Jelajahi Sumber

reworked type system

Nicolas Winkler 6 tahun lalu
induk
melakukan
46ab49b89b
15 mengubah file dengan 290 tambahan dan 628 penghapusan
  1. 92 3
      src/Builtin.cpp
  2. 6 0
      src/Builtin.h
  3. 6 4
      src/CodegenVisitor.cpp
  4. 25 11
      src/Scope.cpp
  5. 17 6
      src/Scope.h
  6. 20 13
      src/ast/AstVisitor.cpp
  7. 0 1
      src/ast/lexer.l
  8. 11 11
      src/sem/CodeGeneration.cpp
  9. 67 18
      src/sem/Context.cpp
  10. 14 9
      src/sem/Context.h
  11. 2 13
      src/sem/Semantic.cpp
  12. 5 6
      src/sem/Semantic.h
  13. 11 317
      src/sem/Type.cpp
  14. 13 215
      src/sem/Type.h
  15. 1 1
      src/test.qlw

+ 92 - 3
src/Builtin.cpp

@@ -1,6 +1,7 @@
 #include "Builtin.h"
 #include "Scope.h"
 #include "Type.h"
+#include "Context.h"
 
 using namespace qlow;
 
@@ -19,7 +20,7 @@ sem::NativeScope qlow::sem::generateNativeScope(Context& context)
     };
 
     for (auto [name, type] : natives) {
-        TypeId id = context.addType(Type::createNativeType(context, name, type));
+        TypeId id = context.createNativeType(name, type);
         scope.addNativeType(name, type, id);
     }
     
@@ -124,7 +125,96 @@ sem::NativeScope qlow::sem::generateNativeScope(Context& context)
     return scope;
 }
 
-/*
+
+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))
+    );
+}
+
+
+sem::NativeTypeScope qlow::sem::generateNativeTypeScope(Context& context, Type::Native native)
+{
+    NativeTypeScope scope{ context, context.getNativeTypeId(native) };
+
+
+    scope.nativeMethods.insert(
+        { "+",
+            std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
+                context.getNativeTypeId(Type::Native::INTEGER),
+                context.getNativeTypeId(native),
+                [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
+                    return builder.CreateAdd(a, b);
+                }
+            )
+        }
+    );
+    scope.nativeMethods.insert(
+        { "-",
+            std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
+                context.getNativeTypeId(Type::Native::INTEGER),
+                context.getNativeTypeId(native),
+                [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
+                    return builder.CreateSub(a, b);
+                }
+            )
+        }
+    );
+    scope.nativeMethods.insert(
+        { "*",
+            std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
+                context.getNativeTypeId(Type::Native::INTEGER),
+                context.getNativeTypeId(native),
+                [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
+                    return builder.CreateMul(a, b);
+                }
+            )
+        }
+    );
+    scope.nativeMethods.insert(
+        { "/",
+            std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
+                context.getNativeTypeId(Type::Native::INTEGER),
+                context.getNativeTypeId(native),
+                [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
+                    return builder.CreateSDiv(a, b);
+                }
+            )
+        }
+    );
+
+
+    scope.nativeMethods.insert(
+        { "==",
+            std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
+                context.getNativeTypeId(Type::Native::BOOLEAN),
+                context.getNativeTypeId(native),
+                [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
+                    return builder.CreateICmpEQ(a, b);
+                }
+            )
+        }
+    );
+    scope.nativeMethods.insert(
+        { "!=",
+            std::make_unique<BinaryNativeMethod>(context.getNativeScope(),
+                context.getNativeTypeId(Type::Native::BOOLEAN),
+                context.getNativeTypeId(native),
+                [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
+                    return builder.CreateICmpNE(a, b);
+                }
+            )
+        }
+    );
+
+    return scope;
+}
+
+
 llvm::Value* qlow::sem::UnaryNativeMethod::generateCode(llvm::IRBuilder<>& builder,
     std::vector<llvm::Value*> arguments)
 {
@@ -142,7 +232,6 @@ llvm::Value* qlow::sem::BinaryNativeMethod::generateCode(llvm::IRBuilder<>& buil
     return generator(builder, arguments[0], arguments[1]);
 }
 
-*/
 
 
 

+ 6 - 0
src/Builtin.h

@@ -4,6 +4,7 @@
 
 #include "Semantic.h"
 #include "Scope.h"
+#include "Type.h"
 
 #include <llvm/IR/Value.h>
 #include <llvm/IR/IRBuilder.h>
@@ -12,7 +13,12 @@ namespace qlow
 {
     namespace sem
     {
+        class Context;
+        
         NativeScope generateNativeScope(Context& context);
+        void fillNativeScope(NativeScope& scope);
+
+        NativeTypeScope generateNativeTypeScope(Context& context, Type::Native native);
         
         struct NativeMethod;
         struct UnaryNativeMethod;

+ 6 - 4
src/CodegenVisitor.cpp

@@ -61,15 +61,17 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::BinaryOperation& binop, llvm::
     
     if (operation != nullptr) {
         // TODO rewrite
-        /*if (sem::NativeMethod* nm = dynamic_cast<sem::NativeMethod*>(operation); nm) {
+        if (sem::NativeMethod* nm = dynamic_cast<sem::NativeMethod*>(operation); nm) {
             return nm->generateCode(builder, {left, right});
         }
-        else*/
+        else
             throw "only native operations supported at the moment";
     }
     else {
         throw "internal error: operation method null";
     }
+
+    // unreachable
         
     if (left == nullptr) {
         printf("WOW: %s\n", binop.left->toString().c_str());
@@ -77,8 +79,8 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::BinaryOperation& binop, llvm::
     
     Value* implicitelyCastedRight = right;
     // TODO rewritten types
-    /*if (leftType != rightType))
-        implicitelyCastedRight = dynamic_cast<sem::NativeType*>(leftType.get())->generateImplicitCast(right);*/
+    //if (leftType != rightType))
+    //    implicitelyCastedRight = dynamic_cast<sem::NativeType*>(leftType.get())->generateImplicitCast(right);
     
     /*
     if (dynamic_cast<sem::NativeType*>(leftType.get())->isIntegerType()) {

+ 25 - 11
src/Scope.cpp

@@ -53,11 +53,11 @@ sem::TypeId sem::GlobalScope::getType(const ast::Type* name)
     }
 
     if (const auto* arr = dynamic_cast<const ast::ArrayType*>(name); arr) {
-        return context.getArrayOf(getType(arr->arrayType.get()));
+        return context.createArrayType(getType(arr->arrayType.get()));
     }
     
     if (const auto* ptr = dynamic_cast<const ast::PointerType*>(name)) {
-        return context.getPointerTo(getType(ptr->derefType.get()));
+        return context.createPointerType(getType(ptr->derefType.get()));
     }
     
     auto native = context.getNativeScope().getType(name);
@@ -74,7 +74,7 @@ sem::TypeId sem::GlobalScope::getType(const ast::Type* name)
     
     auto t = classes.find(classType->typeName);
     if (t != classes.end())
-        return context.addType(Type::createClassType(context, t->second.get()));
+        return context.createClassType(t->second.get());
     
     return NO_TYPE;
 }
@@ -101,7 +101,7 @@ std::string sem::GlobalScope::toString(void)
 sem::TypeId sem::NativeScope::getType(const ast::Type* name)
 {
     if (const auto* arr = dynamic_cast<const ast::ArrayType*>(name); arr) {
-        return context.getArrayOf(getType(arr->arrayType.get()));
+        return context.createArrayType(getType(arr->arrayType.get()));
     }
     
     const auto* classType = dynamic_cast<const ast::ClassType*>(name);
@@ -269,8 +269,10 @@ std::string sem::LocalScope::toString(void)
 
 sem::Variable* sem::TypeScope::getVariable(const std::string& name)
 {
-    if (type.getKind() == Type::Kind::CLASS) {
-        auto& fields = type.getClass()->fields;
+    Type& ty = context.getType(type);
+    
+    if (ty.getKind() == Type::Kind::CLASS) {
+        auto& fields = ty.getClass()->fields;
         if (fields.find(name) != fields.end())
             return fields[name].get();
     }
@@ -281,8 +283,10 @@ sem::Variable* sem::TypeScope::getVariable(const std::string& name)
 
 sem::Method* sem::TypeScope::getMethod(const std::string& name)
 {
-    if (type.getKind() == Type::Kind::CLASS) {
-        auto classRef = type.getClass();
+    Type& ty = context.getType(type);
+    
+    if (ty.getKind() == Type::Kind::CLASS) {
+        auto classRef = ty.getClass();
         auto& methods = classRef->methods;
         if (methods.find(name) != methods.end())
             return methods[name].get();
@@ -316,13 +320,23 @@ bool sem::TypeScope::isNativeTypeScope(void) const
 }
 
 
+sem::NativeTypeScope::NativeTypeScope(NativeTypeScope&&) = default;
+//sem::NativeTypeScope& sem::NativeTypeScope::operator=(NativeTypeScope&&) = default;
+
+
+sem::NativeTypeScope::~NativeTypeScope(void)
+{
+}
+
+
 sem::Method* sem::NativeTypeScope::getMethod(const std::string& name)
 {
-    /*auto m = nativeType.nativeMethods.find(name);
-    if (m != nativeType.nativeMethods.end())
+    auto m = nativeMethods.find(name);
+    if (m != nativeMethods.end())
         return m->second.get();
-    else*/
+    else {
         return TypeScope::getMethod(name);
+    }
 }
 
 

+ 17 - 6
src/Scope.h

@@ -41,9 +41,8 @@ namespace qlow
         class NativeTypeScope;
         
         class Type;
+        struct NativeMethod;
     }
-    
-    class Context;
 }
 
 
@@ -55,6 +54,9 @@ public:
     inline Scope(Context& context) :
         context{ context } {}
 
+    Scope(Scope&&) = default;
+    Scope& operator=(Scope&&) = default;
+
     virtual ~Scope(void);
     virtual Variable* getVariable(const std::string& name) = 0;
     virtual Method* getMethod(const std::string& name) = 0;
@@ -65,7 +67,7 @@ public:
 
     virtual std::string toString(void) = 0;
 
-    inline Context& getContext(void) const { return context; }
+    inline Context& getContext(void) { return context; }
 };
 
 
@@ -151,13 +153,16 @@ public:
 class qlow::sem::TypeScope : public Scope
 {
 protected:
-    Type& type;
+    TypeId type;
 public:
-    inline TypeScope(Context& context, Type& type) :
+    inline TypeScope(Context& context, TypeId type) :
         Scope{ context },
         type{ type }
     {
     }
+
+    TypeScope(TypeScope&&) = default;
+    TypeScope& operator=(TypeScope&&) = default;
     
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);
@@ -172,10 +177,16 @@ public:
 class qlow::sem::NativeTypeScope : public TypeScope
 {
 public:
-    inline NativeTypeScope(Context& context, Type& type) :
+    SymbolTable<NativeMethod> nativeMethods;
+    inline NativeTypeScope(Context& context, TypeId type) :
         TypeScope{ context, type }
     {
     }
+
+    NativeTypeScope(NativeTypeScope&&);
+    //NativeTypeScope& operator=(NativeTypeScope&&);
+
+    ~NativeTypeScope(void);
     
     virtual Method* getMethod(const std::string& name);
     virtual bool isNativeTypeScope(void) const;

+ 20 - 13
src/ast/AstVisitor.cpp

@@ -1,6 +1,7 @@
 #include "AstVisitor.h"
 #include "Ast.h"
 #include "ErrorReporting.h"
+#include "Context.h"
 
 #include <typeinfo>
 
@@ -192,10 +193,11 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FeatureCall& a
     sem::Method* method;
     sem::Variable* var;
     
-    // TODO rewrite types
     if (target) {
-        //method = target->type->getScope().getMethod(ast.name);
-        //var = target->type->getScope().getVariable(ast.name);
+        auto& targetType = scope.getContext().getType(target->type);
+        auto& typeScope = targetType.getTypeScope();
+        method = typeScope.getMethod(ast.name);
+        var = typeScope.getVariable(ast.name);
     }
     else {
         method = scope.getMethod(ast.name);
@@ -244,11 +246,9 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FeatureCall& a
             auto* thisExpr = scope.getVariable("this");
             if (!thisExpr)
                 throw "no this found";
-            //Printer::getInstance().debug() << "feature call " << var->toString() << " is a field\n";
             return std::make_unique<sem::FieldAccessExpression>(std::make_unique<sem::LocalVariableExpression>(thisExpr), field);
         }
         else {
-            //Printer::getInstance().debug() << "feature call " << var->toString() << " is not a field\n";
             return std::make_unique<sem::LocalVariableExpression>(var);
         }
     }
@@ -377,31 +377,38 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::UnaryOperation
 
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::BinaryOperation& ast, sem::Scope& scope)
 {
+    sem::Context& context = scope.getContext();
+
     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);
     
-    throw SemanticError(SemanticError::OPERATOR_NOT_FOUND, "TODO implement", ast.pos);
-    /*
-    sem::Method* operationMethod = leftEval->type->getScope().resolveMethod(
+    auto& scop =  leftType.getTypeScope();
+    sem::Method* operationMethod = scop.resolveMethod(
         ast.opString, { rightEval->type }
     );
     
-    Printer::getInstance().debug() << "looked for operation method for operator " <<
-    ast.opString << std::endl;
+#ifdef DEBUGGING
+    Printer::getInstance() << "looked for operation method for operator " <<
+        ast.opString << std::endl;
+#endif
+
     if (!operationMethod) {
         throw SemanticError(SemanticError::OPERATOR_NOT_FOUND,
             "operator " + ast.opString + " not found for types '" +
-            leftEval->type->asString() + "' and '" + rightEval->type->asString() + "'",
+            leftType.asString() + "' and '" + rightType.asString() + "'",
             ast.opPos);
     }
     
-    auto ret = std::make_unique<sem::BinaryOperation>(leftEval->type, &ast);
+    auto ret = std::make_unique<sem::BinaryOperation>(context, leftEval->type, &ast);
     
     ret->operationMethod = operationMethod;
     ret->opString = ast.opString;
     ret->left = std::move(leftEval);
     ret->right = std::move(rightEval);
-    return ret;*/
+    return ret;
 }
 
 

+ 0 - 1
src/ast/lexer.l

@@ -45,7 +45,6 @@ extern "C" int qlow_parser_wrap(yyscan_t s);
 #define YY_NO_UNISTD_H
 #endif
 
-// TODO rewrite
 #define YY_USER_ACTION                                \
   do {                                                \
     yylloc_param->first_line = yylineno;              \

+ 11 - 11
src/sem/CodeGeneration.cpp

@@ -142,6 +142,7 @@ std::unique_ptr<llvm::Module> generateModule(const sem::GlobalScope& semantic)
 
 llvm::Function* generateFunction(llvm::Module* module, sem::Method* method)
 {
+    sem::Context& semCtxt = method->context;
     using llvm::Function;
     using llvm::Argument;
     using llvm::Type;
@@ -149,22 +150,19 @@ llvm::Function* generateFunction(llvm::Module* module, sem::Method* method)
     
     Type* returnType;
     if (method->returnType)
-        // TODO rewrite
-        ;// returnType = method->returnType->getLlvmType(context);
+        returnType = semCtxt.getLlvmType(method->returnType, context);
     else
         returnType = llvm::Type::getVoidTy(context);
     
     std::vector<Type*> argumentTypes;
     if (method->thisExpression != nullptr) {
-        // TODO rewrite
-        //Type* enclosingType = method->thisExpression->type->getLlvmType(context);
-        //argumentTypes.push_back(enclosingType);
+        Type* enclosingType = semCtxt.getLlvmType(method->thisExpression->type, context);
+        argumentTypes.push_back(enclosingType);
     }
     
     for (auto& arg : method->arguments) {
-        // TODO rewrite
-        //Type* argumentType = arg->type->getLlvmType(context);
-        //argumentTypes.push_back(argumentType);
+        Type* argumentType = semCtxt.getLlvmType(arg->type, context);
+        argumentTypes.push_back(argumentType);
     }
     
     FunctionType* funcType = FunctionType::get(
@@ -295,6 +293,8 @@ llvm::Function* qlow::gen::FunctionGenerator::generate(void)
     using llvm::BasicBlock;
     using llvm::Value;
     using llvm::IRBuilder;
+
+    sem::Context& semCtxt = this->method.context;
     
 #ifdef DEBUGGING
     printf("generate function %s\n", method.name.c_str()); 
@@ -318,9 +318,9 @@ llvm::Function* qlow::gen::FunctionGenerator::generate(void)
         if (var->type == sem::NO_TYPE)
             throw "wtf null type";
         
-        // TODO rewrite
-        //llvm::AllocaInst* v = builder.CreateAlloca(var->type->getLlvmType(context));
-        //var->allocaInst = v;
+
+        llvm::AllocaInst* v = builder.CreateAlloca(semCtxt.getLlvmType(var->type, context));
+        var->allocaInst = v;
     }
     
     for (auto& statement : method.body->statements) {

+ 67 - 18
src/sem/Context.cpp

@@ -3,7 +3,9 @@
 #include "Scope.h"
 #include "Builtin.h"
 
+
 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
 {
@@ -14,6 +16,7 @@ size_t std::hash<std::reference_wrapper<qlow::sem::Type>>::operator() (const std
 Context::Context(void)
 {
     nativeScope = std::make_unique<NativeScope>(sem::generateNativeScope(*this));
+    sem::fillNativeScope(*nativeScope);
 }
 
 
@@ -23,58 +26,104 @@ qlow::sem::TypeId Context::addType(Type&& type) {
     }
     else {
         Type gogo = std::move(type);
-        types.push_back(std::move(gogo));
+        types.push_back({ std::move(gogo), nullptr });
         return types.size() - 1;
     }
 }
 
 
-std::optional<std::reference_wrapper<qlow::sem::Type>> Context::getType(TypeId tid)
+qlow::sem::Type& Context::getType(TypeId tid)
 {
-    if (tid <= types.size()) {
-        return std::make_optional<std::reference_wrapper<qlow::sem::Type>>(types[tid]);
-    }
-    else {
+    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 = getType(tid))
+    if (auto type = getMaybeType(tid))
         return type.value().get().asString();
     else
         return "";
 }
 
 
-qlow::sem::TypeId Context::getPointerTo(TypeId id)
+qlow::sem::TypeId Context::getVoidTypeId(void)
 {
-    return addType(Type::createPointerType(*this, id));
+    return getNativeTypeId(Type::Native::VOID);
 }
 
 
-qlow::sem::TypeId Context::getArrayOf(TypeId id)
+qlow::sem::TypeId Context::getNativeTypeId(Type::Native n)
 {
-    return addType(Type::createArrayType(*this, id));
+    return nativeScope->getType(n);
 }
 
 
-qlow::sem::TypeId Context::getVoidTypeId(void)
+qlow::sem::NativeScope& Context::getNativeScope(void)
 {
-    return getNativeTypeId(Type::Native::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));
+}
 
-qlow::sem::TypeId Context::getNativeTypeId(Type::Native n)
+
+sem::TypeId Context::createClassType(Class* classType)
 {
-    return nativeScope->getType(n);
+    TypeId reserved = types.size();
+    Type t = Type{ *this, Type::Union{ Type::ClassType{ classType }}, reserved };
+    return addType(std::move(t));
 }
 
 
-qlow::sem::NativeScope& Context::getNativeScope(void)
+sem::TypeId Context::createPointerType(TypeId pointsTo)
 {
-    return *nativeScope;
+    TypeId reserved = types.size();
+    Type t = Type{ *this, Type::Union{ Type::PointerType{ pointsTo }}, reserved };
+    return addType(std::move(t));
+}
+
+
+sem::TypeId Context::createArrayType(TypeId pointsTo)
+{
+    TypeId reserved = types.size();
+    Type t = Type{ *this, Type::Union{ Type::ArrayType{ pointsTo }}, reserved };
+    return addType(std::move(t));
+}
+
+
+llvm::Type* Context::getLlvmType(TypeId id, llvm::LLVMContext& llvmCtxt)
+{
+    // TODO at the moment, all types are integers --> fix that
+    if (id < types.size()) {
+        auto& llt = types[id].second;
+        if (llt == nullptr) {
+            if (id == 0)
+                llt = llvm::Type::getInt1Ty(llvmCtxt);
+            else
+                llt = llvm::Type::getInt64Ty(llvmCtxt);
+        }
+        return llt;
+    }
+    else {
+        return nullptr;
+    }
 }
 

+ 14 - 9
src/sem/Context.h

@@ -6,6 +6,9 @@
 #include <vector>
 #include <optional>
 
+#include <llvm/IR/Type.h>
+#include <llvm/IR/LLVMContext.h>
+
 #include "Type.h"
 
 namespace qlow::sem
@@ -30,16 +33,16 @@ namespace std
 class qlow::sem::Context
 {
 private:
-    std::vector<Type> types;
+    std::vector<std::pair<Type, llvm::Type*>> types;
     std::unordered_map<std::reference_wrapper<Type>, TypeId, std::hash<std::reference_wrapper<Type>>, std::equal_to<Type>> typesMap;
-    
-    std::unique_ptr<NativeScope> nativeScope;
 
+    std::unique_ptr<NativeScope> nativeScope;
 public:
     Context(void);
     
     TypeId addType(Type&& type);
-    std::optional<std::reference_wrapper<Type>> getType(TypeId tid);
+    Type& getType(TypeId tid);
+    std::optional<std::reference_wrapper<Type>> getMaybeType(TypeId tid);
 
     /**
      * @brief get a string denoting the type
@@ -49,14 +52,16 @@ public:
      */
     std::string getTypeString(TypeId tid);
 
-    TypeId getPointerTo(TypeId id);
-    TypeId getArrayOf(TypeId id);
-
-
     TypeId getVoidTypeId(void);
     TypeId getNativeTypeId(Type::Native n);
-
     NativeScope& getNativeScope(void);
+
+    TypeId createNativeType(std::string name, Type::Native type);
+    TypeId createClassType(Class* classType);
+    TypeId createPointerType(TypeId pointsTo);
+    TypeId createArrayType(TypeId pointsTo);
+
+    llvm::Type* getLlvmType(TypeId id, llvm::LLVMContext& llvmCtxt);
 };
 
 #endif // QLOW_SEM_CONTEXT_H

+ 2 - 13
src/sem/Semantic.cpp

@@ -114,17 +114,6 @@ std::pair<std::unique_ptr<Context>, std::unique_ptr<GlobalScope>>
 }
 
 
-SemanticObject::~SemanticObject(void)
-{
-}
-
-
-std::string SemanticObject::toString(void) const
-{
-    return "SemanticObject [" + util::toString(this) + "]";
-}
-
-
 std::string Class::toString(void) const
 {
     std::string val = "Class[";
@@ -242,14 +231,14 @@ std::string CastExpression::toString(void) const
 {
     // TODO remove optional unwrapping
     return "CastExpression[" + expression->toString() + " to " +
-        context.getType(targetType).value().get().asString() + "]";
+        context.getType(targetType).asString() + "]";
 }
 
 
 std::string NewArrayExpression::toString(void) const
 {
     // TODO remove optional unwrapping
-    return "NewArrayExpression[" + context.getType(arrayType).value().get().asString() + "; " +
+    return "NewArrayExpression[" + context.getType(arrayType).asString() + "; " +
         length->toString() + "]";
 }
 

+ 5 - 6
src/sem/Semantic.h

@@ -87,7 +87,7 @@ struct qlow::sem::Class : public SemanticObject
         astNode{ astNode },
         name{ astNode->name },
         scope{ globalScope, this },
-        classType{ globalScope.getContext().addType(Type::createClassType(globalScope.getContext(), this)) },
+        classType{ globalScope.getContext().createClassType(this) },
         llvmType{ nullptr }
     {
     }
@@ -190,9 +190,8 @@ struct qlow::sem::ThisExpression : public Variable
     inline ThisExpression(Method* method) :
         Variable{
             method->context,
-            method->context.addType(Type::createPointerType(method->context,
-                        method->context.addType(Type::createClassType(method->context,
-                            method->containingClass)))),
+            method->context.createPointerType(method->context.createClassType(
+                            method->containingClass)),
             "this"
         },
         method{ method }
@@ -342,7 +341,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.getPointerTo(target->type) },
+        Expression{ target->context, context.createPointerType(target->type) },
         target{ std::move(target) }
     {
     }
@@ -402,7 +401,7 @@ struct qlow::sem::NewArrayExpression : public Expression
     std::unique_ptr<Expression> length;
     
     inline NewArrayExpression(Context& context, TypeId arrayType) :
-        Expression{ context, context.getArrayOf(arrayType) },
+        Expression{ context, context.createArrayType(arrayType) },
         arrayType{ arrayType }
     {
     }

+ 11 - 317
src/sem/Type.cpp

@@ -2,52 +2,36 @@
 #include "Scope.h"
 #include "Context.h"
 #include "Semantic.h"
+#include "Builtin.h"
 #include "ErrorReporting.h"
 
 using qlow::sem::TypeId;
 using qlow::sem::Type;
 
+qlow::sem::SemanticObject::~SemanticObject(void) = default;
 
-/*
-TypeId TypeId::toPointer(void) const
-{
-    return context.addType(Type::createPointerType(context, *this));
-}
 
-
-TypeId TypeId::toArray(void) const
+std::string qlow::sem::SemanticObject::toString(void) const
 {
-    return context.addType(Type::createArrayType(context, *this));
+    return "SemanticObject [" + util::toString(this) + "]";
 }
 
-*/
-/*
-Type::NativeType::NativeType(void) = default;
-Type::NativeType::NativeType(NativeType&&) = default;
-
-Type::NativeType::NativeType(Native type) :
-    type{ type }, typeScope{ nullptr } {}
 
-Type::NativeType::~NativeType(void)
+Type::Type(Context& context, Union type, TypeId id) :
+    Type{ context, type, "", id }
 {
 }
-*/
 
-Type::Type(Context& context, Union type) :
-    Type{ context, type, "" }
-{
-}
 
-
-Type::Type(Context& context, Union type, std::string name) :
+Type::Type(Context& context, Union type, std::string name, TypeId id) :
     name{ std::move(name) },
     type{ std::move(type) }
 {
     if (getKind() == Kind::NATIVE) {
-        typeScope = std::make_unique<NativeTypeScope>(context, *this);
+        typeScope = std::make_unique<NativeTypeScope>(context, id);
     }
     else {
-        typeScope = std::make_unique<TypeScope>(context, *this);
+        typeScope = std::make_unique<TypeScope>(context, id);
     }
 }
 
@@ -119,297 +103,7 @@ qlow::sem::Class* Type::getClass(void) const
 }
 
 
-llvm::Type* Type::getLLVMType(llvm::LLVMContext* context)
-{
-    // TODO implement
-    return nullptr;
-}
-
-
-Type Type::createNativeType(Context& c, std::string name, Native type)
-{
-    return Type{ c, Union{ NativeType{ type } }, std::move(name) };
-}
-
-
-Type Type::createClassType(Context& c, Class* classType)
-{
-    if (classType == nullptr) {
-        throw "invalid class type";
-    }
-    return Type{ c, Union{ ClassType{ classType }}};
-}
-
-
-Type Type::createPointerType(Context& c, TypeId pointsTo)
-{
-    return Type{ c, Union{ PointerType{ pointsTo }}};
-}
-
-
-Type Type::createArrayType(Context& c, TypeId pointsTo)
-{
-    return Type{ c, Union{ ArrayType{ pointsTo }}};
-}
-
-
-
-#if 0
-#include "Semantic.h"
-#include "Builtin.h"
-
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/Type.h>
-
-
-using namespace qlow;
-
-
-sem::Type::~Type(void)
-{
-}
-
-
-bool sem::Type::equals(const Type& other) const
-{
-    return this == &other;
-}
-
-
-size_t sem::Type::hash(void) const
-{
-    return std::hash<std::string>()(this->asString());
-}
-
-
-/*std::shared_ptr<sem::Type> sem::Type::VOID =
-    std::make_shared<sem::NativeType>(sem::NativeType::Type::VOID);
-std::shared_ptr<sem::Type> sem::Type::INTEGER =
-    std::make_shared<sem::NativeType>(sem::NativeType::Type::INTEGER);
-std::shared_ptr<sem::Type> sem::Type::BOOLEAN =
-    std::make_shared<sem::NativeType>(sem::NativeType::Type::BOOLEAN);
-*/
-
-std::string sem::PointerType::asString(void) const
-{
-    return derefType->asString() + "*";
-}
-
-
-sem::Scope& sem::PointerType::getScope(void)
-{
-    return scope;
-}
-
-
-llvm::Type* sem::PointerType::getLlvmType(llvm::LLVMContext& context) const
-{
-    return derefType->getLlvmType(context)->getPointerTo();
-}
-
-
-bool sem::PointerType::equals(const Type& other) const
-{
-    if (const PointerType* opt = dynamic_cast<const PointerType*>(&other); opt) {
-        return derefType->equals(*opt->getDerefType());
-    }
-    else
-        return false;
-}
-
-
-std::string sem::ClassType::asString(void) const
+void Type::setTypeScope(std::unique_ptr<TypeScope> scope)
 {
-    return classType->name;
-}
-
-
-
-sem::Scope& sem::ClassType::getScope(void)
-{
-    return scope;
-}
-
-
-llvm::Type* sem::ClassType::getLlvmType (llvm::LLVMContext& context) const
-{
-    return classType->llvmType;
-}
-
-
-bool sem::ClassType::equals(const Type& other) const
-{
-    if (auto* oct = dynamic_cast<const ClassType*>(&other); oct) {
-        return this->classType == oct->classType;
-    }
-    else {
-        return false;
-    }
-}
-
-
-std::string sem::ArrayType::asString(void) const
-{
-    return std::string("[") + arrayType->asString() + "]";
-}
-
-
-sem::Scope& sem::ArrayType::getScope(void)
-{
-    return scope;
-}
-
-
-llvm::Type* sem::ArrayType::getLlvmType (llvm::LLVMContext& context) const
-{
-    // TODO implement
-    return nullptr;
-}
-
-
-bool sem::ArrayType::equals(const Type& other) const
-{
-    if (auto* oct = dynamic_cast<const ArrayType*>(&other); oct) {
-        return this->arrayType->equals(*oct->arrayType);
-    }
-    else {
-        return false;
-    }
-}
-
-
-std::string sem::NativeType::asString(void) const
-{
-    switch(type) {
-        case VOID:
-            return "Void";
-        case INTEGER:
-            return "Integer";
-        case BOOLEAN:
-            return "Boolean";
-        case CHAR:
-            return "Char";
-        case INT8:
-            return "Int8";
-        case INT16:
-            return "Int16";
-        case INT32:
-            return "Int32";
-        case INT64:
-            return "Int64";
-        case INT128:
-            return "Int128";
-        case UINT8:
-            return "UInt8";
-        case UINT16:
-            return "UInt16";
-        case UINT32:
-            return "UInt32";
-        case UINT64:
-            return "UInt64";
-        case UINT128:
-            return "UInt128";
-        case FLOAT32:
-            return "Float32";
-        case FLOAT64:
-            return "Float64";
-        case FLOAT128:
-            return "Float128";
-    }
-}
-
-
-sem::Scope& sem::NativeType::getScope(void)
-{
-    return scope;
-}
-
-
-bool sem::NativeType::isIntegerType(void) const
-{
-    switch(type) {
-        case INTEGER:
-        case INT8:
-        case INT16:
-        case INT32:
-        case INT64:
-        case INT128:
-        case UINT8:
-        case UINT16:
-        case UINT32:
-        case UINT64:
-        case UINT128:
-            return true;
-        default:
-            return false;
-    }
-}
-
-
-llvm::Type* sem::NativeType::getLlvmType(llvm::LLVMContext& context) const
-{
-    switch (type) {
-        case VOID:
-            return llvm::Type::getVoidTy(context);
-        case INTEGER:
-            return llvm::Type::getInt32Ty(context);
-        case BOOLEAN:
-            return llvm::Type::getInt1Ty(context);
-        case CHAR:
-            return llvm::Type::getInt32Ty(context);
-            
-        case INT8:
-            return llvm::Type::getInt8Ty(context);
-        case INT16:
-            return llvm::Type::getInt16Ty(context);
-        case INT32:
-            return llvm::Type::getInt32Ty(context);
-        case INT64:
-            return llvm::Type::getInt64Ty(context);
-        case INT128:
-            return llvm::Type::getInt128Ty(context);
-            
-        case UINT8:
-            return llvm::Type::getInt8Ty(context);
-        case UINT16:
-            return llvm::Type::getInt16Ty(context);
-        case UINT32:
-            return llvm::Type::getInt32Ty(context);
-        case UINT64:
-            return llvm::Type::getInt64Ty(context);
-        case UINT128:
-            return llvm::Type::getInt128Ty(context);
-            
-        case FLOAT32:
-            return llvm::Type::getFloatTy(context);
-        case FLOAT64:
-            return llvm::Type::getDoubleTy(context);
-        case FLOAT128:
-            return llvm::Type::getFP128Ty(context);
-        default:
-            return nullptr;
-    }
-}
-
-
-bool sem::NativeType::equals(const sem::Type& other) const
-{
-    if (auto* oct = dynamic_cast<const NativeType*>(&other); oct) {
-        if (this->type == Type::INTEGER || this->type == Type::INT32) {
-            if (oct->type == Type::INTEGER || oct->type == Type::INT32)
-                // Int32 == Integer
-                return true;
-        }
-        return this->type == oct->type;
-    }
-    else {
-        return false;
-    }
-}
-
-
-llvm::Value* sem::NativeType::generateImplicitCast(llvm::Value* value)
-{
-    // TODO implement
+    this->typeScope = std::move(scope);
 }
-#endif

+ 13 - 215
src/sem/Type.h

@@ -36,32 +36,12 @@ struct qlow::sem::SemanticObject
     virtual ~SemanticObject(void);
     
     /**
-     * \brief converts the object to a readable string for debugging purposes. 
+     * @brief converts the object to a readable string for debugging purposes. 
      */
     virtual std::string toString(void) const;
 };
 
 
-/*
-class qlow::sem::TypeId
-{
-    Context& context;
-    size_t id;
-public:
-    inline TypeId(Context& context, size_t id) :
-        context{ context }, id{ id } {}
-
-    inline TypeId(Context& context) :
-        context{ context }, id{ std::numeric_limits<size_t>::max() } {}
-
-    inline Context& getContext(void) const { return context; }
-    inline size_t getId(void) const { return id; }
-
-    TypeId toPointer(void) const;
-    TypeId toArray(void) const;
-};
-*/
-
 
 class qlow::sem::Type
 {
@@ -83,9 +63,6 @@ public:
     };
 
 private:
-    std::string name;
-    std::unique_ptr<TypeScope> typeScope;
-
     struct NativeType
     {
         Native type;
@@ -111,10 +88,13 @@ private:
     };
 
     using Union = std::variant<NativeType, ClassType, PointerType, ArrayType>;
+
+    std::string name;
+    std::unique_ptr<TypeScope> typeScope;
     Union type;
 
-    inline Type(Context& context, Union type);
-    inline Type(Context& context, Union type, std::string name);
+    Type(Context& context, Union type, TypeId id);
+    Type(Context& context, Union type, std::string name, TypeId id);
 
 public:
     ~Type(void);
@@ -138,198 +118,16 @@ public:
     Class* getClass(void) const;
     
     /**
-     * @brief returns the type scope of this type if the type
-     *        is native, <code>nullptr</code> otherwise.
+     * @brief returns the type scope of this type
      */
-    const TypeScope& getTypeScope(void) const;
-
-    llvm::Type* getLLVMType(llvm::LLVMContext* context);
-
-    static Type createNativeType(Context& c, std::string name, Native type);
-    static Type createClassType(Context& c, Class* classType);
-    static Type createPointerType(Context& c, TypeId pointsTo);
-    static Type createArrayType(Context& c, TypeId pointsTo);
-};
-
- 
-#if 0
-#include "Scope.h"
-
-#include <memory>
-#include <string>
-
-namespace llvm {
-    class Value;
-    class Type;
-    class LLVMContext;
-}
-
-namespace qlow
-{
-    namespace sem
-    {
-        // forward declarations
-        struct Class;
-        
-        class Scope;
-        
-        struct NativeMethod;
-    }
-
-
-    namespace sem
-    {
-        struct SemanticObject;
-        
-        class Type;
-        
-        class PointerType;
-        class ClassType;
-        class ArrayType;
-        class NativeType;
-    }
-}
-
-class qlow::sem::Type : public SemanticObject
-{
-public:
-    virtual ~Type(void);
-
-    /// \returns false by default
-    virtual inline bool isPointerType(void) const { return false; }
-    
-    /// \returns false by default
-    virtual inline bool isClassType(void) const { return false; }
-    
-    /// \returns false by default
-    virtual inline bool isNativeType(void) const { return false; }
-    
-    /// \returns false by default
-    virtual inline bool isArrayType(void) const { return false; }
-
-    virtual std::string asString(void) const = 0;
-    virtual Scope& getScope(void) = 0;
-    
-    virtual y = 0;
-    
-    virtual bool equals(const Type& other) const;
-
-    virtual size_t hash(void) const;
-    
-//    static TypeId VOID;
-//    static TypeId INTEGER;
-//    static TypeId BOOLEAN;
-};
-
-
-class qlow::sem::PointerType : public Type
-{
-    TypeId derefType;
-    sem::TypeScope scope;
-public:
-    inline PointerType(TypeId derefType) :
-        derefType{ derefType },
-        scope{ *this }
-    {
-    }
-    
-    const TypeId& getDerefType(void) const { return derefType; }
-    
-    inline bool isPointerType(void) const override { return true; }
-    
-    virtual std::string asString(void) const override;
-    virtual Scope& getScope(void) override;
-    
-    virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
-    
-    virtual bool equals(const Type& other) const override;
-};
-
-
-class qlow::sem::ClassType : public Type
-{
-    sem::Class* classType;
-    sem::TypeScope scope;
-public:
-    inline ClassType(sem::Class* classType) :
-        classType{ classType },
-        scope{ *this }
-    {
-    }
-    
-    inline bool isClassType(void) const override { return true; }
-    
-    std::string asString(void) const override;
-    Scope& getScope(void) override;
-    
-    virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
-    inline sem::Class* getClassType(void) { return classType; }
-    virtual bool equals(const Type& other) const override;
-};
-
-
-class qlow::sem::ArrayType : public Type
-{
-    std::shared_ptr<sem::Type> arrayType;
-    TypeScope scope;
-public:
-    
-    inline ArrayType(std::shared_ptr<sem::Type> arrayType) :
-        arrayType{ std::move(arrayType) },
-        scope{ *this }
-    {
-    }
-    
-    inline bool isArrayType(void) const override { return true; }
-    
-    std::string asString(void) const override;
-    Scope& getScope(void) override;
-    
-    virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
-    inline std::shared_ptr<sem::Type> getArrayType(void) { return arrayType; }
-    virtual bool equals(const Type& other) const override;
-};
-
-
-class qlow::sem::NativeType : public Type
-{
-    NativeTypeScope scope;
-public:
-    enum Type {
-        VOID,
-        INTEGER,
-        BOOLEAN,
-        CHAR,
-        STRING,
-        INT8, INT16, INT32, INT64, INT128,
-        UINT8, UINT16, UINT32, UINT64, UINT128,
-        FLOAT32, FLOAT64, FLOAT128,
-    };
-    
-    Type type;
-    
-    SymbolTable<NativeMethod> nativeMethods;
-    
-    inline NativeType(Type type) :
-        scope{ *this },
-        type{ type }
-    {
-    }
-    
-    inline bool isNativeType(void) const override { return true; }
+    inline TypeScope& getTypeScope(void) const { return *typeScope; }
     
-    std::string asString(void) const override;
-    Scope& getScope(void) override;
-    
-    bool isIntegerType(void) const;
-    
-    llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
-    virtual bool equals(const sem::Type& other) const override;
-    
-    /// cast an llvm::Value from another native type to this one
-    llvm::Value* generateImplicitCast(llvm::Value* value);
+    /**
+     * @brief sets the type scope of this type
+     */
+    void setTypeScope(std::unique_ptr<TypeScope> scope);
 };
 
-#endif
 
 #endif // QLOW_SEM_TYPE_H
+

+ 1 - 1
src/test.qlw

@@ -6,7 +6,7 @@ fast_fibonacci(i: Integer): Integer do
     count := i
     a := 0
     b := 1
-    while count != 0 do
+    while count do
         temp := a
         a := a + b
         b := temp