Compare commits
3 Commits
8a930db339
...
bd84f3bb3d
Author | SHA1 | Date |
---|---|---|
bog | bd84f3bb3d | |
bog | 076fd79ff1 | |
bog | 90fe4c9f8e |
|
@ -1,6 +1,10 @@
|
||||||
MOD ::= EXPR*
|
MOD ::= EXPR*
|
||||||
EXPR ::=
|
EXPR ::=
|
||||||
| ASSERT
|
| ASSERT
|
||||||
| BUILTIN
|
| EQNE
|
||||||
ASSERT ::= assert EXPR
|
ASSERT ::= assert EXPR
|
||||||
|
EQNE ::=
|
||||||
|
| BUILTIN
|
||||||
|
| BUILTIN eq BUILTIN
|
||||||
|
| BUILTIN ne BUILTIN
|
||||||
BUILTIN ::= num | bool | str
|
BUILTIN ::= num | bool | str
|
||||||
|
|
|
@ -64,6 +64,19 @@ void compiler_run(compiler_t* compiler, node_t* node)
|
||||||
mod_push_instr(compiler->mod, OP_ASSERT, RZ_NO_PARAM);
|
mod_push_instr(compiler->mod, OP_ASSERT, RZ_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_NE:
|
||||||
|
case NODE_EQ: {
|
||||||
|
assert(node->children.size == 2);
|
||||||
|
|
||||||
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
{
|
||||||
|
compiler_run(compiler, node_child(node, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_push_instr(compiler->mod,
|
||||||
|
node->type == NODE_EQ ? OP_EQ : OP_NE, RZ_NO_PARAM);
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "Cannot compile unknown node '%s'",
|
fprintf(stderr, "Cannot compile unknown node '%s'",
|
||||||
NodeTypeStr[node->type]);
|
NodeTypeStr[node->type]);
|
||||||
|
|
44
lib/lexer.c
44
lib/lexer.c
|
@ -1,10 +1,16 @@
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "lib/commons.h"
|
#include "lib/commons.h"
|
||||||
|
|
||||||
#define RZ_KEYWORD(KW, NODE, VAL) \
|
#define RZ_KEYWORD(KW, NODE, VAL) \
|
||||||
{ \
|
{ \
|
||||||
node_t* kw = lexer_try_new_keyword(lexer, KW, NODE, VAL); \
|
node_t* kw = lexer_try_new_keyword(lexer, KW, NODE, VAL, 1); \
|
||||||
if (kw) { lexer_skip_spaces(lexer); return kw; } \
|
if (kw) { lexer_skip_spaces(lexer); return kw; } \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RZ_TEXT(KW, NODE, VAL) \
|
||||||
|
{ \
|
||||||
|
node_t* kw = lexer_try_new_keyword(lexer, KW, NODE, VAL, 0); \
|
||||||
|
if (kw) { lexer_skip_spaces(lexer); return kw; } \
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_init(lexer_t* lexer, char const* source, err_t* err)
|
void lexer_init(lexer_t* lexer, char const* source, err_t* err)
|
||||||
|
@ -30,6 +36,11 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
||||||
|
|
||||||
lexer_skip_spaces(lexer);
|
lexer_skip_spaces(lexer);
|
||||||
|
|
||||||
|
// Text
|
||||||
|
// ====
|
||||||
|
RZ_TEXT("==", NODE_EQ, 0);
|
||||||
|
RZ_TEXT("!=", NODE_NE, 0);
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
// ========
|
// ========
|
||||||
RZ_KEYWORD("true", NODE_BOOL, 1);
|
RZ_KEYWORD("true", NODE_BOOL, 1);
|
||||||
|
@ -156,7 +167,8 @@ void lexer_skip_spaces(lexer_t* lexer)
|
||||||
}
|
}
|
||||||
|
|
||||||
node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw,
|
node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw,
|
||||||
NodeType type, int has_value)
|
NodeType type, int has_value,
|
||||||
|
int is_kw)
|
||||||
{
|
{
|
||||||
assert(lexer);
|
assert(lexer);
|
||||||
assert(kw);
|
assert(kw);
|
||||||
|
@ -182,7 +194,7 @@ node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw,
|
||||||
int next_idx = lexer->cursor + len;
|
int next_idx = lexer->cursor + len;
|
||||||
|
|
||||||
if (next_idx < strlen(lexer->source)
|
if (next_idx < strlen(lexer->source)
|
||||||
&& !isspace(lexer->source[next_idx]))
|
&& (is_kw && !lexer_is_sep(lexer, next_idx)))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -272,3 +284,23 @@ node_t* lexer_try_new_str(lexer_t* lexer)
|
||||||
|
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lexer_is_sep(lexer_t* lexer, size_t idx)
|
||||||
|
{
|
||||||
|
assert(lexer);
|
||||||
|
|
||||||
|
if (idx >= strlen(lexer->source))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char c = lexer->source[idx];
|
||||||
|
|
||||||
|
if (isspace(c))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c == '='
|
||||||
|
|| c == '!';
|
||||||
|
}
|
||||||
|
|
|
@ -20,8 +20,11 @@ NodeType lexer_peek(lexer_t* lexer, int lookahead);
|
||||||
void lexer_skip_spaces(lexer_t* lexer);
|
void lexer_skip_spaces(lexer_t* lexer);
|
||||||
|
|
||||||
node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw,
|
node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw,
|
||||||
NodeType type, int has_value);
|
NodeType type, int has_value,
|
||||||
|
int is_kw);
|
||||||
|
|
||||||
node_t* lexer_try_new_str(lexer_t* lexer);
|
node_t* lexer_try_new_str(lexer_t* lexer);
|
||||||
|
|
||||||
|
int lexer_is_sep(lexer_t* lexer, size_t idx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
12
lib/loader.c
12
lib/loader.c
|
@ -1,4 +1,5 @@
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
#include "lib/commons.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
@ -63,6 +64,15 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
|
||||||
|
|
||||||
node_t* node = parser_try_new_tree(&parser);
|
node_t* node = parser_try_new_tree(&parser);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
char msg[RZ_STR_LIMIT];
|
||||||
|
node_str(node, msg, RZ_STR_LIMIT);
|
||||||
|
|
||||||
|
printf("\n======== AST ========\n");
|
||||||
|
printf("%s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
if (node)
|
if (node)
|
||||||
{
|
{
|
||||||
mod_t mod;
|
mod_t mod;
|
||||||
|
@ -102,7 +112,7 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
|
||||||
// execute
|
// execute
|
||||||
{
|
{
|
||||||
vm_t vm;
|
vm_t vm;
|
||||||
vm_init(&vm, &err);
|
vm_init(&vm, &tysy, &err);
|
||||||
|
|
||||||
int status = vm_exec_mod(&vm, &mod);
|
int status = vm_exec_mod(&vm, &mod);
|
||||||
|
|
||||||
|
|
10
lib/mod.c
10
lib/mod.c
|
@ -98,16 +98,6 @@ size_t mod_push_new_value(mod_t* mod, value_t* value)
|
||||||
assert(mod);
|
assert(mod);
|
||||||
assert(value);
|
assert(value);
|
||||||
|
|
||||||
for (size_t i=0; i<mod->values.size; i++)
|
|
||||||
{
|
|
||||||
if (value_eq(value, mod->values.data[i]))
|
|
||||||
{
|
|
||||||
value_free(value);
|
|
||||||
free(value);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mod->values.size == 0)
|
if (mod->values.size == 0)
|
||||||
{
|
{
|
||||||
mod->values.cap = 2;
|
mod->values.cap = 2;
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
#define NODE_TYPE(G) \
|
#define NODE_TYPE(G) \
|
||||||
G(NODE_MOD), \
|
G(NODE_MOD), \
|
||||||
G(NODE_NUM), G(NODE_BOOL), G(NODE_STR), \
|
G(NODE_NUM), G(NODE_BOOL), G(NODE_STR), \
|
||||||
G(NODE_ASSERT)
|
G(NODE_ASSERT), \
|
||||||
|
G(NODE_EQ), G(NODE_NE)
|
||||||
|
|
||||||
RZ_ENUM_H(NodeType, NODE_TYPE);
|
RZ_ENUM_H(NodeType, NODE_TYPE);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
#define OPCODES(G) \
|
#define OPCODES(G) \
|
||||||
G(OP_ASSERT), \
|
G(OP_ASSERT), \
|
||||||
G(OP_PUSH), G(OP_POP)
|
G(OP_PUSH), G(OP_POP), \
|
||||||
|
G(OP_EQ), G(OP_NE)
|
||||||
|
|
||||||
RZ_ENUM_H(Opcode, OPCODES);
|
RZ_ENUM_H(Opcode, OPCODES);
|
||||||
|
|
||||||
|
|
29
lib/parser.c
29
lib/parser.c
|
@ -61,7 +61,7 @@ node_t* parser_try_new_expr(parser_t* parser)
|
||||||
return parser_try_new_assert(parser);
|
return parser_try_new_assert(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser_try_new_builtin(parser);
|
return parser_try_new_eqne(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
node_t* parser_try_new_assert(parser_t* parser)
|
node_t* parser_try_new_assert(parser_t* parser)
|
||||||
|
@ -77,6 +77,33 @@ node_t* parser_try_new_assert(parser_t* parser)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_eqne(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
node_t* lhs = parser_try_new_builtin(parser);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
NodeType next_type = lexer_peek(parser->lexer, 1);
|
||||||
|
|
||||||
|
if (next_type == NODE_EQ || next_type == NODE_NE)
|
||||||
|
{
|
||||||
|
node_t* node = lexer_try_new_next(parser->lexer);
|
||||||
|
|
||||||
|
node_add_new_child(node, lhs);
|
||||||
|
node_add_new_child(node, parser_try_new_builtin(parser));
|
||||||
|
|
||||||
|
lhs = node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
node_t* parser_try_new_builtin(parser_t* parser)
|
node_t* parser_try_new_builtin(parser_t* parser)
|
||||||
{
|
{
|
||||||
assert(parser);
|
assert(parser);
|
||||||
|
|
|
@ -17,6 +17,7 @@ node_t* parser_try_new_tree(parser_t* parser);
|
||||||
node_t* parser_try_new_mod(parser_t* parser);
|
node_t* parser_try_new_mod(parser_t* parser);
|
||||||
node_t* parser_try_new_expr(parser_t* parser);
|
node_t* parser_try_new_expr(parser_t* parser);
|
||||||
node_t* parser_try_new_assert(parser_t* parser);
|
node_t* parser_try_new_assert(parser_t* parser);
|
||||||
|
node_t* parser_try_new_eqne(parser_t* parser);
|
||||||
node_t* parser_try_new_builtin(parser_t* parser);
|
node_t* parser_try_new_builtin(parser_t* parser);
|
||||||
|
|
||||||
node_t* parser_try_new_consume(parser_t* parser, NodeType type);
|
node_t* parser_try_new_consume(parser_t* parser, NodeType type);
|
||||||
|
|
|
@ -24,7 +24,9 @@ void prepass_run(prepass_t* prepass, node_t* node)
|
||||||
case NODE_NUM:
|
case NODE_NUM:
|
||||||
case NODE_STR:
|
case NODE_STR:
|
||||||
case NODE_BOOL:
|
case NODE_BOOL:
|
||||||
case NODE_ASSERT:{
|
case NODE_ASSERT:
|
||||||
|
case NODE_EQ:
|
||||||
|
case NODE_NE: {
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
{
|
{
|
||||||
prepass_run(prepass, (node_t*) node->children.data[i]);
|
prepass_run(prepass, (node_t*) node->children.data[i]);
|
||||||
|
|
46
lib/vm.c
46
lib/vm.c
|
@ -1,8 +1,9 @@
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "lib/commons.h"
|
#include "lib/commons.h"
|
||||||
|
#include "lib/mod.h"
|
||||||
#include "lib/type.h"
|
#include "lib/type.h"
|
||||||
|
|
||||||
void vm_init(vm_t* vm, err_t* err)
|
void vm_init(vm_t* vm, tysy_t* tysy, err_t* err)
|
||||||
{
|
{
|
||||||
assert(vm);
|
assert(vm);
|
||||||
|
|
||||||
|
@ -10,6 +11,7 @@ void vm_init(vm_t* vm, err_t* err)
|
||||||
vm->bp = 0;
|
vm->bp = 0;
|
||||||
vm->sp = 0;
|
vm->sp = 0;
|
||||||
|
|
||||||
|
vm->tysy = tysy;
|
||||||
vm->err = err;
|
vm->err = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +20,24 @@ void vm_free(vm_t* vm)
|
||||||
assert(vm);
|
assert(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vm_push_value(vm_t* vm, mod_t* mod, value_t* value)
|
||||||
|
{
|
||||||
|
assert(vm);
|
||||||
|
assert(value);
|
||||||
|
|
||||||
|
param_t param = mod_push_new_value(mod, value);
|
||||||
|
vm_push(vm, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_push(vm_t* vm, param_t param)
|
||||||
|
{
|
||||||
|
assert(vm);
|
||||||
|
assert(vm->sp + 1 < RZ_STACK_LIMIT);
|
||||||
|
|
||||||
|
vm->stack[vm->sp] = param;
|
||||||
|
vm->sp++;
|
||||||
|
}
|
||||||
|
|
||||||
param_t vm_pop(vm_t* vm)
|
param_t vm_pop(vm_t* vm)
|
||||||
{
|
{
|
||||||
assert(vm);
|
assert(vm);
|
||||||
|
@ -111,6 +131,30 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case OP_NE:
|
||||||
|
case OP_EQ: {
|
||||||
|
int l = vm_pop(vm);
|
||||||
|
int r = vm_pop(vm);
|
||||||
|
assert(l != -1);
|
||||||
|
assert(r != -1);
|
||||||
|
|
||||||
|
value_t* rhs = mod->values.data[l];
|
||||||
|
value_t* lhs = mod->values.data[r];
|
||||||
|
|
||||||
|
int same_type = lhs->type->kind == rhs->type->kind;
|
||||||
|
int eq = value_eq(lhs, rhs);
|
||||||
|
|
||||||
|
value_t* res = tysy_new_bool(vm->tysy,
|
||||||
|
(op == OP_EQ
|
||||||
|
? (same_type && eq)
|
||||||
|
: (!same_type || !eq)),
|
||||||
|
rhs->line);
|
||||||
|
|
||||||
|
vm_push_value(vm, mod, res);
|
||||||
|
|
||||||
|
vm->pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "Cannot execute unknown opcode '%s'.\n",
|
fprintf(stderr, "Cannot execute unknown opcode '%s'.\n",
|
||||||
OpcodeStr[op]);
|
OpcodeStr[op]);
|
||||||
|
|
6
lib/vm.h
6
lib/vm.h
|
@ -5,8 +5,10 @@
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
#include "mod.h"
|
#include "mod.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
#include "tysy.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
tysy_t* tysy;
|
||||||
param_t stack[RZ_STACK_LIMIT];
|
param_t stack[RZ_STACK_LIMIT];
|
||||||
size_t pc;
|
size_t pc;
|
||||||
size_t bp;
|
size_t bp;
|
||||||
|
@ -15,9 +17,11 @@ typedef struct {
|
||||||
err_t* err;
|
err_t* err;
|
||||||
} vm_t;
|
} vm_t;
|
||||||
|
|
||||||
void vm_init(vm_t* vm, err_t* err);
|
void vm_init(vm_t* vm, tysy_t* tysy, err_t* err);
|
||||||
void vm_free(vm_t* vm);
|
void vm_free(vm_t* vm);
|
||||||
|
|
||||||
|
void vm_push_value(vm_t* vm, mod_t* mod, value_t* value);
|
||||||
|
void vm_push(vm_t* vm, param_t param);
|
||||||
param_t vm_pop(vm_t* vm);
|
param_t vm_pop(vm_t* vm);
|
||||||
|
|
||||||
size_t vm_stack_str(vm_t* vm, char* buffer, size_t size);
|
size_t vm_stack_str(vm_t* vm, char* buffer, size_t size);
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
assert 5 == 5
|
||||||
|
assert 3 != 5
|
||||||
|
|
||||||
|
assert true == true
|
||||||
|
assert false == false
|
||||||
|
assert false != true
|
||||||
|
|
||||||
|
assert "hello" == "hello"
|
||||||
|
assert "world" != "hello"
|
||||||
|
|
||||||
|
assert 7 != "hello"
|
||||||
|
assert false != 23
|
||||||
|
assert "bim" != true
|
|
@ -14,8 +14,6 @@ do
|
||||||
TRACE="$(roza $file 2>&1)"
|
TRACE="$(roza $file 2>&1)"
|
||||||
RES=$?
|
RES=$?
|
||||||
|
|
||||||
# echo -en "\e[33m$file\e[0m ... "
|
|
||||||
|
|
||||||
if [ $RES -ne 0 ]
|
if [ $RES -ne 0 ]
|
||||||
then
|
then
|
||||||
echo
|
echo
|
||||||
|
@ -32,14 +30,7 @@ do
|
||||||
TOTAL=$(($TOTAL + 1))
|
TOTAL=$(($TOTAL + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
echo
|
echo -e "\e[33m$H SUMMARY $H\e[0m"
|
||||||
|
|
||||||
if [ $PASSED -eq $TOTAL ]
|
|
||||||
then
|
|
||||||
echo -e "\e[32m$H All tests passed $H\e[0m"
|
|
||||||
else
|
|
||||||
echo -e "\e[31m$H Some tests failed $H\e[0m"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "PASSED: $PASSED"
|
echo "PASSED: $PASSED"
|
||||||
for ok in $PASSED_LST
|
for ok in $PASSED_LST
|
||||||
|
@ -57,3 +48,10 @@ done
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "TOTAL: $TOTAL"
|
echo "TOTAL: $TOTAL"
|
||||||
|
|
||||||
|
if [ $PASSED -eq $TOTAL ]
|
||||||
|
then
|
||||||
|
echo -e "\e[32m$H All tests passed $H\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31m$H Some tests failed $H\e[0m"
|
||||||
|
fi
|
||||||
|
|
|
@ -8,13 +8,13 @@ static void test_lexer_ok(char const* oracle, char const* source)
|
||||||
lexer_init(&lex, source, NULL);
|
lexer_init(&lex, source, NULL);
|
||||||
|
|
||||||
node_t* tok = lexer_try_new_next(&lex);
|
node_t* tok = lexer_try_new_next(&lex);
|
||||||
cr_assert(tok != NULL);
|
cr_assert(tok != NULL, "error -> %s", source);
|
||||||
|
|
||||||
size_t const SZ = 512;
|
size_t const SZ = 512;
|
||||||
char str[SZ];
|
char str[SZ];
|
||||||
node_str(tok, str, SZ);
|
node_str(tok, str, SZ);
|
||||||
|
|
||||||
cr_assert_str_eq(str, oracle);
|
cr_assert_str_eq(str, oracle, "error -> %s", source);
|
||||||
|
|
||||||
node_free(tok);
|
node_free(tok);
|
||||||
lexer_free(&lex);
|
lexer_free(&lex);
|
||||||
|
@ -30,7 +30,7 @@ static void test_lexer_ko(char const* source)
|
||||||
|
|
||||||
node_t* tok = lexer_try_new_next(&lex);
|
node_t* tok = lexer_try_new_next(&lex);
|
||||||
|
|
||||||
cr_assert(tok == NULL);
|
cr_assert(tok == NULL, "error -> %s", source);
|
||||||
cr_assert(err.size > 0);
|
cr_assert(err.size > 0);
|
||||||
|
|
||||||
err_free(&err);
|
err_free(&err);
|
||||||
|
@ -48,7 +48,7 @@ static void test_lexer(char const* source, size_t n, ...)
|
||||||
for (size_t i=0; i<n; i++)
|
for (size_t i=0; i<n; i++)
|
||||||
{
|
{
|
||||||
node_t* tok = lexer_try_new_next(&lexer);
|
node_t* tok = lexer_try_new_next(&lexer);
|
||||||
cr_assert(NULL != tok);
|
cr_assert(NULL != tok, "error -> %s", source);
|
||||||
|
|
||||||
size_t const SZ = 256;
|
size_t const SZ = 256;
|
||||||
char tok_str[SZ];
|
char tok_str[SZ];
|
||||||
|
@ -109,3 +109,19 @@ Test(lexer, str) {
|
||||||
Test(lexer, assert) {
|
Test(lexer, assert) {
|
||||||
test_lexer("assert", 1, "ASSERT");
|
test_lexer("assert", 1, "ASSERT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(lexer, cmp) {
|
||||||
|
test_lexer("== !=", 2,
|
||||||
|
"EQ",
|
||||||
|
"NE");
|
||||||
|
|
||||||
|
test_lexer("false==true", 3,
|
||||||
|
"BOOL[false]",
|
||||||
|
"EQ",
|
||||||
|
"BOOL[true]");
|
||||||
|
|
||||||
|
test_lexer("false!=true", 3,
|
||||||
|
"BOOL[false]",
|
||||||
|
"NE",
|
||||||
|
"BOOL[true]");
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ static void test_parser_ok(char const* oracle, char const* source)
|
||||||
|
|
||||||
node_t* node = parser_try_new_tree(&parser);
|
node_t* node = parser_try_new_tree(&parser);
|
||||||
|
|
||||||
cr_assert(NULL != node);
|
cr_assert(NULL != node, "error -> %s", source);
|
||||||
|
|
||||||
size_t const SZ = 256;
|
size_t const SZ = 256;
|
||||||
char msg[SZ];
|
char msg[SZ];
|
||||||
|
@ -71,3 +71,8 @@ Test(parser, assert) {
|
||||||
test_parser_ok("MOD(ASSERT(BOOL[false]))", " assert false ");
|
test_parser_ok("MOD(ASSERT(BOOL[false]))", " assert false ");
|
||||||
test_parser_ok("MOD(ASSERT(BOOL[true]))", " assert true ");
|
test_parser_ok("MOD(ASSERT(BOOL[true]))", " assert true ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(parser, eqne) {
|
||||||
|
test_parser_ok("MOD(EQ(NUM[3],NUM[3]))", " 3 == 3 ");
|
||||||
|
test_parser_ok("MOD(NE(NUM[3],NUM[3]))", " 3 != 3 ");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue