From c2e9880c996165432a9b3a360035d2f7fe1f4620 Mon Sep 17 00:00:00 2001 From: bog Date: Thu, 24 Aug 2023 11:55:54 +0200 Subject: [PATCH] ADD: array literals. --- meson.build | 3 + src/array.c | 112 ++++++++++++++++++++++++++ src/array.h | 27 +++++++ src/compiler.c | 5 ++ src/cstatic.c | 30 +++++++ src/lex.l | 6 +- src/main.c | 4 - src/node.h | 3 +- src/opcodes.h | 3 +- src/parser.y | 179 ++++++++++++++++++++++++++++------------- src/type.c | 1 - src/type.h | 3 +- src/value.c | 34 ++++++++ src/value.h | 3 + src/vm.c | 37 +++++++++ src/vm.h | 1 + tests/err_ty_array.wuz | 2 + tests/test_array.wuz | 11 +++ 18 files changed, 400 insertions(+), 64 deletions(-) create mode 100644 src/array.c create mode 100644 src/array.h create mode 100644 tests/err_ty_array.wuz create mode 100644 tests/test_array.wuz diff --git a/meson.build b/meson.build index c499225..da5972d 100644 --- a/meson.build +++ b/meson.build @@ -40,7 +40,10 @@ executable( 'src/utils.c', 'src/opcodes.c', 'src/program.c', + 'src/value.c', + 'src/array.c', + 'src/type.c', 'src/compiler.c', 'src/cstatic.c', diff --git a/src/array.c b/src/array.c new file mode 100644 index 0000000..431b23e --- /dev/null +++ b/src/array.c @@ -0,0 +1,112 @@ +#include "array.h" +#include "value.h" + +void array_init(array* self, type* elements_type) +{ + assert(self); + self->type = type_new_clone(elements_type); + self->children.size = 0; + self->children.capacity = 1; + self->children.data = malloc(sizeof(struct value*) + * self->children.capacity); +} + +void array_free(array* self) +{ + assert(self); + + for (size_t i=0; ichildren.size; i++) + { + value_free((value*) self->children.data[i]); + free(self->children.data[i]); + } + + free(self->children.data); + self->children.data = NULL; + self->children.size = 0; + self->children.capacity = 0; + + type_free(self->type); + free(self->type); self->type = NULL; +} + +void array_push(array* self, struct value* element) +{ + assert(self); + assert(element); + + if (self->children.size >= self->children.capacity) + { + self->children.capacity *= 2; + self->children.data = realloc( + self->children.data, + sizeof(struct value*) + * self->children.capacity + ); + } + + self->children.data[self->children.size] = + (struct value*) value_new_clone((value*) element); + self->children.size++; +} + +size_t array_str(array* self, char* buffer, size_t size) +{ + assert(self); + + size_t sz = 0; + + sz += snprintf(buffer + sz, size - sz, "["); + + for (size_t i=0; ichildren.size; i++) + { + if (i > 0) + { + sz += snprintf(buffer + sz, size - sz, " "); + } + + sz += value_str((value*)self->children.data[i], + buffer + sz, size - sz); + } + + sz += snprintf(buffer + sz, size - sz, "]"); + + return sz; +} + +int array_equals(array* self, array* rhs) +{ + assert(self); + assert(rhs); + + if (self->children.size != rhs->children.size) + { + return 0; + } + + for (size_t i=0; ichildren.size; i++) + { + if (!value_equals( + (value*) self->children.data[i], + (value*) rhs->children.data[i] + )) + { + return 0; + } + } + + return 1; +} + +array* array_new_clone(array* self) +{ + array* clone = malloc(sizeof(array)); + array_init(clone, self->type); + + for (size_t i=0; ichildren.size; i++) + { + array_push(clone, self->children.data[i]); + } + + return clone; +} diff --git a/src/array.h b/src/array.h new file mode 100644 index 0000000..865e561 --- /dev/null +++ b/src/array.h @@ -0,0 +1,27 @@ +#ifndef ARRAY_H +#define ARRAY_H + +#include "commons.h" +#include "type.h" + +struct value; + +typedef struct { + type* type; + struct { + size_t size; + size_t capacity; + struct value** data; + } children; +} array; + +void array_init(array* self, type* elements_type); +void array_free(array* self); + +void array_push(array* self, struct value* element); + +size_t array_str(array* self, char* buffer, size_t size); +int array_equals(array* self, array* rhs); +array* array_new_clone(array* self); + +#endif diff --git a/src/compiler.c b/src/compiler.c index 436718d..509608f 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -163,6 +163,11 @@ void compile_node(compiler* self, node* root, program* prog) compile_children(self, root, prog); program_add_instr(prog, OP_NOT, NO_PARAM); } + else if (root->type == NODE_ARRAY) + { + compile_children(self, root, prog); + program_add_instr(prog, OP_MKARRAY, root->children.size); + } else { compile_children(self, root, prog); diff --git a/src/cstatic.c b/src/cstatic.c index ed225aa..2377732 100644 --- a/src/cstatic.c +++ b/src/cstatic.c @@ -54,6 +54,11 @@ int cstatic_resolve(cstatic* self, node* ast) return TY_STRING; } + else if (ast->type == NODE_ARRAY) + { + return TY_ARRAY; + } + else if (ast->type == NODE_BOOLEAN || ast->type == NODE_EQ || ast->type == NODE_NE) @@ -93,6 +98,31 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size) } } + // Arrays + if (ast->type == NODE_ARRAY) + { + assert(ast->children.size > 0); + int ty = cstatic_resolve(self, ast->children.data[0]); + + for (size_t i=1; ichildren.size; i++) + { + int status = cstatic_check_type( + self, + ast->children.data[i], + msg, + size, + ty, + TYPE_END + ); + + if (!status) + { + return status; + } + } + + return 1; + } // String Operations if (ast->type == NODE_ADD) diff --git a/src/lex.l b/src/lex.l index c0c8f01..7ef0f48 100644 --- a/src/lex.l +++ b/src/lex.l @@ -12,11 +12,11 @@ WHITESPACES [ \t]+ BOOLEAN true|false INTEGER -?[0-9]+ FLOAT -?[0-9]+\.[0-9]+ -STRING \"[^\"]*\" +STRING \"[^"]*\" %% -"\n" { line++; } {COMMENT} {} +"\n" { line++; } {WHITESPACES} {} "assert" { return ASSERT; } @@ -34,6 +34,8 @@ STRING \"[^\"]*\" "!" { return NOT; } "(" { return OPAR; } ")" { return CPAR; } +"[" { return OSQUARE; } +"]" { return CSQUARE; } {BOOLEAN} { yylval.str = yytext; diff --git a/src/main.c b/src/main.c index 75bef70..a590bb4 100644 --- a/src/main.c +++ b/src/main.c @@ -22,10 +22,6 @@ int main(int argc, char** argv) yyin = stdin; } - node* n = malloc(sizeof(node)); - node_init(n, NODE_PROG, "", 1); - stack_push(n); - yyparse(); ast = stack_pop(); diff --git a/src/node.h b/src/node.h index 537b8b5..2644ee9 100644 --- a/src/node.h +++ b/src/node.h @@ -9,7 +9,8 @@ G(NODE_EQ), G(NODE_NE), \ G(NODE_ASSERT), \ G(NODE_UADD), G(NODE_USUB), G(NODE_ADD), G(NODE_SUB), \ - G(NODE_MUL), G(NODE_DIV), G(NODE_MOD), G(NODE_POW) + G(NODE_MUL), G(NODE_DIV), G(NODE_MOD), G(NODE_POW), \ + G(NODE_ARRAY) #include "mutils.h" diff --git a/src/opcodes.h b/src/opcodes.h index 28e3845..3654898 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -27,7 +27,8 @@ G(OP_FUADD), \ G(OP_FUSUB), \ G(OP_CAT), \ - G(OP_SMUL) + G(OP_SMUL), \ + G(OP_MKARRAY) enum Opcodes { OPCODES(GEN_ENUM) diff --git a/src/parser.y b/src/parser.y index 86241e6..05f8843 100644 --- a/src/parser.y +++ b/src/parser.y @@ -18,11 +18,12 @@ %union { char* str; - void* node_val; + size_t n_children; }; %left ASSERT %token BOOLEAN INTEGER FLOAT STRING +%type expr exprs prog; %left EQ NE %left AND %left OR @@ -30,26 +31,37 @@ %left MUL DIV MOD %left POW %left NOT -%type expr; -%token OPAR CPAR +%token OPAR CPAR OSQUARE CSQUARE %% prog: - | exprs { + { + node* n = malloc(sizeof(node)); + node_init(n, NODE_PROG, "", line); + stack_push(n); + $$ = 0; + } + + | exprs { + node* n = malloc(sizeof(node)); + node_init(n, NODE_PROG, "", line); + + for (size_t i=0; i<$1; i++) + { + node_add_child(n, stack_pop()); + } + + stack_push(n); + + $$ = $1; } ; exprs: - exprs expr { - node* parent = stack_top(); - node_add_child(parent, $2); - } + exprs expr { $$ = $1 + $2; } - | expr { - node* parent = stack_top(); - node_add_child(parent, $1); - } + | expr { $$ = $1; } ; @@ -57,115 +69,170 @@ expr: ASSERT expr { node *n = malloc(sizeof(node)); node_init(n, NODE_ASSERT, "", line); - node_add_child(n, $2); - $$ = n; + node_add_child(n, stack_pop()); + stack_push(n); + + $$ = 1; } | ADD expr { node *n = malloc(sizeof(node)); node_init(n, NODE_UADD, "", line); - node_add_child(n, $2); - $$ = n; + node_add_child(n, stack_pop()); + stack_push(n); + $$ = 1; } | SUB expr { node *n = malloc(sizeof(node)); node_init(n, NODE_USUB, "", line); - node_add_child(n, $2); - $$ = n; + node_add_child(n, stack_pop()); + stack_push(n); + $$ = 1; } | expr ADD expr { node *n = malloc(sizeof(node)); node_init(n, NODE_ADD, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | expr SUB expr { node *n = malloc(sizeof(node)); node_init(n, NODE_SUB, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | expr MUL expr { node *n = malloc(sizeof(node)); node_init(n, NODE_MUL, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | expr DIV expr { node *n = malloc(sizeof(node)); node_init(n, NODE_DIV, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | expr MOD expr { node *n = malloc(sizeof(node)); node_init(n, NODE_MOD, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | expr POW expr { node *n = malloc(sizeof(node)); node_init(n, NODE_POW, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | expr EQ expr { node *n = malloc(sizeof(node)); node_init(n, NODE_EQ, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | expr NE expr { node *n = malloc(sizeof(node)); node_init(n, NODE_NE, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | expr AND expr { node *n = malloc(sizeof(node)); node_init(n, NODE_AND, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | expr OR expr { node *n = malloc(sizeof(node)); node_init(n, NODE_OR, "", line); - node_add_child(n, $1); - node_add_child(n, $3); - $$ = n; + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; } | NOT expr { node *n = malloc(sizeof(node)); node_init(n, NODE_NOT, "", line); - node_add_child(n, $2); - $$ = n; + node_add_child(n, stack_pop()); + stack_push(n); + $$ = 1; } | OPAR expr CPAR { $$ = $2; } + | OSQUARE exprs CSQUARE { + node *n = malloc(sizeof(node)); + node_init(n, NODE_ARRAY, "", line); + + node* elements[$2]; + + for (size_t i=0; i<$2; i++) + { + elements[i] = stack_pop(); + } + + for (size_t i=0; i<$2; i++) + { + node_add_child(n, elements[$2 - 1 - i]); + } + + stack_push(n); + $$ = 1; + } + | STRING { node* n = malloc(sizeof(node)); size_t const SZ = strlen($1); @@ -174,25 +241,29 @@ expr: str[SZ - 2] = '\0'; node_init(n, NODE_STRING, str, line); - $$ = n; + stack_push(n); + $$ = 1; } | BOOLEAN { node* n = malloc(sizeof(node)); node_init(n, NODE_BOOLEAN, $1, line); - $$ = n; + stack_push(n); + $$ = 1; } | INTEGER { node* n = malloc(sizeof(node)); node_init(n, NODE_INTEGER, $1, line); - $$ = n; + stack_push(n); + $$ = 1; } | FLOAT { node* n = malloc(sizeof(node)); node_init(n, NODE_FLOAT, $1, line); - $$ = n; + stack_push(n); + $$ = 1; } ; diff --git a/src/type.c b/src/type.c index 3b417af..556c045 100644 --- a/src/type.c +++ b/src/type.c @@ -1,6 +1,5 @@ #include "type.h" - char const* TypesStr[] = { TYPES(GEN_STRING) }; void type_init(type* self, int base_type) diff --git a/src/type.h b/src/type.h index 0095ad8..a7029c3 100644 --- a/src/type.h +++ b/src/type.h @@ -1,5 +1,5 @@ #ifndef TYPE_H -#define TYPE +#define TYPE_H #include "commons.h" @@ -9,6 +9,7 @@ G(TY_INTEGER), \ G(TY_FLOAT), \ G(TY_STRING), \ + G(TY_ARRAY), \ G(TY_TYPE_COUNT) enum Types { diff --git a/src/value.c b/src/value.c index da17a33..f871433 100644 --- a/src/value.c +++ b/src/value.c @@ -1,4 +1,5 @@ #include "value.h" +#include "array.h" void value_init_boolean(value* self, int boolean, int lineno) { @@ -42,6 +43,18 @@ void value_init_string(value* self, char* str, int lineno) type_init(self->type, TY_STRING); } +void value_init_array(value* self, array* arr, int lineno) +{ + assert(self); + + + self->val.array_val = array_new_clone(arr); + + self->lineno = lineno; + self->type = malloc(sizeof(type)); + type_init(self->type, TY_ARRAY); +} + void value_free(value* self) { assert(self); @@ -53,6 +66,14 @@ void value_free(value* self) self->val.string = NULL; } + if (self->type->base_type == TY_ARRAY + && self->val.array_val != NULL) + { + array_free(self->val.array_val); + free(self->val.array_val); + self->val.array_val = NULL; + } + type_free(self->type); free(self->type); self->type = NULL; @@ -70,6 +91,11 @@ value* value_new_clone(value* self) clone->val.string = str_new(self->val.string); } + if (self->type->base_type == TY_ARRAY) + { + clone->val.array_val = array_new_clone(self->val.array_val); + } + clone->lineno = self->lineno; return clone; @@ -106,6 +132,11 @@ int value_equals(value* self, value* rhs) return strcmp(self->val.string, rhs->val.string) == 0; } + if (self->type->base_type == TY_ARRAY) + { + return array_equals(self->val.array_val, rhs->val.array_val); + } + size_t const SZ = 512; char ty_str[SZ]; @@ -126,6 +157,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_ARRAY: + return array_str(self->val.array_val, buffer, size); + case TY_STRING: return snprintf(buffer, size, "%s", self->val.string); diff --git a/src/value.h b/src/value.h index f5ff96e..f100302 100644 --- a/src/value.h +++ b/src/value.h @@ -3,6 +3,7 @@ #include "commons.h" #include "type.h" +#include "array.h" typedef struct { type* type; @@ -12,6 +13,7 @@ typedef struct { int integer; float real_float; char* string; + array* array_val; } val; } value; @@ -19,6 +21,7 @@ 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_init_array(value* self, array* arr, int lineno); void value_free(value* self); diff --git a/src/vm.c b/src/vm.c index 550a2d6..311dfd9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -69,6 +69,8 @@ void vm_exec(vm* self, program* prog) case OP_SMUL: vm_smul(self); break; case OP_CAT: vm_cat(self); break; + case OP_MKARRAY: vm_mkarray(self, param); break; + default: { fprintf(stderr, "unknown opcode %s\n", OpcodesStr[opcode]); @@ -546,3 +548,38 @@ void vm_cat(vm* self) self->pc++; } + +void vm_mkarray(vm* self, int param) +{ + value* elements[param]; + + for (int i=0; itype); + + value* arr_val = malloc(sizeof(value)); + + for (int i=0; ilineno); + vm_push_value(self, arr_val); + + for (int i=0; ipc++; +} diff --git a/src/vm.h b/src/vm.h index 12d5377..0cfeedb 100644 --- a/src/vm.h +++ b/src/vm.h @@ -52,5 +52,6 @@ void vm_assert(vm* self); void vm_smul(vm* self); void vm_cat(vm* self); +void vm_mkarray(vm* self, int param); #endif diff --git a/tests/err_ty_array.wuz b/tests/err_ty_array.wuz new file mode 100644 index 0000000..9b22710 --- /dev/null +++ b/tests/err_ty_array.wuz @@ -0,0 +1,2 @@ +[] +[1 2 3 "4"] diff --git a/tests/test_array.wuz b/tests/test_array.wuz new file mode 100644 index 0000000..76b942f --- /dev/null +++ b/tests/test_array.wuz @@ -0,0 +1,11 @@ +assert [1 - 2 3] == [-1 3] +assert [1 -2 3] == [1 -2 3] + +assert [1 2 3] == [1 2 3] +assert ["a" "b" "c"] == ["a" "b" "c"] + +assert [1 2 3] != [7 2 3] +assert [1 2 3] != [1 2 3 4] + +assert ["a" "b" "c"] != ["ac" "b" "c"] +assert ["a" "b" "c"] != ["a" "b" "c" "d"]