picrin/src/codegen.c

1497 lines
37 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 "picrin.h"
#include "picrin/pair.h"
#include "picrin/irep.h"
#include "picrin/proc.h"
#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-03-23 05:47:55 -04:00
/**
* scope object
*/
2014-01-18 23:20:28 -05:00
typedef struct analyze_scope {
2014-03-22 07:47:27 -04:00
int depth;
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;
2014-03-23 05:47:55 -04:00
/**
* global analyzer state
*/
2014-01-18 23:20:28 -05:00
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 sGREF, sLREF, sCREF, 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 { \
2014-03-25 01:12:53 -04:00
pic_sym sym, gsym; \
sym = pic_intern_cstr(pic, id); \
2014-03-27 03:19:55 -04:00
if (! pic_find_rename(pic, lib->senv, sym, &gsym)) { \
2014-01-18 23:20:28 -05:00
pic_error(pic, "internal error! native VM procedure not found"); \
2014-03-25 01:12:53 -04:00
} \
state->slot = gsym; \
2014-01-18 23:20:28 -05:00
} while (0)
static analyze_state *
new_analyze_state(pic_state *pic)
{
analyze_state *state;
xh_iter it;
2014-01-18 23:20:28 -05:00
struct pic_lib *stdlib;
2014-03-27 23:18:24 -04:00
state = pic_alloc(pic, sizeof(analyze_state));
2014-01-18 23:20:28 -05:00
state->pic = pic;
2014-01-19 23:15:09 -05:00
state->scope = NULL;
2014-01-18 23:20:28 -05:00
2014-06-25 02:39:04 -04:00
stdlib = pic_find_library(pic, pic_read_cstr(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-03-22 07:47:27 -04:00
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-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-03-25 02:29:26 -04:00
xh_begin(&it, &pic->global_tbl);
while (xh_next(&it)) {
pic_sym sym = xh_key(it.e, pic_sym);
xv_push(&state->scope->locals, &sym);
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)) {
2014-03-27 23:18:24 -04:00
scope = pic_alloc(pic, sizeof(analyze_scope));
2014-03-20 08:56:49 -04:00
scope->up = state->scope;
2014-03-22 07:47:27 -04:00
scope->depth = scope->up ? scope->up->depth + 1 : 0;
2014-03-20 08:56:49 -04:00
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;
}
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) {
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)) {
pic_warnf(pic, "redefining variable: ~s", pic_sym_value(sym));
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
}
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;
2014-05-26 03:06:41 -04:00
size_t 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-22 07:47:27 -04:00
static pic_value
analyze_global_var(analyze_state *state, pic_sym sym)
{
pic_state *pic = state->pic;
xh_entry *e;
size_t i;
2014-06-14 07:59:31 -04:00
if ((e = xh_get_int(&pic->global_tbl, sym))) {
2014-03-25 02:29:26 -04:00
i = xh_val(e, size_t);
2014-03-22 07:47:27 -04:00
}
else {
i = pic->glen++;
if (i >= pic->gcapa) {
pic_error(pic, "global table overflow");
}
2014-06-14 07:59:31 -04:00
xh_put_int(&pic->global_tbl, sym, &i);
2014-03-22 07:47:27 -04:00
}
return pic_list2(pic, pic_symbol_value(state->sGREF), pic_int_value(i));
}
static pic_value
analyze_local_var(analyze_state *state, pic_sym sym)
{
pic_state *pic = state->pic;
return pic_list2(pic, pic_symbol_value(state->sLREF), pic_sym_value(sym));
}
static pic_value
analyze_free_var(analyze_state *state, pic_sym sym, int depth)
{
pic_state *pic = state->pic;
return pic_list3(pic, pic_symbol_value(state->sCREF), pic_int_value(depth), pic_sym_value(sym));
}
2014-03-19 22:43:55 -04:00
static pic_value
analyze_var(analyze_state *state, pic_sym sym)
2014-03-19 22:43:55 -04:00
{
pic_state *pic = state->pic;
int depth;
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-22 07:47:27 -04:00
if (depth == state->scope->depth) {
return analyze_global_var(state, sym);
} else if (depth == 0) {
return analyze_local_var(state, sym);
} else {
return analyze_free_var(state, sym, depth);
2014-03-22 07:47:27 -04:00
}
2014-03-19 22:43:55 -04:00
}
2014-03-27 22:49:09 -04:00
static pic_value
2014-03-27 23:26:07 -04:00
analyze_procedure(analyze_state *state, pic_value name, pic_value formals, pic_value body_exprs)
2014-03-27 22:49:09 -04:00
{
pic_state *pic = state->pic;
pic_value args, locals, varg, captures, body;
2014-03-27 22:49:09 -04:00
2014-03-27 23:26:07 -04:00
assert(pic_sym_p(name) || pic_false_p(name));
2014-03-27 22:49:09 -04:00
if (push_scope(state, formals)) {
analyze_scope *scope = state->scope;
pic_sym *var;
size_t i;
args = pic_nil_value();
for (i = scope->args.size; i > 0; --i) {
var = xv_get(&scope->args, i - 1);
pic_push(pic, pic_sym_value(*var), args);
}
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), body_exprs), true);
2014-03-27 22:49:09 -04:00
locals = pic_nil_value();
for (i = scope->locals.size; i > 0; --i) {
var = xv_get(&scope->locals, i - 1);
pic_push(pic, pic_sym_value(*var), locals);
}
captures = pic_nil_value();
for (i = scope->captures.size; i > 0; --i) {
var = xv_get(&scope->captures, i - 1);
pic_push(pic, pic_sym_value(*var), captures);
}
pop_scope(state);
}
else {
pic_errorf(pic, "invalid formal syntax: ~s", args);
}
2014-03-27 23:26:07 -04:00
return pic_list7(pic, pic_sym_value(pic->sLAMBDA), name, args, locals, varg, captures, body);
2014-03-27 22:49:09 -04:00
}
static pic_value
analyze_lambda(analyze_state *state, pic_value obj)
{
pic_state *pic = state->pic;
pic_value formals, body_exprs;
if (pic_length(pic, obj) < 2) {
pic_error(pic, "syntax error");
}
formals = pic_list_ref(pic, obj, 1);
body_exprs = pic_list_tail(pic, obj, 2);
2014-03-27 23:26:07 -04:00
return analyze_procedure(state, pic_false_value(), formals, body_exprs);
}
2014-03-27 22:48:26 -04:00
static pic_value
analyze_declare(analyze_state *state, pic_sym var)
{
define_var(state, var);
return analyze_var(state, var);
2014-03-27 22:48:26 -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;
2014-03-27 22:42:57 -04:00
pic_sym sym;
2014-03-19 08:45:02 -04:00
if (pic_length(pic, obj) < 2) {
pic_error(pic, "syntax error");
}
var = pic_list_ref(pic, obj, 1);
if (pic_pair_p(var)) {
var = pic_list_ref(pic, var, 0);
}
if (! pic_sym_p(var)) {
pic_error(pic, "syntax error");
2014-03-27 22:42:57 -04:00
} else {
sym = pic_sym(var);
2014-03-19 08:45:02 -04:00
}
2014-03-27 22:48:26 -04:00
var = analyze_declare(state, sym);
2014-03-27 22:42:57 -04:00
if (pic_pair_p(pic_list_ref(pic, obj, 1))) {
pic_value formals, body_exprs;
formals = pic_list_tail(pic, pic_list_ref(pic, obj, 1), 1);
body_exprs = pic_list_tail(pic, obj, 2);
2014-03-27 23:26:07 -04:00
val = analyze_procedure(state, pic_sym_value(sym), formals, body_exprs);
2014-03-27 22:42:57 -04:00
} else {
if (pic_length(pic, obj) != 3) {
pic_error(pic, "syntax error");
}
val = analyze(state, pic_list_ref(pic, obj, 2), false);
2014-03-27 22:42:57 -04:00
}
2014-03-19 08:45:02 -04:00
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;
}
#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:
2014-05-27 05:49:04 -04:00
return pic_list2(pic, pic_symbol_value(pic->sQUOTE), pic_int_value(0));
2014-03-19 08:45:02 -04:00
case 2:
return analyze(state, pic_car(pic, pic_cdr(pic, obj)), tailpos);
default:
args = pic_cdr(pic, obj);
FOLD_ARGS(pic->sADD);
return obj;
}
}
static pic_value
analyze_sub(analyze_state *state, pic_value obj)
{
pic_state *pic = state->pic;
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:
2014-05-27 05:49:04 -04:00
return pic_list2(pic, pic_symbol_value(pic->sQUOTE), pic_int_value(1));
2014-03-19 08:45:02 -04:00
case 2:
return analyze(state, pic_car(pic, pic_cdr(pic, obj)), tailpos);
default:
args = pic_cdr(pic, obj);
FOLD_ARGS(pic->sMUL);
return obj;
}
}
static pic_value
analyze_div(analyze_state *state, pic_value obj)
{
pic_state *pic = state->pic;
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 ARGC_ASSERT_WITH_FALLBACK(n) do { \
if (pic_length(pic, obj) != (n) + 1) { \
goto fallback; \
} \
} while (0)
2014-03-19 08:45:02 -04:00
#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: {
return analyze_var(state, pic_sym(obj));
2014-01-18 23:20:28 -05:00
}
case PIC_TT_PAIR: {
pic_value proc;
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
}
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_WITH_FALLBACK(2);
2014-01-18 23:20:28 -05:00
return CONSTRUCT_OP2(pic->sEQ);
}
else if (sym == state->rLT) {
ARGC_ASSERT_WITH_FALLBACK(2);
2014-01-18 23:20:28 -05:00
return CONSTRUCT_OP2(pic->sLT);
}
else if (sym == state->rLE) {
ARGC_ASSERT_WITH_FALLBACK(2);
2014-01-18 23:20:28 -05:00
return CONSTRUCT_OP2(pic->sLE);
}
else if (sym == state->rGT) {
ARGC_ASSERT_WITH_FALLBACK(2);
2014-01-18 23:20:28 -05:00
return CONSTRUCT_OP2(pic->sGT);
}
else if (sym == state->rGE) {
ARGC_ASSERT_WITH_FALLBACK(2);
2014-01-18 23:20:28 -05:00
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
}
fallback:
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-29 07:42:06 -04:00
case PIC_TT_DATA:
2014-03-29 03:55:37 -04:00
case PIC_TT_BOX:
case PIC_TT_DICT:
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);
obj = analyze(state, obj, true);
2014-01-20 02:57:39 -05:00
destroy_analyze_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-03-27 23:26:07 -04:00
pic_sym name;
2014-03-22 05:41:46 -04:00
/* rest args variable is counted as a local */
2014-03-27 23:26:07 -04:00
bool varg;
2014-03-22 05:58:25 -04:00
xvect args, locals, captures;
/* actual bit code sequence */
2014-03-07 08:06:43 -05:00
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;
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;
2013-10-23 04:25:39 -04:00
} codegen_state;
2014-03-27 23:26:07 -04:00
static void push_codegen_context(codegen_state *, pic_value, 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;
2014-03-27 23:18:24 -04:00
state = pic_alloc(pic, sizeof(codegen_state));
2013-10-23 04:25:39 -04:00
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-03-27 23:26:07 -04:00
push_codegen_context(state, pic_false_value(), 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-03-22 07:36:50 -04:00
create_activation(codegen_context *cxt)
2014-03-22 05:58:25 -04:00
{
size_t i, n;
2014-03-25 02:29:26 -04:00
xhash regs;
2014-03-22 05:58:25 -04:00
pic_sym *var;
size_t offset;
2014-03-25 02:29:26 -04:00
xh_init_int(&regs, sizeof(size_t));
2014-03-22 05:58:25 -04:00
offset = 1;
for (i = 0; i < cxt->args.size; ++i) {
var = xv_get(&cxt->args, i);
2014-03-25 02:29:26 -04:00
n = i + offset;
2014-06-14 07:59:31 -04:00
xh_put_int(&regs, *var, &n);
2014-03-22 05:58:25 -04:00
}
offset += i;
for (i = 0; i < cxt->locals.size; ++i) {
var = xv_get(&cxt->locals, i);
2014-03-25 02:29:26 -04:00
n = i + offset;
2014-06-14 07:59:31 -04:00
xh_put_int(&regs, *var, &n);
2014-03-22 05:58:25 -04:00
}
for (i = 0; i < cxt->captures.size; ++i) {
var = xv_get(&cxt->captures, i);
2014-06-14 07:59:31 -04:00
if ((n = xh_val(xh_get_int(&regs, *var), size_t)) <= cxt->args.size || (cxt->varg && n == cxt->args.size + 1)) {
/* copy arguments to capture variable area */
cxt->code[cxt->clen].insn = OP_LREF;
cxt->code[cxt->clen].u.i = n;
cxt->clen++;
} else {
/* otherwise, just extend the stack */
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
}
2014-03-22 05:58:25 -04:00
}
2014-03-25 02:29:26 -04:00
xh_destroy(&regs);
2014-03-22 05:58:25 -04:00
}
static void
2014-03-27 23:26:07 -04:00
push_codegen_context(codegen_state *state, pic_value name, pic_value args, pic_value locals, bool varg, pic_value captures)
{
2014-01-20 02:57:39 -05:00
pic_state *pic = state->pic;
codegen_context *cxt;
pic_value var;
2013-10-20 04:06:47 -04:00
2014-03-27 23:26:07 -04:00
assert(pic_sym_p(name) || pic_false_p(name));
2014-03-27 23:18:24 -04:00
cxt = pic_alloc(pic, sizeof(codegen_context));
2014-01-20 02:57:39 -05:00
cxt->up = state->cxt;
2014-03-27 23:26:07 -04:00
cxt->name = pic_false_p(name)
? pic_intern_cstr(pic, "(anonymous lambda)")
: pic_sym(name);
2014-01-27 07:20:00 -05:00
cxt->varg = varg;
xv_init(&cxt->args, sizeof(pic_sym));
xv_init(&cxt->locals, sizeof(pic_sym));
2014-03-22 05:58:25 -04:00
xv_init(&cxt->captures, sizeof(pic_sym));
pic_for_each (var, args) {
xv_push(&cxt->args, &pic_sym(var));
}
pic_for_each (var, locals) {
xv_push(&cxt->locals, &pic_sym(var));
}
2014-03-22 05:58:25 -04:00
pic_for_each (var, captures) {
xv_push(&cxt->captures, &pic_sym(var));
2014-01-27 07:20:00 -05: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;
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;
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;
2014-03-22 07:36:50 -04:00
create_activation(cxt);
2014-01-20 02:57:39 -05:00
}
static struct pic_irep *
pop_codegen_context(codegen_state *state)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
struct pic_irep *irep;
/* create irep */
2014-01-31 23:44:43 -05:00
irep = (struct pic_irep *)pic_obj_alloc(pic, sizeof(struct pic_irep), PIC_TT_IREP);
2014-03-27 23:26:07 -04:00
irep->name = state->cxt->name;
2014-01-20 02:57:39 -05:00
irep->varg = state->cxt->varg;
irep->argc = state->cxt->args.size + 1;
irep->localc = state->cxt->locals.size;
2014-03-22 06:13:07 -04:00
irep->capturec = state->cxt->captures.size;
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;
/* finalize */
xv_destroy(&cxt->args);
xv_destroy(&cxt->locals);
2014-03-22 05:58:25 -04:00
xv_destroy(&cxt->captures);
2014-01-20 02:57:39 -05:00
/* destroy context */
cxt = cxt->up;
pic_free(pic, state->cxt);
state->cxt = cxt;
return irep;
2013-10-20 04:06:47 -04:00
}
2014-03-22 22:55:06 -04:00
static int
index_capture(codegen_state *state, pic_sym sym, int depth)
{
codegen_context *cxt = state->cxt;
size_t i;
pic_sym *var;
while (depth-- > 0) {
cxt = cxt->up;
}
for (i = 0; i < cxt->captures.size; ++i) {
var = xv_get(&cxt->captures, i);
if (*var == sym)
return i;
}
return -1;
}
static int
index_local(codegen_state *state, pic_sym sym)
{
codegen_context *cxt = state->cxt;
size_t i, offset;
pic_sym *var;
offset = 1;
for (i = 0; i < cxt->args.size; ++i) {
var = xv_get(&cxt->args, i);
if (*var == sym)
return i + offset;
}
offset += i;
for (i = 0; i < cxt->locals.size; ++i) {
var = xv_get(&cxt->locals, i);
if (*var == sym)
return i + offset;
}
return -1;
}
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) {
2014-03-22 22:55:06 -04:00
pic_sym name;
int depth;
depth = pic_int(pic_list_ref(pic, obj, 1));
name = pic_sym(pic_list_ref(pic, obj, 2));
2014-01-20 02:57:39 -05:00
cxt->code[cxt->clen].insn = OP_CREF;
2014-03-22 22:55:06 -04:00
cxt->code[cxt->clen].u.r.depth = depth;
cxt->code[cxt->clen].u.r.idx = index_capture(state, name, depth);
2014-01-20 02:57:39 -05:00
cxt->clen++;
return;
2014-01-24 03:09:51 -05:00
} else if (sym == state->sLREF) {
2014-03-22 22:55:06 -04:00
pic_sym name;
int i;
2014-03-22 22:55:06 -04:00
name = pic_sym(pic_list_ref(pic, obj, 1));
if ((i = index_capture(state, name, 0)) != -1) {
cxt->code[cxt->clen].insn = OP_LREF;
cxt->code[cxt->clen].u.i = i + cxt->args.size + cxt->locals.size + 1;
cxt->clen++;
return;
2014-03-22 22:55:06 -04:00
}
2014-01-20 02:57:39 -05:00
cxt->code[cxt->clen].insn = OP_LREF;
2014-03-22 22:55:06 -04:00
cxt->code[cxt->clen].u.i = index_local(state, name);
2014-01-20 02:57:39 -05:00
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) {
2014-03-22 22:55:06 -04:00
pic_sym name;
int depth;
depth = pic_int(pic_list_ref(pic, var, 1));
name = pic_sym(pic_list_ref(pic, var, 2));
2014-01-20 02:57:39 -05:00
cxt->code[cxt->clen].insn = OP_CSET;
2014-03-22 22:55:06 -04:00
cxt->code[cxt->clen].u.r.depth = depth;
cxt->code[cxt->clen].u.r.idx = index_capture(state, name, depth);
2014-01-20 02:57:39 -05:00
cxt->clen++;
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
return;
}
else if (type == state->sLREF) {
2014-03-22 22:55:06 -04:00
pic_sym name;
int i;
2014-03-22 22:55:06 -04:00
name = pic_sym(pic_list_ref(pic, var, 1));
if ((i = index_capture(state, name, 0)) != -1) {
cxt->code[cxt->clen].insn = OP_LSET;
cxt->code[cxt->clen].u.i = i + cxt->args.size + cxt->locals.size + 1;
cxt->clen++;
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
return;
2014-03-22 22:55:06 -04:00
}
2014-01-27 08:20:08 -05:00
cxt->code[cxt->clen].insn = OP_LSET;
2014-03-22 22:55:06 -04:00
cxt->code[cxt->clen].u.i = index_local(state, name);
2014-01-20 02:57:39 -05:00
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 = 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;
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;
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;
}
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);
}
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-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-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-03-27 23:26:07 -04:00
pic_value name, args, locals, closes, body;
2014-01-27 07:20:00 -05:00
bool varg;
2013-10-23 04:25:39 -04:00
2014-03-27 23:26:07 -04:00
name = pic_list_ref(pic, obj, 1);
args = pic_list_ref(pic, obj, 2);
locals = pic_list_ref(pic, obj, 3);
varg = pic_true_p(pic_list_ref(pic, obj, 4));
closes = pic_list_ref(pic, obj, 5);
body = pic_list_ref(pic, obj, 6);
2013-10-23 04:25:39 -04:00
/* inner environment */
2014-03-27 23:26:07 -04:00
push_codegen_context(state, name, 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);
}
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
}
struct pic_proc *
pic_compile(pic_state *pic, pic_value obj)
2013-10-20 04:06:47 -04:00
{
struct pic_irep *irep;
2014-05-26 03:06:41 -04:00
size_t 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-06-22 07:09:38 -04:00
fprintf(stdout, "ai = %zu\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-06-22 07:09:38 -04:00
fprintf(stdout, "ai = %zu\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");
2014-06-22 07:09:38 -04:00
fprintf(stdout, "ai = %zu\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");
2014-06-22 07:09:38 -04:00
fprintf(stdout, "ai = %zu\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));
return pic_proc_new_irep(pic, irep, NULL);
2013-10-20 04:06:47 -04:00
}