diff --git a/doc/roza.bnf b/doc/roza.bnf index 6e3027d..6de25e0 100644 --- a/doc/roza.bnf +++ b/doc/roza.bnf @@ -1,2 +1,3 @@ MOD ::= EXPR* -EXPR ::= num +EXPR ::= BUILTIN +BUILTIN ::= num | bool diff --git a/lib/compiler.c b/lib/compiler.c index 7b4335e..e34c7e4 100644 --- a/lib/compiler.c +++ b/lib/compiler.c @@ -40,6 +40,15 @@ void compiler_run(compiler_t* compiler, node_t* node) } break; + case NODE_BOOL: { + int value = strcmp(node->value.data, "true") == 0; + value_t* val = tysy_new_bool(compiler->tysy, value); + Opcode op = OP_PUSH; + param_t param = (param_t) mod_push_new_value(compiler->mod, val); + + mod_push_instr(compiler->mod, op, param); + } break; + default: { char msg[RZ_STR_LIMIT]; snprintf(msg, RZ_STR_LIMIT, "Unknown node '%s'", diff --git a/lib/lexer.c b/lib/lexer.c index 2ed9c6f..4c7e02e 100644 --- a/lib/lexer.c +++ b/lib/lexer.c @@ -36,6 +36,15 @@ node_t* lexer_try_new_next(lexer_t* lexer) } } + { + 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; } + } + // scan num { size_t cursor = lexer->cursor; @@ -93,3 +102,72 @@ node_t* lexer_try_new_next(lexer_t* lexer) return NULL; } + +NodeType lexer_peek(lexer_t* lexer, int lookahead) +{ + assert(lexer); + size_t cursor = lexer->cursor; + int line = lexer->line; + + NodeType type = 0; + + for (int i=0; itype; + node_free(node); + free(node); + } + } + + lexer->cursor = cursor; + lexer->line = line; + + return type; +} + +node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw, + NodeType type, int has_value) +{ + assert(lexer); + assert(kw); + + size_t len = strlen(kw); + size_t cursor = lexer->cursor; + + if (cursor + len <= strlen(lexer->source)) + { + int ok = 1; + + for (size_t i=cursor; isource[i] != kw[i - cursor]) + { + ok = 0; + break; + } + } + + if (ok) + { + int next_idx = lexer->cursor + len; + + if (next_idx < strlen(lexer->source) + && !isspace(lexer->source[next_idx])) + { + return NULL; + } + + node_t* node = malloc(sizeof(node_t)); + node_init(node, type, has_value ? (char*) kw : "", lexer->line); + + lexer->cursor += len; + return node; + } + } + + return NULL; +} diff --git a/lib/lexer.h b/lib/lexer.h index 179cce6..d8d9503 100644 --- a/lib/lexer.h +++ b/lib/lexer.h @@ -16,5 +16,9 @@ void lexer_init(lexer_t* lexer, char const* source, err_t* err); void lexer_free(lexer_t* lexer); node_t* lexer_try_new_next(lexer_t* lexer); +NodeType lexer_peek(lexer_t* lexer, int lookahead); + +node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw, + NodeType type, int has_value); #endif diff --git a/lib/node.h b/lib/node.h index 92e4787..f14eb4c 100644 --- a/lib/node.h +++ b/lib/node.h @@ -5,7 +5,8 @@ #define NODE_TYPE(G) \ G(NODE_MOD), \ - G(NODE_NUM) + G(NODE_NUM), \ + G(NODE_BOOL) RZ_ENUM_H(NodeType, NODE_TYPE); diff --git a/lib/parser.c b/lib/parser.c index 6583eca..147260e 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -49,13 +49,20 @@ node_t* parser_try_new_mod(parser_t* parser) node_t* parser_try_new_expr(parser_t* parser) { assert(parser); - return parser_try_new_num(parser); + return parser_try_new_builtin(parser); } -node_t* parser_try_new_num(parser_t* parser) +node_t* parser_try_new_builtin(parser_t* parser) { assert(parser); - return parser_try_new_consume(parser, NODE_NUM); + NodeType next = lexer_peek(parser->lexer, 1); + + if (next == NODE_NUM || next == NODE_BOOL) + { + return parser_try_new_consume(parser, next); + } + + return NULL; } node_t* parser_try_new_consume(parser_t* parser, NodeType type) diff --git a/lib/parser.h b/lib/parser.h index d259c72..894a393 100644 --- a/lib/parser.h +++ b/lib/parser.h @@ -16,7 +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_num(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/type.h b/lib/type.h index f0e4331..a25e79e 100644 --- a/lib/type.h +++ b/lib/type.h @@ -4,7 +4,8 @@ #include "commons.h" #define TYPE_KIND(G) \ - G(TYPE_NUM) + G(TYPE_NUM), \ + G(TYPE_BOOL) RZ_ENUM_H(TypeKind, TYPE_KIND); diff --git a/lib/tysy.c b/lib/tysy.c index 5984655..d05a597 100644 --- a/lib/tysy.c +++ b/lib/tysy.c @@ -7,9 +7,16 @@ void tysy_init(tysy_t* tysy) // num { - type_t* num = malloc(sizeof(type_t)); - type_init(num, TYPE_NUM); - tysy_register_new_type(tysy, "num", num); + type_t* ty = malloc(sizeof(type_t)); + type_init(ty, TYPE_NUM); + tysy_register_new_type(tysy, "num", ty); + } + + // bool + { + type_t* ty = malloc(sizeof(type_t)); + type_init(ty, TYPE_BOOL); + tysy_register_new_type(tysy, "bool", ty); } } @@ -65,3 +72,14 @@ value_t* tysy_new_num(tysy_t* tysy, double value) return val; } + +value_t* tysy_new_bool(tysy_t* tysy, int value) +{ + assert(tysy); + + value_t* val = malloc(sizeof(value_t)); + value_init(val, tysy_try_find_type(tysy, "bool")); + val->value.bool = value; + + return val; +} diff --git a/lib/tysy.h b/lib/tysy.h index 1719120..e947fa7 100644 --- a/lib/tysy.h +++ b/lib/tysy.h @@ -17,5 +17,6 @@ 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); #endif diff --git a/lib/value.c b/lib/value.c index 44bb89a..2c8ed43 100644 --- a/lib/value.c +++ b/lib/value.c @@ -26,6 +26,10 @@ int value_eq(value_t* value, value_t* rhs) return value->value.num == rhs->value.num; } break; + case TYPE_BOOL: { + return value->value.bool == rhs->value.bool; + } break; + default: { fprintf(stderr, "Cannot compare value of type '%s'.\n", TypeKindStr[value->type->kind]); @@ -47,6 +51,14 @@ size_t value_str(value_t* value, char* buffer, size_t size) return snprintf(buffer, size, "%lf", value->value.num); break; - default: return 0; + case TYPE_BOOL: + return snprintf(buffer, size, "%s", value->value.bool ? "true" : "false"); + break; + + default: { + fprintf(stderr, "Cannot stringify unknown value of type '%s'.\n", + TypeKindStr[value->type->kind]); + abort(); + }; } } diff --git a/lib/value.h b/lib/value.h index bc96092..5481b09 100644 --- a/lib/value.h +++ b/lib/value.h @@ -8,6 +8,7 @@ typedef struct { union { double num; + int bool; } value; } value_t; diff --git a/tests/units/lexer.c b/tests/units/lexer.c index 458eab6..c7a75e9 100644 --- a/tests/units/lexer.c +++ b/tests/units/lexer.c @@ -81,3 +81,15 @@ Test(lexer, num) { test_lexer_ko("..2"); test_lexer_ko("2.."); } + +Test(lexer, bool) { + test_lexer_ko("true3"); + test_lexer_ko("1true"); + test_lexer_ko("afalse"); + test_lexer_ko("falset"); + + test_lexer("true 3 false", 3, + "BOOL[true]", + "NUM[3]", + "BOOL[false]"); +} diff --git a/tests/units/parser.c b/tests/units/parser.c index 967f9c4..52c39a9 100644 --- a/tests/units/parser.c +++ b/tests/units/parser.c @@ -58,3 +58,7 @@ Test(parser, num) { test_parser_ko(" ยง "); } + +Test(parser, bool) { + test_parser_ok("MOD(BOOL[true],BOOL[false])", "true false"); +}