From d3f90a5ed13e9e0313fa4cf64776834f87b3f069 Mon Sep 17 00:00:00 2001 From: bog Date: Mon, 11 Dec 2023 18:01:22 +0100 Subject: [PATCH] :sparkles: assert expression. --- doc/roza.bnf | 5 +++- lib/compiler.c | 20 +++++++++----- lib/err.c | 34 +++++++++++++++++++---- lib/err.h | 12 ++++++-- lib/lexer.c | 66 ++++++++++++++++++++++++++++---------------- lib/lexer.h | 1 + lib/loader.c | 39 ++++++++++++++++++++------ lib/mod.c | 18 +++++++++--- lib/node.c | 10 ++++++- lib/node.h | 8 +++--- lib/opcodes.h | 2 +- lib/parser.c | 29 +++++++++++++++++-- lib/parser.h | 1 + lib/prepass.c | 40 +++++++++++++++++++++++++++ lib/prepass.h | 17 ++++++++++++ lib/tysy.c | 12 ++++---- lib/tysy.h | 6 ++-- lib/value.c | 3 +- lib/value.h | 3 +- lib/vm.c | 58 +++++++++++++++++++++++++++++++++++--- lib/vm.h | 9 ++++-- meson.build | 1 + tests/units/lexer.c | 4 +++ tests/units/parser.c | 5 ++++ 24 files changed, 325 insertions(+), 78 deletions(-) create mode 100644 lib/prepass.c create mode 100644 lib/prepass.h diff --git a/doc/roza.bnf b/doc/roza.bnf index 7015dad..ac9fcd6 100644 --- a/doc/roza.bnf +++ b/doc/roza.bnf @@ -1,3 +1,6 @@ MOD ::= EXPR* -EXPR ::= BUILTIN +EXPR ::= +| ASSERT +| BUILTIN +ASSERT ::= assert EXPR BUILTIN ::= num | bool | str diff --git a/lib/compiler.c b/lib/compiler.c index 33de0fa..42ee972 100644 --- a/lib/compiler.c +++ b/lib/compiler.c @@ -32,7 +32,7 @@ void compiler_run(compiler_t* compiler, node_t* node) case NODE_NUM: { double value = atof(node->value.data); - value_t* val = tysy_new_num(compiler->tysy, value); + value_t* val = tysy_new_num(compiler->tysy, value, node->line); Opcode op = OP_PUSH; param_t param = (param_t) mod_push_new_value(compiler->mod, val); @@ -42,7 +42,7 @@ void compiler_run(compiler_t* compiler, node_t* node) case NODE_BOOL: { int value = strcmp(node->value.data, "true") == 0; - value_t* val = tysy_new_bool(compiler->tysy, value); + value_t* val = tysy_new_bool(compiler->tysy, value, node->line); Opcode op = OP_PUSH; param_t param = (param_t) mod_push_new_value(compiler->mod, val); @@ -51,18 +51,24 @@ void compiler_run(compiler_t* compiler, node_t* node) case NODE_STR: { char* value = node->value.data; - value_t* val = tysy_new_str(compiler->tysy, value); + value_t* val = tysy_new_str(compiler->tysy, value, node->line); Opcode op = OP_PUSH; param_t param = (param_t) mod_push_new_value(compiler->mod, val); mod_push_instr(compiler->mod, op, param); } break; + case NODE_ASSERT: { + assert(node->children.size == 1); + compiler_run(compiler, node_child(node, 0)); + mod_push_instr(compiler->mod, OP_ASSERT, RZ_NO_PARAM); + + } break; + default: { - char msg[RZ_STR_LIMIT]; - snprintf(msg, RZ_STR_LIMIT, "Unknown node '%s'", - NodeTypeStr[node->type]); - err_error(compiler->err, msg, node->line); + fprintf(stderr, "Cannot compile unknown node '%s'", + NodeTypeStr[node->type]); + abort(); } break; } } diff --git a/lib/err.c b/lib/err.c index 9d3eb6e..3a70312 100644 --- a/lib/err.c +++ b/lib/err.c @@ -1,5 +1,7 @@ #include "err.h" +RZ_ENUM_C(ErrType, ERR_TYPES); + void err_init(err_t* err) { assert(err); @@ -19,7 +21,7 @@ void err_free(err_t* err) err->size = 0; } -void err_error(err_t* err, char* what, int line) +void err_of_type(err_t* err, char* what, int line, ErrType type) { assert(err); assert(err->size + 1 < RZ_ERROR_STACK_SIZE); @@ -27,21 +29,41 @@ void err_error(err_t* err, char* what, int line) err->errors[err->size] = malloc(sizeof(err_msg_t)); err->errors[err->size]->what = strdup(what); err->errors[err->size]->line = line; + err->errors[err->size]->type = type; err->size++; } -void err_abort(err_t* err) +void err_fatal(err_t* err, char* what, int line) +{ + err_of_type(err, what, line, ERR_FATAL); +} + +int err_dump(err_t* err) { assert(err); + int is_fatal = 0; for (size_t i=0; isize; i++) { - fprintf(stderr, "ERR(%d) %s\n", - err->errors[i]->line, - err->errors[i]->what); + if (err->errors[i]->type == ERR_WARNING) + { + fprintf(stderr, "\33[33mWARNING\33[0m[:%d] %s\n", + err->errors[i]->line, + err->errors[i]->what); + } + + else if (err->errors[i]->type == ERR_FATAL) + { + fprintf(stderr, "\33[31mERROR\33[0m[:%d] %s\n", + err->errors[i]->line, + err->errors[i]->what); + + is_fatal = 1; + } } err_free(err); + err_init(err); - abort(); + return is_fatal; } diff --git a/lib/err.h b/lib/err.h index 09d2c4f..d8a2074 100644 --- a/lib/err.h +++ b/lib/err.h @@ -5,7 +5,13 @@ #include "commons.h" +#define ERR_TYPES(G) \ + G(ERR_WARNING), G(ERR_FATAL) + +RZ_ENUM_H(ErrType, ERR_TYPES); + typedef struct { + ErrType type; char* what; int line; } err_msg_t; @@ -18,7 +24,9 @@ typedef struct { void err_init(err_t* err); void err_free(err_t* err); -void err_error(err_t* err, char* what, int line); -void err_abort(err_t* err); +void err_of_type(err_t* err, char* what, int line, ErrType type); +void err_fatal(err_t* err, char* what, int line); + +int err_dump(err_t* err); #endif diff --git a/lib/lexer.c b/lib/lexer.c index 883c08e..7bb5543 100644 --- a/lib/lexer.c +++ b/lib/lexer.c @@ -1,6 +1,12 @@ #include "lexer.h" #include "lib/commons.h" +#define RZ_KEYWORD(KW, NODE, VAL) \ + { \ + node_t* kw = lexer_try_new_keyword(lexer, KW, NODE, VAL); \ + if (kw) { lexer_skip_spaces(lexer); return kw; } \ + } + void lexer_init(lexer_t* lexer, char const* source, err_t* err) { assert(lexer); @@ -22,35 +28,23 @@ node_t* lexer_try_new_next(lexer_t* lexer) assert(lexer); size_t len = strlen(lexer->source); - // skip spaces - { - while (lexer->cursor < len - && isspace(lexer->source[lexer->cursor])) - { - if (lexer->source[lexer->cursor] == '\n') - { - lexer->line++; - } - - lexer->cursor++; - } - } + lexer_skip_spaces(lexer); // Keywords // ======== - { - node_t* kw = lexer_try_new_keyword(lexer, "true", NODE_BOOL, 1); - if (kw) { return kw; } - } - { - node_t* kw = lexer_try_new_keyword(lexer, "false", NODE_BOOL, 1); - if (kw) { return kw; } - } + RZ_KEYWORD("true", NODE_BOOL, 1); + RZ_KEYWORD("false", NODE_BOOL, 1); + RZ_KEYWORD("assert", NODE_ASSERT, 0); // scan str { node_t* node = lexer_try_new_str(lexer); - if (node) { return node; } + + if (node) + { + lexer_skip_spaces(lexer); + return node; + } } // scan num @@ -94,6 +88,8 @@ node_t* lexer_try_new_next(lexer_t* lexer) str_free(&res_str); lexer->cursor = cursor; + + lexer_skip_spaces(lexer); return tok; } @@ -105,7 +101,7 @@ node_t* lexer_try_new_next(lexer_t* lexer) size_t const SZ = RZ_STR_LIMIT; char msg[SZ]; snprintf(msg, SZ, "unexpected symbol '%c'", lexer->source[lexer->cursor]); - err_error(lexer->err, msg, lexer->line); + err_fatal(lexer->err, msg, lexer->line); } return NULL; @@ -117,7 +113,7 @@ NodeType lexer_peek(lexer_t* lexer, int lookahead) size_t cursor = lexer->cursor; int line = lexer->line; - NodeType type = 0; + NodeType type = -1; for (int i=0; icursor = cursor; @@ -137,6 +137,24 @@ NodeType lexer_peek(lexer_t* lexer, int lookahead) return type; } +void lexer_skip_spaces(lexer_t* lexer) +{ + assert(lexer); + size_t len = strlen(lexer->source); + + while (lexer->cursor < len + && isspace(lexer->source[lexer->cursor])) + { + if (lexer->source[lexer->cursor] == '\n') + { + lexer->line++; + } + + lexer->cursor++; + } + +} + node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw, NodeType type, int has_value) { diff --git a/lib/lexer.h b/lib/lexer.h index 8a1f2d7..1ec7f29 100644 --- a/lib/lexer.h +++ b/lib/lexer.h @@ -17,6 +17,7 @@ void lexer_free(lexer_t* lexer); node_t* lexer_try_new_next(lexer_t* lexer); NodeType lexer_peek(lexer_t* lexer, int lookahead); +void lexer_skip_spaces(lexer_t* lexer); node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw, NodeType type, int has_value); diff --git a/lib/loader.c b/lib/loader.c index a5109a5..068e228 100644 --- a/lib/loader.c +++ b/lib/loader.c @@ -2,6 +2,7 @@ #include "parser.h" #include "loader.h" #include "compiler.h" +#include "prepass.h" #include "mod.h" #include "vm.h" @@ -67,20 +68,41 @@ void loader_ldfile(loader_t* loader, char const* path, int debug) mod_t mod; mod_init(&mod); + // prepass + { + prepass_t prepass; + prepass_init(&prepass, &err); + prepass_run(&prepass, node); + prepass_free(&prepass); + } + // compile { compiler_t compiler; compiler_init(&compiler, &mod, &tysy, &err); compiler_run(&compiler, node); compiler_free(&compiler); - node_free(node); - free(node); } + node_free(node); + free(node); + + // check compilation errors + if (err_dump(&err)) + { + parser_free(&parser); + lexer_free(&lex); + str_free(&source); + tysy_free(&tysy); + err_free(&err); + + abort(); + } + // execute { vm_t vm; - vm_init(&vm); + vm_init(&vm, &err); vm_exec_mod(&vm, &mod); @@ -110,15 +132,14 @@ void loader_ldfile(loader_t* loader, char const* path, int debug) parser_free(&parser); lexer_free(&lex); str_free(&source); + tysy_free(&tysy); - if (err.size > 0) - { - err_abort(&err); - } - else + // check execution errors + if (err_dump(&err)) { err_free(&err); + abort(); } - tysy_free(&tysy); + err_free(&err); } diff --git a/lib/mod.c b/lib/mod.c index 9f5ca93..e361e22 100644 --- a/lib/mod.c +++ b/lib/mod.c @@ -1,4 +1,5 @@ #include "mod.h" +#include "lib/commons.h" void mod_init(mod_t* mod) { @@ -74,10 +75,19 @@ size_t mod_str(mod_t* mod, char* buffer, size_t size) sz += snprintf(buffer + sz, size - sz, "\n======== PROGRAM ========\n"); for (size_t i=0; iprogram.size; i++) { - sz += snprintf(buffer + sz, size - sz, "%d| %s %d\n", - (int) i, - OpcodeStr[mod->program.ops[i]] + strlen("OP_"), - mod->program.params[i]); + if (mod->program.params[i] != RZ_NO_PARAM) + { + sz += snprintf(buffer + sz, size - sz, "%d| %s %d\n", + (int) i, + OpcodeStr[mod->program.ops[i]] + strlen("OP_"), + mod->program.params[i]); + } + else + { + sz += snprintf(buffer + sz, size - sz, "%d| %s\n", + (int) i, + OpcodeStr[mod->program.ops[i]] + strlen("OP_")); + } } return sz; diff --git a/lib/node.c b/lib/node.c index f186cdc..2190479 100644 --- a/lib/node.c +++ b/lib/node.c @@ -34,7 +34,7 @@ void node_free(node_t* node) node->children.cap = 0; } -void node_add_child(node_t* node, node_t* child) +void node_add_new_child(node_t* node, node_t* child) { assert(node); assert(child); @@ -57,6 +57,14 @@ void node_add_child(node_t* node, node_t* child) node->children.size++; } +node_t* node_child(node_t* node, size_t index) +{ + assert(node); + assert(index < node->children.size); + + return (node_t*) node->children.data[index]; +} + size_t node_str(node_t* node, char* buffer, size_t size) { assert(node); diff --git a/lib/node.h b/lib/node.h index c0342b2..9ed6c9e 100644 --- a/lib/node.h +++ b/lib/node.h @@ -5,9 +5,8 @@ #define NODE_TYPE(G) \ G(NODE_MOD), \ - G(NODE_NUM), \ - G(NODE_BOOL), \ - G(NODE_STR) + G(NODE_NUM), G(NODE_BOOL), G(NODE_STR), \ + G(NODE_ASSERT) RZ_ENUM_H(NodeType, NODE_TYPE); @@ -26,7 +25,8 @@ typedef struct { void node_init(node_t* node, NodeType type, char* value, int line); void node_free(node_t* node); -void node_add_child(node_t* node, node_t* child); +void node_add_new_child(node_t* node, node_t* child); +node_t* node_child(node_t* node, size_t index); size_t node_str(node_t* node, char* buffer, size_t size); diff --git a/lib/opcodes.h b/lib/opcodes.h index 77c7040..cea0b73 100644 --- a/lib/opcodes.h +++ b/lib/opcodes.h @@ -4,7 +4,7 @@ #include "commons.h" #define OPCODES(G) \ - G(OP_HALT), \ + G(OP_ASSERT), \ G(OP_PUSH), G(OP_POP) RZ_ENUM_H(Opcode, OPCODES); diff --git a/lib/parser.c b/lib/parser.c index 0812e50..77a3541 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -33,7 +33,7 @@ node_t* parser_try_new_mod(parser_t* parser) if (expr) { - node_add_child(mod, expr); + node_add_new_child(mod, expr); } else { @@ -49,9 +49,34 @@ node_t* parser_try_new_mod(parser_t* parser) node_t* parser_try_new_expr(parser_t* parser) { assert(parser); + NodeType type = lexer_peek(parser->lexer, 1); + + if (type == -1) + { + return NULL; + } + + if (type == NODE_ASSERT) + { + return parser_try_new_assert(parser); + } + return parser_try_new_builtin(parser); } +node_t* parser_try_new_assert(parser_t* parser) +{ + assert(parser); + node_t* node = parser_try_new_consume(parser, NODE_ASSERT); + assert(node); + + node_t* expr = parser_try_new_expr(parser); + assert(expr); + node_add_new_child(node, expr); + + return node; +} + node_t* parser_try_new_builtin(parser_t* parser) { assert(parser); @@ -80,7 +105,7 @@ node_t* parser_try_new_consume(parser_t* parser, NodeType type) size_t const SZ = RZ_STR_LIMIT; char err_msg[SZ]; snprintf(err_msg, SZ, "unexpected node '%s'", NodeTypeStr[next->type]); - err_error(parser->err, err_msg, next->line); + err_fatal(parser->err, err_msg, next->line); node_free(next); free(next); return NULL; diff --git a/lib/parser.h b/lib/parser.h index 894a393..f300764 100644 --- a/lib/parser.h +++ b/lib/parser.h @@ -16,6 +16,7 @@ void parser_free(parser_t* parser); node_t* parser_try_new_tree(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_assert(parser_t* parser); node_t* parser_try_new_builtin(parser_t* parser); node_t* parser_try_new_consume(parser_t* parser, NodeType type); diff --git a/lib/prepass.c b/lib/prepass.c new file mode 100644 index 0000000..1159a4b --- /dev/null +++ b/lib/prepass.c @@ -0,0 +1,40 @@ +#include "prepass.h" + +void prepass_init(prepass_t* prepass, err_t* err) +{ + assert(prepass); + assert(err); + + prepass->err = err; +} + +void prepass_free(prepass_t* prepass) +{ + assert(prepass); +} + +void prepass_run(prepass_t* prepass, node_t* node) +{ + assert(prepass); + assert(node); + + switch (node->type) + { + case NODE_MOD: + case NODE_NUM: + case NODE_STR: + case NODE_BOOL: + case NODE_ASSERT:{ + for (size_t i=0; ichildren.size; i++) + { + prepass_run(prepass, (node_t*) node->children.data[i]); + } + } break; + + default: { + fprintf(stderr, "Cannot prepass unknown node '%s'.\n", + NodeTypeStr[node->type]); + abort(); + } break; + } +} diff --git a/lib/prepass.h b/lib/prepass.h new file mode 100644 index 0000000..5590c3a --- /dev/null +++ b/lib/prepass.h @@ -0,0 +1,17 @@ +#ifndef RZ_PREPASS_H +#define RZ_PREPASS_H + +#include "commons.h" +#include "err.h" +#include "node.h" + +typedef struct { + err_t* err; +} prepass_t; + +void prepass_init(prepass_t* prepass, err_t* err); +void prepass_free(prepass_t* prepass); + +void prepass_run(prepass_t* prepass, node_t* node); + +#endif diff --git a/lib/tysy.c b/lib/tysy.c index 85e3bc5..ebb44e6 100644 --- a/lib/tysy.c +++ b/lib/tysy.c @@ -69,34 +69,34 @@ type_t* tysy_try_find_type(tysy_t* tysy, char* name) return NULL; } -value_t* tysy_new_num(tysy_t* tysy, double value) +value_t* tysy_new_num(tysy_t* tysy, double value, int line) { assert(tysy); value_t* val = malloc(sizeof(value_t)); - value_init(val, tysy_try_find_type(tysy, "num")); + value_init(val, tysy_try_find_type(tysy, "num"), line); val->value.num = value; return val; } -value_t* tysy_new_bool(tysy_t* tysy, int value) +value_t* tysy_new_bool(tysy_t* tysy, int value, int line) { assert(tysy); value_t* val = malloc(sizeof(value_t)); - value_init(val, tysy_try_find_type(tysy, "bool")); + value_init(val, tysy_try_find_type(tysy, "bool"), line); val->value.bool = value; return val; } -value_t* tysy_new_str(tysy_t* tysy, char* value) +value_t* tysy_new_str(tysy_t* tysy, char* value, int line) { assert(tysy); value_t* val = malloc(sizeof(value_t)); - value_init(val, tysy_try_find_type(tysy, "str")); + value_init(val, tysy_try_find_type(tysy, "str"), line); val->value.str = strdup(value); return val; diff --git a/lib/tysy.h b/lib/tysy.h index f4966ad..c75a88b 100644 --- a/lib/tysy.h +++ b/lib/tysy.h @@ -16,8 +16,8 @@ void tysy_free(tysy_t* tysy); void tysy_register_new_type(tysy_t* tysy, char* name, type_t* type); type_t* tysy_try_find_type(tysy_t* tysy, char* name); -value_t* tysy_new_num(tysy_t* tysy, double value); -value_t* tysy_new_bool(tysy_t* tysy, int value); -value_t* tysy_new_str(tysy_t* tysy, char* value); +value_t* tysy_new_num(tysy_t* tysy, double value, int line); +value_t* tysy_new_bool(tysy_t* tysy, int value, int line); +value_t* tysy_new_str(tysy_t* tysy, char* value, int line); #endif diff --git a/lib/value.c b/lib/value.c index b131ec2..e61eb82 100644 --- a/lib/value.c +++ b/lib/value.c @@ -1,11 +1,12 @@ #include "value.h" -void value_init(value_t* value, type_t* type) +void value_init(value_t* value, type_t* type, int line) { assert(value); assert(type); value->type = type; + value->line = line; } void value_free(value_t* value) diff --git a/lib/value.h b/lib/value.h index 4416cc8..596da5e 100644 --- a/lib/value.h +++ b/lib/value.h @@ -12,9 +12,10 @@ typedef struct { char* str; } value; + int line; } value_t; -void value_init(value_t* value, type_t* type); +void value_init(value_t* value, type_t* type, int line); void value_free(value_t* value); int value_eq(value_t* value, value_t* rhs); diff --git a/lib/vm.c b/lib/vm.c index f977ca9..6c495cb 100644 --- a/lib/vm.c +++ b/lib/vm.c @@ -1,13 +1,16 @@ #include "vm.h" #include "lib/commons.h" +#include "lib/type.h" -void vm_init(vm_t* vm) +void vm_init(vm_t* vm, err_t* err) { assert(vm); vm->pc = 0; vm->bp = 0; vm->sp = 0; + + vm->err = err; } void vm_free(vm_t* vm) @@ -15,6 +18,16 @@ void vm_free(vm_t* vm) assert(vm); } +param_t vm_pop(vm_t* vm) +{ + assert(vm); + assert(vm->sp > 0); + param_t param = vm->stack[vm->sp - 1]; + vm->sp--; + + return param; +} + size_t vm_stack_str(vm_t* vm, char* buffer, size_t size) { assert(vm); @@ -37,12 +50,19 @@ void vm_exec_mod(vm_t* vm, mod_t* mod) while (vm->pc < mod->program.size) { - vm_exec_instr(vm, mod->program.ops[vm->pc], - mod->program.params[vm->pc]); + int status = vm_exec_instr(vm, + mod, + mod->program.ops[vm->pc], + mod->program.params[vm->pc]); + + if (!status) + { + return; + } } } -void vm_exec_instr(vm_t* vm, Opcode op, param_t param) +int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) { assert(vm); @@ -61,10 +81,40 @@ void vm_exec_instr(vm_t* vm, Opcode op, param_t param) vm->pc++; } break; + case OP_ASSERT: { + param_t top = vm_pop(vm); + value_t* value = mod->values.data[top]; + + if (value->type->kind != TYPE_BOOL) + { + char msg[RZ_STR_LIMIT]; + snprintf(msg, RZ_STR_LIMIT, + "type mismatch: BOOL expected, got %s.", + TypeKindStr[value->type->kind] + strlen("TYPE_")); + + err_fatal(vm->err, msg, value->line); + + vm->pc++; + break; + } + + if (!value->value.bool) + { + fprintf(stderr, "\33[31mASSERT\33[0m[:%d] assertion failed\n", + value->line); + return 0; + } + + vm->pc++; + + } break; + default: { fprintf(stderr, "Cannot execute unknown opcode '%s'.\n", OpcodeStr[op]); abort(); }; } + + return 1; } diff --git a/lib/vm.h b/lib/vm.h index ace7d1a..b93080f 100644 --- a/lib/vm.h +++ b/lib/vm.h @@ -4,20 +4,25 @@ #include "commons.h" #include "opcodes.h" #include "mod.h" +#include "err.h" typedef struct { param_t stack[RZ_STACK_LIMIT]; size_t pc; size_t bp; size_t sp; + + err_t* err; } vm_t; -void vm_init(vm_t* vm); +void vm_init(vm_t* vm, err_t* err); void vm_free(vm_t* vm); +param_t vm_pop(vm_t* vm); + size_t vm_stack_str(vm_t* vm, char* buffer, size_t size); void vm_exec_mod(vm_t* vm, mod_t* mod); -void vm_exec_instr(vm_t* vm, Opcode op, param_t param); +int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param); #endif diff --git a/meson.build b/meson.build index 3f41da5..758f755 100644 --- a/meson.build +++ b/meson.build @@ -34,6 +34,7 @@ roza_lib = static_library( # comp 'lib/opcodes.c', 'lib/mod.c', + 'lib/prepass.c', 'lib/compiler.c', # exec diff --git a/tests/units/lexer.c b/tests/units/lexer.c index 6c402d7..855540f 100644 --- a/tests/units/lexer.c +++ b/tests/units/lexer.c @@ -105,3 +105,7 @@ Test(lexer, str) { test_lexer("\"the \\\"cat\\\"\"", 1, "STR[the \"cat\"]"); test_lexer("\"hello\\n\\tworld\"", 1, "STR[hello\n\tworld]"); } + +Test(lexer, assert) { + test_lexer("assert", 1, "ASSERT"); +} diff --git a/tests/units/parser.c b/tests/units/parser.c index 5b08530..3a34166 100644 --- a/tests/units/parser.c +++ b/tests/units/parser.c @@ -66,3 +66,8 @@ Test(parser, bool) { Test(parser, str) { test_parser_ok("MOD(STR[bim bam bum])", " \"bim bam bum\""); } + +Test(parser, assert) { + test_parser_ok("MOD(ASSERT(BOOL[false]))", " assert false "); + test_parser_ok("MOD(ASSERT(BOOL[true]))", " assert true "); +}