Browse Source

working on iterators

Nicolas Winkler 6 năm trước cách đây
mục cha
commit
d6b68c2525
20 tập tin đã thay đổi với 278 bổ sung63 xóa
  1. 10 21
      src/Ast.h
  2. 5 1
      src/AstVisitor.cpp
  3. 1 0
      src/AstVisitor.h
  4. 42 4
      src/Builtin.cpp
  5. 47 14
      src/Builtin.h
  6. 1 1
      src/CodeGeneration.cpp
  7. 1 0
      src/CodeGeneration.h
  8. 47 0
      src/CodegenVisitor.cpp
  9. 5 0
      src/Driver.cpp
  10. 1 0
      src/ErrorReporting.cpp
  11. 3 1
      src/ErrorReporting.h
  12. 24 1
      src/Scope.cpp
  13. 2 0
      src/Scope.h
  14. 8 5
      src/Semantic.h
  15. 54 0
      src/Type.cpp
  16. 8 1
      src/Type.h
  17. 13 12
      src/lexer.l
  18. 1 0
      src/main.cpp
  19. 1 1
      src/makefile
  20. 4 1
      src/parser.y

+ 10 - 21
src/Ast.h

@@ -430,24 +430,12 @@ struct qlow::ast::IntConst : public Expression
 
 struct qlow::ast::Operation : public Expression
 {
-    enum Operator {
-        PLUS,
-        MINUS,
-        ASTERISK,
-        SLASH,
-        EQUALS,
-        NOT_EQUALS,
-        AND,
-        OR,
-        XOR,
-        NOT
-    };
-    Operator op;
+    std::string opString;
 
-    inline Operation(Operator op, const CodePosition& cp) :
+    inline Operation(const std::string& opString, const CodePosition& cp) :
         AstObject{ cp },
         Expression{ cp },
-        op(op)
+        opString{ opString }
     {
     }
 };
@@ -464,11 +452,12 @@ struct qlow::ast::UnaryOperation : public Operation
     Side side;
     std::unique_ptr<Expression> expr;
 
-    inline UnaryOperation(std::unique_ptr<Expression> expr, Side side, Operator op, const CodePosition& cp) :
+    inline UnaryOperation(std::unique_ptr<Expression> expr, Side side,
+                          const std::string& op, const CodePosition& cp) :
         AstObject{ cp },
-        Operation(op, cp),
-        side(side),
-        expr(std::move(expr))
+        Operation{ op, cp },
+        side{ side },
+        expr{ std::move(expr) }
     {
     }
 
@@ -481,9 +470,9 @@ struct qlow::ast::BinaryOperation : public Operation
     std::unique_ptr<Expression> left;
     std::unique_ptr<Expression> right;
 
-    inline BinaryOperation(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right, Operator op, const CodePosition& cp) :
+    inline BinaryOperation(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right, const std::string& op, const CodePosition& cp) :
         AstObject{ cp },
-        Operation(op, cp),
+        Operation{ op, cp },
         left(std::move(left)), right(std::move(right))
     {
     }

+ 5 - 1
src/AstVisitor.cpp

@@ -263,7 +263,11 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::BinaryOperatio
     auto leftEval = unique_dynamic_cast<sem::Expression>(ast.left->accept(*this, scope));
     auto rightEval = unique_dynamic_cast<sem::Expression>(ast.right->accept(*this, scope));
     
-    auto ret = std::make_unique<sem::BinaryOperation>(leftEval->type);
+    sem::Method* operationMethod = leftEval->type->getScope().resolveMethod(
+        "+", {}
+    );
+    
+    auto ret = std::make_unique<sem::BinaryOperation>(leftEval->type, &ast);
     
     ret->op = ast.op;
     ret->left = std::move(leftEval);

+ 1 - 0
src/AstVisitor.h

@@ -4,6 +4,7 @@
 #include "Visitor.h"
 #include "Ast.h"
 #include "Semantic.h"
+#include "Builtin.h"
 #include "Scope.h"
 
 

+ 42 - 4
src/Builtin.cpp

@@ -14,11 +14,16 @@ sem::NativeScope qlow::sem::generateNativeScope(void)
     NativeScope scope;
     
     std::map<std::string, NativeType::Type> natives = {
-        { "Integer",    NativeType::INTEGER },
         { "Boolean",    NativeType::BOOLEAN },
         { "Char",       NativeType::CHAR },
         { "String",     NativeType::STRING },
         
+        { "Float32",    NativeType::FLOAT32 },
+        { "Float64",    NativeType::FLOAT64 },
+    };
+    
+    std::map<std::string, NativeType::Type> integers = {
+        { "Integer",    NativeType::INTEGER },
         { "Int8",       NativeType::INT8 },
         { "Int16",      NativeType::INT16 },
         { "Int32",      NativeType::INT32 },
@@ -30,9 +35,6 @@ sem::NativeScope qlow::sem::generateNativeScope(void)
         { "UInt32",     NativeType::UINT32 },
         { "UInt64",     NativeType::UINT64 },
         { "UInt128",    NativeType::UINT128 },
-        
-        { "Float32",    NativeType::FLOAT32 },
-        { "Float64",    NativeType::FLOAT64 },
     };
     
     for (auto [name, type] : natives) {
@@ -40,10 +42,46 @@ sem::NativeScope qlow::sem::generateNativeScope(void)
             <std::shared_ptr<NativeType>>(std::make_shared<NativeType>(type)) });
     }
     
+    for (auto [name, type] : integers) {
+        auto native = std::make_shared<NativeType>(type);
+        
+        native->nativeMethods.insert(
+            { "+",
+                std::make_unique<BinaryNativeMethod>( native, native,
+                [] (llvm::IRBuilder<>& builder, llvm::Value* a, llvm::Value* b) {
+                    return builder.CreateAdd(a, b);
+                })
+            }
+        );
+        
+        scope.types.insert({ name, std::make_unique
+            <std::shared_ptr<NativeType>>(std::move(native)) });
+    }
+    
     return scope;
 }
 
 
+llvm::Value* qlow::sem::UnaryNativeMethod::generateCode(llvm::IRBuilder<>& builder,
+    std::vector<llvm::Value*> arguments)
+{
+    if (arguments.size() != 1)
+        throw "invalid unary operation";
+    return generator(builder, arguments[0]);
+}
+
+
+llvm::Value* qlow::sem::BinaryNativeMethod::generateCode(llvm::IRBuilder<>& builder,
+    std::vector<llvm::Value*> arguments)
+{
+    if (arguments.size() != 2)
+        throw "invalid binary operation";
+    return generator(builder, arguments[0], arguments[1]);
+}
+
+
+
+
 
 
 

+ 47 - 14
src/Builtin.h

@@ -5,6 +5,8 @@
 #include "Semantic.h"
 #include "Scope.h"
 
+#include <llvm/IR/Value.h>
+#include <llvm/IR/IRBuilder.h>
 
 namespace qlow
 {
@@ -13,32 +15,63 @@ namespace qlow
         NativeScope generateNativeScope(void);
         
         struct NativeMethod;
-        class IntegerNativeScope;
+        struct UnaryNativeMethod;
+        struct BinaryNativeMethod;
     }
 }
 
 
 struct qlow::sem::NativeMethod : public sem::Method
 {
-    llvm::Value* generateCode(std::vector<llvm::Value*> arguments);
-}
+    inline NativeMethod(std::shared_ptr<Type> returnType) :
+        Method{ NativeScope::getInstance(), std::move(returnType) }
+    {
+    }
+    
+    virtual llvm::Value* generateCode(llvm::IRBuilder<>& builder,
+                                      std::vector<llvm::Value*> arguments) = 0;
+};
 
 
-class qlow::sem::IntegerNativeScope : public NativeScope
+struct qlow::sem::UnaryNativeMethod : public sem::NativeMethod
 {
-public:
-    void generateAdd();
+    std::function<llvm::Value*(llvm::IRBuilder<>&, llvm::Value*)> generator;
+    
+    inline UnaryNativeMethod(std::shared_ptr<Type> returnType,
+        const std::function
+        <llvm::Value*(llvm::IRBuilder<>&, llvm::Value*)>& generator) :
+        NativeMethod{ std::move(returnType) },
+        generator{ generator }
+    {
+    }
+    
+    virtual llvm::Value* generateCode(llvm::IRBuilder<>& builder,
+                                      std::vector<llvm::Value*> arguments);
 };
 
 
-
-
-
-
-
-
-
-
+struct qlow::sem::BinaryNativeMethod : public sem::NativeMethod
+{
+    using Func = 
+        std::function<llvm::Value*(llvm::IRBuilder<>&, llvm::Value*, llvm::Value*)>;
+    
+    Func generator;
+    Variable argument;
+    
+    inline BinaryNativeMethod(std::shared_ptr<Type> returnType,
+                              std::shared_ptr<Type> argumentType,
+        
+        Func&& generator) :
+        NativeMethod{ std::move(returnType) },
+        generator{ generator },
+        argument{ std::move(argumentType), "arg" }
+    {
+        Method::arguments = { &argument };
+    }
+    
+    virtual llvm::Value* generateCode(llvm::IRBuilder<>& builder,
+                                      std::vector<llvm::Value*> arguments);
+};
 
 #endif // QLOW_SEM_BUILTIN_H
 

+ 1 - 1
src/CodeGeneration.cpp

@@ -190,7 +190,7 @@ void generateObjectFile(const std::string& filename, std::unique_ptr<llvm::Modul
         builder.LoopVectorize = true;
         builder.SLPVectorize = true;
     }
-    
+
     builder.populateModulePassManager(pm);
 
     const char cpu[] = "generic";

+ 1 - 0
src/CodeGeneration.h

@@ -2,6 +2,7 @@
 #define QLOW_CODE_GENERATION_H
 
 #include "Semantic.h"
+#include "Builtin.h"
 #include "CodegenVisitor.h"
 
 #include <stack>

+ 47 - 0
src/CodegenVisitor.cpp

@@ -2,6 +2,9 @@
 #include "CodeGeneration.h"
 
 #include "Type.h"
+#include "Builtin.h"
+
+#include "ErrorReporting.h"
 
 #include <llvm/IR/Constants.h>
 #include <llvm/IR/IRBuilder.h>
@@ -35,7 +38,51 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::BinaryOperation& binop, llvm::
     if (!leftType->isNativeType() || !rightType->isNativeType())
         throw "invalid types in BinaryOperation";
     
+    std::string methodName;
+    
+    switch (binop.op) {
+        case ast::Operation::Operator::PLUS:
+            methodName = "+";
+        case ast::Operation::Operator::MINUS:
+            methodName = "-";
+        case ast::Operation::Operator::ASTERISK:
+            methodName = "*";
+        case ast::Operation::Operator::SLASH:
+            methodName = "/";
+            
+        case ast::Operation::Operator::AND:
+            methodName = "and";
+        case ast::Operation::Operator::OR:
+            methodName = "or";
+        case ast::Operation::Operator::XOR:
+            methodName = "xor";
+            
+        case ast::Operation::Operator::EQUALS:
+            methodName = "==";
+        case ast::Operation::Operator::NOT_EQUALS:
+            methodName = "!=";
+            ;
+    }
+    
+    sem::Method* operation =
+        leftType->getScope().resolveMethod(methodName, {leftType, rightType});
     
+    if (operation != nullptr) {
+        if (sem::NativeMethod* nm = dynamic_cast<sem::NativeMethod*>(operation); nm) {
+            return nm->generateCode(builder, {left, right});
+        }
+        else
+            throw "only native operations supported at the moment";
+    }
+    else {
+        auto errMsg = std::string("operator ") + methodName + " not found for types "
+            + leftType->asString() + " and " + rightType->asString();
+        throw SemanticError(SemanticError::OPERATOR_NOT_FOUND, errMsg,
+            binop.astNode->pos
+        );
+    }
+    
+        
     if (left == nullptr) {
         printf("WOW: %s\n", binop.left->toString().c_str());
     }

+ 5 - 0
src/Driver.cpp

@@ -2,6 +2,7 @@
 
 #include "Ast.h"
 #include "Semantic.h"
+#include "Builtin.h"
 #include "CodeGeneration.h"
 
 #include "Logging.h"
@@ -167,6 +168,10 @@ int Driver::run(void)
         logger.logError(err);
         return 1;
     }
+    catch (SemanticError& err) {
+        err.print(logger);
+        return 1;
+    }
     catch (...) {
         logger.logError("unknown error during code generation");
         return 1;

+ 1 - 0
src/ErrorReporting.cpp

@@ -127,6 +127,7 @@ void SemanticError::print(Logger& logger) const
         {DUPLICATE_CLASS_DEFINITION, "duplicate class definition"},
         {DUPLICATE_FIELD_DECLARATION, "duplicate field declaration"},
         {DUPLICATE_METHOD_DEFINITION, "duplicate method definition"},
+        {OPERATOR_NOT_FOUND, ""},
     };
     std::string& errMsg = error[errorCode];
     logger.logError(errMsg + (errMsg != "" ?  ": " : "") + message, where);

+ 3 - 1
src/ErrorReporting.h

@@ -79,6 +79,7 @@ public:
         DUPLICATE_FIELD_DECLARATION,
         DUPLICATE_METHOD_DEFINITION,
         
+        OPERATOR_NOT_FOUND,
         FEATURE_NOT_FOUND,
     };
     
@@ -90,7 +91,8 @@ public:
             CompileError{ where },
             message{ arg },
             errorCode{ ec }
-    {}
+    {
+    }
 
     virtual void print(Logger&) const override;
 };

+ 24 - 1
src/Scope.cpp

@@ -11,6 +11,25 @@ sem::Scope::~Scope(void)
 }
 
 
+sem::Method* sem::Scope::resolveMethod(const std::string& name,
+    const std::vector<std::shared_ptr<Type>> argumentTypes)
+{
+    sem::Method* m = getMethod(name);
+    if (!m)
+        return nullptr;
+    
+    if (m->arguments.size() != argumentTypes.size())
+        return nullptr;
+    
+    for (size_t i = 0; i < argumentTypes.size(); i++) {
+        if (!m->arguments[i]->type->equals(*argumentTypes[i]))
+            return nullptr;
+    }
+    
+    return m;
+}
+
+
 sem::Variable* sem::GlobalScope::getVariable(const std::string& name)
 {
     return nullptr;
@@ -251,7 +270,11 @@ std::string sem::TypeScope::toString(void)
 
 sem::Method* sem::NativeTypeScope::getMethod(const std::string& name)
 {
-    
+    auto m = nativeType.nativeMethods.find(name);
+    if (m != nativeType.nativeMethods.end())
+        return m->second.get();
+    else
+        return TypeScope::getMethod(name);
 }
 
 

+ 2 - 0
src/Scope.h

@@ -50,6 +50,8 @@ public:
     virtual Method* getMethod(const std::string& name) = 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<std::shared_ptr<Type>> argumentTypes);
 
     virtual std::string toString(void) = 0;
 };

+ 8 - 5
src/Semantic.h

@@ -49,8 +49,6 @@ namespace qlow
         struct FeatureCallExpression;
         
         struct IntConst;
-
-        class SemanticException;
     }
 
     class ExpressionCodegenVisitor;
@@ -104,7 +102,7 @@ struct qlow::sem::Variable : public SemanticObject
     llvm::Value* allocaInst;
     
     Variable(void) = default;
-    inline Variable(std::shared_ptr<Type> type, std::string& name) :
+    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;
@@ -264,9 +262,14 @@ struct qlow::sem::BinaryOperation : public Operation
 {
     std::unique_ptr<Expression> left;
     std::unique_ptr<Expression> right;
+    ast::BinaryOperation* astNode;
     
-    inline BinaryOperation(std::shared_ptr<Type> type) :
-        Operation{ std::move(type) }
+    /// method that is called to execute the operator
+    sem::Method* operationMethod;
+    
+    inline BinaryOperation(std::shared_ptr<Type> type, ast::BinaryOperation* astNode) :
+        Operation{ std::move(type) },
+        astNode{ astNode }
     {
     }
     

+ 54 - 0
src/Type.cpp

@@ -29,6 +29,13 @@ std::shared_ptr<sem::Type> sem::Type::BOOLEAN =
     std::make_shared<sem::NativeType>(sem::NativeType::Type::BOOLEAN);
 */
 
+std::string sem::ClassType::asString(void) const
+{
+    return classType->name;
+}
+
+
+
 sem::Scope& sem::ClassType::getScope(void)
 {
     return scope;
@@ -52,6 +59,12 @@ bool sem::ClassType::equals(const Type& other) const
 }
 
 
+std::string sem::ArrayType::asString(void) const
+{
+    return std::string("[") + arrayType->asString() + "]";
+}
+
+
 sem::Scope& sem::ArrayType::getScope(void)
 {
     return scope;
@@ -76,6 +89,47 @@ bool sem::ArrayType::equals(const Type& other) const
 }
 
 
+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;

+ 8 - 1
src/Type.h

@@ -18,6 +18,8 @@ namespace qlow
         struct Class;
         
         class Scope;
+        
+        struct NativeMethod;
     }
 
 
@@ -45,7 +47,6 @@ struct qlow::sem::SemanticObject
 };
 
 
-
 class qlow::sem::Type : public SemanticObject
 {
 public:
@@ -55,6 +56,7 @@ public:
     virtual bool isNativeType(void) const = 0;
     virtual bool isArrayType(void) const = 0;
 
+    virtual std::string asString(void) const = 0;
     virtual Scope& getScope(void) = 0;
     
     virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const = 0;
@@ -82,6 +84,7 @@ public:
     inline bool isNativeType(void) const override { return false; }
     inline bool isArrayType(void) const override { return false; }
     
+    std::string asString(void) const;
     Scope& getScope(void);
     
     virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
@@ -106,6 +109,7 @@ public:
     inline bool isNativeType(void) const override { return false; }
     inline bool isArrayType(void) const override { return true; }
     
+    std::string asString(void) const;
     Scope& getScope(void);
     
     virtual llvm::Type* getLlvmType(llvm::LLVMContext& context) const override;
@@ -131,6 +135,8 @@ public:
     
     Type type;
     
+    SymbolTable<NativeMethod> nativeMethods;
+    
     inline NativeType(Type type) :
         type{ type },
         scope{ *this }
@@ -141,6 +147,7 @@ public:
     inline bool isNativeType(void) const override { return true; }
     inline bool isArrayType(void) const override { return false; }
     
+    std::string asString(void) const;
     Scope& getScope(void);
     
     bool isIntegerType(void) const;

+ 13 - 12
src/lexer.l

@@ -103,20 +103,21 @@ UTF8CHAR [\x00-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xe
 ":"                     return SET_TOKEN(COLON);
 ";"                     return SET_TOKEN(SEMICOLON);
 ","                     return SET_TOKEN(COMMA);
-":="                    return SET_TOKEN(ASSIGN);
 "."                     return SET_TOKEN(DOT);
 
-"=="                    return SET_TOKEN(EQUALS);
-"!="                    return SET_TOKEN(NOT_EQUALS);
-"and"                   return SET_TOKEN(AND);
-"or"                    return SET_TOKEN(OR);
-"xor"                   return SET_TOKEN(XOR);
-"not"                   return SET_TOKEN(NOT);
-
-"+"                     return SET_TOKEN(PLUS);
-"-"                     return SET_TOKEN(MINUS);
-"*"                     return SET_TOKEN(ASTERISK);
-"/"                     return SET_TOKEN(SLASH);
+":="                    SET_STRING; return ASSIGN;
+
+"=="                    SET_STRING; return EQUALS;
+"!="                    SET_STRING; return NOT_EQUALS;
+"and"                   SET_STRING; return AND;
+"or"                    SET_STRING; return OR;
+"xor"                   SET_STRING; return XOR;
+"not"                   SET_STRING; return NOT;
+
+"+"                     SET_STRING; return PLUS;
+"-"                     SET_STRING; return MINUS;
+"*"                     SET_STRING; return ASTERISK;
+"/"                     SET_STRING; return SLASH;
 
 "("                     return SET_TOKEN(ROUND_LEFT);
 ")"                     return SET_TOKEN(ROUND_RIGHT);

+ 1 - 0
src/main.cpp

@@ -4,6 +4,7 @@
 
 #include "Ast.h"
 #include "Semantic.h"
+#include "Builtin.h"
 #include "CodeGeneration.h"
 
 #include "Driver.h"

+ 1 - 1
src/makefile

@@ -9,7 +9,7 @@ INCLUDEDIRS := -I $(shell $(LLVMCONFIG) --includedir)
 CXXFLAGS := -std=c++17 $(INCLUDEDIRS) # -Wall -Wextra
 
 ifdef STATIC
-LDFLAGS := $(shell $(LLVMCONFIG) --link-static --ldflags --system-libs --libs all) -static
+LDFLAGS := $(shell $(LLVMCONFIG) --link-static --ldflags --system-libs --libs all) -static -dead-strip -s
 else
 LDFLAGS := $(shell $(LLVMCONFIG) --ldflags --system-libs --libs all)
 endif

+ 4 - 1
src/parser.y

@@ -127,10 +127,11 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 
 %token <string> IDENTIFIER
 %token <string> INT_LITERAL
+%token <string> ASTERISK SLASH PLUS MINUS EQUALS NOT_EQUALS AND OR XOR CUSTOM_OPERATOR
 %token <token> TRUE FALSE
 %token <token> CLASS DO END IF ELSE WHILE RETURN NEW EXTERN
 %token <token> NEW_LINE
-%token <token> SEMICOLON COLON COMMA DOT ASSIGN EQUALS NOT_EQUALS
+%token <token> SEMICOLON COLON COMMA DOT ASSIGN
 %token <token> ROUND_LEFT ROUND_RIGHT SQUARE_LEFT SQUARE_RIGHT
 %token <string> UNEXPECTED_SYMBOL
 
@@ -172,6 +173,8 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %left NOT
 %left AND
 %left OR XOR
+%left CUSTOM_OPERATOR
+%left ASSIGN
 
 %start topLevel