Преглед изворни кода

now supports free standing functions

QlowB пре 6 година
родитељ
комит
1a6e8caaa8
10 измењених фајлова са 120 додато и 41 уклоњено
  1. 60 30
      src/CodeGeneration.cpp
  2. 2 1
      src/CodeGeneration.h
  3. 2 1
      src/Driver.cpp
  4. 12 3
      src/ErrorReporting.cpp
  5. 5 0
      src/Logging.h
  6. 1 0
      src/Scope.cpp
  7. 8 1
      src/Semantic.cpp
  8. 7 2
      src/Semantic.h
  9. 11 2
      src/parser.y
  10. 12 1
      src/test.qlw

+ 60 - 30
src/CodeGeneration.cpp

@@ -23,7 +23,7 @@ namespace qlow
 namespace gen
 {
 
-std::unique_ptr<llvm::Module> generateModule(const sem::SymbolTable<sem::Class>& classes)
+std::unique_ptr<llvm::Module> generateModule(const sem::GlobalScope& objects)
 {
     using llvm::Module;
     using llvm::Function;
@@ -34,6 +34,8 @@ std::unique_ptr<llvm::Module> generateModule(const sem::SymbolTable<sem::Class>&
     using llvm::Value;
     using llvm::IRBuilder;
     
+    Logger& logger = Logger::getInstance();
+    
 #ifdef DEBUGGING
         printf("creating llvm module\n"); 
 #endif 
@@ -42,7 +44,7 @@ std::unique_ptr<llvm::Module> generateModule(const sem::SymbolTable<sem::Class>&
 
     // create llvm structs
     // TODO implement detection of circles
-    for (auto& [name, cl] : classes){
+    for (auto& [name, cl] : objects.classes){
         llvm::StructType* st;
         std::vector<llvm::Type*> fields;
 #ifdef DEBUGGING
@@ -57,37 +59,20 @@ std::unique_ptr<llvm::Module> generateModule(const sem::SymbolTable<sem::Class>&
         cl->llvmType = st;
     }
     
+    std::vector<llvm::Function*> functions;
+    
     // create all llvm functions
-    for (auto& [name, cl] : classes) {
+    for (auto& [name, cl] : objects.classes) {
         for (auto& [name, method] : cl->methods) {
-            std::vector<Type*> argumentTypes;
-            Type* returnType = method->returnType.getLlvmType(context);
-            for (auto& arg : method->arguments) {
-                Type* argumentType = arg->type.getLlvmType(context);
-                argumentTypes.push_back(argumentType);
-            }
-            
-            FunctionType* funcType = FunctionType::get(
-                returnType, argumentTypes, false);
-#ifdef DEBUGGING
-            printf("looking up llvm type of %s\n", name.c_str());
-#endif 
-            if (returnType == nullptr)
-                throw "invalid return type";
-            Function* func = Function::Create(funcType, Function::ExternalLinkage, method->name, module.get());
-            method->llvmNode = func;
-            size_t index = 0;
-            for (auto& arg : func->args()) {
-                method->arguments[index]->allocaInst = &arg;
-#ifdef DEBUGGING
-                printf("allocaInst of arg '%s': %p\n", method->arguments[index]->name.c_str(), method->arguments[index]->allocaInst);
-#endif 
-                index++;
-            }
+            functions.push_back(generateFunction(module.get(), method.get()));
         }
     }
+    
+    for (auto& [name, method] : objects.functions) {
+        functions.push_back(generateFunction(module.get(), method.get()));
+    }
 
-    for (auto& [name, cl] : classes){
+    for (auto& [name, cl] : objects.classes){
         for (auto& [name, method] : cl->methods) {
             FunctionGenerator fg(*method, module.get());
             Function* f = fg.generate();
@@ -97,10 +82,55 @@ std::unique_ptr<llvm::Module> generateModule(const sem::SymbolTable<sem::Class>&
 #endif
         }
     }
+    for (auto& [name, method] : objects.functions) {
+        FunctionGenerator fg(*method, module.get());
+        Function* f = fg.generate();
+        llvm::verifyFunction(*f, &llvm::errs());
+#ifdef DEBUGGING
+        printf("verified function: %s\n", method->name.c_str());
+#endif
+    }
     return module;
 }
 
 
+llvm::Function* generateFunction(llvm::Module* module, sem::Method* method)
+{
+    using llvm::Function;
+    using llvm::Argument;
+    using llvm::Type;
+    using llvm::FunctionType;
+    
+    std::vector<Type*> argumentTypes;
+    Type* returnType = method->returnType.getLlvmType(context);
+    for (auto& arg : method->arguments) {
+        Type* argumentType = arg->type.getLlvmType(context);
+        argumentTypes.push_back(argumentType);
+    }
+    
+    FunctionType* funcType = FunctionType::get(
+        returnType, argumentTypes, false);
+#ifdef DEBUGGING
+    printf("looking up llvm type of %s\n", method->name.c_str());
+#endif 
+    if (returnType == nullptr)
+        throw "invalid return type";
+    Function* func = Function::Create(funcType, Function::ExternalLinkage, method->name, module);
+    method->llvmNode = func;
+    size_t index = 0;
+    for (auto& arg : func->args()) {
+        method->arguments[index]->allocaInst = &arg;
+#ifdef DEBUGGING
+        printf("allocaInst of arg '%s': %p\n", method->arguments[index]->name.c_str(), method->arguments[index]->allocaInst);
+#endif 
+        index++;
+    }
+    
+    //printf("UEEEEEEEE %s\n", method->name.c_str());
+    return func;
+}
+
+
 void generateObjectFile(const std::string& filename, std::unique_ptr<llvm::Module> module)
 {
     using llvm::legacy::PassManager;
@@ -137,8 +167,8 @@ void generateObjectFile(const std::string& filename, std::unique_ptr<llvm::Modul
 
     TargetOptions targetOptions;
     auto relocModel = llvm::Optional<llvm::Reloc::Model>();
-    TargetMachine* targetMachine = target->createTargetMachine(targetTriple, cpu,
-            features, targetOptions, relocModel);
+    std::unique_ptr<TargetMachine> targetMachine(target->createTargetMachine(targetTriple, cpu,
+            features, targetOptions, relocModel));
 
     std::error_code errorCode;
     raw_fd_ostream dest(filename, errorCode, llvm::sys::fs::F_None);

+ 2 - 1
src/CodeGeneration.h

@@ -12,7 +12,8 @@ namespace qlow
 {
 namespace gen
 {
-    std::unique_ptr<llvm::Module> generateModule(const sem::SymbolTable<sem::Class>& classes);
+    std::unique_ptr<llvm::Module> generateModule(const sem::GlobalScope& objects);
+    llvm::Function* generateFunction (llvm::Module* module, sem::Method* method);
     void generateObjectFile(const std::string& name, std::unique_ptr<llvm::Module> module);
 
     class FunctionGenerator;

+ 2 - 1
src/Driver.cpp

@@ -112,6 +112,7 @@ int Driver::run(void)
     else {
         mainClass = main->second.get();
     }
+    
     auto mainmain = mainClass->methods.find("main");
     qlow::sem::Method* mainMethod = nullptr;
     if (mainmain == mainClass->methods.end()) {
@@ -126,7 +127,7 @@ int Driver::run(void)
     std::unique_ptr<llvm::Module> mod = nullptr;
     
     try {
-        mod = qlow::gen::generateModule(semClasses->classes);
+        mod = qlow::gen::generateModule(*semClasses);
     }
     catch (const char* err) {
         logger.logError(err);

+ 12 - 3
src/ErrorReporting.cpp

@@ -1,5 +1,6 @@
 #include "ErrorReporting.h"
 
+#include <map>
 #include <fstream>
 
 using qlow::CompileError;
@@ -15,8 +16,8 @@ CompileError::~CompileError(void)
 void CompileError::underlineError(Logger& logger) const
 {
     // TODO implement for multiline errors
-    if (where.first_line != where.last_line)
-        throw "TODO";
+    //if (where.first_line != where.last_line)
+    //    throw "TODO";
     std::ifstream file(where.filename);
     
     if (!file)
@@ -52,7 +53,15 @@ void SyntaxError::print(Logger& logger) const
 
 void SemanticError::print(Logger& logger) const
 {
-    logger.logError(message, where);
+    static std::map<ErrorCode, std::string> error = {
+        {UNKNOWN_TYPE, "unknown type"},
+        {FEATURE_NOT_FOUND, "method or variable not found"},
+        {DUPLICATE_CLASS_DEFINITION, "duplicate class definition"},
+        {DUPLICATE_FIELD_DECLARATION, "duplicate field declaration"},
+        {DUPLICATE_METHOD_DEFINITION, "duplicate method definition"},
+    };
+    std::string& errMsg = error[errorCode];
+    logger.logError(errMsg + (errMsg != "" ?  ": " : "") + message, where);
     underlineError(logger);
 }
 

+ 5 - 0
src/Logging.h

@@ -58,7 +58,12 @@ private:
 
     // type of current logging
     LogLevel logType = LogLevel::OFF;
+    
+#ifdef DEBUGGING
+    LogLevel logLevel = LogLevel::DEBUG;
+#else
     LogLevel logLevel = LogLevel::INFO;
+#endif
 
     static Logger instance;
 

+ 1 - 0
src/Scope.cpp

@@ -61,6 +61,7 @@ std::optional<sem::Type> sem::NativeScope::getType(const std::string& name)
     auto t = types.find(name);
     if (t != types.end())
         return *t->second;
+    
     return std::nullopt;
 }
 

+ 8 - 1
src/Semantic.cpp

@@ -20,7 +20,7 @@ std::unique_ptr<GlobalScope>
     Logger& logger = Logger::getInstance();
 
 #ifdef DEBUGGING
-    printf("starting building semantic representation\n");
+    printf("starting building semantic representation (%d objects)\n", objects.size());
 #endif
 
     // create classes
@@ -73,6 +73,9 @@ std::unique_ptr<GlobalScope>
         else {
             SemanticError se(SemanticError::UNKNOWN_TYPE, method->astNode->type, method->astNode->pos);
         }
+        
+        // otherwise add to the methods list
+        globalScope->functions[method->name] = unique_dynamic_cast<Method>(method->astNode->accept(av, *globalScope));
     }
     
 #ifdef DEBUGGING
@@ -84,6 +87,10 @@ std::unique_ptr<GlobalScope>
             method->body = unique_dynamic_cast<sem::DoEndBlock>(av.visit(*method->astNode->body, method->scope));
         }
     }
+    for (auto& [name, method] : globalScope->functions) {
+        method->body = unique_dynamic_cast<sem::DoEndBlock>(av.visit(*method->astNode->body, method->scope));
+    }
+    
 #ifdef DEBUGGING
     printf("created all method bodies\n");
 #endif

+ 7 - 2
src/Semantic.h

@@ -141,10 +141,15 @@ struct qlow::sem::Method : public SemanticObject
     llvm::Function* llvmNode;
 
     inline Method(Scope& parentScope, const Type& returnType) :
-        returnType{ returnType }, scope{ parentScope } {}
+        returnType{ returnType },
+        scope{ parentScope }
+    {
+    }
     
     inline Method(ast::MethodDefinition* astNode, Scope& parentScope) :
-        astNode{ astNode }, scope{ parentScope }
+        astNode{ astNode },
+        name{ astNode->name },
+        scope{ parentScope }
     {
     }
     

+ 11 - 2
src/parser.y

@@ -105,6 +105,7 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
     qlow::ast::Expression* expression;
     qlow::ast::Operation::Operator op;
 
+    qlow::ast::FieldDeclaration* fieldDeclaration;
     qlow::ast::MethodDefinition* methodDefinition;
 
     qlow::ast::FeatureCall* featureCall;
@@ -132,7 +133,9 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 
 %type <topLevel> topLevel 
 %type <classDefinition> classDefinition
-%type <featureDeclaration> featureDeclaration fieldDeclaration methodDefinition
+%type <featureDeclaration> featureDeclaration
+%type <fieldDeclaration> fieldDeclaration
+%type <methodDefinition> methodDefinition
 %type <featureList> featureList
 %type <argumentList> argumentList
 %type <statements> statements
@@ -176,7 +179,13 @@ topLevel:
     topLevel classDefinition {
         parsedClasses->push_back(std::move(std::unique_ptr<qlow::ast::Class>($2)));
         $2 = nullptr;
+    }
+    |
+    topLevel methodDefinition {
+        parsedClasses->push_back(std::move(std::unique_ptr<qlow::ast::MethodDefinition>($2)));
+        $2 = nullptr;
     };
+    
 
 
 classDefinition:
@@ -267,7 +276,7 @@ ifElseBlock:
     IF expression doEndBlock {
         $$ = new IfElseBlock(std::unique_ptr<Expression>($2),
                              std::unique_ptr<DoEndBlock>($3),
-                             std::unique_ptr<DoEndBlock>(nullptr), @$);
+                             std::make_unique<DoEndBlock>(qlow::OwningList<qlow::ast::Statement>{}, @3), @$);
         $2 = nullptr; $3 = nullptr;
     }
     |

+ 12 - 1
src/test.qlw

@@ -1,5 +1,4 @@
 
-
 class Main
     hoi: Fudi 
     fop: FF do
@@ -28,6 +27,18 @@ class Main
     end
 end
 
+fibonacci(i: Integer): Integer do
+    if i == 0 do
+        return 0
+    else
+    end
+    if i == 1 do
+        return 1
+    else
+    end
+    return fibonacci(i - 1) + fibonacci(i - 2)
+end
+
 
 class FF
     field1: Integer