From 6013d65776c485a6629e1dbc85b67e2ab5c5265b Mon Sep 17 00:00:00 2001 From: bog Date: Wed, 23 Aug 2023 22:16:53 +0200 Subject: [PATCH] ADD: strings. --- src/compiler.c | 63 +++++++++++++++++++++++++++++++++++--- src/cstatic.c | 56 +++++++++++++++++++++++++++++++++- src/lex.l | 6 ++++ src/node.h | 1 + src/opcodes.h | 4 ++- src/parser.y | 12 +++++++- src/type.h | 1 + src/utils.c | 2 +- src/utils.h | 3 +- src/value.c | 34 +++++++++++++++++++++ src/value.h | 3 ++ src/vm.c | 64 +++++++++++++++++++++++++++++++++++++++ src/vm.h | 3 +- tests/err_ty_float.wuz | 2 -- tests/err_ty_int_bool.wuz | 4 --- tests/err_ty_string.wuz | 41 +++++++++++++++++++++++++ tests/errors.sh | 4 +-- tests/test_string.wuz | 8 +++++ 18 files changed, 292 insertions(+), 19 deletions(-) create mode 100644 tests/err_ty_string.wuz create mode 100644 tests/test_string.wuz diff --git a/src/compiler.c b/src/compiler.c index ea67d17..436718d 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -17,7 +17,54 @@ void compile_node(compiler* self, node* root, program* prog) assert(root); assert(prog); - if (root->type == NODE_BOOLEAN) + if (root->type == NODE_MUL) + { + cstatic cs; + cstatic_init(&cs); + + int lhs = cstatic_resolve(&cs, root->children.data[0]); + int rhs = cstatic_resolve(&cs, root->children.data[1]); + + cstatic_free(&cs); + + if (lhs == TY_INTEGER && rhs == TY_STRING) + { + compile_node(self, root->children.data[0], prog); + compile_node(self, root->children.data[1], prog); + program_add_instr(prog, OP_SMUL, NO_PARAM); + } + else if (lhs == TY_STRING && rhs == TY_INTEGER) + { + compile_node(self, root->children.data[1], prog); + compile_node(self, root->children.data[0], prog); + program_add_instr(prog, OP_SMUL, NO_PARAM); + } + else + { + compile_number(self, root, prog, OP_IMUL, OP_FMUL); + } + } + else if (root->type == NODE_ADD) + { + cstatic cs; + cstatic_init(&cs); + + int lhs = cstatic_resolve(&cs, root->children.data[0]); + int rhs = cstatic_resolve(&cs, root->children.data[1]); + + cstatic_free(&cs); + + if (lhs == rhs && lhs == TY_STRING) + { + compile_children(self, root, prog); + program_add_instr(prog, OP_CAT, NO_PARAM); + } + else + { + compile_number(self, root, prog, OP_IADD, OP_FADD); + } + } + else if (root->type == NODE_BOOLEAN) { value val; value_init_boolean(&val, @@ -37,6 +84,16 @@ void compile_node(compiler* self, node* root, program* prog) program_add_instr(prog, OP_PUSH, idx); value_free(&val); } + else if (root->type == NODE_STRING) + { + value val; + value_init_string(&val, + root->value, + root->lineno); + size_t idx = program_add_pool(prog, &val); + program_add_instr(prog, OP_PUSH, idx); + value_free(&val); + } else if (root->type == NODE_INTEGER) { value val; @@ -60,10 +117,6 @@ void compile_node(compiler* self, node* root, program* prog) { compile_number(self, root, prog, OP_IUSUB, OP_FUSUB); } - else if (root->type == NODE_ADD) - { - compile_number(self, root, prog, OP_IADD, OP_FADD); - } else if (root->type == NODE_SUB) { compile_number(self, root, prog, OP_ISUB, OP_FSUB); diff --git a/src/cstatic.c b/src/cstatic.c index cb71407..ed225aa 100644 --- a/src/cstatic.c +++ b/src/cstatic.c @@ -16,6 +16,17 @@ int cstatic_resolve(cstatic* self, node* ast) assert(self); assert(ast); + if (ast->type == NODE_MUL) + { + int lhs = cstatic_resolve(self, ast->children.data[0]); + int rhs = cstatic_resolve(self, ast->children.data[1]); + + if (lhs == TY_STRING || rhs == TY_STRING) + { + return TY_STRING; + } + } + if (ast->type == NODE_INTEGER) { return TY_INTEGER; @@ -24,6 +35,25 @@ int cstatic_resolve(cstatic* self, node* ast) { return TY_FLOAT; } + + else if (ast->type == NODE_ADD) + { + int lhs = cstatic_resolve(self, ast->children.data[0]); + int rhs = cstatic_resolve(self, ast->children.data[1]); + + if (lhs == TY_STRING && rhs == TY_STRING) + { + return TY_STRING; + } + + return lhs; + } + + else if (ast->type == NODE_STRING) + { + return TY_STRING; + } + else if (ast->type == NODE_BOOLEAN || ast->type == NODE_EQ || ast->type == NODE_NE) @@ -64,6 +94,31 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size) } + // String Operations + if (ast->type == NODE_ADD) + { + int lhs = cstatic_resolve(self, ast->children.data[0]); + int rhs = cstatic_resolve(self, ast->children.data[1]); + + + if (lhs == rhs && lhs == TY_STRING) + { + return 1; + } + } + + if (ast->type == NODE_MUL) + { + int lhs = cstatic_resolve(self, ast->children.data[0]); + int rhs = cstatic_resolve(self, ast->children.data[1]); + + if ((lhs == TY_STRING && rhs == TY_INTEGER) + || (lhs == TY_INTEGER && rhs == TY_STRING)) + { + return 1; + } + } + // Integer Binops if (ast->type == NODE_EQ || ast->type == NODE_NE) @@ -140,7 +195,6 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size) return status; } } - // Integer Binops else if (ast->type == NODE_ADD || ast->type == NODE_SUB diff --git a/src/lex.l b/src/lex.l index 1b30856..c0c8f01 100644 --- a/src/lex.l +++ b/src/lex.l @@ -12,6 +12,7 @@ WHITESPACES [ \t]+ BOOLEAN true|false INTEGER -?[0-9]+ FLOAT -?[0-9]+\.[0-9]+ +STRING \"[^\"]*\" %% "\n" { line++; } @@ -39,6 +40,11 @@ FLOAT -?[0-9]+\.[0-9]+ return BOOLEAN; } +{STRING} { + yylval.str = yytext; + return STRING; +} + {FLOAT} { yylval.str = yytext; return FLOAT; diff --git a/src/node.h b/src/node.h index 95da6cb..537b8b5 100644 --- a/src/node.h +++ b/src/node.h @@ -4,6 +4,7 @@ #define NODE_TYPE(G) \ G(NODE_PROG), \ G(NODE_BOOLEAN), G(NODE_INTEGER), G(NODE_FLOAT), \ + G(NODE_STRING), \ G(NODE_AND), G(NODE_OR), G(NODE_NOT), \ G(NODE_EQ), G(NODE_NE), \ G(NODE_ASSERT), \ diff --git a/src/opcodes.h b/src/opcodes.h index cc24be0..28e3845 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -25,7 +25,9 @@ G(OP_FMOD), \ G(OP_FPOW), \ G(OP_FUADD), \ - G(OP_FUSUB), + G(OP_FUSUB), \ + G(OP_CAT), \ + G(OP_SMUL) enum Opcodes { OPCODES(GEN_ENUM) diff --git a/src/parser.y b/src/parser.y index fe76565..86241e6 100644 --- a/src/parser.y +++ b/src/parser.y @@ -22,7 +22,7 @@ }; %left ASSERT -%token BOOLEAN INTEGER FLOAT +%token BOOLEAN INTEGER FLOAT STRING %left EQ NE %left AND %left OR @@ -166,6 +166,16 @@ expr: $$ = $2; } + | STRING { + node* n = malloc(sizeof(node)); + size_t const SZ = strlen($1); + char str[SZ - 2]; + memcpy(str, $1 + 1, SZ - 2); + str[SZ - 2] = '\0'; + + node_init(n, NODE_STRING, str, line); + $$ = n; + } | BOOLEAN { node* n = malloc(sizeof(node)); diff --git a/src/type.h b/src/type.h index ea0d9e4..0095ad8 100644 --- a/src/type.h +++ b/src/type.h @@ -8,6 +8,7 @@ G(TY_BOOLEAN), \ G(TY_INTEGER), \ G(TY_FLOAT), \ + G(TY_STRING), \ G(TY_TYPE_COUNT) enum Types { diff --git a/src/utils.c b/src/utils.c index a996269..3c249a5 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,6 +1,6 @@ #include "utils.h" -char const* str_new(char const* str) +char* str_new(char const* str) { size_t len = strlen(str) + 1; diff --git a/src/utils.h b/src/utils.h index b14f765..8f6839a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,7 +1,8 @@ #ifndef UTILS_H #define UTILS_H #include +#include -char const* str_new(char const* str); +char* str_new(char const* str); #endif diff --git a/src/value.c b/src/value.c index b84c689..da17a33 100644 --- a/src/value.c +++ b/src/value.c @@ -30,9 +30,29 @@ void value_init_float(value* self, float real_float, int lineno) type_init(self->type, TY_FLOAT); } +void value_init_string(value* self, char* str, int lineno) +{ + assert(self); + + self->val.string = str_new(str); + + self->lineno = lineno; + + self->type = malloc(sizeof(type)); + type_init(self->type, TY_STRING); +} + void value_free(value* self) { assert(self); + + if (self->type->base_type == TY_STRING + && self->val.string != NULL) + { + free(self->val.string); + self->val.string = NULL; + } + type_free(self->type); free(self->type); self->type = NULL; @@ -44,6 +64,12 @@ value* value_new_clone(value* self) value* clone = malloc(sizeof(value)); clone->type = type_new_clone(self->type); clone->val = self->val; + + if (self->type->base_type == TY_STRING) + { + clone->val.string = str_new(self->val.string); + } + clone->lineno = self->lineno; return clone; @@ -75,6 +101,11 @@ int value_equals(value* self, value* rhs) return self->val.real_float == rhs->val.real_float; } + if (self->type->base_type == TY_STRING) + { + return strcmp(self->val.string, rhs->val.string) == 0; + } + size_t const SZ = 512; char ty_str[SZ]; @@ -95,6 +126,9 @@ size_t value_str(value* self, char* buffer, size_t size) return snprintf(buffer, size, "%s", self->val.boolean == 0 ? "false" : "true"); + case TY_STRING: + return snprintf(buffer, size, "%s", + self->val.string); case TY_INTEGER: return snprintf(buffer, size, "%d", self->val.integer); diff --git a/src/value.h b/src/value.h index 6cb51d6..f5ff96e 100644 --- a/src/value.h +++ b/src/value.h @@ -11,12 +11,15 @@ typedef struct { int boolean; int integer; float real_float; + char* string; } val; } value; void value_init_boolean(value* self, int boolean, int lineno); void value_init_integer(value* self, int integer, int lineno); void value_init_float(value* self, float real_float, int lineno); +void value_init_string(value* self, char* string, int lineno); + void value_free(value* self); value* value_new_clone(value* self); diff --git a/src/vm.c b/src/vm.c index fe08c48..550a2d6 100644 --- a/src/vm.c +++ b/src/vm.c @@ -65,6 +65,10 @@ void vm_exec(vm* self, program* prog) case OP_FPOW: vm_fpow(self); break; case OP_ASSERT: vm_assert(self); break; + + case OP_SMUL: vm_smul(self); break; + case OP_CAT: vm_cat(self); break; + default: { fprintf(stderr, "unknown opcode %s\n", OpcodesStr[opcode]); @@ -482,3 +486,63 @@ void vm_assert(vm* self) self->pc++; } +void vm_smul(vm* self) +{ + assert(self); + + size_t const SZ = 1024; + char val[SZ]; + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + + int n = lhs->val.integer; + size_t sz = 0; + + for (int i=0; ival.string); + } + + value* res = malloc(sizeof(val)); + value_init_string(res, val, lhs->lineno); + + vm_push_value(self, res); + + value_free(lhs); + free(lhs); + + value_free(rhs); + free(rhs); + + self->pc++; +} + +void vm_cat(vm* self) +{ + assert(self); + + size_t const SZ = 1024; + char val[SZ]; + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + snprintf(val, SZ, "%s%s", lhs->val.string, rhs->val.string); + + value* res = malloc(sizeof(value)); + value_init_string(res, val, lhs->lineno); + vm_push_value(self, res); + + value_free(lhs); + free(lhs); + + value_free(rhs); + free(rhs); + + self->pc++; +} diff --git a/src/vm.h b/src/vm.h index c84055e..12d5377 100644 --- a/src/vm.h +++ b/src/vm.h @@ -50,6 +50,7 @@ void vm_fpow(vm* self); void vm_eq(vm* self); void vm_assert(vm* self); - +void vm_smul(vm* self); +void vm_cat(vm* self); #endif diff --git a/tests/err_ty_float.wuz b/tests/err_ty_float.wuz index 0c1253f..a80c46f 100644 --- a/tests/err_ty_float.wuz +++ b/tests/err_ty_float.wuz @@ -9,7 +9,6 @@ 5 % 2.0 3.0 % 9 1.2 ^ 3 - true + 2.0 3.0 + false false - 2.0 @@ -21,7 +20,6 @@ true / 9 5 % false true % 9 (false && false) ^ 3 - 1.2 && 2.3 1.2 || 2.3 !12.0 diff --git a/tests/err_ty_int_bool.wuz b/tests/err_ty_int_bool.wuz index 2ff019f..3a0f489 100644 --- a/tests/err_ty_int_bool.wuz +++ b/tests/err_ty_int_bool.wuz @@ -6,25 +6,21 @@ 1 / true 1 % true 1 ^ true - true + 1 true - 1 true * 1 true / 1 true % 1 true ^ 1 - true + false true - false true * false true / false true % false true ^ false - 1 && true 2 || false !5 - true && 1 false || -2 !!5 diff --git a/tests/err_ty_string.wuz b/tests/err_ty_string.wuz new file mode 100644 index 0000000..91e5e87 --- /dev/null +++ b/tests/err_ty_string.wuz @@ -0,0 +1,41 @@ ++"a" +-"a" +5 + "a" +"z" + 2 +3.1 + "mpm" +"true" + true + +5 - "a" +"z" - 2 +3.1 - "mpm" +"true" - true + +3.1 * "mpm" +"true" * true + +5 / "a" +"z" / 2 +3.1 / "mpm" +"true" / true + +5 % "a" +"z" % 2 +3.1 % "mpm" +"true" % true + +5 ^ "a" +"z" ^ 2 +3.1 ^ "mpm" +"true" ^ true + +"aze" && true +false && "eza" + +"aze" || true +false || "eza" + +!"eza" + +"aze" && true +false && "eza" + diff --git a/tests/errors.sh b/tests/errors.sh index c403629..d3fb647 100755 --- a/tests/errors.sh +++ b/tests/errors.sh @@ -12,9 +12,9 @@ do while read line; do - echo $line | wuz &> /dev/null + echo "$line" | wuz &> /dev/null RET="$?" - if [ $RET -ne 0 ] || [ "$line" == "" ] + if [ "$RET" != "0" ] || [ "$line" == "" ] then OK=$(($OK+1)) else diff --git a/tests/test_string.wuz b/tests/test_string.wuz new file mode 100644 index 0000000..ff9695b --- /dev/null +++ b/tests/test_string.wuz @@ -0,0 +1,8 @@ +assert "salut" == "salut" +assert "salut" != "alut" + +assert "hello world" == "hello " + "world" + +assert "aaaa" == 4 * "a" +assert "aaaa" == "a" * 4 +assert "abababab" == ("a" + "b") * 4