aboutsummaryrefslogtreecommitdiff
path: root/src/scope.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/scope.c')
-rw-r--r--src/scope.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/src/scope.c b/src/scope.c
new file mode 100644
index 0000000..290dfd6
--- /dev/null
+++ b/src/scope.c
@@ -0,0 +1,153 @@
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <posthaste/scope.h>
+#include <posthaste/debug.h>
+#include <posthaste/vec.h>
+
+struct scope {
+ size_t id;
+ struct scope *parent;
+
+ const char *fname;
+ const char *buf;
+
+ struct vec visible;
+};
+
+struct vec scopes = {0};
+
+struct scope *create_scope()
+{
+ static size_t counter = 0;
+ if (vec_uninit(scopes)) {
+ scopes = vec_create(sizeof(struct scope *));
+ }
+
+ struct scope *scope = calloc(1, sizeof(struct scope));
+ if (!scope)
+ return NULL;
+
+ scope->visible = vec_create(sizeof(struct ast *));
+ scope->id = counter++;
+
+ vect_append(struct scope *, scopes, &scope);
+ return scope;
+}
+
+void scope_add_scope(struct scope *parent, struct scope *scope)
+{
+ scope->parent = parent;
+ scope->fname = parent->fname;
+ scope->buf = parent->buf;
+}
+
+void scope_set_file(struct scope *scope, const char *fname, const char *buf)
+{
+ scope->fname = fname;
+ scope->buf = buf;
+}
+
+struct ast *scope_find(struct scope *scope, char *id)
+{
+ /* not particularly fast, but good enough for now */
+ foreach_vec(vi, scope->visible) {
+ struct ast *n = vect_at(struct ast *, scope->visible, vi);
+ if (same_id(n->id, id))
+ return n;
+ }
+
+ return NULL;
+}
+
+struct ast *file_scope_find(struct scope *scope, char *id)
+{
+ struct ast *exists = scope_find(scope, id);
+ if (exists)
+ return exists;
+
+ if (scope->parent)
+ return file_scope_find(scope->parent, id);
+
+ return NULL;
+}
+
+int scope_add_var(struct scope *scope, struct ast *var)
+{
+ struct ast *exists = scope_find(scope, var_id(var));
+ if (exists) {
+ semantic_error(scope, var, "var redefined");
+ semantic_error(scope, exists, "previously here");
+ return -1;
+ }
+
+ vect_append(struct ast *, scope->visible, &var);
+ return 0;
+}
+
+int scope_add_formal(struct scope *scope, struct ast *formal)
+{
+ struct ast *exists = scope_find(scope, formal_id(formal));
+ if (exists) {
+ semantic_error(scope, formal, "formal redefined");
+ semantic_error(scope, exists, "previously here");
+ return -1;
+ }
+
+ vect_append(struct ast *, scope->visible, &formal);
+ return 0;
+}
+
+int scope_add_proc(struct scope *scope, struct ast *proc)
+{
+ struct ast *exists = scope_find(scope, proc_id(proc));
+ if (exists) {
+ semantic_error(scope, proc, "proc redefined");
+ semantic_error(scope, exists, "previously here");
+ return -1;
+ }
+
+ vect_append(struct ast *, scope->visible, &proc);
+ return 0;
+}
+
+int scope_add_func(struct scope *scope, struct ast *func)
+{
+ struct ast *exists = scope_find(scope, func_id(func));
+ if (exists) {
+ semantic_error(scope, func, "func redefined");
+ semantic_error(scope, exists, "previously here");
+ return -1;
+ }
+
+ vect_append(struct ast *, scope->visible, &func);
+ return 0;
+}
+
+static void destroy_scope(struct scope *scope)
+{
+ vec_destroy(&scope->visible);
+ free(scope);
+}
+
+void destroy_scopes()
+{
+ foreach_vec(si, scopes) {
+ struct scope *s = vect_at(struct scope *, scopes, si);
+ destroy_scope(s);
+ }
+
+ vec_destroy(&scopes);
+}
+
+void semantic_error(struct scope *scope, struct ast *n, const char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ struct src_issue issue;
+ issue.loc = n->loc;
+ issue.fname = scope->fname;
+ issue.buf = scope->buf;
+ vsrc_issue(issue, msg, args);
+ va_end(args);
+}