ADD: comparisons operators.
parent
08fc0d5d19
commit
50f66409b2
|
@ -4,7 +4,10 @@ EXPR ::= IMP
|
||||||
|
|
||||||
IMP ::= OR (imp OR)?
|
IMP ::= OR (imp OR)?
|
||||||
OR ::= AND (or AND)*
|
OR ::= AND (or AND)*
|
||||||
AND ::= TERM (and TERM)*
|
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)*
|
||||||
|
|
|
@ -33,6 +33,39 @@ namespace roza
|
||||||
prog->push_instr(OP_PUSH_CONST, prog->push_value(value));
|
prog->push_instr(OP_PUSH_CONST, prog->push_value(value));
|
||||||
} break;
|
} 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: {
|
case NODE_IMP: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog);
|
||||||
prog->push_instr(OP_IMP);
|
prog->push_instr(OP_IMP);
|
||||||
|
|
|
@ -8,6 +8,12 @@ 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_EQ, false},
|
||||||
|
{"!=", NODE_NE, false},
|
||||||
|
{"<=", NODE_LE, false},
|
||||||
|
{">=", NODE_GE, false},
|
||||||
|
{"<", NODE_LT, false},
|
||||||
|
{">", NODE_GT, false},
|
||||||
{"=>", NODE_IMP, false},
|
{"=>", NODE_IMP, false},
|
||||||
{"+", NODE_ADD, false},
|
{"+", NODE_ADD, false},
|
||||||
{"-", NODE_SUB, false},
|
{"-", NODE_SUB, false},
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
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_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_GE)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -117,6 +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();
|
auto root = parse_expr();
|
||||||
consume_or_nullptr(NODE_EOI);
|
consume_or_nullptr(NODE_EOI);
|
||||||
consume_all(NODE_EOI);
|
consume_all(NODE_EOI);
|
||||||
|
@ -161,9 +162,43 @@ namespace roza
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_and()
|
std::shared_ptr<Node> Parser::parse_and()
|
||||||
{
|
{
|
||||||
auto lhs = parse_term();
|
auto lhs = parse_eq();
|
||||||
|
|
||||||
while (type_is(NODE_AND))
|
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();
|
auto root = consume();
|
||||||
root->add_child(lhs);
|
root->add_child(lhs);
|
||||||
|
|
|
@ -35,6 +35,8 @@ namespace roza
|
||||||
std::shared_ptr<Node> parse_imp();
|
std::shared_ptr<Node> parse_imp();
|
||||||
std::shared_ptr<Node> parse_or();
|
std::shared_ptr<Node> parse_or();
|
||||||
std::shared_ptr<Node> parse_and();
|
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();
|
||||||
|
|
|
@ -23,6 +23,14 @@ namespace roza
|
||||||
case NODE_BOOL:
|
case NODE_BOOL:
|
||||||
break;
|
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_IMP:
|
||||||
case NODE_OR:
|
case NODE_OR:
|
||||||
case NODE_AND: {
|
case NODE_AND: {
|
||||||
|
@ -39,6 +47,10 @@ namespace roza
|
||||||
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
||||||
} break;
|
} 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:
|
||||||
|
|
|
@ -23,6 +23,12 @@ 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_IMP:
|
||||||
case NODE_AND:
|
case NODE_AND:
|
||||||
case NODE_OR:
|
case NODE_OR:
|
||||||
|
|
21
lib/VM.cpp
21
lib/VM.cpp
|
@ -25,6 +25,27 @@ namespace roza
|
||||||
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: {
|
case OP_IMP: {
|
||||||
apply_binop(program, [](auto lhs, auto rhs){
|
apply_binop(program, [](auto lhs, auto rhs){
|
||||||
bool a = lhs->as_bool();
|
bool a = lhs->as_bool();
|
||||||
|
|
|
@ -34,4 +34,26 @@ namespace roza
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ namespace roza
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
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_IMP), G(OP_EQ), G(OP_ILT), G(OP_IGT)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -77,3 +77,18 @@ TEST_CASE_METHOD(LexerTest, "Lexer_bool")
|
||||||
REQUIRE("" == get_str(6));
|
REQUIRE("" == get_str(6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_comparisons")
|
||||||
|
{
|
||||||
|
SECTION("nominal cases")
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -91,3 +91,12 @@ TEST_CASE_METHOD(ParserTest, "Parser_bool")
|
||||||
test_node("PROG(IMP(BOOL[true],BOOL[false]))",
|
test_node("PROG(IMP(BOOL[true],BOOL[false]))",
|
||||||
"true => 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");
|
||||||
|
}
|
||||||
|
|
|
@ -35,3 +35,10 @@ TEST_CASE_METHOD(StaticPassTest, "StaticPass_integer")
|
||||||
test_ok(" 43 ");
|
test_ok(" 43 ");
|
||||||
test_ko(" 43 + 7 * true");
|
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