Nicolas Winkler 6 年 前
コミット
667d49fbe5
8 ファイル変更107 行追加52 行削除
  1. 4 4
      src/Builtin.cpp
  2. 3 5
      src/Builtin.h
  3. 33 19
      src/CodegenVisitor.cpp
  4. 7 6
      src/CodegenVisitor.h
  5. 10 9
      src/Semantic.cpp
  6. 15 7
      src/Semantic.h
  7. 30 1
      src/Type.cpp
  8. 5 1
      src/Type.h

+ 4 - 4
src/Builtin.cpp

@@ -1,16 +1,16 @@
 #include "Builtin.h"
 
 using namespace qlow;
-/*
+
 sem::Class initInt32(void)
 {
-    //sem::Class c(void);
-    //c.astNode = nullptr;
+    sem::Class c{ nullptr, sem::nativeGlobalScope };
+    return c;
 }
 
 
+sem::GlobalScope sem::nativeGlobalScope{};
 sem::Class sem::Int32 = initInt32();
 
 
-*/
 

+ 3 - 5
src/Builtin.h

@@ -3,14 +3,15 @@
 
 
 #include "Semantic.h"
+#include "Scope.h"
 
 
 namespace qlow
 {
     namespace sem
     {
-
-        //extern Class Int32;
+        extern GlobalScope nativeGlobalScope;
+        extern Class Int32;
         //extern Class String;
     }
 }
@@ -27,9 +28,6 @@ namespace qlow
 
 
 
-
-
-
 #endif // QLOW_SEM_BUILTIN_H
 
 

+ 33 - 19
src/CodegenVisitor.cpp

@@ -1,25 +1,31 @@
 #include "CodegenVisitor.h"
 #include "CodeGeneration.h"
 
+#include "Type.h"
+
 #include <llvm/IR/Constants.h>
 #include <llvm/IR/IRBuilder.h>
 
 
 using namespace qlow;
 
-llvm::Value* ExpressionVisitor::visit(sem::LocalVariableExpression& lve, llvm::IRBuilder<>& builder)
+std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::LocalVariableExpression& lve, llvm::IRBuilder<>& builder)
 {
     llvm::Value* val = builder.CreateLoad(lve.var->allocaInst);
-    return val;
+    return { val, lve.var->type };
 }
 
 
-
-llvm::Value* ExpressionVisitor::visit(sem::BinaryOperation& binop, llvm::IRBuilder<>& builder)
+std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::BinaryOperation& binop, llvm::IRBuilder<>& builder)
 {
     using llvm::Value;
-    Value* left = binop.left->accept(*this, builder);
-    Value* right = binop.right->accept(*this, builder);
+    using sem::Type;
+    auto [left, leftType] = binop.left->accept(*this, builder);
+    auto [right, rightType] = binop.right->accept(*this, builder);
+    
+    if (leftType != Type::INTEGER || rightType != Type::INTEGER)
+        throw "invalid types in BinaryOperation";
+    
     if (left == nullptr) {
         printf("WOW: %s\n", binop.left->toString().c_str());
     }
@@ -27,25 +33,28 @@ llvm::Value* ExpressionVisitor::visit(sem::BinaryOperation& binop, llvm::IRBuild
     
     switch (binop.op) {
         case ast::Operation::Operator::PLUS:
-            return builder.CreateAdd(left, right, "add");
+            return { builder.CreateAdd(left, right, "add"), Type::INTEGER };
         case ast::Operation::Operator::MINUS:
-            return builder.CreateSub(left, right, "sub");
+            return { builder.CreateSub(left, right, "sub"), Type::INTEGER };
         case ast::Operation::Operator::ASTERISK:
-            return builder.CreateMul(left, right, "mul");
+            return { builder.CreateMul(left, right, "mul"), Type::INTEGER };
         case ast::Operation::Operator::SLASH:
-            return builder.CreateSDiv(left, right, "add");
+            return { builder.CreateSDiv(left, right, "add"), Type::INTEGER };
     }
 }
 
 
-llvm::Value* ExpressionVisitor::visit(sem::UnaryOperation& unop, llvm::IRBuilder<>& builder)
+std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::UnaryOperation& unop, llvm::IRBuilder<>& builder)
 {
     using llvm::Value;
-    Value* value = unop.arg->accept(*this, builder);
+    auto [value, type] = unop.arg->accept(*this, builder);
+    
+    if (type != sem::Type::INTEGER)
+        throw "invalid type to negate";
 
     switch (unop.op) {
         case ast::Operation::Operator::MINUS:
-            return builder.CreateNeg(value, "negate");
+            return { builder.CreateNeg(value, "negate"), sem::Type::INTEGER };
 
         case ast::Operation::Operator::PLUS:
         [[fallthrough]];
@@ -56,20 +65,25 @@ llvm::Value* ExpressionVisitor::visit(sem::UnaryOperation& unop, llvm::IRBuilder
     }
 }
 
-llvm::Value* ExpressionVisitor::visit(sem::FeatureCallExpression& call, llvm::IRBuilder<>& builder)
+std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::FeatureCallExpression& call, llvm::IRBuilder<>& builder)
 {
     using llvm::Value;
     std::vector<Value*> arguments;
     for (auto& arg : call.arguments) {
-        arguments.push_back(arg->accept(*this, builder));
+        auto [value, type] = arg->accept(*this, builder);
+        // TODO implement type check
+        arguments.push_back(value);
     }
     //return builder.CreateCall(nullptr, arguments);
-    return nullptr;
+    return { nullptr, sem::Type::NULL_TYPE };
 }
 
-llvm::Value* ExpressionVisitor::visit(sem::IntConst& node, llvm::IRBuilder<>& builder)
+std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::IntConst& node, llvm::IRBuilder<>& builder)
 {
-    return llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, std::to_string(node.value), 10));
+    return {
+        llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, std::to_string(node.value), 10)),
+        sem::Type::INTEGER
+    };
 }
 
 
@@ -78,7 +92,7 @@ llvm::Value* StatementVisitor::visit(sem::AssignmentStatement& assignment,
 {
     llvm::IRBuilder<> builder(fg.getContext());
     builder.SetInsertPoint(fg.getCurrentBlock());
-    llvm::Value* val = assignment.value->accept(fg.expressionVisitor, builder);
+    auto [val, type] = assignment.value->accept(fg.expressionVisitor, builder);
     //builder.CreateRet(val);
     return llvm::ConstantFP::get(fg.getContext(), llvm::APFloat(5.0));
 }

+ 7 - 6
src/CodegenVisitor.h

@@ -8,6 +8,7 @@
 #include "Visitor.h"
 #include "Semantic.h"
 #include "Scope.h"
+#include "Type.h"
 
 
 #include <memory>
@@ -31,7 +32,7 @@ namespace qlow
 
 class qlow::ExpressionVisitor :
     public Visitor<
-        llvm::Value*,
+        std::pair<llvm::Value*, sem::Type>,
         llvm::IRBuilder<>,
 
         sem::LocalVariableExpression,
@@ -42,11 +43,11 @@ class qlow::ExpressionVisitor :
     >
 {
 public:
-    llvm::Value* visit(sem::LocalVariableExpression& node, llvm::IRBuilder<>&) override;
-    llvm::Value* visit(sem::BinaryOperation& node, llvm::IRBuilder<>&) override;
-    llvm::Value* visit(sem::UnaryOperation& node, llvm::IRBuilder<>&) override;
-    llvm::Value* visit(sem::FeatureCallExpression& node, llvm::IRBuilder<>&) override;
-    llvm::Value* visit(sem::IntConst& node, llvm::IRBuilder<>&) override;
+    std::pair<llvm::Value*, sem::Type> visit(sem::LocalVariableExpression& node, llvm::IRBuilder<>&) override;
+    std::pair<llvm::Value*, sem::Type> visit(sem::BinaryOperation& node, llvm::IRBuilder<>&) override;
+    std::pair<llvm::Value*, sem::Type> visit(sem::UnaryOperation& node, llvm::IRBuilder<>&) override;
+    std::pair<llvm::Value*, sem::Type> visit(sem::FeatureCallExpression& node, llvm::IRBuilder<>&) override;
+    std::pair<llvm::Value*, sem::Type> visit(sem::IntConst& node, llvm::IRBuilder<>&) override;
 };
 
 

+ 10 - 9
src/Semantic.cpp

@@ -132,20 +132,21 @@ std::string Method::toString(void) const
 
 
 
-#define ACCEPT_DEFINITION(ClassName, Visitor, Arg) \
-llvm::Value* ClassName::accept(Visitor& v, Arg arg) \
+#define COMMA ,
+#define ACCEPT_DEFINITION(ClassName, Visitor, ReturnType, Arg) \
+ReturnType ClassName::accept(Visitor& v, Arg arg) \
 { \
     return v.visit(*this, arg); \
 }
 
-ACCEPT_DEFINITION(LocalVariableExpression, ExpressionVisitor, llvm::IRBuilder<>&)
-ACCEPT_DEFINITION(BinaryOperation, ExpressionVisitor, llvm::IRBuilder<>&)
-ACCEPT_DEFINITION(UnaryOperation, ExpressionVisitor, llvm::IRBuilder<>&)
-ACCEPT_DEFINITION(FeatureCallExpression, ExpressionVisitor, llvm::IRBuilder<>&)
-ACCEPT_DEFINITION(IntConst, ExpressionVisitor, llvm::IRBuilder<>&)
+ACCEPT_DEFINITION(LocalVariableExpression, ExpressionVisitor, std::pair<llvm::Value* COMMA Type>, llvm::IRBuilder<>&)
+ACCEPT_DEFINITION(BinaryOperation, ExpressionVisitor, std::pair<llvm::Value* COMMA Type>, llvm::IRBuilder<>&)
+ACCEPT_DEFINITION(UnaryOperation, ExpressionVisitor, std::pair<llvm::Value* COMMA Type>, llvm::IRBuilder<>&)
+ACCEPT_DEFINITION(FeatureCallExpression, ExpressionVisitor, std::pair<llvm::Value* COMMA Type>, llvm::IRBuilder<>&)
+ACCEPT_DEFINITION(IntConst, ExpressionVisitor, std::pair<llvm::Value* COMMA Type>, llvm::IRBuilder<>&)
 
-ACCEPT_DEFINITION(AssignmentStatement, StatementVisitor, qlow::gen::FunctionGenerator&) 
-ACCEPT_DEFINITION(FeatureCallStatement, StatementVisitor, qlow::gen::FunctionGenerator&) 
+ACCEPT_DEFINITION(AssignmentStatement, StatementVisitor, llvm::Value*, qlow::gen::FunctionGenerator&) 
+ACCEPT_DEFINITION(FeatureCallStatement, StatementVisitor, llvm::Value*, qlow::gen::FunctionGenerator&) 
 
 std::string AssignmentStatement::toString(void) const
 {

+ 15 - 7
src/Semantic.h

@@ -75,10 +75,14 @@ struct qlow::sem::Class : public SemanticObject
     SymbolTable<Method> methods;
     ClassScope scope;
 
+    /// \brief generated during llvm code generation, not availab
     llvm::Type* llvmType;
 
     inline Class(qlow::ast::Class* astNode, GlobalScope& globalScope) :
-        astNode{ astNode }, name{ astNode->name }, scope{ globalScope, this }
+        astNode{ astNode },
+        name{ astNode->name },
+        scope{ globalScope, this },
+        llvmType{ nullptr }
     {
     }
     
@@ -157,7 +161,11 @@ struct qlow::sem::AssignmentStatement : public Statement
 };
 
 
-struct qlow::sem::Expression : public SemanticObject, public Visitable<llvm::Value*, llvm::IRBuilder<>, qlow::ExpressionVisitor>
+struct qlow::sem::Expression :
+    public SemanticObject,
+    public Visitable<std::pair<llvm::Value*, sem::Type>,
+                     llvm::IRBuilder<>,
+                     qlow::ExpressionVisitor>
 {
 };
 
@@ -172,7 +180,7 @@ struct qlow::sem::LocalVariableExpression : public Expression
 {
     Variable* var;
 
-    virtual llvm::Value* accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
+    virtual std::pair<llvm::Value*, sem::Type> accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
     virtual std::string toString(void) const override;
 };
 
@@ -182,7 +190,7 @@ struct qlow::sem::BinaryOperation : public Operation
     std::unique_ptr<Expression> left;
     std::unique_ptr<Expression> right;
     
-    virtual llvm::Value* accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
+    virtual std::pair<llvm::Value*, sem::Type> accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
     
     virtual std::string toString(void) const override;
 };
@@ -192,7 +200,7 @@ struct qlow::sem::UnaryOperation : public Operation
 {
     qlow::ast::UnaryOperation::Side side;
     std::unique_ptr<Expression> arg;
-    virtual llvm::Value* accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
+    virtual std::pair<llvm::Value*, sem::Type> accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
     virtual std::string toString(void) const override;
 };
 
@@ -201,7 +209,7 @@ struct qlow::sem::FeatureCallExpression : public Expression
 {
     Method* callee;
     OwningList<Expression> arguments;
-    virtual llvm::Value* accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
+    virtual std::pair<llvm::Value*, sem::Type> accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
     
     virtual std::string toString(void) const override;
 };
@@ -216,7 +224,7 @@ struct qlow::sem::IntConst : public Expression
     {
     }
     
-    virtual llvm::Value* accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
+    virtual std::pair<llvm::Value*, sem::Type> accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
 };
 
 

+ 30 - 1
src/Type.cpp

@@ -1,6 +1,7 @@
 #include "Type.h"
 
 #include "Semantic.h"
+#include "Builtin.h"
 
 #include <llvm/IR/DerivedTypes.h>
 #include <llvm/IR/Type.h>
@@ -14,6 +15,13 @@ sem::Type::Type(sem::Class* classType) :
     data.classType = classType;
 }
 
+
+sem::Type::Type(Kind kind, Class* classType) :
+    kind{ kind }
+{
+    data.classType = classType;
+}
+
 bool sem::Type::isClassType(void) const
 {
     return kind == Kind::CLASS;
@@ -47,6 +55,27 @@ llvm::Type* sem::Type::getLlvmType(llvm::LLVMContext& context) const
 }
 
 
-const sem::Type sem::Type::INTEGER = sem::Type{ sem::Type::Kind::INTEGER };
+bool sem::Type::operator == (const Type& other) const
+{
+    if (other.kind != this->kind)
+        return false;
+    
+    switch (kind) {
+        case Kind::CLASS:
+            return data.classType == other.data.classType;
+        default:
+            return true;
+    }
+}
+
+
+bool sem::Type::operator != (const Type& other) const
+{
+    return !(*this == other);
+}
+
+
+const sem::Type sem::Type::NULL_TYPE = sem::Type{ sem::Type::Kind::NULL_TYPE };
+const sem::Type sem::Type::INTEGER = sem::Type{ sem::Type::Kind::INTEGER, &sem::Int32 };
 
 

+ 5 - 1
src/Type.h

@@ -48,6 +48,7 @@ public:
         kind{ Kind::NULL_TYPE }, data{ nullptr } {}
 
     Type(Class* classType);
+    Type(Kind kind, qlow::sem::Class* classType);
 
     inline Type(Kind kind) :
         kind{ kind }, data{ nullptr } {}
@@ -57,9 +58,12 @@ public:
 
     Class* getClassType(void);
     llvm::Type* getLlvmType(llvm::LLVMContext& context) const;
+    
+    bool operator == (const Type& other) const;
+    bool operator != (const Type& other) const;
 
+    static const Type NULL_TYPE;
     static const Type INTEGER;
-
 };