ADD: import module from wongola-std.

main
bog 2023-09-29 18:26:05 +02:00
parent 2fe55d2c20
commit 335189c31c
16 changed files with 289 additions and 162 deletions

View File

@ -11,7 +11,7 @@ PARAMS ::= (ident type? (comma ident type?)*)
RET ::= type? RET ::= type?
BLOCK ::= obrace INSTR* cbrace BLOCK ::= obrace INSTR* cbrace
DIR ::= hash ident EXPR DIR ::= hash ident EXPR (as ident)?
EXPR ::= EXPR ::=
| ADDSUB | ADDSUB
@ -29,4 +29,4 @@ LITERAL ::=
CALL ::= ident opar ARGS cpar CALL ::= ident opar ARGS cpar
ARGS ::= (EXPR (comma EXPR)*)? ARGS ::= (EXPR (comma EXPR)*)?
NS ::= ident (dot ident)+ NS ::= ident (dot (ident|CALL))+

View File

@ -3,6 +3,8 @@
#include <llvm/IR/BasicBlock.h> #include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Verifier.h> #include <llvm/IR/Verifier.h>
#include <llvm/IR/Type.h> #include <llvm/IR/Type.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Value.h>
#include <llvm/TargetParser/Host.h> #include <llvm/TargetParser/Host.h>
#include <llvm/Target/TargetOptions.h> #include <llvm/Target/TargetOptions.h>
#include <llvm/Target/TargetMachine.h> #include <llvm/Target/TargetMachine.h>
@ -13,7 +15,8 @@
namespace wg namespace wg
{ {
/*explicit*/ Compiler::Compiler() /*explicit*/ Compiler::Compiler(Mod& mod)
: m_mod { mod }
{ {
} }
@ -51,8 +54,8 @@ namespace wg
opt, opt,
rm); rm);
m_module->setDataLayout(target_machine->createDataLayout()); m_mod.mod().setDataLayout(target_machine->createDataLayout());
m_module->setTargetTriple(target_triple); m_mod.mod().setTargetTriple(target_triple);
auto filename = obj.string(); auto filename = obj.string();
std::error_code ec; std::error_code ec;
@ -68,16 +71,125 @@ namespace wg
llvm::errs() << "Target machine cannot emit a file of this type"; 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(); dest.flush();
} }
void Compiler::init_package(std::shared_ptr<Node> node)
void Compiler::execute(std::shared_ptr<Node> node)
{ {
m_pkg->scan(node, *m_sym); imports(node);
scan(node);
compile(node);
}
void Compiler::imports(std::shared_ptr<Node> 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<Mod>(*func)();
func entry = (func) lib.getAddressOfSymbol
(entry_name.c_str());
if (entry == nullptr)
{
node->loc().error<compile_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<compile_error>("cannot stdlib");
}
}
} break;
default: {
for (size_t i=0; i<node->size(); i++)
{
imports(node->child(i));
}
} break;
}
}
void Compiler::scan(std::shared_ptr<Node> node)
{
switch (node->type())
{
case NODE_FUNDECL: {
std::string name = node->child(0)->repr();
std::vector<llvm::Type*> params;
std::vector<std::shared_ptr<Node>> buffer;
for (size_t i=0; i<node->child(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; i<node->size(); i++)
{
scan(node->child(i));
}
} break;
}
} }
llvm::Value* Compiler::compile(std::shared_ptr<Node> node) llvm::Value* Compiler::compile(std::shared_ptr<Node> node)
@ -102,13 +214,39 @@ namespace wg
} break; } break;
case NODE_DIR: { 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(); auto fun = itr->second->mod().getFunction(ident);
std::cout << "import pkg " << pkg_name << std::endl; WG_ASSERT(fun, "cannot call unknown function '" + ident + "'");
std::vector<llvm::Value*> values;
auto arg_node = node->child(1)->child(1);
for (size_t i=0; i<arg_node->size(); 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<compile_error>("cannot find module '"
+ mod_name
+ "'");
abort();
} }
return nullptr;
} break; } break;
case NODE_RETURN: { case NODE_RETURN: {
@ -165,12 +303,12 @@ namespace wg
case NODE_FUNDECL: { case NODE_FUNDECL: {
auto ident = node->child(0)->repr(); auto ident = node->child(0)->repr();
auto body = node->child(3); 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(); llvm::BasicBlock* old_bb = m_builder->GetInsertBlock();
auto* bb = llvm::BasicBlock::Create(*m_context, auto* bb = llvm::BasicBlock::Create(m_mod.context(),
"entry", "entry",
fun); fun);
m_builder->SetInsertPoint(bb); m_builder->SetInsertPoint(bb);
@ -187,7 +325,7 @@ namespace wg
case NODE_CALL: { case NODE_CALL: {
std::string ident = node->child(0)->repr(); 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 + "'"); WG_ASSERT(fun, "cannot call unknown function '" + ident + "'");
std::vector<llvm::Value*> values; std::vector<llvm::Value*> values;
@ -233,8 +371,7 @@ namespace wg
} break; } break;
case NODE_INT: { case NODE_INT: {
return llvm::ConstantInt::get(m_mod.context(),
return llvm::ConstantInt::get(*m_context,
llvm::APInt(32, llvm::APInt(32,
std::stoi(node->repr()), std::stoi(node->repr()),
true)); true));

View File

@ -8,32 +8,30 @@
#include "commons.hpp" #include "commons.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "SymTable.hpp" #include "SymTable.hpp"
#include "Package.hpp" #include "Mod.hpp"
namespace wg namespace wg
{ {
WG_ERROR(compile_error);
class Compiler class Compiler
{ {
public: public:
explicit Compiler(); explicit Compiler(Mod& mod);
virtual ~Compiler(); virtual ~Compiler();
void gen(std::filesystem::path obj); void gen(std::filesystem::path obj);
void init_package(std::shared_ptr<Node> node);
void execute(std::shared_ptr<Node> node);
void imports(std::shared_ptr<Node> node);
void scan(std::shared_ptr<Node> node);
llvm::Value* compile(std::shared_ptr<Node> node); llvm::Value* compile(std::shared_ptr<Node> node);
private: private:
std::unique_ptr<llvm::LLVMContext> m_context = Mod& m_mod;
std::make_unique<llvm::LLVMContext>(); std::unordered_map<std::string, std::unique_ptr<Mod>> m_imports;
std::unique_ptr<llvm::IRBuilder<>> m_builder = std::unique_ptr<llvm::IRBuilder<>> m_builder =
std::make_unique<llvm::IRBuilder<>>(*m_context); std::make_unique<llvm::IRBuilder<>>(m_mod.context());
std::unique_ptr<llvm::Module> m_module =
std::make_unique<llvm::Module>("my module", *m_context);
std::unique_ptr<SymTable> m_sym = std::make_unique<SymTable>();
std::unique_ptr<Package> m_pkg = std::make_unique<Package>(*m_context,
*m_module);
}; };
} }

View File

@ -5,6 +5,7 @@ namespace wg
{ {
/*explicit*/ Lexer::Lexer() /*explicit*/ Lexer::Lexer()
{ {
add_keyword("as", NODE_AS);
add_keyword("int", NODE_TYPE, true); add_keyword("int", NODE_TYPE, true);
add_keyword("fun", NODE_FUN); add_keyword("fun", NODE_FUN);
add_keyword("return", NODE_RETURN); add_keyword("return", NODE_RETURN);

13
lib/Mod.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "Mod.hpp"
namespace wg
{
/*explicit*/ Mod::Mod(std::string const& name)
: m_name { name }
{
}
/*virtual*/ Mod::~Mod()
{
}
}

34
lib/Mod.hpp Normal file
View File

@ -0,0 +1,34 @@
#ifndef wg_MOD_HPP
#define wg_MOD_HPP
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#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<llvm::LLVMContext> m_context =
std::make_unique<llvm::LLVMContext>();
std::unique_ptr<llvm::Module> m_module =
std::make_unique<llvm::Module>(m_name, *m_context);
std::unique_ptr<SymTable> m_sym = std::make_unique<SymTable>();
};
}
#endif

View File

@ -17,7 +17,8 @@
G(NODE_ARGS), G(NODE_TYPE), G(NODE_RETURN), \ G(NODE_ARGS), G(NODE_TYPE), G(NODE_RETURN), \
G(NODE_FUN), G(NODE_PARAMS), G(NODE_BLOCK), \ G(NODE_FUN), G(NODE_PARAMS), G(NODE_BLOCK), \
G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_FUNDECL), \ 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 namespace wg
{ {

View File

@ -1,81 +0,0 @@
#include <llvm/IR/Value.h>
#include <llvm/IR/Function.h>
#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> 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<llvm::Type*> params;
std::vector<std::shared_ptr<Node>> buffer;
for (size_t i=0; i<node->child(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; i<node->size(); i++)
{
scan(node->child(i), sym);
}
} break;
}
}
}

View File

@ -1,28 +0,0 @@
#ifndef wg_PACKAGE_HPP
#define wg_PACKAGE_HPP
#include "commons.hpp"
#include "SymTable.hpp"
#include "Node.hpp"
#include <llvm/IR/LLVMContext.h>
namespace wg
{
class Package
{
public:
explicit Package(llvm::LLVMContext& context,
llvm::Module& mod);
virtual ~Package();
void scan(std::shared_ptr<Node> node, SymTable& sym);
private:
llvm::LLVMContext& m_context;
llvm::Module& m_module;
std::string m_name;
};
}
#endif

View File

@ -231,6 +231,13 @@ namespace wg
consume(NODE_HASH); consume(NODE_HASH);
node->add_child(consume(NODE_IDENT)); node->add_child(consume(NODE_IDENT));
node->add_child(parse_expr()); node->add_child(parse_expr());
if (type_is(NODE_AS))
{
consume();
node->add_child(consume(NODE_IDENT));
}
return node; return node;
} }
@ -352,8 +359,17 @@ namespace wg
while (type_is(NODE_DOT)) while (type_is(NODE_DOT))
{ {
consume(); consume();
if (type_is(NODE_IDENT)
&& type_is(NODE_OPAR, 1))
{
node->add_child(parse_call());
}
else
{
node->add_child(consume(NODE_IDENT)); node->add_child(consume(NODE_IDENT));
} }
}
return node; return node;
} }

View File

@ -7,13 +7,6 @@ project('wongola',
'cpp_std=c++17' 'cpp_std=c++17'
]) ])
shared_library(
'wongola-std',
sources: [
'std/io.cpp'
],
install: true
)
wongola_lib = static_library( wongola_lib = static_library(
'wongola', 'wongola',
@ -24,7 +17,7 @@ wongola_lib = static_library(
'lib/Compiler.cpp', 'lib/Compiler.cpp',
'lib/Loc.cpp', 'lib/Loc.cpp',
'lib/SymTable.cpp', 'lib/SymTable.cpp',
'lib/Package.cpp', 'lib/Mod.cpp',
], ],
dependencies: [ dependencies: [
dependency('LLVM') dependency('LLVM')
@ -36,6 +29,17 @@ wongola_dep = declare_dependency(
include_directories: ['lib'] include_directories: ['lib']
) )
shared_library(
'wongola-std',
sources: [
'std/io.cpp'
],
dependencies: [
wongola_dep
],
install: true
)
executable('wongoc', executable('wongoc',
sources: [ sources: [
'src/main.cpp', 'src/main.cpp',

View File

@ -5,6 +5,7 @@
#include <Parser.hpp> #include <Parser.hpp>
#include <Compiler.hpp> #include <Compiler.hpp>
#include <llvm/Support/DynamicLibrary.h> #include <llvm/Support/DynamicLibrary.h>
#include "Mod.hpp"
std::filesystem::path name_to_obj(std::string const& path) std::filesystem::path name_to_obj(std::string const& path)
{ {
@ -41,9 +42,10 @@ void load(std::string const& path)
wg::Parser parser; wg::Parser parser;
auto ast = parser.parse(tokens); auto ast = parser.parse(tokens);
wg::Compiler compiler; wg::Mod mod {"main"};
compiler.init_package(ast); wg::Compiler compiler {mod};
compiler.compile(ast);
compiler.execute(ast);
compiler.gen(name_to_obj(path)); compiler.gen(name_to_obj(path));
} }
@ -101,7 +103,7 @@ int main(int argc, char** argv)
ss << "clang++" << " -o " << output_path << " "; ss << "clang++" << " -o " << output_path << " ";
ss << objname; ss << objname;
//ss << " -lwongola-std "; ss << " -lwongola-std ";
system(ss.str().c_str()); system(ss.str().c_str());
std::filesystem::remove(objname); std::filesystem::remove(objname);

View File

@ -1,10 +1,24 @@
#include "io.hpp" #include "io.hpp"
#include <iostream> #include <iostream>
extern "C" void hello(int x) extern "C" std::unique_ptr<wg::Mod> lib_io()
{ {
for (int i=0; i<x; i++) auto mod = std::make_unique<wg::Mod>("io");
{
std::cout << "hello ! " << std::endl; std::vector<llvm::Type*> 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;
} }

View File

@ -1,7 +1,8 @@
#ifndef IO_HPP #ifndef IO_HPP
#define IO_HPP #define IO_HPP
#include "../lib/Mod.hpp"
extern "C" std::unique_ptr<wg::Mod> lib_io();
extern "C" void hello(int x); extern "C" int hello(int x);
#endif #endif

View File

@ -76,3 +76,11 @@ TEST_CASE_METHOD(LexerTest, "Lexer_pkg_namespace")
test_next(lex, "DOT"); test_next(lex, "DOT");
test_end(lex); test_end(lex);
} }
TEST_CASE_METHOD(LexerTest, "Lexer_as")
{
wg::Lexer lex;
lex.scan(" as ");
test_next(lex, "AS");
test_end(lex);
}

View File

@ -29,6 +29,9 @@ TEST_CASE_METHOD(ParserTest, "Parser_dir")
{ {
test_parse("PROG(DIR(IDENT[hello],IDENT[world]))", test_parse("PROG(DIR(IDENT[hello],IDENT[world]))",
"#hello 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]))", test_parse("PROG(NS(IDENT[a],IDENT[b],IDENT[c],IDENT[d]))",
" a.b.c.d; "); " a.b.c.d; ");
test_parse("PROG(NS(IDENT[a],IDENT[b],IDENT[c],"
"CALL(IDENT[d],ARGS)))",
" a.b.c.d(); ");
} }