Merge branch 'improved-hygiene2'
This commit is contained in:
		
						commit
						6c821105fd
					
				|  | @ -1,28 +1,25 @@ | |||
| (define-library (scheme case-lambda) | ||||
|   (import (scheme base)) | ||||
| 
 | ||||
|   (define (length+ list) | ||||
|     (if (pair? list) | ||||
|         (+ 1 (length+ (cdr list))) | ||||
|         0)) | ||||
| 
 | ||||
|   (define-syntax case-lambda | ||||
|     (syntax-rules () | ||||
|       ((case-lambda (params body0 ...) ...) | ||||
|        (lambda args | ||||
|          (let ((len (length args))) | ||||
|            (letrec-syntax | ||||
|                ((cl (syntax-rules ::: () | ||||
|                ((cl (syntax-rules () | ||||
|                       ((cl) | ||||
|                        (error "no matching clause")) | ||||
|                       ((cl ((p :::) . body) . rest) | ||||
|                        (if (= len (length '(p :::))) | ||||
|                            (apply (lambda (p :::) | ||||
|                                     . body) | ||||
|                                   args) | ||||
|                            (cl . rest))) | ||||
|                       ((cl ((p ::: . tail) . body) | ||||
|                            . rest) | ||||
|                        (if (>= len (length '(p :::))) | ||||
|                            (apply | ||||
|                             (lambda (p ::: . tail) | ||||
|                               . body) | ||||
|                             args) | ||||
|                       ((cl (formal . body) . rest) | ||||
|                        (if (if (list? 'formal) | ||||
|                                (= len (length 'formal)) | ||||
|                                (>= len (length+ 'formal))) | ||||
|                            (apply (lambda formal . body) args) | ||||
|                            (cl . rest)))))) | ||||
|              (cl (params body0 ...) ...))))))) | ||||
| 
 | ||||
|  |  | |||
|  | @ -104,6 +104,14 @@ internal_equal_p(pic_state *pic, pic_value x, pic_value y, size_t depth, xhash * | |||
|     } | ||||
|     return true; | ||||
|   } | ||||
|   case PIC_TT_ID: { | ||||
|     struct pic_id *id1, *id2; | ||||
| 
 | ||||
|     id1 = pic_id_ptr(x); | ||||
|     id2 = pic_id_ptr(y); | ||||
| 
 | ||||
|     return pic_eq_p(pic_expand(pic, id1->var, id1->env), pic_expand(pic, id2->var, id2->env)); | ||||
|   } | ||||
|   default: | ||||
|     return false; | ||||
|   } | ||||
|  | @ -195,7 +203,7 @@ pic_init_bool(pic_state *pic) | |||
|   pic_defun(pic, "eqv?", pic_bool_eqv_p); | ||||
|   pic_defun(pic, "equal?", pic_bool_equal_p); | ||||
| 
 | ||||
|   pic_defun_vm(pic, "not", pic->rNOT, pic_bool_not); | ||||
|   pic_defun_vm(pic, "not", pic->uNOT, pic_bool_not); | ||||
| 
 | ||||
|   pic_defun(pic, "boolean?", pic_bool_boolean_p); | ||||
|   pic_defun(pic, "boolean=?", pic_bool_boolean_eq_p); | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -4,6 +4,347 @@ | |||
| 
 | ||||
| #include "picrin.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * macro expander | ||||
|  */ | ||||
| 
 | ||||
| static pic_sym * | ||||
| lookup(pic_state PIC_UNUSED(*pic), pic_value var, struct pic_env *env) | ||||
| { | ||||
|   xh_entry *e; | ||||
| 
 | ||||
|   assert(pic_var_p(var)); | ||||
| 
 | ||||
|   while (env != NULL) { | ||||
|     if ((e = xh_get_ptr(&env->map, pic_ptr(var))) != NULL) { | ||||
|       return xh_val(e, pic_sym *); | ||||
|     } | ||||
|     env = env->up; | ||||
|   } | ||||
|   return NULL; | ||||
| } | ||||
| 
 | ||||
| static pic_sym * | ||||
| resolve(pic_state *pic, pic_value var, struct pic_env *env) | ||||
| { | ||||
|   pic_sym *uid; | ||||
| 
 | ||||
|   assert(pic_var_p(var)); | ||||
|   assert(env != NULL); | ||||
| 
 | ||||
|   while ((uid = lookup(pic, var, env)) == NULL) { | ||||
|     if (pic_sym_p(var)) { | ||||
|       break; | ||||
|     } | ||||
|     env = pic_id_ptr(var)->env; | ||||
|     var = pic_id_ptr(var)->var; | ||||
|   } | ||||
|   if (uid == NULL) { | ||||
|     while (env->up != NULL) { | ||||
|       env = env->up; | ||||
|     } | ||||
|     uid = pic_add_variable(pic, env, var); | ||||
|   } | ||||
|   return uid; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| define_macro(pic_state *pic, pic_sym *uid, struct pic_proc *mac) | ||||
| { | ||||
|   pic_dict_set(pic, pic->macros, uid, pic_obj_value(mac)); | ||||
| } | ||||
| 
 | ||||
| static struct pic_proc * | ||||
| find_macro(pic_state *pic, pic_sym *uid) | ||||
| { | ||||
|   if (! pic_dict_has(pic, pic->macros, uid)) { | ||||
|     return NULL; | ||||
|   } | ||||
|   return pic_proc_ptr(pic_dict_ref(pic, pic->macros, uid)); | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| expand_var(pic_state *pic, pic_value var, struct pic_env *env) | ||||
| { | ||||
|   return pic_obj_value(resolve(pic, var, env)); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| expand_quote(pic_state *pic, pic_value expr) | ||||
| { | ||||
|   return pic_cons(pic, pic_obj_value(pic->uQUOTE), pic_cdr(pic, expr)); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|   pic_value skel = pic_list1(pic, pic_invalid_value()); /* (#<invalid>) */ | ||||
| 
 | ||||
|   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; | ||||
| 
 | ||||
|   if (pic_length(pic, expr) < 2) { | ||||
|     pic_errorf(pic, "syntax error"); | ||||
|   } | ||||
| 
 | ||||
|   in = pic_make_env(pic, env); | ||||
| 
 | ||||
|   for (a = pic_cadr(pic, expr); pic_pair_p(a); a = pic_cdr(pic, a)) { | ||||
|     pic_value var = pic_car(pic, a); | ||||
| 
 | ||||
|     if (! pic_var_p(var)) { | ||||
|       pic_errorf(pic, "syntax error"); | ||||
|     } | ||||
|     pic_add_variable(pic, in, var); | ||||
|   } | ||||
|   if (pic_var_p(a)) { | ||||
|     pic_add_variable(pic, in, a); | ||||
|   } | ||||
|   else if (! pic_nil_p(a)) { | ||||
|     pic_errorf(pic, "syntax error"); | ||||
|   } | ||||
| 
 | ||||
|   deferred = pic_list1(pic, pic_nil_value()); | ||||
| 
 | ||||
|   formal = expand_list(pic, pic_cadr(pic, expr), in, deferred); | ||||
|   body = expand_list(pic, pic_cddr(pic, expr), in, deferred); | ||||
| 
 | ||||
|   expand_deferred(pic, deferred, in); | ||||
| 
 | ||||
|   return pic_cons(pic, pic_obj_value(pic->uLAMBDA), pic_cons(pic, formal, body)); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|   while (pic_length(pic, expr) >= 2 && pic_pair_p(pic_cadr(pic, expr))) { | ||||
|     var = pic_car(pic, pic_cadr(pic, expr)); | ||||
|     val = pic_cdr(pic, pic_cadr(pic, expr)); | ||||
| 
 | ||||
|     expr = pic_list3(pic, pic_obj_value(pic->uDEFINE), var, pic_cons(pic, pic_obj_value(pic->sLAMBDA), pic_cons(pic, val, pic_cddr(pic, expr)))); | ||||
|   } | ||||
| 
 | ||||
|   if (pic_length(pic, expr) != 3) { | ||||
|     pic_errorf(pic, "syntax error"); | ||||
|   } | ||||
| 
 | ||||
|   var = pic_cadr(pic, expr); | ||||
|   if (! pic_var_p(var)) { | ||||
|     pic_errorf(pic, "binding to non-variable object"); | ||||
|   } | ||||
|   if ((uid = pic_find_variable(pic, env, var)) == NULL) { | ||||
|     uid = pic_add_variable(pic, env, var); | ||||
|   } | ||||
|   val = expand(pic, pic_list_ref(pic, expr, 2), env, deferred); | ||||
| 
 | ||||
|   return pic_list3(pic, pic_obj_value(pic->uDEFINE), pic_obj_value(uid), val); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| expand_defmacro(pic_state *pic, pic_value expr, struct pic_env *env) | ||||
| { | ||||
|   pic_value var, val; | ||||
|   pic_sym *uid; | ||||
| 
 | ||||
|   if (pic_length(pic, expr) != 3) { | ||||
|     pic_errorf(pic, "syntax error"); | ||||
|   } | ||||
| 
 | ||||
|   var = pic_cadr(pic, expr); | ||||
|   if (! pic_var_p(var)) { | ||||
|     pic_errorf(pic, "binding to non-variable object"); | ||||
|   } | ||||
|   if ((uid = pic_find_variable(pic, env, var)) == NULL) { | ||||
|     uid = pic_add_variable(pic, env, var); | ||||
|   } else { | ||||
|     pic_warnf(pic, "redefining syntax variable: ~s", var); | ||||
|   } | ||||
| 
 | ||||
|   val = pic_cadr(pic, pic_cdr(pic, expr)); | ||||
| 
 | ||||
|   pic_try { | ||||
|     val = pic_eval(pic, val, env); | ||||
|   } pic_catch { | ||||
|     pic_errorf(pic, "expand error while definition: %s", pic_errmsg(pic)); | ||||
|   } | ||||
| 
 | ||||
|   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_macro(pic_state *pic, struct pic_proc *mac, pic_value expr, struct pic_env *env) | ||||
| { | ||||
|   pic_value v; | ||||
| 
 | ||||
| #if DEBUG | ||||
|   puts("before expand-1:"); | ||||
|   pic_debug(pic, expr); | ||||
|   puts(""); | ||||
| #endif | ||||
| 
 | ||||
|   pic_try { | ||||
|     v = pic_apply2(pic, mac, expr, pic_obj_value(env)); | ||||
|   } pic_catch { | ||||
|     pic_errorf(pic, "expand error while application: %s", pic_errmsg(pic)); | ||||
|   } | ||||
| 
 | ||||
| #if DEBUG | ||||
|   puts("after expand-1:"); | ||||
|   pic_debug(pic, v); | ||||
|   puts(""); | ||||
| #endif | ||||
| 
 | ||||
|   return v; | ||||
| } | ||||
| 
 | ||||
| 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: { | ||||
|     return expand_var(pic, expr, env); | ||||
|   } | ||||
|   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 = resolve(pic, pic_car(pic, expr), env); | ||||
| 
 | ||||
|       if (functor == pic->uDEFINE_MACRO) { | ||||
|         return expand_defmacro(pic, expr, env); | ||||
|       } | ||||
|       else if (functor == pic->uLAMBDA) { | ||||
|         return expand_defer(pic, expr, deferred); | ||||
|       } | ||||
|       else if (functor == pic->uDEFINE) { | ||||
|         return expand_define(pic, expr, env, deferred); | ||||
|       } | ||||
|       else if (functor == pic->uQUOTE) { | ||||
|         return expand_quote(pic, expr); | ||||
|       } | ||||
| 
 | ||||
|       if ((mac = find_macro(pic, functor)) != NULL) { | ||||
|         return expand_node(pic, expand_macro(pic, mac, expr, env), env, deferred); | ||||
|       } | ||||
|     } | ||||
|     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; | ||||
| 
 | ||||
| #if DEBUG | ||||
|   printf("[expand] expanding... "); | ||||
|   pic_debug(pic, expr); | ||||
|   puts(""); | ||||
| #endif | ||||
| 
 | ||||
|   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; | ||||
| } | ||||
| 
 | ||||
| typedef xvect_t(pic_sym *) xvect; | ||||
| 
 | ||||
| #define xv_push_sym(v, x) xv_push(pic_sym *, (v), (x)) | ||||
|  | @ -331,7 +672,7 @@ analyze_procedure(analyze_state *state, pic_value name, pic_value formals, pic_v | |||
|       : pic_false_value(); | ||||
| 
 | ||||
|     /* To know what kind of local variables are defined, analyze body at first. */ | ||||
|     body = analyze(state, pic_cons(pic, pic_obj_value(pic->rBEGIN), body_exprs), true); | ||||
|     body = analyze(state, pic_cons(pic, pic_obj_value(pic->uBEGIN), body_exprs), true); | ||||
| 
 | ||||
|     analyze_deferred(state); | ||||
| 
 | ||||
|  | @ -399,7 +740,7 @@ analyze_define(analyze_state *state, pic_value obj) | |||
| 
 | ||||
|   if (pic_pair_p(pic_list_ref(pic, obj, 2)) | ||||
|       && pic_sym_p(pic_list_ref(pic, pic_list_ref(pic, obj, 2), 0)) | ||||
|       && pic_sym_ptr(pic_list_ref(pic, pic_list_ref(pic, obj, 2), 0)) == pic->rLAMBDA) { | ||||
|       && pic_sym_ptr(pic_list_ref(pic, pic_list_ref(pic, obj, 2), 0)) == pic->uLAMBDA) { | ||||
|     pic_value formals, body_exprs; | ||||
| 
 | ||||
|     formals = pic_list_ref(pic, pic_list_ref(pic, obj, 2), 1); | ||||
|  | @ -698,88 +1039,88 @@ analyze_node(analyze_state *state, pic_value obj, bool tailpos) | |||
|     if (pic_sym_p(proc)) { | ||||
|       pic_sym *sym = pic_sym_ptr(proc); | ||||
| 
 | ||||
|       if (sym == pic->rDEFINE) { | ||||
|       if (sym == pic->uDEFINE) { | ||||
|         return analyze_define(state, obj); | ||||
|       } | ||||
|       else if (sym == pic->rLAMBDA) { | ||||
|       else if (sym == pic->uLAMBDA) { | ||||
|         return analyze_lambda(state, obj); | ||||
|       } | ||||
|       else if (sym == pic->rIF) { | ||||
|       else if (sym == pic->uIF) { | ||||
|         return analyze_if(state, obj, tailpos); | ||||
|       } | ||||
|       else if (sym == pic->rBEGIN) { | ||||
|       else if (sym == pic->uBEGIN) { | ||||
|         return analyze_begin(state, obj, tailpos); | ||||
|       } | ||||
|       else if (sym == pic->rSETBANG) { | ||||
|       else if (sym == pic->uSETBANG) { | ||||
|         return analyze_set(state, obj); | ||||
|       } | ||||
|       else if (sym == pic->rQUOTE) { | ||||
|       else if (sym == pic->uQUOTE) { | ||||
|         return analyze_quote(state, obj); | ||||
|       } | ||||
|       else if (sym == pic->rCONS) { | ||||
|       else if (sym == pic->uCONS) { | ||||
| 	ARGC_ASSERT(2, "cons"); | ||||
|         return CONSTRUCT_OP2(pic->sCONS); | ||||
|       } | ||||
|       else if (sym == pic->rCAR) { | ||||
|       else if (sym == pic->uCAR) { | ||||
| 	ARGC_ASSERT(1, "car"); | ||||
|         return CONSTRUCT_OP1(pic->sCAR); | ||||
|       } | ||||
|       else if (sym == pic->rCDR) { | ||||
|       else if (sym == pic->uCDR) { | ||||
| 	ARGC_ASSERT(1, "cdr"); | ||||
|         return CONSTRUCT_OP1(pic->sCDR); | ||||
|       } | ||||
|       else if (sym == pic->rNILP) { | ||||
|       else if (sym == pic->uNILP) { | ||||
| 	ARGC_ASSERT(1, "nil?"); | ||||
|         return CONSTRUCT_OP1(pic->sNILP); | ||||
|       } | ||||
|       else if (sym == pic->rSYMBOLP) { | ||||
|       else if (sym == pic->uSYMBOLP) { | ||||
|         ARGC_ASSERT(1, "symbol?"); | ||||
|         return CONSTRUCT_OP1(pic->sSYMBOLP); | ||||
|       } | ||||
|       else if (sym == pic->rPAIRP) { | ||||
|       else if (sym == pic->uPAIRP) { | ||||
|         ARGC_ASSERT(1, "pair?"); | ||||
|         return CONSTRUCT_OP1(pic->sPAIRP); | ||||
|       } | ||||
|       else if (sym == pic->rADD) { | ||||
|       else if (sym == pic->uADD) { | ||||
|         return analyze_add(state, obj, tailpos); | ||||
|       } | ||||
|       else if (sym == pic->rSUB) { | ||||
|       else if (sym == pic->uSUB) { | ||||
|         return analyze_sub(state, obj); | ||||
|       } | ||||
|       else if (sym == pic->rMUL) { | ||||
|       else if (sym == pic->uMUL) { | ||||
|         return analyze_mul(state, obj, tailpos); | ||||
|       } | ||||
|       else if (sym == pic->rDIV) { | ||||
|       else if (sym == pic->uDIV) { | ||||
|         return analyze_div(state, obj); | ||||
|       } | ||||
|       else if (sym == pic->rEQ) { | ||||
|       else if (sym == pic->uEQ) { | ||||
| 	ARGC_ASSERT_WITH_FALLBACK(2); | ||||
|         return CONSTRUCT_OP2(pic->sEQ); | ||||
|       } | ||||
|       else if (sym == pic->rLT) { | ||||
|       else if (sym == pic->uLT) { | ||||
| 	ARGC_ASSERT_WITH_FALLBACK(2); | ||||
|         return CONSTRUCT_OP2(pic->sLT); | ||||
|       } | ||||
|       else if (sym == pic->rLE) { | ||||
|       else if (sym == pic->uLE) { | ||||
| 	ARGC_ASSERT_WITH_FALLBACK(2); | ||||
|         return CONSTRUCT_OP2(pic->sLE); | ||||
|       } | ||||
|       else if (sym == pic->rGT) { | ||||
|       else if (sym == pic->uGT) { | ||||
| 	ARGC_ASSERT_WITH_FALLBACK(2); | ||||
|         return CONSTRUCT_OP2(pic->sGT); | ||||
|       } | ||||
|       else if (sym == pic->rGE) { | ||||
|       else if (sym == pic->uGE) { | ||||
| 	ARGC_ASSERT_WITH_FALLBACK(2); | ||||
|         return CONSTRUCT_OP2(pic->sGE); | ||||
|       } | ||||
|       else if (sym == pic->rNOT) { | ||||
|       else if (sym == pic->uNOT) { | ||||
|         ARGC_ASSERT(1, "not"); | ||||
|         return CONSTRUCT_OP1(pic->sNOT); | ||||
|       } | ||||
|       else if (sym == pic->rVALUES) { | ||||
|       else if (sym == pic->uVALUES) { | ||||
|         return analyze_values(state, obj, tailpos); | ||||
|       } | ||||
|       else if (sym == pic->rCALL_WITH_VALUES) { | ||||
|       else if (sym == pic->uCALL_WITH_VALUES) { | ||||
|         return analyze_call_with_values(state, obj, tailpos); | ||||
|       } | ||||
|     } | ||||
|  | @ -1420,7 +1761,7 @@ pic_codegen(pic_state *pic, pic_value obj) | |||
| } | ||||
| 
 | ||||
| struct pic_proc * | ||||
| pic_compile(pic_state *pic, pic_value obj, struct pic_lib *lib) | ||||
| pic_compile(pic_state *pic, pic_value obj, struct pic_env *env) | ||||
| { | ||||
|   struct pic_irep *irep; | ||||
|   size_t ai = pic_gc_arena_preserve(pic); | ||||
|  | @ -1435,10 +1776,10 @@ pic_compile(pic_state *pic, pic_value obj, struct pic_lib *lib) | |||
|   fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic)); | ||||
| #endif | ||||
| 
 | ||||
|   /* macroexpand */ | ||||
|   obj = pic_macroexpand(pic, obj, lib); | ||||
|   /* expand */ | ||||
|   obj = pic_expand(pic, obj, env); | ||||
| #if DEBUG | ||||
|   fprintf(stdout, "## macroexpand completed\n"); | ||||
|   fprintf(stdout, "## expand completed\n"); | ||||
|   pic_debug(pic, obj); | ||||
|   fprintf(stdout, "\n"); | ||||
|   fprintf(stdout, "ai = %zu\n", pic_gc_arena_preserve(pic)); | ||||
|  |  | |||
|  | @ -288,6 +288,6 @@ pic_init_cont(pic_state *pic) | |||
|   pic_defun(pic, "call/cc", pic_cont_callcc); | ||||
|   pic_defun(pic, "dynamic-wind", pic_cont_dynamic_wind); | ||||
| 
 | ||||
|   pic_defun_vm(pic, "values", pic->rVALUES, pic_cont_values); | ||||
|   pic_defun_vm(pic, "call-with-values", pic->rCALL_WITH_VALUES, pic_cont_call_with_values); | ||||
|   pic_defun_vm(pic, "values", pic->uVALUES, pic_cont_values); | ||||
|   pic_defun_vm(pic, "call-with-values", pic->uCALL_WITH_VALUES, pic_cont_call_with_values); | ||||
| } | ||||
|  |  | |||
|  | @ -5,13 +5,13 @@ | |||
| #include "picrin.h" | ||||
| 
 | ||||
| pic_value | ||||
| pic_eval(pic_state *pic, pic_value program, struct pic_lib *lib) | ||||
| pic_eval(pic_state *pic, pic_value program, struct pic_env *env) | ||||
| { | ||||
|   struct pic_proc *proc; | ||||
| 
 | ||||
|   proc = pic_compile(pic, program, lib); | ||||
|   proc = pic_compile(pic, program, env); | ||||
| 
 | ||||
|   return pic_apply(pic, proc, pic_nil_value()); | ||||
|   return pic_apply0(pic, proc); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
|  | @ -26,7 +26,7 @@ pic_eval_eval(pic_state *pic) | |||
|   if (lib == NULL) { | ||||
|     pic_errorf(pic, "no library found: ~s", spec); | ||||
|   } | ||||
|   return pic_eval(pic, program, lib); | ||||
|   return pic_eval(pic, program, lib->env); | ||||
| } | ||||
| 
 | ||||
| void | ||||
|  |  | |||
|  | @ -411,14 +411,23 @@ gc_mark_object(pic_state *pic, struct pic_object *obj) | |||
|   case PIC_TT_BLOB: { | ||||
|     break; | ||||
|   } | ||||
|   case PIC_TT_ID: { | ||||
|     struct pic_id *id = (struct pic_id *)obj; | ||||
|     gc_mark(pic, id->var); | ||||
|     gc_mark_object(pic, (struct pic_object *)id->env); | ||||
|     break; | ||||
|   } | ||||
|   case PIC_TT_ENV: { | ||||
|     struct pic_env *env = (struct pic_env *)obj; | ||||
|     xh_entry *it; | ||||
| 
 | ||||
|     if (env->up) { | ||||
|       gc_mark_object(pic, (struct pic_object *)env->up); | ||||
|     } | ||||
|     gc_mark(pic, env->defer); | ||||
|     gc_mark_object(pic, (struct pic_object *)env->map); | ||||
|     for (it = xh_begin(&env->map); it != NULL; it = xh_next(it)) { | ||||
|       gc_mark_object(pic, xh_key(it, struct pic_object *)); | ||||
|       gc_mark_object(pic, xh_val(it, struct pic_object *)); | ||||
|     } | ||||
|     break; | ||||
|   } | ||||
|   case PIC_TT_LIB: { | ||||
|  | @ -519,7 +528,9 @@ gc_mark_global_symbols(pic_state *pic) | |||
| { | ||||
|   M(sDEFINE); M(sLAMBDA); M(sIF); M(sBEGIN); M(sQUOTE); M(sSETBANG); | ||||
|   M(sQUASIQUOTE); M(sUNQUOTE); M(sUNQUOTE_SPLICING); | ||||
|   M(sDEFINE_SYNTAX); M(sIMPORT); M(sEXPORT); | ||||
|   M(sSYNTAX_QUOTE); M(sSYNTAX_QUASIQUOTE); M(sSYNTAX_UNQUOTE); | ||||
|   M(sSYNTAX_UNQUOTE_SPLICING); | ||||
|   M(sDEFINE_MACRO); M(sIMPORT); M(sEXPORT); | ||||
|   M(sDEFINE_LIBRARY); | ||||
|   M(sCOND_EXPAND); M(sAND); M(sOR); M(sELSE); M(sLIBRARY); | ||||
|   M(sONLY); M(sRENAME); M(sPREFIX); M(sEXCEPT); | ||||
|  | @ -531,15 +542,15 @@ gc_mark_global_symbols(pic_state *pic) | |||
|   M(sCALL); M(sTAILCALL); M(sCALL_WITH_VALUES); M(sTAILCALL_WITH_VALUES); | ||||
|   M(sGREF); M(sLREF); M(sCREF); M(sRETURN); | ||||
| 
 | ||||
|   M(rDEFINE); M(rLAMBDA); M(rIF); M(rBEGIN); M(rQUOTE); M(rSETBANG); | ||||
|   M(rDEFINE_SYNTAX); M(rIMPORT); M(rEXPORT); | ||||
|   M(rDEFINE_LIBRARY); | ||||
|   M(rCOND_EXPAND); | ||||
|   M(rCONS); M(rCAR); M(rCDR); M(rNILP); | ||||
|   M(rSYMBOLP); M(rPAIRP); | ||||
|   M(rADD); M(rSUB); M(rMUL); M(rDIV); | ||||
|   M(rEQ); M(rLT); M(rLE); M(rGT); M(rGE); M(rNOT); | ||||
|   M(rVALUES); M(rCALL_WITH_VALUES); | ||||
|   M(uDEFINE); M(uLAMBDA); M(uIF); M(uBEGIN); M(uQUOTE); M(uSETBANG); | ||||
|   M(uDEFINE_MACRO); M(uIMPORT); M(uEXPORT); | ||||
|   M(uDEFINE_LIBRARY); | ||||
|   M(uCOND_EXPAND); | ||||
|   M(uCONS); M(uCAR); M(uCDR); M(uNILP); | ||||
|   M(uSYMBOLP); M(uPAIRP); | ||||
|   M(uADD); M(uSUB); M(uMUL); M(uDIV); | ||||
|   M(uEQ); M(uLT); M(uLE); M(uGT); M(uGE); M(uNOT); | ||||
|   M(uVALUES); M(uCALL_WITH_VALUES); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
|  | @ -681,7 +692,12 @@ gc_finalize_object(pic_state *pic, struct pic_object *obj) | |||
|   case PIC_TT_ERROR: { | ||||
|     break; | ||||
|   } | ||||
|   case PIC_TT_ID: { | ||||
|     break; | ||||
|   } | ||||
|   case PIC_TT_ENV: { | ||||
|     struct pic_env *env = (struct pic_env *)obj; | ||||
|     xh_destroy(&env->map); | ||||
|     break; | ||||
|   } | ||||
|   case PIC_TT_LIB: { | ||||
|  |  | |||
|  | @ -98,7 +98,9 @@ typedef struct { | |||
| 
 | ||||
|   pic_sym *sDEFINE, *sLAMBDA, *sIF, *sBEGIN, *sQUOTE, *sSETBANG; | ||||
|   pic_sym *sQUASIQUOTE, *sUNQUOTE, *sUNQUOTE_SPLICING; | ||||
|   pic_sym *sDEFINE_SYNTAX, *sIMPORT, *sEXPORT; | ||||
|   pic_sym *sSYNTAX_QUOTE, *sSYNTAX_QUASIQUOTE, *sSYNTAX_UNQUOTE; | ||||
|   pic_sym *sSYNTAX_UNQUOTE_SPLICING; | ||||
|   pic_sym *sDEFINE_MACRO, *sIMPORT, *sEXPORT; | ||||
|   pic_sym *sDEFINE_LIBRARY; | ||||
|   pic_sym *sCOND_EXPAND, *sAND, *sOR, *sELSE, *sLIBRARY; | ||||
|   pic_sym *sONLY, *sRENAME, *sPREFIX, *sEXCEPT; | ||||
|  | @ -111,15 +113,15 @@ typedef struct { | |||
|   pic_sym *sCALL, *sTAILCALL, *sRETURN; | ||||
|   pic_sym *sCALL_WITH_VALUES, *sTAILCALL_WITH_VALUES; | ||||
| 
 | ||||
|   pic_sym *rDEFINE, *rLAMBDA, *rIF, *rBEGIN, *rQUOTE, *rSETBANG; | ||||
|   pic_sym *rDEFINE_SYNTAX, *rIMPORT, *rEXPORT; | ||||
|   pic_sym *rDEFINE_LIBRARY; | ||||
|   pic_sym *rCOND_EXPAND; | ||||
|   pic_sym *rCONS, *rCAR, *rCDR, *rNILP; | ||||
|   pic_sym *rSYMBOLP, *rPAIRP; | ||||
|   pic_sym *rADD, *rSUB, *rMUL, *rDIV; | ||||
|   pic_sym *rEQ, *rLT, *rLE, *rGT, *rGE, *rNOT; | ||||
|   pic_sym *rVALUES, *rCALL_WITH_VALUES; | ||||
|   pic_sym *uDEFINE, *uLAMBDA, *uIF, *uBEGIN, *uQUOTE, *uSETBANG; | ||||
|   pic_sym *uDEFINE_MACRO, *uIMPORT, *uEXPORT; | ||||
|   pic_sym *uDEFINE_LIBRARY; | ||||
|   pic_sym *uCOND_EXPAND; | ||||
|   pic_sym *uCONS, *uCAR, *uCDR, *uNILP; | ||||
|   pic_sym *uSYMBOLP, *uPAIRP; | ||||
|   pic_sym *uADD, *uSUB, *uMUL, *uDIV; | ||||
|   pic_sym *uEQ, *uLT, *uLE, *uGT, *uGE, *uNOT; | ||||
|   pic_sym *uVALUES, *uCALL_WITH_VALUES; | ||||
| 
 | ||||
|   struct pic_lib *PICRIN_BASE; | ||||
|   struct pic_lib *PICRIN_USER; | ||||
|  | @ -127,6 +129,7 @@ typedef struct { | |||
|   pic_value features; | ||||
| 
 | ||||
|   xhash syms;                   /* name to symbol */ | ||||
|   int ucnt; | ||||
|   struct pic_dict *globals; | ||||
|   struct pic_dict *macros; | ||||
|   pic_value libs; | ||||
|  | @ -193,8 +196,6 @@ bool pic_equal_p(pic_state *, pic_value, pic_value); | |||
| pic_sym *pic_intern(pic_state *, pic_str *); | ||||
| pic_sym *pic_intern_cstr(pic_state *, const char *); | ||||
| const char *pic_symbol_name(pic_state *, pic_sym *); | ||||
| pic_sym *pic_gensym(pic_state *, pic_sym *); | ||||
| bool pic_interned_p(pic_state *, pic_sym *); | ||||
| 
 | ||||
| pic_value pic_read(pic_state *, struct pic_port *); | ||||
| pic_value pic_read_cstr(pic_state *, const char *); | ||||
|  | @ -214,9 +215,9 @@ pic_value pic_apply3(pic_state *, struct pic_proc *, pic_value, pic_value, pic_v | |||
| pic_value pic_apply4(pic_state *, struct pic_proc *, pic_value, pic_value, pic_value, pic_value); | ||||
| pic_value pic_apply5(pic_state *, struct pic_proc *, pic_value, pic_value, pic_value, pic_value, pic_value); | ||||
| pic_value pic_apply_trampoline(pic_state *, struct pic_proc *, pic_value); | ||||
| pic_value pic_eval(pic_state *, pic_value, struct pic_lib *); | ||||
| struct pic_proc *pic_compile(pic_state *, pic_value, struct pic_lib *); | ||||
| pic_value pic_macroexpand(pic_state *, pic_value, struct pic_lib *); | ||||
| pic_value pic_eval(pic_state *, pic_value, struct pic_env *); | ||||
| pic_value pic_expand(pic_state *, pic_value, struct pic_env *); | ||||
| struct pic_proc *pic_compile(pic_state *, pic_value, struct pic_env *); | ||||
| 
 | ||||
| struct pic_lib *pic_make_library(pic_state *, pic_value); | ||||
| struct pic_lib *pic_find_library(pic_state *, pic_value); | ||||
|  |  | |||
|  | @ -9,24 +9,35 @@ | |||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| struct pic_id { | ||||
|   PIC_OBJECT_HEADER | ||||
|   pic_value var; | ||||
|   struct pic_env *env; | ||||
| }; | ||||
| 
 | ||||
| struct pic_env { | ||||
|   PIC_OBJECT_HEADER | ||||
|   struct pic_dict *map; | ||||
|   pic_value defer; | ||||
|   xhash map; | ||||
|   struct pic_env *up; | ||||
| }; | ||||
| 
 | ||||
| #define pic_id_p(v) (pic_type(v) == PIC_TT_ID) | ||||
| #define pic_id_ptr(v) ((struct pic_id *)pic_ptr(v)) | ||||
| 
 | ||||
| #define pic_env_p(v) (pic_type(v) == PIC_TT_ENV) | ||||
| #define pic_env_ptr(v) ((struct pic_env *)pic_ptr(v)) | ||||
| 
 | ||||
| bool pic_identifier_p(pic_state *pic, pic_value obj); | ||||
| bool pic_identifier_eq_p(pic_state *, struct pic_env *, pic_sym *, struct pic_env *, pic_sym *); | ||||
| 
 | ||||
| struct pic_id *pic_make_id(pic_state *, pic_value, struct pic_env *); | ||||
| struct pic_env *pic_make_env(pic_state *, struct pic_env *); | ||||
| 
 | ||||
| pic_sym *pic_add_rename(pic_state *, struct pic_env *, pic_sym *); | ||||
| pic_sym *pic_find_rename(pic_state *, struct pic_env *, pic_sym *); | ||||
| void pic_put_rename(pic_state *, struct pic_env *, pic_sym *, pic_sym *); | ||||
| pic_sym *pic_uniq(pic_state *, pic_value); | ||||
| 
 | ||||
| pic_sym *pic_add_variable(pic_state *, struct pic_env *, pic_value); | ||||
| void pic_put_variable(pic_state *, struct pic_env *, pic_value, pic_sym *); | ||||
| pic_sym *pic_find_variable(pic_state *, struct pic_env *, pic_value); | ||||
| 
 | ||||
| bool pic_var_p(pic_value); | ||||
| pic_sym *pic_var_name(pic_state *, pic_value); | ||||
| 
 | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
|  |  | |||
|  | @ -157,6 +157,7 @@ enum pic_tt { | |||
|   PIC_TT_PROC, | ||||
|   PIC_TT_PORT, | ||||
|   PIC_TT_ERROR, | ||||
|   PIC_TT_ID, | ||||
|   PIC_TT_CXT, | ||||
|   PIC_TT_ENV, | ||||
|   PIC_TT_LIB, | ||||
|  | @ -183,6 +184,7 @@ struct pic_blob; | |||
| struct pic_proc; | ||||
| struct pic_port; | ||||
| struct pic_error; | ||||
| struct pic_env; | ||||
| 
 | ||||
| /* set aliases to basic types */ | ||||
| typedef pic_value pic_list; | ||||
|  | @ -314,6 +316,8 @@ pic_type_repr(enum pic_tt tt) | |||
|     return "port"; | ||||
|   case PIC_TT_ERROR: | ||||
|     return "error"; | ||||
|   case PIC_TT_ID: | ||||
|     return "id"; | ||||
|   case PIC_TT_CXT: | ||||
|     return "cxt"; | ||||
|   case PIC_TT_PROC: | ||||
|  |  | |||
|  | @ -9,10 +9,10 @@ setup_default_env(pic_state *pic, struct pic_env *env) | |||
| { | ||||
|   void pic_define_syntactic_keyword(pic_state *, struct pic_env *, pic_sym *, pic_sym *); | ||||
| 
 | ||||
|   pic_define_syntactic_keyword(pic, env, pic->sDEFINE_LIBRARY, pic->rDEFINE_LIBRARY); | ||||
|   pic_define_syntactic_keyword(pic, env, pic->sIMPORT, pic->rIMPORT); | ||||
|   pic_define_syntactic_keyword(pic, env, pic->sEXPORT, pic->rEXPORT); | ||||
|   pic_define_syntactic_keyword(pic, env, pic->sCOND_EXPAND, pic->rCOND_EXPAND); | ||||
|   pic_define_syntactic_keyword(pic, env, pic->sDEFINE_LIBRARY, pic->uDEFINE_LIBRARY); | ||||
|   pic_define_syntactic_keyword(pic, env, pic->sIMPORT, pic->uIMPORT); | ||||
|   pic_define_syntactic_keyword(pic, env, pic->sEXPORT, pic->uEXPORT); | ||||
|   pic_define_syntactic_keyword(pic, env, pic->sCOND_EXPAND, pic->uCOND_EXPAND); | ||||
| } | ||||
| 
 | ||||
| struct pic_lib * | ||||
|  | @ -110,14 +110,14 @@ import_table(pic_state *pic, pic_value spec, struct pic_dict *imports) | |||
|     pic_errorf(pic, "library not found: ~a", spec); | ||||
|   } | ||||
|   pic_dict_for_each (nick, lib->exports, iter) { | ||||
|     pic_sym *realname, *rename; | ||||
|     pic_sym *realname, *uid; | ||||
| 
 | ||||
|     realname = pic_sym_ptr(pic_dict_ref(pic, lib->exports, nick)); | ||||
| 
 | ||||
|     if ((rename = pic_find_rename(pic, lib->env, realname)) == NULL) { | ||||
|     if ((uid = pic_find_variable(pic, lib->env, pic_obj_value(realname))) == NULL) { | ||||
|       pic_errorf(pic, "attempted to export undefined variable '~s'", pic_obj_value(realname)); | ||||
|     } | ||||
|     pic_dict_set(pic, imports, nick, pic_obj_value(rename)); | ||||
|     pic_dict_set(pic, imports, nick, pic_obj_value(uid)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -133,7 +133,7 @@ import(pic_state *pic, pic_value spec) | |||
|   import_table(pic, spec, imports); | ||||
| 
 | ||||
|   pic_dict_for_each (sym, imports, it) { | ||||
|     pic_put_rename(pic, pic->lib->env, sym, pic_sym_ptr(pic_dict_ref(pic, imports, sym))); | ||||
|     pic_put_variable(pic, pic->lib->env, pic_obj_value(sym), pic_sym_ptr(pic_dict_ref(pic, imports, sym))); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -245,7 +245,7 @@ pic_lib_condexpand(pic_state *pic) | |||
| 
 | ||||
|   for (i = 0; i < argc; i++) { | ||||
|     if (condexpand(pic, pic_car(pic, clauses[i]))) { | ||||
|       return pic_cons(pic, pic_obj_value(pic->rBEGIN), pic_cdr(pic, clauses[i])); | ||||
|       return pic_cons(pic, pic_obj_value(pic->sBEGIN), pic_cdr(pic, clauses[i])); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -299,7 +299,7 @@ pic_lib_define_library(pic_state *pic) | |||
|     pic->lib = lib; | ||||
| 
 | ||||
|     for (i = 0; i < argc; ++i) { | ||||
|       pic_void(pic_eval(pic, argv[i], pic->lib)); | ||||
|       pic_void(pic_eval(pic, argv[i], pic->lib->env)); | ||||
|     } | ||||
| 
 | ||||
|     pic->lib = prev; | ||||
|  | @ -317,8 +317,8 @@ pic_init_lib(pic_state *pic) | |||
| { | ||||
|   void pic_defmacro(pic_state *, pic_sym *, pic_sym *, pic_func_t); | ||||
| 
 | ||||
|   pic_defmacro(pic, pic->sCOND_EXPAND, pic->rCOND_EXPAND, pic_lib_condexpand); | ||||
|   pic_defmacro(pic, pic->sIMPORT, pic->rIMPORT, pic_lib_import); | ||||
|   pic_defmacro(pic, pic->sEXPORT, pic->rEXPORT, pic_lib_export); | ||||
|   pic_defmacro(pic, pic->sDEFINE_LIBRARY, pic->rDEFINE_LIBRARY, pic_lib_define_library); | ||||
|   pic_defmacro(pic, pic->sCOND_EXPAND, pic->uCOND_EXPAND, pic_lib_condexpand); | ||||
|   pic_defmacro(pic, pic->sIMPORT, pic->uIMPORT, pic_lib_import); | ||||
|   pic_defmacro(pic, pic->sEXPORT, pic->uEXPORT, pic_lib_export); | ||||
|   pic_defmacro(pic, pic->sDEFINE_LIBRARY, pic->uDEFINE_LIBRARY, pic_lib_define_library); | ||||
| } | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ pic_load_port(pic_state *pic, struct pic_port *port) | |||
|     size_t ai = pic_gc_arena_preserve(pic); | ||||
| 
 | ||||
|     while (! pic_eof_p(form = pic_read(pic, port))) { | ||||
|       pic_eval(pic, form, pic->lib); | ||||
|       pic_eval(pic, form, pic->lib->env); | ||||
| 
 | ||||
|       pic_gc_arena_restore(pic, ai); | ||||
|     } | ||||
|  |  | |||
|  | @ -4,434 +4,92 @@ | |||
| 
 | ||||
| #include "picrin.h" | ||||
| 
 | ||||
| pic_sym * | ||||
| pic_add_rename(pic_state *pic, struct pic_env *env, pic_sym *sym) | ||||
| bool | ||||
| pic_var_p(pic_value obj) | ||||
| { | ||||
|   pic_sym *rename = pic_gensym(pic, sym); | ||||
| 
 | ||||
|   pic_put_rename(pic, env, sym, rename); | ||||
| 
 | ||||
|   return rename; | ||||
|   return pic_sym_p(obj) || pic_id_p(obj); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| pic_put_rename(pic_state *pic, struct pic_env *env, pic_sym *sym, pic_sym *rename) | ||||
| struct pic_id * | ||||
| pic_make_id(pic_state *pic, pic_value var, struct pic_env *env) | ||||
| { | ||||
|   pic_dict_set(pic, env->map, sym, pic_obj_value(rename)); | ||||
| } | ||||
|   struct pic_id *id; | ||||
| 
 | ||||
| pic_sym * | ||||
| pic_find_rename(pic_state *pic, struct pic_env *env, pic_sym *sym) | ||||
| { | ||||
|   if (! pic_dict_has(pic, env->map, sym)) { | ||||
|     return NULL; | ||||
|   } | ||||
|   return pic_sym_ptr(pic_dict_ref(pic, env->map, sym)); | ||||
| } | ||||
|   assert(pic_var_p(var)); | ||||
| 
 | ||||
| static void | ||||
| define_macro(pic_state *pic, pic_sym *rename, struct pic_proc *mac) | ||||
| { | ||||
|   pic_dict_set(pic, pic->macros, rename, pic_obj_value(mac)); | ||||
| } | ||||
| 
 | ||||
| static struct pic_proc * | ||||
| find_macro(pic_state *pic, pic_sym *rename) | ||||
| { | ||||
|   if (! pic_dict_has(pic, pic->macros, rename)) { | ||||
|     return NULL; | ||||
|   } | ||||
|   return pic_proc_ptr(pic_dict_ref(pic, pic->macros, rename)); | ||||
| } | ||||
| 
 | ||||
| static pic_sym * | ||||
| make_identifier(pic_state *pic, pic_sym *sym, struct pic_env *env) | ||||
| { | ||||
|   pic_sym *rename; | ||||
| 
 | ||||
|   while (true) { | ||||
|     if ((rename = pic_find_rename(pic, env, sym)) != NULL) { | ||||
|       return rename; | ||||
|     } | ||||
|     if (! env->up) | ||||
|       break; | ||||
|     env = env->up; | ||||
|   } | ||||
|   if (! pic_interned_p(pic, sym)) { | ||||
|     return sym; | ||||
|   } | ||||
|   else { | ||||
|     return pic_gensym(pic, sym); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static pic_value macroexpand(pic_state *, pic_value, struct pic_env *); | ||||
| static pic_value macroexpand_lambda(pic_state *, pic_value, struct pic_env *); | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand_symbol(pic_state *pic, pic_sym *sym, struct pic_env *env) | ||||
| { | ||||
|   return pic_obj_value(make_identifier(pic, sym, env)); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand_quote(pic_state *pic, pic_value expr) | ||||
| { | ||||
|   return pic_cons(pic, pic_obj_value(pic->rQUOTE), pic_cdr(pic, expr)); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand_list(pic_state *pic, pic_value obj, struct pic_env *env) | ||||
| { | ||||
|   size_t ai = pic_gc_arena_preserve(pic); | ||||
|   pic_value x, head, tail; | ||||
| 
 | ||||
|   if (pic_pair_p(obj)) { | ||||
|     head = macroexpand(pic, pic_car(pic, obj), env); | ||||
|     tail = macroexpand_list(pic, pic_cdr(pic, obj), env); | ||||
|     x = pic_cons(pic, head, tail); | ||||
|   } else { | ||||
|     x = macroexpand(pic, obj, env); | ||||
|   } | ||||
| 
 | ||||
|   pic_gc_arena_restore(pic, ai); | ||||
|   pic_gc_protect(pic, x); | ||||
|   return x; | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand_defer(pic_state *pic, pic_value expr, struct pic_env *env) | ||||
| { | ||||
|   pic_value skel = pic_list1(pic, pic_invalid_value()); /* (#<invalid>) */ | ||||
| 
 | ||||
|   pic_push(pic, pic_cons(pic, expr, skel), env->defer); | ||||
| 
 | ||||
|   return skel; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| macroexpand_deferred(pic_state *pic, struct pic_env *env) | ||||
| { | ||||
|   pic_value defer, val, src, dst, it; | ||||
| 
 | ||||
|   pic_for_each (defer, pic_reverse(pic, env->defer), it) { | ||||
|     src = pic_car(pic, defer); | ||||
|     dst = pic_cdr(pic, defer); | ||||
| 
 | ||||
|     val = macroexpand_lambda(pic, src, env); | ||||
| 
 | ||||
|     /* copy */ | ||||
|     pic_pair_ptr(dst)->car = pic_car(pic, val); | ||||
|     pic_pair_ptr(dst)->cdr = pic_cdr(pic, val); | ||||
|   } | ||||
| 
 | ||||
|   env->defer = pic_nil_value(); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand_lambda(pic_state *pic, pic_value expr, struct pic_env *env) | ||||
| { | ||||
|   pic_value formal, body; | ||||
|   struct pic_env *in; | ||||
|   pic_value a; | ||||
| 
 | ||||
|   if (pic_length(pic, expr) < 2) { | ||||
|     pic_errorf(pic, "syntax error"); | ||||
|   } | ||||
| 
 | ||||
|   in = pic_make_env(pic, env); | ||||
| 
 | ||||
|   for (a = pic_cadr(pic, expr); pic_pair_p(a); a = pic_cdr(pic, a)) { | ||||
|     pic_value v = pic_car(pic, a); | ||||
| 
 | ||||
|     if (! pic_sym_p(v)) { | ||||
|       pic_errorf(pic, "syntax error"); | ||||
|     } | ||||
|     pic_add_rename(pic, in, pic_sym_ptr(v)); | ||||
|   } | ||||
|   if (pic_sym_p(a)) { | ||||
|     pic_add_rename(pic, in, pic_sym_ptr(a)); | ||||
|   } | ||||
|   else if (! pic_nil_p(a)) { | ||||
|     pic_errorf(pic, "syntax error"); | ||||
|   } | ||||
| 
 | ||||
|   formal = macroexpand_list(pic, pic_cadr(pic, expr), in); | ||||
|   body = macroexpand_list(pic, pic_cddr(pic, expr), in); | ||||
| 
 | ||||
|   macroexpand_deferred(pic, in); | ||||
| 
 | ||||
|   return pic_cons(pic, pic_obj_value(pic->rLAMBDA), pic_cons(pic, formal, body)); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand_define(pic_state *pic, pic_value expr, struct pic_env *env) | ||||
| { | ||||
|   pic_sym *sym, *rename; | ||||
|   pic_value var, val; | ||||
| 
 | ||||
|   while (pic_length(pic, expr) >= 2 && pic_pair_p(pic_cadr(pic, expr))) { | ||||
|     var = pic_car(pic, pic_cadr(pic, expr)); | ||||
|     val = pic_cdr(pic, pic_cadr(pic, expr)); | ||||
| 
 | ||||
|     expr = pic_list3(pic, pic_obj_value(pic->rDEFINE), var, pic_cons(pic, pic_obj_value(pic->rLAMBDA), pic_cons(pic, val, pic_cddr(pic, expr)))); | ||||
|   } | ||||
| 
 | ||||
|   if (pic_length(pic, expr) != 3) { | ||||
|     pic_errorf(pic, "syntax error"); | ||||
|   } | ||||
| 
 | ||||
|   var = pic_cadr(pic, expr); | ||||
|   if (! pic_sym_p(var)) { | ||||
|     pic_errorf(pic, "binding to non-symbol object"); | ||||
|   } | ||||
|   sym = pic_sym_ptr(var); | ||||
|   if ((rename = pic_find_rename(pic, env, sym)) == NULL) { | ||||
|     rename = pic_add_rename(pic, env, sym); | ||||
|   } | ||||
|   val = macroexpand(pic, pic_list_ref(pic, expr, 2), env); | ||||
| 
 | ||||
|   return pic_list3(pic, pic_obj_value(pic->rDEFINE), pic_obj_value(rename), val); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand_defsyntax(pic_state *pic, pic_value expr, struct pic_env *env) | ||||
| { | ||||
|   pic_value var, val; | ||||
|   pic_sym *sym, *rename; | ||||
| 
 | ||||
|   if (pic_length(pic, expr) != 3) { | ||||
|     pic_errorf(pic, "syntax error"); | ||||
|   } | ||||
| 
 | ||||
|   var = pic_cadr(pic, expr); | ||||
|   if (! pic_sym_p(var)) { | ||||
|     pic_errorf(pic, "binding to non-symbol object"); | ||||
|   } | ||||
|   sym = pic_sym_ptr(var); | ||||
|   if ((rename = pic_find_rename(pic, env, sym)) == NULL) { | ||||
|     rename = pic_add_rename(pic, env, sym); | ||||
|   } else { | ||||
|     pic_warnf(pic, "redefining syntax variable: ~s", pic_obj_value(sym)); | ||||
|   } | ||||
| 
 | ||||
|   val = pic_cadr(pic, pic_cdr(pic, expr)); | ||||
| 
 | ||||
|   pic_try { | ||||
|     val = pic_eval(pic, val, pic->lib); | ||||
|   } pic_catch { | ||||
|     pic_errorf(pic, "macroexpand error while definition: %s", pic_errmsg(pic)); | ||||
|   } | ||||
| 
 | ||||
|   if (! pic_proc_p(val)) { | ||||
|     pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", var); | ||||
|   } | ||||
| 
 | ||||
|   val = pic_apply1(pic, pic_proc_ptr(val), pic_obj_value(env)); | ||||
| 
 | ||||
|   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)); | ||||
| 
 | ||||
|   return pic_undef_value(); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand_macro(pic_state *pic, struct pic_proc *mac, pic_value expr, struct pic_env *env) | ||||
| { | ||||
|   pic_value v, args; | ||||
| 
 | ||||
| #if DEBUG | ||||
|   puts("before expand-1:"); | ||||
|   pic_debug(pic, expr); | ||||
|   puts(""); | ||||
| #endif | ||||
| 
 | ||||
|   args = pic_list2(pic, expr, pic_obj_value(env)); | ||||
| 
 | ||||
|   pic_try { | ||||
|     v = pic_apply(pic, mac, args); | ||||
|   } pic_catch { | ||||
|     pic_errorf(pic, "macroexpand error while application: %s", pic_errmsg(pic)); | ||||
|   } | ||||
| 
 | ||||
| #if DEBUG | ||||
|   puts("after expand-1:"); | ||||
|   pic_debug(pic, v); | ||||
|   puts(""); | ||||
| #endif | ||||
| 
 | ||||
|   return v; | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand_node(pic_state *pic, pic_value expr, struct pic_env *env) | ||||
| { | ||||
|   switch (pic_type(expr)) { | ||||
|   case PIC_TT_SYMBOL: { | ||||
|     return macroexpand_symbol(pic, pic_sym_ptr(expr), env); | ||||
|   } | ||||
|   case PIC_TT_PAIR: { | ||||
|     pic_value car; | ||||
|     struct pic_proc *mac; | ||||
| 
 | ||||
|     if (! pic_list_p(expr)) { | ||||
|       pic_errorf(pic, "cannot macroexpand improper list: ~s", expr); | ||||
|     } | ||||
| 
 | ||||
|     car = macroexpand(pic, pic_car(pic, expr), env); | ||||
|     if (pic_sym_p(car)) { | ||||
|       pic_sym *tag = pic_sym_ptr(car); | ||||
| 
 | ||||
|       if (tag == pic->rDEFINE_SYNTAX) { | ||||
|         return macroexpand_defsyntax(pic, expr, env); | ||||
|       } | ||||
|       else if (tag == pic->rLAMBDA) { | ||||
|         return macroexpand_defer(pic, expr, env); | ||||
|       } | ||||
|       else if (tag == pic->rDEFINE) { | ||||
|         return macroexpand_define(pic, expr, env); | ||||
|       } | ||||
|       else if (tag == pic->rQUOTE) { | ||||
|         return macroexpand_quote(pic, expr); | ||||
|       } | ||||
| 
 | ||||
|       if ((mac = find_macro(pic, tag)) != NULL) { | ||||
|         return macroexpand_node(pic, macroexpand_macro(pic, mac, expr, env), env); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     return pic_cons(pic, car, macroexpand_list(pic, pic_cdr(pic, expr), env)); | ||||
|   } | ||||
|   default: | ||||
|     return expr; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| macroexpand(pic_state *pic, pic_value expr, struct pic_env *env) | ||||
| { | ||||
|   size_t ai = pic_gc_arena_preserve(pic); | ||||
|   pic_value v; | ||||
| 
 | ||||
| #if DEBUG | ||||
|   printf("[macroexpand] expanding... "); | ||||
|   pic_debug(pic, expr); | ||||
|   puts(""); | ||||
| #endif | ||||
| 
 | ||||
|   v = macroexpand_node(pic, expr, env); | ||||
| 
 | ||||
|   pic_gc_arena_restore(pic, ai); | ||||
|   pic_gc_protect(pic, v); | ||||
|   return v; | ||||
| } | ||||
| 
 | ||||
| pic_value | ||||
| pic_macroexpand(pic_state *pic, pic_value expr, struct pic_lib *lib) | ||||
| { | ||||
|   struct pic_lib *prev; | ||||
|   pic_value v; | ||||
| 
 | ||||
| #if DEBUG | ||||
|   puts("before expand:"); | ||||
|   pic_debug(pic, expr); | ||||
|   puts(""); | ||||
| #endif | ||||
| 
 | ||||
|   /* change library for macro-expansion time processing */ | ||||
|   prev = pic->lib; | ||||
|   pic->lib = lib; | ||||
| 
 | ||||
|   lib->env->defer = pic_nil_value(); /* the last expansion could fail and leave defer field old */ | ||||
| 
 | ||||
|   v = macroexpand(pic, expr, lib->env); | ||||
| 
 | ||||
|   macroexpand_deferred(pic, lib->env); | ||||
| 
 | ||||
|   pic->lib = prev; | ||||
| 
 | ||||
| #if DEBUG | ||||
|   puts("after expand:"); | ||||
|   pic_debug(pic, v); | ||||
|   puts(""); | ||||
| #endif | ||||
| 
 | ||||
|   return v; | ||||
|   id = (struct pic_id *)pic_obj_alloc(pic, sizeof(struct pic_id), PIC_TT_ID); | ||||
|   id->var = var; | ||||
|   id->env = env; | ||||
|   return id; | ||||
| } | ||||
| 
 | ||||
| struct pic_env * | ||||
| pic_make_env(pic_state *pic, struct pic_env *up) | ||||
| { | ||||
|   struct pic_env *env; | ||||
|   struct pic_dict *map; | ||||
| 
 | ||||
|   map = pic_make_dict(pic); | ||||
| 
 | ||||
|   env = (struct pic_env *)pic_obj_alloc(pic, sizeof(struct pic_env), PIC_TT_ENV); | ||||
|   env->up = up; | ||||
|   env->defer = pic_nil_value(); | ||||
|   env->map = map; | ||||
| 
 | ||||
|   xh_init_ptr(&env->map, sizeof(pic_sym *)); | ||||
|   return env; | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| defmacro_call(pic_state *pic) | ||||
| pic_sym * | ||||
| pic_var_name(pic_state PIC_UNUSED(*pic), pic_value var) | ||||
| { | ||||
|   struct pic_proc *self = pic_get_proc(pic); | ||||
|   pic_value args, tmp, proc; | ||||
|   assert(pic_var_p(var)); | ||||
| 
 | ||||
|   pic_get_args(pic, "oo", &args, &tmp); | ||||
|   while (pic_id_p(var)) { | ||||
|     var = pic_id_ptr(var)->var; | ||||
|   } | ||||
|   return pic_sym_ptr(var); | ||||
| } | ||||
| 
 | ||||
|   proc = pic_attr_ref(pic, pic_obj_value(self), "@@transformer"); | ||||
| pic_sym * | ||||
| pic_uniq(pic_state *pic, pic_value var) | ||||
| { | ||||
|   pic_str *str; | ||||
| 
 | ||||
|   return pic_apply_trampoline(pic, pic_proc_ptr(proc), pic_cdr(pic, args)); | ||||
|   assert(pic_var_p(var)); | ||||
| 
 | ||||
|   str = pic_format(pic, "%s.%d", pic_symbol_name(pic, pic_var_name(pic, var)), pic->ucnt++); | ||||
| 
 | ||||
|   return pic_intern(pic, str); | ||||
| } | ||||
| 
 | ||||
| pic_sym * | ||||
| pic_add_variable(pic_state *pic, struct pic_env *env, pic_value var) | ||||
| { | ||||
|   pic_sym *uid; | ||||
| 
 | ||||
|   assert(pic_var_p(var)); | ||||
| 
 | ||||
|   uid = pic_uniq(pic, var); | ||||
| 
 | ||||
|   pic_put_variable(pic, env, var, uid); | ||||
| 
 | ||||
|   return uid; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| pic_defmacro(pic_state *pic, pic_sym *name, pic_sym *id, pic_func_t func) | ||||
| pic_put_variable(pic_state PIC_UNUSED(*pic), struct pic_env *env, pic_value var, pic_sym *uid) | ||||
| { | ||||
|   struct pic_proc *proc, *trans; | ||||
|   assert(pic_var_p(var)); | ||||
| 
 | ||||
|   trans = pic_make_proc(pic, func, pic_symbol_name(pic, name)); | ||||
| 
 | ||||
|   pic_put_rename(pic, pic->lib->env, name, id); | ||||
| 
 | ||||
|   proc = pic_make_proc(pic, defmacro_call, "defmacro_call"); | ||||
|   pic_attr_set(pic, pic_obj_value(proc), "@@transformer", pic_obj_value(trans)); | ||||
| 
 | ||||
|   /* symbol registration */ | ||||
|   define_macro(pic, id, proc); | ||||
| 
 | ||||
|   /* auto export! */ | ||||
|   pic_export(pic, name); | ||||
|   xh_put_ptr(&env->map, pic_ptr(var), &uid); | ||||
| } | ||||
| 
 | ||||
| bool | ||||
| pic_identifier_p(pic_state *pic, pic_value obj) | ||||
| pic_sym * | ||||
| pic_find_variable(pic_state PIC_UNUSED(*pic), struct pic_env *env, pic_value var) | ||||
| { | ||||
|   return pic_sym_p(obj) && ! pic_interned_p(pic, pic_sym_ptr(obj)); | ||||
| } | ||||
|   xh_entry *e; | ||||
| 
 | ||||
| bool | ||||
| pic_identifier_eq_p(pic_state *pic, struct pic_env *env1, pic_sym *sym1, struct pic_env *env2, pic_sym *sym2) | ||||
| { | ||||
|   pic_sym *a, *b; | ||||
|   assert(pic_var_p(var)); | ||||
| 
 | ||||
|   a = make_identifier(pic, sym1, env1); | ||||
|   if (a != make_identifier(pic, sym1, env1)) { | ||||
|     a = sym1; | ||||
|   if ((e = xh_get_ptr(&env->map, pic_ptr(var))) == NULL) { | ||||
|     return NULL; | ||||
|   } | ||||
| 
 | ||||
|   b = make_identifier(pic, sym2, env2); | ||||
|   if (b != make_identifier(pic, sym2, env2)) { | ||||
|     b = sym2; | ||||
|   } | ||||
| 
 | ||||
|   return pic_eq_p(pic_obj_value(a), pic_obj_value(b)); | ||||
|   return xh_val(e, pic_sym *); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
|  | @ -441,40 +99,83 @@ pic_macro_identifier_p(pic_state *pic) | |||
| 
 | ||||
|   pic_get_args(pic, "o", &obj); | ||||
| 
 | ||||
|   return pic_bool_value(pic_identifier_p(pic, obj)); | ||||
|   return pic_bool_value(pic_id_p(obj)); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| pic_macro_make_identifier(pic_state *pic) | ||||
| { | ||||
|   pic_value obj; | ||||
|   pic_sym *sym; | ||||
|   pic_value var, env; | ||||
| 
 | ||||
|   pic_get_args(pic, "mo", &sym, &obj); | ||||
|   pic_get_args(pic, "oo", &var, &env); | ||||
| 
 | ||||
|   pic_assert_type(pic, obj, env); | ||||
|   pic_assert_type(pic, var, var); | ||||
|   pic_assert_type(pic, env, env); | ||||
| 
 | ||||
|   return pic_obj_value(make_identifier(pic, sym, pic_env_ptr(obj))); | ||||
|   return pic_obj_value(pic_make_id(pic, var, pic_env_ptr(env))); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| pic_macro_identifier_eq_p(pic_state *pic) | ||||
| pic_macro_identifier_variable(pic_state *pic) | ||||
| { | ||||
|   pic_sym *sym1, *sym2; | ||||
|   pic_value env1, env2; | ||||
|   pic_value id; | ||||
| 
 | ||||
|   pic_get_args(pic, "omom", &env1, &sym1, &env2, &sym2); | ||||
|   pic_get_args(pic, "o", &id); | ||||
| 
 | ||||
|   pic_assert_type(pic, env1, env); | ||||
|   pic_assert_type(pic, env2, env); | ||||
|   pic_assert_type(pic, id, id); | ||||
| 
 | ||||
|   return pic_bool_value(pic_identifier_eq_p(pic, pic_env_ptr(env1), sym1, pic_env_ptr(env2), sym2)); | ||||
|   return pic_id_ptr(id)->var; | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| pic_macro_identifier_environment(pic_state *pic) | ||||
| { | ||||
|   pic_value id; | ||||
| 
 | ||||
|   pic_get_args(pic, "o", &id); | ||||
| 
 | ||||
|   pic_assert_type(pic, id, id); | ||||
| 
 | ||||
|   return pic_obj_value(pic_id_ptr(id)->env); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| pic_macro_variable_p(pic_state *pic) | ||||
| { | ||||
|   pic_value obj; | ||||
| 
 | ||||
|   pic_get_args(pic, "o", &obj); | ||||
| 
 | ||||
|   return pic_bool_value(pic_var_p(obj)); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| pic_macro_variable_eq_p(pic_state *pic) | ||||
| { | ||||
|   size_t argc, i; | ||||
|   pic_value *argv; | ||||
| 
 | ||||
|   pic_get_args(pic, "*", &argc, &argv); | ||||
| 
 | ||||
|   for (i = 0; i < argc; ++i) { | ||||
|     if (! pic_var_p(argv[i])) { | ||||
|       return pic_false_value(); | ||||
|     } | ||||
|     if (! pic_equal_p(pic, argv[i], argv[0])) { | ||||
|       return pic_false_value(); | ||||
|     } | ||||
|   } | ||||
|   return pic_true_value(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| pic_init_macro(pic_state *pic) | ||||
| { | ||||
|   pic_defun(pic, "identifier?", pic_macro_identifier_p); | ||||
|   pic_defun(pic, "identifier=?", pic_macro_identifier_eq_p); | ||||
|   pic_defun(pic, "make-identifier", pic_macro_make_identifier); | ||||
|   pic_defun(pic, "identifier?", pic_macro_identifier_p); | ||||
|   pic_defun(pic, "identifier-variable", pic_macro_identifier_variable); | ||||
|   pic_defun(pic, "identifier-environment", pic_macro_identifier_environment); | ||||
| 
 | ||||
|   pic_defun(pic, "variable?", pic_macro_variable_p); | ||||
|   pic_defun(pic, "variable=?", pic_macro_variable_eq_p); | ||||
| } | ||||
|  |  | |||
|  | @ -816,17 +816,17 @@ pic_init_number(pic_state *pic) | |||
|   pic_defun(pic, "inexact?", pic_number_inexact_p); | ||||
|   pic_gc_arena_restore(pic, ai); | ||||
| 
 | ||||
|   pic_defun_vm(pic, "=", pic->rEQ, pic_number_eq); | ||||
|   pic_defun_vm(pic, "<", pic->rLT, pic_number_lt); | ||||
|   pic_defun_vm(pic, ">", pic->rGT, pic_number_gt); | ||||
|   pic_defun_vm(pic, "<=", pic->rLE, pic_number_le); | ||||
|   pic_defun_vm(pic, ">=", pic->rGE, pic_number_ge); | ||||
|   pic_defun_vm(pic, "=", pic->uEQ, pic_number_eq); | ||||
|   pic_defun_vm(pic, "<", pic->uLT, pic_number_lt); | ||||
|   pic_defun_vm(pic, ">", pic->uGT, pic_number_gt); | ||||
|   pic_defun_vm(pic, "<=", pic->uLE, pic_number_le); | ||||
|   pic_defun_vm(pic, ">=", pic->uGE, pic_number_ge); | ||||
|   pic_gc_arena_restore(pic, ai); | ||||
| 
 | ||||
|   pic_defun_vm(pic, "+", pic->rADD, pic_number_add); | ||||
|   pic_defun_vm(pic, "-", pic->rSUB, pic_number_sub); | ||||
|   pic_defun_vm(pic, "*", pic->rMUL, pic_number_mul); | ||||
|   pic_defun_vm(pic, "/", pic->rDIV, pic_number_div); | ||||
|   pic_defun_vm(pic, "+", pic->uADD, pic_number_add); | ||||
|   pic_defun_vm(pic, "-", pic->uSUB, pic_number_sub); | ||||
|   pic_defun_vm(pic, "*", pic->uMUL, pic_number_mul); | ||||
|   pic_defun_vm(pic, "/", pic->uDIV, pic_number_div); | ||||
|   pic_gc_arena_restore(pic, ai); | ||||
| 
 | ||||
|   pic_defun(pic, "abs", pic_number_abs); | ||||
|  |  | |||
|  | @ -762,11 +762,11 @@ pic_init_pair(pic_state *pic) | |||
| { | ||||
|   void pic_defun_vm(pic_state *, const char *, pic_sym *, pic_func_t); | ||||
| 
 | ||||
|   pic_defun_vm(pic, "pair?", pic->rPAIRP, pic_pair_pair_p); | ||||
|   pic_defun_vm(pic, "cons", pic->rCONS, pic_pair_cons); | ||||
|   pic_defun_vm(pic, "car", pic->rCAR, pic_pair_car); | ||||
|   pic_defun_vm(pic, "cdr", pic->rCDR, pic_pair_cdr); | ||||
|   pic_defun_vm(pic, "null?", pic->rNILP, pic_pair_null_p); | ||||
|   pic_defun_vm(pic, "pair?", pic->uPAIRP, pic_pair_pair_p); | ||||
|   pic_defun_vm(pic, "cons", pic->uCONS, pic_pair_cons); | ||||
|   pic_defun_vm(pic, "car", pic->uCAR, pic_pair_car); | ||||
|   pic_defun_vm(pic, "cdr", pic->uCDR, pic_pair_cdr); | ||||
|   pic_defun_vm(pic, "null?", pic->uNILP, pic_pair_null_p); | ||||
| 
 | ||||
|   pic_defun(pic, "set-car!", pic_pair_set_car); | ||||
|   pic_defun(pic, "set-cdr!", pic_pair_set_cdr); | ||||
|  |  | |||
|  | @ -153,7 +153,7 @@ read_eval(pic_state *pic, struct pic_port *port, int PIC_UNUSED(c)) | |||
| 
 | ||||
|   form = read(pic, port, next(port)); | ||||
| 
 | ||||
|   return pic_eval(pic, form, pic->lib); | ||||
|   return pic_eval(pic, form, pic->lib->env); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
|  | @ -180,6 +180,30 @@ read_unquote(pic_state *pic, struct pic_port *port, int PIC_UNUSED(c)) | |||
|   return pic_list2(pic, pic_obj_value(tag), read(pic, port, next(port))); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| read_syntax_quote(pic_state *pic, struct pic_port *port, int PIC_UNUSED(c)) | ||||
| { | ||||
|   return pic_list2(pic, pic_obj_value(pic->sSYNTAX_QUOTE), read(pic, port, next(port))); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| read_syntax_quasiquote(pic_state *pic, struct pic_port *port, int PIC_UNUSED(c)) | ||||
| { | ||||
|   return pic_list2(pic, pic_obj_value(pic->sSYNTAX_QUASIQUOTE), read(pic, port, next(port))); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| read_syntax_unquote(pic_state *pic, struct pic_port *port, int PIC_UNUSED(c)) | ||||
| { | ||||
|   pic_sym *tag = pic->sSYNTAX_UNQUOTE; | ||||
| 
 | ||||
|   if (peek(port) == '@') { | ||||
|     tag = pic->sSYNTAX_UNQUOTE_SPLICING; | ||||
|     next(port); | ||||
|   } | ||||
|   return pic_list2(pic, pic_obj_value(tag), read(pic, port, next(port))); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| read_symbol(pic_state *pic, struct pic_port *port, int c) | ||||
| { | ||||
|  | @ -799,6 +823,9 @@ reader_table_init(struct pic_reader *reader) | |||
|   reader->dispatch[';'] = read_datum_comment; | ||||
|   reader->dispatch['t'] = read_true; | ||||
|   reader->dispatch['f'] = read_false; | ||||
|   reader->dispatch['\''] = read_syntax_quote; | ||||
|   reader->dispatch['`'] = read_syntax_quasiquote; | ||||
|   reader->dispatch[','] = read_syntax_unquote; | ||||
|   reader->dispatch['\\'] = read_char; | ||||
|   reader->dispatch['('] = read_vector; | ||||
|   reader->dispatch['u'] = read_undef_or_blob; | ||||
|  |  | |||
|  | @ -103,13 +103,13 @@ pic_init_core(pic_state *pic) | |||
|   pic_deflibrary (pic, "(picrin base)") { | ||||
|     size_t ai = pic_gc_arena_preserve(pic); | ||||
| 
 | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sDEFINE, pic->rDEFINE); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sSETBANG, pic->rSETBANG); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sQUOTE, pic->rQUOTE); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sLAMBDA, pic->rLAMBDA); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sIF, pic->rIF); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sBEGIN, pic->rBEGIN); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sDEFINE_SYNTAX, pic->rDEFINE_SYNTAX); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sDEFINE, pic->uDEFINE); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sSETBANG, pic->uSETBANG); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sQUOTE, pic->uQUOTE); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sLAMBDA, pic->uLAMBDA); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sIF, pic->uIF); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sBEGIN, pic->uBEGIN); | ||||
|     pic_define_syntactic_keyword(pic, pic->lib->env, pic->sDEFINE_MACRO, pic->uDEFINE_MACRO); | ||||
| 
 | ||||
|     pic_init_undef(pic); DONE; | ||||
|     pic_init_bool(pic); DONE; | ||||
|  | @ -222,6 +222,9 @@ pic_open(int argc, char *argv[], char **envp, pic_allocf allocf) | |||
|   /* symbol table */ | ||||
|   xh_init_str(&pic->syms, sizeof(pic_sym *)); | ||||
| 
 | ||||
|   /* unique symbol count */ | ||||
|   pic->ucnt = 0; | ||||
| 
 | ||||
|   /* global variables */ | ||||
|   pic->globals = NULL; | ||||
| 
 | ||||
|  | @ -254,7 +257,7 @@ pic_open(int argc, char *argv[], char **envp, pic_allocf allocf) | |||
| 
 | ||||
|   ai = pic_gc_arena_preserve(pic); | ||||
| 
 | ||||
| #define S(slot,name) pic->slot = pic_intern_cstr(pic, name); | ||||
| #define S(slot,name) pic->slot = pic_intern_cstr(pic, name) | ||||
| 
 | ||||
|   S(sDEFINE, "define"); | ||||
|   S(sLAMBDA, "lambda"); | ||||
|  | @ -265,7 +268,11 @@ pic_open(int argc, char *argv[], char **envp, pic_allocf allocf) | |||
|   S(sQUASIQUOTE, "quasiquote"); | ||||
|   S(sUNQUOTE, "unquote"); | ||||
|   S(sUNQUOTE_SPLICING, "unquote-splicing"); | ||||
|   S(sDEFINE_SYNTAX, "define-syntax"); | ||||
|   S(sSYNTAX_QUOTE, "syntax-quote"); | ||||
|   S(sSYNTAX_QUASIQUOTE, "syntax-quasiquote"); | ||||
|   S(sSYNTAX_UNQUOTE, "syntax-unquote"); | ||||
|   S(sSYNTAX_UNQUOTE_SPLICING, "syntax-unquote-splicing"); | ||||
|   S(sDEFINE_MACRO, "define-macro"); | ||||
|   S(sIMPORT, "import"); | ||||
|   S(sEXPORT, "export"); | ||||
|   S(sDEFINE_LIBRARY, "define-library"); | ||||
|  | @ -308,37 +315,37 @@ pic_open(int argc, char *argv[], char **envp, pic_allocf allocf) | |||
| 
 | ||||
|   pic_gc_arena_restore(pic, ai); | ||||
| 
 | ||||
| #define R(slot,name) pic->slot = pic_gensym(pic, pic_intern_cstr(pic, name)); | ||||
| #define U(slot,name) pic->slot = pic_uniq(pic, pic_obj_value(pic_intern_cstr(pic, name))) | ||||
| 
 | ||||
|   R(rDEFINE, "define"); | ||||
|   R(rLAMBDA, "lambda"); | ||||
|   R(rIF, "if"); | ||||
|   R(rBEGIN, "begin"); | ||||
|   R(rSETBANG, "set!"); | ||||
|   R(rQUOTE, "quote"); | ||||
|   R(rDEFINE_SYNTAX, "define-syntax"); | ||||
|   R(rIMPORT, "import"); | ||||
|   R(rEXPORT, "export"); | ||||
|   R(rDEFINE_LIBRARY, "define-library"); | ||||
|   R(rCOND_EXPAND, "cond-expand"); | ||||
|   R(rCONS, "cons"); | ||||
|   R(rCAR, "car"); | ||||
|   R(rCDR, "cdr"); | ||||
|   R(rNILP, "null?"); | ||||
|   R(rSYMBOLP, "symbol?"); | ||||
|   R(rPAIRP, "pair?"); | ||||
|   R(rADD, "+"); | ||||
|   R(rSUB, "-"); | ||||
|   R(rMUL, "*"); | ||||
|   R(rDIV, "/"); | ||||
|   R(rEQ, "="); | ||||
|   R(rLT, "<"); | ||||
|   R(rLE, "<="); | ||||
|   R(rGT, ">"); | ||||
|   R(rGE, ">="); | ||||
|   R(rNOT, "not"); | ||||
|   R(rVALUES, "values"); | ||||
|   R(rCALL_WITH_VALUES, "call-with-values"); | ||||
|   U(uDEFINE, "define"); | ||||
|   U(uLAMBDA, "lambda"); | ||||
|   U(uIF, "if"); | ||||
|   U(uBEGIN, "begin"); | ||||
|   U(uSETBANG, "set!"); | ||||
|   U(uQUOTE, "quote"); | ||||
|   U(uDEFINE_MACRO, "define-macro"); | ||||
|   U(uIMPORT, "import"); | ||||
|   U(uEXPORT, "export"); | ||||
|   U(uDEFINE_LIBRARY, "define-library"); | ||||
|   U(uCOND_EXPAND, "cond-expand"); | ||||
|   U(uCONS, "cons"); | ||||
|   U(uCAR, "car"); | ||||
|   U(uCDR, "cdr"); | ||||
|   U(uNILP, "null?"); | ||||
|   U(uSYMBOLP, "symbol?"); | ||||
|   U(uPAIRP, "pair?"); | ||||
|   U(uADD, "+"); | ||||
|   U(uSUB, "-"); | ||||
|   U(uMUL, "*"); | ||||
|   U(uDIV, "/"); | ||||
|   U(uEQ, "="); | ||||
|   U(uLT, "<"); | ||||
|   U(uLE, "<="); | ||||
|   U(uGT, ">"); | ||||
|   U(uGE, ">="); | ||||
|   U(uNOT, "not"); | ||||
|   U(uVALUES, "values"); | ||||
|   U(uCALL_WITH_VALUES, "call-with-values"); | ||||
|   pic_gc_arena_restore(pic, ai); | ||||
| 
 | ||||
|   /* root tables */ | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| 
 | ||||
| #include "picrin.h" | ||||
| 
 | ||||
| pic_sym * | ||||
| static pic_sym * | ||||
| pic_make_symbol(pic_state *pic, pic_str *str) | ||||
| { | ||||
|   pic_sym *sym; | ||||
|  | @ -42,25 +42,6 @@ pic_intern_cstr(pic_state *pic, const char *str) | |||
|   return pic_intern(pic, pic_make_str(pic, str, strlen(str))); | ||||
| } | ||||
| 
 | ||||
| pic_sym * | ||||
| pic_gensym(pic_state *pic, pic_sym *base) | ||||
| { | ||||
|   return pic_make_symbol(pic, base->str); | ||||
| } | ||||
| 
 | ||||
| bool | ||||
| pic_interned_p(pic_state *pic, pic_sym *sym) | ||||
| { | ||||
|   xh_entry *e; | ||||
| 
 | ||||
|   e = xh_get_str(&pic->syms, pic_str_cstr(pic, sym->str)); | ||||
|   if (e) { | ||||
|     return sym == xh_val(e, pic_sym *); | ||||
|   } else { | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const char * | ||||
| pic_symbol_name(pic_state *pic, pic_sym *sym) | ||||
| { | ||||
|  | @ -121,7 +102,7 @@ pic_init_symbol(pic_state *pic) | |||
| { | ||||
|   void pic_defun_vm(pic_state *, const char *, pic_sym *, pic_func_t); | ||||
| 
 | ||||
|   pic_defun_vm(pic, "symbol?", pic->rSYMBOLP, pic_symbol_symbol_p); | ||||
|   pic_defun_vm(pic, "symbol?", pic->uSYMBOLP, pic_symbol_symbol_p); | ||||
| 
 | ||||
|   pic_defun(pic, "symbol->string", pic_symbol_symbol_to_string); | ||||
|   pic_defun(pic, "string->symbol", pic_symbol_string_to_symbol); | ||||
|  |  | |||
|  | @ -394,9 +394,9 @@ pic_get_args(pic_state *pic, const char *format, ...) | |||
| } | ||||
| 
 | ||||
| void | ||||
| pic_define_syntactic_keyword(pic_state *pic, struct pic_env *env, pic_sym *sym, pic_sym *rsym) | ||||
| pic_define_syntactic_keyword(pic_state *pic, struct pic_env *env, pic_sym *sym, pic_sym *uid) | ||||
| { | ||||
|   pic_put_rename(pic, env, sym, rsym); | ||||
|   pic_put_variable(pic, env, pic_obj_value(sym), uid); | ||||
| 
 | ||||
|   if (pic->lib && pic->lib->env == env) { | ||||
|     pic_export(pic, sym); | ||||
|  | @ -406,17 +406,17 @@ pic_define_syntactic_keyword(pic_state *pic, struct pic_env *env, pic_sym *sym, | |||
| void | ||||
| pic_define_noexport(pic_state *pic, const char *name, pic_value val) | ||||
| { | ||||
|   pic_sym *sym, *rename; | ||||
|   pic_sym *sym, *uid; | ||||
| 
 | ||||
|   sym = pic_intern_cstr(pic, name); | ||||
| 
 | ||||
|   if ((rename = pic_find_rename(pic, pic->lib->env, sym)) == NULL) { | ||||
|     rename = pic_add_rename(pic, pic->lib->env, sym); | ||||
|   if ((uid = pic_find_variable(pic, pic->lib->env, pic_obj_value(sym))) == NULL) { | ||||
|     uid = pic_add_variable(pic, pic->lib->env, pic_obj_value(sym)); | ||||
|   } else { | ||||
|     pic_warnf(pic, "redefining global"); | ||||
|   } | ||||
| 
 | ||||
|   pic_dict_set(pic, pic->globals, rename, val); | ||||
|   pic_dict_set(pic, pic->globals, uid, val); | ||||
| } | ||||
| 
 | ||||
| void | ||||
|  | @ -430,29 +430,29 @@ pic_define(pic_state *pic, const char *name, pic_value val) | |||
| pic_value | ||||
| pic_ref(pic_state *pic, struct pic_lib *lib, const char *name) | ||||
| { | ||||
|   pic_sym *sym, *rename; | ||||
|   pic_sym *sym, *uid; | ||||
| 
 | ||||
|   sym = pic_intern_cstr(pic, name); | ||||
| 
 | ||||
|   if ((rename = pic_find_rename(pic, lib->env, sym)) == NULL) { | ||||
|   if ((uid = pic_find_variable(pic, lib->env, pic_obj_value(sym))) == NULL) { | ||||
|     pic_errorf(pic, "symbol \"%s\" not defined in library ~s", name, lib->name); | ||||
|   } | ||||
| 
 | ||||
|   return pic_dict_ref(pic, pic->globals, rename); | ||||
|   return pic_dict_ref(pic, pic->globals, uid); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| pic_set(pic_state *pic, struct pic_lib *lib, const char *name, pic_value val) | ||||
| { | ||||
|   pic_sym *sym, *rename; | ||||
|   pic_sym *sym, *uid; | ||||
| 
 | ||||
|   sym = pic_intern_cstr(pic, name); | ||||
| 
 | ||||
|   if ((rename = pic_find_rename(pic, lib->env, sym)) == NULL) { | ||||
|   if ((uid = pic_find_variable(pic, lib->env, pic_obj_value(sym))) == NULL) { | ||||
|     pic_errorf(pic, "symbol \"%s\" not defined in library ~s", name, lib->name); | ||||
|   } | ||||
| 
 | ||||
|   pic_dict_set(pic, pic->globals, rename, val); | ||||
|   pic_dict_set(pic, pic->globals, uid, val); | ||||
| } | ||||
| 
 | ||||
| pic_value | ||||
|  | @ -477,7 +477,7 @@ pic_defun(pic_state *pic, const char *name, pic_func_t cfunc) | |||
| } | ||||
| 
 | ||||
| void | ||||
| pic_defun_vm(pic_state *pic, const char *name, pic_sym *rename, pic_func_t func) | ||||
| pic_defun_vm(pic_state *pic, const char *name, pic_sym *uid, pic_func_t func) | ||||
| { | ||||
|   struct pic_proc *proc; | ||||
|   pic_sym *sym; | ||||
|  | @ -486,9 +486,9 @@ pic_defun_vm(pic_state *pic, const char *name, pic_sym *rename, pic_func_t func) | |||
| 
 | ||||
|   sym = pic_intern_cstr(pic, name); | ||||
| 
 | ||||
|   pic_put_rename(pic, pic->lib->env, sym, rename); | ||||
|   pic_put_variable(pic, pic->lib->env, pic_obj_value(sym), uid); | ||||
| 
 | ||||
|   pic_dict_set(pic, pic->globals, rename, pic_obj_value(proc)); | ||||
|   pic_dict_set(pic, pic->globals, uid, pic_obj_value(proc)); | ||||
| 
 | ||||
|   pic_export(pic, sym); | ||||
| } | ||||
|  | @ -499,6 +499,38 @@ pic_defvar(pic_state *pic, const char *name, pic_value init, struct pic_proc *co | |||
|   pic_define(pic, name, pic_obj_value(pic_make_var(pic, init, conv))); | ||||
| } | ||||
| 
 | ||||
| static pic_value | ||||
| defmacro_call(pic_state *pic) | ||||
| { | ||||
|   struct pic_proc *self = pic_get_proc(pic); | ||||
|   pic_value args, tmp, proc; | ||||
| 
 | ||||
|   pic_get_args(pic, "oo", &args, &tmp); | ||||
| 
 | ||||
|   proc = pic_attr_ref(pic, pic_obj_value(self), "@@transformer"); | ||||
| 
 | ||||
|   return pic_apply_trampoline(pic, pic_proc_ptr(proc), pic_cdr(pic, args)); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| pic_defmacro(pic_state *pic, pic_sym *name, pic_sym *id, pic_func_t func) | ||||
| { | ||||
|   struct pic_proc *proc, *trans; | ||||
| 
 | ||||
|   trans = pic_make_proc(pic, func, pic_symbol_name(pic, name)); | ||||
| 
 | ||||
|   pic_put_variable(pic, pic->lib->env, pic_obj_value(name), id); | ||||
| 
 | ||||
|   proc = pic_make_proc(pic, defmacro_call, "defmacro_call"); | ||||
|   pic_attr_set(pic, pic_obj_value(proc), "@@transformer", pic_obj_value(trans)); | ||||
| 
 | ||||
|   /* symbol registration */ | ||||
|   pic_dict_set(pic, pic->macros, id, pic_obj_value(proc)); | ||||
| 
 | ||||
|   /* auto export! */ | ||||
|   pic_export(pic, name); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| vm_push_cxt(pic_state *pic) | ||||
| { | ||||
|  |  | |||
|  | @ -302,6 +302,9 @@ write_core(struct writer_control *p, pic_value obj) | |||
|     } | ||||
|     xfprintf(file, ")"); | ||||
|     break; | ||||
|   case PIC_TT_ID: | ||||
|     xfprintf(file, "#<identifier %s>", pic_symbol_name(pic, pic_var_name(pic, obj))); | ||||
|     break; | ||||
|   default: | ||||
|     xfprintf(file, "#<%s %p>", pic_type_repr(pic_type(obj)), pic_ptr(obj)); | ||||
|     break; | ||||
|  |  | |||
|  | @ -6,11 +6,16 @@ | |||
|           quote | ||||
|           set! | ||||
|           begin | ||||
|           define-syntax) | ||||
|           define-macro) | ||||
| 
 | ||||
|   (export syntax-error | ||||
|           define-syntax | ||||
|           let-syntax | ||||
|           letrec-syntax) | ||||
|           letrec-syntax | ||||
|           syntax-quote | ||||
|           syntax-quasiquote | ||||
|           syntax-unquote | ||||
|           syntax-unquote-splicing) | ||||
| 
 | ||||
|   (export let | ||||
|           let* | ||||
|  | @ -239,9 +244,13 @@ | |||
|   (export make-parameter | ||||
|           parameterize) | ||||
| 
 | ||||
|   (export identifier? | ||||
|           identifier=? | ||||
|           make-identifier) | ||||
|   (export make-identifier | ||||
|           identifier? | ||||
|           identifier-variable | ||||
|           identifier-environment | ||||
| 
 | ||||
|           variable? | ||||
|           variable=?) | ||||
| 
 | ||||
|   (export call-with-current-continuation | ||||
|           call/cc | ||||
|  |  | |||
|  | @ -3,47 +3,36 @@ | |||
|           (picrin base) | ||||
|           (picrin macro)) | ||||
| 
 | ||||
|   (define-syntax destructuring-bind | ||||
|     (ir-macro-transformer | ||||
|      (lambda (form inject compare) | ||||
|        (let ((formal (car (cdr form))) | ||||
|              (value  (car (cdr (cdr form)))) | ||||
|              (body   (cdr (cdr (cdr form))))) | ||||
|   (define-syntax (destructuring-let formal value . body) | ||||
|     (cond | ||||
|           ((symbol? formal) | ||||
|            `(let ((,formal ,value)) | ||||
|               ,@body)) | ||||
|      ((variable? formal) | ||||
|       #`(let ((#,formal #,value)) | ||||
|           #,@body)) | ||||
|      ((pair? formal) | ||||
|            `(let ((value# ,value)) | ||||
|               (destructuring-bind ,(car formal) (car value#) | ||||
|                 (destructuring-bind ,(cdr formal) (cdr value#) | ||||
|                   ,@body)))) | ||||
|       #`(let ((value #,value)) | ||||
|           (destructuring-let #,(car formal) (car value) | ||||
|             (destructuring-let #,(cdr formal) (cdr value) | ||||
|               #,@body)))) | ||||
|      ((vector? formal) | ||||
|       ;; TODO | ||||
|       (error "fixme")) | ||||
|      (else | ||||
|            `(if (equal? ,value ',formal) | ||||
|       #`(if (equal? #,value '#,formal) | ||||
|             (begin | ||||
|                   ,@body) | ||||
|                 (error "match failure" ,value ',formal)))))))) | ||||
|               #,@body) | ||||
|             (error "match failure" #,value '#,formal))))) | ||||
| 
 | ||||
|   (define-syntax destructuring-lambda | ||||
|     (ir-macro-transformer | ||||
|      (lambda (form inject compare) | ||||
|        (let ((args (car (cdr form))) | ||||
|              (body (cdr (cdr form)))) | ||||
|          `(lambda formal# (destructuring-bind ,args formal# ,@body)))))) | ||||
|   (define-syntax (destructuring-lambda formal . body) | ||||
|     #`(lambda args | ||||
|         (destructuring-let #,formal args #,@body))) | ||||
| 
 | ||||
|   (define-syntax destructuring-define | ||||
|     (ir-macro-transformer | ||||
|      (lambda (form inject compare) | ||||
|        (let ((maybe-formal (cadr form))) | ||||
|          (if (symbol? maybe-formal) | ||||
|              `(define ,@(cdr form)) | ||||
|              `(destructuring-define ,(car maybe-formal) | ||||
|                 (destructuring-lambda ,(cdr maybe-formal) | ||||
|                   ,@(cddr form)))))))) | ||||
|   (define-syntax (destructuring-define formal . body) | ||||
|     (if (variable? formal) | ||||
|         #`(define #,formal #,@body) | ||||
|         #`(destructuring-define #,(car formal) | ||||
|             (destructuring-lambda #,(cdr formal) | ||||
|               #,@body)))) | ||||
| 
 | ||||
|   (export (rename destructuring-bind bind) | ||||
|   (export (rename destructuring-let let) | ||||
|           (rename destructuring-lambda lambda) | ||||
|           (rename destructuring-define define))) | ||||
|  |  | |||
|  | @ -1,141 +1,180 @@ | |||
| (define-library (picrin macro) | ||||
|   (import (picrin base)) | ||||
| 
 | ||||
|   (export identifier? | ||||
|           identifier=? | ||||
|   ;; macro primitives | ||||
| 
 | ||||
|   (export define-macro | ||||
|           make-identifier | ||||
|           identifier? | ||||
|           identifier-variable | ||||
|           identifier-environment | ||||
|           variable? | ||||
|           variable=?) | ||||
| 
 | ||||
|   ;; simple macro | ||||
| 
 | ||||
|   (export define-syntax | ||||
|           syntax-quote | ||||
|           syntax-quasiquote | ||||
|           syntax-unquote | ||||
|           syntax-unquote-splicing) | ||||
| 
 | ||||
|   ;; misc transformers | ||||
| 
 | ||||
|   (export call-with-current-environment | ||||
|           make-syntactic-closure | ||||
|           close-syntax | ||||
|           capture-syntactic-environment | ||||
|           strip-syntax | ||||
|           sc-macro-transformer | ||||
|           rsc-macro-transformer | ||||
|           er-macro-transformer | ||||
|           ir-macro-transformer | ||||
|           ;; strip-syntax | ||||
|           define-macro) | ||||
|           ir-macro-transformer) | ||||
| 
 | ||||
|   ;; assumes no derived expressions are provided yet | ||||
| 
 | ||||
|   (define (walk proc expr) | ||||
|     "walk on symbols" | ||||
|     (if (null? expr) | ||||
|         '() | ||||
|         (if (pair? expr) | ||||
|             (cons (walk proc (car expr)) | ||||
|                   (walk proc (cdr expr))) | ||||
|             (if (vector? expr) | ||||
|                 (list->vector (walk proc (vector->list expr))) | ||||
|                 (if (symbol? expr) | ||||
|                     (proc expr) | ||||
|                     expr))))) | ||||
|   (define-macro call-with-current-environment | ||||
|     (lambda (form env) | ||||
|       `(,(cadr form) ',env))) | ||||
| 
 | ||||
| 
 | ||||
|   ;; syntactic closure | ||||
| 
 | ||||
|   (define (memoize f) | ||||
|     "memoize on symbols" | ||||
|     (define cache (make-dictionary)) | ||||
|     (lambda (sym) | ||||
|       (define value (dictionary-ref cache sym)) | ||||
|       (if (not (undefined? value)) | ||||
|           value | ||||
|           (begin | ||||
|             (define val (f sym)) | ||||
|             (dictionary-set! cache sym val) | ||||
|             val)))) | ||||
| 
 | ||||
|   (define (make-syntactic-closure env free form) | ||||
| 
 | ||||
|     (define resolve | ||||
|       (memoize | ||||
|        (lambda (sym) | ||||
|          (make-identifier sym env)))) | ||||
| 
 | ||||
|     (walk | ||||
|      (lambda (sym) | ||||
|        (if (memq sym free) | ||||
|            sym | ||||
|            (resolve sym))) | ||||
|      form)) | ||||
|     (letrec | ||||
|         ((wrap (let ((register (make-register))) | ||||
|                  (lambda (var) | ||||
|                    (let ((id (register var))) | ||||
|                      (if (undefined? id) | ||||
|                          (let ((id (make-identifier var env))) | ||||
|                            (register var id) | ||||
|                            id) | ||||
|                          id))))) | ||||
|          (walk (lambda (f form) | ||||
|                  (cond | ||||
|                   ((variable? form) | ||||
|                    (f form)) | ||||
|                   ((pair? form) | ||||
|                    (cons (walk f (car form)) (walk f (cdr form)))) | ||||
|                   ((vector? form) | ||||
|                    (list->vector (walk f (vector->list form)))) | ||||
|                   (else | ||||
|                    form))))) | ||||
|       (letrec | ||||
|           ((f (lambda (var) | ||||
|                 (let loop ((free free)) | ||||
|                   (if (null? free) | ||||
|                       (wrap free) | ||||
|                       (if (variable=? var (car free)) | ||||
|                           var | ||||
|                           (loop (cdr free)))))))) | ||||
|         (walk f form)))) | ||||
| 
 | ||||
|   (define (close-syntax form env) | ||||
|     (make-syntactic-closure env '() form)) | ||||
| 
 | ||||
|   (define-syntax capture-syntactic-environment | ||||
|     (lambda (mac-env) | ||||
|       (lambda (form use-env) | ||||
|         (list (cadr form) (list (make-identifier 'quote mac-env) mac-env))))) | ||||
|   (define (strip-syntax form) | ||||
|     (letrec | ||||
|         ((unwrap (lambda (var) | ||||
|                    (identifier-variable var))) | ||||
|          (walk (lambda (f form) | ||||
|                  (cond | ||||
|                   ((variable? form) | ||||
|                    (f form)) | ||||
|                   ((pair? form) | ||||
|                    (cons (walk f (car form)) (walk f (cdr form)))) | ||||
|                   ((vector? form) | ||||
|                    (list->vector (walk f (vector->list form)))) | ||||
|                   (else | ||||
|                    form))))) | ||||
|       (walk unwrap form))) | ||||
| 
 | ||||
|   (define (sc-macro-transformer f) | ||||
|     (lambda (mac-env) | ||||
|       (lambda (expr use-env) | ||||
|         (make-syntactic-closure mac-env '() (f expr use-env))))) | ||||
| 
 | ||||
|   (define (rsc-macro-transformer f) | ||||
|     (lambda (mac-env) | ||||
|       (lambda (expr use-env) | ||||
|         (make-syntactic-closure use-env '() (f expr mac-env))))) | ||||
|   ;; transformers | ||||
| 
 | ||||
|   (define (er-macro-transformer f) | ||||
|     (lambda (mac-env) | ||||
|       (lambda (expr use-env) | ||||
| 
 | ||||
|         (define rename | ||||
|           (memoize | ||||
|            (lambda (sym) | ||||
|              (make-identifier sym mac-env)))) | ||||
|   (define (sc-transformer f) | ||||
|     (lambda (form use-env mac-env) | ||||
|       (make-syntactic-closure mac-env '() (f form use-env)))) | ||||
| 
 | ||||
|         (define (compare x y) | ||||
|           (if (not (symbol? x)) | ||||
|               #f | ||||
|               (if (not (symbol? y)) | ||||
|                   #f | ||||
|                   (identifier=? use-env x use-env y)))) | ||||
|   (define (rsc-transformer f) | ||||
|     (lambda (form use-env mac-env) | ||||
|       (make-syntactic-closure use-env '() (f form mac-env)))) | ||||
| 
 | ||||
|         (f expr rename compare)))) | ||||
|   (define (er-transformer f) | ||||
|     (lambda (form use-env mac-env) | ||||
|       (letrec | ||||
|           ((rename (let ((register (make-register))) | ||||
|                      (lambda (var) | ||||
|                        (let ((id (register var))) | ||||
|                          (if (undefined? id) | ||||
|                              (let ((id (make-identifier var mac-env))) | ||||
|                                (register var id) | ||||
|                                id) | ||||
|                              id))))) | ||||
|            (compare (lambda (x y) | ||||
|                       (variable=? | ||||
|                        (make-identifier x use-env) | ||||
|                        (make-identifier y use-env))))) | ||||
|         (f form rename compare)))) | ||||
| 
 | ||||
|   (define (ir-macro-transformer f) | ||||
|     (lambda (mac-env) | ||||
|       (lambda (expr use-env) | ||||
|   (define (ir-transformer f) | ||||
|     (lambda (form use-env mac-env) | ||||
|       (let ((register1 (make-register)) | ||||
|             (register2 (make-register))) | ||||
|         (letrec | ||||
|             ((inject (lambda (var1) | ||||
|                        (let ((var2 (register1 var1))) | ||||
|                          (if (undefined? var2) | ||||
|                              (let ((var2 (make-identifier var1 use-env))) | ||||
|                                (register1 var1 var2) | ||||
|                                (register2 var2 var1) | ||||
|                                var2) | ||||
|                              var2)))) | ||||
|              (rename (let ((register (make-register))) | ||||
|                        (lambda (var) | ||||
|                          (let ((id (register var))) | ||||
|                            (if (undefined? id) | ||||
|                                (let ((id (make-identifier var mac-env))) | ||||
|                                  (register var id) | ||||
|                                  id) | ||||
|                                id))))) | ||||
|              (flip (lambda (var2) ; unwrap if injected, wrap if not injected | ||||
|                      (let ((var1 (register2 var2))) | ||||
|                        (if (undefined? var1) | ||||
|                            (rename var2) | ||||
|                            var1)))) | ||||
|              (walk (lambda (f form) | ||||
|                      (cond | ||||
|                       ((variable? form) | ||||
|                        (f form)) | ||||
|                       ((pair? form) | ||||
|                        (cons (walk f (car form)) (walk f (cdr form)))) | ||||
|                       ((vector? form) | ||||
|                        (list->vector (walk f (vector->list form)))) | ||||
|                       (else | ||||
|                        form)))) | ||||
|              (compare (lambda (x y) | ||||
|                         (variable=? | ||||
|                          (make-identifier x mac-env) | ||||
|                          (make-identifier y mac-env))))) | ||||
|           (walk flip (f (walk inject form) inject compare)))))) | ||||
| 
 | ||||
|         (define icache* (make-dictionary)) | ||||
|   (define-macro sc-macro-transformer | ||||
|     (lambda (f mac-env) | ||||
|       #`(lambda (form use-env) | ||||
|           ((sc-transformer #,(cadr f)) form use-env #,mac-env)))) | ||||
| 
 | ||||
|         (define inject | ||||
|           (memoize | ||||
|            (lambda (sym) | ||||
|              (define id (make-identifier sym use-env)) | ||||
|              (dictionary-set! icache* id sym) | ||||
|              id))) | ||||
|   (define-macro rsc-macro-transformer | ||||
|     (lambda (f mac-env) | ||||
|       #`(lambda (form use-env) | ||||
|           ((rsc-transformer #,(cadr f)) form use-env #,mac-env)))) | ||||
| 
 | ||||
|         (define rename | ||||
|           (memoize | ||||
|            (lambda (sym) | ||||
|              (make-identifier sym mac-env)))) | ||||
|   (define-macro er-macro-transformer | ||||
|     (lambda (f mac-env) | ||||
|       #`(lambda (form use-env) | ||||
|           ((er-transformer #,(cadr f)) form use-env #,mac-env)))) | ||||
| 
 | ||||
|         (define (compare x y) | ||||
|           (if (not (symbol? x)) | ||||
|               #f | ||||
|               (if (not (symbol? y)) | ||||
|                   #f | ||||
|                   (identifier=? mac-env x mac-env y)))) | ||||
| 
 | ||||
|         (walk (lambda (sym) | ||||
|                 (let ((value (dictionary-ref icache* sym))) | ||||
|                   (if (undefined? value) | ||||
|                       (rename sym) | ||||
|                       value))) | ||||
|               (f (walk inject expr) inject compare))))) | ||||
| 
 | ||||
|   ;; (define (strip-syntax form) | ||||
|   ;;   (walk ungensym form)) | ||||
| 
 | ||||
|   (define-syntax define-macro | ||||
|     (er-macro-transformer | ||||
|      (lambda (expr r c) | ||||
|        (define formal (car (cdr expr))) | ||||
|        (define body   (cdr (cdr expr))) | ||||
|        (if (symbol? formal) | ||||
|            (list (r 'define-syntax) formal | ||||
|                  (list (r 'lambda) (list (r 'form) '_ '_) | ||||
|                        (list (r 'apply) (car body) (list (r 'cdr) (r 'form))))) | ||||
|            (list (r 'define-macro) (car formal) | ||||
|                  (cons (r 'lambda) | ||||
|                        (cons (cdr formal) | ||||
|                              body)))))))) | ||||
|   (define-macro ir-macro-transformer | ||||
|     (lambda (f mac-env) | ||||
|       #`(lambda (form use-env) | ||||
|           ((ir-transformer #,(cadr f)) form use-env #,mac-env))))) | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
|   (import (picrin base) | ||||
|           (picrin macro)) | ||||
| 
 | ||||
|   ;; define-record-type | ||||
|   ;; record meta type | ||||
| 
 | ||||
|   (define ((boot-make-record-type <meta-type>) name) | ||||
|     (let ((rectype (make-record <meta-type>))) | ||||
|  | @ -10,70 +10,50 @@ | |||
|       rectype)) | ||||
| 
 | ||||
|   (define <record-type> | ||||
|     (let ((<record-type> | ||||
|            ((boot-make-record-type #t) 'record-type))) | ||||
|     (let ((<record-type> ((boot-make-record-type #t) 'record-type))) | ||||
|       (record-set! <record-type> '@@type <record-type>) | ||||
|       <record-type>)) | ||||
| 
 | ||||
|   (define make-record-type (boot-make-record-type <record-type>)) | ||||
| 
 | ||||
|   (define-syntax define-record-constructor | ||||
|     (ir-macro-transformer | ||||
|      (lambda (form inject compare?) | ||||
|        (let ((rectype (car (cdr form))) | ||||
| 	     (name    (car (cdr (cdr form)))) | ||||
| 	     (fields  (cdr (cdr (cdr form))))) | ||||
| 	 `(define (,name ,@fields) | ||||
| 	    (let ((record (make-record ,rectype))) | ||||
| 	      ,@(map (lambda (field) | ||||
| 		       `(record-set! record ',field ,field)) | ||||
| 		     fields) | ||||
| 	      record)))))) | ||||
|   ;; define-record-type | ||||
| 
 | ||||
|   (define-syntax define-record-predicate | ||||
|     (ir-macro-transformer | ||||
|      (lambda (form inject compare?) | ||||
|        (let ((rectype (car (cdr form))) | ||||
| 	     (name    (car (cdr (cdr form))))) | ||||
| 	 `(define (,name obj) | ||||
|   (define-syntax (define-record-constructor type name . fields) | ||||
|     (let ((record #'record)) | ||||
|       #`(define (#,name . #,fields) | ||||
|           (let ((#,record (make-record #,type))) | ||||
|             #,@(map (lambda (field) #`(record-set! #,record '#,field #,field)) fields) | ||||
|             #,record)))) | ||||
| 
 | ||||
|   (define-syntax (define-record-predicate type name) | ||||
|     #`(define (#,name obj) | ||||
|         (and (record? obj) | ||||
| 		 (eq? (record-type obj) | ||||
|                       ,rectype))))))) | ||||
|              (eq? (record-type obj) #,type)))) | ||||
| 
 | ||||
|   (define-syntax define-record-field | ||||
|     (ir-macro-transformer | ||||
|      (lambda (form inject compare?) | ||||
|        (let ((pred       (car (cdr form))) | ||||
| 	     (field-name (car (cdr (cdr form)))) | ||||
| 	     (accessor   (car (cdr (cdr (cdr form))))) | ||||
| 	     (modifier?  (cdr (cdr (cdr (cdr form)))))) | ||||
| 	 (if (null? modifier?) | ||||
| 	     `(define (,accessor record) | ||||
| 		(if (,pred record) | ||||
| 		    (record-ref record ',field-name) | ||||
| 		    (error (string-append (symbol->string  ',accessor) ": wrong record type") record))) | ||||
| 	     `(begin | ||||
| 		(define (,accessor record) | ||||
| 		  (if (,pred record) | ||||
| 		      (record-ref record ',field-name) | ||||
| 		      (error (string-append (symbol->string  ',accessor) ": wrong record type") record))) | ||||
| 		(define (,(car modifier?) record val) | ||||
| 		  (if (,pred record) | ||||
| 		      (record-set! record ',field-name val) | ||||
| 		      (error (string-append (symbol->string ',(car modifier?)) ": wrong record type")  record))))))))) | ||||
|   (define-syntax (define-record-accessor pred field accessor) | ||||
|     #`(define (#,accessor record) | ||||
|         (if (#,pred record) | ||||
|             (record-ref record '#,field) | ||||
|             (error (string-append (symbol->string  '#,accessor) ": wrong record type") record)))) | ||||
| 
 | ||||
|   (define-syntax define-record-type | ||||
|     (ir-macro-transformer | ||||
|      (lambda (form inject compare?) | ||||
|        (let ((name   (car (cdr form))) | ||||
| 	     (ctor   (car (cdr (cdr form)))) | ||||
| 	     (pred   (car (cdr (cdr (cdr form))))) | ||||
| 	     (fields (cdr (cdr (cdr (cdr form)))))) | ||||
| 	 `(begin | ||||
| 	    (define ,name (make-record-type ',name)) | ||||
| 	    (define-record-constructor ,name ,@ctor) | ||||
| 	    (define-record-predicate ,name ,pred) | ||||
| 	    ,@(map (lambda (field) `(define-record-field ,pred ,@field)) | ||||
| 		   fields)))))) | ||||
|   (define-syntax (define-record-modifier pred field modifier) | ||||
|     #`(define (#,modifier record val) | ||||
|         (if (#,pred record) | ||||
|             (record-set! record '#,field val) | ||||
|             (error (string-append (symbol->string '#,modifier) ": wrong record type")  record)))) | ||||
| 
 | ||||
|   (define-syntax (define-record-field pred field accessor . modifier-opt) | ||||
|     (if (null? modifier-opt) | ||||
|         #`(define-record-accessor #,pred #,field #,accessor) | ||||
|         #`(begin | ||||
|             (define-record-accessor #,pred #,field #,accessor) | ||||
|             (define-record-modifier #,pred #,field #,(car modifier-opt))))) | ||||
| 
 | ||||
|   (define-syntax (define-record-type name ctor pred . fields) | ||||
|     #`(begin | ||||
|         (define #,name (make-record-type '#,name)) | ||||
|         (define-record-constructor #,name #,@ctor) | ||||
|         (define-record-predicate #,name #,pred) | ||||
|         #,@(map (lambda (field) #`(define-record-field #,pred #,@field)) fields))) | ||||
| 
 | ||||
|   (export define-record-type)) | ||||
|  |  | |||
|  | @ -1,348 +1,243 @@ | |||
| (define-library (picrin syntax-rules) | ||||
|   (import (picrin base) | ||||
|           (picrin control) | ||||
|           (picrin macro)) | ||||
| 
 | ||||
|   (define-syntax define-auxiliary-syntax | ||||
|     (er-macro-transformer | ||||
|      (lambda (expr r c) | ||||
|        (list (r 'define-syntax) (cadr expr) | ||||
|              (list (r 'lambda) '_ | ||||
|                    (list (r 'lambda) '_ | ||||
|                          (list (r 'error) (list (r 'string-append) "invalid use of auxiliary syntax: '" (symbol->string (cadr expr)) "'")))))))) | ||||
|   (define-syntax (define-auxiliary-syntax var) | ||||
|     #`(define-macro #,var | ||||
|         (lambda _ | ||||
|           (error "invalid use of auxiliary syntax" '#,var)))) | ||||
| 
 | ||||
|   (define-auxiliary-syntax _) | ||||
|   (define-auxiliary-syntax ...) | ||||
| 
 | ||||
|   (define (walk proc expr) | ||||
|     (cond | ||||
|      ((null? expr) | ||||
|       '()) | ||||
|      ((pair? expr) | ||||
|       (cons (walk proc (car expr)) | ||||
|             (walk proc (cdr expr)))) | ||||
|      ((vector? expr) | ||||
|       (list->vector (map proc (vector->list expr)))) | ||||
|      (else | ||||
|       (proc expr)))) | ||||
|   (define (succ n) | ||||
|     (+ n 1)) | ||||
| 
 | ||||
|   (define (flatten expr) | ||||
|     (let ((list '())) | ||||
|       (walk | ||||
|        (lambda (x) | ||||
|          (set! list (cons x list))) | ||||
|        expr) | ||||
|       (reverse list))) | ||||
|   (define (pred n) | ||||
|     (if (= n 0) | ||||
|         0 | ||||
|         (- n 1))) | ||||
| 
 | ||||
|   (define (reverse* l) | ||||
|     ;; (reverse* '(a b c d . e)) => (e d c b a) | ||||
|     (let loop ((a '()) | ||||
|                (d l)) | ||||
|       (if (pair? d) | ||||
|           (loop (cons (car d) a) (cdr d)) | ||||
|           (cons d a)))) | ||||
| 
 | ||||
|   (define (every? pred l) | ||||
|     (if (null? l) | ||||
|   (define (every? args) | ||||
|     (if (null? args) | ||||
|         #t | ||||
|         (and (pred (car l)) (every? pred (cdr l))))) | ||||
|         (if (car args) | ||||
|             (every? (cdr args)) | ||||
|             #f))) | ||||
| 
 | ||||
|   (define-syntax syntax-rules | ||||
|     (er-macro-transformer | ||||
|      (lambda (form r compare) | ||||
|        (define _define (r 'define)) | ||||
|        (define _let (r 'let)) | ||||
|        (define _if (r 'if)) | ||||
|        (define _begin (r 'begin)) | ||||
|        (define _lambda (r 'lambda)) | ||||
|        (define _set! (r 'set!)) | ||||
|        (define _not (r 'not)) | ||||
|        (define _and (r 'and)) | ||||
|        (define _car (r 'car)) | ||||
|        (define _cdr (r 'cdr)) | ||||
|        (define _cons (r 'cons)) | ||||
|        (define _pair? (r 'pair?)) | ||||
|        (define _null? (r 'null?)) | ||||
|        (define _symbol? (r 'symbol?)) | ||||
|        (define _vector? (r 'vector?)) | ||||
|        (define _eqv? (r 'eqv?)) | ||||
|        (define _string=? (r 'string=?)) | ||||
|        (define _map (r 'map)) | ||||
|        (define _vector->list (r 'vector->list)) | ||||
|        (define _list->vector (r 'list->vector)) | ||||
|        (define _quote (r 'quote)) | ||||
|        (define _quasiquote (r 'quasiquote)) | ||||
|        (define _unquote (r 'unquote)) | ||||
|        (define _unquote-splicing (r 'unquote-splicing)) | ||||
|        (define _syntax-error (r 'syntax-error)) | ||||
|        (define _escape (r 'escape)) | ||||
|        (define _er-macro-transformer (r 'er-macro-transformer)) | ||||
|   (define (filter f list) | ||||
|     (if (null? list) | ||||
|         '() | ||||
|         (if (f (car list)) | ||||
|             (cons (car list) | ||||
|                   (filter f (cdr list))) | ||||
|             (filter f (cdr list))))) | ||||
| 
 | ||||
|        (define (var->sym v) | ||||
|          (let loop ((cnt 0) | ||||
|                     (v v)) | ||||
|            (if (symbol? v) | ||||
|                (string->symbol | ||||
|                 (string-append (symbol->string v) "/" (number->string cnt))) | ||||
|                (loop (+ 1 cnt) (car v))))) | ||||
|   (define (take-tail n list) | ||||
|     (let drop ((n (- (length list) n)) (list list)) | ||||
|       (if (= n 0) | ||||
|           list | ||||
|           (drop (- n 1) (cdr list))))) | ||||
| 
 | ||||
|        (define push-var list) | ||||
|   (define (drop-tail n list) | ||||
|     (let take ((n (- (length list) n)) (list list)) | ||||
|       (if (= n 0) | ||||
|           '() | ||||
|           (cons (car list) (take (- n 1) (cdr list)))))) | ||||
| 
 | ||||
|        (define (compile-match ellipsis literals pattern) | ||||
| 	 (letrec ((compile-match-base | ||||
| 		   (lambda (pattern) | ||||
| 		     (cond ((member pattern literals compare) | ||||
| 			    (values | ||||
|                               `(,_if (,_and (,_symbol? expr) (cmp expr (rename ',pattern))) | ||||
|                                      #f | ||||
|                                      (exit #f)) | ||||
|                               '())) | ||||
| 			   ((compare pattern (r '_)) (values #f '())) | ||||
| 			   ((and ellipsis (compare pattern ellipsis)) | ||||
| 			    (values `(,_syntax-error "invalid pattern") '())) | ||||
| 			   ((symbol? pattern) | ||||
| 			    (values `(,_set! ,(var->sym pattern) expr) (list pattern))) | ||||
| 			   ((pair? pattern) | ||||
| 			    (compile-match-list pattern)) | ||||
| 			   ((vector? pattern) | ||||
| 			    (compile-match-vector pattern)) | ||||
| 			   ((string? pattern) | ||||
| 			    (values | ||||
|                               `(,_if (,_not (,_string=? ',pattern expr)) | ||||
|                                      (exit #f)) | ||||
|                               '())) | ||||
| 			   (else | ||||
| 			    (values | ||||
|                               `(,_if (,_not (,_eqv? ',pattern expr)) | ||||
|                                      (exit #f)) | ||||
|                               '()))))) | ||||
|   (define (map-keys f assoc) | ||||
|     (map (lambda (s) `(,(f (car s)) . ,(cdr s))) assoc)) | ||||
| 
 | ||||
| 		  (compile-match-list | ||||
| 		   (lambda (pattern) | ||||
| 		     (let loop ((pattern pattern) | ||||
| 				(matches '()) | ||||
| 				(vars '()) | ||||
| 				(accessor 'expr)) | ||||
| 		       (cond ;; (hoge) | ||||
| 			((not (pair? (cdr pattern))) | ||||
| 			 (let*-values (((match1 vars1) (compile-match-base (car pattern))) | ||||
| 				       ((match2 vars2) (compile-match-base (cdr pattern)))) | ||||
| 			   (values | ||||
|                              `(,_begin ,@(reverse matches) | ||||
|                                        (,_if (,_pair? ,accessor) | ||||
|                                              (,_begin | ||||
|                                               (,_let ((expr (,_car ,accessor))) | ||||
|                                                      ,match1) | ||||
|                                               (,_let ((expr (,_cdr ,accessor))) | ||||
|                                                      ,match2)) | ||||
|                                              (exit #f))) | ||||
|                              (append vars (append vars1 vars2))))) | ||||
| 			;; (hoge ... rest args) | ||||
| 			((and ellipsis (compare (cadr pattern) ellipsis)) | ||||
| 			 (let-values (((match-r vars-r) (compile-match-list-reverse pattern))) | ||||
| 			   (values | ||||
|                              `(,_begin ,@(reverse matches) | ||||
|                                        (,_let ((expr (,_let loop ((a ()) | ||||
|                                                                   (d ,accessor)) | ||||
|                                                             (,_if (,_pair? d) | ||||
|                                                                   (loop (,_cons (,_car d) a) (,_cdr d)) | ||||
|                                                                   (,_cons d a))))) | ||||
|                                               ,match-r)) | ||||
|                              (append vars vars-r)))) | ||||
| 			(else | ||||
| 			 (let-values (((match1 vars1) (compile-match-base (car pattern)))) | ||||
| 			   (loop (cdr pattern) | ||||
| 				 (cons `(,_if (,_pair? ,accessor) | ||||
| 					      (,_let ((expr (,_car ,accessor))) | ||||
| 						     ,match1) | ||||
| 					      (exit #f)) | ||||
| 				       matches) | ||||
| 				 (append vars vars1) | ||||
| 				 `(,_cdr ,accessor)))))))) | ||||
|   (define (map-values f assoc) | ||||
|     (map (lambda (s) `(,(car s) . ,(f (cdr s)))) assoc)) | ||||
| 
 | ||||
| 		  (compile-match-list-reverse | ||||
| 		   (lambda (pattern) | ||||
| 		     (let loop ((pattern (reverse* pattern)) | ||||
| 				(matches '()) | ||||
| 				(vars '()) | ||||
| 				(accessor 'expr)) | ||||
| 		       (cond ((and ellipsis (compare (car pattern) ellipsis)) | ||||
| 			      (let-values (((match1 vars1) (compile-match-ellipsis (cadr pattern)))) | ||||
| 				(values | ||||
|                                   `(,_begin ,@(reverse matches) | ||||
|                                             (,_let ((expr ,accessor)) | ||||
|                                                    ,match1)) | ||||
|                                   (append vars vars1)))) | ||||
| 			     (else | ||||
| 			      (let-values (((match1 vars1) (compile-match-base (car pattern)))) | ||||
| 				(loop (cdr pattern) | ||||
| 				      (cons `(,_let ((expr (,_car ,accessor))) ,match1) matches) | ||||
| 				      (append vars vars1) | ||||
| 				      `(,_cdr ,accessor)))))))) | ||||
|   ;; TODO | ||||
|   ;; - placeholder | ||||
|   ;; - vector | ||||
|   ;; - (... template) pattern | ||||
| 
 | ||||
| 		  (compile-match-ellipsis | ||||
| 		   (lambda (pattern) | ||||
| 		     (let-values (((match vars) (compile-match-base pattern))) | ||||
| 		       (values | ||||
|                          `(,_let loop ((expr expr)) | ||||
|                                  (,_if (,_not (,_null? expr)) | ||||
|                                        (,_let ,(map (lambda (var) `(,(var->sym var) '())) vars) | ||||
|                                               (,_let ((expr (,_car expr))) | ||||
|                                                      ,match) | ||||
|                                               ,@(map | ||||
|                                                  (lambda (var) | ||||
|                                                    `(,_set! ,(var->sym (push-var var)) | ||||
|                                                             (,_cons ,(var->sym var) ,(var->sym (push-var var))))) | ||||
|                                                  vars) | ||||
|                                               (loop (,_cdr expr))))) | ||||
|                          (map push-var vars))))) | ||||
|   ;; p ::= constant | ||||
|   ;;     | var | ||||
|   ;;     | (p ... . p)      (in input pattern, tail p should be a proper list) | ||||
|   ;;     | (p . p) | ||||
| 
 | ||||
| 		  (compile-match-vector | ||||
| 		   (lambda (pattern) | ||||
| 		     (let-values (((match vars) (compile-match-base (vector->list pattern)))) | ||||
| 		       (values | ||||
|                          `(,_if (,_vector? expr) | ||||
|                                 (,_let ((expr (,_vector->list expr))) | ||||
|                                        ,match) | ||||
|                                 (exit #f)) | ||||
|                          vars))))) | ||||
|   (define (compile ellipsis literals rules) | ||||
| 
 | ||||
| 	   (let-values (((match vars) (compile-match-base (cdr pattern)))) | ||||
| 	     (values `(,_let ((expr (,_cdr expr))) | ||||
| 			     ,match | ||||
|     (define (constant? obj) | ||||
|       (and (not (pair? obj)) | ||||
|            (not (variable? obj)))) | ||||
| 
 | ||||
|     (define (literal? obj) | ||||
|       (and (variable? obj) | ||||
|            (memq obj literals))) | ||||
| 
 | ||||
|     (define (many? pat) | ||||
|       (and (pair? pat) | ||||
|            (pair? (cdr pat)) | ||||
|            (variable? (cadr pat)) | ||||
|            (variable=? (cadr pat) ellipsis))) | ||||
| 
 | ||||
|     (define (pattern-validator pat)      ; pattern -> validator | ||||
|       (letrec | ||||
|           ((pattern-validator | ||||
|             (lambda (pat form) | ||||
|               (cond | ||||
|                ((constant? pat) | ||||
|                 #`(equal? '#,pat #,form)) | ||||
|                ((literal? pat) | ||||
|                 #`(and (variable? #,form) (variable=? #'#,pat #,form))) | ||||
|                ((variable? pat) | ||||
|                 #t) | ||||
| 		     vars)))) | ||||
| 
 | ||||
| ;;; compile expand | ||||
|        (define (compile-expand ellipsis reserved template) | ||||
| 	 (letrec ((compile-expand-base | ||||
| 		   (lambda (template ellipsis-valid) | ||||
| 		     (cond ((member template reserved eq?) | ||||
| 			    (values (var->sym template) (list template))) | ||||
| 			   ((symbol? template) | ||||
| 			    (values `(rename ',template) '())) | ||||
| 			   ((pair? template) | ||||
| 			    (compile-expand-list template ellipsis-valid)) | ||||
| 			   ((vector? template) | ||||
| 			    (compile-expand-vector template ellipsis-valid)) | ||||
|                ((many? pat) | ||||
|                 (let ((head #`(drop-tail #,(length (cddr pat)) #,form)) | ||||
|                       (tail #`(take-tail #,(length (cddr pat)) #,form))) | ||||
|                   #`(and (list? #,form) | ||||
|                          (>= (length #,form) #,(length (cddr pat))) | ||||
|                          (every? (map (lambda (#,'it) #,(pattern-validator (car pat) 'it)) #,head)) | ||||
|                          #,(pattern-validator (cddr pat) tail)))) | ||||
|                ((pair? pat) | ||||
|                 #`(and (pair? #,form) | ||||
|                        #,(pattern-validator (car pat) #`(car #,form)) | ||||
|                        #,(pattern-validator (cdr pat) #`(cdr #,form)))) | ||||
|                (else | ||||
| 			    (values `',template '()))))) | ||||
|                 #f))))) | ||||
|         (pattern-validator pat 'it))) | ||||
| 
 | ||||
| 		  (compile-expand-list | ||||
| 		   (lambda (template ellipsis-valid) | ||||
| 		     (let loop ((template template) | ||||
| 				(expands '()) | ||||
| 				(vars '())) | ||||
| 		       (cond ;; (... hoge) | ||||
| 			((and ellipsis-valid | ||||
| 			      (pair? template) | ||||
| 			      (compare (car template) ellipsis)) | ||||
| 			 (if (and (pair? (cdr template)) (null? (cddr template))) | ||||
| 			     (compile-expand-base (cadr template) #f) | ||||
| 			     (values '(,_syntax-error "invalid template") '()))) | ||||
| 			;; hoge | ||||
| 			((not (pair? template)) | ||||
| 			 (let-values (((expand1 vars1) | ||||
| 				       (compile-expand-base template ellipsis-valid))) | ||||
| 			   (values | ||||
|                              `(,_quasiquote (,@(reverse expands) . (,_unquote ,expand1))) | ||||
|                              (append vars vars1)))) | ||||
| 			;; (a ... rest syms) | ||||
| 			((and ellipsis-valid | ||||
| 			      (pair? (cdr template)) | ||||
| 			      (compare (cadr template) ellipsis)) | ||||
| 			 (let-values (((expand1 vars1) | ||||
| 				       (compile-expand-base (car template) ellipsis-valid))) | ||||
| 			   (loop (cddr template) | ||||
| 				 (cons | ||||
| 				  `(,_unquote-splicing | ||||
| 				    (,_map (,_lambda ,(map var->sym vars1) ,expand1) | ||||
| 					   ,@(map (lambda (v) (var->sym (push-var v))) vars1))) | ||||
| 				  expands) | ||||
| 				 (append vars (map push-var vars1))))) | ||||
| 			(else | ||||
| 			 (let-values (((expand1 vars1) | ||||
| 				       (compile-expand-base (car template) ellipsis-valid))) | ||||
| 			   (loop (cdr template) | ||||
| 				 (cons | ||||
| 				  `(,_unquote ,expand1) | ||||
| 				  expands) | ||||
| 				 (append vars vars1)))))))) | ||||
|     (define (pattern-variables pat)       ; pattern -> (freevar) | ||||
|       (cond | ||||
|        ((constant? pat) | ||||
|         '()) | ||||
|        ((literal? pat) | ||||
|         '()) | ||||
|        ((variable? pat) | ||||
|         `(,pat)) | ||||
|        ((many? pat) | ||||
|         (append (pattern-variables (car pat)) | ||||
|                 (pattern-variables (cddr pat)))) | ||||
|        ((pair? pat) | ||||
|         (append (pattern-variables (car pat)) | ||||
|                 (pattern-variables (cdr pat)))))) | ||||
| 
 | ||||
| 		  (compile-expand-vector | ||||
| 		   (lambda (template ellipsis-valid) | ||||
| 		     (let-values (((expand1 vars1) | ||||
| 				   (compile-expand-base (vector->list template) ellipsis-valid))) | ||||
| 		       (values | ||||
|                          `(,_list->vector ,expand1) | ||||
|                          vars1))))) | ||||
|     (define (pattern-levels pat)          ; pattern -> ((var * int)) | ||||
|       (cond | ||||
|        ((constant? pat) | ||||
|         '()) | ||||
|        ((literal? pat) | ||||
|         '()) | ||||
|        ((variable? pat) | ||||
|         `((,pat . 0))) | ||||
|        ((many? pat) | ||||
|         (append (map-values succ (pattern-levels (car pat))) | ||||
|                 (pattern-levels (cddr pat)))) | ||||
|        ((pair? pat) | ||||
|         (append (pattern-levels (car pat)) | ||||
|                 (pattern-levels (cdr pat)))))) | ||||
| 
 | ||||
| 	   (compile-expand-base template ellipsis))) | ||||
|     (define (pattern-selectors pat)       ; pattern -> ((var * selector)) | ||||
|       (letrec | ||||
|           ((pattern-selectors | ||||
|             (lambda (pat form) | ||||
|               (cond | ||||
|                ((constant? pat) | ||||
|                 '()) | ||||
|                ((literal? pat) | ||||
|                 '()) | ||||
|                ((variable? pat) | ||||
|                 `((,pat . ,form))) | ||||
|                ((many? pat) | ||||
|                 (let ((head #`(drop-tail #,(length (cddr pat)) #,form)) | ||||
|                       (tail #`(take-tail #,(length (cddr pat)) #,form))) | ||||
|                   (let ((envs (pattern-selectors (car pat) 'it))) | ||||
|                     (append | ||||
|                      (map-values (lambda (s) #`(map (lambda (#,'it) #,s) #,head)) envs) | ||||
|                      (pattern-selectors (cddr pat) tail))))) | ||||
|                ((pair? pat) | ||||
|                 (append (pattern-selectors (car pat) #`(car #,form)) | ||||
|                         (pattern-selectors (cdr pat) #`(cdr #,form)))))))) | ||||
|         (pattern-selectors pat 'it))) | ||||
| 
 | ||||
|        (define (check-vars vars-pattern vars-template) | ||||
| 	 ;;fixme | ||||
| 	 #t) | ||||
|     (define (template-representation pat levels selectors) | ||||
|       (cond | ||||
|        ((constant? pat) | ||||
|         pat) | ||||
|        ((variable? pat) | ||||
|         (let ((it (assq pat levels))) | ||||
|           (if it | ||||
|               (if (= 0 (cdr it)) | ||||
|                   (cdr (assq pat selectors)) | ||||
|                   (error "unmatched pattern variable level" pat)) | ||||
|               #`(#,'rename '#,pat)))) | ||||
|        ((many? pat) | ||||
|         (letrec* | ||||
|             ((inner-pat | ||||
|               (car pat)) | ||||
|              (inner-levels | ||||
|               (map (lambda (s) `(,(car s) . ,(pred (cdr s)))) levels)) | ||||
|              (inner-freevars | ||||
|               (filter (lambda (v) (assq v levels)) (pattern-variables inner-pat))) | ||||
|              (inner-vars | ||||
|               ;; select only vars declared with ellipsis | ||||
|               (filter (lambda (v) (> (cdr (assq v levels)) 0)) inner-freevars)) | ||||
|              (inner-tmps | ||||
|               (map (lambda (v) #'it) inner-vars)) | ||||
|              (inner-selectors | ||||
|               ;; first env '(map cons ...)' shadows second env 'selectors' | ||||
|               (append (map cons inner-vars inner-tmps) selectors)) | ||||
|              (inner-rep | ||||
|               (template-representation inner-pat inner-levels inner-selectors)) | ||||
|              (sorted-selectors | ||||
|               (map (lambda (v) (assq v selectors)) inner-vars)) | ||||
|              (list-of-selectors | ||||
|               ;; ((a . xs) (b . ys) (c . zs)) -> (xs ys zs) | ||||
|               (map cdr sorted-selectors))) | ||||
|           (let ((rep1 #`(map (lambda #,inner-tmps #,inner-rep) #,@list-of-selectors)) | ||||
|                 (rep2 (template-representation (cddr pat) levels selectors))) | ||||
|             #`(append #,rep1 #,rep2)))) | ||||
|        ((pair? pat) | ||||
|         #`(cons #,(template-representation (car pat) levels selectors) | ||||
|                 #,(template-representation (cdr pat) levels selectors))))) | ||||
| 
 | ||||
|        (define (compile-rule ellipsis literals rule) | ||||
| 	 (let ((pattern (car rule)) | ||||
| 	       (template (cadr rule))) | ||||
| 	   (let*-values (((match vars-match) | ||||
| 			  (compile-match ellipsis literals pattern)) | ||||
| 			 ((expand vars-expand) | ||||
| 			  (compile-expand ellipsis (flatten vars-match) template))) | ||||
| 	     (if (check-vars vars-match vars-expand) | ||||
| 		 (list vars-match match expand) | ||||
| 		 'mismatch)))) | ||||
|     (define (compile-rule pattern template) | ||||
|       (let ((levels | ||||
|              (pattern-levels pattern)) | ||||
|             (selectors | ||||
|              (pattern-selectors pattern))) | ||||
|         (template-representation template levels selectors))) | ||||
| 
 | ||||
|        (define (expand-clauses clauses rename) | ||||
| 	 (cond ((null? clauses) | ||||
| 		`(,_quote (syntax-error "no matching pattern"))) | ||||
| 	       ((compare (car clauses) 'mismatch) | ||||
| 		`(,_syntax-error "invalid rule")) | ||||
| 	       (else | ||||
| 		(let ((vars (list-ref (car clauses) 0)) | ||||
| 		      (match (list-ref (car clauses) 1)) | ||||
| 		      (expand (list-ref (car clauses) 2))) | ||||
| 		  `(,_let ,(map (lambda (v) (list (var->sym v) '())) vars) | ||||
| 			  (,_let ((result (,_escape (,_lambda (exit) ,match)))) | ||||
| 				 (,_if result | ||||
| 				       ,expand | ||||
| 				       ,(expand-clauses (cdr clauses) rename)))))))) | ||||
|     (define (compile-rules rules) | ||||
|       (if (null? rules) | ||||
|           #`(error "unmatch") | ||||
|           (let ((pattern (car (car rules))) | ||||
|                 (template (cadr (car rules)))) | ||||
|             #`(if #,(pattern-validator pattern) | ||||
|                   #,(compile-rule pattern template) | ||||
|                   #,(compile-rules (cdr rules)))))) | ||||
| 
 | ||||
|        (define (normalize-form form) | ||||
| 	 (if (and (list? form) (>= (length form) 2)) | ||||
| 	     (let ((ellipsis '...) | ||||
| 		   (literals (cadr form)) | ||||
| 		   (rules (cddr form))) | ||||
|     (define (compile rules) | ||||
|       #`(call-with-current-environment | ||||
|          (lambda (env) | ||||
|            (letrec | ||||
|                ((#,'rename (let ((reg (make-register))) | ||||
|                              (lambda (x) | ||||
|                                (if (undefined? (reg x)) | ||||
|                                    (let ((id (make-identifier x env))) | ||||
|                                      (reg x id) | ||||
|                                      id) | ||||
|                                    (reg x)))))) | ||||
|              (lambda #,'it | ||||
|                #,(compile-rules rules)))))) | ||||
| 
 | ||||
| 	       (when (symbol? literals) | ||||
|                  (set! ellipsis literals) | ||||
|                  (set! literals (car rules)) | ||||
|                  (set! rules (cdr rules))) | ||||
|     (let ((rules (map-keys cdr rules))) ; TODO: check pattern head is a variable | ||||
|       (compile rules))) | ||||
| 
 | ||||
| 	       (if (and (symbol? ellipsis) | ||||
| 			(list? literals) | ||||
| 			(every? symbol? literals) | ||||
| 			(list? rules) | ||||
| 			(every? (lambda (l) (and (list? l) (= (length l) 2))) rules)) | ||||
| 		   (if (member ellipsis literals compare) | ||||
| 		       `(syntax-rules #f ,literals ,@rules) | ||||
| 		       `(syntax-rules ,ellipsis ,literals ,@rules)) | ||||
| 		   #f)) | ||||
| 	     #f)) | ||||
|   (define-syntax (syntax-rules . args) | ||||
|     (if (list? (car args)) | ||||
|         #`(syntax-rules ... #,@args) | ||||
|         (let ((ellipsis (car args)) | ||||
|               (literals (car (cdr args))) | ||||
|               (rules    (cdr (cdr args)))) | ||||
|           (compile ellipsis literals rules)))) | ||||
| 
 | ||||
|        (let ((form (normalize-form form))) | ||||
| 	 (if form | ||||
| 	     (let ((ellipsis (list-ref form 1)) | ||||
| 		   (literals (list-ref form 2)) | ||||
| 		   (rules (list-tail form 3))) | ||||
| 	       (let ((clauses (map (lambda (rule) (compile-rule ellipsis literals rule)) | ||||
| 				   rules))) | ||||
| 		 `(,_er-macro-transformer | ||||
| 		   (,_lambda (expr rename cmp) | ||||
| 			     ,(expand-clauses clauses r))))) | ||||
| 
 | ||||
| 	     `(,_syntax-error "malformed syntax-rules")))))) | ||||
| 
 | ||||
|   (export syntax-rules | ||||
|           _ | ||||
|  |  | |||
|  | @ -460,9 +460,9 @@ | |||
|   (syntax-rules () | ||||
|     ((be-like-begin name) | ||||
|      (define-syntax name | ||||
|        (syntax-rules () | ||||
|          ((name expr (... ...)) | ||||
|           (begin expr (... ...)))))))) | ||||
|        (syntax-rules ::: () | ||||
|          ((name expr :::) | ||||
|           (begin expr :::))))))) | ||||
| (be-like-begin sequence) | ||||
| (test 4 (sequence 1 2 3 4)) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Yuichi Nishiwaki
						Yuichi Nishiwaki