✨ bool literals.
parent
46dc8b8c2d
commit
dc4a74ad15
|
@ -1,2 +1,3 @@
|
|||
MOD ::= EXPR*
|
||||
EXPR ::= num
|
||||
EXPR ::= BUILTIN
|
||||
BUILTIN ::= num | bool
|
||||
|
|
|
@ -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'",
|
||||
|
|
78
lib/lexer.c
78
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; i<lookahead; i++)
|
||||
{
|
||||
node_t* node = lexer_try_new_next(lexer);
|
||||
|
||||
if (node)
|
||||
{
|
||||
type = node->type;
|
||||
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; i<cursor + len; i++)
|
||||
{
|
||||
if (lexer->source[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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
13
lib/parser.c
13
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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
24
lib/tysy.c
24
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
14
lib/value.c
14
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();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ typedef struct {
|
|||
|
||||
union {
|
||||
double num;
|
||||
int bool;
|
||||
} value;
|
||||
|
||||
} value_t;
|
||||
|
|
|
@ -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]");
|
||||
}
|
||||
|
|
|
@ -58,3 +58,7 @@ Test(parser, num) {
|
|||
|
||||
test_parser_ko(" § ");
|
||||
}
|
||||
|
||||
Test(parser, bool) {
|
||||
test_parser_ok("MOD(BOOL[true],BOOL[false])", "true false");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue