ADD: comparisons operators.

main
bog 2023-08-31 11:37:13 +02:00
parent 08fc0d5d19
commit 50f66409b2
15 changed files with 178 additions and 4 deletions

View File

@ -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)*

View File

@ -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);

View File

@ -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},

View File

@ -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
{ {

View File

@ -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);

View File

@ -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();

View File

@ -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:

View File

@ -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:

View File

@ -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();

View File

@ -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);
}
}
} }

View File

@ -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;

View File

@ -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
{ {

View File

@ -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));
}
}

View File

@ -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");
}

View File

@ -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");
}