picrin/src/codegen.c

1623 lines
40 KiB
C
Raw Normal View History

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"
#include "picrin/lib.h"
#include "picrin/macro.h"
#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
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);
irep->code = NULL;
2014-01-18 03:19:46 -05:00
irep->clen = 0;
irep->argc = -1;
irep->localc = -1;
irep->varg = false;
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-23 04:56:42 -05:00
static pic_sym *
analyze_args(pic_state *pic, pic_value args, bool *varg, int *argc, int *localc)
2014-01-18 23:20:28 -05:00
{
2014-01-27 07:17:04 -05:00
pic_sym *syms = (pic_sym *)pic_alloc(pic, sizeof(pic_sym));
int i = 1, l = 0;
2014-01-20 02:57:39 -05:00
pic_value v;
*varg = false;
for (v = args; pic_pair_p(v); v = pic_cdr(pic, v)) {
pic_value sym;
2014-01-18 23:20:28 -05:00
2014-01-20 02:57:39 -05:00
sym = pic_car(pic, v);
2014-01-23 04:56:42 -05:00
if (! pic_symbol_p(sym)) {
pic_free(pic, syms);
return NULL;
}
2014-01-27 07:17:04 -05:00
syms = (pic_sym *)pic_realloc(pic, syms, sizeof(pic_sym) * (i + 1));
2014-01-23 04:56:42 -05:00
syms[i] = pic_sym(sym);
2014-01-20 02:57:39 -05:00
i++;
}
if (pic_nil_p(v)) {
/* pass */
}
else if (pic_symbol_p(v)) {
*varg = true;
2014-01-27 07:17:04 -05:00
syms = (pic_sym *)pic_realloc(pic, syms, sizeof(pic_sym) * (i + 1));
2014-01-23 04:56:42 -05:00
syms[i] = pic_sym(v);
2014-01-20 02:57:39 -05:00
l++;
2014-01-18 23:20:28 -05:00
}
2014-01-20 02:57:39 -05:00
else {
2014-01-23 04:56:42 -05:00
pic_free(pic, syms);
return NULL;
2014-01-20 02:57:39 -05:00
}
*argc = i;
*localc = l;
2014-01-23 04:56:42 -05:00
return syms;
2014-01-20 02:57:39 -05:00
}
2014-01-18 23:20:28 -05:00
2014-01-20 02:57:39 -05:00
static bool
valid_formal(pic_state *pic, pic_value formal)
{
bool varg;
int argc, localc;
2014-01-23 04:56:42 -05:00
pic_sym *syms;
2014-01-20 02:57:39 -05:00
2014-01-23 04:56:42 -05:00
syms = analyze_args(pic, formal, &varg, &argc, &localc);
if (syms == NULL) {
return false;
}
else {
pic_free(pic, syms);
return true;
}
2014-01-18 23:20:28 -05:00
}
typedef struct analyze_scope {
/* rest args variable is counted by localc */
2014-01-23 01:03:43 -05:00
bool varg;
int argc, localc;
2014-01-23 04:57:18 -05:00
/* if variable v is captured, then xh_get(var_tbl, v) == 1 */
struct xhash *var_tbl;
pic_sym *vars;
2014-01-18 23:20:28 -05:00
struct analyze_scope *up;
} analyze_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;
2014-01-27 07:20:12 -05:00
pic_sym sCALL, sTAILCALL, sREF;
2014-01-18 23:20:28 -05:00
} analyze_state;
2014-01-19 23:15:09 -05:00
static void push_scope(analyze_state *, pic_value);
static void pop_scope(analyze_state *);
2014-01-18 23:20:28 -05:00
#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;
2014-01-23 01:03:43 -05:00
struct xhash *global_tbl;
2014-01-20 02:57:39 -05:00
struct xh_iter it;
2014-01-18 23:20:28 -05:00
struct pic_lib *stdlib;
state = (analyze_state *)pic_alloc(pic, sizeof(analyze_state));
state->pic = pic;
2014-01-19 23:15:09 -05:00
state->scope = NULL;
2014-01-18 23:20:28 -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, ">=");
register_symbol(pic, state, sCALL, "call");
register_symbol(pic, state, sTAILCALL, "tail-call");
register_symbol(pic, state, sREF, "ref");
2014-01-18 23:20:28 -05:00
2014-01-19 23:15:09 -05:00
/* push initial scope */
push_scope(state, pic_nil_value());
2014-01-23 01:03:43 -05:00
global_tbl = pic->global_tbl;
for (it = xh_begin(global_tbl); ! xh_isend(&it); xh_next(global_tbl, &it)) {
2014-01-23 04:57:18 -05:00
xh_put(state->scope->var_tbl, it.e->key, 0);
2014-01-20 02:57:39 -05:00
}
2014-01-18 23:20:28 -05:00
return state;
}
2014-01-20 02:57:39 -05:00
static void
destroy_analyze_state(analyze_state *state)
{
pop_scope(state);
pic_free(state->pic, state);
}
2014-01-18 23:20:28 -05:00
static void
push_scope(analyze_state *state, pic_value args)
{
pic_state *pic = state->pic;
analyze_scope *scope;
2014-01-23 04:57:18 -05:00
int i;
2014-01-18 23:20:28 -05:00
scope = (analyze_scope *)pic_alloc(pic, sizeof(analyze_scope));
scope->up = state->scope;
2014-01-23 04:57:18 -05:00
scope->var_tbl = xh_new();
2014-01-18 23:20:28 -05:00
scope->varg = false;
2014-01-23 04:57:18 -05:00
scope->vars = analyze_args(pic, args, &scope->varg, &scope->argc, &scope->localc);
2014-01-18 23:20:28 -05:00
2014-01-23 04:57:18 -05:00
if (scope->vars == NULL) {
2014-01-18 23:20:28 -05:00
pic_error(pic, "logic flaw");
}
2014-01-19 23:04:21 -05:00
2014-01-23 04:57:18 -05:00
for (i = 1; i < scope->argc + scope->localc; ++i) {
xh_put(scope->var_tbl, pic_symbol_name(pic, scope->vars[i]), 0);
2014-01-19 23:04:21 -05:00
}
2014-01-19 01:36:02 -05:00
state->scope = scope;
2014-01-18 23:20:28 -05:00
}
static void
pop_scope(analyze_state *state)
{
analyze_scope *scope;
scope = state->scope;
2014-01-30 00:33:16 -05:00
xh_destroy(scope->var_tbl);
2014-01-23 04:57:18 -05:00
pic_free(state->pic, scope->vars);
2014-01-18 23:20:28 -05:00
scope = scope->up;
pic_free(state->pic, state->scope);
state->scope = scope;
}
2014-01-19 23:04:21 -05:00
static int
2014-01-23 04:57:18 -05:00
lookup_var(analyze_state *state, pic_sym sym)
2014-01-18 23:20:28 -05:00
{
analyze_scope *scope = state->scope;
struct xh_entry *e;
2014-01-19 23:04:21 -05:00
int depth = 0;
2014-01-23 04:57:18 -05:00
const char *key = pic_symbol_name(state->pic, sym);
2014-01-18 23:20:28 -05:00
enter:
2014-01-23 04:57:18 -05:00
e = xh_get(scope->var_tbl, key);
if (e) {
2014-01-19 23:04:21 -05:00
if (depth > 0) { /* mark dirty */
2014-01-23 04:57:18 -05:00
xh_put(scope->var_tbl, key, 1);
2014-01-18 23:20:28 -05:00
}
2014-01-19 23:04:21 -05:00
return depth;
2014-01-18 23:20:28 -05:00
}
if (scope->up) {
scope = scope->up;
2014-01-19 23:04:21 -05:00
++depth;
2014-01-18 23:20:28 -05:00
goto enter;
}
2014-01-19 23:04:21 -05:00
return -1;
2014-01-18 23:20:28 -05:00
}
2014-01-19 23:04:21 -05:00
static void
2014-01-23 04:57:18 -05:00
define_var(analyze_state *state, pic_sym sym)
2014-01-18 23:20:28 -05:00
{
2014-01-23 04:57:18 -05:00
pic_state *pic = state->pic;
2014-01-19 23:04:21 -05:00
analyze_scope *scope = state->scope;
2014-01-23 04:57:18 -05:00
const char *name = pic_symbol_name(pic, sym);
2014-01-18 23:20:28 -05:00
2014-01-23 04:57:18 -05:00
xh_put(state->scope->var_tbl, name, 0);
2014-01-18 23:20:28 -05:00
2014-01-23 04:57:18 -05:00
scope->localc++;
2014-01-27 07:17:04 -05:00
scope->vars = (pic_sym *)pic_realloc(pic, scope->vars, sizeof(pic_sym) * (scope->argc + scope->localc));
2014-01-23 04:57:18 -05:00
scope->vars[scope->argc + scope->localc - 1] = sym;
2014-01-18 23:20:28 -05:00
}
static pic_value
new_ref(analyze_state *state, int depth, pic_sym sym)
2014-01-18 23:20:28 -05:00
{
2014-01-19 23:04:21 -05:00
return pic_list(state->pic, 3,
pic_symbol_value(state->sREF),
2014-01-19 23:04:21 -05:00
pic_int_value(depth),
pic_symbol_value(sym));
2014-01-18 23:20:28 -05:00
}
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;
switch (pic_type(obj)) {
case PIC_TT_SYMBOL: {
2014-01-23 04:57:18 -05:00
pic_sym sym = pic_sym(obj);
2014-01-19 23:04:21 -05:00
int depth;
2014-01-18 23:20:28 -05:00
2014-01-23 04:57:18 -05:00
depth = lookup_var(state, sym);
2014-01-19 23:04:21 -05:00
if (depth == -1) {
2014-01-18 23:20:28 -05:00
pic_error(pic, "symbol: unbound variable");
}
2014-01-19 23:04:21 -05:00
/* at this stage, lref/cref/gref are not distinguished */
2014-01-23 04:57:18 -05:00
return new_ref(state, depth, sym);
2014-01-18 23:20:28 -05:00
}
case PIC_TT_PAIR: {
pic_value proc;
if (! pic_list_p(pic, obj)) {
pic_error(pic, "invalid expression given");
}
proc = pic_list_ref(pic, obj, 0);
2014-01-18 23:20:28 -05:00
if (pic_symbol_p(proc)) {
pic_sym sym = pic_sym(proc);
if (sym == pic->sDEFINE) {
pic_value var, val;
if (pic_length(pic, obj) < 2) {
pic_error(pic, "syntax error");
}
var = pic_list_ref(pic, obj, 1);
2014-01-18 23:20:28 -05:00
if (pic_pair_p(var)) {
val = pic_cons(pic, pic_symbol_value(pic->sLAMBDA),
pic_cons(pic, pic_list_tail(pic, var, 1),
pic_list_tail(pic, obj, 2)));
var = pic_list_ref(pic, var, 0);
2014-01-18 23:20:28 -05:00
}
else {
if (pic_length(pic, obj) != 3) {
pic_error(pic, "syntax error");
}
val = pic_list_ref(pic, obj, 2);
2014-01-18 23:20:28 -05:00
}
if (! pic_symbol_p(var)) {
pic_error(pic, "syntax error");
}
2014-01-23 04:57:18 -05:00
define_var(state, pic_sym(var));
2014-01-19 23:04:21 -05:00
return pic_list(pic, 3,
pic_symbol_value(pic->sSETBANG),
analyze(state, var, false),
analyze(state, val, false));
2014-01-18 23:20:28 -05:00
}
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_list_ref(pic, obj, 3);
2014-01-18 23:20:28 -05:00
FALLTHROUGH;
case 3:
if_true = pic_list_ref(pic, obj, 2);
2014-01-18 23:20:28 -05:00
}
return pic_list(pic, 4,
pic_symbol_value(pic->sIF),
analyze(state, pic_list_ref(pic, obj, 1), false),
2014-01-18 23:20:28 -05:00
analyze(state, if_true, tailpos),
analyze(state, if_false, tailpos));
}
else if (sym == pic->sBEGIN) {
pic_value seq;
bool tail;
switch (pic_length(pic, obj)) {
case 1:
return analyze(state, pic_none_value(), tailpos);
case 2:
return analyze(state, pic_list_ref(pic, obj, 1), tailpos);
default:
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);
2014-01-18 23:20:28 -05:00
}
return pic_reverse(pic, seq);
2014-01-18 23:20:28 -05:00
}
}
else if (sym == pic->sSETBANG) {
pic_value var, val;
if (pic_length(pic, obj) != 3) {
pic_error(pic, "syntax error");
}
var = pic_list_ref(pic, obj, 1);
2014-01-18 23:20:28 -05:00
if (! pic_symbol_p(var)) {
pic_error(pic, "syntax error");
}
val = pic_list_ref(pic, obj, 2);
2014-01-18 23:20:28 -05:00
2014-01-19 23:04:21 -05:00
return pic_list(pic, 3,
pic_symbol_value(pic->sSETBANG),
analyze(state, var, false),
analyze(state, val, false));
2014-01-18 23:20:28 -05:00
}
else if (sym == pic->sQUOTE) {
if (pic_length(pic, obj) != 2) {
pic_error(pic, "syntax error");
}
2014-01-23 05:21:37 -05:00
return obj;
2014-01-18 23:20:28 -05:00
}
#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_list_ref(pic, obj, 1), false))
2014-01-18 23:20:28 -05:00
#define CONSTRUCT_OP2(op) \
pic_list(pic, 3, \
pic_symbol_value(op), \
analyze(state, pic_list_ref(pic, obj, 1), false), \
analyze(state, pic_list_ref(pic, obj, 2), false))
2014-01-18 23:20:28 -05:00
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); \
2014-01-27 08:20:31 -05:00
for (args = pic_cdr(pic, args); ! pic_nil_p(args); args = pic_cdr(pic, args)) { \
2014-01-18 23:20:28 -05:00
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:
2014-01-23 05:21:37 -05:00
case PIC_TT_CHAR:
2014-01-18 23:20:28 -05:00
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) {
2014-01-18 23:20:28 -05:00
call = state->sCALL;
} else {
call = state->sTAILCALL;
}
seq = pic_list(pic, 1, pic_symbol_value(call));
2014-01-19 01:36:02 -05:00
for (; ! pic_nil_p(obj); obj = pic_cdr(pic, obj)) {
2014-01-18 23:20:28 -05:00
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-27 07:20:00 -05:00
pic_value args, body, locals, varg, closes;
2014-01-18 23:20:28 -05:00
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");
}
push_scope(state, args);
{
2014-01-23 04:57:18 -05:00
analyze_scope *scope = state->scope;
int i;
2014-01-19 23:04:21 -05:00
/* analyze body in inner environment */
2014-01-18 23:20:28 -05:00
body = pic_cdr(pic, pic_cdr(pic, obj));
body = pic_cons(pic, pic_symbol_value(pic->sBEGIN), body);
body = analyze(state, body, true);
2014-01-19 23:04:21 -05:00
2014-01-27 07:20:00 -05:00
args = pic_nil_value();
for (i = 1; i < scope->argc; ++i) {
args = pic_cons(pic, pic_symbol_value(scope->vars[i]), args);
2014-01-23 04:57:18 -05:00
}
2014-01-27 07:20:00 -05:00
args = pic_reverse(pic, args);
locals = pic_nil_value();
for (i = 0; i < scope->localc; ++i) {
locals = pic_cons(pic, pic_symbol_value(scope->vars[scope->argc + i]), locals);
}
locals = pic_reverse(pic, locals);
varg = scope->varg ? pic_true_value() : pic_false_value();
closes = pic_nil_value();
2014-01-23 04:57:18 -05:00
for (i = 1; i < scope->argc + scope->localc; ++i) {
pic_sym var = scope->vars[i];
if (xh_get(scope->var_tbl, pic_symbol_name(pic, var))) {
2014-01-27 07:20:00 -05:00
closes = pic_cons(pic, pic_symbol_value(var), closes);
2014-01-19 23:04:21 -05:00
}
}
2014-01-27 07:20:00 -05:00
closes = pic_reverse(pic, closes);
2014-01-18 23:20:28 -05:00
}
pop_scope(state);
2014-01-27 07:20:00 -05:00
obj = pic_list(pic, 6, pic_symbol_value(pic->sLAMBDA), args, locals, varg, closes, body);
2014-01-19 01:35:36 -05:00
pic_gc_arena_restore(pic, ai);
pic_gc_protect(pic, obj);
return obj;
2014-01-18 23:20:28 -05:00
}
2014-01-20 02:57:39 -05:00
pic_value
pic_analyze(pic_state *pic, pic_value obj)
{
analyze_state *state;
state = new_analyze_state(pic);
obj = analyze(state, obj, false);
destroy_analyze_state(state);
return obj;
}
2014-01-24 03:11:37 -05:00
typedef struct resolver_scope {
int depth;
bool varg;
int argc, localc;
2014-01-24 03:11:37 -05:00
struct xhash *cvs, *lvs;
unsigned cv_num;
struct resolver_scope *up;
} resolver_scope;
typedef struct resolver_state {
pic_state *pic;
resolver_scope *scope;
2014-01-27 07:20:12 -05:00
pic_sym sREF;
2014-01-24 03:11:37 -05:00
pic_sym sGREF, sCREF, sLREF;
} resolver_state;
2014-01-27 07:20:00 -05:00
static void push_resolver_scope(resolver_state *, pic_value, pic_value, bool, pic_value);
2014-01-24 03:11:37 -05:00
static void pop_resolver_scope(resolver_state *);
static resolver_state *
new_resolver_state(pic_state *pic)
{
resolver_state *state;
state = (resolver_state *)pic_alloc(pic, sizeof(resolver_state));
state->pic = pic;
state->scope = NULL;
register_symbol(pic, state, sREF, "ref");
register_symbol(pic, state, sGREF, "gref");
register_symbol(pic, state, sLREF, "lref");
register_symbol(pic, state, sCREF, "cref");
2014-01-27 07:20:00 -05:00
push_resolver_scope(state, pic_nil_value(), pic_nil_value(), false, pic_nil_value());
2014-01-24 03:11:37 -05:00
return state;
}
static void
destroy_resolver_state(resolver_state *state)
{
2014-01-27 07:18:03 -05:00
pop_resolver_scope(state);
pic_free(state->pic, state);
2014-01-24 03:11:37 -05:00
}
static void
2014-01-27 07:20:00 -05:00
push_resolver_scope(resolver_state *state, pic_value args, pic_value locals, bool varg, pic_value closes)
2014-01-24 03:11:37 -05:00
{
pic_state *pic = state->pic;
resolver_scope *scope;
2014-01-27 07:20:00 -05:00
int i, c;
2014-01-24 03:11:37 -05:00
scope = (resolver_scope *)pic_alloc(pic, sizeof(resolver_scope));
scope->up = state->scope;
scope->depth = scope->up ? scope->up->depth + 1 : 0;
scope->lvs = xh_new();
scope->cvs = xh_new();
2014-01-27 07:20:00 -05:00
scope->argc = pic_length(pic, args) + 1;
scope->localc = pic_length(pic, locals);
scope->varg = varg;
2014-01-24 03:11:37 -05:00
2014-01-27 07:20:00 -05:00
/* arguments */
for (i = 1; i < scope->argc; ++i) {
xh_put(scope->lvs, pic_symbol_name(pic, pic_sym(pic_list_ref(pic, args, i - 1))), i);
2014-01-24 03:11:37 -05:00
}
2014-01-27 07:20:00 -05:00
/* locals */
for (i = 0; i < scope->localc; ++i) {
xh_put(scope->lvs, pic_symbol_name(pic, pic_sym(pic_list_ref(pic, locals, i))), scope->argc + i);
2014-01-24 03:11:37 -05:00
}
/* closed variables */
scope->cv_num = 0;
2014-01-27 07:20:00 -05:00
for (i = 0, c = pic_length(pic, closes); i < c; ++i) {
xh_put(scope->cvs, pic_symbol_name(pic, pic_sym(pic_list_ref(pic, closes, i))), scope->cv_num++);
2014-01-24 03:11:37 -05:00
}
state->scope = scope;
}
static void
pop_resolver_scope(resolver_state *state)
{
2014-01-27 07:18:03 -05:00
resolver_scope *scope;
scope = state->scope;
2014-01-30 00:33:16 -05:00
xh_destroy(scope->cvs);
xh_destroy(scope->lvs);
2014-01-27 07:18:03 -05:00
scope = scope->up;
pic_free(state->pic, state->scope);
state->scope = scope;
2014-01-24 03:11:37 -05:00
}
static bool
is_closed(resolver_state *state, pic_sym sym)
2014-01-24 03:11:37 -05:00
{
return xh_get(state->scope->cvs, pic_symbol_name(state->pic, sym)) != NULL;
2014-01-24 03:11:37 -05:00
}
static pic_value
resolve_gref(resolver_state *state, pic_sym sym)
{
pic_state *pic = state->pic;
const char *name = pic_symbol_name(pic, sym);
struct xh_entry *e;
size_t i;
2014-01-24 03:11:37 -05:00
if ((e = xh_get(pic->global_tbl, name))) {
i = e->val;
}
else {
i = pic->glen++;
if (i >= pic->gcapa) {
pic_error(pic, "global table overflow");
}
xh_put(pic->global_tbl, name, i);
}
return pic_list(pic, 2, pic_symbol_value(state->sGREF), pic_int_value(i));
}
static pic_value
resolve_lref(resolver_state *state, pic_sym sym)
{
pic_state *pic = state->pic;
int i;
i = xh_get(state->scope->lvs, pic_symbol_name(pic, sym))->val;
return pic_list(pic, 2, pic_symbol_value(state->sLREF), pic_int_value(i));
}
static pic_value
resolve_cref(resolver_state *state, int depth, pic_sym sym)
{
pic_state *pic = state->pic;
resolver_scope *scope = state->scope;
int i, d;
d = depth;
while (d-- > 0) {
scope = scope->up;
}
i = xh_get(scope->cvs, pic_symbol_name(pic, sym))->val;
return pic_list(pic, 3,
pic_symbol_value(state->sCREF),
pic_int_value(depth),
pic_int_value(i));
}
2014-01-27 07:17:24 -05:00
static pic_value resolve_reference_node(resolver_state *state, pic_value obj);
2014-01-24 03:11:37 -05:00
static pic_value
resolve_reference(resolver_state *state, pic_value obj)
2014-01-27 07:17:24 -05:00
{
int ai = pic_gc_arena_preserve(state->pic);
obj = resolve_reference_node(state, obj);
pic_gc_arena_restore(state->pic, ai);
pic_gc_protect(state->pic, obj);
return obj;
}
static pic_value
resolve_reference_node(resolver_state *state, pic_value obj)
2014-01-24 03:11:37 -05:00
{
pic_state *pic = state->pic;
resolver_scope *scope = state->scope;
pic_sym tag;
if (! pic_pair_p(obj))
return obj;
tag = pic_sym(pic_car(pic, obj));
if (tag == state->sREF) {
int depth;
pic_sym sym;
depth = pic_int(pic_list_ref(pic, obj, 1));
sym = pic_sym(pic_list_ref(pic, obj, 2));
if (depth == scope->depth) {
return resolve_gref(state, sym);
}
else if (depth == 0 && is_closed(state, sym)) {
2014-01-24 03:11:37 -05:00
return resolve_lref(state, sym);
}
else {
return resolve_cref(state, depth, sym);
}
}
else if (tag == pic->sLAMBDA) {
2014-01-27 07:20:00 -05:00
pic_value args, locals, closes, body;
bool varg;
2014-01-24 03:11:37 -05:00
args = pic_list_ref(pic, obj, 1);
2014-01-27 07:20:00 -05:00
locals = pic_list_ref(pic, obj, 2);
varg = pic_true_p(pic_list_ref(pic, obj, 3));
closes = pic_list_ref(pic, obj, 4);
body = pic_list_ref(pic, obj, 5);
2014-01-24 03:11:37 -05:00
2014-01-27 07:20:00 -05:00
push_resolver_scope(state, args, locals, varg, closes);
2014-01-24 03:11:37 -05:00
{
body = resolve_reference(state, body);
}
pop_resolver_scope(state);
2014-01-27 07:20:00 -05:00
return pic_list(pic, 6, pic_symbol_value(pic->sLAMBDA), args, locals, pic_bool_value(varg), closes, body);
2014-01-24 03:11:37 -05:00
}
else if (tag == pic->sQUOTE) {
return obj;
}
else {
2014-01-27 08:20:18 -05:00
int ai = pic_gc_arena_preserve(pic);
2014-01-24 03:11:37 -05:00
pic_value seq = pic_list(pic, 1, pic_symbol_value(tag));
for (obj = pic_cdr(pic, obj); ! pic_nil_p(obj); obj = pic_cdr(pic, obj)) {
seq = pic_cons(pic, resolve_reference(state, pic_car(pic, obj)), seq);
2014-01-27 08:20:18 -05:00
pic_gc_arena_restore(pic, ai);
pic_gc_protect(pic, obj);
pic_gc_protect(pic, seq);
2014-01-24 03:11:37 -05:00
}
return pic_reverse(pic, seq);
}
}
static pic_value
pic_resolve(pic_state *pic, pic_value obj)
{
resolver_state *state;
state = new_resolver_state(pic);
obj = resolve_reference(state, obj);
destroy_resolver_state(state);
return obj;
}
2014-01-18 03:19:46 -05:00
/**
* scope object
*/
2014-01-20 02:57:39 -05:00
typedef struct codegen_context {
bool varg;
2014-01-18 08:32:41 -05:00
/* rest args variable is counted by localc */
int argc, localc;
/* closed variable table */
unsigned *cv_tbl, cv_num;
/* actual bit code sequence */
struct pic_code *code;
size_t clen, ccapa;
/* 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-20 02:57:39 -05:00
struct codegen_context *up;
} codegen_context;
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;
2014-01-20 02:57:39 -05:00
codegen_context *cxt;
pic_sym sGREF, sCREF, sLREF;
pic_sym sCALL, sTAILCALL;
unsigned *cv_tbl, cv_num;
2013-10-23 04:25:39 -04:00
} codegen_state;
2014-01-27 07:20:00 -05:00
static void push_codegen_context(codegen_state *, pic_value, pic_value, bool, pic_value);
2014-01-20 02:57:39 -05:00
static struct pic_irep *pop_codegen_context(codegen_state *);
2013-10-23 04:25:39 -04:00
static codegen_state *
new_codegen_state(pic_state *pic)
{
codegen_state *state;
state = (codegen_state *)pic_alloc(pic, sizeof(codegen_state));
state->pic = pic;
2014-01-20 02:57:39 -05:00
state->cxt = NULL;
2013-10-23 04:25:39 -04:00
2014-01-20 02:57:39 -05:00
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");
2014-01-27 07:20:00 -05:00
push_codegen_context(state, pic_nil_value(), pic_nil_value(), false, pic_nil_value());
2013-10-23 04:25:39 -04:00
return state;
}
2014-01-20 02:57:39 -05:00
static struct pic_irep *
destroy_codegen_state(codegen_state *state)
2013-10-23 04:25:39 -04:00
{
2014-01-20 02:57:39 -05:00
pic_state *pic = state->pic;
struct pic_irep *irep;
irep = pop_codegen_context(state);
2013-10-23 04:25:39 -04:00
pic_free(pic, state);
2014-01-20 02:57:39 -05:00
return irep;
2013-10-23 04:25:39 -04:00
}
2014-01-20 02:57:39 -05:00
static void
2014-01-27 07:20:00 -05:00
push_codegen_context(codegen_state *state, pic_value args, pic_value locals, bool varg, pic_value closes)
{
2014-01-20 02:57:39 -05:00
pic_state *pic = state->pic;
codegen_context *cxt;
2014-01-27 07:20:00 -05:00
int i, c;
struct xhash *vars;
2013-10-20 04:06:47 -04:00
2014-01-20 02:57:39 -05:00
cxt = (codegen_context *)pic_alloc(pic, sizeof(codegen_context));
cxt->up = state->cxt;
2014-01-27 07:20:00 -05:00
cxt->argc = pic_length(pic, args) + 1;
cxt->localc = pic_length(pic, locals);
cxt->varg = varg;
/* number local variables */
vars = xh_new();
for (i = 1; i < cxt->argc; ++i) {
xh_put(vars, pic_symbol_name(pic, pic_sym(pic_list_ref(pic, args, i - 1))), i);
}
for (i = 0; i < cxt->localc; ++i) {
xh_put(vars, pic_symbol_name(pic, pic_sym(pic_list_ref(pic, locals, i))), cxt->argc + i);
2013-10-20 04:06:47 -04:00
}
2014-01-20 02:57:39 -05:00
2014-01-27 07:20:00 -05:00
/* closed variables */
cxt->cv_tbl = NULL;
cxt->cv_num = 0;
2014-01-27 07:20:00 -05:00
for (i = 0, c = pic_length(pic, closes); i < c; ++i) {
i = cxt->cv_num++;
cxt->cv_tbl = (unsigned *)pic_realloc(pic, cxt->cv_tbl, sizeof(unsigned) * cxt->cv_num);
cxt->cv_tbl[i] = xh_get(vars, pic_symbol_name(pic, pic_sym(pic_list_ref(pic, closes, i))))->val;
}
2014-01-30 00:33:16 -05:00
xh_destroy(vars);
2014-01-20 02:57:39 -05:00
cxt->code = (struct pic_code *)pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(struct pic_code));
cxt->clen = 0;
cxt->ccapa = PIC_ISEQ_SIZE;
cxt->irep = (struct pic_irep **)pic_calloc(pic, PIC_IREP_SIZE, sizeof(struct pic_irep *));
cxt->ilen = 0;
cxt->icapa = PIC_IREP_SIZE;
cxt->pool = (pic_value *)pic_calloc(pic, PIC_POOL_SIZE, sizeof(pic_value));
cxt->plen = 0;
cxt->pcapa = PIC_POOL_SIZE;
state->cxt = cxt;
}
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 = new_irep(pic);
irep->varg = state->cxt->varg;
irep->argc = state->cxt->argc;
irep->localc = state->cxt->localc;
irep->cv_tbl = state->cxt->cv_tbl;
irep->cv_num = state->cxt->cv_num;
2014-01-20 02:57:39 -05:00
irep->code = pic_realloc(pic, state->cxt->code, sizeof(struct 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;
/* destroy context */
cxt = cxt->up;
pic_free(pic, state->cxt);
state->cxt = cxt;
return irep;
2013-10-20 04:06:47 -04:00
}
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
2014-01-20 02:57:39 -05:00
codegen(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-20 02:57:39 -05:00
codegen_context *cxt = state->cxt;
pic_sym sym;
2013-10-20 04:06:47 -04:00
2014-01-23 05:21:37 -05:00
sym = pic_sym(pic_car(pic, obj));
2014-01-20 02:57:39 -05:00
if (sym == state->sGREF) {
cxt->code[cxt->clen].insn = OP_GREF;
cxt->code[cxt->clen].u.i = pic_int(pic_list_ref(pic, obj, 1));
cxt->clen++;
return;
} else if (sym == state->sCREF) {
cxt->code[cxt->clen].insn = OP_CREF;
cxt->code[cxt->clen].u.r.depth = pic_int(pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].u.r.idx = pic_int(pic_list_ref(pic, obj, 2));
cxt->clen++;
return;
2014-01-24 03:09:51 -05:00
} else if (sym == state->sLREF) {
2014-01-20 02:57:39 -05:00
cxt->code[cxt->clen].insn = OP_LREF;
cxt->code[cxt->clen].u.i = pic_int(pic_list_ref(pic, obj, 1));
cxt->clen++;
return;
} else if (sym == pic->sSETBANG) {
pic_value var, val;
pic_sym type;
val = pic_list_ref(pic, obj, 2);
2014-01-20 02:57:39 -05:00
codegen(state, val);
var = pic_list_ref(pic, obj, 1);
2014-01-24 03:11:15 -05:00
type = pic_sym(pic_list_ref(pic, var, 0));
2014-01-20 02:57:39 -05:00
if (type == state->sGREF) {
cxt->code[cxt->clen].insn = OP_GSET;
cxt->code[cxt->clen].u.i = pic_int(pic_list_ref(pic, var, 1));
cxt->clen++;
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
return;
}
else if (type == state->sCREF) {
cxt->code[cxt->clen].insn = OP_CSET;
cxt->code[cxt->clen].u.r.depth = pic_int(pic_list_ref(pic, var, 1));
cxt->code[cxt->clen].u.r.idx = pic_int(pic_list_ref(pic, var, 2));
cxt->clen++;
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
return;
}
else if (type == state->sLREF) {
2014-01-27 08:20:08 -05:00
cxt->code[cxt->clen].insn = OP_LSET;
2014-01-20 02:57:39 -05:00
cxt->code[cxt->clen].u.i = pic_int(pic_list_ref(pic, var, 1));
cxt->clen++;
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
return;
}
}
else if (sym == pic->sLAMBDA) {
int k;
2013-11-06 04:55:06 -05:00
2014-01-20 02:57:39 -05:00
if (cxt->ilen >= cxt->icapa) {
cxt->icapa *= 2;
cxt->irep = (struct pic_irep **)pic_realloc(pic, cxt->irep, sizeof(struct pic_irep *) * cxt->icapa);
}
k = cxt->ilen++;
cxt->code[cxt->clen].insn = OP_LAMBDA;
cxt->code[cxt->clen].u.i = k;
cxt->clen++;
2013-11-06 04:55:06 -05:00
2014-01-20 02:57:39 -05:00
cxt->irep[k] = codegen_lambda(state, obj);
return;
}
else if (sym == pic->sIF) {
int s, t;
2013-11-06 04:55:06 -05:00
2014-01-20 02:57:39 -05:00
codegen(state, pic_list_ref(pic, obj, 1));
2013-11-06 22:18:00 -05:00
2014-01-20 02:57:39 -05:00
cxt->code[cxt->clen].insn = OP_JMPIF;
s = cxt->clen++;
2013-11-06 22:52:59 -05:00
2014-01-20 02:57:39 -05:00
/* if false branch */
codegen(state, pic_list_ref(pic, obj, 3));
cxt->code[cxt->clen].insn = OP_JMP;
t = cxt->clen++;
2013-11-06 22:52:59 -05:00
2014-01-20 02:57:39 -05:00
cxt->code[s].u.i = cxt->clen - s;
2014-01-20 02:57:39 -05:00
/* if true branch */
codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[t].u.i = cxt->clen - t;
return;
2013-10-20 04:06:47 -04:00
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sBEGIN) {
for (obj = pic_cdr(pic, obj); ! pic_nil_p(obj); obj = pic_cdr(pic, obj)) {
codegen(state, pic_car(pic, obj));
2013-10-20 04:06:47 -04:00
}
2014-01-20 02:57:39 -05:00
return;
}
else if (sym == pic->sQUOTE) {
int pidx;
2014-01-23 05:21:37 -05:00
obj = pic_list_ref(pic, obj, 1);
switch (pic_type(obj)) {
case PIC_TT_BOOL:
if (pic_true_p(obj)) {
cxt->code[cxt->clen].insn = OP_PUSHTRUE;
} else {
cxt->code[cxt->clen].insn = OP_PUSHFALSE;
}
cxt->clen++;
return;
case PIC_TT_FLOAT:
cxt->code[cxt->clen].insn = OP_PUSHFLOAT;
cxt->code[cxt->clen].u.f = pic_float(obj);
cxt->clen++;
return;
case PIC_TT_INT:
cxt->code[cxt->clen].insn = OP_PUSHINT;
cxt->code[cxt->clen].u.i = pic_int(obj);
cxt->clen++;
return;
case PIC_TT_NIL:
cxt->code[cxt->clen].insn = OP_PUSHNIL;
cxt->clen++;
return;
case PIC_TT_CHAR:
cxt->code[cxt->clen].insn = OP_PUSHCHAR;
cxt->code[cxt->clen].u.c = pic_char(obj);
cxt->clen++;
return;
default:
if (cxt->plen >= cxt->pcapa) {
cxt->pcapa *= 2;
cxt->pool = (pic_value *)pic_realloc(pic, cxt->pool, sizeof(pic_value) * cxt->pcapa);
}
pidx = cxt->plen++;
cxt->pool[pidx] = obj;
cxt->code[cxt->clen].insn = OP_PUSHCONST;
cxt->code[cxt->clen].u.i = pidx;
cxt->clen++;
return;
2013-10-20 04:06:47 -04:00
}
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sCONS) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_CONS;
cxt->clen++;
return;
2013-10-20 04:06:47 -04:00
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sCAR) {
codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_CAR;
cxt->clen++;
return;
2013-10-27 11:21:24 -04:00
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sCDR) {
codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_CDR;
cxt->clen++;
return;
2013-10-20 04:06:47 -04:00
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sNILP) {
codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_NILP;
cxt->clen++;
return;
2013-11-04 21:37:18 -05:00
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sADD) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_ADD;
cxt->clen++;
return;
2013-10-20 21:48:03 -04:00
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sSUB) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_SUB;
cxt->clen++;
return;
2013-10-20 04:06:47 -04:00
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sMUL) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_MUL;
cxt->clen++;
return;
2013-10-20 04:06:47 -04:00
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sDIV) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_DIV;
cxt->clen++;
return;
}
2014-01-20 02:57:39 -05:00
else if (sym == pic->sMINUS) {
codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_MINUS;
cxt->clen++;
return;
}
else if (sym == pic->sEQ) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_EQ;
cxt->clen++;
2014-01-24 03:09:51 -05:00
return;
2014-01-20 02:57:39 -05:00
}
else if (sym == pic->sLT) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_LT;
cxt->clen++;
2014-01-24 03:09:51 -05:00
return;
2014-01-20 02:57:39 -05:00
}
else if (sym == pic->sLE) {
codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_LE;
cxt->clen++;
2014-01-24 03:09:51 -05:00
return;
2014-01-20 02:57:39 -05:00
}
else if (sym == pic->sGT) {
codegen(state, pic_list_ref(pic, obj, 2));
codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_LT;
cxt->clen++;
2014-01-24 03:09:51 -05:00
return;
2014-01-20 02:57:39 -05:00
}
else if (sym == pic->sGE) {
codegen(state, pic_list_ref(pic, obj, 2));
codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_LE;
cxt->clen++;
2014-01-24 03:09:51 -05:00
return;
2014-01-20 02:57:39 -05:00
}
else if (sym == state->sCALL || sym == state->sTAILCALL) {
int len = pic_length(pic, obj);
for (obj = pic_cdr(pic, obj); ! pic_nil_p(obj); obj = pic_cdr(pic, obj)) {
codegen(state, pic_car(pic, obj));
}
2014-01-20 02:57:39 -05:00
cxt->code[cxt->clen].insn = (sym == state->sCALL) ? OP_CALL : OP_TAILCALL;
2014-01-24 03:10:51 -05:00
cxt->code[cxt->clen].u.i = len - 1;
2014-01-20 02:57:39 -05:00
cxt->clen++;
2014-01-24 03:09:51 -05:00
return;
}
2014-01-20 02:57:39 -05:00
pic_error(pic, "codegen: unknown AST type");
}
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-27 07:20:00 -05:00
pic_value args, locals, closes, body;
bool varg;
2013-10-23 04:25:39 -04:00
2014-01-20 02:57:39 -05:00
args = pic_list_ref(pic, obj, 1);
2014-01-27 07:20:00 -05:00
locals = pic_list_ref(pic, obj, 2);
varg = pic_true_p(pic_list_ref(pic, obj, 3));
closes = pic_list_ref(pic, obj, 4);
body = pic_list_ref(pic, obj, 5);
2013-10-23 04:25:39 -04:00
/* inner environment */
2014-01-27 07:20:00 -05:00
push_codegen_context(state, args, locals, varg, closes);
2013-10-23 04:25:39 -04:00
{
/* body */
2014-01-20 02:57:39 -05:00
codegen(state, body);
state->cxt->code[state->cxt->clen].insn = OP_RET;
state->cxt->clen++;
2013-10-20 04:06:47 -04:00
}
2014-01-20 02:57:39 -05:00
return pop_codegen_context(state);
}
2014-01-20 02:57:39 -05:00
struct pic_irep *
pic_codegen(pic_state *pic, pic_value obj)
{
codegen_state *state;
2013-10-20 04:06:47 -04:00
2014-01-20 02:57:39 -05:00
state = new_codegen_state(pic);
codegen(state, obj);
state->cxt->code[state->cxt->clen].insn = OP_RET;
state->cxt->clen++;
return destroy_codegen_state(state);
2013-10-20 04:06:47 -04:00
}
struct pic_proc *
2014-01-20 02:57:39 -05:00
pic_compile(pic_state *pic, pic_value obj)
2013-10-20 04:06:47 -04:00
{
struct pic_proc *proc;
struct pic_irep *irep;
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
if (setjmp(jmp) == 0) {
pic->jmp = &jmp;
}
else {
/* error occured */
proc = NULL;
goto exit;
}
2014-01-29 23:50:47 -05:00
#if DEBUG
2014-01-27 08:18:49 -05:00
fprintf(stderr, "ai = %d\n", pic_gc_arena_preserve(pic));
2014-01-27 07:14:41 -05:00
fprintf(stderr, "## input expression\n");
pic_debug(pic, obj);
fprintf(stderr, "\n");
2014-01-27 08:18:49 -05:00
fprintf(stderr, "ai = %d\n", pic_gc_arena_preserve(pic));
2014-01-29 23:50:47 -05:00
#endif
2014-01-27 08:18:49 -05:00
2014-01-20 02:57:39 -05:00
/* macroexpand */
obj = pic_macroexpand(pic, obj);
2014-01-29 23:50:47 -05:00
#if DEBUG
fprintf(stderr, "## macroexpand completed\n");
2014-01-27 07:14:41 -05:00
pic_debug(pic, obj);
fprintf(stderr, "\n");
2014-01-27 08:18:49 -05:00
fprintf(stderr, "ai = %d\n", pic_gc_arena_preserve(pic));
2014-01-29 23:50:47 -05:00
#endif
2014-01-27 08:18:49 -05:00
2014-01-20 02:57:39 -05:00
/* analyze */
obj = pic_analyze(pic, obj);
2014-01-29 23:50:47 -05:00
#if DEBUG
fprintf(stderr, "## analyzer completed\n");
2014-01-20 02:57:39 -05:00
pic_debug(pic, obj);
2014-01-27 07:14:41 -05:00
fprintf(stderr, "\n");
2014-01-27 08:18:49 -05:00
fprintf(stderr, "ai = %d\n", pic_gc_arena_preserve(pic));
2014-01-29 23:50:47 -05:00
#endif
2014-01-27 08:18:49 -05:00
2014-01-24 03:11:37 -05:00
/* resolution */
obj = pic_resolve(pic, obj);
2014-01-29 23:50:47 -05:00
#if DEBUG
fprintf(stderr, "## resolver completed\n");
2014-01-24 03:11:37 -05:00
pic_debug(pic, obj);
2014-01-27 07:14:41 -05:00
fprintf(stderr, "\n");
2014-01-27 08:18:49 -05:00
fprintf(stderr, "ai = %d\n", pic_gc_arena_preserve(pic));
2014-01-29 23:50:47 -05:00
#endif
2014-01-27 08:18:49 -05:00
2014-01-20 02:57:39 -05:00
/* codegen */
irep = pic_codegen(pic, obj);
2014-01-29 23:50:47 -05:00
#if DEBUG
fprintf(stderr, "## codegen completed\n");
2014-01-27 07:14:41 -05:00
pic_dump_irep(pic, irep);
fprintf(stderr, "## compilation finished\n");
puts("");
2014-01-29 23:50:47 -05:00
#endif
2013-10-20 04:06:47 -04:00
2014-01-20 02:57:39 -05:00
proc = pic_proc_new_irep(pic, irep, NULL);
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
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
2014-01-24 03:08:35 -05:00
static int
scope_global_define(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;
}
2013-10-23 02:52:14 -04:00
void
pic_define(pic_state *pic, const char *name, pic_value val)
2013-10-23 02:52:14 -04:00
{
int idx;
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
/* register to the senv */
xh_put(pic->lib->senv->tbl, name, gsym);
/* export! */
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
{
2014-01-30 04:15:59 -05:00
UNUSED(pic);
printf("[%2d] ", c.insn);
switch (c.insn) {
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;
case OP_PUSHFLOAT:
printf("OP_PUSHFLOAT\t%f\n", c.u.f);
break;
case OP_PUSHINT:
printf("OP_PUSHINT\t%d\n", c.u.i);
break;
case OP_PUSHCHAR:
printf("OP_PUSHCHAR\t%c\n", c.u.c);
break;
case OP_PUSHCONST:
printf("OP_PUSHCONST\t%d\n", c.u.i);
break;
case OP_GREF:
printf("OP_GREF\t%i\n", c.u.i);
break;
case OP_GSET:
printf("OP_GSET\t%i\n", c.u.i);
break;
case OP_LREF:
printf("OP_LREF\t%d\n", c.u.i);
break;
case OP_LSET:
printf("OP_LSET\t%d\n", c.u.i);
break;
case OP_CREF:
printf("OP_CREF\t%d\t%d\n", c.u.r.depth, c.u.r.idx);
break;
case OP_CSET:
printf("OP_CSET\t%d\t%d\n", c.u.r.depth, c.u.r.idx);
break;
case OP_JMP:
printf("OP_JMP\t%d\n", c.u.i);
break;
case OP_JMPIF:
printf("OP_JMPIF\t%d\n", c.u.i);
break;
case OP_CALL:
printf("OP_CALL\t%d\n", c.u.i);
break;
case OP_TAILCALL:
printf("OP_TAILCALL\t%d\n", c.u.i);
break;
case OP_RET:
puts("OP_RET");
break;
case OP_LAMBDA:
printf("OP_LAMBDA\t%d\n", c.u.i);
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;
case OP_MINUS:
puts("OP_MINUS");
break;
case OP_EQ:
puts("OP_EQ");
break;
case OP_LT:
puts("OP_LT");
break;
case OP_LE:
puts("OP_LE");
break;
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
{
2014-01-30 04:15:59 -05:00
unsigned i;
2013-12-10 04:47:45 -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
}
2014-01-27 07:14:59 -05:00
for (i = 0; i < irep->ilen; ++i) {
pic_dump_irep(pic, irep->irep[i]);
}
2013-10-23 02:52:14 -04:00
}