ADD: basic function3
parent
d72660e6de
commit
620818c42a
|
@ -3,6 +3,7 @@ PROG ::= (INSTR (EOI+ INSTR)*)?
|
|||
INSTR ::= EXPR
|
||||
| assert EXPR
|
||||
| assert_static_fail INSTR
|
||||
| return EXPR
|
||||
| VARDECL
|
||||
| CONSTDECL
|
||||
| ASSIGN
|
||||
|
@ -30,4 +31,14 @@ FACTOR ::= UNOP ((mul | div | mod) UNOP)*
|
|||
UNOP ::= (add | sub | not)? POW
|
||||
POW ::= GROUP (pow GROUP)?
|
||||
GROUP ::= BASE | opar EXPR cpar
|
||||
BASE ::= int | bool | ident
|
||||
BASE ::= int | bool | ident | FUN | CALL
|
||||
|
||||
CALL ::= obrace ident expr* cbrace
|
||||
ARGS ::= expr*
|
||||
|
||||
FUN ::= fun opar PARAMS cpar RET BODY end
|
||||
PARAMS ::= (PARAM (comma PARAM))?
|
||||
PARAM ::= ident (as TYPE)
|
||||
RET ::= arrow TYPE |
|
||||
BODY ::= INSTR*
|
||||
TYPE ::= type | fun lt (type (arrow type)*)? gt
|
||||
|
|
162
lib/Compiler.cpp
162
lib/Compiler.cpp
|
@ -1,5 +1,6 @@
|
|||
#include "Compiler.hpp"
|
||||
#include "lib/Node.hpp"
|
||||
#include "lib/TypeResolver.hpp"
|
||||
#include "lib/opcodes.hpp"
|
||||
#include "StaticPass.hpp"
|
||||
|
||||
|
@ -14,20 +15,64 @@ namespace roza
|
|||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<Program> Compiler::compile(std::shared_ptr<Node> root)
|
||||
std::shared_ptr<Program> Compiler::compile(std::shared_ptr<Node> root,
|
||||
std::shared_ptr<SymTable> sym)
|
||||
{
|
||||
auto program = std::make_shared<Program>();
|
||||
compile_node(root, program);
|
||||
compile_node(root, program, sym);
|
||||
return program;
|
||||
}
|
||||
|
||||
void Compiler::compile_node(std::shared_ptr<Node> root, std::shared_ptr<Program> prog)
|
||||
void Compiler::compile_node(std::shared_ptr<Node> root,
|
||||
std::shared_ptr<Program> prog,
|
||||
std::shared_ptr<SymTable> sym)
|
||||
{
|
||||
switch (root->type())
|
||||
{
|
||||
case NODE_FUN: {
|
||||
auto params = root->child(0);
|
||||
auto ret = root->child(1);
|
||||
auto body = root->child(2);
|
||||
|
||||
TypeResolver resolver {m_log};
|
||||
auto ty = resolver.find(root, *sym);
|
||||
auto fun = std::make_shared<Fun>(ty);
|
||||
|
||||
for (size_t i=0; i<params->size(); i++)
|
||||
{
|
||||
auto param = params->child(i);
|
||||
std::string name = param->child(0)->repr();
|
||||
auto node = param->child(1);
|
||||
|
||||
fun->sym()->declare_mut(name, node);
|
||||
}
|
||||
|
||||
m_fun_stack.push_back(fun);
|
||||
compile_node(body, fun->program(), fun->sym());
|
||||
m_fun_stack.pop_back();
|
||||
|
||||
auto value = std::make_shared<Value>(fun, root->loc());
|
||||
prog->push_instr(OP_PUSH_CONST, prog->push_value(value));
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_RETURN: {
|
||||
compile_node(root->child(0), prog, sym);
|
||||
prog->push_instr(OP_RET);
|
||||
} break;
|
||||
|
||||
case NODE_CALL: {
|
||||
auto fun_addr = sym->find(root->child(0)->repr()).addr;
|
||||
prog->push_instr(OP_PUSH_CONST, fun_addr);
|
||||
|
||||
compile_children(root->child(1), prog, sym);
|
||||
|
||||
prog->push_instr(OP_CALL, root->child(1)->size());
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_IF: {
|
||||
m_sym.enter_scope();
|
||||
sym->enter_scope();
|
||||
|
||||
std::vector<size_t> to_end;
|
||||
|
||||
|
@ -36,11 +81,11 @@ namespace roza
|
|||
auto cond = n->child(0);
|
||||
auto then = n->child(1);
|
||||
|
||||
compile_node(cond, prog);
|
||||
compile_node(cond, prog, sym);
|
||||
size_t cond_addr = prog->size();
|
||||
prog->push_instr(OP_BRF, 0);
|
||||
|
||||
compile_node(then, prog);
|
||||
compile_node(then, prog, sym);
|
||||
|
||||
to_end.push_back(prog->size());
|
||||
prog->push_instr(OP_BR, 0);
|
||||
|
@ -50,7 +95,7 @@ namespace roza
|
|||
if (n->size() > 2)
|
||||
{
|
||||
auto next = n->child(2);
|
||||
compile_node(next, prog);
|
||||
compile_node(next, prog, sym);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -61,17 +106,18 @@ namespace roza
|
|||
prog->set_param(addr, prog->size());
|
||||
}
|
||||
|
||||
m_sym.leave_scope();
|
||||
sym->leave_scope();
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_BODY:
|
||||
case NODE_ELSE:
|
||||
case NODE_THEN: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
} break;
|
||||
|
||||
case NODE_ASSERT: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_ASSERT);
|
||||
} break;
|
||||
|
||||
|
@ -80,10 +126,10 @@ namespace roza
|
|||
|
||||
try
|
||||
{
|
||||
StaticPass static_pass {m_log, m_sym};
|
||||
StaticPass static_pass {m_log, *sym};
|
||||
static_pass.check_children(root);
|
||||
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
|
||||
failed = true;
|
||||
}
|
||||
|
@ -99,30 +145,64 @@ namespace roza
|
|||
} break;
|
||||
|
||||
case NODE_IDENT: {
|
||||
SymEntry const& entry = m_sym.find(root->repr());
|
||||
SymEntry const& entry = sym->find(root->repr());
|
||||
|
||||
if (m_fun_stack.empty())
|
||||
{
|
||||
prog->push_instr(OP_LOAD_GLOBAL, entry.addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
prog->push_instr(OP_LOAD_LOCAL, entry.addr);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_VARDECL: {
|
||||
std::string name = root->child(0)->repr();
|
||||
compile_node(root->child(1), prog);
|
||||
int addr = m_sym.declare_mut(name, root->child(1));
|
||||
compile_node(root->child(1), prog, sym);
|
||||
int addr = sym->declare_mut(name, root->child(1));
|
||||
|
||||
if (m_fun_stack.empty())
|
||||
{
|
||||
prog->push_instr(OP_STORE_GLOBAL, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
prog->push_instr(OP_STORE_LOCAL, addr);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_CONSTDECL: {
|
||||
std::string name = root->child(0)->repr();
|
||||
compile_node(root->child(1), prog);
|
||||
int addr = m_sym.declare(name, root->child(1));
|
||||
compile_node(root->child(1), prog, sym);
|
||||
int addr = sym->declare(name, root->child(1));
|
||||
|
||||
if (m_fun_stack.empty())
|
||||
{
|
||||
prog->push_instr(OP_STORE_GLOBAL, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
prog->push_instr(OP_STORE_LOCAL, addr);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_ASSIGN: {
|
||||
int addr = m_sym.find(root->child(0)->repr()).addr;
|
||||
compile_node(root->child(1), prog);
|
||||
int addr = sym->find(root->child(0)->repr()).addr;
|
||||
compile_node(root->child(1), prog, sym);
|
||||
|
||||
if (m_fun_stack.empty())
|
||||
{
|
||||
prog->push_instr(OP_STORE_GLOBAL, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
prog->push_instr(OP_STORE_LOCAL, addr);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_INT: {
|
||||
|
@ -136,100 +216,100 @@ namespace roza
|
|||
} break;
|
||||
|
||||
case NODE_EQ: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_EQ);
|
||||
} break;
|
||||
|
||||
case NODE_NE: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_EQ);
|
||||
prog->push_instr(OP_NOT);
|
||||
} break;
|
||||
|
||||
case NODE_LT: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_ILT);
|
||||
} break;
|
||||
|
||||
case NODE_GT: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IGT);
|
||||
} break;
|
||||
|
||||
case NODE_LE: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IGT);
|
||||
prog->push_instr(OP_NOT);
|
||||
} break;
|
||||
|
||||
case NODE_GE: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_ILT);
|
||||
prog->push_instr(OP_NOT);
|
||||
} break;
|
||||
|
||||
case NODE_IMP: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IMP);
|
||||
} break;
|
||||
|
||||
case NODE_AND: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_AND);
|
||||
} break;
|
||||
|
||||
case NODE_OR: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_OR);
|
||||
} break;
|
||||
|
||||
case NODE_NOT: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_NOT);
|
||||
} break;
|
||||
|
||||
case NODE_ADD: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IADD);
|
||||
} break;
|
||||
|
||||
case NODE_SUB: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_ISUB);
|
||||
} break;
|
||||
|
||||
case NODE_MUL: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IMUL);
|
||||
} break;
|
||||
|
||||
case NODE_DIV: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IDIV);
|
||||
} break;
|
||||
|
||||
case NODE_MOD: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IMOD);
|
||||
} break;
|
||||
|
||||
case NODE_POW: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IPOW);
|
||||
} break;
|
||||
|
||||
case NODE_UADD: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IUADD);
|
||||
} break;
|
||||
|
||||
case NODE_USUB: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
prog->push_instr(OP_IUSUB);
|
||||
} break;
|
||||
|
||||
case NODE_PROG: {
|
||||
compile_children(root, prog);
|
||||
compile_children(root, prog, sym);
|
||||
} break;
|
||||
|
||||
default:
|
||||
|
@ -237,11 +317,13 @@ namespace roza
|
|||
}
|
||||
}
|
||||
|
||||
void Compiler::compile_children(std::shared_ptr<Node> root, std::shared_ptr<Program> prog)
|
||||
void Compiler::compile_children(std::shared_ptr<Node> root,
|
||||
std::shared_ptr<Program> prog,
|
||||
std::shared_ptr<SymTable> sym)
|
||||
{
|
||||
for (size_t i=0; i<root->size(); i++)
|
||||
{
|
||||
compile_node(root->child(i), prog);
|
||||
compile_node(root->child(i), prog, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "opcodes.hpp"
|
||||
#include "StatusLog.hpp"
|
||||
#include "SymTable.hpp"
|
||||
#include "Fun.hpp"
|
||||
|
||||
namespace roza
|
||||
{
|
||||
|
@ -16,13 +17,20 @@ namespace roza
|
|||
explicit Compiler(StatusLog& log);
|
||||
virtual ~Compiler();
|
||||
|
||||
std::shared_ptr<Program> compile(std::shared_ptr<Node> root);
|
||||
void compile_node(std::shared_ptr<Node> root, std::shared_ptr<Program> prog);
|
||||
void compile_children(std::shared_ptr<Node> root, std::shared_ptr<Program> prog);
|
||||
std::shared_ptr<Program> compile(std::shared_ptr<Node> root,
|
||||
std::shared_ptr<SymTable> sym);
|
||||
|
||||
void compile_node(std::shared_ptr<Node> root,
|
||||
std::shared_ptr<Program> prog,
|
||||
std::shared_ptr<SymTable> sym);
|
||||
|
||||
void compile_children(std::shared_ptr<Node> root,
|
||||
std::shared_ptr<Program> prog,
|
||||
std::shared_ptr<SymTable> sym);
|
||||
|
||||
private:
|
||||
StatusLog& m_log;
|
||||
SymTable m_sym;
|
||||
std::vector<std::shared_ptr<Fun>> m_fun_stack;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#include "Fun.hpp"
|
||||
|
||||
namespace roza
|
||||
{
|
||||
/*explicit*/ Fun::Fun(std::shared_ptr<Type> type)
|
||||
: m_type { type }
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ Fun::~Fun()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef roza_FUN_HPP
|
||||
#define roza_FUN_HPP
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "FunTy.hpp"
|
||||
#include "Program.hpp"
|
||||
#include "SymTable.hpp"
|
||||
|
||||
namespace roza
|
||||
{
|
||||
class Fun
|
||||
{
|
||||
public:
|
||||
explicit Fun(std::shared_ptr<Type> type);
|
||||
virtual ~Fun();
|
||||
|
||||
std::shared_ptr<Type> type() const { return m_type; }
|
||||
std::shared_ptr<SymTable> sym() const { return m_sym; }
|
||||
std::shared_ptr<Program> program() const { return m_program; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Type> m_type;
|
||||
std::shared_ptr<Program> m_program = std::make_shared<Program>();
|
||||
std::shared_ptr<SymTable> m_sym = std::make_shared<SymTable>();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,61 @@
|
|||
#include "FunTy.hpp"
|
||||
|
||||
namespace roza
|
||||
{
|
||||
/*explicit*/ FunTy::FunTy()
|
||||
: Type(TY_FUN)
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ FunTy::~FunTy()
|
||||
{
|
||||
}
|
||||
|
||||
void FunTy::add_input(std::shared_ptr<Type> ty)
|
||||
{
|
||||
m_inputs.push_back(ty);
|
||||
}
|
||||
|
||||
void FunTy::set_output(std::shared_ptr<Type> ty)
|
||||
{
|
||||
m_output = ty;
|
||||
}
|
||||
|
||||
std::string FunTy::string() const /*override*/
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "FUN";
|
||||
ss << "<";
|
||||
|
||||
if (m_inputs.empty() && m_output->base() == TY_NIL)
|
||||
{
|
||||
ss << ">";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string sep;
|
||||
|
||||
for (auto ty: m_inputs)
|
||||
{
|
||||
ss << sep << ty->string();
|
||||
sep = " -> ";
|
||||
}
|
||||
|
||||
ss << " -> " << m_output->string();
|
||||
|
||||
ss << ">";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool FunTy::equals(BaseType base_type) const /*override*/
|
||||
{
|
||||
return base_type == TY_FUN;
|
||||
}
|
||||
|
||||
bool FunTy::equals(Type const&) const /*override*/
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef roza_FUNTY_HPP
|
||||
#define roza_FUNTY_HPP
|
||||
|
||||
#include "Type.hpp"
|
||||
|
||||
namespace roza
|
||||
{
|
||||
class FunTy: public Type
|
||||
{
|
||||
public:
|
||||
explicit FunTy();
|
||||
virtual ~FunTy();
|
||||
|
||||
std::shared_ptr<Type> get_output() const { return m_output; }
|
||||
|
||||
void add_input(std::shared_ptr<Type> ty);
|
||||
void set_output(std::shared_ptr<Type> ty);
|
||||
|
||||
std::string string() const override;
|
||||
bool equals(BaseType rhs) const override;
|
||||
bool equals(Type const& rhs) const override;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Type>> m_inputs;
|
||||
std::shared_ptr<Type> m_output = std::make_shared<Type>(TY_NIL);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -8,7 +8,9 @@ namespace roza
|
|||
, m_loc { loc }
|
||||
{
|
||||
std::vector<std::tuple<std::string, NodeType, bool>> texts = {
|
||||
{"->", NODE_ARROW, false},
|
||||
{";", NODE_EOI, false},
|
||||
{",", NODE_COMMA, false},
|
||||
{"==", NODE_EQ, false},
|
||||
{"!=", NODE_NE, false},
|
||||
{"<=", NODE_LE, false},
|
||||
|
@ -24,10 +26,18 @@ namespace roza
|
|||
{"^", NODE_POW, false},
|
||||
{"(", NODE_OPAR, false},
|
||||
{")", NODE_CPAR, false},
|
||||
{"{", NODE_OBRACE, false},
|
||||
{"}", NODE_CBRACE, false},
|
||||
{"=", NODE_ASSIGN, false},
|
||||
};
|
||||
|
||||
std::vector<std::tuple<std::string, NodeType, bool>> keywords = {
|
||||
{"return", NODE_RETURN, true},
|
||||
{"int", NODE_TYPE, true},
|
||||
{"bool", NODE_TYPE, true},
|
||||
{"nil", NODE_TYPE, true},
|
||||
{"fun", NODE_FUN, false},
|
||||
{"as", NODE_AS, false},
|
||||
{"if", NODE_IF, false},
|
||||
{"else", NODE_ELSE, false},
|
||||
{"end", NODE_END, false},
|
||||
|
|
|
@ -14,7 +14,10 @@
|
|||
G(NODE_GE), G(NODE_ASSERT), G(NODE_ASSERT_STATIC_FAIL), \
|
||||
G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_LET), G(NODE_LET_MUT), \
|
||||
G(NODE_VARDECL), G(NODE_CONSTDECL), G(NODE_IF), G(NODE_ELSE), \
|
||||
G(NODE_THEN), G(NODE_END)
|
||||
G(NODE_THEN), G(NODE_END), G(NODE_FUN), G(NODE_AS), G(NODE_TYPE), \
|
||||
G(NODE_PARAMS), G(NODE_RET), G(NODE_BODY), G(NODE_ARROW), \
|
||||
G(NODE_COMMA), G(NODE_PARAM), G(NODE_RETURN), G(NODE_OBRACE), \
|
||||
G(NODE_CBRACE), G(NODE_CALL), G(NODE_ARGS)
|
||||
|
||||
namespace roza
|
||||
{
|
||||
|
|
141
lib/Parser.cpp
141
lib/Parser.cpp
|
@ -141,6 +141,13 @@ namespace roza
|
|||
root->add_child(parse_instr());
|
||||
return root;
|
||||
}
|
||||
else if (type_is(NODE_RETURN))
|
||||
{
|
||||
auto root = consume();
|
||||
root->add_child(parse_expr());
|
||||
ensure(NODE_EOI);
|
||||
return root;
|
||||
}
|
||||
else if (type_is(NODE_LET))
|
||||
{
|
||||
auto root = parse_constdecl();
|
||||
|
@ -453,6 +460,16 @@ namespace roza
|
|||
return consume();
|
||||
}
|
||||
|
||||
if (type_is(NODE_FUN))
|
||||
{
|
||||
return parse_fun();
|
||||
}
|
||||
|
||||
if (type_is(NODE_OBRACE))
|
||||
{
|
||||
return parse_call();
|
||||
}
|
||||
|
||||
m_log.fatal(node()->loc(),
|
||||
"cannot parse unknown node '"
|
||||
+ node()->string()
|
||||
|
@ -461,9 +478,133 @@ namespace roza
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_call()
|
||||
{
|
||||
auto root = std::make_shared<Node>(NODE_CALL, "", node()->loc());
|
||||
consume(NODE_OBRACE);
|
||||
root->add_child(consume(NODE_IDENT));
|
||||
root->add_child(parse_args());
|
||||
consume(NODE_CBRACE);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_args()
|
||||
{
|
||||
auto root = std::make_shared<Node>(NODE_ARGS, "", node()->loc());
|
||||
|
||||
while (!type_is(NODE_CBRACE))
|
||||
{
|
||||
root->add_child(parse_expr());
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_int()
|
||||
{
|
||||
auto root = consume(NODE_INT);
|
||||
return root;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_fun()
|
||||
{
|
||||
auto root = consume(NODE_FUN);
|
||||
consume(NODE_OPAR);
|
||||
root->add_child(parse_params());
|
||||
consume(NODE_CPAR);
|
||||
|
||||
root->add_child(parse_ret());
|
||||
root->add_child(parse_body());
|
||||
|
||||
consume(NODE_END);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_params()
|
||||
{
|
||||
auto root = std::make_shared<Node>(NODE_PARAMS, "", m_lexer.loc());
|
||||
|
||||
if (type_is(NODE_CPAR))
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
root->add_child(parse_param());
|
||||
|
||||
while (type_is(NODE_COMMA))
|
||||
{
|
||||
consume();
|
||||
root->add_child(parse_param());
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_param()
|
||||
{
|
||||
auto root = std::make_shared<Node>(NODE_PARAM, "", m_lexer.loc());
|
||||
root->add_child(consume(NODE_IDENT));
|
||||
|
||||
if(type_is(NODE_AS))
|
||||
{
|
||||
consume();
|
||||
root->add_child(parse_type());
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_ret()
|
||||
{
|
||||
auto root = std::make_shared<Node>(NODE_RET, "", m_lexer.loc());
|
||||
|
||||
if (type_is(NODE_ARROW))
|
||||
{
|
||||
consume();
|
||||
root->add_child(parse_type());
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_body()
|
||||
{
|
||||
auto root = std::make_shared<Node>(NODE_BODY, "", m_lexer.loc());
|
||||
|
||||
while (!type_is(NODE_END))
|
||||
{
|
||||
root->add_child(parse_instr());
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_type()
|
||||
{
|
||||
if (type_is(NODE_FUN))
|
||||
{
|
||||
auto root = std::make_shared<Node>(NODE_TYPE, "fun", node()->loc());
|
||||
consume();
|
||||
|
||||
consume(NODE_LT);
|
||||
|
||||
while (!type_is(NODE_GT))
|
||||
{
|
||||
root->add_child(parse_type());
|
||||
|
||||
if (type_is(NODE_ARROW))
|
||||
{
|
||||
consume();
|
||||
}
|
||||
}
|
||||
|
||||
consume(NODE_GT);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
return consume(NODE_TYPE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,15 @@ namespace roza
|
|||
std::shared_ptr<Node> parse_pow();
|
||||
std::shared_ptr<Node> parse_group();
|
||||
std::shared_ptr<Node> parse_base();
|
||||
std::shared_ptr<Node> parse_call();
|
||||
std::shared_ptr<Node> parse_args();
|
||||
std::shared_ptr<Node> parse_int();
|
||||
std::shared_ptr<Node> parse_fun();
|
||||
std::shared_ptr<Node> parse_params();
|
||||
std::shared_ptr<Node> parse_param();
|
||||
std::shared_ptr<Node> parse_ret();
|
||||
std::shared_ptr<Node> parse_body();
|
||||
std::shared_ptr<Node> parse_type();
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,6 +26,66 @@ namespace roza
|
|||
|
||||
switch (root->type())
|
||||
{
|
||||
case NODE_FUN: {
|
||||
//SymTable fun_sym;
|
||||
//StaticPass pass {m_log, fun_sym};
|
||||
m_sym.enter_scope();
|
||||
auto params = root->child(0);
|
||||
|
||||
for (size_t i=0; i<params->size(); i++)
|
||||
{
|
||||
auto name = params->child(i)->child(0)->repr();
|
||||
auto node = params->child(i)->child(1);
|
||||
|
||||
m_sym.declare_mut(name, node);
|
||||
}
|
||||
|
||||
m_outer_fun_ret = root->child(1)->child(0);
|
||||
check(root->child(2)->child(0));
|
||||
m_outer_fun_ret = nullptr;
|
||||
m_sym.leave_scope();
|
||||
} break;
|
||||
|
||||
case NODE_RETURN: {
|
||||
check_children(root);
|
||||
|
||||
auto actual_ty = resolver.find(root->child(0), m_sym);
|
||||
auto fun_ty = resolver.find(m_outer_fun_ret, m_sym);
|
||||
|
||||
check_types(root, fun_ty, actual_ty);
|
||||
} break;
|
||||
|
||||
case NODE_CALL: {
|
||||
check_children(root);
|
||||
|
||||
std::string fname = root->child(0)->repr();
|
||||
auto args = root->child(1);
|
||||
auto entry = m_sym.find(fname);
|
||||
auto params = entry.node->child(0);
|
||||
|
||||
if (args->size() != params->size())
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "function '"<< fname << "' expects " << params->size();
|
||||
ss << " arguments,";
|
||||
ss << " got " << args->size();
|
||||
|
||||
m_log.fatal(root->loc(), ss.str());
|
||||
}
|
||||
|
||||
for (size_t i=0; i<args->size(); i++)
|
||||
{
|
||||
auto arg = args->child(i);
|
||||
auto param = params->child(i);
|
||||
|
||||
auto arg_ty = resolver.find(arg, m_sym);
|
||||
auto param_ty = resolver.find(param->child(1), m_sym);
|
||||
|
||||
check_types(root, param_ty, arg_ty);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_IF: {
|
||||
m_sym.enter_scope();
|
||||
auto cond_type = resolver.find(root->child(0), m_sym);
|
||||
|
@ -34,6 +94,7 @@ namespace roza
|
|||
m_sym.leave_scope();
|
||||
} break;
|
||||
|
||||
case NODE_ARGS:
|
||||
case NODE_THEN:
|
||||
case NODE_ELSE: {
|
||||
check_children(root);
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace roza
|
|||
private:
|
||||
StatusLog& m_log;
|
||||
SymTable m_sym;
|
||||
std::shared_ptr<Node> m_outer_fun_ret;
|
||||
|
||||
void check_types(std::shared_ptr<Node> root,
|
||||
std::shared_ptr<Type> lhs,
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace roza
|
||||
{
|
||||
/*static*/ int SymTable::addr = 0;
|
||||
|
||||
/*explicit*/ SymTable::SymTable()
|
||||
{
|
||||
}
|
||||
|
@ -48,13 +46,13 @@ namespace roza
|
|||
|
||||
m_entries.push_back(SymEntry {
|
||||
name,
|
||||
SymTable::addr++,
|
||||
m_addr++,
|
||||
m_scope,
|
||||
node,
|
||||
false
|
||||
});
|
||||
|
||||
return SymTable::addr - 1;
|
||||
return m_addr - 1;
|
||||
}
|
||||
|
||||
int SymTable::declare_mut(std::string const& name, std::shared_ptr<Node> node)
|
||||
|
@ -137,4 +135,16 @@ namespace roza
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string SymTable::string() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
for (size_t i=0; i<m_entries.size(); i++)
|
||||
{
|
||||
ss << m_entries[i].addr << "\t" << m_entries[i].name << std::endl;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,8 +34,10 @@ namespace roza
|
|||
bool exists(std::string const& name) const;
|
||||
bool exists_in_scope(std::string const& name) const;
|
||||
|
||||
std::string string() const;
|
||||
|
||||
private:
|
||||
static int addr;
|
||||
int m_addr = 0;
|
||||
std::vector<SymEntry> m_entries;
|
||||
int m_scope = 0;
|
||||
};
|
||||
|
|
|
@ -11,18 +11,18 @@ namespace roza
|
|||
{
|
||||
}
|
||||
|
||||
std::string Type::string() const
|
||||
/*virtual*/ std::string Type::string() const
|
||||
{
|
||||
return std::string(BaseTypeStr[m_base])
|
||||
.substr(std::string("TY_").size());
|
||||
}
|
||||
|
||||
bool Type::equals(BaseType rhs) const
|
||||
/*virtual*/ bool Type::equals(BaseType rhs) const
|
||||
{
|
||||
return m_base == rhs;
|
||||
}
|
||||
|
||||
bool Type::equals(Type const& rhs) const
|
||||
/*virtual*/ bool Type::equals(Type const& rhs) const
|
||||
{
|
||||
return m_base == rhs.m_base;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "commons.hpp"
|
||||
|
||||
#define BASE_TYPE(G) \
|
||||
G(TY_INT), G(TY_BOOL)
|
||||
G(TY_INT), G(TY_BOOL), G(TY_FUN), G(TY_NIL)
|
||||
|
||||
namespace roza
|
||||
{
|
||||
|
@ -18,10 +18,10 @@ namespace roza
|
|||
|
||||
BaseType base() const { return m_base; }
|
||||
|
||||
std::string string() const;
|
||||
virtual std::string string() const;
|
||||
|
||||
bool equals(BaseType rhs) const;
|
||||
bool equals(Type const& rhs) const;
|
||||
virtual bool equals(BaseType rhs) const;
|
||||
virtual bool equals(Type const& rhs) const;
|
||||
|
||||
private:
|
||||
BaseType m_base;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "TypeResolver.hpp"
|
||||
#include "FunTy.hpp"
|
||||
|
||||
namespace roza
|
||||
{
|
||||
|
@ -20,6 +21,61 @@ namespace roza
|
|||
return find(root->child(root->size() - 1), sym);
|
||||
} break;
|
||||
|
||||
case NODE_CALL: {
|
||||
auto fun = sym.find(root->child(0)->repr()).node;
|
||||
return find(fun->child(1), sym);
|
||||
} break;
|
||||
|
||||
case NODE_RET: {
|
||||
return find(root->child(0), sym);
|
||||
} break;
|
||||
|
||||
case NODE_FUN: {
|
||||
auto params = root->child(0);
|
||||
auto ret = root->child(1);
|
||||
auto ty = std::make_shared<FunTy>();
|
||||
|
||||
for (size_t i=0; i<params->size(); i++)
|
||||
{
|
||||
ty->add_input(find(params->child(i)->child(1), sym));
|
||||
}
|
||||
|
||||
if (ret->size() > 0)
|
||||
{
|
||||
ty->set_output(find(ret->child(0), sym));
|
||||
}
|
||||
|
||||
return ty;
|
||||
} break;
|
||||
|
||||
case NODE_TYPE: {
|
||||
if (root->repr() == "nil") { return std::make_shared<Type>(TY_NIL); }
|
||||
if (root->repr() == "int") { return std::make_shared<Type>(TY_INT); }
|
||||
if (root->repr() == "bool") { return std::make_shared<Type>(TY_BOOL); }
|
||||
|
||||
if (root->repr() == "fun")
|
||||
{
|
||||
auto ty = std::make_shared<FunTy>();
|
||||
|
||||
if (root->size() > 0)
|
||||
{
|
||||
for (size_t i=0; i<root->size() - 1; i++)
|
||||
{
|
||||
ty->add_input(find(root->child(i), sym));
|
||||
}
|
||||
}
|
||||
|
||||
if (root->size() > 0)
|
||||
{
|
||||
ty->set_output(find(root->child(root->size()-1), sym));
|
||||
}
|
||||
|
||||
return ty;
|
||||
}
|
||||
|
||||
m_log.fatal(root->loc(), "cannot find type of '" + root->repr() + "'");
|
||||
} break;
|
||||
|
||||
case NODE_IDENT: {
|
||||
std::string name = root->repr();
|
||||
SymEntry const& entry = sym.find(name);
|
||||
|
|
98
lib/VM.cpp
98
lib/VM.cpp
|
@ -1,10 +1,12 @@
|
|||
#include "VM.hpp"
|
||||
#include "lib/opcodes.hpp"
|
||||
#include "Fun.hpp"
|
||||
|
||||
namespace roza
|
||||
{
|
||||
/*explicit*/ VM::VM(StatusLog& log)
|
||||
: m_log { log }
|
||||
, m_sp { 0 }
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -20,6 +22,76 @@ namespace roza
|
|||
switch (program->opcode(m_pc))
|
||||
{
|
||||
|
||||
case OP_CALL: {
|
||||
size_t arity = *program->param(m_pc);
|
||||
|
||||
std::vector<param_t> args;
|
||||
|
||||
for (size_t i=0; i<arity; i++)
|
||||
{
|
||||
param_t val = pop();
|
||||
args.insert(std::begin(args), val);
|
||||
}
|
||||
|
||||
auto fun = program->value(pop())->as_fun();
|
||||
|
||||
var_map vars;
|
||||
|
||||
for (size_t i=0; i<args.size(); i++)
|
||||
{
|
||||
if (program->has_value(args[i]))
|
||||
{
|
||||
vars.insert({i, program->value(args[i])});
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare
|
||||
Frame frame {
|
||||
vars,
|
||||
m_pc,
|
||||
m_sp,
|
||||
m_bp
|
||||
};
|
||||
|
||||
m_frames.push_back(frame);
|
||||
|
||||
m_pc = 0;
|
||||
m_bp = m_sp;
|
||||
|
||||
// Execute
|
||||
exec(fun->program());
|
||||
|
||||
// Clear
|
||||
size_t sz = m_sp - m_bp;
|
||||
|
||||
std::vector<param_t> rets;
|
||||
|
||||
for (size_t i=0; i<sz; i++)
|
||||
{
|
||||
rets.insert(rets.begin(), pop());
|
||||
}
|
||||
|
||||
// Restore
|
||||
m_pc = m_frames.back().pc;
|
||||
m_sp = m_frames.back().sp;
|
||||
m_bp = m_frames.back().bp;
|
||||
|
||||
auto ty = std::static_pointer_cast<FunTy>(fun->type());
|
||||
|
||||
if (ty->get_output()->base() != TY_NIL)
|
||||
{
|
||||
push(program->push_value(fun->program()->value(rets.back())));
|
||||
}
|
||||
|
||||
m_frames.pop_back();
|
||||
m_pc++;
|
||||
|
||||
} break;
|
||||
|
||||
case OP_RET: {
|
||||
m_pc = program->size();
|
||||
} break;
|
||||
|
||||
case OP_BRF: {
|
||||
auto value = program->value(pop());
|
||||
|
||||
|
@ -54,6 +126,23 @@ namespace roza
|
|||
m_pc++;
|
||||
} break;
|
||||
|
||||
case OP_LOAD_LOCAL: {
|
||||
int addr = *program->param(m_pc);
|
||||
auto value = m_frames.back().locals[addr];
|
||||
push(program->push_value(value));
|
||||
|
||||
m_pc++;
|
||||
} break;
|
||||
|
||||
case OP_STORE_LOCAL: {
|
||||
auto value = program->value(pop());
|
||||
int addr = *program->param(m_pc);
|
||||
|
||||
m_frames.back().locals[addr] = value;
|
||||
|
||||
m_pc++;
|
||||
} break;
|
||||
|
||||
case OP_ASSERT: {
|
||||
auto value = program->value(pop());
|
||||
|
||||
|
@ -199,7 +288,7 @@ namespace roza
|
|||
{
|
||||
std::stringstream ss;
|
||||
|
||||
for (size_t i=0; i<m_stack.size(); i++)
|
||||
for (size_t i=0; i<m_sp; i++)
|
||||
{
|
||||
ss << i << "\t";
|
||||
|
||||
|
@ -222,15 +311,16 @@ namespace roza
|
|||
|
||||
void VM::push(param_t param)
|
||||
{
|
||||
m_stack.push_back(param);
|
||||
m_stack[m_sp] = param;
|
||||
m_sp++;
|
||||
}
|
||||
|
||||
param_t VM::pop()
|
||||
{
|
||||
assert(m_stack.size() > 0);
|
||||
|
||||
param_t res = m_stack.back();
|
||||
m_stack.pop_back();
|
||||
param_t res = m_stack[m_sp - 1];
|
||||
m_sp--;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
17
lib/VM.hpp
17
lib/VM.hpp
|
@ -14,6 +14,15 @@ namespace roza
|
|||
(std::shared_ptr<Value>,
|
||||
std::shared_ptr<Value>)>;
|
||||
|
||||
using var_map = std::unordered_map<int, std::shared_ptr<Value>>;
|
||||
|
||||
struct Frame {
|
||||
var_map locals;
|
||||
size_t pc;
|
||||
size_t sp;
|
||||
size_t bp;
|
||||
};
|
||||
|
||||
class VM
|
||||
{
|
||||
public:
|
||||
|
@ -25,13 +34,17 @@ namespace roza
|
|||
|
||||
private:
|
||||
StatusLog& m_log;
|
||||
std::vector<param_t> m_stack;
|
||||
std::array<param_t, 4096> m_stack;
|
||||
std::shared_ptr<Program> m_last_program;
|
||||
std::unordered_map<int, std::shared_ptr<Value>> m_globals;
|
||||
var_map m_globals;
|
||||
std::vector<Frame> m_frames;
|
||||
size_t m_sp = 0;
|
||||
size_t m_bp = 0;
|
||||
size_t m_pc = 0;
|
||||
|
||||
void push(param_t param);
|
||||
param_t pop();
|
||||
|
||||
void apply_binop(std::shared_ptr<Program> program, binop_t op);
|
||||
void apply_unop(std::shared_ptr<Program> program, unop_t op);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "Value.hpp"
|
||||
#include "Fun.hpp"
|
||||
|
||||
namespace roza
|
||||
{
|
||||
|
@ -16,6 +17,13 @@ namespace roza
|
|||
{
|
||||
}
|
||||
|
||||
/*explicit*/ Value::Value(std::shared_ptr<Fun> value, SrcLoc loc)
|
||||
: m_type { value->type() }
|
||||
, m_fun_val { value }
|
||||
, m_loc { loc }
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ Value::~Value()
|
||||
{
|
||||
}
|
||||
|
@ -32,6 +40,11 @@ namespace roza
|
|||
return m_bool_val ? "true" : "false";
|
||||
}
|
||||
|
||||
if (m_type->equals(TY_FUN))
|
||||
{
|
||||
return "function: " + m_fun_val->type()->string();
|
||||
}
|
||||
|
||||
assert("cannot stringify unknown value " && 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,17 +7,21 @@
|
|||
|
||||
namespace roza
|
||||
{
|
||||
class Fun;
|
||||
|
||||
class Value
|
||||
{
|
||||
public:
|
||||
explicit Value(int value, SrcLoc loc);
|
||||
explicit Value(bool value, SrcLoc loc);
|
||||
explicit Value(std::shared_ptr<Fun> value, SrcLoc loc);
|
||||
virtual ~Value();
|
||||
|
||||
SrcLoc loc() const { return m_loc; }
|
||||
|
||||
int as_int() const { return m_int_val; }
|
||||
bool as_bool() const { return m_bool_val; }
|
||||
std::shared_ptr<Fun> as_fun() const { return m_fun_val; }
|
||||
|
||||
std::shared_ptr<Type> type() const { return m_type; }
|
||||
std::string string() const;
|
||||
|
@ -27,7 +31,10 @@ namespace roza
|
|||
std::shared_ptr<Type> m_type;
|
||||
int m_int_val;
|
||||
bool m_bool_val;
|
||||
std::shared_ptr<Fun> m_fun_val;
|
||||
|
||||
SrcLoc m_loc;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include "mutils.hpp"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
G(OP_IADD), G(OP_ISUB), G(OP_IMUL), G(OP_IDIV), G(OP_IMOD), G(OP_IPOW), \
|
||||
G(OP_MOD), G(OP_IUADD), G(OP_IUSUB), G(OP_AND), G(OP_OR), G(OP_NOT), \
|
||||
G(OP_IMP), G(OP_EQ), G(OP_ILT), G(OP_IGT), G(OP_ASSERT), G(OP_STORE_GLOBAL), \
|
||||
G(OP_LOAD_GLOBAL), G(OP_BRF), G(OP_BR)
|
||||
G(OP_LOAD_GLOBAL), G(OP_BRF), G(OP_BR), G(OP_RET), G(OP_CALL), \
|
||||
G(OP_LOAD_LOCAL), G(OP_STORE_LOCAL)
|
||||
|
||||
namespace roza
|
||||
{
|
||||
|
|
|
@ -23,6 +23,8 @@ roza_lib = static_library(
|
|||
'lib/Value.cpp',
|
||||
'lib/TypeResolver.cpp',
|
||||
'lib/SymTable.cpp',
|
||||
'lib/FunTy.cpp',
|
||||
'lib/Fun.cpp',
|
||||
]
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
let a = fun (x as int, y as int) -> int
|
||||
return x + y
|
||||
end
|
||||
|
||||
assert 12 == {a 9 3}
|
||||
assert 6 == {a {a 1 2} 3}
|
21
src/main.cpp
21
src/main.cpp
|
@ -1,6 +1,7 @@
|
|||
#include <iostream>
|
||||
#include "Args.hpp"
|
||||
#include "Loader.hpp"
|
||||
#include "../lib/SymTable.hpp"
|
||||
#include "../lib/Lexer.hpp"
|
||||
#include "../lib/Parser.hpp"
|
||||
#include "../lib/StaticPass.hpp"
|
||||
|
@ -20,6 +21,7 @@ int main(int argc, char** argv)
|
|||
std::cerr << "\t--ast, show the AST" << std::endl;
|
||||
std::cerr << "\t--code, show the bytecode" << std::endl;
|
||||
std::cerr << "\t--stack, show the call stack" << std::endl;
|
||||
std::cerr << "\t--throws, throws exception on error" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -33,12 +35,11 @@ int main(int argc, char** argv)
|
|||
|
||||
if (args.inputs().size() > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto do_stuff = [&](){
|
||||
auto source = loader.load(args.inputs()[0]);
|
||||
roza::SrcLoc loc {args.inputs()[0]};
|
||||
roza::StatusLog log;
|
||||
|
||||
auto sym = std::make_shared<roza::SymTable>();
|
||||
auto lexer = std::make_shared<roza::Lexer>(log, loc);
|
||||
auto parser = std::make_shared<roza::Parser>(*lexer, log);
|
||||
auto static_pass = std::make_shared<roza::StaticPass>(log);
|
||||
|
@ -65,7 +66,7 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
static_pass->check(root);
|
||||
auto prog = compiler->compile(root);
|
||||
auto prog = compiler->compile(root, sym);
|
||||
|
||||
if (args.get("--code"))
|
||||
{
|
||||
|
@ -81,12 +82,24 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
if (args.get("--throws"))
|
||||
{
|
||||
do_stuff();
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
do_stuff();
|
||||
}
|
||||
catch(std::exception const& err)
|
||||
{
|
||||
std::cerr << err.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,10 +18,11 @@ public:
|
|||
roza::Lexer lexer {log, loc};
|
||||
roza::Parser parser {lexer, log};
|
||||
roza::Compiler compiler {log};
|
||||
auto sym = std::make_shared<roza::SymTable>();
|
||||
|
||||
lexer.scan(source);
|
||||
auto node = parser.parse();
|
||||
return compiler.compile(node);
|
||||
return compiler.compile(node, sym);
|
||||
}
|
||||
|
||||
void compile_err(std::string const& source)
|
||||
|
|
|
@ -112,3 +112,28 @@ TEST_CASE_METHOD(LexerTest, "Lexer_if")
|
|||
REQUIRE("END" == get_str(2));
|
||||
REQUIRE("" == get_str(3));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_types")
|
||||
{
|
||||
m_lexer.scan(" int bool ");
|
||||
REQUIRE("TYPE[int]" == get_str(0));
|
||||
REQUIRE("TYPE[bool]" == get_str(1));
|
||||
REQUIRE("" == get_str(2));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_fun")
|
||||
{
|
||||
m_lexer.scan(" fun as -> ");
|
||||
REQUIRE("FUN" == get_str(0));
|
||||
REQUIRE("AS" == get_str(1));
|
||||
REQUIRE("ARROW" == get_str(2));
|
||||
REQUIRE("" == get_str(3));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_call")
|
||||
{
|
||||
m_lexer.scan(" {} ");
|
||||
REQUIRE("OBRACE" == get_str(0));
|
||||
REQUIRE("CBRACE" == get_str(1));
|
||||
REQUIRE("" == get_str(2));
|
||||
}
|
||||
|
|
|
@ -137,3 +137,45 @@ TEST_CASE_METHOD(ParserTest, "Parser_if")
|
|||
"ELSE(INT[3])))))",
|
||||
"if true 0; else if false 1; else if true 2; else 3; end");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_fun")
|
||||
{
|
||||
test_node("PROG(FUN(PARAMS,RET,BODY))",
|
||||
"fun () end");
|
||||
|
||||
test_node("PROG(FUN(PARAMS("
|
||||
"PARAM(IDENT[x],TYPE[int]),"
|
||||
"PARAM(IDENT[y],TYPE[bool])"
|
||||
"),RET,BODY))",
|
||||
"fun (x as int, y as bool) end");
|
||||
|
||||
test_node("PROG(FUN(PARAMS,RET,BODY(INT[0],INT[1],INT[2])))",
|
||||
"fun () 0; 1; 2; end");
|
||||
|
||||
test_node("PROG(FUN(PARAMS,RET(TYPE[int]),BODY(INT[0],INT[1],INT[2])))",
|
||||
"fun () -> int 0; 1; 2; end");
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_type")
|
||||
{
|
||||
test_node("PROG(FUN(PARAMS,RET(TYPE[int]),BODY))",
|
||||
"fun () -> int end");
|
||||
|
||||
test_node("PROG(FUN(PARAMS,RET(TYPE[nil]),BODY))",
|
||||
"fun () -> nil end");
|
||||
|
||||
test_node("PROG(FUN(PARAMS,RET(TYPE[fun](TYPE[int],TYPE[bool])),BODY))",
|
||||
"fun () -> fun<int -> bool> end");
|
||||
|
||||
test_node("PROG(FUN(PARAMS,RET(TYPE[fun](TYPE[int],TYPE[fun]("
|
||||
"TYPE[bool],TYPE[bool]"
|
||||
"))),BODY))",
|
||||
"fun () -> fun< int -> fun<bool -> bool> > end");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_call")
|
||||
{
|
||||
test_node("PROG(CALL(IDENT[f],ARGS(IDENT[a],IDENT[b],IDENT[c])))",
|
||||
"{f a b c}");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue