2 /* Interpreter for the Kernel programming language*/
4 /*_ . Credits and License */
6 Copyright (C) 2010,2011 Tom Breton (Tehom)
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "klink-private.h"
29 #define snprintf _snprintf
48 # define stricmp strcasecmp
52 /* Used for documentation purposes, to signal functions in 'interface' */
60 stricmp (const char *s1
, const char *s2
)
76 #endif /* __APPLE__ */
92 /*_ . Configuration */
94 #define banner "Klink 0.0\n"
97 # define prompt "klink> "
101 # define InitFile "init.krn"
104 /*_ , Internal declarations */
106 /*_ , Name-mangling */
107 #define KEY(C_NAME) _k_key_##C_NAME
108 #define DESTR_NAME(C_NAME) _k_destructure_##C_NAME
109 #define OPER(C_NAME) _k_oper_##C_NAME
110 #define APPLICATIVE(C_NAME) _k_appl_##C_NAME
111 #define CHAIN_NAME(C_NAME) _k_chain_##C_NAME
112 #define CHKARRAY(C_NAME) _k_chkvec_##C_NAME
114 /*_ , For forward declarations of combiners */
115 #define FORWARD_DECL_CFUNC(LINKAGE,SUFFIX,C_NAME) \
116 LINKAGE KERNEL_FUN_SIG_##SUFFIX (C_NAME); \
117 kt_boxed_cfunc OPER(C_NAME)
119 #define FORWARD_DECL_PRED(LINKAGE,C_NAME) \
120 FORWARD_DECL_CFUNC(LINKAGE,b00a1,C_NAME)
122 #define FORWARD_DECL_T_PRED(LINKAGE,C_NAME) \
123 LINKAGE kt_boxed_T OPER(C_NAME)
125 #define FORWARD_DECL_CHAIN(LINKAGE,C_NAME) \
126 LINKAGE kt_boxed_vector OPER(C_NAME)
128 #define FORWARD_DECL_APPLICATIVE(LINKAGE,SUFFIX,C_NAME) \
129 FORWARD_DECL_CFUNC(LINKAGE,SUFFIX,C_NAME); \
130 kt_boxed_encap APPLICATIVE(C_NAME); \
134 /* No noun/number agreement for WITH_1_ARGS because I prefer name
136 #define WITH_1_ARGS(A1) \
138 #define WITH_2_ARGS(A1,A2) \
139 WITH_1_ARGS(A1), A2 = arg2
140 #define WITH_3_ARGS(A1,A2,A3) \
141 WITH_2_ARGS(A1,A2), A3 = arg3
142 #define WITH_4_ARGS(A1,A2,A3,A4) \
143 WITH_3_ARGS(A1,A2,A3), A4 = arg4
144 #define WITH_5_ARGS(A1,A2,A3,A4,A5) \
145 WITH_4_ARGS(A1,A2,A3,A4), A5 = arg5
146 /*_ , WITH_REPORTER */
147 #define WITH_REPORTER(SC) \
148 sc_or_null _err_reporter = (SC)
149 /*_ , Defining sub-T types */
150 #define DEF_VEC(T_ENUM, NAME, ARRAY_NAME) \
151 kt_boxed_vector NAME = \
155 sizeof(ARRAY_NAME)/sizeof(ARRAY_NAME[0]), \
160 /*_ , Checking type */
161 /*_ . Certain destructurers and type checks */
162 #define K_ANY REF_OPER(is_any)
163 #define K_NO_TYPE REF_KEY(K_TYCH_NO_TYPE)
164 #define K_ANY_SINGLETON REF_OBJ(_K_any_singleton)
166 /*_ . Internal: Arrays to be in typechecks and destructurers */
167 /* Elements of this array should not call Kernel - should be T_NO_K */
168 /* $$IMPROVE ME Check that when registering combiners */
169 #define SIG_CHKARRAY(C_NAME) pko CHKARRAY(C_NAME)[]
170 /*_ . Boxed destructurers */
171 #define REF_DESTR(C_NAME) REF_OBJ(DESTR_NAME(C_NAME))
172 #define DEF_DESTR(NAME,ARRAY_NAME) \
173 DEF_VEC(T_DESTRUCTURE | T_IMMUTABLE | T_NO_K, NAME, ARRAY_NAME)
175 #define DEF_SIMPLE_DESTR(C_NAME) \
176 DEF_DESTR(DESTR_NAME(C_NAME), CHKARRAY(C_NAME))
181 /* Awkward because we both declare stuff and assign stuff. */
182 #define ALLOC_BOX(NAME,T_ENUM,BOXTYPE) \
183 typedef BOXTYPE _TT; \
184 _TT * NAME = GC_MALLOC(sizeof(_TT)); \
187 /* ALLOC_BOX_PRESUME defines the following:
188 pbox - a pointer to the box
189 pdata - a pointer to the box's contents
191 #define ALLOC_BOX_PRESUME(TYPE,T_ENUM) \
193 ALLOC_BOX(pbox,T_ENUM,BOX_OF(TYPE)); \
194 pdata = &(pbox)->data
198 #define WITH_BOX_TYPE(NAME,P) \
199 _kt_tag * NAME = &((kt_boxed_any *)(P))->type;
202 /* This could mostly be an inlined function, but it wouldn't know
204 #define WITH_UNBOXED_RAW(P,NAME,TYPE,BOXTYPE) \
207 typedef BOXTYPE _TT; \
208 _TT * _pbox = (_TT *)(P); \
209 NAME = &_pbox->data; \
212 /*_ , Entry points */
213 #define WITH_UNBOXED_UNSAFE(NAME,TYPE,P) \
214 WITH_UNBOXED_RAW(P,NAME,TYPE,BOX_OF(TYPE))
217 /* WITH_PSYC_UNBOXED defines the following:
218 pdata - a pointer to the box's contents
220 #define WITH_PSYC_UNBOXED(TYPE,P,T_ENUM,SC) \
221 assert_type(SC,(P),T_ENUM); \
222 WITH_UNBOXED_UNSAFE(pdata,TYPE,P)
226 #define REF_KEY(NAME) REF_OBJ(KEY(NAME))
228 #define BOX_OF_VOID(NAME) \
229 kt_boxed_void KEY(NAME) = { T_KEY | T_IMMUTABLE }; \
230 pko NAME = REF_KEY(NAME)
233 /* All operatives use this, regardless whether they are cfuncs,
235 #define REF_OPER(C_NAME) REF_OBJ(OPER(C_NAME))
238 #define DEF_CFUNC_RAW(NAME,SUFFIX,C_NAME,DESTR,XTRA_FLAGS) \
239 RGSTR(all-builtins,"C-" #C_NAME, REF_OBJ (NAME)) \
240 kt_boxed_cfunc NAME = \
241 { T_CFUNC | T_IMMUTABLE | XTRA_FLAGS, \
242 {{C_NAME}, klink_ftype_##SUFFIX, DESTR, 0}};
244 #define DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME, DESTR,XTRA_FLAGS) \
245 DEF_CFUNC_RAW(OPER(C_NAME),SUFFIX,C_NAME, DESTR,XTRA_FLAGS)
247 #define DEF_CFUNC(SUFFIX,C_NAME,DESTR,XTRA_FLAGS) \
248 KERNEL_FUN_SIG_##SUFFIX(C_NAME); \
249 DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME,DESTR,XTRA_FLAGS); \
250 KERNEL_FUN_SIG_##SUFFIX(C_NAME)
252 #define DEF_SIMPLE_CFUNC(SUFFIX,C_NAME,XTRA_FLAGS) \
253 DEF_SIMPLE_DESTR(C_NAME); \
254 KERNEL_FUN_SIG_##SUFFIX(C_NAME); \
255 DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME,REF_DESTR(C_NAME),XTRA_FLAGS); \
256 KERNEL_FUN_SIG_##SUFFIX(C_NAME)
258 /*_ . Applicatives */
259 #define REF_APPL(C_NAME) REF_OBJ(APPLICATIVE(C_NAME))
261 #define DEF_BOXED_APPLICATIVE(C_NAME,FF) \
262 kt_boxed_encap APPLICATIVE (C_NAME) = \
263 { T_ENCAP | T_IMMUTABLE, \
264 {REF_KEY(K_APPLICATIVE), FF}};
266 #define DEF_APPLICATIVE_W_DESTR(SUFFIX,C_NAME,DESTR,XTRA_FLAGS,RG,K_NAME) \
267 RGSTR(RG,K_NAME, REF_APPL(C_NAME)) \
268 KERNEL_FUN_SIG_##SUFFIX(C_NAME); \
269 DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME,DESTR,XTRA_FLAGS); \
270 DEF_BOXED_APPLICATIVE(C_NAME, REF_OPER (C_NAME)); \
271 KERNEL_FUN_SIG_##SUFFIX(C_NAME)
273 #define DEF_SIMPLE_APPLICATIVE(SUFFIX,C_NAME,XTRA_FLAGS,RG,K_NAME) \
274 RGSTR(RG,K_NAME, REF_APPL(C_NAME)) \
275 DEF_SIMPLE_DESTR(C_NAME); \
276 KERNEL_FUN_SIG_##SUFFIX(C_NAME); \
277 DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME,REF_DESTR(C_NAME),XTRA_FLAGS); \
278 DEF_BOXED_APPLICATIVE(C_NAME, REF_OPER (C_NAME)); \
279 KERNEL_FUN_SIG_##SUFFIX(C_NAME)
281 /*_ . Abbreviations for predicates */
282 /* The underlying C function takes the whole value as its sole arg.
283 Above that, in init.krn an applicative wrapper applies it over a
284 list, using `every?'.
286 #define DEF_SIMPLE_PRED(C_NAME,XTRA_FLAGS,RG,K_NAME) \
287 RGSTR(RG,K_NAME, REF_OPER(C_NAME)) \
288 DEF_CFUNC(b00a1,C_NAME,K_ANY_SINGLETON,XTRA_FLAGS)
290 /* The cfunc is there just to be exported for C use. */
291 #define DEF_T_PRED(C_NAME,T_ENUM,RG,K_NAME) \
292 RGSTR(RG,K_NAME, REF_OPER(C_NAME)) \
293 kt_boxed_T OPER(C_NAME) = \
294 { T_TYPEP | T_IMMUTABLE | T_NO_K, {T_ENUM}}; \
295 int C_NAME(pko p) { return is_type(p,T_ENUM); }
298 /*_ . Curried Functions */
300 #define DEF_BOXED_CURRIED(CURRY_NAME,DECURRIER,ARGS,NEXT) \
301 RGSTR(all-builtins,"C-" #CURRY_NAME, REF_OBJ (CURRY_NAME)) \
302 kt_boxed_curried CURRY_NAME = \
303 { T_CURRIED | T_IMMUTABLE, \
304 {DECURRIER, ARGS, NEXT, 0}};
306 #define DEF_BOXED_PAIR(C_NAME,CAR,CDR) \
307 boxed_vec2 C_NAME = \
308 { T_PAIR | T_IMMUTABLE, {CAR, CDR, }}
311 #define DEF_LISTSTAR2 DEF_BOXED_PAIR
313 #define DEF_LISTSTAR3(C_NAME,A1,A2,A3) \
314 DEF_BOXED_PAIR(C_NAME##__1,A2,A3); \
315 DEF_BOXED_PAIR(C_NAME,A1,REF_OBJ(C_NAME##__1))
317 #define DEF_LIST1(C_NAME,A1) DEF_LISTSTAR2(C_NAME,A1, REF_KEY(K_NIL))
318 #define DEF_LIST2(C_NAME,A1,A2) DEF_LISTSTAR3(C_NAME,A1,A2,REF_KEY(K_NIL))
320 /*_ , Building objects in C */
321 #define ANON_OBJ( TYPE, X ) \
322 (((BOX_OF( TYPE )[]) { X })[0])
324 /* Middle is the same as ANON_OBJ but we can't just use that because
325 of expansion issues */
326 #define ANON_REF( TYPE, X ) \
327 REF_OBJ((((BOX_OF( TYPE )[]) { X })[0]))
329 #define PAIR_DEF( CAR, CDR ) \
330 { T_PAIR | T_IMMUTABLE, { CAR, CDR, }, }
332 #define ANON_PAIR( CAR, CDR ) \
333 ANON_REF(kt_vec2, PAIR_DEF( CAR, CDR ))
335 #define INT_DEF( N ) \
336 { T_NUMBER | T_IMMUTABLE, { 1, { N }, }, }
339 /*_ , Building lists in C */
340 /*_ . Anonymous lists */
342 #define ANON_LISTSTAR2(A1, A2) \
345 #define ANON_LISTSTAR3(A1, A2, A3) \
346 ANON_PAIR(A1, ANON_LISTSTAR2(A2, A3))
348 #define ANON_LISTSTAR4(A1, A2, A3, A4) \
349 ANON_PAIR(A1, ANON_LISTSTAR3(A2, A3, A4))
352 #define ANON_LIST1(A1) \
353 ANON_LISTSTAR2(A1, REF_KEY(K_NIL))
355 #define ANON_LIST2(A1, A2) \
356 ANON_PAIR(A1, ANON_LIST1(A2))
358 #define ANON_LIST3(A1, A2, A3) \
359 ANON_PAIR(A1, ANON_LIST2(A2, A3))
361 #define ANON_LIST4(A1, A2, A3, A4) \
362 ANON_PAIR(A1, ANON_LIST3(A2, A3, A4))
364 #define ANON_LIST5(A1, A2, A3, A4, A5) \
365 ANON_PAIR(A1, ANON_LIST4(A2, A3, A4, A5))
367 #define ANON_LIST6(A1, A2, A3, A4, A5, A6) \
368 ANON_PAIR(A1, ANON_LIST5(A2, A3, A4, A5, A6))
371 /*_ . Dynamic lists */
373 #define LISTSTAR2(A1, A2) \
375 #define LISTSTAR3(A1, A2, A3) \
376 cons (A1, LISTSTAR2(A2, A3))
377 #define LISTSTAR4(A1, A2, A3, A4) \
378 cons (A1, LISTSTAR3(A2, A3, A4))
384 #define LIST2(A1, A2) \
385 cons (A1, LIST1 (A2))
386 #define LIST3(A1, A2, A3) \
387 cons (A1, LIST2 (A2, A3))
388 #define LIST4(A1, A2, A3, A4) \
389 cons (A1, LIST3 (A2, A3, A4))
390 #define LIST5(A1, A2, A3, A4, A5) \
391 cons (A1, LIST4 (A2, A3, A4, A5))
392 #define LIST6(A1, A2, A3, A4, A5, A6) \
393 cons (A1, LIST5 (A2, A3, A4, A5, A6))
395 /*_ , Kernel continuation macros */
396 /*_ . W/o decurrying */
397 #define CONTIN_0_RAW(C_NAME,SC) \
398 klink_push_cont((SC), (C_NAME))
399 #define CONTIN_0(OPER_NAME,SC) \
400 klink_push_cont((SC), REF_OPER (OPER_NAME))
403 /* The use of REF_OPER requires these to be macros. */
405 #define CONTIN_1R(DECURRIER,C_NAME,SC,ARGS) \
406 klink_push_cont((SC), \
407 mk_curried(DECURRIER, ARGS, REF_OPER (C_NAME)))
409 #define CONTIN_2R(DECURRIER,C_NAME,SC,ARG1,ARG2) \
410 CONTIN_1R(DECURRIER,C_NAME,SC,cons(ARG1,ARG2))
412 #define CONTIN_3R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3) \
413 CONTIN_2R(DECURRIER,C_NAME,SC,ARG1,cons(ARG2,ARG3))
415 #define CONTIN_4R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4) \
416 CONTIN_3R(DECURRIER,C_NAME,SC,ARG1,ARG2,cons(ARG3,ARG4))
418 #define CONTIN_5R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,ARG5) \
419 CONTIN_4R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,cons(ARG4,ARG5))
421 #define CONTIN_6R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \
422 CONTIN_5R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,cons(ARG5,ARG6))
426 #define CONTIN_1(DECURRIER,C_NAME,SC,ARG1) \
427 CONTIN_2R(DECURRIER,C_NAME,SC,ARG1,K_NIL)
429 #define CONTIN_2(DECURRIER,C_NAME,SC,ARG1,ARG2) \
430 CONTIN_3R(DECURRIER,C_NAME,SC,ARG1,ARG2,K_NIL)
432 #define CONTIN_3(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3) \
433 CONTIN_4R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,K_NIL)
435 #define CONTIN_4(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4) \
436 CONTIN_5R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,K_NIL)
438 #define CONTIN_5(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,ARG5) \
439 CONTIN_6R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,ARG5,K_NIL)
442 #define kernel_bool(tf) ((tf) ? K_T : K_F)
444 /*_ , Control macros */
446 /* These never return because _klink_error_1 longjmps. */
447 /* $$IMPROVE ME If GCC is used or C99 is available, use __func__ as the function name. */
448 #define KERNEL_ERROR_1(sc,s, a) { _klink_error_1(sc,s,a); return 0; }
449 #define KERNEL_ERROR_0(sc,s) { _klink_error_1(sc,s,0); return 0; }
451 /*_ . Enumerations */
452 /*_ , The port types & flags */
467 typedef enum klink_token
485 /*_ , List metrics */
494 typedef int int4
[lm_max
];
496 /*_ . Struct definitions */
499 typedef BOX_OF (kt_cfunc
)
506 /* Object identity lets us compare instances. */
511 typedef BOX_OF (kt_encap
)
514 /*_ , Curried calls */
516 typedef pko (* decurrier_f
) (klink
* sc
, pko args
, pko value
);
521 decurrier_f decurrier
;
527 typedef BOX_OF (kt_curried
)
530 /*_ , T_typep calls */
537 typedef BOX_OF(typep_t
)
571 typedef BOX_OF(kt_vector
)
575 /*_ , Initialization */
576 static void klink_setup_error_cont (klink
* sc
);
577 static void klink_cycle_restarting (klink
* sc
, pko combiner
);
578 static int klink_cycle_no_restart (klink
* sc
, pko combiner
);
579 static void _klink_cycle (klink
* sc
);
582 /*_ , Error handling */
583 static void _klink_error_1 (klink
* sc
, const char *s
, pko a
);
584 /*_ . Stack control */
585 static int klink_pop_cont (klink
* sc
);
588 static pko
klink_call_cfunc (klink
* sc
, pko functor
, pko env
, pko args
);
589 FORWARD_DECL_CFUNC (static, ps0a2
, k_resume_to_cfunc
);
593 mk_load_ix (int x
, int y
);
598 mk_store (pko data
, int depth
);
602 call_curried(klink
* sc
, pko curried
, pko value
);
604 /*_ , Top level operatives */
605 FORWARD_DECL_APPLICATIVE(static,ps0a0
,kernel_repl
);
606 FORWARD_DECL_APPLICATIVE(static,ps0a0
,kernel_rel
);
607 FORWARD_DECL_APPLICATIVE(static,ps0a1
,kernel_internal_eval
);
610 static INLINE pko
oblist_find_by_name (const char *name
);
611 static pko
oblist_add_by_name (const char *name
);
614 static pko
mk_number (num n
);
616 static num
num_add (num a
, num b
);
617 static num
num_mul (num a
, num b
);
618 static num
num_div (num a
, num b
);
619 static num
num_intdiv (num a
, num b
);
620 static num
num_sub (num a
, num b
);
621 static num
num_rem (num a
, num b
);
622 static num
num_mod (num a
, num b
);
623 static int num_eq (num a
, num b
);
624 static int num_gt (num a
, num b
);
625 static int num_ge (num a
, num b
);
626 static int num_lt (num a
, num b
);
627 static int num_le (num a
, num b
);
630 static double round_per_R5RS (double x
);
633 /*_ , Lists and vectors */
634 FORWARD_DECL_PRED (extern, is_finite_list
);
635 FORWARD_DECL_PRED (extern, is_countable_list
);
636 extern int list_length (pko a
);
637 static pko
reverse (klink
* sc
, pko a
);
638 static pko
unsafe_v2reverse_in_place (pko term
, pko list
);
639 static pko
append (klink
* sc
, pko a
, pko b
);
641 static pko
alloc_basvector (int len
, _kt_tag t_enum
);
642 static void unsafe_basvector_fill (pko vec
, pko obj
);
644 static pko
mk_vector (int len
, pko fill
);
645 INTERFACE
static void fill_vector (pko vec
, pko obj
);
646 INTERFACE
static pko
vector_elem (pko vec
, int ielem
);
647 INTERFACE
static void set_vector_elem (pko vec
, int ielem
, pko a
);
648 INTERFACE
static int vector_len (pko vec
);
650 get_list_metrics_aux (pko a
, int4 presults
);
653 k_counted_map_car(klink
* sc
, int count
, pko list
, _kt_tag t_enum
);
655 k_counted_map_cdr(klink
* sc
, int count
, pko list
, _kt_tag t_enum
);
658 static pko
port_from_filename (const char *fn
, int prop
);
659 static pko
port_from_file (FILE *, int prop
);
660 static pko
port_from_string (char *start
, char *past_the_end
, int prop
);
661 static void port_close (pko p
, int flag
);
662 static void port_finalize_file(GC_PTR obj
, GC_PTR client_data
);
663 static port
*port_rep_from_filename (const char *fn
, int prop
);
664 static port
*port_rep_from_file (FILE *, int prop
);
665 static port
*port_rep_from_string (char *start
, char *past_the_end
, int prop
);
666 static void port_close_port (port
* pt
, int flag
);
667 INLINE port
* portvalue (pko p
);
668 static int basic_inchar (port
* pt
);
669 static int inchar (port
*pt
);
670 static void backchar (port
* pt
, int c
);
672 FORWARD_DECL_APPLICATIVE (extern,ps0a1
, mk_typecheck
);
673 FORWARD_DECL_APPLICATIVE (extern,ps0a1
, mk_destructurer
);
674 FORWARD_DECL_CFUNC (extern, ps0a4
, destructure_resume
);
675 FORWARD_DECL_PRED (extern, is_any
);
676 FORWARD_DECL_T_PRED (extern, is_environment
);
677 FORWARD_DECL_PRED (extern, is_integer
);
679 FORWARD_DECL_CFUNC (extern,ps0a2
,handle_promise_result
);
680 FORWARD_DECL_CFUNC (extern, ps0a1
, mk_promise_lazy
);
681 FORWARD_DECL_APPLICATIVE (extern, ps0a1
, force
);
682 /*_ , About encapsulation */
683 FORWARD_DECL_CFUNC (static,b00a2
, is_encap
);
684 FORWARD_DECL_CFUNC (static,p00a2
, mk_encap
);
685 FORWARD_DECL_CFUNC (static,ps0a2
, unencap
);
686 FORWARD_DECL_APPLICATIVE (extern,p00a0
, mk_encapsulation_type
);
688 /*_ , About combiners per se */
689 FORWARD_DECL_PRED(extern,is_combiner
);
690 /*_ , About operatives */
691 FORWARD_DECL_PRED(extern,is_operative
);
693 schedule_rv_list(klink
* sc
, pko list
);
695 /*_ , About applicatives */
697 FORWARD_DECL_PRED(extern,is_applicative
);
698 FORWARD_DECL_APPLICATIVE(extern,p00a1
,wrap
);
699 FORWARD_DECL_APPLICATIVE(extern,ps0a1
,unwrap
);
700 FORWARD_DECL_APPLICATIVE(extern,p00a1
,unwrap_all
);
702 /*_ , About currying */
707 static pko
dcrry_2A01VLL (klink
* sc
, pko args
, pko value
);
708 static pko
dcrry_3A01dotVLL (klink
* sc
, pko args
, pko value
);
709 static pko
dcrry_2CA01VLLA02 (klink
* sc
, pko args
, pko value
);
710 /* May not be needed */
711 static pko
dcrry_3A01A02VLL (klink
* sc
, pko args
, pko value
);
712 static pko
dcrry_2ALLVLL (klink
* sc
, pko args
, pko value
);
713 static pko
dcrry_2ALLV01 (klink
* sc
, pko args
, pko value
);
715 static pko
dcrry_NdotALL (klink
* sc
, pko args
, pko value
);
716 #define dcrry_1A01 dcrry_NdotALL
717 #define dcrry_1dotALL dcrry_NdotALL
718 #define dcrry_2dotALL dcrry_NdotALL
719 #define dcrry_3dotALL dcrry_NdotALL
720 #define dcrry_4dotALL dcrry_NdotALL
722 static pko
dcrry_1ALL (klink
* sc
, pko args
, pko value
);
724 static pko
dcrry_5ALLdotVLL (klink
* sc
, pko args
, pko value
);
725 #define dcrry_3ALLdotVLL dcrry_5ALLdotVLL
727 static pko
dcrry_NVLLdotALL (klink
* sc
, pko args
, pko value
);
728 #define dcrry_2VLLdotALL dcrry_NVLLdotALL
729 #define dcrry_3VLLdotALL dcrry_NVLLdotALL
730 #define dcrry_4VLLdotALL dcrry_NVLLdotALL
731 #define dcrry_5VLLdotALL dcrry_NVLLdotALL
733 static pko
dcrry_1VLL (klink
* sc
, pko args
, pko value
);
734 static pko
dcrry_NCVLLA01dotAX1 (klink
* sc
, pko args
, pko value
);
735 #define dcrry_2CVLLA01dotAX1 dcrry_NCVLLA01dotAX1
736 #define dcrry_3CVLLA01dotAX1 dcrry_NCVLLA01dotAX1
737 #define dcrry_4CVLLA01dotAX1 dcrry_NCVLLA01dotAX1
738 #define dcrry_5CVLLA01dotAX1 dcrry_NCVLLA01dotAX1
740 FORWARD_DECL_CFUNC(static,ps0a4
,values_pair
);
743 /*_ , Of Kernel evaluation */
744 /*_ . Public functions */
745 FORWARD_DECL_APPLICATIVE(extern,ps0a2
,kernel_eval
);
746 FORWARD_DECL_CFUNC (extern,ps0a3
, vau_1
);
747 /*_ . Other signatures */
748 FORWARD_DECL_APPLICATIVE(static,ps0a3
,kernel_eval_aux
);
749 FORWARD_DECL_APPLICATIVE(static,ps0a3
,kernel_mapeval
);
750 FORWARD_DECL_APPLICATIVE(static,ps0a3
, kernel_mapand_aux
);
751 FORWARD_DECL_APPLICATIVE(extern,ps0a2
, kernel_mapand
);
752 FORWARD_DECL_APPLICATIVE(static,ps0a5
,eval_vau
);
756 FORWARD_DECL_APPLICATIVE(static,ps0a0
,kernel_read_internal
);
757 FORWARD_DECL_CFUNC(extern,ps0a0
,kernel_read_sexp
);
758 FORWARD_DECL_CFUNC(static,ps0a2
,kernel_read_list
);
759 FORWARD_DECL_CFUNC(static,ps0a2
,kernel_treat_dotted_list
);
760 FORWARD_DECL_CFUNC(static,ps0a1
,kernel_treat_qquoted_vec
);
762 static INLINE
int is_one_of (char *s
, int c
);
763 static long binary_decode (const char *s
);
764 static char *readstr_upto (klink
* sc
, char *delim
);
765 static pko
readstrexp (klink
* sc
);
766 static INLINE
int skipspace (klink
* sc
);
767 static int token (klink
* sc
);
768 static pko
mk_atom (klink
* sc
, char *q
);
769 static pko
mk_sharp_const (char *name
);
772 /* $$IMPROVE ME These should mostly be just operatives. */
773 FORWARD_DECL_APPLICATIVE(static,ps0a2
,kernel_print_sexp
);
774 FORWARD_DECL_APPLICATIVE(static,ps0a3
,kernel_print_sexp_aux
);
775 FORWARD_DECL_APPLICATIVE(static,ps0a3
,kernel_print_list
);
776 FORWARD_DECL_APPLICATIVE(static,ps0a4
,kernel_print_vec_from
);
777 static kt_boxed_curried k_print_terminate_list
;
779 static void printslashstring (klink
* sc
, char *s
, int len
);
780 static void atom2str (klink
* sc
, pko l
, char **pp
, int *plen
);
781 static void printatom (klink
* sc
, pko l
);
783 /*_ , Stack & continuations */
784 /*_ . Continuations */
785 static pko
mk_continuation (_kt_spagstack d
);
786 static void klink_push_cont (klink
* sc
, pko combiner
);
788 klink_push_cont_aux (_kt_spagstack old_frame
, pko ff
, pko env
);
789 FORWARD_DECL_APPLICATIVE(extern,p00a1
,continuation_to_applicative
);
790 FORWARD_DECL_CFUNC(static,vs0a2
,invoke_continuation
);
791 FORWARD_DECL_CFUNC(static,ps0a2
,continue_abnormally
);
792 static _kt_spagstack special_dynxtnt
793 (_kt_spagstack outer
, _kt_spagstack prox_dest
, pko envir
);
797 /*_ . Dynamic bindings */
798 static void klink_push_dyn_binding (klink
* sc
, pko id
, pko value
);
799 static pko
klink_find_dyn_binding(klink
* sc
, pko id
);
801 struct stack_profiling
;
803 k_profiling_done_frame(klink
* sc
, struct stack_profiling
* profile
);
806 get_nth_arg( _kt_spagstack frame
, int n
);
808 push_arg (klink
* sc
, pko value
);
810 /*_ , Environment and defining */
811 FORWARD_DECL_CFUNC(static,vs0a3
,kernel_define_tree
);
812 FORWARD_DECL_CFUNC(extern,p00a3
,kernel_define
);
813 FORWARD_DECL_CFUNC(extern,ps0a2
,eval_define
);
814 FORWARD_DECL_CFUNC(extern,ps0a3
,set
);
815 FORWARD_DECL_CFUNC(static,ps0a4
,set_aux
);
817 static pko
find_slot_in_env (pko env
, pko sym
, int all
);
818 static INLINE pko
slot_value_in_env (pko slot
);
819 static INLINE
void set_slot_in_env (pko slot
, pko value
);
821 reverse_find_slot_in_env_aux (pko env
, pko value
);
822 /*_ . Standard environment */
823 FORWARD_DECL_CFUNC(extern,p00a0
, mk_std_environment
);
824 FORWARD_DECL_APPLICATIVE (extern,ps0a0
, get_current_environment
);
825 /*_ , Misc kernel functions */
827 FORWARD_DECL_CFUNC(extern,ps0a1
,arg1
);
828 FORWARD_DECL_APPLICATIVE(extern,ps0a1
,val2val
)
830 /*_ , Error functions */
831 FORWARD_DECL_CFUNC(static,ps0a1
,kernel_err
);
832 FORWARD_DECL_CFUNC(static,ps0a1
,kernel_err_x
);
834 /*_ , For DL if present */
836 FORWARD_DECL_APPLICATIVE(extern,ps0a1
,klink_load_ext
);
840 static pko
mk_symbol_obj (const char *name
);
843 static char *store_string (int len
, const char *str
, char fill
);
845 /*_ . Object declarations */
847 /* These objects are declared here because some macros use them, but
848 should not be directly used. */
849 /* $$IMPROVE ME Somehow hide these better without hiding it from the
850 applicative & destructure macros. */
851 kt_boxed_void
KEY(K_APPLICATIVE
);
852 kt_boxed_void
KEY(K_NIL
);
854 kt_boxed_vector _K_any_singleton
;
855 /*_ , Pointers to base environments */
856 static pko print_lookup_env
;
857 static pko all_builtins_env
;
858 static pko ground_env
;
859 static pko typecheck_env_syms
;
861 static pko print_lookup_unwraps
;
862 static pko print_lookup_to_xary
;
865 /*_ . Low-level treating T-types */
871 WITH_BOX_TYPE(ptype
,p
);
872 return *ptype
& T_MASKTYPE
;
877 is_type (pko p
, int T_index
)
879 return _get_type (p
) == T_index
;
881 /*_ . type_err_string */
883 type_err_string(_kt_tag t_enum
)
888 return "Must be a string";
890 return "Must be a number";
892 return "Must be a symbol";
894 return "Must be a pair";
896 return "Must be a character";
898 return "Must be a port";
900 return "Must be an encapsulation";
902 return "Must be a continuation";
904 return "Must be an environment";
906 return "Must be a recurrence table";
907 case T_RECUR_TRACKER
:
908 return "Must be a recurrence tracker";
910 return "Must be a destructure result";
912 /* Left out types that shouldn't be distinguished in Kernel. */
913 return "Error message for this type needs to be coded";
917 /* If sc is given, it's a assertion making a Kernel error, otherwise
918 it's a C assertion. */
920 assert_type (sc_or_null sc
, pko p
, _kt_tag t_enum
)
922 if(sc
&& (_get_type(p
) != (t_enum
)))
924 const char * err_msg
= type_err_string(t_enum
);
925 _klink_error_1(sc
,err_msg
,p
);
926 return; /* NOTREACHED */
929 { assert (_get_type(p
) == (t_enum
)); }
937 WITH_BOX_TYPE(ptype
,p
);
938 return *ptype
& T_IMMUTABLE
;
941 INTERFACE INLINE
void
944 WITH_BOX_TYPE(ptype
,p
);
945 *ptype
|= T_IMMUTABLE
;
948 /* If sc is given, it's a assertion making a Kernel error, otherwise
949 it's a C assertion. */
951 assert_mutable (sc_or_null sc
, pko p
)
953 WITH_BOX_TYPE(ptype
,p
);
954 if(sc
&& (*ptype
& T_IMMUTABLE
))
956 _klink_error_1(sc
,"Attempt to mutate immutable object",p
);
960 { assert(!(*ptype
& T_IMMUTABLE
)); }
963 #define DEBUG_assert_mutable assert_mutable
965 /*_ , No-call-Kernel */
969 WITH_BOX_TYPE(ptype
,p
);
970 return *ptype
& T_NO_K
;
973 SIG_CHKARRAY(eqp
) = { K_ANY
, K_ANY
, };
974 DEF_SIMPLE_APPLICATIVE(p00a2
,eqp
,T_NO_K
,ground
,"eq?")
977 return kernel_bool(a
== b
);
979 /*_ . Low-level object types */
980 /*_ , vec2 (Low lists) */
987 typedef BOX_OF(kt_vec2
) boxed_vec2
;
990 /* $$IMPROVE ME Disable this if DEBUG_LEVEL is low */
991 void assert_T_is_v2(_kt_tag t_enum
)
993 t_enum
&= T_MASKTYPE
;
996 || t_enum
== T_ENV_PAIR
997 || t_enum
== T_ENV_FRAME
998 || t_enum
== T_PROMISE
999 || t_enum
== T_DESTR_RESULT
1005 v2cons (_kt_tag t_enum
, pko a
, pko b
)
1007 ALLOC_BOX_PRESUME (kt_vec2
, t_enum
);
1008 pbox
->data
._car
= a
;
1009 pbox
->data
._cdr
= b
;
1010 return PTR2PKO(pbox
);
1013 /*_ . Unsafe operations (Typechecks can be disabled) */
1015 unsafe_v2car (pko p
)
1017 assert_T_is_v2(_get_type(p
));
1018 WITH_UNBOXED_UNSAFE(pdata
,kt_vec2
,p
);
1023 unsafe_v2cdr (pko p
)
1025 assert_T_is_v2(_get_type(p
));
1026 WITH_UNBOXED_UNSAFE(pdata
,kt_vec2
,p
);
1031 unsafe_v2set_car (pko p
, pko q
)
1033 assert_T_is_v2(_get_type(p
));
1034 DEBUG_assert_mutable(0,p
);
1035 WITH_UNBOXED_UNSAFE(pdata
,kt_vec2
,p
);
1041 unsafe_v2set_cdr (pko p
, pko q
)
1043 assert_T_is_v2(_get_type(p
));
1044 DEBUG_assert_mutable(0,p
);
1045 WITH_UNBOXED_UNSAFE(pdata
,kt_vec2
,p
);
1050 /*_ . Checked operations */
1052 v2car (sc_or_null err_reporter
, _kt_tag t_enum
, pko p
)
1054 assert_type(err_reporter
,p
,t_enum
);
1055 return unsafe_v2car(p
);
1059 v2cdr (sc_or_null err_reporter
, _kt_tag t_enum
, pko p
)
1061 assert_type(err_reporter
,p
,t_enum
);
1062 return unsafe_v2cdr(p
);
1066 v2set_car (sc_or_null err_reporter
, _kt_tag t_enum
, pko p
, pko q
)
1068 assert_type(err_reporter
,p
,t_enum
);
1069 assert_mutable(err_reporter
,p
);
1070 unsafe_v2set_car(p
,q
);
1075 v2set_cdr (sc_or_null err_reporter
, _kt_tag t_enum
, pko p
, pko q
)
1077 assert_type(err_reporter
,p
,t_enum
);
1078 assert_mutable(err_reporter
,p
);
1079 unsafe_v2set_cdr(p
,q
);
1083 /*_ . "Psychic" macros */
1084 #define WITH_V2(T_ENUM) \
1085 _kt_tag _t_enum = T_ENUM; \
1086 assert_T_is_v2(_t_enum)
1088 /* These expect WITH_REPORTER and WITH_V2 to be used in scope. */
1089 #define PSYC_v2cons(A,B) v2cons (_t_enum, (A), (B))
1090 #define PSYC_v2car(X) v2car (_err_reporter, _t_enum, (X))
1091 #define PSYC_v2cdr(X) v2cdr (_err_reporter, _t_enum, (X))
1092 #define PSYC_v2set_car(A,B) v2set_car (_err_reporter, _t_enum, (A), (B))
1093 #define PSYC_v2set_cdr(A,B) v2set_cdr (_err_reporter, _t_enum, (A), (B))
1095 /*_ . Container macros */
1097 /* This expects _EXPLORE_FUNC to be defined as a macro taking OBJ,
1098 inspecting it but not mutating it. */
1099 #define EXPLORE_v2(OBJ) \
1101 WITH_UNBOXED_UNSAFE(pdata,kt_vec2,OBJ); \
1102 _EXPLORE_FUNC(pdata->_car); \
1103 _EXPLORE_FUNC(pdata->_cdr); \
1106 /* #define _EXPLORE_FUNC(X) trace_tree_cycles(X, p_cycles_data) */
1108 /*_ . Low list operations */
1109 /*_ , v2list_star */
1110 pko
v2list_star(sc_or_null sc
, pko d
, _kt_tag t_enum
)
1115 pko cdr_d
= PSYC_v2cdr (d
);
1118 return PSYC_v2car (d
);
1120 p
= PSYC_v2cons (PSYC_v2car (d
), cdr_d
);
1123 while (PSYC_v2cdr (PSYC_v2cdr (p
)) != K_NIL
)
1125 pko cdr_p
= PSYC_v2cdr (p
);
1126 d
= PSYC_v2cons (PSYC_v2car (p
), cdr_p
);
1127 if (PSYC_v2cdr (cdr_p
) != K_NIL
)
1132 PSYC_v2set_cdr (p
, PSYC_v2car (PSYC_v2cdr (p
)));
1136 /*_ , reverse list -- produce new list */
1137 pko
v2reverse(pko a
, _kt_tag t_enum
)
1141 for (; is_type (a
, t_enum
); a
= unsafe_v2cdr (a
))
1143 p
= v2cons (t_enum
, unsafe_v2car (a
), p
);
1148 /*_ , reverse list -- in-place (Not typechecked) */
1149 /* last_cdr will be the tail of the resulting list. It is usually
1152 list is the list to be reversed. Caller guarantees that list is a
1153 proper list, each link being either some type of vec2 or K_NIL.
1156 unsafe_v2reverse_in_place (pko last_cdr
, pko list
)
1158 pko p
= list
, result
= last_cdr
;
1161 pko scratch
= unsafe_v2cdr (p
);
1162 unsafe_v2set_cdr (p
, result
);
1168 /*_ , append list -- produce new list */
1169 pko
v2append(sc_or_null err_reporter
, pko a
, pko b
, _kt_tag t_enum
)
1176 a
= v2reverse (a
, t_enum
);
1177 /* Correct even if b is nil or a non-list. */
1178 return unsafe_v2reverse_in_place(b
, a
);
1183 /*_ , basvectors (Low vectors) */
1185 /* Above so it can be visible to early typecheck declarations. */
1186 /*_ . Type assert */
1187 void assert_T_is_basvector(_kt_tag t_enum
)
1189 t_enum
&= T_MASKTYPE
;
1191 t_enum
== T_VECTOR
||
1192 t_enum
== T_TYPECHECK
||
1193 t_enum
== T_DESTRUCTURE
1198 /*_ , alloc_basvector */
1200 alloc_basvector (int len
, _kt_tag t_enum
)
1202 assert_T_is_basvector(t_enum
);
1203 ALLOC_BOX_PRESUME(kt_vector
, t_enum
);
1204 pbox
->data
.len
= len
;
1205 pbox
->data
.els
= (pko
*)GC_MALLOC ((sizeof (pko
) * len
));
1206 /* We don't fill this vector, we expect it to be filled later. */
1207 return PTR2PKO(pbox
);
1209 /*_ , mk_basvector_w_args */
1211 mk_basvector_w_args(klink
* sc
, pko args
, _kt_tag t_enum
)
1214 assert_T_is_basvector(t_enum
);
1216 get_list_metrics_aux(args
, metrics
);
1217 if (metrics
[lm_num_nils
] != 1)
1219 KERNEL_ERROR_1 (sc
, "mk_basvector_w_args: not a proper list:", args
);
1221 int len
= metrics
[lm_acyc_len
];
1222 pko vec
= alloc_basvector(len
, t_enum
);
1223 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1226 for (x
= args
, i
= 0; is_pair (x
); x
= cdr (x
), i
++)
1228 pdata
->els
[i
] = car (x
);
1232 /*_ , mk_filled_basvector */
1234 mk_filled_basvector(int len
, pko fill
, _kt_tag t_enum
)
1236 assert_T_is_basvector(t_enum
);
1237 pko vec
= alloc_basvector(len
, t_enum
);
1238 unsafe_basvector_fill (vec
, fill
);
1241 /*_ , mk_basvector_from_array */
1243 mk_basvector_from_array(int len
, pko
* array
, _kt_tag t_enum
)
1245 assert_T_is_basvector(t_enum
);
1246 pko vec
= alloc_basvector(len
, t_enum
);
1247 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1249 for (i
= 0; i
< len
; i
++)
1251 pdata
->els
[i
] = array
[i
];
1255 /*_ , mk_foresliced_basvector */
1257 mk_foresliced_basvector (pko vec
, int excess
, _kt_tag t_enum
)
1259 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1260 const int len
= pdata
->len
;
1261 assert (len
>= excess
);
1262 const int remnant_len
= len
- excess
;
1263 return mk_basvector_from_array (remnant_len
,
1264 pdata
->els
+ excess
,
1267 /*_ . Unsafe operations (Typechecks can be disabled) */
1268 /*_ , unsafe_basvector_fill */
1270 unsafe_basvector_fill (pko vec
, pko obj
)
1272 assert_T_is_basvector(_get_type(vec
));
1273 assert_mutable(0,vec
);
1274 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1277 const int num
= pdata
->len
;
1279 for (i
= 0; i
< num
; i
++)
1280 { pdata
->els
[i
] = obj
; }
1283 /*_ , basvector_len */
1285 basvector_len (pko vec
)
1287 assert_T_is_basvector(_get_type(vec
));
1288 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1292 /*_ , basvector_elem */
1294 basvector_elem (pko vec
, int ielem
)
1296 assert_T_is_basvector(_get_type(vec
));
1297 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1299 assert(ielem
< pdata
->len
);
1300 return pdata
->els
[ielem
];
1303 /*_ , basvector_set_elem */
1305 basvector_set_elem (pko vec
, int ielem
, pko a
)
1307 assert_T_is_basvector(_get_type(vec
));
1308 assert_mutable(0,vec
);
1309 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1311 assert(ielem
< pdata
->len
);
1312 pdata
->els
[ielem
] = a
;
1315 /*_ , basvector_fill_array */
1317 basvector_fill_array(pko vec
, int max_len
, pko
* array
)
1319 assert_T_is_basvector(_get_type(vec
));
1320 WITH_UNBOXED_UNSAFE (p_vec
, kt_vector
, vec
);
1321 int count
= p_vec
->len
;
1322 assert (count
<= max_len
);
1324 for (i
= 0; i
< count
; i
++)
1326 array
[i
] = p_vec
->els
[i
];
1330 /*_ . Checked operations */
1331 /*_ , Basic strings (Low strings) */
1332 /*_ . Struct kt_string */
1342 bastring_value (sc_or_null sc
, _kt_tag t_enum
, pko p
)
1344 WITH_PSYC_UNBOXED(kt_string
,p
, t_enum
, sc
);
1345 return pdata
->_svalue
;
1349 bastring_len (sc_or_null sc
, _kt_tag t_enum
, pko p
)
1351 WITH_PSYC_UNBOXED(kt_string
,p
, t_enum
, sc
);
1352 return pdata
->_length
;
1358 store_string (int len_str
, const char *str
, char fill
)
1362 q
= (char *) GC_MALLOC_ATOMIC (len_str
+ 1);
1365 snprintf (q
, len_str
+ 1, "%s", str
);
1369 memset (q
, fill
, len_str
);
1376 mk_bastring (_kt_tag t_enum
, const char *str
, int len
, char fill
)
1378 ALLOC_BOX_PRESUME (kt_string
, t_enum
);
1379 pbox
->data
._svalue
= store_string(len
, str
, fill
);
1380 pbox
->data
._length
= len
;
1381 return PTR2PKO(pbox
);
1384 /*_ . Type assert */
1385 void assert_T_is_bastring(_kt_tag t_enum
)
1387 t_enum
&= T_MASKTYPE
;
1389 t_enum
== T_STRING
||
1390 t_enum
== T_SYMBOL
);
1393 /*_ . Individual object types */
1399 DEF_SIMPLE_PRED(is_bool
,T_NO_K
,ground
, "boolean?/o1")
1402 return (p
== K_T
) || (p
== K_F
);
1405 SIG_CHKARRAY(not) = { REF_OPER(is_bool
), };
1406 DEF_SIMPLE_APPLICATIVE(p00a1
,not,T_NO_K
,ground
, "not?")
1409 if(p
== K_T
) { return K_F
; }
1410 if(p
== K_F
) { return K_T
; }
1411 errx(6, "not: Argument must be boolean");
1415 /*_ . Number constants */
1417 /* We would use these for "folding" operations like cumulative addition. */
1418 static num num_zero
= { 1, {0}, };
1419 static num num_one
= { 1, {1}, };
1422 #define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
1423 #define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
1425 /*_ . Making them */
1428 mk_integer (long num
)
1430 ALLOC_BOX_PRESUME (struct num
, T_NUMBER
);
1431 pbox
->data
.value
.ivalue
= num
;
1432 pbox
->data
.is_fixnum
= 1;
1433 return PTR2PKO(pbox
);
1439 ALLOC_BOX_PRESUME (num
, T_NUMBER
);
1440 pbox
->data
.value
.rvalue
= n
;
1441 pbox
->data
.is_fixnum
= 0;
1442 return PTR2PKO(pbox
);
1450 return mk_integer (n
.value
.ivalue
);
1454 return mk_real (n
.value
.rvalue
);
1458 /*_ . Checking them */
1459 static int is_zero_double (double x
);
1462 num_is_integer (pko p
)
1464 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1465 return (pdata
->is_fixnum
);
1468 DEF_T_PRED (is_number
,T_NUMBER
,ground
,"number?/o1");
1470 DEF_SIMPLE_PRED (is_posint
,T_NO_K
,ground
,"posint?/o1")
1473 return is_integer (p
) && ivalue (p
) >= 0;
1476 /* $$IMPROVE ME later Integer and real should be separate T_ types. */
1477 DEF_SIMPLE_PRED (is_integer
,T_NO_K
,ground
, "integer?/o1")
1480 if(!is_number (p
)) { return 0; }
1481 WITH_UNBOXED_UNSAFE(pdata
,num
,p
);
1482 return (pdata
->is_fixnum
);
1485 DEF_SIMPLE_PRED (is_real
,T_NO_K
,ground
, "real?/o1")
1488 if(!is_number (p
)) { return 0; }
1489 WITH_UNBOXED_UNSAFE(pdata
,num
,p
);
1490 return (!pdata
->is_fixnum
);
1492 DEF_SIMPLE_PRED (is_zero
,T_NO_K
,ground
, "zero?/o1")
1495 /* Behavior on non-numbers wasn't specified so I'm assuming the
1496 predicate just fails. */
1497 if(!is_number (p
)) { return 0; }
1498 WITH_UNBOXED_UNSAFE(pdata
,num
,p
);
1499 if(pdata
->is_fixnum
)
1501 return (ivalue (p
) == 0);
1505 return is_zero_double(rvalue(p
));
1508 /* $$WRITE ME positive? negative? odd? even? */
1509 /*_ . Getting their values */
1513 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1520 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1521 return (num_is_integer (p
) ? pdata
->value
.ivalue
: (long) pdata
->
1528 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1529 return (!num_is_integer (p
)
1530 ? pdata
->value
.rvalue
: (double) pdata
->value
.ivalue
);
1534 set_ivalue (pko p
, long i
)
1536 assert_mutable(0,p
);
1537 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1538 assert (num_is_integer (p
));
1539 pdata
->value
.ivalue
= i
;
1544 add_to_ivalue (pko p
, long i
)
1546 assert_mutable(0,p
);
1547 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1548 assert (num_is_integer (p
));
1549 pdata
->value
.ivalue
+= i
;
1553 /*_ . Operating on numbers */
1555 num_add (num a
, num b
)
1558 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1561 ret
.value
.ivalue
= a
.value
.ivalue
+ b
.value
.ivalue
;
1565 ret
.value
.rvalue
= num_rvalue (a
) + num_rvalue (b
);
1571 num_mul (num a
, num b
)
1574 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1577 ret
.value
.ivalue
= a
.value
.ivalue
* b
.value
.ivalue
;
1581 ret
.value
.rvalue
= num_rvalue (a
) * num_rvalue (b
);
1587 num_div (num a
, num b
)
1590 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
1591 && a
.value
.ivalue
% b
.value
.ivalue
== 0;
1594 ret
.value
.ivalue
= a
.value
.ivalue
/ b
.value
.ivalue
;
1598 ret
.value
.rvalue
= num_rvalue (a
) / num_rvalue (b
);
1604 num_intdiv (num a
, num b
)
1607 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1610 ret
.value
.ivalue
= a
.value
.ivalue
/ b
.value
.ivalue
;
1614 ret
.value
.rvalue
= num_rvalue (a
) / num_rvalue (b
);
1620 num_sub (num a
, num b
)
1623 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1626 ret
.value
.ivalue
= a
.value
.ivalue
- b
.value
.ivalue
;
1630 ret
.value
.rvalue
= num_rvalue (a
) - num_rvalue (b
);
1636 num_rem (num a
, num b
)
1640 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1641 e1
= num_ivalue (a
);
1642 e2
= num_ivalue (b
);
1644 /* modulo should have same sign as second operand */
1659 ret
.value
.ivalue
= res
;
1664 num_mod (num a
, num b
)
1668 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1669 e1
= num_ivalue (a
);
1670 e2
= num_ivalue (b
);
1673 { /* modulo should have same sign as second operand */
1684 ret
.value
.ivalue
= res
;
1689 num_eq (num a
, num b
)
1692 int is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1695 ret
= a
.value
.ivalue
== b
.value
.ivalue
;
1699 ret
= num_rvalue (a
) == num_rvalue (b
);
1706 num_gt (num a
, num b
)
1709 int is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1712 ret
= a
.value
.ivalue
> b
.value
.ivalue
;
1716 ret
= num_rvalue (a
) > num_rvalue (b
);
1722 num_ge (num a
, num b
)
1724 return !num_lt (a
, b
);
1728 num_lt (num a
, num b
)
1731 int is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1734 ret
= a
.value
.ivalue
< b
.value
.ivalue
;
1738 ret
= num_rvalue (a
) < num_rvalue (b
);
1744 num_le (num a
, num b
)
1746 return !num_gt (a
, b
);
1750 /* Round to nearest. Round to even if midway */
1752 round_per_R5RS (double x
)
1754 double fl
= floor (x
);
1755 double ce
= ceil (x
);
1756 double dfl
= x
- fl
;
1757 double dce
= ce
- x
;
1768 if (fmod (fl
, 2.0) == 0.0)
1769 { /* I imagine this holds */
1781 is_zero_double (double x
)
1783 return x
< DBL_MIN
&& x
> -DBL_MIN
;
1787 binary_decode (const char *s
)
1791 while (*s
!= 0 && (*s
== '1' || *s
== '0'))
1801 /* "Psychically" defines a and b. */
1802 #define WITH_PSYC_AB_ARGS(A_TYPE,B_TYPE) \
1803 WITH_UNBOXED_UNSAFE(a,A_TYPE,arg1); \
1804 WITH_UNBOXED_UNSAFE(b,B_TYPE,arg2)
1808 /*_ . Binary operations */
1809 SIG_CHKARRAY(num_binop
) = { REF_OPER(is_number
), REF_OPER(is_number
), };
1810 DEF_SIMPLE_DESTR(num_binop
);
1812 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_add
,REF_DESTR(num_binop
),0,ground
, "add")
1814 WITH_PSYC_AB_ARGS(num
,num
);
1815 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1816 *pdata
= num_add (*a
, *b
);
1817 return PTR2PKO(pbox
);
1820 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_sub
,REF_DESTR(num_binop
),0,ground
, "sub")
1822 WITH_PSYC_AB_ARGS(num
,num
);
1823 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1824 *pdata
= num_sub (*a
, *b
);
1825 return PTR2PKO(pbox
);
1828 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_mul
,REF_DESTR(num_binop
),0,ground
, "mul")
1830 WITH_PSYC_AB_ARGS(num
,num
);
1831 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1832 *pdata
= num_mul (*a
, *b
);
1833 return PTR2PKO(pbox
);
1836 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_div
,REF_DESTR(num_binop
),0,ground
, "div")
1838 WITH_PSYC_AB_ARGS(num
,num
);
1839 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1840 *pdata
= num_div (*a
, *b
);
1841 return PTR2PKO(pbox
);
1844 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_mod
,REF_DESTR(num_binop
),0,ground
, "mod")
1846 WITH_PSYC_AB_ARGS(num
,num
);
1847 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1848 *pdata
= num_mod (*a
, *b
);
1849 return PTR2PKO(pbox
);
1851 /*_ . Binary predicates */
1852 DEF_APPLICATIVE_W_DESTR(bs0a2
,k_gt
,REF_DESTR(num_binop
),0,ground
, ">?/2")
1854 WITH_PSYC_AB_ARGS(num
,num
);
1855 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1856 return num_gt (*a
, *b
);
1859 DEF_APPLICATIVE_W_DESTR(bs0a2
,k_eq
,REF_DESTR(num_binop
),0,simple
, "equal?/2-num-num")
1861 WITH_PSYC_AB_ARGS(num
,num
);
1862 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1863 return num_eq (*a
, *b
);
1868 DEF_T_PRED (is_character
,T_CHARACTER
,ground
, "character?/o1");
1873 WITH_PSYC_UNBOXED(long,p
,T_CHARACTER
,0);
1878 mk_character (int c
)
1880 ALLOC_BOX_PRESUME (long, T_CHARACTER
);
1882 return PTR2PKO(pbox
);
1885 /*_ . Classifying characters */
1886 #if USE_CHAR_CLASSIFIERS
1890 return isascii (c
) && isalpha (c
);
1896 return isascii (c
) && isdigit (c
);
1902 return isascii (c
) && isspace (c
);
1908 return isascii (c
) && isupper (c
);
1914 return isascii (c
) && islower (c
);
1917 /*_ . Character names */
1919 static const char *charnames
[32] = {
1955 is_ascii_name (const char *name
, int *pc
)
1958 for (i
= 0; i
< 32; i
++)
1960 if (stricmp (name
, charnames
[i
]) == 0)
1966 if (stricmp (name
, "del") == 0)
1976 /*_ , Void objects */
1978 DEF_T_PRED (is_key
, T_KEY
,no
,"");
1982 BOX_OF_VOID (K_NIL
);
1983 BOX_OF_VOID (K_EOF
);
1984 BOX_OF_VOID (K_INERT
);
1985 BOX_OF_VOID (K_IGNORE
);
1986 /*_ . "Secret" objects for built-in keyed dynamic bindings */
1987 BOX_OF_VOID (K_PRINT_FLAG
);
1988 BOX_OF_VOID (K_TRACING
);
1989 BOX_OF_VOID (K_INPORT
);
1990 BOX_OF_VOID (K_OUTPORT
);
1991 BOX_OF_VOID (K_NEST_DEPTH
);
1992 /*_ . Keys for typecheck */
1993 BOX_OF_VOID (K_TYCH_DOT
);
1994 BOX_OF_VOID (K_TYCH_REPEAT
);
1995 BOX_OF_VOID (K_TYCH_OPTIONAL
);
1996 BOX_OF_VOID (K_TYCH_IMP_REPEAT
);
1997 BOX_OF_VOID (K_TYCH_NO_TYPE
);
1999 /*_ . Making them dynamically */
2000 DEF_CFUNC(p00a0
, mk_void
, K_NO_TYPE
,T_NO_K
)
2002 ALLOC_BOX(pbox
,T_KEY
,kt_boxed_void
);
2003 return PTR2PKO(pbox
);
2006 DEF_SIMPLE_PRED(is_null
,T_NO_K
,ground
, "null?/o1")
2011 DEF_SIMPLE_PRED(is_inert
,T_NO_K
,ground
, "inert?/o1")
2014 return p
== K_INERT
;
2016 DEF_SIMPLE_PRED(is_ignore
,T_NO_K
,ground
, "ignore?/o1")
2019 return p
== K_IGNORE
;
2023 /*_ , Typecheck & destructure objects */
2025 /* _car is vector component, _cdr is list component. */
2026 typedef kt_vec2 kt_destr_result
;
2027 /* $$OBSOLETE UNUSED */
2030 pko remaining
; /* Remaining arglist. 0 if we're to
2031 use the value as entire object */
2032 pko typespec
; /* Would prefer to can splice vector */
2033 int index
; /* Index into vector, if typespec is a
2036 /*_ . Enumeration */
2044 DEF_T_PRED (is_destr_result
, T_DESTR_RESULT
, no
, "");
2045 /*_ . Building them */
2046 /*_ , can_be_trivpred */
2047 /* Return true if the object can be used as a trivial predicate: An
2048 xary operative that does not call Kernel and returns a boolean as
2050 DEF_SIMPLE_PRED(can_be_trivpred
,T_NO_K
,unsafe
,"trivpred?/o1")
2053 if(!no_call_k(p
)) { return 0; }
2054 switch(_get_type(p
))
2058 WITH_UNBOXED_UNSAFE(pdata
,kt_cfunc
,p
);
2061 case klink_ftype_b00a1
:
2083 /*_ , k_to_trivpred */
2084 /* Convert a unary or nary function to xary. If not possible, return
2086 /* $$OBSOLESCENT Only used in print lookup, which will change */
2088 k_to_trivpred(pko p
)
2090 if(is_applicative(p
))
2091 { p
= unwrap_all(p
); }
2093 if(can_be_trivpred(p
))
2098 /*_ , type-keys environment */
2099 RGSTR(type
-keys
, "cyclic-repeat", REF_KEY(K_TYCH_IMP_REPEAT
) )
2100 RGSTR(type
-keys
, "optional", REF_KEY(K_TYCH_OPTIONAL
) )
2101 RGSTR(type
-keys
, "repeat", REF_KEY(K_TYCH_REPEAT
) )
2102 RGSTR(type
-keys
, "dot", REF_KEY(K_TYCH_DOT
) )
2104 int any_k (kt_vector
* p_vec_guts
)
2107 for (i
= 0; i
< p_vec_guts
->len
; i
++)
2109 pko obj
= p_vec_guts
->els
[i
];
2110 WITH_BOX_TYPE(tag
,obj
);
2111 if (*tag
| ~(T_NO_K
)) { return 1; }
2117 DEF_APPLICATIVE_W_DESTR (ps0a1
, mk_typecheck
, REF_OPER(is_finite_list
),T_NO_K
,unsafe
, "listtype/N-trivpred")
2119 pko vec
= mk_basvector_w_args(sc
, arg1
, T_TYPECHECK
| T_IMMUTABLE
);
2120 /* If everything is T_NO_K, then give flag T_NO_K. */
2121 WITH_UNBOXED_UNSAFE (pdata
, kt_vector
, vec
);
2124 WITH_BOX_TYPE(tag
,vec
);
2129 /*_ , Destructurer */
2130 /* $$RETHINK ME Maybe add a count field to the struct. */
2131 DEF_APPLICATIVE_W_DESTR (ps0a1
, mk_destructurer
, REF_OPER(is_finite_list
),T_NO_K
,unsafe
, "destructure-list/N-trivpred")
2133 pko vec
= mk_basvector_w_args(sc
, arg1
, T_DESTRUCTURE
| T_IMMUTABLE
);
2134 /* If everything is T_NO_K, then give flag T_NO_K. */
2135 WITH_UNBOXED_UNSAFE (pdata
, kt_vector
, vec
);
2138 WITH_BOX_TYPE(tag
,vec
);
2143 /*_ , Destructurer Result state */
2144 /* Really a mixed vector/list */
2145 /*_ . mk_destr_result */
2148 (int len
, pko
* array
, pko more_vals
)
2150 pko vec
= mk_basvector_from_array(len
, array
, T_VECTOR
);
2151 return v2cons (T_DESTR_RESULT
, vec
, more_vals
);
2153 /*_ . mk_destr_result_add */
2156 (pko old
, int len
, pko
* array
)
2158 pko val_list
= unsafe_v2cdr (old
);
2160 for (i
= 0; i
< len
; i
++)
2162 val_list
= cons ( array
[i
], val_list
);
2164 return v2cons (T_DESTR_RESULT
,
2168 /*_ . destr_result_fill_array */
2170 destr_result_fill_array (pko dr
, int max_len
, pko
* array
)
2172 /* Assume errors are due to C code. */
2174 WITH_PSYC_UNBOXED (kt_destr_result
, dr
, T_DESTR_RESULT
, 0)
2176 basvector_len (pdata
->_car
);
2177 basvector_fill_array(pdata
->_car
, vec_len
, array
);
2178 /* We get args earliest lowest, so insert them in reverse order. */
2179 int list_len
= list_length (pdata
->_cdr
);
2180 int i
= vec_len
+ list_len
- 1;
2181 assert (i
< max_len
);
2183 for (args
= pdata
->_cdr
; args
!= K_NIL
; args
= cdr (args
), i
--)
2185 array
[i
] = car (args
);
2189 /*_ , destr_result_to_vec */
2190 SIG_CHKARRAY (destr_result_to_vec
) =
2192 REF_OPER (is_destr_result
),
2195 DEF_SIMPLE_CFUNC (p00a1
, destr_result_to_vec
, T_NO_K
)
2197 WITH_1_ARGS (destr_result
);
2198 WITH_UNBOXED_UNSAFE (p_destr_result
, kt_destr_result
, destr_result
);
2200 basvector_len (p_destr_result
->_car
) +
2201 list_length (p_destr_result
->_cdr
);
2202 pko vec
= mk_vector (len
, K_NIL
);
2203 WITH_UNBOXED_UNSAFE (p_vec
, kt_vector
, vec
);
2204 destr_result_fill_array (destr_result
, len
, p_vec
->els
);
2208 /*_ . Particular typechecks */
2209 /*_ , Any singleton */
2210 pko _K_ARRAY_any_singleton
[] = { K_ANY
, };
2211 DEF_DESTR(_K_any_singleton
,_K_ARRAY_any_singleton
);
2212 /*_ , Typespec itself */
2213 #define K_TY_TYPESPEC K_ANY
2214 /*_ , Destructure spec itself */
2215 #define K_TY_DESTRSPEC K_ANY
2216 /*_ , Top type (Always succeeds) */
2217 RGSTR(ground
, "true/o1", REF_OPER(is_any
))
2218 DEF_CFUNC(b00a1
,is_any
,K_ANY_SINGLETON
,T_NO_K
)
2221 /* Not entirely redundant; Used internally to check scheduled returns. */
2222 DEF_CFUNC(b00a1
,is_true
,K_ANY_SINGLETON
,T_NO_K
)
2228 /*_ . Internal signatures */
2231 (klink
*sc
, pko argobject
, pko
* ar_typespec
, int count
, int style
);
2233 where_typemiss_repeat
2234 (klink
*sc
, pko argobject
, pko
* ar_typespec
, int count
, int style
);
2236 static where_typemiss_do_spec
2237 (klink
* sc
, pko argobject
, pko
* ar_typespec
, int left
);
2239 /*_ . Typecheck operations */
2241 call_T_typecheck(pko T
, pko obj
)
2243 WITH_PSYC_UNBOXED(typep_t
,T
,T_TYPEP
,0);
2244 return is_type(obj
,pdata
->T_tag
);
2247 /* This is an optimization under-the-hood for running
2248 possibly-compound predicates. Ultimately it will not be exposed.
2249 Later it may have a Kernel "safe counterpart" that is optimized to
2252 It should not call anything that calls Kernel. All its
2253 "components" should be trivpreds (xary operatives that don't use
2254 eval loop), satisfying can_be_trivpred, generally specified
2256 /* We don't have a typecheck typecheck predicate yet, so accept
2257 anything for arg2. */
2258 SIG_CHKARRAY(typecheck
) = { K_ANY
, K_ANY
, };
2259 DEF_SIMPLE_APPLICATIVE (bs0a2
, typecheck
,T_NO_K
,unsafe
,"type?")
2261 WITH_2_ARGS(argobject
,typespec
);
2262 assert(no_call_k(typespec
));
2263 switch(_get_type(typespec
))
2267 WITH_UNBOXED_UNSAFE(pdata
,kt_cfunc
,typespec
);
2270 case klink_ftype_b00a1
:
2272 return pdata
->func
.f_b00a1(argobject
);
2275 errx(7, "typecheck: Object is not a typespec");
2278 break; /* NOTREACHED */
2280 return call_T_typecheck(typespec
, argobject
);
2281 case T_DESTRUCTURE
: /* Fallthru */
2284 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,typespec
);
2285 pko
* ar_typespec
= pdata
->els
;
2286 int left
= pdata
->len
;
2287 int saw_optional
= 0;
2288 for( ; left
; ar_typespec
++, left
--)
2290 pko tych
= *ar_typespec
;
2291 /**** Check for special keys ****/
2292 if(tych
== REF_KEY(K_TYCH_DOT
))
2296 KERNEL_ERROR_0 (sc
, "typecheck: After dot there must "
2297 "be exactly one typespec");
2300 { return typecheck(sc
, argobject
, ar_typespec
[1]); }
2302 if(tych
== REF_KEY(K_TYCH_OPTIONAL
))
2306 KERNEL_ERROR_0 (sc
, "typecheck: Can't have two optionals");
2314 if(tych
== REF_KEY(K_TYCH_REPEAT
))
2317 typecheck_repeat(sc
,argobject
,
2322 if(tych
== REF_KEY(K_TYCH_IMP_REPEAT
))
2325 typecheck_repeat(sc
,argobject
,
2331 /*** Manage stepping ***/
2332 if(!is_pair(argobject
))
2342 pko c
= pair_car(0,argobject
);
2343 argobject
= pair_cdr(0,argobject
);
2345 /*** Do the check ***/
2346 if (!typecheck(sc
, c
, tych
)) { return 0; }
2349 if(argobject
!= K_NIL
)
2356 errx(7, "typecheck: Object is not a typespec");
2358 return 0; /* NOTREACHED */
2360 /*_ , typecheck_repeat */
2363 (klink
*sc
, pko argobject
, pko
* ar_typespec
, int count
, int style
)
2366 get_list_metrics_aux(argobject
, metrics
);
2367 /* Dotted lists don't satisfy repeat */
2368 if(!metrics
[lm_num_nils
]) { return 0; }
2369 if(metrics
[lm_cyc_len
])
2371 /* STYLE may not allow cycles. */
2374 /* If there's a cycle and count doesn't fit into it exactly,
2375 call that a mismatch. */
2376 if(count
% metrics
[lm_cyc_len
])
2379 /* Check the car of each pair. */
2382 for(step
= 0, i
= 0;
2383 step
< metrics
[lm_num_pairs
];
2384 ++step
, ++i
, argobject
= pair_cdr(0,argobject
))
2386 if(i
== count
) { i
= 0; }
2387 assert(is_pair(argobject
));
2388 pko tych
= ar_typespec
[i
];
2389 pko c
= pair_car(0,argobject
);
2390 if (!typecheck(sc
, c
, tych
)) { return 0; }
2394 /*_ , where_typemiss */
2395 /* This parallels typecheck, but where typecheck returned a boolean,
2396 this returns an object indicating where the type failed to match. */
2397 SIG_CHKARRAY(where_typemiss
) = { K_ANY
, K_ANY
, };
2398 DEF_SIMPLE_APPLICATIVE (ps0a2
, where_typemiss
,T_NO_K
,unsafe
, "where-typemiss")
2400 /* Return a list indicating how TYPESPEC failed to match
2402 WITH_2_ARGS(argobject
,typespec
);
2403 assert(no_call_k(typespec
));
2404 switch(_get_type(typespec
))
2408 WITH_UNBOXED_UNSAFE(pdata
,kt_cfunc
,typespec
);
2411 case klink_ftype_b00a1
:
2413 if (pdata
->func
.f_b00a1(argobject
))
2418 { return LIST1(typespec
); }
2421 errx(7, "where_typemiss: Object is not a typespec");
2425 break; /* NOTREACHED */
2428 WITH_PSYC_UNBOXED(typep_t
,typespec
,T_TYPEP
,0);
2429 if (call_T_typecheck(typespec
, argobject
))
2432 { return LIST1(mk_string(type_err_string(pdata
->T_tag
))); }
2438 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,typespec
);
2439 return where_typemiss_do_spec(sc
, argobject
, pdata
->els
, pdata
->len
);
2443 errx(7,"where_typemiss: Object is not a typespec");
2446 return 0; /* NOTREACHED */
2448 /*_ , where_typemiss_do_spec */
2450 where_typemiss_do_spec
2451 (klink
* sc
, pko argobject
, pko
* ar_typespec
, int left
)
2453 int saw_optional
= 0;
2455 for( ; left
; ar_typespec
++, left
--)
2457 pko tych
= *ar_typespec
;
2458 /**** Check for special keys ****/
2459 if(tych
== REF_KEY(K_TYCH_DOT
))
2463 KERNEL_ERROR_0 (sc
, "where_typemiss: After dot there must "
2464 "be exactly one typespec");
2469 where_typemiss(sc
, argobject
, ar_typespec
[1]);
2473 LISTSTAR3(mk_integer(el_num
),
2481 if(tych
== REF_KEY(K_TYCH_OPTIONAL
))
2485 KERNEL_ERROR_0 (sc
, "where_typemiss: Can't have two optionals");
2493 if(tych
== REF_KEY(K_TYCH_REPEAT
))
2496 where_typemiss_repeat(sc
,argobject
,
2501 { return LISTSTAR3(mk_integer(el_num
),mk_symbol("repeat"), result
); }
2505 if(tych
== REF_KEY(K_TYCH_IMP_REPEAT
))
2508 where_typemiss_repeat(sc
,argobject
,
2513 { return LISTSTAR3(mk_integer(el_num
),mk_symbol("improper-repeat"),result
); }
2518 /*** Manage stepping ***/
2519 if(!is_pair(argobject
))
2523 return LIST2(mk_integer(el_num
), mk_symbol("too-few"));
2531 pko c
= pair_car(0,argobject
);
2532 argobject
= pair_cdr(0,argobject
);
2535 /*** Do the check ***/
2536 pko result
= where_typemiss(sc
, c
, tych
);
2538 { return LISTSTAR2(mk_integer(el_num
),result
); }
2541 if(argobject
!= K_NIL
)
2542 { return LIST2(mk_integer(el_num
), mk_symbol("too-many")); }
2546 /*_ , where_typemiss_repeat */
2548 where_typemiss_repeat
2549 (klink
*sc
, pko argobject
, pko
* ar_typespec
, int count
, int style
)
2552 get_list_metrics_aux(argobject
, metrics
);
2553 /* Dotted lists don't satisfy repeat */
2554 if(!metrics
[lm_num_nils
]) { return LIST1(mk_symbol("dotted")); }
2555 if(metrics
[lm_cyc_len
])
2557 /* STYLE may not allow cycles. */
2559 { return LIST1(mk_symbol("circular")); }
2560 /* If there's a cycle and count doesn't fit into it exactly,
2561 call that a mismatch. */
2562 if(count
% metrics
[lm_cyc_len
])
2563 { return LIST1(mk_symbol("misaligned-end")); }
2565 /* Check the car of each pair. */
2568 for(step
= 0, i
= 0;
2569 step
< metrics
[lm_num_pairs
];
2570 ++step
, ++i
, argobject
= pair_cdr(0,argobject
))
2572 if(i
== count
) { i
= 0; }
2573 assert(is_pair(argobject
));
2574 pko tych
= ar_typespec
[i
];
2575 pko c
= pair_car(0,argobject
);
2576 pko result
= where_typemiss(sc
, c
, tych
);
2578 { return LISTSTAR2(mk_integer(step
),result
); }
2583 /*_ . Destructuring operations */
2584 /*_ , destructure_by_bool */
2585 /* Just for calling back after a freeform predicate */
2586 SIG_CHKARRAY (destructure_by_bool
) =
2588 REF_OPER (is_destr_result
),
2592 DEF_SIMPLE_CFUNC (ps0a3
, destructure_by_bool
, 0)
2594 WITH_3_ARGS (destr_result
, argobject
, satisfied
);
2595 if (satisfied
== K_T
)
2598 mk_destr_result_add (destr_result
, 1, &argobject
);
2600 else if (satisfied
!= K_F
)
2602 KERNEL_ERROR_0 (sc
, "Predicate should return a boolean");
2606 KERNEL_ERROR_0 (sc
, "type mismatch on non-C predicate");
2610 /*_ , destructure_how_many */
2612 destructure_how_many (pko typespec
)
2614 switch (_get_type(typespec
))
2619 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,typespec
);
2620 pko
* ar_typespec
= pdata
->els
;
2621 int left
= pdata
->len
;
2622 for( ; left
; ar_typespec
++, left
--)
2624 pko tych
= *ar_typespec
;
2625 count
+= destructure_how_many (tych
);
2635 /*_ , destructure_make_ops */
2637 destructure_make_ops
2638 (pko argobject
, pko typespec
, int saw_optional
)
2641 /* Operations to run, in reverse order. */
2643 /* ^V= result-so-far */
2644 REF_OPER (destructure_resume
),
2645 /* V= (result-so-far argobject spec optional?) */
2646 mk_load (LIST4 (mk_load_ix (1, 0),
2649 kernel_bool (saw_optional
))),
2650 mk_store (K_ANY
, 1),
2651 /* V= forced-argobject */
2653 /* ^V= (argobject) */
2654 mk_load (LIST1 (argobject
)),
2656 /* ^V= result-so-far */
2659 /*_ , destructure_make_ops_to_bool */
2661 destructure_make_ops_to_bool
2662 (pko argobject
, pko op_on_argobject
)
2664 assert (is_combiner (op_on_argobject
));
2666 /* Operations to run, in reverse order. */
2668 /* ^V= result-so-far */
2669 REF_OPER (destructure_by_bool
),
2670 /* V= (result-so-far bool spec optional?) */
2671 mk_load (LIST3 (mk_load_ix (1, 0),
2673 mk_load_ix (0, 0))),
2674 mk_store (K_ANY
, 1),
2677 /* ^V= (argobject) */
2678 mk_load (LIST1 (argobject
)),
2680 /* ^V= result-so-far */
2683 /*_ , destructure */
2684 /* Callers: past_end should point into the same array as *outarray.
2685 It will indicate the maximum number number of elements we may
2686 write. The return value is the remainder of the outarray if
2687 successful, otherwise NULL.
2688 The meaning of extra_result depends on the return value:
2689 * On success, it's unused.
2690 * On destr_err, it's unused (but will later hold an error object)
2691 * On destr_must_call_k, it holds a list of operations.
2695 (klink
* sc
, pko argobject
, pko typespec
, pko
** outarray
,
2696 pko
* past_end
, pko
* extra_result
, int saw_optional
)
2698 if(*outarray
== past_end
)
2700 /* $$IMPROVE ME Treat this error like other mismatches */
2701 KERNEL_ERROR_0 (sc
, "destructure: past end of output array");
2703 if(_get_type(typespec
) == T_DESTRUCTURE
)
2705 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,typespec
);
2706 pko
* ar_typespec
= pdata
->els
;
2707 int left
= pdata
->len
;
2708 for( ; left
; ar_typespec
++, left
--)
2710 pko tych
= *ar_typespec
;
2712 /**** Check for special keys ****/
2713 if(tych
== REF_KEY(K_TYCH_DOT
))
2717 KERNEL_ERROR_0 (sc
, "destructure: After dot there must "
2718 "be exactly one typespec");
2721 { return destructure(sc
, argobject
,
2729 if(tych
== REF_KEY(K_TYCH_OPTIONAL
))
2733 KERNEL_ERROR_0 (sc
, "destructure: Can't have two optionals");
2741 /*** Manage stepping ***/
2742 if(!is_pair(argobject
))
2746 *outarray
[0] = K_INERT
;
2750 if (is_promise (argobject
))
2752 WITH_BOX_TYPE(tag
,typespec
);
2754 mk_foresliced_basvector (typespec
,
2758 destructure_make_ops (argobject
,
2761 return destr_must_call_k
;
2770 pko c
= pair_car(0,argobject
);
2771 argobject
= pair_cdr(0,argobject
);
2782 /* Success keeps exploring */
2785 /* Simple error just ends exploration */
2788 case destr_must_call_k
:
2790 WITH_BOX_TYPE(tag
,typespec
);
2791 /* $$IMPROVE ME If length = 0, this is just
2792 REF_OPER (is_null) */
2794 mk_foresliced_basvector (typespec
,
2795 pdata
->len
- left
+ 1,
2797 pko raw_oplist
= *extra_result
;
2800 REF_OPER (destructure_resume
),
2801 /* ^V= (result-so-far argobject spec
2803 mk_load (LIST4 (mk_load_ix (0, 0),
2806 kernel_bool (saw_optional
))),
2807 mk_store (K_ANY
, 1),
2808 /* ^V= result-so-far */
2813 errx (7, "Unrecognized enumeration");
2817 if(argobject
== K_NIL
)
2818 { return destr_success
; }
2819 else if (is_promise (argobject
))
2821 pko new_typespec
= REF_OPER (is_null
);
2823 destructure_make_ops (argobject
,
2826 return destr_must_call_k
;
2829 { return destr_err
; }
2832 else if (!no_call_k(typespec
))
2834 if (!is_combiner (typespec
))
2836 KERNEL_ERROR_0 (sc
, "spec must be a combiner");
2840 /* $$LIKELY BUG This somehow arranges to look at a typespec that
2841 is just a key, length 0 when interacting with nested. */
2843 destructure_make_ops_to_bool (argobject
, typespec
);
2844 return destr_must_call_k
;
2846 else if(typecheck(sc
, argobject
, typespec
))
2848 *outarray
[0] = argobject
;
2850 return destr_success
;
2852 else if (is_promise (argobject
))
2855 destructure_make_ops (argobject
,
2858 return destr_must_call_k
;
2865 /*_ , destructure_to_array */
2867 destructure_to_array
2869 pko obj
, /* Object to extract values from */
2870 pko type
, /* Type spec */
2871 pko
* array
, /* Array to be filled */
2872 size_t length
, /* Maximum length of that array */
2873 pko resume_op
, /* Combiner to schedule if we resume */
2874 pko resume_data
/* Extra data to the resume op */
2877 if (type
== K_NO_TYPE
)
2879 pko
* orig_array
= array
;
2880 pko extra_result
= 0;
2881 kt_destr_outcome outcome
=
2882 destructure (sc
, obj
, type
, &array
, array
+ length
, &extra_result
, 0);
2890 pko err
= where_typemiss (sc
, obj
, type
);
2891 extra_result
= err
? err
: mk_string("Couldn't find the typemiss");
2892 _klink_error_1 (sc
, "type mismatch:",
2893 LIST2(resume_data
, extra_result
));
2898 case destr_must_call_k
:
2900 /* Arrange for a resume. */
2901 int read_len
= array
- orig_array
;
2902 pko result_so_far
= mk_destr_result (read_len
, orig_array
, K_NIL
);
2903 assert (is_combiner (resume_op
));
2904 CONTIN_0_RAW (resume_op
, sc
);
2905 /* ^^^V= (final-destr_result . resume_data) */
2906 CONTIN_0_RAW (mk_load (LISTSTAR2 (mk_load_ix (0, 0),
2909 CONTIN_0_RAW (mk_store (K_ANY
, 1), sc
);
2910 /* ^^^V= final-destr_result */
2911 schedule_rv_list (sc
, extra_result
);
2912 /* ^^^V= current-destr_result */
2913 /* $$ENCAPSULATE ME */
2914 sc
->value
= result_so_far
;
2915 longjmp (sc
->pseudocontinuation
, 1);
2922 errx (7, "Unrecognized enumeration");
2926 /*_ , destructure_resume */
2927 SIG_CHKARRAY (destructure_resume
) =
2929 REF_OPER (is_destr_result
),
2934 DEF_SIMPLE_CFUNC (ps0a4
, destructure_resume
, 0)
2936 WITH_4_ARGS (destr_result
, argobject
, typespec
, opt_p
);
2937 const int max_args
= 5;
2938 pko arg_array
[max_args
];
2939 pko
* outarray
= arg_array
;
2941 kt_destr_outcome outcome
=
2946 arg_array
+ max_args
,
2953 int new_len
= outarray
- arg_array
;
2955 mk_destr_result_add (destr_result
, new_len
, arg_array
);
2959 KERNEL_ERROR_1 (sc
, "type mismatch:", extra_result
);
2962 case destr_must_call_k
:
2964 /* Arrange for another force+resume. This will feed whatever
2965 was there before. */
2966 int read_len
= outarray
- arg_array
;
2968 mk_destr_result_add (destr_result
,
2971 schedule_rv_list (sc
, extra_result
);
2972 return result_so_far
;
2977 errx (7, "Unrecognized enumeration");
2981 /*_ , do-destructure */
2982 /* We don't have a typecheck typecheck predicate yet, so accept
2983 anything for arg2. Really it can be what typecheck accepts or
2984 T_DESTRUCTURE, checked recursively. */
2985 SIG_CHKARRAY (do_destructure
) = { K_ANY
, K_ANY
, };
2986 DEF_SIMPLE_APPLICATIVE (ps0a2
, do_destructure
,T_NO_K
,unsafe
,"do-destructure")
2988 WITH_2_ARGS (argobject
,typespec
);
2989 int len
= destructure_how_many (typespec
);
2990 pko vec
= mk_vector (len
, K_NIL
);
2991 WITH_UNBOXED_UNSAFE (pdata
,kt_vector
,vec
);
2992 destructure_to_array
2998 REF_OPER (destr_result_to_vec
),
3004 /*_ , C functions as objects */
3007 typedef struct kt_opstore
3009 pko destr
; /* Often a T_DESTRUCTURE */
3014 DEF_T_PRED (is_cfunc
, T_CFUNC
,no
,"");
3017 /* For external use, if some code ever wants to make these objects
3019 /* $$MAKE ME SAFE Set type-check fields */
3021 mk_cfunc (const kt_cfunc
* f
)
3023 typedef kt_boxed_cfunc TT
;
3024 errx(4, "Don't use mk_cfunc yet")
3025 TT
*pbox
= GC_MALLOC (sizeof (TT
));
3026 pbox
->type
= T_CFUNC
;
3028 return PTR2PKO(pbox
);
3032 INLINE
const kt_cfunc
*
3033 get_cfunc_func (pko p
)
3035 WITH_PSYC_UNBOXED(kt_cfunc
,p
,T_CFUNC
,0)
3038 /*_ . cfunc_resume */
3040 /*_ . mk_cfunc_resume */
3042 mk_cfunc_resume (pko cfunc
)
3044 ALLOC_BOX_PRESUME (kt_cfunc
, T_CFUNC_RESUME
);
3045 pbox
->data
= *get_cfunc_func (cfunc
);
3046 return PTR2PKO(pbox
);
3049 /*_ . Curried functions */
3050 /*_ , About objects */
3053 { return is_type (p
, T_CURRIED
); }
3056 mk_curried (decurrier_f decurrier
, pko args
, pko next
)
3058 ALLOC_BOX(pbox
,T_CURRIED
,kt_boxed_curried
);
3059 pbox
->data
.decurrier
= decurrier
;
3060 pbox
->data
.args
= args
;
3061 pbox
->data
.next
= next
;
3062 pbox
->data
.argcheck
= 0;
3063 return PTR2PKO(pbox
);
3066 /*_ . call_curried */
3068 call_curried(klink
* sc
, pko curried
, pko value
)
3070 WITH_PSYC_UNBOXED(kt_curried
,curried
,T_CURRIED
,sc
);
3072 /* First schedule the next one if there is any */
3075 klink_push_cont(sc
, pdata
->next
);
3078 /* Then call the decurrier with the data field and the value,
3079 returning its result. */
3080 return pdata
->decurrier (sc
, pdata
->args
, value
);
3085 typedef kt_vector kt_chain
;
3089 #define SIG_CHAIN(C_NAME) pko CHAIN_NAME(C_NAME)[]
3090 #define DEF_CHAIN(NAME, ARRAY_NAME) \
3091 DEF_VEC(T_CHAIN | T_IMMUTABLE, NAME, ARRAY_NAME)
3093 #define DEF_SIMPLE_CHAIN(C_NAME) \
3094 RGSTR(all-builtins,"C-" #C_NAME, REF_OPER (C_NAME)) \
3095 DEF_CHAIN(OPER(C_NAME), CHAIN_NAME(C_NAME))
3100 schedule_chain(klink
* sc
, const kt_vector
* chain
)
3102 _kt_spagstack dump
= sc
->dump
;
3104 for(i
= chain
->len
- 1; i
>= 0; i
--)
3106 pko comb
= chain
->els
[i
];
3107 /* If frame_depth is unassigned, assign it. */
3108 if(_get_type(comb
) == T_STORE
)
3110 WITH_UNBOXED_UNSAFE( pdata
, kt_opstore
, comb
);
3111 if(pdata
->frame_depth
< 0)
3112 { pdata
->frame_depth
= chain
->len
- 1 - i
; }
3114 /* Push it as a combiner */
3115 dump
= klink_push_cont_aux(dump
, comb
, sc
->envir
);
3122 eval_chain( klink
* sc
, pko functor
, pko value
)
3124 WITH_PSYC_UNBOXED( kt_vector
, functor
, T_CHAIN
, 0 );
3125 schedule_chain( sc
, pdata
);
3128 /*_ . schedule_rv_list */
3130 schedule_rv_list (klink
* sc
, pko list
)
3133 _kt_spagstack dump
= sc
->dump
;
3134 for(; list
!= K_NIL
; list
= cdr (list
))
3136 pko comb
= car (list
);
3137 /* $$PUNT If frame_depth is unassigned, assign it. */
3139 /* Push it as a combiner */
3140 dump
= klink_push_cont_aux(dump
, comb
, sc
->envir
);
3147 mk_notrace( pko combiner
)
3149 ALLOC_BOX_PRESUME( pko
, T_NOTRACE
);
3151 return PTR2PKO(pbox
);
3156 notrace_comb( pko p
)
3158 WITH_PSYC_UNBOXED( pko
, p
, T_NOTRACE
, 0 );
3164 #define STORE_DEF(DATA) \
3165 { T_STORE | T_IMMUTABLE, { DATA, -1, }, }
3167 #define ANON_STORE(DATA) \
3168 ANON_REF (kt_opstore, STORE_DEF(DATA))
3170 /*_ . dynamically */
3172 mk_store (pko data
, int depth
)
3174 ALLOC_BOX_PRESUME(kt_opstore
, T_STORE
| T_IMMUTABLE
);
3175 pdata
->destr
= data
;
3176 pdata
->frame_depth
= depth
;
3177 return PTR2PKO(pbox
);
3182 typedef pko kt_opload
;
3186 #define LOAD_DEF( DATA ) \
3187 { T_LOAD | T_IMMUTABLE, DATA, }
3189 #define ANON_LOAD( DATA ) \
3190 ANON_REF( pko, LOAD_DEF( DATA ))
3192 #define ANON_LOAD_IX( X, Y ) \
3193 ANON_PAIR(ANON_REF(num, INT_DEF( X )), \
3194 ANON_REF(num, INT_DEF( Y )))
3195 /*_ . dynamically */
3198 mk_load_ix (int x
, int y
)
3200 return cons (mk_integer (x
), mk_integer (y
));
3206 ALLOC_BOX_PRESUME(kt_opload
, T_LOAD
| T_IMMUTABLE
);
3208 return PTR2PKO(pbox
);
3211 /*_ , pairs proper */
3213 DEF_T_PRED (is_pair
, T_PAIR
,ground
, "pair?/o1");
3216 SIG_CHKARRAY(Xcons
) = { K_ANY
, K_ANY
, };
3217 DEF_SIMPLE_DESTR(Xcons
);
3218 DEF_APPLICATIVE_W_DESTR(p00a2
,mk_pair
, REF_DESTR(Xcons
),T_NO_K
,ground
, "cons")
3224 DEF_APPLICATIVE_W_DESTR(p00a2
,mk_mutable_pair
, REF_DESTR(Xcons
),T_NO_K
,ground
, "mcons")
3227 return mcons (a
, b
);
3230 /*_ . Parts and operations */
3232 SIG_CHKARRAY(pair_cxr
) = { REF_OPER(is_pair
), };
3233 DEF_SIMPLE_DESTR(pair_cxr
);
3234 DEF_APPLICATIVE_W_DESTR(ps0a1
,pair_car
, REF_DESTR(pair_cxr
),T_NO_K
,ground
, "car")
3237 return v2car(sc
,T_PAIR
,p
);
3240 DEF_APPLICATIVE_W_DESTR(ps0a1
,pair_cdr
, REF_DESTR(pair_cxr
),T_NO_K
,ground
, "cdr")
3243 return v2cdr(sc
,T_PAIR
,p
);
3246 SIG_CHKARRAY(pair_set_cxr
) = { REF_OPER(is_pair
), K_ANY
, };
3247 DEF_SIMPLE_DESTR(pair_set_cxr
);
3248 DEF_APPLICATIVE_W_DESTR(ps0a2
,set_car
, REF_DESTR(pair_set_cxr
),T_NO_K
,ground
, "set-car!")
3251 v2set_car(sc
,T_PAIR
,p
,q
);
3255 DEF_APPLICATIVE_W_DESTR(ps0a2
,set_cdr
, REF_DESTR(pair_set_cxr
),T_NO_K
,ground
, "set-cdr!")
3258 v2set_cdr(sc
,T_PAIR
,p
,q
);
3265 DEF_T_PRED (is_string
, T_STRING
,ground
,"string?/o1");
3268 INTERFACE INLINE pko
3269 mk_string (const char *str
)
3271 return mk_bastring (T_STRING
, str
, strlen (str
), 0);
3274 INTERFACE INLINE pko
3275 mk_counted_string (const char *str
, int len
)
3277 return mk_bastring (T_STRING
, str
, len
, 0);
3280 INTERFACE INLINE pko
3281 mk_empty_string (int len
, char fill
)
3283 return mk_bastring (T_STRING
, 0, len
, fill
);
3285 /*_ . Create static */
3286 /* $$WRITE ME As for k_print_terminate_list macros */
3289 INTERFACE INLINE
char *
3290 string_value (pko p
)
3292 return bastring_value(0,T_STRING
,p
);
3295 INTERFACE INLINE
int
3298 return bastring_len(0,T_STRING
,p
);
3303 DEF_T_PRED(is_symbol
, T_SYMBOL
,ground
,"symbol?/o1");
3306 mk_symbol_obj (const char *name
)
3308 return mk_bastring (T_SYMBOL
| T_IMMUTABLE
, name
, strlen (name
), 0);
3311 /* We want symbol objects to be unique per name, so check an oblist of
3314 mk_symbol (const char *name
)
3316 /* first check oblist */
3317 pko x
= oblist_find_by_name (name
);
3324 x
= oblist_add_by_name (name
);
3328 /*_ . oblist implementation */
3329 /*_ , Global object */
3330 static pko oblist
= 0;
3331 /*_ , Oblist as hash table */
3332 #ifndef USE_OBJECT_LIST
3334 static int hash_fn (const char *key
, int table_size
);
3337 oblist_initial_value ()
3339 return mk_vector (461, K_NIL
);
3342 /* returns the new symbol */
3344 oblist_add_by_name (const char *name
)
3346 pko x
= mk_symbol_obj (name
);
3347 int location
= hash_fn (name
, vector_len (oblist
));
3348 set_vector_elem (oblist
, location
,
3349 cons (x
, vector_elem (oblist
, location
)));
3354 oblist_find_by_name (const char *name
)
3361 location
= hash_fn (name
, vector_len (oblist
));
3362 for (x
= vector_elem (oblist
, location
); x
!= K_NIL
; x
= cdr (x
))
3364 s
= symname (0,car (x
));
3365 /* case-insensitive, per R5RS section 2. */
3366 if (stricmp (name
, s
) == 0)
3375 oblist_all_symbols (void)
3379 pko ob_list
= K_NIL
;
3381 for (i
= 0; i
< vector_len (oblist
); i
++)
3383 for (x
= vector_elem (oblist
, i
); x
!= K_NIL
; x
= cdr (x
))
3385 ob_list
= mcons (x
, ob_list
);
3391 /*_ , Oblist as list */
3395 oblist_initial_value ()
3401 oblist_find_by_name (const char *name
)
3406 for (x
= oblist
; x
!= K_NIL
; x
= cdr (x
))
3408 s
= symname (0,car (x
));
3409 /* case-insensitive, per R5RS section 2. */
3410 if (stricmp (name
, s
) == 0)
3418 /* returns the new symbol */
3420 oblist_add_by_name (const char *name
)
3422 pko x
= mk_symbol_obj (name
);
3423 oblist
= cons (x
, oblist
);
3428 oblist_all_symbols (void)
3436 /*_ . Parts and operations */
3437 SIG_CHKARRAY(string_to_symbol
) = { REF_OPER(is_string
), };
3438 DEF_SIMPLE_APPLICATIVE(ps0a1
,string_to_symbol
,T_NO_K
,ground
, "string->symbol")
3440 return mk_symbol(string_value(arg1
));
3443 INTERFACE INLINE
char *
3444 symname (sc_or_null sc
, pko p
)
3446 return bastring_value (sc
,T_SYMBOL
, p
);
3453 DEF_T_PRED (is_vector
, T_VECTOR
,unsafe
,"vector?/o1");
3456 /*_ , mk_vector (T_ level) */
3457 INTERFACE
static pko
3458 mk_vector (int len
, pko fill
)
3459 { return mk_filled_basvector(len
, fill
, T_VECTOR
); }
3461 /*_ , k_mk_vector (K level) */
3462 /* $$RETHINK ME This may not be wanted. */
3463 SIG_CHKARRAY(k_mk_vector
) = { REF_OPER(is_integer
), REF_KEY(K_TYCH_OPTIONAL
), K_ANY
, };
3464 DEF_SIMPLE_APPLICATIVE (ps0a2
, k_mk_vector
,T_NO_K
,unsafe
,"make-vector")
3466 WITH_2_ARGS(k_len
, fill
);
3468 int len
= ivalue (k_len
);
3469 if (fill
== K_INERT
)
3471 return mk_vector (len
, fill
);
3475 /* K_ANY instead of REF_OPER(is_finite_list) because
3476 mk_basvector_w_args checks list-ness internally */
3477 DEF_APPLICATIVE_W_DESTR(ps0a1
, vector
, K_ANY
,T_NO_K
,unsafe
,"vector")
3480 return mk_basvector_w_args(sc
,p
,T_VECTOR
);
3483 /*_ . Operations (T_ level) */
3484 /*_ , fill_vector */
3486 INTERFACE
static void
3487 fill_vector (pko vec
, pko obj
)
3489 assert(_get_type(vec
) == T_VECTOR
);
3490 unsafe_basvector_fill(vec
,obj
);
3493 /*_ . Parts of vectors (T_ level) */
3495 INTERFACE
static int
3496 vector_len (pko vec
)
3498 assert(_get_type(vec
) == T_VECTOR
);
3499 return basvector_len(vec
);
3502 INTERFACE
static pko
3503 vector_elem (pko vec
, int ielem
)
3505 assert(_get_type(vec
) == T_VECTOR
);
3506 return basvector_elem(vec
, ielem
);
3509 INTERFACE
static void
3510 set_vector_elem (pko vec
, int ielem
, pko a
)
3512 assert(_get_type(vec
) == T_VECTOR
);
3513 basvector_set_elem(vec
, ielem
, a
);
3518 /* T_PROMISE is essentially a handle, pointing to a pair of either
3519 (expression env) or (value #f). We use #f, not nil, because nil is
3520 a possible environment. */
3524 RGSTR(ground
,"$lazy", REF_OPER(mk_promise_lazy
))
3525 DEF_CFUNC(ps0a1
, mk_promise_lazy
, K_ANY_SINGLETON
, T_NO_K
)
3528 pko guts
= mcons(p
, mcons(sc
->envir
, mk_continuation(sc
->dump
)));
3529 return v2cons (T_PROMISE
, guts
, K_NIL
);
3532 /* $$CHECK ME Is K_ANY correct? Or K_ANY_SINGLETON? */
3533 DEF_APPLICATIVE_W_DESTR(p00a1
,mk_promise_memo
,K_ANY
,T_NO_K
,ground
,"memoize")
3536 pko guts
= mcons(p
, K_F
);
3537 return v2cons (T_PROMISE
, guts
, K_NIL
);
3541 DEF_T_PRED (is_promise
,T_PROMISE
,ground
,"promise?/o1");
3543 /*_ , promise_schedule_eval */
3545 promise_schedule_eval(klink
* sc
, pko p
)
3548 pko guts
= unsafe_v2car(p
);
3549 pko env
= car(cdr(guts
));
3550 pko dynxtnt
= cdr(cdr(guts
));
3551 /* Arrange to eval the expression and pass the result to
3552 handle_promise_result */
3553 CONTIN_1R(dcrry_2ALLVLL
,handle_promise_result
,sc
,p
);
3554 /* $$ENCAP ME This deals with continuation guts, so should be
3555 encapped. As a special continuation-maker? */
3556 _kt_spagstack new_dump
=
3557 special_dynxtnt (cont_dump(dynxtnt
), sc
->dump
, env
);
3558 sc
->dump
= new_dump
;
3559 CONTIN_2(dcrry_2dotALL
, kernel_eval
, sc
, car(guts
), env
);
3562 /*_ , handle_promise_result */
3563 SIG_CHKARRAY(handle_promise_result
) = { REF_OPER(is_promise
), K_ANY
};
3564 DEF_SIMPLE_CFUNC(ps0a2
,handle_promise_result
,0)
3566 /* guts are only made by C code so if they're wrong it's a C
3569 WITH_2_ARGS(p
,value
);
3570 pko guts
= unsafe_v2car(p
);
3572 /* if p already has a result, return it */
3573 if(cdr(guts
) == K_F
)
3574 { return car(guts
); }
3575 /* If value is again a promise, set this promise's guts to that
3576 promise's guts and force it again, which will force both (This is
3577 why we need promises to be 2-layer) */
3578 else if(is_promise(value
))
3580 unsafe_v2set_car (p
, unsafe_v2car(value
));
3581 return promise_schedule_eval(sc
, p
);
3583 /* Otherwise set the value and return it. */
3586 unsafe_v2set_car (guts
, value
);
3587 unsafe_v2set_cdr (guts
, K_F
);
3593 DEF_APPLICATIVE_W_DESTR (ps0a1
, force
, K_ANY_SINGLETON
,T_NO_K
,ground
,"force")
3595 /* guts are only made by this C code here, so if they're wrong it's
3602 pko guts
= unsafe_v2car(p
);
3603 if(cdr(guts
) == K_F
)
3604 { return car(guts
); }
3606 { return promise_schedule_eval(sc
,p
); }
3612 /* $$IMPROVE ME Just directly contain the port structure. Possibly
3613 split port into several T_ types. */
3617 ALLOC_BOX_PRESUME (port
*, T_PORT
);
3619 return PTR2PKO(pbox
);
3623 port_rep_from_filename (const char *fn
, int prop
)
3628 if (prop
== (port_input
| port_output
))
3632 else if (prop
== port_output
)
3645 pt
= port_rep_from_file (f
, prop
);
3646 pt
->rep
.stdio
.closeit
= 1;
3650 { pt
->rep
.stdio
.filename
= store_string (strlen (fn
), fn
, 0); }
3652 pt
->rep
.stdio
.curr_line
= 0;
3658 port_from_filename (const char *fn
, int prop
)
3661 pt
= port_rep_from_filename (fn
, prop
);
3666 return mk_port (pt
);
3670 port_rep_from_file (FILE * f
, int prop
)
3673 pt
= (port
*) GC_MALLOC_ATOMIC (sizeof *pt
);
3678 /* Don't care what goes in these but GC really wants to provide it
3679 so here are dummy objects to put it in. */
3680 GC_finalization_proc ofn
;
3682 GC_register_finalizer(pt
, port_finalize_file
, 0, &ofn
, &ocd
);
3683 pt
->kind
= port_file
| prop
;
3684 pt
->rep
.stdio
.file
= f
;
3685 pt
->rep
.stdio
.closeit
= 0;
3690 port_from_file (FILE * f
, int prop
)
3693 pt
= port_rep_from_file (f
, prop
);
3698 return mk_port (pt
);
3702 port_rep_from_string (char *start
, char *past_the_end
, int prop
)
3705 pt
= (port
*) GC_MALLOC_ATOMIC (sizeof (port
));
3710 pt
->kind
= port_string
| prop
;
3711 pt
->rep
.string
.start
= start
;
3712 pt
->rep
.string
.curr
= start
;
3713 pt
->rep
.string
.past_the_end
= past_the_end
;
3718 port_from_string (char *start
, char *past_the_end
, int prop
)
3721 pt
= port_rep_from_string (start
, past_the_end
, prop
);
3726 return mk_port (pt
);
3729 #define BLOCK_SIZE 256
3732 realloc_port_string (port
* p
)
3734 /* $$IMPROVE ME Just use REALLOC. */
3735 char *start
= p
->rep
.string
.start
;
3736 size_t new_size
= p
->rep
.string
.past_the_end
- start
+ 1 + BLOCK_SIZE
;
3737 char *str
= GC_MALLOC_ATOMIC (new_size
);
3740 memset (str
, ' ', new_size
- 1);
3741 str
[new_size
- 1] = '\0';
3742 strcpy (str
, start
);
3743 p
->rep
.string
.start
= str
;
3744 p
->rep
.string
.past_the_end
= str
+ new_size
- 1;
3745 p
->rep
.string
.curr
-= start
- str
;
3756 port_rep_from_scratch (void)
3760 pt
= (port
*) GC_MALLOC_ATOMIC (sizeof (port
));
3765 start
= GC_MALLOC_ATOMIC (BLOCK_SIZE
);
3770 memset (start
, ' ', BLOCK_SIZE
- 1);
3771 start
[BLOCK_SIZE
- 1] = '\0';
3772 pt
->kind
= port_string
| port_output
| port_srfi6
;
3773 pt
->rep
.string
.start
= start
;
3774 pt
->rep
.string
.curr
= start
;
3775 pt
->rep
.string
.past_the_end
= start
+ BLOCK_SIZE
- 1;
3780 port_from_scratch (void)
3783 pt
= port_rep_from_scratch ();
3788 return mk_port (pt
);
3791 /*_ . open-input-file */
3792 SIG_CHKARRAY(k_open_input_file
) =
3793 { REF_OPER(is_string
), };
3794 DEF_SIMPLE_APPLICATIVE(ps0a1
,k_open_input_file
,0,ground
, "open-input-file")
3796 WITH_1_ARGS(filename
);
3797 return port_from_filename (string_value(filename
), port_file
| port_input
);
3803 DEF_T_PRED (is_port
, T_PORT
,ground
,"port?/o1");
3805 DEF_SIMPLE_PRED (is_inport
,T_NO_K
,ground
,"input-port?/o1")
3808 return is_port (p
) && portvalue (p
)->kind
& port_input
;
3811 DEF_SIMPLE_PRED (is_outport
,T_NO_K
,ground
,"output-port?/o1")
3814 return is_port (p
) && portvalue (p
)->kind
& port_output
;
3821 WITH_PSYC_UNBOXED(port
*,p
,T_PORT
,0);
3826 set_portvalue (pko p
, port
* newport
)
3828 assert_mutable(0,p
);
3829 WITH_PSYC_UNBOXED(port
*,p
,T_PORT
,0);
3834 /*_ . reading from ports */
3840 if (pt
->kind
& port_saw_EOF
)
3842 c
= basic_inchar (pt
);
3844 { pt
->kind
|= port_saw_EOF
; }
3848 if (pt
->kind
& port_file
)
3849 { pt
->rep
.stdio
.curr_line
++; }
3857 basic_inchar (port
* pt
)
3859 if (pt
->kind
& port_file
)
3861 return fgetc (pt
->rep
.stdio
.file
);
3865 if (*pt
->rep
.string
.curr
== 0 ||
3866 pt
->rep
.string
.curr
== pt
->rep
.string
.past_the_end
)
3872 return *pt
->rep
.string
.curr
++;
3877 /* back character to input buffer */
3879 backchar (port
* pt
, int c
)
3884 if (pt
->kind
& port_file
)
3886 ungetc (c
, pt
->rep
.stdio
.file
);
3890 pt
->rep
.stdio
.curr_line
--;
3896 if (pt
->rep
.string
.curr
!= pt
->rep
.string
.start
)
3898 --pt
->rep
.string
.curr
;
3905 /*_ . (get-char textual-input-port) */
3906 SIG_CHKARRAY(get_char
) = { REF_OPER(is_inport
), };
3907 DEF_SIMPLE_APPLICATIVE(p00a1
,get_char
,T_NO_K
,ground
, "get-char")
3910 assert(is_inport(port
));
3911 int c
= inchar(portvalue(port
));
3915 { return mk_character(c
); }
3918 /*_ . Finalization */
3920 port_finalize_file(GC_PTR obj
, GC_PTR client_data
)
3923 if ((pt
->kind
& port_file
) && pt
->rep
.stdio
.closeit
)
3924 { port_close_port (pt
, port_input
| port_output
); }
3928 port_close (pko p
, int flag
)
3931 port_close_port(portvalue (p
), flag
);
3935 port_close_port (port
* pt
, int flag
)
3938 if ((pt
->kind
& (port_input
| port_output
)) == 0)
3940 if (pt
->kind
& port_file
)
3943 /* Cleanup is here so (close-*-port) functions could work too */
3944 pt
->rep
.stdio
.curr_line
= 0;
3948 fclose (pt
->rep
.stdio
.file
);
3950 pt
->kind
= port_free
;
3955 /*_ , Encapsulation type */
3957 SIG_CHKARRAY(is_encap
) = { REF_OPER(is_key
), K_ANY
};
3958 DEF_SIMPLE_CFUNC(b00a2
, is_encap
,T_NO_K
)
3960 WITH_2_ARGS(type
, p
);
3961 if (is_type (p
, T_ENCAP
))
3963 WITH_UNBOXED_UNSAFE(pdata
,kt_encap
,p
);
3964 return (pdata
->type
== type
);
3972 /* NOT directly part of the interface. */
3973 SIG_CHKARRAY(unencap
) = { REF_OPER(is_key
), K_ANY
};
3974 DEF_SIMPLE_CFUNC(ps0a2
, unencap
,T_NO_K
)
3976 WITH_2_ARGS(type
, p
);
3977 if (is_encap (type
, p
))
3979 WITH_UNBOXED_UNSAFE(pdata
,kt_encap
,p
);
3980 return pdata
->value
;
3984 /* We have no type-name to give to the error message. */
3985 KERNEL_ERROR_0 (sc
, "unencap: wrong type");
3989 /* NOT directly part of the interface. */
3990 SIG_CHKARRAY(mk_encap
) = { REF_OPER(is_key
), K_ANY
};
3991 DEF_SIMPLE_CFUNC(p00a2
, mk_encap
,T_NO_K
)
3993 WITH_2_ARGS(type
, value
);
3994 ALLOC_BOX_PRESUME (kt_encap
, T_ENCAP
);
3995 pbox
->data
.type
= type
;
3996 pbox
->data
.value
= value
;
3997 return PTR2PKO(pbox
);
4000 DEF_APPLICATIVE_W_DESTR (p00a0
, mk_encapsulation_type
, K_NO_TYPE
,T_NO_K
,ground
, "make-encapsulation-type/raw")
4002 /* A unique cell representing a type */
4003 pko type
= mk_void();
4004 /* $$IMPROVE ME make typespecs for the curried objs. trivpred is
4005 effectively that spec object. */
4006 pko e
= wrap (mk_curried (dcrry_2ALLV01
, type
, REF_OPER (mk_encap
)));
4007 pko trivpred
= mk_curried (dcrry_2ALLV01
, type
, REF_OPER (is_encap
));
4008 pko d
= wrap (mk_curried (dcrry_2ALLV01
, type
, REF_OPER (unencap
)));
4009 return LIST3 (e
, trivpred
, d
);
4011 /*_ , Listloop types */
4012 /*_ . Forward declarations */
4014 /*_ . Enumerations */
4016 /* How to turn the current list into current value and next list. */
4023 } kt_loopstyle_step
;
4031 } kt_loopstyle_argix
;
4033 /*_ . Function signatures. */
4034 typedef pko (* kt_listloop_mk_val
)(pko value
, struct kt_listloop
* pll
);
4036 typedef struct kt_listloop_style
4038 pko combiner
; /* Default combiner or NULL. */
4039 int collect_p
; /* Whether to collect a (reversed)
4040 list of the returns. */
4041 kt_loopstyle_step step
;
4042 kt_listloop_mk_val mk_val
; /* From returned value+state -> passed value. */
4043 pko destructurer
; /* A destructurer contents */
4044 /* Selection of args. Each entry correspond to one arg in "full
4045 args", and indexes something in the array of actual args that the
4046 destructurer retrieves. */
4047 int arg_select
[lls_num_args
];
4048 } kt_listloop_style
;
4049 typedef struct kt_listloop
4051 pko combiner
; /* The combiner to use repeatedly. */
4052 pko list
; /* The list to loop over */
4053 int top_length
; /* Length of top element, for lls_many. */
4054 int countdown
; /* Num elements left, or negative if unused. */
4055 int countup
; /* Upwards count from 0. */
4056 pko stop_on
; /* Stop if return value is this. Can
4058 kt_listloop_style
* style
; /* Non-NULL pointer to style. */
4060 /*_ , Internal signatures */
4062 listloop_aux (klink
* sc
,
4063 kt_listloop_style
* style_v
,
4065 pko style_args
[lls_num_args
]);
4066 FORWARD_DECL_CFUNC (static, ps0a3
, listloop_resume
);
4069 /*_ , Listloop styles */
4075 kt_loopstyle_step step
,
4076 kt_listloop_mk_val mk_val
)
4078 ALLOC_BOX_PRESUME(kt_listloop_style
,T_LISTLOOP_STYLE
);
4079 pdata
->combiner
= combiner
;
4080 pdata
->collect_p
= collect_p
;
4082 pdata
->mk_val
= mk_val
;
4083 return PTR2PKO(pbox
);
4093 kt_listloop_style
* style
)
4095 ALLOC_BOX_PRESUME(kt_listloop
,T_LISTLOOP
);
4096 pdata
->combiner
= combiner
;
4098 pdata
->top_length
= top_length
;
4099 pdata
->countdown
= count
;
4100 pdata
->countup
= -1;
4101 pdata
->stop_on
= stop_on
;
4102 pdata
->style
= style
;
4103 return PTR2PKO(pbox
);
4107 copy_listloop(const kt_listloop
* orig
)
4109 ALLOC_BOX_PRESUME(kt_listloop
,T_LISTLOOP
);
4110 memcpy (pdata
, orig
, sizeof(kt_listloop
));
4111 return PTR2PKO(pbox
);
4115 DEF_T_PRED(is_listloop
, T_LISTLOOP
, no
, "");
4116 DEF_T_PRED(is_listloop_style
, T_LISTLOOP_STYLE
, no
, "");
4118 /*_ . Pre-existing style objects */
4119 /*_ , listloop-style-sequence */
4120 RGSTR(simple
,"listloop-style-sequence",REF_OBJ(sequence_style
))
4121 static BOX_OF(kt_listloop_style
) sequence_style
=
4125 REF_OPER(kernel_eval
),
4129 K_NO_TYPE
, /* No args contemplated */
4130 { [0 ... lls_num_args
- 1] = -1, }
4133 /*_ , listloop-style-neighbors */
4134 RGSTR(simple
,"listloop-style-neighbors",REF_OBJ(neighbor_style
))
4135 SIG_CHKARRAY(neighbor_style
) =
4137 REF_OPER(is_integer
),
4139 DEF_SIMPLE_DESTR(neighbor_style
);
4140 static BOX_OF(kt_listloop_style
) neighbor_style
=
4148 REF_DESTR(neighbor_style
),
4149 /* See http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html. */
4150 { [0 ... lls_num_args
- 1] = -1, [lls_count
] = 0, },
4155 /* Create a listloop object. */
4156 /* $$IMPROVE ME This may become what style operative T_ type calls.
4157 Rename it eval_listloop_style. */
4158 SIG_CHKARRAY(listloop
) =
4160 REF_OPER(is_listloop_style
),
4161 REF_OPER(is_countable_list
),
4162 REF_KEY(K_TYCH_DOT
),
4166 DEF_SIMPLE_APPLICATIVE(ps0a3
, listloop
,0,ground
, "listloop")
4168 WITH_3_ARGS(style
, list
, args
);
4170 WITH_UNBOXED_UNSAFE(style_v
,kt_listloop_style
, style
);
4171 pko style_args
[lls_num_args
];
4172 /* Destructure the args by style */
4173 destructure_to_array(sc
,
4175 style_v
->destructurer
,
4178 REF_OPER (listloop_resume
),
4179 LIST2 (style
, list
));
4180 return listloop_aux (sc
, style_v
, list
, style_args
);
4182 /*_ , listloop_resume */
4183 SIG_CHKARRAY (listloop_resume
) =
4185 REF_OPER (is_destr_result
),
4186 REF_OPER(is_listloop_style
),
4187 REF_OPER(is_countable_list
),
4189 DEF_SIMPLE_CFUNC(ps0a3
, listloop_resume
, 0)
4191 WITH_3_ARGS (destr_result
, style
, list
);
4192 pko style_args
[lls_num_args
];
4193 destr_result_fill_array (destr_result
, lls_num_args
, style_args
);
4194 WITH_UNBOXED_UNSAFE(style_v
,kt_listloop_style
, style
);
4195 return listloop_aux (sc
, style_v
, list
, style_args
);
4197 /*_ , listloop_aux */
4200 (klink
* sc
, kt_listloop_style
* style_v
, pko list
, pko style_args
[lls_num_args
])
4202 /*** Get the actual arg objects ***/
4203 #define GET_OBJ(_INDEX) \
4204 ((style_v->arg_select[_INDEX] < 0) ? K_INERT : style_args[style_v->arg_select[_INDEX]])
4206 pko count
= GET_OBJ(lls_count
);
4207 pko combiner
= GET_OBJ(lls_combiner
);
4208 pko top_length
= GET_OBJ(lls_top_count
);
4211 /*** Extract values from the objects, using defaults as needed ***/
4212 int countv
= (count
== K_INERT
) ? -1L : ivalue(count
);
4213 int top_lengthv
= (top_length
== K_INERT
) ? 1 : ivalue(top_length
);
4214 if(combiner
== K_INERT
)
4216 combiner
= style_v
->combiner
;
4219 /*** Make the loop object itself ***/
4220 pko ll
= mk_listloop( combiner
, list
, top_lengthv
, countv
, 0, style_v
);
4223 /*_ , Evaluating one iteration */
4225 eval_listloop(klink
* sc
, pko functor
, pko value
)
4228 WITH_PSYC_UNBOXED(kt_listloop
, functor
, T_LISTLOOP
, sc
);
4230 /*** Test whether done, maybe return current value. ***/
4231 /* If we're not checking, value will be NULL so this won't
4232 trigger. pdata->countup is 0 for the first element. */
4233 if((pdata
->countup
>= 0) && (value
== pdata
->stop_on
))
4235 /* $$IMPROVE ME This will ct an "abnormal return" value from
4236 this and the other data. */
4239 /* If we're not counting down, value will be negative so this won't
4241 if(pdata
->countdown
== 0)
4245 /* And if we run out of elements, we have to stop regardless. */
4246 if(pdata
->list
== K_NIL
)
4248 /* $$IMPROVE ME Error if we're counting down (ie, if count
4253 /*** Step list, getting new value ***/
4254 pko new_list
, new_value
;
4256 switch(pdata
->style
->step
)
4259 new_list
= cdr( pdata
->list
);
4260 /* We assume the common case of val as list. */
4261 new_value
= LIST1(car( pdata
->list
));
4265 /* $$IMPROVE ME Also test that next item (new_list) is non-empty */
4266 new_list
= cdr( pdata
->list
);
4267 new_value
= LIST2(car( pdata
->list
), car(new_list
));
4270 new_list
= k_counted_map_cdr(sc
, pdata
->top_length
, pdata
->list
, T_PAIR
);
4271 new_value
= k_counted_map_car(sc
, pdata
->top_length
, pdata
->list
, T_PAIR
);
4274 KERNEL_ERROR_0(sc
,"I know nut-ting about that case");
4277 /* Convert it if applicable. */
4278 if(pdata
->style
->mk_val
)
4280 new_value
= pdata
->style
->mk_val(new_value
, pdata
);
4283 /*** Arrange a new iteration. ***/
4284 /* We don't have to re-setup the final chain, if any, because it's
4285 still there from the earlier call. Just the combiner (if any)
4286 and a fresh listloop operative. */
4287 pko new_listloop
= copy_listloop(pdata
);
4289 WITH_UNBOXED_UNSAFE(new_pdata
,kt_listloop
,new_listloop
);
4290 new_pdata
->list
= new_list
;
4291 if(new_pdata
->countdown
> 0)
4292 { new_pdata
->countdown
--; }
4293 new_pdata
->countup
++;
4296 if(pdata
->style
->collect_p
)
4298 CONTIN_0_RAW (mk_curried(dcrry_NVLLdotALL
, value
, new_listloop
), sc
);
4302 CONTIN_0_RAW(new_listloop
, sc
);
4305 CONTIN_0_RAW(pdata
->combiner
, sc
);
4309 /*_ . Handling lists */
4311 DEF_APPLICATIVE_W_DESTR (ps0a1
, list_star
, REF_OPER(is_finite_list
),T_NO_K
,ground
, "list*")
4313 return v2list_star(sc
, arg1
, T_PAIR
);
4316 SIG_CHKARRAY(reverse
) = { REF_OPER(is_finite_list
), };
4317 DEF_SIMPLE_APPLICATIVE (ps0a1
, reverse
,T_NO_K
,ground
, "reverse")
4320 return v2reverse(a
,T_PAIR
);
4322 /*_ . reverse list -- in-place */
4323 /* Don't just use unsafe_v2reverse_in_place, it checks nothing. This
4324 may be reserved for optimization only. */
4326 /*_ . append list -- produce new list */
4327 /* $$IMPROVE ME This defines append/2 but we'll want append/N. Do
4329 SIG_CHKARRAY(append
) = { REF_OPER(is_finite_list
), K_ANY
, };
4330 DEF_SIMPLE_APPLICATIVE (ps0a2
, append
,T_NO_K
,simple
, "append")
4333 return v2append(sc
,a
,b
,T_PAIR
);
4335 /*_ , is_finite_list */
4336 DEF_SIMPLE_PRED (is_finite_list
,T_NO_K
,ground
, "finite-list?/o1")
4340 get_list_metrics_aux(p
, metrics
);
4341 return (metrics
[lm_num_nils
] == 1);
4343 /*_ , is_countable_list */
4344 DEF_SIMPLE_PRED (is_countable_list
,T_NO_K
,ground
, "countable-list?/o1")
4348 get_list_metrics_aux(p
, metrics
);
4349 return (metrics
[lm_num_nils
] || metrics
[lm_cyc_len
]);
4351 /*_ , list_length */
4356 dotted list: -2 minus length before dot
4358 The extra meanings will change since callers can use
4359 get_list_metrics_aux now. Return lm_acyc_len even for dotted
4360 lists, return positive infinity for circular lists.
4367 get_list_metrics_aux(p
, metrics
);
4369 if(metrics
[lm_num_nils
] == 1)
4370 { return metrics
[lm_acyc_len
]; }
4371 /* A circular list */
4372 /* $$IMPROVE ME Return +oo. First make a type and object for +oo */
4373 if(metrics
[lm_cyc_len
] != 0)
4375 /* $$IMPROVE ME Return lm_acyc_len again, merge with the other
4377 /* Otherwise it's dotted */
4378 return 2 - metrics
[lm_acyc_len
];
4380 /*_ , list_length_k */
4381 DEF_APPLICATIVE_W_DESTR(p00a1
, list_length_k
, K_ANY_SINGLETON
,T_NO_K
,ground
, "length")
4384 return mk_integer(list_length(p
));
4387 /*_ , get_list_metrics */
4388 DEF_APPLICATIVE_W_DESTR(p00a1
, get_list_metrics
, K_ANY_SINGLETON
,T_NO_K
,ground
, "get-list-metrics")
4392 get_list_metrics_aux(p
, metrics
);
4393 return LIST4(mk_integer(metrics
[0]),
4394 mk_integer(metrics
[1]),
4395 mk_integer(metrics
[2]),
4396 mk_integer(metrics
[3]));
4398 /*_ , get_list_metrics_aux */
4399 /* RESULTS must be an int4 (an array of 4 integers). get_list_metrics_aux
4400 will fill it with (See enum lm_index):
4402 * the number of pairs in a
4403 * the number of nil objects in a
4404 * the acyclic prefix length of a
4405 * the cycle length of a
4408 /* $$IMPROVE ME Take a flag so we can skip work such as finding
4409 prefix-length when we don't need to do it. This will cause some
4410 result positions to be interpreted differently: when it's cycling,
4411 lm_acyc_len and lm_num_pairs may both overshoot (but never
4416 get_list_metrics_aux (pko a
, int4 presults
)
4418 int * results
= presults
; /* Make it easier to index. */
4425 /* Use Brent's Algorithm, but we have to check for nil and non-pair
4426 too, so I rearranged the loop. We also count steps, because in
4427 some cases we use number of steps directly. */
4433 results
[lm_num_pairs
] = steps
;
4434 results
[lm_num_nils
] = 1;
4435 results
[lm_acyc_len
] = steps
;
4436 results
[lm_cyc_len
] = 0;
4439 if (!is_pair (fast
))
4441 results
[lm_num_pairs
] = steps
;
4442 results
[lm_num_nils
] = 0;
4443 results
[lm_acyc_len
] = steps
;
4444 results
[lm_cyc_len
] = 0;
4450 /* The fast cursor has caught up with the slow cursor so the
4451 structure is circular and loop_len is the cycle length.
4452 We still need to find prefix length.
4456 /* Restart the turtle from the beginning */
4458 /* Restart the hare from position LOOP_LEN */
4459 for(i
= 0, fast
= a
; i
< loop_len
; i
++)
4460 { fast
= cdr (fast
); }
4461 /* Since hare has exactly a loop_len head start, when it
4462 goes around the loop exactly once it will be in the same
4463 position as turtle, so turtle will have only walked the
4472 results
[lm_num_pairs
] = prefix_len
+ loop_len
;
4473 results
[lm_num_nils
] = 0;
4474 results
[lm_acyc_len
] = prefix_len
;
4475 results
[lm_cyc_len
] = loop_len
;
4478 if(power
== loop_len
)
4480 /* Re-plant the slow cursor */
4489 /*_ . Handling trees */
4490 /*_ , copy_es_immutable */
4491 DEF_APPLICATIVE_W_DESTR (ps0a1
, copy_es_immutable
, K_ANY_SINGLETON
,T_NO_K
,ground
, "copy-es-immutable")
4493 WITH_1_ARGS(object
);
4495 if (is_pair (object
))
4497 /* If it's already immutable, can we assume it's immutable
4498 * all the way down and just return it? */
4500 (copy_es_immutable (sc
, car (object
)),
4501 copy_es_immutable (sc
, cdr (object
)));
4508 /*_ , Get tree cycles */
4510 /*_ , kt_recurrence_table */
4511 /* Really just a specialized resizeable lookup table from object to
4512 count. Internals may change. */
4513 /* $$IMPROVE ME Look up more efficiently. Current GC is not
4514 compacting, so we can hash or sort addresses meaningfully. */
4522 kt_recurrence_table
;
4523 /*_ , recur_entry */
4526 /* $$IMPROVE ME These two fields may become one enumerated field */
4531 /*_ , kt_recur_tracker */
4535 recur_entry
* entries
;
4539 /*_ . is_recurrence_table */
4540 DEF_T_PRED(is_recurrence_table
,T_RECURRENCES
,ground
, "recurrence-table?/o1");
4542 /*_ . is_recur_tracker */
4543 DEF_SIMPLE_PRED(is_recur_tracker
,T_NO_K
,ground
, "recur-tracker?/o1")
4546 return (p
== K_NIL
) || is_type (p
, T_RECUR_TRACKER
);
4548 /*_ . recurrences_to_recur_tracker */
4549 SIG_CHKARRAY(recurrences_to_recur_tracker
) =
4550 { REF_OPER(is_recurrence_table
), };
4551 DEF_SIMPLE_APPLICATIVE(p00a1
,recurrences_to_recur_tracker
,T_NO_K
,ground
, "recurrences->tracker")
4553 WITH_1_ARGS(recurrences
);
4554 assert_type(0,recurrences
,T_RECURRENCES
);
4556 WITH_UNBOXED_UNSAFE(ptable
, kt_recurrence_table
,recurrences
);
4557 /* $$IMPROVE ME Scan for counts > 1, and if there are none,
4559 if(ptable
->table_size
== 0)
4562 ALLOC_BOX_PRESUME(kt_recur_tracker
,T_RECUR_TRACKER
);
4563 /* $$MAKE ME SAFE This assumes that sharing is OK, recurrences
4564 won't mutate the LUT. When we have COW or similar, make it
4565 safe. At least check for immutability. */
4566 pdata
->objs
= ptable
->objs
;
4567 pdata
->table_size
= ptable
->table_size
;
4568 pdata
->current_index
= 0;
4570 GC_MALLOC_ATOMIC(sizeof(recur_entry
) * ptable
->table_size
);
4572 for(i
= 0; i
< ptable
->table_size
; i
++)
4574 recur_entry
* p_entry
= &pdata
->entries
[i
];
4575 p_entry
->count
= ptable
->counts
[i
];
4576 p_entry
->index_in_walk
= 0;
4577 p_entry
->seen_in_walk
= 0;
4579 return PTR2PKO(pbox
);
4582 /*_ . recurrences_list_objects */
4583 /* $$WRITE ME Get a list of all objects and their recurrence counts */
4584 /*_ . objtable_get_index */
4587 (pko
* objs
, int table_size
, pko obj
)
4590 for(i
= 0; i
< table_size
; i
++)
4597 /*_ . recurrences_get_seen_count */
4598 /* Return the number of times OBJ has been seen before. If "add" is
4599 non-zero, increment the count too (but return its previous
4602 recurrences_get_seen_count
4603 (kt_recurrence_table
* p_cycles_data
, pko obj
, int add
)
4605 int index
= objtable_get_index(p_cycles_data
->objs
,
4606 p_cycles_data
->table_size
,
4610 int count
= p_cycles_data
->counts
[index
];
4611 /* Maybe record another sighting of this object. */
4613 { p_cycles_data
->counts
[index
]++; }
4614 /* We've found our return value. */
4618 /* We only get here if search didn't find anything. */
4619 /* Make sure we have enough space for this object. */
4622 if(p_cycles_data
->table_size
== p_cycles_data
->alloced_size
)
4624 p_cycles_data
->alloced_size
*= 2;
4625 p_cycles_data
->counts
= GC_REALLOC(p_cycles_data
->counts
, sizeof(int) * p_cycles_data
->alloced_size
);
4626 p_cycles_data
->objs
= GC_REALLOC(p_cycles_data
->objs
, sizeof(pko
) * p_cycles_data
->alloced_size
);
4628 int index
= p_cycles_data
->table_size
;
4629 /* Record what it was */
4630 p_cycles_data
->objs
[index
] = obj
;
4631 /* We have now seen it once. */
4632 p_cycles_data
->counts
[index
] = 1;
4633 p_cycles_data
->table_size
++;
4637 /*_ . recurrences_get_object_count */
4638 /* Given an object, list its count */
4639 SIG_CHKARRAY(recurrences_get_object_count
) =
4640 { REF_OPER(is_recurrence_table
), K_ANY
, };
4641 DEF_SIMPLE_APPLICATIVE(p00a2
, recurrences_get_object_count
,T_NO_K
,ground
, "recurrences-get-object-count")
4643 WITH_2_ARGS(table
, obj
);
4644 WITH_PSYC_UNBOXED(kt_recurrence_table
,table
, T_RECURRENCES
, 0);
4645 int seen_count
= recurrences_get_seen_count(pdata
, obj
, 0);
4646 return mk_integer(seen_count
);
4648 /*_ . init_recurrence_table */
4650 init_recurrence_table(kt_recurrence_table
* p_cycles_data
, int initial_size
)
4652 p_cycles_data
->objs
= initial_size
?
4653 GC_MALLOC(sizeof(pko
) * initial_size
) : 0;
4654 p_cycles_data
->counts
= initial_size
?
4655 GC_MALLOC(sizeof(int) * initial_size
) : 0;
4656 p_cycles_data
->alloced_size
= initial_size
;
4657 p_cycles_data
->table_size
= 0;
4659 /*_ . trace_tree_cycles */
4662 (pko tree
, kt_recurrence_table
* p_cycles_data
)
4664 /* Special case for the "empty container", not because it's just a
4665 key but because "exploring" it does nothing. */
4668 /* Maybe skip this object entirely */
4669 /* $$IMPROVE ME Parameterize this */
4670 switch(_get_type(tree
))
4678 if(recurrences_get_seen_count(p_cycles_data
,tree
, 1) != 0)
4681 /* Switch on tree type */
4682 switch(_get_type(tree
))
4686 #define _EXPLORE_FUNC(X) trace_tree_cycles(X, p_cycles_data)
4688 #undef _EXPLORE_FUNC
4693 /* Done this exploration */
4698 /*_ . get_recurrences */
4699 SIG_CHKARRAY(get_recurrences
) = { K_ANY
, };
4700 DEF_SIMPLE_APPLICATIVE (ps0a1
, get_recurrences
,T_NO_K
,ground
, "get-recurrences")
4703 /* No reason to even start exploring non-containers */
4704 /* $$IMPROVE ME Allow containers other than pairs */
4705 int explore_p
= (_get_type(tree
) == T_PAIR
);
4706 ALLOC_BOX_PRESUME(kt_recurrence_table
, T_RECURRENCES
);
4707 init_recurrence_table(pdata
, explore_p
? 8 : 0);
4709 { trace_tree_cycles(tree
,pdata
); }
4710 return PTR2PKO(pbox
);
4715 /*_ , Making result objects */
4717 /* make symbol or number atom from string */
4719 mk_atom (klink
* sc
, char *q
)
4722 int has_dec_point
= 0;
4726 if ((p
= strstr (q
, "::")) != 0)
4729 return mcons (sc
->COLON_HOOK
,
4730 mcons (mcons (sc
->QUOTE
,
4731 mcons (mk_atom (sc
, p
+ 2), K_NIL
)),
4732 mcons (mk_symbol (strlwr (q
)), K_NIL
)));
4738 if ((c
== '+') || (c
== '-'))
4748 return (mk_symbol (strlwr (q
)));
4757 return (mk_symbol (strlwr (q
)));
4760 else if (!isdigit (c
))
4762 return (mk_symbol (strlwr (q
)));
4765 for (; (c
= *p
) != 0; ++p
)
4777 else if ((c
== 'e') || (c
== 'E'))
4781 has_dec_point
= 1; /* decimal point illegal
4784 if ((*p
== '-') || (*p
== '+') || isdigit (*p
))
4790 return (mk_symbol (strlwr (q
)));
4795 return mk_real (atof (q
));
4797 return (mk_integer (atol (q
)));
4802 mk_sharp_const (char *name
)
4805 char tmp
[STRBUFFSIZE
];
4807 if (!strcmp (name
, "t"))
4809 else if (!strcmp (name
, "f"))
4811 else if (!strcmp (name
, "ignore"))
4813 else if (!strcmp (name
, "inert"))
4815 else if (*name
== 'o')
4817 snprintf (tmp
, STRBUFFSIZE
, "0%s", name
+ 1);
4818 sscanf (tmp
, "%lo", &x
);
4819 return (mk_integer (x
));
4821 else if (*name
== 'd')
4822 { /* #d (decimal) */
4823 sscanf (name
+ 1, "%ld", &x
);
4824 return (mk_integer (x
));
4826 else if (*name
== 'x')
4828 snprintf (tmp
, STRBUFFSIZE
, "0x%s", name
+ 1);
4829 sscanf (tmp
, "%lx", &x
);
4830 return (mk_integer (x
));
4832 else if (*name
== 'b')
4834 x
= binary_decode (name
+ 1);
4835 return (mk_integer (x
));
4837 else if (*name
== '\\')
4838 { /* #\w (character) */
4840 if (stricmp (name
+ 1, "space") == 0)
4844 else if (stricmp (name
+ 1, "newline") == 0)
4848 else if (stricmp (name
+ 1, "return") == 0)
4852 else if (stricmp (name
+ 1, "tab") == 0)
4856 else if (name
[1] == 'x' && name
[2] != 0)
4859 if (sscanf (name
+ 2, "%x", &c1
) == 1 && c1
< UCHAR_MAX
)
4869 else if (is_ascii_name (name
+ 1, &c
))
4874 else if (name
[2] == 0)
4882 return mk_character (c
);
4888 /*_ , Reading strings */
4889 /* read characters up to delimiter, but cater to character constants */
4891 readstr_upto (klink
* sc
, char *delim
)
4893 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
4895 char *p
= sc
->strbuff
;
4897 while ((p
- sc
->strbuff
< sizeof (sc
->strbuff
)) &&
4898 !is_one_of (delim
, (*p
++ = inchar (pt
))));
4900 if (p
== sc
->strbuff
+ 2 && p
[-2] == '\\')
4906 backchar (pt
, p
[-1]);
4912 /* skip white characters */
4914 skipspace (klink
* sc
)
4916 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
4920 { c
= inchar (pt
); }
4921 while (isspace (c
));
4932 /* check c is in chars */
4934 is_one_of (char *s
, int c
)
4944 /*_ , Reading expressions */
4945 /* read string expression "xxx...xxx" */
4947 readstrexp (klink
* sc
)
4949 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
4950 char *p
= sc
->strbuff
;
4954 { st_ok
, st_bsl
, st_x1
, st_x2
, st_oct1
, st_oct2
} state
= st_ok
;
4959 if (c
== EOF
|| p
- sc
->strbuff
> sizeof (sc
->strbuff
) - 1)
4973 return mk_counted_string (sc
->strbuff
, p
- sc
->strbuff
);
5023 if (c
>= '0' && c
<= 'F')
5027 c1
= (c1
<< 4) + c
- '0';
5031 c1
= (c1
<< 4) + c
- 'A' + 10;
5050 if (c
< '0' || c
> '7')
5058 if (state
== st_oct2
&& c1
>= 32)
5061 c1
= (c1
<< 3) + (c
- '0');
5063 if (state
== st_oct1
)
5082 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
5089 switch (c
= inchar (pt
))
5094 return (TOK_LPAREN
);
5096 return (TOK_RPAREN
);
5099 if (is_one_of (" \n\t", c
))
5112 while ((c
= inchar (pt
)) != '\n' && c
!= EOF
)
5121 return (token (sc
));
5124 return (TOK_DQUOTE
);
5126 return (TOK_BQUOTE
);
5128 if ((c
= inchar (pt
)) == '@')
5130 return (TOK_ATMARK
);
5145 while ((c
= inchar (pt
)) != '\n' && c
!= EOF
)
5154 return (token (sc
));
5160 /* $$UNHACKIFY ME! This is a horrible hack. */
5161 if (is_one_of (" itfodxb\\", c
))
5163 return TOK_SHARP_CONST
;
5175 /*_ , Nesting check */
5176 /*_ . create_nesting_check */
5177 void create_nesting_check(klink
* sc
)
5178 { klink_push_dyn_binding(sc
,K_NEST_DEPTH
,mk_integer(0)); }
5179 /*_ . nest_depth_ok_p */
5180 int nest_depth_ok_p(klink
* sc
)
5183 klink_find_dyn_binding(sc
,K_NEST_DEPTH
);
5186 return ivalue(nesting
) == 0;
5188 /*_ . change_nesting_depth */
5189 void change_nesting_depth(klink
* sc
, signed int change
)
5192 klink_find_dyn_binding(sc
,K_NEST_DEPTH
);
5193 add_to_ivalue(nesting
,change
);
5195 /*_ , C-style entry points */
5197 /*_ . kernel_read_internal */
5198 /* The only reason that this is separate from kernel_read_sexp is that
5199 it gets a token, which kernel_read_sexp does almost always, except
5200 once when a caller tricks it with TOK_LPAREN, and once when
5201 kernel_read_list effectively puts back a token it didn't decode. */
5203 DEF_APPLICATIVE_W_DESTR (ps0a0
, kernel_read_internal
, K_NO_TYPE
,0,ground
, "read")
5205 token_t tok
= token (sc
);
5211 create_nesting_check(sc
);
5212 return kernel_read_sexp (sc
);
5215 /*_ . kernel_read_sexp */
5216 DEF_CFUNC (ps0a0
, kernel_read_sexp
, K_NO_TYPE
,0)
5224 CONTIN_0 (vector
, sc
);
5228 sc
->tok
= token (sc
);
5229 if (sc
->tok
== TOK_RPAREN
)
5233 else if (sc
->tok
== TOK_DOT
)
5235 KERNEL_ERROR_0 (sc
, "syntax error: illegal dot expression");
5239 change_nesting_depth(sc
, 1);
5240 CONTIN_1 (dcrry_2A01VLL
, kernel_read_list
, sc
, K_NIL
);
5241 CONTIN_0 (kernel_read_sexp
, sc
);
5246 pko pquote
= REF_OPER(arg1
);
5247 CONTIN_1 (dcrry_2A01VLL
, val2val
, sc
, pquote
);
5249 sc
->tok
= token (sc
);
5250 CONTIN_0 (kernel_read_sexp
, sc
);
5254 sc
->tok
= token (sc
);
5255 if (sc
->tok
== TOK_VEC
)
5257 /* $$CLEAN ME Do this more cleanly than by changing tokens
5258 to trick it. Maybe factor the TOK_LPAREN treatment so we
5260 klink_push_cont (sc
, REF_OPER (kernel_treat_qquoted_vec
));
5261 sc
->tok
= TOK_LPAREN
;
5262 /* $$CLEANUP Seems like this could be combined with the part
5264 CONTIN_0 (kernel_read_sexp
, sc
);
5269 /* Punt for now: Give quoted symbols rather than actual
5270 operators. ,Similarly sc->UNQUOTE, sc->UNQUOTESP */
5271 CONTIN_1 (dcrry_2A01VLL
, val2val
, sc
, sc
->QQUOTE
);
5274 CONTIN_0 (kernel_read_sexp
, sc
);
5278 CONTIN_1 (dcrry_2A01VLL
, val2val
, sc
, sc
->UNQUOTE
);
5279 sc
->tok
= token (sc
);
5280 CONTIN_0 (kernel_read_sexp
, sc
);
5283 CONTIN_1 (dcrry_2A01VLL
, val2val
, sc
, sc
->UNQUOTESP
);
5284 sc
->tok
= token (sc
);
5285 CONTIN_0 (kernel_read_sexp
, sc
);
5288 return mk_atom (sc
, readstr_upto (sc
, "();\t\n\r "));
5291 pko x
= readstrexp (sc
);
5294 KERNEL_ERROR_0 (sc
, "Error reading string");
5301 pko sharp_hook
= sc
->SHARP_HOOK
;
5303 is_symbol(sharp_hook
)
5304 ? find_slot_in_env (sc
->envir
, sharp_hook
, 1)
5308 KERNEL_ERROR_0 (sc
, "undefined sharp expression");
5312 pko form
= mcons (slot_value_in_env (f
), K_NIL
);
5313 return kernel_eval (sc
, form
, sc
->envir
);
5316 case TOK_SHARP_CONST
:
5318 pko x
= mk_sharp_const (readstr_upto (sc
, "();\t\n\r "));
5321 KERNEL_ERROR_0 (sc
, "undefined sharp expression");
5329 KERNEL_ERROR_0 (sc
, "syntax error: illegal token");
5334 /* $$IMPROVE ME Use currying ops instead of accumulating by hand */
5335 SIG_CHKARRAY(kernel_read_list
) = { REF_OPER(is_finite_list
), K_ANY
, };
5336 DEF_SIMPLE_CFUNC (ps0a2
, kernel_read_list
,0)
5338 WITH_2_ARGS (old_accum
,value
);
5339 pko accum
= mcons (value
, old_accum
);
5340 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
5341 sc
->tok
= token (sc
);
5342 if (sc
->tok
== TOK_EOF
)
5346 else if (sc
->tok
== TOK_RPAREN
)
5348 /* $$RECONSIDER ME Why is this done? To accept CR from user? */
5349 int c
= inchar (pt
);
5354 change_nesting_depth(sc
, -1);
5355 return (unsafe_v2reverse_in_place (K_NIL
, accum
));
5357 else if (sc
->tok
== TOK_DOT
)
5359 CONTIN_1 (dcrry_2A01VLL
, kernel_treat_dotted_list
, sc
, accum
);
5360 sc
->tok
= token (sc
);
5361 CONTIN_0 (kernel_read_sexp
, sc
);
5366 CONTIN_1 (dcrry_2A01VLL
, kernel_read_list
, sc
, accum
);
5367 CONTIN_0 (kernel_read_sexp
, sc
);
5372 /*_ . Treat end of dotted list */
5374 DEF_CFUNC (ps0a2
, kernel_treat_dotted_list
, REF_DESTR(kernel_read_list
),T_NO_K
)
5376 WITH_2_ARGS(args
,value
);
5378 if (token (sc
) != TOK_RPAREN
)
5380 KERNEL_ERROR_0 (sc
, "syntax error: illegal dot expression");
5384 change_nesting_depth(sc
, -1);
5385 return (unsafe_v2reverse_in_place (value
, args
));
5389 /*_ . Treat quasiquoted vector */
5391 DEF_CFUNC (ps0a1
, kernel_treat_qquoted_vec
, K_ANY
,T_NO_K
)
5394 /* $$IMPROVE ME Include vector applicative directly, not by applying
5395 symbol. This does need to apply, though, so that backquote (now
5396 seeing a list) can be run on "value" first*/
5397 return (mcons (mk_symbol ("apply"),
5398 mcons (mk_symbol ("vector"),
5399 mcons (mcons (sc
->QQUOTE
, mcons (value
, K_NIL
)),
5402 /*_ , Loading files */
5403 /*_ . load_from_port */
5404 /* $$RETHINK ME This soon need no longer be a cfunc */
5405 SIG_CHKARRAY(load_from_port
) = { REF_OPER(is_inport
), REF_OPER(is_environment
)};
5406 DEF_SIMPLE_CFUNC(ps0a2
,load_from_port
,0)
5408 WITH_2_ARGS(inport
,env
);
5409 assert (is_port(inport
));
5410 assert (is_environment(env
));
5411 /* Print that we're loading (If there's an outport, and we may want
5412 to add a verbosity condition based on a dynamic variable) */
5413 pko the_outport
= klink_find_dyn_binding(sc
,K_OUTPORT
);
5414 if(the_outport
&& (the_outport
!= K_NIL
))
5416 port
* pt
= portvalue(inport
);
5417 if(pt
->kind
& port_file
)
5419 const char *fname
= pt
->rep
.stdio
.filename
;
5421 { fname
= "<unknown>"; }
5422 putstr(sc
,"Loading ");
5428 /* We will do the evals in ENV */
5430 klink_push_dyn_binding(sc
,K_INPORT
,inport
);
5431 return kernel_rel(sc
);
5435 SIG_CHKARRAY(k_load_file
) = { REF_OPER(is_string
), };
5436 DEF_SIMPLE_APPLICATIVE(ps0a1
,k_load_file
,0,ground
, "load")
5438 WITH_1_ARGS(filename_ob
);
5439 const char * filename
= string_value(filename_ob
);
5440 pko p
= port_from_filename (filename
, port_file
| port_input
);
5443 KERNEL_ERROR_1(sc
,"unable to open", filename_ob
);
5446 return load_from_port(sc
,p
,sc
->envir
);
5448 /*_ . get-module-from-port */
5449 SIG_CHKARRAY(k_get_mod_fm_port
) =
5450 { REF_OPER(is_port
), REF_KEY(K_TYCH_OPTIONAL
), REF_OPER(is_environment
), };
5451 DEF_SIMPLE_APPLICATIVE(ps0a2
,k_get_mod_fm_port
,0,ground
, "get-module-from-port")
5453 WITH_2_ARGS(port
, params
);
5454 pko env
= mk_std_environment();
5455 if(params
!= K_INERT
)
5457 assert(is_environment(params
));
5458 kernel_define (env
, mk_symbol ("module-parameters"), params
);
5460 /* Ultimately return that environment. */
5461 CONTIN_1R(dcrry_NdotALL
,val2val
,sc
,env
);
5462 return load_from_port(sc
, port
,env
);
5466 /*_ , Writing chars */
5468 putstr (klink
* sc
, const char *s
)
5470 pko the_outport
= klink_find_dyn_binding(sc
,K_OUTPORT
);
5471 port
*pt
= portvalue (the_outport
); /* $$MAKE ME SAFER - check for K_NIL */
5473 if (pt
->kind
& port_file
)
5475 fputs (s
, pt
->rep
.stdio
.file
);
5481 if (pt
->rep
.string
.curr
!= pt
->rep
.string
.past_the_end
)
5483 *pt
->rep
.string
.curr
++ = *s
;
5485 else if (pt
->kind
& port_srfi6
&& realloc_port_string (pt
))
5487 *pt
->rep
.string
.curr
++ = *s
;
5494 putchars (klink
* sc
, const char *s
, int len
)
5496 pko the_outport
= klink_find_dyn_binding(sc
,K_OUTPORT
);
5497 port
*pt
= portvalue (the_outport
); /* $$MAKE ME SAFER - check for K_NIL */
5499 if (pt
->kind
& port_file
)
5501 fwrite (s
, 1, len
, pt
->rep
.stdio
.file
);
5507 if (pt
->rep
.string
.curr
!= pt
->rep
.string
.past_the_end
)
5509 *pt
->rep
.string
.curr
++ = *s
++;
5511 else if (pt
->kind
& port_srfi6
&& realloc_port_string (pt
))
5513 *pt
->rep
.string
.curr
++ = *s
++;
5520 putcharacter (klink
* sc
, int c
)
5522 pko the_outport
= klink_find_dyn_binding(sc
,K_OUTPORT
);
5523 port
*pt
= portvalue (the_outport
); /* $$MAKE ME SAFER - check for K_NIL */
5525 if (pt
->kind
& port_file
)
5527 fputc (c
, pt
->rep
.stdio
.file
);
5531 if (pt
->rep
.string
.curr
!= pt
->rep
.string
.past_the_end
)
5533 *pt
->rep
.string
.curr
++ = c
;
5535 else if (pt
->kind
& port_srfi6
&& realloc_port_string (pt
))
5537 *pt
->rep
.string
.curr
++ = c
;
5542 #define ok_abbrev(x) (is_pair(x) && cdr(x) == K_NIL)
5545 printslashstring (klink
* sc
, char *p
, int len
)
5548 unsigned char *s
= (unsigned char *) p
;
5549 putcharacter (sc
, '"');
5550 for (i
= 0; i
< len
; i
++)
5552 if (*s
== 0xff || *s
== '"' || *s
< ' ' || *s
== '\\')
5554 putcharacter (sc
, '\\');
5558 putcharacter (sc
, '"');
5561 putcharacter (sc
, 'n');
5564 putcharacter (sc
, 't');
5567 putcharacter (sc
, 'r');
5570 putcharacter (sc
, '\\');
5575 putcharacter (sc
, 'x');
5578 putcharacter (sc
, d
+ '0');
5582 putcharacter (sc
, d
- 10 + 'A');
5587 putcharacter (sc
, d
+ '0');
5591 putcharacter (sc
, d
- 10 + 'A');
5598 putcharacter (sc
, *s
);
5602 putcharacter (sc
, '"');
5605 /*_ , Printing atoms */
5607 printatom (klink
* sc
, pko l
)
5611 atom2str (sc
, l
, &p
, &len
);
5612 putchars (sc
, p
, len
);
5616 /* Uses internal buffer unless string pointer is already available */
5618 atom2str (klink
* sc
, pko l
, char **pp
, int *plen
)
5622 pko p_escapes
= klink_find_dyn_binding(sc
,K_PRINT_FLAG
);
5623 int escapes
= (p_escapes
== K_T
) ? 1 : 0;
5637 else if (l
== K_INERT
)
5641 else if (l
== K_IGNORE
)
5645 else if (l
== K_EOF
)
5649 else if (is_port (l
))
5652 snprintf (p
, STRBUFFSIZE
, "#<PORT>");
5654 else if (is_number (l
))
5657 if (num_is_integer (l
))
5659 snprintf (p
, STRBUFFSIZE
, "%ld", ivalue (l
));
5663 snprintf (p
, STRBUFFSIZE
, "%.10g", rvalue (l
));
5666 else if (is_string (l
))
5670 p
= string_value (l
);
5673 { /* Hack, uses the fact that printing is needed */
5676 printslashstring (sc
, string_value (l
), string_len (l
));
5680 else if (is_character (l
))
5682 int c
= charvalue (l
);
5694 snprintf (p
, STRBUFFSIZE
, "#\\space");
5697 snprintf (p
, STRBUFFSIZE
, "#\\newline");
5700 snprintf (p
, STRBUFFSIZE
, "#\\return");
5703 snprintf (p
, STRBUFFSIZE
, "#\\tab");
5709 snprintf (p
, STRBUFFSIZE
, "#\\del");
5714 snprintf (p
, STRBUFFSIZE
, "#\\%s", charnames
[c
]);
5720 snprintf (p
, STRBUFFSIZE
, "#\\x%x", c
);
5725 snprintf (p
, STRBUFFSIZE
, "#\\%c", c
);
5731 else if (is_symbol (l
))
5737 else if (is_environment (l
))
5739 p
= "#<ENVIRONMENT>";
5741 else if (is_continuation (l
))
5743 p
= "#<CONTINUATION>";
5745 else if (is_operative (l
)
5746 /* $$TRANSITIONAL When these can be launched by
5747 themselves, this check will be folded into is_operative */
5748 || is_type (l
, T_DESTRUCTURE
)
5749 || is_type (l
, T_TYPECHECK
)
5750 || is_type (l
, T_TYPEP
))
5752 /* $$TRANSITIONAL This logic will move, probably into
5753 k_print_special_and_balk_p, and become more general. */
5755 print_lookup_unwraps
?
5756 reverse_find_slot_in_env_aux(print_lookup_unwraps
,l
) :
5761 snprintf (p
, STRBUFFSIZE
, ",(unwrap #,%s)", symname(0, car(slot
)));
5766 print_lookup_to_xary
?
5767 reverse_find_slot_in_env_aux(print_lookup_to_xary
,l
) :
5771 /* We don't say it's the tree-ary version, because the
5772 tree-ary conversion is not exposed. */
5773 p
= symname(0, car(slot
));
5779 reverse_find_slot_in_env_aux(all_builtins_env
, l
) :
5783 p
= symname(0, car(slot
));
5786 { p
= "#<OPERATIVE>"; }}
5789 else if (is_promise (l
))
5793 else if (is_applicative (l
))
5795 p
= "#<APPLICATIVE>";
5797 else if (is_type (l
, T_ENCAP
))
5799 p
= "#<ENCAPSULATION>";
5801 else if (is_type (l
, T_KEY
))
5805 else if (is_type (l
, T_RECUR_TRACKER
))
5807 p
= "#<RECURRENCE TRACKER>";
5809 else if (is_type (l
, T_RECURRENCES
))
5811 p
= "#<RECURRENCE TABLE>";
5816 snprintf (p
, STRBUFFSIZE
, "#<ERROR %d>", _get_type(l
));
5822 /*_ , C-style entry points */
5824 /*_ , kernel_print_sexp */
5825 SIG_CHKARRAY(kernel_print_sexp
) =
5826 { K_ANY
, REF_KEY(K_TYCH_OPTIONAL
), REF_OPER(is_environment
), };
5828 DEF_SIMPLE_CFUNC (ps0a2
, kernel_print_sexp
,0)
5830 WITH_2_ARGS(sexp
, lookup_env
);
5831 pko recurrences
= get_recurrences(sc
, sexp
);
5832 pko tracker
= recurrences_to_recur_tracker(recurrences
);
5833 /* $$IMPROVE ME Default to an environment that knows sharp
5835 return kernel_print_sexp_aux
5838 ((lookup_env
== K_INERT
) ? ground_env
: lookup_env
));
5840 /*_ , k_print_special_and_balk_p */
5841 /* Possibly print a replacement or prefix. Return 1 if we should now
5842 skip printing sexp (Because it's shared), 0 otherwise. */
5844 k_print_special_and_balk_p
5845 (klink
* sc
, pko tracker
, pko lookup_env
, pko sexp
)
5848 /* If this object is directly known to printer, print its symbol. */
5849 if(lookup_env
!= K_NIL
)
5851 pko slot
= reverse_find_slot_in_env_aux(lookup_env
,sexp
);
5854 putstr (sc
, "#,"); /* Reader is to convert the symbol */
5855 printatom (sc
, car(slot
));
5859 if(tracker
== K_NIL
)
5862 /* $$IMPROVE ME Parameterize this and share that parameterization
5863 with get_recurrences */
5864 switch(_get_type(sexp
))
5873 WITH_PSYC_UNBOXED(kt_recur_tracker
,tracker
, T_RECUR_TRACKER
, sc
);
5874 int index
= objtable_get_index(pdata
->objs
,pdata
->table_size
,sexp
);
5875 if(index
< 0) { return 0; }
5876 recur_entry
* slot
= &pdata
->entries
[index
];
5877 if(slot
->count
<= 1) { return 0; }
5879 if(slot
->seen_in_walk
)
5881 char *p
= sc
->strbuff
;
5882 snprintf (p
, STRBUFFSIZE
, "#%d", slot
->index_in_walk
);
5883 putchars (sc
, p
, strlen (p
));
5884 return 1; /* Skip printing the object */
5888 slot
->seen_in_walk
= 1;
5889 slot
->index_in_walk
= pdata
->current_index
;
5890 pdata
->current_index
++;
5891 char *p
= sc
->strbuff
;
5892 snprintf (p
, STRBUFFSIZE
, "#%d=", slot
->index_in_walk
);
5893 putchars (sc
, p
, strlen (p
));
5894 return 0; /* Still should print the object */
5897 /*_ , kernel_print_sexp_aux */
5898 SIG_CHKARRAY(kernel_print_sexp_aux
) =
5899 { K_ANY
, REF_OPER(is_recur_tracker
), REF_OPER(is_environment
), };
5901 DEF_SIMPLE_CFUNC (ps0a3
, kernel_print_sexp_aux
,0)
5903 WITH_3_ARGS(sexp
, recur_tracker
, lookup_env
);
5905 if(k_print_special_and_balk_p(sc
, recur_tracker
, lookup_env
, sexp
))
5907 if (is_vector (sexp
))
5910 CONTIN_4 (dcrry_4dotALL
, kernel_print_vec_from
, sc
, sexp
,
5911 mk_integer (0), recur_tracker
, lookup_env
);
5914 else if (!is_pair (sexp
))
5916 printatom (sc
, sexp
);
5919 /* $$FIX ME Recognize quote etc.
5921 That is hard since the quote operative is not currently defined
5922 as such and we no longer have syntax.
5924 else if (car (sexp
) == sc
->QUOTE
&& ok_abbrev (cdr (sexp
)))
5927 return kernel_print_sexp_aux (sc
, cadr (sexp
), recur_tracker
, lookup_env
);
5929 else if (car (sexp
) == sc
->QQUOTE
&& ok_abbrev (cdr (sexp
)))
5932 return kernel_print_sexp_aux (sc
, cadr (sexp
), recur_tracker
, lookup_env
);
5934 else if (car (sexp
) == sc
->UNQUOTE
&& ok_abbrev (cdr (sexp
)))
5937 return kernel_print_sexp_aux (sc
, cadr (sexp
), recur_tracker
, lookup_env
);
5939 else if (car (sexp
) == sc
->UNQUOTESP
&& ok_abbrev (cdr (sexp
)))
5942 return kernel_print_sexp_aux (sc
, cadr (sexp
), recur_tracker
, lookup_env
);
5947 CONTIN_0_RAW(REF_OBJ(k_print_terminate_list
), sc
);
5948 CONTIN_3 (dcrry_2dotALL
, kernel_print_list
, sc
, cdr (sexp
), recur_tracker
, lookup_env
);
5949 return kernel_print_sexp_aux (sc
, car (sexp
), recur_tracker
, lookup_env
);
5952 /*_ , print_value */
5953 DEF_BOXED_CURRIED(print_value
,
5956 REF_OPER (kernel_print_sexp
));
5957 /*_ . k_print_string */
5958 SIG_CHKARRAY(k_print_string
) = { REF_OPER(is_string
), };
5960 DEF_SIMPLE_CFUNC (ps0a1
, k_print_string
,T_NO_K
)
5963 putstr (sc
, string_value(str
));
5966 /*_ . k_print_terminate_list */
5967 /* $$RETHINK ME This may be the long way to do it. */
5969 BOX_OF(kt_string
) _k_string_rpar
=
5970 { T_STRING
| T_IMMUTABLE
,
5971 { ")", sizeof(")"), },
5974 BOX_OF(kt_vec2
) _k_list_string_rpar
=
5975 { T_PAIR
| T_IMMUTABLE
,
5976 { REF_OBJ(_k_string_rpar
), REF_KEY(K_NIL
)}
5979 DEF_BOXED_CURRIED(k_print_terminate_list
,
5981 REF_OBJ(_k_list_string_rpar
),
5982 REF_OPER(k_print_string
));
5984 RGSTR(ground
, "newline", REF_OBJ(k_newline
))
5986 BOX_OF(kt_string
) _k_string_newline
=
5987 { T_STRING
| T_IMMUTABLE
,
5988 { "\n", sizeof("\n"), }, };
5990 BOX_OF(kt_vec2
) _k_list_string_newline
=
5991 { T_PAIR
| T_IMMUTABLE
,
5992 { REF_OBJ(_k_string_newline
), REF_KEY(K_NIL
)}
5995 DEF_BOXED_CURRIED(k_newline
,
5997 REF_OBJ(_k_list_string_newline
),
5998 REF_OPER(k_print_string
));
6000 /*_ . kernel_print_list */
6002 DEF_CFUNC (ps0a3
, kernel_print_list
, REF_DESTR(kernel_print_sexp_aux
),0)
6005 WITH_3_ARGS(sexp
, recur_tracker
, lookup_env
);
6006 if(is_pair (sexp
)) { putstr (sc
, " "); }
6007 else if (sexp
!= K_NIL
) { putstr (sc
, " . "); }
6010 if(k_print_special_and_balk_p(sc
, recur_tracker
, lookup_env
, sexp
))
6014 CONTIN_3 (dcrry_3dotALL
, kernel_print_list
, sc
, cdr (sexp
), recur_tracker
, lookup_env
);
6015 return kernel_print_sexp_aux (sc
, car (sexp
), recur_tracker
, lookup_env
);
6017 if (is_vector (sexp
))
6019 /* $$RETHINK ME What does this even print? */
6020 CONTIN_3 (dcrry_3dotALL
, kernel_print_list
, sc
, K_NIL
, recur_tracker
, lookup_env
);
6021 return kernel_print_sexp_aux (sc
, sexp
, recur_tracker
, lookup_env
);
6026 printatom (sc
, sexp
);
6032 /*_ . kernel_print_vec_from */
6033 SIG_CHKARRAY(kernel_print_vec_from
) =
6035 REF_OPER(is_integer
),
6036 REF_OPER(is_recur_tracker
),
6037 REF_OPER(is_environment
), };
6038 DEF_SIMPLE_CFUNC (ps0a4
, kernel_print_vec_from
,0)
6040 WITH_4_ARGS(vec
,k_i
, recur_tracker
, lookup_env
);
6041 int i
= ivalue (k_i
);
6042 int len
= vector_len (vec
);
6050 pko elem
= vector_elem (vec
, i
);
6051 set_ivalue (k_i
, i
+ 1);
6052 CONTIN_4 (dcrry_4dotALL
, kernel_print_vec_from
, sc
, vec
, arg2
, recur_tracker
, lookup_env
);
6054 return kernel_print_sexp_aux (sc
, elem
, recur_tracker
, lookup_env
);
6057 /*_ , Kernel entry points */
6059 DEF_APPLICATIVE_W_DESTR(ps0a1
,k_write
,K_ANY_SINGLETON
,0,ground
, "write")
6062 klink_push_dyn_binding(sc
,K_PRINT_FLAG
,K_T
);
6063 return kernel_print_sexp(sc
,p
,K_INERT
);
6067 DEF_APPLICATIVE_W_DESTR(ps0a1
,k_display
,K_ANY_SINGLETON
,0,ground
, "display")
6070 klink_push_dyn_binding(sc
,K_PRINT_FLAG
,K_F
);
6071 return kernel_print_sexp(sc
,p
,K_INERT
);
6075 /*_ . tracing_say */
6076 /* $$TRANSITIONAL Until we have actual trace hook */
6077 SIG_CHKARRAY(tracing_say
) = { REF_OPER(is_string
), K_ANY
, };
6078 DEF_SIMPLE_CFUNC (ps0a2
, tracing_say
,T_NO_K
)
6080 WITH_2_ARGS(k_string
, value
);
6083 putstr (sc
, string_value(k_string
));
6089 /*_ . Equivalence */
6090 /*_ , Equivalence of atoms */
6091 SIG_CHKARRAY(eqv
) = { K_ANY
, K_ANY
, };
6092 DEF_SIMPLE_APPLICATIVE(b00a2
,eqv
,T_NO_K
,simple
,"equal?/2-atom-atom")
6100 const char * a_str
= string_value (a
);
6101 const char * b_str
= string_value (b
);
6102 if (a_str
== b_str
) { return 1; }
6103 return !strcmp(a_str
, b_str
);
6108 else if (is_number (a
))
6112 if (num_is_integer (a
) == num_is_integer (b
))
6113 return num_eq (nvalue (a
), nvalue (b
));
6117 else if (is_character (a
))
6119 if (is_character (b
))
6120 return charvalue (a
) == charvalue (b
);
6124 else if (is_port (a
))
6136 /*_ , Equivalence of containers */
6138 /*_ . Hash function */
6139 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
6142 hash_fn (const char *key
, int table_size
)
6144 unsigned int hashed
= 0;
6146 int bits_per_int
= sizeof (unsigned int) * 8;
6148 for (c
= key
; *c
; c
++)
6150 /* letters have about 5 bits in them */
6151 hashed
= (hashed
<< 5) | (hashed
>> (bits_per_int
- 5));
6154 return hashed
% table_size
;
6158 /* Quick and dirty hash function for pointers */
6160 ptr_hash_fn(void * ptr
, int table_size
)
6161 { return (long)ptr
% table_size
; }
6163 /*_ . binder/accessor maker */
6164 pko
make_keyed_variable(pko gen_binder
, pko gen_accessor
)
6166 /* Make a unique key object */
6167 pko key
= mk_void();
6168 pko binder
= wrap (mk_curried
6172 pko accessor
= wrap (mk_curried
6176 /* Curry and wrap the two things. */
6177 return LIST2 (binder
, accessor
);
6180 /*_ . Environment implementation */
6181 /*_ , New-style environment objects */
6185 /* T_ENV_FRAME is a vec2 used as a pair in the env tree. It
6186 indicates a frame boundary.
6188 /* T_ENV_PAIR is another vec2 used as a pair in the env tree. It
6189 indicates no frame boundary.
6192 /* Other types are (hackishly) still shared with the vanilla types:
6194 A vector is interpeted as a hash table vector that is "as if" it
6195 were a list of T_ENV_PAIR. Each element is an alist of bindings.
6196 It can only hold symbol bindings, not keyed bindings, because we
6197 can't hash keyed bindings.
6199 A pair is interpreted as a binding of something and value. That
6200 something can be either a symbol or a key (void object). It is
6201 held directly by an T_ENV_FRAME or T_ENV_PAIR (or "as if", by the
6202 alists of a hash table vector).
6206 /*_ . Object functions */
6208 DEF_T_PRED (is_environment
, T_ENV_FRAME
,ground
,"environment?/o1");
6210 /*_ , New environment implementation */
6212 #ifndef USE_ALIST_ENV
6214 find_slot_in_env_vector (pko eobj
, pko hdl
)
6216 for (; eobj
!= K_NIL
; eobj
= unsafe_v2cdr (eobj
))
6218 assert (is_pair (eobj
));
6219 pko slot
= unsafe_v2car (eobj
);
6220 assert (is_pair (slot
));
6221 if (unsafe_v2car (slot
) == hdl
)
6230 reverse_find_slot_in_env_vector (pko eobj
, pko value
)
6232 for (; eobj
!= K_NIL
; eobj
= unsafe_v2cdr (eobj
))
6234 assert (is_pair (eobj
));
6235 pko slot
= unsafe_v2car (eobj
);
6236 assert (is_pair (slot
));
6237 if (unsafe_v2cdr (slot
) == value
)
6247 * If we're using vectors, each frame of the environment may be a hash
6248 * table: a vector of alists hashed by variable name. In practice, we
6249 * use a vector only for the initial frame; subsequent frames are too
6250 * small and transient for the lookup speed to out-weigh the cost of
6251 * making a new vector.
6254 make_new_frame(pko old_env
)
6257 #ifndef USE_ALIST_ENV
6258 /* $$IMPROVE ME Make a better test for whether to make vector. */
6259 /* The interaction-environment has about 300 variables in it. */
6260 if (old_env
== K_NIL
)
6262 new_frame
= mk_vector (461, K_NIL
);
6270 return v2cons (T_ENV_FRAME
, new_frame
, old_env
);
6274 new_slot_spec_in_env (pko env
, pko variable
, pko value
)
6276 assert(is_environment(env
));
6277 assert(is_symbol(variable
));
6278 pko slot
= mcons (variable
, value
);
6279 pko car_env
= unsafe_v2car (env
);
6280 #ifndef USE_ALIST_ENV
6281 if (is_vector (car_env
))
6283 int location
= hash_fn (symname (0,variable
), vector_len (car_env
));
6285 set_vector_elem (car_env
, location
,
6287 vector_elem (car_env
, location
)));
6292 pko new_list
= v2cons (T_ENV_PAIR
, slot
, car_env
);
6293 unsafe_v2set_car (env
, new_list
);
6297 enum env_frame_search_restriction
6300 env_fsr_only_coming_frame
,
6301 env_fsr_only_this_frame
,
6304 /* This explores a tree of bindings, punctuated by frames past which
6305 we sometimes don't search. */
6307 find_slot_in_env_aux (pko eobj
, pko hdl
, int restr
)
6311 _kt_tag type
= _get_type (eobj
);
6314 /* We have a slot (Which for now is just a pair) */
6316 if(unsafe_v2car (eobj
) == hdl
)
6320 #ifndef USE_ALIST_ENV
6323 /* Only for symbols. */
6324 if(!is_symbol (hdl
)) { return 0; }
6325 int location
= hash_fn (symname (0,hdl
), vector_len (eobj
));
6326 pko el
= vector_elem (eobj
, location
);
6327 return find_slot_in_env_vector (el
, hdl
);
6330 /* We have some sort of env pair */
6332 /* Check whether we should keep looking. */
6337 case env_fsr_only_coming_frame
:
6338 restr
= env_fsr_only_this_frame
;
6340 case env_fsr_only_this_frame
:
6344 "find_slot_in_env_aux: Bad restriction enum: %d", restr
);
6349 /* Explore car before cdr */
6350 pko found
= find_slot_in_env_aux (unsafe_v2car (eobj
), hdl
, restr
);
6351 if(found
) { return found
; }
6352 return find_slot_in_env_aux (unsafe_v2cdr (eobj
),hdl
,restr
);
6355 /* No other type should be found */
6357 "find_slot_in_env_aux: Bad type: %d", type
);
6358 return 0; /* NOTREACHED */
6363 find_slot_in_env (pko env
, pko hdl
, int all
)
6365 assert(is_environment(env
));
6366 enum env_frame_search_restriction restr
=
6367 all
? env_fsr_all
: env_fsr_only_coming_frame
;
6368 return find_slot_in_env_aux(env
,hdl
,restr
);
6370 /*_ , Reverse find-slot */
6371 /*_ . env_confirm_slot */
6373 env_confirm_slot(pko env
, pko slot
)
6375 assert(is_pair(slot
));
6377 (find_slot_in_env_aux(env
,unsafe_v2car(slot
),env_fsr_all
) == slot
);
6379 /*_ . reverse_find_slot_in_env_aux2 */
6381 reverse_find_slot_in_env_aux2(pko env
, pko eobj
, pko value
)
6385 _kt_tag type
= _get_type (eobj
);
6388 /* We have a slot (Which for now is just a pair) */
6390 if((unsafe_v2cdr (eobj
) == value
)
6391 && env_confirm_slot(env
, eobj
))
6395 #ifndef USE_ALIST_ENV
6398 /* $$IMPROVE ME Create a reverse-lookup vector if we come here
6399 and there is none. */
6401 for(i
= 0; i
< vector_len (eobj
); ++i
)
6403 pko slot
= reverse_find_slot_in_env_vector(vector_elem (eobj
, i
), value
);
6405 env_confirm_slot(env
, slot
))
6411 /* We have some sort of env pair */
6416 /* Explore car before cdr */
6418 reverse_find_slot_in_env_aux2 (env
, unsafe_v2car (eobj
), value
);
6419 if(found
&& env_confirm_slot(env
, found
))
6422 reverse_find_slot_in_env_aux2 (env
, unsafe_v2cdr (eobj
), value
);
6423 if(found
&& env_confirm_slot(env
, found
))
6428 /* No other type should be found */
6430 "reverse_find_slot_in_env_aux2: Bad type: %d", type
);
6431 return 0; /* NOTREACHED */
6435 /*_ . reverse_find_slot_in_env_aux */
6437 reverse_find_slot_in_env_aux (pko env
, pko value
)
6439 assert(is_environment(env
));
6440 return reverse_find_slot_in_env_aux2(env
, env
, value
);
6443 /*_ . Entry point */
6444 /* Exposed for testing */
6445 /* NB, args are in different order than in the helpers */
6446 SIG_CHKARRAY(reverse_find_slot_in_env
) =
6447 { K_ANY
, REF_OPER(is_environment
), };
6448 DEF_SIMPLE_APPLICATIVE (ps0a2
, reverse_find_slot_in_env
,T_NO_K
,unsafe
, "reverse-lookup")
6450 WITH_2_ARGS(value
,env
);
6452 pko slot
= reverse_find_slot_in_env_aux(env
, value
);
6453 if(slot
) { return car(slot
); }
6456 KERNEL_ERROR_0(sc
, "reverse_find_slot_in_env: No match");
6460 /*_ . reverse-binds?/2 */
6461 /* $$IMPROVE ME Maybe combine these */
6462 DEF_APPLICATIVE_W_DESTR(b00a2
,reverse_binds_p
,
6463 REF_DESTR(reverse_find_slot_in_env
),
6464 T_NO_K
,simple
,"reverse-binds?/2")
6466 WITH_2_ARGS(value
,env
);
6467 return reverse_find_slot_in_env_aux(env
, value
) ? 1 : 0;
6469 /*_ , Shared functions */
6472 new_frame_in_env (klink
* sc
, pko old_env
)
6474 sc
->envir
= make_new_frame (old_env
);
6478 set_slot_in_env (pko slot
, pko value
)
6480 assert (is_pair (slot
));
6481 set_cdr (0, slot
, value
);
6485 slot_value_in_env (pko slot
)
6488 assert (is_pair (slot
));
6492 /*_ , Keyed static bindings */
6494 /*_ , Making them */
6495 /* Make a new frame containing just the one keyed static variable. */
6497 env_plus_keyed_var (pko key
, pko value
, pko old_env
)
6499 pko slot
= cons (key
, value
);
6500 return v2cons (T_ENV_FRAME
, slot
, old_env
);
6502 /*_ , Finding them */
6503 /* find_slot_in_env works for this too. */
6506 SIG_CHKARRAY(klink_ksb_binder
) =
6507 { REF_OPER(is_key
), K_ANY
, REF_OPER(is_environment
), };
6508 DEF_SIMPLE_CFUNC(ps0a3
,klink_ksb_binder
,T_NO_K
)
6510 WITH_3_ARGS(key
, value
, env
);
6511 /* Check that env is in fact a environment. */
6512 if(!is_environment(env
))
6515 "klink_ksb_binder: Arg 2 must be an environment: ",
6518 /* Return a new environment with just that binding. */
6519 return env_plus_keyed_var(key
, value
, env
);
6523 SIG_CHKARRAY(klink_ksb_accessor
) =
6524 { REF_OPER(is_key
), };
6525 DEF_SIMPLE_CFUNC(ps0a1
,klink_ksb_accessor
,T_NO_K
)
6528 pko value
= find_slot_in_env(sc
->envir
,key
,1);
6531 KERNEL_ERROR_0(sc
, "klink_ksb_accessor: No binding found");
6534 return slot_value_in_env (value
);
6537 /*_ , make_keyed_static_variable */
6538 RGSTR(ground
, "make-keyed-static-variable", REF_OPER(make_keyed_static_variable
))
6539 DEF_CFUNC(p00a0
, make_keyed_static_variable
,K_NO_TYPE
,T_NO_K
)
6541 return make_keyed_variable(
6542 REF_OPER(klink_ksb_binder
),
6543 REF_OPER (klink_ksb_accessor
));
6545 /*_ , Building environments */
6546 /* Argobject is checked internally, so K_ANY */
6547 DEF_APPLICATIVE_W_DESTR(ps0a1
,make_environment
,K_ANY
,T_NO_K
,ground
, "make-environment")
6549 WITH_1_ARGS(parents
);
6550 /* $$IMPROVE ME Factor this so we only call get_list_metrics_aux
6551 once on this object. */
6553 get_list_metrics_aux(parents
, metrics
);
6554 pko typecheck
= REF_OPER(is_environment
);
6555 /* This will reject dotted lists */
6556 if(!typecheck_repeat(sc
,parents
,&typecheck
,1,1))
6558 KERNEL_ERROR_0 (sc
, "make_environment: argobject must be a list of environments");
6561 /* Collect the parent environments. */
6563 pko rv_par_list
= K_NIL
;
6564 for(i
= 0; i
< metrics
[lm_num_pairs
]; ++i
, parents
= pair_cdr(0, parents
))
6566 pko pare
= pair_car(0, parents
);
6567 rv_par_list
= v2cons (T_ENV_PAIR
, pare
, rv_par_list
);
6570 /* Reverse the list in place. */
6573 par_list
= unsafe_v2reverse_in_place(K_NIL
, rv_par_list
);
6575 /* $$IMPROVE ME Check for redundant environments and skip them.
6576 Check only *previous* environments, because we still need to
6577 search correctly. When recurrences walks environments too, we
6578 can use that to find them. */
6579 /* $$IMPROVE ME Add to environment information to block rechecks. */
6581 /* Return a new environment with all of those as parents. */
6582 return make_new_frame(par_list
);
6585 RGSTR(simple
,"$binds?/2", REF_OPER(bindsp_1
))
6586 SIG_CHKARRAY(bindsp_1
) =
6587 { REF_OPER(is_environment
), REF_OPER(is_symbol
), };
6588 DEF_SIMPLE_CFUNC(bs0a2
,bindsp_1
,T_NO_K
)
6590 WITH_2_ARGS(env
, sym
);
6591 return find_slot_in_env(env
, sym
, 1) ? 1 : 0;
6593 /*_ , find-binding */
6594 DEF_APPLICATIVE_W_DESTR(ps0a2
,find_binding
,REF_DESTR(bindsp_1
),T_NO_K
,ground
,"find-binding")
6596 WITH_2_ARGS(env
, sym
);
6597 pko binding
= find_slot_in_env(env
, sym
, 1);
6600 return cons(K_T
,slot_value_in_env (binding
));
6604 return cons(K_F
,K_INERT
);
6609 /*_ , Enumerations */
6610 enum klink_stack_cell_types
6619 ksct_arg_barrier
, /* Barrier to propagating pseudo-env. */
6623 struct dump_stack_frame
6628 struct stack_binding
6640 struct stack_profiling
6653 typedef struct dump_stack_frame_cell
6655 enum klink_stack_cell_types type
;
6659 struct dump_stack_frame frame
;
6660 struct stack_binding binding
;
6661 struct stack_guards guards
;
6662 struct stack_profiling profiling
;
6663 struct stack_arg pseudoenv
;
6665 } dump_stack_frame_cell
;
6670 dump_stack_initialize (klink
* sc
)
6676 stack_empty (klink
* sc
)
6677 { return sc
->dump
== 0; }
6681 klink_pop_cont (klink
* sc
)
6683 _kt_spagstack rv_pseudoenvs
= 0;
6685 /* Always return frame, which sc->dump will be set to. */
6686 /* for(frame = sc->dump; frame != 0; frame = frame->next) */
6695 const _kt_spagstack frame
= sc
->dump
;
6696 if(frame
->type
== ksct_frame
)
6698 const struct dump_stack_frame
*pdata
= &frame
->data
.frame
;
6699 sc
->next_func
= pdata
->ff
;
6700 sc
->envir
= pdata
->envir
;
6702 _kt_spagstack final_frame
= frame
->next
;
6704 /* Add the collected pseudo-env elements */
6705 while(rv_pseudoenvs
)
6707 _kt_spagstack el
= rv_pseudoenvs
;
6708 _kt_spagstack new_top
= rv_pseudoenvs
->next
;
6709 el
->next
= final_frame
;
6711 rv_pseudoenvs
= new_top
;
6713 sc
->dump
= final_frame
;
6718 if(frame
->type
== ksct_profile
)
6720 struct stack_profiling
* pdata
= &frame
->data
.profiling
;
6721 k_profiling_done_frame(sc
,pdata
);
6722 sc
->dump
= frame
->next
;
6725 else if( frame
->type
== ksct_args
)
6727 struct stack_arg
* old_pe
= &frame
->data
.pseudoenv
;
6728 if(old_pe
->frame_depth
> 0)
6730 /* Make a copy, to be re-added lower down */
6731 _kt_spagstack new_pseudoenv
=
6733 GC_MALLOC (sizeof (dump_stack_frame_cell
));
6734 struct stack_arg
* new_pe
= &new_pseudoenv
->data
.pseudoenv
;
6735 new_pe
->vec
= old_pe
->vec
;
6736 new_pe
->frame_depth
= old_pe
->frame_depth
- 1;
6738 new_pseudoenv
->type
= ksct_args
;
6739 new_pseudoenv
->next
= rv_pseudoenvs
;
6740 rv_pseudoenvs
= new_pseudoenv
;
6743 sc
->dump
= frame
->next
;
6745 else if( frame
->type
== ksct_arg_barrier
)
6747 errx( 0, "Not allowed");
6749 sc
->dump
= frame
->next
;
6753 sc
->dump
= frame
->next
;
6759 static _kt_spagstack
6761 (_kt_spagstack old_frame
, pko ff
, pko env
)
6763 _kt_spagstack frame
=
6765 GC_MALLOC (sizeof (dump_stack_frame_cell
));
6766 struct dump_stack_frame
* pdata
= &frame
->data
.frame
;
6770 frame
->type
= ksct_frame
;
6771 frame
->next
= old_frame
;
6777 klink_push_cont (klink
* sc
, pko ff
)
6778 { sc
->dump
= klink_push_cont_aux(sc
->dump
, ff
, sc
->envir
); }
6780 /*_ , Dynamic bindings */
6782 /* We do not pop dynamic bindings, only frames. */
6783 /* We deal with dynamic bindings in the context of the interpreter so
6784 that in the future we can cache them. */
6786 klink_push_dyn_binding (klink
* sc
, pko key
, pko value
)
6788 _kt_spagstack frame
=
6790 GC_MALLOC (sizeof (dump_stack_frame_cell
));
6791 struct stack_binding
*pdata
= &frame
->data
.binding
;
6794 pdata
->value
= value
;
6796 frame
->type
= ksct_binding
;
6797 frame
->next
= sc
->dump
;
6803 klink_find_dyn_binding(klink
* sc
, pko key
)
6805 _kt_spagstack frame
= sc
->dump
;
6814 if(frame
->type
== ksct_binding
)
6816 const struct stack_binding
*pdata
= &frame
->data
.binding
;
6817 if(pdata
->key
== key
)
6818 { return pdata
->value
; }
6820 frame
= frame
->next
;
6825 /*_ . klink_push_guards */
6826 static _kt_spagstack
6828 (_kt_spagstack old_frame
, pko guards
, pko envir
, int exit
)
6830 _kt_spagstack frame
=
6832 GC_MALLOC (sizeof (dump_stack_frame_cell
));
6833 struct stack_guards
* pdata
= &frame
->data
.guards
;
6834 pdata
->guards
= guards
;
6835 pdata
->envir
= envir
;
6837 frame
->type
= exit
? ksct_exit_guards
: ksct_entry_guards
;
6838 frame
->next
= old_frame
;
6841 /*_ . get_guards_lo1st */
6842 /* Get a list of guard entries, root-most on top. */
6844 get_guards_lo1st(_kt_spagstack frame
)
6847 for(; frame
!= 0; frame
= frame
->next
)
6849 if((frame
->type
== ksct_entry_guards
) ||
6850 (frame
->type
== ksct_exit_guards
))
6852 list
= cons(mk_continuation(frame
), list
);
6860 /*_ , set_nth_arg */
6862 /* Set the nth arg */
6863 /* Unused, probably for a while, probably will never be used in this
6866 set_nth_arg(klink
* sc
, int n
, pko value
)
6868 _kt_spagstack frame
= sc
->dump
;
6870 for(frame
= sc
->dump
; frame
!= 0; frame
= frame
->next
)
6872 if(frame
->type
== ksct_args
)
6876 frame
->data
.arg
= value
;
6883 /* If we got here we never encountered the target. */
6887 /*_ . Store from value */
6888 /*_ , push_arg_raw */
6890 push_arg_raw(_kt_spagstack old_frame
, pko value
, int frame_depth
)
6892 _kt_spagstack frame
=
6894 GC_MALLOC (sizeof (dump_stack_frame_cell
));
6896 frame
->data
.pseudoenv
.vec
= value
;
6897 frame
->data
.pseudoenv
.frame_depth
= frame_depth
;
6898 frame
->type
= ksct_args
;
6899 frame
->next
= old_frame
;
6905 k_do_store(klink
* sc
, pko functor
, pko value
)
6907 WITH_PSYC_UNBOXED( kt_opstore
, functor
, T_STORE
, sc
);
6908 /* $$MAKE ME SAFE do_destructure must be safe vs resuming. Error if
6909 not T_NO_K. Don't try to maybe resume, because so far we never
6912 pko vec
= do_destructure( sc
, value
, pdata
->destr
);
6913 /* Push that as arg */
6914 sc
->dump
= push_arg_raw (sc
->dump
, vec
, pdata
->frame_depth
);
6917 /*_ . Load to value */
6918 /*_ , get_nth_arg */
6920 get_nth_arg( _kt_spagstack frame
, int n
)
6923 for(; frame
!= 0; frame
= frame
->next
)
6925 if(frame
->type
== ksct_args
)
6928 { return frame
->data
.pseudoenv
.vec
; }
6933 /* If we got here we never encountered the target. */
6937 /*_ , k_load_recurse */
6938 /* $$IMPROVE ME Add a shortcut for accessing value without ever
6941 k_load_recurse( _kt_spagstack frame
, pko tree
)
6943 if(_get_type( tree
) == T_PAIR
)
6945 WITH_PSYC_UNBOXED( kt_vec2
, tree
, T_PAIR
, 0 );
6946 if( is_integer( pdata
->_car
) && is_integer( pdata
->_cdr
))
6948 /* Pair of integers: Look up that item, look up secondary
6950 const int n
= ivalue( pdata
->_car
);
6951 const int m
= ivalue( pdata
->_cdr
);
6952 pko vec
= get_nth_arg( frame
, n
);
6954 assert( is_vector( vec
));
6955 pko value
= basvector_elem( vec
, m
);
6961 /* Pair, not integers: Explore car and cdr, return cons of them. */
6963 k_load_recurse( frame
, pdata
->_car
),
6964 k_load_recurse( frame
, pdata
->_cdr
));
6969 /* Anything else: Return it literally. */
6975 /* T_LOAD C-destructures as a singleton. It will contain a tree */
6976 /* This may largely take over for decurriers. */
6978 k_do_load(klink
* sc
, pko functor
, pko value
)
6980 WITH_PSYC_UNBOXED( pko
, functor
, T_LOAD
, sc
);
6981 return k_load_recurse( sc
->dump
, *pdata
);
6984 /*_ , Stack ancestry */
6985 /*_ . frame_is_ancestor_of */
6986 int frame_is_ancestor_of(_kt_spagstack frame
, _kt_spagstack other
)
6988 /* Walk from other towards root. Return 1 if we ever encounter
6989 frame, otherwise 0. */
6990 for(; other
!= 0; other
= other
->next
)
6997 /*_ . special_dynxtnt */
6998 /* Make a child of dynamic extent OUTER that evals with dynamic
6999 environment ENVIR continues normally to PROX_DEST. */
7000 _kt_spagstack special_dynxtnt
7001 (_kt_spagstack outer
, _kt_spagstack prox_dest
, pko envir
)
7004 klink_push_cont_aux(outer
,
7005 mk_curried(dcrry_2A01VLL
,
7006 LIST1(mk_continuation(prox_dest
)),
7007 REF_OPER(invoke_continuation
)),
7010 /*_ . curr_frame_depth */
7011 int curr_frame_depth(_kt_spagstack frame
)
7013 /* Walk towards root, counting. */
7015 for(; frame
!= 0; frame
= frame
->next
, count
++)
7019 /*_ , Continuations */
7023 _kt_spagstack frame
;
7028 DEF_T_PRED (is_continuation
, T_CONTINUATION
,ground
, "continuation?/o1");
7031 mk_continuation (_kt_spagstack frame
)
7033 ALLOC_BOX_PRESUME (continuation_t
, T_CONTINUATION
);
7034 pdata
->frame
= frame
;
7035 return PTR2PKO(pbox
);
7038 static _kt_spagstack
7041 WITH_PSYC_UNBOXED(continuation_t
,p
,T_CONTINUATION
,0);
7042 return pdata
->frame
;
7045 /*_ . Continuations WRT interpreter */
7046 /*_ , current_continuation */
7048 current_continuation (klink
* sc
)
7050 return mk_continuation (sc
->dump
);
7053 /*_ , invoke_continuation */
7054 /* DOES NOT RETURN */
7055 /* Control is resumed at _klink_cycle */
7057 /* Static and not directly available to Kernel, it's the eventual
7058 target of continuation_to_applicative. */
7059 SIG_CHKARRAY(invoke_continuation
) =
7060 { REF_OPER(is_continuation
), K_ANY
, };
7061 DEF_SIMPLE_CFUNC(vs0a2
,invoke_continuation
,T_NO_K
)
7063 WITH_2_ARGS (p
, value
);
7064 assert(is_continuation(p
));
7066 { sc
->dump
= cont_dump (p
); }
7068 longjmp (sc
->pseudocontinuation
, 1);
7071 /* Add the appropriate guard, if any, and return the new proximate
7075 (_kt_spagstack prox_dest
, _kt_spagstack to_contain
,
7076 pko guard_list
, pko envir
, _kt_spagstack outer
)
7080 for(x
= guard_list
; x
!= K_NIL
; x
= cdr(x
))
7082 pko selector
= car(car(x
));
7083 assert(is_continuation(selector
));
7084 if(frame_is_ancestor_of(cont_dump(selector
), to_contain
))
7086 /* Call has to take place in the dynamic extent of the
7087 next frame around this set of guards, so that the
7088 interceptor has access to dynamic bindings, but then
7089 control has to continue normally to the next guard or
7090 finally to the destination.
7092 So we extend the next frame with a call to
7093 invoke_continuation, currying the next destination in the
7094 chain. That does not check guards, so in effect it
7095 continues normally. Then we extend that with a call to
7096 the interceptor, currying an continuation->applicative of
7097 the guards' outer continuation.
7099 NB, continuation->applicative is correct. It would be
7100 wrong to shortcircuit it. Although there are no guards
7101 between there and the outer continuation, the
7102 continuation we pass might be called from another dynamic
7103 context. But it needs to be unwrapped.
7105 pko wrapped_interceptor
= cadr(car(x
));
7106 assert(is_applicative(wrapped_interceptor
));
7107 pko interceptor
= unwrap(0,wrapped_interceptor
);
7108 assert(is_operative(interceptor
));
7110 _kt_spagstack med_frame
=
7111 special_dynxtnt(outer
, prox_dest
, envir
);
7113 klink_push_cont_aux(med_frame
,
7114 mk_curried(dcrry_2VLLdotALL
,
7115 LIST1(continuation_to_applicative(mk_continuation(outer
))),
7119 /* We use only the first match so end the loop. */
7125 /*_ , add_guard_chain */
7128 (_kt_spagstack prox_dest
, pko guard_frame_list
, _kt_spagstack to_contain
, int exit
)
7131 const enum klink_stack_cell_types tag
7132 = exit
? ksct_exit_guards
: ksct_entry_guards
;
7133 for( ; guard_frame_list
!= K_NIL
; guard_frame_list
= cdr(guard_frame_list
))
7135 _kt_spagstack guard_frame
= cont_dump(car(guard_frame_list
));
7136 if(guard_frame
->type
== tag
)
7138 struct stack_guards
* pguards
= &guard_frame
->data
.guards
;
7140 add_guard(prox_dest
,
7144 exit
? guard_frame
->next
: guard_frame
);
7149 /*_ , continue_abnormally */
7150 /*** Arrange to "walk" from current continuation to c, passing control
7151 thru appropriate guards. ***/
7152 SIG_CHKARRAY(continue_abnormally
) =
7153 { REF_OPER(is_continuation
), K_ANY
, };
7154 /* I don't give this T_NO_K even though technically it longjmps
7155 rather than pushing into the eval loop. In the future we may
7156 distinguish those two cases. */
7157 DEF_SIMPLE_CFUNC(ps0a2
,continue_abnormally
,0)
7159 WITH_2_ARGS(c
,value
);
7161 _kt_spagstack source
= sc
->dump
;
7162 _kt_spagstack destination
= cont_dump (c
);
7164 /*** Find the guard frames on the intermediate path. ***/
7166 /* Control is exiting our current frame, so collect guards from
7167 there towards root. What we get is lowest first. */
7168 pko exiting_lo1st
= get_guards_lo1st(source
);
7169 /* Control is entering c's frame, so collect guards from there
7170 towards root. Again it's lowest first. */
7171 pko entering_lo1st
= get_guards_lo1st(destination
);
7173 /* Remove identical entries from the top, thus removing any merged
7175 while((exiting_lo1st
!= K_NIL
) &&
7176 (entering_lo1st
!= K_NIL
) &&
7177 (cont_dump(car(exiting_lo1st
)) == cont_dump(car(entering_lo1st
))))
7179 exiting_lo1st
= cdr(exiting_lo1st
);
7180 entering_lo1st
= cdr(entering_lo1st
);
7185 /*** Construct a string of calls to the appropriate guards, ending
7186 at destination. We collect in the reverse of the order that
7187 they will be run, so collect from "entering" first, from
7188 highest to lowest, then collect from "exiting", from lowest to
7191 _kt_spagstack prox_dest
= destination
;
7193 pko entering_hi1st
= reverse(sc
, entering_lo1st
);
7194 prox_dest
= add_guard_chain(prox_dest
, entering_hi1st
, destination
, 0);
7195 prox_dest
= add_guard_chain(prox_dest
, exiting_lo1st
, source
, 1);
7197 invoke_continuation(sc
, mk_continuation(prox_dest
), value
);
7198 return value
; /* NOTREACHED */
7203 SIG_CHKARRAY(call_cc
) = { REF_OPER(is_combiner
), };
7204 DEF_SIMPLE_APPLICATIVE(ps0a1
,call_cc
,0,ground
, "call/cc")
7206 WITH_1_ARGS(combiner
);
7207 pko cc
= current_continuation(sc
);
7208 return kernel_eval_aux(sc
,combiner
,LIST1(cc
),sc
->envir
);
7210 /*_ , extend-continuation */
7211 /*_ . extend_continuation_aux */
7213 extend_continuation_aux(_kt_spagstack old_frame
, pko a
, pko env
)
7215 _kt_spagstack frame
= klink_push_cont_aux(old_frame
, a
, env
);
7216 return mk_continuation(frame
);
7218 /*_ . extend_continuation */
7219 SIG_CHKARRAY(extend_continuation
) =
7220 { REF_OPER(is_continuation
),
7221 REF_OPER(is_applicative
),
7222 REF_KEY(K_TYCH_OPTIONAL
),
7223 REF_OPER(is_environment
),
7225 DEF_SIMPLE_APPLICATIVE(ps0a3
, extend_continuation
,T_NO_K
,ground
, "extend-continuation")
7227 WITH_3_ARGS(c
, a
, env
);
7228 assert(is_applicative(a
));
7229 if(env
== K_INERT
) { env
= make_new_frame(K_NIL
); }
7230 return extend_continuation_aux(cont_dump(c
), unwrap(sc
,a
), env
);
7232 /*_ , continuation->applicative */
7233 SIG_CHKARRAY(continuation_to_applicative
) = { REF_OPER(is_continuation
), };
7234 DEF_SIMPLE_APPLICATIVE(p00a1
,continuation_to_applicative
,T_NO_K
,ground
, "continuation->applicative")
7238 wrap(mk_curried (dcrry_2A01VLL
, LIST1(c
), REF_OPER(continue_abnormally
)));
7241 /*_ , guard-continuation */
7242 /* Each guard list is repeat (list continuation applicative) */
7243 /* We'd like to spec that applicative take 2 args, a continuation and
7244 a value, and be wrapped exactly once. */
7245 SIG_CHKARRAY(guard_continuation
) =
7246 { K_ANY
, REF_OPER(is_continuation
), K_ANY
, };
7247 DEF_SIMPLE_APPLICATIVE(ps0a3
,guard_continuation
,T_NO_K
,ground
, "guard-continuation")
7249 WITH_3_ARGS(entry_guards
, c
, exit_guards
);
7250 /* The spec wants an outer continuation to keeps sets of guards from
7251 being mixed together if there are two calls to guard_continuation
7252 with the same c. But that happens naturally here, so it seems
7255 /* $$IMPROVE ME Copy the es of both lists of guards. */
7256 _kt_spagstack frame
= cont_dump(c
);
7257 if(entry_guards
!= K_NIL
)
7259 frame
= klink_push_guards(frame
, entry_guards
, sc
->envir
, 0);
7261 if(exit_guards
!= K_NIL
)
7263 frame
= klink_push_guards(frame
, exit_guards
, sc
->envir
, 1);
7266 pko inner_cont
= mk_continuation(frame
);
7270 /*_ , guard-dynamic-extent */
7271 SIG_CHKARRAY(guard_dynamic_extent
) =
7273 REF_OPER(is_finite_list
),
7274 REF_OPER(is_applicative
),
7275 REF_OPER(is_finite_list
),
7277 /* DOES NOT RETURN */
7278 DEF_SIMPLE_APPLICATIVE(ps0a3
,guard_dynamic_extent
,0,ground
, "guard-dynamic-extent")
7280 WITH_3_ARGS(entry
,app
,exit
);
7281 pko cont
= guard_continuation(sc
,entry
,current_continuation(sc
),exit
);
7282 pko cont2
= extend_continuation(sc
,cont
, app
, sc
->envir
);
7283 /* Skip directly into the new continuation, don't invoke the
7285 invoke_continuation(sc
,cont2
, K_NIL
);
7290 /*_ , Keyed dynamic bindings */
7291 /*_ . klink_kdb_binder */
7292 SIG_CHKARRAY(klink_kdb_binder
) =
7293 { REF_OPER(is_key
), K_ANY
, REF_OPER(is_combiner
), };
7294 DEF_SIMPLE_CFUNC(ps0a3
,klink_kdb_binder
,T_NO_K
)
7296 WITH_3_ARGS(key
, value
, combiner
);
7297 /* Check that combiner is in fact a combiner. */
7298 if(!is_combiner(combiner
))
7301 "klink_kdb_binder: Arg 2 must be a combiner: ",
7304 /* Push the new binding. */
7305 klink_push_dyn_binding(sc
, key
, value
);
7306 /* $$IMPROVE ME In general, should can control calling better than
7307 this. Possibly do this thru invoke_continuation, except we're
7308 not arbitrarily changing continuations. */
7309 /* $$IMPROVE ME Want a better way to control what environment to
7310 push in. In fact, that's much like a dynamic variable. */
7311 /* $$IMPROVE ME Want a better and cheaper way to make empty
7312 environments. The vector thing should be controlled by a hint. */
7313 /* Make an empty static environment */
7314 new_frame_in_env(sc
,K_NIL
);
7315 /* Push combiner in that environment. */
7316 klink_push_cont(sc
,combiner
);
7317 /* And call it with no operands. */
7320 /* Combines with data to become "an applicative that takes two
7321 arguments, the second of which must be a oper. It calls its
7322 second argument with no operands (nil operand tree) in a fresh empty
7323 environment, and returns the result." */
7324 /*_ . klink_kdb_accessor */
7325 SIG_CHKARRAY(klink_kdb_accessor
) =
7326 { REF_OPER(is_key
), };
7327 DEF_SIMPLE_CFUNC(ps0a1
,klink_kdb_accessor
,T_NO_K
)
7330 pko value
= klink_find_dyn_binding(sc
,key
);
7333 KERNEL_ERROR_0(sc
, "klink_kdb_accessor: No binding found");
7337 /* Combines with data to become "an applicative that takes zero
7338 arguments. If the call to a occurs within the dynamic extent of a
7339 call to b, then a returns the value of the first argument passed to
7340 b in the smallest enclosing dynamic extent of a call to b. If the
7341 call to a is not within the dynamic extent of any call to b, an
7344 /*_ . make_keyed_dynamic_variable */
7345 RGSTR(ground
, "make-keyed-dynamic-variable", REF_OPER(make_keyed_dynamic_variable
))
7347 DEF_CFUNC(p00a0
, make_keyed_dynamic_variable
,K_NO_TYPE
,T_NO_K
)
7349 return make_keyed_variable(
7350 REF_OPER(klink_kdb_binder
),
7351 REF_OPER (klink_kdb_accessor
));
7356 typedef struct profiling_data
7364 profiling_data
* entries
;
7368 /*_ . Current data */
7369 /* This may be moved to per interpreter, or even more fine-grained. */
7370 /* This may not always be the way we get elapsed counts. */
7371 static long k_profiling_count
= 0;
7372 static int k_profiling_p
= 0; /* Are we profiling now? */
7373 /* If we are profiling, init this if it's not initted */
7374 static kt_profile_table k_profiling_table
= { 0 };
7375 /*_ . Dealing with table (All will be shared with other lookup tables) */
7378 init_profile_table(kt_profile_table
* p_table
, int initial_size
)
7380 p_table
->objs
= initial_size
?
7381 GC_MALLOC(sizeof(pko
) * initial_size
) : 0;
7382 p_table
->entries
= initial_size
?
7383 GC_MALLOC(sizeof(profiling_data
) * initial_size
) : 0;
7384 p_table
->alloced_size
= initial_size
;
7385 p_table
->table_size
= 0;
7387 /*_ , Increase its size */
7389 enlarge_profile_table(kt_profile_table
* p_table
)
7391 if(p_table
->table_size
== p_table
->alloced_size
)
7393 p_table
->alloced_size
*= 2;
7394 p_table
->entries
= GC_REALLOC(p_table
->entries
, sizeof(profiling_data
) * p_table
->alloced_size
);
7395 p_table
->objs
= GC_REALLOC(p_table
->objs
, sizeof(pko
) * p_table
->alloced_size
);
7400 /*_ , Searching in it */
7401 /* Use objtable_get_index */
7402 /*_ . On the stack */
7403 static struct stack_profiling
*
7404 klink_find_profile_in_frame (_kt_spagstack frame
, pko ff
)
7407 (frame
!= 0) && (frame
->type
!= ksct_frame
) ;
7408 frame
= frame
->next
)
7410 if(frame
->type
== ksct_profile
)
7412 struct stack_profiling
*pdata
= &frame
->data
.profiling
;
7413 if(pdata
->ff
== ff
) { return pdata
; }
7418 /*_ . Profile collection operations */
7419 /*_ , When eval loop steps */
7421 k_profiling_step(void)
7422 { k_profiling_count
++; }
7423 /*_ , When we begin executing a frame */
7424 /* Push a stack_profiling cell onto the frame. */
7427 k_profiling_new_frame(klink
* sc
, pko ff
)
7429 if(!k_profiling_p
) { return; }
7430 if(!is_operative(ff
)) { return; }
7431 /* Do this only if ff is interesting (which for the moment means
7432 that it can be found in ground environment). */
7433 if(!reverse_binds_p(ff
, ground_env
) &&
7434 !reverse_binds_p(ff
, print_lookup_unwraps
) &&
7435 !reverse_binds_p(ff
, print_lookup_to_xary
))
7437 struct stack_profiling
* found_profile
=
7438 klink_find_profile_in_frame (sc
->dump
, ff
);
7439 /* If the same combiner is already being profiled in this frame,
7440 don't add another copy. */
7443 /* $$IMPROVE ME Count tail calls */
7447 /* Push a profiling frame */
7448 _kt_spagstack old_frame
= sc
->dump
;
7449 _kt_spagstack frame
=
7451 GC_MALLOC (sizeof (dump_stack_frame_cell
));
7452 struct stack_profiling
* pdata
= &frame
->data
.profiling
;
7454 pdata
->initial_count
= k_profiling_count
;
7455 pdata
->returned_p
= 0;
7456 frame
->type
= ksct_profile
;
7457 frame
->next
= old_frame
;
7462 /*_ , When we pop a stack_profiling cell */
7464 k_profiling_done_frame(klink
* sc
, struct stack_profiling
* profile
)
7466 if(!k_profiling_p
) { return; }
7467 profiling_data
* pdata
= 0;
7468 pko ff
= profile
->ff
;
7470 /* This stack_profiling cell is popped past but it might be used
7471 again if we re-enter, so mark it accordingly. */
7472 profile
->returned_p
= 1;
7473 if(k_profiling_table
.alloced_size
== 0)
7474 { init_profile_table(&k_profiling_table
, 8); }
7477 int index
= objtable_get_index(k_profiling_table
.objs
, k_profiling_table
.table_size
, ff
);
7479 { pdata
= &k_profiling_table
.entries
[index
]; }
7482 /* Create it if needed */
7485 /* Increase size as needed */
7486 enlarge_profile_table(&k_profiling_table
);
7488 const int index
= k_profiling_table
.table_size
;
7489 k_profiling_table
.objs
[index
] = ff
;
7490 k_profiling_table
.table_size
++;
7491 pdata
= &k_profiling_table
.entries
[index
];
7492 /* Initialize it here */
7493 pdata
->num_calls
= 0;
7494 pdata
->num_evalloops
= 0;
7497 /* Add to its counts: Num calls. Num eval-loops taken. */
7499 pdata
->num_evalloops
+= k_profiling_count
- profile
->initial_count
;
7502 /*_ , Turn profiling on */
7503 /* Maybe better as a command-line switch or binder. */
7504 SIG_CHKARRAY(profiling
) = { REF_OPER(is_integer
), };
7505 DEF_SIMPLE_APPLICATIVE (ps0a1
, profiling
,T_NO_K
,ground
, "profiling")
7507 WITH_1_ARGS(profile_p
);
7508 int pr
= k_profiling_p
;
7509 k_profiling_p
= ivalue (profile_p
);
7510 return mk_integer (pr
);
7513 /*_ , Dumping profiling data */
7514 /* Return a list of the profiled combiners. */
7515 DEF_APPLICATIVE_W_DESTR(ps0a0
,get_profiling_data
,K_NO_TYPE
,T_NO_K
,ground
,"get-profiling-data")
7518 pko result_list
= K_NIL
;
7519 for(index
= 0; index
< k_profiling_table
.table_size
; index
++)
7521 pko ff
= k_profiling_table
.objs
[index
];
7522 profiling_data
* pdata
= &k_profiling_table
.entries
[index
];
7524 /* Element format: (object num-calls num-evalloops) */
7527 mk_integer(pdata
->num_calls
),
7528 mk_integer(pdata
->num_evalloops
)),
7531 /* Don't care about order so no need to reverse the list. */
7534 /*_ . Reset profiling data */
7535 /*_ , Alternative definitions for no profiling */
7537 #define k_profiling_step()
7538 #define k_profiling_new_frame(DUMMY, DUMMY2)
7540 /*_ . Error handling */
7541 /*_ , _klink_error_1 */
7543 _klink_error_1 (klink
* sc
, const char *s
, pko a
)
7546 const char *str
= s
;
7547 char sbuf
[STRBUFFSIZE
];
7548 pko the_inport
= klink_find_dyn_binding(sc
,K_INPORT
);
7549 if (the_inport
&& (the_inport
!= K_NIL
))
7551 port
* pt
= portvalue(the_inport
);
7552 /* Make sure error is not in REPL */
7553 if((pt
->kind
& port_file
) && (pt
->rep
.stdio
.file
!= stdin
))
7555 /* Count is 0-based but print it 1-based. */
7556 int ln
= pt
->rep
.stdio
.curr_line
+ 1;
7557 const char *fname
= pt
->rep
.stdio
.filename
;
7560 { fname
= "<unknown>"; }
7562 snprintf (sbuf
, STRBUFFSIZE
, "(%s : %i) %s", fname
, ln
, s
);
7564 str
= (const char *) sbuf
;
7568 const char *str
= s
;
7572 pko err_string
= mk_string (str
);
7575 err_arg
= mcons (a
, K_NIL
);
7581 err_arg
= mcons (err_string
, err_arg
);
7582 invoke_continuation (sc
, sc
->error_continuation
, err_arg
);
7588 /*_ , Default cheap error handlers */
7590 DEF_CFUNC (ps0a1
, kernel_err
, K_ANY
,0)
7595 putstr (sc
, "Error with no arguments. I know nut-ting!");
7598 if(!is_finite_list(arg1
))
7600 putstr (sc
, "kernel_err: arg must be a finite list");
7604 assert(is_pair(arg1
));
7605 int got_string
= is_string (car (arg1
));
7606 pko args_x
= got_string
? cdr (arg1
) : arg1
;
7607 const char *message
= got_string
? string_value (car (arg1
)) : " -- ";
7609 putstr (sc
, "Error: ");
7610 putstr (sc
, message
);
7611 return kernel_err_x (sc
, args_x
);
7614 /*_ . kernel_err_x */
7615 DEF_CFUNC (ps0a1
, kernel_err_x
, K_ANY_SINGLETON
,0)
7622 assert(is_pair(args
));
7623 CONTIN_1 (dcrry_1dotALL
, kernel_err_x
, sc
, cdr (args
));
7624 klink_push_dyn_binding(sc
,K_PRINT_FLAG
,K_T
);
7625 CONTIN_1 (dcrry_1dotALL
, kernel_print_sexp
, sc
, car (args
));
7634 /*_ . kernel_err_return */
7635 DEF_CFUNC(ps0a1
,kernel_err_return
, K_ANY
,0)
7637 /* This should not set sc->done, because when it's called it still
7638 must print the error, which may require more eval loops. */
7640 return kernel_err(sc
, arg1
);
7644 DEF_APPLICATIVE_W_DESTR(ps0a1
,error
,K_ANY
,0,ground
,"error")
7646 WITH_1_ARGS(err_arg
);
7647 invoke_continuation (sc
, sc
->error_continuation
, err_arg
);
7648 return 0; /* NOTREACHED */
7650 /*_ . error-descriptor? */
7651 /* $$WRITE ME TO replace the punted version */
7653 /*_ . Support for calling C functions */
7655 /*_ , klink_call_cfunc_aux */
7657 klink_call_cfunc_aux (klink
* sc
, const kt_cfunc
* p_cfunc
, pko
* arg_array
)
7659 switch (p_cfunc
->type
)
7661 /* For these macros, the arglist is parenthesized so is
7664 /* ***************************************** */
7665 /* For function types returning bool as int (bXXaX) */
7666 #define CASE_CFUNCTYPE_bX(SUFFIX,ARGLIST) \
7667 case klink_ftype_##SUFFIX: \
7668 return kernel_bool(p_cfunc->func.f_##SUFFIX ARGLIST)
7670 CASE_CFUNCTYPE_bX (b00a1
, (arg_array
[0]));
7671 CASE_CFUNCTYPE_bX (b00a2
, (arg_array
[0], arg_array
[1]));
7672 CASE_CFUNCTYPE_bX (bs0a2
, (sc
, arg_array
[0], arg_array
[1]));
7674 #undef CASE_CFUNCTYPE_bX
7677 /* ***************************************** */
7678 /* For function types returning pko (pXXaX) */
7679 #define CASE_CFUNCTYPE_pX(SUFFIX,ARGLIST) \
7680 case klink_ftype_##SUFFIX: \
7681 return p_cfunc->func.f_##SUFFIX ARGLIST
7683 CASE_CFUNCTYPE_pX (p00a0
, ());
7684 CASE_CFUNCTYPE_pX (p00a1
, (arg_array
[0]));
7685 CASE_CFUNCTYPE_pX (p00a2
, (arg_array
[0], arg_array
[1]));
7686 CASE_CFUNCTYPE_pX (p00a3
, (arg_array
[0], arg_array
[1], arg_array
[2]));
7688 CASE_CFUNCTYPE_pX (ps0a0
, (sc
));
7689 CASE_CFUNCTYPE_pX (ps0a1
, (sc
, arg_array
[0]));
7690 CASE_CFUNCTYPE_pX (ps0a2
, (sc
, arg_array
[0], arg_array
[1]));
7691 CASE_CFUNCTYPE_pX (ps0a3
, (sc
, arg_array
[0], arg_array
[1], arg_array
[2]));
7692 CASE_CFUNCTYPE_pX (ps0a4
, (sc
, arg_array
[0], arg_array
[1],
7693 arg_array
[2], arg_array
[3]));
7694 CASE_CFUNCTYPE_pX (ps0a5
, (sc
, arg_array
[0], arg_array
[1], arg_array
[2], arg_array
[3], arg_array
[4]));
7696 #undef CASE_CFUNCTYPE_pX
7699 /* ***************************************** */
7700 /* For function types returning void (vXXaX) */
7701 #define CASE_CFUNCTYPE_vX(SUFFIX,ARGLIST) \
7702 case klink_ftype_##SUFFIX: \
7703 p_cfunc->func.f_##SUFFIX ARGLIST; \
7706 CASE_CFUNCTYPE_vX (vs0a2
, (sc
, arg_array
[0], arg_array
[1]));
7707 CASE_CFUNCTYPE_vX (vs0a3
, (sc
, arg_array
[0], arg_array
[1], arg_array
[2]));
7709 #undef CASE_CFUNCTYPE_vX
7713 "kernel_call: About that function type, I know nut-ting!");
7716 /*_ , klink_call_cfunc */
7718 klink_call_cfunc (klink
* sc
, pko functor
, pko env
, pko args
)
7720 const kt_cfunc
* p_cfunc
= get_cfunc_func (functor
);
7721 assert(p_cfunc
->argcheck
);
7722 const int max_args
= 5;
7723 pko arg_array
[max_args
];
7724 destructure_to_array(sc
,args
,
7728 REF_OPER (k_resume_to_cfunc
),
7730 return klink_call_cfunc_aux (sc
, p_cfunc
, arg_array
);
7732 /*_ , k_resume_to_cfunc */
7733 SIG_CHKARRAY (k_resume_to_cfunc
) =
7735 REF_OPER (is_destr_result
),
7736 REF_KEY (K_TYCH_DOT
),
7737 REF_OPER (is_cfunc
),
7739 DEF_SIMPLE_CFUNC (ps0a2
, k_resume_to_cfunc
, 0)
7741 WITH_2_ARGS (destr_result
, functor
);
7742 assert_type (0, functor
, T_CFUNC
);
7743 const int max_args
= 5;
7744 pko arg_array
[max_args
];
7745 destr_result_fill_array (destr_result
, max_args
, arg_array
);
7746 return klink_call_cfunc_aux (sc
, get_cfunc_func (functor
), arg_array
);
7748 /*_ . Some decurriers */
7750 dcrry_2A01VLL (klink
* sc
, pko args
, pko value
)
7753 return LIST2(car (args
), value
);
7755 static pko
dcrry_3A01dotVLL (klink
* sc
, pko args
, pko value
)
7758 return cons (car (args
), value
);
7761 dcrry_2CA01VLLA02 (klink
* sc
, pko args
, pko value
)
7764 return LIST2( cons (car (args
), value
), cadr (args
));
7766 /* May not be needed */
7768 dcrry_3A01A02VLL (klink
* sc
, pko args
, pko value
)
7771 return LIST3(car (args
), cadr (args
), value
);
7774 dcrry_2ALLVLL (klink
* sc
, pko args
, pko value
)
7776 return LIST2(args
, value
);
7778 static pko
dcrry_2ALLV01 (klink
* sc
, pko args
, pko value
)
7781 return LIST2(args
, car (value
));
7785 dcrry_NCVLLA01dotAX1 (klink
* sc
, pko args
, pko value
)
7788 return cons(cons (value
, car (args
)), cdr (args
));
7790 static pko
dcrry_NdotALL (klink
* sc
, pko args
, pko value
)
7793 static pko
dcrry_1ALL (klink
* sc
, pko args
, pko value
)
7794 { return cons( args
, K_NIL
); }
7796 static pko
dcrry_5ALLdotVLL (klink
* sc
, pko args
, pko value
)
7797 { return cons (args
, value
); }
7799 static pko
dcrry_NVLLdotALL (klink
* sc
, pko args
, pko value
)
7800 { return cons (value
, args
); }
7803 dcrry_1VLL (klink
* sc
, pko args
, pko value
)
7804 { return LIST1 (value
); }
7807 /*_ , Internal functions */
7808 /*_ . kernel_define_tree_aux */
7810 kernel_define_tree_aux
7811 (klink
* sc
, pko value
, pko formal
, pko env
, pko
* extra_result
)
7814 if (is_pair (formal
))
7816 if (is_pair (value
))
7818 kt_destr_outcome outcome
=
7819 kernel_define_tree_aux (sc
, car (value
), car (formal
), env
,
7824 /* $$IMPROVE ME On error, give a more accurate position. */
7826 kernel_define_tree_aux (sc
, cdr (value
), cdr (formal
), env
,
7830 case destr_must_call_k
:
7831 /* $$IMPROVE ME Also schedule to resume the cdr */
7832 /* Operations to run, in reverse order. */
7836 REF_OPER (kernel_define_tree
),
7837 /* V= (value formal env) */
7838 mk_load (LIST3 (cdr (value
),
7842 return destr_must_call_k
;
7844 errx (7, "Unrecognized enumeration");
7847 if (is_promise (value
))
7849 /* Operations to run, in reverse order. */
7853 REF_OPER (kernel_define_tree
),
7854 /* V= (forced-value formal env) */
7855 mk_load (LIST3 (mk_load_ix (0, 0),
7858 mk_store (K_ANY
, 1),
7859 /* V= forced-argobject */
7862 mk_load (LIST1 (value
)));
7863 return destr_must_call_k
;
7868 "kernel_define_tree: value must be a pair: ", value
);
7869 return destr_err
; /* NOTREACHED */
7872 /* We can encounter NIL at the end of a non-dotted list, so mustn't
7873 try to bind it, and value list must end here too. */
7874 else if (formal
== K_NIL
)
7879 "kernel_define_tree: too many args: ", value
);
7880 return destr_err
; /* NOTREACHED */
7882 return destr_success
;
7884 /* If formal is #ignore, don't try to bind it, do nothing. */
7885 else if (formal
== K_IGNORE
)
7887 return destr_success
;
7889 /* If it's a symbol, bind it. Even a promise is bound thus. */
7890 else if (is_symbol (formal
))
7892 kernel_define (env
, formal
, value
);
7893 return destr_success
;
7898 "kernel_define_tree: can't bind to: ", formal
);
7899 return destr_err
; /* NOTREACHED */
7902 /*_ . kernel_define_tree */
7903 /* This can no longer be assumed to be T_NO_K, in case promises must
7905 SIG_CHKARRAY(kernel_define_tree
) =
7906 { K_ANY
, K_ANY
, REF_OPER(is_environment
), };
7907 DEF_SIMPLE_CFUNC(vs0a3
,kernel_define_tree
,0)
7909 WITH_3_ARGS(value
, formal
, env
);
7911 kt_destr_outcome outcome
=
7912 kernel_define_tree_aux(sc
, value
, formal
, env
, &extra_result
);
7918 /* Later this may raise the error */
7920 case destr_must_call_k
:
7921 schedule_rv_list (sc
, extra_result
);
7924 errx (7, "Unrecognized enumeration");
7927 /*_ . kernel_define */
7928 SIG_CHKARRAY(kernel_define
) =
7930 REF_OPER(is_environment
),
7931 REF_OPER(is_symbol
),
7934 DEF_SIMPLE_CFUNC(p00a3
,kernel_define
,T_NO_K
)
7936 WITH_3_ARGS(env
, symbol
, value
);
7937 assert(is_symbol(symbol
));
7938 pko x
= find_slot_in_env (env
, symbol
, 0);
7941 set_slot_in_env (x
, value
);
7945 new_slot_spec_in_env (env
, symbol
, value
);
7949 void klink_define (klink
* sc
, pko symbol
, pko value
)
7950 { kernel_define(sc
->envir
,symbol
,value
); }
7952 /*_ , Supporting kernel registerables */
7953 /*_ . eval_define */
7954 RGSTR(ground
, "$define!", REF_OPER(eval_define
))
7955 SIG_CHKARRAY(eval_define
) =
7957 DEF_SIMPLE_CFUNC(ps0a2
,eval_define
,0)
7959 pko env
= sc
->envir
;
7960 WITH_2_ARGS(formal
, expr
);
7961 CONTIN_2(dcrry_3VLLdotALL
,kernel_define_tree
,sc
,formal
,env
);
7962 /* Using args functionality:
7968 RUN, in reverse order
7969 kernel_define_tree (CONTIN_0)
7970 make arglist from 3 args ($$WRITE MY SUPPORT) - or from 2 args and value.
7971 (The 2 slots will go here)
7972 put return value in new slot ($$WRITE MY SUPPORT)
7976 Possibly "make arglist" will be an array of integers, -1 meaning
7977 the current value. And on its own it could do decurrying.
7979 return kernel_eval(sc
,expr
,env
);
7982 RGSTR(ground
, "$set!", REF_OPER(set
))
7984 { K_ANY
, K_ANY
, K_ANY
, };
7985 DEF_SIMPLE_CFUNC(ps0a3
,set
,0)
7987 pko env
= sc
->envir
;
7988 WITH_3_ARGS(env_expr
, formal
, expr
);
7989 /* Using args functionality:
7991 RUN, in reverse order
7992 kernel_define_tree (CONTIN_0)
7993 make arglist from 3 args - or from 2 args and value.
7994 put return value in new slot
7996 make arglist from 1 arg
7999 put return value in new slot
8001 expr (Passed directly)
8005 CONTIN_0(kernel_define_tree
,sc
);
8007 kernel_mapeval(sc
, K_NIL
,
8009 LIST2(REF_OPER (arg1
), formal
),
8014 /*_ . Misc Kernel functions */
8017 SIG_CHKARRAY(tracing
) = { REF_OPER(is_integer
), };
8018 DEF_SIMPLE_APPLICATIVE (ps0a1
, tracing
,T_NO_K
,ground
, "tracing")
8020 WITH_1_ARGS(trace_p
);
8021 int tr
= sc
->tracing
;
8022 sc
->tracing
= ivalue (trace_p
);
8023 return mk_integer (tr
);
8026 /*_ , new_tracing */
8028 SIG_CHKARRAY(new_tracing
) = { REF_OPER(is_integer
), };
8029 DEF_SIMPLE_APPLICATIVE (ps0a1
, new_tracing
,T_NO_K
,ground
, "new-tracing")
8031 WITH_1_ARGS(trace_p
);
8032 int tr
= sc
->new_tracing
;
8033 sc
->new_tracing
= ivalue (trace_p
);
8034 return mk_integer (tr
);
8038 /*_ , get-current-environment */
8039 DEF_APPLICATIVE_W_DESTR (ps0a0
, get_current_environment
, K_NO_TYPE
,T_NO_K
,ground
, "get-current-environment")
8040 { return sc
->envir
; }
8042 /*_ , arg1, $quote, list */
8043 DEF_APPLICATIVE_W_DESTR (ps0a1
, arg1
, K_ANY_SINGLETON
,T_NO_K
,ground
, "identity")
8048 /* Same, unwrapped */
8049 RGSTR(ground
, "$quote", REF_OPER(arg1
))
8052 RGSTR(ground
, "list", REF_APPL(val2val
))
8053 /* The underlying C function here is "arg1", but it's called with
8054 the whole argobject as arg1 */
8055 /* K_ANY instead of REF_OPER(is_finite_list) because we deliberately allow
8056 non-lists and improper lists. */
8057 DEF_CFUNC_RAW(OPER(val2val
),ps0a1
,arg1
,K_ANY
,T_NO_K
);
8058 DEF_BOXED_APPLICATIVE(val2val
, REF_OPER (val2val
));
8061 RGSTR(ground
,"exit",REF_OPER(k_quit
))
8062 DEF_CFUNC(ps0a0
,k_quit
,K_NO_TYPE
,0)
8064 if(!nest_depth_ok_p(sc
))
8065 { sc
->retcode
= 1; }
8068 return K_INERT
; /* Value is unused anyways */
8071 RGSTR(ground
,"gc",REF_OPER(k_gc
))
8072 DEF_CFUNC(ps0a0
,k_gc
,K_NO_TYPE
,0)
8080 RGSTR(ground
, "$if", REF_OPER(k_if
))
8081 FORWARD_DECL_CFUNC(static,ps0a3
,k_if_literal
);
8082 SIG_CHKARRAY(k_if
) = { K_ANY
, K_ANY
, K_ANY
, };
8083 DEF_SIMPLE_DESTR( k_if
);
8086 /* Store (test consequent alternative) */
8087 ANON_STORE(REF_DESTR(k_if
)),
8089 ANON_LOAD(ANON_LIST1(ANON_LOAD_IX( 0, 0 ))),
8090 /* value = (test) */
8092 REF_OPER(kernel_eval
),
8094 /* Store (test_result) */
8097 ANON_LOAD(ANON_LIST3(ANON_LOAD_IX( 0, 0 ),
8098 ANON_LOAD_IX( 1, 1 ),
8099 ANON_LOAD_IX( 1, 2 ))),
8101 /* test_result, consequent, alternative */
8102 REF_OPER(k_if_literal
),
8105 DEF_SIMPLE_CHAIN(k_if
);
8107 SIG_CHKARRAY(k_if_literal
) = { REF_OPER(is_bool
), K_ANY
, K_ANY
, };
8108 DEF_SIMPLE_CFUNC(ps0a3
,k_if_literal
,0)
8110 WITH_3_ARGS(test
, consequent
, alternative
);
8111 if(test
== K_T
) { return kernel_eval(sc
, consequent
, sc
->envir
); }
8112 if(test
== K_F
) { return kernel_eval(sc
, alternative
, sc
->envir
); }
8113 KERNEL_ERROR_1(sc
,"Must be a boolean: ", test
);
8116 /*_ . Routines for applicatives */
8117 BOX_OF_VOID (K_APPLICATIVE
);
8119 DEF_SIMPLE_PRED (is_applicative
,T_NO_K
,ground
, "applicative?/o1")
8122 return is_encap (REF_KEY(K_APPLICATIVE
), p
);
8125 DEF_SIMPLE_PRED (is_combiner
,T_NO_K
,ground
, "combiner?/o1")
8128 return is_applicative(p
) || is_operative(p
);
8131 SIG_CHKARRAY(wrap
) = { REF_OPER(is_combiner
) };
8132 DEF_SIMPLE_APPLICATIVE (p00a1
, wrap
,T_NO_K
,ground
, "wrap")
8135 return mk_encap (REF_KEY(K_APPLICATIVE
), p
);
8138 SIG_CHKARRAY(unwrap
) = { REF_OPER(is_applicative
) };
8139 DEF_SIMPLE_APPLICATIVE (ps0a1
, unwrap
,T_NO_K
,ground
, "unwrap")
8142 return unencap (sc
, REF_KEY(K_APPLICATIVE
), p
);
8145 SIG_CHKARRAY(unwrap_all
) = { REF_OPER(is_combiner
) };
8146 DEF_SIMPLE_APPLICATIVE (p00a1
, unwrap_all
,T_NO_K
,ground
, "unwrap-all")
8149 /* Wrapping does not allowing circular wrapping, so this will
8151 while(is_encap (REF_KEY(K_APPLICATIVE
), p
))
8152 { p
= unencap (0, REF_KEY(K_APPLICATIVE
), p
); }
8158 /*_ , is_operative */
8159 /* This can be hacked quicker by suppressing 1 more bit and testing
8160 * just once. Requires keeping those T_ types co-ordinated, though. */
8161 DEF_SIMPLE_PRED (is_operative
,T_NO_K
,ground
, "operative?/o1")
8165 is_type (p
, T_CFUNC
)
8166 || is_type (p
, T_CFUNC_RESUME
)
8167 || is_type (p
, T_CURRIED
)
8168 || is_type (p
, T_LISTLOOP
)
8169 || is_type (p
, T_CHAIN
)
8170 || is_type (p
, T_STORE
)
8171 || is_type (p
, T_LOAD
)
8172 || is_type (p
, T_TYPEP
);
8176 RGSTR(simple
, "$vau/3", REF_OPER(vau_1
))
8178 /* This is a simple vau for bootstrap. It handles just a single
8179 expression. It's in ground for now, but will be only in
8180 low-for-optimization later */
8182 /* $$IMPROVE ME Check that formals is a non-circular list with no
8183 duplicated symbols. If this check is typical for
8184 kernel_define_tree (probably), pass that an initially blank
8185 environment and it can check for symbols and error if they are
8188 eformal is almost REF_OPER(is_symbol) but must accept #ignore also.
8190 SIG_CHKARRAY(vau_1
) = { K_ANY
, K_ANY
, K_ANY
};
8191 DEF_SIMPLE_CFUNC (ps0a3
, vau_1
,0)
8193 pko env
= sc
->envir
;
8194 WITH_3_ARGS(formals
, eformal
, expression
);
8195 /* This defines a vau object. Evaluating it is different.
8198 /* $$IMPROVE ME Could compile the expression now, but that's not so
8199 easy in Kernel. At least make a hook for that. */
8201 /* Vau data is a list of the 4 things:
8202 The dynamic environment
8204 An immutable copy of the formals es
8205 An immutable copy of the expression
8207 $$IMPROVE ME Make not a list but a dedicated struct.
8212 copy_es_immutable(sc
, formals
),
8213 copy_es_immutable (sc
, expression
));
8215 mk_curried (dcrry_5VLLdotALL
, vau_data
, REF_OPER (eval_vau
));
8218 /*_ . Evaluation, Kernel style */
8219 /*_ , Calling operatives */
8221 /* Again, can't simply say REF_OPER(is_symbol) because it might be
8223 SIG_CHKARRAY(eval_vau
) =
8225 REF_OPER(is_environment
),
8229 DEF_SIMPLE_CFUNC (ps0a5
, eval_vau
,0)
8231 pko env
= sc
->envir
;
8232 WITH_5_ARGS(args
, old_env
, eformal
, formals
, expression
);
8234 /* Make a new environment, child of the static environment (which
8235 we get now while making the vau) and put it into the envir
8237 new_frame_in_env (sc
, old_env
);
8239 /* This will change in kernel_define, not here. */
8240 /* Bind the dynamic environment to the eformal symbol. */
8241 kernel_define_tree (sc
, env
, eformal
, sc
->envir
);
8243 /* Bind the formals (symbols) to the operands (values) treewise. */
8245 kt_destr_outcome outcome
=
8246 kernel_define_tree_aux(sc
, args
, formals
, sc
->envir
, &extra_result
);
8252 /* Later this may raise the error */
8254 case destr_must_call_k
:
8255 CONTIN_2 (dcrry_2dotALL
, kernel_eval
, sc
, expression
, sc
->envir
);
8256 schedule_rv_list (sc
, extra_result
);
8259 errx (7, "Unrecognized enumeration");
8262 /* Evaluate the expression. */
8263 return kernel_eval (sc
, expression
, sc
->envir
);
8266 /*_ , Kernel eval mutual callers */
8267 /*_ . kernel_eval */
8269 /* Optionally define a tracing kernel_eval */
8270 SIG_CHKARRAY(kernel_eval
) = { K_ANY
, REF_KEY(K_TYCH_OPTIONAL
), REF_OPER(is_environment
), };
8271 DEF_SIMPLE_DESTR(kernel_eval
);
8273 FORWARD_DECL_CFUNC(static,ps0a2
,kernel_real_eval
);
8274 DEF_APPLICATIVE_W_DESTR (ps0a2
, kernel_eval
, REF_DESTR(kernel_eval
),0,ground
, "eval")
8276 WITH_2_ARGS(form
, env
);
8277 /* $$RETHINK ME Set sc->envir here, remove arg from
8278 kernel_real_eval, and the tracing call will know its own env,
8279 it may just be a closure with form as value. */
8286 CONTIN_2 (dcrry_2dotALL
, kernel_real_eval
, sc
, form
, env
);
8287 putstr (sc
, "\nEval: ");
8288 CONTIN_1 (dcrry_1dotALL
, kernel_print_sexp
, sc
, form
);
8293 return kernel_real_eval (sc
, form
, env
);
8298 /* Define either kernel_eval (if not defined above) or kernel_real_eval */
8300 /* $$IMPROVE MY DESIGN Don't like the pointers being different
8301 levels of pointingness. In fact, we always potentially have
8302 tracing (or w/e) so let's lose the preprocessor condition. */
8304 DEF_CFUNC (ps0a2
, kernel_real_eval
, REF_DESTR(kernel_eval
),0)
8306 DEF_APPLICATIVE_W_DESTR (ps0a2
, kernel_eval
, REF_DESTR(kernel_eval
),0,ground
, "eval")
8310 WITH_2_ARGS(form
, env
);
8312 /* Evaluate form in env */
8314 form: form to be evaluated
8315 env: environment to evaluate it in.
8319 /* $$IMPROVE ME Let this be done in kernel_eval and lose the env
8320 argument, here just assert that we have an environment. */
8323 if (is_environment (env
))
8324 { sc
->envir
= env
; }
8327 KERNEL_ERROR_0 (sc
, "eval: Arg 2 must be an environment:");
8331 if (is_symbol (form
))
8333 pko x
= find_slot_in_env (env
, form
, 1);
8336 return slot_value_in_env (x
);
8340 KERNEL_ERROR_1 (sc
, "eval: unbound variable:", form
);
8344 else if (is_pair (form
))
8346 CONTIN_2 (dcrry_3VLLdotALL
, kernel_eval_aux
, sc
, cdr (form
), env
);
8347 return kernel_eval (sc
, car (form
), env
);
8349 /* Otherwise return the object literally. */
8355 /*_ . kernel_eval_aux */
8356 /* The stage of `eval' when we've already decided that we're to use a
8357 combiner and what that combiner is. */
8358 /* $$IMPROVE ME Lose the env argument, it's always sc->envir */
8359 SIG_CHKARRAY(kernel_eval_aux
) =
8360 { REF_OPER(is_combiner
), K_ANY
, REF_OPER(is_environment
), };
8361 DEF_SIMPLE_DESTR(kernel_eval_aux
);
8362 DEF_CFUNC (ps0a3
, kernel_eval_aux
, REF_DESTR(kernel_eval_aux
),0)
8364 WITH_3_ARGS(functor
, args
, env
);
8365 assert (is_environment (env
));
8367 functor: what the car of the form has evaluated to.
8368 args: cdr of form, as yet unevaluated.
8369 env: environment to evaluate in.
8371 k_profiling_new_frame(sc
, functor
);
8372 if(is_type(functor
, T_CFUNC
))
8374 return klink_call_cfunc(sc
, functor
, env
, args
);
8376 else if(is_type(functor
, T_CURRIED
))
8378 return call_curried(sc
, functor
, args
);
8380 else if(is_type(functor
, T_TYPEP
))
8382 /* $$MOVE ME Into something paralleling the other operative calls */
8383 /* $$IMPROVE ME Check arg number */
8386 { KERNEL_ERROR_1 (sc
, "Takes one arg: ", functor
); }
8387 return kernel_bool(call_T_typecheck(functor
,car(args
)));
8389 else if(is_type(functor
, T_LISTLOOP
))
8391 return eval_listloop(sc
, functor
,args
);
8393 else if(is_type(functor
, T_CHAIN
))
8395 return eval_chain( sc
, functor
, args
);
8397 else if ( is_type( functor
, T_STORE
))
8399 return k_do_store( sc
, functor
, args
);
8401 else if ( is_type( functor
, T_LOAD
))
8403 return k_do_load( sc
, functor
, args
);
8405 else if (is_applicative (functor
))
8408 Get the underlying operative.
8409 Evaluate arguments (may make frames)
8410 Use the oper on the arguments
8412 pko oper
= unwrap (sc
, functor
);
8415 get_list_metrics_aux(args
, metrics
);
8416 if(metrics
[lm_cyc_len
] != 0)
8418 KERNEL_ERROR_1 (sc
, "kernel_eval_aux: Arguments must be a list", args
);
8420 sc
->envir
= env
; /* $$IMPROVE ME Treat this cache better */
8421 CONTIN_2 (dcrry_2CA01VLLA02
, kernel_eval
, sc
, oper
, env
);
8425 CONTIN_3 (dcrry_4dotALL
, kernel_mapeval
, sc
, K_NIL
, args
, env
);
8426 CONTIN_1 (dcrry_1dotALL
, kernel_print_sexp
, sc
, args
);
8427 putstr (sc
, "\nApply to: ");
8432 { return kernel_mapeval (sc
, K_NIL
, args
, env
); }
8436 KERNEL_ERROR_1 (sc
, "eval: can't apply:", functor
);
8439 /*_ , Eval mappers */
8440 /*_ . kernel_mapeval */
8441 /* Evaluate each datum in list arg2, Kernel-returning a list of the results. */
8442 SIG_CHKARRAY(kernel_mapeval
) =
8443 { REF_OPER(is_finite_list
), REF_OPER(is_finite_list
), REF_OPER(is_environment
), };
8444 DEF_SIMPLE_DESTR(kernel_mapeval
);
8445 DEF_CFUNC (ps0a3
, kernel_mapeval
, REF_DESTR(kernel_mapeval
),0)
8448 WITH_3_ARGS(accum
, args
, env
);
8449 assert (is_environment (env
));
8452 * The list of evaluated arguments, in reverse order.
8453 * Purpose: Used as an accumulator.
8455 args: list of forms to be evaluated.
8456 * Precondition: Must be a proper list (is_list must give true)
8457 * When called by itself: The forms that remain yet to be evaluated
8459 env: The environment to evaluate in.
8462 /* If there are remaining arguments, arrange to evaluate one,
8463 add the result to accumulator, and return control here. */
8466 /* This can't be converted to a loop because we don't know
8467 whether kernel_eval_aux will create more frames. */
8468 CONTIN_3 (dcrry_3CVLLA01dotAX1
,
8469 kernel_mapeval
, sc
, accum
, cdr (args
), env
);
8470 return kernel_eval (sc
, car (args
), env
);
8472 /* If there are no remaining arguments, reverse the accumulator
8473 and return it. Can't reverse in place because other
8474 continuations might re-use the same accumulator state. */
8475 else if (args
== K_NIL
)
8476 { return reverse (sc
, accum
); }
8479 /* This shouldn't be reachable because we check for it being
8480 a list beforehand in kernel_eval_aux. */
8481 errx (4, "mapeval: arguments must be a list:");
8485 RGSTR(ground
,"$bad-sequence",REF_OPER(kernel_sequence
))
8486 SIG_CHKARRAY(kernel_sequence
) =
8487 { REF_KEY(K_TYCH_DOT
), REF_OPER(is_countable_list
), };
8488 DEF_SIMPLE_CFUNC(ps0a1
,kernel_sequence
,0)
8491 /* Ultimately return #inert */
8492 /* $$IMPROVE ME This shouldn't accumulate args only to discard
8494 CONTIN_0_RAW(mk_curried(dcrry_NdotALL
, K_INERT
, 0), sc
);
8495 return kernel_mapeval(sc
,K_NIL
,forms
,sc
->envir
);
8498 /*_ . kernel_mapand_aux */
8499 /* Call proc on each datum in args, Kernel-returning true if all
8500 succeed, otherwise false. */
8501 SIG_CHKARRAY(kernel_mapand_aux
) =
8502 { REF_OPER(is_bool
),
8503 REF_OPER(is_combiner
),
8504 REF_OPER(is_finite_list
),
8506 DEF_SIMPLE_CFUNC (ps0a3
, kernel_mapand_aux
,0)
8509 WITH_3_ARGS(ok
, proc
, args
);
8512 * Whether the last invocation of this succeeded. Initialize with
8515 * proc: A boolean combiner (predicate) to apply to these objects
8517 * args: list of objects to apply proc to
8518 * Precondition: Must be a proper list
8523 { KERNEL_ERROR_1(sc
, "kernel_mapand_aux: Must be boolean: ", ok
); }
8524 /* If there are remaining arguments, arrange to evaluate one and
8525 return control here. */
8528 /* This can't be converted to a loop because we don't know
8529 whether kernel_eval_aux will create more frames. */
8530 CONTIN_2 (dcrry_3VLLdotALL
,
8531 kernel_mapand_aux
, sc
, proc
, cdr (args
));
8532 return kernel_eval_aux (sc
, proc
, car (args
), sc
->envir
);
8534 /* If there are no remaining arguments, return true. */
8535 else if (args
== K_NIL
)
8539 /* This shouldn't be reachable because we check for it being a
8541 errx (4, "mapbool: arguments must be a list:");
8545 /*_ . kernel_mapand */
8546 SIG_CHKARRAY(kernel_mapand
) =
8547 { REF_OPER(is_combiner
),
8548 REF_OPER(is_finite_list
),
8550 DEF_SIMPLE_APPLICATIVE (ps0a2
, kernel_mapand
,0,simple
, "every?/2-xary")
8552 WITH_2_ARGS(proc
, args
);
8553 /* $$IMPROVE ME Get list metrics here and if we get a circular
8554 list, treat it correctly (How is TBD). */
8555 return kernel_mapand_aux(sc
,REF_KEY(K_T
), proc
, args
);
8557 /*_ . kernel_mapor_aux */
8558 /* Call proc on each datum in args, Kernel-returning true if all
8559 succeed, otherwise false. */
8560 SIG_CHKARRAY(kernel_mapor_aux
) =
8561 { REF_OPER(is_bool
),
8562 REF_OPER(is_combiner
),
8563 REF_OPER(is_finite_list
),
8565 DEF_SIMPLE_CFUNC (ps0a3
, kernel_mapor_aux
,0)
8568 WITH_3_ARGS(ok
, proc
, args
);
8571 * Whether the last invocation of this succeeded. Initialize with
8574 * proc: A boolean combiner (predicate) to apply to these objects
8576 * args: list of objects to apply proc to
8577 * Precondition: Must be a proper list
8582 { KERNEL_ERROR_1(sc
, "kernel_mapor_aux: Must be boolean: ", ok
); }
8583 /* If there are remaining arguments, arrange to evaluate one and
8584 return control here. */
8587 /* This can't be converted to a loop because we don't know
8588 whether kernel_eval_aux will create more frames. */
8589 CONTIN_2 (dcrry_3VLLdotALL
,
8590 kernel_mapor_aux
, sc
, proc
, cdr (args
));
8591 return kernel_eval_aux (sc
, proc
, car (args
), sc
->envir
);
8593 /* If there are no remaining arguments, return false. */
8594 else if (args
== K_NIL
)
8598 /* This shouldn't be reachable because we check for it being a
8600 errx (4, "mapbool: arguments must be a list:");
8603 /*_ . kernel_mapor */
8604 SIG_CHKARRAY(kernel_mapor
) =
8605 { REF_OPER(is_combiner
),
8606 REF_OPER(is_finite_list
),
8608 DEF_SIMPLE_APPLICATIVE (ps0a2
, kernel_mapor
,0,simple
, "some?/2-xary")
8610 WITH_2_ARGS(proc
, args
);
8611 /* $$IMPROVE ME Get list metrics here and if we get a circular
8612 list, treat it correctly (How is TBD). */
8613 return kernel_mapor_aux(sc
,REF_KEY(K_F
), proc
, args
);
8616 /*_ , Kernel combiners */
8618 /* $$IMPROVE ME Make referring to curried operatives neater. */
8619 RGSTR(ground
, "$and?", REF_OBJ(k_oper_andp
))
8620 DEF_BOXED_CURRIED(k_oper_andp
,
8622 REF_OPER(kernel_internal_eval
),
8623 REF_OPER(kernel_mapand
));
8626 RGSTR(ground
, "$or?", REF_OBJ(k_oper_orp
))
8627 DEF_BOXED_CURRIED(k_oper_orp
,
8629 REF_OPER(kernel_internal_eval
),
8630 REF_OPER(kernel_mapor
));
8633 /*_ . k_counted_map_aux */
8634 /* $$USE ME MORE Export both to simple: "counted-map1-car"
8635 "counted-map1-cdr" */
8637 k_counted_map_car(klink
* sc
, int count
, pko list
, _kt_tag t_enum
)
8640 pko rv_result
= K_NIL
;
8641 for(i
= 0; i
< count
; ++i
, list
= pair_cdr(0, list
))
8643 assert(is_pair(list
));
8644 pko obj
= pair_car(0, list
);
8645 rv_result
= v2cons (t_enum
, pair_car(sc
, obj
), rv_result
);
8648 /* Reverse the list in place. */
8649 return unsafe_v2reverse_in_place(K_NIL
, rv_result
);
8653 k_counted_map_cdr(klink
* sc
, int count
, pko list
, _kt_tag t_enum
)
8656 pko rv_result
= K_NIL
;
8657 for(i
= 0; i
< count
; ++i
, list
= pair_cdr(0, list
))
8659 assert(is_pair(list
));
8660 pko obj
= pair_car(0, list
);
8661 rv_result
= v2cons (t_enum
, pair_cdr(sc
, obj
), rv_result
);
8664 /* Reverse the list in place. */
8665 return unsafe_v2reverse_in_place(K_NIL
, rv_result
);
8668 /* Evaluate COUNT datums in list ARGS, Kernel-returning a list of the
8670 SIG_CHKARRAY(k_counted_map_aux
) =
8671 { REF_OPER(is_finite_list
),
8672 REF_OPER(is_integer
),
8673 REF_OPER(is_integer
),
8674 REF_OPER(is_operative
),
8675 REF_OPER(is_finite_list
),
8677 DEF_SIMPLE_APPLICATIVE (ps0a5
, k_counted_map_aux
, 0,simple
, "counted-map/5")
8679 WITH_5_ARGS(accum
, count
, len
, oper
, args
);
8680 assert (is_integer (count
));
8681 /* $$IMPROVE ME Check the other args too */
8685 * The list of evaluated arguments, in reverse order.
8686 * Purpose: Used as an accumulator.
8689 * The number of arguments remaining
8692 * The effective length of args.
8697 args: list of lists of arguments to this.
8699 * Precondition: Must be a proper list (is_finite_list must give
8700 true). args will not be cyclic, we'll check for and handle
8701 encycling outside of here.
8704 /* If there are remaining arguments, arrange to operate on one, cons
8705 the result to accumulator, and return control here. */
8706 if (ivalue (count
) > 0)
8708 assert(is_pair(args
));
8709 int len_v
= ivalue(len
);
8710 /* This can't be converted to a loop because we don't know
8711 whether kernel_eval_aux will create more frames.
8713 $$IMPROVE ME Check T_NO_K of proc; if it's set, we can loop.
8715 CONTIN_5 (dcrry_5CVLLA01dotAX1
,
8716 k_counted_map_aux
, sc
, accum
,
8717 mk_integer(ivalue(count
) - 1),
8720 k_counted_map_cdr(sc
, len_v
, args
, T_PAIR
));
8722 return kernel_eval_aux (sc
,
8724 k_counted_map_car(sc
, len_v
, args
, T_PAIR
),
8727 /* If there are no remaining arguments, reverse the accumulator
8728 and return it. Can't reverse in place because other
8729 continuations might re-use the same accumulator state. */
8731 { return reverse (sc
, accum
); }
8735 /*_ . counted-every?/5 */
8736 SIG_CHKARRAY(k_counted_every
) =
8737 { REF_OPER(is_bool
),
8738 REF_OPER(is_integer
),
8739 REF_OPER(is_integer
),
8740 REF_OPER(is_operative
),
8741 REF_OPER(is_finite_list
),
8743 DEF_SIMPLE_APPLICATIVE (ps0a5
, k_counted_every
,0,simple
,"counted-every?/5")
8745 WITH_5_ARGS(ok
, count
, len
, oper
, args
);
8746 assert (is_bool (ok
));
8747 assert (is_integer (count
));
8748 assert (is_integer (len
));
8752 * Whether the last invocation of this succeeded. Initialize with
8756 * The number of arguments remaining
8759 * The effective length of args.
8764 args: list of lists of arguments to this.
8766 * Precondition: Must be a proper list (is_finite_list must give
8767 true). args will not be cyclic, we'll check for and handle
8768 encycling outside of here.
8774 { KERNEL_ERROR_1(sc
, "k_counted_every: Must be boolean: ", ok
); }
8776 /* If there are remaining arguments, arrange to evaluate one and
8777 return control here. */
8778 if (ivalue (count
) > 0)
8780 assert(is_pair(args
));
8781 int len_v
= ivalue(len
);
8782 /* This can't be converted to a loop because we don't know
8783 whether kernel_eval_aux will create more frames.
8785 $$IMPROVE ME Check T_NO_K of proc; if it's set, we can loop.
8787 CONTIN_4 (dcrry_4VLLdotALL
,
8788 k_counted_every
, sc
,
8789 mk_integer(ivalue(count
) - 1),
8792 k_counted_map_cdr(sc
, len_v
, args
, T_PAIR
));
8794 return kernel_eval_aux (sc
,
8796 k_counted_map_car(sc
, len_v
, args
, T_PAIR
),
8799 /* If there are no remaining arguments, return true. */
8805 /*_ . counted-some?/5 */
8806 SIG_CHKARRAY(k_counted_some
) =
8807 { REF_OPER(is_bool
),
8808 REF_OPER(is_integer
),
8809 REF_OPER(is_integer
),
8810 REF_OPER(is_operative
),
8811 REF_OPER(is_finite_list
),
8813 DEF_SIMPLE_APPLICATIVE (ps0a5
, k_counted_some
,0,simple
,"counted-some?/5")
8815 WITH_5_ARGS(ok
, count
, len
, oper
, args
);
8816 assert (is_bool (ok
));
8817 assert (is_integer (count
));
8818 assert (is_integer (len
));
8823 { KERNEL_ERROR_1(sc
, "k_counted_some: Must be boolean: ", ok
); }
8825 /* If there are remaining arguments, arrange to evaluate one and
8826 return control here. */
8827 if (ivalue (count
) > 0)
8829 assert(is_pair(args
));
8830 int len_v
= ivalue(len
);
8831 /* This can't be converted to a loop because we don't know
8832 whether kernel_eval_aux will create more frames.
8834 $$IMPROVE ME Check T_NO_K of proc; if it's set, we can loop.
8836 CONTIN_4 (dcrry_4VLLdotALL
,
8838 mk_integer(ivalue(count
) - 1),
8841 k_counted_map_cdr(sc
, len_v
, args
, T_PAIR
));
8843 return kernel_eval_aux (sc
,
8845 k_counted_map_car(sc
, len_v
, args
, T_PAIR
),
8848 /* If there are no remaining arguments, return false. */
8854 /*_ . Klink top level */
8855 /*_ , kernel_repl */
8856 DEF_CFUNC(ps0a0
, kernel_repl
, K_NO_TYPE
,0)
8858 /* If we reached the end of file, this loop is done. */
8859 port
*pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
8861 if (pt
->kind
& port_saw_EOF
)
8865 putstr (sc
, prompt
);
8867 assert (is_environment (sc
->envir
));
8869 /* Arrange another iteration */
8870 CONTIN_0 (kernel_repl
, sc
);
8871 klink_push_dyn_binding(sc
,K_PRINT_FLAG
,K_T
);
8872 klink_push_cont(sc
, REF_OBJ(print_value
));
8874 CONTIN_1 (dcrry_2A01VLL
, tracing_say
, sc
, mk_string("\nGives: "));
8876 CONTIN_0 (kernel_internal_eval
, sc
);
8877 CONTIN_0 (kernel_read_internal
, sc
);
8882 static const kt_vector rel_chain
=
8887 REF_OPER(kernel_read_internal
),
8888 REF_OPER(kernel_internal_eval
),
8889 REF_OPER(kernel_rel
),
8893 DEF_CFUNC(ps0a0
, kernel_rel
, K_NO_TYPE
,0)
8895 /* If we reached the end of file, this loop is done. */
8896 port
*pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
8898 if (pt
->kind
& port_saw_EOF
)
8901 assert (is_environment (sc
->envir
));
8904 schedule_chain( sc
, &rel_chain
);
8906 /* Arrange another iteration */
8907 CONTIN_0 (kernel_rel
, sc
);
8908 CONTIN_0 (kernel_internal_eval
, sc
);
8909 CONTIN_0 (kernel_read_internal
, sc
);
8914 /*_ , kernel_internal_eval */
8915 /* Convert the aftermath of kernel_read_internal to something kernel_eval
8917 /* $$IMPROVE ME realize this as a currier. But it's not a curried
8918 object as such because it carries no internal data. */
8919 DEF_CFUNC (ps0a1
, kernel_internal_eval
, K_ANY
,0)
8922 if( sc
->new_tracing
)
8923 { klink_push_dyn_binding( sc
, K_TRACING
, K_T
); }
8924 return kernel_eval (sc
, value
, sc
->envir
);
8927 /*_ . Constructing environments */
8928 /*_ , Declarations for built-in environments */
8929 /* These are initialized before they are registered. */
8930 static pko print_lookup_env
= 0;
8931 static pko all_builtins_env
= 0;
8932 static pko ground_env
= 0;
8933 #define unsafe_env ground_env
8934 #define simple_env ground_env
8935 static pko typecheck_env_syms
= 0;
8937 /*_ , What to include */
8938 #ifndef COLLECT_RGSTRS /* If we're collecting, these files may not
8939 have been generated yet */
8940 const kernel_registerable preregister
[] =
8942 /* $$MOVE ME These others will move into dedicated arrays, and be
8943 combined so that they can all be seen in init.krn but not in
8945 #include "registerables/ground.inc"
8946 #include "registerables/unsafe.inc"
8947 #include "registerables/simple.inc"
8948 /* $$TRANSITIONAL */
8949 { "type?", REF_APPL(typecheck
), },
8950 { "do-destructure", REF_APPL(do_destructure
), },
8953 const kernel_registerable all_builtins
[] =
8955 #include "registerables/all-builtins.inc"
8958 const kernel_registerable print_lookup_rgsts
[] =
8960 { "#f", REF_KEY(K_F
), },
8961 { "#t", REF_KEY(K_T
), },
8962 { "#inert", REF_KEY(K_INERT
), },
8963 { "#ignore", REF_KEY(K_IGNORE
), },
8965 { "$quote", REF_OPER(arg1
), },
8967 /* $$IMPROVE ME Add the other quote-like symbols here. */
8968 /* quasiquote, unquote, unquote-splicing */
8972 const kernel_registerable typecheck_syms_rgsts
[] =
8974 #include "registerables/type-keys.inc"
8981 /* Bind each of an array of kernel_registerables into env. */
8983 k_register_list (const kernel_registerable
* list
, int count
, pko env
)
8987 assert (is_environment (env
));
8988 for (i
= 0; i
< count
; i
++)
8990 kernel_define (env
, mk_symbol (list
[i
].name
), list
[i
].data
);
8994 /*_ , k_regstrs_to_env */
8996 k_regstrs_to_env(const kernel_registerable
* list
, int count
)
8998 pko env
= make_new_frame(K_NIL
);
8999 k_register_list (list
, count
, env
);
9003 #define K_REGSTRS_TO_ENV(RGSTRS)\
9004 k_regstrs_to_env(RGSTRS, sizeof (RGSTRS) / sizeof (RGSTRS[0]))
9005 /*_ , setup_print_secondary_lookup */
9006 static pko print_lookup_unwraps
= 0;
9007 static pko print_lookup_to_xary
= 0;
9009 setup_print_secondary_lookup(void)
9011 /* Quick and dirty: Set up tables corresponding to the ground env
9012 and put the registering stuff in them. */
9013 /* What this really accomplishes is to make prepared lookup tables
9014 available for particular print operations. Later we'll use a
9015 more general approach and this will become just a cache. */
9016 print_lookup_unwraps
= make_new_frame(K_NIL
);
9017 print_lookup_to_xary
= make_new_frame(K_NIL
);
9019 const kernel_registerable
* list
= preregister
;
9020 int count
= sizeof (preregister
) / sizeof (preregister
[0]);
9021 for (i
= 0; i
< count
; i
++)
9023 pko obj
= list
[i
].data
;
9024 if(is_applicative(obj
))
9026 kernel_define (print_lookup_unwraps
,
9027 mk_symbol (list
[i
].name
),
9030 pko xary
= k_to_trivpred(obj
);
9031 if((xary
!= K_NIL
) && xary
!= obj
)
9033 kernel_define (print_lookup_to_xary
,
9034 mk_symbol (list
[i
].name
),
9040 /*_ , make-kernel-standard-environment */
9041 /* Though it would be neater for this to define ground environment if
9042 there is none, that would mean it would need the eval loop and so
9043 couldn't be done early. So it relies on the ground environment
9044 being already defined. */
9045 RGSTR(ground
,"make-kernel-standard-environment", REF_OPER(mk_std_environment
))
9046 DEF_CFUNC(p00a0
, mk_std_environment
, K_NO_TYPE
,T_NO_K
)
9049 return make_new_frame(ground_env
);
9052 /*_ . The eval cycle */
9054 /*_ . Make an error continuation */
9056 klink_record_error_cont (klink
* sc
, pko error_continuation
)
9058 /* Record error continuation. */
9059 kernel_define (sc
->envir
,
9060 mk_symbol ("error-continuation"),
9061 error_continuation
);
9062 /* Also record it in interpreter, so built-ins can see it w/o
9064 sc
->error_continuation
= error_continuation
;
9067 /*_ , Entry points */
9068 /*_ . Eval cycle that restarts on error */
9070 klink_cycle_restarting (klink
* sc
, pko combiner
)
9072 assert(is_combiner(combiner
));
9073 assert(is_environment(sc
->envir
));
9074 /* Arrange to stop if we ever reach where we started. */
9075 klink_push_cont (sc
, REF_OPER (k_quit
));
9077 /* Grab root continuation. */
9078 kernel_define (sc
->envir
,
9079 mk_symbol ("root-continuation"),
9080 current_continuation (sc
));
9082 /* Make main continuation */
9083 klink_push_cont (sc
, combiner
);
9085 /* Make error continuation on top of main continuation. */
9086 pko error_continuation
=
9087 extend_continuation_aux(sc
->dump
, REF_OPER(kernel_err
), sc
->envir
);
9089 klink_record_error_cont(sc
, error_continuation
);
9091 /* Conceptually sc->retcode is a keyed dynamic variable that
9095 /* $$RECONSIDER ME Maybe indicate quit value */
9097 /*_ . Eval cycle that terminates on error */
9099 klink_cycle_no_restart (klink
* sc
, pko combiner
)
9101 assert(is_combiner(combiner
));
9102 assert(is_environment(sc
->envir
));
9103 /* Arrange to stop if we ever reach where we started. */
9104 klink_push_cont (sc
, REF_OPER (k_quit
));
9106 /* Grab root continuation. */
9107 kernel_define (sc
->envir
,
9108 mk_symbol ("root-continuation"),
9109 current_continuation (sc
));
9111 /* Make error continuation that quits. */
9112 pko error_continuation
=
9113 extend_continuation_aux(sc
->dump
, REF_OPER(kernel_err_return
), sc
->envir
);
9115 klink_record_error_cont(sc
, error_continuation
);
9117 klink_push_cont (sc
, combiner
);
9119 /* Conceptually sc->retcode is a keyed dynamic variable that
9120 kernel_err sets. Actually it's entirely cached in the
9127 /*_ , _klink_cycle (Don't use this directly) */
9129 _klink_cycle (klink
* sc
)
9131 pko value
= K_INERT
;
9136 int i
= setjmp (sc
->pseudocontinuation
);
9140 int got_new_frame
= klink_pop_cont (sc
);
9141 /* $$RETHINK ME Is this test still needed? Could be just
9145 /* $$IMPROVE ME Instead, a function that governs
9147 if (sc
->new_tracing
)
9149 if(_get_type( sc
->next_func
) == T_NOTRACE
)
9151 sc
->next_func
= notrace_comb( sc
->next_func
);
9155 klink_find_dyn_binding(sc
, K_TRACING
);
9156 /* Now we know the other branch should have been
9158 if( !tracing
|| ( tracing
== K_F
))
9161 /* Enqueue a version that will execute without
9162 tracing. Its descendants will be traced. */
9163 CONTIN_0_RAW (mk_notrace(mk_curried(dcrry_1dotALL
,
9165 mk_notrace(sc
->next_func
))),
9167 switch (_get_type (sc
->next_func
))
9170 putstr (sc
, "\nLoad ");
9174 putstr (sc
, "\nStore ");
9178 putstr (sc
, "\nDecurry ");
9184 /* Find and print current frame depth */
9185 int depth
= curr_frame_depth (sc
->dump
);
9186 char * str
= sc
->strbuff
;
9187 snprintf (str
, STRBUFFSIZE
, "\n%d: ", depth
);
9190 klink_push_dyn_binding (sc
, K_TRACING
, K_F
);
9191 putstr (sc
, "Eval: ");
9192 value
= kernel_print_sexp (sc
,
9193 cons (sc
->next_func
, value
),
9200 value
= kernel_eval_aux (sc
, sc
->next_func
, value
, sc
->envir
);
9204 /* Stop looping if stack is empty. */
9209 /* Otherwise something jumped to a continuation. Get the
9210 value and keep looping. */
9215 /* In case we're called nested in another _klink_cycle, don't
9220 /*_ . Vtable interface */
9221 /* initialization of Klink */
9224 static struct klink_interface vtbl
=
9276 /* $$MOVE ME Later after I separate some headers
9277 This belongs in dynload.c, could be just:
9278 SIG_CHKARRAY(klink_load_ext) = { REF_OPER(is_string), };
9279 DEF_SIMPLE_APPLICATIVE(ps0a1,klink_load_ext,0,ground, "load-extension") {...}
9281 RGSTR(ground
, "load-extension", REF_APPL(klink_load_ext
))
9282 SIG_CHKARRAY(klink_load_ext
) = { REF_OPER(is_string
), };
9283 DEF_SIMPLE_DESTR(klink_load_ext
);
9284 DEF_CFUNC_PSYCNAME(ps0a1
,klink_load_ext
, REF_DESTR(klink_load_ext
),0);
9285 DEF_BOXED_APPLICATIVE(klink_load_ext
, REF_OPER (klink_load_ext
));
9291 /*_ . Initializing Klink */
9292 /*_ , Allocate and initialize */
9295 klink_alloc_init (FILE * in
, FILE * out
)
9297 klink
*sc
= (klink
*) GC_MALLOC (sizeof (klink
));
9298 if (!klink_init (sc
, in
, out
))
9309 /*_ , Initialization without allocation */
9311 klink_init (klink
* sc
, FILE * in
, FILE * out
)
9313 /* Init stack first, just in case something calls _klink_error_1. */
9314 dump_stack_initialize (sc
);
9315 /* Initialize ports early in case something prints. */
9316 /* $$IMPROVE ME Should accept general ports of appropriate in/out. */
9317 klink_set_input_port_file (sc
, in
);
9318 klink_set_output_port_file (sc
, out
);
9321 /* Why do we need this field if there is a static table? */
9326 sc
->new_tracing
= 0;
9329 { oblist
= oblist_initial_value (); }
9332 /* Add the Kernel built-ins */
9333 if(!print_lookup_env
)
9335 print_lookup_env
= K_REGSTRS_TO_ENV(print_lookup_rgsts
);
9337 if(!all_builtins_env
)
9339 all_builtins_env
= K_REGSTRS_TO_ENV(all_builtins
);
9341 if(!typecheck_env_syms
)
9342 { typecheck_env_syms
= K_REGSTRS_TO_ENV(typecheck_syms_rgsts
); }
9345 /** Register objects from hard-coded list. **/
9346 ground_env
= K_REGSTRS_TO_ENV(preregister
);
9347 /* $$TRANSITIONAL Set up special lookup tables related to preregister. */
9348 setup_print_secondary_lookup();
9349 /** Bind certain objects that we make at init time. **/
9350 kernel_define (ground_env
,
9351 mk_symbol ("print-lookup-env"),
9353 kernel_define (unsafe_env
,
9354 mk_symbol ("typecheck-special-syms"),
9355 typecheck_env_syms
);
9357 /** Read some definitions from a prolog **/
9358 /* We need an envir before klink_call, because that defines a
9359 few things. Those bindings are specific to one instance of
9360 the interpreter so they do not belong in anything shared such
9362 /* $$IMPROVE ME Something in the call chain (klink_call?) should
9363 guarantee an environment. Needn't have anything in it to
9365 sc
->envir
= make_new_frame(K_NIL
);
9367 /* Can't easily merge this with klink_load_named_file. Two
9368 difficulties: it uses klink_cycle_restarting while klink_call
9369 uses klink_cycle_no_restart, and here we need to control the
9370 load environment. */
9371 pko p
= port_from_filename (InitFile
, port_file
| port_input
);
9372 if (p
== K_NIL
) { return 0; }
9374 /* We can't use k_get_mod_fm_port to manage parameters because
9375 later we will need the environment to have several parents:
9376 ground, simple, unsafe, possibly more. */
9377 /* Params: `into' = ground environment */
9378 /* We can't share this with the previous frame-making, because
9379 it should not define in the same environment. */
9380 pko params
= make_new_frame(K_NIL
);
9381 kernel_define (params
, mk_symbol ("into"), ground_env
);
9382 pko env
= make_new_frame(ground_env
);
9383 kernel_define (env
, mk_symbol ("module-parameters"), params
);
9384 int retcode
= klink_call(sc
,
9385 REF_OPER(load_from_port
),
9387 if(retcode
) { return 0; }
9389 /* The load will have written various things into ground
9390 environment. sc->envir is unsuitable now because it is this
9391 load's environment. */
9394 assert (is_environment (ground_env
));
9395 sc
->envir
= make_new_frame(ground_env
);
9397 #if 1 /* Transitional. Leave this on for the moment */
9398 /* initialization of global pointers to special symbols */
9399 sc
->QUOTE
= mk_symbol ("quote");
9400 sc
->QQUOTE
= mk_symbol ("quasiquote");
9401 sc
->UNQUOTE
= mk_symbol ("unquote");
9402 sc
->UNQUOTESP
= mk_symbol ("unquote-splicing");
9403 sc
->COLON_HOOK
= mk_symbol ("*colon-hook*");
9404 sc
->SHARP_HOOK
= mk_symbol ("*sharp-hook*");
9411 klink_deinit (klink
* sc
)
9416 /*_ . Using Klink from C */
9417 /*_ , To set ports */
9419 klink_set_input_port_file (klink
* sc
, FILE * fin
)
9421 klink_push_dyn_binding(sc
,K_INPORT
,port_from_file (fin
, port_input
));
9425 klink_set_input_port_string (klink
* sc
, char *start
, char *past_the_end
)
9427 klink_push_dyn_binding(sc
,
9429 port_from_string (start
, past_the_end
, port_input
));
9433 klink_set_output_port_file (klink
* sc
, FILE * fout
)
9435 klink_push_dyn_binding(sc
,K_OUTPORT
,port_from_file (fout
, port_output
));
9439 klink_set_output_port_string (klink
* sc
, char *start
, char *past_the_end
)
9441 klink_push_dyn_binding(sc
,
9443 port_from_string (start
, past_the_end
, port_output
));
9445 /*_ , To set external data */
9447 klink_set_external_data (klink
* sc
, void *p
)
9454 /*_ . Load file (C) */
9457 klink_load_port (klink
* sc
, pko p
, int interactive
)
9466 klink_push_dyn_binding(sc
,K_INPORT
,p
);
9472 REF_OPER (kernel_repl
) :
9473 REF_OPER (kernel_rel
);
9474 klink_cycle_restarting (sc
, combiner
);
9478 /*_ , klink_load_file */
9480 klink_load_file (klink
* sc
, FILE * fin
)
9482 klink_load_port (sc
,
9483 port_from_file (fin
, port_file
| port_input
),
9487 /*_ , klink_load_named_file */
9489 klink_load_named_file (klink
* sc
, FILE * fin
, const char *filename
)
9492 port_from_filename (filename
, port_file
| port_input
),
9496 /*_ . load string (C) */
9499 klink_load_string (klink
* sc
, const char *cmd
)
9502 port_from_string ((char *)cmd
,
9503 (char *)cmd
+ strlen (cmd
),
9504 port_input
| port_string
),
9508 /*_ , Apply combiner */
9509 /* sc is presumed to be already set up.
9510 The final value or error argument is in sc->value.
9511 The return code is duplicated in sc->retcode.
9514 klink_call (klink
* sc
, pko func
, pko args
)
9516 klink_cycle_no_restart (sc
,
9517 mk_curried(dcrry_NdotALL
,args
,func
));
9522 /* This is completely unexercised. */
9525 klink_eval (klink
* sc
, pko obj
)
9527 klink_cycle_no_restart(sc
,
9528 mk_curried(dcrry_2dotALL
,
9529 LIST2(obj
,sc
->envir
),
9530 REF_OPER(kernel_eval
)));
9534 /*_ . Main (if standalone) */
9537 #if defined(__APPLE__) && !defined (OSX)
9541 extern MacTS_main (int argc
, char **argv
);
9543 int argc
= ccommand (&argv
);
9544 MacTS_main (argc
, argv
);
9550 MacTS_main (int argc
, char **argv
)
9554 main (int argc
, char **argv
)
9559 char *file_name
= 0; /* Was InitFile */
9567 if (argc
== 2 && strcmp (argv
[1], "-?") == 0)
9569 printf ("Usage: klink -?\n");
9570 printf ("or: klink [<file1> <file2> ...]\n");
9571 printf ("followed by\n");
9572 printf (" -1 <file> [<arg1> <arg2> ...]\n");
9573 printf (" -c <Kernel commands> [<arg1> <arg2> ...]\n");
9574 printf ("assuming that the executable is named klink.\n");
9575 printf ("Use - as filename for stdin.\n");
9579 /* Make error_continuation semi-safe until it's properly set. */
9580 sc
.error_continuation
= 0;
9581 int i
= setjmp (sc
.pseudocontinuation
);
9584 if (!klink_init (&sc
, stdin
, stdout
))
9586 fprintf (stderr
, "Could not initialize!\n");
9592 fprintf (stderr
, "Kernel error encountered while initializing!\n");
9596 /* $$IMPROVE ME Maybe use get_opts instead. */
9599 /* $$IMPROVE ME Add a principled way of sometimes including
9600 filename defined in environment. Eg getenv
9604 if(!file_name
) { break; }
9605 if (strcmp (file_name
, "-") == 0)
9609 else if (strcmp (file_name
, "-1") == 0 || strcmp (file_name
, "-c") == 0)
9612 /* $$FACTOR ME This is a messy way to distinguish command
9613 string from filename string */
9614 isfile
= (file_name
[1] == '1');
9615 file_name
= *argv
++;
9616 if (strcmp (file_name
, "-") == 0)
9622 fin
= fopen (file_name
, "r");
9625 /* Put remaining command-line args into *args* in envir. */
9626 for (; *argv
; argv
++)
9628 pko value
= mk_string (*argv
);
9629 args
= mcons (value
, args
);
9631 args
= unsafe_v2reverse_in_place (K_NIL
, args
);
9632 /* Instead, use (command-line) as accessor and provide the
9633 whole command line as a list of strings. */
9634 kernel_define (sc
.envir
, mk_symbol ("*args*"), args
);
9639 fin
= fopen (file_name
, "r");
9641 if (isfile
&& fin
== 0)
9643 fprintf (stderr
, "Could not open file %s\n", file_name
);
9649 /* $$IMPROVE ME Use klink_load_named_file, replacing the
9650 file-opening code, so we can report filename */
9651 klink_load_file (&sc
, fin
);
9655 klink_load_string (&sc
, file_name
);
9657 if (!isfile
|| fin
!= stdin
)
9659 if (sc
.retcode
!= 0)
9661 fprintf (stderr
, "Errors encountered reading %s\n",
9674 /* $$MAKE ME CLEANER Quick and dirty for now, we make an
9675 environment for this but let everything else modify ground
9676 env. I'd like to be more correct about that. */
9677 /* Make an interactive environment over ground_env. */
9678 new_frame_in_env (&sc
, sc
.envir
);
9679 klink_load_file (&sc
, stdin
);
9681 retcode
= sc
.retcode
;