✨ bool literals.
parent
46dc8b8c2d
commit
dc4a74ad15
|
@ -1,2 +1,3 @@
|
||||||
MOD ::= EXPR*
|
MOD ::= EXPR*
|
||||||
EXPR ::= num
|
EXPR ::= BUILTIN
|
||||||
|
BUILTIN ::= num | bool
|
||||||
|
|
|
@ -40,6 +40,15 @@ void compiler_run(compiler_t* compiler, node_t* node)
|
||||||
|
|
||||||
} break;
|
} 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: {
|
default: {
|
||||||
char msg[RZ_STR_LIMIT];
|
char msg[RZ_STR_LIMIT];
|
||||||
snprintf(msg, RZ_STR_LIMIT, "Unknown node '%s'",
|
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
|
// scan num
|
||||||
{
|
{
|
||||||
size_t cursor = lexer->cursor;
|
size_t cursor = lexer->cursor;
|
||||||
|
@ -93,3 +102,72 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
||||||
|
|
||||||
return NULL;
|
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);
|
void lexer_free(lexer_t* lexer);
|
||||||
|
|
||||||
node_t* lexer_try_new_next(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
|
#endif
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
#define NODE_TYPE(G) \
|
#define NODE_TYPE(G) \
|
||||||
G(NODE_MOD), \
|
G(NODE_MOD), \
|
||||||
G(NODE_NUM)
|
G(NODE_NUM), \
|
||||||
|
G(NODE_BOOL)
|
||||||
|
|
||||||
RZ_ENUM_H(NodeType, NODE_TYPE);
|
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)
|
node_t* parser_try_new_expr(parser_t* parser)
|
||||||
{
|
{
|
||||||
assert(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);
|
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)
|
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_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_num(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);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
|
|
||||||
#define TYPE_KIND(G) \
|
#define TYPE_KIND(G) \
|
||||||
G(TYPE_NUM)
|
G(TYPE_NUM), \
|
||||||
|
G(TYPE_BOOL)
|
||||||
|
|
||||||
RZ_ENUM_H(TypeKind, TYPE_KIND);
|
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
|
// num
|
||||||
{
|
{
|
||||||
type_t* num = malloc(sizeof(type_t));
|
type_t* ty = malloc(sizeof(type_t));
|
||||||
type_init(num, TYPE_NUM);
|
type_init(ty, TYPE_NUM);
|
||||||
tysy_register_new_type(tysy, "num", 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;
|
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);
|
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_num(tysy_t* tysy, double value);
|
||||||
|
value_t* tysy_new_bool(tysy_t* tysy, int value);
|
||||||
|
|
||||||
#endif
|
#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;
|
return value->value.num == rhs->value.num;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case TYPE_BOOL: {
|
||||||
|
return value->value.bool == rhs->value.bool;
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "Cannot compare value of type '%s'.\n",
|
fprintf(stderr, "Cannot compare value of type '%s'.\n",
|
||||||
TypeKindStr[value->type->kind]);
|
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);
|
return snprintf(buffer, size, "%lf", value->value.num);
|
||||||
break;
|
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 {
|
union {
|
||||||
double num;
|
double num;
|
||||||
|
int bool;
|
||||||
} value;
|
} value;
|
||||||
|
|
||||||
} value_t;
|
} value_t;
|
||||||
|
|
|
@ -81,3 +81,15 @@ Test(lexer, num) {
|
||||||
test_lexer_ko("..2");
|
test_lexer_ko("..2");
|
||||||
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_ko(" § ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(parser, bool) {
|
||||||
|
test_parser_ok("MOD(BOOL[true],BOOL[false])", "true false");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue