From f4eb33c76c06495d21d3438dbfc28ef3d3dd66a2 Mon Sep 17 00:00:00 2001 From: bog Date: Sun, 10 Dec 2023 04:49:28 +0100 Subject: [PATCH] :sparkles: str literal. --- doc/roza.bnf | 2 +- lib/compiler.c | 9 ++++++++ lib/lexer.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ lib/lexer.h | 2 ++ lib/node.h | 3 ++- lib/parser.c | 2 +- lib/type.h | 3 +-- lib/tysy.c | 18 ++++++++++++++++ lib/tysy.h | 1 + lib/value.c | 13 ++++++++++++ lib/value.h | 1 + tests/units/lexer.c | 9 ++++++++ tests/units/parser.c | 4 ++++ 13 files changed, 112 insertions(+), 5 deletions(-) diff --git a/doc/roza.bnf b/doc/roza.bnf index 6de25e0..7015dad 100644 --- a/doc/roza.bnf +++ b/doc/roza.bnf @@ -1,3 +1,3 @@ MOD ::= EXPR* EXPR ::= BUILTIN -BUILTIN ::= num | bool +BUILTIN ::= num | bool | str diff --git a/lib/compiler.c b/lib/compiler.c index e34c7e4..33de0fa 100644 --- a/lib/compiler.c +++ b/lib/compiler.c @@ -49,6 +49,15 @@ void compiler_run(compiler_t* compiler, node_t* node) mod_push_instr(compiler->mod, op, param); } 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: { char msg[RZ_STR_LIMIT]; snprintf(msg, RZ_STR_LIMIT, "Unknown node '%s'", diff --git a/lib/lexer.c b/lib/lexer.c index 4c7e02e..d780f29 100644 --- a/lib/lexer.c +++ b/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); if (kw) { return kw; } @@ -45,6 +47,12 @@ node_t* lexer_try_new_next(lexer_t* lexer) if (kw) { return kw; } } + // scan str + { + node_t* node = lexer_try_new_str(lexer); + if (node) { return node; } + } + // scan num { size_t cursor = lexer->cursor; @@ -171,3 +179,45 @@ node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw, 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; +} diff --git a/lib/lexer.h b/lib/lexer.h index d8d9503..8a1f2d7 100644 --- a/lib/lexer.h +++ b/lib/lexer.h @@ -21,4 +21,6 @@ NodeType lexer_peek(lexer_t* lexer, int lookahead); node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw, NodeType type, int has_value); +node_t* lexer_try_new_str(lexer_t* lexer); + #endif diff --git a/lib/node.h b/lib/node.h index f14eb4c..c0342b2 100644 --- a/lib/node.h +++ b/lib/node.h @@ -6,7 +6,8 @@ #define NODE_TYPE(G) \ G(NODE_MOD), \ G(NODE_NUM), \ - G(NODE_BOOL) + G(NODE_BOOL), \ + G(NODE_STR) RZ_ENUM_H(NodeType, NODE_TYPE); diff --git a/lib/parser.c b/lib/parser.c index 147260e..0812e50 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -57,7 +57,7 @@ node_t* parser_try_new_builtin(parser_t* parser) assert(parser); 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); } diff --git a/lib/type.h b/lib/type.h index a25e79e..08612af 100644 --- a/lib/type.h +++ b/lib/type.h @@ -4,8 +4,7 @@ #include "commons.h" #define TYPE_KIND(G) \ - G(TYPE_NUM), \ - G(TYPE_BOOL) + G(TYPE_NUM), G(TYPE_BOOL), G(TYPE_STR) RZ_ENUM_H(TypeKind, TYPE_KIND); diff --git a/lib/tysy.c b/lib/tysy.c index d05a597..85e3bc5 100644 --- a/lib/tysy.c +++ b/lib/tysy.c @@ -18,6 +18,13 @@ void tysy_init(tysy_t* tysy) type_init(ty, TYPE_BOOL); 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) @@ -83,3 +90,14 @@ value_t* tysy_new_bool(tysy_t* tysy, int value) 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; +} diff --git a/lib/tysy.h b/lib/tysy.h index e947fa7..f4966ad 100644 --- a/lib/tysy.h +++ b/lib/tysy.h @@ -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_bool(tysy_t* tysy, int value); +value_t* tysy_new_str(tysy_t* tysy, char* value); #endif diff --git a/lib/value.c b/lib/value.c index 2c8ed43..b131ec2 100644 --- a/lib/value.c +++ b/lib/value.c @@ -11,6 +11,11 @@ void value_init(value_t* value, type_t* type) void value_free(value_t* value) { assert(value); + + if (value->type->kind == TYPE_STR) + { + free(value->value.str); + } } 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; } break; + case TYPE_STR: { + return strcmp(value->value.str, rhs->value.str) == 0; + } break; + default: { fprintf(stderr, "Cannot compare value of type '%s'.\n", 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"); break; + case TYPE_STR: + return snprintf(buffer, size, "\"%s\"", value->value.str); + break; + default: { fprintf(stderr, "Cannot stringify unknown value of type '%s'.\n", TypeKindStr[value->type->kind]); diff --git a/lib/value.h b/lib/value.h index 5481b09..4416cc8 100644 --- a/lib/value.h +++ b/lib/value.h @@ -9,6 +9,7 @@ typedef struct { union { double num; int bool; + char* str; } value; } value_t; diff --git a/tests/units/lexer.c b/tests/units/lexer.c index c7a75e9..9e36361 100644 --- a/tests/units/lexer.c +++ b/tests/units/lexer.c @@ -93,3 +93,12 @@ Test(lexer, bool) { "NUM[3]", "BOOL[false]"); } + +Test(lexer, str) { + test_lexer_ko("\"hello"); + test_lexer_ko("hello\""); + + test_lexer(" \"bonjour\" \" monde \"", 2, + "STR[bonjour]", + "STR[ monde ]"); +} diff --git a/tests/units/parser.c b/tests/units/parser.c index 52c39a9..5b08530 100644 --- a/tests/units/parser.c +++ b/tests/units/parser.c @@ -62,3 +62,7 @@ Test(parser, num) { Test(parser, bool) { test_parser_ok("MOD(BOOL[true],BOOL[false])", "true false"); } + +Test(parser, str) { + test_parser_ok("MOD(STR[bim bam bum])", " \"bim bam bum\""); +}