Nicolas Winkler пре 6 година
родитељ
комит
680ed98de0
16 измењених фајлова са 272 додато и 175 уклоњено
  1. 2 0
      src/Ast.cpp
  2. 67 11
      src/Ast.h
  3. 5 5
      src/AstVisitor.cpp
  4. 4 0
      src/AstVisitor.h
  5. 2 0
      src/Builtin.cpp
  6. 5 5
      src/CodegenVisitor.cpp
  7. 6 6
      src/CodegenVisitor.h
  8. 24 11
      src/Scope.cpp
  9. 23 16
      src/Scope.h
  10. 7 7
      src/Semantic.cpp
  11. 10 13
      src/Semantic.h
  12. 14 50
      src/Type.cpp
  13. 59 32
      src/Type.h
  14. 6 6
      src/TypeVisitor.h
  15. 2 0
      src/lexer.l
  16. 36 13
      src/parser.y

+ 2 - 0
src/Ast.cpp

@@ -19,6 +19,8 @@ std::unique_ptr<qlow::sem::SemanticObject> ClassName::accept(Visitor& v, sem::Sc
 }
 
 ACCEPT_DEFINITION(Class, StructureVisitor)
+ACCEPT_DEFINITION(ClassType, StructureVisitor)
+ACCEPT_DEFINITION(ArrayType, StructureVisitor)
 ACCEPT_DEFINITION(FeatureDeclaration, StructureVisitor)
 ACCEPT_DEFINITION(FieldDeclaration, StructureVisitor)
 ACCEPT_DEFINITION(MethodDefinition, StructureVisitor)

+ 67 - 11
src/Ast.h

@@ -44,6 +44,10 @@ namespace qlow
 
         struct Class;
 
+        struct Type;
+        struct ClassType;
+        struct ArrayType;
+        
         struct FeatureDeclaration;
 
         struct FieldDeclaration;
@@ -111,14 +115,66 @@ struct qlow::ast::Class : public AstObject
 };
 
 
+struct qlow::ast::Type : public AstObject
+{
+    inline Type(const CodePosition& cp) :
+        AstObject{ cp }
+    {
+    }
+    
+    virtual std::string asString(void) const = 0;
+};
+
+
+struct qlow::ast::ClassType : public ast::Type
+{
+    std::string typeName;
+    
+    inline ClassType(const std::string& typeName, const CodePosition& cp) :
+        Type{ cp },
+        typeName{ typeName }
+    {
+    }
+    
+    inline ClassType(std::string&& typeName, const CodePosition& cp) :
+        Type{ cp },
+        typeName{ std::move(typeName) }
+    {
+    }
+    
+    inline std::string asString(void) const override { return typeName; }
+    
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&) override;
+};
+
+
+struct qlow::ast::ArrayType : public ast::Type 
+{
+    std::unique_ptr<ast::Type> superType;
+    
+    inline ArrayType(std::unique_ptr<ast::Type> superType, const CodePosition& cp) :
+        Type{ cp },
+        superType{ std::move(superType) }
+    {
+    }
+    
+    inline std::string asString(void) const override {
+        return std::string("[") + superType->asString() + "]";
+    }
+    
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&) override;
+};
+
+
 struct qlow::ast::FeatureDeclaration : public AstObject
 {
     std::string name;
-    std::string type;
+    std::unique_ptr<ast::Type> type;
 
-    inline FeatureDeclaration(const std::string& type, const std::string& name, const CodePosition& cp) :
+    inline FeatureDeclaration(std::unique_ptr<ast::Type> type, const std::string& name, const CodePosition& cp) :
         AstObject{ cp },
-        name(name), type(type)
+        name{ name },
+        type{ std::move(type) }
     {
     }
 
@@ -128,8 +184,8 @@ struct qlow::ast::FeatureDeclaration : public AstObject
 
 struct qlow::ast::FieldDeclaration : public FeatureDeclaration
 {
-    inline FieldDeclaration(const std::string& type, const std::string& name, const CodePosition& cp) :
-        FeatureDeclaration(type, name, cp)
+    inline FieldDeclaration(std::unique_ptr<ast::Type> type, const std::string& name, const CodePosition& cp) :
+        FeatureDeclaration{ std::move(type), name, cp }
     {
     }
 
@@ -142,19 +198,19 @@ struct qlow::ast::MethodDefinition : public FeatureDeclaration
     OwningList<ArgumentDeclaration> arguments;
     std::unique_ptr<DoEndBlock> body;
 
-    inline MethodDefinition(const std::string& type, const std::string& name,
+    inline MethodDefinition(std::unique_ptr<ast::Type> type, const std::string& name,
             std::unique_ptr<DoEndBlock> body, const CodePosition& cp) :
-        FeatureDeclaration(type, name, cp),
-        body(std::move(body))
+        FeatureDeclaration{ std::move(type), name, cp },
+        body{ std::move(body) }
     {
     }
 
 
-    inline MethodDefinition(const std::string& type, const std::string& name,
+    inline MethodDefinition(std::unique_ptr<ast::Type> type, const std::string& name,
             OwningList<ArgumentDeclaration>&& arguments, std::unique_ptr<DoEndBlock> body, const CodePosition& cp) :
-        FeatureDeclaration(type, name, cp),
+        FeatureDeclaration{ std::move(type), name, cp },
         arguments(std::move(arguments)),
-        body(std::move(body))
+        body{ std::move(body) }
     {
     }
 

+ 5 - 5
src/AstVisitor.cpp

@@ -29,13 +29,13 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FieldDeclarati
 {
     auto f = std::make_unique<sem::Field>();
     f->name = ast.name;
-    auto type = scope.getType(ast.type);
+    auto* type = scope.getType(*ast.type);
     if (type) {
-        f->type = type.value();
+        f->type = type;
     }
     else {
         throw SemanticError(SemanticError::UNKNOWN_TYPE,
-            ast.type,
+            ast.type->asString(),
             ast.pos
         );
     }
@@ -45,7 +45,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FieldDeclarati
 
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::MethodDefinition& ast, sem::Scope& scope)
 {
-    auto returnType = scope.getType(ast.type);
+    auto returnType = scope.getType(*ast.type);
     if (!returnType) {
         throw SemanticError(SemanticError::UNKNOWN_TYPE,
             ast.type,
@@ -107,7 +107,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::DoEndBlock& as
     for (auto& statement : ast.statements) {
         
         if (ast::NewVariableStatement* nvs = dynamic_cast<ast::NewVariableStatement*>(statement.get()); nvs) {
-            auto type = body->scope.getType(nvs->type);
+            auto type = body->scope.getType(*nvs->type);
 
             if (!type)
                 throw SemanticError(SemanticError::UNKNOWN_TYPE, nvs->type, nvs->pos);

+ 4 - 0
src/AstVisitor.h

@@ -59,6 +59,8 @@ class qlow::StructureVisitor :
         sem::Scope&,
 
         ast::Class,
+        ast::ClassType,
+        ast::ArrayType,
         ast::FeatureDeclaration,
         ast::FieldDeclaration,
         ast::MethodDefinition,
@@ -80,6 +82,8 @@ public:
     using ReturnType = std::unique_ptr<sem::SemanticObject>;
 
     ReturnType visit(ast::Class& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::ClassType& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::ArrayType& ast, sem::Scope& scope) override;
     ReturnType visit(ast::FeatureDeclaration& ast, sem::Scope& scope) override;
     ReturnType visit(ast::FieldDeclaration& ast, sem::Scope& scope) override;
     ReturnType visit(ast::MethodDefinition& ast, sem::Scope& scope) override;

+ 2 - 0
src/Builtin.cpp

@@ -12,6 +12,7 @@ sem::NativeScope qlow::sem::generateNativeScope(void)
     
     sem::NativeScope scope;
     
+    /*
     std::unique_ptr<sem::Type> int32 =
         std::make_unique<sem::Type>(sem::Type::Kind::INTEGER, &sem::int32);
     std::unique_ptr<sem::Type> boolean =
@@ -20,6 +21,7 @@ sem::NativeScope qlow::sem::generateNativeScope(void)
     scope.types.insert({"Integer", std::move(int32)});
     scope.types.insert({"Boolean", std::move(boolean)});
     return scope;
+    */
 }
 
 

+ 5 - 5
src/CodegenVisitor.cpp

@@ -9,7 +9,7 @@
 
 using namespace qlow;
 
-std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::LocalVariableExpression& lve, llvm::IRBuilder<>& builder)
+std::pair<llvm::Value*, sem::Type*> ExpressionVisitor::visit(sem::LocalVariableExpression& lve, llvm::IRBuilder<>& builder)
 {
     assert(lve.var->allocaInst != nullptr);
     if (llvm::dyn_cast<llvm::AllocaInst>(lve.var->allocaInst)) {
@@ -22,7 +22,7 @@ std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::LocalVariableEx
 }
 
 
-std::pair<llvm::Value*, sem::Type> 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;
     using sem::Type;
@@ -59,7 +59,7 @@ std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::BinaryOperation
 }
 
 
-std::pair<llvm::Value*, sem::Type> 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;
     auto [value, type] = unop.arg->accept(*this, builder);
@@ -77,7 +77,7 @@ std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::UnaryOperation&
     }
 }
 
-std::pair<llvm::Value*, sem::Type> 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;
@@ -102,7 +102,7 @@ std::pair<llvm::Value*, sem::Type> ExpressionVisitor::visit(sem::FeatureCallExpr
     //return { nullptr, sem::Type::NULL_TYPE };
 }
 
-std::pair<llvm::Value*, sem::Type> 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)),

+ 6 - 6
src/CodegenVisitor.h

@@ -32,7 +32,7 @@ namespace qlow
 
 class qlow::ExpressionVisitor :
     public Visitor<
-        std::pair<llvm::Value*, sem::Type>,
+        std::pair<llvm::Value*, sem::Type*>,
         llvm::IRBuilder<>,
 
         sem::LocalVariableExpression,
@@ -43,11 +43,11 @@ class qlow::ExpressionVisitor :
     >
 {
 public:
-    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;
+    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;
 };
 
 

+ 24 - 11
src/Scope.cpp

@@ -1,4 +1,5 @@
 #include "Scope.h"
+#include "Ast.h"
 #include "Semantic.h"
 #include "Builtin.h"
 
@@ -24,23 +25,35 @@ sem::Method* sem::GlobalScope::getMethod(const std::string& name)
 }
 
 
-std::optional<sem::Type> sem::GlobalScope::getType(const std::string& name)
+sem::Type* sem::GlobalScope::getType(const ast::Type& name)
 {
+    if (const auto* arr = dynamic_cast<const ast::ArrayType*>(&name); arr) {
+        return new sem::ArrayType(getType(arr->arrayType));
+    }
+    
+    const auto* classType = dynamic_cast<const ast::ClassType*>(&name);
+   
+    if (!classType)
+        throw "internal error";
+    
+    /*
     auto native = NativeScope::getInstance().getType(name);
     if (native) {
         return native;
     }
+    */
     
-    auto t = classes.find(name);
+    auto t = classes.find(classType->classType->name);
     if (t != classes.end())
-        return std::make_optional(Type(t->second.get()));
-    return std::nullopt;
+        return new sem::ClassType(t->second);
+    
+    return nullptr;
 }
 
 
-std::optional<sem::Type> sem::GlobalScope::getReturnableType(void)
+sem::Type* sem::GlobalScope::getReturnableType(void)
 {
-    return std::nullopt;
+    return nullptr;
 }
 
 
@@ -56,7 +69,7 @@ std::string sem::GlobalScope::toString(void)
 }
 
 
-std::optional<sem::Type> sem::NativeScope::getType(const std::string& name)
+sem::Type* sem::NativeScope::getType(const std::string& name)
 {
     auto t = types.find(name);
     if (t != types.end())
@@ -119,13 +132,13 @@ std::string sem::ClassScope::toString(void)
 }
 
 
-std::optional<sem::Type> sem::ClassScope::getType(const std::string& name)
+sem::Type* sem::ClassScope::getType(const std::string& name)
 {
     return parentScope.getType(name);
 }
 
 
-std::optional<sem::Type> sem::ClassScope::getReturnableType(void)
+sem::Type* sem::ClassScope::getReturnableType(void)
 {
     return std::nullopt;
 }
@@ -159,13 +172,13 @@ sem::Method* sem::LocalScope::getMethod(const std::string& name)
 }
 
 
-std::optional<sem::Type> sem::LocalScope::getType(const std::string& name)
+sem::Type* sem::LocalScope::getType(const std::string& name)
 {
     return parentScope.getType(name);
 }
 
 
-std::optional<sem::Type> sem::LocalScope::getReturnableType(void)
+sem::Type* sem::LocalScope::getReturnableType(void)
 {
     return returnType;
 }

+ 23 - 16
src/Scope.h

@@ -9,6 +9,11 @@
 
 namespace qlow
 {
+    namespace ast
+    {
+        struct Type;
+    }
+    
     namespace sem
     {
         /*!
@@ -37,8 +42,8 @@ public:
     virtual ~Scope(void);
     virtual Variable* getVariable(const std::string& name) = 0;
     virtual Method* getMethod(const std::string& name) = 0;
-    virtual std::optional<Type> getType(const std::string& name) = 0;
-    virtual std::optional<Type> getReturnableType(void) = 0;
+    virtual Type* getType(const ast::Type& name) = 0;
+    virtual Type* getReturnableType(void) = 0;
 
     virtual std::string toString(void) = 0;
 };
@@ -52,8 +57,8 @@ public:
 public:
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);
-    virtual std::optional<Type> getType(const std::string& name);
-    virtual std::optional<Type> getReturnableType(void);
+    virtual Type* getType(const ast::Type& name);
+    virtual Type* getReturnableType(void);
 
     virtual std::string toString(void);
 };
@@ -65,7 +70,7 @@ class qlow::sem::NativeScope : public GlobalScope
 public:
     SymbolTable<Type> types;
 public:
-    virtual std::optional<Type> getType(const std::string& name);
+    virtual Type* getType(const ast::Type& name);
 
     virtual std::string toString(void);
     
@@ -85,8 +90,8 @@ public:
     }
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);
-    virtual std::optional<Type> getType(const std::string& name);
-    virtual std::optional<Type> getReturnableType(void);
+    virtual Type* getType(const ast::Type& name);
+    virtual Type* getReturnableType(void);
     virtual std::string toString(void);
 };
 
@@ -95,21 +100,23 @@ class qlow::sem::LocalScope : public Scope
 {
     Scope& parentScope;
     SymbolTable<Variable> localVariables;
-    Type returnType;
+    Type* returnType;
 public:
-    inline LocalScope(Scope& parentScope, const Type& returnType) :
-        parentScope{ parentScope }, returnType{ returnType }
-    {}
+    inline LocalScope(Scope& parentScope, Type* returnType) :
+        parentScope{ parentScope },
+        returnType{ returnType }
+    {
+    }
 
     inline LocalScope(Scope& parentScope) :
         parentScope{ parentScope }
     {
-        std::optional<Type> returnable = parentScope.getReturnableType();
+        Type* returnable = parentScope.getReturnableType();
         if (returnable) {
-            returnType = returnable.value();
+            returnType = returnable;
         }
         else {
-            returnType = Type(Type::Kind::NULL_TYPE);
+            returnType = nullptr;
         }
     }
 
@@ -118,8 +125,8 @@ public:
 
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);
-    virtual std::optional<Type> getType(const std::string& name);
-    virtual std::optional<Type> getReturnableType(void);
+    virtual Type* getType(const ast::Type& name);
+    virtual Type* getReturnableType(void);
     virtual std::string toString(void);
 };
 

+ 7 - 7
src/Semantic.cpp

@@ -66,12 +66,12 @@ std::unique_ptr<GlobalScope>
     }
     
     for (auto& [name, method] : globalScope->functions) {
-        auto returnType = globalScope->getType(method->astNode->type);
+        auto returnType = globalScope->getType(*method->astNode->type);
         if (returnType) {
             method->returnType = returnType.value();
         }
         else {
-            SemanticError se(SemanticError::UNKNOWN_TYPE, method->astNode->type, method->astNode->pos);
+            SemanticError se(SemanticError::UNKNOWN_TYPE, method->astNode->type->asString(), method->astNode->pos);
         }
         
         // otherwise add to the methods list
@@ -164,11 +164,11 @@ ReturnType ClassName::accept(Visitor& v, Arg arg) \
     return v.visit(*this, arg); \
 }
 
-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(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, llvm::Value*, qlow::gen::FunctionGenerator&) 
 ACCEPT_DEFINITION(DoEndBlock, StatementVisitor, llvm::Value*, qlow::gen::FunctionGenerator&) 

+ 10 - 13
src/Semantic.h

@@ -103,7 +103,7 @@ struct qlow::sem::Class : public SemanticObject
 
 struct qlow::sem::Variable : public SemanticObject
 {
-    Type type;
+    Type* type;
     std::string name;
 
     /// if this is a local variable, this stores a reference to the llvm
@@ -111,7 +111,7 @@ struct qlow::sem::Variable : public SemanticObject
     llvm::Value* allocaInst;
     
     Variable(void) = default;
-    inline Variable(Type type, std::string& name) :
+    inline Variable(Type* type, std::string& name) :
         type{ type }, name{ name }, allocaInst { nullptr } {}
         
     virtual std::string toString(void) const override;
@@ -120,9 +120,6 @@ struct qlow::sem::Variable : public SemanticObject
 
 struct qlow::sem::Field : public Variable
 {
-    Type type;
-    std::string name;
-    
     virtual std::string toString(void) const override;
 };
 
@@ -130,7 +127,7 @@ struct qlow::sem::Field : public Variable
 struct qlow::sem::Method : public SemanticObject
 {
     Class* containingType;
-    Type returnType;
+    Type* returnType;
     std::vector<Variable*> arguments;
     std::string name;
     ast::MethodDefinition* astNode;
@@ -140,7 +137,7 @@ struct qlow::sem::Method : public SemanticObject
 
     llvm::Function* llvmNode;
 
-    inline Method(Scope& parentScope, const Type& returnType) :
+    inline Method(Scope& parentScope, Type* returnType) :
         returnType{ returnType },
         scope{ parentScope }
     {
@@ -214,7 +211,7 @@ struct qlow::sem::ReturnStatement : public Statement
 
 struct qlow::sem::Expression :
     public SemanticObject,
-    public Visitable<std::pair<llvm::Value*, sem::Type>,
+    public Visitable<std::pair<llvm::Value*, sem::Type*>,
                      llvm::IRBuilder<>,
                      qlow::ExpressionVisitor>
 {
@@ -231,7 +228,7 @@ struct qlow::sem::LocalVariableExpression : public Expression
 {
     Variable* var;
 
-    virtual std::pair<llvm::Value*, sem::Type> 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;
 };
 
@@ -241,7 +238,7 @@ struct qlow::sem::BinaryOperation : public Operation
     std::unique_ptr<Expression> left;
     std::unique_ptr<Expression> right;
     
-    virtual std::pair<llvm::Value*, sem::Type> 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;
 };
@@ -251,7 +248,7 @@ struct qlow::sem::UnaryOperation : public Operation
 {
     qlow::ast::UnaryOperation::Side side;
     std::unique_ptr<Expression> arg;
-    virtual std::pair<llvm::Value*, sem::Type> 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;
 };
 
@@ -260,7 +257,7 @@ struct qlow::sem::FeatureCallExpression : public Expression
 {
     Method* callee;
     OwningList<Expression> arguments;
-    virtual std::pair<llvm::Value*, sem::Type> 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;
 };
@@ -275,7 +272,7 @@ struct qlow::sem::IntConst : public Expression
     {
     }
     
-    virtual std::pair<llvm::Value*, sem::Type> accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
+    virtual std::pair<llvm::Value*, sem::Type*> accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
 };
 
 

+ 14 - 50
src/Type.cpp

@@ -9,76 +9,40 @@
 
 using namespace qlow;
 
-sem::Type::Type(sem::Class* classType) :
-    kind{ Kind::CLASS }
-{
-    data.classType = classType;
-}
-
 
-sem::Type::Type(Kind kind, Class* classType) :
-    kind{ kind }
+sem::Type::~Type(void)
 {
-    data.classType = classType;
 }
 
-bool sem::Type::isClassType(void) const
-{
-    return kind == Kind::CLASS;
-}
 
-
-bool sem::Type::isNative(void) const
+bool sem::Type::operator == (const Type& other) const
 {
-    return kind != Kind::CLASS;
+    return this == &other;
 }
 
 
-sem::Class* sem::Type::getClassType(void)
+bool sem::Type::operator != (const Type& other) const
 {
-    if (kind != Kind::CLASS)
-        throw "internal error";
-    return data.classType;
+    return !(*this != other);
 }
 
 
-llvm::Type* sem::Type::getLlvmType(llvm::LLVMContext& context) const
-{
-    switch (kind) {
-        case Kind::NULL_TYPE:
-            return llvm::Type::getVoidTy(context);
-        case Kind::INTEGER:
-            return llvm::Type::getInt32Ty(context);
-        case Kind::BOOLEAN:
-            return llvm::Type::getInt1Ty(context);
-        case Kind::CLASS:
-            return data.classType->llvmType;
-    }
-}
+sem::Type* sem::Type::INTEGER = new sem::NativeType(sem::NativeType::Type::INTEGER);
+sem::Type* sem::Type::BOOLEAN = new sem::NativeType(sem::NativeType::Type::BOOLEAN);
 
 
-bool sem::Type::operator == (const Type& other) const
+llvm::Type* sem::ClassType::getLlvmType (llvm::LLVMContext& context) const
 {
-    if (other.kind != this->kind)
-        return false;
-    
-    switch (kind) {
-        case Kind::CLASS:
-            return data.classType == other.data.classType;
-        default:
-            return true;
-    }
+    return classType->llvmType;
 }
 
 
-bool sem::Type::operator != (const Type& other) const
+llvm::Type* sem::NativeType::getLlvmType (llvm::LLVMContext& context) const
 {
-    return !(*this == other);
+    switch(type) {
+        case INTEGER:
+            context
+    }
 }
 
 
-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 };
-const sem::Type sem::Type::BOOLEAN = sem::Type{ sem::Type::Kind::BOOLEAN, &sem::boolean };
-
-

+ 59 - 32
src/Type.h

@@ -1,6 +1,8 @@
 #ifndef QLOW_SEM_TYPE_H
 #define QLOW_SEM_TYPE_H
 
+#include <memory>
+
 namespace llvm {
     class Type;
     class LLVMContext;
@@ -12,13 +14,16 @@ namespace qlow
     {
         // forward declarations
         struct Class;
-        struct NativeType;
     }
 
 
     namespace sem
     {
         class Type;
+        
+        class ClassType;
+        class ArrayType;
+        class NativeType;
     }
 }
 
@@ -26,46 +31,68 @@ namespace qlow
 class qlow::sem::Type
 {
 public:
-    enum class Kind
-    {
-        NULL_TYPE,
-        INTEGER,
-        BOOLEAN,
-        CLASS,
-    };
+    virtual ~Type(void);
 
-private:
-    union Data
-    {
-        Class* classType;
-    };
+    virtual bool isClassType(void) const = 0;
+    virtual bool isNativeType(void) const = 0;
+    virtual bool isArrayType(void) const = 0;
 
-    Kind kind;
-    Data data;
+    Class* getClassType(void);
+    virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const = 0;
+    
+    virtual bool operator == (const Type& other) const;
+    virtual bool operator != (const Type& other) const;
+    
+    static Type* INTEGER;
+    static Type* BOOLEAN;
+};
 
-public:
 
-    inline Type(void) :
-        kind{ Kind::NULL_TYPE }, data{ nullptr } {}
+class qlow::sem::ClassType : public Type
+{
+    sem::Class* classType;
+public:
+    inline bool isClassType(void) const override { return true; }
+    inline bool isNativeType(void) const override { return false; }
+    inline bool isArrayType(void) const override { return false; }
+    
+    virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
+    inline sem::Class* getClassType(void) { return classType; }
+};
 
-    Type(Class* classType);
-    Type(Kind kind, qlow::sem::Class* classType);
 
-    inline Type(Kind kind) :
-        kind{ kind }, data{ nullptr } {}
+class qlow::sem::ArrayType : public Type
+{
+    sem::Type* arrayType;
+public:
+    inline bool isClassType(void) const override { return false; }
+    inline bool isNativeType(void) const override { return false; }
+    inline bool isArrayType(void) const override { return true; }
+    
+    inline sem::Type* getArrayType(void) { return arrayType; }
+};
 
-    bool isClassType(void) const;
-    bool isNative(void) const;
 
-    Class* getClassType(void);
-    llvm::Type* getLlvmType(llvm::LLVMContext& context) const;
+class qlow::sem::NativeType : public Type
+{
+public:
+    enum Type {
+        INTEGER,
+        BOOLEAN
+    };
     
-    bool operator == (const Type& other) const;
-    bool operator != (const Type& other) const;
-
-    static const Type NULL_TYPE;
-    static const Type INTEGER;
-    static const Type BOOLEAN;
+    Type type;
+    
+    inline NativeType(Type type) :
+        type{ type }
+    {
+    }
+    
+    inline bool isClassType(void) const override { return false; }
+    inline bool isNativeType(void) const override { return true; }
+    inline bool isArrayType(void) const override { return false; }
+    
+    virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const;
 };
 
 

+ 6 - 6
src/TypeVisitor.h

@@ -15,7 +15,7 @@ namespace qlow
 
 class qlow::sem::TypeVisitor :
     public Visitor<
-        qlow::sem::Type,
+        qlow::sem::Type*,
         const sem::SymbolTable<sem::Class>,
 
         sem::Expression,
@@ -27,11 +27,11 @@ class qlow::sem::TypeVisitor :
 {
 
 public:
-    qlow::sem::Type visit(sem::Expression& expr, const sem::SymbolTable<sem::Class>& classes) override;
-    qlow::sem::Type visit(sem::UnaryOperation& expr, const sem::SymbolTable<sem::Class>& classes) override;
-    qlow::sem::Type visit(sem::BinaryOperation& expr, const sem::SymbolTable<sem::Class>& classes) override;
-    qlow::sem::Type visit(sem::FeatureCallExpression& expr, const sem::SymbolTable<sem::Class>& classes) override;
-    qlow::sem::Type visit(sem::IntConst& expr, const sem::SymbolTable<sem::Class>& classes) override;
+    qlow::sem::Type* visit(sem::Expression& expr, const sem::SymbolTable<sem::Class>& classes) override;
+    qlow::sem::Type* visit(sem::UnaryOperation& expr, const sem::SymbolTable<sem::Class>& classes) override;
+    qlow::sem::Type* visit(sem::BinaryOperation& expr, const sem::SymbolTable<sem::Class>& classes) override;
+    qlow::sem::Type* visit(sem::FeatureCallExpression& expr, const sem::SymbolTable<sem::Class>& classes) override;
+    qlow::sem::Type* visit(sem::IntConst& expr, const sem::SymbolTable<sem::Class>& classes) override;
 };
 
 #endif // QLOW_SEM_TYPEVISITOR_H

+ 2 - 0
src/lexer.l

@@ -111,6 +111,8 @@ extern const char* qlow_parser_filename;
 
 "("                     return SET_TOKEN(ROUND_LEFT);
 ")"                     return SET_TOKEN(ROUND_RIGHT);
+"["                     return SET_TOKEN(SQUARE_LEFT);
+"]"                     return SET_TOKEN(SQUARE_RIGHT);
 
 "false"                 return SET_TOKEN(FALSE);
 "true"                  return SET_TOKEN(TRUE);

+ 36 - 13
src/parser.y

@@ -93,6 +93,11 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %union {
     std::vector<std::unique_ptr<qlow::ast::AstObject>>* topLevel;
     qlow::ast::Class* classDefinition;
+    
+    qlow::ast::Type* type;
+    qlow::ast::ClassType* classType;
+    qlow::ast::ArrayType* arrayType;
+    
     qlow::ast::FeatureDeclaration* featureDeclaration;
     std::vector<std::unique_ptr<qlow::ast::FeatureDeclaration>>* featureList;
     std::vector<std::unique_ptr<qlow::ast::ArgumentDeclaration>>* argumentList;
@@ -128,11 +133,12 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %token <token> CLASS DO END IF ELSE WHILE RETURN
 %token <token> NEW_LINE
 %token <token> SEMICOLON COLON COMMA DOT ASSIGN
-%token <token> ROUND_LEFT ROUND_RIGHT
+%token <token> ROUND_LEFT ROUND_RIGHT SQUARE_LEFT SQUARE_RIGHT
 %token <string> UNEXPECTED_SYMBOL
 
 %type <topLevel> topLevel 
 %type <classDefinition> classDefinition
+%type <type> type 
 %type <featureDeclaration> featureDeclaration
 %type <fieldDeclaration> fieldDeclaration
 %type <methodDefinition> methodDefinition
@@ -194,6 +200,20 @@ classDefinition:
         delete $2; delete $3; $2 = 0; $3 = 0;
     };
 
+type:
+    IDENTIFIER {
+        $$ = new qlow::ast::ClassType(std::move(*$1), @$);
+        delete $1; $1 = nullptr;
+    }
+    |
+    SQUARE_LEFT type SQUARE_RIGHT {
+        $$ = new qlow::ast::ArrayType(std::unique_ptr<qlow::ast::Type>($2), @$);
+    }
+    |
+    SQUARE_LEFT error SQUARE_RIGHT {
+        reportError(qlow::SyntaxError(@2));
+    };
+    
 
 featureList:
     /* empty */ {
@@ -217,31 +237,34 @@ featureDeclaration:
 
 
 fieldDeclaration:
-    IDENTIFIER COLON IDENTIFIER {
-        $$ = new FieldDeclaration(*$3, *$1, @$);
-        delete $3; delete $1; $1 = $3 = 0;
+    IDENTIFIER COLON type {
+        $$ = new FieldDeclaration(std::unique_ptr<qlow::ast::Type>($3), std::move(*$1), @$);
+        delete $1; $1 = nullptr;
     };
 
 
 methodDefinition:
-    IDENTIFIER COLON IDENTIFIER doEndBlock {
-        $$ = new MethodDefinition(*$3, *$1, std::move(std::unique_ptr<DoEndBlock>($4)), @$);
-        delete $3; delete $1; $1 = $3 = 0;
+    IDENTIFIER COLON type doEndBlock {
+        $$ = new MethodDefinition(std::unique_ptr<qlow::ast::Type>($3), *$1, std::unique_ptr<DoEndBlock>($4), @$);
+        delete $1; $1 = nullptr;
     }
     |
     IDENTIFIER doEndBlock {
-        $$ = new MethodDefinition("", *$1, std::move(std::unique_ptr<DoEndBlock>($2)), @$);
-        delete $1; $1 = 0;
+        $$ = new MethodDefinition(nullptr, *$1, std::move(std::unique_ptr<DoEndBlock>($2)), @$);
+        delete $1; $1 = nullptr;
     }
     |
     IDENTIFIER
-        ROUND_LEFT argumentList ROUND_RIGHT COLON IDENTIFIER doEndBlock {
-        $$ = new MethodDefinition(*$6, *$1, std::move(*$3), std::move(std::unique_ptr<DoEndBlock>($7)), @$);
-        delete $6; delete $1; delete $3; $1 = $6 = nullptr; $3 = nullptr;
+        ROUND_LEFT argumentList ROUND_RIGHT COLON type doEndBlock {
+        $$ = new MethodDefinition(std::unique_ptr<qlow::ast::Type>($6),
+                                 *$1, std::move(*$3),
+                                 std::unique_ptr<DoEndBlock>($7),
+                                 @$);
+        delete $1; delete $3; $1 = nullptr; $3 = nullptr;
     }
     |
     IDENTIFIER ROUND_LEFT argumentList ROUND_RIGHT doEndBlock {
-        $$ = new MethodDefinition("", *$1, std::move(*$3), std::move(std::unique_ptr<DoEndBlock>($5)), @$);
+        $$ = new MethodDefinition(nullptr, *$1, std::move(*$3), std::move(std::unique_ptr<DoEndBlock>($5)), @$);
         delete $1; delete $3; $1 = nullptr; $3 = nullptr;
     };