Compare commits
4 Commits
506961fff5
...
217f5c2f92
Author | SHA1 | Date |
---|---|---|
bog | 217f5c2f92 | |
bog | 335189c31c | |
bog | 2fe55d2c20 | |
bog | f7857a5d4b |
|
@ -11,11 +11,16 @@ PARAMS ::= (ident type? (comma ident type?)*)
|
|||
RET ::= type?
|
||||
BLOCK ::= obrace INSTR* cbrace
|
||||
|
||||
DIR ::= hash ident EXPR
|
||||
DIR ::= hash ident EXPR (as ident)?
|
||||
|
||||
EXPR ::=
|
||||
| ADDSUB
|
||||
| OR
|
||||
|
||||
OR ::= AND (or AND)*
|
||||
AND ::= EQNE (and EQNE)*
|
||||
|
||||
EQNE ::= CMP ((eq|ne) CMP)?
|
||||
CMP ::= ADDSUB ((lt|le|gt|ge) ADDSUB)?
|
||||
|
||||
ADDSUB ::= MULDIVMOD ((add|sub) MULDIVMOD)*
|
||||
MULDIVMOD ::= LITERAL ((mul|div|mod) LITERAL)*
|
||||
|
@ -24,6 +29,10 @@ LITERAL ::=
|
|||
| ident
|
||||
| int
|
||||
| CALL
|
||||
| NS
|
||||
| not LITERAL
|
||||
|
||||
CALL ::= ident opar ARGS cpar
|
||||
ARGS ::= (EXPR (comma EXPR)*)?
|
||||
|
||||
NS ::= ident (dot (ident|CALL))+
|
||||
|
|
277
lib/Compiler.cpp
277
lib/Compiler.cpp
|
@ -1,7 +1,10 @@
|
|||
#include "Compiler.hpp"
|
||||
#include <llvm/Support/DynamicLibrary.h>
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/Verifier.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Value.h>
|
||||
#include <llvm/TargetParser/Host.h>
|
||||
#include <llvm/Target/TargetOptions.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
|
@ -12,7 +15,8 @@
|
|||
|
||||
namespace wg
|
||||
{
|
||||
/*explicit*/ Compiler::Compiler()
|
||||
/*explicit*/ Compiler::Compiler(Mod& mod)
|
||||
: m_mod { mod }
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -50,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;
|
||||
|
@ -67,12 +71,127 @@ namespace wg
|
|||
llvm::errs() << "Target machine cannot emit a file of this type";
|
||||
}
|
||||
|
||||
llvm::verifyModule(*m_module);
|
||||
pass.run(*m_module);
|
||||
llvm::verifyModule(m_mod.mod());
|
||||
|
||||
pass.run(m_mod.mod());
|
||||
|
||||
dest.flush();
|
||||
}
|
||||
|
||||
|
||||
void Compiler::execute(std::shared_ptr<Node> node)
|
||||
{
|
||||
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)
|
||||
{
|
||||
switch (node->type())
|
||||
|
@ -94,11 +213,47 @@ namespace wg
|
|||
return nullptr;
|
||||
} break;
|
||||
|
||||
case NODE_DIR: {
|
||||
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))
|
||||
{
|
||||
auto fun = itr->second->mod().getFunction(ident);
|
||||
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();
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_RETURN: {
|
||||
return m_builder->CreateRet(compile(node->child(0)));
|
||||
} break;
|
||||
|
||||
case NODE_EXTERN: {
|
||||
/*case NODE_EXTERN: {
|
||||
auto ident = node->child(0)->repr();
|
||||
auto params = node->child(1);
|
||||
auto ret = node->child(2);
|
||||
|
@ -143,57 +298,17 @@ namespace wg
|
|||
|
||||
m_sym->declare_prototype(ident, fun_type, node->loc());
|
||||
return fun;
|
||||
} break;
|
||||
} break;*/
|
||||
|
||||
case NODE_FUNDECL: {
|
||||
auto ident = node->child(0)->repr();
|
||||
auto params = node->child(1);
|
||||
auto ret = node->child(2);
|
||||
|
||||
std::vector<std::string> names;
|
||||
std::vector<llvm::Type*> types;
|
||||
|
||||
for (size_t i=0; i<params->size(); i++)
|
||||
{
|
||||
auto param = params->child(i);
|
||||
|
||||
if (param->type() == NODE_IDENT)
|
||||
{
|
||||
names.push_back(param->repr());
|
||||
}
|
||||
else if (param->type() == NODE_TYPE)
|
||||
{
|
||||
auto ty = llvm::Type::getInt32Ty(*m_context);
|
||||
|
||||
for (auto name: names)
|
||||
{
|
||||
m_sym->declare(name, ty, node->loc());
|
||||
types.push_back(ty);
|
||||
}
|
||||
|
||||
names.clear();
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Type* ret_type = llvm::Type::getVoidTy(*m_context);
|
||||
auto body = node->child(3);
|
||||
auto fun = m_mod.mod(). getFunction(ident);
|
||||
|
||||
if (ret->size() > 0)
|
||||
{
|
||||
ret_type = llvm::Type::getInt32Ty(*m_context);
|
||||
}
|
||||
|
||||
auto fun_type = llvm::FunctionType::get(ret_type, types, false);
|
||||
auto fun = llvm::Function::Create(fun_type,
|
||||
llvm::Function::ExternalLinkage,
|
||||
ident,
|
||||
*m_module);
|
||||
|
||||
m_sym->declare(ident, fun_type, node->loc());
|
||||
|
||||
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);
|
||||
|
@ -210,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<llvm::Value*> values;
|
||||
|
@ -256,13 +371,71 @@ 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));
|
||||
} break;
|
||||
|
||||
case NODE_BOOL: {
|
||||
return llvm::ConstantInt::getBool(m_mod.context(),
|
||||
node->repr() == "true");
|
||||
} break;
|
||||
|
||||
case NODE_AND: {
|
||||
auto lhs = compile(node->child(0));
|
||||
auto rhs = compile(node->child(1));
|
||||
return m_builder->CreateAnd(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_OR: {
|
||||
auto lhs = compile(node->child(0));
|
||||
auto rhs = compile(node->child(1));
|
||||
return m_builder->CreateOr(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_NOT: {
|
||||
auto lhs = compile(node->child(0));
|
||||
return m_builder->CreateNot(lhs);
|
||||
} break;
|
||||
|
||||
case NODE_EQ: {
|
||||
auto lhs = compile(node->child(0));
|
||||
auto rhs = compile(node->child(1));
|
||||
return m_builder->CreateICmpEQ(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_NE: {
|
||||
auto lhs = compile(node->child(0));
|
||||
auto rhs = compile(node->child(1));
|
||||
return m_builder->CreateICmpNE(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_LT: {
|
||||
auto lhs = compile(node->child(0));
|
||||
auto rhs = compile(node->child(1));
|
||||
return m_builder->CreateICmpSLT(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_LE: {
|
||||
auto lhs = compile(node->child(0));
|
||||
auto rhs = compile(node->child(1));
|
||||
return m_builder->CreateICmpSLE(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_GT: {
|
||||
auto lhs = compile(node->child(0));
|
||||
auto rhs = compile(node->child(1));
|
||||
return m_builder->CreateICmpSGT(lhs, rhs);
|
||||
} break;
|
||||
|
||||
|
||||
case NODE_GE: {
|
||||
auto lhs = compile(node->child(0));
|
||||
auto rhs = compile(node->child(1));
|
||||
return m_builder->CreateICmpSGE(lhs, rhs);
|
||||
} break;
|
||||
|
||||
default:
|
||||
WG_ASSERT(false,
|
||||
std::string()
|
||||
|
|
|
@ -8,29 +8,30 @@
|
|||
#include "commons.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "SymTable.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 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);
|
||||
|
||||
private:
|
||||
std::unique_ptr<llvm::LLVMContext> m_context =
|
||||
std::make_unique<llvm::LLVMContext>();
|
||||
|
||||
Mod& m_mod;
|
||||
std::unordered_map<std::string, std::unique_ptr<Mod>> m_imports;
|
||||
std::unique_ptr<llvm::IRBuilder<>> m_builder =
|
||||
std::make_unique<llvm::IRBuilder<>>(*m_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::make_unique<llvm::IRBuilder<>>(m_mod.context());
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,26 @@ namespace wg
|
|||
{
|
||||
/*explicit*/ Lexer::Lexer()
|
||||
{
|
||||
add_keyword("true", NODE_BOOL, true);
|
||||
add_keyword("false", NODE_BOOL, true);
|
||||
add_keyword("as", NODE_AS);
|
||||
add_keyword("int", NODE_TYPE, true);
|
||||
add_keyword("fun", NODE_FUN);
|
||||
add_keyword("return", NODE_RETURN);
|
||||
add_keyword("extern", NODE_EXTERN);
|
||||
add_keyword("and", NODE_AND);
|
||||
add_keyword("or", NODE_OR);
|
||||
add_keyword("not", NODE_NOT);
|
||||
|
||||
add_text("==", NODE_EQ);
|
||||
add_text("<>", NODE_NE);
|
||||
|
||||
add_text("<", NODE_LT);
|
||||
add_text("<=", NODE_LE);
|
||||
add_text(">", NODE_GT);
|
||||
add_text(">=", NODE_GE);
|
||||
|
||||
add_text(".", NODE_DOT);
|
||||
add_text("{", NODE_OBRACE);
|
||||
add_text("}", NODE_CBRACE);
|
||||
add_text(",", NODE_COMMA);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#include "Mod.hpp"
|
||||
|
||||
namespace wg
|
||||
{
|
||||
/*explicit*/ Mod::Mod(std::string const& name)
|
||||
: m_name { name }
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ Mod::~Mod()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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
|
31
lib/Node.hpp
31
lib/Node.hpp
|
@ -4,20 +4,23 @@
|
|||
#include "commons.hpp"
|
||||
#include "Loc.hpp"
|
||||
|
||||
#define NODE_TYPES(G) \
|
||||
G(NODE_PROG), \
|
||||
G(NODE_IDENT), \
|
||||
G(NODE_HASH), \
|
||||
G(NODE_DIR), \
|
||||
G(NODE_INT), \
|
||||
G(NODE_ADD), G(NODE_SUB), \
|
||||
G(NODE_MUL),G(NODE_DIV), \
|
||||
G(NODE_MOD), G(NODE_OPAR), G(NODE_CPAR), \
|
||||
G(NODE_SEMICOLON), G(NODE_COMMA), G(NODE_CALL), \
|
||||
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)
|
||||
#define NODE_TYPES(G) \
|
||||
G(NODE_PROG), \
|
||||
G(NODE_IDENT), \
|
||||
G(NODE_HASH), \
|
||||
G(NODE_DIR), \
|
||||
G(NODE_INT), \
|
||||
G(NODE_ADD), G(NODE_SUB), \
|
||||
G(NODE_MUL),G(NODE_DIV), \
|
||||
G(NODE_MOD), G(NODE_OPAR), G(NODE_CPAR), \
|
||||
G(NODE_SEMICOLON), G(NODE_COMMA), G(NODE_CALL), \
|
||||
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_AS), G(NODE_BOOL), G(NODE_AND), G(NODE_OR), \
|
||||
G(NODE_NOT), G(NODE_EQ), G(NODE_NE), G(NODE_LT), G(NODE_GT), \
|
||||
G(NODE_LE), G(NODE_GE)
|
||||
|
||||
namespace wg
|
||||
{
|
||||
|
|
110
lib/Parser.cpp
110
lib/Parser.cpp
|
@ -231,12 +231,83 @@ 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;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_expr()
|
||||
{
|
||||
return parse_addsub();
|
||||
return parse_or();
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_or()
|
||||
{
|
||||
auto lhs = parse_and();
|
||||
|
||||
while (type_is(NODE_OR))
|
||||
{
|
||||
auto node = consume();
|
||||
node->add_child(lhs);
|
||||
node->add_child(parse_and());
|
||||
lhs = node;
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_and()
|
||||
{
|
||||
auto lhs = parse_eqne();
|
||||
|
||||
while (type_is(NODE_AND))
|
||||
{
|
||||
auto node = consume();
|
||||
node->add_child(lhs);
|
||||
node->add_child(parse_eqne());
|
||||
lhs = node;
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_eqne()
|
||||
{
|
||||
auto lhs = parse_cmp();
|
||||
|
||||
if (type_is(NODE_EQ)
|
||||
|| type_is(NODE_NE))
|
||||
{
|
||||
auto node = consume();
|
||||
node->add_child(lhs);
|
||||
node->add_child(parse_cmp());
|
||||
lhs = node;
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_cmp()
|
||||
{
|
||||
auto lhs = parse_addsub();
|
||||
|
||||
if (type_is(NODE_LT)
|
||||
|| type_is(NODE_LE)
|
||||
|| type_is(NODE_GT)
|
||||
|| type_is(NODE_GE))
|
||||
{
|
||||
auto node = consume();
|
||||
node->add_child(lhs);
|
||||
node->add_child(parse_addsub());
|
||||
lhs = node;
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_addsub()
|
||||
|
@ -280,7 +351,21 @@ namespace wg
|
|||
return parse_call();
|
||||
}
|
||||
|
||||
if (type_is(NODE_IDENT)
|
||||
&& type_is(NODE_DOT, 1))
|
||||
{
|
||||
return parse_ns();
|
||||
}
|
||||
|
||||
if (type_is(NODE_NOT))
|
||||
{
|
||||
auto node = consume();
|
||||
node->add_child(parse_literal());
|
||||
return node;
|
||||
}
|
||||
|
||||
if (type_is(NODE_INT)
|
||||
|| type_is(NODE_BOOL)
|
||||
|| type_is(NODE_IDENT))
|
||||
{
|
||||
return consume();
|
||||
|
@ -337,4 +422,27 @@ namespace wg
|
|||
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_ns()
|
||||
{
|
||||
auto node = make_node(NODE_NS);
|
||||
node->add_child(consume(NODE_IDENT));
|
||||
|
||||
while (type_is(NODE_DOT))
|
||||
{
|
||||
consume();
|
||||
|
||||
if (type_is(NODE_IDENT)
|
||||
&& type_is(NODE_OPAR, 1))
|
||||
{
|
||||
node->add_child(parse_call());
|
||||
}
|
||||
else
|
||||
{
|
||||
node->add_child(consume(NODE_IDENT));
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,11 @@ namespace wg
|
|||
std::shared_ptr<Node> parse_dir();
|
||||
|
||||
std::shared_ptr<Node> parse_expr();
|
||||
std::shared_ptr<Node> parse_or();
|
||||
std::shared_ptr<Node> parse_and();
|
||||
|
||||
std::shared_ptr<Node> parse_eqne();
|
||||
std::shared_ptr<Node> parse_cmp();
|
||||
|
||||
std::shared_ptr<Node> parse_addsub();
|
||||
std::shared_ptr<Node> parse_muldivmod();
|
||||
|
@ -45,6 +50,8 @@ namespace wg
|
|||
std::shared_ptr<Node> parse_call();
|
||||
std::shared_ptr<Node> parse_args();
|
||||
|
||||
std::shared_ptr<Node> parse_ns();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
13
meson.build
13
meson.build
|
@ -7,6 +7,7 @@ project('wongola',
|
|||
'cpp_std=c++17'
|
||||
])
|
||||
|
||||
|
||||
wongola_lib = static_library(
|
||||
'wongola',
|
||||
sources: [
|
||||
|
@ -16,6 +17,7 @@ wongola_lib = static_library(
|
|||
'lib/Compiler.cpp',
|
||||
'lib/Loc.cpp',
|
||||
'lib/SymTable.cpp',
|
||||
'lib/Mod.cpp',
|
||||
],
|
||||
dependencies: [
|
||||
dependency('LLVM')
|
||||
|
@ -27,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',
|
||||
|
|
11
src/main.cpp
11
src/main.cpp
|
@ -4,6 +4,8 @@
|
|||
#include <Lexer.hpp>
|
||||
#include <Parser.hpp>
|
||||
#include <Compiler.hpp>
|
||||
#include <llvm/Support/DynamicLibrary.h>
|
||||
#include "Mod.hpp"
|
||||
|
||||
std::filesystem::path name_to_obj(std::string const& path)
|
||||
{
|
||||
|
@ -40,8 +42,10 @@ void load(std::string const& path)
|
|||
wg::Parser parser;
|
||||
auto ast = parser.parse(tokens);
|
||||
|
||||
wg::Compiler compiler;
|
||||
compiler.compile(ast);
|
||||
wg::Mod mod {"main"};
|
||||
wg::Compiler compiler {mod};
|
||||
|
||||
compiler.execute(ast);
|
||||
compiler.gen(name_to_obj(path));
|
||||
}
|
||||
|
||||
|
@ -97,8 +101,9 @@ int main(int argc, char** argv)
|
|||
|
||||
std::stringstream ss;
|
||||
ss << "clang++" << " -o " << output_path << " ";
|
||||
ss << objname;
|
||||
|
||||
ss << objname;
|
||||
ss << " -lwongola-std ";
|
||||
system(ss.str().c_str());
|
||||
|
||||
std::filesystem::remove(objname);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#include "io.hpp"
|
||||
#include <iostream>
|
||||
|
||||
extern "C" std::unique_ptr<wg::Mod> lib_io()
|
||||
{
|
||||
auto mod = std::make_unique<wg::Mod>("io");
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef IO_HPP
|
||||
#define IO_HPP
|
||||
#include "../lib/Mod.hpp"
|
||||
|
||||
extern "C" std::unique_ptr<wg::Mod> lib_io();
|
||||
extern "C" int hello(int x);
|
||||
|
||||
#endif
|
|
@ -68,3 +68,46 @@ TEST_CASE_METHOD(LexerTest, "Lexer_fun_call")
|
|||
test_next(lex, "EXTERN");
|
||||
test_end(lex);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_pkg_namespace")
|
||||
{
|
||||
wg::Lexer lex;
|
||||
lex.scan(" . ");
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_bool")
|
||||
{
|
||||
wg::Lexer lex;
|
||||
lex.scan(" true and false or not afalse truea ");
|
||||
test_next(lex, "BOOL[true]");
|
||||
test_next(lex, "AND");
|
||||
test_next(lex, "BOOL[false]");
|
||||
test_next(lex, "OR");
|
||||
test_next(lex, "NOT");
|
||||
test_next(lex, "IDENT[afalse]");
|
||||
test_next(lex, "IDENT[truea]");
|
||||
test_end(lex);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_cmp")
|
||||
{
|
||||
wg::Lexer lex;
|
||||
lex.scan(" == <> < <= > >= ");
|
||||
test_next(lex, "EQ");
|
||||
test_next(lex, "NE");
|
||||
test_next(lex, "LT");
|
||||
test_next(lex, "LE");
|
||||
test_next(lex, "GT");
|
||||
test_next(lex, "GE");
|
||||
test_end(lex);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
@ -90,3 +93,28 @@ TEST_CASE_METHOD(ParserTest, "Parser_fundecl")
|
|||
test_parse("PROG(RETURN(ADD(CALL(IDENT[a],ARGS),INT[1])))",
|
||||
" return a() + 1; ");
|
||||
}
|
||||
|
||||
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(); ");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_bool")
|
||||
{
|
||||
test_parse("PROG(OR(AND(NOT(BOOL[true]),BOOL[false]),BOOL[true]))",
|
||||
" not true and false or true; ");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_comparisons")
|
||||
{
|
||||
test_parse("PROG(AND(EQ(INT[7],INT[3]),LT(INT[3],INT[7])))",
|
||||
" 7 == 3 and 3 < 7; ");
|
||||
|
||||
test_parse("PROG(OR(NE(INT[7],INT[3]),GE(INT[3],INT[7])))",
|
||||
" 7 <> 3 or 3 >= 7; ");
|
||||
}
|
||||
|
|
Reference in New Issue