✨ str literal.
parent
dc4a74ad15
commit
f4eb33c76c
|
@ -1,3 +1,3 @@
|
||||||
MOD ::= EXPR*
|
MOD ::= EXPR*
|
||||||
EXPR ::= BUILTIN
|
EXPR ::= BUILTIN
|
||||||
BUILTIN ::= num | bool
|
BUILTIN ::= num | bool | str
|
||||||
|
|
|
@ -49,6 +49,15 @@ void compiler_run(compiler_t* compiler, node_t* node)
|
||||||
mod_push_instr(compiler->mod, op, param);
|
mod_push_instr(compiler->mod, op, param);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_STR: {
|
||||||
|
char* value = node->value.data;
|
||||||
|
value_t* val = tysy_new_str(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'",
|
||||||
|
|
50
lib/lexer.c
50
lib/lexer.c
|
@ -36,6 +36,8 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keywords
|
||||||
|
// ========
|
||||||
{
|
{
|
||||||
node_t* kw = lexer_try_new_keyword(lexer, "true", NODE_BOOL, 1);
|
node_t* kw = lexer_try_new_keyword(lexer, "true", NODE_BOOL, 1);
|
||||||
if (kw) { return kw; }
|
if (kw) { return kw; }
|
||||||
|
@ -45,6 +47,12 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
||||||
if (kw) { return kw; }
|
if (kw) { return kw; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// scan str
|
||||||
|
{
|
||||||
|
node_t* node = lexer_try_new_str(lexer);
|
||||||
|
if (node) { return node; }
|
||||||
|
}
|
||||||
|
|
||||||
// scan num
|
// scan num
|
||||||
{
|
{
|
||||||
size_t cursor = lexer->cursor;
|
size_t cursor = lexer->cursor;
|
||||||
|
@ -171,3 +179,45 @@ node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw,
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_t* lexer_try_new_str(lexer_t* lexer)
|
||||||
|
{
|
||||||
|
assert(lexer);
|
||||||
|
|
||||||
|
size_t cursor = lexer->cursor;
|
||||||
|
size_t len = strlen(lexer->source);
|
||||||
|
|
||||||
|
str_t res_str;
|
||||||
|
str_init(&res_str);
|
||||||
|
|
||||||
|
if (cursor >= len || lexer->source[cursor] != '"')
|
||||||
|
{
|
||||||
|
str_free(&res_str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor++;
|
||||||
|
|
||||||
|
while (cursor < len
|
||||||
|
&& lexer->source[cursor] != '"')
|
||||||
|
{
|
||||||
|
str_push(&res_str, lexer->source[cursor]);
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor >= len || lexer->source[cursor] != '"')
|
||||||
|
{
|
||||||
|
str_free(&res_str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor++;
|
||||||
|
|
||||||
|
node_t* tok = malloc(sizeof(node_t));
|
||||||
|
node_init(tok, NODE_STR, res_str.data, lexer->line);
|
||||||
|
str_free(&res_str);
|
||||||
|
|
||||||
|
lexer->cursor = cursor;
|
||||||
|
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
|
@ -21,4 +21,6 @@ NodeType lexer_peek(lexer_t* lexer, int lookahead);
|
||||||
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);
|
||||||
|
|
||||||
|
node_t* lexer_try_new_str(lexer_t* lexer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
#define NODE_TYPE(G) \
|
#define NODE_TYPE(G) \
|
||||||
G(NODE_MOD), \
|
G(NODE_MOD), \
|
||||||
G(NODE_NUM), \
|
G(NODE_NUM), \
|
||||||
G(NODE_BOOL)
|
G(NODE_BOOL), \
|
||||||
|
G(NODE_STR)
|
||||||
|
|
||||||
RZ_ENUM_H(NodeType, NODE_TYPE);
|
RZ_ENUM_H(NodeType, NODE_TYPE);
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ node_t* parser_try_new_builtin(parser_t* parser)
|
||||||
assert(parser);
|
assert(parser);
|
||||||
NodeType next = lexer_peek(parser->lexer, 1);
|
NodeType next = lexer_peek(parser->lexer, 1);
|
||||||
|
|
||||||
if (next == NODE_NUM || next == NODE_BOOL)
|
if (next == NODE_NUM || next == NODE_BOOL || next == NODE_STR)
|
||||||
{
|
{
|
||||||
return parser_try_new_consume(parser, next);
|
return parser_try_new_consume(parser, next);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
|
|
||||||
#define TYPE_KIND(G) \
|
#define TYPE_KIND(G) \
|
||||||
G(TYPE_NUM), \
|
G(TYPE_NUM), G(TYPE_BOOL), G(TYPE_STR)
|
||||||
G(TYPE_BOOL)
|
|
||||||
|
|
||||||
RZ_ENUM_H(TypeKind, TYPE_KIND);
|
RZ_ENUM_H(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
|
18
lib/tysy.c
18
lib/tysy.c
|
@ -18,6 +18,13 @@ void tysy_init(tysy_t* tysy)
|
||||||
type_init(ty, TYPE_BOOL);
|
type_init(ty, TYPE_BOOL);
|
||||||
tysy_register_new_type(tysy, "bool", ty);
|
tysy_register_new_type(tysy, "bool", ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// str
|
||||||
|
{
|
||||||
|
type_t* ty = malloc(sizeof(type_t));
|
||||||
|
type_init(ty, TYPE_STR);
|
||||||
|
tysy_register_new_type(tysy, "str", ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tysy_free(tysy_t* tysy)
|
void tysy_free(tysy_t* tysy)
|
||||||
|
@ -83,3 +90,14 @@ value_t* tysy_new_bool(tysy_t* tysy, int value)
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value_t* tysy_new_str(tysy_t* tysy, char* value)
|
||||||
|
{
|
||||||
|
assert(tysy);
|
||||||
|
|
||||||
|
value_t* val = malloc(sizeof(value_t));
|
||||||
|
value_init(val, tysy_try_find_type(tysy, "str"));
|
||||||
|
val->value.str = strdup(value);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
|
@ -18,5 +18,6 @@ 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);
|
value_t* tysy_new_bool(tysy_t* tysy, int value);
|
||||||
|
value_t* tysy_new_str(tysy_t* tysy, char* value);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
13
lib/value.c
13
lib/value.c
|
@ -11,6 +11,11 @@ void value_init(value_t* value, type_t* type)
|
||||||
void value_free(value_t* value)
|
void value_free(value_t* value)
|
||||||
{
|
{
|
||||||
assert(value);
|
assert(value);
|
||||||
|
|
||||||
|
if (value->type->kind == TYPE_STR)
|
||||||
|
{
|
||||||
|
free(value->value.str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int value_eq(value_t* value, value_t* rhs)
|
int value_eq(value_t* value, value_t* rhs)
|
||||||
|
@ -30,6 +35,10 @@ int value_eq(value_t* value, value_t* rhs)
|
||||||
return value->value.bool == rhs->value.bool;
|
return value->value.bool == rhs->value.bool;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case TYPE_STR: {
|
||||||
|
return strcmp(value->value.str, rhs->value.str) == 0;
|
||||||
|
} 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]);
|
||||||
|
@ -55,6 +64,10 @@ size_t value_str(value_t* value, char* buffer, size_t size)
|
||||||
return snprintf(buffer, size, "%s", value->value.bool ? "true" : "false");
|
return snprintf(buffer, size, "%s", value->value.bool ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TYPE_STR:
|
||||||
|
return snprintf(buffer, size, "\"%s\"", value->value.str);
|
||||||
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "Cannot stringify unknown value of type '%s'.\n",
|
fprintf(stderr, "Cannot stringify unknown value of type '%s'.\n",
|
||||||
TypeKindStr[value->type->kind]);
|
TypeKindStr[value->type->kind]);
|
||||||
|
|
|
@ -9,6 +9,7 @@ typedef struct {
|
||||||
union {
|
union {
|
||||||
double num;
|
double num;
|
||||||
int bool;
|
int bool;
|
||||||
|
char* str;
|
||||||
} value;
|
} value;
|
||||||
|
|
||||||
} value_t;
|
} value_t;
|
||||||
|
|
|
@ -93,3 +93,12 @@ Test(lexer, bool) {
|
||||||
"NUM[3]",
|
"NUM[3]",
|
||||||
"BOOL[false]");
|
"BOOL[false]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(lexer, str) {
|
||||||
|
test_lexer_ko("\"hello");
|
||||||
|
test_lexer_ko("hello\"");
|
||||||
|
|
||||||
|
test_lexer(" \"bonjour\" \" monde \"", 2,
|
||||||
|
"STR[bonjour]",
|
||||||
|
"STR[ monde ]");
|
||||||
|
}
|
||||||
|
|
|
@ -62,3 +62,7 @@ Test(parser, num) {
|
||||||
Test(parser, bool) {
|
Test(parser, bool) {
|
||||||
test_parser_ok("MOD(BOOL[true],BOOL[false])", "true false");
|
test_parser_ok("MOD(BOOL[true],BOOL[false])", "true false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(parser, str) {
|
||||||
|
test_parser_ok("MOD(STR[bim bam bum])", " \"bim bam bum\"");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue