diff --git a/include/picrin/macro.h b/include/picrin/macro.h index 14097046..b22de253 100644 --- a/include/picrin/macro.h +++ b/include/picrin/macro.h @@ -27,13 +27,12 @@ struct pic_sc { struct pic_senv *senv; }; -#define pic_sc(v) ((struct pic_sc *)pic_ptr(v)) #define pic_sc_p(v) (pic_type(v) == PIC_TT_SC) +#define pic_sc_ptr(v) ((struct pic_sc *)pic_ptr(v)) -#define pic_macro(v) ((struct pic_macro *)pic_ptr(v)) #define pic_macro_p(v) (pic_type(v) == PIC_TT_MACRO) +#define pic_macro_ptr(v) ((struct pic_macro *)pic_ptr(v)) -#define pic_senv(v) ((struct pic_senv *)pic_ptr(v)) #define pic_senv_p(v) (pic_type(v) == PIC_TT_SENV) #define pic_senv_ptr(v) ((struct pic_senv *)pic_ptr(v)) diff --git a/include/picrin/proc.h b/include/picrin/proc.h index 86e11121..d96fb6c3 100644 --- a/include/picrin/proc.h +++ b/include/picrin/proc.h @@ -40,9 +40,9 @@ struct pic_proc { #define pic_proc_irep_p(proc) ((proc)->kind == PIC_PROC_KIND_IREP) #define pic_proc_p(o) (pic_type(o) == PIC_TT_PROC) -#define pic_env_p(o) (pic_type(o) == PIC_TT_ENV) - #define pic_proc_ptr(o) ((struct pic_proc *)pic_ptr(o)) + +#define pic_env_p(o) (pic_type(o) == PIC_TT_ENV) #define pic_env_ptr(o) ((struct pic_env *)pic_ptr(o)) struct pic_proc *pic_proc_new(pic_state *, pic_func_t, const char *); diff --git a/src/macro.c b/src/macro.c index dd92fba9..508c2904 100644 --- a/src/macro.c +++ b/src/macro.c @@ -11,6 +11,81 @@ #include "picrin/error.h" #include "picrin/box.h" +struct pic_senv * +pic_null_syntactic_env(pic_state *pic) +{ + struct pic_senv *senv; + + senv = (struct pic_senv *)pic_obj_alloc(pic, sizeof(struct pic_senv), PIC_TT_SENV); + senv->up = NULL; + xh_init_int(&senv->renames, sizeof(pic_sym)); + + return senv; +} + +struct pic_senv * +pic_minimal_syntactic_env(pic_state *pic) +{ + struct pic_senv *senv = pic_null_syntactic_env(pic); + + pic_put_rename(pic, senv, pic->sDEFINE_LIBRARY, pic->sDEFINE_LIBRARY); + pic_put_rename(pic, senv, pic->sIMPORT, pic->sIMPORT); + pic_put_rename(pic, senv, pic->sEXPORT, pic->sEXPORT); + + return senv; +} + +struct pic_senv * +pic_core_syntactic_env(pic_state *pic) +{ + struct pic_senv *senv = pic_minimal_syntactic_env(pic); + + pic_put_rename(pic, senv, pic->sDEFINE, pic->sDEFINE); + pic_put_rename(pic, senv, pic->sSETBANG, pic->sSETBANG); + pic_put_rename(pic, senv, pic->sQUOTE, pic->sQUOTE); + pic_put_rename(pic, senv, pic->sLAMBDA, pic->sLAMBDA); + pic_put_rename(pic, senv, pic->sIF, pic->sIF); + pic_put_rename(pic, senv, pic->sBEGIN, pic->sBEGIN); + pic_put_rename(pic, senv, pic->sDEFINE_SYNTAX, pic->sDEFINE_SYNTAX); + + return senv; +} + +static pic_value macroexpand(pic_state *, pic_value, struct pic_senv *, pic_value); + +static struct pic_senv * +push_scope(pic_state *pic, pic_value formals, struct pic_senv *up, pic_value assoc_box) +{ + struct pic_senv *senv; + pic_value a; + + senv = (struct pic_senv *)pic_obj_alloc(pic, sizeof(struct pic_senv), PIC_TT_SENV); + senv->up = up; + xh_init_int(&senv->renames, sizeof(pic_sym)); + + for (a = formals; pic_pair_p(a); a = pic_cdr(pic, a)) { + pic_value v = pic_car(pic, a); + + if (! pic_sym_p(v)) { + v = macroexpand(pic, v, up, assoc_box); + } + if (! pic_sym_p(v)) { + pic_error(pic, "syntax error"); + } + pic_add_rename(pic, senv, pic_sym(v)); + } + if (! pic_sym_p(a)) { + a = macroexpand(pic, a, up, assoc_box); + } + if (pic_sym_p(a)) { + pic_add_rename(pic, senv, pic_sym(a)); + } + else if (! pic_nil_p(a)) { + pic_error(pic, "syntax error"); + } + return senv; +} + pic_sym pic_add_rename(pic_state *pic, struct pic_senv *senv, pic_sym sym) { @@ -45,103 +120,6 @@ pic_find_rename(pic_state *pic, struct pic_senv *senv, pic_sym sym, pic_sym *ren return true; } -static pic_value macroexpand(pic_state *, pic_value, struct pic_senv *, pic_value); -static pic_value macroexpand_list(pic_state *, pic_value, struct pic_senv *, pic_value); - -static struct pic_senv * -senv_new(pic_state *pic, struct pic_senv *up) -{ - struct pic_senv *senv; - - senv = (struct pic_senv *)pic_obj_alloc(pic, sizeof(struct pic_senv), PIC_TT_SENV); - senv->up = up; - xh_init_int(&senv->renames, sizeof(pic_sym)); - - return senv; -} - -static struct pic_senv * -senv_new_local(pic_state *pic, pic_value formals, struct pic_senv *up, pic_value assoc_box) -{ - struct pic_senv *senv; - pic_value a; - - senv = senv_new(pic, up); - - for (a = formals; pic_pair_p(a); a = pic_cdr(pic, a)) { - pic_value v = pic_car(pic, a); - - if (! pic_sym_p(v)) { - v = macroexpand(pic, v, up, assoc_box); - } - if (! pic_sym_p(v)) { - pic_error(pic, "syntax error"); - } - pic_add_rename(pic, senv, pic_sym(v)); - } - if (! pic_sym_p(a)) { - a = macroexpand(pic, a, up, assoc_box); - } - if (pic_sym_p(a)) { - pic_add_rename(pic, senv, pic_sym(a)); - } - else if (! pic_nil_p(a)) { - pic_error(pic, "syntax error"); - } - return senv; -} - -struct pic_macro * -macro_new(pic_state *pic, struct pic_proc *proc, struct pic_senv *mac_env) -{ - struct pic_macro *mac; - - mac = (struct pic_macro *)pic_obj_alloc(pic, sizeof(struct pic_macro), PIC_TT_MACRO); - mac->senv = mac_env; - mac->proc = proc; - return mac; -} - -static struct pic_sc * -sc_new(pic_state *pic, pic_value expr, struct pic_senv *senv) -{ - struct pic_sc *sc; - - sc = (struct pic_sc *)pic_obj_alloc(pic, sizeof(struct pic_sc), PIC_TT_SC); - sc->expr = expr; - sc->senv = senv; - return sc; -} - -static bool -identifier_p(pic_value obj) -{ - if (pic_sym_p(obj)) { - return true; - } - if (pic_sc_p(obj)) { - return identifier_p(pic_sc(obj)->expr); - } - return false; -} - -static bool -identifier_eq_p(pic_state *pic, struct pic_senv *e1, pic_value x, struct pic_senv *e2, pic_value y) -{ - pic_value box; - - if (! (identifier_p(x) && identifier_p(y))) { - return false; - } - - box = pic_box(pic, pic_nil_value()); - - x = macroexpand(pic, x, e1, box); - y = macroexpand(pic, y, e2, box); - - return pic_eq_p(x, y); -} - void pic_import(pic_state *pic, pic_value spec) { @@ -179,51 +157,43 @@ pic_export(pic_state *pic, pic_sym sym) xh_put(&pic->lib->exports, sym, &rename); } +static void +define_macro(pic_state *pic, pic_sym rename, struct pic_proc *proc, struct pic_senv *senv) +{ + struct pic_macro *mac; + + mac = (struct pic_macro *)pic_obj_alloc(pic, sizeof(struct pic_macro), PIC_TT_MACRO); + mac->senv = senv; + mac->proc = proc; + + xh_put(&pic->macros, rename, &mac); +} + +static struct pic_macro * +find_macro(pic_state *pic, pic_sym rename) +{ + xh_entry *e; + + if ((e = xh_get(&pic->macros, rename)) == NULL) { + return NULL; + } + return xh_val(e, struct pic_macro *); +} + void pic_defmacro(pic_state *pic, const char *name, struct pic_proc *macro) { - struct pic_macro *mac; pic_sym sym, rename; - /* new macro */ - mac = macro_new(pic, macro, NULL); - /* symbol registration */ sym = pic_intern_cstr(pic, name); rename = pic_add_rename(pic, pic->lib->senv, sym); - xh_put(&pic->macros, rename, &mac); + define_macro(pic, rename, macro, NULL); /* auto export! */ pic_export(pic, sym); } -static pic_sym -symbol_rename(pic_state *pic, pic_sym sym, struct pic_senv *senv, pic_value assoc_box) -{ - pic_sym rename; - pic_value x; - - if (! pic_interned_p(pic, sym)) { - return sym; - } - while (true) { - if (pic_find_rename(pic, senv, sym, &rename)) { - return rename; - } - if (! senv->up) - break; - senv = senv->up; - } - x = pic_assq(pic, pic_sym_value(sym), pic_unbox(pic, assoc_box)); - if (pic_test(x)) { - return pic_sym(pic_cdr(pic, x)); - } else { - rename = pic_gensym(pic, sym); - pic_set_box(pic, assoc_box, pic_acons(pic, pic_sym_value(sym), pic_sym_value(rename), pic_unbox(pic, assoc_box))); - return rename; - } -} - static pic_value macroexpand_node(pic_state *, pic_value, struct pic_senv *, pic_value); static pic_value @@ -239,299 +209,6 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv, pic_value ass return v; } -static pic_value -macroexpand_node(pic_state *pic, pic_value expr, struct pic_senv *senv, pic_value assoc_box) -{ -#if DEBUG - printf("[macroexpand] expanding... "); - pic_debug(pic, expr); - puts(""); -#endif - - switch (pic_type(expr)) { - case PIC_TT_SC: { - struct pic_sc *sc; - - sc = pic_sc(expr); - return macroexpand(pic, sc->expr, sc->senv, assoc_box); - } - case PIC_TT_SYMBOL: { - return pic_symbol_value(symbol_rename(pic, pic_sym(expr), senv, assoc_box)); - } - case PIC_TT_PAIR: { - pic_value car, v; - xh_entry *e; - - if (! pic_list_p(expr)) { - pic_errorf(pic, "cannot macroexpand improper list: ~s", expr); - } - - car = macroexpand(pic, pic_car(pic, expr), senv, assoc_box); - if (pic_sym_p(car)) { - pic_sym tag = pic_sym(car); - - if (tag == pic->sDEFINE_LIBRARY) { - struct pic_lib *prev = pic->lib; - - if (pic_length(pic, expr) < 2) { - pic_error(pic, "syntax error"); - } - pic_make_library(pic, pic_cadr(pic, expr)); - - pic_try { - pic_in_library(pic, pic_cadr(pic, expr)); - - pic_for_each (v, pic_cddr(pic, expr)) { - int ai = pic_gc_arena_preserve(pic); - - pic_eval(pic, v); - - pic_gc_arena_restore(pic, ai); - } - - pic_in_library(pic, prev->name); - } - pic_catch { - /* restores pic->lib even if an error occurs */ - pic_in_library(pic, prev->name); - pic_throw(pic, pic->err); - } - - return pic_none_value(); - } - - else if (tag == pic->sIMPORT) { - pic_value spec; - pic_for_each (spec, pic_cdr(pic, expr)) { - pic_import(pic, spec); - } - return pic_none_value(); - } - - else if (tag == pic->sEXPORT) { - pic_value spec; - pic_for_each (spec, pic_cdr(pic, expr)) { - if (! pic_sym_p(spec)) { - pic_error(pic, "syntax error"); - } - /* TODO: warn if symbol is shadowed by local variable */ - pic_export(pic, pic_sym(spec)); - } - return pic_none_value(); - } - - else if (tag == pic->sDEFINE_SYNTAX) { - pic_value var, val; - pic_sym sym, rename; - struct pic_macro *mac; - - if (pic_length(pic, expr) != 3) { - pic_error(pic, "syntax error"); - } - - var = pic_cadr(pic, expr); - if (! pic_sym_p(var)) { - var = macroexpand(pic, var, senv, assoc_box); - } - if (! pic_sym_p(var)) { - pic_error(pic, "binding to non-symbol object"); - } - sym = pic_sym(var); - if (! pic_find_rename(pic, senv, sym, &rename)) { - rename = pic_add_rename(pic, senv, sym); - } - - val = pic_cadr(pic, pic_cdr(pic, expr)); - - pic_try { - v = pic_eval(pic, val); - } pic_catch { - pic_errorf(pic, "macroexpand error: %s", pic_errmsg(pic)); - } - - if (! pic_proc_p(v)) { - pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", var); - } - - mac = macro_new(pic, pic_proc_ptr(v), senv); - xh_put(&pic->macros, rename, &mac); - - return pic_none_value(); - } - - else if (tag == pic->sDEFINE_MACRO) { - pic_value var, val; - pic_sym sym, rename; - struct pic_macro *mac; - - if (pic_length(pic, expr) < 2) { - pic_error(pic, "syntax error"); - } - - var = pic_car(pic, pic_cdr(pic, expr)); - if (pic_pair_p(var)) { - /* FIXME: unhygienic */ - val = pic_cons(pic, pic_symbol_value(pic->sLAMBDA), - pic_cons(pic, pic_cdr(pic, var), - pic_cdr(pic, pic_cdr(pic, expr)))); - var = pic_car(pic, var); - } - else { - if (pic_length(pic, expr) != 3) { - pic_error(pic, "syntax_error"); - } - val = pic_car(pic, pic_cdr(pic, pic_cdr(pic, expr))); - } - if (! pic_sym_p(var)) { - pic_error(pic, "syntax error"); - } - sym = pic_sym(var); - if (! pic_find_rename(pic, senv, sym, &rename)) { - rename = pic_add_rename(pic, senv, sym); - } - - pic_try { - v = pic_eval(pic, val); - } pic_catch { - pic_errorf(pic, "macroexpand error: %s", pic_errmsg(pic)); - } - - if (! pic_proc_p(v)) { - pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", var); - } - - mac = macro_new(pic, pic_proc_ptr(v), NULL); - xh_put(&pic->macros, rename, &mac); - - return pic_none_value(); - } - - else if (tag == pic->sLAMBDA) { - struct pic_senv *in = senv_new_local(pic, pic_cadr(pic, expr), senv, assoc_box); - - return pic_cons(pic, car, - pic_cons(pic, - macroexpand_list(pic, pic_cadr(pic, expr), in, assoc_box), - macroexpand_list(pic, pic_cddr(pic, expr), in, assoc_box))); - } - - else if (tag == pic->sDEFINE) { - pic_sym sym; - pic_value formals; - - if (pic_length(pic, expr) < 2) { - pic_error(pic, "syntax error"); - } - - formals = pic_cadr(pic, expr); - if (pic_pair_p(formals)) { - struct pic_senv *in = senv_new_local(pic, pic_cdr(pic, formals), senv, assoc_box); - pic_value a; - - /* defined symbol */ - a = pic_car(pic, formals); - if (! pic_sym_p(a)) { - a = macroexpand(pic, a, senv, assoc_box); - } - if (! pic_sym_p(a)) { - pic_error(pic, "binding to non-symbol object"); - } - sym = pic_sym(a); - if (! pic_find_rename(pic, senv, sym, NULL)) { - pic_add_rename(pic, senv, sym); - } - - /* binding value */ - return pic_cons(pic, car, - pic_cons(pic, - macroexpand_list(pic, pic_cadr(pic, expr), in, assoc_box), - macroexpand_list(pic, pic_cddr(pic, expr), in, assoc_box))); - } - - if (! pic_sym_p(formals)) { - formals = macroexpand(pic, formals, senv, assoc_box); - } - if (! pic_sym_p(formals)) { - pic_error(pic, "binding to non-symbol object"); - } - sym = pic_sym(formals); - if (! pic_find_rename(pic, senv, sym, NULL)) { - pic_add_rename(pic, senv, sym); - } - - return pic_cons(pic, pic_symbol_value(tag), macroexpand_list(pic, pic_cdr(pic, expr), senv, assoc_box)); - } - - else if (tag == pic->sQUOTE) { - return pic_cons(pic, car, pic_cdr(pic, expr)); - } - - /* macro */ - if ((e = xh_get(&pic->macros, tag)) != NULL) { - pic_value v, args; - struct pic_macro *mac; - -#if DEBUG - puts("before expand-1:"); - pic_debug(pic, expr); - puts(""); -#endif - - mac = xh_val(e, struct pic_macro *); - if (mac->senv == NULL) { /* legacy macro */ - args = pic_cdr(pic, expr); - } - else { - args = pic_list3(pic, expr, pic_obj_value(senv), pic_obj_value(mac->senv)); - } - - pic_try { - v = pic_apply(pic, mac->proc, args); - } pic_catch { - pic_errorf(pic, "macroexpand error: %s", pic_errmsg(pic)); - } - -#if DEBUG - puts("after expand-1:"); - pic_debug(pic, v); - puts(""); -#endif - - return macroexpand(pic, v, senv, assoc_box); - } - } - - return pic_cons(pic, car, macroexpand_list(pic, pic_cdr(pic, expr), senv, assoc_box)); - } - case PIC_TT_EOF: - case PIC_TT_NIL: - case PIC_TT_BOOL: - case PIC_TT_FLOAT: - case PIC_TT_INT: - case PIC_TT_CHAR: - case PIC_TT_STRING: - case PIC_TT_VECTOR: - case PIC_TT_BLOB: { - return expr; - } - case PIC_TT_PROC: - case PIC_TT_PORT: - case PIC_TT_ERROR: - case PIC_TT_ENV: - case PIC_TT_CONT: - case PIC_TT_UNDEF: - case PIC_TT_SENV: - case PIC_TT_MACRO: - case PIC_TT_LIB: - case PIC_TT_VAR: - case PIC_TT_IREP: - case PIC_TT_DATA: - case PIC_TT_BOX: - pic_errorf(pic, "unexpected value type: ~s", expr); - } - UNREACHABLE(); -} - static pic_value macroexpand_list(pic_state *pic, pic_value list, struct pic_senv *senv, pic_value assoc_box) { @@ -567,6 +244,369 @@ macroexpand_list(pic_state *pic, pic_value list, struct pic_senv *senv, pic_valu return list; } +static pic_sym +macroexpand_symbol(pic_state *pic, pic_sym sym, struct pic_senv *senv, pic_value assoc_box) +{ + pic_sym rename; + pic_value x; + + if (! pic_interned_p(pic, sym)) { + return sym; + } + while (true) { + if (pic_find_rename(pic, senv, sym, &rename)) { + return rename; + } + if (! senv->up) + break; + senv = senv->up; + } + x = pic_assq(pic, pic_sym_value(sym), pic_unbox(pic, assoc_box)); + if (pic_test(x)) { + return pic_sym(pic_cdr(pic, x)); + } else { + rename = pic_gensym(pic, sym); + pic_set_box(pic, assoc_box, pic_acons(pic, pic_sym_value(sym), pic_sym_value(rename), pic_unbox(pic, assoc_box))); + return rename; + } +} + +static pic_value +macroexpand_deflibrary(pic_state *pic, pic_value expr) +{ + struct pic_lib *prev = pic->lib; + pic_value v; + + if (pic_length(pic, expr) < 2) { + pic_error(pic, "syntax error"); + } + + pic_make_library(pic, pic_cadr(pic, expr)); + + pic_try { + pic_in_library(pic, pic_cadr(pic, expr)); + + pic_for_each (v, pic_cddr(pic, expr)) { + int ai = pic_gc_arena_preserve(pic); + + pic_eval(pic, v); + + pic_gc_arena_restore(pic, ai); + } + + pic_in_library(pic, prev->name); + } + pic_catch { + /* restores pic->lib even if an error occurs */ + pic_in_library(pic, prev->name); + pic_throw(pic, pic->err); + } + + return pic_none_value(); +} + +static pic_value +macroexpand_import(pic_state *pic, pic_value expr) +{ + pic_value spec; + + pic_for_each (spec, pic_cdr(pic, expr)) { + pic_import(pic, spec); + } + + return pic_none_value(); +} + +static pic_value +macroexpand_export(pic_state *pic, pic_value expr) +{ + pic_value spec; + + pic_for_each (spec, pic_cdr(pic, expr)) { + if (! pic_sym_p(spec)) { + pic_error(pic, "syntax error"); + } + /* TODO: warn if symbol is shadowed by local variable */ + pic_export(pic, pic_sym(spec)); + } + + return pic_none_value(); +} + +static pic_value +macroexpand_defsyntax(pic_state *pic, pic_value expr, struct pic_senv *senv, pic_value assoc_box) +{ + pic_value var, val; + pic_sym sym, rename; + + if (pic_length(pic, expr) != 3) { + pic_error(pic, "syntax error"); + } + + var = pic_cadr(pic, expr); + if (! pic_sym_p(var)) { + var = macroexpand(pic, var, senv, assoc_box); + } + if (! pic_sym_p(var)) { + pic_error(pic, "binding to non-symbol object"); + } + sym = pic_sym(var); + if (! pic_find_rename(pic, senv, sym, &rename)) { + rename = pic_add_rename(pic, senv, sym); + } + + val = pic_cadr(pic, pic_cdr(pic, expr)); + + pic_try { + val = pic_eval(pic, val); + } pic_catch { + pic_errorf(pic, "macroexpand error: %s", pic_errmsg(pic)); + } + + if (! pic_proc_p(val)) { + pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", var); + } + + define_macro(pic, rename, pic_proc_ptr(val), senv); + + return pic_none_value(); +} + +static pic_value +macroexpand_defmacro(pic_state *pic, pic_value expr, struct pic_senv *senv) +{ + pic_value var, val; + pic_sym sym, rename; + + if (pic_length(pic, expr) < 2) { + pic_error(pic, "syntax error"); + } + + var = pic_car(pic, pic_cdr(pic, expr)); + if (pic_pair_p(var)) { + /* FIXME: unhygienic */ + val = pic_cons(pic, pic_sym_value(pic->sLAMBDA), + pic_cons(pic, pic_cdr(pic, var), + pic_cdr(pic, pic_cdr(pic, expr)))); + var = pic_car(pic, var); + } + else { + if (pic_length(pic, expr) != 3) { + pic_error(pic, "syntax_error"); + } + val = pic_car(pic, pic_cdr(pic, pic_cdr(pic, expr))); + } + if (! pic_sym_p(var)) { + pic_error(pic, "syntax error"); + } + sym = pic_sym(var); + if (! pic_find_rename(pic, senv, sym, &rename)) { + rename = pic_add_rename(pic, senv, sym); + } + + pic_try { + val = pic_eval(pic, val); + } pic_catch { + pic_errorf(pic, "macroexpand error: %s", pic_errmsg(pic)); + } + + if (! pic_proc_p(val)) { + pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", var); + } + + define_macro(pic, rename, pic_proc_ptr(val), NULL); + + return pic_none_value(); +} + +static pic_value +macroexpand_define(pic_state *pic, pic_value expr, struct pic_senv *senv, pic_value assoc_box) +{ + pic_sym sym; + pic_value formals; + + if (pic_length(pic, expr) < 2) { + pic_error(pic, "syntax error"); + } + + formals = pic_cadr(pic, expr); + if (pic_pair_p(formals)) { + struct pic_senv *in = push_scope(pic, pic_cdr(pic, formals), senv, assoc_box); + pic_value a; + + /* defined symbol */ + a = pic_car(pic, formals); + if (! pic_sym_p(a)) { + a = macroexpand(pic, a, senv, assoc_box); + } + if (! pic_sym_p(a)) { + pic_error(pic, "binding to non-symbol object"); + } + sym = pic_sym(a); + if (! pic_find_rename(pic, senv, sym, NULL)) { + pic_add_rename(pic, senv, sym); + } + + /* binding value */ + return pic_cons(pic, pic_sym_value(pic->sDEFINE), + pic_cons(pic, + macroexpand_list(pic, pic_cadr(pic, expr), in, assoc_box), + macroexpand_list(pic, pic_cddr(pic, expr), in, assoc_box))); + } + + if (! pic_sym_p(formals)) { + formals = macroexpand(pic, formals, senv, assoc_box); + } + if (! pic_sym_p(formals)) { + pic_error(pic, "binding to non-symbol object"); + } + sym = pic_sym(formals); + if (! pic_find_rename(pic, senv, sym, NULL)) { + pic_add_rename(pic, senv, sym); + } + + return pic_cons(pic, pic_sym_value(pic->sDEFINE), macroexpand_list(pic, pic_cdr(pic, expr), senv, assoc_box)); +} + +static pic_value +macroexpand_lambda(pic_state *pic, pic_value expr, struct pic_senv *senv, pic_value assoc_box) +{ + struct pic_senv *in = push_scope(pic, pic_cadr(pic, expr), senv, assoc_box); + + return pic_cons(pic, pic_sym_value(pic->sLAMBDA), + pic_cons(pic, + macroexpand_list(pic, pic_cadr(pic, expr), in, assoc_box), + macroexpand_list(pic, pic_cddr(pic, expr), in, assoc_box))); +} + +static pic_value +macroexpand_quote(pic_state *pic, pic_value expr) +{ + return pic_cons(pic, pic_sym_value(pic->sQUOTE), pic_cdr(pic, expr)); +} + +static pic_value +macroexpand_macro(pic_state *pic, struct pic_macro *mac, pic_value expr, struct pic_senv *senv, pic_value assoc_box) +{ + pic_value v, args; + +#if DEBUG + puts("before expand-1:"); + pic_debug(pic, expr); + puts(""); +#endif + + if (mac->senv == NULL) { /* legacy macro */ + args = pic_cdr(pic, expr); + } + else { + args = pic_list3(pic, expr, pic_obj_value(senv), pic_obj_value(mac->senv)); + } + + pic_try { + v = pic_apply(pic, mac->proc, args); + } pic_catch { + pic_errorf(pic, "macroexpand error: %s", pic_errmsg(pic)); + } + +#if DEBUG + puts("after expand-1:"); + pic_debug(pic, v); + puts(""); +#endif + + return macroexpand(pic, v, senv, assoc_box); +} + +static pic_value +macroexpand_node(pic_state *pic, pic_value expr, struct pic_senv *senv, pic_value assoc_box) +{ +#if DEBUG + printf("[macroexpand] expanding... "); + pic_debug(pic, expr); + puts(""); +#endif + + switch (pic_type(expr)) { + case PIC_TT_SC: { + return macroexpand(pic, pic_sc_ptr(expr)->expr, pic_sc_ptr(expr)->senv, assoc_box); + } + case PIC_TT_SYMBOL: { + return pic_sym_value(macroexpand_symbol(pic, pic_sym(expr), senv, assoc_box)); + } + case PIC_TT_PAIR: { + pic_value car; + struct pic_macro *mac; + + if (! pic_list_p(expr)) { + pic_errorf(pic, "cannot macroexpand improper list: ~s", expr); + } + + car = macroexpand(pic, pic_car(pic, expr), senv, assoc_box); + if (pic_sym_p(car)) { + pic_sym tag = pic_sym(car); + + if (tag == pic->sDEFINE_LIBRARY) { + return macroexpand_deflibrary(pic, expr); + } + else if (tag == pic->sIMPORT) { + return macroexpand_import(pic, expr); + } + else if (tag == pic->sEXPORT) { + return macroexpand_export(pic, expr); + } + else if (tag == pic->sDEFINE_SYNTAX) { + return macroexpand_defsyntax(pic, expr, senv, assoc_box); + } + else if (tag == pic->sDEFINE_MACRO) { + return macroexpand_defmacro(pic, expr, senv); + } + else if (tag == pic->sLAMBDA) { + return macroexpand_lambda(pic, expr, senv, assoc_box); + } + else if (tag == pic->sDEFINE) { + return macroexpand_define(pic, expr, senv, assoc_box); + } + else if (tag == pic->sQUOTE) { + return macroexpand_quote(pic, expr); + } + + if ((mac = find_macro(pic, tag)) != NULL) { + return macroexpand_macro(pic, mac, expr, senv, assoc_box); + } + } + + return pic_cons(pic, car, macroexpand_list(pic, pic_cdr(pic, expr), senv, assoc_box)); + } + case PIC_TT_EOF: + case PIC_TT_NIL: + case PIC_TT_BOOL: + case PIC_TT_FLOAT: + case PIC_TT_INT: + case PIC_TT_CHAR: + case PIC_TT_STRING: + case PIC_TT_VECTOR: + case PIC_TT_BLOB: { + return expr; + } + case PIC_TT_PROC: + case PIC_TT_PORT: + case PIC_TT_ERROR: + case PIC_TT_ENV: + case PIC_TT_CONT: + case PIC_TT_UNDEF: + case PIC_TT_SENV: + case PIC_TT_MACRO: + case PIC_TT_LIB: + case PIC_TT_VAR: + case PIC_TT_IREP: + case PIC_TT_DATA: + case PIC_TT_BOX: + pic_errorf(pic, "unexpected value type: ~s", expr); + } + UNREACHABLE(); +} + pic_value pic_macroexpand(pic_state *pic, pic_value expr) { @@ -591,45 +631,6 @@ pic_macroexpand(pic_state *pic, pic_value expr) return v; } -struct pic_senv * -pic_null_syntactic_env(pic_state *pic) -{ - return senv_new(pic, NULL); -} - -#define register_core_syntax(pic,senv,id) do { \ - pic_sym sym = pic_intern_cstr(pic, id); \ - pic_put_rename(pic, senv, sym, sym); \ - } while (0) - -struct pic_senv * -pic_minimal_syntactic_env(pic_state *pic) -{ - struct pic_senv *senv = pic_null_syntactic_env(pic); - - register_core_syntax(pic, senv, "define-library"); - register_core_syntax(pic, senv, "import"); - register_core_syntax(pic, senv, "export"); - - return senv; -} - -struct pic_senv * -pic_core_syntactic_env(pic_state *pic) -{ - struct pic_senv *senv = pic_minimal_syntactic_env(pic); - - register_core_syntax(pic, senv, "define"); - register_core_syntax(pic, senv, "set!"); - register_core_syntax(pic, senv, "quote"); - register_core_syntax(pic, senv, "lambda"); - register_core_syntax(pic, senv, "if"); - register_core_syntax(pic, senv, "begin"); - register_core_syntax(pic, senv, "define-syntax"); - - return senv; -} - /* once read.c is implemented move there */ static pic_value pic_macro_include(pic_state *pic) @@ -641,7 +642,7 @@ pic_macro_include(pic_state *pic) pic_get_args(pic, "*", &argc, &argv); /* FIXME unhygienic */ - body = pic_list1(pic, pic_symbol_value(pic->sBEGIN)); + body = pic_list1(pic, pic_sym_value(pic->sBEGIN)); for (i = 0; i < argc; ++i) { const char *filename; @@ -672,7 +673,7 @@ pic_macro_gensym(pic_state *pic) pic_get_args(pic, ""); uniq = pic_gensym(pic, pic_intern_cstr(pic, skel)); - return pic_symbol_value(uniq); + return pic_sym_value(uniq); } static pic_value @@ -685,6 +686,46 @@ pic_macro_macroexpand(pic_state *pic) return pic_macroexpand(pic, expr); } +static struct pic_sc * +sc_new(pic_state *pic, pic_value expr, struct pic_senv *senv) +{ + struct pic_sc *sc; + + sc = (struct pic_sc *)pic_obj_alloc(pic, sizeof(struct pic_sc), PIC_TT_SC); + sc->expr = expr; + sc->senv = senv; + return sc; +} + +static bool +sc_identifier_p(pic_value obj) +{ + if (pic_sym_p(obj)) { + return true; + } + if (pic_sc_p(obj)) { + return sc_identifier_p(pic_sc_ptr(obj)->expr); + } + return false; +} + +static bool +sc_identifier_eq_p(pic_state *pic, struct pic_senv *e1, pic_value x, struct pic_senv *e2, pic_value y) +{ + pic_value box; + + if (! (sc_identifier_p(x) && sc_identifier_p(y))) { + return false; + } + + box = pic_box(pic, pic_nil_value()); + + x = macroexpand(pic, x, e1, box); + y = macroexpand(pic, y, e2, box); + + return pic_eq_p(x, y); +} + static pic_value pic_macro_make_sc(pic_state *pic) { @@ -697,7 +738,7 @@ pic_macro_make_sc(pic_state *pic) pic_error(pic, "make-syntactic-closure: senv required"); /* just ignore free_vars for now */ - sc = sc_new(pic, expr, pic_senv(senv)); + sc = sc_new(pic, expr, pic_senv_ptr(senv)); return pic_obj_value(sc); } @@ -709,7 +750,7 @@ pic_macro_identifier_p(pic_state *pic) pic_get_args(pic, "o", &obj); - return pic_bool_value(identifier_p(obj)); + return pic_bool_value(sc_identifier_p(obj)); } static pic_value @@ -723,13 +764,13 @@ pic_macro_identifier_eq_p(pic_state *pic) if (! pic_senv_p(e)) { pic_error(pic, "unexpected type of argument 1"); } - e1 = pic_senv(e); + e1 = pic_senv_ptr(e); if (! pic_senv_p(f)) { pic_error(pic, "unexpected type of argument 3"); } - e2 = pic_senv(f); + e2 = pic_senv_ptr(f); - return pic_bool_value(identifier_eq_p(pic, e1, x, e2, y)); + return pic_bool_value(sc_identifier_eq_p(pic, e1, x, e2, y)); } static pic_value @@ -744,7 +785,7 @@ er_macro_rename(pic_state *pic) mac_env = pic_senv_ptr(pic_proc_cv_ref(pic, pic_get_proc(pic), 1)); assoc_box = pic_proc_cv_ref(pic, pic_get_proc(pic), 2); - return pic_symbol_value(symbol_rename(pic, sym, mac_env, assoc_box)); + return pic_sym_value(macroexpand_symbol(pic, sym, mac_env, assoc_box)); } static pic_value @@ -763,8 +804,8 @@ er_macro_compare(pic_state *pic) use_env = pic_senv_ptr(pic_proc_cv_ref(pic, pic_get_proc(pic), 0)); assoc_box = pic_proc_cv_ref(pic, pic_get_proc(pic), 2); - m = symbol_rename(pic, pic_sym(a), use_env, assoc_box); - n = symbol_rename(pic, pic_sym(b), use_env, assoc_box); + m = macroexpand_symbol(pic, pic_sym(a), use_env, assoc_box); + n = macroexpand_symbol(pic, pic_sym(b), use_env, assoc_box); return pic_bool_value(m == n); } @@ -829,7 +870,7 @@ ir_macro_inject(pic_state *pic) use_env = pic_senv_ptr(pic_proc_cv_ref(pic, pic_get_proc(pic), 0)); assoc_box = pic_proc_cv_ref(pic, pic_get_proc(pic), 2); - return pic_symbol_value(symbol_rename(pic, sym, use_env, assoc_box)); + return pic_sym_value(macroexpand_symbol(pic, sym, use_env, assoc_box)); } static pic_value @@ -848,8 +889,8 @@ ir_macro_compare(pic_state *pic) mac_env = pic_senv_ptr(pic_proc_cv_ref(pic, pic_get_proc(pic), 1)); assoc_box = pic_proc_cv_ref(pic, pic_get_proc(pic), 2); - m = symbol_rename(pic, pic_sym(a), mac_env, assoc_box); - n = symbol_rename(pic, pic_sym(b), mac_env, assoc_box); + m = macroexpand_symbol(pic, pic_sym(a), mac_env, assoc_box); + n = macroexpand_symbol(pic, pic_sym(b), mac_env, assoc_box); return pic_bool_value(m == n); } @@ -859,7 +900,7 @@ ir_macro_wrap(pic_state *pic, pic_value expr, struct pic_senv *use_env, pic_valu { if (pic_sym_p(expr)) { pic_value r; - r = pic_sym_value(symbol_rename(pic, pic_sym(expr), use_env, assoc_box)); + r = pic_sym_value(macroexpand_symbol(pic, pic_sym(expr), use_env, assoc_box)); *ir = pic_acons(pic, r, expr, *ir); return r; } @@ -881,7 +922,7 @@ ir_macro_unwrap(pic_state *pic, pic_value expr, struct pic_senv *mac_env, pic_va if (pic_test(r = pic_assq(pic, expr, *ir))) { return pic_cdr(pic, r); } - return pic_sym_value(symbol_rename(pic, pic_sym(expr), mac_env, assoc_box)); + return pic_sym_value(macroexpand_symbol(pic, pic_sym(expr), mac_env, assoc_box)); } else if (pic_pair_p(expr)) { return pic_cons(pic, diff --git a/src/write.c b/src/write.c index 4c59d8ed..2eb3575e 100644 --- a/src/write.c +++ b/src/write.c @@ -320,7 +320,7 @@ write_core(struct writer_control *p, pic_value obj) break; case PIC_TT_SC: xfprintf(file, "#expr); + write_core(p, pic_sc_ptr(obj)->expr); xfprintf(file, ">"); break; case PIC_TT_LIB: