2014-01-17 06:58:31 -05:00
|
|
|
/**
|
|
|
|
* See Copyright Notice in picrin.h
|
|
|
|
*/
|
|
|
|
|
2013-10-20 04:06:47 -04:00
|
|
|
#include <stdio.h>
|
2014-01-12 10:50:45 -05:00
|
|
|
#include <assert.h>
|
2013-10-20 04:06:47 -04:00
|
|
|
|
|
|
|
#include "picrin.h"
|
|
|
|
#include "picrin/pair.h"
|
|
|
|
#include "picrin/irep.h"
|
|
|
|
#include "picrin/proc.h"
|
2013-12-07 23:47:09 -05:00
|
|
|
#include "picrin/lib.h"
|
|
|
|
#include "picrin/macro.h"
|
2013-10-22 09:22:35 -04:00
|
|
|
#include "xhash/xhash.h"
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2014-01-08 01:22:23 -05:00
|
|
|
#if PIC_NONE_IS_FALSE
|
|
|
|
# define OP_PUSHNONE OP_PUSHFALSE
|
|
|
|
#else
|
|
|
|
# error enable PIC_NONE_IS_FALSE
|
|
|
|
#endif
|
|
|
|
|
2013-10-23 13:51:02 -04:00
|
|
|
#define FALLTHROUGH ((void)0)
|
|
|
|
|
2014-01-18 03:19:46 -05:00
|
|
|
static struct pic_irep *
|
|
|
|
new_irep(pic_state *pic)
|
|
|
|
{
|
|
|
|
struct pic_irep *irep;
|
|
|
|
|
|
|
|
irep = (struct pic_irep *)pic_obj_alloc(pic, sizeof(struct pic_irep), PIC_TT_IREP);
|
2014-01-18 06:49:01 -05:00
|
|
|
irep->code = NULL;
|
2014-01-18 03:19:46 -05:00
|
|
|
irep->clen = 0;
|
|
|
|
irep->argc = -1;
|
|
|
|
irep->localc = -1;
|
|
|
|
irep->varg = false;
|
2014-01-18 07:48:50 -05:00
|
|
|
irep->irep = NULL;
|
2014-01-18 08:32:41 -05:00
|
|
|
irep->pool = NULL;
|
2014-01-18 03:19:46 -05:00
|
|
|
return irep;
|
|
|
|
}
|
|
|
|
|
2014-01-18 23:20:28 -05:00
|
|
|
static bool
|
|
|
|
valid_formal(pic_state *pic, pic_value formal)
|
|
|
|
{
|
|
|
|
if (pic_symbol_p(formal))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
while (pic_pair_p(formal)) {
|
|
|
|
if (! pic_symbol_p(pic_car(pic, formal))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
formal = pic_cdr(pic, formal);
|
|
|
|
}
|
|
|
|
if (pic_nil_p(formal))
|
|
|
|
return true;
|
|
|
|
if (pic_symbol_p(formal))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct analyze_scope {
|
|
|
|
bool varg;
|
|
|
|
/* rest args variable is counted by localc */
|
|
|
|
size_t argc, localc;
|
|
|
|
/* local variables are 1-indexed, 0 is reserved for the callee */
|
|
|
|
struct xhash *local_tbl;
|
|
|
|
/* if local var i is captured, then dirty_flags[i] == 1 */
|
|
|
|
int *dirty_flags;
|
|
|
|
|
|
|
|
struct analyze_scope *up;
|
|
|
|
} analyze_scope;
|
|
|
|
|
|
|
|
static analyze_scope *
|
|
|
|
global_scope(pic_state *pic)
|
|
|
|
{
|
|
|
|
analyze_scope *scope;
|
|
|
|
|
|
|
|
scope = (analyze_scope *)pic_alloc(pic, sizeof(analyze_scope));
|
|
|
|
scope->up = NULL;
|
|
|
|
scope->local_tbl = pic->global_tbl;
|
|
|
|
scope->argc = -1;
|
|
|
|
scope->localc = -1;
|
|
|
|
scope->varg = false;
|
|
|
|
scope->dirty_flags = NULL;
|
|
|
|
|
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct analyze_state {
|
|
|
|
pic_state *pic;
|
|
|
|
analyze_scope *scope;
|
|
|
|
pic_sym rCONS, rCAR, rCDR, rNILP;
|
|
|
|
pic_sym rADD, rSUB, rMUL, rDIV;
|
|
|
|
pic_sym rEQ, rLT, rLE, rGT, rGE;
|
|
|
|
pic_sym sCALL, sTAILCALL;
|
|
|
|
pic_sym sGREF, sLREF, sCREF;
|
|
|
|
pic_sym sGSET, sLSET, sCSET;
|
|
|
|
} analyze_state;
|
|
|
|
|
|
|
|
#define register_symbol(pic, state, slot, name) do { \
|
|
|
|
state->slot = pic_intern_cstr(pic, name); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define register_renamed_symbol(pic, state, slot, lib, name) do { \
|
|
|
|
struct xh_entry *e; \
|
|
|
|
if (! (e = xh_get(lib->senv->tbl, name))) \
|
|
|
|
pic_error(pic, "internal error! native VM procedure not found"); \
|
|
|
|
state->slot = e->val; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static analyze_state *
|
|
|
|
new_analyze_state(pic_state *pic)
|
|
|
|
{
|
|
|
|
analyze_state *state;
|
|
|
|
struct pic_lib *stdlib;
|
|
|
|
|
|
|
|
state = (analyze_state *)pic_alloc(pic, sizeof(analyze_state));
|
|
|
|
state->pic = pic;
|
|
|
|
state->scope = global_scope(pic);
|
|
|
|
|
|
|
|
stdlib = pic_find_library(pic, pic_parse(pic, "(scheme base)"));
|
|
|
|
|
|
|
|
/* native VM procedures */
|
|
|
|
register_renamed_symbol(pic, state, rCONS, stdlib, "cons");
|
|
|
|
register_renamed_symbol(pic, state, rCAR, stdlib, "car");
|
|
|
|
register_renamed_symbol(pic, state, rCDR, stdlib, "cdr");
|
|
|
|
register_renamed_symbol(pic, state, rNILP, stdlib, "null?");
|
|
|
|
register_renamed_symbol(pic, state, rADD, stdlib, "+");
|
|
|
|
register_renamed_symbol(pic, state, rSUB, stdlib, "-");
|
|
|
|
register_renamed_symbol(pic, state, rMUL, stdlib, "*");
|
|
|
|
register_renamed_symbol(pic, state, rDIV, stdlib, "/");
|
|
|
|
register_renamed_symbol(pic, state, rEQ, stdlib, "=");
|
|
|
|
register_renamed_symbol(pic, state, rLT, stdlib, "<");
|
|
|
|
register_renamed_symbol(pic, state, rLE, stdlib, "<=");
|
|
|
|
register_renamed_symbol(pic, state, rGT, stdlib, ">");
|
|
|
|
register_renamed_symbol(pic, state, rGE, stdlib, ">=");
|
|
|
|
|
|
|
|
register_symbol(pic, state, sCALL, "call");
|
|
|
|
register_symbol(pic, state, sTAILCALL, "tail-call");
|
|
|
|
register_symbol(pic, state, sGREF, "gref");
|
|
|
|
register_symbol(pic, state, sLREF, "lref");
|
|
|
|
register_symbol(pic, state, sCREF, "cref");
|
|
|
|
register_symbol(pic, state, sGREF, "gref");
|
|
|
|
register_symbol(pic, state, sLREF, "lref");
|
|
|
|
register_symbol(pic, state, sCREF, "cref");
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
push_scope(analyze_state *state, pic_value args)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
analyze_scope *scope;
|
|
|
|
struct xhash *x;
|
|
|
|
pic_value v;
|
|
|
|
int i, l;
|
|
|
|
|
|
|
|
scope = (analyze_scope *)pic_alloc(pic, sizeof(analyze_scope));
|
|
|
|
scope->up = state->scope;
|
|
|
|
scope->local_tbl = x = xh_new();
|
|
|
|
scope->varg = false;
|
|
|
|
|
|
|
|
i = 1; l = 0;
|
|
|
|
for (v = args; pic_pair_p(v); v = pic_cdr(pic, v)) {
|
|
|
|
pic_value sym;
|
|
|
|
|
|
|
|
sym = pic_car(pic, v);
|
|
|
|
xh_put(x, pic_symbol_name(pic, pic_sym(sym)), i++);
|
|
|
|
}
|
|
|
|
if (pic_nil_p(v)) {
|
|
|
|
/* pass */
|
|
|
|
}
|
|
|
|
else if (pic_symbol_p(v)) {
|
|
|
|
scope->varg = true;
|
|
|
|
xh_put(x, pic_symbol_name(pic, pic_sym(v)), i + l++);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic_error(pic, "logic flaw");
|
|
|
|
}
|
|
|
|
scope->argc = i;
|
|
|
|
scope->localc = l;
|
|
|
|
scope->dirty_flags = (int *)pic_calloc(pic, i + l, sizeof(int));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pop_scope(analyze_state *state)
|
|
|
|
{
|
|
|
|
analyze_scope *scope;
|
|
|
|
|
|
|
|
scope = state->scope;
|
|
|
|
xh_destroy(scope->local_tbl);
|
|
|
|
pic_free(state->pic, scope->dirty_flags);
|
|
|
|
|
|
|
|
scope = scope->up;
|
|
|
|
pic_free(state->pic, state->scope);
|
|
|
|
state->scope = scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
static analyze_scope *
|
|
|
|
lookup_var(analyze_state *state, const char *key, int *depth, int *idx)
|
|
|
|
{
|
|
|
|
analyze_scope *scope = state->scope;
|
|
|
|
struct xh_entry *e;
|
|
|
|
int d = 0;
|
|
|
|
|
|
|
|
enter:
|
|
|
|
|
|
|
|
e = xh_get(scope->local_tbl, key);
|
|
|
|
if (e && e->val >= 0) {
|
|
|
|
if (scope->up == NULL) { /* global */
|
|
|
|
*depth = -1;
|
|
|
|
}
|
|
|
|
else { /* non-global */
|
|
|
|
*depth = d;
|
|
|
|
}
|
|
|
|
*idx = e->val;
|
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
if (scope->up) {
|
|
|
|
scope = scope->up;
|
|
|
|
++d;
|
|
|
|
goto enter;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
define_global_var(pic_state *pic, const char *name)
|
|
|
|
{
|
|
|
|
struct xh_entry *e;
|
|
|
|
|
|
|
|
if ((e = xh_get(pic->global_tbl, name))) {
|
|
|
|
pic_warn(pic, "redefining global");
|
|
|
|
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
|
|
|
|
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
|
|
|
|
is_global_scope(analyze_scope *scope)
|
|
|
|
{
|
|
|
|
return scope->up == NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
new_gref(analyze_state *state, int idx)
|
|
|
|
{
|
|
|
|
return pic_list(state->pic, 2, pic_symbol_value(state->sGREF), pic_int_value(idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-01-19 01:35:36 -05:00
|
|
|
static pic_value analyze_node(analyze_state *, pic_value, bool);
|
2014-01-18 23:20:28 -05:00
|
|
|
static pic_value analyze_call(analyze_state *, pic_value, bool);
|
|
|
|
static pic_value analyze_lambda(analyze_state *, pic_value);
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze(analyze_state *state, pic_value obj, bool tailpos)
|
2014-01-19 01:35:36 -05:00
|
|
|
{
|
|
|
|
int ai = pic_gc_arena_preserve(state->pic);
|
|
|
|
pic_value res;
|
|
|
|
|
|
|
|
res = analyze_node(state, obj, tailpos);
|
|
|
|
|
|
|
|
pic_gc_arena_restore(state->pic, ai);
|
|
|
|
pic_gc_protect(state->pic, res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_node(analyze_state *state, pic_value obj, bool tailpos)
|
2014-01-18 23:20:28 -05:00
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
analyze_scope *scope = state->scope;
|
|
|
|
|
|
|
|
switch (pic_type(obj)) {
|
|
|
|
case PIC_TT_SYMBOL: {
|
|
|
|
analyze_scope *s;
|
|
|
|
int depth = -1, idx = -1;
|
|
|
|
const char *name = pic_symbol_name(pic, pic_sym(obj));
|
|
|
|
|
|
|
|
s = lookup_var(state, name, &depth, &idx);
|
|
|
|
if (! s) {
|
|
|
|
#if DEBUG
|
|
|
|
printf("%s\n", name);
|
|
|
|
#endif
|
|
|
|
pic_error(pic, "symbol: unbound variable");
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (depth) {
|
|
|
|
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: {
|
|
|
|
pic_value proc;
|
|
|
|
|
|
|
|
if (! pic_list_p(pic, obj)) {
|
|
|
|
pic_error(pic, "invalid expression given");
|
|
|
|
}
|
|
|
|
|
|
|
|
proc = pic_car(pic, obj);
|
|
|
|
if (pic_symbol_p(proc)) {
|
|
|
|
pic_sym sym = pic_sym(proc);
|
|
|
|
|
|
|
|
if (sym == pic->sDEFINE) {
|
|
|
|
int idx;
|
|
|
|
pic_value var, val;
|
|
|
|
|
|
|
|
if (pic_length(pic, obj) < 2) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
var = pic_car(pic, pic_cdr(pic, obj));
|
|
|
|
if (pic_pair_p(var)) {
|
|
|
|
val = pic_cons(pic, pic_symbol_value(pic->sLAMBDA),
|
|
|
|
pic_cons(pic, pic_cdr(pic, var),
|
|
|
|
pic_cdr(pic, pic_cdr(pic, obj))));
|
|
|
|
var = pic_car(pic, var);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pic_length(pic, obj) != 3) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
val = pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)));
|
|
|
|
}
|
|
|
|
if (! pic_symbol_p(var)) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_global_scope(scope)) {
|
|
|
|
idx = define_global_var(pic, pic_symbol_name(pic, pic_sym(var)));
|
|
|
|
return new_gset(state, idx, analyze(state, val, false));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
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) {
|
|
|
|
return analyze_lambda(state, obj);
|
|
|
|
}
|
|
|
|
else if (sym == pic->sIF) {
|
|
|
|
pic_value if_true, if_false;
|
|
|
|
|
|
|
|
if_false = pic_none_value();
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
default:
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if_false = pic_car(pic, pic_cdr(pic, pic_cdr(pic, pic_cdr(pic, obj))));
|
|
|
|
FALLTHROUGH;
|
|
|
|
case 3:
|
|
|
|
if_true = pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return pic_list(pic, 4,
|
|
|
|
pic_symbol_value(pic->sIF),
|
|
|
|
analyze(state, pic_car(pic, pic_cdr(pic, obj)), false),
|
|
|
|
analyze(state, if_true, tailpos),
|
|
|
|
analyze(state, if_false, tailpos));
|
|
|
|
}
|
|
|
|
else if (sym == pic->sBEGIN) {
|
|
|
|
pic_value seq;
|
|
|
|
bool tail;
|
|
|
|
|
|
|
|
/* TODO: unwrap if the number of objects is 1 or 0 */
|
|
|
|
seq = pic_list(pic, 1, pic_symbol_value(pic->sBEGIN));
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
else if (sym == pic->sSETBANG) {
|
|
|
|
analyze_scope *s;
|
|
|
|
pic_value var, val;
|
|
|
|
int depth = -1, idx = -1;
|
|
|
|
|
|
|
|
if (pic_length(pic, obj) != 3) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
var = pic_car(pic, pic_cdr(pic, obj));
|
|
|
|
if (! pic_symbol_p(var)) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
s = lookup_var(state, pic_symbol_name(pic, pic_sym(var)), &depth, &idx);
|
|
|
|
if (! s) {
|
|
|
|
pic_error(pic, "unbound variable");
|
|
|
|
}
|
|
|
|
|
|
|
|
val = pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)));
|
|
|
|
|
|
|
|
switch (depth) {
|
|
|
|
case -1: /* global */
|
|
|
|
return new_gset(state, idx, val);
|
|
|
|
default: /* nonlocal */
|
|
|
|
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) {
|
|
|
|
if (pic_length(pic, obj) != 2) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
return obj; /* TODO: quote only if necessary */
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ARGC_ASSERT(n) do { \
|
|
|
|
if (pic_length(pic, obj) != (n) + 1) { \
|
|
|
|
pic_error(pic, "wrong number of arguments"); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define CONSTRUCT_OP1(op) \
|
|
|
|
pic_list(pic, 2, \
|
|
|
|
pic_symbol_value(op), \
|
|
|
|
analyze(state, pic_car(pic, pic_cdr(pic, obj)), false))
|
|
|
|
|
|
|
|
#define CONSTRUCT_OP2(op) \
|
|
|
|
pic_list(pic, 3, \
|
|
|
|
pic_symbol_value(op), \
|
|
|
|
analyze(state, pic_car(pic, pic_cdr(pic, obj)), false), \
|
|
|
|
analyze(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false))
|
|
|
|
|
|
|
|
else if (sym == state->rCONS) {
|
|
|
|
ARGC_ASSERT(2);
|
|
|
|
return CONSTRUCT_OP2(pic->sCONS);
|
|
|
|
}
|
|
|
|
else if (sym == state->rCAR) {
|
|
|
|
ARGC_ASSERT(1);
|
|
|
|
return CONSTRUCT_OP1(pic->sCAR);
|
|
|
|
}
|
|
|
|
else if (sym == state->rCDR) {
|
|
|
|
ARGC_ASSERT(1);
|
|
|
|
return CONSTRUCT_OP1(pic->sCDR);
|
|
|
|
}
|
|
|
|
else if (sym == state->rNILP) {
|
|
|
|
ARGC_ASSERT(1);
|
|
|
|
return CONSTRUCT_OP1(pic->sNILP);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ARGC_ASSERT_GE(n) do { \
|
|
|
|
if (pic_length(pic, obj) < (n) + 1) { \
|
|
|
|
pic_error(pic, "wrong number of arguments"); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define FOLD_ARGS(sym) do { \
|
|
|
|
obj = analyze(state, pic_car(pic, args), false); \
|
|
|
|
for (args = pic_cdr(pic, obj); ! pic_nil_p(args); args = pic_cdr(pic, args)) { \
|
|
|
|
obj = pic_list(pic, 3, pic_symbol_value(sym), obj, \
|
|
|
|
analyze(state, pic_car(pic, args), false)); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
else if (sym == state->rADD) {
|
|
|
|
pic_value args;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(0);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 1:
|
|
|
|
return pic_int_value(0);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sym == state->rSUB) {
|
|
|
|
pic_value args;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(1);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 2:
|
|
|
|
return pic_list(pic, 2, pic_symbol_value(pic->sMINUS),
|
|
|
|
analyze(state, pic_car(pic, pic_cdr(pic, obj)), false));
|
|
|
|
default:
|
|
|
|
args = pic_cdr(pic, obj);
|
|
|
|
FOLD_ARGS(pic->sSUB);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sym == state->rMUL) {
|
|
|
|
pic_value args;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(0);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 1:
|
|
|
|
return pic_int_value(1);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sym == state->rDIV) {
|
|
|
|
pic_value args;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(1);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 2:
|
|
|
|
args = pic_cdr(pic, obj);
|
|
|
|
obj = pic_list(pic, 3, proc, pic_float_value(1), pic_car(pic, args));
|
|
|
|
return analyze(state, obj, tailpos);
|
|
|
|
default:
|
|
|
|
args = pic_cdr(pic, obj);
|
|
|
|
FOLD_ARGS(pic->sDIV);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (sym == state->rEQ) {
|
|
|
|
ARGC_ASSERT(2);
|
|
|
|
return CONSTRUCT_OP2(pic->sEQ);
|
|
|
|
}
|
|
|
|
else if (sym == state->rLT) {
|
|
|
|
ARGC_ASSERT(2);
|
|
|
|
return CONSTRUCT_OP2(pic->sLT);
|
|
|
|
}
|
|
|
|
else if (sym == state->rLE) {
|
|
|
|
ARGC_ASSERT(2);
|
|
|
|
return CONSTRUCT_OP2(pic->sLE);
|
|
|
|
}
|
|
|
|
else if (sym == state->rGT) {
|
|
|
|
ARGC_ASSERT(2);
|
|
|
|
return CONSTRUCT_OP2(pic->sGT);
|
|
|
|
}
|
|
|
|
else if (sym == state->rGE) {
|
|
|
|
ARGC_ASSERT(2);
|
|
|
|
return CONSTRUCT_OP2(pic->sGE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return analyze_call(state, obj, tailpos);
|
|
|
|
}
|
|
|
|
case PIC_TT_BOOL:
|
|
|
|
case PIC_TT_FLOAT:
|
|
|
|
case PIC_TT_INT:
|
|
|
|
case PIC_TT_NIL:
|
|
|
|
case PIC_TT_CHAR: {
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
case PIC_TT_STRING:
|
|
|
|
case PIC_TT_VECTOR:
|
|
|
|
case PIC_TT_BLOB: {
|
|
|
|
return pic_list(pic, 2, pic_symbol_value(pic->sQUOTE), obj);
|
|
|
|
}
|
|
|
|
case PIC_TT_CONT:
|
|
|
|
case PIC_TT_ENV:
|
|
|
|
case PIC_TT_PROC:
|
|
|
|
case PIC_TT_UNDEF:
|
|
|
|
case PIC_TT_EOF:
|
|
|
|
case PIC_TT_PORT:
|
|
|
|
case PIC_TT_ERROR:
|
|
|
|
case PIC_TT_SENV:
|
|
|
|
case PIC_TT_SYNTAX:
|
|
|
|
case PIC_TT_SC:
|
|
|
|
case PIC_TT_LIB:
|
|
|
|
case PIC_TT_VAR:
|
|
|
|
case PIC_TT_IREP:
|
|
|
|
pic_error(pic, "invalid expression given");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_call(analyze_state *state, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
2014-01-19 01:35:36 -05:00
|
|
|
int ai = pic_gc_arena_preserve(pic);
|
2014-01-18 23:20:28 -05:00
|
|
|
pic_value seq;
|
|
|
|
pic_sym call;
|
|
|
|
|
|
|
|
if (tailpos) {
|
|
|
|
call = state->sCALL;
|
|
|
|
} else {
|
|
|
|
call = state->sTAILCALL;
|
|
|
|
}
|
|
|
|
seq = pic_list(pic, 1, pic_symbol_value(call));
|
|
|
|
for (; ! pic_nil_p(seq); obj = pic_cdr(pic, obj)) {
|
|
|
|
seq = pic_cons(pic, analyze(state, pic_car(pic, obj), false), seq);
|
|
|
|
}
|
2014-01-19 01:35:36 -05:00
|
|
|
seq = pic_reverse(pic, seq);
|
|
|
|
|
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
pic_gc_protect(pic, seq);
|
|
|
|
return seq;
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_lambda(analyze_state *state, pic_value obj)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
2014-01-19 01:35:36 -05:00
|
|
|
int ai = pic_gc_arena_preserve(pic);
|
2014-01-18 23:20:28 -05:00
|
|
|
pic_value args, body;
|
|
|
|
|
|
|
|
if (pic_length(pic, obj) < 2) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* formal arguments */
|
|
|
|
args = pic_car(pic, pic_cdr(pic, obj));
|
|
|
|
if (! valid_formal(pic, args)) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* analyze body in inner environment */
|
|
|
|
push_scope(state, args);
|
|
|
|
{
|
|
|
|
body = pic_cdr(pic, pic_cdr(pic, obj));
|
|
|
|
body = pic_cons(pic, pic_symbol_value(pic->sBEGIN), body);
|
|
|
|
body = analyze(state, body, true);
|
|
|
|
}
|
|
|
|
pop_scope(state);
|
|
|
|
|
2014-01-19 01:35:36 -05:00
|
|
|
obj = pic_list(pic, 3, pic_symbol_value(pic->sLAMBDA), args, body);
|
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
pic_gc_protect(pic, obj);
|
|
|
|
return obj;
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
|
2014-01-18 03:19:46 -05:00
|
|
|
/**
|
|
|
|
* scope object
|
|
|
|
*/
|
|
|
|
|
2013-10-23 02:52:14 -04:00
|
|
|
typedef struct codegen_scope {
|
2014-01-18 06:49:01 -05:00
|
|
|
bool varg;
|
2013-10-29 23:16:45 -04:00
|
|
|
/* local variables are 1-indexed, 0 is reserved for the callee */
|
2013-10-22 09:22:35 -04:00
|
|
|
struct xhash *local_tbl;
|
2014-01-18 08:32:41 -05:00
|
|
|
/* rest args variable is counted by localc */
|
2013-11-01 05:55:23 -04:00
|
|
|
size_t argc, localc;
|
2013-11-04 19:14:21 -05:00
|
|
|
/* if local var i is captured, then dirty_flags[i] == 1 */
|
|
|
|
int *dirty_flags;
|
2014-01-18 06:49:01 -05:00
|
|
|
/* actual bit code sequence */
|
|
|
|
struct pic_code *code;
|
|
|
|
size_t clen, ccapa;
|
2014-01-18 07:48:50 -05:00
|
|
|
/* child ireps */
|
|
|
|
struct pic_irep **irep;
|
|
|
|
size_t ilen, icapa;
|
2014-01-18 08:32:41 -05:00
|
|
|
/* constant object pool */
|
|
|
|
pic_value *pool;
|
|
|
|
size_t plen, pcapa;
|
2014-01-18 06:49:01 -05:00
|
|
|
|
|
|
|
struct codegen_scope *up;
|
2013-10-23 02:52:14 -04:00
|
|
|
} codegen_scope;
|
2013-10-22 09:22:35 -04:00
|
|
|
|
2013-10-23 02:52:14 -04:00
|
|
|
static codegen_scope *
|
2013-10-22 09:22:35 -04:00
|
|
|
new_global_scope(pic_state *pic)
|
|
|
|
{
|
2013-10-23 02:52:14 -04:00
|
|
|
codegen_scope *scope;
|
2013-10-22 09:22:35 -04:00
|
|
|
|
2013-10-23 02:52:14 -04:00
|
|
|
scope = (codegen_scope *)pic_alloc(pic, sizeof(codegen_scope));
|
2013-10-22 09:22:35 -04:00
|
|
|
scope->up = NULL;
|
|
|
|
scope->local_tbl = pic->global_tbl;
|
2013-10-23 11:09:40 -04:00
|
|
|
scope->argc = -1;
|
2013-11-01 05:55:23 -04:00
|
|
|
scope->localc = -1;
|
2013-11-04 19:14:21 -05:00
|
|
|
scope->dirty_flags = NULL;
|
2013-10-27 05:13:36 -04:00
|
|
|
scope->varg = false;
|
2014-01-18 08:54:28 -05:00
|
|
|
scope->code = (struct pic_code *)pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(struct pic_code));
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->clen = 0;
|
2014-01-18 08:54:28 -05:00
|
|
|
scope->ccapa = PIC_ISEQ_SIZE;
|
2014-01-18 07:48:50 -05:00
|
|
|
scope->irep = (struct pic_irep **)pic_calloc(pic, PIC_IREP_SIZE, sizeof(struct pic_irep *));
|
|
|
|
scope->ilen = 0;
|
|
|
|
scope->icapa = PIC_IREP_SIZE;
|
2014-01-18 08:32:41 -05:00
|
|
|
scope->pool = (pic_value *)pic_calloc(pic, PIC_POOL_SIZE, sizeof(pic_value));
|
|
|
|
scope->plen = 0;
|
|
|
|
scope->pcapa = PIC_POOL_SIZE;
|
2014-01-18 06:49:01 -05:00
|
|
|
|
2013-10-22 09:22:35 -04:00
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
|
2013-10-23 02:52:14 -04:00
|
|
|
static codegen_scope *
|
|
|
|
new_local_scope(pic_state *pic, pic_value args, codegen_scope *scope)
|
2013-10-20 04:06:47 -04:00
|
|
|
{
|
2013-10-23 02:52:14 -04:00
|
|
|
codegen_scope *new_scope;
|
2013-10-20 04:06:47 -04:00
|
|
|
pic_value v;
|
2013-11-01 05:55:23 -04:00
|
|
|
int i, l;
|
2013-10-22 09:22:35 -04:00
|
|
|
struct xhash *x;
|
|
|
|
|
2013-10-23 02:52:14 -04:00
|
|
|
new_scope = (codegen_scope *)pic_alloc(pic, sizeof(codegen_scope));
|
2013-10-22 09:22:35 -04:00
|
|
|
new_scope->up = scope;
|
|
|
|
new_scope->local_tbl = x = xh_new();
|
2013-10-27 05:13:36 -04:00
|
|
|
new_scope->varg = false;
|
2013-10-22 09:22:35 -04:00
|
|
|
|
2013-11-01 05:55:23 -04:00
|
|
|
i = 1; l = 0;
|
2013-10-27 05:13:36 -04:00
|
|
|
for (v = args; pic_pair_p(v); v = pic_cdr(pic, v)) {
|
2013-10-22 09:22:35 -04:00
|
|
|
pic_value sym;
|
|
|
|
|
|
|
|
sym = pic_car(pic, v);
|
2013-10-28 13:11:31 -04:00
|
|
|
xh_put(x, pic_symbol_name(pic, pic_sym(sym)), i++);
|
2013-10-22 09:22:35 -04:00
|
|
|
}
|
2013-10-27 05:13:36 -04:00
|
|
|
if (pic_nil_p(v)) {
|
|
|
|
/* pass */
|
|
|
|
}
|
|
|
|
else if (pic_symbol_p(v)) {
|
|
|
|
new_scope->varg = true;
|
2013-11-01 05:55:23 -04:00
|
|
|
xh_put(x, pic_symbol_name(pic, pic_sym(v)), i + l++);
|
2013-10-27 05:13:36 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic_error(pic, "logic flaw");
|
|
|
|
}
|
2013-10-23 11:09:40 -04:00
|
|
|
new_scope->argc = i;
|
2013-11-01 05:55:23 -04:00
|
|
|
new_scope->localc = l;
|
2013-11-04 19:14:21 -05:00
|
|
|
new_scope->dirty_flags = (int *)pic_calloc(pic, i + l, sizeof(int));
|
2013-10-22 09:22:35 -04:00
|
|
|
|
2014-01-18 08:54:28 -05:00
|
|
|
new_scope->code = (struct pic_code *)pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(struct pic_code));
|
2014-01-18 06:49:01 -05:00
|
|
|
new_scope->clen = 0;
|
2014-01-18 08:54:28 -05:00
|
|
|
new_scope->ccapa = PIC_ISEQ_SIZE;
|
2014-01-18 06:49:01 -05:00
|
|
|
|
2014-01-18 07:48:50 -05:00
|
|
|
new_scope->irep = (struct pic_irep **)pic_calloc(pic, PIC_IREP_SIZE, sizeof(struct pic_irep *));
|
|
|
|
new_scope->ilen = 0;
|
|
|
|
new_scope->icapa = PIC_IREP_SIZE;
|
|
|
|
|
2014-01-18 08:32:41 -05:00
|
|
|
new_scope->pool = (pic_value *)pic_calloc(pic, PIC_POOL_SIZE, sizeof(pic_value));
|
|
|
|
new_scope->plen = 0;
|
|
|
|
new_scope->pcapa = PIC_POOL_SIZE;
|
|
|
|
|
2013-10-22 09:22:35 -04:00
|
|
|
return new_scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-10-23 04:25:39 -04:00
|
|
|
destroy_scope(pic_state *pic, codegen_scope *scope)
|
2013-10-22 09:22:35 -04:00
|
|
|
{
|
|
|
|
if (scope->up) {
|
|
|
|
xh_destory(scope->local_tbl);
|
2013-11-04 19:14:21 -05:00
|
|
|
pic_free(pic, scope->dirty_flags);
|
2013-10-22 09:22:35 -04:00
|
|
|
}
|
|
|
|
pic_free(pic, scope);
|
|
|
|
}
|
|
|
|
|
2014-01-18 03:19:46 -05:00
|
|
|
/**
|
|
|
|
* global codegen state
|
|
|
|
*/
|
2013-10-23 04:25:39 -04:00
|
|
|
|
|
|
|
typedef struct codegen_state {
|
|
|
|
pic_state *pic;
|
|
|
|
codegen_scope *scope;
|
2014-01-18 14:47:18 -05:00
|
|
|
pic_sym rCONS, rCAR, rCDR, rNILP;
|
|
|
|
pic_sym rADD, rSUB, rMUL, rDIV;
|
|
|
|
pic_sym rEQ, rLT, rLE, rGT, rGE;
|
2013-10-23 04:25:39 -04:00
|
|
|
} codegen_state;
|
|
|
|
|
2014-01-18 14:47:18 -05:00
|
|
|
#define register_renamed_symbol(pic, state, slot, lib, name) do { \
|
|
|
|
struct xh_entry *e; \
|
|
|
|
if (! (e = xh_get(lib->senv->tbl, name))) \
|
|
|
|
pic_error(pic, "internal error! native VM procedure not found"); \
|
|
|
|
state->slot = e->val; \
|
|
|
|
} while (0)
|
|
|
|
|
2013-10-23 04:25:39 -04:00
|
|
|
static codegen_state *
|
|
|
|
new_codegen_state(pic_state *pic)
|
|
|
|
{
|
|
|
|
codegen_state *state;
|
2014-01-18 14:47:18 -05:00
|
|
|
struct pic_lib *stdlib;
|
2013-10-23 04:25:39 -04:00
|
|
|
|
|
|
|
state = (codegen_state *)pic_alloc(pic, sizeof(codegen_state));
|
|
|
|
state->pic = pic;
|
|
|
|
state->scope = new_global_scope(pic);
|
|
|
|
|
2014-01-18 14:47:18 -05:00
|
|
|
stdlib = pic_find_library(pic, pic_parse(pic, "(scheme base)"));
|
|
|
|
|
|
|
|
/* native VM procedures */
|
|
|
|
register_renamed_symbol(pic, state, rCONS, stdlib, "cons");
|
|
|
|
register_renamed_symbol(pic, state, rCAR, stdlib, "car");
|
|
|
|
register_renamed_symbol(pic, state, rCDR, stdlib, "cdr");
|
|
|
|
register_renamed_symbol(pic, state, rNILP, stdlib, "null?");
|
|
|
|
register_renamed_symbol(pic, state, rADD, stdlib, "+");
|
|
|
|
register_renamed_symbol(pic, state, rSUB, stdlib, "-");
|
|
|
|
register_renamed_symbol(pic, state, rMUL, stdlib, "*");
|
|
|
|
register_renamed_symbol(pic, state, rDIV, stdlib, "/");
|
|
|
|
register_renamed_symbol(pic, state, rEQ, stdlib, "=");
|
|
|
|
register_renamed_symbol(pic, state, rLT, stdlib, "<");
|
|
|
|
register_renamed_symbol(pic, state, rLE, stdlib, "<=");
|
|
|
|
register_renamed_symbol(pic, state, rGT, stdlib, ">");
|
|
|
|
register_renamed_symbol(pic, state, rGE, stdlib, ">=");
|
|
|
|
|
2013-10-23 04:25:39 -04:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
destroy_codegen_state(pic_state *pic, codegen_state *state)
|
|
|
|
{
|
|
|
|
destroy_scope(pic, state->scope);
|
|
|
|
pic_free(pic, state);
|
|
|
|
}
|
|
|
|
|
2013-10-23 11:33:37 -04:00
|
|
|
static codegen_scope *
|
2013-10-23 04:25:39 -04:00
|
|
|
scope_lookup(codegen_state *state, const char *key, int *depth, int *idx)
|
2013-10-22 09:22:35 -04:00
|
|
|
{
|
2013-10-23 04:25:39 -04:00
|
|
|
codegen_scope *scope = state->scope;
|
2013-10-22 09:22:35 -04:00
|
|
|
struct xh_entry *e;
|
2013-10-20 04:06:47 -04:00
|
|
|
int d = 0;
|
|
|
|
|
|
|
|
enter:
|
|
|
|
|
2013-10-22 09:22:35 -04:00
|
|
|
e = xh_get(scope->local_tbl, key);
|
2013-10-30 03:37:43 -04:00
|
|
|
if (e && e->val >= 0) {
|
2013-10-22 09:22:35 -04:00
|
|
|
if (scope->up == NULL) { /* global */
|
2013-10-20 04:06:47 -04:00
|
|
|
*depth = -1;
|
|
|
|
}
|
|
|
|
else { /* non-global */
|
|
|
|
*depth = d;
|
|
|
|
}
|
2013-10-22 09:22:35 -04:00
|
|
|
*idx = e->val;
|
2013-10-23 11:33:37 -04:00
|
|
|
return scope;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
2013-10-22 09:22:35 -04:00
|
|
|
if (scope->up) {
|
|
|
|
scope = scope->up;
|
2013-10-20 04:06:47 -04:00
|
|
|
++d;
|
|
|
|
goto enter;
|
|
|
|
}
|
2013-10-23 11:33:37 -04:00
|
|
|
return NULL;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2013-10-22 09:22:35 -04:00
|
|
|
scope_global_define(pic_state *pic, const char *name)
|
2013-10-20 04:06:47 -04:00
|
|
|
{
|
2013-10-22 09:22:35 -04:00
|
|
|
struct xh_entry *e;
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-22 09:22:35 -04:00
|
|
|
if ((e = xh_get(pic->global_tbl, name))) {
|
2013-10-24 09:29:40 -04:00
|
|
|
pic_warn(pic, "redefining global");
|
2013-10-22 09:22:35 -04:00
|
|
|
return e->val;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
2013-10-22 09:22:35 -04:00
|
|
|
e = xh_put(pic->global_tbl, name, pic->glen++);
|
|
|
|
if (pic->glen >= pic->gcapa) {
|
|
|
|
pic_error(pic, "global table overflow");
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
2013-10-22 09:22:35 -04:00
|
|
|
return e->val;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
|
|
|
|
2013-11-13 04:08:22 -05:00
|
|
|
static int
|
|
|
|
scope_local_define(pic_state *pic, const char *name, codegen_scope *scope)
|
|
|
|
{
|
|
|
|
struct xh_entry *e;
|
|
|
|
|
|
|
|
e = xh_put(scope->local_tbl, name, scope->argc + scope->localc++);
|
2013-11-16 23:10:36 -05:00
|
|
|
scope->dirty_flags = (int *)pic_realloc(pic, scope->dirty_flags, (scope->argc + scope->localc) * sizeof(int));
|
|
|
|
scope->dirty_flags[e->val] = 0;
|
2013-11-13 04:08:22 -05:00
|
|
|
return e->val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
scope_is_global(codegen_scope *scope)
|
|
|
|
{
|
|
|
|
return scope->up == NULL;
|
|
|
|
}
|
|
|
|
|
2013-10-29 21:04:23 -04:00
|
|
|
static void codegen_call(codegen_state *, pic_value, bool);
|
2013-10-23 04:26:02 -04:00
|
|
|
static struct pic_irep *codegen_lambda(codegen_state *, pic_value);
|
2013-10-20 04:06:47 -04:00
|
|
|
|
|
|
|
static void
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(codegen_state *state, pic_value obj, bool tailpos)
|
2013-10-20 04:06:47 -04:00
|
|
|
{
|
2013-10-23 04:25:39 -04:00
|
|
|
pic_state *pic = state->pic;
|
2014-01-18 06:49:01 -05:00
|
|
|
codegen_scope *scope = state->scope;
|
2013-10-20 04:06:47 -04:00
|
|
|
|
|
|
|
switch (pic_type(obj)) {
|
|
|
|
case PIC_TT_SYMBOL: {
|
2013-10-23 11:33:37 -04:00
|
|
|
codegen_scope *s;
|
2013-12-03 09:10:46 -05:00
|
|
|
int depth = -1, idx = -1;
|
2013-10-22 09:22:35 -04:00
|
|
|
const char *name;
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-28 13:11:31 -04:00
|
|
|
name = pic_symbol_name(pic, pic_sym(obj));
|
2013-10-23 11:33:37 -04:00
|
|
|
s = scope_lookup(state, name, &depth, &idx);
|
|
|
|
if (! s) {
|
2013-11-26 19:52:30 -05:00
|
|
|
#if DEBUG
|
|
|
|
printf("%s\n", name);
|
|
|
|
#endif
|
|
|
|
pic_error(pic, "symbol: unbound variable");
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
|
|
|
|
2013-10-23 13:51:02 -04:00
|
|
|
switch (depth) {
|
|
|
|
case -1: /* global */
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_GREF;
|
|
|
|
scope->code[scope->clen].u.i = idx;
|
|
|
|
scope->clen++;
|
2013-10-23 13:51:02 -04:00
|
|
|
break;
|
|
|
|
default: /* nonlocal */
|
2013-11-04 19:14:21 -05:00
|
|
|
s->dirty_flags[idx] = 1;
|
2013-10-23 13:51:02 -04:00
|
|
|
/* at this stage, lref and cref are not distinguished */
|
|
|
|
FALLTHROUGH;
|
|
|
|
case 0: /* local */
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_CREF;
|
|
|
|
scope->code[scope->clen].u.r.depth = depth;
|
|
|
|
scope->code[scope->clen].u.r.idx = idx;
|
|
|
|
scope->clen++;
|
2013-10-23 13:51:02 -04:00
|
|
|
break;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PIC_TT_PAIR: {
|
|
|
|
pic_value proc;
|
|
|
|
|
2013-10-24 08:55:07 -04:00
|
|
|
if (! pic_list_p(pic, obj)) {
|
|
|
|
pic_error(pic, "invalid expression given");
|
|
|
|
}
|
|
|
|
|
2013-10-20 04:06:47 -04:00
|
|
|
proc = pic_car(pic, obj);
|
2013-10-28 13:11:31 -04:00
|
|
|
if (pic_symbol_p(proc)) {
|
|
|
|
pic_sym sym = pic_sym(proc);
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-28 13:11:31 -04:00
|
|
|
if (sym == pic->sDEFINE) {
|
|
|
|
int idx;
|
|
|
|
pic_value var, val;
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-29 09:16:16 -04:00
|
|
|
if (pic_length(pic, obj) < 2) {
|
2013-10-26 13:51:06 -04:00
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
2013-10-28 13:11:31 -04:00
|
|
|
|
|
|
|
var = pic_car(pic, pic_cdr(pic, obj));
|
|
|
|
if (pic_pair_p(var)) {
|
|
|
|
val = pic_cons(pic, pic_symbol_value(pic->sLAMBDA),
|
|
|
|
pic_cons(pic, pic_cdr(pic, var),
|
|
|
|
pic_cdr(pic, pic_cdr(pic, obj))));
|
|
|
|
var = pic_car(pic, var);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pic_length(pic, obj) != 3) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
val = pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)));
|
|
|
|
}
|
|
|
|
if (! pic_symbol_p(var)) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
2014-01-18 06:53:16 -05:00
|
|
|
if (scope_is_global(scope)) {
|
2013-11-13 04:08:22 -05:00
|
|
|
idx = scope_global_define(pic, pic_symbol_name(pic, pic_sym(var)));
|
|
|
|
codegen(state, val, false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_GSET;
|
|
|
|
scope->code[scope->clen].u.i = idx;
|
|
|
|
scope->clen++;
|
|
|
|
scope->code[scope->clen].insn = OP_PUSHNONE;
|
|
|
|
scope->clen++;
|
2013-11-13 04:08:22 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
2014-01-18 06:53:16 -05:00
|
|
|
idx = scope_local_define(pic, pic_symbol_name(pic, pic_sym(var)), scope);
|
2013-11-13 04:08:22 -05:00
|
|
|
codegen(state, val, false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_CSET;
|
|
|
|
scope->code[scope->clen].u.r.depth = 0;
|
|
|
|
scope->code[scope->clen].u.r.idx = idx;
|
|
|
|
scope->clen++;
|
|
|
|
scope->code[scope->clen].insn = OP_PUSHNONE;
|
|
|
|
scope->clen++;
|
2013-11-13 04:08:22 -05:00
|
|
|
break;
|
|
|
|
}
|
2013-10-26 13:51:06 -04:00
|
|
|
}
|
2013-10-28 13:11:31 -04:00
|
|
|
else if (sym == pic->sLAMBDA) {
|
2013-11-21 09:28:43 -05:00
|
|
|
int k;
|
|
|
|
|
2014-01-18 07:48:50 -05:00
|
|
|
if (scope->ilen >= scope->icapa) {
|
2013-11-21 09:28:43 -05:00
|
|
|
#if DEBUG
|
|
|
|
puts("irep realloced");
|
|
|
|
#endif
|
2014-01-18 07:48:50 -05:00
|
|
|
scope->icapa *= 2;
|
2014-01-18 09:01:00 -05:00
|
|
|
scope->irep = (struct pic_irep **)pic_realloc(pic, scope->irep, sizeof(struct pic_irep *) * scope->icapa);
|
2013-11-21 09:28:43 -05:00
|
|
|
}
|
2014-01-18 07:48:50 -05:00
|
|
|
k = scope->ilen++;
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_LAMBDA;
|
|
|
|
scope->code[scope->clen].u.i = k;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
|
2014-01-18 07:48:50 -05:00
|
|
|
scope->irep[k] = codegen_lambda(state, obj);
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
2013-10-24 08:55:07 -04:00
|
|
|
}
|
2013-10-28 13:11:31 -04:00
|
|
|
else if (sym == pic->sIF) {
|
|
|
|
int s,t;
|
2013-10-29 09:15:58 -04:00
|
|
|
pic_value if_true, if_false;
|
2013-10-24 08:55:07 -04:00
|
|
|
|
2014-01-08 01:22:23 -05:00
|
|
|
if_false = pic_none_value();
|
2013-10-29 09:15:58 -04:00
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
default:
|
2013-10-28 13:11:31 -04:00
|
|
|
pic_error(pic, "syntax error");
|
2013-10-29 09:15:58 -04:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if_false = pic_car(pic, pic_cdr(pic, pic_cdr(pic, pic_cdr(pic, obj))));
|
|
|
|
FALLTHROUGH;
|
|
|
|
case 3:
|
|
|
|
if_true = pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)));
|
2013-10-28 13:11:31 -04:00
|
|
|
}
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_JMPIF;
|
|
|
|
s = scope->clen++;
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-28 13:11:31 -04:00
|
|
|
/* if false branch */
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, if_false, tailpos);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_JMP;
|
|
|
|
t = scope->clen++;
|
2013-10-24 08:55:07 -04:00
|
|
|
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[s].u.i = scope->clen - s;
|
2013-10-28 13:11:31 -04:00
|
|
|
|
|
|
|
/* if true branch */
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, if_true, tailpos);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[t].u.i = scope->clen - t;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (sym == pic->sBEGIN) {
|
2013-10-29 21:04:23 -04:00
|
|
|
int i, len;
|
2013-10-28 13:11:31 -04:00
|
|
|
pic_value v, seq;
|
|
|
|
|
|
|
|
seq = pic_cdr(pic, obj);
|
2013-10-29 21:04:23 -04:00
|
|
|
len = pic_length(pic, seq);
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
|
|
v = pic_car(pic, seq);
|
|
|
|
if (i + 1 >= len) {
|
|
|
|
codegen(state, v, tailpos);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
codegen(state, v, false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_POP;
|
|
|
|
scope->clen++;
|
2013-10-29 21:04:23 -04:00
|
|
|
}
|
|
|
|
seq = pic_cdr(pic, seq);
|
2013-10-28 13:11:31 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (sym == pic->sSETBANG) {
|
|
|
|
codegen_scope *s;
|
|
|
|
pic_value var;
|
2013-12-03 09:10:46 -05:00
|
|
|
int depth = -1, idx = -1;
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-28 13:11:31 -04:00
|
|
|
if (pic_length(pic, obj) != 3) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-28 13:11:31 -04:00
|
|
|
var = pic_car(pic, pic_cdr(pic, obj));
|
|
|
|
if (! pic_symbol_p(var)) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-28 13:11:31 -04:00
|
|
|
s = scope_lookup(state, pic_symbol_name(pic, pic_sym(var)), &depth, &idx);
|
|
|
|
if (! s) {
|
|
|
|
pic_error(pic, "unbound variable");
|
|
|
|
}
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
|
2013-10-28 13:11:31 -04:00
|
|
|
|
|
|
|
switch (depth) {
|
|
|
|
case -1: /* global */
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_GSET;
|
|
|
|
scope->code[scope->clen].u.i = idx;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
default: /* nonlocal */
|
2013-11-04 19:14:21 -05:00
|
|
|
s->dirty_flags[idx] = 1;
|
2013-10-28 13:11:31 -04:00
|
|
|
/* at this stage, lset and cset are not distinguished */
|
|
|
|
FALLTHROUGH;
|
|
|
|
case 0: /* local */
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_CSET;
|
|
|
|
scope->code[scope->clen].u.r.depth = depth;
|
|
|
|
scope->code[scope->clen].u.r.idx = idx;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHNONE;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
2013-10-28 13:11:31 -04:00
|
|
|
else if (sym == pic->sQUOTE) {
|
|
|
|
int pidx;
|
2013-10-23 14:14:32 -04:00
|
|
|
|
2013-10-28 13:11:31 -04:00
|
|
|
if (pic_length(pic, obj) != 2) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
2013-10-24 08:55:07 -04:00
|
|
|
|
2014-01-18 08:56:43 -05:00
|
|
|
if (scope->plen >= scope->pcapa) {
|
|
|
|
scope->pcapa *= 2;
|
2014-01-18 09:01:00 -05:00
|
|
|
scope->pool = (pic_value *)pic_realloc(pic, scope->pool, sizeof(pic_value) * scope->pcapa);
|
2013-11-22 09:35:51 -05:00
|
|
|
}
|
2014-01-18 08:56:43 -05:00
|
|
|
pidx = scope->plen++;
|
2014-01-18 08:32:41 -05:00
|
|
|
scope->pool[pidx] = pic_car(pic, pic_cdr(pic, obj));
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHCONST;
|
|
|
|
scope->code[scope->clen].u.i = pidx;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
2013-10-24 08:55:07 -04:00
|
|
|
}
|
|
|
|
|
2013-10-28 13:11:31 -04:00
|
|
|
#define ARGC_ASSERT(n) do { \
|
|
|
|
if (pic_length(pic, obj) != (n) + 1) { \
|
|
|
|
pic_error(pic, "wrong number of arguments"); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rCONS) {
|
2013-10-28 13:11:31 -04:00
|
|
|
ARGC_ASSERT(2);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_CONS;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
2013-10-23 14:14:32 -04:00
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rCAR) {
|
2013-10-28 13:11:31 -04:00
|
|
|
ARGC_ASSERT(1);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_CAR;
|
|
|
|
scope->clen++;
|
2013-10-23 14:14:32 -04:00
|
|
|
break;
|
2013-10-28 13:11:31 -04:00
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rCDR) {
|
2013-10-28 13:11:31 -04:00
|
|
|
ARGC_ASSERT(1);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_CDR;
|
|
|
|
scope->clen++;
|
2013-10-23 14:14:32 -04:00
|
|
|
break;
|
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rNILP) {
|
2013-10-28 13:11:31 -04:00
|
|
|
ARGC_ASSERT(1);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_NILP;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2013-11-06 04:55:06 -05:00
|
|
|
|
|
|
|
#define ARGC_ASSERT_GE(n) do { \
|
|
|
|
if (pic_length(pic, obj) < (n) + 1) { \
|
|
|
|
pic_error(pic, "wrong number of arguments"); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rADD) {
|
2013-11-06 04:55:06 -05:00
|
|
|
pic_value args;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(0);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 1:
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHINT;
|
|
|
|
scope->code[scope->clen].u.i = 0;
|
|
|
|
scope->clen++;
|
2013-11-06 04:55:06 -05:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), tailpos);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
args = pic_cdr(pic, obj);
|
|
|
|
codegen(state, pic_car(pic, args), false);
|
|
|
|
while (pic_length(pic, args) >= 2) {
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, args)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_ADD;
|
|
|
|
scope->clen++;
|
2013-11-06 04:55:06 -05:00
|
|
|
args = pic_cdr(pic, args);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rSUB) {
|
2013-11-06 22:18:00 -05:00
|
|
|
pic_value args;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(1);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 2:
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_MINUS;
|
|
|
|
scope->clen++;
|
2013-11-06 22:18:00 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
args = pic_cdr(pic, obj);
|
|
|
|
codegen(state, pic_car(pic, args), false);
|
|
|
|
while (pic_length(pic, args) >= 2) {
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, args)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_SUB;
|
|
|
|
scope->clen++;
|
2013-11-06 22:18:00 -05:00
|
|
|
args = pic_cdr(pic, args);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rMUL) {
|
2013-11-06 22:52:59 -05:00
|
|
|
pic_value args;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(0);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 1:
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHINT;
|
|
|
|
scope->code[scope->clen].u.i = 1;
|
|
|
|
scope->clen++;
|
2013-11-06 22:52:59 -05:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), tailpos);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
args = pic_cdr(pic, obj);
|
|
|
|
codegen(state, pic_car(pic, args), false);
|
|
|
|
while (pic_length(pic, args) >= 2) {
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, args)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_MUL;
|
|
|
|
scope->clen++;
|
2013-11-06 22:52:59 -05:00
|
|
|
args = pic_cdr(pic, args);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rDIV) {
|
2013-11-06 22:52:59 -05:00
|
|
|
pic_value args;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(1);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 2:
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHINT;
|
|
|
|
scope->code[scope->clen].u.i = 1;
|
|
|
|
scope->clen++;
|
2013-11-06 22:52:59 -05:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_DIV;
|
|
|
|
scope->clen++;
|
2013-11-06 22:52:59 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
args = pic_cdr(pic, obj);
|
|
|
|
codegen(state, pic_car(pic, args), false);
|
|
|
|
while (pic_length(pic, args) >= 2) {
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, args)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_DIV;
|
|
|
|
scope->clen++;
|
2013-11-06 22:52:59 -05:00
|
|
|
args = pic_cdr(pic, args);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rEQ) {
|
2013-10-28 13:11:31 -04:00
|
|
|
ARGC_ASSERT(2);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_EQ;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rLT) {
|
2013-10-28 13:11:31 -04:00
|
|
|
ARGC_ASSERT(2);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_LT;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rLE) {
|
2013-10-28 13:11:31 -04:00
|
|
|
ARGC_ASSERT(2);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_LE;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rGT) {
|
2013-10-28 13:11:31 -04:00
|
|
|
ARGC_ASSERT(2);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_LT;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
|
|
|
}
|
2014-01-18 14:47:18 -05:00
|
|
|
else if (sym == state->rGE) {
|
2013-10-28 13:11:31 -04:00
|
|
|
ARGC_ASSERT(2);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
|
|
|
|
codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_LE;
|
|
|
|
scope->clen++;
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
2013-10-24 08:55:07 -04:00
|
|
|
}
|
2013-10-20 20:29:56 -04:00
|
|
|
}
|
2013-10-24 08:55:07 -04:00
|
|
|
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen_call(state, obj, tailpos);
|
2013-10-28 13:11:31 -04:00
|
|
|
break;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
|
|
|
case PIC_TT_BOOL: {
|
|
|
|
if (pic_true_p(obj)) {
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHTRUE;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
|
|
|
else {
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHFALSE;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->clen++;
|
2013-10-20 04:06:47 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PIC_TT_FLOAT: {
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHFLOAT;
|
|
|
|
scope->code[scope->clen].u.f = pic_float(obj);
|
|
|
|
scope->clen++;
|
2013-10-20 04:06:47 -04:00
|
|
|
break;
|
|
|
|
}
|
2013-10-27 11:21:24 -04:00
|
|
|
case PIC_TT_INT: {
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHINT;
|
|
|
|
scope->code[scope->clen].u.i = pic_int(obj);
|
|
|
|
scope->clen++;
|
2013-10-27 11:21:24 -04:00
|
|
|
break;
|
|
|
|
}
|
2013-10-20 04:06:47 -04:00
|
|
|
case PIC_TT_NIL: {
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHNIL;
|
|
|
|
scope->clen++;
|
2013-10-20 04:06:47 -04:00
|
|
|
break;
|
|
|
|
}
|
2013-11-04 21:37:18 -05:00
|
|
|
case PIC_TT_CHAR: {
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHCHAR;
|
|
|
|
scope->code[scope->clen].u.c = pic_char(obj);
|
|
|
|
scope->clen++;
|
2013-11-04 21:37:18 -05:00
|
|
|
break;
|
|
|
|
}
|
2013-10-29 02:51:37 -04:00
|
|
|
case PIC_TT_STRING:
|
2013-11-04 22:38:23 -05:00
|
|
|
case PIC_TT_VECTOR:
|
|
|
|
case PIC_TT_BLOB: {
|
2013-10-20 21:48:03 -04:00
|
|
|
int pidx;
|
2014-01-18 08:56:43 -05:00
|
|
|
if (scope->plen >= scope->pcapa) {
|
|
|
|
scope->pcapa *= 2;
|
2014-01-18 09:01:00 -05:00
|
|
|
scope->pool = (pic_value *)pic_realloc(pic, scope->pool, sizeof(pic_value) * scope->pcapa);
|
2013-11-22 09:35:51 -05:00
|
|
|
}
|
2014-01-18 08:56:43 -05:00
|
|
|
pidx = scope->plen++;
|
2014-01-18 08:32:41 -05:00
|
|
|
scope->pool[pidx] = obj;
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = OP_PUSHCONST;
|
|
|
|
scope->code[scope->clen].u.i = pidx;
|
|
|
|
scope->clen++;
|
2013-10-20 21:48:03 -04:00
|
|
|
break;
|
|
|
|
}
|
2013-11-09 00:14:25 -05:00
|
|
|
case PIC_TT_CONT:
|
2013-10-23 13:02:07 -04:00
|
|
|
case PIC_TT_ENV:
|
2013-10-20 04:06:47 -04:00
|
|
|
case PIC_TT_PROC:
|
|
|
|
case PIC_TT_UNDEF:
|
2013-10-22 03:02:20 -04:00
|
|
|
case PIC_TT_EOF:
|
2013-11-17 03:25:26 -05:00
|
|
|
case PIC_TT_PORT:
|
2013-11-26 07:05:02 -05:00
|
|
|
case PIC_TT_ERROR:
|
|
|
|
case PIC_TT_SENV:
|
2013-11-27 01:04:02 -05:00
|
|
|
case PIC_TT_SYNTAX:
|
2013-12-07 06:58:18 -05:00
|
|
|
case PIC_TT_SC:
|
2014-01-08 10:39:13 -05:00
|
|
|
case PIC_TT_LIB:
|
2014-01-18 02:51:54 -05:00
|
|
|
case PIC_TT_VAR:
|
|
|
|
case PIC_TT_IREP:
|
2013-10-20 05:17:12 -04:00
|
|
|
pic_error(pic, "invalid expression given");
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen_call(codegen_state *state, pic_value obj, bool tailpos)
|
2013-10-20 04:06:47 -04:00
|
|
|
{
|
2013-10-23 04:25:39 -04:00
|
|
|
pic_state *pic = state->pic;
|
2014-01-18 06:49:01 -05:00
|
|
|
codegen_scope *scope = state->scope;
|
2013-10-20 04:06:47 -04:00
|
|
|
pic_value seq;
|
|
|
|
int i = 0;
|
|
|
|
|
2013-10-23 02:55:42 -04:00
|
|
|
for (seq = obj; ! pic_nil_p(seq); seq = pic_cdr(pic, seq)) {
|
2013-10-20 04:06:47 -04:00
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
v = pic_car(pic, seq);
|
2013-10-29 21:04:23 -04:00
|
|
|
codegen(state, v, false);
|
2013-10-20 04:06:47 -04:00
|
|
|
++i;
|
|
|
|
}
|
2014-01-18 06:49:01 -05:00
|
|
|
scope->code[scope->clen].insn = tailpos ? OP_TAILCALL : OP_CALL;
|
|
|
|
scope->code[scope->clen].u.i = i;
|
|
|
|
scope->clen++;
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
|
|
|
|
2013-11-04 20:27:44 -05:00
|
|
|
static void
|
2013-11-16 23:12:59 -05:00
|
|
|
lift_cv(pic_state *pic, struct pic_irep *irep, int d)
|
2013-11-04 20:27:44 -05:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct pic_code c;
|
|
|
|
|
|
|
|
for (i = 0; i < irep->clen; ++i) {
|
|
|
|
c = irep->code[i];
|
|
|
|
switch (c.insn) {
|
|
|
|
default:
|
|
|
|
/* pass */
|
|
|
|
break;
|
|
|
|
case OP_LAMBDA:
|
2014-01-18 07:48:50 -05:00
|
|
|
if (irep->irep[c.u.i]->cv_num == 0)
|
|
|
|
lift_cv(pic, irep->irep[c.u.i], d);
|
2013-11-28 21:41:45 -05:00
|
|
|
else
|
2014-01-18 07:48:50 -05:00
|
|
|
lift_cv(pic, irep->irep[c.u.i], d + 1);
|
2013-11-04 20:27:44 -05:00
|
|
|
break;
|
|
|
|
case OP_CREF:
|
|
|
|
case OP_CSET:
|
2013-11-16 23:12:59 -05:00
|
|
|
if (irep->code[i].u.r.depth > d)
|
|
|
|
irep->code[i].u.r.depth--;
|
2013-11-04 20:27:44 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-04 20:23:06 -05:00
|
|
|
static void
|
|
|
|
slide_cv(pic_state *pic, unsigned *cv_tbl, unsigned cv_num, struct pic_irep *irep, int d)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
struct pic_code c;
|
|
|
|
|
|
|
|
for (i = 0; i < irep->clen; ++i) {
|
|
|
|
c = irep->code[i];
|
|
|
|
switch (c.insn) {
|
|
|
|
default:
|
|
|
|
/* pass */
|
|
|
|
break;
|
|
|
|
case OP_LAMBDA:
|
2014-01-18 07:48:50 -05:00
|
|
|
if (irep->irep[c.u.i]->cv_num == 0) {
|
|
|
|
slide_cv(pic, cv_tbl, cv_num, irep->irep[c.u.i], d);
|
2013-11-04 20:27:44 -05:00
|
|
|
}
|
|
|
|
else {
|
2014-01-18 07:48:50 -05:00
|
|
|
slide_cv(pic, cv_tbl, cv_num, irep->irep[c.u.i], d + 1);
|
2013-11-04 20:27:44 -05:00
|
|
|
}
|
2013-11-04 20:23:06 -05:00
|
|
|
break;
|
|
|
|
case OP_CREF:
|
|
|
|
case OP_CSET:
|
2013-11-04 21:32:09 -05:00
|
|
|
if (d != c.u.r.depth)
|
2013-11-04 20:23:06 -05:00
|
|
|
break;
|
|
|
|
for (j = 0; j < cv_num; ++j) {
|
2013-11-04 21:32:09 -05:00
|
|
|
if (c.u.r.idx == cv_tbl[j]) {
|
|
|
|
irep->code[i].u.r.idx = j;
|
2013-11-04 20:23:06 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-20 04:06:47 -04:00
|
|
|
static struct pic_irep *
|
2013-10-23 04:26:02 -04:00
|
|
|
codegen_lambda(codegen_state *state, pic_value obj)
|
2013-10-20 04:06:47 -04:00
|
|
|
{
|
2013-10-23 04:25:39 -04:00
|
|
|
pic_state *pic = state->pic;
|
2014-01-18 06:49:01 -05:00
|
|
|
struct pic_irep *irep;
|
2013-10-24 08:55:07 -04:00
|
|
|
pic_value args, body, v;
|
2013-11-04 20:23:06 -05:00
|
|
|
int i, c, k;
|
2013-10-23 04:25:39 -04:00
|
|
|
|
2013-10-24 08:55:07 -04:00
|
|
|
if (pic_length(pic, obj) < 2) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
args = pic_car(pic, pic_cdr(pic, obj));
|
|
|
|
if (! valid_formal(pic, args)) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
2013-10-23 04:25:39 -04:00
|
|
|
/* inner environment */
|
2013-10-24 08:55:07 -04:00
|
|
|
state->scope = new_local_scope(pic, args, state->scope);
|
2013-10-23 04:25:39 -04:00
|
|
|
{
|
|
|
|
/* body */
|
|
|
|
body = pic_cdr(pic, pic_cdr(pic, obj));
|
|
|
|
for (v = body; ! pic_nil_p(v); v = pic_cdr(pic, v)) {
|
2013-10-29 21:04:23 -04:00
|
|
|
if (pic_nil_p(pic_cdr(pic, v))) {
|
|
|
|
codegen(state, pic_car(pic, v), true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
codegen(state, pic_car(pic, v), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
state->scope->code[state->scope->clen].insn = OP_POP;
|
|
|
|
state->scope->clen++;
|
2013-10-29 21:04:23 -04:00
|
|
|
}
|
2013-10-23 04:25:39 -04:00
|
|
|
}
|
2014-01-18 06:49:01 -05:00
|
|
|
state->scope->code[state->scope->clen].insn = OP_RET;
|
|
|
|
state->scope->clen++;
|
2013-10-23 11:33:37 -04:00
|
|
|
|
2014-01-18 06:49:01 -05:00
|
|
|
/* create irep */
|
|
|
|
irep = new_irep(pic);
|
|
|
|
irep->varg = state->scope->varg;
|
|
|
|
irep->argc = state->scope->argc;
|
2013-11-13 04:08:22 -05:00
|
|
|
irep->localc = state->scope->localc;
|
2014-01-18 07:47:52 -05:00
|
|
|
irep->code = pic_realloc(pic, state->scope->code, sizeof(struct pic_code) * state->scope->clen);
|
2014-01-18 06:49:01 -05:00
|
|
|
irep->clen = state->scope->clen;
|
2014-01-18 07:48:50 -05:00
|
|
|
irep->irep = pic_realloc(pic, state->scope->irep, sizeof(struct pic_irep *) * state->scope->ilen);
|
|
|
|
irep->ilen = state->scope->ilen;
|
2014-01-18 08:32:41 -05:00
|
|
|
irep->pool = pic_realloc(pic, state->scope->pool, sizeof(pic_value) * state->scope->plen);
|
|
|
|
irep->plen = state->scope->plen;
|
2013-11-13 04:08:22 -05:00
|
|
|
|
2013-11-04 20:23:06 -05:00
|
|
|
/* fixup local references */
|
2013-10-23 13:51:02 -04:00
|
|
|
for (i = 0; i < irep->clen; ++i) {
|
|
|
|
struct pic_code c = irep->code[i];
|
2013-11-04 19:14:21 -05:00
|
|
|
switch (c.insn) {
|
|
|
|
default:
|
|
|
|
/* pass */
|
|
|
|
break;
|
|
|
|
case OP_CREF:
|
2013-11-04 21:32:09 -05:00
|
|
|
if (c.u.r.depth == 0 && ! state->scope->dirty_flags[c.u.r.idx]) {
|
2013-11-04 19:14:21 -05:00
|
|
|
irep->code[i].insn = OP_LREF;
|
2013-11-04 21:32:09 -05:00
|
|
|
irep->code[i].u.i = irep->code[i].u.r.idx;
|
2013-11-04 19:14:21 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OP_CSET:
|
2013-11-04 21:32:09 -05:00
|
|
|
if (c.u.r.depth == 0 && ! state->scope->dirty_flags[c.u.r.idx]) {
|
2013-11-04 19:14:21 -05:00
|
|
|
irep->code[i].insn = OP_LSET;
|
2013-11-04 21:32:09 -05:00
|
|
|
irep->code[i].u.i = irep->code[i].u.r.idx;
|
2013-11-04 19:14:21 -05:00
|
|
|
}
|
|
|
|
break;
|
2013-10-23 13:51:02 -04:00
|
|
|
}
|
2013-11-04 20:23:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* fixup closed variables */
|
|
|
|
c = 0;
|
|
|
|
for (i = 0; i < irep->argc + irep->localc; ++i) {
|
|
|
|
if (state->scope->dirty_flags[i])
|
|
|
|
++c;
|
|
|
|
}
|
2013-11-04 20:27:44 -05:00
|
|
|
if (c == 0) {
|
2013-11-16 23:12:59 -05:00
|
|
|
lift_cv(pic, irep, 0);
|
2013-11-04 20:27:44 -05:00
|
|
|
irep->cv_tbl = NULL;
|
|
|
|
irep->cv_num = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
irep->cv_tbl = (unsigned *)pic_calloc(pic, c, sizeof(unsigned));
|
|
|
|
k = 0;
|
|
|
|
for (i = 0; i < irep->argc + irep->localc; ++i) {
|
|
|
|
if (state->scope->dirty_flags[i]) {
|
|
|
|
irep->cv_tbl[k] = i;
|
|
|
|
++k;
|
|
|
|
}
|
2013-10-23 14:14:32 -04:00
|
|
|
}
|
2013-11-04 20:27:44 -05:00
|
|
|
irep->cv_num = c;
|
|
|
|
slide_cv(pic, irep->cv_tbl, irep->cv_num, irep, 0);
|
2013-10-23 11:33:37 -04:00
|
|
|
}
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
2013-10-23 04:25:39 -04:00
|
|
|
destroy_scope(pic, state->scope);
|
2013-10-22 09:22:35 -04:00
|
|
|
|
2014-01-18 06:49:01 -05:00
|
|
|
state->scope = state->scope->up;
|
2013-10-20 04:06:47 -04:00
|
|
|
|
|
|
|
#if VM_DEBUG
|
2013-11-16 09:32:34 -05:00
|
|
|
printf("* generated lambda:\n");
|
2014-01-18 02:23:12 -05:00
|
|
|
pic_dump_irep(pic, irep);
|
2013-10-20 04:06:47 -04:00
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return irep;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct pic_proc *
|
2013-10-22 09:22:35 -04:00
|
|
|
pic_codegen(pic_state *pic, pic_value obj)
|
2013-10-20 04:06:47 -04:00
|
|
|
{
|
|
|
|
struct pic_proc *proc;
|
2013-10-23 04:25:39 -04:00
|
|
|
codegen_state *state;
|
2014-01-18 06:49:01 -05:00
|
|
|
struct pic_irep *irep;
|
2013-11-14 05:25:03 -05:00
|
|
|
jmp_buf jmp, *prev_jmp = pic->jmp;
|
2013-11-15 05:54:47 -05:00
|
|
|
int ai = pic_gc_arena_preserve(pic);
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-23 04:25:39 -04:00
|
|
|
state = new_codegen_state(pic);
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-11-14 05:25:03 -05:00
|
|
|
if (setjmp(jmp) == 0) {
|
|
|
|
pic->jmp = &jmp;
|
2013-10-20 05:17:12 -04:00
|
|
|
}
|
2013-11-14 05:25:03 -05:00
|
|
|
else {
|
|
|
|
/* error occured */
|
|
|
|
proc = NULL;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2013-11-18 02:36:44 -05:00
|
|
|
codegen(state, pic_macroexpand(pic, obj), false);
|
2014-01-18 06:49:01 -05:00
|
|
|
state->scope->code[state->scope->clen].insn = OP_RET;
|
|
|
|
state->scope->clen++;
|
2013-10-28 04:45:13 -04:00
|
|
|
|
2014-01-18 06:49:01 -05:00
|
|
|
irep = new_irep(pic);
|
|
|
|
irep->varg = false;
|
|
|
|
irep->argc = 1;
|
|
|
|
irep->localc = 0;
|
2014-01-18 07:47:52 -05:00
|
|
|
irep->code = pic_realloc(pic, state->scope->code, sizeof(struct pic_code) * state->scope->clen);
|
2014-01-18 06:49:01 -05:00
|
|
|
irep->clen = state->scope->clen;
|
2014-01-18 07:48:50 -05:00
|
|
|
irep->irep = pic_realloc(pic, state->scope->irep, sizeof(struct pic_irep *) * state->scope->ilen);
|
|
|
|
irep->ilen = state->scope->ilen;
|
2014-01-18 08:32:41 -05:00
|
|
|
irep->pool = pic_realloc(pic, state->scope->pool, sizeof(pic_value) * state->scope->plen);
|
|
|
|
irep->plen = state->scope->plen;
|
2014-01-18 06:49:01 -05:00
|
|
|
irep->cv_num = 0;
|
|
|
|
irep->cv_tbl = NULL;
|
|
|
|
|
|
|
|
proc = pic_proc_new_irep(pic, irep, NULL);
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2013-10-23 04:25:39 -04:00
|
|
|
destroy_codegen_state(pic, state);
|
2013-10-22 09:22:35 -04:00
|
|
|
|
2013-10-20 04:06:47 -04:00
|
|
|
#if VM_DEBUG
|
2014-01-18 02:23:12 -05:00
|
|
|
pic_dump_irep(pic, proc->u.irep);
|
2013-10-20 04:06:47 -04:00
|
|
|
#endif
|
|
|
|
|
2013-11-14 05:25:03 -05:00
|
|
|
exit:
|
|
|
|
pic->jmp = prev_jmp;
|
|
|
|
|
2013-11-15 05:54:47 -05:00
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
pic_gc_protect(pic, pic_obj_value(proc));
|
|
|
|
|
2013-10-20 04:06:47 -04:00
|
|
|
return proc;
|
|
|
|
}
|
2013-10-23 02:52:14 -04:00
|
|
|
|
|
|
|
void
|
2014-01-12 10:45:49 -05:00
|
|
|
pic_define(pic_state *pic, const char *name, pic_value val)
|
2013-10-23 02:52:14 -04:00
|
|
|
{
|
|
|
|
int idx;
|
2014-01-12 02:09:19 -05:00
|
|
|
pic_sym gsym;
|
|
|
|
|
|
|
|
gsym = pic_gensym(pic, pic_intern_cstr(pic, name));
|
|
|
|
|
|
|
|
/* push to the global arena */
|
|
|
|
idx = scope_global_define(pic, pic_symbol_name(pic, gsym));
|
|
|
|
pic->globals[idx] = val;
|
2013-10-23 02:52:14 -04:00
|
|
|
|
2014-01-12 02:09:19 -05:00
|
|
|
/* register to the senv */
|
2014-01-12 10:45:49 -05:00
|
|
|
xh_put(pic->lib->senv->tbl, name, gsym);
|
2013-12-07 23:47:09 -05:00
|
|
|
|
2014-01-12 02:09:19 -05:00
|
|
|
/* export! */
|
2014-01-12 10:45:49 -05:00
|
|
|
pic_export(pic, pic_intern_cstr(pic, name));
|
2013-10-23 02:52:14 -04:00
|
|
|
}
|
|
|
|
|
2014-01-17 22:55:44 -05:00
|
|
|
static int
|
|
|
|
global_ref(pic_state *pic, const char *name)
|
2014-01-12 10:50:45 -05:00
|
|
|
{
|
|
|
|
struct xh_entry *e;
|
|
|
|
|
|
|
|
if (! (e = xh_get(pic->lib->senv->tbl, name))) {
|
|
|
|
pic_error(pic, "symbol not defined");
|
|
|
|
}
|
|
|
|
assert(e->val >= 0);
|
|
|
|
if (! (e = xh_get(pic->global_tbl, pic_symbol_name(pic, (pic_sym)e->val)))) {
|
|
|
|
pic_abort(pic, "logic flaw");
|
|
|
|
}
|
2014-01-17 22:55:44 -05:00
|
|
|
return e->val;
|
|
|
|
}
|
|
|
|
|
|
|
|
pic_value
|
|
|
|
pic_ref(pic_state *pic, const char *name)
|
|
|
|
{
|
|
|
|
int gid;
|
|
|
|
|
|
|
|
gid = global_ref(pic, name);
|
|
|
|
return pic->globals[gid];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pic_set(pic_state *pic, const char *name, pic_value value)
|
|
|
|
{
|
|
|
|
int gid;
|
|
|
|
|
|
|
|
gid = global_ref(pic, name);
|
|
|
|
pic->globals[gid] = value;
|
2014-01-12 10:50:45 -05:00
|
|
|
}
|
|
|
|
|
2013-10-30 03:43:15 -04:00
|
|
|
void
|
2013-12-10 04:47:45 -05:00
|
|
|
print_code(pic_state *pic, struct pic_code c)
|
2013-10-23 02:52:14 -04:00
|
|
|
{
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("[%2d] ", c.insn);
|
|
|
|
switch (c.insn) {
|
2013-10-23 02:52:14 -04:00
|
|
|
case OP_POP:
|
|
|
|
puts("OP_POP");
|
|
|
|
break;
|
|
|
|
case OP_PUSHNIL:
|
|
|
|
puts("OP_PUSHNIL");
|
|
|
|
break;
|
|
|
|
case OP_PUSHTRUE:
|
|
|
|
puts("OP_PUSHTRUE");
|
|
|
|
break;
|
|
|
|
case OP_PUSHFALSE:
|
|
|
|
puts("OP_PUSHFALSE");
|
|
|
|
break;
|
2013-10-27 11:21:24 -04:00
|
|
|
case OP_PUSHFLOAT:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_PUSHFLOAT\t%f\n", c.u.f);
|
2013-10-27 11:21:24 -04:00
|
|
|
break;
|
|
|
|
case OP_PUSHINT:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_PUSHINT\t%d\n", c.u.i);
|
2013-10-23 02:52:14 -04:00
|
|
|
break;
|
2013-11-04 21:37:18 -05:00
|
|
|
case OP_PUSHCHAR:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_PUSHCHAR\t%c\n", c.u.c);
|
2013-11-04 21:37:18 -05:00
|
|
|
break;
|
2013-10-23 02:52:14 -04:00
|
|
|
case OP_PUSHCONST:
|
2014-01-18 08:32:41 -05:00
|
|
|
printf("OP_PUSHCONST\t%d\n", c.u.i);
|
2013-10-23 02:52:14 -04:00
|
|
|
break;
|
|
|
|
case OP_GREF:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_GREF\t%i\n", c.u.i);
|
2013-10-23 02:52:14 -04:00
|
|
|
break;
|
|
|
|
case OP_GSET:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_GSET\t%i\n", c.u.i);
|
2013-10-23 02:52:14 -04:00
|
|
|
break;
|
|
|
|
case OP_LREF:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_LREF\t%d\n", c.u.i);
|
2013-10-23 02:52:14 -04:00
|
|
|
break;
|
2013-10-23 14:14:32 -04:00
|
|
|
case OP_LSET:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_LSET\t%d\n", c.u.i);
|
2013-10-23 14:14:32 -04:00
|
|
|
break;
|
2013-10-23 13:04:49 -04:00
|
|
|
case OP_CREF:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_CREF\t%d\t%d\n", c.u.r.depth, c.u.r.idx);
|
2013-10-23 13:04:49 -04:00
|
|
|
break;
|
2013-10-23 14:14:32 -04:00
|
|
|
case OP_CSET:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_CSET\t%d\t%d\n", c.u.r.depth, c.u.r.idx);
|
2013-10-23 14:14:32 -04:00
|
|
|
break;
|
2013-10-23 02:52:14 -04:00
|
|
|
case OP_JMP:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_JMP\t%d\n", c.u.i);
|
2013-10-23 02:52:14 -04:00
|
|
|
break;
|
|
|
|
case OP_JMPIF:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_JMPIF\t%d\n", c.u.i);
|
2013-10-23 02:52:14 -04:00
|
|
|
break;
|
|
|
|
case OP_CALL:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_CALL\t%d\n", c.u.i);
|
2013-10-23 02:52:14 -04:00
|
|
|
break;
|
2013-10-29 21:03:46 -04:00
|
|
|
case OP_TAILCALL:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_TAILCALL\t%d\n", c.u.i);
|
2013-10-29 21:03:46 -04:00
|
|
|
break;
|
2013-10-23 02:52:14 -04:00
|
|
|
case OP_RET:
|
|
|
|
puts("OP_RET");
|
|
|
|
break;
|
|
|
|
case OP_LAMBDA:
|
2013-12-10 04:47:45 -05:00
|
|
|
printf("OP_LAMBDA\t%d\n", c.u.i);
|
2013-10-23 02:52:14 -04:00
|
|
|
break;
|
|
|
|
case OP_CONS:
|
|
|
|
puts("OP_CONS");
|
|
|
|
break;
|
|
|
|
case OP_CAR:
|
|
|
|
puts("OP_CAR");
|
|
|
|
break;
|
|
|
|
case OP_NILP:
|
|
|
|
puts("OP_NILP");
|
|
|
|
break;
|
|
|
|
case OP_CDR:
|
|
|
|
puts("OP_CDR");
|
|
|
|
break;
|
|
|
|
case OP_ADD:
|
|
|
|
puts("OP_ADD");
|
|
|
|
break;
|
|
|
|
case OP_SUB:
|
|
|
|
puts("OP_SUB");
|
|
|
|
break;
|
|
|
|
case OP_MUL:
|
|
|
|
puts("OP_MUL");
|
|
|
|
break;
|
|
|
|
case OP_DIV:
|
|
|
|
puts("OP_DIV");
|
|
|
|
break;
|
2013-11-06 22:18:00 -05:00
|
|
|
case OP_MINUS:
|
|
|
|
puts("OP_MINUS");
|
|
|
|
break;
|
2013-10-24 08:10:13 -04:00
|
|
|
case OP_EQ:
|
|
|
|
puts("OP_EQ");
|
|
|
|
break;
|
|
|
|
case OP_LT:
|
|
|
|
puts("OP_LT");
|
|
|
|
break;
|
|
|
|
case OP_LE:
|
|
|
|
puts("OP_LE");
|
|
|
|
break;
|
2013-10-23 02:52:14 -04:00
|
|
|
case OP_STOP:
|
|
|
|
puts("OP_STOP");
|
|
|
|
break;
|
|
|
|
}
|
2013-12-10 04:47:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-01-18 02:23:12 -05:00
|
|
|
pic_dump_irep(pic_state *pic, struct pic_irep *irep)
|
2013-12-10 04:47:45 -05:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2014-01-05 04:10:33 -05:00
|
|
|
printf("## irep %p\n", (void *)irep);
|
2014-01-18 07:03:12 -05:00
|
|
|
printf("[clen = %zd, argc = %d, localc = %d]\n", irep->clen, irep->argc, irep->localc);
|
2013-12-10 04:47:45 -05:00
|
|
|
printf(":: cv_num = %d\n", irep->cv_num);
|
|
|
|
for (i = 0; i < irep->cv_num; ++i) {
|
|
|
|
printf(": %d -> %d\n", irep->cv_tbl[i], i);
|
|
|
|
}
|
|
|
|
for (i = 0; i < irep->clen; ++i) {
|
|
|
|
print_code(pic, irep->code[i]);
|
2013-10-23 02:52:14 -04:00
|
|
|
}
|
|
|
|
}
|