change lookup_var API
This commit is contained in:
parent
fbeb32ee83
commit
b2c74552f2
174
src/codegen.c
174
src/codegen.c
|
@ -64,7 +64,7 @@ typedef struct analyze_scope {
|
||||||
/* local variables are 1-indexed, 0 is reserved for the callee */
|
/* local variables are 1-indexed, 0 is reserved for the callee */
|
||||||
struct xhash *local_tbl;
|
struct xhash *local_tbl;
|
||||||
/* if local var i is captured, then dirty_flags[i] == 1 */
|
/* if local var i is captured, then dirty_flags[i] == 1 */
|
||||||
int *dirty_flags;
|
struct xhash *dirty_flags;
|
||||||
|
|
||||||
struct analyze_scope *up;
|
struct analyze_scope *up;
|
||||||
} analyze_scope;
|
} analyze_scope;
|
||||||
|
@ -152,12 +152,14 @@ push_scope(analyze_state *state, pic_value args)
|
||||||
pic_state *pic = state->pic;
|
pic_state *pic = state->pic;
|
||||||
analyze_scope *scope;
|
analyze_scope *scope;
|
||||||
struct xhash *x;
|
struct xhash *x;
|
||||||
|
struct xh_iter it;
|
||||||
pic_value v;
|
pic_value v;
|
||||||
int i, l;
|
int i, l;
|
||||||
|
|
||||||
scope = (analyze_scope *)pic_alloc(pic, sizeof(analyze_scope));
|
scope = (analyze_scope *)pic_alloc(pic, sizeof(analyze_scope));
|
||||||
scope->up = state->scope;
|
scope->up = state->scope;
|
||||||
scope->local_tbl = x = xh_new();
|
scope->local_tbl = x = xh_new();
|
||||||
|
scope->dirty_flags = xh_new();
|
||||||
scope->varg = false;
|
scope->varg = false;
|
||||||
|
|
||||||
i = 1;
|
i = 1;
|
||||||
|
@ -180,7 +182,11 @@ push_scope(analyze_state *state, pic_value args)
|
||||||
}
|
}
|
||||||
scope->argc = i;
|
scope->argc = i;
|
||||||
scope->localc = l;
|
scope->localc = l;
|
||||||
scope->dirty_flags = (int *)pic_calloc(pic, i + l, sizeof(int));
|
|
||||||
|
/* set dirty flags */
|
||||||
|
for (it = xh_begin(x); ! xh_isend(&it); xh_next(x, &it)) {
|
||||||
|
xh_put(scope->dirty_flags, it.e->key, 0);
|
||||||
|
}
|
||||||
|
|
||||||
state->scope = scope;
|
state->scope = scope;
|
||||||
}
|
}
|
||||||
|
@ -192,66 +198,48 @@ pop_scope(analyze_state *state)
|
||||||
|
|
||||||
scope = state->scope;
|
scope = state->scope;
|
||||||
xh_destory(scope->local_tbl);
|
xh_destory(scope->local_tbl);
|
||||||
pic_free(state->pic, scope->dirty_flags);
|
xh_destory(scope->dirty_flags);
|
||||||
|
|
||||||
scope = scope->up;
|
scope = scope->up;
|
||||||
pic_free(state->pic, state->scope);
|
pic_free(state->pic, state->scope);
|
||||||
state->scope = scope;
|
state->scope = scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
static analyze_scope *
|
static int
|
||||||
lookup_var(analyze_state *state, const char *key, int *depth, int *idx)
|
lookup_var(analyze_state *state, const char *key)
|
||||||
{
|
{
|
||||||
analyze_scope *scope = state->scope;
|
analyze_scope *scope = state->scope;
|
||||||
struct xh_entry *e;
|
struct xh_entry *e;
|
||||||
int d = 0;
|
int depth = 0;
|
||||||
|
|
||||||
enter:
|
enter:
|
||||||
|
|
||||||
e = xh_get(scope->local_tbl, key);
|
e = xh_get(scope->local_tbl, key);
|
||||||
if (e && e->val >= 0) {
|
if (e && e->val >= 0) {
|
||||||
if (scope->up == NULL) { /* global */
|
if (depth > 0) { /* mark dirty */
|
||||||
*depth = -1;
|
xh_put(scope->dirty_flags, key, 1);
|
||||||
}
|
}
|
||||||
else { /* non-global */
|
return depth;
|
||||||
*depth = d;
|
|
||||||
}
|
|
||||||
*idx = e->val;
|
|
||||||
return scope;
|
|
||||||
}
|
}
|
||||||
if (scope->up) {
|
if (scope->up) {
|
||||||
scope = scope->up;
|
scope = scope->up;
|
||||||
++d;
|
++depth;
|
||||||
goto enter;
|
goto enter;
|
||||||
}
|
}
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
define_global_var(pic_state *pic, const char *name)
|
define_var(analyze_state *state, const char *name)
|
||||||
{
|
{
|
||||||
struct xh_entry *e;
|
struct xh_entry *e;
|
||||||
|
analyze_scope *scope = state->scope;
|
||||||
|
int c;
|
||||||
|
|
||||||
if ((e = xh_get(pic->global_tbl, name))) {
|
c = scope->argc + scope->localc++;
|
||||||
pic_warn(pic, "redefining global");
|
e = xh_put(state->scope->local_tbl, name, c);
|
||||||
return e->val;
|
|
||||||
}
|
|
||||||
e = xh_put(pic->global_tbl, name, pic->glen++);
|
|
||||||
if (pic->glen >= pic->gcapa) {
|
|
||||||
pic_error(pic, "global table overflow");
|
|
||||||
}
|
|
||||||
return e->val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
xh_put(scope->dirty_flags, name, 0);
|
||||||
define_local_var(pic_state *pic, const char *name, analyze_scope *scope)
|
|
||||||
{
|
|
||||||
struct xh_entry *e;
|
|
||||||
|
|
||||||
e = xh_put(scope->local_tbl, name, scope->argc + scope->localc++);
|
|
||||||
scope->dirty_flags = (int *)pic_realloc(pic, scope->dirty_flags, (scope->argc + scope->localc) * sizeof(int));
|
|
||||||
scope->dirty_flags[e->val] = 0;
|
|
||||||
return e->val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -261,27 +249,12 @@ is_global_scope(analyze_scope *scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
static pic_value
|
static pic_value
|
||||||
new_gref(analyze_state *state, int idx)
|
new_cref(analyze_state *state, int depth, pic_sym sym)
|
||||||
{
|
{
|
||||||
return pic_list(state->pic, 2, pic_symbol_value(state->sGREF), pic_int_value(idx));
|
return pic_list(state->pic, 3,
|
||||||
}
|
pic_symbol_value(state->sCREF),
|
||||||
|
pic_int_value(depth),
|
||||||
static pic_value
|
pic_symbol_value(sym));
|
||||||
new_gset(analyze_state *state, int idx, pic_value value)
|
|
||||||
{
|
|
||||||
return pic_list(state->pic, 3, pic_symbol_value(state->sGSET), pic_int_value(idx), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static pic_value
|
|
||||||
new_cref(analyze_state *state, int depth, int idx)
|
|
||||||
{
|
|
||||||
return pic_list(state->pic, 3, pic_symbol_value(state->sCREF), pic_int_value(depth), pic_int_value(idx));
|
|
||||||
}
|
|
||||||
|
|
||||||
static pic_value
|
|
||||||
new_cset(analyze_state *state, int depth, int idx, pic_value value)
|
|
||||||
{
|
|
||||||
return pic_list(state->pic, 4, pic_symbol_value(state->sCSET), pic_int_value(depth), pic_int_value(idx), value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static pic_value analyze_node(analyze_state *, pic_value, bool);
|
static pic_value analyze_node(analyze_state *, pic_value, bool);
|
||||||
|
@ -305,32 +278,18 @@ static pic_value
|
||||||
analyze_node(analyze_state *state, pic_value obj, bool tailpos)
|
analyze_node(analyze_state *state, pic_value obj, bool tailpos)
|
||||||
{
|
{
|
||||||
pic_state *pic = state->pic;
|
pic_state *pic = state->pic;
|
||||||
analyze_scope *scope = state->scope;
|
|
||||||
|
|
||||||
switch (pic_type(obj)) {
|
switch (pic_type(obj)) {
|
||||||
case PIC_TT_SYMBOL: {
|
case PIC_TT_SYMBOL: {
|
||||||
analyze_scope *s;
|
|
||||||
int depth = -1, idx = -1;
|
|
||||||
const char *name = pic_symbol_name(pic, pic_sym(obj));
|
const char *name = pic_symbol_name(pic, pic_sym(obj));
|
||||||
|
int depth;
|
||||||
|
|
||||||
s = lookup_var(state, name, &depth, &idx);
|
depth = lookup_var(state, name);
|
||||||
if (! s) {
|
if (depth == -1) {
|
||||||
#if DEBUG
|
|
||||||
printf("%s\n", name);
|
|
||||||
#endif
|
|
||||||
pic_error(pic, "symbol: unbound variable");
|
pic_error(pic, "symbol: unbound variable");
|
||||||
}
|
}
|
||||||
|
/* at this stage, lref/cref/gref are not distinguished */
|
||||||
switch (depth) {
|
return new_cref(state, depth, pic_sym(obj));
|
||||||
case -1: /* global */
|
|
||||||
return new_gref(state, idx);
|
|
||||||
default: /* nonlocal */
|
|
||||||
s->dirty_flags[idx] = 1;
|
|
||||||
/* at this stage, lref and cref are not distinguished */
|
|
||||||
FALLTHROUGH;
|
|
||||||
case 0: /* local */
|
|
||||||
return new_cref(state, depth, idx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case PIC_TT_PAIR: {
|
case PIC_TT_PAIR: {
|
||||||
pic_value proc;
|
pic_value proc;
|
||||||
|
@ -344,7 +303,6 @@ analyze_node(analyze_state *state, pic_value obj, bool tailpos)
|
||||||
pic_sym sym = pic_sym(proc);
|
pic_sym sym = pic_sym(proc);
|
||||||
|
|
||||||
if (sym == pic->sDEFINE) {
|
if (sym == pic->sDEFINE) {
|
||||||
int idx;
|
|
||||||
pic_value var, val;
|
pic_value var, val;
|
||||||
|
|
||||||
if (pic_length(pic, obj) < 2) {
|
if (pic_length(pic, obj) < 2) {
|
||||||
|
@ -368,14 +326,11 @@ analyze_node(analyze_state *state, pic_value obj, bool tailpos)
|
||||||
pic_error(pic, "syntax error");
|
pic_error(pic, "syntax error");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_global_scope(scope)) {
|
define_var(state, pic_symbol_name(pic, pic_sym(var)));
|
||||||
idx = define_global_var(pic, pic_symbol_name(pic, pic_sym(var)));
|
return pic_list(pic, 3,
|
||||||
return new_gset(state, idx, analyze(state, val, false));
|
pic_symbol_value(pic->sSETBANG),
|
||||||
}
|
analyze(state, var, false),
|
||||||
else {
|
analyze(state, val, false));
|
||||||
idx = define_local_var(pic, pic_symbol_name(pic, pic_sym(var)), scope);
|
|
||||||
return new_cset(state, 0, idx, analyze(state, val, false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (sym == pic->sLAMBDA) {
|
else if (sym == pic->sLAMBDA) {
|
||||||
return analyze_lambda(state, obj);
|
return analyze_lambda(state, obj);
|
||||||
|
@ -418,9 +373,8 @@ analyze_node(analyze_state *state, pic_value obj, bool tailpos)
|
||||||
return pic_reverse(pic, seq);
|
return pic_reverse(pic, seq);
|
||||||
}
|
}
|
||||||
else if (sym == pic->sSETBANG) {
|
else if (sym == pic->sSETBANG) {
|
||||||
analyze_scope *s;
|
|
||||||
pic_value var, val;
|
pic_value var, val;
|
||||||
int depth = -1, idx = -1;
|
int depth;
|
||||||
|
|
||||||
if (pic_length(pic, obj) != 3) {
|
if (pic_length(pic, obj) != 3) {
|
||||||
pic_error(pic, "syntax error");
|
pic_error(pic, "syntax error");
|
||||||
|
@ -431,23 +385,17 @@ analyze_node(analyze_state *state, pic_value obj, bool tailpos)
|
||||||
pic_error(pic, "syntax error");
|
pic_error(pic, "syntax error");
|
||||||
}
|
}
|
||||||
|
|
||||||
s = lookup_var(state, pic_symbol_name(pic, pic_sym(var)), &depth, &idx);
|
depth = lookup_var(state, pic_symbol_name(pic, pic_sym(var)));
|
||||||
if (! s) {
|
if (depth == -1) {
|
||||||
pic_error(pic, "unbound variable");
|
pic_error(pic, "unbound variable");
|
||||||
}
|
}
|
||||||
|
|
||||||
val = pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)));
|
val = pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)));
|
||||||
|
|
||||||
switch (depth) {
|
return pic_list(pic, 3,
|
||||||
case -1: /* global */
|
pic_symbol_value(pic->sSETBANG),
|
||||||
return new_gset(state, idx, val);
|
analyze(state, var, false),
|
||||||
default: /* nonlocal */
|
analyze(state, val, false));
|
||||||
s->dirty_flags[idx] = 1;
|
|
||||||
/* at this stage, lset and cset are not distinguished */
|
|
||||||
FALLTHROUGH;
|
|
||||||
case 0: /* local */
|
|
||||||
return new_cset(state, depth, idx, val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (sym == pic->sQUOTE) {
|
else if (sym == pic->sQUOTE) {
|
||||||
if (pic_length(pic, obj) != 2) {
|
if (pic_length(pic, obj) != 2) {
|
||||||
|
@ -645,7 +593,7 @@ analyze_lambda(analyze_state *state, pic_value obj)
|
||||||
{
|
{
|
||||||
pic_state *pic = state->pic;
|
pic_state *pic = state->pic;
|
||||||
int ai = pic_gc_arena_preserve(pic);
|
int ai = pic_gc_arena_preserve(pic);
|
||||||
pic_value args, body;
|
pic_value args, body, defs;
|
||||||
|
|
||||||
if (pic_length(pic, obj) < 2) {
|
if (pic_length(pic, obj) < 2) {
|
||||||
pic_error(pic, "syntax error");
|
pic_error(pic, "syntax error");
|
||||||
|
@ -657,12 +605,35 @@ analyze_lambda(analyze_state *state, pic_value obj)
|
||||||
pic_error(pic, "syntax error");
|
pic_error(pic, "syntax error");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* analyze body in inner environment */
|
|
||||||
push_scope(state, args);
|
push_scope(state, args);
|
||||||
{
|
{
|
||||||
|
struct xhash *dirty_flags;
|
||||||
|
struct xh_iter it;
|
||||||
|
|
||||||
|
/* analyze body in inner environment */
|
||||||
body = pic_cdr(pic, pic_cdr(pic, obj));
|
body = pic_cdr(pic, pic_cdr(pic, obj));
|
||||||
body = pic_cons(pic, pic_symbol_value(pic->sBEGIN), body);
|
body = pic_cons(pic, pic_symbol_value(pic->sBEGIN), body);
|
||||||
body = analyze(state, body, true);
|
body = analyze(state, body, true);
|
||||||
|
|
||||||
|
dirty_flags = state->scope->dirty_flags;
|
||||||
|
|
||||||
|
/* declare local variables */
|
||||||
|
defs = pic_list(pic, 1, pic_symbol_value(pic->sBEGIN));
|
||||||
|
for (it = xh_begin(dirty_flags); ! xh_isend(&it); xh_next(dirty_flags, &it)) {
|
||||||
|
pic_value close;
|
||||||
|
if (it.e->val == 1) {
|
||||||
|
close = pic_true_value();
|
||||||
|
} else {
|
||||||
|
close = pic_false_value();
|
||||||
|
}
|
||||||
|
defs = pic_cons(pic,
|
||||||
|
pic_list(pic, 3,
|
||||||
|
pic_symbol_value(pic->sDEFINE),
|
||||||
|
pic_symbol_value(pic_intern_cstr(pic, it.e->key)),
|
||||||
|
close),
|
||||||
|
defs);
|
||||||
|
}
|
||||||
|
defs = pic_reverse(pic, defs);
|
||||||
}
|
}
|
||||||
pop_scope(state);
|
pop_scope(state);
|
||||||
|
|
||||||
|
@ -735,7 +706,8 @@ new_local_scope(pic_state *pic, pic_value args, codegen_scope *scope)
|
||||||
new_scope->local_tbl = x = xh_new();
|
new_scope->local_tbl = x = xh_new();
|
||||||
new_scope->varg = false;
|
new_scope->varg = false;
|
||||||
|
|
||||||
i = 1; l = 0;
|
i = 1;
|
||||||
|
l = 0;
|
||||||
for (v = args; pic_pair_p(v); v = pic_cdr(pic, v)) {
|
for (v = args; pic_pair_p(v); v = pic_cdr(pic, v)) {
|
||||||
pic_value sym;
|
pic_value sym;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue