picrin/extlib/benz/codegen.c

1146 lines
29 KiB
C
Raw Normal View History

2014-08-25 00:38:09 -04:00
/**
* See Copyright Notice in picrin.h
*/
#include "picrin.h"
2015-07-08 15:40:15 -04:00
#include "picrin/opcode.h"
2014-08-25 00:38:09 -04:00
2015-06-16 08:01:46 -04:00
/**
* macro expander
*/
static void
define_macro(pic_state *pic, pic_sym *uid, struct pic_proc *mac)
{
2015-08-04 20:42:17 -04:00
if (pic_reg_has(pic, pic->macros, uid)) {
pic_warnf(pic, "redefining syntax variable: ~s", pic_obj_value(uid));
}
2015-08-04 20:42:17 -04:00
pic_reg_set(pic, pic->macros, uid, pic_obj_value(mac));
2015-06-16 08:01:46 -04:00
}
static struct pic_proc *
find_macro(pic_state *pic, pic_sym *uid)
{
2015-08-04 20:42:17 -04:00
if (! pic_reg_has(pic, pic->macros, uid)) {
2015-06-16 08:01:46 -04:00
return NULL;
}
2015-08-04 20:42:17 -04:00
return pic_proc_ptr(pic_reg_ref(pic, pic->macros, uid));
2015-06-16 08:01:46 -04:00
}
2015-06-22 04:41:17 -04:00
static void
shadow_macro(pic_state *pic, pic_sym *uid)
{
2015-08-04 20:42:17 -04:00
if (pic_reg_has(pic, pic->macros, uid)) {
pic_reg_del(pic, pic->macros, uid);
2015-06-22 04:41:17 -04:00
}
}
2015-06-16 08:01:46 -04:00
static pic_value expand(pic_state *, pic_value, struct pic_env *, pic_value);
static pic_value expand_lambda(pic_state *, pic_value, struct pic_env *);
static pic_value
2015-06-28 14:52:00 -04:00
expand_var(pic_state *pic, pic_value var, struct pic_env *env, pic_value deferred)
2015-06-16 08:01:46 -04:00
{
2015-06-28 14:52:00 -04:00
struct pic_proc *mac;
pic_sym *functor;
functor = pic_resolve_variable(pic, env, var);
2015-06-28 14:52:00 -04:00
if ((mac = find_macro(pic, functor)) != NULL) {
return expand(pic, pic_apply2(pic, mac, var, pic_obj_value(env)), env, deferred);
}
return pic_obj_value(functor);
2015-06-16 08:01:46 -04:00
}
static pic_value
expand_quote(pic_state *pic, pic_value expr)
{
return pic_cons(pic, pic_obj_value(pic->sQUOTE), pic_cdr(pic, expr));
2015-06-16 08:01:46 -04:00
}
static pic_value
expand_list(pic_state *pic, pic_value obj, struct pic_env *env, pic_value deferred)
{
size_t ai = pic_gc_arena_preserve(pic);
pic_value x, head, tail;
if (pic_pair_p(obj)) {
head = expand(pic, pic_car(pic, obj), env, deferred);
tail = expand_list(pic, pic_cdr(pic, obj), env, deferred);
x = pic_cons(pic, head, tail);
} else {
x = expand(pic, obj, env, deferred);
}
pic_gc_arena_restore(pic, ai);
pic_gc_protect(pic, x);
return x;
}
static pic_value
expand_defer(pic_state *pic, pic_value expr, pic_value deferred)
{
2015-07-01 15:36:21 -04:00
pic_value skel = pic_cons(pic, pic_invalid_value(), pic_invalid_value());
2015-06-16 08:01:46 -04:00
pic_set_car(pic, deferred, pic_acons(pic, expr, skel, pic_car(pic, deferred)));
return skel;
}
static void
expand_deferred(pic_state *pic, pic_value deferred, struct pic_env *env)
{
pic_value defer, val, src, dst, it;
deferred = pic_car(pic, deferred);
pic_for_each (defer, pic_reverse(pic, deferred), it) {
src = pic_car(pic, defer);
dst = pic_cdr(pic, defer);
val = expand_lambda(pic, src, env);
/* copy */
pic_set_car(pic, dst, pic_car(pic, val));
pic_set_cdr(pic, dst, pic_cdr(pic, val));
}
}
static pic_value
expand_lambda(pic_state *pic, pic_value expr, struct pic_env *env)
{
pic_value formal, body;
struct pic_env *in;
pic_value a, deferred;
in = pic_make_env(pic, env);
for (a = pic_cadr(pic, expr); pic_pair_p(a); a = pic_cdr(pic, a)) {
2015-06-27 04:50:14 -04:00
pic_add_variable(pic, in, pic_car(pic, a));
2015-06-16 08:01:46 -04:00
}
if (pic_var_p(a)) {
pic_add_variable(pic, in, a);
}
deferred = pic_list1(pic, pic_nil_value());
2015-06-27 05:47:16 -04:00
formal = expand_list(pic, pic_list_ref(pic, expr, 1), in, deferred);
body = expand(pic, pic_list_ref(pic, expr, 2), in, deferred);
2015-06-16 08:01:46 -04:00
expand_deferred(pic, deferred, in);
return pic_list3(pic, pic_obj_value(pic->sLAMBDA), formal, body);
2015-06-16 08:01:46 -04:00
}
static pic_value
expand_define(pic_state *pic, pic_value expr, struct pic_env *env, pic_value deferred)
{
pic_sym *uid;
pic_value var, val;
var = pic_cadr(pic, expr);
if ((uid = pic_find_variable(pic, env, var)) == NULL) {
uid = pic_add_variable(pic, env, var);
2015-06-22 04:41:17 -04:00
} else {
shadow_macro(pic, uid);
2015-06-16 08:01:46 -04:00
}
val = expand(pic, pic_list_ref(pic, expr, 2), env, deferred);
return pic_list3(pic, pic_obj_value(pic->sDEFINE), pic_obj_value(uid), val);
2015-06-16 08:01:46 -04:00
}
static pic_value
expand_defmacro(pic_state *pic, pic_value expr, struct pic_env *env)
{
pic_value var, val;
pic_sym *uid;
var = pic_cadr(pic, expr);
if ((uid = pic_find_variable(pic, env, var)) == NULL) {
uid = pic_add_variable(pic, env, var);
}
val = pic_eval(pic, pic_list_ref(pic, expr, 2), env);
2015-06-16 08:01:46 -04:00
if (! pic_proc_p(val)) {
pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", var);
}
define_macro(pic, uid, pic_proc_ptr(val));
return pic_undef_value();
}
static pic_value
expand_node(pic_state *pic, pic_value expr, struct pic_env *env, pic_value deferred)
{
switch (pic_type(expr)) {
case PIC_TT_ID:
case PIC_TT_SYMBOL: {
2015-06-28 14:52:00 -04:00
return expand_var(pic, expr, env, deferred);
2015-06-16 08:01:46 -04:00
}
case PIC_TT_PAIR: {
struct pic_proc *mac;
if (! pic_list_p(expr)) {
pic_errorf(pic, "cannot expand improper list: ~s", expr);
}
if (pic_var_p(pic_car(pic, expr))) {
pic_sym *functor;
functor = pic_resolve_variable(pic, env, pic_car(pic, expr));
2015-06-16 08:01:46 -04:00
if (functor == pic->sDEFINE_MACRO) {
2015-06-16 08:01:46 -04:00
return expand_defmacro(pic, expr, env);
}
else if (functor == pic->sLAMBDA) {
2015-06-16 08:01:46 -04:00
return expand_defer(pic, expr, deferred);
}
else if (functor == pic->sDEFINE) {
2015-06-16 08:01:46 -04:00
return expand_define(pic, expr, env, deferred);
}
else if (functor == pic->sQUOTE) {
2015-06-16 08:01:46 -04:00
return expand_quote(pic, expr);
}
if ((mac = find_macro(pic, functor)) != NULL) {
2015-06-28 14:52:00 -04:00
return expand(pic, pic_apply2(pic, mac, expr, pic_obj_value(env)), env, deferred);
2015-06-16 08:01:46 -04:00
}
}
return expand_list(pic, expr, env, deferred);
}
default:
return expr;
}
}
static pic_value
expand(pic_state *pic, pic_value expr, struct pic_env *env, pic_value deferred)
{
size_t ai = pic_gc_arena_preserve(pic);
pic_value v;
v = expand_node(pic, expr, env, deferred);
pic_gc_arena_restore(pic, ai);
pic_gc_protect(pic, v);
return v;
}
pic_value
pic_expand(pic_state *pic, pic_value expr, struct pic_env *env)
{
pic_value v, deferred;
#if DEBUG
puts("before expand:");
pic_debug(pic, expr);
puts("");
#endif
deferred = pic_list1(pic, pic_nil_value());
v = expand(pic, expr, env, deferred);
expand_deferred(pic, deferred, env);
#if DEBUG
puts("after expand:");
pic_debug(pic, v);
puts("");
#endif
return v;
}
2015-07-22 03:09:31 -04:00
static pic_value
optimize_beta(pic_state *pic, pic_value expr)
{
size_t ai = pic_gc_arena_preserve(pic);
pic_value functor, formals, args, tmp, val, it, defs;
if (! pic_list_p(expr))
return expr;
if (pic_nil_p(expr))
return expr;
if (pic_sym_p(pic_list_ref(pic, expr, 0))) {
pic_sym *sym = pic_sym_ptr(pic_list_ref(pic, expr, 0));
if (sym == pic->sQUOTE) {
2015-07-22 03:09:31 -04:00
return expr;
} else if (sym == pic->sLAMBDA) {
2015-07-22 03:09:31 -04:00
return pic_list3(pic, pic_list_ref(pic, expr, 0), pic_list_ref(pic, expr, 1), optimize_beta(pic, pic_list_ref(pic, expr, 2)));
}
}
tmp = pic_nil_value();
pic_for_each (val, expr, it) {
pic_push(pic, optimize_beta(pic, val), tmp);
}
expr = pic_reverse(pic, tmp);
pic_gc_arena_restore(pic, ai);
pic_gc_protect(pic, expr);
functor = pic_list_ref(pic, expr, 0);
if (pic_pair_p(functor) && pic_eq_p(pic_car(pic, functor), pic_obj_value(pic->sLAMBDA))) {
2015-07-22 03:09:31 -04:00
formals = pic_list_ref(pic, functor, 1);
if (! pic_list_p(formals))
goto exit; /* TODO: support ((lambda args x) 1 2) */
args = pic_cdr(pic, expr);
if (pic_length(pic, formals) != pic_length(pic, args))
goto exit;
defs = pic_nil_value();
pic_for_each (val, args, it) {
pic_push(pic, pic_list3(pic, pic_obj_value(pic->sDEFINE), pic_car(pic, formals), val), defs);
2015-07-22 03:09:31 -04:00
formals = pic_cdr(pic, formals);
}
expr = pic_list_ref(pic, functor, 2);
pic_for_each (val, defs, it) {
expr = pic_list3(pic, pic_obj_value(pic->sBEGIN), val, expr);
2015-07-22 03:09:31 -04:00
}
}
exit:
pic_gc_arena_restore(pic, ai);
pic_gc_protect(pic, expr);
return expr;
}
pic_value
pic_optimize(pic_state *pic, pic_value expr)
{
return optimize_beta(pic, expr);
}
2015-06-27 02:30:17 -04:00
KHASH_DECLARE(a, pic_sym *, int)
KHASH_DEFINE2(a, pic_sym *, int, 0, kh_ptr_hash_func, kh_ptr_hash_equal)
2015-01-22 08:15:12 -05:00
/**
* TODO: don't use khash_t, use kvec_t instead
*/
2014-08-25 00:38:09 -04:00
typedef struct analyze_scope {
int depth;
2015-06-27 02:30:17 -04:00
pic_sym *rest; /* Nullable */
khash_t(a) args, locals, captures; /* rest args variable is counted as a local */
pic_value defer;
2014-08-25 00:38:09 -04:00
struct analyze_scope *up;
} analyze_scope;
2015-06-27 05:47:16 -04:00
static void
analyzer_scope_init(pic_state *pic, analyze_scope *scope, pic_value formal, analyze_scope *up)
2014-08-25 00:38:09 -04:00
{
2015-06-27 05:47:16 -04:00
int ret;
2015-06-27 03:33:31 -04:00
kh_init(a, &scope->args);
kh_init(a, &scope->locals);
kh_init(a, &scope->captures);
2015-06-27 05:47:16 -04:00
/* analyze formal */
for (; pic_pair_p(formal); formal = pic_cdr(pic, formal)) {
kh_put(a, &scope->args, pic_sym_ptr(pic_car(pic, formal)), &ret);
}
if (pic_nil_p(formal)) {
scope->rest = NULL;
2015-06-27 03:33:31 -04:00
}
else {
2015-06-27 05:47:16 -04:00
scope->rest = pic_sym_ptr(formal);
kh_put(a, &scope->locals, pic_sym_ptr(formal), &ret);
2015-06-27 03:33:31 -04:00
}
2015-06-27 05:47:16 -04:00
scope->up = up;
scope->depth = up ? up->depth + 1 : 0;
2015-07-01 15:36:21 -04:00
scope->defer = pic_list1(pic, pic_nil_value());
2014-08-25 00:38:09 -04:00
}
static void
2015-06-27 03:33:31 -04:00
analyzer_scope_destroy(pic_state *pic, analyze_scope *scope)
2014-08-25 00:38:09 -04:00
{
2015-06-27 03:33:31 -04:00
kh_destroy(a, &scope->args);
kh_destroy(a, &scope->locals);
kh_destroy(a, &scope->captures);
2014-08-25 00:38:09 -04:00
}
static bool
2015-06-27 03:44:05 -04:00
search_scope(analyze_scope *scope, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
2015-06-27 02:59:22 -04:00
return kh_get(a, &scope->args, sym) != kh_end(&scope->args) || kh_get(a, &scope->locals, sym) != kh_end(&scope->locals) || scope->depth == 0;
2014-08-25 00:38:09 -04:00
}
static int
2015-06-27 03:33:31 -04:00
find_var(pic_state *pic, analyze_scope *scope, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
2015-06-27 11:21:25 -04:00
int depth = 0, ret;
2014-08-25 00:38:09 -04:00
while (scope) {
2015-06-27 03:44:05 -04:00
if (search_scope(scope, sym)) {
2014-08-25 00:38:09 -04:00
if (depth > 0) {
2015-06-27 11:21:25 -04:00
kh_put(a, &scope->captures, sym, &ret); /* capture! */
2014-08-25 00:38:09 -04:00
}
return depth;
}
depth++;
scope = scope->up;
}
2015-06-27 03:44:05 -04:00
PIC_UNREACHABLE();
2014-08-25 00:38:09 -04:00
}
static void
2015-06-27 03:33:31 -04:00
define_var(pic_state *pic, analyze_scope *scope, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
2015-06-27 02:30:17 -04:00
int ret;
2014-08-25 00:38:09 -04:00
2015-06-27 03:44:05 -04:00
if (search_scope(scope, sym)) {
2015-08-04 20:36:32 -04:00
if (scope->depth > 0 || (pic_reg_has(pic, pic->globals, sym) && ! pic_invalid_p(pic_box_ptr(pic_reg_ref(pic, pic->globals, sym))->value))) {
2015-06-27 02:59:22 -04:00
pic_warnf(pic, "redefining variable: ~s", pic_obj_value(sym));
}
2014-08-25 00:38:09 -04:00
return;
}
2015-06-27 02:30:17 -04:00
kh_put(a, &scope->locals, sym, &ret);
2014-08-25 00:38:09 -04:00
}
static pic_value analyze(pic_state *, analyze_scope *, pic_value);
2015-06-27 11:29:28 -04:00
static pic_value analyze_lambda(pic_state *, analyze_scope *, pic_value);
2014-08-25 00:38:09 -04:00
2015-08-25 06:37:20 -04:00
#define GREF pic_intern(pic, "gref")
#define LREF pic_intern(pic, "lref")
#define CREF pic_intern(pic, "cref")
#define CALL pic_intern(pic, "call")
2014-08-25 00:38:09 -04:00
static pic_value
2015-06-27 03:33:31 -04:00
analyze_var(pic_state *pic, analyze_scope *scope, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
int depth;
2015-06-27 03:44:05 -04:00
depth = find_var(pic, scope, sym);
2014-08-25 00:38:09 -04:00
2015-06-27 03:33:31 -04:00
if (depth == scope->depth) {
2015-08-25 06:37:20 -04:00
return pic_list2(pic, pic_obj_value(GREF), pic_obj_value(sym));
2014-08-25 00:38:09 -04:00
} else if (depth == 0) {
2015-08-25 06:37:20 -04:00
return pic_list2(pic, pic_obj_value(LREF), pic_obj_value(sym));
2014-08-25 00:38:09 -04:00
} else {
2015-08-25 06:37:20 -04:00
return pic_list3(pic, pic_obj_value(CREF), pic_int_value(depth), pic_obj_value(sym));
2014-08-25 00:38:09 -04:00
}
}
static pic_value
2015-06-27 06:19:43 -04:00
analyze_defer(pic_state *pic, analyze_scope *scope, pic_value form)
{
2015-07-01 15:36:21 -04:00
pic_value skel = pic_cons(pic, pic_invalid_value(), pic_invalid_value());
2015-07-01 15:36:21 -04:00
pic_set_car(pic, scope->defer, pic_acons(pic, form, skel, pic_car(pic, scope->defer)));
return skel;
}
static void
2015-06-27 03:33:31 -04:00
analyze_deferred(pic_state *pic, analyze_scope *scope)
{
2015-07-01 15:36:21 -04:00
pic_value defer, val, src, dst, it;
scope->defer = pic_car(pic, scope->defer);
2015-06-27 03:33:31 -04:00
pic_for_each (defer, pic_reverse(pic, scope->defer), it) {
2015-07-01 15:36:21 -04:00
src = pic_car(pic, defer);
dst = pic_cdr(pic, defer);
2015-07-01 15:36:21 -04:00
val = analyze_lambda(pic, scope, src);
/* copy */
2015-07-01 15:36:21 -04:00
pic_set_car(pic, dst, pic_car(pic, val));
pic_set_cdr(pic, dst, pic_cdr(pic, val));
}
}
2014-08-25 00:38:09 -04:00
static pic_value
2015-06-27 11:29:28 -04:00
analyze_lambda(pic_state *pic, analyze_scope *up, pic_value form)
2014-08-25 00:38:09 -04:00
{
2015-06-27 03:33:31 -04:00
analyze_scope s, *scope = &s;
2015-06-27 06:19:43 -04:00
pic_value formals, body;
2015-06-27 05:47:16 -04:00
pic_value rest = pic_undef_value();
2015-06-27 02:30:17 -04:00
pic_vec *args, *locals, *captures;
2015-08-26 06:04:27 -04:00
int i, j;
2015-07-12 20:13:19 -04:00
khiter_t it;
2014-08-25 00:38:09 -04:00
2015-06-27 06:19:43 -04:00
formals = pic_list_ref(pic, form, 1);
body = pic_list_ref(pic, form, 2);
2015-06-27 05:47:16 -04:00
analyzer_scope_init(pic, scope, formals, up);
2014-08-25 00:38:09 -04:00
2015-06-27 05:47:16 -04:00
/* analyze body */
body = analyze(pic, scope, body);
2015-06-27 05:47:16 -04:00
analyze_deferred(pic, scope);
2015-06-27 05:47:16 -04:00
args = pic_make_vec(pic, kh_size(&scope->args));
for (i = 0; pic_pair_p(formals); formals = pic_cdr(pic, formals), i++) {
args->data[i] = pic_car(pic, formals);
}
2015-06-27 02:30:17 -04:00
2015-06-27 05:47:16 -04:00
if (scope->rest != NULL) {
rest = pic_obj_value(scope->rest);
}
2014-08-25 00:38:09 -04:00
2015-06-27 05:47:16 -04:00
locals = pic_make_vec(pic, kh_size(&scope->locals));
j = 0;
if (scope->rest != NULL) {
locals->data[j++] = pic_obj_value(scope->rest);
}
for (it = kh_begin(&scope->locals); it < kh_end(&scope->locals); ++it) {
2015-07-12 20:13:19 -04:00
if (kh_exist(&scope->locals, it)) {
if (scope->rest != NULL && kh_key(&scope->locals, it) == scope->rest)
continue;
2015-07-12 20:13:19 -04:00
locals->data[j++] = pic_obj_value(kh_key(&scope->locals, it));
2015-06-27 02:30:17 -04:00
}
2015-06-27 05:47:16 -04:00
}
2015-06-27 02:30:17 -04:00
2015-06-27 05:47:16 -04:00
captures = pic_make_vec(pic, kh_size(&scope->captures));
2015-07-12 20:13:19 -04:00
for (it = kh_begin(&scope->captures), j = 0; it < kh_end(&scope->captures); ++it) {
if (kh_exist(&scope->captures, it)) {
captures->data[j++] = pic_obj_value(kh_key(&scope->captures, it));
2014-08-25 00:38:09 -04:00
}
}
2015-06-27 05:47:16 -04:00
analyzer_scope_destroy(pic, scope);
return pic_list6(pic, pic_obj_value(pic->sLAMBDA), rest, pic_obj_value(args), pic_obj_value(locals), pic_obj_value(captures), body);
2014-08-25 00:38:09 -04:00
}
static pic_value
analyze_list(pic_state *pic, analyze_scope *scope, pic_value obj)
2014-08-25 00:38:09 -04:00
{
pic_value seq = pic_nil_value(), val, it;
2014-08-25 00:38:09 -04:00
pic_for_each (val, obj, it) {
pic_push(pic, analyze(pic, scope, val), seq);
2014-08-25 00:38:09 -04:00
}
return pic_reverse(pic, seq);
}
static pic_value
analyze_define(pic_state *pic, analyze_scope *scope, pic_value obj)
2014-08-25 00:38:09 -04:00
{
define_var(pic, scope, pic_sym_ptr(pic_list_ref(pic, obj, 1)));
2014-08-25 00:38:09 -04:00
return pic_cons(pic, pic_car(pic, obj), analyze_list(pic, scope, pic_cdr(pic, obj)));
2014-08-25 00:38:09 -04:00
}
static pic_value
analyze_call(pic_state *pic, analyze_scope *scope, pic_value obj)
2014-08-25 00:38:09 -04:00
{
2015-08-25 06:37:20 -04:00
return pic_cons(pic, pic_obj_value(CALL), analyze_list(pic, scope, obj));
2014-08-25 00:38:09 -04:00
}
static pic_value
analyze_node(pic_state *pic, analyze_scope *scope, pic_value obj)
2014-08-25 00:38:09 -04:00
{
switch (pic_type(obj)) {
case PIC_TT_SYMBOL: {
2015-06-27 03:33:31 -04:00
return analyze_var(pic, scope, pic_sym_ptr(obj));
2014-08-25 00:38:09 -04:00
}
case PIC_TT_PAIR: {
pic_value proc;
if (! pic_list_p(obj)) {
pic_errorf(pic, "invalid expression given: ~s", obj);
}
proc = pic_list_ref(pic, obj, 0);
if (pic_sym_p(proc)) {
2015-01-20 02:02:28 -05:00
pic_sym *sym = pic_sym_ptr(proc);
2014-08-25 00:38:09 -04:00
if (sym == pic->sDEFINE) {
2015-06-27 03:33:31 -04:00
return analyze_define(pic, scope, obj);
2014-08-25 00:38:09 -04:00
}
else if (sym == pic->sLAMBDA) {
2015-06-27 06:19:43 -04:00
return analyze_defer(pic, scope, obj);
2014-08-25 00:38:09 -04:00
}
else if (sym == pic->sQUOTE) {
return obj;
2014-08-25 00:38:09 -04:00
}
else if (sym == pic->sBEGIN || sym == pic->sSETBANG || sym == pic->sIF) {
return pic_cons(pic, pic_car(pic, obj), analyze_list(pic, scope, pic_cdr(pic, obj)));
2014-08-25 00:38:09 -04:00
}
}
return analyze_call(pic, scope, obj);
2014-08-25 00:38:09 -04:00
}
default:
return pic_list2(pic, pic_obj_value(pic->sQUOTE), obj);
2014-08-25 00:38:09 -04:00
}
}
2015-06-27 11:29:28 -04:00
static pic_value
analyze(pic_state *pic, analyze_scope *scope, pic_value obj)
2015-06-27 11:29:28 -04:00
{
size_t ai = pic_gc_arena_preserve(pic);
pic_value res;
res = analyze_node(pic, scope, obj);
2015-06-27 11:29:28 -04:00
pic_gc_arena_restore(pic, ai);
pic_gc_protect(pic, res);
return res;
}
2014-08-25 00:38:09 -04:00
pic_value
pic_analyze(pic_state *pic, pic_value obj)
{
2015-06-27 03:33:31 -04:00
analyze_scope s, *scope = &s;
2014-08-25 00:38:09 -04:00
2015-06-27 03:33:31 -04:00
analyzer_scope_init(pic, scope, pic_nil_value(), NULL);
2014-08-25 00:38:09 -04:00
obj = analyze(pic, scope, obj);
2014-08-25 00:38:09 -04:00
2015-06-27 03:33:31 -04:00
analyze_deferred(pic, scope);
2015-06-27 03:33:31 -04:00
analyzer_scope_destroy(pic, scope);
2014-08-25 00:38:09 -04:00
return obj;
}
typedef struct codegen_context {
/* rest args variable is counted as a local */
2015-06-27 02:30:17 -04:00
pic_sym *rest;
pic_vec *args, *locals, *captures;
2014-08-25 00:38:09 -04:00
/* actual bit code sequence */
pic_code *code;
size_t clen, ccapa;
/* child ireps */
2016-02-06 04:15:15 -05:00
union irep_node *irep;
2014-08-25 00:38:09 -04:00
size_t ilen, icapa;
/* constant object pool */
2016-02-05 07:41:20 -05:00
int *ints;
size_t klen, kcapa;
2016-02-06 06:52:36 -05:00
double *nums;
size_t flen, fcapa;
2014-08-25 00:38:09 -04:00
pic_value *pool;
size_t plen, pcapa;
struct codegen_context *up;
} codegen_context;
2015-06-27 03:33:31 -04:00
static void create_activation(pic_state *, codegen_context *);
2014-08-25 00:38:09 -04:00
static void
2015-06-27 06:02:18 -04:00
codegen_context_init(pic_state *pic, codegen_context *cxt, codegen_context *up, pic_sym *rest, pic_vec *args, pic_vec *locals, pic_vec *captures)
2014-08-25 00:38:09 -04:00
{
2015-06-27 03:33:31 -04:00
cxt->up = up;
cxt->rest = rest;
cxt->args = args;
cxt->locals = locals;
cxt->captures = captures;
cxt->code = pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(pic_code));
cxt->clen = 0;
cxt->ccapa = PIC_ISEQ_SIZE;
2015-06-27 02:30:17 -04:00
2016-02-06 04:15:15 -05:00
cxt->irep = pic_calloc(pic, PIC_IREP_SIZE, sizeof(union irep_node));
2015-06-27 03:33:31 -04:00
cxt->ilen = 0;
cxt->icapa = PIC_IREP_SIZE;
2014-08-25 00:38:09 -04:00
2015-06-27 03:33:31 -04:00
cxt->pool = pic_calloc(pic, PIC_POOL_SIZE, sizeof(pic_value));
cxt->plen = 0;
cxt->pcapa = PIC_POOL_SIZE;
2016-02-05 07:41:20 -05:00
cxt->ints = pic_calloc(pic, PIC_POOL_SIZE, sizeof(int));
cxt->klen = 0;
cxt->kcapa = PIC_POOL_SIZE;
2016-02-06 06:52:36 -05:00
cxt->nums = pic_calloc(pic, PIC_POOL_SIZE, sizeof(double));
cxt->flen = 0;
cxt->fcapa = PIC_POOL_SIZE;
2015-06-27 03:33:31 -04:00
create_activation(pic, cxt);
2014-08-25 00:38:09 -04:00
}
static struct pic_irep *
2015-06-27 03:33:31 -04:00
codegen_context_destroy(pic_state *pic, codegen_context *cxt)
2014-08-25 00:38:09 -04:00
{
struct pic_irep *irep;
2015-06-27 03:33:31 -04:00
/* create irep */
2016-02-04 10:30:11 -05:00
irep = pic_malloc(pic, sizeof(struct pic_irep));
irep->refc = 1;
2015-06-27 03:33:31 -04:00
irep->varg = cxt->rest != NULL;
irep->argc = (int)cxt->args->len + 1;
irep->localc = (int)cxt->locals->len;
irep->capturec = (int)cxt->captures->len;
2016-02-06 04:15:15 -05:00
irep->u.s.code = pic_realloc(pic, cxt->code, sizeof(pic_code) * cxt->clen);
irep->u.s.irep = pic_realloc(pic, cxt->irep, sizeof(union irep_node) * cxt->ilen);
irep->u.s.ints = pic_realloc(pic, cxt->ints, sizeof(int) * cxt->klen);
2016-02-06 06:52:36 -05:00
irep->u.s.nums = pic_realloc(pic, cxt->nums, sizeof(double) * cxt->flen);
2015-06-27 03:33:31 -04:00
irep->pool = pic_realloc(pic, cxt->pool, sizeof(pic_value) * cxt->plen);
2016-02-06 04:15:15 -05:00
irep->ncode = cxt->clen;
irep->nirep = cxt->ilen;
irep->nints = cxt->klen;
2016-02-06 06:52:36 -05:00
irep->nnums = cxt->flen;
2016-02-06 04:15:15 -05:00
irep->npool = cxt->plen;
2014-08-25 00:38:09 -04:00
2016-02-04 10:30:11 -05:00
irep->list.next = pic->ireps.next;
irep->list.prev = &pic->ireps;
irep->list.next->prev = &irep->list;
irep->list.prev->next = &irep->list;
2014-08-25 00:38:09 -04:00
return irep;
}
2015-06-27 11:25:02 -04:00
#define check_size(pic, cxt, x, name, type) do { \
if (cxt->x##len >= cxt->x##capa) { \
cxt->x##capa *= 2; \
cxt->name = pic_realloc(pic, cxt->name, sizeof(type) * cxt->x##capa); \
} \
} while (0)
2015-06-27 11:25:02 -04:00
#define check_code_size(pic, cxt) check_size(pic, cxt, c, code, pic_code)
#define check_irep_size(pic, cxt) check_size(pic, cxt, i, irep, struct pic_irep *)
#define check_pool_size(pic, cxt) check_size(pic, cxt, p, pool, pic_value)
2016-02-06 06:52:36 -05:00
#define check_ints_size(pic, cxt) check_size(pic, cxt, k, ints, int)
#define check_nums_size(pic, cxt) check_size(pic, cxt, f, nums, double)
2015-06-27 11:25:02 -04:00
#define emit_n(pic, cxt, ins) do { \
check_code_size(pic, cxt); \
cxt->code[cxt->clen].insn = ins; \
cxt->clen++; \
} while (0) \
#define emit_i(pic, cxt, ins, I) do { \
check_code_size(pic, cxt); \
cxt->code[cxt->clen].insn = ins; \
2016-02-05 07:53:25 -05:00
cxt->code[cxt->clen].a = I; \
2015-06-27 11:25:02 -04:00
cxt->clen++; \
} while (0) \
#define emit_r(pic, cxt, ins, D, I) do { \
check_code_size(pic, cxt); \
cxt->code[cxt->clen].insn = ins; \
2016-02-05 07:53:25 -05:00
cxt->code[cxt->clen].a = D; \
cxt->code[cxt->clen].b = I; \
2015-06-27 11:25:02 -04:00
cxt->clen++; \
} while (0) \
2015-07-04 01:02:29 -04:00
#define emit_ret(pic, cxt, tailpos) if (tailpos) emit_n(pic, cxt, OP_RET)
2015-07-01 16:07:16 -04:00
2014-08-25 00:38:09 -04:00
static int
2015-06-27 03:33:31 -04:00
index_capture(codegen_context *cxt, pic_sym *sym, int depth)
2014-08-25 00:38:09 -04:00
{
2015-08-26 06:04:27 -04:00
int i;
2014-08-25 00:38:09 -04:00
while (depth-- > 0) {
cxt = cxt->up;
}
2015-06-27 02:30:17 -04:00
for (i = 0; i < cxt->captures->len; ++i) {
if (pic_sym_ptr(cxt->captures->data[i]) == sym)
2015-08-26 06:04:27 -04:00
return i;
2014-08-25 00:38:09 -04:00
}
return -1;
}
static int
2015-06-27 03:33:31 -04:00
index_local(codegen_context *cxt, pic_sym *sym)
2014-08-25 00:38:09 -04:00
{
2015-08-26 06:04:27 -04:00
int i, offset;
2014-08-25 00:38:09 -04:00
offset = 1;
2015-06-27 02:30:17 -04:00
for (i = 0; i < cxt->args->len; ++i) {
if (pic_sym_ptr(cxt->args->data[i]) == sym)
2015-08-26 06:04:27 -04:00
return i + offset;
2014-08-25 00:38:09 -04:00
}
offset += i;
2015-06-27 02:30:17 -04:00
for (i = 0; i < cxt->locals->len; ++i) {
if (pic_sym_ptr(cxt->locals->data[i]) == sym)
2015-08-26 06:04:27 -04:00
return i + offset;
2014-08-25 00:38:09 -04:00
}
return -1;
}
2015-01-18 11:29:00 -05:00
static int
2015-07-07 01:42:50 -04:00
index_global(pic_state *pic, codegen_context *cxt, pic_sym *name)
2015-01-18 11:29:00 -05:00
{
2015-08-04 20:03:09 -04:00
extern struct pic_box *pic_vm_gref_slot(pic_state *, pic_sym *);
2015-07-07 01:42:50 -04:00
int pidx;
2015-08-04 20:03:09 -04:00
struct pic_box *slot;
2015-01-18 11:29:00 -05:00
2015-07-07 01:42:50 -04:00
slot = pic_vm_gref_slot(pic, name);
check_pool_size(pic, cxt);
pidx = (int)cxt->plen++;
2015-08-04 20:03:09 -04:00
cxt->pool[pidx] = pic_obj_value(slot);
2015-07-07 01:42:50 -04:00
return pidx;
2015-01-18 11:29:00 -05:00
}
2015-07-04 04:24:39 -04:00
static void
create_activation(pic_state *pic, codegen_context *cxt)
{
2015-08-26 06:04:27 -04:00
int i, n;
2015-07-04 04:24:39 -04:00
for (i = 0; i < cxt->captures->len; ++i) {
n = index_local(cxt, pic_sym_ptr(cxt->captures->data[i]));
assert(n != -1);
2015-08-26 06:04:27 -04:00
if (n <= cxt->args->len || cxt->rest == pic_sym_ptr(cxt->captures->data[i])) {
2015-07-04 04:24:39 -04:00
/* copy arguments to capture variable area */
emit_i(pic, cxt, OP_LREF, n);
} else {
/* otherwise, just extend the stack */
emit_n(pic, cxt, OP_PUSHUNDEF);
}
}
}
static void codegen(pic_state *, codegen_context *, pic_value, bool);
2015-06-27 11:29:28 -04:00
2014-08-25 00:38:09 -04:00
static void
2015-07-01 16:07:16 -04:00
codegen_ref(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
2014-08-25 00:38:09 -04:00
{
2015-01-20 02:02:28 -05:00
pic_sym *sym;
2014-08-25 00:38:09 -04:00
2015-01-20 01:31:17 -05:00
sym = pic_sym_ptr(pic_car(pic, obj));
2015-08-25 06:37:20 -04:00
if (sym == GREF) {
2015-07-07 01:42:50 -04:00
pic_sym *name;
name = pic_sym_ptr(pic_list_ref(pic, obj, 1));
emit_i(pic, cxt, OP_GREF, index_global(pic, cxt, name));
emit_ret(pic, cxt, tailpos);
2015-07-01 14:33:25 -04:00
}
2015-08-25 06:37:20 -04:00
else if (sym == CREF) {
2015-01-20 02:02:28 -05:00
pic_sym *name;
2014-08-25 00:38:09 -04:00
int depth;
depth = pic_int(pic_list_ref(pic, obj, 1));
2015-01-20 01:31:17 -05:00
name = pic_sym_ptr(pic_list_ref(pic, obj, 2));
2015-06-27 03:33:31 -04:00
emit_r(pic, cxt, OP_CREF, depth, index_capture(cxt, name, depth));
emit_ret(pic, cxt, tailpos);
2015-07-01 14:33:25 -04:00
}
2015-08-25 06:37:20 -04:00
else if (sym == LREF) {
2015-01-20 02:02:28 -05:00
pic_sym *name;
2014-08-25 00:38:09 -04:00
int i;
2015-01-20 01:31:17 -05:00
name = pic_sym_ptr(pic_list_ref(pic, obj, 1));
2015-06-27 03:33:31 -04:00
if ((i = index_capture(cxt, name, 0)) != -1) {
emit_i(pic, cxt, OP_LREF, i + (int)cxt->args->len + (int)cxt->locals->len + 1);
emit_ret(pic, cxt, tailpos);
2015-07-01 16:07:16 -04:00
} else {
emit_i(pic, cxt, OP_LREF, index_local(cxt, name));
emit_ret(pic, cxt, tailpos);
2014-08-25 00:38:09 -04:00
}
2015-07-01 14:33:25 -04:00
}
2015-07-01 16:07:16 -04:00
}
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
static void
codegen_set(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
{
pic_value var, val;
pic_sym *type;
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
val = pic_list_ref(pic, obj, 2);
codegen(pic, cxt, val, false);
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
var = pic_list_ref(pic, obj, 1);
type = pic_sym_ptr(pic_list_ref(pic, var, 0));
2015-08-25 06:37:20 -04:00
if (type == GREF) {
2015-07-07 01:42:50 -04:00
pic_sym *name;
name = pic_sym_ptr(pic_list_ref(pic, var, 1));
emit_i(pic, cxt, OP_GSET, index_global(pic, cxt, name));
2015-07-01 16:07:16 -04:00
emit_ret(pic, cxt, tailpos);
}
2015-08-25 06:37:20 -04:00
else if (type == CREF) {
2015-07-01 16:07:16 -04:00
pic_sym *name;
int depth;
depth = pic_int(pic_list_ref(pic, var, 1));
name = pic_sym_ptr(pic_list_ref(pic, var, 2));
emit_r(pic, cxt, OP_CSET, depth, index_capture(cxt, name, depth));
emit_ret(pic, cxt, tailpos);
}
2015-08-25 06:37:20 -04:00
else if (type == LREF) {
2015-07-01 16:07:16 -04:00
pic_sym *name;
int i;
name = pic_sym_ptr(pic_list_ref(pic, var, 1));
if ((i = index_capture(cxt, name, 0)) != -1) {
emit_i(pic, cxt, OP_LSET, i + (int)cxt->args->len + (int)cxt->locals->len + 1);
emit_ret(pic, cxt, tailpos);
2015-07-01 16:07:16 -04:00
} else {
2015-06-27 03:33:31 -04:00
emit_i(pic, cxt, OP_LSET, index_local(cxt, name));
emit_ret(pic, cxt, tailpos);
2014-08-25 00:38:09 -04:00
}
}
2015-07-01 16:07:16 -04:00
}
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
static void
codegen_lambda(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
{
codegen_context c, *inner_cxt = &c;
pic_value rest_opt, body;
pic_sym *rest = NULL;
pic_vec *args, *locals, *captures;
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
check_irep_size(pic, cxt);
/* extract arguments */
rest_opt = pic_list_ref(pic, obj, 1);
if (pic_sym_p(rest_opt)) {
rest = pic_sym_ptr(rest_opt);
2014-08-25 00:38:09 -04:00
}
2015-07-01 16:07:16 -04:00
args = pic_vec_ptr(pic_list_ref(pic, obj, 2));
locals = pic_vec_ptr(pic_list_ref(pic, obj, 3));
captures = pic_vec_ptr(pic_list_ref(pic, obj, 4));
body = pic_list_ref(pic, obj, 5);
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
/* emit irep */
codegen_context_init(pic, inner_cxt, cxt, rest, args, locals, captures);
codegen(pic, inner_cxt, body, true);
2016-02-06 04:15:15 -05:00
cxt->irep[cxt->ilen].i = codegen_context_destroy(pic, inner_cxt);
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
/* emit OP_LAMBDA */
emit_i(pic, cxt, OP_LAMBDA, cxt->ilen++);
emit_ret(pic, cxt, tailpos);
}
2015-07-01 16:07:16 -04:00
static void
codegen_if(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
{
int s, t;
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
codegen(pic, cxt, pic_list_ref(pic, obj, 1), false);
2015-07-01 16:07:16 -04:00
s = (int)cxt->clen;
2015-07-01 16:07:16 -04:00
emit_n(pic, cxt, OP_JMPIF);
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
/* if false branch */
codegen(pic, cxt, pic_list_ref(pic, obj, 3), tailpos);
2014-08-25 00:38:09 -04:00
2015-07-01 16:07:16 -04:00
t = (int)cxt->clen;
emit_n(pic, cxt, OP_JMP);
2016-02-05 07:53:25 -05:00
cxt->code[s].a = (int)cxt->clen - s;
2015-07-01 16:07:16 -04:00
/* if true branch */
codegen(pic, cxt, pic_list_ref(pic, obj, 2), tailpos);
2016-02-05 07:53:25 -05:00
cxt->code[t].a = (int)cxt->clen - t;
2015-07-01 16:07:16 -04:00
}
static void
codegen_begin(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
{
codegen(pic, cxt, pic_list_ref(pic, obj, 1), false);
emit_n(pic, cxt, OP_POP);
codegen(pic, cxt, pic_list_ref(pic, obj, 2), tailpos);
}
static void
codegen_quote(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
{
int pidx;
obj = pic_list_ref(pic, obj, 1);
switch (pic_type(obj)) {
2016-02-02 14:07:05 -05:00
case PIC_TT_UNDEF:
emit_n(pic, cxt, OP_PUSHUNDEF);
break;
2015-07-01 16:07:16 -04:00
case PIC_TT_BOOL:
emit_n(pic, cxt, (pic_true_p(obj) ? OP_PUSHTRUE : OP_PUSHFALSE));
break;
case PIC_TT_INT:
2016-02-05 07:41:20 -05:00
check_ints_size(pic, cxt);
pidx = (int)cxt->klen++;
cxt->ints[pidx] = pic_int(obj);
emit_i(pic, cxt, OP_PUSHINT, pidx);
2015-07-01 16:07:16 -04:00
break;
2016-02-06 06:52:36 -05:00
case PIC_TT_FLOAT:
check_nums_size(pic, cxt);
pidx = (int)cxt->flen++;
cxt->nums[pidx] = pic_float(obj);
emit_i(pic, cxt, OP_PUSHFLOAT, pidx);
break;
2015-07-01 16:07:16 -04:00
case PIC_TT_NIL:
emit_n(pic, cxt, OP_PUSHNIL);
break;
2016-02-06 06:43:21 -05:00
case PIC_TT_EOF:
emit_n(pic, cxt, OP_PUSHEOF);
break;
2015-07-01 16:07:16 -04:00
case PIC_TT_CHAR:
2016-02-05 07:41:20 -05:00
check_ints_size(pic, cxt);
pidx = (int)cxt->klen++;
cxt->ints[pidx] = pic_char(obj);
emit_i(pic, cxt, OP_PUSHCHAR, pidx);
2015-07-01 16:07:16 -04:00
break;
default:
check_pool_size(pic, cxt);
pidx = (int)cxt->plen++;
cxt->pool[pidx] = obj;
emit_i(pic, cxt, OP_PUSHCONST, pidx);
break;
2014-08-25 00:38:09 -04:00
}
2016-02-05 07:41:20 -05:00
emit_ret(pic, cxt, tailpos);
2015-07-01 16:07:16 -04:00
}
2014-08-25 00:38:09 -04:00
2015-07-01 16:26:05 -04:00
#define VM(uid, op) \
if (sym == uid) { \
2015-08-10 10:53:36 -04:00
emit_i(pic, cxt, op, len - 1); \
2015-07-01 16:26:05 -04:00
emit_ret(pic, cxt, tailpos); \
2015-08-10 10:53:36 -04:00
return; \
2015-07-01 16:26:05 -04:00
}
2015-07-01 16:07:16 -04:00
2015-08-10 10:53:36 -04:00
static void
codegen_call(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
{
int len = (int)pic_length(pic, obj);
pic_value elt, it, functor;
pic_for_each (elt, pic_cdr(pic, obj), it) {
codegen(pic, cxt, elt, false);
}
functor = pic_list_ref(pic, obj, 1);
2015-08-25 06:37:20 -04:00
if (pic_sym_ptr(pic_list_ref(pic, functor, 0)) == GREF) {
2015-08-10 10:53:36 -04:00
pic_sym *sym;
sym = pic_sym_ptr(pic_list_ref(pic, functor, 1));
VM(pic->sCONS, OP_CONS)
VM(pic->sCAR, OP_CAR)
VM(pic->sCDR, OP_CDR)
VM(pic->sNILP, OP_NILP)
VM(pic->sSYMBOLP, OP_SYMBOLP)
VM(pic->sPAIRP, OP_PAIRP)
VM(pic->sNOT, OP_NOT)
VM(pic->sEQ, OP_EQ)
VM(pic->sLT, OP_LT)
VM(pic->sLE, OP_LE)
VM(pic->sGT, OP_GT)
VM(pic->sGE, OP_GE)
VM(pic->sADD, OP_ADD)
VM(pic->sSUB, OP_SUB)
VM(pic->sMUL, OP_MUL)
VM(pic->sDIV, OP_DIV)
2015-07-01 16:07:16 -04:00
}
2015-07-01 16:07:16 -04:00
emit_i(pic, cxt, (tailpos ? OP_TAILCALL : OP_CALL), len - 1);
}
static void
codegen(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
{
pic_sym *sym;
sym = pic_sym_ptr(pic_car(pic, obj));
2015-08-25 06:37:20 -04:00
if (sym == GREF || sym == CREF || sym == LREF) {
2015-07-01 16:07:16 -04:00
codegen_ref(pic, cxt, obj, tailpos);
}
else if (sym == pic->sSETBANG || sym == pic->sDEFINE) {
2015-07-01 16:07:16 -04:00
codegen_set(pic, cxt, obj, tailpos);
}
else if (sym == pic->sLAMBDA) {
2015-07-01 16:07:16 -04:00
codegen_lambda(pic, cxt, obj, tailpos);
}
else if (sym == pic->sIF) {
2015-07-01 16:07:16 -04:00
codegen_if(pic, cxt, obj, tailpos);
}
else if (sym == pic->sBEGIN) {
2015-07-01 16:07:16 -04:00
codegen_begin(pic, cxt, obj, tailpos);
}
else if (sym == pic->sQUOTE) {
2015-07-01 16:07:16 -04:00
codegen_quote(pic, cxt, obj, tailpos);
}
2015-08-25 06:37:20 -04:00
else if (sym == CALL) {
2015-07-01 16:07:16 -04:00
codegen_call(pic, cxt, obj, tailpos);
}
else {
pic_errorf(pic, "codegen: unknown AST type ~s", obj);
2014-08-25 00:38:09 -04:00
}
}
struct pic_irep *
pic_codegen(pic_state *pic, pic_value obj)
{
2015-06-27 03:33:31 -04:00
pic_vec *empty = pic_make_vec(pic, 0);
codegen_context c, *cxt = &c;
2014-08-25 00:38:09 -04:00
2015-06-27 06:02:18 -04:00
codegen_context_init(pic, cxt, NULL, NULL, empty, empty, empty);
2014-08-25 00:38:09 -04:00
codegen(pic, cxt, obj, true);
2014-08-25 00:38:09 -04:00
2015-06-27 03:33:31 -04:00
return codegen_context_destroy(pic, cxt);
2014-08-25 00:38:09 -04:00
}
2015-06-27 12:51:20 -04:00
#define SAVE(pic, ai, obj) pic_gc_arena_restore(pic, ai); pic_gc_protect(pic, obj)
2014-08-25 00:38:09 -04:00
struct pic_proc *
pic_compile(pic_state *pic, pic_value obj, struct pic_env *env)
2014-08-25 00:38:09 -04:00
{
struct pic_irep *irep;
2016-02-04 10:30:11 -05:00
struct pic_proc *proc;
2014-08-25 00:38:09 -04:00
size_t ai = pic_gc_arena_preserve(pic);
#if DEBUG
fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic));
fprintf(stdout, "# input expression\n");
2015-06-27 04:44:06 -04:00
pic_write(pic, obj);
2014-08-25 00:38:09 -04:00
fprintf(stdout, "\n");
fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic));
#endif
2015-06-16 07:19:04 -04:00
/* expand */
obj = pic_expand(pic, obj, env);
2014-08-25 00:38:09 -04:00
#if DEBUG
2015-06-16 07:19:04 -04:00
fprintf(stdout, "## expand completed\n");
2015-06-27 04:44:06 -04:00
pic_write(pic, obj);
2014-08-25 00:38:09 -04:00
fprintf(stdout, "\n");
fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic));
#endif
2015-06-27 12:51:20 -04:00
SAVE(pic, ai, obj);
2015-07-22 03:09:31 -04:00
/* optimize */
obj = pic_optimize(pic, obj);
#if DEBUG
fprintf(stdout, "## optimize completed\n");
pic_write(pic, obj);
fprintf(stdout, "\n");
fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic));
#endif
SAVE(pic, ai, obj);
2014-08-25 00:38:09 -04:00
/* analyze */
obj = pic_analyze(pic, obj);
#if DEBUG
fprintf(stdout, "## analyzer completed\n");
2015-06-27 04:44:06 -04:00
pic_write(pic, obj);
2014-08-25 00:38:09 -04:00
fprintf(stdout, "\n");
fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic));
#endif
2015-06-27 12:51:20 -04:00
SAVE(pic, ai, obj);
2014-08-25 00:38:09 -04:00
/* codegen */
irep = pic_codegen(pic, obj);
#if DEBUG
fprintf(stdout, "## codegen completed\n");
pic_dump_irep(irep);
#endif
#if DEBUG
fprintf(stdout, "# compilation finished\n");
puts("");
#endif
2016-02-04 10:30:11 -05:00
proc = pic_make_proc_irep(pic, irep, NULL);
pic_irep_decref(pic, irep);
2014-08-25 00:38:09 -04:00
2016-02-04 10:30:11 -05:00
return proc;
2014-08-25 00:38:09 -04:00
}