Преглед на файлове

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

Nicolas Winkler преди 6 години
родител
ревизия
378e1390dd

+ 17 - 7
src/CMakeLists.txt

@@ -13,23 +13,28 @@ set(CMAKE_CXX_EXTENSIONS OFF)
 
 
 
 
 
 
-find_package(BISON 3.0.0 REQUIRED)
-find_package(FLEX 2.4.0 REQUIRED)
+find_package(BISON 3.0.0)
+find_package(FLEX 2.4.0)
 find_package(LLVM REQUIRED CONFIG)
 find_package(LLVM REQUIRED CONFIG)
 
 
 if( NOT LLVM_FOUND )
 if( NOT LLVM_FOUND )
   message(FATAL_ERROR "LLVM package can't be found. Set CMAKE_PREFIX_PATH variable to LLVM's installation prefix.")
   message(FATAL_ERROR "LLVM package can't be found. Set CMAKE_PREFIX_PATH variable to LLVM's installation prefix.")
 endif()
 endif()
 
 
-BISON_TARGET(QlowParser ast/syntax.y ${CMAKE_CURRENT_BINARY_DIR}/syntax.cpp)
-FLEX_TARGET(QlowLexer ast/lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp)
-ADD_FLEX_BISON_DEPENDENCY(QlowLexer QlowParser)
+if ( BISON_FOUND AND FLEX_FOUND )
+    BISON_TARGET(QlowParser ast/syntax.y ${CMAKE_CURRENT_BINARY_DIR}/syntax.cpp)
+    FLEX_TARGET(QlowLexer ast/lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp)
+    ADD_FLEX_BISON_DEPENDENCY(QlowLexer QlowParser)
+else()
+    FILE(GLOB AdditionalSources bison/*.cpp)
+    include_directories(bison/)
+endif()
 
 
 FILE(GLOB CppSources *.cpp ast/*.cpp sem/*.cpp)
 FILE(GLOB CppSources *.cpp ast/*.cpp sem/*.cpp)
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 include_directories(ast sem .)
 include_directories(ast sem .)
 
 
-add_executable(${PROJECT_NAME} ${BISON_QlowParser_OUTPUTS} ${FLEX_QlowLexer_OUTPUTS} ${CppSources})
+add_executable(${PROJECT_NAME} ${BISON_QlowParser_OUTPUTS} ${FLEX_QlowLexer_OUTPUTS} ${CppSources} ${AdditionalSources})
 
 
 
 
 include_directories( ${LLVM_INCLUDE_DIRS} )
 include_directories( ${LLVM_INCLUDE_DIRS} )
@@ -55,7 +60,12 @@ endif()
 
 
 #explicit_llvm_config(${PROJECT_NAME} STATIC_LIBRARY)
 #explicit_llvm_config(${PROJECT_NAME} STATIC_LIBRARY)
 llvm_config(${PROJECT_NAME})
 llvm_config(${PROJECT_NAME})
-target_link_libraries(${PROJECT_NAME} LLVM)
+
+llvm_map_components_to_libnames(llvm_libs X86 passes)
+
+message( ${llvm_libs} )
+target_link_libraries(${PROJECT_NAME} ${llvm_libs})
+
 
 
 #    MIRParser
 #    MIRParser
 #    LTO
 #    LTO

+ 1 - 5
src/CodegenVisitor.cpp

@@ -131,7 +131,7 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::CastExpression& cast, llvm::IR
 llvm::Value* ExpressionCodegenVisitor::visit(sem::NewExpression& nexpr, llvm::IRBuilder<>& builder)
 llvm::Value* ExpressionCodegenVisitor::visit(sem::NewExpression& nexpr, llvm::IRBuilder<>& builder)
 {
 {
     using llvm::Value;
     using llvm::Value;
-    
+
     sem::Context& semCtxt = nexpr.context;
     sem::Context& semCtxt = nexpr.context;
     sem::TypeId type = nexpr.type;
     sem::TypeId type = nexpr.type;
 
 
@@ -213,10 +213,6 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::FieldAccessExpression& access,
     }
     }
     
     
     llvm::Value* target = access.target->accept(fg.lvalueVisitor, fg);
     llvm::Value* target = access.target->accept(fg.lvalueVisitor, fg);
-    llvm::raw_os_ostream os(Printer::getInstance());
-    type->print(os);
-    os << "\n";
-    os.flush();
 
 
     int structIndex = access.accessed->llvmStructIndex;
     int structIndex = access.accessed->llvmStructIndex;
     llvm::ArrayRef<Value*> indexList = {
     llvm::ArrayRef<Value*> indexList = {

+ 9 - 2
src/ErrorReporting.cpp

@@ -94,7 +94,7 @@ const std::string& InternalError::getMessage(void) const noexcept
     if (errors.find(errorCode) != errors.end())
     if (errors.find(errorCode) != errors.end())
         return errors.at(errorCode);
         return errors.at(errorCode);
     else {
     else {
-        static std::string msg = "error message not found"s;
+        static std::string msg = ""s;
         return msg;
         return msg;
     }
     }
 }
 }
@@ -223,7 +223,7 @@ std::string SemanticError::getMessage(void) const noexcept
     if (errors.find(errorCode) != errors.end())
     if (errors.find(errorCode) != errors.end())
         return errors.at(errorCode);
         return errors.at(errorCode);
     else
     else
-        return "error message not found"s;
+        return ""s;
 }
 }
 
 
 
 
@@ -234,3 +234,10 @@ SemanticError SemanticError::invalidReturnType(const std::string& should,
         should + ", but " + is + " is given.", where };
         should + ", but " + is + " is given.", where };
 }
 }
 
 
+
+SemanticError SemanticError::newForNonClass(const std::string& type,
+    const CodePosition& where)
+{
+    return SemanticError{ NEW_FOR_NON_CLASS, "cannot allocate instance of non-class type '" + type + "' using new", where };
+}
+

+ 2 - 0
src/ErrorReporting.h

@@ -126,6 +126,7 @@ public:
         WRONG_NUMBER_OF_ARGUMENTS,
         WRONG_NUMBER_OF_ARGUMENTS,
         TYPE_MISMATCH,
         TYPE_MISMATCH,
         INVALID_RETURN_TYPE,
         INVALID_RETURN_TYPE,
+        NEW_FOR_NON_CLASS,
     };
     };
     
     
     
     
@@ -148,6 +149,7 @@ public:
     virtual std::string getMessage(void) const noexcept;
     virtual std::string getMessage(void) const noexcept;
 
 
     static SemanticError invalidReturnType(const std::string& should, const std::string& is, const CodePosition& where);
     static SemanticError invalidReturnType(const std::string& should, const std::string& is, const CodePosition& where);
+    static SemanticError newForNonClass(const std::string& type, const CodePosition& where);
 };
 };
 
 
 
 

+ 2 - 4
src/ast/Ast.cpp

@@ -6,11 +6,9 @@
 
 
 using namespace qlow::ast;
 using namespace qlow::ast;
 
 
-void Ast::merge(Ast&& other)
+void Ast::merge(Ast other)
 {
 {
-    objects.insert(objects.end(),
-                   std::make_move_iterator(other.objects.begin()),
-                   std::make_move_iterator(other.objects.end()));
+    std::move(other.objects.begin(), other.objects.end(), std::back_inserter(this->objects));
 }
 }
 
 
 
 

+ 21 - 3
src/ast/Ast.h

@@ -44,6 +44,8 @@ namespace qlow
         // base class
         // base class
         struct AstObject;
         struct AstObject;
 
 
+        struct ImportDeclaration;
+
         struct Class;
         struct Class;
 
 
         struct Type;
         struct Type;
@@ -104,7 +106,7 @@ public:
     inline const OwningList<AstObject>& getObjects(void) const  { return objects; }
     inline const OwningList<AstObject>& getObjects(void) const  { return objects; }
     inline       OwningList<AstObject>& getObjects(void)        { return objects; }
     inline       OwningList<AstObject>& getObjects(void)        { return objects; }
 
 
-    void merge(Ast&& other);
+    void merge(Ast other);
 };
 };
 
 
 
 
@@ -120,14 +122,30 @@ struct qlow::ast::AstObject :
 };
 };
 
 
 
 
+struct qlow::ast::ImportDeclaration
+{
+    CodePosition pos;
+    std::string imported;
+    
+    inline ImportDeclaration(std::string imported, const CodePosition& cp) :
+        pos{ cp },
+        imported{ std::move(imported) }
+    {
+    }
+};
+
+
 struct qlow::ast::Class : public AstObject
 struct qlow::ast::Class : public AstObject
 {
 {
     std::string name;
     std::string name;
     OwningList<FeatureDeclaration> features;
     OwningList<FeatureDeclaration> features;
+
+    /// true if it is a class, false if struct
+    bool isReferenceType;
     
     
-    inline Class(const std::string& name, OwningList<FeatureDeclaration>& features, const CodePosition& cp) :
+    inline Class(std::string name, OwningList<FeatureDeclaration>& features, bool isReferenceType, const CodePosition& cp) :
         AstObject{ cp },
         AstObject{ cp },
-        name{ name }, features(std::move(features))
+        name{ std::move(name) }, features(std::move(features)), isReferenceType{ isReferenceType }
     {
     {
     }
     }
 
 

+ 7 - 2
src/ast/AstVisitor.cpp

@@ -415,8 +415,13 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::BinaryOperatio
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewExpression& ast, sem::Scope& scope)
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewExpression& ast, sem::Scope& scope)
 {
 {
     auto ret = std::make_unique<sem::NewExpression>(scope.getContext(), scope.getType(ast.type.get()));
     auto ret = std::make_unique<sem::NewExpression>(scope.getContext(), scope.getType(ast.type.get()));
-    return ret;
-    //return nullptr;
+    auto* classType = scope.getContext().getType(ret->type).getClass();
+    if (classType != nullptr && classType->isReferenceType) {
+        return ret;
+    }
+    else {
+        throw SemanticError::newForNonClass(scope.getContext().getType(ret->type).asString(), ast.pos);
+    }
 }
 }
 
 
 
 

+ 7 - 0
src/ast/Parser.cpp

@@ -25,3 +25,10 @@ qlow::ast::Ast Parser::parse(void)
 
 
     return result;
     return result;
 }
 }
+
+
+void Parser::addImports(std::vector<std::unique_ptr<ImportDeclaration>> toAdd)
+{
+    std::move(toAdd.begin(), toAdd.end(), std::back_inserter(this->imports));
+
+}

+ 3 - 0
src/ast/Parser.h

@@ -17,12 +17,15 @@ class qlow::ast::Parser
 {
 {
     FILE* stream;
     FILE* stream;
     std::string filename;
     std::string filename;
+    std::vector<std::unique_ptr<ImportDeclaration>> imports;
 public:
 public:
     inline Parser(FILE* stream, std::string filename) :
     inline Parser(FILE* stream, std::string filename) :
         stream{ stream }, filename{ std::move(filename) } {}
         stream{ stream }, filename{ std::move(filename) } {}
     
     
     Ast parse(void);
     Ast parse(void);
 
 
+    void addImports(std::vector<std::unique_ptr<ImportDeclaration>> toAdd);
+
     inline const std::string& getFilename(void) const { return filename; }
     inline const std::string& getFilename(void) const { return filename; }
 };
 };
 
 

+ 1 - 0
src/ast/lexer.l

@@ -103,6 +103,7 @@ UTF8CHAR [\x00-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xe
 "return"                return SET_TOKEN(RETURN);
 "return"                return SET_TOKEN(RETURN);
 "new"                   return SET_TOKEN(NEW);
 "new"                   return SET_TOKEN(NEW);
 "extern"                return SET_TOKEN(EXTERN);
 "extern"                return SET_TOKEN(EXTERN);
+"import"                return SET_TOKEN(IMPORT);
 
 
 ":"                     return SET_TOKEN(COLON);
 ":"                     return SET_TOKEN(COLON);
 ";"                     return SET_TOKEN(SEMICOLON);
 ";"                     return SET_TOKEN(SEMICOLON);

+ 39 - 4
src/ast/syntax.y

@@ -91,7 +91,7 @@ while (0)
 %lex-param   { yyscan_t scanner }
 %lex-param   { yyscan_t scanner }
 %parse-param { yyscan_t scanner }
 %parse-param { yyscan_t scanner }
 %parse-param { qlow::ast::Ast& ast }
 %parse-param { qlow::ast::Ast& ast }
-%parse-param { const qlow::ast::Parser& parser }
+%parse-param { qlow::ast::Parser& parser }
 
 
 
 
 %define api.prefix {qlow_parser_}
 %define api.prefix {qlow_parser_}
@@ -149,6 +149,9 @@ while (0)
     qlow::ast::NewArrayExpression* newArrayExpression;
     qlow::ast::NewArrayExpression* newArrayExpression;
     qlow::ast::CastExpression* castExpression;
     qlow::ast::CastExpression* castExpression;
 
 
+    qlow::ast::ImportDeclaration* importDeclaration;
+    std::vector<std::unique_ptr<qlow::ast::ImportDeclaration>>* importList;
+
     const char* cString;
     const char* cString;
     std::string* string;
     std::string* string;
     int token;
     int token;
@@ -159,12 +162,15 @@ while (0)
 %token <string> INT_LITERAL
 %token <string> INT_LITERAL
 %token <string> ASTERISK SLASH PLUS MINUS EQUALS NOT_EQUALS AND OR XOR CUSTOM_OPERATOR
 %token <string> ASTERISK SLASH PLUS MINUS EQUALS NOT_EQUALS AND OR XOR CUSTOM_OPERATOR
 %token <token> TRUE FALSE
 %token <token> TRUE FALSE
-%token <token> CLASS STRUCT DO END IF ELSE WHILE RETURN NEW EXTERN AS
+%token <token> CLASS STRUCT DO END IF ELSE WHILE RETURN NEW AS
+%token <token> EXTERN IMPORT
 %token <token> NEW_LINE
 %token <token> NEW_LINE
 %token <token> SEMICOLON COLON COMMA DOT ASSIGN AMPERSAND
 %token <token> SEMICOLON COLON COMMA DOT ASSIGN AMPERSAND
 %token <token> ROUND_LEFT ROUND_RIGHT SQUARE_LEFT SQUARE_RIGHT
 %token <token> ROUND_LEFT ROUND_RIGHT SQUARE_LEFT SQUARE_RIGHT
 %token <string> UNEXPECTED_SYMBOL
 %token <string> UNEXPECTED_SYMBOL
 
 
+%type <importDeclaration> importDeclaration
+%type <importList> importList
 %type <topLevel> topLevel
 %type <topLevel> topLevel
 %type <classDefinition> classDefinition
 %type <classDefinition> classDefinition
 %type <type> type
 %type <type> type
@@ -216,7 +222,9 @@ while (0)
 
 
 /* list of class definitions */
 /* list of class definitions */
 topLevel:
 topLevel:
-    /* empty */ {
+    importList {
+       parser.addImports(std::move(*$1));
+       delete $1; $1 = nullptr;
        $$ = &ast;
        $$ = &ast;
     }
     }
     |
     |
@@ -254,10 +262,31 @@ topLevel:
         $3 = nullptr;
         $3 = nullptr;
     };
     };
 
 
+importList:
+    /* empty */ {
+        $$ = new std::vector<std::unique_ptr<qlow::ast::ImportDeclaration>>();
+    }
+    |
+    importList importDeclaration {
+        $$ = $1;
+        $$->emplace_back($2);
+        $2 = nullptr;
+    };
+
+importDeclaration:
+    IMPORT IDENTIFIER {
+        $$ = new qlow::ast::ImportDeclaration(std::move(*$2), @2);
+        delete $2; $2 = nullptr;
+    };
 
 
 classDefinition:
 classDefinition:
     CLASS IDENTIFIER featureList END {
     CLASS IDENTIFIER featureList END {
-        $$ = new Class(*$2, *$3, @$);
+        $$ = new Class(std::move(*$2), *$3, true, @$);
+        delete $2; delete $3; $2 = 0; $3 = 0;
+    }
+    |
+    STRUCT IDENTIFIER featureList END {
+        $$ = new Class(std::move(*$2), *$3, false, @$);
         delete $2; delete $3; $2 = 0; $3 = 0;
         delete $2; delete $3; $2 = 0; $3 = 0;
     }
     }
     |
     |
@@ -265,6 +294,12 @@ classDefinition:
         reportError(qlow::SyntaxError(@2));
         reportError(qlow::SyntaxError(@2));
         yyerrok;
         yyerrok;
         $$ = nullptr;
         $$ = nullptr;
+    }
+    |
+    STRUCT error END {
+        reportError(qlow::SyntaxError(@2));
+        yyerrok;
+        $$ = nullptr;
     };
     };
 
 
 
 

+ 7 - 5
src/sem/CodeGeneration.cpp

@@ -226,11 +226,13 @@ void generateObjectFile(const std::string& filename, std::unique_ptr<llvm::Modul
     if (broken)
     if (broken)
         throw "invalid llvm module";
         throw "invalid llvm module";
     
     
-    llvm::InitializeAllTargetInfos();
-    llvm::InitializeAllTargets();
-    llvm::InitializeAllTargetMCs();
-    llvm::InitializeAllAsmParsers();
-    llvm::InitializeAllAsmPrinters();
+    llvm::InitializeNativeTarget ();
+    llvm::InitializeNativeTargetAsmPrinter();
+    //llvm::InitializeAllTargetInfos();
+    //llvm::InitializeAllTargets();
+    //llvm::InitializeAllTargetMCs();
+    //llvm::InitializeAllAsmParsers();
+    //llvm::InitializeAllAsmPrinters();
 
 
     PassManager pm;
     PassManager pm;
     
     

+ 2 - 1
src/sem/Context.cpp

@@ -156,7 +156,8 @@ void Context::createLlvmTypes(llvm::LLVMContext& llvmCtxt)
             }
             }
 
 
             llvm::dyn_cast<llvm::StructType>(llvmType)->setBody(llvm::ArrayRef(structTypes));
             llvm::dyn_cast<llvm::StructType>(llvmType)->setBody(llvm::ArrayRef(structTypes));
-            llvmType = llvmType->getPointerTo();
+            if (type.getClass()->isReferenceType)
+                llvmType = llvmType->getPointerTo();
         }
         }
     }
     }
 }
 }

+ 4 - 0
src/sem/Semantic.h

@@ -74,6 +74,7 @@ struct qlow::sem::Class : public SemanticObject
 {
 {
     qlow::ast::Class* astNode;
     qlow::ast::Class* astNode;
     std::string name;
     std::string name;
+    bool isReferenceType;
     SymbolTable<Field> fields;
     SymbolTable<Field> fields;
     SymbolTable<Method> methods;
     SymbolTable<Method> methods;
     ClassScope scope;
     ClassScope scope;
@@ -87,6 +88,7 @@ struct qlow::sem::Class : public SemanticObject
         SemanticObject{ globalScope.getContext() },
         SemanticObject{ globalScope.getContext() },
         astNode{ astNode },
         astNode{ astNode },
         name{ astNode->name },
         name{ astNode->name },
+        isReferenceType{ astNode->isReferenceType },
         scope{ globalScope, this },
         scope{ globalScope, this },
         classType{ globalScope.getContext().createClassType(this) },
         classType{ globalScope.getContext().createClassType(this) },
         llvmType{ nullptr }
         llvmType{ nullptr }
@@ -103,6 +105,8 @@ struct qlow::sem::Class : public SemanticObject
     {
     {
     }
     }
 
 
+    
+
     virtual std::string toString(void) const override;
     virtual std::string toString(void) const override;
 };
 };
 
 

+ 0 - 1
src/sem/Type.cpp

@@ -129,7 +129,6 @@ size_t Type::hash(void) const
         type
         type
     );
     );
     auto h = type.index() * 2542345234523 + value1;
     auto h = type.index() * 2542345234523 + value1;
-    Printer::getInstance() << h << std::endl;
     return h;
     return h;
 }
 }
 
 

+ 1 - 1
src/tests/structs.qlw

@@ -1,4 +1,4 @@
-
+import std
 
 
 class Vec
 class Vec
     x: Integer
     x: Integer

+ 48 - 0
tests/runTests.py

@@ -0,0 +1,48 @@
+#!/usr/bin/python
+
+import sys
+import os
+import subprocess
+import difflib
+
+
+if len(sys.argv) <= 1:
+    print("please specify the qlow executable as a command line argument")
+    exit()
+
+qlow_executable = sys.argv[1]
+
+succeeded = 0
+failed = 0
+
+def test_file(path):
+    test = [qlow_executable, path, "-o", path + ".o"]
+    print("running test " + " ".join(test))
+    output = subprocess.run(test, stdout=subprocess.PIPE)
+    with open(path + ".c.did", "w") as out:
+        out.write(output.stdout.decode("utf-8"))
+    
+    with open(path + ".c.did", "r") as did, open(path + ".c.should", "r") as should:
+        if did.readlines() == should.readlines():
+            global succeeded
+            succeeded += 1
+        else:
+            global failed
+            failed += 1
+
+
+
+def run_directory(dir):
+    for root, dirs, files in os.walk(dir):
+        for filename in files:
+            if filename.endswith(".qlw"):
+                test_file(os.path.join(root, filename))
+
+def print_results():
+    print("%d out of %d tests succeeded: %d%%" % (succeeded, succeeded + failed, 100 * succeeded / (succeeded + failed)))
+
+run_directory(".")
+
+print_results()
+
+

+ 15 - 0
tests/syntax/class.qlw

@@ -0,0 +1,15 @@
+class A
+    field: Integer
+    field2: B
+end
+
+class B
+    field: A
+end
+
+
+main do
+    a: A
+    a := new A
+end
+

+ 0 - 0
tests/syntax/class.qlw.c.should


+ 1 - 1
vim/syntax/qlow.vim

@@ -12,7 +12,7 @@ endif
 syntax match commenty "//.*"
 syntax match commenty "//.*"
 syntax region multicommenty start="/\*"  end="\*/" contains=multicommenty
 syntax region multicommenty start="/\*"  end="\*/" contains=multicommenty
 
 
-syn keyword keywordy class struct do end if while return extern as new
+syn keyword keywordy class struct do end if while return extern as new import
 syn keyword typey Integer Boolean Abool
 syn keyword typey Integer Boolean Abool
 syn keyword typey String Char 
 syn keyword typey String Char 
 syn keyword typey Float32 Float64
 syn keyword typey Float32 Float64