2014-09-08 05:47:20 -04:00
|
|
|
/**
|
|
|
|
* See Copyright Notice in picrin.h
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "picrin.h"
|
2016-02-20 10:58:58 -05:00
|
|
|
#include "picrin/extra.h"
|
2016-02-20 11:13:16 -05:00
|
|
|
#include "picrin/private/object.h"
|
2016-02-21 05:53:31 -05:00
|
|
|
#include "picrin/private/vm.h"
|
2016-02-20 11:13:16 -05:00
|
|
|
#include "picrin/private/state.h"
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-22 09:57:07 -05:00
|
|
|
static pic_value pic_compile(pic_state *, pic_value);
|
|
|
|
|
2016-02-22 12:37:33 -05:00
|
|
|
#define EQ(sym, lit) (strcmp(pic_sym(pic, sym), lit) == 0)
|
2016-02-20 14:34:26 -05:00
|
|
|
#define S(lit) (pic_intern_lit(pic, lit))
|
|
|
|
|
2016-02-22 09:57:07 -05:00
|
|
|
static void
|
|
|
|
define_macro(pic_state *pic, pic_value uid, pic_value mac)
|
|
|
|
{
|
|
|
|
if (pic_weak_has(pic, pic->macros, uid)) {
|
2016-02-22 12:39:33 -05:00
|
|
|
pic_warnf(pic, "redefining syntax variable: %s", pic_sym(pic, uid));
|
2016-02-22 09:57:07 -05:00
|
|
|
}
|
|
|
|
pic_weak_set(pic, pic->macros, uid, mac);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
find_macro(pic_state *pic, pic_value uid, pic_value *mac)
|
|
|
|
{
|
|
|
|
if (! pic_weak_has(pic, pic->macros, uid)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*mac = pic_weak_ref(pic, pic->macros, uid);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
shadow_macro(pic_state *pic, pic_value uid)
|
|
|
|
{
|
|
|
|
if (pic_weak_has(pic, pic->macros, uid)) {
|
|
|
|
pic_weak_del(pic, pic->macros, uid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value expand(pic_state *, pic_value expr, pic_value env, pic_value deferred);
|
|
|
|
static pic_value expand_lambda(pic_state *, pic_value expr, pic_value env);
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
expand_var(pic_state *pic, pic_value id, pic_value env, pic_value deferred)
|
|
|
|
{
|
|
|
|
pic_value mac, functor;
|
|
|
|
|
|
|
|
functor = pic_find_identifier(pic, id, env);
|
|
|
|
|
|
|
|
if (find_macro(pic, functor, &mac)) {
|
|
|
|
return expand(pic, pic_call(pic, mac, 2, id, env), env, deferred);
|
|
|
|
}
|
|
|
|
return functor;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
expand_quote(pic_state *pic, pic_value expr)
|
|
|
|
{
|
|
|
|
return pic_cons(pic, S("quote"), pic_cdr(pic, expr));
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
expand_list(pic_state *pic, pic_value obj, pic_value env, pic_value deferred)
|
|
|
|
{
|
|
|
|
size_t ai = pic_enter(pic);
|
|
|
|
pic_value x, head, tail;
|
|
|
|
|
|
|
|
if (pic_pair_p(pic, 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_leave(pic, ai);
|
|
|
|
pic_protect(pic, x);
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
expand_defer(pic_state *pic, pic_value expr, pic_value deferred)
|
|
|
|
{
|
|
|
|
pic_value skel = pic_cons(pic, pic_invalid_value(pic), pic_invalid_value(pic));
|
|
|
|
|
|
|
|
pic_set_car(pic, deferred, pic_cons(pic, pic_cons(pic, expr, skel), pic_car(pic, deferred)));
|
|
|
|
|
|
|
|
return skel;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
expand_deferred(pic_state *pic, pic_value deferred, pic_value 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, pic_value env)
|
|
|
|
{
|
|
|
|
pic_value formal, body;
|
|
|
|
pic_value in;
|
|
|
|
pic_value a, deferred;
|
|
|
|
|
|
|
|
in = pic_make_env(pic, env);
|
|
|
|
|
|
|
|
for (a = pic_cadr(pic, expr); pic_pair_p(pic, a); a = pic_cdr(pic, a)) {
|
|
|
|
pic_add_identifier(pic, pic_car(pic, a), in);
|
|
|
|
}
|
|
|
|
if (pic_id_p(pic, a)) {
|
|
|
|
pic_add_identifier(pic, a, in);
|
|
|
|
}
|
|
|
|
|
|
|
|
deferred = pic_list(pic, 1, pic_nil_value(pic));
|
|
|
|
|
|
|
|
formal = expand_list(pic, pic_list_ref(pic, expr, 1), in, deferred);
|
|
|
|
body = expand(pic, pic_list_ref(pic, expr, 2), in, deferred);
|
|
|
|
|
|
|
|
expand_deferred(pic, deferred, in);
|
|
|
|
|
|
|
|
return pic_list(pic, 3, S("lambda"), formal, body);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
expand_define(pic_state *pic, pic_value expr, pic_value env, pic_value deferred)
|
|
|
|
{
|
|
|
|
pic_value uid, val;
|
|
|
|
|
|
|
|
uid = pic_add_identifier(pic, pic_list_ref(pic, expr, 1), env);
|
|
|
|
|
|
|
|
shadow_macro(pic, uid);
|
|
|
|
|
|
|
|
val = expand(pic, pic_list_ref(pic, expr, 2), env, deferred);
|
|
|
|
|
|
|
|
return pic_list(pic, 3, S("define"), uid, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
expand_defmacro(pic_state *pic, pic_value expr, pic_value env)
|
|
|
|
{
|
|
|
|
pic_value uid, val;
|
|
|
|
|
|
|
|
uid = pic_add_identifier(pic, pic_list_ref(pic, expr, 1), env);
|
|
|
|
|
|
|
|
val = pic_call(pic, pic_compile(pic, pic_expand(pic, pic_list_ref(pic, expr, 2), env)), 0);
|
|
|
|
if (! pic_proc_p(pic, val)) {
|
|
|
|
pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", pic_list_ref(pic, expr, 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
define_macro(pic, uid, val);
|
|
|
|
|
|
|
|
return pic_undef_value(pic);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
expand_node(pic_state *pic, pic_value expr, pic_value env, pic_value deferred)
|
|
|
|
{
|
|
|
|
switch (pic_type(pic, expr)) {
|
|
|
|
case PIC_TYPE_ID:
|
|
|
|
case PIC_TYPE_SYMBOL: {
|
|
|
|
return expand_var(pic, expr, env, deferred);
|
|
|
|
}
|
|
|
|
case PIC_TYPE_PAIR: {
|
|
|
|
pic_value mac;
|
|
|
|
|
|
|
|
if (! pic_list_p(pic, expr)) {
|
|
|
|
pic_errorf(pic, "cannot expand improper list: ~s", expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pic_id_p(pic, pic_car(pic, expr))) {
|
|
|
|
pic_value functor;
|
|
|
|
|
|
|
|
functor = pic_find_identifier(pic, pic_car(pic, expr), env);
|
|
|
|
|
|
|
|
if (EQ(functor, "define-macro")) {
|
|
|
|
return expand_defmacro(pic, expr, env);
|
|
|
|
}
|
|
|
|
else if (EQ(functor, "lambda")) {
|
|
|
|
return expand_defer(pic, expr, deferred);
|
|
|
|
}
|
|
|
|
else if (EQ(functor, "define")) {
|
|
|
|
return expand_define(pic, expr, env, deferred);
|
|
|
|
}
|
|
|
|
else if (EQ(functor, "quote")) {
|
|
|
|
return expand_quote(pic, expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (find_macro(pic, functor, &mac)) {
|
|
|
|
return expand(pic, pic_call(pic, mac, 2, expr, env), env, deferred);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return expand_list(pic, expr, env, deferred);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
expand(pic_state *pic, pic_value expr, pic_value env, pic_value deferred)
|
|
|
|
{
|
|
|
|
size_t ai = pic_enter(pic);
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
v = expand_node(pic, expr, env, deferred);
|
|
|
|
|
|
|
|
pic_leave(pic, ai);
|
|
|
|
pic_protect(pic, v);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
pic_value
|
|
|
|
pic_expand(pic_state *pic, pic_value expr, pic_value env)
|
|
|
|
{
|
|
|
|
pic_value v, deferred;
|
|
|
|
|
|
|
|
deferred = pic_list(pic, 1, pic_nil_value(pic));
|
|
|
|
|
|
|
|
v = expand(pic, expr, env, deferred);
|
|
|
|
|
|
|
|
expand_deferred(pic, deferred, env);
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2016-02-06 09:55:39 -05:00
|
|
|
static pic_value
|
|
|
|
optimize_beta(pic_state *pic, pic_value expr)
|
|
|
|
{
|
2016-02-19 02:17:13 -05:00
|
|
|
size_t ai = pic_enter(pic);
|
2016-02-06 09:55:39 -05:00
|
|
|
pic_value functor, formals, args, tmp, val, it, defs;
|
|
|
|
|
2016-02-18 06:15:42 -05:00
|
|
|
if (! pic_list_p(pic, expr))
|
2016-02-06 09:55:39 -05:00
|
|
|
return expr;
|
|
|
|
|
2016-02-18 06:15:42 -05:00
|
|
|
if (pic_nil_p(pic, expr))
|
2016-02-06 09:55:39 -05:00
|
|
|
return expr;
|
|
|
|
|
2016-02-18 06:15:42 -05:00
|
|
|
if (pic_sym_p(pic, pic_list_ref(pic, expr, 0))) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value sym = pic_list_ref(pic, expr, 0);
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-20 14:34:26 -05:00
|
|
|
if (EQ(sym, "quote")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
return expr;
|
2016-02-20 14:34:26 -05:00
|
|
|
} else if (EQ(sym, "lambda")) {
|
|
|
|
return pic_list(pic, 3, S("lambda"), pic_list_ref(pic, expr, 1), optimize_beta(pic, pic_list_ref(pic, expr, 2)));
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 06:15:42 -05:00
|
|
|
tmp = pic_nil_value(pic);
|
2016-02-06 09:55:39 -05:00
|
|
|
pic_for_each (val, expr, it) {
|
|
|
|
pic_push(pic, optimize_beta(pic, val), tmp);
|
|
|
|
}
|
|
|
|
expr = pic_reverse(pic, tmp);
|
|
|
|
|
2016-02-19 02:17:13 -05:00
|
|
|
pic_leave(pic, ai);
|
|
|
|
pic_protect(pic, expr);
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
functor = pic_list_ref(pic, expr, 0);
|
2016-02-20 14:34:26 -05:00
|
|
|
if (pic_pair_p(pic, functor) && EQ(pic_car(pic, functor), "lambda")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
formals = pic_list_ref(pic, functor, 1);
|
2016-02-18 06:15:42 -05:00
|
|
|
if (! pic_list_p(pic, formals))
|
2016-02-06 09:55:39 -05:00
|
|
|
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;
|
2016-02-18 06:15:42 -05:00
|
|
|
defs = pic_nil_value(pic);
|
2016-02-06 09:55:39 -05:00
|
|
|
pic_for_each (val, args, it) {
|
2016-02-20 14:34:26 -05:00
|
|
|
pic_push(pic, pic_list(pic, 3, S("define"), pic_car(pic, formals), val), defs);
|
2016-02-06 09:55:39 -05:00
|
|
|
formals = pic_cdr(pic, formals);
|
|
|
|
}
|
|
|
|
expr = pic_list_ref(pic, functor, 2);
|
|
|
|
pic_for_each (val, defs, it) {
|
2016-02-20 14:34:26 -05:00
|
|
|
expr = pic_list(pic, 3, S("begin"), val, expr);
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
exit:
|
|
|
|
|
2016-02-19 02:17:13 -05:00
|
|
|
pic_leave(pic, ai);
|
|
|
|
pic_protect(pic, expr);
|
2016-02-06 09:55:39 -05:00
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
pic_optimize(pic_state *pic, pic_value expr)
|
|
|
|
{
|
|
|
|
return optimize_beta(pic, expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct analyze_scope {
|
|
|
|
int depth;
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value rest; /* Nullable */
|
|
|
|
pic_value args, locals, captures; /* rest args variable is counted as a local */
|
2016-02-06 09:55:39 -05:00
|
|
|
pic_value defer;
|
|
|
|
struct analyze_scope *up;
|
|
|
|
} analyze_scope;
|
|
|
|
|
|
|
|
static void
|
|
|
|
analyzer_scope_init(pic_state *pic, analyze_scope *scope, pic_value formal, analyze_scope *up)
|
|
|
|
{
|
2016-02-20 01:31:14 -05:00
|
|
|
scope->args = pic_make_dict(pic);
|
|
|
|
scope->locals = pic_make_dict(pic);
|
|
|
|
scope->captures = pic_make_dict(pic);
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
/* analyze formal */
|
2016-02-18 06:15:42 -05:00
|
|
|
for (; pic_pair_p(pic, formal); formal = pic_cdr(pic, formal)) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_dict_set(pic, scope->args, pic_car(pic, formal), pic_true_value(pic));
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
2016-02-18 06:15:42 -05:00
|
|
|
if (pic_nil_p(pic, formal)) {
|
2016-02-20 01:31:14 -05:00
|
|
|
scope->rest = pic_false_value(pic);
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
else {
|
2016-02-20 01:31:14 -05:00
|
|
|
scope->rest = formal;
|
|
|
|
pic_dict_set(pic, scope->locals, formal, pic_true_value(pic));
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
scope->up = up;
|
|
|
|
scope->depth = up ? up->depth + 1 : 0;
|
2016-02-18 12:29:40 -05:00
|
|
|
scope->defer = pic_list(pic, 1, pic_nil_value(pic));
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-02-21 05:19:35 -05:00
|
|
|
analyzer_scope_destroy(pic_state *PIC_UNUSED(pic), analyze_scope *PIC_UNUSED(scope))
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
2016-02-20 01:31:14 -05:00
|
|
|
/* nothing here */
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2016-02-22 09:49:39 -05:00
|
|
|
find_local_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
2016-02-20 01:31:14 -05:00
|
|
|
return pic_dict_has(pic, scope->args, sym) || pic_dict_has(pic, scope->locals, sym) || scope->depth == 0;
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-02-20 01:31:14 -05:00
|
|
|
find_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
2016-02-20 01:31:14 -05:00
|
|
|
int depth = 0;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
while (scope) {
|
2016-02-22 09:49:39 -05:00
|
|
|
if (find_local_var(pic, scope, sym)) {
|
2016-02-06 09:55:39 -05:00
|
|
|
if (depth > 0) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_dict_set(pic, scope->captures, sym, pic_true_value(pic)); /* capture! */
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
return depth;
|
|
|
|
}
|
|
|
|
depth++;
|
|
|
|
scope = scope->up;
|
|
|
|
}
|
|
|
|
PIC_UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-02-20 01:31:14 -05:00
|
|
|
define_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
2016-02-20 03:27:13 -05:00
|
|
|
if (scope->depth > 0) {
|
|
|
|
/* local */
|
2016-02-22 09:49:39 -05:00
|
|
|
if (find_local_var(pic, scope, sym)) {
|
2016-02-22 12:39:33 -05:00
|
|
|
pic_warnf(pic, "redefining variable: %s", pic_sym(pic, sym));
|
2016-02-20 03:27:13 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
pic_dict_set(pic, scope->locals, sym, pic_true_value(pic));
|
|
|
|
} else {
|
|
|
|
/* global */
|
|
|
|
if (pic_weak_has(pic, pic->globals, sym)) {
|
2016-02-22 12:39:33 -05:00
|
|
|
pic_warnf(pic, "redefining variable: %s", pic_sym(pic, sym));
|
2016-02-20 03:27:13 -05:00
|
|
|
return;
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
2016-02-20 05:00:41 -05:00
|
|
|
pic_weak_set(pic, pic->globals, sym, pic_invalid_value(pic));
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value analyze(pic_state *, analyze_scope *, pic_value);
|
|
|
|
static pic_value analyze_lambda(pic_state *, analyze_scope *, pic_value);
|
|
|
|
|
|
|
|
static pic_value
|
2016-02-20 01:31:14 -05:00
|
|
|
analyze_var(pic_state *pic, analyze_scope *scope, pic_value sym)
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
|
|
|
int depth;
|
|
|
|
|
|
|
|
depth = find_var(pic, scope, sym);
|
|
|
|
|
|
|
|
if (depth == scope->depth) {
|
2016-02-20 14:34:26 -05:00
|
|
|
return pic_list(pic, 2, S("gref"), sym);
|
2016-02-06 09:55:39 -05:00
|
|
|
} else if (depth == 0) {
|
2016-02-20 14:34:26 -05:00
|
|
|
return pic_list(pic, 2, S("lref"), sym);
|
2016-02-06 09:55:39 -05:00
|
|
|
} else {
|
2016-02-20 14:34:26 -05:00
|
|
|
return pic_list(pic, 3, S("cref"), pic_int_value(pic, depth), sym);
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_defer(pic_state *pic, analyze_scope *scope, pic_value form)
|
|
|
|
{
|
2016-02-20 05:00:41 -05:00
|
|
|
pic_value skel = pic_cons(pic, pic_invalid_value(pic), pic_invalid_value(pic));
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-18 12:29:40 -05:00
|
|
|
pic_set_car(pic, scope->defer, pic_cons(pic, pic_cons(pic, form, skel), pic_car(pic, scope->defer)));
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
return skel;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
analyze_deferred(pic_state *pic, analyze_scope *scope)
|
|
|
|
{
|
|
|
|
pic_value defer, val, src, dst, it;
|
|
|
|
|
|
|
|
scope->defer = pic_car(pic, scope->defer);
|
|
|
|
|
|
|
|
pic_for_each (defer, pic_reverse(pic, scope->defer), it) {
|
|
|
|
src = pic_car(pic, defer);
|
|
|
|
dst = pic_cdr(pic, defer);
|
|
|
|
|
|
|
|
val = analyze_lambda(pic, scope, src);
|
|
|
|
|
|
|
|
/* copy */
|
|
|
|
pic_set_car(pic, dst, pic_car(pic, val));
|
|
|
|
pic_set_cdr(pic, dst, pic_cdr(pic, val));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_lambda(pic_state *pic, analyze_scope *up, pic_value form)
|
|
|
|
{
|
|
|
|
analyze_scope s, *scope = &s;
|
|
|
|
pic_value formals, body;
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value rest;
|
|
|
|
pic_value args, locals, captures, key;
|
|
|
|
int i, j, it;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
formals = pic_list_ref(pic, form, 1);
|
|
|
|
body = pic_list_ref(pic, form, 2);
|
|
|
|
|
|
|
|
analyzer_scope_init(pic, scope, formals, up);
|
|
|
|
|
|
|
|
/* analyze body */
|
|
|
|
body = analyze(pic, scope, body);
|
|
|
|
analyze_deferred(pic, scope);
|
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
args = pic_make_vec(pic, pic_dict_size(pic, scope->args), NULL);
|
2016-02-18 06:15:42 -05:00
|
|
|
for (i = 0; pic_pair_p(pic, formals); formals = pic_cdr(pic, formals), i++) {
|
2016-02-19 07:56:45 -05:00
|
|
|
pic_vec_set(pic, args, i, pic_car(pic, formals));
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
rest = scope->rest;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
locals = pic_make_vec(pic, pic_dict_size(pic, scope->locals), NULL);
|
2016-02-06 09:55:39 -05:00
|
|
|
j = 0;
|
2016-02-20 01:31:14 -05:00
|
|
|
if (pic_sym_p(pic, scope->rest)) {
|
|
|
|
pic_vec_set(pic, locals, j++, scope->rest);
|
|
|
|
}
|
|
|
|
it = 0;
|
|
|
|
while (pic_dict_next(pic, scope->locals, &it, &key, NULL)) {
|
|
|
|
if (pic_eq_p(pic, key, rest))
|
|
|
|
continue;
|
|
|
|
pic_vec_set(pic, locals, j++, key);
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
captures = pic_make_vec(pic, pic_dict_size(pic, scope->captures), NULL);
|
|
|
|
it = 0;
|
|
|
|
j = 0;
|
|
|
|
while (pic_dict_next(pic, scope->captures, &it, &key, NULL)) {
|
|
|
|
pic_vec_set(pic, captures, j++, key);
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
analyzer_scope_destroy(pic, scope);
|
|
|
|
|
2016-02-20 14:34:26 -05:00
|
|
|
return pic_list(pic, 6, S("lambda"), rest, args, locals, captures, body);
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_list(pic_state *pic, analyze_scope *scope, pic_value obj)
|
|
|
|
{
|
2016-02-18 06:15:42 -05:00
|
|
|
pic_value seq = pic_nil_value(pic), val, it;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
pic_for_each (val, obj, it) {
|
|
|
|
pic_push(pic, analyze(pic, scope, val), seq);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pic_reverse(pic, seq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_define(pic_state *pic, analyze_scope *scope, pic_value obj)
|
|
|
|
{
|
2016-02-20 01:31:14 -05:00
|
|
|
define_var(pic, scope, pic_list_ref(pic, obj, 1));
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
return pic_cons(pic, pic_car(pic, obj), analyze_list(pic, scope, pic_cdr(pic, obj)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_call(pic_state *pic, analyze_scope *scope, pic_value obj)
|
|
|
|
{
|
2016-02-20 14:34:26 -05:00
|
|
|
return pic_cons(pic, S("call"), analyze_list(pic, scope, obj));
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze_node(pic_state *pic, analyze_scope *scope, pic_value obj)
|
|
|
|
{
|
2016-02-18 06:15:42 -05:00
|
|
|
switch (pic_type(pic, obj)) {
|
2016-02-18 09:25:45 -05:00
|
|
|
case PIC_TYPE_SYMBOL: {
|
2016-02-20 01:31:14 -05:00
|
|
|
return analyze_var(pic, scope, obj);
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
2016-02-18 09:25:45 -05:00
|
|
|
case PIC_TYPE_PAIR: {
|
2016-02-06 09:55:39 -05:00
|
|
|
pic_value proc;
|
|
|
|
|
2016-02-18 06:15:42 -05:00
|
|
|
if (! pic_list_p(pic, obj)) {
|
2016-02-06 09:55:39 -05:00
|
|
|
pic_errorf(pic, "invalid expression given: ~s", obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
proc = pic_list_ref(pic, obj, 0);
|
2016-02-18 06:15:42 -05:00
|
|
|
if (pic_sym_p(pic, proc)) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value sym = proc;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-20 14:34:26 -05:00
|
|
|
if (EQ(sym, "define")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
return analyze_define(pic, scope, obj);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "lambda")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
return analyze_defer(pic, scope, obj);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "quote")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
return obj;
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "begin") || EQ(sym, "set!") || EQ(sym, "if")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
return pic_cons(pic, pic_car(pic, obj), analyze_list(pic, scope, pic_cdr(pic, obj)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return analyze_call(pic, scope, obj);
|
|
|
|
}
|
|
|
|
default:
|
2016-02-20 14:34:26 -05:00
|
|
|
return pic_list(pic, 2, S("quote"), obj);
|
2016-02-06 09:55:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
analyze(pic_state *pic, analyze_scope *scope, pic_value obj)
|
|
|
|
{
|
2016-02-19 02:17:13 -05:00
|
|
|
size_t ai = pic_enter(pic);
|
2016-02-06 09:55:39 -05:00
|
|
|
pic_value res;
|
|
|
|
|
|
|
|
res = analyze_node(pic, scope, obj);
|
|
|
|
|
2016-02-19 02:17:13 -05:00
|
|
|
pic_leave(pic, ai);
|
|
|
|
pic_protect(pic, res);
|
2016-02-06 09:55:39 -05:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
pic_analyze(pic_state *pic, pic_value obj)
|
|
|
|
{
|
|
|
|
analyze_scope s, *scope = &s;
|
|
|
|
|
2016-02-18 06:15:42 -05:00
|
|
|
analyzer_scope_init(pic, scope, pic_nil_value(pic), NULL);
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
obj = analyze(pic, scope, obj);
|
|
|
|
|
|
|
|
analyze_deferred(pic, scope);
|
|
|
|
|
|
|
|
analyzer_scope_destroy(pic, scope);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct codegen_context {
|
|
|
|
/* rest args variable is counted as a local */
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value rest;
|
2016-02-19 07:56:45 -05:00
|
|
|
pic_value args, locals, captures;
|
2016-02-06 09:55:39 -05:00
|
|
|
/* actual bit code sequence */
|
2016-02-21 06:32:00 -05:00
|
|
|
struct code *code;
|
2016-02-06 09:55:39 -05:00
|
|
|
size_t clen, ccapa;
|
|
|
|
/* child ireps */
|
2016-02-21 06:32:00 -05:00
|
|
|
struct irep **irep;
|
2016-02-06 09:55:39 -05:00
|
|
|
size_t ilen, icapa;
|
|
|
|
/* constant object pool */
|
|
|
|
int *ints;
|
|
|
|
size_t klen, kcapa;
|
|
|
|
double *nums;
|
|
|
|
size_t flen, fcapa;
|
2016-02-21 06:32:00 -05:00
|
|
|
struct object **pool;
|
2016-02-06 09:55:39 -05:00
|
|
|
size_t plen, pcapa;
|
|
|
|
|
|
|
|
struct codegen_context *up;
|
|
|
|
} codegen_context;
|
|
|
|
|
|
|
|
static void create_activation(pic_state *, codegen_context *);
|
|
|
|
|
|
|
|
static void
|
2016-02-20 01:31:14 -05:00
|
|
|
codegen_context_init(pic_state *pic, codegen_context *cxt, codegen_context *up, pic_value rest, pic_value args, pic_value locals, pic_value captures)
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
|
|
|
cxt->up = up;
|
|
|
|
cxt->rest = rest;
|
|
|
|
|
|
|
|
cxt->args = args;
|
|
|
|
cxt->locals = locals;
|
|
|
|
cxt->captures = captures;
|
|
|
|
|
2016-02-21 06:32:00 -05:00
|
|
|
cxt->code = pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(struct code));
|
2016-02-06 09:55:39 -05:00
|
|
|
cxt->clen = 0;
|
|
|
|
cxt->ccapa = PIC_ISEQ_SIZE;
|
|
|
|
|
2016-02-21 06:32:00 -05:00
|
|
|
cxt->irep = pic_calloc(pic, PIC_IREP_SIZE, sizeof(struct irep *));
|
2016-02-06 09:55:39 -05:00
|
|
|
cxt->ilen = 0;
|
|
|
|
cxt->icapa = PIC_IREP_SIZE;
|
|
|
|
|
2016-02-21 06:32:00 -05:00
|
|
|
cxt->pool = pic_calloc(pic, PIC_POOL_SIZE, sizeof(struct object *));
|
2016-02-06 09:55:39 -05:00
|
|
|
cxt->plen = 0;
|
|
|
|
cxt->pcapa = PIC_POOL_SIZE;
|
|
|
|
|
|
|
|
cxt->ints = pic_calloc(pic, PIC_POOL_SIZE, sizeof(int));
|
|
|
|
cxt->klen = 0;
|
|
|
|
cxt->kcapa = PIC_POOL_SIZE;
|
|
|
|
|
|
|
|
cxt->nums = pic_calloc(pic, PIC_POOL_SIZE, sizeof(double));
|
|
|
|
cxt->flen = 0;
|
|
|
|
cxt->fcapa = PIC_POOL_SIZE;
|
|
|
|
|
|
|
|
create_activation(pic, cxt);
|
|
|
|
}
|
|
|
|
|
2016-02-21 06:32:00 -05:00
|
|
|
static struct irep *
|
2016-02-06 09:55:39 -05:00
|
|
|
codegen_context_destroy(pic_state *pic, codegen_context *cxt)
|
|
|
|
{
|
2016-02-21 06:32:00 -05:00
|
|
|
struct irep *irep;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
/* create irep */
|
2016-02-21 06:32:00 -05:00
|
|
|
irep = pic_malloc(pic, sizeof(struct irep));
|
2016-02-06 09:55:39 -05:00
|
|
|
irep->refc = 1;
|
2016-02-20 01:31:14 -05:00
|
|
|
irep->varg = pic_sym_p(pic, cxt->rest);
|
2016-02-19 07:56:45 -05:00
|
|
|
irep->argc = pic_vec_len(pic, cxt->args) + 1;
|
|
|
|
irep->localc = pic_vec_len(pic, cxt->locals);
|
|
|
|
irep->capturec = pic_vec_len(pic, cxt->captures);
|
2016-02-21 06:32:00 -05:00
|
|
|
irep->code = pic_realloc(pic, cxt->code, sizeof(struct code) * cxt->clen);
|
|
|
|
irep->irep = pic_realloc(pic, cxt->irep, sizeof(struct irep *) * cxt->ilen);
|
2016-02-07 23:51:41 -05:00
|
|
|
irep->ints = pic_realloc(pic, cxt->ints, sizeof(int) * cxt->klen);
|
|
|
|
irep->nums = pic_realloc(pic, cxt->nums, sizeof(double) * cxt->flen);
|
2016-02-21 06:32:00 -05:00
|
|
|
irep->pool = pic_realloc(pic, cxt->pool, sizeof(struct object *) * cxt->plen);
|
2016-02-06 09:55:39 -05:00
|
|
|
irep->ncode = cxt->clen;
|
|
|
|
irep->nirep = cxt->ilen;
|
|
|
|
irep->nints = cxt->klen;
|
|
|
|
irep->nnums = cxt->flen;
|
|
|
|
irep->npool = cxt->plen;
|
|
|
|
|
|
|
|
irep->list.next = pic->ireps.next;
|
|
|
|
irep->list.prev = &pic->ireps;
|
|
|
|
irep->list.next->prev = &irep->list;
|
|
|
|
irep->list.prev->next = &irep->list;
|
|
|
|
|
|
|
|
return irep;
|
|
|
|
}
|
|
|
|
|
|
|
|
#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)
|
|
|
|
|
2016-02-21 06:32:00 -05:00
|
|
|
#define check_code_size(pic, cxt) check_size(pic, cxt, c, code, struct code)
|
|
|
|
#define check_irep_size(pic, cxt) check_size(pic, cxt, i, irep, struct irep *)
|
|
|
|
#define check_pool_size(pic, cxt) check_size(pic, cxt, p, pool, struct object *)
|
2016-02-06 09:55:39 -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)
|
|
|
|
|
|
|
|
#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; \
|
|
|
|
cxt->code[cxt->clen].a = I; \
|
|
|
|
cxt->clen++; \
|
|
|
|
} while (0) \
|
|
|
|
|
|
|
|
#define emit_r(pic, cxt, ins, D, I) do { \
|
|
|
|
check_code_size(pic, cxt); \
|
|
|
|
cxt->code[cxt->clen].insn = ins; \
|
|
|
|
cxt->code[cxt->clen].a = D; \
|
|
|
|
cxt->code[cxt->clen].b = I; \
|
|
|
|
cxt->clen++; \
|
|
|
|
} while (0) \
|
|
|
|
|
|
|
|
#define emit_ret(pic, cxt, tailpos) if (tailpos) emit_n(pic, cxt, OP_RET)
|
|
|
|
|
|
|
|
static int
|
2016-02-20 01:31:14 -05:00
|
|
|
index_capture(pic_state *pic, codegen_context *cxt, pic_value sym, int depth)
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
while (depth-- > 0) {
|
|
|
|
cxt = cxt->up;
|
|
|
|
}
|
|
|
|
|
2016-02-19 07:56:45 -05:00
|
|
|
for (i = 0; i < pic_vec_len(pic, cxt->captures); ++i) {
|
2016-02-20 01:31:14 -05:00
|
|
|
if (pic_eq_p(pic, sym, pic_vec_ref(pic, cxt->captures, i)))
|
2016-02-06 09:55:39 -05:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-02-20 01:31:14 -05:00
|
|
|
index_local(pic_state *pic, codegen_context *cxt, pic_value sym)
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
|
|
|
int i, offset;
|
|
|
|
|
|
|
|
offset = 1;
|
2016-02-19 07:56:45 -05:00
|
|
|
for (i = 0; i < pic_vec_len(pic, cxt->args); ++i) {
|
2016-02-20 01:31:14 -05:00
|
|
|
if (pic_eq_p(pic, sym, pic_vec_ref(pic, cxt->args, i)))
|
2016-02-06 09:55:39 -05:00
|
|
|
return i + offset;
|
|
|
|
}
|
|
|
|
offset += i;
|
2016-02-19 07:56:45 -05:00
|
|
|
for (i = 0; i < pic_vec_len(pic, cxt->locals); ++i) {
|
2016-02-20 01:31:14 -05:00
|
|
|
if (pic_eq_p(pic, sym, pic_vec_ref(pic, cxt->locals, i)))
|
2016-02-06 09:55:39 -05:00
|
|
|
return i + offset;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-02-20 01:31:14 -05:00
|
|
|
index_global(pic_state *pic, codegen_context *cxt, pic_value name)
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
|
|
|
int pidx;
|
|
|
|
|
|
|
|
check_pool_size(pic, cxt);
|
|
|
|
pidx = (int)cxt->plen++;
|
2016-02-21 06:32:00 -05:00
|
|
|
cxt->pool[pidx] = (struct object *)pic_sym_ptr(pic, name);
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
return pidx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
create_activation(pic_state *pic, codegen_context *cxt)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
|
2016-02-19 07:56:45 -05:00
|
|
|
for (i = 0; i < pic_vec_len(pic, cxt->captures); ++i) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value sym = pic_vec_ref(pic, cxt->captures, i);
|
2016-02-19 07:56:45 -05:00
|
|
|
n = index_local(pic, cxt, sym);
|
2016-02-06 09:55:39 -05:00
|
|
|
assert(n != -1);
|
2016-02-20 01:31:14 -05:00
|
|
|
if (n <= pic_vec_len(pic, cxt->args) || pic_eq_p(pic, sym, cxt->rest)) {
|
2016-02-06 09:55:39 -05: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);
|
|
|
|
|
|
|
|
static void
|
|
|
|
codegen_ref(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
|
|
|
|
{
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value sym;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
sym = pic_car(pic, obj);
|
2016-02-20 14:34:26 -05:00
|
|
|
if (EQ(sym, "gref")) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value name;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
name = pic_list_ref(pic, obj, 1);
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_i(pic, cxt, OP_GREF, index_global(pic, cxt, name));
|
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "cref")) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value name;
|
2016-02-06 09:55:39 -05:00
|
|
|
int depth;
|
|
|
|
|
2016-02-18 06:15:42 -05:00
|
|
|
depth = pic_int(pic, pic_list_ref(pic, obj, 1));
|
2016-02-20 01:31:14 -05:00
|
|
|
name = pic_list_ref(pic, obj, 2);
|
2016-02-19 07:56:45 -05:00
|
|
|
emit_r(pic, cxt, OP_CREF, depth, index_capture(pic, cxt, name, depth));
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "lref")) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value name;
|
2016-02-06 09:55:39 -05:00
|
|
|
int i;
|
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
name = pic_list_ref(pic, obj, 1);
|
2016-02-19 07:56:45 -05:00
|
|
|
if ((i = index_capture(pic, cxt, name, 0)) != -1) {
|
|
|
|
emit_i(pic, cxt, OP_LREF, i + pic_vec_len(pic, cxt->args) + pic_vec_len(pic, cxt->locals) + 1);
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
} else {
|
2016-02-19 07:56:45 -05:00
|
|
|
emit_i(pic, cxt, OP_LREF, index_local(pic, cxt, name));
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
codegen_set(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
pic_value var, val;
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value type;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
val = pic_list_ref(pic, obj, 2);
|
|
|
|
codegen(pic, cxt, val, false);
|
|
|
|
|
|
|
|
var = pic_list_ref(pic, obj, 1);
|
2016-02-20 01:31:14 -05:00
|
|
|
type = pic_list_ref(pic, var, 0);
|
2016-02-20 14:34:26 -05:00
|
|
|
if (EQ(type, "gref")) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value name;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
name = pic_list_ref(pic, var, 1);
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_i(pic, cxt, OP_GSET, index_global(pic, cxt, name));
|
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(type, "cref")) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value name;
|
2016-02-06 09:55:39 -05:00
|
|
|
int depth;
|
|
|
|
|
2016-02-18 06:15:42 -05:00
|
|
|
depth = pic_int(pic, pic_list_ref(pic, var, 1));
|
2016-02-20 01:31:14 -05:00
|
|
|
name = pic_list_ref(pic, var, 2);
|
2016-02-19 07:56:45 -05:00
|
|
|
emit_r(pic, cxt, OP_CSET, depth, index_capture(pic, cxt, name, depth));
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(type, "lref")) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value name;
|
2016-02-06 09:55:39 -05:00
|
|
|
int i;
|
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
name = pic_list_ref(pic, var, 1);
|
2016-02-19 07:56:45 -05:00
|
|
|
if ((i = index_capture(pic, cxt, name, 0)) != -1) {
|
|
|
|
emit_i(pic, cxt, OP_LSET, i + pic_vec_len(pic, cxt->args) + pic_vec_len(pic, cxt->locals) + 1);
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
} else {
|
2016-02-19 07:56:45 -05:00
|
|
|
emit_i(pic, cxt, OP_LSET, index_local(pic, cxt, name));
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
codegen_lambda(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
codegen_context c, *inner_cxt = &c;
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value rest, body;
|
2016-02-19 07:56:45 -05:00
|
|
|
pic_value args, locals, captures;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
check_irep_size(pic, cxt);
|
|
|
|
|
|
|
|
/* extract arguments */
|
2016-02-20 01:31:14 -05:00
|
|
|
rest = pic_list_ref(pic, obj, 1);
|
2016-02-19 07:56:45 -05:00
|
|
|
args = pic_list_ref(pic, obj, 2);
|
|
|
|
locals = pic_list_ref(pic, obj, 3);
|
|
|
|
captures = pic_list_ref(pic, obj, 4);
|
2016-02-06 09:55:39 -05:00
|
|
|
body = pic_list_ref(pic, obj, 5);
|
|
|
|
|
|
|
|
/* emit irep */
|
|
|
|
codegen_context_init(pic, inner_cxt, cxt, rest, args, locals, captures);
|
|
|
|
codegen(pic, inner_cxt, body, true);
|
2016-02-07 23:51:41 -05:00
|
|
|
cxt->irep[cxt->ilen] = codegen_context_destroy(pic, inner_cxt);
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
/* emit OP_LAMBDA */
|
|
|
|
emit_i(pic, cxt, OP_LAMBDA, cxt->ilen++);
|
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
codegen_if(pic_state *pic, codegen_context *cxt, pic_value obj, bool tailpos)
|
|
|
|
{
|
|
|
|
int s, t;
|
|
|
|
|
|
|
|
codegen(pic, cxt, pic_list_ref(pic, obj, 1), false);
|
|
|
|
|
|
|
|
s = (int)cxt->clen;
|
|
|
|
|
|
|
|
emit_n(pic, cxt, OP_JMPIF);
|
|
|
|
|
|
|
|
/* if false branch */
|
|
|
|
codegen(pic, cxt, pic_list_ref(pic, obj, 3), tailpos);
|
|
|
|
|
|
|
|
t = (int)cxt->clen;
|
|
|
|
|
|
|
|
emit_n(pic, cxt, OP_JMP);
|
|
|
|
|
|
|
|
cxt->code[s].a = (int)cxt->clen - s;
|
|
|
|
|
|
|
|
/* if true branch */
|
|
|
|
codegen(pic, cxt, pic_list_ref(pic, obj, 2), tailpos);
|
|
|
|
cxt->code[t].a = (int)cxt->clen - t;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2016-02-18 06:15:42 -05:00
|
|
|
switch (pic_type(pic, obj)) {
|
2016-02-18 09:25:45 -05:00
|
|
|
case PIC_TYPE_UNDEF:
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_n(pic, cxt, OP_PUSHUNDEF);
|
|
|
|
break;
|
2016-02-18 09:25:45 -05:00
|
|
|
case PIC_TYPE_TRUE:
|
|
|
|
emit_n(pic, cxt, OP_PUSHTRUE);
|
2016-02-06 09:55:39 -05:00
|
|
|
break;
|
2016-02-18 09:25:45 -05:00
|
|
|
case PIC_TYPE_FALSE:
|
|
|
|
emit_n(pic, cxt, OP_PUSHFALSE);
|
|
|
|
break;
|
|
|
|
case PIC_TYPE_INT:
|
2016-02-06 09:55:39 -05:00
|
|
|
check_ints_size(pic, cxt);
|
|
|
|
pidx = (int)cxt->klen++;
|
2016-02-18 06:15:42 -05:00
|
|
|
cxt->ints[pidx] = pic_int(pic, obj);
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_i(pic, cxt, OP_PUSHINT, pidx);
|
|
|
|
break;
|
2016-02-18 09:25:45 -05:00
|
|
|
case PIC_TYPE_FLOAT:
|
2016-02-06 09:55:39 -05:00
|
|
|
check_nums_size(pic, cxt);
|
|
|
|
pidx = (int)cxt->flen++;
|
2016-02-18 06:15:42 -05:00
|
|
|
cxt->nums[pidx] = pic_float(pic, obj);
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_i(pic, cxt, OP_PUSHFLOAT, pidx);
|
|
|
|
break;
|
2016-02-18 09:25:45 -05:00
|
|
|
case PIC_TYPE_NIL:
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_n(pic, cxt, OP_PUSHNIL);
|
|
|
|
break;
|
2016-02-18 09:25:45 -05:00
|
|
|
case PIC_TYPE_EOF:
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_n(pic, cxt, OP_PUSHEOF);
|
|
|
|
break;
|
2016-02-18 09:25:45 -05:00
|
|
|
case PIC_TYPE_CHAR:
|
2016-02-06 09:55:39 -05:00
|
|
|
check_ints_size(pic, cxt);
|
|
|
|
pidx = (int)cxt->klen++;
|
2016-02-18 06:15:42 -05:00
|
|
|
cxt->ints[pidx] = pic_char(pic, obj);
|
2016-02-06 09:55:39 -05:00
|
|
|
emit_i(pic, cxt, OP_PUSHCHAR, pidx);
|
|
|
|
break;
|
|
|
|
default:
|
2016-02-18 09:25:45 -05:00
|
|
|
assert(pic_obj_p(pic,obj));
|
2016-02-06 09:55:39 -05:00
|
|
|
check_pool_size(pic, cxt);
|
|
|
|
pidx = (int)cxt->plen++;
|
|
|
|
cxt->pool[pidx] = pic_obj_ptr(obj);
|
|
|
|
emit_i(pic, cxt, OP_PUSHCONST, pidx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
emit_ret(pic, cxt, tailpos);
|
|
|
|
}
|
|
|
|
|
2016-02-20 14:34:26 -05:00
|
|
|
#define VM(name, op) \
|
|
|
|
if (EQ(sym, name)) { \
|
2016-02-20 01:31:14 -05:00
|
|
|
emit_i(pic, cxt, op, len - 1); \
|
|
|
|
emit_ret(pic, cxt, tailpos); \
|
|
|
|
return; \
|
|
|
|
}
|
2016-02-06 09:55:39 -05: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);
|
2016-02-20 14:34:26 -05:00
|
|
|
if (EQ(pic_list_ref(pic, functor, 0), "gref")) {
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value sym;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
sym = pic_list_ref(pic, functor, 1);
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-20 14:34:26 -05:00
|
|
|
VM("cons", OP_CONS)
|
|
|
|
VM("car", OP_CAR)
|
|
|
|
VM("cdr", OP_CDR)
|
|
|
|
VM("null?", OP_NILP)
|
|
|
|
VM("symbol?", OP_SYMBOLP)
|
|
|
|
VM("pair?", OP_PAIRP)
|
|
|
|
VM("not", OP_NOT)
|
|
|
|
VM("=", OP_EQ)
|
|
|
|
VM("<", OP_LT)
|
|
|
|
VM("<=", OP_LE)
|
|
|
|
VM(">", OP_GT)
|
|
|
|
VM(">=", OP_GE)
|
|
|
|
VM("+", OP_ADD)
|
|
|
|
VM("-", OP_SUB)
|
|
|
|
VM("*", OP_MUL)
|
|
|
|
VM("/", OP_DIV)
|
2016-02-06 09:55:39 -05: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)
|
|
|
|
{
|
2016-02-20 01:31:14 -05:00
|
|
|
pic_value sym;
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
sym = pic_car(pic, obj);
|
2016-02-20 14:34:26 -05:00
|
|
|
if (EQ(sym, "gref") || EQ(sym, "cref") || EQ(sym, "lref")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
codegen_ref(pic, cxt, obj, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "set!") || EQ(sym, "define")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
codegen_set(pic, cxt, obj, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "lambda")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
codegen_lambda(pic, cxt, obj, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "if")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
codegen_if(pic, cxt, obj, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "begin")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
codegen_begin(pic, cxt, obj, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "quote")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
codegen_quote(pic, cxt, obj, tailpos);
|
|
|
|
}
|
2016-02-20 14:34:26 -05:00
|
|
|
else if (EQ(sym, "call")) {
|
2016-02-06 09:55:39 -05:00
|
|
|
codegen_call(pic, cxt, obj, tailpos);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic_errorf(pic, "codegen: unknown AST type ~s", obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-21 06:32:00 -05:00
|
|
|
static struct irep *
|
2016-02-06 09:55:39 -05:00
|
|
|
pic_codegen(pic_state *pic, pic_value obj)
|
|
|
|
{
|
2016-02-19 07:56:45 -05:00
|
|
|
pic_value empty = pic_make_vec(pic, 0, NULL);
|
2016-02-06 09:55:39 -05:00
|
|
|
codegen_context c, *cxt = &c;
|
|
|
|
|
2016-02-20 01:31:14 -05:00
|
|
|
codegen_context_init(pic, cxt, NULL, pic_false_value(pic), empty, empty, empty);
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
codegen(pic, cxt, obj, true);
|
|
|
|
|
|
|
|
return codegen_context_destroy(pic, cxt);
|
|
|
|
}
|
|
|
|
|
2016-02-19 02:17:13 -05:00
|
|
|
#define SAVE(pic, ai, obj) pic_leave(pic, ai); pic_protect(pic, obj)
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-22 09:57:07 -05:00
|
|
|
static pic_value
|
2016-02-06 10:07:29 -05:00
|
|
|
pic_compile(pic_state *pic, pic_value obj)
|
2016-02-06 09:55:39 -05:00
|
|
|
{
|
2016-02-21 06:32:00 -05:00
|
|
|
struct irep *irep;
|
2016-02-19 10:03:16 -05:00
|
|
|
pic_value proc;
|
2016-02-19 02:17:13 -05:00
|
|
|
size_t ai = pic_enter(pic);
|
2016-02-06 09:55:39 -05:00
|
|
|
|
2016-02-21 06:13:05 -05:00
|
|
|
#if 0
|
2016-02-19 02:17:13 -05:00
|
|
|
fprintf(stdout, "ai = %zu\n", pic_enter(pic));
|
2016-02-06 09:55:39 -05:00
|
|
|
|
|
|
|
fprintf(stdout, "# input expression\n");
|
|
|
|
pic_write(pic, obj);
|
|
|
|
fprintf(stdout, "\n");
|
|
|
|
|
2016-02-19 02:17:13 -05:00
|
|
|
fprintf(stdout, "ai = %zu\n", pic_enter(pic));
|
2016-02-06 09:55:39 -05:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* optimize */
|
|
|
|
obj = pic_optimize(pic, obj);
|
2016-02-21 06:13:05 -05:00
|
|
|
#if 0
|
2016-02-06 09:55:39 -05:00
|
|
|
fprintf(stdout, "## optimize completed\n");
|
|
|
|
pic_write(pic, obj);
|
|
|
|
fprintf(stdout, "\n");
|
2016-02-19 02:17:13 -05:00
|
|
|
fprintf(stdout, "ai = %zu\n", pic_enter(pic));
|
2016-02-06 09:55:39 -05:00
|
|
|
#endif
|
|
|
|
|
|
|
|
SAVE(pic, ai, obj);
|
|
|
|
|
|
|
|
/* analyze */
|
|
|
|
obj = pic_analyze(pic, obj);
|
2016-02-21 06:13:05 -05:00
|
|
|
#if 0
|
2016-02-06 09:55:39 -05:00
|
|
|
fprintf(stdout, "## analyzer completed\n");
|
|
|
|
pic_write(pic, obj);
|
|
|
|
fprintf(stdout, "\n");
|
2016-02-19 02:17:13 -05:00
|
|
|
fprintf(stdout, "ai = %zu\n", pic_enter(pic));
|
2016-02-06 09:55:39 -05:00
|
|
|
#endif
|
|
|
|
|
|
|
|
SAVE(pic, ai, obj);
|
|
|
|
|
|
|
|
/* codegen */
|
|
|
|
irep = pic_codegen(pic, obj);
|
|
|
|
|
|
|
|
proc = pic_make_proc_irep(pic, irep, NULL);
|
|
|
|
|
|
|
|
pic_irep_decref(pic, irep);
|
|
|
|
|
|
|
|
return proc;
|
|
|
|
}
|
2014-09-08 05:47:20 -04:00
|
|
|
|
|
|
|
pic_value
|
2016-02-18 03:39:32 -05:00
|
|
|
pic_eval(pic_state *pic, pic_value program, const char *lib)
|
2014-09-08 05:47:20 -04:00
|
|
|
{
|
2016-02-18 03:39:32 -05:00
|
|
|
const char *prev_lib = pic_current_library(pic);
|
2016-02-20 02:33:51 -05:00
|
|
|
pic_value env, r;
|
2016-02-06 14:23:46 -05:00
|
|
|
|
2016-02-18 03:39:32 -05:00
|
|
|
env = pic_library_environment(pic, lib);
|
|
|
|
|
|
|
|
pic_in_library(pic, lib);
|
2016-02-06 14:23:46 -05:00
|
|
|
pic_try {
|
2016-02-18 03:39:32 -05:00
|
|
|
r = pic_call(pic, pic_compile(pic, pic_expand(pic, program, env)), 0);
|
2016-02-06 14:23:46 -05:00
|
|
|
}
|
|
|
|
pic_catch {
|
2016-02-18 03:39:32 -05:00
|
|
|
pic_in_library(pic, prev_lib);
|
2016-02-20 10:30:40 -05:00
|
|
|
pic_raise(pic, pic_err(pic));
|
2016-02-06 14:23:46 -05:00
|
|
|
}
|
2016-02-18 03:39:32 -05:00
|
|
|
pic_in_library(pic, prev_lib);
|
2014-09-08 05:47:20 -04:00
|
|
|
|
2016-02-06 14:23:46 -05:00
|
|
|
return r;
|
2014-09-08 05:47:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
pic_eval_eval(pic_state *pic)
|
|
|
|
{
|
2016-02-18 03:39:32 -05:00
|
|
|
pic_value program;
|
|
|
|
const char *str;
|
2014-09-08 05:47:20 -04:00
|
|
|
|
2016-02-18 03:39:32 -05:00
|
|
|
pic_get_args(pic, "oz", &program, &str);
|
2015-06-16 09:51:49 -04:00
|
|
|
|
2016-02-18 03:39:32 -05:00
|
|
|
return pic_eval(pic, program, str);
|
2014-09-08 05:47:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pic_init_eval(pic_state *pic)
|
|
|
|
{
|
2014-09-08 06:38:19 -04:00
|
|
|
pic_defun(pic, "eval", pic_eval_eval);
|
2014-09-08 05:47:20 -04:00
|
|
|
}
|