picrin/extlib/benz/codegen.c

1473 lines
36 KiB
C
Raw Normal View History

2014-08-25 00:38:09 -04:00
/**
* See Copyright Notice in picrin.h
*/
#include "picrin.h"
2015-01-22 08:15:12 -05:00
typedef xvect_t(pic_sym *) xvect;
#define xv_push_sym(v, x) xv_push(pic_sym *, (v), (x))
2014-08-25 00:38:09 -04:00
/**
* scope object
*/
typedef struct analyze_scope {
int depth;
bool varg;
xvect args, locals, captures; /* rest args variable is counted as a local */
pic_value defer;
2014-08-25 00:38:09 -04:00
struct analyze_scope *up;
} analyze_scope;
/**
* global analyzer state
*/
typedef struct analyze_state {
pic_state *pic;
analyze_scope *scope;
} analyze_state;
static bool push_scope(analyze_state *, pic_value);
static void pop_scope(analyze_state *);
static analyze_state *
new_analyze_state(pic_state *pic)
{
analyze_state *state;
2015-01-20 02:02:28 -05:00
pic_sym *sym;
2015-01-22 05:33:42 -05:00
xh_entry *it;
2014-08-25 00:38:09 -04:00
2015-05-28 03:42:16 -04:00
state = pic_malloc(pic, sizeof(analyze_state));
2014-08-25 00:38:09 -04:00
state->pic = pic;
state->scope = NULL;
/* push initial scope */
push_scope(state, pic_nil_value());
2015-01-22 05:33:42 -05:00
pic_dict_for_each (sym, pic->globals, it) {
2015-01-22 08:15:12 -05:00
xv_push_sym(state->scope->locals, sym);
2014-08-25 00:38:09 -04:00
}
return state;
}
static void
destroy_analyze_state(analyze_state *state)
{
pop_scope(state);
pic_free(state->pic, state);
}
static bool
analyze_args(pic_state *pic, pic_value formals, bool *varg, xvect *args, xvect *locals)
{
pic_value v, t;
2015-01-20 02:02:28 -05:00
pic_sym *sym;
2014-08-25 00:38:09 -04:00
for (v = formals; pic_pair_p(v); v = pic_cdr(pic, v)) {
t = pic_car(pic, v);
if (! pic_sym_p(t)) {
2014-08-25 00:38:09 -04:00
return false;
}
2015-01-20 01:31:17 -05:00
sym = pic_sym_ptr(t);
2015-01-22 08:15:12 -05:00
xv_push_sym(*args, sym);
2014-08-25 00:38:09 -04:00
}
if (pic_nil_p(v)) {
*varg = false;
}
else if (pic_sym_p(v)) {
*varg = true;
2015-01-20 01:31:17 -05:00
sym = pic_sym_ptr(v);
2015-01-22 08:15:12 -05:00
xv_push_sym(*locals, sym);
2014-08-25 00:38:09 -04:00
}
else {
return false;
}
return true;
}
static bool
push_scope(analyze_state *state, pic_value formals)
{
pic_state *pic = state->pic;
2015-05-28 03:42:16 -04:00
analyze_scope *scope = pic_malloc(pic, sizeof(analyze_scope));
2014-08-25 00:38:09 -04:00
bool varg;
xv_init(scope->args);
xv_init(scope->locals);
xv_init(scope->captures);
2014-08-25 00:38:09 -04:00
if (analyze_args(pic, formals, &varg, &scope->args, &scope->locals)) {
2014-08-25 00:38:09 -04:00
scope->up = state->scope;
scope->depth = scope->up ? scope->up->depth + 1 : 0;
scope->varg = varg;
scope->defer = pic_nil_value();
2014-08-25 00:38:09 -04:00
state->scope = scope;
return true;
}
else {
xv_destroy(scope->args);
xv_destroy(scope->locals);
xv_destroy(scope->captures);
pic_free(pic, scope);
2014-08-25 00:38:09 -04:00
return false;
}
}
static void
pop_scope(analyze_state *state)
{
2015-01-22 08:15:12 -05:00
pic_state *pic = state->pic;
2014-08-25 00:38:09 -04:00
analyze_scope *scope;
scope = state->scope;
2015-01-22 08:15:12 -05:00
xv_destroy(scope->args);
xv_destroy(scope->locals);
xv_destroy(scope->captures);
2014-08-25 00:38:09 -04:00
scope = scope->up;
pic_free(state->pic, state->scope);
state->scope = scope;
}
static bool
2015-01-20 02:02:28 -05:00
lookup_scope(analyze_scope *scope, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
size_t i;
/* args */
2015-01-22 08:15:12 -05:00
for (i = 0; i < xv_size(scope->args); ++i) {
if (xv_A(scope->args, i) == sym)
2014-08-25 00:38:09 -04:00
return true;
}
/* locals */
2015-01-22 08:15:12 -05:00
for (i = 0; i < xv_size(scope->locals); ++i) {
if (xv_A(scope->locals, i) == sym)
2014-08-25 00:38:09 -04:00
return true;
}
return false;
}
static void
2015-01-22 08:15:12 -05:00
capture_var(pic_state *pic, analyze_scope *scope, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
size_t i;
2015-01-22 08:15:12 -05:00
for (i = 0; i < xv_size(scope->captures); ++i) {
if (xv_A(scope->captures, i) == sym) {
2014-08-25 00:38:09 -04:00
break;
}
}
2015-01-22 08:15:12 -05:00
if (i == xv_size(scope->captures)) {
xv_push_sym(scope->captures, sym);
2014-08-25 00:38:09 -04:00
}
}
static int
2015-01-20 02:02:28 -05:00
find_var(analyze_state *state, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
analyze_scope *scope = state->scope;
int depth = 0;
while (scope) {
if (lookup_scope(scope, sym)) {
if (depth > 0) {
2015-01-22 08:15:12 -05:00
capture_var(state->pic, scope, sym);
2014-08-25 00:38:09 -04:00
}
return depth;
}
depth++;
scope = scope->up;
}
return -1;
}
static void
2015-01-20 02:02:28 -05:00
define_var(analyze_state *state, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
pic_state *pic = state->pic;
analyze_scope *scope = state->scope;
if (lookup_scope(scope, sym)) {
2015-01-18 21:08:27 -05:00
pic_warnf(pic, "redefining variable: ~s", pic_obj_value(sym));
2014-08-25 00:38:09 -04:00
return;
}
2015-01-22 08:15:12 -05:00
xv_push_sym(scope->locals, sym);
2014-08-25 00:38:09 -04:00
}
static pic_value analyze_node(analyze_state *, pic_value, bool);
static pic_value analyze_procedure(analyze_state *, pic_value, pic_value, pic_value);
2014-08-25 00:38:09 -04:00
static pic_value
analyze(analyze_state *state, pic_value obj, bool tailpos)
{
pic_state *pic = state->pic;
size_t ai = pic_gc_arena_preserve(pic);
pic_value res;
2015-01-20 02:02:28 -05:00
pic_sym *tag;
2014-08-25 00:38:09 -04:00
res = analyze_node(state, obj, tailpos);
2015-01-20 01:31:17 -05:00
tag = pic_sym_ptr(pic_car(pic, res));
2014-08-25 00:38:09 -04:00
if (tailpos) {
2015-01-19 00:35:42 -05:00
if (tag == pic->sIF || tag == pic->sBEGIN || tag == pic->sTAILCALL || tag == pic->sTAILCALL_WITH_VALUES || tag == pic->sRETURN) {
2014-08-25 00:38:09 -04:00
/* pass through */
}
else {
2015-01-19 00:35:42 -05:00
res = pic_list2(pic, pic_obj_value(pic->sRETURN), res);
2014-08-25 00:38:09 -04:00
}
}
pic_gc_arena_restore(pic, ai);
pic_gc_protect(pic, res);
pic_gc_protect(pic, state->scope->defer);
2014-08-25 00:38:09 -04:00
return res;
}
static pic_value
2015-01-20 02:02:28 -05:00
analyze_global_var(analyze_state *state, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
pic_state *pic = state->pic;
2015-01-19 00:35:42 -05:00
return pic_list2(pic, pic_obj_value(pic->sGREF), pic_obj_value(sym));
2014-08-25 00:38:09 -04:00
}
static pic_value
2015-01-20 02:02:28 -05:00
analyze_local_var(analyze_state *state, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
pic_state *pic = state->pic;
2015-01-19 00:35:42 -05:00
return pic_list2(pic, pic_obj_value(pic->sLREF), pic_obj_value(sym));
2014-08-25 00:38:09 -04:00
}
static pic_value
2015-01-20 02:02:28 -05:00
analyze_free_var(analyze_state *state, pic_sym *sym, int depth)
2014-08-25 00:38:09 -04:00
{
pic_state *pic = state->pic;
2015-01-19 00:35:42 -05:00
return pic_list3(pic, pic_obj_value(pic->sCREF), pic_int_value(depth), pic_obj_value(sym));
2014-08-25 00:38:09 -04:00
}
static pic_value
2015-01-20 02:02:28 -05:00
analyze_var(analyze_state *state, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
pic_state *pic = state->pic;
int depth;
if ((depth = find_var(state, sym)) == -1) {
pic_errorf(pic, "unbound variable %s", pic_symbol_name(pic, sym));
}
if (depth == state->scope->depth) {
return analyze_global_var(state, sym);
} else if (depth == 0) {
return analyze_local_var(state, sym);
} else {
return analyze_free_var(state, sym, depth);
}
}
static pic_value
analyze_defer(analyze_state *state, pic_value name, pic_value formal, pic_value body)
{
pic_state *pic = state->pic;
2015-01-20 02:02:28 -05:00
pic_sym *sNOWHERE = pic_intern_cstr(pic, "<<nowhere>>");
pic_value skel;
2015-01-19 00:35:42 -05:00
skel = pic_list2(pic, pic_obj_value(pic->sGREF), pic_obj_value(sNOWHERE));
pic_push(pic, pic_list4(pic, name, formal, body, skel), state->scope->defer);
return skel;
}
static void
analyze_deferred(analyze_state *state)
{
pic_state *pic = state->pic;
2015-01-22 05:28:31 -05:00
pic_value defer, val, name, formal, body, dst, it;
2015-01-22 05:28:31 -05:00
pic_for_each (defer, pic_reverse(pic, state->scope->defer), it) {
name = pic_list_ref(pic, defer, 0);
formal = pic_list_ref(pic, defer, 1);
body = pic_list_ref(pic, defer, 2);
dst = pic_list_ref(pic, defer, 3);
val = analyze_procedure(state, name, formal, body);
/* copy */
pic_pair_ptr(dst)->car = pic_car(pic, val);
pic_pair_ptr(dst)->cdr = pic_cdr(pic, val);
}
state->scope->defer = pic_nil_value();
}
2014-08-25 00:38:09 -04:00
static pic_value
analyze_procedure(analyze_state *state, pic_value name, pic_value formals, pic_value body_exprs)
{
pic_state *pic = state->pic;
pic_value args, locals, varg, captures, body;
assert(pic_sym_p(name) || pic_false_p(name));
if (push_scope(state, formals)) {
analyze_scope *scope = state->scope;
size_t i;
args = pic_nil_value();
2015-01-22 08:15:12 -05:00
for (i = xv_size(scope->args); i > 0; --i) {
pic_push(pic, pic_obj_value(xv_A(scope->args, i - 1)), args);
2014-08-25 00:38:09 -04:00
}
varg = scope->varg
? pic_true_value()
: pic_false_value();
/* To know what kind of local variables are defined, analyze body at first. */
2015-01-18 21:08:27 -05:00
body = analyze(state, pic_cons(pic, pic_obj_value(pic->rBEGIN), body_exprs), true);
2014-08-25 00:38:09 -04:00
analyze_deferred(state);
2014-08-25 00:38:09 -04:00
locals = pic_nil_value();
2015-01-22 08:15:12 -05:00
for (i = xv_size(scope->locals); i > 0; --i) {
pic_push(pic, pic_obj_value(xv_A(scope->locals, i - 1)), locals);
2014-08-25 00:38:09 -04:00
}
captures = pic_nil_value();
2015-01-22 08:15:12 -05:00
for (i = xv_size(scope->captures); i > 0; --i) {
pic_push(pic, pic_obj_value(xv_A(scope->captures, i - 1)), captures);
2014-08-25 00:38:09 -04:00
}
pop_scope(state);
}
else {
2015-02-01 07:25:48 -05:00
pic_errorf(pic, "invalid formal syntax: ~s", formals);
2014-08-25 00:38:09 -04:00
}
2015-01-18 21:08:27 -05:00
return pic_list7(pic, pic_obj_value(pic->sLAMBDA), name, args, locals, varg, captures, body);
2014-08-25 00:38:09 -04:00
}
static pic_value
analyze_lambda(analyze_state *state, pic_value obj)
{
pic_state *pic = state->pic;
pic_value formals, body_exprs;
if (pic_length(pic, obj) < 2) {
2014-09-16 10:43:15 -04:00
pic_errorf(pic, "syntax error");
2014-08-25 00:38:09 -04:00
}
formals = pic_list_ref(pic, obj, 1);
body_exprs = pic_list_tail(pic, obj, 2);
return analyze_defer(state, pic_false_value(), formals, body_exprs);
2014-08-25 00:38:09 -04:00
}
static pic_value
2015-01-20 02:02:28 -05:00
analyze_declare(analyze_state *state, pic_sym *var)
2014-08-25 00:38:09 -04:00
{
define_var(state, var);
return analyze_var(state, var);
}
static pic_value
analyze_define(analyze_state *state, pic_value obj)
{
pic_state *pic = state->pic;
pic_value var, val;
2015-01-20 02:02:28 -05:00
pic_sym *sym;
2014-08-25 00:38:09 -04:00
if (pic_length(pic, obj) != 3) {
2014-09-16 10:43:15 -04:00
pic_errorf(pic, "syntax error");
2014-08-25 00:38:09 -04:00
}
var = pic_list_ref(pic, obj, 1);
if (! pic_sym_p(var)) {
2014-09-16 10:43:15 -04:00
pic_errorf(pic, "syntax error");
2014-08-25 00:38:09 -04:00
} else {
2015-01-20 01:31:17 -05:00
sym = pic_sym_ptr(var);
2014-08-25 00:38:09 -04:00
}
var = analyze_declare(state, sym);
if (pic_pair_p(pic_list_ref(pic, obj, 2))
&& pic_sym_p(pic_list_ref(pic, pic_list_ref(pic, obj, 2), 0))
2015-01-20 01:31:17 -05:00
&& pic_sym_ptr(pic_list_ref(pic, pic_list_ref(pic, obj, 2), 0)) == pic->rLAMBDA) {
2014-08-25 00:38:09 -04:00
pic_value formals, body_exprs;
formals = pic_list_ref(pic, pic_list_ref(pic, obj, 2), 1);
body_exprs = pic_list_tail(pic, pic_list_ref(pic, obj, 2), 2);
2015-01-18 21:08:27 -05:00
val = analyze_defer(state, pic_obj_value(sym), formals, body_exprs);
2014-08-25 00:38:09 -04:00
} else {
if (pic_length(pic, obj) != 3) {
2014-09-16 10:43:15 -04:00
pic_errorf(pic, "syntax error");
2014-08-25 00:38:09 -04:00
}
val = analyze(state, pic_list_ref(pic, obj, 2), false);
}
2015-01-18 21:08:27 -05:00
return pic_list3(pic, pic_obj_value(pic->sSETBANG), var, val);
2014-08-25 00:38:09 -04:00
}
static pic_value
analyze_if(analyze_state *state, pic_value obj, bool tailpos)
{
pic_state *pic = state->pic;
pic_value cond, if_true, if_false;
2015-06-09 03:34:45 -04:00
if_false = pic_undef_value();
2014-08-25 00:38:09 -04:00
switch (pic_length(pic, obj)) {
default:
2014-09-16 10:43:15 -04:00
pic_errorf(pic, "syntax error");
2014-08-25 00:38:09 -04:00
case 4:
if_false = pic_list_ref(pic, obj, 3);
PIC_FALLTHROUGH;
2014-08-25 00:38:09 -04:00
case 3:
if_true = pic_list_ref(pic, obj, 2);
}
/* analyze in order */
cond = analyze(state, pic_list_ref(pic, obj, 1), false);
if_true = analyze(state, if_true, tailpos);
if_false = analyze(state, if_false, tailpos);
2015-01-18 21:08:27 -05:00
return pic_list4(pic, pic_obj_value(pic->sIF), cond, if_true, if_false);
2014-08-25 00:38:09 -04:00
}
static pic_value
analyze_begin(analyze_state *state, pic_value obj, bool tailpos)
{
pic_state *pic = state->pic;
pic_value seq;
bool tail;
switch (pic_length(pic, obj)) {
case 1:
2015-06-09 03:34:45 -04:00
return analyze(state, pic_undef_value(), tailpos);
2014-08-25 00:38:09 -04:00
case 2:
return analyze(state, pic_list_ref(pic, obj, 1), tailpos);
default:
2015-01-18 21:08:27 -05:00
seq = pic_list1(pic, pic_obj_value(pic->sBEGIN));
2014-08-25 00:38:09 -04:00
for (obj = pic_cdr(pic, obj); ! pic_nil_p(obj); obj = pic_cdr(pic, obj)) {
if (pic_nil_p(pic_cdr(pic, obj))) {
tail = tailpos;
} else {
tail = false;
}
seq = pic_cons(pic, analyze(state, pic_car(pic, obj), tail), seq);
}
return pic_reverse(pic, seq);
}
}
static pic_value
analyze_set(analyze_state *state, pic_value obj)
{
pic_state *pic = state->pic;
pic_value var, val;
if (pic_length(pic, obj) != 3) {
2014-09-16 10:43:15 -04:00
pic_errorf(pic, "syntax error");
2014-08-25 00:38:09 -04:00
}
var = pic_list_ref(pic, obj, 1);
if (! pic_sym_p(var)) {
2014-09-16 10:43:15 -04:00
pic_errorf(pic, "syntax error");
2014-08-25 00:38:09 -04:00
}
val = pic_list_ref(pic, obj, 2);
var = analyze(state, var, false);
val = analyze(state, val, false);
2015-01-18 21:08:27 -05:00
return pic_list3(pic, pic_obj_value(pic->sSETBANG), var, val);
2014-08-25 00:38:09 -04:00
}
static pic_value
analyze_quote(analyze_state *state, pic_value obj)
{
pic_state *pic = state->pic;
if (pic_length(pic, obj) != 2) {
2014-09-16 10:43:15 -04:00
pic_errorf(pic, "syntax error");
2014-08-25 00:38:09 -04:00
}
2015-01-18 21:08:27 -05:00
return pic_list2(pic, pic_obj_value(pic->sQUOTE), pic_list_ref(pic, obj, 1));
2014-08-25 00:38:09 -04:00
}
2015-01-19 13:03:48 -05:00
#define ARGC_ASSERT_GE(n, name) do { \
if (pic_length(pic, obj) < (n) + 1) { \
pic_errorf(pic, \
#name ": wrong number of arguments (%d for at least %d)", \
2015-01-19 13:03:48 -05:00
pic_length(pic, obj) - 1, \
n); \
} \
2015-01-18 21:02:22 -05:00
} while (0)
#define FOLD_ARGS(sym) do { \
obj = analyze(state, pic_car(pic, args), false); \
2015-01-22 05:28:31 -05:00
pic_for_each (arg, pic_cdr(pic, args), it) { \
2015-01-18 21:08:27 -05:00
obj = pic_list3(pic, pic_obj_value(sym), obj, \
2015-01-18 21:02:22 -05:00
analyze(state, arg, false)); \
} \
} while (0)
2014-08-25 00:38:09 -04:00
static pic_value
analyze_add(analyze_state *state, pic_value obj, bool tailpos)
{
pic_state *pic = state->pic;
2015-01-22 05:28:31 -05:00
pic_value args, arg, it;
2014-08-25 00:38:09 -04:00
2015-01-19 13:03:48 -05:00
ARGC_ASSERT_GE(0, "+");
2014-08-25 00:38:09 -04:00
switch (pic_length(pic, obj)) {
case 1:
2015-01-18 21:08:27 -05:00
return pic_list2(pic, pic_obj_value(pic->sQUOTE), pic_int_value(0));
2014-08-25 00:38:09 -04:00
case 2:
return analyze(state, pic_car(pic, pic_cdr(pic, obj)), tailpos);
default:
args = pic_cdr(pic, obj);
FOLD_ARGS(pic->sADD);
return obj;
}
}
static pic_value
analyze_sub(analyze_state *state, pic_value obj)
{
pic_state *pic = state->pic;
2015-01-22 05:28:31 -05:00
pic_value args, arg, it;
2014-08-25 00:38:09 -04:00
2015-01-19 13:03:48 -05:00
ARGC_ASSERT_GE(1, "-");
2014-08-25 00:38:09 -04:00
switch (pic_length(pic, obj)) {
case 2:
2015-01-18 21:08:27 -05:00
return pic_list2(pic, pic_obj_value(pic->sMINUS),
2014-08-25 00:38:09 -04:00
analyze(state, pic_car(pic, pic_cdr(pic, obj)), false));
default:
args = pic_cdr(pic, obj);
FOLD_ARGS(pic->sSUB);
return obj;
}
}
static pic_value
analyze_mul(analyze_state *state, pic_value obj, bool tailpos)
{
pic_state *pic = state->pic;
2015-01-22 05:28:31 -05:00
pic_value args, arg, it;
2014-08-25 00:38:09 -04:00
2015-01-19 13:03:48 -05:00
ARGC_ASSERT_GE(0, "*");
2014-08-25 00:38:09 -04:00
switch (pic_length(pic, obj)) {
case 1:
2015-01-18 21:08:27 -05:00
return pic_list2(pic, pic_obj_value(pic->sQUOTE), pic_int_value(1));
2014-08-25 00:38:09 -04:00
case 2:
return analyze(state, pic_car(pic, pic_cdr(pic, obj)), tailpos);
default:
args = pic_cdr(pic, obj);
FOLD_ARGS(pic->sMUL);
return obj;
}
}
static pic_value
analyze_div(analyze_state *state, pic_value obj)
{
pic_state *pic = state->pic;
2015-01-22 05:28:31 -05:00
pic_value args, arg, it;
2014-08-25 00:38:09 -04:00
2015-01-19 13:03:48 -05:00
ARGC_ASSERT_GE(1, "/");
2014-08-25 00:38:09 -04:00
switch (pic_length(pic, obj)) {
case 2:
args = pic_cdr(pic, obj);
#if PIC_ENABLE_FLOAT
2014-08-25 00:38:09 -04:00
obj = pic_list3(pic, pic_car(pic, obj), pic_float_value(1), pic_car(pic, args));
#else
obj = pic_list3(pic, pic_car(pic, obj), pic_int_value(1), pic_car(pic, args));
#endif
2014-08-25 00:38:09 -04:00
return analyze(state, obj, false);
default:
args = pic_cdr(pic, obj);
FOLD_ARGS(pic->sDIV);
return obj;
}
}
static pic_value
analyze_call(analyze_state *state, pic_value obj, bool tailpos)
{
pic_state *pic = state->pic;
2015-01-22 05:28:31 -05:00
pic_value seq, elt, it;
2015-01-20 02:02:28 -05:00
pic_sym *call;
2014-08-25 00:38:09 -04:00
if (! tailpos) {
2015-01-19 00:35:42 -05:00
call = pic->sCALL;
2014-08-25 00:38:09 -04:00
} else {
2015-01-19 00:35:42 -05:00
call = pic->sTAILCALL;
2014-08-25 00:38:09 -04:00
}
2015-01-18 21:08:27 -05:00
seq = pic_list1(pic, pic_obj_value(call));
2015-01-22 05:28:31 -05:00
pic_for_each (elt, obj, it) {
2014-08-25 00:38:09 -04:00
seq = pic_cons(pic, analyze(state, elt, false), seq);
}
return pic_reverse(pic, seq);
}
static pic_value
analyze_values(analyze_state *state, pic_value obj, bool tailpos)
{
pic_state *pic = state->pic;
2015-01-22 05:28:31 -05:00
pic_value v, seq, it;
2014-08-25 00:38:09 -04:00
if (! tailpos) {
return analyze_call(state, obj, false);
}
2015-01-19 00:35:42 -05:00
seq = pic_list1(pic, pic_obj_value(pic->sRETURN));
2015-01-22 05:28:31 -05:00
pic_for_each (v, pic_cdr(pic, obj), it) {
2014-08-25 00:38:09 -04:00
seq = pic_cons(pic, analyze(state, v, false), seq);
}
return pic_reverse(pic, seq);
}
static pic_value
analyze_call_with_values(analyze_state *state, pic_value obj, bool tailpos)
{
pic_state *pic = state->pic;
pic_value prod, cnsm;
2015-01-20 02:02:28 -05:00
pic_sym *call;
2014-08-25 00:38:09 -04:00
if (pic_length(pic, obj) != 3) {
pic_errorf(pic, "call-with-values: wrong number of arguments (%d for 2)", pic_length(pic, obj) - 1);
2014-08-25 00:38:09 -04:00
}
if (! tailpos) {
2015-01-19 00:35:42 -05:00
call = pic->sCALL_WITH_VALUES;
2014-08-25 00:38:09 -04:00
} else {
2015-01-19 00:35:42 -05:00
call = pic->sTAILCALL_WITH_VALUES;
2014-08-25 00:38:09 -04:00
}
prod = analyze(state, pic_list_ref(pic, obj, 1), false);
cnsm = analyze(state, pic_list_ref(pic, obj, 2), false);
2015-01-18 21:08:27 -05:00
return pic_list3(pic, pic_obj_value(call), prod, cnsm);
2014-08-25 00:38:09 -04:00
}
#define ARGC_ASSERT(n, name) do { \
if (pic_length(pic, obj) != (n) + 1) { \
pic_errorf(pic, #name ": wrong number of arguments (%d for %d)", \
pic_length(pic, obj) - 1, n); \
} \
2015-01-18 21:02:22 -05:00
} while (0)
#define ARGC_ASSERT_WITH_FALLBACK(n) do { \
if (pic_length(pic, obj) != (n) + 1) { \
goto fallback; \
} \
} while (0)
#define CONSTRUCT_OP1(op) \
pic_list2(pic, \
2015-01-18 21:08:27 -05:00
pic_obj_value(op), \
2015-01-18 21:02:22 -05:00
analyze(state, pic_list_ref(pic, obj, 1), false))
#define CONSTRUCT_OP2(op) \
pic_list3(pic, \
2015-01-18 21:08:27 -05:00
pic_obj_value(op), \
2015-01-18 21:02:22 -05:00
analyze(state, pic_list_ref(pic, obj, 1), false), \
analyze(state, pic_list_ref(pic, obj, 2), false))
2014-08-25 00:38:09 -04:00
static pic_value
analyze_node(analyze_state *state, pic_value obj, bool tailpos)
{
pic_state *pic = state->pic;
switch (pic_type(obj)) {
case PIC_TT_SYMBOL: {
2015-01-20 01:31:17 -05:00
return analyze_var(state, pic_sym_ptr(obj));
2014-08-25 00:38:09 -04:00
}
case PIC_TT_PAIR: {
pic_value proc;
if (! pic_list_p(obj)) {
pic_errorf(pic, "invalid expression given: ~s", obj);
}
proc = pic_list_ref(pic, obj, 0);
if (pic_sym_p(proc)) {
2015-01-20 02:02:28 -05:00
pic_sym *sym = pic_sym_ptr(proc);
2014-08-25 00:38:09 -04:00
if (sym == pic->rDEFINE) {
return analyze_define(state, obj);
}
else if (sym == pic->rLAMBDA) {
return analyze_lambda(state, obj);
}
else if (sym == pic->rIF) {
return analyze_if(state, obj, tailpos);
}
else if (sym == pic->rBEGIN) {
return analyze_begin(state, obj, tailpos);
}
else if (sym == pic->rSETBANG) {
return analyze_set(state, obj);
}
else if (sym == pic->rQUOTE) {
return analyze_quote(state, obj);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rCONS) {
ARGC_ASSERT(2, "cons");
2014-08-25 00:38:09 -04:00
return CONSTRUCT_OP2(pic->sCONS);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rCAR) {
ARGC_ASSERT(1, "car");
2014-08-25 00:38:09 -04:00
return CONSTRUCT_OP1(pic->sCAR);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rCDR) {
ARGC_ASSERT(1, "cdr");
2014-08-25 00:38:09 -04:00
return CONSTRUCT_OP1(pic->sCDR);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rNILP) {
ARGC_ASSERT(1, "nil?");
2014-08-25 00:38:09 -04:00
return CONSTRUCT_OP1(pic->sNILP);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rSYMBOLP) {
ARGC_ASSERT(1, "symbol?");
2015-01-18 23:16:07 -05:00
return CONSTRUCT_OP1(pic->sSYMBOLP);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rPAIRP) {
ARGC_ASSERT(1, "pair?");
2015-01-18 23:16:07 -05:00
return CONSTRUCT_OP1(pic->sPAIRP);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rADD) {
2014-08-25 00:38:09 -04:00
return analyze_add(state, obj, tailpos);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rSUB) {
2014-08-25 00:38:09 -04:00
return analyze_sub(state, obj);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rMUL) {
2014-08-25 00:38:09 -04:00
return analyze_mul(state, obj, tailpos);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rDIV) {
2014-08-25 00:38:09 -04:00
return analyze_div(state, obj);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rEQ) {
2014-08-25 00:38:09 -04:00
ARGC_ASSERT_WITH_FALLBACK(2);
return CONSTRUCT_OP2(pic->sEQ);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rLT) {
2014-08-25 00:38:09 -04:00
ARGC_ASSERT_WITH_FALLBACK(2);
return CONSTRUCT_OP2(pic->sLT);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rLE) {
2014-08-25 00:38:09 -04:00
ARGC_ASSERT_WITH_FALLBACK(2);
return CONSTRUCT_OP2(pic->sLE);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rGT) {
2014-08-25 00:38:09 -04:00
ARGC_ASSERT_WITH_FALLBACK(2);
return CONSTRUCT_OP2(pic->sGT);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rGE) {
2014-08-25 00:38:09 -04:00
ARGC_ASSERT_WITH_FALLBACK(2);
return CONSTRUCT_OP2(pic->sGE);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rNOT) {
ARGC_ASSERT(1, "not");
2014-08-25 00:38:09 -04:00
return CONSTRUCT_OP1(pic->sNOT);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rVALUES) {
2014-08-25 00:38:09 -04:00
return analyze_values(state, obj, tailpos);
}
2015-06-04 00:53:41 -04:00
else if (sym == pic->rCALL_WITH_VALUES) {
2014-08-25 00:38:09 -04:00
return analyze_call_with_values(state, obj, tailpos);
}
}
2015-01-18 21:02:22 -05:00
fallback:
2014-08-25 00:38:09 -04:00
return analyze_call(state, obj, tailpos);
}
default:
2015-01-18 21:08:27 -05:00
return pic_list2(pic, pic_obj_value(pic->sQUOTE), obj);
2014-08-25 00:38:09 -04:00
}
}
pic_value
pic_analyze(pic_state *pic, pic_value obj)
{
analyze_state *state;
state = new_analyze_state(pic);
obj = analyze(state, obj, true);
analyze_deferred(state);
2014-08-25 00:38:09 -04:00
destroy_analyze_state(state);
return obj;
}
/**
* scope object
*/
typedef struct codegen_context {
2015-01-20 02:02:28 -05:00
pic_sym *name;
2014-08-25 00:38:09 -04:00
/* rest args variable is counted as a local */
bool varg;
xvect args, locals, captures;
/* actual bit code sequence */
pic_code *code;
size_t clen, ccapa;
/* child ireps */
struct pic_irep **irep;
size_t ilen, icapa;
/* constant object pool */
pic_value *pool;
size_t plen, pcapa;
2015-01-18 11:29:00 -05:00
/* symbol pool */
2015-01-20 02:02:28 -05:00
pic_sym **syms;
2015-01-18 11:29:00 -05:00
size_t slen, scapa;
2014-08-25 00:38:09 -04:00
struct codegen_context *up;
} codegen_context;
/**
* global codegen state
*/
typedef struct codegen_state {
pic_state *pic;
codegen_context *cxt;
} codegen_state;
static void push_codegen_context(codegen_state *, pic_value, pic_value, pic_value, bool, pic_value);
static struct pic_irep *pop_codegen_context(codegen_state *);
static codegen_state *
new_codegen_state(pic_state *pic)
{
codegen_state *state;
2015-05-28 03:42:16 -04:00
state = pic_malloc(pic, sizeof(codegen_state));
2014-08-25 00:38:09 -04:00
state->pic = pic;
state->cxt = NULL;
push_codegen_context(state, pic_false_value(), pic_nil_value(), pic_nil_value(), false, pic_nil_value());
return state;
}
static struct pic_irep *
destroy_codegen_state(codegen_state *state)
{
pic_state *pic = state->pic;
struct pic_irep *irep;
irep = pop_codegen_context(state);
pic_free(pic, state);
return irep;
}
static void
emit_n(codegen_state *state, enum pic_opcode insn)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
if (cxt->clen >= cxt->ccapa) {
cxt->ccapa *= 2;
cxt->code = pic_realloc(pic, cxt->code, sizeof(pic_code) * cxt->ccapa);
}
cxt->code[cxt->clen].insn = insn;
cxt->clen++;
}
static void
emit_i(codegen_state *state, enum pic_opcode insn, int i)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
if (cxt->clen >= cxt->ccapa) {
cxt->ccapa *= 2;
cxt->code = pic_realloc(pic, cxt->code, sizeof(pic_code) * cxt->ccapa);
}
cxt->code[cxt->clen].insn = insn;
cxt->code[cxt->clen].u.i = i;
cxt->clen++;
}
static void
emit_c(codegen_state *state, enum pic_opcode insn, char c)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
if (cxt->clen >= cxt->ccapa) {
cxt->ccapa *= 2;
cxt->code = pic_realloc(pic, cxt->code, sizeof(pic_code) * cxt->ccapa);
}
cxt->code[cxt->clen].insn = insn;
cxt->code[cxt->clen].u.c = c;
cxt->clen++;
}
static void
emit_r(codegen_state *state, enum pic_opcode insn, int d, int i)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
if (cxt->clen >= cxt->ccapa) {
cxt->ccapa *= 2;
cxt->code = pic_realloc(pic, cxt->code, sizeof(pic_code) * cxt->ccapa);
}
cxt->code[cxt->clen].insn = insn;
cxt->code[cxt->clen].u.r.depth = d;
cxt->code[cxt->clen].u.r.idx = i;
cxt->clen++;
}
static void
create_activation(codegen_state *state)
2014-08-25 00:38:09 -04:00
{
2015-05-27 13:12:26 -04:00
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
2014-08-25 00:38:09 -04:00
size_t i, n;
xhash regs;
size_t offset;
xh_init_ptr(&regs, sizeof(size_t));
2014-08-25 00:38:09 -04:00
offset = 1;
2015-01-22 08:15:12 -05:00
for (i = 0; i < xv_size(cxt->args); ++i) {
2014-08-25 00:38:09 -04:00
n = i + offset;
2015-01-22 08:15:12 -05:00
xh_put_ptr(&regs, xv_A(cxt->args, i), &n);
2014-08-25 00:38:09 -04:00
}
offset += i;
2015-01-22 08:15:12 -05:00
for (i = 0; i < xv_size(cxt->locals); ++i) {
2014-08-25 00:38:09 -04:00
n = i + offset;
2015-01-22 08:15:12 -05:00
xh_put_ptr(&regs, xv_A(cxt->locals, i), &n);
2014-08-25 00:38:09 -04:00
}
2015-01-22 08:15:12 -05:00
for (i = 0; i < xv_size(cxt->captures); ++i) {
n = xh_val(xh_get_ptr(&regs, xv_A(cxt->captures, i)), size_t);
if (n <= xv_size(cxt->args) || (cxt->varg && n == xv_size(cxt->args) + 1)) {
2014-08-25 00:38:09 -04:00
/* copy arguments to capture variable area */
emit_i(state, OP_LREF, (int)n);
2014-08-25 00:38:09 -04:00
} else {
/* otherwise, just extend the stack */
2015-06-09 03:34:45 -04:00
emit_n(state, OP_PUSHUNDEF);
2014-08-25 00:38:09 -04:00
}
}
xh_destroy(&regs);
}
static void
push_codegen_context(codegen_state *state, pic_value name, pic_value args, pic_value locals, bool varg, pic_value captures)
{
pic_state *pic = state->pic;
codegen_context *cxt;
2015-01-22 05:28:31 -05:00
pic_value var, it;
2014-08-25 00:38:09 -04:00
assert(pic_sym_p(name) || pic_false_p(name));
2015-05-28 03:42:16 -04:00
cxt = pic_malloc(pic, sizeof(codegen_context));
2014-08-25 00:38:09 -04:00
cxt->up = state->cxt;
cxt->name = pic_false_p(name)
? pic_intern_cstr(pic, "(anonymous lambda)")
2015-01-20 01:31:17 -05:00
: pic_sym_ptr(name);
2014-08-25 00:38:09 -04:00
cxt->varg = varg;
2015-01-22 08:15:12 -05:00
xv_init(cxt->args);
xv_init(cxt->locals);
xv_init(cxt->captures);
2014-08-25 00:38:09 -04:00
2015-01-22 05:28:31 -05:00
pic_for_each (var, args, it) {
2015-01-22 08:15:12 -05:00
xv_push_sym(cxt->args, pic_sym_ptr(var));
2014-08-25 00:38:09 -04:00
}
2015-01-22 05:28:31 -05:00
pic_for_each (var, locals, it) {
2015-01-22 08:15:12 -05:00
xv_push_sym(cxt->locals, pic_sym_ptr(var));
2014-08-25 00:38:09 -04:00
}
2015-01-22 05:28:31 -05:00
pic_for_each (var, captures, it) {
2015-01-22 08:15:12 -05:00
xv_push_sym(cxt->captures, pic_sym_ptr(var));
2014-08-25 00:38:09 -04:00
}
cxt->code = pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(pic_code));
cxt->clen = 0;
cxt->ccapa = PIC_ISEQ_SIZE;
cxt->irep = pic_calloc(pic, PIC_IREP_SIZE, sizeof(struct pic_irep *));
cxt->ilen = 0;
cxt->icapa = PIC_IREP_SIZE;
cxt->pool = pic_calloc(pic, PIC_POOL_SIZE, sizeof(pic_value));
cxt->plen = 0;
cxt->pcapa = PIC_POOL_SIZE;
2015-01-21 07:59:50 -05:00
cxt->syms = pic_calloc(pic, PIC_SYMS_SIZE, sizeof(pic_sym *));
2015-01-18 11:29:00 -05:00
cxt->slen = 0;
2015-01-21 07:59:50 -05:00
cxt->scapa = PIC_SYMS_SIZE;
2015-01-18 11:29:00 -05:00
2014-08-25 00:38:09 -04:00
state->cxt = cxt;
create_activation(state);
2014-08-25 00:38:09 -04:00
}
static struct pic_irep *
pop_codegen_context(codegen_state *state)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
struct pic_irep *irep;
/* create irep */
irep = (struct pic_irep *)pic_obj_alloc(pic, sizeof(struct pic_irep), PIC_TT_IREP);
irep->name = state->cxt->name;
irep->varg = state->cxt->varg;
2015-01-22 08:15:12 -05:00
irep->argc = (int)xv_size(state->cxt->args) + 1;
irep->localc = (int)xv_size(state->cxt->locals);
irep->capturec = (int)xv_size(state->cxt->captures);
2014-08-25 00:38:09 -04:00
irep->code = pic_realloc(pic, state->cxt->code, sizeof(pic_code) * state->cxt->clen);
irep->clen = state->cxt->clen;
irep->irep = pic_realloc(pic, state->cxt->irep, sizeof(struct pic_irep *) * state->cxt->ilen);
irep->ilen = state->cxt->ilen;
irep->pool = pic_realloc(pic, state->cxt->pool, sizeof(pic_value) * state->cxt->plen);
irep->plen = state->cxt->plen;
2015-01-20 02:02:28 -05:00
irep->syms = pic_realloc(pic, state->cxt->syms, sizeof(pic_sym *) * state->cxt->slen);
2015-01-18 11:29:00 -05:00
irep->slen = state->cxt->slen;
2014-08-25 00:38:09 -04:00
/* finalize */
2015-01-22 08:15:12 -05:00
xv_destroy(cxt->args);
xv_destroy(cxt->locals);
xv_destroy(cxt->captures);
2014-08-25 00:38:09 -04:00
/* destroy context */
cxt = cxt->up;
pic_free(pic, state->cxt);
state->cxt = cxt;
return irep;
}
static int
2015-01-20 02:02:28 -05:00
index_capture(codegen_state *state, pic_sym *sym, int depth)
2014-08-25 00:38:09 -04:00
{
codegen_context *cxt = state->cxt;
size_t i;
while (depth-- > 0) {
cxt = cxt->up;
}
2015-01-22 08:15:12 -05:00
for (i = 0; i < xv_size(cxt->captures); ++i) {
if (xv_A(cxt->captures, i) == sym)
2014-09-26 04:36:00 -04:00
return (int)i;
2014-08-25 00:38:09 -04:00
}
return -1;
}
static int
2015-01-20 02:02:28 -05:00
index_local(codegen_state *state, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
codegen_context *cxt = state->cxt;
2014-09-27 04:18:11 -04:00
size_t i, offset;
2014-08-25 00:38:09 -04:00
offset = 1;
2015-01-22 08:15:12 -05:00
for (i = 0; i < xv_size(cxt->args); ++i) {
if (xv_A(cxt->args, i) == sym)
2014-09-27 04:18:11 -04:00
return (int)(i + offset);
2014-08-25 00:38:09 -04:00
}
offset += i;
2015-01-22 08:15:12 -05:00
for (i = 0; i < xv_size(cxt->locals); ++i) {
if (xv_A(cxt->locals, i) == sym)
2014-09-27 04:18:11 -04:00
return (int)(i + offset);
2014-08-25 00:38:09 -04:00
}
return -1;
}
2015-01-18 11:29:00 -05:00
static int
2015-01-20 02:02:28 -05:00
index_symbol(codegen_state *state, pic_sym *sym)
2015-01-18 11:29:00 -05:00
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
size_t i;
for (i = 0; i < cxt->slen; ++i) {
if (cxt->syms[i] == sym) {
return i;
}
}
if (cxt->slen >= cxt->scapa) {
cxt->scapa *= 2;
2015-01-20 02:02:28 -05:00
cxt->syms = pic_realloc(pic, cxt->syms, sizeof(pic_sym *) * cxt->scapa);
2015-01-18 11:29:00 -05:00
}
cxt->syms[cxt->slen++] = sym;
return i;
}
2014-08-25 00:38:09 -04:00
static struct pic_irep *codegen_lambda(codegen_state *, pic_value);
static void
codegen(codegen_state *state, pic_value obj)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
2015-01-20 02:02:28 -05:00
pic_sym *sym;
2014-08-25 00:38:09 -04:00
2015-01-20 01:31:17 -05:00
sym = pic_sym_ptr(pic_car(pic, obj));
2015-01-19 00:35:42 -05:00
if (sym == pic->sGREF) {
emit_i(state, OP_GREF, index_symbol(state, pic_sym_ptr(pic_list_ref(pic, obj, 1))));
2014-08-25 00:38:09 -04:00
return;
2015-01-19 00:35:42 -05:00
} else if (sym == pic->sCREF) {
2015-01-20 02:02:28 -05:00
pic_sym *name;
2014-08-25 00:38:09 -04:00
int depth;
depth = pic_int(pic_list_ref(pic, obj, 1));
2015-01-20 01:31:17 -05:00
name = pic_sym_ptr(pic_list_ref(pic, obj, 2));
emit_r(state, OP_CREF, depth, index_capture(state, name, depth));
2014-08-25 00:38:09 -04:00
return;
2015-01-19 00:35:42 -05:00
} else if (sym == pic->sLREF) {
2015-01-20 02:02:28 -05:00
pic_sym *name;
2014-08-25 00:38:09 -04:00
int i;
2015-01-20 01:31:17 -05:00
name = pic_sym_ptr(pic_list_ref(pic, obj, 1));
2014-08-25 00:38:09 -04:00
if ((i = index_capture(state, name, 0)) != -1) {
emit_i(state, OP_LREF, i + (int)xv_size(cxt->args) + (int)xv_size(cxt->locals) + 1);
2014-08-25 00:38:09 -04:00
return;
}
emit_i(state, OP_LREF, index_local(state, name));
2014-08-25 00:38:09 -04:00
return;
} else if (sym == pic->sSETBANG) {
pic_value var, val;
2015-01-20 02:02:28 -05:00
pic_sym *type;
2014-08-25 00:38:09 -04:00
val = pic_list_ref(pic, obj, 2);
codegen(state, val);
var = pic_list_ref(pic, obj, 1);
2015-01-20 01:31:17 -05:00
type = pic_sym_ptr(pic_list_ref(pic, var, 0));
2015-01-19 00:35:42 -05:00
if (type == pic->sGREF) {
emit_i(state, OP_GSET, index_symbol(state, pic_sym_ptr(pic_list_ref(pic, var, 1))));
2015-06-09 03:34:45 -04:00
emit_n(state, OP_PUSHUNDEF);
2014-08-25 00:38:09 -04:00
return;
}
2015-01-19 00:35:42 -05:00
else if (type == pic->sCREF) {
2015-01-20 02:02:28 -05:00
pic_sym *name;
2014-08-25 00:38:09 -04:00
int depth;
depth = pic_int(pic_list_ref(pic, var, 1));
2015-01-20 01:31:17 -05:00
name = pic_sym_ptr(pic_list_ref(pic, var, 2));
emit_r(state, OP_CSET, depth, index_capture(state, name, depth));
2015-06-09 03:34:45 -04:00
emit_n(state, OP_PUSHUNDEF);
2014-08-25 00:38:09 -04:00
return;
}
2015-01-19 00:35:42 -05:00
else if (type == pic->sLREF) {
2015-01-20 02:02:28 -05:00
pic_sym *name;
2014-08-25 00:38:09 -04:00
int i;
2015-01-20 01:31:17 -05:00
name = pic_sym_ptr(pic_list_ref(pic, var, 1));
2014-08-25 00:38:09 -04:00
if ((i = index_capture(state, name, 0)) != -1) {
emit_i(state, OP_LSET, i + (int)xv_size(cxt->args) + (int)xv_size(cxt->locals) + 1);
2015-06-09 03:34:45 -04:00
emit_n(state, OP_PUSHUNDEF);
2014-08-25 00:38:09 -04:00
return;
}
emit_i(state, OP_LSET, index_local(state, name));
2015-06-09 03:34:45 -04:00
emit_n(state, OP_PUSHUNDEF);
2014-08-25 00:38:09 -04:00
return;
}
}
else if (sym == pic->sLAMBDA) {
int k;
if (cxt->ilen >= cxt->icapa) {
cxt->icapa *= 2;
cxt->irep = pic_realloc(pic, cxt->irep, sizeof(struct pic_irep *) * cxt->icapa);
}
2014-09-27 04:18:11 -04:00
k = (int)cxt->ilen++;
emit_i(state, OP_LAMBDA, k);
2014-08-25 00:38:09 -04:00
cxt->irep[k] = codegen_lambda(state, obj);
return;
}
else if (sym == pic->sIF) {
int s, t;
codegen(state, pic_list_ref(pic, obj, 1));
s = (int)cxt->clen;
emit_n(state, OP_JMPIF);
2014-08-25 00:38:09 -04:00
/* if false branch */
codegen(state, pic_list_ref(pic, obj, 3));
t = (int)cxt->clen;
emit_n(state, OP_JMP);
2014-08-25 00:38:09 -04:00
2014-09-27 04:18:11 -04:00
cxt->code[s].u.i = (int)cxt->clen - s;
2014-08-25 00:38:09 -04:00
/* if true branch */
codegen(state, pic_list_ref(pic, obj, 2));
2014-09-27 04:18:11 -04:00
cxt->code[t].u.i = (int)cxt->clen - t;
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sBEGIN) {
2015-01-22 05:28:31 -05:00
pic_value elt, it;
2014-08-25 00:38:09 -04:00
int i = 0;
2015-01-22 05:28:31 -05:00
pic_for_each (elt, pic_cdr(pic, obj), it) {
2014-08-25 00:38:09 -04:00
if (i++ != 0) {
emit_n(state, OP_POP);
2014-08-25 00:38:09 -04:00
}
codegen(state, elt);
}
return;
}
else if (sym == pic->sQUOTE) {
int pidx;
obj = pic_list_ref(pic, obj, 1);
switch (pic_type(obj)) {
case PIC_TT_BOOL:
emit_n(state, (pic_true_p(obj) ? OP_PUSHTRUE : OP_PUSHFALSE));
2014-08-25 00:38:09 -04:00
return;
case PIC_TT_INT:
emit_i(state, OP_PUSHINT, pic_int(obj));
2014-08-25 00:38:09 -04:00
return;
case PIC_TT_NIL:
emit_n(state, OP_PUSHNIL);
2014-08-25 00:38:09 -04:00
return;
case PIC_TT_CHAR:
emit_c(state, OP_PUSHCHAR, pic_char(obj));
2014-08-25 00:38:09 -04:00
return;
default:
if (cxt->plen >= cxt->pcapa) {
cxt->pcapa *= 2;
cxt->pool = pic_realloc(pic, cxt->pool, sizeof(pic_value) * cxt->pcapa);
}
2014-09-27 04:18:11 -04:00
pidx = (int)cxt->plen++;
2014-08-25 00:38:09 -04:00
cxt->pool[pidx] = obj;
emit_i(state, OP_PUSHCONST, pidx);
2014-08-25 00:38:09 -04:00
return;
}
}
else if (sym == pic->sCONS) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
emit_n(state, OP_CONS);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sCAR) {
codegen(state, pic_list_ref(pic, obj, 1));
emit_n(state, OP_CAR);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sCDR) {
codegen(state, pic_list_ref(pic, obj, 1));
emit_n(state, OP_CDR);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sNILP) {
codegen(state, pic_list_ref(pic, obj, 1));
emit_n(state, OP_NILP);
2014-08-25 00:38:09 -04:00
return;
}
2015-01-18 23:16:07 -05:00
else if (sym == pic->sSYMBOLP) {
codegen(state, pic_list_ref(pic, obj, 1));
emit_n(state, OP_SYMBOLP);
return;
}
2015-01-18 23:16:07 -05:00
else if (sym == pic->sPAIRP) {
codegen(state, pic_list_ref(pic, obj, 1));
emit_n(state, OP_PAIRP);
return;
}
2014-08-25 00:38:09 -04:00
else if (sym == pic->sADD) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
emit_n(state, OP_ADD);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sSUB) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
emit_n(state, OP_SUB);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sMUL) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
emit_n(state, OP_MUL);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sDIV) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
emit_n(state, OP_DIV);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sMINUS) {
codegen(state, pic_list_ref(pic, obj, 1));
emit_n(state, OP_MINUS);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sEQ) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
emit_n(state, OP_EQ);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sLT) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
emit_n(state, OP_LT);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sLE) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
emit_n(state, OP_LE);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sGT) {
codegen(state, pic_list_ref(pic, obj, 2));
codegen(state, pic_list_ref(pic, obj, 1));
emit_n(state, OP_LT);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sGE) {
codegen(state, pic_list_ref(pic, obj, 2));
codegen(state, pic_list_ref(pic, obj, 1));
emit_n(state, OP_LE);
2014-08-25 00:38:09 -04:00
return;
}
else if (sym == pic->sNOT) {
codegen(state, pic_list_ref(pic, obj, 1));
emit_n(state, OP_NOT);
2014-08-25 00:38:09 -04:00
return;
}
2015-01-19 00:35:42 -05:00
else if (sym == pic->sCALL || sym == pic->sTAILCALL) {
2014-09-27 06:58:04 -04:00
int len = (int)pic_length(pic, obj);
2015-01-22 05:28:31 -05:00
pic_value elt, it;
2014-08-25 00:38:09 -04:00
2015-01-22 05:28:31 -05:00
pic_for_each (elt, pic_cdr(pic, obj), it) {
2014-08-25 00:38:09 -04:00
codegen(state, elt);
}
emit_i(state, (sym == pic->sCALL ? OP_CALL : OP_TAILCALL), len - 1);
2014-08-25 00:38:09 -04:00
return;
}
2015-01-19 00:35:42 -05:00
else if (sym == pic->sCALL_WITH_VALUES || sym == pic->sTAILCALL_WITH_VALUES) {
2014-08-25 00:38:09 -04:00
/* stack consumer at first */
codegen(state, pic_list_ref(pic, obj, 2));
codegen(state, pic_list_ref(pic, obj, 1));
/* call producer */
emit_i(state, OP_CALL, 1);
2014-08-25 00:38:09 -04:00
/* call consumer */
emit_i(state, (sym == pic->sCALL_WITH_VALUES ? OP_CALL : OP_TAILCALL), -1);
2014-08-25 00:38:09 -04:00
return;
}
2015-01-19 00:35:42 -05:00
else if (sym == pic->sRETURN) {
2014-09-27 06:58:04 -04:00
int len = (int)pic_length(pic, obj);
2015-01-22 05:28:31 -05:00
pic_value elt, it;
2014-08-25 00:38:09 -04:00
2015-01-22 05:28:31 -05:00
pic_for_each (elt, pic_cdr(pic, obj), it) {
2014-08-25 00:38:09 -04:00
codegen(state, elt);
}
emit_i(state, OP_RET, len - 1);
2014-08-25 00:38:09 -04:00
return;
}
2015-01-18 23:12:45 -05:00
pic_errorf(pic, "codegen: unknown AST type ~s", obj);
2014-08-25 00:38:09 -04:00
}
static struct pic_irep *
codegen_lambda(codegen_state *state, pic_value obj)
{
pic_state *pic = state->pic;
pic_value name, args, locals, closes, body;
bool varg;
name = pic_list_ref(pic, obj, 1);
args = pic_list_ref(pic, obj, 2);
locals = pic_list_ref(pic, obj, 3);
varg = pic_true_p(pic_list_ref(pic, obj, 4));
closes = pic_list_ref(pic, obj, 5);
body = pic_list_ref(pic, obj, 6);
/* inner environment */
push_codegen_context(state, name, args, locals, varg, closes);
{
/* body */
codegen(state, body);
}
return pop_codegen_context(state);
}
struct pic_irep *
pic_codegen(pic_state *pic, pic_value obj)
{
codegen_state *state;
state = new_codegen_state(pic);
codegen(state, obj);
return destroy_codegen_state(state);
}
struct pic_proc *
pic_compile(pic_state *pic, pic_value obj, struct pic_lib *lib)
{
struct pic_irep *irep;
size_t ai = pic_gc_arena_preserve(pic);
#if DEBUG
fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic));
fprintf(stdout, "# input expression\n");
pic_debug(pic, obj);
fprintf(stdout, "\n");
fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic));
#endif
/* macroexpand */
obj = pic_macroexpand(pic, obj, lib);
#if DEBUG
fprintf(stdout, "## macroexpand completed\n");
pic_debug(pic, obj);
fprintf(stdout, "\n");
fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic));
#endif
/* analyze */
obj = pic_analyze(pic, obj);
#if DEBUG
fprintf(stdout, "## analyzer completed\n");
pic_debug(pic, obj);
fprintf(stdout, "\n");
fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic));
#endif
/* codegen */
irep = pic_codegen(pic, obj);
#if DEBUG
fprintf(stdout, "## codegen completed\n");
pic_dump_irep(irep);
#endif
#if DEBUG
fprintf(stdout, "# compilation finished\n");
puts("");
#endif
pic_gc_arena_restore(pic, ai);
pic_gc_protect(pic, pic_obj_value(irep));
2014-09-12 06:46:54 -04:00
return pic_make_proc_irep(pic, irep, NULL);
2014-08-25 00:38:09 -04:00
}