2014-01-17 06:58:31 -05:00
|
|
|
/**
|
|
|
|
* See Copyright Notice in picrin.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-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 23:20:28 -05:00
|
|
|
typedef struct analyze_scope {
|
2014-01-23 01:03:43 -05:00
|
|
|
bool varg;
|
2014-03-20 23:34:45 -04:00
|
|
|
xvect args, locals, captures; /* rest args variable is counted as a local */
|
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;
|
2014-02-02 00:55:46 -05:00
|
|
|
pic_sym rEQ, rLT, rLE, rGT, rGE, rNOT;
|
2014-02-20 04:38:09 -05:00
|
|
|
pic_sym rVALUES, rCALL_WITH_VALUES;
|
|
|
|
pic_sym sCALL, sTAILCALL, sCALL_WITH_VALUES, sTAILCALL_WITH_VALUES;
|
|
|
|
pic_sym sREF, sRETURN;
|
2014-01-18 23:20:28 -05:00
|
|
|
} analyze_state;
|
|
|
|
|
2014-03-20 00:41:47 -04:00
|
|
|
static bool push_scope(analyze_state *, pic_value);
|
2014-01-19 23:15:09 -05:00
|
|
|
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)
|
|
|
|
|
2014-02-11 20:39:20 -05:00
|
|
|
#define register_renamed_symbol(pic, state, slot, lib, id) do { \
|
|
|
|
xh_entry *e; \
|
|
|
|
if (! (e = xh_get_int(lib->senv->name, pic_intern_cstr(pic, id)))) \
|
2014-01-18 23:20:28 -05:00
|
|
|
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-02-06 11:15:17 -05:00
|
|
|
xhash *global_tbl;
|
|
|
|
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
|
|
|
|
2014-03-01 06:21:44 -05:00
|
|
|
stdlib = pic_find_library(pic, pic_read(pic, "(scheme base)"));
|
2014-01-18 23:20:28 -05:00
|
|
|
|
|
|
|
/* 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, ">=");
|
2014-02-02 00:55:46 -05:00
|
|
|
register_renamed_symbol(pic, state, rNOT, stdlib, "not");
|
2014-02-20 04:00:30 -05:00
|
|
|
register_renamed_symbol(pic, state, rVALUES, stdlib, "values");
|
2014-02-20 04:38:09 -05:00
|
|
|
register_renamed_symbol(pic, state, rCALL_WITH_VALUES, stdlib, "call-with-values");
|
2014-01-18 23:20:28 -05:00
|
|
|
|
|
|
|
register_symbol(pic, state, sCALL, "call");
|
|
|
|
register_symbol(pic, state, sTAILCALL, "tail-call");
|
2014-02-20 04:38:09 -05:00
|
|
|
register_symbol(pic, state, sCALL_WITH_VALUES, "call-with-values");
|
|
|
|
register_symbol(pic, state, sTAILCALL_WITH_VALUES, "tailcall-with-values");
|
2014-01-23 01:18:41 -05:00
|
|
|
register_symbol(pic, state, sREF, "ref");
|
2014-02-04 04:20:35 -05:00
|
|
|
register_symbol(pic, state, sRETURN, "return");
|
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;
|
2014-02-01 06:01:26 -05:00
|
|
|
for (xh_begin(global_tbl, &it); ! xh_isend(&it); xh_next(&it)) {
|
2014-03-20 08:56:49 -04:00
|
|
|
xv_push(&state->scope->locals, &it.e->key);
|
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-03-20 08:56:49 -04:00
|
|
|
static bool
|
|
|
|
analyze_args(pic_state *pic, pic_value formals, bool *varg, xvect *args, xvect *locals)
|
2014-03-20 00:48:51 -04:00
|
|
|
{
|
2014-03-20 08:56:49 -04:00
|
|
|
pic_value v, sym;
|
2014-03-20 00:48:51 -04:00
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
for (v = formals; pic_pair_p(v); v = pic_cdr(pic, v)) {
|
2014-03-20 00:48:51 -04:00
|
|
|
sym = pic_car(pic, v);
|
|
|
|
if (! pic_sym_p(sym)) {
|
2014-03-20 08:56:49 -04:00
|
|
|
return false;
|
2014-03-20 00:48:51 -04:00
|
|
|
}
|
2014-03-20 08:56:49 -04:00
|
|
|
xv_push(args, &pic_sym(sym));
|
2014-03-20 00:48:51 -04:00
|
|
|
}
|
|
|
|
if (pic_nil_p(v)) {
|
2014-03-20 08:56:49 -04:00
|
|
|
*varg = false;
|
2014-03-20 00:48:51 -04:00
|
|
|
}
|
|
|
|
else if (pic_sym_p(v)) {
|
|
|
|
*varg = true;
|
2014-03-20 08:56:49 -04:00
|
|
|
xv_push(locals, &pic_sym(v));
|
2014-03-20 00:48:51 -04:00
|
|
|
}
|
|
|
|
else {
|
2014-03-20 08:56:49 -04:00
|
|
|
return false;
|
2014-03-20 00:48:51 -04:00
|
|
|
}
|
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
return true;
|
2014-03-20 00:48:51 -04:00
|
|
|
}
|
|
|
|
|
2014-03-20 00:41:47 -04:00
|
|
|
static bool
|
2014-03-20 08:56:49 -04:00
|
|
|
push_scope(analyze_state *state, pic_value formals)
|
2014-01-18 23:20:28 -05:00
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
analyze_scope *scope;
|
2014-03-20 08:56:49 -04:00
|
|
|
bool varg;
|
2014-03-20 23:34:45 -04:00
|
|
|
xvect args, locals, captures;
|
2014-03-20 08:56:49 -04:00
|
|
|
|
|
|
|
xv_init(&args, sizeof(pic_sym));
|
|
|
|
xv_init(&locals, sizeof(pic_sym));
|
2014-03-20 23:34:45 -04:00
|
|
|
xv_init(&captures, sizeof(pic_sym));
|
2014-03-20 08:56:49 -04:00
|
|
|
|
|
|
|
if (analyze_args(pic, formals, &varg, &args, &locals)) {
|
|
|
|
scope = (analyze_scope *)pic_alloc(pic, sizeof(analyze_scope));
|
|
|
|
scope->up = state->scope;
|
|
|
|
scope->varg = varg;
|
|
|
|
scope->args = args;
|
|
|
|
scope->locals = locals;
|
2014-03-20 23:34:45 -04:00
|
|
|
scope->captures = captures;
|
2014-01-18 23:20:28 -05:00
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
state->scope = scope;
|
2014-01-19 23:04:21 -05:00
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
xv_destroy(&args);
|
|
|
|
xv_destroy(&locals);
|
|
|
|
return false;
|
2014-01-19 23:04:21 -05:00
|
|
|
}
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pop_scope(analyze_state *state)
|
|
|
|
{
|
|
|
|
analyze_scope *scope;
|
|
|
|
|
|
|
|
scope = state->scope;
|
2014-03-20 08:56:49 -04:00
|
|
|
xv_destroy(&scope->args);
|
|
|
|
xv_destroy(&scope->locals);
|
2014-03-20 23:34:45 -04:00
|
|
|
xv_destroy(&scope->captures);
|
2014-01-18 23:20:28 -05:00
|
|
|
|
|
|
|
scope = scope->up;
|
|
|
|
pic_free(state->pic, state->scope);
|
|
|
|
state->scope = scope;
|
|
|
|
}
|
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
static bool
|
|
|
|
lookup_scope(analyze_scope *scope, pic_sym sym)
|
|
|
|
{
|
2014-03-20 09:12:20 -04:00
|
|
|
pic_sym *arg, *local;
|
2014-03-20 08:56:49 -04:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
/* args */
|
|
|
|
for (i = 0; i < scope->args.size; ++i) {
|
2014-03-20 09:12:20 -04:00
|
|
|
arg = xv_get(&scope->args, i);
|
|
|
|
if (*arg == sym)
|
2014-03-20 08:56:49 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/* locals */
|
|
|
|
for (i = 0; i < scope->locals.size; ++i) {
|
2014-03-20 09:12:20 -04:00
|
|
|
local = xv_get(&scope->locals, i);
|
|
|
|
if (*local == sym)
|
2014-03-20 08:56:49 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-03-20 23:51:57 -04:00
|
|
|
static void
|
|
|
|
capture_var(analyze_scope *scope, pic_sym sym)
|
|
|
|
{
|
|
|
|
pic_sym *var;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < scope->captures.size; ++i) {
|
|
|
|
var = xv_get(&scope->captures, i);
|
|
|
|
if (*var == sym) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == scope->captures.size) {
|
|
|
|
xv_push(&scope->captures, &sym);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:04:21 -05:00
|
|
|
static int
|
2014-03-20 08:56:49 -04:00
|
|
|
find_var(analyze_state *state, pic_sym sym)
|
2014-01-18 23:20:28 -05:00
|
|
|
{
|
|
|
|
analyze_scope *scope = state->scope;
|
2014-01-19 23:04:21 -05:00
|
|
|
int depth = 0;
|
2014-01-18 23:20:28 -05:00
|
|
|
|
2014-03-20 00:48:51 -04:00
|
|
|
while (scope) {
|
2014-03-20 08:56:49 -04:00
|
|
|
if (lookup_scope(scope, sym)) {
|
|
|
|
if (depth > 0) {
|
2014-03-20 23:51:57 -04:00
|
|
|
capture_var(scope, sym);
|
2014-03-20 00:48:51 -04:00
|
|
|
}
|
|
|
|
return depth;
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
2014-03-20 00:48:51 -04:00
|
|
|
depth++;
|
2014-01-18 23:20:28 -05:00
|
|
|
scope = scope->up;
|
|
|
|
}
|
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-02-06 12:12:43 -05:00
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
if (lookup_scope(scope, sym)) {
|
2014-02-06 12:15:08 -05:00
|
|
|
pic_warn(pic, "redefining variable");
|
2014-02-06 12:12:43 -05:00
|
|
|
return;
|
|
|
|
}
|
2014-01-18 23:20:28 -05:00
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
xv_push(&scope->locals, &sym);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
2014-01-23 01:18:41 -05:00
|
|
|
new_ref(analyze_state *state, int depth, pic_sym sym)
|
2014-01-18 23:20:28 -05:00
|
|
|
{
|
2014-03-01 06:46:08 -05:00
|
|
|
return pic_list3(state->pic,
|
|
|
|
pic_symbol_value(state->sREF),
|
|
|
|
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(analyze_state *state, pic_value obj, bool tailpos)
|
2014-01-19 01:35:36 -05:00
|
|
|
{
|
2014-02-04 04:20:35 -05:00
|
|
|
pic_state *pic = state->pic;
|
|
|
|
int ai = pic_gc_arena_preserve(pic);
|
2014-01-19 01:35:36 -05:00
|
|
|
pic_value res;
|
2014-02-04 04:20:35 -05:00
|
|
|
pic_sym tag;
|
2014-01-19 01:35:36 -05:00
|
|
|
|
|
|
|
res = analyze_node(state, obj, tailpos);
|
|
|
|
|
2014-02-04 04:20:35 -05:00
|
|
|
tag = pic_sym(pic_car(pic, res));
|
|
|
|
if (tailpos) {
|
2014-02-20 04:38:09 -05:00
|
|
|
if (tag == pic->sIF || tag == pic->sBEGIN || tag == state->sTAILCALL || tag == state->sTAILCALL_WITH_VALUES || tag == state->sRETURN) {
|
2014-02-04 04:20:35 -05:00
|
|
|
/* pass through */
|
|
|
|
}
|
|
|
|
else {
|
2014-03-01 06:46:08 -05:00
|
|
|
res = pic_list2(pic, pic_symbol_value(state->sRETURN), res);
|
2014-02-04 04:20:35 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
pic_gc_protect(pic, res);
|
2014-01-19 01:35:36 -05:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-03-19 22:43:55 -04:00
|
|
|
static pic_value
|
|
|
|
analyze_var(analyze_state *state, pic_value obj)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_sym sym;
|
|
|
|
int depth;
|
|
|
|
|
|
|
|
sym = pic_sym(obj);
|
2014-03-20 08:56:49 -04:00
|
|
|
if ((depth = find_var(state, sym)) == -1) {
|
2014-03-19 22:43:55 -04:00
|
|
|
pic_errorf(pic, "unbound variable %s", pic_symbol_name(pic, sym));
|
|
|
|
}
|
2014-03-20 08:56:49 -04:00
|
|
|
return new_ref(state, depth, sym);
|
2014-03-19 22:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-19 08:45:02 -04:00
|
|
|
static pic_value
|
|
|
|
analyze_define(analyze_state *state, pic_value obj)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value var, val;
|
|
|
|
|
|
|
|
if (pic_length(pic, obj) < 2) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
var = pic_list_ref(pic, obj, 1);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pic_length(pic, obj) != 3) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
val = pic_list_ref(pic, obj, 2);
|
|
|
|
}
|
|
|
|
if (! pic_sym_p(var)) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
define_var(state, pic_sym(var));
|
|
|
|
|
|
|
|
var = analyze(state, var, false);
|
|
|
|
val = analyze(state, val, false);
|
|
|
|
|
|
|
|
return pic_list3(pic, pic_symbol_value(pic->sSETBANG), var, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_if(analyze_state *state, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value cond, if_true, if_false;
|
|
|
|
|
|
|
|
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);
|
|
|
|
FALLTHROUGH;
|
|
|
|
case 3:
|
|
|
|
if_true = pic_list_ref(pic, obj, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* analyze in order */
|
|
|
|
cond = analyze(state, pic_list_ref(pic, obj, 1), false);
|
|
|
|
if_true = analyze(state, if_true, tailpos);
|
|
|
|
if_false = analyze(state, if_false, tailpos);
|
|
|
|
|
|
|
|
return pic_list4(pic, pic_symbol_value(pic->sIF), cond, if_true, if_false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_begin(analyze_state *state, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value seq;
|
|
|
|
bool tail;
|
|
|
|
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 1:
|
|
|
|
return analyze(state, pic_none_value(), tailpos);
|
|
|
|
case 2:
|
|
|
|
return analyze(state, pic_list_ref(pic, obj, 1), tailpos);
|
|
|
|
default:
|
|
|
|
seq = pic_list1(pic, 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_set(analyze_state *state, pic_value obj)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value var, val;
|
|
|
|
|
|
|
|
if (pic_length(pic, obj) != 3) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
var = pic_list_ref(pic, obj, 1);
|
|
|
|
if (! pic_sym_p(var)) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
val = pic_list_ref(pic, obj, 2);
|
|
|
|
|
|
|
|
var = analyze(state, var, false);
|
|
|
|
val = analyze(state, val, false);
|
|
|
|
|
|
|
|
return pic_list3(pic, pic_symbol_value(pic->sSETBANG), var, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_quote(analyze_state *state, pic_value obj)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
|
|
|
|
if (pic_length(pic, obj) != 2) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_lambda(analyze_state *state, pic_value obj)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
2014-03-20 08:56:49 -04:00
|
|
|
pic_value formals, args, locals, varg, captures, body;
|
2014-03-19 08:45:02 -04:00
|
|
|
|
|
|
|
if (pic_length(pic, obj) < 2) {
|
|
|
|
pic_error(pic, "syntax error");
|
|
|
|
}
|
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
formals = pic_car(pic, pic_cdr(pic, obj));
|
2014-03-19 08:45:02 -04:00
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
if (push_scope(state, formals)) {
|
2014-03-19 08:45:02 -04:00
|
|
|
analyze_scope *scope = state->scope;
|
2014-03-20 09:12:20 -04:00
|
|
|
pic_sym *var;
|
2014-03-20 08:56:49 -04:00
|
|
|
size_t i;
|
2014-03-19 08:45:02 -04:00
|
|
|
|
|
|
|
args = pic_nil_value();
|
2014-03-20 08:56:49 -04:00
|
|
|
for (i = scope->args.size; i > 0; --i) {
|
2014-03-20 09:12:20 -04:00
|
|
|
var = xv_get(&scope->args, i - 1);
|
|
|
|
pic_push(pic, pic_sym_value(*var), args);
|
2014-03-19 08:45:02 -04:00
|
|
|
}
|
|
|
|
|
2014-03-20 19:20:33 -04:00
|
|
|
varg = scope->varg
|
|
|
|
? pic_true_value()
|
|
|
|
: pic_false_value();
|
|
|
|
|
|
|
|
/* To know what kind of local variables are defined, analyze body at first. */
|
|
|
|
body = analyze(state, pic_cons(pic, pic_sym_value(pic->sBEGIN), pic_list_tail(pic, obj, 2)), true);
|
|
|
|
|
2014-03-19 08:45:02 -04:00
|
|
|
locals = pic_nil_value();
|
2014-03-20 08:56:49 -04:00
|
|
|
for (i = scope->locals.size; i > 0; --i) {
|
2014-03-20 09:12:20 -04:00
|
|
|
var = xv_get(&scope->locals, i - 1);
|
|
|
|
pic_push(pic, pic_sym_value(*var), locals);
|
2014-03-19 08:45:02 -04:00
|
|
|
}
|
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
captures = pic_nil_value();
|
2014-03-20 23:34:45 -04:00
|
|
|
for (i = scope->captures.size; i > 0; --i) {
|
|
|
|
var = xv_get(&scope->captures, i - 1);
|
|
|
|
pic_push(pic, pic_sym_value(*var), captures);
|
2014-03-19 08:45:02 -04:00
|
|
|
}
|
2014-03-20 00:41:47 -04:00
|
|
|
|
|
|
|
pop_scope(state);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic_errorf(pic, "invalid formal syntax: ~s", args);
|
2014-03-19 08:45:02 -04:00
|
|
|
}
|
|
|
|
|
2014-03-20 08:56:49 -04:00
|
|
|
return pic_list6(pic, pic_sym_value(pic->sLAMBDA), args, locals, varg, captures, body);
|
2014-03-19 08:45:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#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); \
|
|
|
|
pic_for_each (arg, pic_cdr(pic, args)) { \
|
|
|
|
obj = pic_list3(pic, pic_symbol_value(sym), obj, \
|
|
|
|
analyze(state, arg, false)); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_add(analyze_state *state, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value args, arg;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_sub(analyze_state *state, pic_value obj)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value args, arg;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(1);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 2:
|
|
|
|
return pic_list2(pic, 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_mul(analyze_state *state, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value args, arg;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_div(analyze_state *state, pic_value obj)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value args, arg;
|
|
|
|
|
|
|
|
ARGC_ASSERT_GE(1);
|
|
|
|
switch (pic_length(pic, obj)) {
|
|
|
|
case 2:
|
|
|
|
args = pic_cdr(pic, obj);
|
|
|
|
obj = pic_list3(pic, pic_car(pic, obj), pic_float_value(1), pic_car(pic, args));
|
|
|
|
return analyze(state, obj, false);
|
|
|
|
default:
|
|
|
|
args = pic_cdr(pic, obj);
|
|
|
|
FOLD_ARGS(pic->sDIV);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_call(analyze_state *state, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value seq, elt;
|
|
|
|
pic_sym call;
|
|
|
|
|
|
|
|
if (! tailpos) {
|
|
|
|
call = state->sCALL;
|
|
|
|
} else {
|
|
|
|
call = state->sTAILCALL;
|
|
|
|
}
|
|
|
|
seq = pic_list1(pic, pic_symbol_value(call));
|
|
|
|
pic_for_each (elt, obj) {
|
|
|
|
seq = pic_cons(pic, analyze(state, elt, false), seq);
|
|
|
|
}
|
2014-03-20 00:44:35 -04:00
|
|
|
return pic_reverse(pic, seq);
|
2014-03-19 08:45:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_values(analyze_state *state, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value v, seq;
|
|
|
|
|
|
|
|
if (! tailpos) {
|
|
|
|
return analyze_call(state, obj, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
seq = pic_list1(pic, pic_symbol_value(state->sRETURN));
|
|
|
|
pic_for_each (v, pic_cdr(pic, obj)) {
|
|
|
|
seq = pic_cons(pic, analyze(state, v, false), seq);
|
|
|
|
}
|
|
|
|
return pic_reverse(pic, seq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_call_with_values(analyze_state *state, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
pic_value prod, cnsm;
|
|
|
|
pic_sym call;
|
|
|
|
|
|
|
|
if (pic_length(pic, obj) != 3) {
|
|
|
|
pic_error(pic, "wrong number of arguments");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! tailpos) {
|
|
|
|
call = state->sCALL_WITH_VALUES;
|
|
|
|
} else {
|
|
|
|
call = state->sTAILCALL_WITH_VALUES;
|
|
|
|
}
|
|
|
|
prod = analyze(state, pic_list_ref(pic, obj, 1), false);
|
|
|
|
cnsm = analyze(state, pic_list_ref(pic, obj, 2), false);
|
|
|
|
return pic_list3(pic, pic_symbol_value(call), prod, cnsm);
|
|
|
|
}
|
|
|
|
|
|
|
|
#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_list2(pic, \
|
|
|
|
pic_symbol_value(op), \
|
|
|
|
analyze(state, pic_list_ref(pic, obj, 1), false))
|
|
|
|
|
|
|
|
#define CONSTRUCT_OP2(op) \
|
|
|
|
pic_list3(pic, \
|
|
|
|
pic_symbol_value(op), \
|
|
|
|
analyze(state, pic_list_ref(pic, obj, 1), false), \
|
|
|
|
analyze(state, pic_list_ref(pic, obj, 2), false))
|
|
|
|
|
2014-01-19 01:35:36 -05:00
|
|
|
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-03-19 22:43:55 -04:00
|
|
|
return analyze_var(state, obj);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
case PIC_TT_PAIR: {
|
|
|
|
pic_value proc;
|
|
|
|
|
2014-03-16 10:12:07 -04:00
|
|
|
if (! pic_list_p(obj)) {
|
2014-03-03 08:44:38 -05:00
|
|
|
pic_errorf(pic, "invalid expression given: ~s", obj);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
|
2014-01-23 02:32:20 -05:00
|
|
|
proc = pic_list_ref(pic, obj, 0);
|
2014-01-30 13:03:36 -05:00
|
|
|
if (pic_sym_p(proc)) {
|
2014-01-18 23:20:28 -05:00
|
|
|
pic_sym sym = pic_sym(proc);
|
|
|
|
|
|
|
|
if (sym == pic->sDEFINE) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_define(state, obj);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
else if (sym == pic->sLAMBDA) {
|
|
|
|
return analyze_lambda(state, obj);
|
|
|
|
}
|
|
|
|
else if (sym == pic->sIF) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_if(state, obj, tailpos);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
else if (sym == pic->sBEGIN) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_begin(state, obj, tailpos);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
else if (sym == pic->sSETBANG) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_set(state, obj);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
else if (sym == pic->sQUOTE) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_quote(state, obj);
|
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);
|
|
|
|
}
|
|
|
|
else if (sym == state->rADD) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_add(state, obj, tailpos);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
else if (sym == state->rSUB) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_sub(state, obj);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
else if (sym == state->rMUL) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_mul(state, obj, tailpos);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
else if (sym == state->rDIV) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_div(state, obj);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
2014-02-02 00:55:46 -05:00
|
|
|
else if (sym == state->rNOT) {
|
|
|
|
ARGC_ASSERT(1);
|
|
|
|
return CONSTRUCT_OP1(pic->sNOT);
|
|
|
|
}
|
2014-03-19 08:45:02 -04:00
|
|
|
else if (sym == state->rVALUES) {
|
|
|
|
return analyze_values(state, obj, tailpos);
|
2014-02-20 04:00:30 -05:00
|
|
|
}
|
2014-02-20 04:38:09 -05:00
|
|
|
else if (sym == state->rCALL_WITH_VALUES) {
|
2014-03-19 08:45:02 -04:00
|
|
|
return analyze_call_with_values(state, obj, tailpos);
|
2014-02-20 04:38:09 -05:00
|
|
|
}
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
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: {
|
2014-03-01 06:46:08 -05:00
|
|
|
return pic_list2(pic, pic_symbol_value(pic->sQUOTE), obj);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
|
|
|
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:
|
2014-02-11 21:13:29 -05:00
|
|
|
case PIC_TT_MACRO:
|
2014-01-18 23:20:28 -05:00
|
|
|
case PIC_TT_SC:
|
|
|
|
case PIC_TT_LIB:
|
|
|
|
case PIC_TT_VAR:
|
|
|
|
case PIC_TT_IREP:
|
2014-03-19 08:45:02 -04:00
|
|
|
pic_errorf(pic, "invalid expression given: ~s", obj);
|
2014-01-18 23:20:28 -05:00
|
|
|
}
|
2014-03-19 08:45:02 -04:00
|
|
|
UNREACHABLE();
|
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);
|
|
|
|
|
2014-02-04 04:23:37 -05:00
|
|
|
obj = analyze(state, obj, true);
|
2014-01-20 02:57:39 -05:00
|
|
|
|
|
|
|
destroy_analyze_state(state);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2014-01-24 03:11:37 -05:00
|
|
|
typedef struct resolver_scope {
|
|
|
|
int depth;
|
|
|
|
bool varg;
|
2014-01-30 04:14:33 -05:00
|
|
|
int argc, localc;
|
2014-02-06 11:15:17 -05:00
|
|
|
xhash *cvs, *lvs;
|
2014-01-24 03:11:37 -05:00
|
|
|
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;
|
2014-02-06 11:08:57 -05:00
|
|
|
scope->lvs = xh_new_int();
|
|
|
|
scope->cvs = xh_new_int();
|
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) {
|
2014-02-06 11:08:57 -05:00
|
|
|
xh_put_int(scope->lvs, 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) {
|
2014-02-06 11:08:57 -05:00
|
|
|
xh_put_int(scope->lvs, 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) {
|
2014-02-06 11:08:57 -05:00
|
|
|
xh_put_int(scope->cvs, 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
|
2014-01-27 08:19:26 -05:00
|
|
|
is_closed(resolver_state *state, pic_sym sym)
|
2014-01-24 03:11:37 -05:00
|
|
|
{
|
2014-02-06 11:08:57 -05:00
|
|
|
return xh_get_int(state->scope->cvs, 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;
|
2014-02-06 11:15:17 -05:00
|
|
|
xh_entry *e;
|
2014-01-30 04:14:33 -05:00
|
|
|
size_t i;
|
2014-01-24 03:11:37 -05:00
|
|
|
|
2014-02-06 11:08:57 -05:00
|
|
|
if ((e = xh_get_int(pic->global_tbl, sym))) {
|
2014-01-24 03:11:37 -05:00
|
|
|
i = e->val;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
i = pic->glen++;
|
|
|
|
if (i >= pic->gcapa) {
|
|
|
|
pic_error(pic, "global table overflow");
|
|
|
|
}
|
2014-02-06 11:08:57 -05:00
|
|
|
xh_put_int(pic->global_tbl, sym, i);
|
2014-01-24 03:11:37 -05:00
|
|
|
}
|
2014-03-01 06:46:08 -05:00
|
|
|
return pic_list2(pic, pic_symbol_value(state->sGREF), pic_int_value(i));
|
2014-01-24 03:11:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
resolve_lref(resolver_state *state, pic_sym sym)
|
|
|
|
{
|
|
|
|
pic_state *pic = state->pic;
|
|
|
|
int i;
|
|
|
|
|
2014-02-06 11:08:57 -05:00
|
|
|
i = xh_get_int(state->scope->lvs, sym)->val;
|
2014-01-24 03:11:37 -05:00
|
|
|
|
2014-03-01 06:46:08 -05:00
|
|
|
return pic_list2(pic, pic_symbol_value(state->sLREF), pic_int_value(i));
|
2014-01-24 03:11:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-02-06 11:08:57 -05:00
|
|
|
i = xh_get_int(scope->cvs, sym)->val;
|
2014-01-24 03:11:37 -05:00
|
|
|
|
2014-03-01 06:46:08 -05:00
|
|
|
return pic_list3(pic,
|
|
|
|
pic_symbol_value(state->sCREF),
|
|
|
|
pic_int_value(depth),
|
|
|
|
pic_int_value(i));
|
2014-01-24 03:11:37 -05:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
2014-02-03 20:18:31 -05:00
|
|
|
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-03-01 06:46:08 -05:00
|
|
|
return pic_list6(pic, 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-03-01 06:46:08 -05:00
|
|
|
pic_value seq = pic_list1(pic, pic_symbol_value(tag)), elt;
|
2014-02-01 02:05:29 -05:00
|
|
|
|
|
|
|
pic_for_each (elt, pic_cdr(pic, obj)) {
|
|
|
|
seq = pic_cons(pic, resolve_reference(state, elt), seq);
|
2014-01-27 08:20:18 -05:00
|
|
|
|
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
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 {
|
2014-01-18 06:49:01 -05:00
|
|
|
bool varg;
|
2014-01-18 08:32:41 -05:00
|
|
|
/* rest args variable is counted by localc */
|
2014-01-30 04:14:33 -05:00
|
|
|
int argc, localc;
|
2014-01-23 04:55:39 -05:00
|
|
|
/* closed variable table */
|
|
|
|
unsigned *cv_tbl, cv_num;
|
2014-01-18 06:49:01 -05:00
|
|
|
/* actual bit code sequence */
|
2014-03-07 08:06:43 -05:00
|
|
|
pic_code *code;
|
2014-01-18 06:49:01 -05:00
|
|
|
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
|
|
|
|
2014-01-20 02:57:39 -05:00
|
|
|
struct codegen_context *up;
|
|
|
|
} codegen_context;
|
2013-10-22 09:22:35 -04:00
|
|
|
|
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;
|
2014-02-04 04:20:35 -05:00
|
|
|
pic_sym sCALL, sTAILCALL, sRETURN;
|
2014-02-20 04:38:09 -05:00
|
|
|
pic_sym sCALL_WITH_VALUES, sTAILCALL_WITH_VALUES;
|
2014-01-23 04:55:39 -05:00
|
|
|
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 *);
|
2014-01-18 14:47:18 -05:00
|
|
|
|
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-02-04 04:20:35 -05:00
|
|
|
register_symbol(pic, state, sRETURN, "return");
|
2014-02-20 04:38:09 -05:00
|
|
|
register_symbol(pic, state, sCALL_WITH_VALUES, "call-with-values");
|
|
|
|
register_symbol(pic, state, sTAILCALL_WITH_VALUES, "tailcall-with-values");
|
2014-01-18 14:47:18 -05:00
|
|
|
|
2014-01-27 07:20:00 -05:00
|
|
|
push_codegen_context(state, pic_nil_value(), pic_nil_value(), false, pic_nil_value());
|
2014-01-18 14:47:18 -05:00
|
|
|
|
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)
|
2013-10-22 09:22:35 -04:00
|
|
|
{
|
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;
|
2014-02-06 11:15:17 -05:00
|
|
|
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 */
|
2014-02-06 11:08:57 -05:00
|
|
|
vars = xh_new_int();
|
2014-01-27 07:20:00 -05:00
|
|
|
for (i = 1; i < cxt->argc; ++i) {
|
2014-02-06 11:08:57 -05:00
|
|
|
xh_put_int(vars, pic_sym(pic_list_ref(pic, args, i - 1)), i);
|
2014-01-27 07:20:00 -05:00
|
|
|
}
|
|
|
|
for (i = 0; i < cxt->localc; ++i) {
|
2014-02-06 11:08:57 -05:00
|
|
|
xh_put_int(vars, 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 */
|
2014-01-23 04:55:39 -05:00
|
|
|
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++;
|
2014-03-22 05:29:14 -04:00
|
|
|
cxt->cv_tbl = pic_realloc(pic, cxt->cv_tbl, sizeof(unsigned) * cxt->cv_num);
|
2014-02-06 11:08:57 -05:00
|
|
|
cxt->cv_tbl[i] = xh_get_int(vars, pic_sym(pic_list_ref(pic, closes, i)))->val;
|
2014-01-27 07:20:00 -05:00
|
|
|
}
|
|
|
|
|
2014-01-30 00:33:16 -05:00
|
|
|
xh_destroy(vars);
|
2014-01-23 04:55:39 -05:00
|
|
|
|
2014-03-22 05:29:14 -04:00
|
|
|
cxt->code = pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(pic_code));
|
2014-01-20 02:57:39 -05:00
|
|
|
cxt->clen = 0;
|
|
|
|
cxt->ccapa = PIC_ISEQ_SIZE;
|
|
|
|
|
2014-03-22 05:29:14 -04:00
|
|
|
cxt->irep = pic_calloc(pic, PIC_IREP_SIZE, sizeof(struct pic_irep *));
|
2014-01-20 02:57:39 -05:00
|
|
|
cxt->ilen = 0;
|
|
|
|
cxt->icapa = PIC_IREP_SIZE;
|
|
|
|
|
2014-03-22 05:29:14 -04:00
|
|
|
cxt->pool = pic_calloc(pic, PIC_POOL_SIZE, sizeof(pic_value));
|
2014-01-20 02:57:39 -05:00
|
|
|
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 */
|
2014-01-31 23:44:43 -05:00
|
|
|
irep = (struct pic_irep *)pic_obj_alloc(pic, sizeof(struct pic_irep), PIC_TT_IREP);
|
2014-01-20 02:57:39 -05:00
|
|
|
irep->varg = state->cxt->varg;
|
|
|
|
irep->argc = state->cxt->argc;
|
|
|
|
irep->localc = state->cxt->localc;
|
2014-01-23 04:55:39 -05:00
|
|
|
irep->cv_tbl = state->cxt->cv_tbl;
|
|
|
|
irep->cv_num = state->cxt->cv_num;
|
2014-03-07 08:06:43 -05:00
|
|
|
irep->code = pic_realloc(pic, state->cxt->code, sizeof(pic_code) * state->cxt->clen);
|
2014-01-20 02:57:39 -05:00
|
|
|
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;
|
|
|
|
|
2014-01-23 02:32:20 -05:00
|
|
|
val = pic_list_ref(pic, obj, 2);
|
2014-01-20 02:57:39 -05:00
|
|
|
codegen(state, val);
|
|
|
|
|
2014-01-23 02:32:20 -05:00
|
|
|
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;
|
2014-03-22 05:29:14 -04:00
|
|
|
cxt->irep = pic_realloc(pic, cxt->irep, sizeof(struct pic_irep *) * cxt->icapa);
|
2014-01-20 02:57:39 -05:00
|
|
|
}
|
|
|
|
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;
|
2013-10-24 08:55:07 -04:00
|
|
|
|
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) {
|
2014-02-01 02:05:29 -05:00
|
|
|
pic_value elt;
|
2014-02-22 19:16:29 -05:00
|
|
|
int i = 0;
|
|
|
|
|
2014-02-01 02:05:29 -05:00
|
|
|
pic_for_each (elt, pic_cdr(pic, obj)) {
|
2014-02-22 19:16:29 -05:00
|
|
|
if (i++ != 0) {
|
|
|
|
cxt->code[cxt->clen].insn = OP_POP;
|
|
|
|
cxt->clen++;
|
|
|
|
}
|
2014-02-01 02:05:29 -05:00
|
|
|
codegen(state, elt);
|
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_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;
|
2014-03-22 05:29:14 -04:00
|
|
|
cxt->pool = pic_realloc(pic, cxt->pool, sizeof(pic_value) * cxt->pcapa);
|
2014-01-23 05:21:37 -05:00
|
|
|
}
|
|
|
|
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;
|
2013-11-04 20:27:44 -05:00
|
|
|
}
|
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
|
|
|
}
|
2014-02-02 00:55:46 -05:00
|
|
|
else if (sym == pic->sNOT) {
|
|
|
|
codegen(state, pic_list_ref(pic, obj, 1));
|
|
|
|
cxt->code[cxt->clen].insn = OP_NOT;
|
|
|
|
cxt->clen++;
|
|
|
|
return;
|
|
|
|
}
|
2014-01-20 02:57:39 -05:00
|
|
|
else if (sym == state->sCALL || sym == state->sTAILCALL) {
|
|
|
|
int len = pic_length(pic, obj);
|
2014-02-01 02:05:29 -05:00
|
|
|
pic_value elt;
|
|
|
|
|
|
|
|
pic_for_each (elt, pic_cdr(pic, obj)) {
|
|
|
|
codegen(state, elt);
|
2013-11-04 20:23:06 -05:00
|
|
|
}
|
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;
|
2013-11-04 20:23:06 -05:00
|
|
|
}
|
2014-02-20 04:38:09 -05:00
|
|
|
else if (sym == state->sCALL_WITH_VALUES || sym == state->sTAILCALL_WITH_VALUES) {
|
|
|
|
/* stack consumer at first */
|
|
|
|
codegen(state, pic_list_ref(pic, obj, 2));
|
|
|
|
codegen(state, pic_list_ref(pic, obj, 1));
|
|
|
|
/* call producer */
|
|
|
|
cxt->code[cxt->clen].insn = OP_CALL;
|
|
|
|
cxt->code[cxt->clen].u.i = 1;
|
|
|
|
cxt->clen++;
|
|
|
|
/* call consumer */
|
|
|
|
cxt->code[cxt->clen].insn = (sym == state->sCALL_WITH_VALUES) ? OP_CALL : OP_TAILCALL;
|
|
|
|
cxt->code[cxt->clen].u.i = -1;
|
|
|
|
cxt->clen++;
|
|
|
|
return;
|
|
|
|
}
|
2014-02-04 04:20:35 -05:00
|
|
|
else if (sym == state->sRETURN) {
|
2014-02-20 02:01:29 -05:00
|
|
|
int len = pic_length(pic, obj);
|
|
|
|
pic_value elt;
|
|
|
|
|
|
|
|
pic_for_each (elt, pic_cdr(pic, obj)) {
|
|
|
|
codegen(state, elt);
|
|
|
|
}
|
2014-02-04 04:20:35 -05:00
|
|
|
cxt->code[cxt->clen].insn = OP_RET;
|
2014-02-20 02:01:29 -05:00
|
|
|
cxt->code[cxt->clen].u.i = len - 1;
|
2014-02-04 04:20:35 -05:00
|
|
|
cxt->clen++;
|
|
|
|
return;
|
|
|
|
}
|
2014-01-20 02:57:39 -05:00
|
|
|
pic_error(pic, "codegen: unknown AST type");
|
2013-11-04 20:23:06 -05:00
|
|
|
}
|
|
|
|
|
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-24 08:55:07 -04:00
|
|
|
|
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);
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
2014-01-20 02:57:39 -05:00
|
|
|
return pop_codegen_context(state);
|
|
|
|
}
|
2013-10-22 09:22:35 -04:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
return destroy_codegen_state(state);
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|
|
|
|
|
2014-03-03 08:49:59 -05:00
|
|
|
struct pic_proc *
|
|
|
|
pic_compile(pic_state *pic, pic_value obj)
|
2013-10-20 04:06:47 -04:00
|
|
|
{
|
2014-01-18 06:49:01 -05:00
|
|
|
struct pic_irep *irep;
|
2013-11-15 05:54:47 -05:00
|
|
|
int ai = pic_gc_arena_preserve(pic);
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2014-01-29 23:50:47 -05:00
|
|
|
#if DEBUG
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "ai = %d\n", pic_gc_arena_preserve(pic));
|
2014-01-27 08:18:49 -05:00
|
|
|
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "# input expression\n");
|
2014-01-27 07:14:41 -05:00
|
|
|
pic_debug(pic, obj);
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "\n");
|
2014-01-27 07:14:41 -05:00
|
|
|
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "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
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "## macroexpand completed\n");
|
2014-01-27 07:14:41 -05:00
|
|
|
pic_debug(pic, obj);
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "\n");
|
|
|
|
fprintf(stdout, "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
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "## analyzer completed\n");
|
2014-01-20 02:57:39 -05:00
|
|
|
pic_debug(pic, obj);
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "\n");
|
|
|
|
fprintf(stdout, "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
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "## resolver completed\n");
|
2014-01-24 03:11:37 -05:00
|
|
|
pic_debug(pic, obj);
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "\n");
|
|
|
|
fprintf(stdout, "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
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "## codegen completed\n");
|
2014-03-19 06:44:45 -04:00
|
|
|
pic_dump_irep(irep);
|
2014-02-04 04:53:51 -05:00
|
|
|
#endif
|
2014-01-27 07:14:41 -05:00
|
|
|
|
2014-02-04 04:53:51 -05:00
|
|
|
#if DEBUG
|
2014-02-20 03:58:00 -05:00
|
|
|
fprintf(stdout, "# compilation finished\n");
|
2014-01-27 07:14:41 -05:00
|
|
|
puts("");
|
2014-01-29 23:50:47 -05:00
|
|
|
#endif
|
2013-10-20 04:06:47 -04:00
|
|
|
|
2014-02-04 04:53:40 -05:00
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
pic_gc_protect(pic, pic_obj_value(irep));
|
2013-10-22 09:22:35 -04:00
|
|
|
|
2014-03-03 08:49:59 -05:00
|
|
|
return pic_proc_new_irep(pic, irep, NULL);
|
2013-10-20 04:06:47 -04:00
|
|
|
}
|