summaryrefslogtreecommitdiff
path: root/scope.c
diff options
context:
space:
mode:
Diffstat (limited to 'scope.c')
-rw-r--r--scope.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/scope.c b/scope.c
new file mode 100644
index 0000000..cc7d7db
--- /dev/null
+++ b/scope.c
@@ -0,0 +1,51 @@
+static bool add_ident_decls(Block *b, Declaration *d) {
+ bool ret = true;
+ arr_foreach(d->idents, Identifier, ident) {
+ IdentDecl **decls = &(*ident)->decls;
+ if (arr_len(*decls)) {
+ /* check that it hasn't been declared in this block */
+ IdentDecl *prev = arr_last(*decls);
+ if (prev->scope == b) {
+ err_print(d->where, "Re-declaration of identifier in the same block.");
+ info_print(prev->decl->where, "Previous declaration was here.");
+ ret = false;
+ continue;
+ }
+ }
+ ident_add_decl(*ident, d, b);
+ }
+ return ret;
+}
+
+static void remove_ident_decls(Block *b, Declaration *d) {
+ arr_foreach(d->idents, Identifier, ident) {
+ IdentTree *id_info = *ident;
+ IdentDecl **decls = &id_info->decls;
+ IdentDecl *last_decl = arr_last(*decls);
+ if (last_decl && last_decl->scope == b) {
+ arr_remove_last(decls); /* remove that declaration */
+ }
+ }
+}
+
+/* pass NULL for block for global scope */
+static bool block_enter(Block *b, Statement *stmts) {
+ bool ret = true;
+ arr_foreach(stmts, Statement, stmt) {
+ if (stmt->kind == STMT_DECL) {
+ Declaration *decl = &stmt->decl;
+ if (!add_ident_decls(b, decl))
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+static void block_exit(Block *b, Statement *stmts) {
+ arr_foreach(stmts, Statement, stmt) {
+ if (stmt->kind == STMT_DECL) {
+ Declaration *decl = &stmt->decl;
+ remove_ident_decls(b, decl);
+ }
+ }
+}