Nicolas Winkler 6 years ago
parent
commit
277058937d
16 changed files with 184 additions and 10 deletions
  1. 1 0
      src/Ast.cpp
  2. 33 0
      src/Ast.h
  3. 14 0
      src/AstVisitor.cpp
  4. 2 0
      src/AstVisitor.h
  5. 3 0
      src/CodeGeneration.cpp
  6. 24 0
      src/CodegenVisitor.cpp
  7. 16 0
      src/CodegenVisitor.h
  8. 9 3
      src/ErrorReporting.cpp
  9. 26 0
      src/ErrorReporting.h
  10. 4 0
      src/Scope.cpp
  11. 2 0
      src/Scope.h
  12. 1 0
      src/Semantic.cpp
  13. 21 0
      src/Semantic.h
  14. 1 0
      src/lexer.l
  15. 20 2
      src/parser.y
  16. 7 5
      src/tests/structs.qlw

+ 1 - 0
src/Ast.cpp

@@ -33,6 +33,7 @@ ACCEPT_DEFINITION(FeatureCall, StructureVisitor)
 ACCEPT_DEFINITION(AssignmentStatement, StructureVisitor)
 ACCEPT_DEFINITION(ReturnStatement, StructureVisitor)
 ACCEPT_DEFINITION(LocalVariableStatement, StructureVisitor)
+ACCEPT_DEFINITION(AddressExpression, StructureVisitor)
 ACCEPT_DEFINITION(IntConst, StructureVisitor)
 ACCEPT_DEFINITION(UnaryOperation, StructureVisitor)
 ACCEPT_DEFINITION(BinaryOperation, StructureVisitor)

+ 33 - 0
src/Ast.h

@@ -47,6 +47,7 @@ namespace qlow
         struct Type;
         struct ClassType;
         struct ArrayType;
+        struct PointerType;
         
         struct FeatureDeclaration;
 
@@ -68,6 +69,7 @@ namespace qlow
         struct AssignmentStatement;
         struct ReturnStatement;
         struct LocalVariableStatement;
+        struct AddressExpression;
         struct IntConst;
 
         struct Operation;
@@ -168,6 +170,22 @@ struct qlow::ast::ArrayType : public ast::Type
 };
 
 
+struct qlow::ast::PointerType : public ast::Type 
+{
+    std::unique_ptr<ast::Type> derefType;
+    
+    inline PointerType(std::unique_ptr<ast::Type> derefType, const CodePosition& cp) :
+        Type{ cp },
+        derefType{ std::move(derefType) }
+    {
+    }
+    
+    inline std::string asString(void) const override {
+        return derefType->asString() + "*";
+    }
+};
+
+
 struct qlow::ast::FeatureDeclaration : public AstObject
 {
     std::string name;
@@ -416,6 +434,21 @@ struct qlow::ast::LocalVariableStatement : public Statement
 };
 
 
+struct qlow::ast::AddressExpression : public Expression
+{
+    std::unique_ptr<Expression> target;
+    inline AddressExpression(std::unique_ptr<Expression> target,
+                             const CodePosition& cp) :
+        AstObject{ cp },
+        Expression{ cp },
+       target{ std::move(target) }
+    {
+    } 
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
 struct qlow::ast::IntConst : public Expression
 {
     unsigned long long value;

+ 14 - 0
src/AstVisitor.cpp

@@ -342,6 +342,20 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::LocalVariableS
 }
 
 
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(
+    ast::AddressExpression& ast, sem::Scope& scope)
+{
+    auto target = unique_dynamic_cast<sem::Expression>(ast.target->accept(*this, scope));
+    auto& targetType = target->type;
+    
+    if (!target->isLValue()) {
+        throw NotLValue(targetType->asString(), ast.pos);
+    }
+    
+    return std::make_unique<sem::AddressExpression>(std::move(target));
+}
+
+
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::IntConst& ast, sem::Scope& scope)
 {
     return std::make_unique<sem::IntConst>(ast.value);

+ 2 - 0
src/AstVisitor.h

@@ -46,6 +46,7 @@ class qlow::StructureVisitor :
         ast::AssignmentStatement,
         ast::ReturnStatement,
         ast::LocalVariableStatement,
+        ast::AddressExpression,
         ast::IntConst,
         ast::UnaryOperation,
         ast::BinaryOperation,
@@ -70,6 +71,7 @@ public:
     ReturnType visit(ast::AssignmentStatement& ast, sem::Scope& scope) override;
     ReturnType visit(ast::ReturnStatement& ast, sem::Scope& scope) override;
     ReturnType visit(ast::LocalVariableStatement& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::AddressExpression& ast, sem::Scope& scope) override;
     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;

+ 3 - 0
src/CodeGeneration.cpp

@@ -302,6 +302,9 @@ llvm::Function* qlow::gen::FunctionGenerator::generate(void)
     for (auto& [name, var] : method.body->scope.getLocals()) {
         if (var.get() == nullptr)
             throw "wtf null variable";
+        if (var->type == nullptr)
+            throw "wtf null type";
+        
         llvm::AllocaInst* v = builder.CreateAlloca(var->type->getLlvmType(context));
         var->allocaInst = v;
     }

+ 24 - 0
src/CodegenVisitor.cpp

@@ -194,6 +194,21 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::FieldAccessExpression& access,
 }
 
 
+llvm::Value* ExpressionCodegenVisitor::visit(sem::AddressExpression& node, llvm::IRBuilder<>& builder)
+{
+    using llvm::Value;
+    Value* lvalue = node.target->accept(fg.lvalueVisitor, builder);
+    
+    // this check is unnecessary
+    if (auto* allocaInst = llvm::dyn_cast<llvm::AllocaInst>(lvalue)) {
+        return lvalue;
+    }
+    else {
+        return lvalue;
+    }
+}
+
+
 llvm::Value* ExpressionCodegenVisitor::visit(sem::IntConst& node, llvm::IRBuilder<>& builder)
 {
     return llvm::ConstantInt::get(builder.getContext(),
@@ -435,5 +450,14 @@ llvm::Value* StatementVisitor::visit(sem::FeatureCallStatement& fc, gen::Functio
 }
 
 
+llvm::Value* CastGenerator::generateCast(llvm::Value* toCast,
+                                          llvm::IRBuilder<>& b)
+{
+    return b.CreateCast(
+        llvm::Instruction::CastOps::BitCast, toCast,
+        cast.to->getLlvmType(b.getContext()));
+}
+
+
 
 

+ 16 - 0
src/CodegenVisitor.h

@@ -9,6 +9,7 @@
 #include "Semantic.h"
 #include "Scope.h"
 #include "Type.h"
+#include "Cast.h"
 
 
 #include <memory>
@@ -28,6 +29,7 @@ namespace qlow
     class ExpressionCodegenVisitor;
     class LValueVisitor;
     class StatementVisitor;
+    class CastGenerator;
 }
 
 
@@ -43,6 +45,7 @@ class qlow::ExpressionCodegenVisitor :
         sem::NewArrayExpression,
         sem::MethodCallExpression,
         sem::FieldAccessExpression,
+        sem::AddressExpression,
         sem::IntConst,
         sem::ThisExpression
     >
@@ -61,6 +64,7 @@ public:
     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;
+    llvm::Value* visit(sem::AddressExpression& node, llvm::IRBuilder<>&) override;
     llvm::Value* visit(sem::IntConst& node, llvm::IRBuilder<>&) override;
     llvm::Value* visit(sem::ThisExpression& node, llvm::IRBuilder<>&) override;
 };
@@ -106,6 +110,18 @@ public:
 };
 
 
+class qlow::CastGenerator
+{
+    sem::Cast cast;
+public:
+    inline CastGenerator(const sem::Cast& cast) :
+        cast{ cast }
+    {
+    }
+    
+    
+    llvm::Value* generateCast(llvm::Value* toCast, llvm::IRBuilder<>& b);
+};
 
 
 #endif // QLOW_CODEGEN_VISITOR_H

+ 9 - 3
src/ErrorReporting.cpp

@@ -135,6 +135,14 @@ void SyntaxError::print(Logger& logger) const
 
 void SemanticError::print(Logger& logger) const
 {
+    std::string errMsg = getMessage();
+    logger.logError(errMsg + (errMsg != "" ?  ": " : "") + message, where);
+    underlineError(logger);
+}
+
+
+std::string SemanticError::getMessage(void) const
+{
     static std::map<ErrorCode, std::string> error = {
         {UNKNOWN_TYPE, "unknown type"},
         {FEATURE_NOT_FOUND, "method or variable not found"},
@@ -144,9 +152,7 @@ void SemanticError::print(Logger& logger) const
         {OPERATOR_NOT_FOUND, ""},
         {WRONG_NUMBER_OF_ARGUMENTS, "wrong number of arguments passed"},
     };
-    std::string& errMsg = error[errorCode];
-    logger.logError(errMsg + (errMsg != "" ?  ": " : "") + message, where);
-    underlineError(logger);
+    return error[errorCode];
 }
 
 

+ 26 - 0
src/ErrorReporting.h

@@ -11,7 +11,9 @@ namespace qlow
     class CompileError;
     
     class SyntaxError;
+    
     class SemanticError;
+    class NotLValue;
     
     void reportError(const CompileError& ce);
     void reportError(const std::string& message);
@@ -97,8 +99,32 @@ public:
             errorCode{ ec }
     {
     }
+    
+    inline SemanticError(const CodePosition& where) :
+        CompileError{ where }
+    {
+    }
 
     virtual void print(Logger&) const override;
+    virtual std::string getMessage(void) const;
+};
+
+
+class qlow::NotLValue : public SemanticError
+{
+    std::string type;
+public:
+    inline NotLValue(const std::string& type, const CodePosition& where) :
+        SemanticError{ where },
+        type{ type }
+    {
+    }
+    
+    inline virtual std::string getMessage(void) const override
+    {
+        return "Can't take address of non-lvalue value of type '" +
+            type + "'";
+    }
 };
 
 

+ 4 - 0
src/Scope.cpp

@@ -51,6 +51,10 @@ std::shared_ptr<sem::Type> sem::GlobalScope::getType(const ast::Type& name)
         return std::make_shared<sem::ArrayType>(getType(*arr->arrayType));
     }
     
+    if (const auto* ptr = dynamic_cast<const ast::PointerType*>(&name)) {
+        return std::make_shared<sem::PointerType>(getType(*ptr->derefType));
+    }
+    
     auto native = NativeScope::getInstance().getType(name);
     if (native) {
         return native;

+ 2 - 0
src/Scope.h

@@ -27,6 +27,7 @@ namespace qlow
         struct Class;
         struct Method;
         struct Variable;
+        class Cast;
 
         class Scope;
         class GlobalScope;
@@ -62,6 +63,7 @@ class qlow::sem::GlobalScope : public Scope
 public:
     SymbolTable<Class> classes;
     SymbolTable<Method> functions;
+    OwningList<Cast> casts;
 public:
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);

+ 1 - 0
src/Semantic.cpp

@@ -190,6 +190,7 @@ ACCEPT_DEFINITION(NewArrayExpression, ExpressionCodegenVisitor, llvm::Value*, ll
 ACCEPT_DEFINITION(UnaryOperation, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 ACCEPT_DEFINITION(MethodCallExpression, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 ACCEPT_DEFINITION(FieldAccessExpression, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
+ACCEPT_DEFINITION(AddressExpression, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 ACCEPT_DEFINITION(IntConst, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 ACCEPT_DEFINITION(ThisExpression, ExpressionCodegenVisitor, llvm::Value*, llvm::IRBuilder<>&)
 

+ 21 - 0
src/Semantic.h

@@ -41,6 +41,7 @@ namespace qlow
         struct ReturnStatement;
         
         struct LocalVariableExpression;
+        struct AddressExpression;
 
         struct Operation;
         struct UnaryOperation;
@@ -265,6 +266,8 @@ struct qlow::sem::Expression :
     {
     }
     
+    inline virtual bool isLValue(void) const { return false; }
+    
     virtual llvm::Value* accept(ExpressionCodegenVisitor& visitor, llvm::IRBuilder<>& arg2) override = 0;
     virtual llvm::Value* accept(LValueVisitor& visitor, llvm::IRBuilder<>& arg2) override;
 };
@@ -290,6 +293,8 @@ struct qlow::sem::LocalVariableExpression : public Expression
         var{ var }
     {
     }
+    
+    inline virtual bool isLValue(void) const override { return true; }
 
     virtual llvm::Value* accept(ExpressionCodegenVisitor& visitor, llvm::IRBuilder<>& arg2) override;
     virtual llvm::Value* accept(LValueVisitor& visitor, llvm::IRBuilder<>& arg2);
@@ -297,6 +302,20 @@ struct qlow::sem::LocalVariableExpression : public Expression
 };
 
 
+struct qlow::sem::AddressExpression : public Expression
+{
+    std::unique_ptr<sem::Expression> target;
+    
+    inline AddressExpression(std::unique_ptr<sem::Expression> target) :
+        Expression{ std::make_shared<sem::PointerType>(target->type) },
+        target{ std::move(target) }
+    {
+    }
+    
+    virtual llvm::Value* accept(ExpressionCodegenVisitor& visitor, llvm::IRBuilder<>& arg2) override;
+};
+
+
 struct qlow::sem::BinaryOperation : public Operation
 {
     std::unique_ptr<Expression> left;
@@ -406,6 +425,8 @@ struct qlow::sem::FieldAccessExpression : public Expression
     {
     }
     
+    inline virtual bool isLValue(void) const override { return true; }
+    
     virtual llvm::Value* accept(ExpressionCodegenVisitor& visitor, llvm::IRBuilder<>& arg2) override;
     virtual llvm::Value* accept(LValueVisitor& visitor, llvm::IRBuilder<>& arg2) override;
     

+ 1 - 0
src/lexer.l

@@ -104,6 +104,7 @@ UTF8CHAR [\x00-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xe
 ";"                     return SET_TOKEN(SEMICOLON);
 ","                     return SET_TOKEN(COMMA);
 "."                     return SET_TOKEN(DOT);
+"&"                     return SET_TOKEN(AMPERSAND);
 
 ":="                    SET_STRING; return ASSIGN;
 

+ 20 - 2
src/parser.y

@@ -93,6 +93,7 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
     qlow::ast::Type* type;
     qlow::ast::ClassType* classType;
     qlow::ast::ArrayType* arrayType;
+    qlow::ast::PointerType* pointerType;
     
     qlow::ast::FeatureDeclaration* featureDeclaration;
     std::vector<std::unique_ptr<qlow::ast::FeatureDeclaration>>* featureList;
@@ -113,6 +114,7 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
     qlow::ast::AssignmentStatement* assignmentStatement;
     qlow::ast::ReturnStatement* returnStatement;
     qlow::ast::LocalVariableStatement* localVariableStatement;
+    qlow::ast::AddressExpression* addressExpression;
 
     qlow::ast::UnaryOperation* unaryOperation;
     qlow::ast::BinaryOperation* binaryOperation;
@@ -132,7 +134,7 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %token <token> TRUE FALSE
 %token <token> CLASS DO END IF ELSE WHILE RETURN NEW EXTERN AS
 %token <token> NEW_LINE
-%token <token> SEMICOLON COLON COMMA DOT ASSIGN
+%token <token> SEMICOLON COLON COMMA DOT ASSIGN AMPERSAND
 %token <token> ROUND_LEFT ROUND_RIGHT SQUARE_LEFT SQUARE_RIGHT
 %token <string> UNEXPECTED_SYMBOL
 
@@ -157,6 +159,7 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %type <assignmentStatement> assignmentStatement 
 %type <returnStatement> returnStatement 
 %type <localVariableStatement> localVariableStatement
+%type <addressExpression> addressExpression 
 %type <string> operator
 %type <unaryOperation> unaryOperation
 %type <binaryOperation> binaryOperation
@@ -176,7 +179,7 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %left EQUALS
 %left PLUS MINUS
 %left ASTERISK SLASH
-%left AS 
+%left AS
 %left DOT
 
 %start topLevel
@@ -238,8 +241,14 @@ type:
         delete $1; $1 = nullptr;
     }
     |
+    type ASTERISK {
+        $$ = new qlow::ast::PointerType(std::unique_ptr<Type>($1), @$);
+        $1 = nullptr;
+    }
+    |
     SQUARE_LEFT type SQUARE_RIGHT {
         $$ = new qlow::ast::ArrayType(std::unique_ptr<qlow::ast::Type>($2), @$);
+        $2 = nullptr;
     }
     |
     SQUARE_LEFT error SQUARE_RIGHT {
@@ -505,6 +514,10 @@ expression:
         $$ = $1;
     }
     |
+    addressExpression {
+        $$ = $1;
+    }
+    |
     INT_LITERAL {
         $$ = new IntConst(std::move(*$1), @$);
         delete $1;
@@ -626,6 +639,11 @@ operator:
     |
     CUSTOM_OPERATOR { $$ = $1; };
 
+addressExpression:
+    AMPERSAND expression {
+        $$ = new AddressExpression(std::unique_ptr<Expression>($2), @$);
+        $2 = nullptr;
+    };
 
 paranthesesExpression:
     ROUND_LEFT expression ROUND_RIGHT {

+ 7 - 5
src/tests/structs.qlw

@@ -25,18 +25,20 @@ class Vec
 end
 
 
-nothing do
+create_vec: Vec do
     var: Vec
-    var.x := 1
-    var.y := 1
+    var.x := 3
+    var.y := 4
+    return var
 end
 
 
 main: Integer do
     var: Vec
 
-    var.x := 3
-    var.y := 4
+    //var.x := 3
+    //var.y := 4
+    var := create_vec
 
     return var.inner_product
 end