From ceab70ed845b6ea73d6600aa5df1b7812dd5848f Mon Sep 17 00:00:00 2001 From: Ludwig Lehnert Date: Tue, 24 Dec 2024 17:46:47 +0100 Subject: [PATCH] further progress --- compiler/.vscode/settings.json | 1 + compiler/CMakeLists.txt | 4 +- compiler/include/AST/AST.h | 1 + compiler/include/AST/Base.h | 5 + compiler/include/AST/BaseASTVisitor.h | 19 + compiler/include/AST/Stmt/AssignStmt.h | 2 + compiler/include/AST/Stmt/Block.h | 7 + compiler/include/AST/Stmt/ExprStmt.h | 2 + compiler/include/AST/Stmt/FnDecl.h | 4 + compiler/include/AST/Stmt/IfStmt.h | 5 + compiler/include/AST/Stmt/InlineAsm.h | 46 ++ compiler/include/AST/Stmt/RetStmt.h | 2 + compiler/include/AST/Stmt/VarDecl.h | 2 + compiler/include/AST/Stmt/WhileStmt.h | 4 + compiler/include/Compile.h | 10 + compiler/plsm.g4 | 83 ++- compiler/src/AST/Stmt/InlineAsm.cpp | 45 ++ compiler/src/Visitors/Compiler.cpp | 567 ++++++++++++++++++ .../{Anlaysis => Visitors}/NameAnalysis.cpp | 16 +- .../{Anlaysis => Visitors}/TypeAnalysis.cpp | 197 +++++- compiler/src/main.cpp | 8 +- examples/new | Bin 0 -> 16488 bytes examples/new.plsm | 30 +- 23 files changed, 1019 insertions(+), 41 deletions(-) create mode 100644 compiler/include/AST/Stmt/InlineAsm.h create mode 100644 compiler/include/Compile.h create mode 100644 compiler/src/AST/Stmt/InlineAsm.cpp create mode 100644 compiler/src/Visitors/Compiler.cpp rename compiler/src/{Anlaysis => Visitors}/NameAnalysis.cpp (89%) rename compiler/src/{Anlaysis => Visitors}/TypeAnalysis.cpp (67%) create mode 100755 examples/new diff --git a/compiler/.vscode/settings.json b/compiler/.vscode/settings.json index 2930828..d211f7b 100644 --- a/compiler/.vscode/settings.json +++ b/compiler/.vscode/settings.json @@ -2,6 +2,7 @@ "C_Cpp.default.includePath": [ "${workspaceFolder}/include/", "${workspaceFolder}/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp/runtime/src", + "/usr/lib64/llvm18/include", ], "files.associations": { "*.embeddedhtml": "html", diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt index 4ee8249..8ed3d00 100644 --- a/compiler/CMakeLists.txt +++ b/compiler/CMakeLists.txt @@ -44,7 +44,9 @@ add_dependencies(plsm antlr4_static) target_include_directories(plsm PRIVATE ${CMAKE_SOURCE_DIR}/include) target_include_directories(plsm PRIVATE ${ANTLR4_INCLUDE_DIRS}) target_link_directories(plsm PRIVATE ${ANTLR4_OUTPUT_DIR}) -target_link_libraries(plsm PRIVATE antlr4-runtime Boost::json) +target_link_directories(plsm PRIVATE /usr/lib64/llvm18/lib) +target_include_directories(plsm PRIVATE /usr/lib64/llvm18/include) +target_link_libraries(plsm PRIVATE antlr4-runtime Boost::json LLVM-18) add_custom_target(clean-all COMMAND ${CMAKE_COMMAND} -E rm -rf diff --git a/compiler/include/AST/AST.h b/compiler/include/AST/AST.h index 5136e82..1964983 100644 --- a/compiler/include/AST/AST.h +++ b/compiler/include/AST/AST.h @@ -18,6 +18,7 @@ #include "Stmt/ExprStmt.h" #include "Stmt/FnDecl.h" #include "Stmt/IfStmt.h" +#include "Stmt/InlineAsm.h" #include "Stmt/RetStmt.h" #include "Stmt/VarDecl.h" #include "Stmt/WhileStmt.h" diff --git a/compiler/include/AST/Base.h b/compiler/include/AST/Base.h index ec403d8..f199353 100644 --- a/compiler/include/AST/Base.h +++ b/compiler/include/AST/Base.h @@ -65,6 +65,9 @@ public: virtual std::any visit(FnParam &fnParam, std::any param) = 0; virtual std::any visit(FnDecl &fnDecl, std::any param) = 0; virtual std::any visit(IfStmt &ifStmt, std::any param) = 0; + virtual std::any visit(InlineAsmConstraint &inlineAsmConstraint, + std::any param) = 0; + virtual std::any visit(InlineAsm &inlineAsm, std::any param) = 0; virtual std::any visit(RetStmt &retStmt, std::any param) = 0; virtual std::any visit(VarDecl &varDecl, std::any param) = 0; virtual std::any visit(WhileStmt &whileStmt, std::any param) = 0; @@ -227,6 +230,8 @@ public: static Stmt *fromJson(boost::json::value json); + virtual bool alywasReturns() const = 0; + virtual bool isStmt() const override { return true; } }; diff --git a/compiler/include/AST/BaseASTVisitor.h b/compiler/include/AST/BaseASTVisitor.h index e3f41e1..7597fc4 100644 --- a/compiler/include/AST/BaseASTVisitor.h +++ b/compiler/include/AST/BaseASTVisitor.h @@ -142,6 +142,25 @@ public: return std::any(); } + virtual std::any visit(InlineAsmConstraint &inlineAsmConstraint, + std::any param) override { + return std::any(); + } + + virtual std::any visit(InlineAsm &inlineAsm, std::any param) override { + for (auto &c : inlineAsm.outputs) { + if (c.get()) + c->accept(this, param); + } + + for (auto &c : inlineAsm.inputs) { + if (c.get()) + c->accept(this, param); + } + + return std::any(); + } + virtual std::any visit(RetStmt &retStmt, std::any param) override { if (retStmt.value.get()) retStmt.value->accept(this, param); diff --git a/compiler/include/AST/Stmt/AssignStmt.h b/compiler/include/AST/Stmt/AssignStmt.h index 937dc5e..ae8356e 100644 --- a/compiler/include/AST/Stmt/AssignStmt.h +++ b/compiler/include/AST/Stmt/AssignStmt.h @@ -17,6 +17,8 @@ public: virtual boost::json::value toJson() const override; static AssignStmt *fromJson(boost::json::value json); + virtual bool alywasReturns() const override { return false; } + virtual std::any accept(ASTVisitor *visitor, std::any param) override { return visitor->visit(*this, param); } diff --git a/compiler/include/AST/Stmt/Block.h b/compiler/include/AST/Stmt/Block.h index 7f96236..aa261d0 100644 --- a/compiler/include/AST/Stmt/Block.h +++ b/compiler/include/AST/Stmt/Block.h @@ -15,6 +15,13 @@ public: virtual boost::json::value toJson() const override; static Block *fromJson(boost::json::value json); + bool alywasReturns() const { + for (auto &stmt : stmts) + if (stmt.get() && stmt->alywasReturns()) + return true; + return false; + } + virtual std::any accept(ASTVisitor *visitor, std::any param) override { return visitor->visit(*this, param); } diff --git a/compiler/include/AST/Stmt/ExprStmt.h b/compiler/include/AST/Stmt/ExprStmt.h index c562f63..3854e84 100644 --- a/compiler/include/AST/Stmt/ExprStmt.h +++ b/compiler/include/AST/Stmt/ExprStmt.h @@ -15,6 +15,8 @@ public: virtual boost::json::value toJson() const override; static ExprStmt *fromJson(boost::json::value json); + virtual bool alywasReturns() const override { return false; } + virtual std::any accept(ASTVisitor *visitor, std::any param) override { return visitor->visit(*this, param); } diff --git a/compiler/include/AST/Stmt/FnDecl.h b/compiler/include/AST/Stmt/FnDecl.h index d187f5b..fee2d55 100644 --- a/compiler/include/AST/Stmt/FnDecl.h +++ b/compiler/include/AST/Stmt/FnDecl.h @@ -44,6 +44,10 @@ public: virtual boost::json::value toJson() const override; static FnDecl *fromJson(boost::json::value json); + virtual bool alywasReturns() const override { + throw std::runtime_error("should not call FnDecl::alywasReturns"); + } + virtual std::any accept(ASTVisitor *visitor, std::any param) override { return visitor->visit(*this, param); } diff --git a/compiler/include/AST/Stmt/IfStmt.h b/compiler/include/AST/Stmt/IfStmt.h index a5b62ea..73bea24 100644 --- a/compiler/include/AST/Stmt/IfStmt.h +++ b/compiler/include/AST/Stmt/IfStmt.h @@ -19,6 +19,11 @@ public: virtual boost::json::value toJson() const override; static IfStmt *fromJson(boost::json::value json); + virtual bool alywasReturns() const override { + return (ifBody.get() && ifBody->alywasReturns()) || + (elseBody.get() && elseBody->alywasReturns()); + } + virtual std::any accept(ASTVisitor *visitor, std::any param) override { return visitor->visit(*this, param); } diff --git a/compiler/include/AST/Stmt/InlineAsm.h b/compiler/include/AST/Stmt/InlineAsm.h new file mode 100644 index 0000000..ed77f39 --- /dev/null +++ b/compiler/include/AST/Stmt/InlineAsm.h @@ -0,0 +1,46 @@ +#include "AST/Base.h" + +namespace plsm { +namespace ast { + +class InlineAsmConstraint : public ASTNode { +public: + std::string constraint, variable; + + InlineAsmConstraint(LOC_ARG, std::string constraint, std::string variable) + : ASTNode(sourceRange), constraint(constraint), variable(variable) {} + + virtual boost::json::value toJson() const override; + static InlineAsmConstraint *fromJson(boost::json::value json); + + virtual std::any accept(ASTVisitor *visitor, std::any param) override { + return visitor->visit(*this, param); + } +}; + +class InlineAsm : public Stmt { +public: + std::string code; + std::vector> outputs; + std::vector> inputs; + std::vector clobbers; + + InlineAsm(LOC_ARG, std::string code, + std::vector> outputs, + std::vector> inputs, + std::vector clobbers) + : Stmt(sourceRange), code(code), outputs(std::move(outputs)), + inputs(std::move(inputs)), clobbers(clobbers) {} + + virtual boost::json::value toJson() const override; + static InlineAsm *fromJson(boost::json::value json); + + virtual bool alywasReturns() const override { return false; } + + virtual std::any accept(ASTVisitor *visitor, std::any param) override { + return visitor->visit(*this, param); + } +}; + +} // namespace ast +} // namespace plsm \ No newline at end of file diff --git a/compiler/include/AST/Stmt/RetStmt.h b/compiler/include/AST/Stmt/RetStmt.h index 4ef2ef1..f0cab32 100644 --- a/compiler/include/AST/Stmt/RetStmt.h +++ b/compiler/include/AST/Stmt/RetStmt.h @@ -15,6 +15,8 @@ public: virtual boost::json::value toJson() const override; static RetStmt *fromJson(boost::json::value json); + virtual bool alywasReturns() const override { return true; } + virtual std::any accept(ASTVisitor *visitor, std::any param) override { return visitor->visit(*this, param); } diff --git a/compiler/include/AST/Stmt/VarDecl.h b/compiler/include/AST/Stmt/VarDecl.h index 808edcb..d80326b 100644 --- a/compiler/include/AST/Stmt/VarDecl.h +++ b/compiler/include/AST/Stmt/VarDecl.h @@ -20,6 +20,8 @@ public: virtual boost::json::value toJson() const override; static VarDecl *fromJson(boost::json::value json); + virtual bool alywasReturns() const override { return false; } + virtual std::any accept(ASTVisitor *visitor, std::any param) override { return visitor->visit(*this, param); } diff --git a/compiler/include/AST/Stmt/WhileStmt.h b/compiler/include/AST/Stmt/WhileStmt.h index ba7d1d1..a00d2ba 100644 --- a/compiler/include/AST/Stmt/WhileStmt.h +++ b/compiler/include/AST/Stmt/WhileStmt.h @@ -18,6 +18,10 @@ public: virtual boost::json::value toJson() const override; static WhileStmt *fromJson(boost::json::value json); + virtual bool alywasReturns() const override { + return (body.get() && body->alywasReturns()); + } + virtual std::any accept(ASTVisitor *visitor, std::any param) override { return visitor->visit(*this, param); } diff --git a/compiler/include/Compile.h b/compiler/include/Compile.h new file mode 100644 index 0000000..f2ecd7a --- /dev/null +++ b/compiler/include/Compile.h @@ -0,0 +1,10 @@ +#pragma once + +#include "AST/AST.h" + +namespace plsm { + +void compileModule(std::unique_ptr &module, + const std::string &filename); + +} // namespace plsm diff --git a/compiler/plsm.g4 b/compiler/plsm.g4 index 4506511..a00741a 100644 --- a/compiler/plsm.g4 +++ b/compiler/plsm.g4 @@ -4,6 +4,7 @@ grammar plsm; #include "AST/AST.h" #include "Utils.h" #include +#include #include using namespace plsm::utils; @@ -95,8 +96,51 @@ stmt } | whileStmt { $ast = ptrcast($ctx->whileStmt()->ast); + } + | inlineAsm { + $ast = ptrcast($ctx->inlineAsm()->ast); }; +inlineAsm + returns[std::unique_ptr ast]: + 'inline' 'asm' '(' inlineAsmCode = string ( + ':' outputs += inlineAsmConstraint ( + ',' outputs += inlineAsmConstraint + )* + )? ( + ':' inputs += inlineAsmConstraint ( + ',' inputs += inlineAsmConstraint + )* + )? (':' clobbers += string ( ',' clobbers += string)*)? ')' ';' { + auto code = $ctx->inlineAsmCode->value; + + std::vector> outputs; + for (auto &output : $ctx->outputs) { + outputs.push_back(std::move(output->ast)); + } + + std::vector> inputs; + for (auto &input : $ctx->inputs) { + inputs.push_back(std::move(input->ast)); + } + + std::vector clobbers; + for (auto &clobber : $ctx->clobbers) { + clobbers.push_back(clobber->value); + } + + $ast = std::make_unique( + getSourceRange($ctx), code, std::move(outputs), std::move(inputs), clobbers); + }; + +inlineAsmConstraint + returns[std::unique_ptr ast]: + string '(' IDENTIFIER ')' { + auto constraint = $ctx->string()->value; + auto variable = $ctx->IDENTIFIER()->getText(); + $ast = std::make_unique(getSourceRange($ctx), constraint, variable); + }; + whileStmt returns[std::unique_ptr ast]: 'while' '(' condition = expr ')' ( @@ -168,7 +212,7 @@ fnDecl fnParam returns[std::unique_ptr ast]: - IDENTIFIER typeName { + IDENTIFIER ':' typeName { $ast = std::make_unique(getSourceRange($ctx), $ctx->IDENTIFIER()->getText(), std::move($ctx->typeName()->ast)); }; @@ -216,10 +260,6 @@ binaryExpr auto binExpr = std::make_unique(getSourceRange($ctx), op, std::move($ctx->lhs->ast), std::move($ctx->rhs->ast)); $ast = ptrcast(binExpr); - } - | operand = binaryExpr 'as' typeName { - auto castExpr = std::make_unique(getSourceRange($ctx), std::move($ctx->operand->ast), std::move($ctx->typeName()->ast)); - $ast = ptrcast(castExpr); } | lhs = binaryExpr op = ( '==' @@ -258,6 +298,10 @@ unaryExpr } | functionCall { $ast = ptrcast($ctx->functionCall()->ast); + } + | unaryExpr 'as' typeName { + auto castExpr = std::make_unique(getSourceRange($ctx), std::move($ctx->unaryExpr()->ast), std::move($ctx->typeName()->ast)); + $ast = ptrcast(castExpr); } | '!' unaryExpr { auto unExpr = std::make_unique(getSourceRange($ctx), UnOp::NOT, std::move($ctx->unaryExpr()->ast)); @@ -314,6 +358,9 @@ factorExpr auto text = $ctx->BOOL()->getText(); auto val = std::make_unique(getSourceRange($ctx), text == "true" ? 1 : 0); $ast = ptrcast(val); + } + | lambdaExpr { + $ast = ptrcast($ctx->lambdaExpr()->ast); } | '(' expr ')' { $ast = std::move($ctx->expr()->ast); @@ -330,6 +377,17 @@ functionCall $ast = std::make_unique(getSourceRange($ctx), std::move($ctx->callee->ast), std::move(args)); }; +lambdaExpr + returns[std::unique_ptr ast]: + '@' '(' (params += fnParam (',' params += fnParam)*)? ')' typeName '{' block '}' { + std::vector> params; + for (auto ¶m : $ctx->params) { + params.push_back(std::move(param->ast)); + } + + $ast = std::make_unique(getSourceRange($ctx), std::move(params), std::move($ctx->typeName()->ast), std::move($ctx->block()->ast)); + }; + typeName returns[std::unique_ptr ast]: IDENTIFIER { @@ -338,10 +396,23 @@ typeName $ast = ptrcast(named); }; +string + returns[std::string value]: + STRING { + auto encoded = $ctx->STRING()->getText(); + auto decoded = boost::json::parse(encoded); + $value = decoded.as_string(); + }; + +STRING: '"' (ESC | ~["\\\r\n])* '"'; +fragment ESC: '\\' (["\\/bfnrt] | 'u' HEX HEX HEX HEX); +fragment HEX: [0-9a-fA-F]; + INT: [0-9]+ | '0x' [0-9a-fA-F]+ | '0o' [0-7]+ | '0b' [01]+; FLOAT: [0-9]+ '.' | [0-9]* '.' [0-9]+; BOOL: 'true' | 'false'; IDENTIFIER: [a-zA-Z_] [a-zA-Z0-9_]*; -WHITESPACE: [ \r\n\t]+ -> skip; \ No newline at end of file +WHITESPACE: [ \r\n\t]+ -> skip; +COMMENT: (('//' ~( '\r' | '\n')*) | ('/*' .*? '*/')) -> skip; \ No newline at end of file diff --git a/compiler/src/AST/Stmt/InlineAsm.cpp b/compiler/src/AST/Stmt/InlineAsm.cpp new file mode 100644 index 0000000..0a430e2 --- /dev/null +++ b/compiler/src/AST/Stmt/InlineAsm.cpp @@ -0,0 +1,45 @@ +#include "AST/AST.h" +#include "Utils.h" + +namespace plsm { +namespace ast { + +boost::json::value InlineAsmConstraint::toJson() const { + return { + {"@type", "InlineAsmConstraint"}, + {"constraint", constraint}, + {"variable", variable}, + }; +} + +InlineAsmConstraint *InlineAsmConstraint::fromJson(boost::json::value json) { + auto constraint = + getJsonValue(json, "constraint"); + auto variable = + getJsonValue(json, "variable"); + return new InlineAsmConstraint(SourceRange::json(), constraint, variable); +} + +boost::json::value InlineAsm::toJson() const { + return { + {"@type", "InlineAsm"}, + {"code", code}, + {"outputs", utils::mapToJson(outputs)}, + {"inputs", utils::mapToJson(inputs)}, + {"clobbers", clobbers}, + }; +} + +InlineAsm *InlineAsm::fromJson(boost::json::value json) { + auto name = getJsonValue(json, "name"); + auto outputs = + fromJsonVector(json, "outputs"); + auto inputs = fromJsonVector(json, "inputs"); + auto clobbers = + getJsonValue>(json, "clobbers"); + return new InlineAsm(SourceRange::json(), name, std::move(outputs), + std::move(inputs), clobbers); +} + +} // namespace ast +} // namespace plsm diff --git a/compiler/src/Visitors/Compiler.cpp b/compiler/src/Visitors/Compiler.cpp new file mode 100644 index 0000000..5c4f400 --- /dev/null +++ b/compiler/src/Visitors/Compiler.cpp @@ -0,0 +1,567 @@ +#include "AST/BaseASTVisitor.h" +#include "Compile.h" +#include "Utils.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace plsm { +using namespace ast; + +namespace { + +static llvm::Type *getLLVMType(llvm::LLVMContext &ctx, + const std::shared_ptr &type) { + if (utils::is(type.get())) { + auto primitiveType = (PrimitiveType *)type.get(); + if (primitiveType->name == "i8" || primitiveType->name == "u8") + return llvm::Type::getInt8Ty(ctx); + if (primitiveType->name == "i16" || primitiveType->name == "u16") + return llvm::Type::getInt16Ty(ctx); + if (primitiveType->name == "i32" || primitiveType->name == "u32") + return llvm::Type::getInt32Ty(ctx); + if (primitiveType->name == "i64" || primitiveType->name == "u64") + return llvm::Type::getInt64Ty(ctx); + if (primitiveType->name == "i128" || primitiveType->name == "u128") + return llvm::Type::getInt128Ty(ctx); + if (primitiveType->name == "float") + return llvm::Type::getFloatTy(ctx); + if (primitiveType->name == "double") + return llvm::Type::getDoubleTy(ctx); + } + + else if (utils::is(type.get())) { + auto functionType = (FunctionType *)type.get(); + auto returnType = getLLVMType(ctx, functionType->returnType); + + std::vector llvmParams; + llvmParams.push_back(llvm::IntegerType::get(ctx, 8)->getPointerTo()); + for (auto ¶mType : functionType->paramTypes) + llvmParams.push_back(getLLVMType(ctx, paramType)); + + return llvm::FunctionType::get(returnType, llvmParams, false); + } + + throw std::runtime_error("cannot determine llvm type"); + return nullptr; +} +class IRGenerator1 : public BaseASTVisitor { + llvm::LLVMContext &ctx; + llvm::Module &mod; + llvm::IRBuilder<> &builder; + + std::map &symbolMap; + std::set &functions; + +public: + IRGenerator1(llvm::LLVMContext &ctx, llvm::Module &mod, + llvm::IRBuilder<> &builder, + std::map &symbolMap, + std::set &functions) + : ctx(ctx), mod(mod), builder(builder), symbolMap(symbolMap), + functions(functions) {} + + virtual std::any visit(VarDecl &varDecl, std::any param) override { + auto llvmType = getLLVMType(ctx, varDecl.symbol->type); + + // auto global = new llvm::GlobalVariable(mod, llvmType, false, + // llvm::GlobalValue::ExternalLinkage, + // nullptr, varDecl.name); + auto global = mod.getOrInsertGlobal(varDecl.name, llvmType); + + symbolMap[varDecl.symbol.get()] = global; + + return std::any(); + } + + virtual std::any visit(FnDecl &fnDecl, std::any param) override { + auto functionType = + (llvm::FunctionType *)getLLVMType(ctx, fnDecl.symbol->type); + + mod.getOrInsertFunction(fnDecl.name, functionType); + auto function = mod.getFunction(fnDecl.name); + symbolMap[fnDecl.symbol.get()] = function; + functions.insert(function); + + return std::any(); + } +}; + +class IRGenerator2 : public BaseASTVisitor { + llvm::LLVMContext &ctx; + llvm::Module &mod; + llvm::IRBuilder<> &builder; + + std::map &symbolMap; + std::set &functions; + std::set lambdas; + + llvm::Value *retStore = nullptr; + llvm::BasicBlock *retBlock = nullptr; + + llvm::Value *rvalueForLValue = nullptr; + + size_t labelCounter = 0; + std::string createLabel() { return "L" + std::to_string(labelCounter++); } + + llvm::Value *wrapCallee(llvm::Value *callee) { + auto ptr = llvm::IntegerType::get(ctx, 8)->getPointerTo(); + auto structType = llvm::StructType::get(ptr, callee->getType()); + + auto store = builder.CreateAlloca(structType); + auto ep = builder.CreateStructGEP(structType, store, 0); + builder.CreateStore(llvm::ConstantPointerNull::get(ptr), ep); + ep = builder.CreateStructGEP(structType, store, 1); + builder.CreateStore(callee, ep); + + return store; + + // (f() -> asdf) -> { context, f() -> asdf } + } + +public: + IRGenerator2(llvm::LLVMContext &ctx, llvm::Module &mod, + llvm::IRBuilder<> &builder, + std::map &symbolMap, + std::set &functions) + : ctx(ctx), mod(mod), builder(builder), symbolMap(symbolMap), + functions(functions) {} + + virtual std::any visit(FnDecl &fnDecl, std::any param) override { + auto function = mod.getFunction(fnDecl.name); + auto block = llvm::BasicBlock::Create(ctx, createLabel(), function); + builder.SetInsertPoint(block); + + size_t i = 0; + for (auto &arg : function->args()) { + if (i > 0) { + auto store = builder.CreateAlloca(arg.getType(), nullptr); + builder.CreateStore(&arg, store); + symbolMap[fnDecl.params[i - 1]->symbol.get()] = store; + } + + i += 1; + } + + auto fnType = (llvm::FunctionType *)getLLVMType(ctx, fnDecl.symbol->type); + retStore = builder.CreateAlloca(fnType->getReturnType()); + retBlock = llvm::BasicBlock::Create(ctx, createLabel(), function); + + BaseASTVisitor::visit(fnDecl, param); + if (!fnDecl.body->alywasReturns()) + builder.CreateBr(retBlock); + + builder.SetInsertPoint(retBlock); + auto retVal = builder.CreateLoad(fnType->getReturnType(), retStore); + builder.CreateRet(retVal); + + return std::any(); + } + + virtual std::any visit(VarDecl &varDecl, std::any param) override { + auto store = builder.CreateAlloca(getLLVMType(ctx, varDecl.symbol->type)); + symbolMap[varDecl.symbol.get()] = store; + return std::any(); + } + + virtual std::any visit(BinExpr &binExpr, std::any param) override { + auto lhs = std::any_cast(binExpr.lhs->accept(this, param)); + auto rhs = std::any_cast(binExpr.rhs->accept(this, param)); + + auto primitiveType = (PrimitiveType *)binExpr.type.get(); + auto name = primitiveType->name; + + auto isFloat = name == "float" || name == "double"; + auto isUnsigned = name[0] == 'u'; + + switch (binExpr.op) { + case BinOp::ADD: + if (isFloat) + return builder.CreateFAdd(lhs, rhs); + return builder.CreateAdd(lhs, rhs); + case BinOp::SUB: + if (isFloat) + return builder.CreateFSub(lhs, rhs); + return builder.CreateSub(lhs, rhs); + case BinOp::MUL: + if (isFloat) + return builder.CreateFMul(lhs, rhs); + return builder.CreateMul(lhs, rhs); + case BinOp::DIV: + if (isFloat) + return builder.CreateFDiv(lhs, rhs); + if (isUnsigned) + return builder.CreateUDiv(lhs, rhs); + return builder.CreateSDiv(lhs, rhs); + case BinOp::MOD: + if (isUnsigned) + return builder.CreateURem(lhs, rhs); + return builder.CreateSRem(lhs, rhs); + case BinOp::EQ: + return builder.CreateICmpEQ(lhs, rhs); + case BinOp::NE: + return builder.CreateICmpNE(lhs, rhs); + case BinOp::LT: + if (isFloat) + return builder.CreateFCmpOGT(lhs, rhs); + if (isUnsigned) + return builder.CreateICmpULT(lhs, rhs); + return builder.CreateICmpSLT(lhs, rhs); + case BinOp::GT: + if (isFloat) + return builder.CreateFCmpOGT(lhs, rhs); + if (isUnsigned) + return builder.CreateICmpUGT(lhs, rhs); + return builder.CreateICmpSGT(lhs, rhs); + case BinOp::LE: + if (isFloat) + return builder.CreateFCmpOLE(lhs, rhs); + if (isUnsigned) + return builder.CreateICmpULE(lhs, rhs); + return builder.CreateICmpSLE(lhs, rhs); + case BinOp::GE: + if (isFloat) + return builder.CreateFCmpOGE(lhs, rhs); + if (isUnsigned) + return builder.CreateICmpUGE(lhs, rhs); + return builder.CreateICmpSGE(lhs, rhs); + case BinOp::AND: + return builder.CreateAnd(lhs, rhs); + case BinOp::OR: + return builder.CreateOr(lhs, rhs); + } + + throw std::runtime_error("binop not implemented"); + } + + virtual std::any visit(UnExpr &unExpr, std::any param) override { + auto expr = std::any_cast(unExpr.expr->accept(this, param)); + + switch (unExpr.op) { + case UnOp::NEG: + return builder.CreateNeg(expr); + case UnOp::NOT: + return builder.CreateNot(expr); + case UnOp::POS: + return expr; + } + + throw std::runtime_error("unop not implemented"); + } + + virtual std::any visit(CastExpr &castExpr, std::any param) override { + auto value = + std::any_cast(castExpr.value->accept(this, param)); + + if (utils::is(castExpr.value->type.get()) && + utils::is(castExpr.type.get())) { + auto primitiveType = (PrimitiveType *)castExpr.value->type.get(); + auto newPrimitiveType = (PrimitiveType *)castExpr.type.get(); + + auto newType = getLLVMType(ctx, castExpr.type); + + auto wasFloat = + primitiveType->name == "float" || primitiveType->name == "double"; + auto wasUnsigned = primitiveType->name[0] == 'u'; + auto willFloat = newPrimitiveType->name == "float" || + newPrimitiveType->name == "double"; + auto willUnsigned = newPrimitiveType->name[0] == 'u'; + + if (wasFloat) { + if (willFloat) { + if (primitiveType->name == "double") + return builder.CreateFPExt(value, newType); + else + return builder.CreateFPTrunc(value, newType); + } + + else { + if (willUnsigned) + return builder.CreateFPToUI(value, newType); + else + return builder.CreateFPToSI(value, newType); + } + } + + else { + if (willFloat) { + if (wasUnsigned) + return builder.CreateUIToFP(value, newType); + else + return builder.CreateSIToFP(value, newType); + } + + if (willUnsigned) + return builder.CreateZExtOrTrunc(value, newType); + else + return builder.CreateSExtOrTrunc(value, newType); + } + } + + throw std::runtime_error("cast not implemented"); + } + + virtual std::any visit(CallExpr &callExpr, std::any param) override { + auto callee = + std::any_cast(callExpr.callee->accept(this, param)); + + auto ptrType = llvm::IntegerType::get(ctx, 8)->getPointerTo(); + auto structType = llvm::StructType::get(ptrType, ptrType); + auto ep = builder.CreateStructGEP(structType, callee, 0); + auto callCtx = builder.CreateLoad(ptrType, ep); + + ep = builder.CreateStructGEP(structType, callee, 1); + auto realCallee = (llvm::Value *)builder.CreateLoad(ptrType, ep); + + // realCallee = builder.CreatePointerCast(realCallee, calleeType); + + std::vector llvmArgs; + llvmArgs.push_back(callCtx); + for (auto &arg : callExpr.args) { + llvmArgs.push_back( + std::any_cast(arg->accept(this, param))); + } + + auto calleeType = + (llvm::FunctionType *)getLLVMType(ctx, callExpr.callee->type); + return (llvm::Value *)builder.CreateCall(calleeType, realCallee, llvmArgs); + } + + virtual std::any visit(Identifier &identifier, std::any param) override { + auto value = symbolMap[identifier.symbol.get()]; + + if (rvalueForLValue) { + builder.CreateStore(rvalueForLValue, value); + return nullptr; + } + + else { + if (functions.count(value)) + return wrapCallee(value); + if (utils::is(identifier.type.get())) + return value; + + auto loadType = getLLVMType(ctx, identifier.type); + return (llvm::Value *)builder.CreateLoad(loadType, value); + } + } + + virtual std::any visit(IntValue &intValue, std::any param) override { + return (llvm::Value *)llvm::ConstantInt::get( + getLLVMType(ctx, intValue.type), intValue.value); + } + + virtual std::any visit(FloatValue &floatValue, std::any param) override { + return (llvm::Value *)llvm::ConstantFP::get( + getLLVMType(ctx, floatValue.type), floatValue.value); + } + + virtual std::any visit(RetStmt &retStmt, std::any param) override { + auto value = + std::any_cast(retStmt.value->accept(this, param)); + + builder.CreateStore(value, retStore); + builder.CreateBr(retBlock); + + return std::any(); + } + + virtual std::any visit(IfStmt &ifStmt, std::any param) override { + auto cond = + std::any_cast(ifStmt.condition->accept(this, param)); + + auto fn = builder.GetInsertBlock()->getParent(); + auto ifBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn); + auto elseBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn); + + llvm::BasicBlock *endBlock = nullptr; + if (!ifStmt.alywasReturns()) + endBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn); + + builder.CreateCondBr(cond, ifBlock, elseBlock); + + builder.SetInsertPoint(ifBlock); + ifStmt.ifBody->accept(this, param); + if (endBlock && !ifStmt.ifBody->alywasReturns()) + builder.CreateBr(endBlock); + + builder.SetInsertPoint(elseBlock); + ifStmt.elseBody->accept(this, param); + if (endBlock && !ifStmt.elseBody->alywasReturns()) + builder.CreateBr(endBlock); + + if (endBlock && !ifStmt.alywasReturns()) + builder.SetInsertPoint(endBlock); + + return std::any(); + } + + virtual std::any visit(WhileStmt &whileStmt, std::any param) override { + auto fn = builder.GetInsertBlock()->getParent(); + auto condBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn); + auto whileBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn); + auto endBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn); + + builder.CreateBr(condBlock); + + builder.SetInsertPoint(condBlock); + auto cond = + std::any_cast(whileStmt.condition->accept(this, param)); + builder.CreateCondBr(cond, whileBlock, endBlock); + + builder.SetInsertPoint(whileBlock); + whileStmt.body->accept(this, param); + if (!whileStmt.body->alywasReturns()) + builder.CreateBr(condBlock); + + builder.SetInsertPoint(endBlock); + + return std::any(); + } + + virtual std::any visit(AssignStmt &assignStmt, std::any param) override { + auto rvalue = + std::any_cast(assignStmt.rval->accept(this, param)); + + rvalueForLValue = rvalue; + auto lvalue = assignStmt.lval->accept(this, param); + rvalueForLValue = nullptr; + + return std::any(); + } +}; + +static void runMPM(llvm::Module &mod) { + llvm::PassBuilder passBuilder; + + llvm::ModuleAnalysisManager mam; + llvm::CGSCCAnalysisManager gam; + llvm::FunctionAnalysisManager fam; + llvm::LoopAnalysisManager lam; + + llvm::ModulePassManager mpm; + + passBuilder.registerModuleAnalyses(mam); + passBuilder.registerCGSCCAnalyses(gam); + passBuilder.registerFunctionAnalyses(fam); + passBuilder.registerLoopAnalyses(lam); + + passBuilder.crossRegisterProxies(lam, fam, gam, mam); + + mpm = passBuilder.buildModuleOptimizationPipeline( + llvm::OptimizationLevel::O3, llvm::ThinOrFullLTOPhase::None); + + mpm.run(mod, mam); + + mam.clear(); + gam.clear(); + fam.clear(); + lam.clear(); +} + +static void writeToFile(llvm::LLVMContext &ctx, llvm::Module &mod, + llvm::IRBuilder<> &builder, + const std::string &outfile) { + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllAsmPrinters(); + + auto target = LLVM_DEFAULT_TARGET_TRIPLE; + + mod.setTargetTriple(target); + + std::string err; + const llvm::Target *t = llvm::TargetRegistry::lookupTarget(target, err); + if (!t) + throw std::runtime_error(err); + + llvm::TargetMachine *targetMachine = + t->createTargetMachine(target, "", "", llvm::TargetOptions(), + // TODO: make configurable + llvm::Reloc::PIC_); + + mod.setDataLayout(targetMachine->createDataLayout()); + + std::error_code ec; + llvm::raw_fd_ostream dest(outfile, ec, llvm::sys::fs::OF_None); + if (ec) + throw std::runtime_error(ec.message()); + + llvm::legacy::PassManager pm; + + auto &tm = (llvm::LLVMTargetMachine &)*targetMachine; + + pm.add(new llvm::TargetLibraryInfoWrapperPass()); + pm.add(new llvm::MachineModuleInfoWrapperPass(&tm)); + + bool objResult = targetMachine->addPassesToEmitFile( + pm, dest, nullptr, llvm::CodeGenFileType::ObjectFile); + + if (objResult) + throw std::runtime_error("failed to produce " + outfile); + + pm.run(mod); + dest.flush(); +} + +} // namespace + +void compileModule(std::unique_ptr &module, + const std::string &filename) { + auto moduleId = filename; + + llvm::LLVMContext ctx; + llvm::Module mod(moduleId, ctx); + llvm::IRBuilder<> builder(ctx); + + std::map symbolMap; + std::set functions; + + IRGenerator1 generator1(ctx, mod, builder, symbolMap, functions); + module->accept(&generator1, nullptr); + + IRGenerator2 generator2(ctx, mod, builder, symbolMap, functions); + for (auto &stmt : module->stmts) { + if (utils::is(stmt.get())) + stmt->accept(&generator2, nullptr); + } + + if (llvm::verifyModule(mod, &llvm::errs())) { + mod.print(llvm::outs(), nullptr); + llvm::outs().flush(); + throw std::runtime_error("Module verification failed"); + } + + runMPM(mod); // info: does not work, programs will malfunction + + mod.print(llvm::outs(), nullptr); + llvm::outs().flush(); + + // std::cout << "----------------------------------------------" << std::endl; + // mod.print(llvm::outs(), nullptr); + // llvm::outs().flush(); + + writeToFile(ctx, mod, builder, filename + ".o"); +} + +} // namespace plsm \ No newline at end of file diff --git a/compiler/src/Anlaysis/NameAnalysis.cpp b/compiler/src/Visitors/NameAnalysis.cpp similarity index 89% rename from compiler/src/Anlaysis/NameAnalysis.cpp rename to compiler/src/Visitors/NameAnalysis.cpp index d2257b3..a35feec 100644 --- a/compiler/src/Anlaysis/NameAnalysis.cpp +++ b/compiler/src/Visitors/NameAnalysis.cpp @@ -21,6 +21,12 @@ public: if (!fnDecl.name.size()) return std::any(); + if (scopes->back().count(fnDecl.name)) { + errors::put( + fnDecl.error("redeclaration of global symbol '" + fnDecl.name + "'")); + return std::any(); + } + auto symbol = std::make_shared(fnDecl.name); fnDecl.symbol = symbol; scopes->back()[fnDecl.name] = symbol; @@ -32,6 +38,12 @@ public: if (!varDecl.name.size()) return std::any(); + if (scopes->back().count(varDecl.name)) { + errors::put(varDecl.error("redeclaration of global symbol '" + + varDecl.name + "'")); + return std::any(); + } + auto symbol = std::make_shared(varDecl.name); varDecl.symbol = symbol; scopes->back()[varDecl.name] = symbol; @@ -137,9 +149,7 @@ void performNameAnalysis(std::unique_ptr &module) { NameAnalysisVisitor1 visitor1(&scopes); NameAnalysisVisitor2 visitor2(&scopes); - for (auto &stmt : module->stmts) { - stmt->accept(&visitor1, nullptr); - } + module->accept(&visitor1, nullptr); for (auto &stmt : module->stmts) { if (utils::is(stmt.get())) diff --git a/compiler/src/Anlaysis/TypeAnalysis.cpp b/compiler/src/Visitors/TypeAnalysis.cpp similarity index 67% rename from compiler/src/Anlaysis/TypeAnalysis.cpp rename to compiler/src/Visitors/TypeAnalysis.cpp index d4b36ba..eab42b9 100644 --- a/compiler/src/Anlaysis/TypeAnalysis.cpp +++ b/compiler/src/Visitors/TypeAnalysis.cpp @@ -21,10 +21,12 @@ static std::map> primitiveTypes = { {"i16", std::make_shared("i16")}, {"i32", std::make_shared("i32")}, {"i64", std::make_shared("i64")}, + {"i128", std::make_shared("i128")}, {"u8", std::make_shared("u8")}, {"u16", std::make_shared("u16")}, {"u32", std::make_shared("u32")}, {"u64", std::make_shared("u64")}, + {"u128", std::make_shared("u128")}, {"float", std::make_shared("float")}, {"double", std::make_shared("double")}, }; @@ -48,6 +50,9 @@ static std::shared_ptr resolveTypeName(const TypeName *typeName) { static void castTo(std::unique_ptr &expr, const std::shared_ptr &type) { + if (*expr->type == *type) + return; + auto cast = new CastExpr(expr->sourceRange, std::move(expr), std::unique_ptr(type->toTypeName())); cast->type = type; @@ -68,14 +73,17 @@ static bool tryAssignTo(std::unique_ptr &from, const PrimitiveType *toT = (PrimitiveType *)toType.get(); std::map> castMatrix = { - {"i8", {"i16", "i32", "i64", "u8", "u16", "u32", "u64"}}, - {"i16", {"i32", "i64", "u16", "u32", "u64"}}, - {"i32", {"i64", "u32", "u64"}}, - {"i64", {"u64"}}, - {"u8", {"i16", "i32", "i64", "u16", "u32", "u64"}}, - {"u16", {"i32", "i64", "u32", "u64"}}, - {"u32", {"i64", "u64"}}, - {"u64", {}}, + {"i8", + {"i16", "i32", "i64", "u8", "u16", "u32", "u64", "i128", "u128"}}, + {"i16", {"i32", "i64", "u16", "u32", "u64", "i128", "u128"}}, + {"i32", {"i64", "u32", "u64", "i128", "u128"}}, + {"i64", {"u64", "i128", "u128"}}, + {"i128", {"u128"}}, + {"u8", {"i16", "i32", "i64", "u16", "u32", "u64", "i128", "u128"}}, + {"u16", {"i32", "i64", "u32", "u64", "i128", "u128"}}, + {"u32", {"i64", "u64", "i128", "u128"}}, + {"u64", {"i128", "u128"}}, + {"u128", {}}, {"float", {"double"}}, {"double", {}}, }; @@ -108,14 +116,15 @@ static bool canBeCastedTo(std::unique_ptr &from, PrimitiveType *fromT = (PrimitiveType *)from->type.get(); const PrimitiveType *toT = (PrimitiveType *)toType.get(); - std::vector allNumberTypes = {"i8", "i16", "i32", "i64", - "u8", "u16", "u32", "u64", - "float", "double"}; + std::vector allNumberTypes = { + "i8", "i16", "i32", "i64", "i128", "u8", + "u16", "u32", "u64", "u128", "float", "double"}; std::map> castMatrix = { {"i8", allNumberTypes}, {"i16", allNumberTypes}, {"i32", allNumberTypes}, {"i64", allNumberTypes}, - {"u8", allNumberTypes}, {"u16", allNumberTypes}, - {"u32", allNumberTypes}, {"u64", allNumberTypes}, + {"i128", allNumberTypes}, {"u8", allNumberTypes}, + {"u16", allNumberTypes}, {"u32", allNumberTypes}, + {"u64", allNumberTypes}, {"u128", allNumberTypes}, {"float", allNumberTypes}, {"double", allNumberTypes}, }; @@ -168,6 +177,11 @@ public: } virtual std::any visit(FnDecl &fnDecl, std::any param) override { + if (!(fnDecl.body.get() && fnDecl.body->alywasReturns())) { + errors::put(fnDecl.error("function '" + fnDecl.name + + "' does not always return a value")); + } + if (!fnDecl.symbol.get()) return std::any(); @@ -240,6 +254,39 @@ public: return std::any(); } + virtual std::any visit(LambdaExpr &lambdaExpr, std::any param) override { + std::shared_ptr returnType(nullptr); + if (lambdaExpr.returnTypeName.get()) { + lambdaExpr.returnTypeName->accept(this, param); + returnType = lambdaExpr.returnTypeName->type; + } + + std::vector> paramTypes; + for (auto &p : lambdaExpr.params) { + if (p.get()) + p->accept(this, param); + + if (p->symbol.get()) { + paramTypes.push_back(p->symbol->type); + } else { + paramTypes.push_back(std::shared_ptr(nullptr)); + } + } + + lambdaExpr.type = std::make_shared(paramTypes, returnType); + + auto prevReturnType = currentReturnType; + currentReturnType = returnType; + + if (lambdaExpr.body.get()) { + lambdaExpr.body->accept(this, param); + } + + currentReturnType = prevReturnType; + + return std::any(); + } + virtual std::any visit(Identifier &identifier, std::any param) override { if (!identifier.symbol.get()) return std::any(); @@ -306,6 +353,11 @@ public: if (!assignStmt.lval.get() || !assignStmt.rval->type.get()) return std::any(); + if (!utils::is(assignStmt.lval.get())) { + errors::put(assignStmt.error("invalid lvalue")); + return std::any(); + } + if (!tryAssignTo(assignStmt.rval, assignStmt.lval->type)) { errors::put(assignStmt.error("assignment type mismatch")); return std::any(); @@ -376,14 +428,125 @@ public: return std::any(); } - callExpr.type = callExpr.callee->type; - auto functionType = (FunctionType *)(callExpr.callee->type.get()); + + callExpr.type = functionType->returnType; + if (functionType->paramTypes.size() != callExpr.args.size()) { errors::put(callExpr.error("wrong number of arguments")); return std::any(); } + size_t smallerArgCount = + std::min(functionType->paramTypes.size(), callExpr.args.size()); + + for (size_t i = 0; i < smallerArgCount; i++) { + if (!callExpr.args[i].get() || !functionType->paramTypes[i].get()) + continue; + if (!callExpr.args[i]->type.get()) + continue; + + if (!tryAssignTo(callExpr.args[i], functionType->paramTypes[i])) { + errors::put(callExpr.args[i]->error("argument type mismatch")); + } + } + + return std::any(); + } + + virtual std::any visit(UnExpr &unExpr, std::any param) override { + BaseASTVisitor::visit(unExpr, param); + + if (!unExpr.expr.get() || !unExpr.expr->type.get()) + return std::any(); + + if (!utils::is(unExpr.expr->type.get())) { + errors::put(unExpr.error("operand must be of primitive type")); + return std::any(); + } + + if (unExpr.op == UnOp::NEG) { + castTo(unExpr.expr, std::make_shared("i32")); + } + + unExpr.type = unExpr.expr->type; + + return std::any(); + } + + virtual std::any visit(BinExpr &binExpr, std::any param) override { + BaseASTVisitor::visit(binExpr, param); + + if (!binExpr.lhs.get() || !binExpr.rhs.get()) + return std::any(); + if (!binExpr.lhs->type.get() || !binExpr.rhs->type.get()) + return std::any(); + + if (!utils::is(binExpr.lhs->type.get()) || + !utils::is(binExpr.rhs->type.get())) { + errors::put(binExpr.error("operands must be of primitive type")); + return std::any(); + } + + switch (binExpr.op) { + case BinOp::ADD: + case BinOp::SUB: + case BinOp::MUL: + case BinOp::DIV: { + if (!tryAssignTo(binExpr.rhs, binExpr.lhs->type)) { + if (!tryAssignTo(binExpr.lhs, binExpr.rhs->type)) { + errors::put( + binExpr.error("operands incompatible, explicit cast required")); + return std::any(); + } + } + + binExpr.type = binExpr.lhs->type; + + break; + } + case BinOp::MOD: { + auto lhsSuccess = + tryAssignTo(binExpr.lhs, std::make_shared("i64")); + auto rhsSuccess = + tryAssignTo(binExpr.rhs, std::make_shared("i64")); + + if (!lhsSuccess || !rhsSuccess) { + errors::put(binExpr.error("operands must be of integer type")); + return std::any(); + } + + binExpr.type = std::make_shared("i64"); + } + case BinOp::EQ: + case BinOp::NE: + case BinOp::LT: + case BinOp::GT: + case BinOp::LE: + case BinOp::GE: { + if (!tryAssignTo(binExpr.rhs, binExpr.lhs->type)) { + if (!tryAssignTo(binExpr.lhs, binExpr.rhs->type)) { + errors::put( + binExpr.error("operands incompatible, explicit cast required")); + return std::any(); + } + } + + binExpr.type = std::make_shared("i32"); + + break; + } + case BinOp::AND: + case BinOp::OR: { + castTo(binExpr.lhs, std::make_shared("i32")); + castTo(binExpr.rhs, std::make_shared("i32")); + + binExpr.type = std::make_shared("i32"); + + break; + } + } + return std::any(); } }; @@ -394,9 +557,7 @@ void performTypeAnalysis(std::unique_ptr &module) { TypeAnalysisVisitor1 visitor1; TypeAnalysisVisitor2 visitor2; - for (auto &stmt : module->stmts) { - stmt->accept(&visitor1, std::any()); - } + module->accept(&visitor1, nullptr); for (auto &stmt : module->stmts) { if (utils::is(stmt.get())) diff --git a/compiler/src/main.cpp b/compiler/src/main.cpp index d40249f..8c5c907 100644 --- a/compiler/src/main.cpp +++ b/compiler/src/main.cpp @@ -4,6 +4,7 @@ #include #include "Analysis.h" +#include "Compile.h" #include "Errors.h" #include "Parser.h" @@ -30,11 +31,16 @@ int main(int argc, char *argv[]) { try { auto module = plsm::parse(argv[1], input); - // std::cout << module->toJsonString() << std::endl; plsm::performNameAnalysis(module); plsm::performTypeAnalysis(module); + // std::cout << module->toJsonString() << std::endl; + + if (!plsm::errors::get().size()) { + plsm::compileModule(module, std::string(argv[1])); + } + // std::cout << "\n\n"; // std::cout << plsm::ast::Module::fromJson(module->toJson())->toJson() << diff --git a/examples/new b/examples/new new file mode 100755 index 0000000000000000000000000000000000000000..e943eaefa4307b7296c30b3d5177cd39f73eaa11 GIT binary patch literal 16488 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 OpbHnypMw+<#lHX^DL-!j literal 0 HcmV?d00001 diff --git a/examples/new.plsm b/examples/new.plsm index d2b03cb..d73e5d2 100644 --- a/examples/new.plsm +++ b/examples/new.plsm @@ -1,16 +1,22 @@ -var asdf : i64; +fun addFirst(n : i32) i32 { + var result : i32; + result = 0; -fun main(arg0 i64) i8 { - var a : i64; - a = 10 + 2; - - if (asdf > 1000) { - a = 1; - } else if (asdf > 500) { - a = 2; - } else { - a = 3; + var i : i32; + i = 0; + while (i < n) { + result = result + i; + i = i + 1; } - ret 100; + ret result; +} + +// fun f(n : i32) i32 { +// if (n < 2) ret n; +// ret f(n - 1); +// } + +fun main(argc : i32) u8 { + ret addFirst(argc) as u8; }