✨ comparison operators.
parent
f0fa844c8a
commit
f1b82208ce
|
@ -5,7 +5,9 @@ EXPR ::=
|
||||||
ASSERT ::= (assert_eq|assert_ne) tuple
|
ASSERT ::= (assert_eq|assert_ne) tuple
|
||||||
IN ::= OR (in OR)?
|
IN ::= OR (in OR)?
|
||||||
OR ::= AND (or AND)*
|
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)*
|
TERM ::= FACTOR ((add|sub) FACTOR)*
|
||||||
FACTOR ::= USUB ((mul|div|mod) USUB)*
|
FACTOR ::= USUB ((mul|div|mod) USUB)*
|
||||||
USUB ::= sub* NOT
|
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_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_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_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);
|
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)
|
int ccm_is_num(ccm_t* self, CCM value)
|
||||||
{
|
{
|
||||||
value_t const* val = self->values.data[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));
|
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);
|
size_t ccm_str(ccm_t* self, char* buffer, size_t size);
|
||||||
|
|
||||||
CCM ccm_from_value(ccm_t* self, value_t* value);
|
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);
|
int ccm_is_num(ccm_t* self, CCM value);
|
||||||
double ccm_from_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_pow(ccm_t* self);
|
||||||
void ccm_not(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
|
#endif
|
||||||
|
|
|
@ -30,6 +30,45 @@ void compiler_compile(compiler_t* self,
|
||||||
|
|
||||||
switch (node->kind)
|
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: {
|
case NODE_INDEX: {
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
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)
|
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: {
|
case OP_INDEX: {
|
||||||
CCM ccm_target = ccm_pop(ccm);
|
CCM ccm_target = ccm_pop(ccm);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,12 @@ void lexer_init(lexer_t* self)
|
||||||
str_init(&self->separators);
|
str_init(&self->separators);
|
||||||
|
|
||||||
vec_init(&self->texts);
|
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_COMMA);
|
||||||
lexer_add_text(self, "(", NODE_OPAR);
|
lexer_add_text(self, "(", NODE_OPAR);
|
||||||
lexer_add_text(self, ")", NODE_CPAR);
|
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_ASSERT_EQ), G(NODE_ASSERT_NE), G(NODE_BOOL), \
|
||||||
G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IN), \
|
G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IN), \
|
||||||
G(NODE_OSQUARE), G(NODE_CSQUARE), G(NODE_INDEX), \
|
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);
|
CCM_ENUM_H(NodeKind, NODE_KIND);
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ typedef struct {
|
||||||
int line;
|
int line;
|
||||||
} node_t;
|
} node_t;
|
||||||
|
|
||||||
void node_init(node_t* self, NodeKind kind,
|
void node_init(node_t* self, NodeKind kind,
|
||||||
char const* value, int line);
|
char const* value, int line);
|
||||||
void node_free(node_t* self);
|
void node_free(node_t* self);
|
||||||
|
|
||||||
|
|
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)
|
node_t* parser_try_new_and(parser_t* self)
|
||||||
{
|
{
|
||||||
assert(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; }
|
if (!lhs) { return NULL; }
|
||||||
|
|
||||||
while (lexer_peek_kind(self->lexer, NODE_AND, 0))
|
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_init(node, NODE_AND, "", lhs->line);
|
||||||
|
|
||||||
node_push_new_child(node, lhs);
|
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)
|
if (!rhs)
|
||||||
{
|
{
|
||||||
|
@ -256,6 +256,64 @@ node_t* parser_try_new_and(parser_t* self)
|
||||||
return lhs;
|
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)
|
node_t* parser_try_new_term(parser_t* self)
|
||||||
{
|
{
|
||||||
assert(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_in(parser_t* self);
|
||||||
node_t* parser_try_new_or(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_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_term(parser_t* self);
|
||||||
node_t* parser_try_new_factor(parser_t* self);
|
node_t* parser_try_new_factor(parser_t* self);
|
||||||
node_t* parser_try_new_usub(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