add normalizer
This commit is contained in:
parent
574c8ce884
commit
917704e9a4
|
@ -300,48 +300,123 @@ pic_optimize(pic_state *pic, pic_value expr)
|
|||
return optimize_beta(pic, expr);
|
||||
}
|
||||
|
||||
static pic_value normalize(pic_state *pic, pic_value expr, pic_value locals, bool in);
|
||||
|
||||
static pic_value
|
||||
normalize_body(pic_state *pic, pic_value expr, bool in)
|
||||
{
|
||||
pic_value v, locals;
|
||||
|
||||
locals = pic_list(pic, 1, pic_nil_value(pic));
|
||||
|
||||
v = normalize(pic, expr, locals, in);
|
||||
|
||||
if (! in) {
|
||||
return v;
|
||||
}
|
||||
return pic_list(pic, 3, S("let"), pic_car(pic, locals), v);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
normalize(pic_state *pic, pic_value expr, pic_value locals, bool in)
|
||||
{
|
||||
pic_value proc, e, it, r;
|
||||
|
||||
if (! pic_list_p(pic, expr))
|
||||
return expr;
|
||||
|
||||
if (! pic_pair_p(pic, expr))
|
||||
return expr;
|
||||
|
||||
proc = pic_list_ref(pic, expr, 0);
|
||||
if (pic_sym_p(pic, proc)) {
|
||||
pic_value sym = proc;
|
||||
|
||||
if (EQ(sym, "define")) {
|
||||
pic_value var, val;
|
||||
|
||||
var = pic_list_ref(pic, expr, 1);
|
||||
|
||||
if (! in) { /* global */
|
||||
if (pic_weak_has(pic, pic->globals, var)) {
|
||||
pic_warnf(pic, "redefining variable: %s", pic_sym(pic, var));
|
||||
}
|
||||
pic_weak_set(pic, pic->globals, var, pic_invalid_value(pic));
|
||||
} else { /* local */
|
||||
bool found = false;
|
||||
|
||||
pic_for_each (e, pic_car(pic, locals), it) {
|
||||
if (pic_eq_p(pic, e, var)) {
|
||||
pic_warnf(pic, "redefining variable: %s", pic_sym(pic, var));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! found) {
|
||||
pic_set_car(pic, locals, pic_cons(pic, var, pic_car(pic, locals)));
|
||||
}
|
||||
}
|
||||
val = normalize(pic, pic_list_ref(pic, expr, 2), locals, in);
|
||||
return pic_list(pic, 3, S("set!"), var, val);
|
||||
}
|
||||
else if (EQ(sym, "lambda")) {
|
||||
return pic_list(pic, 3, S("lambda"), pic_list_ref(pic, expr, 1), normalize_body(pic, pic_list_ref(pic, expr, 2), true));
|
||||
}
|
||||
else if (EQ(sym, "quote")) {
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
|
||||
r = pic_nil_value(pic);
|
||||
pic_for_each (e, expr, it) {
|
||||
pic_push(pic, normalize(pic, e, locals, in), r);
|
||||
}
|
||||
return pic_reverse(pic, r);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_normalize(pic_state *pic, pic_value expr)
|
||||
{
|
||||
return normalize_body(pic, expr, false);
|
||||
}
|
||||
|
||||
typedef struct analyze_scope {
|
||||
int depth;
|
||||
pic_value rest; /* Nullable */
|
||||
pic_value args, locals, captures; /* rest args variable is counted as a local */
|
||||
pic_value defer;
|
||||
pic_value args, locals, captures;
|
||||
struct analyze_scope *up;
|
||||
} analyze_scope;
|
||||
|
||||
static void
|
||||
analyzer_scope_init(pic_state *pic, analyze_scope *scope, pic_value formal, analyze_scope *up)
|
||||
analyzer_scope_init(pic_state *pic, analyze_scope *scope, pic_value args, pic_value locals, analyze_scope *up)
|
||||
{
|
||||
scope->args = pic_make_dict(pic);
|
||||
scope->locals = pic_make_dict(pic);
|
||||
scope->args = args;
|
||||
scope->locals = locals;
|
||||
scope->captures = pic_make_dict(pic);
|
||||
|
||||
/* analyze formal */
|
||||
for (; pic_pair_p(pic, formal); formal = pic_cdr(pic, formal)) {
|
||||
pic_dict_set(pic, scope->args, pic_car(pic, formal), pic_true_value(pic));
|
||||
}
|
||||
if (pic_nil_p(pic, formal)) {
|
||||
scope->rest = pic_false_value(pic);
|
||||
}
|
||||
else {
|
||||
scope->rest = formal;
|
||||
pic_dict_set(pic, scope->locals, formal, pic_true_value(pic));
|
||||
}
|
||||
|
||||
scope->up = up;
|
||||
scope->depth = up ? up->depth + 1 : 0;
|
||||
scope->defer = pic_list(pic, 1, pic_nil_value(pic));
|
||||
}
|
||||
|
||||
static void
|
||||
analyzer_scope_destroy(pic_state *PIC_UNUSED(pic), analyze_scope *PIC_UNUSED(scope))
|
||||
{
|
||||
/* nothing here */
|
||||
}
|
||||
|
||||
static bool
|
||||
find_local_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
||||
{
|
||||
return pic_dict_has(pic, scope->args, sym) || pic_dict_has(pic, scope->locals, sym) || scope->depth == 0;
|
||||
pic_value args, locals;
|
||||
|
||||
/* args */
|
||||
for (args = scope->args; pic_pair_p(pic, args); args = pic_cdr(pic, args)) {
|
||||
if (pic_eq_p(pic, pic_car(pic, args), sym))
|
||||
return true;
|
||||
}
|
||||
if (! pic_nil_p(pic, args)) {
|
||||
if (pic_eq_p(pic, args, sym))
|
||||
return true;
|
||||
}
|
||||
|
||||
/* locals */
|
||||
for (locals = scope->locals; pic_pair_p(pic, locals); locals = pic_cdr(pic, locals)) {
|
||||
if (pic_eq_p(pic, pic_car(pic, locals), sym))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -359,27 +434,7 @@ find_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
|||
depth++;
|
||||
scope = scope->up;
|
||||
}
|
||||
PIC_UNREACHABLE();
|
||||
}
|
||||
|
||||
static void
|
||||
define_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
||||
{
|
||||
if (scope->depth > 0) {
|
||||
/* local */
|
||||
if (find_local_var(pic, scope, sym)) {
|
||||
pic_warnf(pic, "redefining variable: %s", pic_sym(pic, sym));
|
||||
return;
|
||||
}
|
||||
pic_dict_set(pic, scope->locals, sym, pic_true_value(pic));
|
||||
} else {
|
||||
/* global */
|
||||
if (pic_weak_has(pic, pic->globals, sym)) {
|
||||
pic_warnf(pic, "redefining variable: %s", pic_sym(pic, sym));
|
||||
return;
|
||||
}
|
||||
pic_weak_set(pic, pic->globals, sym, pic_invalid_value(pic));
|
||||
}
|
||||
return depth - 1; /* global variable */
|
||||
}
|
||||
|
||||
static pic_value analyze(pic_state *, analyze_scope *, pic_value);
|
||||
|
@ -401,82 +456,22 @@ analyze_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
|||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
analyze_defer(pic_state *pic, analyze_scope *scope, pic_value form)
|
||||
{
|
||||
pic_value skel = pic_cons(pic, pic_invalid_value(pic), pic_invalid_value(pic));
|
||||
|
||||
pic_set_car(pic, scope->defer, pic_cons(pic, pic_cons(pic, form, skel), pic_car(pic, scope->defer)));
|
||||
|
||||
return skel;
|
||||
}
|
||||
|
||||
static void
|
||||
analyze_deferred(pic_state *pic, analyze_scope *scope)
|
||||
{
|
||||
pic_value defer, val, src, dst, it;
|
||||
|
||||
scope->defer = pic_car(pic, scope->defer);
|
||||
|
||||
pic_for_each (defer, pic_reverse(pic, scope->defer), it) {
|
||||
src = pic_car(pic, defer);
|
||||
dst = pic_cdr(pic, defer);
|
||||
|
||||
val = analyze_lambda(pic, scope, src);
|
||||
|
||||
/* copy */
|
||||
pic_set_car(pic, dst, pic_car(pic, val));
|
||||
pic_set_cdr(pic, dst, pic_cdr(pic, val));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
analyze_lambda(pic_state *pic, analyze_scope *up, pic_value form)
|
||||
{
|
||||
analyze_scope s, *scope = &s;
|
||||
pic_value formals, body;
|
||||
pic_value rest;
|
||||
pic_value args, locals, captures, key;
|
||||
int i, j, it;
|
||||
pic_value body, args, locals;
|
||||
|
||||
formals = pic_list_ref(pic, form, 1);
|
||||
body = pic_list_ref(pic, form, 2);
|
||||
args = pic_list_ref(pic, form, 1);
|
||||
locals = pic_list_ref(pic, pic_list_ref(pic, form, 2), 1);
|
||||
body = pic_list_ref(pic, pic_list_ref(pic, form, 2), 2);
|
||||
|
||||
analyzer_scope_init(pic, scope, formals, up);
|
||||
analyzer_scope_init(pic, scope, args, locals, up);
|
||||
|
||||
/* analyze body */
|
||||
body = analyze(pic, scope, body);
|
||||
analyze_deferred(pic, scope);
|
||||
|
||||
args = pic_make_vec(pic, pic_dict_size(pic, scope->args), NULL);
|
||||
for (i = 0; pic_pair_p(pic, formals); formals = pic_cdr(pic, formals), i++) {
|
||||
pic_vec_set(pic, args, i, pic_car(pic, formals));
|
||||
}
|
||||
|
||||
rest = scope->rest;
|
||||
|
||||
locals = pic_make_vec(pic, pic_dict_size(pic, scope->locals), NULL);
|
||||
j = 0;
|
||||
if (pic_sym_p(pic, scope->rest)) {
|
||||
pic_vec_set(pic, locals, j++, scope->rest);
|
||||
}
|
||||
it = 0;
|
||||
while (pic_dict_next(pic, scope->locals, &it, &key, NULL)) {
|
||||
if (pic_eq_p(pic, key, rest))
|
||||
continue;
|
||||
pic_vec_set(pic, locals, j++, key);
|
||||
}
|
||||
|
||||
captures = pic_make_vec(pic, pic_dict_size(pic, scope->captures), NULL);
|
||||
it = 0;
|
||||
j = 0;
|
||||
while (pic_dict_next(pic, scope->captures, &it, &key, NULL)) {
|
||||
pic_vec_set(pic, captures, j++, key);
|
||||
}
|
||||
|
||||
analyzer_scope_destroy(pic, scope);
|
||||
|
||||
return pic_list(pic, 6, S("lambda"), rest, args, locals, captures, body);
|
||||
return pic_list(pic, 5, S("lambda"), args, locals, scope->captures, body);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
|
@ -491,14 +486,6 @@ analyze_list(pic_state *pic, analyze_scope *scope, pic_value obj)
|
|||
return pic_reverse(pic, seq);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
analyze_define(pic_state *pic, analyze_scope *scope, pic_value obj)
|
||||
{
|
||||
define_var(pic, scope, pic_list_ref(pic, obj, 1));
|
||||
|
||||
return pic_cons(pic, pic_car(pic, obj), analyze_list(pic, scope, pic_cdr(pic, obj)));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
analyze_call(pic_state *pic, analyze_scope *scope, pic_value obj)
|
||||
{
|
||||
|
@ -523,11 +510,8 @@ analyze_node(pic_state *pic, analyze_scope *scope, pic_value obj)
|
|||
if (pic_sym_p(pic, proc)) {
|
||||
pic_value sym = proc;
|
||||
|
||||
if (EQ(sym, "define")) {
|
||||
return analyze_define(pic, scope, obj);
|
||||
}
|
||||
else if (EQ(sym, "lambda")) {
|
||||
return analyze_defer(pic, scope, obj);
|
||||
if (EQ(sym, "lambda")) {
|
||||
return analyze_lambda(pic, scope, obj);
|
||||
}
|
||||
else if (EQ(sym, "quote")) {
|
||||
return obj;
|
||||
|
@ -562,13 +546,10 @@ pic_analyze(pic_state *pic, pic_value obj)
|
|||
{
|
||||
analyze_scope s, *scope = &s;
|
||||
|
||||
analyzer_scope_init(pic, scope, pic_nil_value(pic), NULL);
|
||||
analyzer_scope_init(pic, scope, pic_nil_value(pic), pic_nil_value(pic), NULL);
|
||||
|
||||
obj = analyze(pic, scope, obj);
|
||||
|
||||
analyze_deferred(pic, scope);
|
||||
|
||||
analyzer_scope_destroy(pic, scope);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -596,14 +577,40 @@ typedef struct codegen_context {
|
|||
static void create_activation(pic_state *, codegen_context *);
|
||||
|
||||
static void
|
||||
codegen_context_init(pic_state *pic, codegen_context *cxt, codegen_context *up, pic_value rest, pic_value args, pic_value locals, pic_value captures)
|
||||
codegen_context_init(pic_state *pic, codegen_context *cxt, codegen_context *up, pic_value args, pic_value locals, pic_value captures)
|
||||
{
|
||||
cxt->up = up;
|
||||
cxt->rest = rest;
|
||||
pic_value tmp;
|
||||
int i, it;
|
||||
|
||||
cxt->args = args;
|
||||
cxt->locals = locals;
|
||||
cxt->captures = captures;
|
||||
for (i = 0, tmp = args; pic_pair_p(pic, tmp); tmp = pic_cdr(pic, tmp))
|
||||
i++;
|
||||
cxt->args = pic_make_vec(pic, i, NULL);
|
||||
for (i = 0, tmp = args; pic_pair_p(pic, tmp); tmp = pic_cdr(pic, tmp)) {
|
||||
pic_vec_set(pic, cxt->args, i++, pic_car(pic, tmp));
|
||||
}
|
||||
|
||||
cxt->rest = tmp;
|
||||
|
||||
i = pic_length(pic, locals);
|
||||
if (pic_sym_p(pic, cxt->rest)) {
|
||||
i++;
|
||||
}
|
||||
cxt->locals = pic_make_vec(pic, i, NULL);
|
||||
i = 0;
|
||||
if (pic_sym_p(pic, cxt->rest)) {
|
||||
pic_vec_set(pic, cxt->locals, i++, cxt->rest);
|
||||
}
|
||||
for (tmp = locals; pic_pair_p(pic, tmp); tmp = pic_cdr(pic, tmp)) {
|
||||
pic_vec_set(pic, cxt->locals, i++, pic_car(pic, tmp));
|
||||
}
|
||||
|
||||
cxt->captures = pic_make_vec(pic, pic_dict_size(pic, captures), NULL);
|
||||
it = i = 0;
|
||||
while (pic_dict_next(pic, captures, &it, &tmp, NULL)) {
|
||||
pic_vec_set(pic, cxt->captures, i++, tmp);
|
||||
}
|
||||
|
||||
cxt->up = up;
|
||||
|
||||
cxt->code = pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(struct code));
|
||||
cxt->clen = 0;
|
||||
|
@ -878,20 +885,18 @@ static void
|
|||
codegen_lambda(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
|
||||
{
|
||||
codegen_context c, *inner_cxt = &c;
|
||||
pic_value rest, body;
|
||||
pic_value args, locals, captures;
|
||||
pic_value args, locals, captures, body;
|
||||
|
||||
check_irep_size(pic, cxt);
|
||||
|
||||
/* extract arguments */
|
||||
rest = pic_list_ref(pic, obj, 1);
|
||||
args = pic_list_ref(pic, obj, 2);
|
||||
locals = pic_list_ref(pic, obj, 3);
|
||||
captures = pic_list_ref(pic, obj, 4);
|
||||
body = pic_list_ref(pic, obj, 5);
|
||||
args = pic_list_ref(pic, obj, 1);
|
||||
locals = pic_list_ref(pic, obj, 2);
|
||||
captures = pic_list_ref(pic, obj, 3);
|
||||
body = pic_list_ref(pic, obj, 4);
|
||||
|
||||
/* emit irep */
|
||||
codegen_context_init(pic, inner_cxt, cxt, rest, args, locals, captures);
|
||||
codegen_context_init(pic, inner_cxt, cxt, args, locals, captures);
|
||||
codegen(pic, inner_cxt, body, true);
|
||||
cxt->irep[cxt->ilen] = codegen_context_destroy(pic, inner_cxt);
|
||||
|
||||
|
@ -1050,10 +1055,9 @@ codegen(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
|
|||
static struct irep *
|
||||
pic_codegen(pic_state *pic, pic_value obj)
|
||||
{
|
||||
pic_value empty = pic_make_vec(pic, 0, NULL);
|
||||
codegen_context c, *cxt = &c;
|
||||
|
||||
codegen_context_init(pic, cxt, NULL, pic_false_value(pic), empty, empty, empty);
|
||||
codegen_context_init(pic, cxt, NULL, pic_nil_value(pic), pic_nil_value(pic), pic_make_dict(pic));
|
||||
|
||||
codegen(pic, cxt, obj, true);
|
||||
|
||||
|
@ -1081,6 +1085,14 @@ pic_compile(pic_state *pic, pic_value obj)
|
|||
|
||||
SAVE(pic, ai, obj);
|
||||
|
||||
/* normalize */
|
||||
obj = pic_normalize(pic, obj);
|
||||
#if 0
|
||||
pic_printf(pic, "## normalize completed\n~s\n", obj);
|
||||
#endif
|
||||
|
||||
SAVE(pic, ai, obj);
|
||||
|
||||
/* analyze */
|
||||
obj = pic_analyze(pic, obj);
|
||||
#if 0
|
||||
|
|
Loading…
Reference in New Issue