aboutsummaryrefslogtreecommitdiff
path: root/src/scope.c
blob: 4cec4929fcfc5602baf114ce1747eccba359df09 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <stddef.h>
#include <stdlib.h>

#include <posthaste/scope.h>
#include <posthaste/debug.h>
#include <posthaste/utils.h>
#include <posthaste/vec.h>

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);
}