Browse Source

Merge branch 'types' of https://git.winfor.ch/nicolas/qlow into types

Nicolas Winkler 6 years ago
parent
commit
46274655b4
14 changed files with 890 additions and 136 deletions
  1. 33 0
      src/.gitignore
  2. 336 0
      src/CodeGeneration.cpp
  3. 57 0
      src/CodeGeneration.h
  4. 221 0
      src/Driver.cpp
  5. 52 0
      src/Driver.h
  6. 2 2
      src/Scope.cpp
  7. 32 58
      src/Scope.h
  8. 9 0
      src/ast/Ast.h
  9. 99 0
      src/main.cpp
  10. 2 2
      src/makefile
  11. 1 1
      src/sem/Context.h
  12. 4 3
      src/sem/Semantic.cpp
  13. 17 31
      src/sem/Semantic.h
  14. 25 39
      src/sem/Type.h

+ 33 - 0
src/.gitignore

@@ -0,0 +1,33 @@
+
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app

+ 336 - 0
src/CodeGeneration.cpp

@@ -0,0 +1,336 @@
+#include "CodeGeneration.h"
+
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/LegacyPassManager.h>
+#include <llvm/Transforms/IPO/PassManagerBuilder.h>
+#include <llvm/IR/Type.h>
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/Constants.h>
+#include <llvm/IR/BasicBlock.h>
+#include <llvm/IR/Verifier.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Attributes.h>
+#include <llvm/Target/TargetMachine.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Support/FileSystem.h>
+#include <llvm/Support/raw_os_ostream.h>
+
+
+using namespace qlow;
+
+static llvm::LLVMContext context;
+
+namespace qlow
+{
+namespace gen
+{
+
+std::unique_ptr<llvm::Module> generateModule(const sem::GlobalScope& objects)
+{
+    using llvm::Module;
+    using llvm::Function;
+    using llvm::Argument;
+    using llvm::Type;
+    using llvm::FunctionType;
+    using llvm::BasicBlock;
+    using llvm::Value;
+    using llvm::IRBuilder;
+    
+    Logger& logger = Logger::getInstance();
+    
+#ifdef DEBUGGING
+        printf("creating llvm module\n"); 
+#endif 
+
+    std::unique_ptr<Module> module = llvm::make_unique<Module>("qlow_module", context);
+
+    // create llvm structs
+    // TODO implement detection of circles
+    for (auto& [name, cl] : objects.classes) {
+        llvm::StructType* st;
+        std::vector<llvm::Type*> fields;
+#ifdef DEBUGGING
+        printf("creating llvm struct for %s\n", name.c_str());
+#endif
+        int llvmStructIndex = 0;
+        for (auto& [name, field] : cl->fields) {
+            field->llvmStructIndex = llvmStructIndex;
+            fields.push_back(field->type->getLlvmType(context));
+            if (fields[fields.size() - 1] == nullptr)
+                throw "internal error: possible circular dependency";
+            
+            llvmStructIndex++;
+        }
+        st = llvm::StructType::create(context, fields, name);
+        cl->llvmType = st;
+    }
+    
+    llvm::AttrBuilder ab;
+    ab.addAttribute(llvm::Attribute::AttrKind::NoInline);
+    ab.addAttribute(llvm::Attribute::AttrKind::NoUnwind);
+    //ab.addAttribute(llvm::Attribute::AttrKind::OptimizeNone);
+    //ab.addAttribute(llvm::Attribute::AttrKind::UWTable);
+    ab.addAttribute("no-frame-pointer-elim", "true");
+    ab.addAttribute("no-frame-pointer-elim-non-leaf");
+    llvm::AttributeSet as = llvm::AttributeSet::get(context, ab);
+    
+    
+    std::vector<llvm::Function*> functions;
+    auto verifyStream = llvm::raw_os_ostream(logger.debug());
+    
+    // create all llvm functions
+    for (auto& [name, cl] : objects.classes) {
+        for (auto& [name, method] : cl->methods) {
+            Function* func = generateFunction(module.get(), method.get());
+            for (auto a : as) {
+                func->addFnAttr(a);
+            }
+            functions.push_back(func);
+        }
+    }
+    
+    for (auto& [name, method] : objects.functions) {
+        Function* func = generateFunction(module.get(), method.get());
+        for (auto a : as) {
+            func->addFnAttr(a);
+        }
+        functions.push_back(func);
+    }
+
+    for (auto& [name, cl] : objects.classes){
+        for (auto& [name, method] : cl->methods) {
+            if (!method->body)
+                continue;
+            
+            FunctionGenerator fg(*method, module.get(), as);
+            Function* f = fg.generate();
+            logger.debug() << "verifying function: " << method->name << std::endl;
+            bool corrupt = llvm::verifyFunction(*f, &verifyStream);
+            if (corrupt) {
+                module->print(verifyStream, nullptr);
+                throw "corrupt llvm function";
+            }
+#ifdef DEBUGGING
+            printf("verified function: %s\n", method->name.c_str());
+#endif
+        }
+    }
+    for (auto& [name, method] : objects.functions) {
+        if (!method->body)
+            continue;
+        
+        FunctionGenerator fg(*method, module.get(), as);
+        Function* f = fg.generate();
+        logger.debug() << "verifying function: " << method->name << std::endl;
+        bool corrupt = llvm::verifyFunction(*f, &verifyStream);
+        if (corrupt) {
+            module->print(verifyStream, nullptr);
+            throw "corrupt llvm function";
+        }
+#ifdef DEBUGGING
+        printf("verified function: %s\n", method->name.c_str());
+#endif
+    }
+    return module;
+}
+
+
+llvm::Function* generateFunction(llvm::Module* module, sem::Method* method)
+{
+    using llvm::Function;
+    using llvm::Argument;
+    using llvm::Type;
+    using llvm::FunctionType;
+    
+    Type* returnType;
+    if (method->returnType)
+        returnType = method->returnType->getLlvmType(context);
+    else
+        returnType = llvm::Type::getVoidTy(context);
+    
+    std::vector<Type*> argumentTypes;
+    if (method->thisExpression != nullptr) {
+        Type* enclosingType = method->thisExpression->type->getLlvmType(context);
+        argumentTypes.push_back(enclosingType);
+    }
+    
+    for (auto& arg : method->arguments) {
+        Type* argumentType = arg->type->getLlvmType(context);
+        argumentTypes.push_back(argumentType);
+    }
+    
+    FunctionType* funcType = FunctionType::get(
+        returnType, argumentTypes, false);
+#ifdef DEBUGGING
+    printf("looking up llvm type of %s\n", method->name.c_str());
+#endif 
+    if (returnType == nullptr)
+        throw "invalid return type";
+    Function* func = Function::Create(funcType, Function::ExternalLinkage, method->name, module);
+    method->llvmNode = func;
+    
+    // linking alloca instances for funcs
+    auto argIterator = func->arg_begin();
+    if (method->thisExpression != nullptr) {
+        method->thisExpression->allocaInst = &*argIterator;
+        Logger::getInstance().debug() << "allocaInst of this";
+        argIterator++;
+    }
+    
+    size_t argIndex = 0;
+    for (; argIterator != func->arg_end(); argIterator++) {
+        if (argIndex > method->arguments.size())
+            throw "internal error";
+        method->arguments[argIndex]->allocaInst = &*argIterator;
+#ifdef DEBUGGING
+        printf("allocaInst of arg '%s': %p\n", method->arguments[argIndex]->name.c_str(), method->arguments[argIndex]->allocaInst);
+#endif 
+        argIndex++;
+    }
+    
+    //printf("UEEEEEEEE %s\n", method->name.c_str());
+    return func;
+}
+
+
+void generateObjectFile(const std::string& filename, std::unique_ptr<llvm::Module> module, int optLevel)
+{
+    using llvm::legacy::PassManager;
+    using llvm::PassManagerBuilder;
+    using llvm::raw_fd_ostream;
+    using llvm::Target;
+    using llvm::TargetMachine;
+    using llvm::TargetRegistry;
+    using llvm::TargetOptions;
+
+    Logger& logger = Logger::getInstance();
+    logger.debug() << "verifying mod" << std::endl;
+    auto ostr = llvm::raw_os_ostream(logger.debug());
+#ifdef DEBUGGING
+    module->print(ostr, nullptr);
+#endif
+    bool broken = llvm::verifyModule(*module);
+    
+    if (broken)
+        throw "invalid llvm module";
+    
+    logger.debug() << "mod verified" << std::endl;
+
+    llvm::InitializeAllTargetInfos();
+    llvm::InitializeAllTargets();
+    llvm::InitializeAllTargetMCs();
+    llvm::InitializeAllAsmParsers();
+    llvm::InitializeAllAsmPrinters();
+
+    PassManager pm;
+    
+    int sizeLevel = 0;
+    PassManagerBuilder builder;
+    builder.OptLevel = optLevel;
+    builder.SizeLevel = sizeLevel;
+    if (optLevel >= 2) {
+        builder.DisableUnitAtATime = false;
+        builder.DisableUnrollLoops = false;
+        builder.LoopVectorize = true;
+        builder.SLPVectorize = true;
+    }
+
+    builder.populateModulePassManager(pm);
+
+    const char cpu[] = "generic";
+    const char features[] = "";
+
+    std::string error;
+    std::string targetTriple = llvm::sys::getDefaultTargetTriple();
+    const Target* target = TargetRegistry::lookupTarget(targetTriple, error);
+
+    if (!target) {
+        logger.debug() << "could not create target: " << error << std::endl;
+        throw "internal error";
+    }
+
+    TargetOptions targetOptions;
+    auto relocModel = llvm::Optional<llvm::Reloc::Model>(llvm::Reloc::Model::PIC_);
+    std::unique_ptr<TargetMachine> targetMachine(
+        target->createTargetMachine(targetTriple, cpu,
+            features, targetOptions, relocModel));
+
+    std::error_code errorCode;
+    raw_fd_ostream dest(filename, errorCode, llvm::sys::fs::F_None);
+    targetMachine->addPassesToEmitFile(pm, dest, &dest,
+//        llvm::LLVMTargetMachine::CGFT_ObjectFile,
+        llvm::TargetMachine::CGFT_ObjectFile);
+
+    pm.run(*module);
+    dest.flush();
+    dest.close();
+
+    return;
+}
+
+} // namespace gen
+} // namespace qlow
+
+
+llvm::Function* qlow::gen::FunctionGenerator::generate(void)
+{
+    using llvm::Function;
+    using llvm::Argument;
+    using llvm::Type;
+    using llvm::FunctionType;
+    using llvm::BasicBlock;
+    using llvm::Value;
+    using llvm::IRBuilder;
+    
+#ifdef DEBUGGING
+    printf("generate function %s\n", method.name.c_str()); 
+#endif
+
+    Function* func = module->getFunction(method.name);
+
+    if (func == nullptr) {
+        throw "internal error: function not found";
+    }
+
+    BasicBlock* bb = BasicBlock::Create(context, "entry", func);
+
+    pushBlock(bb);
+
+    IRBuilder<> builder(context);
+    builder.SetInsertPoint(bb);
+    for (auto& [name, var] : method.body->scope.getLocals()) {
+        if (var.get() == nullptr)
+            throw "wtf null variable";
+        if (var->type == nullptr)
+            throw "wtf null type";
+        
+        llvm::AllocaInst* v = builder.CreateAlloca(var->type->getLlvmType(context));
+        var->allocaInst = v;
+    }
+    
+    for (auto& statement : method.body->statements) {
+#ifdef DEBUGGING
+        printf("statement visit %s\n", statement->toString().c_str());
+#endif
+        statement->accept(statementVisitor, *this);
+    }
+    
+
+#ifdef DEBUGGING
+    printf("End of Function\n");
+#endif
+    
+    //Value* val = llvm::ConstantFP::get(context, llvm::APFloat(5.0));
+    
+    builder.SetInsertPoint(getCurrentBlock());
+    if (method.returnType->equals(sem::NativeType(sem::NativeType::Type::VOID))) {
+        if (!getCurrentBlock()->getTerminator())
+            builder.CreateRetVoid();
+    }
+
+    return func;
+}
+
+
+

+ 57 - 0
src/CodeGeneration.h

@@ -0,0 +1,57 @@
+#ifndef QLOW_CODE_GENERATION_H
+#define QLOW_CODE_GENERATION_H
+
+#include "Semantic.h"
+#include "Builtin.h"
+#include "CodegenVisitor.h"
+
+#include <stack>
+
+#include <llvm/IR/Module.h>
+
+namespace qlow
+{
+namespace gen
+{
+    std::unique_ptr<llvm::Module> generateModule(const sem::GlobalScope& objects);
+    llvm::Function* generateFunction (llvm::Module* module, sem::Method* method);
+    void generateObjectFile(const std::string& name, std::unique_ptr<llvm::Module> module, int optLevel);
+
+    class FunctionGenerator;
+}
+}
+
+class qlow::gen::FunctionGenerator
+{
+    const sem::Method& method;
+    llvm::Module* module;
+    llvm::AttributeSet& attributes;
+
+    std::stack<llvm::BasicBlock*> basicBlocks;
+
+public:
+
+    StatementVisitor statementVisitor;
+    ExpressionCodegenVisitor expressionVisitor;
+    LValueVisitor lvalueVisitor;
+
+    inline FunctionGenerator(const sem::Method& m, llvm::Module* module,
+        llvm::AttributeSet& attributes) :
+        method{ m },
+        module{ module },
+        attributes{ attributes },
+        expressionVisitor{ *this }
+    {
+    }
+
+    llvm::Function* generate(void);
+
+    inline llvm::Module* getModule(void) const { return module; }
+    inline llvm::LLVMContext& getContext(void) const { return module->getContext(); }
+    inline llvm::BasicBlock* getCurrentBlock(void) const { return basicBlocks.top(); }
+    inline void pushBlock(llvm::BasicBlock* bb) { basicBlocks.push(bb); }
+    inline llvm::BasicBlock* popBlock(void) { auto* bb = basicBlocks.top(); basicBlocks.pop(); return bb; }
+};
+
+
+#endif // QLOW_CODE_GENERATION_H

+ 221 - 0
src/Driver.cpp

@@ -0,0 +1,221 @@
+#include "Driver.h"
+
+#include "Ast.h"
+#include "Semantic.h"
+#include "Builtin.h"
+#include "CodeGeneration.h"
+
+#include "Logging.h"
+
+#include <cstdio>
+
+extern std::unique_ptr<std::vector<std::unique_ptr<qlow::ast::AstObject>>> parsedClasses;
+extern FILE* qlow_parser_in;
+extern int qlow_parser_parse(void);
+extern const char* qlow_parser_filename;
+
+using namespace qlow;
+
+Options Options::parseOptions(int argc, char** argv)
+{
+    static const std::map<std::string, bool Options::*> boolArgs = 
+    {
+        {"-S",              &Options::emitAssembly},
+        {"--emit-assembly", &Options::emitAssembly},
+        {"-L",              &Options::emitLlvm},
+        {"--emit-llvm",     &Options::emitLlvm},
+    };
+    
+    Options options{};
+    
+    for (int i = 1; i < argc; i++) {
+        std::string arg = argv[i];
+        if (boolArgs.find(arg) != boolArgs.end()) {
+            bool Options::* attr = boolArgs.find(arg)->second;
+            options.*attr = true;
+        }
+        else if (arg == "-o" || arg == "--out") {
+            if (argc > i + 1) {
+                options.outfile = argv[++i];
+            }
+            else {
+                throw "Please specify a filename after '-o'";
+            }
+        }
+        else if (arg.rfind("-O", 0) == 0) {
+            if (arg.size() > 2) {
+                options.optLevel = std::stoi(arg.substr(2));
+            }
+            else {
+                options.optLevel = 2;
+            }
+        }
+        else {
+            if (options.outfile == "")
+                options.outfile = arg + ".o";
+            options.infiles.push_back(std::move(arg));
+        }
+    }
+    if (options.outfile == "")
+        options.outfile = "a.out";
+    return options;
+}
+
+
+Driver::Driver(int argc, char** argv) :
+    options{ Options::parseOptions(argc, argv) }
+{
+}
+
+
+int Driver::run(void)
+{
+    Logger& logger = Logger::getInstance();
+    
+    logger.debug() << "starting parser" << std::endl;
+    //logger.logError("driver not yet implemented", {options.emitAssembly ? "asm" : "noasm", 10, 11, 12, 13});
+    
+    std::vector<std::unique_ptr<qlow::ast::AstObject>> objects;
+    bool errorOccurred = false;
+    
+    for (auto& filename : options.infiles) {
+        std::FILE* file = std::fopen(filename.c_str(), "r");
+        ::qlow_parser_filename = filename.c_str();
+        
+        try {
+            auto newObjects = parseFile(file);
+            objects.insert(objects.end(),
+                           std::make_move_iterator(newObjects.begin()),
+                           std::make_move_iterator(newObjects.end()));
+        }
+        catch (const CompileError& ce) {
+            ce.print(logger);
+            errorOccurred = true;
+        }
+        catch (const char* errMsg) {
+            reportError(errMsg);
+            errorOccurred = true;
+        }
+        catch (...) {
+            reportError("an unknown error occurred.");
+            errorOccurred = true;
+        }
+        
+        if (file)
+            std::fclose(file);
+    }
+    
+    if (errorOccurred) {
+        logger << "Aborting due to syntax errors." << std::endl;
+        return 1;
+    }
+    
+    std::unique_ptr<qlow::sem::GlobalScope> semClasses = nullptr;
+    try {
+        semClasses =
+            qlow::sem::createFromAst(objects);
+    }
+    catch(SemanticError& se) {
+        se.print(logger);
+        errorOccurred = true;
+    }
+    catch(const char* err) {
+        reportError(err);
+        errorOccurred = true;
+    }
+    catch (...) {
+        reportError("an unknown error occurred.");
+        errorOccurred = true;
+    }
+    
+    if (errorOccurred) {
+        logger << "Aborting due to semantic errors." << std::endl;
+        return 1;
+    }
+    
+
+    for (auto& [a, b] : semClasses->classes) {
+        logger.debug() << a << ": " << b->toString() << std::endl;
+    }
+    
+    
+
+    /*auto main = semClasses->classes.find("Main");
+    qlow::sem::Class* mainClass = nullptr;
+    if (main == semClasses->classes.end()) {
+        logger.logError("No Main class found");
+        return 1;
+    }
+    else {
+        mainClass = main->second.get();
+    }*/
+    
+    auto* mainMethod = semClasses->getMethod("main");
+    if (mainMethod == nullptr && false) {
+        // TODO handle main ckeck well
+        logger.logError("no main method found");
+        return 1;
+    }
+    
+    logger.debug() << "starting code generation!" << std::endl;
+
+    std::unique_ptr<llvm::Module> mod = nullptr;
+    
+    try {
+        mod = qlow::gen::generateModule(*semClasses);
+    }
+    catch (const char* err) {
+        reportError(err);
+        return 1;
+    }
+    catch (SemanticError& err) {
+        err.print(logger);
+        return 1;
+    }
+    catch (...) {
+        reportError("unknown error during code generation");
+        return 1;
+    }
+    
+    try {
+        qlow::gen::generateObjectFile(options.outfile, std::move(mod), options.optLevel);
+    }
+    catch (const char* msg) {
+        logger.logError(msg);
+        return 1;
+    }
+    catch (...) {
+        logger.logError("unknown error during object file creation");
+        reportError("unknown error during object file creation");
+        return 1;
+    }
+    
+    logger.debug() << "object exported!" << std::endl;
+    
+    return 0;
+}
+
+
+std::vector<std::unique_ptr<qlow::ast::AstObject>> Driver::parseFile(FILE* file)
+{
+    ::qlow_parser_in = file;
+    if (!::qlow_parser_in)
+        throw "Could not run parser: Invalid file";
+    
+    ::qlow_parser_parse();
+    
+    auto retval = std::move(*parsedClasses);
+    parsedClasses.reset();
+    return retval;
+}
+
+
+
+
+
+
+
+
+
+
+

+ 52 - 0
src/Driver.h

@@ -0,0 +1,52 @@
+#ifndef QLOW_DRIVER_H
+#define QLOW_DRIVER_H
+
+#include <vector>
+#include <optional>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace qlow
+{
+    struct Options;
+    
+    class Driver;
+    
+    
+    namespace ast
+    {
+        struct AstObject;
+    }
+}
+
+
+struct qlow::Options
+{
+    bool emitAssembly;
+    bool emitLlvm;
+    std::string outfile = "a.out";
+    std::vector<std::string> infiles;
+    
+    int optLevel = 0;
+    
+    static Options parseOptions(int argc, char** argv);
+};
+
+
+class qlow::Driver
+{
+    Options options;
+public:
+    Driver(void) = delete;
+    Driver(int argc, char** argv);
+    
+    int run(void);
+    
+    /// \brief runs the parser over a given stream
+    /// \warning Don't call concurrently. Not (yet) supported!
+    std::vector<std::unique_ptr<qlow::ast::AstObject>> parseFile(FILE* file);
+};
+
+
+#endif // QLOW_DRIVER_H

+ 2 - 2
src/Scope.cpp

@@ -12,7 +12,7 @@ sem::Scope::~Scope(void)
 
 
 sem::Method* sem::Scope::resolveMethod(const std::string& name,
-    const std::vector<TypeId> argumentTypes)
+    const std::vector<std::shared_ptr<Type>> argumentTypes)
 {
     sem::Method* m = getMethod(name);
     if (!m)
@@ -45,7 +45,7 @@ sem::Method* sem::GlobalScope::getMethod(const std::string& name)
 }
 
 
-qlow::sem::TypeId sem::GlobalScope::getType(const ast::Type& name)
+std::shared_ptr<sem::Type> sem::GlobalScope::getType(const ast::Type& name)
 {
     if (const auto* arr = dynamic_cast<const ast::ArrayType*>(&name); arr) {
         return std::make_shared<sem::ArrayType>(getType(*arr->arrayType));

+ 32 - 58
src/Scope.h

@@ -25,7 +25,7 @@ namespace qlow
         template<typename T>
         using SymbolTable = std::map<std::string, std::unique_ptr<T>>;
 
-        class Semantic;
+
         struct Class;
         struct Method;
         struct Variable;
@@ -40,8 +40,6 @@ namespace qlow
         class NativeTypeScope;
         
         class Type;
-        using TypeId = size_t;
-
         class NativeType;
     }
 }
@@ -49,25 +47,16 @@ namespace qlow
 
 class qlow::sem::Scope
 {
-protected:
-    const Semantic& semantic;
 public:
-    inline Scope(const Semantic& semantic) :
-        semantic{ semantic }
-    {
-    }
-
     virtual ~Scope(void);
     virtual Variable* getVariable(const std::string& name) = 0;
     virtual Method* getMethod(const std::string& name) = 0;
-    virtual std::optional<TypeId> getType(const ast::Type& name) = 0;
-    virtual std::optional<TypeId> getReturnableType(void) = 0;
+    virtual std::shared_ptr<Type> getType(const ast::Type& name) = 0;
+    virtual std::shared_ptr<Type> getReturnableType(void) = 0;
     virtual Method* resolveMethod(const std::string& name,
-        const std::vector<TypeId> argumentTypes);
+        const std::vector<std::shared_ptr<Type>> argumentTypes);
 
     virtual std::string toString(void) = 0;
-
-    inline const Semantic& getSemantic(void) const { return semantic; }
 };
 
 
@@ -78,18 +67,12 @@ public:
     SymbolTable<Method> functions;
     OwningList<Cast> casts;
 public:
-    inline GlobalScope(const Semantic& semantic) :
-        Scope{ semantic }
-    {
-    }
-
+    virtual Variable* getVariable(const std::string& name);
+    virtual Method* getMethod(const std::string& name);
+    virtual std::shared_ptr<Type> getType(const ast::Type& name);
+    virtual std::shared_ptr<Type> getReturnableType(void);
 
-    virtual Variable* getVariable(const std::string& name) override;
-    virtual Method* getMethod(const std::string& name) override;
-    virtual std::optional<TypeId> getType(const ast::Type& name) override;
-    virtual std::optional<TypeId> getReturnableType(void) override;
-
-    virtual std::string toString(void) override;
+    virtual std::string toString(void);
 };
 
 
@@ -99,14 +82,9 @@ class qlow::sem::NativeScope : public GlobalScope
 public:
     SymbolTable<std::shared_ptr<NativeType>> types;
 public:
-    inline NativeScope(const Semantic& semantic) :
-        GlobalScope{ semantic }
-    {
-    }
-
-    virtual std::optional<TypeId> getType(const ast::Type& name);
+    virtual std::shared_ptr<Type> getType(const ast::Type& name);
 
-    virtual std::string toString(void) override;
+    virtual std::string toString(void);
     
     static NativeScope& getInstance(void);
 };
@@ -119,17 +97,14 @@ class qlow::sem::ClassScope : public Scope
     Class* classRef;
 public:
     inline ClassScope(Scope& parentScope, Class* classRef) :
-        Scope{ parentScope.getSemantic() },
-        parentScope{ parentScope },
-        classRef{ classRef }
+        parentScope{ parentScope }, classRef{ classRef }
     {
     }
-
-    virtual Variable* getVariable(const std::string& name) override;
-    virtual Method* getMethod(const std::string& name) override;
-    virtual std::optional<TypeId> getType(const ast::Type& name) override;
-    virtual std::optional<TypeId> getReturnableType(void) override;
-    virtual std::string toString(void) override;
+    virtual Variable* getVariable(const std::string& name);
+    virtual Method* getMethod(const std::string& name);
+    virtual std::shared_ptr<Type> getType(const ast::Type& name);
+    virtual std::shared_ptr<Type> getReturnableType(void);
+    virtual std::string toString(void);
 };
 
 
@@ -137,7 +112,7 @@ class qlow::sem::LocalScope : public Scope
 {
     Scope& parentScope;
     SymbolTable<Variable> localVariables;
-    std::optional<TypeId> returnType;
+    std::shared_ptr<Type> returnType;
     Method* enclosingMethod;
 public:
     LocalScope(Scope& parentScope, Method* enclosingMethod);
@@ -146,11 +121,11 @@ public:
     void putVariable(const std::string& name, std::unique_ptr<Variable> v);
     SymbolTable<Variable>& getLocals(void);
 
-    virtual Variable* getVariable(const std::string& name) override;
-    virtual Method* getMethod(const std::string& name) override;
-    virtual std::optional<TypeId> getType(const ast::Type& name) override;
-    virtual std::optional<TypeId> getReturnableType(void) override;
-    virtual std::string toString(void) override;
+    virtual Variable* getVariable(const std::string& name);
+    virtual Method* getMethod(const std::string& name);
+    virtual std::shared_ptr<Type> getType(const ast::Type& name);
+    virtual std::shared_ptr<Type> getReturnableType(void);
+    virtual std::string toString(void);
 };
 
 
@@ -159,18 +134,17 @@ class qlow::sem::TypeScope : public Scope
 protected:
     Type& type;
 public:
-    inline TypeScope(const Semantic& semantic, Type& type) :
-        Scope{ semantic },
+    inline TypeScope(Type& type) :
         type{ type }
     {
     }
     
     
-    virtual Variable* getVariable(const std::string& name) override;
-    virtual Method* getMethod(const std::string& name) override;
-    virtual std::optional<TypeId> getType(const ast::Type& name) override;
-    virtual std::optional<TypeId> getReturnableType(void) override;
-    virtual std::string toString(void) override;
+    virtual Variable* getVariable(const std::string& name);
+    virtual Method* getMethod(const std::string& name);
+    virtual std::shared_ptr<Type> getType(const ast::Type& name);
+    virtual std::shared_ptr<Type> getReturnableType(void);
+    virtual std::string toString(void);
 };
 
 
@@ -178,14 +152,14 @@ class qlow::sem::NativeTypeScope : public TypeScope
 {
     NativeType& nativeType;
 public:
-    inline NativeTypeScope(const Semantic& semantic, NativeType& type) :
-        TypeScope{ semantic, (Type&) type },
+    inline NativeTypeScope(NativeType& type) :
+        TypeScope{ (Type&) type },
         nativeType{ type }
     {
     }
     
     
-    virtual Method* getMethod(const std::string& name) override;
+    virtual Method* getMethod(const std::string& name);
     std::shared_ptr<Type> implementInlineOperation(const std::string&, llvm::Value* a);
 };
 

+ 9 - 0
src/ast/Ast.h

@@ -39,6 +39,8 @@ namespace qlow
     class StructureVisitor;
     namespace ast
     {
+        class Ast;
+
         // base class
         struct AstObject;
 
@@ -94,6 +96,13 @@ namespace qlow
 }
 
 
+class qlow::ast::Ast
+{
+    OwningList<AstObject> objects;
+public:
+    inline const OwningList<AstObject>& getObjects(void) const { return objects; }
+};
+
 
 struct qlow::ast::AstObject :
     public Visitable<std::unique_ptr<sem::SemanticObject>, sem::Scope&, StructureVisitor>

+ 99 - 0
src/main.cpp

@@ -1,9 +1,108 @@
+#include <iostream>
+
+#include <unistd.h>
+
+#include "Ast.h"
+#include "Semantic.h"
+#include "Builtin.h"
+#include "CodeGeneration.h"
+
 #include "Driver.h"
 
+
+extern std::unique_ptr<std::vector<std::unique_ptr<qlow::ast::Class>>> parsedClasses;
+extern FILE* qlow_parser_in;
+extern int qlow_parser_parse(void);
+
+
 int main(int argc, char** argv)
 {
+    /*int c;
+    while ((c = getopt(argc, argv, "c:")) != -1) {
+        switch (c) {
+            case 'c':
+                printf("c: %s", optarg);
+            break;
+            default:
+                printf("ay: %c\n", c);
+        }
+    }*/
+    
     qlow::Driver driver(argc, argv);
     return driver.run();
+
+    return 0;
+    /*
+    {
+    const char* filename = argv[optind];
+    
+    try {
+        ::qlow_parser_in = stdin;
+        
+        ::qlow_parser_in = fopen(filename, "r");
+        if (!::qlow_parser_in)
+            throw (std::string("File not found: ") + filename).c_str();
+        
+        ::qlow_parser_parse();
+        std::cout << parsedClasses->size() << std::endl;
+
+        std::cout << "parsing completed!" << std::endl;
+
+        std::unique_ptr<qlow::sem::GlobalScope> semClasses =
+            qlow::sem::createFromAst(*parsedClasses.get());
+
+        for (auto& [a, b] : semClasses->classes) {
+            std::cout << a << ": " << b->toString() << std::endl;
+        }
+
+        auto main = semClasses->classes.find("Main");
+        qlow::sem::Class* mainClass = nullptr;
+        if (main == semClasses->classes.end()) {
+            throw "No Main class found!";
+        }
+        else {
+            mainClass = main->second.get();
+        }
+        auto mainmain = mainClass->methods.find("main");
+        qlow::sem::Method* mainMethod = nullptr;
+        if (mainmain == mainClass->methods.end()) {
+            //throw "No main method found inside Main class!";
+        }
+        else {
+            mainMethod = mainmain->second.get();
+        }
+        
+        std::cout << "starting code generation!" << std::endl;
+
+        auto mod = qlow::gen::generateModule(semClasses->classes);
+        qlow::gen::generateObjectFile("obj.o", std::move(mod));
+        
+        std::cout << "object exported!" << std::endl;
+    }
+    catch (qlow::sem::SemanticException& se)
+    {
+        std::cerr << se.getMessage() << std::endl;
+    }
+    catch (const std::string& err)
+    {
+        std::cerr << err << std::endl;
+    }
+    catch (const char* err)
+    {
+        std::cerr << err << std::endl;
+    }
+    catch (...)
+    {
+        std::cerr << "an unknown error occurred" << std::endl;
+    }
+    
+    if (::qlow_parser_in != stdin)
+        fclose(::qlow_parser_in);
+    }
+
+    for (auto&& c : *parsedClasses) {
+        delete c.release();
+    }*/
 }
 
 

+ 2 - 2
src/makefile

@@ -5,8 +5,8 @@ CXX := clang++
 
 LLVMCONFIG := llvm-config
 
-INCLUDEDIRS := -I$(shell $(LLVMCONFIG) --includedir) -I. -I.. -Isem/ -Iast/
-CXXFLAGS := -std=c++17 $(INCLUDEDIRS) -w $(FLAGS) # -Wall -Wextra
+INCLUDEDIRS := -I$(shell $(LLVMCONFIG) --includedir):. -I.. -Isem/ -Iast/ -I.
+CXXFLAGS := -std=c++17 $(INCLUDEDIRS) -w # -Wall -Wextra
 
 ifdef STATIC
 LDFLAGS := $(shell $(LLVMCONFIG) --link-static --ldflags --system-libs --libs all) -static -dead-strip -s

+ 1 - 1
src/sem/Context.h

@@ -8,7 +8,7 @@ namespace qlow::sem
 {
     class Context;
     
-    using TypeId = size_tg
+    using TypeId = size_t;
 }
 
 

+ 4 - 3
src/sem/Semantic.cpp

@@ -16,7 +16,8 @@ namespace qlow
 namespace sem
 {
 
-std::unique_ptr<Semantic> createFromAst(Ast& ast)
+std::unique_ptr<GlobalScope>
+    createFromAst(const std::vector<std::unique_ptr<qlow::ast::AstObject>>& objects)
 {
     
     Logger& logger = Logger::getInstance();
@@ -27,7 +28,7 @@ std::unique_ptr<Semantic> createFromAst(Ast& ast)
 
     // create classes
     std::unique_ptr<sem::GlobalScope> globalScope = std::make_unique<sem::GlobalScope>();
-    for (auto& astObject : ast.getObjects()) {
+    for (auto& astObject : objects) {
         if (auto* cls = dynamic_cast<ast::Class*>(astObject.get()); cls) {
             globalScope->classes[cls->name] = std::make_unique<sem::Class>(cls, *globalScope);
         }
@@ -105,7 +106,7 @@ std::unique_ptr<Semantic> createFromAst(Ast& ast)
     printf("created all method bodies\n");
 #endif
     
-    return std::make_unique<Semantic>(globalScope);
+    return globalScope;
 }
 
 }

+ 17 - 31
src/sem/Semantic.h

@@ -18,10 +18,8 @@ namespace qlow
 {
     namespace sem
     {
-
-        class Semantic;
-
-        std::unique_ptr<Semantic> createFromAst(ast::Ast& ast);
+        std::unique_ptr<GlobalScope>
+            createFromAst(const std::vector<std::unique_ptr<qlow::ast::AstObject>>& objects);
 
         struct Class;
 
@@ -70,18 +68,6 @@ namespace qlow
 }
 
 
-class qlow::sem::Semantic
-{
-    std::unique_ptr<GlobalScope> globalScope;
-
-    std::vector<std::unique_ptr<Type>> types;
-public:
-    const SymbolTable<Class> getClasses(void) const;
-
-    TypeId getOrInsert(Class* cl);
-};
-
-
 struct qlow::sem::Class : public SemanticObject
 {
     qlow::ast::Class* astNode;
@@ -115,7 +101,7 @@ struct qlow::sem::Class : public SemanticObject
 
 struct qlow::sem::Variable : public SemanticObject
 {
-    TypeId type;
+    std::shared_ptr<Type> type;
     std::string name;
     bool isParameter;
 
@@ -124,13 +110,13 @@ struct qlow::sem::Variable : public SemanticObject
     llvm::Value* allocaInst;
     
     Variable(void) = default;
-    inline Variable(TypeId type, const std::string& name) :
-        type{ type },
+    inline Variable(std::shared_ptr<Type> type, const std::string& name) :
+        type{ std::move(type) },
         name{ name },
         allocaInst { nullptr }
     {
     }
-
+        
     virtual std::string toString(void) const override;
 };
 
@@ -145,7 +131,7 @@ struct qlow::sem::Field : public Variable
 struct qlow::sem::Method : public SemanticObject
 {
     Class* containingType;
-    std::optional<TypeId> returnType;
+    std::shared_ptr<Type> returnType;
     std::vector<Variable*> arguments;
     std::string name;
     ast::MethodDefinition* astNode;
@@ -156,7 +142,7 @@ struct qlow::sem::Method : public SemanticObject
 
     llvm::Function* llvmNode;
 
-    inline Method(Scope& parentScope, std::optional<TypeId> returnType) :
+    inline Method(Scope& parentScope, std::shared_ptr<Type> returnType) :
         containingType{ nullptr },
         returnType{ std::move(returnType) },
         scope{ parentScope, this },
@@ -185,7 +171,7 @@ struct qlow::sem::ThisExpression : public Variable
 {
     Method* method;
     inline ThisExpression(Method* method) :
-        Variable{ ClassType{ method->containingType }, "this" },
+        Variable{ std::make_shared<PointerType>(std::make_shared<ClassType>(method->containingType)), "this" },
         method{ method }
     {
     }
@@ -275,7 +261,7 @@ struct qlow::sem::Expression :
 {
     std::shared_ptr<sem::Type> type;
     
-    inline Expression(std::optional<TypeId> type) :
+    inline Expression(std::shared_ptr<Type> type) :
         type{ std::move(type) }
     {
     }
@@ -291,7 +277,7 @@ struct qlow::sem::Operation : public Expression
 {
     std::string opString;
     
-    inline Operation(std::optional<TypeId> type) :
+    inline Operation(std::shared_ptr<Type> type) :
         Expression{ std::move(type) }
     {
     }
@@ -339,7 +325,7 @@ struct qlow::sem::BinaryOperation : public Operation
     /// method that is called to execute the operator
     sem::Method* operationMethod;
     
-    inline BinaryOperation(std::optional<TypeId> type, ast::BinaryOperation* astNode) :
+    inline BinaryOperation(std::shared_ptr<Type> type, ast::BinaryOperation* astNode) :
         Operation{ std::move(type) },
         astNode{ astNode }
     {
@@ -354,12 +340,12 @@ struct qlow::sem::BinaryOperation : public Operation
 struct qlow::sem::CastExpression : public Expression
 {
     std::unique_ptr<Expression> expression;
-    std::optional<TypeId> targetType;
+    std::shared_ptr<Type> targetType;
     
     ast::CastExpression* astNode;
     
     inline CastExpression(std::unique_ptr<Expression> expression,
-                          std::optional<TypeId> type,
+                          std::shared_ptr<Type> type,
                           ast::CastExpression* astNode) :
         Expression{ type },
         expression{ std::move(expression) },
@@ -376,10 +362,10 @@ struct qlow::sem::CastExpression : public Expression
 
 struct qlow::sem::NewArrayExpression : public Expression
 {
-    std::optional<TypeId> arrayType;
+    std::shared_ptr<Type> arrayType;
     std::unique_ptr<Expression> length;
     
-    inline NewArrayExpression(std::optional<TypeId> arrayType) :
+    inline NewArrayExpression(std::shared_ptr<Type> arrayType) :
         Expression{ std::make_shared<ArrayType>(arrayType) },
         arrayType{ std::move(arrayType) }
     {
@@ -395,7 +381,7 @@ struct qlow::sem::UnaryOperation : public Operation
     qlow::ast::UnaryOperation::Side side;
     std::unique_ptr<Expression> arg;
     
-    inline UnaryOperation(std::optional<TypeId> type) :
+    inline UnaryOperation(std::shared_ptr<Type> type) :
         Operation{ std::move(type) }
     {
     }

+ 25 - 39
src/sem/Type.h

@@ -26,7 +26,6 @@ namespace qlow
     namespace sem
     {
         struct SemanticObject;
-        class Semantic;
         
         class Type;
         
@@ -51,15 +50,7 @@ struct qlow::sem::SemanticObject
 
 class qlow::sem::Type : public SemanticObject
 {
-protected:
-    const Semantic& semantic;
 public:
-
-    inline Type(const Semantic& semantic) :
-        semantic{ semantic }
-    {
-    }
-
     virtual ~Type(void);
 
     /// \returns false by default
@@ -89,25 +80,24 @@ public:
 
 class qlow::sem::PointerType : public Type
 {
-    //std::shared_ptr<Type> derefType;
-    TypeId derefType;
+    std::shared_ptr<Type> derefType;
     sem::TypeScope scope;
 public:
-    inline PointerType(const Semantic& semantic) :
-        Type{ semantic },
-        scope{ semantic, *this }
+    inline PointerType(std::shared_ptr<Type> derefType) :
+        derefType{ derefType },
+        scope{ *this }
     {
     }
-
-    TypeId getDerefType(void) const { return derefType; }
-
+    
+    const std::shared_ptr<Type>& 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;
 };
 
@@ -117,34 +107,32 @@ class qlow::sem::ClassType : public Type
     sem::Class* classType;
     sem::TypeScope scope;
 public:
-    inline ClassType(const Semantic& semantic, sem::Class* classType) :
-        Type{ semantic },
+    inline ClassType(sem::Class* classType) :
         classType{ classType },
-        scope{ semantic, *this }
+        scope{ *this }
     {
     }
-
+    
     inline bool isClassType(void) const override { return true; }
-
+    
     std::string asString(void) const;
     Scope& getScope(void);
-
+    
     virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
     inline sem::Class* getClassType(void) { return classType; }
-    virtual bool equals(const Type& other) const override;
+    virtual bool equals(const Type& other) const;
 };
 
 
 class qlow::sem::ArrayType : public Type
 {
-    TypeId arrayType;
+    std::shared_ptr<sem::Type> arrayType;
     TypeScope scope;
 public:
     
-    inline ArrayType(const Semantic& semantic, TypeId arrayType) :
-        Type{ semantic },
-        arrayType{ arrayType },
-        scope{semantic, *this }
+    inline ArrayType(std::shared_ptr<sem::Type> arrayType) :
+        arrayType{ std::move(arrayType) },
+        scope{ *this }
     {
     }
     
@@ -154,8 +142,8 @@ public:
     Scope& getScope(void);
     
     virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
-    inline TypeId getArrayType(void) { return arrayType; }
-    virtual bool equals(const Type& other) const override;
+    inline std::shared_ptr<sem::Type> getArrayType(void) { return arrayType; }
+    virtual bool equals(const Type& other) const;
 };
 
 
@@ -178,10 +166,9 @@ public:
     
     SymbolTable<NativeMethod> nativeMethods;
     
-    inline NativeType(const Semantic& semantic, Type type) :
-        sem::Type{ semantic },
+    inline NativeType(Type type) :
         type{ type },
-        scope{ semantic, *this }
+        scope{ *this }
     {
     }
     
@@ -193,7 +180,7 @@ public:
     bool isIntegerType(void) const;
     
     llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
-    virtual bool equals(const sem::Type& other) const override;
+    virtual bool equals(const sem::Type& other) const;
     
     /// cast an llvm::Value from another native type to this one
     llvm::Value* generateImplicitCast(llvm::Value* value);
@@ -201,4 +188,3 @@ public:
 
 
 #endif // QLOW_SEM_TYPE_H
-