Nicolas Winkler 6 years ago
parent
commit
7f04239c29
22 changed files with 408 additions and 137 deletions
  1. 2 3
      src/Ast.cpp
  2. 37 18
      src/Ast.h
  3. 21 14
      src/AstVisitor.cpp
  4. 8 8
      src/AstVisitor.h
  5. 13 3
      src/Builtin.cpp
  6. 0 2
      src/Builtin.h
  7. 9 4
      src/CodeGeneration.cpp
  8. 2 2
      src/CodegenVisitor.cpp
  9. 1 0
      src/Driver.cpp
  10. 87 19
      src/ErrorReporting.cpp
  11. 11 0
      src/ErrorReporting.h
  12. 23 12
      src/Scope.cpp
  13. 4 3
      src/Scope.h
  14. 14 4
      src/Semantic.cpp
  15. 12 0
      src/Semantic.h
  16. 49 10
      src/Type.cpp
  17. 19 5
      src/Type.h
  18. 5 5
      src/TypeVisitor.cpp
  19. 32 2
      src/lexer.l
  20. 2 2
      src/makefile
  21. 55 20
      src/parser.y
  22. 2 1
      src/test.qlw

+ 2 - 3
src/Ast.cpp

@@ -19,8 +19,6 @@ std::unique_ptr<qlow::sem::SemanticObject> ClassName::accept(Visitor& v, sem::Sc
 }
 
 ACCEPT_DEFINITION(Class, StructureVisitor)
-ACCEPT_DEFINITION(ClassType, StructureVisitor)
-ACCEPT_DEFINITION(ArrayType, StructureVisitor)
 ACCEPT_DEFINITION(FeatureDeclaration, StructureVisitor)
 ACCEPT_DEFINITION(FieldDeclaration, StructureVisitor)
 ACCEPT_DEFINITION(MethodDefinition, StructureVisitor)
@@ -33,10 +31,11 @@ ACCEPT_DEFINITION(Expression, StructureVisitor)
 ACCEPT_DEFINITION(FeatureCall, StructureVisitor)
 ACCEPT_DEFINITION(AssignmentStatement, StructureVisitor)
 ACCEPT_DEFINITION(ReturnStatement, StructureVisitor)
-ACCEPT_DEFINITION(NewVariableStatement, StructureVisitor)
+ACCEPT_DEFINITION(LocalVariableStatement, StructureVisitor)
 ACCEPT_DEFINITION(IntConst, StructureVisitor)
 ACCEPT_DEFINITION(UnaryOperation, StructureVisitor)
 ACCEPT_DEFINITION(BinaryOperation, StructureVisitor)
+ACCEPT_DEFINITION(NewArrayExpression, StructureVisitor)
 
 
 

+ 37 - 18
src/Ast.h

@@ -66,12 +66,14 @@ namespace qlow
         struct FeatureCall;
         struct AssignmentStatement;
         struct ReturnStatement;
-        struct NewVariableStatement;
+        struct LocalVariableStatement;
         struct IntConst;
 
         struct Operation;
         struct UnaryOperation;
         struct BinaryOperation;
+        
+        struct NewArrayExpression;
     }
 
     namespace sem
@@ -123,6 +125,7 @@ struct qlow::ast::Type : public AstObject
     }
     
     virtual std::string asString(void) const = 0;
+    virtual inline std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&) override {}
 };
 
 
@@ -143,26 +146,22 @@ struct qlow::ast::ClassType : public ast::Type
     }
     
     inline std::string asString(void) const override { return typeName; }
-    
-    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&) override;
 };
 
 
 struct qlow::ast::ArrayType : public ast::Type 
 {
-    std::unique_ptr<ast::Type> superType;
+    std::unique_ptr<ast::Type> arrayType;
     
-    inline ArrayType(std::unique_ptr<ast::Type> superType, const CodePosition& cp) :
+    inline ArrayType(std::unique_ptr<ast::Type> arrayType, const CodePosition& cp) :
         Type{ cp },
-        superType{ std::move(superType) }
+        arrayType{ std::move(arrayType) }
     {
     }
     
     inline std::string asString(void) const override {
-        return std::string("[") + superType->asString() + "]";
+        return std::string("[") + arrayType->asString() + "]";
     }
-    
-    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&) override;
 };
 
 
@@ -220,11 +219,12 @@ struct qlow::ast::MethodDefinition : public FeatureDeclaration
 
 struct qlow::ast::VariableDeclaration  : public AstObject
 {
-    std::string type;
+    std::unique_ptr<ast::Type> type;
     std::string name;
-    inline VariableDeclaration(const std::string& type, const std::string& name, const CodePosition& cp) :
+    inline VariableDeclaration(std::unique_ptr<ast::Type> type, std::string&& name, const CodePosition& cp) :
         AstObject{ cp },
-        type(type), name(name)
+        type{ std::move(type) },
+        name{ std::move(name) }
     {
     }
 
@@ -235,8 +235,8 @@ struct qlow::ast::VariableDeclaration  : public AstObject
 struct qlow::ast::ArgumentDeclaration :
     public VariableDeclaration
 {
-    inline ArgumentDeclaration(const std::string& type, const std::string& name, const CodePosition& cp) :
-        VariableDeclaration(type, name, cp)
+    inline ArgumentDeclaration(std::unique_ptr<ast::Type> type, std::string&& name, const CodePosition& cp) :
+        VariableDeclaration{ std::move(type), std::move(name), cp }
     {
     }
 
@@ -358,14 +358,15 @@ struct qlow::ast::AssignmentStatement : public Statement
 };
 
 
-struct qlow::ast::NewVariableStatement : public Statement
+struct qlow::ast::LocalVariableStatement : public Statement
 {
     std::string name;
-    std::string type;
-    inline NewVariableStatement(std::string&& name, std::string&& type, const CodePosition& cp) :
+    std::unique_ptr<ast::Type> type;
+    inline LocalVariableStatement(std::string&& name, std::unique_ptr<Type> type, const CodePosition& cp) :
         AstObject{ cp },
         Statement{ cp },
-       name{ name }, type{ type }
+       name{ name },
+       type{ std::move(type) }
     {
     } 
 
@@ -450,6 +451,24 @@ struct qlow::ast::BinaryOperation : public Operation
 };
 
 
+struct qlow::ast::NewArrayExpression : public Expression
+{
+    std::unique_ptr<ast::Type> type;
+    std::unique_ptr<Expression> length;
+    inline NewArrayExpression(std::unique_ptr<ast::Type> type,
+                              std::unique_ptr<Expression> length,
+                              const CodePosition& cp) :
+        AstObject{ cp },
+        Expression{ cp },
+        type{ std::move(type) },
+        length{ std::move(length) }
+    {
+    }
+    
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
 #endif // QLOW_AST_H
 
 

+ 21 - 14
src/AstVisitor.cpp

@@ -36,7 +36,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FieldDeclarati
     else {
         throw SemanticError(SemanticError::UNKNOWN_TYPE,
             ast.type->asString(),
-            ast.pos
+            ast.type->pos
         );
     }
     return f;
@@ -48,11 +48,11 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::MethodDefiniti
     auto returnType = scope.getType(*ast.type);
     if (!returnType) {
         throw SemanticError(SemanticError::UNKNOWN_TYPE,
-            ast.type,
-            ast.pos
+            ast.type->asString(),
+            ast.type->pos
         );
     }
-    auto m = std::make_unique<sem::Method>(scope, returnType.value());
+    auto m = std::make_unique<sem::Method>(scope, returnType);
     m->name = ast.name;
     m->astNode = &ast;
     
@@ -79,14 +79,14 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::VariableDeclar
 {
     auto v = std::make_unique<sem::Variable>();
     v->name = ast.name;
-    auto type = scope.getType(ast.type);
+    auto* type = scope.getType(*ast.type);
     if (type) {
-        v->type = type.value();
+        v->type = type;
     }
     else {
         throw SemanticError(SemanticError::UNKNOWN_TYPE,
-            ast.type,
-            ast.pos
+            ast.type->asString(),
+            ast.type->pos
         );
     }
     return v;
@@ -106,13 +106,14 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::DoEndBlock& as
     auto body = std::make_unique<sem::DoEndBlock>(scope);
     for (auto& statement : ast.statements) {
         
-        if (ast::NewVariableStatement* nvs = dynamic_cast<ast::NewVariableStatement*>(statement.get()); nvs) {
-            auto type = body->scope.getType(*nvs->type);
+        if (ast::LocalVariableStatement* nvs = dynamic_cast<ast::LocalVariableStatement*>(statement.get()); nvs) {
+            auto* type = body->scope.getType(*nvs->type);
 
             if (!type)
-                throw SemanticError(SemanticError::UNKNOWN_TYPE, nvs->type, nvs->pos);
-
-            auto var = std::make_unique<sem::Variable>(type.value(), nvs->name);
+                throw SemanticError(SemanticError::UNKNOWN_TYPE,
+                                    nvs->type->asString(),
+                                    nvs->type->pos);
+            auto var = std::make_unique<sem::Variable>(type, nvs->name);
             body->scope.putVariable(nvs->name, std::move(var));
             continue;
         }
@@ -212,7 +213,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::ReturnStatemen
 }
 
 
-std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewVariableStatement& ast, sem::Scope& scope)
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::LocalVariableStatement& ast, sem::Scope& scope)
 {
     throw "shouldn't be called";
 }
@@ -244,3 +245,9 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::BinaryOperatio
 }
 
 
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewArrayExpression& ast, sem::Scope& scope)
+{
+    auto ret = std::make_unique<sem::BinaryOperation>();
+    return ret;
+}
+

+ 8 - 8
src/AstVisitor.h

@@ -37,12 +37,14 @@ namespace qlow
 
         struct FeatureCall;
         struct AssignmentStatement;
-        struct NewVariableStatement;
+        struct LocalVariableStatement;
         struct IntConst;
 
         struct Operation;
         struct UnaryOperation;
         struct BinaryOperation;
+        
+        struct NewArrayExpression;
     }
 }
 
@@ -59,8 +61,6 @@ class qlow::StructureVisitor :
         sem::Scope&,
 
         ast::Class,
-        ast::ClassType,
-        ast::ArrayType,
         ast::FeatureDeclaration,
         ast::FieldDeclaration,
         ast::MethodDefinition,
@@ -72,18 +72,17 @@ class qlow::StructureVisitor :
         ast::FeatureCall,
         ast::AssignmentStatement,
         ast::ReturnStatement,
-        ast::NewVariableStatement,
+        ast::LocalVariableStatement,
         ast::IntConst,
         ast::UnaryOperation,
-        ast::BinaryOperation
+        ast::BinaryOperation,
+        ast::NewArrayExpression
     >
 {
 public:
     using ReturnType = std::unique_ptr<sem::SemanticObject>;
 
     ReturnType visit(ast::Class& ast, sem::Scope& scope) override;
-    ReturnType visit(ast::ClassType& ast, sem::Scope& scope) override;
-    ReturnType visit(ast::ArrayType& ast, sem::Scope& scope) override;
     ReturnType visit(ast::FeatureDeclaration& ast, sem::Scope& scope) override;
     ReturnType visit(ast::FieldDeclaration& ast, sem::Scope& scope) override;
     ReturnType visit(ast::MethodDefinition& ast, sem::Scope& scope) override;
@@ -95,10 +94,11 @@ public:
     ReturnType visit(ast::FeatureCall& ast, sem::Scope& scope) override;
     ReturnType visit(ast::AssignmentStatement& ast, sem::Scope& scope) override;
     ReturnType visit(ast::ReturnStatement& ast, sem::Scope& scope) override;
-    ReturnType visit(ast::NewVariableStatement& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::LocalVariableStatement& ast, sem::Scope& scope) override;
     ReturnType visit(ast::IntConst& ast, sem::Scope& scope) override;
     ReturnType visit(ast::UnaryOperation& ast, sem::Scope& scope) override;
     ReturnType visit(ast::BinaryOperation& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::NewArrayExpression& ast, sem::Scope& scope) override;
 };
 
 

+ 13 - 3
src/Builtin.cpp

@@ -3,14 +3,24 @@
 
 using namespace qlow;
 
-sem::Class sem::int32 = sem::Class{ "Integer", sem::NativeScope::getInstance() };
-sem::Class sem::boolean = sem::Class{ "Boolean", sem::NativeScope::getInstance() };
 
 sem::NativeScope qlow::sem::generateNativeScope(void)
 {
     using sem::Class;
+    using sem::NativeType;
+    using sem::NativeScope;
     
-    sem::NativeScope scope;
+    NativeScope scope;
+    
+    scope.types.insert(
+        {"Integer", std::make_unique<NativeType>(NativeType::INTEGER)}
+    );
+    
+    scope.types.insert(
+        {"Boolean", std::make_unique<NativeType>(NativeType::BOOLEAN)}
+    );
+    
+    return scope;
     
     /*
     std::unique_ptr<sem::Type> int32 =

+ 0 - 2
src/Builtin.h

@@ -10,8 +10,6 @@ namespace qlow
 {
     namespace sem
     {
-        extern Class int32;
-        extern Class boolean;
         NativeScope generateNativeScope(void);
     }
 }

+ 9 - 4
src/CodeGeneration.cpp

@@ -51,7 +51,7 @@ std::unique_ptr<llvm::Module> generateModule(const sem::GlobalScope& objects)
         printf("creating llvm struct for %s\n", name.c_str());
 #endif 
         for (auto& [name, field] : cl->fields) {
-            fields.push_back(field->type.getLlvmType(context));
+            fields.push_back(field->type->getLlvmType(context));
             if (fields[fields.size() - 1] == nullptr)
                 throw "internal error: possible circular dependency";
         }
@@ -102,9 +102,14 @@ llvm::Function* generateFunction(llvm::Module* module, sem::Method* method)
     using llvm::FunctionType;
     
     std::vector<Type*> argumentTypes;
-    Type* returnType = method->returnType.getLlvmType(context);
+    Type* returnType;
+    if (method->returnType)
+        returnType = method->returnType->getLlvmType(context);
+    else
+        returnType = llvm::Type::getVoidTy(context);
+    
     for (auto& arg : method->arguments) {
-        Type* argumentType = arg->type.getLlvmType(context);
+        Type* argumentType = arg->type->getLlvmType(context);
         argumentTypes.push_back(argumentType);
     }
     
@@ -215,7 +220,7 @@ llvm::Function* qlow::gen::FunctionGenerator::generate(void)
     for (auto& [name, var] : method.body->scope.getLocals()) {
         if (var.get() == nullptr)
             throw "wtf null variable";
-        llvm::AllocaInst* v = builder.CreateAlloca(var->type.getLlvmType(context));
+        llvm::AllocaInst* v = builder.CreateAlloca(var->type->getLlvmType(context));
         var->allocaInst = v;
     }
     

+ 2 - 2
src/CodegenVisitor.cpp

@@ -29,7 +29,7 @@ std::pair<llvm::Value*, sem::Type*> ExpressionVisitor::visit(sem::BinaryOperatio
     auto [left, leftType] = binop.left->accept(*this, builder);
     auto [right, rightType] = binop.right->accept(*this, builder);
     
-    if (leftType != Type::INTEGER || rightType != Type::INTEGER)
+    if (!leftType->equals(Type::INTEGER) || !rightType->equals(Type::INTEGER))
         throw "invalid types in BinaryOperation";
     
     if (left == nullptr) {
@@ -89,7 +89,7 @@ std::pair<llvm::Value*, sem::Type*> ExpressionVisitor::visit(sem::FeatureCallExp
         auto& arg = call.arguments[i];
         auto [value, type] = arg->accept(*this, builder);
         
-        if (type != call.callee->arguments[i]->type) {
+        if (!type->equals(call.callee->arguments[i]->type)) {
             throw "argument type mismatch";
         }
         

+ 1 - 0
src/Driver.cpp

@@ -21,6 +21,7 @@ Options Options::parseOptions(int argc, char** argv)
     {
         {"-S",              &Options::emitAssembly},
         {"--emit-assembly", &Options::emitAssembly},
+        {"-O3",             &Options::emitAssembly},
         {"-L",              &Options::emitLlvm},
         {"--emit-llvm",     &Options::emitLlvm},
     };

+ 87 - 19
src/ErrorReporting.cpp

@@ -8,45 +8,113 @@ using qlow::SyntaxError;
 using qlow::SemanticError;
 
 
+namespace qlow
+{
+    void reportError(const CompileError& ce)
+    {
+        Logger& logger = Logger::getInstance();
+        
+        ce.print(logger);
+    }
+}
+
+
+
 CompileError::~CompileError(void)
 {
 }
 
 
+// TODO rewrite more compact and more readable
 void CompileError::underlineError(Logger& logger) const
 {
-    // TODO implement for multiline errors
-    //if (where.first_line != where.last_line)
-    //    throw "TODO";
     std::ifstream file(where.filename);
     
     if (!file)
         return;
     
-    size_t lineNr = 1;
-    while (lineNr < where.first_line) {
-        if (file.get() == '\n') {
-            lineNr++;
+    if (where.isMultiline()) {
+        size_t lineNr = 1;
+        while (lineNr < where.first_line) {
+            if (file.get() == '\n') {
+                lineNr++;
+            }
         }
+        std::string line;
+        std::getline(file, line);
+        
+        int lineNrLength = std::to_string(lineNr).size();
+        
+        logger.err() << "from here:" << std::endl;
+        logger.foreground(Logger::Color::YELLOW, true);
+        logger.err() << lineNr;
+        logger.removeFormatting();
+        logger.err() << ": " << line << std::endl;
+        for (size_t i = 0; i < where.first_column + lineNrLength + 2; i++) {
+            logger.err() << ' ';
+        }
+        logger.foreground(Logger::Color::RED, true);
+        for (size_t i = where.first_column; i < line.size(); i++) {
+            logger.err() << '^';
+        }
+        logger.removeFormatting();
+        
+        lineNr++;
+        while (lineNr < where.last_line) {
+            if (file.get() == '\n') {
+                lineNr++;
+            }
+        }
+        
+        std::getline(file, line);
+        lineNrLength = std::to_string(lineNr).size();
+        logger.err() << std::endl << "to here:" << std::endl;
+        
+        logger.foreground(Logger::Color::YELLOW, true);
+        logger.err() << lineNr;
+        logger.removeFormatting();
+        logger.err() << ": " << line << std::endl;
+        for (size_t i = 0; i < lineNrLength + 2; i++) {
+            logger.err() << ' ';
+        }
+        logger.foreground(Logger::Color::RED, true);
+        for (size_t i = 0; i < where.last_column; i++) {
+            logger.err() << '^';
+        }
+        logger.removeFormatting();
+        logger.err() << std::endl;
+        
     }
-    std::string line;
-    std::getline(file, line);
-    logger.err() << line << std::endl;
-    for (size_t i = 0; i < where.first_column; i++) {
-        logger.err() << ' ';
-    }
-    logger.foreground(Logger::Color::RED, true);
-    for (size_t i = where.first_column; i < where.last_column; i++) {
-        logger.err() << '^';
+    else {
+        size_t lineNr = 1;
+        while (lineNr < where.first_line) {
+            if (file.get() == '\n') {
+                lineNr++;
+            }
+        }
+        std::string line;
+        std::getline(file, line);
+        logger.err() << line << std::endl;
+        for (size_t i = 0; i < where.first_column; i++) {
+            logger.err() << ' ';
+        }
+        logger.foreground(Logger::Color::RED, true);
+        for (size_t i = where.first_column; i < where.last_column; i++) {
+            logger.err() << '^';
+        }
+        logger.removeFormatting();
+        logger.err() << std::endl;
     }
-    logger.removeFormatting();
-    logger.err() << std::endl;
 }
 
 
 void SyntaxError::print(Logger& logger) const
 {
-    logger.logError("Syntax error", where);
+    using namespace std::literals;
+    if (message == "")
+        logger.logError("Syntax error", where);
+    else
+        logger.logError("Syntax error: "s + message, where);
     underlineError(logger);
 }
 

+ 11 - 0
src/ErrorReporting.h

@@ -12,6 +12,8 @@ namespace qlow
     
     class SyntaxError;
     class SemanticError;
+    
+    void reportError(const CompileError& ce);
 }
 
 
@@ -25,6 +27,8 @@ struct qlow::CodePosition
     int last_line;
     int first_column;
     int last_column;
+    
+    inline bool isMultiline(void) const { return first_line != last_line; }
 };
 
 
@@ -47,12 +51,19 @@ public:
 
 class qlow::SyntaxError : public CompileError
 {
+    std::string message;
 public:
     inline SyntaxError(const CodePosition& where) :
         CompileError{ where }
     {
     }
     
+    inline SyntaxError(const std::string& message, const CodePosition& where) :
+        CompileError{ where },
+        message{ message }
+    {
+    }
+    
     virtual void print(Logger&) const override;
 };
 

+ 23 - 12
src/Scope.cpp

@@ -1,6 +1,7 @@
 #include "Scope.h"
 #include "Ast.h"
 #include "Semantic.h"
+#include "Type.h"
 #include "Builtin.h"
 
 using namespace qlow;
@@ -28,7 +29,7 @@ sem::Method* sem::GlobalScope::getMethod(const std::string& name)
 sem::Type* sem::GlobalScope::getType(const ast::Type& name)
 {
     if (const auto* arr = dynamic_cast<const ast::ArrayType*>(&name); arr) {
-        return new sem::ArrayType(getType(arr->arrayType));
+        return new sem::ArrayType(getType(*arr->arrayType));
     }
     
     const auto* classType = dynamic_cast<const ast::ClassType*>(&name);
@@ -36,16 +37,16 @@ sem::Type* sem::GlobalScope::getType(const ast::Type& name)
     if (!classType)
         throw "internal error";
     
-    /*
+    
     auto native = NativeScope::getInstance().getType(name);
     if (native) {
         return native;
     }
-    */
     
-    auto t = classes.find(classType->classType->name);
+    
+    auto t = classes.find(classType->typeName);
     if (t != classes.end())
-        return new sem::ClassType(t->second);
+        return new sem::ClassType(t->second.get());
     
     return nullptr;
 }
@@ -69,13 +70,23 @@ std::string sem::GlobalScope::toString(void)
 }
 
 
-sem::Type* sem::NativeScope::getType(const std::string& name)
+sem::Type* sem::NativeScope::getType(const ast::Type& name)
 {
-    auto t = types.find(name);
+    if (const auto* arr = dynamic_cast<const ast::ArrayType*>(&name); arr) {
+        return new sem::ArrayType(getType(*arr->arrayType));
+    }
+    
+    const auto* classType = dynamic_cast<const ast::ClassType*>(&name);
+   
+    if (!classType)
+        throw "internal error";
+    
+    
+    auto t = types.find(classType->typeName);
     if (t != types.end())
-        return *t->second;
+        return t->second.get();
     
-    return std::nullopt;
+    return nullptr;
 }
 
 
@@ -132,7 +143,7 @@ std::string sem::ClassScope::toString(void)
 }
 
 
-sem::Type* sem::ClassScope::getType(const std::string& name)
+sem::Type* sem::ClassScope::getType(const ast::Type& name)
 {
     return parentScope.getType(name);
 }
@@ -140,7 +151,7 @@ sem::Type* sem::ClassScope::getType(const std::string& name)
 
 sem::Type* sem::ClassScope::getReturnableType(void)
 {
-    return std::nullopt;
+    return nullptr;
 }
 
 
@@ -172,7 +183,7 @@ sem::Method* sem::LocalScope::getMethod(const std::string& name)
 }
 
 
-sem::Type* sem::LocalScope::getType(const std::string& name)
+sem::Type* sem::LocalScope::getType(const ast::Type& name)
 {
     return parentScope.getType(name);
 }

+ 4 - 3
src/Scope.h

@@ -5,8 +5,6 @@
 #include <map>
 #include <memory>
 
-#include "Type.h"
-
 namespace qlow
 {
     namespace ast
@@ -32,6 +30,9 @@ namespace qlow
         class NativeScope;
         class ClassScope;
         class LocalScope;
+        
+        class Type;
+        class NativeType;
     }
 }
 
@@ -68,7 +69,7 @@ class qlow::sem::NativeScope : public GlobalScope
 {
     static NativeScope instance;
 public:
-    SymbolTable<Type> types;
+    SymbolTable<NativeType> types;
 public:
     virtual Type* getType(const ast::Type& name);
 

+ 14 - 4
src/Semantic.cpp

@@ -1,4 +1,5 @@
 #include "Semantic.h"
+#include "Type.h"
 #include "Ast.h"
 #include "AstVisitor.h"
 
@@ -68,10 +69,12 @@ std::unique_ptr<GlobalScope>
     for (auto& [name, method] : globalScope->functions) {
         auto returnType = globalScope->getType(*method->astNode->type);
         if (returnType) {
-            method->returnType = returnType.value();
+            method->returnType = returnType;
         }
         else {
-            SemanticError se(SemanticError::UNKNOWN_TYPE, method->astNode->type->asString(), method->astNode->pos);
+            SemanticError se(SemanticError::UNKNOWN_TYPE,
+                             method->astNode->type->asString(),
+                             method->astNode->type->pos);
         }
         
         // otherwise add to the methods list
@@ -195,6 +198,12 @@ std::string LocalVariableExpression::toString(void) const
 }
 
 
+std::string UnaryOperation::toString(void) const
+{
+    return "UnaryOperation[" + arg->toString() + "]";
+}
+
+
 std::string BinaryOperation::toString(void) const
 {
     return "BinaryOperation[" + left->toString() + ", " +
@@ -202,9 +211,10 @@ std::string BinaryOperation::toString(void) const
 }
 
 
-std::string UnaryOperation::toString(void) const
+std::string NewArrayExpression::toString(void) const
 {
-    return "UnaryOperation[" + arg->toString() + "]";
+    return "NewArrayExpression[" + arrayType->toString() + "; " +
+        length->toString() + "]";
 }
 
 

+ 12 - 0
src/Semantic.h

@@ -41,6 +41,8 @@ namespace qlow
         struct Operation;
         struct UnaryOperation;
         struct BinaryOperation;
+        
+        struct NewArrayExpression;
 
         struct FeatureCallExpression;
         
@@ -244,6 +246,16 @@ struct qlow::sem::BinaryOperation : public Operation
 };
 
 
+struct qlow::sem::NewArrayExpression : public Expression
+{
+    std::unique_ptr<Type> arrayType;
+    std::unique_ptr<Expression> length;
+    
+    virtual std::pair<llvm::Value*, sem::Type*> accept(ExpressionVisitor& visitor, llvm::IRBuilder<>& arg2) override;
+    virtual std::string toString(void) const override;
+};
+
+
 struct qlow::sem::UnaryOperation : public Operation
 {
     qlow::ast::UnaryOperation::Side side;

+ 49 - 10
src/Type.cpp

@@ -15,15 +15,9 @@ sem::Type::~Type(void)
 }
 
 
-bool sem::Type::operator == (const Type& other) const
+bool sem::Type::equals(const Type* other) const
 {
-    return this == &other;
-}
-
-
-bool sem::Type::operator != (const Type& other) const
-{
-    return !(*this != other);
+    return this == other;
 }
 
 
@@ -37,12 +31,57 @@ llvm::Type* sem::ClassType::getLlvmType (llvm::LLVMContext& context) const
 }
 
 
+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;
+    }
+}
+
+
+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;
+    }
+}
+
+
 llvm::Type* sem::NativeType::getLlvmType (llvm::LLVMContext& context) const
 {
-    switch(type) {
+    switch (type) {
+        /*case Kind::NULL_TYPE:
+            return llvm::Type::getVoidTy(context);*/
         case INTEGER:
-            
+            return llvm::Type::getInt32Ty(context);
+        case BOOLEAN:
+            return llvm::Type::getInt1Ty(context);
+        /*case Kind::CLASS:
+            return data.classType->llvmType;*/
     }
 }
 
 
+bool sem::NativeType::equals(const sem::Type* other) const
+{
+    if (auto* oct = dynamic_cast<const NativeType*>(other); oct) {
+        return this->type == oct->type;
+    }
+    else {
+        return false;
+    }
+}
+

+ 19 - 5
src/Type.h

@@ -2,6 +2,7 @@
 #define QLOW_SEM_TYPE_H
 
 #include <memory>
+#include "Semantic.h"
 
 namespace llvm {
     class Type;
@@ -28,7 +29,7 @@ namespace qlow
 }
 
 
-class qlow::sem::Type
+class qlow::sem::Type : public SemanticObject
 {
 public:
     virtual ~Type(void);
@@ -37,11 +38,9 @@ public:
     virtual bool isNativeType(void) const = 0;
     virtual bool isArrayType(void) const = 0;
 
-    Class* getClassType(void);
     virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const = 0;
     
-    virtual bool operator == (const Type& other) const;
-    virtual bool operator != (const Type& other) const;
+    virtual bool equals(const Type* other) const;
     
     static Type* INTEGER;
     static Type* BOOLEAN;
@@ -52,12 +51,18 @@ class qlow::sem::ClassType : public Type
 {
     sem::Class* classType;
 public:
+    inline ClassType(sem::Class* classType) :
+        classType{ classType }
+    {
+    }
+    
     inline bool isClassType(void) const override { return true; }
     inline bool isNativeType(void) const override { return false; }
     inline bool isArrayType(void) const override { return false; }
     
     virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
     inline sem::Class* getClassType(void) { return classType; }
+    virtual bool equals(const Type* other) const;
 };
 
 
@@ -65,11 +70,19 @@ class qlow::sem::ArrayType : public Type
 {
     sem::Type* arrayType;
 public:
+    
+    inline ArrayType(sem::Type* arrayType) :
+        arrayType{ arrayType }
+    {
+    }
+    
     inline bool isClassType(void) const override { return false; }
     inline bool isNativeType(void) const override { return false; }
     inline bool isArrayType(void) const override { return true; }
     
+    virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
     inline sem::Type* getArrayType(void) { return arrayType; }
+    virtual bool equals(const Type* other) const;
 };
 
 
@@ -92,7 +105,8 @@ public:
     inline bool isNativeType(void) const override { return true; }
     inline bool isArrayType(void) const override { return false; }
     
-    virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const;
+    llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
+    virtual bool equals(const sem::Type* other) const;
 };
 
 

+ 5 - 5
src/TypeVisitor.cpp

@@ -4,30 +4,30 @@ using namespace qlow;
 
 
 
-sem::Type sem::TypeVisitor::visit(sem::Expression& expr, const sem::SymbolTable<sem::Class>& classes)
+sem::Type* sem::TypeVisitor::visit(sem::Expression& expr, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 
 
-sem::Type sem::TypeVisitor::visit(sem::UnaryOperation& expr, const sem::SymbolTable<sem::Class>& classes)
+sem::Type* sem::TypeVisitor::visit(sem::UnaryOperation& expr, const sem::SymbolTable<sem::Class>& classes)
 {
     return visit(*expr.arg, classes);
 }
 
 
-sem::Type sem::TypeVisitor::visit(sem::BinaryOperation& expr, const sem::SymbolTable<sem::Class>& classes)
+sem::Type* sem::TypeVisitor::visit(sem::BinaryOperation& expr, const sem::SymbolTable<sem::Class>& classes)
 {
     return visit(*expr.left, classes);
 }
 
 
-sem::Type sem::TypeVisitor::visit(sem::FeatureCallExpression& expr, const sem::SymbolTable<sem::Class>& classes)
+sem::Type* sem::TypeVisitor::visit(sem::FeatureCallExpression& expr, const sem::SymbolTable<sem::Class>& classes)
 {
     return expr.callee->returnType;
 }
 
 
-sem::Type sem::TypeVisitor::visit(sem::IntConst& expr, const sem::SymbolTable<sem::Class>& classes)
+sem::Type* sem::TypeVisitor::visit(sem::IntConst& expr, const sem::SymbolTable<sem::Class>& classes)
 {
     return Type::INTEGER;
 }

+ 32 - 2
src/lexer.l

@@ -32,7 +32,7 @@ extern "C" int yywrap()
 {
     return 1; /* do not continue on EOF */
 }
-
+/*  */
 int commentDepth;
 
 size_t offset;
@@ -61,6 +61,11 @@ extern const char* qlow_parser_filename;
 %x STRING
 %s METHOD
 
+UTF8CHAR [\x00-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xec][\x80-\xbf][\x80-\xbf]|\xed[\x80-\x9f][\x80-\xbf]|[\xee\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf3][\x80-\xbf][\x80-\xbf][\x80-\xbf]|\xf4[\x80-\x8f][\x80-\xbf][\x80-\xbf]
+
+/*UTF8CHAR [a-zA-Z0-9_]
+*/
+
 %%
 
 <COMMENT>"/*"           commentDepth++;
@@ -72,7 +77,8 @@ extern const char* qlow_parser_filename;
 <LINE_COMMENT>.         ; // inside comment, ignore everything
 
 <STRING>"\""            yy_pop_state();
-<STRING>[^\"^]*         printf("%s\n", std::string(yytext, yyleng).c_str());
+<STRING>[^\"^\n]*          printf("%s\n", std::string(yytext, yyleng).c_str());
+<STRING>\n              SET_STRING; return UNEXPECTED_SYMBOL; 
 
 "/*"                    yy_push_state(COMMENT); commentDepth = 1;
 "//"                    yy_push_state(LINE_COMMENT);
@@ -91,6 +97,7 @@ extern const char* qlow_parser_filename;
 "while"                 return SET_TOKEN(WHILE);
 "else"                  return SET_TOKEN(ELSE);
 "return"                return SET_TOKEN(RETURN);
+"new"                   return SET_TOKEN(NEW);
 
 ":"                     return SET_TOKEN(COLON);
 ";"                     return SET_TOKEN(SEMICOLON);
@@ -120,6 +127,29 @@ extern const char* qlow_parser_filename;
 [0-9_]+                 SET_STRING; return INT_LITERAL;
 0x[0-9A-Fa-f]+          SET_STRING; return INT_LITERAL;
 [a-zA-Z_][a-zA-Z0-9_]*  SET_STRING; return IDENTIFIER;
+
 .                       SET_STRING; return UNEXPECTED_SYMBOL; // printf("Unexpected symbol %s.\n", std::string(yytext, yyleng).c_str()); yyterminate();
 
 %%
+
+// [a-zA-Z_][a-zA-Z0-9_]*  SET_STRING; return IDENTIFIER;
+
+
+/*
+QLOW_PARSER_LTYPE qlow_parser_lloc;
+const char* qlow_parser_filename;
+QLOW_PARSER_STYPE qlow_parser_lval;
+
+int main() {
+    while (true) {
+        yylex();
+        auto& qpl = qlow_parser_lval;
+        if (qpl.token > 0 && qpl.token < 1000) {
+            printf("token %d\n", qpl.token);
+        }
+        else {
+            printf("string %s\n", qpl.string->c_str());
+        }
+    }
+}
+*/

+ 2 - 2
src/makefile

@@ -17,7 +17,7 @@ endif
 YACC := bison
 YACCFLAGS := -d
 LEX := flex
-LEXFLAGS :=
+LEXFLAGS := "-8"
 
 #OBJECTS := $(patsubst %.cpp, %.o, $(wildcard *.cpp */*.cpp))
 OBJECTS := $(patsubst %.cpp, %.o, $(wildcard *.cpp)) \
@@ -48,7 +48,7 @@ parser.o: parser.cpp
 	$(YACC) -o $@ $< $(YACCFLAGS)
 
 %.cpp: %.l parser.cpp
-	$(LEX) -o $@ $< $(LEXFLAGS)
+	$(LEX) $(LEXFLAGS) -o $@ $<
 
 
 

+ 55 - 20
src/parser.y

@@ -39,12 +39,7 @@ int qlow_parser_error(const char* msg)
 {
     //throw msg;
     //printf("error happened: %s\n", msg);
-}
-
-void reportError(const qlow::SyntaxError& se)
-{
-    qlow::Logger& logger = qlow::Logger::getInstance();
-    se.print(logger);
+    // throw msg;
 }
 
 std::unique_ptr<std::vector<std::unique_ptr<qlow::ast::AstObject>>> parsedClasses;
@@ -116,10 +111,12 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
     qlow::ast::FeatureCall* featureCall;
     qlow::ast::AssignmentStatement* assignmentStatement;
     qlow::ast::ReturnStatement* returnStatement;
-    qlow::ast::NewVariableStatement* newVariableStatement;
+    qlow::ast::LocalVariableStatement* localVariableStatement;
 
     qlow::ast::UnaryOperation* unaryOperation;
     qlow::ast::BinaryOperation* binaryOperation;
+    
+    qlow::ast::NewArrayExpression* newArrayExpression;
 
     const char* cString;
     std::string* string;
@@ -130,7 +127,7 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %token <string> IDENTIFIER
 %token <string> INT_LITERAL
 %token <token> TRUE FALSE
-%token <token> CLASS DO END IF ELSE WHILE RETURN
+%token <token> CLASS DO END IF ELSE WHILE RETURN NEW
 %token <token> NEW_LINE
 %token <token> SEMICOLON COLON COMMA DOT ASSIGN
 %token <token> ROUND_LEFT ROUND_RIGHT SQUARE_LEFT SQUARE_RIGHT
@@ -155,9 +152,10 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %type <featureCall> featureCall
 %type <assignmentStatement> assignmentStatement 
 %type <returnStatement> returnStatement 
-%type <newVariableStatement> newVariableStatement
+%type <localVariableStatement> localVariableStatement
 %type <unaryOperation> unaryOperation
 %type <binaryOperation> binaryOperation
+%type <newArrayExpression> newArrayExpression
 
 %destructor { } <token>
 %destructor { } <op>
@@ -175,7 +173,6 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 
 %%
 
-
 /* list of class definitions */
 topLevel:
     /* empty */ {
@@ -190,16 +187,36 @@ topLevel:
     topLevel methodDefinition {
         parsedClasses->push_back(std::move(std::unique_ptr<qlow::ast::MethodDefinition>($2)));
         $2 = nullptr;
+    }
+    |
+    topLevel error methodDefinition {
+        reportError(qlow::SyntaxError(@2));
+        yyerrok;
+        parsedClasses->push_back(std::move(std::unique_ptr<qlow::ast::MethodDefinition>($3)));
+        $3 = nullptr;
+    }
+    |
+    topLevel error classDefinition {
+        reportError(qlow::SyntaxError(@2));
+        yyerrok;
+        parsedClasses->push_back(std::move(std::unique_ptr<qlow::ast::Class>($3)));
+        $3 = nullptr;
     };
-    
 
 
 classDefinition:
     CLASS IDENTIFIER featureList END {
         $$ = new Class(*$2, *$3, @$);
         delete $2; delete $3; $2 = 0; $3 = 0;
+    }
+    |
+    CLASS error END {
+        reportError(qlow::SyntaxError(@2));
+        yyerrok;
+        $$ = nullptr;
     };
 
+
 type:
     IDENTIFIER {
         $$ = new qlow::ast::ClassType(std::move(*$1), @$);
@@ -211,7 +228,7 @@ type:
     }
     |
     SQUARE_LEFT error SQUARE_RIGHT {
-        reportError(qlow::SyntaxError(@2));
+        reportError(qlow::SyntaxError("invalid type", @2));
     };
     
 
@@ -223,6 +240,15 @@ featureList:
     featureList featureDeclaration {
         $$ = $1;
         $$->push_back(std::move(std::unique_ptr<FeatureDeclaration>($2)));
+        $2 = nullptr;
+    }
+    |
+    featureList error featureDeclaration {
+        $$ = $1;
+        yyerrok;
+        reportError(qlow::SyntaxError(@2));
+        $$->push_back(std::move(std::unique_ptr<FeatureDeclaration>($3)));
+        $3 = nullptr;
     };
 
 
@@ -282,9 +308,9 @@ argumentList:
 
 
 argumentDeclaration:
-    IDENTIFIER COLON IDENTIFIER {
-        $$ = new ArgumentDeclaration(*$3, *$1, @$);
-        delete $3; delete $1; $1 = $3 = 0;
+    IDENTIFIER COLON type {
+        $$ = new ArgumentDeclaration(std::unique_ptr<qlow::ast::Type>($3), std::move(*$1), @$);
+        delete $1; $1 = nullptr; $3 = nullptr;
     };
 
 
@@ -349,7 +375,7 @@ statement:
         $$ = $1;
     }
     |
-    newVariableStatement statementEnd {
+    localVariableStatement statementEnd {
         $$ = $1;
     }
     |
@@ -422,6 +448,10 @@ expression:
         $$ = $1;
     }
     |
+    newArrayExpression {
+        $$ = $1;
+    }
+    |
     INT_LITERAL {
         $$ = new IntConst(std::move(*$1), @$);
         delete $1;
@@ -487,6 +517,11 @@ paranthesesExpression:
         $$ = $2;
     };
 
+newArrayExpression:
+    NEW SQUARE_LEFT type SEMICOLON expression SQUARE_RIGHT {
+        
+    };
+
 
 assignmentStatement:
     expression ASSIGN expression {
@@ -498,10 +533,10 @@ returnStatement:
         $$ = new ReturnStatement(std::unique_ptr<Expression>($2), @$);
     };
 
-newVariableStatement:
-    IDENTIFIER COLON IDENTIFIER {
-        $$ = new NewVariableStatement(std::move(*$1), std::move(*$3), @$);
-        delete $3; delete $1; $3 = 0; $1 = 0;
+localVariableStatement:
+    IDENTIFIER COLON type {
+        $$ = new LocalVariableStatement(std::move(*$1), std::unique_ptr<qlow::ast::Type>($3), @$);
+        delete $1; $3 = nullptr; $1 = nullptr;
     };
 
 

+ 2 - 1
src/test.qlw

@@ -1,9 +1,10 @@
 
 class Main
     hoi: Fudi 
+    //gaga -> Main;
+
     fop: FF do
         var: Integer
-
         var := 5
         var := 10 + 4 * 6 + 1