Compare commits
No commits in common. "66283e23bb53457cd30a321b8a860c1175ab7501" and "051b696b26eaa7735996d0db490cde3198915f4b" have entirely different histories.
66283e23bb
...
051b696b26
|
@ -1,22 +1,11 @@
|
||||||
PROG ::= (INSTR (EOI+ INSTR)*)?
|
PROG ::= (INSTR (EOI INSTR)*)?
|
||||||
|
|
||||||
INSTR ::= EXPR
|
INSTR ::= EXPR
|
||||||
| assert EXPR
|
EXPR ::= TERM
|
||||||
| assert_static_fail EXPR
|
|
||||||
|
|
||||||
EXPR ::= IMP
|
|
||||||
|
|
||||||
IMP ::= OR (imp OR)?
|
|
||||||
OR ::= AND (or AND)*
|
|
||||||
AND ::= EQ (and EQ)*
|
|
||||||
|
|
||||||
EQ ::= CMP ((eq | ne) CMP)?
|
|
||||||
CMP ::= TERM ((lt | le | gt | ge) TERM)?
|
|
||||||
|
|
||||||
TERM ::= FACTOR ((add | sub) FACTOR)*
|
TERM ::= FACTOR ((add | sub) FACTOR)*
|
||||||
FACTOR ::= UNOP ((mul | div | mod) UNOP)*
|
FACTOR ::= UNOP ((mul | div | mod) UNOP)*
|
||||||
|
|
||||||
UNOP ::= (add | sub | not)? POW
|
UNOP ::= (add | sub)? POW
|
||||||
POW ::= GROUP (pow GROUP)?
|
POW ::= GROUP (pow GROUP)?
|
||||||
GROUP ::= BASE | opar EXPR cpar
|
GROUP ::= BASE | opar EXPR cpar
|
||||||
BASE ::= int | bool
|
BASE ::= int
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#include "Compiler.hpp"
|
#include "Compiler.hpp"
|
||||||
#include "lib/Node.hpp"
|
|
||||||
#include "lib/opcodes.hpp"
|
#include "lib/opcodes.hpp"
|
||||||
#include "StaticPass.hpp"
|
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
@ -25,96 +23,11 @@ namespace roza
|
||||||
{
|
{
|
||||||
switch (root->type())
|
switch (root->type())
|
||||||
{
|
{
|
||||||
case NODE_ASSERT: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_ASSERT);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_ASSERT_STATIC_FAIL: {
|
|
||||||
bool failed = false;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
StaticPass static_pass {m_log};
|
|
||||||
static_pass.check_children(root);
|
|
||||||
compile_children(root, prog);
|
|
||||||
|
|
||||||
failed = true;
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failed)
|
|
||||||
{
|
|
||||||
m_log.fatal(root->loc(), "static assertion failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
} 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));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_BOOL: {
|
|
||||||
auto value = std::make_shared<Value>(root->repr() == "true", root->loc());
|
|
||||||
prog->push_instr(OP_PUSH_CONST, prog->push_value(value));
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_EQ: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_EQ);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_NE: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_EQ);
|
|
||||||
prog->push_instr(OP_NOT);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_LT: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_ILT);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_GT: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_IGT);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_LE: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_IGT);
|
|
||||||
prog->push_instr(OP_NOT);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_GE: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_ILT);
|
|
||||||
prog->push_instr(OP_NOT);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_IMP: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_IMP);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_AND: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_AND);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_OR: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_OR);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_NOT: {
|
|
||||||
compile_children(root, prog);
|
|
||||||
prog->push_instr(OP_NOT);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_ADD: {
|
case NODE_ADD: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog);
|
||||||
prog->push_instr(OP_IADD);
|
prog->push_instr(OP_IADD);
|
||||||
|
|
|
@ -7,52 +7,15 @@ namespace roza
|
||||||
: m_log { log }
|
: m_log { log }
|
||||||
, m_loc { loc }
|
, m_loc { loc }
|
||||||
{
|
{
|
||||||
std::vector<std::tuple<std::string, NodeType, bool>> texts = {
|
|
||||||
{"==", NODE_EQ, false},
|
|
||||||
{"!=", NODE_NE, false},
|
|
||||||
{"<=", NODE_LE, false},
|
|
||||||
{">=", NODE_GE, false},
|
|
||||||
{"<", NODE_LT, false},
|
|
||||||
{">", NODE_GT, false},
|
|
||||||
{"=>", NODE_IMP, false},
|
|
||||||
{"+", NODE_ADD, false},
|
|
||||||
{"-", NODE_SUB, false},
|
|
||||||
{"*", NODE_MUL, false},
|
|
||||||
{"/", NODE_DIV, false},
|
|
||||||
{"%", NODE_MOD, false},
|
|
||||||
{"^", NODE_POW, false},
|
|
||||||
{"(", NODE_OPAR, false},
|
|
||||||
{")", NODE_CPAR, false},
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::tuple<std::string, NodeType, bool>> keywords = {
|
|
||||||
{"true", NODE_BOOL, true},
|
|
||||||
{"false", NODE_BOOL, true},
|
|
||||||
{"and", NODE_AND, false},
|
|
||||||
{"or", NODE_OR, false},
|
|
||||||
{"not", NODE_NOT, false},
|
|
||||||
{"assert_static_fail", NODE_ASSERT_STATIC_FAIL, 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));
|
||||||
|
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "+", NODE_ADD, false));
|
||||||
for (auto const& entry: keywords)
|
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "-", NODE_SUB, false));
|
||||||
{
|
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "*", NODE_MUL, false));
|
||||||
m_scanners.push_back(std::bind(&Lexer::scan_keyword, this,
|
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "/", NODE_DIV, false));
|
||||||
std::get<0>(entry),
|
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "%", NODE_MOD, false));
|
||||||
std::get<1>(entry),
|
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "^", NODE_POW, false));
|
||||||
std::get<2>(entry)));
|
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "(", NODE_OPAR, false));
|
||||||
}
|
m_scanners.push_back(std::bind(&Lexer::scan_text, this, ")", NODE_CPAR, false));
|
||||||
|
|
||||||
for (auto const& entry: texts)
|
|
||||||
{
|
|
||||||
m_scanners.push_back(std::bind(&Lexer::scan_text, this,
|
|
||||||
std::get<0>(entry),
|
|
||||||
std::get<1>(entry),
|
|
||||||
std::get<2>(entry)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,18 +118,6 @@ namespace roza
|
||||||
return m_nodes.at(index);
|
return m_nodes.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lexer::is_sep(size_t index) const
|
|
||||||
{
|
|
||||||
if (index >= m_source.size())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
char c = m_source[index];
|
|
||||||
|
|
||||||
return !std::isalnum(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
ScanInfo Lexer::scan_int() const
|
ScanInfo Lexer::scan_int() const
|
||||||
{
|
{
|
||||||
size_t cursor = m_cursor;
|
size_t cursor = m_cursor;
|
||||||
|
@ -209,20 +160,4 @@ namespace roza
|
||||||
m_cursor + text.size()
|
m_cursor + text.size()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanInfo Lexer::scan_keyword(std::string const& keyword,
|
|
||||||
NodeType type,
|
|
||||||
bool value) const
|
|
||||||
{
|
|
||||||
auto info = scan_text(keyword, type, value);
|
|
||||||
|
|
||||||
if (is_sep(info.cursor))
|
|
||||||
{
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ScanInfo {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,16 +38,10 @@ namespace roza
|
||||||
std::vector<std::shared_ptr<Node>> m_nodes;
|
std::vector<std::shared_ptr<Node>> m_nodes;
|
||||||
std::vector<scanner> m_scanners;
|
std::vector<scanner> m_scanners;
|
||||||
|
|
||||||
bool is_sep(size_t index) const;
|
|
||||||
|
|
||||||
ScanInfo scan_int() const;
|
ScanInfo scan_int() const;
|
||||||
ScanInfo scan_text(std::string const& text,
|
ScanInfo scan_text(std::string const& text,
|
||||||
NodeType type,
|
NodeType type,
|
||||||
bool value=false) const;
|
bool value=false) const;
|
||||||
|
|
||||||
ScanInfo scan_keyword(std::string const& keyword,
|
|
||||||
NodeType type,
|
|
||||||
bool value=false) const;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,7 @@
|
||||||
G(NODE_PROG), G(NODE_INSTR), G(NODE_EOI), \
|
G(NODE_PROG), G(NODE_INSTR), G(NODE_EOI), \
|
||||||
G(NODE_INT), G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), \
|
G(NODE_INT), G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), \
|
||||||
G(NODE_DIV), G(NODE_MOD), G(NODE_POW), G(NODE_OPAR), \
|
G(NODE_DIV), G(NODE_MOD), G(NODE_POW), G(NODE_OPAR), \
|
||||||
G(NODE_CPAR), G(NODE_UADD), G(NODE_USUB), G(NODE_BOOL), \
|
G(NODE_CPAR), G(NODE_UADD), G(NODE_USUB)
|
||||||
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_GE), G(NODE_ASSERT), G(NODE_ASSERT_STATIC_FAIL)
|
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
122
lib/Parser.cpp
122
lib/Parser.cpp
|
@ -1,6 +1,5 @@
|
||||||
#include "Parser.hpp"
|
#include "Parser.hpp"
|
||||||
#include "lib/Node.hpp"
|
#include "lib/Node.hpp"
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
@ -68,7 +67,6 @@ namespace roza
|
||||||
+ "', got '"
|
+ "', got '"
|
||||||
+ NodeTypeStr[type()]
|
+ NodeTypeStr[type()]
|
||||||
+ "'");
|
+ "'");
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,22 +117,7 @@ namespace roza
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_instr()
|
std::shared_ptr<Node> Parser::parse_instr()
|
||||||
{
|
{
|
||||||
consume_all(NODE_EOI);
|
auto root = parse_expr();
|
||||||
|
|
||||||
std::shared_ptr<Node> root;
|
|
||||||
|
|
||||||
if (type_is(NODE_ASSERT)
|
|
||||||
|| type_is(NODE_ASSERT_STATIC_FAIL))
|
|
||||||
{
|
|
||||||
root = consume();
|
|
||||||
root->add_child(parse_expr());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
root = parse_expr();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
consume_or_nullptr(NODE_EOI);
|
consume_or_nullptr(NODE_EOI);
|
||||||
consume_all(NODE_EOI);
|
consume_all(NODE_EOI);
|
||||||
|
|
||||||
|
@ -143,86 +126,7 @@ namespace roza
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_expr()
|
std::shared_ptr<Node> Parser::parse_expr()
|
||||||
{
|
{
|
||||||
return parse_imp();
|
return parse_term();
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_imp()
|
|
||||||
{
|
|
||||||
auto lhs = parse_or();
|
|
||||||
|
|
||||||
if (type_is(NODE_IMP))
|
|
||||||
{
|
|
||||||
auto root = consume();
|
|
||||||
root->add_child(lhs);
|
|
||||||
root->add_child(parse_or());
|
|
||||||
lhs = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_or()
|
|
||||||
{
|
|
||||||
auto lhs = parse_and();
|
|
||||||
|
|
||||||
while (type_is(NODE_OR))
|
|
||||||
{
|
|
||||||
auto root = consume();
|
|
||||||
root->add_child(lhs);
|
|
||||||
root->add_child(parse_and());
|
|
||||||
lhs = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_and()
|
|
||||||
{
|
|
||||||
auto lhs = parse_eq();
|
|
||||||
|
|
||||||
while (type_is(NODE_AND))
|
|
||||||
{
|
|
||||||
auto root = consume();
|
|
||||||
root->add_child(lhs);
|
|
||||||
root->add_child(parse_eq());
|
|
||||||
lhs = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_eq()
|
|
||||||
{
|
|
||||||
auto lhs = parse_cmp();
|
|
||||||
|
|
||||||
if (type_is(NODE_EQ)
|
|
||||||
|| type_is(NODE_NE))
|
|
||||||
{
|
|
||||||
auto root = consume();
|
|
||||||
root->add_child(lhs);
|
|
||||||
root->add_child(parse_cmp());
|
|
||||||
lhs = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_cmp()
|
|
||||||
{
|
|
||||||
auto lhs = parse_term();
|
|
||||||
|
|
||||||
if (type_is(NODE_LT)
|
|
||||||
|| type_is(NODE_LE)
|
|
||||||
|| type_is(NODE_GT)
|
|
||||||
|| type_is(NODE_GE))
|
|
||||||
{
|
|
||||||
auto root = consume();
|
|
||||||
root->add_child(lhs);
|
|
||||||
root->add_child(parse_term());
|
|
||||||
lhs = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lhs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_term()
|
std::shared_ptr<Node> Parser::parse_term()
|
||||||
|
@ -277,15 +181,6 @@ namespace roza
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_is(NODE_NOT))
|
|
||||||
{
|
|
||||||
auto root = std::make_shared<Node>(NODE_NOT, "", m_lexer.loc());
|
|
||||||
next();
|
|
||||||
|
|
||||||
root->add_child(parse_pow());
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parse_pow();
|
return parse_pow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,18 +214,7 @@ namespace roza
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_base()
|
std::shared_ptr<Node> Parser::parse_base()
|
||||||
{
|
{
|
||||||
if (type_is(NODE_INT)
|
return parse_int();
|
||||||
|| type_is(NODE_BOOL))
|
|
||||||
{
|
|
||||||
return consume();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.fatal(node()->loc(),
|
|
||||||
"unknown node '"
|
|
||||||
+ node()->string()
|
|
||||||
+ "'");
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_int()
|
std::shared_ptr<Node> Parser::parse_int()
|
||||||
|
|
|
@ -32,11 +32,6 @@ namespace roza
|
||||||
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_expr();
|
std::shared_ptr<Node> parse_expr();
|
||||||
std::shared_ptr<Node> parse_imp();
|
|
||||||
std::shared_ptr<Node> parse_or();
|
|
||||||
std::shared_ptr<Node> parse_and();
|
|
||||||
std::shared_ptr<Node> parse_eq();
|
|
||||||
std::shared_ptr<Node> parse_cmp();
|
|
||||||
std::shared_ptr<Node> parse_term();
|
std::shared_ptr<Node> parse_term();
|
||||||
std::shared_ptr<Node> parse_factor();
|
std::shared_ptr<Node> parse_factor();
|
||||||
std::shared_ptr<Node> parse_unop();
|
std::shared_ptr<Node> parse_unop();
|
||||||
|
|
|
@ -19,116 +19,43 @@ namespace roza
|
||||||
|
|
||||||
switch (root->type())
|
switch (root->type())
|
||||||
{
|
{
|
||||||
case NODE_ASSERT_STATIC_FAIL:
|
case NODE_INT: break;
|
||||||
case NODE_INT:
|
|
||||||
case NODE_BOOL:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NODE_EQ:
|
|
||||||
case NODE_NE: {
|
|
||||||
check_children(root);
|
|
||||||
auto lhs = resolver.find(root->child(0));
|
|
||||||
auto rhs = resolver.find(root->child(1));
|
|
||||||
check_types(root, lhs, rhs);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_IMP:
|
|
||||||
case NODE_OR:
|
|
||||||
case NODE_AND: {
|
|
||||||
check_children(root);
|
|
||||||
auto lhs = resolver.find(root->child(0));
|
|
||||||
auto rhs = resolver.find(root->child(1));
|
|
||||||
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
|
||||||
check_types(root, lhs, rhs);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_ASSERT:
|
|
||||||
case NODE_NOT: {
|
|
||||||
check_children(root);
|
|
||||||
auto lhs = resolver.find(root->child(0));
|
|
||||||
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_LT:
|
|
||||||
case NODE_LE:
|
|
||||||
case NODE_GT:
|
|
||||||
case NODE_GE:
|
|
||||||
case NODE_ADD:
|
case NODE_ADD:
|
||||||
case NODE_SUB:
|
case NODE_SUB:
|
||||||
case NODE_MUL:
|
case NODE_MUL:
|
||||||
case NODE_DIV:
|
case NODE_DIV:
|
||||||
case NODE_MOD:
|
case NODE_MOD:
|
||||||
case NODE_POW: {
|
case NODE_POW: {
|
||||||
check_children(root);
|
|
||||||
auto lhs = resolver.find(root->child(0));
|
auto lhs = resolver.find(root->child(0));
|
||||||
auto rhs = resolver.find(root->child(1));
|
auto rhs = resolver.find(root->child(1));
|
||||||
check_types(root, lhs, std::make_shared<Type>(TY_INT));
|
|
||||||
check_types(root, lhs, rhs);
|
if (!lhs->equals(*rhs))
|
||||||
|
{
|
||||||
|
m_log.fatal(root->loc(),
|
||||||
|
std::string()
|
||||||
|
+ "type mismatch, expected '"
|
||||||
|
+ lhs->string()
|
||||||
|
+ "', got '"
|
||||||
|
+ rhs->string()
|
||||||
|
+ "'");
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_UADD:
|
case NODE_UADD:
|
||||||
case NODE_USUB: {
|
case NODE_USUB: {
|
||||||
check_children(root);
|
|
||||||
auto lhs = resolver.find(root->child(0));
|
|
||||||
check_types(root, lhs, std::make_shared<Type>(TY_INT));
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_PROG: {
|
case NODE_PROG: {
|
||||||
check_children(root);
|
for (size_t i=0; i<root->size(); i++)
|
||||||
|
{
|
||||||
|
check(root->child(i));
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
m_log.fatal(root->loc(), "cannot check node '" + root->string() + "'");
|
m_log.fatal(root->loc(), "cannot check node '" + root->string() + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StaticPass::check_children(std::shared_ptr<Node> root)
|
|
||||||
{
|
|
||||||
for (size_t i=0; i<root->size(); i++)
|
|
||||||
{
|
|
||||||
check(root->child(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StaticPass::check_types(std::shared_ptr<Node> root,
|
|
||||||
std::shared_ptr<Type> lhs,
|
|
||||||
std::shared_ptr<Type> rhs)
|
|
||||||
{
|
|
||||||
if (!lhs->equals(*rhs))
|
|
||||||
{
|
|
||||||
m_log.fatal(root->loc(),
|
|
||||||
std::string()
|
|
||||||
+ "type mismatch, expected '"
|
|
||||||
+ lhs->string()
|
|
||||||
+ "', got '"
|
|
||||||
+ rhs->string()
|
|
||||||
+ "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StaticPass::check_types(std::shared_ptr<Node> root,
|
|
||||||
std::shared_ptr<Type> lhs,
|
|
||||||
std::vector<std::shared_ptr<Type>> const& rhs)
|
|
||||||
{
|
|
||||||
for (auto const& ty: rhs)
|
|
||||||
{
|
|
||||||
if (lhs->equals(*ty))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
|
|
||||||
ss << "type mismatch, got '" << lhs->string() << "'";
|
|
||||||
ss << "candidates are:" << std::endl;
|
|
||||||
|
|
||||||
for (auto ty: rhs)
|
|
||||||
{
|
|
||||||
ss << "\t-> " << ty->string() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.fatal(root->loc(), ss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "StatusLog.hpp"
|
#include "StatusLog.hpp"
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "Type.hpp"
|
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
@ -15,18 +14,9 @@ namespace roza
|
||||||
virtual ~StaticPass();
|
virtual ~StaticPass();
|
||||||
|
|
||||||
void check(std::shared_ptr<Node> root);
|
void check(std::shared_ptr<Node> root);
|
||||||
void check_children(std::shared_ptr<Node> root);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StatusLog& m_log;
|
StatusLog& m_log;
|
||||||
|
|
||||||
void check_types(std::shared_ptr<Node> root,
|
|
||||||
std::shared_ptr<Type> lhs,
|
|
||||||
std::shared_ptr<Type> rhs);
|
|
||||||
|
|
||||||
void check_types(std::shared_ptr<Node> root,
|
|
||||||
std::shared_ptr<Type> lhs,
|
|
||||||
std::vector<std::shared_ptr<Type>> const& rhs);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,20 +23,6 @@ namespace roza
|
||||||
return std::make_shared<Type>(BaseType::TY_INT);
|
return std::make_shared<Type>(BaseType::TY_INT);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_EQ:
|
|
||||||
case NODE_NE:
|
|
||||||
case NODE_LT:
|
|
||||||
case NODE_LE:
|
|
||||||
case NODE_GT:
|
|
||||||
case NODE_GE:
|
|
||||||
case NODE_IMP:
|
|
||||||
case NODE_AND:
|
|
||||||
case NODE_OR:
|
|
||||||
case NODE_NOT:
|
|
||||||
case NODE_BOOL: {
|
|
||||||
return std::make_shared<Type>(BaseType::TY_BOOL);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_ADD:
|
case NODE_ADD:
|
||||||
case NODE_SUB:
|
case NODE_SUB:
|
||||||
case NODE_MUL:
|
case NODE_MUL:
|
||||||
|
|
67
lib/VM.cpp
67
lib/VM.cpp
|
@ -19,76 +19,12 @@ namespace roza
|
||||||
{
|
{
|
||||||
switch (program->opcode(m_pc))
|
switch (program->opcode(m_pc))
|
||||||
{
|
{
|
||||||
case OP_ASSERT: {
|
|
||||||
auto value = program->value(pop());
|
|
||||||
|
|
||||||
if (!value->as_bool())
|
|
||||||
{
|
|
||||||
m_log.fatal(value->loc(), "assertion failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pc++;
|
|
||||||
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_PUSH_CONST: {
|
case OP_PUSH_CONST: {
|
||||||
param_t param = *program->param(m_pc);
|
param_t param = *program->param(m_pc);
|
||||||
push(param);
|
push(param);
|
||||||
m_pc++;
|
m_pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OP_EQ: {
|
|
||||||
apply_binop(program, [](auto lhs, auto rhs){
|
|
||||||
return std::make_shared<Value>(lhs->equals(*rhs),
|
|
||||||
lhs->loc());
|
|
||||||
});
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_ILT: {
|
|
||||||
apply_binop(program, [](auto lhs, auto rhs){
|
|
||||||
return std::make_shared<Value>(lhs->as_int() < rhs->as_int(),
|
|
||||||
lhs->loc());
|
|
||||||
});
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_IGT: {
|
|
||||||
apply_binop(program, [](auto lhs, auto rhs){
|
|
||||||
return std::make_shared<Value>(lhs->as_int() > rhs->as_int(),
|
|
||||||
lhs->loc());
|
|
||||||
});
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_IMP: {
|
|
||||||
apply_binop(program, [](auto lhs, auto rhs){
|
|
||||||
bool a = lhs->as_bool();
|
|
||||||
bool b = rhs->as_bool();
|
|
||||||
|
|
||||||
return std::make_shared<Value>(!a || b,
|
|
||||||
lhs->loc());
|
|
||||||
});
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_AND: {
|
|
||||||
apply_binop(program, [](auto lhs, auto rhs){
|
|
||||||
return std::make_shared<Value>(lhs->as_bool() && rhs->as_bool(),
|
|
||||||
lhs->loc());
|
|
||||||
});
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_OR: {
|
|
||||||
apply_binop(program, [](auto lhs, auto rhs){
|
|
||||||
return std::make_shared<Value>(lhs->as_bool() || rhs->as_bool(),
|
|
||||||
lhs->loc());
|
|
||||||
});
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_NOT: {
|
|
||||||
apply_unop(program, [](auto lhs){
|
|
||||||
return std::make_shared<Value>(!lhs->as_bool(),
|
|
||||||
lhs->loc());
|
|
||||||
});
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_IADD: {
|
case OP_IADD: {
|
||||||
apply_binop(program, [](auto lhs, auto rhs){
|
apply_binop(program, [](auto lhs, auto rhs){
|
||||||
return std::make_shared<Value>(lhs->as_int() + rhs->as_int(),
|
return std::make_shared<Value>(lhs->as_int() + rhs->as_int(),
|
||||||
|
@ -126,8 +62,7 @@ namespace roza
|
||||||
|
|
||||||
case OP_IPOW: {
|
case OP_IPOW: {
|
||||||
apply_binop(program, [](auto lhs, auto rhs){
|
apply_binop(program, [](auto lhs, auto rhs){
|
||||||
return std::make_shared<Value>(static_cast<int>(std::pow(lhs->as_int(),
|
return std::make_shared<Value>(std::pow(lhs->as_int(), rhs->as_int()),
|
||||||
rhs->as_int())),
|
|
||||||
lhs->loc());
|
lhs->loc());
|
||||||
});
|
});
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -9,13 +9,6 @@ namespace roza
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*explicit*/ Value::Value(bool value, SrcLoc loc)
|
|
||||||
: m_type { std::make_shared<Type>(BaseType::TY_BOOL) }
|
|
||||||
, m_bool_val { value }
|
|
||||||
, m_loc { loc }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*virtual*/ Value::~Value()
|
/*virtual*/ Value::~Value()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -27,33 +20,6 @@ namespace roza
|
||||||
return std::to_string(m_int_val);
|
return std::to_string(m_int_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_type->equals(TY_BOOL))
|
|
||||||
{
|
|
||||||
return m_bool_val ? "true" : "false";
|
|
||||||
}
|
|
||||||
|
|
||||||
assert("cannot stringify unknown value " && 0);
|
assert("cannot stringify unknown value " && 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::equals(Value const& rhs) const
|
|
||||||
{
|
|
||||||
if (!m_type->equals(*rhs.m_type))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (m_type->base())
|
|
||||||
{
|
|
||||||
case TY_BOOL: {
|
|
||||||
return as_bool() == rhs.as_bool();
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case TY_INT: {
|
|
||||||
return as_int() == rhs.as_int();
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert("value equals: base type not found" && 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,22 +11,16 @@ namespace roza
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Value(int value, SrcLoc loc);
|
explicit Value(int value, SrcLoc loc);
|
||||||
explicit Value(bool 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; }
|
|
||||||
|
|
||||||
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;
|
||||||
bool equals(Value const& rhs) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Type> m_type;
|
std::shared_ptr<Type> m_type;
|
||||||
int m_int_val;
|
int m_int_val;
|
||||||
bool m_bool_val;
|
|
||||||
SrcLoc m_loc;
|
SrcLoc m_loc;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
G(OP_PUSH_CONST), \
|
G(OP_PUSH_CONST), \
|
||||||
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_IMP), G(OP_EQ), G(OP_ILT), G(OP_IGT), G(OP_ASSERT)
|
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
OK=0
|
|
||||||
KO=0
|
|
||||||
TOTAL=0
|
|
||||||
|
|
||||||
for file in $(find . -name "test_*.roza" | sort)
|
|
||||||
do
|
|
||||||
roza $file
|
|
||||||
RET="$?"
|
|
||||||
NAME=$(basename "$file" | cut -d '.' -f1)
|
|
||||||
|
|
||||||
echo -en "\e[34m$NAME...\e[0m"
|
|
||||||
|
|
||||||
if [ "$RET" == 0 ]
|
|
||||||
then
|
|
||||||
echo -e " \e[32mok\e[0m"
|
|
||||||
OK=$(($OK + 1))
|
|
||||||
else
|
|
||||||
echo -e " \e[31mko\e[0m"
|
|
||||||
KO=$(($KO + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
TOTAL=$(($TOTAL + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $OK -eq $TOTAL ]
|
|
||||||
then
|
|
||||||
echo -e "\e[32m=== all tests passed ($OK) ===\e[0m"
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
echo -e "\e[31m=== some tests failed ($KO) ===\e[0m"
|
|
||||||
exit -1
|
|
||||||
fi
|
|
|
@ -1,30 +0,0 @@
|
||||||
assert true == true
|
|
||||||
assert false == false
|
|
||||||
|
|
||||||
assert true == (true and true)
|
|
||||||
assert false == (true and false)
|
|
||||||
assert false == (false and true)
|
|
||||||
assert false == (false and false)
|
|
||||||
|
|
||||||
assert true == (true or true)
|
|
||||||
assert true == (true or false)
|
|
||||||
assert true == (false or true)
|
|
||||||
assert false == (false or false)
|
|
||||||
|
|
||||||
assert false == not true
|
|
||||||
assert true == not false
|
|
||||||
|
|
||||||
assert true == (true => true)
|
|
||||||
assert false == (true => false)
|
|
||||||
assert true == (false => true)
|
|
||||||
assert true == (false => false)
|
|
||||||
|
|
||||||
assert (false or true) == (not (true and false))
|
|
||||||
|
|
||||||
assert_static_fail 1 and true
|
|
||||||
assert_static_fail false and 7
|
|
||||||
assert_static_fail 1 or true
|
|
||||||
assert_static_fail false or 7
|
|
||||||
assert_static_fail not 9
|
|
||||||
assert_static_fail 3 => true
|
|
||||||
assert_static_fail true => 7
|
|
|
@ -1,54 +0,0 @@
|
||||||
assert 5 == 5
|
|
||||||
assert 3 != 5
|
|
||||||
assert -9 == -10 + 1
|
|
||||||
assert -4 == 3 - 7
|
|
||||||
assert 4 == 7 - 3
|
|
||||||
assert 21 == 3 * 7
|
|
||||||
assert 3 == 21 / 7
|
|
||||||
assert 2 == 21 / 8
|
|
||||||
assert 3 == 7 % 4
|
|
||||||
assert 128 == 2 ^ 7
|
|
||||||
assert -128 == -2 ^ 7
|
|
||||||
assert 3 == +3
|
|
||||||
assert 0 - 7 == -7
|
|
||||||
|
|
||||||
assert 7 == 1 + 2 * 3
|
|
||||||
assert 9 == (1 + 2) * 3
|
|
||||||
|
|
||||||
assert true == 5 < 6
|
|
||||||
assert false == 5 < 5
|
|
||||||
assert false == 5 < 4
|
|
||||||
assert true == 5 <= 6
|
|
||||||
assert true == 5 <= 5
|
|
||||||
assert false == 5 <= 4
|
|
||||||
assert false == 5 > 6
|
|
||||||
assert false == 5 > 5
|
|
||||||
assert true == 5 > 4
|
|
||||||
assert false == 5 >= 6
|
|
||||||
assert true == 5 >= 5
|
|
||||||
assert true == 5 >= 4
|
|
||||||
|
|
||||||
assert_static_fail 5 + true
|
|
||||||
assert_static_fail 5 - true
|
|
||||||
assert_static_fail 5 * true
|
|
||||||
assert_static_fail 5 / true
|
|
||||||
assert_static_fail 5 % true
|
|
||||||
assert_static_fail 5 ^ true
|
|
||||||
assert_static_fail -true
|
|
||||||
assert_static_fail +true
|
|
||||||
|
|
||||||
assert_static_fail true + 9
|
|
||||||
assert_static_fail true - (4 + 1)
|
|
||||||
assert_static_fail true * 7
|
|
||||||
assert_static_fail true / 3
|
|
||||||
assert_static_fail true % 15
|
|
||||||
assert_static_fail true ^ 2
|
|
||||||
|
|
||||||
assert_static_fail true > 1
|
|
||||||
assert_static_fail 2 > false
|
|
||||||
assert_static_fail true < 1
|
|
||||||
assert_static_fail 2 < false
|
|
||||||
assert_static_fail true >= 1
|
|
||||||
assert_static_fail 2 >= false
|
|
||||||
assert_static_fail true <= 1
|
|
||||||
assert_static_fail 2 <= false
|
|
92
src/main.cpp
92
src/main.cpp
|
@ -33,61 +33,51 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
if (args.inputs().size() > 0)
|
if (args.inputs().size() > 0)
|
||||||
{
|
{
|
||||||
try
|
auto source = loader.load(args.inputs()[0]);
|
||||||
|
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"))
|
||||||
{
|
{
|
||||||
auto source = loader.load(args.inputs()[0]);
|
std::cout << "Tokens:" << std::endl;
|
||||||
roza::SrcLoc loc {args.inputs()[0]};
|
for (size_t i=0; i<lexer->size(); i++)
|
||||||
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;
|
std::cout << "\t" << lexer->get_or_nullptr(i)->string() << 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)
|
|
||||||
{
|
|
||||||
std::cerr << err.what() << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,42 +55,3 @@ TEST_CASE_METHOD(LexerTest, "Lexer_int_arith")
|
||||||
REQUIRE("CPAR" == get_str(7));
|
REQUIRE("CPAR" == get_str(7));
|
||||||
REQUIRE("" == get_str(8));
|
REQUIRE("" == get_str(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(LexerTest, "Lexer_keywords")
|
|
||||||
{
|
|
||||||
REQUIRE_THROWS(m_lexer.scan(" andor "));
|
|
||||||
REQUIRE_NOTHROW(m_lexer.scan(" and+ "));
|
|
||||||
REQUIRE_NOTHROW(m_lexer.scan(" (and) "));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(LexerTest, "Lexer_bool")
|
|
||||||
{
|
|
||||||
m_lexer.scan("and or not true false =>");
|
|
||||||
REQUIRE("AND" == get_str(0));
|
|
||||||
REQUIRE("OR" == get_str(1));
|
|
||||||
REQUIRE("NOT" == get_str(2));
|
|
||||||
REQUIRE("BOOL[true]" == get_str(3));
|
|
||||||
REQUIRE("BOOL[false]" == get_str(4));
|
|
||||||
REQUIRE("IMP" == get_str(5));
|
|
||||||
REQUIRE("" == get_str(6));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(LexerTest, "Lexer_comparisons")
|
|
||||||
{
|
|
||||||
m_lexer.scan("== != < > <= >=");
|
|
||||||
REQUIRE("EQ" == get_str(0));
|
|
||||||
REQUIRE("NE" == get_str(1));
|
|
||||||
REQUIRE("LT" == get_str(2));
|
|
||||||
REQUIRE("GT" == get_str(3));
|
|
||||||
REQUIRE("LE" == get_str(4));
|
|
||||||
REQUIRE("GE" == get_str(5));
|
|
||||||
REQUIRE("" == get_str(6));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(LexerTest, "Lexer_asserts")
|
|
||||||
{
|
|
||||||
m_lexer.scan(" assert assert_static_fail ");
|
|
||||||
REQUIRE("ASSERT" == get_str(0));
|
|
||||||
REQUIRE("ASSERT_STATIC_FAIL" == get_str(1));
|
|
||||||
REQUIRE("" == get_str(2));
|
|
||||||
}
|
|
||||||
|
|
|
@ -70,43 +70,3 @@ TEST_CASE_METHOD(ParserTest, "Parser_int_arith")
|
||||||
|
|
||||||
test_node("PROG(USUB(POW(INT[2],INT[7])))", " -2^7 ");
|
test_node("PROG(USUB(POW(INT[2],INT[7])))", " -2^7 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(ParserTest, "Parser_bool")
|
|
||||||
{
|
|
||||||
test_node("PROG(BOOL[true])",
|
|
||||||
"true");
|
|
||||||
|
|
||||||
test_node("PROG(AND(BOOL[true],BOOL[false]))",
|
|
||||||
"true and false");
|
|
||||||
|
|
||||||
test_node("PROG(OR(BOOL[true],BOOL[false]))",
|
|
||||||
"true or false");
|
|
||||||
|
|
||||||
test_node("PROG(NOT(BOOL[false]))",
|
|
||||||
"not false");
|
|
||||||
|
|
||||||
test_node("PROG(NOT(OR(BOOL[false],BOOL[true])))",
|
|
||||||
"not (false or true)");
|
|
||||||
|
|
||||||
test_node("PROG(IMP(BOOL[true],BOOL[false]))",
|
|
||||||
"true => false");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(ParserTest, "Parser_comparisons")
|
|
||||||
{
|
|
||||||
test_node("PROG(LT(INT[5],INT[3]))",
|
|
||||||
"5 < 3");
|
|
||||||
|
|
||||||
test_node("PROG(EQ(LE(INT[5],INT[3]),BOOL[false]))",
|
|
||||||
"5 <= 3 == false");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(ParserTest, "Parser_assertions")
|
|
||||||
{
|
|
||||||
test_node("PROG(ASSERT(EQ(ADD(INT[1],INT[1]),INT[2])))",
|
|
||||||
"assert 1 + 1 == 2");
|
|
||||||
|
|
||||||
test_node("PROG(ASSERT_STATIC_FAIL(EQ(ADD(INT[1],INT[1]),INT[2])))",
|
|
||||||
"assert_static_fail 1 + 1 == 2");
|
|
||||||
}
|
|
||||||
|
|
|
@ -33,12 +33,4 @@ protected:
|
||||||
TEST_CASE_METHOD(StaticPassTest, "StaticPass_integer")
|
TEST_CASE_METHOD(StaticPassTest, "StaticPass_integer")
|
||||||
{
|
{
|
||||||
test_ok(" 43 ");
|
test_ok(" 43 ");
|
||||||
test_ko(" 43 + 7 * true");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(StaticPassTest, "StaticPass_cmp")
|
|
||||||
{
|
|
||||||
test_ok(" 43 < 12 ");
|
|
||||||
test_ko(" 3 == true");
|
|
||||||
test_ko(" 2 > false");
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue