浏览代码

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)
 
 if( NOT LLVM_FOUND )
   message(FATAL_ERROR "LLVM package can't be found. Set CMAKE_PREFIX_PATH variable to LLVM's installation prefix.")
 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)
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 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} )
@@ -55,7 +60,12 @@ endif()
 
 #explicit_llvm_config(${PROJECT_NAME} STATIC_LIBRARY)
 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
 #    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)
 {
     using llvm::Value;
-    
+
     sem::Context& semCtxt = nexpr.context;
     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::raw_os_ostream os(Printer::getInstance());
-    type->print(os);
-    os << "\n";
-    os.flush();
 
     int structIndex = access.accessed->llvmStructIndex;
     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())
         return errors.at(errorCode);
     else {
-        static std::string msg = "error message not found"s;
+        static std::string msg = ""s;
         return msg;
     }
 }
@@ -223,7 +223,7 @@ std::string SemanticError::getMessage(void) const noexcept
     if (errors.find(errorCode) != errors.end())
         return errors.at(errorCode);
     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 };
 }
 
+
+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,
         TYPE_MISMATCH,
         INVALID_RETURN_TYPE,
+        NEW_FOR_NON_CLASS,
     };
     
     
@@ -148,6 +149,7 @@ public:
     virtual std::string getMessage(void) const noexcept;
 
     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;
 
-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
         struct AstObject;
 
+        struct ImportDeclaration;
+
         struct Class;
 
         struct Type;
@@ -104,7 +106,7 @@ public:
     inline const OwningList<AstObject>& getObjects(void) const  { 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
 {
     std::string name;
     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 },
-        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)
 {
     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;
 }
+
+
+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;
     std::string filename;
+    std::vector<std::unique_ptr<ImportDeclaration>> imports;
 public:
     inline Parser(FILE* stream, std::string filename) :
         stream{ stream }, filename{ std::move(filename) } {}
     
     Ast parse(void);
 
+    void addImports(std::vector<std::unique_ptr<ImportDeclaration>> toAdd);
+
     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);
 "new"                   return SET_TOKEN(NEW);
 "extern"                return SET_TOKEN(EXTERN);
+"import"                return SET_TOKEN(IMPORT);
 
 ":"                     return SET_TOKEN(COLON);
 ";"                     return SET_TOKEN(SEMICOLON);

+ 39 - 4
src/ast/syntax.y

@@ -91,7 +91,7 @@ while (0)
 %lex-param   { yyscan_t scanner }
 %parse-param { yyscan_t scanner }
 %parse-param { qlow::ast::Ast& ast }
-%parse-param { const qlow::ast::Parser& parser }
+%parse-param { qlow::ast::Parser& parser }
 
 
 %define api.prefix {qlow_parser_}
@@ -149,6 +149,9 @@ while (0)
     qlow::ast::NewArrayExpression* newArrayExpression;
     qlow::ast::CastExpression* castExpression;
 
+    qlow::ast::ImportDeclaration* importDeclaration;
+    std::vector<std::unique_ptr<qlow::ast::ImportDeclaration>>* importList;
+
     const char* cString;
     std::string* string;
     int token;
@@ -159,12 +162,15 @@ while (0)
 %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 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> SEMICOLON COLON COMMA DOT ASSIGN AMPERSAND
 %token <token> ROUND_LEFT ROUND_RIGHT SQUARE_LEFT SQUARE_RIGHT
 %token <string> UNEXPECTED_SYMBOL
 
+%type <importDeclaration> importDeclaration
+%type <importList> importList
 %type <topLevel> topLevel
 %type <classDefinition> classDefinition
 %type <type> type
@@ -216,7 +222,9 @@ while (0)
 
 /* list of class definitions */
 topLevel:
-    /* empty */ {
+    importList {
+       parser.addImports(std::move(*$1));
+       delete $1; $1 = nullptr;
        $$ = &ast;
     }
     |
@@ -254,10 +262,31 @@ topLevel:
         $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:
     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;
     }
     |
@@ -265,6 +294,12 @@ classDefinition:
         reportError(qlow::SyntaxError(@2));
         yyerrok;
         $$ = 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)
         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;
     

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

+ 0 - 1
src/sem/Type.cpp

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

+ 1 - 1
src/tests/structs.qlw

@@ -1,4 +1,4 @@
-
+import std
 
 class Vec
     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 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 String Char 
 syn keyword typey Float32 Float64