ADD: global variable declaration (mutable or not).
parent
66283e23bb
commit
b9072c580f
|
@ -2,7 +2,14 @@ PROG ::= (INSTR (EOI+ INSTR)*)?
|
||||||
|
|
||||||
INSTR ::= EXPR
|
INSTR ::= EXPR
|
||||||
| assert EXPR
|
| assert EXPR
|
||||||
| assert_static_fail EXPR
|
| assert_static_fail INSTR
|
||||||
|
| VARDECL
|
||||||
|
| CONSTDECL
|
||||||
|
| ASSIGN
|
||||||
|
|
||||||
|
VARDECL ::= let_mut ident assign EXPR
|
||||||
|
CONSTDECL ::= let ident assign EXPR
|
||||||
|
ASSIGN ::= ident assign EXPR
|
||||||
|
|
||||||
EXPR ::= IMP
|
EXPR ::= IMP
|
||||||
|
|
||||||
|
@ -19,4 +26,4 @@ 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
|
BASE ::= int | bool | ident
|
||||||
|
|
|
@ -35,8 +35,9 @@ namespace roza
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
StaticPass static_pass {m_log};
|
StaticPass static_pass {m_log, m_sym};
|
||||||
static_pass.check_children(root);
|
static_pass.check_children(root);
|
||||||
|
|
||||||
compile_children(root, prog);
|
compile_children(root, prog);
|
||||||
|
|
||||||
failed = true;
|
failed = true;
|
||||||
|
@ -52,6 +53,33 @@ namespace roza
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_IDENT: {
|
||||||
|
SymEntry const& entry = m_sym.find(root->repr());
|
||||||
|
prog->push_instr(OP_LOAD_GLOBAL, 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));
|
||||||
|
prog->push_instr(OP_STORE_GLOBAL, 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));
|
||||||
|
prog->push_instr(OP_STORE_GLOBAL, addr);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_ASSIGN: {
|
||||||
|
int addr = m_sym.find(root->child(0)->repr()).addr;
|
||||||
|
compile_node(root->child(1), prog);
|
||||||
|
prog->push_instr(OP_STORE_GLOBAL, addr);
|
||||||
|
} break;
|
||||||
|
|
||||||
case NODE_INT: {
|
case NODE_INT: {
|
||||||
auto value = std::make_shared<Value>(std::stoi(root->repr()), root->loc());
|
auto value = std::make_shared<Value>(std::stoi(root->repr()), root->loc());
|
||||||
prog->push_instr(OP_PUSH_CONST, prog->push_value(value));
|
prog->push_instr(OP_PUSH_CONST, prog->push_value(value));
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "opcodes.hpp"
|
#include "opcodes.hpp"
|
||||||
#include "StatusLog.hpp"
|
#include "StatusLog.hpp"
|
||||||
|
#include "SymTable.hpp"
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
@ -21,6 +22,7 @@ namespace roza
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StatusLog& m_log;
|
StatusLog& m_log;
|
||||||
|
SymTable m_sym;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,12 @@ namespace roza
|
||||||
{"^", NODE_POW, false},
|
{"^", NODE_POW, false},
|
||||||
{"(", NODE_OPAR, false},
|
{"(", NODE_OPAR, false},
|
||||||
{")", NODE_CPAR, false},
|
{")", NODE_CPAR, false},
|
||||||
|
{"=", NODE_ASSIGN, false},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::tuple<std::string, NodeType, bool>> keywords = {
|
std::vector<std::tuple<std::string, NodeType, bool>> keywords = {
|
||||||
|
{"let!", NODE_LET_MUT, false},
|
||||||
|
{"let", NODE_LET, false},
|
||||||
{"true", NODE_BOOL, true},
|
{"true", NODE_BOOL, true},
|
||||||
{"false", NODE_BOOL, true},
|
{"false", NODE_BOOL, true},
|
||||||
{"and", NODE_AND, false},
|
{"and", NODE_AND, false},
|
||||||
|
@ -35,7 +38,6 @@ namespace roza
|
||||||
{"assert", NODE_ASSERT, false},
|
{"assert", NODE_ASSERT, false},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
m_scanners.push_back(std::bind(&Lexer::scan_int, this));
|
m_scanners.push_back(std::bind(&Lexer::scan_int, this));
|
||||||
|
|
||||||
for (auto const& entry: keywords)
|
for (auto const& entry: keywords)
|
||||||
|
@ -54,6 +56,7 @@ namespace roza
|
||||||
std::get<2>(entry)));
|
std::get<2>(entry)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_scanners.push_back(std::bind(&Lexer::scan_ident, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*virtual*/ Lexer::~Lexer()
|
/*virtual*/ Lexer::~Lexer()
|
||||||
|
@ -225,4 +228,42 @@ namespace roza
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScanInfo Lexer::scan_ident() const
|
||||||
|
{
|
||||||
|
size_t cursor = m_cursor;
|
||||||
|
std::string value;
|
||||||
|
|
||||||
|
auto is_ident = [](size_t pos, char c){
|
||||||
|
bool other = false;
|
||||||
|
|
||||||
|
if (pos > 0)
|
||||||
|
{
|
||||||
|
other =
|
||||||
|
std::isdigit(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return c == '_' || std::isalpha(c) || other;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
while (cursor < m_source.size()
|
||||||
|
&& is_ident(pos, m_source[cursor]))
|
||||||
|
{
|
||||||
|
value += m_source[cursor];
|
||||||
|
cursor++;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.empty() == false)
|
||||||
|
{
|
||||||
|
return ScanInfo {
|
||||||
|
std::make_shared<Node>(NODE_IDENT, value, loc()),
|
||||||
|
cursor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ScanInfo {
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,8 @@ namespace roza
|
||||||
ScanInfo scan_keyword(std::string const& keyword,
|
ScanInfo scan_keyword(std::string const& keyword,
|
||||||
NodeType type,
|
NodeType type,
|
||||||
bool value=false) const;
|
bool value=false) const;
|
||||||
|
|
||||||
|
ScanInfo scan_ident() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,9 @@
|
||||||
G(NODE_CPAR), G(NODE_UADD), G(NODE_USUB), G(NODE_BOOL), \
|
G(NODE_CPAR), G(NODE_UADD), G(NODE_USUB), G(NODE_BOOL), \
|
||||||
G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IMP), \
|
G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IMP), \
|
||||||
G(NODE_EQ), G(NODE_NE), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
|
G(NODE_EQ), G(NODE_NE), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
|
||||||
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_VARDECL), G(NODE_CONSTDECL)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -94,6 +94,12 @@ namespace roza
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::ensure(NodeType type)
|
||||||
|
{
|
||||||
|
consume_or_nullptr(type);
|
||||||
|
consume_all(type);
|
||||||
|
}
|
||||||
|
|
||||||
void Parser::next()
|
void Parser::next()
|
||||||
{
|
{
|
||||||
m_cursor++;
|
m_cursor++;
|
||||||
|
@ -121,22 +127,88 @@ namespace roza
|
||||||
{
|
{
|
||||||
consume_all(NODE_EOI);
|
consume_all(NODE_EOI);
|
||||||
|
|
||||||
std::shared_ptr<Node> root;
|
if (type_is(NODE_ASSERT))
|
||||||
|
|
||||||
if (type_is(NODE_ASSERT)
|
|
||||||
|| type_is(NODE_ASSERT_STATIC_FAIL))
|
|
||||||
{
|
{
|
||||||
root = consume();
|
auto root = consume();
|
||||||
root->add_child(parse_expr());
|
root->add_child(parse_expr());
|
||||||
|
|
||||||
|
ensure(NODE_EOI);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
else if (type_is(NODE_ASSERT_STATIC_FAIL))
|
||||||
|
{
|
||||||
|
auto root = consume();
|
||||||
|
root->add_child(parse_instr());
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
else if (type_is(NODE_LET))
|
||||||
|
{
|
||||||
|
auto root = parse_constdecl();
|
||||||
|
ensure(NODE_EOI);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
else if (type_is(NODE_LET_MUT))
|
||||||
|
{
|
||||||
|
auto root = parse_vardecl();
|
||||||
|
ensure(NODE_EOI);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
else if (type_is(NODE_IDENT) && type_is(NODE_ASSIGN, 1))
|
||||||
|
{
|
||||||
|
auto root = parse_assign();
|
||||||
|
ensure(NODE_EOI);
|
||||||
|
return root;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
root = parse_expr();
|
auto root = parse_expr();
|
||||||
|
ensure(NODE_EOI);
|
||||||
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_log.fatal(node()->loc(),
|
||||||
|
std::string()
|
||||||
|
+ "unknown instruction '"
|
||||||
|
+ std::string(NodeTypeStr[node()->type()])
|
||||||
|
.substr(std::string("NODE_").size())
|
||||||
|
+ "'");
|
||||||
|
|
||||||
consume_or_nullptr(NODE_EOI);
|
return nullptr;
|
||||||
consume_all(NODE_EOI);
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse_vardecl()
|
||||||
|
{
|
||||||
|
consume(NODE_LET_MUT);
|
||||||
|
auto root = std::make_shared<Node>(NODE_VARDECL, "", node()->loc());
|
||||||
|
auto ident = consume(NODE_IDENT);
|
||||||
|
consume(NODE_ASSIGN);
|
||||||
|
auto expr = parse_expr();
|
||||||
|
root->add_child(ident);
|
||||||
|
root->add_child(expr);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse_constdecl()
|
||||||
|
{
|
||||||
|
consume(NODE_LET);
|
||||||
|
auto root = std::make_shared<Node>(NODE_CONSTDECL, "", node()->loc());
|
||||||
|
auto ident = consume(NODE_IDENT);
|
||||||
|
consume(NODE_ASSIGN);
|
||||||
|
auto expr = parse_expr();
|
||||||
|
root->add_child(ident);
|
||||||
|
root->add_child(expr);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse_assign()
|
||||||
|
{
|
||||||
|
auto lhs = consume(NODE_IDENT);
|
||||||
|
auto root = consume(NODE_ASSIGN);
|
||||||
|
|
||||||
|
root->add_child(lhs);
|
||||||
|
root->add_child(parse_expr());
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
@ -320,13 +392,14 @@ namespace roza
|
||||||
std::shared_ptr<Node> Parser::parse_base()
|
std::shared_ptr<Node> Parser::parse_base()
|
||||||
{
|
{
|
||||||
if (type_is(NODE_INT)
|
if (type_is(NODE_INT)
|
||||||
|| type_is(NODE_BOOL))
|
|| type_is(NODE_BOOL)
|
||||||
|
|| type_is(NODE_IDENT))
|
||||||
{
|
{
|
||||||
return consume();
|
return consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.fatal(node()->loc(),
|
m_log.fatal(node()->loc(),
|
||||||
"unknown node '"
|
"cannot parse unknown node '"
|
||||||
+ node()->string()
|
+ node()->string()
|
||||||
+ "'");
|
+ "'");
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,16 @@ namespace roza
|
||||||
std::shared_ptr<Node> consume(NodeType type);
|
std::shared_ptr<Node> consume(NodeType type);
|
||||||
void consume_all(NodeType type);
|
void consume_all(NodeType type);
|
||||||
std::shared_ptr<Node> consume();
|
std::shared_ptr<Node> consume();
|
||||||
|
void ensure(NodeType type);
|
||||||
void next();
|
void next();
|
||||||
|
|
||||||
std::shared_ptr<Node> parse_prog();
|
std::shared_ptr<Node> parse_prog();
|
||||||
std::shared_ptr<Node> parse_instr();
|
std::shared_ptr<Node> parse_instr();
|
||||||
|
|
||||||
|
std::shared_ptr<Node> parse_vardecl();
|
||||||
|
std::shared_ptr<Node> parse_constdecl();
|
||||||
|
std::shared_ptr<Node> parse_assign();
|
||||||
|
|
||||||
std::shared_ptr<Node> parse_expr();
|
std::shared_ptr<Node> parse_expr();
|
||||||
std::shared_ptr<Node> parse_imp();
|
std::shared_ptr<Node> parse_imp();
|
||||||
std::shared_ptr<Node> parse_or();
|
std::shared_ptr<Node> parse_or();
|
||||||
|
|
|
@ -5,7 +5,13 @@
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
/*explicit*/ StaticPass::StaticPass(StatusLog& log)
|
/*explicit*/ StaticPass::StaticPass(StatusLog& log)
|
||||||
|
: StaticPass (log, SymTable {})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*explicit*/ StaticPass::StaticPass(StatusLog& log, SymTable const& sym_table)
|
||||||
: m_log { log }
|
: m_log { log }
|
||||||
|
, m_sym { SymTable(sym_table) }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +22,35 @@ namespace roza
|
||||||
void StaticPass::check(std::shared_ptr<Node> root)
|
void StaticPass::check(std::shared_ptr<Node> root)
|
||||||
{
|
{
|
||||||
TypeResolver resolver {m_log};
|
TypeResolver resolver {m_log};
|
||||||
|
assert(root);
|
||||||
|
|
||||||
switch (root->type())
|
switch (root->type())
|
||||||
{
|
{
|
||||||
|
case NODE_CONSTDECL: {
|
||||||
|
check(root->child(1));
|
||||||
|
m_sym.declare(root->child(0)->repr(), root->child(1));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_VARDECL: {
|
||||||
|
check(root->child(1));
|
||||||
|
m_sym.declare_mut(root->child(0)->repr(), root->child(1));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_ASSIGN: {
|
||||||
|
auto const& entry = m_sym.find(root->child(0)->repr());
|
||||||
|
|
||||||
|
if (!entry.is_mut)
|
||||||
|
{
|
||||||
|
m_log.fatal(root->child(0)->loc(),
|
||||||
|
root->child(0)->repr() + " is not mutable");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lhs = resolver.find(entry.node, m_sym);
|
||||||
|
auto rhs = resolver.find(root->child(1), m_sym);
|
||||||
|
check_types(root, lhs, rhs);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_IDENT:
|
||||||
case NODE_ASSERT_STATIC_FAIL:
|
case NODE_ASSERT_STATIC_FAIL:
|
||||||
case NODE_INT:
|
case NODE_INT:
|
||||||
case NODE_BOOL:
|
case NODE_BOOL:
|
||||||
|
@ -27,8 +59,8 @@ namespace roza
|
||||||
case NODE_EQ:
|
case NODE_EQ:
|
||||||
case NODE_NE: {
|
case NODE_NE: {
|
||||||
check_children(root);
|
check_children(root);
|
||||||
auto lhs = resolver.find(root->child(0));
|
auto lhs = resolver.find(root->child(0), m_sym);
|
||||||
auto rhs = resolver.find(root->child(1));
|
auto rhs = resolver.find(root->child(1), m_sym);
|
||||||
check_types(root, lhs, rhs);
|
check_types(root, lhs, rhs);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -36,8 +68,8 @@ namespace roza
|
||||||
case NODE_OR:
|
case NODE_OR:
|
||||||
case NODE_AND: {
|
case NODE_AND: {
|
||||||
check_children(root);
|
check_children(root);
|
||||||
auto lhs = resolver.find(root->child(0));
|
auto lhs = resolver.find(root->child(0), m_sym);
|
||||||
auto rhs = resolver.find(root->child(1));
|
auto rhs = resolver.find(root->child(1), m_sym);
|
||||||
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
||||||
check_types(root, lhs, rhs);
|
check_types(root, lhs, rhs);
|
||||||
} break;
|
} break;
|
||||||
|
@ -45,7 +77,7 @@ namespace roza
|
||||||
case NODE_ASSERT:
|
case NODE_ASSERT:
|
||||||
case NODE_NOT: {
|
case NODE_NOT: {
|
||||||
check_children(root);
|
check_children(root);
|
||||||
auto lhs = resolver.find(root->child(0));
|
auto lhs = resolver.find(root->child(0), m_sym);
|
||||||
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -60,8 +92,9 @@ namespace roza
|
||||||
case NODE_MOD:
|
case NODE_MOD:
|
||||||
case NODE_POW: {
|
case NODE_POW: {
|
||||||
check_children(root);
|
check_children(root);
|
||||||
auto lhs = resolver.find(root->child(0));
|
auto lhs = resolver.find(root->child(0), m_sym);
|
||||||
auto rhs = resolver.find(root->child(1));
|
auto rhs = resolver.find(root->child(1), m_sym);
|
||||||
|
|
||||||
check_types(root, lhs, std::make_shared<Type>(TY_INT));
|
check_types(root, lhs, std::make_shared<Type>(TY_INT));
|
||||||
check_types(root, lhs, rhs);
|
check_types(root, lhs, rhs);
|
||||||
} break;
|
} break;
|
||||||
|
@ -69,7 +102,7 @@ namespace roza
|
||||||
case NODE_UADD:
|
case NODE_UADD:
|
||||||
case NODE_USUB: {
|
case NODE_USUB: {
|
||||||
check_children(root);
|
check_children(root);
|
||||||
auto lhs = resolver.find(root->child(0));
|
auto lhs = resolver.find(root->child(0), m_sym);
|
||||||
check_types(root, lhs, std::make_shared<Type>(TY_INT));
|
check_types(root, lhs, std::make_shared<Type>(TY_INT));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -94,6 +127,9 @@ namespace roza
|
||||||
std::shared_ptr<Type> lhs,
|
std::shared_ptr<Type> lhs,
|
||||||
std::shared_ptr<Type> rhs)
|
std::shared_ptr<Type> rhs)
|
||||||
{
|
{
|
||||||
|
assert(lhs);
|
||||||
|
assert(rhs);
|
||||||
|
|
||||||
if (!lhs->equals(*rhs))
|
if (!lhs->equals(*rhs))
|
||||||
{
|
{
|
||||||
m_log.fatal(root->loc(),
|
m_log.fatal(root->loc(),
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "StatusLog.hpp"
|
#include "StatusLog.hpp"
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "Type.hpp"
|
#include "Type.hpp"
|
||||||
|
#include "SymTable.hpp"
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
@ -12,6 +13,7 @@ namespace roza
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit StaticPass(StatusLog& log);
|
explicit StaticPass(StatusLog& log);
|
||||||
|
explicit StaticPass(StatusLog& log, SymTable const& sym_table);
|
||||||
virtual ~StaticPass();
|
virtual ~StaticPass();
|
||||||
|
|
||||||
void check(std::shared_ptr<Node> root);
|
void check(std::shared_ptr<Node> root);
|
||||||
|
@ -19,6 +21,7 @@ namespace roza
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StatusLog& m_log;
|
StatusLog& m_log;
|
||||||
|
SymTable m_sym;
|
||||||
|
|
||||||
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,
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include "SymTable.hpp"
|
||||||
|
|
||||||
|
namespace roza
|
||||||
|
{
|
||||||
|
/*static*/ int SymTable::addr = 0;
|
||||||
|
|
||||||
|
/*explicit*/ SymTable::SymTable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*explicit*/ SymTable::SymTable(SymTable const& sym_table)
|
||||||
|
{
|
||||||
|
m_scope = sym_table.m_scope;
|
||||||
|
|
||||||
|
for (auto const& entry: sym_table.m_entries)
|
||||||
|
{
|
||||||
|
m_entries[entry.first] = entry.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ SymTable::~SymTable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int SymTable::declare(std::string const& name, std::shared_ptr<Node> node)
|
||||||
|
{
|
||||||
|
assert(!exists(name));
|
||||||
|
|
||||||
|
m_entries.insert({name, SymEntry {
|
||||||
|
SymTable::addr++,
|
||||||
|
m_scope,
|
||||||
|
node,
|
||||||
|
false
|
||||||
|
}});
|
||||||
|
|
||||||
|
return SymTable::addr - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SymTable::declare_mut(std::string const& name, std::shared_ptr<Node> node)
|
||||||
|
{
|
||||||
|
assert(!exists(name));
|
||||||
|
|
||||||
|
m_entries.insert({name, SymEntry {
|
||||||
|
SymTable::addr++,
|
||||||
|
m_scope,
|
||||||
|
node,
|
||||||
|
true
|
||||||
|
}});
|
||||||
|
|
||||||
|
return SymTable::addr - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymEntry& SymTable::find(std::string const& name)
|
||||||
|
{
|
||||||
|
assert(exists(name));
|
||||||
|
return m_entries[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
SymEntry const& SymTable::find(std::string const& name) const
|
||||||
|
{
|
||||||
|
assert(exists(name));
|
||||||
|
return m_entries.at(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SymTable::exists(std::string const& name) const
|
||||||
|
{
|
||||||
|
return m_entries.find(name) != std::end(m_entries);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef roza_SYMTABLE_HPP
|
||||||
|
#define roza_SYMTABLE_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
#include "Node.hpp"
|
||||||
|
|
||||||
|
namespace roza
|
||||||
|
{
|
||||||
|
struct SymEntry {
|
||||||
|
int addr;
|
||||||
|
int scope;
|
||||||
|
std::shared_ptr<Node> node;
|
||||||
|
bool is_mut;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SymTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SymTable();
|
||||||
|
explicit SymTable(SymTable const& sym_table);
|
||||||
|
|
||||||
|
virtual ~SymTable();
|
||||||
|
|
||||||
|
int declare(std::string const& name, std::shared_ptr<Node> node);
|
||||||
|
int declare_mut(std::string const& name, std::shared_ptr<Node> node);
|
||||||
|
|
||||||
|
SymEntry& find(std::string const& name);
|
||||||
|
SymEntry const& find(std::string const& name) const;
|
||||||
|
|
||||||
|
bool exists(std::string const& name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int addr;
|
||||||
|
std::unordered_map<std::string, SymEntry> m_entries;
|
||||||
|
int m_scope = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -11,12 +11,24 @@ namespace roza
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Type> TypeResolver::find(std::shared_ptr<Node> root)
|
std::shared_ptr<Type> TypeResolver::find(std::shared_ptr<Node> root,
|
||||||
|
SymTable const& sym)
|
||||||
{
|
{
|
||||||
switch (root->type())
|
switch (root->type())
|
||||||
{
|
{
|
||||||
case NODE_PROG: {
|
case NODE_PROG: {
|
||||||
return find(root->child(root->size() - 1));
|
return find(root->child(root->size() - 1), sym);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_IDENT: {
|
||||||
|
std::string name = root->repr();
|
||||||
|
SymEntry const& entry = sym.find(name);
|
||||||
|
return find(entry.node, sym);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_CONSTDECL:
|
||||||
|
case NODE_VARDECL: {
|
||||||
|
auto ty = find(root->child(1), sym);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_INT: {
|
case NODE_INT: {
|
||||||
|
@ -45,7 +57,7 @@ namespace roza
|
||||||
case NODE_POW:
|
case NODE_POW:
|
||||||
case NODE_UADD:
|
case NODE_UADD:
|
||||||
case NODE_USUB:{
|
case NODE_USUB:{
|
||||||
return find(root->child(0));
|
return find(root->child(0), sym);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "Type.hpp"
|
#include "Type.hpp"
|
||||||
#include "StatusLog.hpp"
|
#include "StatusLog.hpp"
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
|
#include "SymTable.hpp"
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
@ -14,7 +15,7 @@ namespace roza
|
||||||
explicit TypeResolver(StatusLog& log);
|
explicit TypeResolver(StatusLog& log);
|
||||||
virtual ~TypeResolver();
|
virtual ~TypeResolver();
|
||||||
|
|
||||||
std::shared_ptr<Type> find(std::shared_ptr<Node> root);
|
std::shared_ptr<Type> find(std::shared_ptr<Node> root, SymTable const& sym);
|
||||||
private:
|
private:
|
||||||
StatusLog& m_log;
|
StatusLog& m_log;
|
||||||
};
|
};
|
||||||
|
|
17
lib/VM.cpp
17
lib/VM.cpp
|
@ -19,6 +19,23 @@ namespace roza
|
||||||
{
|
{
|
||||||
switch (program->opcode(m_pc))
|
switch (program->opcode(m_pc))
|
||||||
{
|
{
|
||||||
|
case OP_LOAD_GLOBAL: {
|
||||||
|
int addr = *program->param(m_pc);
|
||||||
|
auto value = m_globals[addr];
|
||||||
|
push(program->push_value(value));
|
||||||
|
|
||||||
|
m_pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OP_STORE_GLOBAL: {
|
||||||
|
auto value = program->value(pop());
|
||||||
|
int addr = *program->param(m_pc);
|
||||||
|
|
||||||
|
m_globals[addr] = value;
|
||||||
|
|
||||||
|
m_pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
case OP_ASSERT: {
|
case OP_ASSERT: {
|
||||||
auto value = program->value(pop());
|
auto value = program->value(pop());
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace roza
|
||||||
StatusLog& m_log;
|
StatusLog& m_log;
|
||||||
std::vector<param_t> m_stack;
|
std::vector<param_t> 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;
|
||||||
size_t m_pc = 0;
|
size_t m_pc = 0;
|
||||||
|
|
||||||
void push(param_t param);
|
void push(param_t param);
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
G(OP_POP), \
|
G(OP_POP), \
|
||||||
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_IMP), G(OP_EQ), G(OP_ILT), G(OP_IGT), G(OP_ASSERT), G(OP_STORE_GLOBAL), \
|
||||||
|
G(OP_LOAD_GLOBAL)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,7 @@ roza_lib = static_library(
|
||||||
'lib/Type.cpp',
|
'lib/Type.cpp',
|
||||||
'lib/Value.cpp',
|
'lib/Value.cpp',
|
||||||
'lib/TypeResolver.cpp',
|
'lib/TypeResolver.cpp',
|
||||||
|
'lib/SymTable.cpp',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
let! a = 34
|
||||||
|
|
||||||
|
assert 34 == a
|
||||||
|
assert 102 == 3 * a
|
||||||
|
|
||||||
|
a = 9
|
||||||
|
|
||||||
|
a = a + 1
|
||||||
|
|
||||||
|
assert 11 == a + 1
|
||||||
|
|
||||||
|
assert_static_fail a and true
|
||||||
|
assert_static_fail a = false
|
||||||
|
|
||||||
|
let b = 7
|
||||||
|
|
||||||
|
assert 7 == b
|
||||||
|
assert 42 == 6 * b
|
||||||
|
assert 17 == a + b
|
||||||
|
|
||||||
|
assert_static_fail b = 4
|
|
@ -58,7 +58,6 @@ TEST_CASE_METHOD(LexerTest, "Lexer_int_arith")
|
||||||
|
|
||||||
TEST_CASE_METHOD(LexerTest, "Lexer_keywords")
|
TEST_CASE_METHOD(LexerTest, "Lexer_keywords")
|
||||||
{
|
{
|
||||||
REQUIRE_THROWS(m_lexer.scan(" andor "));
|
|
||||||
REQUIRE_NOTHROW(m_lexer.scan(" and+ "));
|
REQUIRE_NOTHROW(m_lexer.scan(" and+ "));
|
||||||
REQUIRE_NOTHROW(m_lexer.scan(" (and) "));
|
REQUIRE_NOTHROW(m_lexer.scan(" (and) "));
|
||||||
}
|
}
|
||||||
|
@ -94,3 +93,13 @@ TEST_CASE_METHOD(LexerTest, "Lexer_asserts")
|
||||||
REQUIRE("ASSERT_STATIC_FAIL" == get_str(1));
|
REQUIRE("ASSERT_STATIC_FAIL" == get_str(1));
|
||||||
REQUIRE("" == get_str(2));
|
REQUIRE("" == get_str(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_declarations")
|
||||||
|
{
|
||||||
|
m_lexer.scan(" let let! hello = ");
|
||||||
|
REQUIRE("LET" == get_str(0));
|
||||||
|
REQUIRE("LET_MUT" == get_str(1));
|
||||||
|
REQUIRE("IDENT[hello]" == get_str(2));
|
||||||
|
REQUIRE("ASSIGN" == get_str(3));
|
||||||
|
REQUIRE("" == get_str(4));
|
||||||
|
}
|
||||||
|
|
|
@ -110,3 +110,15 @@ TEST_CASE_METHOD(ParserTest, "Parser_assertions")
|
||||||
test_node("PROG(ASSERT_STATIC_FAIL(EQ(ADD(INT[1],INT[1]),INT[2])))",
|
test_node("PROG(ASSERT_STATIC_FAIL(EQ(ADD(INT[1],INT[1]),INT[2])))",
|
||||||
"assert_static_fail 1 + 1 == 2");
|
"assert_static_fail 1 + 1 == 2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_vardecl")
|
||||||
|
{
|
||||||
|
test_node("PROG(VARDECL(IDENT[x],INT[34]))",
|
||||||
|
"let! x = 34");
|
||||||
|
|
||||||
|
test_node("PROG(CONSTDECL(IDENT[x],INT[34]))",
|
||||||
|
"let x = 34");
|
||||||
|
|
||||||
|
test_node("PROG(CONSTDECL(IDENT[_coucou],MUL(INT[6],INT[7])))",
|
||||||
|
"let _coucou = 6 * 7");
|
||||||
|
}
|
||||||
|
|
|
@ -16,11 +16,12 @@ public:
|
||||||
roza::StatusLog log;
|
roza::StatusLog log;
|
||||||
roza::Lexer lexer {log, loc};
|
roza::Lexer lexer {log, loc};
|
||||||
roza::Parser parser {lexer, log};
|
roza::Parser parser {lexer, log};
|
||||||
|
roza::SymTable sym;
|
||||||
roza::TypeResolver resolver {log};
|
roza::TypeResolver resolver {log};
|
||||||
|
|
||||||
lexer.scan(source);
|
lexer.scan(source);
|
||||||
auto node = parser.parse();
|
auto node = parser.parse();
|
||||||
return resolver.find(node);
|
return resolver.find(node, sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_ty(std::string const& source, std::shared_ptr<roza::Type> ty)
|
void test_ty(std::string const& source, std::shared_ptr<roza::Type> ty)
|
||||||
|
|
Loading…
Reference in New Issue