diff --git a/doc/grammar.bnf b/doc/grammar.bnf index acbdd86..a2fdb80 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -11,7 +11,7 @@ PARAMS ::= (ident type? (comma ident type?)*) RET ::= type? BLOCK ::= obrace INSTR* cbrace -DIR ::= hash ident EXPR +DIR ::= hash ident EXPR (as ident)? EXPR ::= | ADDSUB @@ -29,4 +29,4 @@ LITERAL ::= CALL ::= ident opar ARGS cpar ARGS ::= (EXPR (comma EXPR)*)? -NS ::= ident (dot ident)+ +NS ::= ident (dot (ident|CALL))+ diff --git a/lib/Compiler.cpp b/lib/Compiler.cpp index b051982..378a069 100644 --- a/lib/Compiler.cpp +++ b/lib/Compiler.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -13,7 +15,8 @@ namespace wg { - /*explicit*/ Compiler::Compiler() + /*explicit*/ Compiler::Compiler(Mod& mod) + : m_mod { mod } { } @@ -51,8 +54,8 @@ namespace wg opt, rm); - m_module->setDataLayout(target_machine->createDataLayout()); - m_module->setTargetTriple(target_triple); + m_mod.mod().setDataLayout(target_machine->createDataLayout()); + m_mod.mod().setTargetTriple(target_triple); auto filename = obj.string(); std::error_code ec; @@ -68,16 +71,125 @@ namespace wg llvm::errs() << "Target machine cannot emit a file of this type"; } - llvm::verifyModule(*m_module); + llvm::verifyModule(m_mod.mod()); - pass.run(*m_module); + pass.run(m_mod.mod()); dest.flush(); } - void Compiler::init_package(std::shared_ptr node) + + void Compiler::execute(std::shared_ptr node) { - m_pkg->scan(node, *m_sym); + imports(node); + scan(node); + compile(node); + } + + void Compiler::imports(std::shared_ptr node) + { + switch (node->type()) + { + case NODE_DIR: { + if (node->child(0)->repr() == "import") + { + auto mod_name = node->child(1)->repr(); + auto lib_path = "/usr/lib/libwongola-std.so"; + auto lib = llvm::sys::DynamicLibrary::getLibrary(lib_path); + + if (lib.isValid()) + { + std::string entry_name = "lib_" + mod_name; + typedef std::unique_ptr(*func)(); + + func entry = (func) lib.getAddressOfSymbol + (entry_name.c_str()); + + if (entry == nullptr) + { + node->loc().error + ("cannot import module '" + + mod_name + + "'"); + } + + if (node->size() == 3) + { + mod_name = node->child(2)->repr(); + } + + m_imports.insert({mod_name, entry()}); + } + else + { + node->loc().error("cannot stdlib"); + } + } + + } break; + default: { + for (size_t i=0; isize(); i++) + { + imports(node->child(i)); + } + } break; + } + } + + void Compiler::scan(std::shared_ptr node) + { + switch (node->type()) + { + case NODE_FUNDECL: { + std::string name = node->child(0)->repr(); + std::vector params; + std::vector> buffer; + + for (size_t i=0; ichild(1)->size(); i++) + { + auto param = node->child(1)->child(i); + + if (param->type() == NODE_IDENT) + { + buffer.push_back(param); + } + else if (param->type() == NODE_TYPE) + { + for (auto p: buffer) + { + params.push_back((llvm::Type*) + llvm::Type::getInt32Ty(m_mod.context())); + } + + buffer.clear(); + } + } + + auto* ret = llvm::Type::getVoidTy(m_mod.context()); + + if (node->child(2)->size() > 0) + { + ret = (llvm::Type*) llvm::Type::getInt32Ty(m_mod.context()); + } + + auto* fun_ty = llvm::FunctionType::get(ret, params, false); + + m_mod.sym().declare_prototype(name, fun_ty, node->loc()); + + llvm::Function::Create(fun_ty, + llvm::Function::ExternalLinkage, + name, + m_mod.mod()); + + } break; + + default: { + for (size_t i=0; isize(); i++) + { + scan(node->child(i)); + } + } break; + } } llvm::Value* Compiler::compile(std::shared_ptr node) @@ -102,13 +214,39 @@ namespace wg } break; case NODE_DIR: { - if (node->child(0)->repr() == "import") + return nullptr; + } break; + + case NODE_NS: { + auto mod_name = node->child(0)->repr(); + auto ident = node->child(1)->child(0)->repr(); + + if (auto itr=m_imports.find(mod_name); + itr != std::end(m_imports)) { - std::string pkg_name = node->child(1)->repr(); - std::cout << "import pkg " << pkg_name << std::endl; + auto fun = itr->second->mod().getFunction(ident); + WG_ASSERT(fun, "cannot call unknown function '" + ident + "'"); + + std::vector values; + + auto arg_node = node->child(1)->child(1); + for (size_t i=0; isize(); i++) + { + auto arg = arg_node->child(i); + auto val = compile(arg); + values.push_back(val); + } + + return m_builder->CreateCall(fun, values); + } + else + { + node->loc().error("cannot find module '" + + mod_name + + "'"); + abort(); } - return nullptr; } break; case NODE_RETURN: { @@ -165,12 +303,12 @@ namespace wg case NODE_FUNDECL: { auto ident = node->child(0)->repr(); auto body = node->child(3); - auto fun = m_module-> getFunction(ident); + auto fun = m_mod.mod(). getFunction(ident); llvm::BasicBlock* old_bb = m_builder->GetInsertBlock(); - auto* bb = llvm::BasicBlock::Create(*m_context, + auto* bb = llvm::BasicBlock::Create(m_mod.context(), "entry", fun); m_builder->SetInsertPoint(bb); @@ -187,7 +325,7 @@ namespace wg case NODE_CALL: { std::string ident = node->child(0)->repr(); - auto fun = m_module->getFunction(ident); + auto fun = m_mod.mod().getFunction(ident); WG_ASSERT(fun, "cannot call unknown function '" + ident + "'"); std::vector values; @@ -233,8 +371,7 @@ namespace wg } break; case NODE_INT: { - - return llvm::ConstantInt::get(*m_context, + return llvm::ConstantInt::get(m_mod.context(), llvm::APInt(32, std::stoi(node->repr()), true)); diff --git a/lib/Compiler.hpp b/lib/Compiler.hpp index 5e1d5fd..290dfae 100644 --- a/lib/Compiler.hpp +++ b/lib/Compiler.hpp @@ -8,32 +8,30 @@ #include "commons.hpp" #include "Node.hpp" #include "SymTable.hpp" -#include "Package.hpp" +#include "Mod.hpp" namespace wg { + WG_ERROR(compile_error); + class Compiler { public: - explicit Compiler(); + explicit Compiler(Mod& mod); virtual ~Compiler(); void gen(std::filesystem::path obj); - void init_package(std::shared_ptr node); + + void execute(std::shared_ptr node); + void imports(std::shared_ptr node); + void scan(std::shared_ptr node); llvm::Value* compile(std::shared_ptr node); + private: - std::unique_ptr m_context = - std::make_unique(); - + Mod& m_mod; + std::unordered_map> m_imports; std::unique_ptr> m_builder = - std::make_unique>(*m_context); - - std::unique_ptr m_module = - std::make_unique("my module", *m_context); - - std::unique_ptr m_sym = std::make_unique(); - std::unique_ptr m_pkg = std::make_unique(*m_context, - *m_module); + std::make_unique>(m_mod.context()); }; } diff --git a/lib/Lexer.cpp b/lib/Lexer.cpp index f68832c..10587aa 100644 --- a/lib/Lexer.cpp +++ b/lib/Lexer.cpp @@ -5,6 +5,7 @@ namespace wg { /*explicit*/ Lexer::Lexer() { + add_keyword("as", NODE_AS); add_keyword("int", NODE_TYPE, true); add_keyword("fun", NODE_FUN); add_keyword("return", NODE_RETURN); diff --git a/lib/Mod.cpp b/lib/Mod.cpp new file mode 100644 index 0000000..4423b68 --- /dev/null +++ b/lib/Mod.cpp @@ -0,0 +1,13 @@ +#include "Mod.hpp" + +namespace wg +{ + /*explicit*/ Mod::Mod(std::string const& name) + : m_name { name } + { + } + + /*virtual*/ Mod::~Mod() + { + } +} diff --git a/lib/Mod.hpp b/lib/Mod.hpp new file mode 100644 index 0000000..a54c10e --- /dev/null +++ b/lib/Mod.hpp @@ -0,0 +1,34 @@ +#ifndef wg_MOD_HPP +#define wg_MOD_HPP + +#include +#include + +#include "SymTable.hpp" +#include "commons.hpp" + +namespace wg +{ + class Mod + { + public: + explicit Mod(std::string const& name); + virtual ~Mod(); + + llvm::LLVMContext& context() { return *m_context; } + llvm::Module& mod() { return *m_module; } + SymTable& sym() { return *m_sym; } + + private: + std::string m_name; + std::unique_ptr m_context = + std::make_unique(); + + std::unique_ptr m_module = + std::make_unique(m_name, *m_context); + + std::unique_ptr m_sym = std::make_unique(); + }; +} + +#endif diff --git a/lib/Node.hpp b/lib/Node.hpp index ed55dc4..a13897e 100644 --- a/lib/Node.hpp +++ b/lib/Node.hpp @@ -17,7 +17,8 @@ G(NODE_ARGS), G(NODE_TYPE), G(NODE_RETURN), \ G(NODE_FUN), G(NODE_PARAMS), G(NODE_BLOCK), \ G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_FUNDECL), \ - G(NODE_EXTERN), G(NODE_RET), G(NODE_DOT), G(NODE_NS) + G(NODE_EXTERN), G(NODE_RET), G(NODE_DOT), G(NODE_NS), \ + G(NODE_AS) namespace wg { diff --git a/lib/Package.cpp b/lib/Package.cpp deleted file mode 100644 index 3d253ad..0000000 --- a/lib/Package.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include - -#include "Package.hpp" - -namespace wg -{ - /*explicit*/ Package::Package(llvm::LLVMContext& context, - llvm::Module& mod) - : m_context { context } - , m_module { mod } - { - } - - /*virtual*/ Package::~Package() - { - } - - void Package::scan(std::shared_ptr node, SymTable& sym) - { - switch (node->type()) - { - case NODE_DIR: { - if (node->child(0)->repr() == "package") - { - m_name = node->child(1)->repr(); - } - } break; - - case NODE_FUNDECL: { - std::string name = node->child(0)->repr(); - std::vector params; - std::vector> buffer; - - for (size_t i=0; ichild(1)->size(); i++) - { - auto param = node->child(1)->child(i); - - if (param->type() == NODE_IDENT) - { - buffer.push_back(param); - } - else if (param->type() == NODE_TYPE) - { - for (auto p: buffer) - { - params.push_back((llvm::Type*) - llvm::Type::getInt32Ty(m_context)); - } - - buffer.clear(); - } - } - - auto* ret = llvm::Type::getVoidTy(m_context); - - if (node->child(2)->size() > 0) - { - ret = (llvm::Type*) llvm::Type::getInt32Ty(m_context); - } - - auto* fun_ty = llvm::FunctionType::get(ret, params, false); - - sym.declare_prototype(name, fun_ty, node->loc()); - - llvm::Function::Create(fun_ty, - llvm::Function::ExternalLinkage, - name, - m_module); - - } break; - - default: { - for (size_t i=0; isize(); i++) - { - scan(node->child(i), sym); - } - } break; - } - } -} diff --git a/lib/Package.hpp b/lib/Package.hpp deleted file mode 100644 index 99d7a73..0000000 --- a/lib/Package.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef wg_PACKAGE_HPP -#define wg_PACKAGE_HPP - -#include "commons.hpp" - -#include "SymTable.hpp" -#include "Node.hpp" -#include - -namespace wg -{ - class Package - { - public: - explicit Package(llvm::LLVMContext& context, - llvm::Module& mod); - virtual ~Package(); - - void scan(std::shared_ptr node, SymTable& sym); - - private: - llvm::LLVMContext& m_context; - llvm::Module& m_module; - std::string m_name; - }; -} - -#endif diff --git a/lib/Parser.cpp b/lib/Parser.cpp index c782e19..a4a3880 100644 --- a/lib/Parser.cpp +++ b/lib/Parser.cpp @@ -231,6 +231,13 @@ namespace wg consume(NODE_HASH); node->add_child(consume(NODE_IDENT)); node->add_child(parse_expr()); + + if (type_is(NODE_AS)) + { + consume(); + node->add_child(consume(NODE_IDENT)); + } + return node; } @@ -352,7 +359,16 @@ namespace wg while (type_is(NODE_DOT)) { consume(); - node->add_child(consume(NODE_IDENT)); + + if (type_is(NODE_IDENT) + && type_is(NODE_OPAR, 1)) + { + node->add_child(parse_call()); + } + else + { + node->add_child(consume(NODE_IDENT)); + } } return node; diff --git a/meson.build b/meson.build index ece59ac..2f265f3 100644 --- a/meson.build +++ b/meson.build @@ -7,13 +7,6 @@ project('wongola', 'cpp_std=c++17' ]) -shared_library( - 'wongola-std', - sources: [ - 'std/io.cpp' - ], - install: true -) wongola_lib = static_library( 'wongola', @@ -24,7 +17,7 @@ wongola_lib = static_library( 'lib/Compiler.cpp', 'lib/Loc.cpp', 'lib/SymTable.cpp', - 'lib/Package.cpp', + 'lib/Mod.cpp', ], dependencies: [ dependency('LLVM') @@ -36,6 +29,17 @@ wongola_dep = declare_dependency( include_directories: ['lib'] ) +shared_library( + 'wongola-std', + sources: [ + 'std/io.cpp' + ], + dependencies: [ + wongola_dep + ], + install: true +) + executable('wongoc', sources: [ 'src/main.cpp', diff --git a/src/main.cpp b/src/main.cpp index be68271..107064d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "Mod.hpp" std::filesystem::path name_to_obj(std::string const& path) { @@ -41,9 +42,10 @@ void load(std::string const& path) wg::Parser parser; auto ast = parser.parse(tokens); - wg::Compiler compiler; - compiler.init_package(ast); - compiler.compile(ast); + wg::Mod mod {"main"}; + wg::Compiler compiler {mod}; + + compiler.execute(ast); compiler.gen(name_to_obj(path)); } @@ -101,7 +103,7 @@ int main(int argc, char** argv) ss << "clang++" << " -o " << output_path << " "; ss << objname; - //ss << " -lwongola-std "; + ss << " -lwongola-std "; system(ss.str().c_str()); std::filesystem::remove(objname); diff --git a/std/io.cpp b/std/io.cpp index 58e54d7..bd4aac8 100644 --- a/std/io.cpp +++ b/std/io.cpp @@ -1,10 +1,24 @@ #include "io.hpp" #include -extern "C" void hello(int x) +extern "C" std::unique_ptr lib_io() { - for (int i=0; i("io"); + + std::vector params; + auto* ret = llvm::Type::getInt32Ty(mod->context()); + + auto* ftype = llvm::FunctionType::get(ret, params, false); + + llvm::Function::Create(ftype, + llvm::Function::ExternalLinkage, + "hello", + mod->mod()); + + return mod; +} + +extern "C" int hello(int x) +{ + return 2 * x + 1; } diff --git a/std/io.hpp b/std/io.hpp index 8aba0f2..5ac3f44 100644 --- a/std/io.hpp +++ b/std/io.hpp @@ -1,7 +1,8 @@ #ifndef IO_HPP #define IO_HPP +#include "../lib/Mod.hpp" - -extern "C" void hello(int x); +extern "C" std::unique_ptr lib_io(); +extern "C" int hello(int x); #endif diff --git a/tests/Lexer.cpp b/tests/Lexer.cpp index 8c80d60..bb364c7 100644 --- a/tests/Lexer.cpp +++ b/tests/Lexer.cpp @@ -76,3 +76,11 @@ TEST_CASE_METHOD(LexerTest, "Lexer_pkg_namespace") test_next(lex, "DOT"); test_end(lex); } + +TEST_CASE_METHOD(LexerTest, "Lexer_as") +{ + wg::Lexer lex; + lex.scan(" as "); + test_next(lex, "AS"); + test_end(lex); +} diff --git a/tests/Parser.cpp b/tests/Parser.cpp index b3deea4..9d4c3c0 100644 --- a/tests/Parser.cpp +++ b/tests/Parser.cpp @@ -29,6 +29,9 @@ TEST_CASE_METHOD(ParserTest, "Parser_dir") { test_parse("PROG(DIR(IDENT[hello],IDENT[world]))", "#hello world"); + + test_parse("PROG(DIR(IDENT[hello],IDENT[world],IDENT[boom]))", + "#hello world as boom"); } @@ -95,4 +98,8 @@ TEST_CASE_METHOD(ParserTest, "Parser_namespace") { test_parse("PROG(NS(IDENT[a],IDENT[b],IDENT[c],IDENT[d]))", " a.b.c.d; "); + + test_parse("PROG(NS(IDENT[a],IDENT[b],IDENT[c]," + "CALL(IDENT[d],ARGS)))", + " a.b.c.d(); "); }