#include #include "proc.h" /* procedures */ /* the tangle of arenas here will need to be sorted out eventually: currently * we have two arenas for every single procedure, a permanent one lasting the * full length of compilation, and a scratch arena reset after every statement. * so, long-lasting node data and very temporary allocations. * * this works fine when there's just one procedure, but long-term there should * be a couple arenas per _worker thread_, not per procedure. and for this, * there's a third kind of data --- stuff that lasts the length of parsing one * procedure, but no longer; scope information, mainly. * * so in the end we might have like * _Thread_local Arena graph_arena, scratch_arena, parse_arena; */ 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); } }