ADD: basic function3
parent
d72660e6de
commit
620818c42a
|
@ -3,6 +3,7 @@ PROG ::= (INSTR (EOI+ INSTR)*)?
|
||||||
INSTR ::= EXPR
|
INSTR ::= EXPR
|
||||||
| assert EXPR
|
| assert EXPR
|
||||||
| assert_static_fail INSTR
|
| assert_static_fail INSTR
|
||||||
|
| return EXPR
|
||||||
| VARDECL
|
| VARDECL
|
||||||
| CONSTDECL
|
| CONSTDECL
|
||||||
| ASSIGN
|
| ASSIGN
|
||||||
|
@ -30,4 +31,14 @@ FACTOR ::= UNOP ((mul | div | mod) UNOP)*
|
||||||
UNOP ::= (add | sub | not)? POW
|
UNOP ::= (add | sub | not)? POW
|
||||||
POW ::= GROUP (pow GROUP)?
|
POW ::= GROUP (pow GROUP)?
|
||||||
GROUP ::= BASE | opar EXPR cpar
|
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
|
||||||
|
|
170
lib/Compiler.cpp
170
lib/Compiler.cpp
|
@ -1,5 +1,6 @@
|
||||||
#include "Compiler.hpp"
|
#include "Compiler.hpp"
|
||||||
#include "lib/Node.hpp"
|
#include "lib/Node.hpp"
|
||||||
|
#include "lib/TypeResolver.hpp"
|
||||||
#include "lib/opcodes.hpp"
|
#include "lib/opcodes.hpp"
|
||||||
#include "StaticPass.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>();
|
auto program = std::make_shared<Program>();
|
||||||
compile_node(root, program);
|
compile_node(root, program, sym);
|
||||||
return program;
|
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())
|
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: {
|
case NODE_IF: {
|
||||||
m_sym.enter_scope();
|
sym->enter_scope();
|
||||||
|
|
||||||
std::vector<size_t> to_end;
|
std::vector<size_t> to_end;
|
||||||
|
|
||||||
|
@ -36,11 +81,11 @@ namespace roza
|
||||||
auto cond = n->child(0);
|
auto cond = n->child(0);
|
||||||
auto then = n->child(1);
|
auto then = n->child(1);
|
||||||
|
|
||||||
compile_node(cond, prog);
|
compile_node(cond, prog, sym);
|
||||||
size_t cond_addr = prog->size();
|
size_t cond_addr = prog->size();
|
||||||
prog->push_instr(OP_BRF, 0);
|
prog->push_instr(OP_BRF, 0);
|
||||||
|
|
||||||
compile_node(then, prog);
|
compile_node(then, prog, sym);
|
||||||
|
|
||||||
to_end.push_back(prog->size());
|
to_end.push_back(prog->size());
|
||||||
prog->push_instr(OP_BR, 0);
|
prog->push_instr(OP_BR, 0);
|
||||||
|
@ -50,7 +95,7 @@ namespace roza
|
||||||
if (n->size() > 2)
|
if (n->size() > 2)
|
||||||
{
|
{
|
||||||
auto next = n->child(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());
|
prog->set_param(addr, prog->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sym.leave_scope();
|
sym->leave_scope();
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_BODY:
|
||||||
case NODE_ELSE:
|
case NODE_ELSE:
|
||||||
case NODE_THEN: {
|
case NODE_THEN: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_ASSERT: {
|
case NODE_ASSERT: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_ASSERT);
|
prog->push_instr(OP_ASSERT);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -80,10 +126,10 @@ namespace roza
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
StaticPass static_pass {m_log, m_sym};
|
StaticPass static_pass {m_log, *sym};
|
||||||
static_pass.check_children(root);
|
static_pass.check_children(root);
|
||||||
|
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
|
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
|
@ -99,30 +145,64 @@ namespace roza
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_IDENT: {
|
case NODE_IDENT: {
|
||||||
SymEntry const& entry = m_sym.find(root->repr());
|
SymEntry const& entry = sym->find(root->repr());
|
||||||
prog->push_instr(OP_LOAD_GLOBAL, entry.addr);
|
|
||||||
|
if (m_fun_stack.empty())
|
||||||
|
{
|
||||||
|
prog->push_instr(OP_LOAD_GLOBAL, entry.addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prog->push_instr(OP_LOAD_LOCAL, entry.addr);
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_VARDECL: {
|
case NODE_VARDECL: {
|
||||||
std::string name = root->child(0)->repr();
|
std::string name = root->child(0)->repr();
|
||||||
compile_node(root->child(1), prog);
|
compile_node(root->child(1), prog, sym);
|
||||||
int addr = m_sym.declare_mut(name, root->child(1));
|
int addr = sym->declare_mut(name, root->child(1));
|
||||||
prog->push_instr(OP_STORE_GLOBAL, addr);
|
|
||||||
|
if (m_fun_stack.empty())
|
||||||
|
{
|
||||||
|
prog->push_instr(OP_STORE_GLOBAL, addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prog->push_instr(OP_STORE_LOCAL, addr);
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_CONSTDECL: {
|
case NODE_CONSTDECL: {
|
||||||
std::string name = root->child(0)->repr();
|
std::string name = root->child(0)->repr();
|
||||||
compile_node(root->child(1), prog);
|
compile_node(root->child(1), prog, sym);
|
||||||
int addr = m_sym.declare(name, root->child(1));
|
int addr = sym->declare(name, root->child(1));
|
||||||
prog->push_instr(OP_STORE_GLOBAL, addr);
|
|
||||||
|
if (m_fun_stack.empty())
|
||||||
|
{
|
||||||
|
prog->push_instr(OP_STORE_GLOBAL, addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prog->push_instr(OP_STORE_LOCAL, addr);
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_ASSIGN: {
|
case NODE_ASSIGN: {
|
||||||
int addr = m_sym.find(root->child(0)->repr()).addr;
|
int addr = sym->find(root->child(0)->repr()).addr;
|
||||||
compile_node(root->child(1), prog);
|
compile_node(root->child(1), prog, sym);
|
||||||
prog->push_instr(OP_STORE_GLOBAL, addr);
|
|
||||||
|
if (m_fun_stack.empty())
|
||||||
|
{
|
||||||
|
prog->push_instr(OP_STORE_GLOBAL, addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prog->push_instr(OP_STORE_LOCAL, addr);
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_INT: {
|
case NODE_INT: {
|
||||||
|
@ -136,100 +216,100 @@ namespace roza
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_EQ: {
|
case NODE_EQ: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_EQ);
|
prog->push_instr(OP_EQ);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_NE: {
|
case NODE_NE: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_EQ);
|
prog->push_instr(OP_EQ);
|
||||||
prog->push_instr(OP_NOT);
|
prog->push_instr(OP_NOT);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_LT: {
|
case NODE_LT: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_ILT);
|
prog->push_instr(OP_ILT);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_GT: {
|
case NODE_GT: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IGT);
|
prog->push_instr(OP_IGT);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_LE: {
|
case NODE_LE: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IGT);
|
prog->push_instr(OP_IGT);
|
||||||
prog->push_instr(OP_NOT);
|
prog->push_instr(OP_NOT);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_GE: {
|
case NODE_GE: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_ILT);
|
prog->push_instr(OP_ILT);
|
||||||
prog->push_instr(OP_NOT);
|
prog->push_instr(OP_NOT);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_IMP: {
|
case NODE_IMP: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IMP);
|
prog->push_instr(OP_IMP);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_AND: {
|
case NODE_AND: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_AND);
|
prog->push_instr(OP_AND);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_OR: {
|
case NODE_OR: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_OR);
|
prog->push_instr(OP_OR);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_NOT: {
|
case NODE_NOT: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_NOT);
|
prog->push_instr(OP_NOT);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_ADD: {
|
case NODE_ADD: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IADD);
|
prog->push_instr(OP_IADD);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_SUB: {
|
case NODE_SUB: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_ISUB);
|
prog->push_instr(OP_ISUB);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_MUL: {
|
case NODE_MUL: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IMUL);
|
prog->push_instr(OP_IMUL);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_DIV: {
|
case NODE_DIV: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IDIV);
|
prog->push_instr(OP_IDIV);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_MOD: {
|
case NODE_MOD: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IMOD);
|
prog->push_instr(OP_IMOD);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_POW: {
|
case NODE_POW: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IPOW);
|
prog->push_instr(OP_IPOW);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_UADD: {
|
case NODE_UADD: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IUADD);
|
prog->push_instr(OP_IUADD);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_USUB: {
|
case NODE_USUB: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
prog->push_instr(OP_IUSUB);
|
prog->push_instr(OP_IUSUB);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_PROG: {
|
case NODE_PROG: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog, sym);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
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++)
|
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 "opcodes.hpp"
|
||||||
#include "StatusLog.hpp"
|
#include "StatusLog.hpp"
|
||||||
#include "SymTable.hpp"
|
#include "SymTable.hpp"
|
||||||
|
#include "Fun.hpp"
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
@ -16,13 +17,20 @@ namespace roza
|
||||||
explicit Compiler(StatusLog& log);
|
explicit Compiler(StatusLog& log);
|
||||||
virtual ~Compiler();
|
virtual ~Compiler();
|
||||||
|
|
||||||
std::shared_ptr<Program> compile(std::shared_ptr<Node> root);
|
std::shared_ptr<Program> compile(std::shared_ptr<Node> root,
|
||||||
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);
|
|
||||||
|
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:
|
private:
|
||||||
StatusLog& m_log;
|
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 }
|
, m_loc { loc }
|
||||||
{
|
{
|
||||||
std::vector<std::tuple<std::string, NodeType, bool>> texts = {
|
std::vector<std::tuple<std::string, NodeType, bool>> texts = {
|
||||||
|
{"->", NODE_ARROW, false},
|
||||||
{";", NODE_EOI, false},
|
{";", NODE_EOI, false},
|
||||||
|
{",", NODE_COMMA, false},
|
||||||
{"==", NODE_EQ, false},
|
{"==", NODE_EQ, false},
|
||||||
{"!=", NODE_NE, false},
|
{"!=", NODE_NE, false},
|
||||||
{"<=", NODE_LE, false},
|
{"<=", NODE_LE, false},
|
||||||
|
@ -24,10 +26,18 @@ namespace roza
|
||||||
{"^", NODE_POW, false},
|
{"^", NODE_POW, false},
|
||||||
{"(", NODE_OPAR, false},
|
{"(", NODE_OPAR, false},
|
||||||
{")", NODE_CPAR, false},
|
{")", NODE_CPAR, false},
|
||||||
|
{"{", NODE_OBRACE, false},
|
||||||
|
{"}", NODE_CBRACE, false},
|
||||||
{"=", NODE_ASSIGN, false},
|
{"=", NODE_ASSIGN, false},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::tuple<std::string, NodeType, bool>> keywords = {
|
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},
|
{"if", NODE_IF, false},
|
||||||
{"else", NODE_ELSE, false},
|
{"else", NODE_ELSE, false},
|
||||||
{"end", NODE_END, false},
|
{"end", NODE_END, false},
|
||||||
|
|
|
@ -14,7 +14,10 @@
|
||||||
G(NODE_GE), G(NODE_ASSERT), G(NODE_ASSERT_STATIC_FAIL), \
|
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_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_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
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
141
lib/Parser.cpp
141
lib/Parser.cpp
|
@ -141,6 +141,13 @@ namespace roza
|
||||||
root->add_child(parse_instr());
|
root->add_child(parse_instr());
|
||||||
return root;
|
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))
|
else if (type_is(NODE_LET))
|
||||||
{
|
{
|
||||||
auto root = parse_constdecl();
|
auto root = parse_constdecl();
|
||||||
|
@ -453,6 +460,16 @@ namespace roza
|
||||||
return consume();
|
return consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type_is(NODE_FUN))
|
||||||
|
{
|
||||||
|
return parse_fun();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type_is(NODE_OBRACE))
|
||||||
|
{
|
||||||
|
return parse_call();
|
||||||
|
}
|
||||||
|
|
||||||
m_log.fatal(node()->loc(),
|
m_log.fatal(node()->loc(),
|
||||||
"cannot parse unknown node '"
|
"cannot parse unknown node '"
|
||||||
+ node()->string()
|
+ node()->string()
|
||||||
|
@ -461,9 +478,133 @@ namespace roza
|
||||||
return nullptr;
|
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()
|
std::shared_ptr<Node> Parser::parse_int()
|
||||||
{
|
{
|
||||||
auto root = consume(NODE_INT);
|
auto root = consume(NODE_INT);
|
||||||
return root;
|
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_pow();
|
||||||
std::shared_ptr<Node> parse_group();
|
std::shared_ptr<Node> parse_group();
|
||||||
std::shared_ptr<Node> parse_base();
|
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_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())
|
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: {
|
case NODE_IF: {
|
||||||
m_sym.enter_scope();
|
m_sym.enter_scope();
|
||||||
auto cond_type = resolver.find(root->child(0), m_sym);
|
auto cond_type = resolver.find(root->child(0), m_sym);
|
||||||
|
@ -34,6 +94,7 @@ namespace roza
|
||||||
m_sym.leave_scope();
|
m_sym.leave_scope();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_ARGS:
|
||||||
case NODE_THEN:
|
case NODE_THEN:
|
||||||
case NODE_ELSE: {
|
case NODE_ELSE: {
|
||||||
check_children(root);
|
check_children(root);
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace roza
|
||||||
private:
|
private:
|
||||||
StatusLog& m_log;
|
StatusLog& m_log;
|
||||||
SymTable m_sym;
|
SymTable m_sym;
|
||||||
|
std::shared_ptr<Node> m_outer_fun_ret;
|
||||||
|
|
||||||
void check_types(std::shared_ptr<Node> root,
|
void check_types(std::shared_ptr<Node> root,
|
||||||
std::shared_ptr<Type> lhs,
|
std::shared_ptr<Type> lhs,
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
/*static*/ int SymTable::addr = 0;
|
|
||||||
|
|
||||||
/*explicit*/ SymTable::SymTable()
|
/*explicit*/ SymTable::SymTable()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -48,13 +46,13 @@ namespace roza
|
||||||
|
|
||||||
m_entries.push_back(SymEntry {
|
m_entries.push_back(SymEntry {
|
||||||
name,
|
name,
|
||||||
SymTable::addr++,
|
m_addr++,
|
||||||
m_scope,
|
m_scope,
|
||||||
node,
|
node,
|
||||||
false
|
false
|
||||||
});
|
});
|
||||||
|
|
||||||
return SymTable::addr - 1;
|
return m_addr - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SymTable::declare_mut(std::string const& name, std::shared_ptr<Node> node)
|
int SymTable::declare_mut(std::string const& name, std::shared_ptr<Node> node)
|
||||||
|
@ -137,4 +135,16 @@ namespace roza
|
||||||
|
|
||||||
return false;
|
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(std::string const& name) const;
|
||||||
bool exists_in_scope(std::string const& name) const;
|
bool exists_in_scope(std::string const& name) const;
|
||||||
|
|
||||||
|
std::string string() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int addr;
|
int m_addr = 0;
|
||||||
std::vector<SymEntry> m_entries;
|
std::vector<SymEntry> m_entries;
|
||||||
int m_scope = 0;
|
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])
|
return std::string(BaseTypeStr[m_base])
|
||||||
.substr(std::string("TY_").size());
|
.substr(std::string("TY_").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Type::equals(BaseType rhs) const
|
/*virtual*/ bool Type::equals(BaseType rhs) const
|
||||||
{
|
{
|
||||||
return m_base == rhs;
|
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;
|
return m_base == rhs.m_base;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
|
|
||||||
#define BASE_TYPE(G) \
|
#define BASE_TYPE(G) \
|
||||||
G(TY_INT), G(TY_BOOL)
|
G(TY_INT), G(TY_BOOL), G(TY_FUN), G(TY_NIL)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
@ -18,10 +18,10 @@ namespace roza
|
||||||
|
|
||||||
BaseType base() const { return m_base; }
|
BaseType base() const { return m_base; }
|
||||||
|
|
||||||
std::string string() const;
|
virtual std::string string() const;
|
||||||
|
|
||||||
bool equals(BaseType rhs) const;
|
virtual bool equals(BaseType rhs) const;
|
||||||
bool equals(Type const& rhs) const;
|
virtual bool equals(Type const& rhs) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BaseType m_base;
|
BaseType m_base;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "TypeResolver.hpp"
|
#include "TypeResolver.hpp"
|
||||||
|
#include "FunTy.hpp"
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
@ -20,6 +21,61 @@ namespace roza
|
||||||
return find(root->child(root->size() - 1), sym);
|
return find(root->child(root->size() - 1), sym);
|
||||||
} break;
|
} 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: {
|
case NODE_IDENT: {
|
||||||
std::string name = root->repr();
|
std::string name = root->repr();
|
||||||
SymEntry const& entry = sym.find(name);
|
SymEntry const& entry = sym.find(name);
|
||||||
|
|
98
lib/VM.cpp
98
lib/VM.cpp
|
@ -1,10 +1,12 @@
|
||||||
#include "VM.hpp"
|
#include "VM.hpp"
|
||||||
#include "lib/opcodes.hpp"
|
#include "lib/opcodes.hpp"
|
||||||
|
#include "Fun.hpp"
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
/*explicit*/ VM::VM(StatusLog& log)
|
/*explicit*/ VM::VM(StatusLog& log)
|
||||||
: m_log { log }
|
: m_log { log }
|
||||||
|
, m_sp { 0 }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +22,76 @@ namespace roza
|
||||||
switch (program->opcode(m_pc))
|
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: {
|
case OP_BRF: {
|
||||||
auto value = program->value(pop());
|
auto value = program->value(pop());
|
||||||
|
|
||||||
|
@ -54,6 +126,23 @@ namespace roza
|
||||||
m_pc++;
|
m_pc++;
|
||||||
} break;
|
} 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: {
|
case OP_ASSERT: {
|
||||||
auto value = program->value(pop());
|
auto value = program->value(pop());
|
||||||
|
|
||||||
|
@ -199,7 +288,7 @@ namespace roza
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
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";
|
ss << i << "\t";
|
||||||
|
|
||||||
|
@ -222,15 +311,16 @@ namespace roza
|
||||||
|
|
||||||
void VM::push(param_t param)
|
void VM::push(param_t param)
|
||||||
{
|
{
|
||||||
m_stack.push_back(param);
|
m_stack[m_sp] = param;
|
||||||
|
m_sp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
param_t VM::pop()
|
param_t VM::pop()
|
||||||
{
|
{
|
||||||
assert(m_stack.size() > 0);
|
assert(m_stack.size() > 0);
|
||||||
|
|
||||||
param_t res = m_stack.back();
|
param_t res = m_stack[m_sp - 1];
|
||||||
m_stack.pop_back();
|
m_sp--;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
lib/VM.hpp
17
lib/VM.hpp
|
@ -14,6 +14,15 @@ namespace roza
|
||||||
(std::shared_ptr<Value>,
|
(std::shared_ptr<Value>,
|
||||||
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
|
class VM
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -25,13 +34,17 @@ namespace roza
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StatusLog& m_log;
|
StatusLog& m_log;
|
||||||
std::vector<param_t> m_stack;
|
std::array<param_t, 4096> m_stack;
|
||||||
std::shared_ptr<Program> m_last_program;
|
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;
|
size_t m_pc = 0;
|
||||||
|
|
||||||
void push(param_t param);
|
void push(param_t param);
|
||||||
param_t pop();
|
param_t pop();
|
||||||
|
|
||||||
void apply_binop(std::shared_ptr<Program> program, binop_t op);
|
void apply_binop(std::shared_ptr<Program> program, binop_t op);
|
||||||
void apply_unop(std::shared_ptr<Program> program, unop_t op);
|
void apply_unop(std::shared_ptr<Program> program, unop_t op);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Value.hpp"
|
#include "Value.hpp"
|
||||||
|
#include "Fun.hpp"
|
||||||
|
|
||||||
namespace roza
|
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()
|
/*virtual*/ Value::~Value()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -32,6 +40,11 @@ namespace roza
|
||||||
return m_bool_val ? "true" : "false";
|
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);
|
assert("cannot stringify unknown value " && 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,17 +7,21 @@
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
class Fun;
|
||||||
|
|
||||||
class Value
|
class Value
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Value(int value, SrcLoc loc);
|
explicit Value(int value, SrcLoc loc);
|
||||||
explicit Value(bool value, SrcLoc loc);
|
explicit Value(bool value, SrcLoc loc);
|
||||||
|
explicit Value(std::shared_ptr<Fun> value, SrcLoc loc);
|
||||||
virtual ~Value();
|
virtual ~Value();
|
||||||
|
|
||||||
SrcLoc loc() const { return m_loc; }
|
SrcLoc loc() const { return m_loc; }
|
||||||
|
|
||||||
int as_int() const { return m_int_val; }
|
int as_int() const { return m_int_val; }
|
||||||
bool as_bool() const { return m_bool_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::shared_ptr<Type> type() const { return m_type; }
|
||||||
std::string string() const;
|
std::string string() const;
|
||||||
|
@ -27,7 +31,10 @@ namespace roza
|
||||||
std::shared_ptr<Type> m_type;
|
std::shared_ptr<Type> m_type;
|
||||||
int m_int_val;
|
int m_int_val;
|
||||||
bool m_bool_val;
|
bool m_bool_val;
|
||||||
|
std::shared_ptr<Fun> m_fun_val;
|
||||||
|
|
||||||
SrcLoc m_loc;
|
SrcLoc m_loc;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <array>
|
||||||
#include "mutils.hpp"
|
#include "mutils.hpp"
|
||||||
|
|
||||||
#endif
|
#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_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_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_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
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,8 @@ roza_lib = static_library(
|
||||||
'lib/Value.cpp',
|
'lib/Value.cpp',
|
||||||
'lib/TypeResolver.cpp',
|
'lib/TypeResolver.cpp',
|
||||||
'lib/SymTable.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}
|
113
src/main.cpp
113
src/main.cpp
|
@ -1,6 +1,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Args.hpp"
|
#include "Args.hpp"
|
||||||
#include "Loader.hpp"
|
#include "Loader.hpp"
|
||||||
|
#include "../lib/SymTable.hpp"
|
||||||
#include "../lib/Lexer.hpp"
|
#include "../lib/Lexer.hpp"
|
||||||
#include "../lib/Parser.hpp"
|
#include "../lib/Parser.hpp"
|
||||||
#include "../lib/StaticPass.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--ast, show the AST" << std::endl;
|
||||||
std::cerr << "\t--code, show the bytecode" << std::endl;
|
std::cerr << "\t--code, show the bytecode" << std::endl;
|
||||||
std::cerr << "\t--stack, show the call stack" << std::endl;
|
std::cerr << "\t--stack, show the call stack" << std::endl;
|
||||||
|
std::cerr << "\t--throws, throws exception on error" << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,59 +35,70 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
if (args.inputs().size() > 0)
|
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);
|
||||||
|
auto compiler = std::make_shared<roza::Compiler>(log);
|
||||||
|
auto vm = std::make_shared<roza::VM>(log);
|
||||||
|
|
||||||
|
lexer->scan(source);
|
||||||
|
|
||||||
|
if (args.get("--tokens"))
|
||||||
|
{
|
||||||
|
std::cout << "Tokens:" << std::endl;
|
||||||
|
for (size_t i=0; i<lexer->size(); i++)
|
||||||
|
{
|
||||||
|
std::cout << "\t" << lexer->get_or_nullptr(i)->string() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto root = parser->parse();
|
||||||
|
|
||||||
|
if (args.get("--ast"))
|
||||||
|
{
|
||||||
|
std::cout << "AST:" << std::endl;
|
||||||
|
std::cout << root->string() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_pass->check(root);
|
||||||
|
auto prog = compiler->compile(root, sym);
|
||||||
|
|
||||||
|
if (args.get("--code"))
|
||||||
|
{
|
||||||
|
std::cout << "Bytecode:" << std::endl;
|
||||||
|
std::cout << prog->string() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm->exec(prog);
|
||||||
|
|
||||||
|
if (args.get("--stack"))
|
||||||
|
{
|
||||||
|
std::cout << vm->string() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (args.get("--throws"))
|
||||||
{
|
{
|
||||||
auto source = loader.load(args.inputs()[0]);
|
do_stuff();
|
||||||
roza::SrcLoc loc {args.inputs()[0]};
|
|
||||||
roza::StatusLog log;
|
|
||||||
|
|
||||||
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);
|
|
||||||
auto compiler = std::make_shared<roza::Compiler>(log);
|
|
||||||
auto vm = std::make_shared<roza::VM>(log);
|
|
||||||
|
|
||||||
lexer->scan(source);
|
|
||||||
|
|
||||||
if (args.get("--tokens"))
|
|
||||||
{
|
|
||||||
std::cout << "Tokens:" << std::endl;
|
|
||||||
for (size_t i=0; i<lexer->size(); i++)
|
|
||||||
{
|
|
||||||
std::cout << "\t" << lexer->get_or_nullptr(i)->string() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto root = parser->parse();
|
|
||||||
|
|
||||||
if (args.get("--ast"))
|
|
||||||
{
|
|
||||||
std::cout << "AST:" << std::endl;
|
|
||||||
std::cout << root->string() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static_pass->check(root);
|
|
||||||
auto prog = compiler->compile(root);
|
|
||||||
|
|
||||||
if (args.get("--code"))
|
|
||||||
{
|
|
||||||
std::cout << "Bytecode:" << std::endl;
|
|
||||||
std::cout << prog->string() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->exec(prog);
|
|
||||||
|
|
||||||
if (args.get("--stack"))
|
|
||||||
{
|
|
||||||
std::cout << vm->string() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
catch(std::exception const& err)
|
else
|
||||||
{
|
{
|
||||||
std::cerr << err.what() << std::endl;
|
try
|
||||||
return -1;
|
{
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
catch(std::exception const& err)
|
||||||
|
{
|
||||||
|
std::cerr << err.what() << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -18,10 +18,11 @@ public:
|
||||||
roza::Lexer lexer {log, loc};
|
roza::Lexer lexer {log, loc};
|
||||||
roza::Parser parser {lexer, log};
|
roza::Parser parser {lexer, log};
|
||||||
roza::Compiler compiler {log};
|
roza::Compiler compiler {log};
|
||||||
|
auto sym = std::make_shared<roza::SymTable>();
|
||||||
|
|
||||||
lexer.scan(source);
|
lexer.scan(source);
|
||||||
auto node = parser.parse();
|
auto node = parser.parse();
|
||||||
return compiler.compile(node);
|
return compiler.compile(node, sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_err(std::string const& source)
|
void compile_err(std::string const& source)
|
||||||
|
|
|
@ -112,3 +112,28 @@ TEST_CASE_METHOD(LexerTest, "Lexer_if")
|
||||||
REQUIRE("END" == get_str(2));
|
REQUIRE("END" == get_str(2));
|
||||||
REQUIRE("" == get_str(3));
|
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])))))",
|
"ELSE(INT[3])))))",
|
||||||
"if true 0; else if false 1; else if true 2; else 3; end");
|
"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