Quellcode durchsuchen

reworked types again

Nicolas Winkler vor 6 Jahren
Ursprung
Commit
da24db8b45
14 geänderte Dateien mit 498 neuen und 459 gelöschten Zeilen
  1. 24 24
      src/Builtin.cpp
  2. 5 5
      src/Builtin.h
  3. 6 6
      src/Cast.h
  4. 6 6
      src/CodegenVisitor.cpp
  5. 34 36
      src/Scope.cpp
  6. 21 21
      src/Scope.h
  7. 19 22
      src/ast/AstVisitor.cpp
  8. 7 10
      src/sem/CodeGeneration.cpp
  9. 49 104
      src/sem/Context.cpp
  10. 19 27
      src/sem/Context.h
  11. 12 5
      src/sem/Semantic.cpp
  12. 21 21
      src/sem/Semantic.h
  13. 173 113
      src/sem/Type.cpp
  14. 102 59
      src/sem/Type.h

+ 24 - 24
src/Builtin.cpp

@@ -17,18 +17,18 @@ sem::NativeScope qlow::sem::generateNativeScope(Context& context)
     
     NativeScope scope{ context };
 
-    std::map<std::string, Type::Native> natives = {
-        { "Void",       Type::Native::VOID },
-        { "Boolean",    Type::Native::BOOLEAN },
-        { "Integer",    Type::Native::INTEGER },
+    std::map<std::string, NativeType::NType> natives = {
+        { "Void",       NativeType::NType::VOID },
+        { "Boolean",    NativeType::NType::BOOLEAN },
+        { "Integer",    NativeType::NType::INTEGER },
     };
 
     for (auto [name, type] : natives) {
-        TypeId id = context.createNativeType(name, type);
+        Type* id = context.getNativeType(type);
         scope.addNativeType(name, type, id);
     }
     
-    /*std::map<std::string, NativeType::Type> natives = {
+    /*std::map<std::string, NativeType::NType> natives = {
         { "Boolean",    NativeType::BOOLEAN },
         { "Char",       NativeType::CHAR },
         { "String",     NativeType::STRING },
@@ -37,7 +37,7 @@ sem::NativeScope qlow::sem::generateNativeScope(Context& context)
         { "Float64",    NativeType::FLOAT64 },
     };
     
-    std::map<std::string, NativeType::Type> integers = {
+    std::map<std::string, NativeType::NType> integers = {
         { "Integer",    NativeType::INTEGER },
         { "Int8",       NativeType::INT8 },
         { "Int16",      NativeType::INT16 },
@@ -134,23 +134,23 @@ void qlow::sem::fillNativeScope(NativeScope& scope)
 {
     Context& context = scope.getContext();
 
-    TypeId integer = context.getNativeTypeId(Type::Native::INTEGER);
-    context.getType(integer).setTypeScope(
-        std::make_unique<NativeTypeScope>(generateNativeTypeScope(context, Type::Native::INTEGER))
+    Type* integer = context.getNativeType(NativeType::NType::INTEGER);
+    integer->setTypeScope(
+        std::make_unique<NativeTypeScope>(generateNativeTypeScope(context, NativeType::NType::INTEGER))
     );
 }
 
 
-sem::NativeTypeScope qlow::sem::generateNativeTypeScope(Context& context, Type::Native native)
+sem::NativeTypeScope qlow::sem::generateNativeTypeScope(Context& context, NativeType::NType native)
 {
-    NativeTypeScope scope{ context, context.getNativeTypeId(native) };
+    NativeTypeScope scope{ context, context.getNativeType(native) };
 
 
     scope.nativeMethods.insert(
         { "+",
             std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
-                context.getNativeTypeId(Type::Native::INTEGER),
-                context.getNativeTypeId(native),
+                context.getNativeType(NativeType::NType::INTEGER),
+                context.getNativeType(native),
                 [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
                     return builder.CreateAdd(a, b);
                 }
@@ -160,8 +160,8 @@ sem::NativeTypeScope qlow::sem::generateNativeTypeScope(Context& context, Type::
     scope.nativeMethods.insert(
         { "-",
             std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
-                context.getNativeTypeId(Type::Native::INTEGER),
-                context.getNativeTypeId(native),
+                context.getNativeType(NativeType::NType::INTEGER),
+                context.getNativeType(native),
                 [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
                     return builder.CreateSub(a, b);
                 }
@@ -171,8 +171,8 @@ sem::NativeTypeScope qlow::sem::generateNativeTypeScope(Context& context, Type::
     scope.nativeMethods.insert(
         { "*",
             std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
-                context.getNativeTypeId(Type::Native::INTEGER),
-                context.getNativeTypeId(native),
+                context.getNativeType(NativeType::NType::INTEGER),
+                context.getNativeType(native),
                 [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
                     return builder.CreateMul(a, b);
                 }
@@ -182,8 +182,8 @@ sem::NativeTypeScope qlow::sem::generateNativeTypeScope(Context& context, Type::
     scope.nativeMethods.insert(
         { "/",
             std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
-                context.getNativeTypeId(Type::Native::INTEGER),
-                context.getNativeTypeId(native),
+                context.getNativeType(NativeType::NType::INTEGER),
+                context.getNativeType(native),
                 [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
                     return builder.CreateSDiv(a, b);
                 }
@@ -195,8 +195,8 @@ sem::NativeTypeScope qlow::sem::generateNativeTypeScope(Context& context, Type::
     scope.nativeMethods.insert(
         { "==",
             std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
-                context.getNativeTypeId(Type::Native::BOOLEAN),
-                context.getNativeTypeId(native),
+                context.getNativeType(NativeType::NType::BOOLEAN),
+                context.getNativeType(native),
                 [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
                     return builder.CreateICmpEQ(a, b);
                 }
@@ -206,8 +206,8 @@ sem::NativeTypeScope qlow::sem::generateNativeTypeScope(Context& context, Type::
     scope.nativeMethods.insert(
         { "!=",
             std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
-                context.getNativeTypeId(Type::Native::BOOLEAN),
-                context.getNativeTypeId(native),
+                context.getNativeType(NativeType::NType::BOOLEAN),
+                context.getNativeType(native),
                 [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
                     return builder.CreateICmpNE(a, b);
                 }

+ 5 - 5
src/Builtin.h

@@ -18,7 +18,7 @@ namespace qlow
         NativeScope generateNativeScope(Context& context);
         void fillNativeScope(NativeScope& scope);
 
-        NativeTypeScope generateNativeTypeScope(Context& context, Type::Native native);
+        NativeTypeScope generateNativeTypeScope(Context& context, NativeType::NType native);
         
         struct NativeMethod;
         struct UnaryNativeMethod;
@@ -29,7 +29,7 @@ namespace qlow
 
 struct qlow::sem::NativeMethod : public sem::Method
 {
-    inline NativeMethod(NativeScope& scope, TypeId returnType) :
+    inline NativeMethod(NativeScope& scope, Type* returnType) :
         Method{ scope, returnType, false }
     {
     }
@@ -44,7 +44,7 @@ struct qlow::sem::UnaryNativeMethod : public sem::NativeMethod
     std::function<llvm::Value*(llvm::IRBuilder<>&, llvm::Value*)> generator;
     
     inline UnaryNativeMethod(NativeScope& scope,
-                             TypeId returnType,
+                             Type* returnType,
                              const std::function
                              <llvm::Value*(llvm::IRBuilder<>&, llvm::Value*)>& generator) :
         NativeMethod{ scope, returnType },
@@ -66,8 +66,8 @@ struct qlow::sem::BinaryNativeMethod : public sem::NativeMethod
     Variable argument;
     
     inline BinaryNativeMethod(NativeScope& scope,
-                              TypeId returnType,
-                              TypeId argumentType,
+                              Type* returnType,
+                              Type* argumentType,
                               Func&& generator) :
         NativeMethod{ scope, returnType },
         generator{ generator },

+ 6 - 6
src/Cast.h

@@ -19,17 +19,17 @@ namespace qlow
 class qlow::sem::Cast
 {
 public:
-    TypeId to;
-    
+    Type* to;
+
     bool isExplicit;
-    
-    inline Cast(TypeId to) :
+
+    inline Cast(Type* to) :
         to{ to },
         isExplicit{ true }
     {
     }
-    
-    inline Cast(TypeId to, bool isExplicit) :
+
+    inline Cast(Type* to, bool isExplicit) :
         to{ to },
         isExplicit{ isExplicit }
     {

+ 6 - 6
src/CodegenVisitor.cpp

@@ -18,7 +18,7 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::LocalVariableExpression& lve,
 {
     assert(lve.var->allocaInst != nullptr);
     if (llvm::dyn_cast<llvm::AllocaInst>(lve.var->allocaInst)) {
-        llvm::Type* returnType = lve.context.getLlvmType(lve.type, builder.getContext());
+        llvm::Type* returnType = lve.type->getLlvmType(builder.getContext());
         llvm::Value* val = builder.CreateLoad(returnType, lve.var->allocaInst);
         return val;
     }
@@ -34,7 +34,7 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::UnaryOperation& unop, llvm::IR
     auto value = unop.arg->accept(*this, builder);
     auto& type = unop.arg->type;
     
-    if (type == sem::NO_TYPE)//(type->equals(sem::NativeType(sem::NativeType::Type::VOID)))
+    if (type == nullptr)//(type->equals(sem::NativeType(sem::NativeType::Type::VOID)))
         throw "invalid type to negate";
 
     /*
@@ -133,10 +133,10 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::NewExpression& nexpr, llvm::IR
     using llvm::Value;
 
     sem::Context& semCtxt = nexpr.context;
-    sem::TypeId type = nexpr.type;
+    sem::Type* type = nexpr.type;
 
     const llvm::DataLayout& layout = builder.GetInsertBlock()->getModule()->getDataLayout();
-    llvm::Type* llvmTy = semCtxt.getLlvmType(type, builder.getContext())->getPointerElementType();
+    llvm::Type* llvmTy = type->getLlvmType(builder.getContext())->getPointerElementType();
     auto allocSize = layout.getTypeAllocSize(llvmTy);
 
     auto size = llvm::ConstantInt::get(builder.getContext(), llvm::APInt(32, allocSize, false));
@@ -204,7 +204,7 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::FieldAccessExpression& access,
 
     sem::Context& semCtxt = access.context;
     
-    Type* type = semCtxt.getLlvmType(access.target->type, builder.getContext());
+    Type* type = access.target->type->getLlvmType(builder.getContext());
     
     if (type == nullptr)
         throw "no access type";
@@ -313,7 +313,7 @@ llvm::Value* LValueVisitor::visit(sem::FieldAccessExpression& access, qlow::gen:
     using llvm::Type;
     sem::Context& semCtxt = access.context;
     
-    Type* type = semCtxt.getLlvmType(access.target->type, fg.builder.getContext());
+    Type* type = access.target->type->getLlvmType(fg.builder.getContext());
     
     if (type == nullptr)
         throw "no access type";

+ 34 - 36
src/Scope.cpp

@@ -13,7 +13,7 @@ sem::Scope::~Scope(void)
 
 
 sem::Method* sem::Scope::resolveMethod(const std::string& name,
-    const std::vector<TypeId> argumentTypes)
+    const std::vector<Type*>& argumentTypes)
 {
     sem::Method* m = getMethod(name);
     if (!m)
@@ -46,22 +46,22 @@ sem::Method* sem::GlobalScope::getMethod(const std::string& name)
 }
 
 
-sem::TypeId sem::GlobalScope::getType(const ast::Type* name)
+sem::Type* sem::GlobalScope::getType(const ast::Type* name)
 {
     if (name == nullptr) {
-        return context.getVoidTypeId();
+        return context.getVoidType();
     }
 
     if (const auto* arr = dynamic_cast<const ast::ArrayType*>(name); arr) {
-        return context.createArrayType(getType(arr->arrayType.get()));
+        return context.getArrayType(getType(arr->arrayType.get()));
     }
     
-    if (const auto* ptr = dynamic_cast<const ast::PointerType*>(name)) {
+    /*if (const auto* ptr = dynamic_cast<const ast::PointerType*>(name)) {
         return context.createPointerType(getType(ptr->derefType.get()));
-    }
+    }*/
     
     auto native = context.getNativeScope().getType(name);
-    if (native != sem::NO_TYPE) {
+    if (native != nullptr) {
         return native;
     }
 
@@ -74,15 +74,15 @@ sem::TypeId sem::GlobalScope::getType(const ast::Type* name)
     
     auto t = classes.find(classType->typeName);
     if (t != classes.end())
-        return context.createClassType(t->second.get());
+        return context.getClassType(t->second.get());
     
-    return NO_TYPE;
+    return nullptr;
 }
 
 
-qlow::sem::TypeId sem::GlobalScope::getReturnableType(void)
+qlow::sem::Type* sem::GlobalScope::getReturnableType(void)
 {
-    return NO_TYPE;
+    return nullptr;
 }
 
 
@@ -98,36 +98,38 @@ std::string sem::GlobalScope::toString(void)
 }
 
 
-sem::TypeId sem::NativeScope::getType(const ast::Type* name)
+sem::Type* sem::NativeScope::getType(const ast::Type* name)
 {
+    if (name == nullptr) {
+        return context.getVoidType();
+    }
     if (const auto* arr = dynamic_cast<const ast::ArrayType*>(name); arr) {
-        return context.createArrayType(getType(arr->arrayType.get()));
+        return context.getArrayType(getType(arr->arrayType.get()));
     }
     
     const auto* classType = dynamic_cast<const ast::ClassType*>(name);
    
     if (!classType)
-        return NO_TYPE;
+        return nullptr;
 
-    
     auto t = types.find(classType->typeName);
     if (t != types.end())
         return t->second;
     
-    return NO_TYPE;
+    return nullptr;
 }
 
 
-sem::TypeId sem::NativeScope::getType(Type::Native nt)
+sem::Type* sem::NativeScope::getType(NativeType::NType nt)
 {
     if (typesByNative.find(nt) == typesByNative.end())
-        return sem::NO_TYPE;
+        return nullptr;
     else
         return typesByNative[nt];
 }
 
 
-void sem::NativeScope::addNativeType(std::string name, Type::Native nt, TypeId id)
+void sem::NativeScope::addNativeType(std::string name, NativeType::NType nt, Type* id)
 {
     types.emplace(std::move(name), id);
     typesByNative.emplace(nt, id);
@@ -180,15 +182,15 @@ std::string sem::ClassScope::toString(void)
 }
 
 
-sem::TypeId sem::ClassScope::getType(const ast::Type* name)
+sem::Type* sem::ClassScope::getType(const ast::Type* name)
 {
     return parentScope.getType(name);
 }
 
 
-sem::TypeId sem::ClassScope::getReturnableType(void)
+sem::Type* sem::ClassScope::getReturnableType(void)
 {
-    return NO_TYPE;
+    return nullptr;
 }
 
 
@@ -243,13 +245,13 @@ sem::Method* sem::LocalScope::getMethod(const std::string& name)
 }
 
 
-sem::TypeId sem::LocalScope::getType(const ast::Type* name)
+sem::Type* sem::LocalScope::getType(const ast::Type* name)
 {
     return parentScope.getType(name);
 }
 
 
-sem::TypeId sem::LocalScope::getReturnableType(void)
+sem::Type* sem::LocalScope::getReturnableType(void)
 {
     return returnType;
 }
@@ -269,10 +271,8 @@ std::string sem::LocalScope::toString(void)
 
 sem::Variable* sem::TypeScope::getVariable(const std::string& name)
 {
-    Type& ty = context.getType(type);
-    
-    if (ty.getKind() == Type::Kind::CLASS) {
-        auto& fields = ty.getClass()->fields;
+    if (type->isClassType()) {
+        auto& fields = type->getClass()->fields;
         if (fields.find(name) != fields.end())
             return fields[name].get();
     }
@@ -283,10 +283,8 @@ sem::Variable* sem::TypeScope::getVariable(const std::string& name)
 
 sem::Method* sem::TypeScope::getMethod(const std::string& name)
 {
-    Type& ty = context.getType(type);
-    
-    if (ty.getKind() == Type::Kind::CLASS) {
-        auto classRef = ty.getClass();
+    if (type->isClassType()) {
+        auto classRef = type->getClass();
         auto& methods = classRef->methods;
         if (methods.find(name) != methods.end())
             return methods[name].get();
@@ -295,15 +293,15 @@ sem::Method* sem::TypeScope::getMethod(const std::string& name)
 }
 
 
-sem::TypeId sem::TypeScope::getType(const ast::Type* name)
+sem::Type* sem::TypeScope::getType(const ast::Type* name)
 {
-    return NO_TYPE;
+    return nullptr;
 }
 
 
-sem::TypeId sem::TypeScope::getReturnableType(void)
+sem::Type* sem::TypeScope::getReturnableType(void)
 {
-    return NO_TYPE;
+    return nullptr;
 }
 
 

+ 21 - 21
src/Scope.h

@@ -60,10 +60,10 @@ public:
     virtual ~Scope(void);
     virtual Variable* getVariable(const std::string& name) = 0;
     virtual Method* getMethod(const std::string& name) = 0;
-    virtual TypeId getType(const ast::Type* name) = 0;
-    virtual TypeId getReturnableType(void) = 0;
+    virtual Type* getType(const ast::Type* name) = 0;
+    virtual Type* getReturnableType(void) = 0;
     virtual Method* resolveMethod(const std::string& name,
-        const std::vector<TypeId> argumentTypes);
+        const std::vector<Type*>& argumentTypes);
 
     virtual std::string toString(void) = 0;
 
@@ -83,8 +83,8 @@ public:
 
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);
-    virtual TypeId getType(const ast::Type* name);
-    virtual TypeId getReturnableType(void);
+    virtual Type* getType(const ast::Type* name);
+    virtual Type* getReturnableType(void);
 
     inline const SymbolTable<Class>& getClasses(void) const { return classes; }
     inline const SymbolTable<Method>& getMethods(void) const { return functions; }
@@ -96,15 +96,15 @@ public:
 class qlow::sem::NativeScope : public GlobalScope
 {
 protected:
-    std::unordered_map<std::string, TypeId> types;
-    std::map<Type::Native, TypeId> typesByNative;
+    std::unordered_map<std::string, Type*> types;
+    std::map<NativeType::NType, Type*> typesByNative;
 public:
     inline NativeScope(Context& context) :
         GlobalScope{ context } {}
 
-    virtual TypeId getType(const ast::Type* name);
-    virtual TypeId getType(Type::Native nt);
-    virtual void addNativeType(std::string name, Type::Native nt, TypeId id);
+    virtual Type* getType(const ast::Type* name);
+    virtual Type* getType(NativeType::NType nt);
+    virtual void addNativeType(std::string name, NativeType::NType nt, Type* id);
 
     virtual std::string toString(void);
 };
@@ -123,8 +123,8 @@ public:
     }
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);
-    virtual TypeId getType(const ast::Type* name);
-    virtual TypeId getReturnableType(void);
+    virtual Type* getType(const ast::Type* name);
+    virtual Type* getReturnableType(void);
     virtual std::string toString(void);
 };
 
@@ -133,7 +133,7 @@ class qlow::sem::LocalScope : public Scope
 {
     Scope& parentScope;
     SymbolTable<Variable> localVariables;
-    TypeId returnType;
+    Type* returnType;
     Method* enclosingMethod;
 public:
     LocalScope(Scope& parentScope, Method* enclosingMethod);
@@ -144,8 +144,8 @@ public:
 
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);
-    virtual TypeId getType(const ast::Type* name);
-    virtual TypeId getReturnableType(void);
+    virtual Type* getType(const ast::Type* name);
+    virtual Type* getReturnableType(void);
     virtual std::string toString(void);
 };
 
@@ -153,9 +153,9 @@ public:
 class qlow::sem::TypeScope : public Scope
 {
 protected:
-    TypeId type;
+    Type* type;
 public:
-    inline TypeScope(Context& context, TypeId type) :
+    inline TypeScope(Context& context, Type* type) :
         Scope{ context },
         type{ type }
     {
@@ -166,8 +166,8 @@ public:
     
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);
-    virtual TypeId getType(const ast::Type* name);
-    virtual TypeId getReturnableType(void);
+    virtual Type* getType(const ast::Type* name);
+    virtual Type* getReturnableType(void);
     virtual std::string toString(void);
 
     virtual bool isNativeTypeScope(void) const;
@@ -178,7 +178,7 @@ class qlow::sem::NativeTypeScope : public TypeScope
 {
 public:
     SymbolTable<NativeMethod> nativeMethods;
-    inline NativeTypeScope(Context& context, TypeId type) :
+    inline NativeTypeScope(Context& context, Type* type) :
         TypeScope{ context, type }
     {
     }
@@ -191,7 +191,7 @@ public:
     virtual Method* getMethod(const std::string& name);
     virtual bool isNativeTypeScope(void) const;
 
-    TypeId implementInlineOperation(const std::string&, llvm::Value* a);
+    Type* implementInlineOperation(const std::string&, llvm::Value* a);
 };
 
 

+ 19 - 22
src/ast/AstVisitor.cpp

@@ -30,8 +30,8 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FieldDeclarati
 {
     auto f = std::make_unique<sem::Field>(scope.getContext());
     f->name = ast.name;
-    auto type = scope.getType(ast.type.get());
-    if (type != sem::NO_TYPE) {
+    auto* type = scope.getType(ast.type.get());
+    if (type != nullptr) {
         f->type = type;
     }
     else {
@@ -47,7 +47,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.get());
-    if (returnType == sem::NO_TYPE) {
+    if (returnType == nullptr) {
         throw SemanticError(SemanticError::UNKNOWN_TYPE,
             ast.type->asString(),
             ast.type->pos
@@ -82,7 +82,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::VariableDeclar
     auto v = std::make_unique<sem::Variable>(scope.getContext());
     v->name = ast.name;
     auto type = scope.getType(ast.type.get());
-    if (type != sem::NO_TYPE) {
+    if (type != nullptr) {
         v->type = type;
     }
     else {
@@ -114,7 +114,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::DoEndBlock& as
         if (ast::LocalVariableStatement* nvs = dynamic_cast<ast::LocalVariableStatement*>(statement.get()); nvs) {
             auto type = body->scope.getType(nvs->type.get());
 
-            if (type == sem::NO_TYPE)
+            if (type == nullptr)
                 throw SemanticError(SemanticError::UNKNOWN_TYPE,
                                     nvs->type->asString(),
                                     nvs->type->pos);
@@ -194,8 +194,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FeatureCall& a
     sem::Variable* var;
 
     if (target) {
-        auto& targetType = scope.getContext().getType(target->type);
-        auto& typeScope = targetType.getTypeScope();
+        auto& typeScope = target->type->getTypeScope();
         method = typeScope.getMethod(ast.name);
         var = typeScope.getVariable(ast.name);
     }
@@ -293,16 +292,14 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::AssignmentStat
     as->value = unique_dynamic_cast<sem::Expression>(ast.expr->accept(*this, scope));
     as->target = unique_dynamic_cast<sem::Expression>(ast.target->accept(*this, scope));
     
-    if (as->target->type == as->value->type) {
+    if (as->target->type->operator==(*as->value->type)) {
         return as;
     }
     else {
         throw SemanticError(
             SemanticError::TYPE_MISMATCH,
-            "Can't assign expression of type to type.",
-            // TODO rewrite
-            //"Can't assign expression of type '" + as->value->type->asString() +
-            //"' to value of type '" + as->target->type->asString() + "'.",
+            "Can't assign expression of type '" + as->value->type->asString() +
+            "' to value of type '" + as->target->type->asString() + "'.",
             ast.pos
         );
     }
@@ -313,7 +310,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::ReturnStatemen
 {
     auto shouldReturn = scope.getReturnableType();
     
-    if (shouldReturn == sem::NO_TYPE) {
+    if (shouldReturn == nullptr) {
         if (ast.expr == nullptr)
             return std::make_unique<sem::ReturnStatement>(scope.getContext());
         else
@@ -334,8 +331,8 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::ReturnStatemen
     auto returnValue = unique_dynamic_cast<sem::Expression>(ast.expr->accept(*this, scope));
     
     if (shouldReturn != returnValue->type) {
-        auto should = scope.getContext().getTypeString(shouldReturn);
-        auto is = scope.getContext().getTypeString(returnValue->type);
+        auto should = shouldReturn->asString();
+        auto is = returnValue->type->asString();
         throw SemanticError::invalidReturnType(should, is, ast.expr->pos);
     }
     
@@ -358,7 +355,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(
     auto targetType = target->type;
     
     if (!target->isLValue()) {
-        throw NotLValue(scope.getContext().getTypeString(targetType), ast.pos);
+        throw NotLValue(targetType->asString(), ast.pos);
     }
     
     return std::make_unique<sem::AddressExpression>(std::move(target));
@@ -390,10 +387,10 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::BinaryOperatio
     auto leftEval = unique_dynamic_cast<sem::Expression>(ast.left->accept(*this, scope));
     auto rightEval = unique_dynamic_cast<sem::Expression>(ast.right->accept(*this, scope));
 
-    auto& leftType = context.getType(leftEval->type);
-    auto& rightType = context.getType(rightEval->type);
+    auto* leftType = leftEval->type;
+    auto* rightType = rightEval->type;
 
-    auto& scop =  leftType.getTypeScope();
+    auto& scop =  leftType->getTypeScope();
     sem::Method* operationMethod = scop.resolveMethod(
         ast.opString, { rightEval->type }
     );
@@ -406,7 +403,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::BinaryOperatio
     if (!operationMethod) {
         throw SemanticError(SemanticError::OPERATOR_NOT_FOUND,
             "operator " + ast.opString + " not found for types '" +
-            leftType.asString() + "' and '" + rightType.asString() + "'",
+            leftType->asString() + "' and '" + rightType->asString() + "'",
             ast.opPos);
     }
     
@@ -423,12 +420,12 @@ 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()));
-    auto* classType = scope.getContext().getType(ret->type).getClass();
+    auto* classType = ret->type->getClass();
     if (classType != nullptr && classType->isReferenceType) {
         return ret;
     }
     else {
-        throw SemanticError::newForNonClass(scope.getContext().getType(ret->type).asString(), ast.pos);
+        throw SemanticError::newForNonClass(ret->type->asString(), ast.pos);
     }
 }
 

+ 7 - 10
src/sem/CodeGeneration.cpp

@@ -154,18 +154,18 @@ llvm::Function* generateFunction(llvm::Module* module, sem::Method* method)
     
     Type* returnType;
     if (method->returnType)
-        returnType = semCtxt.getLlvmType(method->returnType, context);
+        returnType = method->returnType->getLlvmType(context);
     else
         returnType = llvm::Type::getVoidTy(context);
     
     std::vector<Type*> argumentTypes;
     if (method->thisExpression != nullptr) {
-        Type* enclosingType = semCtxt.getLlvmType(method->thisExpression->type, context);
+        Type* enclosingType = method->thisExpression->type->getLlvmType(context);
         argumentTypes.push_back(enclosingType);
     }
     
     for (auto& arg : method->arguments) {
-        Type* argumentType = semCtxt.getLlvmType(arg->type, context);
+        Type* argumentType = arg->type->getLlvmType(context);
         argumentTypes.push_back(argumentType);
     }
     
@@ -362,11 +362,11 @@ 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 == sem::NO_TYPE)
+        if (var->type == nullptr)
             throw "wtf null type";
         
 
-        llvm::AllocaInst* v = builder.CreateAlloca(semCtxt.getLlvmType(var->type, context));
+        llvm::AllocaInst* v = builder.CreateAlloca(var->type->getLlvmType(context));
         var->allocaInst = v;
     }
     
@@ -386,11 +386,8 @@ llvm::Function* qlow::gen::FunctionGenerator::generate(void)
     
     builder.SetInsertPoint(getCurrentBlock());
     //if (method.returnType->equals(sem::NativeType(sem::NativeType::Type::VOID))) {
-    if (method.returnType == sem::NO_TYPE ||
-        (semCtxt.getType(method.returnType).getKind() == sem::Type::Kind::NATIVE &&
-        semCtxt.getType(method.returnType).getNativeKind() == sem::Type::Native::VOID)) {
-        if (!getCurrentBlock()->getTerminator())
-            builder.CreateRetVoid();
+    if (method.returnType == nullptr || method.returnType->isVoid()) {
+        builder.CreateRetVoid();
     }
 
     return func;

+ 49 - 104
src/sem/Context.cpp

@@ -7,9 +7,9 @@
 using qlow::sem::Context;
 using namespace qlow;
 
-size_t std::hash<std::reference_wrapper<qlow::sem::Type>>::operator() (const std::reference_wrapper<qlow::sem::Type>& t) const
+size_t std::hash<qlow::sem::Type*>::operator() (qlow::sem::Type* t) const
 {
-    return t.get().hash();
+    return t->hash();
 }
 
 
@@ -20,56 +20,10 @@ Context::Context(void)
 }
 
 
-qlow::sem::TypeId Context::addType(Type&& type) {
-    if (typesMap.count(type) != 0) {
-        return typesMap[type];
-    }
-    else {
-        Type gogo = std::move(type);
-        types.push_back({ std::move(gogo), nullptr });
-        auto id = types.size() - 1;
-        typesMap[types[id].first] = id;
-        return id;
-    }
-}
-
-
-qlow::sem::Type& Context::getType(TypeId tid)
-{
-    if (tid <= types.size())
-        return types[tid].first;
-    else
-        throw InternalError(InternalError::INVALID_TYPE);
-}
-
-
-std::optional<std::reference_wrapper<sem::Type>> Context::getMaybeType(TypeId tid)
-{
-    if (tid <= types.size())
-        return std::make_optional(std::reference_wrapper<Type>(types[tid].first));
-    else
-        return std::nullopt;
-}
-
-
-std::string Context::getTypeString(TypeId tid)
-{
-    if (auto type = getMaybeType(tid))
-        return type.value().get().asString();
-    else
-        return "";
-}
-
-
-qlow::sem::TypeId Context::getVoidTypeId(void)
-{
-    return getNativeTypeId(Type::Native::VOID);
-}
-
-
-qlow::sem::TypeId Context::getNativeTypeId(Type::Native n)
+qlow::sem::Type* Context::getVoidType(void)
 {
-    return nativeScope->getType(n);
+    // maybe small optimization potential here
+    return getNativeType(NativeType::NType::VOID);
 }
 
 
@@ -78,86 +32,77 @@ qlow::sem::NativeScope& Context::getNativeScope(void)
     return *nativeScope;
 }
 
-// TODO rewrite, so on creating already existant type, there should be no need to create type at all
-sem::TypeId Context::createNativeType(std::string name, Type::Native type)
-{
-    TypeId reserved = types.size();
-    Type t = { *this, Type::Union{ Type::NativeType{ type } }, std::move(name), reserved };
-    return addType(std::move(t));
-}
-
 
-sem::TypeId Context::createClassType(Class* classType)
+sem::Type* Context::getNativeType(NativeType::NType nativeType)
 {
-    TypeId reserved = types.size();
-    Type t = Type{ *this, Type::Union{ Type::ClassType{ classType }}, reserved };
-    return addType(std::move(t));
-}
-
+    auto t = std::unique_ptr<NativeType>(new NativeType(nativeType));
 
-sem::TypeId Context::createPointerType(TypeId pointsTo)
-{
-    TypeId reserved = types.size();
-    Type t = Type{ *this, Type::Union{ Type::PointerType{ pointsTo }}, reserved };
-    return addType(std::move(t));
+    const auto& find = typeMap.find(t.get());
+    if (find != typeMap.end()) {
+        return types[find->second].get();
+    }
+    else {
+        typeMap[t.get()] = types.size();
+        types.push_back(std::move(t));
+        return types[types.size() - 1].get();
+    }
 }
 
 
-sem::TypeId Context::createArrayType(TypeId pointsTo)
+sem::Type* Context::getClassType(Class* classType)
 {
-    TypeId reserved = types.size();
-    Type t = Type{ *this, Type::Union{ Type::ArrayType{ pointsTo }}, reserved };
-    return addType(std::move(t));
+    auto t = std::unique_ptr<ClassType>(new ClassType(classType));
+
+    const auto& find = typeMap.find(t.get());
+    if (find != typeMap.end()) {
+        return types[find->second].get();
+    }
+    else {
+        typeMap[t.get()] = types.size();
+        types.push_back(std::move(t));
+        return types[types.size() - 1].get();
+    }
 }
 
 
-llvm::Type* Context::getLlvmType(TypeId id, llvm::LLVMContext& llvmCtxt)
+sem::Type* Context::getArrayType(Type* pointsTo)
 {
-    // TODO at the moment, all types are integers --> fix that
-    if (id < types.size()) {
-        auto& llt = types[id].second;
-        return llt;
+    auto t = std::unique_ptr<ArrayType>(new ArrayType(pointsTo));
+
+    const auto& find = typeMap.find(t.get());
+    if (find != typeMap.end()) {
+        return types[find->second].get();
     }
     else {
-        return nullptr;
+        typeMap[t.get()] = types.size();
+        types.push_back(std::move(t));
+        return types[types.size() - 1].get();
     }
 }
 
 
 void Context::createLlvmTypes(llvm::LLVMContext& llvmCtxt)
 {
-    for (auto& [type, llvmType] : types) {
-        if (type.getKind() != Type::Kind::NATIVE) {
-            llvmType = llvm::StructType::create(llvmCtxt, type.asIdentifier());
+    for (auto& type : types) {
+        if (type->isNativeType()) {
+            type->createLlvmTypeDecl(llvmCtxt);
         }
-    }
-    for (auto& [type, llvmType] : types) {
-        if (type.getKind() == Type::Kind::NATIVE) {
-            switch (type.getNativeKind()) {
-            case Type::Native::BOOLEAN:
-                llvmType = llvm::Type::getInt1Ty(llvmCtxt);
-                break;
-            case Type::Native::INTEGER:
-                llvmType = llvm::Type::getInt64Ty(llvmCtxt);
-                break;
-            case Type::Native::VOID:
-                llvmType = llvm::Type::getVoidTy(llvmCtxt);
-                break;
-            }
+        else {
+            type->llvmType = llvm::StructType::create(llvmCtxt, type->asIdentifier());
         }
     }
-    for (auto& [type, llvmType] : types) {
-        if (type.getKind() == Type::Kind::CLASS) {
+    for (auto& type : types) {
+        if (type->isClassType()) {
             std::vector<llvm::Type*> structTypes;
 
-            for (auto& [name, field] : type.getClass()->fields) {
-                structTypes.push_back(types[field->type].second);
+            for (auto& [name, field] : type->getClass()->fields) {
+                structTypes.push_back(field->type->getLlvmType(llvmCtxt));
                 field->llvmStructIndex = structTypes.size() - 1;
             }
 
-            llvm::dyn_cast<llvm::StructType>(llvmType)->setBody(llvm::ArrayRef(structTypes));
-            if (type.getClass()->isReferenceType)
-                llvmType = llvmType->getPointerTo();
+            llvm::dyn_cast<llvm::StructType>(type->llvmType)->setBody(llvm::ArrayRef(structTypes));
+            if (type->getClass()->isReferenceType)
+                type->llvmType = type->llvmType->getPointerTo();
         }
     }
 }

+ 19 - 27
src/sem/Context.h

@@ -10,6 +10,7 @@
 #include <llvm/IR/LLVMContext.h>
 
 #include "Type.h"
+#include "Util.h"
 
 namespace qlow::sem
 {
@@ -23,55 +24,46 @@ namespace qlow::sem
 namespace std
 {
     template<>
-    struct hash<std::reference_wrapper<qlow::sem::Type>>
+    struct hash<qlow::sem::Type*>
     {
-        size_t operator() (const std::reference_wrapper<qlow::sem::Type>& t) const;
+        size_t operator() (qlow::sem::Type* t) const;
     };
 
 
     template<>
-    struct equal_to<std::reference_wrapper<qlow::sem::Type>>
+    struct equal_to<qlow::sem::Type*>
     {
-        inline bool operator() (const std::reference_wrapper<qlow::sem::Type>& a, const std::reference_wrapper<qlow::sem::Type>& b) const
+        inline bool operator() (qlow::sem::Type* a, qlow::sem::Type* b) const
         {
-            return a.get() == b.get();
+            return a->equals(*b);
         }
     };
 }
 
 
+/**
+ * @brief owning context for all types
+ * 
+ * This class ensures that there is only ever one
+ */
 class qlow::sem::Context
 {
 private:
-    std::vector<std::pair<Type, llvm::Type*>> types;
-    std::unordered_map<std::reference_wrapper<Type>, TypeId> typesMap;
+    OwningList<Type> types;
+    std::unordered_map<Type*, size_t> typeMap;
 
     std::unique_ptr<NativeScope> nativeScope;
 public:
     Context(void);
-    
-    TypeId addType(Type&& type);
-    Type& getType(TypeId tid);
-    std::optional<std::reference_wrapper<Type>> getMaybeType(TypeId tid);
-
-    /**
-     * @brief get a string denoting the type
-     * 
-     * @return the name of the type if the given id is valid,
-     *         an empty string otherwise.
-     */
-    std::string getTypeString(TypeId tid);
-
-    TypeId getVoidTypeId(void);
-    TypeId getNativeTypeId(Type::Native n);
+
+    Type* getVoidType(void);
     NativeScope& getNativeScope(void);
 
-    TypeId createNativeType(std::string name, Type::Native type);
-    TypeId createClassType(Class* classType);
-    TypeId createPointerType(TypeId pointsTo);
-    TypeId createArrayType(TypeId pointsTo);
+    Type* getNativeType(NativeType::NType type);
+    Type* getClassType(Class* c);
+    Type* getArrayType(Type* pointsTo);
 
-    llvm::Type* getLlvmType(TypeId id, llvm::LLVMContext& llvmCtxt);
+    //llvm::Type* getLlvmType(TypeId id, llvm::LLVMContext& llvmCtxt);
 
     void createLlvmTypes(llvm::LLVMContext& llvmCtxt);
 };

+ 12 - 5
src/sem/Semantic.cpp

@@ -71,13 +71,20 @@ std::pair<std::unique_ptr<Context>, std::unique_ptr<GlobalScope>>
     
     for (auto& [name, method] : globalScope->functions) {
         auto returnType = globalScope->getType(method->astNode->type.get());
-        if (returnType != NO_TYPE) {
+        if (returnType != nullptr) {
             method->returnType = returnType;
         }
         else {
-            SemanticError se(SemanticError::UNKNOWN_TYPE,
+            if (method->astNode->type == nullptr) {
+                throw SemanticError(SemanticError::UNKNOWN_TYPE,
+                            method->name,
+                            method->astNode->pos);
+            }
+            else {
+                throw SemanticError(SemanticError::UNKNOWN_TYPE,
                             method->astNode->type->asString(),
                             method->astNode->type->pos);
+            }
         }
         
         // otherwise add to the methods list
@@ -232,21 +239,21 @@ std::string CastExpression::toString(void) const
 {
     // TODO remove optional unwrapping
     return "CastExpression[" + expression->toString() + " to " +
-        context.getType(targetType).asString() + "]";
+        targetType->asString() + "]";
 }
 
 
 std::string NewExpression::toString(void) const
 {
     // TODO remove optional unwrapping
-    return "NewExpression[" + context.getType(type).asString() + "]";
+    return "NewExpression[" + type->asString() + "]";
 }
 
 
 std::string NewArrayExpression::toString(void) const
 {
     // TODO remove optional unwrapping
-    return "NewArrayExpression[" + context.getType(arrayType).asString() + "; " +
+    return "NewArrayExpression[" + elementType->asString() + "; " +
         length->toString() + "]";
 }
 

+ 21 - 21
src/sem/Semantic.h

@@ -78,7 +78,7 @@ struct qlow::sem::Class : public SemanticObject
     SymbolTable<Field> fields;
     SymbolTable<Method> methods;
     ClassScope scope;
-    TypeId classType;
+    Type* classType;
 
     /// \brief generated during llvm code generation, not availab
     llvm::Type* llvmType;
@@ -90,7 +90,7 @@ struct qlow::sem::Class : public SemanticObject
         name{ astNode->name },
         isReferenceType{ astNode->isReferenceType },
         scope{ globalScope, this },
-        classType{ globalScope.getContext().createClassType(this) },
+        classType{ globalScope.getContext().getClassType(this) },
         llvmType{ nullptr }
     {
     }
@@ -113,7 +113,7 @@ struct qlow::sem::Class : public SemanticObject
 
 struct qlow::sem::Variable : public SemanticObject
 {
-    TypeId type;
+    Type* type;
     std::string name;
     bool isParameter;
 
@@ -123,7 +123,7 @@ struct qlow::sem::Variable : public SemanticObject
     
     inline Variable(Context& context) :
         SemanticObject{ context } {}
-    inline Variable(Context& context, TypeId type, const std::string& name) :
+    inline Variable(Context& context, Type* type, const std::string& name) :
         SemanticObject{ context },
         type{ type },
         name{ name },
@@ -148,7 +148,7 @@ struct qlow::sem::Field : public Variable
 struct qlow::sem::Method : public SemanticObject
 {
     Class* containingClass;
-    TypeId returnType;
+    Type* returnType;
     std::vector<Variable*> arguments;
     std::string name;
     ast::MethodDefinition* astNode;
@@ -161,7 +161,7 @@ struct qlow::sem::Method : public SemanticObject
     llvm::Function* llvmNode;
 
     inline Method(Scope& parentScope,
-            TypeId returnType, bool isExtern) :
+            Type* returnType, bool isExtern) :
         SemanticObject{ parentScope.getContext() },
         containingClass{ nullptr },
         returnType{ returnType },
@@ -198,7 +198,7 @@ struct qlow::sem::ThisExpression : public Variable
     inline ThisExpression(Method* method) :
         Variable{
             method->context,
-            method->context.createClassType(method->containingClass),
+            method->context.getClassType(method->containingClass),
             "this"
         },
         method{ method }
@@ -299,9 +299,9 @@ struct qlow::sem::Expression :
                      qlow::gen::FunctionGenerator,
                      qlow::LValueVisitor>
 {
-    TypeId type;
+    Type* type;
     
-    inline Expression(Context& context, TypeId type) :
+    inline Expression(Context& context, Type* type) :
         SemanticObject{ context },
         type{ type }
     {
@@ -318,7 +318,7 @@ struct qlow::sem::Operation : public Expression
 {
     std::string opString;
     
-    inline Operation(Context& context, TypeId type) :
+    inline Operation(Context& context, Type* type) :
         Expression{ context, type }
     {
     }
@@ -348,7 +348,7 @@ struct qlow::sem::AddressExpression : public Expression
     std::unique_ptr<sem::Expression> target;
     
     inline AddressExpression(std::unique_ptr<sem::Expression> target) :
-        Expression{ target->context, context.createPointerType(target->type) },
+        Expression{ target->context, nullptr /*context.createPointerType(target->type)*/ },
         target{ std::move(target) }
     {
     }
@@ -367,7 +367,7 @@ struct qlow::sem::BinaryOperation : public Operation
     sem::Method* operationMethod;
     
     inline BinaryOperation(Context& context,
-            TypeId type, ast::BinaryOperation* astNode) :
+            Type* type, ast::BinaryOperation* astNode) :
         Operation{ context, type },
         astNode{ astNode }
     {
@@ -382,12 +382,12 @@ struct qlow::sem::BinaryOperation : public Operation
 struct qlow::sem::CastExpression : public Expression
 {
     std::unique_ptr<Expression> expression;
-    TypeId targetType;
+    Type* targetType;
     
     ast::CastExpression* astNode;
     
     inline CastExpression(std::unique_ptr<Expression> expression,
-                          TypeId type,
+                          Type* type,
                           ast::CastExpression* astNode) :
         Expression{ expression->context, type },
         expression{ std::move(expression) },
@@ -404,7 +404,7 @@ struct qlow::sem::CastExpression : public Expression
 
 struct qlow::sem::NewExpression : public Expression
 {
-    inline NewExpression(Context& context, TypeId type) :
+    inline NewExpression(Context& context, Type* type) :
         Expression{ context, type }
     {
     }
@@ -416,12 +416,12 @@ struct qlow::sem::NewExpression : public Expression
 
 struct qlow::sem::NewArrayExpression : public Expression
 {
-    TypeId arrayType;
+    Type* elementType;
     std::unique_ptr<Expression> length;
     
-    inline NewArrayExpression(Context& context, TypeId arrayType) :
-        Expression{ context, context.createArrayType(arrayType) },
-        arrayType{ arrayType }
+    inline NewArrayExpression(Context& context, Type* elementType) :
+        Expression{ context, context.getArrayType(elementType) },
+        elementType{ elementType }
     {
     }
     
@@ -435,7 +435,7 @@ struct qlow::sem::UnaryOperation : public Operation
     qlow::ast::UnaryOperation::Side side;
     std::unique_ptr<Expression> arg;
     
-    inline UnaryOperation(Context& context, TypeId type) :
+    inline UnaryOperation(Context& context, Type* type) :
         Operation{ context, type }
     {
     }
@@ -493,7 +493,7 @@ struct qlow::sem::IntConst : public Expression
     unsigned long long value;
 
     inline IntConst(Context& context, unsigned long long value) :
-        Expression{ context, context.getNativeTypeId(Type::Native::INTEGER) },
+        Expression{ context, context.getNativeType(NativeType::NType::INTEGER) },
         value{ value }
     {
     }

+ 173 - 113
src/sem/Type.cpp

@@ -5,8 +5,14 @@
 #include "Builtin.h"
 #include "ErrorReporting.h"
 
-using qlow::sem::TypeId;
+#include <llvm/IR/Type.h>
+
+#include <map>
+
 using qlow::sem::Type;
+using qlow::sem::NativeType;
+using qlow::sem::ClassType;
+using qlow::sem::ArrayType;
 
 qlow::sem::SemanticObject::~SemanticObject(void) = default;
 
@@ -16,141 +22,195 @@ std::string qlow::sem::SemanticObject::toString(void) const
     return "SemanticObject [" + util::toString(this) + "]";
 }
 
+Type::Type(void) = default;
+Type::~Type(void) = default;
+
 
-Type::Type(Context& context, Union type, TypeId id) :
-    Type{ context, type, "", id }
+bool Type::operator==(const Type& other) const
 {
+    // ensured because context only ever creates a type once
+    return this->equals(other);
 }
 
 
-Type::Type(Context& context, Union type, std::string name, TypeId id) :
-    type{ std::move(type) }
+qlow::sem::Class* Type::getClass(void) const
 {
-    if (getKind() == Kind::NATIVE) {
-        typeScope = std::make_unique<NativeTypeScope>(context, id);
-    }
-    else {
-        typeScope = std::make_unique<TypeScope>(context, id);
-    }
+    return nullptr;
 }
 
 
-Type::~Type(void) = default;
+void Type::setTypeScope(std::unique_ptr<TypeScope> scope)
+{
+    this->typeScope = std::move(scope);
+}
+
+
+/*void Type::setLlvmType(llvm::Type* type)
+{
+    llvmType = type;
+}*/
+
+
+llvm::Type* Type::getLlvmType(llvm::LLVMContext& c) const
+{
+    return llvmType;
+}
+
+
+bool Type::isClassType(void) const
+{
+    return false;
+}
+
+
+bool Type::isNativeType(void) const
+{
+    return false;
+}
+
+
+bool Type::isArrayType(void) const
+{
+    return false;
+}
+
+
+bool Type::isVoid(void) const
+{
+    return false;
+}
+
+
+bool NativeType::equals(const Type& other) const
+{
+    return other.isNativeType() && static_cast<const NativeType&>(other).type == type;
+}
+
+
+bool NativeType::isNativeType(void) const
+{
+    return true;
+}
+
+
+bool NativeType::isVoid(void) const
+{
+    return this->type == NType::VOID;
+}
+
+
+std::string NativeType::asString(void) const
+{
+    static const std::map<NType, std::string> names {
+        { NType::VOID, "Void" },
+        { NType::INTEGER, "Integer" },
+        { NType::BOOLEAN, "Boolean" },
+    };
+    return names.at(type);
+}
 
 
-Type::Kind Type::getKind(void) const
+std::string NativeType::asIdentifier(void) const
 {
-    switch(type.index()) {
-        case 0: return Kind::NATIVE;
-        case 1: return Kind::CLASS;
-        case 2: return Kind::POINTER;
-        case 3: return Kind::ARRAY;
+    return asString();
+}
+
+
+size_t NativeType::hash(void) const
+{
+    return static_cast<size_t>(this->type) * 234598245 + 234568276587;
+}
+
+
+void NativeType::createLlvmTypeDecl(llvm::LLVMContext& ctxt)
+{
+    switch(type) {
+    case NType::VOID:
+        llvmType = llvm::Type::getVoidTy(ctxt);
+        break;
+    case NType::INTEGER:
+        llvmType = llvm::Type::getInt64Ty(ctxt);
+        break;
+    case NType::BOOLEAN:
+        llvmType = llvm::Type::getInt1Ty(ctxt);
+        break;
     }
-    // should never arrive here
-    throw InternalError(InternalError::INVALID_TYPE);
-}
-
-
-Type::Native Type::getNativeKind(void) const
-{
-    return std::get<NativeType>(this->type).type;
-}
-
-
-std::string Type::asString(void) const
-{
-    using namespace std::literals;
-    return std::visit(
-        [&] (const auto& t) -> std::string {
-            using T = std::decay_t<decltype(t)>;
-            if constexpr (std::is_same<T, NativeType>::value) {
-                return "native";
-            }
-            else if constexpr (std::is_same<T, ClassType>::value) {
-                return this->getClass()->name;
-            }
-            else if constexpr (std::is_same<T, PointerType>::value) {
-                return this->typeScope->getContext().getType(t.targetType).asString() + "*";
-            }
-            else if constexpr (std::is_same<T, ArrayType>::value) {
-                return "["s + this->typeScope->getContext().getType(t.targetType).asString() + "]";
-            }
-        }
-        ,
-        type
-    );
-}
-
-
-std::string Type::asIdentifier(void) const
-{
-    using namespace std::literals;
-    return std::visit(
-        [&] (const auto& t) -> std::string {
-            using T = std::decay_t<decltype(t)>;
-            if constexpr (std::is_same<T, NativeType>::value) {
-                return "native";
-            }
-            else if constexpr (std::is_same<T, ClassType>::value) {
-                return this->getClass()->name;
-            }
-            else if constexpr (std::is_same<T, PointerType>::value) {
-                return this->typeScope->getContext().getType(t.targetType).asIdentifier() + "_ptr";
-            }
-            else if constexpr (std::is_same<T, ArrayType>::value) {
-                return this->typeScope->getContext().getType(t.targetType).asIdentifier() + "_arr";
-            }
-        }
-        ,
-        type
-    );
-}
-
-
-size_t Type::hash(void) const
-{
-    auto value1 = std::visit(
-        [&] (const auto& t) -> size_t {
-            using T = std::decay_t<decltype(t)>;
-            if constexpr (std::is_same<T, NativeType>::value) {
-                return static_cast<size_t>(t.type) * 2345279;
-            }
-            else if constexpr (std::is_same<T, ClassType>::value) {
-                return reinterpret_cast<size_t>(t.classType) * 1;
-            }
-            else if constexpr (std::is_same<T, PointerType>::value) {
-                return t.targetType * 143115587;
-            }
-            else if constexpr (std::is_same<T, ArrayType>::value) {
-                //return "[" + context.getType(t.targetType) + "]";
-                return t.targetType * 2342345;
-            }
-        },
-        type
-    );
-    auto h = type.index() * 2542345234523 + value1;
-    return h;
 }
 
 
-bool Type::operator==(const Type& other) const
+bool ClassType::equals(const Type& other) const
 {
-    return //this->name == other.name &&
-           this->type == other.type;
+    return other.isClassType() && other.getClass() == getClass();
 }
 
 
-qlow::sem::Class* Type::getClass(void) const
+qlow::sem::Class* ClassType::getClass(void) const
 {
-    const auto* classType = std::get_if<ClassType>(&type);
-    if (classType)
-        return classType->classType;
-    else
-        return nullptr;
+    return type;
 }
 
 
-void Type::setTypeScope(std::unique_ptr<TypeScope> scope)
+bool ClassType::isClassType(void) const
 {
-    this->typeScope = std::move(scope);
+    return true;
+}
+
+
+std::string ClassType::asString(void) const
+{
+    return type->name;
+}
+
+
+std::string ClassType::asIdentifier(void) const
+{
+    return type->name;
+}
+
+
+size_t ClassType::hash(void) const
+{
+    return reinterpret_cast<size_t>(type);
+}
+
+
+void ClassType::createLlvmTypeDecl(llvm::LLVMContext& ctxt)
+{
+    llvmType = llvm::StructType::create(ctxt, asIdentifier());
+}
+
+
+bool ArrayType::equals(const Type& other) const
+{
+    return other.isArrayType() && elementType->equals(*static_cast<const ArrayType&>(other).elementType);
+}
+
+
+bool ArrayType::isArrayType(void) const
+{
+    return true;
+}
+
+
+std::string ArrayType::asString(void) const
+{
+    return "[" + elementType->asString() + "]";
+}
+
+
+std::string ArrayType::asIdentifier(void) const
+{
+    return elementType->asString() + "_arr";
+}
+
+
+size_t ArrayType::hash(void) const
+{
+    return 2345792834579ull + elementType->hash() * 1234817233;
+}
+
+
+void ArrayType::createLlvmTypeDecl(llvm::LLVMContext& ctxt)
+{
+    llvmType = llvm::StructType::create(ctxt, asIdentifier());
 }

+ 102 - 59
src/sem/Type.h

@@ -12,13 +12,14 @@ namespace llvm {
     class LLVMContext;
 }
 
+
 namespace qlow::sem
 {
     struct SemanticObject;
     class Type;
-    
-    using TypeId = size_t;
-    const TypeId NO_TYPE = std::numeric_limits<TypeId>::max();
+    class NativeType;
+    class ClassType;
+    class ArrayType;
 
     // forward declarations to other files
     struct Class;
@@ -46,79 +47,37 @@ struct qlow::sem::SemanticObject
 class qlow::sem::Type
 {
     friend class Context;
-public:
-    enum class Kind
-    {
-        NATIVE,
-        CLASS,
-        POINTER,
-        ARRAY
-    };
-
-    enum class Native
-    {
-        VOID,
-        BOOLEAN,
-        INTEGER,
-    };
-
-private:
-    struct NativeType
-    {
-        Native type;
-        inline bool operator==(const NativeType& other) const { return type == other.type; }
-    };
-
-    struct ClassType
-    {
-        Class* classType;
-        inline bool operator==(const ClassType& other) const { return classType == other.classType; }
-    };
-
-    struct PointerType
-    {
-        TypeId targetType;
-        inline bool operator==(const PointerType& other) const { return targetType == other.targetType; }
-    };
-
-    struct ArrayType 
-    {
-        TypeId targetType;
-        inline bool operator==(const ArrayType& other) const { return targetType == other.targetType; }
-    };
-
-    using Union = std::variant<NativeType, ClassType, PointerType, ArrayType>;
-
+protected:
     std::unique_ptr<TypeScope> typeScope;
-    Union type;
+    llvm::Type* llvmType;
 
-    Type(Context& context, Union type, TypeId id);
-    Type(Context& context, Union type, std::string name, TypeId id);
+    Type(void);
 
 public:
-    ~Type(void);
+
+    virtual ~Type(void);
+
     Type(const Type& other) = delete;
-    Type(Type&& other) = default;
+    Type(Type&& other) = delete;
     void operator = (const Type& other) = delete;
-    Type& operator = (Type&& other) = default;
+    Type& operator = (Type&& other) = delete;
 
-    Kind getKind(void) const;
-    Native getNativeKind(void) const;
-
-    std::string asString(void) const;
-    std::string asIdentifier(void) const;
-    size_t hash(void) const;
+    virtual std::string asString(void) const = 0;
+    virtual std::string asIdentifier(void) const = 0;
+    virtual size_t hash(void) const = 0;
 
     bool operator == (const Type& other) const;
     inline bool operator != (const Type& other) const { return !this->operator==(other); }
 
+    virtual bool equals(const Type& other) const = 0;
+
     /**
      * @brief return the class of this type if it is a class type,
      *        <code>nullptr</code> otherwise.
      * @post ensures that if <code>this->getKind() == Kind::CLASS</code>,
      *       it will not return a <code>nullptr</code>
      */
-    Class* getClass(void) const;
+    virtual Class* getClass(void) const;
     
     /**
      * @brief returns the type scope of this type
@@ -129,6 +88,90 @@ public:
      * @brief sets the type scope of this type
      */
     void setTypeScope(std::unique_ptr<TypeScope> scope);
+
+    //virtual void setLlvmType(llvm::Type* type);
+    virtual llvm::Type* getLlvmType(llvm::LLVMContext&) const;
+
+    virtual void createLlvmTypeDecl(llvm::LLVMContext&) = 0;
+
+    virtual bool isClassType(void) const;
+    virtual bool isNativeType(void) const;
+    virtual bool isArrayType(void) const;
+
+    virtual bool isVoid(void) const;
+};
+
+
+class qlow::sem::NativeType : public Type
+{
+    friend class Context;
+public:
+    enum class NType
+    {
+        VOID,
+        INTEGER,
+        BOOLEAN,
+    };
+protected:
+
+    NType type;
+    inline NativeType(NType type) :
+        type{ type }
+    {
+    }
+public:
+
+    virtual bool equals(const Type& other) const override;
+
+    virtual bool isNativeType(void) const override;
+    virtual bool isVoid(void) const override;
+
+    virtual std::string asString(void) const override;
+    virtual std::string asIdentifier(void) const override;
+    virtual size_t hash(void) const override;
+
+    virtual void createLlvmTypeDecl(llvm::LLVMContext&) override;
+};
+
+
+class qlow::sem::ClassType : public Type
+{
+    friend class Context;
+protected:
+    Class* type;
+    inline ClassType(Class* type) :
+        type{ type }
+    {
+    }
+public:
+    virtual bool equals(const Type& other) const override;
+    virtual bool isClassType(void) const override;
+    virtual Class* getClass(void) const override;
+
+    virtual std::string asString(void) const override;
+    virtual std::string asIdentifier(void) const override;
+    virtual size_t hash(void) const override;
+    virtual void createLlvmTypeDecl(llvm::LLVMContext&) override;
+};
+
+
+class qlow::sem::ArrayType : public Type
+{
+    friend class Context;
+protected:
+    Type* elementType;
+    inline ArrayType(Type* elementType) :
+        elementType{ elementType }
+    {
+    }
+public:
+    virtual bool equals(const Type& other) const override;
+    virtual bool isArrayType(void) const override;
+
+    virtual std::string asString(void) const override;
+    virtual std::string asIdentifier(void) const override;
+    virtual size_t hash(void) const override;
+    virtual void createLlvmTypeDecl(llvm::LLVMContext&) override;
 };