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 */
151 #define VEC_DEF_FROM_ARRAY(ARRAY_NAME) \
153 sizeof(ARRAY_NAME)/sizeof(ARRAY_NAME[0]), \
157 #define DEF_VEC(T_ENUM, NAME, ARRAY_NAME) \
158 kt_boxed_vector NAME = \
161 VEC_DEF_FROM_ARRAY (ARRAY_NAME), \
164 /*_ , Checking type */
165 /*_ . Certain destructurers and type checks */
166 #define K_ANY REF_OPER(is_any)
167 #define K_NO_TYPE REF_KEY(K_TYCH_NO_TYPE)
168 #define K_ANY_SINGLETON REF_OBJ(_K_any_singleton)
170 /*_ . Internal: Arrays to be in typechecks and destructurers */
171 /* Elements of this array should not call Kernel - should be T_NO_K */
172 /* $$IMPROVE ME Check that when registering combiners */
173 #define SIG_CHKARRAY(C_NAME) pko CHKARRAY(C_NAME)[]
174 /*_ . Boxed destructurers */
175 #define REF_DESTR(C_NAME) REF_OBJ(DESTR_NAME(C_NAME))
176 #define DESTR_DEF_FROM_ARRAY(ARRAY_NAME) \
177 { VEC_DEF_FROM_ARRAY (ARRAY_NAME), -1, }
179 #define DEF_DESTR(NAME,ARRAY_NAME) \
180 kt_boxed_destr_list NAME = \
182 T_DESTRUCTURE | T_IMMUTABLE | T_NO_K, \
183 DESTR_DEF_FROM_ARRAY(ARRAY_NAME), \
186 /* DEF_VEC(T_DESTRUCTURE | T_IMMUTABLE | T_NO_K, NAME, ARRAY_NAME) */
188 #define DEF_SIMPLE_DESTR(C_NAME) \
189 DEF_DESTR(DESTR_NAME(C_NAME), CHKARRAY(C_NAME))
194 /* Awkward because we both declare stuff and assign stuff. */
195 #define ALLOC_BOX(NAME,T_ENUM,BOXTYPE) \
196 typedef BOXTYPE _TT; \
197 _TT * NAME = GC_MALLOC(sizeof(_TT)); \
200 /* ALLOC_BOX_PRESUME defines the following:
201 pbox - a pointer to the box
202 pdata - a pointer to the box's contents
204 #define ALLOC_BOX_PRESUME(TYPE,T_ENUM) \
206 ALLOC_BOX(pbox,T_ENUM,BOX_OF(TYPE)); \
207 pdata = &(pbox)->data
211 #define WITH_BOX_TYPE(NAME,P) \
212 _kt_tag * NAME = &((kt_boxed_any *)(P))->type;
215 /* This could mostly be an inlined function, but it wouldn't know
217 #define WITH_UNBOXED_RAW(P,NAME,TYPE,BOXTYPE) \
220 typedef BOXTYPE _TT; \
221 _TT * _pbox = (_TT *)(P); \
222 NAME = &_pbox->data; \
225 /*_ , Entry points */
226 #define WITH_UNBOXED_UNSAFE(NAME,TYPE,P) \
227 WITH_UNBOXED_RAW(P,NAME,TYPE,BOX_OF(TYPE))
230 /* WITH_PSYC_UNBOXED defines the following:
231 pdata - a pointer to the box's contents
233 #define WITH_PSYC_UNBOXED(TYPE,P,T_ENUM,SC) \
234 assert_type(SC,(P),T_ENUM); \
235 WITH_UNBOXED_UNSAFE(pdata,TYPE,P)
239 #define REF_KEY(NAME) REF_OBJ(KEY(NAME))
241 #define BOX_OF_VOID(NAME) \
242 kt_boxed_void KEY(NAME) = { T_KEY | T_IMMUTABLE }; \
243 pko NAME = REF_KEY(NAME)
246 /* All operatives use this, regardless whether they are cfuncs,
248 #define REF_OPER(C_NAME) REF_OBJ(OPER(C_NAME))
251 #define DEF_CFUNC_RAW(NAME,SUFFIX,C_NAME,DESTR,XTRA_FLAGS) \
252 RGSTR(all-builtins,"C-" #C_NAME, REF_OBJ (NAME)) \
253 kt_boxed_cfunc NAME = \
254 { T_CFUNC | T_IMMUTABLE | XTRA_FLAGS, \
255 {{C_NAME}, klink_ftype_##SUFFIX, DESTR, 0}};
257 #define DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME, DESTR,XTRA_FLAGS) \
258 DEF_CFUNC_RAW(OPER(C_NAME),SUFFIX,C_NAME, DESTR,XTRA_FLAGS)
260 #define DEF_CFUNC(SUFFIX,C_NAME,DESTR,XTRA_FLAGS) \
261 KERNEL_FUN_SIG_##SUFFIX(C_NAME); \
262 DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME,DESTR,XTRA_FLAGS); \
263 KERNEL_FUN_SIG_##SUFFIX(C_NAME)
265 #define DEF_SIMPLE_CFUNC(SUFFIX,C_NAME,XTRA_FLAGS) \
266 DEF_SIMPLE_DESTR(C_NAME); \
267 KERNEL_FUN_SIG_##SUFFIX(C_NAME); \
268 DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME,REF_DESTR(C_NAME),XTRA_FLAGS); \
269 KERNEL_FUN_SIG_##SUFFIX(C_NAME)
271 /*_ . Applicatives */
272 #define REF_APPL(C_NAME) REF_OBJ(APPLICATIVE(C_NAME))
274 #define DEF_BOXED_APPLICATIVE(C_NAME,FF) \
275 kt_boxed_encap APPLICATIVE (C_NAME) = \
276 { T_ENCAP | T_IMMUTABLE, \
277 {REF_KEY(K_APPLICATIVE), FF}};
279 #define DEF_APPLICATIVE_W_DESTR(SUFFIX,C_NAME,DESTR,XTRA_FLAGS,RG,K_NAME) \
280 RGSTR(RG,K_NAME, REF_APPL(C_NAME)) \
281 KERNEL_FUN_SIG_##SUFFIX(C_NAME); \
282 DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME,DESTR,XTRA_FLAGS); \
283 DEF_BOXED_APPLICATIVE(C_NAME, REF_OPER (C_NAME)); \
284 KERNEL_FUN_SIG_##SUFFIX(C_NAME)
286 #define DEF_SIMPLE_APPLICATIVE(SUFFIX,C_NAME,XTRA_FLAGS,RG,K_NAME) \
287 RGSTR(RG,K_NAME, REF_APPL(C_NAME)) \
288 DEF_SIMPLE_DESTR(C_NAME); \
289 KERNEL_FUN_SIG_##SUFFIX(C_NAME); \
290 DEF_CFUNC_PSYCNAME(SUFFIX,C_NAME,REF_DESTR(C_NAME),XTRA_FLAGS); \
291 DEF_BOXED_APPLICATIVE(C_NAME, REF_OPER (C_NAME)); \
292 KERNEL_FUN_SIG_##SUFFIX(C_NAME)
294 /*_ . Abbreviations for predicates */
295 /* The underlying C function takes the whole value as its sole arg.
296 Above that, in init.krn an applicative wrapper applies it over a
297 list, using `every?'.
299 #define DEF_SIMPLE_PRED(C_NAME,XTRA_FLAGS,RG,K_NAME) \
300 RGSTR(RG,K_NAME, REF_OPER(C_NAME)) \
301 DEF_CFUNC(b00a1,C_NAME,K_ANY_SINGLETON,XTRA_FLAGS)
303 /* The cfunc is there just to be exported for C use. */
304 #define DEF_T_PRED(C_NAME,T_ENUM,RG,K_NAME) \
305 RGSTR(RG,K_NAME, REF_OPER(C_NAME)) \
306 kt_boxed_T OPER(C_NAME) = \
307 { T_TYPEP | T_IMMUTABLE | T_NO_K, {T_ENUM}}; \
308 int C_NAME(pko p) { return is_type(p,T_ENUM); }
311 /*_ . Curried Functions */
313 #define DEF_BOXED_CURRIED(CURRY_NAME,DECURRIER,ARGS,NEXT) \
314 RGSTR(all-builtins,"C-" #CURRY_NAME, REF_OBJ (CURRY_NAME)) \
315 kt_boxed_curried CURRY_NAME = \
316 { T_CURRIED | T_IMMUTABLE, \
317 {DECURRIER, ARGS, NEXT, 0}};
319 #define DEF_BOXED_PAIR(C_NAME,CAR,CDR) \
320 boxed_vec2 C_NAME = \
321 { T_PAIR | T_IMMUTABLE, {CAR, CDR, }}
324 #define DEF_LISTSTAR2 DEF_BOXED_PAIR
326 #define DEF_LISTSTAR3(C_NAME,A1,A2,A3) \
327 DEF_BOXED_PAIR(C_NAME##__1,A2,A3); \
328 DEF_BOXED_PAIR(C_NAME,A1,REF_OBJ(C_NAME##__1))
330 #define DEF_LIST1(C_NAME,A1) DEF_LISTSTAR2(C_NAME,A1, REF_KEY(K_NIL))
331 #define DEF_LIST2(C_NAME,A1,A2) DEF_LISTSTAR3(C_NAME,A1,A2,REF_KEY(K_NIL))
333 /*_ , Building objects in C */
334 #define ANON_OBJ( TYPE, X ) \
335 (((BOX_OF( TYPE )[]) { X })[0])
337 /* Middle is the same as ANON_OBJ but we can't just use that because
338 of expansion issues */
339 #define ANON_REF( TYPE, X ) \
340 REF_OBJ((((BOX_OF( TYPE )[]) { X })[0]))
342 #define PAIR_DEF( CAR, CDR ) \
343 { T_PAIR | T_IMMUTABLE, { CAR, CDR, }, }
345 #define ANON_PAIR( CAR, CDR ) \
346 ANON_REF(kt_vec2, PAIR_DEF( CAR, CDR ))
348 #define INT_DEF( N ) \
349 { T_NUMBER | T_IMMUTABLE, { 1, { N }, }, }
352 /*_ , Building lists in C */
353 /*_ . Anonymous lists */
355 #define ANON_LISTSTAR2(A1, A2) \
358 #define ANON_LISTSTAR3(A1, A2, A3) \
359 ANON_PAIR(A1, ANON_LISTSTAR2(A2, A3))
361 #define ANON_LISTSTAR4(A1, A2, A3, A4) \
362 ANON_PAIR(A1, ANON_LISTSTAR3(A2, A3, A4))
365 #define ANON_LIST1(A1) \
366 ANON_LISTSTAR2(A1, REF_KEY(K_NIL))
368 #define ANON_LIST2(A1, A2) \
369 ANON_PAIR(A1, ANON_LIST1(A2))
371 #define ANON_LIST3(A1, A2, A3) \
372 ANON_PAIR(A1, ANON_LIST2(A2, A3))
374 #define ANON_LIST4(A1, A2, A3, A4) \
375 ANON_PAIR(A1, ANON_LIST3(A2, A3, A4))
377 #define ANON_LIST5(A1, A2, A3, A4, A5) \
378 ANON_PAIR(A1, ANON_LIST4(A2, A3, A4, A5))
380 #define ANON_LIST6(A1, A2, A3, A4, A5, A6) \
381 ANON_PAIR(A1, ANON_LIST5(A2, A3, A4, A5, A6))
384 /*_ . Dynamic lists */
386 #define LISTSTAR2(A1, A2) \
388 #define LISTSTAR3(A1, A2, A3) \
389 cons (A1, LISTSTAR2(A2, A3))
390 #define LISTSTAR4(A1, A2, A3, A4) \
391 cons (A1, LISTSTAR3(A2, A3, A4))
397 #define LIST2(A1, A2) \
398 cons (A1, LIST1 (A2))
399 #define LIST3(A1, A2, A3) \
400 cons (A1, LIST2 (A2, A3))
401 #define LIST4(A1, A2, A3, A4) \
402 cons (A1, LIST3 (A2, A3, A4))
403 #define LIST5(A1, A2, A3, A4, A5) \
404 cons (A1, LIST4 (A2, A3, A4, A5))
405 #define LIST6(A1, A2, A3, A4, A5, A6) \
406 cons (A1, LIST5 (A2, A3, A4, A5, A6))
408 /*_ , Kernel continuation macros */
409 /*_ . W/o decurrying */
410 #define CONTIN_0_RAW(C_NAME,SC) \
411 klink_push_cont((SC), (C_NAME))
412 #define CONTIN_0(OPER_NAME,SC) \
413 klink_push_cont((SC), REF_OPER (OPER_NAME))
416 /* The use of REF_OPER requires these to be macros. */
418 #define CONTIN_1R(DECURRIER,C_NAME,SC,ARGS) \
419 klink_push_cont((SC), \
420 mk_curried(DECURRIER, ARGS, REF_OPER (C_NAME)))
422 #define CONTIN_2R(DECURRIER,C_NAME,SC,ARG1,ARG2) \
423 CONTIN_1R(DECURRIER,C_NAME,SC,cons(ARG1,ARG2))
425 #define CONTIN_3R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3) \
426 CONTIN_2R(DECURRIER,C_NAME,SC,ARG1,cons(ARG2,ARG3))
428 #define CONTIN_4R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4) \
429 CONTIN_3R(DECURRIER,C_NAME,SC,ARG1,ARG2,cons(ARG3,ARG4))
431 #define CONTIN_5R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,ARG5) \
432 CONTIN_4R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,cons(ARG4,ARG5))
434 #define CONTIN_6R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \
435 CONTIN_5R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,cons(ARG5,ARG6))
439 #define CONTIN_1(DECURRIER,C_NAME,SC,ARG1) \
440 CONTIN_2R(DECURRIER,C_NAME,SC,ARG1,K_NIL)
442 #define CONTIN_2(DECURRIER,C_NAME,SC,ARG1,ARG2) \
443 CONTIN_3R(DECURRIER,C_NAME,SC,ARG1,ARG2,K_NIL)
445 #define CONTIN_3(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3) \
446 CONTIN_4R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,K_NIL)
448 #define CONTIN_4(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4) \
449 CONTIN_5R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,K_NIL)
451 #define CONTIN_5(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,ARG5) \
452 CONTIN_6R(DECURRIER,C_NAME,SC,ARG1,ARG2,ARG3,ARG4,ARG5,K_NIL)
455 #define kernel_bool(tf) ((tf) ? K_T : K_F)
457 /*_ , Control macros */
459 /* These never return because _klink_error_1 longjmps. */
460 /* $$IMPROVE ME If GCC is used or C99 is available, use __func__ as the function name. */
461 #define KERNEL_ERROR_1(sc,s, a) { _klink_error_1(sc,s,a); return 0; }
462 #define KERNEL_ERROR_0(sc,s) { _klink_error_1(sc,s,0); return 0; }
464 /*_ . Enumerations */
465 /*_ , The port types & flags */
480 typedef enum klink_token
498 /*_ , List metrics */
507 typedef int int4
[lm_max
];
509 /*_ . Struct definitions */
512 typedef BOX_OF (kt_cfunc
)
519 /* Object identity lets us compare instances. */
524 typedef BOX_OF (kt_encap
)
527 /*_ , Curried calls */
529 typedef pko (* decurrier_f
) (klink
* sc
, pko args
, pko value
);
534 decurrier_f decurrier
;
540 typedef BOX_OF (kt_curried
)
543 /*_ , T_typep calls */
550 typedef BOX_OF(typep_t
)
584 typedef BOX_OF(kt_vector
)
586 /*_ , Destructurer */
587 /*_ , kt_destr_list */
594 typedef BOX_OF(kt_destr_list
)
598 /*_ , Initialization */
599 static void klink_setup_error_cont (klink
* sc
);
600 static void klink_cycle_restarting (klink
* sc
, pko combiner
);
601 static int klink_cycle_no_restart (klink
* sc
, pko combiner
);
602 static void _klink_cycle (klink
* sc
);
605 /*_ , Error handling */
606 static void _klink_error_1 (klink
* sc
, const char *s
, pko a
);
607 /*_ . Stack control */
608 static int klink_pop_cont (klink
* sc
);
611 static pko
klink_call_cfunc (klink
* sc
, pko functor
, pko env
, pko args
);
612 FORWARD_DECL_CFUNC (static, ps0a2
, k_resume_to_cfunc
);
616 mk_load_ix (int x
, int y
);
621 mk_store (pko data
, int depth
);
625 call_curried(klink
* sc
, pko curried
, pko value
);
627 /*_ , Top level operatives */
628 FORWARD_DECL_APPLICATIVE(static,ps0a0
,kernel_repl
);
629 FORWARD_DECL_APPLICATIVE(static,ps0a0
,kernel_rel
);
630 FORWARD_DECL_APPLICATIVE(static,ps0a1
,kernel_internal_eval
);
633 static INLINE pko
oblist_find_by_name (const char *name
);
634 static pko
oblist_add_by_name (const char *name
);
637 static pko
mk_number (num n
);
639 static num
num_add (num a
, num b
);
640 static num
num_mul (num a
, num b
);
641 static num
num_div (num a
, num b
);
642 static num
num_intdiv (num a
, num b
);
643 static num
num_sub (num a
, num b
);
644 static num
num_rem (num a
, num b
);
645 static num
num_mod (num a
, num b
);
646 static int num_eq (num a
, num b
);
647 static int num_gt (num a
, num b
);
648 static int num_ge (num a
, num b
);
649 static int num_lt (num a
, num b
);
650 static int num_le (num a
, num b
);
653 static double round_per_R5RS (double x
);
656 /*_ , Lists and vectors */
657 FORWARD_DECL_PRED (extern, is_finite_list
);
658 FORWARD_DECL_PRED (extern, is_countable_list
);
659 extern int list_length (pko a
);
660 static pko
reverse (klink
* sc
, pko a
);
661 static pko
unsafe_v2reverse_in_place (pko term
, pko list
);
662 static pko
append (klink
* sc
, pko a
, pko b
);
664 static pko
alloc_basvector (int len
, _kt_tag t_enum
);
665 static void unsafe_basvector_fill (pko vec
, pko obj
);
667 static pko
mk_vector (int len
, pko fill
);
668 INTERFACE
static void fill_vector (pko vec
, pko obj
);
669 INTERFACE
static pko
vector_elem (pko vec
, int ielem
);
670 INTERFACE
static void set_vector_elem (pko vec
, int ielem
, pko a
);
671 INTERFACE
static int vector_len (pko vec
);
673 get_list_metrics_aux (pko a
, int4 presults
);
676 k_counted_map_car(klink
* sc
, int count
, pko list
, _kt_tag t_enum
);
678 k_counted_map_cdr(klink
* sc
, int count
, pko list
, _kt_tag t_enum
);
681 static pko
port_from_filename (const char *fn
, int prop
);
682 static pko
port_from_file (FILE *, int prop
);
683 static pko
port_from_string (char *start
, char *past_the_end
, int prop
);
684 static void port_close (pko p
, int flag
);
685 static void port_finalize_file(GC_PTR obj
, GC_PTR client_data
);
686 static port
*port_rep_from_filename (const char *fn
, int prop
);
687 static port
*port_rep_from_file (FILE *, int prop
);
688 static port
*port_rep_from_string (char *start
, char *past_the_end
, int prop
);
689 static void port_close_port (port
* pt
, int flag
);
690 INLINE port
* portvalue (pko p
);
691 static int basic_inchar (port
* pt
);
692 static int inchar (port
*pt
);
693 static void backchar (port
* pt
, int c
);
695 FORWARD_DECL_APPLICATIVE (extern,ps0a1
, mk_typecheck
);
696 FORWARD_DECL_APPLICATIVE (extern,ps0a1
, mk_destructurer
);
697 FORWARD_DECL_CFUNC (extern, ps0a4
, destructure_resume
);
698 FORWARD_DECL_PRED (extern, is_any
);
699 FORWARD_DECL_T_PRED (extern, is_environment
);
700 FORWARD_DECL_PRED (extern, is_integer
);
702 FORWARD_DECL_CFUNC (extern,ps0a2
,handle_promise_result
);
703 FORWARD_DECL_CFUNC (extern, ps0a1
, mk_promise_lazy
);
704 FORWARD_DECL_APPLICATIVE (extern, ps0a1
, force
);
705 /*_ , About encapsulation */
706 FORWARD_DECL_CFUNC (static,b00a2
, is_encap
);
707 FORWARD_DECL_CFUNC (static,p00a2
, mk_encap
);
708 FORWARD_DECL_CFUNC (static,ps0a2
, unencap
);
709 FORWARD_DECL_APPLICATIVE (extern,p00a0
, mk_encapsulation_type
);
711 /*_ , About combiners per se */
712 FORWARD_DECL_PRED(extern,is_combiner
);
713 /*_ , About operatives */
714 FORWARD_DECL_PRED(extern,is_operative
);
716 schedule_rv_list(klink
* sc
, pko list
);
718 /*_ , About applicatives */
720 FORWARD_DECL_PRED(extern,is_applicative
);
721 FORWARD_DECL_APPLICATIVE(extern,p00a1
,wrap
);
722 FORWARD_DECL_APPLICATIVE(extern,ps0a1
,unwrap
);
723 FORWARD_DECL_APPLICATIVE(extern,p00a1
,unwrap_all
);
725 /*_ , About currying */
730 static pko
dcrry_2A01VLL (klink
* sc
, pko args
, pko value
);
731 static pko
dcrry_3A01dotVLL (klink
* sc
, pko args
, pko value
);
732 static pko
dcrry_2CA01VLLA02 (klink
* sc
, pko args
, pko value
);
733 /* May not be needed */
734 static pko
dcrry_3A01A02VLL (klink
* sc
, pko args
, pko value
);
735 static pko
dcrry_2ALLVLL (klink
* sc
, pko args
, pko value
);
736 static pko
dcrry_2ALLV01 (klink
* sc
, pko args
, pko value
);
738 static pko
dcrry_NdotALL (klink
* sc
, pko args
, pko value
);
739 #define dcrry_1A01 dcrry_NdotALL
740 #define dcrry_1dotALL dcrry_NdotALL
741 #define dcrry_2dotALL dcrry_NdotALL
742 #define dcrry_3dotALL dcrry_NdotALL
743 #define dcrry_4dotALL dcrry_NdotALL
745 static pko
dcrry_1ALL (klink
* sc
, pko args
, pko value
);
747 static pko
dcrry_5ALLdotVLL (klink
* sc
, pko args
, pko value
);
748 #define dcrry_3ALLdotVLL dcrry_5ALLdotVLL
750 static pko
dcrry_NVLLdotALL (klink
* sc
, pko args
, pko value
);
751 #define dcrry_2VLLdotALL dcrry_NVLLdotALL
752 #define dcrry_3VLLdotALL dcrry_NVLLdotALL
753 #define dcrry_4VLLdotALL dcrry_NVLLdotALL
754 #define dcrry_5VLLdotALL dcrry_NVLLdotALL
756 static pko
dcrry_1VLL (klink
* sc
, pko args
, pko value
);
757 static pko
dcrry_NCVLLA01dotAX1 (klink
* sc
, pko args
, pko value
);
758 #define dcrry_2CVLLA01dotAX1 dcrry_NCVLLA01dotAX1
759 #define dcrry_3CVLLA01dotAX1 dcrry_NCVLLA01dotAX1
760 #define dcrry_4CVLLA01dotAX1 dcrry_NCVLLA01dotAX1
761 #define dcrry_5CVLLA01dotAX1 dcrry_NCVLLA01dotAX1
763 FORWARD_DECL_CFUNC(static,ps0a4
,values_pair
);
766 /*_ , Of Kernel evaluation */
767 /*_ . Public functions */
768 FORWARD_DECL_APPLICATIVE(extern,ps0a2
,kernel_eval
);
769 FORWARD_DECL_CFUNC (extern,ps0a3
, vau_1
);
770 /*_ . Other signatures */
771 FORWARD_DECL_APPLICATIVE(static,ps0a3
,kernel_eval_aux
);
772 FORWARD_DECL_APPLICATIVE(static,ps0a3
,kernel_mapeval
);
773 FORWARD_DECL_APPLICATIVE(static,ps0a3
, kernel_mapand_aux
);
774 FORWARD_DECL_APPLICATIVE(extern,ps0a2
, kernel_mapand
);
775 FORWARD_DECL_APPLICATIVE(static,ps0a5
,eval_vau
);
779 FORWARD_DECL_APPLICATIVE(static,ps0a0
,kernel_read_internal
);
780 FORWARD_DECL_CFUNC(extern,ps0a0
,kernel_read_sexp
);
781 FORWARD_DECL_CFUNC(static,ps0a2
,kernel_read_list
);
782 FORWARD_DECL_CFUNC(static,ps0a2
,kernel_treat_dotted_list
);
783 FORWARD_DECL_CFUNC(static,ps0a1
,kernel_treat_qquoted_vec
);
785 static INLINE
int is_one_of (char *s
, int c
);
786 static long binary_decode (const char *s
);
787 static char *readstr_upto (klink
* sc
, char *delim
);
788 static pko
readstrexp (klink
* sc
);
789 static INLINE
int skipspace (klink
* sc
);
790 static int token (klink
* sc
);
791 static pko
mk_atom (klink
* sc
, char *q
);
792 static pko
mk_sharp_const (char *name
);
795 /* $$IMPROVE ME These should mostly be just operatives. */
796 FORWARD_DECL_APPLICATIVE(static,ps0a2
,kernel_print_sexp
);
797 FORWARD_DECL_APPLICATIVE(static,ps0a3
,kernel_print_sexp_aux
);
798 FORWARD_DECL_APPLICATIVE(static,ps0a3
,kernel_print_list
);
799 FORWARD_DECL_APPLICATIVE(static,ps0a4
,kernel_print_vec_from
);
800 static kt_boxed_curried k_print_terminate_list
;
802 static void printslashstring (klink
* sc
, char *s
, int len
);
803 static void atom2str (klink
* sc
, pko l
, char **pp
, int *plen
);
804 static void printatom (klink
* sc
, pko l
);
806 /*_ , Stack & continuations */
807 /*_ . Continuations */
808 static pko
mk_continuation (_kt_spagstack d
);
809 static void klink_push_cont (klink
* sc
, pko combiner
);
811 klink_push_cont_aux (_kt_spagstack old_frame
, pko ff
, pko env
);
812 FORWARD_DECL_APPLICATIVE(extern,p00a1
,continuation_to_applicative
);
813 FORWARD_DECL_CFUNC(static,vs0a2
,invoke_continuation
);
814 FORWARD_DECL_CFUNC(static,ps0a2
,continue_abnormally
);
815 static _kt_spagstack special_dynxtnt
816 (_kt_spagstack outer
, _kt_spagstack prox_dest
, pko envir
);
820 /*_ . Dynamic bindings */
821 static void klink_push_dyn_binding (klink
* sc
, pko id
, pko value
);
822 static pko
klink_find_dyn_binding(klink
* sc
, pko id
);
824 struct stack_profiling
;
826 k_profiling_done_frame(klink
* sc
, struct stack_profiling
* profile
);
829 get_nth_arg( _kt_spagstack frame
, int n
);
831 push_arg (klink
* sc
, pko value
);
833 /*_ , Environment and defining */
834 FORWARD_DECL_CFUNC(static,vs0a3
,kernel_define_tree
);
835 FORWARD_DECL_CFUNC(extern,p00a3
,kernel_define
);
836 FORWARD_DECL_CFUNC(extern,ps0a2
,eval_define
);
837 FORWARD_DECL_CFUNC(extern,ps0a3
,set
);
838 FORWARD_DECL_CFUNC(static,ps0a4
,set_aux
);
840 static pko
find_slot_in_env (pko env
, pko sym
, int all
);
841 static INLINE pko
slot_value_in_env (pko slot
);
842 static INLINE
void set_slot_in_env (pko slot
, pko value
);
844 reverse_find_slot_in_env_aux (pko env
, pko value
);
845 /*_ . Standard environment */
846 FORWARD_DECL_CFUNC(extern,p00a0
, mk_std_environment
);
847 FORWARD_DECL_APPLICATIVE (extern,ps0a0
, get_current_environment
);
848 /*_ , Misc kernel functions */
850 FORWARD_DECL_CFUNC(extern,ps0a1
,arg1
);
851 FORWARD_DECL_APPLICATIVE(extern,ps0a1
,val2val
)
853 /*_ , Error functions */
854 FORWARD_DECL_CFUNC(static,ps0a1
,kernel_err
);
855 FORWARD_DECL_CFUNC(static,ps0a1
,kernel_err_x
);
857 /*_ , For DL if present */
859 FORWARD_DECL_APPLICATIVE(extern,ps0a1
,klink_load_ext
);
863 static pko
mk_symbol_obj (const char *name
);
866 static char *store_string (int len
, const char *str
, char fill
);
868 /*_ . Object declarations */
870 /* These objects are declared here because some macros use them, but
871 should not be directly used. */
872 /* $$IMPROVE ME Somehow hide these better without hiding it from the
873 applicative & destructure macros. */
874 kt_boxed_void
KEY(K_APPLICATIVE
);
875 kt_boxed_void
KEY(K_NIL
);
877 kt_boxed_destr_list _K_any_singleton
;
878 /*_ , Pointers to base environments */
879 static pko print_lookup_env
;
880 static pko all_builtins_env
;
881 static pko ground_env
;
882 static pko typecheck_env_syms
;
884 static pko print_lookup_unwraps
;
885 static pko print_lookup_to_xary
;
888 /*_ . Low-level treating T-types */
894 WITH_BOX_TYPE(ptype
,p
);
895 return *ptype
& T_MASKTYPE
;
900 is_type (pko p
, int T_index
)
902 return _get_type (p
) == T_index
;
904 /*_ . type_err_string */
906 type_err_string(_kt_tag t_enum
)
911 return "Must be a string";
913 return "Must be a number";
915 return "Must be a symbol";
917 return "Must be a pair";
919 return "Must be a character";
921 return "Must be a port";
923 return "Must be an encapsulation";
925 return "Must be a continuation";
927 return "Must be an environment";
929 return "Must be a recurrence table";
930 case T_RECUR_TRACKER
:
931 return "Must be a recurrence tracker";
933 return "Must be a destructure result";
935 /* Left out types that shouldn't be distinguished in Kernel. */
936 return "Error message for this type needs to be coded";
940 /* If sc is given, it's a assertion making a Kernel error, otherwise
941 it's a C assertion. */
943 assert_type (sc_or_null sc
, pko p
, _kt_tag t_enum
)
945 if(sc
&& (_get_type(p
) != (t_enum
)))
947 const char * err_msg
= type_err_string(t_enum
);
948 _klink_error_1(sc
,err_msg
,p
);
949 return; /* NOTREACHED */
952 { assert (_get_type(p
) == (t_enum
)); }
960 WITH_BOX_TYPE(ptype
,p
);
961 return *ptype
& T_IMMUTABLE
;
964 INTERFACE INLINE
void
967 WITH_BOX_TYPE(ptype
,p
);
968 *ptype
|= T_IMMUTABLE
;
971 /* If sc is given, it's a assertion making a Kernel error, otherwise
972 it's a C assertion. */
974 assert_mutable (sc_or_null sc
, pko p
)
976 WITH_BOX_TYPE(ptype
,p
);
977 if(sc
&& (*ptype
& T_IMMUTABLE
))
979 _klink_error_1(sc
,"Attempt to mutate immutable object",p
);
983 { assert(!(*ptype
& T_IMMUTABLE
)); }
986 #define DEBUG_assert_mutable assert_mutable
988 /*_ , No-call-Kernel */
992 WITH_BOX_TYPE(ptype
,p
);
993 return *ptype
& T_NO_K
;
996 SIG_CHKARRAY(eqp
) = { K_ANY
, K_ANY
, };
997 DEF_SIMPLE_APPLICATIVE(p00a2
,eqp
,T_NO_K
,ground
,"eq?")
1000 return kernel_bool(a
== b
);
1002 /*_ . Low-level object types */
1003 /*_ , vec2 (Low lists) */
1010 typedef BOX_OF(kt_vec2
) boxed_vec2
;
1012 /*_ . Type assert */
1013 /* $$IMPROVE ME Disable this if DEBUG_LEVEL is low */
1014 void assert_T_is_v2(_kt_tag t_enum
)
1016 t_enum
&= T_MASKTYPE
;
1019 || t_enum
== T_ENV_PAIR
1020 || t_enum
== T_ENV_FRAME
1021 || t_enum
== T_PROMISE
1022 || t_enum
== T_DESTR_RESULT
1028 v2cons (_kt_tag t_enum
, pko a
, pko b
)
1030 ALLOC_BOX_PRESUME (kt_vec2
, t_enum
);
1031 pbox
->data
._car
= a
;
1032 pbox
->data
._cdr
= b
;
1033 return PTR2PKO(pbox
);
1036 /*_ . Unsafe operations (Typechecks can be disabled) */
1038 unsafe_v2car (pko p
)
1040 assert_T_is_v2(_get_type(p
));
1041 WITH_UNBOXED_UNSAFE(pdata
,kt_vec2
,p
);
1046 unsafe_v2cdr (pko p
)
1048 assert_T_is_v2(_get_type(p
));
1049 WITH_UNBOXED_UNSAFE(pdata
,kt_vec2
,p
);
1054 unsafe_v2set_car (pko p
, pko q
)
1056 assert_T_is_v2(_get_type(p
));
1057 DEBUG_assert_mutable(0,p
);
1058 WITH_UNBOXED_UNSAFE(pdata
,kt_vec2
,p
);
1064 unsafe_v2set_cdr (pko p
, pko q
)
1066 assert_T_is_v2(_get_type(p
));
1067 DEBUG_assert_mutable(0,p
);
1068 WITH_UNBOXED_UNSAFE(pdata
,kt_vec2
,p
);
1073 /*_ . Checked operations */
1075 v2car (sc_or_null err_reporter
, _kt_tag t_enum
, pko p
)
1077 assert_type(err_reporter
,p
,t_enum
);
1078 return unsafe_v2car(p
);
1082 v2cdr (sc_or_null err_reporter
, _kt_tag t_enum
, pko p
)
1084 assert_type(err_reporter
,p
,t_enum
);
1085 return unsafe_v2cdr(p
);
1089 v2set_car (sc_or_null err_reporter
, _kt_tag t_enum
, pko p
, pko q
)
1091 assert_type(err_reporter
,p
,t_enum
);
1092 assert_mutable(err_reporter
,p
);
1093 unsafe_v2set_car(p
,q
);
1098 v2set_cdr (sc_or_null err_reporter
, _kt_tag t_enum
, pko p
, pko q
)
1100 assert_type(err_reporter
,p
,t_enum
);
1101 assert_mutable(err_reporter
,p
);
1102 unsafe_v2set_cdr(p
,q
);
1106 /*_ . "Psychic" macros */
1107 #define WITH_V2(T_ENUM) \
1108 _kt_tag _t_enum = T_ENUM; \
1109 assert_T_is_v2(_t_enum)
1111 /* These expect WITH_REPORTER and WITH_V2 to be used in scope. */
1112 #define PSYC_v2cons(A,B) v2cons (_t_enum, (A), (B))
1113 #define PSYC_v2car(X) v2car (_err_reporter, _t_enum, (X))
1114 #define PSYC_v2cdr(X) v2cdr (_err_reporter, _t_enum, (X))
1115 #define PSYC_v2set_car(A,B) v2set_car (_err_reporter, _t_enum, (A), (B))
1116 #define PSYC_v2set_cdr(A,B) v2set_cdr (_err_reporter, _t_enum, (A), (B))
1118 /*_ . Container macros */
1120 /* This expects _EXPLORE_FUNC to be defined as a macro taking OBJ,
1121 inspecting it but not mutating it. */
1122 #define EXPLORE_v2(OBJ) \
1124 WITH_UNBOXED_UNSAFE(pdata,kt_vec2,OBJ); \
1125 _EXPLORE_FUNC(pdata->_car); \
1126 _EXPLORE_FUNC(pdata->_cdr); \
1129 /* #define _EXPLORE_FUNC(X) trace_tree_cycles(X, p_cycles_data) */
1131 /*_ . Low list operations */
1132 /*_ , v2list_star */
1133 pko
v2list_star(sc_or_null sc
, pko d
, _kt_tag t_enum
)
1138 pko cdr_d
= PSYC_v2cdr (d
);
1141 return PSYC_v2car (d
);
1143 p
= PSYC_v2cons (PSYC_v2car (d
), cdr_d
);
1146 while (PSYC_v2cdr (PSYC_v2cdr (p
)) != K_NIL
)
1148 pko cdr_p
= PSYC_v2cdr (p
);
1149 d
= PSYC_v2cons (PSYC_v2car (p
), cdr_p
);
1150 if (PSYC_v2cdr (cdr_p
) != K_NIL
)
1155 PSYC_v2set_cdr (p
, PSYC_v2car (PSYC_v2cdr (p
)));
1159 /*_ , reverse list -- produce new list */
1160 pko
v2reverse(pko a
, _kt_tag t_enum
)
1164 for (; is_type (a
, t_enum
); a
= unsafe_v2cdr (a
))
1166 p
= v2cons (t_enum
, unsafe_v2car (a
), p
);
1171 /*_ , reverse list -- in-place (Not typechecked) */
1172 /* last_cdr will be the tail of the resulting list. It is usually
1175 list is the list to be reversed. Caller guarantees that list is a
1176 proper list, each link being either some type of vec2 or K_NIL.
1179 unsafe_v2reverse_in_place (pko last_cdr
, pko list
)
1181 pko p
= list
, result
= last_cdr
;
1184 pko scratch
= unsafe_v2cdr (p
);
1185 unsafe_v2set_cdr (p
, result
);
1191 /*_ , append list -- produce new list */
1192 pko
v2append(sc_or_null err_reporter
, pko a
, pko b
, _kt_tag t_enum
)
1199 a
= v2reverse (a
, t_enum
);
1200 /* Correct even if b is nil or a non-list. */
1201 return unsafe_v2reverse_in_place(b
, a
);
1206 /*_ , basvectors (Low vectors) */
1208 /* Above so it can be visible to early typecheck declarations. */
1209 /*_ . Type assert */
1210 void assert_T_is_basvector(_kt_tag t_enum
)
1212 t_enum
&= T_MASKTYPE
;
1214 t_enum
== T_VECTOR
||
1215 t_enum
== T_TYPECHECK
||
1216 t_enum
== T_DESTRUCTURE
1221 /*_ , rough_basvec_init */
1222 /* Create the elements but don't assign to them. */
1224 basvec_init_rough (kt_vector
* pvec
, int len
)
1227 pvec
->els
= (pko
*)GC_MALLOC ((sizeof (pko
) * len
));
1229 /*_ , basvec_init_by_list */
1230 /* Initialize the elements of PVEC with the first LEN elements of
1231 ARGS. ARGS must be a list with at least LEN elements. */
1233 basvec_init_by_list (kt_vector
* pvec
, pko args
)
1237 const int num
= pvec
->len
;
1239 for (x
= args
, i
= 0; i
< num
; x
= cdr (x
), i
++)
1241 assert (is_pair (x
));
1242 pvec
->els
[i
] = car (x
);
1245 /*_ , basvec_init_by_array */
1246 /* Initialize the elements of PVEC with the first LEN elements of
1247 ARRAY. ARRAY must be an array with at least LEN elements. */
1249 basvec_init_by_array (kt_vector
* pvec
, pko
* array
)
1252 const int num
= pvec
->len
;
1253 for (i
= 0; i
< num
; i
++)
1255 pvec
->els
[i
] = array
[i
];
1258 /*_ , basvec_init_by_single */
1260 basvec_init_by_single (kt_vector
* pvec
, pko obj
)
1263 const int num
= pvec
->len
;
1265 for (i
= 0; i
< num
; i
++)
1266 { pvec
->els
[i
] = obj
; }
1269 /*_ , Get element */
1271 basvec_get_element (kt_vector
* pvec
, int index
)
1274 assert(index
< pvec
->len
);
1275 return pvec
->els
[index
];
1279 basvec_fill_array(kt_vector
* pvec
, int max_len
, pko
* array
)
1282 const int num
= pvec
->len
;
1284 assert (num
<= max_len
);
1285 for (i
= 0; i
< num
; i
++)
1287 array
[i
] = pvec
->els
[i
];
1293 basvec_set_element (kt_vector
* pvec
, int index
, pko obj
)
1296 assert(index
< pvec
->len
);
1297 pvec
->els
[index
] = obj
;
1300 /*_ . Treat as boxed */
1301 /* Functions following here assume that kt_vector is in a box by itself. */
1302 /*_ , alloc_basvector */
1304 alloc_basvector (int len
, _kt_tag t_enum
)
1306 assert_T_is_basvector(t_enum
);
1307 ALLOC_BOX_PRESUME(kt_vector
, t_enum
);
1308 basvec_init_rough(&pbox
->data
, len
);
1309 return PTR2PKO(pbox
);
1311 /*_ , mk_basvector_w_args */
1313 mk_basvector_w_args(klink
* sc
, pko args
, _kt_tag t_enum
)
1315 assert_T_is_basvector(t_enum
);
1317 get_list_metrics_aux(args
, metrics
);
1318 if (metrics
[lm_num_nils
] != 1)
1320 KERNEL_ERROR_1 (sc
, "mk_basvector_w_args: not a proper list:", args
);
1322 int len
= metrics
[lm_acyc_len
];
1323 pko vec
= alloc_basvector(len
, t_enum
);
1324 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1325 basvec_init_by_list (pdata
, args
);
1328 /*_ , mk_filled_basvector */
1330 mk_filled_basvector(int len
, pko fill
, _kt_tag t_enum
)
1332 assert_T_is_basvector(t_enum
);
1333 pko vec
= alloc_basvector(len
, t_enum
);
1334 unsafe_basvector_fill (vec
, fill
);
1337 /*_ , mk_basvector_from_array */
1339 mk_basvector_from_array(int len
, pko
* array
, _kt_tag t_enum
)
1341 assert_T_is_basvector(t_enum
);
1342 pko vec
= alloc_basvector(len
, t_enum
);
1343 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1344 basvec_init_by_array (pdata
, array
);
1347 /*_ , mk_foresliced_basvector */
1349 mk_foresliced_basvector (pko vec
, int excess
, _kt_tag t_enum
)
1351 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1352 const int len
= pdata
->len
;
1353 assert (len
>= excess
);
1354 const int remnant_len
= len
- excess
;
1355 return mk_basvector_from_array (remnant_len
,
1356 pdata
->els
+ excess
,
1359 /*_ . Unsafe operations (Typechecks can be disabled) */
1360 /*_ , unsafe_basvector_fill */
1362 unsafe_basvector_fill (pko vec
, pko obj
)
1364 assert_T_is_basvector(_get_type(vec
));
1365 assert_mutable(0,vec
);
1366 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1367 basvec_init_by_single (pdata
, obj
);
1369 /*_ , basvector_len */
1371 basvector_len (pko vec
)
1373 assert_T_is_basvector(_get_type(vec
));
1374 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1378 /*_ , basvector_elem */
1380 basvector_elem (pko vec
, int ielem
)
1382 assert_T_is_basvector(_get_type(vec
));
1383 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1384 return basvec_get_element (pdata
, ielem
);
1387 /*_ , basvector_set_elem */
1389 basvector_set_elem (pko vec
, int ielem
, pko a
)
1391 assert_T_is_basvector(_get_type(vec
));
1392 assert_mutable(0,vec
);
1393 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,vec
);
1394 basvec_set_element (pdata
, ielem
, a
);
1397 /*_ , basvector_fill_array */
1399 basvector_fill_array(pko vec
, int max_len
, pko
* array
)
1401 assert_T_is_basvector(_get_type(vec
));
1402 WITH_UNBOXED_UNSAFE (p_vec
, kt_vector
, vec
);
1403 basvec_fill_array (p_vec
, max_len
, array
);
1406 /*_ . Checked operations */
1407 /*_ , Basic strings (Low strings) */
1408 /*_ . Struct kt_string */
1418 bastring_value (sc_or_null sc
, _kt_tag t_enum
, pko p
)
1420 WITH_PSYC_UNBOXED(kt_string
,p
, t_enum
, sc
);
1421 return pdata
->_svalue
;
1425 bastring_len (sc_or_null sc
, _kt_tag t_enum
, pko p
)
1427 WITH_PSYC_UNBOXED(kt_string
,p
, t_enum
, sc
);
1428 return pdata
->_length
;
1434 store_string (int len_str
, const char *str
, char fill
)
1438 q
= (char *) GC_MALLOC_ATOMIC (len_str
+ 1);
1441 snprintf (q
, len_str
+ 1, "%s", str
);
1445 memset (q
, fill
, len_str
);
1452 mk_bastring (_kt_tag t_enum
, const char *str
, int len
, char fill
)
1454 ALLOC_BOX_PRESUME (kt_string
, t_enum
);
1455 pbox
->data
._svalue
= store_string(len
, str
, fill
);
1456 pbox
->data
._length
= len
;
1457 return PTR2PKO(pbox
);
1460 /*_ . Type assert */
1461 void assert_T_is_bastring(_kt_tag t_enum
)
1463 t_enum
&= T_MASKTYPE
;
1465 t_enum
== T_STRING
||
1466 t_enum
== T_SYMBOL
);
1469 /*_ . Individual object types */
1475 DEF_SIMPLE_PRED(is_bool
,T_NO_K
,ground
, "boolean?/o1")
1478 return (p
== K_T
) || (p
== K_F
);
1481 SIG_CHKARRAY(not) = { REF_OPER(is_bool
), };
1482 DEF_SIMPLE_APPLICATIVE(p00a1
,not,T_NO_K
,ground
, "not?")
1485 if(p
== K_T
) { return K_F
; }
1486 if(p
== K_F
) { return K_T
; }
1487 errx(6, "not: Argument must be boolean");
1491 /*_ . Number constants */
1493 /* We would use these for "folding" operations like cumulative addition. */
1494 static num num_zero
= { 1, {0}, };
1495 static num num_one
= { 1, {1}, };
1498 #define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
1499 #define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
1501 /*_ . Making them */
1504 mk_integer (long num
)
1506 ALLOC_BOX_PRESUME (struct num
, T_NUMBER
);
1507 pbox
->data
.value
.ivalue
= num
;
1508 pbox
->data
.is_fixnum
= 1;
1509 return PTR2PKO(pbox
);
1515 ALLOC_BOX_PRESUME (num
, T_NUMBER
);
1516 pbox
->data
.value
.rvalue
= n
;
1517 pbox
->data
.is_fixnum
= 0;
1518 return PTR2PKO(pbox
);
1526 return mk_integer (n
.value
.ivalue
);
1530 return mk_real (n
.value
.rvalue
);
1534 /*_ . Checking them */
1535 static int is_zero_double (double x
);
1538 num_is_integer (pko p
)
1540 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1541 return (pdata
->is_fixnum
);
1544 DEF_T_PRED (is_number
,T_NUMBER
,ground
,"number?/o1");
1546 DEF_SIMPLE_PRED (is_posint
,T_NO_K
,ground
,"posint?/o1")
1549 return is_integer (p
) && ivalue (p
) >= 0;
1552 /* $$IMPROVE ME later Integer and real should be separate T_ types. */
1553 DEF_SIMPLE_PRED (is_integer
,T_NO_K
,ground
, "integer?/o1")
1556 if(!is_number (p
)) { return 0; }
1557 WITH_UNBOXED_UNSAFE(pdata
,num
,p
);
1558 return (pdata
->is_fixnum
);
1561 DEF_SIMPLE_PRED (is_real
,T_NO_K
,ground
, "real?/o1")
1564 if(!is_number (p
)) { return 0; }
1565 WITH_UNBOXED_UNSAFE(pdata
,num
,p
);
1566 return (!pdata
->is_fixnum
);
1568 DEF_SIMPLE_PRED (is_zero
,T_NO_K
,ground
, "zero?/o1")
1571 /* Behavior on non-numbers wasn't specified so I'm assuming the
1572 predicate just fails. */
1573 if(!is_number (p
)) { return 0; }
1574 WITH_UNBOXED_UNSAFE(pdata
,num
,p
);
1575 if(pdata
->is_fixnum
)
1577 return (ivalue (p
) == 0);
1581 return is_zero_double(rvalue(p
));
1584 /* $$WRITE ME positive? negative? odd? even? */
1585 /*_ . Getting their values */
1589 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1596 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1597 return (num_is_integer (p
) ? pdata
->value
.ivalue
: (long) pdata
->
1604 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1605 return (!num_is_integer (p
)
1606 ? pdata
->value
.rvalue
: (double) pdata
->value
.ivalue
);
1610 set_ivalue (pko p
, long i
)
1612 assert_mutable(0,p
);
1613 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1614 assert (num_is_integer (p
));
1615 pdata
->value
.ivalue
= i
;
1620 add_to_ivalue (pko p
, long i
)
1622 assert_mutable(0,p
);
1623 WITH_PSYC_UNBOXED(num
,p
,T_NUMBER
,0);
1624 assert (num_is_integer (p
));
1625 pdata
->value
.ivalue
+= i
;
1629 /*_ . Operating on numbers */
1631 num_add (num a
, num b
)
1634 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1637 ret
.value
.ivalue
= a
.value
.ivalue
+ b
.value
.ivalue
;
1641 ret
.value
.rvalue
= num_rvalue (a
) + num_rvalue (b
);
1647 num_mul (num a
, num b
)
1650 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1653 ret
.value
.ivalue
= a
.value
.ivalue
* b
.value
.ivalue
;
1657 ret
.value
.rvalue
= num_rvalue (a
) * num_rvalue (b
);
1663 num_div (num a
, num b
)
1666 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
1667 && a
.value
.ivalue
% b
.value
.ivalue
== 0;
1670 ret
.value
.ivalue
= a
.value
.ivalue
/ b
.value
.ivalue
;
1674 ret
.value
.rvalue
= num_rvalue (a
) / num_rvalue (b
);
1680 num_intdiv (num a
, num b
)
1683 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1686 ret
.value
.ivalue
= a
.value
.ivalue
/ b
.value
.ivalue
;
1690 ret
.value
.rvalue
= num_rvalue (a
) / num_rvalue (b
);
1696 num_sub (num a
, num b
)
1699 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1702 ret
.value
.ivalue
= a
.value
.ivalue
- b
.value
.ivalue
;
1706 ret
.value
.rvalue
= num_rvalue (a
) - num_rvalue (b
);
1712 num_rem (num a
, num b
)
1716 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1717 e1
= num_ivalue (a
);
1718 e2
= num_ivalue (b
);
1720 /* modulo should have same sign as second operand */
1735 ret
.value
.ivalue
= res
;
1740 num_mod (num a
, num b
)
1744 ret
.is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1745 e1
= num_ivalue (a
);
1746 e2
= num_ivalue (b
);
1749 { /* modulo should have same sign as second operand */
1760 ret
.value
.ivalue
= res
;
1765 num_eq (num a
, num b
)
1768 int is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1771 ret
= a
.value
.ivalue
== b
.value
.ivalue
;
1775 ret
= num_rvalue (a
) == num_rvalue (b
);
1782 num_gt (num a
, num b
)
1785 int is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1788 ret
= a
.value
.ivalue
> b
.value
.ivalue
;
1792 ret
= num_rvalue (a
) > num_rvalue (b
);
1798 num_ge (num a
, num b
)
1800 return !num_lt (a
, b
);
1804 num_lt (num a
, num b
)
1807 int is_fixnum
= a
.is_fixnum
&& b
.is_fixnum
;
1810 ret
= a
.value
.ivalue
< b
.value
.ivalue
;
1814 ret
= num_rvalue (a
) < num_rvalue (b
);
1820 num_le (num a
, num b
)
1822 return !num_gt (a
, b
);
1826 /* Round to nearest. Round to even if midway */
1828 round_per_R5RS (double x
)
1830 double fl
= floor (x
);
1831 double ce
= ceil (x
);
1832 double dfl
= x
- fl
;
1833 double dce
= ce
- x
;
1844 if (fmod (fl
, 2.0) == 0.0)
1845 { /* I imagine this holds */
1857 is_zero_double (double x
)
1859 return x
< DBL_MIN
&& x
> -DBL_MIN
;
1863 binary_decode (const char *s
)
1867 while (*s
!= 0 && (*s
== '1' || *s
== '0'))
1877 /* "Psychically" defines a and b. */
1878 #define WITH_PSYC_AB_ARGS(A_TYPE,B_TYPE) \
1879 WITH_UNBOXED_UNSAFE(a,A_TYPE,arg1); \
1880 WITH_UNBOXED_UNSAFE(b,B_TYPE,arg2)
1884 /*_ . Binary operations */
1885 SIG_CHKARRAY(num_binop
) = { REF_OPER(is_number
), REF_OPER(is_number
), };
1886 DEF_SIMPLE_DESTR(num_binop
);
1888 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_add
,REF_DESTR(num_binop
),0,ground
, "add")
1890 WITH_PSYC_AB_ARGS(num
,num
);
1891 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1892 *pdata
= num_add (*a
, *b
);
1893 return PTR2PKO(pbox
);
1896 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_sub
,REF_DESTR(num_binop
),0,ground
, "sub")
1898 WITH_PSYC_AB_ARGS(num
,num
);
1899 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1900 *pdata
= num_sub (*a
, *b
);
1901 return PTR2PKO(pbox
);
1904 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_mul
,REF_DESTR(num_binop
),0,ground
, "mul")
1906 WITH_PSYC_AB_ARGS(num
,num
);
1907 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1908 *pdata
= num_mul (*a
, *b
);
1909 return PTR2PKO(pbox
);
1912 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_div
,REF_DESTR(num_binop
),0,ground
, "div")
1914 WITH_PSYC_AB_ARGS(num
,num
);
1915 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1916 *pdata
= num_div (*a
, *b
);
1917 return PTR2PKO(pbox
);
1920 DEF_APPLICATIVE_W_DESTR(ps0a2
,k_mod
,REF_DESTR(num_binop
),0,ground
, "mod")
1922 WITH_PSYC_AB_ARGS(num
,num
);
1923 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1924 *pdata
= num_mod (*a
, *b
);
1925 return PTR2PKO(pbox
);
1927 /*_ . Binary predicates */
1928 DEF_APPLICATIVE_W_DESTR(bs0a2
,k_gt
,REF_DESTR(num_binop
),0,ground
, ">?/2")
1930 WITH_PSYC_AB_ARGS(num
,num
);
1931 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1932 return num_gt (*a
, *b
);
1935 DEF_APPLICATIVE_W_DESTR(bs0a2
,k_eq
,REF_DESTR(num_binop
),0,simple
, "equal?/2-num-num")
1937 WITH_PSYC_AB_ARGS(num
,num
);
1938 ALLOC_BOX_PRESUME(num
,T_NUMBER
);
1939 return num_eq (*a
, *b
);
1944 DEF_T_PRED (is_character
,T_CHARACTER
,ground
, "character?/o1");
1949 WITH_PSYC_UNBOXED(long,p
,T_CHARACTER
,0);
1954 mk_character (int c
)
1956 ALLOC_BOX_PRESUME (long, T_CHARACTER
);
1958 return PTR2PKO(pbox
);
1961 /*_ . Classifying characters */
1962 #if USE_CHAR_CLASSIFIERS
1966 return isascii (c
) && isalpha (c
);
1972 return isascii (c
) && isdigit (c
);
1978 return isascii (c
) && isspace (c
);
1984 return isascii (c
) && isupper (c
);
1990 return isascii (c
) && islower (c
);
1993 /*_ . Character names */
1995 static const char *charnames
[32] = {
2031 is_ascii_name (const char *name
, int *pc
)
2034 for (i
= 0; i
< 32; i
++)
2036 if (stricmp (name
, charnames
[i
]) == 0)
2042 if (stricmp (name
, "del") == 0)
2052 /*_ , Void objects */
2054 DEF_T_PRED (is_key
, T_KEY
,no
,"");
2058 BOX_OF_VOID (K_NIL
);
2059 BOX_OF_VOID (K_EOF
);
2060 BOX_OF_VOID (K_INERT
);
2061 BOX_OF_VOID (K_IGNORE
);
2062 /*_ . "Secret" objects for built-in keyed dynamic bindings */
2063 BOX_OF_VOID (K_PRINT_FLAG
);
2064 BOX_OF_VOID (K_TRACING
);
2065 BOX_OF_VOID (K_INPORT
);
2066 BOX_OF_VOID (K_OUTPORT
);
2067 BOX_OF_VOID (K_NEST_DEPTH
);
2068 /*_ . Keys for typecheck */
2069 BOX_OF_VOID (K_TYCH_DOT
);
2070 BOX_OF_VOID (K_TYCH_REPEAT
);
2071 BOX_OF_VOID (K_TYCH_OPTIONAL
);
2072 BOX_OF_VOID (K_TYCH_IMP_REPEAT
);
2073 BOX_OF_VOID (K_TYCH_NO_TYPE
);
2075 /*_ . Making them dynamically */
2076 DEF_CFUNC(p00a0
, mk_void
, K_NO_TYPE
,T_NO_K
)
2078 ALLOC_BOX(pbox
,T_KEY
,kt_boxed_void
);
2079 return PTR2PKO(pbox
);
2082 DEF_SIMPLE_PRED(is_null
,T_NO_K
,ground
, "null?/o1")
2087 DEF_SIMPLE_PRED(is_inert
,T_NO_K
,ground
, "inert?/o1")
2090 return p
== K_INERT
;
2092 DEF_SIMPLE_PRED(is_ignore
,T_NO_K
,ground
, "ignore?/o1")
2095 return p
== K_IGNORE
;
2099 /*_ , Typecheck & destructure objects */
2101 /* _car is vector component, _cdr is list component. */
2102 typedef kt_vec2 kt_destr_result
;
2103 /*_ . Enumeration */
2111 DEF_T_PRED (is_destr_result
, T_DESTR_RESULT
, no
, "");
2112 /*_ . Building them */
2113 /*_ , can_be_trivpred */
2114 /* Return true if the object can be used as a trivial predicate: An
2115 xary operative that does not call Kernel and returns a boolean as
2117 DEF_SIMPLE_PRED(can_be_trivpred
,T_NO_K
,unsafe
,"trivpred?/o1")
2120 if(!no_call_k(p
)) { return 0; }
2121 switch(_get_type(p
))
2125 WITH_UNBOXED_UNSAFE(pdata
,kt_cfunc
,p
);
2128 case klink_ftype_b00a1
:
2150 /*_ , k_to_trivpred */
2151 /* Convert a unary or nary function to xary. If not possible, return
2153 /* $$OBSOLESCENT Only used in print lookup, which will change */
2155 k_to_trivpred(pko p
)
2157 if(is_applicative(p
))
2158 { p
= unwrap_all(p
); }
2160 if(can_be_trivpred(p
))
2165 /*_ , type-keys environment */
2166 RGSTR(type
-keys
, "cyclic-repeat", REF_KEY(K_TYCH_IMP_REPEAT
) )
2167 RGSTR(type
-keys
, "optional", REF_KEY(K_TYCH_OPTIONAL
) )
2168 RGSTR(type
-keys
, "repeat", REF_KEY(K_TYCH_REPEAT
) )
2169 RGSTR(type
-keys
, "dot", REF_KEY(K_TYCH_DOT
) )
2171 int any_k (kt_vector
* p_vec_guts
)
2174 for (i
= 0; i
< p_vec_guts
->len
; i
++)
2176 pko obj
= p_vec_guts
->els
[i
];
2177 WITH_BOX_TYPE(tag
,obj
);
2178 if (*tag
| ~(T_NO_K
)) { return 1; }
2184 DEF_APPLICATIVE_W_DESTR (ps0a1
, mk_typecheck
, REF_OPER(is_finite_list
),T_NO_K
,unsafe
, "listtype/N-trivpred")
2186 pko vec
= mk_basvector_w_args(sc
, arg1
, T_TYPECHECK
| T_IMMUTABLE
| T_NO_K
);
2187 #if 0 /* $$ENABLE ME later */
2188 /* If everything is T_NO_K, then give flag T_NO_K. */
2189 WITH_UNBOXED_UNSAFE (pdata
, kt_vector
, vec
);
2192 WITH_BOX_TYPE(tag
,vec
);
2198 /*_ , Destructurer */
2199 DEF_APPLICATIVE_W_DESTR (ps0a1
, mk_destructurer
, REF_OPER(is_finite_list
),T_NO_K
,unsafe
, "destructure-list/N-trivpred")
2201 /* $$IMPROVE MY SUPPORT A destructurer should fill up this */
2203 get_list_metrics_aux(arg1
, metrics
);
2204 if (metrics
[lm_num_nils
] != 1)
2206 KERNEL_ERROR_1 (sc
, "mk_destructurer: not a proper list:", arg1
);
2208 int len
= metrics
[lm_acyc_len
];
2209 ALLOC_BOX_PRESUME(kt_destr_list
, T_DESTRUCTURE
| T_IMMUTABLE
| T_NO_K
);
2210 basvec_init_rough (&pdata
->cvec
, len
);
2211 basvec_init_by_list (&pdata
->cvec
, arg1
);
2212 pdata
->num_targets
= -1;
2214 #if 0 /* $$ENABLE ME later when typemiss check is OK for this */
2215 /* If everything is T_NO_K, then give flag T_NO_K. */
2216 if (!any_k (&pdata
->cvec
))
2218 WITH_BOX_TYPE(tag
,vec
);
2222 return PTR2PKO(pbox
);
2224 /*_ , Destructurer Result state */
2225 /* Really a mixed vector/list */
2226 /*_ . mk_destr_result */
2229 (int len
, pko
* array
, pko more_vals
)
2231 pko vec
= mk_basvector_from_array(len
, array
, T_VECTOR
);
2232 return v2cons (T_DESTR_RESULT
, vec
, more_vals
);
2234 /*_ . mk_destr_result_add */
2237 (pko old
, int len
, pko
* array
)
2239 pko val_list
= unsafe_v2cdr (old
);
2241 for (i
= 0; i
< len
; i
++)
2243 val_list
= cons ( array
[i
], val_list
);
2245 return v2cons (T_DESTR_RESULT
,
2249 /*_ . destr_result_fill_array */
2251 destr_result_fill_array (pko dr
, int max_len
, pko
* array
)
2253 /* Assume errors are due to C code. */
2255 WITH_PSYC_UNBOXED (kt_destr_result
, dr
, T_DESTR_RESULT
, 0)
2257 basvector_len (pdata
->_car
);
2258 basvector_fill_array(pdata
->_car
, vec_len
, array
);
2259 /* We get args earliest lowest, so insert them in reverse order. */
2260 int list_len
= list_length (pdata
->_cdr
);
2261 int i
= vec_len
+ list_len
- 1;
2262 assert (i
< max_len
);
2264 for (args
= pdata
->_cdr
; args
!= K_NIL
; args
= cdr (args
), i
--)
2266 array
[i
] = car (args
);
2270 /*_ , destr_result_to_vec */
2271 SIG_CHKARRAY (destr_result_to_vec
) =
2273 REF_OPER (is_destr_result
),
2276 DEF_SIMPLE_CFUNC (p00a1
, destr_result_to_vec
, T_NO_K
)
2278 WITH_1_ARGS (destr_result
);
2279 WITH_UNBOXED_UNSAFE (p_destr_result
, kt_destr_result
, destr_result
);
2281 basvector_len (p_destr_result
->_car
) +
2282 list_length (p_destr_result
->_cdr
);
2283 pko vec
= mk_vector (len
, K_NIL
);
2284 WITH_UNBOXED_UNSAFE (p_vec
, kt_destr_list
, vec
);
2285 destr_result_fill_array (destr_result
, len
, p_vec
->cvec
.els
);
2289 /*_ . Particular typechecks */
2290 /*_ , Any singleton */
2291 pko _K_ARRAY_any_singleton
[] = { K_ANY
, };
2292 DEF_DESTR(_K_any_singleton
,_K_ARRAY_any_singleton
);
2293 /*_ , Typespec itself */
2294 #define K_TY_TYPESPEC K_ANY
2295 /*_ , Destructure spec itself */
2296 #define K_TY_DESTRSPEC K_ANY
2297 /*_ , Top type (Always succeeds) */
2298 RGSTR(ground
, "true/o1", REF_OPER(is_any
))
2299 DEF_CFUNC(b00a1
,is_any
,K_ANY_SINGLETON
,T_NO_K
)
2302 /* Not entirely redundant; Used internally to check scheduled returns. */
2303 DEF_CFUNC(b00a1
,is_true
,K_ANY_SINGLETON
,T_NO_K
)
2309 /*_ . Internal signatures */
2312 (klink
*sc
, pko argobject
, pko
* ar_typespec
, int count
, int style
);
2314 where_typemiss_repeat
2315 (klink
*sc
, pko argobject
, pko
* ar_typespec
, int count
, int style
);
2317 static where_typemiss_do_spec
2318 (klink
* sc
, pko argobject
, pko
* ar_typespec
, int left
);
2320 typecheck_by_vec (klink
* sc
, pko argobject
, pko
* ar_typespec
, int left
);
2322 /*_ . Typecheck operations */
2324 call_T_typecheck(pko T
, pko obj
)
2326 WITH_PSYC_UNBOXED(typep_t
,T
,T_TYPEP
,0);
2327 return is_type(obj
,pdata
->T_tag
);
2330 /* This is an optimization under-the-hood for running
2331 possibly-compound predicates. Ultimately it will not be exposed.
2332 Later it may have a Kernel "safe counterpart" that is optimized to
2335 It should not call anything that calls Kernel. All its
2336 "components" should be trivpreds (xary operatives that don't use
2337 eval loop), satisfying can_be_trivpred, generally specified
2339 /* We don't have a typecheck typecheck predicate yet, so accept
2340 anything for arg2. */
2341 SIG_CHKARRAY(typecheck
) = { K_ANY
, K_ANY
, };
2342 DEF_SIMPLE_APPLICATIVE (bs0a2
, typecheck
,T_NO_K
,unsafe
,"type?")
2344 WITH_2_ARGS(argobject
,typespec
);
2345 assert(no_call_k(typespec
));
2346 switch(_get_type(typespec
))
2350 WITH_UNBOXED_UNSAFE(pdata
,kt_cfunc
,typespec
);
2353 case klink_ftype_b00a1
:
2355 return pdata
->func
.f_b00a1(argobject
);
2358 errx(7, "typecheck: Object is not a typespec");
2361 break; /* NOTREACHED */
2363 return call_T_typecheck(typespec
, argobject
);
2364 case T_DESTRUCTURE
: /* Fallthru */
2366 WITH_UNBOXED_UNSAFE(pdata
,kt_destr_list
,typespec
);
2367 pko
* ar_typespec
= pdata
->cvec
.els
;
2368 int left
= pdata
->cvec
.len
;
2369 return typecheck_by_vec (sc
, argobject
, ar_typespec
, left
);
2373 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,typespec
);
2374 pko
* ar_typespec
= pdata
->els
;
2375 int left
= pdata
->len
;
2376 return typecheck_by_vec (sc
, argobject
, ar_typespec
, left
);
2380 errx(7, "typecheck: Object is not a typespec");
2382 return 0; /* NOTREACHED */
2384 /*_ , typecheck_by_vec */
2386 typecheck_by_vec (klink
* sc
, pko argobject
, pko
* ar_typespec
, int left
)
2388 int saw_optional
= 0;
2389 for( ; left
; ar_typespec
++, left
--)
2391 pko tych
= *ar_typespec
;
2392 /**** Check for special keys ****/
2393 if(tych
== REF_KEY(K_TYCH_DOT
))
2397 KERNEL_ERROR_0 (sc
, "typecheck: After dot there must "
2398 "be exactly one typespec");
2401 { return typecheck(sc
, argobject
, ar_typespec
[1]); }
2403 if(tych
== REF_KEY(K_TYCH_OPTIONAL
))
2407 KERNEL_ERROR_0 (sc
, "typecheck: Can't have two optionals");
2415 if(tych
== REF_KEY(K_TYCH_REPEAT
))
2418 typecheck_repeat(sc
,argobject
,
2423 if(tych
== REF_KEY(K_TYCH_IMP_REPEAT
))
2426 typecheck_repeat(sc
,argobject
,
2432 /*** Manage stepping ***/
2433 if(!is_pair(argobject
))
2443 pko c
= pair_car(0,argobject
);
2444 argobject
= pair_cdr(0,argobject
);
2446 /*** Do the check ***/
2447 if (!typecheck(sc
, c
, tych
)) { return 0; }
2450 if(argobject
!= K_NIL
)
2455 /*_ , typecheck_repeat */
2458 (klink
*sc
, pko argobject
, pko
* ar_typespec
, int count
, int style
)
2461 get_list_metrics_aux(argobject
, metrics
);
2462 /* Dotted lists don't satisfy repeat */
2463 if(!metrics
[lm_num_nils
]) { return 0; }
2464 if(metrics
[lm_cyc_len
])
2466 /* STYLE may not allow cycles. */
2469 /* If there's a cycle and count doesn't fit into it exactly,
2470 call that a mismatch. */
2471 if(count
% metrics
[lm_cyc_len
])
2474 /* Check the car of each pair. */
2477 for(step
= 0, i
= 0;
2478 step
< metrics
[lm_num_pairs
];
2479 ++step
, ++i
, argobject
= pair_cdr(0,argobject
))
2481 if(i
== count
) { i
= 0; }
2482 assert(is_pair(argobject
));
2483 pko tych
= ar_typespec
[i
];
2484 pko c
= pair_car(0,argobject
);
2485 if (!typecheck(sc
, c
, tych
)) { return 0; }
2489 /*_ , where_typemiss */
2490 /* This parallels typecheck, but where typecheck returned a boolean,
2491 this returns an object indicating where the type failed to match. */
2492 SIG_CHKARRAY(where_typemiss
) = { K_ANY
, K_ANY
, };
2493 DEF_SIMPLE_APPLICATIVE (ps0a2
, where_typemiss
,T_NO_K
,unsafe
, "where-typemiss")
2495 /* Return a list indicating how TYPESPEC failed to match
2497 WITH_2_ARGS(argobject
,typespec
);
2498 assert(no_call_k(typespec
));
2499 switch(_get_type(typespec
))
2503 WITH_UNBOXED_UNSAFE(pdata
,kt_cfunc
,typespec
);
2506 case klink_ftype_b00a1
:
2508 if (pdata
->func
.f_b00a1(argobject
))
2513 { return LIST1(typespec
); }
2516 errx(7, "where_typemiss: Object is not a typespec");
2520 break; /* NOTREACHED */
2523 WITH_PSYC_UNBOXED(typep_t
,typespec
,T_TYPEP
,0);
2524 if (call_T_typecheck(typespec
, argobject
))
2527 { return LIST1(mk_string(type_err_string(pdata
->T_tag
))); }
2532 WITH_UNBOXED_UNSAFE(pdata
,kt_destr_list
,typespec
);
2533 return where_typemiss_do_spec(sc
, argobject
, pdata
->cvec
.els
, pdata
->cvec
.len
);
2537 WITH_UNBOXED_UNSAFE(pdata
,kt_vector
,typespec
);
2538 return where_typemiss_do_spec(sc
, argobject
, pdata
->els
, pdata
->len
);
2542 errx(7,"where_typemiss: Object is not a typespec");
2545 return 0; /* NOTREACHED */
2547 /*_ , where_typemiss_do_spec */
2549 where_typemiss_do_spec
2550 (klink
* sc
, pko argobject
, pko
* ar_typespec
, int left
)
2552 int saw_optional
= 0;
2554 for( ; left
; ar_typespec
++, left
--)
2556 pko tych
= *ar_typespec
;
2557 /**** Check for special keys ****/
2558 if(tych
== REF_KEY(K_TYCH_DOT
))
2562 KERNEL_ERROR_0 (sc
, "where_typemiss: After dot there must "
2563 "be exactly one typespec");
2568 where_typemiss(sc
, argobject
, ar_typespec
[1]);
2572 LISTSTAR3(mk_integer(el_num
),
2580 if(tych
== REF_KEY(K_TYCH_OPTIONAL
))
2584 KERNEL_ERROR_0 (sc
, "where_typemiss: Can't have two optionals");
2592 if(tych
== REF_KEY(K_TYCH_REPEAT
))
2595 where_typemiss_repeat(sc
,argobject
,
2600 { return LISTSTAR3(mk_integer(el_num
),mk_symbol("repeat"), result
); }
2604 if(tych
== REF_KEY(K_TYCH_IMP_REPEAT
))
2607 where_typemiss_repeat(sc
,argobject
,
2612 { return LISTSTAR3(mk_integer(el_num
),mk_symbol("improper-repeat"),result
); }
2617 /*** Manage stepping ***/
2618 if(!is_pair(argobject
))
2622 return LIST2(mk_integer(el_num
), mk_symbol("too-few"));
2630 pko c
= pair_car(0,argobject
);
2631 argobject
= pair_cdr(0,argobject
);
2634 /*** Do the check ***/
2635 pko result
= where_typemiss(sc
, c
, tych
);
2637 { return LISTSTAR2(mk_integer(el_num
),result
); }
2640 if(argobject
!= K_NIL
)
2641 { return LIST2(mk_integer(el_num
), mk_symbol("too-many")); }
2645 /*_ , where_typemiss_repeat */
2647 where_typemiss_repeat
2648 (klink
*sc
, pko argobject
, pko
* ar_typespec
, int count
, int style
)
2651 get_list_metrics_aux(argobject
, metrics
);
2652 /* Dotted lists don't satisfy repeat */
2653 if(!metrics
[lm_num_nils
]) { return LIST1(mk_symbol("dotted")); }
2654 if(metrics
[lm_cyc_len
])
2656 /* STYLE may not allow cycles. */
2658 { return LIST1(mk_symbol("circular")); }
2659 /* If there's a cycle and count doesn't fit into it exactly,
2660 call that a mismatch. */
2661 if(count
% metrics
[lm_cyc_len
])
2662 { return LIST1(mk_symbol("misaligned-end")); }
2664 /* Check the car of each pair. */
2667 for(step
= 0, i
= 0;
2668 step
< metrics
[lm_num_pairs
];
2669 ++step
, ++i
, argobject
= pair_cdr(0,argobject
))
2671 if(i
== count
) { i
= 0; }
2672 assert(is_pair(argobject
));
2673 pko tych
= ar_typespec
[i
];
2674 pko c
= pair_car(0,argobject
);
2675 pko result
= where_typemiss(sc
, c
, tych
);
2677 { return LISTSTAR2(mk_integer(step
),result
); }
2682 /*_ . Destructuring operations */
2683 /*_ , destructure_by_bool */
2684 /* Just for calling back after a freeform predicate */
2685 SIG_CHKARRAY (destructure_by_bool
) =
2687 REF_OPER (is_destr_result
),
2691 DEF_SIMPLE_CFUNC (ps0a3
, destructure_by_bool
, 0)
2693 WITH_3_ARGS (destr_result
, argobject
, satisfied
);
2694 if (satisfied
== K_T
)
2697 mk_destr_result_add (destr_result
, 1, &argobject
);
2699 else if (satisfied
!= K_F
)
2701 KERNEL_ERROR_0 (sc
, "Predicate should return a boolean");
2705 KERNEL_ERROR_0 (sc
, "type mismatch on non-C predicate");
2709 /*_ , destructure_how_many */
2711 destructure_how_many (pko typespec
)
2713 switch (_get_type(typespec
))
2717 WITH_UNBOXED_UNSAFE(pdata
,kt_destr_list
,typespec
);
2718 if (pdata
->num_targets
>= 0)
2719 { return pdata
->num_targets
;}
2723 pko
* ar_typespec
= pdata
->cvec
.els
;
2724 int left
= pdata
->cvec
.len
;
2725 for( ; left
; ar_typespec
++, left
--)
2727 pko tych
= *ar_typespec
;
2728 count
+= destructure_how_many (tych
);
2730 pdata
->num_targets
= count
;
2740 /*_ , destructure_make_ops */
2742 destructure_make_ops
2743 (pko argobject
, pko typespec
, int saw_optional
)
2746 /* Operations to run, in reverse order. */
2748 /* ^V= result-so-far */
2749 REF_OPER (destructure_resume
),
2750 /* V= (result-so-far argobject spec optional?) */
2751 mk_load (LIST4 (mk_load_ix (1, 0),
2754 kernel_bool (saw_optional
))),
2755 mk_store (K_ANY
, 1),
2756 /* V= forced-argobject */
2758 /* ^V= (argobject) */
2759 mk_load (LIST1 (argobject
)),
2761 /* ^V= result-so-far */
2764 /*_ , destructure_make_ops_to_bool */
2766 destructure_make_ops_to_bool
2767 (pko argobject
, pko op_on_argobject
)
2769 assert (is_combiner (op_on_argobject
));
2771 /* Operations to run, in reverse order. */
2773 /* ^V= result-so-far */
2774 REF_OPER (destructure_by_bool
),
2775 /* V= (result-so-far bool spec) */
2776 mk_load (LIST3 (mk_load_ix (1, 0),
2778 mk_load_ix (0, 0))),
2779 mk_store (K_ANY
, 1),
2782 /* ^V= (argobject) */
2783 mk_load (LIST1 (argobject
)),
2785 /* ^V= result-so-far */
2788 /*_ , destructure */
2789 /* Callers: past_end should point into the same array as *outarray.
2790 It will indicate the maximum number number of elements we may
2791 write. The return value is the remainder of the outarray if
2792 successful, otherwise NULL.
2793 The meaning of extra_result depends on the return value:
2794 * On success, it's unused.
2795 * On destr_err, it's unused (but will later hold an error object)
2796 * On destr_must_call_k, it holds a list of operations.
2800 (klink
* sc
, pko argobject
, pko typespec
, pko
** outarray
,
2801 pko
* past_end
, pko
* extra_result
, int saw_optional
)
2803 if(*outarray
== past_end
)
2805 /* $$IMPROVE ME Treat this error like other mismatches */
2806 KERNEL_ERROR_0 (sc
, "destructure: past end of output array");
2808 if(_get_type(typespec
) == T_DESTRUCTURE
)
2810 WITH_UNBOXED_UNSAFE(pdata
,kt_destr_list
,typespec
);
2811 pko
* ar_typespec
= pdata
->cvec
.els
;
2812 int left
= pdata
->cvec
.len
;
2813 for( ; left
; ar_typespec
++, left
--)
2815 pko tych
= *ar_typespec
;
2817 /**** Check for special keys ****/
2818 if(tych
== REF_KEY(K_TYCH_DOT
))
2822 KERNEL_ERROR_0 (sc
, "destructure: After dot there must "
2823 "be exactly one typespec");
2826 { return destructure(sc
, argobject
,
2834 if(tych
== REF_KEY(K_TYCH_OPTIONAL
))
2838 KERNEL_ERROR_0 (sc
, "destructure: Can't have two optionals");
2846 /*** Manage stepping ***/
2847 if(!is_pair(argobject
))
2851 *outarray
[0] = K_INERT
;
2855 if (is_promise (argobject
))
2857 WITH_BOX_TYPE(tag
,typespec
);
2859 mk_foresliced_basvector (typespec
,
2860 pdata
->cvec
.len
- left
,
2863 destructure_make_ops (argobject
,
2866 return destr_must_call_k
;
2875 pko c
= pair_car(0,argobject
);
2876 argobject
= pair_cdr(0,argobject
);
2887 /* Success keeps exploring */
2890 /* Simple error just ends exploration */
2893 case destr_must_call_k
:
2895 WITH_BOX_TYPE(tag
,typespec
);
2896 /* $$IMPROVE ME If length = 0, this is just
2897 REF_OPER (is_null) */
2899 mk_foresliced_basvector (typespec
,
2900 pdata
->cvec
.len
- left
+ 1,
2902 pko raw_oplist
= *extra_result
;
2905 REF_OPER (destructure_resume
),
2906 /* ^V= (result-so-far argobject spec
2908 mk_load (LIST4 (mk_load_ix (0, 0),
2911 kernel_bool (saw_optional
))),
2912 mk_store (K_ANY
, 1),
2913 /* ^V= result-so-far */
2918 errx (7, "Unrecognized enumeration");
2922 if(argobject
== K_NIL
)
2923 { return destr_success
; }
2924 else if (is_promise (argobject
))
2926 pko new_typespec
= REF_OPER (is_null
);
2928 destructure_make_ops (argobject
,
2931 return destr_must_call_k
;
2934 { return destr_err
; }
2937 else if (!no_call_k(typespec
))
2939 if (!is_combiner (typespec
))
2941 KERNEL_ERROR_0 (sc
, "spec must be a combiner");
2945 /* $$LIKELY BUG This somehow arranges to look at a typespec that
2946 is just a key, length 0 when interacting with nested. */
2948 destructure_make_ops_to_bool (argobject
, typespec
);
2949 return destr_must_call_k
;
2951 else if(typecheck(sc
, argobject
, typespec
))
2953 *outarray
[0] = argobject
;
2955 return destr_success
;
2957 else if (is_promise (argobject
))
2960 destructure_make_ops (argobject
,
2963 return destr_must_call_k
;
2970 /*_ , destructure_to_array */
2972 destructure_to_array
2974 pko obj
, /* Object to extract values from */
2975 pko type
, /* Type spec */
2976 pko
* array
, /* Array to be filled */
2977 size_t length
, /* Maximum length of that array */
2978 pko resume_op
, /* Combiner to schedule if we resume */
2979 pko resume_data
/* Extra data to the resume op */
2982 if (type
== K_NO_TYPE
)
2984 pko
* orig_array
= array
;
2985 pko extra_result
= 0;
2986 kt_destr_outcome outcome
=
2987 destructure (sc
, obj
, type
, &array
, array
+ length
, &extra_result
, 0);
2995 pko err
= where_typemiss (sc
, obj
, type
);
2996 extra_result
= err
? err
: mk_string("Couldn't find the typemiss");
2997 _klink_error_1 (sc
, "type mismatch:",
2998 LIST2(resume_data
, extra_result
));
3003 case destr_must_call_k
:
3005 /* Arrange for a resume. */
3006 int read_len
= array
- orig_array
;
3007 pko result_so_far
= mk_destr_result (read_len
, orig_array
, K_NIL
);
3008 assert (is_combiner (resume_op
));
3009 CONTIN_0_RAW (resume_op
, sc
);
3010 /* ^^^V= (final-destr_result . resume_data) */
3011 CONTIN_0_RAW (mk_load (LISTSTAR2 (mk_load_ix (0, 0),
3014 CONTIN_0_RAW (mk_store (K_ANY
, 1), sc
);
3015 /* ^^^V= final-destr_result */
3016 schedule_rv_list (sc
, extra_result
);
3017 /* ^^^V= current-destr_result */
3018 /* $$ENCAPSULATE ME */
3019 sc
->value
= result_so_far
;
3020 longjmp (sc
->pseudocontinuation
, 1);
3027 errx (7, "Unrecognized enumeration");
3031 /*_ , destructure_resume */
3032 SIG_CHKARRAY (destructure_resume
) =
3034 REF_OPER (is_destr_result
),
3039 DEF_SIMPLE_CFUNC (ps0a4
, destructure_resume
, 0)
3041 WITH_4_ARGS (destr_result
, argobject
, typespec
, opt_p
);
3042 const int max_args
= 5;
3043 pko arg_array
[max_args
];
3044 pko
* outarray
= arg_array
;
3045 pko extra_result
= 0;
3046 kt_destr_outcome outcome
=
3051 arg_array
+ max_args
,
3058 int new_len
= outarray
- arg_array
;
3060 mk_destr_result_add (destr_result
, new_len
, arg_array
);
3064 KERNEL_ERROR_1 (sc
, "type mismatch:", extra_result
);
3067 case destr_must_call_k
:
3069 /* Arrange for another force+resume. This will feed whatever
3070 was there before. */
3071 int read_len
= outarray
- arg_array
;
3073 mk_destr_result_add (destr_result
,
3076 schedule_rv_list (sc
, extra_result
);
3077 return result_so_far
;
3082 errx (7, "Unrecognized enumeration");
3086 /*_ , do-destructure */
3087 /* We don't have a typecheck typecheck predicate yet, so accept
3088 anything for arg2. Really it can be what typecheck accepts or
3089 T_DESTRUCTURE, checked recursively. */
3090 SIG_CHKARRAY (do_destructure
) = { K_ANY
, K_ANY
, };
3091 DEF_SIMPLE_APPLICATIVE (ps0a2
, do_destructure
,T_NO_K
,unsafe
,"do-destructure")
3093 WITH_2_ARGS (argobject
,typespec
);
3094 int len
= destructure_how_many (typespec
);
3095 pko vec
= mk_vector (len
, K_NIL
);
3096 WITH_UNBOXED_UNSAFE (pdata
,kt_destr_list
,vec
);
3097 destructure_to_array
3103 REF_OPER (destr_result_to_vec
),
3109 /*_ , C functions as objects */
3112 typedef struct kt_opstore
3114 pko destr
; /* Often a T_DESTRUCTURE */
3119 DEF_T_PRED (is_cfunc
, T_CFUNC
,no
,"");
3122 /* For external use, if some code ever wants to make these objects
3124 /* $$MAKE ME SAFE Set type-check fields */
3126 mk_cfunc (const kt_cfunc
* f
)
3128 typedef kt_boxed_cfunc TT
;
3129 errx(4, "Don't use mk_cfunc yet")
3130 TT
*pbox
= GC_MALLOC (sizeof (TT
));
3131 pbox
->type
= T_CFUNC
;
3133 return PTR2PKO(pbox
);
3137 INLINE
const kt_cfunc
*
3138 get_cfunc_func (pko p
)
3140 WITH_PSYC_UNBOXED(kt_cfunc
,p
,T_CFUNC
,0)
3143 /*_ . cfunc_resume */
3145 /*_ . mk_cfunc_resume */
3147 mk_cfunc_resume (pko cfunc
)
3149 ALLOC_BOX_PRESUME (kt_cfunc
, T_CFUNC_RESUME
);
3150 pbox
->data
= *get_cfunc_func (cfunc
);
3151 return PTR2PKO(pbox
);
3154 /*_ . Curried functions */
3155 /*_ , About objects */
3158 { return is_type (p
, T_CURRIED
); }
3161 mk_curried (decurrier_f decurrier
, pko args
, pko next
)
3163 ALLOC_BOX(pbox
,T_CURRIED
,kt_boxed_curried
);
3164 pbox
->data
.decurrier
= decurrier
;
3165 pbox
->data
.args
= args
;
3166 pbox
->data
.next
= next
;
3167 pbox
->data
.argcheck
= 0;
3168 return PTR2PKO(pbox
);
3171 /*_ . call_curried */
3173 call_curried(klink
* sc
, pko curried
, pko value
)
3175 WITH_PSYC_UNBOXED(kt_curried
,curried
,T_CURRIED
,sc
);
3177 /* First schedule the next one if there is any */
3180 klink_push_cont(sc
, pdata
->next
);
3183 /* Then call the decurrier with the data field and the value,
3184 returning its result. */
3185 return pdata
->decurrier (sc
, pdata
->args
, value
);
3190 typedef kt_vector kt_chain
;
3194 #define SIG_CHAIN(C_NAME) pko CHAIN_NAME(C_NAME)[]
3195 #define DEF_CHAIN(NAME, ARRAY_NAME) \
3196 DEF_VEC(T_CHAIN | T_IMMUTABLE, NAME, ARRAY_NAME)
3198 #define DEF_SIMPLE_CHAIN(C_NAME) \
3199 RGSTR(all-builtins,"C-" #C_NAME, REF_OPER (C_NAME)) \
3200 DEF_CHAIN(OPER(C_NAME), CHAIN_NAME(C_NAME))
3205 schedule_chain(klink
* sc
, const kt_vector
* chain
)
3207 _kt_spagstack dump
= sc
->dump
;
3209 for(i
= chain
->len
- 1; i
>= 0; i
--)
3211 pko comb
= chain
->els
[i
];
3212 /* If frame_depth is unassigned, assign it. */
3213 if(_get_type(comb
) == T_STORE
)
3215 WITH_UNBOXED_UNSAFE( pdata
, kt_opstore
, comb
);
3216 if(pdata
->frame_depth
< 0)
3217 { pdata
->frame_depth
= chain
->len
- 1 - i
; }
3219 /* Push it as a combiner */
3220 dump
= klink_push_cont_aux(dump
, comb
, sc
->envir
);
3227 eval_chain( klink
* sc
, pko functor
, pko value
)
3229 WITH_PSYC_UNBOXED( kt_vector
, functor
, T_CHAIN
, 0 );
3230 schedule_chain( sc
, pdata
);
3233 /*_ . schedule_rv_list */
3235 schedule_rv_list (klink
* sc
, pko list
)
3238 _kt_spagstack dump
= sc
->dump
;
3239 for(; list
!= K_NIL
; list
= cdr (list
))
3241 pko comb
= car (list
);
3242 /* $$PUNT If frame_depth is unassigned, assign it. */
3244 /* Push it as a combiner */
3245 dump
= klink_push_cont_aux(dump
, comb
, sc
->envir
);
3252 mk_notrace( pko combiner
)
3254 ALLOC_BOX_PRESUME( pko
, T_NOTRACE
);
3256 return PTR2PKO(pbox
);
3261 notrace_comb( pko p
)
3263 WITH_PSYC_UNBOXED( pko
, p
, T_NOTRACE
, 0 );
3269 #define STORE_DEF(DATA) \
3270 { T_STORE | T_IMMUTABLE, { DATA, -1, }, }
3272 #define ANON_STORE(DATA) \
3273 ANON_REF (kt_opstore, STORE_DEF(DATA))
3275 /*_ . dynamically */
3277 mk_store (pko data
, int depth
)
3279 ALLOC_BOX_PRESUME(kt_opstore
, T_STORE
| T_IMMUTABLE
);
3280 pdata
->destr
= data
;
3281 pdata
->frame_depth
= depth
;
3282 return PTR2PKO(pbox
);
3287 typedef pko kt_opload
;
3291 #define LOAD_DEF( DATA ) \
3292 { T_LOAD | T_IMMUTABLE, DATA, }
3294 #define ANON_LOAD( DATA ) \
3295 ANON_REF( pko, LOAD_DEF( DATA ))
3297 #define ANON_LOAD_IX( X, Y ) \
3298 ANON_PAIR(ANON_REF(num, INT_DEF( X )), \
3299 ANON_REF(num, INT_DEF( Y )))
3300 /*_ . dynamically */
3303 mk_load_ix (int x
, int y
)
3305 return cons (mk_integer (x
), mk_integer (y
));
3311 ALLOC_BOX_PRESUME(kt_opload
, T_LOAD
| T_IMMUTABLE
);
3313 return PTR2PKO(pbox
);
3316 /*_ , pairs proper */
3318 DEF_T_PRED (is_pair
, T_PAIR
,ground
, "pair?/o1");
3321 SIG_CHKARRAY(Xcons
) = { K_ANY
, K_ANY
, };
3322 DEF_SIMPLE_DESTR(Xcons
);
3323 DEF_APPLICATIVE_W_DESTR(p00a2
,mk_pair
, REF_DESTR(Xcons
),T_NO_K
,ground
, "cons")
3329 DEF_APPLICATIVE_W_DESTR(p00a2
,mk_mutable_pair
, REF_DESTR(Xcons
),T_NO_K
,ground
, "mcons")
3332 return mcons (a
, b
);
3335 /*_ . Parts and operations */
3337 SIG_CHKARRAY(pair_cxr
) = { REF_OPER(is_pair
), };
3338 DEF_SIMPLE_DESTR(pair_cxr
);
3339 DEF_APPLICATIVE_W_DESTR(ps0a1
,pair_car
, REF_DESTR(pair_cxr
),T_NO_K
,ground
, "car")
3342 return v2car(sc
,T_PAIR
,p
);
3345 DEF_APPLICATIVE_W_DESTR(ps0a1
,pair_cdr
, REF_DESTR(pair_cxr
),T_NO_K
,ground
, "cdr")
3348 return v2cdr(sc
,T_PAIR
,p
);
3351 SIG_CHKARRAY(pair_set_cxr
) = { REF_OPER(is_pair
), K_ANY
, };
3352 DEF_SIMPLE_DESTR(pair_set_cxr
);
3353 DEF_APPLICATIVE_W_DESTR(ps0a2
,set_car
, REF_DESTR(pair_set_cxr
),T_NO_K
,ground
, "set-car!")
3356 v2set_car(sc
,T_PAIR
,p
,q
);
3360 DEF_APPLICATIVE_W_DESTR(ps0a2
,set_cdr
, REF_DESTR(pair_set_cxr
),T_NO_K
,ground
, "set-cdr!")
3363 v2set_cdr(sc
,T_PAIR
,p
,q
);
3366 /*_ , Normal (one arg) */
3367 /*_ , Values as pairs */
3368 DEF_CFUNC_RAW(OPER (valcar
), ps0a1
, pair_car
, REF_OPER (is_pair
), T_NO_K
);
3369 DEF_CFUNC_RAW(OPER (valcdr
), ps0a1
, pair_cdr
, REF_OPER (is_pair
), T_NO_K
);
3373 DEF_T_PRED (is_string
, T_STRING
,ground
,"string?/o1");
3376 INTERFACE INLINE pko
3377 mk_string (const char *str
)
3379 return mk_bastring (T_STRING
, str
, strlen (str
), 0);
3382 INTERFACE INLINE pko
3383 mk_counted_string (const char *str
, int len
)
3385 return mk_bastring (T_STRING
, str
, len
, 0);
3388 INTERFACE INLINE pko
3389 mk_empty_string (int len
, char fill
)
3391 return mk_bastring (T_STRING
, 0, len
, fill
);
3393 /*_ . Create static */
3394 /* $$WRITE ME As for k_print_terminate_list macros */
3397 INTERFACE INLINE
char *
3398 string_value (pko p
)
3400 return bastring_value(0,T_STRING
,p
);
3403 INTERFACE INLINE
int
3406 return bastring_len(0,T_STRING
,p
);
3411 DEF_T_PRED(is_symbol
, T_SYMBOL
,ground
,"symbol?/o1");
3414 mk_symbol_obj (const char *name
)
3416 return mk_bastring (T_SYMBOL
| T_IMMUTABLE
, name
, strlen (name
), 0);
3419 /* We want symbol objects to be unique per name, so check an oblist of
3422 mk_symbol (const char *name
)
3424 /* first check oblist */
3425 pko x
= oblist_find_by_name (name
);
3432 x
= oblist_add_by_name (name
);
3436 /*_ . oblist implementation */
3437 /*_ , Global object */
3438 static pko oblist
= 0;
3439 /*_ , Oblist as hash table */
3440 #ifndef USE_OBJECT_LIST
3442 static int hash_fn (const char *key
, int table_size
);
3445 oblist_initial_value ()
3447 return mk_vector (461, K_NIL
);
3450 /* returns the new symbol */
3452 oblist_add_by_name (const char *name
)
3454 pko x
= mk_symbol_obj (name
);
3455 int location
= hash_fn (name
, vector_len (oblist
));
3456 set_vector_elem (oblist
, location
,
3457 cons (x
, vector_elem (oblist
, location
)));
3462 oblist_find_by_name (const char *name
)
3469 location
= hash_fn (name
, vector_len (oblist
));
3470 for (x
= vector_elem (oblist
, location
); x
!= K_NIL
; x
= cdr (x
))
3472 s
= symname (0,car (x
));
3473 /* case-insensitive, per R5RS section 2. */
3474 if (stricmp (name
, s
) == 0)
3483 oblist_all_symbols (void)
3487 pko ob_list
= K_NIL
;
3489 for (i
= 0; i
< vector_len (oblist
); i
++)
3491 for (x
= vector_elem (oblist
, i
); x
!= K_NIL
; x
= cdr (x
))
3493 ob_list
= mcons (x
, ob_list
);
3499 /*_ , Oblist as list */
3503 oblist_initial_value ()
3509 oblist_find_by_name (const char *name
)
3514 for (x
= oblist
; x
!= K_NIL
; x
= cdr (x
))
3516 s
= symname (0,car (x
));
3517 /* case-insensitive, per R5RS section 2. */
3518 if (stricmp (name
, s
) == 0)
3526 /* returns the new symbol */
3528 oblist_add_by_name (const char *name
)
3530 pko x
= mk_symbol_obj (name
);
3531 oblist
= cons (x
, oblist
);
3536 oblist_all_symbols (void)
3544 /*_ . Parts and operations */
3545 SIG_CHKARRAY(string_to_symbol
) = { REF_OPER(is_string
), };
3546 DEF_SIMPLE_APPLICATIVE(ps0a1
,string_to_symbol
,T_NO_K
,ground
, "string->symbol")
3548 return mk_symbol(string_value(arg1
));
3551 INTERFACE INLINE
char *
3552 symname (sc_or_null sc
, pko p
)
3554 return bastring_value (sc
,T_SYMBOL
, p
);
3561 DEF_T_PRED (is_vector
, T_VECTOR
,unsafe
,"vector?/o1");
3564 /*_ , mk_vector (T_ level) */
3565 INTERFACE
static pko
3566 mk_vector (int len
, pko fill
)
3567 { return mk_filled_basvector(len
, fill
, T_VECTOR
); }
3569 /*_ , k_mk_vector (K level) */
3570 /* $$RETHINK ME This may not be wanted. */
3571 SIG_CHKARRAY(k_mk_vector
) = { REF_OPER(is_integer
), REF_KEY(K_TYCH_OPTIONAL
), K_ANY
, };
3572 DEF_SIMPLE_APPLICATIVE (ps0a2
, k_mk_vector
,T_NO_K
,unsafe
,"make-vector")
3574 WITH_2_ARGS(k_len
, fill
);
3576 int len
= ivalue (k_len
);
3577 if (fill
== K_INERT
)
3579 return mk_vector (len
, fill
);
3583 /* K_ANY instead of REF_OPER(is_finite_list) because
3584 mk_basvector_w_args checks list-ness internally */
3585 DEF_APPLICATIVE_W_DESTR(ps0a1
, vector
, K_ANY
,T_NO_K
,unsafe
,"vector")
3588 return mk_basvector_w_args(sc
,p
,T_VECTOR
);
3591 /*_ . Operations (T_ level) */
3592 /*_ , fill_vector */
3594 INTERFACE
static void
3595 fill_vector (pko vec
, pko obj
)
3597 assert(_get_type(vec
) == T_VECTOR
);
3598 unsafe_basvector_fill(vec
,obj
);
3601 /*_ . Parts of vectors (T_ level) */
3603 INTERFACE
static int
3604 vector_len (pko vec
)
3606 assert(_get_type(vec
) == T_VECTOR
);
3607 return basvector_len(vec
);
3610 INTERFACE
static pko
3611 vector_elem (pko vec
, int ielem
)
3613 assert(_get_type(vec
) == T_VECTOR
);
3614 return basvector_elem(vec
, ielem
);
3617 INTERFACE
static void
3618 set_vector_elem (pko vec
, int ielem
, pko a
)
3620 assert(_get_type(vec
) == T_VECTOR
);
3621 basvector_set_elem(vec
, ielem
, a
);
3626 /* T_PROMISE is essentially a handle, pointing to a pair of either
3627 (expression env) or (value #f). We use #f, not nil, because nil is
3628 a possible environment. */
3632 RGSTR(ground
,"$lazy", REF_OPER(mk_promise_lazy
))
3633 DEF_CFUNC(ps0a1
, mk_promise_lazy
, K_ANY_SINGLETON
, T_NO_K
)
3636 pko guts
= mcons(p
, mcons(sc
->envir
, mk_continuation(sc
->dump
)));
3637 return v2cons (T_PROMISE
, guts
, K_NIL
);
3640 /* $$CHECK ME Is K_ANY correct? Or K_ANY_SINGLETON? */
3641 DEF_APPLICATIVE_W_DESTR(p00a1
,mk_promise_memo
,K_ANY
,T_NO_K
,ground
,"memoize")
3644 pko guts
= mcons(p
, K_F
);
3645 return v2cons (T_PROMISE
, guts
, K_NIL
);
3649 DEF_T_PRED (is_promise
,T_PROMISE
,ground
,"promise?/o1");
3651 /*_ , promise_schedule_eval */
3653 promise_schedule_eval(klink
* sc
, pko p
)
3656 pko guts
= unsafe_v2car(p
);
3657 pko env
= car(cdr(guts
));
3658 pko dynxtnt
= cdr(cdr(guts
));
3659 /* Arrange to eval the expression and pass the result to
3660 handle_promise_result */
3661 CONTIN_1R(dcrry_2ALLVLL
,handle_promise_result
,sc
,p
);
3662 /* $$ENCAP ME This deals with continuation guts, so should be
3663 encapped. As a special continuation-maker? */
3664 _kt_spagstack new_dump
=
3665 special_dynxtnt (cont_dump(dynxtnt
), sc
->dump
, env
);
3666 sc
->dump
= new_dump
;
3667 CONTIN_2(dcrry_2dotALL
, kernel_eval
, sc
, car(guts
), env
);
3670 /*_ , handle_promise_result */
3671 SIG_CHKARRAY(handle_promise_result
) = { REF_OPER(is_promise
), K_ANY
};
3672 DEF_SIMPLE_CFUNC(ps0a2
,handle_promise_result
,0)
3674 /* guts are only made by C code so if they're wrong it's a C
3677 WITH_2_ARGS(p
,value
);
3678 pko guts
= unsafe_v2car(p
);
3680 /* if p already has a result, return it */
3681 if(cdr(guts
) == K_F
)
3682 { return car(guts
); }
3683 /* If value is again a promise, set this promise's guts to that
3684 promise's guts and force it again, which will force both (This is
3685 why we need promises to be 2-layer) */
3686 else if(is_promise(value
))
3688 unsafe_v2set_car (p
, unsafe_v2car(value
));
3689 return promise_schedule_eval(sc
, p
);
3691 /* Otherwise set the value and return it. */
3694 unsafe_v2set_car (guts
, value
);
3695 unsafe_v2set_cdr (guts
, K_F
);
3701 DEF_APPLICATIVE_W_DESTR (ps0a1
, force
, K_ANY_SINGLETON
,T_NO_K
,ground
,"force")
3703 /* guts are only made by this C code here, so if they're wrong it's
3710 pko guts
= unsafe_v2car(p
);
3711 if(cdr(guts
) == K_F
)
3712 { return car(guts
); }
3714 { return promise_schedule_eval(sc
,p
); }
3720 /* $$IMPROVE ME Just directly contain the port structure. Possibly
3721 split port into several T_ types. */
3725 ALLOC_BOX_PRESUME (port
*, T_PORT
);
3727 return PTR2PKO(pbox
);
3731 port_rep_from_filename (const char *fn
, int prop
)
3736 if (prop
== (port_input
| port_output
))
3740 else if (prop
== port_output
)
3753 pt
= port_rep_from_file (f
, prop
);
3754 pt
->rep
.stdio
.closeit
= 1;
3758 { pt
->rep
.stdio
.filename
= store_string (strlen (fn
), fn
, 0); }
3760 pt
->rep
.stdio
.curr_line
= 0;
3766 port_from_filename (const char *fn
, int prop
)
3769 pt
= port_rep_from_filename (fn
, prop
);
3774 return mk_port (pt
);
3778 port_rep_from_file (FILE * f
, int prop
)
3781 pt
= (port
*) GC_MALLOC_ATOMIC (sizeof *pt
);
3786 /* Don't care what goes in these but GC really wants to provide it
3787 so here are dummy objects to put it in. */
3788 GC_finalization_proc ofn
;
3790 GC_register_finalizer(pt
, port_finalize_file
, 0, &ofn
, &ocd
);
3791 pt
->kind
= port_file
| prop
;
3792 pt
->rep
.stdio
.file
= f
;
3793 pt
->rep
.stdio
.closeit
= 0;
3798 port_from_file (FILE * f
, int prop
)
3801 pt
= port_rep_from_file (f
, prop
);
3806 return mk_port (pt
);
3810 port_rep_from_string (char *start
, char *past_the_end
, int prop
)
3813 pt
= (port
*) GC_MALLOC_ATOMIC (sizeof (port
));
3818 pt
->kind
= port_string
| prop
;
3819 pt
->rep
.string
.start
= start
;
3820 pt
->rep
.string
.curr
= start
;
3821 pt
->rep
.string
.past_the_end
= past_the_end
;
3826 port_from_string (char *start
, char *past_the_end
, int prop
)
3829 pt
= port_rep_from_string (start
, past_the_end
, prop
);
3834 return mk_port (pt
);
3837 #define BLOCK_SIZE 256
3840 realloc_port_string (port
* p
)
3842 /* $$IMPROVE ME Just use REALLOC. */
3843 char *start
= p
->rep
.string
.start
;
3844 size_t new_size
= p
->rep
.string
.past_the_end
- start
+ 1 + BLOCK_SIZE
;
3845 char *str
= GC_MALLOC_ATOMIC (new_size
);
3848 memset (str
, ' ', new_size
- 1);
3849 str
[new_size
- 1] = '\0';
3850 strcpy (str
, start
);
3851 p
->rep
.string
.start
= str
;
3852 p
->rep
.string
.past_the_end
= str
+ new_size
- 1;
3853 p
->rep
.string
.curr
-= start
- str
;
3864 port_rep_from_scratch (void)
3868 pt
= (port
*) GC_MALLOC_ATOMIC (sizeof (port
));
3873 start
= GC_MALLOC_ATOMIC (BLOCK_SIZE
);
3878 memset (start
, ' ', BLOCK_SIZE
- 1);
3879 start
[BLOCK_SIZE
- 1] = '\0';
3880 pt
->kind
= port_string
| port_output
| port_srfi6
;
3881 pt
->rep
.string
.start
= start
;
3882 pt
->rep
.string
.curr
= start
;
3883 pt
->rep
.string
.past_the_end
= start
+ BLOCK_SIZE
- 1;
3888 port_from_scratch (void)
3891 pt
= port_rep_from_scratch ();
3896 return mk_port (pt
);
3899 /*_ . open-input-file */
3900 SIG_CHKARRAY(k_open_input_file
) =
3901 { REF_OPER(is_string
), };
3902 DEF_SIMPLE_APPLICATIVE(ps0a1
,k_open_input_file
,0,ground
, "open-input-file")
3904 WITH_1_ARGS(filename
);
3905 return port_from_filename (string_value(filename
), port_file
| port_input
);
3911 DEF_T_PRED (is_port
, T_PORT
,ground
,"port?/o1");
3913 DEF_SIMPLE_PRED (is_inport
,T_NO_K
,ground
,"input-port?/o1")
3916 return is_port (p
) && portvalue (p
)->kind
& port_input
;
3919 DEF_SIMPLE_PRED (is_outport
,T_NO_K
,ground
,"output-port?/o1")
3922 return is_port (p
) && portvalue (p
)->kind
& port_output
;
3929 WITH_PSYC_UNBOXED(port
*,p
,T_PORT
,0);
3934 set_portvalue (pko p
, port
* newport
)
3936 assert_mutable(0,p
);
3937 WITH_PSYC_UNBOXED(port
*,p
,T_PORT
,0);
3942 /*_ . reading from ports */
3948 if (pt
->kind
& port_saw_EOF
)
3950 c
= basic_inchar (pt
);
3952 { pt
->kind
|= port_saw_EOF
; }
3956 if (pt
->kind
& port_file
)
3957 { pt
->rep
.stdio
.curr_line
++; }
3965 basic_inchar (port
* pt
)
3967 if (pt
->kind
& port_file
)
3969 return fgetc (pt
->rep
.stdio
.file
);
3973 if (*pt
->rep
.string
.curr
== 0 ||
3974 pt
->rep
.string
.curr
== pt
->rep
.string
.past_the_end
)
3980 return *pt
->rep
.string
.curr
++;
3985 /* back character to input buffer */
3987 backchar (port
* pt
, int c
)
3992 if (pt
->kind
& port_file
)
3994 ungetc (c
, pt
->rep
.stdio
.file
);
3998 pt
->rep
.stdio
.curr_line
--;
4004 if (pt
->rep
.string
.curr
!= pt
->rep
.string
.start
)
4006 --pt
->rep
.string
.curr
;
4013 /*_ . (get-char textual-input-port) */
4014 SIG_CHKARRAY(get_char
) = { REF_OPER(is_inport
), };
4015 DEF_SIMPLE_APPLICATIVE(p00a1
,get_char
,T_NO_K
,ground
, "get-char")
4018 assert(is_inport(port
));
4019 int c
= inchar(portvalue(port
));
4023 { return mk_character(c
); }
4026 /*_ . Finalization */
4028 port_finalize_file(GC_PTR obj
, GC_PTR client_data
)
4031 if ((pt
->kind
& port_file
) && pt
->rep
.stdio
.closeit
)
4032 { port_close_port (pt
, port_input
| port_output
); }
4036 port_close (pko p
, int flag
)
4039 port_close_port(portvalue (p
), flag
);
4043 port_close_port (port
* pt
, int flag
)
4046 if ((pt
->kind
& (port_input
| port_output
)) == 0)
4048 if (pt
->kind
& port_file
)
4051 /* Cleanup is here so (close-*-port) functions could work too */
4052 pt
->rep
.stdio
.curr_line
= 0;
4056 fclose (pt
->rep
.stdio
.file
);
4058 pt
->kind
= port_free
;
4063 /*_ , Encapsulation type */
4065 SIG_CHKARRAY(is_encap
) = { REF_OPER(is_key
), K_ANY
};
4066 DEF_SIMPLE_CFUNC(b00a2
, is_encap
,T_NO_K
)
4068 WITH_2_ARGS(type
, p
);
4069 if (is_type (p
, T_ENCAP
))
4071 WITH_UNBOXED_UNSAFE(pdata
,kt_encap
,p
);
4072 return (pdata
->type
== type
);
4080 /* NOT directly part of the interface. */
4081 SIG_CHKARRAY(unencap
) = { REF_OPER(is_key
), K_ANY
};
4082 DEF_SIMPLE_CFUNC(ps0a2
, unencap
,T_NO_K
)
4084 WITH_2_ARGS(type
, p
);
4085 if (is_encap (type
, p
))
4087 WITH_UNBOXED_UNSAFE(pdata
,kt_encap
,p
);
4088 return pdata
->value
;
4092 /* We have no type-name to give to the error message. */
4093 KERNEL_ERROR_0 (sc
, "unencap: wrong type");
4097 /* NOT directly part of the interface. */
4098 SIG_CHKARRAY(mk_encap
) = { REF_OPER(is_key
), K_ANY
};
4099 DEF_SIMPLE_CFUNC(p00a2
, mk_encap
,T_NO_K
)
4101 WITH_2_ARGS(type
, value
);
4102 ALLOC_BOX_PRESUME (kt_encap
, T_ENCAP
);
4103 pbox
->data
.type
= type
;
4104 pbox
->data
.value
= value
;
4105 return PTR2PKO(pbox
);
4108 DEF_APPLICATIVE_W_DESTR (p00a0
, mk_encapsulation_type
, K_NO_TYPE
,T_NO_K
,ground
, "make-encapsulation-type/raw")
4110 /* A unique cell representing a type */
4111 pko type
= mk_void();
4112 /* $$IMPROVE ME make typespecs for the curried objs. trivpred is
4113 effectively that spec object. */
4114 pko e
= wrap (mk_curried (dcrry_2ALLV01
, type
, REF_OPER (mk_encap
)));
4115 pko trivpred
= mk_curried (dcrry_2ALLV01
, type
, REF_OPER (is_encap
));
4116 pko d
= wrap (mk_curried (dcrry_2ALLV01
, type
, REF_OPER (unencap
)));
4117 return LIST3 (e
, trivpred
, d
);
4119 /*_ , Listloop types */
4120 /*_ . Forward declarations */
4122 /*_ . Enumerations */
4124 /* How to turn the current list into current value and next list. */
4131 } kt_loopstyle_step
;
4139 } kt_loopstyle_argix
;
4141 /*_ . Function signatures. */
4142 typedef pko (* kt_listloop_mk_val
)(pko value
, struct kt_listloop
* pll
);
4144 typedef struct kt_listloop_style
4146 pko combiner
; /* Default combiner or NULL. */
4147 int collect_p
; /* Whether to collect a (reversed)
4148 list of the returns. */
4149 kt_loopstyle_step step
;
4150 kt_listloop_mk_val mk_val
; /* From returned value+state -> passed value. */
4151 pko destructurer
; /* A destructurer contents */
4152 /* Selection of args. Each entry correspond to one arg in "full
4153 args", and indexes something in the array of actual args that the
4154 destructurer retrieves. */
4155 int arg_select
[lls_num_args
];
4156 } kt_listloop_style
;
4157 typedef struct kt_listloop
4159 pko combiner
; /* The combiner to use repeatedly. */
4160 pko list
; /* The list to loop over */
4161 int top_length
; /* Length of top element, for lls_many. */
4162 int countdown
; /* Num elements left, or negative if unused. */
4163 int countup
; /* Upwards count from 0. */
4164 pko stop_on
; /* Stop if return value is this. Can
4166 kt_listloop_style
* style
; /* Non-NULL pointer to style. */
4168 /*_ , Internal signatures */
4170 listloop_aux (klink
* sc
,
4171 kt_listloop_style
* style_v
,
4173 pko style_args
[lls_num_args
]);
4174 FORWARD_DECL_CFUNC (static, ps0a3
, listloop_resume
);
4177 /*_ , Listloop styles */
4183 kt_loopstyle_step step
,
4184 kt_listloop_mk_val mk_val
)
4186 ALLOC_BOX_PRESUME(kt_listloop_style
,T_LISTLOOP_STYLE
);
4187 pdata
->combiner
= combiner
;
4188 pdata
->collect_p
= collect_p
;
4190 pdata
->mk_val
= mk_val
;
4191 return PTR2PKO(pbox
);
4201 kt_listloop_style
* style
)
4203 ALLOC_BOX_PRESUME(kt_listloop
,T_LISTLOOP
);
4204 pdata
->combiner
= combiner
;
4206 pdata
->top_length
= top_length
;
4207 pdata
->countdown
= count
;
4208 pdata
->countup
= -1;
4209 pdata
->stop_on
= stop_on
;
4210 pdata
->style
= style
;
4211 return PTR2PKO(pbox
);
4215 copy_listloop(const kt_listloop
* orig
)
4217 ALLOC_BOX_PRESUME(kt_listloop
,T_LISTLOOP
);
4218 memcpy (pdata
, orig
, sizeof(kt_listloop
));
4219 return PTR2PKO(pbox
);
4223 DEF_T_PRED(is_listloop
, T_LISTLOOP
, no
, "");
4224 DEF_T_PRED(is_listloop_style
, T_LISTLOOP_STYLE
, no
, "");
4226 /*_ . Pre-existing style objects */
4227 /*_ , listloop-style-sequence */
4228 RGSTR(simple
,"listloop-style-sequence",REF_OBJ(sequence_style
))
4229 static BOX_OF(kt_listloop_style
) sequence_style
=
4233 REF_OPER(kernel_eval
),
4237 K_NO_TYPE
, /* No args contemplated */
4238 { [0 ... lls_num_args
- 1] = -1, }
4241 /*_ , listloop-style-neighbors */
4242 RGSTR(simple
,"listloop-style-neighbors",REF_OBJ(neighbor_style
))
4243 SIG_CHKARRAY(neighbor_style
) =
4245 REF_OPER(is_integer
),
4247 DEF_SIMPLE_DESTR(neighbor_style
);
4248 static BOX_OF(kt_listloop_style
) neighbor_style
=
4256 REF_DESTR(neighbor_style
),
4257 /* See http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html. */
4258 { [0 ... lls_num_args
- 1] = -1, [lls_count
] = 0, },
4263 /* Create a listloop object. */
4264 /* $$IMPROVE ME This may become what style operative T_ type calls.
4265 Rename it eval_listloop_style. */
4266 SIG_CHKARRAY(listloop
) =
4268 REF_OPER(is_listloop_style
),
4269 REF_OPER(is_countable_list
),
4270 REF_KEY(K_TYCH_DOT
),
4274 DEF_SIMPLE_APPLICATIVE(ps0a3
, listloop
,0,ground
, "listloop")
4276 WITH_3_ARGS(style
, list
, args
);
4278 WITH_UNBOXED_UNSAFE(style_v
,kt_listloop_style
, style
);
4279 pko style_args
[lls_num_args
];
4280 /* Destructure the args by style */
4281 destructure_to_array(sc
,
4283 style_v
->destructurer
,
4286 REF_OPER (listloop_resume
),
4287 LIST2 (style
, list
));
4288 return listloop_aux (sc
, style_v
, list
, style_args
);
4290 /*_ , listloop_resume */
4291 SIG_CHKARRAY (listloop_resume
) =
4293 REF_OPER (is_destr_result
),
4294 REF_OPER(is_listloop_style
),
4295 REF_OPER(is_countable_list
),
4297 DEF_SIMPLE_CFUNC(ps0a3
, listloop_resume
, 0)
4299 WITH_3_ARGS (destr_result
, style
, list
);
4300 pko style_args
[lls_num_args
];
4301 destr_result_fill_array (destr_result
, lls_num_args
, style_args
);
4302 WITH_UNBOXED_UNSAFE(style_v
,kt_listloop_style
, style
);
4303 return listloop_aux (sc
, style_v
, list
, style_args
);
4305 /*_ , listloop_aux */
4308 (klink
* sc
, kt_listloop_style
* style_v
, pko list
, pko style_args
[lls_num_args
])
4310 /*** Get the actual arg objects ***/
4311 #define GET_OBJ(_INDEX) \
4312 ((style_v->arg_select[_INDEX] < 0) ? K_INERT : style_args[style_v->arg_select[_INDEX]])
4314 pko count
= GET_OBJ(lls_count
);
4315 pko combiner
= GET_OBJ(lls_combiner
);
4316 pko top_length
= GET_OBJ(lls_top_count
);
4319 /*** Extract values from the objects, using defaults as needed ***/
4320 int countv
= (count
== K_INERT
) ? -1L : ivalue(count
);
4321 int top_lengthv
= (top_length
== K_INERT
) ? 1 : ivalue(top_length
);
4322 if(combiner
== K_INERT
)
4324 combiner
= style_v
->combiner
;
4327 /*** Make the loop object itself ***/
4328 pko ll
= mk_listloop( combiner
, list
, top_lengthv
, countv
, 0, style_v
);
4331 /*_ , Evaluating one iteration */
4333 eval_listloop(klink
* sc
, pko functor
, pko value
)
4336 WITH_PSYC_UNBOXED(kt_listloop
, functor
, T_LISTLOOP
, sc
);
4338 /*** Test whether done, maybe return current value. ***/
4339 /* If we're not checking, value will be NULL so this won't
4340 trigger. pdata->countup is 0 for the first element. */
4341 if((pdata
->countup
>= 0) && (value
== pdata
->stop_on
))
4343 /* $$IMPROVE ME This will ct an "abnormal return" value from
4344 this and the other data. */
4347 /* If we're not counting down, value will be negative so this won't
4349 if(pdata
->countdown
== 0)
4353 /* And if we run out of elements, we have to stop regardless. */
4354 if(pdata
->list
== K_NIL
)
4356 /* $$IMPROVE ME Error if we're counting down (ie, if count
4361 /*** Step list, getting new value ***/
4362 pko new_list
, new_value
;
4364 switch(pdata
->style
->step
)
4367 new_list
= cdr( pdata
->list
);
4368 /* We assume the common case of val as list. */
4369 new_value
= LIST1(car( pdata
->list
));
4373 /* $$IMPROVE ME Also test that next item (new_list) is non-empty */
4374 new_list
= cdr( pdata
->list
);
4375 new_value
= LIST2(car( pdata
->list
), car(new_list
));
4378 new_list
= k_counted_map_cdr(sc
, pdata
->top_length
, pdata
->list
, T_PAIR
);
4379 new_value
= k_counted_map_car(sc
, pdata
->top_length
, pdata
->list
, T_PAIR
);
4382 KERNEL_ERROR_0(sc
,"I know nut-ting about that case");
4385 /* Convert it if applicable. */
4386 if(pdata
->style
->mk_val
)
4388 new_value
= pdata
->style
->mk_val(new_value
, pdata
);
4391 /*** Arrange a new iteration. ***/
4392 /* We don't have to re-setup the final chain, if any, because it's
4393 still there from the earlier call. Just the combiner (if any)
4394 and a fresh listloop operative. */
4395 pko new_listloop
= copy_listloop(pdata
);
4397 WITH_UNBOXED_UNSAFE(new_pdata
,kt_listloop
,new_listloop
);
4398 new_pdata
->list
= new_list
;
4399 if(new_pdata
->countdown
> 0)
4400 { new_pdata
->countdown
--; }
4401 new_pdata
->countup
++;
4404 if(pdata
->style
->collect_p
)
4406 CONTIN_0_RAW (mk_curried(dcrry_NVLLdotALL
, value
, new_listloop
), sc
);
4410 CONTIN_0_RAW(new_listloop
, sc
);
4413 CONTIN_0_RAW(pdata
->combiner
, sc
);
4417 /*_ . Handling lists */
4419 DEF_APPLICATIVE_W_DESTR (ps0a1
, list_star
, REF_OPER(is_finite_list
),T_NO_K
,ground
, "list*")
4421 return v2list_star(sc
, arg1
, T_PAIR
);
4424 SIG_CHKARRAY(reverse
) = { REF_OPER(is_finite_list
), };
4425 DEF_SIMPLE_APPLICATIVE (ps0a1
, reverse
,T_NO_K
,ground
, "reverse")
4428 return v2reverse(a
,T_PAIR
);
4430 /*_ . reverse list -- in-place */
4431 /* Don't just use unsafe_v2reverse_in_place, it checks nothing. This
4432 may be reserved for optimization only. */
4434 /*_ . append list -- produce new list */
4435 /* $$IMPROVE ME This defines append/2 but we'll want append/N. Do
4437 SIG_CHKARRAY(append
) = { REF_OPER(is_finite_list
), K_ANY
, };
4438 DEF_SIMPLE_APPLICATIVE (ps0a2
, append
,T_NO_K
,simple
, "append")
4441 return v2append(sc
,a
,b
,T_PAIR
);
4443 /*_ , is_finite_list */
4444 DEF_SIMPLE_PRED (is_finite_list
,T_NO_K
,ground
, "finite-list?/o1")
4448 get_list_metrics_aux(p
, metrics
);
4449 return (metrics
[lm_num_nils
] == 1);
4451 /*_ , is_countable_list */
4452 DEF_SIMPLE_PRED (is_countable_list
,T_NO_K
,ground
, "countable-list?/o1")
4456 get_list_metrics_aux(p
, metrics
);
4457 return (metrics
[lm_num_nils
] || metrics
[lm_cyc_len
]);
4459 /*_ , list_length */
4464 dotted list: -2 minus length before dot
4466 The extra meanings will change since callers can use
4467 get_list_metrics_aux now. Return lm_acyc_len even for dotted
4468 lists, return positive infinity for circular lists.
4475 get_list_metrics_aux(p
, metrics
);
4477 if(metrics
[lm_num_nils
] == 1)
4478 { return metrics
[lm_acyc_len
]; }
4479 /* A circular list */
4480 /* $$IMPROVE ME Return +oo. First make a type and object for +oo */
4481 if(metrics
[lm_cyc_len
] != 0)
4483 /* $$IMPROVE ME Return lm_acyc_len again, merge with the other
4485 /* Otherwise it's dotted */
4486 return 2 - metrics
[lm_acyc_len
];
4488 /*_ , list_length_k */
4489 DEF_APPLICATIVE_W_DESTR(p00a1
, list_length_k
, K_ANY_SINGLETON
,T_NO_K
,ground
, "length")
4492 return mk_integer(list_length(p
));
4495 /*_ , get_list_metrics */
4496 DEF_APPLICATIVE_W_DESTR(p00a1
, get_list_metrics
, K_ANY_SINGLETON
,T_NO_K
,ground
, "get-list-metrics")
4500 get_list_metrics_aux(p
, metrics
);
4501 return LIST4(mk_integer(metrics
[0]),
4502 mk_integer(metrics
[1]),
4503 mk_integer(metrics
[2]),
4504 mk_integer(metrics
[3]));
4506 /*_ , get_list_metrics_aux */
4507 /* RESULTS must be an int4 (an array of 4 integers). get_list_metrics_aux
4508 will fill it with (See enum lm_index):
4510 * the number of pairs in a
4511 * the number of nil objects in a
4512 * the acyclic prefix length of a
4513 * the cycle length of a
4516 /* $$IMPROVE ME Take a flag so we can skip work such as finding
4517 prefix-length when we don't need to do it. This will cause some
4518 result positions to be interpreted differently: when it's cycling,
4519 lm_acyc_len and lm_num_pairs may both overshoot (but never
4524 get_list_metrics_aux (pko a
, int4 presults
)
4526 int * results
= presults
; /* Make it easier to index. */
4533 /* Use Brent's Algorithm, but we have to check for nil and non-pair
4534 too, so I rearranged the loop. We also count steps, because in
4535 some cases we use number of steps directly. */
4541 results
[lm_num_pairs
] = steps
;
4542 results
[lm_num_nils
] = 1;
4543 results
[lm_acyc_len
] = steps
;
4544 results
[lm_cyc_len
] = 0;
4547 if (!is_pair (fast
))
4549 results
[lm_num_pairs
] = steps
;
4550 results
[lm_num_nils
] = 0;
4551 results
[lm_acyc_len
] = steps
;
4552 results
[lm_cyc_len
] = 0;
4558 /* The fast cursor has caught up with the slow cursor so the
4559 structure is circular and loop_len is the cycle length.
4560 We still need to find prefix length.
4564 /* Restart the turtle from the beginning */
4566 /* Restart the hare from position LOOP_LEN */
4567 for(i
= 0, fast
= a
; i
< loop_len
; i
++)
4568 { fast
= cdr (fast
); }
4569 /* Since hare has exactly a loop_len head start, when it
4570 goes around the loop exactly once it will be in the same
4571 position as turtle, so turtle will have only walked the
4580 results
[lm_num_pairs
] = prefix_len
+ loop_len
;
4581 results
[lm_num_nils
] = 0;
4582 results
[lm_acyc_len
] = prefix_len
;
4583 results
[lm_cyc_len
] = loop_len
;
4586 if(power
== loop_len
)
4588 /* Re-plant the slow cursor */
4597 /*_ . Handling trees */
4598 /*_ , copy_es_immutable */
4599 DEF_APPLICATIVE_W_DESTR (ps0a1
, copy_es_immutable
, K_ANY_SINGLETON
,T_NO_K
,ground
, "copy-es-immutable")
4601 WITH_1_ARGS(object
);
4603 if (is_pair (object
))
4605 /* If it's already immutable, can we assume it's immutable
4606 * all the way down and just return it? */
4608 (copy_es_immutable (sc
, car (object
)),
4609 copy_es_immutable (sc
, cdr (object
)));
4616 /*_ , Get tree cycles */
4618 /*_ , kt_recurrence_table */
4619 /* Really just a specialized resizeable lookup table from object to
4620 count. Internals may change. */
4621 /* $$IMPROVE ME Look up more efficiently. Current GC is not
4622 compacting, so we can hash or sort addresses meaningfully. */
4630 kt_recurrence_table
;
4631 /*_ , recur_entry */
4634 /* $$IMPROVE ME These two fields may become one enumerated field */
4639 /*_ , kt_recur_tracker */
4643 recur_entry
* entries
;
4647 /*_ . is_recurrence_table */
4648 DEF_T_PRED(is_recurrence_table
,T_RECURRENCES
,ground
, "recurrence-table?/o1");
4650 /*_ . is_recur_tracker */
4651 DEF_SIMPLE_PRED(is_recur_tracker
,T_NO_K
,ground
, "recur-tracker?/o1")
4654 return (p
== K_NIL
) || is_type (p
, T_RECUR_TRACKER
);
4656 /*_ . recurrences_to_recur_tracker */
4657 SIG_CHKARRAY(recurrences_to_recur_tracker
) =
4658 { REF_OPER(is_recurrence_table
), };
4659 DEF_SIMPLE_APPLICATIVE(p00a1
,recurrences_to_recur_tracker
,T_NO_K
,ground
, "recurrences->tracker")
4661 WITH_1_ARGS(recurrences
);
4662 assert_type(0,recurrences
,T_RECURRENCES
);
4664 WITH_UNBOXED_UNSAFE(ptable
, kt_recurrence_table
,recurrences
);
4665 /* $$IMPROVE ME Scan for counts > 1, and if there are none,
4667 if(ptable
->table_size
== 0)
4670 ALLOC_BOX_PRESUME(kt_recur_tracker
,T_RECUR_TRACKER
);
4671 /* $$MAKE ME SAFE This assumes that sharing is OK, recurrences
4672 won't mutate the LUT. When we have COW or similar, make it
4673 safe. At least check for immutability. */
4674 pdata
->objs
= ptable
->objs
;
4675 pdata
->table_size
= ptable
->table_size
;
4676 pdata
->current_index
= 0;
4678 GC_MALLOC_ATOMIC(sizeof(recur_entry
) * ptable
->table_size
);
4680 for(i
= 0; i
< ptable
->table_size
; i
++)
4682 recur_entry
* p_entry
= &pdata
->entries
[i
];
4683 p_entry
->count
= ptable
->counts
[i
];
4684 p_entry
->index_in_walk
= 0;
4685 p_entry
->seen_in_walk
= 0;
4687 return PTR2PKO(pbox
);
4690 /*_ . recurrences_list_objects */
4691 /* $$WRITE ME Get a list of all objects and their recurrence counts */
4692 /*_ . objtable_get_index */
4695 (pko
* objs
, int table_size
, pko obj
)
4698 for(i
= 0; i
< table_size
; i
++)
4705 /*_ . recurrences_get_seen_count */
4706 /* Return the number of times OBJ has been seen before. If "add" is
4707 non-zero, increment the count too (but return its previous
4710 recurrences_get_seen_count
4711 (kt_recurrence_table
* p_cycles_data
, pko obj
, int add
)
4713 int index
= objtable_get_index(p_cycles_data
->objs
,
4714 p_cycles_data
->table_size
,
4718 int count
= p_cycles_data
->counts
[index
];
4719 /* Maybe record another sighting of this object. */
4721 { p_cycles_data
->counts
[index
]++; }
4722 /* We've found our return value. */
4726 /* We only get here if search didn't find anything. */
4727 /* Make sure we have enough space for this object. */
4730 if(p_cycles_data
->table_size
== p_cycles_data
->alloced_size
)
4732 p_cycles_data
->alloced_size
*= 2;
4733 p_cycles_data
->counts
= GC_REALLOC(p_cycles_data
->counts
, sizeof(int) * p_cycles_data
->alloced_size
);
4734 p_cycles_data
->objs
= GC_REALLOC(p_cycles_data
->objs
, sizeof(pko
) * p_cycles_data
->alloced_size
);
4736 int index
= p_cycles_data
->table_size
;
4737 /* Record what it was */
4738 p_cycles_data
->objs
[index
] = obj
;
4739 /* We have now seen it once. */
4740 p_cycles_data
->counts
[index
] = 1;
4741 p_cycles_data
->table_size
++;
4745 /*_ . recurrences_get_object_count */
4746 /* Given an object, list its count */
4747 SIG_CHKARRAY(recurrences_get_object_count
) =
4748 { REF_OPER(is_recurrence_table
), K_ANY
, };
4749 DEF_SIMPLE_APPLICATIVE(p00a2
, recurrences_get_object_count
,T_NO_K
,ground
, "recurrences-get-object-count")
4751 WITH_2_ARGS(table
, obj
);
4752 WITH_PSYC_UNBOXED(kt_recurrence_table
,table
, T_RECURRENCES
, 0);
4753 int seen_count
= recurrences_get_seen_count(pdata
, obj
, 0);
4754 return mk_integer(seen_count
);
4756 /*_ . init_recurrence_table */
4758 init_recurrence_table(kt_recurrence_table
* p_cycles_data
, int initial_size
)
4760 p_cycles_data
->objs
= initial_size
?
4761 GC_MALLOC(sizeof(pko
) * initial_size
) : 0;
4762 p_cycles_data
->counts
= initial_size
?
4763 GC_MALLOC(sizeof(int) * initial_size
) : 0;
4764 p_cycles_data
->alloced_size
= initial_size
;
4765 p_cycles_data
->table_size
= 0;
4767 /*_ . trace_tree_cycles */
4770 (pko tree
, kt_recurrence_table
* p_cycles_data
)
4772 /* Special case for the "empty container", not because it's just a
4773 key but because "exploring" it does nothing. */
4776 /* Maybe skip this object entirely */
4777 /* $$IMPROVE ME Parameterize this */
4778 switch(_get_type(tree
))
4786 if(recurrences_get_seen_count(p_cycles_data
,tree
, 1) != 0)
4789 /* Switch on tree type */
4790 switch(_get_type(tree
))
4794 #define _EXPLORE_FUNC(X) trace_tree_cycles(X, p_cycles_data)
4796 #undef _EXPLORE_FUNC
4801 /* Done this exploration */
4806 /*_ . get_recurrences */
4807 SIG_CHKARRAY(get_recurrences
) = { K_ANY
, };
4808 DEF_SIMPLE_APPLICATIVE (ps0a1
, get_recurrences
,T_NO_K
,ground
, "get-recurrences")
4811 /* No reason to even start exploring non-containers */
4812 /* $$IMPROVE ME Allow containers other than pairs */
4813 int explore_p
= (_get_type(tree
) == T_PAIR
);
4814 ALLOC_BOX_PRESUME(kt_recurrence_table
, T_RECURRENCES
);
4815 init_recurrence_table(pdata
, explore_p
? 8 : 0);
4817 { trace_tree_cycles(tree
,pdata
); }
4818 return PTR2PKO(pbox
);
4823 /*_ , Making result objects */
4825 /* make symbol or number atom from string */
4827 mk_atom (klink
* sc
, char *q
)
4830 int has_dec_point
= 0;
4834 if ((p
= strstr (q
, "::")) != 0)
4837 return mcons (sc
->COLON_HOOK
,
4838 mcons (mcons (sc
->QUOTE
,
4839 mcons (mk_atom (sc
, p
+ 2), K_NIL
)),
4840 mcons (mk_symbol (strlwr (q
)), K_NIL
)));
4846 if ((c
== '+') || (c
== '-'))
4856 return (mk_symbol (strlwr (q
)));
4865 return (mk_symbol (strlwr (q
)));
4868 else if (!isdigit (c
))
4870 return (mk_symbol (strlwr (q
)));
4873 for (; (c
= *p
) != 0; ++p
)
4885 else if ((c
== 'e') || (c
== 'E'))
4889 has_dec_point
= 1; /* decimal point illegal
4892 if ((*p
== '-') || (*p
== '+') || isdigit (*p
))
4898 return (mk_symbol (strlwr (q
)));
4903 return mk_real (atof (q
));
4905 return (mk_integer (atol (q
)));
4910 mk_sharp_const (char *name
)
4913 char tmp
[STRBUFFSIZE
];
4915 if (!strcmp (name
, "t"))
4917 else if (!strcmp (name
, "f"))
4919 else if (!strcmp (name
, "ignore"))
4921 else if (!strcmp (name
, "inert"))
4923 else if (*name
== 'o')
4925 snprintf (tmp
, STRBUFFSIZE
, "0%s", name
+ 1);
4926 sscanf (tmp
, "%lo", &x
);
4927 return (mk_integer (x
));
4929 else if (*name
== 'd')
4930 { /* #d (decimal) */
4931 sscanf (name
+ 1, "%ld", &x
);
4932 return (mk_integer (x
));
4934 else if (*name
== 'x')
4936 snprintf (tmp
, STRBUFFSIZE
, "0x%s", name
+ 1);
4937 sscanf (tmp
, "%lx", &x
);
4938 return (mk_integer (x
));
4940 else if (*name
== 'b')
4942 x
= binary_decode (name
+ 1);
4943 return (mk_integer (x
));
4945 else if (*name
== '\\')
4946 { /* #\w (character) */
4948 if (stricmp (name
+ 1, "space") == 0)
4952 else if (stricmp (name
+ 1, "newline") == 0)
4956 else if (stricmp (name
+ 1, "return") == 0)
4960 else if (stricmp (name
+ 1, "tab") == 0)
4964 else if (name
[1] == 'x' && name
[2] != 0)
4967 if (sscanf (name
+ 2, "%x", &c1
) == 1 && c1
< UCHAR_MAX
)
4977 else if (is_ascii_name (name
+ 1, &c
))
4982 else if (name
[2] == 0)
4990 return mk_character (c
);
4996 /*_ , Reading strings */
4997 /* read characters up to delimiter, but cater to character constants */
4999 readstr_upto (klink
* sc
, char *delim
)
5001 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
5003 char *p
= sc
->strbuff
;
5005 while ((p
- sc
->strbuff
< sizeof (sc
->strbuff
)) &&
5006 !is_one_of (delim
, (*p
++ = inchar (pt
))));
5008 if (p
== sc
->strbuff
+ 2 && p
[-2] == '\\')
5014 backchar (pt
, p
[-1]);
5020 /* skip white characters */
5022 skipspace (klink
* sc
)
5024 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
5028 { c
= inchar (pt
); }
5029 while (isspace (c
));
5040 /* check c is in chars */
5042 is_one_of (char *s
, int c
)
5052 /*_ , Reading expressions */
5053 /* read string expression "xxx...xxx" */
5055 readstrexp (klink
* sc
)
5057 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
5058 char *p
= sc
->strbuff
;
5062 { st_ok
, st_bsl
, st_x1
, st_x2
, st_oct1
, st_oct2
} state
= st_ok
;
5067 if (c
== EOF
|| p
- sc
->strbuff
> sizeof (sc
->strbuff
) - 1)
5081 return mk_counted_string (sc
->strbuff
, p
- sc
->strbuff
);
5131 if (c
>= '0' && c
<= 'F')
5135 c1
= (c1
<< 4) + c
- '0';
5139 c1
= (c1
<< 4) + c
- 'A' + 10;
5158 if (c
< '0' || c
> '7')
5166 if (state
== st_oct2
&& c1
>= 32)
5169 c1
= (c1
<< 3) + (c
- '0');
5171 if (state
== st_oct1
)
5190 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
5197 switch (c
= inchar (pt
))
5202 return (TOK_LPAREN
);
5204 return (TOK_RPAREN
);
5207 if (is_one_of (" \n\t", c
))
5220 while ((c
= inchar (pt
)) != '\n' && c
!= EOF
)
5229 return (token (sc
));
5232 return (TOK_DQUOTE
);
5234 return (TOK_BQUOTE
);
5236 if ((c
= inchar (pt
)) == '@')
5238 return (TOK_ATMARK
);
5253 while ((c
= inchar (pt
)) != '\n' && c
!= EOF
)
5262 return (token (sc
));
5268 /* $$UNHACKIFY ME! This is a horrible hack. */
5269 if (is_one_of (" itfodxb\\", c
))
5271 return TOK_SHARP_CONST
;
5283 /*_ , Nesting check */
5284 /*_ . create_nesting_check */
5285 void create_nesting_check(klink
* sc
)
5286 { klink_push_dyn_binding(sc
,K_NEST_DEPTH
,mk_integer(0)); }
5287 /*_ . nest_depth_ok_p */
5288 int nest_depth_ok_p(klink
* sc
)
5291 klink_find_dyn_binding(sc
,K_NEST_DEPTH
);
5294 return ivalue(nesting
) == 0;
5296 /*_ . change_nesting_depth */
5297 void change_nesting_depth(klink
* sc
, signed int change
)
5300 klink_find_dyn_binding(sc
,K_NEST_DEPTH
);
5301 add_to_ivalue(nesting
,change
);
5303 /*_ , C-style entry points */
5305 /*_ . kernel_read_internal */
5306 /* The only reason that this is separate from kernel_read_sexp is that
5307 it gets a token, which kernel_read_sexp does almost always, except
5308 once when a caller tricks it with TOK_LPAREN, and once when
5309 kernel_read_list effectively puts back a token it didn't decode. */
5311 DEF_APPLICATIVE_W_DESTR (ps0a0
, kernel_read_internal
, K_NO_TYPE
,0,ground
, "read")
5313 token_t tok
= token (sc
);
5319 create_nesting_check(sc
);
5320 return kernel_read_sexp (sc
);
5323 /*_ . kernel_read_sexp */
5324 DEF_CFUNC (ps0a0
, kernel_read_sexp
, K_NO_TYPE
,0)
5332 CONTIN_0 (vector
, sc
);
5336 sc
->tok
= token (sc
);
5337 if (sc
->tok
== TOK_RPAREN
)
5341 else if (sc
->tok
== TOK_DOT
)
5343 KERNEL_ERROR_0 (sc
, "syntax error: illegal dot expression");
5347 change_nesting_depth(sc
, 1);
5348 CONTIN_1 (dcrry_2A01VLL
, kernel_read_list
, sc
, K_NIL
);
5349 CONTIN_0 (kernel_read_sexp
, sc
);
5354 pko pquote
= REF_OPER(arg1
);
5355 CONTIN_1 (dcrry_2A01VLL
, val2val
, sc
, pquote
);
5357 sc
->tok
= token (sc
);
5358 CONTIN_0 (kernel_read_sexp
, sc
);
5362 sc
->tok
= token (sc
);
5363 if (sc
->tok
== TOK_VEC
)
5365 /* $$CLEAN ME Do this more cleanly than by changing tokens
5366 to trick it. Maybe factor the TOK_LPAREN treatment so we
5368 klink_push_cont (sc
, REF_OPER (kernel_treat_qquoted_vec
));
5369 sc
->tok
= TOK_LPAREN
;
5370 /* $$CLEANUP Seems like this could be combined with the part
5372 CONTIN_0 (kernel_read_sexp
, sc
);
5377 /* Punt for now: Give quoted symbols rather than actual
5378 operators. ,Similarly sc->UNQUOTE, sc->UNQUOTESP */
5379 CONTIN_1 (dcrry_2A01VLL
, val2val
, sc
, sc
->QQUOTE
);
5382 CONTIN_0 (kernel_read_sexp
, sc
);
5386 CONTIN_1 (dcrry_2A01VLL
, val2val
, sc
, sc
->UNQUOTE
);
5387 sc
->tok
= token (sc
);
5388 CONTIN_0 (kernel_read_sexp
, sc
);
5391 CONTIN_1 (dcrry_2A01VLL
, val2val
, sc
, sc
->UNQUOTESP
);
5392 sc
->tok
= token (sc
);
5393 CONTIN_0 (kernel_read_sexp
, sc
);
5396 return mk_atom (sc
, readstr_upto (sc
, "();\t\n\r "));
5399 pko x
= readstrexp (sc
);
5402 KERNEL_ERROR_0 (sc
, "Error reading string");
5409 pko sharp_hook
= sc
->SHARP_HOOK
;
5411 is_symbol(sharp_hook
)
5412 ? find_slot_in_env (sc
->envir
, sharp_hook
, 1)
5416 KERNEL_ERROR_0 (sc
, "undefined sharp expression");
5420 pko form
= mcons (slot_value_in_env (f
), K_NIL
);
5421 return kernel_eval (sc
, form
, sc
->envir
);
5424 case TOK_SHARP_CONST
:
5426 pko x
= mk_sharp_const (readstr_upto (sc
, "();\t\n\r "));
5429 KERNEL_ERROR_0 (sc
, "undefined sharp expression");
5437 KERNEL_ERROR_0 (sc
, "syntax error: illegal token");
5442 /* $$IMPROVE ME Use currying ops instead of accumulating by hand */
5443 SIG_CHKARRAY(kernel_read_list
) = { REF_OPER(is_finite_list
), K_ANY
, };
5444 DEF_SIMPLE_CFUNC (ps0a2
, kernel_read_list
,0)
5446 WITH_2_ARGS (old_accum
,value
);
5447 pko accum
= mcons (value
, old_accum
);
5448 port
* pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
5449 sc
->tok
= token (sc
);
5450 if (sc
->tok
== TOK_EOF
)
5454 else if (sc
->tok
== TOK_RPAREN
)
5456 /* $$RECONSIDER ME Why is this done? To accept CR from user? */
5457 int c
= inchar (pt
);
5462 change_nesting_depth(sc
, -1);
5463 return (unsafe_v2reverse_in_place (K_NIL
, accum
));
5465 else if (sc
->tok
== TOK_DOT
)
5467 CONTIN_1 (dcrry_2A01VLL
, kernel_treat_dotted_list
, sc
, accum
);
5468 sc
->tok
= token (sc
);
5469 CONTIN_0 (kernel_read_sexp
, sc
);
5474 CONTIN_1 (dcrry_2A01VLL
, kernel_read_list
, sc
, accum
);
5475 CONTIN_0 (kernel_read_sexp
, sc
);
5480 /*_ . Treat end of dotted list */
5482 DEF_CFUNC (ps0a2
, kernel_treat_dotted_list
, REF_DESTR(kernel_read_list
),T_NO_K
)
5484 WITH_2_ARGS(args
,value
);
5486 if (token (sc
) != TOK_RPAREN
)
5488 KERNEL_ERROR_0 (sc
, "syntax error: illegal dot expression");
5492 change_nesting_depth(sc
, -1);
5493 return (unsafe_v2reverse_in_place (value
, args
));
5497 /*_ . Treat quasiquoted vector */
5499 DEF_CFUNC (ps0a1
, kernel_treat_qquoted_vec
, K_ANY
,T_NO_K
)
5502 /* $$IMPROVE ME Include vector applicative directly, not by applying
5503 symbol. This does need to apply, though, so that backquote (now
5504 seeing a list) can be run on "value" first*/
5505 return (mcons (mk_symbol ("apply"),
5506 mcons (mk_symbol ("vector"),
5507 mcons (mcons (sc
->QQUOTE
, mcons (value
, K_NIL
)),
5510 /*_ , Loading files */
5511 /*_ . load_from_port */
5512 /* $$RETHINK ME This soon need no longer be a cfunc */
5513 SIG_CHKARRAY(load_from_port
) = { REF_OPER(is_inport
), REF_OPER(is_environment
)};
5514 DEF_SIMPLE_CFUNC(ps0a2
,load_from_port
,0)
5516 WITH_2_ARGS(inport
,env
);
5517 assert (is_port(inport
));
5518 assert (is_environment(env
));
5519 /* Print that we're loading (If there's an outport, and we may want
5520 to add a verbosity condition based on a dynamic variable) */
5521 pko the_outport
= klink_find_dyn_binding(sc
,K_OUTPORT
);
5522 if(the_outport
&& (the_outport
!= K_NIL
))
5524 port
* pt
= portvalue(inport
);
5525 if(pt
->kind
& port_file
)
5527 const char *fname
= pt
->rep
.stdio
.filename
;
5529 { fname
= "<unknown>"; }
5530 putstr(sc
,"Loading ");
5536 /* We will do the evals in ENV */
5538 klink_push_dyn_binding(sc
,K_INPORT
,inport
);
5539 return kernel_rel(sc
);
5543 SIG_CHKARRAY(k_load_file
) = { REF_OPER(is_string
), };
5544 DEF_SIMPLE_APPLICATIVE(ps0a1
,k_load_file
,0,ground
, "load")
5546 WITH_1_ARGS(filename_ob
);
5547 const char * filename
= string_value(filename_ob
);
5548 pko p
= port_from_filename (filename
, port_file
| port_input
);
5551 KERNEL_ERROR_1(sc
,"unable to open", filename_ob
);
5554 return load_from_port(sc
,p
,sc
->envir
);
5556 /*_ . get-module-from-port */
5557 SIG_CHKARRAY(k_get_mod_fm_port
) =
5558 { REF_OPER(is_port
), REF_KEY(K_TYCH_OPTIONAL
), REF_OPER(is_environment
), };
5559 DEF_SIMPLE_APPLICATIVE(ps0a2
,k_get_mod_fm_port
,0,ground
, "get-module-from-port")
5561 WITH_2_ARGS(port
, params
);
5562 pko env
= mk_std_environment();
5563 if(params
!= K_INERT
)
5565 assert(is_environment(params
));
5566 kernel_define (env
, mk_symbol ("module-parameters"), params
);
5568 /* Ultimately return that environment. */
5569 CONTIN_1R(dcrry_NdotALL
,val2val
,sc
,env
);
5570 return load_from_port(sc
, port
,env
);
5574 /*_ , Writing chars */
5576 putstr (klink
* sc
, const char *s
)
5578 pko the_outport
= klink_find_dyn_binding(sc
,K_OUTPORT
);
5579 port
*pt
= portvalue (the_outport
); /* $$MAKE ME SAFER - check for K_NIL */
5581 if (pt
->kind
& port_file
)
5583 fputs (s
, pt
->rep
.stdio
.file
);
5589 if (pt
->rep
.string
.curr
!= pt
->rep
.string
.past_the_end
)
5591 *pt
->rep
.string
.curr
++ = *s
;
5593 else if (pt
->kind
& port_srfi6
&& realloc_port_string (pt
))
5595 *pt
->rep
.string
.curr
++ = *s
;
5602 putchars (klink
* sc
, const char *s
, int len
)
5604 pko the_outport
= klink_find_dyn_binding(sc
,K_OUTPORT
);
5605 port
*pt
= portvalue (the_outport
); /* $$MAKE ME SAFER - check for K_NIL */
5607 if (pt
->kind
& port_file
)
5609 fwrite (s
, 1, len
, pt
->rep
.stdio
.file
);
5615 if (pt
->rep
.string
.curr
!= pt
->rep
.string
.past_the_end
)
5617 *pt
->rep
.string
.curr
++ = *s
++;
5619 else if (pt
->kind
& port_srfi6
&& realloc_port_string (pt
))
5621 *pt
->rep
.string
.curr
++ = *s
++;
5628 putcharacter (klink
* sc
, int c
)
5630 pko the_outport
= klink_find_dyn_binding(sc
,K_OUTPORT
);
5631 port
*pt
= portvalue (the_outport
); /* $$MAKE ME SAFER - check for K_NIL */
5633 if (pt
->kind
& port_file
)
5635 fputc (c
, pt
->rep
.stdio
.file
);
5639 if (pt
->rep
.string
.curr
!= pt
->rep
.string
.past_the_end
)
5641 *pt
->rep
.string
.curr
++ = c
;
5643 else if (pt
->kind
& port_srfi6
&& realloc_port_string (pt
))
5645 *pt
->rep
.string
.curr
++ = c
;
5650 #define ok_abbrev(x) (is_pair(x) && cdr(x) == K_NIL)
5653 printslashstring (klink
* sc
, char *p
, int len
)
5656 unsigned char *s
= (unsigned char *) p
;
5657 putcharacter (sc
, '"');
5658 for (i
= 0; i
< len
; i
++)
5660 if (*s
== 0xff || *s
== '"' || *s
< ' ' || *s
== '\\')
5662 putcharacter (sc
, '\\');
5666 putcharacter (sc
, '"');
5669 putcharacter (sc
, 'n');
5672 putcharacter (sc
, 't');
5675 putcharacter (sc
, 'r');
5678 putcharacter (sc
, '\\');
5683 putcharacter (sc
, 'x');
5686 putcharacter (sc
, d
+ '0');
5690 putcharacter (sc
, d
- 10 + 'A');
5695 putcharacter (sc
, d
+ '0');
5699 putcharacter (sc
, d
- 10 + 'A');
5706 putcharacter (sc
, *s
);
5710 putcharacter (sc
, '"');
5713 /*_ , Printing atoms */
5715 printatom (klink
* sc
, pko l
)
5719 atom2str (sc
, l
, &p
, &len
);
5720 putchars (sc
, p
, len
);
5724 /* Uses internal buffer unless string pointer is already available */
5726 atom2str (klink
* sc
, pko l
, char **pp
, int *plen
)
5730 pko p_escapes
= klink_find_dyn_binding(sc
,K_PRINT_FLAG
);
5731 int escapes
= (p_escapes
== K_T
) ? 1 : 0;
5745 else if (l
== K_INERT
)
5749 else if (l
== K_IGNORE
)
5753 else if (l
== K_EOF
)
5757 else if (is_port (l
))
5760 snprintf (p
, STRBUFFSIZE
, "#<PORT>");
5762 else if (is_number (l
))
5765 if (num_is_integer (l
))
5767 snprintf (p
, STRBUFFSIZE
, "%ld", ivalue (l
));
5771 snprintf (p
, STRBUFFSIZE
, "%.10g", rvalue (l
));
5774 else if (is_string (l
))
5778 p
= string_value (l
);
5781 { /* Hack, uses the fact that printing is needed */
5784 printslashstring (sc
, string_value (l
), string_len (l
));
5788 else if (is_character (l
))
5790 int c
= charvalue (l
);
5802 snprintf (p
, STRBUFFSIZE
, "#\\space");
5805 snprintf (p
, STRBUFFSIZE
, "#\\newline");
5808 snprintf (p
, STRBUFFSIZE
, "#\\return");
5811 snprintf (p
, STRBUFFSIZE
, "#\\tab");
5817 snprintf (p
, STRBUFFSIZE
, "#\\del");
5822 snprintf (p
, STRBUFFSIZE
, "#\\%s", charnames
[c
]);
5828 snprintf (p
, STRBUFFSIZE
, "#\\x%x", c
);
5833 snprintf (p
, STRBUFFSIZE
, "#\\%c", c
);
5839 else if (is_symbol (l
))
5845 else if (is_environment (l
))
5847 p
= "#<ENVIRONMENT>";
5849 else if (is_continuation (l
))
5851 p
= "#<CONTINUATION>";
5853 else if (is_operative (l
)
5854 /* $$TRANSITIONAL When these can be launched by
5855 themselves, this check will be folded into is_operative */
5856 || is_type (l
, T_DESTRUCTURE
)
5857 || is_type (l
, T_TYPECHECK
)
5858 || is_type (l
, T_TYPEP
))
5860 /* $$TRANSITIONAL This logic will move, probably into
5861 k_print_special_and_balk_p, and become more general. */
5863 print_lookup_unwraps
?
5864 reverse_find_slot_in_env_aux(print_lookup_unwraps
,l
) :
5869 snprintf (p
, STRBUFFSIZE
, ",(unwrap #,%s)", symname(0, car(slot
)));
5874 print_lookup_to_xary
?
5875 reverse_find_slot_in_env_aux(print_lookup_to_xary
,l
) :
5879 /* We don't say it's the tree-ary version, because the
5880 tree-ary conversion is not exposed. */
5881 p
= symname(0, car(slot
));
5887 reverse_find_slot_in_env_aux(all_builtins_env
, l
) :
5891 p
= symname(0, car(slot
));
5894 { p
= "#<OPERATIVE>"; }}
5897 else if (is_promise (l
))
5901 else if (is_applicative (l
))
5903 p
= "#<APPLICATIVE>";
5905 else if (is_type (l
, T_ENCAP
))
5907 p
= "#<ENCAPSULATION>";
5909 else if (is_type (l
, T_KEY
))
5913 else if (is_type (l
, T_RECUR_TRACKER
))
5915 p
= "#<RECURRENCE TRACKER>";
5917 else if (is_type (l
, T_RECURRENCES
))
5919 p
= "#<RECURRENCE TABLE>";
5924 snprintf (p
, STRBUFFSIZE
, "#<ERROR %d>", _get_type(l
));
5930 /*_ , C-style entry points */
5932 /*_ , kernel_print_sexp */
5933 SIG_CHKARRAY(kernel_print_sexp
) =
5934 { K_ANY
, REF_KEY(K_TYCH_OPTIONAL
), REF_OPER(is_environment
), };
5936 DEF_SIMPLE_CFUNC (ps0a2
, kernel_print_sexp
,0)
5938 WITH_2_ARGS(sexp
, lookup_env
);
5939 pko recurrences
= get_recurrences(sc
, sexp
);
5940 pko tracker
= recurrences_to_recur_tracker(recurrences
);
5941 /* $$IMPROVE ME Default to an environment that knows sharp
5943 return kernel_print_sexp_aux
5946 ((lookup_env
== K_INERT
) ? ground_env
: lookup_env
));
5948 /*_ , k_print_special_and_balk_p */
5949 /* Possibly print a replacement or prefix. Return 1 if we should now
5950 skip printing sexp (Because it's shared), 0 otherwise. */
5952 k_print_special_and_balk_p
5953 (klink
* sc
, pko tracker
, pko lookup_env
, pko sexp
)
5956 /* If this object is directly known to printer, print its symbol. */
5957 if(lookup_env
!= K_NIL
)
5959 pko slot
= reverse_find_slot_in_env_aux(lookup_env
,sexp
);
5962 putstr (sc
, "#,"); /* Reader is to convert the symbol */
5963 printatom (sc
, car(slot
));
5967 if(tracker
== K_NIL
)
5970 /* $$IMPROVE ME Parameterize this and share that parameterization
5971 with get_recurrences */
5972 switch(_get_type(sexp
))
5981 WITH_PSYC_UNBOXED(kt_recur_tracker
,tracker
, T_RECUR_TRACKER
, sc
);
5982 int index
= objtable_get_index(pdata
->objs
,pdata
->table_size
,sexp
);
5983 if(index
< 0) { return 0; }
5984 recur_entry
* slot
= &pdata
->entries
[index
];
5985 if(slot
->count
<= 1) { return 0; }
5987 if(slot
->seen_in_walk
)
5989 char *p
= sc
->strbuff
;
5990 snprintf (p
, STRBUFFSIZE
, "#%d", slot
->index_in_walk
);
5991 putchars (sc
, p
, strlen (p
));
5992 return 1; /* Skip printing the object */
5996 slot
->seen_in_walk
= 1;
5997 slot
->index_in_walk
= pdata
->current_index
;
5998 pdata
->current_index
++;
5999 char *p
= sc
->strbuff
;
6000 snprintf (p
, STRBUFFSIZE
, "#%d=", slot
->index_in_walk
);
6001 putchars (sc
, p
, strlen (p
));
6002 return 0; /* Still should print the object */
6005 /*_ , kernel_print_sexp_aux */
6006 SIG_CHKARRAY(kernel_print_sexp_aux
) =
6007 { K_ANY
, REF_OPER(is_recur_tracker
), REF_OPER(is_environment
), };
6009 DEF_SIMPLE_CFUNC (ps0a3
, kernel_print_sexp_aux
,0)
6011 WITH_3_ARGS(sexp
, recur_tracker
, lookup_env
);
6013 if(k_print_special_and_balk_p(sc
, recur_tracker
, lookup_env
, sexp
))
6015 if (is_vector (sexp
))
6018 CONTIN_4 (dcrry_4dotALL
, kernel_print_vec_from
, sc
, sexp
,
6019 mk_integer (0), recur_tracker
, lookup_env
);
6022 else if (!is_pair (sexp
))
6024 printatom (sc
, sexp
);
6027 /* $$FIX ME Recognize quote etc.
6029 That is hard since the quote operative is not currently defined
6030 as such and we no longer have syntax.
6032 else if (car (sexp
) == sc
->QUOTE
&& ok_abbrev (cdr (sexp
)))
6035 return kernel_print_sexp_aux (sc
, cadr (sexp
), recur_tracker
, lookup_env
);
6037 else if (car (sexp
) == sc
->QQUOTE
&& ok_abbrev (cdr (sexp
)))
6040 return kernel_print_sexp_aux (sc
, cadr (sexp
), recur_tracker
, lookup_env
);
6042 else if (car (sexp
) == sc
->UNQUOTE
&& ok_abbrev (cdr (sexp
)))
6045 return kernel_print_sexp_aux (sc
, cadr (sexp
), recur_tracker
, lookup_env
);
6047 else if (car (sexp
) == sc
->UNQUOTESP
&& ok_abbrev (cdr (sexp
)))
6050 return kernel_print_sexp_aux (sc
, cadr (sexp
), recur_tracker
, lookup_env
);
6055 CONTIN_0_RAW(REF_OBJ(k_print_terminate_list
), sc
);
6056 CONTIN_3 (dcrry_2dotALL
, kernel_print_list
, sc
, cdr (sexp
), recur_tracker
, lookup_env
);
6057 return kernel_print_sexp_aux (sc
, car (sexp
), recur_tracker
, lookup_env
);
6060 /*_ , print_value */
6061 DEF_BOXED_CURRIED(print_value
,
6064 REF_OPER (kernel_print_sexp
));
6065 /*_ . k_print_string */
6066 SIG_CHKARRAY(k_print_string
) = { REF_OPER(is_string
), };
6068 DEF_SIMPLE_CFUNC (ps0a1
, k_print_string
,T_NO_K
)
6071 putstr (sc
, string_value(str
));
6074 /*_ . k_print_terminate_list */
6075 /* $$RETHINK ME This may be the long way to do it. */
6077 BOX_OF(kt_string
) _k_string_rpar
=
6078 { T_STRING
| T_IMMUTABLE
,
6079 { ")", sizeof(")"), },
6082 BOX_OF(kt_vec2
) _k_list_string_rpar
=
6083 { T_PAIR
| T_IMMUTABLE
,
6084 { REF_OBJ(_k_string_rpar
), REF_KEY(K_NIL
)}
6087 DEF_BOXED_CURRIED(k_print_terminate_list
,
6089 REF_OBJ(_k_list_string_rpar
),
6090 REF_OPER(k_print_string
));
6092 RGSTR(ground
, "newline", REF_OBJ(k_newline
))
6094 BOX_OF(kt_string
) _k_string_newline
=
6095 { T_STRING
| T_IMMUTABLE
,
6096 { "\n", sizeof("\n"), }, };
6098 BOX_OF(kt_vec2
) _k_list_string_newline
=
6099 { T_PAIR
| T_IMMUTABLE
,
6100 { REF_OBJ(_k_string_newline
), REF_KEY(K_NIL
)}
6103 DEF_BOXED_CURRIED(k_newline
,
6105 REF_OBJ(_k_list_string_newline
),
6106 REF_OPER(k_print_string
));
6108 /*_ . kernel_print_list */
6110 DEF_CFUNC (ps0a3
, kernel_print_list
, REF_DESTR(kernel_print_sexp_aux
),0)
6113 WITH_3_ARGS(sexp
, recur_tracker
, lookup_env
);
6114 if(is_pair (sexp
)) { putstr (sc
, " "); }
6115 else if (sexp
!= K_NIL
) { putstr (sc
, " . "); }
6118 if(k_print_special_and_balk_p(sc
, recur_tracker
, lookup_env
, sexp
))
6122 CONTIN_3 (dcrry_3dotALL
, kernel_print_list
, sc
, cdr (sexp
), recur_tracker
, lookup_env
);
6123 return kernel_print_sexp_aux (sc
, car (sexp
), recur_tracker
, lookup_env
);
6125 if (is_vector (sexp
))
6127 /* $$RETHINK ME What does this even print? */
6128 CONTIN_3 (dcrry_3dotALL
, kernel_print_list
, sc
, K_NIL
, recur_tracker
, lookup_env
);
6129 return kernel_print_sexp_aux (sc
, sexp
, recur_tracker
, lookup_env
);
6134 printatom (sc
, sexp
);
6140 /*_ . kernel_print_vec_from */
6141 SIG_CHKARRAY(kernel_print_vec_from
) =
6143 REF_OPER(is_integer
),
6144 REF_OPER(is_recur_tracker
),
6145 REF_OPER(is_environment
), };
6146 DEF_SIMPLE_CFUNC (ps0a4
, kernel_print_vec_from
,0)
6148 WITH_4_ARGS(vec
,k_i
, recur_tracker
, lookup_env
);
6149 int i
= ivalue (k_i
);
6150 int len
= vector_len (vec
);
6158 pko elem
= vector_elem (vec
, i
);
6159 set_ivalue (k_i
, i
+ 1);
6160 CONTIN_4 (dcrry_4dotALL
, kernel_print_vec_from
, sc
, vec
, arg2
, recur_tracker
, lookup_env
);
6162 return kernel_print_sexp_aux (sc
, elem
, recur_tracker
, lookup_env
);
6165 /*_ , Kernel entry points */
6167 DEF_APPLICATIVE_W_DESTR(ps0a1
,k_write
,K_ANY_SINGLETON
,0,ground
, "write")
6170 klink_push_dyn_binding(sc
,K_PRINT_FLAG
,K_T
);
6171 return kernel_print_sexp(sc
,p
,K_INERT
);
6175 DEF_APPLICATIVE_W_DESTR(ps0a1
,k_display
,K_ANY_SINGLETON
,0,ground
, "display")
6178 klink_push_dyn_binding(sc
,K_PRINT_FLAG
,K_F
);
6179 return kernel_print_sexp(sc
,p
,K_INERT
);
6183 /*_ . tracing_say */
6184 /* $$TRANSITIONAL Until we have actual trace hook */
6185 SIG_CHKARRAY(tracing_say
) = { REF_OPER(is_string
), K_ANY
, };
6186 DEF_SIMPLE_CFUNC (ps0a2
, tracing_say
,T_NO_K
)
6188 WITH_2_ARGS(k_string
, value
);
6191 putstr (sc
, string_value(k_string
));
6197 /*_ . Equivalence */
6198 /*_ , Equivalence of atoms */
6199 SIG_CHKARRAY(eqv
) = { K_ANY
, K_ANY
, };
6200 DEF_SIMPLE_APPLICATIVE(b00a2
,eqv
,T_NO_K
,simple
,"equal?/2-atom-atom")
6208 const char * a_str
= string_value (a
);
6209 const char * b_str
= string_value (b
);
6210 if (a_str
== b_str
) { return 1; }
6211 return !strcmp(a_str
, b_str
);
6216 else if (is_number (a
))
6220 if (num_is_integer (a
) == num_is_integer (b
))
6221 return num_eq (nvalue (a
), nvalue (b
));
6225 else if (is_character (a
))
6227 if (is_character (b
))
6228 return charvalue (a
) == charvalue (b
);
6232 else if (is_port (a
))
6244 /*_ , Equivalence of containers */
6246 /*_ . Hash function */
6247 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
6250 hash_fn (const char *key
, int table_size
)
6252 unsigned int hashed
= 0;
6254 int bits_per_int
= sizeof (unsigned int) * 8;
6256 for (c
= key
; *c
; c
++)
6258 /* letters have about 5 bits in them */
6259 hashed
= (hashed
<< 5) | (hashed
>> (bits_per_int
- 5));
6262 return hashed
% table_size
;
6266 /* Quick and dirty hash function for pointers */
6268 ptr_hash_fn(void * ptr
, int table_size
)
6269 { return (long)ptr
% table_size
; }
6271 /*_ . binder/accessor maker */
6272 pko
make_keyed_variable(pko gen_binder
, pko gen_accessor
)
6274 /* Make a unique key object */
6275 pko key
= mk_void();
6276 pko binder
= wrap (mk_curried
6280 pko accessor
= wrap (mk_curried
6284 /* Curry and wrap the two things. */
6285 return LIST2 (binder
, accessor
);
6288 /*_ . Environment implementation */
6289 /*_ , New-style environment objects */
6293 /* T_ENV_FRAME is a vec2 used as a pair in the env tree. It
6294 indicates a frame boundary.
6296 /* T_ENV_PAIR is another vec2 used as a pair in the env tree. It
6297 indicates no frame boundary.
6300 /* Other types are (hackishly) still shared with the vanilla types:
6302 A vector is interpeted as a hash table vector that is "as if" it
6303 were a list of T_ENV_PAIR. Each element is an alist of bindings.
6304 It can only hold symbol bindings, not keyed bindings, because we
6305 can't hash keyed bindings.
6307 A pair is interpreted as a binding of something and value. That
6308 something can be either a symbol or a key (void object). It is
6309 held directly by an T_ENV_FRAME or T_ENV_PAIR (or "as if", by the
6310 alists of a hash table vector).
6314 /*_ . Object functions */
6316 DEF_T_PRED (is_environment
, T_ENV_FRAME
,ground
,"environment?/o1");
6318 /*_ , New environment implementation */
6320 #ifndef USE_ALIST_ENV
6322 find_slot_in_env_vector (pko eobj
, pko hdl
)
6324 for (; eobj
!= K_NIL
; eobj
= unsafe_v2cdr (eobj
))
6326 assert (is_pair (eobj
));
6327 pko slot
= unsafe_v2car (eobj
);
6328 assert (is_pair (slot
));
6329 if (unsafe_v2car (slot
) == hdl
)
6338 reverse_find_slot_in_env_vector (pko eobj
, pko value
)
6340 for (; eobj
!= K_NIL
; eobj
= unsafe_v2cdr (eobj
))
6342 assert (is_pair (eobj
));
6343 pko slot
= unsafe_v2car (eobj
);
6344 assert (is_pair (slot
));
6345 if (unsafe_v2cdr (slot
) == value
)
6355 * If we're using vectors, each frame of the environment may be a hash
6356 * table: a vector of alists hashed by variable name. In practice, we
6357 * use a vector only for the initial frame; subsequent frames are too
6358 * small and transient for the lookup speed to out-weigh the cost of
6359 * making a new vector.
6362 make_new_frame(pko old_env
)
6365 #ifndef USE_ALIST_ENV
6366 /* $$IMPROVE ME Make a better test for whether to make vector. */
6367 /* The interaction-environment has about 300 variables in it. */
6368 if (old_env
== K_NIL
)
6370 new_frame
= mk_vector (461, K_NIL
);
6378 return v2cons (T_ENV_FRAME
, new_frame
, old_env
);
6382 new_slot_spec_in_env (pko env
, pko variable
, pko value
)
6384 assert(is_environment(env
));
6385 assert(is_symbol(variable
));
6386 pko slot
= mcons (variable
, value
);
6387 pko car_env
= unsafe_v2car (env
);
6388 #ifndef USE_ALIST_ENV
6389 if (is_vector (car_env
))
6391 int location
= hash_fn (symname (0,variable
), vector_len (car_env
));
6393 set_vector_elem (car_env
, location
,
6395 vector_elem (car_env
, location
)));
6400 pko new_list
= v2cons (T_ENV_PAIR
, slot
, car_env
);
6401 unsafe_v2set_car (env
, new_list
);
6405 enum env_frame_search_restriction
6408 env_fsr_only_coming_frame
,
6409 env_fsr_only_this_frame
,
6412 /* This explores a tree of bindings, punctuated by frames past which
6413 we sometimes don't search. */
6415 find_slot_in_env_aux (pko eobj
, pko hdl
, int restr
)
6419 _kt_tag type
= _get_type (eobj
);
6422 /* We have a slot (Which for now is just a pair) */
6424 if(unsafe_v2car (eobj
) == hdl
)
6428 #ifndef USE_ALIST_ENV
6431 /* Only for symbols. */
6432 if(!is_symbol (hdl
)) { return 0; }
6433 int location
= hash_fn (symname (0,hdl
), vector_len (eobj
));
6434 pko el
= vector_elem (eobj
, location
);
6435 return find_slot_in_env_vector (el
, hdl
);
6438 /* We have some sort of env pair */
6440 /* Check whether we should keep looking. */
6445 case env_fsr_only_coming_frame
:
6446 restr
= env_fsr_only_this_frame
;
6448 case env_fsr_only_this_frame
:
6452 "find_slot_in_env_aux: Bad restriction enum: %d", restr
);
6457 /* Explore car before cdr */
6458 pko found
= find_slot_in_env_aux (unsafe_v2car (eobj
), hdl
, restr
);
6459 if(found
) { return found
; }
6460 return find_slot_in_env_aux (unsafe_v2cdr (eobj
),hdl
,restr
);
6463 /* No other type should be found */
6465 "find_slot_in_env_aux: Bad type: %d", type
);
6466 return 0; /* NOTREACHED */
6471 find_slot_in_env (pko env
, pko hdl
, int all
)
6473 assert(is_environment(env
));
6474 enum env_frame_search_restriction restr
=
6475 all
? env_fsr_all
: env_fsr_only_coming_frame
;
6476 return find_slot_in_env_aux(env
,hdl
,restr
);
6478 /*_ , Reverse find-slot */
6479 /*_ . env_confirm_slot */
6481 env_confirm_slot(pko env
, pko slot
)
6483 assert(is_pair(slot
));
6485 (find_slot_in_env_aux(env
,unsafe_v2car(slot
),env_fsr_all
) == slot
);
6487 /*_ . reverse_find_slot_in_env_aux2 */
6489 reverse_find_slot_in_env_aux2(pko env
, pko eobj
, pko value
)
6493 _kt_tag type
= _get_type (eobj
);
6496 /* We have a slot (Which for now is just a pair) */
6498 if((unsafe_v2cdr (eobj
) == value
)
6499 && env_confirm_slot(env
, eobj
))
6503 #ifndef USE_ALIST_ENV
6506 /* $$IMPROVE ME Create a reverse-lookup vector if we come here
6507 and there is none. */
6509 for(i
= 0; i
< vector_len (eobj
); ++i
)
6511 pko slot
= reverse_find_slot_in_env_vector(vector_elem (eobj
, i
), value
);
6513 env_confirm_slot(env
, slot
))
6519 /* We have some sort of env pair */
6524 /* Explore car before cdr */
6526 reverse_find_slot_in_env_aux2 (env
, unsafe_v2car (eobj
), value
);
6527 if(found
&& env_confirm_slot(env
, found
))
6530 reverse_find_slot_in_env_aux2 (env
, unsafe_v2cdr (eobj
), value
);
6531 if(found
&& env_confirm_slot(env
, found
))
6536 /* No other type should be found */
6538 "reverse_find_slot_in_env_aux2: Bad type: %d", type
);
6539 return 0; /* NOTREACHED */
6543 /*_ . reverse_find_slot_in_env_aux */
6545 reverse_find_slot_in_env_aux (pko env
, pko value
)
6547 assert(is_environment(env
));
6548 return reverse_find_slot_in_env_aux2(env
, env
, value
);
6551 /*_ . Entry point */
6552 /* Exposed for testing */
6553 /* NB, args are in different order than in the helpers */
6554 SIG_CHKARRAY(reverse_find_slot_in_env
) =
6555 { K_ANY
, REF_OPER(is_environment
), };
6556 DEF_SIMPLE_APPLICATIVE (ps0a2
, reverse_find_slot_in_env
,T_NO_K
,unsafe
, "reverse-lookup")
6558 WITH_2_ARGS(value
,env
);
6560 pko slot
= reverse_find_slot_in_env_aux(env
, value
);
6561 if(slot
) { return car(slot
); }
6564 KERNEL_ERROR_0(sc
, "reverse_find_slot_in_env: No match");
6568 /*_ . reverse-binds?/2 */
6569 /* $$IMPROVE ME Maybe combine these */
6570 DEF_APPLICATIVE_W_DESTR(b00a2
,reverse_binds_p
,
6571 REF_DESTR(reverse_find_slot_in_env
),
6572 T_NO_K
,simple
,"reverse-binds?/2")
6574 WITH_2_ARGS(value
,env
);
6575 return reverse_find_slot_in_env_aux(env
, value
) ? 1 : 0;
6577 /*_ , Shared functions */
6580 new_frame_in_env (klink
* sc
, pko old_env
)
6582 sc
->envir
= make_new_frame (old_env
);
6586 set_slot_in_env (pko slot
, pko value
)
6588 assert (is_pair (slot
));
6589 set_cdr (0, slot
, value
);
6593 slot_value_in_env (pko slot
)
6596 assert (is_pair (slot
));
6600 /*_ , Keyed static bindings */
6602 /*_ , Making them */
6603 /* Make a new frame containing just the one keyed static variable. */
6605 env_plus_keyed_var (pko key
, pko value
, pko old_env
)
6607 pko slot
= cons (key
, value
);
6608 return v2cons (T_ENV_FRAME
, slot
, old_env
);
6610 /*_ , Finding them */
6611 /* find_slot_in_env works for this too. */
6614 SIG_CHKARRAY(klink_ksb_binder
) =
6615 { REF_OPER(is_key
), K_ANY
, REF_OPER(is_environment
), };
6616 DEF_SIMPLE_CFUNC(ps0a3
,klink_ksb_binder
,T_NO_K
)
6618 WITH_3_ARGS(key
, value
, env
);
6619 /* Check that env is in fact a environment. */
6620 if(!is_environment(env
))
6623 "klink_ksb_binder: Arg 2 must be an environment: ",
6626 /* Return a new environment with just that binding. */
6627 return env_plus_keyed_var(key
, value
, env
);
6631 SIG_CHKARRAY(klink_ksb_accessor
) =
6632 { REF_OPER(is_key
), };
6633 DEF_SIMPLE_CFUNC(ps0a1
,klink_ksb_accessor
,T_NO_K
)
6636 pko value
= find_slot_in_env(sc
->envir
,key
,1);
6639 KERNEL_ERROR_0(sc
, "klink_ksb_accessor: No binding found");
6642 return slot_value_in_env (value
);
6645 /*_ , make_keyed_static_variable */
6646 RGSTR(ground
, "make-keyed-static-variable", REF_OPER(make_keyed_static_variable
))
6647 DEF_CFUNC(p00a0
, make_keyed_static_variable
,K_NO_TYPE
,T_NO_K
)
6649 return make_keyed_variable(
6650 REF_OPER(klink_ksb_binder
),
6651 REF_OPER (klink_ksb_accessor
));
6653 /*_ , Building environments */
6654 /* Argobject is checked internally, so K_ANY */
6655 DEF_APPLICATIVE_W_DESTR(ps0a1
,make_environment
,K_ANY
,T_NO_K
,ground
, "make-environment")
6657 WITH_1_ARGS(parents
);
6658 /* $$IMPROVE ME Factor this so we only call get_list_metrics_aux
6659 once on this object. */
6661 get_list_metrics_aux(parents
, metrics
);
6662 pko typecheck
= REF_OPER(is_environment
);
6663 /* This will reject dotted lists */
6664 if(!typecheck_repeat(sc
,parents
,&typecheck
,1,1))
6666 KERNEL_ERROR_0 (sc
, "make_environment: argobject must be a list of environments");
6669 /* Collect the parent environments. */
6671 pko rv_par_list
= K_NIL
;
6672 for(i
= 0; i
< metrics
[lm_num_pairs
]; ++i
, parents
= pair_cdr(0, parents
))
6674 pko pare
= pair_car(0, parents
);
6675 rv_par_list
= v2cons (T_ENV_PAIR
, pare
, rv_par_list
);
6678 /* Reverse the list in place. */
6681 par_list
= unsafe_v2reverse_in_place(K_NIL
, rv_par_list
);
6683 /* $$IMPROVE ME Check for redundant environments and skip them.
6684 Check only *previous* environments, because we still need to
6685 search correctly. When recurrences walks environments too, we
6686 can use that to find them. */
6687 /* $$IMPROVE ME Add to environment information to block rechecks. */
6689 /* Return a new environment with all of those as parents. */
6690 return make_new_frame(par_list
);
6693 RGSTR(simple
,"$binds?/2", REF_OPER(bindsp_1
))
6694 SIG_CHKARRAY(bindsp_1
) =
6695 { REF_OPER(is_environment
), REF_OPER(is_symbol
), };
6696 DEF_SIMPLE_CFUNC(bs0a2
,bindsp_1
,T_NO_K
)
6698 WITH_2_ARGS(env
, sym
);
6699 return find_slot_in_env(env
, sym
, 1) ? 1 : 0;
6701 /*_ , find-binding */
6702 DEF_APPLICATIVE_W_DESTR(ps0a2
,find_binding
,REF_DESTR(bindsp_1
),T_NO_K
,ground
,"find-binding")
6704 WITH_2_ARGS(env
, sym
);
6705 pko binding
= find_slot_in_env(env
, sym
, 1);
6708 return cons(K_T
,slot_value_in_env (binding
));
6712 return cons(K_F
,K_INERT
);
6717 /*_ , Enumerations */
6718 enum klink_stack_cell_types
6727 ksct_arg_barrier
, /* Barrier to propagating pseudo-env. */
6731 struct dump_stack_frame
6736 struct stack_binding
6748 struct stack_profiling
6761 typedef struct dump_stack_frame_cell
6763 enum klink_stack_cell_types type
;
6767 struct dump_stack_frame frame
;
6768 struct stack_binding binding
;
6769 struct stack_guards guards
;
6770 struct stack_profiling profiling
;
6771 struct stack_arg pseudoenv
;
6773 } dump_stack_frame_cell
;
6778 dump_stack_initialize (klink
* sc
)
6784 stack_empty (klink
* sc
)
6785 { return sc
->dump
== 0; }
6789 klink_pop_cont (klink
* sc
)
6791 _kt_spagstack rv_pseudoenvs
= 0;
6793 /* Always return frame, which sc->dump will be set to. */
6794 /* for(frame = sc->dump; frame != 0; frame = frame->next) */
6803 const _kt_spagstack frame
= sc
->dump
;
6804 if(frame
->type
== ksct_frame
)
6806 const struct dump_stack_frame
*pdata
= &frame
->data
.frame
;
6807 sc
->next_func
= pdata
->ff
;
6808 sc
->envir
= pdata
->envir
;
6810 _kt_spagstack final_frame
= frame
->next
;
6812 /* Add the collected pseudo-env elements */
6813 while(rv_pseudoenvs
)
6815 _kt_spagstack el
= rv_pseudoenvs
;
6816 _kt_spagstack new_top
= rv_pseudoenvs
->next
;
6817 el
->next
= final_frame
;
6819 rv_pseudoenvs
= new_top
;
6821 sc
->dump
= final_frame
;
6826 if(frame
->type
== ksct_profile
)
6828 struct stack_profiling
* pdata
= &frame
->data
.profiling
;
6829 k_profiling_done_frame(sc
,pdata
);
6830 sc
->dump
= frame
->next
;
6833 else if( frame
->type
== ksct_args
)
6835 struct stack_arg
* old_pe
= &frame
->data
.pseudoenv
;
6836 if(old_pe
->frame_depth
> 0)
6838 /* Make a copy, to be re-added lower down */
6839 _kt_spagstack new_pseudoenv
=
6841 GC_MALLOC (sizeof (dump_stack_frame_cell
));
6842 struct stack_arg
* new_pe
= &new_pseudoenv
->data
.pseudoenv
;
6843 new_pe
->vec
= old_pe
->vec
;
6844 new_pe
->frame_depth
= old_pe
->frame_depth
- 1;
6846 new_pseudoenv
->type
= ksct_args
;
6847 new_pseudoenv
->next
= rv_pseudoenvs
;
6848 rv_pseudoenvs
= new_pseudoenv
;
6851 sc
->dump
= frame
->next
;
6853 else if( frame
->type
== ksct_arg_barrier
)
6855 errx( 0, "Not allowed");
6857 sc
->dump
= frame
->next
;
6861 sc
->dump
= frame
->next
;
6867 static _kt_spagstack
6869 (_kt_spagstack old_frame
, pko ff
, pko env
)
6871 _kt_spagstack frame
=
6873 GC_MALLOC (sizeof (dump_stack_frame_cell
));
6874 struct dump_stack_frame
* pdata
= &frame
->data
.frame
;
6878 frame
->type
= ksct_frame
;
6879 frame
->next
= old_frame
;
6885 klink_push_cont (klink
* sc
, pko ff
)
6886 { sc
->dump
= klink_push_cont_aux(sc
->dump
, ff
, sc
->envir
); }
6888 /*_ , Dynamic bindings */
6890 /* We do not pop dynamic bindings, only frames. */
6891 /* We deal with dynamic bindings in the context of the interpreter so
6892 that in the future we can cache them. */
6894 klink_push_dyn_binding (klink
* sc
, pko key
, pko value
)
6896 _kt_spagstack frame
=
6898 GC_MALLOC (sizeof (dump_stack_frame_cell
));
6899 struct stack_binding
*pdata
= &frame
->data
.binding
;
6902 pdata
->value
= value
;
6904 frame
->type
= ksct_binding
;
6905 frame
->next
= sc
->dump
;
6911 klink_find_dyn_binding(klink
* sc
, pko key
)
6913 _kt_spagstack frame
= sc
->dump
;
6922 if(frame
->type
== ksct_binding
)
6924 const struct stack_binding
*pdata
= &frame
->data
.binding
;
6925 if(pdata
->key
== key
)
6926 { return pdata
->value
; }
6928 frame
= frame
->next
;
6933 /*_ . klink_push_guards */
6934 static _kt_spagstack
6936 (_kt_spagstack old_frame
, pko guards
, pko envir
, int exit
)
6938 _kt_spagstack frame
=
6940 GC_MALLOC (sizeof (dump_stack_frame_cell
));
6941 struct stack_guards
* pdata
= &frame
->data
.guards
;
6942 pdata
->guards
= guards
;
6943 pdata
->envir
= envir
;
6945 frame
->type
= exit
? ksct_exit_guards
: ksct_entry_guards
;
6946 frame
->next
= old_frame
;
6949 /*_ . get_guards_lo1st */
6950 /* Get a list of guard entries, root-most on top. */
6952 get_guards_lo1st(_kt_spagstack frame
)
6955 for(; frame
!= 0; frame
= frame
->next
)
6957 if((frame
->type
== ksct_entry_guards
) ||
6958 (frame
->type
== ksct_exit_guards
))
6960 list
= cons(mk_continuation(frame
), list
);
6968 /*_ , set_nth_arg */
6970 /* Set the nth arg */
6971 /* Unused, probably for a while, probably will never be used in this
6974 set_nth_arg(klink
* sc
, int n
, pko value
)
6976 _kt_spagstack frame
= sc
->dump
;
6978 for(frame
= sc
->dump
; frame
!= 0; frame
= frame
->next
)
6980 if(frame
->type
== ksct_args
)
6984 frame
->data
.arg
= value
;
6991 /* If we got here we never encountered the target. */
6995 /*_ . Store from value */
6996 /*_ , push_arg_raw */
6998 push_arg_raw(_kt_spagstack old_frame
, pko value
, int frame_depth
)
7000 _kt_spagstack frame
=
7002 GC_MALLOC (sizeof (dump_stack_frame_cell
));
7004 frame
->data
.pseudoenv
.vec
= value
;
7005 frame
->data
.pseudoenv
.frame_depth
= frame_depth
;
7006 frame
->type
= ksct_args
;
7007 frame
->next
= old_frame
;
7013 k_do_store(klink
* sc
, pko functor
, pko value
)
7015 WITH_PSYC_UNBOXED( kt_opstore
, functor
, T_STORE
, sc
);
7016 /* $$MAKE ME SAFE do_destructure must be safe vs resuming. Error if
7017 not T_NO_K. Don't try to maybe resume, because so far we never
7020 pko vec
= do_destructure( sc
, value
, pdata
->destr
);
7021 /* Push that as arg */
7022 sc
->dump
= push_arg_raw (sc
->dump
, vec
, pdata
->frame_depth
);
7025 /*_ . Load to value */
7026 /*_ , get_nth_arg */
7028 get_nth_arg( _kt_spagstack frame
, int n
)
7031 for(; frame
!= 0; frame
= frame
->next
)
7033 if(frame
->type
== ksct_args
)
7036 { return frame
->data
.pseudoenv
.vec
; }
7041 /* If we got here we never encountered the target. */
7045 /*_ , k_load_recurse */
7046 /* $$IMPROVE ME Add a shortcut for accessing value without ever
7049 k_load_recurse( _kt_spagstack frame
, pko tree
)
7051 if(_get_type( tree
) == T_PAIR
)
7053 WITH_PSYC_UNBOXED( kt_vec2
, tree
, T_PAIR
, 0 );
7054 if( is_integer( pdata
->_car
) && is_integer( pdata
->_cdr
))
7056 /* Pair of integers: Look up that item, look up secondary
7058 const int n
= ivalue( pdata
->_car
);
7059 const int m
= ivalue( pdata
->_cdr
);
7060 pko vec
= get_nth_arg( frame
, n
);
7062 assert( is_vector( vec
));
7063 pko value
= basvector_elem( vec
, m
);
7069 /* Pair, not integers: Explore car and cdr, return cons of them. */
7071 k_load_recurse( frame
, pdata
->_car
),
7072 k_load_recurse( frame
, pdata
->_cdr
));
7077 /* Anything else: Return it literally. */
7083 /* T_LOAD C-destructures as a singleton. It will contain a tree */
7084 /* This may largely take over for decurriers. */
7086 k_do_load(klink
* sc
, pko functor
, pko value
)
7088 WITH_PSYC_UNBOXED( pko
, functor
, T_LOAD
, sc
);
7089 return k_load_recurse( sc
->dump
, *pdata
);
7092 /*_ , Stack ancestry */
7093 /*_ . frame_is_ancestor_of */
7094 int frame_is_ancestor_of(_kt_spagstack frame
, _kt_spagstack other
)
7096 /* Walk from other towards root. Return 1 if we ever encounter
7097 frame, otherwise 0. */
7098 for(; other
!= 0; other
= other
->next
)
7105 /*_ . special_dynxtnt */
7106 /* Make a child of dynamic extent OUTER that evals with dynamic
7107 environment ENVIR continues normally to PROX_DEST. */
7108 _kt_spagstack special_dynxtnt
7109 (_kt_spagstack outer
, _kt_spagstack prox_dest
, pko envir
)
7112 klink_push_cont_aux(outer
,
7113 mk_curried(dcrry_2A01VLL
,
7114 LIST1(mk_continuation(prox_dest
)),
7115 REF_OPER(invoke_continuation
)),
7118 /*_ . curr_frame_depth */
7119 int curr_frame_depth(_kt_spagstack frame
)
7121 /* Walk towards root, counting. */
7123 for(; frame
!= 0; frame
= frame
->next
, count
++)
7127 /*_ , Continuations */
7131 _kt_spagstack frame
;
7136 DEF_T_PRED (is_continuation
, T_CONTINUATION
,ground
, "continuation?/o1");
7139 mk_continuation (_kt_spagstack frame
)
7141 ALLOC_BOX_PRESUME (continuation_t
, T_CONTINUATION
);
7142 pdata
->frame
= frame
;
7143 return PTR2PKO(pbox
);
7146 static _kt_spagstack
7149 WITH_PSYC_UNBOXED(continuation_t
,p
,T_CONTINUATION
,0);
7150 return pdata
->frame
;
7153 /*_ . Continuations WRT interpreter */
7154 /*_ , current_continuation */
7156 current_continuation (klink
* sc
)
7158 return mk_continuation (sc
->dump
);
7161 /*_ , invoke_continuation */
7162 /* DOES NOT RETURN */
7163 /* Control is resumed at _klink_cycle */
7165 /* Static and not directly available to Kernel, it's the eventual
7166 target of continuation_to_applicative. */
7167 SIG_CHKARRAY(invoke_continuation
) =
7168 { REF_OPER(is_continuation
), K_ANY
, };
7169 DEF_SIMPLE_CFUNC(vs0a2
,invoke_continuation
,T_NO_K
)
7171 WITH_2_ARGS (p
, value
);
7172 assert(is_continuation(p
));
7174 { sc
->dump
= cont_dump (p
); }
7176 longjmp (sc
->pseudocontinuation
, 1);
7179 /* Add the appropriate guard, if any, and return the new proximate
7183 (_kt_spagstack prox_dest
, _kt_spagstack to_contain
,
7184 pko guard_list
, pko envir
, _kt_spagstack outer
)
7188 for(x
= guard_list
; x
!= K_NIL
; x
= cdr(x
))
7190 pko selector
= car(car(x
));
7191 assert(is_continuation(selector
));
7192 if(frame_is_ancestor_of(cont_dump(selector
), to_contain
))
7194 /* Call has to take place in the dynamic extent of the
7195 next frame around this set of guards, so that the
7196 interceptor has access to dynamic bindings, but then
7197 control has to continue normally to the next guard or
7198 finally to the destination.
7200 So we extend the next frame with a call to
7201 invoke_continuation, currying the next destination in the
7202 chain. That does not check guards, so in effect it
7203 continues normally. Then we extend that with a call to
7204 the interceptor, currying an continuation->applicative of
7205 the guards' outer continuation.
7207 NB, continuation->applicative is correct. It would be
7208 wrong to shortcircuit it. Although there are no guards
7209 between there and the outer continuation, the
7210 continuation we pass might be called from another dynamic
7211 context. But it needs to be unwrapped.
7213 pko wrapped_interceptor
= cadr(car(x
));
7214 assert(is_applicative(wrapped_interceptor
));
7215 pko interceptor
= unwrap(0,wrapped_interceptor
);
7216 assert(is_operative(interceptor
));
7218 _kt_spagstack med_frame
=
7219 special_dynxtnt(outer
, prox_dest
, envir
);
7221 klink_push_cont_aux(med_frame
,
7222 mk_curried(dcrry_2VLLdotALL
,
7223 LIST1(continuation_to_applicative(mk_continuation(outer
))),
7227 /* We use only the first match so end the loop. */
7233 /*_ , add_guard_chain */
7236 (_kt_spagstack prox_dest
, pko guard_frame_list
, _kt_spagstack to_contain
, int exit
)
7239 const enum klink_stack_cell_types tag
7240 = exit
? ksct_exit_guards
: ksct_entry_guards
;
7241 for( ; guard_frame_list
!= K_NIL
; guard_frame_list
= cdr(guard_frame_list
))
7243 _kt_spagstack guard_frame
= cont_dump(car(guard_frame_list
));
7244 if(guard_frame
->type
== tag
)
7246 struct stack_guards
* pguards
= &guard_frame
->data
.guards
;
7248 add_guard(prox_dest
,
7252 exit
? guard_frame
->next
: guard_frame
);
7257 /*_ , continue_abnormally */
7258 /*** Arrange to "walk" from current continuation to c, passing control
7259 thru appropriate guards. ***/
7260 SIG_CHKARRAY(continue_abnormally
) =
7261 { REF_OPER(is_continuation
), K_ANY
, };
7262 /* I don't give this T_NO_K even though technically it longjmps
7263 rather than pushing into the eval loop. In the future we may
7264 distinguish those two cases. */
7265 DEF_SIMPLE_CFUNC(ps0a2
,continue_abnormally
,0)
7267 WITH_2_ARGS(c
,value
);
7269 _kt_spagstack source
= sc
->dump
;
7270 _kt_spagstack destination
= cont_dump (c
);
7272 /*** Find the guard frames on the intermediate path. ***/
7274 /* Control is exiting our current frame, so collect guards from
7275 there towards root. What we get is lowest first. */
7276 pko exiting_lo1st
= get_guards_lo1st(source
);
7277 /* Control is entering c's frame, so collect guards from there
7278 towards root. Again it's lowest first. */
7279 pko entering_lo1st
= get_guards_lo1st(destination
);
7281 /* Remove identical entries from the top, thus removing any merged
7283 while((exiting_lo1st
!= K_NIL
) &&
7284 (entering_lo1st
!= K_NIL
) &&
7285 (cont_dump(car(exiting_lo1st
)) == cont_dump(car(entering_lo1st
))))
7287 exiting_lo1st
= cdr(exiting_lo1st
);
7288 entering_lo1st
= cdr(entering_lo1st
);
7293 /*** Construct a string of calls to the appropriate guards, ending
7294 at destination. We collect in the reverse of the order that
7295 they will be run, so collect from "entering" first, from
7296 highest to lowest, then collect from "exiting", from lowest to
7299 _kt_spagstack prox_dest
= destination
;
7301 pko entering_hi1st
= reverse(sc
, entering_lo1st
);
7302 prox_dest
= add_guard_chain(prox_dest
, entering_hi1st
, destination
, 0);
7303 prox_dest
= add_guard_chain(prox_dest
, exiting_lo1st
, source
, 1);
7305 invoke_continuation(sc
, mk_continuation(prox_dest
), value
);
7306 return value
; /* NOTREACHED */
7311 SIG_CHKARRAY(call_cc
) = { REF_OPER(is_combiner
), };
7312 DEF_SIMPLE_APPLICATIVE(ps0a1
,call_cc
,0,ground
, "call/cc")
7314 WITH_1_ARGS(combiner
);
7315 pko cc
= current_continuation(sc
);
7316 return kernel_eval_aux(sc
,combiner
,LIST1(cc
),sc
->envir
);
7318 /*_ , extend-continuation */
7319 /*_ . extend_continuation_aux */
7321 extend_continuation_aux(_kt_spagstack old_frame
, pko a
, pko env
)
7323 _kt_spagstack frame
= klink_push_cont_aux(old_frame
, a
, env
);
7324 return mk_continuation(frame
);
7326 /*_ . extend_continuation */
7327 SIG_CHKARRAY(extend_continuation
) =
7328 { REF_OPER(is_continuation
),
7329 REF_OPER(is_applicative
),
7330 REF_KEY(K_TYCH_OPTIONAL
),
7331 REF_OPER(is_environment
),
7333 DEF_SIMPLE_APPLICATIVE(ps0a3
, extend_continuation
,T_NO_K
,ground
, "extend-continuation")
7335 WITH_3_ARGS(c
, a
, env
);
7336 assert(is_applicative(a
));
7337 if(env
== K_INERT
) { env
= make_new_frame(K_NIL
); }
7338 return extend_continuation_aux(cont_dump(c
), unwrap(sc
,a
), env
);
7340 /*_ , continuation->applicative */
7341 SIG_CHKARRAY(continuation_to_applicative
) = { REF_OPER(is_continuation
), };
7342 DEF_SIMPLE_APPLICATIVE(p00a1
,continuation_to_applicative
,T_NO_K
,ground
, "continuation->applicative")
7346 wrap(mk_curried (dcrry_2A01VLL
, LIST1(c
), REF_OPER(continue_abnormally
)));
7349 /*_ , guard-continuation */
7350 /* Each guard list is repeat (list continuation applicative) */
7351 /* We'd like to spec that applicative take 2 args, a continuation and
7352 a value, and be wrapped exactly once. */
7353 SIG_CHKARRAY(guard_continuation
) =
7354 { K_ANY
, REF_OPER(is_continuation
), K_ANY
, };
7355 DEF_SIMPLE_APPLICATIVE(ps0a3
,guard_continuation
,T_NO_K
,ground
, "guard-continuation")
7357 WITH_3_ARGS(entry_guards
, c
, exit_guards
);
7358 /* The spec wants an outer continuation to keeps sets of guards from
7359 being mixed together if there are two calls to guard_continuation
7360 with the same c. But that happens naturally here, so it seems
7363 /* $$IMPROVE ME Copy the es of both lists of guards. */
7364 _kt_spagstack frame
= cont_dump(c
);
7365 if(entry_guards
!= K_NIL
)
7367 frame
= klink_push_guards(frame
, entry_guards
, sc
->envir
, 0);
7369 if(exit_guards
!= K_NIL
)
7371 frame
= klink_push_guards(frame
, exit_guards
, sc
->envir
, 1);
7374 pko inner_cont
= mk_continuation(frame
);
7378 /*_ , guard-dynamic-extent */
7379 SIG_CHKARRAY(guard_dynamic_extent
) =
7381 REF_OPER(is_finite_list
),
7382 REF_OPER(is_applicative
),
7383 REF_OPER(is_finite_list
),
7385 /* DOES NOT RETURN */
7386 DEF_SIMPLE_APPLICATIVE(ps0a3
,guard_dynamic_extent
,0,ground
, "guard-dynamic-extent")
7388 WITH_3_ARGS(entry
,app
,exit
);
7389 pko cont
= guard_continuation(sc
,entry
,current_continuation(sc
),exit
);
7390 pko cont2
= extend_continuation(sc
,cont
, app
, sc
->envir
);
7391 /* Skip directly into the new continuation, don't invoke the
7393 invoke_continuation(sc
,cont2
, K_NIL
);
7398 /*_ , Keyed dynamic bindings */
7399 /*_ . klink_kdb_binder */
7400 SIG_CHKARRAY(klink_kdb_binder
) =
7401 { REF_OPER(is_key
), K_ANY
, REF_OPER(is_combiner
), };
7402 DEF_SIMPLE_CFUNC(ps0a3
,klink_kdb_binder
,T_NO_K
)
7404 WITH_3_ARGS(key
, value
, combiner
);
7405 /* Check that combiner is in fact a combiner. */
7406 if(!is_combiner(combiner
))
7409 "klink_kdb_binder: Arg 2 must be a combiner: ",
7412 /* Push the new binding. */
7413 klink_push_dyn_binding(sc
, key
, value
);
7414 /* $$IMPROVE ME In general, should can control calling better than
7415 this. Possibly do this thru invoke_continuation, except we're
7416 not arbitrarily changing continuations. */
7417 /* $$IMPROVE ME Want a better way to control what environment to
7418 push in. In fact, that's much like a dynamic variable. */
7419 /* $$IMPROVE ME Want a better and cheaper way to make empty
7420 environments. The vector thing should be controlled by a hint. */
7421 /* Make an empty static environment */
7422 new_frame_in_env(sc
,K_NIL
);
7423 /* Push combiner in that environment. */
7424 klink_push_cont(sc
,combiner
);
7425 /* And call it with no operands. */
7428 /* Combines with data to become "an applicative that takes two
7429 arguments, the second of which must be a oper. It calls its
7430 second argument with no operands (nil operand tree) in a fresh empty
7431 environment, and returns the result." */
7432 /*_ . klink_kdb_accessor */
7433 SIG_CHKARRAY(klink_kdb_accessor
) =
7434 { REF_OPER(is_key
), };
7435 DEF_SIMPLE_CFUNC(ps0a1
,klink_kdb_accessor
,T_NO_K
)
7438 pko value
= klink_find_dyn_binding(sc
,key
);
7441 KERNEL_ERROR_0(sc
, "klink_kdb_accessor: No binding found");
7445 /* Combines with data to become "an applicative that takes zero
7446 arguments. If the call to a occurs within the dynamic extent of a
7447 call to b, then a returns the value of the first argument passed to
7448 b in the smallest enclosing dynamic extent of a call to b. If the
7449 call to a is not within the dynamic extent of any call to b, an
7452 /*_ . make_keyed_dynamic_variable */
7453 RGSTR(ground
, "make-keyed-dynamic-variable", REF_OPER(make_keyed_dynamic_variable
))
7455 DEF_CFUNC(p00a0
, make_keyed_dynamic_variable
,K_NO_TYPE
,T_NO_K
)
7457 return make_keyed_variable(
7458 REF_OPER(klink_kdb_binder
),
7459 REF_OPER (klink_kdb_accessor
));
7464 typedef struct profiling_data
7472 profiling_data
* entries
;
7476 /*_ . Current data */
7477 /* This may be moved to per interpreter, or even more fine-grained. */
7478 /* This may not always be the way we get elapsed counts. */
7479 static long k_profiling_count
= 0;
7480 static int k_profiling_p
= 0; /* Are we profiling now? */
7481 /* If we are profiling, init this if it's not initted */
7482 static kt_profile_table k_profiling_table
= { 0 };
7483 /*_ . Dealing with table (All will be shared with other lookup tables) */
7486 init_profile_table(kt_profile_table
* p_table
, int initial_size
)
7488 p_table
->objs
= initial_size
?
7489 GC_MALLOC(sizeof(pko
) * initial_size
) : 0;
7490 p_table
->entries
= initial_size
?
7491 GC_MALLOC(sizeof(profiling_data
) * initial_size
) : 0;
7492 p_table
->alloced_size
= initial_size
;
7493 p_table
->table_size
= 0;
7495 /*_ , Increase its size */
7497 enlarge_profile_table(kt_profile_table
* p_table
)
7499 if(p_table
->table_size
== p_table
->alloced_size
)
7501 p_table
->alloced_size
*= 2;
7502 p_table
->entries
= GC_REALLOC(p_table
->entries
, sizeof(profiling_data
) * p_table
->alloced_size
);
7503 p_table
->objs
= GC_REALLOC(p_table
->objs
, sizeof(pko
) * p_table
->alloced_size
);
7508 /*_ , Searching in it */
7509 /* Use objtable_get_index */
7510 /*_ . On the stack */
7511 static struct stack_profiling
*
7512 klink_find_profile_in_frame (_kt_spagstack frame
, pko ff
)
7515 (frame
!= 0) && (frame
->type
!= ksct_frame
) ;
7516 frame
= frame
->next
)
7518 if(frame
->type
== ksct_profile
)
7520 struct stack_profiling
*pdata
= &frame
->data
.profiling
;
7521 if(pdata
->ff
== ff
) { return pdata
; }
7526 /*_ . Profile collection operations */
7527 /*_ , When eval loop steps */
7529 k_profiling_step(void)
7530 { k_profiling_count
++; }
7531 /*_ , When we begin executing a frame */
7532 /* Push a stack_profiling cell onto the frame. */
7535 k_profiling_new_frame(klink
* sc
, pko ff
)
7537 if(!k_profiling_p
) { return; }
7538 if(!is_operative(ff
)) { return; }
7539 /* Do this only if ff is interesting (which for the moment means
7540 that it can be found in ground environment). */
7541 if(!reverse_binds_p(ff
, ground_env
) &&
7542 !reverse_binds_p(ff
, print_lookup_unwraps
) &&
7543 !reverse_binds_p(ff
, print_lookup_to_xary
))
7545 struct stack_profiling
* found_profile
=
7546 klink_find_profile_in_frame (sc
->dump
, ff
);
7547 /* If the same combiner is already being profiled in this frame,
7548 don't add another copy. */
7551 /* $$IMPROVE ME Count tail calls */
7555 /* Push a profiling frame */
7556 _kt_spagstack old_frame
= sc
->dump
;
7557 _kt_spagstack frame
=
7559 GC_MALLOC (sizeof (dump_stack_frame_cell
));
7560 struct stack_profiling
* pdata
= &frame
->data
.profiling
;
7562 pdata
->initial_count
= k_profiling_count
;
7563 pdata
->returned_p
= 0;
7564 frame
->type
= ksct_profile
;
7565 frame
->next
= old_frame
;
7570 /*_ , When we pop a stack_profiling cell */
7572 k_profiling_done_frame(klink
* sc
, struct stack_profiling
* profile
)
7574 if(!k_profiling_p
) { return; }
7575 profiling_data
* pdata
= 0;
7576 pko ff
= profile
->ff
;
7578 /* This stack_profiling cell is popped past but it might be used
7579 again if we re-enter, so mark it accordingly. */
7580 profile
->returned_p
= 1;
7581 if(k_profiling_table
.alloced_size
== 0)
7582 { init_profile_table(&k_profiling_table
, 8); }
7585 int index
= objtable_get_index(k_profiling_table
.objs
, k_profiling_table
.table_size
, ff
);
7587 { pdata
= &k_profiling_table
.entries
[index
]; }
7590 /* Create it if needed */
7593 /* Increase size as needed */
7594 enlarge_profile_table(&k_profiling_table
);
7596 const int index
= k_profiling_table
.table_size
;
7597 k_profiling_table
.objs
[index
] = ff
;
7598 k_profiling_table
.table_size
++;
7599 pdata
= &k_profiling_table
.entries
[index
];
7600 /* Initialize it here */
7601 pdata
->num_calls
= 0;
7602 pdata
->num_evalloops
= 0;
7605 /* Add to its counts: Num calls. Num eval-loops taken. */
7607 pdata
->num_evalloops
+= k_profiling_count
- profile
->initial_count
;
7610 /*_ , Turn profiling on */
7611 /* Maybe better as a command-line switch or binder. */
7612 SIG_CHKARRAY(profiling
) = { REF_OPER(is_integer
), };
7613 DEF_SIMPLE_APPLICATIVE (ps0a1
, profiling
,T_NO_K
,ground
, "profiling")
7615 WITH_1_ARGS(profile_p
);
7616 int pr
= k_profiling_p
;
7617 k_profiling_p
= ivalue (profile_p
);
7618 return mk_integer (pr
);
7621 /*_ , Dumping profiling data */
7622 /* Return a list of the profiled combiners. */
7623 DEF_APPLICATIVE_W_DESTR(ps0a0
,get_profiling_data
,K_NO_TYPE
,T_NO_K
,ground
,"get-profiling-data")
7626 pko result_list
= K_NIL
;
7627 for(index
= 0; index
< k_profiling_table
.table_size
; index
++)
7629 pko ff
= k_profiling_table
.objs
[index
];
7630 profiling_data
* pdata
= &k_profiling_table
.entries
[index
];
7632 /* Element format: (object num-calls num-evalloops) */
7635 mk_integer(pdata
->num_calls
),
7636 mk_integer(pdata
->num_evalloops
)),
7639 /* Don't care about order so no need to reverse the list. */
7642 /*_ . Reset profiling data */
7643 /*_ , Alternative definitions for no profiling */
7645 #define k_profiling_step()
7646 #define k_profiling_new_frame(DUMMY, DUMMY2)
7648 /*_ . Error handling */
7649 /*_ , _klink_error_1 */
7651 _klink_error_1 (klink
* sc
, const char *s
, pko a
)
7654 const char *str
= s
;
7655 char sbuf
[STRBUFFSIZE
];
7656 pko the_inport
= klink_find_dyn_binding(sc
,K_INPORT
);
7657 if (the_inport
&& (the_inport
!= K_NIL
))
7659 port
* pt
= portvalue(the_inport
);
7660 /* Make sure error is not in REPL */
7661 if((pt
->kind
& port_file
) && (pt
->rep
.stdio
.file
!= stdin
))
7663 /* Count is 0-based but print it 1-based. */
7664 int ln
= pt
->rep
.stdio
.curr_line
+ 1;
7665 const char *fname
= pt
->rep
.stdio
.filename
;
7668 { fname
= "<unknown>"; }
7670 snprintf (sbuf
, STRBUFFSIZE
, "(%s : %i) %s", fname
, ln
, s
);
7672 str
= (const char *) sbuf
;
7676 const char *str
= s
;
7680 pko err_string
= mk_string (str
);
7683 err_arg
= mcons (a
, K_NIL
);
7689 err_arg
= mcons (err_string
, err_arg
);
7690 invoke_continuation (sc
, sc
->error_continuation
, err_arg
);
7696 /*_ , Default cheap error handlers */
7698 DEF_CFUNC (ps0a1
, kernel_err
, K_ANY
,0)
7703 putstr (sc
, "Error with no arguments. I know nut-ting!");
7706 if(!is_finite_list(arg1
))
7708 putstr (sc
, "kernel_err: arg must be a finite list");
7712 assert(is_pair(arg1
));
7713 int got_string
= is_string (car (arg1
));
7714 pko args_x
= got_string
? cdr (arg1
) : arg1
;
7715 const char *message
= got_string
? string_value (car (arg1
)) : " -- ";
7717 putstr (sc
, "Error: ");
7718 putstr (sc
, message
);
7719 return kernel_err_x (sc
, args_x
);
7722 /*_ . kernel_err_x */
7723 DEF_CFUNC (ps0a1
, kernel_err_x
, K_ANY_SINGLETON
,0)
7730 assert(is_pair(args
));
7731 CONTIN_1 (dcrry_1dotALL
, kernel_err_x
, sc
, cdr (args
));
7732 klink_push_dyn_binding(sc
,K_PRINT_FLAG
,K_T
);
7733 CONTIN_1 (dcrry_1dotALL
, kernel_print_sexp
, sc
, car (args
));
7742 /*_ . kernel_err_return */
7743 DEF_CFUNC(ps0a1
,kernel_err_return
, K_ANY
,0)
7745 /* This should not set sc->done, because when it's called it still
7746 must print the error, which may require more eval loops. */
7748 return kernel_err(sc
, arg1
);
7752 DEF_APPLICATIVE_W_DESTR(ps0a1
,error
,K_ANY
,0,ground
,"error")
7754 WITH_1_ARGS(err_arg
);
7755 invoke_continuation (sc
, sc
->error_continuation
, err_arg
);
7756 return 0; /* NOTREACHED */
7758 /*_ . error-descriptor? */
7759 /* $$WRITE ME TO replace the punted version */
7761 /*_ . Support for calling C functions */
7763 /*_ , klink_call_cfunc_aux */
7765 klink_call_cfunc_aux (klink
* sc
, const kt_cfunc
* p_cfunc
, pko
* arg_array
)
7767 switch (p_cfunc
->type
)
7769 /* For these macros, the arglist is parenthesized so is
7772 /* ***************************************** */
7773 /* For function types returning bool as int (bXXaX) */
7774 #define CASE_CFUNCTYPE_bX(SUFFIX,ARGLIST) \
7775 case klink_ftype_##SUFFIX: \
7776 return kernel_bool(p_cfunc->func.f_##SUFFIX ARGLIST)
7778 CASE_CFUNCTYPE_bX (b00a1
, (arg_array
[0]));
7779 CASE_CFUNCTYPE_bX (b00a2
, (arg_array
[0], arg_array
[1]));
7780 CASE_CFUNCTYPE_bX (bs0a2
, (sc
, arg_array
[0], arg_array
[1]));
7782 #undef CASE_CFUNCTYPE_bX
7785 /* ***************************************** */
7786 /* For function types returning pko (pXXaX) */
7787 #define CASE_CFUNCTYPE_pX(SUFFIX,ARGLIST) \
7788 case klink_ftype_##SUFFIX: \
7789 return p_cfunc->func.f_##SUFFIX ARGLIST
7791 CASE_CFUNCTYPE_pX (p00a0
, ());
7792 CASE_CFUNCTYPE_pX (p00a1
, (arg_array
[0]));
7793 CASE_CFUNCTYPE_pX (p00a2
, (arg_array
[0], arg_array
[1]));
7794 CASE_CFUNCTYPE_pX (p00a3
, (arg_array
[0], arg_array
[1], arg_array
[2]));
7796 CASE_CFUNCTYPE_pX (ps0a0
, (sc
));
7797 CASE_CFUNCTYPE_pX (ps0a1
, (sc
, arg_array
[0]));
7798 CASE_CFUNCTYPE_pX (ps0a2
, (sc
, arg_array
[0], arg_array
[1]));
7799 CASE_CFUNCTYPE_pX (ps0a3
, (sc
, arg_array
[0], arg_array
[1], arg_array
[2]));
7800 CASE_CFUNCTYPE_pX (ps0a4
, (sc
, arg_array
[0], arg_array
[1],
7801 arg_array
[2], arg_array
[3]));
7802 CASE_CFUNCTYPE_pX (ps0a5
, (sc
, arg_array
[0], arg_array
[1], arg_array
[2], arg_array
[3], arg_array
[4]));
7804 #undef CASE_CFUNCTYPE_pX
7807 /* ***************************************** */
7808 /* For function types returning void (vXXaX) */
7809 #define CASE_CFUNCTYPE_vX(SUFFIX,ARGLIST) \
7810 case klink_ftype_##SUFFIX: \
7811 p_cfunc->func.f_##SUFFIX ARGLIST; \
7814 CASE_CFUNCTYPE_vX (vs0a2
, (sc
, arg_array
[0], arg_array
[1]));
7815 CASE_CFUNCTYPE_vX (vs0a3
, (sc
, arg_array
[0], arg_array
[1], arg_array
[2]));
7817 #undef CASE_CFUNCTYPE_vX
7821 "kernel_call: About that function type, I know nut-ting!");
7824 /*_ , klink_call_cfunc */
7826 klink_call_cfunc (klink
* sc
, pko functor
, pko env
, pko args
)
7828 const kt_cfunc
* p_cfunc
= get_cfunc_func (functor
);
7829 assert(p_cfunc
->argcheck
);
7830 const int max_args
= destructure_how_many (p_cfunc
->argcheck
);
7831 pko arg_array
[max_args
];
7832 destructure_to_array(sc
,args
,
7836 REF_OPER (k_resume_to_cfunc
),
7838 return klink_call_cfunc_aux (sc
, p_cfunc
, arg_array
);
7840 /*_ , k_resume_to_cfunc */
7841 SIG_CHKARRAY (k_resume_to_cfunc
) =
7843 REF_OPER (is_destr_result
),
7844 REF_KEY (K_TYCH_DOT
),
7845 REF_OPER (is_cfunc
),
7847 DEF_SIMPLE_CFUNC (ps0a2
, k_resume_to_cfunc
, 0)
7849 WITH_2_ARGS (destr_result
, functor
);
7850 assert_type (0, functor
, T_CFUNC
);
7851 const int max_args
= 5;
7852 pko arg_array
[max_args
];
7853 destr_result_fill_array (destr_result
, max_args
, arg_array
);
7854 return klink_call_cfunc_aux (sc
, get_cfunc_func (functor
), arg_array
);
7856 /*_ . Some decurriers */
7858 dcrry_2A01VLL (klink
* sc
, pko args
, pko value
)
7861 return LIST2(car (args
), value
);
7863 static pko
dcrry_3A01dotVLL (klink
* sc
, pko args
, pko value
)
7866 return cons (car (args
), value
);
7869 dcrry_2CA01VLLA02 (klink
* sc
, pko args
, pko value
)
7872 return LIST2( cons (car (args
), value
), cadr (args
));
7874 /* May not be needed */
7876 dcrry_3A01A02VLL (klink
* sc
, pko args
, pko value
)
7879 return LIST3(car (args
), cadr (args
), value
);
7882 dcrry_2ALLVLL (klink
* sc
, pko args
, pko value
)
7884 return LIST2(args
, value
);
7886 static pko
dcrry_2ALLV01 (klink
* sc
, pko args
, pko value
)
7889 return LIST2(args
, car (value
));
7893 dcrry_NCVLLA01dotAX1 (klink
* sc
, pko args
, pko value
)
7896 return cons(cons (value
, car (args
)), cdr (args
));
7898 static pko
dcrry_NdotALL (klink
* sc
, pko args
, pko value
)
7901 static pko
dcrry_1ALL (klink
* sc
, pko args
, pko value
)
7902 { return cons( args
, K_NIL
); }
7904 static pko
dcrry_5ALLdotVLL (klink
* sc
, pko args
, pko value
)
7905 { return cons (args
, value
); }
7907 static pko
dcrry_NVLLdotALL (klink
* sc
, pko args
, pko value
)
7908 { return cons (value
, args
); }
7911 dcrry_1VLL (klink
* sc
, pko args
, pko value
)
7912 { return LIST1 (value
); }
7915 /*_ , Internal functions */
7916 /*_ . kernel_define_tree_aux */
7918 kernel_define_tree_aux
7919 (klink
* sc
, pko value
, pko formal
, pko env
, pko
* extra_result
)
7922 if (is_pair (formal
))
7924 if (is_pair (value
))
7926 kt_destr_outcome outcome
=
7927 kernel_define_tree_aux (sc
, car (value
), car (formal
), env
,
7932 /* $$IMPROVE ME On error, give a more accurate position. */
7934 kernel_define_tree_aux (sc
, cdr (value
), cdr (formal
), env
,
7938 case destr_must_call_k
:
7939 /* $$IMPROVE ME Also schedule to resume the cdr */
7940 /* Operations to run, in reverse order. */
7944 REF_OPER (kernel_define_tree
),
7945 /* V= (value formal env) */
7946 mk_load (LIST3 (cdr (value
),
7950 return destr_must_call_k
;
7952 errx (7, "Unrecognized enumeration");
7955 if (is_promise (value
))
7957 /* Operations to run, in reverse order. */
7961 REF_OPER (kernel_define_tree
),
7962 /* V= (forced-value formal env) */
7963 mk_load (LIST3 (mk_load_ix (0, 0),
7966 mk_store (K_ANY
, 1),
7967 /* V= forced-argobject */
7970 mk_load (LIST1 (value
)));
7971 return destr_must_call_k
;
7976 "kernel_define_tree: value must be a pair: ", value
);
7977 return destr_err
; /* NOTREACHED */
7980 /* We can encounter NIL at the end of a non-dotted list, so mustn't
7981 try to bind it, and value list must end here too. */
7982 else if (formal
== K_NIL
)
7987 "kernel_define_tree: too many args: ", value
);
7988 return destr_err
; /* NOTREACHED */
7990 return destr_success
;
7992 /* If formal is #ignore, don't try to bind it, do nothing. */
7993 else if (formal
== K_IGNORE
)
7995 return destr_success
;
7997 /* If it's a symbol, bind it. Even a promise is bound thus. */
7998 else if (is_symbol (formal
))
8000 kernel_define (env
, formal
, value
);
8001 return destr_success
;
8006 "kernel_define_tree: can't bind to: ", formal
);
8007 return destr_err
; /* NOTREACHED */
8010 /*_ . kernel_define_tree */
8011 /* This can no longer be assumed to be T_NO_K, in case promises must
8013 SIG_CHKARRAY(kernel_define_tree
) =
8014 { K_ANY
, K_ANY
, REF_OPER(is_environment
), };
8015 DEF_SIMPLE_CFUNC(vs0a3
,kernel_define_tree
,0)
8017 WITH_3_ARGS(value
, formal
, env
);
8019 kt_destr_outcome outcome
=
8020 kernel_define_tree_aux(sc
, value
, formal
, env
, &extra_result
);
8026 /* Later this may raise the error */
8028 case destr_must_call_k
:
8029 schedule_rv_list (sc
, extra_result
);
8032 errx (7, "Unrecognized enumeration");
8035 /*_ . kernel_define */
8036 SIG_CHKARRAY(kernel_define
) =
8038 REF_OPER(is_environment
),
8039 REF_OPER(is_symbol
),
8042 DEF_SIMPLE_CFUNC(p00a3
,kernel_define
,T_NO_K
)
8044 WITH_3_ARGS(env
, symbol
, value
);
8045 assert(is_symbol(symbol
));
8046 pko x
= find_slot_in_env (env
, symbol
, 0);
8049 set_slot_in_env (x
, value
);
8053 new_slot_spec_in_env (env
, symbol
, value
);
8057 void klink_define (klink
* sc
, pko symbol
, pko value
)
8058 { kernel_define(sc
->envir
,symbol
,value
); }
8060 /*_ , Supporting kernel registerables */
8061 /*_ . eval_define */
8062 RGSTR(ground
, "$define!", REF_OPER(eval_define
))
8063 SIG_CHKARRAY(eval_define
) =
8065 DEF_SIMPLE_CFUNC(ps0a2
,eval_define
,0)
8067 pko env
= sc
->envir
;
8068 WITH_2_ARGS(formal
, expr
);
8069 CONTIN_2(dcrry_3VLLdotALL
,kernel_define_tree
,sc
,formal
,env
);
8070 /* Using args functionality:
8076 RUN, in reverse order
8077 kernel_define_tree (CONTIN_0)
8078 make arglist from 3 args ($$WRITE MY SUPPORT) - or from 2 args and value.
8079 (The 2 slots will go here)
8080 put return value in new slot ($$WRITE MY SUPPORT)
8084 Possibly "make arglist" will be an array of integers, -1 meaning
8085 the current value. And on its own it could do decurrying.
8087 return kernel_eval(sc
,expr
,env
);
8090 RGSTR(ground
, "$set!", REF_OPER(set
))
8092 { K_ANY
, K_ANY
, K_ANY
, };
8093 DEF_SIMPLE_CFUNC(ps0a3
,set
,0)
8095 pko env
= sc
->envir
;
8096 WITH_3_ARGS(env_expr
, formal
, expr
);
8097 /* Using args functionality:
8099 RUN, in reverse order
8100 kernel_define_tree (CONTIN_0)
8101 make arglist from 3 args - or from 2 args and value.
8102 put return value in new slot
8104 make arglist from 1 arg
8107 put return value in new slot
8109 expr (Passed directly)
8113 CONTIN_0(kernel_define_tree
,sc
);
8115 kernel_mapeval(sc
, K_NIL
,
8117 LIST2(REF_OPER (arg1
), formal
),
8122 /*_ . Misc Kernel functions */
8125 SIG_CHKARRAY(tracing
) = { REF_OPER(is_integer
), };
8126 DEF_SIMPLE_APPLICATIVE (ps0a1
, tracing
,T_NO_K
,ground
, "tracing")
8128 WITH_1_ARGS(trace_p
);
8129 int tr
= sc
->tracing
;
8130 sc
->tracing
= ivalue (trace_p
);
8131 return mk_integer (tr
);
8134 /*_ , new_tracing */
8136 SIG_CHKARRAY(new_tracing
) = { REF_OPER(is_integer
), };
8137 DEF_SIMPLE_APPLICATIVE (ps0a1
, new_tracing
,T_NO_K
,ground
, "new-tracing")
8139 WITH_1_ARGS(trace_p
);
8140 int tr
= sc
->new_tracing
;
8141 sc
->new_tracing
= ivalue (trace_p
);
8142 return mk_integer (tr
);
8146 /*_ , get-current-environment */
8147 DEF_APPLICATIVE_W_DESTR (ps0a0
, get_current_environment
, K_NO_TYPE
,T_NO_K
,ground
, "get-current-environment")
8148 { return sc
->envir
; }
8150 /*_ , arg1, $quote, list */
8151 DEF_APPLICATIVE_W_DESTR (ps0a1
, arg1
, K_ANY_SINGLETON
,T_NO_K
,ground
, "identity")
8156 /* Same, unwrapped */
8157 RGSTR(ground
, "$quote", REF_OPER(arg1
))
8160 RGSTR(ground
, "list", REF_APPL(val2val
))
8161 /* The underlying C function here is "arg1", but it's called with
8162 the whole argobject as arg1 */
8163 /* K_ANY instead of REF_OPER(is_finite_list) because we deliberately allow
8164 non-lists and improper lists. */
8165 DEF_CFUNC_RAW(OPER(val2val
),ps0a1
,arg1
,K_ANY
,T_NO_K
);
8166 DEF_BOXED_APPLICATIVE(val2val
, REF_OPER (val2val
));
8169 RGSTR(ground
,"exit",REF_OPER(k_quit
))
8170 DEF_CFUNC(ps0a0
,k_quit
,K_NO_TYPE
,0)
8172 if(!nest_depth_ok_p(sc
))
8173 { sc
->retcode
= 1; }
8176 return K_INERT
; /* Value is unused anyways */
8179 RGSTR(ground
,"gc",REF_OPER(k_gc
))
8180 DEF_CFUNC(ps0a0
,k_gc
,K_NO_TYPE
,0)
8188 RGSTR(ground
, "$if", REF_OPER(k_if
))
8189 FORWARD_DECL_CFUNC(static,ps0a3
,k_if_literal
);
8190 SIG_CHKARRAY(k_if
) = { K_ANY
, K_ANY
, K_ANY
, };
8191 DEF_SIMPLE_DESTR( k_if
);
8194 /* Store (test consequent alternative) */
8195 ANON_STORE(REF_DESTR(k_if
)),
8197 ANON_LOAD(ANON_LIST1(ANON_LOAD_IX( 0, 0 ))),
8198 /* value = (test) */
8200 REF_OPER(kernel_eval
),
8202 /* Store (test_result) */
8205 ANON_LOAD(ANON_LIST3(ANON_LOAD_IX( 0, 0 ),
8206 ANON_LOAD_IX( 1, 1 ),
8207 ANON_LOAD_IX( 1, 2 ))),
8209 /* test_result, consequent, alternative */
8210 REF_OPER(k_if_literal
),
8213 DEF_SIMPLE_CHAIN(k_if
);
8215 SIG_CHKARRAY(k_if_literal
) = { REF_OPER(is_bool
), K_ANY
, K_ANY
, };
8216 DEF_SIMPLE_CFUNC(ps0a3
,k_if_literal
,0)
8218 WITH_3_ARGS(test
, consequent
, alternative
);
8219 if(test
== K_T
) { return kernel_eval(sc
, consequent
, sc
->envir
); }
8220 if(test
== K_F
) { return kernel_eval(sc
, alternative
, sc
->envir
); }
8221 KERNEL_ERROR_1(sc
,"Must be a boolean: ", test
);
8224 /*_ . Routines for applicatives */
8225 BOX_OF_VOID (K_APPLICATIVE
);
8227 DEF_SIMPLE_PRED (is_applicative
,T_NO_K
,ground
, "applicative?/o1")
8230 return is_encap (REF_KEY(K_APPLICATIVE
), p
);
8233 DEF_SIMPLE_PRED (is_combiner
,T_NO_K
,ground
, "combiner?/o1")
8236 return is_applicative(p
) || is_operative(p
);
8239 SIG_CHKARRAY(wrap
) = { REF_OPER(is_combiner
) };
8240 DEF_SIMPLE_APPLICATIVE (p00a1
, wrap
,T_NO_K
,ground
, "wrap")
8243 return mk_encap (REF_KEY(K_APPLICATIVE
), p
);
8246 SIG_CHKARRAY(unwrap
) = { REF_OPER(is_applicative
) };
8247 DEF_SIMPLE_APPLICATIVE (ps0a1
, unwrap
,T_NO_K
,ground
, "unwrap")
8250 return unencap (sc
, REF_KEY(K_APPLICATIVE
), p
);
8253 SIG_CHKARRAY(unwrap_all
) = { REF_OPER(is_combiner
) };
8254 DEF_SIMPLE_APPLICATIVE (p00a1
, unwrap_all
,T_NO_K
,ground
, "unwrap-all")
8257 /* Wrapping does not allowing circular wrapping, so this will
8259 while(is_encap (REF_KEY(K_APPLICATIVE
), p
))
8260 { p
= unencap (0, REF_KEY(K_APPLICATIVE
), p
); }
8266 /*_ , is_operative */
8267 /* This can be hacked quicker by suppressing 1 more bit and testing
8268 * just once. Requires keeping those T_ types co-ordinated, though. */
8269 DEF_SIMPLE_PRED (is_operative
,T_NO_K
,ground
, "operative?/o1")
8273 is_type (p
, T_CFUNC
)
8274 || is_type (p
, T_CFUNC_RESUME
)
8275 || is_type (p
, T_CURRIED
)
8276 || is_type (p
, T_LISTLOOP
)
8277 || is_type (p
, T_CHAIN
)
8278 || is_type (p
, T_STORE
)
8279 || is_type (p
, T_LOAD
)
8280 || is_type (p
, T_TYPEP
);
8284 RGSTR(simple
, "$vau/3", REF_OPER(vau_1
))
8286 /* This is a simple vau for bootstrap. It handles just a single
8287 expression. It's in ground for now, but will be only in
8288 low-for-optimization later */
8290 /* $$IMPROVE ME Check that formals is a non-circular list with no
8291 duplicated symbols. If this check is typical for
8292 kernel_define_tree (probably), pass that an initially blank
8293 environment and it can check for symbols and error if they are
8296 eformal is almost REF_OPER(is_symbol) but must accept #ignore also.
8298 SIG_CHKARRAY(vau_1
) = { K_ANY
, K_ANY
, K_ANY
};
8299 DEF_SIMPLE_CFUNC (ps0a3
, vau_1
,0)
8301 pko env
= sc
->envir
;
8302 WITH_3_ARGS(formals
, eformal
, expression
);
8303 /* This defines a vau object. Evaluating it is different.
8306 /* $$IMPROVE ME Could compile the expression now, but that's not so
8307 easy in Kernel. At least make a hook for that. */
8309 /* Vau data is a list of the 4 things:
8310 The dynamic environment
8312 An immutable copy of the formals es
8313 An immutable copy of the expression
8315 $$IMPROVE ME Make not a list but a dedicated struct.
8320 copy_es_immutable(sc
, formals
),
8321 copy_es_immutable (sc
, expression
));
8323 mk_curried (dcrry_5VLLdotALL
, vau_data
, REF_OPER (eval_vau
));
8326 /*_ . Evaluation, Kernel style */
8327 /*_ , Calling operatives */
8329 /* Again, can't simply say REF_OPER(is_symbol) because it might be
8331 SIG_CHKARRAY(eval_vau
) =
8333 REF_OPER(is_environment
),
8337 DEF_SIMPLE_CFUNC (ps0a5
, eval_vau
,0)
8339 pko env
= sc
->envir
;
8340 WITH_5_ARGS(args
, old_env
, eformal
, formals
, expression
);
8342 /* Make a new environment, child of the static environment (which
8343 we get now while making the vau) and put it into the envir
8345 new_frame_in_env (sc
, old_env
);
8347 /* This will change in kernel_define, not here. */
8348 /* Bind the dynamic environment to the eformal symbol. */
8349 kernel_define_tree (sc
, env
, eformal
, sc
->envir
);
8351 /* Bind the formals (symbols) to the operands (values) treewise. */
8353 kt_destr_outcome outcome
=
8354 kernel_define_tree_aux(sc
, args
, formals
, sc
->envir
, &extra_result
);
8360 /* Later this may raise the error */
8362 case destr_must_call_k
:
8363 CONTIN_2 (dcrry_2dotALL
, kernel_eval
, sc
, expression
, sc
->envir
);
8364 schedule_rv_list (sc
, extra_result
);
8367 errx (7, "Unrecognized enumeration");
8370 /* Evaluate the expression. */
8371 return kernel_eval (sc
, expression
, sc
->envir
);
8374 /*_ , Kernel eval mutual callers */
8375 /*_ . kernel_eval */
8377 /* Optionally define a tracing kernel_eval */
8378 SIG_CHKARRAY(kernel_eval
) = { K_ANY
, REF_KEY(K_TYCH_OPTIONAL
), REF_OPER(is_environment
), };
8379 DEF_SIMPLE_DESTR(kernel_eval
);
8381 FORWARD_DECL_CFUNC(static,ps0a2
,kernel_real_eval
);
8382 DEF_APPLICATIVE_W_DESTR (ps0a2
, kernel_eval
, REF_DESTR(kernel_eval
),0,ground
, "eval")
8384 WITH_2_ARGS(form
, env
);
8385 /* $$RETHINK ME Set sc->envir here, remove arg from
8386 kernel_real_eval, and the tracing call will know its own env,
8387 it may just be a closure with form as value. */
8394 CONTIN_2 (dcrry_2dotALL
, kernel_real_eval
, sc
, form
, env
);
8395 putstr (sc
, "\nEval: ");
8396 CONTIN_1 (dcrry_1dotALL
, kernel_print_sexp
, sc
, form
);
8401 return kernel_real_eval (sc
, form
, env
);
8406 /* Define either kernel_eval (if not defined above) or kernel_real_eval */
8408 /* $$IMPROVE MY DESIGN Don't like the pointers being different
8409 levels of pointingness. In fact, we always potentially have
8410 tracing (or w/e) so let's lose the preprocessor condition. */
8412 DEF_CFUNC (ps0a2
, kernel_real_eval
, REF_DESTR(kernel_eval
),0)
8414 DEF_APPLICATIVE_W_DESTR (ps0a2
, kernel_eval
, REF_DESTR(kernel_eval
),0,ground
, "eval")
8418 WITH_2_ARGS(form
, env
);
8420 /* Evaluate form in env */
8422 form: form to be evaluated
8423 env: environment to evaluate it in.
8427 /* $$IMPROVE ME Let this be done in kernel_eval and lose the env
8428 argument, here just assert that we have an environment. */
8431 if (is_environment (env
))
8432 { sc
->envir
= env
; }
8435 KERNEL_ERROR_0 (sc
, "eval: Arg 2 must be an environment:");
8439 if (is_symbol (form
))
8441 pko x
= find_slot_in_env (env
, form
, 1);
8444 return slot_value_in_env (x
);
8448 KERNEL_ERROR_1 (sc
, "eval: unbound variable:", form
);
8452 else if (is_pair (form
))
8454 CONTIN_2 (dcrry_3VLLdotALL
, kernel_eval_aux
, sc
, cdr (form
), env
);
8455 return kernel_eval (sc
, car (form
), env
);
8457 /* Otherwise return the object literally. */
8463 /*_ . kernel_eval_aux */
8464 /* The stage of `eval' when we've already decided that we're to use a
8465 combiner and what that combiner is. */
8466 /* $$IMPROVE ME Lose the env argument, it's always sc->envir */
8467 SIG_CHKARRAY(kernel_eval_aux
) =
8468 { REF_OPER(is_combiner
), K_ANY
, REF_OPER(is_environment
), };
8469 DEF_SIMPLE_DESTR(kernel_eval_aux
);
8470 DEF_CFUNC (ps0a3
, kernel_eval_aux
, REF_DESTR(kernel_eval_aux
),0)
8472 WITH_3_ARGS(functor
, args
, env
);
8473 assert (is_environment (env
));
8475 functor: what the car of the form has evaluated to.
8476 args: cdr of form, as yet unevaluated.
8477 env: environment to evaluate in.
8479 k_profiling_new_frame(sc
, functor
);
8480 if(is_type(functor
, T_CFUNC
))
8482 return klink_call_cfunc(sc
, functor
, env
, args
);
8484 else if(is_type(functor
, T_CURRIED
))
8486 return call_curried(sc
, functor
, args
);
8488 else if(is_type(functor
, T_TYPEP
))
8490 /* $$MOVE ME Into something paralleling the other operative calls */
8491 /* $$IMPROVE ME Check arg number */
8494 { KERNEL_ERROR_1 (sc
, "Takes one arg: ", functor
); }
8495 return kernel_bool(call_T_typecheck(functor
,car(args
)));
8497 else if(is_type(functor
, T_LISTLOOP
))
8499 return eval_listloop(sc
, functor
,args
);
8501 else if(is_type(functor
, T_CHAIN
))
8503 return eval_chain( sc
, functor
, args
);
8505 else if ( is_type( functor
, T_STORE
))
8507 return k_do_store( sc
, functor
, args
);
8509 else if ( is_type( functor
, T_LOAD
))
8511 return k_do_load( sc
, functor
, args
);
8513 else if (is_applicative (functor
))
8516 Get the underlying operative.
8517 Evaluate arguments (may make frames)
8518 Use the oper on the arguments
8520 pko oper
= unwrap (sc
, functor
);
8523 get_list_metrics_aux(args
, metrics
);
8524 if(metrics
[lm_cyc_len
] != 0)
8526 KERNEL_ERROR_1 (sc
, "kernel_eval_aux: Arguments must be a list", args
);
8528 sc
->envir
= env
; /* $$IMPROVE ME Treat this cache better */
8529 CONTIN_2 (dcrry_2CA01VLLA02
, kernel_eval
, sc
, oper
, env
);
8533 CONTIN_3 (dcrry_4dotALL
, kernel_mapeval
, sc
, K_NIL
, args
, env
);
8534 CONTIN_1 (dcrry_1dotALL
, kernel_print_sexp
, sc
, args
);
8535 putstr (sc
, "\nApply to: ");
8540 { return kernel_mapeval (sc
, K_NIL
, args
, env
); }
8544 KERNEL_ERROR_1 (sc
, "eval: can't apply:", functor
);
8547 /*_ , Eval mappers */
8548 /*_ . kernel_mapeval */
8549 /* Evaluate each datum in list arg2, Kernel-returning a list of the results. */
8550 SIG_CHKARRAY(kernel_mapeval
) =
8551 { REF_OPER(is_finite_list
), REF_OPER(is_finite_list
), REF_OPER(is_environment
), };
8552 DEF_SIMPLE_DESTR(kernel_mapeval
);
8553 DEF_CFUNC (ps0a3
, kernel_mapeval
, REF_DESTR(kernel_mapeval
),0)
8556 WITH_3_ARGS(accum
, args
, env
);
8557 assert (is_environment (env
));
8560 * The list of evaluated arguments, in reverse order.
8561 * Purpose: Used as an accumulator.
8563 args: list of forms to be evaluated.
8564 * Precondition: Must be a proper list (is_list must give true)
8565 * When called by itself: The forms that remain yet to be evaluated
8567 env: The environment to evaluate in.
8570 /* If there are remaining arguments, arrange to evaluate one,
8571 add the result to accumulator, and return control here. */
8574 /* This can't be converted to a loop because we don't know
8575 whether kernel_eval_aux will create more frames. */
8576 CONTIN_3 (dcrry_3CVLLA01dotAX1
,
8577 kernel_mapeval
, sc
, accum
, cdr (args
), env
);
8578 return kernel_eval (sc
, car (args
), env
);
8580 /* If there are no remaining arguments, reverse the accumulator
8581 and return it. Can't reverse in place because other
8582 continuations might re-use the same accumulator state. */
8583 else if (args
== K_NIL
)
8584 { return reverse (sc
, accum
); }
8587 /* This shouldn't be reachable because we check for it being
8588 a list beforehand in kernel_eval_aux. */
8589 errx (4, "mapeval: arguments must be a list:");
8593 RGSTR(ground
,"$bad-sequence",REF_OPER(kernel_sequence
))
8594 SIG_CHKARRAY(kernel_sequence
) =
8595 { REF_KEY(K_TYCH_DOT
), REF_OPER(is_countable_list
), };
8596 DEF_SIMPLE_CFUNC(ps0a1
,kernel_sequence
,0)
8599 /* Ultimately return #inert */
8600 /* $$IMPROVE ME This shouldn't accumulate args only to discard
8602 CONTIN_0_RAW(mk_curried(dcrry_NdotALL
, K_INERT
, 0), sc
);
8603 return kernel_mapeval(sc
,K_NIL
,forms
,sc
->envir
);
8606 /*_ . kernel_mapand_aux */
8607 /* Call proc on each datum in args, Kernel-returning true if all
8608 succeed, otherwise false. */
8609 SIG_CHKARRAY(kernel_mapand_aux
) =
8610 { REF_OPER(is_bool
),
8611 REF_OPER(is_combiner
),
8612 REF_OPER(is_finite_list
),
8614 DEF_SIMPLE_CFUNC (ps0a3
, kernel_mapand_aux
,0)
8617 WITH_3_ARGS(ok
, proc
, args
);
8620 * Whether the last invocation of this succeeded. Initialize with
8623 * proc: A boolean combiner (predicate) to apply to these objects
8625 * args: list of objects to apply proc to
8626 * Precondition: Must be a proper list
8631 { KERNEL_ERROR_1(sc
, "kernel_mapand_aux: Must be boolean: ", ok
); }
8632 /* If there are remaining arguments, arrange to evaluate one and
8633 return control here. */
8636 /* This can't be converted to a loop because we don't know
8637 whether kernel_eval_aux will create more frames. */
8638 CONTIN_2 (dcrry_3VLLdotALL
,
8639 kernel_mapand_aux
, sc
, proc
, cdr (args
));
8640 return kernel_eval_aux (sc
, proc
, car (args
), sc
->envir
);
8642 /* If there are no remaining arguments, return true. */
8643 else if (args
== K_NIL
)
8647 /* This shouldn't be reachable because we check for it being a
8649 errx (4, "mapbool: arguments must be a list:");
8653 /*_ . kernel_mapand */
8654 SIG_CHKARRAY(kernel_mapand
) =
8655 { REF_OPER(is_combiner
),
8656 REF_OPER(is_finite_list
),
8658 DEF_SIMPLE_APPLICATIVE (ps0a2
, kernel_mapand
,0,simple
, "every?/2-xary")
8660 WITH_2_ARGS(proc
, args
);
8661 /* $$IMPROVE ME Get list metrics here and if we get a circular
8662 list, treat it correctly (How is TBD). */
8663 return kernel_mapand_aux(sc
,REF_KEY(K_T
), proc
, args
);
8665 /*_ . kernel_mapor_aux */
8666 /* Call proc on each datum in args, Kernel-returning true if all
8667 succeed, otherwise false. */
8668 SIG_CHKARRAY(kernel_mapor_aux
) =
8669 { REF_OPER(is_bool
),
8670 REF_OPER(is_combiner
),
8671 REF_OPER(is_finite_list
),
8673 DEF_SIMPLE_CFUNC (ps0a3
, kernel_mapor_aux
,0)
8676 WITH_3_ARGS(ok
, proc
, args
);
8679 * Whether the last invocation of this succeeded. Initialize with
8682 * proc: A boolean combiner (predicate) to apply to these objects
8684 * args: list of objects to apply proc to
8685 * Precondition: Must be a proper list
8690 { KERNEL_ERROR_1(sc
, "kernel_mapor_aux: Must be boolean: ", ok
); }
8691 /* If there are remaining arguments, arrange to evaluate one and
8692 return control here. */
8695 /* This can't be converted to a loop because we don't know
8696 whether kernel_eval_aux will create more frames. */
8697 CONTIN_2 (dcrry_3VLLdotALL
,
8698 kernel_mapor_aux
, sc
, proc
, cdr (args
));
8699 return kernel_eval_aux (sc
, proc
, car (args
), sc
->envir
);
8701 /* If there are no remaining arguments, return false. */
8702 else if (args
== K_NIL
)
8706 /* This shouldn't be reachable because we check for it being a
8708 errx (4, "mapbool: arguments must be a list:");
8711 /*_ . kernel_mapor */
8712 SIG_CHKARRAY(kernel_mapor
) =
8713 { REF_OPER(is_combiner
),
8714 REF_OPER(is_finite_list
),
8716 DEF_SIMPLE_APPLICATIVE (ps0a2
, kernel_mapor
,0,simple
, "some?/2-xary")
8718 WITH_2_ARGS(proc
, args
);
8719 /* $$IMPROVE ME Get list metrics here and if we get a circular
8720 list, treat it correctly (How is TBD). */
8721 return kernel_mapor_aux(sc
,REF_KEY(K_F
), proc
, args
);
8724 /*_ , Kernel combiners */
8726 /* $$IMPROVE ME Make referring to curried operatives neater. */
8727 RGSTR(ground
, "$and?", REF_OBJ(k_oper_andp
))
8728 DEF_BOXED_CURRIED(k_oper_andp
,
8730 REF_OPER(kernel_internal_eval
),
8731 REF_OPER(kernel_mapand
));
8734 RGSTR(ground
, "$or?", REF_OBJ(k_oper_orp
))
8735 DEF_BOXED_CURRIED(k_oper_orp
,
8737 REF_OPER(kernel_internal_eval
),
8738 REF_OPER(kernel_mapor
));
8741 /*_ . k_counted_map_aux */
8742 /* $$USE ME MORE Export both to simple: "counted-map1-car"
8743 "counted-map1-cdr" */
8745 k_counted_map_car(klink
* sc
, int count
, pko list
, _kt_tag t_enum
)
8748 pko rv_result
= K_NIL
;
8749 for(i
= 0; i
< count
; ++i
, list
= pair_cdr(0, list
))
8751 assert(is_pair(list
));
8752 pko obj
= pair_car(0, list
);
8753 rv_result
= v2cons (t_enum
, pair_car(sc
, obj
), rv_result
);
8756 /* Reverse the list in place. */
8757 return unsafe_v2reverse_in_place(K_NIL
, rv_result
);
8761 k_counted_map_cdr(klink
* sc
, int count
, pko list
, _kt_tag t_enum
)
8764 pko rv_result
= K_NIL
;
8765 for(i
= 0; i
< count
; ++i
, list
= pair_cdr(0, list
))
8767 assert(is_pair(list
));
8768 pko obj
= pair_car(0, list
);
8769 rv_result
= v2cons (t_enum
, pair_cdr(sc
, obj
), rv_result
);
8772 /* Reverse the list in place. */
8773 return unsafe_v2reverse_in_place(K_NIL
, rv_result
);
8776 /* Evaluate COUNT datums in list ARGS, Kernel-returning a list of the
8778 SIG_CHKARRAY(k_counted_map_aux
) =
8779 { REF_OPER(is_finite_list
),
8780 REF_OPER(is_integer
),
8781 REF_OPER(is_integer
),
8782 REF_OPER(is_operative
),
8783 REF_OPER(is_finite_list
),
8785 DEF_SIMPLE_APPLICATIVE (ps0a5
, k_counted_map_aux
, 0,simple
, "counted-map/5")
8787 WITH_5_ARGS(accum
, count
, len
, oper
, args
);
8788 assert (is_integer (count
));
8789 /* $$IMPROVE ME Check the other args too */
8793 * The list of evaluated arguments, in reverse order.
8794 * Purpose: Used as an accumulator.
8797 * The number of arguments remaining
8800 * The effective length of args.
8805 args: list of lists of arguments to this.
8807 * Precondition: Must be a proper list (is_finite_list must give
8808 true). args will not be cyclic, we'll check for and handle
8809 encycling outside of here.
8812 /* If there are remaining arguments, arrange to operate on one, cons
8813 the result to accumulator, and return control here. */
8814 if (ivalue (count
) > 0)
8816 assert(is_pair(args
));
8817 int len_v
= ivalue(len
);
8818 /* This can't be converted to a loop because we don't know
8819 whether kernel_eval_aux will create more frames.
8821 $$IMPROVE ME Check T_NO_K of proc; if it's set, we can loop.
8823 CONTIN_5 (dcrry_5CVLLA01dotAX1
,
8824 k_counted_map_aux
, sc
, accum
,
8825 mk_integer(ivalue(count
) - 1),
8828 k_counted_map_cdr(sc
, len_v
, args
, T_PAIR
));
8830 return kernel_eval_aux (sc
,
8832 k_counted_map_car(sc
, len_v
, args
, T_PAIR
),
8835 /* If there are no remaining arguments, reverse the accumulator
8836 and return it. Can't reverse in place because other
8837 continuations might re-use the same accumulator state. */
8839 { return reverse (sc
, accum
); }
8843 /*_ . counted-every?/5 */
8844 SIG_CHKARRAY(k_counted_every
) =
8845 { REF_OPER(is_bool
),
8846 REF_OPER(is_integer
),
8847 REF_OPER(is_integer
),
8848 REF_OPER(is_operative
),
8849 REF_OPER(is_finite_list
),
8851 DEF_SIMPLE_APPLICATIVE (ps0a5
, k_counted_every
,0,simple
,"counted-every?/5")
8853 WITH_5_ARGS(ok
, count
, len
, oper
, args
);
8854 assert (is_bool (ok
));
8855 assert (is_integer (count
));
8856 assert (is_integer (len
));
8860 * Whether the last invocation of this succeeded. Initialize with
8864 * The number of arguments remaining
8867 * The effective length of args.
8872 args: list of lists of arguments to this.
8874 * Precondition: Must be a proper list (is_finite_list must give
8875 true). args will not be cyclic, we'll check for and handle
8876 encycling outside of here.
8882 { KERNEL_ERROR_1(sc
, "k_counted_every: Must be boolean: ", ok
); }
8884 /* If there are remaining arguments, arrange to evaluate one and
8885 return control here. */
8886 if (ivalue (count
) > 0)
8888 assert(is_pair(args
));
8889 int len_v
= ivalue(len
);
8890 /* This can't be converted to a loop because we don't know
8891 whether kernel_eval_aux will create more frames.
8893 $$IMPROVE ME Check T_NO_K of proc; if it's set, we can loop.
8895 CONTIN_4 (dcrry_4VLLdotALL
,
8896 k_counted_every
, sc
,
8897 mk_integer(ivalue(count
) - 1),
8900 k_counted_map_cdr(sc
, len_v
, args
, T_PAIR
));
8902 return kernel_eval_aux (sc
,
8904 k_counted_map_car(sc
, len_v
, args
, T_PAIR
),
8907 /* If there are no remaining arguments, return true. */
8913 /*_ . counted-some?/5 */
8914 SIG_CHKARRAY(k_counted_some
) =
8915 { REF_OPER(is_bool
),
8916 REF_OPER(is_integer
),
8917 REF_OPER(is_integer
),
8918 REF_OPER(is_operative
),
8919 REF_OPER(is_finite_list
),
8921 DEF_SIMPLE_APPLICATIVE (ps0a5
, k_counted_some
,0,simple
,"counted-some?/5")
8923 WITH_5_ARGS(ok
, count
, len
, oper
, args
);
8924 assert (is_bool (ok
));
8925 assert (is_integer (count
));
8926 assert (is_integer (len
));
8931 { KERNEL_ERROR_1(sc
, "k_counted_some: Must be boolean: ", ok
); }
8933 /* If there are remaining arguments, arrange to evaluate one and
8934 return control here. */
8935 if (ivalue (count
) > 0)
8937 assert(is_pair(args
));
8938 int len_v
= ivalue(len
);
8939 /* This can't be converted to a loop because we don't know
8940 whether kernel_eval_aux will create more frames.
8942 $$IMPROVE ME Check T_NO_K of proc; if it's set, we can loop.
8944 CONTIN_4 (dcrry_4VLLdotALL
,
8946 mk_integer(ivalue(count
) - 1),
8949 k_counted_map_cdr(sc
, len_v
, args
, T_PAIR
));
8951 return kernel_eval_aux (sc
,
8953 k_counted_map_car(sc
, len_v
, args
, T_PAIR
),
8956 /* If there are no remaining arguments, return false. */
8962 /*_ . Klink top level */
8963 /*_ , kernel_repl */
8964 DEF_CFUNC(ps0a0
, kernel_repl
, K_NO_TYPE
,0)
8966 /* If we reached the end of file, this loop is done. */
8967 port
*pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
8969 if (pt
->kind
& port_saw_EOF
)
8973 putstr (sc
, prompt
);
8975 assert (is_environment (sc
->envir
));
8977 /* Arrange another iteration */
8978 CONTIN_0 (kernel_repl
, sc
);
8979 klink_push_dyn_binding(sc
,K_PRINT_FLAG
,K_T
);
8980 klink_push_cont(sc
, REF_OBJ(print_value
));
8982 CONTIN_1 (dcrry_2A01VLL
, tracing_say
, sc
, mk_string("\nGives: "));
8984 CONTIN_0 (kernel_internal_eval
, sc
);
8985 CONTIN_0 (kernel_read_internal
, sc
);
8990 static const kt_vector rel_chain
=
8995 REF_OPER(kernel_read_internal
),
8996 REF_OPER(kernel_internal_eval
),
8997 REF_OPER(kernel_rel
),
9001 DEF_CFUNC(ps0a0
, kernel_rel
, K_NO_TYPE
,0)
9003 /* If we reached the end of file, this loop is done. */
9004 port
*pt
= portvalue (klink_find_dyn_binding(sc
,K_INPORT
));
9006 if (pt
->kind
& port_saw_EOF
)
9009 assert (is_environment (sc
->envir
));
9012 schedule_chain( sc
, &rel_chain
);
9014 /* Arrange another iteration */
9015 CONTIN_0 (kernel_rel
, sc
);
9016 CONTIN_0 (kernel_internal_eval
, sc
);
9017 CONTIN_0 (kernel_read_internal
, sc
);
9022 /*_ , kernel_internal_eval */
9023 /* Convert the aftermath of kernel_read_internal to something kernel_eval
9025 /* $$IMPROVE ME realize this as a currier. But it's not a curried
9026 object as such because it carries no internal data. */
9027 DEF_CFUNC (ps0a1
, kernel_internal_eval
, K_ANY
,0)
9030 if( sc
->new_tracing
)
9031 { klink_push_dyn_binding( sc
, K_TRACING
, K_T
); }
9032 return kernel_eval (sc
, value
, sc
->envir
);
9035 /*_ . Constructing environments */
9036 /*_ , Declarations for built-in environments */
9037 /* These are initialized before they are registered. */
9038 static pko print_lookup_env
= 0;
9039 static pko all_builtins_env
= 0;
9040 static pko ground_env
= 0;
9041 #define unsafe_env ground_env
9042 #define simple_env ground_env
9043 static pko typecheck_env_syms
= 0;
9045 /*_ , What to include */
9046 #ifndef COLLECT_RGSTRS /* If we're collecting, these files may not
9047 have been generated yet */
9048 const kernel_registerable preregister
[] =
9050 /* $$MOVE ME These others will move into dedicated arrays, and be
9051 combined so that they can all be seen in init.krn but not in
9053 #include "registerables/ground.inc"
9054 #include "registerables/unsafe.inc"
9055 #include "registerables/simple.inc"
9056 /* $$TRANSITIONAL */
9057 { "type?", REF_APPL(typecheck
), },
9058 { "do-destructure", REF_APPL(do_destructure
), },
9061 const kernel_registerable all_builtins
[] =
9063 #include "registerables/all-builtins.inc"
9066 const kernel_registerable print_lookup_rgsts
[] =
9068 { "#f", REF_KEY(K_F
), },
9069 { "#t", REF_KEY(K_T
), },
9070 { "#inert", REF_KEY(K_INERT
), },
9071 { "#ignore", REF_KEY(K_IGNORE
), },
9073 { "$quote", REF_OPER(arg1
), },
9075 /* $$IMPROVE ME Add the other quote-like symbols here. */
9076 /* quasiquote, unquote, unquote-splicing */
9080 const kernel_registerable typecheck_syms_rgsts
[] =
9082 #include "registerables/type-keys.inc"
9089 /* Bind each of an array of kernel_registerables into env. */
9091 k_register_list (const kernel_registerable
* list
, int count
, pko env
)
9095 assert (is_environment (env
));
9096 for (i
= 0; i
< count
; i
++)
9098 kernel_define (env
, mk_symbol (list
[i
].name
), list
[i
].data
);
9102 /*_ , k_regstrs_to_env */
9104 k_regstrs_to_env(const kernel_registerable
* list
, int count
)
9106 pko env
= make_new_frame(K_NIL
);
9107 k_register_list (list
, count
, env
);
9111 #define K_REGSTRS_TO_ENV(RGSTRS)\
9112 k_regstrs_to_env(RGSTRS, sizeof (RGSTRS) / sizeof (RGSTRS[0]))
9113 /*_ , setup_print_secondary_lookup */
9114 static pko print_lookup_unwraps
= 0;
9115 static pko print_lookup_to_xary
= 0;
9117 setup_print_secondary_lookup(void)
9119 /* Quick and dirty: Set up tables corresponding to the ground env
9120 and put the registering stuff in them. */
9121 /* What this really accomplishes is to make prepared lookup tables
9122 available for particular print operations. Later we'll use a
9123 more general approach and this will become just a cache. */
9124 print_lookup_unwraps
= make_new_frame(K_NIL
);
9125 print_lookup_to_xary
= make_new_frame(K_NIL
);
9127 const kernel_registerable
* list
= preregister
;
9128 int count
= sizeof (preregister
) / sizeof (preregister
[0]);
9129 for (i
= 0; i
< count
; i
++)
9131 pko obj
= list
[i
].data
;
9132 if(is_applicative(obj
))
9134 kernel_define (print_lookup_unwraps
,
9135 mk_symbol (list
[i
].name
),
9138 pko xary
= k_to_trivpred(obj
);
9139 if((xary
!= K_NIL
) && xary
!= obj
)
9141 kernel_define (print_lookup_to_xary
,
9142 mk_symbol (list
[i
].name
),
9148 /*_ , make-kernel-standard-environment */
9149 /* Though it would be neater for this to define ground environment if
9150 there is none, that would mean it would need the eval loop and so
9151 couldn't be done early. So it relies on the ground environment
9152 being already defined. */
9153 RGSTR(ground
,"make-kernel-standard-environment", REF_OPER(mk_std_environment
))
9154 DEF_CFUNC(p00a0
, mk_std_environment
, K_NO_TYPE
,T_NO_K
)
9157 return make_new_frame(ground_env
);
9160 /*_ . The eval cycle */
9162 /*_ . Make an error continuation */
9164 klink_record_error_cont (klink
* sc
, pko error_continuation
)
9166 /* Record error continuation. */
9167 kernel_define (sc
->envir
,
9168 mk_symbol ("error-continuation"),
9169 error_continuation
);
9170 /* Also record it in interpreter, so built-ins can see it w/o
9172 sc
->error_continuation
= error_continuation
;
9175 /*_ , Entry points */
9176 /*_ . Eval cycle that restarts on error */
9178 klink_cycle_restarting (klink
* sc
, pko combiner
)
9180 assert(is_combiner(combiner
));
9181 assert(is_environment(sc
->envir
));
9182 /* Arrange to stop if we ever reach where we started. */
9183 klink_push_cont (sc
, REF_OPER (k_quit
));
9185 /* Grab root continuation. */
9186 kernel_define (sc
->envir
,
9187 mk_symbol ("root-continuation"),
9188 current_continuation (sc
));
9190 /* Make main continuation */
9191 klink_push_cont (sc
, combiner
);
9193 /* Make error continuation on top of main continuation. */
9194 pko error_continuation
=
9195 extend_continuation_aux(sc
->dump
, REF_OPER(kernel_err
), sc
->envir
);
9197 klink_record_error_cont(sc
, error_continuation
);
9199 /* Conceptually sc->retcode is a keyed dynamic variable that
9203 /* $$RECONSIDER ME Maybe indicate quit value */
9205 /*_ . Eval cycle that terminates on error */
9207 klink_cycle_no_restart (klink
* sc
, pko combiner
)
9209 assert(is_combiner(combiner
));
9210 assert(is_environment(sc
->envir
));
9211 /* Arrange to stop if we ever reach where we started. */
9212 klink_push_cont (sc
, REF_OPER (k_quit
));
9214 /* Grab root continuation. */
9215 kernel_define (sc
->envir
,
9216 mk_symbol ("root-continuation"),
9217 current_continuation (sc
));
9219 /* Make error continuation that quits. */
9220 pko error_continuation
=
9221 extend_continuation_aux(sc
->dump
, REF_OPER(kernel_err_return
), sc
->envir
);
9223 klink_record_error_cont(sc
, error_continuation
);
9225 klink_push_cont (sc
, combiner
);
9227 /* Conceptually sc->retcode is a keyed dynamic variable that
9228 kernel_err sets. Actually it's entirely cached in the
9235 /*_ , _klink_cycle (Don't use this directly) */
9237 _klink_cycle (klink
* sc
)
9239 pko value
= K_INERT
;
9244 int i
= setjmp (sc
->pseudocontinuation
);
9248 int got_new_frame
= klink_pop_cont (sc
);
9249 /* $$RETHINK ME Is this test still needed? Could be just
9253 /* $$IMPROVE ME Instead, a function that governs
9255 if (sc
->new_tracing
)
9257 if(_get_type( sc
->next_func
) == T_NOTRACE
)
9259 sc
->next_func
= notrace_comb( sc
->next_func
);
9263 klink_find_dyn_binding(sc
, K_TRACING
);
9264 /* Now we know the other branch should have been
9266 if( !tracing
|| ( tracing
== K_F
))
9269 /* Enqueue a version that will execute without
9270 tracing. Its descendants will be traced. */
9271 CONTIN_0_RAW (mk_notrace(mk_curried(dcrry_1dotALL
,
9273 mk_notrace(sc
->next_func
))),
9275 switch (_get_type (sc
->next_func
))
9278 putstr (sc
, "\nLoad ");
9282 putstr (sc
, "\nStore ");
9286 putstr (sc
, "\nDecurry ");
9292 /* Find and print current frame depth */
9293 int depth
= curr_frame_depth (sc
->dump
);
9294 char * str
= sc
->strbuff
;
9295 snprintf (str
, STRBUFFSIZE
, "\n%d: ", depth
);
9298 klink_push_dyn_binding (sc
, K_TRACING
, K_F
);
9299 putstr (sc
, "Eval: ");
9300 value
= kernel_print_sexp (sc
,
9301 cons (sc
->next_func
, value
),
9308 value
= kernel_eval_aux (sc
, sc
->next_func
, value
, sc
->envir
);
9312 /* Stop looping if stack is empty. */
9317 /* Otherwise something jumped to a continuation. Get the
9318 value and keep looping. */
9323 /* In case we're called nested in another _klink_cycle, don't
9328 /*_ . Vtable interface */
9329 /* initialization of Klink */
9332 static struct klink_interface vtbl
=
9384 /* $$MOVE ME Later after I separate some headers
9385 This belongs in dynload.c, could be just:
9386 SIG_CHKARRAY(klink_load_ext) = { REF_OPER(is_string), };
9387 DEF_SIMPLE_APPLICATIVE(ps0a1,klink_load_ext,0,ground, "load-extension") {...}
9389 RGSTR(ground
, "load-extension", REF_APPL(klink_load_ext
))
9390 SIG_CHKARRAY(klink_load_ext
) = { REF_OPER(is_string
), };
9391 DEF_SIMPLE_DESTR(klink_load_ext
);
9392 DEF_CFUNC_PSYCNAME(ps0a1
,klink_load_ext
, REF_DESTR(klink_load_ext
),0);
9393 DEF_BOXED_APPLICATIVE(klink_load_ext
, REF_OPER (klink_load_ext
));
9399 /*_ . Initializing Klink */
9400 /*_ , Allocate and initialize */
9403 klink_alloc_init (FILE * in
, FILE * out
)
9405 klink
*sc
= (klink
*) GC_MALLOC (sizeof (klink
));
9406 if (!klink_init (sc
, in
, out
))
9417 /*_ , Initialization without allocation */
9419 klink_init (klink
* sc
, FILE * in
, FILE * out
)
9421 /* Init stack first, just in case something calls _klink_error_1. */
9422 dump_stack_initialize (sc
);
9423 /* Initialize ports early in case something prints. */
9424 /* $$IMPROVE ME Should accept general ports of appropriate in/out. */
9425 klink_set_input_port_file (sc
, in
);
9426 klink_set_output_port_file (sc
, out
);
9429 /* Why do we need this field if there is a static table? */
9434 sc
->new_tracing
= 0;
9437 { oblist
= oblist_initial_value (); }
9440 /* Add the Kernel built-ins */
9441 if(!print_lookup_env
)
9443 print_lookup_env
= K_REGSTRS_TO_ENV(print_lookup_rgsts
);
9445 if(!all_builtins_env
)
9447 all_builtins_env
= K_REGSTRS_TO_ENV(all_builtins
);
9449 if(!typecheck_env_syms
)
9450 { typecheck_env_syms
= K_REGSTRS_TO_ENV(typecheck_syms_rgsts
); }
9453 /** Register objects from hard-coded list. **/
9454 ground_env
= K_REGSTRS_TO_ENV(preregister
);
9455 /* $$TRANSITIONAL Set up special lookup tables related to preregister. */
9456 setup_print_secondary_lookup();
9457 /** Bind certain objects that we make at init time. **/
9458 kernel_define (ground_env
,
9459 mk_symbol ("print-lookup-env"),
9461 kernel_define (unsafe_env
,
9462 mk_symbol ("typecheck-special-syms"),
9463 typecheck_env_syms
);
9465 /** Read some definitions from a prolog **/
9466 /* We need an envir before klink_call, because that defines a
9467 few things. Those bindings are specific to one instance of
9468 the interpreter so they do not belong in anything shared such
9470 /* $$IMPROVE ME Something in the call chain (klink_call?) should
9471 guarantee an environment. Needn't have anything in it to
9473 sc
->envir
= make_new_frame(K_NIL
);
9475 /* Can't easily merge this with klink_load_named_file. Two
9476 difficulties: it uses klink_cycle_restarting while klink_call
9477 uses klink_cycle_no_restart, and here we need to control the
9478 load environment. */
9479 pko p
= port_from_filename (InitFile
, port_file
| port_input
);
9480 if (p
== K_NIL
) { return 0; }
9482 /* We can't use k_get_mod_fm_port to manage parameters because
9483 later we will need the environment to have several parents:
9484 ground, simple, unsafe, possibly more. */
9485 /* Params: `into' = ground environment */
9486 /* We can't share this with the previous frame-making, because
9487 it should not define in the same environment. */
9488 pko params
= make_new_frame(K_NIL
);
9489 kernel_define (params
, mk_symbol ("into"), ground_env
);
9490 pko env
= make_new_frame(ground_env
);
9491 kernel_define (env
, mk_symbol ("module-parameters"), params
);
9492 int retcode
= klink_call(sc
,
9493 REF_OPER(load_from_port
),
9495 if(retcode
) { return 0; }
9497 /* The load will have written various things into ground
9498 environment. sc->envir is unsuitable now because it is this
9499 load's environment. */
9502 assert (is_environment (ground_env
));
9503 sc
->envir
= make_new_frame(ground_env
);
9505 #if 1 /* Transitional. Leave this on for the moment */
9506 /* initialization of global pointers to special symbols */
9507 sc
->QUOTE
= mk_symbol ("quote");
9508 sc
->QQUOTE
= mk_symbol ("quasiquote");
9509 sc
->UNQUOTE
= mk_symbol ("unquote");
9510 sc
->UNQUOTESP
= mk_symbol ("unquote-splicing");
9511 sc
->COLON_HOOK
= mk_symbol ("*colon-hook*");
9512 sc
->SHARP_HOOK
= mk_symbol ("*sharp-hook*");
9519 klink_deinit (klink
* sc
)
9524 /*_ . Using Klink from C */
9525 /*_ , To set ports */
9527 klink_set_input_port_file (klink
* sc
, FILE * fin
)
9529 klink_push_dyn_binding(sc
,K_INPORT
,port_from_file (fin
, port_input
));
9533 klink_set_input_port_string (klink
* sc
, char *start
, char *past_the_end
)
9535 klink_push_dyn_binding(sc
,
9537 port_from_string (start
, past_the_end
, port_input
));
9541 klink_set_output_port_file (klink
* sc
, FILE * fout
)
9543 klink_push_dyn_binding(sc
,K_OUTPORT
,port_from_file (fout
, port_output
));
9547 klink_set_output_port_string (klink
* sc
, char *start
, char *past_the_end
)
9549 klink_push_dyn_binding(sc
,
9551 port_from_string (start
, past_the_end
, port_output
));
9553 /*_ , To set external data */
9555 klink_set_external_data (klink
* sc
, void *p
)
9562 /*_ . Load file (C) */
9565 klink_load_port (klink
* sc
, pko p
, int interactive
)
9574 klink_push_dyn_binding(sc
,K_INPORT
,p
);
9580 REF_OPER (kernel_repl
) :
9581 REF_OPER (kernel_rel
);
9582 klink_cycle_restarting (sc
, combiner
);
9586 /*_ , klink_load_file */
9588 klink_load_file (klink
* sc
, FILE * fin
)
9590 klink_load_port (sc
,
9591 port_from_file (fin
, port_file
| port_input
),
9595 /*_ , klink_load_named_file */
9597 klink_load_named_file (klink
* sc
, FILE * fin
, const char *filename
)
9600 port_from_filename (filename
, port_file
| port_input
),
9604 /*_ . load string (C) */
9607 klink_load_string (klink
* sc
, const char *cmd
)
9610 port_from_string ((char *)cmd
,
9611 (char *)cmd
+ strlen (cmd
),
9612 port_input
| port_string
),
9616 /*_ , Apply combiner */
9617 /* sc is presumed to be already set up.
9618 The final value or error argument is in sc->value.
9619 The return code is duplicated in sc->retcode.
9622 klink_call (klink
* sc
, pko func
, pko args
)
9624 klink_cycle_no_restart (sc
,
9625 mk_curried(dcrry_NdotALL
,args
,func
));
9630 /* This is completely unexercised. */
9633 klink_eval (klink
* sc
, pko obj
)
9635 klink_cycle_no_restart(sc
,
9636 mk_curried(dcrry_2dotALL
,
9637 LIST2(obj
,sc
->envir
),
9638 REF_OPER(kernel_eval
)));
9642 /*_ . Main (if standalone) */
9645 #if defined(__APPLE__) && !defined (OSX)
9649 extern MacTS_main (int argc
, char **argv
);
9651 int argc
= ccommand (&argv
);
9652 MacTS_main (argc
, argv
);
9658 MacTS_main (int argc
, char **argv
)
9662 main (int argc
, char **argv
)
9667 char *file_name
= 0; /* Was InitFile */
9675 if (argc
== 2 && strcmp (argv
[1], "-?") == 0)
9677 printf ("Usage: klink -?\n");
9678 printf ("or: klink [<file1> <file2> ...]\n");
9679 printf ("followed by\n");
9680 printf (" -1 <file> [<arg1> <arg2> ...]\n");
9681 printf (" -c <Kernel commands> [<arg1> <arg2> ...]\n");
9682 printf ("assuming that the executable is named klink.\n");
9683 printf ("Use - as filename for stdin.\n");
9687 /* Make error_continuation semi-safe until it's properly set. */
9688 sc
.error_continuation
= 0;
9689 int i
= setjmp (sc
.pseudocontinuation
);
9692 if (!klink_init (&sc
, stdin
, stdout
))
9694 fprintf (stderr
, "Could not initialize!\n");
9700 fprintf (stderr
, "Kernel error encountered while initializing!\n");
9704 /* $$IMPROVE ME Maybe use get_opts instead. */
9707 /* $$IMPROVE ME Add a principled way of sometimes including
9708 filename defined in environment. Eg getenv
9712 if(!file_name
) { break; }
9713 if (strcmp (file_name
, "-") == 0)
9717 else if (strcmp (file_name
, "-1") == 0 || strcmp (file_name
, "-c") == 0)
9720 /* $$FACTOR ME This is a messy way to distinguish command
9721 string from filename string */
9722 isfile
= (file_name
[1] == '1');
9723 file_name
= *argv
++;
9724 if (strcmp (file_name
, "-") == 0)
9730 fin
= fopen (file_name
, "r");
9733 /* Put remaining command-line args into *args* in envir. */
9734 for (; *argv
; argv
++)
9736 pko value
= mk_string (*argv
);
9737 args
= mcons (value
, args
);
9739 args
= unsafe_v2reverse_in_place (K_NIL
, args
);
9740 /* Instead, use (command-line) as accessor and provide the
9741 whole command line as a list of strings. */
9742 kernel_define (sc
.envir
, mk_symbol ("*args*"), args
);
9747 fin
= fopen (file_name
, "r");
9749 if (isfile
&& fin
== 0)
9751 fprintf (stderr
, "Could not open file %s\n", file_name
);
9757 /* $$IMPROVE ME Use klink_load_named_file, replacing the
9758 file-opening code, so we can report filename */
9759 klink_load_file (&sc
, fin
);
9763 klink_load_string (&sc
, file_name
);
9765 if (!isfile
|| fin
!= stdin
)
9767 if (sc
.retcode
!= 0)
9769 fprintf (stderr
, "Errors encountered reading %s\n",
9782 /* $$MAKE ME CLEANER Quick and dirty for now, we make an
9783 environment for this but let everything else modify ground
9784 env. I'd like to be more correct about that. */
9785 /* Make an interactive environment over ground_env. */
9786 new_frame_in_env (&sc
, sc
.envir
);
9787 klink_load_file (&sc
, stdin
);
9789 retcode
= sc
.retcode
;