Bläddra i källkod

field access now works more or less

Nicolas Winkler 6 år sedan
förälder
incheckning
ab4a9e8f97
11 ändrade filer med 88 tillägg och 23 borttagningar
  1. 44 2
      src/AstVisitor.cpp
  2. 6 2
      src/CodeGeneration.cpp
  3. 4 2
      src/CodegenVisitor.cpp
  4. 1 0
      src/ErrorReporting.h
  5. 0 11
      src/Logging.cpp
  6. 10 1
      src/Logging.h
  7. 1 0
      src/Semantic.h
  8. 3 3
      src/lexer.l
  9. 5 0
      src/parser.y
  10. 2 2
      src/test.qlw
  11. 12 0
      src/tests/structs.qlw

+ 44 - 2
src/AstVisitor.cpp

@@ -282,14 +282,56 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::AssignmentStat
 //    as->target = unique_dynamic_cast<sem::Expression>(visit(*ast.target, classes));
     as->value = unique_dynamic_cast<sem::Expression>(ast.expr->accept(*this, scope));
     as->target = unique_dynamic_cast<sem::Expression>(ast.target->accept(*this, scope));
-    return as;
+    
+    if (as->target->type->equals(*as->value->type)) {
+        return as;
+    }
+    else {
+        throw SemanticError(
+            SemanticError::TYPE_MISMATCH,
+            "Can't assign expression of type '" + as->value->type->asString() +
+            "' to value of type '" + as->target->type->asString() + "'.",
+            ast.pos
+        );
+    }
 }
 
 
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::ReturnStatement& ast, sem::Scope& scope)
 {
+    auto shouldReturn = scope.getReturnableType();
+    
+    if (shouldReturn == nullptr) {
+        if (ast.expr == nullptr)
+            return std::make_unique<sem::ReturnStatement>();
+        else
+            throw SemanticError(
+                SemanticError::INVALID_RETURN_TYPE,
+                "This method should not return any value.",
+                ast.expr->pos
+            );
+    }
+    else if (ast.expr == nullptr) {
+        throw SemanticError(
+            SemanticError::INVALID_RETURN_TYPE,
+            "This method should return a value.",
+            ast.pos
+        );
+    }
+    
+    auto returnValue = unique_dynamic_cast<sem::Expression>(ast.expr->accept(*this, scope));
+    
+    if (!shouldReturn->equals(*returnValue->type)) {
+        throw SemanticError(
+            SemanticError::INVALID_RETURN_TYPE,
+            "return value must be of type '" + shouldReturn->asString() + "' (not '" +
+            returnValue->type->asString() + "')",
+            ast.expr->pos
+        );
+    }
+    
     auto as = std::make_unique<sem::ReturnStatement>();
-    as->value = unique_dynamic_cast<sem::Expression>(ast.expr->accept(*this, scope));
+    as->value = std::move(returnValue);
     return as;
 }
 

+ 6 - 2
src/CodeGeneration.cpp

@@ -46,16 +46,20 @@ std::unique_ptr<llvm::Module> generateModule(const sem::GlobalScope& objects)
 
     // create llvm structs
     // TODO implement detection of circles
-    for (auto& [name, cl] : objects.classes){
+    for (auto& [name, cl] : objects.classes) {
         llvm::StructType* st;
         std::vector<llvm::Type*> fields;
 #ifdef DEBUGGING
         printf("creating llvm struct for %s\n", name.c_str());
-#endif 
+#endif
+        int llvmStructIndex = 0;
         for (auto& [name, field] : cl->fields) {
+            field->llvmStructIndex = llvmStructIndex;
             fields.push_back(field->type->getLlvmType(context));
             if (fields[fields.size() - 1] == nullptr)
                 throw "internal error: possible circular dependency";
+            
+            llvmStructIndex++;
         }
         st = llvm::StructType::create(context, fields, name);
         cl->llvmType = st;

+ 4 - 2
src/CodegenVisitor.cpp

@@ -177,8 +177,9 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::FieldAccessExpression& access,
     
     llvm::Value* target = access.target->accept(fg.lvalueVisitor, builder);
     
+    int structIndex = access.accessed->llvmStructIndex;
     llvm::ArrayRef<Value*> indexList = {
-        llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, 0, false)),
+        llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, structIndex, false)),
         llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, 0, false))
     };
     Value* ptr = builder.CreateGEP(type, target, indexList);
@@ -267,8 +268,9 @@ llvm::Value* LValueVisitor::visit(sem::FieldAccessExpression& access, llvm::IRBu
     
     llvm::Value* target = access.target->accept(*this, builder);
     
+    int structIndex = access.accessed->llvmStructIndex;
     llvm::ArrayRef<Value*> indexList = {
-        llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, 0, false)),
+        llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, structIndex, false)),
         llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, 0, false))
     };
     Value* ptr = builder.CreateGEP(type, target, indexList);

+ 1 - 0
src/ErrorReporting.h

@@ -84,6 +84,7 @@ public:
         FEATURE_NOT_FOUND,
         WRONG_NUMBER_OF_ARGUMENTS,
         TYPE_MISMATCH,
+        INVALID_RETURN_TYPE,
     };
     
     

+ 0 - 11
src/Logging.cpp

@@ -68,17 +68,6 @@ void Logger::logError(const std::string& errMsg, const qlow::CodePosition& cp)
 }
 
 
-std::ostream& Logger::operator()(LogLevel ll)
-{
-    if (logLevel >= ll) {
-        return *this;
-    }
-    else {
-        return nullStream;
-    }
-}
-
-
 int Logger::overflow(int c)
 {
     target.put(char(c));

+ 10 - 1
src/Logging.h

@@ -80,7 +80,16 @@ public:
     void logError(const std::string& errMsg);
     void logError(const std::string& errMsg, const qlow::CodePosition& cp);
 
-    std::ostream& operator() (LogLevel ll);
+    inline std::ostream& operator()(LogLevel ll)
+    {
+        if (logLevel >= ll) {
+            return *this;
+        }
+        else {
+            return nullStream;
+        }
+    }
+    
     inline std::ostream& none (void) { return (*this)(LogLevel::NONE); }
     inline std::ostream& err  (void) { return (*this)(LogLevel::ERROR); }
     inline std::ostream& warn (void) { return (*this)(LogLevel::WARNING); }

+ 1 - 0
src/Semantic.h

@@ -122,6 +122,7 @@ struct qlow::sem::Variable : public SemanticObject
 
 struct qlow::sem::Field : public Variable
 {
+    int llvmStructIndex;
     virtual std::string toString(void) const override;
 };
 

+ 3 - 3
src/lexer.l

@@ -70,15 +70,15 @@ UTF8CHAR [\x00-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xe
 
 <COMMENT>"/*"           commentDepth++;
 <COMMENT>"*/"           if ((--commentDepth) == 0) { BEGIN(INITIAL); };
-<COMMENT>\n             ;
+<COMMENT>\n             offset = 0;
 <COMMENT>.              ; // inside comment, ignore everything
 
-<LINE_COMMENT>\n        yy_pop_state(); //yy_push_state(INITIAL);
+<LINE_COMMENT>\n        offset = 0; yy_pop_state(); //yy_push_state(INITIAL);
 <LINE_COMMENT>.         ; // inside comment, ignore everything
 
 <STRING>"\""            yy_pop_state();
 <STRING>[^\"^\n]*          printf("%s\n", std::string(yytext, yyleng).c_str());
-<STRING>\n              SET_STRING; return UNEXPECTED_SYMBOL; 
+<STRING>\n              offset = 0; SET_STRING; return UNEXPECTED_SYMBOL; 
 
 "/*"                    yy_push_state(COMMENT); commentDepth = 1;
 "//"                    yy_push_state(LINE_COMMENT);

+ 5 - 0
src/parser.y

@@ -40,6 +40,7 @@ int qlow_parser_error(const char* msg)
     //throw msg;
     //printf("error happened: %s\n", msg);
     // throw msg;
+    return 0;
 }
 
 std::unique_ptr<std::vector<std::unique_ptr<qlow::ast::AstObject>>> parsedClasses;
@@ -595,6 +596,10 @@ assignmentStatement:
 returnStatement:
     RETURN expression {
         $$ = new ReturnStatement(std::unique_ptr<Expression>($2), @$);
+    }
+    |
+    RETURN {
+        $$ = new ReturnStatement(nullptr, @$);
     };
 
 localVariableStatement:

+ 2 - 2
src/test.qlw

@@ -16,7 +16,7 @@ fast_fibonacci(i: Integer): Integer do
     return a
 end
 
-extern do_shit
+//extern do_shit
 
 
 bignumbers do
@@ -30,7 +30,7 @@ end
 
 main2 do
     value: Integer
-    do_shit
+    //do_shit
 end
 
 

+ 12 - 0
src/tests/structs.qlw

@@ -9,6 +9,15 @@ class Vec
         return x
         //return 123
     end
+
+    increment_both do
+        x := x + 1
+        y := y + 1
+    end
+
+    get_sum: Integer do
+        return x + y
+    end
 end
 
 
@@ -18,9 +27,12 @@ main: Integer do
     value := 2
 
     var.x := value + 10
+    var.y := 100
 
     //var.x := 2
     value := var.yuhu
+    var.increment_both
+    value := var.get_sum
 //    var.x := 4
 //    var.hohoo := 4
     return value