diff --git a/src/compiler.c b/src/compiler.c index c6dad67..0d4a3e5 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -24,7 +24,14 @@ void compile_node(compiler* self, node* root, program* prog) assert(root); assert(prog); - if (root->type == NODE_INDEX) + if (root->type == NODE_DO) + { + symtable_enter_scope(self->sym); + compile_children(self, root, prog); + symtable_leave_scope(self->sym); + } + + else if (root->type == NODE_INDEX) { compile_children(self, root, prog); program_add_instr(prog, OP_ADEREF, NO_PARAM); diff --git a/src/cstatic.c b/src/cstatic.c index 58a2176..02a0492 100644 --- a/src/cstatic.c +++ b/src/cstatic.c @@ -43,6 +43,14 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast) return ty; } + if (ast->type == NODE_DO) + { + type* ty = cstatic_resolve_new(self, + sym, + ast->children.data[0]); + return ty; + } + if (ast->type == NODE_VARDECL) { type* ty = cstatic_resolve_new(self, @@ -220,6 +228,28 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz assert(self); assert(ast); + // DO BLOCK + if (ast->type == NODE_DO) + { + symtable_enter_scope(sym); + + for (size_t i=0; ichildren.size; i++) + { + int status = cstatic_check(self, + ast->children.data[i], + sym, msg, size); + + if (!status) + { + return -1; + } + } + + symtable_leave_scope(sym); + + return 1; + } + // Children for (size_t i=0; ichildren.size; i++) { @@ -417,8 +447,9 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz || ast->type == NODE_CONSTDECL) { char const* name = ast->children.data[0]->value; - - if (symtable_find(sym, name)) + symentry* entry = symtable_find(sym, name); + + if (entry && entry->scope >= sym->scope) { fprintf(stderr, "E(%d): '%s' is already defined.\n", ast->lineno, diff --git a/src/lex.l b/src/lex.l index 0618455..70ffb13 100644 --- a/src/lex.l +++ b/src/lex.l @@ -26,6 +26,8 @@ IDENT [_A-Za-z][_A-Za-z0-9]* return TYPE; } +"do" { return DO; } +"end" { return END; } "let!" { return LET_MUT; } "let" { return LET; } "assert" { return ASSERT; } diff --git a/src/node.h b/src/node.h index 5c6d0e5..580c4e1 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_ASSIGN) + G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO) #include "mutils.h" diff --git a/src/parser.y b/src/parser.y index 6ab5f6f..ab867fb 100644 --- a/src/parser.y +++ b/src/parser.y @@ -35,7 +35,7 @@ %left NOT %token OPAR CPAR %token OSQUARE CSQUARE COMMA -%token LET LET_MUT ASSIGN +%token LET LET_MUT ASSIGN DO END %type expr_unop %% @@ -78,8 +78,32 @@ exprs: expr: + // BLOCK + DO exprs END { + node *n = malloc(sizeof(node)); + node_init(n, NODE_DO, "", line); + + size_t const SZ = $2; + node* all[SZ]; + + for (size_t i=0; iid = 0; - + self->scope = 0; self->entries.size = 0; self->entries.capacity = 1; self->entries.data = malloc(sizeof(symentry*) @@ -17,14 +17,9 @@ void symtable_free(symtable* self) for (size_t i=0; ientries.size; i++) { - node_free(self->entries.data[i]->sym_node); - free(self->entries.data[i]->sym_node); - self->entries.data[i]->sym_node = NULL; - - free(self->entries.data[i]->name); - type_free(self->entries.data[i]->ty); - free(self->entries.data[i]->ty); + symentry_free(self->entries.data[i]); free(self->entries.data[i]); + } free(self->entries.data); @@ -34,6 +29,19 @@ void symtable_free(symtable* self) self->entries.data = NULL; } +void symentry_free(symentry* self) +{ + assert(self); + + node_free(self->sym_node); + free(self->sym_node); + self->sym_node = NULL; + + free(self->name); + type_free(self->ty); + free(self->ty); +} + size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sym_node) { assert(self); @@ -67,6 +75,7 @@ size_t symtable_declare(symtable* self, char const* name, type* ty, node* sym_no self->entries.data[self->entries.size]->ty = type_new_clone(ty); self->entries.data[self->entries.size]->id = self->id; self->entries.data[self->entries.size]->is_mut = 0; + self->entries.data[self->entries.size]->scope = self->scope; self->entries.data[self->entries.size]->sym_node = node_new_clone(sym_node); self->entries.size++; @@ -76,14 +85,51 @@ size_t symtable_declare(symtable* self, char const* name, type* ty, node* sym_no symentry* symtable_find(symtable* self, char const* name) { assert(self); + int scope_max = 0; + symentry* entry = NULL; for (size_t i=0; ientries.size; i++) { if (strcmp(self->entries.data[i]->name, name) == 0) { - return self->entries.data[i]; + if (entry == NULL + || self->entries.data[i]->scope > scope_max) + { + entry = self->entries.data[i]; + scope_max = entry->scope; + } } } - return NULL; + return entry; +} + +void symtable_enter_scope(symtable* self) +{ + assert(self); + self->scope++; +} + +void symtable_leave_scope(symtable* self) +{ + assert(self); + + for (size_t i=0; ientries.size; i++) + { + if (self->entries.data[i]->scope >= self->scope) + { + + for (size_t j=i; jentries.size - 1; j++) + { + self->entries.data[j] = self->entries.data[j + 1]; + } + + symentry_free(self->entries.data[i]); + free(self->entries.data[i]); + + self->entries.size--; + } + } + + self->scope--; } diff --git a/src/symtable.h b/src/symtable.h index a8d0a97..8f13d37 100644 --- a/src/symtable.h +++ b/src/symtable.h @@ -11,6 +11,7 @@ typedef struct { char* name; type* ty; node* sym_node; + int scope; } symentry; typedef struct { @@ -21,13 +22,18 @@ typedef struct { } entries; size_t id; + int scope; } symtable; void symtable_init(symtable* self); void symtable_free(symtable* self); +void symentry_free(symentry* self); size_t symtable_declare(symtable* self, char const* name, type* ty, node* sym_node); size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sym_node); symentry* symtable_find(symtable* self, char const* name); +void symtable_enter_scope(symtable* self); +void symtable_leave_scope(symtable* self); + #endif diff --git a/tests/err_do.wuz b/tests/err_do.wuz new file mode 100644 index 0000000..a1a3d6b --- /dev/null +++ b/tests/err_do.wuz @@ -0,0 +1 @@ +do let x = 3 end x diff --git a/tests/test_do.wuz b/tests/test_do.wuz new file mode 100644 index 0000000..b3fe08c --- /dev/null +++ b/tests/test_do.wuz @@ -0,0 +1,29 @@ +do + let! a = 29 + a = 31 + assert 31 == a +end + +let b = do + 4 + 1 + 7 +end + +assert 7 == b + +let c = 3.2 + +do + let c = [47] + assert [47] == c + + do + let c = "salut" + assert "salut" == c + end + + assert [47] == c +end + +assert 3.2 == c +