✨ comparison operators.
parent
f0fa844c8a
commit
f1b82208ce
|
@ -5,7 +5,9 @@ EXPR ::=
|
|||
ASSERT ::= (assert_eq|assert_ne) tuple
|
||||
IN ::= OR (in OR)?
|
||||
OR ::= AND (or AND)*
|
||||
AND ::= TERM (and TERM)*
|
||||
AND ::= EQNE (and EQNE)*
|
||||
EQNE ::= CMP ((eq|ne) CMP)?
|
||||
CMP ::= TERM ((lt|le|gt|ge) TERM)?
|
||||
TERM ::= FACTOR ((add|sub) FACTOR)*
|
||||
FACTOR ::= USUB ((mul|div|mod) USUB)*
|
||||
USUB ::= sub* NOT
|
||||
|
|
|
@ -8,7 +8,8 @@ G(OP_PUSH), G(OP_POP), \
|
|||
G(OP_ADD), G(OP_SUB), G(OP_USUB), G(OP_MUL), \
|
||||
G(OP_DIV), G(OP_POW), G(OP_MOD), G(OP_MK_TUPLE), \
|
||||
G(OP_ASSERT_EQ), G(OP_ASSERT_NE), G(OP_BRF), G(OP_BR), \
|
||||
G(OP_NOT), G(OP_IN), G(OP_INDEX)
|
||||
G(OP_NOT), G(OP_IN), G(OP_INDEX), G(OP_EQ), G(OP_LT), \
|
||||
G(OP_GT)
|
||||
|
||||
CCM_ENUM_H(Opcode, OPCODES);
|
||||
|
||||
|
|
69
lib/ccm.c
69
lib/ccm.c
|
@ -84,6 +84,13 @@ CCM ccm_from_value(ccm_t* self, value_t* value)
|
|||
}
|
||||
}
|
||||
|
||||
value_t* ccm_to_value(ccm_t* self, CCM value)
|
||||
{
|
||||
assert(self);
|
||||
assert(value < self->values.size);
|
||||
return (value_t*) self->values.data[value];
|
||||
}
|
||||
|
||||
int ccm_is_num(ccm_t* self, CCM value)
|
||||
{
|
||||
value_t const* val = self->values.data[value];
|
||||
|
@ -386,3 +393,65 @@ void ccm_not(ccm_t* self)
|
|||
|
||||
ccm_push(self, ccm_to_boolean(self, !lhs, line));
|
||||
}
|
||||
|
||||
void ccm_eq(ccm_t* self)
|
||||
{
|
||||
CCM ccm_rhs = ccm_pop(self);
|
||||
CCM ccm_lhs = ccm_pop(self);
|
||||
|
||||
value_t* lhs = ccm_to_value(self, ccm_lhs);
|
||||
value_t* rhs = ccm_to_value(self, ccm_rhs);
|
||||
int line = ((value_t*) self->values.data[ccm_lhs])->line;
|
||||
|
||||
int eq = value_equals(lhs, rhs);
|
||||
ccm_push(self, ccm_to_boolean(self, eq, line));
|
||||
}
|
||||
|
||||
void ccm_ne(ccm_t* self)
|
||||
{
|
||||
CCM ccm_rhs = ccm_pop(self);
|
||||
CCM ccm_lhs = ccm_pop(self);
|
||||
|
||||
value_t* lhs = ccm_to_value(self, ccm_lhs);
|
||||
value_t* rhs = ccm_to_value(self, ccm_rhs);
|
||||
int line = ((value_t*) self->values.data[ccm_lhs])->line;
|
||||
|
||||
int eq = value_equals(lhs, rhs);
|
||||
ccm_push(self, ccm_to_boolean(self, !eq, line));
|
||||
}
|
||||
|
||||
void ccm_lt(ccm_t* self)
|
||||
{
|
||||
CCM ccm_rhs = ccm_pop(self);
|
||||
CCM ccm_lhs = ccm_pop(self);
|
||||
|
||||
double lhs = ccm_from_num(self, ccm_lhs);
|
||||
double rhs = ccm_from_num(self, ccm_rhs);
|
||||
int line = ((value_t*) self->values.data[ccm_lhs])->line;
|
||||
|
||||
ccm_push(self, ccm_to_boolean(self, lhs < rhs, line));
|
||||
}
|
||||
|
||||
void ccm_le(ccm_t* self)
|
||||
{
|
||||
ccm_gt(self);
|
||||
ccm_not(self);
|
||||
}
|
||||
|
||||
void ccm_gt(ccm_t* self)
|
||||
{
|
||||
CCM ccm_rhs = ccm_pop(self);
|
||||
CCM ccm_lhs = ccm_pop(self);
|
||||
|
||||
double lhs = ccm_from_num(self, ccm_lhs);
|
||||
double rhs = ccm_from_num(self, ccm_rhs);
|
||||
int line = ((value_t*) self->values.data[ccm_lhs])->line;
|
||||
|
||||
ccm_push(self, ccm_to_boolean(self, lhs > rhs, line));
|
||||
}
|
||||
|
||||
void ccm_ge(ccm_t* self)
|
||||
{
|
||||
ccm_lt(self);
|
||||
ccm_not(self);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ void ccm_free(ccm_t* self);
|
|||
size_t ccm_str(ccm_t* self, char* buffer, size_t size);
|
||||
|
||||
CCM ccm_from_value(ccm_t* self, value_t* value);
|
||||
value_t* ccm_to_value(ccm_t* self, CCM value);
|
||||
|
||||
int ccm_is_num(ccm_t* self, CCM value);
|
||||
double ccm_from_num(ccm_t* self, CCM value);
|
||||
|
@ -51,4 +52,11 @@ void ccm_mod(ccm_t* self);
|
|||
void ccm_pow(ccm_t* self);
|
||||
void ccm_not(ccm_t* self);
|
||||
|
||||
void ccm_eq(ccm_t* self);
|
||||
void ccm_ne(ccm_t* self);
|
||||
void ccm_lt(ccm_t* self);
|
||||
void ccm_le(ccm_t* self);
|
||||
void ccm_gt(ccm_t* self);
|
||||
void ccm_ge(ccm_t* self);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,45 @@ void compiler_compile(compiler_t* self,
|
|||
|
||||
switch (node->kind)
|
||||
{
|
||||
case NODE_LT: {
|
||||
compiler_compile(self, node->children.data[0], prog);
|
||||
compiler_compile(self, node->children.data[1], prog);
|
||||
prog_add_instr(prog, OP_LT, CCM_NO_PARAM);
|
||||
} break;
|
||||
|
||||
case NODE_LE: {
|
||||
compiler_compile(self, node->children.data[0], prog);
|
||||
compiler_compile(self, node->children.data[1], prog);
|
||||
prog_add_instr(prog, OP_GT, CCM_NO_PARAM);
|
||||
prog_add_instr(prog, OP_NOT, CCM_NO_PARAM);
|
||||
} break;
|
||||
|
||||
case NODE_GT: {
|
||||
compiler_compile(self, node->children.data[0], prog);
|
||||
compiler_compile(self, node->children.data[1], prog);
|
||||
prog_add_instr(prog, OP_GT, CCM_NO_PARAM);
|
||||
} break;
|
||||
|
||||
case NODE_GE: {
|
||||
compiler_compile(self, node->children.data[0], prog);
|
||||
compiler_compile(self, node->children.data[1], prog);
|
||||
prog_add_instr(prog, OP_LT, CCM_NO_PARAM);
|
||||
prog_add_instr(prog, OP_NOT, CCM_NO_PARAM);
|
||||
} break;
|
||||
|
||||
case NODE_EQ: {
|
||||
compiler_compile(self, node->children.data[0], prog);
|
||||
compiler_compile(self, node->children.data[1], prog);
|
||||
prog_add_instr(prog, OP_EQ, CCM_NO_PARAM);
|
||||
} break;
|
||||
|
||||
case NODE_NE: {
|
||||
compiler_compile(self, node->children.data[0], prog);
|
||||
compiler_compile(self, node->children.data[1], prog);
|
||||
prog_add_instr(prog, OP_EQ, CCM_NO_PARAM);
|
||||
prog_add_instr(prog, OP_NOT, CCM_NO_PARAM);
|
||||
} break;
|
||||
|
||||
case NODE_INDEX: {
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
|
|
15
lib/exec.c
15
lib/exec.c
|
@ -44,6 +44,21 @@ void exec_instr(exec_t* self,
|
|||
|
||||
switch (op)
|
||||
{
|
||||
case OP_EQ: {
|
||||
ccm_eq(ccm);
|
||||
self->pc++;
|
||||
} break;
|
||||
|
||||
case OP_LT: {
|
||||
ccm_lt(ccm);
|
||||
self->pc++;
|
||||
} break;
|
||||
|
||||
case OP_GT: {
|
||||
ccm_gt(ccm);
|
||||
self->pc++;
|
||||
} break;
|
||||
|
||||
case OP_INDEX: {
|
||||
CCM ccm_target = ccm_pop(ccm);
|
||||
|
||||
|
|
|
@ -15,6 +15,12 @@ void lexer_init(lexer_t* self)
|
|||
str_init(&self->separators);
|
||||
|
||||
vec_init(&self->texts);
|
||||
lexer_add_text(self, "<>", NODE_NE);
|
||||
lexer_add_text(self, "==", NODE_EQ);
|
||||
lexer_add_text(self, "<=", NODE_LE);
|
||||
lexer_add_text(self, ">=", NODE_GE);
|
||||
lexer_add_text(self, "<", NODE_LT);
|
||||
lexer_add_text(self, ">", NODE_GT);
|
||||
lexer_add_text(self, ",", NODE_COMMA);
|
||||
lexer_add_text(self, "(", NODE_OPAR);
|
||||
lexer_add_text(self, ")", NODE_CPAR);
|
||||
|
|
|
@ -12,7 +12,8 @@ G(NODE_DIV), G(NODE_MOD), G(NODE_COMMA), G(NODE_TUPLE), \
|
|||
G(NODE_ASSERT_EQ), G(NODE_ASSERT_NE), G(NODE_BOOL), \
|
||||
G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IN), \
|
||||
G(NODE_OSQUARE), G(NODE_CSQUARE), G(NODE_INDEX), \
|
||||
G(NODE_STR)
|
||||
G(NODE_STR), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
|
||||
G(NODE_GE), G(NODE_EQ), G(NODE_NE)
|
||||
|
||||
CCM_ENUM_H(NodeKind, NODE_KIND);
|
||||
|
||||
|
|
62
lib/parser.c
62
lib/parser.c
|
@ -229,7 +229,7 @@ node_t* parser_try_new_or(parser_t* self)
|
|||
node_t* parser_try_new_and(parser_t* self)
|
||||
{
|
||||
assert(self);
|
||||
node_t* lhs = CCM_TRY(parser_try_new_term);
|
||||
node_t* lhs = CCM_TRY(parser_try_new_eqne);
|
||||
if (!lhs) { return NULL; }
|
||||
|
||||
while (lexer_peek_kind(self->lexer, NODE_AND, 0))
|
||||
|
@ -239,7 +239,7 @@ node_t* parser_try_new_and(parser_t* self)
|
|||
node_init(node, NODE_AND, "", lhs->line);
|
||||
|
||||
node_push_new_child(node, lhs);
|
||||
node_t* rhs = CCM_TRY(parser_try_new_term);
|
||||
node_t* rhs = CCM_TRY(parser_try_new_eqne);
|
||||
|
||||
if (!rhs)
|
||||
{
|
||||
|
@ -256,6 +256,64 @@ node_t* parser_try_new_and(parser_t* self)
|
|||
return lhs;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_eqne(parser_t* self)
|
||||
{
|
||||
assert(self);
|
||||
node_t* lhs = CCM_TRY(parser_try_new_cmp);
|
||||
if (!lhs) { return NULL; }
|
||||
|
||||
if (lexer_peek_kind(self->lexer, NODE_EQ, 0)
|
||||
|| lexer_peek_kind(self->lexer, NODE_NE, 0))
|
||||
{
|
||||
node_t* node = lexer_try_new_next(self->lexer);
|
||||
|
||||
node_t* rhs = CCM_TRY(parser_try_new_cmp);
|
||||
|
||||
if (!rhs)
|
||||
{
|
||||
node_free(node); free(node);
|
||||
node_free(lhs); free(lhs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node_push_new_child(node, lhs);
|
||||
node_push_new_child(node, rhs);
|
||||
lhs = node;
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_cmp(parser_t* self)
|
||||
{
|
||||
assert(self);
|
||||
node_t* lhs = CCM_TRY(parser_try_new_term);
|
||||
if (!lhs) { return NULL; }
|
||||
|
||||
if (lexer_peek_kind(self->lexer, NODE_LT, 0)
|
||||
|| lexer_peek_kind(self->lexer, NODE_LE, 0)
|
||||
|| lexer_peek_kind(self->lexer, NODE_GT, 0)
|
||||
|| lexer_peek_kind(self->lexer, NODE_GE, 0))
|
||||
{
|
||||
node_t* node = lexer_try_new_next(self->lexer);
|
||||
|
||||
node_t* rhs = CCM_TRY(parser_try_new_term);
|
||||
|
||||
if (!rhs)
|
||||
{
|
||||
node_free(node); free(node);
|
||||
node_free(lhs); free(lhs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node_push_new_child(node, lhs);
|
||||
node_push_new_child(node, rhs);
|
||||
lhs = node;
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_term(parser_t* self)
|
||||
{
|
||||
assert(self);
|
||||
|
|
|
@ -29,6 +29,8 @@ node_t* parser_try_new_assert(parser_t* self);
|
|||
node_t* parser_try_new_in(parser_t* self);
|
||||
node_t* parser_try_new_or(parser_t* self);
|
||||
node_t* parser_try_new_and(parser_t* self);
|
||||
node_t* parser_try_new_eqne(parser_t* self);
|
||||
node_t* parser_try_new_cmp(parser_t* self);
|
||||
node_t* parser_try_new_term(parser_t* self);
|
||||
node_t* parser_try_new_factor(parser_t* self);
|
||||
node_t* parser_try_new_usub(parser_t* self);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
assert_eq (true, 3 == 3)
|
||||
assert_eq (false, "3" == 3)
|
||||
assert_eq (false, 5 == 3)
|
||||
|
||||
assert_eq (false, 3 <> 3)
|
||||
assert_eq (true, "3" <> 3)
|
||||
assert_eq (true, 5 <> 3)
|
||||
|
||||
assert_eq (true, 5 < 7)
|
||||
assert_eq (false, 5 < 5)
|
||||
assert_eq (false, 9 < 4)
|
||||
|
||||
assert_eq (true, 5 <= 7)
|
||||
assert_eq (true, 5 <= 5)
|
||||
assert_eq (false, 9 <= 4)
|
||||
|
||||
assert_eq (true, 12 > 1)
|
||||
assert_eq (false, -2 > -2)
|
||||
assert_eq (false, 0 > 8)
|
||||
|
||||
assert_eq (true, 12 >= 1)
|
||||
assert_eq (true, -2 >= -2)
|
||||
assert_eq (false, 0 >= 8)
|
|
@ -0,0 +1,29 @@
|
|||
assert_eq ("hello", "hello")
|
||||
assert_ne ("hello", "world")
|
||||
|
||||
# INDEX
|
||||
# =====
|
||||
assert_eq ("hello"[0], "h")
|
||||
assert_eq ("hello"[1], "e")
|
||||
assert_eq ("hello"[2], "l")
|
||||
assert_eq ("hello"[3], "l")
|
||||
assert_eq ("hello"[4], "o")
|
||||
|
||||
assert_eq ("hello"[-5], "h")
|
||||
assert_eq ("hello"[-4], "e")
|
||||
assert_eq ("hello"[-3], "l")
|
||||
assert_eq ("hello"[-2], "l")
|
||||
assert_eq ("hello"[-1], "o")
|
||||
|
||||
# BINOPS
|
||||
# ======
|
||||
assert_eq (
|
||||
"hello world", "hello "
|
||||
+ "world"
|
||||
)
|
||||
|
||||
assert_eq ("www", "w" * 3)
|
||||
assert_eq ("wwww", 4 * "w")
|
||||
assert_eq ("abab", ("a" + "b") * 2)
|
||||
assert_eq ("abab", 2 * ("a" + "b"))
|
||||
|
Loading…
Reference in New Issue