Kaynağa Gözat

allowing malloc

Nicolas Winkler 6 yıl önce
ebeveyn
işleme
ad91633c6b

+ 20 - 0
src/CodegenVisitor.cpp

@@ -8,6 +8,7 @@
 
 #include <llvm/IR/Constants.h>
 #include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/DataLayout.h>
 #include <llvm/Support/raw_os_ostream.h>
 
 
@@ -127,6 +128,25 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::CastExpression& cast, llvm::IR
 }
 
 
+llvm::Value* ExpressionCodegenVisitor::visit(sem::NewExpression& nexpr, llvm::IRBuilder<>& builder)
+{
+    using llvm::Value;
+    
+    sem::Context& semCtxt = nexpr.context;
+    sem::TypeId type = nexpr.type;
+
+    const llvm::DataLayout& layout = builder.GetInsertBlock()->getModule()->getDataLayout();
+    llvm::Type* llvmTy = semCtxt.getLlvmType(type, builder.getContext())->getPointerElementType();
+    auto allocSize = layout.getTypeAllocSize(llvmTy);
+
+    auto size = llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, allocSize, false));
+    auto mallocCall = llvm::CallInst::CreateMalloc(builder.GetInsertBlock(), size->getType(), llvmTy, size, nullptr, nullptr, "");
+    //auto casted = builder.CreateBitCast(mallocCall, llvmTy);
+    builder.GetInsertBlock()->getInstList().push_back(llvm::cast<llvm::Instruction>(mallocCall));
+    return mallocCall;
+}
+
+
 llvm::Value* ExpressionCodegenVisitor::visit(sem::NewArrayExpression& naexpr, llvm::IRBuilder<>& builder)
 {
     using llvm::Value;

+ 2 - 0
src/CodegenVisitor.h

@@ -42,6 +42,7 @@ class qlow::ExpressionCodegenVisitor :
         sem::UnaryOperation,
         sem::BinaryOperation,
         sem::CastExpression,
+        sem::NewExpression,
         sem::NewArrayExpression,
         sem::MethodCallExpression,
         sem::FieldAccessExpression,
@@ -61,6 +62,7 @@ public:
     llvm::Value* visit(sem::UnaryOperation& node, llvm::IRBuilder<>&) override;
     llvm::Value* visit(sem::BinaryOperation& node, llvm::IRBuilder<>&) override;
     llvm::Value* visit(sem::CastExpression& node, llvm::IRBuilder<>&) override;
+    llvm::Value* visit(sem::NewExpression& node, llvm::IRBuilder<>&) override;
     llvm::Value* visit(sem::NewArrayExpression& node, llvm::IRBuilder<>&) override;
     llvm::Value* visit(sem::MethodCallExpression& node, llvm::IRBuilder<>&) override;
     llvm::Value* visit(sem::FieldAccessExpression& node, llvm::IRBuilder<>&) override;

+ 1 - 0
src/ast/Ast.cpp

@@ -44,6 +44,7 @@ ACCEPT_DEFINITION(AddressExpression, StructureVisitor)
 ACCEPT_DEFINITION(IntConst, StructureVisitor)
 ACCEPT_DEFINITION(UnaryOperation, StructureVisitor)
 ACCEPT_DEFINITION(BinaryOperation, StructureVisitor)
+ACCEPT_DEFINITION(NewExpression, StructureVisitor)
 ACCEPT_DEFINITION(NewArrayExpression, StructureVisitor)
 ACCEPT_DEFINITION(CastExpression, StructureVisitor)
 

+ 16 - 0
src/ast/Ast.h

@@ -78,6 +78,7 @@ namespace qlow
         struct UnaryOperation;
         struct BinaryOperation;
         
+        struct NewExpression;
         struct NewArrayExpression;
         
         struct CastExpression;
@@ -542,6 +543,21 @@ struct qlow::ast::BinaryOperation : public Operation
 };
 
 
+struct qlow::ast::NewExpression : public Expression
+{
+    std::unique_ptr<ast::Type> type;
+    inline NewExpression(std::unique_ptr<ast::Type> type,
+                              const CodePosition& cp) :
+        AstObject{ cp },
+        Expression{ cp },
+        type{ std::move(type) }
+    {
+    }
+    
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
 struct qlow::ast::NewArrayExpression : public Expression
 {
     std::unique_ptr<ast::Type> type;

+ 8 - 0
src/ast/AstVisitor.cpp

@@ -412,6 +412,14 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::BinaryOperatio
 }
 
 
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewExpression& ast, sem::Scope& scope)
+{
+    auto ret = std::make_unique<sem::NewExpression>(scope.getContext(), scope.getType(ast.type.get()));
+    return ret;
+    //return nullptr;
+}
+
+
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewArrayExpression& ast, sem::Scope& scope)
 {
     auto ret = std::make_unique<sem::NewArrayExpression>(scope.getContext(), scope.getType(ast.type.get()));

+ 2 - 0
src/ast/AstVisitor.h

@@ -50,6 +50,7 @@ class qlow::StructureVisitor :
         ast::IntConst,
         ast::UnaryOperation,
         ast::BinaryOperation,
+        ast::NewExpression,
         ast::NewArrayExpression,
         ast::CastExpression
     >
@@ -75,6 +76,7 @@ public:
     ReturnType visit(ast::IntConst& ast, sem::Scope& scope) override;
     ReturnType visit(ast::UnaryOperation& ast, sem::Scope& scope) override;
     ReturnType visit(ast::BinaryOperation& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::NewExpression& ast, sem::Scope& scope) override;
     ReturnType visit(ast::NewArrayExpression& ast, sem::Scope& scope) override;
     ReturnType visit(ast::CastExpression& ast, sem::Scope& scope) override;
 };

+ 1 - 0
src/ast/lexer.l

@@ -93,6 +93,7 @@ UTF8CHAR [\x00-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xe
 \n                      yycolumn = 0; //return SET_TOKEN(NEW_LINE);
 
 "class"                 return SET_TOKEN(CLASS);
+"struct"                return SET_TOKEN(STRUCT);
 "do"                    yy_push_state(METHOD, yyscanner); return SET_TOKEN(DO);
 <METHOD>"end"           yy_pop_state(yyscanner); return SET_TOKEN(END);
 <INITIAL>"end"          return SET_TOKEN(END);

+ 29 - 19
src/ast/syntax.y

@@ -22,18 +22,20 @@
 %code requires {
 #include "Ast.h"
 
+// declare location type
 using QLOW_PARSER_LTYPE = qlow::CodePosition;
 using YYLTYPE = QLOW_PARSER_LTYPE;
 #define QLOW_PARSER_LTYPE_IS_DECLARED
 
+// declare token struct
 union QLOW_PARSER_STYPE;
 using YYSTYPE = QLOW_PARSER_STYPE;
 
+// define yyscan_t
 #ifndef YY_TYPEDEF_YY_SCANNER_T
 #define YY_TYPEDEF_YY_SCANNER_T
 typedef void* yyscan_t;
 #endif
-//#define qlow_parser_lex(a,b,c)  (({ auto v = qlow_parser_lex(a, b, c); v; }))
 }
 
 %{
@@ -49,13 +51,10 @@ typedef void* yyscan_t;
 
 using namespace qlow::ast;
 
-//extern int qlow_parser_lex();
-//void yy_pop_state();
-
 int qlow_parser_error(qlow::CodePosition* loc, yyscan_t scan,
     Ast& ast, const Parser& parser, const char* msg)
 {
-    //throw msg;
+    throw qlow::SyntaxError(*loc);
     //printf("error happened: %s\n", msg);
     // throw msg;
     return 0;
@@ -64,7 +63,7 @@ int qlow_parser_error(qlow::CodePosition* loc, yyscan_t scan,
 
 extern "C" int qlow_parser_wrap(yyscan_t s)
 {
-    return 1; /* do not continue on EOF */
+    return 1;
 }
 
 
@@ -76,7 +75,7 @@ do                                                        \
       (Cur).first_column = YYRHSLOC(Rhs, 1).first_column; \
       (Cur).last_line    = YYRHSLOC(Rhs, N).last_line;    \
       (Cur).last_column  = YYRHSLOC(Rhs, N).last_column;  \
-      (Cur).filename     = parser.getFilename().c_str();  \
+      (Cur).filename     = parser.getFilename();          \
     }                                                     \
   else                                                    \
     {                                                     \
@@ -84,7 +83,7 @@ do                                                        \
         YYRHSLOC(Rhs, 0).last_line;                       \
       (Cur).first_column = (Cur).last_column =            \
         YYRHSLOC(Rhs, 0).last_column;                     \
-      (Cur).filename = parser.getFilename().c_str();      \
+      (Cur).filename = parser.getFilename();              \
     }                                                     \
 while (0)
 %}
@@ -98,6 +97,8 @@ while (0)
 %define api.prefix {qlow_parser_}
 %define parse.error verbose
 %define api.pure full
+
+// for better error messages
 // %define parse.lac full
 
 %locations
@@ -106,10 +107,7 @@ while (0)
 
 %initial-action
 {
-    // NOTE: the filename only lives as long as the parser.
-    // Do not use after deletion of the parser.
-    const auto* filename = parser.getFilename().c_str();
-    @$.filename = filename;
+    @$.filename = parser.getFilename();
     qlow_parser_set_extra(parser.getFilename(), scanner);
 };
 
@@ -147,6 +145,7 @@ while (0)
     qlow::ast::UnaryOperation* unaryOperation;
     qlow::ast::BinaryOperation* binaryOperation;
 
+    qlow::ast::NewExpression* newExpression;
     qlow::ast::NewArrayExpression* newArrayExpression;
     qlow::ast::CastExpression* castExpression;
 
@@ -160,15 +159,15 @@ while (0)
 %token <string> INT_LITERAL
 %token <string> ASTERISK SLASH PLUS MINUS EQUALS NOT_EQUALS AND OR XOR CUSTOM_OPERATOR
 %token <token> TRUE FALSE
-%token <token> CLASS DO END IF ELSE WHILE RETURN NEW EXTERN AS
+%token <token> CLASS STRUCT DO END IF ELSE WHILE RETURN NEW EXTERN AS
 %token <token> NEW_LINE
 %token <token> SEMICOLON COLON COMMA DOT ASSIGN AMPERSAND
 %token <token> ROUND_LEFT ROUND_RIGHT SQUARE_LEFT SQUARE_RIGHT
 %token <string> UNEXPECTED_SYMBOL
 
-%type <topLevel> topLevel 
+%type <topLevel> topLevel
 %type <classDefinition> classDefinition
-%type <type> type 
+%type <type> type
 %type <featureDeclaration> featureDeclaration
 %type <fieldDeclaration> fieldDeclaration
 %type <methodDefinition> methodDefinition
@@ -179,18 +178,19 @@ while (0)
 %type <expressionList> expressionList
 %type <argumentDeclaration> argumentDeclaration
 %type <doEndBlock> doEndBlock
-%type <ifElseBlock> ifElseBlock 
+%type <ifElseBlock> ifElseBlock
 %type <whileBlock> whileBlock
 %type <statement> statement
 %type <expression> expression operationExpression paranthesesExpression
 %type <featureCall> featureCall
-%type <assignmentStatement> assignmentStatement 
-%type <returnStatement> returnStatement 
+%type <assignmentStatement> assignmentStatement
+%type <returnStatement> returnStatement
 %type <localVariableStatement> localVariableStatement
-%type <addressExpression> addressExpression 
+%type <addressExpression> addressExpression
 %type <string> operator
 %type <unaryOperation> unaryOperation
 %type <binaryOperation> binaryOperation
+%type <newExpression> newExpression
 %type <newArrayExpression> newArrayExpression
 %type <castExpression> castExpression
 
@@ -539,6 +539,10 @@ expression:
         $$ = $1;
     }
     |
+    newExpression {
+        $$ = $1;
+    }
+    |
     newArrayExpression {
         $$ = $1;
     }
@@ -683,6 +687,12 @@ paranthesesExpression:
         $$ = $2;
     };
 
+newExpression:
+    NEW type {
+        $$ = new NewExpression(std::unique_ptr<qlow::ast::Type>($2), @$);
+        $2 = nullptr;
+    };
+
 newArrayExpression:
     NEW SQUARE_LEFT type SEMICOLON expression SQUARE_RIGHT {
         $$ = nullptr;

+ 4 - 4
src/sem/CodeGeneration.cpp

@@ -113,9 +113,9 @@ std::unique_ptr<llvm::Module> generateModule(sem::GlobalScope& semantic)
             bool corrupt = llvm::verifyFunction(*f, &verifyStream);
             if (corrupt) {
 #ifdef DEBUGGING
-                module->print(verifyStream, nullptr);
+                //module->print(verifyStream, nullptr);
 #endif
-                throw (std::string("corrupt llvm function") + method->name).c_str();
+                throw (std::string("corrupt llvm function: ") + method->name).c_str();
             }
 #ifdef DEBUGGING
             printf("verified function: %s\n", method->name.c_str());
@@ -131,8 +131,8 @@ std::unique_ptr<llvm::Module> generateModule(sem::GlobalScope& semantic)
         //printer.debug() << "verifying function: " << method->name << std::endl;
         bool corrupt = llvm::verifyFunction(*f, &verifyStream);
         if (corrupt) {
-            module->print(verifyStream, nullptr);
-            throw method->name.c_str();
+            f->print(verifyStream, nullptr);
+            throw (std::string("corrupt llvm function: ") + method->name).c_str();
         }
 #ifdef DEBUGGING
         printf("verified function: %s\n", method->name.c_str());

+ 8 - 0
src/sem/Semantic.cpp

@@ -176,6 +176,7 @@ ReturnType ClassName::accept(Visitor& v, Arg arg) \
 ACCEPT_DEFINITION(LocalVariableExpression, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 ACCEPT_DEFINITION(BinaryOperation, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 ACCEPT_DEFINITION(CastExpression, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
+ACCEPT_DEFINITION(NewExpression, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 ACCEPT_DEFINITION(NewArrayExpression, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 ACCEPT_DEFINITION(UnaryOperation, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 ACCEPT_DEFINITION(MethodCallExpression, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
@@ -235,6 +236,13 @@ std::string CastExpression::toString(void) const
 }
 
 
+std::string NewExpression::toString(void) const
+{
+    // TODO remove optional unwrapping
+    return "NewExpression[" + context.getType(type).asString() + "]";
+}
+
+
 std::string NewArrayExpression::toString(void) const
 {
     // TODO remove optional unwrapping

+ 13 - 0
src/sem/Semantic.h

@@ -50,6 +50,7 @@ namespace qlow
         
         struct CastExpression;
         
+        struct NewExpression;
         struct NewArrayExpression;
 
         struct MethodCallExpression;
@@ -394,6 +395,18 @@ struct qlow::sem::CastExpression : public Expression
 };
 
 
+struct qlow::sem::NewExpression : public Expression
+{
+    inline NewExpression(Context& context, TypeId type) :
+        Expression{ context, type }
+    {
+    }
+    
+    virtual llvm::Value* accept(ExpressionCodegenVisitor& visitor, llvm::IRBuilder<>& arg2) override;
+    virtual std::string toString(void) const override;
+};
+
+
 struct qlow::sem::NewArrayExpression : public Expression
 {
     TypeId arrayType;

+ 1 - 0
src/tests/structs.qlw

@@ -27,6 +27,7 @@ end
 
 create_vec: Vec do
     var: Vec
+    var := new Vec
     var.x := 3
     var.y := 4
     return var