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);
|
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 {
|
typedef struct analyze_scope {
|
||||||
int depth;
|
int depth;
|
||||||
pic_value rest; /* Nullable */
|
pic_value args, locals, captures;
|
||||||
pic_value args, locals, captures; /* rest args variable is counted as a local */
|
|
||||||
pic_value defer;
|
|
||||||
struct analyze_scope *up;
|
struct analyze_scope *up;
|
||||||
} analyze_scope;
|
} analyze_scope;
|
||||||
|
|
||||||
static void
|
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->args = args;
|
||||||
scope->locals = pic_make_dict(pic);
|
scope->locals = locals;
|
||||||
scope->captures = pic_make_dict(pic);
|
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->up = up;
|
||||||
scope->depth = up ? up->depth + 1 : 0;
|
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
|
static bool
|
||||||
find_local_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
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
|
static int
|
||||||
|
@ -359,27 +434,7 @@ find_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
||||||
depth++;
|
depth++;
|
||||||
scope = scope->up;
|
scope = scope->up;
|
||||||
}
|
}
|
||||||
PIC_UNREACHABLE();
|
return depth - 1; /* global variable */
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static pic_value analyze(pic_state *, analyze_scope *, pic_value);
|
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
|
static pic_value
|
||||||
analyze_lambda(pic_state *pic, analyze_scope *up, pic_value form)
|
analyze_lambda(pic_state *pic, analyze_scope *up, pic_value form)
|
||||||
{
|
{
|
||||||
analyze_scope s, *scope = &s;
|
analyze_scope s, *scope = &s;
|
||||||
pic_value formals, body;
|
pic_value body, args, locals;
|
||||||
pic_value rest;
|
|
||||||
pic_value args, locals, captures, key;
|
|
||||||
int i, j, it;
|
|
||||||
|
|
||||||
formals = pic_list_ref(pic, form, 1);
|
args = pic_list_ref(pic, form, 1);
|
||||||
body = pic_list_ref(pic, form, 2);
|
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 */
|
/* analyze body */
|
||||||
body = analyze(pic, scope, body);
|
body = analyze(pic, scope, body);
|
||||||
analyze_deferred(pic, scope);
|
|
||||||
|
|
||||||
args = pic_make_vec(pic, pic_dict_size(pic, scope->args), NULL);
|
return pic_list(pic, 5, S("lambda"), args, locals, scope->captures, body);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static pic_value
|
static pic_value
|
||||||
|
@ -491,14 +486,6 @@ analyze_list(pic_state *pic, analyze_scope *scope, pic_value obj)
|
||||||
return pic_reverse(pic, seq);
|
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
|
static pic_value
|
||||||
analyze_call(pic_state *pic, analyze_scope *scope, pic_value obj)
|
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)) {
|
if (pic_sym_p(pic, proc)) {
|
||||||
pic_value sym = proc;
|
pic_value sym = proc;
|
||||||
|
|
||||||
if (EQ(sym, "define")) {
|
if (EQ(sym, "lambda")) {
|
||||||
return analyze_define(pic, scope, obj);
|
return analyze_lambda(pic, scope, obj);
|
||||||
}
|
|
||||||
else if (EQ(sym, "lambda")) {
|
|
||||||
return analyze_defer(pic, scope, obj);
|
|
||||||
}
|
}
|
||||||
else if (EQ(sym, "quote")) {
|
else if (EQ(sym, "quote")) {
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -562,13 +546,10 @@ pic_analyze(pic_state *pic, pic_value obj)
|
||||||
{
|
{
|
||||||
analyze_scope s, *scope = &s;
|
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);
|
obj = analyze(pic, scope, obj);
|
||||||
|
|
||||||
analyze_deferred(pic, scope);
|
|
||||||
|
|
||||||
analyzer_scope_destroy(pic, scope);
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,14 +577,40 @@ typedef struct codegen_context {
|
||||||
static void create_activation(pic_state *, codegen_context *);
|
static void create_activation(pic_state *, codegen_context *);
|
||||||
|
|
||||||
static void
|
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;
|
pic_value tmp;
|
||||||
cxt->rest = rest;
|
int i, it;
|
||||||
|
|
||||||
cxt->args = args;
|
for (i = 0, tmp = args; pic_pair_p(pic, tmp); tmp = pic_cdr(pic, tmp))
|
||||||
cxt->locals = locals;
|
i++;
|
||||||
cxt->captures = captures;
|
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->code = pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(struct code));
|
||||||
cxt->clen = 0;
|
cxt->clen = 0;
|
||||||
|
@ -878,20 +885,18 @@ static void
|
||||||
codegen_lambda(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
|
codegen_lambda(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
|
||||||
{
|
{
|
||||||
codegen_context c, *inner_cxt = &c;
|
codegen_context c, *inner_cxt = &c;
|
||||||
pic_value rest, body;
|
pic_value args, locals, captures, body;
|
||||||
pic_value args, locals, captures;
|
|
||||||
|
|
||||||
check_irep_size(pic, cxt);
|
check_irep_size(pic, cxt);
|
||||||
|
|
||||||
/* extract arguments */
|
/* extract arguments */
|
||||||
rest = pic_list_ref(pic, obj, 1);
|
args = pic_list_ref(pic, obj, 1);
|
||||||
args = pic_list_ref(pic, obj, 2);
|
locals = pic_list_ref(pic, obj, 2);
|
||||||
locals = pic_list_ref(pic, obj, 3);
|
captures = pic_list_ref(pic, obj, 3);
|
||||||
captures = pic_list_ref(pic, obj, 4);
|
body = pic_list_ref(pic, obj, 4);
|
||||||
body = pic_list_ref(pic, obj, 5);
|
|
||||||
|
|
||||||
/* emit irep */
|
/* 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);
|
codegen(pic, inner_cxt, body, true);
|
||||||
cxt->irep[cxt->ilen] = codegen_context_destroy(pic, inner_cxt);
|
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 *
|
static struct irep *
|
||||||
pic_codegen(pic_state *pic, pic_value obj)
|
pic_codegen(pic_state *pic, pic_value obj)
|
||||||
{
|
{
|
||||||
pic_value empty = pic_make_vec(pic, 0, NULL);
|
|
||||||
codegen_context c, *cxt = &c;
|
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);
|
codegen(pic, cxt, obj, true);
|
||||||
|
|
||||||
|
@ -1081,6 +1085,14 @@ pic_compile(pic_state *pic, pic_value obj)
|
||||||
|
|
||||||
SAVE(pic, ai, 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 */
|
/* analyze */
|
||||||
obj = pic_analyze(pic, obj);
|
obj = pic_analyze(pic, obj);
|
||||||
#if 0
|
#if 0
|
||||||
|
|
Loading…
Reference in New Issue