From 502a31d5c9a00f326018c07334dc3995aa3d1e1c Mon Sep 17 00:00:00 2001 From: bog Date: Sat, 26 Aug 2023 06:53:14 +0200 Subject: [PATCH] ADD: vars index assignment. --- src/array.c | 6 ++ src/array.h | 1 + src/compiler.c | 31 ++++++++++- src/cstatic.c | 132 +++++++++++++++++++++++++++++++++++++++++++- src/cstatic.h | 4 ++ src/node.h | 2 +- src/opcodes.h | 4 +- src/parser.y | 39 +++++++++++-- src/vm.c | 118 ++++++++++++++++++++++++++++++++++++++- src/vm.h | 3 + tests/err_vars.wuz | 4 ++ tests/test_vars.wuz | 17 ++++++ 12 files changed, 350 insertions(+), 11 deletions(-) diff --git a/src/array.c b/src/array.c index 53516c7..e33f364 100644 --- a/src/array.c +++ b/src/array.c @@ -30,6 +30,12 @@ void array_free(array* self) free(self->type); self->type = NULL; } +struct value* array_deref(array* self, size_t index) +{ + assert(index < self->children.size); + return (struct value*) self->children.data[index]; +} + struct value* array_deref_copy(array* self, size_t index) { assert(index < self->children.size); diff --git a/src/array.h b/src/array.h index 39dbf60..25498aa 100644 --- a/src/array.h +++ b/src/array.h @@ -19,6 +19,7 @@ void array_init(array* self, type* elements_type); void array_free(array* self); struct value* array_deref_copy(array* self, size_t index); +struct value* array_deref(array* self, size_t index); void array_push(array* self, struct value* element); size_t array_str(array* self, char* buffer, size_t size); diff --git a/src/compiler.c b/src/compiler.c index e94ee07..c6dad67 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -39,7 +39,7 @@ void compile_node(compiler* self, node* root, program* prog) self->sym, root->children.data[1]); - size_t id = symtable_declare_mut( + size_t id = symtable_declare( self->sym, root->children.data[0]->value, ty, @@ -76,6 +76,35 @@ void compile_node(compiler* self, node* root, program* prog) free(ty); cstatic_free(&cs); } + else if (root->type == NODE_ASSIGN) + { + node* ident_node = root->children.data[0]; + + symentry* entry = symtable_find( + self->sym, + ident_node->value + ); + + assert(entry); + + if (root->children.size == 3) + { + node* array_node = root->children.data[1]; + node* expr_node = root->children.data[2]; + + compile_node(self, array_node, prog); + compile_node(self, expr_node, prog); + + program_add_instr(prog, OP_ASTORE, entry->id); + } + else + { + node* expr_node = root->children.data[1]; + + compile_node(self, expr_node, prog); + program_add_instr(prog, OP_STORE, entry->id); + } + } else if (root->type == NODE_IDENT) { symentry* entry = symtable_find(self->sym, root->value); diff --git a/src/cstatic.c b/src/cstatic.c index f818601..58a2176 100644 --- a/src/cstatic.c +++ b/src/cstatic.c @@ -51,6 +51,21 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast) return ty; } + if (ast->type == NODE_ASSIGN) + { + size_t i = 1; + + if (ast->children.size == 3) + { + i = 2; + } + + type* ty = cstatic_resolve_new(self, + sym, + ast->children.data[i]); + return ty; + } + if (ast->type == NODE_ADD) { type* lhs = cstatic_resolve_new(self, sym, ast->children.data[0]); @@ -309,6 +324,95 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz return 1; } + if (ast->type == NODE_ASSIGN) + { + char const* name = ast->children.data[0]->value; + + if (!symtable_find(sym, name)) + { + fprintf(stderr, "E(%d): '%s' is undefined.\n", + ast->lineno, + name); + exit(-1); + } + + symentry* entry = symtable_find(sym, name); + + if (!entry->is_mut) + { + fprintf(stderr, "E(%d): '%s' is not mutable.\n", + ast->lineno, + name); + exit(-1); + } + + if (ast->children.size == 3) + { + type* expr_ty = cstatic_resolve_new(self, + sym, + ast->children.data[2] + ); + + type* array_ty = cstatic_resolve_new(self, + sym, + ast->children.data[0] + ); + + size_t dim = ast->children.data[1]->children.size; + + type* iter = array_ty; + + for (size_t i=0; isub_types.size == 0) + { + fprintf(stderr, + "E(%d): array assignement " + "wrong dimension, expected" + " '%ld', got '%ld'.\n", ast->lineno, + i, dim); + exit(-1); + } + + iter = iter->sub_types.data[0]; + } + + int status = + cstatic_check_same_type_ptr(self, + ast->children.data[0], + iter, + expr_ty, sym, + msg, size); + + if (!status) + { + return 0; + } + + type_free(array_ty); free(array_ty); + type_free(expr_ty); free(expr_ty); + + return 1; + } + else + { + int status = cstatic_check_same_type( + self, + ast->children.data[0], + ast->children.data[1], + sym, + msg, + size + ); + + if (!status) + { + return 0; + } + } + + return 1; + } if (ast->type == NODE_VARDECL || ast->type == NODE_CONSTDECL) { @@ -327,11 +431,11 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz if (ast->type == NODE_VARDECL) { - symtable_declare(sym, name, ty, ast->children.data[1]); + symtable_declare_mut(sym, name, ty, ast->children.data[1]); } else { - symtable_declare_mut(sym, name, ty, ast->children.data[1]); + symtable_declare(sym, name, ty, ast->children.data[1]); } type_free(ty); @@ -695,6 +799,30 @@ int cstatic_check_type_base(cstatic* self, node* lhs, symtable* sym, return 0; } +int cstatic_check_same_type_ptr(cstatic* self, node* lhs, + type* left, type* right, symtable* sym, char* msg, size_t size) +{ + assert(self); + + if (!type_equals(left, right)) + { + size_t sz = 0; + + sz += snprintf(msg + sz, size - sz, "E(%d): expected '", lhs->lineno); + sz += type_str(left, msg + sz, size - sz); + sz += snprintf(msg + sz, size - sz, "', got '"); + sz += type_str(right, msg + sz, size - sz); + sz += snprintf(msg + sz, size - sz, "'"); + + type_free(left); free(left); + type_free(right); free(right); + + return 0; + } + + return 1; +} + int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym, char* msg, size_t size) { diff --git a/src/cstatic.h b/src/cstatic.h index b596423..9b6d3ad 100644 --- a/src/cstatic.h +++ b/src/cstatic.h @@ -26,6 +26,10 @@ int cstatic_check_type(cstatic* self, node* lhs, symtable* sym, int cstatic_check_type_base(cstatic* self, node* lhs, symtable* sym, char* msg, size_t size, int types, ...); +int cstatic_check_same_type_ptr(cstatic* self, + node* lhs, type* left, type* right, symtable* sym, + char* msg, size_t size); + int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym, char* msg, size_t size); diff --git a/src/node.h b/src/node.h index bd19b1b..5c6d0e5 100644 --- a/src/node.h +++ b/src/node.h @@ -12,7 +12,7 @@ G(NODE_MUL), G(NODE_DIV), G(NODE_MOD), G(NODE_POW), \ G(NODE_ARRAY), G(NODE_INDEX), G(NODE_LT), G(NODE_LE), \ G(NODE_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT), \ - G(NODE_CONSTDECL) + G(NODE_CONSTDECL), G(NODE_ASSIGN) #include "mutils.h" diff --git a/src/opcodes.h b/src/opcodes.h index ad67f42..8c73fec 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -43,7 +43,9 @@ G(OP_FGT), \ G(OP_FGE), \ G(OP_STORE), \ - G(OP_LOAD) + G(OP_LOAD), \ + G(OP_ASTORE) + enum Opcodes { OPCODES(GEN_ENUM) diff --git a/src/parser.y b/src/parser.y index 5a6d5e6..6ab5f6f 100644 --- a/src/parser.y +++ b/src/parser.y @@ -79,7 +79,24 @@ exprs: expr: // INDEX - expr array { + expr array ASSIGN expr { + node* n = malloc(sizeof(node)); + node_init(n, NODE_ASSIGN, "", line); + + node* expr_node = stack_pop(); + node* array_node = stack_pop(); + node* ident_node = stack_pop(); + + node_add_child(n, ident_node); + node_add_child(n, array_node); + node_add_child(n, expr_node); + + stack_push(n); + + $$ = 1; + } + + | expr array { node *n = malloc(sizeof(node)); node_init(n, NODE_INDEX, "", line); size_t const SZ = $1 + $2; @@ -104,7 +121,7 @@ expr: | LET_MUT ident ASSIGN expr { node* n = malloc(sizeof(node)); - node_init(n, NODE_CONSTDECL, "", line); + node_init(n, NODE_VARDECL, "", line); node* rhs = stack_pop(); node* lhs = stack_pop(); @@ -119,7 +136,22 @@ expr: | LET ident ASSIGN expr { node* n = malloc(sizeof(node)); - node_init(n, NODE_VARDECL, "", line); + node_init(n, NODE_CONSTDECL, "", line); + + node* rhs = stack_pop(); + node* lhs = stack_pop(); + + node_add_child(n, lhs); + node_add_child(n, rhs); + + stack_push(n); + + $$ = 1; + } + + | ident ASSIGN expr { + node* n = malloc(sizeof(node)); + node_init(n, NODE_ASSIGN, "", line); node* rhs = stack_pop(); node* lhs = stack_pop(); @@ -151,7 +183,6 @@ expr: } - | expr LT expr { node *n = malloc(sizeof(node)); node_init(n, NODE_LT, "", line); diff --git a/src/vm.c b/src/vm.c index 2899292..86ee598 100644 --- a/src/vm.c +++ b/src/vm.c @@ -102,6 +102,7 @@ void vm_exec(vm* self, program* prog) case OP_LOAD: vm_load(self, param); break; case OP_STORE: vm_store(self, param); break; + case OP_ASTORE: vm_astore(self, param); break; default: { fprintf(stderr, "unknown opcode %s\n", @@ -167,7 +168,17 @@ void vm_set(vm* self, size_t addr, value* val) assert(self); assert(val); - if (self->vars.size > self->vars.capacity) + if (vm_exists(self, addr)) + { + size_t id = vm_find(self, addr); + value_free(self->vars.data[id]->val); + free(self->vars.data[id]->val); + + self->vars.data[id]->val = value_new_clone(val); + return; + } + + if (self->vars.size >= self->vars.capacity) { self->vars.capacity *= 2; self->vars.data = realloc( @@ -179,9 +190,42 @@ void vm_set(vm* self, size_t addr, value* val) self->vars.data[self->vars.size] = malloc(sizeof(var)); self->vars.data[self->vars.size]->addr = addr; self->vars.data[self->vars.size]->val = value_new_clone(val); + self->vars.size++; } +int vm_exists(vm* self, size_t addr) +{ + assert(self); + + for (size_t i=0; ivars.size; i++) + { + if (self->vars.data[i]->addr == addr) + { + return 1; + } + + } + + return 0; +} + +size_t vm_find(vm* self, size_t addr) +{ + assert(self); + + for (size_t i=0; ivars.size; i++) + { + if (self->vars.data[i]->addr == addr) + { + return i; + } + + } + assert(0); + return 0; +} + value* vm_get(vm* self, size_t addr) { assert(self); @@ -197,6 +241,38 @@ value* vm_get(vm* self, size_t addr) return NULL; } +value* vm_array_deref(vm* self, value* array_val, value* index_val) +{ + assert(self); + + value* idx = index_val; + value* arr = array_val; + + array* idx_array = idx->val.array_val; + + value* val = NULL; + + for (size_t i=0; ichildren.size; i++) + { + size_t index = ((value*) idx_array->children.data[i])->val.integer; + + val = (value*) array_deref( + arr->val.array_val, + index); + + if (val->type->base_type == TY_ARRAY) + { + value_free(arr); + free(arr); + arr = val; + } + } + + value_free(idx); free(idx); + + return val; +} + void vm_push(vm* self, int param) { assert(self); @@ -683,6 +759,11 @@ void vm_aderef(vm* self) vm_push_value(self, val); value_free(idx); free(idx); + + if (arr != val) + { + value_free(arr); free(arr); + } self->pc++; } @@ -960,7 +1041,6 @@ void vm_store(vm* self, int param) assert(self); value* val = vm_pop_value(self); - vm_set(self, param, val); value_free(val); @@ -979,3 +1059,37 @@ void vm_load(vm* self, int param) self->pc++; } + +void vm_astore(vm* self, int param) +{ + assert(self); + + value* expr_val = vm_pop_value(self); + value* index_val = vm_pop_value(self); + + size_t id = vm_find(self, param); + value* array_val = self->vars.data[id]->val; + + value* val = array_val; + + for (size_t i=0; ival.array_val->children.size - 1; i++) + { + value* v = (value*) index_val->val.array_val->children.data[i]; + size_t index = v->val.integer; + val = (value*) val->val.array_val->children.data[index]; + } + + size_t last_i = index_val->val.array_val->children.size - 1; + value* v = (value*) index_val->val.array_val->children.data[last_i]; + size_t index = v->val.integer; + + value_free((value*) val->val.array_val->children.data[index]); + free(val->val.array_val->children.data[index]); + + val->val.array_val->children.data[index] = (struct value*) expr_val; + + value_free(index_val); free(index_val); + + self->pc++; +} + diff --git a/src/vm.h b/src/vm.h index 36f7c9a..bf91284 100644 --- a/src/vm.h +++ b/src/vm.h @@ -36,6 +36,8 @@ value* vm_pop_value(vm* self); size_t vm_str(vm* self, char* buffer, size_t size); void vm_set(vm* self, size_t addr, value* val); +size_t vm_find(vm* self, size_t addr); +int vm_exists(vm* self, size_t addr); value* vm_get(vm* self, size_t addr); void vm_push(vm* self, int param); @@ -86,5 +88,6 @@ void vm_fge(vm* self); void vm_store(vm* self, int param); void vm_load(vm* self, int param); +void vm_astore(vm* self, int param); #endif diff --git a/tests/err_vars.wuz b/tests/err_vars.wuz index 57415d5..7d264f7 100644 --- a/tests/err_vars.wuz +++ b/tests/err_vars.wuz @@ -2,3 +2,7 @@ let x = 0 x + 1.2 let x = false x + "false" let x=0 let x=7 let x=[1, 2] x[7, 9] +let x = 0 x = 3.2 +let x = 0 x = 7 +let x=[1, 2] x[0] = 3.2 +let x=[3, 4] x[0] = 7 diff --git a/tests/test_vars.wuz b/tests/test_vars.wuz index 8438bbd..3409a08 100644 --- a/tests/test_vars.wuz +++ b/tests/test_vars.wuz @@ -15,4 +15,21 @@ assert [2, 4] == d[e] assert [6, 8] == d[f] let! g = 4 +let! h = 7 +let i = 3 +h = h + i + +assert 10 == h + +let! j = [1, 2, 3] +j[0] = 12 +j[1] = j[0] + 1 +assert [12, 13, 3] == j + +let! k = [[2, 4], [6, 8]] +k[1, 0] = 12 +assert [[2, 4], [12, 8]] == k + +k[1] = k[1] + [3] +assert [[2, 4], [12, 8, 3]] == k