summaryrefslogtreecommitdiff
path: root/proc.c
blob: ff1197f82010397f1904376ab8ace10036a8fec8 (plain)
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
#include <string.h>
#include "proc.h"

/* procedures */

void proc_init(Proc *proc, Str name) {
	memset(proc, 0, sizeof(Proc));
	Graph *g = &proc->graph;
	proc->pool.arena = &proc->perm;
	proc->scope.arena = &proc->perm;
	g->pool = &proc->pool;
	g->start = node_new(g, N_START, NULL);
	g->start->type = (Type) {
		.lvl = T_BOT,
		.t = T_TUPLE,
		.next = NULL
	};
	g->stop = node_new_empty(g, N_STOP);
	g->ctrl = g->start;
	g->keepalive = node_new(g, N_KEEPALIVE, NULL);
	proc->name = name;
}

void proc_free(Proc *proc) {
	arena_free(&proc->perm);
	arena_free(&proc->scratch);
}

/* scope */

NameBinding *scope_find(Scope *scope, Str name) {
	for (ScopeFrame *f = scope->tail; f; f = f->prev) {
		for (NameBinding *b = f->latest; b; b = b->prev) {
			if (str_eql(b->name, name)) {
				return b;
			}
		}
	}
	return NULL;
}

ScopeFrame *scope_push(Scope *scope) {
	ScopeFrame *f;
	if (scope->free_scope) {
		f = scope->free_scope;
		*f = (ScopeFrame) { 0 };
		scope->free_scope = f->prev;
	} else {
		f = new(scope->arena, ScopeFrame);
	}
	f->prev = scope->tail;
	scope->tail = f;
	return f;
}

ScopeFrame *scope_pop(Scope *scope, Graph *g) {
	ScopeFrame *f = scope->tail;
	scope->tail = f->prev;
	f->prev = scope->free_scope;
	scope->free_scope = f;
	for (NameBinding *b = f->latest; b; ) {
		NameBinding *p = b->prev;
		b->prev = scope->free_bind;
		scope->free_bind = b;
		node_remove(g, b->node, g->keepalive);
		b = p;
	}
	return scope->tail;
}

/* returns previous value */
NameBinding *scope_bind(Scope *scope, Str name, Node *value, LexSpan pos, Graph *g) {
	NameBinding *prev = scope_find(scope, name);
	NameBinding *b;
	if (scope->free_bind) {
		b = scope->free_bind;
		*b = (NameBinding) { 0 };
		scope->free_bind = b->prev;
	} else {
		b = new(scope->arena, NameBinding);
	}
	b->name = name;
	b->prev = scope->tail->latest;
	scope->tail->latest = b;
	b->node = value;
	b->src_pos = pos;
	node_add(g, value, g->keepalive);
	return prev;
}

NameBinding *scope_update(NameBinding *b, Node *to, Graph *g) {
	Node *n = b->node;
	node_add(g, to, g->keepalive);
	b->node = to;
	node_remove(g, n, g->keepalive);
	return b;
}

/* adds to keepalive so these aren't invalidated */
void scope_collect(Scope *scope, Graph *g, ScopeNameList *nl, Arena *arena) {
	for (ScopeFrame *f = scope->tail; f; f = f->prev) {
		for (NameBinding *b = f->latest; b; b = b->prev) {
			node_add(g, b->node, g->keepalive);
			ZDA_PUSH(arena, nl, (ScopeName) { b->name, b->node });
		}
	}
}

void scope_uncollect(Scope *scope, Graph *g, ScopeNameList *nl) {
	for (int i = 0; i < nl->len; i++) {
		node_remove(g, nl->data[i].node, g->keepalive);
	}
}