1 /* s7, a Scheme interpreter
2  *
3  *   derived from TinyScheme 1.39, but not a single byte of that code remains
4  *   SPDX-License-Identifier: 0BSD
5  *
6  * Bill Schottstaedt, bil@ccrma.stanford.edu
7  *
8  * Mike Scholz provided the FreeBSD support (complex trig funcs, etc)
9  * Rick Taube, Andrew Burnson, Donny Ward, and Greg Santucci provided the MS Visual C++ support
10  * Kjetil Matheussen provided the mingw support
11  *
12  * Documentation is in s7.h and s7.html.
13  * s7test.scm is a regression test.
14  * repl.scm is a vt100-based listener.
15  * nrepl.scm is a notcurses-based listener.
16  * cload.scm and lib*.scm tie in various C libraries.
17  * lint.scm checks Scheme code for infelicities.
18  * r7rs.scm implements some of r7rs (small).
19  * write.scm currrently has pretty-print.
20  * mockery.scm has the mock-data definitions.
21  * reactive.scm has reactive-set and friends.
22  * stuff.scm has some stuff.
23  * profile.scm has code to display profile data.
24  * debug.scm has debugging aids.
25  * case.scm has case*, an extension of case to pattern matching.
26  * timing tests are in the s7 tools directory
27  *
28  * s7.c is organized as follows:
29  *    structs and type flags
30  *    internal debugging stuff
31  *    constants
32  *    GC
33  *    stacks
34  *    symbols and keywords
35  *    lets
36  *    continuations
37  *    numbers
38  *    characters
39  *    strings
40  *    ports
41  *    format
42  *    lists
43  *    vectors
44  *    hash-tables
45  *    c-objects
46  *    functions
47  *    equal?
48  *    generic length, copy, reverse, fill!, append
49  *    error handlers
50  *    sundry leftovers
51  *    the optimizers
52  *    multiple-values, quasiquote
53  *    eval
54  *    *s7*
55  *    initialization and free
56  *    repl
57  *
58  * naming conventions: s7_* usually are C accessible (s7.h), g_* are scheme accessible,
59  *   H_* are documentation strings, Q_* are procedure signatures,
60  *   *_1 are ancillary functions, big_* refer to gmp,
61  *   scheme "?" corresponds to C "is_", scheme "->" to C "_to_".
62  *
63  * ---------------- compile time switches ----------------
64  */
65 
66 #include "mus-config.h"
67 
68 /*
69  * Your config file goes here, or just replace that #include line with the defines you need.
70  * The compile-time switches involve booleans, complex numbers, and multiprecision arithmetic.
71  * Currently we assume we have setjmp.h (used by the error handlers).
72  *
73  * Complex number support, which is problematic in C++, Solaris, and netBSD
74  *   is on the HAVE_COMPLEX_NUMBERS switch. In OSX or Linux, if you're not using C++,
75  *
76  *   #define HAVE_COMPLEX_NUMBERS 1
77  *   #define HAVE_COMPLEX_TRIG 1
78  *
79  *   In C++ I use:
80  *
81  *   #define HAVE_COMPLEX_NUMBERS 1
82  *   #define HAVE_COMPLEX_TRIG 0
83  *
84  *   In Windows, both are 0.
85  *
86  *   Some systems (FreeBSD) have complex.h, but some random subset of the trig funcs, so
87  *   HAVE_COMPLEX_NUMBERS means we can find
88  *      cimag creal cabs csqrt carg conj
89  *   and HAVE_COMPLEX_TRIG means we have
90  *      cacos cacosh casin casinh catan catanh ccos ccosh cexp clog cpow csin csinh ctan ctanh
91  *
92  * When HAVE_COMPLEX_NUMBERS is 0, the complex functions are stubs that simply return their
93  *   argument -- this will be very confusing for the s7 user because, for example, (sqrt -2)
94  *   will return something bogus (it might not signal an error).
95  *
96  * so the incoming (non-s7-specific) compile-time switches are
97  *     HAVE_COMPLEX_NUMBERS, HAVE_COMPLEX_TRIG, SIZEOF_VOID_P
98  * if SIZEOF_VOID_P is not defined, we look for __SIZEOF_POINTER__ instead,
99  *   the default is to assume that we're running on a 64-bit machine.
100  *
101  * To get multiprecision arithmetic, set WITH_GMP to 1.
102  *   You'll also need libgmp, libmpfr, and libmpc (version 0.8.0 or later)
103  *
104  * and we use these predefined macros: __cplusplus, _MSC_VER, __GNUC__, __clang__, __ANDROID__
105  *
106  * if WITH_SYSTEM_EXTRAS is 1 (default is 1 unless _MSC_VER), various OS and file related functions are included.
107  * in openBSD I think you need to include -ftrampolines in CFLAGS.
108  * if you want this file to compile into a stand-alone interpreter, define WITH_MAIN
109  *   to use nrepl, also define WITH_NOTCURSES
110  *
111  * -O3 produces segfaults, and is often slower than -O2 (at least according to callgrind)
112  * -march=native seems to improve tree-vectorization which is important in Snd
113  * -ffast-math makes a mess of NaNs, and does not appear to be faster
114  * for timing tests, I use: -O2 -march=native -fomit-frame-pointer -funroll-loops
115  *   some say -funroll-loops has no effect, but it is consistently faster (according to callgrind) in s7's timing tests
116  * according to callgrind, clang is normally about 10% slower than gcc, and vectorization either doesn't work or is much worse than gcc's
117  *   also g++ appears to be slightly slower than gcc
118  */
119 
120 #if (defined(__GNUC__) || defined(__clang__)) /* s7 uses PRId64 so (for example) g++ 4.4 is too old */
121   #define WITH_GCC 1
122 #else
123   #define WITH_GCC 0
124 #endif
125 
126 
127 /* ---------------- initial sizes ---------------- */
128 
129 #ifndef INITIAL_HEAP_SIZE
130   #define INITIAL_HEAP_SIZE 128000
131 #endif
132 /* the heap grows as needed, this is its initial size. If the initial heap is small, s7 can run in about 2.5 Mbytes of memory.
133  * There are many cases where a bigger heap is faster (but harware cache size probably matters more).
134  * The heap size must be a multiple of 32.  Each object takes 48 bytes.
135  */
136 
137 #ifndef SYMBOL_TABLE_SIZE
138   #define SYMBOL_TABLE_SIZE 32749
139 #endif
140 /* names are hashed into the symbol table (a vector) and collisions are chained as lists. */
141 /* 16381: thash +80 [string->symbol] tauto +45[sublet called 4x as often?] tlet +80 [g_symbol] */
142 
143 #ifndef INITIAL_STACK_SIZE
144   #define INITIAL_STACK_SIZE 2048
145 #endif
146 /* the stack grows as needed, each frame takes 4 entries, this is its initial size.
147  *   this needs to be big enough to handle the eval_c_strings at startup (ca 100)
148  *   In s7test.scm, the maximum stack size is ca 440.  In snd-test.scm, it's ca 200.
149  */
150 #define STACK_RESIZE_TRIGGER (INITIAL_STACK_SIZE / 2)
151 
152 #ifndef INITIAL_PROTECTED_OBJECTS_SIZE
153   #define INITIAL_PROTECTED_OBJECTS_SIZE 16
154 #endif
155 /* a vector of objects that are (semi-permanently) protected from the GC, grows as needed */
156 
157 #ifndef GC_TEMPS_SIZE
158   #define GC_TEMPS_SIZE 256
159 #endif
160 /* the number of recent objects that are temporarily gc-protected; 8 works for s7test and snd-test.
161  *    For the FFI, this sets the lag between a call on s7_cons and the first moment when its result
162  *    might be vulnerable to the GC.
163  */
164 
165 
166 /* ---------------- scheme choices ---------------- */
167 
168 #ifndef WITH_GMP
169   #define WITH_GMP 0
170   /* this includes multiprecision arithmetic for all numeric types and functions, using gmp, mpfr, and mpc
171    * WITH_GMP adds the following functions: bignum and bignum?, and (*s7* 'bignum-precision)
172    */
173 #endif
174 
175 #ifndef DEFAULT_BIGNUM_PRECISION
176   #define DEFAULT_BIGNUM_PRECISION 128 /* (*s7* 'bignum-precision) initial value, must be >= 2 */
177 #endif
178 
179 #ifndef WITH_PURE_S7
180   #define WITH_PURE_S7 0
181 #endif
182 #if WITH_PURE_S7
183   #define WITH_EXTRA_EXPONENT_MARKERS 0
184   #define WITH_IMMUTABLE_UNQUOTE 1
185   /* also omitted: *-ci* functions, char-ready?, cond-expand, multiple-values-bind|set!, call-with-values
186    *   and a lot more (inexact/exact, integer-length,  etc) -- see s7.html.
187    */
188 #endif
189 
190 #ifndef WITH_EXTRA_EXPONENT_MARKERS
191   #define WITH_EXTRA_EXPONENT_MARKERS 0
192 #endif
193 /* if 1, s7 recognizes "d", "f", "l", and "s" as exponent markers, in addition to "e" (also "D", "F", "L", "S") */
194 
195 #ifndef WITH_SYSTEM_EXTRAS
196   #define WITH_SYSTEM_EXTRAS (!_MSC_VER)
197   /* this adds several functions that access file info, directories, times, etc */
198 #endif
199 
200 #ifndef WITH_IMMUTABLE_UNQUOTE
201   #define WITH_IMMUTABLE_UNQUOTE 0
202   /* this removes the name "unquote" */
203 #endif
204 
205 #ifndef WITH_C_LOADER
206   #if WITH_GCC && (!__MINGW32__) && (!__CYGWIN__)
207     #define WITH_C_LOADER 1
208   /* (load file.so [e]) looks for (e 'init_func) and if found, calls it
209    *   as the shared object init function.  If WITH_SYSTEM_EXTRAS is 0, the caller
210    *   needs to supply system and delete-file so that cload.scm works.
211    */
212   #else
213     #define WITH_C_LOADER 0
214   #endif
215 #endif
216 
217 #ifndef WITH_HISTORY
218   #define WITH_HISTORY 0
219   /* this includes a circular buffer of previous evaluations for debugging, ((owlet) 'error-history) and (*s7* 'history-size) */
220 #endif
221 
222 #ifndef DEFAULT_HISTORY_SIZE
223   #define DEFAULT_HISTORY_SIZE 8
224   /* this is the default length of the eval history buffer */
225 #endif
226 #if WITH_HISTORY
227   #define MAX_HISTORY_SIZE 1048576
228 #endif
229 
230 #ifndef DEFAULT_PRINT_LENGTH
231   #define DEFAULT_PRINT_LENGTH 32 /* (*s7* 'print-length) initial value */
232 #endif
233 
234 /* in case mus-config.h forgets these */
235 #ifdef _MSC_VER
236   #ifndef HAVE_COMPLEX_NUMBERS
237     #define HAVE_COMPLEX_NUMBERS 0
238   #endif
239   #ifndef HAVE_COMPLEX_TRIG
240     #define HAVE_COMPLEX_TRIG 0
241   #endif
242 #else
243   #ifndef HAVE_COMPLEX_NUMBERS
244     #define HAVE_COMPLEX_NUMBERS 1
245   #endif
246   #if __cplusplus
247     #ifndef HAVE_COMPLEX_TRIG
248       #define HAVE_COMPLEX_TRIG 0
249     #endif
250   #else
251     #ifndef HAVE_COMPLEX_TRIG
252       #define HAVE_COMPLEX_TRIG 1
253     #endif
254   #endif
255 #endif
256 
257 /* -------------------------------------------------------------------------------- */
258 
259 #ifndef WITH_MULTITHREAD_CHECKS
260   #define WITH_MULTITHREAD_CHECKS 0
261   /* debugging aid if using s7 in a multithreaded program -- this code courtesy of Kjetil Matheussen */
262 #endif
263 
264 #ifndef S7_DEBUGGING
265   #define S7_DEBUGGING 0
266 #endif
267 
268 #undef DEBUGGING
269 #define DEBUGGING typo!
270 #define HAVE_GMP typo!
271 
272 #define SHOW_EVAL_OPS 0
273 
274 #ifndef _GNU_SOURCE
275   #define _GNU_SOURCE
276 /* for qsort_r, grumble... */
277 #endif
278 
279 #ifndef _MSC_VER
280   #include <unistd.h>
281   #include <sys/param.h>
282   #include <strings.h>
283   #include <errno.h>
284   #include <locale.h>
285 #else
286   /* in Snd these are in mus-config.h */
287   #ifndef MUS_CONFIG_H_LOADED
288     #if _MSC_VER < 1900
289       #define snprintf _snprintf
290     #endif
291     #if _MSC_VER > 1200
292       #define _CRT_SECURE_NO_DEPRECATE 1
293       #define _CRT_NONSTDC_NO_DEPRECATE 1
294       #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
295     #endif
296   #endif
297   #include <io.h>
298   #pragma warning(disable: 4244) /* conversion might cause loss of data warning */
299 #endif
300 
301 #if WITH_GCC && (!S7_DEBUGGING)
302   #define Inline inline __attribute__((__always_inline__))
303 #else
304   #ifdef _MSC_VER
305     #define Inline __forceinline
306   #else
307     #define Inline inline
308   #endif
309 #endif
310 
311 #ifndef WITH_VECTORIZE
312   #define WITH_VECTORIZE 1
313 #endif
314 
315 #if (WITH_VECTORIZE) && (defined(__GNUC__) && __GNUC__ >= 5)
316   #define Vectorized __attribute__((optimize("tree-vectorize")))
317 #else
318   #define Vectorized
319 #endif
320 
321 #if WITH_GCC
322   #define Sentinel __attribute__((sentinel))
323 #else
324   #define Sentinel
325 #endif
326 
327 #ifndef S7_ALIGNED
328   #define S7_ALIGNED 0
329 #endif
330 
331 #include <stdio.h>
332 #include <limits.h>
333 #include <ctype.h>
334 #include <string.h>
335 #include <stdlib.h>
336 #include <sys/types.h>
337 #include <time.h>
338 #include <stdarg.h>
339 #include <stddef.h>
340 #include <stdint.h>
341 #include <inttypes.h>
342 #include <setjmp.h>
343 
344 #ifdef _MSC_VER
345   #define MS_WINDOWS 1
346 #else
347   #define MS_WINDOWS 0
348 #endif
349 
350 #if (!MS_WINDOWS)
351   #include <pthread.h>
352 #endif
353 
354 #if __cplusplus
355   #include <cmath>
356 #else
357   #include <math.h>
358 #endif
359 
360 /* there is also apparently __STDC_NO_COMPLEX__ */
361 #if HAVE_COMPLEX_NUMBERS
362   #if __cplusplus
363     #include <complex>
364   #else
365     #include <complex.h>
366     #ifndef __SUNPRO_C
367       #if defined(__sun) && defined(__SVR4)
368         #undef _Complex_I
369         #define _Complex_I 1.0fi
370       #endif
371     #endif
372   #endif
373 
374   #ifndef CMPLX
375     #if (!(defined(__cplusplus))) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__INTEL_COMPILER)
376       #define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y))
377     #else
378       #define CMPLX(r, i) ((r) + ((i) * _Complex_I))
379     #endif
380   #endif
381 #endif
382 
383 #include "s7.h"
384 
385 #ifndef M_PI
386   #define M_PI 3.1415926535897932384626433832795029L
387 #endif
388 
389 #ifndef INFINITY
390   #ifndef HUGE_VAL
391     #define INFINITY (1.0/0.0) /* -log(0.0) is triggering dumb complaints from cppcheck */
392     /* there is sometimes a function, infinity(), MSC apparently uses HUGE_VALF, gcc has __builtin_huge_val() */
393   #else
394     #define INFINITY HUGE_VAL
395   #endif
396 #endif
397 
398 #ifndef NAN
399   #define NAN (INFINITY / INFINITY)
400 #endif
401 
402 #define BOLD_TEXT "\033[1m"
403 #define UNBOLD_TEXT "\033[22m"
404 
405 #if ((!__NetBSD__) && ((_MSC_VER) || (!defined(__STC__)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L))))
406   #define __func__ __FUNCTION__
407 #endif
408 
409 #define display(Obj) string_value(s7_object_to_string(sc, Obj, false))
410 #define display_80(Obj) string_value(object_to_truncated_string(sc, Obj, 80))
411 
412 typedef intptr_t opcode_t;
413 
414 #if (((defined(SIZEOF_VOID_P)) && (SIZEOF_VOID_P == 4)) || ((defined(__SIZEOF_POINTER__)) && (__SIZEOF_POINTER__ == 4)) || (!defined(__LP64__)))
415   #define NUMBER_NAME_SIZE 2 /* pointless */
416   #define POINTER_32 true
417 #else
418   #define NUMBER_NAME_SIZE 22 /* leave 1 for uint8_t name len (byte 0), 1 for terminating nul */
419   #define POINTER_32 false
420 #endif
421 
422 #define WRITE_REAL_PRECISION 16
423 typedef long double long_double;
424 
425 #define print_s7_int PRId64
426 #define print_pointer PRIdPTR
427 
428 #define MAX_FLOAT_FORMAT_PRECISION 128
429 
430 /* types */
431 enum {T_FREE = 0,
432       T_PAIR, T_NIL, T_UNUSED, T_UNDEFINED, T_UNSPECIFIED, T_EOF, T_BOOLEAN, T_CHARACTER, T_SYNTAX, T_SYMBOL,
433       T_INTEGER, T_RATIO, T_REAL, T_COMPLEX, T_BIG_INTEGER, T_BIG_RATIO, T_BIG_REAL, T_BIG_COMPLEX,
434       T_STRING, T_C_OBJECT, T_VECTOR, T_INT_VECTOR, T_FLOAT_VECTOR, T_BYTE_VECTOR,
435       T_CATCH, T_DYNAMIC_WIND, T_HASH_TABLE, T_LET, T_ITERATOR,
436       T_STACK, T_COUNTER, T_SLOT, T_C_POINTER, T_OUTPUT_PORT, T_INPUT_PORT, T_RANDOM_STATE, T_CONTINUATION, T_GOTO,
437       T_CLOSURE, T_CLOSURE_STAR, T_MACRO, T_MACRO_STAR, T_BACRO, T_BACRO_STAR, T_C_MACRO,
438       T_C_FUNCTION_STAR, T_C_FUNCTION, T_C_ANY_ARGS_FUNCTION, T_C_OPT_ARGS_FUNCTION, T_C_RST_ARGS_FUNCTION,
439       NUM_TYPES};
440 /* T_UNUSED, T_STACK, T_SLOT, T_DYNAMIC_WIND, T_CATCH, and T_COUNTER are internal */
441 
442 #if S7_DEBUGGING || SHOW_EVAL_OPS
443 static const char *s7_type_names[] =
444   {"free", "pair", "nil", "unused", "undefined", "unspecified", "eof_object", "boolean", "character", "syntax", "symbol",
445    "integer", "ratio", "real", "complex", "big_integer", "big_ratio", "big_real", "big_complex",
446    "string", "c_object", "vector", "int_vector", "float_vector", "byte_vector",
447    "catch", "dynamic_wind", "hash_table", "let", "iterator",
448    "stack", "counter", "slot", "c_pointer", "output_port", "input_port", "random_state", "continuation", "goto",
449    "closure", "closure*", "macro", "macro*", "bacro", "bacro*", "c_macro",
450    "c_function*", "c_function", "c_any_args_function", "c_opt_args_function", "c_rst_args_function"
451    };
452 #endif
453 
454 typedef struct block_t {
455   union {
456     void *data;
457     s7_pointer d_ptr;
458     s7_int *i_ptr;
459     s7_int pos;
460   } dx;
461   int32_t index;
462   union {
463     bool needs_free;
464     uint32_t tag;
465   } ln;
466   s7_int size;
467   union {
468     struct block_t *next;
469     char *documentation;
470     s7_pointer ksym;
471     s7_int nx_int;
472     s7_int *ix_ptr;
473     struct {
474       uint32_t i1, i2;
475     } ix;
476   } nx;
477   union {
478     s7_pointer ex_ptr;
479     void *ex_info;
480     s7_int ckey;
481   } ex;
482 } block_t;
483 
484 #define NUM_BLOCK_LISTS 18
485 #define TOP_BLOCK_LIST 17
486 #define BLOCK_LIST 0
487 
488 #define block_data(p)                    p->dx.data
489 #define block_index(p)                   p->index
490 #define block_set_index(p, Index)        p->index = Index
491 #define block_size(p)                    p->size
492 #define block_set_size(p, Size)          p->size = Size
493 #define block_next(p)                    p->nx.next
494 #define block_info(p)                    p->ex.ex_info
495 
496 typedef block_t hash_entry_t;
497 #define hash_entry_key(p)                p->dx.d_ptr
498 #define hash_entry_value(p)              (p)->ex.ex_ptr
499 #define hash_entry_set_value(p, Val)     p->ex.ex_ptr = Val
500 #define hash_entry_next(p)               block_next(p)
501 #define hash_entry_raw_hash(p)           block_size(p)
502 #define hash_entry_set_raw_hash(p, Hash) block_set_size(p, Hash)
503 
504 typedef block_t vdims_t;
505 #define vdims_rank(p)                    p->size
506 #define vector_elements_should_be_freed(p) p->ln.needs_free
507 #define vdims_dims(p)                    p->dx.i_ptr
508 #define vdims_offsets(p)                 p->nx.ix_ptr
509 #define vdims_original(p)                p->ex.ex_ptr
510 
511 
512 typedef enum {TOKEN_EOF, TOKEN_LEFT_PAREN, TOKEN_RIGHT_PAREN, TOKEN_DOT, TOKEN_ATOM, TOKEN_QUOTE, TOKEN_DOUBLE_QUOTE, TOKEN_BACK_QUOTE,
513 	      TOKEN_COMMA, TOKEN_AT_MARK, TOKEN_SHARP_CONST, TOKEN_VECTOR, TOKEN_BYTE_VECTOR, TOKEN_INT_VECTOR, TOKEN_FLOAT_VECTOR} token_t;
514 
515 typedef enum {NO_ARTICLE, INDEFINITE_ARTICLE} article_t;
516 typedef enum {DWIND_INIT, DWIND_BODY, DWIND_FINISH} dwind_t;
517 enum {NO_SAFETY = 0, IMMUTABLE_VECTOR_SAFETY, MORE_SAFETY_WARNINGS};  /* (*s7* 'safety) settings */
518 
519 /* IO ports */
520 typedef enum {FILE_PORT, STRING_PORT, FUNCTION_PORT} port_type_t;
521 
522 typedef struct {
523   int32_t (*read_character)(s7_scheme *sc, s7_pointer port);             /* function to read a character, int32_t for EOF */
524   void (*write_character)(s7_scheme *sc, uint8_t c, s7_pointer port);    /* function to write a character */
525   void (*write_string)(s7_scheme *sc, const char *str, s7_int len, s7_pointer port); /* function to write a string of known length */
526   token_t (*read_semicolon)(s7_scheme *sc, s7_pointer port);             /* internal skip-to-semicolon reader */
527   int32_t (*read_white_space)(s7_scheme *sc, s7_pointer port);           /* internal skip white space reader */
528   s7_pointer (*read_name)(s7_scheme *sc, s7_pointer pt);                 /* internal get-next-name reader */
529   s7_pointer (*read_sharp)(s7_scheme *sc, s7_pointer pt);                /* internal get-next-sharp-constant reader */
530   s7_pointer (*read_line)(s7_scheme *sc, s7_pointer pt, bool eol_case);  /* function to read a string up to \n */
531   void (*displayer)(s7_scheme *sc, const char *s, s7_pointer pt);
532   void (*close_port)(s7_scheme *sc, s7_pointer p);                       /* close-in|output-port */
533 } port_functions_t;
534 
535 typedef struct {
536   bool needs_free, is_closed;
537   port_type_t ptype;
538   FILE *file;
539   char *filename;
540   block_t *filename_block;
541   uint32_t line_number, file_number;
542   s7_int filename_length;
543   block_t *block;
544   s7_pointer orig_str;    /* GC protection for string port string */
545   const port_functions_t *pf;
546   s7_pointer (*input_function)(s7_scheme *sc, s7_read_t read_choice, s7_pointer port);
547   void (*output_function)(s7_scheme *sc, uint8_t c, s7_pointer port);
548 } port_t;
549 
550 typedef enum {o_d_v, o_d_vd, o_d_vdd, o_d_vid, o_d_id, o_d_7pi, o_d_7pii, o_d_7piid,
551 	      o_d_ip, o_d_pd, o_d_7pid, o_d, o_d_d, o_d_dd, o_d_7dd, o_d_ddd, o_d_dddd,
552 	      o_i_i, o_i_7i, o_i_ii, o_i_7ii, o_i_iii, o_i_7pi, o_i_7pii, o_i_7piii, o_d_p,
553 	      o_b_p, o_b_7p, o_b_pp, o_b_7pp, o_b_pp_unchecked, o_b_pi, o_b_ii, o_b_7ii, o_b_dd,
554 	      o_p, o_p_p, o_p_ii, o_p_d, o_p_dd, o_i_7d, o_i_7p, o_d_7d, o_p_pp, o_p_ppp, o_p_pi, o_p_pi_unchecked,
555 	      o_p_ppi, o_p_i, o_p_pii, o_p_pip, o_p_pip_unchecked, o_p_piip, o_b_i, o_b_d} opt_func_t;
556 
557 typedef struct opt_funcs_t {
558   opt_func_t typ;
559   void *func;
560   struct opt_funcs_t *next;
561 } opt_funcs_t;
562 
563 typedef struct {
564   const char *name;
565   int32_t name_length;
566   uint32_t id;
567   char *doc;
568   block_t *block;
569   opt_funcs_t *opt_data; /* vunion-functions (see below) */
570   s7_pointer generic_ff, setter, signature, pars;
571   s7_pointer (*chooser)(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops);
572   /* arg_defaults|names call_args only T_C_FUNCTION_STAR -- call args for GC protection */
573   union {
574     s7_pointer *arg_defaults;
575     s7_pointer bool_setter;
576   } dam;
577   union {
578     s7_pointer *arg_names;
579     s7_pointer c_sym;
580   } sam;
581   union {
582     s7_pointer call_args;
583     void (*marker)(s7_pointer p, s7_int len);
584   } cam;
585 } c_proc_t;
586 
587 
588 typedef struct {
589   s7_int type, outer_type;
590   s7_pointer scheme_name, getter, setter;
591   void (*mark)(void *val);
592   void (*free)(void *value);           /* this will go away someday (use gc_free) */
593   bool (*eql)(void *val1, void *val2); /* this will go away someday (use equal) */
594 #if (!DISABLE_DEPRECATED)
595   char *(*print)(s7_scheme *sc, void *value);
596 #endif
597   s7_pointer (*equal)      (s7_scheme *sc, s7_pointer args);
598   s7_pointer (*equivalent) (s7_scheme *sc, s7_pointer args);
599   s7_pointer (*ref)        (s7_scheme *sc, s7_pointer args);
600   s7_pointer (*set)        (s7_scheme *sc, s7_pointer args);
601   s7_pointer (*length)     (s7_scheme *sc, s7_pointer args);
602   s7_pointer (*reverse)    (s7_scheme *sc, s7_pointer args);
603   s7_pointer (*copy)       (s7_scheme *sc, s7_pointer args);
604   s7_pointer (*fill)       (s7_scheme *sc, s7_pointer args);
605   s7_pointer (*to_list)    (s7_scheme *sc, s7_pointer args);
606   s7_pointer (*to_string)  (s7_scheme *sc, s7_pointer args);
607   s7_pointer (*gc_mark)    (s7_scheme *sc, s7_pointer args);
608   s7_pointer (*gc_free)    (s7_scheme *sc, s7_pointer args);
609 } c_object_t;
610 
611 
612 typedef s7_int (*hash_map_t)(s7_scheme *sc, s7_pointer table, s7_pointer key);          /* hash-table object->location mapper */
613 typedef hash_entry_t *(*hash_check_t)(s7_scheme *sc, s7_pointer table, s7_pointer key); /* hash-table object equality function */
614 static hash_map_t default_hash_map[NUM_TYPES];
615 
616 
617 typedef s7_int (*s7_i_7pi_t)(s7_scheme *sc, s7_pointer p, s7_int i1);
618 typedef s7_int (*s7_i_7pii_t)(s7_scheme *sc, s7_pointer p, s7_int i1, s7_int i2);
619 typedef s7_int (*s7_i_7piii_t)(s7_scheme *sc, s7_pointer p, s7_int i1, s7_int i2, s7_int i3);
620 typedef s7_int (*s7_i_iii_t)(s7_int i1, s7_int i2, s7_int i3);
621 typedef s7_int (*s7_i_7i_t)(s7_scheme *sc, s7_int i1);
622 typedef s7_int (*s7_i_7ii_t)(s7_scheme *sc, s7_int i1, s7_int i2);
623 typedef bool (*s7_b_pp_t)(s7_pointer p1, s7_pointer p2);
624 typedef bool (*s7_b_7pp_t)(s7_scheme *sc, s7_pointer p1, s7_pointer p2);
625 typedef bool (*s7_b_7p_t)(s7_scheme *sc, s7_pointer p1);
626 typedef bool (*s7_b_pi_t)(s7_scheme *sc, s7_pointer p1, s7_int i2);
627 typedef bool (*s7_b_d_t)(s7_double p1);
628 typedef bool (*s7_b_i_t)(s7_int p1);
629 typedef bool (*s7_b_ii_t)(s7_int p1, s7_int p2);
630 typedef bool (*s7_b_7ii_t)(s7_scheme *sc, s7_int p1, s7_int p2);
631 typedef bool (*s7_b_dd_t)(s7_double p1, s7_double p2);
632 typedef s7_pointer (*s7_p_p_t)(s7_scheme *sc, s7_pointer p);
633 typedef s7_pointer (*s7_p_t)(s7_scheme *sc);
634 typedef s7_pointer (*s7_p_pp_t)(s7_scheme *sc, s7_pointer p1, s7_pointer p2);
635 typedef s7_pointer (*s7_p_ppi_t)(s7_scheme *sc, s7_pointer p1, s7_pointer p2, s7_int i1);
636 typedef s7_pointer (*s7_p_ppp_t)(s7_scheme *sc, s7_pointer p1, s7_pointer p2, s7_pointer p3);
637 typedef s7_pointer (*s7_p_pi_t)(s7_scheme *sc, s7_pointer p1, s7_int i1);
638 typedef s7_pointer (*s7_p_pii_t)(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_int i2);
639 typedef s7_pointer (*s7_p_pip_t)(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_pointer p2);
640 typedef s7_pointer (*s7_p_piip_t)(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_int i2, s7_pointer p3);
641 typedef s7_pointer (*s7_p_i_t)(s7_scheme *sc, s7_int i);
642 typedef s7_pointer (*s7_p_ii_t)(s7_scheme *sc, s7_int i1, s7_int i2);
643 typedef s7_pointer (*s7_p_dd_t)(s7_scheme *sc, s7_double x1, s7_double x2);
644 typedef s7_double (*s7_d_7d_t)(s7_scheme *sc, s7_double p1);
645 typedef s7_double (*s7_d_7dd_t)(s7_scheme *sc, s7_double p1, s7_double p2);
646 typedef s7_double (*s7_d_7pii_t)(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_int i2);
647 typedef s7_double (*s7_d_7piid_t)(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_int i2, s7_double x1);
648 
649 typedef struct opt_info opt_info;
650 
651 typedef union {
652   s7_int i;
653   s7_double x;
654   s7_pointer p;
655   void *obj;
656   opt_info *o1;
657   s7_function call;
658   s7_double (*d_f)(void);
659   s7_double (*d_d_f)(s7_double x);
660   s7_double (*d_7d_f)(s7_scheme *sc, s7_double x);
661   s7_double (*d_dd_f)(s7_double x1, s7_double x2);
662   s7_double (*d_7dd_f)(s7_scheme *sc, s7_double x1, s7_double x2);
663   s7_double (*d_ddd_f)(s7_double x1, s7_double x2, s7_double x3);
664   s7_double (*d_dddd_f)(s7_double x1, s7_double x2, s7_double x3, s7_double x4);
665   s7_double (*d_v_f)(void *obj);
666   s7_double (*d_vd_f)(void *obj, s7_double fm);
667   s7_double (*d_vdd_f)(void *obj, s7_double x1, s7_double x2);
668   s7_double (*d_vid_f)(void *obj, s7_int i, s7_double fm);
669   s7_double (*d_id_f)(s7_int i, s7_double fm);
670   s7_double (*d_7pi_f)(s7_scheme *sc, s7_pointer obj, s7_int i1);
671   s7_double (*d_7pii_f)(s7_scheme *sc, s7_pointer obj, s7_int i1, s7_int i2);
672   s7_double (*d_7piid_f)(s7_scheme *sc, s7_pointer obj, s7_int i1, s7_int i2, s7_double x);
673   s7_double (*d_ip_f)(s7_int i1, s7_pointer p);
674   s7_double (*d_pd_f)(s7_pointer obj, s7_double x);
675   s7_double (*d_7pid_f)(s7_scheme *sc, s7_pointer obj, s7_int i1, s7_double x);
676   s7_double (*d_p_f)(s7_pointer p);
677   s7_int (*i_7d_f)(s7_scheme *sc, s7_double i1);
678   s7_int (*i_7p_f)(s7_scheme *sc, s7_pointer i1);
679   s7_int (*i_i_f)(s7_int i1);
680   s7_int (*i_7i_f)(s7_scheme *sc, s7_int i1);
681   s7_int (*i_ii_f)(s7_int i1, s7_int i2);
682   s7_int (*i_7ii_f)(s7_scheme *sc, s7_int i1, s7_int i2);
683   s7_int (*i_iii_f)(s7_int i1, s7_int i2, s7_int i3);
684   s7_int (*i_7pi_f)(s7_scheme *sc, s7_pointer p, s7_int i1);
685   s7_int (*i_7pii_f)(s7_scheme *sc, s7_pointer p, s7_int i1, s7_int i2);
686   s7_int (*i_7piii_f)(s7_scheme *sc, s7_pointer p, s7_int i1, s7_int i2, s7_int i3);
687   bool (*b_i_f)(s7_int p);
688   bool (*b_d_f)(s7_double p);
689   bool (*b_p_f)(s7_pointer p);
690   bool (*b_pp_f)(s7_pointer p1, s7_pointer p2);
691   bool (*b_7pp_f)(s7_scheme *sc, s7_pointer p1, s7_pointer p2);
692   bool (*b_7p_f)(s7_scheme *sc, s7_pointer p1);
693   bool (*b_pi_f)(s7_scheme *sc, s7_pointer p1, s7_int i2);
694   bool (*b_ii_f)(s7_int i1, s7_int i2);
695   bool (*b_7ii_f)(s7_scheme *sc, s7_int i1, s7_int i2);
696   bool (*b_dd_f)(s7_double x1, s7_double x2);
697   s7_pointer (*p_f)(s7_scheme *sc);
698   s7_pointer (*p_p_f)(s7_scheme *sc, s7_pointer p);
699   s7_pointer (*p_pp_f)(s7_scheme *sc, s7_pointer p1, s7_pointer p2);
700   s7_pointer (*p_ppp_f)(s7_scheme *sc, s7_pointer p, s7_pointer p2, s7_pointer p3);
701   s7_pointer (*p_pi_f)(s7_scheme *sc, s7_pointer p1, s7_int i1);
702   s7_pointer (*p_pii_f)(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_int i2);
703   s7_pointer (*p_ppi_f)(s7_scheme *sc, s7_pointer p1, s7_pointer p2, s7_int i1);
704   s7_pointer (*p_pip_f)(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_pointer p2);
705   s7_pointer (*p_piip_f)(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_int i2, s7_pointer p3);
706   s7_pointer (*p_i_f)(s7_scheme *sc, s7_int i);
707   s7_pointer (*p_ii_f)(s7_scheme *sc, s7_int x1, s7_int x2);
708   s7_pointer (*p_d_f)(s7_scheme *sc, s7_double x);
709   s7_pointer (*p_dd_f)(s7_scheme *sc, s7_double x1, s7_double x2);
710   s7_double (*fd)(opt_info *o);
711   s7_int (*fi)(opt_info *o);
712   bool (*fb)(opt_info *o);
713   s7_pointer (*fp)(opt_info *o);
714 } vunion;
715 
716 #ifndef OPT_SC_DEBUGGING
717   #define OPT_SC_DEBUGGING 0
718 #endif
719 #define NUM_VUNIONS 15
720 struct opt_info {
721   vunion v[NUM_VUNIONS];
722 #if S7_DEBUGGING || OPT_SC_DEBUGGING
723   int64_t unused1;
724 #endif
725   s7_scheme *sc;
726 #if S7_DEBUGGING || OPT_SC_DEBUGGING
727   int64_t unused2;
728   const char *opo_func;
729   int opo_line;
730 #endif
731 };
732 
733 #define O_WRAP (NUM_VUNIONS - 1)
734 
735 #if WITH_GMP
736 typedef struct bigint {mpz_t n; struct bigint *nxt;} bigint;
737 typedef struct bigrat {mpq_t q; struct bigrat *nxt;} bigrat;
738 typedef struct bigflt {mpfr_t x; struct bigflt *nxt;} bigflt;
739 typedef struct bigcmp {mpc_t z; struct bigcmp *nxt;} bigcmp;
740 #endif
741 
742 
743 /* -------------------------------- cell structure -------------------------------- */
744 
745 typedef struct s7_cell {
746   union {
747     uint64_t flag;                /* type info */
748     int64_t signed_flag;
749     uint8_t type_field;
750     uint16_t sflag;
751     struct {
752       uint32_t unused_low_flag;
753       uint16_t opt_choice;
754       uint16_t high_flag;
755     } opts;
756   } tf;
757   union {
758 
759     union {                       /* integers, floats */
760       s7_int integer_value;
761       s7_double real_value;
762 
763       struct {                    /* ratios */
764 	s7_int numerator;
765 	s7_int denominator;
766       } fraction_value;
767 
768       struct {                    /* complex numbers */
769 	s7_double rl;
770 	s7_double im;
771       } complex_value;
772 
773 #if WITH_GMP
774       bigint *bgi;                /* bignums */
775       bigrat *bgr;
776       bigflt *bgf;
777       bigcmp *bgc;
778 #endif
779     } number;
780 
781     struct {
782       s7_int unused1, unused2;     /* always int64_t so this is 16 bytes */
783       uint8_t name[24];
784     } number_name;
785 
786     struct {                       /* ports */
787       port_t *port;
788       uint8_t *data;
789       s7_int size, point;
790       block_t *block;
791     } prt;
792 
793     struct{                        /* characters */
794       uint8_t c, up_c;
795       int32_t length;
796       bool alpha_c, digit_c, space_c, upper_c, lower_c;
797       char c_name[12];
798     } chr;
799 
800     struct {                       /* c-pointers */
801       void *c_pointer;
802       s7_pointer c_type, info, weak1, weak2;
803     } cptr;
804 
805     struct {                       /* vectors */
806       s7_int length;
807       union {
808 	s7_pointer *objects;
809 	s7_int *ints;
810 	s7_double *floats;
811 	uint8_t *bytes;
812       } elements;
813       block_t *block;
814       s7_pointer (*vget)(s7_scheme *sc, s7_pointer vec, s7_int loc);
815       union {
816 	s7_pointer (*vset)(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val);
817 	s7_pointer fset;
818       } setv;
819     } vector;
820 
821     struct {                        /* stacks (internal) struct must match vector above for length/objects */
822       s7_int length;
823       s7_pointer *objects;
824       block_t *block;
825       int64_t top, flags;
826     } stk;
827 
828     struct {                        /* hash-tables */
829       s7_int mask;
830       hash_entry_t **elements;
831       hash_check_t hash_func;
832       hash_map_t *loc;
833       block_t *block;
834     } hasher;
835 
836     struct {                        /* iterators */
837       s7_pointer obj, cur;
838       union {
839 	s7_int loc;
840 	s7_pointer lcur;
841       } lc;
842       union {
843 	s7_int len;
844 	s7_pointer slow;
845 	hash_entry_t *hcur;
846       } lw;
847       s7_pointer (*next)(s7_scheme *sc, s7_pointer iterator);
848     } iter;
849 
850     struct {
851       c_proc_t *c_proc;              /* C functions, macros */
852       s7_function ff;
853       s7_int required_args, optional_args, all_args;
854     } fnc;
855 
856     struct {                         /* pairs */
857       s7_pointer car, cdr, opt1, opt2, opt3;
858     } cons;
859 
860     struct {                         /* pairs */
861       s7_pointer car, cdr, opt1, opt2;
862       uint8_t opt_type;
863     } cons_ext;
864 
865     struct {                         /* special purpose pairs (symbol-table etc) */
866       s7_pointer unused_car, unused_cdr;
867       uint64_t hash;
868       const char *fstr;
869       uint64_t location;            /* line/file/position, also used in symbol_table as raw_len */
870     } sym_cons;
871 
872     struct {                        /* scheme functions */
873       s7_pointer args, body, env, setter; /* args can be a symbol, as well as a list, setter can be #f as well as a procedure/closure */
874       int32_t arity;
875     } func;
876 
877     struct {                        /* strings */
878       s7_int length;
879       char *svalue;
880       uint64_t hash;                /* string hash-index */
881       block_t *block;
882       block_t *gensym_block;
883     } string;
884 
885     struct {                       /* symbols */
886       s7_pointer name, global_slot, local_slot;
887       int64_t id;                  /* which let last bound the symbol -- for faster symbol lookup */
888       uint32_t ctr;                /* how many times has symbol been bound */
889       uint32_t tag;                /* symbol as member of a set (tree-set-memq etc), high 32 bits are in symbol_info (the string block) */
890     } sym;
891 
892     struct {                       /* syntax */
893       s7_pointer symbol;
894       opcode_t op;
895       int32_t min_args, max_args;
896       const char *documentation;
897     } syn;
898 
899     struct {                       /* slots (bindings) */
900       s7_pointer sym, val, nxt, pending_value, expr;
901     } slt;
902 
903     struct {                       /* lets (environments) */
904       s7_pointer slots, nxt;
905       int64_t id;                  /* id of rootlet is -1 */
906       union {
907 	struct {
908 	  s7_pointer function;     /* *function* (code) if this is a funclet */
909 	  uint32_t line, file;     /* *function* location if it is known */
910 	} efnc;
911 	struct {
912 	  s7_pointer dox1, dox2;   /* do loop variables */
913 	} dox;
914 	struct {                   /* (catch #t ...) opts */
915 	  uint64_t op_stack_loc, goto_loc;
916 	} ctall;
917 	struct {
918 	  s7_int key;              /* s7_int is sc->baffle_ctr type */
919 	} bafl;
920       } edat;
921     } envr;
922 
923     struct {                        /* special stuff like #<unspecified> */
924       s7_pointer car, cdr;          /* unique_car|cdr, for sc->nil these are sc->unspecified for faster assoc etc */
925       int64_t unused_let_id;        /* let_id(sc->nil) is -1, so this needs to align with envr.id above, only used by sc->nil, so free elsewhere */
926       const char *name;
927       s7_int len;
928     } unq;
929 
930     struct {                        /* #<...> */
931       char *name;                   /* not const because the GC frees it */
932       s7_int len;
933     } undef;
934 
935     struct {                        /* #<eof> */
936       const char *name;
937       s7_int len;
938     } eof;
939 
940     struct {                        /* counter (internal) */
941       s7_pointer result, list, env, slots; /* env = counter_let (curlet after map/for-each let created) */
942       uint64_t cap;                 /* sc->capture_let_counter for let reuse */
943     } ctr;
944 
945     struct {                        /* random-state */
946 #if WITH_GMP
947       gmp_randstate_t state;
948 #else
949       uint64_t seed, carry;
950 #endif
951     } rng;
952 
953     struct {                        /* additional object types (C) */
954       s7_int type;
955       void *value;                  /*  the value the caller associates with the c_object */
956       s7_pointer e;                 /*   the method list, if any (openlet) */
957       s7_scheme *sc;
958     } c_obj;
959 
960     struct {                        /* continuations */
961       block_t *block;
962       s7_pointer stack, op_stack;
963       s7_pointer *stack_start, *stack_end;
964     } cwcc;
965 
966     struct {                        /* call-with-exit */
967       uint64_t goto_loc, op_stack_loc;
968       bool active;
969       s7_pointer name;
970     } rexit;
971 
972     struct {                        /* catch */
973       uint64_t goto_loc, op_stack_loc;
974       s7_pointer tag;
975       s7_pointer handler;
976     } rcatch; /* C++ reserves "catch" I guess */
977 
978     struct {                        /* dynamic-wind */
979       s7_pointer in, out, body;
980       dwind_t state;
981     } winder;
982   } object;
983 
984 #if S7_DEBUGGING
985   int32_t current_alloc_line, previous_alloc_line, uses, explicit_free_line, gc_line;
986   int64_t current_alloc_type, previous_alloc_type, debugger_bits;
987   const char *current_alloc_func, *previous_alloc_func, *gc_func;
988 #endif
989 } s7_cell;
990 
991 
992 typedef struct s7_big_cell {
993   s7_cell cell;
994   int64_t big_hloc;
995 } s7_big_cell;
996 typedef struct s7_big_cell *s7_big_pointer;
997 
998 typedef struct heap_block_t {
999   intptr_t start, end;
1000   int64_t offset;
1001   struct heap_block_t *next;
1002 } heap_block_t;
1003 
1004 typedef struct {
1005   s7_pointer *objs;
1006   int32_t size, top, ref, size2;
1007   bool has_hits;
1008   int32_t *refs;
1009   s7_pointer cycle_port, init_port;
1010   s7_int cycle_loc, init_loc;
1011   bool *defined;
1012 } shared_info_t;
1013 
1014 typedef struct {
1015   s7_int loc, curly_len, ctr;
1016   char *curly_str;
1017   s7_pointer args, orig_str, curly_arg;
1018   s7_pointer port, strport;
1019 } format_data_t;
1020 
1021 typedef struct gc_obj_t {
1022   s7_pointer p;
1023   struct gc_obj_t *nxt;
1024 } gc_obj_t;
1025 
1026 typedef struct {
1027   s7_pointer *list;
1028   s7_int size, loc;
1029 } gc_list_t;
1030 
1031 typedef struct {
1032   int32_t size, top, excl_size, excl_top;
1033   s7_pointer *funcs;
1034   s7_int *data, *excl;
1035 } profile_data_t;
1036 
1037 
1038 /* -------------------------------- s7_scheme struct -------------------------------- */
1039 struct s7_scheme {
1040   s7_pointer code;
1041   s7_pointer curlet;                  /* layout of first 4 entries should match stack frame layout */
1042   s7_pointer args;                    /* arguments of current function */
1043   opcode_t cur_op;
1044   s7_pointer value;
1045   s7_pointer cur_code;
1046   token_t tok;
1047 
1048   s7_pointer stack;                   /* stack is a vector */
1049   uint32_t stack_size;
1050   s7_pointer *stack_start, *stack_end, *stack_resize_trigger;
1051 
1052   s7_pointer *op_stack, *op_stack_now, *op_stack_end;
1053   uint32_t op_stack_size, max_stack_size;
1054 
1055   s7_cell **heap, **free_heap, **free_heap_top, **free_heap_trigger, **previous_free_heap_top;
1056   int64_t heap_size, gc_freed, gc_total_freed, max_heap_size, gc_temps_size;
1057   s7_double gc_resize_heap_fraction, gc_resize_heap_by_4_fraction;
1058   s7_int gc_calls, gc_total_time, gc_start, gc_end;
1059   heap_block_t *heap_blocks;
1060 
1061 #if WITH_HISTORY
1062   s7_pointer eval_history1, eval_history2, error_history, history_sink, history_pairs, old_cur_code;
1063   bool using_history1;
1064 #endif
1065 
1066 #if WITH_MULTITHREAD_CHECKS
1067   int32_t lock_count;
1068   pthread_mutex_t lock;
1069 #endif
1070 
1071   gc_obj_t *permanent_objects, *permanent_lets;
1072   s7_pointer protected_objects, protected_setters, protected_setter_symbols;  /* vectors of gc-protected objects */
1073   s7_int *gpofl; /* "gc_protected_objects_free_locations" (so we never have to do a linear search for a place to store something) */
1074   s7_int protected_objects_size, protected_setters_size, protected_setters_loc;
1075   s7_int gpofl_loc;
1076 
1077   s7_pointer nil;                     /* empty list */
1078   s7_pointer T;                       /* #t */
1079   s7_pointer F;                       /* #f */
1080   s7_pointer undefined;               /* #<undefined> */
1081   s7_pointer unspecified;             /* #<unspecified> */
1082   s7_pointer no_value;                /* the (values) value */
1083   s7_pointer unused;                  /* a marker for an unoccupied slot in sc->protected_objects (and other similar stuff) */
1084 
1085   s7_pointer symbol_table;            /* symbol table */
1086   s7_pointer rootlet, shadow_rootlet; /* rootlet */
1087   s7_int rootlet_entries;
1088   s7_pointer unlet;                   /* original bindings of predefined functions */
1089 
1090   s7_pointer input_port;              /* current-input-port */
1091   s7_pointer *input_port_stack;       /*   input port stack (load and read internally) */
1092   uint32_t input_port_stack_size, input_port_stack_loc;
1093 
1094   s7_pointer output_port;             /* current-output-port */
1095   s7_pointer error_port;              /* current-error-port */
1096   s7_pointer owlet;                   /* owlet */
1097   s7_pointer error_type, error_data, error_code, error_line, error_file, error_position; /* owlet slots */
1098   s7_pointer standard_input, standard_output, standard_error;
1099 
1100   s7_pointer sharp_readers;           /* the binding pair for the global *#readers* list */
1101   s7_pointer load_hook;               /* *load-hook* hook object */
1102   s7_pointer autoload_hook;           /* *autoload-hook* hook object */
1103   s7_pointer unbound_variable_hook;   /* *unbound-variable-hook* hook object */
1104   s7_pointer missing_close_paren_hook, rootlet_redefinition_hook;
1105   s7_pointer error_hook, read_error_hook; /* *error-hook* hook object, and *read-error-hook* */
1106   bool gc_off;                        /* gc_off: if true, the GC won't run */
1107   uint32_t gc_stats, gensym_counter, f_class, add_class, multiply_class, subtract_class, num_eq_class;
1108   int32_t format_column;
1109   uint64_t capture_let_counter;
1110   bool short_print, is_autoloading, in_with_let, object_out_locked, has_openlets, is_expanding, accept_all_keyword_arguments, got_tc, got_rec, not_tc;
1111   s7_int rec_tc_args;
1112   int64_t let_number;
1113   s7_double default_rationalize_error, equivalent_float_epsilon, hash_table_float_epsilon;
1114   s7_int default_hash_table_length, initial_string_port_length, print_length, objstr_max_len, history_size, true_history_size, output_port_data_size;
1115   s7_int max_vector_length, max_string_length, max_list_length, max_vector_dimensions, max_format_length, max_port_data_size, rec_loc, rec_len;
1116   s7_pointer stacktrace_defaults;
1117 
1118   s7_pointer rec_stack, rec_testp, rec_f1p, rec_f2p, rec_f3p, rec_f4p, rec_f5p, rec_f6p, rec_f7p, rec_f8p, rec_f9p;
1119   s7_pointer rec_resp, rec_slot1, rec_slot2, rec_slot3, rec_p1, rec_p2;
1120   s7_pointer *rec_els;
1121   s7_function rec_testf, rec_f1f, rec_f2f, rec_f3f, rec_f4f, rec_f5f, rec_f6f, rec_f7f, rec_f8f, rec_f9f, rec_resf, rec_fn;
1122   s7_int (*rec_fi1)(opt_info *o);
1123   s7_int (*rec_fi2)(opt_info *o);
1124   s7_int (*rec_fi3)(opt_info *o);
1125   s7_int (*rec_fi4)(opt_info *o);
1126   s7_int (*rec_fi5)(opt_info *o);
1127   s7_int (*rec_fi6)(opt_info *o);
1128   bool (*rec_fb1)(opt_info *o);
1129   bool (*rec_fb2)(opt_info *o);
1130 
1131   opt_info *rec_test_o, *rec_result_o, *rec_a1_o, *rec_a2_o, *rec_a3_o, *rec_a4_o, *rec_a5_o, *rec_a6_o;
1132   s7_i_ii_t rec_i_ii_f;
1133   s7_d_dd_t rec_d_dd_f;
1134   s7_pointer rec_val1, rec_val2;
1135 
1136   int32_t float_format_precision;
1137   vdims_t *wrap_only;
1138 
1139   char *typnam;
1140   int32_t typnam_len, print_width;
1141   s7_pointer *singletons;
1142   block_t *unentry;                   /* hash-table lookup failure indicator */
1143 
1144   #define INITIAL_FILE_NAMES_SIZE 8
1145   s7_pointer *file_names;
1146   int32_t file_names_size, file_names_top;
1147 
1148   #define INITIAL_STRBUF_SIZE 1024
1149   s7_int strbuf_size;
1150   char *strbuf;
1151 
1152   char *read_line_buf;
1153   s7_int read_line_buf_size;
1154 
1155   s7_pointer u, v, w, x, y, z;         /* evaluator local vars */
1156   s7_pointer temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp_cell_2;
1157   s7_pointer t1_1, t2_1, t2_2, t3_1, t3_2, t3_3, z2_1, z2_2, t4_1, u1_1, u2_1;
1158 
1159   jmp_buf goto_start;
1160   bool longjmp_ok;
1161   int32_t setjmp_loc;
1162 
1163   void (*begin_hook)(s7_scheme *sc, bool *val);
1164   opcode_t begin_op;
1165 
1166   bool debug_or_profile, profiling_gensyms;
1167   s7_int current_line, s7_call_line, safety, debug, profile;
1168   profile_data_t *profile_data;
1169   const char *current_file, *s7_call_file, *s7_call_name;
1170 
1171   shared_info_t *circle_info;
1172   format_data_t **fdats;
1173   int32_t num_fdats, last_error_line;
1174   s7_pointer elist_1, elist_2, elist_3, elist_4, elist_5, plist_1, plist_2, plist_2_2, plist_3, qlist_2, qlist_3, clist_1;
1175   gc_list_t *strings, *vectors, *input_ports, *output_ports, *input_string_ports, *continuations, *c_objects, *hash_tables;
1176   gc_list_t *gensyms, *undefineds, *lambdas, *multivectors, *weak_refs, *weak_hash_iterators, *opt1_funcs;
1177 #if (WITH_GMP)
1178   gc_list_t *big_integers, *big_ratios, *big_reals, *big_complexes, *big_random_states;
1179   mpz_t mpz_1, mpz_2, mpz_3, mpz_4;
1180   mpq_t mpq_1, mpq_2, mpq_3;
1181   mpfr_t mpfr_1, mpfr_2, mpfr_3;
1182   mpc_t mpc_1, mpc_2;
1183   void *ratloc;
1184   bigint *bigints;
1185   bigrat *bigrats;
1186   bigflt *bigflts;
1187   bigcmp *bigcmps;
1188 #endif
1189   s7_pointer *setters;
1190   s7_int setters_size, setters_loc;
1191   s7_pointer *tree_pointers;
1192   int32_t tree_pointers_size, tree_pointers_top, permanent_cells, string_wrapper_pos, num_to_str_size;
1193   s7_pointer format_ports;
1194   uint32_t alloc_pointer_k, alloc_function_k, alloc_symbol_k;
1195   s7_cell *alloc_pointer_cells;
1196   c_proc_t *alloc_function_cells;
1197   uint32_t alloc_big_pointer_k;
1198   s7_big_cell *alloc_big_pointer_cells;
1199   s7_pointer *string_wrappers;
1200   uint8_t *alloc_symbol_cells;
1201   char *num_to_str;
1202 
1203   block_t *block_lists[NUM_BLOCK_LISTS];
1204   size_t alloc_string_k;
1205   char *alloc_string_cells;
1206 
1207   c_object_t **c_object_types;
1208   int32_t c_object_types_size, num_c_object_types;
1209   s7_pointer type_to_typers[NUM_TYPES];
1210 
1211   uint32_t syms_tag, syms_tag2;
1212   int32_t bignum_precision;
1213   s7_int baffle_ctr;
1214   s7_pointer default_rng;
1215 
1216   s7_pointer sort_body, sort_begin, sort_v1, sort_v2;
1217   opcode_t sort_op;
1218   s7_int sort_body_len;
1219   s7_b_7pp_t sort_f;
1220   opt_info *sort_o;
1221   bool (*sort_fb)(opt_info *o);
1222 
1223   #define INT_TO_STR_SIZE 32
1224   char int_to_str1[INT_TO_STR_SIZE], int_to_str2[INT_TO_STR_SIZE], int_to_str3[INT_TO_STR_SIZE], int_to_str4[INT_TO_STR_SIZE], int_to_str5[INT_TO_STR_SIZE];
1225 
1226   s7_pointer abs_symbol, acos_symbol, acosh_symbol, add_symbol, angle_symbol, append_symbol, apply_symbol, apply_values_symbol, arity_symbol,
1227              ash_symbol, asin_symbol, asinh_symbol, assoc_symbol, assq_symbol, assv_symbol, atan_symbol, atanh_symbol, autoload_symbol, autoloader_symbol,
1228              bacro_symbol, bacro_star_symbol, bignum_symbol, byte_vector_symbol, byte_vector_ref_symbol, byte_vector_set_symbol, byte_vector_to_string_symbol,
1229              c_pointer_symbol, c_pointer_info_symbol, c_pointer_to_list_symbol, c_pointer_type_symbol, c_pointer_weak1_symbol, c_pointer_weak2_symbol, c_pointer_with_type,
1230              caaaar_symbol, caaadr_symbol, caaar_symbol, caadar_symbol, caaddr_symbol, caadr_symbol,
1231              caar_symbol, cadaar_symbol, cadadr_symbol, cadar_symbol, caddar_symbol, cadddr_symbol, caddr_symbol, cadr_symbol,
1232              call_cc_symbol, call_with_current_continuation_symbol, call_with_exit_symbol, call_with_input_file_symbol,
1233              call_with_input_string_symbol, call_with_output_file_symbol, call_with_output_string_symbol, car_symbol,
1234              catch_symbol, cdaaar_symbol, cdaadr_symbol, cdaar_symbol, cdadar_symbol, cdaddr_symbol, cdadr_symbol, cdar_symbol,
1235              cddaar_symbol, cddadr_symbol, cddar_symbol, cdddar_symbol, cddddr_symbol, cdddr_symbol, cddr_symbol, cdr_symbol,
1236              ceiling_symbol, char_downcase_symbol, char_eq_symbol, char_geq_symbol, char_gt_symbol, char_leq_symbol, char_lt_symbol,
1237              char_position_symbol, char_to_integer_symbol, char_upcase_symbol, cload_directory_symbol, close_input_port_symbol,
1238              close_output_port_symbol, complex_symbol, cons_symbol, copy_symbol, cos_symbol, cosh_symbol, coverlet_symbol,
1239              curlet_symbol, current_error_port_symbol, current_input_port_symbol, current_output_port_symbol, cutlet_symbol, cyclic_sequences_symbol,
1240              denominator_symbol, dilambda_symbol, display_symbol, divide_symbol, documentation_symbol, dynamic_wind_symbol, dynamic_unwind_symbol,
1241              num_eq_symbol, error_symbol, eval_string_symbol, eval_symbol, exact_to_inexact_symbol, exit_symbol, exp_symbol, expt_symbol,
1242              features_symbol, fill_symbol, float_vector_ref_symbol, float_vector_set_symbol, float_vector_symbol, floor_symbol,
1243              flush_output_port_symbol, for_each_symbol, format_symbol, funclet_symbol, _function__symbol,
1244              gc_symbol, gcd_symbol, gensym_symbol, geq_symbol, get_output_string_symbol, gt_symbol,
1245              hash_table_entries_symbol, hash_table_ref_symbol, hash_table_set_symbol, hash_table_symbol, help_symbol,
1246              imag_part_symbol, immutable_symbol, inexact_to_exact_symbol, inlet_symbol, int_vector_ref_symbol, int_vector_set_symbol, int_vector_symbol,
1247              integer_decode_float_symbol, integer_to_char_symbol,
1248              is_aritable_symbol, is_bignum_symbol, is_boolean_symbol, is_byte_symbol, is_byte_vector_symbol,
1249              is_c_object_symbol, c_object_type_symbol, is_c_pointer_symbol, is_char_alphabetic_symbol, is_char_lower_case_symbol, is_char_numeric_symbol,
1250              is_char_symbol, is_char_upper_case_symbol, is_char_whitespace_symbol, is_complex_symbol, is_constant_symbol,
1251              is_continuation_symbol, is_defined_symbol, is_dilambda_symbol, is_eof_object_symbol, is_eq_symbol, is_equal_symbol,
1252              is_eqv_symbol, is_even_symbol, is_exact_symbol, is_float_vector_symbol, is_funclet_symbol,
1253              is_gensym_symbol, is_goto_symbol, is_hash_table_symbol, is_immutable_symbol,
1254              is_inexact_symbol, is_infinite_symbol, is_input_port_symbol, is_int_vector_symbol, is_integer_symbol, is_iterator_symbol,
1255              is_keyword_symbol, is_let_symbol, is_list_symbol, is_macro_symbol, is_equivalent_symbol, is_nan_symbol, is_negative_symbol,
1256              is_null_symbol, is_number_symbol, is_odd_symbol, is_openlet_symbol, is_output_port_symbol, is_pair_symbol,
1257              is_port_closed_symbol, is_positive_symbol, is_procedure_symbol, is_proper_list_symbol, is_provided_symbol,
1258              is_random_state_symbol, is_rational_symbol, is_real_symbol, is_sequence_symbol, is_string_symbol, is_subvector_symbol,
1259              is_symbol_symbol, is_syntax_symbol, is_vector_symbol, is_weak_hash_table_symbol, is_zero_symbol,
1260              iterate_symbol, iterator_is_at_end_symbol, iterator_sequence_symbol,
1261              is_float_symbol, is_integer_or_real_at_end_symbol, is_integer_or_any_at_end_symbol, is_unspecified_symbol, is_undefined_symbol,
1262              keyword_to_symbol_symbol,
1263              lcm_symbol, length_symbol, leq_symbol, let_ref_fallback_symbol, let_ref_symbol, let_set_fallback_symbol,
1264              let_set_symbol, let_temporarily_symbol, libraries_symbol, list_ref_symbol, list_set_symbol, list_symbol, list_tail_symbol, list_values_symbol,
1265              load_path_symbol, load_symbol, log_symbol, logand_symbol, logbit_symbol, logior_symbol, lognot_symbol, logxor_symbol, lt_symbol,
1266              macro_symbol, macro_star_symbol, magnitude_symbol, make_byte_vector_symbol, make_float_vector_symbol, make_hash_table_symbol,
1267              make_weak_hash_table_symbol, make_int_vector_symbol, make_iterator_symbol, string_to_keyword_symbol, make_list_symbol, make_string_symbol,
1268              make_vector_symbol, map_symbol, max_symbol, member_symbol, memq_symbol, memv_symbol, min_symbol, modulo_symbol, multiply_symbol,
1269              name_symbol, newline_symbol, not_symbol, number_to_string_symbol, numerator_symbol,
1270              object_to_string_symbol, object_to_let_symbol, open_input_file_symbol, open_input_function_symbol, open_input_string_symbol,
1271              open_output_file_symbol, open_output_function_symbol, open_output_string_symbol, openlet_symbol, outlet_symbol, owlet_symbol,
1272              pair_filename_symbol, pair_line_number_symbol, peek_char_symbol, pi_symbol, port_filename_symbol, port_line_number_symbol,
1273              port_file_symbol, port_position_symbol, procedure_source_symbol, provide_symbol,
1274              quotient_symbol,
1275              random_state_symbol, random_state_to_list_symbol, random_symbol, rationalize_symbol, read_byte_symbol,
1276              read_char_symbol, read_line_symbol, read_string_symbol, read_symbol, real_part_symbol, remainder_symbol,
1277              require_symbol, reverse_symbol, reverseb_symbol, rootlet_symbol, round_symbol,
1278              setter_symbol, set_car_symbol, set_cdr_symbol,
1279              set_current_error_port_symbol, set_current_input_port_symbol, set_current_output_port_symbol,
1280              signature_symbol, sin_symbol, sinh_symbol, sort_symbol, sqrt_symbol,
1281              stacktrace_symbol, string_append_symbol, string_copy_symbol, string_downcase_symbol, string_eq_symbol, string_fill_symbol,
1282              string_geq_symbol, string_gt_symbol, string_leq_symbol, string_lt_symbol, string_position_symbol, string_ref_symbol,
1283              string_set_symbol, string_symbol, string_to_number_symbol, string_to_symbol_symbol, string_upcase_symbol,
1284              sublet_symbol, substring_symbol, subtract_symbol, subvector_symbol, subvector_position_symbol, subvector_vector_symbol,
1285              symbol_symbol, symbol_to_dynamic_value_symbol,
1286              symbol_to_keyword_symbol, symbol_to_string_symbol, symbol_to_value_symbol,
1287              tan_symbol, tanh_symbol, throw_symbol, string_to_byte_vector_symbol,
1288              tree_count_symbol, tree_leaves_symbol, tree_memq_symbol, tree_set_memq_symbol, tree_is_cyclic_symbol, truncate_symbol, type_of_symbol,
1289              unlet_symbol,
1290              values_symbol, varlet_symbol, vector_append_symbol, vector_dimensions_symbol, vector_fill_symbol, vector_ref_symbol,
1291              vector_set_symbol, vector_symbol,
1292              weak_hash_table_symbol, with_input_from_file_symbol, with_input_from_string_symbol, with_output_to_file_symbol, with_output_to_string_symbol,
1293              write_byte_symbol, write_char_symbol, write_string_symbol, write_symbol,
1294              local_documentation_symbol, local_signature_symbol, local_setter_symbol, local_iterator_symbol;
1295   s7_pointer hash_code_symbol, dummy_equal_hash_table;
1296 #if (!WITH_PURE_S7)
1297   s7_pointer is_char_ready_symbol, char_ci_leq_symbol, char_ci_lt_symbol, char_ci_eq_symbol, char_ci_geq_symbol, char_ci_gt_symbol,
1298              let_to_list_symbol, integer_length_symbol, string_ci_leq_symbol, string_ci_lt_symbol, string_ci_eq_symbol,
1299              string_ci_geq_symbol, string_ci_gt_symbol, string_to_list_symbol, vector_to_list_symbol, string_length_symbol,
1300              list_to_string_symbol, list_to_vector_symbol, vector_length_symbol;
1301 #endif
1302 
1303   /* syntax symbols et al */
1304   s7_pointer else_symbol, lambda_symbol, lambda_star_symbol, let_symbol, quote_symbol, quasiquote_symbol, unquote_symbol, macroexpand_symbol,
1305              define_expansion_symbol, define_expansion_star_symbol, with_let_symbol, if_symbol, autoload_error_symbol,
1306              when_symbol, unless_symbol, begin_symbol, cond_symbol, case_symbol, and_symbol, or_symbol, do_symbol,
1307              define_symbol, define_star_symbol, define_constant_symbol, with_baffle_symbol, define_macro_symbol,
1308              define_macro_star_symbol, define_bacro_symbol, define_bacro_star_symbol, letrec_symbol, letrec_star_symbol, let_star_symbol,
1309              key_rest_symbol, key_allow_other_keys_symbol, key_readable_symbol, key_display_symbol, key_write_symbol, value_symbol, type_symbol,
1310              baffled_symbol, set_symbol, body_symbol, class_name_symbol, feed_to_symbol, format_error_symbol, immutable_error_symbol,
1311              wrong_number_of_args_symbol, read_error_symbol, string_read_error_symbol, syntax_error_symbol, division_by_zero_symbol, bad_result_symbol,
1312              no_catch_symbol, io_error_symbol, invalid_escape_function_symbol, wrong_type_arg_symbol, out_of_range_symbol, out_of_memory_symbol,
1313              missing_method_symbol, unbound_variable_symbol, key_if_symbol, symbol_table_symbol, profile_in_symbol, trace_in_symbol;
1314 
1315   /* signatures of sequences used as applicable objects: ("hi" 1) */
1316   s7_pointer string_signature, vector_signature, float_vector_signature, int_vector_signature, byte_vector_signature,
1317              c_object_signature, let_signature, hash_table_signature, pair_signature;
1318   /* common signatures */
1319   s7_pointer pcl_bc, pcl_bs, pcl_bt, pcl_c, pcl_e, pcl_f, pcl_i, pcl_n, pcl_r, pcl_s, pcl_v, pl_bc, pl_bn, pl_bt, pl_p, pl_sf, pl_tl, pl_nn;
1320 
1321   /* optimizer s7_functions */
1322   s7_pointer add_2, add_3, add_1x, add_x1, subtract_1, subtract_2, subtract_3, subtract_x1, subtract_2f, subtract_f2, simple_char_eq,
1323              char_equal_2, char_greater_2, char_less_2, char_position_csi, string_equal_2, substring_uncopied, display_2, display_f,
1324              string_greater_2, string_less_2, symbol_to_string_uncopied, get_output_string_uncopied, string_equal_2c, string_c1, string_append_2,
1325              vector_ref_2, vector_ref_3, vector_set_3, vector_set_4, read_char_1, dynamic_wind_unchecked, append_2,
1326              fv_ref_2, fv_ref_3, fv_set_3, fv_set_unchecked, iv_ref_2, iv_ref_3, iv_set_3, bv_ref_2, bv_ref_3, bv_set_3,
1327              list_0, list_1, list_2, list_3, list_set_i, hash_table_ref_2, hash_table_2, list_ref_0, list_ref_1, list_ref_2,
1328              format_f, format_no_column, format_just_control_string, format_as_objstr, values_uncopied,
1329              memq_2, memq_3, memq_4, memq_any, tree_set_memq_syms, simple_inlet, profile_out,
1330              lint_let_ref, lint_let_set, geq_2, add_i_random, is_defined_in_rootlet;
1331 
1332   s7_pointer multiply_2, invert_1, invert_x, divide_2, divide_by_2,
1333              num_eq_2, num_eq_xi, num_eq_ix, less_xi, less_xf, less_x0, less_2, greater_xi, greater_xf, greater_2,
1334              leq_xi, leq_2, geq_xi, geq_xf, random_i, random_f, random_1,
1335              mul_2_ff, mul_2_ii, mul_2_if, mul_2_fi, mul_2_xi, mul_2_ix, mul_2_fx, mul_2_xf,
1336              add_2_ff, add_2_ii, add_2_if, add_2_fi, add_2_xi, add_2_ix, add_2_fx, add_2_xf;
1337   s7_pointer seed_symbol, carry_symbol;
1338 
1339   /* object->let symbols */
1340   s7_pointer active_symbol, goto_symbol, data_symbol, weak_symbol, dimensions_symbol, info_symbol, c_type_symbol, source_symbol, c_object_ref_symbol,
1341              at_end_symbol, sequence_symbol, position_symbol, entries_symbol, locked_symbol, function_symbol, open_symbol, alias_symbol, port_type_symbol,
1342              file_symbol, file_info_symbol, line_symbol, c_object_let_symbol, class_symbol, c_object_length_symbol, c_object_set_symbol, current_value_symbol,
1343              c_object_copy_symbol, c_object_fill_symbol, c_object_reverse_symbol, c_object_to_list_symbol, c_object_to_string_symbol, closed_symbol,
1344              mutable_symbol, size_symbol, original_vector_symbol, pointer_symbol;
1345 
1346 #if WITH_SYSTEM_EXTRAS
1347   s7_pointer is_directory_symbol, file_exists_symbol, delete_file_symbol, getenv_symbol, system_symbol, directory_to_list_symbol, file_mtime_symbol;
1348 #endif
1349   s7_pointer open_input_function_choices[S7_NUM_READ_CHOICES];
1350   s7_pointer closed_input_function, closed_output_function;
1351   s7_pointer vector_set_function, string_set_function, list_set_function, hash_table_set_function, let_set_function, c_object_set_function, last_function;
1352 
1353   s7_pointer wrong_type_arg_info, out_of_range_info, simple_wrong_type_arg_info, simple_out_of_range_info;
1354   s7_pointer integer_wrapper1, integer_wrapper2, integer_wrapper3;
1355   s7_pointer real_wrapper1, real_wrapper2, real_wrapper3, real_wrapper4;
1356 
1357   #define NUM_SAFE_PRELISTS 8
1358   #define NUM_SAFE_LISTS 64               /* 36 is the biggest normally (lint.scm), 49 in s7test, 57 in snd-test */
1359   s7_pointer safe_lists[NUM_SAFE_LISTS];
1360   int32_t current_safe_list;
1361 
1362   s7_pointer autoload_table, s7_let, s7_let_symbol;
1363   const char ***autoload_names;
1364   s7_int *autoload_names_sizes;
1365   bool **autoloaded_already;
1366   s7_int autoload_names_loc, autoload_names_top;
1367   int32_t format_depth;
1368   bool undefined_identifier_warnings, undefined_constant_warnings, stop_at_error;
1369 
1370   opt_funcs_t *alloc_opt_func_cells;
1371   int32_t alloc_opt_func_k;
1372 
1373   int32_t pc;
1374   #define OPTS_SIZE 256          /* pqw-vox needs 178 */
1375   opt_info *opts[OPTS_SIZE + 1]; /* this form is a lot faster than opt_info**! */
1376 
1377   #define INITIAL_SAVED_POINTERS_SIZE 256 /* s7test: 838, thash: 55377, trec: 81 */
1378   void **saved_pointers;
1379   s7_int saved_pointers_loc, saved_pointers_size;
1380 
1381   s7_pointer prepackaged_type_names[NUM_TYPES];
1382 
1383 #if S7_DEBUGGING
1384   int *tc_rec_calls;
1385   int last_gc_line;
1386 #endif
1387 };
1388 
1389 #if S7_DEBUGGING
1390   static void gdb_break(void) {};
1391 #endif
1392 static s7_scheme *cur_sc = NULL; /* intended for gdb (see gdbinit), but also used if S7_DEBUGGING unfortunately */
1393 
1394 #if S7_DEBUGGING || OPT_SC_DEBUGGING
1395 static s7_scheme *opt_sc(opt_info *o)
1396 {
1397   if ((o->sc != cur_sc) || (o->unused1 != 0) || (o->unused2 != 0))
1398     {
1399       int i;
1400       for (i = 0; i < OPTS_SIZE; i++) if (o == cur_sc->opts[i]) break;
1401       fprintf(stderr, "o[%d] overwritten: %ld %p %ld %s %p\n", i, o->unused1, o->sc, o->unused2, (o->sc != cur_sc) ? "o->sc != cur_sc" : "", cur_sc);
1402       if (cur_sc->stop_at_error) abort();
1403     }
1404   return(o->sc);
1405 }
1406 
1407 static void scan_opts(s7_scheme *sc, int lim) {int i; for (i = 0; i < lim; i++) opt_sc(sc->opts[i]);}
1408 static int V_ind_1(int index, const char *func, int line) {if (index >= NUM_VUNIONS) fprintf(stderr, "%s[%d]: o->v index %d\n", func, line, index); return(index);}
1409 #define V_ind(I) V_ind_1(I, __func__, __LINE__)
1410 #else
1411 #define opt_sc(o) o->sc
1412 #define V_ind(I) I
1413 #endif
1414 #define opt_set_sc(o, sc) o->sc = sc
1415 
1416 
1417 /* -------------------------------- mallocate -------------------------------- */
1418 
1419 static void add_saved_pointer(s7_scheme *sc, void *p)
1420 {
1421   if (sc->saved_pointers_loc == sc->saved_pointers_size)
1422     {
1423       sc->saved_pointers_size *= 2;
1424       sc->saved_pointers = (void **)realloc(sc->saved_pointers, sc->saved_pointers_size * sizeof(void *));
1425     }
1426   sc->saved_pointers[sc->saved_pointers_loc++] = p;
1427 }
1428 
1429 #if POINTER_32
1430 static void *Malloc(size_t bytes)
1431 {
1432   void *p;
1433   p = malloc(bytes);
1434   if (!p) s7_error(cur_sc, cur_sc->out_of_memory_symbol, cur_sc->nil);
1435   return(p);
1436 }
1437 
1438 static void *Calloc(size_t nmemb, size_t size)
1439 {
1440   void *p;
1441   p = calloc(nmemb, size);
1442   if (!p) s7_error(cur_sc, cur_sc->out_of_memory_symbol, cur_sc->nil);
1443   return(p);
1444 }
1445 
1446 static void *Realloc(void *ptr, size_t size)
1447 {
1448   void *p;
1449   p = realloc(ptr, size);
1450   if (!p) s7_error(cur_sc, cur_sc->out_of_memory_symbol, cur_sc->nil);
1451   return(p);
1452 }
1453 #else
1454 #define Malloc malloc
1455 #define Calloc calloc
1456 #define Realloc realloc
1457 #endif
1458 
1459 static const int32_t intlen_bits[256] =
1460   {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
1461    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
1462    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
1463    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
1464    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
1465    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
1466    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
1467    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
1468 
1469 static void memclr(void *s, size_t n)
1470 {
1471   uint8_t *s2;
1472 #if S7_ALIGNED
1473   s2 = (uint8_t *)s;
1474 #else
1475 #if (defined(__x86_64__) || defined(__i386__))
1476   if (n >= 8)
1477     {
1478       int64_t *s1 = (int64_t *)s;
1479       size_t n8 = n >> 3;
1480       do {*s1++ = 0;} while (--n8 > 0);
1481       n &= 7;
1482       s2 = (uint8_t *)s1;
1483     }
1484   else s2 = (uint8_t *)s;
1485 #else
1486   s2 = (uint8_t *)s;
1487 #endif
1488 #endif
1489   while (n > 0)
1490     {
1491       *s2++ = 0;
1492       n--;
1493     }
1494 }
1495 
1496 #define LOOP_4(Code) do {Code; Code; Code; Code;} while (0)
1497 #define LOOP_8(Code) do {Code; Code; Code; Code; Code; Code; Code; Code;} while (0)
1498 #define STEP_8(Var) (((Var) & 0x7) == 0)
1499 
1500 #if POINTER_32
1501 #define memclr64 memclr
1502 #else
1503 static Vectorized void memclr64(void *p, size_t bytes)
1504 {
1505   size_t i, n;
1506   int64_t *vals;
1507   vals = (int64_t *)p;
1508   n = bytes >> 3;
1509   for (i = 0; i < n; )
1510     LOOP_8(vals[i++] = 0);
1511 }
1512 #endif
1513 
1514 static void init_block_lists(s7_scheme *sc)
1515 {
1516   int32_t i;
1517   for (i = 0; i < NUM_BLOCK_LISTS; i++)
1518     sc->block_lists[i] = NULL;
1519 }
1520 
1521 static inline void liberate(s7_scheme *sc, block_t *p)
1522 {
1523   if (block_index(p) != TOP_BLOCK_LIST)
1524     {
1525       block_next(p) = (struct block_t *)sc->block_lists[block_index(p)];
1526       sc->block_lists[block_index(p)] = p;
1527     }
1528   else
1529     {
1530       if (block_data(p))
1531 	{
1532 	  free(block_data(p));
1533 	  block_data(p) = NULL;
1534 	}
1535       block_next(p) = (struct block_t *)sc->block_lists[BLOCK_LIST];
1536       sc->block_lists[BLOCK_LIST] = p;
1537     }
1538 }
1539 
1540 static inline void liberate_block(s7_scheme *sc, block_t *p)
1541 {
1542   block_next(p) = (struct block_t *)sc->block_lists[BLOCK_LIST]; /* BLOCK_LIST=0 */
1543   sc->block_lists[BLOCK_LIST] = p;
1544 }
1545 
1546 static void fill_block_list(s7_scheme *sc)
1547 {
1548   int32_t i;
1549   block_t *b;
1550   #define BLOCK_MALLOC_SIZE 256
1551   b = (block_t *)Malloc(BLOCK_MALLOC_SIZE * sizeof(block_t)); /* batch alloc means blocks in this batch can't be freed, only returned to the list */
1552   add_saved_pointer(sc, b);
1553   sc->block_lists[BLOCK_LIST] = b;
1554   for (i = 0; i < BLOCK_MALLOC_SIZE - 1; b++, i++)
1555     block_next(b) = (block_t *)(b + 1);
1556   block_next(b) = NULL;
1557 }
1558 
1559 static inline block_t *mallocate_block(s7_scheme *sc)
1560 {
1561   block_t *p;
1562   if (!sc->block_lists[BLOCK_LIST])
1563     fill_block_list(sc);                /* this is much faster than allocating blocks as needed */
1564   p = sc->block_lists[BLOCK_LIST];
1565   sc->block_lists[BLOCK_LIST] = (block_t *)(block_next(p));
1566   block_set_index(p, BLOCK_LIST);
1567   return(p);
1568 }
1569 
1570 static inline char *permalloc(s7_scheme *sc, size_t len)
1571 {
1572   #define ALLOC_STRING_SIZE (65536 * 8) /* going up to 16 made no difference in timings */
1573   #define ALLOC_MAX_STRING (512 * 8)    /* was 256 -- sets max size of block space lost at the end, but smaller = more direct malloc calls */
1574   char *result;
1575   size_t next_k;
1576 
1577   len = (len + 7) & (~7);            /* 8-byte aligned -- more than half the time, len is already 8-byte aligned */
1578   next_k = sc->alloc_string_k + len;
1579   if (next_k > ALLOC_STRING_SIZE)
1580     {
1581       if (len >= ALLOC_MAX_STRING)
1582 	{
1583 	  result = (char *)Malloc(len);
1584 	  add_saved_pointer(sc, result);
1585 	  return(result);
1586 	}
1587       sc->alloc_string_cells = (char *)Malloc(ALLOC_STRING_SIZE); /* get a new block */
1588       add_saved_pointer(sc, sc->alloc_string_cells);
1589       sc->alloc_string_k = 0;
1590       next_k = len;
1591     }
1592   result = &(sc->alloc_string_cells[sc->alloc_string_k]);
1593   sc->alloc_string_k = next_k;
1594   return(result);
1595 }
1596 
1597 static Inline block_t *mallocate(s7_scheme *sc, size_t bytes)
1598 {
1599   block_t *p;
1600   if (bytes > 0)
1601     {
1602       int32_t index;
1603       if (bytes <= 8) /* presetting a version of intlen_bits with 3's gave only a small speed-up */
1604 	index = 3;
1605       else
1606 	{
1607 	  if (bytes <= 256)
1608 	    index = intlen_bits[bytes - 1];
1609 	  else index = (bytes <= 65536) ? (8 + intlen_bits[(bytes - 1) >> 8]) : TOP_BLOCK_LIST;   /* expansion to (1 << 17) made no difference */
1610 	}
1611       p = sc->block_lists[index];
1612       if (p)
1613 	sc->block_lists[index] = (block_t *)block_next(p);
1614       else
1615 	{
1616 	  if (index < (TOP_BLOCK_LIST - 1))
1617 	    {
1618 	      p = sc->block_lists[index + 1];
1619 	      if (p)
1620 		{
1621 		  /* we are "borrowing" a block from the next larger bin -- this saves space but costs a bit of time.
1622 		   *   in a tauto run repeating every call 1000 times, the old form ends up at 129M and 31.1 secs,
1623 		   *   whereas the borrowing form ends at 116M and 31.5 secs, but most of my tests show a slight
1624 		   *   speed-up, probably because grabbing a block here is faster than making a new one.
1625 		   *   Worst case is tlet: 8 slower in callgrind.
1626 		   */
1627 		  sc->block_lists[index + 1] = (block_t *)block_next(p);
1628 		  block_set_size(p, bytes);
1629 		  return(p);
1630 		}}
1631 	  p = mallocate_block(sc);
1632 	  block_data(p) = (index < TOP_BLOCK_LIST) ? (void *)permalloc(sc, (size_t)(1 << index)) : Malloc(bytes);
1633 	  block_set_index(p, index);
1634 	}}
1635   else p = mallocate_block(sc);
1636   block_set_size(p, bytes);
1637   return(p);
1638 }
1639 
1640 static block_t *callocate(s7_scheme *sc, size_t bytes)
1641 {
1642   block_t *p;
1643   p = mallocate(sc, bytes);
1644   if ((block_data(p)) && (block_index(p) != BLOCK_LIST))
1645     {
1646       if ((block_index(p) >= 6) &&               /* there are at least 64 bytes in the block */
1647 	  ((block_index(p) != TOP_BLOCK_LIST) || /*   but top_block is by bytes (not powers of 2) */
1648 	   ((bytes & 0x3f) == 0)))               /*   memclr64 assumes it can clear 64-bytes at a time, memclr64 is much faster than memclr */
1649 	memclr64((void *)block_data(p), bytes);
1650       else memclr((void *)(block_data(p)), bytes);
1651     }
1652   return(p);
1653 }
1654 
1655 static block_t *reallocate(s7_scheme *sc, block_t *op, size_t bytes)
1656 {
1657   block_t *np;
1658   np = mallocate(sc, bytes);
1659   if (block_data(op))  /* presumably block_data(np) is not null */
1660     memcpy((uint8_t *)(block_data(np)), (uint8_t *)(block_data(op)), block_size(op));
1661   liberate(sc, op);
1662   return(np);
1663 }
1664 
1665 
1666 /* -------------------------------------------------------------------------------- */
1667 
1668 typedef enum {P_DISPLAY, P_WRITE, P_READABLE, P_KEY} use_write_t;
1669 
1670 static s7_pointer too_many_arguments_string, not_enough_arguments_string, missing_method_string,
1671   a_boolean_string, a_byte_vector_string, a_format_port_string, a_let_string, a_list_string, a_non_constant_symbol_string,
1672   a_non_negative_integer_string, a_normal_procedure_string, a_normal_real_string, a_number_string, a_procedure_string,
1673   a_proper_list_string, a_random_state_object_string, a_rational_string, a_sequence_string, a_symbol_string, a_thunk_string,
1674   a_valid_radix_string, an_association_list_string, an_eq_func_string, an_input_file_port_string, an_input_port_string,
1675   an_input_string_port_string, an_open_port_string, an_output_file_port_string, an_output_port_string, an_output_string_port_string,
1676   an_unsigned_byte_string, caaar_a_list_string, caadr_a_list_string, caar_a_list_string, cadar_a_list_string, caddr_a_list_string,
1677   cadr_a_list_string, car_a_list_string, cdaar_a_list_string, cdadr_a_list_string, cdar_a_list_string, cddar_a_list_string,
1678   cdddr_a_list_string, cddr_a_list_string, cdr_a_list_string, immutable_error_string, its_infinite_string, its_nan_string,
1679   its_negative_string, its_too_large_string, its_too_small_string, parameter_set_twice_string, result_is_too_large_string,
1680   something_applicable_string, too_many_indices_string, value_is_missing_string, no_setter_string,
1681   format_string_1, format_string_2, format_string_3, format_string_4;
1682 
1683 static bool t_number_p[NUM_TYPES], t_small_real_p[NUM_TYPES], t_rational_p[NUM_TYPES], t_real_p[NUM_TYPES], t_big_number_p[NUM_TYPES];
1684 static bool t_simple_p[NUM_TYPES], t_structure_p[NUM_TYPES];
1685 static bool t_any_macro_p[NUM_TYPES], t_any_closure_p[NUM_TYPES], t_has_closure_let[NUM_TYPES];
1686 static bool t_mappable_p[NUM_TYPES], t_sequence_p[NUM_TYPES], t_vector_p[NUM_TYPES];
1687 static bool t_procedure_p[NUM_TYPES], t_applicable_p[NUM_TYPES];
1688 #if S7_DEBUGGING
1689 static bool t_freeze_p[NUM_TYPES]; /* free_cell sanity check */
1690 #endif
1691 
1692 static void init_types(void)
1693 {
1694   int32_t i;
1695   for (i = 0; i < NUM_TYPES; i++)
1696     {
1697       t_number_p[i] = false;
1698       t_small_real_p[i] = false;
1699       t_real_p[i] = false;
1700       t_rational_p[i] = false;
1701       t_simple_p[i] = false;
1702       t_structure_p[i] = false;
1703       t_any_macro_p[i] = false;
1704       t_any_closure_p[i] = false;
1705       t_has_closure_let[i] = false;
1706       t_sequence_p[i] = false;
1707       t_mappable_p[i] = false;
1708       t_vector_p[i] = false;
1709       t_applicable_p[i] = false;
1710       t_procedure_p[i] = false;
1711 #if S7_DEBUGGING
1712       t_freeze_p[i] = false;
1713 #endif
1714     }
1715   t_number_p[T_INTEGER] = true;
1716   t_number_p[T_RATIO] = true;
1717   t_number_p[T_REAL] = true;
1718   t_number_p[T_COMPLEX] = true;
1719   t_number_p[T_BIG_INTEGER] = true;
1720   t_number_p[T_BIG_RATIO] = true;
1721   t_number_p[T_BIG_REAL] = true;
1722   t_number_p[T_BIG_COMPLEX] = true;
1723 
1724   t_rational_p[T_INTEGER] = true;
1725   t_rational_p[T_RATIO] = true;
1726   t_rational_p[T_BIG_INTEGER] = true;
1727   t_rational_p[T_BIG_RATIO] = true;
1728 
1729   t_small_real_p[T_INTEGER] = true;
1730   t_small_real_p[T_RATIO] = true;
1731   t_small_real_p[T_REAL] = true;
1732 
1733   t_real_p[T_INTEGER] = true;
1734   t_real_p[T_RATIO] = true;
1735   t_real_p[T_REAL] = true;
1736   t_real_p[T_BIG_INTEGER] = true;
1737   t_real_p[T_BIG_RATIO] = true;
1738   t_real_p[T_BIG_REAL] = true;
1739 
1740   t_big_number_p[T_BIG_INTEGER] = true;
1741   t_big_number_p[T_BIG_RATIO] = true;
1742   t_big_number_p[T_BIG_REAL] = true;
1743   t_big_number_p[T_BIG_COMPLEX] = true;
1744 
1745   t_structure_p[T_PAIR] = true;
1746   t_structure_p[T_VECTOR] = true;
1747   t_structure_p[T_HASH_TABLE] = true;
1748   t_structure_p[T_SLOT] = true;
1749   t_structure_p[T_LET] = true;
1750   t_structure_p[T_ITERATOR] = true;
1751   t_structure_p[T_C_POINTER] = true;
1752   t_structure_p[T_C_OBJECT] = true;
1753 
1754   t_sequence_p[T_NIL] = true;
1755   t_sequence_p[T_PAIR] = true;
1756   t_sequence_p[T_STRING] = true;
1757   t_sequence_p[T_VECTOR] = true;
1758   t_sequence_p[T_INT_VECTOR] = true;
1759   t_sequence_p[T_FLOAT_VECTOR] = true;
1760   t_sequence_p[T_BYTE_VECTOR] = true;
1761   t_sequence_p[T_HASH_TABLE] = true;
1762   t_sequence_p[T_LET] = true;
1763   t_sequence_p[T_C_OBJECT] = true;
1764 
1765   t_mappable_p[T_PAIR] = true;
1766   t_mappable_p[T_STRING] = true;
1767   t_mappable_p[T_VECTOR] = true;
1768   t_mappable_p[T_INT_VECTOR] = true;
1769   t_mappable_p[T_FLOAT_VECTOR] = true;
1770   t_mappable_p[T_BYTE_VECTOR] = true;
1771   t_mappable_p[T_HASH_TABLE] = true;
1772   t_mappable_p[T_LET] = true;
1773   t_mappable_p[T_C_OBJECT] = true;
1774   t_mappable_p[T_ITERATOR] = true;
1775   t_mappable_p[T_C_MACRO] = true;
1776   t_mappable_p[T_MACRO] = true;
1777   t_mappable_p[T_BACRO] = true;
1778   t_mappable_p[T_MACRO_STAR] = true;
1779   t_mappable_p[T_BACRO_STAR] = true;
1780   t_mappable_p[T_CLOSURE] = true;
1781   t_mappable_p[T_CLOSURE_STAR] = true;
1782 
1783   t_vector_p[T_VECTOR] = true;
1784   t_vector_p[T_INT_VECTOR] = true;
1785   t_vector_p[T_FLOAT_VECTOR] = true;
1786   t_vector_p[T_BYTE_VECTOR] = true;
1787 
1788   t_applicable_p[T_PAIR] = true;
1789   t_applicable_p[T_STRING] = true;
1790   t_applicable_p[T_VECTOR] = true;
1791   t_applicable_p[T_INT_VECTOR] = true;
1792   t_applicable_p[T_FLOAT_VECTOR] = true;
1793   t_applicable_p[T_BYTE_VECTOR] = true;
1794   t_applicable_p[T_HASH_TABLE] = true;
1795   t_applicable_p[T_ITERATOR] = true;
1796   t_applicable_p[T_LET] = true;
1797   t_applicable_p[T_C_OBJECT] = true;
1798   t_applicable_p[T_C_MACRO] = true;
1799   t_applicable_p[T_MACRO] = true;
1800   t_applicable_p[T_BACRO] = true;
1801   t_applicable_p[T_MACRO_STAR] = true;
1802   t_applicable_p[T_BACRO_STAR] = true;
1803   t_applicable_p[T_SYNTAX] = true;
1804   t_applicable_p[T_C_FUNCTION] = true;
1805   t_applicable_p[T_C_FUNCTION_STAR] = true;
1806   t_applicable_p[T_C_ANY_ARGS_FUNCTION] = true;
1807   t_applicable_p[T_C_OPT_ARGS_FUNCTION] = true;
1808   t_applicable_p[T_C_RST_ARGS_FUNCTION] = true;
1809   t_applicable_p[T_CLOSURE] = true;
1810   t_applicable_p[T_CLOSURE_STAR] = true;
1811   t_applicable_p[T_GOTO] = true;
1812   t_applicable_p[T_CONTINUATION] = true;
1813 
1814   /* t_procedure_p[T_C_OBJECT] = true; */
1815   t_procedure_p[T_C_FUNCTION] = true;
1816   t_procedure_p[T_C_FUNCTION_STAR] = true;
1817   t_procedure_p[T_C_ANY_ARGS_FUNCTION] = true;
1818   t_procedure_p[T_C_OPT_ARGS_FUNCTION] = true;
1819   t_procedure_p[T_C_RST_ARGS_FUNCTION] = true;
1820   t_procedure_p[T_CLOSURE] = true;
1821   t_procedure_p[T_CLOSURE_STAR] = true;
1822   t_procedure_p[T_GOTO] = true;
1823   t_procedure_p[T_CONTINUATION] = true;
1824 
1825   t_any_macro_p[T_C_MACRO] = true;
1826   t_any_macro_p[T_MACRO] = true;
1827   t_any_macro_p[T_BACRO] = true;
1828   t_any_macro_p[T_MACRO_STAR] = true;
1829   t_any_macro_p[T_BACRO_STAR] = true;
1830 
1831   t_any_closure_p[T_CLOSURE] = true;
1832   t_any_closure_p[T_CLOSURE_STAR] = true;
1833 
1834   t_has_closure_let[T_MACRO] = true;
1835   t_has_closure_let[T_BACRO] = true;
1836   t_has_closure_let[T_MACRO_STAR] = true;
1837   t_has_closure_let[T_BACRO_STAR] = true;
1838   t_has_closure_let[T_CLOSURE] = true;
1839   t_has_closure_let[T_CLOSURE_STAR] = true;
1840 
1841   t_simple_p[T_NIL] = true;
1842   /* t_simple_p[T_UNDEFINED] = true; */ /* only #<undefined> itself will work with eq? */
1843   t_simple_p[T_EOF] = true;
1844   t_simple_p[T_BOOLEAN] = true;
1845   t_simple_p[T_CHARACTER] = true;
1846   t_simple_p[T_SYMBOL] = true;
1847   t_simple_p[T_SYNTAX] = true;
1848   t_simple_p[T_C_MACRO] = true;
1849   t_simple_p[T_C_FUNCTION] = true;
1850   t_simple_p[T_C_FUNCTION_STAR] = true;
1851   t_simple_p[T_C_ANY_ARGS_FUNCTION] = true;
1852   t_simple_p[T_C_OPT_ARGS_FUNCTION] = true;
1853   t_simple_p[T_C_RST_ARGS_FUNCTION] = true;
1854   /* not completely sure about the next ones */
1855   t_simple_p[T_LET] = true;
1856   t_simple_p[T_INPUT_PORT] = true;
1857   t_simple_p[T_OUTPUT_PORT] = true;
1858 
1859 #if S7_DEBUGGING
1860   t_freeze_p[T_STRING] = true;
1861   t_freeze_p[T_BYTE_VECTOR] = true;
1862   t_freeze_p[T_VECTOR] = true;
1863   t_freeze_p[T_FLOAT_VECTOR] = true;
1864   t_freeze_p[T_INT_VECTOR] = true;
1865   t_freeze_p[T_UNDEFINED] = true;
1866   t_freeze_p[T_C_OBJECT] = true;
1867   t_freeze_p[T_HASH_TABLE] = true;
1868   t_freeze_p[T_C_FUNCTION] = true;
1869   t_freeze_p[T_CONTINUATION] = true;
1870   t_freeze_p[T_INPUT_PORT] = true;
1871   t_freeze_p[T_OUTPUT_PORT] = true;
1872 #endif
1873 }
1874 
1875 void s7_show_history(s7_scheme *sc);
1876 
1877 #if WITH_HISTORY
1878 #define current_code(Sc)               car(Sc->cur_code)
1879 #define set_current_code(Sc, Code)     do {Sc->cur_code = cdr(Sc->cur_code); set_car(Sc->cur_code, T_Pos(Code));} while (0)
1880 #define replace_current_code(Sc, Code) set_car(Sc->cur_code, T_Pos(Code))
1881 #define mark_current_code(Sc)          do {int32_t i; s7_pointer p; for (p = Sc->cur_code, i = 0; i < Sc->history_size; i++, p = cdr(p)) gc_mark(car(p));} while (0)
1882 #else
1883 #define current_code(Sc)               Sc->cur_code
1884 #define set_current_code(Sc, Code)     Sc->cur_code = T_Pos(Code)
1885 #define replace_current_code(Sc, Code) Sc->cur_code = T_Pos(Code)
1886 #define mark_current_code(Sc)          gc_mark(Sc->cur_code)
1887 #endif
1888 
1889 #define full_type(p)  ((p)->tf.flag)
1890 #define typesflag(p) ((p)->tf.sflag)
1891 #define TYPE_MASK    0xff
1892 
1893 #if S7_DEBUGGING
1894   static bool printing_gc_info = false;
1895   static void print_gc_info(s7_scheme *sc, s7_pointer obj, int32_t line);
1896   static s7_pointer check_ref(s7_pointer p, uint8_t expected_type, const char *func, int32_t line, const char *func1, const char *func2);
1897   static s7_pointer check_ref7(s7_pointer p, const char *func, int32_t line);
1898   static s7_pointer check_ref16(s7_pointer p, const char *func, int32_t line);
1899   static s7_pointer check_nref(s7_pointer p, const char *func, int32_t line);
1900   static s7_pointer check_let_ref(s7_pointer p, uint64_t role, const char *func, int32_t line);
1901 
1902   #define unchecked_type(p) ((p)->tf.type_field)
1903 #if WITH_GCC
1904   #define type(p) ({uint8_t _t_; _t_ = (p)->tf.type_field; if ((!printing_gc_info) && ((_t_ == T_FREE) || (_t_ >= NUM_TYPES))) print_gc_info(cur_sc, p, __LINE__); _t_;})
1905 #else
1906   #define type(p) (p)->tf.type_field
1907 #endif
1908   #define set_full_type(p, f) set_type_1(p, f, __func__, __LINE__)
1909   /* these check most s7_cell field references (and many type bits) for consistency */
1910   #define T_Int(P) check_ref(P, T_INTEGER,           __func__, __LINE__, NULL, NULL)
1911   #define T_Rel(P) check_ref(P, T_REAL,              __func__, __LINE__, NULL, NULL)
1912   #define T_Frc(P) check_ref2(P, T_RATIO, T_INTEGER, __func__, __LINE__, NULL, NULL)
1913   #define T_Cmp(P) check_ref(P, T_COMPLEX,           __func__, __LINE__, NULL, NULL)
1914   #define T_Bgi(P) check_ref(P, T_BIG_INTEGER,       __func__, __LINE__, "sweep", NULL)
1915   #define T_Bgr(P) check_ref(P, T_BIG_REAL,          __func__, __LINE__, "sweep", NULL)
1916   #define T_Bgf(P) check_ref(P, T_BIG_RATIO,         __func__, __LINE__, "sweep", NULL)
1917   #define T_Bgz(P) check_ref(P, T_BIG_COMPLEX,       __func__, __LINE__, "sweep", NULL)
1918   #define T_Chr(P) check_ref(P, T_CHARACTER,         __func__, __LINE__, NULL, NULL)
1919   #define T_Undf(P) check_ref(P, T_UNDEFINED,        __func__, __LINE__, "sweep", NULL)
1920   #define T_Eof(P) check_ref(P, T_EOF,               __func__, __LINE__, "sweep", NULL)
1921   #define T_Ctr(P) check_ref(P, T_COUNTER,           __func__, __LINE__, NULL, NULL)
1922   #define T_Ptr(P) check_ref(P, T_C_POINTER,         __func__, __LINE__, NULL, NULL)
1923   #define T_Got(P) check_ref(P, T_GOTO,              __func__, __LINE__, NULL, NULL)
1924   #define T_Stk(P) check_ref(P, T_STACK,             __func__, __LINE__, NULL, NULL)
1925   #define T_Pair(P) check_ref(P, T_PAIR,             __func__, __LINE__, NULL, NULL)
1926   #define T_Cat(P) check_ref(P, T_CATCH,             __func__, __LINE__, NULL, NULL)
1927   #define T_Dyn(P) check_ref(P, T_DYNAMIC_WIND,      __func__, __LINE__, NULL, NULL)
1928   #define T_Slt(P) check_ref(P, T_SLOT,              __func__, __LINE__, NULL, NULL)
1929   #define T_Sld(P) check_ref2(P, T_SLOT, T_UNDEFINED,__func__, __LINE__, NULL, NULL)
1930   #define T_Syn(P) check_ref(P, T_SYNTAX,            __func__, __LINE__, NULL, NULL)
1931   #define T_CMac(P) check_ref(P, T_C_MACRO,          __func__, __LINE__, NULL, NULL)
1932   #define T_Let(P) check_ref(P, T_LET,               __func__, __LINE__, NULL, NULL)
1933   #define T_Ran(P) check_ref(P, T_RANDOM_STATE,      __func__, __LINE__, NULL, NULL)
1934   #define T_Lst(P) check_ref2(P, T_PAIR, T_NIL,      __func__, __LINE__, "gc", NULL)
1935   #define T_Str(P) check_ref(P, T_STRING,            __func__, __LINE__, "sweep", NULL)
1936   #define T_BVc(P) check_ref(P, T_BYTE_VECTOR,       __func__, __LINE__, "sweep", NULL)
1937   #define T_Obj(P) check_ref(P, T_C_OBJECT,          __func__, __LINE__, "sweep", "s7_c_object_value")
1938   #define T_Hsh(P) check_ref(P, T_HASH_TABLE,        __func__, __LINE__, "sweep", "free_hash_table")
1939   #define T_Itr(P) check_ref(P, T_ITERATOR,          __func__, __LINE__, "sweep", "process_iterator")
1940   #define T_Con(P) check_ref(P, T_CONTINUATION,      __func__, __LINE__, "sweep", "process_continuation")
1941   #define T_Fvc(P) check_ref(P, T_FLOAT_VECTOR,      __func__, __LINE__, "sweep", NULL)
1942   #define T_Ivc(P) check_ref(P, T_INT_VECTOR,        __func__, __LINE__, "sweep", NULL)
1943   #define T_Nvc(P) check_ref(P, T_VECTOR,            __func__, __LINE__, "sweep", NULL)
1944   #define T_Sym(P) check_ref(P, T_SYMBOL,            __func__, __LINE__, "sweep", "remove_gensym_from_symbol_table")
1945   #define T_Fst(P) check_ref(P, T_C_FUNCTION_STAR,   __func__, __LINE__, NULL, NULL)
1946   #define T_Pcs(P) check_ref2(P, T_PAIR, T_CLOSURE_STAR, __func__, __LINE__, NULL, NULL)
1947   #define T_Prt(P) check_ref3(P,                     __func__, __LINE__) /* input|output_port */
1948   #define T_Vec(P) check_ref4(P,                     __func__, __LINE__) /* any vector */
1949   #define T_SVec(P) check_ref13(P,                   __func__, __LINE__) /* subvector */
1950   #define T_Clo(P) check_ref5(P,                     __func__, __LINE__) /* has closure let */
1951   #define T_Fnc(P) check_ref6(P,                     __func__, __LINE__) /* any c_function|c_macro */
1952   #define T_Prc(P) check_ref14(P,                    __func__, __LINE__) /* any procedure or #f */
1953   #define T_Num(P) check_ref7(P,                     __func__, __LINE__) /* any number (not bignums) */
1954   #define T_Seq(P) check_ref8(P,                     __func__, __LINE__) /* any sequence or structure */
1955   #define T_Met(P) check_ref9(P,                     __func__, __LINE__) /* anything that might contain a method */
1956   #define T_Arg(P) check_ref10(P,                    __func__, __LINE__) /* closure arg (list, symbol) */
1957   #define T_App(P) check_ref11(sc, P,                __func__, __LINE__) /* applicable or #f */
1958   #define T_Sln(P) check_ref12(P,                    __func__, __LINE__) /* slot or nil */
1959   #define T_Nmv(P) check_ref15(P,                    __func__, __LINE__) /* not multiple-value, not free */
1960   #define T_Lid(P) check_ref16(P,                    __func__, __LINE__) /* let/nil */
1961   #define T_Mac(P) check_ref17(P,                    __func__, __LINE__) /* and non-C macro */
1962   #define T_Pos(P) check_nref(P,                     __func__, __LINE__) /* not free */
1963   #define T_Any(P) check_cell(sc, P,                 __func__, __LINE__) /* any cell */
1964 
1965 #else
1966   /* if not debugging, all those checks go away */
1967   #define T_Int(P)  P
1968   #define T_Rel(P)  P
1969   #define T_Frc(P)  P
1970   #define T_Cmp(P)  P
1971   #define T_Bgi(P)  P
1972   #define T_Bgr(P)  P
1973   #define T_Bgf(P)  P
1974   #define T_Bgz(P)  P
1975   #define T_Str(P)  P
1976   #define T_BVc(P)  P
1977   #define T_Syn(P)  P
1978   #define T_Chr(P)  P
1979   #define T_Undf(P) P
1980   #define T_Eof(P) P
1981   #define T_Obj(P)  P
1982   #define T_Ctr(P)  P
1983   #define T_Hsh(P)  P
1984   #define T_Itr(P)  P
1985   #define T_Ptr(P)  P
1986   #define T_Got(P)  P
1987   #define T_Con(P)  P
1988   #define T_Stk(P)  P
1989   #define T_Prt(P)  P
1990   #define T_Ivc(P)  P
1991   #define T_Fvc(P)  P
1992   #define T_Nvc(P)  P
1993   #define T_Vec(P)  P
1994   #define T_SVec(P) P
1995   #define T_Pair(P) P
1996   #define T_Ran(P)  P
1997   #define T_Dyn(P)  P
1998   #define T_Cat(P)  P
1999   #define T_Clo(P)  P
2000   #define T_Fnc(P)  P
2001   #define T_Prc(P)  P
2002   #define T_Fst(P)  P
2003   #define T_Pcs(P)  P
2004   #define T_Slt(P)  P
2005   #define T_Sln(P)  P
2006   #define T_Sld(P)  P
2007   #define T_Sym(P)  P
2008   #define T_Let(P)  P
2009   #define T_Lid(P)  P
2010   #define T_Lst(P)  P
2011   #define T_Num(P)  P
2012   #define T_Seq(P)  P
2013   #define T_Met(P)  P
2014   #define T_Mac(P)  P
2015   #define T_CMac(P) P
2016   #define T_Arg(P)  P
2017   #define T_App(P)  P
2018   #define T_Pos(P)  P
2019   #define T_Nmv(P)  P
2020   #define T_Any(P)  P
2021 
2022   #define unchecked_type(p)            ((p)->tf.type_field)
2023   #define type(p)                      ((p)->tf.type_field)
2024   #define set_full_type(p, f)          full_type(p) = f
2025 #endif
2026 #define signed_type(p)                 (p)->tf.signed_flag
2027 
2028 #define is_number(P)                   t_number_p[type(P)]
2029 #define is_small_real(P)               t_small_real_p[type(P)]
2030 #define is_real(P)                     t_real_p[type(P)]
2031 #define is_rational(P)                 t_rational_p[type(P)]
2032 #define is_big_number(p)               t_big_number_p[type(p)]
2033 #define is_t_integer(p)                (type(p) == T_INTEGER)
2034 #define is_t_ratio(p)                  (type(p) == T_RATIO)
2035 #define is_t_real(p)                   (type(p) == T_REAL)
2036 #define is_t_complex(p)                (type(p) == T_COMPLEX)
2037 #define is_t_big_integer(p)            (type(p) == T_BIG_INTEGER)
2038 #define is_t_big_ratio(p)              (type(p) == T_BIG_RATIO)
2039 #define is_t_big_real(p)               (type(p) == T_BIG_REAL)
2040 #define is_t_big_complex(p)            (type(p) == T_BIG_COMPLEX)
2041 
2042 #define is_free(p)                     (type(p) == T_FREE)
2043 #define is_free_and_clear(p)           (full_type(p) == T_FREE)
2044 #define is_simple(P)                   t_simple_p[type(P)]  /* eq? */
2045 #define has_structure(P)               ((t_structure_p[type(P)]) && ((!is_normal_vector(P)) || (!has_simple_elements(P))))
2046 
2047 #define is_any_macro(P)                t_any_macro_p[type(P)]
2048 #define is_any_closure(P)              t_any_closure_p[type(P)]
2049 #define is_any_procedure(P)            (type(P) >= T_CLOSURE)
2050 #define has_closure_let(P)             t_has_closure_let[type(P)]
2051 
2052 #define is_simple_sequence(P)          (t_sequence_p[type(P)])
2053 #define is_sequence(P)                 ((t_sequence_p[type(P)]) || (has_methods(P)))
2054 #define is_mutable_sequence(P)         (((t_sequence_p[type(P)]) || (has_methods(P))) && (!is_immutable(P)))
2055 #define is_mappable(P)                 (t_mappable_p[type(P)])
2056 #define is_applicable(P)               (t_applicable_p[type(P)])
2057 /* this misses #() which is not applicable to anything, and "", and inapplicable c-objects like random-state */
2058 #define is_procedure(p)                ((t_procedure_p[type(p)]) || ((is_c_object(p)) && (is_safe_procedure(p))))
2059 #define is_t_procedure(p)              (t_procedure_p[type(p)])
2060 
2061 /* the layout of these bits does matter in several cases -- don't shadow SYNTACTIC_PAIR and OPTIMIZED_PAIR */
2062 #define TYPE_BITS                      8
2063 
2064 #define set_type_bit(p, b)             full_type(p) |= (b)
2065 #define clear_type_bit(p, b)           full_type(p) &= (~(b))
2066 #define has_type_bit(p, b)             ((full_type(p) & (b)) != 0)
2067 
2068 #define set_type0_bit(p, b)            typesflag(p) |= (b)
2069 #define clear_type0_bit(p, b)          typesflag(p) &= (~(b))
2070 #define has_type0_bit(p, b)            ((typesflag(p) & (b)) != 0)
2071 
2072 #define set_type1_bit(p, b)            (p)->tf.opts.high_flag |= (b)
2073 #define clear_type1_bit(p, b)          (p)->tf.opts.high_flag &= (~(b))
2074 #define has_type1_bit(p, b)            (((p)->tf.opts.high_flag & (b)) != 0)
2075 
2076 #define T_SYNTACTIC                    (1 << (TYPE_BITS + 1))
2077 #define is_syntactic(p)                has_type0_bit(T_Pos(p), T_SYNTACTIC)
2078 #define is_syntactic_symbol(p)         (typesflag(T_Pos(p)) == (uint16_t)(T_SYMBOL | T_SYNTACTIC))
2079 #define is_syntactic_pair(p)           (typesflag(T_Pos(p)) == (uint16_t)(T_PAIR | T_SYNTACTIC))
2080 /* this marks symbols that represent syntax objects, it should be in the second byte */
2081 
2082 #define T_SIMPLE_ARG_DEFAULTS          (1 << (TYPE_BITS + 2))
2083 #define lambda_has_simple_defaults(p)  has_type_bit(T_Pair(closure_body(p)), T_SIMPLE_ARG_DEFAULTS)
2084 #define lambda_set_simple_defaults(p)  set_type_bit(T_Pair(p), T_SIMPLE_ARG_DEFAULTS)
2085 /* are all lambda* default values simple? This is set on closure_body, so it doesn't mess up closure_is_ok_1 */
2086 
2087 #define T_LIST_IN_USE                  T_SIMPLE_ARG_DEFAULTS
2088 #define list_is_in_use(p)              has_type0_bit(T_Pair(p), T_LIST_IN_USE)
2089 #define set_list_in_use(p)             set_type_bit(T_Pair(p), T_LIST_IN_USE)
2090 #define clear_list_in_use(p)           do {clear_type_bit(T_Pair(p), T_LIST_IN_USE); sc->current_safe_list = 0;} while (0)
2091 /* if (!is_immutable(p)) free_vlist(sc, p) seems plausible here, but it got no hits in s7test and other cases */
2092 
2093 #define T_ONE_FORM                     T_SIMPLE_ARG_DEFAULTS
2094 #define set_closure_has_one_form(p)    set_type_bit(T_Clo(p), T_ONE_FORM)
2095 #define T_MULTIFORM                    (1 << (TYPE_BITS + 0))
2096 #define set_closure_has_multiform(p)   set_type_bit(T_Clo(p), T_MULTIFORM)
2097 #define T_ONE_FORM_FX_ARG              (T_ONE_FORM | T_MULTIFORM)
2098 #define set_closure_one_form_fx_arg(p) set_type_bit(T_Clo(p), T_ONE_FORM_FX_ARG)
2099 /* can't use T_HAS_FX here because closure_is_ok wants to examine typesflag */
2100 
2101 #define T_OPTIMIZED                    (1 << (TYPE_BITS + 3))
2102 #define set_optimized(p)               set_type0_bit(T_Pair(p), T_OPTIMIZED)
2103 #define clear_optimized(p)             clear_type0_bit(T_Pair(p), T_OPTIMIZED | T_SYNTACTIC | T_HAS_FX | T_HAS_FN)
2104 #define OPTIMIZED_PAIR                 (uint16_t)(T_PAIR | T_OPTIMIZED)
2105 #define is_optimized(p)                (typesflag(T_Pos(p)) == OPTIMIZED_PAIR)
2106 /* optimizer flag for an expression that has optimization info, it should be in the second byte */
2107 
2108 #define T_SCOPE_SAFE                   T_OPTIMIZED
2109 #define is_scope_safe(p)               has_type_bit(T_Fnc(p), T_SCOPE_SAFE)
2110 #define set_scope_safe(p)              set_type_bit(T_Fnc(p), T_SCOPE_SAFE)
2111 
2112 #define T_SAFE_CLOSURE                 (1 << (TYPE_BITS + 4))
2113 #define is_safe_closure(p)             has_type0_bit(T_Clo(p), T_SAFE_CLOSURE)
2114 #define set_safe_closure(p)            set_type0_bit(T_Clo(p), T_SAFE_CLOSURE)
2115 #define is_safe_closure_body(p)        has_type0_bit(T_Pair(p), T_SAFE_CLOSURE)
2116 #define set_safe_closure_body(p)       set_type0_bit(T_Pair(p), T_SAFE_CLOSURE)
2117 #define clear_safe_closure_body(p)     clear_type0_bit(T_Pair(p), T_SAFE_CLOSURE)
2118 
2119 /* optimizer flag for a closure body that is completely simple (every expression is safe)
2120  *   set_safe_closure happens only in define_funchcecked, clear only in procedure_source, bits only here
2121  *   this has to be separate from T_SAFE_PROCEDURE, and should be in the second byte (closure_is_ok_1 checks typesflag).
2122  * define -> optimize_lambda sets safe -> define_funchecked -> make_funclet for the let
2123  *   similarly, named let -> optimize_lambda, then let creates the let if safe
2124  *   thereafter, optimizer uses OP_SAFE_CLOSURE* which calls update_let*
2125  */
2126 
2127 #define T_DONT_EVAL_ARGS               (1 << (TYPE_BITS + 5))
2128 #define dont_eval_args(p)              has_type0_bit(T_Pos(p), T_DONT_EVAL_ARGS)
2129 /* this marks things that don't evaluate their arguments */
2130 
2131 #define T_EXPANSION                    (1 << (TYPE_BITS + 6))
2132 #define is_expansion(p)                has_type0_bit(T_Any(p), T_EXPANSION)
2133 #define clear_expansion(p)             clear_type0_bit(T_Sym(p), T_EXPANSION)
2134 /* this marks the symbol and its run-time macro value, distinguishing it from an ordinary macro */
2135 
2136 #define T_MULTIPLE_VALUE               (1 << (TYPE_BITS + 7))
2137 #define is_multiple_value(p)           has_type0_bit(T_Pos(p), T_MULTIPLE_VALUE)
2138 #define set_multiple_value(p)          set_type0_bit(T_Pair(p), T_MULTIPLE_VALUE)
2139 #define clear_multiple_value(p)        clear_type0_bit(T_Pair(p), T_MULTIPLE_VALUE)
2140 #define multiple_value(p)              p
2141 /* this bit marks a list (from "values") that is waiting for a chance to be spliced into its caller's argument list.
2142  *   It is normally on only for a very short time.
2143  */
2144 
2145 #define T_MATCHED                      T_MULTIPLE_VALUE
2146 #define is_matched_pair(p)             has_type0_bit(T_Pair(p), T_MATCHED)
2147 #define clear_match_pair(p)            clear_type0_bit(T_Pair(p), T_MATCHED)
2148 #define set_match_pair(p)              set_type0_bit(T_Pair(p), T_MATCHED)
2149 #define set_match_symbol(p)            set_type0_bit(T_Sym(p), T_MATCHED)
2150 #define is_matched_symbol(p)           has_type0_bit(T_Sym(p), T_MATCHED)
2151 #define clear_match_symbol(p)          clear_type0_bit(T_Sym(p), T_MATCHED)
2152 
2153 #define T_GLOBAL                       (1 << (TYPE_BITS + 8))
2154 #define T_LOCAL                        (1 << (TYPE_BITS + 12))
2155 #define is_global(p)                   has_type_bit(T_Sym(p), T_GLOBAL)
2156 #define set_global(p)                  do {if ((full_type(T_Sym(p)) & T_LOCAL) == 0) full_type(p) |= T_GLOBAL;} while (0)
2157 /* T_LOCAL marks a symbol that has been used locally */
2158 /* T_GLOBAL marks something defined (bound) at the top-level, and never defined locally */
2159 
2160 #if 0
2161   /* to find who is stomping on our symbols: */
2162   static void set_local_1(s7_scheme *sc, s7_pointer symbol, const char *func, int32_t line)
2163   {
2164     if (is_global(symbol))
2165       {
2166 	fprintf(stderr, "%s[%d]: %s%s%s in %s\n",
2167 		func, line,
2168 		BOLD_TEXT, s7_object_to_c_string(sc, symbol), UNBOLD_TEXT,
2169 		display_80(sc->cur_code));
2170 	/* gdb_break(); */
2171       }
2172     full_type(symbol) = (full_type(symbol) & ~(T_DONT_EVAL_ARGS | T_GLOBAL | T_SYNTACTIC));
2173   }
2174   #define set_local(Symbol) set_local_1(sc, Symbol, __func__, __LINE__)
2175 #else
2176 #define set_local(p)                   full_type(T_Sym(p)) = ((full_type(p) | T_LOCAL) & ~(T_DONT_EVAL_ARGS | T_GLOBAL | T_SYNTACTIC))
2177 #endif
2178 
2179 #define T_HIGH_C                       T_LOCAL
2180 #define has_high_c(p)                  has_type_bit(T_Pair(p), T_HIGH_C)
2181 #define set_has_high_c(p)              set_type_bit(T_Pair(p), T_HIGH_C)
2182 
2183 #define T_TC                           T_LOCAL
2184 #define has_tc(p)                      has_type_bit(T_Pair(p), T_TC)
2185 #define set_has_tc(p)                  set_type_bit(T_Pair(p), T_TC)
2186 
2187 #define T_UNSAFE_DO                    T_GLOBAL
2188 #define is_unsafe_do(p)                has_type_bit(T_Pair(p), T_UNSAFE_DO)
2189 #define set_unsafe_do(p)               set_type_bit(T_Pair(p), T_UNSAFE_DO)
2190 /* marks do-loops that resist optimization */
2191 
2192 #define T_DOX_SLOT1                    T_GLOBAL
2193 #define has_dox_slot1(p)               has_type_bit(T_Let(p), T_DOX_SLOT1)
2194 #define set_has_dox_slot1(p)           set_type_bit(T_Let(p), T_DOX_SLOT1)
2195 /* marks a let that includes the dox_slot1 */
2196 
2197 #define T_COLLECTED                    (1 << (TYPE_BITS + 9))
2198 #define is_collected(p)                has_type_bit(T_Seq(p), T_COLLECTED)
2199 #define is_collected_unchecked(p)      has_type_bit(p, T_COLLECTED)
2200 #define set_collected(p)               set_type_bit(T_Seq(p), T_COLLECTED)
2201 /* #define clear_collected(p)          clear_type_bit(T_Seq(p), T_COLLECTED) */
2202 /* this is a transient flag used by the printer to catch cycles.  It affects only objects that have structure.
2203  *   We can't use a low bit (bit 7 for example), because collect_shared_info inspects the object's type.
2204  */
2205 
2206 #define T_LOCATION                     (1 << (TYPE_BITS + 10))
2207 #define has_location(p)                has_type_bit(T_Pair(p), T_LOCATION)
2208 #define set_has_location(p)            set_type_bit(T_Pair(p), T_LOCATION)
2209 /* pair in question has line/file/position info added during read, or the environment has function placement info
2210  *   this bit should not be in the first byte -- SYNTACTIC_PAIR ignores it.
2211  */
2212 
2213 #define T_LOADER_PORT                  T_LOCATION
2214 #define is_loader_port(p)              has_type_bit(T_Prt(p), T_LOADER_PORT)
2215 #define set_loader_port(p)             set_type_bit(T_Prt(p), T_LOADER_PORT)
2216 #define clear_loader_port(p)           clear_type_bit(T_Prt(p), T_LOADER_PORT)
2217 /* to block random load-time reads from screwing up the load process, this bit marks a port used by the loader */
2218 
2219 #define T_HAS_SETTER                   T_LOCATION
2220 #define symbol_has_setter(p)           has_type_bit(T_Sym(p), T_HAS_SETTER)
2221 #define symbol_set_has_setter(p)       set_type_bit(T_Sym(p), T_HAS_SETTER)
2222 #define slot_has_setter(p)             has_type_bit(T_Slt(p), T_HAS_SETTER)
2223 #define slot_set_has_setter(p)         set_type_bit(T_Slt(p), T_HAS_SETTER)
2224 /* marks a slot that has a setter or symbol that might have a setter */
2225 
2226 #define T_WITH_LET_LET                 T_LOCATION
2227 #define is_with_let_let(p)             has_type_bit(T_Let(p), T_WITH_LET_LET)
2228 #define set_with_let_let(p)            set_type_bit(T_Let(p), T_WITH_LET_LET)
2229 /* marks a let that is the argument to with-let */
2230 
2231 #define T_SIMPLE_DEFAULTS              T_LOCATION
2232 #define c_func_has_simple_defaults(p)  has_type_bit(T_Fst(p), T_SIMPLE_DEFAULTS)
2233 #define c_func_set_simple_defaults(p)  set_type_bit(T_Fst(p), T_SIMPLE_DEFAULTS)
2234 #define c_func_clear_simple_defaults(p) clear_type_bit(T_Fst(p), T_SIMPLE_DEFAULTS)
2235 /* flag c_func_star arg defaults that need GC protection */
2236 
2237 #define T_NO_SETTER                    T_LOCATION
2238 #define closure_no_setter(p)           has_type_bit(T_Clo(p), T_NO_SETTER)
2239 #define closure_set_no_setter(p)       set_type_bit(T_Clo(p), T_NO_SETTER)
2240 
2241 #define T_SHARED                       (1 << (TYPE_BITS + 11))
2242 #define is_shared(p)                   has_type_bit(T_Seq(p), T_SHARED)
2243 #define set_shared(p)                  set_type_bit(T_Seq(p), T_SHARED)
2244 #define is_collected_or_shared(p)      has_type_bit(p, T_COLLECTED | T_SHARED)
2245 #define clear_collected_and_shared(p)  clear_type_bit(p, T_COLLECTED | T_SHARED) /* this can clear free cells = calloc */
2246 /* T_LOCAL is bit 12 */
2247 
2248 #define T_SAFE_PROCEDURE               (1 << (TYPE_BITS + 13))
2249 #define is_safe_procedure(p)           has_type_bit(T_Pos(p), T_SAFE_PROCEDURE) /* used in is_procedure so can't be T_App */
2250 #define is_safe_or_scope_safe_procedure(p) ((full_type(T_Fnc(p)) & (T_SCOPE_SAFE | T_SAFE_PROCEDURE)) != 0)
2251 /* applicable objects that do not return or modify their arg list directly (no :rest arg in particular),
2252  *    and that can't call themselves either directly or via s7_call, and that don't mess with the stack.
2253  */
2254 
2255 #define T_CHECKED                      (1 << (TYPE_BITS + 14))
2256 #define set_checked(p)                 set_type_bit(T_Pair(p), T_CHECKED)
2257 #define is_checked(p)                  has_type_bit(T_Pair(p), T_CHECKED)
2258 #define clear_checked(p)               clear_type_bit(T_Pair(p), T_CHECKED)
2259 #define set_checked_slot(p)            set_type_bit(T_Slt(p), T_CHECKED)
2260 #define is_checked_slot(p)             has_type_bit(T_Slt(p), T_CHECKED)
2261 #define clear_checked_slot(p)          clear_type_bit(T_Slt(p), T_CHECKED)
2262 
2263 #define T_ALL_INTEGER                  T_CHECKED
2264 #define is_all_integer(p)              has_type_bit(T_Sym(p), T_ALL_INTEGER)
2265 #define set_all_integer(p)             set_type_bit(T_Sym(p), T_ALL_INTEGER)
2266 
2267 #define T_UNSAFE                       (1 << (TYPE_BITS + 15))
2268 #define set_unsafe(p)                  set_type_bit(T_Pair(p), T_UNSAFE)
2269 #define set_unsafely_optimized(p)      full_type(T_Pair(p)) = (full_type(p) | T_UNSAFE | T_OPTIMIZED)
2270 #define is_unsafe(p)                   has_type_bit(T_Pair(p), T_UNSAFE)
2271 #define clear_unsafe(p)                clear_type_bit(T_Pair(p), T_UNSAFE)
2272 #define is_safely_optimized(p)         ((full_type(T_Pair(p)) & (T_OPTIMIZED | T_UNSAFE)) == T_OPTIMIZED) /* was T_Pos 30-Jan-21 */
2273 /* optimizer flag saying "this expression is not completely self-contained.  It might involve the stack, etc" */
2274 
2275 #define T_CLEAN_SYMBOL                 T_UNSAFE
2276 #define is_clean_symbol(p)             has_type_bit(T_Sym(p), T_CLEAN_SYMBOL)
2277 #define set_clean_symbol(p)            set_type_bit(T_Sym(p), T_CLEAN_SYMBOL)
2278 /* set if we know the symbol name can be printed without quotes (slashification) */
2279 
2280 #define T_HAS_STEPPER                  T_UNSAFE
2281 #define has_stepper(p)                 has_type_bit(T_Slt(p), T_HAS_STEPPER)
2282 #define set_has_stepper(p)             set_type_bit(T_Slt(p), T_HAS_STEPPER)
2283 
2284 #define T_DOX_SLOT2                    T_UNSAFE
2285 #define has_dox_slot2(p)               has_type_bit(T_Let(p), T_DOX_SLOT2)
2286 #define set_has_dox_slot2(p)           set_type_bit(T_Let(p), T_DOX_SLOT2)
2287 /* marks a let that includes the dox_slot2 */
2288 
2289 #define T_IMMUTABLE                    (1 << (TYPE_BITS + 16))
2290 #define is_immutable(p)                has_type_bit(T_Pos(p), T_IMMUTABLE)
2291 #define set_immutable(p)               set_type_bit(T_Pos(p), T_IMMUTABLE)
2292 #define set_immutable_let(p)           set_type_bit(T_Lid(p), T_IMMUTABLE)
2293 #define is_immutable_port(p)           has_type_bit(T_Prt(p), T_IMMUTABLE)
2294 #define is_immutable_symbol(p)         has_type_bit(T_Sym(p), T_IMMUTABLE)
2295 #define is_immutable_slot(p)           has_type_bit(T_Slt(p), T_IMMUTABLE)
2296 #define is_immutable_pair(p)           has_type_bit(T_Pair(p), T_IMMUTABLE)
2297 #define is_immutable_vector(p)         has_type_bit(T_Vec(p), T_IMMUTABLE)
2298 #define is_immutable_string(p)         has_type_bit(T_Str(p), T_IMMUTABLE)
2299 /* T_IMMUTABLE is compatible with T_MUTABLE -- the latter is an internal bit for locally mutable numbers */
2300 
2301 #define T_SETTER                       (1 << (TYPE_BITS + 17))
2302 #define set_is_setter(p)               set_type_bit(T_Sym(p), T_SETTER)
2303 #define is_setter(p)                   has_type_bit(T_Sym(p), T_SETTER)
2304 /* optimizer flag for a procedure that sets some variable (set-car! for example). */
2305 
2306 #define T_ALLOW_OTHER_KEYS             T_SETTER
2307 #define set_allow_other_keys(p)        set_type_bit(T_Pair(p), T_ALLOW_OTHER_KEYS)
2308 #define allows_other_keys(p)           has_type_bit(T_Pair(p), T_ALLOW_OTHER_KEYS)
2309 #define c_function_set_allow_other_keys(p) set_type_bit(T_Fst(p), T_ALLOW_OTHER_KEYS)
2310 #define c_function_allows_other_keys(p)    has_type_bit(T_Fst(p), T_ALLOW_OTHER_KEYS)
2311 /* marks arglist (or c_function*) that allows keyword args other than those in the parameter list;
2312  *   we can't allow (define* (f :allow-other-keys)...) because there's only one nil, and besides, it does say "other".
2313  */
2314 
2315 #define T_LET_REMOVED                  T_SETTER
2316 #define let_set_removed(p)             set_type_bit(T_Let(p), T_LET_REMOVED)
2317 #define let_removed(p)                 has_type_bit(T_Let(p), T_LET_REMOVED)
2318 /* mark lets that have been removed from the heap or checked for that possibility */
2319 
2320 #define T_HAS_EXPRESSION               T_SETTER
2321 #define slot_set_has_expression(p)     set_type_bit(T_Slt(p), T_HAS_EXPRESSION)
2322 #define slot_has_expression(p)         has_type_bit(T_Slt(p), T_HAS_EXPRESSION)
2323 
2324 #define T_MUTABLE                      (1 << (TYPE_BITS + 18))
2325 #define is_mutable_number(p)           has_type_bit(T_Num(p), T_MUTABLE)
2326 #define is_mutable_integer(p)          has_type_bit(T_Int(p), T_MUTABLE)
2327 #define clear_mutable_number(p)        clear_type_bit(T_Num(p), T_MUTABLE)
2328 #define clear_mutable_integer(p)       clear_type_bit(T_Int(p), T_MUTABLE)
2329 /* used for mutable numbers, can occur with T_IMMUTABLE (outside view vs inside) */
2330 
2331 #define T_HAS_KEYWORD                  T_MUTABLE
2332 #define has_keyword(p)                 has_type_bit(T_Sym(p), T_HAS_KEYWORD)
2333 #define set_has_keyword(p)             set_type_bit(T_Sym(p), T_HAS_KEYWORD)
2334 
2335 #define T_MARK_SEQ                     T_MUTABLE
2336 #define is_mark_seq(p)                 has_type_bit(T_Itr(p), T_MARK_SEQ)
2337 #define set_mark_seq(p)                set_type_bit(T_Itr(p), T_MARK_SEQ)
2338 /* used in iterators for GC mark of sequence */
2339 
2340 #define T_STEP_END                     T_MUTABLE
2341 #define is_step_end(p)                 has_type_bit(T_Slt(p), T_STEP_END)
2342 #define set_step_end(p)                set_type_bit(T_Slt(p), T_STEP_END)
2343 /* marks a slot that holds a do-loop's step-or-end variable, numerator=current, denominator=end */
2344 
2345 #define T_NO_CELL_OPT                  T_MUTABLE
2346 #define set_no_cell_opt(p)             set_type_bit(T_Pair(p), T_NO_CELL_OPT)
2347 #define no_cell_opt(p)                 has_type_bit(T_Pair(p), T_NO_CELL_OPT)
2348 
2349 #define T_NO_INT_OPT                   T_SETTER
2350 #define set_no_int_opt(p)              set_type_bit(T_Pair(p), T_NO_INT_OPT)
2351 #define no_int_opt(p)                  has_type_bit(T_Pair(p), T_NO_INT_OPT)
2352 
2353 #define T_NO_FLOAT_OPT                 T_UNSAFE
2354 #define set_no_float_opt(p)            set_type_bit(T_Pair(p), T_NO_FLOAT_OPT)
2355 #define no_float_opt(p)                has_type_bit(T_Pair(p), T_NO_FLOAT_OPT)
2356 
2357 #define T_NO_BOOL_OPT                  T_SAFE_STEPPER
2358 #define set_no_bool_opt(p)             set_type_bit(T_Pair(p), T_NO_BOOL_OPT)
2359 #define no_bool_opt(p)                 has_type_bit(T_Pair(p), T_NO_BOOL_OPT)
2360 
2361 #define T_INTEGER_KEYS                 T_SETTER
2362 #define set_has_integer_keys(p)        set_type_bit(T_Pair(p), T_INTEGER_KEYS)
2363 #define has_integer_keys(p)            has_type_bit(T_Pair(p), T_INTEGER_KEYS)
2364 
2365 #define T_SAFE_STEPPER                 (1 << (TYPE_BITS + 19))
2366 #define is_safe_stepper(p)             has_type_bit(T_Slt(p), T_SAFE_STEPPER)
2367 #define set_safe_stepper(p)            set_type_bit(T_Slt(p), T_SAFE_STEPPER)
2368 #define clear_safe_stepper(p)          clear_type_bit(T_Slt(p), T_SAFE_STEPPER)
2369 #define is_safe_stepper_expr(p)        has_type_bit(T_Pair(p), T_SAFE_STEPPER)
2370 #define set_safe_stepper_expr(p)       set_type_bit(T_Pair(p), T_SAFE_STEPPER)
2371 
2372 #define T_NUMBER_NAME                  T_SAFE_STEPPER
2373 #define has_number_name(p)             has_type_bit(T_Num(p), T_NUMBER_NAME)
2374 #define set_has_number_name(p)         set_type_bit(T_Num(p), T_NUMBER_NAME)
2375 /* marks numbers that have a saved version of their string representation */
2376 
2377 #define T_MAYBE_SAFE                   T_SAFE_STEPPER
2378 #define is_maybe_safe(p)               has_type_bit(T_Fnc(p), T_MAYBE_SAFE)
2379 #define set_maybe_safe(p)              set_type_bit(T_Fnc(p), T_MAYBE_SAFE)
2380 
2381 #define T_PAIR_MACRO                   T_SAFE_STEPPER
2382 #define has_pair_macro(p)              has_type_bit(T_Mac(p), T_PAIR_MACRO)
2383 #define set_has_pair_macro(p)          set_type_bit(T_Mac(p), T_PAIR_MACRO)
2384 
2385 #define T_HAS_LET_SET_FALLBACK         T_SAFE_STEPPER
2386 #define T_HAS_LET_REF_FALLBACK         T_MUTABLE
2387 #define has_let_ref_fallback(p)        ((full_type(T_Lid(p)) & (T_HAS_LET_REF_FALLBACK | T_HAS_METHODS)) == (T_HAS_LET_REF_FALLBACK | T_HAS_METHODS))
2388 #define has_let_set_fallback(p)        ((full_type(T_Lid(p)) & (T_HAS_LET_SET_FALLBACK | T_HAS_METHODS)) == (T_HAS_LET_SET_FALLBACK | T_HAS_METHODS))
2389 #define set_has_let_ref_fallback(p)    set_type_bit(T_Let(p), T_HAS_LET_REF_FALLBACK)
2390 #define set_has_let_set_fallback(p)    set_type_bit(T_Let(p), T_HAS_LET_SET_FALLBACK)
2391 #define has_let_fallback(p)            has_type_bit(T_Lid(p), (T_HAS_LET_REF_FALLBACK | T_HAS_LET_SET_FALLBACK))
2392 #define set_all_methods(p, e)          full_type(T_Let(p)) |= (full_type(e) & (T_HAS_METHODS | T_HAS_LET_REF_FALLBACK | T_HAS_LET_SET_FALLBACK))
2393 
2394 #define T_WEAK_HASH                    T_SAFE_STEPPER
2395 #define set_weak_hash_table(p)         set_type_bit(T_Hsh(p), T_WEAK_HASH)
2396 #define is_weak_hash_table(p)          has_type_bit(T_Hsh(p), T_WEAK_HASH)
2397 
2398 #define T_ALL_FLOAT                    T_SAFE_STEPPER
2399 #define is_all_float(p)                has_type_bit(T_Sym(p), T_ALL_FLOAT)
2400 #define set_all_float(p)               set_type_bit(T_Sym(p), T_ALL_FLOAT)
2401 #define set_all_integer_and_float(p)   set_type_bit(T_Sym(p), (T_ALL_INTEGER | T_ALL_FLOAT))
2402 
2403 #define T_COPY_ARGS                    (1 << (TYPE_BITS + 20))
2404 #define needs_copied_args(p)           has_type_bit(T_Pos(p), T_COPY_ARGS) /* set via explicit T_COPY_ARGS on macros etc */
2405 #define set_needs_copied_args(p)       set_type_bit(T_Pair(p), T_COPY_ARGS)
2406 #define clear_needs_copied_args(p)     clear_type_bit(T_Pair(p), T_COPY_ARGS)
2407 /* this marks something that might mess with its argument list, it should not be in the second byte */
2408 
2409 #define T_GENSYM                       (1 << (TYPE_BITS + 21))
2410 #define is_gensym(p)                   has_type_bit(T_Sym(p), T_GENSYM)
2411 /* symbol is from gensym (GC-able etc) */
2412 
2413 #define T_FUNCLET                      T_GENSYM
2414 #define is_funclet(p)                  has_type_bit(T_Let(p), T_FUNCLET)
2415 #define set_funclet(p)                 set_type_bit(T_Let(p), T_FUNCLET)
2416 /* this marks a funclet */
2417 
2418 #define T_HASH_CHOSEN                  T_GENSYM
2419 #define hash_chosen(p)                 has_type_bit(T_Hsh(p), T_HASH_CHOSEN)
2420 #define hash_set_chosen(p)             set_type_bit(T_Hsh(p), T_HASH_CHOSEN)
2421 #define hash_clear_chosen(p)           clear_type_bit(T_Hsh(p), T_HASH_CHOSEN)
2422 
2423 #define T_DOCUMENTED                   T_GENSYM
2424 #define is_documented(p)               has_type_bit(T_Str(p), T_DOCUMENTED)
2425 #define set_documented(p)              set_type_bit(T_Str(p), T_DOCUMENTED)
2426 /* this marks a symbol that has documentation (bit is set on name cell) */
2427 
2428 #define T_DOTTED_PAIR                  T_GENSYM
2429 #define is_dotted_pair(p)              has_type_bit(T_Lst(p), T_DOTTED_PAIR)
2430 #define pair_set_dotted(p)             set_type_bit(T_Pair(p), T_DOTTED_PAIR)
2431 /* reader indication that a list it just read was dotted */
2432 
2433 #define T_SUBVECTOR                    T_GENSYM
2434 #define is_subvector(p)                has_type_bit(T_Vec(p), T_SUBVECTOR)
2435 
2436 #define T_HAS_PENDING_VALUE            T_GENSYM
2437 #define slot_set_has_pending_value(p)  set_type_bit(T_Slt(p), T_HAS_PENDING_VALUE)
2438 #define slot_has_pending_value(p)      has_type_bit(T_Slt(p), T_HAS_PENDING_VALUE)
2439 #define slot_clear_has_pending_value(p) clear_type_bit(T_Slt(p), T_HAS_PENDING_VALUE)
2440 
2441 #define T_HAS_METHODS                  (1 << (TYPE_BITS + 22))
2442 #define has_methods(p)                 has_type_bit(T_Pos(p), T_HAS_METHODS)
2443 #define has_active_methods(sc, p)      ((has_type_bit(T_Pos(p), T_HAS_METHODS)) && (sc->has_openlets)) /* g_char #<eof> */
2444 #define set_has_methods(p)             set_type_bit(T_Met(p), T_HAS_METHODS)
2445 #define clear_has_methods(p)           clear_type_bit(T_Met(p), T_HAS_METHODS)
2446 /* this marks an environment or closure that is "open" for generic functions etc, don't reuse this bit */
2447 
2448 #define T_ITER_OK                      (1LL << (TYPE_BITS + 23))
2449 #define iter_ok(p)                     has_type_bit(T_Pos(p), T_ITER_OK) /* not T_Itr(p) here because this bit is globally unique */
2450 #define clear_iter_ok(p)               clear_type_bit(T_Itr(p), T_ITER_OK)
2451 
2452 /* its faster here to use the high_flag bits rather than typeflag bits */
2453 #define BIT_ROOM                       16
2454 #define T_FULL_SYMCONS                 (1LL << (TYPE_BITS + BIT_ROOM + 24))
2455 #define T_SYMCONS                      (1 << 0)
2456 #define is_possibly_constant(p)        has_type1_bit(T_Sym(p), T_SYMCONS)
2457 #define set_possibly_constant(p)       set_type1_bit(T_Sym(p), T_SYMCONS)
2458 #define is_probably_constant(p)        has_type_bit(T_Sym(p), (T_FULL_SYMCONS | T_IMMUTABLE))
2459 
2460 #define T_HAS_LET_ARG                  T_SYMCONS
2461 #define has_let_arg(p)                 has_type1_bit(T_Prc(p), T_HAS_LET_ARG)
2462 #define set_has_let_arg(p)             set_type1_bit(T_Prc(p), T_HAS_LET_ARG)
2463 /* p is a setter procedure, "let arg" refers to the setter's optional third (let) argument */
2464 
2465 #define T_HASH_VALUE_TYPE              T_SYMCONS
2466 #define has_hash_value_type(p)         has_type1_bit(T_Hsh(p), T_HASH_VALUE_TYPE)
2467 #define set_has_hash_value_type(p)     set_type1_bit(T_Hsh(p), T_HASH_VALUE_TYPE)
2468 
2469 #define T_INT_OPTABLE                  T_SYMCONS
2470 #define is_int_optable(p)              has_type1_bit(T_Pair(p), T_INT_OPTABLE)
2471 #define set_is_int_optable(p)          set_type1_bit(T_Pair(p), T_INT_OPTABLE)
2472 
2473 /* symbol free here */
2474 #define T_FULL_HAS_LET_FILE            (1LL << (TYPE_BITS + BIT_ROOM + 25))
2475 #define T_HAS_LET_FILE                 (1 << 1)
2476 #define has_let_file(p)                has_type1_bit(T_Let(p), T_HAS_LET_FILE)
2477 #define set_has_let_file(p)            set_type1_bit(T_Let(p), T_HAS_LET_FILE)
2478 #define clear_has_let_file(p)          clear_type1_bit(T_Let(p), T_HAS_LET_FILE)
2479 
2480 #define T_TYPED_VECTOR                 T_HAS_LET_FILE
2481 #define is_typed_vector(p)             has_type1_bit(T_Vec(p), T_TYPED_VECTOR)
2482 #define set_typed_vector(p)            set_type1_bit(T_Vec(p), T_TYPED_VECTOR)
2483 
2484 #define T_TYPED_HASH_TABLE             T_HAS_LET_FILE
2485 #define is_typed_hash_table(p)         has_type1_bit(T_Hsh(p), T_TYPED_HASH_TABLE)
2486 #define set_typed_hash_table(p)        set_type1_bit(T_Hsh(p), T_TYPED_HASH_TABLE)
2487 
2488 #define T_BOOL_SETTER                  T_HAS_LET_FILE
2489 #define c_function_has_bool_setter(p)  has_type1_bit(T_Fnc(p), T_BOOL_SETTER)
2490 #define c_function_set_has_bool_setter(p) set_type1_bit(T_Fnc(p), T_BOOL_SETTER)
2491 
2492 #define T_REST_SLOT                    T_HAS_LET_FILE
2493 #define is_rest_slot(p)                has_type1_bit(T_Slt(p), T_REST_SLOT)
2494 #define set_is_rest_slot(p)            set_type1_bit(T_Slt(p), T_REST_SLOT)
2495 
2496 #define T_NO_DEFAULTS                  T_HAS_LET_FILE
2497 #define T_FULL_NO_DEFAULTS             T_FULL_HAS_LET_FILE
2498 #define has_no_defaults(p)             has_type1_bit(T_Pcs(p), T_NO_DEFAULTS)
2499 #define set_has_no_defaults(p)         set_type1_bit(T_Pcs(p), T_NO_DEFAULTS)
2500 /* pair=closure* body, transferred to closure* */
2501 
2502 #define T_FULL_DEFINER                 (1LL << (TYPE_BITS + BIT_ROOM + 26))
2503 #define T_DEFINER                      (1 << 2)
2504 #define is_definer(p)                  has_type1_bit(T_Sym(p), T_DEFINER)
2505 #define set_is_definer(p)              set_type1_bit(T_Sym(p), T_DEFINER)
2506 #define is_func_definer(p)             has_type1_bit(T_Fnc(p), T_DEFINER)
2507 #define set_func_is_definer(p)         do {set_type1_bit(T_Fnc(initial_value(p)), T_DEFINER); set_type1_bit(T_Sym(p), T_DEFINER);} while (0)
2508 #define is_syntax_definer(p)           has_type1_bit(T_Syn(p), T_DEFINER)
2509 #define set_syntax_is_definer(p)       do {set_type1_bit(T_Syn(initial_value(p)), T_DEFINER); set_type1_bit(T_Sym(p), T_DEFINER);} while (0)
2510 /* this marks "definers" like define and define-macro */
2511 
2512 #define T_MACLET                       T_DEFINER
2513 #define is_maclet(p)                   has_type1_bit(T_Let(p), T_MACLET)
2514 #define set_maclet(p)                  set_type1_bit(T_Let(p), T_MACLET)
2515 /* this marks a maclet */
2516 
2517 #define T_HAS_FX                       T_DEFINER
2518 #define set_has_fx(p)                  set_type1_bit(T_Pair(p), T_HAS_FX)
2519 #define has_fx(p)                      has_type1_bit(T_Pair(p), T_HAS_FX)
2520 #define clear_has_fx(p)                clear_type1_bit(T_Pair(p), T_HAS_FX)
2521 
2522 #define T_SLOT_DEFAULTS                T_DEFINER
2523 #define slot_defaults(p)               has_type1_bit(T_Slt(p), T_SLOT_DEFAULTS)
2524 #define set_slot_defaults(p)           set_type1_bit(T_Slt(p), T_SLOT_DEFAULTS)
2525 
2526 #define T_WEAK_HASH_ITERATOR           T_DEFINER
2527 #define is_weak_hash_iterator(p)       has_type1_bit(T_Itr(p), T_WEAK_HASH_ITERATOR)
2528 #define set_weak_hash_iterator(p)      set_type1_bit(T_Itr(p), T_WEAK_HASH_ITERATOR)
2529 #define clear_weak_hash_iterator(p)    clear_type1_bit(T_Itr(p), T_WEAK_HASH_ITERATOR)
2530 
2531 #define T_HASH_KEY_TYPE                T_DEFINER
2532 #define has_hash_key_type(p)           has_type1_bit(T_Hsh(p), T_HASH_KEY_TYPE)
2533 #define set_has_hash_key_type(p)       set_type1_bit(T_Hsh(p), T_HASH_KEY_TYPE)
2534 
2535 #define T_FULL_BINDER                  (1LL << (TYPE_BITS + BIT_ROOM + 27))
2536 #define T_BINDER                       (1 << 3)
2537 #define set_syntax_is_binder(p)        do {set_type1_bit(T_Syn(initial_value(p)), T_BINDER); set_type1_bit(T_Sym(p), T_BINDER);} while (0)
2538 #define is_definer_or_binder(p)        has_type1_bit(T_Sym(p), T_DEFINER | T_BINDER)
2539 /* this marks "binders" like let */
2540 
2541 #define T_SAFE_ARGS                    T_BINDER
2542 #define has_safe_args(p)               has_type1_bit(T_Fnc(p), T_SAFE_ARGS)
2543 #define set_has_safe_args(p)           set_type1_bit(T_Fnc(p), T_SAFE_ARGS)
2544 
2545 /* #define T_TREE_COLLECTED            T_FULL_BINDER */
2546 #define T_SHORT_TREE_COLLECTED         T_BINDER
2547 #define tree_is_collected(p)           has_type1_bit(T_Pair(p), T_SHORT_TREE_COLLECTED)
2548 #define tree_set_collected(p)          set_type1_bit(T_Pair(p), T_SHORT_TREE_COLLECTED)
2549 #define tree_clear_collected(p)        clear_type1_bit(T_Pair(p), T_SHORT_TREE_COLLECTED)
2550 
2551 #define T_SIMPLE_VALUES                T_BINDER
2552 #define has_simple_values(p)           has_type1_bit(T_Hsh(p), T_SIMPLE_VALUES)
2553 #define set_has_simple_values(p)       set_type1_bit(T_Hsh(p), T_SIMPLE_VALUES)
2554 
2555 #define T_VERY_SAFE_CLOSURE            (1LL << (TYPE_BITS + BIT_ROOM + 28))
2556 #define T_SHORT_VERY_SAFE_CLOSURE      (1 << 4)
2557 #define is_very_safe_closure(p)        has_type1_bit(T_Clo(p), T_SHORT_VERY_SAFE_CLOSURE)
2558 #define set_very_safe_closure(p)       set_type1_bit(T_Clo(p), T_SHORT_VERY_SAFE_CLOSURE)
2559 #define closure_bits(p)                (full_type(T_Pair(p)) & (T_SAFE_CLOSURE | T_VERY_SAFE_CLOSURE | T_FULL_NO_DEFAULTS))
2560 #define is_very_safe_closure_body(p)   has_type1_bit(T_Pair(p), T_SHORT_VERY_SAFE_CLOSURE)
2561 #define set_very_safe_closure_body(p)  set_type1_bit(T_Pair(p), T_SHORT_VERY_SAFE_CLOSURE)
2562 
2563 #define T_BAFFLE_LET                   T_SHORT_VERY_SAFE_CLOSURE
2564 #define is_baffle_let(p)               has_type1_bit(T_Let(p), T_BAFFLE_LET)
2565 #define set_baffle_let(p)              set_type1_bit(T_Let(p), T_BAFFLE_LET)
2566 
2567 #define T_CYCLIC                       (1LL << (TYPE_BITS + BIT_ROOM + 29))
2568 #define T_SHORT_CYCLIC                 (1 << 5)
2569 #define is_cyclic(p)                   has_type1_bit(T_Seq(p), T_SHORT_CYCLIC)
2570 #define set_cyclic(p)                  set_type1_bit(T_Seq(p), T_SHORT_CYCLIC)
2571 
2572 #define T_CYCLIC_SET                   (1LL << (TYPE_BITS + BIT_ROOM + 30))
2573 #define T_SHORT_CYCLIC_SET             (1 << 6)
2574 #define is_cyclic_set(p)               has_type1_bit(T_Seq(p), T_SHORT_CYCLIC_SET) /* was T_Pos 30-Jan-21 */
2575 #define set_cyclic_set(p)              set_type1_bit(T_Seq(p), T_SHORT_CYCLIC_SET)
2576 #define clear_cyclic_bits(p)           clear_type_bit(p, T_COLLECTED | T_SHARED | T_CYCLIC | T_CYCLIC_SET)
2577 
2578 #define T_KEYWORD                      (1LL << (TYPE_BITS + BIT_ROOM + 31))
2579 #define T_SHORT_KEYWORD                (1 << 7)
2580 #define is_keyword(p)                  has_type1_bit(T_Pos(p), T_SHORT_KEYWORD)
2581 /* this bit distinguishes a symbol from a symbol that is also a keyword */
2582 
2583 #define T_FULL_SIMPLE_ELEMENTS         (1LL << (TYPE_BITS + BIT_ROOM + 32))
2584 #define T_SIMPLE_ELEMENTS              (1 << 8)
2585 #define has_simple_elements(p)         has_type1_bit(T_Nvc(p), T_SIMPLE_ELEMENTS)
2586 #define set_has_simple_elements(p)     set_type1_bit(T_Nvc(p), T_SIMPLE_ELEMENTS)
2587 #define c_function_has_simple_elements(p)     has_type1_bit(T_Fnc(p), T_SIMPLE_ELEMENTS)
2588 #define c_function_set_has_simple_elements(p) set_type1_bit(T_Fnc(p), T_SIMPLE_ELEMENTS)
2589 /* c_func case here refers to boolean? et al -- structure element type declaration that ensures a simple object */
2590 
2591 #define T_SIMPLE_KEYS                  T_SIMPLE_ELEMENTS
2592 #define has_simple_keys(p)             has_type1_bit(T_Hsh(p), T_SIMPLE_KEYS)
2593 #define set_has_simple_keys(p)         set_type1_bit(T_Hsh(p), T_SIMPLE_KEYS)
2594 
2595 #define T_SAFE_SETTER                  T_SIMPLE_ELEMENTS
2596 #define is_safe_setter(p)              has_type1_bit(T_Sym(p), T_SAFE_SETTER)
2597 #define set_is_safe_setter(p)          set_type1_bit(T_Sym(p), T_SAFE_SETTER)
2598 
2599 #define T_FLOAT_OPTABLE                T_SIMPLE_ELEMENTS
2600 #define is_float_optable(p)            has_type1_bit(T_Pair(p), T_FLOAT_OPTABLE)
2601 #define set_is_float_optable(p)        set_type1_bit(T_Pair(p), T_FLOAT_OPTABLE)
2602 
2603 #define T_FULL_CASE_KEY                (1LL << (TYPE_BITS + BIT_ROOM + 33))
2604 #define T_CASE_KEY                     (1 << 9)
2605 #define is_case_key(p)                 has_type1_bit(T_Pos(p), T_CASE_KEY)
2606 #define set_case_key(p)                set_type1_bit(T_Sym(p), T_CASE_KEY)
2607 
2608 #define T_OPT1_FUNC_LISTED             T_CASE_KEY
2609 #define opt1_func_listed(p)            has_type1_bit(T_Pair(p), T_OPT1_FUNC_LISTED)
2610 #define set_opt1_func_listed(p)        set_type1_bit(T_Pair(p), T_OPT1_FUNC_LISTED)
2611 
2612 #define T_FULL_HAS_GX                  (1LL << (TYPE_BITS + BIT_ROOM + 34))
2613 #define T_HAS_GX                       (1 << 10)
2614 #define has_gx(p)                      has_type1_bit(T_Pair(p), T_HAS_GX)
2615 #define set_has_gx(p)                  set_type1_bit(T_Pair(p), T_HAS_GX)
2616 
2617 #define T_FULL_UNKNOPT                 (1LL << (TYPE_BITS + BIT_ROOM + 35))
2618 #define T_UNKNOPT                      (1 << 11)
2619 #define is_unknopt(p)                  has_type1_bit(T_Pair(p), T_UNKNOPT)
2620 #define set_is_unknopt(p)              set_type1_bit(T_Pair(p), T_UNKNOPT)
2621 
2622 #define T_MAC_OK                       T_UNKNOPT
2623 #define mac_is_ok(p)                   has_type1_bit(T_Pair(p), T_MAC_OK)
2624 #define set_mac_is_ok(p)               set_type1_bit(T_Pair(p), T_MAC_OK)
2625 /* marks a macro (via (macro...)) that has been checked -- easier (and slower) than making 4 or 5 more ops, op_macro_unchecked and so on */
2626 
2627 #define T_FULL_SAFETY_CHECKED          (1LL << (TYPE_BITS + BIT_ROOM + 36))
2628 #define T_SAFETY_CHECKED               (1 << 12)
2629 #define is_safety_checked(p)           has_type1_bit(T_Pair(p), T_SAFETY_CHECKED)
2630 #define set_safety_checked(p)          set_type1_bit(T_Pair(p), T_SAFETY_CHECKED)
2631 
2632 #define T_FULL_HAS_FN                  (1LL << (TYPE_BITS + BIT_ROOM + 36))
2633 #define T_HAS_FN                       (1 << 13)
2634 #define set_has_fn(p)                  set_type1_bit(T_Pair(p), T_HAS_FN)
2635 #define has_fn(p)                      has_type1_bit(T_Pair(p), T_HAS_FN)
2636 
2637 #define UNUSED_BITS                    0
2638 
2639 #define T_GC_MARK                      0x8000000000000000
2640 #define is_marked(p)                   has_type_bit(p, T_GC_MARK)
2641 #define set_mark(p)                    set_type_bit(T_Pos(p), T_GC_MARK)
2642 #define clear_mark(p)                  clear_type_bit(p, T_GC_MARK)
2643 /* using the sign bit, bit 23 (or 55) == 31 (or 63) for this makes a big difference in the GC */
2644 
2645 #define T_UNHEAP                       0x4000000000000000
2646 #define T_SHORT_UNHEAP                 (1 << 14)
2647 #define not_in_heap(p)                 has_type1_bit(T_Pos(p), T_SHORT_UNHEAP)
2648 #define in_heap(p)                     (((T_Pos(p))->tf.opts.high_flag & T_SHORT_UNHEAP) == 0)
2649 #define unheap(sc, p)                  set_type1_bit(T_Pos(p), T_SHORT_UNHEAP)
2650 
2651 #define is_eof(p)                      ((T_Pos(p)) == eof_object)
2652 #define is_true(Sc, p)                 ((T_Pos(p)) != Sc->F)
2653 #define is_false(Sc, p)                ((T_Pos(p)) == Sc->F)
2654 
2655 #ifdef _MSC_VER
2656   static s7_pointer make_boolean(s7_scheme *sc, bool val) {if (val) return(sc->T); return(sc->F);}
2657 #else
2658   #define make_boolean(sc, Val)        ((Val) ? sc->T : sc->F)
2659 #endif
2660 
2661 #define is_pair(p)                     (type(p) == T_PAIR)
2662 #define is_mutable_pair(p)             ((full_type(T_Pos(p)) & (TYPE_MASK | T_IMMUTABLE)) == T_PAIR)
2663 #define is_null(p)                     ((T_Pos(p)) == sc->nil)
2664 #define is_not_null(p)                 ((T_Pos(p)) != sc->nil)
2665 #define is_list(p)                     ((is_pair(p)) || (type(p) == T_NIL))
2666 #define is_quoted_pair(p)              ((is_pair(p)) && (car(p) == sc->quote_symbol))
2667 #define is_unquoted_pair(p)            ((is_pair(p)) && (car(p) != sc->quote_symbol))
2668 #define is_quoted_symbol(p)            ((is_pair(p)) && (car(p) == sc->quote_symbol) && (is_symbol(cadr(p))))
2669 
2670 
2671 /* pair line/file/position */
2672 #define PAIR_LINE_BITS       24
2673 #define PAIR_FILE_BITS       12
2674 #define PAIR_POSITION_BITS   28
2675 #define PAIR_LINE_OFFSET     0
2676 #define PAIR_FILE_OFFSET     PAIR_LINE_BITS
2677 #define PAIR_POSITION_OFFSET (PAIR_LINE_BITS + PAIR_FILE_BITS)
2678 #define PAIR_LINE_MASK       ((1 << PAIR_LINE_BITS) - 1)
2679 #define PAIR_FILE_MASK       ((1 << PAIR_FILE_BITS) - 1)
2680 #define PAIR_POSITION_MASK   ((1 << PAIR_POSITION_BITS) - 1)
2681 
2682 #define port_location(Pt) (((port_line_number(Pt) & PAIR_LINE_MASK) << PAIR_LINE_OFFSET) | \
2683                            ((port_file_number(Pt) & PAIR_FILE_MASK) << PAIR_FILE_OFFSET) | \
2684                            ((port_position(Pt) & PAIR_POSITION_MASK) << PAIR_POSITION_OFFSET))
2685 #define location_to_line(Loc)     ((Loc >> PAIR_LINE_OFFSET) & PAIR_LINE_MASK)
2686 #define location_to_file(Loc)     ((Loc >> PAIR_FILE_OFFSET) & PAIR_FILE_MASK)
2687 #define location_to_position(Loc) ((Loc >> PAIR_POSITION_OFFSET) & PAIR_POSITION_MASK)
2688 
2689 #define pair_line_number(p)            location_to_line(pair_location(p))
2690 #define pair_file_number(p)            location_to_file(pair_location(p))
2691 #define pair_position(p)               location_to_position(pair_location(p))
2692 
2693 #if (!S7_DEBUGGING)
2694 #define pair_location(p)               (p)->object.sym_cons.location
2695 #define pair_set_location(p, X)        (p)->object.sym_cons.location = X
2696 #define pair_raw_hash(p)               (p)->object.sym_cons.hash
2697 #define pair_set_raw_hash(p, X)        (p)->object.sym_cons.hash = X
2698 #define pair_raw_len(p)                (p)->object.sym_cons.location
2699 #define pair_set_raw_len(p, X)         (p)->object.sym_cons.location = X
2700 #define pair_raw_name(p)               (p)->object.sym_cons.fstr
2701 #define pair_set_raw_name(p, X)        (p)->object.sym_cons.fstr = X
2702 /* opt1 == raw_hash, opt2 == raw_name, opt3 == line|ctr + len, but hash/name/len only apply to the symbol table so there's no collision */
2703 
2704 #define opt1(p, r)                     ((p)->object.cons.opt1)
2705 #define set_opt1(p, x, r)              (p)->object.cons.opt1 = x
2706 #define opt2(p, r)                     ((p)->object.cons.opt2)
2707 #define set_opt2(p, x, r)              (p)->object.cons.opt2 = (s7_pointer)(x)
2708 #define opt3(p, r)                     ((p)->object.cons.opt3)
2709 #define set_opt3(p, x, r)              do {(p)->object.cons.opt3 = x; clear_type_bit(p, T_LOCATION);} while (0)
2710 /* 29-Oct-18 this used to clear T_OPTIMIZED -- optimize_op was sharing opt3 with line info */
2711 
2712 #else
2713 
2714 /* the 3 opt fields hold most of the varigated optimizer info, so they are used in many conflicting ways.
2715  * the bits and funcs here try to track each such use, and report any cross-talk or collisions.
2716  * all of this machinery vanishes if debugging is turned off.
2717  */
2718 #define OPT1_SET                       (1 << 0)
2719 #define OPT2_SET                       (1 << 1)
2720 #define OPT3_SET                       (1 << 2)
2721 
2722 #define OPT1_FAST                      (1 << 3)   /* fast list in member/assoc circular list check */
2723 #define OPT1_CFUNC                     (1 << 4)   /* c-function */
2724 #define OPT1_CLAUSE                    (1 << 5)   /* case clause */
2725 #define OPT1_LAMBDA                    (1 << 6)   /* lambda(*) */
2726 #define OPT1_SYM                       (1 << 7)   /* symbol */
2727 #define OPT1_PAIR                      (1 << 8)   /* pair */
2728 #define OPT1_CON                       (1 << 9)   /* constant from eval's point of view */
2729 #define OPT1_GOTO                      (1 << 10)  /* call-with-exit exit func */
2730 #define OPT1_ANY                       (1 << 11)  /* anything -- deliberate unchecked case */
2731 #define OPT1_HASH                      (1 << 12)
2732 #define OPT1_MASK                      (OPT1_FAST | OPT1_CFUNC | OPT1_CLAUSE | OPT1_LAMBDA | OPT1_SYM | OPT1_PAIR | OPT1_CON | OPT1_GOTO | OPT1_ANY | OPT1_HASH)
2733 
2734 #define opt1_is_set(p)                 (((T_Pair(p))->debugger_bits & OPT1_SET) != 0)
2735 #define set_opt1_is_set(p)             (T_Pair(p))->debugger_bits |= OPT1_SET
2736 #define opt1_role_matches(p, Role)     (((T_Pair(p))->debugger_bits & OPT1_MASK) == Role)
2737 #define set_opt1_role(p, Role)         (T_Pair(p))->debugger_bits = (Role | ((p)->debugger_bits & ~OPT1_MASK))
2738 #define opt1(p, Role)                  opt1_1(sc, T_Pair(p), Role, __func__, __LINE__)
2739 #define set_opt1(p, x, Role)           set_opt1_1(T_Pair(p), x, Role)
2740 
2741 #define OPT2_KEY                       (1 << 13)  /* case key */
2742 #define OPT2_SLOW                      (1 << 14)  /* slow list in member/assoc circular list check */
2743 #define OPT2_SYM                       (1 << 15)  /* symbol */
2744 #define OPT2_PAIR                      (1 << 16)  /* pair */
2745 #define OPT2_CON                       (1 << 17)  /* constant as above */
2746 #define OPT2_FX                        (1 << 18)  /* fx (fx_*) func (sc, form) */
2747 #define OPT2_FN                        (1 << 19)  /* fn (s7_function) func (sc, arglist) */
2748 #define OPT2_LAMBDA                    (1 << 20)  /* lambda form */
2749 #define OPT2_NAME                      (1 << 21)
2750 #define OPT2_DIRECT                    (1LL << 32)
2751 #define OPT2_INT                       (1LL << 33)
2752 #define OPT2_MASK                      (OPT2_KEY | OPT2_SLOW | OPT2_SYM | OPT2_PAIR | OPT2_CON | OPT2_FX | OPT2_FN | OPT2_LAMBDA | OPT2_DIRECT | OPT2_NAME | OPT2_INT)
2753 
2754 #define opt2_is_set(p)                 (((T_Pair(p))->debugger_bits & OPT2_SET) != 0)
2755 #define set_opt2_is_set(p)             (T_Pair(p))->debugger_bits |= OPT2_SET
2756 #define opt2_role_matches(p, Role)     (((T_Pair(p))->debugger_bits & OPT2_MASK) == Role)
2757 #define set_opt2_role(p, Role)         (T_Pair(p))->debugger_bits = (Role | ((p)->debugger_bits & ~OPT2_MASK))
2758 #define opt2(p, Role)                  opt2_1(sc, T_Pair(p), Role, __func__, __LINE__)
2759 #define set_opt2(p, x, Role)           set_opt2_1(sc, T_Pair(p), (s7_pointer)(x), Role, __func__, __LINE__)
2760 
2761 #define OPT3_ARGLEN                    (1 << 22)  /* arglist length */
2762 #define OPT3_SYM                       (1 << 23)  /* expression symbol access */
2763 #define OPT3_AND                       (1 << 24)  /* and second clause */
2764 #define OPT3_DIRECT                    (1 << 25)  /* direct call info */
2765 #define OPT3_ANY                       (1 << 26)
2766 #define OPT3_LET                       (1 << 27)  /* let or #f */
2767 #define OPT3_CON                       (1 << 28)
2768 #define OPT3_LOCATION                  (1 << 29)
2769 #define OPT3_LEN                       (1 << 30)
2770 #define OPT3_BYTE                      (1LL << 31)
2771 #define OPT3_INT                       (1LL << 34)
2772 #define OPT3_MASK                      (OPT3_ARGLEN | OPT3_SYM | OPT3_AND | OPT3_ANY | OPT3_LET | OPT3_BYTE | OPT3_LOCATION | OPT3_LEN | OPT3_DIRECT | OPT3_CON | OPT3_INT)
2773 
2774 #define opt3_is_set(p)                 (((T_Pair(p))->debugger_bits & OPT3_SET) != 0)
2775 #define set_opt3_is_set(p)             (T_Pair(p))->debugger_bits |= OPT3_SET
2776 #define opt3_role_matches(p, Role)     (((T_Pair(p))->debugger_bits & OPT3_MASK) == Role)
2777 #define set_opt3_role(p, Role)         (T_Pair(p))->debugger_bits = (Role | ((p)->debugger_bits & ~OPT3_MASK))
2778 #define opt3(p, Role)                  opt3_1(sc, T_Pair(p), Role, __func__, __LINE__)
2779 #define set_opt3(p, x, Role)           set_opt3_1(T_Pair(p), x, Role)
2780 
2781 #define pair_location(p)               opt3_location_1(sc, T_Pair(p), __func__, __LINE__)
2782 #define pair_set_location(p, X)        set_opt3_location_1(T_Pair(p), X)
2783 #define pair_raw_hash(p)               opt1_hash_1(sc, T_Pair(p), __func__, __LINE__)
2784 #define pair_set_raw_hash(p, X)        set_opt1_hash_1(T_Pair(p), X)
2785 #define pair_raw_len(p)                opt3_len_1(sc, T_Pair(p), __func__, __LINE__)
2786 #define pair_set_raw_len(p, X)         set_opt3_len_1(T_Pair(p), X)
2787 #define pair_raw_name(p)               opt2_name_1(sc, T_Pair(p), __func__, __LINE__)
2788 #define pair_set_raw_name(p, X)        set_opt2_name_1(T_Pair(p), X)
2789 
2790 #define L_HIT                          (1LL << 40) /* "L_SET" is taken */
2791 #define L_FUNC                         (1LL << 41)
2792 #define L_DOX                          (1LL << 42)
2793 #define L_CATCH                        (1LL << 43)
2794 #define L_MASK                         (L_FUNC | L_DOX | L_CATCH)
2795 #endif
2796 
2797 #define opt1_fast(P)                   T_Lst(opt1(P,                OPT1_FAST))
2798 #define set_opt1_fast(P, X)            set_opt1(P, T_Pair(X),       OPT1_FAST)
2799 #define opt1_cfunc(P)                  T_Pos(opt1(P,                OPT1_CFUNC))
2800 #define set_opt1_cfunc(P, X)           set_opt1(P, T_Pos(X),        OPT1_CFUNC)
2801 #define opt1_lambda_unchecked(P)       opt1(P,                      OPT1_LAMBDA) /* can be free/null? from s7_call? */
2802 #define opt1_lambda(P)                 T_Clo(opt1(P,                OPT1_LAMBDA))
2803 #define set_opt1_lambda(P, X)          set_opt1(P, T_Clo(X),        OPT1_LAMBDA)
2804 #define set_opt1_lambda_add(P, X)      do {set_opt1(P, T_Clo(X), OPT1_LAMBDA); add_opt1_func(sc, P);} while (0)
2805 #define opt1_goto(P)                   T_Pos(opt1(P,                OPT1_GOTO))  /* used when checking for non-goto unknown in eval, so can't be T_Got */
2806 #define set_opt1_goto(P, X)            set_opt1(P, T_Pos(X),        OPT1_GOTO)
2807 #define opt1_clause(P)                 T_Pos(opt1(P,                OPT1_CLAUSE))
2808 #define set_opt1_clause(P, X)          set_opt1(P, T_Pos(X),        OPT1_CLAUSE)
2809 #define opt1_sym(P)                    T_Sym(opt1(P,                OPT1_SYM))
2810 #define set_opt1_sym(P, X)             set_opt1(P, T_Sym(X),        OPT1_SYM)
2811 #define opt1_pair(P)                   T_Lst(opt1(P,                OPT1_PAIR))
2812 #define set_opt1_pair(P, X)            set_opt1(P, T_Lst(X),        OPT1_PAIR)
2813 #define opt1_con(P)                    T_Pos(opt1(P,                OPT1_CON))
2814 #define set_opt1_con(P, X)             set_opt1(P, T_Pos(X),        OPT1_CON)
2815 #define opt1_any(P)                    opt1(P,                      OPT1_ANY)    /* can be free in closure_is_ok */
2816 #define set_opt1_any(P, X)             set_opt1(P, X,               OPT1_ANY)
2817 
2818 #define opt2_any(P)                    opt2(P,                      OPT2_KEY)
2819 #define set_opt2_any(P, X)             set_opt2(P, X,               OPT2_KEY)
2820 #define opt2_int(P)                    T_Int(opt2(P,                OPT2_INT))
2821 #define set_opt2_int(P, X)             set_opt2(P, T_Int(X),        OPT2_INT)
2822 #define opt2_slow(P)                   T_Lst(opt2(P,                OPT2_SLOW))
2823 #define set_opt2_slow(P, X)            set_opt2(P, T_Pair(X),       OPT2_SLOW)
2824 #define opt2_sym(P)                    T_Sym(opt2(P,                OPT2_SYM))
2825 #define set_opt2_sym(P, X)             set_opt2(P, T_Sym(X),        OPT2_SYM)
2826 #define opt2_pair(P)                   T_Lst(opt2(P,                OPT2_PAIR))
2827 #define set_opt2_pair(P, X)            set_opt2(P, T_Lst(X),        OPT2_PAIR)
2828 #define opt2_con(P)                    T_Pos(opt2(P,                OPT2_CON))
2829 #define set_opt2_con(P, X)             set_opt2(P, T_Pos(X),        OPT2_CON)
2830 #define opt2_lambda(P)                 T_Pair(opt2(P,               OPT2_LAMBDA))
2831 #define set_opt2_lambda(P, X)          set_opt2(P, T_Pair(X),       OPT2_LAMBDA)
2832 #define opt2_direct(P)                 opt2(P,                      OPT2_DIRECT)
2833 #define set_opt2_direct(P, X)          set_opt2(P, (s7_pointer)(X), OPT2_DIRECT)
2834 
2835 #define opt3_arglen(P)                 T_Int(opt3(P,                OPT3_ARGLEN))
2836 #define set_opt3_arglen(P, X)          set_opt3(P, T_Int(X),        OPT3_ARGLEN)
2837 #define opt3_int(P)                    T_Int(opt3(P,                OPT3_INT))
2838 #define set_opt3_int(P, X)             set_opt3(P, T_Int(X),        OPT3_INT)
2839 #define opt3_sym(P)                    T_Sym(opt3(P,                OPT3_SYM))
2840 #define set_opt3_sym(P, X)             set_opt3(P, T_Sym(X),        OPT3_SYM)
2841 #define opt3_con(P)                    T_Pos(opt3(P,                OPT3_CON))
2842 #define set_opt3_con(P, X)             set_opt3(P, T_Pos(X),        OPT3_CON)
2843 #define opt3_pair(P)                   T_Pair(opt3(P,               OPT3_AND))
2844 #define set_opt3_pair(P, X)            set_opt3(P, T_Pair(X),       OPT3_AND)
2845 #define opt3_any(P)                    opt3(P,                      OPT3_ANY)
2846 #define set_opt3_any(P, X)             set_opt3(P, X,               OPT3_ANY)
2847 #define opt3_let(P)                    T_Lid(opt3(P,                OPT3_LET))
2848 #define set_opt3_let(P, X)             set_opt3(P, T_Lid(X),        OPT3_LET)
2849 #define opt3_direct(P)                 opt3(P,                      OPT3_DIRECT)
2850 #define set_opt3_direct(P, X)          set_opt3(P, (s7_pointer)(X), OPT3_DIRECT)
2851 
2852 #if S7_DEBUGGING
2853 #define opt3_byte(p)                   opt3_byte_1(sc, T_Pair(p), OPT3_BYTE, __func__, __LINE__)
2854 #define set_opt3_byte(p, x)            set_opt3_byte_1(T_Pair(p), x, OPT3_BYTE, __func__, __LINE__)
2855 #else
2856 #define opt3_byte(P)                   T_Pair(P)->object.cons_ext.opt_type /* op_if_is_type, opt_type == opt3 in cons_ext */
2857 #define set_opt3_byte(P, X)            do {T_Pair(P)->object.cons_ext.opt_type = X; clear_type_bit(P, T_LOCATION);} while (0)
2858 #endif
2859 
2860 #define pair_macro(P)                  opt2_sym(P)
2861 #define set_pair_macro(P, Name)        set_opt2_sym(P, Name)
2862 
2863 #define fn_proc(f)                     ((s7_function)opt2(f, OPT2_FN))
2864 #define fx_proc(f)                     ((s7_function)opt2(f, OPT2_FX))
2865 #define fn_proc_unchecked(f)           ((s7_function)(T_Pair(f)->object.cons.opt2))
2866 #define fx_proc_unchecked(f)           ((s7_function)(T_Pair(f)->object.cons.opt2)) /* unused */
2867 
2868 #define set_fx(f, _X_)                 do {s7_pointer X; X = (s7_pointer)(_X_); set_opt2(f, X, OPT2_FX); if (X) set_has_fx(f); else clear_has_fx(f);} while (0)
2869 #define set_fx_direct(f, X)            do {set_opt2(f, (s7_pointer)(X), OPT2_FX); set_has_fx(f);} while (0)
2870 #define set_fn(f, _X_)                 do {s7_pointer X; X = (s7_pointer)(_X_); set_opt2(f, X, OPT2_FN); if (X) set_has_fn(f); else clear_has_fx(f);} while (0)
2871 #define set_fn_direct(f, X)            do {set_opt2(f, (s7_pointer)(X), OPT2_FN); set_has_fn(f);} while (0)
2872 
2873 #if WITH_GCC
2874 #define fx_call(Sc, F)                 ({s7_pointer _P_; _P_ = F; fx_proc(_P_)(Sc, car(_P_));})
2875 #define d_call(Sc, F)                  ({s7_pointer _P_; _P_ = F; fn_proc(_P_)(Sc, cdr(_P_));})
2876 #define fn_call(Sc, F)                 ({s7_pointer _P_; _P_ = F; fn_proc(_P_)(Sc, cdr(_P_));})
2877 #else
2878 #define fx_call(Sc, F)                 fn_proc(F)(Sc, car(F))
2879 #define d_call(Sc, F)                  fn_proc(F)(Sc, cdr(F))
2880 #define fn_call(Sc, F)                 fn_proc(F)(Sc, cdr(F))
2881 #endif
2882 /* fx_call can affect the stack and sc->value */
2883 
2884 #define car(p)                         (T_Pair(p))->object.cons.car
2885 #define set_car(p, Val)                (T_Pair(p))->object.cons.car = T_Pos(Val)
2886 #define cdr(p)                         (T_Pair(p))->object.cons.cdr
2887 #define set_cdr(p, Val)                (T_Pair(p))->object.cons.cdr = T_Pos(Val)
2888 #define unchecked_car(p)               (T_Pos(p))->object.cons.car
2889 #define unchecked_cdr(p)               (T_Pos(p))->object.cons.cdr
2890 
2891 #define caar(p)                        car(car(p))
2892 #define cadr(p)                        car(cdr(p))
2893 #define set_cadr(p, Val)               (T_Pair(p))->object.cons.cdr->object.cons.car = T_Pos(Val)
2894 #define cdar(p)                        cdr(car(p))
2895 #define set_cdar(p, Val)               (T_Pair(p))->object.cons.car->object.cons.cdr = T_Pos(Val)
2896 #define cddr(p)                        cdr(cdr(p))
2897 
2898 #define caaar(p)                       car(car(car(p)))
2899 #define cadar(p)                       car(cdr(car(p)))
2900 #define cdadr(p)                       cdr(car(cdr(p)))
2901 #define caddr(p)                       car(cdr(cdr(p)))
2902 #define set_caddr(p, Val)              (T_Pair(p))->object.cons.cdr->object.cons.cdr->object.cons.car = T_Pos(Val)
2903 #define caadr(p)                       car(car(cdr(p)))
2904 #define cdaar(p)                       cdr(car(car(p)))
2905 #define cdddr(p)                       cdr(cdr(cdr(p)))
2906 #define cddar(p)                       cdr(cdr(car(p)))
2907 
2908 #define caaadr(p)                      car(car(car(cdr(p))))
2909 #define caadar(p)                      car(car(cdr(car(p))))
2910 #define cadaar(p)                      car(cdr(car(car(p))))
2911 #define cadddr(p)                      car(cdr(cdr(cdr(p))))
2912 #define caaddr(p)                      car(car(cdr(cdr(p))))
2913 #define cddddr(p)                      cdr(cdr(cdr(cdr(p))))
2914 #define caddar(p)                      car(cdr(cdr(car(p))))
2915 #define cdadar(p)                      cdr(car(cdr(car(p))))
2916 #define cdaddr(p)                      cdr(car(cdr(cdr(p))))
2917 #define caaaar(p)                      car(car(car(car(p))))
2918 #define cadadr(p)                      car(cdr(car(cdr(p))))
2919 #define cdaadr(p)                      cdr(car(car(cdr(p))))
2920 #define cdaaar(p)                      cdr(car(car(car(p))))
2921 #define cdddar(p)                      cdr(cdr(cdr(car(p))))
2922 #define cddadr(p)                      cdr(cdr(car(cdr(p))))
2923 #define cddaar(p)                      cdr(cdr(car(car(p))))
2924 
2925 #define cadaddr(p)                     car(cdr(car(cdr(cdr(p)))))
2926 #define caddadr(p)                     car(cdr(cdr(car(cdr(p)))))
2927 #define caddaddr(p)                    car(cdr(cdr(car(cdr(cdr(p))))))
2928 
2929 #if WITH_GCC
2930   /* slightly tricky because cons can be called recursively */
2931   #define cons(Sc, A, B)   ({s7_pointer _X_, _A_, _B_; _A_ = A; _B_ = B; new_cell(Sc, _X_, T_PAIR | T_SAFE_PROCEDURE); set_car(_X_, _A_); set_cdr(_X_, _B_); _X_;})
2932 #else
2933   #define cons(Sc, A, B)               s7_cons(Sc, A, B)
2934 #endif
2935 
2936 #define list_1(Sc, A)                  cons(Sc, A, Sc->nil)
2937 #define list_2(Sc, A, B)               cons_unchecked(Sc, A, cons(Sc, B, Sc->nil))
2938 #define list_3(Sc, A, B, C)            cons_unchecked(Sc, A, cons_unchecked(Sc, B, cons(Sc, C, Sc->nil)))
2939 #define list_4(Sc, A, B, C, D)         cons_unchecked(Sc, A, cons_unchecked(Sc, B, cons_unchecked(Sc, C, cons(Sc, D, Sc->nil))))
2940 
2941 #define is_string(p)                   (type(p) == T_STRING)
2942 #define is_mutable_string(p)           ((full_type(T_Pos(p)) & (TYPE_MASK | T_IMMUTABLE)) == T_STRING)
2943 #define string_value(p)                (T_Str(p))->object.string.svalue
2944 #define string_length(p)               (T_Str(p))->object.string.length
2945 #define string_hash(p)                 (T_Str(p))->object.string.hash
2946 #define string_block(p)                (T_Str(p))->object.string.block
2947 #define unchecked_string_block(p)      p->object.string.block
2948 
2949 #define character(p)                   (T_Chr(p))->object.chr.c
2950 #define upper_character(p)             (T_Chr(p))->object.chr.up_c
2951 #define is_char_alphabetic(p)          (T_Chr(p))->object.chr.alpha_c
2952 #define is_char_numeric(p)             (T_Chr(p))->object.chr.digit_c
2953 #define is_char_whitespace(p)          (T_Chr(p))->object.chr.space_c
2954 #define is_char_uppercase(p)           (T_Chr(p))->object.chr.upper_c
2955 #define is_char_lowercase(p)           (T_Chr(p))->object.chr.lower_c
2956 #define character_name(p)              (T_Chr(p))->object.chr.c_name
2957 #define character_name_length(p)       (T_Chr(p))->object.chr.length
2958 
2959 #define optimize_op(P)                 (P)->tf.opts.opt_choice
2960 #define set_optimize_op(P, Op)         (P)->tf.opts.opt_choice = Op
2961 #define OP_HOP_MASK                    0xfffe
2962 #define optimize_op_match(P, Q)        ((is_optimized(P)) && ((optimize_op(P) & OP_HOP_MASK) == (Q)))
2963 #define op_no_hop(P)                   (optimize_op(P) & OP_HOP_MASK)
2964 #define op_has_hop(P)                  ((optimize_op(P) & 1) != 0)
2965 #define clear_optimize_op(P)           set_optimize_op(P, 0)
2966 #define set_safe_optimize_op(P, Q)     do {set_optimized(P); set_optimize_op(P, Q);} while (0)
2967 #define set_unsafe_optimize_op(P, Q)   do {set_unsafely_optimized(P); set_optimize_op(P, Q);} while (0)
2968 
2969 #define is_symbol(p)                   (type(p) == T_SYMBOL)
2970 #define is_normal_symbol(p)            ((is_symbol(p)) && (!is_keyword(p)))
2971 #define is_safe_symbol(p)              ((is_symbol(p)) && (is_slot(lookup_slot_from(p, sc->curlet))))
2972 #define symbol_name_cell(p)            T_Str((T_Sym(p))->object.sym.name)
2973 #define symbol_set_name_cell(p, S)     (T_Sym(p))->object.sym.name = T_Str(S)
2974 #define symbol_name(p)                 string_value(symbol_name_cell(p))
2975 #define symbol_name_length(p)          string_length(symbol_name_cell(p))
2976 #define gensym_block(p)                symbol_name_cell(p)->object.string.gensym_block
2977 #define pointer_map(p)                 (s7_int)((intptr_t)(p) >> 8)
2978 #define symbol_id(p)                   (T_Sym(p))->object.sym.id
2979 #define symbol_set_id_unchecked(p, X)  (T_Sym(p))->object.sym.id = X
2980 #if S7_DEBUGGING
2981 static void symbol_set_id(s7_pointer p, s7_int id)
2982 {
2983   if (id < symbol_id(p))
2984     {
2985       fprintf(stderr, "id mismatch: sym: %s %" print_s7_int ", let: %" print_s7_int "\n", symbol_name(p), symbol_id(p), id);
2986       abort();
2987     }
2988   (T_Sym(p))->object.sym.id = id;
2989 }
2990 #else
2991 #define symbol_set_id(p, X)            (T_Sym(p))->object.sym.id = X
2992 #endif
2993 /* we need 64-bits here, since we don't want this thing to wrap around, and lets are created at a great rate
2994  *    callgrind says this is faster than an uint32_t!
2995  */
2996 #define symbol_info(p)                 (symbol_name_cell(p))->object.string.block
2997 #define symbol_type(p)                 (block_size(symbol_info(p)) & 0xff)   /* boolean function bool type */
2998 #define symbol_set_type(p, Type)       block_size(symbol_info(p)) = ((block_size(symbol_info(p)) & ~0xff) | (Type & 0xff))
2999 #define symbol_clear_type(p)           block_size(symbol_info(p)) = 0
3000 #define symbol_s7_let(p)               ((uint8_t)((block_size(symbol_info(p)) >> 8) & 0xff))  /* *s7* field id */
3001 #define symbol_set_s7_let(p, Field)    block_size(symbol_info(p)) = ((block_size(symbol_info(p)) & ~0xff00) | ((Field & 0xff) << 8))
3002 #define initial_slot(p)                T_Sld(symbol_info(p)->ex.ex_ptr)
3003 #define set_initial_slot(p, Val)       symbol_info(p)->ex.ex_ptr = T_Sld(Val)
3004 #define global_slot(p)                 T_Sld((T_Sym(p))->object.sym.global_slot)
3005 #define set_global_slot(p, Val)        (T_Sym(p))->object.sym.global_slot = T_Sld(Val)
3006 #define local_slot(p)                  T_Sln((T_Sym(p))->object.sym.local_slot)
3007 #define set_local_slot(p, Val)         (T_Sym(p))->object.sym.local_slot = T_Slt(Val)
3008 
3009 #define initial_value(p)               slot_value(initial_slot(T_Sym(p)))
3010 #define local_value(p)                 slot_value(local_slot(T_Sym(p)))
3011 #define unchecked_local_value(p)       local_slot(p)->object.slt.val
3012 #define global_value(p)                slot_value(global_slot(T_Sym(p)))
3013 
3014 #define keyword_symbol(p)              symbol_info(p)->nx.ksym               /* keyword only, so does not collide with documentation */
3015 #define keyword_set_symbol(p, Val)     symbol_info(p)->nx.ksym = T_Sym(Val)
3016 #define symbol_help(p)                 symbol_info(p)->nx.documentation
3017 #define symbol_set_help(p, Doc)        symbol_info(p)->nx.documentation = Doc
3018 #define symbol_tag(p)                  (T_Sym(p))->object.sym.tag
3019 #define symbol_set_tag(p, Val)         (T_Sym(p))->object.sym.tag = Val
3020 #define symbol_ctr(p)                  (T_Sym(p))->object.sym.ctr            /* needs to be in the symbol object (not symbol_info) for speed */
3021 #define symbol_clear_ctr(p)            (T_Sym(p))->object.sym.ctr = 0
3022 #define symbol_increment_ctr(p)        (T_Sym(p))->object.sym.ctr++
3023 #define symbol_tag2(p)                 symbol_info(p)->ln.tag
3024 #define symbol_set_tag2(p, Val)        symbol_info(p)->ln.tag = Val
3025 #define symbol_has_help(p)             (is_documented(symbol_name_cell(p)))
3026 #define symbol_set_has_help(p)         set_documented(symbol_name_cell(p))
3027 
3028 #define symbol_position(p) symbol_info(p)->dx.pos /* this only needs 32 of the available 64 bits */
3029 #define symbol_set_position(p, Pos) symbol_info(p)->dx.pos = Pos
3030 #define PD_POSITION_UNSET -1
3031 
3032 #define symbol_set_local_slot_unchecked(Symbol, Id, Slot) \
3033   do {(Symbol)->object.sym.local_slot = T_Sln(Slot); symbol_set_id_unchecked(Symbol, Id); symbol_increment_ctr(Symbol);} while (0)
3034 #define symbol_set_local_slot_unchecked_and_unincremented(Symbol, Id, Slot) \
3035   do {(Symbol)->object.sym.local_slot = T_Sln(Slot); symbol_set_id_unchecked(Symbol, Id);} while (0)
3036 #define symbol_set_local_slot(Symbol, Id, Slot) \
3037   do {set_local_slot(Symbol, Slot); symbol_set_id(Symbol, Id); symbol_increment_ctr(Symbol);} while (0)
3038 #define symbol_set_local_slot_unincremented(Symbol, Id, Slot) \
3039   do {set_local_slot(Symbol, Slot); symbol_set_id(Symbol, Id);} while (0)
3040 /* set slot before id in case Slot is an expression that tries to find the current Symbol slot (using its old Id obviously) */
3041 
3042 #define is_slot(p)                     (type(p) == T_SLOT)
3043 #define slot_symbol(p)                 T_Sym((T_Slt(p))->object.slt.sym)
3044 #define slot_set_symbol(p, Sym)        (T_Slt(p))->object.slt.sym = T_Sym(Sym)
3045 #define slot_value(p)                  T_Nmv((T_Slt(p))->object.slt.val)
3046 #define slot_set_value(p, Val)         (T_Slt(p))->object.slt.val = T_Nmv(Val)
3047 #define slot_set_value_with_hook(Slot, Value) \
3048   do {if (hook_has_functions(sc->rootlet_redefinition_hook)) slot_set_value_with_hook_1(sc, Slot, Value); else slot_set_value(Slot, Value);} while (0)
3049 #define next_slot(p)                   T_Sln((T_Slt(p))->object.slt.nxt)
3050 #define slot_set_next(p, Val)          (T_Slt(p))->object.slt.nxt = T_Sln(Val)
3051 #define slot_set_pending_value(p, Val) do {(T_Slt(p))->object.slt.pending_value = T_Pos(Val); slot_set_has_pending_value(p);} while (0)
3052 #define slot_simply_set_pending_value(p, Val) (T_Slt(p))->object.slt.pending_value = T_Pos(Val)
3053 #if S7_DEBUGGING
3054 static s7_pointer slot_pending_value(s7_pointer p) \
3055   {if (slot_has_pending_value(p)) return(p->object.slt.pending_value); fprintf(stderr, "slot: no pending value\n"); abort();}
3056 static s7_pointer slot_expression(s7_pointer p)    \
3057   {if (slot_has_expression(p)) return(p->object.slt.expr); fprintf(stderr, "slot: no expression\n"); abort();}
3058 #else
3059 #define slot_pending_value(p)          (T_Slt(p))->object.slt.pending_value
3060 #define slot_expression(p)             (T_Slt(p))->object.slt.expr
3061 #endif
3062 #define slot_pending_value_unchecked(p) (T_Slt(p))->object.slt.pending_value
3063 #define slot_set_expression(p, Val)    do {(T_Slt(p))->object.slt.expr = T_Pos(Val); slot_set_has_expression(p);} while (0)
3064 #define slot_just_set_expression(p, Val) (T_Slt(p))->object.slt.expr = T_Pos(Val)
3065 #define slot_setter(p)                 T_Prc(T_Slt(p)->object.slt.expr)
3066 #define slot_set_setter_1(p, Val)      (T_Slt(p))->object.slt.expr = T_Prc(Val)
3067 #if S7_DEBUGGING
3068 #define tis_slot(p) ((p) && (T_Slt(p)))
3069 #else
3070 #define tis_slot(p) (p) /* used for loop through let slots which end in nil, not for general slot recognition */
3071 #endif
3072 #define slot_end(sc) NULL
3073 #define is_slot_end(p) (!(p))
3074 
3075 #define is_syntax(p)                   (type(p) == T_SYNTAX)
3076 #define syntax_symbol(p)               T_Sym((T_Syn(p))->object.syn.symbol)
3077 #define syntax_set_symbol(p, Sym)      (T_Syn(p))->object.syn.symbol = T_Sym(Sym)
3078 #define syntax_opcode(p)               (T_Syn(p))->object.syn.op
3079 #define syntax_min_args(p)             (T_Syn(p))->object.syn.min_args
3080 #define syntax_max_args(p)             (T_Syn(p))->object.syn.max_args
3081 #define syntax_documentation(p)        (T_Syn(p))->object.syn.documentation
3082 
3083 #define set_syntactic_pair(p)          full_type(T_Pair(p)) = (T_PAIR | T_SYNTACTIC | (full_type(p) & (0xffffffffffff0000 & ~T_OPTIMIZED)))
3084 #define pair_set_syntax_op(p, X)       do {set_optimize_op(p, X); set_syntactic_pair(p);} while (0)
3085 #define symbol_syntax_op_checked(p)    ((is_syntactic_pair(p)) ? optimize_op(p) : symbol_syntax_op(car(p)))
3086 #define symbol_syntax_op(p)            syntax_opcode(global_value(p))
3087 
3088 #define INITIAL_ROOTLET_SIZE           512
3089 #define let_id(p)                      (T_Lid(p))->object.envr.id
3090 #define let_set_id(p, Id)              (T_Lid(p))->object.envr.id = Id
3091 #define is_let(p)                      (type(p) == T_LET)
3092 #define is_let_unchecked(p)            (unchecked_type(p) == T_LET)
3093 #define let_slots(p)                   T_Sln((T_Let(p))->object.envr.slots)
3094 #define let_outlet(p)                  T_Lid((T_Let(p))->object.envr.nxt)
3095 #define let_set_outlet(p, ol)          (T_Let(p))->object.envr.nxt = T_Lid(ol)
3096 #if S7_DEBUGGING
3097   #define let_set_slots(p, Slot)         do {if ((not_in_heap(p)) && (Slot) && (in_heap(Slot))) fprintf(stderr, "let + slot mismatch\n"); T_Let(p)->object.envr.slots = T_Sln(Slot);} while (0)
3098   #define C_Let(p, role)                 check_let_ref(p, role, __func__, __LINE__)
3099   #define S_Let(p, role)                 check_let_set(p, role, __func__, __LINE__)
3100 #else
3101   #define let_set_slots(p, Slot)         (T_Let(p))->object.envr.slots = T_Sln(Slot)
3102   #define C_Let(p, role)                 p
3103   #define S_Let(p, role)                 p
3104 #endif
3105 #define funclet_function(p)            T_Sym((C_Let(p, L_FUNC))->object.envr.edat.efnc.function)
3106 #define funclet_set_function(p, F)     (S_Let(p, L_FUNC))->object.envr.edat.efnc.function = T_Sym(F)
3107 
3108 #define let_baffle_key(p)              (T_Let(p))->object.envr.edat.bafl.key
3109 #define set_let_baffle_key(p, K)       (T_Let(p))->object.envr.edat.bafl.key = K
3110 
3111 #define let_line(p)                    (C_Let(p, L_FUNC))->object.envr.edat.efnc.line
3112 #define let_set_line(p, L)             (S_Let(p, L_FUNC))->object.envr.edat.efnc.line = L
3113 #define let_file(p)                    (C_Let(p, L_FUNC))->object.envr.edat.efnc.file
3114 #define let_set_file(p, F)             (S_Let(p, L_FUNC))->object.envr.edat.efnc.file = F
3115 
3116 #define let_dox_slot1(p)               T_Slt((C_Let(p, L_DOX))->object.envr.edat.dox.dox1)
3117 #define let_set_dox_slot1(p, S)        do {(S_Let(p, L_DOX))->object.envr.edat.dox.dox1 = T_Slt(S); set_has_dox_slot1(p);} while (0)
3118 #define let_dox_slot2(p)               T_Sld((C_Let(p, L_DOX))->object.envr.edat.dox.dox2)
3119 #define let_set_dox_slot2(p, S)        do {(S_Let(p, L_DOX))->object.envr.edat.dox.dox2 = T_Slt(S); set_has_dox_slot2(p);} while (0)
3120 #define let_dox_slot2_unchecked(p)     T_Sld(C_Let(p, L_DOX)->object.envr.edat.dox.dox2)
3121 #define let_set_dox_slot2_unchecked(p, S) do {S_Let(p, L_DOX)->object.envr.edat.dox.dox2 = T_Sld(S); set_has_dox_slot2(p);} while (0)
3122 #define let_dox1_value(p)              slot_value(let_dox_slot1(p))
3123 #define let_dox2_value(p)              slot_value(let_dox_slot2(p))
3124 
3125 #define unique_name(p)                 (p)->object.unq.name
3126 #define unique_name_length(p)          (p)->object.unq.len
3127 #define is_unspecified(p)              (type(p) == T_UNSPECIFIED)
3128 #define unique_car(p)                  (p)->object.unq.car
3129 #define unique_cdr(p)                  (p)->object.unq.cdr
3130 
3131 #define is_undefined(p)                (type(p) == T_UNDEFINED)
3132 #define undefined_name(p)              (T_Undf(p))->object.undef.name
3133 #define undefined_name_length(p)       (T_Undf(p))->object.undef.len
3134 #define undefined_set_name_length(p, L) (T_Undf(p))->object.undef.len = L
3135 #define eof_name(p)                    (T_Eof(p))->object.eof.name
3136 #define eof_name_length(p)             (T_Eof(p))->object.eof.len
3137 
3138 #define is_any_vector(p)               t_vector_p[type(p)]
3139 #define is_normal_vector(p)            (type(p) == T_VECTOR)
3140 #define vector_length(p)               (p)->object.vector.length
3141 #define unchecked_vector_elements(p)   (p)->object.vector.elements.objects
3142 #define unchecked_vector_element(p, i) ((p)->object.vector.elements.objects[i])
3143 #define vector_element(p, i)           ((T_Vec(p))->object.vector.elements.objects[i])
3144 #define vector_elements(p)             (T_Vec(p))->object.vector.elements.objects
3145 #define vector_getter(p)               (T_Vec(p))->object.vector.vget
3146 #define vector_setter(p)               (T_Vec(p))->object.vector.setv.vset
3147 #define vector_block(p)                (T_Vec(p))->object.vector.block
3148 #define unchecked_vector_block(p)      p->object.vector.block
3149 
3150 #define typed_vector_typer(p)          T_Prc((T_Vec(p))->object.vector.setv.fset)
3151 #define typed_vector_set_typer(p, Fnc) (T_Vec(p))->object.vector.setv.fset = T_Prc(Fnc)
3152 #define typed_vector_gc_mark(p)        ((is_c_function(typed_vector_typer(p))) ? c_function_marker(typed_vector_typer(p)) : mark_typed_vector_1)
3153 #define typed_vector_typer_call(sc, p, Args) \
3154   ((is_c_function(typed_vector_typer(p))) ? c_function_call(typed_vector_typer(p))(sc, Args) : s7_apply_function(sc, typed_vector_typer(p), Args))
3155 
3156 #define is_int_vector(p)               (type(p) == T_INT_VECTOR)
3157 #define int_vector(p, i)               ((T_Ivc(p))->object.vector.elements.ints[i])
3158 #define int_vector_ints(p)             (T_Ivc(p))->object.vector.elements.ints
3159 
3160 #define is_float_vector(p)             (type(p) == T_FLOAT_VECTOR)
3161 #define float_vector(p, i)             ((T_Fvc(p))->object.vector.elements.floats[i])
3162 #define float_vector_floats(p)         (T_Fvc(p))->object.vector.elements.floats
3163 
3164 #define is_byte_vector(p)              (type(p) == T_BYTE_VECTOR)
3165 #define byte_vector_length(p)          (T_BVc(p))->object.vector.length
3166 #define byte_vector_bytes(p)           (T_BVc(p))->object.vector.elements.bytes
3167 #define byte_vector(p, i)              ((T_BVc(p))->object.vector.elements.bytes[i])
3168 #define is_string_or_byte_vector(p)    ((type(p) == T_STRING) || (type(p) == T_BYTE_VECTOR))
3169 
3170 #define vector_dimension_info(p)       ((vdims_t *)(T_Vec(p))->object.vector.block->ex.ex_info)
3171 #define vector_set_dimension_info(p, d) (T_Vec(p))->object.vector.block->ex.ex_info = (void  *)d
3172 #define vector_ndims(p)                vdims_rank(vector_dimension_info(p))
3173 #define vector_dimension(p, i)         vdims_dims(vector_dimension_info(p))[i]
3174 #define vector_dimensions(p)           vdims_dims(vector_dimension_info(p))
3175 #define vector_offset(p, i)            vdims_offsets(vector_dimension_info(p))[i]
3176 #define vector_offsets(p)              vdims_offsets(vector_dimension_info(p))
3177 #define vector_rank(p)                 ((vector_dimension_info(p)) ? vector_ndims(p) : 1)
3178 #define vector_has_dimensional_info(p) (vector_dimension_info(p))
3179 
3180 #define subvector_vector(p)            T_Vec(((vector_dimension_info(T_SVec(p))) ? vdims_original(vector_dimension_info(p)) : (p)->object.vector.block->nx.ksym))
3181 #define subvector_set_vector(p, vect)  (T_SVec(p))->object.vector.block->nx.ksym = T_Vec(vect)
3182 
3183 #define rootlet_element(p, i)          unchecked_vector_element(p, i)
3184 #define rootlet_elements(p)            unchecked_vector_elements(p)
3185 #define rootlet_block(p)               unchecked_vector_block(p)
3186 
3187 #define stack_element(p, i)            unchecked_vector_element(T_Stk(p), i)
3188 #define stack_elements(p)              unchecked_vector_elements(T_Stk(p))
3189 #define stack_block(p)                 unchecked_vector_block(T_Stk(p))
3190 #define current_stack_top(Sc)          ((Sc)->stack_end - (Sc)->stack_start)
3191 #define temp_stack_top(p)              (T_Stk(p))->object.stk.top
3192 /* #define stack_flags(p)              (T_Stk(p))->object.stk.flags */
3193 #define stack_clear_flags(p)           (T_Stk(p))->object.stk.flags = 0
3194 #define stack_has_pairs(p)             (((T_Stk(p))->object.stk.flags & 1) != 0)
3195 #define stack_set_has_pairs(p)         (T_Stk(p))->object.stk.flags |= 1
3196 /* #define stack_has_circles(p)        (((T_Stk(p))->object.stk.flags & 4) != 0) */
3197 /* #define stack_set_has_circles(p)    (T_Stk(p))->object.stk.flags |= 4 */
3198 #define stack_has_counters(p)          (((T_Stk(p))->object.stk.flags & 2) != 0)
3199 #define stack_set_has_counters(p)      (T_Stk(p))->object.stk.flags |= 2
3200 
3201 #define is_hash_table(p)               (type(p) == T_HASH_TABLE)
3202 #define is_mutable_hash_table(p)       ((full_type(T_Pos(p)) & (TYPE_MASK | T_IMMUTABLE)) == T_HASH_TABLE)
3203 #define hash_table_mask(p)             (T_Hsh(p))->object.hasher.mask
3204 #define hash_table_block(p)            (T_Hsh(p))->object.hasher.block
3205 #define unchecked_hash_table_block(p)  p->object.hasher.block
3206 #define hash_table_set_block(p, b)     (T_Hsh(p))->object.hasher.block = b
3207 #define hash_table_element(p, i)       (T_Hsh(p))->object.hasher.elements[i]
3208 #define hash_table_elements(p)         (T_Hsh(p))->object.hasher.elements /* block data (dx) */
3209 #define hash_table_entries(p)          hash_table_block(p)->nx.nx_int
3210 #define hash_table_checker(p)          (T_Hsh(p))->object.hasher.hash_func
3211 #define hash_table_mapper(p)           (T_Hsh(p))->object.hasher.loc
3212 #define hash_table_checker_locked(p)   (hash_table_mapper(p) != default_hash_map)
3213 #define hash_table_procedures(p)       T_Lst(hash_table_block(p)->ex.ex_ptr)
3214 #define hash_table_set_procedures(p, Lst)  hash_table_block(p)->ex.ex_ptr = T_Lst(Lst)
3215 #define hash_table_procedures_checker(p)   car(hash_table_procedures(p))
3216 #define hash_table_procedures_mapper(p)    cdr(hash_table_procedures(p))
3217 #define hash_table_set_procedures_mapper(p, f) set_cdr(hash_table_procedures(p), f)
3218 #define hash_table_key_typer(p)            T_Prc(opt1_any(hash_table_procedures(p)))
3219 #define hash_table_set_key_typer(p, Fnc)   set_opt1_any(p, T_Prc(Fnc))
3220 #define hash_table_value_typer(p)          T_Prc(opt2_any(hash_table_procedures(p)))
3221 #define hash_table_set_value_typer(p, Fnc) set_opt2_any(p, T_Prc(Fnc))
3222 #define weak_hash_iters(p)                 hash_table_block(p)->ln.tag
3223 
3224 #if S7_DEBUGGING
3225 #define T_Itr_Pos(p)                   titr_pos(sc, T_Itr(p), __func__, __LINE__)
3226 #define T_Itr_Len(p)                   titr_len(sc, T_Itr(p), __func__, __LINE__)
3227 #define T_Itr_Hash(p)                  titr_hash(sc, T_Itr(p), __func__, __LINE__)
3228 #define T_Itr_Let(p)                   titr_let(sc, T_Itr(p), __func__, __LINE__)
3229 #define T_Itr_Pair(p)                  titr_pair(sc, T_Itr(p), __func__, __LINE__)
3230 #else
3231 #define T_Itr_Pos(p)                   p
3232 #define T_Itr_Len(p)                   p
3233 #define T_Itr_Hash(p)                  p
3234 #define T_Itr_Let(p)                   p
3235 #define T_Itr_Pair(p)                  p
3236 #endif
3237 
3238 #define is_iterator(p)                 (type(p) == T_ITERATOR)
3239 #define iterator_sequence(p)           (T_Itr(p))->object.iter.obj
3240 #define iterator_position(p)           (T_Itr_Pos(p))->object.iter.lc.loc
3241 #define iterator_length(p)             (T_Itr_Len(p))->object.iter.lw.len
3242 #define iterator_next(p)               (T_Itr(p))->object.iter.next
3243 #define iterator_is_at_end(p)          ((full_type(T_Itr(p)) & T_ITER_OK) == 0)
3244 #define iterator_slow(p)               T_Lst((T_Itr_Pair(p))->object.iter.lw.slow)
3245 #define iterator_set_slow(p, Val)      (T_Itr_Pair(p))->object.iter.lw.slow = T_Lst(Val)
3246 #define iterator_hash_current(p)       (T_Itr_Hash(p))->object.iter.lw.hcur
3247 #define iterator_current(p)            (T_Itr(p))->object.iter.cur
3248 #define iterator_current_slot(p)       T_Sln((T_Itr_Let(p))->object.iter.lc.lcur)
3249 #define iterator_set_current_slot(p, Val) (T_Itr_Let(p))->object.iter.lc.lcur = T_Sln(Val)
3250 #define iterator_let_cons(p)           (T_Itr_Let(p))->object.iter.cur
3251 
3252 #define ITERATOR_END                   eof_object
3253 #define ITERATOR_END_NAME              "#<eof>"
3254 
3255 #define is_input_port(p)               (type(p) == T_INPUT_PORT)
3256 #define is_output_port(p)              (type(p) == T_OUTPUT_PORT)
3257 #define port_port(p)                   (T_Prt(p))->object.prt.port
3258 #define is_string_port(p)              (port_type(p) == STRING_PORT)
3259 #define is_file_port(p)                (port_type(p) == FILE_PORT)
3260 #define is_function_port(p)            (port_type(p) == FUNCTION_PORT)
3261 #define port_filename_block(p)         port_port(p)->filename_block
3262 #define port_filename(p)               port_port(p)->filename
3263 #define port_filename_length(p)        port_port(p)->filename_length
3264 #define port_file(p)                   port_port(p)->file
3265 #define port_data_block(p)             port_port(p)->block
3266 #define unchecked_port_data_block(p)   p->object.prt.port->block
3267 #define port_line_number(p)            port_port(p)->line_number
3268 #define port_file_number(p)            port_port(p)->file_number
3269 #define port_data(p)                   (T_Prt(p))->object.prt.data
3270 #define port_data_size(p)              (T_Prt(p))->object.prt.size
3271 #define port_position(p)               (T_Prt(p))->object.prt.point
3272 #define port_block(p)                  (T_Prt(p))->object.prt.block
3273 #define port_type(p)                   port_port(p)->ptype
3274 #define port_is_closed(p)              port_port(p)->is_closed
3275 #define port_set_closed(p, Val)        port_port(p)->is_closed = Val /* this can't be a type bit because sweep checks it after the type has been cleared */
3276 #define port_needs_free(p)             port_port(p)->needs_free
3277 #define port_next(p)                   port_block(p)->nx.next
3278 #define port_original_input_string(p)  port_port(p)->orig_str
3279 #define port_output_function(p)        port_port(p)->output_function /* these two are for function ports */
3280 #define port_output_scheme_function(p) port_port(p)->orig_str
3281 #define port_input_function(p)         port_port(p)->input_function
3282 #define port_input_scheme_function(p)  port_port(p)->orig_str
3283 
3284 #define current_input_port(Sc)         Sc->input_port
3285 #define set_current_input_port(Sc, P)  Sc->input_port = P
3286 #define current_output_port(Sc)        Sc->output_port
3287 #define set_current_output_port(Sc, P) Sc->output_port = P
3288 
3289 #define port_read_character(p)         port_port(p)->pf->read_character
3290 #define port_read_line(p)              port_port(p)->pf->read_line
3291 #define port_display(p)                port_port(p)->pf->displayer
3292 #define port_write_character(p)        port_port(p)->pf->write_character
3293 #define port_write_string(p)           port_port(p)->pf->write_string
3294 #define port_read_semicolon(p)         port_port(p)->pf->read_semicolon
3295 #define port_read_white_space(p)       port_port(p)->pf->read_white_space
3296 #define port_read_name(p)              port_port(p)->pf->read_name
3297 #define port_read_sharp(p)             port_port(p)->pf->read_sharp
3298 #define port_close(p)                  port_port(p)->pf->close_port
3299 
3300 #define is_c_function(f)               (type(f) >= T_C_FUNCTION)
3301 #define is_c_function_star(f)          (type(f) == T_C_FUNCTION_STAR)
3302 #define is_any_c_function(f)           (type(f) >= T_C_FUNCTION_STAR)
3303 #define c_function_data(f)             (T_Fnc(f))->object.fnc.c_proc
3304 #define c_function_call(f)             (T_Fnc(f))->object.fnc.ff
3305 #define c_function_required_args(f)    (T_Fnc(f))->object.fnc.required_args
3306 #define c_function_optional_args(f)    (T_Fnc(f))->object.fnc.optional_args
3307 #define c_function_all_args(f)         (T_Fnc(f))->object.fnc.all_args
3308 #define c_function_name(f)             c_function_data(f)->name
3309 #define c_function_name_length(f)      c_function_data(f)->name_length
3310 #define c_function_documentation(f)    c_function_data(f)->doc
3311 #define c_function_signature(f)        c_function_data(f)->signature
3312 #define c_function_setter(f)           T_Prc(c_function_data(f)->setter)
3313 #define c_function_set_setter(f, Val)  c_function_data(f)->setter = T_Prc(Val)
3314 #define c_function_block(f)            (f)->object.fnc.c_proc->block /* no type checking here */
3315 #define c_function_class(f)            c_function_data(f)->id
3316 #define c_function_chooser(f)          c_function_data(f)->chooser
3317 #define c_function_base(f)             T_App(c_function_data(f)->generic_ff)
3318 #define c_function_set_base(f, Val)    c_function_data(f)->generic_ff = T_App(Val)
3319 #define c_function_marker(f)           c_function_data(f)->cam.marker              /* the mark function for the vector (mark_vector_1 etc) */
3320 #define c_function_set_marker(f, Val)  c_function_data(f)->cam.marker = Val
3321 #define c_function_symbol(f)           c_function_data(f)->sam.c_sym
3322 
3323 #define c_function_bool_setter(f)      c_function_data(f)->dam.bool_setter
3324 #define c_function_set_bool_setter(f, Val) c_function_data(f)->dam.bool_setter = Val
3325 #define c_function_arg_defaults(f)     c_function_data(T_Fst(f))->dam.arg_defaults
3326 #define c_function_call_args(f)        c_function_data(T_Fst(f))->cam.call_args
3327 #define c_function_arg_names(f)        c_function_data(T_Fst(f))->sam.arg_names
3328 
3329 #define set_c_function(X, f)           do {set_opt1_cfunc(X, f); set_fn_direct(X, c_function_call(f));} while (0)
3330 #define c_function_opt_data(f)         c_function_data(f)->opt_data
3331 
3332 #define is_c_macro(p)                  (type(p) == T_C_MACRO)
3333 #define c_macro_data(f)                (T_CMac(f))->object.fnc.c_proc
3334 #define c_macro_call(f)                (T_CMac(f))->object.fnc.ff
3335 #define c_macro_name(f)                c_macro_data(f)->name
3336 #define c_macro_name_length(f)         c_macro_data(f)->name_length
3337 #define c_macro_required_args(f)       (T_CMac(f))->object.fnc.required_args
3338 #define c_macro_all_args(f)            (T_CMac(f))->object.fnc.all_args
3339 #define c_macro_setter(f)              T_Prc(c_macro_data(f)->setter)
3340 #define c_macro_set_setter(f, Val)     c_macro_data(f)->setter = T_Prc(Val)
3341 
3342 #define is_random_state(p)             (type(p) == T_RANDOM_STATE)
3343 #define random_gmp_state(p)            (p)->object.rng.state /* sweep sees free cell in big_random_state gc_list and needs to call gmprandclear on its value */
3344 #define random_seed(p)                 (T_Ran(p))->object.rng.seed
3345 #define random_carry(p)                (T_Ran(p))->object.rng.carry
3346 
3347 #define continuation_block(p)          (T_Con(p))->object.cwcc.block
3348 #define continuation_stack(p)          T_Stk(T_Con(p)->object.cwcc.stack)
3349 #define continuation_set_stack(p, Val) (T_Con(p))->object.cwcc.stack = T_Stk(Val)
3350 #define continuation_stack_end(p)      (T_Con(p))->object.cwcc.stack_end
3351 #define continuation_stack_start(p)    (T_Con(p))->object.cwcc.stack_start
3352 #define continuation_stack_top(p)      (continuation_stack_end(p) - continuation_stack_start(p))
3353 #define continuation_op_stack(p)       (T_Con(p))->object.cwcc.op_stack
3354 #define continuation_stack_size(p)     continuation_block(p)->nx.ix.i1
3355 #define continuation_op_loc(p)         continuation_block(p)->nx.ix.i2
3356 #define continuation_op_size(p)        continuation_block(p)->ln.tag
3357 #define continuation_key(p)            continuation_block(p)->ex.ckey
3358 /* this can overflow int32_t -- baffle_key is s7_int, so ckey should be also */
3359 #define continuation_name(p)           continuation_block(p)->dx.d_ptr
3360 
3361 #define call_exit_goto_loc(p)          (T_Got(p))->object.rexit.goto_loc
3362 #define call_exit_op_loc(p)            (T_Got(p))->object.rexit.op_stack_loc
3363 #define call_exit_active(p)            (T_Got(p))->object.rexit.active
3364 #define call_exit_name(p)              (T_Got(p))->object.rexit.name
3365 
3366 #define is_continuation(p)             (type(p) == T_CONTINUATION)
3367 #define is_goto(p)                     (type(p) == T_GOTO)
3368 #define is_macro(p)                    (type(p) == T_MACRO)
3369 #define is_macro_star(p)               (type(p) == T_MACRO_STAR)
3370 #define is_bacro_star(p)               (type(p) == T_BACRO_STAR)
3371 #define is_either_macro(p)             ((is_macro(p)) || (is_macro_star(p)))
3372 #define is_either_bacro(p)             ((type(p) == T_BACRO) || (type(p) == T_BACRO_STAR))
3373 
3374 #define is_closure(p)                  (type(p) == T_CLOSURE)
3375 #define is_closure_star(p)             (type(p) == T_CLOSURE_STAR)
3376 #define closure_args(p)                T_Arg((T_Clo(p))->object.func.args)
3377 #define closure_set_args(p, Val)       (T_Clo(p))->object.func.args = T_Arg(Val)
3378 #define closure_body(p)                (T_Pair((T_Clo(p))->object.func.body))
3379 #define closure_set_body(p, Val)       (T_Clo(p))->object.func.body = T_Pair(Val)
3380 #define closure_let(p)                 T_Lid((T_Clo(p))->object.func.env)
3381 #define closure_set_let(p, L)          (T_Clo(p))->object.func.env = T_Lid(L)
3382 #define closure_arity(p)               (T_Clo(p))->object.func.arity
3383 #define closure_set_arity(p, A)        (T_Clo(p))->object.func.arity = A
3384 
3385 #define closure_setter(p)              (T_Prc((T_Clo(p))->object.func.setter))
3386 #define closure_set_setter(p, Val)     (T_Clo(p))->object.func.setter = T_Prc(Val)
3387 #define closure_map_list(p)            (T_Pair((T_Clo(p))->object.func.setter))
3388 #define closure_set_map_list(p, Val)   (T_Clo(p))->object.func.setter = T_Pair(Val)
3389 #define closure_setter_or_map_list(p)  (T_Clo(p)->object.func.setter)
3390 /* closure_map_list refers to a cyclic list detector in map; since in this case map makes a new closure for its own use,
3391  *   closure_map_list doesn't collide with closure_setter.
3392  */
3393 
3394 #define CLOSURE_ARITY_NOT_SET          0x40000000
3395 #define MAX_ARITY                      0x20000000
3396 #define closure_arity_unknown(p)       (closure_arity(p) == CLOSURE_ARITY_NOT_SET)
3397 #define is_thunk(Sc, Fnc)              ((type(Fnc) >= T_GOTO) && (s7_is_aritable(Sc, Fnc, 0)))
3398 
3399 #define hook_has_functions(p)          (is_pair(s7_hook_functions(sc, T_Clo(p))))
3400 
3401 #define catch_tag(p)                   (T_Cat(p))->object.rcatch.tag
3402 #define catch_goto_loc(p)              (T_Cat(p))->object.rcatch.goto_loc
3403 #define catch_op_loc(p)                (T_Cat(p))->object.rcatch.op_stack_loc
3404 #define catch_handler(p)               T_Pos((T_Cat(p))->object.rcatch.handler)
3405 #define catch_set_handler(p, val)      (T_Cat(p))->object.rcatch.handler = T_Pos(val)
3406 
3407 #define catch_all_goto_loc(p)          (C_Let(p, L_CATCH))->object.envr.edat.ctall.goto_loc
3408 #define catch_all_set_goto_loc(p, L)   (S_Let(p, L_CATCH))->object.envr.edat.ctall.goto_loc = L
3409 #define catch_all_op_loc(p)            (C_Let(p, L_CATCH))->object.envr.edat.ctall.op_stack_loc
3410 #define catch_all_set_op_loc(p, L)     (S_Let(p, L_CATCH))->object.envr.edat.ctall.op_stack_loc = L
3411 
3412 #define dynamic_wind_state(p)          (T_Dyn(p))->object.winder.state
3413 #define dynamic_wind_in(p)             (T_Dyn(p))->object.winder.in
3414 #define dynamic_wind_out(p)            (T_Dyn(p))->object.winder.out
3415 #define dynamic_wind_body(p)           (T_Dyn(p))->object.winder.body
3416 
3417 #define is_c_object(p)                 (type(p) == T_C_OBJECT)
3418 #define c_object_value(p)              (T_Obj(p))->object.c_obj.value
3419 #define c_object_type(p)               (T_Obj(p))->object.c_obj.type
3420 #define c_object_let(p)                T_Lid((T_Obj(p))->object.c_obj.e)
3421 #define c_object_set_let(p, L)         (T_Obj(p))->object.c_obj.e = T_Lid(L)
3422 #define c_object_s7(p)                 (T_Obj(p))->object.c_obj.sc
3423 
3424 #define c_object_info(Sc, p)           Sc->c_object_types[c_object_type(T_Obj(p))]
3425 #define c_object_free(Sc, p)           c_object_info(Sc, p)->free
3426 #define c_object_mark(Sc, p)           c_object_info(Sc, p)->mark
3427 #define c_object_gc_mark(Sc, p)        c_object_info(Sc, p)->gc_mark
3428 #define c_object_gc_free(Sc, p)        c_object_info(Sc, p)->gc_free
3429 #define c_object_ref(Sc, p)            c_object_info(Sc, p)->ref
3430 #define c_object_getf(Sc, p)           c_object_info(Sc, p)->getter
3431 #define c_object_set(Sc, p)            c_object_info(Sc, p)->set
3432 #define c_object_setf(Sc, p)           c_object_info(Sc, p)->setter
3433 #if (!DISABLE_DEPRECATED)
3434   #define c_object_print(Sc, p)        c_object_info(Sc, p)->print
3435 #endif
3436 #define c_object_len(Sc, p)            c_object_info(Sc, p)->length
3437 #define c_object_eql(Sc, p)            c_object_info(Sc, p)->eql
3438 #define c_object_equal(Sc, p)          c_object_info(Sc, p)->equal
3439 #define c_object_equivalent(Sc, p)     c_object_info(Sc, p)->equivalent
3440 #define c_object_fill(Sc, p)           c_object_info(Sc, p)->fill
3441 #define c_object_copy(Sc, p)           c_object_info(Sc, p)->copy
3442 #define c_object_reverse(Sc, p)        c_object_info(Sc, p)->reverse
3443 #define c_object_to_list(Sc, p)        c_object_info(Sc, p)->to_list
3444 #define c_object_to_string(Sc, p)      c_object_info(Sc, p)->to_string
3445 #define c_object_scheme_name(Sc, p)    T_Str(c_object_info(Sc, p)->scheme_name)
3446 
3447 #define c_pointer(p)                   (T_Ptr(p))->object.cptr.c_pointer
3448 #define c_pointer_type(p)              (T_Ptr(p))->object.cptr.c_type
3449 #define c_pointer_info(p)              (T_Ptr(p))->object.cptr.info
3450 #define c_pointer_weak1(p)             (T_Ptr(p))->object.cptr.weak1
3451 #define c_pointer_weak2(p)             (T_Ptr(p))->object.cptr.weak2
3452 #define c_pointer_set_weak1(p, q)      (T_Ptr(p))->object.cptr.weak1 = T_Pos(q)
3453 #define c_pointer_set_weak2(p, q)      (T_Ptr(p))->object.cptr.weak2 = T_Pos(q)
3454 #define is_c_pointer(p)                (type(p) == T_C_POINTER)
3455 
3456 #define is_counter(p)                  (type(p) == T_COUNTER)
3457 #define counter_result(p)              (T_Ctr(p))->object.ctr.result
3458 #define counter_set_result(p, Val)     (T_Ctr(p))->object.ctr.result = T_Pos(Val)
3459 #define counter_list(p)                (T_Ctr(p))->object.ctr.list
3460 #define counter_set_list(p, Val)       (T_Ctr(p))->object.ctr.list = T_Pos(Val)
3461 #define counter_capture(p)             (T_Ctr(p))->object.ctr.cap
3462 #define counter_set_capture(p, Val)    (T_Ctr(p))->object.ctr.cap = Val
3463 #define counter_let(p)                 T_Lid((T_Ctr(p))->object.ctr.env)
3464 #define counter_set_let(p, L)          (T_Ctr(p))->object.ctr.env = T_Lid(L)
3465 #define counter_slots(p)               T_Sln(T_Ctr(p)->object.ctr.slots)
3466 #define counter_set_slots(p, Val)      (T_Ctr(p))->object.ctr.slots = T_Sln(Val)
3467 
3468 #if __cplusplus && HAVE_COMPLEX_NUMBERS
3469   using namespace std;                /* the code has to work in C as well as C++, so we can't scatter std:: all over the place */
3470   typedef complex<s7_double> s7_complex;
3471   static s7_double Real(complex<s7_double> x) {return(real(x));} /* protect the C++ name */
3472   static s7_double Imag(complex<s7_double> x) {return(imag(x));}
3473 #endif
3474 
3475 #define integer(p)                     (T_Int(p))->object.number.integer_value
3476 #define set_integer(p, x)              integer(p) = x
3477 #define real(p)                        (T_Rel(p))->object.number.real_value
3478 #define set_real(p, x)                 real(p) = x
3479 #define numerator(p)                   (T_Frc(p))->object.number.fraction_value.numerator
3480 #define denominator(p)                 (T_Frc(p))->object.number.fraction_value.denominator
3481 #define fraction(p)                    (((long_double)numerator(p)) / ((long_double)denominator(p)))
3482 #define inverted_fraction(p)           (((long_double)denominator(p)) / ((long_double)numerator(p)))
3483 #define real_part(p)                   (T_Cmp(p))->object.number.complex_value.rl
3484 #define set_real_part(p, x)            real_part(p) = x
3485 #define imag_part(p)                   (T_Cmp(p))->object.number.complex_value.im
3486 #define set_imag_part(p, x)            imag_part(p) = x
3487 #if HAVE_COMPLEX_NUMBERS
3488   #define to_c_complex(p)              CMPLX(real_part(p), imag_part(p))
3489 #endif
3490 
3491 #if WITH_GMP
3492 #define big_integer(p)                 ((T_Bgi(p))->object.number.bgi->n)
3493 #define big_integer_nxt(p)             (p)->object.number.bgi->nxt
3494 #define big_integer_bgi(p)             (p)->object.number.bgi
3495 #define big_ratio(p)                   ((T_Bgf(p))->object.number.bgr->q)
3496 #define big_ratio_nxt(p)               (p)->object.number.bgr->nxt
3497 #define big_ratio_bgr(p)               (p)->object.number.bgr
3498 #define big_real(p)                    ((T_Bgr(p))->object.number.bgf->x)
3499 #define big_real_nxt(p)                (p)->object.number.bgf->nxt
3500 #define big_real_bgf(p)                (p)->object.number.bgf
3501 #define big_complex(p)                 ((T_Bgz(p))->object.number.bgc->z)
3502 #define big_complex_nxt(p)             (p)->object.number.bgc->nxt
3503 #define big_complex_bgc(p)             (p)->object.number.bgc
3504 #endif
3505 
3506 #if S7_DEBUGGING
3507 static void set_type_1(s7_pointer p, uint64_t f, const char *func, int line)
3508 {
3509   p->previous_alloc_line = p->current_alloc_line;
3510   p->previous_alloc_func = p->current_alloc_func;
3511   p->previous_alloc_type = p->current_alloc_type;
3512   p->current_alloc_line = line;
3513   p->current_alloc_func = func;
3514   p->current_alloc_type = f;
3515   p->explicit_free_line = 0;
3516   p->uses++;
3517   if (((f) & TYPE_MASK) == T_FREE)
3518     fprintf(stderr, "%d: set free, %p type to %" PRIx64 "\n", __LINE__, p, (int64_t)(f));
3519   else
3520     {
3521       if (((f) & TYPE_MASK) >= NUM_TYPES)
3522 	fprintf(stderr, "%d: set invalid type, %p type to %" PRIx64 "\n", __LINE__, p, (int64_t)(f));
3523       else
3524 	{
3525 	  if (((full_type(p) & T_IMMUTABLE) != 0) && ((full_type(p) != (uint64_t)(f))))
3526 	    {
3527 	      fprintf(stderr, "%s[%d]: set immutable %p type %d to %" print_s7_int "\n", __func__, __LINE__, p, unchecked_type(p), (int64_t)(f));
3528 	      abort();
3529 	    }
3530           if (((full_type(p) & T_UNHEAP) != 0) && (((f) & T_UNHEAP) == 0))
3531 	    fprintf(stderr, "%s[%d]: clearing unheap in set type!\n", __func__, __LINE__);
3532 	}}
3533   full_type(p) = f;
3534 }
3535 #endif
3536 
3537 #define number_name(p)                 (char *)((T_Num(p))->object.number_name.name + 1)
3538 #define number_name_length(p)          (T_Num(p))->object.number_name.name[0]
3539 
3540 static void set_number_name(s7_pointer p, const char *name, int32_t len)
3541 {
3542   /* if no number name: teq +110 tread +30 tform +90 */
3543   if ((len >= 0) && (len < NUMBER_NAME_SIZE) && (!is_mutable_number(p)))
3544     {
3545       set_has_number_name(p);
3546       number_name_length(p) = (uint8_t)len;
3547       memcpy((void *)number_name(p), (void *)name, len);
3548       (number_name(p))[len] = 0;
3549     }
3550 }
3551 
3552 static s7_int s7_int_min = 0;
3553 static int32_t s7_int_digits_by_radix[17];
3554 
3555 #define S7_INT_BITS 63
3556 
3557 #define S7_INT64_MAX 9223372036854775807LL
3558 #define S7_INT64_MIN (int64_t)(-S7_INT64_MAX - 1LL)
3559 
3560 #define S7_INT32_MAX 2147483647LL
3561 #define S7_INT32_MIN (-S7_INT32_MAX - 1LL)
3562 
3563 static void init_int_limits(void)
3564 {
3565   int32_t i;
3566 #if WITH_GMP
3567 #define S7_LOG_INT64_MAX 36.736800
3568 #else
3569   /* actually not safe = (log (- (expt 2 63) 1)) and (log (- (expt 2 31) 1)) (using 63 and 31 bits) */
3570 #define S7_LOG_INT64_MAX 43.668274
3571 #endif
3572 
3573   s7_int_min = S7_INT64_MIN; /* see comment in s7_make_ratio -- we're trying to hack around a gcc bug (9.2.1 Ubuntu) */
3574 
3575   s7_int_digits_by_radix[0] = 0;
3576   s7_int_digits_by_radix[1] = 0;
3577 
3578   for (i = 2; i < 17; i++)
3579     s7_int_digits_by_radix[i] = (int32_t)(floor(S7_LOG_INT64_MAX / log((double)i)));
3580 }
3581 
3582 static s7_pointer make_permanent_integer_unchecked(s7_int i)
3583 {
3584   s7_pointer p;
3585   p = (s7_pointer)Calloc(1, sizeof(s7_cell));
3586   set_type_bit(p, T_IMMUTABLE | T_INTEGER | T_UNHEAP);
3587   integer(p) = i;
3588   return(p);
3589 }
3590 
3591 #define NUM_CHARS 256
3592 
3593 #ifndef NUM_SMALL_INTS
3594   #define NUM_SMALL_INTS 8192
3595   /* 65536: tshoot -6, tvect -50, dup -26, trclo -27, tmap -48, tsort -14, tlet -16, trec -58, thash -40 */
3596 #else
3597 #if (NUM_SMALL_INTS < NUM_CHARS)
3598   #error num_small_ints is less than num_chars which will not work
3599   /* g_char_to_integer assumes this is at least NUM_CHARS */
3600 #endif
3601 #endif
3602 
3603 static s7_pointer *small_ints = NULL;
3604 #define small_int(Val) small_ints[Val]
3605 #define is_small_int(n) ((n & ~(NUM_SMALL_INTS - 1)) == 0)                 /* ((n >= 0) && (n < NUM_SMALL_INTS)) is slower */
3606 
3607 static s7_pointer real_zero, real_NaN, complex_NaN, real_pi, real_one, arity_not_set, max_arity, real_infinity, real_minus_infinity;
3608 static s7_pointer int_zero, int_one, int_two, int_three, minus_one, minus_two, mostfix, leastfix;
3609 
3610 static void init_small_ints(void)
3611 {
3612   const char *ones[10] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
3613   s7_cell *cells;
3614   int32_t i;
3615   small_ints = (s7_pointer *)malloc(NUM_SMALL_INTS * sizeof(s7_pointer));
3616   cells = (s7_cell *)calloc((NUM_SMALL_INTS), sizeof(s7_cell));
3617   for (i = 0; i < NUM_SMALL_INTS; i++)
3618     {
3619       s7_pointer p;
3620       small_ints[i] = &cells[i];
3621       p = small_ints[i];
3622       set_type_bit(p, T_IMMUTABLE | T_INTEGER | T_UNHEAP);
3623       integer(p) = i;
3624     }
3625   for (i = 0; i < 10; i++)
3626     set_number_name(small_ints[i], ones[i], 1);
3627 
3628   /* setup a few other numbers while we're here */
3629   #define EXTRA_NUMBERS 11
3630   cells = (s7_cell *)calloc(EXTRA_NUMBERS, sizeof(s7_cell));
3631 
3632   #define init_real(Ptr, Num, Name, Name_Len) do {set_full_type(Ptr, T_REAL | T_IMMUTABLE | T_UNHEAP); set_real(Ptr, Num); set_number_name(Ptr, Name, Name_Len);} while (0)
3633   #define init_real_no_name(Ptr, Num)         do {set_full_type(Ptr, T_REAL | T_IMMUTABLE | T_UNHEAP); set_real(Ptr, Num);} while (0)
3634   #define init_complex(Ptr, Real, Imag, Name, Name_Len) \
3635     do {set_full_type(Ptr, T_COMPLEX | T_IMMUTABLE | T_UNHEAP); set_real_part(Ptr, Real); set_imag_part(Ptr, Imag); set_number_name(Ptr, Name, Name_Len);} while (0)
3636 
3637   real_zero = &cells[0]; init_real(real_zero, 0.0, "0.0", 3);
3638   real_one = &cells[1]; init_real(real_one, 1.0, "1.0", 3);
3639   real_NaN = &cells[2]; init_real(real_NaN, NAN, "+nan.0", 6);
3640   complex_NaN = &cells[10]; init_complex(complex_NaN, NAN, NAN, "+nan.0+nan.0i", 13);
3641   real_infinity = &cells[3]; init_real(real_infinity, INFINITY, "+inf.0", 6);
3642   real_minus_infinity = &cells[4]; init_real(real_minus_infinity, -INFINITY, "-inf.0", 6);
3643   real_pi = &cells[5]; init_real_no_name(real_pi, 3.1415926535897932384626433832795029L);
3644 
3645   #define init_integer(Ptr, Num, Name, Name_Len) do {set_full_type(Ptr, T_INTEGER | T_IMMUTABLE | T_UNHEAP); set_integer(Ptr, Num); set_number_name(Ptr, Name, Name_Len);} while (0)
3646   #define init_integer_no_name(Ptr, Num)         do {set_full_type(Ptr, T_INTEGER | T_IMMUTABLE | T_UNHEAP); set_integer(Ptr, Num);} while (0)
3647 
3648   arity_not_set = &cells[6]; init_integer_no_name(arity_not_set, CLOSURE_ARITY_NOT_SET);
3649   max_arity = &cells[7]; init_integer_no_name(max_arity, MAX_ARITY);
3650   minus_one = &cells[8]; init_integer(minus_one, -1, "-1", 2);
3651   minus_two = &cells[9]; init_integer(minus_two, -2, "-2", 2);
3652   int_zero = small_ints[0];
3653   int_one = small_ints[1];
3654   int_two = small_ints[2];
3655   int_three = small_ints[3];
3656 
3657   mostfix = make_permanent_integer_unchecked(S7_INT64_MAX);
3658   leastfix = make_permanent_integer_unchecked(s7_int_min);
3659   set_number_name(mostfix, "9223372036854775807", 19);
3660   set_number_name(leastfix, "-9223372036854775808", 20);
3661 }
3662 
3663 
3664 /* -------------------------------------------------------------------------------- */
3665 #if (defined(__FreeBSD__)) || ((defined(__linux__)) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ > 17)) || (defined(__OpenBSD__)) || (defined(__NetBSD__))
3666   static inline s7_int my_clock(void)
3667   {
3668     struct timespec ts;
3669     clock_gettime(CLOCK_MONOTONIC, &ts);
3670     /* coarse: 0.057u 0.007s, monotonic: 0.083u 0.007s, clock(): 0.624u 0.372s -- coarse since Linux 2.6.32, glibc > 2.17
3671      *   FreeBSD has CLOCK_MONOTONIC_FAST in place of COARSE, OpenBSD and netBSD have neither
3672      *   clock_getres places 1 in tv_nsec in linux, so I assume I divide billion/tv_nsec
3673      *   MacOSX has clock_get_time, and after Sierra 10.12 has clock_gettime
3674      *     apparently we include /usr/include/AvailabilityMacros.h, then #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
3675      *   Windows has QueryPerformanceCounter or something
3676      * maybe just check for POSIX compatibility?
3677      */
3678     return(ts.tv_sec * 1000000000 + ts.tv_nsec); /* accumulated into s7_int so this should be ok: s7.h gives it 64 bits */
3679   }
3680 
3681   static s7_int ticks_per_second(void)
3682   {
3683     struct timespec ts;
3684     clock_getres(CLOCK_MONOTONIC, &ts);
3685     return((ts.tv_nsec == 0) ? 1000000000 : (1000000000 / ts.tv_nsec));
3686   }
3687 #else
3688   #define my_clock clock
3689   #define ticks_per_second() CLOCKS_PER_SEC
3690 #endif
3691 
3692 #ifndef GC_TRIGGER_SIZE
3693   #define GC_TRIGGER_SIZE 64
3694 #endif
3695 
3696 #if S7_DEBUGGING
3697 static void try_to_call_gc_1(s7_scheme *sc, const char *func, int line);
3698 #define try_to_call_gc(Sc) try_to_call_gc_1(Sc, __func__, __LINE__)
3699 #else
3700 static void try_to_call_gc(s7_scheme *sc);
3701 #endif
3702 
3703 #define GC_STATS 1
3704 #define HEAP_STATS 2
3705 #define STACK_STATS 4
3706 #define PROTECTED_OBJECTS_STATS 8
3707 
3708 #define show_gc_stats(Sc)                ((Sc->gc_stats & GC_STATS) != 0)
3709 #define show_stack_stats(Sc)             ((Sc->gc_stats & STACK_STATS) != 0)
3710 #define show_heap_stats(Sc)              ((Sc->gc_stats & HEAP_STATS) != 0)
3711 #define show_protected_objects_stats(Sc) ((Sc->gc_stats & PROTECTED_OBJECTS_STATS) != 0)
3712 
3713 /* new_cell has to include the new cell's type.  In the free list, it is 0 (T_FREE).  If we remove it here,
3714  *   but then hit some error before setting the type, the GC sweep thinks it is a free cell already and
3715  *   does not return it to the free list: a memory leak.
3716  */
3717 #if (!S7_DEBUGGING)
3718 #define new_cell(Sc, Obj, Type)			\
3719   do {						\
3720     if (Sc->free_heap_top <= Sc->free_heap_trigger) try_to_call_gc(Sc); \
3721     Obj = (*(--(Sc->free_heap_top))); \
3722     set_full_type(Obj, Type);	      \
3723     } while (0)
3724 
3725 #define new_cell_no_check(Sc, Obj, Type) do {Obj = (*(--(Sc->free_heap_top))); set_full_type(Obj, Type);} while (0)
3726   /* since sc->free_heap_trigger is GC_TRIGGER_SIZE above the free heap base, we don't need
3727    *   to check it repeatedly after the first such check.
3728    */
3729 #else
3730 
3731 #define new_cell(Sc, Obj, Type)						\
3732   do {									\
3733     if (Sc->free_heap_top <= Sc->free_heap_trigger) try_to_call_gc(Sc); \
3734     Obj = (*(--(Sc->free_heap_top)));					\
3735     Obj->debugger_bits = 0;						\
3736     set_full_type(Obj, Type);						\
3737   } while (0)
3738 
3739 #define new_cell_no_check(Sc, Obj, Type)		    \
3740   do {							    \
3741     Obj = (*(--(Sc->free_heap_top)));			    \
3742     if (Sc->free_heap_top < Sc->free_heap) {fprintf(stderr, "free heap exhausted\n"); abort();}\
3743     Obj->debugger_bits = 0;						\
3744     set_full_type(Obj, Type);				    \
3745     } while (0)
3746 #endif
3747 
3748 #if WITH_GCC
3749 #define make_integer(Sc, N) ({ s7_int _N_; _N_ = (N); (is_small_int(_N_) ? small_int(_N_) : ({ s7_pointer _I_; new_cell(Sc, _I_, T_INTEGER); integer(_I_) = _N_; _I_;}) ); })
3750 
3751 #define make_real(Sc, X) ({ s7_pointer _R_; s7_double _N_ = (X); new_cell(Sc, _R_, T_REAL); set_real(_R_, _N_); _R_;})
3752 
3753 #define make_complex_unchecked(Sc, R, I) ({ s7_pointer _C_; new_cell(Sc, _C_, T_COMPLEX); set_real_part(_C_, R); set_imag_part(_C_, I); _C_;})
3754 #define make_complex(Sc, R, I)						\
3755   ({ s7_double _im_; _im_ = (I); ((_im_ == 0.0) ? make_real(Sc, R) : \
3756 				  ({ s7_pointer _C_; new_cell(Sc, _C_, T_COMPLEX); set_real_part(_C_, R); set_imag_part(_C_, _im_); _C_;}) ); })
3757 
3758 #define real_to_double(Sc, X, Caller)   ({ s7_pointer _x_; _x_ = (X); ((type(_x_) == T_REAL) ? real(_x_) : s7_number_to_real_with_caller(Sc, _x_, Caller)); })
3759 #define rational_to_double(Sc, X)       ({ s7_pointer _x_; _x_ = (X); ((type(_x_) == T_INTEGER) ? (s7_double)integer(_x_) : fraction(_x_)); })
3760 
3761 #else
3762 
3763 #define make_integer(Sc, N)           s7_make_integer(Sc, N)
3764 #define make_real(Sc, X)              s7_make_real(Sc, X)
3765 #define make_complex(Sc, R, I)        s7_make_complex(Sc, R, I)
3766 #define make_complex_unchecked(Sc, R, I) s7_make_complex(Sc, R, I)
3767 #define real_to_double(Sc, X, Caller) s7_number_to_real_with_caller(Sc, X, Caller)
3768 #define rational_to_double(Sc, X)     s7_number_to_real(Sc, X)
3769 #endif
3770 
3771 static inline s7_pointer wrap_integer1(s7_scheme *sc, s7_int x) {integer(sc->integer_wrapper1) = x; return(sc->integer_wrapper1);}
3772 static inline s7_pointer wrap_integer2(s7_scheme *sc, s7_int x) {integer(sc->integer_wrapper2) = x; return(sc->integer_wrapper2);}
3773 static inline s7_pointer wrap_integer3(s7_scheme *sc, s7_int x) {integer(sc->integer_wrapper3) = x; return(sc->integer_wrapper3);}
3774 static inline s7_pointer wrap_real1(s7_scheme *sc, s7_double x) {real(sc->real_wrapper1) = x; return(sc->real_wrapper1);}
3775 static inline s7_pointer wrap_real2(s7_scheme *sc, s7_double x) {real(sc->real_wrapper2) = x; return(sc->real_wrapper2);}
3776 
3777 
3778 /* --------------------------------------------------------------------------------
3779  * local versions of some standard C library functions
3780  * timing tests involving these are very hard to interpret
3781  * local_memset and memclr are faster using int64_t than int32_t
3782  */
3783 
3784 static void local_memset(void *s, uint8_t val, size_t n)
3785 {
3786   uint8_t *s2;
3787 #if S7_ALIGNED
3788   s2 = (uint8_t *)s;
3789 #else
3790 #if (defined(__x86_64__) || defined(__i386__))
3791   if (n >= 8)
3792     {
3793       int64_t ival;
3794       int64_t *s1 = (int64_t *)s;
3795       size_t n8 = n >> 3;
3796       ival = val | (val << 8) | (val << 16) | (((uint64_t)val) << 24); /* uint64_t casts make gcc/clang/fsanitize happy */
3797       ival = (((uint64_t)ival) << 32) | ival;
3798       do {*s1++ = ival;} while (--n8 > 0);
3799       n &= 7;
3800       s2 = (uint8_t *)s1;
3801     }
3802   else s2 = (uint8_t *)s;
3803 #else
3804   s2 = (uint8_t *)s;
3805 #endif
3806 #endif
3807   while (n > 0)
3808     {
3809       *s2++ = val;
3810       n--;
3811     }
3812 }
3813 
3814 static inline s7_int safe_strlen(const char *str)
3815 {
3816   /* this is safer than strlen, and slightly faster */
3817   const char *tmp = str;
3818   if ((!tmp) || (!(*tmp))) return(0);
3819   for (; *tmp; ++tmp);
3820   return(tmp - str);
3821 }
3822 
3823 static char *copy_string_with_length(const char *str, s7_int len)
3824 {
3825   char *newstr;
3826 #if S7_DEBUGGING
3827   if ((len <= 0) || (!str)) fprintf(stderr, "%s[%d]: len: %" print_s7_int ", str: %s\n", __func__, __LINE__, len, str);
3828 #endif
3829   if (len > (1LL << 48)) return(NULL); /* squelch an idiotic warning */
3830   newstr = (char *)Malloc(len + 1);
3831   if (len != 0)
3832     memcpy((void *)newstr, (void *)str, len);
3833   newstr[len] = '\0';
3834   return(newstr);
3835 }
3836 
3837 static char *copy_string(const char *str) {return(copy_string_with_length(str, safe_strlen(str)));}
3838 
3839 static bool local_strcmp(const char *s1, const char *s2)
3840 {
3841   while (true)
3842     {
3843       if (*s1 != *s2++) return(false);
3844       if (*s1++ == 0) return(true);
3845     }
3846   return(true);
3847 }
3848 
3849 #define c_strings_are_equal(Str1, Str2) (local_strcmp(Str1, Str2))
3850 /* scheme strings can have embedded nulls. */
3851 
3852 static bool safe_strcmp(const char *s1, const char *s2)
3853 {
3854   if ((!s1) || (!s2)) return(s1 == s2);
3855   return(local_strcmp(s1, s2));
3856 }
3857 
3858 static bool local_strncmp(const char *s1, const char *s2, size_t n)
3859 {
3860 #if ((!S7_ALIGNED) && (defined(__x86_64__) || defined(__i386__))) /* unaligned accesses are safe on i386 hardware, sez everyone */
3861   if (n >= 8)
3862     {
3863       int64_t *is1, *is2;
3864       size_t n8 = n >> 3;
3865       is1 = (int64_t *)s1;
3866       is2 = (int64_t *)s2;
3867       do {if (*is1++ != *is2++) return(false);} while (--n8 > 0);
3868       s1 = (const char *)is1;
3869       s2 = (const char *)is2;
3870       n &= 7;
3871     }
3872 #endif
3873   while (n > 0)
3874     {
3875       if (*s1++ != *s2++) return(false);
3876       n--;
3877     }
3878   return(true);
3879 }
3880 
3881 #define strings_are_equal_with_length(Str1, Str2, Len) (local_strncmp(Str1, Str2, Len))
3882 
3883 static Sentinel size_t catstrs(char *dst, size_t len, ...) /* NULL-terminated arg list */
3884 {
3885   const char *s, *dend;
3886   char *d;
3887   va_list ap;
3888   d = dst;
3889   dend = (const char *)(dst + len);
3890   while ((*d) && (d < dend)) d++; /* stop at NULL or end-of-buffer */
3891   va_start(ap, len);
3892   for (s = va_arg(ap, const char *); s != NULL; s = va_arg(ap, const char *))
3893     while ((*s) && (d < dend)) {*d++ = *s++;}
3894   *d = '\0';
3895   va_end (ap);
3896   return(d - dst);
3897 }
3898 
3899 static Sentinel size_t catstrs_direct(char *dst, const char *s1, ...) /* NULL-terminated arg list, dst is destination only (assumed empty), all args known to fit in dst */
3900 {
3901   const char *s;
3902   char *d;
3903   va_list ap;
3904   d = dst;
3905   va_start(ap, s1);
3906   for (s = s1; s != NULL; s = va_arg(ap, const char *))
3907     while (*s) {*d++ = *s++;}
3908   *d = '\0';
3909   va_end (ap);
3910   return(d - dst);
3911 }
3912 
3913 static char *pos_int_to_str(s7_scheme *sc, s7_int num, s7_int *len, char endc)
3914 {
3915   char *p, *op;
3916 
3917   p = (char *)(sc->int_to_str3 + INT_TO_STR_SIZE - 1);
3918   op = p;
3919   *p-- = '\0';
3920   if (endc != '\0') *p-- = endc;
3921   do {*p-- = "0123456789"[num % 10]; num /= 10;} while (num);
3922   (*len) = op - p;           /* this includes the trailing #\null */
3923   return((char *)(p + 1));
3924 }
3925 
3926 static char *pos_int_to_str_direct(s7_scheme *sc, s7_int num)
3927 {
3928   char *p;
3929   p = (char *)(sc->int_to_str4 + INT_TO_STR_SIZE - 1);
3930   *p-- = '\0';
3931   do {*p-- = "0123456789"[num % 10]; num /= 10;} while (num);
3932   return((char *)(p + 1));
3933 }
3934 
3935 static char *pos_int_to_str_direct_1(s7_scheme *sc, s7_int num)
3936 {
3937   char *p;
3938   p = (char *)(sc->int_to_str5 + INT_TO_STR_SIZE - 1);
3939   *p-- = '\0';
3940   do {*p-- = "0123456789"[num % 10]; num /= 10;} while (num);
3941   return((char *)(p + 1));
3942 }
3943 
3944 static s7_pointer object_to_truncated_string(s7_scheme *sc, s7_pointer p, s7_int len);
3945 
3946 #if S7_DEBUGGING
3947   #define wrap_string(Sc, Str, Len) wrap_string_1(Sc, Str, Len, __func__, __LINE__)
3948   static s7_pointer wrap_string_1(s7_scheme *sc, const char *str, s7_int len, const char *func, int line);
3949 #else
3950   static s7_pointer wrap_string(s7_scheme *sc, const char *str, s7_int len);
3951 #endif
3952 
3953 #if S7_DEBUGGING && WITH_GCC
3954   static s7_pointer lookup_1(s7_scheme *sc, s7_pointer symbol);
3955   #define lookup(Sc, Sym) check_null_sym(Sc, lookup_1(Sc, Sym), Sym, __LINE__, __func__)
3956   static s7_pointer check_null_sym(s7_scheme *sc, s7_pointer p, s7_pointer sym, int32_t line, const char *func);
3957   #define lookup_unexamined(Sc, Sym) lookup_1(Sc, Sym)
3958 #else
3959   static inline s7_pointer lookup(s7_scheme *sc, s7_pointer symbol);
3960   #define lookup_unexamined(Sc, Sym) lookup(Sc, Sym)
3961 #endif
3962 
3963 #if WITH_GCC
3964   #if S7_DEBUGGING
3965     #define lookup_checked(Sc, Sym) ({s7_pointer _x_; _x_ = lookup_1(Sc, Sym); ((_x_) ? _x_ : unbound_variable(Sc, Sym));})
3966   #else
3967     #define lookup_checked(Sc, Sym) ({s7_pointer _x_; _x_ = lookup(Sc, Sym); ((_x_) ? _x_ : unbound_variable(Sc, Sym));})
3968   #endif
3969 #else
3970   #define lookup_checked(Sc, Sym) lookup(Sc, Sym)
3971 #endif
3972 
3973 static s7_pointer cons_unchecked(s7_scheme *sc, s7_pointer a, s7_pointer b);
3974 static s7_pointer unbound_variable(s7_scheme *sc, s7_pointer sym);
3975 static s7_pointer find_method(s7_scheme *sc, s7_pointer let, s7_pointer symbol);
3976 static s7_pointer find_method_with_let(s7_scheme *sc, s7_pointer let, s7_pointer symbol);
3977 static s7_pointer find_let(s7_scheme *sc, s7_pointer obj);
3978 static s7_pointer prepackaged_type_name(s7_scheme *sc, s7_pointer x);
3979 static const char *type_name(s7_scheme *sc, s7_pointer arg, article_t article);
3980 
3981 static s7_pointer simple_wrong_type_arg_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg, s7_pointer typnam, s7_pointer descr);
3982 static s7_pointer wrong_type_arg_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg_n, s7_pointer arg, s7_pointer typnam, s7_pointer descr);
3983 static s7_pointer out_of_range_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg_n, s7_pointer arg, s7_pointer descr);
3984 static s7_pointer simple_out_of_range_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg, s7_pointer descr);
3985 
3986 /* putting off the type description until s7_error via the sc->unused marker below makes it possible
3987  *    for gcc to speed up the functions that call these as tail-calls.  1-2% overall speedup!
3988  */
3989 #define simple_wrong_type_argument(Sc, Caller, Arg, Desired_Type) \
3990   simple_wrong_type_arg_error_prepackaged(Sc, symbol_name_cell(Caller), Arg, Sc->unused, Sc->prepackaged_type_names[Desired_Type])
3991 
3992 #define wrong_type_argument(Sc, Caller, Num, Arg, Desired_Type)	\
3993   wrong_type_arg_error_prepackaged(Sc, symbol_name_cell(Caller), make_integer(Sc, Num), Arg, Sc->unused, Sc->prepackaged_type_names[Desired_Type])
3994 
3995 #define simple_wrong_type_argument_with_type(Sc, Caller, Arg, Type) \
3996   simple_wrong_type_arg_error_prepackaged(Sc, symbol_name_cell(Caller), Arg, Sc->unused, Type)
3997 
3998 #define wrong_type_argument_with_type(Sc, Caller, Num, Arg, Type)	\
3999   wrong_type_arg_error_prepackaged(Sc, symbol_name_cell(Caller), make_integer(Sc, Num), Arg, Sc->unused, Type)
4000 
4001 #define simple_out_of_range(Sc, Caller, Arg, Description)   simple_out_of_range_error_prepackaged(Sc, symbol_name_cell(Caller), Arg, Description)
4002 #define out_of_range(Sc, Caller, Arg_Num, Arg, Description) out_of_range_error_prepackaged(Sc, symbol_name_cell(Caller), Arg_Num, Arg, Description)
4003 
4004 
4005 /* ---------------- evaluator ops ---------------- */
4006 
4007 /* C=constant, S=symbol, A=fx-callable, Q=quote, D=list of constants, FX=list of A's, P=parlous?, O=one form, M=multiform */
4008 enum {OP_UNOPT, OP_GC_PROTECT, /* must be an even number of ops here, op_gc_protect used below as boundary marker */
4009 
4010       OP_SAFE_C_D, HOP_SAFE_C_D, OP_SAFE_C_S, HOP_SAFE_C_S,
4011       OP_SAFE_C_SS, HOP_SAFE_C_SS, OP_SAFE_C_SC, HOP_SAFE_C_SC, OP_SAFE_C_CS, HOP_SAFE_C_CS, OP_SAFE_C_CQ, HOP_SAFE_C_CQ,
4012       OP_SAFE_C_SSS, HOP_SAFE_C_SSS, OP_SAFE_C_SCS, HOP_SAFE_C_SCS, OP_SAFE_C_SSC, HOP_SAFE_C_SSC, OP_SAFE_C_CSS, HOP_SAFE_C_CSS,
4013       OP_SAFE_C_SCC, HOP_SAFE_C_SCC, OP_SAFE_C_CSC, HOP_SAFE_C_CSC, OP_SAFE_C_CCS, HOP_SAFE_C_CCS,
4014       OP_SAFE_C_ALL_S, HOP_SAFE_C_ALL_S, OP_SAFE_C_opDq, HOP_SAFE_C_opDq, OP_SAFE_C_opSq, HOP_SAFE_C_opSq,
4015       OP_SAFE_C_opSSq, HOP_SAFE_C_opSSq, OP_SAFE_C_opSCq, HOP_SAFE_C_opSCq,
4016       OP_SAFE_C_opCSq, HOP_SAFE_C_opCSq, OP_SAFE_C_S_opSq, HOP_SAFE_C_S_opSq,
4017       OP_SAFE_C_C_opSCq, HOP_SAFE_C_C_opSCq, OP_SAFE_C_S_opSCq, HOP_SAFE_C_S_opSCq, OP_SAFE_C_S_opCSq, HOP_SAFE_C_S_opCSq,
4018       OP_SAFE_C_opSq_S, HOP_SAFE_C_opSq_S, OP_SAFE_C_opSq_C, HOP_SAFE_C_opSq_C,
4019       OP_SAFE_C_opSq_opSq, HOP_SAFE_C_opSq_opSq, OP_SAFE_C_S_opSSq, HOP_SAFE_C_S_opSSq, OP_SAFE_C_C_opSq, HOP_SAFE_C_C_opSq,
4020       OP_SAFE_C_opCSq_C, HOP_SAFE_C_opCSq_C, OP_SAFE_C_opSSq_C, HOP_SAFE_C_opSSq_C, OP_SAFE_C_C_opSSq, HOP_SAFE_C_C_opSSq,
4021       OP_SAFE_C_opSSq_opSSq, HOP_SAFE_C_opSSq_opSSq, OP_SAFE_C_opSSq_opSq, HOP_SAFE_C_opSSq_opSq, OP_SAFE_C_opSq_opSSq, HOP_SAFE_C_opSq_opSSq,
4022       OP_SAFE_C_opSSq_S, HOP_SAFE_C_opSSq_S, OP_SAFE_C_opCSq_S, HOP_SAFE_C_opCSq_S, OP_SAFE_C_opSCq_C, HOP_SAFE_C_opSCq_C,
4023       OP_SAFE_C_op_opSSqq_S, HOP_SAFE_C_op_opSSqq_S, OP_SAFE_C_op_opSqq, HOP_SAFE_C_op_opSqq,
4024       OP_SAFE_C_op_S_opSqq, HOP_SAFE_C_op_S_opSqq, OP_SAFE_C_op_opSq_Sq, HOP_SAFE_C_op_opSq_Sq, OP_SAFE_C_opSq_CS, HOP_SAFE_C_opSq_CS,
4025 
4026       OP_SAFE_C_A, HOP_SAFE_C_A, OP_SAFE_C_AA, HOP_SAFE_C_AA, OP_SAFE_C_SA, HOP_SAFE_C_SA, OP_SAFE_C_AS, HOP_SAFE_C_AS,
4027       OP_SAFE_C_CA, HOP_SAFE_C_CA, OP_SAFE_C_AC, HOP_SAFE_C_AC, OP_SAFE_C_AAA, HOP_SAFE_C_AAA, OP_SAFE_C_4A, HOP_SAFE_C_4A,
4028       OP_SAFE_C_ALL_A, HOP_SAFE_C_ALL_A, OP_SAFE_C_ALL_CA, HOP_SAFE_C_ALL_CA, OP_SAFE_C_INLET_CA, HOP_SAFE_C_INLET_CA,
4029       OP_SAFE_C_SSA, HOP_SAFE_C_SSA, OP_SAFE_C_SAS, HOP_SAFE_C_SAS, OP_SAFE_C_SAA, HOP_SAFE_C_SAA,
4030       OP_SAFE_C_CSA, HOP_SAFE_C_CSA, OP_SAFE_C_SCA, HOP_SAFE_C_SCA, OP_SAFE_C_ASS, HOP_SAFE_C_ASS,
4031       OP_SAFE_C_CAC, HOP_SAFE_C_CAC,                                  /* OP_SAFE_C_CCA, HOP_SAFE_C_CCA, */
4032       OP_SAFE_C_opAq, HOP_SAFE_C_opAq, OP_SAFE_C_opAAq, HOP_SAFE_C_opAAq, OP_SAFE_C_opAAAq, HOP_SAFE_C_opAAAq,
4033       OP_SAFE_C_S_opAq, HOP_SAFE_C_S_opAq, OP_SAFE_C_opAq_S, HOP_SAFE_C_opAq_S,
4034       OP_SAFE_C_S_opAAq, HOP_SAFE_C_S_opAAq, OP_SAFE_C_S_opAAAq, HOP_SAFE_C_S_opAAAq,
4035       OP_SAFE_C_FUNCTION_STAR, HOP_SAFE_C_FUNCTION_STAR, OP_SAFE_C_FUNCTION_STAR_A, HOP_SAFE_C_FUNCTION_STAR_A,
4036       OP_SAFE_C_FUNCTION_STAR_AA, HOP_SAFE_C_FUNCTION_STAR_AA, OP_SAFE_C_FUNCTION_STAR_ALL_A, HOP_SAFE_C_FUNCTION_STAR_ALL_A,
4037       OP_SAFE_C_P, HOP_SAFE_C_P,
4038 
4039       OP_THUNK, HOP_THUNK, OP_THUNK_ANY, HOP_THUNK_ANY, OP_SAFE_THUNK, HOP_SAFE_THUNK, OP_SAFE_THUNK_A, HOP_SAFE_THUNK_A,
4040 
4041       OP_CLOSURE_S, HOP_CLOSURE_S, OP_CLOSURE_S_O, HOP_CLOSURE_S_O,
4042       OP_SAFE_CLOSURE_S, HOP_SAFE_CLOSURE_S, OP_SAFE_CLOSURE_S_O, HOP_SAFE_CLOSURE_S_O,
4043       OP_SAFE_CLOSURE_S_A, HOP_SAFE_CLOSURE_S_A, OP_SAFE_CLOSURE_S_TO_S, HOP_SAFE_CLOSURE_S_TO_S, OP_SAFE_CLOSURE_S_TO_SC, HOP_SAFE_CLOSURE_S_TO_SC,
4044       OP_CLOSURE_C, HOP_CLOSURE_C, OP_CLOSURE_C_O, HOP_CLOSURE_C_O,
4045       OP_SAFE_CLOSURE_C, HOP_SAFE_CLOSURE_C, OP_SAFE_CLOSURE_C_O, HOP_SAFE_CLOSURE_C_O, OP_SAFE_CLOSURE_C_A, HOP_SAFE_CLOSURE_C_A,
4046       OP_CLOSURE_A, HOP_CLOSURE_A, OP_CLOSURE_A_O, HOP_CLOSURE_A_O,
4047       OP_SAFE_CLOSURE_A, HOP_SAFE_CLOSURE_A, OP_SAFE_CLOSURE_A_O, HOP_SAFE_CLOSURE_A_O, OP_SAFE_CLOSURE_A_A, HOP_SAFE_CLOSURE_A_A,
4048       OP_SAFE_CLOSURE_A_TO_SC, HOP_SAFE_CLOSURE_A_TO_SC,
4049 
4050       OP_CLOSURE_P, HOP_CLOSURE_P, OP_SAFE_CLOSURE_P, HOP_SAFE_CLOSURE_P, OP_SAFE_CLOSURE_P_A, HOP_SAFE_CLOSURE_P_A,
4051       OP_CLOSURE_AP, HOP_CLOSURE_AP, OP_CLOSURE_PA, HOP_CLOSURE_PA, OP_CLOSURE_PP, HOP_CLOSURE_PP,
4052       OP_SAFE_CLOSURE_AP, HOP_SAFE_CLOSURE_AP, OP_SAFE_CLOSURE_PA, HOP_SAFE_CLOSURE_PA, OP_SAFE_CLOSURE_PP, HOP_SAFE_CLOSURE_PP,
4053       OP_CLOSURE_FA, HOP_CLOSURE_FA,
4054       OP_ANY_CLOSURE_3P, HOP_ANY_CLOSURE_3P, OP_ANY_CLOSURE_4P, HOP_ANY_CLOSURE_4P,
4055 
4056       OP_CLOSURE_SS, HOP_CLOSURE_SS, OP_CLOSURE_SS_O, HOP_CLOSURE_SS_O,
4057       OP_SAFE_CLOSURE_SS, HOP_SAFE_CLOSURE_SS, OP_SAFE_CLOSURE_SS_O, HOP_SAFE_CLOSURE_SS_O, OP_SAFE_CLOSURE_SS_A, HOP_SAFE_CLOSURE_SS_A,
4058       OP_CLOSURE_SC, HOP_CLOSURE_SC, OP_CLOSURE_SC_O, HOP_CLOSURE_SC_O,
4059       OP_SAFE_CLOSURE_SC, HOP_SAFE_CLOSURE_SC, OP_SAFE_CLOSURE_SC_O, HOP_SAFE_CLOSURE_SC_O,
4060       OP_CLOSURE_3S, HOP_CLOSURE_3S, OP_CLOSURE_4S, HOP_CLOSURE_4S,
4061 
4062       OP_CLOSURE_AA, HOP_CLOSURE_AA, OP_CLOSURE_AA_O, HOP_CLOSURE_AA_O,
4063       OP_SAFE_CLOSURE_AA, HOP_SAFE_CLOSURE_AA, OP_SAFE_CLOSURE_AA_O, HOP_SAFE_CLOSURE_AA_O, OP_SAFE_CLOSURE_AA_A, HOP_SAFE_CLOSURE_AA_A,
4064 
4065       OP_CLOSURE_ALL_A, HOP_CLOSURE_ALL_A, OP_CLOSURE_ASS, HOP_CLOSURE_ASS, OP_CLOSURE_SAS, HOP_CLOSURE_SAS ,OP_CLOSURE_AAS, HOP_CLOSURE_AAS,
4066       OP_CLOSURE_SAA, HOP_CLOSURE_SAA, OP_CLOSURE_ASA, HOP_CLOSURE_ASA, OP_CLOSURE_ALL_S, HOP_CLOSURE_ALL_S, OP_CLOSURE_ANY_ALL_A, HOP_CLOSURE_ANY_ALL_A,
4067       OP_SAFE_CLOSURE_SAA, HOP_SAFE_CLOSURE_SAA, OP_SAFE_CLOSURE_SSA, HOP_SAFE_CLOSURE_SSA, OP_CLOSURE_3A, HOP_CLOSURE_3A, OP_CLOSURE_4A, HOP_CLOSURE_4A,
4068       OP_SAFE_CLOSURE_AGG, HOP_SAFE_CLOSURE_AGG, OP_SAFE_CLOSURE_ALL_A, HOP_SAFE_CLOSURE_ALL_A,
4069       OP_SAFE_CLOSURE_3S, HOP_SAFE_CLOSURE_3S, OP_SAFE_CLOSURE_ALL_S, HOP_SAFE_CLOSURE_ALL_S,
4070       OP_SAFE_CLOSURE_3S_A, HOP_SAFE_CLOSURE_3S_A,
4071       OP_ANY_CLOSURE_FP, HOP_ANY_CLOSURE_FP,
4072 
4073       OP_CLOSURE_STAR_A, HOP_CLOSURE_STAR_A, OP_CLOSURE_STAR_ALL_A, HOP_CLOSURE_STAR_ALL_A,
4074       OP_SAFE_CLOSURE_STAR_A, HOP_SAFE_CLOSURE_STAR_A, OP_SAFE_CLOSURE_STAR_AA, HOP_SAFE_CLOSURE_STAR_AA,
4075       OP_SAFE_CLOSURE_STAR_AA_O, HOP_SAFE_CLOSURE_STAR_AA_O, OP_SAFE_CLOSURE_STAR_A1, HOP_SAFE_CLOSURE_STAR_A1,
4076       OP_SAFE_CLOSURE_STAR_KA, HOP_SAFE_CLOSURE_STAR_KA, OP_CLOSURE_STAR_KA, HOP_CLOSURE_STAR_KA,
4077       OP_SAFE_CLOSURE_STAR_ALL_A, HOP_SAFE_CLOSURE_STAR_ALL_A, OP_SAFE_CLOSURE_STAR_ALL_A_0, HOP_SAFE_CLOSURE_STAR_ALL_A_0,
4078       OP_SAFE_CLOSURE_STAR_ALL_A_1, HOP_SAFE_CLOSURE_STAR_ALL_A_1, OP_SAFE_CLOSURE_STAR_ALL_A_2, HOP_SAFE_CLOSURE_STAR_ALL_A_2,
4079 
4080       OP_CALL_WITH_EXIT, HOP_CALL_WITH_EXIT, OP_CALL_WITH_EXIT_O, HOP_CALL_WITH_EXIT_O,
4081       OP_C_CATCH, HOP_C_CATCH, OP_C_CATCH_ALL, HOP_C_CATCH_ALL, OP_C_CATCH_ALL_O, HOP_C_CATCH_ALL_O, OP_C_CATCH_ALL_A, HOP_C_CATCH_ALL_A,
4082       OP_C_S_opSq, HOP_C_S_opSq, OP_C_SS, HOP_C_SS, OP_C_S, HOP_C_S, OP_READ_S, HOP_READ_S, OP_C_P, HOP_C_P, OP_C_AP, HOP_C_AP,
4083       OP_C_A, HOP_C_A, OP_C_AA, HOP_C_AA, OP_C, HOP_C, OP_C_ALL_A, HOP_C_ALL_A,
4084 
4085       OP_CL_S, HOP_CL_S, OP_CL_SS, HOP_CL_SS, OP_CL_A, HOP_CL_A, OP_CL_AA, HOP_CL_AA, OP_CL_ALL_A, HOP_CL_ALL_A, OP_CL_FA, HOP_CL_FA, OP_CL_SAS, HOP_CL_SAS,
4086 
4087       OP_SAFE_C_PP, HOP_SAFE_C_PP, OP_SAFE_C_FF, HOP_SAFE_C_FF,
4088       OP_SAFE_C_opSq_P, HOP_SAFE_C_opSq_P,
4089       OP_SAFE_C_SP, HOP_SAFE_C_SP, OP_SAFE_C_CP, HOP_SAFE_C_CP,
4090       OP_SAFE_C_AP, HOP_SAFE_C_AP, OP_SAFE_C_PA, HOP_SAFE_C_PA,
4091       OP_SAFE_C_PS, HOP_SAFE_C_PS, OP_SAFE_C_PC, HOP_SAFE_C_PC,
4092       OP_SAFE_C_SSP, HOP_SAFE_C_SSP, OP_ANY_C_FP, HOP_ANY_C_FP,
4093       /* end of h_opts */
4094 
4095       OP_APPLY_SS, OP_APPLY_SA, OP_APPLY_SL,
4096       OP_MACRO_D, OP_MACRO_STAR_D,
4097       OP_WITH_IO, OP_WITH_IO_1, OP_WITH_OUTPUT_TO_STRING, OP_WITH_IO_C, OP_CALL_WITH_OUTPUT_STRING,
4098       OP_S, OP_S_S, OP_S_C, OP_S_A, OP_MAP_FA, OP_S_AA, OP_A_A, OP_A_AA, OP_P_S, OP_P_S_1,
4099       OP_IMPLICIT_GOTO, OP_IMPLICIT_GOTO_A, OP_IMPLICIT_CONTINUATION_A,
4100       OP_IMPLICIT_ITERATE, OP_IMPLICIT_VECTOR_REF_A, OP_IMPLICIT_VECTOR_REF_AA, OP_IMPLICIT_STRING_REF_A,
4101       OP_IMPLICIT_C_OBJECT_REF_A, OP_IMPLICIT_PAIR_REF_A, OP_IMPLICIT_HASH_TABLE_REF_A, OP_IMPLICIT_LET_REF_C, OP_IMPLICIT_LET_REF_A,
4102       OP_IMPLICIT_S7_LET_REF_S, OP_IMPLICIT_S7_LET_SET_SA,
4103       OP_IMPLICIT_VECTOR_SET_3, OP_IMPLICIT_VECTOR_SET_4,
4104       OP_UNKNOWN, OP_UNKNOWN_ALL_S, OP_UNKNOWN_ALL_A, OP_UNKNOWN_G, OP_UNKNOWN_GG, OP_UNKNOWN_A, OP_UNKNOWN_AA, OP_UNKNOWN_FP,
4105 
4106       OP_SYM, OP_GLOBAL_SYM, OP_CON, OP_PAIR_SYM, OP_PAIR_PAIR, OP_PAIR_ANY,
4107       HOP_SSA_DIRECT, HOP_HASH_TABLE_INCREMENT, OP_CLEAR_OPTS,
4108 
4109       OP_READ_INTERNAL, OP_EVAL,
4110       OP_EVAL_ARGS, OP_EVAL_ARGS1, OP_EVAL_ARGS2, OP_EVAL_ARGS3, OP_EVAL_ARGS4, OP_EVAL_ARGS5,
4111       OP_APPLY, OP_EVAL_MACRO, OP_LAMBDA, OP_QUOTE, OP_QUOTE_UNCHECKED, OP_MACROEXPAND, OP_CALL_CC,
4112       OP_DEFINE, OP_DEFINE1, OP_BEGIN, OP_BEGIN_HOOK, OP_BEGIN_NO_HOOK, OP_BEGIN_UNCHECKED,
4113       OP_BEGIN_1_UNCHECKED, OP_BEGIN_2_UNCHECKED, OP_BEGIN_ALL_A, OP_BEGIN_AA,
4114       OP_IF, OP_IF1, OP_WHEN, OP_UNLESS, OP_SET, OP_SET1, OP_SET2,
4115       OP_LET, OP_LET1, OP_LET_STAR, OP_LET_STAR1, OP_LET_STAR2,
4116       OP_LETREC, OP_LETREC1, OP_LETREC_STAR, OP_LETREC_STAR1,
4117       OP_LET_TEMPORARILY, OP_LET_TEMP_UNCHECKED, OP_LET_TEMP_INIT1, OP_LET_TEMP_INIT2, OP_LET_TEMP_DONE, OP_LET_TEMP_DONE1,
4118       OP_LET_TEMP_S7, OP_LET_TEMP_FX, OP_LET_TEMP_FX_1, OP_LET_TEMP_SETTER, OP_LET_TEMP_UNWIND, OP_LET_TEMP_S7_UNWIND, OP_LET_TEMP_SETTER_UNWIND,
4119       OP_LET_TEMP_A_A,
4120       OP_COND, OP_COND1, OP_FEED_TO_1, OP_COND_SIMPLE, OP_COND1_SIMPLE, OP_COND_SIMPLE_O, OP_COND1_SIMPLE_O,
4121       OP_AND, OP_OR,
4122       OP_DEFINE_MACRO, OP_DEFINE_MACRO_STAR, OP_DEFINE_EXPANSION, OP_DEFINE_EXPANSION_STAR, OP_MACRO, OP_MACRO_STAR,
4123       OP_CASE,
4124       OP_READ_LIST, OP_READ_NEXT, OP_READ_DOT, OP_READ_QUOTE,
4125       OP_READ_QUASIQUOTE, OP_READ_UNQUOTE, OP_READ_APPLY_VALUES,
4126       OP_READ_VECTOR, OP_READ_BYTE_VECTOR, OP_READ_INT_VECTOR, OP_READ_FLOAT_VECTOR, OP_READ_DONE,
4127       OP_LOAD_RETURN_IF_EOF, OP_LOAD_CLOSE_AND_POP_IF_EOF, OP_EVAL_DONE, OP_SPLICE_VALUES,
4128       OP_CATCH, OP_DYNAMIC_WIND, OP_DYNAMIC_UNWIND, OP_DYNAMIC_UNWIND_PROFILE, OP_PROFILE_IN,
4129       OP_DEFINE_CONSTANT, OP_DEFINE_CONSTANT1,
4130       OP_DO, OP_DO_END, OP_DO_END1, OP_DO_STEP, OP_DO_STEP2, OP_DO_INIT,
4131       OP_DEFINE_STAR, OP_LAMBDA_STAR, OP_LAMBDA_STAR_DEFAULT, OP_ERROR_QUIT, OP_UNWIND_INPUT, OP_UNWIND_OUTPUT,
4132       OP_ERROR_HOOK_QUIT,
4133       OP_WITH_LET, OP_WITH_LET1, OP_WITH_LET_UNCHECKED, OP_WITH_LET_S, OP_WITH_UNLET_S,
4134       OP_WITH_BAFFLE, OP_WITH_BAFFLE_UNCHECKED, OP_EXPANSION,
4135       OP_FOR_EACH, OP_FOR_EACH_1, OP_FOR_EACH_2, OP_FOR_EACH_3,
4136       OP_MAP, OP_MAP_1, OP_MAP_2, OP_MAP_GATHER, OP_MAP_GATHER_1, OP_MAP_GATHER_2, OP_MAP_GATHER_3,
4137       OP_BARRIER, OP_DEACTIVATE_GOTO,
4138       OP_DEFINE_BACRO, OP_DEFINE_BACRO_STAR, OP_BACRO, OP_BACRO_STAR,
4139       OP_GET_OUTPUT_STRING,
4140       OP_SORT, OP_SORT1, OP_SORT2, OP_SORT3, OP_SORT_PAIR_END, OP_SORT_VECTOR_END, OP_SORT_STRING_END,
4141       OP_EVAL_STRING,
4142       OP_MEMBER_IF, OP_ASSOC_IF, OP_MEMBER_IF1, OP_ASSOC_IF1,
4143       OP_LAMBDA_UNCHECKED, OP_LET_UNCHECKED, OP_CATCH_1, OP_CATCH_2, OP_CATCH_ALL,
4144 
4145       OP_SET_UNCHECKED, OP_SET_SYMBOL_C, OP_SET_SYMBOL_S, OP_SET_SYMBOL_P, OP_SET_SYMBOL_A,
4146       OP_SET_NORMAL, OP_SET_PAIR, OP_SET_DILAMBDA, OP_SET_DILAMBDA_P, OP_SET_DILAMBDA_P_1, OP_SET_DILAMBDA_SA_A,
4147       OP_SET_PAIR_A, OP_SET_PAIR_P, OP_SET_PAIR_ZA,
4148       OP_SET_PAIR_P_1, OP_SET_FROM_SETTER, OP_SET_PWS, OP_SET_LET_S, OP_SET_LET_FX, OP_SET_SAFE,
4149       OP_INCREMENT_BY_1, OP_DECREMENT_BY_1, OP_SET_CONS,
4150       OP_INCREMENT_SS, OP_INCREMENT_SP, OP_INCREMENT_SA, OP_INCREMENT_SAA,
4151 
4152       OP_LETREC_UNCHECKED, OP_LETREC_STAR_UNCHECKED, OP_COND_UNCHECKED,
4153       OP_LAMBDA_STAR_UNCHECKED, OP_DO_UNCHECKED, OP_DEFINE_UNCHECKED, OP_DEFINE_STAR_UNCHECKED, OP_DEFINE_FUNCHECKED, OP_DEFINE_CONSTANT_UNCHECKED,
4154       OP_DEFINE_WITH_SETTER,
4155 
4156       OP_LET_NO_VARS, OP_NAMED_LET, OP_NAMED_LET_NO_VARS, OP_NAMED_LET_FX, OP_NAMED_LET_STAR,
4157       OP_LET_FX_OLD, OP_LET_FX_NEW, OP_LET_2A_OLD, OP_LET_2A_NEW, OP_LET_3A_OLD, OP_LET_3A_NEW,
4158       OP_LET_opSSq_OLD, OP_LET_opSSq_NEW, OP_LET_opSSq_E_OLD, OP_LET_opSSq_E_NEW, OP_LET_opaSSq_OLD, OP_LET_opaSSq_NEW, OP_LET_opaSSq_E_OLD, OP_LET_opaSSq_E_NEW,
4159       OP_LET_ONE_OLD, OP_LET_ONE_NEW, OP_LET_ONE_P_OLD, OP_LET_ONE_P_NEW,
4160       OP_LET_ONE_OLD_1, OP_LET_ONE_NEW_1, OP_LET_ONE_P_OLD_1, OP_LET_ONE_P_NEW_1,
4161       OP_LET_A_OLD, OP_LET_A_NEW, OP_LET_A_P_OLD, OP_LET_A_P_NEW,
4162       OP_LET_A_A_OLD, OP_LET_A_A_NEW, OP_LET_A_FX_OLD, OP_LET_A_FX_NEW, OP_LET_A_OLD_2, OP_LET_A_NEW_2,
4163       OP_LET_STAR_FX, OP_LET_STAR_FX_A,
4164 
4165       OP_CASE_A_E_S, OP_CASE_A_I_S, OP_CASE_A_G_S, OP_CASE_A_E_G, OP_CASE_A_G_G, OP_CASE_A_S_S, OP_CASE_A_S_G,
4166       OP_CASE_S_E_S, OP_CASE_S_I_S, OP_CASE_S_G_S, OP_CASE_S_E_G, OP_CASE_S_G_G, OP_CASE_S_S_S, OP_CASE_S_S_G,
4167       OP_CASE_P_E_S, OP_CASE_P_I_S, OP_CASE_P_G_S, OP_CASE_P_E_G, OP_CASE_P_G_G, OP_CASE_P_S_S, OP_CASE_P_S_G,
4168       OP_CASE_E_S, OP_CASE_I_S, OP_CASE_G_S, OP_CASE_E_G, OP_CASE_G_G, OP_CASE_S_S, OP_CASE_S_G,
4169 
4170       OP_IF_UNCHECKED, OP_AND_P, OP_AND_P1, OP_AND_AP, OP_AND_PAIR_P,
4171       OP_AND_SAFE_P1, OP_AND_SAFE_P2, OP_AND_SAFE_P3, OP_AND_SAFE_P_REST, OP_AND_2, OP_AND_3, OP_AND_N, OP_AND_S_2,
4172       OP_OR_P, OP_OR_P1, OP_OR_AP, OP_OR_2, OP_OR_3, OP_OR_N, OP_OR_S_2, OP_OR_S_TYPE_2,
4173       OP_WHEN_S, OP_WHEN_A, OP_WHEN_P, OP_WHEN_AND_AP, OP_WHEN_AND_2, OP_WHEN_AND_3, OP_UNLESS_S, OP_UNLESS_A, OP_UNLESS_P,
4174 
4175       OP_IF_A_C_C, OP_IF_A_A, OP_IF_A_A_A, OP_IF_S_A_A, OP_IF_AND2_S_A, OP_IF_NOT_A_A, OP_IF_NOT_A_A_A,
4176       OP_IF_A_A_P, OP_IF_A_P_A, OP_IF_S_P_A, OP_IF_IS_TYPE_S_P_A, OP_IF_IS_TYPE_S_A_A,
4177       OP_IF_S_P, OP_IF_S_P_P, OP_IF_S_R, OP_IF_S_N, OP_IF_S_N_N,
4178       OP_IF_opSq_P, OP_IF_opSq_P_P, OP_IF_opSq_R, OP_IF_opSq_N, OP_IF_opSq_N_N,
4179       OP_IF_IS_TYPE_S_P, OP_IF_IS_TYPE_S_P_P, OP_IF_IS_TYPE_S_R, OP_IF_IS_TYPE_S_N, OP_IF_IS_TYPE_S_N_N,
4180       OP_IF_A_P, OP_IF_A_P_P, OP_IF_A_R, OP_IF_A_N, OP_IF_A_N_N,
4181       OP_IF_AND2_P, OP_IF_AND2_P_P, OP_IF_AND2_R, OP_IF_AND2_N, OP_IF_AND2_N_N,
4182       OP_IF_AND3_P, OP_IF_AND3_P_P, OP_IF_AND3_R, OP_IF_AND3_N, OP_IF_AND3_N_N,  /* or3 got few hits */
4183       OP_IF_P_P, OP_IF_P_P_P, OP_IF_P_R, OP_IF_P_N, OP_IF_P_N_N,
4184       OP_IF_ANDP_P, OP_IF_ANDP_P_P, OP_IF_ANDP_R, OP_IF_ANDP_N, OP_IF_ANDP_N_N,
4185       OP_IF_ORP_P, OP_IF_ORP_P_P, OP_IF_ORP_R, OP_IF_ORP_N, OP_IF_ORP_N_N,
4186       OP_IF_OR2_P, OP_IF_OR2_P_P, OP_IF_OR2_R, OP_IF_OR2_N, OP_IF_OR2_N_N,
4187       OP_IF_PP, OP_IF_PPP, OP_IF_PR, OP_IF_PRR, OP_WHEN_PP, OP_UNLESS_PP,
4188 
4189       OP_COND_FX_FX, OP_COND_FX_FP, OP_COND_FX_FP_1, OP_COND_FX_2E, OP_COND_FX_3E, OP_COND_FX_FP_O,
4190       OP_COND_FEED, OP_COND_FEED_1,
4191 
4192       OP_SIMPLE_DO, OP_SIMPLE_DO_STEP, OP_SAFE_DOTIMES, OP_SAFE_DOTIMES_STEP, OP_SAFE_DOTIMES_STEP_O,
4193       OP_SAFE_DO, OP_SAFE_DO_STEP, OP_DOX, OP_DOX_STEP, OP_DOX_STEP_O, OP_DOX_NO_BODY, OP_DOX_PENDING_NO_BODY, OP_DOX_INIT,
4194       OP_DOTIMES_P, OP_DOTIMES_STEP_O,
4195       OP_DO_NO_VARS, OP_DO_NO_VARS_NO_OPT, OP_DO_NO_VARS_NO_OPT_1,
4196       OP_DO_NO_BODY_FX_VARS, OP_DO_NO_BODY_FX_VARS_STEP, OP_DO_NO_BODY_FX_VARS_STEP_1,
4197 
4198       OP_SAFE_C_P_1, OP_SAFE_C_PP_1, OP_SAFE_C_PP_3_MV, OP_SAFE_C_PP_5, OP_SAFE_C_PP_6_MV,
4199       OP_SAFE_C_SP_1, OP_SAFE_C_SP_MV, OP_SAFE_CONS_SP_1, OP_SAFE_VECTOR_SP_1, OP_SAFE_ADD_SP_1, OP_SAFE_MULTIPLY_SP_1, OP_SAFE_SUBTRACT_SP_1,
4200       OP_SAFE_C_PS_1, OP_SAFE_C_PC_1, OP_SAFE_C_PS_MV, OP_SAFE_C_PC_MV,
4201       OP_EVAL_MACRO_MV, OP_MACROEXPAND_1, OP_APPLY_LAMBDA,
4202       OP_SAFE_CLOSURE_P_1, OP_CLOSURE_P_1, OP_SAFE_CLOSURE_P_A_1,
4203       OP_SAFE_CLOSURE_AP_1, OP_SAFE_CLOSURE_PA_1, OP_SAFE_CLOSURE_PP_1, OP_ANY_CLOSURE_FP_1, OP_ANY_CLOSURE_FP_MV_1,
4204       OP_INCREMENT_SP_1, OP_INCREMENT_SP_MV,
4205       OP_ANY_C_FP_1, OP_ANY_C_FP_MV_1, OP_SAFE_C_SSP_1, OP_SAFE_C_SSP_MV_1,
4206       OP_C_P_1, OP_C_P_MV, OP_C_AP_1, OP_C_AP_MV, OP_ANY_C_FP_2,
4207       OP_CLOSURE_AP_1, OP_CLOSURE_PA_1, OP_CLOSURE_PP_1,
4208       OP_SAFE_C_PA_1, OP_SAFE_C_PA_MV, OP_ANY_CLOSURE_FP_2,
4209       OP_ANY_CLOSURE_3P_1, OP_ANY_CLOSURE_3P_2, OP_ANY_CLOSURE_3P_3,
4210       OP_ANY_CLOSURE_4P_1, OP_ANY_CLOSURE_4P_2, OP_ANY_CLOSURE_4P_3, OP_ANY_CLOSURE_4P_4,
4211       OP_SET_WITH_LET_1, OP_SET_WITH_LET_2,
4212 
4213       OP_TC_AND_A_OR_A_LA, OP_TC_OR_A_AND_A_LA, OP_TC_AND_A_OR_A_LAA, OP_TC_OR_A_AND_A_LAA, OP_TC_OR_A_A_AND_A_A_LA,
4214       OP_TC_OR_A_AND_A_A_L3A, OP_TC_AND_A_OR_A_A_LA, OP_TC_OR_A_AND_A_A_LA,
4215       OP_TC_LET_WHEN_LAA, OP_TC_LET_UNLESS_LAA,
4216       OP_TC_COND_A_Z_A_Z_LAA, OP_TC_COND_A_Z_A_LAA_Z, OP_TC_COND_A_Z_A_LAA_LAA, OP_TC_LET_COND,
4217       OP_TC_IF_A_Z_LA, OP_TC_IF_A_Z_LAA, OP_TC_IF_A_Z_L3A, OP_TC_IF_A_L3A_Z, OP_TC_IF_A_LA_Z, OP_TC_IF_A_LAA_Z,
4218       OP_TC_IF_A_Z_IF_A_Z_LA, OP_TC_IF_A_Z_IF_A_LA_Z, OP_TC_IF_A_Z_IF_A_Z_LAA, OP_TC_IF_A_Z_IF_A_LAA_Z, OP_TC_IF_A_Z_IF_A_L3A_L3A,
4219       OP_TC_COND_A_Z_A_Z_LA, OP_TC_COND_A_Z_A_LA_Z, OP_TC_COND_A_Z_LA, OP_TC_COND_A_LA_Z, OP_TC_COND_A_Z_LAA, OP_TC_COND_A_LAA_Z,
4220       OP_TC_LET_IF_A_Z_LA, OP_TC_LET_IF_A_Z_LAA, OP_TC_IF_A_Z_LET_IF_A_Z_LAA,
4221       OP_TC_CASE_LA, OP_TC_AND_A_IF_A_Z_LA, OP_TC_AND_A_IF_A_LA_Z,
4222 
4223       OP_RECUR_IF_A_A_opA_LAq, OP_RECUR_IF_A_opA_LAq_A, OP_RECUR_IF_A_A_opLA_Aq, OP_RECUR_IF_A_opLA_Aq_A,
4224       OP_RECUR_IF_A_A_opLA_LAq, OP_RECUR_IF_A_opLA_LAq_A,
4225       OP_RECUR_IF_A_A_opA_LA_LAq, OP_RECUR_IF_A_opA_LA_LAq_A,
4226       OP_RECUR_IF_A_A_opLA_LA_LAq, OP_RECUR_IF_A_A_IF_A_A_opLA_LAq, OP_RECUR_IF_A_A_IF_A_A_opLAA_LAAq,
4227       OP_RECUR_IF_A_A_opA_LAAq, OP_RECUR_IF_A_opA_LAAq_A, OP_RECUR_IF_A_A_opA_L3Aq,
4228       OP_RECUR_IF_A_A_LopL3A_L3A_L3Aq, OP_RECUR_IF_A_A_AND_A_LAA_LAA,
4229       OP_RECUR_IF_A_A_IF_A_LAA_opA_LAAq, /* same as cond case below */
4230       OP_RECUR_COND_A_A_opA_LAq, OP_RECUR_COND_A_A_opA_LAAq,
4231       OP_RECUR_COND_A_A_A_A_opLA_LAq, OP_RECUR_COND_A_A_A_A_opLAA_LAAq, OP_RECUR_COND_A_A_A_A_opA_LAAq,
4232       OP_RECUR_COND_A_A_A_LAA_LopA_LAAq, OP_RECUR_COND_A_A_A_LAA_opA_LAAq,
4233       OP_RECUR_AND_A_OR_A_LAA_LAA,
4234 
4235       NUM_OPS};
4236 
4237 #define is_tc_op(Op) ((Op >= OP_TC_AND_A_OR_A_LA) && (Op <= OP_TC_CASE_LA))
4238 
4239 typedef enum{E_C_P, E_C_PP, E_C_CP, E_C_SP, E_C_PC, E_C_PS} combine_op_t;
4240 
4241 static const char* op_names[NUM_OPS] =
4242      {"unopt", "gc_protect",
4243 
4244       "safe_c_d", "h_safe_c_d", "safe_c_s", "h_safe_c_s",
4245       "safe_c_ss", "h_safe_c_ss", "safe_c_sc", "h_safe_c_sc", "safe_c_cs", "h_safe_c_cs", "safe_c_cq", "h_safe_c_cq",
4246       "safe_c_sss", "h_safe_c_sss", "safe_c_scs", "h_safe_c_scs", "safe_c_ssc", "h_safe_c_ssc", "safe_c_css", "h_safe_c_css",
4247       "safe_c_scc", "h_safe_c_scc", "safe_c_csc", "h_safe_c_csc", "safe_c_ccs", "h_safe_c_ccs",
4248       "safe_c_all_s", "h_safe_c_all_s", "safe_c_opdq", "h_safe_c_opdq", "safe_c_opsq", "h_safe_c_opsq",
4249       "safe_c_opssq", "h_safe_c_opssq", "safe_c_opscq", "h_safe_c_opscq",
4250       "safe_c_opcsq", "h_safe_c_opcsq", "safe_c_s_opsq", "h_safe_c_s_opsq",
4251       "safe_c_c_opscq", "h_safe_c_c_opscq", "safe_c_s_opscq", "h_safe_c_s_opscq", "safe_c_s_opcsq", "h_safe_c_s_opcsq",
4252       "safe_c_opsq_s", "h_safe_c_opsq_s", "safe_c_opsq_c", "h_safe_c_opsq_c",
4253       "safe_c_opsq_opsq", "h_safe_c_opsq_opsq", "safe_c_s_opssq", "h_safe_c_s_opssq", "safe_c_c_opsq", "h_safe_c_c_opsq",
4254       "safe_c_opcsq_c", "h_safe_c_opcsq_c", "safe_c_opssq_c", "h_safe_c_opssq_c", "safe_c_c_opssq", "h_safe_c_c_opssq",
4255       "safe_c_opssq_opssq", "h_safe_c_opssq_opssq", "safe_c_opssq_opsq", "h_safe_c_opssq_opsq", "safe_c_opsq_opssq", "h_safe_c_opsq_opssq",
4256       "safe_c_opssq_s", "h_safe_c_opssq_s", "safe_c_opcsq_s", "h_safe_c_opcsq_s", "safe_c_opscq_c", "h_safe_c_opscq_c",
4257       "safe_c_op_opssqq_s", "h_safe_c_op_opssqq_s", "safe_c_op_opsqq", "h_safe_c_op_opsqq",
4258       "safe_c_op_s_opsqq", "h_safe_c_op_s_opsqq", "safe_c_op_opsq_sq", "h_safe_c_op_opsq_sq", "safe_c_opsq_cs", "h_safe_c_opsq_cs",
4259 
4260       "safe_c_a", "h_safe_c_a", "safe_c_aa", "h_safe_c_aa", "safe_c_sa", "h_safe_c_sa", "safe_c_as", "h_safe_c_as",
4261       "safe_c_ca", "h_safe_c_ca", "safe_c_ac", "h_safe_c_ac", "safe_c_aaa", "h_safe_c_aaa", "safe_c_4a", "h_safe_c_4a",
4262       "safe_c_all_a", "h_safe_c_all_a", "safe_c_all_ca", "h_safe_c_all_ca", "safe_c_inlet_ca", "h_safe_c_inlet_ca",
4263       "safe_c_ssa", "h_safe_c_ssa", "safe_c_sas", "h_safe_c_sas", "safe_c_saa", "h_safe_c_saa",
4264       "safe_c_csa", "h_safe_c_csa", "safe_c_sca", "h_safe_c_sca", "safe_c_ass", "h_safe_c_ass",
4265       "safe_c_cac", "h_safe_c_cac",
4266       "safe_c_opaq", "h_safe_c_opaq", "safe_c_opaaq", "h_safe_c_opaaq", "safe_c_opaaaq", "h_safe_c_opaaaq",
4267       "safe_c_s_opaq", "h_safe_c_s_opaq", "safe_c_opaq_s", "h_safe_c_opaq_s",
4268       "safe_c_s_opaaq", "h_safe_c_s_opaaq", "safe_c_s_opaaaq", "h_safe_c_s_opaaaq",
4269       "safe_c_function*", "h_safe_c_function*", "safe_c_function*_a", "h_safe_c_function*_a",
4270       "safe_c_function*_aa", "h_safe_c_function*_aa", "safe_c_function*_fx", "h_safe_c_function*_fx",
4271       "safe_c_p", "h_safe_c_p",
4272 
4273       "thunk", "h_thunk", "thunk_any", "h_thunk_any", "safe_thunk", "h_safe_thunk", "safe_thunk_a", "h_safe_thunk_a",
4274 
4275       "closure_s", "h_closure_s", "closure_s_o", "h_closure_s_o",
4276       "safe_closure_s", "h_safe_closure_s", "safe_closure_s_o", "h_safe_closure_s_o",
4277       "safe_closure_s_a", "h_safe_closure_s_a", "safe_closure_s_to_s", "h_safe_closure_s_to_s", "safe_closure_s_to_sc", "h_safe_closure_s_to_sc",
4278       "closure_c", "h_closure_c", "closure_c_o", "h_closure_c_o",
4279       "safe_closure_c", "h_safe_closure_c", "safe_closure_c_o", "h_safe_closure_c_o", "safe_closure_c_a", "h_safe_closure_c_a",
4280       "closure_a", "h_closure_a", "closure_a_o", "h_closure_a_o",
4281       "safe_closure_a", "h_safe_closure_a", "safe_closure_a_o", "h_safe_closure_a_o", "safe_closure_a_a", "h_safe_closure_a_a",
4282       "safe_closure_a_to_sc", "h_safe_closure_a_to_sc",
4283 
4284       "closure_p", "h_closure_p", "safe_closure_p", "h_safe_closure_p", "safe_closure_p_a", "h_safe_closure_p_a",
4285       "closure_ap", "h_closure_ap", "closure_pa", "h_closure_pa", "closure_pp", "h_closure_pp",
4286       "safe_closure_ap", "h_safe_closure_ap", "safe_closure_pa", "h_safe_closure_pa", "safe_closure_pp", "h_safe_closure_pp",
4287       "closure_fa", "h_closure_fa",
4288       "any_closure_3p", "h_any_closure_3p", "any_closure_4p", "h_any_closure_4p",
4289 
4290       "closure_ss", "h_closure_ss", "closure_ss_o", "h_closure_ss_o",
4291       "safe_closure_ss", "h_safe_closure_ss", "safe_closure_ss_o", "h_safe_closure_ss_o", "safe_closure_ss_a", "h_safe_closure_ss_a",
4292       "closure_sc", "h_closure_sc", "closure_sc_o", "h_closure_sc_o",
4293       "safe_closure_sc", "h_safe_closure_sc", "safe_closure_sc_o", "h_safe_closure_sc_o",
4294       "closure_3s", "h_closure_3s", "closure_4s", "h_closure_4s",
4295 
4296       "closure_aa", "h_closure_aa", "closure_aa_o", "h_closure_aa_o",
4297       "safe_closure_aa", "h_safe_closure_aa", "safe_closure_aa_o", "h_safe_closure_aa_o", "safe_closure_aa_a", "h_safe_closure_aa_a",
4298 
4299       "closure_all_a", "h_closure_all_a", "closure_ass", "h_closure_ass", "closure_sas", "h_closure_sas", "closure_aas", "h_closure_aas",
4300       "closure_saa", "h_closure_saa", "closure_asa", "h_closure_asa", "closure_all_s", "h_closure_all_s", "closure_any_all_a", "h_closure_any_all_a",
4301       "safe_closure_saa", "h_safe_closure_saa", "safe_closure_ssa", "h_safe_closure_ssa", "closure_3a", "h_closure_3a", "closure_4a", "h_closure_4a",
4302       "safe_closure_agg", "h_safe_closure_agg", "safe_closure_all_a", "h_safe_closure_all_a",
4303       "safe_closure_3s", "h_safe_closure_3s", "safe_closure_all_s", "h_safe_closure_all_s",
4304       "safe_closure_3s_a", "h_safe_closure_3s_a",
4305       "any_closure_fp", "h_any_closure_fp",
4306 
4307       "closure*_a", "h_closure*_a", "closure*_fx", "h_closure*_fx",
4308       "safe_closure*_a", "h_safe_closure*_a", "safe_closure*_aa", "h_safe_closure*_aa",
4309       "safe_closure*_aa_o", "h_safe_closure*_aa_o", "safe_closure*_a1", "h_safe_closure*_a1",
4310       "safe_closure*_ka", "h_safe_closure*_ka", "closure*_ka", "h_closure*_ka",
4311       "safe_closure*_fx", "h_safe_closure*_fx", "safe_closure*_fx_0", "h_safe_closure*_fx_0",
4312       "safe_closure*_fx_1", "h_safe_closure*_fx_1", "safe_closure*_fx_2", "h_safe_closure*_fx_2",
4313 
4314       "call_with_exit", "h_call_with_exit", "call_with_exit_o", "h_call_with_exit_o",
4315       "c_catch", "h_c_catch", "c_catch_all", "h_c_catch_all", "c_catch_all_o", "h_c_catch_all_o", "c_catch_all_a", "h_c_catch_all_a",
4316       "c_s_opsq", "h_c_s_opsq", "c_ss", "h_c_ss", "c_s", "h_c_s", "read_s", "h_read_s", "c_p", "h_c_p", "c_ap", "h_c_ap",
4317       "c_a", "h_c_a", "c_aa", "h_c_aa", "c", "h_c", "c_fx", "h_c_fx",
4318 
4319       "cl_s", "h_cl_s", "cl_ss", "h_cl_ss", "cl_a", "h_cl_a", "cl_aa", "h_cl_aa", "cl_all_a", "h_cl_all_a", "cl_fa", "h_cl_fa", "cl_sas", "h_cl_sas",
4320 
4321       "safe_c_pp", "h_safe_c_pp", "safe_c_ff", "h_safe_c_ff",
4322       "safe_c_opsq_p", "h_safe_c_opsq_p",
4323       "safe_c_sp", "h_safe_c_sp", "safe_c_cp", "h_safe_c_cp",
4324       "safe_c_ap", "h_safe_c_ap", "safe_c_pa", "h_safe_c_pa",
4325       "safe_c_ps", "h_safe_c_ps", "safe_c_pc", "h_safe_c_pc",
4326       "safe_c_ssp", "h_safe_c_ssp", "any_c_fp", "h_any_c_fp",
4327 
4328       "apply_ss", "apply_sa", "apply_sl",
4329       "macro_d", "macro*_d",
4330       "with_input_from_string", "with_input_from_string_1", "with_output_to_string", "with_input_from_string_c", "call_with_output_string",
4331       "s", "s_s", "s_c", "s_a", "cl_fa_1", "s_aa", "a_a", "a_aa", "p_s", "p_s_1",
4332       "implicit_goto", "implicit_goto_a", "implicit_continuation_a",
4333       "implicit_iterate", "implicit_vector_ref_a", "implicit_vector_ref_aa", "implicit_string_ref_a",
4334       "implicit_c_object_ref_a", "implicit_pair_ref_a", "implicit_hash_table_ref_a", "implicit_let_ref_c", "implicit_let_ref_a",
4335       "implicit_*s7*_ref_s", "implicit_*s7*_set_sa",
4336       "implicit_vector_set_3", "implicit_vector_set_4",
4337       "unknown_thunk", "unknown_all_s", "unknown_all_a", "unknown_g", "unknown_gg", "unknown_a", "unknown_aa", "unknown_fp",
4338 
4339       "symbol", "global-symbol", "constant", "pair_sym", "pair_pair", "pair_any",
4340       "h_ssa_direct", "h_hash_table_increment", "clear_opts",
4341 
4342       "read_internal", "eval",
4343       "eval_args", "eval_args1", "eval_args2", "eval_args3", "eval_args4", "eval_args5",
4344       "apply", "eval_macro", "lambda", "quote", "quote_unchecked", "macroexpand", "call/cc",
4345       "define", "define1", "begin", "begin_hook", "begin_no_hook", "begin_unchecked",
4346       "begin_1_unchecked", "begin_2_unchecked", "begin_all_a", "begin_aa",
4347       "if", "if1", "when", "unless", "set", "set1", "set2",
4348       "let", "let1", "let*", "let*1", "let*2",
4349       "letrec", "letrec1", "letrec*", "letrec*1",
4350       "let_temporarily", "let_temp_unchecked", "let_temp_init1", "let_temp_init2", "let_temp_done", "let_temp_done1",
4351       "let_temp_s7", "let_temp_fx", "let_temp_fx_1", "let_temp_setter", "let_temp_unwind", "let_temp_s7_unwind", "let_temp_setter_unwind",
4352       "let_temp_a_a",
4353       "cond", "cond1", "feed_to_1", "cond_simple", "cond1_simple", "cond_simple_o", "cond1_simple_o",
4354       "and", "or",
4355       "define_macro", "define_macro*", "define_expansion", "define_expansion*", "macro", "macro*",
4356       "case", "read_list", "read_next", "read_dot", "read_quote",
4357       "read_quasiquote", "read_unquote", "read_apply_values",
4358       "read_vector", "read_byte_vector", "read_int_vector", "read_float_vector", "read_done",
4359       "load_return_if_eof", "load_close_and_pop_if_eof", "eval_done", "splice_values",
4360       "catch", "dynamic_wind", "dynamic_unwind", "dynamic_unwind_profile", "profile_in",
4361       "define_constant", "define_constant1",
4362       "do", "do_end", "do_end1", "do_step", "do_step2", "do_init",
4363       "define*", "lambda*", "lambda*_default", "error_quit", "unwind_input", "unwind_output",
4364       "error_hook_quit",
4365       "with_let", "with_let1", "with_let_unchecked", "with_let_s", "with_unlet_s",
4366       "with_baffle", "with_baffle_unchecked", "expansion",
4367       "for_each", "for_each_1", "for_each_2", "for_each_3",
4368       "map", "map_1", "map_2", "map_gather", "map_gather_1", "map_gather_2", "map_gather_3",
4369       "barrier", "deactivate_goto",
4370       "define_bacro", "define_bacro*", "bacro", "bacro*",
4371       "get_output_string",
4372       "sort", "sort1", "sort2", "sort3", "sort_pair_end", "sort_vector_end", "sort_string_end",
4373       "eval_string",
4374       "member_if", "assoc_if", "member_if1", "assoc_if1",
4375       "lambda_unchecked", "let_unchecked", "catch_1", "catch_2", "catch_all",
4376       "set_unchecked", "set_symbol_c", "set_symbol_s", "set_symbol_p", "set_symbol_a",
4377       "set_normal", "set_pair", "set_dilambda", "set_dilambda_p", "set_dilambda_p_1", "set_dilambda_sa_a",
4378       "set_pair_a", "set_pair_p", "set_pair_za",
4379       "set_pair_p_1", "set_from_setter", "set_pws", "set_let_s", "set_let_fx", "set_safe",
4380       "increment_1", "decrement_1", "set_cons",
4381       "increment_ss", "increment_sp", "increment_sa", "increment_saa",
4382       "letrec_unchecked", "letrec*_unchecked", "cond_unchecked",
4383       "lambda*_unchecked", "do_unchecked", "define_unchecked", "define*_unchecked", "define_funchecked", "define_constant_unchecked",
4384       "define_with_setter",
4385 
4386       "let_no_vars", "named_let", "named_let_no_vars", "named_let_fx", "named_let*",
4387       "let_fx_old", "let_fx_new", "let_2a_old", "let_2a_new", "let_3a_old", "let_3a_new",
4388       "let_opssq_old", "let_opssq_new", "let_opssq_e_old", "let_opssq_e_new", "let_opassq_old", "let_opassq_new", "let_opassq_e_old", "let_opassq_e_new",
4389       "let_one_old", "let_one_new", "let_one_p_old", "let_one_p_new",
4390       "let_one_old_1", "let_one_new_1", "let_one_p_old_1", "let_one_p_new_1",
4391       "let_a_old", "let_a_new", "let_a_p_old", "let_a_p_new",
4392       "let_a_a_old", "let_a_a_new", "let_a_fx_old", "let_a_fx_new", "let_a_old_2", "let_a_new_2",
4393       "let*_fx", "let*_fx_a",
4394 
4395       "case_a_e_s", "case_a_i_s", "case_a_g_s", "case_a_e_g", "case_a_g_g", "case_a_s_s", "case_a_s_g",
4396       "case_s_e_s", "case_s_i_s", "case_s_g_s", "case_s_e_g", "case_s_g_g", "case_s_s_s", "case_s_s_g",
4397       "case_p_e_s", "case_p_i_s", "case_p_g_s", "case_p_e_g", "case_p_g_g", "case_p_s_s", "case_p_s_g",
4398       "case_e_s", "case_i_s", "case_g_s", "case_e_g", "case_g_g", "case_s_s", "case_s_g",
4399 
4400       "if_unchecked", "and_p", "and_p1", "and_ap", "and_pair_p",
4401       "and_safe_p1", "op_and_safe_p2", "and_safe_p3", "and_safe_p_rest", "and_2", "and_3", "and_n", "and_s_2",
4402       "or_p", "or_p1", "or_ap", "or_2", "or_3", "or_n", "or_s_2", "or_s_type_2",
4403       "when_s", "when_a", "when_p", "when_and_ap", "when_and_2", "when_and_3", "unless_s", "unless_a", "unless_p",
4404 
4405       "if_a_c_c", "if_a_a", "if_a_a_a", "if_s_a_a", "if_and2_s_a", "if_not_a_a", "if_not_a_a_a",
4406       "if_a_a_p", "if_a_p_a", "if_s_p_a", "if_is_type_s_p_a", "if_is_type_s_a_a",
4407       "if_s_p", "if_s_p_p", "if_s_r", "if_s_n", "if_s_n_n",
4408       "if_opsq_p", "if_opsq_p_p", "if_opsq_r", "if_opsq_n", "if_opsq_n_n",
4409       "if_is_type_s_p", "if_is_type_s_p_p", "if_is_type_s_r", "if_is_type_s_n", "if_is_type_s_n_n",
4410       "if_a_p", "if_a_p_p", "if_a_r", "if_a_n", "if_a_n_n",
4411       "if_and2_p", "if_and2_p_p", "if_and2_r", "if_and2_n", "if_and2_n_n",
4412       "if_and3_p", "if_and3_p_p", "if_and3_r", "if_and3_n", "if_and3_n_n",
4413       "if_p_p", "if_p_p_p", "if_p_r", "if_p_n", "if_p_n_n",
4414       "if_andp_p", "if_andp_p_p", "if_andp_r", "if_andp_n", "if_andp_n_n",
4415       "if_orp_p", "if_orp_p_p", "if_orp_r", "if_orp_n", "if_orp_n_n",
4416       "if_or2_p", "if_or2_p_p", "if_or2_r", "if_or2_n", "if_or2_n_n",
4417       "if_pp", "if_ppp", "if_pr", "if_prr", "when_pp", "unless_pp",
4418 
4419       "cond_fx_fx", "cond_fx_fp", "cond_fx_fp_1", "cond_fx_2e", "cond_fx_3e", "cond_fx_fp_o",
4420       "cond_feed", "cond_feed_1",
4421 
4422       "simple_do", "simple_do_step", "safe_dotimes", "safe_dotimes_step", "safe_dotimes_step_o",
4423       "safe_do", "safe_do_step", "dox", "dox_step", "dox_step_o", "dox_no_body", "dox_pending_no_body", "dox_init",
4424       "dotimes_p", "dotimes_step_o",
4425       "do_no_vars", "do_no_vars_no_opt", "do_no_vars_no_opt_1",
4426       "do_no_body_fx_vars", "do_no_body_fx_vars_step", "do_no_body_fx_vars_step_1",
4427 
4428       "safe_c_p_1", "safe_c_pp_1", "safe_c_pp_3_mv", "safe_c_pp_5", "safe_c_pp_6_mv",
4429       "safe_c_sp_1", "safe_c_sp_mv", "safe_cons_sp_1", "safe_vector_sp_1", "safe_add_sp_1", "safe_multiply_sp_1", "safe_subtract_sp_1",
4430       "safe_c_ps_1", "safe_c_pc_1", "safe_c_ps_mv", "safe_c_pc_mv",
4431       "eval_macro_mv", "macroexpand_1", "apply_lambda",
4432       "safe_closure_p_1", "closure_p_1", "safe_closure_p_a_1",
4433       "safe_closure_ap_1", "safe_closure_pa_1", "safe_closure_pp_1", "any_closure_fp_1", "any_closure_fp_mv_1",
4434       "increment_sp_1", "increment_sp_mv",
4435       "any_c_fp_1", "any_c_fp_mv_1", "safe_c_ssp_1", "safe_c_ssp_mv_1",
4436       "c_p_1", "c_p_mv", "c_ap_1", "c_ap_mv", "any_c_fp_2",
4437       "closure_ap_1", "closure_pa_1", "closure_pp_1",
4438       "safe_c_pa_1", "safe_c_pa_mv", "any_closure_fp_2",
4439       "any_closure_3p_1", "any_closure_3p_2", "any_closure_3p_3",
4440       "any_closure_4p_1", "any_closure_4p_2", "any_closure_4p_3", "any_closure_4p_4",
4441       "set_with_let_1", "set_with_let_2",
4442 
4443       "tc_and_a_or_a_la", "tc_or_a_and_a_la", "tc_and_a_or_a_laa", "tc_or_a_and_a_laa", "tc_or_a_a_and_a_a_la",
4444       "tc_or_a_and_a_a_l3a", "tc_and_a_or_a_a_la", "tc_or_a_and_a_a_la",
4445       "tc_let_when_laa", "tc_let_unless_laa",
4446       "tc_cond_a_z_a_z_laa", "tc_cond_a_z_a_laa_z", "tc_cond_a_z_a_laa_laa", "tc_let_cond",
4447       "tc_if_a_z_la", "tc_if_a_z_laa", "tc_if_a_z_l3a", "tc_if_a_l3a_z", "tc_if_a_la_z", "tc_if_a_laa_z",
4448       "tc_if_a_z_if_a_z_la", "tc_if_a_z_if_a_la_z", "tc_if_a_z_if_a_z_laa", "tc_if_a_z_if_a_laa_z", "tc_if_a_z_if_a_l3a_l3a",
4449       "tc_cond_a_z_a_z_la", "tc_cond_a_z_a_la_z", "tc_cond_a_z_la", "tc_cond_a_la_z", "tc_cond_a_z_laa", "tc_cond_a_laa_z",
4450       "tc_let_if_a_z_la", "tc_let_if_a_z_laa", "if_a_z_let_if_a_z_laa",
4451       "tc_case_la", "tc_and_a_if_a_z_la", "tc_and_a_if_a_la_z",
4452 
4453       "recur_if_a_a_opa_laq", "recur_if_a_opa_laq_a", "recur_if_a_a_opla_aq", "recur_if_a_opla_aq_a",
4454       "recur_if_a_a_opla_laq", "recur_if_a_opla_laq_a",
4455       "recur_if_a_a_opa_la_laq", "recur_if_a_opa_la_laq_a",
4456       "recur_if_a_a_opla_la_laq", "recur_if_a_a_if_a_a_opla_laq", "recur_if_a_a_if_a_a_oplaa_laaq",
4457       "recur_if_a_a_opa_laaq", "recur_if_a_opa_laaq_a", "recur_if_a_a_opa_l3aq",
4458       "recur_if_a_a_lopl3a_l3a_l3aq", "recur_if_a_a_and_a_laa_laa",
4459       "recur_if_a_a_if_a_laa_opa_laaq",
4460       "recur_cond_a_a_op_a_laq", "recur_cond_a_a_op_a_laaq",
4461       "recur_cond_a_a_a_a_opla_laq", "recur_cond_a_a_a_a_oplaa_laaq", "recur_cond_a_a_a_a_opa_laaq",
4462       "recur_cond_a_a_a_laa_lopa_laaq", "recur_cond_a_a_a_laa_opa_laaq",
4463       "recur_and_a_or_a_laa_laa",
4464 };
4465 
4466 #define is_safe_c_op(op)  ((op >= OP_SAFE_C_D) && (op < OP_THUNK))
4467 #define is_unknown_op(op) ((op >= OP_UNKNOWN) && (op <= OP_UNKNOWN_FP))
4468 #define is_h_safe_c_d(P)  (optimize_op(P) == HOP_SAFE_C_D)
4469 #define is_safe_c_s(P)    ((optimize_op(P) == OP_SAFE_C_S) || (optimize_op(P) == HOP_SAFE_C_S))
4470 #define is_h_safe_c_s(P)  (optimize_op(P) == HOP_SAFE_C_S)
4471 #define FIRST_UNHOPPABLE_OP OP_APPLY_SS
4472 
4473 static bool is_h_optimized(s7_pointer p)
4474 {
4475   return((is_optimized(p)) &&
4476 	 (op_has_hop(p)) &&
4477 	 (optimize_op(p) < FIRST_UNHOPPABLE_OP) &&  /* was OP_S? */
4478 	 (optimize_op(p) > OP_GC_PROTECT));
4479 }
4480 
4481 
4482 /* -------------------------------- internal debugging apparatus -------------------------------- */
4483 
4484 static int64_t heap_location(s7_scheme *sc, s7_pointer p)
4485 {
4486   heap_block_t *hp;
4487   for (hp = sc->heap_blocks; hp; hp = hp->next)
4488     if (((intptr_t)p >= hp->start) && ((intptr_t)p < hp->end))
4489       return(hp->offset + (((intptr_t)p - hp->start) / sizeof(s7_cell)));
4490   return(((s7_big_pointer)p)->big_hloc);
4491 }
4492 
4493 #if TRAP_SEGFAULT
4494 #include <signal.h>
4495 static sigjmp_buf senv; /* global here is not a problem -- it is used only to protect s7_is_valid */
4496 static volatile sig_atomic_t can_jump = 0;
4497 static void segv(int32_t ignored) {if (can_jump) siglongjmp(senv, 1);}
4498 #endif
4499 
4500 bool s7_is_valid(s7_scheme *sc, s7_pointer arg)
4501 {
4502   bool result = false;
4503   if (!arg) return(false);
4504 #if TRAP_SEGFAULT
4505   if (sigsetjmp(senv, 1) == 0)
4506     {
4507       void (*old_segv)(int32_t sig);
4508       can_jump = 1;
4509       old_segv = signal(SIGSEGV, segv);
4510 #endif
4511       if ((unchecked_type(arg) > T_FREE) &&
4512 	  (unchecked_type(arg) < NUM_TYPES))
4513 	{
4514 	  if (not_in_heap(arg))
4515 	    result = true;
4516 	  else
4517 	    {
4518 	      int64_t loc;
4519 	      loc = heap_location(sc, arg);
4520 	      if ((loc >= 0) && (loc < sc->heap_size))
4521 		result = (sc->heap[loc] == arg);
4522 	    }}
4523 #if TRAP_SEGFAULT
4524       signal(SIGSEGV, old_segv);
4525     }
4526   else result = false;
4527   can_jump = 0;
4528 #endif
4529   return(result);
4530 }
4531 
4532 void s7_show_let(s7_scheme *sc) /* debugging convenience */
4533 {
4534   s7_pointer olet;
4535   for (olet = sc->curlet; is_let(T_Lid(olet)); olet = let_outlet(olet))
4536     {
4537       if (olet == sc->owlet)
4538 	fprintf(stderr, "(owlet): ");
4539       else
4540 	{
4541 	  if (is_funclet(olet))
4542 	    fprintf(stderr, "(%s funclet): ", display(funclet_function(olet)));
4543 	  else
4544 	    if (olet == sc->shadow_rootlet)
4545 	      fprintf(stderr, "(shadow rootlet): ");
4546 	}
4547       fprintf(stderr, "%s\n", display(olet));
4548     }
4549 }
4550 
4551 #define safe_print(Code)	   \
4552   do {				   \
4553     bool old_open, old_stop;	   \
4554     old_open = sc->has_openlets;   \
4555     old_stop = sc->stop_at_error;  \
4556     sc->has_openlets = false;      \
4557     sc->stop_at_error = false;	   \
4558     Code;			   \
4559     sc->stop_at_error = old_stop;  \
4560     sc->has_openlets = old_open;   \
4561   } while (0)
4562 
4563 void s7_show_history(s7_scheme *sc)
4564 {
4565 #if WITH_HISTORY
4566   if (sc->cur_code == sc->history_sink)
4567     fprintf(stderr, "history diabled\n");
4568   else
4569     {
4570       int32_t i, size;
4571       s7_pointer p;
4572       size = sc->history_size;
4573       fprintf(stderr, "history:\n");
4574       for (i = 0, p = cdr(sc->cur_code); i < size; i++, p = cdr(p)) /* stepper "i" is not redundant */
4575 	safe_print(fprintf(stderr, "%d: %s\n", i, display_80(car(p))));
4576       fprintf(stderr, "\n");
4577     }
4578 #else
4579   fprintf(stderr, "%s\n", display(sc->cur_code));
4580 #endif
4581 }
4582 
4583 #define stack_code(Stack, Loc)  stack_element(Stack, Loc - 3)
4584 #define stack_let(Stack, Loc)   stack_element(Stack, Loc - 2)
4585 #define stack_args(Stack, Loc)  stack_element(Stack, Loc - 1)
4586 #define stack_op(Stack, Loc)    ((opcode_t)(stack_element(Stack, Loc)))
4587 
4588 void s7_show_stack(s7_scheme *sc)
4589 {
4590   int64_t i;
4591   fprintf(stderr, "stack:\n");
4592   for (i = current_stack_top(sc) - 1; i >= 3; i -= 4)
4593     fprintf(stderr, "  %s\n", op_names[stack_op(sc->stack, i)]);
4594 }
4595 
4596 
4597 static char *describe_type_bits(s7_scheme *sc, s7_pointer obj) /* used outside S7_DEBUGGING in display_any (fallback for display_functions) */
4598 {
4599   uint64_t full_typ;
4600   uint8_t typ;
4601   char *buf;
4602 
4603   buf = (char *)Malloc(1024);
4604   typ = unchecked_type(obj);
4605   full_typ = full_type(obj);
4606 
4607   /* if debugging, all of these bits are being watched, so we need to access them directly */
4608   snprintf(buf, 1024,
4609 	   "type: %s? (%d), opt_op: %d, flags: #x%" PRIx64 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
4610 	   type_name(sc, obj, NO_ARTICLE),
4611 	   typ,
4612 	   optimize_op(obj),
4613 	   full_typ,
4614 	   /* bit 0 (the first 8 bits are easy...) */
4615 	   ((full_typ & T_MULTIFORM) != 0) ?      ((is_any_closure(obj)) ? (((full_typ & T_ONE_FORM) != 0) ? " clo-has-fx" : " multiform") : " ?0?") : "",
4616 	   /* bit 1 */
4617 	   ((full_typ & T_SYNTACTIC) != 0) ?      (((is_pair(obj)) || (is_syntax(obj)) || (is_normal_symbol(obj))) ? " syntactic" : " ?1?") : "",
4618 	   /* bit 2 */
4619 	   ((full_typ & T_SIMPLE_ARG_DEFAULTS) != 0) ? ((is_pair(obj)) ? " simple-args|in-use" :
4620 							((is_any_closure(obj)) ? " one-form" :
4621 							 " ?2?")) : "",
4622 	   /* bit 3 */
4623 	   ((full_typ & T_OPTIMIZED) != 0) ?      ((is_c_function(obj)) ? " scope-safe" :
4624 						   ((is_pair(obj)) ? " optimized" :
4625 						    " ?3?")) : "",
4626 	   /* bit 4 */
4627 	   ((full_typ & T_SAFE_CLOSURE) != 0) ?   (((has_closure_let(obj)) || (is_pair(obj))) ? " safe-closure" : " ?4?") : "",
4628 	   /* bit 5 */
4629 	   ((full_typ & T_DONT_EVAL_ARGS) != 0) ? (((is_any_macro(obj)) || (is_syntax(obj))) ? " dont-eval-args" : " ?5?") : "",
4630 	   /* bit 6 */
4631 	   ((full_typ & T_EXPANSION) != 0) ?      (((is_normal_symbol(obj)) || (is_either_macro(obj))) ? " expansion" : " ?6?") : "",
4632 	   /* bit 7 */
4633 	   ((full_typ & T_MULTIPLE_VALUE) != 0) ? ((is_symbol(obj)) ? " matched" :
4634 						   ((is_pair(obj)) ? " values|matched" :
4635 						    " ?7?")) : "",
4636 	   /* bit 8 */
4637 	   ((full_typ & T_GLOBAL) != 0) ?         ((is_pair(obj)) ? " unsafe-do" :
4638 						   (((is_symbol(obj)) || (is_syntax(obj))) ? " global" :
4639 						    ((is_let(obj)) ? " dox_slot1" :
4640 						     " ?8?"))) : "",
4641 	   /* bit 9 */
4642 	   ((full_typ & T_COLLECTED) != 0) ?      " collected" : "",
4643 	   /* bit 10 */
4644 	   ((full_typ & T_LOCATION) != 0) ?       ((is_pair(obj)) ? " line-number" :
4645 						   ((is_input_port(obj)) ? " loader-port" :
4646 						    ((is_let(obj)) ? " with-let" :
4647 						     ((is_any_procedure(obj)) ? " simple-defaults" :
4648 						      (((is_normal_symbol(obj)) || (is_slot(obj))) ? " has-setter" :
4649 						       " ?10?"))))) : "",
4650 	   /* bit 11 */
4651 	   ((full_typ & T_SHARED) != 0) ?         ((is_sequence(obj)) ? " shared" : " ?11?") : "",
4652 	   /* bit 12 */
4653 	   ((full_typ & T_LOCAL) != 0) ?          ((is_normal_symbol(obj)) ? " local" :
4654 						   ((is_pair(obj)) ? " high-c" :
4655 						    " ?12?")) : "",
4656 	   /* bit 13 */
4657 	   ((full_typ & T_SAFE_PROCEDURE) != 0) ? " safe-procedure" : "",
4658 	   /* bit 14 */
4659 	   ((full_typ & T_CHECKED) != 0) ?        (((is_pair(obj)) || (is_slot(obj))) ? " checked" :
4660 						   ((is_symbol(obj)) ? " all-integer" :
4661 						    " ?14?")) : "",
4662 	   /* bit 15 */
4663 	   ((full_typ & T_UNSAFE) != 0) ?         ((is_symbol(obj)) ? " clean-symbol" :
4664 						   ((is_slot(obj)) ? " has-stepper" :
4665 						    ((is_pair(obj)) ? " unsafely-opt|no-float-opt" :
4666 						     ((is_let(obj)) ? " dox-slot2" :
4667 						      " ?15?")))) : "",
4668 	   /* bit 16 */
4669 	   ((full_typ & T_IMMUTABLE) != 0) ?      " immutable" : "",
4670 	   /* bit 17 */
4671 	   ((full_typ & T_SETTER) != 0) ?         ((is_normal_symbol(obj)) ? " setter" :
4672 						   ((is_pair(obj)) ? " allow-other-keys|no-int-opt" :
4673 						    ((is_slot(obj)) ? " has-expression" :
4674 						     ((is_c_function_star(obj)) ? " allow-other-keys" :
4675 						      " ?17?")))) : "",
4676 	   /* bit 18 */
4677 	   ((full_typ & T_MUTABLE) != 0) ?        ((is_number(obj)) ? " mutable" :
4678 						   ((is_symbol(obj)) ? " has-keyword" :
4679 						    ((is_let(obj)) ? " let-ref-fallback" :
4680 						     ((is_iterator(obj)) ? " mark-sequence" :
4681 						      ((is_slot(obj)) ? " step-end" :
4682 						       ((is_let(obj)) ? " ref-fallback" :
4683 							((is_pair(obj)) ? " no-opt" :
4684 							 " ?18?"))))))) : "",
4685 	   /* bit 19 */
4686 	   ((full_typ & T_SAFE_STEPPER) != 0) ?   ((is_let(obj)) ? " set-fallback" :
4687 						   ((is_slot(obj)) ? " safe-stepper" :
4688 						    ((is_c_function(obj)) ? " maybe-safe" :
4689 						     ((is_number(obj)) ? " print-name" :
4690 						      ((is_pair(obj)) ? " direct-opt" :
4691 						       ((is_hash_table(obj)) ? " weak-hash" :
4692 							((is_any_macro(obj)) ? " pair-macro-set" :
4693 							 ((is_symbol(obj)) ? " all-float" :
4694 							  " ?19?")))))))) : "",
4695 	   /* bit 20, for c_function case see sc->apply */
4696 	   ((full_typ & T_COPY_ARGS) != 0) ?      (((is_pair(obj)) || (is_any_macro(obj)) || (is_syntax(obj)) ||
4697 						    (is_any_closure(obj)) || (is_c_function(obj))) ? " copy-args" :
4698 						    " ?20?") : "",
4699 	   /* bit 21 */
4700 	   ((full_typ & T_GENSYM) != 0) ?         ((is_let(obj)) ? " funclet" :
4701 						   ((is_normal_symbol(obj)) ? " gensym" :
4702 						    ((is_string(obj)) ? " documented-symbol" :
4703 						     ((is_hash_table(obj)) ? " hash-chosen" :
4704 						      ((is_pair(obj)) ? " dotted" :
4705 						       ((is_any_vector(obj)) ? " subvector" :
4706 							((is_slot(obj)) ? " has-pending-value" :
4707 							 ((is_any_closure(obj)) ? " unknopt" :
4708 							  " ?21?")))))))) : "",
4709 	   /* bit 22 */
4710 	   ((full_typ & T_HAS_METHODS) != 0) ?    (((is_let(obj)) || (is_c_object(obj)) || (is_any_closure(obj)) ||
4711 						    (is_any_macro(obj)) || (is_c_pointer(obj))) ? " has-methods" : " ?22?") : "",
4712 	   /* bit 23 */
4713 	   ((full_typ & T_ITER_OK) != 0) ?        ((is_iterator(obj)) ? " iter-ok" : " ?23?") : "",
4714 	   /* bit 24+16 */
4715 	   ((full_typ & T_FULL_SYMCONS) != 0) ?   ((is_symbol(obj)) ? " possibly-constant" :
4716 						   ((is_procedure(obj)) ? " has-let-arg" :
4717 						    ((is_hash_table(obj)) ? " has-value-type" :
4718 						     ((is_pair(obj)) ? " int-optable" :
4719 						      " ?24?")))) : "",
4720 	   /* bit 25+16 */
4721 	   ((full_typ & T_FULL_HAS_LET_FILE) != 0) ? ((is_let(obj)) ? " has-let-file" :
4722 						      ((is_any_vector(obj)) ? " typed-vector" :
4723 						       ((is_hash_table(obj)) ? " typed-hash-table" :
4724 							((is_c_function(obj)) ? " has-bool-setter" :
4725 							 ((is_slot(obj)) ? " rest-slot" :
4726 							  (((is_pair(obj)) || (is_closure_star(obj))) ? " no-defaults" :
4727 							   " ?25?")))))) : "",
4728 	   /* bit 26+16 */
4729 	   ((full_typ & T_FULL_DEFINER) != 0) ?   ((is_normal_symbol(obj)) ? " definer" :
4730 						   ((is_pair(obj)) ? " has-fx" :
4731 						    ((is_slot(obj)) ? " slot-defaults" :
4732 						     ((is_iterator(obj)) ? " weak-hash-iterator" :
4733 						      ((is_hash_table(obj)) ? " has-key-type" :
4734 						       ((is_let(obj)) ? " maclet" :
4735 							((is_c_function(obj)) ? " func-definer" :
4736 							 ((is_syntax(obj)) ? " syntax-definer" :
4737 							  " ?26?")))))))) : "",
4738 	   /* bit 27+16 */
4739 	   ((full_typ & T_FULL_BINDER) != 0) ?    ((is_pair(obj)) ? " tree-collected" :
4740 						   ((is_hash_table(obj)) ? " simple-values" :
4741 						    ((is_normal_symbol(obj)) ? " binder" :
4742 						     ((is_c_function(obj)) ? " safe-args" :
4743 						      " ?27?")))) : "",
4744 	   /* bit 28+16 */
4745 	   ((full_typ & T_VERY_SAFE_CLOSURE) != 0) ? (((is_pair(obj)) || (is_any_closure(obj))) ? " very-safe-closure" :
4746 						      ((is_let(obj)) ? " baffle-let" :
4747 						      " ?28?")) : "",
4748 	   /* bit 29+16 */
4749 	   ((full_typ & T_CYCLIC) != 0) ?         (((is_simple_sequence(obj)) || (t_structure_p[type(obj)]) ||
4750 						    (is_any_closure(obj))) ? " cyclic" : " ?29?") : "",
4751 	   /* bit 30+16 */
4752 	   ((full_typ & T_CYCLIC_SET) != 0) ?     (((is_simple_sequence(obj)) || (t_structure_p[type(obj)]) ||
4753 						    (is_any_closure(obj))) ? " cyclic-set" : " ?30?") : "",
4754 	   /* bit 31+16 */
4755 	   ((full_typ & T_KEYWORD) != 0) ?        ((is_symbol(obj)) ? " keyword" : " ?31?") : "",
4756 	   /* bit 32+16 */
4757 	   ((full_typ & T_FULL_SIMPLE_ELEMENTS) != 0) ? ((is_normal_vector(obj)) ? " simple-elements" :
4758 							 ((is_hash_table(obj)) ? " simple-keys" :
4759 							  ((is_normal_symbol(obj)) ? " safe-setter" :
4760 							   ((is_pair(obj)) ? " float-optable" :
4761 							    ((typ >= T_C_MACRO) ? " function-simple-elements" :
4762 							     " 32?"))))) : "",
4763 	   /* bit 33+16 */
4764 	   ((full_typ & T_FULL_CASE_KEY) != 0) ?  ((is_symbol(obj)) ? " case-key" :
4765 						   ((is_pair(obj)) ? " opt1-func-listed" :
4766 						    " ?33?")) : "",
4767 	   /* bit 34+16 */
4768 	   ((full_typ & T_FULL_HAS_GX) != 0) ?    ((is_pair(obj)) ? " has-gx" : " ?34?") : "",
4769 	   /* bit 35+16 */
4770 	   ((full_typ & T_FULL_UNKNOPT) != 0) ?    ((is_pair(obj)) ? " unknopt" : " ?35?") : "",
4771 	   /* bit 36+16 */
4772 	   ((full_typ & T_FULL_SAFETY_CHECKED) != 0) ? ((is_pair(obj)) ? " safety-checked" : " ?36?") : "",
4773 	   ((full_typ & T_FULL_HAS_FN) != 0) ?    ((is_pair(obj)) ? " has-fn" : " ?37") : "",
4774 	   ((full_typ & UNUSED_BITS) != 0) ?      " unused bits set?" : "",
4775 	   /* bit 54 */
4776 	   ((full_typ & T_UNHEAP) != 0) ?         " unheap" : "",
4777 	   /* bit 55 */
4778 	   ((full_typ & T_GC_MARK) != 0) ?        " gc-marked" : "",
4779 
4780 	   ((is_symbol(obj)) && (((uint8_t)(symbol_type(obj) & 0xff) >= NUM_TYPES) || ((symbol_type(obj) & ~0xffff) != 0))) ? " bad-symbol-type" : "");
4781 
4782   return(buf);
4783 }
4784 
4785 #if S7_DEBUGGING
4786 static bool has_odd_bits(s7_pointer obj)
4787 {
4788   uint64_t full_typ;
4789   full_typ = full_type(obj);
4790 
4791   if ((full_typ & UNUSED_BITS) != 0) return(true);
4792   if (((full_typ & T_MULTIFORM) != 0) && (!is_any_closure(obj))) return(true);
4793   if (((full_typ & T_KEYWORD) != 0) && ((!is_symbol(obj)) || (!is_global(obj)) || (is_gensym(obj)))) return(true);
4794   if (((full_typ & T_SYNTACTIC) != 0) && (!is_syntax(obj)) && (!is_pair(obj)) && (!is_normal_symbol(obj))) return(true);
4795   if (((full_typ & T_SIMPLE_ARG_DEFAULTS) != 0) && (!is_pair(obj)) && (!is_any_closure(obj))) return(true);
4796   if (((full_typ & T_OPTIMIZED) != 0) && (!is_c_function(obj)) && (!is_pair(obj))) return(true);
4797   if (((full_typ & T_SAFE_CLOSURE) != 0) && (!is_any_closure(obj)) && (!is_pair(obj))) return(true);
4798   if (((full_typ & T_EXPANSION) != 0) && (!is_normal_symbol(obj)) && (!is_either_macro(obj))) return(true);
4799   if (((full_typ & T_MULTIPLE_VALUE) != 0) && (!is_symbol(obj)) && (!is_pair(obj))) return(true);
4800   if (((full_typ & T_GLOBAL) != 0) && (!is_pair(obj)) && (!is_symbol(obj)) && (!is_let(obj)) && (!is_syntax(obj))) return(true);
4801   if (((full_typ & T_ITER_OK) != 0) && (!is_iterator(obj))) return(true);
4802   if (((full_typ & T_FULL_SYMCONS) != 0) && (!is_symbol(obj)) && (!is_procedure(obj)) && (!is_let(obj)) && (!is_hash_table(obj)) && (!is_pair(obj))) return(true);
4803   if (((full_typ & T_LOCAL) != 0) && (!is_normal_symbol(obj)) && (!is_pair(obj))) return(true);
4804   if (((full_typ & T_COPY_ARGS) != 0) && (!is_pair(obj)) && (!is_any_macro(obj)) && (!is_any_closure(obj)) && (!is_c_function(obj)) && (!is_syntax(obj))) return(true);
4805   if (((full_typ & T_UNSAFE) != 0) && (!is_symbol(obj)) && (!is_slot(obj)) && (!is_let(obj)) && (!is_pair(obj))) return(true);
4806   if (((full_typ & T_VERY_SAFE_CLOSURE) != 0) && (!is_pair(obj)) && (!is_any_closure(obj)) && (!is_let(obj))) return(true);
4807   if (((full_typ & T_FULL_CASE_KEY) != 0) && (!is_symbol(obj)) && (!is_pair(obj))) return(true);
4808   if (((full_typ & T_FULL_UNKNOPT) != 0) && (!is_pair(obj))) return(true);
4809   if (((full_typ & T_FULL_SAFETY_CHECKED) != 0) && (!is_pair(obj))) return(true);
4810   if (((full_typ & T_FULL_HAS_GX) != 0) && (!is_pair(obj)) && (!is_any_closure(obj))) return(true);
4811   if (((full_typ & T_DONT_EVAL_ARGS) != 0) && (!is_any_macro(obj)) && (!is_syntax(obj))) return(true);
4812   if (((full_typ & T_CHECKED) != 0) && (!is_slot(obj)) && (!is_pair(obj)) && (!is_symbol(obj))) return(true);
4813   if (((full_typ & T_SHARED) != 0) && (!t_sequence_p[type(obj)]) && (!t_structure_p[type(obj)]) && (!is_any_closure(obj))) return(true);
4814   if (((full_typ & T_FULL_BINDER) != 0) &&
4815       ((!is_pair(obj)) && (!is_hash_table(obj)) && (!is_normal_symbol(obj)) && (!is_c_function(obj)) && (!is_syntax(obj))))
4816     return(true);
4817   if (((full_typ & T_FULL_DEFINER) != 0) &&
4818       (!is_normal_symbol(obj)) && (!is_c_function(obj)) && (!is_pair(obj)) && (!is_slot(obj)) && (!is_iterator(obj)) &&
4819       (!is_hash_table(obj)) && (!is_let(obj)) && (!is_syntax(obj)))
4820     return(true);
4821   if (((full_typ & T_FULL_HAS_LET_FILE) != 0) &&
4822       (!is_let(obj)) && (!is_any_vector(obj)) && (!is_hash_table(obj)) && (!is_c_function(obj)) && (!is_slot(obj)) && (!is_pair(obj)) && (!is_closure_star(obj)))
4823     return(true);
4824   if (((full_typ & T_SAFE_STEPPER) != 0) &&
4825       (!is_let(obj)) && (!is_slot(obj)) && (!is_c_function(obj)) && (!is_number(obj)) && (!is_pair(obj)) && (!is_hash_table(obj)) && (!is_any_macro(obj)) && (!is_symbol(obj)))
4826     return(true);
4827   if (((full_typ & T_SETTER) != 0) &&
4828       (!is_slot(obj)) && (!is_normal_symbol(obj)) && (!is_pair(obj)) && (!is_let(obj)) && (!is_c_function_star(obj)))
4829     return(true);
4830   if (((full_typ & T_LOCATION) != 0) &&
4831       (!is_pair(obj)) && (!is_input_port(obj)) && (!is_let(obj)) && (!is_any_procedure(obj)) && (!is_symbol(obj)) && (!is_slot(obj)))
4832     return(true);
4833   if (((full_typ & T_MUTABLE) != 0) &&
4834       (!is_number(obj)) && (!is_symbol(obj)) && (!is_let(obj)) && (!is_iterator(obj)) && (!is_slot(obj)) && (!is_let(obj)) && (!is_pair(obj)))
4835     return(true);
4836   if (((full_typ & T_GENSYM) != 0) && (!is_slot(obj)) && (!is_any_closure(obj)) &&
4837       (!is_let(obj)) && (!is_symbol(obj)) && (!is_string(obj)) && (!is_hash_table(obj)) && (!is_pair(obj)) && (!is_any_vector(obj)))
4838     return(true);
4839   if (((full_typ & T_FULL_SIMPLE_ELEMENTS) != 0) &&
4840       ((!is_normal_vector(obj)) && (!is_hash_table(obj)) && (!is_normal_symbol(obj)) && (!is_pair(obj)) && (unchecked_type(obj) < T_C_MACRO)))
4841     return(true);
4842   if (((full_typ & T_CYCLIC) != 0) && (!is_simple_sequence(obj)) && (!t_structure_p[type(obj)]) && (!is_any_closure(obj)))
4843     return(true);
4844   if (((full_typ & T_CYCLIC_SET) != 0) && (!is_simple_sequence(obj)) && (!t_structure_p[type(obj)]) && (!is_any_closure(obj)))
4845     return(true);
4846   if (((full_typ & T_FULL_HAS_FN) != 0) && (!is_pair(obj))) return(true);
4847 
4848   if (is_symbol(obj))
4849     {
4850       if ((uint8_t)(symbol_type(obj) & 0xff) >= NUM_TYPES)
4851 	return(true);
4852       if ((symbol_type(obj) & ~0xffff) != 0)
4853 	return(true);
4854     }
4855 
4856   if ((signed_type(obj) == 0) && ((full_typ & T_GC_MARK) != 0)) return(true);
4857   return(false);
4858 }
4859 
4860 static const char *check_name(s7_scheme *sc, int32_t typ)
4861 {
4862   if ((typ >= 0) && (typ < NUM_TYPES))
4863     {
4864       s7_pointer p;
4865       p = sc->prepackaged_type_names[typ];
4866       if (is_string(p)) return(string_value(p));
4867       fprintf(stderr, "%s fell through: %d\n", __func__, typ);
4868     }
4869   return("unknown type!");
4870 }
4871 
4872 static char *safe_object_to_string(s7_pointer p)
4873 {
4874   uint8_t typ;
4875   char *buf;
4876   typ = unchecked_type(p);
4877   buf = (char *)Malloc(128);
4878   snprintf(buf, 128, "type: %d", typ);
4879   return(buf);
4880 }
4881 
4882 static void complain(const char* complaint, s7_pointer p, const char *func, int line, uint8_t typ)
4883 {
4884   fprintf(stderr, complaint,
4885 	  BOLD_TEXT,
4886 	  func, line, check_name(cur_sc, typ), safe_object_to_string(p),
4887 	  UNBOLD_TEXT);
4888   if (cur_sc->stop_at_error) abort();
4889 }
4890 
4891 static char* show_debugger_bits(s7_pointer obj);
4892 
4893 static s7_pointer check_ref(s7_pointer p, uint8_t expected_type, const char *func, int32_t line, const char *func1, const char *func2)
4894 {
4895   if (!p)
4896     fprintf(stderr, "%s[%d]: null pointer passed to check_ref\n", func, line);
4897   else
4898     {
4899       uint8_t typ;
4900       typ = unchecked_type(p);
4901       if (typ != expected_type)
4902 	{
4903 	  if ((!func1) || (typ != T_FREE))
4904 	    {
4905 	      fprintf(stderr, "%s%s[%d]: not %s, but %s (%s)%s\n",
4906 		      BOLD_TEXT,
4907 		      func, line, check_name(cur_sc, expected_type), check_name(cur_sc, typ), safe_object_to_string(p),
4908 		      UNBOLD_TEXT);
4909 	      if ((typ != T_FREE) && (is_syntactic_pair(p)) && (optimize_op(p) == 0))
4910 		fprintf(stderr, "syn 0: %s[%d]\n", func, line);
4911 	      if (cur_sc->stop_at_error) abort();
4912 	    }
4913 	  else
4914 	    if ((strcmp(func, func1) != 0) &&
4915 		((!func2) || (strcmp(func, func2) != 0)))
4916 	      {
4917 		fprintf(stderr, "%s%s[%d]: free cell, not %s%s\n", BOLD_TEXT, func, line, check_name(cur_sc, expected_type), UNBOLD_TEXT);
4918 		if (cur_sc->stop_at_error) abort();
4919 	      }}}
4920   return(p);
4921 }
4922 
4923 static s7_pointer check_let_ref(s7_pointer p, uint64_t role, const char *func, int32_t line)
4924 {
4925   check_ref(p, T_LET, func, line, NULL, NULL);
4926   if ((p->debugger_bits & L_HIT) == 0) fprintf(stderr, "%s[%d]: let not set\n", func, line);
4927   if ((p->debugger_bits & L_MASK) != role) fprintf(stderr, "%s[%d]: let bad role\n", func, line);
4928   return(p);
4929 }
4930 
4931 static s7_pointer check_let_set(s7_pointer p, uint64_t role, const char *func, int32_t line)
4932 {
4933   check_ref(p, T_LET, func, line, NULL, NULL);
4934   p->debugger_bits &= (~L_MASK);
4935   p->debugger_bits |= (L_HIT | role);
4936   return(p);
4937 }
4938 
4939 static s7_pointer check_ref2(s7_pointer p, uint8_t expected_type, int32_t other_type, const char *func, int32_t line, const char *func1, const char *func2)
4940 {
4941   if (!p)
4942     fprintf(stderr, "%s[%d]: null pointer passed to check_ref2\n", func, line);
4943   else
4944     {
4945       uint8_t typ;
4946       typ = unchecked_type(p);
4947       if ((typ != expected_type) && (typ != other_type))
4948 	return(check_ref(p, expected_type, func, line, func1, func2));
4949     }
4950   return(p);
4951 }
4952 
4953 static s7_pointer check_ref3(s7_pointer p, const char *func, int32_t line)
4954 {
4955   uint8_t typ;
4956   typ = unchecked_type(p);
4957   if ((typ != T_INPUT_PORT) && (typ != T_OUTPUT_PORT) && (typ != T_FREE))
4958     complain("%s%s[%d]: not a port, but %s (%s)%s\n", p, func, line, typ);
4959   return(p);
4960 }
4961 
4962 static s7_pointer check_ref4(s7_pointer p, const char *func, int32_t line)
4963 {
4964   if ((strcmp(func, "sweep") != 0) &&
4965       (strcmp(func, "process_multivector") != 0))
4966     {
4967       uint8_t typ;
4968       typ = unchecked_type(p);
4969       if (!t_vector_p[typ])
4970 	complain("%s%s[%d]: not a vector, but %s (%s)%s\n", p, func, line, typ);
4971     }
4972   return(p);
4973 }
4974 
4975 static s7_pointer check_ref5(s7_pointer p, const char *func, int32_t line)
4976 {
4977   uint8_t typ;
4978   typ = unchecked_type(p);
4979   if (!t_has_closure_let[typ])
4980     complain("%s%s[%d]: not a closure, but %s (%s)%s\n", p, func, line, typ);
4981   return(p);
4982 }
4983 
4984 static s7_pointer check_ref6(s7_pointer p, const char *func, int32_t line)
4985 {
4986   uint8_t typ;
4987   typ = unchecked_type(p);
4988   if (typ < T_C_MACRO)
4989     complain("%s%s[%d]: not a c function, but %s (%s)%s\n", p, func, line, typ);
4990   return(p);
4991 }
4992 
4993 static s7_pointer check_ref7(s7_pointer p, const char *func, int32_t line)
4994 {
4995   uint8_t typ;
4996   typ = unchecked_type(p);
4997   if ((typ < T_INTEGER) || (typ > T_COMPLEX))
4998     complain("%s%s[%d]: not a number, but %s (%s)%s\n", p, func, line, typ);
4999   return(p);
5000 }
5001 
5002 static s7_pointer check_ref8(s7_pointer p, const char *func, int32_t line)
5003 {
5004   uint8_t typ;
5005   typ = unchecked_type(p);
5006   if ((!t_sequence_p[typ]) && (!t_structure_p[typ]) && (!is_any_closure(p))) /* closure as iterator -- see s7test */
5007     complain("%s%s[%d]: not a sequence or structure, but %s (%s)%s\n", p, func, line, typ);
5008   return(p);
5009 }
5010 
5011 static s7_pointer check_ref9(s7_pointer p, const char *func, int32_t line)
5012 {
5013   uint8_t typ;
5014   typ = unchecked_type(p);
5015   if ((typ != T_LET) && (typ != T_C_OBJECT) && (!is_any_closure(p)) && (!is_any_macro(p)) && (typ != T_C_POINTER))
5016     complain("%s%s[%d]: not a possible method holder, but %s (%s)%s\n", p, func, line, typ);
5017   return(p);
5018 }
5019 
5020 static s7_pointer check_ref10(s7_pointer p, const char *func, int32_t line)
5021 {
5022   uint8_t typ;
5023   typ = unchecked_type(p);
5024   if ((typ != T_PAIR) && (typ != T_NIL) && (typ != T_SYMBOL))
5025     complain("%s%s[%d]: arglist is %s (%s)%s?\n", p, func, line, typ);
5026   return(p);
5027 }
5028 
5029 static s7_pointer check_ref11(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
5030 {
5031   uint8_t typ;
5032   typ = unchecked_type(p);
5033   if ((!t_applicable_p[typ]) && (p != sc->F))
5034     complain("%s%s[%d]: applicable object is %s (%s)%s?\n", p, func, line, typ);
5035   return(p);
5036 }
5037 
5038 static s7_pointer check_ref12(s7_pointer p, const char *func, int32_t line)
5039 {
5040   uint8_t typ;
5041   if (is_slot_end(p)) return(p);
5042   typ = unchecked_type(p);
5043   if ((typ != T_SLOT) && (typ != T_NIL)) /* unset slots are nil */
5044     complain("%s%s[%d]: slot is %s (%s)%s?\n", p, func, line, typ);
5045   return(p);
5046 }
5047 
5048 static s7_pointer check_ref13(s7_pointer p, const char *func, int32_t line)
5049 {
5050   uint8_t typ;
5051   typ = unchecked_type(p);
5052   if (!is_any_vector(p))
5053     complain("%s%s[%d]: subvector is %s (%s)%s?\n", p, func, line, typ);
5054   if (!is_subvector(p))
5055     complain("%s%s[%d]: subvector is %s (%s), but not a subvector?%s\n", p, func, line, typ);
5056   return(p);
5057 }
5058 
5059 static s7_pointer check_ref14(s7_pointer p, const char *func, int32_t line)
5060 {
5061   uint8_t typ;
5062   typ = unchecked_type(p);
5063   if ((!is_any_procedure(p)) && (!s7_is_boolean(p)))
5064     complain("%s%s[%d]: procedure setter is %s (%s)%s?\n", p, func, line, typ);
5065   return(p);
5066 }
5067 
5068 static s7_pointer check_ref15(s7_pointer p, const char *func, int32_t line) /* called in mark_let so s7_scheme* for cur_sc is difficult */
5069 {
5070   uint8_t typ;
5071   check_nref(p, func, line);
5072   typ = unchecked_type(p);
5073   if (is_multiple_value(p))
5074     complain("%s%s[%d]: slot value is a multiple-value, %s (%s)%s?\n", p, func, line, typ);
5075   if (has_odd_bits(p))
5076     {char *s; fprintf(stderr, "odd bits: %s\n", s = describe_type_bits(cur_sc, p)); free(s);}
5077   return(p);
5078 }
5079 
5080 static s7_pointer check_ref16(s7_pointer p, const char *func, int32_t line)
5081 {
5082   uint8_t typ;
5083   check_nref(p, func, line);
5084   typ = unchecked_type(p);
5085   if ((typ != T_LET) && (typ != T_NIL))
5086     complain("%s%s[%d]: not a let or nil, but %s (%s)%s\n", p, func, line, typ);
5087   return(p);
5088 }
5089 
5090 static s7_pointer check_ref17(s7_pointer p, const char *func, int32_t line)
5091 {
5092   uint8_t typ;
5093   typ = unchecked_type(p);
5094   if ((!is_any_macro(p)) || (is_c_macro(p)))
5095     complain("%s%s[%d]: macro is %s (%s)%s?\n", p, func, line, typ);
5096   return(p);
5097 }
5098 
5099 static s7_pointer check_cell(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
5100 {
5101   if (!p)
5102     {
5103       fprintf(stderr, "%s%s[%d]: null pointer!%s\n", BOLD_TEXT, func, line, UNBOLD_TEXT);
5104       if (sc->stop_at_error) abort();
5105     }
5106   else
5107     {
5108       uint8_t typ;
5109       typ = unchecked_type(p);
5110       if (typ >= NUM_TYPES)
5111 	{
5112 	  fprintf(stderr, "%s%s[%d]: attempt to use messed up cell (type: %d)%s\n", BOLD_TEXT, func, line, typ, UNBOLD_TEXT);
5113 	  if (sc->stop_at_error) abort();
5114 	}}
5115   return(p);
5116 }
5117 
5118 static void print_gc_info(s7_scheme *sc, s7_pointer obj, int32_t line)
5119 {
5120   if (!obj)
5121     fprintf(stderr, "[%d]: obj is %p\n", line, obj);
5122   else
5123     {
5124       if (unchecked_type(obj) != T_FREE)
5125 	fprintf(stderr, "[%d]: %p type is %d?\n", line, obj, unchecked_type(obj));
5126       else
5127 	{
5128 	  s7_int free_type;
5129 	  char *bits;
5130 	  char fline[128];
5131 	  free_type = full_type(obj);
5132 	  full_type(obj) = obj->current_alloc_type;
5133 	  printing_gc_info = true;
5134 	  bits = describe_type_bits(sc, obj); /* this func called in type macro */
5135 	  printing_gc_info = false;
5136 	  full_type(obj) = free_type;
5137 	  if (obj->explicit_free_line > 0)
5138 	    snprintf(fline, 128, ", freed at %d, ", obj->explicit_free_line);
5139 	  fprintf(stderr, "%s%p is free (line %d, alloc type: %s %" print_s7_int " #x%" PRIx64 " (%s)), current: %s[%d], previous: %s[%d], %sgc: %s[%d]%s\n",
5140 		  BOLD_TEXT,
5141 		  obj, line,
5142 		  s7_type_names[obj->current_alloc_type & 0xff], obj->current_alloc_type, obj->current_alloc_type,
5143 		  bits,
5144 		  obj->current_alloc_func, obj->current_alloc_line,
5145 		  obj->previous_alloc_func, obj->previous_alloc_line,
5146 		  (obj->explicit_free_line > 0) ? fline : "",
5147 		  obj->gc_func, obj->gc_line,
5148 		  UNBOLD_TEXT);
5149 	  free(bits);
5150 	}}
5151   if (sc->stop_at_error) abort();
5152 }
5153 
5154 static s7_pointer check_nref(s7_pointer p, const char *func, int32_t line)
5155 {
5156   uint8_t typ;
5157   check_cell(cur_sc, p, func, line);
5158   typ = unchecked_type(p);
5159   if (typ == T_FREE)
5160     {
5161       fprintf(stderr, "%s%s[%d]: attempt to use free cell%s\n", BOLD_TEXT, func, line, UNBOLD_TEXT);
5162       print_gc_info(cur_sc, p, line);
5163     }
5164   return(p);
5165 }
5166 
5167 static const char *opt1_role_name(uint64_t role)
5168 {
5169   if (role == OPT1_FAST) return("opt1_fast");
5170   if (role == OPT1_CFUNC) return("opt1_cfunc");
5171   if (role == OPT1_LAMBDA) return("opt_lambda");
5172   if (role == OPT1_CLAUSE) return("opt1_clause");
5173   if (role == OPT1_GOTO) return("opt1_goto");
5174   if (role == OPT1_SYM) return("opt1_sym");
5175   if (role == OPT1_PAIR) return("opt1_pair");
5176   if (role == OPT1_CON) return("opt1_con");
5177   if (role == OPT1_ANY) return("opt1_any");
5178   return((role == OPT1_HASH) ? "opt1_hash" : "opt1_unknown");
5179 }
5180 
5181 static const char *opt2_role_name(uint64_t role)
5182 {
5183   if (role == OPT2_FX) return("opt2_fx");
5184   if (role == OPT2_FN) return("opt2_fn");
5185   if (role == OPT2_KEY) return("opt2_any");
5186   if (role == OPT2_SLOW) return("opt2_slow");
5187   if (role == OPT2_SYM) return("opt2_sym");
5188   if (role == OPT2_PAIR) return("opt2_pair");
5189   if (role == OPT2_CON) return("opt2_con");
5190   if (role == OPT2_LAMBDA) return("opt2_lambda");
5191   if (role == OPT2_DIRECT) return("opt2_direct");
5192   if (role == OPT2_INT) return("opt2_int");
5193   return((role == OPT2_NAME) ? "opt2_raw_name" : "opt2_unknown");
5194 }
5195 
5196 static const char *opt3_role_name(uint64_t role)
5197 {
5198   if (role == OPT3_ARGLEN) return("opt3_arglen");
5199   if (role == OPT3_SYM) return("opt3_sym");
5200   if (role == OPT3_CON) return("opt3_con");
5201   if (role == OPT3_AND) return("opt3_pair");
5202   if (role == OPT3_ANY) return("opt3_any");
5203   if (role == OPT3_LET) return("opt3_let");
5204   if (role == OPT3_BYTE) return("opt3_byte");
5205   if (role == OPT3_DIRECT) return("direct_opt3");
5206   if (role == OPT3_LEN) return("opt3_len");
5207   if (role == OPT3_INT) return("opt3_int");
5208   return((role == OPT3_LOCATION) ? "opt3_location" : "opt3_unknown");
5209 }
5210 
5211 static char* show_debugger_bits(s7_pointer p)
5212 {
5213   char *bits_str;
5214   int64_t bits;
5215   bits = p->debugger_bits;
5216   bits_str = (char *)Malloc(512);
5217   snprintf(bits_str, 512, " %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
5218 	   ((bits & OPT1_SET) != 0) ? " opt1_set" : "",
5219 	   ((bits & OPT1_FAST) != 0) ? " opt1_fast" : "",
5220 	   ((bits & OPT1_CFUNC) != 0) ? " opt1_cfunc" : "",
5221 	   ((bits & OPT1_CLAUSE) != 0) ? " opt1_clause" : "",
5222 	   ((bits & OPT1_LAMBDA) != 0) ? " opt_lambda" : "",
5223 	   ((bits & OPT1_SYM) != 0) ? " opt1_sym" : "",
5224 	   ((bits & OPT1_PAIR) != 0) ? " opt1_pair" : "",
5225 	   ((bits & OPT1_CON) != 0) ? " opt1_con" : "",
5226 	   ((bits & OPT1_GOTO) != 0) ? " opt1_goto" : "",
5227 	   ((bits & OPT1_ANY) != 0) ? " opt1_any" : "",
5228 	   ((bits & OPT1_HASH) != 0) ? " opt1_raw_hash" : "",
5229 
5230 	   ((bits & OPT2_SET) != 0) ? " opt2_set" : "",
5231 	   ((bits & OPT2_KEY) != 0) ? " opt2_any" : "",
5232 	   ((bits & OPT2_SLOW) != 0) ? " opt2_slow" : "",
5233 	   ((bits & OPT2_SYM) != 0) ? " opt2_sym" : "",
5234 	   ((bits & OPT2_PAIR) != 0) ? " opt2_pair" : "",
5235 	   ((bits & OPT2_CON) != 0) ? " opt2_con" : "",
5236 	   ((bits & OPT2_FX) != 0) ? " opt2_fx" : "",
5237 	   ((bits & OPT2_FN) != 0) ? " opt2_fn" : "",
5238 	   ((bits & OPT2_LAMBDA) != 0) ? " opt2_lambda" : "",
5239 	   ((bits & OPT2_DIRECT) != 0) ? " opt2_direct" : "",
5240 	   ((bits & OPT2_NAME) != 0) ? " opt2_raw_name" : "",
5241 	   ((bits & OPT2_INT) != 0) ? " opt2_int" : "",
5242 
5243 	   ((bits & OPT3_SET) != 0) ? " opt3_set" : "",
5244 	   ((bits & OPT3_ARGLEN) != 0) ? " opt3_arglen" : "",
5245 	   ((bits & OPT3_SYM) != 0) ? " opt3_sym" : "",
5246 	   ((bits & OPT3_CON) != 0) ? " opt3_con" : "",
5247 	   ((bits & OPT3_AND) != 0) ? " opt3_pair " : "",
5248 	   ((bits & OPT3_ANY) != 0) ? " opt3_any " : "",
5249 	   ((bits & OPT3_LET) != 0) ? " opt3_let " : "",
5250 	   ((bits & OPT3_BYTE) != 0) ? " opt3_byte " : "",
5251 	   ((bits & OPT3_DIRECT) != 0) ? " opt3_direct" : "",
5252 	   ((bits & OPT3_LOCATION) != 0) ? " opt3_location" : "",
5253 	   ((bits & OPT3_LEN) != 0) ? " opt3_len" : "",
5254 	   ((bits & OPT3_INT) != 0) ? " opt3_int" : "",
5255 
5256 	   ((bits & L_HIT) != 0) ? " let_set" : "",
5257 	   ((bits & L_FUNC) != 0) ? " let_func" : "",
5258 	   ((bits & L_DOX) != 0) ? " let_dox" : "",
5259 	   ((bits & L_CATCH) != 0) ? " let_catch" : "");
5260   return(bits_str);
5261 }
5262 
5263 static void show_opt1_bits(s7_pointer p, const char *func, int32_t line, uint64_t role)
5264 {
5265   char *bits;
5266   bits = show_debugger_bits(p);
5267   fprintf(stderr, "%s%s[%d]%s: opt1: %p->%p wants %s, debugger bits are %" PRIx64 "%s but expects %lx",
5268 	  BOLD_TEXT,
5269 	  func, line,
5270 	  UNBOLD_TEXT,
5271 	  p, p->object.cons.opt1,
5272 	  opt1_role_name(role),
5273 	  p->debugger_bits, bits, role);
5274   free(bits);
5275 }
5276 
5277 static s7_pointer opt1_1(s7_scheme *sc, s7_pointer p, uint64_t role, const char *func, int32_t line)
5278 {
5279   if ((!opt1_is_set(p)) ||
5280       ((!opt1_role_matches(p, role)) &&
5281        (role != OPT1_ANY)))
5282     {
5283       show_opt1_bits(p, func, line, role);
5284       if (sc->stop_at_error) abort();
5285     }
5286   return(p->object.cons.opt1);
5287 }
5288 
5289 static void base_opt1(s7_pointer p, uint64_t role)
5290 {
5291   set_opt1_role(p, role);
5292   set_opt1_is_set(p);
5293 }
5294 
5295 static s7_pointer set_opt1_1(s7_pointer p, s7_pointer x, uint64_t role)
5296 {
5297   /* if ((opt1_role_matches(p, OPT1_LAMBDA)) && (role != OPT1_LAMBDA)) fprintf(stderr, "reset opt1_lambda to %s\n", opt1_role_name(role)); */
5298   p->object.cons.opt1 = x;
5299   base_opt1(p, role);
5300   return(x);
5301 }
5302 
5303 static uint64_t opt1_hash_1(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
5304 {
5305   if ((!opt1_is_set(p)) ||
5306       (!opt1_role_matches(p, OPT1_HASH)))
5307     {
5308       show_opt1_bits(p, func, line, (uint64_t)OPT1_HASH);
5309       if (sc->stop_at_error) abort();
5310     }
5311   return(p->object.sym_cons.hash);
5312 }
5313 
5314 static void set_opt1_hash_1(s7_pointer p, uint64_t x)
5315 {
5316   p->object.sym_cons.hash = x;
5317   base_opt1(p, OPT1_HASH);
5318 }
5319 
5320 static void show_opt2_bits(s7_pointer p, const char *func, int32_t line, uint64_t role)
5321 {
5322   char *bits;
5323   bits = show_debugger_bits(p);
5324   fprintf(stderr, "%s%s[%d]%s: opt2: %p->%p wants %s, debugger bits are %" PRIx64 "%s but expects %lx %s",
5325 	  BOLD_TEXT,
5326 	  func, line,
5327 	  UNBOLD_TEXT,
5328 	  p, p->object.cons.opt2,
5329 	  opt2_role_name(role),
5330 	  p->debugger_bits, bits, role,
5331 	  opt2_role_name(role));
5332   free(bits);
5333 }
5334 
5335 static bool f_call_func_mismatch(const char *func)
5336 {
5337   return((!safe_strcmp(func, "check_and")) &&  /* these reflect set_fx|unchecked where the destination checks for null fx_proc */
5338 	 (!safe_strcmp(func, "check_or")) &&
5339 	 (!safe_strcmp(func, "eval")) &&
5340 	 (!safe_strcmp(func, "set_any_c_fp")) &&
5341 	 (!safe_strcmp(func, "set_any_closure_fp")) &&
5342 	 (!safe_strcmp(func, "optimize_func_two_args")) &&
5343 	 (!safe_strcmp(func, "optimize_func_many_args")) &&
5344 	 (!safe_strcmp(func, "optimize_func_three_args")) &&
5345 	 (!safe_strcmp(func, "fx_c_ff")) &&
5346 	 (!safe_strcmp(func, "op_map_fa")));
5347 }
5348 
5349 static s7_pointer opt2_1(s7_scheme *sc, s7_pointer p, uint64_t role, const char *func, int32_t line)
5350 {
5351   if ((!opt2_is_set(p)) ||
5352       (!opt2_role_matches(p, role)))
5353     {
5354       show_opt2_bits(p, func, line, role);
5355       if (sc->stop_at_error) abort();
5356     }
5357   return(p->object.cons.opt2);
5358 }
5359 
5360 static void base_opt2(s7_pointer p, uint64_t role)
5361 {
5362   set_opt2_role(p, role);
5363   set_opt2_is_set(p);
5364 }
5365 
5366 static void set_opt2_1(s7_scheme *sc, s7_pointer p, s7_pointer x, uint64_t role, const char *func, int32_t line)
5367 {
5368   if ((role == OPT2_FX) &&
5369       (x == NULL) &&
5370       (f_call_func_mismatch(func)))
5371     fprintf(stderr, "%s[%d]: set fx_proc for %s to null (%s%s%s)\n", func, line,
5372 	    string_value(object_to_truncated_string(sc, p, 80)),
5373 	    ((is_h_optimized(car(p))) && (is_safe_c_op(optimize_op(car(p))))) ? BOLD_TEXT : "",
5374 	    op_names[optimize_op(car(p))],
5375 	    ((is_h_optimized(car(p))) && (is_safe_c_op(optimize_op(car(p))))) ? UNBOLD_TEXT : "");
5376 
5377   if ((role != OPT2_FX) && (role != OPT2_DIRECT) && (has_fx(p))) /* sometimes opt2_direct just specializes fx */
5378     fprintf(stderr, "%s[%d]: overwrite has_fx: %s %s\n", func, line, opt2_role_name(role), display_80(p));
5379   p->object.cons.opt2 = x;
5380   base_opt2(p, role);
5381 }
5382 
5383 static const char *opt2_name_1(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
5384 {
5385   if ((!opt2_is_set(p)) ||
5386       (!opt2_role_matches(p, OPT2_NAME)))
5387     {
5388       show_opt2_bits(p, func, line, (uint64_t)OPT2_NAME);
5389       if (sc->stop_at_error) abort();
5390     }
5391   return(p->object.sym_cons.fstr);
5392 }
5393 
5394 static void set_opt2_name_1(s7_pointer p, const char *str)
5395 {
5396   p->object.sym_cons.fstr = str;
5397   base_opt2(p, OPT2_NAME);
5398 }
5399 
5400 static void show_opt3_bits(s7_pointer p, const char *func, int32_t line, uint64_t role)
5401 {
5402   char *bits;
5403   bits = show_debugger_bits(p);
5404   fprintf(stderr, "%s%s[%d]%s: opt3: %s %" PRIx64 "%s", BOLD_TEXT, func, line, UNBOLD_TEXT, opt3_role_name(role), p->debugger_bits, bits);
5405   free(bits);
5406 }
5407 
5408 static void check_opt3_bits(s7_scheme *sc, s7_pointer p, uint64_t role, const char *func, int32_t line)
5409 {
5410   if ((!opt3_is_set(p)) ||
5411       (!opt3_role_matches(p, role)))
5412     {
5413       show_opt3_bits(p, func, line, role);
5414       if (sc->stop_at_error) abort();
5415     }
5416 }
5417 
5418 static s7_pointer opt3_1(s7_scheme *sc, s7_pointer p, uint64_t role, const char *func, int32_t line)
5419 {
5420   check_opt3_bits(sc, p, role, func, line);
5421   return(p->object.cons.opt3);
5422 }
5423 
5424 static void base_opt3(s7_pointer p, uint64_t role)
5425 {
5426   set_opt3_role(p, role);
5427   set_opt3_is_set(p);
5428 }
5429 
5430 static void set_opt3_1(s7_pointer p, s7_pointer x, uint64_t role)
5431 {
5432   clear_type_bit(p, T_LOCATION);
5433   p->object.cons.opt3 = x;
5434   base_opt3(p, role);
5435 }
5436 
5437 static uint8_t opt3_byte_1(s7_scheme *sc, s7_pointer p, uint64_t role, const char *func, int32_t line)
5438 {
5439   check_opt3_bits(sc, p, role, func, line);
5440   return(p->object.cons_ext.opt_type);
5441 }
5442 
5443 static void set_opt3_byte_1(s7_pointer p, uint8_t x, uint64_t role, const char *func, int32_t line)
5444 {
5445   clear_type_bit(p, T_LOCATION);
5446   p->object.cons_ext.opt_type = x;
5447   base_opt3(p, role);
5448 }
5449 
5450 static uint64_t opt3_location_1(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
5451 {
5452   if ((!opt3_is_set(p)) ||
5453       ((p->debugger_bits & OPT3_LOCATION) == 0) ||
5454       (!has_location(p)))
5455     {
5456       show_opt3_bits(p, func, line, (uint64_t)OPT3_LOCATION);
5457       if (sc->stop_at_error) abort();
5458     }
5459   return(p->object.sym_cons.location);
5460 
5461 }
5462 
5463 static void set_opt3_location_1(s7_pointer p, uint64_t x)
5464 {
5465   p->object.sym_cons.location = x;
5466   (p)->debugger_bits = (OPT3_LOCATION | (p->debugger_bits & ~OPT3_LEN)); /* turn on line, cancel len */
5467   set_opt3_is_set(p);
5468 }
5469 
5470 static uint64_t opt3_len_1(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
5471 {
5472   if ((!opt3_is_set(p)) ||
5473       ((p->debugger_bits & OPT3_LEN) == 0) ||
5474       (has_location(p)))
5475     {
5476       show_opt3_bits(p, func, line, (uint64_t)OPT3_LEN);
5477       if (sc->stop_at_error) abort();
5478     }
5479   return(p->object.sym_cons.location);
5480 }
5481 
5482 static void set_opt3_len_1(s7_pointer p, uint64_t x)
5483 {
5484   clear_type_bit(p, T_LOCATION);
5485   p->object.sym_cons.location = x;
5486   (p)->debugger_bits = (OPT3_LEN | (p->debugger_bits & ~(OPT3_LOCATION)));
5487   set_opt3_is_set(p);
5488 }
5489 
5490 static void print_debugging_state(s7_scheme *sc, s7_pointer obj, s7_pointer port)
5491 {
5492   /* show current state, current allocated state, and previous allocated state */
5493   char *current_bits, *allocated_bits, *previous_bits, *str;
5494   int64_t save_full_type;
5495   s7_int len, nlen;
5496   const char *excl_name;
5497   block_t *b;
5498 
5499   excl_name = (is_free(obj)) ? "free cell!" : "unknown object!";
5500   current_bits = describe_type_bits(sc, obj);
5501   save_full_type = full_type(obj);
5502   full_type(obj) = obj->current_alloc_type;
5503   allocated_bits = describe_type_bits(sc, obj);
5504   full_type(obj) = obj->previous_alloc_type;
5505   previous_bits = describe_type_bits(sc, obj);
5506   full_type(obj) = save_full_type;
5507 
5508   len = safe_strlen(excl_name) +
5509     safe_strlen(current_bits) + safe_strlen(allocated_bits) + safe_strlen(previous_bits) +
5510     safe_strlen(obj->previous_alloc_func) + safe_strlen(obj->current_alloc_func) + 512;
5511 
5512   b = mallocate(sc, len);
5513   str = (char *)block_data(b);
5514   nlen = snprintf(str, len,
5515 		  "\n<%s %s,\n  current: %s[%d] %s,\n  previous: %s[%d] %s\n  %d uses>",
5516 		  excl_name, current_bits,
5517 		  obj->current_alloc_func, obj->current_alloc_line, allocated_bits,
5518 		  obj->previous_alloc_func, obj->previous_alloc_line, previous_bits,
5519 		  obj->uses);
5520   free(current_bits);
5521   free(allocated_bits);
5522   free(previous_bits);
5523   if (is_null(port))
5524     fprintf(stderr, "%p: %s\n", obj, str);
5525   else port_write_string(port)(sc, str, nlen, port);
5526   liberate(sc, b);
5527 }
5528 
5529 static s7_pointer symbol_to_local_slot(s7_scheme *sc, s7_pointer symbol, s7_pointer e);
5530 static s7_pointer check_null_sym(s7_scheme *sc, s7_pointer p, s7_pointer sym, int32_t line, const char *func)
5531 {
5532   if (!p)
5533     {
5534       s7_pointer slot;
5535       char *s;
5536       fprintf(stderr, "%s%s[%d]: %s unbound%s\n", BOLD_TEXT, func, line, symbol_name(sym), UNBOLD_TEXT);
5537       fprintf(stderr, "  symbol_id: %" print_s7_int ", let_id: %" print_s7_int ", bits: %s", symbol_id(sym), let_id(sc->curlet), s = describe_type_bits(sc, sym));
5538       free(s);
5539       slot = symbol_to_local_slot(sc, sym, sc->curlet);
5540       if (is_slot(slot)) fprintf(stderr, ", slot: %s", display(slot));
5541       fprintf(stderr, "\n");
5542       if (sc->stop_at_error) abort();
5543     }
5544   return(p);
5545 }
5546 #endif /* S7_DEBUGGING */
5547 /* -------------------------------- end internal debugging apparatus -------------------------------- */
5548 
5549 
5550 static s7_pointer set_elist_1(s7_scheme *sc, s7_pointer x1)
5551 {
5552   set_car(sc->elist_1, x1);
5553   return(sc->elist_1);
5554 }
5555 
5556 static s7_pointer set_elist_2(s7_scheme *sc, s7_pointer x1, s7_pointer x2)
5557 {
5558   set_car(sc->elist_2, x1);
5559   set_cadr(sc->elist_2, x2);
5560   return(sc->elist_2);
5561 }
5562 
5563 static s7_pointer set_elist_3(s7_scheme *sc, s7_pointer x1, s7_pointer x2, s7_pointer x3)
5564 {
5565   s7_pointer p;
5566   p = sc->elist_3;
5567   set_car(p, x1); p = cdr(p);
5568   set_car(p, x2); p = cdr(p);
5569   set_car(p, x3);
5570   return(sc->elist_3);
5571 }
5572 
5573 static s7_pointer set_elist_4(s7_scheme *sc, s7_pointer x1, s7_pointer x2, s7_pointer x3, s7_pointer x4)
5574 {
5575   s7_pointer p;
5576   p = sc->elist_4;
5577   set_car(p, x1); p = cdr(p);
5578   set_car(p, x2); p = cdr(p);
5579   set_car(p, x3); p = cdr(p);
5580   set_car(p, x4);
5581   return(sc->elist_4);
5582 }
5583 
5584 static s7_pointer set_elist_5(s7_scheme *sc, s7_pointer x1, s7_pointer x2, s7_pointer x3, s7_pointer x4, s7_pointer x5)
5585 {
5586   s7_pointer p;
5587   p = sc->elist_5;
5588   set_car(p, x1); p = cdr(p);
5589   set_car(p, x2); p = cdr(p);
5590   set_car(p, x3); p = cdr(p);
5591   set_car(p, x4); p = cdr(p);
5592   set_car(p, x5);
5593   return(sc->elist_5);
5594 }
5595 
5596 static s7_pointer set_wlist_3(s7_pointer lst, s7_pointer x1, s7_pointer x2, s7_pointer x3)
5597 {
5598   s7_pointer p;
5599   p = lst;
5600   set_car(p, x1); p = cdr(p);
5601   set_car(p, x2); p = cdr(p);
5602   set_car(p, x3);
5603   return(lst);
5604 }
5605 
5606 static s7_pointer set_wlist_4(s7_pointer lst, s7_pointer x1, s7_pointer x2, s7_pointer x3, s7_pointer x4)
5607 {
5608   s7_pointer p;
5609   p = lst;
5610   set_car(p, x1); p = cdr(p);
5611   set_car(p, x2); p = cdr(p);
5612   set_car(p, x3); p = cdr(p);
5613   set_car(p, x4);
5614   return(lst);
5615 }
5616 
5617 static s7_pointer set_plist_1(s7_scheme *sc, s7_pointer x1)
5618 {
5619   set_car(sc->plist_1, x1);
5620   return(sc->plist_1);
5621 }
5622 
5623 static s7_pointer set_plist_2(s7_scheme *sc, s7_pointer x1, s7_pointer x2)
5624 {
5625   set_car(sc->plist_2, x1);
5626   set_car(sc->plist_2_2, x2);
5627   return(sc->plist_2);
5628 }
5629 
5630 static s7_pointer set_plist_3(s7_scheme *sc, s7_pointer x1, s7_pointer x2, s7_pointer x3)
5631 {
5632   return(set_wlist_3(sc->plist_3, x1, x2, x3));
5633 }
5634 
5635 static s7_pointer set_qlist_2(s7_scheme *sc, s7_pointer x1, s7_pointer x2)
5636 {
5637   set_car(sc->qlist_2, x1);
5638   set_cadr(sc->qlist_2, x2);
5639   return(sc->qlist_2);
5640 }
5641 
5642 static s7_pointer set_qlist_3(s7_scheme *sc, s7_pointer x1, s7_pointer x2, s7_pointer x3)
5643 {
5644   set_car(sc->qlist_3, x1);
5645   set_cadr(sc->qlist_3, x2);
5646   set_caddr(sc->qlist_3, x3);
5647   return(sc->qlist_3);
5648 }
5649 
5650 static s7_pointer set_clist_1(s7_scheme *sc, s7_pointer x1) /* for c_object length method */
5651 {
5652   set_car(sc->clist_1, x1);
5653   return(sc->clist_1);
5654 }
5655 
5656 static s7_pointer set_ulist_1(s7_scheme *sc, s7_pointer x1, s7_pointer x2)
5657 {
5658   set_car(sc->u1_1, x1);
5659   set_cdr(sc->u1_1, x2);
5660   return(sc->u1_1);
5661 }
5662 
5663 static int32_t position_of(s7_pointer p, s7_pointer args)
5664 {
5665   int32_t i;
5666   for (i = 1; p != args; i++, args = cdr(args));
5667   return(i);
5668 }
5669 
5670 #define call_method(Sc, Obj, Method, Args) s7_apply_function(Sc, Method, Args)
5671 
5672 s7_pointer s7_method(s7_scheme *sc, s7_pointer obj, s7_pointer method)
5673 {
5674   if (has_active_methods(sc, obj))
5675     return(find_method_with_let(sc, obj, method));
5676   return(sc->undefined);
5677 }
5678 
5679 /* if a method is shadowing a built-in like abs, it should expect the same args as abs and behave the same -- no multiple values etc. */
5680 #define check_method(Sc, Obj, Method, Args)		\
5681   {							\
5682     s7_pointer func;					\
5683     if ((has_active_methods(Sc, Obj)) &&				\
5684 	((func = find_method_with_let(Sc, Obj, Method)) != Sc->undefined)) \
5685       return(call_method(Sc, Obj, func, Args)); \
5686   }
5687 
5688 static s7_pointer apply_boolean_method(s7_scheme *sc, s7_pointer obj, s7_pointer method)
5689 {
5690   s7_pointer func;
5691   func = find_method_with_let(sc, obj, method);
5692   if (func == sc->undefined) return(sc->F);
5693   return(call_method(sc, obj, func, set_plist_1(sc, obj)));
5694 }
5695 
5696 static s7_pointer missing_method_error(s7_scheme *sc, s7_pointer method, s7_pointer obj)
5697 {
5698   return(s7_error(sc, sc->missing_method_symbol, set_elist_3(sc, missing_method_string, method, obj)));
5699 }
5700 
5701 #define check_boolean_method(Sc, Checker, Method, Args)	       \
5702   {							       \
5703     s7_pointer p;					       \
5704     p = car(Args);					       \
5705     if (Checker(p)) return(Sc->T);			       \
5706     if (!has_active_methods(Sc, p)) return(Sc->F);	       \
5707     return(apply_boolean_method(Sc, p, Method));	       \
5708   }
5709 
5710 static s7_pointer find_and_apply_method(s7_scheme *sc, s7_pointer obj, s7_pointer sym, s7_pointer args)
5711 {
5712   s7_pointer func;
5713   func = find_method_with_let(sc, obj, sym);
5714   if (func != sc->undefined)
5715     return(call_method(sc, obj, func, args));
5716   return(missing_method_error(sc, sym, obj));
5717 }
5718 
5719 static s7_pointer method_or_bust(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer args, uint8_t typ, int32_t num)
5720 {
5721   if (has_active_methods(sc, obj))
5722     return(find_and_apply_method(sc, obj, method, args));
5723   return(wrong_type_argument(sc, method, num, obj, typ));
5724 }
5725 
5726 static s7_pointer method_or_bust_p(s7_scheme *sc, s7_pointer obj, s7_pointer method, uint8_t typ)
5727 {
5728   if (has_active_methods(sc, obj))
5729     return(find_and_apply_method(sc, obj, method, set_plist_1(sc, obj)));
5730   return(wrong_type_argument(sc, method, 1, obj, typ));
5731 }
5732 
5733 static s7_pointer method_or_bust_pp(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer x1, s7_pointer x2, uint8_t typ, int32_t num)
5734 {
5735   if (has_active_methods(sc, obj))
5736     return(find_and_apply_method(sc, obj, method, set_plist_2(sc, x1, x2)));
5737   return(wrong_type_argument(sc, method, num, obj, typ));
5738 }
5739 
5740 static s7_pointer method_or_bust_ppp(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer x1, s7_pointer x2, s7_pointer x3, uint8_t typ, int32_t num)
5741 {
5742   if (has_active_methods(sc, obj))
5743     return(find_and_apply_method(sc, obj, method, set_plist_3(sc, x1, x2, x3)));
5744   return(wrong_type_argument(sc, method, num, obj, typ));
5745 }
5746 
5747 static s7_pointer immutable_object_error(s7_scheme *sc, s7_pointer info) {return(s7_error(sc, sc->immutable_error_symbol, info));}
5748 
5749 static s7_pointer mutable_method_or_bust(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer args, uint8_t typ, int32_t num)
5750 {
5751   if (has_active_methods(sc, obj))
5752     return(find_and_apply_method(sc, obj, method, args));
5753   if (type(obj) != typ)
5754     return(wrong_type_argument(sc, method, num, obj, typ));
5755   if (is_immutable(obj))
5756     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, method, obj)));
5757   return(wrong_type_argument(sc, method, num, obj, typ));
5758 }
5759 
5760 static s7_pointer mutable_method_or_bust_ppp(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer x1, s7_pointer x2, s7_pointer x3, uint8_t typ, int32_t num)
5761 {
5762   return(mutable_method_or_bust(sc, obj, method, set_plist_3(sc, x1, x2, x3), typ, num));
5763 }
5764 
5765 static s7_pointer method_or_bust_one_arg(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer args, uint8_t typ)
5766 {
5767   if (has_active_methods(sc, obj))
5768     return(find_and_apply_method(sc, obj, method, args));
5769   return(simple_wrong_type_argument(sc, method, obj, typ));
5770 }
5771 
5772 static s7_pointer method_or_bust_one_arg_p(s7_scheme *sc, s7_pointer obj, s7_pointer method, uint8_t typ)
5773 {
5774   if (has_active_methods(sc, obj))
5775     return(find_and_apply_method(sc, obj, method, set_plist_1(sc, obj)));
5776   return(simple_wrong_type_argument(sc, method, obj, typ));
5777 }
5778 
5779 static s7_pointer method_or_bust_with_type(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer args, s7_pointer typ, int32_t num)
5780 {
5781   if (has_active_methods(sc, obj))
5782     return(find_and_apply_method(sc, obj, method, args));
5783   return(wrong_type_argument_with_type(sc, method, num, obj, typ));
5784 }
5785 
5786 static s7_pointer method_or_bust_with_type_pp(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer x1, s7_pointer x2, s7_pointer typ, int32_t num)
5787 {
5788   if (has_active_methods(sc, obj))
5789     return(find_and_apply_method(sc, obj, method, set_plist_2(sc, x1, x2)));
5790   return(wrong_type_argument_with_type(sc, method, num, obj, typ));
5791 }
5792 
5793 static s7_pointer method_or_bust_with_type_pi(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer x1, s7_int x2, s7_pointer typ)
5794 {
5795   if (has_active_methods(sc, obj))
5796     return(find_and_apply_method(sc, obj, method, set_plist_2(sc, x1, make_integer(sc, x2))));
5797   return(wrong_type_argument_with_type(sc, method, 1, obj, typ));
5798 }
5799 
5800 static s7_pointer method_or_bust_with_type_pf(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer x1, s7_double x2, s7_pointer typ)
5801 {
5802   if (has_active_methods(sc, obj))
5803     return(find_and_apply_method(sc, obj, method, set_plist_2(sc, x1, make_real(sc, x2))));
5804   return(wrong_type_argument_with_type(sc, method, 1, obj, typ));
5805 }
5806 
5807 static s7_pointer method_or_bust_with_type_one_arg(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer args, s7_pointer typ)
5808 {
5809   if (has_active_methods(sc, obj))
5810     return(find_and_apply_method(sc, obj, method, args));
5811   return(simple_wrong_type_argument_with_type(sc, method, obj, typ));
5812 }
5813 
5814 static s7_pointer method_or_bust_with_type_one_arg_p(s7_scheme *sc, s7_pointer obj, s7_pointer method, s7_pointer typ)
5815 {
5816   if (has_active_methods(sc, obj))
5817     return(find_and_apply_method(sc, obj, method, set_plist_1(sc, obj)));
5818   return(simple_wrong_type_argument_with_type(sc, method, obj, typ));
5819 }
5820 
5821 #define eval_error_any(Sc, ErrType, ErrMsg, Len, Obj) s7_error(Sc, ErrType, set_elist_2(Sc, wrap_string(Sc, ErrMsg, Len), Obj))
5822 #define eval_error(Sc, ErrMsg, Len, Obj) eval_error_any(Sc, Sc->syntax_error_symbol, ErrMsg, Len, Obj)
5823 #define eval_error_with_caller(Sc, ErrMsg, Len, Caller, Obj) s7_error(Sc, Sc->syntax_error_symbol, set_elist_3(Sc, wrap_string(Sc, ErrMsg, Len), Caller, Obj))
5824 #define eval_error_with_caller2(Sc, ErrMsg, Len, Caller, Name, Obj) s7_error(Sc, Sc->syntax_error_symbol, set_elist_4(Sc, wrap_string(Sc, ErrMsg, Len), Caller, Name, Obj))
5825 
5826 
5827 /* -------------------------------- constants -------------------------------- */
5828 
5829 /* #f and #t */
5830 s7_pointer s7_f(s7_scheme *sc) {return(sc->F);}
5831 s7_pointer s7_t(s7_scheme *sc) {return(sc->T);}
5832 
5833 /* () */
5834 s7_pointer s7_nil(s7_scheme *sc)             {return(sc->nil);}
5835 bool s7_is_null(s7_scheme *sc, s7_pointer p) {return(is_null(p));}
5836 static bool is_null_b(s7_pointer p)          {return(type(p) == T_NIL);}
5837 
5838 /* #<undefined> and #<unspecified> */
5839 s7_pointer s7_undefined(s7_scheme *sc)       {return(sc->undefined);}
5840 s7_pointer s7_unspecified(s7_scheme *sc)     {return(sc->unspecified);}
5841 bool s7_is_unspecified(s7_scheme *sc, s7_pointer val) {return(is_unspecified(val));}
5842 
5843 static s7_pointer g_is_undefined(s7_scheme *sc, s7_pointer args)
5844 {
5845   #define H_is_undefined "(undefined? val) returns #t if val is #<undefined> or its reader equivalent"
5846   #define Q_is_undefined sc->pl_bt
5847   check_boolean_method(sc, is_undefined, sc->is_undefined_symbol, args);
5848 }
5849 
5850 static s7_pointer g_is_unspecified(s7_scheme *sc, s7_pointer args)
5851 {
5852   #define H_is_unspecified "(unspecified? val) returns #t if val is #<unspecified>"
5853   #define Q_is_unspecified sc->pl_bt
5854   check_boolean_method(sc, is_unspecified, sc->is_unspecified_symbol, args);
5855 }
5856 
5857 
5858 /* -------------------------------- eof-object? -------------------------------- */
5859 s7_pointer eof_object = NULL;          /* #<eof> -- a character, an entry in the chars array, so not a part of sc */
5860 
5861 s7_pointer s7_eof_object(s7_scheme *sc) {return(eof_object);}
5862 
5863 static s7_pointer g_is_eof_object(s7_scheme *sc, s7_pointer args)
5864 {
5865   #define H_is_eof_object "(eof-object? val) returns #t if val is the end-of-file object"
5866   #define Q_is_eof_object sc->pl_bt
5867   check_boolean_method(sc, is_eof, sc->is_eof_object_symbol, args);
5868 }
5869 
5870 static bool s7_is_eof_object(s7_pointer p) {return(p == eof_object);}
5871 
5872 
5873 /* -------------------------------- not -------------------------------- */
5874 static s7_pointer g_not(s7_scheme *sc, s7_pointer args)
5875 {
5876   #define H_not "(not obj) returns #t if obj is #f, otherwise #t: (not ()) -> #f"
5877   #define Q_not sc->pl_bt
5878   return((car(args) == sc->F) ? sc->T : sc->F);
5879 }
5880 
5881 static bool not_b_7p(s7_scheme *sc, s7_pointer p) {return(p == sc->F);}
5882 
5883 bool s7_boolean(s7_scheme *sc, s7_pointer x) {return(x != sc->F);}
5884 s7_pointer s7_make_boolean(s7_scheme *sc, bool x) {return(make_boolean(sc, x));}
5885 
5886 
5887 /* -------------------------------- boolean? -------------------------------- */
5888 bool s7_is_boolean(s7_pointer x) {return(type(x) == T_BOOLEAN);}
5889 
5890 static s7_pointer g_is_boolean(s7_scheme *sc, s7_pointer args)
5891 {
5892   #define H_is_boolean "(boolean? obj) returns #t if obj is #f or #t: (boolean? ()) -> #f"
5893   #define Q_is_boolean sc->pl_bt
5894   check_boolean_method(sc, s7_is_boolean, sc->is_boolean_symbol, args);
5895 }
5896 
5897 
5898 /* -------------------------------- constant? -------------------------------- */
5899 
5900 static inline s7_pointer lookup_slot_from(s7_pointer symbol, s7_pointer e);
5901 
5902 static inline bool is_constant_symbol(s7_scheme *sc, s7_pointer sym)
5903 {
5904   if (is_immutable_symbol(sym))    /* for keywords */
5905     return(true);
5906   if (is_possibly_constant(sym))
5907     {
5908       s7_pointer slot;
5909       slot = lookup_slot_from(sym, sc->curlet);
5910       return((is_slot(slot)) && (is_immutable_slot(slot)));
5911     }
5912   return(false);
5913 }
5914 
5915 #define is_constant(sc, p) ((type(p) != T_SYMBOL) || (is_constant_symbol(sc, p)))
5916 
5917 static s7_pointer g_is_constant(s7_scheme *sc, s7_pointer args)
5918 {
5919   #define H_is_constant "(constant? obj) returns #t if obj either evaluates to itself, or is a symbol whose binding is constant"
5920   #define Q_is_constant sc->pl_bt
5921   return(make_boolean(sc, is_constant(sc, car(args))));
5922 }
5923 
5924 static s7_pointer is_constant_p_p(s7_scheme *sc, s7_pointer p) {return(make_boolean(sc, is_constant(sc, p)));}
5925 
5926 
5927 /* -------------------------------- immutable? -------------------------------- */
5928 bool s7_is_immutable(s7_pointer p) {return(is_immutable(p));}
5929 
5930 static s7_pointer g_is_immutable(s7_scheme *sc, s7_pointer args)
5931 {
5932   #define H_is_immutable "(immutable? sequence) returns #t if the sequence is immutable. (This function is work-in-progress)"
5933   #define Q_is_immutable sc->pl_bt
5934   s7_pointer p;
5935   p = car(args);
5936   if (is_symbol(p))
5937     {
5938       s7_pointer slot;
5939       slot = lookup_slot_from(p, sc->curlet);
5940       if ((is_slot(slot)) && (is_immutable_slot(slot))) return(sc->T);
5941     }
5942   if (is_number(p)) return(sc->T);
5943   return((is_immutable(p)) ? sc->T : sc->F);
5944 }
5945 
5946 
5947 /* -------------------------------- immutable! -------------------------------- */
5948 s7_pointer s7_immutable(s7_pointer p)
5949 {
5950   set_immutable(p);
5951   return(p);
5952 }
5953 
5954 static s7_pointer g_immutable(s7_scheme *sc, s7_pointer args)
5955 {
5956   #define H_immutable "(immutable! sequence) declares that the sequence's entries can't be changed. The sequence is returned."
5957   #define Q_immutable s7_make_signature(sc, 2, sc->T, sc->T)
5958   s7_pointer p;
5959   p = car(args);
5960   if (is_symbol(p))
5961     {
5962       s7_pointer slot;
5963       slot = lookup_slot_from(p, sc->curlet);
5964       if (is_slot(slot))
5965 	{
5966 	  set_immutable(slot);
5967 	  return(p);  /* symbol is not set immutable ? */
5968 	}}
5969   set_immutable(p);
5970   return(p);
5971 }
5972 
5973 /* -------------------------------- GC -------------------------------- */
5974 
5975 /* in most code, pairs, lets, and slots dominate the heap -- each about 25% to 40% of the
5976  *   total cell allocations.  In snd-test, reals are 50%. slots need not be in the heap,
5977  *   but moving them out to their own free list was actually slower because we need (in that
5978  *   case) to manage them in the sweep process by tracking lets.
5979  */
5980 
5981 #if S7_DEBUGGING
5982 static s7_int s7_gc_protect_2(s7_scheme *sc, s7_pointer x, int32_t line)
5983 {
5984   s7_int loc;
5985   loc = s7_gc_protect(sc, x);
5986   if (loc > 8192)
5987     {
5988       fprintf(stderr, "infinite loop or memory leak at line %d %s?\n", line, string_value(s7_object_to_string(sc, current_code(sc), false)));
5989       abort();
5990     }
5991   return(loc);
5992 }
5993 #define s7_gc_protect_1(Sc, X) s7_gc_protect_2(Sc, X, __LINE__)
5994 #else
5995 #define s7_gc_protect_1(Sc, X) s7_gc_protect(Sc, X)
5996 #endif
5997 
5998 static void resize_gc_protect(s7_scheme *sc)
5999 {
6000   s7_int i, size, new_size;
6001   block_t *ob, *nb;
6002   size = sc->protected_objects_size;
6003   new_size = 2 * size;
6004   ob = vector_block(sc->protected_objects);
6005   nb = reallocate(sc, ob, new_size * sizeof(s7_pointer));
6006   block_info(nb) = NULL;
6007   vector_block(sc->protected_objects) = nb;
6008   vector_elements(sc->protected_objects) = (s7_pointer *)block_data(nb);
6009   vector_length(sc->protected_objects) = new_size;
6010   sc->protected_objects_size = new_size;
6011   sc->gpofl = (s7_int *)Realloc(sc->gpofl, new_size * sizeof(s7_int));
6012   for (i = size; i < new_size; i++)
6013     {
6014       vector_element(sc->protected_objects, i) = sc->unused;
6015       sc->gpofl[++sc->gpofl_loc] = i;
6016     }
6017 }
6018 
6019 s7_int s7_gc_protect(s7_scheme *sc, s7_pointer x)
6020 {
6021   s7_int loc;
6022   if (sc->gpofl_loc < 0)
6023     resize_gc_protect(sc);
6024   loc = sc->gpofl[sc->gpofl_loc--];
6025   vector_element(sc->protected_objects, loc) = x;
6026   return(loc);
6027 }
6028 
6029 void s7_gc_unprotect_at(s7_scheme *sc, s7_int loc)
6030 {
6031   if (loc < sc->protected_objects_size)
6032     {
6033       if (vector_element(sc->protected_objects, loc) != sc->unused)
6034 	sc->gpofl[++sc->gpofl_loc] = loc;
6035 #if S7_DEBUGGING
6036       else fprintf(stderr, "redundant gc_unprotect_at location %" print_s7_int "\n", loc);
6037 #endif
6038       vector_element(sc->protected_objects, loc) = sc->unused;
6039     }
6040 }
6041 
6042 s7_pointer s7_gc_protected_at(s7_scheme *sc, s7_int loc)
6043 {
6044   s7_pointer obj;
6045 
6046   obj = sc->unspecified;
6047   if (loc < sc->protected_objects_size)
6048     obj = vector_element(sc->protected_objects, loc);
6049   if (obj == sc->unused)
6050     return(sc->unspecified);
6051 
6052   return(obj);
6053 }
6054 
6055 #define gc_protected_at(Sc, Loc) vector_element(Sc->protected_objects, Loc)
6056 
6057 s7_pointer s7_gc_protect_via_location(s7_scheme *sc, s7_pointer x, s7_int loc)
6058 {
6059   vector_element(sc->protected_objects, loc) = x;
6060   return(x);
6061 }
6062 
6063 s7_pointer s7_gc_unprotect_via_location(s7_scheme *sc, s7_int loc)
6064 {
6065   vector_element(sc->protected_objects, loc) = sc->F;
6066   return(sc->F);
6067 }
6068 
6069 
6070 static void (*mark_function[NUM_TYPES])(s7_pointer p);
6071 
6072 void s7_mark(s7_pointer p)
6073 {
6074   if (!is_marked(p))
6075     (*mark_function[unchecked_type(p)])(p);
6076 }
6077 
6078 static inline void gc_mark(s7_pointer p)
6079 {
6080   if (!is_marked(p))
6081     (*mark_function[unchecked_type(p)])(p);
6082 }
6083 
6084 static inline void mark_slot(s7_pointer p)
6085 {
6086   set_mark(T_Slt(p));
6087   gc_mark(slot_value(p));
6088   if (slot_has_setter(p))
6089     gc_mark(slot_setter(p));
6090   if (slot_has_pending_value(p))
6091     gc_mark(slot_pending_value(p));
6092   set_mark(slot_symbol(p));
6093 }
6094 
6095 static void mark_noop(s7_pointer p) {}
6096 
6097 static void close_output_port(s7_scheme *sc, s7_pointer p);
6098 static void remove_gensym_from_symbol_table(s7_scheme *sc, s7_pointer sym);
6099 static void cull_weak_hash_table(s7_scheme *sc, s7_pointer table);
6100 
6101 static void process_iterator(s7_scheme *sc, s7_pointer s1)
6102 {
6103   if (is_weak_hash_iterator(s1))
6104     {
6105       s7_pointer h;
6106       clear_weak_hash_iterator(s1);
6107       h = iterator_sequence(s1);
6108       if (unchecked_type(h) == T_HASH_TABLE)
6109 	{
6110 #if S7_DEBUGGING
6111 	  if (weak_hash_iters(h) == 0)
6112 	    fprintf(stderr, "in gc weak has iters wrapping under!\n");
6113 #endif
6114 	  weak_hash_iters(h)--;
6115 	}}
6116 }
6117 
6118 static void process_multivector(s7_scheme *sc, s7_pointer s1)
6119 {
6120   vdims_t *info;
6121   info = vector_dimension_info(s1);  /* a multidimensional empty vector can have dimension info, wrapped vectors always have dimension info */
6122   if ((info) &&
6123       (info != sc->wrap_only))
6124     {
6125       if (vector_elements_should_be_freed(info)) /* a kludge for foreign code convenience */
6126 	{
6127 	  free(vector_elements(s1));
6128 	  vector_elements_should_be_freed(info) = false;
6129 	}
6130       liberate(sc, info);
6131       vector_set_dimension_info(s1, NULL);
6132     }
6133   liberate(sc, vector_block(s1));
6134 }
6135 
6136 static void process_input_string_port(s7_scheme *sc, s7_pointer s1)
6137 {
6138 #if S7_DEBUGGING
6139   /* this set of ports is a subset of the ports that respond true to is_string_port --
6140    *   the latter include file ports fully read into local memory; see read_file which uses add_input_port, not add_input_string_port
6141    */
6142   if (port_filename(s1))
6143     fprintf(stderr, "string input port has a filename: %s\n", port_filename(s1));
6144   if (port_needs_free(s1))
6145     fprintf(stderr, "string input port needs data release\n");
6146 #endif
6147 
6148   liberate(sc, port_block(s1));
6149 }
6150 
6151 static void free_port_data(s7_scheme *sc, s7_pointer s1)
6152 {
6153   if (port_data(s1))
6154     {
6155       liberate(sc, port_data_block(s1));
6156       port_data_block(s1) = NULL;
6157       port_data(s1) = NULL;
6158       port_data_size(s1) = 0;
6159     }
6160   port_needs_free(s1) = false;
6161 }
6162 
6163 static void close_input_function(s7_scheme *sc, s7_pointer p);
6164 
6165 static void process_input_port(s7_scheme *sc, s7_pointer s1)
6166 {
6167   if (!port_is_closed(s1))
6168     {
6169       if (is_file_port(s1))
6170 	{
6171 	  if (port_file(s1))
6172 	    {
6173 	      fclose(port_file(s1));
6174 	      port_file(s1) = NULL;
6175 	    }}
6176       else
6177 	if (is_function_port(s1))
6178 	  close_input_function(sc, s1);
6179     }
6180   if (port_needs_free(s1))
6181     free_port_data(sc, s1);
6182 
6183   if (port_filename(s1))
6184     {
6185       liberate(sc, port_filename_block(s1));
6186       port_filename(s1) = NULL;
6187     }
6188   liberate(sc, port_block(s1));
6189 }
6190 
6191 static void process_output_port(s7_scheme *sc, s7_pointer s1)
6192 {
6193   close_output_port(sc, s1); /* needed for free filename, etc */
6194   liberate(sc, port_block(s1));
6195   if (port_needs_free(s1))
6196     {
6197       if (port_data_block(s1))
6198 	{
6199 	  liberate(sc, port_data_block(s1));
6200 	  port_data_block(s1) = NULL;
6201 	}
6202       port_needs_free(s1) = false;
6203     }
6204 }
6205 
6206 static void process_continuation(s7_scheme *sc, s7_pointer s1)
6207 {
6208   continuation_op_stack(s1) = NULL;
6209   liberate_block(sc, continuation_block(s1));
6210 }
6211 
6212 #if WITH_GMP
6213 
6214 #if ((__GNU_MP_VERSION < 6) || ((__GNU_MP_VERSION == 6) && (__GNU_MP_VERSION_MINOR == 0)))
6215 static int mpq_cmp_z(const mpq_t op1, const mpz_t op2)
6216 {
6217   mpq_t z1;
6218   int result;
6219   mpq_init(z1);
6220   mpq_set_z(z1, op2);
6221   result = mpq_cmp(op1, z1);
6222   mpq_clear(z1);
6223   return(result);
6224 }
6225 #endif
6226 
6227 static void free_big_integer(s7_scheme *sc, s7_pointer p)
6228 {
6229   big_integer_nxt(p) = sc->bigints;
6230   sc->bigints = big_integer_bgi(p);
6231   big_integer_bgi(p) = NULL;
6232 }
6233 
6234 static void free_big_ratio(s7_scheme *sc, s7_pointer p)
6235 {
6236   big_ratio_nxt(p) = sc->bigrats;
6237   sc->bigrats = big_ratio_bgr(p);
6238   big_ratio_bgr(p) = NULL;
6239 }
6240 
6241 static void free_big_real(s7_scheme *sc, s7_pointer p)
6242 {
6243   big_real_nxt(p) = sc->bigflts;
6244   sc->bigflts = big_real_bgf(p);
6245   big_real_bgf(p) = NULL;
6246 }
6247 
6248 static void free_big_complex(s7_scheme *sc, s7_pointer p)
6249 {
6250   big_complex_nxt(p) = sc->bigcmps;
6251   sc->bigcmps = big_complex_bgc(p);
6252   big_complex_bgc(p) = NULL;
6253 }
6254 #endif
6255 
6256 static void free_hash_table(s7_scheme *sc, s7_pointer table);
6257 
6258 static void sweep(s7_scheme *sc)
6259 {
6260   s7_int i, j;
6261   s7_pointer s1;
6262   gc_list_t *gp;
6263 
6264   #define process_gc_list(Code)			\
6265     if (gp->loc > 0)				\
6266       {						\
6267         for (i = 0, j = 0; i < gp->loc; i++)		\
6268           {						\
6269             s1 = gp->list[i];				\
6270             if (is_free_and_clear(s1))			\
6271               {						\
6272                 Code;					\
6273               }						\
6274             else gp->list[j++] = s1;			\
6275           }						\
6276         gp->loc = j;					\
6277       }							\
6278 
6279   gp = sc->strings;
6280   process_gc_list(liberate(sc, string_block(s1)))
6281 
6282   gp = sc->gensyms;
6283   process_gc_list(remove_gensym_from_symbol_table(sc, s1); liberate(sc, gensym_block(s1)))
6284   if (gp->loc == 0) mark_function[T_SYMBOL] = mark_noop;
6285 
6286   gp = sc->undefineds;
6287   process_gc_list(free(undefined_name(s1)))
6288 
6289   gp = sc->c_objects;
6290   process_gc_list((c_object_gc_free(sc, s1)) ? (void)(*(c_object_gc_free(sc, s1)))(sc, s1) : (void)(*(c_object_free(sc, s1)))(c_object_value(s1)))
6291 
6292   gp = sc->lambdas;
6293   process_gc_list(liberate(sc, c_function_block(s1)))
6294 
6295   gp = sc->vectors;
6296   process_gc_list(liberate(sc, vector_block(s1)))
6297 
6298   gp = sc->multivectors;
6299   process_gc_list(process_multivector(sc, s1));
6300 
6301   gp = sc->hash_tables;
6302   if (gp->loc > 0)
6303     {
6304       for (i = 0, j = 0; i < gp->loc; i++)
6305 	{
6306 	  s1 = gp->list[i];
6307 	  if (is_free_and_clear(s1))
6308 	    free_hash_table(sc, s1);
6309 	  else
6310 	    {
6311 	      if ((is_weak_hash_table(s1)) &&
6312 		  (weak_hash_iters(s1) == 0))
6313 		cull_weak_hash_table(sc, s1);
6314 	      gp->list[j++] = s1;
6315 	    }}
6316       gp->loc = j;
6317     }
6318 
6319   gp = sc->weak_hash_iterators;
6320   process_gc_list(process_iterator(sc, s1));
6321 
6322   gp = sc->opt1_funcs;
6323   if (gp->loc > 0)
6324     {
6325       for (i = 0, j = 0; i < gp->loc; i++)
6326 	{
6327 	  s1 = gp->list[i];
6328 	  if (!is_free_and_clear(s1))
6329 	    gp->list[j++] = s1;
6330 	}
6331       gp->loc = j;
6332     }
6333 
6334   gp = sc->input_ports;
6335   process_gc_list(process_input_port(sc, s1));
6336 
6337   gp = sc->input_string_ports;
6338   process_gc_list(process_input_string_port(sc, s1));
6339 
6340   gp = sc->output_ports;
6341   process_gc_list(process_output_port(sc, s1));
6342 
6343   gp = sc->continuations;
6344   process_gc_list(process_continuation(sc, s1));
6345 
6346   gp = sc->weak_refs;
6347   if (gp->loc > 0)
6348     {
6349       for (i = 0, j = 0; i < gp->loc; i++)
6350 	{
6351 	  s1 = gp->list[i];
6352 	  if (!is_free_and_clear(s1))
6353 	    {
6354 	      if (is_free_and_clear(c_pointer_weak1(s1)))
6355 		c_pointer_weak1(s1) = sc->F;
6356 	      if (is_free_and_clear(c_pointer_weak2(s1)))
6357 		c_pointer_weak2(s1) = sc->F;
6358 	      if ((c_pointer_weak1(s1) != sc->F) ||
6359 		  (c_pointer_weak2(s1) != sc->F))
6360 		gp->list[j++] = s1;
6361 	    }}
6362       gp->loc = j;
6363     }
6364 
6365 #if WITH_GMP
6366   gp = sc->big_integers;
6367   process_gc_list(free_big_integer(sc, s1))
6368 
6369   gp = sc->big_ratios;
6370   process_gc_list(free_big_ratio(sc ,s1))
6371 
6372   gp = sc->big_reals;
6373   process_gc_list(free_big_real(sc, s1))
6374 
6375   gp = sc->big_complexes;
6376   process_gc_list(free_big_complex(sc, s1))
6377 
6378   gp = sc->big_random_states;
6379   process_gc_list(gmp_randclear(random_gmp_state(s1)))
6380 #endif
6381 }
6382 
6383 static inline void add_to_gc_list(gc_list_t *gp, s7_pointer p)
6384 {
6385   if (gp->loc == gp->size)
6386     {
6387       gp->size *= 2;
6388       gp->list = (s7_pointer *)realloc(gp->list, gp->size * sizeof(s7_pointer));
6389     }
6390   gp->list[gp->loc++] = p;
6391 }
6392 
6393 static gc_list_t *make_gc_list(void)
6394 {
6395   gc_list_t *gp;
6396   #define INIT_GC_CACHE_SIZE 4
6397   gp = (gc_list_t *)malloc(sizeof(gc_list_t));
6398   gp->size = INIT_GC_CACHE_SIZE;
6399   gp->loc = 0;
6400   gp->list = (s7_pointer *)malloc(gp->size * sizeof(s7_pointer));
6401   return(gp);
6402 }
6403 
6404 static void just_mark(s7_pointer p)
6405 {
6406   set_mark(p);
6407 }
6408 
6409 static void add_gensym(s7_scheme *sc, s7_pointer p)
6410 {
6411   add_to_gc_list(sc->gensyms, p);
6412   mark_function[T_SYMBOL] = just_mark;
6413 }
6414 
6415 #define add_c_object(sc, p)          add_to_gc_list(sc->c_objects, p)
6416 #define add_hash_table(sc, p)        add_to_gc_list(sc->hash_tables, p)
6417 #define add_string(sc, p)            add_to_gc_list(sc->strings, p)
6418 #define add_input_port(sc, p)        add_to_gc_list(sc->input_ports, p)
6419 #define add_input_string_port(sc, p) add_to_gc_list(sc->input_string_ports, p)
6420 #define add_output_port(sc, p)       add_to_gc_list(sc->output_ports, p)
6421 #define add_continuation(sc, p)      add_to_gc_list(sc->continuations, p)
6422 #define add_undefined(sc, p)         add_to_gc_list(sc->undefineds, p)
6423 #define add_vector(sc, p)            add_to_gc_list(sc->vectors, p)
6424 #define add_multivector(sc, p)       add_to_gc_list(sc->multivectors, p)
6425 #define add_lambda(sc, p)            add_to_gc_list(sc->lambdas, p)
6426 #define add_weak_ref(sc, p)          add_to_gc_list(sc->weak_refs, p)
6427 #define add_weak_hash_iterator(sc, p) add_to_gc_list(sc->weak_hash_iterators, p)
6428 #define add_opt1_func(sc, p) do {if (!opt1_func_listed(p)) add_to_gc_list(sc->opt1_funcs, p); set_opt1_func_listed(p);} while (0)
6429 
6430 #if WITH_GMP
6431 #define add_big_integer(sc, p)       add_to_gc_list(sc->big_integers, p)
6432 #define add_big_ratio(sc, p)         add_to_gc_list(sc->big_ratios, p)
6433 #define add_big_real(sc, p)          add_to_gc_list(sc->big_reals, p)
6434 #define add_big_complex(sc, p)       add_to_gc_list(sc->big_complexes, p)
6435 #define add_big_random_state(sc, p)  add_to_gc_list(sc->big_random_states, p)
6436 #endif
6437 
6438 static void init_gc_caches(s7_scheme *sc)
6439 {
6440   sc->strings = make_gc_list();
6441   sc->gensyms = make_gc_list();
6442   sc->undefineds = make_gc_list();
6443   sc->vectors = make_gc_list();
6444   sc->multivectors = make_gc_list();
6445   sc->hash_tables = make_gc_list();
6446   sc->input_ports = make_gc_list();
6447   sc->input_string_ports = make_gc_list();
6448   sc->output_ports = make_gc_list();
6449   sc->continuations = make_gc_list();
6450   sc->c_objects = make_gc_list();
6451   sc->lambdas = make_gc_list();
6452   sc->weak_refs = make_gc_list();
6453   sc->weak_hash_iterators = make_gc_list();
6454   sc->opt1_funcs = make_gc_list();
6455 #if WITH_GMP
6456   sc->big_integers = make_gc_list();
6457   sc->big_ratios = make_gc_list();
6458   sc->big_reals = make_gc_list();
6459   sc->big_complexes = make_gc_list();
6460   sc->big_random_states = make_gc_list();
6461   sc->ratloc = NULL;
6462 #endif
6463 
6464   /* slightly unrelated... */
6465   sc->setters_size = 4;
6466   sc->setters_loc = 0;
6467   sc->setters = (s7_pointer *)malloc(sc->setters_size * sizeof(s7_pointer));
6468 }
6469 
6470 static s7_pointer permanent_cons(s7_scheme *sc, s7_pointer a, s7_pointer b, uint64_t type);
6471 
6472 static void add_setter(s7_scheme *sc, s7_pointer p, s7_pointer setter)
6473 {
6474   /* setters GC-protected. The c_function_setter field can't be used because the built-in functions
6475    *   are often removed from the heap and never thereafter marked.  Only closures and macros are protected here.
6476    */
6477   s7_int i;
6478 #if S7_DEBUGGING
6479   if ((!is_any_closure(setter)) && (!is_any_macro(setter)))
6480     fprintf(stderr, "add_setter: %s %d?\n", display(setter), type(setter));
6481 #endif
6482   for (i = 0; i < sc->setters_loc; i++)
6483     {
6484       s7_pointer x;
6485       x = sc->setters[i];
6486       if (car(x) == p)
6487 	{
6488 	  set_cdr(x, setter);
6489 	  return;
6490  	}}
6491   if (sc->setters_loc == sc->setters_size)
6492     {
6493       sc->setters_size *= 2;
6494       sc->setters = (s7_pointer *)Realloc(sc->setters, sc->setters_size * sizeof(s7_pointer));
6495     }
6496   sc->setters[sc->setters_loc++] = permanent_cons(sc, p, setter, T_PAIR | T_IMMUTABLE);
6497 }
6498 
6499 static void mark_symbol_vector(s7_pointer p, s7_int len)
6500 {
6501   set_mark(p);
6502   if (mark_function[T_SYMBOL] != mark_noop) /* else no gensyms */
6503     {
6504       s7_int i;
6505       s7_pointer *e;
6506       e = vector_elements(p);
6507       for (i = 0; i < len; i++)
6508 	if (is_gensym(e[i]))
6509 	  set_mark(e[i]);
6510     }
6511 }
6512 
6513 static void mark_simple_vector(s7_pointer p, s7_int len)
6514 {
6515   s7_int i;
6516   s7_pointer *e;
6517   set_mark(p);
6518   e = vector_elements(p);
6519   for (i = 0; i < len; i++)
6520     set_mark(e[i]);
6521 }
6522 
6523 static void just_mark_vector(s7_pointer p, s7_int len)
6524 {
6525   set_mark(p);
6526 }
6527 
6528 static void mark_vector_1(s7_pointer p, s7_int top)
6529 {
6530   s7_pointer *tp, *tend, *tend4;
6531 
6532   set_mark(p);
6533 
6534   tp = (s7_pointer *)(vector_elements(p));
6535   if (!tp) return;
6536   tend = (s7_pointer *)(tp + top);
6537   tend4 = (s7_pointer *)(tend - 8);
6538 
6539   while (tp <= tend4)
6540     LOOP_8(gc_mark(*tp++));
6541   while (tp < tend)
6542     gc_mark(*tp++);
6543 }
6544 
6545 static void mark_typed_vector_1(s7_pointer p, s7_int top) /* for typed vectors with closure setters */
6546 {
6547   gc_mark(typed_vector_typer(p));
6548   mark_vector_1(p, top);
6549 }
6550 
6551 static void mark_let(s7_pointer let)
6552 {
6553   s7_pointer x;
6554   for (x = let; is_let(x) && (!is_marked(x)); x = let_outlet(x))
6555     {
6556       s7_pointer y;
6557       set_mark(x);
6558       if (has_dox_slot1(x)) mark_slot(let_dox_slot1(x));
6559       if ((has_dox_slot2(x)) && (is_slot(let_dox_slot2(x)))) mark_slot(let_dox_slot2(x));
6560       for (y = let_slots(x); tis_slot(y); y = next_slot(y))
6561 	if (!is_marked(y)) /* slot value might be the enclosing let */
6562 	  mark_slot(y);
6563     }
6564 }
6565 
6566 #if WITH_HISTORY
6567 static void gc_owlet_mark(s7_pointer tp)
6568 {
6569   /* gc_mark but if tp is a pair ignore the marked bit on unheaped entries */
6570   if (is_pair(tp))
6571     {
6572       s7_pointer p;
6573       p = tp;
6574       do {
6575 	set_mark(p);
6576 	gc_mark(car(p)); /* does this need to be gc_owlet_mark? I can't find a case */
6577 	p = cdr(p);
6578       } while ((is_pair(p)) && (p != tp) && ((not_in_heap(p)) || (!is_marked(p)))); /* ((full_type(p) & (TYPE_MASK | T_GC_MARK)) == T_PAIR) is much slower */
6579       gc_mark(p);
6580     }
6581   else
6582     if (!is_marked(tp))
6583       (*mark_function[unchecked_type(tp)])(tp);
6584 }
6585 #endif
6586 
6587 static void mark_owlet(s7_scheme *sc)
6588 {
6589 #if WITH_HISTORY
6590   {
6591     s7_pointer p1, p2, p3;
6592     int32_t i;
6593     for (i = 1, p1 = sc->eval_history1, p2 = sc->eval_history2, p3 = sc->history_pairs; ; i++, p2 = cdr(p2), p3 = cdr(p3))
6594       {
6595 	set_mark(p1); /* pointless? they're permanent */
6596 	set_mark(p2);
6597 	set_mark(p3);
6598 	gc_owlet_mark(car(p1));
6599 	gc_owlet_mark(car(p2));
6600 	gc_owlet_mark(car(p3));
6601 	p1 = cdr(p1);
6602 	if (p1 == sc->eval_history1) break; /* these are circular lists */
6603       }}
6604 #endif
6605 
6606   /* sc->error_type and friends are slots in owlet */
6607   mark_slot(sc->error_type);
6608   slot_set_value(sc->error_data, sc->F); /* or maybe mark_tree(slot_value(sc->error_data)) ? */
6609   mark_slot(sc->error_data);
6610   mark_slot(sc->error_code);
6611   mark_slot(sc->error_line);
6612   mark_slot(sc->error_file);
6613   mark_slot(sc->error_position);
6614 #if WITH_HISTORY
6615   mark_slot(sc->error_history);
6616 #endif
6617   set_mark(sc->owlet);
6618   mark_let(let_outlet(sc->owlet));
6619 }
6620 
6621 static void mark_c_pointer(s7_pointer p)
6622 {
6623   set_mark(p);
6624   gc_mark(c_pointer_type(p));
6625   gc_mark(c_pointer_info(p));
6626 }
6627 
6628 static void mark_c_proc_star(s7_pointer p)
6629 {
6630   set_mark(p);
6631   if ((!c_func_has_simple_defaults(p)) &&
6632       (c_function_call_args(p))) /* NULL if not a safe function */
6633     {
6634       s7_pointer arg;
6635       for (arg = c_function_call_args(p); is_pair(arg); arg = cdr(arg))
6636 	gc_mark(car(arg));
6637     }
6638 }
6639 
6640 static void mark_pair(s7_pointer p)
6641 {
6642   do {
6643     set_mark(p);
6644     gc_mark(car(p)); /* expanding this to avoid recursion is slower */
6645     p = cdr(p);
6646   } while ((is_pair(p)) && (!is_marked(p))); /* ((full_type(p) & (TYPE_MASK | T_GC_MARK)) == T_PAIR) is much slower */
6647   gc_mark(p);
6648 }
6649 
6650 static void mark_counter(s7_pointer p)
6651 {
6652   set_mark(p);
6653   gc_mark(counter_result(p));
6654   gc_mark(counter_list(p));
6655   gc_mark(counter_let(p));
6656 }
6657 
6658 static void mark_closure(s7_pointer p)
6659 {
6660   set_mark(p);
6661   gc_mark(closure_args(p));
6662   gc_mark(closure_body(p));
6663   mark_let(closure_let(p));
6664   gc_mark(closure_setter_or_map_list(p));
6665 }
6666 
6667 static void mark_stack_1(s7_pointer p, s7_int top)
6668 {
6669   s7_pointer *tp, *tend;
6670   set_mark(p);
6671   tp = (s7_pointer *)(stack_elements(p));
6672   if (!tp) return;
6673   tend = (s7_pointer *)(tp + top);
6674   while (tp < tend)
6675     {
6676       gc_mark(*tp++);
6677       gc_mark(*tp++);
6678       gc_mark(*tp++);
6679       tp++;
6680     }
6681 }
6682 
6683 static void mark_stack(s7_pointer p)
6684 {
6685   /* we can have a bare stack waiting for a continuation to hold it if the new_cell for the continuation triggers the GC!  But we need a top-of-stack?? */
6686   mark_stack_1(p, temp_stack_top(p));
6687 }
6688 
6689 static void mark_continuation(s7_pointer p)
6690 {
6691   set_mark(p);
6692   if (!is_marked(continuation_stack(p))) /* can these be cyclic? */
6693     mark_stack_1(continuation_stack(p), continuation_stack_top(p));
6694   gc_mark(continuation_op_stack(p));
6695 }
6696 
6697 static void mark_vector(s7_pointer p)
6698 {
6699   if (is_typed_vector(p))
6700     typed_vector_gc_mark(p)(p, vector_length(p));
6701   else mark_vector_1(p, vector_length(p));
6702 }
6703 
6704 static void mark_vector_possibly_shared(s7_pointer p)
6705 {
6706   /* If a subvector (an inner dimension) of a vector is the only remaining reference
6707    *    to the main vector, we want to make sure the main vector is not GC'd until
6708    *    the subvector is also GC-able.  The subvector field either points to the
6709    *    parent vector, or it is sc->F, so we need to check for a vector parent if
6710    *    the current is multidimensional (this will include 1-dim slices).  We need
6711    *    to keep the parent case separate (i.e. sc->F means the current is the original)
6712    *    so that we only free once (or remove_from_heap once).
6713    *
6714    * If we have a subvector of a subvector, and the middle and original are not otherwise
6715    *   in use, we mark the middle one, but (since it itself is not in use anywhere else)
6716    *   we don't mark the original!  So we need to follow the share-vector chain marking every one.
6717    *
6718    * To remove a cell from the heap, we need its current heap location so that we can replace it.
6719    *   The heap is allocated as needed in monolithic blocks of (say) 1/2M s7_cells. When a cell
6720    *   is replaced, the new cell (at heap[x] say) is no longer from the original block. Since the
6721    *   GC clears all type bits when it frees a cell, we can't use a type bit to distinguish the
6722    *   replacements from the originals, but we need that info because in the base case, we use
6723    *   the distance of the cell from the base cell to get "x", its location.  In the replacement
6724    *   case, we add the location at the end of the s7_cell (s7_big_cell).  We track the current
6725    *   heap blocks via the sc->heap_blocks list.  To get the location of "p" above, we run through
6726    *   that list looking for a block it fits in.  If none is found, we assume it is an s7_big_cell
6727    *   and use the saved location.
6728    */
6729   if (is_subvector(p))
6730     mark_vector_possibly_shared(subvector_vector(p));
6731 
6732   /* mark_vector_1 does not check the marked bit, so if subvector below is in a cycle involving
6733    *   the calling vector, we get infinite recursion unless we check the mark bit here.
6734    */
6735   if (!is_marked(p))
6736     mark_vector_1(p, vector_length(p));
6737 }
6738 
6739 static void mark_int_or_float_vector(s7_pointer p)
6740 {
6741   set_mark(p);
6742 }
6743 
6744 static void mark_int_or_float_vector_possibly_shared(s7_pointer p)
6745 {
6746   if (is_subvector(p))
6747     mark_int_or_float_vector_possibly_shared(subvector_vector(p));
6748   set_mark(p);
6749 }
6750 
6751 static void mark_c_object(s7_pointer p)
6752 {
6753   set_mark(p);
6754   if (c_object_gc_mark(c_object_s7(p), p))
6755     (*(c_object_gc_mark(c_object_s7(p), p)))(c_object_s7(p), p);
6756   else (*(c_object_mark(c_object_s7(p), p)))(c_object_value(p));
6757 }
6758 
6759 static void mark_catch(s7_pointer p)
6760 {
6761   set_mark(p);
6762   gc_mark(catch_tag(p));
6763   gc_mark(catch_handler(p));
6764 }
6765 
6766 static void mark_dynamic_wind(s7_pointer p)
6767 {
6768   set_mark(p);
6769   gc_mark(dynamic_wind_in(p));
6770   gc_mark(dynamic_wind_out(p));
6771   gc_mark(dynamic_wind_body(p));
6772 }
6773 
6774 /* if is_typed_hash_table then if c_function_marker(key|value_typer) is just_mark_vector, we can ignore that field,
6775  *    if it's mark_simple_vector, we just set_mark (key|value), else we gc_mark
6776  */
6777 static void mark_hash_table(s7_pointer p)
6778 {
6779   set_mark(p);
6780   gc_mark(hash_table_procedures(p));
6781   if (hash_table_entries(p) > 0)
6782     {
6783       s7_int len;
6784       hash_entry_t **entries, **last;
6785 
6786       entries = hash_table_elements(p);
6787       len = hash_table_mask(p) + 1;
6788       last = (hash_entry_t **)(entries + len);
6789 
6790       if ((is_weak_hash_table(p)) &&
6791 	  (weak_hash_iters(p) == 0))
6792 	{
6793 	  while (entries < last)
6794 	    {
6795 	      hash_entry_t *xp;
6796 	      for (xp = *entries++; xp; xp = hash_entry_next(xp))
6797 		gc_mark(hash_entry_value(xp));
6798 	      for (xp = *entries++; xp; xp = hash_entry_next(xp))
6799 		gc_mark(hash_entry_value(xp));
6800 	    }}
6801       else
6802 	while (entries < last) /* counting entries here was slightly faster */
6803 	  {
6804 	    hash_entry_t *xp;
6805 	    for (xp = *entries++; xp; xp = hash_entry_next(xp))
6806 	      {
6807 		gc_mark(hash_entry_key(xp));
6808 		gc_mark(hash_entry_value(xp));
6809 	      }
6810 	    for (xp = *entries++; xp; xp = hash_entry_next(xp))
6811 	      {
6812 		gc_mark(hash_entry_key(xp));
6813 		gc_mark(hash_entry_value(xp));
6814 	      }}}
6815 }
6816 
6817 static void mark_iterator(s7_pointer p)
6818 {
6819   set_mark(p);
6820   gc_mark(iterator_sequence(p));
6821   if (is_mark_seq(p))
6822     gc_mark(iterator_current(p));
6823 }
6824 
6825 static void mark_input_port(s7_pointer p)
6826 {
6827   set_mark(p);
6828   gc_mark(port_input_scheme_function(p)); /* this is also a string port's string */
6829 }
6830 
6831 static void mark_output_port(s7_pointer p)
6832 {
6833   set_mark(p);
6834   if (is_function_port(p))
6835     gc_mark(port_output_scheme_function(p));
6836 }
6837 
6838 #define clear_type(p) full_type(p) = T_FREE
6839 
6840 static void init_mark_functions(void)
6841 {
6842   mark_function[T_FREE]                = mark_noop;
6843   mark_function[T_UNDEFINED]           = just_mark;
6844   mark_function[T_EOF]                 = mark_noop;
6845   mark_function[T_UNSPECIFIED]         = mark_noop;
6846   mark_function[T_NIL]                 = mark_noop;
6847   mark_function[T_UNUSED]              = mark_noop;
6848   mark_function[T_BOOLEAN]             = mark_noop;
6849   mark_function[T_SYNTAX]              = mark_noop;
6850   mark_function[T_CHARACTER]           = mark_noop;
6851   mark_function[T_SYMBOL]              = mark_noop; /* this changes to just_mark when gensyms are in the heap */
6852   mark_function[T_STRING]              = just_mark;
6853   mark_function[T_INTEGER]             = just_mark;
6854   mark_function[T_RATIO]               = just_mark;
6855   mark_function[T_REAL]                = just_mark;
6856   mark_function[T_COMPLEX]             = just_mark;
6857   mark_function[T_BIG_INTEGER]         = just_mark;
6858   mark_function[T_BIG_RATIO]           = just_mark;
6859   mark_function[T_BIG_REAL]            = just_mark;
6860   mark_function[T_BIG_COMPLEX]         = just_mark;
6861   mark_function[T_RANDOM_STATE]        = just_mark;
6862   mark_function[T_GOTO]                = just_mark;
6863   mark_function[T_OUTPUT_PORT]         = just_mark; /* changed to mark_output_port if output function ports are active */
6864   mark_function[T_C_MACRO]             = just_mark;
6865   mark_function[T_C_POINTER]           = mark_c_pointer;
6866   mark_function[T_C_FUNCTION]          = just_mark;
6867   mark_function[T_C_FUNCTION_STAR]     = just_mark; /* changes to mark_c_proc_star if defaults involve an expression */
6868   mark_function[T_C_ANY_ARGS_FUNCTION] = just_mark;
6869   mark_function[T_C_OPT_ARGS_FUNCTION] = just_mark;
6870   mark_function[T_C_RST_ARGS_FUNCTION] = just_mark;
6871   mark_function[T_PAIR]                = mark_pair;
6872   mark_function[T_CLOSURE]             = mark_closure;
6873   mark_function[T_CLOSURE_STAR]        = mark_closure;
6874   mark_function[T_CONTINUATION]        = mark_continuation;
6875   mark_function[T_INPUT_PORT]          = mark_input_port;
6876   mark_function[T_VECTOR]              = mark_vector; /* this changes if subvector created (similarly below) */
6877   mark_function[T_INT_VECTOR]          = mark_int_or_float_vector;
6878   mark_function[T_FLOAT_VECTOR]        = mark_int_or_float_vector;
6879   mark_function[T_BYTE_VECTOR]         = just_mark;
6880   mark_function[T_MACRO]               = mark_closure;
6881   mark_function[T_BACRO]               = mark_closure;
6882   mark_function[T_MACRO_STAR]          = mark_closure;
6883   mark_function[T_BACRO_STAR]          = mark_closure;
6884   mark_function[T_C_OBJECT]            = mark_c_object;
6885   mark_function[T_CATCH]               = mark_catch;
6886   mark_function[T_DYNAMIC_WIND]        = mark_dynamic_wind;
6887   mark_function[T_HASH_TABLE]          = mark_hash_table;
6888   mark_function[T_ITERATOR]            = mark_iterator;
6889   mark_function[T_LET]                 = mark_let;
6890   mark_function[T_STACK]               = mark_stack;
6891   mark_function[T_COUNTER]             = mark_counter;
6892   mark_function[T_SLOT]                = mark_slot;
6893 }
6894 
6895 static void mark_op_stack(s7_scheme *sc)
6896 {
6897   s7_pointer *p, *tp;
6898   tp = sc->op_stack_now;
6899   p = sc->op_stack;
6900   while (p < tp)
6901     gc_mark(*p++);
6902 }
6903 
6904 static void mark_input_port_stack(s7_scheme *sc)
6905 {
6906   s7_pointer *p, *tp;
6907   tp = (s7_pointer *)(sc->input_port_stack + sc->input_port_stack_loc);
6908   for (p = sc->input_port_stack; p < tp; p++)
6909     gc_mark(*p);
6910 }
6911 
6912 static void mark_rootlet(s7_scheme *sc)
6913 {
6914   s7_pointer ge;
6915   s7_pointer *tmp, *top;
6916 
6917   ge = sc->rootlet;
6918   tmp = rootlet_elements(ge);
6919   top = (s7_pointer *)(tmp + sc->rootlet_entries);
6920 
6921   set_mark(ge);
6922   while (tmp < top)
6923     gc_mark(slot_value(*tmp++));
6924   /* slot_setter is handled below with an explicit list -- more code than its worth probably */
6925   /* we're not marking slot_symbol above which makes me worry that a top-level gensym won't be protected
6926    *   (apply define (gensym) '(32)), then try to get the GC to clobber {gensym}-0,
6927    *   but I can't get it to break, so they must be protected somehow; apparently they are
6928    *   removed from the heap!  At least: (define-macro (defit) (let ((n (gensym))) `(define (,n) (format #t "fun")))) (defit)
6929    *   removes the function from the heap (protecting the gensym).
6930    */
6931 }
6932 
6933 /* arrays for permanent_objects are not needed yet: init: cells: 0, lets: 0, s7test: cells: 4, lets: 10, snd-test: cells: 14, lets: 1147 */
6934 
6935 /* mark_closure calls mark_let on closure_let(func) which marks slot values.
6936  *   if we move rootlet to end, unmarked closures at that point could mark let/slot but not slot value?
6937  *   or save safe-closure lets to handle all at end?  or a gc_list of safe closure lets and only mark let if not safe?
6938  */
6939 
6940 static void mark_permanent_objects(s7_scheme *sc)
6941 {
6942   gc_obj_t *g;
6943   for (g = sc->permanent_objects; g; g = (gc_obj_t *)(g->nxt))
6944     gc_mark(g->p);
6945   /* permanent_objects also has lets (removed from heap) -- should they be handled like permanent_lets?
6946    *    if unmarked should either be removed from the list and perhaps placed on a free list?
6947    *    if outlet is free can the let potentially be in use?
6948    *    there are many more permanent_lets(slots) than permanent objects
6949    */
6950 }
6951 /* do we mark funclet slot values from the function as root?  Maybe treat them like permanent_lets here? */
6952 
6953 static void unmark_permanent_objects(s7_scheme *sc)
6954 {
6955   gc_obj_t *g;
6956   for (g = sc->permanent_objects; g; g = (gc_obj_t *)(g->nxt))
6957     clear_mark(g->p);
6958   for (g = sc->permanent_lets; g; g = (gc_obj_t *)(g->nxt)) /* there are lets and slots in this list */
6959     clear_mark(g->p);
6960 }
6961 
6962 #if (!MS_WINDOWS)
6963   #include <time.h>
6964   #include <sys/time.h>
6965 #endif
6966 
6967 #if S7_DEBUGGING
6968 static bool has_odd_bits(s7_pointer obj);
6969 #endif
6970 void s7_show_let(s7_scheme *sc);
6971 static char *describe_type_bits(s7_scheme *sc, s7_pointer obj);
6972 static s7_pointer make_symbol(s7_scheme *sc, const char *name);
6973 static void s7_warn(s7_scheme *sc, s7_int len, const char *ctrl, ...);
6974 
6975 #if S7_DEBUGGING
6976 static int64_t gc(s7_scheme *sc, const char *func, int line)
6977 #else
6978 static int64_t gc(s7_scheme *sc)
6979 #endif
6980 {
6981   s7_cell **old_free_heap_top;
6982   sc->gc_start = my_clock();
6983   sc->gc_calls++;
6984 #if S7_DEBUGGING
6985   sc->last_gc_line = line;
6986 #endif
6987   mark_rootlet(sc);
6988   mark_owlet(sc);
6989 
6990   gc_mark(sc->code);
6991   if (sc->args) gc_mark(sc->args);
6992   mark_let(sc->curlet);
6993   mark_current_code(sc); /* probably redundant if with_history */
6994 
6995   mark_stack_1(sc->stack, current_stack_top(sc));
6996   gc_mark(sc->u);
6997   gc_mark(sc->v);
6998   gc_mark(sc->w);
6999   gc_mark(sc->x);
7000   gc_mark(sc->y);
7001   gc_mark(sc->z);
7002   gc_mark(sc->value);
7003 
7004   gc_mark(sc->temp1);
7005   gc_mark(sc->temp2);
7006   gc_mark(sc->temp3);
7007   gc_mark(sc->temp4);
7008   gc_mark(sc->temp5);
7009   gc_mark(sc->temp6);
7010   gc_mark(sc->temp7);
7011   gc_mark(sc->temp8);
7012   gc_mark(sc->temp9);
7013 
7014   set_mark(current_input_port(sc));
7015   mark_input_port_stack(sc);
7016   set_mark(current_output_port(sc));
7017   set_mark(sc->error_port);
7018   gc_mark(sc->stacktrace_defaults);
7019   gc_mark(sc->autoload_table);
7020   gc_mark(sc->default_rng);
7021 
7022   /* permanent lists that might escape and therefore need GC protection */
7023   mark_pair(sc->temp_cell_2);
7024   gc_mark(car(sc->t1_1));
7025   gc_mark(car(sc->t2_1)); gc_mark(car(sc->t2_2));
7026   gc_mark(car(sc->t3_1)); gc_mark(car(sc->t3_2)); gc_mark(car(sc->t3_3)); gc_mark(car(sc->t4_1));
7027   gc_mark(car(sc->plist_1));
7028   gc_mark(car(sc->clist_1));
7029   gc_mark(car(sc->plist_2)); gc_mark(cadr(sc->plist_2));
7030   gc_mark(car(sc->qlist_2)); gc_mark(cadr(sc->qlist_2));
7031   gc_mark(car(sc->qlist_3)); gc_mark(cadr(sc->qlist_3)); gc_mark(caddr(sc->qlist_3));
7032   gc_mark(car(sc->u1_1));
7033   gc_mark(car(sc->u2_1));
7034 
7035   gc_mark(sc->rec_p1);
7036   gc_mark(sc->rec_p2);
7037 
7038   {
7039     s7_pointer p;
7040     for (p = sc->wrong_type_arg_info; is_pair(p); p = cdr(p)) gc_mark(car(p));
7041     for (p = sc->simple_wrong_type_arg_info; is_pair(p); p = cdr(p)) gc_mark(car(p));
7042     for (p = sc->out_of_range_info; is_pair(p); p = cdr(p)) gc_mark(car(p));
7043     for (p = sc->simple_out_of_range_info; is_pair(p); p = cdr(p)) gc_mark(car(p));
7044     gc_mark(car(sc->elist_1));
7045     gc_mark(car(sc->elist_2));
7046     gc_mark(cadr(sc->elist_2));
7047     for (p = sc->plist_3; is_pair(p); p = cdr(p)) gc_mark(car(p));
7048     for (p = sc->elist_3; is_pair(p); p = cdr(p)) gc_mark(car(p));
7049     for (p = sc->elist_4; is_pair(p); p = cdr(p)) gc_mark(car(p));
7050     for (p = sc->elist_5; is_pair(p); p = cdr(p)) gc_mark(car(p));
7051   }
7052 
7053   {
7054     s7_int i;
7055     s7_pointer p;
7056     for (i = 1; i < NUM_SAFE_LISTS; i++)
7057       if ((is_pair(sc->safe_lists[i])) &&
7058 	  (list_is_in_use(sc->safe_lists[i])))
7059 	for (p = sc->safe_lists[i]; is_pair(p); p = cdr(p))
7060 	  gc_mark(car(p));
7061 
7062     for (i = 0; i < sc->setters_loc; i++)
7063       gc_mark(cdr(sc->setters[i]));
7064 
7065     for (i = 0; i < sc->num_fdats; i++)
7066       if (sc->fdats[i])
7067 	gc_mark(sc->fdats[i]->curly_arg);
7068 
7069     if (sc->rec_stack)
7070       {
7071 	just_mark(sc->rec_stack);
7072 	for (i = 0; i < sc->rec_loc; i++)
7073 	  gc_mark(sc->rec_els[i]);
7074       }}
7075   mark_vector(sc->protected_objects);
7076   mark_vector(sc->protected_setters);
7077   set_mark(sc->protected_setter_symbols);
7078 
7079   /* now protect recent allocations using the free_heap cells above the current free_heap_top (if any).
7080    * cells above sc->free_heap_top might be malloc'd garbage (after heap reallocation), so we keep track of
7081    *   where the last actually freed cells were after the previous GC call.  We're trying to
7082    *   GC protect the previous GC_TEMPS_SIZE allocated pointers so that the caller doesn't have
7083    *   to gc-protect every temporary cell.
7084    * There's one remaining possible problem.  s7_remove_from_heap frees cells outside
7085    *   the GC and might push free_heap_top beyond its previous_free_heap_top, then
7086    *   an immediate explicit gc call might not see those temp cells.
7087    */
7088   {
7089     s7_pointer *tmps, *tmps_top;
7090 
7091     tmps = sc->free_heap_top;
7092     tmps_top = tmps + sc->gc_temps_size;
7093     if (tmps_top > sc->previous_free_heap_top)
7094       tmps_top = sc->previous_free_heap_top;
7095 
7096     while (tmps < tmps_top)
7097       gc_mark(*tmps++);
7098   }
7099   mark_op_stack(sc);
7100   mark_permanent_objects(sc);
7101 
7102   if (sc->profiling_gensyms)
7103     {
7104       profile_data_t *pd;
7105       int32_t i;
7106       pd = sc->profile_data;
7107       for (i = 0; i < pd->top; i++)
7108 	if (is_gensym(pd->funcs[i]))
7109 	  set_mark(pd->funcs[i]);
7110     }
7111 
7112   {
7113     s7_int i;
7114     gc_list_t *gp;
7115     gp = sc->opt1_funcs;
7116     for (i = 0; i < gp->loc; i++)
7117       {
7118 	s7_pointer s1;
7119 	s1 = T_Pair(gp->list[i]);
7120 	if ((is_marked(s1)) && (!is_marked(opt1_any(s1)))) /* opt1_lambda, but op_unknown* can change to opt1_cfunc etc */
7121 	  set_mark(opt1_any(s1));
7122       }}
7123 
7124   /* free up all unmarked objects */
7125   old_free_heap_top = sc->free_heap_top;
7126   {
7127     s7_pointer *fp, *tp, *heap_top;
7128     fp = sc->free_heap_top;
7129 
7130     tp = sc->heap;
7131     heap_top = (s7_pointer *)(sc->heap + sc->heap_size);
7132 
7133 #if S7_DEBUGGING
7134   #define gc_object(Tp)							\
7135     p = (*Tp++);							\
7136     if (signed_type(p) > 0)						\
7137       {								        \
7138         p->debugger_bits = 0; p->gc_func = func; p->gc_line = line;	\
7139         /* if (unchecked_type(p) == T_PAIR) {p->object.cons.opt1 = NULL; p->object.cons.opt2 = NULL; p->object.cons.opt3 = NULL;} */\
7140         if (has_odd_bits(p)) {char *s; fprintf(stderr, "odd bits: %s\n", s = describe_type_bits(sc, p)); free(s);} \
7141         signed_type(p) = 0;						\
7142         (*fp++) = p;							\
7143       }									\
7144     else if (signed_type(p) < 0) clear_mark(p);
7145 #else
7146   #define gc_object(Tp) p = (*Tp++); if (signed_type(p) > 0) {signed_type(p) = 0; (*fp++) = p;} else if (signed_type(p) < 0) clear_mark(p);
7147   /* this appears to be about 10% faster than the previous form
7148    *   if the sign bit is on, but no other bits, this version will take no action (it thinks the cell is on the free list), but
7149    *   it means we've marked a free cell as in-use: since types are set as soon as removed from the free list, this has to be a bug
7150    *   (this case is caught by has_odd_bits).  If ignored, the type will be set, and later the bit cleared, so no problem?
7151    *   An alternate form that simply calls clear_mark (no check for < 0) appears to be the same speed even in cases with lots
7152    *   of long-lived objects.
7153    */
7154 #endif
7155     while (tp < heap_top)          /* != here or ^ makes no difference, going to 64 doesn't matter (this is less than .1% in all cases) */
7156       {
7157 	s7_pointer p;
7158 	LOOP_8(gc_object(tp));
7159 	LOOP_8(gc_object(tp));
7160 	LOOP_8(gc_object(tp));
7161 	LOOP_8(gc_object(tp));
7162       }
7163     /* I tried using pthreads here, since there is no need for a lock in this loop, but the *fp++ part needs to
7164      *   be local to each thread, then merged at the end.  In my timing tests, the current version was faster.
7165      *   If NUM_THREADS=2, and all thread variables are local, surely there's no "false sharing"?
7166      */
7167     sc->free_heap_top = fp;
7168     sweep(sc);
7169   }
7170 
7171   unmark_permanent_objects(sc);
7172   sc->gc_freed = (int64_t)(sc->free_heap_top - old_free_heap_top);
7173   sc->gc_total_freed += sc->gc_freed;
7174   sc->gc_end = my_clock();
7175   sc->gc_total_time += (sc->gc_end - sc->gc_start);
7176 
7177   if (sc->gc_stats != 0)
7178     {
7179       if (show_gc_stats(sc))
7180 	{
7181 #if (!MS_WINDOWS)
7182 	  s7_warn(sc, 256, "gc freed %" print_s7_int "/%" print_s7_int " (free: %" print_pointer "), time: %f\n",
7183 		  sc->gc_freed, sc->heap_size, (intptr_t)(sc->free_heap_top - sc->free_heap), (double)(sc->gc_end - sc->gc_start) / ticks_per_second());
7184 #else
7185 	  s7_warn(sc, 256, "gc freed %" print_s7_int "/%" print_s7_int "\n", sc->gc_freed, sc->heap_size);
7186 #endif
7187 	}
7188       if (show_protected_objects_stats(sc))
7189 	{
7190 	  s7_int len, i, num;
7191 	  len = vector_length(sc->protected_objects); /* allocated at startup */
7192 	  for (i = 0, num = 0; i < len; i++)
7193 	    if (vector_element(sc->protected_objects, i) != sc->unused)
7194 	      num++;
7195 	  s7_warn(sc, 256, "gc-protected-objects: %" print_s7_int " in use of %" print_s7_int "\n", num, len);
7196 	}}
7197   sc->previous_free_heap_top = sc->free_heap_top;
7198   return(sc->gc_freed);
7199 }
7200 
7201 #define GC_RESIZE_HEAP_BY_4_FRACTION 0.67
7202 /*   .5+.1: test -3?, dup +86, tmap +45, tsort -3, thash +305
7203  *   .85+.7: dup -5
7204  */
7205 
7206 static void resize_heap_to(s7_scheme *sc, int64_t size)
7207 {
7208   int64_t old_size, old_free, k;
7209   s7_cell *cells;
7210   s7_pointer p;
7211   s7_cell **cp;
7212   heap_block_t *hp;
7213 
7214   old_size = sc->heap_size;
7215   old_free = sc->free_heap_top - sc->free_heap;
7216   if (size == 0)
7217     {
7218       /* (sc->heap_size < 2048000) */  /* 8192000 here improves various gc benchmarks only slightly */
7219       /* maybe the choice of 4 should depend on how much space was freed rather than the current heap_size? */
7220       if (old_free < old_size * sc->gc_resize_heap_by_4_fraction)
7221 	sc->heap_size *= 4;          /* *8 if < 1M (or whatever) doesn't make much difference */
7222       else sc->heap_size *= 2;
7223     }
7224   else
7225     {
7226       if (size > sc->heap_size)
7227 	while (sc->heap_size < size) sc->heap_size *= 2;
7228       else return;
7229     }
7230   /* do not call new_cell here! */
7231 
7232   if (((2 * sc->heap_size * sizeof(s7_cell *)) + ((sc->heap_size - old_size) * sizeof(s7_cell))) >= SIZE_MAX)
7233     {
7234       s7_warn(sc, 256, "heap size requested, %ld => %ld bytes, is greater than size_t: %ld\n",
7235 	      (long int)(sc->heap_size),
7236 	      (long int)((2 * sc->heap_size * sizeof(s7_cell *)) + ((sc->heap_size - old_size) * sizeof(s7_cell))),
7237 	      (long int)SIZE_MAX);
7238       sc->heap_size = old_size + 64000;
7239     }
7240 
7241   cp = (s7_cell **)realloc(sc->heap, sc->heap_size * sizeof(s7_cell *));
7242   if (!cp)
7243     {
7244       s7_warn(sc, 256, "heap reallocation failed! tried to get %" print_s7_int " bytes (will retry with a smaller amount)\n", (int64_t)(sc->heap_size * sizeof(s7_cell *)));
7245       sc->heap_size = old_size + 64000;
7246       sc->heap = (s7_cell **)Realloc(sc->heap, sc->heap_size * sizeof(s7_cell *));
7247     }
7248   else sc->heap = cp;
7249 
7250   sc->free_heap = (s7_cell **)Realloc(sc->free_heap, sc->heap_size * sizeof(s7_cell *));
7251   sc->free_heap_trigger = (s7_cell **)(sc->free_heap + GC_TRIGGER_SIZE);
7252   sc->free_heap_top = sc->free_heap + old_free; /* incremented below, added old_free 21-Aug-12?!? */
7253 
7254   cells = (s7_cell *)Calloc(sc->heap_size - old_size, sizeof(s7_cell));
7255   add_saved_pointer(sc, (void *)cells);
7256   for (p = cells, k = old_size; k < sc->heap_size;)
7257     {
7258       LOOP_8(sc->heap[k++] = p; (*sc->free_heap_top++) = p++);
7259       LOOP_8(sc->heap[k++] = p; (*sc->free_heap_top++) = p++);
7260       LOOP_8(sc->heap[k++] = p; (*sc->free_heap_top++) = p++);
7261       LOOP_8(sc->heap[k++] = p; (*sc->free_heap_top++) = p++);
7262     }
7263   hp = (heap_block_t *)Malloc(sizeof(heap_block_t));
7264   hp->start = (intptr_t)cells;
7265   hp->end = (intptr_t)cells + ((sc->heap_size - old_size) * sizeof(s7_cell));
7266   hp->offset = old_size;
7267   hp->next = sc->heap_blocks;
7268   sc->heap_blocks = hp;
7269 
7270   sc->previous_free_heap_top = sc->free_heap_top;
7271 
7272   if (show_heap_stats(sc))
7273     {
7274       char *str;
7275       str = string_value(object_to_truncated_string(sc, current_code(sc), 80));
7276       if (size != 0)
7277 	s7_warn(sc, 512, "heap grows to %" print_s7_int " (old free/size: %" print_s7_int "/%" print_s7_int ", requested %" print_s7_int ") from %s\n",
7278 		sc->heap_size, old_free, old_size, size, str);
7279       else s7_warn(sc, 512, "heap grows to %" print_s7_int " (old free/size: %" print_s7_int "/%" print_s7_int ") from %s\n",
7280 		   sc->heap_size, old_free, old_size, str);
7281     }
7282   if (sc->heap_size >= sc->max_heap_size)
7283     s7_error(sc, make_symbol(sc, "heap-too-big"),
7284 	     set_elist_3(sc, wrap_string(sc, "heap has grown past (*s7* 'max-heap-size): ~S > ~S", 50),
7285 			 wrap_integer1(sc, sc->max_heap_size),
7286 			 wrap_integer2(sc, sc->heap_size)));
7287 }
7288 
7289 #define resize_heap(Sc) resize_heap_to(Sc, 0)
7290 
7291 #ifndef GC_RESIZE_HEAP_FRACTION
7292   #define GC_RESIZE_HEAP_FRACTION 0.8
7293 /* 1/2 is ok, 3/4 speeds up some GC benchmarks, 7/8 is a bit faster, 95/100 comes to a halt (giant heap)
7294  *    in my tests, only tvect.scm ends up larger if 3/4 used
7295  */
7296 #endif
7297 
7298 #if S7_DEBUGGING
7299 static void try_to_call_gc_1(s7_scheme *sc, const char *func, int line)
7300 #else
7301 static void try_to_call_gc(s7_scheme *sc)
7302 #endif
7303 {
7304   /* called only from new_cell */
7305   if (sc->gc_off)     /* we can't just return here!  Someone needs a new cell, and once the heap free list is exhausted, segfault */
7306     resize_heap(sc);
7307   else
7308     {
7309 #if (!S7_DEBUGGING)
7310       int64_t freed_heap;
7311       freed_heap = gc(sc);
7312       if (freed_heap < (sc->heap_size * sc->gc_resize_heap_fraction))
7313 	resize_heap(sc);
7314 #else
7315       gc(sc, func, line);
7316       if ((int64_t)(sc->free_heap_top - sc->free_heap) < (sc->heap_size * sc->gc_resize_heap_fraction))
7317 	resize_heap(sc);
7318 #endif
7319     }
7320 }
7321   /* originally I tried to mark each temporary value until I was done with it, but
7322    *   that way madness lies... By delaying GC of _every_ %$^#%@ pointer, I can dispense
7323    *   with hundreds of individual protections.  So the free_heap's last GC_TEMPS_SIZE
7324    *   allocated pointers are protected during the mark sweep.
7325    */
7326 
7327 static s7_pointer g_gc(s7_scheme *sc, s7_pointer args)
7328 {
7329   #define H_gc "(gc (on #t)) runs the garbage collector.  If 'on' is supplied, it turns the GC on or off. \
7330 Evaluation produces a surprising amount of garbage, so don't leave the GC off for very long!"
7331   #define Q_gc s7_make_signature(sc, 2, sc->T, sc->is_boolean_symbol)
7332 
7333   /* g_gc can't be called in a situation where these lists matter (I think...) */
7334   set_elist_1(sc, sc->nil);
7335   set_plist_1(sc, sc->nil);
7336   set_elist_2(sc, sc->nil, sc->nil);
7337   set_plist_2(sc, sc->nil, sc->nil);
7338   set_clist_1(sc, sc->nil);
7339   set_qlist_2(sc, sc->nil, sc->nil);
7340   set_qlist_3(sc, sc->nil, sc->nil, sc->nil);
7341   set_elist_3(sc, sc->nil, sc->nil, sc->nil);
7342   set_plist_3(sc, sc->nil, sc->nil, sc->nil);
7343   set_elist_4(sc, sc->nil, sc->nil, sc->nil, sc->nil);
7344   set_elist_5(sc, sc->nil, sc->nil, sc->nil, sc->nil, sc->nil);
7345 
7346   if (is_not_null(args))
7347     {
7348       if (!s7_is_boolean(car(args)))
7349 	return(method_or_bust_one_arg(sc, car(args), sc->gc_symbol, args, T_BOOLEAN));
7350       sc->gc_off = (car(args) == sc->F);
7351       if (sc->gc_off)
7352 	return(sc->F);
7353     }
7354 #if S7_DEBUGGING
7355   gc(sc, __func__, __LINE__);
7356 #else
7357   gc(sc);
7358 #endif
7359   return(sc->unspecified);
7360 }
7361 
7362 s7_pointer s7_gc_on(s7_scheme *sc, bool on)
7363 {
7364   sc->gc_off = !on;
7365   return(s7_make_boolean(sc, on));
7366 }
7367 
7368 #if S7_DEBUGGING
7369 static void check_free_heap_size_1(s7_scheme *sc, s7_int size, const char *func, int line)
7370 #define check_free_heap_size(Sc, Size) check_free_heap_size_1(Sc, Size, __func__, __LINE__)
7371 #else
7372 static void check_free_heap_size(s7_scheme *sc, s7_int size)
7373 #endif
7374 {
7375   s7_int free_cells;
7376   free_cells = sc->free_heap_top - sc->free_heap;
7377   if (free_cells < size)
7378     {
7379 #if S7_DEBUGGING
7380       gc(sc, func, line);
7381 #else
7382       gc(sc);
7383 #endif
7384       while ((sc->free_heap_top - sc->free_heap) < size)
7385 	resize_heap(sc);
7386     }
7387 }
7388 
7389 #define ALLOC_POINTER_SIZE 256
7390 static s7_cell *alloc_pointer(s7_scheme *sc)
7391 {
7392   if (sc->alloc_pointer_k == ALLOC_POINTER_SIZE)     /* if either no current block or the block is used up, make a new block */
7393     {
7394       sc->permanent_cells += ALLOC_POINTER_SIZE;
7395       sc->alloc_pointer_cells = (s7_cell *)Calloc(ALLOC_POINTER_SIZE, sizeof(s7_cell));
7396       add_saved_pointer(sc, sc->alloc_pointer_cells);
7397       sc->alloc_pointer_k = 0;
7398     }
7399   return(&(sc->alloc_pointer_cells[sc->alloc_pointer_k++]));
7400 }
7401 
7402 #define ALLOC_BIG_POINTER_SIZE 256
7403 static s7_big_cell *alloc_big_pointer(s7_scheme *sc, int64_t loc)
7404 {
7405   s7_big_pointer p;
7406   if (sc->alloc_big_pointer_k == ALLOC_BIG_POINTER_SIZE)
7407     {
7408       sc->permanent_cells += ALLOC_BIG_POINTER_SIZE;
7409       sc->alloc_big_pointer_cells = (s7_big_cell *)Calloc(ALLOC_BIG_POINTER_SIZE, sizeof(s7_big_cell));
7410       add_saved_pointer(sc, sc->alloc_big_pointer_cells);
7411       sc->alloc_big_pointer_k = 0;
7412     }
7413   p = (&(sc->alloc_big_pointer_cells[sc->alloc_big_pointer_k++]));
7414   p->big_hloc = loc;
7415   /* needed if this new pointer is itself petrified later -- it's not from one of the heap blocks,
7416    *   but it's in the heap, and we'll need to know where it is in the heap to replace it
7417    */
7418   return(p);
7419 }
7420 
7421 static void add_permanent_object(s7_scheme *sc, s7_pointer obj) /* called by remove_from_heap */
7422 {
7423   gc_obj_t *g;
7424   g = (gc_obj_t *)Malloc(sizeof(gc_obj_t));
7425   g->p = obj;
7426   g->nxt = sc->permanent_objects;
7427   sc->permanent_objects = g;
7428 }
7429 
7430 static void add_permanent_let_or_slot(s7_scheme *sc, s7_pointer obj)
7431 {
7432   gc_obj_t *g;
7433   g = (gc_obj_t *)Malloc(sizeof(gc_obj_t));
7434   g->p = obj;
7435   g->nxt = sc->permanent_lets;
7436   sc->permanent_lets = g;
7437 }
7438 
7439 #if S7_DEBUGGING
7440 static const char *type_name_from_type(int32_t typ, article_t article);
7441 
7442 #define free_cell(Sc, P) free_cell_1(Sc, P, __LINE__)
7443 static void free_cell_1(s7_scheme *sc, s7_pointer p, int32_t line)
7444 #else
7445 static void free_cell(s7_scheme *sc, s7_pointer p)
7446 #endif
7447 {
7448 #if S7_DEBUGGING
7449   /* anything that needs gc_list attention should not be freed here */
7450   uint8_t typ;
7451   typ = unchecked_type(p);
7452   if ((t_freeze_p[typ]) || ((typ == T_SYMBOL) && (is_gensym(p))))
7453     fprintf(stderr, "free_cell of %s?\n", type_name_from_type(typ, NO_ARTICLE));
7454   p->debugger_bits = 0;
7455   p->explicit_free_line = line;
7456 #endif
7457   clear_type(p);
7458   (*(sc->free_heap_top++)) = p;
7459 }
7460 
7461 static inline s7_pointer petrify(s7_scheme *sc, s7_pointer x)
7462 {
7463   s7_pointer p;
7464   int64_t loc;
7465   loc = heap_location(sc, x);
7466   p = (s7_pointer)alloc_big_pointer(sc, loc);
7467   sc->heap[loc] = p;
7468   free_cell(sc, p);
7469   unheap(sc, x);
7470   /* set_immutable(x); */ /* if there are GC troubles, this might catch them? */
7471   return(x);
7472 }
7473 
7474 static inline void s7_remove_from_heap(s7_scheme *sc, s7_pointer x)
7475 {
7476   /* global functions are very rarely redefined, so we can remove the function body from
7477    *   the heap when it is defined.  If redefined, we currently lose the memory held by the
7478    *   old definition.  (It is not trivial to recover this memory because it is allocated
7479    *   in blocks, not by the pointer, I think, but s7_define is the point to try).
7480    */
7481   if (not_in_heap(x)) return;
7482   if (is_pair(x))
7483     {
7484       s7_pointer p;
7485       p = x;
7486       do {
7487 	petrify(sc, p);
7488 	s7_remove_from_heap(sc, car(p));
7489 	p = cdr(p);
7490       } while (is_pair(p) && (in_heap(p)));
7491       if (in_heap(p)) petrify(sc, p);
7492       return;
7493     }
7494 
7495   switch (type(x))
7496     {
7497     case T_LET:
7498       if (is_funclet(x)) set_immutable(x);
7499     case T_HASH_TABLE:
7500     case T_VECTOR:
7501       /* not int|float_vector or string because none of their elements are GC-able (so unheap below is ok)
7502        *   but hash-table and let seem like they need protection? And let does happen via define-class.
7503        */
7504       add_permanent_object(sc, x);
7505       return;
7506 
7507     case T_SYMBOL:
7508       if (is_gensym(x))
7509 	{
7510 	  s7_int i;
7511 	  gc_list_t *gp;
7512 	  int64_t loc;
7513 	  loc = heap_location(sc, x);
7514 	  sc->heap[loc] = (s7_pointer)alloc_big_pointer(sc, loc);
7515 	  free_cell(sc, sc->heap[loc]);
7516 	  unheap(sc, x);
7517 
7518 	  gp = sc->gensyms;
7519 	  for (i = 0; i < gp->loc; i++) /* sc->gensyms reaches size 512 during s7test, but this search is called 3 times and costs nothing */
7520 	    if (gp->list[i] == x)
7521 	      {
7522 		s7_int j;
7523 		for (j = i + 1; i < gp->loc - 1; i++, j++)
7524 		  gp->list[i] = gp->list[j];
7525 		gp->list[i] = NULL;
7526 		gp->loc--;
7527 		if (gp->loc == 0) mark_function[T_SYMBOL] = mark_noop;
7528 		break;
7529 	      }}
7530       return;
7531 
7532     case T_CLOSURE: case T_CLOSURE_STAR:
7533     case T_MACRO:   case T_MACRO_STAR:
7534     case T_BACRO:   case T_BACRO_STAR:
7535       /* these need to be GC-protected! */
7536       add_permanent_object(sc, x);
7537       return;
7538 
7539     default:
7540       break;
7541     }
7542 
7543   petrify(sc, x);
7544 }
7545 
7546 
7547 /* -------------------------------- stacks -------------------------------- */
7548 
7549 #define OP_STACK_INITIAL_SIZE 64
7550 
7551 #if S7_DEBUGGING
7552 static void push_op_stack(s7_scheme *sc, s7_pointer op)
7553 {
7554   (*sc->op_stack_now++) = T_Pos(op);
7555   if (sc->op_stack_now > (sc->op_stack + sc->op_stack_size))
7556     {
7557       fprintf(stderr, "%sop_stack overflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
7558       if (sc->stop_at_error) abort();
7559     }
7560 }
7561 
7562 static s7_pointer pop_op_stack(s7_scheme *sc)
7563 {
7564   s7_pointer op;
7565   op = (*(--(sc->op_stack_now)));
7566   if (sc->op_stack_now < sc->op_stack)
7567     {
7568       fprintf(stderr, "%sop_stack underflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
7569       if (sc->stop_at_error) abort();
7570     }
7571   return(T_Pos(op));
7572 }
7573 #else
7574 #define push_op_stack(Sc, Op) (*Sc->op_stack_now++) = Op
7575 #define pop_op_stack(Sc)      (*(--(Sc->op_stack_now)))
7576 #endif
7577 
7578 static void initialize_op_stack(s7_scheme *sc)
7579 {
7580   int32_t i;
7581   sc->op_stack = (s7_pointer *)malloc(OP_STACK_INITIAL_SIZE * sizeof(s7_pointer));
7582   sc->op_stack_size = OP_STACK_INITIAL_SIZE;
7583   sc->op_stack_now = sc->op_stack;
7584   sc->op_stack_end = (s7_pointer *)(sc->op_stack + sc->op_stack_size);
7585   for (i = 0; i < OP_STACK_INITIAL_SIZE; i++)
7586     sc->op_stack[i] = sc->nil;
7587 }
7588 
7589 static void resize_op_stack(s7_scheme *sc)
7590 {
7591   int32_t i, loc, new_size;
7592   loc = (int32_t)(sc->op_stack_now - sc->op_stack);
7593   new_size = sc->op_stack_size * 2;
7594   sc->op_stack = (s7_pointer *)Realloc((void *)(sc->op_stack), new_size * sizeof(s7_pointer));
7595   for (i = sc->op_stack_size; i < new_size; i++)
7596     sc->op_stack[i] = sc->nil;
7597   sc->op_stack_size = (uint32_t)new_size;
7598   sc->op_stack_now = (s7_pointer *)(sc->op_stack + loc);
7599   sc->op_stack_end = (s7_pointer *)(sc->op_stack + sc->op_stack_size);
7600 }
7601 
7602 #if S7_DEBUGGING
7603 static void pop_stack(s7_scheme *sc)
7604 {
7605   sc->stack_end -= 4;
7606   if (sc->stack_end < sc->stack_start)
7607     {
7608       fprintf(stderr, "%sstack underflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
7609       if (sc->stop_at_error) abort();
7610     }
7611   /* here and in push_stack, both code and args might be non-free only because they've been retyped
7612    *   inline (as in named let) -- they actually don't make sense in these cases, but are ignored,
7613    *   and are carried around as GC protection in other cases.
7614    */
7615   sc->code = T_Pos(sc->stack_end[0]);
7616   sc->curlet = T_Pos(sc->stack_end[1]);  /* not T_Lid, see below */
7617   sc->args = T_Pos(sc->stack_end[2]);
7618   sc->cur_op = (opcode_t)(sc->stack_end[3]);
7619   if (sc->cur_op >= NUM_OPS)
7620     {
7621       fprintf(stderr, "%spop_stack[%d] invalid opcode: %" print_pointer " %s\n", BOLD_TEXT, __LINE__, sc->cur_op, UNBOLD_TEXT);
7622       if (sc->stop_at_error) abort();
7623     }
7624 }
7625 
7626 static void pop_stack_no_op(s7_scheme *sc)
7627 {
7628   sc->stack_end -= 4;
7629   if (sc->stack_end < sc->stack_start)
7630     {
7631       fprintf(stderr, "%sstack underflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
7632       if (sc->stop_at_error) abort();
7633     }
7634   sc->code = T_Pos(sc->stack_end[0]);
7635   sc->curlet = T_Pos(sc->stack_end[1]); /* not T_Lid: gc_protect can set this directly (not through push_stack) to anything */
7636   sc->args = T_Pos(sc->stack_end[2]);
7637 }
7638 
7639 #define push_stack(Sc, Op, Args, Code)	\
7640   do {s7_pointer *_end_; _end_ = Sc->stack_end; push_stack_1(Sc, Op, Args, Code, _end_, __func__, __LINE__);} while (0)
7641 
7642 static void push_stack_1(s7_scheme *sc, opcode_t op, s7_pointer args, s7_pointer code, s7_pointer *end, const char *func, int line)
7643 {
7644   if (sc->stack_end >= sc->stack_start + sc->stack_size)
7645     {
7646       fprintf(stderr, "%s%s[%d]: stack overflow%s\n", BOLD_TEXT, func, line, UNBOLD_TEXT);
7647       if (sc->stop_at_error) abort();
7648     }
7649   if (sc->stack_end != end)
7650     fprintf(stderr, "%s[%d]: stack changed in push_stack\n", func, line);
7651   if (op >= NUM_OPS)
7652     {
7653       fprintf(stderr, "%s%s[%d]: push_stack invalid opcode: %" print_pointer " %s\n", BOLD_TEXT, func, line, sc->cur_op, UNBOLD_TEXT);
7654       if (sc->stop_at_error) abort();
7655     }
7656   if (code) sc->stack_end[0] = T_Pos(code);
7657   sc->stack_end[1] = T_Lid(sc->curlet);
7658   if ((args) && (unchecked_type(args) != T_FREE)) sc->stack_end[2] = T_Pos(args);
7659   sc->stack_end[3] = (s7_pointer)op;
7660   sc->stack_end += 4;
7661 }
7662 
7663 #define push_stack_no_code(Sc, Op, Args)        push_stack(Sc, Op, Args, sc->unused)
7664 #define push_stack_no_let_no_code(Sc, Op, Args) push_stack(Sc, Op, Args, sc->unused)
7665 #define push_stack_no_args(Sc, Op, Code)        push_stack(Sc, Op, sc->unused, Code)
7666 #define push_stack_no_let(Sc, Op, Args, Code)   push_stack(Sc, Op, Args, Code)
7667 #define push_stack_op(Sc, Op)                   push_stack(Sc, Op, sc->unused, sc->unused)
7668 #define push_stack_op_let(Sc, Op)               push_stack(Sc, Op, sc->unused, sc->unused)
7669 #define push_stack_direct(Sc, Op)               push_stack(Sc, Op, sc->args, sc->code)
7670 #define push_stack_no_args_direct(Sc, Op)       push_stack(Sc, Op, sc->unused, sc->code)
7671 /* in the non-debugging case, the sc->unused's here are not set, so we can (later) pop free cells */
7672 
7673 #else
7674 
7675 #define pop_stack(Sc) do {Sc->stack_end -= 4; memcpy((void *)Sc, (void *)(Sc->stack_end), 4 * sizeof(s7_pointer));} while (0)
7676 #define pop_stack_no_op(Sc) {Sc->stack_end -= 4; memcpy((void *)Sc, (void *)(Sc->stack_end), 3 * sizeof(s7_pointer));} while (0)
7677 
7678 #define push_stack(Sc, Op, Args, Code) \
7679   do { \
7680       Sc->stack_end[0] = Code; \
7681       Sc->stack_end[1] = sc->curlet; \
7682       Sc->stack_end[2] = Args; \
7683       Sc->stack_end[3] = (s7_pointer)(Op); \
7684       Sc->stack_end += 4; \
7685   } while (0)
7686 
7687 #define push_stack_direct(Sc, Op) \
7688   do { \
7689       memcpy((void *)(Sc->stack_end), (void *)Sc, 3 * sizeof(s7_pointer)); \
7690       Sc->stack_end[3] = (s7_pointer)(Op); \
7691       Sc->stack_end += 4; \
7692   } while (0)
7693 
7694 #define push_stack_no_code(Sc, Op, Args) \
7695   do { \
7696       Sc->stack_end[1] = sc->curlet; \
7697       Sc->stack_end[2] = Args; \
7698       Sc->stack_end[3] = (s7_pointer)(Op); \
7699       Sc->stack_end += 4; \
7700   } while (0)
7701 
7702 #define push_stack_no_let_no_code(Sc, Op, Args) \
7703   do { \
7704       Sc->stack_end[2] = Args; \
7705       Sc->stack_end[3] = (s7_pointer)(Op); \
7706       Sc->stack_end += 4; \
7707   } while (0)
7708 
7709 #define push_stack_no_args(Sc, Op, Code) \
7710   do { \
7711       Sc->stack_end[0] = Code; \
7712       Sc->stack_end[1] = sc->curlet; \
7713       /* Sc->stack_end[2] = Sc->unused; */ \
7714       Sc->stack_end[3] = (s7_pointer)(Op); \
7715       Sc->stack_end += 4; \
7716   } while (0)
7717 
7718 #define push_stack_no_args_direct(Sc, Op) \
7719   do { \
7720       memcpy((void *)(Sc->stack_end), (void *)Sc, 2 * sizeof(s7_pointer));	\
7721       Sc->stack_end[2] = Sc->unused;	   \
7722       Sc->stack_end[3] = (s7_pointer)(Op); \
7723       Sc->stack_end += 4; \
7724   } while (0)
7725 
7726 #define push_stack_no_let(Sc, Op, Args, Code) \
7727   do { \
7728       Sc->stack_end[0] = Code; \
7729       Sc->stack_end[2] = Args; \
7730       Sc->stack_end[3] = (s7_pointer)(Op); \
7731       Sc->stack_end += 4; \
7732   } while (0)
7733 
7734 #define push_stack_op(Sc, Op) \
7735   do { \
7736       /* Sc->stack_end[2] = Sc->unused; */ \
7737       Sc->stack_end[3] = (s7_pointer)(Op); \
7738       Sc->stack_end += 4; \
7739   } while (0)
7740 
7741 #define push_stack_op_let(Sc, Op) \
7742   do { \
7743       Sc->stack_end[1] = sc->curlet; \
7744       /* Sc->stack_end[2] = Sc->unused; */ \
7745       Sc->stack_end[3] = (s7_pointer)(Op); \
7746       Sc->stack_end += 4; \
7747   } while (0)
7748 #endif
7749 /* since we don't GC mark the stack past the stack_top, push_stack_no_args and friends can cause pop_stack to set
7750  *   sc->code and sc->args to currently free objects.
7751  */
7752 
7753 #define main_stack_op(Sc)   ((opcode_t)(Sc->stack_end[-1]))
7754 /* #define main_stack_args(Sc) (Sc->stack_end[-2]) */
7755 /* #define main_stack_let(Sc)  (Sc->stack_end[-3]) */
7756 /* #define main_stack_code(Sc) (Sc->stack_end[-4]) */
7757 /* beware of main_stack_code!  If a function has a tail-call, the main_stack_code that form sees
7758  *   if main_stack_op==op-begin1 can change from call to call -- the begin actually refers
7759  *   to the caller, which is dependent on where the current function was called, so we can't hard-wire
7760  *   any optimizations based on that sequence.
7761  */
7762 
7763 static void stack_reset(s7_scheme *sc)
7764 {
7765   sc->stack_end = sc->stack_start;
7766   push_stack_op(sc, OP_EVAL_DONE);
7767   /* push_stack_op(sc, OP_BARRIER); */
7768 }
7769 
7770 static void resize_stack(s7_scheme *sc)
7771 {
7772   uint64_t loc;
7773   uint32_t new_size;
7774   block_t *ob, *nb;
7775 
7776   loc = current_stack_top(sc);
7777   new_size = sc->stack_size * 2;
7778 
7779   /* how can we trap infinite recursion?  Is a warning in order here? I think I'll add 'max-stack-size */
7780   if (new_size > sc->max_stack_size)
7781     s7_error(sc, make_symbol(sc, "stack-too-big"), set_elist_1(sc, wrap_string(sc, "stack has grown past (*s7* 'max-stack-size)", 43)));
7782 
7783   ob = stack_block(sc->stack);
7784   nb = reallocate(sc, ob, new_size * sizeof(s7_pointer));
7785   block_info(nb) = NULL;
7786   stack_block(sc->stack) = nb;
7787   stack_elements(sc->stack) = (s7_pointer *)block_data(nb);
7788   if (!stack_elements(sc->stack))
7789     s7_error(sc, make_symbol(sc, "stack-too-big"), set_elist_1(sc, wrap_string(sc, "no room to expand stack?", 24)));
7790   {
7791     s7_pointer *orig;
7792     s7_int i, left;
7793     i = sc->stack_size;
7794     left = new_size - i - 8;
7795     orig = stack_elements(sc->stack);
7796     while (i <= left)
7797       LOOP_8(orig[i++] = sc->nil);
7798     for (; i < new_size; i++)
7799       orig[i] = sc->nil;
7800   }
7801   vector_length(sc->stack) = new_size;
7802   sc->stack_size = new_size;
7803 
7804   sc->stack_start = stack_elements(sc->stack);
7805   sc->stack_end = (s7_pointer *)(sc->stack_start + loc);
7806   /* sc->stack_resize_trigger = (s7_pointer *)(sc->stack_start + sc->stack_size / 2); */
7807   sc->stack_resize_trigger = (s7_pointer *)(sc->stack_start + (new_size - STACK_RESIZE_TRIGGER));
7808 
7809   if (show_stack_stats(sc))
7810     {
7811       s7_warn(sc, 128, "stack grows to %u, %s\n", new_size, display_80(current_code(sc)));
7812       s7_show_let(sc);
7813     }
7814 }
7815 
7816 #define check_stack_size(Sc) do {if (Sc->stack_end >= Sc->stack_resize_trigger) resize_stack(Sc);} while (0)
7817 
7818 s7_pointer s7_gc_protect_via_stack(s7_scheme *sc, s7_pointer x)
7819 {
7820   push_stack_no_let_no_code(sc, OP_GC_PROTECT, x);
7821   return(x);
7822 }
7823 
7824 s7_pointer s7_gc_unprotect_via_stack(s7_scheme *sc, s7_pointer x)
7825 {
7826   sc->stack_end -= 4;
7827   return(x);
7828 }
7829 
7830 
7831 /* -------------------------------- symbols -------------------------------- */
7832 
7833 #if __cplusplus
7834 static uint64_t raw_string_hash(const uint8_t *key, s7_int len)
7835 #else
7836 static inline uint64_t raw_string_hash(const uint8_t *key, s7_int len)
7837 #endif
7838 {
7839   uint64_t x;
7840   uint8_t *cx = (uint8_t *)&x;
7841   x = 0;
7842   if (len <= 8)
7843     memcpy((void *)cx, (void *)key, len);
7844   else
7845     {
7846       uint64_t y;
7847       uint8_t *cy = (uint8_t *)&y;
7848       memcpy((void *)cx, (void *)key, 8);
7849       y = 0;
7850       len -= 8;
7851       memcpy((void *)cy, (void *)(key + 8), (len > 8) ? 8 : len); /* compiler complaint here is bogus */
7852       x += y;  /* better than |= but still not great if (for example) > 1B gensyms -- maybe add z? */
7853     }
7854   return(x);
7855 }
7856 
7857 static uint8_t *alloc_symbol(s7_scheme *sc)
7858 {
7859   #define SYMBOL_SIZE (3 * sizeof(s7_cell) + sizeof(block_t))
7860   #define ALLOC_SYMBOL_SIZE (64 * SYMBOL_SIZE)
7861   uint8_t *result;
7862 
7863   if (sc->alloc_symbol_k == ALLOC_SYMBOL_SIZE)
7864     {
7865       sc->alloc_symbol_cells = (uint8_t *)Malloc(ALLOC_SYMBOL_SIZE);
7866       add_saved_pointer(sc, sc->alloc_symbol_cells);
7867       sc->alloc_symbol_k = 0;
7868     }
7869   result = &(sc->alloc_symbol_cells[sc->alloc_symbol_k]);
7870   sc->alloc_symbol_k += SYMBOL_SIZE;
7871   return(result);
7872 }
7873 
7874 static s7_pointer make_permanent_slot(s7_scheme *sc, s7_pointer symbol, s7_pointer value);
7875 static inline s7_pointer make_symbol_with_length(s7_scheme *sc, const char *name, s7_int len);
7876 
7877 static inline s7_pointer new_symbol(s7_scheme *sc, const char *name, s7_int len, uint64_t hash, uint32_t location)
7878 {
7879   /* name might not be null-terminated, these are permanent symbols even in s7_gensym; g_gensym handles everything separately */
7880   s7_pointer x, str, p;
7881   uint8_t *base, *val;
7882 
7883   base = alloc_symbol(sc);
7884   x = (s7_pointer)base;
7885   str = (s7_pointer)(base + sizeof(s7_cell));
7886   p = (s7_pointer)(base + 2 * sizeof(s7_cell));
7887   val = (uint8_t *)permalloc(sc, len + 1);
7888   memcpy((void *)val, (void *)name, len);
7889   val[len] = '\0';
7890 
7891   full_type(str) = T_STRING | T_IMMUTABLE | T_UNHEAP;       /* avoid debugging confusion involving set_type (also below) */
7892   string_length(str) = len;
7893   string_value(str) = (char *)val;
7894   string_hash(str) = hash;
7895 
7896   full_type(x) = T_SYMBOL | T_UNHEAP;
7897   symbol_set_name_cell(x, str);
7898   set_global_slot(x, sc->undefined);                       /* was sc->nil */
7899   symbol_info(x) = (block_t *)(base + 3 * sizeof(s7_cell));
7900   set_initial_slot(x, sc->undefined);
7901   symbol_set_local_slot_unchecked_and_unincremented(x, 0LL, sc->nil);
7902   symbol_set_tag(x, 0);
7903   symbol_set_tag2(x, 0);
7904   symbol_clear_ctr(x); /* alloc_symbol uses malloc */
7905   symbol_clear_type(x);
7906   symbol_set_position(x, PD_POSITION_UNSET);
7907 
7908   if (len > 1)                                             /* not 0, otherwise : is a keyword */
7909     {
7910       if ((name[0] == ':') || (name[len - 1] == ':'))      /* see s7test under keyword? for troubles if both colons are present */
7911 	{
7912 	  s7_pointer slot, ksym;
7913 	  set_type_bit(x, T_IMMUTABLE | T_KEYWORD | T_GLOBAL);
7914 	  set_optimize_op(str, OP_CON);
7915 	  ksym = make_symbol_with_length(sc, (name[0] == ':') ? (char *)(name + 1) : name, len - 1);
7916 	  keyword_set_symbol(x, ksym);
7917 	  set_has_keyword(ksym);
7918 	  /* the keyword symbol needs to be permanent (not a gensym) else we have to laboriously gc-protect it */
7919 	  if ((is_gensym(ksym)) &&
7920 	      (in_heap(ksym)))
7921 	    s7_remove_from_heap(sc, ksym);
7922 	  slot = make_permanent_slot(sc, x, x);
7923 	  set_global_slot(x, slot);
7924 	  set_local_slot(x, slot);
7925 	}}
7926 
7927   full_type(p) = T_PAIR | T_IMMUTABLE | T_UNHEAP;  /* add x to the symbol table */
7928   set_car(p, x);
7929   set_cdr(p, vector_element(sc->symbol_table, location));
7930   vector_element(sc->symbol_table, location) = p;
7931   pair_set_raw_hash(p, hash);
7932   pair_set_raw_len(p, (uint64_t)len); /* symbol name length, so it ought to fit! */
7933   pair_set_raw_name(p, string_value(str));
7934 
7935   return(x);
7936 }
7937 
7938 static inline s7_pointer make_symbol_with_length(s7_scheme *sc, const char *name, s7_int len)
7939 {
7940   s7_pointer x;
7941   uint64_t hash;
7942   uint32_t location;
7943 
7944   hash = raw_string_hash((const uint8_t *)name, len);
7945   location = hash % SYMBOL_TABLE_SIZE;
7946 
7947   if (len <= 8)
7948     {
7949       for (x = vector_element(sc->symbol_table, location); is_pair(x); x = cdr(x))
7950 	if ((hash == pair_raw_hash(x)) &&
7951 	    ((uint64_t)len == pair_raw_len(x)))
7952 	  return(car(x));
7953     }
7954   else
7955     {
7956       for (x = vector_element(sc->symbol_table, location); is_pair(x); x = cdr(x))
7957 	if ((hash == pair_raw_hash(x)) &&
7958 	    ((uint64_t)len == pair_raw_len(x)) &&
7959 	    (strings_are_equal_with_length(name, pair_raw_name(x), len))) /* length here because name might not be null-terminated */
7960 	  return(car(x));
7961     }
7962   return(new_symbol(sc, name, len, hash, location));
7963 }
7964 
7965 static s7_pointer make_symbol(s7_scheme *sc, const char *name) {return(make_symbol_with_length(sc, name, safe_strlen(name)));}
7966 
7967 s7_pointer s7_make_symbol(s7_scheme *sc, const char *name) {return((name) ? make_symbol_with_length(sc, name, safe_strlen(name)) : sc->F);}
7968 
7969 static s7_pointer symbol_table_find_by_name(s7_scheme *sc, const char *name, uint64_t hash, uint32_t location, s7_int len)
7970 {
7971   s7_pointer x;
7972   for (x = vector_element(sc->symbol_table, location); is_not_null(x); x = cdr(x))
7973     if ((hash == pair_raw_hash(x)) &&
7974 	(strings_are_equal_with_length(name, pair_raw_name(x), len)))
7975       return(car(x));
7976   return(sc->nil);
7977 }
7978 
7979 s7_pointer s7_symbol_table_find_name(s7_scheme *sc, const char *name)
7980 {
7981   uint64_t hash;
7982   uint32_t location;
7983   s7_pointer result;
7984   s7_int len;
7985 
7986   hash = raw_string_hash((const uint8_t *)name, len = safe_strlen(name));
7987   location = hash % SYMBOL_TABLE_SIZE;
7988   result = symbol_table_find_by_name(sc, name, hash, location, len);
7989   if (is_null(result))
7990     return(NULL);
7991 
7992   return(result);
7993 }
7994 
7995 #define FILLED true
7996 #define NOT_FILLED false
7997 
7998 
7999 /* -------------------------------- symbol-table -------------------------------- */
8000 static inline s7_pointer make_simple_vector(s7_scheme *sc, s7_int len);
8001 
8002 static s7_pointer g_symbol_table(s7_scheme *sc, s7_pointer args)
8003 {
8004   #define H_symbol_table "(symbol-table) returns a vector containing the current symbol-table symbols"
8005   #define Q_symbol_table s7_make_signature(sc, 1, sc->is_vector_symbol)
8006 
8007   s7_pointer lst, x;
8008   s7_pointer *els, *entries;
8009   int32_t i, j, syms = 0;
8010 
8011   /* this can't be optimized by returning the actual symbol-table (a vector of lists), because
8012    *    gensyms can cause the table's lists and symbols to change at any time.  This wreaks havoc
8013    *    on traversals like for-each.  So, symbol-table returns a snap-shot of the table contents
8014    *    at the time it is called.
8015    *    (define (for-each-symbol func num) (for-each (lambda (sym) (if (> num 0) (for-each-symbol func (- num 1)) (func sym))) (symbol-table)))
8016    *    (for-each-symbol (lambda (sym) (gensym) 1))
8017    */
8018   entries = vector_elements(sc->symbol_table);
8019   for (i = 0; i < SYMBOL_TABLE_SIZE; i++)
8020     for (x = entries[i]; is_not_null(x); x = cdr(x))
8021       syms++;
8022   sc->w = make_simple_vector(sc, syms);
8023   els = vector_elements(sc->w);
8024 
8025   for (i = 0, j = 0; i < SYMBOL_TABLE_SIZE; i++)
8026     for (x = entries[i]; is_not_null(x); x = cdr(x))
8027       els[j++] = car(x);
8028 
8029   lst = sc->w;
8030   sc->w = sc->nil;
8031   return(lst);
8032 }
8033 
8034 bool s7_for_each_symbol_name(s7_scheme *sc, bool (*symbol_func)(const char *symbol_name, void *data), void *data)
8035 {
8036   /* this includes the special constants #<unspecified> and so on for simplicity -- are there any others? */
8037   int32_t i;
8038   s7_pointer x;
8039 
8040   for (i = 0; i < SYMBOL_TABLE_SIZE; i++)
8041     for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
8042       if (symbol_func(symbol_name(car(x)), data))
8043 	return(true);
8044 
8045   return((symbol_func("#t", data))             ||
8046 	 (symbol_func("#f", data))             ||
8047 	 (symbol_func("#<unspecified>", data)) ||
8048 	 (symbol_func("#<undefined>", data))   ||
8049 	 (symbol_func("#<eof>", data))         ||
8050 	 (symbol_func("#true", data))          ||
8051 	 (symbol_func("#false", data)));
8052 }
8053 
8054 bool s7_for_each_symbol(s7_scheme *sc, bool (*symbol_func)(const char *symbol_name, void *data), void *data)
8055 {
8056   int32_t i;
8057   s7_pointer x;
8058 
8059   for (i = 0; i < SYMBOL_TABLE_SIZE; i++)
8060     for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
8061       if (symbol_func(symbol_name(car(x)), data))
8062 	return(true);
8063 
8064   return(false);
8065 }
8066 
8067 /* -------------------------------- gensym -------------------------------- */
8068 static void remove_gensym_from_symbol_table(s7_scheme *sc, s7_pointer sym)
8069 {
8070   /* sym is a free cell at this point (we're called after the GC), but the name_cell is still intact */
8071   s7_pointer x, name;
8072   uint32_t location;
8073 
8074   name = symbol_name_cell(sym);
8075   location = string_hash(name) % SYMBOL_TABLE_SIZE;
8076   x = vector_element(sc->symbol_table, location);
8077 
8078   if (car(x) == sym)
8079     vector_element(sc->symbol_table, location) = cdr(x);
8080   else
8081     {
8082       s7_pointer y;
8083       for (y = x, x = cdr(x); is_pair(x); y = x, x = cdr(x))
8084 	if (car(x) == sym)
8085 	  {
8086 	    set_cdr(y, cdr(x));
8087 	    return;
8088 	  }
8089 #if S7_DEBUGGING
8090       fprintf(stderr, "could not remove %s?\n", string_value(name));
8091 #endif
8092     }
8093 }
8094 
8095 s7_pointer s7_gensym(s7_scheme *sc, const char *prefix)
8096 {
8097   block_t *b;
8098   char *name;
8099   uint32_t location;
8100   s7_int len;
8101   uint64_t hash;
8102   s7_pointer x;
8103 
8104   len = safe_strlen(prefix) + 32;
8105   b = mallocate(sc, len);
8106   name = (char *)block_data(b);
8107   /* there's no point in heroic efforts here to avoid name collisions -- the user can screw up no matter what we do */
8108   name[0] = '\0';
8109   len = catstrs(name, len, "{", (prefix) ? prefix : "", "}-", pos_int_to_str_direct(sc, sc->gensym_counter++), (char *)NULL);
8110   hash = raw_string_hash((const uint8_t *)name, len);
8111   location = hash % SYMBOL_TABLE_SIZE;
8112   x = new_symbol(sc, name, len, hash, location);  /* not T_GENSYM -- might be called from outside */
8113   liberate(sc, b);
8114   return(x);
8115 }
8116 
8117 static bool s7_is_gensym(s7_pointer g) {return((is_symbol(g)) && (is_gensym(g)));}
8118 
8119 static s7_pointer g_is_gensym(s7_scheme *sc, s7_pointer args)
8120 {
8121   #define H_is_gensym "(gensym? sym) returns #t if sym is a gensym"
8122   #define Q_is_gensym sc->pl_bt
8123 
8124   check_boolean_method(sc, s7_is_gensym, sc->is_gensym_symbol, args);
8125 }
8126 
8127 static s7_pointer g_gensym(s7_scheme *sc, s7_pointer args)
8128 {
8129   #define H_gensym "(gensym (prefix \"gensym\")) returns a new, unused symbol"
8130   #define Q_gensym s7_make_signature(sc, 2, sc->is_gensym_symbol, sc->is_string_symbol)
8131 
8132   const char *prefix;
8133   char *name, *p, *base;
8134   s7_int len, plen, nlen;
8135   uint32_t location;
8136   uint64_t hash;
8137   s7_pointer x, str, stc;
8138   block_t *b, *ib;
8139 
8140   /* get symbol name */
8141   if (is_not_null(args))
8142     {
8143       s7_pointer gname;
8144       gname = car(args);
8145       if (!is_string(gname))
8146 	return(method_or_bust_one_arg(sc, gname, sc->gensym_symbol, args, T_STRING));
8147       prefix = string_value(gname);
8148       plen = safe_strlen(prefix);
8149     }
8150   else
8151     {
8152       prefix = "gensym";
8153       plen = 6;
8154     }
8155   len = plen + 32; /* why 32 -- we need room for the gensym_counter integer, but (length "9223372036854775807") = 19 */
8156 
8157   b = mallocate(sc, len + sizeof(block_t) + 2 * sizeof(s7_cell));
8158   /* only 16 of block_t size is actually needed here because only the ln.tag (symbol_tag2) field is used in the embedded block_t */
8159   base = (char *)block_data(b);
8160   str = (s7_cell *)base;
8161   stc = (s7_cell *)(base + sizeof(s7_cell));
8162   ib = (block_t *)(base + 2 * sizeof(s7_cell));
8163   name = (char *)(base + sizeof(block_t) + 2 * sizeof(s7_cell));
8164 
8165   name[0] = '{';
8166   if (plen > 0) memcpy((void *)(name + 1), prefix, plen);
8167   name[plen + 1] = '}';
8168   name[plen + 2] = '-'; /* {gensym}-nnn */
8169 
8170   p = pos_int_to_str(sc, sc->gensym_counter++, &len, '\0');
8171   memcpy((void *)(name + plen + 3), (void *)p, len);
8172   nlen = len + plen + 2;
8173 #if S7_DEBUGGING
8174   if ((s7_int)strlen(name) != nlen)
8175     fprintf(stderr, "%s[%d]: %s len: %" print_s7_int " != %" print_s7_int "\n", __func__, __LINE__, name, nlen, (s7_int)strlen(name));
8176 #endif
8177 
8178   hash = raw_string_hash((const uint8_t *)name, nlen);
8179   location = hash % SYMBOL_TABLE_SIZE;
8180 
8181   if ((sc->safety > 0) &&
8182       (!is_null(symbol_table_find_by_name(sc, name, hash, location, nlen))))
8183     s7_warn(sc, nlen + 32, "%s is already in use!", name);
8184 
8185   /* make-string for symbol name */
8186 #if S7_DEBUGGING
8187   full_type(str) = 0; /* here and below, this is needed to avoid set_type check errors (mallocate above) */
8188 #endif
8189   set_full_type(str, T_STRING | T_IMMUTABLE | T_UNHEAP);
8190   string_length(str) = nlen;
8191   string_value(str) = name;
8192   string_hash(str) = hash;
8193 
8194   /* allocate the symbol in the heap so GC'd when inaccessible */
8195   new_cell(sc, x, T_SYMBOL | T_GENSYM);
8196   symbol_set_name_cell(x, str);
8197   symbol_info(x) = ib;
8198   set_global_slot(x, sc->undefined);
8199   /* set_initial_slot(x, sc->undefined); */
8200   symbol_set_local_slot_unchecked(x, 0LL, sc->nil);
8201   symbol_clear_ctr(x);
8202   symbol_set_tag(x, 0);
8203   symbol_set_tag2(x, 0);
8204   symbol_clear_type(x);
8205   symbol_set_position(x, PD_POSITION_UNSET);
8206   gensym_block(x) = b;
8207 
8208   /* place new symbol in symbol-table, but using calloc so we can easily free it (remove it from the table) in GC sweep */
8209 #if S7_DEBUGGING
8210   full_type(stc) = 0;
8211 #endif
8212   set_full_type(stc, T_PAIR | T_IMMUTABLE | T_UNHEAP);
8213   set_car(stc, x);
8214   set_cdr(stc, vector_element(sc->symbol_table, location));
8215   vector_element(sc->symbol_table, location) = stc;
8216   pair_set_raw_hash(stc, hash);
8217   pair_set_raw_len(stc, (uint64_t)string_length(str));
8218   pair_set_raw_name(stc, string_value(str));
8219 
8220   add_gensym(sc, x);
8221   return(x);
8222 }
8223 
8224 
8225 /* -------------------------------- syntax? -------------------------------- */
8226 bool s7_is_syntax(s7_pointer p) {return(is_syntax(p));}
8227 
8228 static s7_pointer g_is_syntax(s7_scheme *sc, s7_pointer args)
8229 {
8230   #define H_is_syntax "(syntax? obj) returns #t if obj is a syntactic value (e.g. lambda)"
8231   #define Q_is_syntax sc->pl_bt
8232 
8233   check_boolean_method(sc, is_syntax, sc->is_syntax_symbol, args);
8234 }
8235 
8236 
8237 /* -------------------------------- symbol? -------------------------------- */
8238 bool s7_is_symbol(s7_pointer p) {return(is_symbol(p));}
8239 
8240 static s7_pointer g_is_symbol(s7_scheme *sc, s7_pointer args)
8241 {
8242   #define H_is_symbol "(symbol? obj) returns #t if obj is a symbol"
8243   #define Q_is_symbol sc->pl_bt
8244 
8245   check_boolean_method(sc, is_symbol, sc->is_symbol_symbol, args);
8246 }
8247 
8248 const char *s7_symbol_name(s7_pointer p) {return(symbol_name(p));}
8249 s7_pointer s7_name_to_value(s7_scheme *sc, const char *name) {return(s7_symbol_value(sc, make_symbol(sc, name)));}
8250 
8251 
8252 /* -------------------------------- symbol->string -------------------------------- */
8253 
8254 static Inline s7_pointer inline_make_string_with_length(s7_scheme *sc, const char *str, s7_int len)
8255 {
8256   s7_pointer x;
8257   new_cell(sc, x, T_STRING | T_SAFE_PROCEDURE);
8258   string_block(x) = mallocate(sc, len + 1);
8259   string_value(x) = (char *)block_data(string_block(x));
8260   if (len > 0)
8261     memcpy((void *)string_value(x), (void *)str, len);
8262   string_value(x)[len] = 0;
8263   string_length(x) = len;
8264   string_hash(x) = 0;
8265   add_string(sc, x);
8266   return(x);
8267 }
8268 
8269 static inline s7_pointer make_string_with_length(s7_scheme *sc, const char *str, s7_int len)
8270 {
8271   return(inline_make_string_with_length(sc, str, len));
8272 }
8273 
8274 static s7_pointer g_symbol_to_string(s7_scheme *sc, s7_pointer args)
8275 {
8276   #define H_symbol_to_string "(symbol->string sym) returns the symbol sym converted to a string"
8277   #define Q_symbol_to_string s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_symbol_symbol)
8278   s7_pointer sym;
8279 
8280   sym = car(args);
8281   if (!is_symbol(sym))
8282     return(method_or_bust_one_arg(sc, sym, sc->symbol_to_string_symbol, args, T_SYMBOL));
8283   /* s7_make_string uses strlen which stops at an embedded null */
8284   return(inline_make_string_with_length(sc, symbol_name(sym), symbol_name_length(sym)));    /* return a copy */
8285 }
8286 
8287 static s7_pointer g_symbol_to_string_uncopied(s7_scheme *sc, s7_pointer args)
8288 {
8289   s7_pointer sym;
8290   sym = car(args);
8291   if (!is_symbol(sym))
8292     return(method_or_bust_one_arg(sc, sym, sc->symbol_to_string_symbol, args, T_SYMBOL));
8293   if (is_gensym(sym))
8294     return(make_string_with_length(sc, symbol_name(sym), symbol_name_length(sym)));    /* return a copy of gensym name (which will be freed) */
8295   return(symbol_name_cell(sym));
8296 }
8297 
8298 static s7_pointer symbol_to_string_p_p(s7_scheme *sc, s7_pointer sym)
8299 {
8300   if (!is_symbol(sym))
8301     simple_wrong_type_argument(sc, sc->symbol_to_string_symbol, sym, T_SYMBOL);
8302   return(inline_make_string_with_length(sc, symbol_name(sym), symbol_name_length(sym)));
8303 }
8304 
8305 static s7_pointer symbol_to_string_uncopied_p(s7_scheme *sc, s7_pointer sym)
8306 {
8307   if (!is_symbol(sym))
8308     simple_wrong_type_argument(sc, sc->symbol_to_string_symbol, sym, T_SYMBOL);
8309   if (is_gensym(sym))
8310     return(make_string_with_length(sc, symbol_name(sym), symbol_name_length(sym)));
8311   return(symbol_name_cell(sym));
8312 }
8313 
8314 
8315 /* -------------------------------- string->symbol -------------------------------- */
8316 static inline s7_pointer g_string_to_symbol_1(s7_scheme *sc, s7_pointer str, s7_pointer caller)
8317 {
8318   if (is_string(str))
8319     {
8320       if (string_length(str) > 0)
8321 	return(make_symbol_with_length(sc, string_value(str), string_length(str)));
8322       return(simple_wrong_type_argument_with_type(sc, caller, str, wrap_string(sc, "a non-null string", 17)));
8323       /* currently if the string has an embedded null, it marks the end of the new symbol name. */
8324     }
8325   return(method_or_bust_one_arg_p(sc, str, caller, T_STRING));
8326 }
8327 
8328 static s7_pointer g_string_to_symbol(s7_scheme *sc, s7_pointer args)
8329 {
8330   #define H_string_to_symbol "(string->symbol str) returns the string str converted to a symbol"
8331   #define Q_string_to_symbol s7_make_signature(sc, 2, sc->is_symbol_symbol, sc->is_string_symbol)
8332   return(g_string_to_symbol_1(sc, car(args), sc->string_to_symbol_symbol));
8333 }
8334 
8335 static s7_pointer string_to_symbol_p_p(s7_scheme *sc, s7_pointer p) {return(g_string_to_symbol_1(sc, p, sc->string_to_symbol_symbol));}
8336 
8337 
8338 /* -------------------------------- symbol -------------------------------- */
8339 static s7_pointer g_string_append_1(s7_scheme *sc, s7_pointer args, s7_pointer caller);
8340 
8341 static s7_pointer g_symbol(s7_scheme *sc, s7_pointer args)
8342 {
8343   #define H_symbol "(symbol str ...) returns its string arguments concatenated and converted to a symbol"
8344   #define Q_symbol s7_make_circular_signature(sc, 1, 2, sc->is_symbol_symbol, sc->is_string_symbol)
8345 
8346   s7_int len = 0, cur_len;
8347   s7_pointer p, sym;
8348   block_t *b;
8349   char *name;
8350 
8351   for (p = args; is_pair(p); p = cdr(p))
8352     if (is_string(car(p)))
8353       len += string_length(car(p));
8354     else break;
8355 
8356   if (is_pair(p))
8357     {
8358       if (is_null(cdr(args)))
8359 	return(g_string_to_symbol_1(sc, car(args), sc->symbol_symbol));
8360       return(g_string_to_symbol_1(sc, g_string_append_1(sc, args, sc->symbol_symbol), sc->symbol_symbol));
8361     }
8362   if (len == 0)
8363     return(simple_wrong_type_argument_with_type(sc, sc->symbol_symbol, car(args), wrap_string(sc, "a non-null string", 17)));
8364 
8365   b = mallocate(sc, len + 1);
8366   name = (char *)block_data(b);
8367   /* can't use catstrs_direct here because it stops at embedded null */
8368   cur_len = 0;
8369   for (p = args; is_pair(p); p = cdr(p))
8370     {
8371       s7_pointer str;
8372       str = car(p);
8373       if (string_length(str) > 0)
8374 	{
8375 	  memcpy((void *)(name + cur_len), (void *)string_value(str), string_length(str));
8376 	  cur_len += string_length(str);
8377 	}}
8378   name[len] = '\0';
8379   sym = make_symbol_with_length(sc, name, len);
8380   liberate(sc, b);
8381   return(sym);
8382 }
8383 
8384 /* p_p case can use string_to_symbol_p_p */
8385 static s7_pointer symbol_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
8386 {
8387   char buf[256];
8388   s7_int len;
8389   if ((!is_string(p1)) || (!is_string(p2))) return(g_symbol(sc, set_plist_2(sc, p1, p2)));
8390   len = string_length(p1) + string_length(p2);
8391   if ((len == 0) || (len >= 256)) return(g_symbol(sc, set_plist_2(sc, p1, p2)));
8392   memcpy((void *)buf, (void *)string_value(p1), string_length(p1));
8393   memcpy((void *)(buf + string_length(p1)), (void *)string_value(p2), string_length(p2));
8394   return(make_symbol_with_length(sc, buf, len));
8395 }
8396 
8397 
8398 /* -------- symbol sets -------- */
8399 static inline s7_pointer add_symbol_to_list(s7_scheme *sc, s7_pointer sym)
8400 {
8401   symbol_set_tag(sym, sc->syms_tag);
8402   symbol_set_tag2(sym, sc->syms_tag2);
8403   return(sym);
8404 }
8405 
8406 static inline void clear_symbol_list(s7_scheme *sc)
8407 {
8408   sc->syms_tag++;
8409   if (sc->syms_tag == 0)
8410     {
8411       sc->syms_tag = 1; /* we're assuming (in let_equal) that this tag is not 0 */
8412       sc->syms_tag2++;
8413     }
8414 }
8415 
8416 #define symbol_is_in_list(Sc, Sym) ((symbol_tag(Sym) == Sc->syms_tag) && (symbol_tag2(Sym) == Sc->syms_tag2))
8417 
8418 
8419 /* -------------------------------- lets/slots -------------------------------- */
8420 
8421 static Inline s7_pointer make_let(s7_scheme *sc, s7_pointer old_let)
8422 {
8423   s7_pointer x;
8424   new_cell(sc, x, T_LET | T_SAFE_PROCEDURE);
8425   let_set_id(x, ++sc->let_number);
8426   let_set_slots(x, slot_end(sc));
8427   let_set_outlet(x, old_let);
8428   return(x);
8429 }
8430 
8431 static inline s7_pointer make_let_slowly(s7_scheme *sc, s7_pointer old_let)
8432 {
8433   s7_pointer x;
8434   new_cell(sc, x, T_LET | T_SAFE_PROCEDURE);
8435   let_set_id(x, ++sc->let_number);
8436   let_set_slots(x, slot_end(sc));
8437   let_set_outlet(x, old_let);
8438   return(x);
8439 }
8440 
8441 static inline s7_pointer make_simple_let(s7_scheme *sc) /* called only in op_let_fx */
8442 {
8443   s7_pointer let;
8444   new_cell(sc, let, T_LET | T_SAFE_PROCEDURE);
8445   let_set_id(let, sc->let_number + 1);
8446   let_set_slots(let, slot_end(sc));
8447   let_set_outlet(let, sc->curlet);
8448   return(let);
8449 }
8450 
8451 static Inline s7_pointer make_let_with_slot(s7_scheme *sc, s7_pointer old_let, s7_pointer symbol, s7_pointer value)
8452 {
8453   s7_pointer new_let, slot;
8454   new_cell(sc, new_let, T_LET | T_SAFE_PROCEDURE);
8455   let_set_id(new_let, ++sc->let_number);
8456   let_set_outlet(new_let, old_let);
8457   new_cell_no_check(sc, slot, T_SLOT);
8458   slot_set_symbol(slot, symbol);
8459   slot_set_value(slot, value);
8460   symbol_set_local_slot(symbol, sc->let_number, slot);
8461   slot_set_next(slot, slot_end(sc));
8462   let_set_slots(new_let, slot);
8463   return(new_let);
8464 }
8465 
8466 static Inline s7_pointer make_let_with_two_slots(s7_scheme *sc, s7_pointer old_let, s7_pointer symbol1, s7_pointer value1, s7_pointer symbol2, s7_pointer value2)
8467 {
8468   /* we leave value1/value2 computation order to the C compiler here -- in the old macro, it was explicitly value1 then value2
8469    *   this means any let in old scheme code that actually depends on the order may break -- it should be let*.
8470    */
8471   s7_pointer new_let, slot1, slot2;
8472   new_cell(sc, new_let, T_LET | T_SAFE_PROCEDURE);
8473   let_set_id(new_let, ++sc->let_number);
8474   let_set_outlet(new_let, old_let);
8475 
8476   new_cell_no_check(sc, slot1, T_SLOT);
8477   slot_set_symbol(slot1, symbol1);
8478   slot_set_value(slot1, value1);
8479   symbol_set_local_slot(symbol1, sc->let_number, slot1);
8480   let_set_slots(new_let, slot1);
8481 
8482   new_cell_no_check(sc, slot2, T_SLOT);
8483   slot_set_symbol(slot2, symbol2);
8484   slot_set_value(slot2, value2);
8485   symbol_set_local_slot(symbol2, sc->let_number, slot2);
8486   slot_set_next(slot2, slot_end(sc));
8487   slot_set_next(slot1, slot2);
8488 
8489   return(new_let);
8490 }
8491 
8492 /* in all these functions, symbol_set_local_slot should follow slot_set_value so that we can evaluate the slot's value in its old state. */
8493 static inline void another_slot(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value, uint64_t id)
8494 {
8495   s7_pointer slot;
8496   new_cell_no_check(sc, slot, T_SLOT);
8497   slot_set_symbol(slot, symbol);
8498   slot_set_value(slot, value);
8499   slot_set_next(slot, let_slots(let));
8500   let_set_slots(let, slot);
8501   set_local(symbol);
8502   symbol_set_local_slot(symbol, id, slot);
8503 }
8504 
8505 #define add_slot(Sc, Let, Symbol, Value) another_slot(Sc, Let, Symbol, Value, let_id(Let))
8506 
8507 static inline void add_slot_checked(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
8508 {
8509   s7_pointer slot;
8510   new_cell(sc, slot, T_SLOT);
8511   slot_set_symbol(slot, symbol);
8512   slot_set_value(slot, value);
8513   symbol_set_local_slot(symbol, let_id(let), slot);
8514   slot_set_next(slot, let_slots(let));
8515   let_set_slots(let, slot);
8516 }
8517 
8518 static inline void add_slot_checked_with_id(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
8519 {
8520   s7_pointer slot;
8521   new_cell(sc, slot, T_SLOT);
8522   slot_set_symbol(slot, symbol);
8523   slot_set_value(slot, value);
8524   set_local(symbol);
8525   if (let_id(let) >= symbol_id(symbol))
8526     symbol_set_local_slot(symbol, let_id(let), slot);
8527   slot_set_next(slot, let_slots(let));
8528   let_set_slots(let, slot);
8529 }
8530 
8531 static Inline s7_pointer add_slot_at_end(s7_scheme *sc, uint64_t id, s7_pointer last_slot, s7_pointer symbol, s7_pointer value)
8532 {
8533   s7_pointer slot;
8534   new_cell_no_check(sc, slot, T_SLOT);
8535   slot_set_symbol(slot, symbol);
8536   slot_set_next(slot, slot_end(sc));
8537   slot_set_value(slot, value);
8538   symbol_set_local_slot(symbol, id, slot);
8539   slot_set_next(last_slot, slot);
8540   return(slot);
8541 }
8542 
8543 static inline void make_let_with_three_slots(s7_scheme *sc, s7_pointer func, s7_pointer val1, s7_pointer val2, s7_pointer val3)
8544 {
8545   s7_pointer last_slot, cargs;
8546   cargs = closure_args(func);
8547   sc->curlet = make_let_with_two_slots(sc, closure_let(func), car(cargs), val1, cadr(cargs), val2);
8548   last_slot = next_slot(let_slots(sc->curlet));
8549   add_slot_at_end(sc, let_id(sc->curlet), last_slot, caddr(cargs), val3);
8550 }
8551 
8552 static void make_let_with_four_slots(s7_scheme *sc, s7_pointer func, s7_pointer val1, s7_pointer val2, s7_pointer val3, s7_pointer val4)
8553 {
8554   s7_pointer last_slot;
8555   sc->curlet = make_let_with_two_slots(sc, closure_let(func), car(closure_args(func)), val1, cadr(closure_args(func)), val2);
8556   last_slot = next_slot(let_slots(sc->curlet));
8557   last_slot = add_slot_at_end(sc, let_id(sc->curlet), last_slot, caddr(closure_args(func)), val3);
8558   add_slot_at_end(sc, let_id(sc->curlet), last_slot, cadddr(closure_args(func)), val4);
8559 }
8560 
8561 static s7_pointer reuse_as_let(s7_scheme *sc, s7_pointer let, s7_pointer next_let)
8562 {
8563   /* we're reusing let here as a let -- it was probably a pair */
8564 #if S7_DEBUGGING
8565   let->debugger_bits = 0;
8566   if (not_in_heap(let)) fprintf(stderr, "reusing an unheaped let?\n");
8567 #endif
8568   set_full_type(let, T_LET | T_SAFE_PROCEDURE);
8569   let_set_slots(let, slot_end(sc));
8570   let_set_outlet(let, next_let);
8571   let_set_id(let, ++sc->let_number);
8572   return(let);
8573 }
8574 
8575 static s7_pointer reuse_as_slot(s7_scheme *sc, s7_pointer slot, s7_pointer symbol, s7_pointer value)
8576 {
8577 #if S7_DEBUGGING
8578   slot->debugger_bits = 0;
8579   if (not_in_heap(slot)) fprintf(stderr, "reusing a permanent cell?\n");
8580   if (is_multiple_value(value))
8581     {
8582       fprintf(stderr, "%s%s[%d]: multiple-value %s %s%s\n", BOLD_TEXT, __func__, __LINE__, display(value), display(sc->code), UNBOLD_TEXT);
8583       if (sc->stop_at_error) abort();
8584     }
8585 #endif
8586   set_full_type(slot, T_SLOT);
8587   slot_set_symbol(slot, symbol);
8588   slot_set_value(slot, T_Pos(value));
8589   return(slot);
8590 }
8591 
8592 #define update_slot(Slot, Val, Id) do {s7_pointer sym; slot_set_value(Slot, Val); sym = slot_symbol(Slot); symbol_set_local_slot_unincremented(sym, Id, Slot);} while (0)
8593 
8594 static s7_pointer update_let_with_slot(s7_scheme *sc, s7_pointer let, s7_pointer val)
8595 {
8596   s7_pointer slot;
8597   uint64_t id;
8598   id = ++sc->let_number;
8599   let_set_id(let, id);
8600   slot = let_slots(let);
8601   update_slot(slot, val, id);
8602   return(let);
8603 }
8604 
8605 static s7_pointer update_let_with_two_slots(s7_scheme *sc, s7_pointer let, s7_pointer val1, s7_pointer val2)
8606 {
8607   s7_pointer slot;
8608   uint64_t id;
8609   id = ++sc->let_number;
8610   let_set_id(let, id);
8611   slot = let_slots(let);
8612   update_slot(slot, val1, id);
8613   slot = next_slot(slot);
8614   update_slot(slot, val2, id);
8615   return(let);
8616 }
8617 
8618 static s7_pointer update_let_with_three_slots(s7_scheme *sc, s7_pointer let, s7_pointer val1, s7_pointer val2, s7_pointer val3)
8619 {
8620   s7_pointer slot;
8621   uint64_t id;
8622   id = ++sc->let_number;
8623   let_set_id(let, id);
8624   slot = let_slots(let);
8625   update_slot(slot, val1, id);
8626   slot = next_slot(slot);
8627   update_slot(slot, val2, id);
8628   slot = next_slot(slot);
8629   update_slot(slot, val3, id);
8630   return(let);
8631 }
8632 
8633 static s7_pointer update_let_with_four_slots(s7_scheme *sc, s7_pointer let, s7_pointer val1, s7_pointer val2, s7_pointer val3, s7_pointer val4)
8634 {
8635   s7_pointer slot;
8636   uint64_t id;
8637   id = ++sc->let_number;
8638   let_set_id(let, id);
8639   slot = let_slots(let);
8640   update_slot(slot, val1, id);
8641   slot = next_slot(slot);
8642   update_slot(slot, val2, id);
8643   slot = next_slot(slot);
8644   update_slot(slot, val3, id);
8645   slot = next_slot(slot);
8646   update_slot(slot, val4, id);
8647   return(let);
8648 }
8649 
8650 static s7_pointer make_permanent_slot(s7_scheme *sc, s7_pointer symbol, s7_pointer value)
8651 {
8652   s7_pointer slot;
8653   slot = alloc_pointer(sc);
8654   set_full_type(slot, T_SLOT | T_UNHEAP);
8655   slot_set_symbol(slot, symbol);
8656   slot_set_value(slot, value);
8657   return(slot);
8658 }
8659 
8660 static s7_pointer make_permanent_let(s7_scheme *sc, s7_pointer vars)
8661 {
8662   s7_pointer let, var, slot;
8663   let = alloc_pointer(sc);
8664 
8665   set_full_type(let, T_LET | T_SAFE_PROCEDURE | T_UNHEAP);
8666   let_set_id(let, ++sc->let_number);
8667   let_set_outlet(let, sc->curlet);
8668   slot = make_permanent_slot(sc, caar(vars), sc->F);
8669   add_permanent_let_or_slot(sc, slot);
8670   symbol_set_local_slot(caar(vars), sc->let_number, slot);
8671   let_set_slots(let, slot);
8672   for (var = cdr(vars); is_pair(var); var = cdr(var))
8673     {
8674       s7_pointer last_slot;
8675       last_slot = slot;
8676       slot = make_permanent_slot(sc, caar(var), sc->F);
8677       add_permanent_let_or_slot(sc, slot);
8678       symbol_set_local_slot(caar(var), sc->let_number, slot);
8679       slot_set_next(last_slot, slot);
8680     }
8681   slot_set_next(slot, slot_end(sc));
8682   add_permanent_let_or_slot(sc, let); /* need to mark outlet and maybe slot values */
8683   return(let);
8684 }
8685 
8686 static s7_pointer find_let(s7_scheme *sc, s7_pointer obj)
8687 {
8688   if (is_let(obj)) return(obj);
8689   switch (type(obj))
8690     {
8691     case T_MACRO:   case T_MACRO_STAR:
8692     case T_BACRO:   case T_BACRO_STAR:
8693     case T_CLOSURE: case T_CLOSURE_STAR:
8694       return(closure_let(obj));
8695 
8696     case T_C_OBJECT:
8697       return(c_object_let(obj));
8698 
8699     case T_C_POINTER:
8700       if ((is_let(c_pointer_info(obj))) &&
8701 	  (c_pointer_info(obj) != sc->rootlet))
8702 	return(c_pointer_info(obj));
8703     }
8704   return(sc->nil);
8705 }
8706 
8707 static s7_pointer call_setter(s7_scheme *sc, s7_pointer slot, s7_pointer old_value);
8708 
8709 static inline s7_pointer checked_slot_set_value(s7_scheme *sc, s7_pointer y, s7_pointer value)
8710 {
8711   if (slot_has_setter(y))
8712     slot_set_value(y, call_setter(sc, y, value));
8713   else
8714     {
8715       if (is_immutable_slot(y))
8716 	return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->let_set_symbol, slot_symbol(y))));
8717       slot_set_value(y, value);
8718     }
8719   return(slot_value(y));
8720 }
8721 
8722 static s7_pointer let_fill(s7_scheme *sc, s7_pointer args)
8723 {
8724   s7_pointer e, val, p;
8725   e = car(args);
8726 
8727   if ((e == sc->rootlet) || (e == sc->s7_let))
8728     eval_error(sc, "attempt to fill! ~S?", 20, e);
8729   if (e == sc->owlet) /* (owlet) copies sc->owlet, so this probably can't happen */
8730     return(out_of_range(sc, sc->fill_symbol, int_one, e, wrap_string(sc, "can't fill! owlet", 17)));
8731   if (is_funclet(e))
8732     return(out_of_range(sc, sc->fill_symbol, int_one, e, wrap_string(sc, "can't fill! a funclet", 21)));
8733   val = cadr(args);
8734   for (p = let_slots(e); tis_slot(p); p = next_slot(p))
8735     checked_slot_set_value(sc, p, val);
8736   return(val);
8737 }
8738 
8739 static s7_pointer find_method(s7_scheme *sc, s7_pointer let, s7_pointer symbol)
8740 {
8741   s7_pointer slot;
8742   if (symbol_id(symbol) == 0) /* this means the symbol has never been used locally, so how can it be a method? */
8743     return(sc->undefined);
8744   slot = lookup_slot_from(symbol, let);
8745   if (slot != global_slot(symbol))
8746     return(slot_value(slot));
8747   return(sc->undefined);
8748 }
8749 
8750 static s7_pointer find_method_with_let(s7_scheme *sc, s7_pointer let, s7_pointer symbol)
8751 {
8752   return(find_method(sc, find_let(sc, let), symbol));
8753 }
8754 
8755 static s7_int s7_let_length(void);
8756 static s7_int s7_integer_checked(s7_scheme *sc, s7_pointer p);
8757 
8758 static s7_int let_length(s7_scheme *sc, s7_pointer e)
8759 {
8760   /* used by length, applicable_length, copy, and some length optimizations */
8761   s7_int i;
8762   s7_pointer p;
8763 
8764   if (e == sc->rootlet)
8765     return(sc->rootlet_entries);
8766   if (e == sc->s7_let)
8767     return(s7_let_length());
8768 
8769   if (has_active_methods(sc, e))
8770     {
8771       s7_pointer length_func;
8772       length_func = find_method(sc, e, sc->length_symbol);
8773       if (length_func != sc->undefined)
8774 	{
8775 	  p = call_method(sc, e, length_func, set_plist_1(sc, e));
8776 	  return((s7_is_integer(p)) ? s7_integer_checked(sc, p) : -1); /* ?? */
8777 	}}
8778   for (i = 0, p = let_slots(e); tis_slot(p); i++, p = next_slot(p));
8779   return(i);
8780 }
8781 
8782 
8783 static void slot_set_setter(s7_pointer p, s7_pointer val)
8784 {
8785   if ((type(val) == T_C_FUNCTION) &&
8786       (c_function_has_bool_setter(val)))
8787     slot_set_setter_1(p, c_function_bool_setter(val));
8788   else slot_set_setter_1(p, val);
8789 }
8790 
8791 static void slot_set_value_with_hook_1(s7_scheme *sc, s7_pointer slot, s7_pointer value)
8792 {
8793   /* (set! (hook-functions *rootlet-redefinition-hook*) (list (lambda (hook) (format *stderr* "~A ~A~%" (hook 'symbol) (hook 'value))))) */
8794   s7_pointer symbol;
8795   symbol = slot_symbol(slot);
8796   if ((global_slot(symbol) == slot) &&
8797       (value != slot_value(slot)))
8798     s7_call(sc, sc->rootlet_redefinition_hook, set_elist_2(sc, symbol, value));
8799   slot_set_value(slot, value);
8800 }
8801 
8802 static s7_pointer make_slot_1(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
8803 {
8804   /* let is not rootlet */
8805   s7_pointer slot;
8806   new_cell(sc, slot, T_SLOT);
8807   slot_set_symbol(slot, symbol);
8808   slot_set_value(slot, value);
8809   slot_set_next(slot, let_slots(let));
8810   let_set_slots(let, slot);
8811   set_local(symbol);
8812   /* this is called by varlet so we have to be careful about the resultant let_id
8813    *   check for greater to ensure shadowing stays in effect, and equal to do updates (set! in effect)
8814    */
8815   if (let_id(let) >= symbol_id(symbol))
8816     symbol_set_local_slot(symbol, let_id(let), slot);
8817   return(slot);
8818 }
8819 
8820 static s7_pointer make_slot_2(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
8821 {
8822   s7_pointer slot;
8823   new_cell(sc, slot, T_SLOT);
8824   slot_set_symbol(slot, symbol);
8825   slot_set_value(slot, value);
8826   symbol_set_local_slot(symbol, let_id(let), slot);
8827   slot_set_next(slot, let_slots(let));
8828   let_set_slots(let, slot);
8829   return(slot);
8830 }
8831 
8832 static void remove_function_from_heap(s7_scheme *sc, s7_pointer value);
8833 
8834 static void remove_let_from_heap(s7_scheme *sc, s7_pointer lt)
8835 {
8836   s7_pointer p;
8837   for (p = let_slots(lt); tis_slot(p); p = next_slot(p))
8838     {
8839       s7_pointer val;
8840       val = slot_value(p);
8841       if ((has_closure_let(val)) &&
8842 	  (in_heap(closure_args(val))))
8843 	remove_function_from_heap(sc, val);
8844     }
8845   let_set_removed(lt);
8846 }
8847 
8848 static void remove_function_from_heap(s7_scheme *sc, s7_pointer value)
8849 {
8850   s7_pointer lt;
8851   s7_remove_from_heap(sc, closure_args(value));
8852   s7_remove_from_heap(sc, closure_body(value));
8853   /* remove closure if it's local to current func (meaning (define f (let ...) (lambda ...)) removes the enclosing let) */
8854   lt = closure_let(value); /* closure_let and all its outlets can't be rootlet */
8855   if ((is_let(lt)) && (!let_removed(lt)) && (lt != sc->shadow_rootlet))
8856     {
8857       lt = let_outlet(lt);
8858       if ((is_let(lt)) && (!let_removed(lt)) && (lt != sc->shadow_rootlet))
8859 	{
8860 	  remove_let_from_heap(sc, lt);
8861 	  lt = let_outlet(lt);
8862 	  if ((is_let(lt)) && (!let_removed(lt)) && (lt != sc->shadow_rootlet))
8863 	    remove_let_from_heap(sc, lt);
8864 	}}
8865 }
8866 
8867 s7_pointer s7_make_slot(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
8868 {
8869   if ((!is_let(let)) ||
8870       (let == sc->rootlet))
8871     {
8872       s7_pointer ge, slot;
8873       if (is_immutable(sc->rootlet))
8874 	return(immutable_object_error(sc, set_elist_2(sc, wrap_string(sc, "can't define '~S; rootlet is immutable", 38), symbol)));
8875       if ((sc->safety == NO_SAFETY) &&
8876 	  (has_closure_let(value)))
8877 	remove_function_from_heap(sc, value);
8878 
8879       /* first look for existing slot -- this is not always checked before calling s7_make_slot */
8880       if (is_slot(global_slot(symbol)))
8881 	{
8882 	  slot = global_slot(symbol);
8883 	  symbol_increment_ctr(symbol);
8884 	  slot_set_value_with_hook(slot, value);
8885 	  return(slot);
8886 	}
8887 
8888       ge = sc->rootlet;
8889       slot = make_permanent_slot(sc, symbol, value);
8890       rootlet_element(ge, sc->rootlet_entries++) = slot;
8891       if (sc->rootlet_entries >= vector_length(ge))
8892 	{
8893 	  s7_int i, len;
8894 	  block_t *ob, *nb;
8895 	  vector_length(ge) *= 2;
8896 	  len = vector_length(ge);
8897 	  ob = rootlet_block(ge);
8898 	  nb = reallocate(sc, ob, len * sizeof(s7_pointer));
8899 	  block_info(nb) = NULL;
8900 	  rootlet_block(ge) = nb;
8901 	  rootlet_elements(ge) = (s7_pointer *)block_data(nb);
8902 	  for (i = sc->rootlet_entries; i < len; i++)
8903 	    rootlet_element(ge, i) = sc->nil;
8904 	}
8905       set_global_slot(symbol, slot);
8906 
8907       if (symbol_id(symbol) == 0)    /* never defined locally? */
8908 	{
8909 	  if ((!is_gensym(symbol)) &&
8910 	      (initial_slot(symbol) == sc->undefined) &&
8911 	      (not_in_heap(value)) &&     /* else initial_slot value can be GC'd if symbol set! (initial != global, initial unprotected) */
8912 	      ((!sc->unlet) ||            /* init_unlet creates sc->unlet, after that initial_slot is for c_functions?? */
8913 	       (is_c_function(value))))
8914 	    set_initial_slot(symbol, make_permanent_slot(sc, symbol, value));
8915 	  set_local_slot(symbol, slot);
8916 	  set_global(symbol);
8917 	}
8918       symbol_increment_ctr(symbol);
8919       if (is_gensym(symbol))
8920 	s7_remove_from_heap(sc, symbol);
8921       return(slot);
8922     }
8923 
8924   return(make_slot_1(sc, let, symbol, value));
8925   /* there are about as many lets as local variables -- this strikes me as surprising, but it holds up across a lot of code. */
8926 }
8927 
8928 static s7_pointer make_slot(s7_scheme *sc, s7_pointer variable, s7_pointer value)
8929 {
8930   s7_pointer y;
8931   new_cell(sc, y, T_SLOT);
8932   slot_set_symbol(y, variable);
8933   slot_set_value(y, value);
8934   return(y);
8935 }
8936 
8937 
8938 /* -------------------------------- let? -------------------------------- */
8939 bool s7_is_let(s7_pointer e) {return(is_let(e));}
8940 
8941 static s7_pointer g_is_let(s7_scheme *sc, s7_pointer args)
8942 {
8943   #define H_is_let "(let? obj) returns #t if obj is a let."
8944   #define Q_is_let sc->pl_bt
8945 
8946   check_boolean_method(sc, is_let, sc->is_let_symbol, args);
8947 }
8948 
8949 
8950 /* -------------------------------- funclet? -------------------------------- */
8951 static s7_pointer g_is_funclet(s7_scheme *sc, s7_pointer args)
8952 {
8953   s7_pointer lt;
8954   #define H_is_funclet "(funclet? obj) returns #t if obj is a funclet (a function's environment)."
8955   #define Q_is_funclet sc->pl_bt
8956   lt = car(args);
8957   if ((is_let(lt)) && ((is_funclet(lt)) || (is_maclet(lt))))
8958     return(sc->T);
8959   if (!has_active_methods(sc, lt))
8960     return(sc->F);
8961   return(apply_boolean_method(sc, lt, sc->is_funclet_symbol));
8962 }
8963 
8964 
8965 /* -------------------------------- unlet -------------------------------- */
8966 static s7_pointer default_vector_setter(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val);
8967 static s7_pointer default_vector_getter(s7_scheme *sc, s7_pointer vec, s7_int loc);
8968 
8969 #define UNLET_ENTRIES 512 /* 397 if not --disable-deprecated etc */
8970 
8971 static void init_unlet(s7_scheme *sc)
8972 {
8973   int32_t i, k = 0;
8974   s7_pointer x;
8975   s7_pointer *inits, *els;
8976   block_t *block;
8977 
8978   sc->unlet = (s7_pointer)Calloc(1, sizeof(s7_cell));
8979   set_full_type(sc->unlet, T_VECTOR | T_UNHEAP);
8980   vector_length(sc->unlet) = UNLET_ENTRIES;
8981   block = mallocate(sc, UNLET_ENTRIES * sizeof(s7_pointer));
8982   vector_block(sc->unlet) = block;
8983   vector_elements(sc->unlet) = (s7_pointer *)block_data(block);
8984   vector_set_dimension_info(sc->unlet, NULL);
8985   vector_getter(sc->unlet) = default_vector_getter;
8986   vector_setter(sc->unlet) = default_vector_setter;
8987   inits = vector_elements(sc->unlet);
8988   s7_vector_fill(sc, sc->unlet, sc->nil);
8989   els = vector_elements(sc->symbol_table);
8990 
8991   inits[k++] = initial_slot(sc->else_symbol);
8992   for (i = 0; i < SYMBOL_TABLE_SIZE; i++)
8993     for (x = els[i]; is_not_null(x); x = cdr(x))
8994       {
8995 	s7_pointer sym;
8996 	sym = car(x);
8997 	if ((!is_gensym(sym)) && (is_slot(initial_slot(sym))))
8998 	  {
8999 	    s7_pointer val;
9000 	    val = initial_value(sym);
9001 	    if ((is_c_function(val)) || (is_syntax(val)))  /* we assume the initial_slot value needs no GC protection */
9002 	      inits[k++] = initial_slot(sym);
9003 
9004 	    /* non-c_functions that are not set! (and therefore initial_slot GC) protected by default:
9005 	     *    make-hook hook-functions
9006 	     * if these initial_slot values are added to unlet, they need explicit GC protection.
9007 	     */
9008 #if S7_DEBUGGING
9009 	    if (k >= UNLET_ENTRIES)
9010 	      fprintf(stderr, "unlet overflow\n");
9011 #endif
9012 	  }}
9013 }
9014 
9015 static s7_pointer g_unlet(s7_scheme *sc, s7_pointer args)
9016 {
9017   /* add sc->unlet bindings to the current environment */
9018   #define H_unlet "(unlet) returns a let that establishes the original bindings of all the predefined functions"
9019   #define Q_unlet s7_make_signature(sc, 1, sc->is_let_symbol)
9020 
9021   /* slightly confusing:
9022    *    ((unlet) 'abs) -> #<undefined>
9023    *    (defined? 'abs (unlet)) -> #t
9024    * this is because unlet sets up a local environment of unshadowed symbols, and s7_let_ref only looks at the local env chain
9025    *   (that is, if env is not the global env, then the global env is not searched).
9026    */
9027   int32_t i;
9028   s7_pointer *inits;
9029   s7_pointer x;
9030 
9031   sc->w = make_let_slowly(sc, sc->curlet);
9032   inits = vector_elements(sc->unlet);
9033 
9034   for (i = 0; (i < UNLET_ENTRIES) && (is_slot(inits[i])); i++)
9035     {
9036       s7_pointer sym;
9037       x = slot_value(inits[i]);
9038       sym = slot_symbol(inits[i]);
9039       if ((x != global_value(sym)) ||  /* it has been changed globally */
9040 	  ((!is_global(sym)) &&        /* it might be shadowed locally */
9041 	   (s7_symbol_local_value(sc, sym, sc->curlet) != global_value(sym))))
9042 	make_slot_1(sc, sc->w, sym, x);
9043     }
9044   /* if (set! + -) then + needs to be overridden, but the local bit isn't set, so we have to check the actual values in the non-local case.
9045    *   (define (f x) (with-let (unlet) (+ x 1)))
9046    */
9047   x = sc->w;
9048   sc->w = sc->nil;
9049   return(x);
9050 }
9051 
9052 
9053 /* -------------------------------- openlet? -------------------------------- */
9054 bool s7_is_openlet(s7_pointer e) {return(has_methods(e));}
9055 
9056 static s7_pointer g_is_openlet(s7_scheme *sc, s7_pointer args)
9057 {
9058   #define H_is_openlet "(openlet? obj) returns #t is 'obj' has methods."
9059   #define Q_is_openlet sc->pl_bt
9060   s7_pointer e;
9061 
9062   e = car(args);  /* if e is not a let, should this raise an error? -- no, easier to use this way in cond */
9063   check_method(sc, e, sc->is_openlet_symbol, args);
9064   return(make_boolean(sc, has_methods(e)));
9065 }
9066 
9067 
9068 /* -------------------------------- openlet -------------------------------- */
9069 s7_pointer s7_openlet(s7_scheme *sc, s7_pointer e)
9070 {
9071   set_has_methods(e);
9072   return(e);
9073 }
9074 
9075 static s7_pointer g_openlet(s7_scheme *sc, s7_pointer args)
9076 {
9077   #define H_openlet "(openlet e) tells the built-in generic functions that the let 'e might have an over-riding method."
9078   #define Q_openlet sc->pcl_e
9079   s7_pointer e, elet, func;
9080 
9081   e = car(args);
9082   if ((e == sc->rootlet) || (e == sc->nil))
9083     s7_error(sc, sc->out_of_range_symbol, set_elist_1(sc, wrap_string(sc, "can't openlet rootlet", 21)));
9084   elet = find_let(sc, e); /* returns nil if no let found, so has to follow error check above */
9085   if (!is_let(elet))
9086     return(simple_wrong_type_argument_with_type(sc, sc->openlet_symbol, e, a_let_string));
9087 
9088   if ((has_active_methods(sc, e)) &&
9089       ((func = find_method(sc, elet, sc->openlet_symbol)) != sc->undefined))
9090     return(call_method(sc, e, func, args));
9091 
9092   set_has_methods(e);
9093   return(e);
9094 }
9095 
9096 /* -------------------------------- coverlet -------------------------------- */
9097 static s7_pointer g_coverlet(s7_scheme *sc, s7_pointer args)
9098 {
9099   s7_pointer e;
9100   #define H_coverlet "(coverlet e) undoes an earlier openlet."
9101   #define Q_coverlet sc->pcl_e
9102 
9103   e = car(args);
9104   sc->temp3 = e;
9105   check_method(sc, e, sc->coverlet_symbol, set_plist_1(sc, e));
9106   sc->temp3 = sc->nil;
9107   if ((e == sc->rootlet) || (e == sc->s7_let))
9108     s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, wrap_string(sc, "can't coverlet ~S", 17), e));
9109 
9110   if ((is_let(e)) ||
9111       (has_closure_let(e)) ||
9112       ((is_c_object(e)) && (c_object_let(e) != sc->nil)) ||
9113       ((is_c_pointer(e)) && (is_let(c_pointer_info(e)))))
9114     {
9115       clear_has_methods(e);
9116       return(e);
9117     }
9118   return(simple_wrong_type_argument_with_type(sc, sc->coverlet_symbol, e, a_let_string));
9119 }
9120 
9121 
9122 /* -------------------------------- varlet -------------------------------- */
9123 static void append_let(s7_scheme *sc, s7_pointer new_e, s7_pointer old_e)
9124 {
9125   s7_pointer x;
9126 
9127   if ((old_e == sc->rootlet) || (new_e == sc->s7_let))
9128     return;
9129 
9130   if (new_e == sc->rootlet)
9131     {
9132       for (x = let_slots(old_e); tis_slot(x); x = next_slot(x))
9133 	{
9134 	  s7_pointer sym, val;
9135 	  sym = slot_symbol(x);
9136 	  val = slot_value(x);
9137 	  if (is_slot(global_slot(sym)))
9138 	    slot_set_value(global_slot(sym), val);
9139 	  else s7_make_slot(sc, new_e, sym, val);
9140 	}}
9141   else
9142     {
9143       if (old_e == sc->s7_let)
9144 	{
9145 	  s7_pointer iter, carrier;
9146 	  s7_int gc_loc;
9147 	  iter = s7_make_iterator(sc, sc->s7_let);
9148 	  gc_loc = s7_gc_protect(sc, iter);
9149 	  carrier = cons(sc, sc->F, sc->F);
9150 	  iterator_current(iter) = carrier;
9151 	  set_mark_seq(iter); /* so carrier is GC protected by mark_iterator */
9152 	  while (true)
9153 	    {
9154 	      s7_pointer y;
9155 	      y = s7_iterate(sc, iter);
9156 	      if (iterator_is_at_end(iter)) break;
9157 	      make_slot_1(sc, new_e, car(y), cdr(y));
9158 	    }
9159 	  s7_gc_unprotect_at(sc, gc_loc);
9160 	}
9161       else
9162 	for (x = let_slots(old_e); tis_slot(x); x = next_slot(x))
9163 	  make_slot_1(sc, new_e, slot_symbol(x), slot_value(x)); /* not add_slot here because we might run off the free heap end */
9164     }
9165 }
9166 
9167 static s7_pointer check_c_object_let(s7_scheme *sc, s7_pointer old_e, s7_pointer caller)
9168 {
9169   if (is_c_object(old_e))
9170     old_e = c_object_let(old_e);
9171   if (!is_let(old_e))
9172     return(simple_wrong_type_argument_with_type(sc, caller, old_e, a_let_string));
9173   return(old_e);
9174 }
9175 
9176 s7_pointer s7_varlet(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
9177 {
9178   if (!is_let(let))
9179     return(wrong_type_argument_with_type(sc, sc->varlet_symbol, 1, let, a_let_string));
9180 
9181   if (!is_symbol(symbol))
9182     return(wrong_type_argument_with_type(sc, sc->varlet_symbol, 2, symbol, a_symbol_string));
9183 
9184   if ((is_slot(global_slot(symbol))) &&
9185       (is_syntax(global_value(symbol))))
9186     return(wrong_type_argument_with_type(sc, sc->varlet_symbol, 2, symbol, wrap_string(sc, "a non-syntactic name", 20)));
9187 
9188   if (let == sc->rootlet)
9189     {
9190       if (is_slot(global_slot(symbol)))
9191 	slot_set_value(global_slot(symbol), value);
9192       else s7_make_slot(sc, let, symbol, value);
9193     }
9194   else make_slot_1(sc, let, symbol, value);
9195   return(value);
9196 }
9197 
9198 static s7_pointer g_varlet(s7_scheme *sc, s7_pointer args)
9199 {
9200   #define H_varlet "(varlet let ...) adds its arguments (a let, a cons: symbol . value, or two arguments, the symbol and its value) \
9201 to the let let, and returns let.  (varlet (curlet) 'a 1) adds 'a to the current environment with the value 1."
9202   #define Q_varlet s7_make_circular_signature(sc, 2, 4, sc->is_let_symbol, \
9203                      s7_make_signature(sc, 2, sc->is_let_symbol, sc->is_null_symbol), \
9204                        s7_make_signature(sc, 3, sc->is_pair_symbol, sc->is_symbol_symbol, sc->is_let_symbol), \
9205                          sc->T)
9206   /* varlet = with-let + define */
9207   s7_pointer x, e, val;
9208 
9209   e = car(args);
9210   if (is_null(e))
9211     e = sc->rootlet;
9212   else
9213     {
9214       check_method(sc, e, sc->varlet_symbol, args);
9215       if (!is_let(e))
9216 	return(wrong_type_argument_with_type(sc, sc->varlet_symbol, 1, e, a_let_string));
9217       if ((is_immutable(e)) || (e == sc->s7_let))
9218 	return(s7_error(sc, sc->immutable_error_symbol, set_elist_3(sc, wrap_string(sc, "can't (varlet ~{~S~^ ~}), ~S is immutable", 41), args, e)));
9219     }
9220   for (x = cdr(args); is_pair(x); x = cdr(x))
9221     {
9222       s7_pointer sym, p;
9223       p = car(x);
9224       switch (type(p))
9225 	{
9226 	case T_SYMBOL:
9227 	  sym = (is_keyword(p)) ? keyword_symbol(p) : p;
9228 	  if (!is_pair(cdr(x)))
9229 	    s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, value_is_missing_string, sc->varlet_symbol, car(x)));
9230 	  if (is_constant_symbol(sc, sym))
9231 	    return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), sym, a_non_constant_symbol_string));
9232 	  x = cdr(x);
9233 	  val = car(x);
9234 	  break;
9235 
9236 	case T_PAIR:
9237 	  sym = car(p);
9238 	  if (!is_symbol(sym))
9239 	    return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), p, a_symbol_string));
9240 	  if (is_constant_symbol(sc, sym))
9241 	    return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), sym, a_non_constant_symbol_string));
9242 	  val = cdr(p);
9243 	  break;
9244 
9245 	case T_LET:
9246 	  append_let(sc, e, check_c_object_let(sc, p, sc->varlet_symbol));
9247 	  continue;
9248 
9249 	default:
9250 	  return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), p, a_symbol_string));
9251 	}
9252 
9253       if (e == sc->rootlet)
9254 	{
9255 	  if (is_slot(global_slot(sym)))
9256 	    {
9257 	      if (is_syntax(global_value(sym)))
9258 		return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), p, wrap_string(sc, "a non-syntactic keyword", 23)));
9259 	      /*  without this check we can end up turning our code into gibberish:
9260 	       *    (set! quote 1) -> ;can't set! quote
9261 	       *    (varlet (rootlet) '(quote . 1)), :quote -> 1
9262 	       * or worse set quote to a function of one arg that tries to quote something -- infinite loop
9263 	       */
9264 	      slot_set_value_with_hook(global_slot(sym), val);
9265 	    }
9266 	  else s7_make_slot(sc, e, sym, val);
9267 	}
9268       else
9269 	{
9270 	  if ((has_let_fallback(e)) &&
9271 	      ((sym == sc->let_ref_fallback_symbol) || (sym == sc->let_set_fallback_symbol)))
9272 	    return(s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, wrap_string(sc, "varlet can't shadow ~S", 22), sym)));
9273 
9274 	  make_slot_1(sc, e, sym, val);
9275 	}
9276       /* this used to check for sym already defined, and set its value, but that greatly slows down
9277        *   the most common use (adding a slot), and makes it hard to shadow explicitly.  Don't use
9278        *   varlet as a substitute for set!/let-set!.
9279        */
9280     }
9281   return(e);
9282 }
9283 
9284 
9285 /* -------------------------------- cutlet -------------------------------- */
9286 static s7_pointer g_cutlet(s7_scheme *sc, s7_pointer args)
9287 {
9288   #define H_cutlet "(cutlet e symbol ...) removes symbols from the let e."
9289   #define Q_cutlet s7_make_circular_signature(sc, 2, 3, sc->is_let_symbol, sc->is_let_symbol, sc->is_symbol_symbol)
9290 
9291   s7_pointer e, syms;
9292   s7_int the_un_id;
9293 
9294   e = car(args);
9295   if (is_null(e))
9296     e = sc->rootlet;
9297   else
9298     {
9299       check_method(sc, e, sc->cutlet_symbol, args);
9300       if (!is_let(e))
9301 	return(wrong_type_argument_with_type(sc, sc->cutlet_symbol, 1, e, a_let_string));
9302       if ((is_immutable(e)) || (e == sc->s7_let))
9303 	return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->cutlet_symbol, e)));
9304     }
9305   /* besides removing the slot we have to make sure the symbol_id does not match else
9306    *   let-ref and others will use the old slot!  What's the un-id?  Perhaps the next one?
9307    *   (let ((b 1)) (let ((b 2)) (cutlet (curlet) 'b)) b)
9308    */
9309   the_un_id = ++sc->let_number;
9310 
9311   for (syms = cdr(args); is_pair(syms); syms = cdr(syms))
9312     {
9313       s7_pointer sym, slot;
9314       sym = car(syms);
9315 
9316       if (!is_symbol(sym))
9317 	return(wrong_type_argument_with_type(sc, sc->cutlet_symbol, position_of(syms, args), sym, a_symbol_string));
9318 
9319       if (is_keyword(sym))
9320 	sym = keyword_symbol(sym);
9321 
9322       if (e == sc->rootlet)
9323 	{
9324 	  if (is_slot(global_slot(sym)))
9325 	    {
9326 	      symbol_set_id(sym, the_un_id);
9327 	      slot_set_value(global_slot(sym), sc->undefined);
9328 	    }}
9329       else
9330 	{
9331 	  if ((has_let_fallback(e)) &&
9332 	      ((sym == sc->let_ref_fallback_symbol) || (sym == sc->let_set_fallback_symbol)))
9333 	    return(s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, wrap_string(sc, "cutlet can't remove ~S", 22), sym)));
9334 
9335 	  slot = let_slots(e);
9336 	  if (tis_slot(slot))
9337 	    {
9338 	      if (slot_symbol(slot) == sym)
9339 		{
9340 		  let_set_slots(e, next_slot(let_slots(e)));
9341 		  symbol_set_id(sym, the_un_id);
9342 		}
9343 	      else
9344 		{
9345 		  s7_pointer last_slot;
9346 		  last_slot = slot;
9347 		  for (slot = next_slot(let_slots(e)); tis_slot(slot); last_slot = slot, slot = next_slot(slot))
9348 		    if (slot_symbol(slot) == sym)
9349 		      {
9350 			symbol_set_id(sym, the_un_id);
9351 			slot_set_next(last_slot, next_slot(slot));
9352 			break;
9353 		      }}}}}
9354   return(e);
9355 }
9356 
9357 
9358 /* -------------------------------- sublet -------------------------------- */
9359 static s7_pointer sublet_1(s7_scheme *sc, s7_pointer e, s7_pointer bindings, s7_pointer caller)
9360 {
9361   s7_pointer new_e;
9362   new_e = (e == sc->rootlet) ? make_let_slowly(sc, sc->nil) : make_let_slowly(sc, e);
9363   set_all_methods(new_e, e);
9364 
9365   if (!is_null(bindings))
9366     {
9367       s7_pointer x;
9368       sc->temp3 = new_e;
9369 
9370       for (x = bindings; is_pair(x); x = cdr(x))
9371 	{
9372 	  s7_pointer p, sym, val;
9373 
9374 	  p = car(x);
9375 	  switch (type(p))
9376 	    {
9377 	      /* should this insist on one style of field arg?  i.e. (cons sym val) throughout, or :sym val etc? */
9378 	    case T_SYMBOL:
9379 	      sym = (is_keyword(p)) ? keyword_symbol(p) : p;
9380 	      if (!is_pair(cdr(x)))
9381 		s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, value_is_missing_string, caller, car(x)));
9382 	      x = cdr(x);
9383 	      val = car(x);
9384 	      break;
9385 
9386 	    case T_PAIR:
9387 	      sym = car(p);
9388 	      if (!is_symbol(sym))
9389 		return(wrong_type_argument_with_type(sc, caller, 1 + position_of(x, bindings), p, a_symbol_string));
9390 	      if (is_keyword(sym))
9391 		sym = keyword_symbol(sym);
9392 	      val = cdr(p);
9393 	      break;
9394 
9395 	    case T_LET:
9396 	      append_let(sc, new_e, check_c_object_let(sc, p, caller));
9397 	      continue;
9398 
9399 	    default:
9400 	      return(wrong_type_argument_with_type(sc, caller, 1 + position_of(x, bindings), p, a_symbol_string));
9401 	    }
9402 
9403 	  if (is_constant_symbol(sc, sym))
9404 	    return(wrong_type_argument_with_type(sc, caller, 1 + position_of(x, bindings), sym, a_non_constant_symbol_string));
9405 	  if ((is_slot(global_slot(sym))) &&
9406 	      (is_syntax(global_value(sym))))
9407 	    return(wrong_type_argument_with_type(sc, caller, 2, sym, wrap_string(sc, "a non-syntactic name", 20)));
9408 
9409 	  /* here we know new_e is a let and is not rootlet */
9410 	  /* make_slot_1(sc, new_e, sym, val); *//* add_slot without let_id check or is it set_local will not work here */
9411 	  add_slot_checked_with_id(sc, new_e, sym, val);
9412 	  if (sym == sc->let_ref_fallback_symbol)
9413 	    set_has_let_ref_fallback(new_e);
9414 	  else
9415 	    if (sym == sc->let_set_fallback_symbol)
9416 	      set_has_let_set_fallback(new_e);
9417 	}
9418       sc->temp3 = sc->nil;
9419     }
9420   return(new_e);
9421 }
9422 
9423 s7_pointer s7_sublet(s7_scheme *sc, s7_pointer e, s7_pointer bindings)
9424 {
9425   return(sublet_1(sc, e, bindings, sc->sublet_symbol));
9426 }
9427 
9428 static s7_pointer g_sublet(s7_scheme *sc, s7_pointer args)
9429 {
9430   #define H_sublet "(sublet let ...) adds its arguments (each a let or a cons: '(symbol . value)) to let, and returns the new let."
9431   #define Q_sublet Q_varlet
9432   s7_pointer e;
9433 
9434   e = car(args);
9435   if (is_null(e))
9436     e = sc->rootlet;
9437   else
9438     {
9439       check_method(sc, e, sc->sublet_symbol, args);
9440       if (!is_let(e))
9441 	return(wrong_type_argument_with_type(sc, sc->sublet_symbol, 1, e, a_let_string));
9442     }
9443   return(sublet_1(sc, e, cdr(args), sc->sublet_symbol));
9444 }
9445 
9446 
9447 /* -------------------------------- inlet -------------------------------- */
9448 s7_pointer s7_inlet(s7_scheme *sc, s7_pointer args)
9449 {
9450   #define H_inlet "(inlet ...) adds its arguments, each a let, a cons: '(symbol . value), or a keyword/value pair, to a new let, and returns the \
9451 new let. (inlet :a 1 :b 2) or (inlet '(a . 1) '(b . 2))"
9452   #define Q_inlet s7_make_circular_signature(sc, 1, 2, sc->is_let_symbol, sc->T)
9453 
9454   return(sublet_1(sc, sc->rootlet, args, sc->inlet_symbol));
9455 }
9456 
9457 #define g_inlet s7_inlet
9458 
9459 static s7_pointer g_simple_inlet(s7_scheme *sc, s7_pointer args)
9460 {
9461   /* here all args are paired with normal symbol/value, no fallbacks, no immutable symbols etc */
9462   s7_pointer new_e, x;
9463   int64_t id;
9464   new_e = make_let_slowly(sc, sc->nil);
9465   sc->temp3 = new_e;
9466   id = let_id(new_e);
9467   for (x = args; is_pair(x); x = cddr(x))
9468     {
9469       s7_pointer symbol;
9470       symbol = car(x);
9471       if (is_keyword(symbol))                 /* (inlet ':allow-other-keys 3) */
9472 	symbol = keyword_symbol(symbol);
9473       if (is_constant_symbol(sc, symbol))     /* (inlet 'pi 1) */
9474 	return(wrong_type_argument_with_type(sc, sc->inlet_symbol, 1, symbol, a_non_constant_symbol_string));
9475       another_slot(sc, new_e, symbol, cadr(x), id);
9476     }
9477   sc->temp3 = sc->nil;
9478   return(new_e);
9479 }
9480 
9481 static s7_pointer inlet_p_pp(s7_scheme *sc, s7_pointer symbol, s7_pointer value)
9482 {
9483   s7_pointer x;
9484 
9485   if (!is_symbol(symbol))
9486     return(sublet_1(sc, sc->nil, list_2(sc, symbol, value), sc->inlet_symbol));
9487   if (is_keyword(symbol))
9488     symbol = keyword_symbol(symbol);
9489   if (is_constant_symbol(sc, symbol))
9490     return(wrong_type_argument_with_type(sc, sc->inlet_symbol, 1, symbol, a_non_constant_symbol_string));
9491   if ((is_global(symbol)) &&
9492       (is_syntax(global_value(symbol))))
9493     return(wrong_type_argument_with_type(sc, sc->inlet_symbol, 1, symbol, wrap_string(sc, "a non-syntactic name", 20)));
9494 
9495   new_cell(sc, x, T_LET | T_SAFE_PROCEDURE);
9496   sc->temp3 = x;
9497   let_set_id(x, ++sc->let_number);
9498   let_set_outlet(x, sc->nil);
9499   let_set_slots(x, slot_end(sc));
9500   another_slot(sc, x, symbol, value, let_id(x));
9501   sc->temp3 = sc->nil;
9502   return(x);
9503 }
9504 
9505 static s7_pointer g_local_inlet(s7_scheme *sc, s7_int num_args, ...)
9506 {
9507   va_list ap;
9508   s7_int i;
9509   s7_pointer new_e;
9510   int64_t id;
9511 
9512   new_e = make_let_slowly(sc, sc->nil);
9513   sc->temp3 = new_e;
9514   id = let_id(new_e);
9515 
9516   va_start(ap, num_args);
9517   for (i = 0; i < num_args; i += 2)
9518     {
9519       s7_pointer symbol, value;
9520       symbol = va_arg(ap, s7_pointer);
9521       value = va_arg(ap, s7_pointer);
9522       if (is_keyword(symbol))                 /* (inlet ':allow-other-keys 3) */
9523 	symbol = keyword_symbol(symbol);
9524       another_slot(sc, new_e, symbol, value, id);
9525     }
9526   va_end(ap);
9527 
9528   sc->temp3 = sc->nil;
9529   return(new_e);
9530 }
9531 
9532 static bool is_proper_quote(s7_scheme *sc, s7_pointer p)
9533 {
9534   return((is_quoted_pair(p)) &&
9535 	 (is_pair(cdr(p))) &&
9536 	 (is_null(cddr(p))) &&
9537 	 (is_global(sc->quote_symbol)));
9538 }
9539 
9540 static s7_pointer inlet_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
9541 {
9542   if (!ops) return(f);
9543   if ((args > 0) &&
9544       ((args % 2) == 0))
9545     {
9546       s7_pointer p;
9547       for (p = cdr(expr); is_pair(p); p = cddr(p))
9548 	if (!is_keyword(car(p)))
9549 	  {
9550 	    s7_pointer sym;
9551 	    if (!is_proper_quote(sc, car(p)))             /* 'abs etc, but tricky: ':abs */
9552 	      return(f);
9553 	    sym = cadar(p);
9554 	    if ((!is_symbol(sym)) ||
9555 		(is_possibly_constant(sym)) ||            /* define-constant etc */
9556 		(is_syntactic_symbol(sym))  ||            /* (inlet 'if 3) */
9557 		((is_slot(global_slot(sym))) &&
9558 		 (is_syntactic(global_value(sym)))) ||
9559 		(sym == sc->let_ref_fallback_symbol) ||
9560 		(sym == sc->let_set_fallback_symbol))
9561 	      return(f);
9562 	  }
9563       return(sc->simple_inlet);
9564     }
9565   return(f);
9566 }
9567 
9568 
9569 /* -------------------------------- let->list -------------------------------- */
9570 static s7_pointer proper_list_reverse_in_place(s7_scheme *sc, s7_pointer list);
9571 
9572 s7_pointer s7_let_to_list(s7_scheme *sc, s7_pointer let)
9573 {
9574   s7_pointer x;
9575 
9576   sc->temp3 = sc->w;
9577   sc->w = sc->nil;
9578   if (let == sc->rootlet)
9579     {
9580       s7_int i, lim2;
9581       s7_pointer *entries;
9582 
9583       entries = rootlet_elements(let);
9584       lim2 = sc->rootlet_entries;
9585       if (lim2 & 1) lim2--;
9586 
9587       for (i = 0; i < lim2; )
9588 	{
9589 	  sc->w = cons_unchecked(sc, cons(sc, slot_symbol(entries[i]), slot_value(entries[i])), sc->w); i++;
9590 	  sc->w = cons_unchecked(sc, cons_unchecked(sc, slot_symbol(entries[i]), slot_value(entries[i])), sc->w); i++;
9591 	}
9592       if (lim2 < sc->rootlet_entries)
9593 	sc->w = cons_unchecked(sc, cons(sc, slot_symbol(entries[i]), slot_value(entries[i])), sc->w);
9594     }
9595   else
9596     {
9597       s7_pointer iter, func;
9598       s7_int gc_loc = -1;
9599       /* need to check make-iterator method before dropping into let->list */
9600 
9601       if ((has_active_methods(sc, let)) &&
9602 	  ((func = find_method(sc, let, sc->make_iterator_symbol)) != sc->undefined))
9603 	iter = call_method(sc, let, func, set_plist_1(sc, let));
9604       else
9605 	{
9606 	  if (let == sc->s7_let) /* (let->list *s7*) via s7_let_make_iterator */
9607 	    {
9608 	      iter = s7_make_iterator(sc, let);
9609 	      gc_loc = s7_gc_protect(sc, iter);
9610 	    }
9611 	  else iter = sc->nil;
9612 	}
9613 
9614       if (is_null(iter))
9615 	for (x = let_slots(let); tis_slot(x); x = next_slot(x))
9616 	  sc->w = cons_unchecked(sc, cons(sc, slot_symbol(x), slot_value(x)), sc->w);
9617       else
9618 	{
9619 	  /* (begin (load "mockery.scm") (let ((lt ((*mock-pair* 'mock-pair) 1 2 3))) (format *stderr* "~{~A ~}" lt))) */
9620 	  while (true)
9621 	    {
9622 	      x = s7_iterate(sc, iter);
9623 	      if (iterator_is_at_end(iter)) break;
9624 	      sc->w = cons(sc, x, sc->w);
9625 	    }
9626 	  sc->w = proper_list_reverse_in_place(sc, sc->w);
9627 	}
9628       if (gc_loc != -1)
9629 	s7_gc_unprotect_at(sc, gc_loc);
9630     }
9631   x = sc->w;
9632   sc->w = sc->temp3;
9633   sc->temp3 = sc->nil;
9634   return(x);
9635 }
9636 
9637 #if (!WITH_PURE_S7)
9638 static s7_pointer g_let_to_list(s7_scheme *sc, s7_pointer args)
9639 {
9640   #define H_let_to_list "(let->list let) returns let's bindings as a list of cons's: '(symbol . value)."
9641   #define Q_let_to_list s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_let_symbol)
9642 
9643   s7_pointer let;
9644   let = car(args);
9645   check_method(sc, let, sc->let_to_list_symbol, args);
9646   if (!is_let(let))
9647     {
9648       if (is_c_object(let))
9649 	let = c_object_let(let);
9650       else
9651 	if (is_c_pointer(let))
9652 	  let = c_pointer_info(let);
9653       if (!is_let(let))
9654         return(simple_wrong_type_argument_with_type(sc, sc->let_to_list_symbol, let, a_let_string));
9655     }
9656   return(s7_let_to_list(sc, let));
9657 }
9658 #endif
9659 
9660 
9661 /* -------------------------------- let-ref -------------------------------- */
9662 
9663 static s7_pointer call_let_ref_fallback(s7_scheme *sc, s7_pointer let, s7_pointer symbol)
9664 {
9665   s7_pointer p;
9666   /* args could be protected via let = stack_end[1] */
9667   push_stack_no_let(sc, OP_GC_PROTECT, sc->value, sc->code);
9668   p = s7_apply_function(sc, find_method(sc, let, sc->let_ref_fallback_symbol), set_qlist_2(sc, let, symbol));
9669   sc->stack_end -= 4;
9670   sc->code = T_Pos(sc->stack_end[0]);
9671   sc->value = T_Pos(sc->stack_end[2]);
9672   return(p);
9673 }
9674 
9675 static s7_pointer call_let_set_fallback(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
9676 {
9677   s7_pointer p;
9678   push_stack_no_let(sc, OP_GC_PROTECT, sc->value, sc->code);
9679   p = s7_apply_function(sc, find_method(sc, let, sc->let_set_fallback_symbol), set_qlist_3(sc, let, symbol, value));
9680   sc->stack_end -= 4;
9681   sc->code = T_Pos(sc->stack_end[0]);
9682   sc->value = T_Pos(sc->stack_end[2]);
9683   return(p);
9684 }
9685 
9686 inline s7_pointer s7_let_ref(s7_scheme *sc, s7_pointer let, s7_pointer symbol)
9687 {
9688   s7_pointer x, y;
9689   /* (let ((a 1)) ((curlet) 'a)) or ((rootlet) 'abs) */
9690   if (!is_let(let))
9691     return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 1, let, a_let_string));
9692 
9693   if (!is_symbol(symbol))
9694     {
9695 #if S7_DEBUGGING
9696       if ((let != sc->rootlet) && (has_let_ref_fallback(let)))
9697 #else
9698 	if (has_let_ref_fallback(let))
9699 #endif
9700 	return(call_let_ref_fallback(sc, let, symbol));
9701       return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 2, symbol, a_symbol_string));
9702     }
9703 
9704   if (!is_global(sc->let_ref_symbol))
9705     check_method(sc, let, sc->let_ref_symbol, set_plist_2(sc, let, symbol));
9706   /* a let-ref method is almost impossible to write without creating an infinite loop:
9707    *   any reference to the let will probably call let-ref somewhere, calling us again, and looping.
9708    *   This is not a problem in c-objects and funclets because c-object-ref and funclet-ref don't exist.
9709    *   After much wasted debugging, I decided to make let-ref and let-set! immutable.
9710    */
9711 
9712   if (is_keyword(symbol))
9713     symbol = keyword_symbol(symbol);
9714 
9715   if (let == sc->rootlet)
9716     {
9717       y = global_slot(symbol);
9718       return((is_slot(y)) ? slot_value(y) : sc->undefined);
9719     }
9720 
9721   if (let_id(let) == symbol_id(symbol))
9722     return(local_value(symbol)); /* this obviously has to follow the rootlet check */
9723 
9724   for (x = let; is_let(x); x = let_outlet(x))
9725     for (y = let_slots(x); tis_slot(y); y = next_slot(y))
9726       if (slot_symbol(y) == symbol)
9727 	return(slot_value(y));
9728 
9729   if (has_methods(let)) /* this is not a redundant check -- if has_methods, don't check global slot */
9730     {
9731       /* If a let is a mock-hash-table (for example), implicit
9732        *   indexing of the hash-table collides with the same thing for the let (field names
9733        *   versus keys), and we can't just try again here because that makes it too easy to
9734        *   get into infinite recursion.  So, 'let-ref-fallback...
9735        */
9736       if (has_let_ref_fallback(let))
9737 	return(call_let_ref_fallback(sc, let, symbol));
9738     }
9739   else
9740     {
9741       y = global_slot(symbol);  /* (let () ((curlet) 'pi)) */
9742       if (is_slot(y))
9743 	return(slot_value(y));
9744     }
9745   return(sc->undefined);
9746 }
9747 
9748 static s7_pointer g_let_ref(s7_scheme *sc, s7_pointer args)
9749 {
9750   #define H_let_ref "(let-ref let sym) returns the value of the symbol sym in the let"
9751   #define Q_let_ref s7_make_signature(sc, 3, sc->T, sc->is_let_symbol, sc->is_symbol_symbol)
9752   return(s7_let_ref(sc, car(args), cadr(args)));
9753 }
9754 
9755 static s7_pointer slot_in_let(s7_scheme *sc, s7_pointer e, s7_pointer sym)
9756 {
9757   s7_pointer y;
9758   for (y = let_slots(e); tis_slot(y); y = next_slot(y))
9759     if (slot_symbol(y) == sym)
9760       return(y);
9761   return(sc->undefined);
9762 }
9763 
9764 static s7_pointer lint_let_ref_p_pp(s7_scheme *sc, s7_pointer lt, s7_pointer sym)
9765 {
9766   s7_pointer x, y;
9767   for (x = lt; is_let(x); x = let_outlet(x))
9768     for (y = let_slots(x); tis_slot(y); y = next_slot(y))
9769       if (slot_symbol(y) == sym)
9770 	return(slot_value(y));
9771 
9772   if (has_methods(lt))
9773     {
9774       if (has_let_ref_fallback(lt))
9775 	return(call_let_ref_fallback(sc, lt, sym));
9776     }
9777   else
9778     {
9779       y = global_slot(sym);
9780       if (is_slot(y))
9781 	return(slot_value(y));
9782     }
9783   return(sc->undefined);
9784 }
9785 
9786 static inline s7_pointer g_lint_let_ref(s7_scheme *sc, s7_pointer args)
9787 {
9788   s7_pointer lt, y, sym;
9789   lt = car(args);
9790   if (!is_let(lt))
9791     return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 1, lt, a_let_string));
9792   sym = cadr(args);
9793   for (y = let_slots(lt); tis_slot(y); y = next_slot(y))
9794     if (slot_symbol(y) == sym)
9795       return(slot_value(y));
9796   return(lint_let_ref_p_pp(sc, let_outlet(lt), sym));
9797 }
9798 
9799 static s7_pointer let_ref_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
9800 {
9801   if ((!ops) || (!is_global(sc->let_ref_symbol))) return(f);
9802 
9803   if (optimize_op(expr) == HOP_SAFE_C_opSq_C)
9804     {
9805       s7_pointer arg1, arg2;
9806       arg1 = cadr(expr);
9807       arg2 = caddr(expr);
9808       if ((car(arg1) == sc->cdr_symbol) &&
9809 	  (is_quoted_symbol(arg2)) &&
9810 	  (!is_possibly_constant(cadr(arg2))))
9811 	{
9812 	  set_opt3_sym(cdr(expr), cadr(arg2));
9813 	  return(sc->lint_let_ref);
9814 	}}
9815   return(f);
9816 }
9817 
9818 static bool op_implicit_let_ref_c(s7_scheme *sc)
9819 {
9820   s7_pointer s;
9821   s = lookup_checked(sc, car(sc->code));
9822   if (!is_let(s)) {sc->last_function = s; return(false);}
9823   sc->value = s7_let_ref(sc, T_Pos(s), opt3_con(sc->code));
9824   return(true);
9825 }
9826 
9827 static bool op_implicit_let_ref_a(s7_scheme *sc)
9828 {
9829   s7_pointer s;
9830   s = lookup_checked(sc, car(sc->code));
9831   if (!is_let(s)) {sc->last_function = s; return(false);}
9832   sc->value = s7_let_ref(sc, s, fx_call(sc, cdr(sc->code)));
9833   return(true);
9834 }
9835 
9836 
9837 /* -------------------------------- let-set! -------------------------------- */
9838 static s7_pointer let_set_1(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
9839 {
9840   s7_pointer x, y;
9841 
9842   if (is_keyword(symbol))
9843     symbol = keyword_symbol(symbol);
9844   symbol_increment_ctr(symbol);
9845 
9846   if (let == sc->rootlet)
9847     {
9848       if (is_constant_symbol(sc, symbol))  /* (let-set! (rootlet) 'pi #f) */
9849 	return(wrong_type_argument_with_type(sc, sc->let_set_symbol, 2, symbol, a_non_constant_symbol_string));
9850 
9851       y = global_slot(symbol);
9852       if (is_slot(y))
9853 	{
9854 	  if (is_syntax(slot_value(y)))
9855 	    return(wrong_type_argument_with_type(sc, sc->let_set_symbol, 2, symbol, wrap_string(sc, "a non-syntactic keyword", 23)));
9856 
9857 	  if (slot_has_setter(y))
9858 	    slot_set_value(y, call_setter(sc, y, value));
9859 	  else slot_set_value(y, value);
9860 	  return(slot_value(y));
9861 	}
9862       return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, wrap_string(sc, "let-set!: ~A is not defined in ~A", 33), symbol, let)));
9863     }
9864 
9865   if (let_id(let) == symbol_id(symbol))
9866    {
9867      y = local_slot(symbol);
9868      if (is_slot(y))
9869        return(checked_slot_set_value(sc, y, value));
9870    }
9871 
9872   for (x = let; is_let(x); x = let_outlet(x))
9873     for (y = let_slots(x); tis_slot(y); y = next_slot(y))
9874       if (slot_symbol(y) == symbol)
9875 	return(checked_slot_set_value(sc, y, value));
9876 
9877   if ((has_methods(let)) &&
9878       (has_let_set_fallback(let)))
9879     return(call_let_set_fallback(sc, let, symbol, value));
9880 
9881   return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, wrap_string(sc, "let-set!: ~A is not defined in ~A", 33), symbol, let)));
9882   /* not sure about this -- what's the most useful choice? */
9883 }
9884 
9885 s7_pointer s7_let_set(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
9886 {
9887   if (!is_let(let))
9888     return(wrong_type_argument_with_type(sc, sc->let_set_symbol, 1, let, a_let_string));
9889   if (!is_symbol(symbol))
9890     {
9891       if (has_let_set_fallback(let))
9892 	return(call_let_set_fallback(sc, let, symbol, value));
9893       return(wrong_type_argument_with_type(sc, sc->let_set_symbol, 2, symbol, a_symbol_string));
9894     }
9895   if (!is_global(sc->let_set_symbol))
9896     check_method(sc, let, sc->let_set_symbol, set_plist_3(sc, let, symbol, value));
9897   return(let_set_1(sc, let, symbol, value));
9898 }
9899 
9900 static s7_pointer g_let_set(s7_scheme *sc, s7_pointer args)
9901 {
9902   /* (let ((a 1)) (set! ((curlet) 'a) 32) a) */
9903   #define H_let_set "(let-set! let sym val) sets the symbol sym's value in the let to val"
9904   #define Q_let_set s7_make_signature(sc, 4, sc->T, sc->is_let_symbol, sc->is_symbol_symbol, sc->T)
9905 
9906   return(s7_let_set(sc, car(args), cadr(args), caddr(args)));
9907 }
9908 
9909 static s7_pointer let_set_p_ppp_2(s7_scheme *sc, s7_pointer p1, s7_pointer p2, s7_pointer p3)
9910 {
9911   if (!is_symbol(p2))
9912     return(wrong_type_argument_with_type(sc, sc->let_set_symbol, 2, p2, a_symbol_string));
9913   return(let_set_1(sc, p1, p2, p3));
9914 }
9915 
9916 static s7_pointer g_lint_let_set(s7_scheme *sc, s7_pointer args)
9917 {
9918   s7_pointer y, lt, sym, val;
9919 
9920   lt = car(args);
9921   if (!is_let(lt))
9922     return(wrong_type_argument_with_type(sc, sc->let_set_symbol, 1, lt, a_let_string));
9923   sym = cadr(args);
9924   val = caddr(args);
9925 
9926   if (lt != sc->rootlet)
9927     {
9928       s7_pointer x;
9929       for (x = lt; is_let(x); x = let_outlet(x))
9930 	for (y = let_slots(x); tis_slot(y); y = next_slot(y))
9931 	  if (slot_symbol(y) == sym)
9932 	    {
9933 	      if (slot_has_setter(y))
9934 		slot_set_value(y, call_setter(sc, y, val));
9935 	      else slot_set_value(y, val);
9936 	      return(slot_value(y));
9937 	    }
9938 
9939       if ((has_methods(lt)) &&
9940 	  (has_let_set_fallback(lt)))
9941 	return(call_let_set_fallback(sc, lt, sym, val));
9942     }
9943 
9944   y = global_slot(sym);
9945   if (is_slot(y))
9946     {
9947       if (slot_has_setter(y))
9948 	slot_set_value(y, call_setter(sc, y, val));
9949       else slot_set_value(y, val);
9950       return(slot_value(y));
9951     }
9952 
9953   return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, wrap_string(sc, "let-set!: ~A is not defined in ~A", 33), sym, lt)));
9954 }
9955 
9956 static s7_pointer let_set_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
9957 {
9958   if ((!ops) || (!is_global(sc->let_set_symbol))) return(f);
9959   if (optimize_op(expr) == HOP_SAFE_C_opSq_CS)
9960     {
9961       s7_pointer arg1, arg2, arg3;
9962       arg1 = cadr(expr);
9963       arg2 = caddr(expr);
9964       arg3 = cadddr(expr);
9965       if ((car(arg1) == sc->cdr_symbol) &&
9966 	  (car(arg2) == sc->quote_symbol) &&
9967 	  (is_symbol(cadr(arg2))) &&
9968 	  (!is_possibly_constant(cadr(arg2))) &&
9969 	  (!is_possibly_constant(arg3)))
9970 	return(sc->lint_let_set);
9971     }
9972   return(f);
9973 }
9974 
9975 
9976 static s7_pointer reverse_slots(s7_scheme *sc, s7_pointer list)
9977 {
9978   s7_pointer p = list, result, q;
9979 #if S7_DEBUGGING
9980   if ((list) && (!is_slot(list))) fprintf(stderr, "%s: list is %s\n", __func__, s7_type_names[unchecked_type(list)]);
9981 #endif
9982   result = slot_end(sc);
9983 
9984   while (tis_slot(p))
9985     {
9986       q = next_slot(p);
9987       slot_set_next(p, result);
9988       result = p;
9989       p = q;
9990     }
9991   return(result);
9992 }
9993 
9994 static s7_pointer let_copy(s7_scheme *sc, s7_pointer let)
9995 {
9996   if (is_let(let))
9997     {
9998       s7_pointer new_e;
9999 
10000       if (let == sc->rootlet)   /* (copy (rootlet)) or (copy (funclet abs)) etc */
10001 	return(sc->rootlet);
10002 
10003       /* we can't make copy handle lets-as-objects specially because the make-object function in define-class uses copy to make a new object!
10004        *   So if it is present, we get it here, and then there's almost surely trouble.
10005        */
10006       new_e = make_let_slowly(sc, let_outlet(let));
10007       set_all_methods(new_e, let);
10008       sc->temp3 = new_e;
10009       if (tis_slot(let_slots(let)))
10010 	{
10011 	  s7_int id;
10012 	  s7_pointer x, y = NULL;
10013 
10014 	  id = let_id(new_e);
10015 	  for (x = let_slots(let); tis_slot(x); x = next_slot(x))
10016 	    {
10017 	      s7_pointer z;
10018 	      new_cell(sc, z, T_SLOT);
10019 	      slot_set_symbol(z, slot_symbol(x));
10020 	      slot_set_value(z, slot_value(x));
10021 	      if (symbol_id(slot_symbol(z)) != id) /* keep shadowing intact */
10022 		symbol_set_local_slot(slot_symbol(x), id, z);
10023 	      if (slot_has_setter(x))
10024 		{
10025 		  slot_set_setter(z, slot_setter(x));
10026 		  slot_set_has_setter(z);
10027 		}
10028 	      if (y)
10029 		slot_set_next(y, z);
10030 	      else let_set_slots(new_e, z);
10031 	      slot_set_next(z, slot_end(sc));              /* in case GC runs during this loop */
10032 	      y = z;
10033 	    }}
10034       /* We can't do a (normal) loop here then reverse the slots later because the symbol's local_slot has to
10035        *    match the unshadowed slot, not the last in the list:
10036        *    (let ((e1 (inlet 'a 1 'a 2))) (let ((e2 (copy e1))) (list (equal? e1 e2) (equal? (e1 'a) (e2 'a)))))
10037        */
10038       sc->temp3 = sc->nil;
10039       return(new_e);
10040     }
10041   return(sc->nil);
10042 }
10043 
10044 
10045 /* -------------------------------- rootlet -------------------------------- */
10046 static s7_pointer g_rootlet(s7_scheme *sc, s7_pointer ignore)
10047 {
10048   #define H_rootlet "(rootlet) returns the current top-level definitions (symbol bindings)."
10049   #define Q_rootlet s7_make_signature(sc, 1, sc->is_let_symbol)
10050   return(sc->rootlet);
10051 }
10052 /* as with the symbol-table, this function can lead to disaster -- user could
10053  *   clobber the let etc.  But we want it to be editable and augmentable,
10054  *   so I guess I'll leave it alone.  (See curlet|funclet as well).
10055  */
10056 
10057 s7_pointer s7_rootlet(s7_scheme *sc) {return(sc->rootlet);}
10058 
10059 /* shadow_rootlet is a convenience for foreign function writers -- the C code can act as if it were loading everything into rootlet,
10060  *   but when actually loaded, everything can be shunted into a separate namespace (*motif* for example).
10061  */
10062 s7_pointer s7_shadow_rootlet(s7_scheme *sc) {return(sc->shadow_rootlet);}
10063 
10064 s7_pointer s7_set_shadow_rootlet(s7_scheme *sc, s7_pointer let)
10065 {
10066   s7_pointer old_let;
10067   old_let = sc->shadow_rootlet;
10068   sc->shadow_rootlet = let;
10069   return(old_let); /* like s7_set_curlet below */
10070 }
10071 
10072 
10073 /* -------------------------------- curlet -------------------------------- */
10074 
10075 static s7_pointer g_curlet(s7_scheme *sc, s7_pointer args)
10076 {
10077   #define H_curlet "(curlet) returns the current definitions (symbol bindings)"
10078   #define Q_curlet s7_make_signature(sc, 1, sc->is_let_symbol)
10079 
10080   sc->capture_let_counter++;
10081   return((is_let(sc->curlet)) ? sc->curlet : sc->rootlet);
10082 }
10083 
10084 s7_pointer s7_curlet(s7_scheme *sc)
10085 {
10086   sc->capture_let_counter++;
10087   return(sc->curlet);
10088 }
10089 
10090 static void update_symbol_ids(s7_scheme *sc, s7_pointer e)
10091 {
10092   s7_pointer p;
10093   for (p = let_slots(e); tis_slot(p); p = next_slot(p))
10094     {
10095       s7_pointer sym;
10096       sym = slot_symbol(p);
10097       if (symbol_id(sym) != sc->let_number)
10098 	symbol_set_local_slot_unincremented(sym, sc->let_number, p);
10099     }
10100 }
10101 
10102 s7_pointer s7_set_curlet(s7_scheme *sc, s7_pointer e)
10103 {
10104   s7_pointer old_e;
10105   old_e = sc->curlet;
10106   sc->curlet = e;
10107 
10108   if ((is_let(e)) && (let_id(e) > 0)) /* might be () [id=-1] or rootlet [id=0?] etc */
10109     {
10110       let_set_id(e, ++sc->let_number);
10111       update_symbol_ids(sc, e);
10112     }
10113   return(old_e);
10114 }
10115 
10116 
10117 /* -------------------------------- outlet -------------------------------- */
10118 s7_pointer s7_outlet(s7_scheme *sc, s7_pointer e) {return((is_let(e)) ? let_outlet(e) : sc->nil);}
10119 
10120 static s7_pointer g_outlet(s7_scheme *sc, s7_pointer args)
10121 {
10122   #define H_outlet "(outlet let) is the environment that contains let."
10123   #define Q_outlet s7_make_signature(sc, 2, sc->is_let_symbol, sc->is_let_symbol)
10124 
10125   s7_pointer let;
10126 
10127   let = car(args);
10128   if (!is_let(let))
10129     return(s7_wrong_type_arg_error(sc, "outlet", 1, let, "a let")); /* not a method call here! */
10130 
10131   if ((let == sc->rootlet) ||
10132       (is_null(let_outlet(let))))
10133     return(sc->rootlet);
10134   return(let_outlet(let));
10135 }
10136 
10137 static s7_pointer g_set_outlet(s7_scheme *sc, s7_pointer args)
10138 {
10139   /* (let ((a 1)) (let ((b 2)) (set! (outlet (curlet)) (rootlet)) ((curlet) 'a))) */
10140   s7_pointer let, new_outer;
10141 
10142   let = car(args);
10143   if (!is_let(let))
10144     return(s7_wrong_type_arg_error(sc, "set! outlet", 1, let, "a let"));
10145   if ((is_immutable(let)) || (let == sc->s7_let))
10146     return(s7_wrong_type_arg_error(sc, "set! outlet", 1, let, "a mutable let"));
10147 
10148   new_outer = cadr(args);
10149   if (!is_let(new_outer))
10150     return(s7_wrong_type_arg_error(sc, "set! outlet", 2, new_outer, "a let"));
10151 
10152   if (let != sc->rootlet)
10153     let_set_outlet(let, (new_outer == sc->rootlet) ? sc->nil : new_outer);  /* outlet rootlet->() so that slot search can use is_let(outlet) I think */
10154   return(new_outer);
10155 }
10156 
10157 /* -------------------------------- symbol lookup -------------------------------- */
10158 
10159 static inline s7_pointer lookup_from(s7_scheme *sc, const s7_pointer symbol, s7_pointer e)
10160 {
10161   if (let_id(e) == symbol_id(symbol))
10162     return(local_value(symbol));
10163   if (symbol_id(symbol) < let_id(e))
10164     {
10165       do {e = let_outlet(e);} while (symbol_id(symbol) < let_id(e));
10166       if (let_id(e) == symbol_id(symbol))
10167 	return(local_value(symbol));
10168     }
10169   for (; is_let(e); e = let_outlet(e))
10170     {
10171       s7_pointer y;
10172       for (y = let_slots(e); tis_slot(y); y = next_slot(y))
10173 	if (slot_symbol(y) == symbol)
10174 	  return(slot_value(y));
10175     }
10176   if (is_slot(global_slot(symbol)))
10177     return(global_value(symbol));
10178 #if WITH_GCC
10179   return(NULL); /* much faster than various alternatives */
10180 #else
10181   return(unbound_variable(sc, symbol));
10182 #endif
10183 }
10184 
10185 static inline s7_pointer lookup_slot_from(s7_pointer symbol, s7_pointer e)
10186 {
10187   if (let_id(e) == symbol_id(symbol))
10188     return(local_slot(symbol));
10189   if (symbol_id(symbol) < let_id(e))
10190     {
10191       do {e = let_outlet(e);} while (symbol_id(symbol) < let_id(e));
10192       if (let_id(e) == symbol_id(symbol))
10193 	return(local_slot(symbol));
10194     }
10195   for (; is_let(e); e = let_outlet(e))
10196     {
10197       s7_pointer y;
10198       for (y = let_slots(e); tis_slot(y); y = next_slot(y))
10199 	if (slot_symbol(y) == symbol)
10200 	  return(y);
10201     }
10202   return(global_slot(symbol));
10203 }
10204 
10205 #if WITH_GCC && S7_DEBUGGING
10206 static s7_pointer lookup_1(s7_scheme *sc, const s7_pointer symbol) /* sc arg could be omitted, but it makes no difference in timing tests */
10207 #else
10208 static inline s7_pointer lookup(s7_scheme *sc, const s7_pointer symbol) /* lookup_checked includes the unbound_variable call */
10209 #endif
10210 {
10211   return(lookup_from(sc, symbol, sc->curlet));
10212 }
10213 
10214 s7_pointer s7_slot(s7_scheme *sc, s7_pointer symbol) {return(lookup_slot_from(symbol, sc->curlet));}
10215 s7_pointer s7_slot_value(s7_pointer slot) {return(slot_value(slot));}
10216 
10217 s7_pointer s7_slot_set_value(s7_scheme *sc, s7_pointer slot, s7_pointer value)
10218 {
10219   slot_set_value(slot, value);
10220   return(value);
10221 }
10222 
10223 void s7_slot_set_real_value(s7_scheme *sc, s7_pointer slot, s7_double value)
10224 {
10225   set_real(slot_value(slot), value);
10226 }
10227 
10228 static s7_pointer symbol_to_local_slot(s7_scheme *sc, s7_pointer symbol, s7_pointer e)
10229 {
10230   if (!is_let(e))
10231     return(global_slot(symbol));
10232 
10233   if (symbol_id(symbol) != 0)
10234     {
10235       s7_pointer y;
10236       for (y = let_slots(e); tis_slot(y); y = next_slot(y))
10237 	if (slot_symbol(y) == symbol)
10238 	  return(y);
10239     }
10240   return(sc->undefined);
10241 }
10242 
10243 s7_pointer s7_symbol_value(s7_scheme *sc, s7_pointer sym)
10244 {
10245   s7_pointer x;
10246   x = lookup_slot_from(sym, sc->curlet);
10247   return((is_slot(x)) ? slot_value(x) : sc->undefined);
10248 }
10249 
10250 s7_pointer s7_symbol_local_value(s7_scheme *sc, s7_pointer sym, s7_pointer let)
10251 {
10252   /* restrict the search to local let outward */
10253   if ((let == sc->rootlet) || (is_global(sym)))
10254     return((is_slot(global_slot(sym))) ? global_value(sym) : sc->undefined);
10255 
10256   if (is_let(let))
10257     {
10258       if (let_id(let) == symbol_id(sym))
10259 	return(local_value(sym));
10260       if (symbol_id(sym) < let_id(let))
10261 	{
10262 	  do {let = let_outlet(let);} while (symbol_id(sym) < let_id(let));
10263 	  if (let_id(let) == symbol_id(sym))
10264 	    return(local_value(sym));
10265 	}
10266       for (; is_let(let); let = let_outlet(let))
10267 	{
10268 	  s7_pointer y;
10269 	  for (y = let_slots(let); tis_slot(y); y = next_slot(y))
10270 	    if (slot_symbol(y) == sym)
10271 	      return(slot_value(y));
10272 	}
10273       /* need to check rootlet before giving up */
10274       if (is_slot(global_slot(sym)))
10275 	return(global_value(sym));
10276 
10277       /* (let ((e (curlet))) (let ((a 1)) (symbol->value 'a e))) -> #<undefined> not 1 */
10278       return(sc->undefined); /* 29-Nov-17 */
10279     }
10280   return(s7_symbol_value(sc, sym));
10281 }
10282 
10283 
10284 /* -------------------------------- symbol->value -------------------------------- */
10285 
10286 #define lookup_global(Sc, Sym) ((is_global(Sym)) ? global_value(Sym) : lookup_checked(Sc, Sym))
10287 
10288 static s7_pointer g_s7_let_ref_fallback(s7_scheme *sc, s7_pointer args);
10289 static s7_pointer g_s7_let_set_fallback(s7_scheme *sc, s7_pointer args);
10290 
10291 static s7_pointer g_symbol_to_value(s7_scheme *sc, s7_pointer args)
10292 {
10293   #define H_symbol_to_value "(symbol->value sym (let (curlet))) returns the binding of (the value associated with) the \
10294 symbol sym in the given let: (let ((x 32)) (symbol->value 'x)) -> 32"
10295   #define Q_symbol_to_value s7_make_signature(sc, 3, sc->T, sc->is_symbol_symbol, sc->is_let_symbol)
10296   /* (symbol->value 'x e) => (e 'x)? */
10297 
10298   s7_pointer sym;
10299   sym = car(args);
10300 
10301   if (!is_symbol(sym))
10302     return(method_or_bust(sc, sym, sc->symbol_to_value_symbol, args, T_SYMBOL, 1));
10303 
10304   if (is_not_null(cdr(args)))
10305     {
10306       s7_pointer local_let;
10307 
10308       local_let = cadr(args);
10309       if (local_let == sc->unlet_symbol)
10310 	return((is_slot(initial_slot(sym))) ? initial_value(sym) : sc->undefined);
10311 
10312       if (!is_let(local_let))
10313 	return(method_or_bust_with_type(sc, local_let, sc->symbol_to_value_symbol, args, a_let_string, 2));
10314 
10315       if (local_let == sc->s7_let)
10316 	return(g_s7_let_ref_fallback(sc, set_qlist_2(sc, local_let, sym)));
10317 
10318       return(s7_symbol_local_value(sc, sym, local_let));
10319     }
10320 
10321   if (is_global(sym))
10322     return(global_value(sym));
10323 
10324   return(s7_symbol_value(sc, sym));
10325 }
10326 
10327 s7_pointer s7_symbol_set_value(s7_scheme *sc, s7_pointer sym, s7_pointer val)
10328 {
10329   s7_pointer x;
10330   /* if immutable should this return an error? */
10331   x = lookup_slot_from(sym, sc->curlet);
10332   if (is_slot(x))
10333     slot_set_value(x, val); /* with_hook? */
10334   return(val);
10335 }
10336 
10337 
10338 /* -------------------------------- symbol->dynamic-value -------------------------------- */
10339 
10340 static s7_pointer find_dynamic_value(s7_scheme *sc, s7_pointer x, s7_pointer sym, int64_t *id)
10341 {
10342   for (; symbol_id(sym) < let_id(x); x = let_outlet(x));
10343 
10344   if (let_id(x) == symbol_id(sym))
10345     {
10346       (*id) = let_id(x);
10347       return(local_value(sym));
10348     }
10349   for (; (is_let(x)) && (let_id(x) > (*id)); x = let_outlet(x))
10350     {
10351       s7_pointer y;
10352       for (y = let_slots(x); tis_slot(y); y = next_slot(y))
10353 	if (slot_symbol(y) == sym)
10354 	  {
10355 	    (*id) = let_id(x);
10356 	    return(slot_value(y));
10357 	  }}
10358   return(sc->unused);
10359 }
10360 
10361 static s7_pointer g_symbol_to_dynamic_value(s7_scheme *sc, s7_pointer args)
10362 {
10363   #define H_symbol_to_dynamic_value "(symbol->dynamic-value sym) returns the dynamic binding of the symbol sym"
10364   #define Q_symbol_to_dynamic_value s7_make_signature(sc, 2, sc->T, sc->is_symbol_symbol)
10365 
10366   s7_pointer sym, val;
10367   int64_t i, top_id;
10368 
10369   sym = car(args);
10370   if (!is_symbol(sym))
10371     return(method_or_bust(sc, sym, sc->symbol_to_dynamic_value_symbol, args, T_SYMBOL, 1));
10372 
10373   if (is_global(sym))
10374     return(global_value(sym));
10375 
10376   if (let_id(sc->curlet) == symbol_id(sym))
10377     return(local_value(sym));
10378 
10379   top_id = -1;
10380   val = find_dynamic_value(sc, sc->curlet, sym, &top_id);
10381   if (top_id == symbol_id(sym))
10382     return(val);
10383 
10384   for (i = current_stack_top(sc) - 1; i > 0; i -= 4)
10385     if (is_let_unchecked(stack_let(sc->stack, i))) /* OP_GC_PROTECT let slot can be anything (even free) */
10386       {
10387 	s7_pointer cur_val;
10388 	cur_val = find_dynamic_value(sc, stack_let(sc->stack, i), sym, &top_id);
10389 	if (cur_val != sc->unused)
10390 	  val = cur_val;
10391 	if (top_id == symbol_id(sym))
10392 	  return(val);
10393       }
10394   return((val == sc->unused) ? s7_symbol_value(sc, sym) : val);
10395 }
10396 
10397 
10398 typedef bool (safe_sym_t)(s7_scheme *sc, s7_pointer sym, s7_pointer e);
10399 
10400 static bool direct_memq(s7_pointer symbol, s7_pointer symbols)
10401 {
10402   s7_pointer x;
10403   for (x = symbols; is_pair(x); x = cdr(x))
10404     if (car(x) == symbol)
10405 	return(true);
10406   return(false);
10407 }
10408 
10409 static bool direct_assq(s7_pointer symbol, s7_pointer symbols)
10410 { /* used only below in do_symbol_is_safe */
10411   s7_pointer x;
10412   for (x = symbols; is_pair(x); x = cdr(x))
10413     if (caar(x) == symbol)
10414       return(true);
10415   return(false);
10416 }
10417 
10418 static bool do_symbol_is_safe(s7_scheme *sc, s7_pointer sym, s7_pointer e)
10419 {
10420   return((is_slot(global_slot(sym))) ||
10421 	 (direct_assq(sym, e)) ||
10422 	 (is_slot(lookup_slot_from(sym, sc->curlet))));
10423 }
10424 
10425 static bool let_symbol_is_safe(s7_scheme *sc, s7_pointer sym, s7_pointer e)
10426 {
10427   if (is_slot(global_slot(sym)))
10428     return(true);
10429   if (is_null(e))
10430     e = sc->rootlet;
10431   return((!is_with_let_let(e)) &&
10432 	 (is_slot(lookup_slot_from(sym, sc->curlet))));
10433 }
10434 
10435 static bool let_symbol_is_safe_or_listed(s7_scheme *sc, s7_pointer sym, s7_pointer e)
10436 {
10437   return((symbol_is_in_list(sc, sym)) ||
10438 	 (let_symbol_is_safe(sc, sym, e)));
10439 }
10440 
10441 static bool let_star_symbol_is_safe(s7_scheme *sc, s7_pointer sym, s7_pointer e)
10442 {
10443   return((symbol_is_in_list(sc, sym)) ||
10444 	 (is_slot(global_slot(sym))) ||
10445 	 ((is_let(e)) && (!is_with_let_let(e)) && (is_slot(lookup_slot_from(sym, sc->curlet)))));
10446 }
10447 
10448 static bool pair_symbol_is_safe(s7_scheme *sc, s7_pointer sym, s7_pointer e)
10449 {
10450   return((is_slot(global_slot(sym))) ||
10451 	 (direct_memq(sym, e)));
10452 }
10453 
10454 static inline s7_pointer collect_variables(s7_scheme *sc, s7_pointer lst, s7_pointer e)
10455 {
10456   /* collect local variable names from let/do (pre-error-check) */
10457   s7_pointer p;
10458   sc->w = e;
10459   for (p = lst; is_pair(p); p = cdr(p))
10460     sc->w = cons(sc, add_symbol_to_list(sc, caar(p)), sc->w);
10461   return(sc->w);
10462 }
10463 
10464 static s7_pointer collect_parameters(s7_scheme *sc, s7_pointer lst, s7_pointer e)
10465 {
10466   /* collect local variable names from lambda arglists (pre-error-check) */
10467   s7_pointer p;
10468   s7_int the_un_id;
10469   the_un_id = ++sc->let_number;
10470   if (is_symbol(lst))
10471     {
10472       symbol_set_id(lst, the_un_id);
10473       return(cons(sc, add_symbol_to_list(sc, lst), e));
10474     }
10475   sc->w = e;
10476   for (p = lst; is_pair(p); p = cdr(p))
10477     {
10478       s7_pointer car_p;
10479       car_p = car(p);
10480       if (is_pair(car_p))
10481 	car_p = car(car_p);
10482       if (is_normal_symbol(car_p))
10483 	{
10484 	  symbol_set_id(car_p, the_un_id);
10485 	  sc->w = cons(sc, add_symbol_to_list(sc, car_p), sc->w);
10486 	}}
10487   if (is_symbol(p)) /* rest arg */
10488     {
10489       symbol_set_id(p, the_un_id);
10490       sc->w = cons(sc, add_symbol_to_list(sc, p), sc->w);
10491     }
10492   return(sc->w);
10493 }
10494 
10495 typedef enum {OPT_F, OPT_T, OPT_OOPS} opt_t;
10496 static opt_t optimize(s7_scheme *sc, s7_pointer code, int32_t hop, s7_pointer e);
10497 
10498 static void clear_all_optimizations(s7_scheme *sc, s7_pointer p)
10499 {
10500   /* I believe that we would not have been optimized to begin with if the tree were circular,
10501    *   and this tree is supposed to be a function call + args -- a circular list here is a bug.
10502    *   but (define x <circular list>)?
10503    */
10504   if (is_pair(p))
10505     {
10506       if ((is_optimized(p)) &&
10507  	  (((optimize_op(p) >= FIRST_UNHOPPABLE_OP) ||  /* avoid clearing hop ops, fx_function and op_unknown* need to be cleared */
10508 	    (!op_has_hop(p)))))
10509 	{
10510 	  clear_optimized(p);     /* includes T_SYNTACTIC */
10511 	  clear_optimize_op(p);
10512 	}
10513       clear_all_optimizations(sc, cdr(p));
10514       clear_all_optimizations(sc, car(p));
10515     }
10516 }
10517 
10518 #if S7_DEBUGGING
10519 #define unstack(sc) unstack_1(sc, __func__, __LINE__)
10520 static void unstack_1(s7_scheme *sc, const char *func, int line)
10521 {
10522   sc->stack_end -= 4;
10523   if ((((opcode_t)sc->stack_end[3]) != OP_GC_PROTECT) && (((opcode_t)sc->stack_end[3]) != OP_SPLICE_VALUES)) /* splice can happen in object->port */
10524     {
10525       fprintf(stderr, "%s%s[%d]: popped %s?%s\n", BOLD_TEXT, func, line, op_names[(opcode_t)sc->stack_end[3]], UNBOLD_TEXT);
10526       fprintf(stderr, "    code: %s, args: %s\n", display(sc->code), display(sc->args));
10527       fprintf(stderr, "    cur_code: %s, estr: %s\n", display(current_code(sc)), display(s7_name_to_value(sc, "estr")));
10528       if (sc->stop_at_error) abort();
10529     }
10530 }
10531 #else
10532 #define unstack(sc) sc->stack_end -= 4
10533 #endif
10534 
10535 static s7_pointer add_trace(s7_scheme *sc, s7_pointer code)
10536 {
10537   if ((is_pair(car(code))) && (caar(code) == sc->trace_in_symbol))
10538     return(code);
10539   return(cons(sc, list_2(sc, sc->trace_in_symbol, list_1(sc, sc->curlet_symbol)), code));
10540 }
10541 
10542 static s7_pointer add_profile(s7_scheme *sc, s7_pointer code)
10543 {
10544   s7_pointer p;
10545   if ((is_pair(car(code))) && (caar(code) == sc->profile_in_symbol))
10546     return(code);
10547   p = cons(sc, list_2(sc, sc->profile_in_symbol, list_1(sc, sc->curlet_symbol)), code);
10548   set_unsafe_optimize_op(car(p), OP_PROFILE_IN);
10549   return(p);
10550 }
10551 
10552 static bool tree_has_definers(s7_scheme *sc, s7_pointer tree)
10553 {
10554   s7_pointer p;
10555   for (p = tree; is_pair(p); p = cdr(p))
10556     if (tree_has_definers(sc, car(p)))
10557       return(true);
10558   return((is_symbol(tree)) &&
10559 	 (is_definer(tree)));
10560 }
10561 
10562 static s7_pointer make_macro(s7_scheme *sc, opcode_t op, bool unnamed)
10563 {
10564   s7_pointer mac, body, mac_name = NULL;
10565   uint64_t typ;
10566 
10567   switch (op)
10568     {
10569     case OP_DEFINE_MACRO:      case OP_MACRO:      typ = T_MACRO;      break;
10570     case OP_DEFINE_MACRO_STAR: case OP_MACRO_STAR: typ = T_MACRO_STAR; break;
10571     case OP_DEFINE_BACRO:      case OP_BACRO:      typ = T_BACRO;      break;
10572     case OP_DEFINE_BACRO_STAR: case OP_BACRO_STAR: typ = T_BACRO_STAR; break;
10573     case OP_DEFINE_EXPANSION:                      typ = T_MACRO | ((is_let(sc->curlet)) ? 0 : T_EXPANSION);      break; /* local expansions are just normal macros */
10574     case OP_DEFINE_EXPANSION_STAR:                 typ = T_MACRO_STAR | ((is_let(sc->curlet)) ? 0 : T_EXPANSION); break;
10575     default:
10576 #if S7_DEBUGGING
10577       fprintf(stderr, "%s[%d]: got %s\n", __func__, __LINE__, op_names[op]);
10578 #endif
10579       typ = T_MACRO;
10580       break;
10581     }
10582 
10583   new_cell(sc, mac, typ | T_COPY_ARGS | T_DONT_EVAL_ARGS);
10584   sc->temp6 = mac;
10585   closure_set_args(mac, (unnamed) ? car(sc->code) : cdar(sc->code));
10586   body = cdr(sc->code);
10587   closure_set_body(mac, body);
10588   closure_set_setter(mac, sc->F);
10589   closure_set_let(mac, sc->curlet);
10590   closure_set_arity(mac, CLOSURE_ARITY_NOT_SET);
10591   sc->capture_let_counter++;
10592 
10593   if (!unnamed)
10594     {
10595       s7_pointer cx;
10596       mac_name = caar(sc->code);
10597       if (((op == OP_DEFINE_EXPANSION) || (op == OP_DEFINE_EXPANSION_STAR)) &&
10598 	  (!is_let(sc->curlet)))
10599 	set_full_type(mac_name, T_EXPANSION | T_SYMBOL | (full_type(mac_name) & T_UNHEAP)); /* see comment under READ_TOK */
10600       /* symbol? macro name has already been checked, find name in let, and define it */
10601       cx = symbol_to_local_slot(sc, mac_name, sc->curlet);
10602       if (is_slot(cx))
10603 	slot_set_value_with_hook(cx, mac);
10604       else s7_make_slot(sc, sc->curlet, mac_name, mac); /* was current but we've checked immutable already */
10605       if (tree_has_definers(sc, body))
10606 	set_is_definer(mac_name);            /* (list-values 'define ...) aux-13 */
10607     }
10608 
10609   if ((!is_either_bacro(mac)) &&
10610       (optimize(sc, body, 1, collect_parameters(sc, closure_args(mac), sc->nil)) == OPT_OOPS))
10611     clear_all_optimizations(sc, body);
10612 
10613   sc->temp6 = sc->nil;
10614   if (sc->debug > 1) /* no profile here */
10615     {
10616       s7_gc_protect_via_stack(sc, mac);  /* GC protect func during add_trace */
10617       closure_set_body(mac, add_trace(sc, body));
10618       unstack(sc);
10619     }
10620   if (!unnamed)
10621     {
10622       set_pair_macro(closure_body(mac), mac_name);
10623       set_has_pair_macro(mac);
10624       if (has_location(car(sc->code)))
10625 	{
10626 	  pair_set_location(closure_body(mac), pair_location(car(sc->code)));
10627 	  set_has_location(closure_body(mac));
10628 	}}
10629   /* passed to maclet in apply_macro et al, copied in copy_closure */
10630   return(mac);
10631 }
10632 
10633 static Inline s7_pointer inline_make_closure(s7_scheme *sc, s7_pointer args, s7_pointer code, uint64_t type, int32_t arity)
10634 {
10635   /* this is called (almost?) every time a lambda form is evaluated, or during letrec, etc */
10636   s7_pointer x;
10637   new_cell(sc, x, (type | closure_bits(code)));
10638   closure_set_args(x, args);
10639   closure_set_let(x, sc->curlet);
10640   closure_set_setter(x, sc->F);
10641   closure_set_arity(x, arity);
10642   closure_set_body(x, code);           /* in case add_trace triggers GC, new func (x) needs some legit body for mark_closure */
10643   if (sc->debug_or_profile)
10644     {
10645       s7_gc_protect_via_stack(sc, x);  /* GC protect func during add_trace */
10646       closure_set_body(x, (sc->debug > 1) ? add_trace(sc, code) : add_profile(sc, code));
10647       set_closure_has_multiform(x);
10648       unstack(sc);
10649     }
10650   else
10651     {
10652       if (is_pair(cdr(code)))
10653 	set_closure_has_multiform(x);
10654       else set_closure_has_one_form(x);
10655     }
10656   sc->capture_let_counter++;
10657   return(x);
10658 }
10659 
10660 static s7_pointer make_closure(s7_scheme *sc, s7_pointer args, s7_pointer code, uint64_t type, int32_t arity)
10661 {
10662   return(inline_make_closure(sc, args, code, type, arity));
10663 }
10664 
10665 static int32_t closure_length(s7_scheme *sc, s7_pointer e)
10666 {
10667   /* we can't use let_length(sc, closure_let(e)) because the closure_let(closure)
10668    *   changes.  So the open bit is not always on.  Besides, the fallbacks need to be for closures, not lets.
10669    */
10670   s7_pointer length_func;
10671   length_func = find_method(sc, closure_let(e), sc->length_symbol);
10672   if (length_func != sc->undefined)
10673     return((int32_t)s7_integer_checked(sc, call_method(sc, e, length_func, set_plist_1(sc, e))));
10674 
10675   /* there are cases where this should raise a wrong-type-arg error, but for now... */
10676   return(-1);
10677 }
10678 
10679 static s7_pointer cons_unchecked_with_type(s7_scheme *sc, s7_pointer p, s7_pointer a, s7_pointer b);
10680 
10681 static s7_pointer copy_tree_with_type(s7_scheme *sc, s7_pointer tree)
10682 {
10683   /* if sc->safety > NO_SAFETY, '(1 2) is set immutable by the reader, but eval (in that safety case) calls
10684    *   copy_body on the incoming tree, so we have to preserve T_IMMUTABLE in that case.
10685    * if tree is something like (+ 1 (car '#1=(2 . #1#))), we have to see the quoted list and not copy it.
10686    * Before getting here, we have checked that there is room for the entire tree (in copy_body), or 8192 cells (in list_values) in the free heap.
10687    */
10688 #if WITH_GCC
10689   #define COPY_TREE_WITH_TYPE(P) ({s7_pointer _p; _p = P; \
10690                                    cons_unchecked_with_type(sc, _p, (is_unquoted_pair(car(_p))) ? copy_tree_with_type(sc, car(_p)) : car(_p), \
10691                                                                     (is_unquoted_pair(cdr(_p))) ? copy_tree_with_type(sc, cdr(_p)) : cdr(_p));})
10692 #else
10693   #define COPY_TREE_WITH_TYPE(P) copy_tree_with_type(sc, P)
10694 #endif
10695   return(cons_unchecked_with_type(sc, tree,
10696 				  (is_unquoted_pair(car(tree))) ? COPY_TREE_WITH_TYPE(car(tree)) : car(tree),
10697 				  (is_unquoted_pair(cdr(tree))) ? COPY_TREE_WITH_TYPE(cdr(tree)) : cdr(tree)));
10698 }
10699 
10700 static s7_pointer copy_tree(s7_scheme *sc, s7_pointer tree)
10701 {
10702 #if WITH_GCC
10703   #define COPY_TREE(P) ({s7_pointer _p; _p = P; \
10704                          cons_unchecked(sc, (is_unquoted_pair(car(_p))) ? copy_tree(sc, car(_p)) : car(_p), \
10705                                             (is_pair(cdr(_p))) ? copy_tree(sc, cdr(_p)) : cdr(_p));})
10706 #else
10707   #define COPY_TREE(P) copy_tree(sc, P)
10708 #endif
10709   return(cons_unchecked(sc,
10710 			(is_unquoted_pair(car(tree))) ? COPY_TREE(car(tree)) : car(tree),
10711 			(is_pair(cdr(tree))) ? COPY_TREE(cdr(tree)) : cdr(tree)));
10712 }
10713 
10714 
10715 /* -------------------------------- tree-cyclic? -------------------------------- */
10716 #define TREE_NOT_CYCLIC 0
10717 #define TREE_CYCLIC 1
10718 #define TREE_HAS_PAIRS 2
10719 
10720 static int tree_is_cyclic_or_has_pairs(s7_scheme *sc, s7_pointer tree)
10721 {
10722   s7_pointer fast, slow;
10723   bool has_pairs = false;
10724 
10725   if (!is_pair(tree)) return(TREE_NOT_CYCLIC);
10726   slow = tree;
10727   fast = tree;
10728   while (true)
10729     {
10730       if (tree_is_collected(fast)) return(TREE_CYCLIC);
10731       if ((!has_pairs) &&
10732 	  (is_unquoted_pair(car(fast))))
10733 	has_pairs = true;
10734       fast = cdr(fast);
10735       if (!is_pair(fast))
10736 	{
10737 	  if (!has_pairs) return(TREE_NOT_CYCLIC);
10738 	  break;
10739 	}
10740       if (tree_is_collected(fast)) return(TREE_CYCLIC);
10741       if ((!has_pairs) &&
10742 	  (is_unquoted_pair(car(fast))))
10743 	has_pairs = true;
10744       fast = cdr(fast);
10745       if (!is_pair(fast))
10746 	{
10747 	  if (!has_pairs) return(TREE_NOT_CYCLIC);
10748 	  break;
10749 	}
10750       slow = cdr(slow);
10751       if (fast == slow) return(TREE_CYCLIC);
10752     }
10753   return(TREE_HAS_PAIRS);
10754 }
10755 
10756 /* we can't use shared_info here because tree_is_cyclic may be called in the midst of output that depends on sc->circle_info */
10757 
10758 static bool tree_is_cyclic_1(s7_scheme *sc, s7_pointer tree)
10759 {
10760   s7_pointer p;
10761   for (p = tree; is_pair(p); p = cdr(p))
10762     {
10763       tree_set_collected(p);
10764       if (sc->tree_pointers_top == sc->tree_pointers_size)
10765 	{
10766 	  if (sc->tree_pointers_size == 0)
10767 	    {
10768 	      sc->tree_pointers_size = 8;
10769 	      sc->tree_pointers = (s7_pointer *)Malloc(sc->tree_pointers_size * sizeof(s7_pointer));
10770 	    }
10771 	  else
10772 	    {
10773 	      sc->tree_pointers_size *= 2;
10774 	      sc->tree_pointers = (s7_pointer *)Realloc(sc->tree_pointers, sc->tree_pointers_size * sizeof(s7_pointer));
10775 	    }}
10776       sc->tree_pointers[sc->tree_pointers_top++] = p;
10777       if (is_unquoted_pair(car(p)))
10778 	{
10779 	  int32_t i, old_top, result;
10780 	  old_top = sc->tree_pointers_top;
10781 	  result = tree_is_cyclic_or_has_pairs(sc, car(p));
10782 	  if ((result == TREE_CYCLIC) ||
10783 	      (tree_is_cyclic_1(sc, car(p))))
10784 	    return(true);
10785 	  for (i = old_top; i < sc->tree_pointers_top; i++)
10786 	    tree_clear_collected(sc->tree_pointers[i]);
10787 	  sc->tree_pointers_top = old_top;
10788 	}}
10789   return(false);
10790 }
10791 
10792 static bool tree_is_cyclic(s7_scheme *sc, s7_pointer tree)
10793 {
10794   int32_t i, result;
10795 
10796   result = tree_is_cyclic_or_has_pairs(sc, tree);
10797   if (result == TREE_NOT_CYCLIC) return(false);
10798   if (result == TREE_CYCLIC) return(true);
10799   result = tree_is_cyclic_1(sc, tree);
10800   for (i = 0; i < sc->tree_pointers_top; i++)
10801     tree_clear_collected(sc->tree_pointers[i]);
10802   sc->tree_pointers_top = 0;
10803  return(result);
10804 }
10805 
10806 static s7_pointer g_tree_is_cyclic(s7_scheme *sc, s7_pointer args)
10807 {
10808   #define H_tree_is_cyclic "(tree-cyclic? tree) returns #t if the tree has a cycle."
10809   #define Q_tree_is_cyclic sc->pl_bt
10810   return(make_boolean(sc, tree_is_cyclic(sc, car(args))));
10811 }
10812 
10813 static inline s7_int tree_len(s7_scheme *sc, s7_pointer p);
10814 
10815 static s7_pointer copy_body(s7_scheme *sc, s7_pointer p)
10816 {
10817   sc->w = p;
10818   if (tree_is_cyclic(sc, p))
10819     s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "copy: tree is cyclic", 20));
10820   check_free_heap_size(sc, tree_len(sc, p) * 2);
10821   return((sc->safety > NO_SAFETY) ? copy_tree_with_type(sc, p) : copy_tree(sc, p));
10822 }
10823 
10824 static s7_pointer copy_closure(s7_scheme *sc, s7_pointer fnc)
10825 {
10826   /* copy the source tree annotating (for eventual optimization), return a thing of the same type as fnc */
10827   s7_pointer x, body;
10828 
10829   body = copy_body(sc, closure_body(fnc));
10830   if ((is_any_macro(fnc)) && (has_pair_macro(fnc)))
10831     {
10832       set_pair_macro(body, pair_macro(closure_body(fnc)));
10833       set_has_pair_macro(fnc);
10834     }
10835   new_cell(sc, x, full_type(fnc) & (~T_COLLECTED)); /* I'm paranoid about that is_collected bit */
10836   closure_set_args(x, closure_args(fnc));
10837   closure_set_body(x, body);
10838   closure_set_setter(x, closure_setter(fnc));
10839   closure_set_arity(x, closure_arity(fnc));
10840   closure_set_let(x, closure_let(fnc));
10841   return(x);
10842 }
10843 
10844 
10845 /* -------------------------------- defined? -------------------------------- */
10846 static s7_pointer g_is_defined(s7_scheme *sc, s7_pointer args)
10847 {
10848   #define H_is_defined "(defined? symbol (let (curlet)) ignore-globals) returns #t if symbol has a binding (a value) in the environment let.  Only let is searched if ignore-globals is not #f."
10849   #define Q_is_defined s7_make_signature(sc, 4, sc->is_boolean_symbol, sc->is_symbol_symbol, sc->is_let_symbol, sc->is_boolean_symbol)
10850 
10851   /* if the symbol has a global slot and e is unset or rootlet, this returns #t */
10852   s7_pointer sym;
10853   sym = car(args);
10854   if (!is_symbol(sym))
10855     return(method_or_bust(sc, sym, sc->is_defined_symbol, args, T_SYMBOL, 1));
10856 
10857   if (is_pair(cdr(args)))
10858     {
10859       s7_pointer e, b, x;
10860 
10861       e = cadr(args);
10862       if (!is_let(e))
10863 	return(wrong_type_argument_with_type(sc, sc->is_defined_symbol, 2, e, a_let_string));
10864       if (e == sc->s7_let)
10865 	return(make_boolean(sc, symbol_s7_let(sym) != 0));
10866 
10867       if (is_pair(cddr(args)))
10868 	{
10869 	  b = caddr(args);
10870 	  if (!s7_is_boolean(b))
10871 	    return(method_or_bust_with_type(sc, b, sc->is_defined_symbol, args, a_boolean_string, 3));
10872 	}
10873       else b = sc->F;
10874 
10875       if (e == sc->rootlet) /* we checked (let? e) above */
10876 	{
10877 	  if (b == sc->F)
10878 	    return(make_boolean(sc, is_slot(global_slot(sym)))); /* new_symbol and gensym initialize global_slot to #<undefined> */
10879 	  return(sc->F);
10880 	}
10881 
10882       x = symbol_to_local_slot(sc, sym, e);
10883       if (is_slot(x))
10884 	return(sc->T);
10885 
10886       return((b == sc->T) ? sc->F : make_boolean(sc, is_slot(global_slot(sym))));
10887     }
10888   return((is_global(sym)) ? sc->T : make_boolean(sc, is_slot(lookup_slot_from(sym, sc->curlet))));
10889 }
10890 
10891 static s7_pointer g_is_defined_in_rootlet(s7_scheme *sc, s7_pointer args)
10892 {
10893   /* here we know arg2=(rootlet), and no arg3, arg1 is a symbol that needs to be looked-up */
10894   s7_pointer sym;
10895   sym = lookup(sc, car(args));
10896   if (!is_symbol(sym))
10897     return(method_or_bust(sc, sym, sc->is_defined_symbol, args, T_SYMBOL, 1));
10898   return(make_boolean(sc, is_slot(global_slot(sym))));
10899 }
10900 
10901 static s7_pointer is_defined_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
10902 {
10903   if (!ops) return(f);
10904   if ((args == 2) && (is_symbol(cadr(expr))))
10905     {
10906       s7_pointer e;
10907       e = caddr(expr);
10908       if ((is_pair(e)) && (is_null(cdr(e))) && (car(e) == sc->rootlet_symbol))
10909 	{
10910 	  set_safe_optimize_op(expr, HOP_SAFE_C_D);
10911 	  return(sc->is_defined_in_rootlet);
10912 	}}
10913   return(f);
10914 }
10915 
10916 bool s7_is_defined(s7_scheme *sc, const char *name)
10917 {
10918   s7_pointer x;
10919   x = s7_symbol_table_find_name(sc, name);
10920   if (x)
10921     {
10922       x = lookup_slot_from(x, sc->curlet);
10923       return(is_slot(x));
10924     }
10925   return(false);
10926 }
10927 
10928 static bool is_defined_b_7p(s7_scheme *sc, s7_pointer p)
10929 {
10930   if (!is_symbol(p))
10931     simple_wrong_type_argument(sc, sc->is_defined_symbol, p, T_SYMBOL);
10932   return(is_slot(lookup_slot_from(p, sc->curlet)));
10933 }
10934 
10935 static bool is_defined_b_7pp(s7_scheme *sc, s7_pointer p, s7_pointer e) {return(g_is_defined(sc, set_plist_2(sc, p, e)) != sc->F);}
10936 
10937 
10938 void s7_define(s7_scheme *sc, s7_pointer let, s7_pointer symbol, s7_pointer value)
10939 {
10940   s7_pointer x;
10941   if ((let == sc->nil) ||
10942       (let == sc->rootlet))
10943     let = sc->shadow_rootlet;
10944   x = symbol_to_local_slot(sc, symbol, let);
10945   if (is_slot(x))
10946     slot_set_value_with_hook(x, value);
10947   else
10948     {
10949       s7_make_slot(sc, let, symbol, value); /* I think this means C code can override "constant" defs */
10950       /* if let is sc->nil or rootlet, s7_make_slot makes a permanent_slot */
10951       if ((let == sc->shadow_rootlet) &&
10952 	  (!is_slot(global_slot(symbol))))
10953 	{
10954 	  set_global(symbol); /* is_global => global_slot is usable -- is this a good idea? */
10955 	  set_global_slot(symbol, local_slot(symbol));
10956 	}}
10957 }
10958 
10959 s7_pointer s7_define_variable(s7_scheme *sc, const char *name, s7_pointer value)
10960 {
10961   s7_pointer sym;
10962   sym = make_symbol(sc, name);
10963   s7_define(sc, sc->nil, sym, value);
10964   return(sym);
10965 }
10966 
10967 s7_pointer s7_define_variable_with_documentation(s7_scheme *sc, const char *name, s7_pointer value, const char *help)
10968 {
10969   s7_pointer sym;
10970   sym = s7_define_variable(sc, name, value);
10971   symbol_set_has_help(sym);
10972   symbol_set_help(sym, copy_string(help));
10973   add_saved_pointer(sc, symbol_help(sym));
10974   return(sym);
10975 }
10976 
10977 s7_pointer s7_define_constant_with_environment(s7_scheme *sc, s7_pointer envir, const char *name, s7_pointer value)
10978 {
10979   s7_pointer sym;
10980   sym = make_symbol(sc, name);
10981   s7_define(sc, envir, sym, value);
10982   set_immutable(sym);
10983   set_possibly_constant(sym);
10984   set_immutable(global_slot(sym));
10985   set_immutable(local_slot(sym));
10986   return(sym);
10987 }
10988 
10989 s7_pointer s7_define_constant(s7_scheme *sc, const char *name, s7_pointer value)
10990 {
10991   return(s7_define_constant_with_environment(sc, sc->nil, name, value));
10992 }
10993 
10994 /* (define (func a) (let ((cvar (+ a 1))) cvar)) (define-constant cvar 23) (func 1) -> ;can't bind an immutable object: cvar
10995  * (let ((aaa 1)) (define-constant aaa 32) (set! aaa 3)) -> set!: can't alter immutable object: aaa
10996  */
10997 
10998 s7_pointer s7_define_constant_with_documentation(s7_scheme *sc, const char *name, s7_pointer value, const char *help)
10999 {
11000   s7_pointer sym;
11001   sym = s7_define_constant(sc, name, value);
11002   symbol_set_has_help(sym);
11003   symbol_set_help(sym, copy_string(help));
11004   add_saved_pointer(sc, symbol_help(sym));
11005   return(value); /* inconsistent with variable above, but consistent with define_function? */
11006 }
11007 
11008 
11009 /* -------------------------------- keyword? -------------------------------- */
11010 
11011 bool s7_is_keyword(s7_pointer obj) {return(is_keyword(obj));}
11012 
11013 static s7_pointer g_is_keyword(s7_scheme *sc, s7_pointer args)
11014 {
11015   #define H_is_keyword "(keyword? obj) returns #t if obj is a keyword, (keyword? :rest) -> #t"
11016   #define Q_is_keyword sc->pl_bt
11017   check_boolean_method(sc, is_keyword, sc->is_keyword_symbol, args);
11018 }
11019 
11020 
11021 /* -------------------------------- string->keyword -------------------------------- */
11022 s7_pointer s7_make_keyword(s7_scheme *sc, const char *key)
11023 {
11024   s7_pointer sym;
11025   block_t *b;
11026   char *name;
11027   size_t slen;
11028   slen = (size_t)safe_strlen(key);
11029   b = mallocate(sc, slen + 2);
11030   name = (char *)block_data(b);
11031   catstrs_direct(name, ":", key, (const char *)NULL);              /* use catstrs_direct to get around a bug in gcc 8.1 */
11032   sym = make_symbol_with_length(sc, name, slen + 1); /* keyword slot etc taken care of here (in new_symbol actually) */
11033   liberate(sc, b);
11034   return(sym);
11035 }
11036 
11037 static s7_pointer g_string_to_keyword(s7_scheme *sc, s7_pointer args)
11038 {
11039   #define H_string_to_keyword "(string->keyword str) prepends ':' to str and defines that as a keyword"
11040   #define Q_string_to_keyword s7_make_signature(sc, 2, sc->is_keyword_symbol, sc->is_string_symbol)
11041 
11042   s7_pointer str;
11043   str = car(args);
11044   if (!is_string(str))
11045     return(method_or_bust_one_arg(sc, str, sc->string_to_keyword_symbol, args, T_STRING));
11046   if ((string_length(str) == 0) ||
11047       (string_value(str)[0] == '\0'))
11048     return(s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, wrap_string(sc, "string->keyword wants a non-null string: ~S", 43), str)));
11049   return(s7_make_keyword(sc, string_value(str)));
11050 }
11051 
11052 
11053 /* -------------------------------- keyword->symbol -------------------------------- */
11054 static s7_pointer g_keyword_to_symbol(s7_scheme *sc, s7_pointer args)
11055 {
11056   #define H_keyword_to_symbol "(keyword->symbol key) returns a symbol with the same name as key but no prepended colon"
11057   #define Q_keyword_to_symbol s7_make_signature(sc, 2, sc->is_symbol_symbol, sc->is_keyword_symbol)
11058 
11059   s7_pointer sym;
11060   sym = car(args);
11061   if (!is_keyword(sym))
11062     return(method_or_bust_with_type_one_arg(sc, sym, sc->keyword_to_symbol_symbol, args, wrap_string(sc, "a keyword", 9)));
11063   return(keyword_symbol(sym));
11064 }
11065 
11066 s7_pointer s7_keyword_to_symbol(s7_scheme *sc, s7_pointer key) {return(keyword_symbol(key));}
11067 
11068 
11069 /* -------------------------------- symbol->keyword -------------------------------- */
11070 static s7_pointer symbol_to_keyword(s7_scheme *sc, s7_pointer sym) {return(s7_make_keyword(sc, symbol_name(sym)));}
11071 
11072 static s7_pointer g_symbol_to_keyword(s7_scheme *sc, s7_pointer args)
11073 {
11074   #define H_symbol_to_keyword "(symbol->keyword sym) returns a keyword with the same name as sym, but with a colon prepended"
11075   #define Q_symbol_to_keyword s7_make_signature(sc, 2, sc->is_keyword_symbol, sc->is_symbol_symbol)
11076 
11077   if (!is_symbol(car(args)))
11078     return(method_or_bust_one_arg(sc, car(args), sc->symbol_to_keyword_symbol, args, T_SYMBOL));
11079   return(symbol_to_keyword(sc, car(args)));
11080 }
11081 
11082 
11083 /* -------------------------------- c-pointer? -------------------------------- */
11084 bool s7_is_c_pointer(s7_pointer arg) {return(is_c_pointer(arg));}
11085 bool s7_is_c_pointer_of_type(s7_pointer arg, s7_pointer type) {return((is_c_pointer(arg)) && (c_pointer_type(arg) == type));}
11086 
11087 static s7_pointer g_is_c_pointer(s7_scheme *sc, s7_pointer args)
11088 {
11089   #define H_is_c_pointer "(c-pointer? obj type) returns #t if obj is a C pointer being held in s7.  If type is given, the c_pointer's type is also checked."
11090   #define Q_is_c_pointer s7_make_signature(sc, 3, sc->is_boolean_symbol, sc->T, sc->T)
11091 
11092   s7_pointer p;
11093   p = car(args);
11094   if (!is_c_pointer(p))
11095     {
11096       if (!has_active_methods(sc, p)) return(sc->F);
11097       return(apply_boolean_method(sc, p, sc->is_c_pointer_symbol));
11098     }
11099   return((is_pair(cdr(args))) ? make_boolean(sc, c_pointer_type(p) == cadr(args)) : sc->T);
11100 }
11101 
11102 
11103 /* -------------------------------- c-pointer -------------------------------- */
11104 void *s7_c_pointer(s7_pointer p) {return(c_pointer(p));}
11105 
11106 void *s7_c_pointer_with_type(s7_scheme *sc, s7_pointer p, s7_pointer expected_type, const char *caller, s7_int argnum)
11107 {
11108   if (!is_c_pointer(p))
11109     return(wrong_type_arg_error_prepackaged(sc, wrap_string(sc, caller, strlen(caller)), make_integer(sc, argnum), p, sc->unused, sc->prepackaged_type_names[T_C_POINTER]));
11110   if ((c_pointer(p) != NULL) &&
11111       (c_pointer_type(p) != expected_type))
11112     return(s7_error(sc, sc->wrong_type_arg_symbol,
11113 		    set_elist_5(sc, wrap_string(sc, "~S argument ~D got a pointer of type ~S, but expected ~S", 56),
11114 				wrap_string(sc, caller, strlen(caller)),
11115 				make_integer(sc, argnum), c_pointer_type(p), expected_type)));
11116   return(c_pointer(p));
11117 }
11118 
11119 s7_pointer s7_make_c_pointer_with_type(s7_scheme *sc, void *ptr, s7_pointer type, s7_pointer info)
11120 {
11121   s7_pointer x;
11122   new_cell(sc, x, T_C_POINTER);
11123   c_pointer(x) = ptr;
11124   c_pointer_type(x) = type;
11125   c_pointer_info(x) = info;
11126   c_pointer_weak1(x) = sc->F;
11127   c_pointer_weak2(x) = sc->F;
11128   return(x);
11129 }
11130 
11131 s7_pointer s7_make_c_pointer(s7_scheme *sc, void *ptr) {return(s7_make_c_pointer_with_type(sc, ptr, sc->F, sc->F));}
11132 
11133 static s7_pointer g_c_pointer(s7_scheme *sc, s7_pointer args)
11134 {
11135   #define H_c_pointer "(c-pointer int type info weak1 weak2) returns a c-pointer object. The type and info args are optional, defaulting to #f."
11136   #define Q_c_pointer s7_make_circular_signature(sc, 2, 3, sc->is_c_pointer_symbol, sc->is_integer_symbol, sc->T)
11137 
11138   s7_pointer arg, type, info, weak1, weak2, cp;
11139   intptr_t p;
11140 
11141   type = sc->F;
11142   info = sc->F;
11143   weak1 = sc->F;
11144   weak2 = sc->F;
11145   arg = car(args);
11146   if (!s7_is_integer(arg))
11147     return(method_or_bust(sc, arg, sc->c_pointer_symbol, args, T_INTEGER, 1));
11148   p = (intptr_t)s7_integer_checked(sc, arg);     /* (c-pointer (bignum "1234")) */
11149   args = cdr(args);
11150   if (is_pair(args))
11151     {
11152       type = car(args);
11153       args = cdr(args);
11154       if (is_pair(args))
11155 	{
11156 	  info = car(args);
11157 	  args = cdr(args);
11158 	  if (is_pair(args))
11159 	    {
11160 	      weak1 = car(args);
11161 	      args = cdr(args);
11162 	      if (is_pair(args))
11163 		weak2 = car(args);
11164 	    }}}
11165   cp = s7_make_c_pointer_with_type(sc, (void *)p, type, info);
11166   c_pointer_set_weak1(cp, weak1);
11167   c_pointer_set_weak2(cp, weak2);
11168   if ((weak1 != sc->F) || (weak2 != sc->F))
11169     add_weak_ref(sc, cp);
11170   return(cp);
11171 }
11172 
11173 
11174 /* -------------------------------- c-pointer-info -------------------------------- */
11175 static s7_pointer c_pointer_info_p_p(s7_scheme *sc, s7_pointer p)
11176 {
11177   if (!is_c_pointer(p))
11178     return(method_or_bust_p(sc, p, sc->c_pointer_info_symbol, T_C_POINTER));
11179   return(c_pointer_info(p));
11180 }
11181 
11182 static s7_pointer g_c_pointer_info(s7_scheme *sc, s7_pointer args)
11183 {
11184   #define H_c_pointer_info "(c-pointer-info obj) returns the c-pointer info field"
11185   #define Q_c_pointer_info s7_make_signature(sc, 2, sc->T, sc->is_c_pointer_symbol)
11186   return(c_pointer_info_p_p(sc, car(args)));
11187 }
11188 
11189 
11190 /* -------------------------------- c-pointer-type -------------------------------- */
11191 s7_pointer s7_c_pointer_type(s7_pointer p)
11192 {
11193   return((is_c_pointer(p)) ? c_pointer_type(p) : NULL); /* as above */
11194 }
11195 
11196 static s7_pointer c_pointer_type_p_p(s7_scheme *sc, s7_pointer p)
11197 {
11198   return((is_c_pointer(p)) ? c_pointer_type(p) : method_or_bust_p(sc, p, sc->c_pointer_type_symbol, T_C_POINTER));
11199 }
11200 
11201 static s7_pointer g_c_pointer_type(s7_scheme *sc, s7_pointer args)
11202 {
11203   #define H_c_pointer_type "(c-pointer-type obj) returns the c-pointer type field"
11204   #define Q_c_pointer_type s7_make_signature(sc, 2, sc->T, sc->is_c_pointer_symbol)
11205   return(c_pointer_type_p_p(sc, car(args)));
11206 }
11207 
11208 
11209 /* -------------------------------- c-pointer-weak1/2 -------------------------------- */
11210 static s7_pointer c_pointer_weak1_p_p(s7_scheme *sc, s7_pointer p)
11211 {
11212   return((is_c_pointer(p)) ? c_pointer_weak1(p) : method_or_bust_p(sc, p, sc->c_pointer_weak1_symbol, T_C_POINTER));
11213 }
11214 
11215 static s7_pointer g_c_pointer_weak1(s7_scheme *sc, s7_pointer args)
11216 {
11217   #define H_c_pointer_weak1 "(c-pointer-weak1 obj) returns the c-pointer weak1 field"
11218   #define Q_c_pointer_weak1 s7_make_signature(sc, 2, sc->T, sc->is_c_pointer_symbol)
11219   return(c_pointer_weak1_p_p(sc, car(args)));
11220 }
11221 
11222 static s7_pointer c_pointer_weak2_p_p(s7_scheme *sc, s7_pointer p)
11223 {
11224   return((is_c_pointer(p)) ? c_pointer_weak2(p) : method_or_bust_p(sc, p, sc->c_pointer_weak2_symbol, T_C_POINTER));
11225 }
11226 
11227 static s7_pointer g_c_pointer_weak2(s7_scheme *sc, s7_pointer args)
11228 {
11229   #define H_c_pointer_weak2 "(c-pointer-weak2 obj) returns the c-pointer weak2 field"
11230   #define Q_c_pointer_weak2 s7_make_signature(sc, 2, sc->T, sc->is_c_pointer_symbol)
11231   return(c_pointer_weak2_p_p(sc, car(args)));
11232 }
11233 
11234 
11235 /* -------------------------------- c-pointer->list -------------------------------- */
11236 static s7_pointer g_c_pointer_to_list(s7_scheme *sc, s7_pointer args)
11237 {
11238   #define H_c_pointer_to_list "(c-pointer->list obj) returns the c-pointer data as (list pointer-as-int type info)"
11239   #define Q_c_pointer_to_list s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_c_pointer_symbol)
11240 
11241   s7_pointer p;
11242   p = car(args);
11243   if (!is_c_pointer(p))
11244     return(method_or_bust(sc, p, sc->c_pointer_to_list_symbol, args, T_C_POINTER, 1));
11245   return(list_3(sc, make_integer(sc, (s7_int)((intptr_t)c_pointer(p))), c_pointer_type(p), c_pointer_info(p)));
11246 }
11247 
11248 
11249 /* -------------------------------- continuations and gotos -------------------------------- */
11250 
11251 enum {NO_JUMP, CALL_WITH_EXIT_JUMP, THROW_JUMP, CATCH_JUMP, ERROR_JUMP, ERROR_QUIT_JUMP};
11252 enum {NO_SET_JUMP, READ_SET_JUMP, LOAD_SET_JUMP, DYNAMIC_WIND_SET_JUMP, S7_CALL_SET_JUMP, EVAL_SET_JUMP};
11253 
11254 
11255 /* ----------------------- continuation? -------------------------------- */
11256 static s7_pointer g_is_continuation(s7_scheme *sc, s7_pointer args)
11257 {
11258   #define H_is_continuation "(continuation? obj) returns #t if obj is a continuation"
11259   #define Q_is_continuation sc->pl_bt
11260 
11261   check_boolean_method(sc, is_continuation, sc->is_continuation_symbol, args);
11262   /* is this the right thing?  It returns #f for call-with-exit ("goto") because
11263    *   that form of continuation can't continue (via a jump back to its context).
11264    */
11265 }
11266 
11267 static bool s7_is_continuation(s7_pointer p) {return(is_continuation(p));}
11268 
11269 #if S7_DEBUGGING
11270 static s7_pointer check_wrap_return(s7_pointer lst)
11271 {
11272   s7_pointer fast, slow;
11273   for (fast = lst, slow = lst; is_pair(fast); slow = cdr(slow), fast = cdr(fast))
11274     {
11275       if (is_matched_pair(fast)) fprintf(stderr, "matched_pair not cleared\n");
11276       fast = cdr(fast);
11277       if (!is_pair(fast)) return(lst);
11278       if (fast == slow) return(lst);
11279       if (is_matched_pair(fast)) fprintf(stderr, "matched_pair not cleared\n");
11280     }
11281   return(lst);
11282 }
11283 #endif
11284 
11285 static s7_pointer copy_any_list(s7_scheme *sc, s7_pointer a)
11286 {
11287   s7_pointer slow, fast, p;
11288 #if S7_DEBUGGING
11289   #define wrap_return(W) do {fast = W; W = sc->nil; return(check_wrap_return(fast));} while (0)
11290 #else
11291   #define wrap_return(W) do {fast = W; W = sc->nil; return(fast);} while (0)
11292 #endif
11293 
11294   sc->w = list_1(sc, car(a));
11295   p = sc->w;
11296 
11297   slow = cdr(a);
11298   fast = slow;
11299   while (true)
11300     {
11301       if (!is_pair(fast))
11302 	{
11303 	  if (is_null(fast))
11304 	    wrap_return(sc->w);
11305 	  set_cdr(p, fast);
11306 	  wrap_return(sc->w);
11307 	}
11308 
11309       set_cdr(p, list_1(sc, car(fast)));
11310       p = cdr(p);
11311 
11312       fast = cdr(fast);
11313       if (!is_pair(fast))
11314 	{
11315 	  if (is_null(fast))
11316 	    wrap_return(sc->w);
11317 	  set_cdr(p, fast);
11318 	  wrap_return(sc->w);
11319 	}
11320       /* if unrolled further, it's a lot slower? */
11321       set_cdr(p, list_1(sc, car(fast)));
11322       p = cdr(p);
11323 
11324       fast = cdr(fast);
11325       slow = cdr(slow);
11326       if (fast == slow)
11327 	{
11328 	  /* try to preserve the original cyclic structure */
11329 	  s7_pointer p1, f1, p2, f2;
11330 	  set_match_pair(a);
11331 	  for (p1 = sc->w, f1 = a; !(is_matched_pair(cdr(f1))); f1 = cdr(f1), p1 = cdr(p1))
11332 	    set_match_pair(f1);
11333 	  for (p2 = sc->w, f2 = a; cdr(f1) != f2; f2 = cdr(f2), p2 = cdr(p2))
11334 	    clear_match_pair(f2);
11335 	  for (f1 = f2; is_pair(f1); f1 = cdr(f1), f2 = cdr(f2))
11336 	    {
11337 	      clear_match_pair(f1);
11338 	      f1 = cdr(f1);
11339 	      clear_match_pair(f1);
11340 	      if (f1 == f2) break;
11341 	    }
11342 	  clear_match_pair(a);
11343 	  if (is_null(p1))
11344 	    set_cdr(p2, p2);
11345 	  else set_cdr(p1, p2);
11346 	  wrap_return(sc->w);
11347 	}}
11348   wrap_return(sc->w);
11349 }
11350 
11351 static s7_pointer copy_counter(s7_scheme *sc, s7_pointer obj)
11352 {
11353   s7_pointer nobj;
11354   new_cell(sc, nobj, T_COUNTER);
11355   counter_set_result(nobj, counter_result(obj));
11356   counter_set_list(nobj, counter_list(obj));
11357   counter_set_capture(nobj, counter_capture(obj));
11358   counter_set_let(nobj, counter_let(obj));
11359   counter_set_slots(nobj, counter_slots(obj));
11360   return(nobj);
11361 }
11362 
11363 static void copy_stack_list_set_immutable(s7_scheme *sc, s7_pointer pold, s7_pointer pnew)
11364 {
11365   s7_pointer p1, p2, slow;
11366   slow = pold;
11367   for (p1 = pold, p2 = pnew; is_pair(p2); p1 = cdr(p1), p2 = cdr(p2))
11368     {
11369       if (is_immutable(p1)) set_immutable(p2);
11370       if (is_pair(cdr(p1)))
11371 	{
11372 	  p1 = cdr(p1);
11373 	  p2 = cdr(p2);
11374 	  if (is_immutable(p1)) set_immutable(p2);
11375 	  if (p1 == slow) break;
11376 	  slow = cdr(slow);
11377 	}}
11378 }
11379 
11380 static s7_pointer copy_stack(s7_scheme *sc, s7_pointer new_v, s7_pointer old_v, int64_t top)
11381 {
11382   int64_t i;
11383   s7_pointer *nv, *ov;
11384   bool has_pairs = false;
11385 
11386   nv = stack_elements(new_v);
11387   ov = stack_elements(old_v);
11388   memcpy((void *)nv, (void *)ov, top * sizeof(s7_pointer));
11389   stack_clear_flags(new_v);
11390 
11391   s7_gc_on(sc, false);
11392   if (stack_has_counters(old_v))
11393     {
11394       for (i = 2; i < top; i += 4)
11395 	{
11396 	  s7_pointer p;
11397 	  p = ov[i];                               /* args */
11398 	  /* if op_gc_protect, any ov[i] (except op) can be a list, but it isn't the arglist, so it seems to be safe */
11399 	  if (is_pair(p))                          /* args need not be a list (it can be a port or #f, etc) */
11400 	    {
11401 	      has_pairs = true;
11402 	      if (is_null(cdr(p)))
11403 		nv[i] = cons_unchecked(sc, car(p), sc->nil); /* GC is off -- could uncheck list_2 et al also */
11404 	      else
11405 		{
11406 		  if ((is_pair(cdr(p))) && (is_null(cddr(p))))
11407 		    nv[i] = list_2(sc, car(p), cadr(p));
11408 		  else nv[i] = copy_any_list(sc, p);  /* args (copy is needed -- see s7test.scm) */
11409 		  /* if op=eval_args4 for example, this has to be a proper list, and in many cases it doesn't need to be copied */
11410 		}
11411 	      copy_stack_list_set_immutable(sc, p, nv[i]);
11412 	    }
11413 	  /* lst can be dotted or circular here.  The circular list only happens in a case like:
11414 	   *    (dynamic-wind (lambda () (eq? (let ((lst (cons 1 2))) (set-cdr! lst lst) lst) (call/cc (lambda (k) k)))) (lambda () #f) (lambda () #f))
11415 	   *    proper_list_reverse_in_place(sc->args) is one reason we need to copy, another reuse_as_let
11416 	   */
11417 	  else
11418 	    if (is_counter(p))                  /* these can only occur in this context (not in a list etc) */
11419 	      {
11420 		stack_set_has_counters(new_v);
11421 		nv[i] = copy_counter(sc, p);
11422 	      }}}
11423   else
11424     {
11425       for (i = 2; i < top; i += 4)
11426 	if (is_pair(ov[i]))
11427 	  {
11428 	    s7_pointer p;
11429 	    p = ov[i];
11430 	    has_pairs = true;
11431 	    if (is_null(cdr(p)))
11432 	      nv[i] = cons_unchecked(sc, car(p), sc->nil);
11433 	    else
11434 	      {
11435 		if ((is_pair(cdr(p))) && (is_null(cddr(p))))
11436 		  nv[i] = list_2(sc, car(p), cadr(p));
11437 		else nv[i] = copy_any_list(sc, p);  /* args (copy is needed -- see s7test.scm) */
11438 	      }
11439 	    copy_stack_list_set_immutable(sc, p, nv[i]);
11440 	  }}
11441   if (has_pairs) stack_set_has_pairs(new_v);
11442   s7_gc_on(sc, true);
11443   return(new_v);
11444 }
11445 
11446 static s7_pointer copy_op_stack(s7_scheme *sc)
11447 {
11448   s7_pointer nv;
11449   int32_t len;
11450 
11451   len = (int32_t)(sc->op_stack_now - sc->op_stack);
11452   nv = make_simple_vector(sc, len); /* not sc->op_stack_size */
11453   if (len > 0)
11454     {
11455       int32_t i;
11456       s7_pointer *src, *dst;
11457       src = sc->op_stack;
11458       dst = (s7_pointer *)vector_elements(nv);
11459       for (i = len; i > 0; i--) *dst++ = *src++;
11460     }
11461   return(nv);
11462 }
11463 
11464 /* -------------------------------- with-baffle -------------------------------- */
11465 
11466 /* (with-baffle . body) calls body guaranteeing that there can be no jumps into the
11467  *    middle of it from outside -- no outer evaluation of a continuation can jump across this
11468  *    barrier:  The flip-side of call-with-exit.
11469  */
11470 
11471 static bool find_baffle(s7_scheme *sc, s7_int key)
11472 {
11473   /* search backwards through sc->curlet for baffle_let with (continuation_)key as its baffle_key value */
11474   if (sc->baffle_ctr > 0)
11475     {
11476       s7_pointer x;
11477       for (x = sc->curlet; is_let(x); x = let_outlet(x))
11478 	if ((is_baffle_let(x)) &&
11479 	    (let_baffle_key(x) == key))
11480 	  return(true);
11481     }
11482   return(false);
11483 }
11484 
11485 #define NOT_BAFFLED -1
11486 
11487 static s7_int find_any_baffle(s7_scheme *sc)
11488 {
11489   /* search backwards through sc->curlet for any sc->baffle_symbol -- called by s7_make_continuation to set continuation_key */
11490   if (sc->baffle_ctr > 0)
11491     {
11492       s7_pointer x;
11493       for (x = sc->curlet; is_let(x); x = let_outlet(x))
11494 	if (is_baffle_let(x))
11495 	  return(let_baffle_key(x));
11496     }
11497   return(NOT_BAFFLED);
11498 }
11499 
11500 static void check_with_baffle(s7_scheme *sc)
11501 {
11502   if (!s7_is_proper_list(sc, sc->code))
11503     eval_error(sc, "with-baffle: unexpected dot? ~A", 31, sc->code);
11504   pair_set_syntax_op(sc->code, OP_WITH_BAFFLE_UNCHECKED);
11505 }
11506 
11507 static bool op_with_baffle_unchecked(s7_scheme *sc)
11508 {
11509   sc->code = cdr(sc->code);
11510   if (is_null(sc->code))
11511     {
11512       sc->value = sc->nil;
11513       return(true);
11514     }
11515   sc->curlet = make_let(sc, sc->curlet);
11516   set_baffle_let(sc->curlet);
11517   set_let_baffle_key(sc->curlet, sc->baffle_ctr++);
11518   return(false);
11519 }
11520 
11521 
11522 /* -------------------------------- call/cc -------------------------------- */
11523 static void make_room_for_cc_stack(s7_scheme *sc)
11524 {
11525   if ((int64_t)(sc->free_heap_top - sc->free_heap) < (int64_t)(sc->heap_size / 8)) /* we probably never need this much space -- very often we don't need any */
11526     {
11527       int64_t freed_heap;
11528 #if S7_DEBUGGING
11529       freed_heap = gc(sc, __func__, __LINE__);
11530 #else
11531       freed_heap = gc(sc);
11532 #endif
11533       if (freed_heap < (int64_t)(sc->heap_size / 8))
11534 	resize_heap(sc);
11535     }
11536 }
11537 
11538 s7_pointer s7_make_continuation(s7_scheme *sc)
11539 {
11540   s7_pointer x, stack;
11541   int64_t loc;
11542   block_t *block;
11543 
11544   make_room_for_cc_stack(sc);
11545   loc = current_stack_top(sc);
11546   stack = make_simple_vector(sc, loc);
11547   set_full_type(stack, T_STACK);
11548   temp_stack_top(stack) = loc;
11549   copy_stack(sc, stack, sc->stack, loc);
11550   sc->temp8 = stack;
11551 
11552   new_cell(sc, x, T_CONTINUATION);
11553   block = mallocate_block(sc);
11554   continuation_block(x) = block;
11555   continuation_set_stack(x, stack);
11556   continuation_stack_size(x) = vector_length(continuation_stack(x));
11557   continuation_stack_start(x) = stack_elements(continuation_stack(x));
11558   continuation_stack_end(x) = (s7_pointer *)(continuation_stack_start(x) + loc);
11559   continuation_op_stack(x) = copy_op_stack(sc);
11560   continuation_op_loc(x) = (int32_t)(sc->op_stack_now - sc->op_stack);
11561   continuation_op_size(x) = sc->op_stack_size;
11562   continuation_key(x) = find_any_baffle(sc);
11563   continuation_name(x) = sc->F;
11564   sc->temp8 = sc->nil;
11565 
11566   add_continuation(sc, x);
11567   return(x);
11568 }
11569 
11570 static void let_temp_done(s7_scheme *sc, s7_pointer args, s7_pointer code, s7_pointer let);
11571 static void let_temp_unwind(s7_scheme *sc, s7_pointer slot, s7_pointer new_value);
11572 static s7_pointer dynamic_unwind(s7_scheme *sc, s7_pointer func, s7_pointer e);
11573 static s7_pointer eval(s7_scheme *sc, opcode_t first_op);
11574 
11575 static bool check_for_dynamic_winds(s7_scheme *sc, s7_pointer c)
11576 {
11577   /* called only from call_with_current_continuation.
11578    *   if call/cc jumps into a dynamic-wind, the init/finish funcs are wrapped in with-baffle
11579    *   so they'll complain.  Otherwise we're supposed to re-run the init func before diving
11580    *   into the body.  Similarly for let-temporarily.  If a call/cc jumps out of a dynamic-wind
11581    *   body-func, we're supposed to call the finish-func.  The continuation is called at
11582    *   current_stack_top(sc); the continuation form is at continuation_stack_top(c).
11583    */
11584   int64_t i, top1, top2;
11585   opcode_t op;
11586   /* check sc->stack for dynamic-winds we're jumping out of
11587    *    we need to check from the current stack top down to where the continuation stack matches the current stack??
11588    *    this was (i > 0), but that goes too far back; perhaps s7 should save the position of the call/cc invocation.
11589    *    also the two stacks can be different sizes (either can be larger)
11590    */
11591   top1 = current_stack_top(sc);
11592   top2 = continuation_stack_top(c);
11593   for (i = top1 - 1; (i > 0) && ((i >= top2) || (stack_code(sc->stack, i) != stack_code(continuation_stack(c), i))); i -= 4)
11594     {
11595       op = stack_op(sc->stack, i);
11596       switch (op)
11597 	{
11598 	case OP_DYNAMIC_WIND:
11599 	case OP_LET_TEMP_DONE:
11600 	  {
11601 	    s7_pointer x;
11602 	    int64_t j, s_base = 0;
11603 	    x = stack_code(sc->stack, i);
11604 	    for (j = 3; j < top2; j += 4)
11605 	      if (((stack_op(continuation_stack(c), j) == OP_DYNAMIC_WIND) ||
11606 		   (stack_op(continuation_stack(c), j) == OP_LET_TEMP_DONE)) &&
11607 		  (x == stack_code(continuation_stack(c), j)))
11608 		{
11609 		  s_base = i;
11610 		  break;
11611 		}
11612 	    if (s_base == 0)
11613 	      {
11614 		if (op == OP_DYNAMIC_WIND)
11615 		  {
11616 		    if (dynamic_wind_state(x) == DWIND_BODY)
11617 		      {
11618 			dynamic_wind_state(x) = DWIND_FINISH;
11619 			if (dynamic_wind_out(x) != sc->F)
11620 			  {
11621 			    push_stack_direct(sc, OP_EVAL_DONE);
11622 			    sc->args = sc->nil;
11623 			    sc->code = dynamic_wind_out(x);
11624 			    eval(sc, OP_APPLY);
11625 			  }}}
11626 		else let_temp_done(sc, stack_args(sc->stack, i), stack_code(sc->stack, i), stack_let(sc->stack, i));
11627 	      }}
11628 	  break;
11629 
11630 	case OP_DYNAMIC_UNWIND:
11631 	case OP_DYNAMIC_UNWIND_PROFILE:
11632 	  stack_element(sc->stack, i) = (s7_pointer)OP_GC_PROTECT;
11633 	  break;
11634 
11635 	case OP_LET_TEMP_UNWIND:
11636 	  let_temp_unwind(sc, stack_code(sc->stack, i), stack_args(sc->stack, i));
11637 	  break;
11638 
11639 	case OP_LET_TEMP_S7_UNWIND:
11640 	  g_s7_let_set_fallback(sc, set_plist_3(sc, sc->s7_let, stack_code(sc->stack, i), stack_args(sc->stack, i)));
11641 	  break;
11642 
11643 	case OP_BARRIER:
11644 	  if (i > top2)                       /* otherwise it's some unproblematic outer eval-string? */
11645 	    return(false);                    /*    but what if we've already evaluated a dynamic-wind closer? */
11646 	  break;
11647 
11648 	case OP_DEACTIVATE_GOTO:              /* here we're jumping out of an unrelated call-with-exit block */
11649 	  if (i > top2)
11650 	    call_exit_active(stack_args(sc->stack, i)) = false;
11651 	  break;
11652 
11653 	case OP_UNWIND_INPUT:
11654 	  if (stack_args(sc->stack, i) != sc->unused)
11655 	    set_current_input_port(sc, stack_args(sc->stack, i));         /* "args" = port that we shadowed */
11656 	  break;
11657 
11658 	case OP_UNWIND_OUTPUT:
11659 	  if (stack_args(sc->stack, i) != sc->unused)
11660 	    set_current_output_port(sc, stack_args(sc->stack, i));        /* "args" = port that we shadowed */
11661 	  break;
11662 
11663 	default:
11664 	  break;
11665 	}}
11666 
11667   /* check continuation-stack for dynamic-winds we're jumping into */
11668   for (i = current_stack_top(sc) - 1; i < top2; i += 4)
11669     {
11670       op = stack_op(continuation_stack(c), i);
11671       if (op == OP_DYNAMIC_WIND)
11672 	{
11673 	  s7_pointer x;
11674 	  x = stack_code(continuation_stack(c), i);
11675 	  if (dynamic_wind_in(x) != sc->F)
11676 	    {
11677 	      push_stack_direct(sc, OP_EVAL_DONE);
11678 	      sc->args = sc->nil;
11679 	      sc->code = dynamic_wind_in(x);
11680 	      eval(sc, OP_APPLY);
11681 	    }
11682 	  dynamic_wind_state(x) = DWIND_BODY;
11683 	}
11684       else
11685 	if (op == OP_DEACTIVATE_GOTO)
11686 	  call_exit_active(stack_args(continuation_stack(c), i)) = true;
11687       /* not let_temp_done here! */
11688       /* if op == OP_LET_TEMP_DONE, we're jumping back into a let-temporarily.  MIT and Chez scheme say they remember the
11689        *   let-temp vars (fluid-let or parameters in their terminology) at the point of the call/cc, and restore them
11690        *   on re-entry; that strikes me as incoherently complex -- they've wrapped a hidden dynamic-wind around the
11691        *   call/cc to restore all let-temp vars!  I think let-temp here should be the same as let -- if you jump back
11692        *   in, nothing hidden happens. So,
11693        *     (let ((x #f) (cc #f)) (let-temporarily ((x 1)) (set! x 2) (call/cc (lambda (r) (set! cc r))) (display x) (unless (= x 2) (newline) (exit)) (set! x 3) (cc)))
11694        *   behaves the same (in this regard) if let-temp is replaced with let.
11695        */
11696     }
11697   return(true);
11698 }
11699 
11700 static s7_pointer splice_in_values(s7_scheme *sc, s7_pointer args);
11701 
11702 static bool call_with_current_continuation(s7_scheme *sc)
11703 {
11704   s7_pointer c;
11705   c = sc->code;
11706 
11707   /* check for (baffle ...) blocking the current attempt to continue */
11708   if ((continuation_key(c) != NOT_BAFFLED) &&
11709       (!(find_baffle(sc, continuation_key(c)))))
11710     return(false);
11711 
11712   if (!check_for_dynamic_winds(sc, c))
11713     return(true);
11714 
11715   make_room_for_cc_stack(sc);
11716 
11717   /* we push_stack sc->code before calling an embedded eval above, so sc->code should still be c here, etc */
11718   if ((stack_has_pairs(continuation_stack(c))) ||
11719       (stack_has_counters(continuation_stack(c))))
11720     copy_stack(sc, sc->stack, continuation_stack(c), continuation_stack_top(c));
11721   else
11722     {
11723       s7_pointer *nv, *ov;
11724       nv = stack_elements(sc->stack);
11725       ov = stack_elements(continuation_stack(c));
11726       memcpy((void *)nv, (void *)ov, continuation_stack_top(c) * sizeof(s7_pointer));
11727     }
11728   /* copy_stack(sc, sc->stack, continuation_stack(c), continuation_stack_top(c)); */
11729   sc->stack_end = (s7_pointer *)(sc->stack_start + continuation_stack_top(c));
11730 
11731   {
11732     int32_t i, top;
11733     s7_pointer *src, *dst;
11734 
11735     top = continuation_op_loc(c);
11736     sc->op_stack_now = (s7_pointer *)(sc->op_stack + top);
11737     sc->op_stack_size = continuation_op_size(c);
11738     sc->op_stack_end = (s7_pointer *)(sc->op_stack + sc->op_stack_size);
11739 
11740     src = (s7_pointer *)vector_elements(continuation_op_stack(c));
11741     dst = sc->op_stack;
11742     for (i = 0; i < top; i++) dst[i] = src[i];
11743   }
11744 
11745   if (is_null(sc->args))
11746     sc->value = sc->nil;
11747   else sc->value = (is_null(cdr(sc->args))) ? car(sc->args) : splice_in_values(sc, sc->args);
11748   return(true);
11749 }
11750 
11751 static s7_pointer g_call_cc(s7_scheme *sc, s7_pointer args)
11752 {
11753   #define H_call_cc "(call-with-current-continuation (lambda (continuer)...)) is always a mistake!"
11754   #define Q_call_cc s7_make_signature(sc, 2, sc->T, sc->is_procedure_symbol)
11755 
11756   s7_pointer p;
11757   p = car(args);                             /* this is the procedure passed to call/cc */
11758   if (!is_t_procedure(p))                    /* this includes continuations */
11759     {
11760       check_method(sc, p, sc->call_cc_symbol, args);
11761       check_method(sc, p, sc->call_with_current_continuation_symbol, args);
11762       return(simple_wrong_type_argument_with_type(sc, sc->call_cc_symbol, p, a_procedure_string));
11763     }
11764 
11765   if (((!is_closure(p)) ||
11766        (closure_arity(p) != 1)) &&
11767       (!s7_is_aritable(sc, p, 1)))
11768     return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "call/cc procedure, ~A, should take one argument", 47), p)));
11769 
11770   sc->w = s7_make_continuation(sc);
11771   if ((is_any_closure(p)) && (is_pair(closure_args(p))) && (is_symbol(car(closure_args(p)))))
11772     continuation_name(sc->w) = car(closure_args(p));
11773   push_stack(sc, OP_APPLY, list_1(sc, sc->w), p); /* apply function p to continuation sc->w */
11774   sc->w = sc->nil;
11775 
11776   return(sc->nil);
11777 }
11778 
11779 /* we can't naively optimize call/cc to call-with-exit if the continuation is only
11780  *   used as a function in the call/cc body because it might (for example) be wrapped
11781  *   in a lambda form that is being exported.  See b-func in s7test for an example.
11782  */
11783 static void apply_continuation(s7_scheme *sc) /* sc->code is the continuation */
11784 {
11785   if (!call_with_current_continuation(sc))
11786     s7_error(sc, sc->baffled_symbol,
11787 	     (is_symbol(continuation_name(sc->code))) ?
11788 	     set_elist_2(sc, wrap_string(sc, "continuation ~S can't jump into with-baffle", 43), continuation_name(sc->code)) :
11789 	     set_elist_1(sc, wrap_string(sc, "continuation can't jump into with-baffle", 40)));
11790 }
11791 
11792 static void op_call_cc(s7_scheme *sc)
11793 {
11794   sc->w = s7_make_continuation(sc);
11795   continuation_name(sc->w) = caar(opt2_pair(sc->code)); /* caadadr(sc->code) */
11796   sc->curlet = make_let_with_slot(sc, sc->curlet, continuation_name(sc->w), sc->w);
11797   sc->w = sc->nil;
11798   sc->code = cdr(opt2_pair(sc->code)); /* cddadr(sc->code) */
11799 }
11800 
11801 static bool op_implicit_continuation_a(s7_scheme *sc)
11802 {
11803   s7_pointer s, code;
11804   code = sc->code;
11805   s = lookup_checked(sc, car(code));
11806   if (!is_continuation(s)) {sc->last_function = s; return(false);}
11807   sc->code = s;
11808   sc->args = set_plist_1(sc, fx_call(sc, cdr(code)));
11809   apply_continuation(sc);
11810   return(true);
11811 }
11812 
11813 
11814 /* -------------------------------- call-with-exit -------------------------------- */
11815 
11816 static void pop_input_port(s7_scheme *sc);
11817 
11818 static void call_with_exit(s7_scheme *sc)
11819 {
11820   int64_t i, new_stack_top, quit = 0;
11821 
11822   if (!call_exit_active(sc->code))
11823     s7_error(sc, sc->invalid_escape_function_symbol, set_elist_1(sc, wrap_string(sc, "call-with-exit escape procedure called outside its block", 56)));
11824 
11825   call_exit_active(sc->code) = false;
11826   new_stack_top = call_exit_goto_loc(sc->code);
11827   sc->op_stack_now = (s7_pointer *)(sc->op_stack + call_exit_op_loc(sc->code));
11828 
11829   /* look for dynamic-wind in the stack section that we are jumping out of */
11830   for (i = current_stack_top(sc) - 1; i > new_stack_top; i -= 4)
11831     switch (stack_op(sc->stack, i))
11832       {
11833       case OP_DYNAMIC_WIND:
11834 	{
11835 	  s7_pointer lx;
11836 	  lx = stack_code(sc->stack, i);
11837 	  if (dynamic_wind_state(lx) == DWIND_BODY)
11838 	    {
11839 	      dynamic_wind_state(lx) = DWIND_FINISH;
11840 	      if (dynamic_wind_out(lx) != sc->F)
11841 		{
11842 		  push_stack_direct(sc, OP_EVAL_DONE);
11843 		  sc->args = sc->nil;
11844 		  sc->code = dynamic_wind_out(lx);
11845 		  eval(sc, OP_APPLY);
11846 		}}}
11847 	break;
11848 
11849       case OP_DYNAMIC_UNWIND:
11850       case OP_DYNAMIC_UNWIND_PROFILE:
11851 	stack_element(sc->stack, i) = (s7_pointer)OP_GC_PROTECT;
11852 	dynamic_unwind(sc, stack_code(sc->stack, i), stack_args(sc->stack, i));
11853 	break;
11854 
11855       case OP_EVAL_STRING:
11856 	s7_close_input_port(sc, current_input_port(sc));
11857 	pop_input_port(sc);
11858 	break;
11859 
11860       case OP_BARRIER:                /* oops -- we almost certainly went too far */
11861 	goto SET_VALUE;
11862 
11863       case OP_DEACTIVATE_GOTO:        /* here we're jumping into an unrelated call-with-exit block */
11864 	call_exit_active(stack_args(sc->stack, i)) = false;
11865 	break;
11866 
11867       case OP_LET_TEMP_DONE:
11868 	let_temp_done(sc, stack_args(sc->stack, i), stack_code(sc->stack, i), stack_let(sc->stack, i));
11869 	break;
11870 
11871       case OP_LET_TEMP_UNWIND:
11872 	let_temp_unwind(sc, stack_code(sc->stack, i), stack_args(sc->stack, i));
11873 	break;
11874 
11875       case OP_LET_TEMP_S7_UNWIND:
11876 	g_s7_let_set_fallback(sc, set_plist_3(sc, sc->s7_let, stack_code(sc->stack, i), stack_args(sc->stack, i)));
11877 	break;
11878 
11879 	/* call/cc does not close files, but I think call-with-exit should */
11880       case OP_GET_OUTPUT_STRING:
11881       case OP_UNWIND_OUTPUT:
11882 	{
11883 	  s7_pointer x;
11884 	  x = stack_code(sc->stack, i);                /* "code" = port that we opened */
11885 	  s7_close_output_port(sc, x);
11886 	  x = stack_args(sc->stack, i);                /* "args" = port that we shadowed, if not #<unused> */
11887 	  if (x != sc->unused)
11888 	    set_current_output_port(sc, x);
11889 	}
11890 	break;
11891 
11892       case OP_UNWIND_INPUT:
11893 	s7_close_input_port(sc, stack_code(sc->stack, i)); /* "code" = port that we opened */
11894 	if (stack_args(sc->stack, i) != sc->unused)
11895 	  set_current_input_port(sc, stack_args(sc->stack, i));       /* "args" = port that we shadowed */
11896 	break;
11897 
11898       case OP_EVAL_DONE: /* goto called in a method -- put off the inner eval return(s) until we clean up the stack */
11899 	quit++;
11900 	break;
11901 
11902       default:
11903 	break;
11904       }
11905 
11906   /* is this right? maybe the SET_VALUE should skip setting stack_end? */
11907  SET_VALUE:
11908   sc->stack_end = (s7_pointer *)(sc->stack_start + new_stack_top);
11909 
11910   /* the return value should have an implicit values call, just as in call/cc */
11911   if (is_null(sc->args))
11912     sc->value = sc->nil;
11913   else sc->value = (is_null(cdr(sc->args))) ? car(sc->args) : splice_in_values(sc, sc->args);
11914 
11915   if (quit > 0)
11916     {
11917       if (sc->longjmp_ok)
11918 	{
11919 	  pop_stack(sc);
11920 	  longjmp(sc->goto_start, CALL_WITH_EXIT_JUMP);
11921 	}
11922       for (i = 0; i < quit; i++)
11923 	push_stack_op_let(sc, OP_EVAL_DONE);
11924     }
11925 }
11926 
11927 static s7_pointer g_is_goto(s7_scheme *sc, s7_pointer args)
11928 {
11929   #define H_is_goto "(goto? obj) returns #t if obj is a call-with-exit exit function"
11930   #define Q_is_goto sc->pl_bt
11931   return(make_boolean(sc, is_goto(car(args))));
11932 }
11933 
11934 static inline s7_pointer make_goto(s7_scheme *sc, s7_pointer name)
11935 {
11936   s7_pointer x;
11937   new_cell(sc, x, T_GOTO);
11938   call_exit_goto_loc(x) = current_stack_top(sc);
11939   call_exit_op_loc(x) = (int32_t)(sc->op_stack_now - sc->op_stack);
11940   call_exit_active(x) = true;
11941   call_exit_name(x) = name;
11942   return(x);
11943 }
11944 
11945 static s7_pointer g_call_with_exit(s7_scheme *sc, s7_pointer args)   /* (call-with-exit (lambda (return) ...)) */
11946 {
11947   #define H_call_with_exit "(call-with-exit (lambda (exiter) ...)) is call/cc without the ability to jump back into a previous computation."
11948   #define Q_call_with_exit s7_make_signature(sc, 2, sc->values_symbol, sc->is_procedure_symbol)
11949   s7_pointer p, x;
11950 
11951   p = car(args);
11952   if (is_any_closure(p))
11953     {
11954       x = make_goto(sc, ((is_any_closure(p)) && (is_pair(closure_args(p))) && (is_symbol(car(closure_args(p))))) ? car(closure_args(p)) : sc->F);
11955       push_stack(sc, OP_DEACTIVATE_GOTO, x, p); /* this means call-with-exit is not tail-recursive */
11956       push_stack(sc, OP_APPLY, cons_unchecked(sc, x, sc->nil), p);
11957       return(sc->nil);
11958     }
11959 
11960   if (!is_t_procedure(p))                  /* this includes continuations */
11961     return(method_or_bust_with_type_one_arg(sc, p, sc->call_with_exit_symbol, args, a_procedure_string));
11962 
11963   x = make_goto(sc, ((is_any_closure(p)) && (is_pair(closure_args(p))) && (is_symbol(car(closure_args(p))))) ? car(closure_args(p)) : sc->F);
11964   if ((is_any_c_function(p)) && (s7_is_aritable(sc, p, 1)))
11965     {
11966       call_exit_active(x) = false;
11967       return((is_c_function(p)) ? c_function_call(p)(sc, list_1(sc, x)) : s7_apply_function_star(sc, p, set_plist_1(sc, x)));
11968     }
11969   push_stack(sc, OP_DEACTIVATE_GOTO, x, p); /* this means call-with-exit is not tail-recursive */
11970   push_stack(sc, OP_APPLY, cons_unchecked(sc, x, sc->nil), p);
11971   return(sc->nil);
11972   /* this is why call-with-exit is declared an unsafe_defun: a safe function returns its value, but an unsafe one
11973    *   can await a further evaluation (the call-with-exit body).  The sc->nil returned value is ignored.
11974    */
11975 }
11976 
11977 static void op_call_with_exit(s7_scheme *sc)
11978 {
11979   s7_pointer go, args;
11980   args = opt2_pair(sc->code);
11981   go = make_goto(sc, caar(args));
11982   push_stack_no_let_no_code(sc, OP_DEACTIVATE_GOTO, go); /* was also pushing code */
11983   sc->curlet = make_let_with_slot(sc, sc->curlet, caar(args), go);
11984   sc->code = T_Pair(cdr(args));
11985 }
11986 
11987 static void op_call_with_exit_o(s7_scheme *sc)
11988 {
11989   op_call_with_exit(sc);
11990   sc->code = car(sc->code);
11991 }
11992 
11993 static bool op_implicit_goto(s7_scheme *sc)
11994 {
11995   s7_pointer g;
11996   g = lookup_checked(sc, car(sc->code));
11997   if (!is_goto(g)) {sc->last_function = g; return(false);}
11998   set_opt1_goto(sc->code, g);
11999   sc->code = g;
12000   sc->args = sc->nil;
12001   call_with_exit(sc);
12002   return(true);
12003 }
12004 
12005 static bool op_implicit_goto_a(s7_scheme *sc)
12006 {
12007   s7_pointer g;
12008   g = lookup_checked(sc, car(sc->code));
12009   if (!is_goto(g)) {sc->last_function = g; return(false);}
12010   set_opt1_goto(sc->code, g);
12011   sc->args = list_1(sc, fx_call(sc, cdr(sc->code))); /* if dynamic-wind exited, eval might be called, so plist not safe here */
12012   sc->code = g;
12013   call_with_exit(sc);
12014   return(true);
12015 }
12016 
12017 
12018 /* -------------------------------- numbers -------------------------------- */
12019 
12020 static block_t *string_to_block(s7_scheme *sc, const char *p, s7_int len)
12021 {
12022   block_t *b;
12023   char *bp;
12024   b = mallocate(sc, len + 1);
12025   bp = (char *)block_data(b);
12026   memcpy((void *)bp, (void *)p, len);
12027   bp[len] = '\0';
12028   return(b);
12029 }
12030 
12031 static s7_pointer block_to_string(s7_scheme *sc, block_t *block, s7_int len)
12032 {
12033   s7_pointer x;
12034   new_cell(sc, x, T_STRING | T_SAFE_PROCEDURE);
12035   string_block(x) = block;
12036   string_value(x) = (char *)block_data(block);
12037   string_length(x) = len;
12038   string_value(x)[len] = '\0';
12039   string_hash(x) = 0;
12040   add_string(sc, x);
12041   return(x);
12042 }
12043 
12044 static inline s7_pointer make_simple_ratio(s7_scheme *sc, s7_int num, s7_int den)
12045 {
12046   s7_pointer x;
12047   if (den == 1)
12048     return(make_integer(sc, num));
12049   if (den == -1)
12050     return(make_integer(sc, -num));
12051   if ((den == S7_INT64_MIN) && ((num & 1) != 0))
12052     return(make_real(sc, (long_double)num / (long_double)den));
12053   new_cell(sc, x, T_RATIO);
12054   if (den < 0)
12055     {
12056       numerator(x) = -num;
12057       denominator(x) = -den;
12058     }
12059   else
12060     {
12061       numerator(x) = num;
12062       denominator(x) = den;
12063     }
12064   return(x);
12065 }
12066 
12067 static bool is_NaN(s7_double x) {return(x != x);}
12068 /* callgrind says this is faster than isnan, I think (very confusing data...) */
12069 
12070 #if defined(__sun) && defined(__SVR4)
12071   static bool is_inf(s7_double x) {return((x == x) && (is_NaN(x - x)));} /* there's no isinf in Solaris */
12072 #else
12073 #if (!MS_WINDOWS)
12074   #if __cplusplus
12075     #define is_inf(x) std::isinf(x)
12076   #else
12077     #define is_inf(x) isinf(x)
12078   #endif
12079 #else
12080   static bool is_inf(s7_double x) {return((x == x) && (is_NaN(x - x)));}  /* Another possibility: (x * 0) != 0 */
12081 
12082 #if (_MSC_VER < 1700)
12083   /* in MS C, we need to provide inverse hyperbolic trig funcs and cbrt */
12084   static double asinh(double x) {return(log(x + sqrt(1.0 + x * x)));}
12085   static double acosh(double x) {return(log(x + sqrt(x * x - 1.0)));}
12086   /* perhaps less prone to numerical troubles (untested): 2.0 * log(sqrt(0.5 * (x + 1.0)) + sqrt(0.5 * (x - 1.0))) */
12087   static double atanh(double x) {return(log((1.0 + x) / (1.0 - x)) / 2.0);}
12088   static double cbrt(double x) {if (x >= 0.0) return(pow(x, 1.0 / 3.0)); return(-pow(-x, 1.0 / 3.0));}
12089 #endif
12090 #endif /* windows */
12091 #endif /* sun */
12092 
12093 
12094 #if WITH_GMP
12095 static mp_prec_t mpc_precision = DEFAULT_BIGNUM_PRECISION;
12096 static mp_prec_t mpc_set_default_precision(mp_prec_t prec) {mpc_precision = prec; return(prec);}
12097 #define mpc_init(Z) mpc_init2(Z, mpc_precision)
12098 
12099 static bigint *alloc_bigint(s7_scheme *sc)
12100 {
12101   bigint *p;
12102   if (sc->bigints)
12103     {
12104       p = sc->bigints;
12105       sc->bigints = p->nxt;
12106     }
12107   else
12108     {
12109       p = (bigint *)malloc(sizeof(bigint));
12110       /* not permalloc here: gmp must be playing tricky games with realloc or something.  permalloc can lead
12111        *   to mpz_set_si overwriting adjacent memory (valgrind does not catch this), clobbering at least the
12112        *   bigint nxt field.  Someday I need to look at the source.
12113        */
12114       mpz_init(p->n);
12115     }
12116   return(p);
12117 }
12118 
12119 static bigrat *alloc_bigrat(s7_scheme *sc)
12120 {
12121   bigrat *p;
12122   if (sc->bigrats)
12123     {
12124       p = sc->bigrats;
12125       sc->bigrats = p->nxt;
12126     }
12127   else
12128     {
12129       p = (bigrat *)malloc(sizeof(bigrat));
12130       mpq_init(p->q);
12131     }
12132   return(p);
12133 }
12134 
12135 static bigflt *alloc_bigflt(s7_scheme *sc)
12136 {
12137   bigflt *p;
12138   if (sc->bigflts)
12139     {
12140       p = sc->bigflts;
12141       sc->bigflts = p->nxt;
12142       mpfr_set_prec(p->x, sc->bignum_precision);
12143     }
12144   else
12145     {
12146       p = (bigflt *)malloc(sizeof(bigflt));
12147       mpfr_init2(p->x, sc->bignum_precision);
12148     }
12149   return(p);
12150 }
12151 
12152 static bigcmp *alloc_bigcmp(s7_scheme *sc)
12153 {
12154   bigcmp *p;
12155   if (sc->bigcmps)
12156     {
12157       p = sc->bigcmps;
12158       sc->bigcmps = p->nxt;
12159       mpc_set_prec(p->z, sc->bignum_precision);
12160     }
12161   else
12162     {
12163       p = (bigcmp *)malloc(sizeof(bigcmp));
12164       mpc_init(p->z);
12165     }
12166   return(p);
12167 }
12168 
12169 static s7_pointer mpz_to_big_integer(s7_scheme *sc, mpz_t val)
12170 {
12171   s7_pointer x;
12172   new_cell(sc, x, T_BIG_INTEGER);
12173   big_integer_bgi(x) = alloc_bigint(sc);
12174   mpz_set(big_integer(x), val);
12175   add_big_integer(sc, x);
12176   return(x);
12177 }
12178 
12179 static s7_pointer mpz_to_integer(s7_scheme *sc, mpz_t val)
12180 {
12181   if (mpz_fits_slong_p(val))
12182     return(make_integer(sc, mpz_get_si(val)));
12183   return(mpz_to_big_integer(sc, val));
12184 }
12185 
12186 #if (!WITH_PURE_S7)
12187 static s7_pointer mpz_to_big_real(s7_scheme *sc, mpz_t val)
12188 {
12189   s7_pointer x;
12190   new_cell(sc, x, T_BIG_REAL);
12191   big_real_bgf(x) = alloc_bigflt(sc);
12192   add_big_real(sc, x);
12193   mpfr_set_z(big_real(x), val, MPFR_RNDN);
12194   return(x);
12195 }
12196 #endif
12197 
12198 static s7_pointer mpq_to_big_ratio(s7_scheme *sc, mpq_t val)
12199 {
12200   s7_pointer x;
12201   new_cell(sc, x, T_BIG_RATIO);
12202   big_ratio_bgr(x) = alloc_bigrat(sc);
12203   add_big_ratio(sc, x);
12204   mpq_set(big_ratio(x), val);
12205   return(x);
12206 }
12207 
12208 static s7_pointer mpq_to_rational(s7_scheme *sc, mpq_t val)
12209 {
12210   if (mpz_cmp_ui(mpq_denref(val), 1) == 0)
12211     return(mpz_to_integer(sc, mpq_numref(val)));
12212 #if S7_DEBUGGING
12213   mpq_canonicalize(val);
12214   if (mpz_cmp_ui(mpq_denref(val), 1) == 0)
12215     {
12216       fprintf(stderr, "mpq_to_rational: missing canonicalize\n");
12217       return(mpz_to_integer(sc, mpq_numref(val)));
12218     }
12219 #endif
12220  if ((mpz_fits_slong_p(mpq_numref(val))) && (mpz_fits_slong_p(mpq_denref(val))))
12221     return(make_simple_ratio(sc, mpz_get_si(mpq_numref(val)), mpz_get_si(mpq_denref(val))));
12222   return(mpq_to_big_ratio(sc, val));
12223 }
12224 
12225 static s7_pointer mpz_to_rational(s7_scheme *sc, mpz_t n, mpz_t d) /* mpz_3 and mpz_4 */
12226 {
12227   if (mpz_cmp_ui(d, 1) == 0)
12228     return(mpz_to_integer(sc, n));
12229   mpq_set_num(sc->mpq_1, n);
12230   mpq_set_den(sc->mpq_1, d);
12231   mpq_canonicalize(sc->mpq_1);
12232   return(mpq_to_rational(sc, sc->mpq_1));
12233 }
12234 
12235 #if (!WITH_PURE_S7)
12236 static s7_pointer mpq_to_big_real(s7_scheme *sc, mpq_t val)
12237 {
12238   s7_pointer x;
12239   new_cell(sc, x, T_BIG_REAL);
12240   big_real_bgf(x) = alloc_bigflt(sc);
12241   add_big_real(sc, x);
12242   mpfr_set_q(big_real(x), val, MPFR_RNDN);
12243   return(x);
12244 }
12245 #endif
12246 
12247 static s7_pointer any_rational_to_mpq(s7_scheme *sc, s7_pointer z, mpq_t bigq)
12248 {
12249   switch (type(z))
12250     {
12251     case T_INTEGER:     mpq_set_si(bigq, integer(z), 1);                break;
12252     case T_BIG_INTEGER: mpq_set_z(bigq, big_integer(z));                break;
12253     case T_RATIO:       mpq_set_si(bigq, numerator(z), denominator(z)); break;
12254     case T_BIG_RATIO:   mpq_set(bigq, big_ratio(z));                    break;
12255     }
12256   return(z);
12257 }
12258 
12259 static s7_pointer mpfr_to_integer(s7_scheme *sc, mpfr_t val)
12260 {
12261   mpfr_get_z(sc->mpz_4, val, MPFR_RNDN);
12262   return(mpz_to_integer(sc, sc->mpz_4));
12263 }
12264 
12265 static s7_pointer mpfr_to_big_real(s7_scheme *sc, mpfr_t val)
12266 {
12267   s7_pointer x;
12268   new_cell(sc, x, T_BIG_REAL);
12269   add_big_real(sc, x);
12270   big_real_bgf(x) = alloc_bigflt(sc);
12271   mpfr_set(big_real(x), val, MPFR_RNDN);
12272   return(x);
12273 }
12274 
12275 static s7_pointer mpc_to_number(s7_scheme *sc, mpc_t val)
12276 {
12277   s7_pointer x;
12278   if (mpfr_zero_p(mpc_imagref(val)))
12279     return(mpfr_to_big_real(sc, mpc_realref(val)));
12280   new_cell(sc, x, T_BIG_COMPLEX);
12281   big_complex_bgc(x) = alloc_bigcmp(sc);
12282   add_big_complex(sc, x);
12283   mpc_set(big_complex(x), val, MPC_RNDNN);
12284   return(x);
12285 }
12286 
12287 /* s7.h */
12288 mpz_t  *s7_big_integer(s7_pointer x) {return(&big_integer(x));}
12289 mpq_t  *s7_big_ratio(s7_pointer x)   {return(&big_ratio(x));}
12290 mpfr_t *s7_big_real(s7_pointer x)    {return(&big_real(x));}
12291 mpc_t  *s7_big_complex(s7_pointer x) {return(&big_complex(x));}
12292 
12293 bool s7_is_big_integer(s7_pointer x) {return(is_t_big_integer(x));}
12294 bool s7_is_big_ratio(s7_pointer x)   {return(is_t_big_ratio(x));}
12295 bool s7_is_big_real(s7_pointer x)    {return(is_t_big_real(x));}
12296 bool s7_is_big_complex(s7_pointer x) {return(is_t_big_complex(x));}
12297 
12298 s7_pointer s7_make_big_integer(s7_scheme *sc, mpz_t *val) {return(mpz_to_integer(sc, *val));}
12299 s7_pointer s7_make_big_ratio(s7_scheme *sc, mpq_t *val)   {return(mpq_to_rational(sc, *val));}
12300 s7_pointer s7_make_big_real(s7_scheme *sc, mpfr_t *val)   {return(mpfr_to_big_real(sc, *val));}
12301 s7_pointer s7_make_big_complex(s7_scheme *sc, mpc_t *val) {return(mpc_to_number(sc, *val));}
12302 
12303 #if (!WITH_PURE_S7)
12304 static s7_pointer big_integer_to_big_real(s7_scheme *sc, s7_pointer x) {return(mpz_to_big_real(sc, big_integer(x)));}
12305 static s7_pointer big_ratio_to_big_real(s7_scheme *sc, s7_pointer x)   {return(mpq_to_big_real(sc, big_ratio(x)));}
12306 #endif
12307 
12308 static s7_pointer s7_int_to_big_integer(s7_scheme *sc, s7_int val)
12309 {
12310   s7_pointer x;
12311   new_cell(sc, x, T_BIG_INTEGER);
12312   big_integer_bgi(x) = alloc_bigint(sc);
12313   mpz_set_si(big_integer(x), val);
12314   add_big_integer(sc, x);
12315   return(x);
12316 }
12317 
12318 static s7_pointer s7_int_to_big_ratio(s7_scheme *sc, s7_int num, s7_int den)
12319 {
12320   /* (called only in g_bignum), den here always comes from denominator(x) or some positive constant so it is not negative */
12321   s7_pointer x;
12322   new_cell(sc, x, T_BIG_RATIO);
12323   big_ratio_bgr(x) = alloc_bigrat(sc);
12324   add_big_ratio(sc, x);
12325   mpq_set_si(big_ratio(x), num, den);
12326   return(x);
12327 }
12328 
12329 static s7_pointer s7_double_to_big_real(s7_scheme *sc, s7_double rl)
12330 {
12331   s7_pointer x;
12332   new_cell(sc, x, T_BIG_REAL);
12333   big_real_bgf(x) = alloc_bigflt(sc);
12334   add_big_real(sc, x);
12335   mpfr_set_d(big_real(x), rl, MPFR_RNDN);
12336   return(x);
12337 }
12338 
12339 static s7_pointer s7_double_to_big_complex(s7_scheme *sc, s7_double rl, s7_double im)
12340 {
12341   s7_pointer x;
12342   new_cell(sc, x, T_BIG_COMPLEX);
12343   add_big_complex(sc, x);
12344   big_complex_bgc(x) = alloc_bigcmp(sc);
12345   mpc_set_d_d(big_complex(x), rl, im, MPC_RNDNN);
12346   return(x);
12347 }
12348 
12349 static s7_pointer big_pi(s7_scheme *sc)
12350 {
12351   s7_pointer x;
12352   new_cell(sc, x, T_BIG_REAL | T_IMMUTABLE);
12353   big_real_bgf(x) = alloc_bigflt(sc);
12354   add_big_real(sc, x);
12355   mpfr_const_pi(big_real(x), MPFR_RNDN);
12356   return(x);
12357 }
12358 
12359 static bool is_integer_via_method(s7_scheme *sc, s7_pointer p)
12360 {
12361   if (s7_is_integer(p))
12362     return(true);
12363   if (has_active_methods(sc, p))
12364     {
12365       s7_pointer f;
12366       f = find_method_with_let(sc, p, sc->is_integer_symbol);
12367       if (f != sc->undefined)
12368 	return(is_true(sc, call_method(sc, p, f, set_plist_1(sc, p))));
12369     }
12370   return(false);
12371 }
12372 
12373 #if (!WITH_PURE_S7)
12374 static s7_pointer s7_number_to_big_real(s7_scheme *sc, s7_pointer p)
12375 {
12376   s7_pointer x;
12377 
12378   new_cell(sc, x, T_BIG_REAL);
12379   big_real_bgf(x) = alloc_bigflt(sc);
12380   add_big_real(sc, x);
12381 
12382   switch (type(p))
12383     {
12384     case T_INTEGER:
12385       mpfr_set_si(big_real(x), integer(p), MPFR_RNDN);
12386       break;
12387 
12388     case T_RATIO:
12389       /* here we can't use fraction(number(p)) even though that uses long_double division because
12390        *   there are lots of int64_t ratios that will still look the same.
12391        *   We have to do the actual bignum divide by hand.
12392        */
12393       mpq_set_si(sc->mpq_1, numerator(p), denominator(p));
12394       mpfr_set_q(big_real(x), sc->mpq_1, MPFR_RNDN);
12395       break;
12396 
12397     default:
12398       mpfr_set_d(big_real(x), s7_real(p), MPFR_RNDN);
12399       break;
12400     }
12401   return(x);
12402 }
12403 #endif
12404 
12405 static s7_pointer s7_number_to_big_complex(s7_scheme *sc, s7_pointer p)
12406 {
12407   s7_pointer x;
12408   new_cell(sc, x, T_BIG_COMPLEX);
12409   big_complex_bgc(x) = alloc_bigcmp(sc);
12410   add_big_complex(sc, x);
12411 
12412   switch (type(p))
12413     {
12414     case T_INTEGER:
12415       mpc_set_si(big_complex(x), integer(p), MPC_RNDNN);
12416       break;
12417 
12418     case T_RATIO:
12419       /* can't use fraction here */
12420       mpq_set_si(sc->mpq_1, numerator(p), denominator(p));
12421       mpfr_set_q(sc->mpfr_1, sc->mpq_1, MPFR_RNDN);
12422       mpc_set_fr(big_complex(x), sc->mpfr_1, MPC_RNDNN);
12423       break;
12424 
12425     case T_REAL:
12426       mpc_set_d(big_complex(x), s7_real(p), MPC_RNDNN);
12427       break;
12428 
12429     default:
12430       mpc_set_d_d(big_complex(x), real_part(p), imag_part(p), MPC_RNDNN);
12431       break;
12432     }
12433   return(x);
12434 }
12435 
12436 static s7_pointer any_real_to_mpfr(s7_scheme *sc, s7_pointer p, mpfr_t bigx)
12437 {
12438   switch (type(p))
12439     {
12440     case T_INTEGER:
12441       mpfr_set_si(bigx, integer(p), MPFR_RNDN);
12442       break;
12443     case T_RATIO:
12444       mpq_set_si(sc->mpq_1, numerator(p), denominator(p));
12445       mpfr_set_q(bigx, sc->mpq_1, MPFR_RNDN);
12446       break;
12447     case T_REAL:
12448       mpfr_set_d(bigx, real(p), MPFR_RNDN);
12449       if (is_NaN(real(p))) return(real_NaN);
12450       if (is_inf(real(p))) return(real_infinity);
12451       break;
12452     case T_BIG_INTEGER:
12453       mpfr_set_z(bigx, big_integer(p), MPFR_RNDN);
12454       break;
12455     case T_BIG_RATIO:
12456       mpfr_set_q(bigx, big_ratio(p), MPFR_RNDN);
12457       break;
12458     case T_BIG_REAL:
12459       mpfr_set(bigx, big_real(p), MPFR_RNDN);
12460       if (mpfr_nan_p(big_real(p))) return(real_NaN);
12461       if (mpfr_inf_p(big_real(p))) return(real_infinity);
12462       break;
12463     }
12464   return(NULL);
12465 }
12466 
12467 #define mpc_zero_p(z) ((mpfr_zero_p(mpc_realref(z))) && (mpfr_zero_p(mpc_imagref(z))))
12468 
12469 static s7_pointer any_number_to_mpc(s7_scheme *sc, s7_pointer p, mpc_t bigz)
12470 {
12471   switch (type(p))
12472     {
12473     case T_INTEGER:
12474       mpc_set_si(bigz, integer(p), MPC_RNDNN);
12475       break;
12476     case T_RATIO:
12477       mpq_set_si(sc->mpq_1, numerator(p), denominator(p));
12478       mpc_set_q(bigz, sc->mpq_1, MPC_RNDNN);
12479       break;
12480     case T_REAL:
12481       if (is_NaN(real(p))) return(real_NaN);
12482       if (is_inf(real(p))) return(real_infinity);
12483       mpc_set_d(bigz, real(p), MPC_RNDNN);
12484       break;
12485     case T_COMPLEX:
12486       if (is_NaN(imag_part(p))) return(complex_NaN);
12487       if (is_NaN(real_part(p))) return(real_NaN);
12488      mpc_set_d_d(bigz, real_part(p), imag_part(p), MPC_RNDNN);
12489       break;
12490     case T_BIG_INTEGER:
12491       mpc_set_z(bigz, big_integer(p), MPC_RNDNN);
12492       break;
12493     case T_BIG_RATIO:
12494       mpc_set_q(bigz, big_ratio(p), MPC_RNDNN);
12495       break;
12496     case T_BIG_REAL:
12497       mpc_set_fr(bigz, big_real(p), MPC_RNDNN);
12498       if (mpfr_nan_p(big_real(p))) return(real_NaN);
12499       if (mpfr_inf_p(big_real(p))) return(real_infinity);
12500       break;
12501     case T_BIG_COMPLEX:
12502       if (mpfr_nan_p(mpc_imagref(big_complex(p)))) return(complex_NaN);
12503       if (mpfr_nan_p(mpc_realref(big_complex(p)))) return(real_NaN);
12504       mpc_set(bigz, big_complex(p), MPC_RNDNN);
12505       break;
12506     }
12507   return(NULL);
12508 }
12509 
12510 static s7_pointer make_big_complex(s7_scheme *sc, mpfr_t rl, mpfr_t im)
12511 {
12512   /* there is no mpc_get_str equivalent, so we need to split up str,
12513    *   use make_big_real to get the 2 halves, then mpc_init, then
12514    *   mpc_set_fr_fr.
12515    */
12516   s7_pointer x;
12517 
12518   new_cell(sc, x, T_BIG_COMPLEX);
12519   big_complex_bgc(x) = alloc_bigcmp(sc);
12520   add_big_complex(sc, x);
12521   mpc_set_fr_fr(big_complex(x), rl ,im, MPC_RNDNN);
12522   return(x);
12523 }
12524 
12525 static block_t *mpfr_to_string(s7_scheme *sc, mpfr_t val, int32_t radix)
12526 {
12527   char *str;
12528   mp_exp_t expptr;
12529   int32_t ep;
12530   s7_int i, len;
12531   block_t *b, *btmp;
12532 
12533   if (mpfr_zero_p(val))
12534     return(string_to_block(sc, "0.0", 3));
12535 
12536   if (mpfr_nan_p(val))
12537     return(string_to_block(sc, "+nan.0", 6));
12538   if (mpfr_inf_p(val))
12539     return((mpfr_signbit(val) == 0) ? string_to_block(sc, "+inf.0", 6) : string_to_block(sc, "-inf.0", 6));
12540 
12541   b = callocate(sc, sc->bignum_precision + 32);
12542 #if 1
12543   str = mpfr_get_str((char *)block_data(b), &expptr, radix, 0, val, MPFR_RNDN);
12544   ep = (int32_t)expptr;
12545   len = safe_strlen(str);
12546 
12547   /* remove trailing 0's */
12548   for (i = len - 1; i > 3; i--)
12549     if (str[i] != '0')
12550       break;
12551   if (i < len - 1)
12552     str[i + 1] = '\0';
12553 
12554   btmp = mallocate(sc, len + 64);
12555   if (str[0] == '-')
12556     snprintf((char *)block_data(btmp), len + 64, "-%c.%s%c%d", str[1], (char *)(str + 2), (radix <= 10) ? 'E' : '@', ep - 1);
12557   else snprintf((char *)block_data(btmp), len + 64, "%c.%s%c%d", str[0], (char *)(str + 1), (radix <= 10) ? 'E' : '@', ep - 1);
12558 
12559   liberate(sc, b);
12560   return(btmp);
12561 #else
12562   /* this is dumb */
12563   mpfr_snprintf((char *)block_data(b), sc->bignum_precision + 32, "%.*RE", sc->bignum_precision, val); /* default precision is 1!! */
12564   return(b);
12565 #endif
12566 }
12567 
12568 static block_t *mpc_to_string(s7_scheme *sc, mpc_t val, int32_t radix, use_write_t use_write)
12569 {
12570   block_t *rl, *im, *tmp;
12571   s7_int len;
12572 
12573   mpc_real(sc->mpfr_1, val, MPFR_RNDN);
12574   rl = mpfr_to_string(sc, sc->mpfr_1, radix);
12575   mpc_imag(sc->mpfr_2, val, MPFR_RNDN);
12576   im = mpfr_to_string(sc, sc->mpfr_2, radix);
12577 
12578   len = safe_strlen((char *)block_data(rl)) + safe_strlen((char *)block_data(im)) + 128;
12579   tmp = mallocate(sc, len);
12580   snprintf((char *)block_data(tmp), len, "%s%s%si",
12581 	   (char *)block_data(rl),
12582 	   ((((char *)block_data(im))[0] == '-') || (((char *)block_data(im))[0] == '+')) ? "" : "+", (char *)block_data(im));
12583 
12584   liberate(sc, rl);
12585   liberate(sc, im);
12586   return(tmp);
12587 }
12588 
12589 static block_t *big_number_to_string_with_radix(s7_scheme *sc, s7_pointer p, int32_t radix, s7_int width, s7_int *nlen, use_write_t use_write)
12590 {
12591   block_t *str;
12592 
12593   switch (type(p))
12594     {
12595     case T_BIG_INTEGER:
12596       str = callocate(sc, mpz_sizeinbase(big_integer(p), radix) + 64);
12597       mpz_get_str((char *)block_data(str), radix, big_integer(p));
12598       break;
12599     case T_BIG_RATIO:
12600       mpz_set(sc->mpz_1, mpq_numref(big_ratio(p)));
12601       mpz_set(sc->mpz_2, mpq_denref(big_ratio(p)));
12602       str = callocate(sc, mpz_sizeinbase(sc->mpz_1, radix) + mpz_sizeinbase(sc->mpz_2, radix) + 64);
12603       mpq_get_str((char *)block_data(str), radix, big_ratio(p));
12604       break;
12605     case T_BIG_REAL:
12606       str = mpfr_to_string(sc, big_real(p), radix);
12607       break;
12608     default:
12609       str = mpc_to_string(sc, big_complex(p), radix, use_write);
12610       break;
12611     }
12612 
12613   if (width > 0)
12614     {
12615       s7_int len;
12616       len = safe_strlen((char *)block_data(str));
12617       if (width > len)
12618 	{
12619 	  int32_t spaces;
12620 	  block_t *tmp;
12621 	  tmp = (block_t *)mallocate(sc, width + 1);
12622 	  spaces = width - len;
12623 	  ((char *)block_data(tmp))[width] = '\0';
12624 	  memmove((void *)(block_data(tmp) + spaces), (void *)block_data(str), len);
12625 	  memset((void *)block_data(tmp), (int)' ', spaces);
12626 	  (*nlen) = width;
12627 	  liberate(sc, str);
12628 	  return(tmp);
12629 	}
12630       (*nlen) = len;
12631     }
12632   else (*nlen) = safe_strlen((char *)block_data(str));
12633   return(str);
12634 }
12635 
12636 static s7_pointer string_to_big_integer(s7_scheme *sc, const char *str, int32_t radix)
12637 {
12638   mpz_set_str(sc->mpz_4, (str[0] == '+') ? (const char *)(str + 1) : str, radix);
12639   return(mpz_to_integer(sc, sc->mpz_4));
12640 }
12641 
12642 static s7_pointer string_to_big_ratio(s7_scheme *sc, const char *str, int32_t radix)
12643 {
12644   s7_pointer x;
12645 
12646   mpq_set_str(sc->mpq_1, str, radix);
12647   mpq_canonicalize(sc->mpq_1);
12648 
12649   if (mpz_cmp_ui(mpq_denref(sc->mpq_1), 1) == 0)
12650     return(mpz_to_integer(sc, mpq_numref(sc->mpq_1)));
12651 
12652   new_cell(sc, x, T_BIG_RATIO);
12653   big_ratio_bgr(x) = alloc_bigrat(sc);
12654   add_big_ratio(sc, x);
12655   mpq_set(big_ratio(x), sc->mpq_1);
12656   return(x);
12657 }
12658 
12659 static s7_pointer string_to_big_real(s7_scheme *sc, const char *str, int32_t radix)
12660 {
12661   s7_pointer x;
12662   new_cell(sc, x, T_BIG_REAL);
12663   big_real_bgf(x) = alloc_bigflt(sc);
12664   add_big_real(sc, x);
12665   mpfr_set_str(big_real(x), str, radix, MPFR_RNDN);
12666   return(x);
12667 }
12668 
12669 static s7_int string_to_integer(const char *str, int32_t radix, bool *overflow);
12670 static s7_pointer string_to_either_integer(s7_scheme *sc, const char *str, int32_t radix)
12671 {
12672   s7_int val;
12673   bool overflow = false;
12674 
12675   val = string_to_integer(str, radix, &overflow);
12676   if (!overflow)
12677     return(make_integer(sc, val));
12678 
12679   return(string_to_big_integer(sc, str, radix));
12680 }
12681 
12682 static s7_pointer string_to_either_ratio(s7_scheme *sc, const char *nstr, const char *dstr, int32_t radix)
12683 {
12684   s7_int d;
12685   bool overflow = false;
12686 
12687   /* gmp segfaults if passed a bignum/0 so this needs to check first that
12688    *   the denominator is not 0 before letting gmp screw up.  Also, if the
12689    *   first character is '+', gmp returns 0!
12690    */
12691   d = string_to_integer(dstr, radix, &overflow);
12692   if (!overflow)
12693     {
12694       s7_int n;
12695       if (d == 0)
12696 	return(real_NaN);
12697 
12698       n = string_to_integer(nstr, radix, &overflow);
12699       if (!overflow)
12700 	return(s7_make_ratio(sc, n, d));
12701     }
12702   if (nstr[0] == '+')
12703     return(string_to_big_ratio(sc, (const char *)(nstr + 1), radix));
12704   return(string_to_big_ratio(sc, nstr, radix));
12705 }
12706 
12707 static s7_double string_to_double_with_radix(const char *ur_str, int32_t radix, bool *overflow);
12708 static s7_pointer string_to_either_real(s7_scheme *sc, const char *str, int32_t radix)
12709 {
12710   bool overflow = false;
12711   s7_double val;
12712 
12713   val = string_to_double_with_radix((char *)str, radix, &overflow);
12714   if (!overflow)
12715     return(make_real(sc, val));
12716 
12717   return(string_to_big_real(sc, str, radix));
12718 }
12719 
12720 static s7_pointer string_to_either_complex_1(s7_scheme *sc, char *q, char *slash1, char *ex1, bool has_dec_point1, int32_t radix, s7_double *d_rl)
12721 {
12722   bool overflow = false;
12723   /* there's a real problem here -- we don't want to promote s7_double .1 to a bignum because
12724    *    its low order digits are garbage, causing (rationalize .1 0) to return 3602879701896397/36028797018963968
12725    *    no matter what the bignum-precision.  But we can't just fallback on gmp's reader because (for example)
12726    *    it reads 1/2+i or 1+0/0i as 1.0.  Also format gets screwed up.  And string->number signals an error
12727    *    where it should return #f.  I wonder what to do.
12728    */
12729   if ((has_dec_point1) ||
12730       (ex1))
12731     {
12732       (*d_rl) = string_to_double_with_radix(q, radix, &overflow);
12733       if (overflow)
12734 	return(string_to_big_real(sc, q, radix));
12735     }
12736   else
12737     {
12738       if (slash1)
12739 	{
12740 	  s7_int n, d;
12741 
12742 	  /* q can include the slash and denominator */
12743 	  n = string_to_integer(q, radix, &overflow);
12744 	  if (overflow)
12745 	    return(string_to_big_ratio(sc, q, radix));
12746 	  d = string_to_integer(slash1, radix, &overflow);
12747 	  if (!overflow)
12748 	    (*d_rl) = (s7_double)n / (s7_double)d;
12749 	  else return(string_to_big_ratio(sc, q, radix));
12750 	}
12751       else
12752 	{
12753 	  s7_int val;
12754 
12755 	  val = string_to_integer(q, radix, &overflow);
12756 	  if (overflow)
12757 	    return(string_to_big_integer(sc, q, radix));
12758 	  (*d_rl) = (s7_double)val;
12759 	}}
12760   if ((*d_rl) == -0.0) (*d_rl) = 0.0;
12761   return(NULL);
12762 }
12763 
12764 static bool s7_is_zero(s7_pointer x);
12765 static s7_pointer string_to_either_complex(s7_scheme *sc, char *q, char *slash1, char *ex1, bool has_dec_point1,
12766 					   char *plus, char *slash2, char *ex2, bool has_dec_point2,
12767 					   int32_t radix, int32_t has_plus_or_minus)
12768 {
12769   /* this can be just about anything involving 2 real/ratio/int portions, +/- in between and 'i' at the end */
12770   double d_rl = 0.0, d_im = 0.0;
12771   s7_pointer p_rl = NULL, p_im = NULL;
12772 
12773   p_rl = string_to_either_complex_1(sc, q, slash1, ex1, has_dec_point1, radix, &d_rl);
12774   p_im = string_to_either_complex_1(sc, plus, slash2, ex2, has_dec_point2, radix, &d_im);
12775 
12776   if ((d_im == 0.0) &&                     /* 1.0+0.0000000000000000000000000000i */
12777       ((!p_im) || (s7_is_zero(p_im))))
12778     return((p_rl) ? p_rl : make_real(sc, d_rl));
12779 
12780   if ((!p_rl) && (!p_im))
12781     return(s7_make_complex(sc, d_rl, (has_plus_or_minus == -1) ? (-d_im) : d_im));
12782 
12783   if (p_rl)
12784     any_real_to_mpfr(sc, p_rl, sc->mpfr_1);
12785   else mpfr_set_d(sc->mpfr_1, d_rl, MPFR_RNDN);
12786 
12787   if (p_im)
12788     any_real_to_mpfr(sc, p_im, sc->mpfr_2);
12789   else mpfr_set_d(sc->mpfr_2, d_im, MPFR_RNDN);
12790 
12791   if (has_plus_or_minus == -1)
12792     mpfr_neg(sc->mpfr_2, sc->mpfr_2, MPFR_RNDN);
12793 
12794   return(make_big_complex(sc, sc->mpfr_1, sc->mpfr_2));
12795 }
12796 
12797 static bool big_numbers_are_eqv(s7_scheme *sc, s7_pointer a, s7_pointer b)
12798 {
12799   /* either or both can be big here, but not neither, and types might not match at all */
12800 #if S7_DEBUGGING
12801   if ((!s7_is_bignum(a)) && (!s7_is_bignum(b)))
12802     fprintf(stderr, "big eqv but neither is big: %s %s, %s %s\n", display(a), s7_type_names[type(a)], display(b), s7_type_names[type(b)]);
12803 #endif
12804   switch (type(a))
12805     {
12806     case T_INTEGER:
12807       return((is_t_big_integer(b)) && (mpz_cmp_si(big_integer(b), integer(a)) == 0));
12808     case T_BIG_INTEGER:
12809       if (is_t_big_integer(b)) return(mpz_cmp(big_integer(a), big_integer(b)) == 0);
12810       return((is_t_integer(b)) && (mpz_cmp_si(big_integer(a), integer(b)) == 0));
12811     case T_RATIO:
12812       if (is_t_big_ratio(b))
12813 	{
12814 	  mpq_set_si(sc->mpq_1, numerator(a), denominator(a));
12815 	  return(mpq_equal(sc->mpq_1, big_ratio(b)));
12816 	}
12817       return(false);
12818     case T_BIG_RATIO:
12819       if (is_t_big_ratio(b)) return(mpq_equal(big_ratio(a), big_ratio(b)));
12820       if (is_t_ratio(b))
12821 	{
12822 	  mpq_set_si(sc->mpq_1, numerator(b), denominator(b));
12823 	  return(mpq_equal(sc->mpq_1, big_ratio(a)));
12824 	}
12825       return(false);
12826     case T_REAL:
12827       if (is_NaN(real(a))) return(false);
12828       return((is_t_big_real(b)) && (!mpfr_nan_p(big_real(b))) && (mpfr_cmp_d(big_real(b), real(a)) == 0));
12829     case T_BIG_REAL:
12830       if (mpfr_nan_p(big_real(a))) return(false);
12831       if (is_t_big_real(b)) return((!mpfr_nan_p(big_real(b))) && (mpfr_equal_p(big_real(a), big_real(b))));
12832       return((is_t_real(b)) && (!is_NaN(real(b))) && (mpfr_cmp_d(big_real(a), real(b)) == 0));
12833     case T_COMPLEX:
12834       if ((is_NaN(real_part(a))) || (is_NaN(imag_part(a)))) return(false);
12835       if (is_t_big_complex(b))
12836 	{
12837 	  if ((mpfr_nan_p(mpc_realref(big_complex(b)))) || (mpfr_nan_p(mpc_imagref(big_complex(b)))))
12838 	    return(false);
12839 	  mpc_set_d_d(sc->mpc_1, real_part(a), imag_part(a), MPC_RNDNN);
12840 	  return(mpc_cmp(sc->mpc_1, big_complex(b)) == 0);
12841 	}
12842       return(false);
12843     case T_BIG_COMPLEX:
12844       if ((mpfr_nan_p(mpc_realref(big_complex(a)))) || (mpfr_nan_p(mpc_imagref(big_complex(a)))))
12845 	return(false);
12846       if (is_t_big_complex(b))
12847 	{
12848 	  if ((mpfr_nan_p(mpc_realref(big_complex(b)))) || (mpfr_nan_p(mpc_imagref(big_complex(b)))))
12849 	    return(false);
12850 	  return(mpc_cmp(big_complex(a), big_complex(b)) == 0);
12851 	}
12852       if (is_t_complex(b))
12853 	{
12854 	  if ((is_NaN(real_part(b))) || (is_NaN(imag_part(b)))) return(false);
12855 	  mpc_set_d_d(sc->mpc_2, real_part(b), imag_part(b), MPC_RNDNN);
12856 	  return(mpc_cmp(big_complex(a), sc->mpc_1) == 0);
12857 	}}
12858   return(false);
12859 }
12860 
12861 static s7_int big_integer_to_s7_int(s7_scheme *sc, mpz_t n)
12862 {
12863   if (!mpz_fits_slong_p(n))
12864     s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, wrap_string(sc, "big int does not fit in s7_int: ~S", 34), mpz_to_big_integer(sc, n)));
12865   return(mpz_get_si(n));
12866 }
12867 #endif
12868 
12869 #ifndef HAVE_OVERFLOW_CHECKS
12870   #if ((defined(__clang__) && (!POINTER_32) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4))) || (defined(__GNUC__) && __GNUC__ >= 5))
12871     #define HAVE_OVERFLOW_CHECKS 1
12872   #else
12873     #define HAVE_OVERFLOW_CHECKS 0
12874     #pragma message("no arithmetic overflow checks in this version of s7")
12875   #endif
12876 #endif
12877 
12878 #if (defined(__clang__) && (!POINTER_32) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4)))
12879   #define subtract_overflow(A, B, C)       __builtin_ssubll_overflow((long long)A, (long long)B, (long long *)C)
12880   #define add_overflow(A, B, C)            __builtin_saddll_overflow((long long)A, (long long)B, (long long *)C)
12881   #define multiply_overflow(A, B, C)       __builtin_smulll_overflow((long long)A, (long long)B, (long long *)C)
12882   /* #define int32_subtract_overflow(A, B, C) __builtin_ssub_overflow(A, B, C) */
12883   #define int32_add_overflow(A, B, C)      __builtin_sadd_overflow(A, B, C)
12884   #define int32_multiply_overflow(A, B, C) __builtin_smul_overflow(A, B, C)
12885 #else
12886 #if (defined(__GNUC__) && __GNUC__ >= 5)
12887   #define subtract_overflow(A, B, C)       __builtin_sub_overflow(A, B, C)
12888   #define add_overflow(A, B, C)            __builtin_add_overflow(A, B, C)
12889   #define multiply_overflow(A, B, C)       __builtin_mul_overflow(A, B, C)
12890   /* #define int32_subtract_overflow(A, B, C) __builtin_sub_overflow(A, B, C) */
12891   #define int32_add_overflow(A, B, C)      __builtin_add_overflow(A, B, C)
12892   #define int32_multiply_overflow(A, B, C) __builtin_mul_overflow(A, B, C)
12893 #endif
12894 #endif
12895 
12896 #if WITH_GCC
12897 #define s7_int_abs(x) ({s7_int _X_; _X_ = x; _X_ >= 0 ? _X_ : -_X_;})
12898 #else
12899 #define s7_int_abs(x) ((x) >= 0 ? (x) : -(x))
12900 #endif
12901 /* can't use abs even in gcc -- it doesn't work with int64_ts! */
12902 
12903 #if (!__NetBSD__)
12904   #define s7_fabsl(X) fabsl(X)
12905 #else
12906   static double s7_fabsl(long_double x) {if (x < 0.0) return(-x);  return(x);}
12907 #endif
12908 
12909 /* for g_log, we also need round. this version is from stackoverflow, see also r5rs_round below */
12910 double s7_round(double number) {return((number < 0.0) ? ceil(number - 0.5) : floor(number + 0.5));}
12911 
12912 #if HAVE_COMPLEX_NUMBERS
12913 #if __cplusplus
12914   #define _Complex_I (complex<s7_double>(0.0, 1.0))
12915   #define creal(x) Real(x)
12916   #define cimag(x) Imag(x)
12917   #define carg(x) arg(x)
12918   #define cabs(x) abs(x)
12919   #define csqrt(x) sqrt(x)
12920   #define cpow(x, y) pow(x, y)
12921   #define clog(x) log(x)
12922   #define cexp(x) exp(x)
12923   #define csin(x) sin(x)
12924   #define ccos(x) cos(x)
12925   #define ctan(x) tan(x)
12926   #define csinh(x) sinh(x)
12927   #define ccosh(x) cosh(x)
12928   #define ctanh(x) tanh(x)
12929   #define casin(x) asin(x)
12930   #define cacos(x) acos(x)
12931   #define catan(x) atan(x)
12932   #define casinh(x) asinh(x)
12933   #define cacosh(x) acosh(x)
12934   #define catanh(x) atanh(x)
12935 #else
12936   typedef double complex s7_complex;
12937 #endif
12938 
12939 
12940 #if (!HAVE_COMPLEX_TRIG)
12941 #if (__cplusplus)
12942 
12943   static s7_complex ctan(s7_complex z)   {return(csin(z) / ccos(z));}
12944   static s7_complex ctanh(s7_complex z)  {return(csinh(z) / ccosh(z));}
12945   static s7_complex casin(s7_complex z)  {return(-_Complex_I * clog(_Complex_I * z + csqrt(1.0 - z * z)));}
12946   static s7_complex cacos(s7_complex z)  {return(-_Complex_I * clog(z + _Complex_I * csqrt(1.0 - z * z)));}
12947   static s7_complex catan(s7_complex z)  {return(_Complex_I * clog((_Complex_I + z) / (_Complex_I - z)) / 2.0);}
12948   static s7_complex casinh(s7_complex z) {return(clog(z + csqrt(1.0 + z * z)));}
12949   static s7_complex cacosh(s7_complex z) {return(clog(z + csqrt(z * z - 1.0)));}
12950   static s7_complex catanh(s7_complex z) {return(clog((1.0 + z) / (1.0 - z)) / 2.0);}
12951 #else
12952 
12953 #if (!defined(__FreeBSD__)) || (__FreeBSD__ < 12)
12954 static s7_complex clog(s7_complex z) {return(log(fabs(cabs(z))) + carg(z) * _Complex_I);}
12955 static s7_complex cpow(s7_complex x, s7_complex y)
12956 {
12957   s7_double r = cabs(x);
12958   s7_double theta = carg(x);
12959   s7_double yre = creal(y);
12960   s7_double yim = cimag(y);
12961   s7_double nr = exp(yre * log(r) - yim * theta);
12962   s7_double ntheta = yre * theta + yim * log(r);
12963   return(nr * cos(ntheta) + (nr * sin(ntheta)) * _Complex_I);
12964 }
12965 #endif
12966 #if (!defined(__FreeBSD__)) || (__FreeBSD__ < 9) /* untested -- this orignally looked at __FreeBSD_version which apparently no longer exists */
12967   static s7_complex cexp(s7_complex z) {return(exp(creal(z)) * cos(cimag(z)) + (exp(creal(z)) * sin(cimag(z))) * _Complex_I);}
12968 #endif
12969 
12970 #if (!defined(__FreeBSD__)) || (__FreeBSD__ < 10)
12971   static s7_complex csin(s7_complex z)   {return(sin(creal(z)) * cosh(cimag(z)) + (cos(creal(z)) * sinh(cimag(z))) * _Complex_I);}
12972   static s7_complex ccos(s7_complex z)   {return(cos(creal(z)) * cosh(cimag(z)) + (-sin(creal(z)) * sinh(cimag(z))) * _Complex_I);}
12973   static s7_complex csinh(s7_complex z)  {return(sinh(creal(z)) * cos(cimag(z)) + (cosh(creal(z)) * sin(cimag(z))) * _Complex_I);}
12974   static s7_complex ccosh(s7_complex z)  {return(cosh(creal(z)) * cos(cimag(z)) + (sinh(creal(z)) * sin(cimag(z))) * _Complex_I);}
12975   static s7_complex ctan(s7_complex z)   {return(csin(z) / ccos(z));}
12976   static s7_complex ctanh(s7_complex z)  {return(csinh(z) / ccosh(z));}
12977   static s7_complex casin(s7_complex z)  {return(-_Complex_I * clog(_Complex_I * z + csqrt(1.0 - z * z)));}
12978   static s7_complex cacos(s7_complex z)  {return(-_Complex_I * clog(z + _Complex_I * csqrt(1.0 - z * z)));}
12979   static s7_complex catan(s7_complex z)  {return(_Complex_I * clog((_Complex_I + z) / (_Complex_I - z)) / 2.0);}
12980   static s7_complex catanh(s7_complex z) {return(clog((1.0 + z) / (1.0 - z)) / 2.0);}
12981   static s7_complex casinh(s7_complex z) {return(clog(z + csqrt(1.0 + z * z)));}
12982   static s7_complex cacosh(s7_complex z) {return(clog(z + csqrt(z * z - 1.0)));}
12983 #endif /* not FreeBSD 10 */
12984 #endif /* not c++ */
12985 #endif /* not HAVE_COMPLEX_TRIG */
12986 
12987 #else  /* not HAVE_COMPLEX_NUMBERS */
12988   typedef double s7_complex;
12989   #define _Complex_I 1
12990   #define creal(x) x
12991   #define cimag(x) x
12992   #define csin(x) sin(x)
12993   #define casin(x) x
12994   #define ccos(x) cos(x)
12995   #define cacos(x) x
12996   #define ctan(x) x
12997   #define catan(x) x
12998   #define csinh(x) x
12999   #define casinh(x) x
13000   #define ccosh(x) x
13001   #define cacosh(x) x
13002   #define ctanh(x) x
13003   #define catanh(x) x
13004   #define cexp(x) exp(x)
13005   #define cpow(x, y) pow(x, y)
13006   #define clog(x) log(x)
13007   #define csqrt(x) sqrt(x)
13008   #define conj(x) x
13009 #endif
13010 
13011 #ifdef __OpenBSD__
13012   /* openbsd's builtin versions of these functions are not usable */
13013   static s7_complex catanh_1(s7_complex z) {return(clog((1.0 + z) / (1.0 - z)) / 2.0);}
13014   static s7_complex casinh_1(s7_complex z) {return(clog(z + csqrt(1.0 + z * z)));}
13015   static s7_complex cacosh_1(s7_complex z) {return(clog(z + csqrt(z * z - 1.0)));}
13016 #endif
13017 #ifdef __NetBSD__
13018   static s7_complex catanh_1(s7_complex z) {return(clog((1.0 + z) / (1.0 - z)) / 2.0);}
13019   static s7_complex casinh_1(s7_complex z) {return(clog(z + csqrt(1.0 + z * z)));}
13020 #endif
13021 
13022 
13023 bool s7_is_number(s7_pointer p) {return(is_number(p));}
13024 bool s7_is_complex(s7_pointer p) {return(is_number(p));}
13025 
13026 bool s7_is_integer(s7_pointer p)
13027 {
13028 #if WITH_GMP
13029   return((is_t_integer(p)) || (is_t_big_integer(p)));
13030 #else
13031   return(is_t_integer(p));
13032 #endif
13033 }
13034 
13035 bool s7_is_real(s7_pointer p) {return(is_real(p));}
13036 bool s7_is_rational(s7_pointer p) {return(is_rational(p));}
13037 
13038 bool s7_is_ratio(s7_pointer p)
13039 {
13040 #if WITH_GMP
13041   return((is_t_ratio(p)) || (is_t_big_ratio(p)));
13042 #else
13043   return(is_t_ratio(p));
13044 #endif
13045 }
13046 
13047 static s7_int c_gcd(s7_int u, s7_int v)
13048 {
13049   s7_int a, b;
13050 
13051   if ((u == s7_int_min) || (v == s7_int_min))
13052     {
13053       /* can't take abs of these (below) so do it by hand */
13054       s7_int divisor = 1;
13055       if (u == v) return(u);
13056       while (((u & 1) == 0) && ((v & 1) == 0))
13057 	{
13058 	  u /= 2;
13059 	  v /= 2;
13060 	  divisor *= 2;
13061 	}
13062       return(divisor);
13063     }
13064 
13065   a = s7_int_abs(u);
13066   b = s7_int_abs(v);
13067   /* there are faster gcd algorithms but does it ever matter? */
13068   while (b != 0)
13069     {
13070       s7_int temp;
13071       temp = a % b;
13072       a = b;
13073       b = temp;
13074     }
13075   /* if (a < 0) return(-a); */ /* why this? */
13076   return(a);
13077 }
13078 
13079 #define RATIONALIZE_LIMIT 1.0e12
13080 
13081 static bool c_rationalize(s7_double ux, s7_double error, s7_int *numer, s7_int *denom)
13082 {
13083   /*
13084     (define* (rat ux (err 0.0000001))
13085       ;; translated from CL code in Canny, Donald, Ressler, "A Rational Rotation Method for Robust Geometric Algorithms"
13086       (let ((x0 (- ux error))
13087 	    (x1 (+ ux error)))
13088         (let ((i (ceiling x0))
13089 	      (i0 (floor x0))
13090 	      (i1 (ceiling x1))
13091 	      (r 0))
13092           (if (>= x1 i)
13093 	      i
13094 	      (do ((p0 i0 (+ p1 (* r p0)))
13095 	           (q0 1 (+ q1 (* r q0)))
13096 	           (p1 i1 p0)
13097 	           (q1 1 q0)
13098 	           (e0 (- i1 x0) e1p)
13099 	           (e1 (- x0 i0) (- e0p (* r e1p)))
13100 	           (e0p (- i1 x1) e1)
13101 	           (e1p (- x1 i0) (- e0 (* r e1))))
13102 	          ((<= x0 (/ p0 q0) x1)
13103 	           (/ p0 q0))
13104 	        (set! r (min (floor (/ e0 e1))
13105 			     (ceiling (/ e0p e1p)))))))))
13106   */
13107 
13108   double x0, x1;
13109   s7_int i, i0, i1, p0, q0, p1, q1;
13110   double e0, e1, e0p, e1p;
13111   int32_t tries = 0;
13112   /* don't use long_double: the loop below will hang */
13113 
13114   /* #e1e19 is a killer -- it's bigger than most-positive-fixnum, but if we ceil(ux) below
13115    *   it turns into most-negative-fixnum.  1e19 is trouble in many places.
13116    */
13117   if (fabs(ux) > RATIONALIZE_LIMIT)
13118     {
13119       /* (rationalize most-positive-fixnum) should not return most-negative-fixnum
13120        *   but any number > 1e14 here is so inaccurate that rationalize is useless
13121        *   for example,
13122        *     default: (rationalize (/ (*s7* 'most-positive-fixnum) 31111.0)) -> 1185866354261165/4
13123        *     gmp:     (rationalize (/ (*s7* 'most-positive-fixnum) 31111.0)) -> 9223372036854775807/31111
13124        * can't return false here because that confuses some of the callers!
13125        */
13126       (*numer) = (s7_int)ux;
13127       (*denom) = 1;
13128       return(true);
13129     }
13130 
13131   if (error < 0.0) error = -error;
13132   x0 = ux - error;
13133   x1 = ux + error;
13134   i = (s7_int)ceil(x0);
13135 
13136   if (error >= 1.0) /* aw good grief! */
13137     {
13138       if (x0 < 0)
13139 	(*numer) = (x1 < 0) ? (s7_int)floor(x1) : 0;
13140       else (*numer) = i;
13141       (*denom) = 1;
13142       return(true);
13143     }
13144 
13145   if (x1 >= i)
13146     {
13147       (*numer) = (i >= 0) ? i : (s7_int)floor(x1);
13148       (*denom) = 1;
13149       return(true);
13150     }
13151 
13152   i0 = (s7_int)floor(x0);
13153   i1 = (s7_int)ceil(x1);
13154 
13155   p0 = i0;
13156   q0 = 1;
13157   p1 = i1;
13158   q1 = 1;
13159   e0 = i1 - x0;
13160   e1 = x0 - i0;
13161   e0p = i1 - x1;
13162   e1p = x1 - i0;
13163 
13164   while (true)
13165     {
13166       s7_int old_p1, old_q1;
13167       double old_e0, old_e1, old_e0p, val, r, r1;
13168       val = (double)p0 / (double)q0;
13169 
13170       if (((x0 <= val) && (val <= x1)) ||
13171 	  (e1 == 0)                    ||
13172 	  (e1p == 0)                   ||
13173 	  (tries > 100))
13174 	{
13175 	  if ((q0 == s7_int_min) && (p0 == 1)) /* (rationalize 1.000000004297917e-12) when error is 1e-12 */
13176 	    {
13177 	      (*numer) = 0;
13178 	      (*denom) = 1;
13179 	    }
13180 	  else
13181 	    {
13182 	      (*numer) = p0;
13183 	      (*denom) = q0;
13184 	    }
13185 	  return(true);
13186 	}
13187       tries++;
13188 
13189       r = (s7_int)floor(e0 / e1);
13190       r1 = (s7_int)ceil(e0p / e1p);
13191       if (r1 < r) r = r1;
13192 
13193       /* do handles all step vars in parallel */
13194       old_p1 = p1;
13195       p1 = p0;
13196       old_q1 = q1;
13197       q1 = q0;
13198       old_e0 = e0;
13199       e0 = e1p;
13200       old_e0p = e0p;
13201       e0p = e1;
13202       old_e1 = e1;
13203 
13204       p0 = old_p1 + r * p0;
13205       q0 = old_q1 + r * q0;
13206       e1 = old_e0p - r * e1p;
13207       /* if the error is set too low, we can get e1 = 0 here: (rationalize (/ pi) 1e-17) */
13208       e1p = old_e0 - r * old_e1;
13209     }
13210   return(false);
13211 }
13212 
13213 s7_pointer s7_rationalize(s7_scheme *sc, s7_double x, s7_double error)
13214 {
13215   s7_int numer = 0, denom = 1;
13216   if (c_rationalize(x, error, &numer, &denom))
13217     return(s7_make_ratio(sc, numer, denom));
13218   return(make_real(sc, x));
13219 }
13220 
13221 s7_pointer s7_make_integer(s7_scheme *sc, s7_int n)
13222 {
13223   s7_pointer x;
13224   if (is_small_int(n))
13225     return(small_int(n));
13226   new_cell(sc, x, T_INTEGER);
13227   integer(x) = n;
13228   return(x);
13229 }
13230 
13231 static s7_pointer make_mutable_integer(s7_scheme *sc, s7_int n)
13232 {
13233   s7_pointer x;
13234   new_cell(sc, x, T_INTEGER | T_MUTABLE | T_IMMUTABLE);
13235   integer(x) = n;
13236   return(x);
13237 }
13238 
13239 static s7_pointer make_permanent_integer(s7_int i)
13240 {
13241   if (is_small_int(i)) return(small_int(i));
13242 
13243   if (i == MAX_ARITY) return(max_arity);
13244   if (i == CLOSURE_ARITY_NOT_SET) return(arity_not_set);
13245   if (i == -1) return(minus_one);
13246   if (i == -2) return(minus_two);
13247   /* a few -3 */
13248 
13249   return(make_permanent_integer_unchecked(i));
13250 }
13251 
13252 s7_pointer s7_make_real(s7_scheme *sc, s7_double n)
13253 {
13254   s7_pointer x;
13255   new_cell(sc, x, T_REAL);
13256   set_real(x, n);
13257   return(x);
13258 }
13259 
13260 s7_pointer s7_make_mutable_real(s7_scheme *sc, s7_double n)
13261 {
13262   s7_pointer x;
13263   new_cell(sc, x, T_REAL | T_MUTABLE | T_IMMUTABLE);
13264   set_real(x, n);
13265   return(x);
13266 }
13267 
13268 s7_pointer s7_make_complex(s7_scheme *sc, s7_double a, s7_double b)
13269 {
13270   s7_pointer x;
13271   if (b == 0.0)
13272     {
13273       new_cell(sc, x, T_REAL);
13274       set_real(x, a);
13275     }
13276   else
13277     {
13278       new_cell(sc, x, T_COMPLEX);
13279       set_real_part(x, a);
13280       set_imag_part(x, b);
13281     }
13282   return(x);
13283 }
13284 
13285 static s7_complex s7_to_c_complex(s7_pointer p)
13286 {
13287 #if HAVE_COMPLEX_NUMBERS
13288   return(CMPLX(s7_real_part(p), s7_imag_part(p)));
13289 #else
13290   return(0.0);
13291 #endif
13292 }
13293 
13294 static s7_pointer c_complex_to_s7(s7_scheme *sc, s7_complex z)
13295 {
13296   return(make_complex(sc, creal(z), cimag(z)));
13297 }
13298 
13299 static s7_pointer division_by_zero_error(s7_scheme *sc, s7_pointer caller, s7_pointer arg);
13300 
13301 s7_pointer s7_make_ratio(s7_scheme *sc, s7_int a, s7_int b)
13302 {
13303   s7_pointer x;
13304   if (b == 0)
13305     return(division_by_zero_error(sc, wrap_string(sc, "make-ratio", 10), set_elist_2(sc, wrap_integer1(sc, a), int_zero)));
13306   if (a == 0)
13307     return(int_zero);
13308   if (a == b)
13309     return(int_one);
13310   if (b == 1)
13311     return(make_integer(sc, a));
13312 
13313   if (b == s7_int_min)
13314     {
13315       /* we've got a problem... This should not trigger an error during reading -- we might have the
13316        *   ratio on a switch with-bignums or whatever, so its mere occurrence is just an annoyance.
13317        */
13318       if (a & 1)
13319 	return(make_real(sc, (long_double)a / (long_double)b));
13320       a /= 2;
13321       b /= 2;
13322     }
13323 
13324   if (b < 0)
13325     {
13326       a = -a;
13327       b = -b;
13328     }
13329 
13330   if (a == s7_int_min) /* believe it or not, gcc randomly says a != S7_INT64_MIN here but a == s7_int_min even with explicit types! This has to be a bug */
13331     {
13332       while (((a & 1) == 0) && ((b & 1) == 0))
13333 	{
13334 	  a /= 2;
13335 	  b /= 2;
13336 	}}
13337   else
13338     {
13339       s7_int b1, divisor;
13340       divisor = s7_int_abs(a);
13341       b1 = b;
13342       do {
13343 	s7_int temp;
13344 	temp = divisor % b1;
13345 	divisor = b1;
13346 	b1 = temp;
13347       } while (b1 != 0);
13348       if (divisor != 1)
13349 	{
13350 	  a /= divisor;
13351 	  b /= divisor;
13352 	}}
13353   if (b == 1)
13354     return(make_integer(sc, a));
13355 
13356   new_cell(sc, x, T_RATIO);
13357   numerator(x) = a;
13358   denominator(x) = b;
13359   return(x);
13360 }
13361 
13362 
13363 #define WITH_OVERFLOW_ERROR true
13364 #define WITHOUT_OVERFLOW_ERROR false
13365 
13366 #define INT64_TO_DOUBLE_LIMIT (1LL << 53)
13367 #define DOUBLE_TO_INT64_LIMIT (1LL << 53)
13368 
13369 #if (!WITH_PURE_S7)
13370 
13371 /* 9007199254740991LL is where a truncated double starts to skip integers (expt 2 53) = ca 1e16
13372  *   (ceiling (+ 1e16 1)) -> 10000000000000000
13373  *   (> 9007199254740993.0 9007199254740992.0) -> #f ; in non-gmp 64-bit doubles
13374  * but we can't fix this except in the gmp case because:
13375  *   (integer-decode-float (+ (expt 2.0 62) 100)) -> (4503599627370496 10 1)
13376  *   (integer-decode-float (+ (expt 2.0 62) 500)) -> (4503599627370496 10 1)
13377  *   (> (+ (expt 2.0 62) 500) (+ (expt 2.0 62) 100)) -> #f ; non-gmp again
13378  * i.e. the bits are identical.  We can't even detect when it has happened (without tedious effort), so should
13379  *   we just give an error for any floor (or whatever) of an arg>1e16?  (sin has a similar problem)?
13380  *   I think in the non-gmp case I'll throw an error in these cases because the results are bogus:
13381  *   (floor (+ (expt 2.0 62) 512)) -> 4611686018427387904
13382  *   (floor (+ (expt 2.0 62) 513)) -> 4611686018427388928
13383  * another case at the edge: (round 9007199254740992.51) -> 9007199254740992
13384  * This spells trouble for normal arithmetic in this range.  If no gmp,
13385  *    (- (+ (expt 2.0 62) 512) (+ (expt 2.0 62) 513)) = -1024.0 (should be -1.0)
13386  *    but we don't currently give an error in this case -- not sure what the right thing is.
13387  */
13388 
13389 static s7_pointer exact_to_inexact(s7_scheme *sc, s7_pointer x)
13390 {
13391   switch (type(x))
13392     {
13393     case T_INTEGER:
13394 #if WITH_GMP
13395       if ((integer(x) > INT64_TO_DOUBLE_LIMIT) || (integer(x) < -INT64_TO_DOUBLE_LIMIT))
13396 	return(s7_number_to_big_real(sc, x));
13397 #endif
13398       return(make_real(sc, (s7_double)(integer(x))));
13399 
13400     case T_RATIO:
13401 #if WITH_GMP
13402       if ((numerator(x) > INT64_TO_DOUBLE_LIMIT) || (numerator(x) < -INT64_TO_DOUBLE_LIMIT) ||
13403  	  (denominator(x) > INT64_TO_DOUBLE_LIMIT))  /* just a guess */
13404 	return(s7_number_to_big_real(sc, x));
13405 #endif
13406       return(make_real(sc, (s7_double)(fraction(x))));
13407 
13408 #if WITH_GMP
13409     case T_BIG_INTEGER:
13410       return(big_integer_to_big_real(sc, x));
13411 
13412     case T_BIG_RATIO:
13413       return(big_ratio_to_big_real(sc, x));
13414 #endif
13415 
13416     case T_REAL:    case T_BIG_REAL:
13417     case T_COMPLEX: case T_BIG_COMPLEX:
13418       return(x); /* apparently (exact->inexact 1+i) is not an error */
13419 
13420     default:
13421       return(method_or_bust_with_type_one_arg_p(sc, x, sc->exact_to_inexact_symbol, a_number_string));
13422     }
13423 }
13424 
13425 #if WITH_GMP
13426 static s7_pointer big_rationalize(s7_scheme *sc, s7_pointer args);
13427 #endif
13428 
13429 static s7_pointer inexact_to_exact(s7_scheme *sc, s7_pointer x)
13430 {
13431   switch (type(x))
13432     {
13433     case T_INTEGER: case T_BIG_INTEGER:
13434     case T_RATIO:   case T_BIG_RATIO:
13435       return(x);
13436 
13437 #if WITH_GMP
13438     case T_BIG_REAL:
13439       return(big_rationalize(sc, set_plist_1(sc, x)));
13440 #endif
13441 
13442     case T_REAL:
13443       {
13444 	s7_int numer = 0, denom = 1;
13445 	s7_double val;
13446 
13447 	val = real(x);
13448 	if ((is_inf(val)) || (is_NaN(val)))
13449 	  return(simple_wrong_type_argument_with_type(sc, sc->inexact_to_exact_symbol, x, a_normal_real_string));
13450 
13451 	if ((val > DOUBLE_TO_INT64_LIMIT) || (val < -(DOUBLE_TO_INT64_LIMIT)))
13452 	  {
13453 #if WITH_GMP
13454 	    return(big_rationalize(sc, set_plist_1(sc, x))); /* this can handle t_real as well as t_big_real */
13455 #else
13456 	    return(simple_out_of_range(sc, sc->inexact_to_exact_symbol, x, its_too_large_string));
13457 #endif
13458 	  }
13459 	/* c_rationalize limit is RATIONALIZE_LIMIT=1e12 currently so this is a tighter limit than DOUBLE_TO_INT64_LIMIT */
13460 	if (c_rationalize(val, sc->default_rationalize_error, &numer, &denom))
13461 	  return(s7_make_ratio(sc, numer, denom));
13462       }
13463 
13464     default:
13465       return(method_or_bust_one_arg_p(sc, x, sc->inexact_to_exact_symbol, T_REAL));
13466     }
13467   return(x);
13468 }
13469 #endif
13470 
13471 /* this is a mess -- it's too late to clean up s7.h (sigh) */
13472 s7_double s7_number_to_real_with_caller(s7_scheme *sc, s7_pointer x, const char *caller)
13473 {
13474   if (is_t_real(x))
13475     return(real(x));
13476 
13477   switch (type(x))
13478     {
13479     case T_INTEGER:     return((s7_double)integer(x));
13480     case T_RATIO:       return(fraction(x));
13481     case T_REAL:        return(real(x));
13482 #if WITH_GMP
13483     case T_BIG_INTEGER: return((s7_double)big_integer_to_s7_int(sc, big_integer(x)));
13484     case T_BIG_RATIO:   return((s7_double)((long_double)big_integer_to_s7_int(sc, mpq_numref(big_ratio(x))) /
13485 					   (long_double)big_integer_to_s7_int(sc, mpq_denref(big_ratio(x)))));
13486     case T_BIG_REAL:    return((s7_double)mpfr_get_d(big_real(x), MPFR_RNDN));
13487 #endif
13488     }
13489   s7_wrong_type_arg_error(sc, caller, 0, x, "a real number");
13490   return(0.0);
13491 }
13492 
13493 s7_double s7_number_to_real(s7_scheme *sc, s7_pointer x)
13494 {
13495   return(s7_number_to_real_with_caller(sc, x, "s7_number_to_real"));
13496 }
13497 
13498 s7_int s7_number_to_integer_with_caller(s7_scheme *sc, s7_pointer x, const char *caller)
13499 {
13500   if (is_t_integer(x)) return(integer(x));
13501 
13502 #if WITH_GMP
13503   if (is_t_big_integer(x)) return(big_integer_to_s7_int(sc, big_integer(x)));
13504 #endif
13505   s7_wrong_type_arg_error(sc, caller, 0, x, "an integer");
13506   return(0);
13507 }
13508 
13509 s7_int s7_number_to_integer(s7_scheme *sc, s7_pointer x)
13510 {
13511   return(s7_number_to_integer_with_caller(sc, x, "s7_number_to_integer"));
13512 }
13513 
13514 
13515 s7_int s7_numerator(s7_pointer x)
13516 {
13517   switch (type(x))
13518     {
13519     case T_INTEGER:     return(integer(x));
13520     case T_RATIO:       return(numerator(x));
13521 #if WITH_GMP
13522     case T_BIG_INTEGER: return(mpz_get_si(big_integer(x))); /* big_integer_to_s7_int but no sc -- no error if out of range */
13523     case T_BIG_RATIO:   return(mpz_get_si(mpq_numref(big_ratio(x))));
13524 #endif
13525     }
13526   return(0);
13527 }
13528 
13529 s7_int s7_denominator(s7_pointer x)
13530 {
13531   if (is_t_ratio(x)) return(denominator(x));
13532 #if WITH_GMP
13533   if (is_t_big_ratio(x)) return(mpz_get_si(mpq_denref(big_ratio(x))));
13534 #endif
13535   return(1);
13536 }
13537 
13538 s7_int s7_integer(s7_pointer p)
13539 {
13540   if (is_t_integer(p))
13541     return(integer(p));
13542 #if WITH_GMP
13543   if (is_t_big_integer(p))
13544     return(mpz_get_si(big_integer(p)));
13545 #endif
13546   return(0);
13547 }
13548 
13549 static s7_int s7_integer_checked(s7_scheme *sc, s7_pointer p) /* "checked" = gmp range check */
13550 {
13551   if (is_t_integer(p))
13552     return(integer(p));
13553 #if WITH_GMP
13554   if (is_t_big_integer(p))
13555     return(big_integer_to_s7_int(sc, big_integer(p)));
13556 #endif
13557   return(0);
13558 }
13559 
13560 s7_double s7_real(s7_pointer x)
13561 {
13562   if (is_t_real(x)) return(real(x));
13563   switch (type(x))
13564     {
13565     case T_RATIO:       return(fraction(x));
13566     case T_INTEGER:     return((s7_double)integer(x));
13567 #if WITH_GMP
13568     case T_BIG_INTEGER: return((s7_double)mpz_get_si(big_integer(x)));
13569     case T_BIG_REAL:    return((s7_double)mpfr_get_d(big_real(x), MPFR_RNDN));
13570     case T_BIG_RATIO:
13571       {
13572 	s7_double result;
13573 	mpfr_t bx;
13574 	mpfr_init2(bx, DEFAULT_BIGNUM_PRECISION);
13575 	mpfr_set_q(bx, big_ratio(x), MPFR_RNDN);
13576 	result = mpfr_get_d(bx, MPFR_RNDN);
13577 	mpfr_clear(bx);
13578 	return(result);
13579       }
13580 #endif
13581     }
13582   return(0.0);
13583 }
13584 
13585 static bool s7_is_negative(s7_pointer obj)
13586 {
13587   switch (type(obj))
13588     {
13589     case T_INTEGER:     return(integer(obj) < 0);
13590     case T_RATIO:       return(numerator(obj) < 0);
13591 #if WITH_GMP
13592     case T_BIG_INTEGER: return(mpz_cmp_ui(big_integer(obj), 0) < 0);
13593     case T_BIG_RATIO:   return(mpq_cmp_ui(big_ratio(obj), 0, 1) < 0);
13594     case T_BIG_REAL:    return(mpfr_cmp_ui(big_real(obj), 0) < 0);
13595 #endif
13596     default:            return(real(obj) < 0);
13597     }
13598 }
13599 
13600 static bool s7_is_positive(s7_pointer x)
13601 {
13602   switch (type(x))
13603     {
13604     case T_INTEGER:     return(integer(x) > 0);
13605     case T_RATIO:       return(numerator(x) > 0);
13606 #if WITH_GMP
13607     case T_BIG_INTEGER: return(mpz_cmp_ui(big_integer(x), 0) > 0);
13608     case T_BIG_RATIO:   return(mpq_cmp_ui(big_ratio(x), 0, 1) > 0);
13609     case T_BIG_REAL:    return(mpfr_cmp_ui(big_real(x), 0) > 0);
13610 #endif
13611     default:            return(real(x) > 0.0);
13612     }
13613 }
13614 
13615 static bool s7_is_zero(s7_pointer x)
13616 {
13617   switch (type(x))
13618     {
13619     case T_INTEGER:     return(integer(x) == 0);
13620     case T_REAL:        return(real(x) == 0.0);
13621 #if WITH_GMP
13622     case T_BIG_INTEGER: return(mpz_cmp_ui(big_integer(x), 0) == 0);
13623     case T_BIG_RATIO:   return(false);
13624     case T_BIG_REAL:    return(mpfr_zero_p(big_real(x)));
13625 #endif
13626     default:            return(false); /* ratios and complex numbers here are already collapsed into integers and reals */
13627     }
13628 }
13629 
13630 static bool s7_is_one(s7_pointer x)
13631 {
13632   return(((is_t_integer(x)) && (integer(x) == 1)) ||
13633 	 ((is_t_real(x)) && (real(x) == 1.0)));
13634 }
13635 
13636 
13637 /* -------- optimize exponents -------- */
13638 
13639 #define MAX_POW 64
13640 static double **pepow = NULL; /* [17][MAX_POW * 2]; */
13641 
13642 static void init_pows(void)
13643 {
13644   int32_t i, j;
13645   pepow = (double **)malloc(17 * sizeof(double *));
13646   pepow[0] = NULL;
13647   pepow[1] = NULL;
13648   for (i = 2; i < 17; i++) pepow[i] = (double *)malloc((MAX_POW * 2) * sizeof(double));
13649   for (i = 2; i < 17; i++)        /* radix between 2 and 16 */
13650     for (j = -MAX_POW; j < MAX_POW; j++) /* saved exponent between 0 and +/- MAX_POW */
13651       pepow[i][j + MAX_POW] = pow((double)i, (double)j);
13652 }
13653 
13654 static inline double dpow(int32_t x, int32_t y)
13655 {
13656   if ((y >= MAX_POW) || (y < -MAX_POW)) /* this can happen (once in a blue moon) */
13657     return(pow((double)x, (double)y));
13658   return(pepow[x][y + MAX_POW]);
13659 }
13660 
13661 
13662 /* -------------------------------- number->string -------------------------------- */
13663 #define WITH_DTOA 1
13664 #if WITH_DTOA
13665 /* fpconv, revised to fit the local coding style
13666 
13667    The MIT License
13668 
13669 Copyright (c) 2013 Andreas Samoljuk
13670 
13671 Permission is hereby granted, free of charge, to any person obtaining
13672 a copy of this software and associated documentation files (the
13673 "Software"), to deal in the Software without restriction, including
13674 without limitation the rights to use, copy, modify, merge, publish,
13675 distribute, sublicense, and/or sell copies of the Software, and to
13676 permit persons to whom the Software is furnished to do so, subject to
13677 the following conditions:
13678 
13679 The above copyright notice and this permission notice shall be
13680 included in all copies or substantial portions of the Software.
13681 
13682 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13683 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13684 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13685 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
13686 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
13687 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
13688 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13689 */
13690 
13691 #define dtoa_npowers     87
13692 #define dtoa_steppowers  8
13693 #define dtoa_firstpower -348 /* 10 ^ -348 */
13694 #define dtoa_expmax     -32
13695 #define dtoa_expmin     -60
13696 
13697 typedef struct dtoa_Fp {uint64_t frac; int exp;} dtoa_Fp;
13698 
13699 static const dtoa_Fp dtoa_powers_ten[] = {
13700     { 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 }, { 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 },
13701     { 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 }, { 12353653155963782858U, -1060 }, { 18408377700990114895U, -1034 },
13702     { 13715310171984221708U, -1007 }, { 10218702384817765436U, -980 }, { 15227053142812498563U, -954 },  { 11345038669416679861U, -927 },
13703     { 16905424996341287883U, -901 },  { 12595523146049147757U, -874 }, { 9384396036005875287U,  -847 },  { 13983839803942852151U, -821 },
13704     { 10418772551374772303U, -794 },  { 15525180923007089351U, -768 }, { 11567161174868858868U, -741 },  { 17236413322193710309U, -715 },
13705     { 12842128665889583758U, -688 },  { 9568131466127621947U,  -661 }, { 14257626930069360058U, -635 },  { 10622759856335341974U, -608 },
13706     { 15829145694278690180U, -582 },  { 11793632577567316726U, -555 }, { 17573882009934360870U, -529 },  { 13093562431584567480U, -502 },
13707     { 9755464219737475723U,  -475 },  { 14536774485912137811U, -449 }, { 10830740992659433045U, -422 },  { 16139061738043178685U, -396 },
13708     { 12024538023802026127U, -369 },  { 17917957937422433684U, -343 }, { 13349918974505688015U, -316 },  { 9946464728195732843U,  -289 },
13709     { 14821387422376473014U, -263 },  { 11042794154864902060U, -236 }, { 16455045573212060422U, -210 },  { 12259964326927110867U, -183 },
13710     { 18268770466636286478U, -157 },  { 13611294676837538539U, -130 }, { 10141204801825835212U, -103 },  { 15111572745182864684U, -77 },
13711     { 11258999068426240000U, -50 },   { 16777216000000000000U, -24 }, { 12500000000000000000U,   3 },   { 9313225746154785156U,   30 },
13712     { 13877787807814456755U,  56 },   { 10339757656912845936U,  83 }, { 15407439555097886824U, 109 },   { 11479437019748901445U, 136 },
13713     { 17105694144590052135U, 162 },   { 12744735289059618216U, 189 }, { 9495567745759798747U,  216 },   { 14149498560666738074U, 242 },
13714     { 10542197943230523224U, 269 },   { 15709099088952724970U, 295 }, { 11704190886730495818U, 322 },   { 17440603504673385349U, 348 },
13715     { 12994262207056124023U, 375 },   { 9681479787123295682U,  402 }, { 14426529090290212157U, 428 },   { 10748601772107342003U, 455 },
13716     { 16016664761464807395U, 481 },   { 11933345169920330789U, 508 }, { 17782069995880619868U, 534 },   { 13248674568444952270U, 561 },
13717     { 9871031767461413346U,  588 },   { 14708983551653345445U, 614 }, { 10959046745042015199U, 641 },   { 16330252207878254650U, 667 },
13718     { 12166986024289022870U, 694 },   { 18130221999122236476U, 720 }, { 13508068024458167312U, 747 },   { 10064294952495520794U, 774 },
13719     { 14996968138956309548U, 800 },   { 11173611982879273257U, 827 }, { 16649979327439178909U, 853 },   { 12405201291620119593U, 880 },
13720     { 9242595204427927429U,  907 },   { 13772540099066387757U, 933 }, { 10261342003245940623U, 960 },   { 15290591125556738113U, 986 },
13721     { 11392378155556871081U, 1013 },  { 16975966327722178521U, 1039 },
13722     { 12648080533535911531U, 1066 }};
13723 
13724 static dtoa_Fp dtoa_find_cachedpow10(int exp, int* k)
13725 {
13726   int approx, idx;
13727   const double one_log_ten = 0.30102999566398114;
13728 
13729   approx = -(exp + dtoa_npowers) * one_log_ten;
13730   idx = (approx - dtoa_firstpower) / dtoa_steppowers;
13731   while (true)
13732     {
13733       int current;
13734       current = exp + dtoa_powers_ten[idx].exp + 64;
13735       if (current < dtoa_expmin)
13736 	{
13737 	  idx++;
13738 	  continue;
13739         }
13740       if (current > dtoa_expmax)
13741 	{
13742 	  idx--;
13743 	  continue;
13744         }
13745       *k = (dtoa_firstpower + idx * dtoa_steppowers);
13746       return(dtoa_powers_ten[idx]);
13747     }
13748 }
13749 
13750 #define dtoa_fracmask  0x000FFFFFFFFFFFFFU
13751 #define dtoa_expmask   0x7FF0000000000000U
13752 #define dtoa_hiddenbit 0x0010000000000000U
13753 #define dtoa_signmask  0x8000000000000000U
13754 #define dtoa_expbias   (1023 + 52)
13755 #define dtoa_absv(n)   ((n) < 0 ? -(n) : (n))
13756 #define dtoa_minv(a, b) ((a) < (b) ? (a) : (b))
13757 
13758 static uint64_t dtoa_tens[] =
13759   { 10000000000000000000U, 1000000000000000000U, 100000000000000000U,
13760     10000000000000000U, 1000000000000000U, 100000000000000U,
13761     10000000000000U, 1000000000000U, 100000000000U,
13762     10000000000U, 1000000000U, 100000000U,
13763     10000000U, 1000000U, 100000U,
13764     10000U, 1000U, 100U,
13765     10U, 1U};
13766 
13767 static uint64_t dtoa_get_dbits(double d)
13768 {
13769   union {double dbl; uint64_t i;} dbl_bits = {d};
13770   return(dbl_bits.i);
13771 }
13772 
13773 static dtoa_Fp dtoa_build_fp(double d)
13774 {
13775   uint64_t bits;
13776   dtoa_Fp fp;
13777 
13778   bits = dtoa_get_dbits(d);
13779   fp.frac = bits & dtoa_fracmask;
13780   fp.exp = (bits & dtoa_expmask) >> 52;
13781   if (fp.exp)
13782     {
13783       fp.frac += dtoa_hiddenbit;
13784       fp.exp -= dtoa_expbias;
13785     }
13786   else fp.exp = -dtoa_expbias + 1;
13787   return(fp);
13788 }
13789 
13790 static void dtoa_normalize(dtoa_Fp* fp)
13791 {
13792   int shift;
13793   while ((fp->frac & dtoa_hiddenbit) == 0)
13794     {
13795       fp->frac <<= 1;
13796       fp->exp--;
13797     }
13798   shift = 64 - 52 - 1;
13799   fp->frac <<= shift;
13800   fp->exp -= shift;
13801 }
13802 
13803 static void dtoa_get_normalized_boundaries(dtoa_Fp* fp, dtoa_Fp* lower, dtoa_Fp* upper)
13804 {
13805   int u_shift, l_shift;
13806   upper->frac = (fp->frac << 1) + 1;
13807   upper->exp  = fp->exp - 1;
13808   while ((upper->frac & (dtoa_hiddenbit << 1)) == 0)
13809     {
13810       upper->frac <<= 1;
13811       upper->exp--;
13812     }
13813   u_shift = 64 - 52 - 2;
13814   upper->frac <<= u_shift;
13815   upper->exp = upper->exp - u_shift;
13816   l_shift = fp->frac == dtoa_hiddenbit ? 2 : 1;
13817   lower->frac = (fp->frac << l_shift) - 1;
13818   lower->exp = fp->exp - l_shift;
13819   lower->frac <<= lower->exp - upper->exp;
13820   lower->exp = upper->exp;
13821 }
13822 
13823 static dtoa_Fp dtoa_multiply(dtoa_Fp* a, dtoa_Fp* b)
13824 {
13825   dtoa_Fp fp;
13826   uint64_t ah_bl, al_bh, al_bl, ah_bh, tmp;
13827   const uint64_t lomask = 0x00000000FFFFFFFF;
13828 
13829   ah_bl = (a->frac >> 32)    * (b->frac & lomask);
13830   al_bh = (a->frac & lomask) * (b->frac >> 32);
13831   al_bl = (a->frac & lomask) * (b->frac & lomask);
13832   ah_bh = (a->frac >> 32)    * (b->frac >> 32);
13833   tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32);
13834   /* round up */
13835   tmp += 1U << 31;
13836   fp.frac = ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32);
13837   fp.exp = a->exp + b->exp + 64;
13838   return(fp);
13839 }
13840 
13841 static void dtoa_round_digit(char* digits, int ndigits, uint64_t delta, uint64_t rem, uint64_t kappa, uint64_t frac)
13842 {
13843   while ((rem < frac) && (delta - rem >= kappa) &&
13844 	 ((rem + kappa < frac) || (frac - rem > rem + kappa - frac)))
13845     {
13846       digits[ndigits - 1]--;
13847       rem += kappa;
13848     }
13849 }
13850 
13851 static int dtoa_generate_digits(dtoa_Fp* fp, dtoa_Fp* upper, dtoa_Fp* lower, char* digits, int* K)
13852 {
13853   uint64_t part1, part2, wfrac, delta;
13854   uint64_t *divp, *unit;
13855   int idx, kappa;
13856   dtoa_Fp one;
13857 
13858   wfrac = upper->frac - fp->frac;
13859   delta = upper->frac - lower->frac;
13860   one.frac = 1ULL << -upper->exp;
13861   one.exp  = upper->exp;
13862   part1 = upper->frac >> -one.exp;
13863   part2 = upper->frac & (one.frac - 1);
13864   idx = 0;
13865   kappa = 10;
13866 
13867   /* 1000000000 */
13868   for (divp = dtoa_tens + 10; kappa > 0; divp++)
13869     {
13870       uint64_t tmp, div;
13871       unsigned digit;
13872       div = *divp;
13873       digit = part1 / div;
13874       if (digit || idx)
13875 	digits[idx++] = digit + '0';
13876       part1 -= digit * div;
13877       kappa--;
13878       tmp = (part1 << -one.exp) + part2;
13879       if (tmp <= delta)
13880 	{
13881 	  *K += kappa;
13882 	  dtoa_round_digit(digits, idx, delta, tmp, div << -one.exp, wfrac);
13883 	  return(idx);
13884         }}
13885 
13886   /* 10 */
13887   unit = dtoa_tens + 18;
13888   while(true)
13889     {
13890       unsigned digit;
13891       part2 *= 10;
13892       delta *= 10;
13893       kappa--;
13894       digit = part2 >> -one.exp;
13895       if (digit || idx)
13896 	digits[idx++] = digit + '0';
13897       part2 &= one.frac - 1;
13898       if (part2 < delta)
13899 	{
13900 	  *K += kappa;
13901 	  dtoa_round_digit(digits, idx, delta, part2, one.frac, wfrac * *unit);
13902 	  return(idx);
13903 	}
13904       unit--;
13905     }
13906 }
13907 
13908 static int dtoa_grisu2(double d, char* digits, int* K)
13909 {
13910   int k;
13911   dtoa_Fp cp, w, lower, upper;
13912   w = dtoa_build_fp(d);
13913   dtoa_get_normalized_boundaries(&w, &lower, &upper);
13914   dtoa_normalize(&w);
13915   cp = dtoa_find_cachedpow10(upper.exp, &k);
13916   w = dtoa_multiply(&w, &cp);
13917   upper = dtoa_multiply(&upper, &cp);
13918   lower = dtoa_multiply(&lower, &cp);
13919   lower.frac++;
13920   upper.frac--;
13921   *K = -k;
13922   return(dtoa_generate_digits(&w, &upper, &lower, digits, K));
13923 }
13924 
13925 static int dtoa_emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
13926 {
13927   int exp, idx, cent;
13928   char sign;
13929   exp = dtoa_absv(K + ndigits - 1);
13930 
13931   /* write plain integer */
13932   if ((K >= 0) && (exp < (ndigits + 7)))
13933     {
13934       memcpy(dest, digits, ndigits);
13935       memset(dest + ndigits, '0', K);
13936       dest[ndigits + K] = '.';
13937       dest[ndigits + K + 1] = '0';
13938       return(ndigits + K + 2);
13939     }
13940 
13941   /* write decimal w/o scientific notation */
13942   if ((K < 0) && (K > -7 || exp < 4))
13943     {
13944       int offset;
13945       offset = ndigits - dtoa_absv(K);
13946       /* fp < 1.0 -> write leading zero */
13947       if (offset <= 0)
13948 	{
13949 	  offset = -offset;
13950 	  dest[0] = '0';
13951 	  dest[1] = '.';
13952 	  memset(dest + 2, '0', offset);
13953 	  memcpy(dest + offset + 2, digits, ndigits);
13954 	  return(ndigits + 2 + offset);
13955 	  /* fp > 1.0 */
13956 	}
13957       else
13958 	{
13959 	  memcpy(dest, digits, offset);
13960 	  dest[offset] = '.';
13961 	  memcpy(dest + offset + 1, digits + offset, ndigits - offset);
13962 	  return(ndigits + 1);
13963 	}}
13964 
13965   /* write decimal w/ scientific notation */
13966   ndigits = dtoa_minv(ndigits, 18 - neg);
13967   idx = 0;
13968   dest[idx++] = digits[0];
13969   if (ndigits > 1)
13970     {
13971       dest[idx++] = '.';
13972       memcpy(dest + idx, digits + 1, ndigits - 1);
13973       idx += ndigits - 1;
13974     }
13975   dest[idx++] = 'e';
13976   sign = K + ndigits - 1 < 0 ? '-' : '+';
13977   dest[idx++] = sign;
13978   cent = 0;
13979   if (exp > 99)
13980     {
13981       cent = exp / 100;
13982       dest[idx++] = cent + '0';
13983       exp -= cent * 100;
13984     }
13985   if (exp > 9)
13986     {
13987       int dec;
13988       dec = exp / 10;
13989       dest[idx++] = dec + '0';
13990       exp -= dec * 10;
13991     }
13992   else
13993     if (cent)
13994       dest[idx++] = '0';
13995 
13996   dest[idx++] = exp % 10 + '0';
13997   return(idx);
13998 }
13999 
14000 static int dtoa_filter_special(double fp, char* dest, bool neg)
14001 {
14002   uint64_t bits;
14003   bool nan;
14004   if (fp == 0.0)
14005     {
14006       dest[0] = '0'; dest[1] = '.'; dest[2] = '0';
14007       return(3);
14008     }
14009   bits = dtoa_get_dbits(fp);
14010   nan = (bits & dtoa_expmask) == dtoa_expmask;
14011   if (!nan) return(0);
14012 
14013   if (!neg)
14014     {
14015       dest[0] = '+';
14016       dest++;
14017     }
14018   if (bits & dtoa_fracmask)
14019     {
14020       dest[0] = 'n'; dest[1] = 'a'; dest[2] = 'n'; dest[3] = '.'; dest[4] = '0';
14021     }
14022   else
14023     {
14024       dest[0] = 'i'; dest[1] = 'n'; dest[2] = 'f'; dest[3] = '.'; dest[4] = '0';
14025     }
14026   return((neg) ? 5 : 6);
14027 }
14028 
14029 static inline int fpconv_dtoa(double d, char dest[24])
14030 {
14031   char digit[18];
14032   int str_len = 0, spec, K, ndigits;
14033   bool neg = false;
14034 
14035   if (dtoa_get_dbits(d) & dtoa_signmask)
14036     {
14037       dest[0] = '-';
14038       str_len++;
14039       neg = true;
14040     }
14041 
14042   spec = dtoa_filter_special(d, dest + str_len, neg);
14043   if (spec) return(str_len + spec);
14044   K = 0;
14045   ndigits = dtoa_grisu2(d, digit, &K);
14046   str_len += dtoa_emit_digits(digit, ndigits, dest + str_len, K, neg);
14047   return(str_len);
14048 }
14049 #endif
14050 
14051 
14052 /* -------------------------------- number->string -------------------------------- */
14053 static const char dignum[] = "0123456789abcdef";
14054 
14055 static size_t integer_to_string_any_base(char *p, s7_int n, int32_t radix)  /* called by number_to_string_with_radix */
14056 {
14057   s7_int i, len, end;
14058   bool sign;
14059   s7_int pown;
14060 
14061   if ((radix < 2) || (radix > 16))
14062     return(0);
14063 
14064   if (n == S7_INT64_MIN) /* can't negate this, so do it by hand */
14065     {
14066       static const char *mnfs[17] = {"","",
14067 	"-1000000000000000000000000000000000000000000000000000000000000000", "-2021110011022210012102010021220101220222",
14068 	"-20000000000000000000000000000000", "-1104332401304422434310311213", "-1540241003031030222122212",
14069 	"-22341010611245052052301", "-1000000000000000000000", "-67404283172107811828",	"-9223372036854775808",
14070 	"-1728002635214590698",	"-41a792678515120368", "-10b269549075433c38", "-4340724c6c71dc7a8", "-160e2ad3246366808", "-8000000000000000"};
14071 
14072       len = safe_strlen(mnfs[radix]);
14073       memcpy((void *)p, (void *)mnfs[radix], len);
14074       p[len] = '\0';
14075       return(len);
14076     }
14077 
14078   sign = (n < 0);
14079   if (sign) n = -n;
14080 
14081   /* the previous version that counted up to n, rather than dividing down below n, as here,
14082    *   could be confused by large ints on 64 bit machines
14083    */
14084   pown = n;
14085   for (i = 1; i < 100; i++)
14086     {
14087       if (pown < radix)
14088 	break;
14089       pown /= (s7_int)radix;
14090     }
14091   len = i - 1;
14092   if (sign) len++;
14093   end = 0;
14094   if (sign)
14095     {
14096       p[0] = '-';
14097       end++;
14098     }
14099   for (i = len; i >= end; i--)
14100     {
14101       p[i] = dignum[n % radix];
14102       n /= radix;
14103     }
14104   p[len + 1] = '\0';
14105   return(len + 1);
14106 }
14107 
14108 static char *integer_to_string(s7_scheme *sc, s7_int num, s7_int *nlen) /* do not free the returned string */
14109 {
14110   char *p, *op;
14111   bool sign;
14112 
14113   if (num == S7_INT64_MIN)
14114     {
14115       (*nlen) = 20;
14116       return((char *)"-9223372036854775808");
14117     }
14118   p = (char *)(sc->int_to_str1 + INT_TO_STR_SIZE - 1);
14119   op = p;
14120   *p-- = '\0';
14121 
14122   sign = (num < 0);
14123   if (sign) num = -num;  /* we need a positive index below */
14124   do {*p-- = "0123456789"[num % 10]; num /= 10;} while (num);
14125   if (sign)
14126     {
14127       *p = '-';
14128       (*nlen) = op - p;
14129       return(p);
14130     }
14131 
14132   (*nlen) = op - p - 1;
14133   return(++p);
14134 }
14135 
14136 static char *integer_to_string_no_length(s7_scheme *sc, s7_int num) /* do not free the returned string */
14137 {
14138   char *p;
14139   bool sign;
14140 
14141   if (num == S7_INT64_MIN)
14142     return((char *)"-9223372036854775808");
14143   p = (char *)(sc->int_to_str2 + INT_TO_STR_SIZE - 1);
14144   *p-- = '\0';
14145   sign = (num < 0);
14146   if (sign) num = -num;
14147   do {*p-- = "0123456789"[num % 10]; num /= 10;} while (num);
14148   if (sign)
14149     {
14150       *p = '-';
14151       return(p);
14152     }
14153   return(++p);
14154 }
14155 
14156 static inline char *floatify(char *str, s7_int *nlen)
14157 {
14158   if ((!strchr(str, '.')) && (!strchr(str, 'e'))) /* faster than (strcspn(str, ".e") >= (size_t)(*nlen)) */
14159     {
14160       s7_int len;
14161       len = *nlen;
14162       /* snprintf returns "nan" and "inf" but we (stupidly) want "+nan.0" and "+inf.0"; "-nan" and "-inf" will be handled by the normal case */
14163       if (len == 3)
14164 	{
14165 	  if (str[0] == 'n')
14166 	    {
14167 	      str[0] = '+'; str[1] = 'n'; str[2] = 'a'; str[3] = 'n';
14168 	      len = 4;
14169 	    }
14170 	  if (str[0] == 'i')
14171 	    {
14172 	      str[0] = '+'; str[1] = 'i'; str[2] = 'n'; str[3] = 'f';
14173 	      len = 4;
14174 	    }}
14175       str[len]='.';
14176       str[len + 1]='0';
14177       str[len + 2]='\0';
14178       (*nlen) = len + 2;
14179     }
14180   return(str);
14181 }
14182 
14183 static void insert_spaces(s7_scheme *sc, char *src, s7_int width, s7_int len)
14184 {
14185   s7_int spaces;
14186   if (width >= sc->num_to_str_size)
14187     {
14188       sc->num_to_str_size = width + 1;
14189       sc->num_to_str = (char *)Realloc(sc->num_to_str, sc->num_to_str_size);
14190     }
14191   spaces = width - len;
14192   sc->num_to_str[width] = '\0';
14193   memmove((void *)(sc->num_to_str + spaces), (void *)src, len);
14194   memset((void *)(sc->num_to_str), (int)' ', spaces);
14195 }
14196 
14197 static char *number_to_string_base_10(s7_scheme *sc, s7_pointer obj, s7_int width, s7_int precision, char float_choice, s7_int *nlen, use_write_t choice) /* don't free result */
14198 {
14199   /* called by number_to_string_with_radix g_number_to_string, number_to_string_p_p number_to_port format_number */
14200   /* the rest of s7 assumes nlen is set to the correct length
14201    *   a tricky case: (format #f "~f" 1e308) -- tries to print 308 digits! so 256 as default len is too small.
14202    *   but then even worse: (format #f "~F" 1e308+1e308i)!
14203    */
14204   s7_int len;
14205 
14206   len = ((width + precision) > 512) ? (512 + 2 * (width + precision)) : 1024;
14207   if (len > sc->num_to_str_size)
14208     {
14209       sc->num_to_str = (sc->num_to_str) ? (char *)Realloc(sc->num_to_str, len) : (char *)Malloc(len);
14210       sc->num_to_str_size = len;
14211     }
14212 
14213   /* bignums can't happen here */
14214   switch (type(obj))
14215     {
14216     case T_INTEGER:
14217       if (width == 0)
14218 	{
14219 	  if (has_number_name(obj))
14220 	    {
14221 	      (*nlen) = number_name_length(obj);
14222 	      return((char *)number_name(obj));
14223 	    }
14224 	  return(integer_to_string(sc, integer(obj), nlen));
14225 	}
14226       {
14227 	char *p;
14228 	p = integer_to_string(sc, integer(obj), &len);
14229 	if (width > len)
14230 	  {
14231 	    insert_spaces(sc, p, width, len);
14232 	    (*nlen) = width;
14233 	    return(sc->num_to_str);
14234 	  }
14235 	(*nlen) = len;
14236 	return(p);
14237       }
14238 
14239     case T_RATIO:
14240       len = catstrs_direct(sc->num_to_str, integer_to_string_no_length(sc, numerator(obj)), "/", pos_int_to_str_direct(sc, denominator(obj)), (const char *)NULL);
14241       if (width > len)
14242 	{
14243 	  insert_spaces(sc, sc->num_to_str, width, len);
14244 	  (*nlen) = width;
14245 	}
14246       else (*nlen) = len;
14247       return(sc->num_to_str);
14248 
14249     case T_REAL:
14250       if (width == 0)
14251 	{
14252 #if WITH_DTOA
14253 	  if ((float_choice == 'g') &&
14254 	      (precision == WRITE_REAL_PRECISION))
14255 	    {
14256 	      /* (number->string 0.0000001) is sensitive to (*s7* 'float-format-precision) and inconsistent: either 1e-7 or 0.0000001
14257 	       *    because fpconv_dtoa has some complicated decision about 'g' vs 'f' -- not sure if this is a bug.
14258 	       */
14259 	      len = fpconv_dtoa(real(obj), sc->num_to_str);
14260 	      sc->num_to_str[len] = '\0';
14261 	      (*nlen) = len;
14262 	      return(sc->num_to_str);
14263 	    }
14264 #endif
14265 	  len = snprintf(sc->num_to_str, sc->num_to_str_size - 4,
14266 			 (float_choice == 'g') ? "%.*g" : ((float_choice == 'f') ? "%.*f" : "%.*e"),
14267 			 (int32_t)precision, real(obj)); /* -4 for floatify */
14268 	}
14269       else len = snprintf(sc->num_to_str, sc->num_to_str_size - 4,
14270 			  (float_choice == 'g') ? "%*.*g" : ((float_choice == 'f') ? "%*.*f" : "%*.*e"),
14271 			  (int32_t)width, (int32_t)precision, real(obj)); /* -4 for floatify */
14272       (*nlen) = len;
14273       floatify(sc->num_to_str, nlen);
14274       return(sc->num_to_str);
14275 
14276     default:
14277       {
14278 	char *imag;
14279 
14280 	sc->num_to_str[0] = '\0';
14281  	real(sc->real_wrapper4) = imag_part(obj);
14282 	imag = copy_string(number_to_string_base_10(sc, sc->real_wrapper4, 0, precision, float_choice, &len, choice));
14283 
14284 	sc->num_to_str[0] = '\0';
14285  	real(sc->real_wrapper3) = real_part(obj);
14286 	number_to_string_base_10(sc, sc->real_wrapper3, 0, precision, float_choice, &len, choice);
14287 
14288 	sc->num_to_str[len] = '\0';
14289 	len = catstrs(sc->num_to_str, sc->num_to_str_size, ((imag[0] == '+') || (imag[0] == '-')) ? "" : "+", imag, "i", (char *)NULL);
14290 	free(imag);
14291 
14292 	if (width > len)  /* (format #f "~20g" 1+i) */
14293 	  {
14294 	    insert_spaces(sc, sc->num_to_str, width, len); /* this checks sc->num_to_str_size */
14295 	    (*nlen) = width;
14296 	  }
14297 	else (*nlen) = len;
14298       }
14299       break;
14300     }
14301   return(sc->num_to_str);
14302 }
14303 
14304 static block_t *number_to_string_with_radix(s7_scheme *sc, s7_pointer obj, int32_t radix, s7_int width, s7_int precision, char float_choice, s7_int *nlen)
14305 {
14306   /* called by s7_number_to_string (char*), g_number_to_string (strp), number_to_string_p_pp (strp), format_number (strp basically) */
14307   /* the rest of s7 assumes nlen is set to the correct length */
14308   block_t *b;
14309   char *p;
14310   s7_int len, str_len;
14311 
14312 #if WITH_GMP
14313   if (s7_is_bignum(obj))
14314     return(big_number_to_string_with_radix(sc, obj, radix, width, nlen, P_WRITE));
14315   /* this ignores precision because it's way too hard to get the mpfr string to look like
14316    *   C's output -- we either have to call mpfr_get_str twice (the first time just to
14317    *   find out what the exponent is and how long the string actually is), or we have
14318    *   to do messy string manipulations.  So (format #f "",3F" pi) ignores the "3" and
14319    *   prints the full string.  And don't even think about mpfr_snprintf!
14320    */
14321 #endif
14322 
14323   if (radix == 10)
14324     {
14325       p = number_to_string_base_10(sc, obj, width, precision, float_choice, nlen, P_WRITE);
14326       return(string_to_block(sc, p, *nlen));
14327     }
14328 
14329   switch (type(obj))
14330     {
14331     case T_INTEGER:
14332       {
14333 	size_t len1;
14334 	b = mallocate(sc, (128 + width));
14335 	p = (char *)block_data(b);
14336 	len1 = integer_to_string_any_base(p, integer(obj), radix);
14337 	if ((size_t)width > len1)
14338 	  {
14339 	    size_t start;
14340 	    start = width - len1;
14341 	    memmove((void *)(p + start), (void *)p, len1);
14342 	    memset((void *)p, (int)' ', start);
14343 	    p[width] = '\0';
14344 	    *nlen = width;
14345 	  }
14346 	else *nlen = len1;
14347 	return(b);
14348       }
14349 
14350     case T_RATIO:
14351       {
14352 	size_t len1, len2;
14353 	str_len = 256 + width;
14354 	b = mallocate(sc, str_len);
14355 	p = (char *)block_data(b);
14356 	len1 = integer_to_string_any_base(p, numerator(obj), radix);
14357 	p[len1] = '/';
14358 	len2 = integer_to_string_any_base((char *)(p + len1 + 1), denominator(obj), radix);
14359         len = len1 + 1 + len2;
14360         p[len] = '\0';
14361       }
14362       break;
14363 
14364     case T_REAL:
14365       {
14366 	int32_t i;
14367 	s7_int int_part;
14368 	s7_double x, frac_part, min_frac, base;
14369 	bool sign = false;
14370 	char n[128], d[256];
14371 
14372 	x = real(obj);
14373 
14374 	if (is_NaN(x))
14375 	  return(string_to_block(sc, "+nan.0", *nlen = 6));
14376 	if (is_inf(x))
14377 	  {
14378 	    if (x < 0.0)
14379 	      return(string_to_block(sc, "-inf.0", *nlen = 6));
14380 	    return(string_to_block(sc, "+inf.0", *nlen = 6));
14381 	  }
14382 
14383 	if (x < 0.0)
14384 	  {
14385 	    sign = true;
14386 	    x = -x;
14387 	  }
14388 
14389 	if (x > 1.0e18) /* i.e. close to or greater than most-positive-fixnum (9.22e18), so the code below is unlikely to work, (format #f "~X" 1e19) */
14390 	  {
14391 	    int32_t ep;
14392 	    block_t *b1;
14393 	    len = 0;
14394 	    ep = (int32_t)floor(log(x) / log((double)radix));
14395  	    real(sc->real_wrapper3) = x / pow((double)radix, (double)ep); /* divide it down to one digit, then the fractional part */
14396 	    b = number_to_string_with_radix(sc, sc->real_wrapper3, radix, width, precision, float_choice, &len);
14397 	    b1 = mallocate(sc, len + 8);
14398 	    p = (char *)block_data(b1);
14399 	    p[0] = '\0';
14400 	    (*nlen) = catstrs(p, len + 8, (sign) ? "-" : "", (char *)block_data(b), (radix == 16) ? "@" : "e", integer_to_string_no_length(sc, ep), (char *)NULL);
14401 	    liberate(sc, b);
14402 	    return(b1);
14403 	  }
14404 
14405 	int_part = (s7_int)floor(x);
14406 	frac_part = x - int_part;
14407 	integer_to_string_any_base(n, int_part, radix);
14408 	min_frac = dpow(radix, -precision);
14409 
14410 	/* doesn't this assume precision < 128/256 and that we can fit in 256 digits (1e308)? */
14411 	for (i = 0, base = radix; (i < precision) && (frac_part > min_frac); i++, base *= radix)
14412 	  {
14413 	    s7_int ipart;
14414 	    ipart = (s7_int)(frac_part * base);
14415 	    if (ipart >= radix)         /* rounding confusion */
14416 	      ipart = radix - 1;
14417 	    frac_part -= (ipart / base);
14418 	    d[i] = (ipart < 10) ? (char)('0' + ipart) : (char)('a' + ipart -  10);
14419 	  }
14420 	if (i == 0)
14421 	  d[i++] = '0';
14422 	d[i] = '\0';
14423 	b = mallocate(sc, 256);
14424         p = (char *)block_data(b);
14425 	p[0] = '\0';
14426 	len = catstrs(p, 256, (sign) ? "-" : "", n, ".", d, (char *)NULL);
14427 	str_len = 256;
14428       }
14429       break;
14430 
14431     default:
14432       {
14433 	block_t *n, *d;
14434 	char *dp;
14435  	real(sc->real_wrapper3) = real_part(obj);
14436 	n = number_to_string_with_radix(sc, sc->real_wrapper3, radix, 0, precision, float_choice, &len); /* include floatify */
14437  	real(sc->real_wrapper4) = imag_part(obj);
14438 	d = number_to_string_with_radix(sc, sc->real_wrapper4, radix, 0, precision, float_choice, &len);
14439 	dp = (char *)block_data(d);
14440 	b = mallocate(sc, 512);
14441 	p = (char *)block_data(b);
14442 	p[0] = '\0';
14443 	len = catstrs(p, 512, (char *)block_data(n), ((dp[0] == '+') || (dp[0] == '-')) ? "" : "+", dp, "i", (char *)NULL);
14444 	str_len = 512;
14445 	liberate(sc, n);
14446 	liberate(sc, d);
14447       }
14448       break;
14449     }
14450 
14451   if (width > len)
14452     {
14453       s7_int spaces;
14454       if (width >= str_len)
14455 	{
14456 	  str_len = width + 1;
14457 	  b = reallocate(sc, b, str_len);
14458 	  p = (char *)block_data(b);
14459 	}
14460       spaces = width - len;
14461       p[width] = '\0';
14462       memmove((void *)(p + spaces), (void *)p, len);
14463       memset((void *)p, (int)' ', spaces);
14464       (*nlen) = width;
14465     }
14466   else (*nlen) = len;
14467   return(b);
14468 }
14469 
14470 char *s7_number_to_string(s7_scheme *sc, s7_pointer obj, s7_int radix)
14471 {
14472   s7_int nlen = 0;
14473   block_t *b;
14474   char *str;
14475   b = number_to_string_with_radix(sc, obj, radix, 0, 20, 'g', &nlen);  /* (log top 10) so we get all the digits in base 10 (??) */
14476   str = copy_string_with_length((char *)block_data(b), nlen);
14477   liberate(sc, b);
14478   return(str);
14479 }
14480 
14481 static s7_pointer g_number_to_string(s7_scheme *sc, s7_pointer args)
14482 {
14483   #define H_number_to_string "(number->string num (radix 10)) converts the number num into a string."
14484   #define Q_number_to_string s7_make_signature(sc, 3, sc->is_string_symbol, sc->is_number_symbol, sc->is_integer_symbol)
14485 
14486   s7_int nlen = 0, radix; /* ignore cppcheck complaint about radix! */
14487   char *res;
14488   s7_pointer x;
14489 
14490   x = car(args);
14491   if (!s7_is_number(x))
14492     return(method_or_bust_with_type(sc, x, sc->number_to_string_symbol, args, a_number_string, 1));
14493 
14494   if (is_pair(cdr(args)))
14495     {
14496       s7_pointer y;
14497       y = cadr(args);
14498       if (s7_is_integer(y))
14499 	radix = s7_integer_checked(sc, y);
14500       else return(method_or_bust(sc, y, sc->number_to_string_symbol, args, T_INTEGER, 2));
14501       if ((radix < 2) || (radix > 16))
14502 	return(out_of_range(sc, sc->number_to_string_symbol, int_two, y, a_valid_radix_string));
14503 #if (WITH_GMP)
14504       if (!s7_is_bignum(x))
14505 #endif
14506 	{
14507 	  block_t *b;
14508 	  b = number_to_string_with_radix(sc, x, radix, 0, sc->float_format_precision, 'g', &nlen);
14509 	  return(block_to_string(sc, b, nlen));
14510 	}}
14511 #if WITH_GMP
14512   else radix = 10;
14513   if (s7_is_bignum(x))
14514     {
14515       block_t *b;
14516       b = big_number_to_string_with_radix(sc, x, radix, 0, &nlen, P_WRITE);
14517       return(block_to_string(sc, b, nlen));
14518     }
14519   res = number_to_string_base_10(sc, x, 0, sc->float_format_precision, 'g', &nlen, P_WRITE);
14520 #else
14521   if (is_t_integer(x))
14522     {
14523       if (has_number_name(x))
14524 	{
14525 	  nlen = number_name_length(x);
14526 	  res = (char *)number_name(x);
14527 	}
14528       else res = integer_to_string(sc, integer(x), &nlen);
14529     }
14530   else res = number_to_string_base_10(sc, x, 0, sc->float_format_precision, 'g', &nlen, P_WRITE);
14531 #endif
14532   return(inline_make_string_with_length(sc, res, nlen));
14533 }
14534 
14535 static s7_pointer number_to_string_p_p(s7_scheme *sc, s7_pointer p)
14536 {
14537 #if WITH_GMP
14538   return(g_number_to_string(sc, set_plist_1(sc, p)));
14539 #else
14540   s7_int nlen = 0;
14541   char *res;
14542   if (!is_number(p))
14543     return(wrong_type_argument_with_type(sc, sc->number_to_string_symbol, 1, p, a_number_string));
14544   res = number_to_string_base_10(sc, p, 0, sc->float_format_precision, 'g', &nlen, P_WRITE);
14545   return(inline_make_string_with_length(sc, res, nlen));
14546 #endif
14547 }
14548 
14549 static s7_pointer number_to_string_p_i(s7_scheme *sc, s7_int p)
14550 {
14551   s7_int nlen = 0;
14552   char *res;
14553   res = integer_to_string(sc, p, &nlen);
14554   return(inline_make_string_with_length(sc, res, nlen));
14555 }
14556 /* not number_to_string_p_d! */
14557 
14558 static s7_pointer number_to_string_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
14559 {
14560 #if WITH_GMP
14561   return(g_number_to_string(sc, set_plist_2(sc, p1, p2)));
14562 #else
14563   s7_int nlen = 0, radix;
14564   block_t *b;
14565 
14566   if (!is_number(p1))
14567     return(wrong_type_argument_with_type(sc, sc->number_to_string_symbol, 1, p1, a_number_string));
14568   if (!is_t_integer(p2))
14569     return(wrong_type_argument(sc, sc->number_to_string_symbol, 2, p2, T_INTEGER));
14570   radix = s7_integer_checked(sc, p2);
14571   if ((radix < 2) || (radix > 16))
14572     return(out_of_range(sc, sc->number_to_string_symbol, int_two, p2, a_valid_radix_string));
14573 
14574   b = number_to_string_with_radix(sc, p1, radix, 0, sc->float_format_precision, 'g', &nlen);
14575   return(block_to_string(sc, b, nlen));
14576 #endif
14577 }
14578 
14579 
14580 /* -------------------------------------------------------------------------------- */
14581 #define CTABLE_SIZE 256
14582 static bool *exponent_table, *slashify_table, *char_ok_in_a_name, *white_space, *number_table, *symbol_slashify_table;
14583 static int32_t *digits;
14584 
14585 static void init_ctables(void)
14586 {
14587   int32_t i;
14588 
14589   exponent_table = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
14590   slashify_table = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
14591   symbol_slashify_table = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
14592   char_ok_in_a_name = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
14593   white_space = (bool *)calloc(CTABLE_SIZE + 1, sizeof(bool));
14594   white_space++;      /* leave white_space[-1] false for white_space[EOF] */
14595   number_table = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
14596   digits = (int32_t *)calloc(CTABLE_SIZE, sizeof(int32_t));
14597 
14598   for (i = 0; i < CTABLE_SIZE; i++)
14599     {
14600       char_ok_in_a_name[i] = true;
14601       white_space[i] = false;
14602       digits[i] = 256;
14603       number_table[i] = false;
14604     }
14605 
14606   char_ok_in_a_name[0] = false;
14607   char_ok_in_a_name[(uint8_t)'('] = false;  /* cast for C++ */
14608   char_ok_in_a_name[(uint8_t)')'] = false;
14609   char_ok_in_a_name[(uint8_t)';'] = false;
14610   char_ok_in_a_name[(uint8_t)'\t'] = false;
14611   char_ok_in_a_name[(uint8_t)'\n'] = false;
14612   char_ok_in_a_name[(uint8_t)'\r'] = false;
14613   char_ok_in_a_name[(uint8_t)' '] = false;
14614   char_ok_in_a_name[(uint8_t)'"'] = false;
14615 
14616   white_space[(uint8_t)'\t'] = true;
14617   white_space[(uint8_t)'\n'] = true;
14618   white_space[(uint8_t)'\r'] = true;
14619   white_space[(uint8_t)'\f'] = true;
14620   white_space[(uint8_t)'\v'] = true;
14621   white_space[(uint8_t)' '] = true;
14622   white_space[(uint8_t)'\205'] = true; /* 133 */
14623   white_space[(uint8_t)'\240'] = true; /* 160 */
14624 
14625   /* surely only 'e' is needed... */
14626   exponent_table[(uint8_t)'e'] = true; exponent_table[(uint8_t)'E'] = true;
14627   exponent_table[(uint8_t)'@'] = true;
14628 #if WITH_EXTRA_EXPONENT_MARKERS
14629   exponent_table[(uint8_t)'s'] = true; exponent_table[(uint8_t)'S'] = true;
14630   exponent_table[(uint8_t)'f'] = true; exponent_table[(uint8_t)'F'] = true;
14631   exponent_table[(uint8_t)'d'] = true; exponent_table[(uint8_t)'D'] = true;
14632   exponent_table[(uint8_t)'l'] = true; exponent_table[(uint8_t)'L'] = true;
14633 #endif
14634 
14635   for (i = 0; i < 32; i++)
14636     slashify_table[i] = true;
14637   for (i = 127; i < 160; i++)
14638     slashify_table[i] = true;
14639   slashify_table[(uint8_t)'\\'] = true;
14640   slashify_table[(uint8_t)'"'] = true;
14641   slashify_table[(uint8_t)'\n'] = false;
14642 
14643   for (i = 0; i < CTABLE_SIZE; i++)
14644     symbol_slashify_table[i] = ((slashify_table[i]) || (!char_ok_in_a_name[i])); /* force use of (symbol ...) for cases like '(ab) as symbol */
14645 
14646   digits[(uint8_t)'0'] = 0; digits[(uint8_t)'1'] = 1; digits[(uint8_t)'2'] = 2; digits[(uint8_t)'3'] = 3; digits[(uint8_t)'4'] = 4;
14647   digits[(uint8_t)'5'] = 5; digits[(uint8_t)'6'] = 6; digits[(uint8_t)'7'] = 7; digits[(uint8_t)'8'] = 8; digits[(uint8_t)'9'] = 9;
14648   digits[(uint8_t)'a'] = 10; digits[(uint8_t)'A'] = 10;
14649   digits[(uint8_t)'b'] = 11; digits[(uint8_t)'B'] = 11;
14650   digits[(uint8_t)'c'] = 12; digits[(uint8_t)'C'] = 12;
14651   digits[(uint8_t)'d'] = 13; digits[(uint8_t)'D'] = 13;
14652   digits[(uint8_t)'e'] = 14; digits[(uint8_t)'E'] = 14;
14653   digits[(uint8_t)'f'] = 15; digits[(uint8_t)'F'] = 15;
14654 
14655   number_table[(uint8_t)'0'] = true; number_table[(uint8_t)'1'] = true; number_table[(uint8_t)'2'] = true; number_table[(uint8_t)'3'] = true;
14656   number_table[(uint8_t)'4'] = true; number_table[(uint8_t)'5'] = true; number_table[(uint8_t)'6'] = true; number_table[(uint8_t)'7'] = true;
14657   number_table[(uint8_t)'8'] = true; number_table[(uint8_t)'9'] = true; number_table[(uint8_t)'.'] = true;
14658   number_table[(uint8_t)'+'] = true;
14659   number_table[(uint8_t)'-'] = true;
14660   number_table[(uint8_t)'#'] = true;
14661 }
14662 
14663 #define is_white_space(C) white_space[C]
14664   /* this is much faster than C's isspace, and does not depend on the current locale.
14665    * if c == EOF (-1), it indexes into the empty (0) slot we preallocated below white_space
14666    */
14667 
14668 /* -------------------------------- *#readers* -------------------------------- */
14669 static s7_pointer check_sharp_readers(s7_scheme *sc, const char *name)
14670 {
14671   s7_pointer reader, value, args;
14672   bool need_loader_port;
14673   value = sc->F;
14674   args = sc->F;
14675 
14676   /* *#reader* is assumed to be an alist of (char . proc)
14677    *    where each proc takes one argument, the string from just beyond the "#" to the next delimiter.
14678    *    The procedure can call read-char to read ahead in the current-input-port.
14679    *    If it returns anything other than #f, that is the value of the sharp expression.
14680    *    Since #f means "nothing found", it is tricky to handle #F:
14681    *       (cons #\F (lambda (str) (and (string=? str "F") (list 'not #t)))) ; or ''#f used in lint.scm
14682    * This search happens after #|, #t, and #f (and #nD for multivectors?). #! has a fallback.  Added #_ later)
14683    */
14684 
14685   need_loader_port = is_loader_port(current_input_port(sc));
14686   if (need_loader_port)
14687     clear_loader_port(current_input_port(sc));
14688 
14689   /* normally read* can't read from current_input_port(sc) if it is in use by the loader, but here we are deliberately making that possible. */
14690   for (reader = slot_value(sc->sharp_readers); is_not_null(reader); reader = cdr(reader))
14691     if (name[0] == s7_character(caar(reader)))
14692       {
14693 	if (args == sc->F)
14694 	  args = set_plist_1(sc, s7_make_string_wrapper(sc, name)); /* was list_1(sc, make_string(sc, name)) 16-Nov-18 */
14695 	/* args is GC protected by s7_apply_function?? (placed on the stack) */
14696 	value = s7_apply_function(sc, cdar(reader), args); /* this is much less error-safe than s7_call */
14697 	if (value != sc->F)
14698 	  break;
14699       }
14700   if (need_loader_port)
14701     set_loader_port(current_input_port(sc));
14702   return(value);
14703 }
14704 
14705 static s7_pointer g_sharp_readers_set(s7_scheme *sc, s7_pointer args)
14706 {
14707   /* new value must be either () or a proper list of conses (char . func) */
14708   if (is_null(cadr(args))) return(cadr(args));
14709   if (is_pair(cadr(args)))
14710     {
14711       s7_pointer x;
14712       for (x = cadr(args); is_pair(x); x = cdr(x))
14713 	if ((!is_pair(car(x))) ||
14714 	    (!s7_is_character(caar(x))) ||
14715 	    (!s7_is_procedure(cdar(x))))
14716 	  return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't set *#readers* to ~S", 26), cadr(args))));
14717       if (is_null(x))
14718 	return(cadr(args));
14719     }
14720   return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't set *#readers* to ~S", 26), cadr(args))));
14721 }
14722 
14723 static s7_pointer make_undefined(s7_scheme *sc, const char* name)
14724 {
14725   s7_pointer p;
14726   char *newstr;
14727   s7_int len;
14728   new_cell(sc, p, T_UNDEFINED | T_IMMUTABLE);
14729   len = safe_strlen(name);
14730   newstr = (char *)Malloc(len + 2);
14731   newstr[0] = '#';
14732   if (len > 0)
14733     memcpy((void *)(newstr + 1), (void *)name, len);
14734   newstr[len + 1] = '\0';
14735   if (sc->undefined_constant_warnings)
14736     s7_warn(sc, len + 32, "%s is undefined\n", newstr);
14737   undefined_set_name_length(p, len + 1);
14738   undefined_name(p) = newstr;
14739   add_undefined(sc, p);
14740   return(p);
14741 }
14742 
14743 static int32_t inchar(s7_pointer pt)
14744 {
14745   int32_t c;
14746   if (is_file_port(pt))
14747     c = fgetc(port_file(pt)); /* not uint8_t! -- could be EOF */
14748   else
14749     {
14750       if (port_data_size(pt) <= port_position(pt))
14751 	return(EOF);
14752       c = (uint8_t)port_data(pt)[port_position(pt)++];
14753     }
14754 
14755   if (c == '\n')
14756     port_line_number(pt)++;
14757 
14758   return(c);
14759 }
14760 
14761 static void backchar(char c, s7_pointer pt)
14762 {
14763   if (c == '\n')
14764     port_line_number(pt)--;
14765 
14766   if (is_file_port(pt))
14767     ungetc(c, port_file(pt));
14768   else
14769     if (port_position(pt) > 0)
14770       port_position(pt)--;
14771 }
14772 
14773 static void resize_strbuf(s7_scheme *sc, s7_int needed_size)
14774 {
14775   s7_int i, old_size;
14776   old_size = sc->strbuf_size;
14777   while (sc->strbuf_size <= needed_size) sc->strbuf_size *= 2;
14778   sc->strbuf = (char *)Realloc(sc->strbuf, sc->strbuf_size);
14779   for (i = old_size; i < sc->strbuf_size; i++) sc->strbuf[i] = '\0';
14780 }
14781 
14782 static s7_pointer *chars;
14783 
14784 static s7_pointer unknown_sharp_constant(s7_scheme *sc, char *name, s7_pointer pt)
14785 {
14786   if (hook_has_functions(sc->read_error_hook))  /* check *read-error-hook* */
14787     {
14788       s7_pointer result;
14789       bool old_history_enabled;
14790       old_history_enabled = s7_set_history_enabled(sc, false);
14791       /* see sc->error_hook for a more robust way to handle this */
14792       result = s7_call(sc, sc->read_error_hook, set_plist_2(sc, sc->T, s7_make_string_wrapper(sc, name)));
14793       s7_set_history_enabled(sc, old_history_enabled);
14794       if (result != sc->unspecified)
14795 	return(result);
14796     }
14797 
14798   if (pt) /* #<"..."> which gets here as name="#<" */
14799     {
14800       s7_int len;
14801       len = safe_strlen(name);
14802       if ((name[len - 1] != '>') &&
14803 	  (is_input_port(pt)) &&
14804 	  (pt != sc->standard_input))
14805 	{
14806 	  if (s7_peek_char(sc, pt) != chars[(uint8_t)'"']) /* if not #<"...">, just return it */
14807 	    return(make_undefined(sc, name));
14808 
14809 	  if (is_string_port(pt)) /* probably unnecessary (see below) */
14810 	    {
14811 	      s7_int added_len, c;
14812 	      const char *pstart, *p;
14813 	      char *buf;
14814 	      s7_pointer res;
14815 	      c = inchar(pt);
14816 	      pstart = (const char *)(port_data(pt) + port_position(pt));
14817 	      p = strchr(pstart, (int)'"');
14818 	      if (!p)
14819 		{
14820 		  backchar(c, pt);
14821 		  return(make_undefined(sc, name));
14822 		}
14823 	      p++;
14824 	      while (char_ok_in_a_name[(uint8_t)(*p)]) {p++;}
14825 	      added_len = (s7_int)(p - pstart); /* p is one past '>' presumably */
14826 	      /* we can't use strbuf here -- it might be the source of the "name" argument! */
14827 	      buf = (char *)malloc(len + added_len + 2);
14828 	      memcpy((void *)buf, (void *)name, len);
14829 	      buf[len] = '"';            /* from inchar */
14830 	      memcpy((void *)(buf + len + 1), (void *)pstart, added_len);
14831 	      buf[len + added_len + 1] = 0;
14832 	      port_position(pt) += added_len;
14833 	      res = make_undefined(sc, (const char *)buf);
14834 	      free(buf);
14835 	      return(res);
14836 	    }}}
14837   return(make_undefined(sc, name));
14838 }
14839 
14840 static s7_pointer make_atom(s7_scheme *sc, char *q, int32_t radix, bool want_symbol, bool with_error);
14841 #define SYMBOL_OK true
14842 #define NO_SYMBOLS false
14843 
14844 static s7_pointer make_sharp_constant(s7_scheme *sc, char *name, bool with_error, s7_pointer pt, bool error_if_bad_number)
14845 {
14846   /* name is the stuff after the '#', return sc->nil if not a recognized #... entity */
14847 
14848   /* stupid r7rs special cases */
14849   if ((name[0] == 't') &&
14850       ((name[1] == '\0') || (c_strings_are_equal(name, "true"))))
14851     return(sc->T);
14852 
14853   if ((name[0] == 'f') &&
14854       ((name[1] == '\0') || (c_strings_are_equal(name, "false"))))
14855     return(sc->F);
14856 
14857   if (name[0] == '_')
14858     {
14859       /* this needs to be unsettable via *#readers*:
14860        *    (set! *#readers* (list (cons #\_ (lambda (str) (string->symbol (substring str 1))))))
14861        *    (let ((+ -)) (#_+ 1 2)): -1
14862        */
14863       s7_pointer sym;
14864       sym = make_symbol(sc, (char *)(name + 1));
14865       if ((!is_gensym(sym)) && (is_slot(initial_slot(sym))))
14866 	return(initial_value(sym));
14867       /* here we should not necessarily raise an error that *_... is undefined.  reader-cond, for example, needs to
14868        *    read undefined #_ vals that it will eventually discard.
14869        */
14870       return(make_undefined(sc, name));    /* (define x (with-input-from-string "(#_asdf 1 2)" read)) (type-of (car x)) -> undefined? */
14871     }
14872 
14873   if (is_not_null(slot_value(sc->sharp_readers)))
14874     {
14875       s7_pointer x;
14876       x = check_sharp_readers(sc, name);
14877       if (x != sc->F)
14878 	return(x);
14879     }
14880 
14881   if ((name[0] == '\0') || name[1] == '\0')
14882     return(unknown_sharp_constant(sc, name, pt)); /* pt here because #<"..."> comes here as "<" so name[1] is '\0'! */
14883 
14884   switch (name[0])
14885     {
14886       /* -------- #< ... > -------- */
14887     case '<':
14888       if (c_strings_are_equal(name, "<unspecified>"))
14889 	return(sc->unspecified);
14890 
14891       if (c_strings_are_equal(name, "<undefined>"))
14892 	return(sc->undefined);
14893 
14894       if (c_strings_are_equal(name, "<eof>"))
14895 	return(eof_object);
14896 
14897       return(unknown_sharp_constant(sc, name, pt));
14898 
14899       /* -------- #o #x #b -------- */
14900     case 'o':   /* #o (octal) */
14901     case 'x':   /* #x (hex) */
14902     case 'b':   /* #b (binary) */
14903       {
14904 	s7_pointer res;
14905 	res = make_atom(sc, (char *)(name + 1), (name[0] == 'o') ? 8 : ((name[0] == 'x') ? 16 : 2), NO_SYMBOLS, with_error);
14906 	if ((error_if_bad_number) && (res == sc->F)) /* #b32 etc but not if called from string->number */
14907 	  {
14908 	    char buf[256];
14909 	    size_t len;
14910 	    len = snprintf(buf, 256, "#%s is not a number", name);
14911 	    s7_error(sc, sc->read_error_symbol, set_elist_1(sc, s7_make_string_with_length(sc, buf, len))); /* can't use wrap_string here */
14912 	  }
14913 	return(res);
14914       }
14915 
14916       /* -------- #\... -------- */
14917     case '\\':
14918       if (name[2] == 0)                             /* the most common case: #\a */
14919 	return(chars[(uint8_t)(name[1])]);
14920       /* not uint32_t here!  (uint32_t)255 (as a char) returns -1!! */
14921       switch (name[1])
14922 	{
14923 	case 'n':
14924 	  if ((c_strings_are_equal(name + 1, "null")) ||
14925 	      (c_strings_are_equal(name + 1, "nul")))
14926 	    return(chars[0]);
14927 
14928 	  if (c_strings_are_equal(name + 1, "newline"))
14929 	    return(chars[(uint8_t)'\n']);
14930 	  break;
14931 
14932 	case 's': if (c_strings_are_equal(name + 1, "space"))     return(chars[(uint8_t)' ']);  break;
14933 	case 'r': if (c_strings_are_equal(name + 1, "return"))    return(chars[(uint8_t)'\r']); break;
14934 	case 'l': if (c_strings_are_equal(name + 1, "linefeed"))  return(chars[(uint8_t)'\n']); break;
14935 	case 't': if (c_strings_are_equal(name + 1, "tab"))       return(chars[(uint8_t)'\t']); break;
14936 	case 'a': if (c_strings_are_equal(name + 1, "alarm"))     return(chars[7]);             break;
14937 	case 'b': if (c_strings_are_equal(name + 1, "backspace")) return(chars[8]);             break;
14938 	case 'e': if (c_strings_are_equal(name + 1, "escape"))    return(chars[0x1b]);          break;
14939 	case 'd': if (c_strings_are_equal(name + 1, "delete"))    return(chars[0x7f]);          break;
14940 
14941 	case 'x':
14942 	  /* #\x is just x, but apparently #\x<num> is int->char? #\x65 -> #\e, and #\xcebb is lambda? */
14943 	  {
14944 	    /* sscanf here misses errors like #\x1.4, but make_atom misses #\x6/3,
14945 	     *   #\x#b0, #\x#e0.0, #\x-0, #\x#e0e100 etc, so we have to do it at an even lower level.
14946 	     * another problem: #\xbdca2cbec overflows so lval is -593310740 -> segfault unless caught
14947 	     */
14948 	    bool happy = true;
14949 	    char *tmp;
14950 	    int32_t lval = 0;
14951 
14952 	    tmp = (char *)(name + 2);
14953 	    while ((*tmp) && (happy) && (lval >= 0) && (lval < 256))
14954 	      {
14955 		int32_t dig;
14956 		dig = digits[(int32_t)(*tmp++)];
14957 		if (dig < 16)
14958 		  lval = dig + (lval * 16);
14959 		else happy = false;
14960 	      }
14961 	    if ((happy) &&
14962 		(lval < 256) &&
14963 		(lval >= 0))
14964 	      return(chars[lval]);
14965 	  }
14966 	  break;
14967 	}}
14968   return(unknown_sharp_constant(sc, name, NULL));
14969 }
14970 
14971 static s7_int string_to_integer(const char *str, int32_t radix, bool *overflow)
14972 {
14973   bool negative = false;
14974   s7_int lval = 0;
14975   int32_t dig;
14976   char *tmp = (char *)str;
14977 #if WITH_GMP
14978   char *tmp1;
14979 #endif
14980 
14981   if (str[0] == '+')
14982     tmp++;
14983   else
14984     if (str[0] == '-')
14985       {
14986 	negative = true;
14987 	tmp++;
14988       }
14989   while (*tmp == '0') {tmp++;};
14990 #if WITH_GMP
14991   tmp1 = tmp;
14992 #endif
14993 
14994  if (radix == 10)
14995     {
14996       while (true)
14997 	{
14998 	  dig = digits[(uint8_t)(*tmp++)];
14999 	  if (dig > 9) break;
15000 #if HAVE_OVERFLOW_CHECKS
15001 	  if ((multiply_overflow(lval, (s7_int)10, &lval)) ||
15002 	      (add_overflow(lval, (s7_int)dig, &lval)))
15003 	    {
15004 	      if ((radix == 10) &&
15005 		  (strncmp(str, "-9223372036854775808", 20) == 0) &&
15006 		  (digits[(uint8_t)(*tmp++)] > 9)) /* i.e. next thing is not a digit -- "/" for example */
15007 		return(S7_INT64_MIN);
15008 	      *overflow = true;
15009 	      return((negative) ? S7_INT64_MIN : S7_INT64_MAX);
15010 	      break;
15011 	    }
15012 #else
15013 	  lval = dig + (lval * 10);
15014 	  dig = digits[(uint8_t)(*tmp++)];
15015 	  if (dig > 9) break;
15016 	  lval = dig + (lval * 10);
15017 #endif
15018 	}}
15019   else
15020     {
15021       while (true)
15022 	{
15023 	  dig = digits[(uint8_t)(*tmp++)];
15024 	  if (dig >= radix) break;
15025 #if HAVE_OVERFLOW_CHECKS && (!WITH_GMP)
15026 	  {
15027 	    s7_int oval = 0;
15028 	    if (multiply_overflow(lval, (s7_int)radix, &oval))
15029 	      {
15030 		/* maybe a bad idea!  #xffffffffffffffff -> -1??? this is needed for 64-bit number hacks (see s7test.scm bit-reverse) */
15031 		if ((radix == 16) &&
15032 		    (digits[(uint8_t)(*tmp)] >= radix))
15033 		  {
15034 		    lval -= 576460752303423488LL; /* turn off sign bit */
15035 		    lval *= radix;
15036 		    lval += dig;
15037 		    lval -= 9223372036854775807LL;
15038 		    return(lval - 1);
15039 		  }
15040 		lval = oval; /* old case */
15041 		if ((lval == S7_INT64_MIN)  && (digits[(uint8_t)(*tmp++)] > 9))
15042 		  return(lval);
15043 		*overflow = true;
15044 		break;
15045 	      }
15046 	    else lval = oval;
15047 	    if (add_overflow(lval, (s7_int)dig, &lval))
15048 	      {
15049 		if (lval == S7_INT64_MIN) return(lval);
15050 		*overflow = true;
15051 		break;
15052 	      }}
15053 #else
15054 	  lval = dig + (lval * radix);
15055 	  dig = digits[(uint8_t)(*tmp++)];
15056 	  if (dig >= radix) break;
15057 	  lval = dig + (lval * radix);
15058 #endif
15059 	}}
15060 
15061 #if WITH_GMP
15062  if (!(*overflow))
15063    (*overflow) = ((lval > S7_INT32_MAX) ||
15064 		  ((tmp - tmp1) > s7_int_digits_by_radix[radix]));
15065   /* this tells the string->number readers to create a bignum.  We need to be very conservative here to catch contexts such as (/ 1/524288 19073486328125) */
15066 #endif
15067 
15068   return((negative) ? -lval : lval);
15069 }
15070 
15071 /*  9223372036854775807                9223372036854775807
15072  * -9223372036854775808               -9223372036854775808
15073  * 0000000000000000000000000001.0     1.0
15074  * 1.0000000000000000000000000000     1.0
15075  * 1000000000000000000000000000.0e-40 1.0e-12
15076  * 0.0000000000000000000000000001e40  1.0e12
15077  * 1.0e00000000000000000001           10.0
15078  */
15079 
15080 #if WITH_GMP
15081 static s7_double string_to_double_with_radix(const char *ur_str, int32_t radix, bool *overflow)
15082 #else
15083 #define string_to_double_with_radix(Str, Rad, Over) string_to_double_with_radix_1(Str, Rad)
15084 static s7_double string_to_double_with_radix_1(const char *ur_str, int32_t radix)
15085 #endif
15086 {
15087   /* strtod follows LANG which is not what we want (only "." is decimal point in Scheme).
15088    *   To overcome LANG in strtod would require screwing around with setlocale which never works.
15089    *   So we use our own code -- according to valgrind, this function is much faster than strtod.
15090    * comma as decimal point causes ambiguities: `(+ ,1 2) etc
15091    */
15092 
15093   int32_t i, sign = 1, frac_len, int_len, dig, max_len, exponent = 0;
15094   int64_t int_part = 0, frac_part = 0;
15095   char *str;
15096   char *ipart, *fpart;
15097   s7_double dval = 0.0;
15098 
15099   /* there's an ambiguity in number notation here if we allow "1e1" or "1.e1" in base 16 (or 15) -- is e a digit or an exponent marker?
15100    *   but 1e+1, for example disambiguates it -- kind of messy! -- the scheme spec says "e" can only occur in base 10.
15101    * '@' can now be used as the exponent marker (26-Mar-12).
15102    * Another slight ambiguity: 1+1/2i is parsed as 1 + 0.5i, not 1+1/(2i), or (1+1)/(2i) or (1+1/2)i etc
15103    */
15104 
15105   max_len = s7_int_digits_by_radix[radix];
15106   str = (char *)ur_str;
15107 
15108   if (*str == '+')
15109     str++;
15110   else
15111     if (*str == '-')
15112       {
15113 	str++;
15114 	sign = -1;
15115       }
15116   while (*str == '0') {str++;};
15117 
15118   ipart = str;
15119   while (digits[(int32_t)(*str)] < radix) str++;
15120   int_len = str - ipart;
15121 
15122   if (*str == '.') str++;
15123   fpart = str;
15124   while (digits[(int32_t)(*str)] < radix) str++;
15125   frac_len = str - fpart;
15126 
15127   if ((*str) && (exponent_table[(uint8_t)(*str)]))
15128     {
15129       int32_t exp_negative = false;
15130       str++;
15131       if (*str == '+')
15132 	str++;
15133       else
15134 	if (*str == '-')
15135 	  {
15136 	    str++;
15137 	    exp_negative = true;
15138 	  }
15139       while ((dig = digits[(int32_t)(*str++)]) < 10) /* exponent itself is always base 10 */
15140 	{
15141 #if HAVE_OVERFLOW_CHECKS
15142 	  if ((int32_multiply_overflow(exponent, 10, &exponent)) ||
15143 	      (int32_add_overflow(exponent, dig, &exponent)))
15144 	    {
15145 	      exponent = 1000000; /* see below */
15146 	      break;
15147 	    }
15148 #else
15149 	  exponent = dig + (exponent * 10);
15150 #endif
15151 	}
15152 #if (!defined(__GNUC__)) || ((__GNUC__ < 5) && (!defined(__clang__)))
15153       if (exponent < 0)         /* we overflowed, so make sure we notice it below (need to check for 0.0e... first) (Brian Damgaard) */
15154 	exponent = 1000000;     /*   see below for examples -- this number needs to be very big but not too big for add */
15155 #endif
15156       if (exp_negative)
15157 	exponent = -exponent;
15158 
15159       /*           2e12341234123123123123213123123123 -> 0.0
15160        * but exp len is not the decider: 2e00000000000000000000000000000000000000001 -> 20.0
15161        * first zero: 2e123412341231231231231
15162        * then:     2e12341234123123123123123123 -> inf
15163        * then:     2e123412341231231231231231231231231231 -> 0.0
15164        *           2e-123412341231231231231 -> inf
15165        * but:      0e123412341231231231231231231231231231
15166        */
15167     }
15168 
15169 #if WITH_GMP
15170   /* 9007199254740995.0 */
15171   if (int_len + frac_len >= max_len)
15172     {
15173       (*overflow) = true;
15174       return(0.0);
15175     }
15176 #endif
15177 
15178   str = ipart;
15179   if ((int_len + exponent) > max_len)
15180     {
15181       /*  12341234.56789e12                   12341234567889999872.0              1.234123456789e+19
15182        * -1234567890123456789.0              -1234567890123456768.0              -1.2345678901235e+18
15183        *  12345678901234567890.0              12345678901234567168.0              1.2345678901235e+19
15184        *  123.456e30                          123456000000000012741097792995328.0 1.23456e+32
15185        *  12345678901234567890.0e12           12345678901234569054409354903552.0  1.2345678901235e+31
15186        *  1.234567890123456789012e30          1234567890123456849145940148224.0   1.2345678901235e+30
15187        *  1e20                                100000000000000000000.0             1e+20
15188        *  1234567890123456789.0               1234567890123456768.0               1.2345678901235e+18
15189        *  123.456e16                          1234560000000000000.0               1.23456e+18
15190        *  98765432101234567890987654321.0e-5  987654321012345728401408.0          9.8765432101235e+23
15191        *  98765432101234567890987654321.0e-10 9876543210123456512.0               9.8765432101235e+18
15192        *  0.00000000000000001234e20           1234.0
15193        *  0.000000000000000000000000001234e30 1234.0
15194        *  0.0000000000000000000000000000000000001234e40 1234.0
15195        *  0.000000000012345678909876543210e15 12345.678909877
15196        *  0e1000                              0.0
15197        */
15198 
15199       for (i = 0; i < max_len; i++)
15200 	{
15201 	  dig = digits[(int32_t)(*str++)];
15202 	  if (dig < radix)
15203 	    int_part = dig + (int_part * radix);
15204 	  else break;
15205 	}
15206 
15207       /* if the exponent is huge, check for 0 int_part and frac_part before complaining (0e1000 or 0.0e1000)
15208        */
15209       if ((int_part == 0) &&
15210 	  (exponent > max_len))
15211 	{
15212 	  /* if frac_part is also 0, return 0.0 */
15213 	  if (frac_len == 0)
15214 	    return(0.0);
15215 
15216 	  str = fpart;
15217 	  while ((dig = digits[(int32_t)(*str++)]) < radix)
15218 	    frac_part = dig + (frac_part * radix);
15219 	  if (frac_part == 0)
15220 	    return(0.0);
15221 
15222 #if WITH_GMP
15223 	  (*overflow) = true;
15224 #endif
15225 	}
15226 
15227 #if WITH_GMP
15228       (*overflow) = ((int_part > 0) || (exponent > 20));    /* .1e310 is a tricky case */
15229 #endif
15230 
15231       if (int_part != 0) /* 0.<310 zeros here>1e310 for example --
15232 			  *   pow (via dpow) thinks it has to be too big, returns Nan,
15233 			  *   then Nan * 0 -> Nan and the NaN propagates
15234 			  */
15235 	{
15236 	  if (int_len <= max_len)
15237 	    dval = int_part * dpow(radix, exponent);
15238 	  else dval = int_part * dpow(radix, exponent + int_len - max_len);
15239 	}
15240       else dval = 0.0;
15241 
15242       /* shift by exponent, but if int_len > max_len then we assumed (see below) int_len - max_len 0's on the left */
15243       /*   using int_to_int or table lookups here instead of pow did not make any difference in speed */
15244 
15245       if (int_len < max_len)
15246 	{
15247 	  int32_t k;
15248 	  str = fpart;
15249 
15250 	  for (k = 0; (frac_len > 0) && (k < exponent); k += max_len)
15251 	    {
15252 	      int32_t flen;
15253 	      flen = (frac_len > max_len) ? max_len : frac_len; /* ? */
15254 	      frac_len -= max_len;
15255 
15256 	      frac_part = 0;
15257 	      for (i = 0; i < flen; i++)
15258 		frac_part = digits[(int32_t)(*str++)] + (frac_part * radix);
15259 
15260 	      if (frac_part != 0)                                /* same pow->NaN problem as above can occur here */
15261 		dval += frac_part * dpow(radix, exponent - flen - k);
15262 	    }}
15263       else
15264 	{
15265 	  /* some of the fraction is in the integer part before the negative exponent shifts it over */
15266 	  if (int_len > max_len)
15267 	    {
15268 	      int32_t ilen;
15269 	      /* str should be at the last digit we read */
15270 	      ilen = int_len - max_len;                          /* we read these above */
15271 	      if (ilen > max_len)
15272 		ilen = max_len;
15273 
15274 	      for (i = 0; i < ilen; i++)
15275 		frac_part = digits[(int32_t)(*str++)] + (frac_part * radix);
15276 
15277 	      dval += frac_part * dpow(radix, exponent - ilen);
15278 	    }}
15279       return(sign * dval);
15280     }
15281 
15282   /* int_len + exponent <= max_len */
15283 
15284   if (int_len <= max_len)
15285     {
15286       int32_t int_exponent;
15287       /* a better algorithm (since the inaccuracies are in the radix^exponent portion):
15288        *   strip off leading zeros and possible sign,
15289        *   strip off digits beyond max_len, then remove any trailing zeros.
15290        *     (maybe fiddle with the lowest order digit here for rounding, but I doubt it matters)
15291        *   read digits until end of number or max_len reached, ignoring the decimal point
15292        *   get exponent and use it and decimal point location to position the current result integer
15293        * this always combines the same integer and the same exponent no matter how the number is expressed.
15294        */
15295 
15296       int_exponent = exponent;
15297       if (int_len > 0)
15298 	{
15299 	  char *iend;
15300 	  iend = (char *)(str + int_len - 1);
15301 	  while ((*iend == '0') && (iend != str)) {iend--; int_exponent++;}
15302 
15303 	  while (str <= iend)
15304 	    int_part = digits[(int32_t)(*str++)] + (int_part * radix);
15305 	}
15306       dval = (int_exponent == 0) ? (s7_double)int_part : int_part * dpow(radix, int_exponent);
15307     }
15308   else
15309     {
15310       int32_t len, flen;
15311       int64_t frpart = 0;
15312 
15313       /* 98765432101234567890987654321.0e-20    987654321.012346
15314        * 98765432101234567890987654321.0e-29    0.98765432101235
15315        * 98765432101234567890987654321.0e-30    0.098765432101235
15316        * 98765432101234567890987654321.0e-28    9.8765432101235
15317        */
15318 
15319       len = int_len + exponent;
15320       for (i = 0; i < len; i++)
15321 	int_part = digits[(int32_t)(*str++)] + (int_part * radix);
15322 
15323       flen = -exponent;
15324       if (flen > max_len)
15325 	flen = max_len;
15326 
15327       for (i = 0; i < flen; i++)
15328 	frpart = digits[(int32_t)(*str++)] + (frpart * radix);
15329 
15330       if (len <= 0)
15331 	dval = int_part + frpart * dpow(radix, len - flen);
15332       else dval = int_part + frpart * dpow(radix, -flen);
15333     }
15334 
15335   if (frac_len > 0)
15336     {
15337       str = fpart;
15338       if (frac_len <= max_len)
15339 	{
15340 	  /* splitting out base 10 case saves very little here */
15341 	  /* this ignores trailing zeros, so that 0.3 equals 0.300 */
15342 	  char *fend;
15343 
15344 	  fend = (char *)(str + frac_len - 1);
15345 	  while ((*fend == '0') && (fend != str)) {fend--; frac_len--;} /* (= .6 0.6000) */
15346 
15347 	  if ((frac_len & 1) == 0)
15348 	    {
15349 	      while (str <= fend)
15350 		{
15351 		  frac_part = digits[(int32_t)(*str++)] + (frac_part * radix);
15352 		  frac_part = digits[(int32_t)(*str++)] + (frac_part * radix);
15353 		}}
15354 	  else
15355 	    while (str <= fend)
15356 	      frac_part = digits[(int32_t)(*str++)] + (frac_part * radix);
15357 
15358 	  dval += frac_part * dpow(radix, exponent - frac_len);
15359 
15360 	  /* 0.6:    frac:    6, exp: 0.10000000000000000555, val: 0.60000000000000008882
15361 	   * 0.60:   frac:   60, exp: 0.01000000000000000021, val: 0.59999999999999997780
15362 	   * 0.6000: frac: 6000, exp: 0.00010000000000000000, val: 0.59999999999999997780
15363 	   * (= 0.6 0.60): #f
15364 	   * (= #i3/5 0.6): #f
15365 	   * so (string->number (number->string num)) == num only if both num's are the same text (or you get lucky)
15366 	   * (= 0.6 6e-1): #t ; but not 60e-2
15367 	   * to fix the 0.60 case, we need to ignore trailing post-dot zeros.
15368 	   */
15369 	}
15370       else
15371 	{
15372 	  if (exponent <= 0)
15373 	    {
15374 	      for (i = 0; i < max_len; i++)
15375 		frac_part = digits[(int32_t)(*str++)] + (frac_part * radix);
15376 
15377 	      dval += frac_part * dpow(radix, exponent - max_len);
15378 	    }
15379 	  else
15380 	    {
15381 	      /* 1.0123456789876543210e1         10.12345678987654373771
15382 	       * 1.0123456789876543210e10        10123456789.87654304504394531250
15383 	       * 0.000000010000000000000000e10   100.0
15384 	       * 0.000000010000000000000000000000000000000000000e10 100.0
15385 	       * 0.000000012222222222222222222222222222222222222e10 122.22222222222222
15386 	       * 0.000000012222222222222222222222222222222222222e17 1222222222.222222
15387 	       */
15388 
15389 	      int_part = 0;
15390 	      for (i = 0; i < exponent; i++)
15391 		int_part = digits[(int32_t)(*str++)] + (int_part * radix);
15392 
15393 	      frac_len -= exponent;
15394 	      if (frac_len > max_len)
15395 		frac_len = max_len;
15396 
15397 	      for (i = 0; i < frac_len; i++)
15398 		frac_part = digits[(int32_t)(*str++)] + (frac_part * radix);
15399 
15400 	      dval += int_part + frac_part * dpow(radix, -frac_len);
15401 	    }}}
15402 #if WITH_GMP
15403   if ((int_part == 0) &&
15404       (frac_part == 0))
15405     return(0.0);
15406   (*overflow) = ((frac_len - exponent) > max_len);
15407 #endif
15408 
15409   return(sign * dval);
15410 }
15411 
15412 #if (!WITH_GMP)
15413 static s7_pointer make_undefined_bignum(s7_scheme *sc, char *name)
15414 {
15415   block_t *b;
15416   char *buf;
15417   s7_int len;
15418   s7_pointer res;
15419   len = safe_strlen(name) + 16;
15420   b = mallocate(sc, len);
15421   buf = (char *)block_data(b);
15422   snprintf(buf, len, "<bignum: %s>", name);
15423   res = make_undefined(sc, (const char *)buf); /* 123123123123123123123123123123 -> +inf.0 originally, but now #<bignum: 123123...> */
15424   liberate(sc, b);
15425   return(res);
15426 }
15427 #endif
15428 
15429 static s7_pointer nan1_or_bust(s7_scheme *sc, s7_double x, char *p, char *q, int32_t radix, bool want_symbol)
15430 {
15431   s7_int len;
15432   len = safe_strlen(p);
15433   if (p[len - 1] == 'i')        /* +nan.0[+/-]...i */
15434     {
15435       if (len == 6)            /* +nan.0+i */
15436 	return(make_complex_unchecked(sc, x, (p[4] == '+') ? 1.0 : -1.0));
15437       if ((len > 5) && (len < 1024)) /* make compiler happy */
15438 	{
15439 	  char *ip;
15440 	  s7_pointer imag;
15441 	  ip = copy_string_with_length((const char *)(p + 4), len - 5);
15442 	  imag = make_atom(sc, ip, radix, NO_SYMBOLS, WITHOUT_OVERFLOW_ERROR);
15443 	  free(ip);
15444 	  if (s7_is_real(imag))
15445 	    return(make_complex(sc, x, real_to_double(sc, imag, __func__))); /* +nan.0+2/3i etc */
15446 	}}
15447   return((want_symbol) ? make_symbol(sc, q) : sc->F);
15448 }
15449 
15450 static s7_pointer nan2_or_bust(s7_scheme *sc, s7_double x, char *q, int32_t radix, bool want_symbol)
15451 {
15452   s7_int len;
15453   len = safe_strlen(q);
15454   if ((len > 7) && (len < 1024)) /* make compiler happy */
15455     {
15456       char *ip;
15457       s7_pointer rl;
15458       ip = copy_string_with_length((const char *)q, len - 7);
15459       rl = make_atom(sc, ip, radix, NO_SYMBOLS, WITHOUT_OVERFLOW_ERROR);
15460       free(ip);
15461       if (s7_is_real(rl))
15462 	return(make_complex(sc, real_to_double(sc, rl, __func__), x));
15463     }
15464   return((want_symbol) ? make_symbol(sc, q) : sc->F);
15465 }
15466 
15467 static s7_pointer make_atom(s7_scheme *sc, char *q, int32_t radix, bool want_symbol, bool with_error)
15468 {
15469   /* make symbol or number from string */
15470   #define IS_DIGIT(Chr, Rad) (digits[(uint8_t)Chr] < Rad)
15471 
15472   char c, *p;
15473   bool has_dec_point1 = false;
15474 
15475   p = q;
15476   c = *p++;
15477 
15478   /* a number starts with + - . or digit, but so does 1+ for example */
15479 
15480   switch (c)
15481     {
15482     case '#':
15483       /* #<... here only from string->number, I think */
15484       return(make_sharp_constant(sc, p, with_error, NULL, false)); /* make_sharp_constant expects the '#' to be removed */
15485 
15486     case '+':
15487     case '-':
15488       c = *p++;
15489       if (c == '.')
15490 	{
15491 	  has_dec_point1 = true;
15492 	  c = *p++;
15493 	}
15494       if (!c)
15495 	return((want_symbol) ? make_symbol(sc, q) : sc->F);
15496       if (!IS_DIGIT(c, radix))
15497 	{
15498 	  if (has_dec_point1)
15499 	    return((want_symbol) ? make_symbol(sc, q) : sc->F);
15500 	  if (c == 'n')
15501 	    {
15502 	      if (local_strcmp(p, "an.0"))      /* +nan.0 */
15503 		return(real_NaN);
15504 	      if ((local_strncmp(p, "an.0", 4)) &&
15505 		  ((p[4] == '+') || (p[4] == '-')))
15506 		return(nan1_or_bust(sc, NAN, p, q, radix, want_symbol));
15507 	    }
15508 	  if (c == 'i')
15509 	    {
15510 	      if (local_strcmp(p, "nf.0"))  /* +inf.0 */
15511 		return((q[0] == '+') ? real_infinity : real_minus_infinity);
15512 	      if ((local_strncmp(p, "nf.0", 4)) &&
15513 		  ((p[4] == '+') || (p[4] == '-')))
15514 		return(nan1_or_bust(sc, (q[0] == '-') ? -INFINITY : INFINITY, p, q, radix, want_symbol));
15515 	    }
15516 	  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15517 	}
15518       break;
15519 
15520     case '.':
15521       has_dec_point1 = true;
15522       c = *p++;
15523 
15524       if ((!c) || (!IS_DIGIT(c, radix)))
15525 	return((want_symbol) ? make_symbol(sc, q) : sc->F);
15526       break;
15527 
15528     case 'n':
15529       return((want_symbol) ? make_symbol(sc, q) : sc->F);
15530 
15531     case 'i':
15532       return((want_symbol) ? make_symbol(sc, q) : sc->F);
15533 
15534     case '0':        /* these two are always digits */
15535     case '1':
15536       break;
15537 
15538     default:
15539       if (!IS_DIGIT(c, radix))
15540 	return((want_symbol) ? make_symbol(sc, q) : sc->F);
15541       break;
15542     }
15543 
15544   /* now it's possibly a number -- the first character(s) could be part of a number in the current radix */
15545   {
15546     char *slash1 = NULL, *slash2 = NULL, *plus = NULL, *ex1 = NULL, *ex2 = NULL;
15547     bool has_i = false, has_dec_point2 = false;
15548     int32_t has_plus_or_minus = 0, current_radix;
15549 #if (!WITH_GMP)
15550     bool overflow = false; /* for string_to_integer */
15551 #endif
15552     current_radix = radix;  /* current_radix is 10 for the exponent portions, but radix for all the rest */
15553 
15554     for ( ; (c = *p) != 0; ++p)
15555       {
15556 	/* what about embedded null? (string->number (string #\1 (integer->char 0) #\0))
15557 	 *   currently we stop and return 1, but Guile returns #f.
15558 	 *   this also means we can't use substring_uncopied if (string->number (substring...))
15559 	 */
15560 	if (!IS_DIGIT(c, current_radix))         /* moving this inside the switch statement was much slower */
15561 	  {
15562 	    current_radix = radix;
15563 
15564 	    switch (c)
15565 	      {
15566 		/* -------- decimal point -------- */
15567 	      case '.':
15568 		if ((!IS_DIGIT(p[1], current_radix)) &&
15569 		    (!IS_DIGIT(p[-1], current_radix)))
15570 		  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15571 
15572 		if (has_plus_or_minus == 0)
15573 		  {
15574 		    if ((has_dec_point1) || (slash1))
15575 		      return((want_symbol) ? make_symbol(sc, q) : sc->F);
15576 		    has_dec_point1 = true;
15577 		  }
15578 		else
15579 		  {
15580 		    if ((has_dec_point2) || (slash2))
15581 		      return((want_symbol) ? make_symbol(sc, q) : sc->F);
15582 		    has_dec_point2 = true;
15583 		  }
15584 		continue;
15585 
15586 		/* -------- exponent marker -------- */
15587 #if WITH_EXTRA_EXPONENT_MARKERS
15588 		/* 1st 3d-perspective 0.0f 128.0f 3d 1s -- in 2 million lines of public scheme code, not one actual use! */
15589 	      case 's': case 'S':
15590 	      case 'd': case 'D':
15591 	      case 'f': case 'F':
15592 	      case 'l': case 'L':
15593 #endif
15594 	      case 'e': case 'E':
15595 		if (current_radix > 10) /* see above */
15596 		  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15597 		/* fall through -- if '@' used, radices>10 are ok */
15598 
15599 	      case '@':
15600 		current_radix = 10;
15601 
15602 		if (((ex1) ||
15603 		     (slash1)) &&
15604 		    (has_plus_or_minus == 0)) /* ee */
15605 		  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15606 
15607 		if (((ex2) ||
15608 		     (slash2)) &&
15609 		    (has_plus_or_minus != 0)) /* 1+1.0ee */
15610 		  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15611 
15612 		if ((!IS_DIGIT(p[-1], radix)) && /* was current_radix but that's always 10! */
15613 		    (p[-1] != '.'))
15614 		  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15615 
15616 		if (has_plus_or_minus == 0)
15617 		  {
15618 		    ex1 = p;
15619 		    has_dec_point1 = true; /* decimal point illegal from now on */
15620 		  }
15621 		else
15622 		  {
15623 		    ex2 = p;
15624 		    has_dec_point2 = true;
15625 		  }
15626 		p++;
15627 		if ((*p == '-') || (*p == '+')) p++;
15628 		if (IS_DIGIT(*p, current_radix))
15629 		  continue;
15630 		break;
15631 
15632 		/* -------- internal + or - -------- */
15633 	      case '+':
15634 	      case '-':
15635 		if (has_plus_or_minus != 0) /* already have the separator */
15636 		  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15637 
15638 		if (c == '+') has_plus_or_minus = 1; else has_plus_or_minus = -1;
15639 		plus = (char *)(p + 1);
15640 		/* now check for nan/inf as imaginary part */
15641 
15642 		if ((plus[0] == 'n') &&
15643 		    (local_strcmp(plus, "nan.0i")))
15644 		  return(nan2_or_bust(sc, (c == '+') ? NAN : -NAN, q, radix, want_symbol));
15645 		if ((plus[0] == 'i') &&
15646 		    (local_strcmp(plus, "inf.0i")))
15647 		  return(nan2_or_bust(sc, (c == '+') ? INFINITY : -INFINITY, q, radix, want_symbol));
15648 		continue;
15649 
15650 		/* ratio marker */
15651 	      case '/':
15652 		if ((has_plus_or_minus == 0) &&
15653 		    ((ex1) ||
15654 		     (slash1) ||
15655 		     (has_dec_point1)))
15656 		  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15657 
15658 		if ((has_plus_or_minus != 0) &&
15659 		    ((ex2) ||
15660 		     (slash2) ||
15661 		     (has_dec_point2)))
15662 		  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15663 
15664 		if (has_plus_or_minus == 0)
15665 		  slash1 = (char *)(p + 1);
15666 		else slash2 = (char *)(p + 1);
15667 
15668 		if ((!IS_DIGIT(p[1], current_radix)) ||
15669 		    (!IS_DIGIT(p[-1], current_radix)))
15670 		  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15671 
15672 		continue;
15673 
15674 		/* -------- i for the imaginary part -------- */
15675 	      case 'i':
15676 		if ((has_plus_or_minus != 0) &&
15677 		    (!has_i))
15678 		  {
15679 		    has_i = true;
15680 		    continue;
15681 		  }
15682 		break;
15683 
15684 	      default:
15685 		break;
15686 	      }
15687 	    return((want_symbol) ? make_symbol(sc, q) : sc->F);
15688 	  }}
15689 
15690     if ((has_plus_or_minus != 0) &&        /* that is, we have an internal + or - */
15691 	(!has_i))                          /*   but no i for the imaginary part */
15692       return((want_symbol) ? make_symbol(sc, q) : sc->F);
15693 
15694     if (has_i)
15695       {
15696 #if (!WITH_GMP)
15697 	s7_double rl = 0.0, im = 0.0;
15698 #else
15699 	char e1 = 0, e2 = 0;
15700 #endif
15701 	s7_pointer result;
15702 	s7_int len;
15703 	char ql1, pl1;
15704 
15705 	len = safe_strlen(q);
15706 
15707 	if (q[len - 1] != 'i')
15708 	  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15709 
15710 	/* save original string */
15711 	ql1 = q[len - 1];
15712 	pl1 = (*(plus - 1));
15713 #if WITH_GMP
15714 	if (ex1) {e1 = *ex1; (*ex1) = '@';} /* for mpfr */
15715 	if (ex2) {e2 = *ex2; (*ex2) = '@';}
15716 #endif
15717 
15718 	/* look for cases like 1+i */
15719 	q[len - 1] = ((q[len - 2] == '+') || (q[len - 2] == '-')) ? '1' : '\0'; /* remove 'i' */
15720 
15721 	(*((char *)(plus - 1))) = '\0';
15722 
15723 #if (!WITH_GMP)
15724 	if ((has_dec_point1) ||
15725 	    (ex1))  /* (string->number "1100.1+0.11i" 2) -- need to split into 2 honest reals before passing to non-base-10 str->dbl */
15726 	  rl = string_to_double_with_radix(q, radix, ignored);
15727 	else /* no decimal point, no exponent, a ratio (1/2+i for example, but 1+2/3i is handled below) */
15728 	  {
15729 	    if (slash1)
15730 	      {
15731 		/* here the overflow could be innocuous if it's in the denominator and the numerator is 0: 0/100000000000000000000000000000000000000 */
15732 		s7_int num, den;
15733 		num = string_to_integer(q, radix, &overflow);
15734 		if (overflow) return(make_undefined_bignum(sc, q));
15735 		den = string_to_integer(slash1, radix, &overflow);
15736 		if (den == 0)
15737 		  rl = NAN;        /* real_part if complex */
15738 		else
15739 		  {
15740 		    if (num == 0)
15741 		      {
15742 			rl = 0.0;
15743 			overflow = false;
15744 		      }
15745 		    else
15746 		      {
15747 			if (overflow) return(make_undefined_bignum(sc, q)); /* denominator overflow */
15748 			rl = (long_double)num / (long_double)den; /* no gmp, so we do what we can */
15749 		      }}}
15750 	    else
15751 	      {
15752 		rl = (s7_double)string_to_integer(q, radix, &overflow);
15753 		if (overflow) return(make_undefined_bignum(sc, q));
15754 	      }}
15755 	if (rl == -0.0) rl = 0.0;
15756 
15757 	if ((has_dec_point2) ||
15758 	    (ex2))
15759 	  im = string_to_double_with_radix(plus, radix, ignored);
15760 	else
15761 	  {
15762 	    if (slash2) /* complex part I think */
15763 	      {
15764 		/* same as above: 0-0/100000000000000000000000000000000000000i */
15765 		s7_int num, den;
15766 		num = string_to_integer(plus, radix, &overflow);
15767 		if (overflow) return(make_undefined_bignum(sc, q));
15768 		den = string_to_integer(slash2, radix, &overflow);
15769 		if (den == 0)
15770 		  im = NAN;
15771 		else
15772 		  {
15773 		    if (num == 0)
15774 		      {
15775 			im = 0.0;
15776 			overflow = false;
15777 		      }
15778 		    else
15779 		      {
15780 			if (overflow) return(make_undefined_bignum(sc, q)); /* denominator overflow */
15781 			im = (long_double)num / (long_double)den;
15782 		      }}}
15783 	    else
15784 	      {
15785 		im = (s7_double)string_to_integer(plus, radix, &overflow);
15786 		if (overflow) return(make_undefined_bignum(sc, q));
15787 	      }}
15788 	if ((has_plus_or_minus == -1) &&
15789 	    (im != 0.0))
15790 	  im = -im;
15791 	result = s7_make_complex(sc, rl, im);
15792 #else
15793 	result = string_to_either_complex(sc, q, slash1, ex1, has_dec_point1, plus, slash2, ex2, has_dec_point2, radix, has_plus_or_minus);
15794 #endif
15795 
15796 	/* restore original string */
15797 	q[len - 1] = ql1;
15798 	(*((char *)(plus - 1))) = pl1;
15799 #if WITH_GMP
15800 	if (ex1) (*ex1) = e1;
15801 	if (ex2) (*ex2) = e2;
15802 #endif
15803 	return(result);
15804       }
15805 
15806     /* not complex */
15807     if ((has_dec_point1) ||
15808 	(ex1))
15809       {
15810 	s7_pointer result;
15811 
15812 	if (slash1)  /* not complex, so slash and "." is not a number */
15813 	  return((want_symbol) ? make_symbol(sc, q) : sc->F);
15814 
15815 #if (!WITH_GMP)
15816 	result = make_real(sc, string_to_double_with_radix(q, radix, ignored));
15817 #else
15818 	{
15819 	  char old_e = 0;
15820 	  if (ex1)
15821 	    {
15822 	      old_e = (*ex1);
15823 	      (*ex1) = '@';
15824 	    }
15825 	  result = string_to_either_real(sc, q, radix);
15826 	  if (ex1)
15827 	    (*ex1) = old_e;
15828 	}
15829 #endif
15830 	return(result);
15831       }
15832 
15833     /* rational */
15834     if (slash1)
15835 #if (!WITH_GMP)
15836       {
15837 	s7_int n, d;
15838 
15839 	n = string_to_integer(q, radix, &overflow);
15840 	if (overflow) return(make_undefined_bignum(sc, q));
15841 	d = string_to_integer(slash1, radix, &overflow);
15842 
15843 	if ((n == 0) && (d != 0))                        /* 0/100000000000000000000000000000000000000 */
15844 	  return(int_zero);
15845 	if (d == 0)
15846 	  return(real_NaN);
15847 	if (overflow) return(make_undefined_bignum(sc, q));
15848 	/* it would be neat to return 1 from 10000000000000000000000000000/10000000000000000000000000000
15849 	 *   but q is the entire number ('/' included) and slash1 is the stuff after the '/', and every
15850 	 *   big number comes through here, so there's no clean and safe way to check that q == slash1.
15851 	 */
15852 	return(s7_make_ratio(sc, n, d));
15853       }
15854 #else
15855     return(string_to_either_ratio(sc, q, slash1, radix));
15856 #endif
15857 
15858     /* integer */
15859 #if (!WITH_GMP)
15860     {
15861       s7_int x;
15862       x = string_to_integer(q, radix, &overflow);
15863       if (overflow) return(make_undefined_bignum(sc, q));
15864       return(make_integer(sc, x));
15865     }
15866 #else
15867     return(string_to_either_integer(sc, q, radix));
15868 #endif
15869   }
15870 }
15871 
15872 
15873 /* -------------------------------- string->number -------------------------------- */
15874 
15875 static s7_pointer string_to_number(s7_scheme *sc, char *str, int32_t radix)
15876 {
15877   s7_pointer x;
15878   x = make_atom(sc, str, radix, NO_SYMBOLS, WITHOUT_OVERFLOW_ERROR);
15879   return((s7_is_number(x)) ? x : sc->F);  /* only needed because str might start with '#' and not be a number (#t for example) */
15880 }
15881 
15882 static s7_pointer string_to_number_p_p(s7_scheme *sc, s7_pointer str1)
15883 {
15884   char *str;
15885   if (!is_string(str1))
15886     return(wrong_type_argument(sc, sc->string_to_number_symbol, 1, str1, T_STRING));
15887   str = (char *)string_value(str1);
15888   return(((!str) || (!(*str))) ? sc->F : string_to_number(sc, str, 10));
15889 }
15890 
15891 static s7_pointer string_to_number_p_pp(s7_scheme *sc, s7_pointer str1, s7_pointer radix1)
15892 {
15893   s7_int radix;
15894   char *str;
15895 
15896   if (!is_string(str1))
15897     return(wrong_type_argument(sc, sc->string_to_number_symbol, 1, str1, T_STRING));
15898 
15899   if (!is_t_integer(radix1))
15900     return(wrong_type_argument(sc, sc->string_to_number_symbol, 2, radix1, T_INTEGER));
15901   radix = s7_integer_checked(sc, radix1);
15902   if ((radix < 2) || (radix > 16))
15903     return(out_of_range(sc, sc->string_to_number_symbol, int_two, radix1, a_valid_radix_string));
15904 
15905   str = (char *)string_value(str1);
15906   if ((!str) || (!(*str)))
15907     return(sc->F);
15908 
15909   return(string_to_number(sc, str, radix));
15910 }
15911 
15912 static s7_pointer g_string_to_number_1(s7_scheme *sc, s7_pointer args, s7_pointer caller)
15913 {
15914   s7_int radix;
15915   char *str;
15916 
15917   if (!is_string(car(args)))
15918     return(method_or_bust(sc, car(args), caller, args, T_STRING, 1));
15919 
15920   if (is_pair(cdr(args)))
15921     {
15922       s7_pointer rad;
15923       rad = cadr(args);
15924       if (!s7_is_integer(rad))
15925 	return(method_or_bust(sc, rad, caller, args, T_INTEGER, 2));
15926       radix = s7_integer_checked(sc, rad);
15927       if ((radix < 2) || (radix > 16))
15928 	return(out_of_range(sc, caller, int_two, rad, a_valid_radix_string));
15929     }
15930   else radix = 10;
15931   str = (char *)string_value(car(args));
15932   if ((!str) || (!(*str)))
15933     return(sc->F);
15934 
15935   return(string_to_number(sc, str, radix));
15936 }
15937 
15938 static s7_pointer g_string_to_number(s7_scheme *sc, s7_pointer args)
15939 {
15940   #define H_string_to_number "(string->number str (radix 10)) converts str into a number. \
15941 If str does not represent a number, string->number returns #f.  If 'str' has an embedded radix, \
15942 the optional 'radix' argument is ignored: (string->number \"#x11\" 2) -> 17 not 3."
15943   #define Q_string_to_number s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->is_number_symbol, sc->not_symbol), sc->is_string_symbol, sc->is_integer_symbol)
15944 
15945   return(g_string_to_number_1(sc, args, sc->string_to_number_symbol));
15946 }
15947 
15948 
15949 /* -------------------------------- abs -------------------------------- */
15950 static inline s7_pointer abs_p_p(s7_scheme *sc, s7_pointer x)
15951 {
15952   switch (type(x))
15953     {
15954     case T_INTEGER:
15955       if (integer(x) < 0)
15956 	{
15957 #if WITH_GMP
15958 	  if (integer(x) == S7_INT64_MIN)
15959 	    {
15960 	      x = s7_int_to_big_integer(sc, integer(x));
15961 	      mpz_neg(big_integer(x), big_integer(x));
15962 	      return(x);
15963 	    }
15964 #else
15965 	  if (integer(x) == S7_INT64_MIN)
15966 	    return(simple_out_of_range(sc, sc->abs_symbol, set_elist_1(sc, x), result_is_too_large_string));
15967 #endif
15968 	  return(make_integer(sc, -integer(x)));
15969 	}
15970       return(x);
15971 
15972     case T_RATIO:
15973       if (numerator(x) < 0)
15974 	{
15975 #if WITH_GMP && (!POINTER_32)
15976 	  if (numerator(x) == S7_INT64_MIN)
15977 	    {
15978 	      s7_pointer p;
15979 	      mpz_set_si(sc->mpz_1, S7_INT64_MIN);
15980 	      mpz_neg(sc->mpz_1, sc->mpz_1);
15981 	      mpz_set_si(sc->mpz_2, denominator(x));
15982 	      new_cell(sc, p, T_BIG_RATIO);
15983 	      big_ratio_bgr(p) = alloc_bigrat(sc);
15984 	      add_big_ratio(sc, p);
15985 	      mpq_set_num(big_ratio(p), sc->mpz_1);
15986 	      mpq_set_den(big_ratio(p), sc->mpz_2);
15987 	      return(p);
15988 	    }
15989 #else
15990 	  if (numerator(x) == S7_INT64_MIN)
15991 	    return(s7_make_ratio(sc, S7_INT64_MAX, denominator(x)));
15992 #endif
15993 	  return(make_simple_ratio(sc, -numerator(x), denominator(x)));
15994 	}
15995       return(x);
15996 
15997     case T_REAL:
15998       if (is_NaN(real(x)))                  /* (abs -nan.0) -> +nan.0, not -nan.0 */
15999 	return(real_NaN);
16000       return((real(x) < 0.0) ? make_real(sc, -real(x)) : x);
16001 
16002 #if WITH_GMP
16003     case T_BIG_INTEGER:
16004       mpz_abs(sc->mpz_1, big_integer(x));
16005       return(mpz_to_integer(sc, sc->mpz_1));
16006 
16007     case T_BIG_RATIO:
16008       mpq_abs(sc->mpq_1, big_ratio(x));
16009       return(mpq_to_rational(sc, sc->mpq_1));
16010 
16011     case T_BIG_REAL:
16012       mpfr_abs(sc->mpfr_1, big_real(x), MPFR_RNDN);
16013       return(mpfr_to_big_real(sc, sc->mpfr_1));
16014 #endif
16015 
16016     default:
16017       return(method_or_bust_one_arg_p(sc, x, sc->abs_symbol, T_REAL));
16018     }
16019 }
16020 
16021 static s7_pointer g_abs(s7_scheme *sc, s7_pointer args)
16022 {
16023   #define H_abs "(abs x) returns the absolute value of the real number x"
16024   #define Q_abs s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_real_symbol)
16025   s7_pointer x;
16026   x = car(args);
16027   if (is_t_integer(x)) {if (integer(x) >= 0) return(x); if (integer(x) > S7_INT64_MIN) return(make_integer(sc, -integer(x)));}
16028   return(abs_p_p(sc, car(args)));
16029 }
16030 
16031 static s7_double abs_d_d(s7_double x) {return((x < 0.0) ? (-x) : x);}
16032 static s7_int abs_i_i(s7_int x) {return((x < 0) ? (-x) : x);}
16033 
16034 
16035 /* -------------------------------- magnitude -------------------------------- */
16036 
16037 static double my_hypot(double x, double y)
16038 {
16039   /* according to callgrind, this is much faster than libc's hypot */
16040   if (x == 0.0) return(fabs(y));
16041   if (y == 0.0) return(fabs(x));
16042   if (x == y) return(1.414213562373095 * fabs(x));
16043   if ((is_NaN(x)) || (is_NaN(y))) return(NAN);
16044   return(sqrt(x * x + y * y));
16045 }
16046 
16047 static s7_pointer magnitude_p_p(s7_scheme *sc, s7_pointer x)
16048 {
16049   if (is_t_complex(x))
16050     return(make_real(sc, my_hypot(imag_part(x), real_part(x))));
16051 
16052   switch (type(x))
16053     {
16054     case T_INTEGER:
16055       if (integer(x) == S7_INT64_MIN)
16056 	return(make_integer(sc, S7_INT64_MAX));
16057       /* (magnitude -9223372036854775808) -> -9223372036854775808
16058        *   same thing happens in abs, lcm and gcd: (gcd -9223372036854775808) -> -9223372036854775808
16059        */
16060       return((integer(x) < 0) ? make_integer(sc, -integer(x)) : x);
16061 
16062     case T_RATIO:
16063       return((numerator(x) < 0) ? make_simple_ratio(sc, -numerator(x), denominator(x)) : x);
16064 
16065     case T_REAL:
16066       if (is_NaN(real(x)))                 /* (magnitude -nan.0) -> +nan.0, not -nan.0 */
16067 	return(real_NaN);
16068       return((real(x) < 0.0) ? make_real(sc, -real(x)) : x);
16069 
16070 #if WITH_GMP
16071     case T_BIG_INTEGER:
16072     case T_BIG_RATIO:
16073     case T_BIG_REAL:
16074       return(abs_p_p(sc, x));
16075 
16076     case T_BIG_COMPLEX:
16077       mpc_abs(sc->mpfr_1, big_complex(x), MPFR_RNDN);
16078       return(mpfr_to_big_real(sc, sc->mpfr_1));
16079 #endif
16080 
16081     default:
16082       return(method_or_bust_with_type_one_arg_p(sc, x, sc->magnitude_symbol, a_number_string));
16083     }
16084 }
16085 
16086 static s7_pointer g_magnitude(s7_scheme *sc, s7_pointer args)
16087 {
16088   #define H_magnitude "(magnitude z) returns the magnitude of z"
16089   #define Q_magnitude s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
16090   return(magnitude_p_p(sc, car(args)));
16091 }
16092 
16093 
16094 /* -------------------------------- rationalize -------------------------------- */
16095 #if WITH_GMP
16096 
16097 typedef struct {
16098   mpfr_t error, ux, x0, x1;
16099   mpz_t i, i0, i1, n;
16100   mpz_t p0, q0, r, r1, p1, q1, old_p1, old_q1;
16101   mpfr_t val, e0, e1, e0p, e1p, old_e0, old_e1, old_e0p;
16102   mpq_t q;
16103 } rat_locals_t;
16104 
16105 static rat_locals_t *init_rat_locals_t(s7_scheme *sc)
16106 {
16107   rat_locals_t *r;
16108   r = (rat_locals_t *)malloc(sizeof(rat_locals_t));
16109   sc->ratloc = (void *)r;
16110   mpz_inits(r->i, r->i0, r->i1, r->n, r->p0, r->q0, r->r, r->r1, r->p1, r->q1, r->old_p1, r->old_q1, NULL);
16111   mpq_init(r->q);
16112   mpfr_inits2(sc->bignum_precision, r->error, r->ux, r->x0, r->x1, r->val, r->e0, r->e1, r->e0p, r->e1p, r->old_e0, r->old_e1, r->old_e0p, NULL);
16113   return(r);
16114 }
16115 
16116 static void free_rat_locals(s7_scheme *sc)
16117 {
16118   rat_locals_t *r;
16119   r = sc->ratloc;
16120   mpz_clears(r->i, r->i0, r->i1, r->n, r->p0, r->q0, r->r, r->r1, r->p1, r->q1, r->old_p1, r->old_q1, NULL);
16121   mpq_clear(r->q);
16122   mpfr_clears(r->error, r->ux, r->x0, r->x1, r->val, r->e0, r->e1, r->e0p, r->e1p, r->old_e0, r->old_e1, r->old_e0p, NULL);
16123   free(r);
16124 }
16125 
16126 static s7_pointer big_rationalize(s7_scheme *sc, s7_pointer args)
16127 {
16128   /* can return be non-rational? */
16129   /* currently (rationalize 1/0 1e18) -> 0
16130    * remember to pad with many trailing zeros:
16131    *    (rationalize 0.1 0)                -> 3602879701896397/36028797018963968
16132    *    (rationalize 0.1000000000000000 0) -> 1/10
16133    * perhaps gmp number reader used if gmp -- could this be the trailing zeros problem?  (why is the non-gmp case ok?)
16134    *         also the bignum function is faking it.
16135    *         (rationalize (real-part (bignum "0.1+i")) 0) -> 3602879701896397/36028797018963968
16136    * a confusing case:
16137    *   (rationalize 5925563891587147521650777143.74135805596e05) should be 148139097289678688041269428593533951399/250000
16138    * but that requires more than 128 bits of bignum-precision.
16139    */
16140 
16141   s7_pointer pp0;
16142   rat_locals_t *r;
16143 
16144   if (!sc->ratloc) r = init_rat_locals_t(sc); else r = (rat_locals_t *)sc->ratloc;
16145 
16146   pp0 = car(args);
16147   switch (type(pp0))
16148     {
16149     case T_INTEGER:
16150       mpfr_set_si(r->ux, integer(pp0), MPFR_RNDN);
16151       break;
16152     case T_RATIO:
16153       mpq_set_si(sc->mpq_1, numerator(pp0), denominator(pp0));
16154       mpfr_set_q(r->ux, sc->mpq_1, MPFR_RNDN);
16155       break;
16156     case T_REAL:
16157       if (is_NaN(real(pp0)))
16158 	return(out_of_range(sc, sc->rationalize_symbol, int_one, pp0, its_nan_string));
16159       if (is_inf(real(pp0)))
16160 	return(out_of_range(sc, sc->rationalize_symbol, int_one, pp0, its_infinite_string));
16161       mpfr_set_d(r->ux, real(pp0), MPFR_RNDN);
16162       break;
16163     case T_BIG_INTEGER:
16164       mpfr_set_z(r->ux, big_integer(pp0), MPFR_RNDN);
16165       break;
16166     case T_BIG_RATIO:
16167       mpfr_set_q(r->ux, big_ratio(pp0), MPFR_RNDN);
16168       break;
16169     case T_BIG_REAL:
16170       if (mpfr_nan_p(big_real(pp0)))
16171 	return(out_of_range(sc, sc->rationalize_symbol, int_one, pp0, its_nan_string));
16172       if (mpfr_inf_p(big_real(pp0)))
16173 	return(out_of_range(sc, sc->rationalize_symbol, int_one, pp0, its_infinite_string));
16174       mpfr_set(r->ux, big_real(pp0), MPFR_RNDN);
16175       break;
16176     case T_COMPLEX:
16177     case T_BIG_COMPLEX:
16178       return(wrong_type_argument(sc, sc->rationalize_symbol, 1, pp0, T_REAL));
16179     default:
16180       return(method_or_bust(sc, pp0, sc->rationalize_symbol, args, T_REAL, 1));
16181     }
16182 
16183   if (is_not_null(cdr(args)))
16184     {
16185       s7_pointer pp1 = NULL;
16186       pp1 = cadr(args);
16187 
16188       switch (type(pp1))
16189 	{
16190 	case T_INTEGER:
16191 	  mpfr_set_si(r->error, integer(pp1), MPFR_RNDN);
16192 	  break;
16193 	case T_RATIO:
16194 	  mpq_set_si(sc->mpq_1, numerator(pp1), denominator(pp1));
16195 	  mpfr_set_q(r->error, sc->mpq_1, MPFR_RNDN);
16196 	  break;
16197 	case T_REAL:
16198 	  if (is_NaN(real(pp1)))
16199 	    return(out_of_range(sc, sc->rationalize_symbol, int_two, pp1, its_nan_string));
16200 	  if (is_inf(real(pp1)))
16201 	    return(int_zero);
16202 	  mpfr_set_d(r->error, real(pp1), MPFR_RNDN);
16203 	  break;
16204 	case T_BIG_INTEGER:
16205 	  mpfr_set_z(r->error, big_integer(pp1), MPFR_RNDN);
16206 	  break;
16207 	case T_BIG_RATIO:
16208 	  mpfr_set_q(r->error, big_ratio(pp1), MPFR_RNDN);
16209 	  break;
16210 	case T_BIG_REAL:
16211 	  if (mpfr_nan_p(big_real(pp1)))
16212 	    return(out_of_range(sc, sc->rationalize_symbol, int_two, pp1, its_nan_string));
16213 	  if (mpfr_inf_p(big_real(pp1)))
16214 	    return(int_zero);
16215 	  mpfr_set(r->error, big_real(pp1), MPFR_RNDN);
16216 	  break;
16217 	case T_COMPLEX:
16218 	case T_BIG_COMPLEX:
16219 	  return(wrong_type_argument(sc, sc->rationalize_symbol, 2, pp1, T_REAL));
16220 	default:
16221 	  return(method_or_bust(sc, pp1, sc->rationalize_symbol, args, T_REAL, 2));
16222 	}
16223       mpfr_abs(r->error, r->error, MPFR_RNDN);
16224     }
16225   else mpfr_set_d(r->error, sc->default_rationalize_error, MPFR_RNDN);
16226 
16227   mpfr_set(r->x0, r->ux, MPFR_RNDN);            /* x0 = ux - error */
16228   mpfr_sub(r->x0, r->x0, r->error, MPFR_RNDN);
16229   mpfr_set(r->x1, r->ux, MPFR_RNDN);            /* x1 = ux + error */
16230   mpfr_add(r->x1, r->x1, r->error, MPFR_RNDN);
16231   mpfr_get_z(r->i, r->x0, MPFR_RNDU);           /* i = ceil(x0) */
16232 
16233   if (mpfr_cmp_ui(r->error, 1) >= 0)            /* if (error >= 1.0) */
16234     {
16235       if (mpfr_cmp_ui(r->x0, 0) < 0)            /* if (x0 < 0) */
16236 	{
16237 	  if (mpfr_cmp_ui(r->x1, 0) < 0)        /*   if (x1 < 0) */
16238 	    mpfr_get_z(r->n, r->x1, MPFR_RNDD); /*     num = floor(x1) */
16239 	  else mpz_set_ui(r->n, 0);             /*   else num = 0 */
16240 	}
16241       else mpz_set(r->n, r->i);                 /* else num = i */
16242       return(mpz_to_integer(sc, r->n));
16243     }
16244 
16245   if (mpfr_cmp_z(r->x1, r->i) >= 0)             /* if (x1 >= i) */
16246     {
16247       if (mpz_cmp_ui(r->i, 0) >= 0)             /* if (i >= 0) */
16248 	mpz_set(r->n, r->i);                    /*   num = i */
16249       else mpfr_get_z(r->n, r->x1, MPFR_RNDD);  /* else num = floor(x1) */
16250       return(mpz_to_integer(sc, r->n));
16251     }
16252 
16253   mpfr_get_z(r->i0, r->x0, MPFR_RNDD);          /* i0 = floor(x0) */
16254   mpfr_get_z(r->i1, r->x1, MPFR_RNDU);          /* i1 = ceil(x1) */
16255 
16256   mpz_set(r->p0, r->i0);                        /* p0 = i0 */
16257   mpz_set_ui(r->q0, 1);                         /* q0 = 1 */
16258   mpz_set(r->p1, r->i1);                        /* p1 = i1 */
16259   mpz_set_ui(r->q1, 1);                         /* q1 = 1 */
16260   mpfr_sub_z(r->e0, r->x0, r->i1, MPFR_RNDN);   /* e0 = i1 - x0 */
16261   mpfr_neg(r->e0, r->e0, MPFR_RNDN);
16262   mpfr_sub_z(r->e1, r->x0, r->i0, MPFR_RNDN);   /* e1 = x0 - i0 */
16263   mpfr_sub_z(r->e0p, r->x1, r->i1, MPFR_RNDN);  /* e0p = i1 - x1 */
16264   mpfr_neg(r->e0p, r->e0p, MPFR_RNDN);
16265   mpfr_sub_z(r->e1p, r->x1, r->i0, MPFR_RNDN);  /* e1p = x1 - i0 */
16266 
16267   while (true)
16268     {
16269       mpfr_set_z(r->val, r->p0, MPFR_RNDN);
16270       mpfr_div_z(r->val, r->val, r->q0, MPFR_RNDN);  /* val = p0/q0 */
16271 
16272       if (((mpfr_lessequal_p(r->x0, r->val)) &&        /* if ((x0 <= val) && (val <= x1)) */
16273 	   (mpfr_lessequal_p(r->val, r->x1))) ||
16274 	  (mpfr_cmp_ui(r->e1, 0) == 0) ||
16275 	  (mpfr_cmp_ui(r->e1p, 0) == 0))
16276 	/* these last 2 are probably not needed -- they protect against running out of bits in the non-gmp case above */
16277 	{
16278 	  mpq_set_num(r->q, r->p0);                /* return(p0/q0) */
16279 	  mpq_set_den(r->q, r->q0);
16280 	  return(mpq_to_rational(sc, r->q));
16281 	}
16282 
16283       mpfr_div(r->val, r->e0, r->e1, MPFR_RNDN);
16284       mpfr_get_z(r->r, r->val, MPFR_RNDD);           /* r = floor(e0/e1) */
16285       mpfr_div(r->val, r->e0p, r->e1p, MPFR_RNDN);
16286       mpfr_get_z(r->r1, r->val, MPFR_RNDU);          /* r1 = ceil(e0p/e1p) */
16287       if (mpz_cmp(r->r1, r->r) < 0)                 /* if (r1 < r) */
16288 	mpz_set(r->r, r->r1);                       /*   r = r1 */
16289 
16290       mpz_set(r->old_p1, r->p1);                    /* old_p1 = p1 */
16291       mpz_set(r->p1, r->p0);                        /* p1 = p0 */
16292       mpz_set(r->old_q1, r->q1);                    /* old_q1 = q1 */
16293       mpz_set(r->q1, r->q0);                        /* q1 = q0 */
16294 
16295       mpfr_set(r->old_e0, r->e0, MPFR_RNDN);         /* old_e0 = e0 */
16296       mpfr_set(r->e0, r->e1p, MPFR_RNDN);            /* e0 = e1p */
16297       mpfr_set(r->old_e0p, r->e0p, MPFR_RNDN);       /* old_e0p = e0p */
16298       mpfr_set(r->e0p, r->e1, MPFR_RNDN);            /* e0p = e1 */
16299       mpfr_set(r->old_e1, r->e1, MPFR_RNDN);         /* old_e1 = e1 */
16300 
16301       mpz_mul(r->p0, r->p0, r->r);                  /* p0 = old_p1 + r * p0 */
16302       mpz_add(r->p0, r->p0, r->old_p1);
16303 
16304       mpz_mul(r->q0, r->q0, r->r);                  /* q0 = old_q1 + r * q0 */
16305       mpz_add(r->q0, r->q0, r->old_q1);
16306 
16307       mpfr_mul_z(r->e1, r->e1p, r->r, MPFR_RNDN);    /* e1 = old_e0p - r * e1p */
16308       mpfr_sub(r->e1, r->old_e0p, r->e1, MPFR_RNDN);
16309 
16310       mpfr_mul_z(r->e1p, r->old_e1, r->r, MPFR_RNDN);/* e1p = old_e0 - r * old_e1 */
16311       mpfr_sub(r->e1p, r->old_e0, r->e1p, MPFR_RNDN);
16312     }
16313 }
16314 #endif
16315 
16316 static s7_pointer g_rationalize(s7_scheme *sc, s7_pointer args)
16317 {
16318   #define H_rationalize "(rationalize x err) returns the ratio with smallest denominator within err of x"
16319   #define Q_rationalize s7_make_signature(sc, 3, sc->is_rational_symbol, sc->is_real_symbol, sc->is_real_symbol)
16320   /* I can't find a case where this returns a non-rational result */
16321 
16322   s7_double err;
16323   s7_pointer x;
16324 
16325   x = car(args);
16326 #if WITH_GMP
16327   if (is_big_number(x))
16328     return(big_rationalize(sc, args));
16329 #endif
16330   if (!s7_is_real(x))
16331     return(method_or_bust(sc, x, sc->rationalize_symbol, args, T_REAL, 1));
16332 
16333   if (is_not_null(cdr(args)))
16334     {
16335       s7_pointer ex;
16336       ex = cadr(args);
16337 #if WITH_GMP
16338       if (is_big_number(ex))
16339 	return(big_rationalize(sc, args));
16340 #endif
16341       if (!s7_is_real(ex))
16342 	return(method_or_bust(sc, ex, sc->rationalize_symbol, args, T_REAL, 2));
16343       err = real_to_double(sc, ex, "rationalize");
16344       if (is_NaN(err))
16345 	return(out_of_range(sc, sc->rationalize_symbol, int_two, cadr(args), its_nan_string));
16346       if (err < 0.0) err = -err;
16347     }
16348   else err = sc->default_rationalize_error;
16349 
16350   switch (type(x))
16351     {
16352     case T_INTEGER:
16353       {
16354 	s7_int a, b, pa;
16355 	if (err < 1.0) return(x);
16356 	a = s7_integer_checked(sc, x);
16357 	if (a < 0) pa = -a; else pa = a;
16358 	if (err >= pa) return(int_zero);
16359 	b = (s7_int)err;
16360 	pa -= b;
16361 	return((a < 0) ? make_integer(sc, -pa) : make_integer(sc, pa));
16362       }
16363 
16364     case T_RATIO:
16365       if (err == 0.0)
16366 	return(x);
16367 
16368     case T_REAL:
16369       {
16370 	s7_double rat;
16371 	s7_int numer = 0, denom = 1;
16372 
16373 	rat = s7_real(x); /* possible fall through from above */
16374 	if ((is_NaN(rat)) || (is_inf(rat)))
16375 	  return(out_of_range(sc, sc->rationalize_symbol, int_one, x, a_normal_real_string));
16376 
16377 	if (err >= fabs(rat))
16378 	  return(int_zero);
16379 
16380 #if WITH_GMP
16381 	if (fabs(rat) > RATIONALIZE_LIMIT)
16382 	  return(big_rationalize(sc, set_plist_2(sc, x, wrap_real1(sc, err))));
16383 #else
16384 	if (fabs(rat) > RATIONALIZE_LIMIT)
16385 	  return(out_of_range(sc, sc->rationalize_symbol, int_one, x, its_too_large_string));
16386 #endif
16387 	if ((fabs(rat) + fabs(err)) < 1.0e-18)
16388 	  err = 1.0e-18;
16389 	/* (/ 1.0 most-positive-fixnum) is 1.0842021e-19, so if we let err be less than that,
16390 	 * (rationalize 1e-19 1e-20) hangs, but this only affects the initial ceiling, I believe.
16391 	 */
16392 
16393 	if (fabs(rat) < fabs(err))
16394 	  return(int_zero);
16395 
16396 	return((c_rationalize(rat, err, &numer, &denom)) ? s7_make_ratio(sc, numer, denom) : sc->F);
16397       }}
16398   return(sc->F); /* make compiler happy */
16399 }
16400 
16401 static s7_int rationalize_i_i(s7_int x) {return(x);}
16402 static s7_pointer rationalize_p_i(s7_scheme *sc, s7_int x) {return(make_integer(sc, x));}
16403 static s7_pointer rationalize_p_d(s7_scheme *sc, s7_double x)
16404 {
16405   if ((is_NaN(x)) || (is_inf(x)))
16406     return(out_of_range(sc, sc->rationalize_symbol, int_one, make_real(sc, x), a_normal_real_string));
16407   if (fabs(x) > RATIONALIZE_LIMIT)
16408 #if WITH_GMP
16409     return(big_rationalize(sc, set_plist_1(sc, wrap_real1(sc, x))));
16410 #else
16411     return(out_of_range(sc, sc->rationalize_symbol, int_one, make_real(sc, x), its_too_large_string));
16412 #endif
16413   return(s7_rationalize(sc, x, sc->default_rationalize_error));
16414 }
16415 
16416 
16417 /* -------------------------------- angle -------------------------------- */
16418 static s7_pointer g_angle(s7_scheme *sc, s7_pointer args)
16419 {
16420   #define H_angle "(angle z) returns the angle of z"
16421   #define Q_angle s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
16422   s7_pointer x;
16423   /* (angle inf+infi) -> 0.78539816339745 ? I think this should be -pi < ang <= pi */
16424 
16425   x = car(args);
16426   switch (type(x))
16427     {
16428     case T_INTEGER:
16429       return((integer(x) < 0) ? real_pi : int_zero);
16430 
16431     case T_RATIO:
16432       return((numerator(x) < 0) ? real_pi : int_zero);
16433 
16434     case T_REAL:
16435       if (is_NaN(real(x))) return(x);
16436       return((real(x) < 0.0) ? real_pi : real_zero);
16437 
16438     case T_COMPLEX:
16439       return(make_real(sc, atan2(imag_part(x), real_part(x))));
16440 
16441 #if WITH_GMP
16442     case T_BIG_INTEGER:
16443       return((mpz_cmp_ui(big_integer(x), 0) >= 0) ? int_zero : big_pi(sc));
16444 
16445     case T_BIG_RATIO:
16446       return((mpq_cmp_ui(big_ratio(x), 0, 1) >= 0) ? int_zero : big_pi(sc));
16447 
16448     case T_BIG_REAL:
16449       if (mpfr_nan_p(big_real(x))) return(x);
16450       return((mpfr_cmp_d(big_real(x), 0.0) >= 0) ? real_zero : big_pi(sc));
16451 
16452     case T_BIG_COMPLEX:
16453       {
16454 	s7_pointer z;
16455 	new_cell(sc, z, T_BIG_REAL);
16456 	big_real_bgf(z) = alloc_bigflt(sc);
16457 	add_big_real(sc, z);
16458 	mpc_arg(big_real(z), big_complex(x), MPFR_RNDN);
16459 	return(z);
16460       }
16461 #endif
16462 
16463     default:
16464       return(method_or_bust_with_type_one_arg(sc, x, sc->angle_symbol, args, a_number_string));
16465     }
16466 }
16467 
16468 
16469 /* -------------------------------- complex -------------------------------- */
16470 
16471 static s7_pointer g_complex(s7_scheme *sc, s7_pointer args)
16472 {
16473   s7_pointer x, y;
16474   #define H_complex "(complex x1 x2) returns a complex number with real-part x1 and imaginary-part x2"
16475   #define Q_complex s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_real_symbol, sc->is_real_symbol)
16476 
16477   x = car(args);
16478   y = cadr(args);
16479 
16480 #if WITH_GMP
16481   if ((is_big_number(x)) || (is_big_number(y)))
16482     {
16483       s7_pointer p0, p1, p = NULL;
16484 
16485       p0 = car(args);
16486       if (!s7_is_real(p0))
16487 	return(method_or_bust(sc, p0, sc->complex_symbol, args, T_REAL, 1));
16488 
16489       p1 = cadr(args);
16490       if (!s7_is_real(p1))
16491 	return(method_or_bust(sc, p1, sc->complex_symbol, args, T_REAL, 2));
16492 
16493       switch (type(p1))
16494 	{
16495 	case T_INTEGER: case T_RATIO: case T_REAL:
16496 	  {
16497 	    s7_double iz;
16498 	    iz = s7_real(p1);
16499 	    if (iz == 0.0)                      /* imag-part is 0.0 */
16500 	      return(p0);
16501 	    new_cell(sc, p, T_BIG_COMPLEX);
16502 	    big_complex_bgc(p) = alloc_bigcmp(sc);
16503 	    mpfr_set_d(mpc_imagref(big_complex(p)), iz, MPFR_RNDN);
16504 	  }
16505 	  break;
16506 
16507 	case T_BIG_REAL:
16508 	  if (mpfr_zero_p(big_real(p1))) return(p0);
16509 	  new_cell(sc, p, T_BIG_COMPLEX);
16510 	  big_complex_bgc(p) = alloc_bigcmp(sc);
16511 	  mpfr_set(mpc_imagref(big_complex(p)), big_real(p1), MPFR_RNDN);
16512 	  break;
16513 
16514 	case T_BIG_RATIO:
16515 	  new_cell(sc, p, T_BIG_COMPLEX);
16516 	  big_complex_bgc(p) = alloc_bigcmp(sc);
16517 	  mpfr_set_q(mpc_imagref(big_complex(p)), big_ratio(p1), MPFR_RNDN);
16518 	  break;
16519 
16520 	case T_BIG_INTEGER:
16521 	  if (mpz_cmp_ui(big_integer(p1), 0) == 0) return(p0);
16522 	  new_cell(sc, p, T_BIG_COMPLEX);
16523 	  big_complex_bgc(p) = alloc_bigcmp(sc);
16524 	  mpfr_set_z(mpc_imagref(big_complex(p)), big_integer(p1), MPFR_RNDN);
16525 	  break;
16526 	}
16527 
16528       switch (type(p0))
16529 	{
16530 	case T_INTEGER: case T_RATIO: case T_REAL:
16531 	  mpfr_set_d(mpc_realref(big_complex(p)), s7_real(p0), MPFR_RNDN);
16532 	  break;
16533 
16534 	case T_BIG_REAL:
16535 	  mpfr_set(mpc_realref(big_complex(p)), big_real(p0), MPFR_RNDN);
16536 	  break;
16537 
16538 	case T_BIG_RATIO:
16539 	  mpfr_set_q(mpc_realref(big_complex(p)), big_ratio(p0), MPFR_RNDN);
16540 	  break;
16541 
16542 	case T_BIG_INTEGER:
16543 	  mpfr_set_z(mpc_realref(big_complex(p)), big_integer(p0), MPFR_RNDN);
16544 	  break;
16545 	}
16546       add_big_complex(sc, p);
16547       return(p);
16548     }
16549 #endif
16550 
16551   switch (type(y))
16552     {
16553     case T_INTEGER:
16554       switch (type(x))
16555 	{
16556 	case T_INTEGER: return((integer(y) == 0) ? x : s7_make_complex(sc, (s7_double)integer(x), (s7_double)integer(y)));
16557 	  /* these int->dbl's are problematic:
16558 	   *   (complex 9223372036854775807 9007199254740995): 9223372036854776000.0+9007199254740996.0i
16559 	   * should we raise an error?
16560 	   */
16561 	case T_RATIO:  return((integer(y) == 0) ? x : s7_make_complex(sc, (s7_double)fraction(x), (s7_double)integer(y)));
16562 	case T_REAL:   return((integer(y) == 0) ? x : s7_make_complex(sc, real(x), (s7_double)integer(y)));
16563 	default:       return(method_or_bust(sc, x, sc->complex_symbol, args, T_REAL, 1));
16564 	}
16565 
16566     case T_RATIO:
16567       switch (type(x))
16568 	{
16569 	case T_INTEGER: return(s7_make_complex(sc, (s7_double)integer(x), (s7_double)fraction(y)));
16570 	case T_RATIO:   return(s7_make_complex(sc, (s7_double)fraction(x), (s7_double)fraction(y)));
16571 	case T_REAL:    return(s7_make_complex(sc, real(x), (s7_double)fraction(y)));
16572 	default:	return(method_or_bust(sc, x, sc->complex_symbol, args, T_REAL, 1));
16573 	}
16574 
16575     case T_REAL:
16576       switch (type(x))
16577 	{
16578 	case T_INTEGER: return((real(y) == 0.0) ? x : s7_make_complex(sc, (s7_double)integer(x), real(y)));
16579 	case T_RATIO:	return((real(y) == 0.0) ? x : s7_make_complex(sc, (s7_double)fraction(x), real(y)));
16580 	case T_REAL:    return((real(y) == 0.0) ? x : s7_make_complex(sc, real(x), real(y)));
16581 	default:	return(method_or_bust(sc, x, sc->complex_symbol, args, T_REAL, 1));
16582 	}
16583 
16584     default:
16585       return(method_or_bust(sc, (is_let(x)) ? x : y, sc->complex_symbol, args, T_REAL, 2));
16586     }
16587 }
16588 
16589 static s7_pointer complex_p_ii(s7_scheme *sc, s7_int x, s7_int y)
16590 {
16591   return((y == 0) ? make_integer(sc, x) : make_complex_unchecked(sc, (s7_double)x, (s7_double)y));
16592 }
16593 
16594 static s7_pointer complex_p_dd(s7_scheme *sc, s7_double x, s7_double y)
16595 {
16596   return((y == 0) ? make_real(sc, x) : make_complex_unchecked(sc, x, y));
16597 }
16598 
16599 
16600 /* -------------------------------- bignum -------------------------------- */
16601 static s7_pointer g_bignum(s7_scheme *sc, s7_pointer args)
16602 {
16603   #define H_bignum "(bignum val (radix 10)) returns a multiprecision version of the string 'val'. If the argument is a number \
16604 bignum returns that number as a bignum"
16605   #define Q_bignum s7_make_signature(sc, 3, sc->is_bignum_symbol, s7_make_signature(sc, 2, sc->is_number_symbol, sc->is_string_symbol), sc->is_integer_symbol)
16606 
16607 #if WITH_GMP
16608   s7_pointer p;
16609   if (is_number(car(args)))
16610     {
16611       if (!is_null(cdr(args)))
16612 	s7_error(sc, make_symbol(sc, "bignum-error"),
16613 		 set_elist_2(sc, wrap_string(sc, "bignum of a number takes only one argument: ~S", 46), args));
16614       p = car(args);
16615       switch (type(p))
16616 	{
16617 	case T_INTEGER: return(s7_int_to_big_integer(sc, integer(p)));
16618 	case T_RATIO:   return(s7_int_to_big_ratio(sc, numerator(p), denominator(p)));
16619 	case T_REAL:    return(s7_double_to_big_real(sc, real(p)));
16620 	case T_COMPLEX: return(s7_double_to_big_complex(sc, real_part(p), imag_part(p)));
16621 	default:        return(p);
16622 	}}
16623   p = g_string_to_number_1(sc, args, sc->bignum_symbol);
16624   if (is_false(sc, p))                                       /* (bignum "1/3.0") */
16625     s7_error(sc, make_symbol(sc, "bignum-error"),
16626 	     set_elist_2(sc, wrap_string(sc, "bignum string argument does not represent a number: ~S", 54), car(args)));
16627   switch (type(p))
16628     {
16629     case T_INTEGER:   return(s7_int_to_big_integer(sc, integer(p)));
16630     case T_RATIO:     return(s7_int_to_big_ratio(sc, numerator(p), denominator(p)));
16631     case T_COMPLEX:   return(s7_number_to_big_complex(sc, p));
16632     case T_REAL:
16633       if (is_NaN(real(p))) return(p);
16634       return(string_to_big_real(sc, string_value(car(args)), (is_pair(cdr(args))) ? s7_integer_checked(sc, cadr(args)) : 10));
16635     default:
16636       return(p);
16637     }
16638 #else
16639   return((is_number(car(args))) ? car(args) : g_string_to_number_1(sc, args, sc->bignum_symbol));
16640 #endif
16641 }
16642 
16643 
16644 /* -------------------------------- exp -------------------------------- */
16645 #if (!HAVE_COMPLEX_NUMBERS)
16646   static s7_pointer no_complex_numbers_string;
16647 #endif
16648 
16649 #define EXP_LIMIT 100.0
16650 
16651 #if WITH_GMP
16652 static s7_pointer exp_1(s7_scheme *sc, s7_double x)
16653 {
16654   mpfr_set_d(sc->mpfr_1, x, MPFR_RNDN);
16655   mpfr_exp(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
16656   return(mpfr_to_big_real(sc, sc->mpfr_1));
16657 }
16658 
16659 static s7_pointer exp_2(s7_scheme *sc, s7_double x, s7_double y)
16660 {
16661   mpc_set_d_d(sc->mpc_1, x, y, MPC_RNDNN);
16662   mpc_exp(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
16663   return(mpc_to_number(sc, sc->mpc_1));
16664 }
16665 #endif
16666 
16667 static s7_pointer exp_p_p(s7_scheme *sc, s7_pointer x)
16668 {
16669   double z;
16670   switch (type(x))
16671     {
16672     case T_INTEGER:
16673       if (integer(x) == 0) return(int_one);                       /* (exp 0) -> 1 */
16674       z = (s7_double)integer(x);
16675 #if WITH_GMP
16676       if (fabs(z) > EXP_LIMIT)
16677 	return(exp_1(sc, z));
16678 #endif
16679       return(make_real(sc, exp(z)));
16680 
16681     case T_RATIO:
16682       z = (s7_double)fraction(x);
16683 #if WITH_GMP
16684       if (fabs(z) > EXP_LIMIT)
16685 	return(exp_1(sc, z));
16686 #endif
16687       return(make_real(sc, exp(z)));
16688 
16689     case T_REAL:
16690 #if WITH_GMP
16691       if (fabs(real(x)) > EXP_LIMIT)
16692 	return(exp_1(sc, real(x)));
16693 #endif
16694       return(make_real(sc, exp(real(x))));
16695 
16696     case T_COMPLEX:
16697 #if HAVE_COMPLEX_NUMBERS
16698 #if WITH_GMP
16699       if ((fabs(real_part(x)) > EXP_LIMIT) ||
16700 	  (fabs(imag_part(x)) > EXP_LIMIT))
16701 	return(exp_2(sc, real_part(x), imag_part(x)));
16702 #endif
16703       return(c_complex_to_s7(sc, cexp(to_c_complex(x))));
16704       /* this is inaccurate for large arguments:
16705        *   (exp 0+1e20i) -> -0.66491178990701-0.74692189125949i, not 7.639704044417283004001468027378811228331E-1-6.45251285265780844205811711312523007406E-1i
16706        */
16707 #else
16708       return(out_of_range(sc, sc->exp_symbol, int_one, x, no_complex_numbers_string));
16709 #endif
16710 
16711 #if WITH_GMP
16712     case T_BIG_INTEGER:
16713       mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
16714       mpfr_exp(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
16715       return(mpfr_to_big_real(sc, sc->mpfr_1));
16716 
16717     case T_BIG_RATIO:
16718       mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
16719       mpfr_exp(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
16720       return(mpfr_to_big_real(sc, sc->mpfr_1));
16721 
16722     case T_BIG_REAL:
16723       mpfr_exp(sc->mpfr_1, big_real(x), MPFR_RNDN);
16724       return(mpfr_to_big_real(sc, sc->mpfr_1));
16725 
16726     case T_BIG_COMPLEX:
16727       mpc_exp(sc->mpc_1, big_complex(x), MPC_RNDNN);
16728       if (mpfr_zero_p(mpc_imagref(sc->mpc_1)))
16729 	return(mpfr_to_big_real(sc, mpc_realref(sc->mpc_1)));
16730       return(mpc_to_number(sc, sc->mpc_1));
16731 #endif
16732 
16733     default:
16734       return(method_or_bust_with_type_one_arg(sc, x, sc->exp_symbol, list_1(sc, x), a_number_string));
16735     }
16736 }
16737 
16738 static s7_pointer g_exp(s7_scheme *sc, s7_pointer args)
16739 {
16740   #define H_exp "(exp z) returns e^z, (exp 1) is 2.718281828459"
16741   #define Q_exp sc->pl_nn
16742   return(exp_p_p(sc, car(args)));
16743 }
16744 
16745 #if (!WITH_GMP)
16746 static s7_double exp_d_d(s7_double x) {return(exp(x));}
16747 #endif
16748 
16749 
16750 /* -------------------------------- log -------------------------------- */
16751 
16752 #if __cplusplus
16753 #define LOG_2 1.4426950408889634074
16754 #else
16755 #define LOG_2 1.4426950408889634073599246810018921L /* (/ (log 2.0)) */
16756 #endif
16757 static bool is_nan_b_7p(s7_scheme *sc, s7_pointer x);
16758 
16759 #if WITH_GMP
16760 static s7_pointer big_log(s7_scheme *sc, s7_pointer args)
16761 {
16762   s7_pointer p0, p1 = NULL, res;
16763 
16764   p0 = car(args);
16765   if (!s7_is_number(p0))
16766     return(method_or_bust_with_type(sc, p0, sc->log_symbol, args, a_number_string, 1));
16767 
16768   if (is_pair(cdr(args)))
16769     {
16770       p1 = cadr(args);
16771       if (!s7_is_number(p1))
16772 	return(method_or_bust_with_type(sc, p1, sc->log_symbol, args, a_number_string, 2));
16773     }
16774 
16775   if (s7_is_real(p0))
16776     {
16777       res = any_real_to_mpfr(sc, p0, sc->mpfr_1);
16778       if (res == real_NaN) return(res);
16779       if ((s7_is_positive(p0)) &&
16780 	  ((!p1) ||
16781 	   ((s7_is_real(p1)) && (s7_is_positive(p1)))))
16782 	{
16783 	  if (res) return(res);
16784 	  mpfr_log(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
16785 	  if (p1)
16786 	    {
16787 	      res = any_real_to_mpfr(sc, p1, sc->mpfr_2);
16788 	      if (res)
16789 		return((res == real_infinity) ? real_zero : res);
16790 	      if (mpfr_zero_p(sc->mpfr_2))
16791 		return(out_of_range(sc, sc->log_symbol, int_two, p1, wrap_string(sc, "can't be zero", 13)));
16792 	      mpfr_log(sc->mpfr_2, sc->mpfr_2, MPFR_RNDN);
16793 	      mpfr_div(sc->mpfr_1, sc->mpfr_1, sc->mpfr_2, MPFR_RNDN);
16794 	    }
16795 	  if ((mpfr_integer_p(sc->mpfr_1)) && ((is_rational(p0)) && ((!p1) || (is_rational(p1)))))
16796 	    return(mpfr_to_integer(sc, sc->mpfr_1));
16797 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
16798 	}}
16799 
16800   if (p1)
16801     {
16802       res = any_number_to_mpc(sc, p1, sc->mpc_2);
16803       if (res)
16804 	return((res == real_infinity) ? real_zero : complex_NaN);
16805       if (mpc_zero_p(sc->mpc_2))
16806 	return(out_of_range(sc, sc->log_symbol, int_two, p1, wrap_string(sc, "can't be zero", 13)));
16807     }
16808   res = any_number_to_mpc(sc, p0, sc->mpc_1);
16809   if (res)
16810     {
16811       if ((res == real_infinity) && (p1) && ((s7_is_negative(p0))))
16812 	return(make_complex_unchecked(sc, INFINITY, -NAN));
16813       return((res == real_NaN) ? complex_NaN : res);
16814     }
16815   mpc_log(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
16816   if (p1)
16817     {
16818       mpc_log(sc->mpc_2, sc->mpc_2, MPC_RNDNN);
16819       mpc_div(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
16820     }
16821   if (mpfr_zero_p(mpc_imagref(sc->mpc_1)))
16822     return(mpfr_to_big_real(sc, mpc_realref(sc->mpc_1)));
16823   return(mpc_to_number(sc, sc->mpc_1));
16824 }
16825 #endif
16826 
16827 static s7_pointer g_log(s7_scheme *sc, s7_pointer args)
16828 {
16829   #define H_log "(log z1 (z2 e)) returns log(z1) / log(z2) where z2 (the base) defaults to e: (log 8 2) = 3"
16830   #define Q_log sc->pcl_n
16831 
16832   s7_pointer x;
16833 
16834   x = car(args);
16835   if (!s7_is_number(x))
16836     return(method_or_bust_with_type(sc, x, sc->log_symbol, args, a_number_string, 1));
16837 
16838 #if WITH_GMP
16839   if (is_big_number(x)) return(big_log(sc, args));
16840 #endif
16841 
16842   if (is_pair(cdr(args)))
16843     {
16844       s7_pointer y;
16845 
16846       y = cadr(args);
16847       if (!(s7_is_number(y)))
16848 	return(method_or_bust_with_type(sc, y, sc->log_symbol, args, a_number_string, 2));
16849 
16850 #if WITH_GMP
16851       if (is_big_number(y)) return(big_log(sc, args));
16852 #endif
16853 
16854       if ((is_t_integer(y)) && (integer(y) == 2))
16855 	{
16856 	  /* (define (2^n? x) (and (not (zero? x)) (zero? (logand x (- x 1))))) */
16857 	  if (is_t_integer(x))
16858 	    {
16859 	      s7_int ix;
16860 	      ix = s7_integer_checked(sc, x);
16861 	      if (ix > 0)
16862 		{
16863 		  s7_double fx;
16864 #if (__ANDROID__) || (MS_WINDOWS) || (((__GNUC__) && ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ <= 4)))) && (!defined(__clang__)))
16865 		  /* just a guess -- log2 gets a warning in gcc 4.3.2, but not in 4.4.4 */
16866 		  fx = log((double)ix) / log(2.0);
16867 #else
16868 		  fx = log2((double)ix);
16869 #endif
16870 		  /* (s7_int)fx rounds (log 8 2) to 2 in FreeBSD! */
16871 #if (((__GNUC__) && ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 4)))) && (!defined(__clang__)))
16872 		  return(make_real(sc, fx));
16873 #else
16874 		  return(((ix & (ix - 1)) == 0) ? make_integer(sc, (s7_int)s7_round(fx)) : make_real(sc, fx));
16875 #endif
16876 		}}
16877 	  if ((s7_is_real(x)) &&
16878 	      (s7_is_positive(x)))
16879 	    return(make_real(sc, log(s7_real(x)) * LOG_2));
16880 	  return(c_complex_to_s7(sc, clog(s7_to_c_complex(x)) * LOG_2));
16881 	}
16882 
16883       if ((is_t_integer(x)) && (integer(x) == 1) && (is_t_integer(y)) && (integer(y) == 1))  /* (log 1 1) -> 0 (this is NaN in the bignum case) */
16884 	return(int_zero);
16885 
16886       /* (log 1 0) must be 0 since everyone says (expt 0 0) is 1 */
16887       if (s7_is_zero(y))
16888 	{
16889 	  if ((is_t_integer(y)) && (is_t_integer(x)) && (integer(x) == 1))
16890 	    return(y);
16891 	  return(out_of_range(sc, sc->log_symbol, int_two, y, wrap_string(sc, "can't be zero", 13)));
16892 	}
16893 
16894       if ((is_t_real(x)) && (is_NaN(real(x))))
16895 	return(real_NaN);
16896       if (s7_is_one(y))                                     /* this used to raise an error, but the bignum case is simpler if we return inf */
16897 	return((s7_is_one(x)) ? real_zero : real_infinity); /* but (log 1.0 1.0) -> 0.0, currently (log 1/0 1) is inf? */
16898 
16899       if ((s7_is_real(x)) &&
16900 	  (s7_is_real(y)) &&
16901 	  (s7_is_positive(x)) &&
16902 	  (s7_is_positive(y)))
16903 	{
16904 	  if ((s7_is_rational(x)) &&
16905 	      (s7_is_rational(y)))
16906 	    {
16907 	      s7_double res;
16908 	      s7_int ires;
16909 	      res = log(rational_to_double(sc, x)) / log(rational_to_double(sc, y));
16910 	      ires = (s7_int)res;
16911 	      if (res - ires == 0.0)
16912 		return(make_integer(sc, ires));   /* (log 8 2) -> 3 or (log 1/8 2) -> -3 */
16913 	      /* since x and y are rational here, it seems reasonable to try to rationalize the result, but not go overboard?
16914 	       *   what about (expt 16 3/2) -> 64?  also 2 as base is handled above and always returns a float.
16915 	       */
16916 	      if (fabs(res) < RATIONALIZE_LIMIT)
16917 		{
16918 		  s7_int num, den;
16919 		  if ((c_rationalize(res, sc->default_rationalize_error, &num, &den)) &&
16920 		      (s7_int_abs(num) < 100) && (s7_int_abs(den) < 100))
16921 		    return(make_simple_ratio(sc, num, den));
16922 		}
16923 	      return(make_real(sc, res));
16924 	    }
16925 	  return(make_real(sc, log(s7_real(x)) / log(s7_real(y))));
16926 	}
16927       if ((is_t_real(x)) && (is_NaN(real(x))))
16928 	return(real_NaN);
16929       if ((is_t_complex(y)) && ((is_NaN(real_part(y))) || (is_NaN(imag_part(y)))))
16930 	return(real_NaN);
16931       return(c_complex_to_s7(sc, clog(s7_to_c_complex(x)) / clog(s7_to_c_complex(y))));
16932     }
16933 
16934   if (s7_is_real(x))
16935     {
16936       if (s7_is_positive(x))
16937 	return(make_real(sc, log(s7_real(x))));
16938       return(s7_make_complex(sc, log(-s7_real(x)), M_PI));
16939     }
16940   return(c_complex_to_s7(sc, clog(s7_to_c_complex(x))));
16941 }
16942 
16943 
16944 /* -------------------------------- sin -------------------------------- */
16945 #define SIN_LIMIT 1.0e16
16946 #define SINH_LIMIT 20.0
16947 /* (- (sinh (bignum 30.0)) (sinh 30.0)): -3.718172657214174140191915872003397016115E-4
16948  * (- (sinh (bignum 20.0)) (sinh 20.0)): -7.865629467297586346406367346575835463792E-10, slightly worse (e-8) if imag-part
16949  */
16950 
16951 static s7_pointer sin_p_p(s7_scheme *sc, s7_pointer x)
16952 {
16953 #if (!WITH_GMP)
16954   if (is_t_real(x)) return(make_real(sc, sin(real(x)))); /* range check in gmp case */
16955 #endif
16956   switch (type(x))
16957     {
16958     case T_INTEGER:
16959       if (integer(x) == 0) return(int_zero);           /* (sin 0) -> 0 */
16960 #if WITH_GMP
16961       if (integer(x) > SIN_LIMIT)
16962 	{
16963 	  mpz_set_si(sc->mpz_1, integer(x));
16964 	  mpfr_set_z(sc->mpfr_1, sc->mpz_1, MPFR_RNDN);
16965 	  mpfr_sin(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
16966 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
16967 	}
16968 #endif
16969       return(make_real(sc, sin((s7_double)(integer(x)))));
16970 
16971     case T_RATIO:
16972       return(make_real(sc, sin((s7_double)(fraction(x)))));
16973 
16974     case T_REAL:
16975       {
16976 	s7_double y;
16977 	y = real(x);
16978 #if WITH_GMP
16979 	if (fabs(y) > SIN_LIMIT)
16980 	  {
16981 	    mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
16982 	    mpfr_sin(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
16983 	    return(mpfr_to_big_real(sc, sc->mpfr_1));
16984 	  }
16985 #endif
16986 	return(make_real(sc, sin(y)));
16987       }
16988 
16989     case T_COMPLEX:
16990 #if WITH_GMP
16991       if ((fabs(real_part(x)) > SIN_LIMIT) || (fabs(imag_part(x)) > SINH_LIMIT))
16992 	{
16993 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
16994 	  mpc_sin(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
16995 	  return(mpc_to_number(sc, sc->mpc_1));
16996 	}
16997 #endif
16998 #if HAVE_COMPLEX_NUMBERS
16999       return(c_complex_to_s7(sc, csin(to_c_complex(x))));
17000 #else
17001       return(out_of_range(sc, sc->sin_symbol, int_one, x, no_complex_numbers_string));
17002 #endif
17003 
17004 #if WITH_GMP
17005     case T_BIG_INTEGER:
17006       mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
17007       mpfr_sin(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17008       return(mpfr_to_big_real(sc, sc->mpfr_1));
17009 
17010     case T_BIG_RATIO:
17011       mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
17012       mpfr_sin(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17013       return(mpfr_to_big_real(sc, sc->mpfr_1));
17014 
17015     case T_BIG_REAL:
17016       mpfr_sin(sc->mpfr_1, big_real(x), MPFR_RNDN);
17017       return(mpfr_to_big_real(sc, sc->mpfr_1));
17018 
17019     case T_BIG_COMPLEX:
17020       mpc_sin(sc->mpc_1, big_complex(x), MPC_RNDNN);
17021       if (mpfr_zero_p(mpc_imagref(sc->mpc_1)))
17022 	return(mpfr_to_big_real(sc, mpc_realref(sc->mpc_1)));
17023       return(mpc_to_number(sc, sc->mpc_1));
17024 #endif
17025 
17026     default:
17027       return(method_or_bust_with_type_one_arg_p(sc, x, sc->sin_symbol, a_number_string));
17028     }
17029   /* sin is inaccurate over about 1e30.  There's a way to get true results, but it involves fancy "range reduction" techniques.
17030    * (sin 1e32): 0.5852334864823946
17031    *   but it should be 3.901970254333630491697613212893425767786E-1
17032    * (remainder 1e22 (* 2 pi)) -> 1.0057952155665e+22 !! (it's now a range error)
17033    *   it should be 5.263007914620499494429139986095833592117E0
17034    * before comparing imag-part to 0, we need to look for NaN and inf, else:
17035    *    (sinh 0+0/0i) -> 0.0 and (sinh (log 0.0)) -> inf.0
17036    */
17037 }
17038 
17039 static s7_pointer g_sin(s7_scheme *sc, s7_pointer args)
17040 {
17041   #define H_sin "(sin z) returns sin(z)"
17042   #define Q_sin sc->pl_nn
17043   return(sin_p_p(sc, car(args)));
17044 }
17045 
17046 #if WITH_GMP
17047 static s7_pointer sin_p_d(s7_scheme *sc, s7_double x)
17048 {
17049   if (fabs(x) > SIN_LIMIT)
17050     {
17051       mpfr_set_d(sc->mpfr_1, x, MPFR_RNDN);
17052       mpfr_sin(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17053       return(mpfr_to_big_real(sc, sc->mpfr_1));
17054     }
17055   return(make_real(sc, sin(x)));
17056 }
17057 #else
17058 static s7_double sin_d_d(s7_double x) {return(sin(x));}
17059 static s7_pointer sin_p_d(s7_scheme *sc, s7_double x) {return(make_real(sc, sin(x)));}
17060 #endif
17061 
17062 
17063 /* -------------------------------- cos -------------------------------- */
17064 static s7_pointer cos_p_p(s7_scheme *sc, s7_pointer x)
17065 {
17066 #if (!WITH_GMP)
17067   if (is_t_real(x)) return(make_real(sc, cos(real(x)))); /* range check in gmp case */
17068 #endif
17069   switch (type(x))
17070     {
17071     case T_INTEGER:
17072       if (integer(x) == 0) return(int_one);             /* (cos 0) -> 1 */
17073 #if WITH_GMP
17074       if (integer(x) > SIN_LIMIT)
17075 	{
17076 	  mpz_set_si(sc->mpz_1, integer(x));
17077 	  mpfr_set_z(sc->mpfr_1, sc->mpz_1, MPFR_RNDN);
17078 	  mpfr_cos(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17079 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
17080 	}
17081 #endif
17082       return(make_real(sc, cos((s7_double)(integer(x)))));
17083 
17084     case T_RATIO:
17085       return(make_real(sc, cos((s7_double)(fraction(x)))));
17086 
17087     case T_REAL: /* if with_gmp */
17088       {
17089 	s7_double y;
17090 	y = real(x);
17091 #if WITH_GMP
17092 	if (fabs(y) > SIN_LIMIT)
17093 	  {
17094 	    mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
17095 	    mpfr_cos(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17096 	    return(mpfr_to_big_real(sc, sc->mpfr_1));
17097 	  }
17098 #endif
17099 	return(make_real(sc, cos(y)));
17100       }
17101 
17102     case T_COMPLEX:
17103 #if WITH_GMP
17104       if ((fabs(real_part(x)) > SIN_LIMIT) || (fabs(imag_part(x)) > SINH_LIMIT))
17105 	{
17106 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
17107 	  mpc_cos(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17108 	  return(mpc_to_number(sc, sc->mpc_1));
17109 	}
17110 #endif
17111 #if HAVE_COMPLEX_NUMBERS
17112       return(c_complex_to_s7(sc, ccos(to_c_complex(x))));
17113 #else
17114       return(out_of_range(sc, sc->cos_symbol, int_one, x, no_complex_numbers_string));
17115 #endif
17116 
17117 #if WITH_GMP
17118     case T_BIG_INTEGER:
17119       mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
17120       mpfr_cos(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17121       return(mpfr_to_big_real(sc, sc->mpfr_1));
17122 
17123     case T_BIG_RATIO:
17124       mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
17125       mpfr_cos(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17126       return(mpfr_to_big_real(sc, sc->mpfr_1));
17127 
17128     case T_BIG_REAL:
17129       mpfr_cos(sc->mpfr_1, big_real(x), MPFR_RNDN);
17130       return(mpfr_to_big_real(sc, sc->mpfr_1));
17131 
17132     case T_BIG_COMPLEX:
17133       mpc_cos(sc->mpc_1, big_complex(x), MPC_RNDNN);
17134       if (mpfr_zero_p(mpc_imagref(sc->mpc_1)))
17135 	return(mpfr_to_big_real(sc, mpc_realref(sc->mpc_1)));
17136       return(mpc_to_number(sc, sc->mpc_1));
17137 #endif
17138 
17139     default:
17140       return(method_or_bust_with_type_one_arg_p(sc, x, sc->cos_symbol, a_number_string));
17141     }
17142 }
17143 
17144 static s7_pointer g_cos(s7_scheme *sc, s7_pointer args)
17145 {
17146   #define H_cos "(cos z) returns cos(z)"
17147   #define Q_cos sc->pl_nn
17148   return(cos_p_p(sc, car(args)));
17149 }
17150 
17151 #if WITH_GMP
17152 static s7_pointer cos_p_d(s7_scheme *sc, s7_double x)
17153 {
17154   if (fabs(x) > SIN_LIMIT)
17155     {
17156       mpfr_set_d(sc->mpfr_1, x, MPFR_RNDN);
17157       mpfr_cos(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17158       return(mpfr_to_big_real(sc, sc->mpfr_1));
17159     }
17160   return(make_real(sc, cos(x)));
17161 }
17162 #else
17163 static s7_double cos_d_d(s7_double x) {return(cos(x));}
17164 static s7_pointer cos_p_d(s7_scheme *sc, s7_double x) {return(make_real(sc, cos(x)));}
17165 #endif
17166 
17167 
17168 /* -------------------------------- tan -------------------------------- */
17169 #define TAN_LIMIT 1.0e18
17170 
17171 static s7_pointer tan_p_p(s7_scheme *sc, s7_pointer x)
17172 {
17173 #if (!WITH_GMP)
17174   if (is_t_real(x)) return(make_real(sc, tan(real(x))));
17175 #endif
17176   switch (type(x))
17177     {
17178     case T_INTEGER:
17179       if (integer(x) == 0) return(int_zero);                      /* (tan 0) -> 0 */
17180 #if WITH_GMP
17181       if (integer(x) > TAN_LIMIT)
17182 	{
17183 	  mpz_set_si(sc->mpz_1, integer(x));
17184 	  mpfr_set_z(sc->mpfr_1, sc->mpz_1, MPFR_RNDN);
17185 	  mpfr_tan(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17186 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
17187 	}
17188 #endif
17189       return(make_real(sc, tan((s7_double)(integer(x)))));
17190 
17191     case T_RATIO:
17192       return(make_real(sc, tan((s7_double)(fraction(x)))));
17193 
17194 #if WITH_GMP
17195     case T_REAL:
17196       if (fabs(real(x)) > TAN_LIMIT)
17197 	{
17198 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
17199 	  mpfr_tan(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17200 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
17201 	}
17202 #endif
17203       return(make_real(sc, tan(real(x))));
17204 
17205     case T_COMPLEX:
17206 #if HAVE_COMPLEX_NUMBERS
17207       if (imag_part(x) > 350.0)
17208 	return(s7_make_complex(sc, 0.0, 1.0));
17209       return((imag_part(x) < -350.0) ? s7_make_complex(sc, 0.0, -1.0) : c_complex_to_s7(sc, ctan(to_c_complex(x))));
17210 #else
17211       return(out_of_range(sc, sc->tan_symbol, int_one, x, no_complex_numbers_string));
17212 #endif
17213 
17214 #if WITH_GMP
17215     case T_BIG_INTEGER:
17216       mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
17217       mpfr_tan(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17218       return(mpfr_to_big_real(sc, sc->mpfr_1));
17219 
17220     case T_BIG_RATIO:
17221       mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
17222       mpfr_tan(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17223       return(mpfr_to_big_real(sc, sc->mpfr_1));
17224 
17225     case T_BIG_REAL:
17226       mpfr_tan(sc->mpfr_1, big_real(x), MPFR_RNDN);
17227       return(mpfr_to_big_real(sc, sc->mpfr_1));
17228 
17229     case T_BIG_COMPLEX:
17230       if ((MPC_INEX_IM(mpc_cmp_si_si(big_complex(x), 1, 350))) > 0)
17231 	return(s7_make_complex(sc, 0.0, 1.0));
17232       if ((MPC_INEX_IM(mpc_cmp_si_si(big_complex(x), 1, -350))) < 0)
17233 	return(s7_make_complex(sc, 0.0, -1.0));
17234       mpc_tan(sc->mpc_1, big_complex(x), MPC_RNDNN);
17235       if (mpfr_zero_p(mpc_imagref(sc->mpc_1)))
17236 	return(mpfr_to_big_real(sc, mpc_realref(sc->mpc_1)));
17237       return(mpc_to_number(sc, sc->mpc_1));
17238 #endif
17239 
17240     default:
17241       return(method_or_bust_with_type_one_arg_p(sc, x, sc->tan_symbol, a_number_string));
17242     }
17243 }
17244 
17245 static s7_pointer g_tan(s7_scheme *sc, s7_pointer args)
17246 {
17247   #define H_tan "(tan z) returns tan(z)"
17248   #define Q_tan sc->pl_nn
17249   return(tan_p_p(sc, car(args)));
17250 }
17251 
17252 static s7_double tan_d_d(s7_double x) {return(tan(x));}
17253 
17254 
17255 /* -------------------------------- asin -------------------------------- */
17256 static s7_pointer c_asin(s7_scheme *sc, s7_double x)
17257 {
17258   s7_double absx, recip;
17259   s7_complex result;
17260 
17261   absx = fabs(x);
17262   if (absx <= 1.0)
17263     return(make_real(sc, asin(x)));
17264 
17265   /* otherwise use maxima code: */
17266   recip = 1.0 / absx;
17267   result = (M_PI / 2.0) - (_Complex_I * clog(absx * (1.0 + (sqrt(1.0 + recip) * csqrt(1.0 - recip)))));
17268   return((x < 0.0) ? c_complex_to_s7(sc, -result) : c_complex_to_s7(sc, result));
17269 }
17270 
17271 static s7_pointer asin_p_p(s7_scheme *sc, s7_pointer p)
17272 {
17273   if (is_t_real(p)) return(c_asin(sc, real(p)));
17274   switch (type(p))
17275     {
17276     case T_INTEGER:
17277       if (integer(p) == 0) return(int_zero);                    /* (asin 0) -> 0 */
17278       /* in netBSD, (asin 2) returns 0.25383842987008+0.25383842987008i according to Peter Bex */
17279       return(c_asin(sc, (s7_double)integer(p)));
17280 
17281     case T_RATIO:
17282       return(c_asin(sc, fraction(p)));
17283 
17284     case T_COMPLEX:
17285 #if HAVE_COMPLEX_NUMBERS
17286       /* if either real or imag part is very large, use explicit formula, not casin */
17287       /*   this code taken from sbcl's src/code/irrat.lisp; break is around x+70000000i */
17288       if ((fabs(real_part(p)) > 1.0e7) ||
17289 	  (fabs(imag_part(p)) > 1.0e7))
17290 	{
17291 	  s7_complex sq1mz, sq1pz, z;
17292 	  z = to_c_complex(p);
17293 	  sq1mz = csqrt(1.0 - z);
17294 	  sq1pz = csqrt(1.0 + z);
17295 	  return(s7_make_complex(sc, atan(real_part(p) / creal(sq1mz * sq1pz)), asinh(cimag(sq1pz * conj(sq1mz)))));
17296 	}
17297       return(c_complex_to_s7(sc, casin(to_c_complex(p))));
17298 #else
17299       return(out_of_range(sc, sc->asin_symbol, int_one, p, no_complex_numbers_string));
17300 #endif
17301 
17302 #if WITH_GMP
17303     case T_BIG_INTEGER:
17304       mpfr_set_z(sc->mpfr_1, big_integer(p), MPFR_RNDN);
17305       goto ASIN_BIG_REAL;
17306 
17307     case T_BIG_RATIO:
17308       mpfr_set_q(sc->mpfr_1, big_ratio(p), MPFR_RNDN);
17309       goto ASIN_BIG_REAL;
17310 
17311     case T_BIG_REAL:
17312       if (mpfr_inf_p(big_real(p)))
17313 	{
17314 	  if (mpfr_cmp_ui(big_real(p), 0) < 0)
17315 	    return(make_complex_unchecked(sc, NAN, INFINITY)); /* match non-bignum choice */
17316 	  return(make_complex_unchecked(sc, NAN, -INFINITY));
17317 	}
17318       mpfr_set(sc->mpfr_1, big_real(p), MPFR_RNDN);
17319     ASIN_BIG_REAL:
17320       mpfr_set_ui(sc->mpfr_2, 1, MPFR_RNDN);
17321       if (mpfr_cmpabs(sc->mpfr_1, sc->mpfr_2) <= 0)
17322 	{
17323 	  mpfr_asin(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17324 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
17325 	}
17326       mpc_set_fr(sc->mpc_1, sc->mpfr_1, MPC_RNDNN);
17327       mpc_asin(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17328       return(mpc_to_number(sc, sc->mpc_1));
17329 
17330     case T_BIG_COMPLEX:
17331       mpc_asin(sc->mpc_1, big_complex(p), MPC_RNDNN);
17332       return(mpc_to_number(sc, sc->mpc_1));
17333 #endif
17334 
17335     default:
17336       return(method_or_bust_with_type_one_arg_p(sc, p, sc->asin_symbol, a_number_string));
17337     }
17338 }
17339 
17340 static s7_pointer g_asin(s7_scheme *sc, s7_pointer args)
17341 {
17342   #define H_asin "(asin z) returns asin(z); (sin (asin x)) = x"
17343   #define Q_asin sc->pl_nn
17344   return(asin_p_p(sc, car(args)));
17345 }
17346 
17347 
17348 /* -------------------------------- acos -------------------------------- */
17349 static s7_pointer c_acos(s7_scheme *sc, s7_double x)
17350 {
17351   s7_double absx, recip;
17352   s7_complex result;
17353 
17354   absx = fabs(x);
17355   if (absx <= 1.0)
17356     return(make_real(sc, acos(x)));
17357 
17358   /* else follow maxima again: */
17359   recip = 1.0 / absx;
17360   if (x > 0.0)
17361     result = _Complex_I * clog(absx * (1.0 + (sqrt(1.0 + recip) * csqrt(1.0 - recip))));
17362   else result = M_PI - _Complex_I * clog(absx * (1.0 + (sqrt(1.0 + recip) * csqrt(1.0 - recip))));
17363   return(c_complex_to_s7(sc, result));
17364 }
17365 
17366 static s7_pointer g_acos(s7_scheme *sc, s7_pointer args)
17367 {
17368   #define H_acos "(acos z) returns acos(z); (cos (acos 1)) = 1"
17369   #define Q_acos sc->pl_nn
17370   s7_pointer p;
17371 
17372   p = car(args);
17373   switch (type(p))
17374     {
17375     case T_INTEGER:
17376       return((integer(p) == 1) ? int_zero : c_acos(sc, (s7_double)integer(p)));
17377 
17378     case T_RATIO:
17379       return(c_acos(sc, fraction(p)));
17380 
17381     case T_REAL:
17382       return(c_acos(sc, real(p)));
17383 
17384     case T_COMPLEX:
17385 #if HAVE_COMPLEX_NUMBERS
17386       /* if either real or imag part is very large, use explicit formula, not cacos */
17387       /*   this code taken from sbcl's src/code/irrat.lisp */
17388 
17389       if ((fabs(real_part(p)) > 1.0e7) ||
17390 	  (fabs(imag_part(p)) > 1.0e7))
17391 	{
17392 	  s7_complex sq1mz, sq1pz, z;
17393 	  z = to_c_complex(p);
17394 	  sq1mz = csqrt(1.0 - z);
17395 	  sq1pz = csqrt(1.0 + z);	  /* creal(sq1pz) can be 0.0 */
17396 	  if (creal(sq1pz) == 0.0)        /* so the atan arg will be inf, so the real part will be pi/2(?) */
17397 	    return(s7_make_complex(sc, M_PI / 2.0, asinh(cimag(sq1mz * conj(sq1pz)))));
17398 	  return(s7_make_complex(sc, 2.0 * atan(creal(sq1mz) / creal(sq1pz)), asinh(cimag(sq1mz * conj(sq1pz)))));
17399 	}
17400       return(c_complex_to_s7(sc, cacos(s7_to_c_complex(p))));
17401 #else
17402       return(out_of_range(sc, sc->acos_symbol, int_one, p, no_complex_numbers_string));
17403 #endif
17404 
17405 #if WITH_GMP
17406     case T_BIG_INTEGER:
17407       mpfr_set_z(sc->mpfr_1, big_integer(p), MPFR_RNDN);
17408       goto ACOS_BIG_REAL;
17409 
17410     case T_BIG_RATIO:
17411       mpfr_set_q(sc->mpfr_1, big_ratio(p), MPFR_RNDN);
17412       goto ACOS_BIG_REAL;
17413 
17414     case T_BIG_REAL:
17415       if (mpfr_inf_p(big_real(p)))
17416 	{
17417 	  if (mpfr_cmp_ui(big_real(p), 0) < 0)
17418 	    return(make_complex_unchecked(sc, -NAN, -INFINITY)); /* match non-bignum choice */
17419 	  return(make_complex_unchecked(sc, -NAN, INFINITY));
17420 	}
17421       mpfr_set(sc->mpfr_1, big_real(p), MPFR_RNDN);
17422     ACOS_BIG_REAL:
17423       mpfr_set_ui(sc->mpfr_2, 1, MPFR_RNDN);
17424       if (mpfr_cmpabs(sc->mpfr_1, sc->mpfr_2) <= 0)
17425 	{
17426 	  mpfr_acos(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17427 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
17428 	}
17429       mpc_set_fr(sc->mpc_1, sc->mpfr_1, MPC_RNDNN);
17430       mpc_acos(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17431       return(mpc_to_number(sc, sc->mpc_1));
17432 
17433     case T_BIG_COMPLEX:
17434       mpc_acos(sc->mpc_1, big_complex(p), MPC_RNDNN);
17435       return(mpc_to_number(sc, sc->mpc_1));
17436 #endif
17437 
17438     default:
17439       return(method_or_bust_with_type_one_arg_p(sc, p, sc->acos_symbol, a_number_string));
17440     }
17441 }
17442 
17443 
17444 /* -------------------------------- atan -------------------------------- */
17445 static s7_pointer g_atan(s7_scheme *sc, s7_pointer args)
17446 {
17447   #define H_atan "(atan z) returns atan(z), (atan y x) returns atan(y/x)"
17448   #define Q_atan s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_number_symbol, sc->is_real_symbol)
17449   /* actually if there are two args, both should be real, but how to express that in the signature? */
17450   s7_pointer x, y;
17451 
17452   /* currently (atan inf.0 inf.0) -> 0.78539816339745, and (atan inf.0 -inf.0) -> 2.3561944901923 (etc) */
17453 
17454   x = car(args);
17455   if (!is_pair(cdr(args)))
17456     {
17457       switch (type(x))
17458 	{
17459 	case T_INTEGER:
17460 	  return((integer(x) == 0) ? int_zero : make_real(sc, atan((double)integer(x))));
17461 
17462 	case T_RATIO:
17463 	  return(make_real(sc, atan(fraction(x))));
17464 
17465 	case T_REAL:
17466 	  return(make_real(sc, atan(real(x))));
17467 
17468 	case T_COMPLEX:
17469 #if HAVE_COMPLEX_NUMBERS
17470 	  return(c_complex_to_s7(sc, catan(to_c_complex(x))));
17471 #else
17472 	  return(out_of_range(sc, sc->atan_symbol, int_one, x, no_complex_numbers_string));
17473 #endif
17474 
17475 #if WITH_GMP
17476 	case T_BIG_INTEGER:
17477 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
17478 	  mpfr_atan(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17479 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
17480 
17481 	case T_BIG_RATIO:
17482 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
17483 	  mpfr_atan(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17484 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
17485 
17486 	case T_BIG_REAL:
17487 	  mpfr_atan(sc->mpfr_1, big_real(x), MPFR_RNDN);
17488 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
17489 
17490 	case T_BIG_COMPLEX:
17491 	  mpc_atan(sc->mpc_1, big_complex(x), MPC_RNDNN);
17492 	  return(mpc_to_number(sc, sc->mpc_1));
17493 #endif
17494 	default:
17495 	  return(method_or_bust_with_type_one_arg(sc, x, sc->atan_symbol, args, a_number_string));
17496 	}}
17497 
17498   y = cadr(args);
17499   switch (type(x))
17500     {
17501     case T_INTEGER: case T_RATIO: case T_REAL:
17502       if (is_small_real(y))
17503 	return(make_real(sc, atan2(s7_real(x), s7_real(y))));
17504 #if WITH_GMP
17505       if (!s7_is_real(y))
17506 	return(method_or_bust(sc, y, sc->atan_symbol, args, T_REAL, 2));
17507       mpfr_set_d(sc->mpfr_1, s7_real(x), MPFR_RNDN);
17508       goto ATAN2_BIG_REAL;
17509     case T_BIG_INTEGER:
17510       mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
17511       goto ATAN2_BIG_REAL;
17512     case T_BIG_RATIO:
17513       mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
17514       goto ATAN2_BIG_REAL;
17515     case T_BIG_REAL:
17516       mpfr_set(sc->mpfr_1, big_real(x), MPFR_RNDN);
17517       goto ATAN2_BIG_REAL;
17518 #endif
17519     default:
17520       return(method_or_bust(sc, x, sc->atan_symbol, args, T_REAL, 1));
17521     }
17522 #if WITH_GMP
17523  ATAN2_BIG_REAL:
17524   if (is_small_real(y))
17525     mpfr_set_d(sc->mpfr_2, s7_real(y), MPFR_RNDN);
17526   else
17527     {
17528       if (is_t_big_real(y))
17529 	mpfr_set(sc->mpfr_2, big_real(y), MPFR_RNDN);
17530       else
17531 	{
17532 	  if (is_t_big_integer(y))
17533 	    mpfr_set_z(sc->mpfr_2, big_integer(y), MPFR_RNDN);
17534 	  else
17535 	    {
17536 	      if (is_t_big_ratio(y))
17537 		mpfr_set_q(sc->mpfr_2, big_ratio(y), MPFR_RNDN);
17538 	      else return(method_or_bust(sc, y, sc->atan_symbol, args, T_REAL, 2));
17539 	    }}}
17540   mpfr_atan2(sc->mpfr_1, sc->mpfr_1, sc->mpfr_2, MPFR_RNDN);
17541   return(mpfr_to_big_real(sc, sc->mpfr_1));
17542 #endif
17543 }
17544 
17545 static s7_double atan_d_dd(s7_double x, s7_double y) {return(atan2(x, y));}
17546 
17547 
17548 /* -------------------------------- sinh -------------------------------- */
17549 static s7_pointer g_sinh(s7_scheme *sc, s7_pointer args)
17550 {
17551   #define H_sinh "(sinh z) returns sinh(z)"
17552   #define Q_sinh sc->pl_nn
17553 
17554   s7_pointer x;
17555   x = car(args);
17556   switch (type(x))
17557     {
17558     case T_INTEGER:
17559       if (integer(x) == 0) return(int_zero);                    /* (sinh 0) -> 0 */
17560 
17561     case T_REAL:
17562     case T_RATIO:
17563       {
17564 	s7_double y;
17565 	y = s7_real(x);
17566 #if WITH_GMP
17567 	if (fabs(y) > SINH_LIMIT)
17568 	  {
17569 	    mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
17570 	    mpfr_sinh(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17571 	    return(mpfr_to_big_real(sc, sc->mpfr_1));
17572 	  }
17573 #endif
17574 	return(make_real(sc, sinh(y)));
17575       }
17576 
17577     case T_COMPLEX:
17578 #if WITH_GMP
17579       if ((fabs(real_part(x)) > SINH_LIMIT) || (fabs(imag_part(x)) > SINH_LIMIT))
17580 	{
17581 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
17582 	  mpc_sinh(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17583 	  return(mpc_to_number(sc, sc->mpc_1));
17584 	}
17585 #endif
17586 
17587 #if HAVE_COMPLEX_NUMBERS
17588       return(c_complex_to_s7(sc, csinh(to_c_complex(x))));
17589 #else
17590       return(out_of_range(sc, sc->sinh_symbol, int_one, x, no_complex_numbers_string));
17591 #endif
17592 
17593 #if WITH_GMP
17594     case T_BIG_INTEGER:
17595       mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
17596       mpfr_sinh(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17597       return(mpfr_to_big_real(sc, sc->mpfr_1));
17598 
17599     case T_BIG_RATIO:
17600       mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
17601       mpfr_sinh(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17602       return(mpfr_to_big_real(sc, sc->mpfr_1));
17603 
17604     case T_BIG_REAL:
17605       mpfr_sinh(sc->mpfr_1, big_real(x), MPFR_RNDN);
17606       return(mpfr_to_big_real(sc, sc->mpfr_1));
17607 
17608     case T_BIG_COMPLEX:
17609       mpc_sinh(sc->mpc_1, big_complex(x), MPC_RNDNN);
17610       if (mpfr_zero_p(mpc_imagref(sc->mpc_1)))
17611 	return(mpfr_to_big_real(sc, mpc_realref(sc->mpc_1)));
17612       return(mpc_to_number(sc, sc->mpc_1));
17613 #endif
17614 
17615     default:
17616       return(method_or_bust_with_type_one_arg(sc, x, sc->sinh_symbol, args, a_number_string));
17617     }
17618 }
17619 
17620 #if (!WITH_GMP)
17621 static s7_double sinh_d_d(s7_double x) {return(sinh(x));}
17622 #endif
17623 
17624 
17625 /* -------------------------------- cosh -------------------------------- */
17626 static s7_pointer g_cosh(s7_scheme *sc, s7_pointer args)
17627 {
17628   #define H_cosh "(cosh z) returns cosh(z)"
17629   #define Q_cosh sc->pl_nn
17630 
17631   s7_pointer x;
17632   x = car(args);
17633   switch (type(x))
17634     {
17635     case T_INTEGER:
17636       if (integer(x) == 0) return(int_one);                   /* (cosh 0) -> 1 */
17637 
17638     case T_REAL:
17639     case T_RATIO:
17640       {
17641 	s7_double y;
17642 	y = s7_real(x);
17643 #if WITH_GMP
17644 	if (fabs(y) > SINH_LIMIT)
17645 	  {
17646 	    mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
17647 	    mpfr_cosh(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17648 	    return(mpfr_to_big_real(sc, sc->mpfr_1));
17649 	  }
17650 #endif
17651 	return(make_real(sc, cosh(y)));
17652       }
17653 
17654     case T_COMPLEX:
17655 #if WITH_GMP
17656       if ((fabs(real_part(x)) > SINH_LIMIT) || (fabs(imag_part(x)) > SINH_LIMIT))
17657 	{
17658 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
17659 	  mpc_cosh(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17660 	  return(mpc_to_number(sc, sc->mpc_1));
17661 	}
17662 #endif
17663 #if HAVE_COMPLEX_NUMBERS
17664       return(c_complex_to_s7(sc, ccosh(to_c_complex(x))));
17665 #else
17666       return(out_of_range(sc, sc->cosh_symbol, int_one, x, no_complex_numbers_string));
17667 #endif
17668 
17669 #if WITH_GMP
17670     case T_BIG_INTEGER:
17671       mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
17672       mpfr_cosh(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17673       return(mpfr_to_big_real(sc, sc->mpfr_1));
17674 
17675     case T_BIG_RATIO:
17676       mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
17677       mpfr_cosh(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17678       return(mpfr_to_big_real(sc, sc->mpfr_1));
17679 
17680     case T_BIG_REAL:
17681       mpfr_cosh(sc->mpfr_1, big_real(x), MPFR_RNDN);
17682       return(mpfr_to_big_real(sc, sc->mpfr_1));
17683 
17684     case T_BIG_COMPLEX:
17685       mpc_cosh(sc->mpc_1, big_complex(x), MPC_RNDNN);
17686       if (mpfr_zero_p(mpc_imagref(sc->mpc_1)))
17687 	return(mpfr_to_big_real(sc, mpc_realref(sc->mpc_1)));
17688       return(mpc_to_number(sc, sc->mpc_1));
17689 #endif
17690 
17691     default:
17692       return(method_or_bust_with_type_one_arg(sc, x, sc->cosh_symbol, args, a_number_string));
17693     }
17694 }
17695 
17696 #if (!WITH_GMP)
17697 static s7_double cosh_d_d(s7_double x) {return(cosh(x));}
17698 #endif
17699 
17700 
17701 /* -------------------------------- tanh -------------------------------- */
17702 #define TANH_LIMIT 350.0
17703 static s7_pointer g_tanh(s7_scheme *sc, s7_pointer args)
17704 {
17705   #define H_tanh "(tanh z) returns tanh(z)"
17706   #define Q_tanh sc->pl_nn
17707 
17708   s7_pointer x;
17709   x = car(args);
17710   switch (type(x))
17711     {
17712     case T_INTEGER:
17713       if (integer(x) == 0) return(int_zero);  /* (tanh 0) -> 0 */
17714 
17715     case T_REAL:
17716     case T_RATIO:
17717       return(make_real(sc, tanh(s7_real(x))));
17718 
17719     case T_COMPLEX:
17720 #if HAVE_COMPLEX_NUMBERS
17721       if (real_part(x) > TANH_LIMIT)
17722 	return(real_one);                         /* closer than 0.0 which is what ctanh is about to return! */
17723       if (real_part(x) < -TANH_LIMIT)
17724 	return(make_real(sc, -1.0));              /* closer than ctanh's -0.0 */
17725       return(c_complex_to_s7(sc, ctanh(to_c_complex(x))));
17726 #else
17727       return(out_of_range(sc, sc->tanh_symbol, int_one, x, no_complex_numbers_string));
17728 #endif
17729 
17730 #if WITH_GMP
17731     case T_BIG_INTEGER:
17732       mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
17733       goto BIG_REAL_TANH;
17734 
17735     case T_BIG_RATIO:
17736       mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
17737       goto BIG_REAL_TANH;
17738 
17739     case T_BIG_REAL:
17740       if (mpfr_nan_p(big_real(x))) return(real_NaN);
17741       mpfr_set(sc->mpfr_1, big_real(x), MPFR_RNDN);
17742 
17743     BIG_REAL_TANH:
17744       if (mpfr_cmp_d(sc->mpfr_1, TANH_LIMIT) > 0) return(real_one);
17745       if (mpfr_cmp_d(sc->mpfr_1, -TANH_LIMIT) < 0) return(make_real(sc, -1.0));
17746       mpfr_tanh(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17747       return(mpfr_to_big_real(sc, sc->mpfr_1));
17748 
17749     case T_BIG_COMPLEX:
17750       if ((MPC_INEX_RE(mpc_cmp_si_si(big_complex(x), TANH_LIMIT, 1))) > 0)
17751 	return(real_one);
17752       if ((MPC_INEX_RE(mpc_cmp_si_si(big_complex(x), -TANH_LIMIT, 1))) < 0)
17753 	return(make_real(sc, -1.0));
17754 
17755       if ((mpfr_nan_p(mpc_imagref(big_complex(x)))) ||
17756 	  (mpfr_inf_p(mpc_imagref(big_complex(x)))))
17757 	{
17758 	  if (mpfr_cmp_ui(mpc_realref(big_complex(x)), 0) == 0)
17759 	    return(make_complex_unchecked(sc, 0.0, NAN)); /* match non-bignum choice */
17760 	  return(complex_NaN);
17761 	}
17762 
17763       mpc_tanh(sc->mpc_1, big_complex(x), MPC_RNDNN);
17764       if (mpfr_zero_p(mpc_imagref(sc->mpc_1)))
17765 	return(mpfr_to_big_real(sc, mpc_realref(sc->mpc_1)));
17766       return(mpc_to_number(sc, sc->mpc_1));
17767 #endif
17768 
17769     default:
17770       return(method_or_bust_with_type_one_arg(sc, x, sc->tanh_symbol, args, a_number_string));
17771     }
17772 }
17773 
17774 static s7_double tanh_d_d(s7_double x) {return(tanh(x));}
17775 
17776 
17777 /* -------------------------------- asinh -------------------------------- */
17778 
17779 static s7_pointer g_asinh(s7_scheme *sc, s7_pointer args)
17780 {
17781   #define H_asinh "(asinh z) returns asinh(z)"
17782   #define Q_asinh sc->pl_nn
17783   s7_pointer x;
17784   x = car(args);
17785   switch (type(x))
17786     {
17787     case T_INTEGER:
17788       return((integer(x) == 0) ? int_zero : make_real(sc, asinh((s7_double)integer(x))));
17789 
17790     case T_RATIO:
17791       return(make_real(sc, asinh(fraction(x))));
17792 
17793     case T_REAL:
17794       return(make_real(sc, asinh(real(x))));
17795 
17796     case T_COMPLEX:
17797 #if HAVE_COMPLEX_NUMBERS
17798   #if (defined(__OpenBSD__)) || (defined(__NetBSD__))
17799       return(c_complex_to_s7(sc, casinh_1(to_c_complex(x))));
17800   #else
17801       return(c_complex_to_s7(sc, casinh(to_c_complex(x))));
17802   #endif
17803 #else
17804       return(out_of_range(sc, sc->asinh_symbol, int_one, x, no_complex_numbers_string));
17805 #endif
17806 
17807 #if WITH_GMP
17808     case T_BIG_INTEGER:
17809       mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
17810       mpfr_asinh(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17811       return(mpfr_to_big_real(sc, sc->mpfr_1));
17812 
17813     case T_BIG_RATIO:
17814       mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
17815       mpfr_asinh(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17816       return(mpfr_to_big_real(sc, sc->mpfr_1));
17817 
17818     case T_BIG_REAL:
17819       mpfr_asinh(sc->mpfr_1, big_real(x), MPFR_RNDN);
17820       return(mpfr_to_big_real(sc, sc->mpfr_1));
17821 
17822     case T_BIG_COMPLEX:
17823       mpc_asinh(sc->mpc_1, big_complex(x), MPC_RNDNN);
17824       return(mpc_to_number(sc, sc->mpc_1));
17825 #endif
17826 
17827     default:
17828       return(method_or_bust_with_type_one_arg_p(sc, x, sc->asinh_symbol, a_number_string));
17829     }
17830 }
17831 
17832 
17833 /* -------------------------------- acosh -------------------------------- */
17834 static s7_pointer g_acosh(s7_scheme *sc, s7_pointer args)
17835 {
17836   #define H_acosh "(acosh z) returns acosh(z)"
17837   #define Q_acosh sc->pl_nn
17838   s7_pointer x;
17839   x = car(args);
17840   switch (type(x))
17841     {
17842     case T_INTEGER:
17843       if (integer(x) == 1) return(int_zero);
17844 
17845     case T_REAL:
17846     case T_RATIO:
17847       {
17848 	double x1;
17849 	x1 = s7_real(x);
17850 	if (x1 >= 1.0)
17851 	  return(make_real(sc, acosh(x1)));
17852       }
17853 
17854     case T_COMPLEX:
17855 #if HAVE_COMPLEX_NUMBERS
17856   #ifdef __OpenBSD__
17857       return(c_complex_to_s7(sc, cacosh_1(s7_to_c_complex(x))));
17858   #else
17859       return(c_complex_to_s7(sc, cacosh(s7_to_c_complex(x)))); /* not to_c_complex because x might not be complex */
17860   #endif
17861 #else
17862       /* since we can fall through to this branch, we need a better error message than "must be a number, not 0.0" */
17863       return(out_of_range(sc, sc->acosh_symbol, int_one, x, no_complex_numbers_string));
17864 #endif
17865 
17866 #if WITH_GMP
17867     case T_BIG_INTEGER:
17868       mpc_set_z(sc->mpc_1, big_integer(x), MPC_RNDNN);
17869       mpc_acosh(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17870       return(mpc_to_number(sc, sc->mpc_1));
17871 
17872     case T_BIG_RATIO:
17873       mpc_set_q(sc->mpc_1, big_ratio(x), MPC_RNDNN);
17874       mpc_acosh(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17875       return(mpc_to_number(sc, sc->mpc_1));
17876 
17877     case T_BIG_REAL:
17878       mpc_set_fr(sc->mpc_1, big_real(x), MPC_RNDNN);
17879       mpc_acosh(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17880       return(mpc_to_number(sc, sc->mpc_1));
17881 
17882     case T_BIG_COMPLEX:
17883       mpc_acosh(sc->mpc_1, big_complex(x), MPC_RNDNN);
17884       return(mpc_to_number(sc, sc->mpc_1));
17885 #endif
17886 
17887     default:
17888       return(method_or_bust_with_type_one_arg_p(sc, x, sc->acosh_symbol, a_number_string));
17889     }
17890 }
17891 
17892 
17893 /* -------------------------------- atanh -------------------------------- */
17894 static s7_pointer g_atanh(s7_scheme *sc, s7_pointer args)
17895 {
17896   #define H_atanh "(atanh z) returns atanh(z)"
17897   #define Q_atanh sc->pl_nn
17898   s7_pointer x;
17899   x = car(args);
17900   switch (type(x))
17901     {
17902     case T_INTEGER:
17903       if (integer(x) == 0) return(int_zero);                    /* (atanh 0) -> 0 */
17904 
17905     case T_REAL:
17906     case T_RATIO:
17907       {
17908 	double x1;
17909 	x1 = s7_real(x);
17910 	if (fabs(x1) < 1.0)
17911 	  return(make_real(sc, atanh(x1)));
17912       }
17913       /* if we can't distinguish x from 1.0 even with long_doubles, we'll get inf.0:
17914        *    (atanh 9223372036854775/9223372036854776) -> 18.714973875119
17915        *    (atanh 92233720368547758/92233720368547757) -> inf.0
17916        *    (atanh (bignum 92233720368547758/92233720368547757)) -> 1.987812468492420421418925013176932317086E1+1.570796326794896619231321691639751442098E0i
17917        *    but the imaginary part is unnecessary
17918        */
17919     case T_COMPLEX:
17920 #if HAVE_COMPLEX_NUMBERS
17921   #if (defined(__OpenBSD__)) || (defined(__NetBSD__))
17922       return(c_complex_to_s7(sc, catanh_1(s7_to_c_complex(x))));
17923   #else
17924       return(c_complex_to_s7(sc, catanh(s7_to_c_complex(x))));
17925   #endif
17926 #else
17927       return(out_of_range(sc, sc->atanh_symbol, int_one, x, no_complex_numbers_string));
17928 #endif
17929 
17930 #if WITH_GMP
17931     case T_BIG_INTEGER:
17932       mpfr_set_z(sc->mpfr_2, big_integer(x), MPFR_RNDN);
17933       goto ATANH_BIG_REAL;
17934 
17935     case T_BIG_RATIO:
17936       mpfr_set_q(sc->mpfr_2, big_ratio(x), MPFR_RNDN);
17937       goto ATANH_BIG_REAL;
17938 
17939     case T_BIG_REAL:
17940       mpfr_set(sc->mpfr_2, big_real(x), MPFR_RNDN);
17941     ATANH_BIG_REAL:
17942       mpfr_set_ui(sc->mpfr_1, 1, MPFR_RNDN);
17943       if (mpfr_cmpabs(sc->mpfr_2, sc->mpfr_1) < 0)
17944 	{
17945 	  mpfr_atanh(sc->mpfr_2, sc->mpfr_2, MPFR_RNDN);
17946 	  return(mpfr_to_big_real(sc, sc->mpfr_2));
17947 	}
17948       mpc_set_fr(sc->mpc_1, sc->mpfr_2, MPC_RNDNN);
17949       mpc_atanh(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17950       return(mpc_to_number(sc, sc->mpc_1));
17951 
17952     case T_BIG_COMPLEX:
17953       mpc_atanh(sc->mpc_1, big_complex(x), MPC_RNDNN);
17954       return(mpc_to_number(sc, sc->mpc_1));
17955 #endif
17956 
17957     default:
17958       return(method_or_bust_with_type_one_arg_p(sc, x, sc->atanh_symbol, a_number_string));
17959     }
17960 }
17961 
17962 
17963 /* -------------------------------- sqrt -------------------------------- */
17964 
17965 static s7_pointer sqrt_p_p(s7_scheme *sc, s7_pointer p)
17966 {
17967   switch (type(p))
17968     {
17969     case T_INTEGER:
17970       {
17971 	s7_double sqx;
17972 	if (integer(p) >= 0)
17973 	  {
17974 	    s7_int ix;
17975 #if WITH_GMP
17976 	    mpz_set_si(sc->mpz_1, integer(p));
17977 	    mpz_sqrtrem(sc->mpz_1, sc->mpz_2, sc->mpz_1);
17978 	    if (mpz_cmp_ui(sc->mpz_2, 0) == 0)
17979 	      return(make_integer(sc, mpz_get_si(sc->mpz_1)));
17980 	    mpfr_set_si(sc->mpfr_1, integer(p), MPFR_RNDN);
17981 	    mpfr_sqrt(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
17982 	    return(mpfr_to_big_real(sc, sc->mpfr_1));
17983 #endif
17984 	    sqx = sqrt((s7_double)integer(p));
17985 	    ix = (s7_int)sqx;
17986 	    return(((ix * ix) == integer(p)) ? make_integer(sc, ix) : make_real(sc, sqx));
17987 	    /* Mark Weaver notes that (zero? (- (sqrt 9007199136250226) 94906265.0)) -> #t
17988 	     * but (* 94906265 94906265) -> 9007199136250225 -- oops
17989 	     * if we use bigfloats, we're ok:
17990 	     *    (* (sqrt 9007199136250226.0) (sqrt 9007199136250226.0)) -> 9.007199136250226000000000000000000000026E15
17991 	     * at least we return a real here, not an incorrect integer and (sqrt 9007199136250225) -> 94906265
17992 	     */
17993 	  }
17994 #if HAVE_COMPLEX_NUMBERS
17995 #if WITH_GMP
17996 	mpc_set_si(sc->mpc_1, integer(p), MPC_RNDNN);
17997 	mpc_sqrt(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
17998 	return(mpc_to_number(sc, sc->mpc_1));
17999 #endif
18000 	sqx = (s7_double)integer(p); /* we're trying to protect against (sqrt -9223372036854775808) where we can't negate the integer argument */
18001 	return(s7_make_complex(sc, 0.0, sqrt((s7_double)(-sqx))));
18002 #else
18003 	return(out_of_range(sc, sc->sqrt_symbol, int_one, p, no_complex_numbers_string));
18004 #endif
18005       }
18006 
18007     case T_RATIO:
18008       if (numerator(p) > 0) /* else it's complex, so it can't be a ratio */
18009 	{
18010 	  s7_int nm;
18011 	  nm = (s7_int)sqrt(numerator(p));
18012 	  if (nm * nm == numerator(p))
18013 	    {
18014 	      s7_int dn;
18015 	      dn = (s7_int)sqrt(denominator(p));
18016 	      if (dn * dn == denominator(p))
18017 		return(s7_make_ratio(sc, nm, dn));
18018 	    }
18019 	  return(make_real(sc, sqrt((s7_double)fraction(p))));
18020 	}
18021 #if HAVE_COMPLEX_NUMBERS
18022       return(s7_make_complex(sc, 0.0, sqrt((s7_double)(-fraction(p)))));
18023 #else
18024       return(out_of_range(sc, sc->sqrt_symbol, int_one, p, no_complex_numbers_string));
18025 #endif
18026 
18027     case T_REAL:
18028       if (is_NaN(real(p)))
18029 	return(real_NaN);
18030       if (real(p) >= 0.0)
18031 	return(make_real(sc, sqrt(real(p))));
18032       return(s7_make_complex(sc, 0.0, sqrt(-real(p))));
18033 
18034     case T_COMPLEX:    /* (* inf.0 (sqrt -1)) -> -nan+infi, but (sqrt -inf.0) -> 0+infi */
18035 #if HAVE_COMPLEX_NUMBERS
18036       return(c_complex_to_s7(sc, csqrt(to_c_complex(p)))); /* sqrt(+inf.0+1.0i) -> +inf.0 */
18037 #else
18038       return(out_of_range(sc, sc->sqrt_symbol, int_one, p, no_complex_numbers_string));
18039 #endif
18040 
18041 #if WITH_GMP
18042     case T_BIG_INTEGER:
18043       if (mpz_cmp_ui(big_integer(p), 0) >= 0)
18044 	{
18045 	  mpz_sqrtrem(sc->mpz_1, sc->mpz_2, big_integer(p));
18046 	  if (mpz_cmp_ui(sc->mpz_2, 0) == 0)
18047 	    return(mpz_to_integer(sc, sc->mpz_1));
18048 	  mpfr_set_z(sc->mpfr_1, big_integer(p), MPFR_RNDN);
18049 	  mpfr_sqrt(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
18050 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
18051 	}
18052       mpc_set_z(sc->mpc_1, big_integer(p), MPC_RNDNN);
18053       mpc_sqrt(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
18054       return(mpc_to_number(sc, sc->mpc_1));
18055 
18056     case T_BIG_RATIO: /* if big ratio, check both num and den for squares */
18057       if (mpq_cmp_ui(big_ratio(p), 0, 1) < 0)
18058 	{
18059 	  mpc_set_q(sc->mpc_1, big_ratio(p), MPC_RNDNN);
18060 	  mpc_sqrt(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
18061 	  return(mpc_to_number(sc, sc->mpc_1));
18062 	}
18063       mpz_sqrtrem(sc->mpz_1, sc->mpz_2, mpq_numref(big_ratio(p)));
18064       if (mpz_cmp_ui(sc->mpz_2, 0) == 0)
18065 	{
18066 	  mpz_sqrtrem(sc->mpz_3, sc->mpz_2, mpq_denref(big_ratio(p)));
18067 	  if (mpz_cmp_ui(sc->mpz_2, 0) == 0)
18068 	    {
18069 	      mpq_set_num(sc->mpq_1, sc->mpz_1);
18070 	      mpq_set_den(sc->mpq_1, sc->mpz_3);
18071 	      mpq_canonicalize(sc->mpq_1);
18072 	      return(mpq_to_rational(sc, sc->mpq_1));
18073 	    }}
18074       mpfr_set_q(sc->mpfr_1, big_ratio(p), MPFR_RNDN);
18075       mpfr_sqrt(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
18076       return(mpfr_to_big_real(sc, sc->mpfr_1));
18077 
18078     case T_BIG_REAL:
18079       if (mpfr_cmp_ui(big_real(p), 0) < 0)
18080 	{
18081 	  mpc_set_fr(sc->mpc_1, big_real(p), MPC_RNDNN);
18082 	  mpc_sqrt(sc->mpc_1, sc->mpc_1, MPC_RNDNN);
18083 	  return(mpc_to_number(sc, sc->mpc_1));
18084 	}
18085       mpfr_sqrt(sc->mpfr_1, big_real(p), MPFR_RNDN);
18086       return(mpfr_to_big_real(sc, sc->mpfr_1));
18087 
18088     case T_BIG_COMPLEX:
18089       mpc_sqrt(sc->mpc_1, big_complex(p), MPC_RNDNN);
18090       return(mpc_to_number(sc, sc->mpc_1));
18091 #endif
18092 
18093     default:
18094       return(method_or_bust_with_type_one_arg_p(sc, p, sc->sqrt_symbol, a_number_string));
18095     }
18096 }
18097 
18098 static s7_pointer g_sqrt(s7_scheme *sc, s7_pointer args)
18099 {
18100   #define H_sqrt "(sqrt z) returns the square root of z"
18101   #define Q_sqrt sc->pl_nn
18102   return(sqrt_p_p(sc, car(args)));
18103 }
18104 
18105 
18106 /* -------------------------------- expt -------------------------------- */
18107 
18108 static s7_int int_to_int(s7_int x, s7_int n)
18109 {
18110   /* from GSL */
18111   s7_int value = 1;
18112   do {
18113     if (n & 1) value *= x;
18114     n >>= 1;
18115 #if HAVE_OVERFLOW_CHECKS
18116     if (multiply_overflow(x, x, &x))
18117       break;
18118 #else
18119     x *= x;
18120 #endif
18121   } while (n);
18122   return(value);
18123 }
18124 
18125 static const int64_t nth_roots[63] = {
18126   S7_INT64_MAX, S7_INT64_MAX, 3037000499LL, 2097151, 55108, 6208, 1448, 511, 234, 127, 78, 52, 38, 28, 22,
18127   18, 15, 13, 11, 9, 8, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2,
18128   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
18129 
18130 static bool int_pow_ok(s7_int x, s7_int y)
18131 {
18132   return((y < S7_INT_BITS) && (nth_roots[y] >= s7_int_abs(x)));
18133 }
18134 
18135 #if WITH_GMP
18136 static s7_pointer real_part_p_p(s7_scheme *sc, s7_pointer p);
18137 static bool lt_b_pi(s7_scheme *sc, s7_pointer p1, s7_int p2);
18138 
18139 static s7_pointer big_expt(s7_scheme *sc, s7_pointer args)
18140 {
18141   s7_pointer x, y, res;
18142   x = car(args);
18143   if (!s7_is_number(x))
18144     return(method_or_bust_with_type(sc, x, sc->expt_symbol, args, a_number_string, 1));
18145 
18146   y = cadr(args);
18147   if (!s7_is_number(y))
18148     return(method_or_bust_with_type(sc, y, sc->expt_symbol, args, a_number_string, 2));
18149 
18150   if (s7_is_zero(x))
18151     {
18152       if ((s7_is_integer(x)) &&
18153 	  (s7_is_integer(y)) &&
18154 	  (s7_is_zero(y)))
18155 	return(int_one);
18156 
18157       if (s7_is_real(y))
18158 	{
18159 	  if (s7_is_negative(y))
18160 	    return(division_by_zero_error(sc, sc->expt_symbol, args));
18161 	}
18162       else
18163 	if (s7_is_negative(real_part_p_p(sc, y))) /* handle big_complex as well as complex */
18164 	  return(division_by_zero_error(sc, sc->expt_symbol, args));
18165 
18166       if ((s7_is_rational(x)) &&
18167 	  (s7_is_rational(y)))
18168 	return(int_zero);
18169       return(real_zero);
18170     }
18171 
18172   if (s7_is_integer(y))
18173     {
18174       s7_int yval;
18175       yval = s7_integer_checked(sc, y);
18176       if (yval == 0)
18177 	return((s7_is_rational(x)) ? int_one : real_one);
18178 
18179       if (yval == 1)
18180 	return(x);
18181 
18182       if (!is_big_number(x))
18183 	{
18184 	  if ((s7_is_one(x)) || (s7_is_zero(x)))
18185 	    return(x);
18186 	}
18187 
18188       if ((yval < S7_INT32_MAX) &&
18189 	  (yval > S7_INT32_MIN))
18190 	{
18191 	  /* (protect against gmp exception if for example (expt 1/9223372036854775807 -9223372036854775807) */
18192 	  if (s7_is_integer(x))
18193 	    {
18194 	      if (is_t_big_integer(x))
18195 		mpz_set(sc->mpz_2, big_integer(x));
18196 	      else mpz_set_si(sc->mpz_2, integer(x));
18197 	      if (yval >= 0)
18198 		{
18199 		  mpz_pow_ui(sc->mpz_2, sc->mpz_2, (uint32_t)yval);
18200 		  return(mpz_to_integer(sc, sc->mpz_2));
18201 		}
18202 	      mpz_pow_ui(sc->mpz_2, sc->mpz_2, (uint32_t)(-yval));
18203 	      mpq_set_z(sc->mpq_1, sc->mpz_2);
18204 	      mpq_inv(sc->mpq_1, sc->mpq_1);
18205 	      if (mpz_cmp_ui(mpq_denref(sc->mpq_1), 1) == 0)
18206 		return(mpz_to_integer(sc, mpq_numref(sc->mpq_1)));
18207 	      return(mpq_to_big_ratio(sc, sc->mpq_1));
18208 	    }
18209 
18210 	  if (s7_is_ratio(x)) /* here y is an integer */
18211 	    {
18212 	      if (is_t_big_ratio(x))
18213 		{
18214 		  mpz_set(sc->mpz_1, mpq_numref(big_ratio(x)));
18215 		  mpz_set(sc->mpz_2, mpq_denref(big_ratio(x)));
18216 		}
18217 	      else
18218 		{
18219 		  mpz_set_si(sc->mpz_1, numerator(x));
18220 		  mpz_set_si(sc->mpz_2, denominator(x));
18221 		}
18222 	      if (yval >= 0)
18223 		{
18224 		  mpz_pow_ui(sc->mpz_1, sc->mpz_1, (uint32_t)yval);
18225 		  mpz_pow_ui(sc->mpz_2, sc->mpz_2, (uint32_t)yval);
18226 		  mpq_set_num(sc->mpq_1, sc->mpz_1);
18227 		  mpq_set_den(sc->mpq_1, sc->mpz_2);
18228 		}
18229 	      else
18230 		{
18231 		  yval = -yval;
18232 		  mpz_pow_ui(sc->mpz_1, sc->mpz_1, (uint32_t)yval);
18233 		  mpz_pow_ui(sc->mpz_2, sc->mpz_2, (uint32_t)yval);
18234 		  mpq_set_num(sc->mpq_1, sc->mpz_2);
18235 		  mpq_set_den(sc->mpq_1, sc->mpz_1);
18236 		  mpq_canonicalize(sc->mpq_1);
18237 		}
18238 	      if (mpz_cmp_ui(mpq_denref(sc->mpq_1), 1) == 0)
18239 		return(mpz_to_integer(sc, mpq_numref(sc->mpq_1)));
18240 	      return(mpq_to_big_ratio(sc, sc->mpq_1));
18241 	    }
18242 
18243 	  if (s7_is_real(x))
18244 	    {
18245 	      if (is_t_big_real(x))
18246 		mpfr_set(sc->mpfr_1, big_real(x), MPFR_RNDN);
18247 	      else mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
18248 	      mpfr_pow_si(sc->mpfr_1, sc->mpfr_1, yval, MPFR_RNDN);
18249 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
18250 	    }}}
18251 
18252   if ((is_t_ratio(y)) &&              /* not s7_is_ratio which accepts bignums */
18253       (numerator(y) == 1))
18254     {
18255       if (denominator(y) == 2)
18256 	return(sqrt_p_p(sc, x));
18257 
18258       if ((s7_is_real(x)) &&
18259 	  (denominator(y) == 3))
18260 	{
18261 	  any_real_to_mpfr(sc, x, sc->mpfr_1);
18262 	  mpfr_cbrt(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
18263 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
18264 	}}
18265 
18266   res = any_number_to_mpc(sc, y, sc->mpc_2);
18267   if (res == real_infinity)
18268     {
18269       if (s7_is_one(x)) return(int_one);
18270       if (s7_is_real(x))
18271 	{
18272 	  if (s7_is_zero(x))
18273 	    {
18274 	      if (s7_is_negative(y)) return(division_by_zero_error(sc, sc->expt_symbol, args));
18275 	      return(real_zero);
18276 	    }
18277 	  if (lt_b_pi(sc, x, 0))
18278 	    {
18279 	      if (lt_b_pi(sc, x, -1))
18280 		return((s7_is_positive(y)) ? real_infinity : real_zero);
18281 	      return((s7_is_positive(y)) ? real_zero : real_infinity);
18282 	    }
18283 	  if (lt_b_pi(sc, x, 1))
18284 	    return((s7_is_positive(y)) ? real_zero : real_infinity);
18285 	  return((s7_is_positive(y)) ? real_infinity : real_zero);
18286 	}
18287       return((s7_is_negative(y)) ? real_zero : complex_NaN);
18288     }
18289   if (res) return(complex_NaN);
18290 
18291   if ((s7_is_real(x)) &&
18292       (s7_is_real(y)) &&
18293       (s7_is_positive(x)))
18294     {
18295       res = any_real_to_mpfr(sc, x, sc->mpfr_1);
18296       if (res)
18297 	{
18298 	  if (res == real_infinity)
18299 	    {
18300 	      if (s7_is_negative(y)) return(real_zero);
18301 	      return((s7_is_zero(y)) ? real_one : real_infinity);
18302 	    }
18303 	  return(complex_NaN);
18304 	}
18305       mpfr_pow(sc->mpfr_1, sc->mpfr_1, mpc_realref(sc->mpc_2), MPFR_RNDN);
18306       return(mpfr_to_big_real(sc, sc->mpfr_1));
18307     }
18308 
18309   res = any_number_to_mpc(sc, x, sc->mpc_1);
18310   if (res)
18311     {
18312       if ((res == real_infinity) && (s7_is_real(y)))
18313 	{
18314 	  if (s7_is_negative(y)) return(real_zero);
18315 	  return((s7_is_zero(y)) ? real_one : real_infinity);
18316 	}
18317       return(complex_NaN);
18318     }
18319   if (mpc_cmp_si_si(sc->mpc_1, 0, 0) == 0)
18320     return(int_zero);
18321   if (mpc_cmp_si_si(sc->mpc_1, 1, 0) == 0)
18322     return(int_one);
18323 
18324   mpc_pow(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
18325 
18326   if ((!mpfr_nan_p(mpc_imagref(sc->mpc_1))) && (mpfr_cmp_ui(mpc_imagref(sc->mpc_1), 0) == 0)) /* (expt -inf.0 1/3) -> +inf.0+nan.0i in mpc */
18327     {
18328       if ((s7_is_rational(car(args))) &&
18329 	  (s7_is_rational(cadr(args))) &&
18330 	  (mpfr_integer_p(mpc_realref(sc->mpc_1)) != 0))
18331 	{
18332 	  /* mpfr_integer_p can be confused: (expt 2718/1000 (bignum 617/5)) returns an int32_t if precision=128, float if 512 */
18333 	  /*   so first make sure we're within (say) 31 bits */
18334 	  mpfr_set_ui(sc->mpfr_1, S7_INT32_MAX, MPFR_RNDN);
18335 	  if (mpfr_cmpabs(mpc_realref(sc->mpc_1), sc->mpfr_1) < 0)
18336 	    {
18337 	      mpfr_get_z(sc->mpz_1, mpc_realref(sc->mpc_1), MPFR_RNDN);
18338 	      return(mpz_to_integer(sc, sc->mpz_1));
18339 	    }}
18340       mpfr_set(sc->mpfr_1, mpc_realref(sc->mpc_1), MPFR_RNDN);
18341       return(mpfr_to_big_real(sc, sc->mpfr_1));
18342     }
18343   return(mpc_to_number(sc, sc->mpc_1));
18344 }
18345 #endif
18346 
18347 static s7_pointer g_expt(s7_scheme *sc, s7_pointer args)
18348 {
18349   #define H_expt "(expt z1 z2) returns z1^z2"
18350   #define Q_expt sc->pcl_n
18351   s7_pointer n, pw;
18352 
18353 #if WITH_GMP
18354   return(big_expt(sc, args));
18355   /* big_expt sometimes chooses a different value: g_expt (expt -1 1/3) is -1, but big_expt (expt -1 (bignum 1/3)) is (complex 1/2 (/ (sqrt 3) 2)) */
18356 #endif
18357 
18358   n = car(args);
18359   if (!s7_is_number(n))
18360     return(method_or_bust_with_type(sc, n, sc->expt_symbol, args, a_number_string, 1));
18361 
18362   pw = cadr(args);
18363   if (!s7_is_number(pw))
18364     return(method_or_bust_with_type(sc, pw, sc->expt_symbol, args, a_number_string, 2));
18365 
18366   /* this provides more than 2 args to expt:
18367    *  if (is_not_null(cddr(args))) return(g_expt(sc, list_2(sc, car(args), g_expt(sc, cdr(args)))));
18368    * but it's unusual in scheme to process args in reverse order, and the syntax by itself is ambiguous (does (expt 2 2 3) = 256 or 64?)
18369    */
18370 
18371   if (s7_is_zero(n))
18372     {
18373       if (s7_is_zero(pw))
18374 	{
18375 	  if ((s7_is_integer(n)) && (s7_is_integer(pw)))       /* (expt 0 0) -> 1 */
18376 	    return(int_one);
18377 	  return(real_zero);                                   /* (expt 0.0 0) -> 0.0 */
18378 	}
18379 
18380       if (s7_is_real(pw))
18381 	{
18382 	  if (s7_is_negative(pw))                              /* (expt 0 -1) */
18383 	    return(division_by_zero_error(sc, sc->expt_symbol, args));
18384 	  /* (Clisp gives divide-by-zero error here, Guile returns inf.0) */
18385 
18386 	  if (is_NaN(s7_real(pw)))                             /* (expt 0 +nan.0) */
18387 	    return(pw);
18388 	}
18389       else
18390 	{                                                      /* (expt 0 a+bi) */
18391 	  if (real_part(pw) < 0.0)                             /* (expt 0 -1+i) */
18392 	    return(division_by_zero_error(sc, sc->expt_symbol, args));
18393 	  if ((is_NaN(real_part(pw))) ||                       /* (expt 0 0+1/0i) */
18394 	      (is_NaN(imag_part(pw))))
18395 	    return(real_NaN);
18396 	}
18397 
18398       if ((s7_is_integer(n)) && (s7_is_integer(pw)))           /* pw != 0, (expt 0 2312) */
18399 	return(int_zero);
18400       return(real_zero);                                       /* (expt 0.0 123123) */
18401     }
18402 
18403   if (s7_is_one(pw))
18404     {
18405       if (s7_is_integer(pw))                                   /* (expt x 1) */
18406 	return(n);
18407       if (is_rational(n))                                      /* (expt ratio 1.0) */
18408 	return(make_real(sc, rational_to_double(sc, n)));
18409       return(n);
18410     }
18411 
18412   if (is_t_integer(pw))
18413     {
18414       s7_int y;
18415       y = integer(pw);
18416       if (y == 0)
18417 	{
18418 	  if (is_rational(n))                                 /* (expt 3 0) */
18419 	    return(int_one);
18420 	  if ((is_NaN(s7_real_part(n))) ||                    /* (expt 1/0 0) -> NaN */
18421 	      (is_NaN(s7_imag_part(n))))                      /* (expt (complex 0 1/0) 0) -> NaN */
18422 	    return(n);
18423 	  return(real_one);                                   /* (expt 3.0 0) */
18424 	}
18425 
18426       switch (type(n))
18427 	{
18428 	case T_INTEGER:
18429 	  {
18430 	    s7_int x;
18431 	    x = s7_integer_checked(sc, n);
18432 	    if (x == 1)                                       /* (expt 1 y) */
18433 	      return(n);
18434 
18435 	    if (x == -1)
18436 	      {
18437 		if (y == S7_INT64_MIN)                          /* (expt -1 most-negative-fixnum) */
18438 		  return(int_one);
18439 		if (s7_int_abs(y) & 1)                          /* (expt -1 odd-int) */
18440 		  return(n);
18441 		return(int_one);                              /* (expt -1 even-int) */
18442 	      }
18443 
18444 	    if (y == S7_INT64_MIN)                              /* (expt x most-negative-fixnum) */
18445 	      return(int_zero);
18446 	    if (x == S7_INT64_MIN)                              /* (expt most-negative-fixnum y) */
18447 	      return(make_real(sc, pow((double)x, (double)y)));
18448 
18449 	    if (int_pow_ok(x, s7_int_abs(y)))
18450 	      {
18451 		if (y > 0)
18452 		  return(make_integer(sc, int_to_int(x, y)));
18453 		return(s7_make_ratio(sc, 1, int_to_int(x, -y)));
18454 	      }}
18455 	  break;
18456 
18457 	case T_RATIO:
18458 	  {
18459 	    s7_int nm, dn;
18460 
18461 	    nm = numerator(n);
18462 	    dn = denominator(n);
18463 
18464 	    if (y == S7_INT64_MIN)
18465 	      {
18466 		if (s7_int_abs(nm) > dn)
18467 		  return(int_zero);                /* (expt 4/3 most-negative-fixnum) -> 0? */
18468 		return(real_infinity);               /* (expt 3/4 most-negative-fixnum) -> inf? */
18469 	      }
18470 
18471 	    if ((int_pow_ok(nm, s7_int_abs(y))) &&
18472 		(int_pow_ok(dn, s7_int_abs(y))))
18473 	      {
18474 		if (y > 0)
18475 		  return(s7_make_ratio(sc, int_to_int(nm, y), int_to_int(dn, y)));
18476 		return(s7_make_ratio(sc, int_to_int(dn, -y), int_to_int(nm, -y)));
18477 	      }}
18478 	  break;
18479 	  /* occasionally int^rat can be int32_t but it happens so infrequently it's probably not worth checking
18480 	   *  one possibly easy case: (expt 1 1/2) -> 1 (-1?) etc
18481 	   */
18482 
18483 	case T_REAL:
18484 	  /* (expt -1.0 most-positive-fixnum) should be -1.0
18485 	   * (expt -1.0 (+ (expt 2 53) 1)) -> -1.0
18486 	   * (expt -1.0 (- 1 (expt 2 54))) -> -1.0
18487 	   */
18488 	  if (real(n) == -1.0)
18489 	    {
18490 	      if (y == S7_INT64_MIN)
18491 		return(real_one);
18492 	      return((s7_int_abs(y) & 1) ? n : real_one);
18493 	    }
18494 	  break;
18495 
18496 	case T_COMPLEX:
18497 #if HAVE_COMPLEX_NUMBERS
18498 	  if ((s7_real_part(n) == 0.0) &&
18499 	      ((s7_imag_part(n) == 1.0) ||
18500 	       (s7_imag_part(n) == -1.0)))
18501 	    {
18502 	      bool yp, np;
18503 	      yp = (y > 0);
18504 	      np = (s7_imag_part(n) > 0.0);
18505 	      switch (s7_int_abs(y) % 4)
18506 		{
18507 		case 0: return(real_one);
18508 		case 1: return(s7_make_complex(sc, 0.0, (yp == np) ? 1.0 : -1.0));
18509 		case 2: return(make_real(sc, -1.0));
18510 		case 3: return(s7_make_complex(sc, 0.0, (yp == np) ? -1.0 : 1.0));
18511 		}}
18512 #else
18513 	  return(out_of_range(sc, sc->expt_symbol, int_two, n, no_complex_numbers_string));
18514 #endif
18515 	  break;
18516 	}}
18517 
18518   if ((s7_is_real(n)) &&
18519       (s7_is_real(pw)))
18520     {
18521       s7_double x, y;
18522 
18523       if ((is_t_ratio(pw)) &&
18524 	  (numerator(pw) == 1))
18525 	{
18526 	  if (denominator(pw) == 2)
18527 	    return(sqrt_p_p(sc, n));
18528 	  if (denominator(pw) == 3)
18529 	    return(make_real(sc, cbrt(s7_real(n)))); /* (expt 27 1/3) should be 3, not 3.0... */
18530 	  /* but: (expt 512/729 1/3) -> 0.88888888888889, and 4 -> sqrt(sqrt...) etc? */
18531 	}
18532 
18533       x = s7_real(n);
18534       y = s7_real(pw);
18535 
18536       if (is_NaN(x)) return(n);
18537       if (is_NaN(y)) return(pw);
18538       if (y == 0.0) return(real_one);
18539 
18540       /* I think pow(rl, inf) is ok */
18541       if (x > 0.0)
18542 	return(make_real(sc, pow(x, y)));      /* tricky cases abound here: (expt -1 1/9223372036854775807) */
18543     }
18544 
18545   /* (expt 0+i 1e+16) = 0.98156860153485-0.19111012657867i ?
18546    * (expt 0+i 1+1/0i) = 0.0 ??
18547    */
18548   return(c_complex_to_s7(sc, cpow(s7_to_c_complex(n), s7_to_c_complex(pw))));
18549 }
18550 
18551 
18552 /* -------------------------------- lcm -------------------------------- */
18553 
18554 #if WITH_GMP
18555 static s7_pointer big_lcm(s7_scheme *sc, s7_int num, s7_int den, s7_pointer args)
18556 {
18557   s7_pointer x;
18558   mpz_set_si(sc->mpz_3, num);
18559   mpz_set_si(sc->mpz_4, den);
18560 
18561   for (x = args; is_pair(x); x = cdr(x))
18562     {
18563       s7_pointer rat;
18564       rat = car(x);
18565       switch (type(rat))
18566 	{
18567 	case T_INTEGER:
18568 	  mpz_set_si(sc->mpz_1, integer(rat));
18569 	  mpz_lcm(sc->mpz_3, sc->mpz_3, sc->mpz_1);
18570 	  mpz_set_si(sc->mpz_4, 1);
18571 	  break;
18572 
18573 	case T_RATIO:
18574 	  mpz_set_si(sc->mpz_1, numerator(rat));
18575 	  mpz_set_si(sc->mpz_2, denominator(rat));
18576 	  mpz_lcm(sc->mpz_3, sc->mpz_3, sc->mpz_1);
18577 	  mpz_gcd(sc->mpz_4, sc->mpz_4, sc->mpz_2);
18578 	  break;
18579 
18580 	case T_BIG_INTEGER:
18581 	  mpz_lcm(sc->mpz_3, sc->mpz_3, big_integer(rat));
18582 	  mpz_set_si(sc->mpz_4, 1);
18583 	  break;
18584 
18585 	case T_BIG_RATIO:
18586 	  mpz_lcm(sc->mpz_3, sc->mpz_3, mpq_numref(big_ratio(rat)));
18587 	  mpz_gcd(sc->mpz_4, sc->mpz_4, mpq_denref(big_ratio(rat)));
18588 	  break;
18589 
18590 	case T_REAL: case T_BIG_REAL: case T_COMPLEX: case T_BIG_COMPLEX:
18591 	  return(wrong_type_argument_with_type(sc, sc->lcm_symbol, position_of(x, args), rat, a_rational_string));
18592 
18593 	default:
18594 	  return(method_or_bust_with_type(sc, rat, sc->lcm_symbol,
18595 					  set_ulist_1(sc, mpz_to_rational(sc, sc->mpz_3, sc->mpz_4), x),
18596 					  a_rational_string, position_of(x, args)));
18597 	}}
18598   return(mpz_to_rational(sc, sc->mpz_3, sc->mpz_4));
18599 }
18600 #endif
18601 
18602 static s7_pointer g_lcm(s7_scheme *sc, s7_pointer args)
18603 {
18604   /* (/ (* m n) (gcd m n)), (lcm a b c) -> (lcm a (lcm b c)) */
18605   #define H_lcm "(lcm ...) returns the least common multiple of its rational arguments"
18606   #define Q_lcm sc->pcl_f
18607 
18608   s7_int n = 1, d = 0;
18609   s7_pointer p;
18610 
18611   if (!is_pair(args))
18612     return(int_one);
18613 
18614   if (!is_pair(cdr(args)))
18615     {
18616       if (!is_rational(car(args)))
18617 	return(method_or_bust_with_type(sc, car(args), sc->lcm_symbol, args, a_rational_string, 1));
18618       return(g_abs(sc, args));
18619     }
18620 
18621   for (p = args; is_pair(p); p = cdr(p))
18622     {
18623       s7_pointer x;
18624       s7_int b;
18625 #if HAVE_OVERFLOW_CHECKS
18626       s7_int n1;
18627 #endif
18628       x = car(p);
18629       switch (type(x))
18630 	{
18631 	case T_INTEGER:
18632 	  d = 1;
18633 	  if (integer(x) == 0) /* return 0 unless there's a wrong-type-arg (geez what a mess) */
18634 	    {
18635 	      for (p = cdr(p); is_pair(p); p = cdr(p))
18636 		{
18637 		  s7_pointer x1;
18638 		  x1 = car(p);
18639 		  if (is_number(x1))
18640 		    {
18641 		      if (!is_rational(x1))
18642 			return(wrong_type_argument_with_type(sc, sc->lcm_symbol, position_of(p, args), x1, a_rational_string));
18643 		    }
18644 		  else
18645 		    {
18646 		      if (has_active_methods(sc, x1))
18647 			{
18648 			  s7_pointer f;
18649 			  f = find_method_with_let(sc, x1, sc->is_rational_symbol);
18650 			  if ((f == sc->undefined) ||
18651 			      (is_false(sc, call_method(sc, x1, f, set_plist_1(sc, x1)))))
18652 			    return(wrong_type_argument_with_type(sc, sc->lcm_symbol, position_of(p, args), x1, a_rational_string));
18653 			}
18654 		      else return(wrong_type_argument_with_type(sc, sc->lcm_symbol, position_of(p, args), x1, a_rational_string));
18655 		    }}
18656 	      return(int_zero);
18657 	    }
18658 	  b = integer(x);
18659 	  if (b < 0)
18660 	    {
18661 	      if (b == S7_INT64_MIN)
18662 #if WITH_GMP
18663 		return(big_lcm(sc, n, d, p));
18664 #else
18665 		return(simple_out_of_range(sc, sc->lcm_symbol, args, its_too_large_string));
18666 #endif
18667 	      b = -b;
18668 	    }
18669 #if HAVE_OVERFLOW_CHECKS
18670 	  if (multiply_overflow(n / c_gcd(n, b), b, &n1))
18671 #if WITH_GMP
18672 	    return(big_lcm(sc, n, d, p));
18673 #else
18674 	    return(simple_out_of_range(sc, sc->lcm_symbol, args, result_is_too_large_string));
18675 #endif
18676 	  n = n1;
18677 #else
18678 	  n = (n / c_gcd(n, b)) * b;
18679 #endif
18680 	  break;
18681 
18682 	case T_RATIO:
18683 	  b = numerator(x);
18684 	  if (b < 0)
18685 	    {
18686 	      if (b == S7_INT64_MIN)
18687 #if WITH_GMP
18688 		return(big_lcm(sc, n, d, p));
18689 #else
18690 		return(simple_out_of_range(sc, sc->lcm_symbol, args, its_too_large_string));
18691 #endif
18692 	      b = -b;
18693 	    }
18694 #if HAVE_OVERFLOW_CHECKS
18695 	  if (multiply_overflow(n / c_gcd(n, b), b, &n1))  /* (lcm 92233720368547758/3 3005/2) */
18696 #if WITH_GMP
18697 	    return(big_lcm(sc, n, d, p));
18698 #else
18699 	    return(simple_out_of_range(sc, sc->lcm_symbol, args, wrap_string(sc, "intermediate result is too large", 32)));
18700 #endif
18701           n = n1;
18702 #else
18703 	  n = (n / c_gcd(n, b)) * b;
18704 #endif
18705 	  if (d == 0)
18706 	    d = (p == args) ? denominator(x) : 1;
18707 	  else d = c_gcd(d, denominator(x));
18708 	  break;
18709 
18710 #if WITH_GMP
18711 	case T_BIG_INTEGER:
18712 	  d = 1;
18713 	case T_BIG_RATIO:
18714 	  return(big_lcm(sc, n, d, p));
18715 #endif
18716 
18717 	case T_REAL: case T_BIG_REAL: case T_COMPLEX: case T_BIG_COMPLEX:
18718 	  return(wrong_type_argument_with_type(sc, sc->lcm_symbol, position_of(p, args), x, a_rational_string));
18719 
18720 	default:
18721 	  return(method_or_bust_with_type(sc, x, sc->lcm_symbol,
18722 					  set_ulist_1(sc, (d <= 1) ? make_integer(sc, n) : s7_make_ratio(sc, n, d), p),
18723 					  a_rational_string, position_of(p, args)));
18724 	}}
18725 
18726   return((d <= 1) ? make_integer(sc, n) : make_simple_ratio(sc, n, d));
18727 }
18728 
18729 
18730 /* -------------------------------- gcd -------------------------------- */
18731 
18732 #if WITH_GMP
18733 static s7_pointer big_gcd(s7_scheme *sc, s7_int num, s7_int den, s7_pointer args)
18734 {
18735   s7_pointer x;
18736 
18737   mpz_set_si(sc->mpz_3, num);
18738   mpz_set_si(sc->mpz_4, den);
18739 
18740   for (x = args; is_pair(x); x = cdr(x))
18741     {
18742       s7_pointer rat;
18743       rat = car(x);
18744       switch (type(rat))
18745 	{
18746 	case T_INTEGER:
18747 	  mpz_set_si(sc->mpz_1, integer(rat));
18748 	  mpz_gcd(sc->mpz_3, sc->mpz_3, sc->mpz_1);
18749 	  break;
18750 
18751 	case T_RATIO:
18752 	  mpz_set_si(sc->mpz_1, numerator(rat));
18753 	  mpz_set_si(sc->mpz_2, denominator(rat));
18754 	  mpz_gcd(sc->mpz_3, sc->mpz_3, sc->mpz_1);
18755 	  mpz_lcm(sc->mpz_4, sc->mpz_4, sc->mpz_2);
18756 	  break;
18757 
18758 	case T_BIG_INTEGER:
18759 	  mpz_gcd(sc->mpz_3, sc->mpz_3, big_integer(rat));
18760 	  break;
18761 
18762 	case T_BIG_RATIO:
18763 	  mpz_gcd(sc->mpz_3, sc->mpz_3, mpq_numref(big_ratio(rat)));
18764 	  mpz_lcm(sc->mpz_4, sc->mpz_4, mpq_denref(big_ratio(rat)));
18765 	  break;
18766 
18767 	case T_REAL: case T_BIG_REAL: case T_COMPLEX: case T_BIG_COMPLEX:
18768 	  return(wrong_type_argument_with_type(sc, sc->gcd_symbol, position_of(x, args), rat, a_rational_string));
18769 
18770 	default:
18771 	  return(method_or_bust_with_type(sc, rat, sc->gcd_symbol,
18772 					  set_ulist_1(sc, mpz_to_rational(sc, sc->mpz_3, sc->mpz_4), x),
18773 					  a_rational_string, position_of(x, args)));
18774 	}}
18775   return(mpz_to_rational(sc, sc->mpz_3, sc->mpz_4));
18776 }
18777 #endif
18778 
18779 static s7_pointer g_gcd(s7_scheme *sc, s7_pointer args)
18780 {
18781   #define H_gcd "(gcd ...) returns the greatest common divisor of its rational arguments"
18782   #define Q_gcd sc->pcl_f
18783 
18784   s7_int n = 0, d = 1;
18785   s7_pointer p;
18786 
18787   if (!is_pair(args))       /* (gcd) */
18788     return(int_zero);
18789 
18790   if (!is_pair(cdr(args)))  /* (gcd 3/4) */
18791     {
18792       if (!is_rational(car(args)))
18793 	return(method_or_bust_with_type(sc, car(args), sc->gcd_symbol, args, a_rational_string, 1));
18794       return(abs_p_p(sc, car(args)));
18795     }
18796 
18797   for (p = args; is_pair(p); p = cdr(p))
18798     {
18799       s7_pointer x;
18800       x = car(p);
18801       switch (type(x))
18802 	{
18803 	case T_INTEGER:
18804 	  if (integer(x) == S7_INT64_MIN)
18805 #if WITH_GMP
18806 	    return(big_gcd(sc, n, d, p));
18807 #else
18808 	    return(simple_out_of_range(sc, sc->lcm_symbol, args, its_too_large_string));
18809 #endif
18810 	  n = c_gcd(n, integer(x));
18811 	  break;
18812 
18813 	case T_RATIO:
18814 	  {
18815 #if HAVE_OVERFLOW_CHECKS
18816 	    s7_int dn;
18817 #endif
18818 	    n = c_gcd(n, numerator(x));
18819 	    if (d == 1)
18820 	      d = denominator(x);
18821 	    else
18822 	      {
18823 		s7_int b;
18824 		b = denominator(x);
18825 #if HAVE_OVERFLOW_CHECKS
18826 		if (multiply_overflow(d / c_gcd(d, b), b, &dn)) /* (gcd 1/92233720368547758 1/3005) */
18827 #if WITH_GMP
18828 		  return(big_gcd(sc, n, d, x));
18829 #else
18830 		  return(simple_out_of_range(sc, sc->gcd_symbol, args, wrap_string(sc, "intermediate result is too large", 32)));
18831 #endif
18832 		d = dn;
18833 #else
18834 		d = (d / c_gcd(d, b)) * b;
18835 #endif
18836 	      }}
18837 	  break;
18838 
18839 #if WITH_GMP
18840 	case T_BIG_INTEGER:
18841 	case T_BIG_RATIO:
18842 	  return(big_gcd(sc, n, d, p));
18843 #endif
18844 
18845 	case T_REAL: case T_BIG_REAL: case T_COMPLEX: case T_BIG_COMPLEX:
18846 	  return(wrong_type_argument_with_type(sc, sc->gcd_symbol, position_of(p, args), x, a_rational_string));
18847 
18848 	default:
18849 	  return(method_or_bust_with_type(sc, x, sc->gcd_symbol,
18850 					  set_ulist_1(sc, (d <= 1) ? make_integer(sc, n) : s7_make_ratio(sc, n, d), p),
18851 					  a_rational_string, position_of(p, args)));
18852 	}}
18853   return((d <= 1) ? make_integer(sc, n) : make_simple_ratio(sc, n, d));
18854 }
18855 
18856 
18857 /* -------------------------------- floor -------------------------------- */
18858 
18859 static s7_pointer floor_p_p(s7_scheme *sc, s7_pointer x)
18860 {
18861   switch (type(x))
18862     {
18863     case T_INTEGER:
18864       return(x);
18865 
18866     case T_RATIO:
18867       {
18868 	s7_int val;
18869 	val = numerator(x) / denominator(x);
18870 	/* C "/" truncates? -- C spec says "truncation toward 0" */
18871 	/* we're avoiding "floor" here because the int->double conversion introduces inaccuracies for big numbers
18872 	 *   but it's used by opt_i_d_c (via s7_number_to_real) so floor_i_7d below can return different results:
18873 	 *   (let () (define (func) (do ((i 0 (+ i 1))) ((= i 1)) (display (floor 3441313796169221281/1720656898084610641)) (newline))) (func)): 1
18874 	 *   (let () (define (func) (do ((i 0 (+ i 1))) ((= i 1)) (display (/ (floor 3441313796169221281/1720656898084610641))) (newline))) (func)): 1/2
18875 	 */
18876 	return((numerator(x) < 0) ? make_integer(sc, val - 1) : make_integer(sc, val)); /* not "val" because it might be truncated to 0 */
18877       }
18878 
18879     case T_REAL:
18880       {
18881 	s7_double z;
18882 	z = real(x);
18883 	if (is_NaN(z))
18884 	  return(simple_out_of_range(sc, sc->floor_symbol, x, its_nan_string));
18885 	if (is_inf(z))
18886 	  return(simple_out_of_range(sc, sc->floor_symbol, x, its_infinite_string));
18887 #if WITH_GMP
18888 	if (fabs(z) > DOUBLE_TO_INT64_LIMIT)
18889 	  {
18890 	    mpfr_set_d(sc->mpfr_1, z, MPFR_RNDN);
18891 	    mpfr_get_z(sc->mpz_1, sc->mpfr_1, MPFR_RNDD);
18892 	    return(mpz_to_integer(sc, sc->mpz_1));
18893 	  }
18894 #else
18895 	if (fabs(z) > DOUBLE_TO_INT64_LIMIT)
18896 	  return(simple_out_of_range(sc, sc->floor_symbol, x, its_too_large_string));
18897 #endif
18898 	return(make_integer(sc, (s7_int)floor(z)));
18899 	/* floor here rounds down, whereas a straight int<=real coercion apparently rounds towards 0 */
18900       }
18901 
18902 #if WITH_GMP
18903     case T_BIG_INTEGER:
18904       return(x);
18905 
18906     case T_BIG_RATIO:
18907       mpz_fdiv_q(sc->mpz_1, mpq_numref(big_ratio(x)), mpq_denref(big_ratio(x)));
18908       return(mpz_to_integer(sc, sc->mpz_1));
18909 
18910     case T_BIG_REAL:
18911       if (mpfr_nan_p(big_real(x)))
18912 	return(simple_out_of_range(sc, sc->floor_symbol, x, its_nan_string));
18913       if (mpfr_inf_p(big_real(x)))
18914 	return(simple_out_of_range(sc, sc->floor_symbol, x, its_infinite_string));
18915       mpfr_get_z(sc->mpz_1, big_real(x), MPFR_RNDD);
18916       return(mpz_to_integer(sc, sc->mpz_1));
18917 
18918     case T_BIG_COMPLEX:
18919 #endif
18920     case T_COMPLEX:
18921       return(s7_wrong_type_arg_error(sc, "floor", 0, x, "a real number"));
18922 
18923     default:
18924       return(method_or_bust_one_arg_p(sc, x, sc->floor_symbol, T_REAL));
18925     }
18926 }
18927 
18928 static s7_pointer g_floor(s7_scheme *sc, s7_pointer args)
18929 {
18930   #define H_floor "(floor x) returns the integer closest to x toward -inf"
18931   #define Q_floor s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
18932   return(floor_p_p(sc, car(args)));
18933 }
18934 
18935 static s7_int floor_i_i(s7_int i) {return(i);}
18936 
18937 #if (!WITH_GMP)
18938 static s7_int floor_i_7d(s7_scheme *sc, s7_double x)
18939 {
18940   if (is_NaN(x))
18941     simple_out_of_range(sc, sc->floor_symbol, wrap_real1(sc, x), its_nan_string);
18942   if (fabs(x) > DOUBLE_TO_INT64_LIMIT)
18943     simple_out_of_range(sc, sc->floor_symbol, wrap_real1(sc, x), its_too_large_string);
18944   return((s7_int)floor(x));
18945 }
18946 
18947 static s7_int floor_i_7p(s7_scheme *sc, s7_pointer p)
18948 {
18949   if (is_t_integer(p)) return(integer(p));
18950   if (is_t_real(p)) return(floor_i_7d(sc, real(p)));
18951   if (is_t_ratio(p)) /* for consistency with floor_p_p, don't use floor(fraction(p)) */
18952     {
18953       s7_int val;
18954       val = numerator(p) / denominator(p);
18955       return((numerator(p) < 0) ? val - 1 : val);
18956     }
18957   return(s7_integer_checked(sc, method_or_bust_p(sc, p, sc->floor_symbol, T_REAL)));
18958 }
18959 #endif
18960 
18961 
18962 /* -------------------------------- ceiling -------------------------------- */
18963 static s7_pointer g_ceiling(s7_scheme *sc, s7_pointer args)
18964 {
18965   #define H_ceiling "(ceiling x) returns the integer closest to x toward inf"
18966   #define Q_ceiling s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
18967 
18968   s7_pointer x;
18969 
18970   x = car(args);
18971   switch (type(x))
18972     {
18973     case T_INTEGER:
18974       return(x);
18975 
18976     case T_RATIO:
18977       {
18978 	s7_int val;
18979 	val = numerator(x) / denominator(x);
18980 	return((numerator(x) < 0) ? make_integer(sc, val) : make_integer(sc, val + 1));
18981       }
18982 
18983     case T_REAL:
18984       {
18985 	s7_double z;
18986 	z = real(x);
18987 	if (is_NaN(z))
18988 	  return(simple_out_of_range(sc, sc->ceiling_symbol, x, its_nan_string));
18989 	if (is_inf(z))
18990 	  return(simple_out_of_range(sc, sc->ceiling_symbol, x, its_infinite_string));
18991 #if WITH_GMP
18992 	if (fabs(z) > DOUBLE_TO_INT64_LIMIT)
18993 	  {
18994 	    mpfr_set_d(sc->mpfr_1, z, MPFR_RNDN);
18995 	    mpfr_get_z(sc->mpz_1, sc->mpfr_1, MPFR_RNDU);
18996 	    return(mpz_to_integer(sc, sc->mpz_1));
18997 	  }
18998 #else
18999 	if (fabs(z) > DOUBLE_TO_INT64_LIMIT)
19000 	  return(simple_out_of_range(sc, sc->ceiling_symbol, x, its_too_large_string));
19001 #endif
19002 	return(make_integer(sc, (s7_int)ceil(real(x))));
19003       }
19004 
19005 #if WITH_GMP
19006     case T_BIG_INTEGER:
19007       return(x);
19008 
19009     case T_BIG_RATIO:
19010       mpz_cdiv_q(sc->mpz_1, mpq_numref(big_ratio(x)), mpq_denref(big_ratio(x)));
19011       return(mpz_to_integer(sc, sc->mpz_1));
19012 
19013     case T_BIG_REAL:
19014       if (mpfr_nan_p(big_real(x)))
19015 	return(simple_out_of_range(sc, sc->ceiling_symbol, x, its_nan_string));
19016       if (mpfr_inf_p(big_real(x)))
19017 	return(simple_out_of_range(sc, sc->ceiling_symbol, x, its_infinite_string));
19018       mpfr_get_z(sc->mpz_1, big_real(x), MPFR_RNDU);
19019       return(mpz_to_integer(sc, sc->mpz_1));
19020 
19021     case T_BIG_COMPLEX:
19022 #endif
19023     case T_COMPLEX:
19024     default:
19025       return(method_or_bust_one_arg(sc, x, sc->ceiling_symbol, args, T_REAL));
19026     }
19027 }
19028 
19029 static s7_int ceiling_i_i(s7_int i) {return(i);}
19030 
19031 #if (!WITH_GMP)
19032 static s7_int ceiling_i_7d(s7_scheme *sc, s7_double x)
19033 {
19034   if (is_NaN(x))
19035     simple_out_of_range(sc, sc->ceiling_symbol, wrap_real1(sc, x), its_nan_string);
19036   if ((is_inf(x)) ||
19037       (x > DOUBLE_TO_INT64_LIMIT) || (x < -DOUBLE_TO_INT64_LIMIT))
19038     simple_out_of_range(sc, sc->ceiling_symbol, wrap_real1(sc, x), its_too_large_string);
19039   return((s7_int)ceil(x));
19040 }
19041 
19042 static s7_int ceiling_i_7p(s7_scheme *sc, s7_pointer p)
19043 {
19044   if (is_t_integer(p)) return(integer(p));
19045   if (is_t_real(p)) return(ceiling_i_7d(sc, real(p)));
19046   if (is_t_ratio(p)) return((s7_int)(ceil(fraction(p))));
19047   return(s7_integer_checked(sc, method_or_bust_p(sc, p, sc->ceiling_symbol, T_REAL)));
19048 }
19049 #endif
19050 
19051 
19052 /* -------------------------------- truncate -------------------------------- */
19053 static s7_pointer truncate_p_p(s7_scheme *sc, s7_pointer x)
19054 {
19055   switch (type(x))
19056     {
19057     case T_INTEGER:
19058       return(x);
19059 
19060     case T_RATIO:
19061       return(make_integer(sc, (s7_int)(numerator(x) / denominator(x)))); /* C "/" already truncates (but this divide is not accurate over e13) */
19062 
19063     case T_REAL:
19064       {
19065 	s7_double z;
19066 	z = real(x);
19067 	if (is_NaN(z))
19068 	  return(simple_out_of_range(sc, sc->truncate_symbol, x, its_nan_string));
19069 	if (is_inf(z))
19070 	  return(simple_out_of_range(sc, sc->truncate_symbol, x, its_infinite_string));
19071 #if WITH_GMP
19072 	if (fabs(z) > DOUBLE_TO_INT64_LIMIT)
19073 	  {
19074 	    mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
19075 	    mpfr_get_z(sc->mpz_1, sc->mpfr_1, MPFR_RNDZ);
19076 	    return(mpz_to_integer(sc, sc->mpz_1));
19077 	  }
19078 #else
19079 	if (fabs(z) > DOUBLE_TO_INT64_LIMIT)
19080 	  return(simple_out_of_range(sc, sc->truncate_symbol, x, its_too_large_string));
19081 #endif
19082 	return((z > 0.0) ? make_integer(sc, (s7_int)floor(z)) : make_integer(sc, (s7_int)ceil(z)));
19083       }
19084 
19085 #if WITH_GMP
19086     case T_BIG_INTEGER:
19087       return(x);
19088 
19089     case T_BIG_RATIO:
19090       mpz_tdiv_q(sc->mpz_1, mpq_numref(big_ratio(x)), mpq_denref(big_ratio(x)));
19091       return(mpz_to_integer(sc, sc->mpz_1));
19092 
19093     case T_BIG_REAL:
19094       if (mpfr_nan_p(big_real(x)))
19095 	return(simple_out_of_range(sc, sc->truncate_symbol, x, its_nan_string));
19096       if (mpfr_inf_p(big_real(x)))
19097 	return(simple_out_of_range(sc, sc->truncate_symbol, x, its_infinite_string));
19098       mpfr_get_z(sc->mpz_1, big_real(x), MPFR_RNDZ);
19099       return(mpz_to_integer(sc, sc->mpz_1));
19100 
19101     case T_BIG_COMPLEX:
19102 #endif
19103     case T_COMPLEX:
19104     default:
19105       return(method_or_bust_one_arg_p(sc, x, sc->truncate_symbol, T_REAL));
19106     }
19107 }
19108 
19109 static s7_pointer g_truncate(s7_scheme *sc, s7_pointer args)
19110 {
19111   #define H_truncate "(truncate x) returns the integer closest to x toward 0"
19112   #define Q_truncate s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
19113   return(truncate_p_p(sc, car(args)));
19114 }
19115 
19116 static s7_int truncate_i_i(s7_int i) {return(i);}
19117 
19118 #if (!WITH_GMP)
19119 static s7_int truncate_i_7d(s7_scheme *sc, s7_double x)
19120 {
19121   if (is_NaN(x))
19122     simple_out_of_range(sc, sc->truncate_symbol, wrap_real1(sc, x), its_nan_string);
19123   if (is_inf(x))
19124     simple_out_of_range(sc, sc->truncate_symbol, wrap_real1(sc, x), its_infinite_string);
19125   if (fabs(x) > DOUBLE_TO_INT64_LIMIT)
19126     simple_out_of_range(sc, sc->truncate_symbol, wrap_real1(sc, x), its_too_large_string);
19127   return((x > 0.0) ? (s7_int)floor(x) : (s7_int)ceil(x));
19128 }
19129 #endif
19130 
19131 
19132 /* -------------------------------- round -------------------------------- */
19133 static s7_double r5rs_round(s7_double x)
19134 {
19135   s7_double fl, ce, dfl, dce;
19136 
19137   fl = floor(x);
19138   ce = ceil(x);
19139   dfl = x - fl;
19140   dce = ce - x;
19141 
19142   if (dfl > dce) return(ce);
19143   if (dfl < dce) return(fl);
19144   return((fmod(fl, 2.0) == 0.0) ? fl : ce);
19145 }
19146 
19147 static s7_pointer g_round(s7_scheme *sc, s7_pointer args)
19148 {
19149   #define H_round "(round x) returns the integer closest to x"
19150   #define Q_round s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
19151 
19152   s7_pointer x;
19153   x = car(args);
19154   switch (type(x))
19155     {
19156     case T_INTEGER:
19157       return(x);
19158 
19159     case T_RATIO:
19160       {
19161 	s7_int truncated, remains;
19162 	long_double frac;
19163 
19164 	truncated = numerator(x) / denominator(x);
19165 	remains = numerator(x) % denominator(x);
19166 	frac = s7_fabsl((long_double)remains / (long_double)denominator(x));
19167 
19168 	if ((frac > 0.5) ||
19169 	    ((frac == 0.5) &&
19170 	     (truncated % 2 != 0)))
19171 	  return((numerator(x) < 0) ? make_integer(sc, truncated - 1) : make_integer(sc, truncated + 1));
19172 	return(make_integer(sc, truncated));
19173       }
19174 
19175     case T_REAL:
19176       {
19177 	s7_double z;
19178 	z = real(x);
19179 	if (is_NaN(z))
19180 	  return(simple_out_of_range(sc, sc->round_symbol, x, its_nan_string));
19181 	if (is_inf(z))
19182 	  return(simple_out_of_range(sc, sc->round_symbol, x, its_infinite_string));
19183 #if WITH_GMP
19184 	if (fabs(z) > DOUBLE_TO_INT64_LIMIT)
19185 	  {
19186 	    mpfr_set_d(sc->mpfr_1, z, MPFR_RNDN);
19187 	    mpfr_rint(sc->mpfr_2, sc->mpfr_1, MPFR_RNDN); /* mpfr_roundeven in mpfr 4.0.0 */
19188 	    mpfr_get_z(sc->mpz_3, sc->mpfr_2, MPFR_RNDN);
19189 	    return(mpz_to_integer(sc, sc->mpz_3));
19190 	  }
19191 #else
19192 	if (fabs(z) > DOUBLE_TO_INT64_LIMIT)
19193 	  return(simple_out_of_range(sc, sc->round_symbol, x, its_too_large_string));
19194 #endif
19195 	return(make_integer(sc, (s7_int)r5rs_round(z)));
19196       }
19197 
19198 #if WITH_GMP
19199       case T_BIG_INTEGER:
19200 	return(x);
19201 
19202     case T_BIG_RATIO:
19203       {
19204 	int32_t rnd;
19205 	mpz_fdiv_qr(sc->mpz_1, sc->mpz_2, mpq_numref(big_ratio(x)), mpq_denref(big_ratio(x)));
19206 	mpz_mul_ui(sc->mpz_2, sc->mpz_2, 2);
19207 	rnd = mpz_cmpabs(sc->mpz_2, mpq_denref(big_ratio(x)));
19208 	mpz_fdiv_q(sc->mpz_2, sc->mpz_2, mpq_denref(big_ratio(x)));
19209 	if (rnd > 0)
19210 	  mpz_add(sc->mpz_1, sc->mpz_1, sc->mpz_2);
19211 	else
19212 	  if ((rnd == 0) &&
19213 	      (mpz_odd_p(sc->mpz_1)))
19214 	    mpz_add_ui(sc->mpz_1, sc->mpz_1, 1);
19215 	return(mpz_to_integer(sc, sc->mpz_1));
19216       }
19217 
19218     case T_BIG_REAL:
19219       if (mpfr_nan_p(big_real(x)))
19220 	return(simple_out_of_range(sc, sc->round_symbol, x, its_nan_string));
19221       if (mpfr_inf_p(big_real(x)))
19222 	return(simple_out_of_range(sc, sc->round_symbol, x, its_infinite_string));
19223       mpfr_set(sc->mpfr_1, big_real(x), MPFR_RNDN);
19224       mpfr_rint(sc->mpfr_2, sc->mpfr_1, MPFR_RNDN);
19225       mpfr_get_z(sc->mpz_3, sc->mpfr_2, MPFR_RNDN);
19226       return(mpz_to_integer(sc, sc->mpz_3));
19227 
19228     case T_BIG_COMPLEX:
19229 #endif
19230     case T_COMPLEX:
19231     default:
19232       return(method_or_bust_one_arg(sc, x, sc->round_symbol, args, T_REAL));
19233     }
19234 }
19235 
19236 static s7_int round_i_i(s7_int i) {return(i);}
19237 
19238 #if (!WITH_GMP)
19239 static s7_int round_i_7d(s7_scheme *sc, s7_double z)
19240 {
19241   if (is_NaN(z))
19242     simple_out_of_range(sc, sc->round_symbol, wrap_real1(sc, z), its_nan_string);
19243   if ((is_inf(z)) ||
19244       (z > DOUBLE_TO_INT64_LIMIT) || (z < -DOUBLE_TO_INT64_LIMIT))
19245     simple_out_of_range(sc, sc->round_symbol, wrap_real1(sc, z), its_too_large_string);
19246   return((s7_int)r5rs_round(z));
19247 }
19248 #endif
19249 
19250 
19251 /* ---------------------------------------- add ---------------------------------------- */
19252 
19253 static inline s7_pointer add_if_overflow_to_real_or_big_integer(s7_scheme *sc, s7_int x, s7_int y)
19254 {
19255 #if HAVE_OVERFLOW_CHECKS
19256   s7_int val;
19257   if (add_overflow(x, y, &val))
19258 #if WITH_GMP
19259     {
19260       mpz_set_si(sc->mpz_1, x);
19261       mpz_set_si(sc->mpz_2, y);
19262       mpz_add(sc->mpz_1, sc->mpz_1, sc->mpz_2);
19263       return(mpz_to_big_integer(sc, sc->mpz_1));
19264     }
19265 #else
19266   return(make_real(sc, (long_double)x + (long_double)y));
19267 #endif
19268   return(make_integer(sc, val));
19269 #else
19270   return(make_integer(sc, x + y));
19271 #endif
19272 }
19273 
19274 static s7_pointer integer_ratio_add_if_overflow_to_real_or_rational(s7_scheme *sc, s7_pointer x, s7_pointer y) /* x: int, y:ratio */
19275 {
19276 #if HAVE_OVERFLOW_CHECKS
19277   s7_int z;
19278   if ((multiply_overflow(integer(x), denominator(y), &z)) ||
19279       (add_overflow(z, numerator(y), &z)))
19280 #if WITH_GMP
19281     {
19282       mpz_set_si(sc->mpz_1, integer(x));
19283       mpz_mul_si(sc->mpz_1, sc->mpz_1, denominator(y));
19284       mpz_set_si(sc->mpz_2, numerator(y));
19285       mpz_add(mpq_numref(sc->mpq_1), sc->mpz_2, sc->mpz_1);
19286       mpz_set_si(mpq_denref(sc->mpq_1), denominator(y));
19287       return(mpq_to_rational(sc, sc->mpq_1));
19288     }
19289 #else
19290     return(make_real(sc, (long_double)integer(x) + fraction(y)));
19291 #endif
19292     return(s7_make_ratio(sc, z, denominator(y)));
19293 #else
19294   return(s7_make_ratio(sc, integer(x) * denominator(y) + numerator(y), denominator(y)));
19295 #endif
19296 }
19297 
19298 #define parcel_out_fractions(X, Y) do {d1 = denominator(x); n1 = numerator(x); d2 = denominator(y); n2 = numerator(y);} while (0)
19299 /* add_out_x|y here (as in lt_out_x|y) gives a small speed-up, say 3-7 callgrind units, about 2% */
19300 
19301 static s7_pointer add_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
19302 {
19303   switch (type(x))
19304     {
19305     case T_INTEGER:
19306       switch (type(y))
19307 	{
19308 	case T_INTEGER:
19309 	  return(add_if_overflow_to_real_or_big_integer(sc, integer(x), integer(y)));
19310 	case T_RATIO:
19311 	  return(integer_ratio_add_if_overflow_to_real_or_rational(sc, x, y));
19312 	case T_REAL:
19313 #if WITH_GMP
19314 	  if (s7_int_abs(integer(x)) >= INT64_TO_DOUBLE_LIMIT) /* (+ 9223372036854775807 .1), >= needed for (+ 9007199254740992 1.0) */
19315 	    {
19316 	      mpfr_set_si(sc->mpfr_1, integer(x), MPFR_RNDN);
19317 	      mpfr_add_d(sc->mpfr_1, sc->mpfr_1, real(y), MPFR_RNDN);
19318 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
19319 	    }
19320 #endif
19321 	  return(make_real(sc, (long_double)integer(x) + real(y)));
19322 	case T_COMPLEX:
19323 	  return(s7_make_complex(sc, (long_double)integer(x) + (long_double)real_part(y), imag_part(y)));
19324 #if WITH_GMP
19325 	case T_BIG_INTEGER:
19326 	  mpz_set_si(sc->mpz_1, integer(x));
19327 	  mpz_add(sc->mpz_1, sc->mpz_1, big_integer(y));
19328 	  return(mpz_to_integer(sc, sc->mpz_1));
19329 	case T_BIG_RATIO:
19330 	  mpq_set_si(sc->mpq_1, integer(x), 1);
19331 	  mpq_add(sc->mpq_1, sc->mpq_1, big_ratio(y));
19332 	  return(mpq_to_rational(sc, sc->mpq_1));
19333 	case T_BIG_REAL:
19334 	  mpfr_add_si(sc->mpfr_1, big_real(y), integer(x), MPFR_RNDN);
19335 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19336 	case T_BIG_COMPLEX:
19337 	  mpc_set_si(sc->mpc_1, integer(x), MPC_RNDNN);
19338 	  mpc_add(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
19339 	  return(mpc_to_number(sc, sc->mpc_1));
19340 #endif
19341 	default:
19342 	  return(method_or_bust_with_type_pp(sc, y, sc->add_symbol, x, y, a_number_string, 2));
19343 	}
19344 
19345     case T_RATIO:
19346       switch (type(y))
19347 	{
19348 	case T_INTEGER:
19349 	  return(integer_ratio_add_if_overflow_to_real_or_rational(sc, y, x));
19350 	case T_RATIO:
19351 	  {
19352 	    s7_int d1, d2, n1, n2;
19353 	    parcel_out_fractions(x, y);
19354 	    if (d1 == d2)
19355 	      {
19356 #if HAVE_OVERFLOW_CHECKS
19357 		s7_int q;
19358 		if (add_overflow(n1, n2, &q))
19359 #if WITH_GMP
19360 		  {
19361 		    mpq_set_si(sc->mpq_1, n1, d1);
19362 		    mpq_set_si(sc->mpq_2, n2, d2);
19363 		    mpq_add(sc->mpq_1, sc->mpq_1, sc->mpq_2);
19364 		    return(mpq_to_rational(sc, sc->mpq_1));
19365 		  }
19366 #else
19367 		return(make_real(sc, ((long_double)n1 + (long_double)n2) / (long_double)d1));
19368 #endif
19369 	        return(s7_make_ratio(sc, q, d1));
19370 #else
19371 		return(s7_make_ratio(sc, n1 + n2, d1));
19372 #endif
19373 	      }
19374 
19375 #if HAVE_OVERFLOW_CHECKS
19376 	    {
19377 	      s7_int n1d2, n2d1, d1d2, q;
19378 	      if ((multiply_overflow(d1, d2, &d1d2)) ||
19379 		  (multiply_overflow(n1, d2, &n1d2)) ||
19380 		  (multiply_overflow(n2, d1, &n2d1)) ||
19381 		  (add_overflow(n1d2, n2d1, &q)))
19382 #if WITH_GMP
19383 		{
19384 		  mpq_set_si(sc->mpq_1, n1, d1);
19385 		  mpq_set_si(sc->mpq_2, n2, d2);
19386 		  mpq_add(sc->mpq_1, sc->mpq_1, sc->mpq_2);
19387 		  return(mpq_to_rational(sc, sc->mpq_1));
19388 		}
19389 #else
19390 	      return(make_real(sc, ((long_double)n1 / (long_double)d1) + ((long_double)n2 / (long_double)d2)));
19391 #endif
19392 	      return(s7_make_ratio(sc, q, d1d2));
19393 	    }
19394 #else
19395 	    return(s7_make_ratio(sc, n1 * d2 + n2 * d1, d1 * d2));
19396 #endif
19397 	  }
19398 	case T_REAL:
19399 	  return(make_real(sc, fraction(x) + real(y)));
19400 	case T_COMPLEX:
19401 	  return(s7_make_complex(sc, fraction(x) + real_part(y), imag_part(y)));
19402 #if WITH_GMP
19403 	case T_BIG_INTEGER:
19404 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
19405 	  mpq_set_z(sc->mpq_2, big_integer(y));
19406 	  mpq_add(sc->mpq_1, sc->mpq_1, sc->mpq_2);
19407 	  return(mpq_to_rational(sc, sc->mpq_1));
19408 	case T_BIG_RATIO:
19409 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
19410 	  mpq_add(sc->mpq_1, sc->mpq_1, big_ratio(y));
19411 	  return(mpq_to_rational(sc, sc->mpq_1));
19412 	case T_BIG_REAL:
19413 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
19414 	  mpfr_add_q(sc->mpfr_1, big_real(y), sc->mpq_1, MPFR_RNDN);
19415 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19416 	case T_BIG_COMPLEX:
19417 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
19418 	  mpc_set_q(sc->mpc_1, sc->mpq_1, MPC_RNDNN);
19419 	  mpc_add(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
19420 	  return(mpc_to_number(sc, sc->mpc_1));
19421 #endif
19422 	default:
19423 	  return(method_or_bust_with_type_pp(sc, y, sc->add_symbol, x, y, a_number_string, 2));
19424 	}
19425 
19426     case T_REAL:
19427       switch (type(y))
19428 	{
19429 	case T_INTEGER:
19430 #if WITH_GMP
19431 	  if (s7_int_abs(integer(y)) >= INT64_TO_DOUBLE_LIMIT) /* (+ .1 9223372036854775807) */
19432 	    {
19433 	      mpfr_set_si(sc->mpfr_1, integer(y), MPFR_RNDN);
19434 	      mpfr_add_d(sc->mpfr_1, sc->mpfr_1, real(x), MPFR_RNDN);
19435 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
19436 	    }
19437 #endif
19438 	  return(make_real(sc, real(x) + (long_double)integer(y)));
19439 	case T_RATIO:
19440 	  return(make_real(sc, real(x) + fraction(y)));
19441 	case T_REAL:
19442 	  return(make_real(sc, real(x) + real(y)));
19443 	case T_COMPLEX:
19444 	  return(s7_make_complex(sc, real(x) + real_part(y), imag_part(y)));
19445 #if WITH_GMP
19446 	case T_BIG_INTEGER:
19447 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
19448 	  mpfr_add_z(sc->mpfr_1, sc->mpfr_1, big_integer(y), MPFR_RNDN);
19449 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19450 	case T_BIG_RATIO:
19451 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
19452 	  mpfr_add_q(sc->mpfr_1, sc->mpfr_1, big_ratio(y), MPFR_RNDN);
19453 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19454 	case T_BIG_REAL:
19455 	  mpfr_add_d(sc->mpfr_1, big_real(y), real(x), MPFR_RNDN);
19456 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19457 	case T_BIG_COMPLEX:
19458 	  mpc_set_d_d(sc->mpc_1, real(x), 0.0, MPC_RNDNN);
19459 	  mpc_add(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
19460 	  return(mpc_to_number(sc, sc->mpc_1));
19461 #endif
19462 	default:
19463 	  return(method_or_bust_with_type_pp(sc, y, sc->add_symbol, x, y, a_number_string, 2));
19464 	}
19465 
19466     case T_COMPLEX:
19467       switch (type(y))
19468 	{
19469 	case T_INTEGER:
19470 	  return(s7_make_complex(sc, real_part(x) + integer(y), imag_part(x)));
19471 	case T_RATIO:
19472 	  return(s7_make_complex(sc, real_part(x) + fraction(y), imag_part(x)));
19473 	case T_REAL:
19474 	  return(s7_make_complex(sc, real_part(x) + real(y), imag_part(x)));
19475 	case T_COMPLEX:
19476 	  return(make_complex(sc, real_part(x) + real_part(y), imag_part(x) + imag_part(y)));
19477 #if WITH_GMP
19478 	case T_BIG_INTEGER:
19479 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
19480 	  mpc_set_z(sc->mpc_2, big_integer(y), MPC_RNDNN);
19481 	  mpc_add(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
19482 	  return(mpc_to_number(sc, sc->mpc_1));
19483 	case T_BIG_RATIO:
19484 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
19485 	  mpc_set_q(sc->mpc_2, big_ratio(y), MPC_RNDNN);
19486 	  mpc_add(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
19487 	  return(mpc_to_number(sc, sc->mpc_1));
19488 	case T_BIG_REAL:
19489 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
19490 	  mpc_add_fr(sc->mpc_1, sc->mpc_1, big_real(y), MPC_RNDNN);
19491 	  return(mpc_to_number(sc, sc->mpc_1));
19492 	case T_BIG_COMPLEX:
19493 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
19494 	  mpc_add(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
19495 	  return(mpc_to_number(sc, sc->mpc_1));
19496 #endif
19497 	default:
19498 	  return(method_or_bust_with_type_pp(sc, y, sc->add_symbol, x, y, a_number_string, 2));
19499 	}
19500 
19501 #if WITH_GMP
19502     case T_BIG_INTEGER:
19503       switch (type(y))
19504 	{
19505 	case T_INTEGER:
19506 	  mpz_set_si(sc->mpz_1, integer(y));
19507 	  mpz_add(sc->mpz_1, big_integer(x), sc->mpz_1);
19508 	  return(mpz_to_integer(sc, sc->mpz_1));
19509 	case T_RATIO:
19510 	  mpq_set_z(sc->mpq_2, big_integer(x));
19511 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
19512 	  mpq_add(sc->mpq_1, sc->mpq_2, sc->mpq_1);
19513 	  mpq_canonicalize(sc->mpq_1);
19514 	  return(mpq_to_rational(sc, sc->mpq_1));
19515 	case T_REAL:
19516 	  if (is_NaN(real(y))) return(real_NaN);
19517 	  mpfr_set_d(sc->mpfr_1, real(y), MPFR_RNDN);
19518 	  mpfr_add_z(sc->mpfr_1, sc->mpfr_1, big_integer(x), MPFR_RNDN);
19519 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19520 	case T_COMPLEX:
19521 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
19522 	  mpc_set_z(sc->mpc_2, big_integer(x), MPC_RNDNN);
19523 	  mpc_add(sc->mpc_1, sc->mpc_2, sc->mpc_1, MPC_RNDNN);
19524 	  return(mpc_to_number(sc, sc->mpc_1));
19525 	case T_BIG_INTEGER:
19526 	  mpz_add(sc->mpz_1, big_integer(x), big_integer(y));
19527 	  return(mpz_to_integer(sc, sc->mpz_1));
19528 	case T_BIG_RATIO:
19529 	  mpq_set_z(sc->mpq_1, big_integer(x));
19530 	  mpq_add(sc->mpq_1, sc->mpq_1, big_ratio(y));
19531 	  return(mpq_to_rational(sc, sc->mpq_1));
19532 	case T_BIG_REAL:
19533 	  mpfr_add_z(sc->mpfr_1, big_real(y), big_integer(x), MPFR_RNDN);
19534 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19535 	case T_BIG_COMPLEX:
19536 	  mpc_set_z(sc->mpc_1, big_integer(x), MPC_RNDNN);
19537 	  mpc_add(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
19538 	  return(mpc_to_number(sc, sc->mpc_1));
19539 	default:
19540 	  return(method_or_bust_with_type_pp(sc, y, sc->add_symbol, x, y, a_number_string, 2));
19541 	}
19542 
19543     case T_BIG_RATIO:
19544       switch (type(y))
19545 	{
19546 	case T_INTEGER:
19547 	  mpq_set_si(sc->mpq_1, integer(y), 1);
19548 	  mpq_add(sc->mpq_1, big_ratio(x), sc->mpq_1);
19549 	  return(mpq_to_rational(sc, sc->mpq_1));
19550 	case T_RATIO:
19551 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
19552 	  mpq_add(sc->mpq_1, big_ratio(x), sc->mpq_1);
19553 	  return(mpq_to_rational(sc, sc->mpq_1));
19554 	case T_REAL:
19555 	  if (is_NaN(real(y))) return(real_NaN);
19556 	  mpfr_set_d(sc->mpfr_1, real(y), MPFR_RNDN);
19557 	  mpfr_add_q(sc->mpfr_1, sc->mpfr_1, big_ratio(x), MPFR_RNDN);
19558 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19559 	case T_COMPLEX:
19560 	  mpc_set_q(sc->mpc_1, big_ratio(x), MPC_RNDNN);
19561 	  mpc_set_d_d(sc->mpc_2, real_part(y), imag_part(y), MPC_RNDNN);
19562 	  mpc_add(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
19563 	  return(mpc_to_number(sc, sc->mpc_1));
19564 	case T_BIG_INTEGER:
19565 	  mpq_set_z(sc->mpq_1, big_integer(y));
19566 	  mpq_add(sc->mpq_1, big_ratio(x), sc->mpq_1);
19567 	  mpq_canonicalize(sc->mpq_1);
19568 	  return(mpq_to_rational(sc, sc->mpq_1));
19569 	case T_BIG_RATIO:
19570 	  mpq_add(sc->mpq_1, big_ratio(x), big_ratio(y));
19571 	  mpq_canonicalize(sc->mpq_1);
19572 	  return(mpq_to_rational(sc, sc->mpq_1));
19573 	case T_BIG_REAL:
19574 	  mpfr_add_q(sc->mpfr_1, big_real(y), big_ratio(x), MPFR_RNDN);
19575 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19576 	case T_BIG_COMPLEX:
19577 	  mpc_set_q(sc->mpc_1, big_ratio(x), MPC_RNDNN);
19578 	  mpc_add(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
19579 	  return(mpc_to_number(sc, sc->mpc_1));
19580 	default:
19581 	  return(method_or_bust_with_type_pp(sc, y, sc->add_symbol, x, y, a_number_string, 2));
19582 	}
19583 
19584     case T_BIG_REAL:
19585       switch (type(y))
19586 	{
19587 	case T_INTEGER:
19588 	  mpfr_add_si(sc->mpfr_1, big_real(x), integer(y), MPFR_RNDN);
19589 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19590 	case T_RATIO:
19591 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
19592 	  mpfr_add_q(sc->mpfr_1, big_real(x), sc->mpq_1, MPFR_RNDN);
19593 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19594 	case T_REAL:
19595 	  if (is_NaN(real(y))) return(real_NaN);
19596 	  mpfr_add_d(sc->mpfr_1, big_real(x), real(y), MPFR_RNDN);
19597 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19598 	case T_COMPLEX:
19599 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
19600 	  mpc_add_fr(sc->mpc_1, sc->mpc_1, big_real(x), MPC_RNDNN);
19601 	  return(mpc_to_number(sc, sc->mpc_1));
19602 	case T_BIG_INTEGER:
19603 	  mpfr_add_z(sc->mpfr_1, big_real(x), big_integer(y), MPFR_RNDN);
19604 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19605 	case T_BIG_RATIO:
19606 	  mpfr_add_q(sc->mpfr_1, big_real(x), big_ratio(y), MPFR_RNDN);
19607 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19608 	case T_BIG_REAL:
19609 	  mpfr_add(sc->mpfr_1, big_real(x), big_real(y), MPFR_RNDN);
19610 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19611 	case T_BIG_COMPLEX:
19612 	  mpc_add_fr(sc->mpc_1, big_complex(y), big_real(x), MPC_RNDNN);
19613 	  return(mpc_to_number(sc, sc->mpc_1));
19614 	default:
19615 	  return(method_or_bust_with_type_pp(sc, y, sc->add_symbol, x, y, a_number_string, 2));
19616 	}
19617     case T_BIG_COMPLEX:
19618       switch (type(y))
19619 	{
19620 	case T_INTEGER:
19621 	  mpc_set_si(sc->mpc_1, integer(y), MPC_RNDNN);
19622 	  mpc_add(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
19623 	  return(mpc_to_number(sc, sc->mpc_1));
19624 	case T_RATIO:
19625 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
19626 	  mpc_set_q(sc->mpc_1, sc->mpq_1, MPC_RNDNN);
19627 	  mpc_add(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
19628 	  return(mpc_to_number(sc, sc->mpc_1));
19629 	case T_REAL:
19630 	  /* if (is_NaN(real(y))) return(real_NaN); */
19631 	  mpc_set_d_d(sc->mpc_1, real(y), 0.0, MPC_RNDNN);
19632 	  mpc_add(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
19633 	  return(mpc_to_number(sc, sc->mpc_1));
19634 	case T_COMPLEX:
19635 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
19636 	  mpc_add(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
19637 	  return(mpc_to_number(sc, sc->mpc_1));
19638 	case T_BIG_INTEGER:
19639 	  mpc_set_z(sc->mpc_1, big_integer(y), MPC_RNDNN);
19640 	  mpc_add(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
19641 	  return(mpc_to_number(sc, sc->mpc_1));
19642 	case T_BIG_RATIO:
19643 	  mpc_set_q(sc->mpc_1, big_ratio(y), MPC_RNDNN);
19644 	  mpc_add(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
19645 	  return(mpc_to_number(sc, sc->mpc_1));
19646 	case T_BIG_REAL:
19647 	  mpc_add_fr(sc->mpc_1, big_complex(x), big_real(y), MPC_RNDNN);
19648 	  return(mpc_to_number(sc, sc->mpc_1));
19649 	case T_BIG_COMPLEX:
19650 	  mpc_add(sc->mpc_1, big_complex(x), big_complex(y), MPC_RNDNN);
19651 	  return(mpc_to_number(sc, sc->mpc_1));
19652 	default:
19653 	  return(method_or_bust_with_type_pp(sc, y, sc->add_symbol, x, y, a_number_string, 2));
19654 	}
19655 #endif
19656       default:
19657 	return(method_or_bust_with_type_pp(sc, x, sc->add_symbol, x, y, a_number_string, 1));
19658     }
19659 }
19660 
19661 static s7_pointer add_p_ppp(s7_scheme *sc, s7_pointer x, s7_pointer y, s7_pointer z) {return(add_p_pp(sc, add_p_pp(sc, x, y), z));}
19662 
19663 static s7_pointer g_add(s7_scheme *sc, s7_pointer args)
19664 {
19665   #define H_add "(+ ...) adds its arguments"
19666   #define Q_add sc->pcl_n
19667   s7_pointer x, p;
19668 
19669   if (is_null(args))
19670     return(int_zero);
19671 
19672   x = car(args);
19673   p = cdr(args);
19674   if (is_null(p))
19675     {
19676       if (!is_number(x))
19677 	return(method_or_bust_with_type_one_arg(sc, x, sc->add_symbol, args, a_number_string));
19678       return(x);
19679     }
19680 
19681   if (is_null(cdr(p)))
19682     return(add_p_pp(sc, x, car(p)));
19683 
19684   for (; is_pair(p); p = cdr(p))
19685     x = add_p_pp(sc, x, car(p));
19686 
19687   return(x);
19688 }
19689 
19690 static s7_pointer g_add_2(s7_scheme *sc, s7_pointer args) {return(add_p_pp(sc, car(args), cadr(args)));}
19691 
19692 static s7_pointer g_add_3(s7_scheme *sc, s7_pointer args)
19693 {
19694   s7_pointer p0, p1, p2;
19695   p0 = car(args);
19696   p1 = cadr(args);
19697   p2 = caddr(args);
19698   if ((is_t_integer(p0)) && (is_t_integer(p1)) && (is_t_integer(p2)))
19699     {
19700 #if HAVE_OVERFLOW_CHECKS
19701       s7_int val;
19702       if ((!add_overflow(integer(p0), integer(p1), &val)) &&
19703 	  (!add_overflow(val, integer(p2), &val)))
19704 	return(make_integer(sc, val));
19705 #if WITH_GMP
19706       mpz_set_si(sc->mpz_1, integer(p0));
19707       mpz_set_si(sc->mpz_2, integer(p1));
19708       mpz_add(sc->mpz_1, sc->mpz_1, sc->mpz_2);
19709       mpz_set_si(sc->mpz_2, integer(p2));
19710       mpz_add(sc->mpz_1, sc->mpz_1, sc->mpz_2);
19711       return(mpz_to_integer(sc, sc->mpz_1));
19712 #else
19713       return(make_real(sc, (long_double)integer(p0) + (long_double)integer(p1) + (long_double)integer(p2)));
19714 #endif
19715 #else
19716       return(make_integer(sc, integer(p0) + integer(p1) + integer(p2)));
19717 #endif
19718     }
19719   if ((is_t_real(p0)) && (is_t_real(p1)) && (is_t_real(p2)))
19720     return(make_real(sc, real(p0) + real(p1) + real(p2)));
19721   return(add_p_pp(sc, add_p_pp(sc, p0, p1), p2));
19722 }
19723 /* trade-off in add_3: time saved by using add_p_pp, but it conses up a new number cell, so subsequent gc can overwhelm the gains, and add add_p_pp overhead
19724  *   need int wrap as output or reuse-if-known-temp, or perhaps free if not permanent
19725  */
19726 
19727 static s7_pointer g_add_x1_1(s7_scheme *sc, s7_pointer x, int pos)
19728 {
19729   if (is_t_integer(x))
19730     return(add_if_overflow_to_real_or_big_integer(sc, integer(x), 1));
19731 
19732   switch (type(x))
19733     {
19734     case T_RATIO:   return(add_p_pp(sc, x, int_one));
19735     case T_REAL:    return(make_real(sc, real(x) + 1.0));
19736     case T_COMPLEX: return(s7_make_complex(sc, real_part(x) + 1.0, imag_part(x)));
19737 #if WITH_GMP
19738     case T_BIG_INTEGER:
19739       mpz_set_si(sc->mpz_1, 1);
19740       mpz_add(sc->mpz_1, big_integer(x), sc->mpz_1);
19741       return(mpz_to_integer(sc, sc->mpz_1));
19742     case T_BIG_RATIO:
19743     case T_BIG_REAL:
19744     case T_BIG_COMPLEX:
19745       return(add_p_pp(sc, x, int_one));
19746 #endif
19747     default:
19748       return(method_or_bust_with_type(sc, x, sc->add_symbol,
19749 				      (pos == 1) ? list_2(sc, x, int_one) : list_2(sc, int_one, x),
19750 				      a_number_string, pos));
19751     }
19752   return(x);
19753 }
19754 
19755 #if WITH_GMP
19756 static s7_pointer g_add_x1(s7_scheme *sc, s7_pointer args) {return(g_add_x1_1(sc, car(args), 1));}
19757 #else
19758 static s7_pointer g_add_x1(s7_scheme *sc, s7_pointer args)
19759 {
19760   s7_pointer x;
19761   x = car(args);
19762   if (is_t_integer(x)) return(make_integer(sc, integer(x) + 1));
19763   if (is_t_real(x)) return(make_real(sc, real(x) + 1.0));
19764   if (is_t_complex(x)) return(s7_make_complex(sc, real_part(x) + 1.0, imag_part(x)));
19765   return(add_p_pp(sc, x, int_one));
19766 }
19767 #endif
19768 static s7_pointer g_add_1x(s7_scheme *sc, s7_pointer args) {return(g_add_x1_1(sc, cadr(args), 2));}
19769 
19770 static s7_pointer g_add_xi(s7_scheme *sc, s7_pointer x, s7_int y)
19771 {
19772   if (is_t_integer(x))
19773     return(add_if_overflow_to_real_or_big_integer(sc, integer(x), y));
19774 
19775   switch (type(x))
19776     {
19777     case T_RATIO:   return(add_p_pp(sc, x, wrap_integer1(sc, y)));
19778     case T_REAL:    return(make_real(sc, real(x) + y));
19779     case T_COMPLEX: return(s7_make_complex(sc, real_part(x) + y, imag_part(x)));
19780 #if WITH_GMP
19781     case T_BIG_INTEGER:
19782       mpz_set_si(sc->mpz_1, y);
19783       mpz_add(sc->mpz_1, big_integer(x), sc->mpz_1);
19784       return(mpz_to_integer(sc, sc->mpz_1));
19785     case T_BIG_RATIO:
19786     case T_BIG_REAL:
19787     case T_BIG_COMPLEX:
19788       return(add_p_pp(sc, x, wrap_integer1(sc, y)));
19789 #endif
19790     default: return(method_or_bust_with_type_pi(sc, x, sc->add_symbol, x, y, a_number_string));
19791     }
19792   return(x);
19793 }
19794 
19795 static s7_pointer g_add_xf(s7_scheme *sc, s7_pointer x, s7_double y)
19796 {
19797   if (is_t_real(x)) return(make_real(sc, real(x) + y));
19798   switch (type(x))
19799     {
19800     case T_INTEGER: return(make_real(sc, integer(x) + y));
19801     case T_RATIO:   return(make_real(sc, fraction(x) + y));
19802     case T_COMPLEX: return(s7_make_complex(sc, real_part(x) + y, imag_part(x)));
19803 #if WITH_GMP
19804     case T_BIG_INTEGER: case T_BIG_RATIO: case T_BIG_REAL: case T_BIG_COMPLEX:
19805       return(add_p_pp(sc, x, wrap_real1(sc, y)));
19806 #endif
19807     default: return(method_or_bust_with_type_pf(sc, x, sc->add_symbol, x, y, a_number_string));
19808     }
19809   return(x);
19810 }
19811 
19812 static s7_pointer g_add_2_ff(s7_scheme *sc, s7_pointer args)
19813 {
19814 #if WITH_GMP
19815   if ((is_t_real(car(args))) && (is_t_real(cadr(args))))
19816     return(make_real(sc, real(car(args)) + real(cadr(args))));
19817   return(add_p_pp(sc, car(args), cadr(args)));
19818 #else
19819   return(make_real(sc, real(car(args)) + real(cadr(args))));
19820 #endif
19821 }
19822 
19823 static s7_pointer g_add_2_ii(s7_scheme *sc, s7_pointer args)
19824 {
19825 #if WITH_GMP
19826   if ((is_t_integer(car(args))) && (is_t_integer(cadr(args))))
19827 #endif
19828     return(add_if_overflow_to_real_or_big_integer(sc, integer(car(args)), integer(cadr(args))));
19829 #if WITH_GMP
19830   return(g_add(sc, args)); /* possibly bigint? */
19831 #endif
19832 }
19833 
19834 #if WITH_GMP
19835 static s7_pointer add_2_if(s7_scheme *sc, s7_pointer x, s7_pointer y)
19836 {
19837   if ((is_t_integer(x)) && (is_t_real(y)))
19838     {
19839       if (s7_int_abs(integer(x)) >= INT64_TO_DOUBLE_LIMIT)
19840 	{
19841 	  mpfr_set_si(sc->mpfr_1, integer(x), MPFR_RNDN);
19842 	  mpfr_add_d(sc->mpfr_1, sc->mpfr_1, real(y), MPFR_RNDN);
19843 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
19844 	}
19845       return(make_real(sc, integer(x) + real(y)));
19846     }
19847   return(add_p_pp(sc, x, y));
19848 }
19849 
19850 static s7_pointer g_add_2_if(s7_scheme *sc, s7_pointer args) {return(add_2_if(sc, car(args), cadr(args)));}
19851 static s7_pointer g_add_2_fi(s7_scheme *sc, s7_pointer args) {return(add_2_if(sc, cadr(args), car(args)));}
19852 
19853 static s7_pointer g_add_2_xi(s7_scheme *sc, s7_pointer args) {if (is_t_integer(cadr(args))) return(g_add_xi(sc, car(args), integer(cadr(args)))); return(g_add(sc, args));}
19854 static s7_pointer g_add_2_ix(s7_scheme *sc, s7_pointer args) {if (is_t_integer(car(args))) return(g_add_xi(sc, cadr(args), integer(car(args)))); return(g_add(sc, args));}
19855 static s7_pointer g_add_2_xf(s7_scheme *sc, s7_pointer args) {if (is_t_real(cadr(args))) return(g_add_xf(sc, car(args), real(cadr(args)))); return(g_add(sc, args));}
19856 static s7_pointer g_add_2_fx(s7_scheme *sc, s7_pointer args) {if (is_t_real(car(args))) return(g_add_xf(sc, cadr(args), real(car(args)))); return(g_add(sc, args));}
19857 
19858 #else
19859 
19860 static s7_pointer g_add_2_if(s7_scheme *sc, s7_pointer args) {return(make_real(sc, integer(car(args)) + real(cadr(args))));}
19861 static s7_pointer g_add_2_fi(s7_scheme *sc, s7_pointer args) {return(make_real(sc, real(car(args)) + integer(cadr(args))));}
19862 static s7_pointer g_add_2_xi(s7_scheme *sc, s7_pointer args) {return(g_add_xi(sc, car(args), integer(cadr(args))));}
19863 static s7_pointer g_add_2_ix(s7_scheme *sc, s7_pointer args) {return(g_add_xi(sc, cadr(args), integer(car(args))));}
19864 static s7_pointer g_add_2_xf(s7_scheme *sc, s7_pointer args) {return(g_add_xf(sc, car(args), real(cadr(args))));}
19865 static s7_pointer g_add_2_fx(s7_scheme *sc, s7_pointer args) {return(g_add_xf(sc, cadr(args), real(car(args))));}
19866 #endif
19867 
19868 static s7_pointer add_p_dd(s7_scheme *sc, s7_double x1, s7_double x2) {return(make_real(sc, x1 + x2));}
19869 /* add_p_ii and add_d_id unhittable apparently */
19870 
19871 static s7_double add_d_d(s7_double x) {return(x);}
19872 static s7_double add_d_dd(s7_double x1, s7_double x2) {return(x1 + x2);}
19873 static s7_double add_d_ddd(s7_double x1, s7_double x2, s7_double x3) {return(x1 + x2 + x3);}
19874 static s7_double add_d_dddd(s7_double x1, s7_double x2, s7_double x3, s7_double x4) {return(x1 + x2 + x3 + x4);}
19875 
19876 static s7_int add_i_ii(s7_int i1, s7_int i2) {return(i1 + i2);}
19877 static s7_int add_i_iii(s7_int i1, s7_int i2, s7_int i3) {return(i1 + i2 + i3);}
19878 
19879 static s7_pointer argument_type(s7_scheme *sc, s7_pointer arg1)
19880 {
19881   if (is_pair(arg1))
19882     {
19883       if (car(arg1) == sc->quote_symbol)
19884 	return((is_pair(cdr(arg1))) ? s7_type_of(sc, cadr(arg1)) : NULL);    /* arg1 = (quote) */
19885 
19886       if ((is_h_optimized(arg1)) &&
19887 	  (is_safe_c_op(optimize_op(arg1))) &&
19888 	  (is_c_function(opt1_cfunc(arg1))))
19889 	{
19890 	  s7_pointer sig;
19891 	  sig = c_function_signature(opt1_cfunc(arg1));
19892 	  if ((sig) &&
19893 	      (is_pair(sig)) &&
19894 	      (is_symbol(car(sig))))
19895 	    return(car(sig));
19896 	}
19897       /* perhaps add closure sig if we can depend on it (immutable func etc) */
19898     }
19899   else
19900     if (!is_symbol(arg1))
19901       return(s7_type_of(sc, arg1));
19902   return(NULL);
19903 }
19904 
19905 static s7_pointer chooser_check_arg_types(s7_scheme *sc, s7_pointer arg1, s7_pointer arg2, s7_pointer fallback,
19906 					  s7_pointer f_2_ff, s7_pointer f_2_ii, s7_pointer f_2_if, s7_pointer f_2_fi,
19907 					  s7_pointer f_2_xi, s7_pointer f_2_ix, s7_pointer f_2_fx, s7_pointer f_2_xf)
19908 {
19909   s7_pointer arg1_type, arg2_type;
19910 
19911   arg1_type = argument_type(sc, arg1);
19912   arg2_type = argument_type(sc, arg2);
19913   if ((arg1_type) || (arg2_type))
19914     {
19915       if (arg1_type == sc->is_float_symbol)
19916 	{
19917 	  if (arg2_type == sc->is_float_symbol)
19918 	    return(f_2_ff);
19919 	  return((arg2_type == sc->is_integer_symbol) ? f_2_fi : f_2_fx);
19920 	}
19921       if (arg1_type == sc->is_integer_symbol)
19922 	{
19923 	  if (arg2_type == sc->is_float_symbol)
19924 	    return(f_2_if);
19925 	  return((arg2_type == sc->is_integer_symbol) ? f_2_ii : f_2_ix);
19926 	}
19927       if (arg2_type == sc->is_float_symbol)
19928 	return(f_2_xf);
19929       if (arg2_type == sc->is_integer_symbol)
19930 	return(f_2_xi);
19931     }
19932   return(fallback);
19933 }
19934 
19935 static s7_pointer g_random_i(s7_scheme *sc, s7_pointer args);
19936 
19937 static s7_pointer add_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
19938 {
19939   /* (+ s f) (+ (* s s) s) (+ s s) (+ s (* s s)) */
19940   if (args == 2)
19941     {
19942       if (ops)
19943 	{
19944 	  s7_pointer arg1, arg2;
19945 	  arg1 = cadr(expr);
19946 	  arg2 = caddr(expr);
19947 	  if (arg2 == int_one)                          /* (+ ... 1) */
19948 	    return(sc->add_x1);
19949 	  if ((is_t_integer(arg1)) && ((is_pair(arg2)) && (is_optimized(arg2)) && (is_h_safe_c_d(arg2)) && (fn_proc(arg2) == g_random_i)))
19950 	    {
19951 	      set_opt3_int(cdr(expr), cadr(arg2));
19952 	      set_safe_optimize_op(expr, HOP_SAFE_C_D); /* op if r op? */
19953 	      return(sc->add_i_random);
19954 	    }
19955 	  if (arg1 == int_one)
19956 	    return(sc->add_1x);
19957 	  return(chooser_check_arg_types(sc, arg1, arg2, sc->add_2,
19958 					 sc->add_2_ff, sc->add_2_ii, sc->add_2_if, sc->add_2_fi,
19959 					 sc->add_2_xi, sc->add_2_ix, sc->add_2_fx, sc->add_2_xf));
19960 	}
19961       return(sc->add_2);
19962     }
19963   return((args == 3) ? sc->add_3 : f);
19964 }
19965 
19966 /* ---------------------------------------- subtract ---------------------------------------- */
19967 
19968 static s7_pointer negate_p_p(s7_scheme *sc, s7_pointer p)     /* can't use "negate" because it confuses C++! */
19969 {
19970   switch (type(p))
19971     {
19972     case T_INTEGER:
19973       if (integer(p) == S7_INT64_MIN)
19974 #if WITH_GMP
19975 	{
19976 	  mpz_set_si(sc->mpz_1, S7_INT64_MIN);
19977 	  mpz_neg(sc->mpz_1, sc->mpz_1);
19978 	  return(mpz_to_big_integer(sc, sc->mpz_1));
19979 	}
19980 #else
19981 	return(simple_out_of_range(sc, sc->subtract_symbol, p, wrap_string(sc, "most-negative-fixnum can't be negated", 37)));
19982 #endif
19983       return(make_integer(sc, -integer(p)));
19984 
19985     case T_RATIO:
19986       return(make_simple_ratio(sc, -numerator(p), denominator(p)));
19987 
19988     case T_REAL:
19989       return(make_real(sc, -real(p)));
19990 
19991     case T_COMPLEX:
19992       return(s7_make_complex(sc, -real_part(p), -imag_part(p)));
19993 
19994 #if WITH_GMP
19995     case T_BIG_INTEGER:
19996       mpz_neg(sc->mpz_1, big_integer(p));
19997       return(mpz_to_integer(sc, sc->mpz_1));
19998 
19999     case T_BIG_RATIO:
20000       mpq_neg(sc->mpq_1, big_ratio(p));
20001       mpq_canonicalize(sc->mpq_1);
20002       return(mpq_to_rational(sc, sc->mpq_1));
20003 
20004     case T_BIG_REAL:
20005       mpfr_neg(sc->mpfr_1, big_real(p), MPFR_RNDN);
20006       return(mpfr_to_big_real(sc, sc->mpfr_1));
20007 
20008     case T_BIG_COMPLEX:
20009       mpc_neg(sc->mpc_1, big_complex(p), MPC_RNDNN);
20010       return(mpc_to_number(sc, sc->mpc_1));
20011 #endif
20012 
20013     default:
20014       return(method_or_bust_with_type_one_arg_p(sc, p, sc->subtract_symbol, a_number_string));
20015     }
20016 }
20017 
20018 static inline s7_pointer subtract_if_overflow_to_real_or_big_integer(s7_scheme *sc, s7_int x, s7_int y)
20019 {
20020 #if HAVE_OVERFLOW_CHECKS
20021   s7_int val;
20022   if (subtract_overflow(x, y, &val))
20023 #if WITH_GMP
20024     {
20025       mpz_set_si(sc->mpz_1, x);
20026       mpz_set_si(sc->mpz_2, y);
20027       mpz_sub(sc->mpz_1, sc->mpz_1, sc->mpz_2);
20028       return(mpz_to_big_integer(sc, sc->mpz_1));
20029     }
20030 #else
20031   return(make_real(sc, (double)x - (double)y));
20032 #endif
20033   return(make_integer(sc, val));
20034 #else
20035   return(make_integer(sc, x - y));
20036 #endif
20037 }
20038 
20039 static s7_pointer subtract_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
20040 {
20041   switch (type(x))
20042     {
20043     case T_INTEGER:
20044       if (integer(x) == 0)
20045 	return(negate_p_p(sc, y));
20046       switch (type(y))
20047 	{
20048 	case T_INTEGER:
20049 	  return(subtract_if_overflow_to_real_or_big_integer(sc, integer(x), integer(y)));
20050 
20051 	case T_RATIO:
20052 	  {
20053 #if HAVE_OVERFLOW_CHECKS
20054 	    s7_int z;
20055 	    if ((multiply_overflow(integer(x), denominator(y), &z)) ||
20056 		(subtract_overflow(z, numerator(y), &z)))
20057 #if WITH_GMP
20058 	      {
20059 		mpz_set_si(sc->mpz_1, integer(x));
20060 		mpz_mul_si(sc->mpz_1, sc->mpz_1, denominator(y));
20061 		mpz_set_si(sc->mpz_2, numerator(y));
20062 		mpz_sub(mpq_numref(sc->mpq_1), sc->mpz_1, sc->mpz_2);
20063 		mpz_set_si(mpq_denref(sc->mpq_1), denominator(y));
20064 		return(mpq_to_rational(sc, sc->mpq_1));
20065 	      }
20066 #else
20067 	      return(make_real(sc, (long_double)integer(x) - fraction(y)));
20068 #endif
20069 	      return(s7_make_ratio(sc, z, denominator(y)));
20070 #else
20071 	    return(s7_make_ratio(sc, integer(x) * denominator(y) - numerator(y), denominator(y)));
20072 #endif
20073 	  }
20074 	case T_REAL:
20075 #if WITH_GMP
20076 	  if (s7_int_abs(integer(x)) >= INT64_TO_DOUBLE_LIMIT) /* (- 9223372036854775807 .1) */
20077 	    {
20078 	      mpfr_set_si(sc->mpfr_1, integer(x), MPFR_RNDN);
20079 	      mpfr_sub_d(sc->mpfr_1, sc->mpfr_1, real(y), MPFR_RNDN);
20080 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
20081 	    }
20082 #endif
20083 	  return(make_real(sc, (long_double)integer(x) - real(y)));
20084 	case T_COMPLEX:
20085 	  return(s7_make_complex(sc, (long_double)integer(x) - real_part(y), -imag_part(y)));
20086 #if WITH_GMP
20087 	case T_BIG_INTEGER:
20088 	  mpz_set_si(sc->mpz_1, integer(x));
20089 	  mpz_sub(sc->mpz_1, sc->mpz_1, big_integer(y));
20090 	  return(mpz_to_integer(sc, sc->mpz_1));
20091 	case T_BIG_RATIO:
20092 	  mpq_set_si(sc->mpq_1, integer(x), 1);
20093 	  mpq_sub(sc->mpq_1, sc->mpq_1, big_ratio(y));
20094 	  return(mpq_to_rational(sc, sc->mpq_1));
20095 	case T_BIG_REAL:
20096 	  mpfr_si_sub(sc->mpfr_1, integer(x), big_real(y), MPFR_RNDN);
20097 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20098 	case T_BIG_COMPLEX:
20099 	  mpc_set_si(sc->mpc_1, integer(x), MPC_RNDNN);
20100 	  mpc_sub(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20101 	  return(mpc_to_number(sc, sc->mpc_1));
20102 #endif
20103 	default:
20104 	  return(method_or_bust_with_type_pp(sc, y, sc->subtract_symbol, x, y, a_number_string, 2));
20105 	}
20106 
20107     case T_RATIO:
20108       switch (type(y))
20109 	{
20110 	case T_INTEGER:
20111 	  {
20112 #if HAVE_OVERFLOW_CHECKS
20113 	    s7_int z;
20114 	    if ((multiply_overflow(integer(y), denominator(x), &z)) ||
20115 		(subtract_overflow(numerator(x), z, &z)))
20116 #if WITH_GMP
20117 	      {
20118 		mpz_set_si(sc->mpz_1, integer(y));
20119 		mpz_mul_si(sc->mpz_1, sc->mpz_1, denominator(x));
20120 		mpz_set_si(sc->mpz_2, numerator(x));
20121 		mpz_sub(mpq_numref(sc->mpq_1), sc->mpz_2, sc->mpz_1);
20122 		mpz_set_si(mpq_denref(sc->mpq_1), denominator(x));
20123 		return(mpq_to_rational(sc, sc->mpq_1));
20124 	      }
20125 #else
20126 	    return(make_real(sc, fraction(x) - (long_double)integer(y)));
20127 #endif
20128 	    return(s7_make_ratio(sc, z, denominator(x)));
20129 #else
20130 	    return(s7_make_ratio(sc, numerator(x) - (integer(y) * denominator(x)), denominator(x)));
20131 #endif
20132 	  }
20133 	case T_RATIO:
20134 	  {
20135 	    s7_int d1, d2, n1, n2;
20136 	    parcel_out_fractions(x, y);
20137 	    if (d1 == d2)
20138 	      {
20139 #if HAVE_OVERFLOW_CHECKS
20140 		s7_int q;
20141 		if (subtract_overflow(n1, n2, &q))
20142 #if WITH_GMP
20143 		  {
20144 		    mpq_set_si(sc->mpq_1, n1, d1);
20145 		    mpq_set_si(sc->mpq_2, n2, d2);
20146 		    mpq_sub(sc->mpq_1, sc->mpq_1, sc->mpq_2);
20147 		    return(mpq_to_rational(sc, sc->mpq_1));
20148 		  }
20149 #else
20150 		return(make_real(sc, ((long_double)n1 - (long_double)n2) / (long_double)d1));
20151 #endif
20152 	        return(s7_make_ratio(sc, q, d1));
20153 #else
20154 		return(s7_make_ratio(sc, numerator(x) - numerator(y), denominator(x)));
20155 #endif
20156 	      }
20157 
20158 #if HAVE_OVERFLOW_CHECKS
20159 	    {
20160 	      s7_int n1d2, n2d1, d1d2, q;
20161 	      if ((multiply_overflow(d1, d2, &d1d2)) ||
20162 		  (multiply_overflow(n1, d2, &n1d2)) ||
20163 		  (multiply_overflow(n2, d1, &n2d1)) ||
20164 		  (subtract_overflow(n1d2, n2d1, &q)))
20165 #if WITH_GMP
20166 		{
20167 		  mpq_set_si(sc->mpq_1, n1, d1);
20168 		  mpq_set_si(sc->mpq_2, n2, d2);
20169 		  mpq_sub(sc->mpq_1, sc->mpq_1, sc->mpq_2);
20170 		  return(mpq_to_rational(sc, sc->mpq_1));
20171 		}
20172 #else
20173 	      return(make_real(sc, ((long_double)n1 / (long_double)d1) - ((long_double)n2 / (long_double)d2)));
20174 #endif
20175 	      return(s7_make_ratio(sc, q, d1d2));
20176 	    }
20177 #else
20178 	    return(s7_make_ratio(sc, n1 * d2 - n2 * d1, d1 * d2));
20179 #endif
20180 	  }
20181 	case T_REAL:
20182 	  return(make_real(sc, fraction(x) - real(y)));
20183 	case T_COMPLEX:
20184 	  return(s7_make_complex(sc, fraction(x) - real_part(y), -imag_part(y)));
20185 #if WITH_GMP
20186 	case T_BIG_INTEGER:
20187 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
20188 	  mpq_set_z(sc->mpq_2, big_integer(y));
20189 	  mpq_sub(sc->mpq_1, sc->mpq_1, sc->mpq_2);
20190 	  return(mpq_to_rational(sc, sc->mpq_1));
20191 	case T_BIG_RATIO:
20192 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
20193 	  mpq_sub(sc->mpq_1, sc->mpq_1, big_ratio(y));
20194 	  return(mpq_to_rational(sc, sc->mpq_1));
20195 	case T_BIG_REAL:
20196 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
20197 	  mpfr_set_q(sc->mpfr_1, sc->mpq_1, MPFR_RNDN);
20198 	  mpfr_sub(sc->mpfr_1, sc->mpfr_1, big_real(y), MPFR_RNDN);
20199 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20200 	case T_BIG_COMPLEX:
20201 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
20202 	  mpc_set_q(sc->mpc_1, sc->mpq_1, MPC_RNDNN);
20203 	  mpc_sub(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20204 	  return(mpc_to_number(sc, sc->mpc_1));
20205 #endif
20206 	default:
20207 	  return(method_or_bust_with_type_pp(sc, y, sc->subtract_symbol, x, y, a_number_string, 2));
20208 	}
20209 
20210     case T_REAL:
20211       switch (type(y))
20212 	{
20213 	case T_INTEGER:
20214 #if WITH_GMP
20215 	  if (s7_int_abs(integer(y)) >= INT64_TO_DOUBLE_LIMIT) /* (- .1 92233720368547758071) */
20216 	    {
20217 	      mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
20218 	      mpfr_sub_si(sc->mpfr_1, sc->mpfr_1, integer(y), MPFR_RNDN);
20219 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
20220 	    }
20221 #endif
20222 	  return(make_real(sc, real(x) - (long_double)integer(y))); /* long_double saves (- 9007199254740996.0 9007199254740995): 1.0 */
20223 	case T_RATIO:
20224 	  return(make_real(sc, real(x) - fraction(y)));
20225 	case T_REAL:
20226 	  return(make_real(sc, real(x) - real(y)));
20227 	case T_COMPLEX:
20228 	  return(s7_make_complex(sc, real(x) - real_part(y), -imag_part(y)));
20229 #if WITH_GMP
20230 	case T_BIG_INTEGER:
20231 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
20232 	  mpfr_sub_z(sc->mpfr_1, sc->mpfr_1, big_integer(y), MPFR_RNDN);
20233 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20234 	case T_BIG_RATIO:
20235 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
20236 	  mpfr_sub_q(sc->mpfr_1, sc->mpfr_1, big_ratio(y), MPFR_RNDN);
20237 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20238 	case T_BIG_REAL:
20239 	  mpfr_d_sub(sc->mpfr_1, real(x), big_real(y), MPFR_RNDN);
20240 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20241 	case T_BIG_COMPLEX:
20242 	  mpc_set_d_d(sc->mpc_1, real(x), 0.0, MPC_RNDNN);
20243 	  mpc_sub(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20244 	  return(mpc_to_number(sc, sc->mpc_1));
20245 #endif
20246 	default:
20247 	  return(method_or_bust_with_type_pp(sc, y, sc->subtract_symbol, x, y, a_number_string, 2));
20248 	}
20249 
20250     case T_COMPLEX:
20251       switch (type(y))
20252 	{
20253 	case T_INTEGER:
20254 	  return(s7_make_complex(sc, real_part(x) - integer(y), imag_part(x)));
20255 	case T_RATIO:
20256 	  return(s7_make_complex(sc, real_part(x) - fraction(y), imag_part(x)));
20257 	case T_REAL:
20258 	  return(s7_make_complex(sc, real_part(x) - real(y), imag_part(x)));
20259 	case T_COMPLEX:
20260 	  return(make_complex(sc, real_part(x) - real_part(y), imag_part(x) - imag_part(y)));
20261 #if WITH_GMP
20262 	case T_BIG_INTEGER:
20263 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
20264 	  mpc_set_z(sc->mpc_2, big_integer(y), MPC_RNDNN);
20265 	  mpc_sub(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
20266 	  return(mpc_to_number(sc, sc->mpc_1));
20267 	case T_BIG_RATIO:
20268 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
20269 	  mpc_set_q(sc->mpc_2, big_ratio(y), MPC_RNDNN);
20270 	  mpc_sub(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
20271 	  return(mpc_to_number(sc, sc->mpc_1));
20272 	case T_BIG_REAL:
20273 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
20274 	  mpc_sub_fr(sc->mpc_1, sc->mpc_1, big_real(y), MPC_RNDNN);
20275 	  return(mpc_to_number(sc, sc->mpc_1));
20276 	case T_BIG_COMPLEX:
20277 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
20278 	  mpc_sub(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20279 	  return(mpc_to_number(sc, sc->mpc_1));
20280 #endif
20281 	default:
20282 	  return(method_or_bust_with_type_pp(sc, y, sc->subtract_symbol, x, y, a_number_string, 2));
20283 	}
20284 
20285 #if WITH_GMP
20286     case T_BIG_INTEGER:
20287       switch (type(y))
20288 	{
20289 	case T_INTEGER:
20290 	  mpz_set_si(sc->mpz_1, integer(y));
20291 	  mpz_sub(sc->mpz_1, big_integer(x), sc->mpz_1);
20292 	  return(mpz_to_integer(sc, sc->mpz_1));
20293 	case T_RATIO:
20294 	  mpq_set_z(sc->mpq_2, big_integer(x));
20295 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
20296 	  mpq_sub(sc->mpq_1, sc->mpq_2, sc->mpq_1);
20297 	  mpq_canonicalize(sc->mpq_1);
20298 	  return(mpq_to_rational(sc, sc->mpq_1));
20299 	case T_REAL:
20300 	  if (is_NaN(real(y))) return(real_NaN);
20301 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
20302 	  mpfr_sub_d(sc->mpfr_1, sc->mpfr_1, real(y), MPFR_RNDN);
20303 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20304 	case T_COMPLEX:
20305 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
20306 	  mpc_set_z(sc->mpc_2, big_integer(x), MPC_RNDNN);
20307 	  mpc_sub(sc->mpc_1, sc->mpc_2, sc->mpc_1, MPC_RNDNN);
20308 	  return(mpc_to_number(sc, sc->mpc_1));
20309 	case T_BIG_INTEGER:
20310 	  mpz_sub(sc->mpz_1, big_integer(x), big_integer(y));
20311 	  return(mpz_to_integer(sc, sc->mpz_1));
20312 	case T_BIG_RATIO:
20313 	  mpq_set_z(sc->mpq_1, big_integer(x));
20314 	  mpq_sub(sc->mpq_1, sc->mpq_1, big_ratio(y));
20315 	  return(mpq_to_rational(sc, sc->mpq_1));
20316 	case T_BIG_REAL:
20317 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
20318 	  mpfr_sub(sc->mpfr_1, sc->mpfr_1, big_real(y), MPFR_RNDN);
20319 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20320 	case T_BIG_COMPLEX:
20321 	  mpc_set_z(sc->mpc_1, big_integer(x), MPC_RNDNN);
20322 	  mpc_sub(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20323 	  return(mpc_to_number(sc, sc->mpc_1));
20324 	default:
20325 	  return(method_or_bust_with_type_pp(sc, y, sc->subtract_symbol, x, y, a_number_string, 2));
20326 	}
20327 
20328     case T_BIG_RATIO:
20329       switch (type(y))
20330 	{
20331 	case T_INTEGER:
20332 	  mpq_set_si(sc->mpq_1, integer(y), 1);
20333 	  mpq_sub(sc->mpq_1, big_ratio(x), sc->mpq_1);
20334 	  return(mpq_to_rational(sc, sc->mpq_1));
20335 	case T_RATIO:
20336 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
20337 	  mpq_sub(sc->mpq_1, big_ratio(x), sc->mpq_1);
20338 	  return(mpq_to_rational(sc, sc->mpq_1));
20339 	case T_REAL:
20340 	  if (is_NaN(real(y))) return(real_NaN);
20341 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
20342 	  mpfr_sub_d(sc->mpfr_1, sc->mpfr_1, real(y), MPFR_RNDN);
20343 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20344 	case T_COMPLEX:
20345 	  mpc_set_q(sc->mpc_1, big_ratio(x), MPC_RNDNN);
20346 	  mpc_set_d_d(sc->mpc_2, real_part(y), imag_part(y), MPC_RNDNN);
20347 	  mpc_sub(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
20348 	  return(mpc_to_number(sc, sc->mpc_1));
20349 	case T_BIG_INTEGER:
20350 	  mpq_set_z(sc->mpq_1, big_integer(y));
20351 	  mpq_sub(sc->mpq_1, big_ratio(x), sc->mpq_1);
20352 	  mpq_canonicalize(sc->mpq_1);
20353 	  return(mpq_to_rational(sc, sc->mpq_1));
20354 	case T_BIG_RATIO:
20355 	  mpq_sub(sc->mpq_1, big_ratio(x), big_ratio(y));
20356 	  mpq_canonicalize(sc->mpq_1);
20357 	  return(mpq_to_rational(sc, sc->mpq_1));
20358 	case T_BIG_REAL:
20359 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
20360 	  mpfr_sub(sc->mpfr_1, sc->mpfr_1, big_real(y), MPFR_RNDN);
20361 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20362 	case T_BIG_COMPLEX:
20363 	  mpc_set_q(sc->mpc_1, big_ratio(x), MPC_RNDNN);
20364 	  mpc_sub(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20365 	  return(mpc_to_number(sc, sc->mpc_1));
20366 	default:
20367 	  return(method_or_bust_with_type_pp(sc, y, sc->subtract_symbol, x, y, a_number_string, 2));
20368 	}
20369 
20370     case T_BIG_REAL:
20371       switch (type(y))
20372 	{
20373 	case T_INTEGER:
20374 	  mpfr_sub_si(sc->mpfr_1, big_real(x), integer(y), MPFR_RNDN);
20375 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20376 	case T_RATIO:
20377 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
20378 	  mpfr_sub_q(sc->mpfr_1, big_real(x), sc->mpq_1, MPFR_RNDN);
20379 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20380 	case T_REAL:
20381 	  if (is_NaN(real(y))) return(real_NaN);
20382 	  mpfr_sub_d(sc->mpfr_1, big_real(x), real(y), MPFR_RNDN);
20383 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20384 	case T_COMPLEX:
20385 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
20386 	  mpc_fr_sub(sc->mpc_1, big_real(x), sc->mpc_1, MPC_RNDNN);
20387 	  return(mpc_to_number(sc, sc->mpc_1));
20388 	case T_BIG_INTEGER:
20389 	  mpfr_sub_z(sc->mpfr_1, big_real(x), big_integer(y), MPFR_RNDN);
20390 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20391 	case T_BIG_RATIO:
20392 	  mpfr_sub_q(sc->mpfr_1, big_real(x), big_ratio(y), MPFR_RNDN);
20393 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20394 	case T_BIG_REAL:
20395 	  mpfr_sub(sc->mpfr_1, big_real(x), big_real(y), MPFR_RNDN);
20396 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20397 	case T_BIG_COMPLEX:
20398 	  mpc_fr_sub(sc->mpc_1, big_real(x), big_complex(y), MPC_RNDNN);
20399 	  return(mpc_to_number(sc, sc->mpc_1));
20400 	default:
20401 	  return(method_or_bust_with_type_pp(sc, y, sc->subtract_symbol, x, y, a_number_string, 2));
20402 	}
20403     case T_BIG_COMPLEX:
20404       switch (type(y))
20405 	{
20406 	case T_INTEGER:
20407 	  mpc_set_si(sc->mpc_2, integer(y), MPC_RNDNN);
20408 	  mpc_sub(sc->mpc_1, big_complex(x), sc->mpc_2, MPC_RNDNN);
20409 	  return(mpc_to_number(sc, sc->mpc_1));
20410 	case T_RATIO:
20411 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
20412 	  mpc_set_q(sc->mpc_1, sc->mpq_1, MPC_RNDNN);
20413 	  mpc_sub(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20414 	  return(mpc_to_number(sc, sc->mpc_1));
20415 	case T_REAL:
20416 	  /* if (is_NaN(real(y))) return(real_NaN); */
20417 	  mpc_set_d_d(sc->mpc_1, real(y), 0.0, MPC_RNDNN);
20418 	  mpc_sub(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20419 	  return(mpc_to_number(sc, sc->mpc_1));
20420 	case T_COMPLEX:
20421 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
20422 	  mpc_sub(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20423 	  return(mpc_to_number(sc, sc->mpc_1));
20424 	case T_BIG_INTEGER:
20425 	  mpc_set_z(sc->mpc_1, big_integer(y), MPC_RNDNN);
20426 	  mpc_sub(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20427 	  return(mpc_to_number(sc, sc->mpc_1));
20428 	case T_BIG_RATIO:
20429 	  mpc_set_q(sc->mpc_1, big_ratio(y), MPC_RNDNN);
20430 	  mpc_sub(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20431 	  return(mpc_to_number(sc, sc->mpc_1));
20432 	case T_BIG_REAL:
20433 	  mpc_sub_fr(sc->mpc_1, big_complex(x), big_real(y), MPC_RNDNN);
20434 	  return(mpc_to_number(sc, sc->mpc_1));
20435 	case T_BIG_COMPLEX:
20436 	  mpc_sub(sc->mpc_1, big_complex(x), big_complex(y), MPC_RNDNN);
20437 	  return(mpc_to_number(sc, sc->mpc_1));
20438 	default:
20439 	  return(method_or_bust_with_type_pp(sc, y, sc->subtract_symbol, x, y, a_number_string, 2));
20440 	}
20441 #endif
20442       default:
20443 	return(method_or_bust_with_type_pp(sc, x, sc->subtract_symbol, x, y, a_number_string, 1));
20444     }
20445 }
20446 
20447 static s7_pointer g_subtract(s7_scheme *sc, s7_pointer args)
20448 {
20449   #define H_subtract "(- x1 ...) subtracts its trailing arguments from the first, or negates the first if only one it is given"
20450   #define Q_subtract sc->pcl_n
20451 
20452   s7_pointer x, p;
20453   x = car(args);
20454   p = cdr(args);
20455 
20456   if (is_null(p))
20457     return(negate_p_p(sc, x));
20458 
20459   return((is_null(cddr(args))) ? subtract_p_pp(sc, x, cadr(args)) : subtract_p_pp(sc, x, g_add(sc, cdr(args))));
20460 }
20461 
20462 static s7_pointer g_subtract_1(s7_scheme *sc, s7_pointer args) {return(negate_p_p(sc, car(args)));}
20463 static s7_pointer g_subtract_2(s7_scheme *sc, s7_pointer args) {return(subtract_p_pp(sc, car(args), cadr(args)));}
20464 /* static s7_pointer g_subtract_3(s7_scheme *sc, s7_pointer args) {return(subtract_p_pp(sc, subtract_p_pp(sc, car(args), cadr(args)), caddr(args)));} */
20465 static s7_pointer g_subtract_3(s7_scheme *sc, s7_pointer args) {return(subtract_p_pp(sc, car(args), add_p_pp(sc, cadr(args), caddr(args))));}
20466 
20467 static s7_pointer minus_c1(s7_scheme *sc, s7_pointer x)
20468 {
20469   switch (type(x))
20470     {
20471     case T_INTEGER: return(subtract_if_overflow_to_real_or_big_integer(sc, integer(x), 1));
20472     case T_RATIO:   return(subtract_p_pp(sc, x, int_one));
20473     case T_REAL:    return(make_real(sc, real(x) - 1.0));
20474     case T_COMPLEX: return(s7_make_complex(sc, real_part(x) - 1.0, imag_part(x)));
20475 #if WITH_GMP
20476     case T_BIG_INTEGER: case T_BIG_RATIO: case T_BIG_REAL: case T_BIG_COMPLEX:
20477       return(subtract_p_pp(sc, x, int_one));
20478 #endif
20479     default:
20480       return(method_or_bust_with_type_pp(sc, x, sc->subtract_symbol, x, int_one, a_number_string, 1));
20481     }
20482   return(x);
20483 }
20484 
20485 static s7_pointer g_subtract_x1(s7_scheme *sc, s7_pointer args)
20486 {
20487   s7_pointer p;
20488   p = car(args);
20489 #if WITH_GMP
20490   return(subtract_p_pp(sc, p, int_one));
20491 #endif
20492   return((is_t_integer(p)) ? make_integer(sc, integer(p) - 1) : minus_c1(sc, p));
20493 }
20494 
20495 static s7_pointer g_subtract_2f(s7_scheme *sc, s7_pointer args) /* (- x f) */
20496 {
20497   s7_pointer x;
20498   s7_double n;
20499 
20500   x = car(args);
20501   n = real(cadr(args)); /* checked below is_t_real */
20502   if (is_t_real(x)) return(make_real(sc, real(x) - n));
20503 
20504   switch (type(x))
20505     {
20506     case T_INTEGER: return(make_real(sc, integer(x) - n));
20507     case T_RATIO:   return(make_real(sc, fraction(x) - n));
20508     case T_COMPLEX: return(s7_make_complex(sc, real_part(x) - n, imag_part(x)));
20509 #if WITH_GMP
20510     case T_BIG_INTEGER: case T_BIG_RATIO: case T_BIG_REAL: case T_BIG_COMPLEX:
20511       return(subtract_p_pp(sc, x, cadr(args)));
20512 #endif
20513     default:
20514       return(method_or_bust_with_type(sc, x, sc->subtract_symbol, args, a_number_string, 1));
20515     }
20516   return(x);
20517 }
20518 
20519 static s7_pointer g_subtract_f2(s7_scheme *sc, s7_pointer args) /* (- f x) */
20520 {
20521   s7_pointer x;
20522   s7_double n;
20523 
20524   x = cadr(args);
20525   n = real(car(args)); /* checked below is_t_real */
20526   if (is_t_real(x)) return(make_real(sc, n - real(x)));
20527 
20528   switch (type(x))
20529     {
20530     case T_INTEGER: return(make_real(sc, n - integer(x)));
20531     case T_RATIO:   return(make_real(sc, n - fraction(x)));
20532     case T_COMPLEX: return(s7_make_complex(sc, n - real_part(x), -imag_part(x)));
20533 #if WITH_GMP
20534     case T_BIG_INTEGER: case T_BIG_RATIO: case T_BIG_REAL: case T_BIG_COMPLEX:
20535       return(subtract_p_pp(sc, car(args), x));
20536 #endif
20537     default:
20538       return(method_or_bust_with_type(sc, x, sc->subtract_symbol, args, a_number_string, 1));
20539     }
20540   return(x);
20541 }
20542 
20543 static s7_int subtract_i_ii(s7_int i1, s7_int i2) {return(i1 - i2);}
20544 static s7_int subtract_i_i(s7_int x) {return(-x);}
20545 static s7_int subtract_i_iii(s7_int i1, s7_int i2, s7_int i3) {return(i1 - i2 - i3);}
20546 
20547 static s7_double subtract_d_d(s7_double x) {return(-x);}
20548 static s7_double subtract_d_dd(s7_double x1, s7_double x2) {return(x1 - x2);}
20549 static s7_double subtract_d_ddd(s7_double x1, s7_double x2, s7_double x3) {return(x1 - x2 - x3);}
20550 static s7_double subtract_d_dddd(s7_double x1, s7_double x2, s7_double x3, s7_double x4) {return(x1 - x2 - x3 - x4);}
20551 
20552 static s7_pointer subtract_p_dd(s7_scheme *sc, s7_double x1, s7_double x2) {return(make_real(sc, x1 - x2));}
20553 static s7_pointer subtract_p_ii(s7_scheme *sc, s7_int i1, s7_int i2) {return(make_integer(sc, i1 - i2));}
20554 
20555 static s7_pointer g_sub_xi(s7_scheme *sc, s7_pointer x, s7_int y)
20556 {
20557   if (is_t_integer(x))
20558     return(subtract_if_overflow_to_real_or_big_integer(sc, integer(x), y));
20559 
20560   switch (type(x))
20561     {
20562     case T_RATIO:   return(s7_make_ratio(sc, numerator(x) - (y * denominator(x)), denominator(x)));
20563     case T_REAL:    return(make_real(sc, real(x) - y));
20564     case T_COMPLEX: return(s7_make_complex(sc, real_part(x) - y, imag_part(x)));
20565 #if WITH_GMP
20566     case T_BIG_INTEGER:
20567       mpz_set_si(sc->mpz_1, y);
20568       mpz_sub(sc->mpz_1, big_integer(x), sc->mpz_1);
20569       return(mpz_to_integer(sc, sc->mpz_1));
20570     case T_BIG_RATIO:
20571     case T_BIG_REAL:
20572     case T_BIG_COMPLEX:
20573       return(subtract_p_pp(sc, x, wrap_integer1(sc, y)));
20574 #endif
20575     default: return(method_or_bust_with_type_pi(sc, x, sc->subtract_symbol, x, y, a_number_string));
20576     }
20577   return(x);
20578 }
20579 
20580 static s7_pointer subtract_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
20581 {
20582   if (args == 1)
20583     return(sc->subtract_1);
20584 
20585   if (args == 2)
20586     {
20587       if (ops)
20588 	{
20589 	  s7_pointer arg1, arg2;
20590 	  arg1 = cadr(expr);
20591 	  arg2 = caddr(expr);
20592 	  if (arg2 == int_one) return(sc->subtract_x1);
20593 	  if (is_t_real(arg1)) return(sc->subtract_f2);
20594 	  if (is_t_real(arg2)) return(sc->subtract_2f);
20595 	}
20596       return(sc->subtract_2);
20597     }
20598   return((args == 3) ? sc->subtract_3 : f);
20599 }
20600 
20601 
20602 /* ---------------------------------------- multiply ---------------------------------------- */
20603 
20604 #define QUOTIENT_FLOAT_LIMIT 1e13
20605 #define QUOTIENT_INT_LIMIT 10000000000000
20606 /* fraction(x) is not accurate enough if it involves numbers over e18 even when done with long_doubles */
20607 
20608 static inline s7_pointer multiply_if_overflow_to_real_or_big_integer(s7_scheme *sc, s7_int x, s7_int y)
20609 {
20610 #if HAVE_OVERFLOW_CHECKS
20611   s7_int val;
20612   if (multiply_overflow(x, y, &val))
20613 #if WITH_GMP
20614     {
20615       mpz_set_si(sc->mpz_1, x);
20616       mpz_mul_si(sc->mpz_1, sc->mpz_1, y);
20617       return(mpz_to_big_integer(sc, sc->mpz_1));
20618     }
20619 #else
20620     return(make_real(sc, (double)x * (double)y));
20621 #endif
20622     return(make_integer(sc, val));
20623 #else
20624   return(make_integer(sc, x * y));
20625 #endif
20626 }
20627 
20628 static s7_pointer integer_ratio_multiply_if_overflow_to_real_or_ratio(s7_scheme *sc, s7_int x, s7_pointer y)
20629 {
20630 #if HAVE_OVERFLOW_CHECKS
20631   s7_int z;
20632   if (multiply_overflow(x, numerator(y), &z))
20633 #if WITH_GMP
20634     {
20635       mpz_set_si(sc->mpz_1, x);
20636       mpz_mul_si(sc->mpz_1, sc->mpz_1, numerator(y));
20637       mpq_set_si(sc->mpq_1, 1, denominator(y));
20638       mpq_set_num(sc->mpq_1, sc->mpz_1);
20639       mpq_canonicalize(sc->mpq_1);
20640       return(mpq_to_rational(sc, sc->mpq_1));
20641     }
20642 #else
20643     return(make_real(sc, (double)x * fraction(y)));
20644 #endif
20645     return(s7_make_ratio(sc, z, denominator(y)));
20646 #else
20647   return(s7_make_ratio(sc, x * numerator(y), denominator(y)));
20648 #endif
20649 }
20650 
20651 static s7_pointer multiply_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
20652 {
20653   switch (type(x))
20654     {
20655     case T_INTEGER:
20656       switch (type(y))
20657 	{
20658 	case T_INTEGER:
20659 	  return(multiply_if_overflow_to_real_or_big_integer(sc, integer(x), integer(y)));
20660 	case T_RATIO:
20661 	  return(integer_ratio_multiply_if_overflow_to_real_or_ratio(sc, integer(x), y));
20662 	case T_REAL:
20663 #if WITH_GMP
20664 	  if (s7_int_abs(integer(x)) > QUOTIENT_INT_LIMIT)
20665 	    {
20666 	      mpfr_set_si(sc->mpfr_1, integer(x), MPFR_RNDN);
20667 	      mpfr_set_d(sc->mpfr_2, real(y), MPFR_RNDN);
20668 	      mpfr_mul(sc->mpfr_1, sc->mpfr_1, sc->mpfr_2, MPFR_RNDN);
20669 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
20670 	    }
20671 #endif
20672 	  return(make_real(sc, (long_double)integer(x) * real(y)));
20673 	case T_COMPLEX:
20674 	  return(s7_make_complex(sc, (long_double)integer(x) * real_part(y), (long_double)integer(x) * imag_part(y)));
20675 #if WITH_GMP
20676 	case T_BIG_INTEGER:
20677 	  mpz_mul_si(sc->mpz_1, big_integer(y), integer(x));
20678 	  return(mpz_to_integer(sc, sc->mpz_1));
20679 	case T_BIG_RATIO:
20680 	  mpq_set_si(sc->mpq_1, integer(x), 1);
20681 	  mpq_mul(sc->mpq_1, sc->mpq_1, big_ratio(y));
20682 	  return(mpq_to_rational(sc, sc->mpq_1));
20683 	case T_BIG_REAL:
20684 	  mpfr_mul_si(sc->mpfr_1, big_real(y), integer(x), MPFR_RNDN);
20685 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20686 	case T_BIG_COMPLEX:
20687 	  mpc_mul_si(sc->mpc_1, big_complex(y), integer(x), MPC_RNDNN);
20688 	  return(mpc_to_number(sc, sc->mpc_1)); /* x might be 0 */
20689 #endif
20690 	default:
20691 	  return(method_or_bust_with_type_pp(sc, y, sc->multiply_symbol, x, y, a_number_string, 2));
20692 	}
20693 
20694     case T_RATIO:
20695       switch (type(y))
20696 	{
20697 	case T_INTEGER:
20698 	  return(integer_ratio_multiply_if_overflow_to_real_or_ratio(sc, integer(y), x));
20699 	case T_RATIO:
20700 	  {
20701 	    s7_int d1, d2, n1, n2;
20702 	    parcel_out_fractions(x, y);
20703 #if HAVE_OVERFLOW_CHECKS
20704 	    {
20705 	      s7_int n1n2, d1d2;
20706 	      if ((multiply_overflow(d1, d2, &d1d2)) ||
20707 		  (multiply_overflow(n1, n2, &n1n2)))
20708 #if WITH_GMP
20709 		{
20710 		  mpq_set_si(sc->mpq_1, n1, d1);
20711 		  mpq_set_si(sc->mpq_2, n2, d2);
20712 		  mpq_mul(sc->mpq_1, sc->mpq_1, sc->mpq_2);
20713 		  mpq_canonicalize(sc->mpq_1);
20714 		  return(mpq_to_rational(sc, sc->mpq_1));
20715 		}
20716 #else
20717 	      return(make_real(sc, fraction(x) * fraction(y)));
20718 #endif
20719 	      return(s7_make_ratio(sc, n1n2, d1d2));
20720 	    }
20721 #else
20722 	    return(s7_make_ratio(sc, n1 * n2, d1 * d2));
20723 #endif
20724 	  }
20725 	case T_REAL:
20726 #if WITH_GMP
20727 	  if (numerator(x) > QUOTIENT_INT_LIMIT)
20728 	    {
20729 	      mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
20730 	      mpfr_set_q(sc->mpfr_1, sc->mpq_1, MPFR_RNDN);
20731 	      mpfr_mul_d(sc->mpfr_1, sc->mpfr_1, real(y), MPFR_RNDN);
20732 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
20733 	    }
20734 #endif
20735 	  return(make_real(sc, fraction(x) * real(y)));
20736 	case T_COMPLEX:
20737 	  return(s7_make_complex(sc, fraction(x) * real_part(y), fraction(x) * imag_part(y)));
20738 #if WITH_GMP
20739 	case T_BIG_INTEGER:
20740 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
20741 	  mpq_set_z(sc->mpq_2, big_integer(y));
20742 	  mpq_mul(sc->mpq_1, sc->mpq_1, sc->mpq_2);
20743 	  mpq_canonicalize(sc->mpq_1);
20744 	  return(mpq_to_rational(sc, sc->mpq_1));
20745 	case T_BIG_RATIO:
20746 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
20747 	  mpq_mul(sc->mpq_1, sc->mpq_1, big_ratio(y));
20748 	  mpq_canonicalize(sc->mpq_1);
20749 	  return(mpq_to_rational(sc, sc->mpq_1));
20750 	case T_BIG_REAL:
20751 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
20752 	  mpfr_mul_q(sc->mpfr_1, big_real(y), sc->mpq_1, MPFR_RNDN);
20753 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20754 	case T_BIG_COMPLEX:
20755 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
20756 	  mpc_set_q(sc->mpc_1, sc->mpq_1, MPC_RNDNN);
20757 	  mpc_mul(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20758 	  return(mpc_to_number(sc, sc->mpc_1));
20759 #endif
20760 	default:
20761 	  return(method_or_bust_with_type_pp(sc, y, sc->multiply_symbol, x, y, a_number_string, 2));
20762 	}
20763 
20764     case T_REAL:
20765       switch (type(y))
20766 	{
20767 	case T_INTEGER:
20768 #if WITH_GMP
20769 	  if (s7_int_abs(integer(y)) > QUOTIENT_INT_LIMIT)
20770 	    {
20771 	      mpfr_set_si(sc->mpfr_1, integer(y), MPFR_RNDN);
20772 	      mpfr_set_d(sc->mpfr_2, real(x), MPFR_RNDN);
20773 	      mpfr_mul(sc->mpfr_1, sc->mpfr_1, sc->mpfr_2, MPFR_RNDN);
20774 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
20775 	    }
20776 #endif
20777 	  return(make_real(sc, real(x) * (long_double)integer(y)));
20778 	case T_RATIO:
20779 #if WITH_GMP
20780 	  if (numerator(y) > QUOTIENT_INT_LIMIT)
20781 	    {
20782 	      mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
20783 	      mpfr_set_q(sc->mpfr_1, sc->mpq_1, MPFR_RNDN);
20784 	      mpfr_mul_d(sc->mpfr_1, sc->mpfr_1, real(x), MPFR_RNDN);
20785 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
20786 	    }
20787 #endif
20788 	  return(make_real(sc, fraction(y) * real(x)));
20789 	case T_REAL:
20790 	  return(make_real(sc, real(x) * real(y)));
20791 	case T_COMPLEX:
20792 	  return(make_complex(sc, real(x) * real_part(y), real(x) * imag_part(y)));
20793 #if WITH_GMP
20794 	case T_BIG_INTEGER:
20795 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
20796 	  mpfr_mul_z(sc->mpfr_1, sc->mpfr_1, big_integer(y), MPFR_RNDN);
20797 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20798 	case T_BIG_RATIO:
20799 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
20800 	  mpfr_mul_q(sc->mpfr_1, sc->mpfr_1, big_ratio(y), MPFR_RNDN);
20801 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20802 	case T_BIG_REAL:
20803 	  mpfr_mul_d(sc->mpfr_1, big_real(y), real(x), MPFR_RNDN);
20804 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20805 	case T_BIG_COMPLEX:
20806 	  mpc_set_d_d(sc->mpc_1, real(x), 0.0, MPC_RNDNN);
20807 	  mpc_mul(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20808 	  return(mpc_to_number(sc, sc->mpc_1)); /* x might = 0.0 */
20809 #endif
20810 	default:
20811 	  return(method_or_bust_with_type_pp(sc, y, sc->multiply_symbol, x, y, a_number_string, 2));
20812 	}
20813 
20814     case T_COMPLEX:
20815       switch (type(y))
20816 	{
20817 	case T_INTEGER:
20818 	  return(make_complex(sc, real_part(x) * integer(y), imag_part(x) * integer(y)));
20819 	case T_RATIO:
20820 	  return(s7_make_complex(sc, real_part(x) * fraction(y), imag_part(x) * fraction(y)));
20821 	case T_REAL:
20822 	  return(make_complex(sc, real_part(x) * real(y), imag_part(x) * real(y)));
20823 	case T_COMPLEX:
20824 	  {
20825 	    s7_double r1, r2, i1, i2;
20826 	    r1 = real_part(x);
20827 	    r2 = real_part(y);
20828 	    i1 = imag_part(x);
20829 	    i2 = imag_part(y);
20830 	    return(make_complex(sc, r1 * r2 - i1 * i2, r1 * i2 + r2 * i1));
20831 	  }
20832 #if WITH_GMP
20833 	case T_BIG_INTEGER:
20834 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
20835 	  mpc_set_z(sc->mpc_2, big_integer(y), MPC_RNDNN);
20836 	  mpc_mul(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
20837 	  return(mpc_to_number(sc, sc->mpc_1));
20838 	case T_BIG_RATIO:
20839 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
20840 	  mpc_set_q(sc->mpc_2, big_ratio(y), MPC_RNDNN);
20841 	  mpc_mul(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
20842 	  return(mpc_to_number(sc, sc->mpc_1));
20843 	case T_BIG_REAL:
20844 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
20845 	  mpc_mul_fr(sc->mpc_1, sc->mpc_1, big_real(y), MPC_RNDNN);
20846 	  return(mpc_to_number(sc, sc->mpc_1));
20847 	case T_BIG_COMPLEX:
20848 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
20849 	  mpc_mul(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20850 	  return(mpc_to_number(sc, sc->mpc_1));
20851 #endif
20852 	default:
20853 	  return(method_or_bust_with_type_pp(sc, y, sc->multiply_symbol, x, y, a_number_string, 2));
20854 	}
20855 
20856 #if WITH_GMP
20857     case T_BIG_INTEGER:
20858       switch (type(y))
20859 	{
20860 	case T_INTEGER:
20861 	  mpz_mul_si(sc->mpz_1, big_integer(x), integer(y));
20862 	  return(mpz_to_integer(sc, sc->mpz_1));
20863 	case T_RATIO:
20864 	  mpq_set_z(sc->mpq_2, big_integer(x));
20865 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
20866 	  mpq_mul(sc->mpq_1, sc->mpq_2, sc->mpq_1);
20867 	  mpq_canonicalize(sc->mpq_1);
20868 	  return(mpq_to_rational(sc, sc->mpq_1));
20869 	case T_REAL:
20870 	  if (is_NaN(real(y))) return(real_NaN);
20871 	  mpfr_set_d(sc->mpfr_1, real(y), MPFR_RNDN);
20872 	  mpfr_mul_z(sc->mpfr_1, sc->mpfr_1, big_integer(x), MPFR_RNDN);
20873 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20874 	case T_COMPLEX:
20875 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
20876 	  mpc_set_z(sc->mpc_2, big_integer(x), MPC_RNDNN);
20877 	  mpc_mul(sc->mpc_1, sc->mpc_2, sc->mpc_1, MPC_RNDNN);
20878 	  return(mpc_to_number(sc, sc->mpc_1));
20879 	case T_BIG_INTEGER:
20880 	  mpz_mul(sc->mpz_1, big_integer(x), big_integer(y));
20881 	  return(mpz_to_integer(sc, sc->mpz_1));
20882 	case T_BIG_RATIO:
20883 	  mpq_set_z(sc->mpq_1, big_integer(x));
20884 	  mpq_mul(sc->mpq_1, sc->mpq_1, big_ratio(y));
20885 	  return(mpq_to_rational(sc, sc->mpq_1));
20886 	case T_BIG_REAL:
20887 	  mpfr_mul_z(sc->mpfr_1, big_real(y), big_integer(x), MPFR_RNDN);
20888 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20889 	case T_BIG_COMPLEX:
20890 	  mpc_set_z(sc->mpc_1, big_integer(x), MPC_RNDNN);
20891 	  mpc_mul(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20892 	  return(mpc_to_number(sc, sc->mpc_1));
20893 	default:
20894 	  return(method_or_bust_with_type_pp(sc, y, sc->multiply_symbol, x, y, a_number_string, 2));
20895 	}
20896 
20897     case T_BIG_RATIO:
20898       switch (type(y))
20899 	{
20900 	case T_INTEGER:
20901 	  mpq_set_si(sc->mpq_1, integer(y), 1);
20902 	  mpq_mul(sc->mpq_1, big_ratio(x), sc->mpq_1);
20903 	  return(mpq_to_rational(sc, sc->mpq_1));
20904 	case T_RATIO:
20905 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
20906 	  mpq_mul(sc->mpq_1, big_ratio(x), sc->mpq_1);
20907 	  return(mpq_to_rational(sc, sc->mpq_1));
20908 	case T_REAL:
20909 	  if (is_NaN(real(y))) return(real_NaN);
20910 	  mpfr_set_d(sc->mpfr_1, real(y), MPFR_RNDN);
20911 	  mpfr_mul_q(sc->mpfr_1, sc->mpfr_1, big_ratio(x), MPFR_RNDN);
20912 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20913 	case T_COMPLEX:
20914 	  mpc_set_q(sc->mpc_1, big_ratio(x), MPC_RNDNN);
20915 	  mpc_set_d_d(sc->mpc_2, real_part(y), imag_part(y), MPC_RNDNN);
20916 	  mpc_mul(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
20917 	  return(mpc_to_number(sc, sc->mpc_1));
20918 	case T_BIG_INTEGER:
20919 	  mpq_set_z(sc->mpq_1, big_integer(y));
20920 	  mpq_mul(sc->mpq_1, big_ratio(x), sc->mpq_1);
20921 	  mpq_canonicalize(sc->mpq_1);
20922 	  return(mpq_to_rational(sc, sc->mpq_1));
20923 	case T_BIG_RATIO:
20924 	  mpq_mul(sc->mpq_1, big_ratio(x), big_ratio(y));
20925 	  mpq_canonicalize(sc->mpq_1);
20926 	  return(mpq_to_rational(sc, sc->mpq_1));
20927 	case T_BIG_REAL:
20928 	  mpfr_mul_q(sc->mpfr_1, big_real(y), big_ratio(x), MPFR_RNDN);
20929 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20930 	case T_BIG_COMPLEX:
20931 	  mpc_set_q(sc->mpc_1, big_ratio(x), MPC_RNDNN);
20932 	  mpc_mul(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
20933 	  return(mpc_to_number(sc, sc->mpc_1));
20934 	default:
20935 	  return(method_or_bust_with_type_pp(sc, y, sc->multiply_symbol, x, y, a_number_string, 2));
20936 	}
20937 
20938     case T_BIG_REAL:
20939       switch (type(y))
20940 	{
20941 	case T_INTEGER:
20942 	  mpfr_mul_si(sc->mpfr_1, big_real(x), integer(y), MPFR_RNDN);
20943 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20944 	case T_RATIO:
20945 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
20946 	  mpfr_mul_q(sc->mpfr_1, big_real(x), sc->mpq_1, MPFR_RNDN);
20947 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20948 	case T_REAL:
20949 	  if (is_NaN(real(y))) return(real_NaN);
20950 	  mpfr_mul_d(sc->mpfr_1, big_real(x), real(y), MPFR_RNDN);
20951 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20952 	case T_COMPLEX:
20953 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
20954 	  mpc_mul_fr(sc->mpc_1, sc->mpc_1, big_real(x), MPC_RNDNN);
20955 	  return(mpc_to_number(sc, sc->mpc_1));
20956 	case T_BIG_INTEGER:
20957 	  mpfr_mul_z(sc->mpfr_1, big_real(x), big_integer(y), MPFR_RNDN);
20958 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20959 	case T_BIG_RATIO:
20960 	  mpfr_mul_q(sc->mpfr_1, big_real(x), big_ratio(y), MPFR_RNDN);
20961 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20962 	case T_BIG_REAL:
20963 	  mpfr_mul(sc->mpfr_1, big_real(x), big_real(y), MPFR_RNDN);
20964 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
20965 	case T_BIG_COMPLEX:
20966 	  mpc_mul_fr(sc->mpc_1, big_complex(y), big_real(x), MPC_RNDNN);
20967 	  return(mpc_to_number(sc, sc->mpc_1)); /* 0.0? */
20968 	default:
20969 	  return(method_or_bust_with_type_pp(sc, y, sc->multiply_symbol, x, y, a_number_string, 2));
20970 	}
20971     case T_BIG_COMPLEX:
20972       switch (type(y))
20973 	{
20974 	case T_INTEGER:
20975 	  mpc_mul_si(sc->mpc_1, big_complex(x), integer(y), MPC_RNDNN);
20976 	  return(mpc_to_number(sc, sc->mpc_1));
20977 	case T_RATIO:
20978 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
20979 	  mpc_set_q(sc->mpc_1, sc->mpq_1, MPC_RNDNN);
20980 	  mpc_mul(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20981 	  return(mpc_to_number(sc, sc->mpc_1));
20982 	case T_REAL:
20983 	  /* if (is_NaN(real(y))) return(real_NaN); */
20984 	  mpc_set_d_d(sc->mpc_1, real(y), 0.0, MPC_RNDNN);
20985 	  mpc_mul(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20986 	  return(mpc_to_number(sc, sc->mpc_1));
20987 	case T_COMPLEX:
20988 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
20989 	  mpc_mul(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20990 	  return(mpc_to_number(sc, sc->mpc_1));
20991 	case T_BIG_INTEGER:
20992 	  mpc_set_z(sc->mpc_1, big_integer(y), MPC_RNDNN);
20993 	  mpc_mul(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20994 	  return(mpc_to_number(sc, sc->mpc_1));
20995 	case T_BIG_RATIO:
20996 	  mpc_set_q(sc->mpc_1, big_ratio(y), MPC_RNDNN);
20997 	  mpc_mul(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
20998 	  return(mpc_to_number(sc, sc->mpc_1));
20999 	case T_BIG_REAL:
21000 	  mpc_mul_fr(sc->mpc_1, big_complex(x), big_real(y), MPC_RNDNN);
21001 	  return(mpc_to_number(sc, sc->mpc_1));
21002 	case T_BIG_COMPLEX:
21003 	  mpc_mul(sc->mpc_1, big_complex(x), big_complex(y), MPC_RNDNN);
21004 	  return(mpc_to_number(sc, sc->mpc_1));
21005 	default:
21006 	  return(method_or_bust_with_type_pp(sc, y, sc->multiply_symbol, x, y, a_number_string, 2));
21007 	}
21008 #endif
21009       default:
21010 	return(method_or_bust_with_type_pp(sc, x, sc->multiply_symbol, x, y, a_number_string, 1));
21011     }
21012 }
21013 
21014 static s7_pointer multiply_p_ppp(s7_scheme *sc, s7_pointer x, s7_pointer y, s7_pointer z) {return(multiply_p_pp(sc, multiply_p_pp(sc, x, y), z));}
21015 
21016 static s7_pointer multiply_method_or_bust(s7_scheme *sc, s7_pointer obj, s7_pointer caller, s7_pointer args, s7_pointer typ, int32_t num)
21017 {
21018   if (has_active_methods(sc, obj))
21019     return(find_and_apply_method(sc, obj, sc->multiply_symbol, args));
21020   if (num == 0)
21021     return(simple_wrong_type_argument_with_type(sc, sc->multiply_symbol, obj, typ));
21022   return(wrong_type_argument_with_type(sc, sc->multiply_symbol, num, obj, typ));
21023 }
21024 
21025 static s7_pointer g_multiply(s7_scheme *sc, s7_pointer args)
21026 {
21027   #define H_multiply "(* ...) multiplies its arguments"
21028   #define Q_multiply sc->pcl_n
21029 
21030   s7_pointer x, p;
21031 
21032   if (is_null(args))
21033     return(int_one);
21034 
21035   x = car(args);
21036   p = cdr(args);
21037   if (is_null(p))
21038     {
21039       if (!is_number(x))
21040 	return(multiply_method_or_bust(sc, x, sc->multiply_symbol, args, a_number_string, 0));
21041       return(x);
21042     }
21043 
21044   if (is_null(cdr(p)))
21045     return(multiply_p_pp(sc, x, car(p)));
21046 
21047   for (; is_pair(p); p = cdr(p))
21048     x = multiply_p_pp(sc, x, car(p));
21049   return(x);
21050 }
21051 
21052 static s7_pointer g_multiply_2(s7_scheme *sc, s7_pointer args) {return(multiply_p_pp(sc, car(args), cadr(args)));}
21053 
21054 static s7_pointer g_mul_xi(s7_scheme *sc, s7_pointer x, s7_int n)
21055 {
21056   switch (type(x))
21057     {
21058     case T_INTEGER: return(multiply_if_overflow_to_real_or_big_integer(sc, integer(x), n));
21059     case T_RATIO:   return(integer_ratio_multiply_if_overflow_to_real_or_ratio(sc, n, x));
21060     case T_REAL:    return(make_real(sc, real(x) * n));
21061     case T_COMPLEX: return(s7_make_complex(sc, real_part(x) * n, imag_part(x) * n));
21062 #if WITH_GMP
21063     case T_BIG_INTEGER:
21064       mpz_mul_si(sc->mpz_1, big_integer(x), n);
21065       return(mpz_to_integer(sc, sc->mpz_1));
21066     case T_BIG_RATIO:
21067     case T_BIG_REAL:
21068     case T_BIG_COMPLEX:
21069       return(multiply_p_pp(sc, x, wrap_integer1(sc, n)));
21070 #endif
21071     default:
21072       /* we can get here from mul_2_xi for example so the non-integer argument might not be a symbol */
21073       return(method_or_bust_with_type_pi(sc, x, sc->multiply_symbol, x, n, a_number_string));
21074     }
21075   return(x);
21076 }
21077 
21078 static s7_pointer g_mul_xf(s7_scheme *sc, s7_pointer x, s7_double y)
21079 {
21080   switch (type(x))
21081     {
21082     case T_INTEGER: return(make_real(sc, integer(x) * y));
21083     case T_RATIO:   return(make_real(sc, numerator(x) * y / denominator(x)));
21084     case T_REAL:    return(make_real(sc, real(x) * y));
21085     case T_COMPLEX: return(s7_make_complex(sc, real_part(x) * y, imag_part(x) * y));
21086 #if WITH_GMP
21087     case T_BIG_INTEGER:
21088       mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
21089       mpfr_mul_z(sc->mpfr_1, sc->mpfr_1, big_integer(x), MPFR_RNDN);
21090       return(mpfr_to_big_real(sc, sc->mpfr_1));
21091     case T_BIG_RATIO:
21092       mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
21093       mpfr_mul_q(sc->mpfr_1, sc->mpfr_1, big_ratio(x), MPFR_RNDN);
21094       return(mpfr_to_big_real(sc, sc->mpfr_1));
21095     case T_BIG_REAL:
21096       mpfr_mul_d(sc->mpfr_1, big_real(x), y, MPFR_RNDN);
21097       return(mpfr_to_big_real(sc, sc->mpfr_1));
21098     case T_BIG_COMPLEX:
21099       mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
21100       mpc_mul_fr(sc->mpc_1, big_complex(x), sc->mpfr_1, MPC_RNDNN);
21101       return(mpc_to_number(sc, sc->mpc_1));
21102 #endif
21103     default: return(method_or_bust_with_type_pf(sc, x, sc->multiply_symbol, x, y, a_number_string));
21104     }
21105   return(x);
21106 }
21107 
21108 #if WITH_GMP
21109 static s7_pointer g_mul_2_if(s7_scheme *sc, s7_pointer args) {
21110   if ((is_t_integer(car(args))) && (is_t_real(cadr(args))))
21111     return(make_real(sc, integer(car(args)) * real(cadr(args))));
21112   return(multiply_p_pp(sc, car(args), cadr(args)));
21113 }
21114 static s7_pointer g_mul_2_fi(s7_scheme *sc, s7_pointer args)
21115 {
21116   if ((is_t_integer(cadr(args))) && (is_t_real(car(args))))
21117     return(make_real(sc, real(car(args)) * integer(cadr(args))));
21118   return(multiply_p_pp(sc, car(args), cadr(args)));
21119 }
21120 static s7_pointer g_mul_2_xi(s7_scheme *sc, s7_pointer args) {if (is_t_integer(cadr(args))) return(g_mul_xi(sc, car(args), integer(cadr(args)))); return(g_multiply(sc, args));}
21121 static s7_pointer g_mul_2_ix(s7_scheme *sc, s7_pointer args) {if (is_t_integer(car(args))) return(g_mul_xi(sc, cadr(args), integer(car(args)))); return(g_multiply(sc, args));}
21122 static s7_pointer g_mul_2_xf(s7_scheme *sc, s7_pointer args) {if (is_t_real(cadr(args))) return(g_mul_xf(sc, car(args), real(cadr(args)))); return(g_multiply(sc, args));}
21123 static s7_pointer g_mul_2_fx(s7_scheme *sc, s7_pointer args) {if (is_t_real(car(args))) return(g_mul_xf(sc, cadr(args), real(car(args)))); return(g_multiply(sc, args));}
21124 static s7_pointer g_mul_2_ff(s7_scheme *sc, s7_pointer args) {return(multiply_p_pp(sc, car(args), cadr(args)));}
21125 static s7_pointer g_mul_2_ii(s7_scheme *sc, s7_pointer args) {return(multiply_p_pp(sc, car(args), cadr(args)));}
21126 #else
21127 static s7_pointer g_mul_2_if(s7_scheme *sc, s7_pointer args) {return(make_real(sc, integer(car(args)) * real(cadr(args))));}
21128 static s7_pointer g_mul_2_fi(s7_scheme *sc, s7_pointer args) {return(make_real(sc, real(car(args)) * integer(cadr(args))));}
21129 static s7_pointer g_mul_2_xi(s7_scheme *sc, s7_pointer args) {return(g_mul_xi(sc, car(args), integer(cadr(args))));}
21130 static s7_pointer g_mul_2_ix(s7_scheme *sc, s7_pointer args) {return(g_mul_xi(sc, cadr(args), integer(car(args))));}
21131 static s7_pointer g_mul_2_xf(s7_scheme *sc, s7_pointer args) {return(g_mul_xf(sc, car(args), real(cadr(args))));}
21132 static s7_pointer g_mul_2_fx(s7_scheme *sc, s7_pointer args) {return(g_mul_xf(sc, cadr(args), real(car(args))));}
21133 static s7_pointer g_mul_2_ff(s7_scheme *sc, s7_pointer args) {return(make_real(sc, real(car(args)) * real(cadr(args))));}
21134 
21135 static s7_pointer g_mul_2_ii(s7_scheme *sc, s7_pointer args)
21136 {
21137 #if HAVE_OVERFLOW_CHECKS
21138   s7_int val, x, y;
21139   x = integer(car(args));
21140   y = integer(cadr(args));
21141   if (multiply_overflow(x, y, &val))
21142     return(make_real(sc, (double)x * (double)y));
21143   return(make_integer(sc, val));
21144 #else
21145   return(make_integer(sc, integer(car(args)) * integer(cadr(args))));
21146 #endif
21147 }
21148 #endif
21149 
21150 static s7_int multiply_i_ii(s7_int i1, s7_int i2)
21151 {
21152 #if HAVE_OVERFLOW_CHECKS
21153   s7_int val;
21154   if (multiply_overflow(i1, i2, &val))
21155     return(S7_INT64_MAX); /* this is inconsistent with other unopt cases where an overflow -> double result */
21156   /* (let () (define (func) (do ((i 0 (+ i 1))) ((= i 1)) (do ((j 0 (+ j 1))) ((= j 1)) (even? (* (ash 1 43) (ash 1 43)))))) (define (hi) (func)) (hi)) */
21157   return(val);
21158 #else
21159   return(i1 * i2);
21160 #endif
21161 }
21162 
21163 static s7_int multiply_i_iii(s7_int i1, s7_int i2, s7_int i3)
21164 {
21165 #if HAVE_OVERFLOW_CHECKS
21166   s7_int val1, val2;
21167   if (multiply_overflow(i1, i2, &val1))
21168     return(S7_INT64_MAX);
21169   if (multiply_overflow(val1, i3, &val2))
21170     return(S7_INT64_MAX);
21171   return(val2);
21172 #else
21173   return(i1 * i2 * i3);
21174 #endif
21175 }
21176 
21177 static s7_double multiply_d_d(s7_double x) {return(x);}
21178 static s7_double multiply_d_dd(s7_double x1, s7_double x2) {return(x1 * x2);}
21179 static s7_double multiply_d_ddd(s7_double x1, s7_double x2, s7_double x3) {return(x1 * x2 * x3);}
21180 static s7_double multiply_d_dddd(s7_double x1, s7_double x2, s7_double x3, s7_double x4) {return(x1 * x2 * x3 * x4);}
21181 static s7_pointer mul_p_dd(s7_scheme *sc, s7_double x1, s7_double x2) {return(make_real(sc, x1 * x2));}
21182 
21183 static s7_pointer multiply_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
21184 {
21185   if (args == 2)
21186     {
21187       if (ops)
21188 	return(chooser_check_arg_types(sc, cadr(expr), caddr(expr), sc->multiply_2,
21189 				       sc->mul_2_ff, sc->mul_2_ii, sc->mul_2_if, sc->mul_2_fi,
21190 				       sc->mul_2_xi, sc->mul_2_ix, sc->mul_2_fx, sc->mul_2_xf));
21191       return(sc->multiply_2);
21192     }
21193   return(f);
21194 }
21195 
21196 
21197 /* ---------------------------------------- divide ---------------------------------------- */
21198 
21199 static s7_pointer complex_invert(s7_scheme *sc, s7_pointer p)
21200 {
21201   s7_double r2, i2, den;
21202   r2 = real_part(p);
21203   i2 = imag_part(p);
21204   den = (r2 * r2 + i2 * i2);
21205   /* here if p is, for example, -inf.0+i, den is +inf.0 so -i2/den is -0.0 (in gcc anyway), so the imag part is 0.0 */
21206   return(s7_make_complex(sc, r2 / den, -i2 / den));
21207 }
21208 
21209 static s7_pointer invert_p_p(s7_scheme *sc, s7_pointer p)
21210 {
21211 #if WITH_GMP
21212   s7_pointer x;
21213 #endif
21214   switch (type(p))
21215     {
21216     case T_INTEGER:
21217 #if WITH_GMP && (!POINTER_32)
21218       if (integer(p) == S7_INT64_MIN) /* (/ 1 (*s7* 'most-negative-fixnum)) -> -1/9223372036854775808 */
21219 	{
21220 	  new_cell(sc, x, T_BIG_RATIO);
21221 	  big_ratio_bgr(x) = alloc_bigrat(sc);
21222 	  add_big_ratio(sc, x);
21223 	  mpz_set_si(sc->mpz_1, S7_INT64_MAX);
21224 	  mpz_set_si(sc->mpz_2, 1);
21225 	  mpz_add(sc->mpz_1, sc->mpz_1, sc->mpz_2);
21226 	  mpq_set_si(big_ratio(x), -1, 1);
21227 	  mpq_set_den(big_ratio(x), sc->mpz_1); /* geez... */
21228 	  return(x);
21229 	}
21230 #endif
21231       if (integer(p) == 0)
21232 	return(division_by_zero_error(sc, sc->divide_symbol, p));
21233       return(make_simple_ratio(sc, 1, integer(p)));  /* this checks for int */
21234     case T_RATIO:
21235       return(make_simple_ratio(sc, denominator(p), numerator(p)));
21236     case T_REAL:
21237       if (real(p) == 0.0)
21238 	return(division_by_zero_error(sc, sc->divide_symbol, p));
21239       return(make_real(sc, 1.0 / real(p)));
21240     case T_COMPLEX:
21241       return(complex_invert(sc, p));
21242 
21243 #if WITH_GMP
21244     case T_BIG_INTEGER:
21245       if (mpz_cmp_ui(big_integer(p), 0) == 0)
21246 	return(division_by_zero_error(sc, sc->divide_symbol, p));
21247       if ((mpz_cmp_ui(big_integer(p), 1) == 0) || (mpz_cmp_si(big_integer(p), -1) == 0))
21248 	return(p);
21249       new_cell(sc, x, T_BIG_RATIO);
21250       big_ratio_bgr(x) = alloc_bigrat(sc);
21251       add_big_ratio(sc, x);
21252       mpq_set_si(big_ratio(x), 1, 1);
21253       mpq_set_den(big_ratio(x), big_integer(p));
21254       mpq_canonicalize(big_ratio(x));
21255       return(x);
21256 
21257     case T_BIG_RATIO:
21258       if (mpz_cmp_ui(mpq_numref(big_ratio(p)), 1) == 0)
21259 	return(mpz_to_integer(sc, mpq_denref(big_ratio(p))));
21260       if (mpz_cmp_si(mpq_numref(big_ratio(p)), -1) == 0)
21261 	{
21262 	  mpz_neg(sc->mpz_1, mpq_denref(big_ratio(p)));
21263 	  return(mpz_to_integer(sc, sc->mpz_1));
21264 	}
21265       new_cell(sc, x, T_BIG_RATIO);
21266       big_ratio_bgr(x) = alloc_bigrat(sc);
21267       add_big_ratio(sc, x);
21268       mpq_inv(big_ratio(x), big_ratio(p));
21269       mpq_canonicalize(big_ratio(x));
21270       return(x);
21271 
21272     case T_BIG_REAL:
21273       if (mpfr_zero_p(big_real(p)))
21274 	return(division_by_zero_error(sc, sc->divide_symbol, p));
21275       x = mpfr_to_big_real(sc, big_real(p));
21276       mpfr_ui_div(big_real(x), 1, big_real(x), MPFR_RNDN);
21277       return(x);
21278 
21279     case T_BIG_COMPLEX:
21280       if ((!mpfr_number_p(mpc_realref(big_complex(p)))) || (!mpfr_number_p(mpc_imagref(big_complex(p)))))
21281 	return(complex_NaN);
21282       mpc_ui_div(sc->mpc_1, 1, big_complex(p), MPC_RNDNN);
21283       return(mpc_to_number(sc, sc->mpc_1)); /* x might be 0+0i if real-part is inf? */
21284 #endif
21285     default:
21286       check_method(sc, p, sc->divide_symbol, set_plist_1(sc, p));
21287       return(wrong_type_argument_with_type(sc, sc->divide_symbol, 1, p, a_number_string));
21288     }
21289 }
21290 
21291 static s7_pointer divide_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
21292 {
21293   /* splitting out real/real here saves very little */
21294 
21295   switch (type(x))
21296     {
21297     case T_INTEGER:
21298       switch (type(y))
21299 	{
21300 	  /* -------- integer x -------- */
21301 	case T_INTEGER:
21302 	  if (integer(y) == 0)
21303 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21304 	  if (integer(x) == 1)  /* mainly to handle (/ 1 -9223372036854775808) correctly! */
21305 	    return(invert_p_p(sc, y));
21306 	  return(s7_make_ratio(sc, integer(x), integer(y)));
21307 
21308 	case T_RATIO:
21309 #if HAVE_OVERFLOW_CHECKS
21310 	  {
21311 	    s7_int dn;
21312 	    if (multiply_overflow(integer(x), denominator(y), &dn))
21313 #if WITH_GMP
21314 	      {
21315 		mpq_set_si(sc->mpq_1, integer(x), 1);
21316 		mpq_set_si(sc->mpq_2, numerator(y), denominator(y));
21317 		mpq_div(sc->mpq_1, sc->mpq_1, sc->mpq_2);
21318 		mpq_canonicalize(sc->mpq_1);
21319 		return(mpq_to_rational(sc, sc->mpq_1));
21320 	      }
21321 #else
21322 	      return(make_real(sc, integer(x) * inverted_fraction(y)));
21323 #endif
21324 	    return(s7_make_ratio(sc, dn, numerator(y)));
21325 	  }
21326 #else
21327 	  return(s7_make_ratio(sc, integer(x) * denominator(y), numerator(y)));
21328 #endif
21329 
21330 	case T_REAL:
21331 	  if (is_NaN(real(y))) return(real_NaN);
21332 	  if (is_inf(real(y))) return(real_zero);
21333 	  if (real(y) == 0.0)
21334 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21335 #if WITH_GMP
21336 	  if ((s7_int_abs(integer(x))) > QUOTIENT_INT_LIMIT)
21337 	    {
21338 	      mpfr_set_si(sc->mpfr_1, integer(x), MPFR_RNDN);
21339 	      mpfr_set_d(sc->mpfr_2, real(y), MPFR_RNDN);
21340 	      mpfr_div(sc->mpfr_1, sc->mpfr_1, sc->mpfr_2, MPFR_RNDN);
21341 	      return(mpfr_to_big_real(sc, sc->mpfr_1));
21342 	    }
21343 #endif
21344 	  return(make_real(sc, (s7_double)(integer(x)) / real(y)));
21345 
21346 	case T_COMPLEX:
21347 	  {
21348 	    s7_double r1, i2, r2, den;
21349 	    r1 = (s7_double)integer(x);
21350 	    r2 = real_part(y);
21351 	    i2 = imag_part(y);
21352 	    den = 1.0 / (r2 * r2 + i2 * i2);
21353 	    /* we could avoid the squaring (see Knuth II p613 16), not a big deal: (/ 1.0e308+1.0e308i 2.0e308+2.0e308i) => nan, (gmp case is ok here) */
21354 	    return(s7_make_complex(sc, r1 * r2 * den, -(r1 * i2 * den)));
21355 	  }
21356 
21357 #if WITH_GMP
21358 	case T_BIG_INTEGER:
21359 	  if (mpz_cmp_ui(big_integer(y), 0) == 0)
21360 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21361 	  mpq_set_si(sc->mpq_1, integer(x), 1);
21362 	  mpq_set_den(sc->mpq_1, big_integer(y));
21363 	  mpq_canonicalize(sc->mpq_1);
21364 	  return(mpq_to_rational(sc, sc->mpq_1));
21365 	case T_BIG_RATIO:
21366 	  mpq_set_si(sc->mpq_1, integer(x), 1);
21367 	  mpq_div(sc->mpq_1, sc->mpq_1, big_ratio(y));
21368 	  mpq_canonicalize(sc->mpq_1);
21369 	  return(mpq_to_rational(sc, sc->mpq_1));
21370 	case T_BIG_REAL:
21371 	  if (mpfr_zero_p(big_real(y)))
21372 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21373 	  mpfr_si_div(sc->mpfr_1, integer(x), big_real(y), MPFR_RNDN);
21374 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21375 	case T_BIG_COMPLEX:
21376 	  if ((!mpfr_number_p(mpc_realref(big_complex(y)))) || (!mpfr_number_p(mpc_imagref(big_complex(y)))))
21377 	    return(complex_NaN);
21378 	  mpc_set_si(sc->mpc_1, integer(x), MPC_RNDNN);
21379 	  mpc_div(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
21380 	  return(mpc_to_number(sc, sc->mpc_1)); /* x might be 0? */
21381 #endif
21382 
21383 	default:
21384 	  return(method_or_bust_with_type_pp(sc, y, sc->divide_symbol, x, y, a_number_string, 2));
21385 	}
21386       break;
21387 
21388       /* -------- ratio x -------- */
21389     case T_RATIO:
21390       switch (type(y))
21391 	{
21392 	case T_INTEGER:
21393 	  if (integer(y) == 0)
21394 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21395 #if HAVE_OVERFLOW_CHECKS
21396 	  {
21397 	    s7_int dn;
21398 	    if (multiply_overflow(denominator(x), integer(y), &dn))
21399 #if WITH_GMP
21400 	      {
21401 		mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
21402 		mpq_set_si(sc->mpq_2, integer(y), 1);
21403 		mpq_div(sc->mpq_1, sc->mpq_1, sc->mpq_2);
21404 		return(mpq_to_rational(sc, sc->mpq_1));
21405 	      }
21406 #else
21407 	      return(make_real(sc, (long_double)numerator(x) / ((long_double)denominator(x) * (long_double)integer(y))));
21408 #endif
21409 	    return(s7_make_ratio(sc, numerator(x), dn));
21410 	  }
21411 #else
21412 	  return(s7_make_ratio(sc, numerator(x), denominator(x) * integer(y)));
21413 #endif
21414 
21415 	case T_RATIO:
21416 	  {
21417 	    s7_int d1, d2, n1, n2;
21418 	    parcel_out_fractions(x, y);
21419 	    if (d1 == d2)
21420 	      return(s7_make_ratio(sc, n1, n2));
21421 #if HAVE_OVERFLOW_CHECKS
21422 	    if ((multiply_overflow(n1, d2, &n1)) ||
21423 		(multiply_overflow(n2, d1, &d1)))
21424 	      {
21425 #if WITH_GMP
21426 		mpq_set_si(sc->mpq_1, numerator(x), denominator(x)); /* not n1 and d1! they are garbage here */
21427 		mpq_set_si(sc->mpq_2, n2, d2);
21428 		mpq_div(sc->mpq_1, sc->mpq_1, sc->mpq_2);
21429 		return(mpq_to_rational(sc, sc->mpq_1));
21430 #else
21431 		s7_double r1, r2;
21432 		r1 = fraction(x);
21433 		r2 = inverted_fraction(y);
21434 		return(make_real(sc, r1 * r2));
21435 #endif
21436 	      }
21437 	    return(s7_make_ratio(sc, n1, d1));
21438 #else
21439 	    return(s7_make_ratio(sc, n1 * d2, n2 * d1));
21440 #endif
21441 	  }
21442 
21443 	case T_REAL:
21444 	  if (real(y) == 0.0)
21445 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21446 	  return(make_real(sc, fraction(x) / real(y)));
21447 
21448 	case T_COMPLEX:
21449 	  {
21450 	    s7_double rx, r2, i2, den;
21451 	    rx = fraction(x);
21452 	    r2 = real_part(y);
21453 	    i2 = imag_part(y);
21454 	    den = 1.0 / (r2 * r2 + i2 * i2);
21455 	    return(s7_make_complex(sc, rx * r2 * den, -rx * i2 * den)); /* not unchecked: (/ 3/4 -inf.0+i) */
21456 	  }
21457 
21458 #if WITH_GMP
21459 	case T_BIG_INTEGER:
21460 	  if (mpz_cmp_ui(big_integer(y), 0) == 0)
21461 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21462 	  mpq_set_z(sc->mpq_1, big_integer(y));
21463 	  mpq_set_si(sc->mpq_2, numerator(x), denominator(x));
21464 	  mpq_div(sc->mpq_1, sc->mpq_2, sc->mpq_1);
21465 	  return(mpq_to_rational(sc, sc->mpq_1));
21466 	case T_BIG_RATIO:
21467 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
21468 	  mpq_div(sc->mpq_1, sc->mpq_1, big_ratio(y));
21469 	  return(mpq_to_rational(sc, sc->mpq_1));
21470 	case T_BIG_REAL:
21471 	  if (mpfr_zero_p(big_real(y)))
21472 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21473 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
21474 	  mpfr_set_q(sc->mpfr_1, sc->mpq_1, MPFR_RNDN);
21475 	  mpfr_div(sc->mpfr_1, sc->mpfr_1, big_real(y), MPFR_RNDN);
21476 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21477 	case T_BIG_COMPLEX:
21478 	  if ((!mpfr_number_p(mpc_realref(big_complex(y)))) || (!mpfr_number_p(mpc_imagref(big_complex(y)))))
21479 	    return(complex_NaN);
21480 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
21481 	  mpc_set_q(sc->mpc_1, sc->mpq_1, MPC_RNDNN);
21482 	  mpc_div(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
21483 	  return(mpc_to_number(sc, sc->mpc_1));
21484 #endif
21485 	default:
21486 	  return(method_or_bust_with_type_pp(sc, y, sc->divide_symbol, x, y, a_number_string, 2));
21487 	}
21488 
21489       /* -------- real x -------- */
21490     case T_REAL:
21491       switch (type(y))
21492 	{
21493 	case T_INTEGER:
21494 	  if (integer(y) == 0)
21495 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21496 	  if (is_NaN(real(x))) return(real_NaN); /* what is (/ +nan.0 0)? */
21497 	  if (is_inf(real(x)))
21498 	    return((real(x) > 0.0) ? ((integer(y) > 0) ? real_infinity : real_minus_infinity) : ((integer(y) > 0) ? real_minus_infinity : real_infinity));
21499 	  return(make_real(sc, (long_double)real(x) / (long_double)integer(y)));
21500 
21501 	case T_RATIO:
21502 	  if (is_NaN(real(x))) return(real_NaN);
21503 	  if (is_inf(real(x)))
21504 	    return((real(x) > 0) ? ((numerator(y) > 0) ? real_infinity : real_minus_infinity) : ((numerator(y) > 0) ? real_minus_infinity : real_infinity));
21505 	  return(make_real(sc, real(x) * inverted_fraction(y)));
21506 
21507 	case T_REAL:
21508 	  if (is_NaN(real(y))) return(real_NaN);
21509 	  if (real(y) == 0.0)
21510 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21511 	  if (is_NaN(real(x))) return(real_NaN);
21512 	  if (is_inf(real(y)))
21513 	    return((is_inf(real(x))) ? real_NaN : real_zero);
21514 	  return(make_real(sc, real(x) / real(y)));
21515 
21516 	case T_COMPLEX:
21517 	  {
21518 	    s7_double den, r2, i2;
21519 	    if (is_NaN(real(x))) return(complex_NaN);
21520 	    r2 = real_part(y);
21521 	    i2 = imag_part(y);
21522 	    if ((is_NaN(r2)) || (is_inf(r2))) return(complex_NaN);
21523 	    if ((is_NaN(i2)) || (is_inf(i2))) return(complex_NaN);
21524 	    den = 1.0 / (r2 * r2 + i2 * i2);
21525 	    return(s7_make_complex(sc, real(x) * r2 * den, -real(x) * i2 * den));
21526 	  }
21527 
21528 #if WITH_GMP
21529 	case T_BIG_INTEGER:
21530 	  if (mpz_cmp_ui(big_integer(y), 0) == 0)
21531 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21532 	  mpfr_set_z(sc->mpfr_1, big_integer(y), MPFR_RNDN);
21533 	  mpfr_d_div(sc->mpfr_1, real(x), sc->mpfr_1, MPFR_RNDN);
21534 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21535 	case T_BIG_RATIO:
21536 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
21537 	  mpfr_div_q(sc->mpfr_1, sc->mpfr_1, big_ratio(y), MPFR_RNDN);
21538 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21539 	case T_BIG_REAL:
21540 	  if (mpfr_zero_p(big_real(y)))
21541 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21542 	  mpfr_d_div(sc->mpfr_1, real(x), big_real(y), MPFR_RNDN);
21543 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21544 	case T_BIG_COMPLEX:
21545 	  if ((is_NaN(real(x))) || (!mpfr_number_p(mpc_realref(big_complex(y)))) || (!mpfr_number_p(mpc_imagref(big_complex(y)))))
21546 	    return(complex_NaN);
21547 	  mpc_set_d_d(sc->mpc_1, real(x), 0.0, MPC_RNDNN);
21548 	  mpc_div(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
21549 	  return(mpc_to_number(sc, sc->mpc_1));
21550 #endif
21551 	default:
21552 	  return(method_or_bust_with_type_pp(sc, y, sc->divide_symbol, x, y, a_number_string, 2));
21553 	}
21554 
21555       /* -------- complex x -------- */
21556     case T_COMPLEX:
21557       switch (type(y))
21558 	{
21559 	case T_INTEGER:
21560 	  {
21561 	    s7_double r1;
21562 	    if (integer(y) == 0)
21563 	      return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21564 	    r1 = (long_double)1.0 / (long_double)integer(y);
21565 	    return(s7_make_complex(sc, real_part(x) * r1, imag_part(x) * r1));
21566 	  }
21567 
21568 	case T_RATIO:
21569 	  {
21570 	    s7_double frac;
21571 	    frac = inverted_fraction(y);
21572 	    return(make_complex(sc, real_part(x) * frac, imag_part(x) * frac));
21573 	  }
21574 
21575 	case T_REAL:
21576 	  {
21577 	    s7_double r1;
21578 	    if (real(y) == 0.0)
21579 	      return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21580 	    r1 = 1.0 / real(y);
21581 	    return(make_complex(sc, real_part(x) * r1, imag_part(x) * r1)); /* (/ 0.0+1.0i +inf.0) */
21582 	  }
21583 
21584 	case T_COMPLEX:
21585 	  {
21586 	    s7_double r1, r2, i1, i2, den;
21587 	    r1 = real_part(x);
21588 	    if (is_NaN(r1)) return(real_NaN);
21589 	    i1 = imag_part(x);
21590 	    if (is_NaN(i1)) return(real_NaN);
21591 	    r2 = real_part(y);
21592 	    if (is_NaN(r2)) return(real_NaN);
21593 	    if (is_inf(r2)) return(complex_NaN);
21594 	    i2 = imag_part(y);
21595 	    if (is_NaN(i2)) return(real_NaN);
21596 	    den = 1.0 / (r2 * r2 + i2 * i2);
21597 	    return(s7_make_complex(sc, (r1 * r2 + i1 * i2) * den, (r2 * i1 - r1 * i2) * den));
21598 	  }
21599 
21600 #if WITH_GMP
21601 	case T_BIG_INTEGER:
21602 	  if (mpz_cmp_ui(big_integer(y), 0) == 0)
21603 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21604 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
21605 	  mpc_set_z(sc->mpc_2, big_integer(y), MPC_RNDNN);
21606 	  mpc_div(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
21607 	  return(mpc_to_number(sc, sc->mpc_1));
21608 	case T_BIG_RATIO:
21609 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
21610 	  mpc_set_q(sc->mpc_2, big_ratio(y), MPC_RNDNN);
21611 	  mpc_div(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
21612 	  return(mpc_to_number(sc, sc->mpc_1));
21613 	case T_BIG_REAL:
21614 	  if (mpfr_zero_p(big_real(y)))
21615 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21616 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
21617 	  mpc_div_fr(sc->mpc_1, sc->mpc_1, big_real(y), MPC_RNDNN);
21618 	  return(mpc_to_number(sc, sc->mpc_1));
21619 	case T_BIG_COMPLEX:
21620 	  if ((!mpfr_number_p(mpc_realref(big_complex(y)))) || (!mpfr_number_p(mpc_imagref(big_complex(y)))))
21621 	    return(complex_NaN);
21622 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
21623 	  mpc_div(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
21624 	  return(mpc_to_number(sc, sc->mpc_1));
21625 #endif
21626 
21627 	default:
21628 	  return(method_or_bust_with_type_pp(sc, y, sc->divide_symbol, x, y, a_number_string, 2));
21629 	}
21630 
21631 #if WITH_GMP
21632     case T_BIG_INTEGER:
21633       switch (type(y))
21634 	{
21635 	case T_INTEGER:
21636 	  if (integer(y) == 0)
21637 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21638 	  mpz_set_si(sc->mpz_1, integer(y));
21639 	  mpq_set_num(sc->mpq_1, big_integer(x));
21640 	  mpq_set_den(sc->mpq_1, sc->mpz_1);
21641 	  mpq_canonicalize(sc->mpq_1);
21642 	  return(mpq_to_rational(sc, sc->mpq_1));
21643 	case T_RATIO:
21644 	  mpq_set_z(sc->mpq_2, big_integer(x));
21645 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y)); /* can't invert here, mpq den=unsigned */
21646 	  mpq_div(sc->mpq_1, sc->mpq_2, sc->mpq_1);
21647 	  mpq_canonicalize(sc->mpq_1);
21648 	  return(mpq_to_rational(sc, sc->mpq_1));
21649 	case T_REAL:
21650 	  if (is_NaN(real(y))) return(real_NaN);
21651 	  if (real(y) == 0.0)
21652 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21653 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
21654 	  mpfr_div_d(sc->mpfr_1, sc->mpfr_1, real(y), MPFR_RNDN);
21655 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21656 	case T_COMPLEX:
21657 	  if ((is_NaN(real_part(y))) || (is_NaN(imag_part(y))) ||
21658 	      (is_inf(real_part(y))) || (is_inf(imag_part(y))))
21659 	    return(complex_NaN);
21660 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
21661 	  mpc_set_z(sc->mpc_2, big_integer(x), MPC_RNDNN);
21662 	  mpc_div(sc->mpc_1, sc->mpc_2, sc->mpc_1, MPC_RNDNN);
21663 	  return(mpc_to_number(sc, sc->mpc_1));
21664 	case T_BIG_INTEGER:
21665 	  if (mpz_cmp_ui(big_integer(y), 0) == 0)
21666 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21667 	  mpq_set_num(sc->mpq_1, big_integer(x));
21668 	  mpq_set_den(sc->mpq_1, big_integer(y));
21669 	  mpq_canonicalize(sc->mpq_1);
21670 	  return(mpq_to_rational(sc, sc->mpq_1));
21671 	case T_BIG_RATIO:
21672 	  mpq_set_si(sc->mpq_1, 0, 1);
21673 	  mpq_set_num(sc->mpq_1, big_integer(x));
21674 	  mpq_div(sc->mpq_1, sc->mpq_1, big_ratio(y));
21675 	  return(mpq_to_rational(sc, sc->mpq_1));
21676 	case T_BIG_REAL:
21677 	  if (mpfr_zero_p(big_real(y)))
21678 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21679 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
21680 	  mpfr_div(sc->mpfr_1, sc->mpfr_1, big_real(y), MPFR_RNDN);
21681 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21682 	case T_BIG_COMPLEX:
21683 	  if ((!mpfr_number_p(mpc_realref(big_complex(y)))) || (!mpfr_number_p(mpc_imagref(big_complex(y)))))
21684 	    return(complex_NaN);
21685 	  mpc_set_z(sc->mpc_1, big_integer(x), MPC_RNDNN);
21686 	  mpc_div(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
21687 	  return(mpc_to_number(sc, sc->mpc_1));
21688 	default:
21689 	  return(method_or_bust_with_type_pp(sc, y, sc->divide_symbol, x, y, a_number_string, 2));
21690 	}
21691     case T_BIG_RATIO:
21692       switch (type(y))
21693 	{
21694 	case T_INTEGER:
21695 	  if (integer(y) == 0)
21696 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21697 	  mpq_set_si(sc->mpq_1, integer(y), 1);
21698 	  mpq_div(sc->mpq_1, big_ratio(x), sc->mpq_1);
21699 	  return(mpq_to_rational(sc, sc->mpq_1));
21700 	case T_RATIO:
21701 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
21702 	  mpq_div(sc->mpq_1, big_ratio(x), sc->mpq_1);
21703 	  return(mpq_to_rational(sc, sc->mpq_1));
21704 	case T_REAL:
21705 	  if (is_NaN(real(y))) return(real_NaN);
21706 	  if (real(y) == 0.0)
21707 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21708 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
21709 	  mpfr_div_d(sc->mpfr_1, sc->mpfr_1, real(y), MPFR_RNDN);
21710 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21711 	case T_COMPLEX:
21712 	  if ((is_NaN(real_part(y))) || (is_NaN(imag_part(y))) ||
21713 	      (is_inf(real_part(y))) || (is_inf(imag_part(y))))
21714 	    return(complex_NaN);
21715 	  mpc_set_q(sc->mpc_1, big_ratio(x), MPC_RNDNN);
21716 	  mpc_set_d_d(sc->mpc_2, real_part(y), imag_part(y), MPC_RNDNN);
21717 	  mpc_div(sc->mpc_1, sc->mpc_1, sc->mpc_2, MPC_RNDNN);
21718 	  return(mpc_to_number(sc, sc->mpc_1));
21719 	case T_BIG_INTEGER:
21720 	  if (mpz_cmp_ui(big_integer(y), 0) == 0)
21721 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21722 	  mpq_set_z(sc->mpq_1, big_integer(y));
21723 	  mpq_div(sc->mpq_1, big_ratio(x), sc->mpq_1);
21724 	  mpq_canonicalize(sc->mpq_1);
21725 	  return(mpq_to_rational(sc, sc->mpq_1));
21726 	case T_BIG_RATIO:
21727 	  mpq_div(sc->mpq_1, big_ratio(x), big_ratio(y));
21728 	  mpq_canonicalize(sc->mpq_1);
21729 	  return(mpq_to_rational(sc, sc->mpq_1));
21730 	case T_BIG_REAL:
21731 	  if (mpfr_zero_p(big_real(y)))
21732 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21733 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
21734 	  mpfr_div(sc->mpfr_1, sc->mpfr_1, big_real(y), MPFR_RNDN);
21735 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21736 	case T_BIG_COMPLEX:
21737 	  if ((!mpfr_number_p(mpc_realref(big_complex(y)))) || (!mpfr_number_p(mpc_imagref(big_complex(y)))))
21738 	    return(complex_NaN);
21739 	  mpc_set_q(sc->mpc_1, big_ratio(x), MPC_RNDNN);
21740 	  mpc_div(sc->mpc_1, sc->mpc_1, big_complex(y), MPC_RNDNN);
21741 	  return(mpc_to_number(sc, sc->mpc_1));
21742 	default:
21743 	  return(method_or_bust_with_type_pp(sc, y, sc->divide_symbol, x, y, a_number_string, 2));
21744 	}
21745     case T_BIG_REAL:
21746       switch (type(y))
21747 	{
21748 	case T_INTEGER:
21749 	  if (integer(y) == 0)
21750 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21751 	  mpfr_div_si(sc->mpfr_1, big_real(x), integer(y), MPFR_RNDN);
21752 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21753 	case T_RATIO:
21754 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
21755 	  mpfr_div_q(sc->mpfr_1, big_real(x), sc->mpq_1, MPFR_RNDN);
21756 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21757 	case T_REAL:
21758 	  if (is_NaN(real(y))) return(real_NaN);
21759 	  if (real(y) == 0.0)
21760 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21761 	  mpfr_div_d(sc->mpfr_1, big_real(x), real(y), MPFR_RNDN);
21762 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21763 	case T_COMPLEX:
21764 	  if ((is_NaN(real_part(y))) || (is_NaN(imag_part(y))) ||
21765 	      (is_inf(real_part(y))) || (is_inf(imag_part(y))))
21766 	    return(complex_NaN);
21767 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
21768 	  mpc_fr_div(sc->mpc_1, big_real(x), sc->mpc_1, MPC_RNDNN);
21769 	  return(mpc_to_number(sc, sc->mpc_1));
21770 	case T_BIG_INTEGER:
21771 	  if (mpz_cmp_ui(big_integer(y), 0) == 0)
21772 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21773 	  mpfr_div_z(sc->mpfr_1, big_real(x), big_integer(y), MPFR_RNDN);
21774 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21775 	case T_BIG_RATIO:
21776 	  mpfr_div_q(sc->mpfr_1, big_real(x), big_ratio(y), MPFR_RNDN);
21777 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21778 	case T_BIG_REAL:
21779 	  if (mpfr_zero_p(big_real(y)))
21780 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21781 	  mpfr_div(sc->mpfr_1, big_real(x), big_real(y), MPFR_RNDN);
21782 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
21783 	case T_BIG_COMPLEX:
21784 	  if ((!mpfr_number_p(mpc_realref(big_complex(y)))) || (!mpfr_number_p(mpc_imagref(big_complex(y)))))
21785 	    return(complex_NaN);
21786 	  mpc_fr_div(sc->mpc_1, big_real(x), big_complex(y), MPC_RNDNN);
21787 	  return(mpc_to_number(sc, sc->mpc_1));
21788 	default:
21789 	  return(method_or_bust_with_type_pp(sc, y, sc->divide_symbol, x, y, a_number_string, 2));
21790 	}
21791     case T_BIG_COMPLEX:
21792       switch (type(y))
21793 	{
21794 	case T_INTEGER:
21795 	  if (integer(y) == 0)
21796 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21797 	  mpc_set_si(sc->mpc_1, integer(y), MPC_RNDNN);
21798 	  mpc_div(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
21799 	  return(mpc_to_number(sc, sc->mpc_1));
21800 	case T_RATIO:
21801 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
21802 	  mpc_set_q(sc->mpc_1, sc->mpq_1, MPC_RNDNN);
21803 	  mpc_div(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
21804 	  return(mpc_to_number(sc, sc->mpc_1));
21805 	case T_REAL:
21806 	  /* if (is_NaN(real(y))) return(real_NaN); */
21807 	  if (real(y) == 0.0)
21808 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21809 	  mpc_set_d_d(sc->mpc_1, real(y), 0.0, MPC_RNDNN);
21810 	  mpc_div(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
21811 	  return(mpc_to_number(sc, sc->mpc_1));
21812 	case T_COMPLEX:
21813 	  if ((is_NaN(real_part(y))) || (is_NaN(imag_part(y))) ||
21814 	      (is_inf(real_part(y))) || (is_inf(imag_part(y))))
21815 	    return(complex_NaN);
21816 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
21817 	  mpc_div(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
21818 	  return(mpc_to_number(sc, sc->mpc_1));
21819 	case T_BIG_INTEGER:
21820 	  if (mpz_cmp_ui(big_integer(y), 0) == 0)
21821 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21822 	  mpc_set_z(sc->mpc_1, big_integer(y), MPC_RNDNN);
21823 	  mpc_div(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
21824 	  return(mpc_to_number(sc, sc->mpc_1));
21825 	case T_BIG_RATIO:
21826 	  mpc_set_q(sc->mpc_1, big_ratio(y), MPC_RNDNN);
21827 	  mpc_div(sc->mpc_1, big_complex(x), sc->mpc_1, MPC_RNDNN);
21828 	  return(mpc_to_number(sc, sc->mpc_1));
21829 	case T_BIG_REAL:
21830 	  if (mpfr_zero_p(big_real(y)))
21831 	    return(division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, x, y)));
21832 	  mpc_div_fr(sc->mpc_1, big_complex(x), big_real(y), MPC_RNDNN);
21833 	  return(mpc_to_number(sc, sc->mpc_1));
21834 	case T_BIG_COMPLEX:
21835 	  if ((!mpfr_number_p(mpc_realref(big_complex(y)))) || (!mpfr_number_p(mpc_imagref(big_complex(y)))))
21836 	    return(complex_NaN);
21837 	  mpc_div(sc->mpc_1, big_complex(x), big_complex(y), MPC_RNDNN);
21838 	  return(mpc_to_number(sc, sc->mpc_1));
21839 	default:
21840 	  return(method_or_bust_with_type_pp(sc, y, sc->divide_symbol, x, y, a_number_string, 2));
21841 	}
21842 #endif
21843 
21844       /* x is not a built-in number */
21845     default:
21846       return(method_or_bust_with_type_pp(sc, x, sc->divide_symbol, x, y, a_number_string, 1)); /* not args here! y = apply * to cdr(args) */
21847     }
21848 
21849   return(NULL); /* make the compiler happy */
21850 }
21851 
21852 static s7_pointer g_divide(s7_scheme *sc, s7_pointer args)
21853 {
21854   #define H_divide "(/ x1 ...) divides its first argument by the rest, or inverts the first if there is only one argument"
21855   #define Q_divide sc->pcl_n
21856 
21857   s7_pointer x, y, p;
21858 
21859   x = car(args);
21860   p = cdr(args);
21861 
21862   if (is_null(p))            /* (/ x) */
21863     {
21864       if (!is_number(x))
21865 	return(method_or_bust_with_type_one_arg(sc, x, sc->divide_symbol, args, a_number_string));
21866       return(invert_p_p(sc, x));
21867     }
21868 
21869   if (is_null(cdr(p)))
21870     return(divide_p_pp(sc, x, cadr(args)));
21871 
21872   y = g_multiply(sc, p); /* in some schemes (/ 1 0 +nan.0) is not equal to (/ 1 (* 0 +nan.0)), in s7 they're both +nan.0 */
21873   return(divide_p_pp(sc, x, y));
21874 }
21875 
21876 static s7_pointer g_invert_1(s7_scheme *sc, s7_pointer args) {return(invert_p_p(sc, car(args)));}
21877 static s7_pointer g_divide_2(s7_scheme *sc, s7_pointer args) {return(divide_p_pp(sc, car(args), cadr(args)));}
21878 
21879 static s7_pointer g_divide_by_2(s7_scheme *sc, s7_pointer args)
21880 {
21881   /* (/ x 2) */
21882   s7_pointer num;
21883   num = car(args);
21884   if (is_t_integer(num))
21885     {
21886       s7_int i;
21887       i = integer(num);
21888       if (i & 1)
21889 	{
21890 	  s7_pointer x;
21891 	  new_cell(sc, x, T_RATIO);
21892 	  numerator(x) = i;
21893 	  denominator(x) = 2;
21894 	  return(x);
21895 	}
21896       return(make_integer(sc, i >> 1));
21897     }
21898   switch (type(num))
21899     {
21900     case T_RATIO:
21901 #if HAVE_OVERFLOW_CHECKS
21902       {
21903 	s7_int dn;
21904 	if (multiply_overflow(denominator(num), 2, &dn))
21905 	  {
21906 	    if ((numerator(num) & 1) == 1)
21907 #if WITH_GMP
21908 	      {
21909 		mpq_set_si(sc->mpq_1, numerator(num), denominator(num));
21910 		mpq_set_si(sc->mpq_2, 1, 2);
21911 		mpq_mul(sc->mpq_1, sc->mpq_1, sc->mpq_2);
21912 		return(mpq_to_rational(sc, sc->mpq_1));
21913 	      }
21914 #else
21915 	      return(make_real(sc, ((long_double)numerator(num) * 0.5) / (long_double)denominator(num)));
21916 #endif
21917 	    return(s7_make_ratio(sc, numerator(num) / 2, denominator(num)));
21918 	  }
21919 	return(s7_make_ratio(sc, numerator(num), dn));
21920       }
21921 #else
21922       return(s7_make_ratio(sc, numerator(num), denominator(num) * 2));
21923 #endif
21924 
21925     case T_REAL:    return(make_real(sc, real(num) * 0.5));
21926     case T_COMPLEX: return(make_complex_unchecked(sc, real_part(num) * 0.5, imag_part(num) * 0.5));
21927 
21928 #if WITH_GMP
21929     case T_BIG_INTEGER:
21930       mpq_set_z(sc->mpq_1, big_integer(num));
21931       mpz_mul_ui(mpq_denref(sc->mpq_1), mpq_denref(sc->mpq_1), 2);
21932       mpq_canonicalize(sc->mpq_1);
21933       return(mpq_to_rational(sc, sc->mpq_1));
21934     case T_BIG_RATIO:
21935       mpq_set_si(sc->mpq_1, 2, 1);
21936       mpq_div(sc->mpq_1, big_ratio(num), sc->mpq_1);
21937       mpq_canonicalize(sc->mpq_1);
21938       return(mpq_to_rational(sc, sc->mpq_1));
21939     case T_BIG_REAL:
21940       mpfr_div_si(sc->mpfr_1, big_real(num), 2, MPFR_RNDN);
21941       return(mpfr_to_big_real(sc, sc->mpfr_1));
21942     case T_BIG_COMPLEX:
21943       mpc_set_si(sc->mpc_1, 2, MPC_RNDNN);
21944       mpc_div(sc->mpc_1, big_complex(num), sc->mpc_1, MPC_RNDNN);
21945       return(mpc_to_number(sc, sc->mpc_1));
21946 #endif
21947     default:
21948       return(method_or_bust_with_type_pp(sc, num, sc->divide_symbol, num, int_two, a_number_string, 1));
21949     }
21950 }
21951 
21952 static s7_pointer g_invert_x(s7_scheme *sc, s7_pointer args)
21953 {
21954   /* (/ 1.0 x) */
21955   if (is_t_real(cadr(args)))
21956     {
21957       s7_double rl;
21958       rl = s7_real(cadr(args));
21959       if (rl == 0.0)
21960 	return(division_by_zero_error(sc, sc->divide_symbol, args));
21961       return((is_NaN(rl)) ? real_NaN : make_real(sc, 1.0 / rl));
21962     }
21963   return(g_divide(sc, args));
21964 }
21965 
21966 static s7_double divide_d_7d(s7_scheme *sc, s7_double x)
21967 {
21968   if (x == 0.0) division_by_zero_error(sc, sc->divide_symbol, set_elist_1(sc, real_zero));
21969   return(1.0 / x);
21970 }
21971 
21972 static s7_double divide_d_7dd(s7_scheme *sc, s7_double x1, s7_double x2)
21973 {
21974   if (x2 == 0.0) division_by_zero_error(sc, sc->divide_symbol, set_elist_1(sc, real_zero));
21975   return(x1 / x2);
21976 }
21977 
21978 static s7_pointer divide_p_ii(s7_scheme *sc, s7_int x, s7_int y) {return(s7_make_ratio(sc, x, y));} /* make-ratio checks for y==0 */
21979 static s7_pointer divide_p_i(s7_scheme *sc, s7_int x) {return(s7_make_ratio(sc, 1, x));}
21980 
21981 static s7_pointer divide_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
21982 {
21983   if (args == 1)
21984     return(sc->invert_1);
21985   if (ops)
21986     {
21987       if (args == 2)
21988 	{
21989 	  s7_pointer arg1;
21990 	  arg1 = cadr(expr);
21991 	  if ((is_t_real(arg1)) && (real(arg1) == 1.0))
21992 	    return(sc->invert_x);
21993 	  return(((is_t_integer(caddr(expr))) && (integer(caddr(expr)) == 2)) ? sc->divide_by_2 : sc->divide_2);
21994 	}}
21995   return(f);
21996 }
21997 
21998 
21999 /* -------------------------------- quotient -------------------------------- */
22000 
22001 static inline s7_int quotient_i_7ii(s7_scheme *sc, s7_int x, s7_int y)
22002 {
22003   if ((y > 0) || (y < -1)) return(x / y);
22004   if (y == 0)
22005     division_by_zero_error(sc, sc->quotient_symbol, set_elist_2(sc, wrap_integer1(sc, x), wrap_integer2(sc, y)));
22006   if ((y == -1) && (x == S7_INT64_MIN))   /* (quotient most-negative-fixnum -1) */
22007     simple_out_of_range(sc, sc->quotient_symbol, set_elist_2(sc, wrap_integer1(sc, x), wrap_integer2(sc, y)), its_too_large_string);
22008   return(x / y);
22009 }
22010 
22011 #if (!WITH_GMP)
22012 static s7_pointer s7_truncate(s7_scheme *sc, s7_pointer caller, s7_double xf)   /* can't use "truncate" -- it's in unistd.h */
22013 {
22014   if (fabs(xf) > QUOTIENT_FLOAT_LIMIT)
22015     return(simple_out_of_range(sc, caller, wrap_real1(sc, xf), its_too_large_string));
22016   return((xf > 0.0) ? make_integer(sc, (s7_int)floor(xf)) : make_integer(sc, (s7_int)ceil(xf)));
22017 }
22018 
22019 static s7_int c_quo_dbl(s7_scheme *sc, s7_double x, s7_double y)
22020 {
22021   s7_double xf;
22022 
22023   if (y == 0.0)
22024     division_by_zero_error(sc, sc->quotient_symbol, set_elist_2(sc, wrap_real1(sc, x), wrap_real2(sc, y)));
22025   if ((is_inf(y)) || (is_NaN(y))) /* here we can't return NAN so I guess we should signal an error */
22026     wrong_type_argument_with_type(sc, sc->quotient_symbol, 2, wrap_real1(sc, y), a_normal_real_string);
22027   xf = x / y;
22028   if (fabs(xf) > QUOTIENT_FLOAT_LIMIT)
22029     simple_out_of_range(sc, sc->quotient_symbol, wrap_real1(sc, xf), its_too_large_string);
22030   return((xf > 0.0) ? (s7_int)floor(xf) : (s7_int)ceil(xf));
22031 }
22032 #endif
22033 
22034 static s7_int quotient_i_ii_unchecked(s7_int i1, s7_int i2) {return(i1 / i2);} /* i2 > 0 */
22035 
22036 static s7_pointer quotient_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
22037 {
22038 #if WITH_GMP
22039   if ((s7_is_real(x)) && (s7_is_real(y)))
22040     {
22041       if (s7_is_zero(y))
22042 	division_by_zero_error(sc, sc->quotient_symbol, set_elist_2(sc, x, y));
22043       if ((s7_is_integer(x)) && (s7_is_integer(y)))
22044 	{
22045 	  if (is_t_integer(x)) mpz_set_si(sc->mpz_1, integer(x)); else mpz_set(sc->mpz_1, big_integer(x));
22046 	  if (is_t_integer(y)) mpz_set_si(sc->mpz_2, integer(y)); else mpz_set(sc->mpz_2, big_integer(y));
22047 	  mpz_tdiv_q(sc->mpz_1, sc->mpz_1, sc->mpz_2);
22048 	}
22049       else
22050 	{
22051 	  if ((!is_rational(x)) || (!is_rational(y)))
22052 	    {
22053 	      if (any_real_to_mpfr(sc, x, sc->mpfr_1)) return(real_NaN);
22054 	      if (any_real_to_mpfr(sc, y, sc->mpfr_2)) return(real_NaN);
22055 	      mpfr_div(sc->mpfr_3, sc->mpfr_1, sc->mpfr_2, MPFR_RNDN);
22056 	      mpfr_get_z(sc->mpz_1, sc->mpfr_3, MPFR_RNDZ);
22057 	    }
22058 	  else
22059 	    {
22060 	      any_rational_to_mpq(sc, x, sc->mpq_1);
22061 	      any_rational_to_mpq(sc, y, sc->mpq_2);
22062 	      mpq_div(sc->mpq_3, sc->mpq_1, sc->mpq_2);
22063 	      mpz_tdiv_q(sc->mpz_1, mpq_numref(sc->mpq_3), mpq_denref(sc->mpq_3));
22064 	    }}
22065       return(mpz_to_integer(sc, sc->mpz_1));
22066     }
22067   return(method_or_bust_pp(sc, (s7_is_real(x)) ? y : x, sc->quotient_symbol, x, y, T_REAL, (s7_is_real(x)) ? 2 : 1));
22068 #else
22069 
22070   s7_int d1, d2, n1, n2;
22071   if ((is_t_integer(x)) && (is_t_integer(y)))
22072     return(make_integer(sc, quotient_i_7ii(sc, integer(x), integer(y))));
22073 
22074   switch (type(x))
22075     {
22076     case T_INTEGER:
22077       switch (type(y))
22078 	{
22079 	case T_INTEGER:
22080 	  return(make_integer(sc, quotient_i_7ii(sc, integer(x), integer(y))));
22081 
22082 	case T_RATIO:
22083 	  n1 = integer(x);
22084 	  d1 = 1;
22085 	  n2 = numerator(y);
22086 	  d2 = denominator(y);
22087 	  /* (quotient -9223372036854775808 -1/9223372036854775807): arithmetic exception in the no-overflow-checks case */
22088 	  goto RATIO_QUO_RATIO;
22089 
22090 	case T_REAL:
22091 	  if (real(y) == 0.0)
22092 	    return(division_by_zero_error(sc, sc->quotient_symbol, set_elist_2(sc, x, y)));
22093 	  if ((is_inf(real(y))) || (is_NaN(real(y))))
22094 	    return(real_NaN);
22095 	  return(s7_truncate(sc, sc->quotient_symbol, (s7_double)integer(x) / real(y))); /* s7_truncate returns an integer */
22096 
22097 	default:
22098 	  return(method_or_bust_pp(sc, y, sc->quotient_symbol, x, y, T_REAL, 2));
22099 	}
22100 
22101     case T_RATIO:
22102       switch (type(y))
22103 	{
22104 	case T_INTEGER:
22105 	  if (integer(y) == 0)
22106 	    return(division_by_zero_error(sc, sc->quotient_symbol, set_elist_2(sc, x, y)));
22107 	  n1 = numerator(x);
22108 	  d1 = denominator(x);
22109 	  n2 = integer(y);
22110 	  d2 = 1;
22111 	  goto RATIO_QUO_RATIO;
22112 	  /* this can lose:
22113 	   *   (quotient 1 2305843009213693952/4611686018427387903) -> 2, not 1
22114 	   *   (quotient 21053343141/6701487259 3587785776203/1142027682075) -> 1, not 0
22115 	   */
22116 
22117 	case T_RATIO:
22118 	  parcel_out_fractions(x, y);
22119 	RATIO_QUO_RATIO:
22120 	  if (d1 == d2)
22121 	    return(make_integer(sc, n1 / n2));              /* (quotient 3/9223372036854775807 1/9223372036854775807) */
22122 	  if (n1 == n2)
22123 	    return(make_integer(sc, d2 / d1));              /* (quotient 9223372036854775807/2 9223372036854775807/8) */
22124 #if HAVE_OVERFLOW_CHECKS
22125 	  {
22126 	    s7_int n1d2, n2d1;
22127 	    if ((multiply_overflow(n1, d2, &n1d2)) ||
22128 		(multiply_overflow(n2, d1, &n2d1)))
22129 	      return(s7_truncate(sc, sc->quotient_symbol, ((long_double)n1 / (long_double)n2) * ((long_double)d2 / (long_double)d1)));
22130 	    return(make_integer(sc, n1d2 / n2d1));
22131 	  }
22132 #else
22133 	  return(make_integer(sc, (n1 * d2) / (n2 * d1)));
22134 #endif
22135 
22136 	case T_REAL:
22137 	  if (real(y) == 0.0)
22138 	    return(division_by_zero_error(sc, sc->quotient_symbol, set_elist_2(sc, x, y)));
22139 	  if ((is_inf(real(y))) || (is_NaN(real(y))))
22140 	    return(real_NaN);
22141 	  return(s7_truncate(sc, sc->quotient_symbol, (s7_double)fraction(x) / real(y)));
22142 
22143 	default:
22144 	  return(method_or_bust_pp(sc, y, sc->quotient_symbol, x, y, T_REAL, 2));
22145 	}
22146 
22147     case T_REAL:
22148       if (((is_inf(real(x))) || (is_NaN(real(x)))) && (s7_is_real(y)))
22149 	return(real_NaN);
22150       /* if infs allowed we need to return infs/nans, else:
22151        *    (quotient inf.0 1e-309) -> -9223372036854775808
22152        *    (quotient inf.0 inf.0) -> -9223372036854775808
22153        */
22154 
22155       switch (type(y))
22156 	{
22157 	case T_INTEGER:
22158 	  if (integer(y) == 0)
22159 	    return(division_by_zero_error(sc, sc->quotient_symbol, set_elist_2(sc, x, y)));
22160 	  return(s7_truncate(sc, sc->quotient_symbol, (long_double)real(x) / (long_double)integer(y)));
22161 
22162 	case T_RATIO: return(s7_truncate(sc, sc->quotient_symbol, real(x) / (s7_double)fraction(y)));
22163 	case T_REAL:  return(make_integer(sc, c_quo_dbl(sc, real(x), real(y)))); /* c_quo_dbl returns an integer */
22164 	default:      return(method_or_bust_pp(sc, y, sc->quotient_symbol, x, y, T_REAL, 2));
22165 	}
22166 
22167     default:
22168       return(method_or_bust_pp(sc, x, sc->quotient_symbol, x, y, T_REAL, 2));
22169     }
22170 #endif
22171 }
22172 
22173 static s7_pointer g_quotient(s7_scheme *sc, s7_pointer args)
22174 {
22175   #define H_quotient "(quotient x1 x2) returns the integer quotient of x1 and x2; (quotient 4 3) = 1"
22176   #define Q_quotient sc->pcl_r
22177   /* sig was '(integer? ...) but quotient can return NaN */
22178   /* (define (quo x1 x2) (truncate (/ x1 x2))) ; slib */
22179   return(quotient_p_pp(sc, car(args), cadr(args)));
22180 }
22181 
22182 
22183 /* -------------------------------- remainder -------------------------------- */
22184 
22185 #if WITH_GMP
22186 static s7_pointer big_mod_or_rem(s7_scheme *sc, s7_pointer x, s7_pointer y, bool use_floor)
22187 {
22188   if ((s7_is_real(x)) && (s7_is_real(y)))
22189     {
22190       if ((s7_is_integer(x)) && (s7_is_integer(y)))
22191 	{
22192 	  if (is_t_integer(x)) mpz_set_si(sc->mpz_1, integer(x)); else mpz_set(sc->mpz_1, big_integer(x));
22193 	  if (is_t_integer(y)) mpz_set_si(sc->mpz_2, integer(y)); else mpz_set(sc->mpz_2, big_integer(y));
22194 	  if (use_floor)
22195 	    mpz_fdiv_q(sc->mpz_3, sc->mpz_1, sc->mpz_2);
22196 	  else mpz_tdiv_q(sc->mpz_3, sc->mpz_1, sc->mpz_2);
22197 	  mpz_mul(sc->mpz_3, sc->mpz_3, sc->mpz_2);
22198 	  mpz_sub(sc->mpz_1, sc->mpz_1, sc->mpz_3);
22199 	  return(mpz_to_integer(sc, sc->mpz_1));
22200 	}
22201       if ((!is_rational(x)) || (!is_rational(y)))
22202 	{
22203 	  any_real_to_mpfr(sc, x, sc->mpfr_1);
22204 	  any_real_to_mpfr(sc, y, sc->mpfr_2);
22205 	  mpfr_div(sc->mpfr_3, sc->mpfr_1, sc->mpfr_2, MPFR_RNDN);
22206 	  if (use_floor)
22207 	    mpfr_get_z(sc->mpz_1, sc->mpfr_3, MPFR_RNDD);
22208 	  else mpfr_get_z(sc->mpz_1, sc->mpfr_3, MPFR_RNDZ);
22209 	  mpfr_mul_z(sc->mpfr_2, sc->mpfr_2, sc->mpz_1, MPFR_RNDN);
22210 	  mpfr_sub(sc->mpfr_1, sc->mpfr_1, sc->mpfr_2, MPFR_RNDN);
22211 	  return(mpfr_to_big_real(sc, sc->mpfr_1));
22212 	}
22213       any_rational_to_mpq(sc, x, sc->mpq_1);
22214       any_rational_to_mpq(sc, y, sc->mpq_2);
22215       mpq_div(sc->mpq_3, sc->mpq_1, sc->mpq_2);
22216       if (use_floor)
22217 	mpz_fdiv_q(sc->mpz_1, mpq_numref(sc->mpq_3), mpq_denref(sc->mpq_3));
22218       else mpz_tdiv_q(sc->mpz_1, mpq_numref(sc->mpq_3), mpq_denref(sc->mpq_3));
22219       mpz_mul(mpq_numref(sc->mpq_2), sc->mpz_1, mpq_numref(sc->mpq_2));
22220       mpq_sub(sc->mpq_1, sc->mpq_1, sc->mpq_2);
22221       mpq_canonicalize(sc->mpq_1);
22222       return(mpq_to_rational(sc, sc->mpq_1));
22223     }
22224   return(method_or_bust_pp(sc, (s7_is_real(x)) ? y : x, (use_floor) ? sc->modulo_symbol : sc->remainder_symbol, x, y, T_REAL, (s7_is_real(x)) ? 2 : 1));
22225 }
22226 #endif
22227 
22228 #define REMAINDER_FLOAT_LIMIT 1e13
22229 
22230 static inline s7_int remainder_i_7ii(s7_scheme *sc, s7_int x, s7_int y)
22231 {
22232   if ((y > 1) || (y < -1)) return(x % y);
22233   if (y == 0)
22234     division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, wrap_integer1(sc, x), wrap_integer2(sc, y)));
22235   return(0);
22236 }
22237 
22238 static s7_double c_rem_dbl(s7_scheme *sc, s7_double x, s7_double y)
22239 {
22240   s7_int quo;
22241   s7_double pre_quo;
22242   if ((is_inf(y)) || (is_NaN(y)))
22243     return(NAN);
22244   pre_quo = x / y;
22245   if (fabs(pre_quo) > REMAINDER_FLOAT_LIMIT)
22246     simple_out_of_range(sc, sc->remainder_symbol, set_elist_2(sc, wrap_real1(sc, x), wrap_real2(sc, y)), its_too_large_string);
22247   quo = (pre_quo > 0.0) ? (s7_int)floor(pre_quo) : (s7_int)ceil(pre_quo);
22248   return(x - (y * quo));
22249 }
22250 
22251 static s7_int remainder_i_ii_unchecked(s7_int i1, s7_int i2) {return(i1 % i2);} /* i2 > 1 */
22252 static s7_double remainder_d_7dd(s7_scheme *sc, s7_double x1, s7_double x2)
22253 {
22254   if (x2 == 0.0)
22255     division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, wrap_real1(sc, x1), wrap_real2(sc, x2)));
22256   if ((is_inf(x1)) || (is_NaN(x1))) /* match remainder_p_pp */
22257     return(NAN);
22258   return(c_rem_dbl(sc, x1, x2));
22259 }
22260 
22261 static s7_pointer remainder_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
22262 {
22263 #if WITH_GMP
22264   if (s7_is_zero(y))
22265     division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, x, y));
22266   return(big_mod_or_rem(sc, x, y, false));
22267 #else
22268   s7_int quo, d1, d2, n1, n2;
22269   s7_double pre_quo;
22270 
22271   if ((is_t_integer(x)) && (is_t_integer(y)))
22272     return(make_integer(sc, remainder_i_7ii(sc, integer(x), integer(y))));
22273 
22274   switch (type(x))
22275     {
22276     case T_INTEGER:
22277       switch (type(y))
22278 	{
22279 	case T_INTEGER:
22280 	  return(make_integer(sc, remainder_i_7ii(sc, integer(x), integer(y))));
22281 
22282 	case T_RATIO:
22283 	  n1 = integer(x);
22284 	  d1 = 1;
22285 	  n2 = numerator(y);
22286 	  d2 = denominator(y);
22287 	  goto RATIO_REM_RATIO;
22288 
22289 	case T_REAL:
22290 	  if (real(y) == 0.0)
22291 	    return(division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, x, y)));
22292 	  if ((is_inf(real(y))) || (is_NaN(real(y))))
22293 	    return(real_NaN);
22294 	  pre_quo = (long_double)integer(x) / (long_double)real(y);
22295 	  if (fabs(pre_quo) > REMAINDER_FLOAT_LIMIT)
22296 	    return(simple_out_of_range(sc, sc->remainder_symbol, set_elist_2(sc, x, y), its_too_large_string));
22297 	  if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
22298 	  return(make_real(sc, integer(x) - real(y) * quo));
22299 
22300 	default:
22301 	  return(method_or_bust_pp(sc, y, sc->remainder_symbol, x, y, T_REAL, 2));
22302 	}
22303 
22304     case T_RATIO:
22305       switch (type(y))
22306 	{
22307 	case T_INTEGER:
22308 	  n2 = integer(y);
22309  	  if (n2 == 0)
22310  	    return(division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, x, y)));
22311 	  n1 = numerator(x);
22312 	  d1 = denominator(x);
22313 	  d2 = 1;
22314 	  goto RATIO_REM_RATIO;
22315 
22316 	case T_RATIO:
22317 	  parcel_out_fractions(x, y);
22318 	RATIO_REM_RATIO:
22319 	  if (d1 == d2)
22320 	    quo = (s7_int)(n1 / n2);
22321 	  else
22322 	    {
22323 	      if (n1 == n2)
22324 		quo = (s7_int)(d2 / d1);
22325 	      else
22326 		{
22327 #if HAVE_OVERFLOW_CHECKS
22328 		  s7_int n1d2, n2d1;
22329 		  if ((multiply_overflow(n1, d2, &n1d2)) ||
22330 		      (multiply_overflow(n2, d1, &n2d1)))
22331 		    {
22332 		      pre_quo = ((long_double)n1 / (long_double)n2) * ((long_double)d2 / (long_double)d1);
22333 		      if (fabs(pre_quo) > REMAINDER_FLOAT_LIMIT)
22334 			return(simple_out_of_range(sc, sc->remainder_symbol, set_elist_2(sc, x, y), its_too_large_string));
22335 		      if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
22336 		    }
22337 		  else quo = n1d2 / n2d1;
22338 #else
22339 		  quo = (n1 * d2) / (n2 * d1);
22340 #endif
22341 		}}
22342 	  if (quo == 0)
22343 	    return(x);
22344 
22345 #if HAVE_OVERFLOW_CHECKS
22346 	  {
22347 	    s7_int dn, nq;
22348 	    if (!multiply_overflow(n2, quo, &nq))
22349 	      {
22350 		if ((d1 == d2) &&
22351 		    (!subtract_overflow(n1, nq, &dn)))
22352 		  return(s7_make_ratio(sc, dn, d1));
22353 
22354 		if ((!multiply_overflow(n1, d2, &dn)) &&
22355 		    (!multiply_overflow(nq, d1, &nq)) &&
22356 		    (!subtract_overflow(dn, nq, &nq)) &&
22357 		    (!multiply_overflow(d1, d2, &d1)))
22358 		  return(s7_make_ratio(sc, nq, d1));
22359 	      }}
22360 #else
22361 	  if (d1 == d2)
22362 	    return(s7_make_ratio(sc, n1 - n2 * quo, d1));
22363 
22364 	  return(s7_make_ratio(sc, n1 * d2 - n2 * d1 * quo, d1 * d2));
22365 #endif
22366 	  return(simple_out_of_range(sc, sc->remainder_symbol, set_elist_2(sc, x, y), wrap_string(sc, "intermediate (a/b) is too large", 31)));
22367 
22368 	case T_REAL:
22369 	  {
22370 	    s7_double frac;
22371 	    if (real(y) == 0.0)
22372 	      return(division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, x, y)));
22373 	    if ((is_inf(real(y))) || (is_NaN(real(y))))
22374 	      return(real_NaN);
22375 	    if (s7_int_abs(numerator(x)) > QUOTIENT_INT_LIMIT)
22376 	      return(subtract_p_pp(sc, x, multiply_p_pp(sc, y, quotient_p_pp(sc, x, y))));
22377 	    frac = (s7_double)fraction(x);
22378 	    pre_quo = frac / real(y);
22379 	    if (fabs(pre_quo) > REMAINDER_FLOAT_LIMIT)
22380 	      return(simple_out_of_range(sc, sc->remainder_symbol, set_elist_2(sc, x, y), its_too_large_string));
22381 	    if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
22382 	    return(make_real(sc, frac - real(y) * quo));
22383 	  }
22384 
22385 	default:
22386 	  return(method_or_bust_pp(sc, y, sc->remainder_symbol, x, y, T_REAL, 2));
22387 	}
22388 
22389     case T_REAL:
22390       if (((is_inf(real(x))) || (is_NaN(real(x)))) && (s7_is_real(y)))
22391 	{
22392 	  if (s7_is_zero(y))
22393 	    return(division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, x, y)));
22394 	  return(real_NaN);
22395 	}
22396       switch (type(y))
22397 	{
22398 	case T_INTEGER:
22399 	  if (integer(y) == 0)
22400 	    return(division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, x, y)));
22401 	  /* actually here (and elsewhere) if y > INT64_TO_DOUBLE_LIMIT, the result is probably wrong */
22402 	  pre_quo = (long_double)real(x) / (long_double)integer(y);
22403 	  if (fabs(pre_quo) > REMAINDER_FLOAT_LIMIT)
22404 	    return(simple_out_of_range(sc, sc->remainder_symbol, set_elist_2(sc, x, y), its_too_large_string));
22405 	  if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
22406 	  return(make_real(sc, real(x) - integer(y) * quo));
22407 	  /* but... (remainder 1e+18 9223372036854775807) -> 1e+18 */
22408 
22409 	case T_RATIO:
22410 	  if (s7_int_abs(numerator(y)) > QUOTIENT_INT_LIMIT)
22411 	    return(subtract_p_pp(sc, x, multiply_p_pp(sc, y, quotient_p_pp(sc, x, y))));
22412 	  {
22413 	    s7_double frac;
22414 	    frac = (s7_double)fraction(y);
22415 	    pre_quo = real(x) / frac;
22416 	    if (fabs(pre_quo) > REMAINDER_FLOAT_LIMIT)
22417 	      return(simple_out_of_range(sc, sc->remainder_symbol, set_elist_2(sc, x, y), its_too_large_string));
22418 	    if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
22419 	    return(make_real(sc, real(x) - frac * quo));
22420 	  }
22421 
22422 	case T_REAL:
22423 	  if (real(y) == 0.0)
22424 	    return(division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, x, y)));
22425 	  return(make_real(sc, c_rem_dbl(sc, real(x), real(y))));
22426 	  /* see under sin -- this calculation is completely bogus if "a" is large
22427 	   * (quotient 1e22 (* 2 pi)) -> -9223372036854775808 but it should be 1591549430918953357688,
22428 	   * (remainder 1e22 (* 2 pi)) -> 1.0057952155665e+22 -- the "remainder" is greater than the original argument!
22429 	   * Clisp gives 0.0 here, as does sbcl, currently s7 throws an error (out-of-range).
22430 	   */
22431 
22432 	default:
22433 	  return(method_or_bust_pp(sc, y, sc->remainder_symbol, x, y, T_REAL, 2));
22434 	}
22435 
22436     default:
22437       return(method_or_bust_pp(sc, x, sc->remainder_symbol, x, y, T_REAL, 1));
22438     }
22439 #endif
22440 }
22441 
22442 static s7_pointer g_remainder(s7_scheme *sc, s7_pointer args)
22443 {
22444   #define H_remainder "(remainder x1 x2) returns the remainder of x1/x2; (remainder 10 3) = 1"
22445   #define Q_remainder sc->pcl_r
22446   /* (define (rem x1 x2) (- x1 (* x2 (quo x1 x2)))) ; slib, if x2 is an integer (- x1 (truncate x1 x2)), fractional part: (remainder x 1) */
22447   s7_pointer x, y;
22448   x = car(args);
22449   y = cadr(args);
22450   if ((is_t_integer(x)) && (is_t_integer(y)))
22451     return(make_integer(sc, remainder_i_7ii(sc, integer(x), integer(y))));
22452   return(remainder_p_pp(sc, x, y));
22453 }
22454 
22455 
22456 /* -------------------------------- modulo -------------------------------- */
22457 
22458 static s7_int modulo_i_ii(s7_int x, s7_int y)
22459 {
22460   s7_int z;
22461   if (y > 1)
22462     {
22463       z = x % y;
22464       return((z >= 0) ? z : z + y);
22465     }
22466   if (y < -1)
22467     {
22468       z = x % y;
22469       return((z > 0) ? z + y : z);
22470     }
22471   if (y == 0) return(x);     /* else arithmetic exception */
22472   return(0);
22473 }
22474 
22475 static s7_int modulo_i_ii_unchecked(s7_int i1, s7_int i2) /* here we know i2 > 1 */
22476 {
22477   /* i2 > 1 */
22478   s7_int z;
22479   z = i1 % i2;
22480   return((z < 0) ? (z + i2) : z);
22481 }
22482 
22483 static s7_double modulo_d_7dd(s7_scheme *sc, s7_double x1, s7_double x2)
22484 {
22485   s7_double c;
22486   if ((is_NaN(x1)) || (is_NaN(x2)) || (is_inf(x1)) || (is_inf(x2))) return(NAN);
22487   if (x2 == 0.0) return(x1);
22488   if (fabs(x1) > 1e17)
22489     simple_out_of_range(sc, sc->modulo_symbol, wrap_real1(sc, x1), its_too_large_string);
22490   c = x1 / x2;
22491   if ((c > 1e19) || (c < -1e19))
22492     simple_out_of_range(sc, sc->modulo_symbol,
22493 			list_3(sc, sc->divide_symbol, wrap_real1(sc, x1), wrap_real2(sc, x2)),
22494 			wrap_string(sc, "intermediate (a/b) is too large", 31));
22495   return(x1 - x2 * (s7_int)floor(c));
22496 }
22497 
22498 static s7_pointer modulo_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
22499 {
22500 #if WITH_GMP
22501   /* as tricky as expt, so just use bignums; mpz_mod|_ui = mpz_fdiv_r_ui, but sign ignored -- probably not worth the code
22502    *   originally   subtract_p_pp(sc, x, multiply_p_pp(sc, y, floor_p_p(sc, divide_p_pp(sc, x, y))))
22503    *   quotient is                                            truncate_p_p(sc, divide_p_pp(sc, x, y))
22504    *   remainder is subtract_p_pp(sc, x, multiply_p_pp(sc, y, quotient_p_pp(sc, x, y)))
22505    */
22506   if (s7_is_zero(y))
22507     {
22508       if (s7_is_real(x))
22509 	return(x);
22510       return(method_or_bust_pp(sc, x, sc->modulo_symbol, x, y, T_REAL, 1));
22511     }
22512   return(big_mod_or_rem(sc, x, y, true));
22513 #else
22514   s7_double a, b;
22515   s7_int n1, n2, d1, d2;
22516 
22517   switch (type(x))
22518     {
22519     case T_INTEGER:
22520       switch (type(y))
22521 	{
22522 	case T_INTEGER:
22523 	  return(make_integer(sc, modulo_i_ii(integer(x), integer(y))));
22524 
22525 	case T_RATIO:
22526 	  n1 = integer(x);
22527 	  d1 = 1;
22528 	  n2 = numerator(y);
22529 	  d2 = denominator(y);
22530 	  if ((n1 == n2) && (d1 > d2)) return(x); /* signs match so this should be ok */
22531 	  goto RATIO_MOD_RATIO;
22532 
22533 	case T_REAL:
22534 	  if ((integer(x) == S7_INT64_MIN) || (s7_int_abs(integer(x)) > QUOTIENT_INT_LIMIT))
22535 	    return(simple_out_of_range(sc, sc->modulo_symbol, x, its_too_large_string));
22536 	  b = real(y);
22537 	  if (b == 0.0) return(x);
22538 	  if (is_NaN(b)) return(y);
22539 	  if (is_inf(b)) return(real_NaN);
22540 	  a = (s7_double)integer(x);
22541 	  goto REAL_MOD;
22542 
22543 	default:
22544 	  return(method_or_bust_pp(sc, y, sc->modulo_symbol, x, y, T_REAL, 2));
22545 	}
22546 
22547     case T_RATIO:
22548       switch (type(y))
22549 	{
22550 	case T_INTEGER:
22551 	  if (integer(y) == 0) return(x);
22552 	  n1 = numerator(x);
22553 	  d1 = denominator(x);
22554 	  n2 = integer(y);
22555 
22556 	  if ((n2 > 0) && (n1 > 0) && (n2 > n1)) return(x);
22557 	  if ((n2 < 0) && (n1 < 0) && (n2 < n1)) return(x);
22558 	  if (n2 == S7_INT64_MIN)
22559 	    return(simple_out_of_range(sc, sc->modulo_symbol,
22560 				       list_3(sc, sc->divide_symbol, x, y),
22561 				       wrap_string(sc, "intermediate (a/b) is too large", 31)));
22562 	  /* the problem here is that (modulo 3/2 most-negative-fixnum)
22563 	   * will segfault with signal SIGFPE, Arithmetic exception, so try to trap it.
22564 	   */
22565 	  if ((n1 == n2) && (d1 > 1)) return(x);
22566 	  d2 = 1;
22567 	  goto RATIO_MOD_RATIO;
22568 
22569 	case T_RATIO:
22570 	  parcel_out_fractions(x, y);
22571 	  if (d1 == d2)
22572 	    return(s7_make_ratio(sc, modulo_i_ii(n1, n2), d1));
22573 	  if ((n1 == n2) && (d1 > d2)) return(x);
22574 
22575 	RATIO_MOD_RATIO:
22576 #if HAVE_OVERFLOW_CHECKS
22577 	  {
22578 	    s7_int n2d1, n1d2, d1d2, fl;
22579 	    if (!multiply_overflow(n2, d1, &n2d1))
22580 	      {
22581 		if ((n2d1 == 1) || (n2d1 == -1)) /* (modulo 100 -1/2) */
22582 		  return(int_zero);
22583 
22584 		if (!multiply_overflow(n1, d2, &n1d2))
22585 		  {
22586 		    fl = (s7_int)(n1d2 / n2d1);
22587 		    if (((n1 < 0) && (n2 > 0)) ||
22588 			((n1 > 0) && (n2 < 0)))
22589 		      fl -= 1;
22590 		    if (fl == 0)
22591 		      return(x);
22592 
22593 		    if ((!multiply_overflow(d1, d2, &d1d2)) &&
22594 			(!multiply_overflow(fl, n2d1, &fl)) &&
22595 			(!subtract_overflow(n1d2, fl, &fl)))
22596 		      return(s7_make_ratio(sc, fl, d1d2));
22597 		  }}}
22598 #else
22599 	  {
22600 	    s7_int n1d2, n2d1, fl;
22601 	    n1d2 = n1 * d2;
22602 	    n2d1 = n2 * d1;
22603 
22604 	    if (n2d1 == 1)
22605 	      return(int_zero);
22606 
22607 	    /* can't use "floor" here (float->int ruins everything) */
22608 	    fl = (s7_int)(n1d2 / n2d1);
22609 	    if (((n1 < 0) && (n2 > 0)) ||
22610 		((n1 > 0) && (n2 < 0)))
22611 	      fl -= 1;
22612 
22613 	    if (fl == 0)
22614 	      return(x);
22615 
22616 	    return(s7_make_ratio(sc, n1d2 - (n2d1 * fl), d1 * d2));
22617 	  }
22618 #endif
22619 	  return(simple_out_of_range(sc, sc->modulo_symbol,
22620 				     list_3(sc, sc->divide_symbol, x, y),
22621 				     wrap_string(sc, "intermediate (a/b) is too large", 31)));
22622 
22623 	case T_REAL:
22624 	  b = real(y);
22625 	  if (is_inf(b)) return(real_NaN);
22626 	  if (fabs(b) > 1e17)
22627 	    return(simple_out_of_range(sc, sc->modulo_symbol, y, its_too_large_string));
22628 	  if (b == 0.0) return(x);
22629 	  if (is_NaN(b)) return(y);
22630 	  a = fraction(x);
22631 	  return(make_real(sc, a - b * (s7_int)floor(a / b)));
22632 
22633 	default:
22634 	  return(method_or_bust_pp(sc, y, sc->modulo_symbol, x, y, T_REAL, 2));
22635 	}
22636 
22637     case T_REAL:
22638       {
22639 	s7_double c;
22640 	a = real(x);
22641 	if (!is_real(y))
22642 	  return(method_or_bust_pp(sc, y, sc->modulo_symbol, x, y, T_REAL, 2));
22643 	if (is_NaN(a)) return(x);
22644 	if (is_inf(a)) return(real_NaN); /* not b */
22645 	if (fabs(a) > 1e17)
22646 	  return(simple_out_of_range(sc, sc->modulo_symbol, x, its_too_large_string));
22647 
22648 	switch (type(y))
22649 	  {
22650 	  case T_INTEGER:
22651 	    if (integer(y) == 0) return(x);
22652 	    if ((integer(y) == S7_INT64_MIN) || (s7_int_abs(integer(y)) > QUOTIENT_INT_LIMIT))
22653 	      return(simple_out_of_range(sc, sc->modulo_symbol, y, its_too_large_string));
22654 	    b = (s7_double)integer(y);
22655 	    goto REAL_MOD;
22656 
22657 	  case T_RATIO:
22658 	    b = fraction(y);
22659 	    goto REAL_MOD;
22660 
22661 	  case T_REAL:
22662 	    b = real(y);
22663 	    if (b == 0.0) return(x);
22664 	    if (is_NaN(b)) return(y);
22665 	    if (is_inf(b)) return(real_NaN);
22666 	  REAL_MOD:
22667 	    c = a / b;
22668 	    if (fabs(c) > 1e19)
22669 	      return(simple_out_of_range(sc, sc->modulo_symbol,
22670 					 list_3(sc, sc->divide_symbol, x, y),
22671 					 wrap_string(sc, "intermediate (a/b) is too large", 31)));
22672 	    return(make_real(sc, a - b * (s7_int)floor(c)));
22673 
22674 	  default:
22675 	    return(method_or_bust_pp(sc, y, sc->modulo_symbol, x, y, T_REAL, 2));
22676 	  }}
22677 
22678     default:
22679       return(method_or_bust_pp(sc, x, sc->modulo_symbol, x, y, T_REAL, 1));
22680     }
22681 #endif
22682 }
22683 
22684 static s7_pointer g_modulo(s7_scheme *sc, s7_pointer args)
22685 {
22686   #define H_modulo "(modulo x1 x2) returns x1 mod x2; (modulo 4 3) = 1.  The arguments can be real numbers."
22687   #define Q_modulo sc->pcl_r
22688   /* (define (mod x1 x2) (- x1 (* x2 (floor (/ x1 x2))))) from slib
22689    * (mod x 0) = x according to "Concrete Mathematics"
22690    */
22691   return(modulo_p_pp(sc, car(args), cadr(args)));
22692 }
22693 
22694 
22695 /* ---------------------------------------- max ---------------------------------------- */
22696 
22697 static bool is_real_via_method_1(s7_scheme *sc, s7_pointer p)
22698 {
22699   s7_pointer f;
22700   f = find_method_with_let(sc, p, sc->is_real_symbol);
22701   if (f != sc->undefined)
22702     return(is_true(sc, call_method(sc, p, f, set_plist_1(sc, p))));
22703   return(false);
22704 }
22705 
22706 #define is_real_via_method(sc, p) ((s7_is_real(p)) || ((has_active_methods(sc, p)) && (is_real_via_method_1(sc, p))))
22707 
22708 #define max_out_x(Sc, X, Y) method_or_bust_pp(Sc, X, Sc->max_symbol, X, Y, T_REAL, 1)
22709 #define max_out_y(Sc, X, Y) method_or_bust_pp(Sc, Y, Sc->max_symbol, X, Y, T_REAL, 2)
22710 
22711 static s7_pointer max_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
22712 {
22713   /* same basic code as lt_b_7_pp (or any relop) but max returns NaN if NaN encountered, and methods for < and max return
22714    *    different results, so it seems simpler to repeat the other code.
22715    */
22716   if (type(x) == type(y))
22717     {
22718       if (is_t_integer(x))
22719 	return((integer(x) < integer(y)) ? y : x);
22720       if (is_t_real(x))
22721 	return(((is_NaN(real(x))) || (real(x) >= real(y))) ? x : y);
22722       if (is_t_ratio(x))
22723 	return((fraction(x) < fraction(y)) ? y : x);
22724 #if WITH_GMP
22725       if (is_t_big_integer(x))
22726 	return((mpz_cmp(big_integer(x), big_integer(y)) < 0) ? y : x);
22727       if (is_t_big_ratio(x))
22728 	return((mpq_cmp(big_ratio(x), big_ratio(y)) < 0) ? y : x);
22729       if (is_t_big_real(x))
22730 	return(((mpfr_nan_p(big_real(x)) != 0) || (mpfr_greaterequal_p(big_real(x), big_real(y)))) ? x : y); /* ?? */
22731 #endif
22732     }
22733   switch (type(x))
22734     {
22735     case T_INTEGER:
22736       switch (type(y))
22737 	{
22738 	case T_RATIO:
22739 	  return((integer(x) < fraction(y)) ? y : x);
22740 	case T_REAL:
22741 	  if (is_NaN(real(y))) return(y);
22742 	  return((integer(x) < real(y)) ? y : x);
22743 #if WITH_GMP
22744 	case T_BIG_INTEGER:
22745 	  return((mpz_cmp_si(big_integer(y), integer(x)) < 0) ? x : y);
22746 	case T_BIG_RATIO:
22747 	  return((mpq_cmp_si(big_ratio(y), integer(x), 1) < 0) ? x : y);
22748 	case T_BIG_REAL:
22749 	  if (mpfr_nan_p(big_real(y))) return(y);
22750 	  return((mpfr_cmp_si(big_real(y), integer(x)) < 0) ? x : y);
22751 #endif
22752 	default:
22753 	  return(max_out_y(sc, x, y));
22754 	}
22755       break;
22756 
22757     case T_RATIO:
22758       switch (type(y))
22759 	{
22760 	case T_INTEGER:
22761 	  return((fraction(x) < integer(y)) ? y : x);
22762 	case T_REAL:
22763 	  if (is_NaN(real(y))) return(y);
22764 	  return((fraction(x) < real(y)) ? y : x);
22765 #if WITH_GMP
22766 	case T_BIG_INTEGER:
22767 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
22768 	  return((mpq_cmp_z(sc->mpq_1, big_integer(y)) < 0) ? y : x);
22769 	case T_BIG_RATIO:
22770 	  return((mpq_cmp_si(big_ratio(y), numerator(x), denominator(x)) < 0) ? x : y);
22771 	case T_BIG_REAL:
22772 	  if (mpfr_nan_p(big_real(y))) return(y);
22773 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
22774 	  return((mpfr_cmp_q(big_real(y), sc->mpq_1) < 0) ? x : y);
22775 #endif
22776 	default:
22777 	  return(max_out_y(sc, x, y));
22778 	}
22779 
22780     case T_REAL:
22781       switch (type(y))
22782 	{
22783 	case T_INTEGER:
22784 	  if (is_NaN(real(x))) return(x);
22785 	  return((real(x) < integer(y)) ? y : x);
22786 	case T_RATIO:
22787 	  return((real(x) < fraction(y)) ? y : x);
22788 #if WITH_GMP
22789 	case T_BIG_INTEGER:
22790 	  if (is_NaN(real(x))) return(x);
22791 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
22792 	  return((mpfr_cmp_z(sc->mpfr_1, big_integer(y)) < 0) ? y : x);
22793 
22794 	case T_BIG_RATIO:
22795 	  if (is_NaN(real(x))) return(x);
22796 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
22797 	  return((mpfr_cmp_q(sc->mpfr_1, big_ratio(y)) < 0) ? y : x);
22798 
22799 	case T_BIG_REAL:
22800 	  if (is_NaN(real(x))) return(x);
22801 	  if (mpfr_nan_p(big_real(y))) return(y);
22802 	  return((mpfr_cmp_d(big_real(y), real(x)) < 0) ? x : y);
22803 #endif
22804 	default:
22805 	  return(max_out_y(sc, x, y));
22806 	}
22807       break;
22808 
22809 #if WITH_GMP
22810     case T_BIG_INTEGER:
22811       switch (type(y))
22812 	{
22813 	case T_INTEGER:
22814 	  return((mpz_cmp_si(big_integer(x), integer(y)) < 0) ? y : x);
22815 	case T_RATIO:
22816 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
22817 	  return((mpq_cmp_z(sc->mpq_1, big_integer(x)) < 0) ? x : y);
22818 	case T_REAL:
22819 	  if (is_NaN(real(y))) return(y);
22820 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
22821 	  return((mpfr_cmp_d(sc->mpfr_1, real(y)) < 0) ? y : x);
22822 	case T_BIG_RATIO:
22823 	  return((mpq_cmp_z(big_ratio(y), big_integer(x)) < 0) ? x : y);
22824 	case T_BIG_REAL:
22825 	  if (mpfr_nan_p(big_real(y))) return(y);
22826 	  return((mpfr_cmp_z(big_real(y), big_integer(x)) < 0) ? x : y);
22827 	default:
22828 	  return(max_out_y(sc, x, y));
22829 	}
22830     case T_BIG_RATIO:
22831       switch (type(y))
22832 	{
22833 	case T_INTEGER:
22834 	  return((mpq_cmp_si(big_ratio(x), integer(y), 1) < 0) ? y : x);
22835 	case T_RATIO:
22836 	  return((mpq_cmp_si(big_ratio(x), numerator(y), denominator(y)) < 0) ? y : x);
22837 	case T_REAL:
22838 	  if (is_NaN(real(y))) return(y);
22839 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
22840 	  return((mpfr_cmp_d(sc->mpfr_1, real(y)) < 0) ? y : x);
22841 	case T_BIG_INTEGER:
22842 	  return((mpq_cmp_z(big_ratio(x), big_integer(y)) < 0) ? y : x);
22843 	case T_BIG_REAL:
22844 	  if (mpfr_nan_p(big_real(y))) return(y);
22845 	  return((mpfr_cmp_q(big_real(y), big_ratio(x)) < 0) ? x : y);
22846 	default:
22847 	  return(max_out_y(sc, x, y));
22848 	}
22849 
22850     case T_BIG_REAL:
22851       switch (type(y))
22852 	{
22853 	case T_INTEGER:
22854 	  if (mpfr_nan_p(big_real(x))) return(x);
22855 	  return((mpfr_cmp_si(big_real(x), integer(y)) < 0) ? y : x);
22856 	case T_RATIO:
22857 	  if (mpfr_nan_p(big_real(x))) return(x);
22858 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
22859 	  return((mpfr_cmp_q(big_real(x), sc->mpq_1) < 0) ? y : x);
22860 	case T_REAL:
22861 	  if (mpfr_nan_p(big_real(x))) return(x);
22862 	  if (is_NaN(real(y))) return(y);
22863 	  return((mpfr_cmp_d(big_real(x), real(y)) < 0) ? y : x);
22864 	case T_BIG_INTEGER:
22865 	  if (mpfr_nan_p(big_real(x))) return(x);
22866 	  return((mpfr_cmp_z(big_real(x), big_integer(y)) < 0) ? y : x);
22867 	case T_BIG_RATIO:
22868 	  if (mpfr_nan_p(big_real(x))) return(x);
22869 	  return((mpfr_cmp_q(big_real(x), big_ratio(y)) < 0) ? y : x);
22870 	default:
22871 	  return(max_out_y(sc, x, y));
22872 	}
22873 #endif
22874 
22875     default:
22876       return(max_out_x(sc, x, y));
22877     }
22878   return(x);
22879 }
22880 
22881 static s7_pointer g_max(s7_scheme *sc, s7_pointer args)
22882 {
22883   #define H_max "(max ...) returns the maximum of its arguments"
22884   #define Q_max sc->pcl_r
22885 
22886   s7_pointer x, p;
22887   x = car(args);
22888   if (is_null(cdr(args)))
22889     {
22890       if (s7_is_real(x)) return(x);
22891       return(method_or_bust_p(sc, x, sc->max_symbol, T_REAL));
22892     }
22893   for (p = cdr(args); is_pair(p); p = cdr(p))
22894     x = max_p_pp(sc, x, car(p));
22895   return(x);
22896 }
22897 
22898 static s7_int max_i_ii(s7_int i1, s7_int i2) {return((i1 > i2) ? i1 : i2);}
22899 static s7_int max_i_iii(s7_int i1, s7_int i2, s7_int i3) {return((i1 > i2) ? ((i1 > i3) ? i1 : i3) : ((i2 > i3) ? i2 : i3));}
22900 static s7_double max_d_dd(s7_double x1, s7_double x2) {if (is_NaN(x1)) return(x1); return((x1 > x2) ? x1 : x2);}
22901 static s7_double max_d_ddd(s7_double x1, s7_double x2, s7_double x3) {return(max_d_dd(x1, max_d_dd(x2, x3)));}
22902 static s7_double max_d_dddd(s7_double x1, s7_double x2, s7_double x3, s7_double x4) {return(max_d_dd(x1, max_d_ddd(x2, x3, x4)));}
22903 
22904 
22905 /* ---------------------------------------- min ---------------------------------------- */
22906 
22907 #define min_out_x(Sc, X, Y) method_or_bust_pp(Sc, X, Sc->min_symbol, X, Y, T_REAL, 1)
22908 #define min_out_y(Sc, X, Y) method_or_bust_pp(Sc, Y, Sc->min_symbol, X, Y, T_REAL, 2)
22909 
22910 static s7_pointer min_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
22911 {
22912   if (type(x) == type(y))
22913     {
22914       if (is_t_integer(x))
22915 	return((integer(x) > integer(y)) ? y : x);
22916       if (is_t_real(x))
22917 	return(((is_NaN(real(x))) || (real(x) <= real(y))) ? x : y);
22918       if (is_t_ratio(x))
22919 	return((fraction(x) > fraction(y)) ? y : x);
22920 #if WITH_GMP
22921       if (is_t_big_integer(x))
22922 	return((mpz_cmp(big_integer(x), big_integer(y)) > 0) ? y : x);
22923       if (is_t_big_ratio(x))
22924 	return((mpq_cmp(big_ratio(x), big_ratio(y)) > 0) ? y : x);
22925       if (is_t_big_real(x))
22926 	return(((mpfr_nan_p(big_real(x)) != 0) || (mpfr_lessequal_p(big_real(x), big_real(y)))) ? x : y); /* ?? */
22927 #endif
22928     }
22929   switch (type(x))
22930     {
22931     case T_INTEGER:
22932       switch (type(y))
22933 	{
22934 	case T_RATIO:       return((integer(x) > fraction(y)) ? y : x);
22935 	case T_REAL:
22936 	  if (is_NaN(real(y))) return(y);
22937 	  return((integer(x) > real(y)) ? y : x);
22938 #if WITH_GMP
22939 	case T_BIG_INTEGER: return((mpz_cmp_si(big_integer(y), integer(x)) > 0) ? x : y);
22940 	case T_BIG_RATIO:   return((mpq_cmp_si(big_ratio(y), integer(x), 1) > 0) ? x : y);
22941 	case T_BIG_REAL:
22942 	  if (mpfr_nan_p(big_real(y))) return(y);
22943 	  return((mpfr_cmp_si(big_real(y), integer(x)) > 0) ? x : y);
22944 #endif
22945 	default:
22946 	  return(min_out_y(sc, x, y));
22947 	}
22948       break;
22949 
22950     case T_RATIO:
22951       switch (type(y))
22952 	{
22953 	case T_INTEGER:
22954 	  return((fraction(x) > integer(y)) ? y : x);
22955 	case T_REAL:
22956 	  if (is_NaN(real(y))) return(y);
22957 	  return((fraction(x) > real(y)) ? y : x);
22958 #if WITH_GMP
22959 	case T_BIG_INTEGER:
22960 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
22961 	  return((mpq_cmp_z(sc->mpq_1, big_integer(y)) > 0) ? y : x);
22962 	case T_BIG_RATIO:
22963 	  return((mpq_cmp_si(big_ratio(y), numerator(x), denominator(x)) > 0) ? x : y);
22964 	case T_BIG_REAL:
22965 	  if (mpfr_nan_p(big_real(y))) return(y);
22966 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
22967 	  return((mpfr_cmp_q(big_real(y), sc->mpq_1) > 0) ? x : y);
22968 #endif
22969 	default:
22970 	  return(min_out_y(sc, x, y));
22971 	}
22972 
22973     case T_REAL:
22974       switch (type(y))
22975 	{
22976 	case T_INTEGER:
22977 	  if (is_NaN(real(x))) return(x);
22978 	  return((real(x) > integer(y)) ? y : x);
22979 	case T_RATIO:
22980 	  return((real(x) > fraction(y)) ? y : x);
22981 #if WITH_GMP
22982 	case T_BIG_INTEGER:
22983 	  if (is_NaN(real(x))) return(x);
22984 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
22985 	  return((mpfr_cmp_z(sc->mpfr_1, big_integer(y)) > 0) ? y : x);
22986 
22987 	case T_BIG_RATIO:
22988 	  if (is_NaN(real(x))) return(x);
22989 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
22990 	  return((mpfr_cmp_q(sc->mpfr_1, big_ratio(y)) > 0) ? y : x);
22991 
22992 	case T_BIG_REAL:
22993 	  if (is_NaN(real(x))) return(x);
22994 	  if (mpfr_nan_p(big_real(y))) return(y);
22995 	  return((mpfr_cmp_d(big_real(y), real(x)) > 0) ? x : y);
22996 #endif
22997 	default:
22998 	  return(min_out_y(sc, x, y));
22999 	}
23000       break;
23001 
23002 #if WITH_GMP
23003     case T_BIG_INTEGER:
23004       switch (type(y))
23005 	{
23006 	case T_INTEGER:
23007 	  return((mpz_cmp_si(big_integer(x), integer(y)) > 0) ? y : x);
23008 	case T_RATIO:
23009 	  mpq_set_z(sc->mpq_1, big_integer(x));
23010 	  return((mpq_cmp_si(sc->mpq_1, numerator(y), denominator(y)) > 0) ? y : x);
23011 	case T_REAL:
23012 	  if (is_NaN(real(y))) return(y);
23013 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
23014 	  return((mpfr_cmp_d(sc->mpfr_1, real(y)) > 0) ? y : x);
23015 	case T_BIG_RATIO:
23016 	  return((mpq_cmp_z(big_ratio(y), big_integer(x)) > 0) ? x : y);
23017 	case T_BIG_REAL:
23018 	  if (mpfr_nan_p(big_real(y))) return(y);
23019 	  return((mpfr_cmp_z(big_real(y), big_integer(x)) > 0) ? x : y);
23020 	default:
23021 	  return(min_out_y(sc, x, y));
23022 	}
23023     case T_BIG_RATIO:
23024       switch (type(y))
23025 	{
23026 	case T_INTEGER:
23027 	  return((mpq_cmp_si(big_ratio(x), integer(y), 1) > 0) ? y : x);
23028 	case T_RATIO:
23029 	  return((mpq_cmp_si(big_ratio(x), numerator(y), denominator(y)) > 0) ? y : x);
23030 	case T_REAL:
23031 	  if (is_NaN(real(y))) return(y);
23032 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
23033 	  return((mpfr_cmp_d(sc->mpfr_1, real(y)) > 0) ? y : x);
23034 	case T_BIG_INTEGER:
23035 	  return((mpq_cmp_z(big_ratio(x), big_integer(y)) > 0) ? y : x);
23036 	case T_BIG_REAL:
23037 	  if (mpfr_nan_p(big_real(y))) return(y);
23038 	  return((mpfr_cmp_q(big_real(y), big_ratio(x)) > 0) ? x : y);
23039 	default:
23040 	  return(min_out_y(sc, x, y));
23041 	}
23042 
23043     case T_BIG_REAL:
23044       switch (type(y))
23045 	{
23046 	case T_INTEGER:
23047 	  if (mpfr_nan_p(big_real(x))) return(x);
23048 	  return((mpfr_cmp_si(big_real(x), integer(y)) > 0) ? y : x);
23049 	case T_RATIO:
23050 	  if (mpfr_nan_p(big_real(x))) return(x);
23051 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
23052 	  return((mpfr_cmp_q(big_real(x), sc->mpq_1) > 0) ? y : x);
23053 	case T_REAL:
23054 	  if (mpfr_nan_p(big_real(x))) return(x);
23055 	  if (is_NaN(real(y))) return(y);
23056 	  return((mpfr_cmp_d(big_real(x), real(y)) > 0) ? y : x);
23057 	case T_BIG_INTEGER:
23058 	  if (mpfr_nan_p(big_real(x))) return(x);
23059 	  return((mpfr_cmp_z(big_real(x), big_integer(y)) > 0) ? y : x);
23060 	case T_BIG_RATIO:
23061 	  if (mpfr_nan_p(big_real(x))) return(x);
23062 	  return((mpfr_cmp_q(big_real(x), big_ratio(y)) > 0) ? y : x);
23063 	default:
23064 	  return(min_out_y(sc, x, y));
23065 	}
23066 #endif
23067 
23068     default:
23069       return(min_out_x(sc, x, y));
23070     }
23071   return(x);
23072 }
23073 
23074 static s7_pointer g_min(s7_scheme *sc, s7_pointer args)
23075 {
23076   #define H_min "(min ...) returns the minimum of its arguments"
23077   #define Q_min sc->pcl_r
23078 
23079   s7_pointer x, p;
23080   x = car(args);
23081   if (is_null(cdr(args)))
23082     {
23083       if (s7_is_real(x)) return(x);
23084       return(method_or_bust_p(sc, x, sc->min_symbol, T_REAL));
23085     }
23086   for (p = cdr(args); is_pair(p); p = cdr(p))
23087     x = min_p_pp(sc, x, car(p));
23088   return(x);
23089 }
23090 
23091 static s7_int min_i_ii(s7_int i1, s7_int i2) {return((i1 < i2) ? i1 : i2);}
23092 static s7_int min_i_iii(s7_int i1, s7_int i2, s7_int i3) {return((i1 < i2) ? ((i1 < i3) ? i1 : i3) : ((i2 < i3) ? i2 : i3));}
23093 static s7_double min_d_dd(s7_double x1, s7_double x2) {if (is_NaN(x1)) return(x1); return((x1 < x2) ? x1 : x2);}
23094 static s7_double min_d_ddd(s7_double x1, s7_double x2, s7_double x3) {return(min_d_dd(x1, min_d_dd(x2, x3)));}
23095 static s7_double min_d_dddd(s7_double x1, s7_double x2, s7_double x3, s7_double x4) {return(min_d_dd(x1, min_d_ddd(x2, x3, x4)));}
23096 
23097 
23098 /* ---------------------------------------- = ---------------------------------------- */
23099 
23100 static bool eq_out_x(s7_scheme *sc, s7_pointer x, s7_pointer y)
23101 {
23102   if (has_active_methods(sc, x))
23103     return(find_and_apply_method(sc, x, sc->num_eq_symbol, set_plist_2(sc, x, y)) != sc->F);
23104   wrong_type_argument_with_type(sc, sc->num_eq_symbol, 1, x, a_number_string);
23105   return(false);
23106 }
23107 
23108 static bool eq_out_y(s7_scheme *sc, s7_pointer x, s7_pointer y)
23109 {
23110   if (has_active_methods(sc, y))
23111     return(find_and_apply_method(sc, y, sc->num_eq_symbol, set_plist_2(sc, x, y)) != sc->F);
23112   wrong_type_argument_with_type(sc, sc->num_eq_symbol, 2, y, a_number_string);
23113   return(false);
23114 }
23115 
23116 static bool num_eq_b_7pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
23117 {
23118   if (type(x) == type(y))
23119     {
23120       if (is_t_integer(x))
23121 	return(integer(x) == integer(y));
23122       if (is_t_real(x))
23123 	return(real(x) == real(y));
23124       if (is_t_complex(x))
23125 	return((real_part(x) == real_part(y)) && (imag_part(x) == imag_part(y)));
23126       if (is_t_ratio(x))
23127 	return((numerator(x) == numerator(y)) && (denominator(x) == denominator(y)));
23128 #if WITH_GMP
23129       if (is_t_big_integer(x))
23130 	return(mpz_cmp(big_integer(x), big_integer(y)) == 0);
23131       if (is_t_big_ratio(x))
23132 	return(mpq_equal(big_ratio(x), big_ratio(y)));
23133       if (is_t_big_real(x))
23134 	return(mpfr_equal_p(big_real(x), big_real(y)));
23135       if (is_t_big_complex(x)) /* mpc_cmp can't handle NaN */
23136 	{
23137 	  if ((mpfr_nan_p(mpc_realref(big_complex(x)))) || (mpfr_nan_p(mpc_imagref(big_complex(x)))) ||
23138 	      (mpfr_nan_p(mpc_realref(big_complex(y)))) || (mpfr_nan_p(mpc_imagref(big_complex(y)))))
23139 	    return(false);
23140 	  return(mpc_cmp(big_complex(x), big_complex(y)) == 0);
23141 	}
23142 #endif
23143     }
23144 
23145   switch (type(x))
23146     {
23147     case T_INTEGER:
23148       switch (type(y))
23149 	{
23150 	case T_RATIO:
23151 	  return(false);
23152 	case T_REAL:
23153 #if WITH_GMP
23154 	  if (s7_int_abs(integer(x)) >= INT64_TO_DOUBLE_LIMIT)
23155 	    {
23156 	      if (is_NaN(real(y))) return(false);
23157 	      mpfr_set_d(sc->mpfr_1, real(y), MPFR_RNDN);
23158 	      return(mpfr_cmp_si(sc->mpfr_1, integer(x)) == 0);
23159 	    }
23160 #endif
23161 	  return(integer(x) == real(y));
23162 	case T_COMPLEX:
23163 	  return(false);
23164 #if WITH_GMP
23165 	case T_BIG_INTEGER:
23166 	  return((mpz_fits_slong_p(big_integer(y))) && (integer(x) == mpz_get_si(big_integer(y))));
23167 	case T_BIG_RATIO:
23168 	  return(false);
23169 	case T_BIG_REAL:
23170 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_si(big_real(y), integer(x)) == 0));
23171 	case T_BIG_COMPLEX:
23172 	  return(false);
23173 #endif
23174 	default: return(eq_out_y(sc, x, y));
23175 	}
23176       break;
23177 
23178     case T_RATIO:
23179       switch (type(y))
23180 	{
23181 	case T_INTEGER: return(false);
23182 	case T_REAL:    return(fraction(x) == real(y));
23183 	case T_COMPLEX: return(false);
23184 #if WITH_GMP
23185 	case T_BIG_INTEGER:
23186 	  return(false);
23187 	case T_BIG_RATIO:
23188 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
23189 	  return(mpq_equal(sc->mpq_1, big_ratio(y)));
23190 	case T_BIG_REAL:
23191 	  if (mpfr_nan_p(big_real(y))) return(false);
23192 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
23193 	  return(mpfr_cmp_q(big_real(y), sc->mpq_1) == 0);
23194 	case T_BIG_COMPLEX:
23195 	  return(false);
23196 #endif
23197 	default: return(eq_out_y(sc, x, y));
23198 	}
23199       break;
23200 
23201     case T_REAL:
23202       switch (type(y))
23203 	{
23204 	case T_INTEGER:
23205 	  return(real(x) == integer(y));
23206 	case T_RATIO:
23207 	  return(real(x) == fraction(y));
23208 	case T_COMPLEX:
23209 	  return(false);
23210 #if WITH_GMP
23211 	case T_BIG_INTEGER:
23212 	  if (is_NaN(real(x))) return(false);
23213 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
23214 	  return(mpfr_cmp_z(sc->mpfr_1, big_integer(y)) == 0);
23215 	case T_BIG_RATIO:
23216 	  if (is_NaN(real(x))) return(false);
23217 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
23218 	  return(mpfr_cmp_q(sc->mpfr_1, big_ratio(y)) == 0);
23219 	case T_BIG_REAL:
23220 	  if (is_NaN(real(x))) return(false);
23221 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_d(big_real(y), real(x)) == 0));
23222 	case T_BIG_COMPLEX:
23223 	  return(false);
23224 #endif
23225 	default: return(eq_out_y(sc, x, y));
23226 	}
23227       break;
23228 
23229     case T_COMPLEX:
23230       if (is_real(y)) return(false);
23231 #if WITH_GMP
23232       if (is_t_big_complex(y))
23233 	{
23234 	  if ((is_NaN(real_part(x))) || (is_NaN(imag_part(x))) ||
23235 	      (mpfr_nan_p(mpc_realref(big_complex(y)))) || (mpfr_nan_p(mpc_imagref(big_complex(y)))))
23236 	    return(false);
23237 	  mpc_set_d_d(sc->mpc_1, real_part(x), imag_part(x), MPC_RNDNN);
23238 	  return(mpc_cmp(big_complex(y), sc->mpc_1) == 0);
23239 	}
23240 #endif
23241       return(eq_out_y(sc, x, y));
23242 
23243 #if WITH_GMP
23244     case T_BIG_INTEGER:
23245       switch (type(y))
23246 	{
23247 	case T_INTEGER:
23248 	  return((mpz_fits_slong_p(big_integer(x))) && (integer(y) == mpz_get_si(big_integer(x))));
23249 	case T_REAL:
23250 	  if (is_NaN(real(y))) return(false);
23251 	  mpfr_set_d(sc->mpfr_1, real(y), MPFR_RNDN);
23252 	  return(mpfr_cmp_z(sc->mpfr_1, big_integer(x)) == 0);
23253 	case T_RATIO: case T_COMPLEX: case T_BIG_RATIO: case T_BIG_COMPLEX:
23254 	  return(false);
23255 	case T_BIG_REAL:
23256 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_z(big_real(y), big_integer(x)) == 0));
23257 	default: return(eq_out_y(sc, x, y));
23258 	}
23259     case T_BIG_RATIO:
23260       switch (type(y))
23261 	{
23262 	case T_RATIO:
23263 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
23264 	  return(mpq_equal(sc->mpq_1, big_ratio(x)));
23265 	case T_REAL:
23266 	  if (is_NaN(real(y))) return(false);
23267 	  mpfr_set_d(sc->mpfr_1, real(y), MPFR_RNDN);
23268 	  return(mpfr_cmp_q(sc->mpfr_1, big_ratio(x)) == 0);
23269 	case T_INTEGER: case T_BIG_INTEGER: case T_COMPLEX: case T_BIG_COMPLEX:
23270 	  return(false);
23271 	case T_BIG_REAL:
23272 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_q(big_real(y), big_ratio(x)) == 0));
23273 	default: return(eq_out_y(sc, x, y));
23274 	}
23275 
23276     case T_BIG_REAL:
23277       if ((is_number(y)) && (mpfr_nan_p(big_real(x)))) return(false);
23278       switch (type(y))
23279 	{
23280 	case T_INTEGER:
23281 	  return(mpfr_cmp_si(big_real(x), integer(y)) == 0);
23282 	case T_RATIO:
23283 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
23284 	  return(mpfr_cmp_q(big_real(x), sc->mpq_1) == 0);
23285 	case T_REAL:
23286 	  return((!is_NaN(real(y))) && (mpfr_cmp_d(big_real(x), real(y)) == 0));
23287 	case T_BIG_INTEGER:
23288 	  return(mpfr_cmp_z(big_real(x), big_integer(y)) == 0);
23289 	case T_BIG_RATIO:
23290 	  return(mpfr_cmp_q(big_real(x), big_ratio(y)) == 0);
23291 	case T_COMPLEX: case T_BIG_COMPLEX:
23292 	  return(false);
23293 	default: return(eq_out_y(sc, x, y));
23294 	}
23295 
23296     case T_BIG_COMPLEX:
23297       switch (type(y))
23298 	{
23299 	case T_RATIO: case T_REAL: case T_INTEGER: case T_BIG_INTEGER: case T_BIG_RATIO: case T_BIG_REAL:
23300 	  return(false);
23301 	case T_COMPLEX:
23302 	  if ((is_NaN(real_part(y))) || (is_NaN(imag_part(y))) ||
23303 	      (mpfr_nan_p(mpc_realref(big_complex(x)))) || (mpfr_nan_p(mpc_imagref(big_complex(x)))))
23304 	    return(false);
23305 	  mpc_set_d_d(sc->mpc_1, real_part(y), imag_part(y), MPC_RNDNN);
23306 	  return(mpc_cmp(big_complex(x), sc->mpc_1) == 0); /* NaN's not allowed! */
23307 	default: return(eq_out_y(sc, x, y));
23308 	}
23309 #endif
23310 
23311     default: return(eq_out_x(sc, x, y));
23312     }
23313   return(false);
23314 }
23315 
23316 static bool is_number_via_method(s7_scheme *sc, s7_pointer p)
23317 {
23318   if (s7_is_number(p))
23319     return(true);
23320   if (has_active_methods(sc, p))
23321     {
23322       s7_pointer f;
23323       f = find_method_with_let(sc, p, sc->is_number_symbol);
23324       if (f != sc->undefined)
23325 	return(is_true(sc, call_method(sc, p, f, set_plist_1(sc, p))));
23326     }
23327   return(false);
23328 }
23329 
23330 static s7_pointer g_num_eq(s7_scheme *sc, s7_pointer args)
23331 {
23332   #define H_num_eq "(= z1 ...) returns #t if all its arguments are equal"
23333   #define Q_num_eq s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_number_symbol)
23334 
23335   s7_pointer x, p;
23336   x = car(args);
23337   p = cdr(args);
23338 
23339   if (is_null(cdr(p)))
23340     return(make_boolean(sc, num_eq_b_7pp(sc, x, car(p))));
23341 
23342   for (; is_pair(p); p = cdr(p))
23343     if (!num_eq_b_7pp(sc, x, car(p)))
23344       {
23345 	for (p = cdr(p); is_pair(p); p = cdr(p))
23346 	  if (!is_number_via_method(sc, car(p)))
23347 	    return(wrong_type_argument_with_type(sc, sc->num_eq_symbol, position_of(p, args), car(p), a_number_string));
23348 	return(sc->F);
23349       }
23350   return(sc->T);
23351 }
23352 
23353 static bool num_eq_b_ii(s7_int i1, s7_int i2) {return(i1 == i2);}
23354 static bool num_eq_b_dd(s7_double i1, s7_double i2) {return(i1 == i2);}
23355 
23356 static s7_pointer num_eq_p_dd(s7_scheme *sc, s7_double x1, s7_double x2) {return(make_boolean(sc, x1 == x2));}
23357 static s7_pointer num_eq_p_ii(s7_scheme *sc, s7_int x1, s7_int x2)       {return(make_boolean(sc, x1 == x2));}
23358 static s7_pointer num_eq_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(make_boolean(sc, num_eq_b_7pp(sc, x, y)));}
23359 
23360 static s7_pointer num_eq_p_pi(s7_scheme *sc, s7_pointer p1, s7_int p2)
23361 {
23362   if (is_t_integer(p1))
23363     return((integer(p1) == p2) ? sc->T : sc->F);
23364   if (is_t_real(p1))
23365     return((real(p1) == p2) ? sc->T : sc->F);
23366 #if WITH_GMP
23367   if (is_t_big_integer(p1))
23368     return(((mpz_fits_slong_p(big_integer(p1))) && (p2 == mpz_get_si(big_integer(p1)))) ? sc->T : sc->F);
23369   if (is_t_big_real(p1))
23370     return((mpfr_cmp_si(big_real(p1), p2) == 0) ? sc->T : sc->F);
23371 #endif
23372   return((is_number(p1)) ? sc->F : make_boolean(sc, eq_out_x(sc, p1, make_integer(sc, p2))));
23373 }
23374 
23375 static bool num_eq_b_pi(s7_scheme *sc, s7_pointer x, s7_int y)
23376 {
23377   if (is_t_integer(x))
23378     return(integer(x) == y);
23379   if (is_t_real(x))
23380     return(real(x) == y);
23381 #if WITH_GMP
23382   if (is_t_big_integer(x))
23383     return((mpz_fits_slong_p(big_integer(x))) && (y == mpz_get_si(big_integer(x))));
23384   if (is_t_big_real(x))
23385     return(mpfr_cmp_si(big_real(x), y) == 0);
23386 #endif
23387   if (!is_number(x)) /* complex/ratio */
23388     simple_wrong_type_argument_with_type(sc, sc->num_eq_symbol, x, a_number_string);
23389   return(false);
23390 }
23391 
23392 static s7_pointer g_num_eq_2(s7_scheme *sc, s7_pointer args)
23393 {
23394   s7_pointer x, y;
23395   x = car(args);
23396   y = cadr(args);
23397   if ((is_t_integer(x)) && (is_t_integer(y))) /* this is by far the most common case (ratios aren't used much, and = with floats is frowned upon) */
23398     return(make_boolean(sc, integer(x) == integer(y)));
23399   return(make_boolean(sc, num_eq_b_7pp(sc, x, y)));
23400 }
23401 
23402 static inline s7_pointer num_eq_xx(s7_scheme *sc, s7_pointer x, s7_pointer y)
23403 {
23404   if (is_t_integer(x))
23405     return(make_boolean(sc, integer(x) == integer(y)));
23406   if (is_t_real(x))
23407     return((is_NaN(real(x))) ? sc->F : make_boolean(sc, real(x) == integer(y)));
23408   if (!is_number(x))
23409     return(make_boolean(sc, eq_out_x(sc, x, y)));
23410 #if WITH_GMP
23411   if (is_t_big_integer(x))
23412     return(make_boolean(sc, mpz_cmp_si(big_integer(x), integer(y)) == 0));
23413   if (is_t_big_real(x))
23414     {
23415       if (mpfr_nan_p(big_real(x))) return(sc->F);
23416       return(make_boolean(sc, mpfr_cmp_si(big_real(x), integer(y)) == 0));
23417     }
23418   if (is_t_big_ratio(x))
23419     return(make_boolean(sc, mpq_cmp_si(big_ratio(x), integer(y), 1) == 0));
23420 #endif
23421   return(sc->F);
23422 }
23423 
23424 static s7_pointer g_num_eq_xi(s7_scheme *sc, s7_pointer args) {return(num_eq_xx(sc, car(args), cadr(args)));}
23425 static s7_pointer g_num_eq_ix(s7_scheme *sc, s7_pointer args) {return(num_eq_xx(sc, cadr(args), car(args)));}
23426 
23427 static s7_pointer num_eq_chooser(s7_scheme *sc, s7_pointer ur_f, int32_t args, s7_pointer expr, bool ops)
23428 {
23429   if (args == 2)
23430     {
23431       if ((ops) && (is_t_integer(caddr(expr))))
23432 	return(sc->num_eq_xi);
23433       return(((ops) && (is_t_integer(cadr(expr)))) ? sc->num_eq_ix : sc->num_eq_2);
23434     }
23435   return(ur_f);
23436 }
23437 
23438 
23439 /* ---------------------------------------- < ---------------------------------------- */
23440 
23441 static bool lt_out_x(s7_scheme *sc, s7_pointer x, s7_pointer y)
23442 {
23443   if (has_active_methods(sc, x))
23444     return(find_and_apply_method(sc, x, sc->lt_symbol, set_plist_2(sc, x, y)) != sc->F);
23445   wrong_type_argument(sc, sc->lt_symbol, 1, x, T_REAL);
23446   return(false);
23447 }
23448 
23449 static bool lt_out_y(s7_scheme *sc, s7_pointer x, s7_pointer y)
23450 {
23451   if (has_active_methods(sc, y))
23452     return(find_and_apply_method(sc, y, sc->lt_symbol, set_plist_2(sc, x, y)) != sc->F);
23453   wrong_type_argument(sc, sc->lt_symbol, 2, y, T_REAL);
23454   return(false);
23455 }
23456 
23457 static bool lt_b_7pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
23458 {
23459   if (type(x) == type(y))
23460     {
23461       if (is_t_integer(x))
23462 	return(integer(x) < integer(y));
23463       if (is_t_real(x))
23464 	return(real(x) < real(y));
23465       if (is_t_ratio(x))
23466 	return(fraction(x) < fraction(y));
23467 #if WITH_GMP
23468       if (is_t_big_integer(x))
23469 	return(mpz_cmp(big_integer(x), big_integer(y)) < 0);
23470       if (is_t_big_ratio(x))
23471 	return(mpq_cmp(big_ratio(x), big_ratio(y)) < 0);
23472       if (is_t_big_real(x))
23473 	return(mpfr_less_p(big_real(x), big_real(y)));
23474 #endif
23475     }
23476   switch (type(x))
23477     {
23478     case T_INTEGER:
23479       switch (type(y))
23480 	{
23481 	case T_RATIO:	return(integer(x) < fraction(y)); /* ?? */
23482 	case T_REAL:	return(integer(x) < real(y));
23483 #if WITH_GMP
23484 	case T_BIG_INTEGER: return(mpz_cmp_si(big_integer(y), integer(x)) > 0);
23485 	case T_BIG_RATIO:   return(mpq_cmp_si(big_ratio(y), integer(x), 1) > 0);
23486 	case T_BIG_REAL:    return(mpfr_cmp_si(big_real(y), integer(x)) > 0);
23487 #endif
23488 	default: return(lt_out_y(sc, x, y));
23489 	}
23490       break;
23491 
23492     case T_RATIO:
23493       switch (type(y))
23494 	{
23495 	case T_INTEGER: return(fraction(x) < integer(y));
23496 	case T_REAL:    return(fraction(x) < real(y));
23497 #if WITH_GMP
23498 	case T_BIG_INTEGER:
23499 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
23500 	  return(mpq_cmp_z(sc->mpq_1, big_integer(y)) < 0);
23501 	case T_BIG_RATIO:
23502 	  return(mpq_cmp_si(big_ratio(y), numerator(x), denominator(x)) > 0);
23503 	case T_BIG_REAL:
23504 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
23505 	  return(mpfr_cmp_q(big_real(y), sc->mpq_1) > 0);
23506 #endif
23507 	default: return(lt_out_y(sc, x, y));
23508 	}
23509 
23510     case T_REAL:
23511       switch (type(y))
23512 	{
23513 	case T_INTEGER: return(real(x) < integer(y));
23514 	case T_RATIO:	return(real(x) < fraction(y));
23515 #if WITH_GMP
23516 	case T_BIG_INTEGER:
23517 	  if (is_NaN(real(x))) return(false);
23518 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
23519 	  return(mpfr_cmp_z(sc->mpfr_1, big_integer(y)) < 0);
23520 
23521 	case T_BIG_RATIO:
23522 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
23523 	  return(mpfr_cmp_q(sc->mpfr_1, big_ratio(y)) < 0);
23524 
23525 	case T_BIG_REAL:
23526 	  return(mpfr_cmp_d(big_real(y), real(x)) > 0);
23527 #endif
23528 	default: return(lt_out_y(sc, x, y));
23529 	}
23530       break;
23531 
23532 #if WITH_GMP
23533     case T_BIG_INTEGER:
23534       switch (type(y))
23535 	{
23536 	case T_INTEGER:
23537 	  return(mpz_cmp_si(big_integer(x), integer(y)) < 0);
23538 	case T_RATIO:
23539 	  mpq_set_z(sc->mpq_1, big_integer(x));
23540 	  return(mpq_cmp_si(sc->mpq_1, numerator(y), denominator(y)) < 0);
23541 	case T_REAL:
23542 	  if (is_NaN(real(y))) return(false);
23543 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
23544 	  return(mpfr_cmp_d(sc->mpfr_1, real(y)) < 0);
23545 	case T_BIG_RATIO:
23546 	  return(mpq_cmp_z(big_ratio(y), big_integer(x)) > 0);
23547 	case T_BIG_REAL:
23548 	  return(mpfr_cmp_z(big_real(y), big_integer(x)) > 0);
23549 	default: return(lt_out_y(sc, x, y));
23550 	}
23551     case T_BIG_RATIO:
23552       switch (type(y))
23553 	{
23554 	case T_INTEGER:
23555 	  return(mpq_cmp_si(big_ratio(x), integer(y), 1) < 0);
23556 	case T_RATIO:
23557 	  return(mpq_cmp_si(big_ratio(x), numerator(y), denominator(y)) < 0);
23558 	case T_REAL:
23559 	  if (is_NaN(real(y))) return(false);
23560 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
23561 	  return(mpfr_cmp_d(sc->mpfr_1, real(y)) < 0);
23562 	case T_BIG_INTEGER:
23563 	  return(mpq_cmp_z(big_ratio(x), big_integer(y)) < 0);
23564 	case T_BIG_REAL:
23565 	  return(mpfr_cmp_q(big_real(y), big_ratio(x)) > 0);
23566 	default: return(lt_out_y(sc, x, y));
23567 	}
23568 
23569     case T_BIG_REAL:
23570       switch (type(y))
23571 	{
23572 	case T_INTEGER:
23573 	  return(mpfr_cmp_si(big_real(x), integer(y)) < 0);
23574 	case T_RATIO:
23575 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
23576 	  return(mpfr_cmp_q(big_real(x), sc->mpq_1) < 0);
23577 	case T_REAL:
23578 	  return(mpfr_cmp_d(big_real(x), real(y)) < 0);
23579 	case T_BIG_INTEGER:
23580 	  return(mpfr_cmp_z(big_real(x), big_integer(y)) < 0);
23581 	case T_BIG_RATIO:
23582 	  return(mpfr_cmp_q(big_real(x), big_ratio(y)) < 0);
23583 	default: return(lt_out_y(sc, x, y));
23584 	}
23585 #endif
23586 
23587     default: return(lt_out_x(sc, x, y));
23588     }
23589   return(true);
23590 }
23591 
23592 static s7_pointer g_less(s7_scheme *sc, s7_pointer args)
23593 {
23594   #define H_less "(< x1 ...) returns #t if its arguments are in increasing order"
23595   #define Q_less s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
23596 
23597   s7_pointer x, p;
23598   x = car(args);
23599   p = cdr(args);
23600 
23601   if (is_null(cdr(p)))
23602     return(make_boolean(sc, lt_b_7pp(sc, x, car(p))));
23603 
23604   for (; is_pair(p); p = cdr(p))
23605     {
23606       if (!lt_b_7pp(sc, x, car(p)))
23607 	{
23608 	  for (p = cdr(p); is_pair(p); p = cdr(p))
23609 	    if (!is_real_via_method(sc, car(p)))
23610 	      return(wrong_type_argument(sc, sc->lt_symbol, position_of(p, args), car(p), T_REAL));
23611 	  return(sc->F);
23612 	}
23613       x = car(p);
23614     }
23615   return(sc->T);
23616 }
23617 
23618 static bool ratio_lt_pi(s7_pointer x, s7_int y)
23619 {
23620   if ((y >= 0) && (numerator(x) < 0))
23621     return(true);
23622   if ((y <= 0) && (numerator(x) > 0))
23623     return(false);
23624   if (denominator(x) < S7_INT32_MAX)
23625     return(numerator(x) < (y * denominator(x)));
23626   return(fraction(x) < y);
23627 }
23628 
23629 static s7_pointer g_less_x0(s7_scheme *sc, s7_pointer args)
23630 {
23631   s7_pointer x;
23632   x = car(args);
23633   if (is_t_integer(x))
23634     return(make_boolean(sc, integer(x) < 0));
23635   if (is_small_real(x))
23636     return(make_boolean(sc, s7_is_negative(x)));
23637 #if WITH_GMP
23638   if (is_t_big_integer(x))
23639     return(make_boolean(sc, mpz_cmp_si(big_integer(x), 0) < 0));
23640   if (is_t_big_real(x))
23641     return(make_boolean(sc, mpfr_cmp_si(big_real(x), 0) < 0));
23642   if (is_t_big_ratio(x))
23643     return(make_boolean(sc, mpq_cmp_si(big_ratio(x), 0, 1) < 0));
23644 #endif
23645   return(method_or_bust(sc, x, sc->lt_symbol, args, T_REAL, 1));
23646 }
23647 
23648 static s7_pointer g_less_xi(s7_scheme *sc, s7_pointer args)
23649 {
23650   s7_int y;
23651   s7_pointer x;
23652 
23653   x = car(args);
23654   y = integer(cadr(args));
23655 
23656   if (is_t_integer(x))
23657     return(make_boolean(sc, integer(x) < y));
23658   if (is_t_real(x))
23659     return(make_boolean(sc, real(x) < y));
23660   if (is_t_ratio(x))
23661     return(make_boolean(sc, ratio_lt_pi(x, y)));
23662 #if WITH_GMP
23663   if (is_t_big_integer(x))
23664     return(make_boolean(sc, mpz_cmp_si(big_integer(x), y) < 0));
23665   if (is_t_big_real(x))
23666     return(make_boolean(sc, mpfr_cmp_si(big_real(x), y) < 0));
23667   if (is_t_big_ratio(x))
23668     return(make_boolean(sc, mpq_cmp_si(big_ratio(x), y, 1) < 0));
23669 #endif
23670   return(method_or_bust(sc, x, sc->lt_symbol, args, T_REAL, 1));
23671 }
23672 
23673 static s7_pointer g_less_xf(s7_scheme *sc, s7_pointer args)
23674 {
23675   s7_double y;
23676   s7_pointer x;
23677 
23678   x = car(args);
23679   y = real(cadr(args)); /* chooser below checks is_t_real(y) */
23680 
23681   if (is_t_real(x))
23682     return(make_boolean(sc, real(x) < y));
23683   if (is_t_integer(x))
23684     return(make_boolean(sc, integer(x) < y));
23685   if (is_t_ratio(x))
23686     return(make_boolean(sc, fraction(x) < y));
23687 #if WITH_GMP
23688   if (is_t_big_real(x))
23689     return(make_boolean(sc, mpfr_cmp_d(big_real(x), y) < 0));
23690   if (is_t_big_integer(x))
23691     {
23692       mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
23693       return(make_boolean(sc, mpfr_cmp_z(sc->mpfr_1, big_integer(x)) > 0));
23694     }
23695   if (is_t_big_ratio(x))
23696     {
23697       mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
23698       return(make_boolean(sc, mpfr_cmp_q(sc->mpfr_1, big_ratio(x)) > 0));
23699     }
23700 #endif
23701   return(method_or_bust(sc, x, sc->lt_symbol, args, T_REAL, 1));
23702 }
23703 
23704 static inline s7_pointer lt_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2) {return(make_boolean(sc, lt_b_7pp(sc, p1, p2)));}
23705 static bool lt_b_ii(s7_int i1, s7_int i2) {return(i1 < i2);}
23706 static bool lt_b_dd(s7_double i1, s7_double i2) {return(i1 < i2);}
23707 static s7_pointer lt_p_dd(s7_scheme *sc, s7_double x1, s7_double x2) {return(make_boolean(sc, x1 < x2));}
23708 static s7_pointer lt_p_ii(s7_scheme *sc, s7_int x1, s7_int x2) {return(make_boolean(sc, x1 < x2));}
23709 
23710 static bool lt_b_pi(s7_scheme *sc, s7_pointer p1, s7_int p2)
23711 {
23712   if (is_t_integer(p1)) return(integer(p1) < p2);
23713   if (is_t_real(p1))  return(real(p1) < p2);
23714   if (is_t_ratio(p1)) return(ratio_lt_pi(p1, p2));
23715 #if WITH_GMP
23716   if (is_t_big_integer(p1))
23717     return(mpz_cmp_si(big_integer(p1), p2) < 0);
23718   if (is_t_big_real(p1))
23719     return(mpfr_cmp_si(big_real(p1), p2) < 0);
23720   if (is_t_big_ratio(p1))
23721     return(mpq_cmp_si(big_ratio(p1), p2, 1) < 0);
23722 #endif
23723   simple_wrong_type_argument(sc, sc->lt_symbol, p1, T_REAL);
23724   return(false);
23725 }
23726 
23727 static s7_pointer g_less_2(s7_scheme *sc, s7_pointer args) {return(lt_p_pp(sc, car(args), cadr(args)));}
23728 static s7_pointer lt_p_pi(s7_scheme *sc, s7_pointer p1, s7_int p2) {return(make_boolean(sc, lt_b_pi(sc, p1, p2)));}
23729 
23730 static s7_pointer less_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
23731 {
23732   if (args == 2)
23733     {
23734       if (ops)
23735 	{
23736 	  s7_pointer arg2;
23737 	  arg2 = caddr(expr);
23738 	  if (is_t_integer(arg2))
23739 	    {
23740 	      if (integer(arg2) == 0)
23741 		return(sc->less_x0);
23742 
23743 	      if ((integer(arg2) < S7_INT32_MAX) &&
23744 		  (integer(arg2) > S7_INT32_MIN))
23745 		return(sc->less_xi);
23746 	    }
23747 	  if (is_t_real(arg2))
23748 	    return(sc->less_xf);
23749 	}
23750       return(sc->less_2);
23751     }
23752   return(f);
23753 }
23754 
23755 
23756 /* ---------------------------------------- <= ---------------------------------------- */
23757 
23758 static bool leq_out_x(s7_scheme *sc, s7_pointer x, s7_pointer y)
23759 {
23760   if (has_active_methods(sc, x))
23761     return(find_and_apply_method(sc, x, sc->leq_symbol, set_plist_2(sc, x, y)) != sc->F);
23762   wrong_type_argument(sc, sc->leq_symbol, 1, x, T_REAL);
23763   return(false);
23764 }
23765 
23766 static bool leq_out_y(s7_scheme *sc, s7_pointer x, s7_pointer y)
23767 {
23768   if (has_active_methods(sc, y))
23769     return(find_and_apply_method(sc, y, sc->leq_symbol, set_plist_2(sc, x, y)) != sc->F);
23770   wrong_type_argument(sc, sc->leq_symbol, 2, y, T_REAL);
23771   return(false);
23772 }
23773 
23774 static bool leq_b_7pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
23775 {
23776   if (type(x) == type(y))
23777     {
23778       if (is_t_integer(x))
23779 	return(integer(x) <= integer(y));
23780       if (is_t_real(x))
23781 	return(real(x) <= real(y));
23782       if (is_t_ratio(x))
23783 	return(fraction(x) <= fraction(y));
23784 #if WITH_GMP
23785       if (is_t_big_integer(x))
23786 	return(mpz_cmp(big_integer(x), big_integer(y)) <= 0);
23787       if (is_t_big_ratio(x))
23788 	return(mpq_cmp(big_ratio(x), big_ratio(y)) <= 0);
23789       if (is_t_big_real(x))
23790 	return(mpfr_lessequal_p(big_real(x), big_real(y)));
23791 #endif
23792     }
23793   switch (type(x))
23794     {
23795     case T_INTEGER:
23796       switch (type(y))
23797 	{
23798 	case T_RATIO:	return(integer(x) <= fraction(y)); /* ?? */
23799 	case T_REAL:	return(integer(x) <= real(y));
23800 #if WITH_GMP
23801 	case T_BIG_INTEGER: return(mpz_cmp_si(big_integer(y), integer(x)) >= 0);
23802 	case T_BIG_RATIO:   return(mpq_cmp_si(big_ratio(y), integer(x), 1) >= 0);
23803 	case T_BIG_REAL:
23804 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_si(big_real(y), integer(x)) >= 0));
23805 #endif
23806 	default: return(leq_out_y(sc, x, y));
23807 	}
23808       break;
23809 
23810     case T_RATIO:
23811       switch (type(y))
23812 	{
23813 	case T_INTEGER: return(fraction(x) <= integer(y));
23814 	case T_REAL:    return(fraction(x) <= real(y));
23815 #if WITH_GMP
23816 	case T_BIG_INTEGER:
23817 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
23818 	  return(mpq_cmp_z(sc->mpq_1, big_integer(y)) <= 0);
23819 	case T_BIG_RATIO:
23820 	  return(mpq_cmp_si(big_ratio(y), numerator(x), denominator(x)) >= 0);
23821 	case T_BIG_REAL:
23822 	  if (mpfr_nan_p(big_real(y))) return(false);
23823 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
23824 	  return(mpfr_cmp_q(big_real(y), sc->mpq_1) >= 0);
23825 #endif
23826 	default: return(leq_out_y(sc, x, y));
23827 	}
23828 
23829     case T_REAL:
23830       switch (type(y))
23831 	{
23832 	case T_INTEGER: return(real(x) <= integer(y));
23833 	case T_RATIO:	return(real(x) <= fraction(y));
23834 #if WITH_GMP
23835 	case T_BIG_INTEGER:
23836 	  if (is_NaN(real(x))) return(false);
23837 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
23838 	  return(mpfr_cmp_z(sc->mpfr_1, big_integer(y)) <= 0);
23839 
23840 	case T_BIG_RATIO:
23841 	  if (is_NaN(real(x))) return(false);
23842 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
23843 	  return(mpfr_cmp_q(sc->mpfr_1, big_ratio(y)) <= 0);
23844 
23845 	case T_BIG_REAL:
23846 	  if (is_NaN(real(x))) return(false);
23847 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_d(big_real(y), real(x)) >= 0));
23848 #endif
23849 	default: return(leq_out_y(sc, x, y));
23850 	}
23851       break;
23852 
23853 #if WITH_GMP
23854     case T_BIG_INTEGER:
23855       switch (type(y))
23856 	{
23857 	case T_INTEGER:
23858 	  return(mpz_cmp_si(big_integer(x), integer(y)) <= 0);
23859 	case T_RATIO:
23860 	  mpq_set_z(sc->mpq_1, big_integer(x));
23861 	  return(mpq_cmp_si(sc->mpq_1, numerator(y), denominator(y)) <= 0);
23862 	case T_REAL:
23863 	  if (is_NaN(real(y))) return(false);
23864 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
23865 	  return(mpfr_cmp_d(sc->mpfr_1, real(y)) <= 0);
23866 	case T_BIG_RATIO:
23867 	  return(mpq_cmp_z(big_ratio(y), big_integer(x)) >= 0);
23868 	case T_BIG_REAL:
23869 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_z(big_real(y), big_integer(x)) >= 0));
23870 	default: return(leq_out_y(sc, x, y));
23871 	}
23872     case T_BIG_RATIO:
23873       switch (type(y))
23874 	{
23875 	case T_INTEGER:
23876 	  return(mpq_cmp_si(big_ratio(x), integer(y), 1) <= 0);
23877 	case T_RATIO:
23878 	  return(mpq_cmp_si(big_ratio(x), numerator(y), denominator(y)) <= 0);
23879 	case T_REAL:
23880 	  if (is_NaN(real(y))) return(false);
23881 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
23882 	  return(mpfr_cmp_d(sc->mpfr_1, real(y)) <= 0);
23883 	case T_BIG_INTEGER:
23884 	  return(mpq_cmp_z(big_ratio(x), big_integer(y)) <= 0);
23885 	case T_BIG_REAL:
23886 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_q(big_real(y), big_ratio(x)) >= 0));
23887 	default: return(leq_out_y(sc, x, y));
23888 	}
23889 
23890     case T_BIG_REAL:
23891       if ((is_real(y)) && (mpfr_nan_p(big_real(x)))) return(false);
23892       switch (type(y))
23893 	{
23894 	case T_INTEGER:
23895 	  return(mpfr_cmp_si(big_real(x), integer(y)) <= 0);
23896 	case T_RATIO:
23897 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
23898 	  return(mpfr_cmp_q(big_real(x), sc->mpq_1) <= 0);
23899 	case T_REAL:
23900 	  return((!is_NaN(real(y))) && (mpfr_cmp_d(big_real(x), real(y)) <= 0));
23901 	case T_BIG_INTEGER:
23902 	  return(mpfr_cmp_z(big_real(x), big_integer(y)) <= 0);
23903 	case T_BIG_RATIO:
23904 	  return(mpfr_cmp_q(big_real(x), big_ratio(y)) <= 0);
23905 	default: return(leq_out_y(sc, x, y));
23906 	}
23907 #endif
23908 
23909     default: return(leq_out_x(sc, x, y));
23910     }
23911   return(true);
23912 }
23913 
23914 static s7_pointer g_less_or_equal(s7_scheme *sc, s7_pointer args)
23915 {
23916   #define H_less_or_equal "(<= x1 ...) returns #t if its arguments are in non-decreasing order"
23917   #define Q_less_or_equal s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
23918 
23919   s7_pointer x, p;
23920   x = car(args);
23921   p = cdr(args);
23922 
23923   if (is_null(cdr(p)))
23924     return(make_boolean(sc, leq_b_7pp(sc, x, car(p))));
23925 
23926   for (; is_pair(p); x = car(p), p = cdr(p))
23927     if (!leq_b_7pp(sc, x, car(p)))
23928       {
23929 	for (p = cdr(p); is_pair(p); p = cdr(p))
23930 	  if (!is_real_via_method(sc, car(p)))
23931 	    return(wrong_type_argument(sc, sc->leq_symbol, position_of(p, args), car(p), T_REAL));
23932 	return(sc->F);
23933       }
23934   return(sc->T);
23935 }
23936 
23937 static inline s7_pointer leq_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2) {return(make_boolean(sc, leq_b_7pp(sc, p1, p2)));}
23938 static bool leq_b_ii(s7_int i1, s7_int i2) {return(i1 <= i2);}
23939 static bool leq_b_dd(s7_double i1, s7_double i2) {return(i1 <= i2);}
23940 static s7_pointer leq_p_dd(s7_scheme *sc, s7_double x1, s7_double x2) {return(make_boolean(sc, x1 <= x2));}
23941 static s7_pointer leq_p_ii(s7_scheme *sc, s7_int x1, s7_int x2) {return(make_boolean(sc, x1 <= x2));}
23942 
23943 static bool ratio_leq_pi(s7_pointer x, s7_int y)
23944 {
23945   if ((y >= 0) && (numerator(x) <= 0))
23946     return(true);
23947   if ((y <= 0) && (numerator(x) > 0))
23948     return(false);
23949   if (denominator(x) < S7_INT32_MAX)
23950     return(numerator(x) <= (y * denominator(x)));
23951   return(fraction(x) <= y);
23952 }
23953 
23954 static s7_pointer g_leq_xi(s7_scheme *sc, s7_pointer args)
23955 {
23956   s7_int y;
23957   s7_pointer x;
23958 
23959   x = car(args);
23960   y = integer(cadr(args));
23961 
23962   if (is_t_integer(x))
23963     return(make_boolean(sc, integer(x) <= y));
23964   if (is_t_real(x))
23965     return(make_boolean(sc, real(x) <= y));
23966   if (is_t_ratio(x))
23967     return(make_boolean(sc, ratio_leq_pi(x, y)));
23968 #if WITH_GMP
23969   if (is_t_big_integer(x))
23970     return(make_boolean(sc, mpz_cmp_si(big_integer(x), y) <= 0));
23971   if (is_t_big_real(x))
23972     {
23973       if (mpfr_nan_p(big_real(x))) return(sc->F);
23974       return(make_boolean(sc, mpfr_cmp_si(big_real(x), y) <= 0));
23975     }
23976   if (is_t_big_ratio(x))
23977     return(make_boolean(sc, mpq_cmp_si(big_ratio(x), y, 1) <= 0));
23978 #endif
23979   return(method_or_bust(sc, x, sc->leq_symbol, args, T_REAL, 1));
23980 }
23981 
23982 static bool leq_b_pi(s7_scheme *sc, s7_pointer p1, s7_int p2)
23983 {
23984   if (is_t_integer(p1)) return(integer(p1) <= p2);
23985   if (is_t_real(p1))  return(real(p1) <= p2);
23986   if (is_t_ratio(p1)) return(ratio_leq_pi(p1, p2));
23987 #if WITH_GMP
23988   if (is_t_big_integer(p1))
23989     return(mpz_cmp_si(big_integer(p1), p2) <= 0);
23990   if (is_t_big_real(p1))
23991     return(mpfr_cmp_si(big_real(p1), p2) <= 0);
23992   if (is_t_big_ratio(p1))
23993     return(mpq_cmp_si(big_ratio(p1), p2, 1) <= 0);
23994 #endif
23995   simple_wrong_type_argument(sc, sc->leq_symbol, p1, T_REAL);
23996   return(false);
23997 }
23998 
23999 static s7_pointer leq_p_pi(s7_scheme *sc, s7_pointer p1, s7_int p2) {return(make_boolean(sc, leq_b_pi(sc, p1, p2)));}
24000 static s7_pointer g_leq_2(s7_scheme *sc, s7_pointer args) {return(make_boolean(sc, leq_b_7pp(sc, car(args), cadr(args))));}
24001 
24002 static s7_pointer leq_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
24003 {
24004   if (args == 2)
24005     {
24006       if (ops)
24007 	{
24008 	  s7_pointer arg2;
24009 	  arg2 = caddr(expr);
24010 	  if ((is_t_integer(arg2)) &&
24011 	      (integer(arg2) < S7_INT32_MAX) &&
24012 	      (integer(arg2) > S7_INT32_MIN))
24013 	    return(sc->leq_xi);
24014 	}
24015       return(sc->leq_2);
24016     }
24017   return(f);
24018 }
24019 
24020 
24021 /* ---------------------------------------- > ---------------------------------------- */
24022 
24023 static bool gt_out_x(s7_scheme *sc, s7_pointer x, s7_pointer y)
24024 {
24025   if (has_active_methods(sc, x))
24026     return(find_and_apply_method(sc, x, sc->gt_symbol, set_plist_2(sc, x, y)) != sc->F);
24027   wrong_type_argument(sc, sc->gt_symbol, 1, x, T_REAL);
24028   return(false);
24029 }
24030 
24031 static bool gt_out_y(s7_scheme *sc, s7_pointer x, s7_pointer y)
24032 {
24033   if (has_active_methods(sc, y))
24034     return(find_and_apply_method(sc, y, sc->gt_symbol, set_plist_2(sc, x, y)) != sc->F);
24035   wrong_type_argument(sc, sc->gt_symbol, 2, y, T_REAL);
24036   return(false);
24037 }
24038 
24039 static bool gt_b_7pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
24040 {
24041   if (type(x) == type(y))
24042     {
24043       if (is_t_integer(x))
24044 	return(integer(x) > integer(y));
24045       if (is_t_real(x))
24046 	return(real(x) > real(y));
24047       if (is_t_ratio(x))
24048 	return(fraction(x) > fraction(y));
24049 #if WITH_GMP
24050       if (is_t_big_integer(x))
24051 	return(mpz_cmp(big_integer(x), big_integer(y)) > 0);
24052       if (is_t_big_ratio(x))
24053 	return(mpq_cmp(big_ratio(x), big_ratio(y)) > 0);
24054       if (is_t_big_real(x))
24055 	return(mpfr_greater_p(big_real(x), big_real(y)));
24056 #endif
24057     }
24058   switch (type(x))
24059     {
24060     case T_INTEGER:
24061       switch (type(y))
24062 	{
24063 	case T_RATIO:	return(integer(x) > fraction(y)); /* ?? */
24064 	case T_REAL:	return(integer(x) > real(y));
24065 #if WITH_GMP
24066 	case T_BIG_INTEGER: return(mpz_cmp_si(big_integer(y), integer(x)) < 0);
24067 	case T_BIG_RATIO:   return(mpq_cmp_si(big_ratio(y), integer(x), 1) < 0);
24068 	case T_BIG_REAL:    return(mpfr_cmp_si(big_real(y), integer(x)) < 0);
24069 #endif
24070 	default: return(gt_out_y(sc, x, y));
24071 	}
24072       break;
24073 
24074     case T_RATIO:
24075       switch (type(y))
24076 	{
24077 	case T_INTEGER: return(fraction(x) > integer(y));
24078 	case T_REAL:    return(fraction(x) > real(y));
24079 #if WITH_GMP
24080 	case T_BIG_INTEGER:
24081 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
24082 	  return(mpq_cmp_z(sc->mpq_1, big_integer(y)) > 0);
24083 	case T_BIG_RATIO:
24084 	  return(mpq_cmp_si(big_ratio(y), numerator(x), denominator(x)) < 0);
24085 	case T_BIG_REAL:
24086 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
24087 	  return(mpfr_cmp_q(big_real(y), sc->mpq_1) < 0);
24088 #endif
24089 	default: return(gt_out_y(sc, x, y));
24090 	}
24091 
24092     case T_REAL:
24093       switch (type(y))
24094 	{
24095 	case T_INTEGER: return(real(x) > integer(y));
24096 	case T_RATIO:	return(real(x) > fraction(y));
24097 #if WITH_GMP
24098 	case T_BIG_INTEGER:
24099 	  if (is_NaN(real(x))) return(false);
24100 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
24101 	  return(mpfr_cmp_z(sc->mpfr_1, big_integer(y)) > 0);
24102 
24103 	case T_BIG_RATIO:
24104 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
24105 	  return(mpfr_cmp_q(sc->mpfr_1, big_ratio(y)) > 0);
24106 
24107 	case T_BIG_REAL:
24108 	  return(mpfr_cmp_d(big_real(y), real(x)) < 0);
24109 #endif
24110 	default: return(gt_out_y(sc, x, y));
24111 	}
24112       break;
24113 
24114 #if WITH_GMP
24115     case T_BIG_INTEGER:
24116       switch (type(y))
24117 	{
24118 	case T_INTEGER:
24119 	  return(mpz_cmp_si(big_integer(x), integer(y)) > 0);
24120 	case T_RATIO:
24121 	  mpq_set_z(sc->mpq_1, big_integer(x));
24122 	  return(mpq_cmp_si(sc->mpq_1, numerator(y), denominator(y)) > 0);
24123 	case T_REAL:
24124 	  if (is_NaN(real(y))) return(false);
24125 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
24126 	  return(mpfr_cmp_d(sc->mpfr_1, real(y)) > 0);
24127 	case T_BIG_RATIO:
24128 	  return(mpq_cmp_z(big_ratio(y), big_integer(x)) < 0);
24129 	case T_BIG_REAL:
24130 	  return(mpfr_cmp_z(big_real(y), big_integer(x)) < 0);
24131 	default: return(gt_out_y(sc, x, y));
24132 	}
24133     case T_BIG_RATIO:
24134       switch (type(y))
24135 	{
24136 	case T_INTEGER:
24137 	  return(mpq_cmp_si(big_ratio(x), integer(y), 1) > 0);
24138 	case T_RATIO:
24139 	  return(mpq_cmp_si(big_ratio(x), numerator(y), denominator(y)) > 0);
24140 	case T_REAL:
24141 	  if (is_NaN(real(y))) return(false);
24142 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
24143 	  return(mpfr_cmp_d(sc->mpfr_1, real(y)) > 0);
24144 	case T_BIG_INTEGER:
24145 	  return(mpq_cmp_z(big_ratio(x), big_integer(y)) > 0);
24146 	case T_BIG_REAL:
24147 	  return(mpfr_cmp_q(big_real(y), big_ratio(x)) < 0);
24148 	default: return(gt_out_y(sc, x, y));
24149 	}
24150 
24151     case T_BIG_REAL:
24152       switch (type(y))
24153 	{
24154 	case T_INTEGER:
24155 	  return(mpfr_cmp_si(big_real(x), integer(y)) > 0);
24156 	case T_RATIO:
24157 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
24158 	  return(mpfr_cmp_q(big_real(x), sc->mpq_1) > 0);
24159 	case T_REAL:
24160 	  return(mpfr_cmp_d(big_real(x), real(y)) > 0);
24161 	case T_BIG_INTEGER:
24162 	  return(mpfr_cmp_z(big_real(x), big_integer(y)) > 0);
24163 	case T_BIG_RATIO:
24164 	  return(mpfr_cmp_q(big_real(x), big_ratio(y)) > 0);
24165 	default: return(gt_out_y(sc, x, y));
24166 	}
24167 #endif
24168 
24169     default: return(gt_out_x(sc, x, y));
24170     }
24171   return(true);
24172 }
24173 
24174 static s7_pointer g_greater(s7_scheme *sc, s7_pointer args)
24175 {
24176   #define H_greater "(> x1 ...) returns #t if its arguments are in decreasing order"
24177   #define Q_greater s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
24178 
24179   s7_pointer x, p;
24180   x = car(args);
24181   p = cdr(args);
24182 
24183   if (is_null(cdr(p)))
24184     return(make_boolean(sc, gt_b_7pp(sc, x, car(p))));
24185 
24186   for (; is_pair(p); x = car(p), p = cdr(p))
24187     if (!gt_b_7pp(sc, x, car(p)))
24188       {
24189 	for (p = cdr(p); is_pair(p); p = cdr(p))
24190 	  if (!is_real_via_method(sc, car(p)))
24191 	    return(wrong_type_argument(sc, sc->gt_symbol, position_of(p, args), car(p), T_REAL));
24192 	return(sc->F);
24193       }
24194   return(sc->T);
24195 }
24196 
24197 static s7_pointer g_greater_xi(s7_scheme *sc, s7_pointer args)
24198 {
24199   s7_int y;
24200   s7_pointer x;
24201 
24202   x = car(args);
24203   y = integer(cadr(args));
24204 
24205   if (is_t_integer(x))
24206     return(make_boolean(sc, integer(x) > y));
24207   if (is_t_real(x))
24208     return(make_boolean(sc, real(x) > y));
24209   if (is_t_ratio(x))
24210     return(make_boolean(sc, !ratio_leq_pi(x, y)));
24211 #if WITH_GMP
24212   if (is_t_big_integer(x))
24213     return(make_boolean(sc, mpz_cmp_si(big_integer(x), y) > 0));
24214   if (is_t_big_real(x))
24215     return(make_boolean(sc, mpfr_cmp_si(big_real(x), y) > 0));
24216   if (is_t_big_ratio(x))
24217     return(make_boolean(sc, mpq_cmp_si(big_ratio(x), y, 1) > 0));
24218 #endif
24219   return(method_or_bust_with_type(sc, x, sc->gt_symbol, args, a_number_string, 1));
24220 }
24221 
24222 static s7_pointer g_greater_xf(s7_scheme *sc, s7_pointer args)
24223 {
24224   s7_double y;
24225   s7_pointer x;
24226 
24227   x = car(args);
24228   y = real(cadr(args));
24229 
24230   if (is_t_real(x))
24231     return(make_boolean(sc, real(x) > y));
24232 
24233   switch (type(x))
24234     {
24235     case T_INTEGER: return(make_boolean(sc, integer(x) > y));
24236 
24237     case T_RATIO:
24238       /* (> 9223372036854775807/9223372036854775806 1.0) */
24239       if (denominator(x) < S7_INT32_MAX) /* y range check was handled in greater_chooser */
24240 	return(make_boolean(sc, (numerator(x) > (y * denominator(x)))));
24241       return(make_boolean(sc, fraction(x) > y));
24242 
24243 #if WITH_GMP
24244     case T_BIG_INTEGER:
24245       mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
24246       return(make_boolean(sc, mpfr_cmp_z(sc->mpfr_1, big_integer(x)) < 0));
24247 
24248     case T_BIG_RATIO:
24249       mpfr_set_d(sc->mpfr_1, y, MPFR_RNDN);
24250       return(make_boolean(sc, mpfr_cmp_q(sc->mpfr_1, big_ratio(x)) < 0));
24251 
24252     case T_BIG_REAL:
24253       return(make_boolean(sc, mpfr_cmp_d(big_real(x), y) > 0));
24254 #endif
24255     default:
24256       return(method_or_bust_with_type(sc, x, sc->gt_symbol, args, a_number_string, 1));
24257     }
24258   return(sc->T);
24259 }
24260 
24261 static inline s7_pointer gt_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2) {return(make_boolean(sc, gt_b_7pp(sc, p1, p2)));}
24262 static bool gt_b_ii(s7_int i1, s7_int i2) {return(i1 > i2);}
24263 static bool gt_b_dd(s7_double i1, s7_double i2) {return(i1 > i2);}
24264 static s7_pointer gt_p_dd(s7_scheme *sc, s7_double x1, s7_double x2) {return(make_boolean(sc, x1 > x2));}
24265 static s7_pointer gt_p_ii(s7_scheme *sc, s7_int x1, s7_int x2) {return(make_boolean(sc, x1 > x2));}
24266 
24267 static bool gt_b_pi(s7_scheme *sc, s7_pointer p1, s7_int p2)
24268 {
24269   if (is_t_integer(p1)) return(integer(p1) > p2);
24270   if (is_t_real(p1))  return(real(p1) > p2);
24271   if (is_t_ratio(p1)) return(!ratio_leq_pi(p1, p2));
24272 #if WITH_GMP
24273   if (is_t_big_integer(p1))
24274     return(mpz_cmp_si(big_integer(p1), p2) > 0);
24275   if (is_t_big_real(p1))
24276     return(mpfr_cmp_si(big_real(p1), p2) > 0);
24277   if (is_t_big_ratio(p1))
24278     return(mpq_cmp_si(big_ratio(p1), p2, 1) > 0);
24279 #endif
24280   simple_wrong_type_argument(sc, sc->gt_symbol, p1, T_REAL);
24281   return(false);
24282 }
24283 
24284 static s7_pointer gt_p_pi(s7_scheme *sc, s7_pointer p1, s7_int p2) {return(make_boolean(sc, gt_b_pi(sc, p1, p2)));}
24285 
24286 static s7_pointer g_greater_2(s7_scheme *sc, s7_pointer args)
24287 {
24288   /* ridiculous repetition, but overheads are killing this poor thing */
24289   s7_pointer x, y;
24290   x = car(args);
24291   y = cadr(args);
24292   if (type(x) == type(y))
24293     {
24294       if (is_t_integer(x)) return(make_boolean(sc, integer(x) > integer(y)));
24295       if (is_t_real(x))    return(make_boolean(sc, real(x) > real(y)));
24296       if (is_t_ratio(x))   return(make_boolean(sc, fraction(x) > fraction(y)));
24297     }
24298   switch (type(x))
24299     {
24300     case T_INTEGER:
24301       switch (type(y))
24302 	{
24303 	case T_RATIO:   return(gt_p_pp(sc, x, y));
24304 	case T_REAL:    return(make_boolean(sc, integer(x) > real(y)));
24305 #if WITH_GMP
24306 	case T_BIG_INTEGER: case T_BIG_RATIO: case T_BIG_REAL:
24307 	  return(gt_p_pp(sc, x, y));
24308 #endif
24309 	default:        return(make_boolean(sc, gt_out_y(sc, x, y)));
24310 	}
24311       break;
24312 
24313     case T_RATIO:       return(gt_p_pp(sc, x, y));
24314 
24315     case T_REAL:
24316       switch (type(y))
24317 	{
24318 	case T_INTEGER: return(make_boolean(sc, real(x) > integer(y)));
24319 	case T_RATIO:   return(make_boolean(sc, real(x) > fraction(y)));
24320 #if WITH_GMP
24321 	case T_BIG_INTEGER: case T_BIG_RATIO: case T_BIG_REAL:
24322 	  return(gt_p_pp(sc, x, y));
24323 #endif
24324 	default:        return(make_boolean(sc, gt_out_y(sc, x, y)));
24325 	}
24326       break;
24327 #if WITH_GMP
24328     case T_BIG_INTEGER: case T_BIG_RATIO: case T_BIG_REAL:
24329       return(gt_p_pp(sc, x, y));
24330 #endif
24331 
24332     default:            return(make_boolean(sc, gt_out_x(sc, x, y)));
24333     }
24334   return(sc->T);
24335 }
24336 
24337 static s7_pointer greater_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
24338 {
24339   if (args == 2)
24340     {
24341       if (ops)
24342 	{
24343 	  s7_pointer arg2;
24344 	  arg2 = caddr(expr);
24345 
24346 	  if ((is_t_integer(arg2)) &&
24347 	      (integer(arg2) < S7_INT32_MAX) &&
24348 	      (integer(arg2) > S7_INT32_MIN))
24349 	    return(sc->greater_xi);
24350 	  if ((is_t_real(arg2)) &&
24351 	      (real(arg2) < S7_INT32_MAX) &&
24352 	      (real(arg2) > S7_INT32_MIN))
24353 	    return(sc->greater_xf);
24354 	}
24355       return(sc->greater_2);
24356     }
24357   return(f);
24358 }
24359 
24360 
24361 /* ---------------------------------------- >= ---------------------------------------- */
24362 
24363 static bool geq_out_x(s7_scheme *sc, s7_pointer x, s7_pointer y)
24364 {
24365   if (has_active_methods(sc, x))
24366     return(find_and_apply_method(sc, x, sc->geq_symbol, set_plist_2(sc, x, y)) != sc->F);
24367   wrong_type_argument(sc, sc->geq_symbol, 1, x, T_REAL);
24368   return(false);
24369 }
24370 
24371 static bool geq_out_y(s7_scheme *sc, s7_pointer x, s7_pointer y)
24372 {
24373   if (has_active_methods(sc, y))
24374     return(find_and_apply_method(sc, y, sc->geq_symbol, set_plist_2(sc, x, y)) != sc->F);
24375   wrong_type_argument(sc, sc->geq_symbol, 2, y, T_REAL);
24376   return(false);
24377 }
24378 
24379 static bool geq_b_7pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
24380 {
24381   if (type(x) == type(y))
24382     {
24383       if (is_t_integer(x))
24384 	return(integer(x) >= integer(y));
24385       if (is_t_real(x))
24386 	return(real(x) >= real(y));
24387       if (is_t_ratio(x))
24388 	return(fraction(x) >= fraction(y));
24389 #if WITH_GMP
24390       if (is_t_big_integer(x))
24391 	return(mpz_cmp(big_integer(x), big_integer(y)) >= 0);
24392       if (is_t_big_ratio(x))
24393 	return(mpq_cmp(big_ratio(x), big_ratio(y)) >= 0);
24394       if (is_t_big_real(x))
24395 	return(mpfr_greaterequal_p(big_real(x), big_real(y)));
24396 #endif
24397     }
24398   switch (type(x))
24399     {
24400     case T_INTEGER:
24401       switch (type(y))
24402 	{
24403 	case T_RATIO:	return(integer(x) >= fraction(y)); /* ?? */
24404 	case T_REAL:	return(integer(x) >= real(y));
24405 #if WITH_GMP
24406 	case T_BIG_INTEGER: return(mpz_cmp_si(big_integer(y), integer(x)) <= 0);
24407 	case T_BIG_RATIO:   return(mpq_cmp_si(big_ratio(y), integer(x), 1) <= 0);
24408 	case T_BIG_REAL:
24409 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_si(big_real(y), integer(x)) <= 0));
24410 #endif
24411 	default: return(geq_out_y(sc, x, y));
24412 	}
24413       break;
24414 
24415     case T_RATIO:
24416       switch (type(y))
24417 	{
24418 	case T_INTEGER: return(fraction(x) >= integer(y));
24419 	case T_REAL:    return(fraction(x) >= real(y));
24420 #if WITH_GMP
24421 	case T_BIG_INTEGER:
24422 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
24423 	  return(mpq_cmp_z(sc->mpq_1, big_integer(y)) >= 0);
24424 	case T_BIG_RATIO:
24425 	  return(mpq_cmp_si(big_ratio(y), numerator(x), denominator(x)) <= 0);
24426 	case T_BIG_REAL:
24427 	  if (mpfr_nan_p(big_real(y))) return(false);
24428 	  mpq_set_si(sc->mpq_1, numerator(x), denominator(x));
24429 	  return(mpfr_cmp_q(big_real(y), sc->mpq_1) <= 0);
24430 #endif
24431 	default: return(geq_out_y(sc, x, y));
24432 	}
24433 
24434     case T_REAL:
24435       switch (type(y))
24436 	{
24437 	case T_INTEGER: return(real(x) >= integer(y));
24438 	case T_RATIO:	return(real(x) >= fraction(y));
24439 #if WITH_GMP
24440 	case T_BIG_INTEGER:
24441 	  if (is_NaN(real(x))) return(false);
24442 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
24443 	  return(mpfr_cmp_z(sc->mpfr_1, big_integer(y)) >= 0);
24444 	case T_BIG_RATIO:
24445 	  if (is_NaN(real(x))) return(false);
24446 	  mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
24447 	  return(mpfr_cmp_q(sc->mpfr_1, big_ratio(y)) >= 0);
24448 	case T_BIG_REAL:
24449 	  if (is_NaN(real(x))) return(false);
24450 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_d(big_real(y), real(x)) <= 0));
24451 #endif
24452 	default: return(geq_out_y(sc, x, y));
24453 	}
24454       break;
24455 
24456 #if WITH_GMP
24457     case T_BIG_INTEGER:
24458       switch (type(y))
24459 	{
24460 	case T_INTEGER:
24461 	  return(mpz_cmp_si(big_integer(x), integer(y)) >= 0);
24462 	case T_RATIO:
24463 	  mpq_set_z(sc->mpq_1, big_integer(x));
24464 	  return(mpq_cmp_si(sc->mpq_1, numerator(y), denominator(y)) >= 0);
24465 	case T_REAL:
24466 	  if (is_NaN(real(y))) return(false);
24467 	  mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
24468 	  return(mpfr_cmp_d(sc->mpfr_1, real(y)) >= 0);
24469 	case T_BIG_RATIO:
24470 	  return(mpq_cmp_z(big_ratio(y), big_integer(x)) <= 0);
24471 	case T_BIG_REAL:
24472 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_z(big_real(y), big_integer(x)) <= 0));
24473 	default: return(geq_out_y(sc, x, y));
24474 	}
24475     case T_BIG_RATIO:
24476       switch (type(y))
24477 	{
24478 	case T_INTEGER:
24479 	  return(mpq_cmp_si(big_ratio(x), integer(y), 1) >= 0);
24480 	case T_RATIO:
24481 	  return(mpq_cmp_si(big_ratio(x), numerator(y), denominator(y)) >= 0);
24482 	case T_REAL:
24483 	  if (is_NaN(real(y))) return(false);
24484 	  mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
24485 	  return(mpfr_cmp_d(sc->mpfr_1, real(y)) >= 0);
24486 	case T_BIG_INTEGER:
24487 	  return(mpq_cmp_z(big_ratio(x), big_integer(y)) >= 0);
24488 	case T_BIG_REAL:
24489 	  return((!mpfr_nan_p(big_real(y))) && (mpfr_cmp_q(big_real(y), big_ratio(x)) <= 0));
24490 	default: return(geq_out_y(sc, x, y));
24491 	}
24492 
24493     case T_BIG_REAL:
24494       if ((is_real(y)) && (mpfr_nan_p(big_real(x)))) return(false);
24495       switch (type(y))
24496 	{
24497 	case T_INTEGER:
24498 	  return(mpfr_cmp_si(big_real(x), integer(y)) >= 0);
24499 	case T_RATIO:
24500 	  mpq_set_si(sc->mpq_1, numerator(y), denominator(y));
24501 	  return(mpfr_cmp_q(big_real(x), sc->mpq_1) >= 0);
24502 	case T_REAL:
24503 	  return((!is_NaN(real(y))) && (mpfr_cmp_d(big_real(x), real(y)) >= 0));
24504 	case T_BIG_INTEGER:
24505 	  return(mpfr_cmp_z(big_real(x), big_integer(y)) >= 0);
24506 	case T_BIG_RATIO:
24507 	  return(mpfr_cmp_q(big_real(x), big_ratio(y)) >= 0);
24508 	default: return(geq_out_y(sc, x, y));
24509 	}
24510 #endif
24511     default: return(geq_out_x(sc, x, y));
24512     }
24513   return(true);
24514 }
24515 
24516 static s7_pointer g_greater_or_equal(s7_scheme *sc, s7_pointer args)
24517 {
24518   #define H_greater_or_equal "(>= x1 ...) returns #t if its arguments are in non-increasing order"
24519   #define Q_greater_or_equal s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
24520 
24521   s7_pointer x, p;
24522   x = car(args);
24523   p = cdr(args);
24524 
24525   if (is_null(cdr(p)))
24526     return(make_boolean(sc, geq_b_7pp(sc, x, car(p))));
24527 
24528   for (; is_pair(p); x = car(p), p = cdr(p))
24529     if (!geq_b_7pp(sc, x, car(p)))
24530       {
24531 	for (p = cdr(p); is_pair(p); p = cdr(p))
24532 	  if (!is_real_via_method(sc, car(p)))
24533 	    return(wrong_type_argument(sc, sc->geq_symbol, position_of(p, args), car(p), T_REAL));
24534 	return(sc->F);
24535       }
24536   return(sc->T);
24537 }
24538 
24539 static inline s7_pointer geq_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2) {return(make_boolean(sc, geq_b_7pp(sc, p1, p2)));}
24540 static bool geq_b_ii(s7_int i1, s7_int i2) {return(i1 >= i2);}
24541 static bool geq_b_dd(s7_double i1, s7_double i2) {return(i1 >= i2);}
24542 static s7_pointer geq_p_dd(s7_scheme *sc, s7_double x1, s7_double x2) {return(make_boolean(sc, x1 >= x2));}
24543 static s7_pointer geq_p_ii(s7_scheme *sc, s7_int x1, s7_int x2) {return(make_boolean(sc, x1 >= x2));}
24544 
24545 static s7_pointer g_geq_2(s7_scheme *sc, s7_pointer args) {return(make_boolean(sc, geq_b_7pp(sc, car(args), cadr(args))));}
24546 
24547 static s7_pointer g_geq_xf(s7_scheme *sc, s7_pointer args)
24548 {
24549   s7_double y;
24550   s7_pointer x;
24551 
24552   x = car(args);
24553   y = real(cadr(args));
24554   return(make_boolean(sc, ((is_t_real(x)) ? (real(x) >= y) : geq_b_7pp(sc, car(args), cadr(args)))));
24555 }
24556 
24557 static s7_pointer g_geq_xi(s7_scheme *sc, s7_pointer args)
24558 {
24559   s7_int y;
24560   s7_pointer x;
24561 
24562   x = car(args);
24563   y = integer(cadr(args));
24564 
24565   if (is_t_integer(x))
24566     return(make_boolean(sc, integer(x) >= y));
24567   if (is_t_real(x))
24568     return(make_boolean(sc, real(x) >= y));
24569   if (is_t_ratio(x))
24570     return(make_boolean(sc, !ratio_lt_pi(x, y)));
24571 #if WITH_GMP
24572   if (is_t_big_integer(x))
24573     return(make_boolean(sc, mpz_cmp_si(big_integer(x), y) >= 0));
24574   if (is_t_big_real(x))
24575     {
24576       if (mpfr_nan_p(big_real(x))) return(sc->F);
24577       return(make_boolean(sc, mpfr_cmp_si(big_real(x), y) >= 0));
24578     }
24579   if (is_t_big_ratio(x))
24580     return(make_boolean(sc, mpq_cmp_si(big_ratio(x), y, 1) >= 0));
24581 #endif
24582   return(method_or_bust(sc, x, sc->geq_symbol, args, T_REAL, 1));
24583 }
24584 
24585 static bool geq_b_pi(s7_scheme *sc, s7_pointer p1, s7_int p2)
24586 {
24587   if (is_t_integer(p1)) return(integer(p1) >= p2);
24588   if (is_t_real(p1))  return(real(p1) >= p2);
24589   if (is_t_ratio(p1)) return(!ratio_lt_pi(p1, p2));
24590 #if WITH_GMP
24591   if (is_t_big_integer(p1))
24592     return(mpz_cmp_si(big_integer(p1), p2) >= 0);
24593   if (is_t_big_real(p1))
24594     return((!mpfr_nan_p(big_real(p1))) && (mpfr_cmp_si(big_real(p1), p2) >= 0));
24595   if (is_t_big_ratio(p1))
24596     return(mpq_cmp_si(big_ratio(p1), p2, 1) >= 0);
24597 #endif
24598   simple_wrong_type_argument(sc, sc->geq_symbol, p1, T_REAL);
24599   return(false);
24600 }
24601 
24602 static s7_pointer geq_p_pi(s7_scheme *sc, s7_pointer p1, s7_int p2) {return(make_boolean(sc, geq_b_pi(sc, p1, p2)));}
24603 
24604 static s7_pointer geq_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
24605 {
24606   if (args == 2)
24607     {
24608       if (ops)
24609 	{
24610 	  s7_pointer arg2;
24611 	  arg2 = caddr(expr);
24612 	  if ((is_t_integer(arg2)) &&
24613 	      (integer(arg2) < S7_INT32_MAX) &&
24614 	      (integer(arg2) > S7_INT32_MIN))
24615 	    return(sc->geq_xi);
24616 	  if ((is_t_real(arg2)) &&
24617 	      (real(arg2) < S7_INT32_MAX) &&
24618 	      (real(arg2) > S7_INT32_MIN))
24619 	    return(sc->geq_xf);
24620 	}
24621       return(sc->geq_2);
24622     }
24623   return(f);
24624 }
24625 
24626 
24627 /* ---------------------------------------- real-part ---------------------------------------- */
24628 s7_double s7_real_part(s7_pointer x)
24629 {
24630   switch(type(x))
24631     {
24632     case T_INTEGER:     return((s7_double)integer(x));
24633     case T_RATIO:       return(fraction(x));
24634     case T_REAL:        return(real(x));
24635     case T_COMPLEX:     return(real_part(x));
24636 #if WITH_GMP
24637     case T_BIG_INTEGER: return((s7_double)mpz_get_si(big_integer(x)));
24638     case T_BIG_RATIO:   return((s7_double)((long_double)mpz_get_si(mpq_numref(big_ratio(x))) /
24639 					   (long_double)mpz_get_si(mpq_denref(big_ratio(x)))));
24640     case T_BIG_REAL:    return((s7_double)mpfr_get_d(big_real(x), MPFR_RNDN));
24641     case T_BIG_COMPLEX: return((s7_double)mpfr_get_d(mpc_realref(big_complex(x)), MPFR_RNDN));
24642 #endif
24643     }
24644   return(0.0);
24645 }
24646 
24647 static s7_pointer real_part_p_p(s7_scheme *sc, s7_pointer p)
24648 {
24649   switch (type(p))
24650     {
24651     case T_INTEGER:
24652     case T_RATIO:
24653     case T_REAL:
24654       return(p);
24655 
24656     case T_COMPLEX:
24657       return(make_real(sc, real_part(p)));
24658 
24659 #if WITH_GMP
24660     case T_BIG_INTEGER:
24661     case T_BIG_RATIO:
24662     case T_BIG_REAL:
24663       return(p);
24664 
24665     case T_BIG_COMPLEX:
24666       {
24667 	s7_pointer x;
24668 	new_cell(sc, x, T_BIG_REAL);
24669 	big_real_bgf(x) = alloc_bigflt(sc);
24670 	add_big_real(sc, x);
24671 	mpc_real(big_real(x), big_complex(p), MPFR_RNDN);
24672 	return(x);
24673       }
24674 #endif
24675 
24676     default:
24677       return(method_or_bust_with_type_one_arg_p(sc, p, sc->real_part_symbol, a_number_string));
24678     }
24679 }
24680 
24681 static s7_pointer g_real_part(s7_scheme *sc, s7_pointer args)
24682 {
24683   #define H_real_part "(real-part num) returns the real part of num"
24684   #define Q_real_part s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
24685   return(real_part_p_p(sc, car(args)));
24686 }
24687 
24688 
24689 /* ---------------------------------------- imag-part ---------------------------------------- */
24690 s7_double s7_imag_part(s7_pointer x)
24691 {
24692   if (is_t_complex(x))
24693     return(imag_part(x));
24694 #if WITH_GMP
24695   if (is_t_big_complex(x))
24696     return((s7_double)mpfr_get_d(mpc_imagref(big_complex(x)), MPFR_RNDN));
24697 #endif
24698   return(0.0);
24699 }
24700 
24701 static s7_pointer imag_part_p_p(s7_scheme *sc, s7_pointer p)
24702 {
24703  switch (type(p))
24704     {
24705     case T_INTEGER:
24706     case T_RATIO:
24707       return(int_zero);
24708 
24709     case T_REAL:
24710       return(real_zero);
24711 
24712     case T_COMPLEX:
24713       return(make_real(sc, imag_part(p)));
24714 
24715 #if WITH_GMP
24716     case T_BIG_INTEGER:
24717     case T_BIG_RATIO:
24718       return(int_zero);
24719 
24720     case T_BIG_REAL:
24721       return(real_zero);
24722 
24723     case T_BIG_COMPLEX:
24724       {
24725 	s7_pointer x;
24726 	new_cell(sc, x, T_BIG_REAL);
24727 	big_real_bgf(x) = alloc_bigflt(sc);
24728 	add_big_real(sc, x);
24729 	mpc_imag(big_real(x), big_complex(p), MPFR_RNDN);
24730 	return(x);
24731       }
24732 #endif
24733 
24734     default:
24735       return(method_or_bust_with_type_one_arg_p(sc, p, sc->imag_part_symbol, a_number_string));
24736     }
24737 }
24738 
24739 static s7_pointer g_imag_part(s7_scheme *sc, s7_pointer args)
24740 {
24741   #define H_imag_part "(imag-part num) returns the imaginary part of num"
24742   #define Q_imag_part s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
24743   /* currently (imag-part +nan.0) -> 0.0 ? it's true but maybe confusing */
24744   return(imag_part_p_p(sc, car(args)));
24745 }
24746 
24747 
24748 /* ---------------------------------------- numerator denominator ---------------------------------------- */
24749 
24750 static s7_int numerator_i_7p(s7_scheme *sc, s7_pointer p)
24751 {
24752   if (is_t_ratio(p)) return(numerator(p));
24753   if (is_t_integer(p)) return(integer(p));
24754 #if WITH_GMP
24755   if (is_t_big_ratio(p)) return(mpz_get_si(mpq_numref(big_ratio(p))));
24756   if (is_t_big_integer(p)) return(mpz_get_si(big_integer(p)));
24757 #endif
24758   return(integer(method_or_bust_with_type_one_arg_p(sc, p, sc->numerator_symbol, a_rational_string)));
24759 }
24760 
24761 static s7_pointer g_numerator(s7_scheme *sc, s7_pointer args)
24762 {
24763   #define H_numerator "(numerator rat) returns the numerator of the rational number rat"
24764   #define Q_numerator s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_rational_symbol)
24765 
24766   s7_pointer x;
24767   x = car(args);
24768   switch (type(x))
24769     {
24770     case T_RATIO:       return(make_integer(sc, numerator(x)));
24771     case T_INTEGER:     return(x);
24772 #if WITH_GMP
24773     case T_BIG_INTEGER: return(x);
24774     case T_BIG_RATIO:   return(mpz_to_integer(sc, mpq_numref(big_ratio(x))));
24775 #endif
24776     default:            return(method_or_bust_with_type_one_arg(sc, x, sc->numerator_symbol, args, a_rational_string));
24777     }
24778 }
24779 
24780 
24781 static s7_pointer g_denominator(s7_scheme *sc, s7_pointer args)
24782 {
24783   #define H_denominator "(denominator rat) returns the denominator of the rational number rat"
24784   #define Q_denominator s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_rational_symbol)
24785 
24786   s7_pointer x;
24787   x = car(args);
24788   switch (type(x))
24789     {
24790     case T_RATIO:       return(make_integer(sc, denominator(x)));
24791     case T_INTEGER:     return(int_one);
24792 #if WITH_GMP
24793     case T_BIG_INTEGER: return(int_one);
24794     case T_BIG_RATIO:   return(mpz_to_integer(sc, mpq_denref(big_ratio(x))));
24795 #endif
24796     default:            return(method_or_bust_with_type_one_arg(sc, x, sc->denominator_symbol, args, a_rational_string));
24797     }
24798 }
24799 
24800 static s7_int denominator_i_7p(s7_scheme *sc, s7_pointer p)
24801 {
24802   if (is_t_ratio(p)) return(denominator(p));
24803   if (is_t_integer(p)) return(1);
24804 #if WITH_GMP
24805   if (is_t_big_ratio(p)) return(mpz_get_si(mpq_denref(big_ratio(p))));
24806   if (is_t_big_integer(p)) return(1);
24807 #endif
24808   return(integer(method_or_bust_with_type_one_arg_p(sc, p, sc->denominator_symbol, a_rational_string)));
24809 }
24810 
24811 
24812 /* ---------------------------------------- number? bignum? complex? integer? byte? rational? real?  ---------------------------------------- */
24813 
24814 static s7_pointer g_is_number(s7_scheme *sc, s7_pointer args)
24815 {
24816   #define H_is_number "(number? obj) returns #t if obj is a number"
24817   #define Q_is_number sc->pl_bt
24818   check_boolean_method(sc, s7_is_number, sc->is_number_symbol, args); /* we need the s7_* versions here for the GMP case */
24819 }
24820 
24821 bool s7_is_bignum(s7_pointer obj) {return(is_big_number(obj));}
24822 
24823 static s7_pointer g_is_bignum(s7_scheme *sc, s7_pointer args)
24824 {
24825   #define H_is_bignum "(bignum? obj) returns #t if obj is a multiprecision number."
24826   #define Q_is_bignum sc->pl_bt
24827   return(s7_make_boolean(sc, is_big_number(car(args))));
24828 }
24829 
24830 static s7_pointer g_is_integer(s7_scheme *sc, s7_pointer args)
24831 {
24832   #define H_is_integer "(integer? obj) returns #t if obj is an integer"
24833   #define Q_is_integer sc->pl_bt
24834   check_boolean_method(sc, s7_is_integer, sc->is_integer_symbol, args);
24835 }
24836 
24837 static bool is_byte(s7_pointer p) {return((s7_is_integer(p)) && (s7_integer(p) >= 0) && (s7_integer(p) < 256));}
24838 static s7_pointer g_is_byte(s7_scheme *sc, s7_pointer args)
24839 {
24840   #define H_is_byte "(byte? obj) returns #t if obj is a byte (an integer between 0 and 255)"
24841   #define Q_is_byte sc->pl_bt
24842   check_boolean_method(sc, is_byte, sc->is_byte_symbol, args);
24843 }
24844 
24845 static s7_pointer g_is_real(s7_scheme *sc, s7_pointer args)
24846 {
24847   #define H_is_real "(real? obj) returns #t if obj is a real number"
24848   #define Q_is_real sc->pl_bt
24849   check_boolean_method(sc, s7_is_real, sc->is_real_symbol, args);
24850 }
24851 
24852 static s7_pointer g_is_complex(s7_scheme *sc, s7_pointer args)
24853 {
24854   #define H_is_complex "(complex? obj) returns #t if obj is a number"
24855   #define Q_is_complex sc->pl_bt
24856   check_boolean_method(sc, s7_is_number, sc->is_complex_symbol, args);
24857 }
24858 
24859 static s7_pointer g_is_rational(s7_scheme *sc, s7_pointer args)
24860 {
24861   #define H_is_rational "(rational? obj) returns #t if obj is a rational number (either an integer or a ratio)"
24862   #define Q_is_rational sc->pl_bt
24863   check_boolean_method(sc, s7_is_rational, sc->is_rational_symbol, args);
24864   /* in the non-gmp case, (rational? 455702434782048082459/86885567283849955830) -> #f, not #t, and similarly for exact? etc. */
24865 }
24866 
24867 static s7_pointer g_is_float(s7_scheme *sc, s7_pointer args)
24868 {
24869   #define H_is_float "(float? x) returns #t is x is real and not rational."
24870   #define Q_is_float sc->pl_bt
24871   s7_pointer p;
24872   p = car(args);
24873 #if WITH_GMP
24874   return(make_boolean(sc, (is_t_real(p)) || (is_t_big_real(p)))); /* (float? pi) */
24875 #else
24876   return(make_boolean(sc, is_t_real(p)));
24877 #endif
24878 }
24879 
24880 #if WITH_GMP
24881 static bool is_float_b(s7_pointer p) {return((is_t_real(p)) || (is_t_big_real(p)));}
24882 #else
24883 static bool is_float_b(s7_pointer p) {return(is_t_real(p));}
24884 #endif
24885 
24886 
24887 /* ---------------------------------------- nan? ---------------------------------------- */
24888 static bool is_nan_b_7p(s7_scheme *sc, s7_pointer x)
24889 {
24890   switch (type(x))
24891     {
24892     case T_INTEGER:
24893     case T_RATIO:   return(false);
24894     case T_REAL:    return(is_NaN(real(x)));
24895     case T_COMPLEX: return((is_NaN(real_part(x))) || (is_NaN(imag_part(x))));
24896 #if WITH_GMP
24897     case T_BIG_INTEGER:
24898     case T_BIG_RATIO:   return(false);
24899     case T_BIG_REAL:    return(mpfr_nan_p(big_real(x)) != 0);
24900     case T_BIG_COMPLEX: return((mpfr_nan_p(mpc_realref(big_complex(x))) != 0) || (mpfr_nan_p(mpc_imagref(big_complex(x))) != 0));
24901 #endif
24902     default:
24903       if (s7_is_number(x))
24904 	return(method_or_bust_with_type_one_arg_p(sc, x, sc->is_nan_symbol, a_number_string) != sc->F);
24905     }
24906   return(false);
24907 }
24908 
24909 static s7_pointer g_is_nan(s7_scheme *sc, s7_pointer args)
24910 {
24911   #define H_is_nan "(nan? obj) returns #t if obj is a NaN"
24912   #define Q_is_nan sc->pl_bt
24913   return(make_boolean(sc, is_nan_b_7p(sc, car(args))));
24914 }
24915 
24916 
24917 /* ---------------------------------------- infinite? ---------------------------------------- */
24918 static bool is_infinite_b_7p(s7_scheme *sc, s7_pointer x)
24919 {
24920   switch (type(x))
24921     {
24922     case T_INTEGER:
24923     case T_RATIO:    return(false);
24924     case T_REAL:     return(is_inf(real(x)));
24925     case T_COMPLEX:  return((is_inf(real_part(x))) || (is_inf(imag_part(x))));
24926 #if WITH_GMP
24927     case T_BIG_INTEGER:
24928     case T_BIG_RATIO: return(false);
24929     case T_BIG_REAL:  return(mpfr_inf_p(big_real(x)) != 0);
24930     case T_BIG_COMPLEX:
24931       return((mpfr_inf_p(mpc_realref(big_complex(x))) != 0) ||
24932 	     (mpfr_inf_p(mpc_imagref(big_complex(x))) != 0));
24933 #endif
24934     default:
24935       if (s7_is_number(x))
24936 	return(method_or_bust_with_type_one_arg_p(sc, x, sc->is_infinite_symbol, a_number_string) != sc->F);
24937     }
24938   return(false);
24939 }
24940 
24941 static s7_pointer g_is_infinite(s7_scheme *sc, s7_pointer args)
24942 {
24943   #define H_is_infinite "(infinite? obj) returns #t if obj is an infinite real"
24944   #define Q_is_infinite sc->pl_bt
24945   return(make_boolean(sc, is_infinite_b_7p(sc, car(args))));
24946 }
24947 
24948 
24949 /* ---------------------------------------- even? odd?---------------------------------------- */
24950 
24951 static bool is_even_b_7p(s7_scheme *sc, s7_pointer p)
24952 {
24953   if (is_t_integer(p))
24954     return((integer(p) & 1) == 0);
24955 #if WITH_GMP
24956   if (is_t_big_integer(p))
24957     return(mpz_even_p(big_integer(p)));
24958 #endif
24959   simple_wrong_type_argument(sc, sc->is_even_symbol, p, T_INTEGER);
24960   return(false);
24961 }
24962 
24963 static bool is_even_i(s7_int i1) {return((i1 & 1) == 0);}
24964 
24965 static s7_pointer g_is_even(s7_scheme *sc, s7_pointer args)
24966 {
24967   #define H_is_even "(even? int) returns #t if the integer int32_t is even"
24968   #define Q_is_even s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_integer_symbol)
24969 
24970   s7_pointer p;
24971   p = car(args);
24972   if (is_t_integer(p))
24973     return(make_boolean(sc, ((integer(p) & 1) == 0)));
24974 #if WITH_GMP
24975   if (is_t_big_integer(p))
24976     return(make_boolean(sc, mpz_even_p(big_integer(p))));
24977 #endif
24978   return(method_or_bust_one_arg_p(sc, p, sc->is_even_symbol, T_INTEGER));
24979 }
24980 
24981 
24982 static s7_pointer g_is_odd(s7_scheme *sc, s7_pointer args)
24983 {
24984   #define H_is_odd "(odd? int) returns #t if the integer int32_t is odd"
24985   #define Q_is_odd s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_integer_symbol)
24986 
24987   s7_pointer p;
24988   p = car(args);
24989   if (is_t_integer(p))
24990     return(make_boolean(sc, ((integer(p) & 1) == 1)));
24991 #if WITH_GMP
24992   if (is_t_big_integer(p))
24993     return(make_boolean(sc, mpz_odd_p(big_integer(p))));
24994 #endif
24995   return(method_or_bust_one_arg_p(sc, p, sc->is_odd_symbol, T_INTEGER));
24996 }
24997 
24998 static bool is_odd_b_7p(s7_scheme *sc, s7_pointer p)
24999 {
25000   if (is_t_integer(p))
25001     return((integer(p) & 1) == 1);
25002 #if WITH_GMP
25003   if (is_t_big_integer(p))
25004     return(mpz_odd_p(big_integer(p)));
25005 #endif
25006   simple_wrong_type_argument(sc, sc->is_odd_symbol, p, T_INTEGER);
25007   return(false);
25008 }
25009 
25010 static bool is_odd_i(s7_int i1) {return((i1 & 1) == 1);}
25011 
25012 
25013 /* ---------------------------------------- zero? ---------------------------------------- */
25014 
25015 static s7_pointer g_is_zero(s7_scheme *sc, s7_pointer args)
25016 {
25017   #define H_is_zero "(zero? num) returns #t if the number num is zero"
25018   #define Q_is_zero sc->pl_bn
25019   s7_pointer x;
25020   x = car(args);
25021   switch (type(x))
25022     {
25023     case T_INTEGER:     return(make_boolean(sc, integer(x) == 0));
25024     case T_REAL:        return(make_boolean(sc, real(x) == 0.0));
25025     case T_RATIO:
25026     case T_COMPLEX:     return(sc->F);      /* ratios and complex numbers are already collapsed into integers and reals */
25027 #if WITH_GMP
25028     case T_BIG_INTEGER: return(make_boolean(sc, mpz_cmp_ui(big_integer(x), 0) == 0));
25029     case T_BIG_REAL:    return(make_boolean(sc, mpfr_zero_p(big_real(x))));
25030     case T_BIG_RATIO:
25031     case T_BIG_COMPLEX: return(sc->F);
25032 #endif
25033     default:
25034       return(method_or_bust_with_type_one_arg_p(sc, x, sc->is_zero_symbol, a_number_string));
25035     }
25036 }
25037 
25038 static bool is_zero_b_7p(s7_scheme *sc, s7_pointer p)
25039 {
25040 #if WITH_GMP
25041   if (!s7_is_number(p))
25042     simple_wrong_type_argument_with_type(sc, sc->is_zero_symbol, p, a_number_string);
25043   return(s7_is_zero(p));
25044 #else
25045   if (is_t_integer(p))
25046     return(integer(p) == 0);
25047   if (is_t_real(p))
25048     return(real(p) == 0.0);
25049   if (!is_number(p))
25050     simple_wrong_type_argument_with_type(sc, sc->is_zero_symbol, p, a_number_string);
25051   return(false);
25052 #endif
25053 }
25054 
25055 static s7_pointer is_zero_p_p(s7_scheme *sc, s7_pointer p)
25056 {
25057 #if WITH_GMP
25058   if (!s7_is_number(p))
25059     simple_wrong_type_argument_with_type(sc, sc->is_zero_symbol, p, a_number_string);
25060   return(make_boolean(sc, s7_is_zero(p)));
25061 #else
25062   if (is_t_integer(p))
25063     return(make_boolean(sc, integer(p) == 0));
25064   if (is_t_real(p))
25065     return(make_boolean(sc, real(p) == 0.0));
25066   if (!is_number(p))
25067     simple_wrong_type_argument_with_type(sc, sc->is_zero_symbol, p, a_number_string);
25068   return(sc->F);
25069 #endif
25070 }
25071 
25072 static bool is_zero_i(s7_int p) {return(p == 0);}
25073 static bool is_zero_d(s7_double p) {return(p == 0.0);}
25074 
25075 
25076 /* -------------------------------- positive? -------------------------------- */
25077 
25078 static s7_pointer g_is_positive(s7_scheme *sc, s7_pointer args)
25079 {
25080   #define H_is_positive "(positive? num) returns #t if the real number num is positive (greater than 0)"
25081   #define Q_is_positive s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_real_symbol)
25082   s7_pointer x;
25083   x = car(args);
25084   switch (type(x))
25085     {
25086     case T_INTEGER:     return(make_boolean(sc, integer(x) > 0));
25087     case T_RATIO:       return(make_boolean(sc, numerator(x) > 0));
25088     case T_REAL:        return(make_boolean(sc, real(x) > 0.0));
25089 #if WITH_GMP
25090     case T_BIG_INTEGER: return(make_boolean(sc, (mpz_cmp_ui(big_integer(x), 0) > 0)));
25091     case T_BIG_RATIO:   return(make_boolean(sc, (mpq_cmp_ui(big_ratio(x), 0, 1) > 0)));
25092     case T_BIG_REAL:    return(make_boolean(sc, (mpfr_cmp_ui(big_real(x), 0) > 0)));
25093 #endif
25094     default:
25095       return(method_or_bust_one_arg_p(sc, x, sc->is_positive_symbol, T_REAL));
25096     }
25097 }
25098 
25099 static bool is_positive_b_7p(s7_scheme *sc, s7_pointer p)
25100 {
25101 #if WITH_GMP
25102   if (!s7_is_real(p))
25103     simple_wrong_type_argument(sc, sc->is_positive_symbol, p, T_REAL);
25104   return(s7_is_positive(p));
25105 #else
25106   if (is_t_integer(p))
25107     return(integer(p) > 0);
25108   if (is_t_real(p))
25109     return(real(p) > 0.0);
25110   if (!is_small_real(p))
25111     simple_wrong_type_argument(sc, sc->is_positive_symbol, p, T_REAL);
25112   return(numerator(p) > 0);
25113 #endif
25114 }
25115 
25116 static s7_pointer is_positive_p_p(s7_scheme *sc, s7_pointer p)
25117 {
25118 #if WITH_GMP
25119   if (!s7_is_real(p))
25120     simple_wrong_type_argument(sc, sc->is_positive_symbol, p, T_REAL);
25121   return(make_boolean(sc, s7_is_positive(p)));
25122 #else
25123   if (is_t_integer(p))
25124     return((integer(p) > 0) ? sc->T : sc->F);
25125   if (is_t_real(p))
25126     return((real(p) > 0.0) ? sc->T : sc->F);
25127   if (!is_small_real(p))
25128     simple_wrong_type_argument(sc, sc->is_positive_symbol, p, T_REAL);
25129   return((numerator(p) > 0) ? sc->T : sc->F);
25130 #endif
25131 }
25132 
25133 static bool is_positive_i(s7_int p) {return(p > 0);}
25134 static bool is_positive_d(s7_double p) {return(p > 0.0);}
25135 
25136 
25137 /* -------------------------------- negative? -------------------------------- */
25138 
25139 static s7_pointer is_negative_p_p(s7_scheme *sc, s7_pointer x)
25140 {
25141   switch (type(x))
25142     {
25143     case T_INTEGER:     return(make_boolean(sc, integer(x) < 0));
25144     case T_RATIO:       return(make_boolean(sc, numerator(x) < 0));
25145     case T_REAL:        return(make_boolean(sc, real(x) < 0.0));
25146 #if WITH_GMP
25147     case T_BIG_INTEGER: return(make_boolean(sc, (mpz_cmp_ui(big_integer(x), 0) < 0)));
25148     case T_BIG_RATIO:   return(make_boolean(sc, (mpq_cmp_ui(big_ratio(x), 0, 1) < 0)));
25149     case T_BIG_REAL:    return(make_boolean(sc, (mpfr_cmp_ui(big_real(x), 0) < 0)));
25150 #endif
25151     default:
25152       return(method_or_bust_one_arg_p(sc, x, sc->is_negative_symbol, T_REAL));
25153     }
25154 }
25155 
25156 static s7_pointer g_is_negative(s7_scheme *sc, s7_pointer args)
25157 {
25158   #define H_is_negative "(negative? num) returns #t if the real number num is negative (less than 0)"
25159   #define Q_is_negative s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_real_symbol)
25160   return(is_negative_p_p(sc, car(args)));
25161 }
25162 
25163 static bool is_negative_b_7p(s7_scheme *sc, s7_pointer p)
25164 {
25165 #if WITH_GMP
25166   if (!s7_is_real(p))
25167     simple_wrong_type_argument(sc, sc->is_negative_symbol, p, T_REAL);
25168   return(s7_is_negative(p));
25169 #else
25170   if (is_t_integer(p))
25171     return(integer(p) < 0);
25172   if (is_t_real(p))
25173     return(real(p) < 0.0);
25174   if (!is_small_real(p))
25175     simple_wrong_type_argument(sc, sc->is_negative_symbol, p, T_REAL);
25176   return(numerator(p) < 0);
25177 #endif
25178 }
25179 
25180 static bool is_negative_i(s7_int p) {return(p < 0);}
25181 static bool is_negative_d(s7_double p) {return(p < 0.0);}
25182 
25183 
25184 #if (!WITH_PURE_S7)
25185 /* ---------------------------------------- exact<->inexact exact? inexact? ---------------------------------------- */
25186 static s7_pointer g_exact_to_inexact(s7_scheme *sc, s7_pointer args)
25187 {
25188   #define H_exact_to_inexact "(exact->inexact num) converts num to an inexact number; (exact->inexact 3/2) = 1.5"
25189   #define Q_exact_to_inexact s7_make_signature(sc, 2, sc->is_number_symbol, sc->is_number_symbol)
25190   /* arg can be complex -> itself! */
25191   return(exact_to_inexact(sc, car(args)));
25192 }
25193 
25194 static s7_pointer g_inexact_to_exact(s7_scheme *sc, s7_pointer args)
25195 {
25196   #define H_inexact_to_exact "(inexact->exact num) converts num to an exact number; (inexact->exact 1.5) = 3/2"
25197   #define Q_inexact_to_exact s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_real_symbol)
25198   return(inexact_to_exact(sc, car(args)));
25199 }
25200 
25201 static s7_pointer g_is_exact(s7_scheme *sc, s7_pointer args)
25202 {
25203   #define H_is_exact "(exact? num) returns #t if num is exact (an integer or a ratio)"
25204   #define Q_is_exact sc->pl_bn
25205 
25206   s7_pointer x;
25207   x = car(args);
25208   switch (type(x))
25209     {
25210     case T_INTEGER: case T_BIG_INTEGER:
25211     case T_RATIO:   case T_BIG_RATIO:
25212       return(sc->T);
25213     case T_REAL:    case T_BIG_REAL:
25214     case T_COMPLEX: case T_BIG_COMPLEX:
25215       return(sc->F);
25216     default:
25217       return(method_or_bust_with_type_one_arg(sc, x, sc->is_exact_symbol, args, a_number_string));
25218     }
25219 }
25220 
25221 static bool is_exact_b_7p(s7_scheme *sc, s7_pointer p)
25222 {
25223   if (!is_number(p))
25224     simple_wrong_type_argument_with_type(sc, sc->is_exact_symbol, p, a_number_string);
25225   return(is_rational(p));
25226 }
25227 
25228 
25229 static s7_pointer g_is_inexact(s7_scheme *sc, s7_pointer args)
25230 {
25231   #define H_is_inexact "(inexact? num) returns #t if num is inexact (neither an integer nor a ratio)"
25232   #define Q_is_inexact sc->pl_bn
25233 
25234   s7_pointer x;
25235   x = car(args);
25236   switch (type(x))
25237     {
25238     case T_INTEGER:  case T_BIG_INTEGER:
25239     case T_RATIO:    case T_BIG_RATIO:
25240       return(sc->F);
25241     case T_REAL:     case T_BIG_REAL:
25242     case T_COMPLEX:  case T_BIG_COMPLEX:
25243       return(sc->T);
25244     default:
25245       return(method_or_bust_with_type_one_arg(sc, x, sc->is_inexact_symbol, args, a_number_string));
25246     }
25247 }
25248 
25249 static bool is_inexact_b_7p(s7_scheme *sc, s7_pointer p)
25250 {
25251   if (!is_number(p))
25252     simple_wrong_type_argument_with_type(sc, sc->is_inexact_symbol, p, a_number_string);
25253   return(!is_rational(p));
25254 }
25255 
25256 
25257 /* ---------------------------------------- integer-length ---------------------------------------- */
25258 
25259 static int32_t integer_length(s7_int a)
25260 {
25261   #define I_8 256LL
25262   #define I_16 65536LL
25263   #define I_24 16777216LL
25264   #define I_32 4294967296LL
25265   #define I_40 1099511627776LL
25266   #define I_48 281474976710656LL
25267   #define I_56 72057594037927936LL
25268 
25269   /* a might be most-negative-fixnum! in Clisp: (integer-length -9223372036854775808) -> 63 */
25270   if (a < 0)
25271     {
25272       if (a == S7_INT64_MIN) return(63);
25273       a = -a;
25274     }
25275   if (a < I_8) return(intlen_bits[a]);
25276   if (a < I_16) return(8 + intlen_bits[a >> 8]);
25277   if (a < I_24) return(16 + intlen_bits[a >> 16]);
25278   if (a < I_32) return(24 + intlen_bits[a >> 24]);
25279   if (a < I_40) return(32 + intlen_bits[a >> 32]);
25280   if (a < I_48) return(40 + intlen_bits[a >> 40]);
25281   if (a < I_56) return(48 + intlen_bits[a >> 48]);
25282   return(56 + intlen_bits[a >> 56]);
25283 }
25284 
25285 static s7_pointer g_integer_length(s7_scheme *sc, s7_pointer args)
25286 {
25287   #define H_integer_length "(integer-length arg) returns the number of bits required to represent the integer 'arg': (ceiling (log (abs arg) 2))"
25288   #define Q_integer_length sc->pcl_i
25289 
25290   s7_pointer p;
25291   p = car(args);
25292 
25293   if (is_t_integer(p))
25294     {
25295       s7_int x;
25296       x = integer(p);
25297       return((x < 0) ? make_integer(sc, integer_length(-(x + 1))) : make_integer(sc, integer_length(x)));
25298     }
25299 #if WITH_GMP
25300   if (is_t_big_integer(p))
25301     return(make_integer(sc, mpz_sizeinbase(big_integer(p), 2)));
25302 #endif
25303   return(method_or_bust_one_arg(sc, p, sc->integer_length_symbol, args, T_INTEGER));
25304 }
25305 
25306 static s7_int integer_length_i_i(s7_int x)
25307 {
25308   return((x < 0) ? integer_length(-(x + 1)) : integer_length(x));
25309 }
25310 #endif /* !pure s7 */
25311 
25312 
25313 /* ---------------------------------------- integer-decode-float ---------------------------------------- */
25314 static s7_pointer g_integer_decode_float(s7_scheme *sc, s7_pointer args)
25315 {
25316   #define H_integer_decode_float "(integer-decode-float x) returns a list containing the significand, exponent, and \
25317 sign of 'x' (1 = positive, -1 = negative).  (integer-decode-float 0.0): (0 0 1)"
25318   #define Q_integer_decode_float s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_float_symbol)
25319 
25320   typedef union {
25321     int64_t ix;
25322     double fx;
25323   } decode_float_t;
25324 
25325   decode_float_t num;
25326   s7_pointer x;
25327   x = car(args);
25328 
25329   if (is_t_real(x))
25330     {
25331       if (real(x) == 0.0)
25332 	return(list_3(sc, int_zero, int_zero, int_one));
25333       num.fx = (double)real(x);
25334       return(list_3(sc,
25335 		    make_integer(sc, (s7_int)((num.ix & 0xfffffffffffffLL) | 0x10000000000000LL)),
25336 		    make_integer(sc, (s7_int)(((num.ix & 0x7fffffffffffffffLL) >> 52) - 1023 - 52)),
25337 		    make_integer(sc, ((num.ix & 0x8000000000000000LL) != 0) ? -1 : 1)));
25338     }
25339 #if WITH_GMP
25340   if (is_t_big_real(x))
25341     {
25342       mp_exp_t exp_n;
25343       bool neg;
25344       exp_n = mpfr_get_z_exp(sc->mpz_1, big_real(x));
25345       neg = (mpz_cmp_ui(sc->mpz_1, 0) < 0);
25346       if (neg) mpz_abs(sc->mpz_1, sc->mpz_1);
25347       return(list_3(sc, mpz_to_integer(sc, sc->mpz_1), make_integer(sc, exp_n), make_integer(sc, neg ? -1 : 1)));
25348       /* not gmp: (integer-decode-float +nan.0): (6755399441055744 972 1), gmp: (integer-decode-float (bignum +nan.0)): (0 -1073741823 1) */
25349     }
25350 #endif
25351 
25352   return(method_or_bust_with_type_one_arg(sc, x, sc->integer_decode_float_symbol, args, wrap_string(sc, "a non-rational real", 19)));
25353 }
25354 
25355 
25356 /* -------------------------------- logior -------------------------------- */
25357 #if WITH_GMP
25358 static s7_pointer big_logior(s7_scheme *sc, s7_int start, s7_pointer args)
25359 {
25360   s7_pointer x;
25361   mpz_set_si(sc->mpz_1, start);
25362 
25363   for (x = args; is_not_null(x); x = cdr(x))
25364     {
25365       s7_pointer i;
25366       i = car(x);
25367       switch (type(i))
25368 	{
25369 	case T_BIG_INTEGER:
25370 	  mpz_ior(sc->mpz_1, sc->mpz_1, big_integer(i));
25371 	  break;
25372 
25373 	case T_INTEGER:
25374 	  mpz_set_si(sc->mpz_2, integer(i));
25375 	  mpz_ior(sc->mpz_1, sc->mpz_1, sc->mpz_2);
25376 	  break;
25377 
25378 	default:
25379 	  if (!is_integer_via_method(sc, i))
25380 	    return(wrong_type_argument(sc, sc->logior_symbol, position_of(x, args), i, T_INTEGER));
25381 	  return(method_or_bust(sc, i, sc->logior_symbol,
25382 				set_ulist_1(sc, mpz_to_integer(sc, sc->mpz_1), x),
25383 				T_INTEGER, position_of(x, args)));
25384 	}}
25385   return(mpz_to_integer(sc, sc->mpz_1));
25386 }
25387 #endif
25388 
25389 static s7_pointer g_logior(s7_scheme *sc, s7_pointer args)
25390 {
25391   #define H_logior "(logior int32_t ...) returns the OR of its integer arguments (the bits that are on in any of the arguments)"
25392   #define Q_logior sc->pcl_i
25393   s7_int result = 0;
25394   s7_pointer x;
25395 
25396   for (x = args; is_not_null(x); x = cdr(x))
25397     {
25398 #if WITH_GMP
25399       if (is_t_big_integer(car(x)))
25400 	return(big_logior(sc, result, x));
25401 #endif
25402       if (!is_t_integer(car(x)))
25403 	return(method_or_bust(sc, car(x), sc->logior_symbol,
25404 			      (result == 0) ? x : set_ulist_1(sc, make_integer(sc, result), x),
25405 			      T_INTEGER, position_of(x, args)));
25406       result |= integer(car(x));
25407     }
25408   return(make_integer(sc, result));
25409 }
25410 
25411 static s7_int logior_i_ii(s7_int i1, s7_int i2) {return(i1 | i2);}
25412 static s7_int logior_i_iii(s7_int i1, s7_int i2, s7_int i3) {return(i1 | i2 | i3);}
25413 
25414 
25415 /* -------------------------------- logxor -------------------------------- */
25416 #if WITH_GMP
25417 static s7_pointer big_logxor(s7_scheme *sc, s7_int start, s7_pointer args)
25418 {
25419   s7_pointer x;
25420 
25421   mpz_set_si(sc->mpz_1, start);
25422   for (x = args; is_not_null(x); x = cdr(x))
25423     {
25424       s7_pointer i;
25425       i = car(x);
25426       switch (type(i))
25427 	{
25428 	case T_BIG_INTEGER:
25429 	  mpz_xor(sc->mpz_1, sc->mpz_1, big_integer(i));
25430 	  break;
25431 
25432 	case T_INTEGER:
25433 	  mpz_set_si(sc->mpz_2, integer(i));
25434 	  mpz_xor(sc->mpz_1, sc->mpz_1, sc->mpz_2);
25435 	  break;
25436 
25437 	default:
25438 	  if (!is_integer_via_method(sc, i))
25439 	    return(wrong_type_argument(sc, sc->logxor_symbol, position_of(x, args), i, T_INTEGER));
25440 	  return(method_or_bust(sc, i, sc->logxor_symbol,
25441 				set_ulist_1(sc, mpz_to_integer(sc, sc->mpz_1), x),
25442 				T_INTEGER, position_of(x, args)));
25443 	}}
25444   return(mpz_to_integer(sc, sc->mpz_1));
25445 }
25446 #endif
25447 
25448 static s7_pointer g_logxor(s7_scheme *sc, s7_pointer args)
25449 {
25450   #define H_logxor "(logxor int32_t ...) returns the XOR of its integer arguments (the bits that are on in an odd number of the arguments)"
25451   #define Q_logxor sc->pcl_i
25452   s7_int result = 0;
25453   s7_pointer x;
25454 
25455   for (x = args; is_not_null(x); x = cdr(x))
25456     {
25457 #if WITH_GMP
25458       if (is_t_big_integer(car(x)))
25459 	return(big_logxor(sc, result, x));
25460 #endif
25461       if (!is_t_integer(car(x)))
25462 	return(method_or_bust(sc, car(x), sc->logxor_symbol,
25463 			      (result == 0) ? x : set_ulist_1(sc, make_integer(sc, result), x),
25464 			      T_INTEGER, position_of(x, args)));
25465       result ^= integer(car(x));
25466     }
25467   return(make_integer(sc, result));
25468 }
25469 
25470 static s7_int logxor_i_ii(s7_int i1, s7_int i2) {return(i1 ^ i2);}
25471 static s7_int logxor_i_iii(s7_int i1, s7_int i2, s7_int i3) {return(i1 ^ i2 ^ i3);}
25472 
25473 
25474 /* -------------------------------- logand -------------------------------- */
25475 #if WITH_GMP
25476 static s7_pointer big_logand(s7_scheme *sc, s7_int start, s7_pointer args)
25477 {
25478   s7_pointer x;
25479 
25480   mpz_set_si(sc->mpz_1, start);
25481   for (x = args; is_not_null(x); x = cdr(x))
25482     {
25483       s7_pointer i;
25484       i = car(x);
25485       switch (type(i))
25486 	{
25487 	case T_BIG_INTEGER:
25488 	  mpz_and(sc->mpz_1, sc->mpz_1, big_integer(i));
25489 	  break;
25490 
25491 	case T_INTEGER:
25492 	  mpz_set_si(sc->mpz_2, integer(i));
25493 	  mpz_and(sc->mpz_1, sc->mpz_1, sc->mpz_2);
25494 	  break;
25495 
25496 	default:
25497 	  if (!is_integer_via_method(sc, i))
25498 	    return(wrong_type_argument(sc, sc->logand_symbol, position_of(x, args), i, T_INTEGER));
25499 	  return(method_or_bust(sc, i, sc->logand_symbol,
25500 				set_ulist_1(sc, mpz_to_integer(sc, sc->mpz_1), x),
25501 				T_INTEGER, position_of(x, args)));
25502 	}}
25503   return(mpz_to_integer(sc, sc->mpz_1));
25504 }
25505 #endif
25506 
25507 static s7_pointer g_logand(s7_scheme *sc, s7_pointer args)
25508 {
25509   #define H_logand "(logand int32_t ...) returns the AND of its integer arguments (the bits that are on in every argument)"
25510   #define Q_logand sc->pcl_i
25511   s7_int result = -1;
25512   s7_pointer x;
25513 
25514   for (x = args; is_not_null(x); x = cdr(x))
25515     {
25516 #if WITH_GMP
25517       if (is_t_big_integer(car(x)))
25518 	return(big_logand(sc, result, x));
25519 #endif
25520       if (!is_t_integer(car(x)))
25521 	return(method_or_bust(sc, car(x), sc->logand_symbol,
25522 			      (result == -1) ? x : set_ulist_1(sc, make_integer(sc, result), x),
25523 			      T_INTEGER, position_of(x, args)));
25524       result &= integer(car(x));
25525     }
25526   return(make_integer(sc, result));
25527 }
25528 
25529 static s7_int logand_i_ii(s7_int i1, s7_int i2) {return(i1 & i2);}
25530 static s7_int logand_i_iii(s7_int i1, s7_int i2, s7_int i3) {return(i1 & i2 & i3);}
25531 
25532 
25533 /* -------------------------------- lognot -------------------------------- */
25534 
25535 static s7_pointer g_lognot(s7_scheme *sc, s7_pointer args)
25536 {
25537   #define H_lognot "(lognot num) returns the negation of num (its complement, the bits that are not on): (lognot 0) -> -1"
25538   #define Q_lognot sc->pcl_i
25539   s7_pointer x;
25540 
25541   x = car(args);
25542   if (is_t_integer(x))
25543     return(make_integer(sc, ~integer(x)));
25544 
25545 #if WITH_GMP
25546   if (is_t_big_integer(x))
25547     {
25548       mpz_com(sc->mpz_1, big_integer(x));
25549       return(mpz_to_integer(sc, sc->mpz_1));
25550     }
25551 #endif
25552 
25553   return(method_or_bust_one_arg(sc, x, sc->lognot_symbol, args, T_INTEGER));
25554 }
25555 
25556 static s7_int lognot_i_i(s7_int i1) {return(~i1);}
25557 
25558 
25559 /* -------------------------------- logbit? -------------------------------- */
25560 /* logbit?  CL is (logbitp index int) using 2^index, but that order strikes me as backwards
25561  *   at least gmp got the arg order right!
25562  */
25563 
25564 static s7_pointer g_logbit(s7_scheme *sc, s7_pointer args)
25565 {
25566   #define H_logbit "(logbit? int index) returns #t if the index-th bit is on in int, otherwise #f. The argument \
25567 order here follows gmp, and is the opposite of the CL convention.  (logbit? int bit) is the same as (not (zero? (logand int (ash 1 bit))))."
25568   #define Q_logbit s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_integer_symbol)
25569 
25570   s7_pointer x, y;
25571   s7_int index;      /* index in gmp is mp_bitcnt which is an unsigned long int */
25572 
25573   x = car(args);
25574   y = cadr(args);
25575 
25576   if (!s7_is_integer(x))
25577     return(method_or_bust(sc, x, sc->logbit_symbol, args, T_INTEGER, 1));
25578   if (!s7_is_integer(y))
25579     return(method_or_bust(sc, y, sc->logbit_symbol, args, T_INTEGER, 2));
25580 
25581   index = s7_integer_checked(sc, y);
25582   if (index < 0)
25583     return(out_of_range(sc, sc->logbit_symbol, int_two, y, its_negative_string));
25584 
25585 #if WITH_GMP
25586   if (is_t_big_integer(x))
25587     return(make_boolean(sc, (mpz_tstbit(big_integer(x), index) != 0)));
25588 #endif
25589 
25590   if (index >= S7_INT_BITS)           /* not sure about the >: (logbit? -1 64) ?? */
25591     return(make_boolean(sc, integer(x) < 0));
25592 
25593   /* (zero? (logand most-positive-fixnum (ash 1 63))) -> ash argument 2, 63, is out of range (shift is too large)
25594    *   so logbit? has a wider range than the logand/ash shuffle above.
25595    */
25596 
25597   /* all these int64_ts are necessary, else C turns it into an int, gets confused about signs etc */
25598   return(make_boolean(sc, ((((int64_t)(1LL << (int64_t)index)) & (int64_t)integer(x)) != 0)));
25599 }
25600 
25601 static bool logbit_b_7ii(s7_scheme *sc, s7_int i1, s7_int i2)
25602 {
25603   if (i2 < 0)
25604     {
25605       out_of_range(sc, sc->logbit_symbol, int_two, wrap_integer1(sc, i1), its_negative_string);
25606       return(false);
25607     }
25608   if (i2 >= S7_INT_BITS)
25609     return(i1 < 0);
25610   return((((int64_t)(1LL << (int64_t)i2)) & (int64_t)i1) != 0);
25611 }
25612 
25613 static bool logbit_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
25614 {
25615   if (is_t_integer(p1))
25616     {
25617       if (is_t_integer(p2))
25618 	return(logbit_b_7ii(sc, integer(p1), integer(p2)));
25619       simple_wrong_type_argument(sc, sc->logbit_symbol, p2, T_INTEGER);
25620     }
25621 #if WITH_GMP
25622   return(g_logbit(sc, set_plist_2(sc, p1, p2)));
25623 #else
25624   simple_wrong_type_argument(sc, sc->logbit_symbol, p1, T_INTEGER);
25625   return(false);
25626 #endif
25627 }
25628 
25629 
25630 /* -------------------------------- ash -------------------------------- */
25631 static s7_int c_ash(s7_scheme *sc, s7_int arg1, s7_int arg2)
25632 {
25633   if (arg1 == 0) return(0);
25634 
25635   if (arg2 >= S7_INT_BITS)
25636     {
25637       if ((arg1 == -1) && (arg2 == 63))   /* (ash -1 63): most-negative-fixnum */
25638 	return(S7_INT64_MIN);
25639       out_of_range(sc, sc->ash_symbol, int_two, wrap_integer1(sc, arg2), its_too_large_string);
25640     }
25641 
25642   if (arg2 < -S7_INT_BITS)
25643     return((arg1 < 0) ? -1 : 0);        /* (ash -31 -100) */
25644 
25645   /* I can't see any point in protecting this: (ash 9223372036854775807 1) -> -2, but anyone using ash must know something about bits */
25646   if (arg2 >= 0)
25647     {
25648       if (arg1 < 0)
25649 	{
25650 	  uint64_t z;
25651 	  z = (uint64_t)arg1;
25652 	  return((s7_int)(z << arg2));
25653 	}
25654       return(arg1 << arg2);
25655     }
25656   return(arg1 >> -arg2);
25657 }
25658 
25659 static s7_pointer g_ash(s7_scheme *sc, s7_pointer args)
25660 {
25661   #define H_ash "(ash i1 i2) returns i1 shifted right or left i2 times, i1 << i2, (ash 1 3) -> 8, (ash 8 -3) -> 1"
25662   #define Q_ash sc->pcl_i
25663 
25664 #if WITH_GMP
25665   /* here, as in expt, there are cases like (ash 1 63) which need to be handled as bignums */
25666   s7_pointer p0, p1;
25667 
25668   p0 = car(args);
25669   p1 = cadr(args);
25670   /* here, as in expt, there are cases like (ash 1 63) which need to be handled as bignums so there's no easy way to tell when it's safe to drop into g_ash instead. */
25671   if ((s7_is_integer(p0)) && /* this includes bignum ints... */
25672       (s7_is_integer(p1)))
25673     {
25674       s7_int shift;
25675       bool p0_is_big;
25676       int32_t p0_compared_to_zero = 0;
25677 
25678       p0_is_big = is_big_number(p0);
25679       if (p0_is_big)
25680 	p0_compared_to_zero = mpz_cmp_ui(big_integer(p0), 0);
25681       else
25682 	{
25683 	  if (s7_integer_checked(sc, p0) > 0)
25684 	    p0_compared_to_zero = 1;
25685 	  else p0_compared_to_zero = (s7_integer_checked(sc, p0) < 0) ? -1 : 0;
25686 	}
25687 
25688       if (p0_compared_to_zero == 0)
25689 	return(int_zero);
25690 
25691       if (is_big_number(p1))
25692 	{
25693 	  if (!mpz_fits_sint_p(big_integer(p1)))
25694 	    {
25695 	      if (mpz_cmp_ui(big_integer(p1), 0) > 0)
25696 		return(out_of_range(sc, sc->ash_symbol, int_two, p1, its_too_large_string));
25697 
25698 	      /* here if p0 is negative, we need to return -1 */
25699 	      return((p0_compared_to_zero == 1) ? int_zero : minus_one);
25700 	    }
25701 	  shift = mpz_get_si(big_integer(p1));
25702 	}
25703       else
25704 	{
25705 	  shift = s7_integer_checked(sc, p1);
25706 	  if (shift < S7_INT32_MIN)
25707 	    return((p0_compared_to_zero == 1) ? int_zero : minus_one);
25708 	}
25709       if (shift > S7_INT32_MAX)
25710 	return(out_of_range(sc, sc->ash_symbol, int_two, p1, its_too_large_string)); /* gmp calls abort if overflow here */
25711 
25712       if (is_t_big_integer(p0))
25713 	mpz_set(sc->mpz_1, big_integer(p0));
25714       else mpz_set_si(sc->mpz_1, integer(p0));
25715 
25716       if (shift > 0)     /* left */
25717 	mpz_mul_2exp(sc->mpz_1, sc->mpz_1, shift);
25718       else
25719 	if (shift < 0) /* right */
25720 	  mpz_fdiv_q_2exp(sc->mpz_1, sc->mpz_1, (uint32_t)(-shift));
25721 
25722       return(mpz_to_integer(sc, sc->mpz_1));
25723     }
25724   /* else fall through */
25725 #endif
25726   s7_pointer x, y;
25727 
25728   x = car(args);
25729   if (!s7_is_integer(x))
25730     return(method_or_bust(sc, x, sc->ash_symbol, args, T_INTEGER, 1));
25731 
25732   y = cadr(args);
25733   if (!s7_is_integer(y))
25734     return(method_or_bust(sc, y, sc->ash_symbol, args, T_INTEGER, 2));
25735 
25736   return(make_integer(sc, c_ash(sc, s7_integer_checked(sc, x), s7_integer_checked(sc, y))));
25737 }
25738 
25739 #if (!WITH_GMP)
25740   static s7_int ash_i_7ii(s7_scheme *sc, s7_int i1, s7_int i2) {return(c_ash(sc, i1, i2));}
25741 #endif
25742 static s7_int lsh_i_ii_unchecked(s7_int i1, s7_int i2) {return(i1 << i2);} /* this may need gmp special handling, and out-of-range as in c_ash */
25743 static s7_int rsh_i_ii_unchecked(s7_int i1, s7_int i2) {return(i1 >> (-i2));}
25744 static s7_int rsh_i_i2_direct(s7_int i1, s7_int i2) {return(i1 >> 1);}
25745 
25746 
25747 /* -------------------------------- random-state -------------------------------- */
25748 /* random numbers.  The simple version used in clm.c is probably adequate,
25749  *   but here I'll use Marsaglia's MWC algorithm.
25750  *     (random num) -> a number (0..num), if num == 0 return 0, use global default state
25751  *     (random num state) -> same but use this state
25752  *     (random-state seed) -> make a new state
25753  *   to save the current seed, use copy
25754  *   to save it across load, random-state->list and list->random-state.
25755  *   random-state? returns #t if its arg is one of these guys
25756  */
25757 
25758 s7_pointer s7_random_state(s7_scheme *sc, s7_pointer args)
25759 {
25760   #define H_random_state "(random-state seed (carry plausible-default)) returns a new random number state initialized with 'seed'. \
25761 Pass this as the second argument to 'random' to get a repeatable random number sequence:\n\
25762     (let ((seed (random-state 1234))) (random 1.0 seed))"
25763   #define Q_random_state s7_make_circular_signature(sc, 1, 2, sc->is_random_state_symbol, sc->is_integer_symbol)
25764 
25765 #if WITH_GMP
25766   s7_pointer r, seed;
25767   seed = car(args);
25768   if (!s7_is_integer(seed))
25769     return(method_or_bust_one_arg(sc, seed, sc->random_state_symbol, args, T_INTEGER));
25770 
25771   if (is_t_integer(seed))
25772     seed = s7_int_to_big_integer(sc, integer(seed));
25773 
25774   new_cell(sc, r, T_RANDOM_STATE);
25775   gmp_randinit_default(random_gmp_state(r));            /* Mersenne twister */
25776   gmp_randseed(random_gmp_state(r), big_integer(seed)); /* this is ridiculously slow! */
25777   add_big_random_state(sc, r);
25778   return(r);
25779 #else
25780   s7_pointer r1, r2, p;
25781   s7_int i1, i2;
25782 
25783   r1 = car(args);
25784   if (!s7_is_integer(r1))
25785     return(method_or_bust(sc, r1, sc->random_state_symbol, args, T_INTEGER, 1));
25786   i1 = integer(r1);
25787   if (i1 < 0)
25788     return(out_of_range(sc, sc->random_state_symbol, int_one, r1, its_negative_string));
25789 
25790   if (is_null(cdr(args)))
25791     {
25792       new_cell(sc, p, T_RANDOM_STATE);
25793       random_seed(p) = (uint64_t)i1;
25794       random_carry(p) = 1675393560;                          /* should this be dependent on the seed? */
25795       return(p);
25796     }
25797 
25798   r2 = cadr(args);
25799   if (!s7_is_integer(r2))
25800     return(method_or_bust(sc, r2, sc->random_state_symbol, args, T_INTEGER, 2));
25801   i2 = integer(r2);
25802   if (i2 < 0)
25803     return(out_of_range(sc, sc->random_state_symbol, int_two, r2, its_negative_string));
25804 
25805   new_cell(sc, p, T_RANDOM_STATE);
25806   random_seed(p) = (uint64_t)i1;
25807   random_carry(p) = (uint64_t)i2;
25808   return(p);
25809 #endif
25810 }
25811 
25812 #define g_random_state s7_random_state
25813 
25814 static s7_pointer rng_copy(s7_scheme *sc, s7_pointer args)
25815 {
25816 #if WITH_GMP
25817   return(sc->F); /* I can't find a way to copy a gmp random generator */
25818 #else
25819   s7_pointer obj;
25820   obj = car(args);
25821   if (is_random_state(obj))
25822     {
25823       s7_pointer new_r;
25824       new_cell(sc, new_r, T_RANDOM_STATE);
25825       random_seed(new_r) = random_seed(obj);
25826       random_carry(new_r) = random_carry(obj);
25827       return(new_r);
25828     }
25829   return(sc->F);
25830 #endif
25831 }
25832 
25833 
25834 /* -------------------------------- random-state? -------------------------------- */
25835 static s7_pointer g_is_random_state(s7_scheme *sc, s7_pointer args)
25836 {
25837   #define H_is_random_state "(random-state? obj) returns #t if obj is a random-state object (from random-state)."
25838   #define Q_is_random_state sc->pl_bt
25839   check_boolean_method(sc, is_random_state, sc->is_random_state_symbol, args);
25840 }
25841 
25842 static bool is_random_state_b(s7_pointer p) {return(type(p) == T_RANDOM_STATE);}
25843 
25844 
25845 /* -------------------------------- random-state->list -------------------------------- */
25846 s7_pointer s7_random_state_to_list(s7_scheme *sc, s7_pointer args)
25847 {
25848   #define H_random_state_to_list "(random-state->list r) returns the random state object as a list.\
25849 You can later apply random-state to this list to continue a random number sequence from any point."
25850   #define Q_random_state_to_list s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_random_state_symbol)
25851 
25852 #if WITH_GMP
25853   if ((is_pair(args)) &&
25854       (!is_random_state(car(args))))
25855     return(method_or_bust_with_type(sc, car(args), sc->random_state_to_list_symbol, args, a_random_state_object_string, 1));
25856   return(sc->nil);
25857 #else
25858   s7_pointer r;
25859   if (is_null(args))
25860     r = sc->default_rng;
25861   else
25862     {
25863       r = car(args);
25864       if (!is_random_state(r))
25865 	return(method_or_bust_with_type(sc, r, sc->random_state_to_list_symbol, args, a_random_state_object_string, 1));
25866     }
25867   return(list_2(sc, make_integer(sc, random_seed(r)), make_integer(sc, random_carry(r))));
25868 #endif
25869 }
25870 
25871 #define g_random_state_to_list s7_random_state_to_list
25872 
25873 void s7_set_default_random_state(s7_scheme *sc, s7_int seed, s7_int carry)
25874 {
25875 #if (!WITH_GMP)
25876   s7_pointer p;
25877   new_cell(sc, p, T_RANDOM_STATE);
25878   random_seed(p) = (uint64_t)seed;
25879   random_carry(p) = (uint64_t)carry;
25880   sc->default_rng = p;
25881 #endif
25882 }
25883 
25884 
25885 /* -------------------------------- random -------------------------------- */
25886 
25887 #if WITH_GMP
25888 static double next_random(s7_scheme *sc)
25889 #else
25890 static double next_random(s7_pointer r)
25891 #endif
25892 {
25893 #if (!WITH_GMP)
25894   /* The multiply-with-carry generator for 32-bit integers:
25895    *        x(n)=a*x(n-1) + carry mod 2^32
25896    * Choose multiplier a from this list:
25897    *   1791398085 1929682203 1683268614 1965537969 1675393560
25898    *   1967773755 1517746329 1447497129 1655692410 1606218150
25899    *   2051013963 1075433238 1557985959 1781943330 1893513180
25900    *   1631296680 2131995753 2083801278 1873196400 1554115554
25901    * ( or any 'a' for which both a*2^32-1 and a*2^31-1 are prime)
25902    */
25903   double result;
25904   uint64_t temp;
25905   #define RAN_MULT 2131995753UL
25906 
25907   temp = random_seed(r) * RAN_MULT + random_carry(r);
25908   random_seed(r) = (temp & 0xffffffffUL);
25909   random_carry(r) = (temp >> 32);
25910   result = (double)((uint32_t)(random_seed(r))) / 4294967295.5;
25911   /* divisor was 2^32-1 = 4294967295.0, but somehow this can round up once in a billion tries?
25912    *   do we want the double just less than 2^32?
25913    */
25914 
25915   /* (let ((mx 0) (mn 1000)) (do ((i 0 (+ i 1))) ((= i 10000)) (let ((val (random 123))) (set! mx (max mx val)) (set! mn (min mn val)))) (list mn mx)) */
25916   return(result);
25917 #else
25918   mpfr_urandomb(sc->mpfr_1, random_gmp_state(sc->default_rng));
25919   return(mpfr_get_d(sc->mpfr_1, MPFR_RNDN));
25920 #endif
25921 }
25922 
25923 static s7_pointer g_random(s7_scheme *sc, s7_pointer args)
25924 {
25925   #define H_random "(random num (state #f)) returns a random number of the same type as num between zero and num, equalling num only if num is zero"
25926   #define Q_random s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_number_symbol, sc->is_random_state_symbol)
25927   s7_pointer r, num;
25928 
25929   /* if we disallow (random 0) the programmer has to protect every call on random with (if (eqv? x 0) 0 (random x)).  If
25930    *   we claim we're using a half-open interval, then we should also disallow (random 0.0); otherwise the following
25931    *   must be true: (let* ((x 0.0) (y (random x))) (and (>= y 0.0) (< y x))).  The definition above is consistent
25932    *   with (random 0) -> 0, simpler to use in practice, and certainly no worse than (/ 0 0) -> 1.
25933    */
25934   if (is_not_null(cdr(args)))
25935     {
25936       r = cadr(args);
25937       if (!is_random_state(r))
25938 	return(method_or_bust_with_type(sc, r, sc->random_symbol, args, a_random_state_object_string, 2));
25939     }
25940   else r = sc->default_rng;
25941 
25942   num = car(args);
25943   switch (type(num))
25944     {
25945 #if (!WITH_GMP)
25946     case T_INTEGER:
25947       return(make_integer(sc, (s7_int)(integer(num) * next_random(r))));
25948 
25949     case T_RATIO:
25950       {
25951 	s7_double x, error;
25952 	s7_int numer = 0, denom = 1;
25953 	/* the error here needs to take the size of the fraction into account.  Otherwise, if
25954 	 *    error is (say) 1e-6 and the fraction is (say) 9000000/9223372036854775807,
25955 	 *    c_rationalize will always return 0.  But even that isn't foolproof:
25956 	 *    (random 1/562949953421312) -> 1/376367230475000
25957 	 */
25958 	x = fraction(num);
25959 	if ((x < 1.0e-10) && (x > -1.0e-10))
25960 	  {
25961 	    /* 1e-12 is not tight enough:
25962 	     *    (random 1/2251799813685248) -> 1/2250240579436280
25963 	     *    (random -1/4503599627370496) -> -1/4492889778435526
25964 	     *    (random 1/140737488355328) -> 1/140730223985746
25965 	     *    (random -1/35184372088832) -> -1/35183145492420
25966 	     *    (random -1/70368744177664) -> -1/70366866392738
25967 	     *    (random 1/4398046511104) -> 1/4398033095756
25968 	     *    (random 1/137438953472) -> 1/137438941127
25969 	     */
25970 	    if (numerator(num) < -10)
25971 	      numer = -(s7_int)(floor(-numerator(num) * next_random(r)));
25972 	    else
25973 	      {
25974 		if (numerator(num) > 10)
25975 		  numer = (s7_int)floor(numerator(num) * next_random(r));
25976 		else
25977 		  {
25978 		    int64_t diff;
25979 		    numer = numerator(num);
25980 		    diff = S7_INT64_MAX - denominator(num);
25981 		    if (diff < 100)
25982 		      return(s7_make_ratio(sc, numer, denominator(num)));
25983 		    denom = denominator(num) + (s7_int)floor(diff * next_random(r));
25984 		    return(s7_make_ratio(sc, numer, denom));
25985 		  }}
25986 	    return(s7_make_ratio(sc, numer, denominator(num)));
25987 	  }
25988 	error = ((x < 1e-6) && (x > -1e-6)) ? 1e-18 : 1e-12;
25989 	c_rationalize(x * next_random(r), error, &numer, &denom);
25990 	return(s7_make_ratio(sc, numer, denom));
25991       }
25992 
25993     case T_REAL:
25994       return(make_real(sc, real(num) * next_random(r)));
25995 
25996     case T_COMPLEX:
25997       return(s7_make_complex(sc, real_part(num) * next_random(r), imag_part(num) * next_random(r)));
25998 
25999 #else
26000 
26001     case T_INTEGER:
26002       if (integer(num) == 0) return(int_zero);
26003       mpz_set_si(sc->mpz_1, integer(num));
26004       mpz_urandomm(sc->mpz_1, random_gmp_state(r), sc->mpz_1);
26005       if (integer(num) < 0) mpz_neg(sc->mpz_1, sc->mpz_1);
26006       return(make_integer(sc, mpz_get_si(sc->mpz_1)));
26007 
26008     case T_BIG_INTEGER:
26009       if (mpz_cmp_si(big_integer(num), 0) == 0) return(int_zero);
26010       mpz_urandomm(sc->mpz_1, random_gmp_state(r), big_integer(num));
26011       /* this does not work if num is a negative number -- you get positive results. so check num for sign, and negate result if necessary. */
26012       if (mpz_cmp_ui(big_integer(num), 0) < 0)
26013 	mpz_neg(sc->mpz_1, sc->mpz_1);
26014       return(mpz_to_integer(sc, sc->mpz_1));
26015 
26016     case T_RATIO:
26017       mpfr_urandomb(sc->mpfr_1, random_gmp_state(r));
26018       mpq_set_si(sc->mpq_1, numerator(num), denominator(num));
26019       mpfr_mul_q(sc->mpfr_1, sc->mpfr_1, sc->mpq_1, MPFR_RNDN);
26020       mpfr_mul_d(sc->mpfr_2, sc->mpfr_1, sc->default_rationalize_error, MPFR_RNDN);
26021       return(big_rationalize(sc, set_plist_2(sc, mpfr_to_big_real(sc, sc->mpfr_1), mpfr_to_big_real(sc, sc->mpfr_2))));
26022 
26023     case T_BIG_RATIO:
26024       mpfr_urandomb(sc->mpfr_1, random_gmp_state(r));
26025       mpfr_mul_q(sc->mpfr_1, sc->mpfr_1, big_ratio(num), MPFR_RNDN);
26026       mpfr_mul_d(sc->mpfr_2, sc->mpfr_1, sc->default_rationalize_error, MPFR_RNDN);
26027       return(big_rationalize(sc, set_plist_2(sc, mpfr_to_big_real(sc, sc->mpfr_1), mpfr_to_big_real(sc, sc->mpfr_2))));
26028 
26029     case T_REAL:
26030       mpfr_urandomb(sc->mpfr_1, random_gmp_state(r));
26031       mpfr_mul_d(sc->mpfr_1, sc->mpfr_1, real(num), MPFR_RNDN);
26032       return(make_real(sc, mpfr_get_d(sc->mpfr_1, MPFR_RNDN)));
26033 
26034     case T_BIG_REAL:
26035       mpfr_urandomb(sc->mpfr_1, random_gmp_state(r));
26036       mpfr_mul(sc->mpfr_1, sc->mpfr_1, big_real(num), MPFR_RNDN);
26037       return(mpfr_to_big_real(sc, sc->mpfr_1));
26038 
26039     case T_COMPLEX:
26040       mpc_urandom(sc->mpc_1, random_gmp_state(r));
26041       mpfr_mul_d(mpc_realref(sc->mpc_1), mpc_realref(sc->mpc_1), real_part(num), MPFR_RNDN);
26042       mpfr_mul_d(mpc_imagref(sc->mpc_1), mpc_imagref(sc->mpc_1), imag_part(num), MPFR_RNDN);
26043       return(s7_make_complex(sc, mpfr_get_d(mpc_realref(sc->mpc_1), MPFR_RNDN), mpfr_get_d(mpc_imagref(sc->mpc_1), MPFR_RNDN)));
26044 
26045     case T_BIG_COMPLEX:
26046       mpc_urandom(sc->mpc_1, random_gmp_state(r));
26047       mpfr_mul(mpc_realref(sc->mpc_1), mpc_realref(sc->mpc_1), mpc_realref(big_complex(num)), MPFR_RNDN);
26048       mpfr_mul(mpc_imagref(sc->mpc_1), mpc_imagref(sc->mpc_1), mpc_imagref(big_complex(num)), MPFR_RNDN);
26049       return(mpc_to_number(sc, sc->mpc_1));
26050 #endif
26051 
26052     default:
26053       return(method_or_bust_with_type(sc, num, sc->random_symbol, args, a_number_string, 1));
26054     }
26055   return(sc->F);
26056 }
26057 
26058 s7_double s7_random(s7_scheme *sc, s7_pointer state)
26059 {
26060 #if WITH_GMP
26061   mpfr_set_ui(sc->mpfr_1, 1, MPFR_RNDN);
26062   mpfr_urandomb(sc->mpfr_1, random_gmp_state((state) ? state : sc->default_rng));
26063   return((s7_double)mpfr_get_d(sc->mpfr_1, MPFR_RNDN));
26064 #else
26065   return(next_random((state) ? state : sc->default_rng));
26066 #endif
26067 }
26068 
26069 static s7_double random_d_7d(s7_scheme *sc, s7_double x)
26070 {
26071 #if WITH_GMP
26072   return(real(g_random(sc, set_plist_1(sc, wrap_real1(sc, x)))));
26073 #else
26074   return(x * next_random(sc->default_rng));
26075 #endif
26076 }
26077 
26078 static s7_int random_i_7i(s7_scheme *sc, s7_int i)
26079 {
26080 #if WITH_GMP
26081   return(integer(g_random(sc, set_plist_1(sc, wrap_integer1(sc, i)))));
26082 #else
26083   return((s7_int)(i * next_random(sc->default_rng)));
26084 #endif
26085 }
26086 
26087 static s7_pointer g_random_i(s7_scheme *sc, s7_pointer args)
26088 {
26089 #if WITH_GMP
26090   return(g_random(sc, args));
26091 #else
26092   return(make_integer(sc, (s7_int)(integer(car(args)) * next_random(sc->default_rng))));
26093 #endif
26094 }
26095 
26096 static s7_pointer g_random_f(s7_scheme *sc, s7_pointer args)
26097 {
26098 #if WITH_GMP
26099   return(g_random(sc, args));
26100 #else
26101   return(make_real(sc, real(car(args)) * next_random(sc->default_rng)));
26102 #endif
26103 }
26104 
26105 static s7_pointer g_random_1(s7_scheme *sc, s7_pointer args)
26106 {
26107 #if (!WITH_GMP)
26108   s7_pointer r, num;
26109   num = car(args);
26110   r = sc->default_rng;
26111   if (is_t_integer(num))
26112     return(make_integer(sc, (s7_int)(integer(num) * next_random(r))));
26113   if (is_t_real(num))
26114     return(make_real(sc, real(num) * next_random(r)));
26115 #endif
26116   return(g_random(sc, args));
26117 }
26118 
26119 static s7_pointer random_p_p(s7_scheme *sc, s7_pointer num)
26120 {
26121 #if (!WITH_GMP)
26122   if (is_t_integer(num))
26123     return(make_integer(sc, (s7_int)(integer(num) * next_random(sc->default_rng))));
26124   if (is_t_real(num))
26125     return(make_real(sc, real(num) * next_random(sc->default_rng)));
26126 #endif
26127   return(g_random(sc, set_plist_1(sc, num)));
26128 }
26129 
26130 static s7_pointer random_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
26131 {
26132   if (!ops) return(f);
26133   if (args == 1)
26134     {
26135       s7_pointer arg1;
26136       arg1 = cadr(expr);
26137       if (is_t_integer(arg1))
26138 	return(sc->random_i);
26139       return((is_t_real(arg1)) ? sc->random_f : sc->random_1);
26140     }
26141   return(f);
26142 }
26143 
26144 static s7_pointer g_add_i_random(s7_scheme *sc, s7_pointer args)
26145 {
26146 #if WITH_GMP
26147   return(add_p_pp(sc, car(args), random_p_p(sc, cadadr(args))));
26148 #else
26149   s7_int x, y;
26150   x = integer(car(args));
26151   y = integer(opt3_int(args)); /* cadadr */
26152   return(make_integer(sc, x + (s7_int)(y * next_random(sc->default_rng)))); /* (+ -1 (random 1)) -- placement of the (s7_int) cast matters! */
26153 #endif
26154 }
26155 
26156 
26157 /* -------------------------------- characters -------------------------------- */
26158 /* -------------------------------- char<->integer -------------------------------- */
26159 static s7_pointer g_char_to_integer(s7_scheme *sc, s7_pointer args)
26160 {
26161   #define H_char_to_integer "(char->integer c) converts the character c to an integer"
26162   #define Q_char_to_integer s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_char_symbol)
26163 
26164   if (!s7_is_character(car(args)))
26165     return(method_or_bust_one_arg(sc, car(args), sc->char_to_integer_symbol, args, T_CHARACTER));
26166   return(small_int(character(car(args))));
26167 }
26168 
26169 static s7_int char_to_integer_i_7p(s7_scheme *sc, s7_pointer p)
26170 {
26171   if (!s7_is_character(p))
26172     return(integer(method_or_bust_one_arg_p(sc, p, sc->char_to_integer_symbol, T_CHARACTER)));
26173   return(character(p));
26174 }
26175 
26176 static s7_pointer integer_to_char_p_p(s7_scheme *sc, s7_pointer x)
26177 {
26178   s7_int ind;
26179   if (!s7_is_integer(x))
26180     return(method_or_bust_one_arg_p(sc, x, sc->integer_to_char_symbol, T_INTEGER));
26181   ind = s7_integer_checked(sc, x);
26182   if ((ind >= 0) && (ind < NUM_CHARS))
26183     return(s7_make_character(sc, (uint8_t)ind));
26184   return(s7_out_of_range_error(sc, "integer->char", 1, x, "it doen't fit in an unsigned byte"));
26185 }
26186 
26187 static s7_pointer g_integer_to_char(s7_scheme *sc, s7_pointer args)
26188 {
26189   #define H_integer_to_char "(integer->char i) converts the non-negative integer i to a character"
26190   #define Q_integer_to_char s7_make_signature(sc, 2, sc->is_char_symbol, sc->is_integer_symbol)
26191   return(integer_to_char_p_p(sc, car(args)));
26192 }
26193 
26194 static s7_pointer integer_to_char_p_i(s7_scheme *sc, s7_int ind)
26195 {
26196   if ((ind >= 0) && (ind < NUM_CHARS))
26197     return(s7_make_character(sc, (uint8_t)ind));
26198   return(s7_out_of_range_error(sc, "integer->char", 1, wrap_integer2(sc, ind), "it doen't fit in an unsigned byte")); /* int2 s7_out... uses 1 */
26199 }
26200 
26201 
26202 static uint8_t uppers[256], lowers[256];
26203 static void init_uppers(void)
26204 {
26205   int32_t i;
26206   for (i = 0; i < 256; i++)
26207     {
26208       uppers[i] = (uint8_t)toupper(i);
26209       lowers[i] = (uint8_t)tolower(i);
26210     }
26211 }
26212 
26213 static void init_chars(void)
26214 {
26215   s7_cell *cells;
26216   int32_t i;
26217 
26218   chars = (s7_pointer *)malloc((NUM_CHARS + 1) * sizeof(s7_pointer)); /* chars is declared far above */
26219   cells = (s7_cell *)calloc(NUM_CHARS + 1, sizeof(s7_cell));
26220 
26221   chars[0] = &cells[0];
26222   eof_object = chars[0];
26223   set_full_type(eof_object, T_EOF | T_IMMUTABLE | T_UNHEAP);
26224   eof_name_length(eof_object) = 6;
26225   eof_name(eof_object) = "#<eof>";
26226   chars++;                    /* now chars[EOF] == chars[-1] == #<eof> */
26227   cells++;
26228 
26229   for (i = 0; i < NUM_CHARS; i++)
26230     {
26231       s7_pointer cp;
26232       uint8_t c;
26233 
26234       c = (uint8_t)i;
26235       cp = &cells[i];
26236       set_type_bit(cp, T_IMMUTABLE | T_CHARACTER | T_UNHEAP);
26237       set_optimize_op(cp, OP_CON);
26238       character(cp) = c;
26239       upper_character(cp) = (uint8_t)toupper(i);
26240       is_char_alphabetic(cp) = (bool)isalpha(i);
26241       is_char_numeric(cp) = (bool)isdigit(i);
26242       is_char_whitespace(cp) = white_space[i];
26243       is_char_uppercase(cp) = (((bool)isupper(i)) || ((i >= 192) && (i < 208)));
26244       is_char_lowercase(cp) = (bool)islower(i);
26245       chars[i] = cp;
26246 
26247       #define make_character_name(S) memcpy((void *)(&(character_name(cp))), (const void *)(S), character_name_length(cp) = strlen(S))
26248       switch (c)
26249 	{
26250 	case ' ':	 make_character_name("#\\space");     break;
26251 	case '\n':       make_character_name("#\\newline");   break;
26252 	case '\r':       make_character_name("#\\return");    break;
26253 	case '\t':       make_character_name("#\\tab");       break;
26254 	case '\0':       make_character_name("#\\null");      break;
26255 	case (char)0x1b: make_character_name("#\\escape");    break;
26256 	case (char)0x7f: make_character_name("#\\delete");    break;
26257 	case (char)7:    make_character_name("#\\alarm");     break;
26258 	case (char)8:    make_character_name("#\\backspace"); break;
26259 	default:
26260 	  {
26261             #define P_SIZE 12
26262 	    int32_t len;
26263 	    if ((c < 32) || (c >= 127))
26264 	      len = snprintf((char *)(&(character_name(cp))), P_SIZE, "#\\x%x", c);
26265 	    else len = snprintf((char *)(&(character_name(cp))), P_SIZE, "#\\%c", c);
26266 	    character_name_length(cp) = len;
26267 	    break;
26268           }}}
26269 }
26270 
26271 
26272 /* -------------------------------- char-upcase, char-downcase ----------------------- */
26273 static s7_pointer char_upcase_p_p(s7_scheme *sc, s7_pointer c)
26274 {
26275   if (!s7_is_character(c))
26276     return(method_or_bust_one_arg_p(sc, c, sc->char_upcase_symbol, T_CHARACTER));
26277   return(s7_make_character(sc, upper_character(c)));
26278 }
26279 
26280 static s7_pointer char_upcase_p_p_unchecked(s7_scheme *sc, s7_pointer c) {return(s7_make_character(sc, upper_character(c)));}
26281 
26282 static s7_pointer g_char_upcase(s7_scheme *sc, s7_pointer args)
26283 {
26284   #define H_char_upcase "(char-upcase c) converts the character c to upper case"
26285   #define Q_char_upcase sc->pcl_c
26286   return(char_upcase_p_p(sc, car(args)));
26287 }
26288 
26289 static s7_pointer g_char_downcase(s7_scheme *sc, s7_pointer args)
26290 {
26291   #define H_char_downcase "(char-downcase c) converts the character c to lower case"
26292   #define Q_char_downcase sc->pcl_c
26293   if (!s7_is_character(car(args)))
26294     return(method_or_bust_one_arg(sc, car(args), sc->char_downcase_symbol, args, T_CHARACTER));
26295   return(s7_make_character(sc, lowers[character(car(args))]));
26296 }
26297 
26298 
26299 /* -------------------------------- char-alphabetic? char-numeric? char-whitespace? -------------------------------- */
26300 static s7_pointer g_is_char_alphabetic(s7_scheme *sc, s7_pointer args)
26301 {
26302   #define H_is_char_alphabetic "(char-alphabetic? c) returns #t if the character c is alphabetic"
26303   #define Q_is_char_alphabetic sc->pl_bc
26304   if (!s7_is_character(car(args)))
26305     return(method_or_bust_one_arg(sc, car(args), sc->is_char_alphabetic_symbol, args, T_CHARACTER));
26306   return(make_boolean(sc, is_char_alphabetic(car(args))));
26307 
26308   /* isalpha returns #t for (integer->char 226) and others in that range */
26309 }
26310 
26311 static bool is_char_alphabetic_b_7p(s7_scheme *sc, s7_pointer c)
26312 {
26313   if (!s7_is_character(c))
26314     simple_wrong_type_argument(sc, sc->is_char_alphabetic_symbol, c, T_CHARACTER);
26315   return(is_char_alphabetic(c));
26316 }
26317 
26318 static s7_pointer is_char_alphabetic_p_p(s7_scheme *sc, s7_pointer c)
26319 {
26320   if (!s7_is_character(c))
26321     simple_wrong_type_argument(sc, sc->is_char_alphabetic_symbol, c, T_CHARACTER);
26322   return(make_boolean(sc, is_char_alphabetic(c)));
26323 }
26324 
26325 static s7_pointer g_is_char_numeric(s7_scheme *sc, s7_pointer args)
26326 {
26327   s7_pointer arg;
26328   #define H_is_char_numeric "(char-numeric? c) returns #t if the character c is a digit"
26329   #define Q_is_char_numeric sc->pl_bc
26330 
26331   arg = car(args);
26332   if (!s7_is_character(arg))
26333     return(method_or_bust_one_arg(sc, arg, sc->is_char_numeric_symbol, args, T_CHARACTER));
26334   return(make_boolean(sc, is_char_numeric(arg)));
26335 }
26336 
26337 static bool is_char_numeric_b_7p(s7_scheme *sc, s7_pointer c)
26338 {
26339   if (!s7_is_character(c))
26340     simple_wrong_type_argument(sc, sc->is_char_numeric_symbol, c, T_CHARACTER);
26341   return(is_char_numeric(c));
26342 }
26343 
26344 
26345 static s7_pointer g_is_char_whitespace(s7_scheme *sc, s7_pointer args)
26346 {
26347   s7_pointer arg;
26348   #define H_is_char_whitespace "(char-whitespace? c) returns #t if the character c is non-printing character"
26349   #define Q_is_char_whitespace sc->pl_bc
26350 
26351   arg = car(args);
26352   if (!s7_is_character(arg))
26353     return(method_or_bust_one_arg(sc, arg, sc->is_char_whitespace_symbol, args, T_CHARACTER));
26354   return(make_boolean(sc, is_char_whitespace(arg)));
26355 }
26356 
26357 static bool is_char_whitespace_b_7p(s7_scheme *sc, s7_pointer c)
26358 {
26359   if (s7_is_character(c))
26360     return(is_char_whitespace(c));
26361   if (has_active_methods(sc, c))
26362     {
26363       s7_pointer f;
26364       f = find_method_with_let(sc, c, sc->is_char_whitespace_symbol);
26365       if (f != sc->undefined)
26366 	return(is_true(sc, call_method(sc, c, f, set_plist_1(sc, c))));
26367     }
26368   simple_wrong_type_argument(sc, sc->is_char_whitespace_symbol, c, T_CHARACTER);
26369   return(false);
26370 }
26371 
26372 static s7_pointer is_char_whitespace_p_p(s7_scheme *sc, s7_pointer c)
26373 {
26374   if (!s7_is_character(c))
26375     simple_wrong_type_argument(sc, sc->is_char_whitespace_symbol, c, T_CHARACTER);
26376   return(make_boolean(sc, is_char_whitespace(c)));
26377 }
26378 
26379 static s7_pointer is_char_whitespace_p_p_unchecked(s7_scheme *sc, s7_pointer c) {return(make_boolean(sc, is_char_whitespace(c)));}
26380 
26381 
26382 /* -------------------------------- char-upper-case? char-lower-case? -------------------------------- */
26383 static s7_pointer g_is_char_upper_case(s7_scheme *sc, s7_pointer args)
26384 {
26385   s7_pointer arg;
26386   #define H_is_char_upper_case "(char-upper-case? c) returns #t if the character c is in upper case"
26387   #define Q_is_char_upper_case sc->pl_bc
26388 
26389   arg = car(args);
26390   if (!s7_is_character(arg))
26391     return(method_or_bust_one_arg(sc, arg, sc->is_char_upper_case_symbol, args, T_CHARACTER));
26392   return(make_boolean(sc, is_char_uppercase(arg)));
26393 }
26394 
26395 static bool is_char_upper_case_b_7p(s7_scheme *sc, s7_pointer c)
26396 {
26397   if (!s7_is_character(c))
26398     simple_wrong_type_argument(sc, sc->is_char_upper_case_symbol, c, T_CHARACTER);
26399   return(is_char_uppercase(c));
26400 }
26401 
26402 static s7_pointer g_is_char_lower_case(s7_scheme *sc, s7_pointer args)
26403 {
26404   s7_pointer arg;
26405   #define H_is_char_lower_case "(char-lower-case? c) returns #t if the character c is in lower case"
26406   #define Q_is_char_lower_case sc->pl_bc
26407 
26408   arg = car(args);
26409   if (!s7_is_character(arg))
26410     return(method_or_bust_one_arg(sc, arg, sc->is_char_lower_case_symbol, args, T_CHARACTER));
26411   return(make_boolean(sc, is_char_lowercase(arg)));
26412 }
26413 
26414 static bool is_char_lower_case_b_7p(s7_scheme *sc, s7_pointer c)
26415 {
26416   if (!s7_is_character(c))
26417     simple_wrong_type_argument(sc, sc->is_char_lower_case_symbol, c, T_CHARACTER);
26418   return(is_char_lowercase(c));
26419 }
26420 
26421 
26422 /* -------------------------------- char? -------------------------------- */
26423 static s7_pointer g_is_char(s7_scheme *sc, s7_pointer args)
26424 {
26425   #define H_is_char "(char? obj) returns #t if obj is a character"
26426   #define Q_is_char sc->pl_bt
26427   check_boolean_method(sc, s7_is_character, sc->is_char_symbol, args);
26428 }
26429 
26430 s7_pointer s7_make_character(s7_scheme *sc, uint8_t c) {return(chars[c]);}
26431 bool s7_is_character(s7_pointer p) {return(type(p) == T_CHARACTER);}
26432 uint8_t s7_character(s7_pointer p) {return(character(p));}
26433 
26434 
26435 /* -------------------------------- char<? char<=? char>? char>=? char=? -------------------------------- */
26436 static int32_t charcmp(uint8_t c1, uint8_t c2)
26437 {
26438   return((c1 == c2) ? 0 : (c1 < c2) ? -1 : 1);
26439   /* not tolower here -- the single case is apparently supposed to be upper case
26440    *   this matters in a case like (char-ci<? #\_ #\e) which Guile and Gauche say is #f
26441    *   although (char<? #\_ #\e) is #t -- the spec does not say how to interpret this!
26442    */
26443 }
26444 
26445 static bool is_character_via_method(s7_scheme *sc, s7_pointer p)
26446 {
26447   if (s7_is_character(p))
26448     return(true);
26449   if (has_active_methods(sc, p))
26450     {
26451       s7_pointer f;
26452       f = find_method_with_let(sc, p, sc->is_char_symbol);
26453       if (f != sc->undefined)
26454 	return(is_true(sc, call_method(sc, p, f, set_plist_1(sc, p))));
26455     }
26456   return(false);
26457 }
26458 
26459 static s7_pointer char_with_error_check(s7_scheme *sc, s7_pointer x, s7_pointer args, s7_pointer caller)
26460 {
26461   s7_pointer y;
26462   for (y = cdr(x); is_pair(y); y = cdr(y)) /* before returning #f, check for bad trailing arguments */
26463     if (!is_character_via_method(sc, car(y)))
26464       return(wrong_type_argument(sc, caller, position_of(y, args), car(y), T_CHARACTER));
26465   return(sc->F);
26466 }
26467 
26468 static s7_pointer g_char_cmp(s7_scheme *sc, s7_pointer args, int32_t val, s7_pointer sym)
26469 {
26470   s7_pointer x, y;
26471 
26472   y = car(args);
26473   if (!s7_is_character(y))
26474     return(method_or_bust(sc, y, sym, args, T_CHARACTER, 1));
26475 
26476   for (x = cdr(args); is_pair(x); y = car(x), x = cdr(x))
26477     {
26478       if (!s7_is_character(car(x)))
26479 	return(method_or_bust(sc, car(x), sym, set_ulist_1(sc, y, x), T_CHARACTER, position_of(x, args)));
26480       if (charcmp(character(y), character(car(x))) != val)
26481 	return(char_with_error_check(sc, x, args, sym));
26482     }
26483   return(sc->T);
26484 }
26485 
26486 static s7_pointer g_char_cmp_not(s7_scheme *sc, s7_pointer args, int32_t val, s7_pointer sym)
26487 {
26488   s7_pointer x, y;
26489 
26490   y = car(args);
26491   if (!s7_is_character(y))
26492     return(method_or_bust(sc, y, sym, args, T_CHARACTER, 1));
26493 
26494   for (x = cdr(args); is_pair(x); y = car(x), x = cdr(x))
26495     {
26496       if (!s7_is_character(car(x)))
26497 	return(method_or_bust(sc, car(x), sym, set_ulist_1(sc, y, x), T_CHARACTER, position_of(x, args)));
26498       if (charcmp(character(y), character(car(x))) == val)
26499 	return(char_with_error_check(sc, x, args, sym));
26500     }
26501   return(sc->T);
26502 }
26503 
26504 static s7_pointer g_chars_are_equal(s7_scheme *sc, s7_pointer args)
26505 {
26506   #define H_chars_are_equal "(char=? char ...) returns #t if all the character arguments are equal"
26507   #define Q_chars_are_equal sc->pcl_bc
26508 
26509   s7_pointer x, y;
26510 
26511   y = car(args);
26512   if (!s7_is_character(y))
26513     return(method_or_bust(sc, y, sc->char_eq_symbol, args, T_CHARACTER, 1));
26514 
26515   for (x = cdr(args); is_pair(x); x = cdr(x))
26516     {
26517       if (!s7_is_character(car(x)))
26518 	return(method_or_bust(sc, car(x), sc->char_eq_symbol, set_ulist_1(sc, y, x), T_CHARACTER, position_of(x, args)));
26519       if (car(x) != y)
26520 	return(char_with_error_check(sc, x, args, sc->char_eq_symbol));
26521     }
26522   return(sc->T);
26523 }
26524 
26525 
26526 static s7_pointer g_chars_are_less(s7_scheme *sc, s7_pointer args)
26527 {
26528   #define H_chars_are_less "(char<? char ...) returns #t if all the character arguments are increasing"
26529   #define Q_chars_are_less sc->pcl_bc
26530 
26531   return(g_char_cmp(sc, args, -1, sc->char_lt_symbol));
26532 }
26533 
26534 static s7_pointer g_chars_are_greater(s7_scheme *sc, s7_pointer args)
26535 {
26536   #define H_chars_are_greater "(char>? char ...) returns #t if all the character arguments are decreasing"
26537   #define Q_chars_are_greater sc->pcl_bc
26538 
26539   return(g_char_cmp(sc, args, 1, sc->char_gt_symbol));
26540 }
26541 
26542 static s7_pointer g_chars_are_geq(s7_scheme *sc, s7_pointer args)
26543 {
26544   #define H_chars_are_geq "(char>=? char ...) returns #t if all the character arguments are equal or decreasing"
26545   #define Q_chars_are_geq sc->pcl_bc
26546 
26547   return(g_char_cmp_not(sc, args, -1, sc->char_geq_symbol));
26548 }
26549 
26550 static s7_pointer g_chars_are_leq(s7_scheme *sc, s7_pointer args)
26551 {
26552   #define H_chars_are_leq "(char<=? char ...) returns #t if all the character arguments are equal or increasing"
26553   #define Q_chars_are_leq sc->pcl_bc
26554 
26555   return(g_char_cmp_not(sc, args, 1, sc->char_leq_symbol));
26556 }
26557 
26558 static s7_pointer g_simple_char_eq(s7_scheme *sc, s7_pointer args)
26559 {
26560   return(make_boolean(sc, character(car(args)) == character(cadr(args))));
26561 }
26562 
26563 
26564 static inline void check_char2_args(s7_scheme *sc, s7_pointer caller, s7_pointer p1, s7_pointer p2)
26565 {
26566   if (!s7_is_character(p1))
26567     simple_wrong_type_argument(sc, caller, p1, T_CHARACTER);
26568   if (!s7_is_character(p2))
26569     simple_wrong_type_argument(sc, caller, p2, T_CHARACTER);
26570 }
26571 
26572 static bool char_lt_b_unchecked(s7_pointer p1, s7_pointer p2) {return(character(p1) < character(p2));}
26573 static bool char_lt_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26574 {
26575   check_char2_args(sc, sc->char_lt_symbol, p1, p2);
26576   return(character(p1) < character(p2));
26577 }
26578 
26579 static bool char_leq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(character(p1) <= character(p2));}
26580 static bool char_leq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26581 {
26582   check_char2_args(sc, sc->char_leq_symbol, p1, p2);
26583   return(character(p1) <= character(p2));
26584 }
26585 
26586 static bool char_gt_b_unchecked(s7_pointer p1, s7_pointer p2) {return(character(p1) > character(p2));}
26587 static bool char_gt_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26588 {
26589   check_char2_args(sc, sc->char_gt_symbol, p1, p2);
26590   return(character(p1) > character(p2));
26591 }
26592 
26593 static bool char_geq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(character(p1) >= character(p2));}
26594 static bool char_geq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26595 {
26596   check_char2_args(sc, sc->char_geq_symbol, p1, p2);
26597   return(character(p1) >= character(p2));
26598 }
26599 
26600 static bool char_eq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(character(p1) == character(p2));}
26601 
26602 static bool char_eq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26603 {
26604   check_char2_args(sc, sc->char_eq_symbol, p1, p2);
26605   return(character(p1) == character(p2));
26606 }
26607 
26608 static s7_pointer char_eq_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26609 {
26610   check_char2_args(sc, sc->char_eq_symbol, p1, p2);
26611   return(make_boolean(sc, character(p1) == character(p2)));
26612 }
26613 
26614 static s7_pointer g_char_equal_2(s7_scheme *sc, s7_pointer args)
26615 {
26616   if (!s7_is_character(car(args)))
26617     return(method_or_bust(sc, car(args), sc->char_eq_symbol, args, T_CHARACTER, 1));
26618   if (car(args) == cadr(args))
26619     return(sc->T);
26620   if (!s7_is_character(cadr(args)))
26621     return(method_or_bust(sc, cadr(args), sc->char_eq_symbol, args, T_CHARACTER, 2));
26622   return(sc->F);
26623 }
26624 
26625 static s7_pointer g_char_less_2(s7_scheme *sc, s7_pointer args)
26626 {
26627   if (!s7_is_character(car(args)))
26628     return(method_or_bust(sc, car(args), sc->char_lt_symbol, args, T_CHARACTER, 1));
26629   if (!s7_is_character(cadr(args)))
26630     return(method_or_bust(sc, cadr(args), sc->char_lt_symbol, args, T_CHARACTER, 2));
26631   return(make_boolean(sc, character(car(args)) < character(cadr(args))));
26632 }
26633 
26634 static s7_pointer g_char_greater_2(s7_scheme *sc, s7_pointer args)
26635 {
26636   if (!s7_is_character(car(args)))
26637     return(method_or_bust(sc, car(args), sc->char_gt_symbol, args, T_CHARACTER, 1));
26638   if (!s7_is_character(cadr(args)))
26639     return(method_or_bust(sc, cadr(args), sc->char_gt_symbol, args, T_CHARACTER, 2));
26640   return(make_boolean(sc, character(car(args)) > character(cadr(args))));
26641 }
26642 
26643 static bool returns_char(s7_scheme *sc, s7_pointer arg)
26644 {
26645   return(argument_type(sc, arg) == sc->is_char_symbol);
26646 }
26647 
26648 static s7_pointer char_equal_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
26649 {
26650   if (args == 2)
26651     {
26652       if (ops)
26653 	{
26654 	  s7_pointer arg1, arg2;
26655 	  arg1 = cadr(expr);
26656 	  arg2 = caddr(expr);
26657 	  if ((returns_char(sc, arg1)) && (returns_char(sc, arg2)))
26658 	    return(sc->simple_char_eq);
26659 	}
26660       return(sc->char_equal_2);
26661     }
26662   return(f);
26663 }
26664 
26665 static s7_pointer char_less_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
26666 {
26667   return((args == 2) ? sc->char_less_2 : f);
26668 }
26669 
26670 static s7_pointer char_greater_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
26671 {
26672   return((args == 2) ? sc->char_greater_2 : f);
26673 }
26674 
26675 
26676 
26677 /* -------------------------------- char-ci<? char-ci<=? char-ci>? char-ci>=? char-ci=? -------------------------------- */
26678 #if (!WITH_PURE_S7)
26679 static s7_pointer g_char_cmp_ci(s7_scheme *sc, s7_pointer args, int32_t val, s7_pointer sym)
26680 {
26681   s7_pointer x, y;
26682 
26683   y = car(args);
26684   if (!s7_is_character(y))
26685     return(method_or_bust(sc, y, sym, args, T_CHARACTER, 1));
26686 
26687   for (x = cdr(args); is_pair(x); y = car(x), x = cdr(x))
26688     {
26689       if (!s7_is_character(car(x)))
26690 	return(method_or_bust(sc, car(x), sym, set_ulist_1(sc, y, x), T_CHARACTER, position_of(x, args)));
26691       if (charcmp(upper_character(y), upper_character(car(x))) != val)
26692 	return(char_with_error_check(sc, x, args, sym));
26693     }
26694   return(sc->T);
26695 }
26696 
26697 static s7_pointer g_char_cmp_ci_not(s7_scheme *sc, s7_pointer args, int32_t val, s7_pointer sym)
26698 {
26699   s7_pointer x, y;
26700 
26701   y = car(args);
26702   if (!s7_is_character(y))
26703     return(method_or_bust(sc, y, sym, args, T_CHARACTER, 1));
26704   for (x = cdr(args); is_pair(x); y = car(x), x = cdr(x))
26705     {
26706       if (!s7_is_character(car(x)))
26707 	return(method_or_bust(sc, car(x), sym, set_ulist_1(sc, y, x), T_CHARACTER, position_of(x, args)));
26708       if (charcmp(upper_character(y), upper_character(car(x))) == val)
26709 	return(char_with_error_check(sc, x, args, sym));
26710     }
26711   return(sc->T);
26712 }
26713 
26714 static s7_pointer g_chars_are_ci_equal(s7_scheme *sc, s7_pointer args)
26715 {
26716   #define H_chars_are_ci_equal "(char-ci=? char ...) returns #t if all the character arguments are equal, ignoring case"
26717   #define Q_chars_are_ci_equal sc->pcl_bc
26718 
26719   return(g_char_cmp_ci(sc, args, 0, sc->char_ci_eq_symbol));
26720 }
26721 
26722 static s7_pointer g_chars_are_ci_less(s7_scheme *sc, s7_pointer args)
26723 {
26724   #define H_chars_are_ci_less "(char-ci<? char ...) returns #t if all the character arguments are increasing, ignoring case"
26725   #define Q_chars_are_ci_less sc->pcl_bc
26726 
26727   return(g_char_cmp_ci(sc, args, -1, sc->char_ci_lt_symbol));
26728 }
26729 
26730 static s7_pointer g_chars_are_ci_greater(s7_scheme *sc, s7_pointer args)
26731 {
26732   #define H_chars_are_ci_greater "(char-ci>? char ...) returns #t if all the character arguments are decreasing, ignoring case"
26733   #define Q_chars_are_ci_greater sc->pcl_bc
26734 
26735   return(g_char_cmp_ci(sc, args, 1, sc->char_ci_gt_symbol));
26736 }
26737 
26738 static s7_pointer g_chars_are_ci_geq(s7_scheme *sc, s7_pointer args)
26739 {
26740   #define H_chars_are_ci_geq "(char-ci>=? char ...) returns #t if all the character arguments are equal or decreasing, ignoring case"
26741   #define Q_chars_are_ci_geq sc->pcl_bc
26742 
26743   return(g_char_cmp_ci_not(sc, args, -1, sc->char_ci_geq_symbol));
26744 }
26745 
26746 static s7_pointer g_chars_are_ci_leq(s7_scheme *sc, s7_pointer args)
26747 {
26748   #define H_chars_are_ci_leq "(char-ci<=? char ...) returns #t if all the character arguments are equal or increasing, ignoring case"
26749   #define Q_chars_are_ci_leq sc->pcl_bc
26750 
26751   return(g_char_cmp_ci_not(sc, args, 1, sc->char_ci_leq_symbol));
26752 }
26753 
26754 
26755 static bool char_ci_lt_b_unchecked(s7_pointer p1, s7_pointer p2) {return(upper_character(p1) < upper_character(p2));}
26756 static bool char_ci_lt_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26757 {
26758   check_char2_args(sc, sc->char_ci_lt_symbol, p1, p2);
26759   return(upper_character(p1) < upper_character(p2));
26760 }
26761 
26762 static bool char_ci_leq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(upper_character(p1) <= upper_character(p2));}
26763 static bool char_ci_leq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26764 {
26765   check_char2_args(sc, sc->char_ci_leq_symbol, p1, p2);
26766   return(upper_character(p1) <= upper_character(p2));
26767 }
26768 
26769 static bool char_ci_gt_b_unchecked(s7_pointer p1, s7_pointer p2) {return(upper_character(p1) > upper_character(p2));}
26770 static bool char_ci_gt_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26771 {
26772   check_char2_args(sc, sc->char_ci_gt_symbol, p1, p2);
26773   return(upper_character(p1) > upper_character(p2));
26774 }
26775 
26776 static bool char_ci_geq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(upper_character(p1) >= upper_character(p2));}
26777 static bool char_ci_geq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26778 {
26779   check_char2_args(sc, sc->char_ci_geq_symbol, p1, p2);
26780   return(upper_character(p1) >= upper_character(p2));
26781 }
26782 
26783 static bool char_ci_eq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(upper_character(p1) == upper_character(p2));}
26784 static bool char_ci_eq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
26785 {
26786   check_char2_args(sc, sc->char_ci_eq_symbol, p1, p2);
26787   return(upper_character(p1) == upper_character(p2));
26788 }
26789 
26790 #endif /* not pure s7 */
26791 
26792 
26793 /* -------------------------------- char-position -------------------------------- */
26794 static s7_pointer g_char_position(s7_scheme *sc, s7_pointer args)
26795 {
26796   #define H_char_position "(char-position char-or-str str (start 0)) returns the position of the first occurrence of char in str, or #f"
26797   #define Q_char_position s7_make_signature(sc, 4, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->not_symbol), s7_make_signature(sc, 2, sc->is_char_symbol, sc->is_string_symbol), sc->is_string_symbol, sc->is_integer_symbol)
26798 
26799   const char *porig, *pset;
26800   s7_int start, pos, len; /* not "int" because start arg might be most-negative-fixnum */
26801   s7_pointer arg1, arg2;
26802 
26803   arg1 = car(args);
26804   if ((!s7_is_character(arg1)) &&
26805       (!is_string(arg1)))
26806     return(method_or_bust(sc, arg1, sc->char_position_symbol, args, T_CHARACTER, 1));
26807 
26808   arg2 = cadr(args);
26809   if (!is_string(arg2))
26810     return(method_or_bust(sc, arg2, sc->char_position_symbol, args, T_STRING, 2));
26811 
26812   if (is_pair(cddr(args)))
26813     {
26814       s7_pointer arg3;
26815       arg3 = caddr(args);
26816       if (!s7_is_integer(arg3))
26817 	return(method_or_bust(sc, arg3, sc->char_position_symbol, args, T_INTEGER, 3));
26818       start = s7_integer_checked(sc, arg3);
26819       if (start < 0)
26820 	return(wrong_type_argument_with_type(sc, sc->char_position_symbol, 3, arg3, a_non_negative_integer_string));
26821     }
26822   else start = 0;
26823 
26824   porig = string_value(arg2);
26825   len = string_length(arg2);
26826   if (start >= len) return(sc->F);
26827 
26828   if (s7_is_character(arg1))
26829     {
26830       char c;
26831       const char *p;
26832       c = character(arg1);
26833       p = strchr((const char *)(porig + start), (int)c); /* use strchrnul in Gnu C to catch embedded null case */
26834       return((p) ? make_integer(sc, p - porig) : sc->F);
26835     }
26836 
26837   if (string_length(arg1) == 0)
26838     return(sc->F);
26839   pset = string_value(arg1);
26840 
26841   pos = strcspn((const char *)(porig + start), (const char *)pset);
26842   if ((pos + start) < len)
26843     return(make_integer(sc, pos + start));
26844 
26845   /* if the string has an embedded null, we can get erroneous results here --
26846    *   perhaps check for null at pos+start?  What about a searched-for string that also has embedded nulls?
26847    */
26848   return(sc->F);
26849 }
26850 
26851 static s7_pointer char_position_p_ppi(s7_scheme *sc, s7_pointer p1, s7_pointer p2, s7_int start)
26852 {
26853   /* p1 is char, p2 is string */
26854   if (is_string(p2))
26855     {
26856       if (start >= 0)
26857 	{
26858 	  const char *porig, *p;
26859 	  s7_int len;
26860 	  char c;
26861 	  c = character(p1);
26862 	  len = string_length(p2);
26863 	  porig = string_value(p2);
26864 	  if (start >= len) return(sc->F);
26865 	  p = strchr((const char *)(porig + start), (int)c);
26866 	  if (p) return(make_integer(sc, p - porig));
26867 	}
26868       else wrong_type_argument_with_type(sc, sc->char_position_symbol, 3, make_integer(sc, start), a_non_negative_integer_string);
26869     }
26870   else simple_wrong_type_argument(sc, sc->char_position_symbol, p2, T_STRING);
26871   return(sc->F);
26872 }
26873 
26874 static s7_pointer g_char_position_csi(s7_scheme *sc, s7_pointer args)
26875 {
26876   /* assume char arg1, no end */
26877   const char *porig, *p;
26878   char c;
26879   s7_pointer arg2;
26880   s7_int start, len;
26881 
26882   c = character(car(args));
26883   arg2 = cadr(args);
26884 
26885   if (!is_string(arg2))
26886     return(g_char_position(sc, args));
26887 
26888   len = string_length(arg2); /* can't return #f here if len==0 -- need start error check first */
26889   porig = string_value(arg2);
26890 
26891   if (is_pair(cddr(args)))
26892     {
26893       s7_pointer arg3;
26894       arg3 = caddr(args);
26895       if (!s7_is_integer(arg3))
26896 	return(g_char_position(sc, args));
26897       start = s7_integer_checked(sc, arg3);
26898       if (start < 0)
26899 	return(wrong_type_argument_with_type(sc, sc->char_position_symbol, 3, arg3, a_non_negative_integer_string));
26900       if (start >= len) return(sc->F);
26901     }
26902   else start = 0;
26903 
26904   if (len == 0) return(sc->F);
26905   p = strchr((const char *)(porig + start), (int)c);
26906   return((p) ? make_integer(sc, p - porig) : sc->F);
26907 }
26908 
26909 static s7_pointer char_position_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
26910 {
26911   if (!ops) return(f);
26912   if (((args == 2) || (args == 3)) &&
26913       (s7_is_character(cadr(expr))))
26914      return(sc->char_position_csi);
26915   return(f);
26916 }
26917 
26918 
26919 /* -------------------------------- string-position -------------------------------- */
26920 static s7_pointer g_string_position(s7_scheme *sc, s7_pointer args)
26921 {
26922   #define H_string_position "(string-position str1 str2 (start 0)) returns the starting position of str1 in str2 or #f"
26923   #define Q_string_position s7_make_signature(sc, 4, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->not_symbol), sc->is_string_symbol, sc->is_string_symbol, sc->is_integer_symbol)
26924   const char *s1, *s2, *p2;
26925   s7_int start = 0;
26926   s7_pointer s1p, s2p;
26927 
26928   s1p = car(args);
26929   if (!is_string(s1p))
26930     return(method_or_bust(sc, s1p, sc->string_position_symbol, args, T_STRING, 1));
26931 
26932   s2p = cadr(args);
26933   if (!is_string(s2p))
26934     return(method_or_bust(sc, s2p, sc->string_position_symbol, args, T_STRING, 2));
26935 
26936   if (is_pair(cddr(args)))
26937     {
26938       s7_pointer arg3;
26939       arg3 = caddr(args);
26940       if (!s7_is_integer(arg3))
26941 	return(method_or_bust(sc, arg3, sc->string_position_symbol, args, T_INTEGER, 3));
26942       start = s7_integer_checked(sc, arg3);
26943       if (start < 0)
26944 	return(wrong_type_argument_with_type(sc, sc->string_position_symbol, 3, caddr(args), a_non_negative_integer_string));
26945     }
26946 
26947   if (string_length(s1p) == 0)
26948     return(sc->F);
26949   s1 = string_value(s1p);
26950   s2 = string_value(s2p);
26951   if (start >= string_length(s2p))
26952     return(sc->F);
26953 
26954   p2 = strstr((const char *)(s2 + start), s1);
26955   return((p2) ? make_integer(sc, p2 - s2) : sc->F);
26956 }
26957 
26958 
26959 /* -------------------------------- strings -------------------------------- */
26960 
26961 /* prebuilding sc->empty_string and using it wherever len==0 did not produce more than about %.2 speedup
26962  *   (in index.scm where 11% of the strings are empty).  s7test max 4% empty, elsewhere much less.
26963  */
26964 bool s7_is_string(s7_pointer p) {return(is_string(p));}
26965 const char *s7_string(s7_pointer p) {return(string_value(p));}
26966 s7_int s7_string_length(s7_pointer str) {return(string_length(str));}
26967 
26968 s7_pointer s7_make_string_with_length(s7_scheme *sc, const char *str, s7_int len)
26969 {
26970   return(make_string_with_length(sc, str, len));
26971 }
26972 
26973 #define NUM_STRING_WRAPPERS 8 /* should be a power of 2 */
26974 
26975 #if S7_DEBUGGING
26976 static s7_pointer wrap_string_1(s7_scheme *sc, const char *str, s7_int len, const char *func, int line)
26977 #else
26978 static s7_pointer wrap_string(s7_scheme *sc, const char *str, s7_int len)
26979 #endif
26980 {
26981   s7_pointer x;
26982 #if S7_DEBUGGING
26983   if ((strcmp(func, "g_substring_uncopied") != 0) && (strcmp(func, "read_sharp") != 0) &&
26984       (strcmp(func, "g_get_output_string_uncopied") != 0) && (strcmp(func, "substring_uncopied_p_pii") != 0) &&
26985       (len != safe_strlen(str)))
26986     fprintf(stderr, "%s[%d]: %" print_s7_int " != %" print_s7_int ", %s\n", func, line, len, safe_strlen(str), str);
26987 #endif
26988   x = sc->string_wrappers[sc->string_wrapper_pos];
26989   sc->string_wrapper_pos = (sc->string_wrapper_pos + 1) & (NUM_STRING_WRAPPERS - 1); /* i.e. next is pos+1 modulo len */
26990   string_value(x) = (char *)str;
26991   string_length(x) = len;
26992   return(x);
26993 }
26994 
26995 s7_pointer s7_make_string_wrapper(s7_scheme *sc, const char *str) {return(wrap_string(sc, str, safe_strlen(str)));}
26996 
26997 static Inline s7_pointer inline_make_empty_string(s7_scheme *sc, s7_int len, char fill)
26998 {
26999   s7_pointer x;
27000   block_t *b;
27001   new_cell(sc, x, T_STRING);
27002   b = mallocate(sc, len + 1);
27003   string_block(x) = b;
27004   string_value(x) = (char *)block_data(b);
27005   if ((fill != '\0') && (len > 0))
27006     local_memset((void *)(string_value(x)), fill, len);
27007   string_value(x)[len] = 0;
27008   string_hash(x) = 0;
27009   string_length(x) = len;
27010   add_string(sc, x);
27011   return(x);
27012 }
27013 
27014 static s7_pointer make_empty_string(s7_scheme *sc, s7_int len, char fill)
27015 {
27016   return(inline_make_empty_string(sc, len, fill));
27017 }
27018 
27019 s7_pointer s7_make_string(s7_scheme *sc, const char *str)
27020 {
27021   return((str) ? make_string_with_length(sc, str, safe_strlen(str)) : make_empty_string(sc, 0, 0));
27022 }
27023 
27024 static char *make_permanent_c_string(s7_scheme *sc, const char *str)
27025 {
27026   char *x;
27027   s7_int len;
27028   len = safe_strlen(str);
27029   x = (char *)permalloc(sc, len + 1);
27030   memcpy((void *)x, (void *)str, len);
27031   x[len] = 0;
27032   return(x);
27033 }
27034 
27035 s7_pointer s7_make_permanent_string(s7_scheme *sc, const char *str)
27036 {
27037   /* for the symbol table which is never GC'd */
27038   s7_pointer x;
27039   x = alloc_pointer(sc);
27040   set_full_type(x, T_STRING | T_IMMUTABLE | T_UNHEAP);
27041   set_optimize_op(x, OP_CON);
27042   if (str)
27043     {
27044       s7_int len;
27045       len = safe_strlen(str);
27046       string_length(x) = len;
27047       string_block(x) = NULL;
27048       string_value(x) = (char *)permalloc(sc, len + 1);
27049       memcpy((void *)string_value(x), (void *)str, len);
27050       string_value(x)[len] = 0;
27051     }
27052   else
27053     {
27054       string_value(x) = NULL;
27055       string_length(x) = 0;
27056     }
27057   string_hash(x) = 0;
27058   return(x);
27059 }
27060 
27061 static s7_pointer g_is_string(s7_scheme *sc, s7_pointer args)
27062 {
27063   #define H_is_string "(string? obj) returns #t if obj is a string"
27064   #define Q_is_string sc->pl_bt
27065 
27066   check_boolean_method(sc, is_string, sc->is_string_symbol, args);
27067 }
27068 
27069 static s7_pointer make_permanent_string(const char *str)
27070 {
27071   s7_pointer x;
27072   s7_int len;
27073 
27074   x = (s7_pointer)calloc(1, sizeof(s7_cell));
27075   set_full_type(x, T_STRING | T_IMMUTABLE | T_UNHEAP);
27076   set_optimize_op(x, OP_CON);
27077   len = safe_strlen(str);
27078   string_length(x) = len;
27079   string_block(x) = NULL;
27080   string_value(x) = (char *)str;
27081   string_hash(x) = 0;
27082   return(x);
27083 }
27084 
27085 static void init_strings(void)
27086 {
27087   car_a_list_string = make_permanent_string("a pair whose car is also a pair");
27088   cdr_a_list_string = make_permanent_string("a pair whose cdr is also a pair");
27089 
27090   caar_a_list_string = make_permanent_string("a pair whose caar is also a pair");
27091   cadr_a_list_string = make_permanent_string("a pair whose cadr is also a pair");
27092   cdar_a_list_string = make_permanent_string("a pair whose cdar is also a pair");
27093   cddr_a_list_string = make_permanent_string("a pair whose cddr is also a pair");
27094 
27095   caaar_a_list_string = make_permanent_string("a pair whose caaar is also a pair");
27096   caadr_a_list_string = make_permanent_string("a pair whose caadr is also a pair");
27097   cadar_a_list_string = make_permanent_string("a pair whose cadar is also a pair");
27098   caddr_a_list_string = make_permanent_string("a pair whose caddr is also a pair");
27099   cdaar_a_list_string = make_permanent_string("a pair whose cdaar is also a pair");
27100   cdadr_a_list_string = make_permanent_string("a pair whose cdadr is also a pair");
27101   cddar_a_list_string = make_permanent_string("a pair whose cddar is also a pair");
27102   cdddr_a_list_string = make_permanent_string("a pair whose cdddr is also a pair");
27103 
27104   a_list_string =                 make_permanent_string("a list");
27105   an_eq_func_string =             make_permanent_string("a procedure that can take 2 arguments");
27106   an_association_list_string =    make_permanent_string("an association list");
27107   a_normal_real_string =          make_permanent_string("a normal real");
27108   a_rational_string =             make_permanent_string("an integer or a ratio");
27109   a_number_string =               make_permanent_string("a number");
27110   a_procedure_string =            make_permanent_string("a procedure");
27111   a_normal_procedure_string =     make_permanent_string("a normal procedure");
27112   a_let_string =                  make_permanent_string("a let (environment)");
27113   a_proper_list_string =          make_permanent_string("a proper list");
27114   a_boolean_string =              make_permanent_string("a boolean");
27115   a_byte_vector_string =          make_permanent_string("a byte-vector");
27116   an_input_port_string =          make_permanent_string("an input port");
27117   an_open_port_string =           make_permanent_string("an open port");
27118   an_output_port_string =         make_permanent_string("an output port");
27119   an_input_string_port_string =   make_permanent_string("an input string port");
27120   an_input_file_port_string =     make_permanent_string("an input file port");
27121   an_output_string_port_string =  make_permanent_string("an output string port");
27122   an_output_file_port_string =    make_permanent_string("an output file port");
27123   a_thunk_string =                make_permanent_string("a thunk");
27124   a_symbol_string =               make_permanent_string("a symbol");
27125   a_non_negative_integer_string = make_permanent_string("a non-negative integer");
27126   an_unsigned_byte_string =       make_permanent_string("an unsigned byte");
27127   something_applicable_string =   make_permanent_string("a procedure or something applicable");
27128   a_random_state_object_string =  make_permanent_string("a random-state object");
27129   a_format_port_string =          make_permanent_string("#f, #t, (), or an open output port");
27130   a_non_constant_symbol_string =  make_permanent_string("a non-constant symbol");
27131   a_sequence_string =             make_permanent_string("a sequence");
27132   a_valid_radix_string =          make_permanent_string("should be between 2 and 16");
27133   result_is_too_large_string =    make_permanent_string("result is too large");
27134   its_too_large_string =          make_permanent_string("it is too large");
27135   its_too_small_string =          make_permanent_string("it is less than the start position");
27136   its_negative_string =           make_permanent_string("it is negative");
27137   its_nan_string =                make_permanent_string("NaN usually indicates a numerical error");
27138   its_infinite_string =           make_permanent_string("it is infinite");
27139   too_many_indices_string =       make_permanent_string("too many indices");
27140   value_is_missing_string =       make_permanent_string("~A argument ~S's value is missing"); /* not '~A because it's normally a keyword */
27141   parameter_set_twice_string =    make_permanent_string("parameter set twice, ~S in ~S");
27142   immutable_error_string =        make_permanent_string("can't ~S ~S (it is immutable)");
27143   no_setter_string =              make_permanent_string("~A (~A) does not have a setter");
27144 #if (!HAVE_COMPLEX_NUMBERS)
27145   no_complex_numbers_string =     make_permanent_string("this version of s7 does not support complex numbers");
27146 #endif
27147 
27148   format_string_1 = make_permanent_string("format: ~S ~{~S~^ ~}: ~A");
27149   format_string_2 = make_permanent_string("format: ~S: ~A");
27150   format_string_3 = make_permanent_string("format: ~S ~{~S~^ ~}~&~NT^: ~A");
27151   format_string_4 = make_permanent_string("format: ~S~&~NT^: ~A");
27152 
27153   too_many_arguments_string = make_permanent_string("~S: too many arguments: ~A");
27154   not_enough_arguments_string = make_permanent_string("~S: not enough arguments: ~A");
27155   missing_method_string = make_permanent_string("missing ~S method in ~S");
27156 }
27157 
27158 
27159 /* -------------------------------- make-string -------------------------------- */
27160 static s7_pointer g_make_string(s7_scheme *sc, s7_pointer args)
27161 {
27162   #define H_make_string "(make-string len (val #\\space)) makes a string of length len filled with the character val (default: space)"
27163   #define Q_make_string s7_make_signature(sc, 3, sc->is_string_symbol, sc->is_integer_symbol, sc->is_char_symbol)
27164 
27165   s7_pointer n;
27166   s7_int len;
27167 
27168   n = car(args);
27169   if (!s7_is_integer(n))
27170     {
27171       check_method(sc, n, sc->make_string_symbol, args);
27172       return(wrong_type_argument(sc, sc->make_string_symbol, 1, n, T_INTEGER));
27173     }
27174 
27175   len = s7_integer_checked(sc, n);
27176   if ((len < 0) || (len > sc->max_string_length))
27177     return(out_of_range(sc, sc->make_string_symbol, int_one, n, (len < 0) ? its_negative_string : its_too_large_string));
27178 
27179   if (is_not_null(cdr(args)))
27180     {
27181       char fill;
27182       if (!s7_is_character(cadr(args)))
27183 	return(method_or_bust(sc, cadr(args), sc->make_string_symbol, args, T_CHARACTER, 2));
27184       fill = s7_character(cadr(args));
27185       n = make_empty_string(sc, len, fill);
27186       if ((fill == '\0') && (len > 0))
27187 	memclr((void *)string_value(n), (size_t)len);
27188       return(n);
27189     }
27190   return(make_empty_string(sc, len, '\0')); /* #\null here means "don't fill/clear" */
27191 }
27192 
27193 static s7_pointer make_string_p_i(s7_scheme *sc, s7_int len)
27194 {
27195   if ((len < 0) || (len > sc->max_string_length))
27196     return(out_of_range(sc, sc->make_string_symbol, int_one, wrap_integer1(sc, len), (len < 0) ? its_negative_string : its_too_large_string));
27197   return(make_empty_string(sc, len, '\0'));
27198 }
27199 
27200 
27201 #if (!WITH_PURE_S7)
27202 /* -------------------------------- string-length -------------------------------- */
27203 static s7_pointer g_string_length(s7_scheme *sc, s7_pointer args)
27204 {
27205   #define H_string_length "(string-length str) returns the length of the string str"
27206   #define Q_string_length s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_string_symbol)
27207   s7_pointer p;
27208   p = car(args);
27209   if (!is_string(p))
27210     return(method_or_bust_one_arg(sc, p, sc->string_length_symbol, args, T_STRING));
27211   return(make_integer(sc, string_length(p)));
27212 }
27213 
27214 static s7_int string_length_i_7p(s7_scheme *sc, s7_pointer p)
27215 {
27216   if (!is_string(p))
27217     return(integer(method_or_bust_one_arg_p(sc, p, sc->string_length_symbol, T_STRING)));
27218   return(string_length(p));
27219 }
27220 #endif
27221 
27222 
27223 /* -------------------------------- string-up|downcase -------------------------------- */
27224 static s7_pointer g_string_downcase(s7_scheme *sc, s7_pointer args)
27225 {
27226   #define H_string_downcase "(string-downcase str) returns the lower case version of str."
27227   #define Q_string_downcase sc->pcl_s
27228 
27229   s7_pointer p, newstr;
27230   s7_int i, len;
27231   uint8_t *nstr, *ostr;
27232 
27233   p = car(args);
27234   if (!is_string(p))
27235     return(method_or_bust_one_arg_p(sc, p, sc->string_downcase_symbol, T_STRING));
27236   len = string_length(p);
27237   newstr = make_empty_string(sc, len, 0);
27238 
27239   ostr = (uint8_t *)string_value(p);
27240   nstr = (uint8_t *)string_value(newstr);
27241 
27242   if (len >= 128)
27243     {
27244       i = len - 1;
27245       while (i >= 8)
27246 	LOOP_8(nstr[i] = lowers[(uint8_t)ostr[i]]; i--);
27247       while (i >= 0) {nstr[i] = lowers[(uint8_t)ostr[i]]; i--;}
27248     }
27249   else
27250     for (i = 0; i < len; i++)
27251       nstr[i] = lowers[(uint8_t)ostr[i]];
27252   return(newstr);
27253 }
27254 
27255 static s7_pointer g_string_upcase(s7_scheme *sc, s7_pointer args)
27256 {
27257   #define H_string_upcase "(string-upcase str) returns the upper case version of str."
27258   #define Q_string_upcase sc->pcl_s
27259 
27260   s7_pointer p, newstr;
27261   s7_int i, len;
27262   uint8_t *nstr, *ostr;
27263 
27264   p = car(args);
27265   if (!is_string(p))
27266     return(method_or_bust_one_arg_p(sc, p, sc->string_upcase_symbol, T_STRING));
27267   len = string_length(p);
27268   newstr = make_empty_string(sc, len, 0);
27269 
27270   ostr = (uint8_t *)string_value(p);
27271   nstr = (uint8_t *)string_value(newstr);
27272 
27273   if (len >= 128)
27274     {
27275       i = len - 1;
27276       while (i >= 8)
27277 	LOOP_8(nstr[i] = uppers[(uint8_t)ostr[i]]; i--);
27278       while (i >= 0) {nstr[i] = uppers[(uint8_t)ostr[i]]; i--;}
27279     }
27280   else
27281     for (i = 0; i < len; i++)
27282       nstr[i] = uppers[(uint8_t)ostr[i]];
27283   return(newstr);
27284 }
27285 
27286 
27287 /* -------------------------------- string-ref -------------------------------- */
27288 static s7_pointer string_ref_1(s7_scheme *sc, s7_pointer strng, s7_pointer index)
27289 {
27290   char *str;
27291   s7_int ind;
27292 
27293   if (!s7_is_integer(index))
27294     return(method_or_bust_pp(sc, index, sc->string_ref_symbol, strng, index, T_INTEGER, 2));
27295   ind = s7_integer_checked(sc, index);
27296   if (ind < 0)
27297     return(out_of_range(sc, sc->string_ref_symbol, int_two, index, a_non_negative_integer_string));
27298   if (ind >= string_length(strng))
27299     return(out_of_range(sc, sc->string_ref_symbol, int_two, index, its_too_large_string));
27300 
27301   str = string_value(strng);
27302   return(s7_make_character(sc, ((uint8_t *)str)[ind]));
27303 }
27304 
27305 static s7_pointer g_string_ref(s7_scheme *sc, s7_pointer args)
27306 {
27307   #define H_string_ref "(string-ref str index) returns the character at the index-th element of the string str"
27308   #define Q_string_ref s7_make_signature(sc, 3, sc->is_char_symbol, sc->is_string_symbol, sc->is_integer_symbol)
27309 
27310   s7_pointer strng;
27311   strng = car(args);
27312   if (!is_string(strng))
27313     return(method_or_bust(sc, strng, sc->string_ref_symbol, args, T_STRING, 1));
27314   return(string_ref_1(sc, strng, cadr(args)));
27315 }
27316 
27317 static s7_pointer string_ref_p_pi(s7_scheme *sc, s7_pointer p1, s7_int i1)
27318 {
27319   if (!is_string(p1))
27320     simple_wrong_type_argument(sc, sc->string_ref_symbol, p1, T_STRING);
27321   if ((i1 >= 0) && (i1 < string_length(p1)))
27322     return(chars[((uint8_t *)string_value(p1))[i1]]);
27323   out_of_range(sc, sc->string_ref_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
27324   return(p1);
27325 }
27326 
27327 static s7_pointer string_ref_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer i1)
27328 {
27329   if (!is_string(p1))
27330     return(method_or_bust_pp(sc, p1, sc->string_ref_symbol, p1, i1, T_STRING, 1));
27331   return(string_ref_1(sc, p1, i1));
27332 }
27333 
27334 static s7_pointer string_ref_p_p0(s7_scheme *sc, s7_pointer p1, s7_pointer i1) /* i1 can be NULL */
27335 {
27336   if (is_string(p1))
27337     {
27338       if (string_length(p1) > 0)
27339 	return(chars[((uint8_t *)string_value(p1))[0]]);
27340       out_of_range(sc, sc->string_ref_symbol, int_two, int_zero, its_too_large_string);
27341       return(p1);
27342     }
27343   return(method_or_bust_pp(sc, p1, sc->string_ref_symbol, p1, int_zero, T_STRING, 1));
27344 }
27345 
27346 static s7_pointer string_plast_via_method(s7_scheme *sc, s7_pointer p1)
27347 {
27348   s7_pointer len;
27349   len = method_or_bust_one_arg_p(sc, p1, sc->length_symbol, T_STRING);
27350   return(method_or_bust_with_type_pi(sc, p1, sc->string_ref_symbol, p1, integer(len) - 1, sc->prepackaged_type_names[T_STRING]));
27351 }
27352 
27353 static s7_pointer string_ref_p_plast(s7_scheme *sc, s7_pointer p1, s7_pointer i1)
27354 {
27355   if (is_string(p1))
27356     {
27357       if (string_length(p1) > 0)
27358 	return(chars[((uint8_t *)string_value(p1))[string_length(p1) - 1]]);
27359       out_of_range(sc, sc->string_ref_symbol, int_two, wrap_integer1(sc, string_length(p1) - 1), its_too_large_string);
27360       return(p1);
27361     }
27362   return(string_plast_via_method(sc, p1));
27363 }
27364 
27365 static s7_pointer string_ref_p_pi_unchecked(s7_scheme *sc, s7_pointer p1, s7_int i1)
27366 {
27367   if ((i1 >= 0) && (i1 < string_length(p1)))
27368     return(chars[((uint8_t *)string_value(p1))[i1]]);
27369   out_of_range(sc, sc->string_ref_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
27370   return(p1);
27371 }
27372 
27373 static s7_pointer string_ref_unchecked(s7_scheme *sc, s7_pointer p1, s7_int i1) {return(chars[((uint8_t *)string_value(p1))[i1]]);}
27374 
27375 
27376 /* -------------------------------- string-set! -------------------------------- */
27377 static s7_pointer g_string_set(s7_scheme *sc, s7_pointer args)
27378 {
27379   #define H_string_set "(string-set! str index chr) sets the index-th element of the string str to the character chr"
27380   #define Q_string_set s7_make_signature(sc, 4, sc->is_char_symbol, sc->is_string_symbol, sc->is_integer_symbol, sc->is_char_symbol)
27381 
27382   s7_pointer strng, c, index;
27383   char *str;
27384   s7_int ind;
27385 
27386   strng = car(args);
27387   if (!is_mutable_string(strng))
27388     return(mutable_method_or_bust(sc, strng, sc->string_set_symbol, args, T_STRING, 1));
27389 
27390   index = cadr(args);
27391   if (!s7_is_integer(index))
27392     return(method_or_bust(sc, index, sc->string_set_symbol, args, T_INTEGER, 2));
27393   ind = s7_integer_checked(sc, index);
27394   if (ind < 0)
27395     return(out_of_range(sc, sc->string_set_symbol, int_two, index, a_non_negative_integer_string));
27396   if (ind >= string_length(strng))
27397     return(out_of_range(sc, sc->string_set_symbol, int_two, index, its_too_large_string));
27398 
27399   str = string_value(strng);
27400   c = caddr(args);
27401   if (!s7_is_character(c))
27402     return(method_or_bust(sc, c, sc->string_set_symbol, args, T_CHARACTER, 3));
27403 
27404   str[ind] = (char)s7_character(c);
27405   return(c);
27406 }
27407 
27408 static s7_pointer string_set_p_pip(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_pointer p2)
27409 {
27410   if (!is_string(p1))
27411     simple_wrong_type_argument(sc, sc->string_set_symbol, p1, T_STRING);
27412   if (!s7_is_character(p2))
27413     simple_wrong_type_argument(sc, sc->string_set_symbol, p2, T_CHARACTER);
27414   if ((i1 >= 0) && (i1 < string_length(p1)))
27415     string_value(p1)[i1] = s7_character(p2);
27416   else out_of_range(sc, sc->string_set_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
27417   return(p2);
27418 }
27419 
27420 static s7_pointer string_set_p_pip_unchecked(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_pointer p2)
27421 {
27422   if ((i1 >= 0) && (i1 < string_length(p1)))
27423     string_value(p1)[i1] = s7_character(p2);
27424   else out_of_range(sc, sc->string_set_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
27425   return(p2);
27426 }
27427 
27428 static s7_pointer string_set_unchecked(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_pointer p2) {string_value(p1)[i1] = s7_character(p2); return(p2);}
27429 
27430 
27431 /* -------------------------------- string-append -------------------------------- */
27432 static s7_pointer g_string_append_1(s7_scheme *sc, s7_pointer args, s7_pointer caller)
27433 {
27434   #define H_string_append "(string-append str1 ...) appends all its string arguments into one string"
27435   #define Q_string_append sc->pcl_s
27436 
27437   s7_int len = 0;
27438   s7_pointer x, newstr;
27439   char *pos;
27440 
27441   if (is_null(args))
27442     return(make_string_with_length(sc, "", 0));
27443 
27444   push_stack_no_let_no_code(sc, OP_GC_PROTECT, args);
27445   /* get length for new string */
27446   for (x = args; is_not_null(x); x = cdr(x))
27447     {
27448       s7_pointer p;
27449       p = car(x);
27450       if (!is_string(p))
27451 	{
27452 	  /* look for string-append and if found, cobble up a plausible intermediate call */
27453 	  if (has_active_methods(sc, p))
27454 	    {
27455 	      s7_pointer func;
27456 	      func = find_method_with_let(sc, p, caller);
27457 	      if (func != sc->undefined)
27458 		{
27459 		  s7_pointer y;
27460 		  if (len == 0)
27461 		    {
27462 		      unstack(sc);
27463 		      return(call_method(sc, p, func, x)); /* not args (string-append "" "" ...) */
27464 		    }
27465 		  newstr = make_empty_string(sc, len, 0);
27466 		  for (pos = string_value(newstr), y = args; y != x; pos += string_length(car(y)), y = cdr(y))
27467 		    memcpy(pos, string_value(car(y)), string_length(car(y)));
27468 		  unstack(sc);
27469 		  return(call_method(sc, p, func, set_ulist_1(sc, newstr, x)));
27470 		}}
27471 	  unstack(sc);
27472 	  return(wrong_type_argument(sc, caller, position_of(x, args), p, T_STRING));
27473 	}
27474       len += string_length(p);
27475     }
27476 
27477   if (len == 0)
27478     {
27479       unstack(sc);
27480       return(make_string_with_length(sc, "", 0)); /* not car(args) here since it might be immutable (string_wrapper for example) */
27481     }
27482 
27483   if (len > sc->max_string_length)
27484     {
27485       unstack(sc);
27486       return(s7_error(sc, sc->out_of_range_symbol,
27487 		      set_elist_4(sc, wrap_string(sc, "~S new string length, ~D, is larger than (*s7* 'max-string-length): ~D", 70),
27488 				  caller, wrap_integer1(sc, len), wrap_integer2(sc, sc->max_string_length))));
27489     }
27490 
27491   newstr = inline_make_empty_string(sc, len, 0);
27492   for (pos = string_value(newstr), x = args; is_not_null(x); x = cdr(x))
27493     {
27494       len = string_length(car(x));
27495       if (len > 0)
27496 	{
27497 	  memcpy(pos, string_value(car(x)), len);
27498 	  pos += len;
27499 	}}
27500   unstack(sc);
27501   return(newstr);
27502 }
27503 
27504 static s7_pointer g_string_append(s7_scheme *sc, s7_pointer args)
27505 {
27506   return(g_string_append_1(sc, args, sc->string_append_symbol));
27507 }
27508 
27509 static s7_pointer string_append_p_pp(s7_scheme *sc, s7_pointer s1, s7_pointer s2)
27510 {
27511   if ((is_string(s1)) && (is_string(s2)))
27512     {
27513       s7_int len, pos;
27514       s7_pointer newstr;
27515       pos = string_length(s1);
27516       len = pos + string_length(s2);
27517       if (len == 0) return(s1);
27518       if (len > sc->max_string_length)
27519 	return(s7_error(sc, sc->out_of_range_symbol,
27520 			set_elist_4(sc, wrap_string(sc, "~S new string length, ~D, is larger than (*s7* 'max-string-length): ~D", 70),
27521 				    sc->string_append_symbol, wrap_integer1(sc, len), wrap_integer2(sc, sc->max_string_length))));
27522       newstr = make_empty_string(sc, len, 0); /* len+1 0-terminated */
27523       if (pos > 0)
27524 	memcpy(string_value(newstr), string_value(s1), pos);
27525       if (string_length(s2) > 0)
27526 	memcpy((char *)(string_value(newstr) + pos), string_value(s2), string_length(s2));
27527       return(newstr);
27528     }
27529   return(g_string_append_1(sc, list_2(sc, s1, s2), sc->string_append_symbol));
27530 }
27531 
27532 static s7_pointer g_string_append_2(s7_scheme *sc, s7_pointer args)
27533 {
27534   return(string_append_p_pp(sc, car(args), cadr(args)));
27535 }
27536 
27537 static void check_for_substring_temp(s7_scheme *sc, s7_pointer expr);
27538 
27539 static s7_pointer string_append_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
27540 {
27541   check_for_substring_temp(sc, expr);
27542   return((args == 2) ? sc->string_append_2 : f);
27543 }
27544 
27545 
27546 /* -------------------------------- substring -------------------------------- */
27547 static s7_pointer start_and_end(s7_scheme *sc, s7_pointer caller, s7_pointer args, int32_t position, s7_pointer index_args, s7_int *start, s7_int *end)
27548 {
27549   /* we assume that *start=0 and *end=length, that end is "exclusive", return true if the start/end points are not changed */
27550   s7_pointer pstart;
27551   s7_int index;
27552 
27553   pstart = car(index_args);
27554   if (!s7_is_integer(pstart))
27555     return(method_or_bust(sc, pstart, caller, args, T_INTEGER, position));
27556   index = s7_integer_checked(sc, pstart);
27557   if ((index < 0) ||
27558       (index > *end)) /* *end == length here */
27559     return(out_of_range(sc, caller, small_int(position), pstart, (index < 0) ? its_negative_string : its_too_large_string));
27560   *start = index;
27561 
27562   if (is_pair(cdr(index_args)))
27563     {
27564       s7_pointer pend;
27565       pend = cadr(index_args);
27566       if (!s7_is_integer(pend))
27567 	return(method_or_bust(sc, pend, caller, args, T_INTEGER, position + 1));
27568       index = s7_integer_checked(sc, pend);
27569       if ((index < *start) ||
27570 	  (index > *end))
27571 	return(out_of_range(sc, caller, small_int(position + 1), pend, (index < *start) ? its_too_small_string : its_too_large_string));
27572       *end = index;
27573     }
27574   return(sc->unused);
27575 }
27576 
27577 static s7_pointer g_substring(s7_scheme *sc, s7_pointer args)
27578 {
27579   #define H_substring "(substring str start (end (length str))) returns the portion of the string str between start and \
27580 end: (substring \"01234\" 1 2) -> \"1\""
27581   #define Q_substring s7_make_circular_signature(sc, 2, 3, sc->is_string_symbol, sc->is_string_symbol, sc->is_integer_symbol)
27582 
27583   s7_pointer x, str;
27584   s7_int start = 0, end, len;
27585   char *s;
27586 
27587   str = car(args);
27588   if (!is_string(str))
27589     return(method_or_bust(sc, str, sc->substring_symbol, args, T_STRING, 1));
27590 
27591   end = string_length(str);
27592   if (!is_null(cdr(args)))
27593     {
27594       x = start_and_end(sc, sc->substring_symbol, args, 2, cdr(args), &start, &end);
27595       if (x != sc->unused) return(x);
27596     }
27597   s = string_value(str);
27598   len = end - start;
27599   x = inline_make_string_with_length(sc, (char *)(s + start), len);
27600   string_value(x)[len] = 0;
27601   return(x);
27602 }
27603 
27604 static s7_pointer g_substring_uncopied(s7_scheme *sc, s7_pointer args)
27605 {
27606   s7_pointer str;
27607   s7_int start = 0, end;
27608 
27609   str = car(args);
27610   if (!is_string(str))
27611     return(method_or_bust(sc, str, sc->substring_symbol, args, T_STRING, 1));
27612 
27613   end = string_length(str);
27614   if (!is_null(cdr(args)))
27615     {
27616       s7_pointer x;
27617       x = start_and_end(sc, sc->substring_symbol, args, 2, cdr(args), &start, &end);
27618       if (x != sc->unused) return(x);
27619     }
27620   return(wrap_string(sc, (char *)(string_value(str) + start), end - start));
27621 }
27622 
27623 static s7_pointer substring_uncopied_p_pii(s7_scheme *sc, s7_pointer str, s7_int start, s7_int end)
27624 {
27625   if (!is_string(str))
27626     return(method_or_bust(sc, str, sc->substring_symbol, list_3(sc, str, make_integer(sc, start), make_integer(sc, end)), T_STRING, 1));
27627   if ((end < start) || (end > string_length(str)))
27628     return(out_of_range(sc, sc->substring_symbol, int_three, wrap_integer1(sc, end), (end < start) ? its_too_small_string : its_too_large_string));
27629   if ((start < 0) || (start > end))
27630     return(out_of_range(sc, sc->substring_symbol, int_two, wrap_integer1(sc, start), (start < 0) ? its_negative_string : its_too_large_string));
27631 
27632   return(wrap_string(sc, (char *)(string_value(str) + start), end - start));
27633 }
27634 
27635 static s7_pointer g_get_output_string(s7_scheme *sc, s7_pointer args);
27636 
27637 static void check_for_substring_temp(s7_scheme *sc, s7_pointer expr)
27638 {
27639   s7_pointer nps[NUM_STRING_WRAPPERS];
27640   s7_pointer p, arg;
27641   int32_t pairs = 0, substrs = 0;
27642   /* a bit tricky -- accept temp only if there's just one inner expression and it calls substring
27643    *   and don't use this for arg if arg is returned: (reverse! (write-string (symbol->string x)))
27644    */
27645   for (p = cdr(expr); is_pair(p); p = cdr(p))
27646     {
27647       arg = car(p);
27648       if (is_pair(arg))
27649 	{
27650 	  pairs++;
27651 	  if ((is_symbol(car(arg))) &&
27652 	      (is_safely_optimized(arg)) &&
27653 	      (has_fn(arg)))
27654 	    {
27655 	      if (fn_proc(arg) == g_substring)
27656 		{
27657 		  if (substrs < NUM_STRING_WRAPPERS)
27658 		    nps[substrs++] = arg;
27659 		}
27660 	      else
27661 		{
27662 		  if (fn_proc(arg) == g_symbol_to_string)
27663 		    set_c_function(arg, sc->symbol_to_string_uncopied);
27664 		  else
27665 		    if ((fn_proc(arg) == g_get_output_string) && (is_null(cddr(arg))))
27666 		      set_c_function(arg, sc->get_output_string_uncopied);
27667 		}}}}
27668   if ((pairs > 0) &&
27669       (pairs == substrs))
27670     {
27671       int32_t i;
27672       for (i = 0; i < substrs; i++)
27673 	set_c_function(nps[i], sc->substring_uncopied);
27674     }
27675 }
27676 
27677 static s7_pointer string_substring_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
27678 {
27679   /* used by several string functions */
27680   check_for_substring_temp(sc, expr);
27681   return(f);
27682 }
27683 
27684 
27685 /* -------------------------------- string-copy -------------------------------- */
27686 static s7_pointer g_string_copy(s7_scheme *sc, s7_pointer args)
27687 {
27688   #define H_string_copy "(string-copy str dest-str (dest-start 0) dest-end) returns a copy of its string argument.  If dest-str is given, \
27689     string-copy copies its first argument into the second, starting at dest-start in the second string and returns dest-str"
27690   #define Q_string_copy s7_make_signature(sc, 5, sc->is_string_symbol, sc->is_string_symbol, sc->is_string_symbol, sc->is_integer_symbol, sc->is_integer_symbol)
27691   s7_pointer source;
27692   source = car(args);
27693   if (!is_string(source))
27694     return(method_or_bust(sc, source, sc->string_copy_symbol, args, T_STRING, 1));
27695   if (is_null(cdr(args)))
27696     return(make_string_with_length(sc, string_value(source), string_length(source)));
27697 
27698   {
27699     s7_int start, end;
27700     s7_pointer p, dest;
27701 
27702     dest = cadr(args);
27703     if (!is_string(dest))
27704       return(wrong_type_argument(sc, sc->string_copy_symbol, 2, dest, T_STRING));
27705     if (is_immutable(dest))
27706       return(immutable_object_error(sc, set_elist_2(sc, wrap_string(sc, "can't string-copy to ~S; it is immutable", 40), dest)));
27707 
27708     end = string_length(dest);
27709     p = cddr(args);
27710     if (is_null(p))
27711       start = 0;
27712     else
27713       {
27714 	if (!s7_is_integer(car(p)))
27715 	  return(wrong_type_argument(sc, sc->string_copy_symbol, 3, car(p), T_INTEGER));
27716 	start = s7_integer(car(p));
27717 	if (start < 0) start = 0;
27718 	p = cdr(p);
27719 	if (is_null(p))
27720 	  end = start + string_length(source);
27721 	else
27722 	  {
27723 	    if (!s7_is_integer(car(p)))
27724 	      return(wrong_type_argument(sc, sc->string_copy_symbol, 4, car(p), T_INTEGER));
27725 	    end = s7_integer(car(p));
27726 	    if (end < 0) end = start;
27727 	  }}
27728     if (end > string_length(dest)) end = string_length(dest);
27729     if (end <= start) return(dest);
27730     if ((end - start) > string_length(source)) end = start + string_length(source);
27731     memcpy((void *)(string_value(dest) + start), (void *)(string_value(source)), end - start);
27732     return(dest);
27733   }
27734 }
27735 
27736 static s7_pointer string_copy_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
27737 {
27738   if (args == 1) check_for_substring_temp(sc, expr);
27739   return(f);
27740 }
27741 
27742 
27743 /* -------------------------------- string comparisons -------------------------------- */
27744 static int32_t scheme_strcmp(s7_pointer s1, s7_pointer s2)
27745 {
27746   /* tricky here because str[i] must be treated as unsigned: (string<? (string (integer->char #xf0)) (string (integer->char #x70)))
27747    *   and null or lack thereof does not say anything about the string end
27748    */
27749   size_t i, len, len1, len2;
27750   char *str1, *str2;
27751 
27752   len1 = (size_t)string_length(s1);
27753   len2 = (size_t)string_length(s2);
27754   len = (len1 > len2) ? len2 : len1;
27755 
27756   str1 = string_value(s1);
27757   str2 = string_value(s2);
27758 
27759   if (len < sizeof(size_t))
27760     {
27761       for (i = 0; i < len; i++)
27762 	{
27763 	  if ((uint8_t)(str1[i]) < (uint8_t )(str2[i]))
27764 	    return(-1);
27765 	  if ((uint8_t)(str1[i]) > (uint8_t)(str2[i]))
27766 	    return(1);
27767 	}}
27768   else
27769     {
27770       /* this algorithm from stackoverflow(?), with various changes (original did not work for large strings, etc) */
27771       size_t last, pos;
27772       size_t *ptr1, *ptr2;
27773 
27774       last = len / sizeof(size_t);
27775       for (ptr1 = (size_t *)str1, ptr2 = (size_t *)str2, i = 0; i < last; i++)
27776 	if (ptr1[i] ^ ptr2[i])
27777 	  break;
27778 
27779       for (pos = i * sizeof(size_t); pos < len; pos++)
27780 	{
27781 	  if ((uint8_t)str1[pos] < (uint8_t)str2[pos])
27782 	    return(-1);
27783 	  if ((uint8_t)str1[pos] > (uint8_t)str2[pos])
27784 	    return(1);
27785 	}}
27786   if (len1 < len2)
27787     return(-1);
27788   return((len1 > len2) ? 1 : 0);
27789 }
27790 
27791 static bool is_string_via_method(s7_scheme *sc, s7_pointer p)
27792 {
27793   if (s7_is_string(p))
27794     return(true);
27795   if (has_active_methods(sc, p))
27796     {
27797       s7_pointer f;
27798       f = find_method_with_let(sc, p, sc->is_string_symbol);
27799       if (f != sc->undefined)
27800 	return(is_true(sc, call_method(sc, p, f, set_plist_1(sc, p))));
27801     }
27802   return(false);
27803 }
27804 
27805 static s7_pointer g_string_cmp(s7_scheme *sc, s7_pointer args, int32_t val, s7_pointer sym)
27806 {
27807   s7_pointer x, y;
27808 
27809   y = car(args);
27810   if (!is_string(y))
27811     return(method_or_bust(sc, y, sym, args, T_STRING, 1));
27812 
27813   for (x = cdr(args); is_not_null(x); y = car(x), x = cdr(x))
27814     {
27815       if (!is_string(car(x)))
27816 	return(method_or_bust(sc, car(x), sym, set_ulist_1(sc, y, x), T_STRING, position_of(x, args)));
27817       if (scheme_strcmp(y, car(x)) != val)
27818 	{
27819 	  for (y = cdr(x); is_pair(y); y = cdr(y))
27820 	    if (!is_string_via_method(sc, car(y)))
27821 	      return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_STRING));
27822 	  return(sc->F);
27823 	}}
27824   return(sc->T);
27825 }
27826 
27827 static s7_pointer g_string_cmp_not(s7_scheme *sc, s7_pointer args, int32_t val, s7_pointer sym)
27828 {
27829   s7_pointer x, y;
27830 
27831   y = car(args);
27832   if (!is_string(y))
27833     return(method_or_bust(sc, y, sym, args, T_STRING, 1));
27834 
27835   for (x = cdr(args); is_not_null(x); y = car(x), x = cdr(x))
27836     {
27837       if (!is_string(car(x)))
27838 	return(method_or_bust(sc, car(x), sym, set_ulist_1(sc, y, x), T_STRING, position_of(x, args)));
27839       if (scheme_strcmp(y, car(x)) == val)
27840 	{
27841 	  for (y = cdr(x); is_pair(y); y = cdr(y))
27842 	    if (!is_string_via_method(sc, car(y)))
27843 	      return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_STRING));
27844 	  return(sc->F);
27845 	}}
27846   return(sc->T);
27847 }
27848 
27849 static bool scheme_strings_are_equal(s7_pointer x, s7_pointer y)
27850 {
27851   return((string_length(x) == string_length(y)) &&
27852 	 (strings_are_equal_with_length(string_value(x), string_value(y), string_length(x))));
27853 }
27854 
27855 static s7_pointer g_strings_are_equal(s7_scheme *sc, s7_pointer args)
27856 {
27857   #define H_strings_are_equal "(string=? str ...) returns #t if all the string arguments are equal"
27858   #define Q_strings_are_equal sc->pcl_bs
27859 
27860   /* C-based check stops at null, but we can have embedded nulls.
27861    *   (let ((s1 "1234") (s2 "1245")) (string-set! s1 1 #\null) (string-set! s2 1 #\null) (string=? s1 s2))
27862    */
27863   s7_pointer x, y;
27864   bool happy = true;
27865 
27866   y = car(args);
27867   if (!is_string(y))
27868     return(method_or_bust(sc, y, sc->string_eq_symbol, args, T_STRING, 1));
27869 
27870   for (x = cdr(args); is_pair(x); x = cdr(x))
27871     {
27872       s7_pointer p;
27873       p = car(x);
27874       if (y != p)
27875 	{
27876 	  if (!is_string(p))
27877 	    return(method_or_bust(sc, p, sc->string_eq_symbol, set_ulist_1(sc, y, x), T_STRING, position_of(x, args)));
27878 	  if (happy)
27879 	    happy = scheme_strings_are_equal(p, y);
27880 	}}
27881   return((happy) ? sc->T : sc->F);
27882 }
27883 
27884 static s7_pointer g_strings_are_less(s7_scheme *sc, s7_pointer args)
27885 {
27886   #define H_strings_are_less "(string<? str ...) returns #t if all the string arguments are increasing"
27887   #define Q_strings_are_less sc->pcl_bs
27888 
27889   return(g_string_cmp(sc, args, -1, sc->string_lt_symbol));
27890 }
27891 
27892 static s7_pointer g_strings_are_greater(s7_scheme *sc, s7_pointer args)
27893 {
27894   #define H_strings_are_greater "(string>? str ...) returns #t if all the string arguments are decreasing"
27895   #define Q_strings_are_greater sc->pcl_bs
27896 
27897   return(g_string_cmp(sc, args, 1, sc->string_gt_symbol));
27898 }
27899 
27900 static s7_pointer g_strings_are_geq(s7_scheme *sc, s7_pointer args)
27901 {
27902   #define H_strings_are_geq "(string>=? str ...) returns #t if all the string arguments are equal or decreasing"
27903   #define Q_strings_are_geq sc->pcl_bs
27904 
27905   return(g_string_cmp_not(sc, args, -1, sc->string_geq_symbol));
27906 }
27907 
27908 static s7_pointer g_strings_are_leq(s7_scheme *sc, s7_pointer args)
27909 {
27910   #define H_strings_are_leq "(string<=? str ...) returns #t if all the string arguments are equal or increasing"
27911   #define Q_strings_are_leq sc->pcl_bs
27912 
27913   return(g_string_cmp_not(sc, args, 1, sc->string_leq_symbol));
27914 }
27915 
27916 static s7_pointer g_string_equal_2(s7_scheme *sc, s7_pointer args)
27917 {
27918   if (!is_string(car(args)))
27919     return(method_or_bust(sc, car(args), sc->string_eq_symbol, args, T_STRING, 1));
27920   if (!is_string(cadr(args)))
27921     return(method_or_bust(sc, cadr(args), sc->string_eq_symbol, args, T_STRING, 2));
27922   return(make_boolean(sc, scheme_strings_are_equal(car(args), cadr(args))));
27923 }
27924 
27925 static s7_pointer g_string_equal_2c(s7_scheme *sc, s7_pointer args)
27926 {
27927   if (!is_string(car(args)))
27928     return(method_or_bust(sc, car(args), sc->string_eq_symbol, args, T_STRING, 1));
27929   return(make_boolean(sc, scheme_strings_are_equal(car(args), cadr(args))));
27930 }
27931 
27932 static s7_pointer g_string_less_2(s7_scheme *sc, s7_pointer args)
27933 {
27934   if (!is_string(car(args)))
27935     return(method_or_bust(sc, car(args), sc->string_lt_symbol, args, T_STRING, 1));
27936   if (!is_string(cadr(args)))
27937     return(method_or_bust(sc, cadr(args), sc->string_lt_symbol, args, T_STRING, 2));
27938   return(make_boolean(sc, scheme_strcmp(car(args), cadr(args)) == -1));
27939 }
27940 
27941 static s7_pointer g_string_greater_2(s7_scheme *sc, s7_pointer args)
27942 {
27943   if (!is_string(car(args)))
27944     return(method_or_bust(sc, car(args), sc->string_gt_symbol, args, T_STRING, 1));
27945   if (!is_string(cadr(args)))
27946     return(method_or_bust(sc, cadr(args), sc->string_gt_symbol, args, T_STRING, 2));
27947   return(make_boolean(sc, scheme_strcmp(car(args), cadr(args)) == 1));
27948 }
27949 
27950 static inline void check_string2_args(s7_scheme *sc, s7_pointer caller, s7_pointer p1, s7_pointer p2)
27951 {
27952   if (!is_string(p1))
27953     simple_wrong_type_argument(sc, caller, p1, T_STRING);
27954   if (!s7_is_string(p2))
27955     simple_wrong_type_argument(sc, caller, p2, T_STRING);
27956 }
27957 
27958 static bool string_lt_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strcmp(p1, p2) == -1);}
27959 static bool string_lt_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
27960 {
27961   check_string2_args(sc, sc->string_lt_symbol, p1, p2);
27962   return(scheme_strcmp(p1, p2) == -1);
27963 }
27964 
27965 static bool string_leq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strcmp(p1, p2) != 1);}
27966 static bool string_leq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
27967 {
27968   check_string2_args(sc, sc->string_leq_symbol, p1, p2);
27969   return(scheme_strcmp(p1, p2) != 1);
27970 }
27971 
27972 static bool string_gt_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strcmp(p1, p2) == 1);}
27973 static bool string_gt_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
27974 {
27975   check_string2_args(sc, sc->string_gt_symbol, p1, p2);
27976   return(scheme_strcmp(p1, p2) == 1);
27977 }
27978 
27979 static bool string_geq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strcmp(p1, p2) != -1);}
27980 static bool string_geq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
27981 {
27982   check_string2_args(sc, sc->string_geq_symbol, p1, p2);
27983   return(scheme_strcmp(p1, p2) != -1);
27984 }
27985 
27986 static bool string_eq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strings_are_equal(p1, p2));}
27987 static bool string_eq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
27988 {
27989   check_string2_args(sc, sc->string_eq_symbol, p1, p2);
27990   return(scheme_strings_are_equal(p1, p2));
27991 }
27992 
27993 
27994 static s7_pointer string_equal_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
27995 {
27996   check_for_substring_temp(sc, expr);
27997   return((args == 2) ? ((is_string(caddr(expr))) ? sc->string_equal_2c : sc->string_equal_2) : f);
27998 }
27999 
28000 static s7_pointer string_less_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
28001 {
28002   check_for_substring_temp(sc, expr);
28003   return((args == 2) ? sc->string_less_2 : f);
28004 }
28005 
28006 static s7_pointer string_greater_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
28007 {
28008   check_for_substring_temp(sc, expr);
28009   return((args == 2) ? sc->string_greater_2 : f);
28010 }
28011 
28012 
28013 #if (!WITH_PURE_S7)
28014 static int32_t scheme_strcasecmp(s7_pointer s1, s7_pointer s2)
28015 {
28016   /* same as scheme_strcmp -- watch out for unwanted sign! and lack of trailing null (length sets string end).
28017    */
28018   s7_int i, len, len1, len2;
28019   uint8_t *str1, *str2;
28020 
28021   len1 = string_length(s1);
28022   len2 = string_length(s2);
28023   len = (len1 > len2) ? len2 : len1;
28024 
28025   str1 = (uint8_t *)string_value(s1);
28026   str2 = (uint8_t *)string_value(s2);
28027 
28028   for (i = 0; i < len; i++)
28029     {
28030       if (uppers[(int32_t)str1[i]] < uppers[(int32_t)str2[i]])
28031 	return(-1);
28032       if (uppers[(int32_t)str1[i]] > uppers[(int32_t)str2[i]])
28033 	return(1);
28034     }
28035 
28036   if (len1 < len2)
28037     return(-1);
28038   return((len1 > len2) ? 1 : 0);
28039 }
28040 
28041 static bool scheme_strequal_ci(s7_pointer s1, s7_pointer s2)
28042 {
28043   /* same as scheme_strcmp -- watch out for unwanted sign! */
28044   s7_int i, len, len2;
28045   uint8_t *str1, *str2;
28046 
28047   len = string_length(s1);
28048   len2 = string_length(s2);
28049   if (len != len2)
28050     return(false);
28051 
28052   str1 = (uint8_t *)string_value(s1);
28053   str2 = (uint8_t *)string_value(s2);
28054 
28055   for (i = 0; i < len; i++)
28056     if (uppers[(int32_t)str1[i]] != uppers[(int32_t)str2[i]])
28057       return(false);
28058   return(true);
28059 }
28060 
28061 static s7_pointer string_check_method(s7_scheme *sc, s7_pointer sym, s7_pointer x, s7_pointer y, s7_pointer args)
28062 {
28063   for (y = cdr(x); is_pair(y); y = cdr(y))
28064     if (!is_string_via_method(sc, car(y)))
28065       return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_STRING));
28066   return(sc->F);
28067 }
28068 
28069 static s7_pointer g_string_ci_cmp(s7_scheme *sc, s7_pointer args, int32_t val, s7_pointer sym)
28070 {
28071   s7_pointer x, y;
28072 
28073   y = car(args);
28074   if (!is_string(y))
28075     return(method_or_bust(sc, y, sym, args, T_STRING, 1));
28076 
28077   for (x = cdr(args); is_not_null(x); y = car(x), x = cdr(x))
28078     {
28079       if (!is_string(car(x)))
28080 	return(method_or_bust(sc, car(x), sym, set_ulist_1(sc, y, x), T_STRING, position_of(x, args)));
28081       if (val == 0)
28082 	{
28083 	  if (!scheme_strequal_ci(y, car(x)))
28084 	    return(string_check_method(sc, sym, x, y, args));
28085 	}
28086       else
28087 	if (scheme_strcasecmp(y, car(x)) != val)
28088 	  return(string_check_method(sc, sym, x, y, args));
28089     }
28090   return(sc->T);
28091 }
28092 
28093 static s7_pointer g_string_ci_cmp_not(s7_scheme *sc, s7_pointer args, int32_t val, s7_pointer sym)
28094 {
28095   s7_pointer x, y;
28096 
28097   y = car(args);
28098   if (!is_string(y))
28099     return(method_or_bust(sc, y, sym, args, T_STRING, 1));
28100 
28101   for (x = cdr(args); is_not_null(x); y = car(x), x = cdr(x))
28102     {
28103       if (!is_string(car(x)))
28104 	return(method_or_bust(sc, car(x), sym, set_ulist_1(sc, y, x), T_STRING, position_of(x, args)));
28105       if (scheme_strcasecmp(y, car(x)) == val)
28106 	return(string_check_method(sc, sym, x, y, args));
28107     }
28108   return(sc->T);
28109 }
28110 
28111 static s7_pointer g_strings_are_ci_equal(s7_scheme *sc, s7_pointer args)
28112 {
28113   #define H_strings_are_ci_equal "(string-ci=? str ...) returns #t if all the string arguments are equal, ignoring case"
28114   #define Q_strings_are_ci_equal sc->pcl_bs
28115   return(g_string_ci_cmp(sc, args, 0, sc->string_ci_eq_symbol));
28116 }
28117 
28118 static s7_pointer g_strings_are_ci_less(s7_scheme *sc, s7_pointer args)
28119 {
28120   #define H_strings_are_ci_less "(string-ci<? str ...) returns #t if all the string arguments are increasing, ignoring case"
28121   #define Q_strings_are_ci_less sc->pcl_bs
28122   return(g_string_ci_cmp(sc, args, -1, sc->string_ci_lt_symbol));
28123 }
28124 
28125 static s7_pointer g_strings_are_ci_greater(s7_scheme *sc, s7_pointer args)
28126 {
28127   #define H_strings_are_ci_greater "(string-ci>? str ...) returns #t if all the string arguments are decreasing, ignoring case"
28128   #define Q_strings_are_ci_greater sc->pcl_bs
28129   return(g_string_ci_cmp(sc, args, 1, sc->string_ci_gt_symbol));
28130 }
28131 
28132 static s7_pointer g_strings_are_ci_geq(s7_scheme *sc, s7_pointer args)
28133 {
28134   #define H_strings_are_ci_geq "(string-ci>=? str ...) returns #t if all the string arguments are equal or decreasing, ignoring case"
28135   #define Q_strings_are_ci_geq sc->pcl_bs
28136   return(g_string_ci_cmp_not(sc, args, -1, sc->string_ci_geq_symbol));
28137 }
28138 
28139 static s7_pointer g_strings_are_ci_leq(s7_scheme *sc, s7_pointer args)
28140 {
28141   #define H_strings_are_ci_leq "(string-ci<=? str ...) returns #t if all the string arguments are equal or increasing, ignoring case"
28142   #define Q_strings_are_ci_leq sc->pcl_bs
28143   return(g_string_ci_cmp_not(sc, args, 1, sc->string_ci_leq_symbol));
28144 }
28145 
28146 static bool string_ci_lt_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strcasecmp(p1, p2) == -1);}
28147 static bool string_ci_lt_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
28148 {
28149   check_string2_args(sc, sc->string_ci_lt_symbol, p1, p2);
28150   return(scheme_strcasecmp(p1, p2) == -1);
28151 }
28152 
28153 static bool string_ci_leq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strcasecmp(p1, p2) != 1);}
28154 static bool string_ci_leq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
28155 {
28156   check_string2_args(sc, sc->string_ci_leq_symbol, p1, p2);
28157   return(scheme_strcasecmp(p1, p2) != 1);
28158 }
28159 
28160 static bool string_ci_gt_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strcasecmp(p1, p2) == 1);}
28161 static bool string_ci_gt_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
28162 {
28163   check_string2_args(sc, sc->string_ci_gt_symbol, p1, p2);
28164   return(scheme_strcasecmp(p1, p2) == 1);
28165 }
28166 
28167 static bool string_ci_geq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strcasecmp(p1, p2) != -1);}
28168 static bool string_ci_geq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
28169 {
28170   check_string2_args(sc, sc->string_ci_geq_symbol, p1, p2);
28171   return(scheme_strcasecmp(p1, p2) != -1);
28172 }
28173 
28174 static bool string_ci_eq_b_unchecked(s7_pointer p1, s7_pointer p2) {return(scheme_strcasecmp(p1, p2) == 0);}
28175 static bool string_ci_eq_b_7pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
28176 {
28177   check_string2_args(sc, sc->string_ci_eq_symbol, p1, p2);
28178   return(scheme_strcasecmp(p1, p2) == 0);
28179 }
28180 #endif /* pure s7 */
28181 
28182 static s7_pointer g_string_fill_1(s7_scheme *sc, s7_pointer caller, s7_pointer args)
28183 {
28184   s7_pointer x, chr;
28185   s7_int start = 0, end;
28186   x = car(args);
28187 
28188   if (!is_string(x))
28189     return(method_or_bust(sc, x, caller, args, T_STRING, 1)); /* not two methods here */
28190   if (is_immutable_string(x))
28191     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, caller, x)));
28192 
28193   chr = cadr(args);
28194   if (!s7_is_character(chr))
28195     return(method_or_bust(sc, chr, caller, args, T_CHARACTER, 2));
28196 
28197   end = string_length(x);
28198   if (!is_null(cddr(args)))
28199     {
28200       s7_pointer p;
28201       p = start_and_end(sc, caller, args, 3, cddr(args), &start, &end);
28202       if (p != sc->unused)
28203 	return(p);
28204       if (start == end) return(chr);
28205     }
28206   if (end == 0) return(chr);
28207 
28208   if ((int)(character(chr)) == 0)
28209     memclr((void *)(string_value(x) + start), end - start);
28210   else local_memset((void *)(string_value(x) + start), (int32_t)character(chr), end - start);
28211 
28212   return(chr);
28213 }
28214 
28215 #if (!WITH_PURE_S7)
28216 /* -------------------------------- string-fill! -------------------------------- */
28217 static s7_pointer g_string_fill(s7_scheme *sc, s7_pointer args)
28218 {
28219   #define H_string_fill "(string-fill! str chr start end) fills the string str with the character chr"
28220   #define Q_string_fill s7_make_signature(sc, 5, s7_make_signature(sc, 2, sc->is_char_symbol, sc->is_integer_symbol), sc->is_string_symbol, sc->is_char_symbol, sc->is_integer_symbol, sc->is_integer_symbol)
28221   return(g_string_fill_1(sc, sc->string_fill_symbol, args));
28222 }
28223 #endif
28224 
28225 
28226 /* -------------------------------- string -------------------------------- */
28227 static s7_pointer g_string_1(s7_scheme *sc, s7_pointer args, s7_pointer sym)
28228 {
28229   int32_t i, len;
28230   s7_pointer x, newstr;
28231   char *str;
28232 
28233   /* get length for new string and check arg types */
28234   for (len = 0, x = args; is_not_null(x); len++, x = cdr(x))
28235     {
28236       s7_pointer p;
28237       p = car(x);
28238       if (!s7_is_character(p))
28239 	{
28240 	  if (has_active_methods(sc, p))
28241 	    {
28242 	      s7_pointer func;
28243 	      func = find_method_with_let(sc, p, sym);
28244 	      if (func != sc->undefined)
28245 		{
28246 		  s7_pointer y;
28247 		  if (len == 0)
28248 		    return(call_method(sc, p, func, args));
28249 		  newstr = make_empty_string(sc, len, 0);
28250 		  str = string_value(newstr);
28251 		  for (i = 0, y = args; y != x; i++, y = cdr(y))
28252 		    str[i] = character(car(y));
28253 		  return(g_string_append_1(sc, set_plist_2(sc, newstr, call_method(sc, p, func, x)), sym));
28254 		}}
28255 	  return(wrong_type_argument(sc, sym, len + 1, car(x), T_CHARACTER));
28256 	}}
28257   newstr = inline_make_empty_string(sc, len, 0);
28258   str = string_value(newstr);
28259   for (i = 0, x = args; is_not_null(x); i++, x = cdr(x))
28260     str[i] = character(car(x));
28261 
28262   return(newstr);
28263 }
28264 
28265 static s7_pointer g_string(s7_scheme *sc, s7_pointer args)
28266 {
28267   #define H_string "(string chr...) appends all its character arguments into one string"
28268   #define Q_string s7_make_circular_signature(sc, 1, 2, sc->is_string_symbol, sc->is_char_symbol)
28269 
28270   return((is_null(args)) ? make_string_with_length(sc, "", 0) : g_string_1(sc, args, sc->string_symbol));
28271 }
28272 
28273 static s7_pointer g_string_c1(s7_scheme *sc, s7_pointer args)
28274 {
28275   s7_pointer c, str;
28276   /* no multiple values here because no pairs below */
28277   c = car(args);
28278   if (!s7_is_character(c))
28279     return(method_or_bust(sc, c, sc->string_symbol, args, T_CHARACTER, 1));
28280   str = inline_make_empty_string(sc, 1, 0); /* can't put character(c) here because null is handled specially */
28281   string_value(str)[0] = character(c);
28282   return(str);
28283 }
28284 
28285 static s7_pointer string_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
28286 {
28287   return(((args == 1) && (!is_pair(cadr(expr)))) ? sc->string_c1 : f);
28288 }
28289 
28290 static s7_pointer string_p_p(s7_scheme *sc, s7_pointer p)
28291 {
28292   s7_pointer str;
28293   if (!s7_is_character(p)) return(g_string_1(sc, set_plist_1(sc, p), sc->string_symbol));
28294   str = inline_make_empty_string(sc, 1, 0);
28295   string_value(str)[0] = character(p);
28296   return(str);
28297 }
28298 
28299 
28300 /* -------------------------------- list->string -------------------------------- */
28301 #if (!WITH_PURE_S7)
28302 static s7_pointer g_list_to_string(s7_scheme *sc, s7_pointer args)
28303 {
28304   #define H_list_to_string "(list->string lst) appends all the list's characters into one string; (apply string lst)"
28305   #define Q_list_to_string s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_proper_list_symbol)
28306 
28307   if (is_null(car(args)))
28308     return(make_string_with_length(sc, "", 0));
28309 
28310   if (!s7_is_proper_list(sc, car(args)))
28311     return(method_or_bust_with_type_one_arg(sc, car(args), sc->list_to_string_symbol, args,
28312 					    wrap_string(sc, "a (proper, non-circular) list of characters", 43)));
28313   return(g_string_1(sc, car(args), sc->list_to_string_symbol));
28314 }
28315 #endif
28316 
28317 
28318 /* -------------------------------- string->list -------------------------------- */
28319 static s7_pointer s7_string_to_list(s7_scheme *sc, const char *str, s7_int len)
28320 {
28321   s7_int i;
28322   s7_pointer result;
28323   if (len == 0)
28324     return(sc->nil);
28325   check_free_heap_size(sc, len);
28326   sc->v = sc->nil;
28327   for (i = len - 1; i >= 0; i--)
28328     sc->v = cons_unchecked(sc, s7_make_character(sc, ((uint8_t)str[i])), sc->v);
28329   result = sc->v;
28330   sc->v = sc->nil;
28331   return(result);
28332 }
28333 
28334 #if (!WITH_PURE_S7)
28335 static s7_pointer g_string_to_list(s7_scheme *sc, s7_pointer args)
28336 {
28337   #define H_string_to_list "(string->list str start end) returns the elements of the string str in a list; (map values str)"
28338   #define Q_string_to_list s7_make_circular_signature(sc, 2, 3, sc->is_proper_list_symbol, sc->is_string_symbol, sc->is_integer_symbol)
28339 
28340   s7_int i, start = 0, end;
28341   s7_pointer p, str;
28342 
28343   str = car(args);
28344   if (!is_string(str))
28345     return(method_or_bust_one_arg(sc, str, sc->string_to_list_symbol, args, T_STRING));
28346 
28347   end = string_length(str);
28348   if (!is_null(cdr(args)))
28349     {
28350       p = start_and_end(sc, sc->string_to_list_symbol, args, 2, cdr(args), &start, &end);
28351       if (p != sc->unused) return(p);
28352       if (start == end) return(sc->nil);
28353     }
28354   else
28355     if (end == 0) return(sc->nil);
28356   if ((end - start) > sc->max_list_length)
28357     return(out_of_range(sc, sc->string_to_list_symbol, int_one, car(args), its_too_large_string));
28358 
28359   sc->w = sc->nil;
28360   check_free_heap_size(sc, end - start);
28361   for (i = end - 1; i >= start; i--)
28362     sc->w = cons_unchecked(sc, s7_make_character(sc, ((uint8_t)string_value(str)[i])), sc->w);
28363   p = sc->w;
28364   sc->w = sc->nil;
28365   return(p);
28366 }
28367 #endif
28368 
28369 
28370 /* -------------------------------- port-closed? -------------------------------- */
28371 static s7_pointer g_is_port_closed(s7_scheme *sc, s7_pointer args)
28372 {
28373   #define H_is_port_closed "(port-closed? p) returns #t if the port p is closed."
28374   #define Q_is_port_closed s7_make_signature(sc, 2, sc->is_boolean_symbol, s7_make_signature(sc, 3, sc->is_input_port_symbol, sc->is_output_port_symbol, sc->not_symbol))
28375   s7_pointer x;
28376 
28377   x = car(args);
28378   if ((is_input_port(x)) || (is_output_port(x)))
28379     return(make_boolean(sc, port_is_closed(x)));
28380   if ((x == current_output_port(sc)) && (x == sc->F))
28381     return(sc->F);
28382   return(method_or_bust_with_type_one_arg(sc, x, sc->is_port_closed_symbol, args, wrap_string(sc, "a port", 6)));
28383 }
28384 
28385 static bool is_port_closed_b_7p(s7_scheme *sc, s7_pointer x)
28386 {
28387   if ((is_input_port(x)) || (is_output_port(x)))
28388     return(port_is_closed(x));
28389   if ((x == current_output_port(sc)) && (x == sc->F))
28390     return(false);
28391   simple_wrong_type_argument_with_type(sc, sc->is_port_closed_symbol, x, wrap_string(sc, "a port", 6));
28392   return(false);
28393 }
28394 
28395 
28396 /* -------------------------------- port-position -------------------------------- */
28397 
28398 static s7_pointer g_port_position(s7_scheme *sc, s7_pointer args)
28399 {
28400   #define H_port_position "(port-position input-port) returns the current location (in bytes) in the port's data where the next read will take place."
28401   #define Q_port_position s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_input_port_symbol)
28402   s7_pointer port;
28403 
28404   port = car(args);
28405   if (!(is_input_port(port)))
28406     return(simple_wrong_type_argument(sc, sc->port_position_symbol, port, T_INPUT_PORT));
28407   if (port_is_closed(port))
28408     return(s7_wrong_type_arg_error(sc, "port-position", 0, port, "an open input port"));
28409   if (is_string_port(port))
28410     return(make_integer(sc, port_position(port)));
28411 #if (!MS_WINDOWS)
28412   if (is_file_port(port))
28413     return(make_integer(sc, ftell(port_file(port))));
28414 #endif
28415   return(int_zero);
28416 }
28417 
28418 static s7_pointer g_set_port_position(s7_scheme *sc, s7_pointer args)
28419 {
28420   s7_pointer port, pos;
28421   s7_int position;
28422 
28423   port = car(args);
28424   if (!(is_input_port(port)))
28425     return(s7_wrong_type_arg_error(sc, "set! port-position", 1, port, "an input port"));
28426   if (port_is_closed(port))
28427     return(s7_wrong_type_arg_error(sc, "set! port-position", 1, port, "an open input port"));
28428 
28429   pos = cadr(args);
28430   if (!is_t_integer(pos))
28431     return(s7_wrong_type_arg_error(sc, "set! port-position", 2, pos, "an integer"));
28432   position = s7_integer_checked(sc, pos);
28433   if (position < 0)
28434     return(out_of_range(sc, sc->port_position_symbol, int_two, pos, its_negative_string));
28435 
28436   if (is_string_port(port))
28437     port_position(port) = position;
28438 #if (!MS_WINDOWS)
28439   else
28440     if (is_file_port(port))
28441       {
28442 	rewind(port_file(port));
28443 	fseek(port_file(port), (long)position, SEEK_SET);
28444       }
28445 #endif
28446   return(pos);
28447 }
28448 
28449 
28450 /* -------------------------------- port-file -------------------------------- */
28451 
28452 static s7_pointer g_port_file(s7_scheme *sc, s7_pointer args)
28453 {
28454   #define H_port_file "(port-file port) returns the FILE* pointer associated with the port, wrapped in a c-pointer object"
28455   #define Q_port_file s7_make_signature(sc, 2, sc->is_c_pointer_symbol, s7_make_signature(sc, 2, sc->is_input_port_symbol, sc->is_output_port_symbol))
28456   s7_pointer port;
28457 
28458   port = car(args);
28459   if ((!is_input_port(port)) &&
28460       (!is_output_port(port)))
28461     return(s7_wrong_type_arg_error(sc, "port-file", 0, port, "a port"));
28462   if (port_is_closed(port))
28463     return(s7_wrong_type_arg_error(sc, "port-file", 0, port, "an open port"));
28464 #if (!MS_WINDOWS)
28465   if (is_file_port(port))
28466     return(s7_make_c_pointer_with_type(sc, (void *)(port_file(port)), s7_make_symbol(sc, "FILE*"), sc->F));
28467 #endif
28468   return(s7_make_c_pointer(sc, NULL));
28469 }
28470 
28471 
28472 /* -------------------------------- port-line-number -------------------------------- */
28473 static s7_pointer port_line_number_p_p(s7_scheme *sc, s7_pointer x)
28474 {
28475   if ((!(is_input_port(x))) ||
28476       (port_is_closed(x)))
28477     return(method_or_bust_with_type_one_arg_p(sc, x, sc->port_line_number_symbol, an_input_port_string));
28478   return(make_integer(sc, port_line_number(x)));
28479 }
28480 
28481 static s7_pointer g_port_line_number(s7_scheme *sc, s7_pointer args)
28482 {
28483   #define H_port_line_number "(port-line-number input-file-port) returns the current read line number of port"
28484   #define Q_port_line_number s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_input_port_symbol)
28485   return(port_line_number_p_p(sc, (is_null(args)) ? current_input_port(sc) : car(args)));
28486 }
28487 
28488 s7_int s7_port_line_number(s7_scheme *sc, s7_pointer p)
28489 {
28490   if (!(is_input_port(p)))
28491     simple_wrong_type_argument(sc, sc->port_line_number_symbol, p, T_INPUT_PORT);
28492   return(port_line_number(p));
28493 }
28494 
28495 static s7_pointer g_set_port_line_number(s7_scheme *sc, s7_pointer args)
28496 {
28497   s7_pointer p, line;
28498 
28499   if ((is_null(car(args))) ||
28500       ((is_null(cdr(args))) && (is_t_integer(car(args)))))
28501     p = current_input_port(sc);
28502   else
28503     {
28504       p = car(args);
28505       if (!(is_input_port(p)))
28506 	return(s7_wrong_type_arg_error(sc, "set! port-line-number", 1, p, "an input port"));
28507     }
28508 
28509   line = (is_null(cdr(args)) ? car(args) : cadr(args));
28510   if (!is_t_integer(line))
28511     return(s7_wrong_type_arg_error(sc, "set! port-line-number", 2, line, "an integer"));
28512   port_line_number(p) = integer(line);
28513   return(line);
28514 }
28515 
28516 
28517 /* -------------------------------- port-filename -------------------------------- */
28518 const char *s7_port_filename(s7_scheme *sc, s7_pointer x)
28519 {
28520   if (((is_input_port(x)) ||
28521        (is_output_port(x))) &&
28522       (!port_is_closed(x)))
28523     return(port_filename(x));
28524   return(NULL);
28525 }
28526 
28527 static s7_pointer port_filename_p_p(s7_scheme *sc, s7_pointer x)
28528 {
28529   if (((is_input_port(x)) ||
28530        (is_output_port(x))) &&
28531       (!port_is_closed(x)))
28532     {
28533       if (port_filename(x))
28534 	return(make_string_with_length(sc, port_filename(x), port_filename_length(x))); /* not wrapper here! */
28535       return(make_string_with_length(sc, "", 0));
28536       /* otherwise (eval-string (port-filename)) and (string->symbol (port-filename)) segfault */
28537     }
28538   return(method_or_bust_with_type_one_arg_p(sc, x, sc->port_filename_symbol, an_open_port_string));
28539 }
28540 
28541 static s7_pointer g_port_filename(s7_scheme *sc, s7_pointer args)
28542 {
28543   #define H_port_filename "(port-filename file-port) returns the filename associated with port"
28544   #define Q_port_filename s7_make_signature(sc, 2, sc->is_string_symbol, s7_make_signature(sc, 2, sc->is_input_port_symbol, sc->is_output_port_symbol))
28545   return(port_filename_p_p(sc, (is_null(args)) ? current_input_port(sc) : car(args)));
28546 }
28547 
28548 
28549 /* -------------------------------- pair-line-number -------------------------------- */
28550 static s7_pointer pair_line_number_p_p(s7_scheme *sc, s7_pointer p)
28551 {
28552   if (!is_pair(p))
28553     return(method_or_bust_one_arg_p(sc, p, sc->pair_line_number_symbol, T_PAIR));
28554   return((has_location(p)) ? make_integer(sc, pair_line_number(p)) : sc->F);
28555 }
28556 
28557 static s7_pointer g_pair_line_number(s7_scheme *sc, s7_pointer args)
28558 {
28559   #define H_pair_line_number "(pair-line-number pair) returns the line number at which it read 'pair', or #f if no such number is available"
28560   #define Q_pair_line_number s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->not_symbol), sc->is_pair_symbol)
28561   return(pair_line_number_p_p(sc, car(args)));
28562 }
28563 
28564 
28565 /* -------------------------------- pair-filename -------------------------------- */
28566 static s7_pointer g_pair_filename(s7_scheme *sc, s7_pointer args)
28567 {
28568   #define H_pair_filename "(pair-filename pair) returns the name of the file containing 'pair'"
28569   #define Q_pair_filename s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_string_symbol, sc->not_symbol), sc->is_pair_symbol)
28570   s7_pointer p;
28571   p = car(args);
28572 
28573   if (!is_pair(p))
28574     {
28575       check_method(sc, p, sc->pair_filename_symbol, args);
28576       return(simple_wrong_type_argument(sc, sc->pair_filename_symbol, p, T_PAIR));
28577     }
28578   return((has_location(p)) ? sc->file_names[pair_file_number(p)] : sc->F);
28579 }
28580 
28581 
28582 /* -------------------------------- input-port? -------------------------------- */
28583 bool s7_is_input_port(s7_scheme *sc, s7_pointer p) {return(is_input_port(p));}
28584 static bool is_input_port_b(s7_pointer p) {return(is_input_port(p));}
28585 
28586 static s7_pointer g_is_input_port(s7_scheme *sc, s7_pointer args)
28587 {
28588   #define H_is_input_port "(input-port? p) returns #t if p is an input port"
28589   #define Q_is_input_port sc->pl_bt
28590   check_boolean_method(sc, is_input_port, sc->is_input_port_symbol, args);
28591 }
28592 
28593 
28594 /* -------------------------------- output-port? -------------------------------- */
28595 bool s7_is_output_port(s7_scheme *sc, s7_pointer p) {return(is_output_port(p));}
28596 static bool is_output_port_b(s7_pointer p) {return(is_output_port(p));}
28597 
28598 static s7_pointer g_is_output_port(s7_scheme *sc, s7_pointer args)
28599 {
28600   #define H_is_output_port "(output-port? p) returns #t if p is an output port"
28601   #define Q_is_output_port sc->pl_bt
28602   check_boolean_method(sc, is_output_port, sc->is_output_port_symbol, args);
28603 }
28604 
28605 
28606 /* -------------------------------- current-input-port -------------------------------- */
28607 s7_pointer s7_current_input_port(s7_scheme *sc) {return(current_input_port(sc));}
28608 
28609 static s7_pointer g_current_input_port(s7_scheme *sc, s7_pointer args)
28610 {
28611   #define H_current_input_port "(current-input-port) returns the current input port"
28612   #define Q_current_input_port s7_make_signature(sc, 1, sc->is_input_port_symbol)
28613   return(current_input_port(sc));
28614 }
28615 
28616 static s7_pointer g_set_current_input_port(s7_scheme *sc, s7_pointer args)
28617 {
28618   #define H_set_current_input_port "(set-current-input-port port) sets the current-input port to port and returns the previous value of the input port"
28619   #define Q_set_current_input_port s7_make_signature(sc, 2, sc->is_input_port_symbol, sc->is_input_port_symbol)
28620 
28621   s7_pointer old_port, port;
28622   old_port = current_input_port(sc);
28623   port = car(args);
28624   if ((is_input_port(port)) &&
28625       (!port_is_closed(port)))
28626     set_current_input_port(sc, port);
28627   else
28628     {
28629       check_method(sc, port, sc->set_current_input_port_symbol, args);
28630       return(s7_wrong_type_arg_error(sc, "set-current-input-port", 0, port, "an open input port"));
28631     }
28632   return(old_port);
28633 }
28634 
28635 s7_pointer s7_set_current_input_port(s7_scheme *sc, s7_pointer port)
28636 {
28637   s7_pointer old_port;
28638   old_port = current_input_port(sc);
28639   set_current_input_port(sc, port);
28640   return(old_port);
28641 }
28642 
28643 
28644 /* -------------------------------- current-output-port -------------------------------- */
28645 s7_pointer s7_current_output_port(s7_scheme *sc) {return(current_output_port(sc));}
28646 
28647 s7_pointer s7_set_current_output_port(s7_scheme *sc, s7_pointer port)
28648 {
28649   s7_pointer old_port;
28650   old_port = current_output_port(sc);
28651   set_current_output_port(sc, port);
28652   return(old_port);
28653 }
28654 
28655 static s7_pointer g_current_output_port(s7_scheme *sc, s7_pointer args)
28656 {
28657   #define H_current_output_port "(current-output-port) returns the current output port"
28658   #define Q_current_output_port s7_make_signature(sc, 1, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
28659   return(current_output_port(sc));
28660 }
28661 
28662 static s7_pointer g_set_current_output_port(s7_scheme *sc, s7_pointer args)
28663 {
28664   #define H_set_current_output_port "(set-current-output-port port) sets the current-output port to port and returns the previous value of the output port"
28665   #define Q_set_current_output_port s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol), s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
28666 
28667   s7_pointer old_port, port;
28668   old_port = current_output_port(sc);
28669   port = car(args);
28670   if (((is_output_port(port)) &&
28671        (!port_is_closed(port))) ||
28672       (port == sc->F))
28673     set_current_output_port(sc, port);
28674   else
28675     {
28676       check_method(sc, port, sc->set_current_output_port_symbol, args);
28677       return(s7_wrong_type_arg_error(sc, "set-current-output-port", 0, port, "an open output port"));
28678     }
28679   return(old_port);
28680 }
28681 
28682 
28683 /* -------------------------------- current-error-port -------------------------------- */
28684 s7_pointer s7_current_error_port(s7_scheme *sc) {return(sc->error_port);}
28685 
28686 s7_pointer s7_set_current_error_port(s7_scheme *sc, s7_pointer port)
28687 {
28688   s7_pointer old_port;
28689   old_port = sc->error_port;
28690   sc->error_port = port;
28691   return(old_port);
28692 }
28693 
28694 static s7_pointer g_current_error_port(s7_scheme *sc, s7_pointer args)
28695 {
28696   #define H_current_error_port "(current-error-port) returns the current error port"
28697   #define Q_current_error_port s7_make_signature(sc, 1, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
28698   return(sc->error_port);
28699 }
28700 
28701 static s7_pointer g_set_current_error_port(s7_scheme *sc, s7_pointer args)
28702 {
28703   #define H_set_current_error_port "(set-current-error-port port) sets the current-error port to port and returns the previous value of the error port"
28704   #define Q_set_current_error_port s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol), s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
28705   s7_pointer old_port, port;
28706 
28707   old_port = sc->error_port;
28708   port = car(args);
28709   if (((is_output_port(port)) &&
28710        (!port_is_closed(port))) ||
28711       (port == sc->F))
28712     sc->error_port = port;
28713   else
28714     {
28715       check_method(sc, port, sc->set_current_error_port_symbol, args);
28716       return(s7_wrong_type_arg_error(sc, "set-current-error-port", 0, port, "an open output port"));
28717     }
28718   return(old_port);
28719 }
28720 
28721 
28722 /* -------------------------------- char-ready? -------------------------------- */
28723 #if (!WITH_PURE_S7)
28724 static s7_pointer g_is_char_ready(s7_scheme *sc, s7_pointer args)
28725 {
28726   #define H_is_char_ready "(char-ready? (port (current-input-port))) returns #t if a character is ready for input on the given port"
28727   #define Q_is_char_ready s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_input_port_symbol)
28728   if (is_not_null(args))
28729     {
28730       s7_pointer pt = car(args);
28731       if (!is_input_port(pt))
28732 	return(method_or_bust_with_type_one_arg(sc, pt, sc->is_char_ready_symbol, args, an_input_port_string));
28733       if (port_is_closed(pt))
28734 	return(simple_wrong_type_argument_with_type(sc, sc->is_char_ready_symbol, pt, an_open_port_string));
28735 
28736       if (is_function_port(pt))
28737 	{
28738 	  s7_pointer res;
28739 	  res = (*(port_input_function(pt)))(sc, S7_IS_CHAR_READY, pt);
28740 	  if (is_multiple_value(res))  /* can only happen if more than one value in res */
28741 	    {
28742 	      clear_multiple_value(res);
28743 	      s7_error(sc, sc->bad_result_symbol, set_elist_2(sc, wrap_string(sc, "input-function-port char-ready? returned: ~S", 44), res));
28744 	    }
28745 	  return(make_boolean(sc, (res != sc->F))); /* char-ready? returns a boolean */
28746 	}
28747       return(make_boolean(sc, is_string_port(pt)));
28748     }
28749   return(make_boolean(sc, (is_input_port(current_input_port(sc))) && (is_string_port(current_input_port(sc)))));
28750 }
28751 #endif
28752 
28753 /* -------- ports -------- */
28754 static int32_t closed_port_read_char(s7_scheme *sc, s7_pointer port);
28755 static s7_pointer closed_port_read_line(s7_scheme *sc, s7_pointer port, bool with_eol);
28756 static void closed_port_write_char(s7_scheme *sc, uint8_t c, s7_pointer port);
28757 static void closed_port_write_string(s7_scheme *sc, const char *str, s7_int len, s7_pointer port);
28758 static void closed_port_display(s7_scheme *sc, const char *s, s7_pointer port);
28759 
28760 static void close_closed_port(s7_scheme *sc, s7_pointer port) {return;}
28761 
28762 static port_functions_t closed_port_functions =
28763   {closed_port_read_char, closed_port_write_char, closed_port_write_string, NULL, NULL, NULL, NULL,
28764    closed_port_read_line, closed_port_display, close_closed_port};
28765 
28766 
28767 static void close_input_file(s7_scheme *sc, s7_pointer p)
28768 {
28769   if (port_filename(p))
28770     {
28771       /* for string ports, this is the original input file name */
28772       liberate(sc, port_filename_block(p));
28773       port_filename(p) = NULL;
28774     }
28775   if (port_file(p))
28776     {
28777       fclose(port_file(p));
28778       port_file(p) = NULL;
28779     }
28780   if (port_needs_free(p))
28781     free_port_data(sc, p);
28782 
28783   port_port(p)->pf = &closed_port_functions;
28784   port_set_closed(p, true);
28785   port_position(p) = 0;
28786 }
28787 
28788 static void close_input_string(s7_scheme *sc, s7_pointer p)
28789 {
28790   if (port_filename(p))
28791     {
28792       /* for string ports, this is the original input file name */
28793       liberate(sc, port_filename_block(p));
28794       port_filename(p) = NULL;
28795     }
28796   if (port_needs_free(p))
28797     free_port_data(sc, p);
28798 
28799   port_port(p)->pf = &closed_port_functions;
28800   port_set_closed(p, true);
28801   port_position(p) = 0;
28802 }
28803 
28804 static void close_simple_input_string(s7_scheme *sc, s7_pointer p)
28805 {
28806 #if S7_DEBUGGING
28807   if (port_filename(p))
28808     fprintf(stderr, "%s: port has a filename\n", __func__);
28809   if (port_needs_free(p))
28810     fprintf(stderr, "%s: port needs free\n", __func__);
28811 #endif
28812   port_port(p)->pf = &closed_port_functions;
28813   port_set_closed(p, true);
28814   port_position(p) = 0;
28815 }
28816 
28817 void s7_close_input_port(s7_scheme *sc, s7_pointer p) {port_close(p)(sc, p);}
28818 
28819 
28820 /* -------------------------------- close-input-port -------------------------------- */
28821 static s7_pointer g_close_input_port(s7_scheme *sc, s7_pointer args)
28822 {
28823   s7_pointer pt;
28824   #define H_close_input_port "(close-input-port port) closes the port"
28825   #define Q_close_input_port s7_make_signature(sc, 2, sc->is_unspecified_symbol, sc->is_input_port_symbol)
28826 
28827   pt = car(args);
28828   if (!is_input_port(pt))
28829     return(method_or_bust_with_type_one_arg_p(sc, pt, sc->close_input_port_symbol, an_input_port_string));
28830   if ((!is_immutable_port(pt)) &&  /* (close-input-port *stdin*) */
28831       (!is_loader_port(pt)))       /* top-level unmatched (close-input-port (current-input-port)) should not clobber the loader's input port */
28832     s7_close_input_port(sc, pt);
28833   return(sc->unspecified);
28834 }
28835 
28836 
28837 /* -------------------------------- flush-output-port -------------------------------- */
28838 void s7_flush_output_port(s7_scheme *sc, s7_pointer p)
28839 {
28840   if ((!is_output_port(p)) ||
28841       (!is_file_port(p)) ||
28842       (port_is_closed(p)) ||
28843       (p == sc->F))
28844     return;
28845 
28846   if (port_file(p))
28847     {
28848       if (port_position(p) > 0)
28849 	{
28850 	  if (fwrite((void *)(port_data(p)), 1, port_position(p), port_file(p)) != (size_t)port_position(p))
28851 	    s7_warn(sc, 64, "fwrite trouble in flush-output-port\n");
28852 	  port_position(p) = 0;
28853 	}
28854       fflush(port_file(p));
28855     }
28856 }
28857 
28858 static s7_pointer g_flush_output_port(s7_scheme *sc, s7_pointer args)
28859 {
28860   #define H_flush_output_port "(flush-output-port port) flushes the file port (that is, it writes any accumulated output to the output file)"
28861   #define Q_flush_output_port s7_make_signature(sc, 2, sc->T, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
28862   s7_pointer pt;
28863 
28864   pt = (is_null(args)) ? current_output_port(sc) : car(args);
28865   if (!is_output_port(pt))
28866     {
28867       if (pt == sc->F) return(pt);
28868       return(method_or_bust_with_type_one_arg(sc, pt, sc->flush_output_port_symbol, args, an_output_port_string));
28869     }
28870   s7_flush_output_port(sc, pt);
28871   return(pt);
28872 }
28873 
28874 
28875 /* -------------------------------- close-output-port -------------------------------- */
28876 static void close_output_file(s7_scheme *sc, s7_pointer p)
28877 {
28878   if (port_filename(p)) /* only a file output port has a filename(?) */
28879     {
28880       liberate(sc, port_filename_block(p));
28881       port_filename(p) = NULL;
28882       port_filename_length(p) = 0;
28883     }
28884   if (port_file(p))
28885     {
28886       if ((port_position(p) > 0) &&
28887 	  (fwrite((void *)(port_data(p)), 1, port_position(p), port_file(p)) != (size_t)port_position(p)))
28888 	s7_warn(sc, 64, "fwrite trouble in close-output-port\n");
28889       fflush(port_file(p));
28890       fclose(port_file(p));
28891       port_file(p) = NULL;
28892     }
28893   port_port(p)->pf = &closed_port_functions;
28894   port_set_closed(p, true);
28895   port_position(p) = 0;
28896 }
28897 
28898 static void close_output_string(s7_scheme *sc, s7_pointer p)
28899 {
28900   if (port_data(p))
28901     {
28902       port_data(p) = NULL;
28903       port_data_size(p) = 0;
28904     }
28905   port_port(p)->pf = &closed_port_functions;
28906   port_set_closed(p, true);
28907   port_position(p) = 0;
28908 }
28909 
28910 static void close_output_port(s7_scheme *sc, s7_pointer p) {port_close(p)(sc, p);}
28911 
28912 void s7_close_output_port(s7_scheme *sc, s7_pointer p)
28913 {
28914   if ((p == sc->F) || (is_immutable_port(p))) return; /* can these happen? */
28915   close_output_port(sc, p);
28916 }
28917 
28918 static s7_pointer g_close_output_port(s7_scheme *sc, s7_pointer args)
28919 {
28920   s7_pointer pt;
28921   #define H_close_output_port "(close-output-port port) closes the port"
28922   #define Q_close_output_port s7_make_signature(sc, 2, sc->is_unspecified_symbol, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
28923 
28924   pt = car(args);
28925   if (!is_output_port(pt))
28926     {
28927       if (pt == sc->F) return(sc->unspecified);
28928       return(method_or_bust_with_type_one_arg_p(sc, pt, sc->close_output_port_symbol, an_output_port_string));
28929     }
28930   s7_close_output_port(sc, pt);
28931   return(sc->unspecified);
28932 }
28933 
28934 
28935 /* -------- read character functions -------- */
28936 
28937 static int32_t file_read_char(s7_scheme *sc, s7_pointer port)
28938 {
28939   return(fgetc(port_file(port)));
28940 }
28941 
28942 static int32_t function_read_char(s7_scheme *sc, s7_pointer port)
28943 {
28944   s7_pointer res;
28945   res = (*(port_input_function(port)))(sc, S7_READ_CHAR, port);
28946   if (is_eof(res)) return(EOF);
28947   if (!s7_is_character(res))          /* port_input_function might return some non-character */
28948     {
28949       if (is_multiple_value(res))
28950 	{
28951 	  clear_multiple_value(res);
28952 	  s7_error(sc, sc->bad_result_symbol, set_elist_2(sc, wrap_string(sc, "input-function-port read-char returned: ~S", 42), res));
28953 	}
28954       s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "input_function_port read_char returned: ~S", 42), res));
28955     }
28956   return((int32_t)character(res));    /* kinda nutty -- we return chars[this] in g_read_char! */
28957 }
28958 
28959 static int32_t string_read_char(s7_scheme *sc, s7_pointer port)
28960 {
28961   return((port_data_size(port) <= port_position(port)) ? EOF : (uint8_t)port_data(port)[port_position(port)++]); /* port_string_length is 0 if no port string */
28962 }
28963 
28964 static int32_t output_read_char(s7_scheme *sc, s7_pointer port)
28965 {
28966   simple_wrong_type_argument_with_type(sc, sc->read_char_symbol, port, an_input_port_string);
28967   return(0);
28968 }
28969 
28970 static int32_t closed_port_read_char(s7_scheme *sc, s7_pointer port)
28971 {
28972   simple_wrong_type_argument_with_type(sc, sc->read_char_symbol, port, an_open_port_string);
28973   return(0);
28974 }
28975 
28976 
28977 /* -------- read line functions -------- */
28978 
28979 static s7_pointer output_read_line(s7_scheme *sc, s7_pointer port, bool with_eol)
28980 {
28981   return(simple_wrong_type_argument_with_type(sc, sc->read_line_symbol, port, an_input_port_string));
28982 }
28983 
28984 static s7_pointer closed_port_read_line(s7_scheme *sc, s7_pointer port, bool with_eol)
28985 {
28986   return(simple_wrong_type_argument_with_type(sc, sc->read_line_symbol, port, an_open_port_string));
28987 }
28988 
28989 static s7_pointer function_read_line(s7_scheme *sc, s7_pointer port, bool with_eol)
28990 {
28991   s7_pointer res;
28992   res = (*(port_input_function(port)))(sc, S7_READ_LINE, port);
28993   if (is_multiple_value(res))
28994     {
28995       clear_multiple_value(res);
28996       s7_error(sc, sc->bad_result_symbol, set_elist_2(sc, wrap_string(sc, "input-function-port read-line returned: ~S", 42), res));
28997     }
28998   return(res);
28999 }
29000 
29001 static s7_pointer stdin_read_line(s7_scheme *sc, s7_pointer port, bool with_eol)
29002 {
29003   if (!sc->read_line_buf)
29004     {
29005       sc->read_line_buf_size = 1024;
29006       sc->read_line_buf = (char *)Malloc(sc->read_line_buf_size);
29007     }
29008 
29009   if (fgets(sc->read_line_buf, sc->read_line_buf_size, stdin))
29010     return(s7_make_string(sc, sc->read_line_buf)); /* fgets adds the trailing '\0' */
29011   return(make_string_with_length(sc, NULL, 0));
29012 }
29013 
29014 static s7_pointer file_read_line(s7_scheme *sc, s7_pointer port, bool with_eol)
29015 {
29016   /* read into read_line_buf concatenating reads until newline found.  string is read_line_buf to pos-of-newline.
29017    *   reset file position to reflect newline pos.
29018    */
29019   int32_t reads = 0;
29020   char *str;
29021   s7_int read_size;
29022   if (!sc->read_line_buf)
29023     {
29024       sc->read_line_buf_size = 1024;
29025       sc->read_line_buf = (char *)Malloc(sc->read_line_buf_size);
29026     }
29027   read_size = sc->read_line_buf_size;
29028   str = fgets(sc->read_line_buf, read_size, port_file(port)); /* reads size-1 at most, EOF and newline also terminate read */
29029   if (!str) return(eof_object);                               /* EOF or error with no char read */
29030 
29031   while (true)
29032     {
29033       s7_int cur_size;
29034       char *buf, *snew;
29035 
29036       snew = strchr(sc->read_line_buf, (int)'\n'); /* or maybe just strlen + end-of-string=newline */
29037       if (snew)
29038 	{
29039 	  s7_int pos;
29040 	  pos = (s7_int)(snew - sc->read_line_buf);
29041 	  port_line_number(port)++;
29042 	  return(make_string_with_length(sc, sc->read_line_buf, (with_eol) ? (pos + 1) : pos));
29043 	}
29044       reads++;
29045       cur_size = strlen(sc->read_line_buf);
29046       if ((cur_size + reads) < read_size) /* end of data, no newline */
29047 	return(make_string_with_length(sc, sc->read_line_buf, cur_size));
29048 
29049       /* need more data */
29050       sc->read_line_buf_size *= 2;
29051       sc->read_line_buf = (char *)Realloc(sc->read_line_buf, sc->read_line_buf_size);
29052       buf = (char *)(sc->read_line_buf + cur_size);
29053       str = fgets(buf, read_size, port_file(port));
29054       if (!str) return(eof_object);
29055       read_size = sc->read_line_buf_size;
29056     }
29057   return(eof_object);
29058 }
29059 
29060 static s7_pointer string_read_line(s7_scheme *sc, s7_pointer port, bool with_eol)
29061 {
29062   s7_int i, port_start;
29063   uint8_t *port_str, *cur, *start;
29064 
29065   port_start = port_position(port);
29066   port_str = port_data(port);
29067   start = (uint8_t *)(port_str + port_start);
29068 
29069   cur = (uint8_t *)strchr((const char *)start, (int)'\n'); /* this can run off the end making valgrind unhappy, but I think it's innocuous */
29070   if (cur)
29071     {
29072       port_line_number(port)++;
29073       i = cur - port_str;
29074       port_position(port) = i + 1;
29075       return(make_string_with_length(sc, (const char *)start, ((with_eol) ? i + 1 : i) - port_start));
29076     }
29077   i = port_data_size(port);
29078   port_position(port) = i;
29079   if (i <= port_start)         /* the < part can happen -- if not caught we try to create a string of length - 1 -> segfault */
29080     return(eof_object);
29081 
29082   return(inline_make_string_with_length(sc, (const char *)start, i - port_start));
29083 }
29084 
29085 
29086 /* -------- write character functions -------- */
29087 
29088 static void resize_port_data(s7_scheme *sc, s7_pointer pt, s7_int new_size)
29089 {
29090   s7_int loc;
29091   block_t *nb;
29092 
29093   loc = port_data_size(pt);
29094   if (new_size < loc) return;
29095   if (new_size > sc->max_port_data_size)
29096     s7_error(sc, make_symbol(sc, "port-too-big"),
29097 	     set_elist_1(sc, wrap_string(sc, "port data size has grown past (*s7* 'max-port-data-size)", 56)));
29098 
29099   nb = reallocate(sc, port_data_block(pt), new_size);
29100   port_data_block(pt) = nb;
29101   port_data(pt) = (uint8_t *)(block_data(nb));
29102   port_data_size(pt) = new_size;
29103 }
29104 
29105 static void string_write_char_resized(s7_scheme *sc, uint8_t c, s7_pointer pt)
29106 {
29107   /* this division looks repetitive, but it is much faster */
29108   resize_port_data(sc, pt, port_data_size(pt) * 2);
29109   port_data(pt)[port_position(pt)++] = c;
29110 }
29111 
29112 static void string_write_char(s7_scheme *sc, uint8_t c, s7_pointer pt)
29113 {
29114   if (port_position(pt) < port_data_size(pt))
29115     port_data(pt)[port_position(pt)++] = c;
29116   else string_write_char_resized(sc, c, pt);
29117 }
29118 
29119 static void stdout_write_char(s7_scheme *sc, uint8_t c, s7_pointer port) {fputc(c, stdout);}
29120 static void stderr_write_char(s7_scheme *sc, uint8_t c, s7_pointer port) {fputc(c, stderr);}
29121 
29122 static void function_write_char(s7_scheme *sc, uint8_t c, s7_pointer port)
29123 {
29124   (*(port_output_function(port)))(sc, c, port);
29125 }
29126 
29127 static Inline void inline_file_write_char(s7_scheme *sc, uint8_t c, s7_pointer port)
29128 {
29129   if (port_position(port) == sc->output_port_data_size)
29130     {
29131       if (fwrite((void *)(port_data(port)), 1, sc->output_port_data_size, port_file(port)) != (size_t)sc->output_port_data_size)
29132 	s7_warn(sc, 64, "fwrite trouble during write-char\n");
29133       port_position(port) = 0;
29134     }
29135   port_data(port)[port_position(port)++] = c;
29136 }
29137 
29138 static void file_write_char(s7_scheme *sc, uint8_t c, s7_pointer port) {return(inline_file_write_char(sc, c, port));}
29139 
29140 static void input_write_char(s7_scheme *sc, uint8_t c, s7_pointer port)
29141 {
29142   simple_wrong_type_argument_with_type(sc, sc->write_char_symbol, port, an_output_port_string);
29143 }
29144 
29145 static void closed_port_write_char(s7_scheme *sc, uint8_t c, s7_pointer port)
29146 {
29147   simple_wrong_type_argument_with_type(sc, sc->write_char_symbol, port, an_open_port_string);
29148 }
29149 
29150 
29151 /* -------- write string functions -------- */
29152 
29153 static void input_write_string(s7_scheme *sc, const char *str, s7_int len, s7_pointer port)
29154 {
29155   simple_wrong_type_argument_with_type(sc, sc->write_symbol, port, an_output_port_string);
29156 }
29157 
29158 static void closed_port_write_string(s7_scheme *sc, const char *str, s7_int len, s7_pointer port)
29159 {
29160   simple_wrong_type_argument_with_type(sc, sc->write_symbol, port, an_open_port_string);
29161 }
29162 
29163 static void input_display(s7_scheme *sc, const char *s, s7_pointer port)
29164 {
29165   simple_wrong_type_argument_with_type(sc, sc->display_symbol, port, an_output_port_string);
29166 }
29167 
29168 static void closed_port_display(s7_scheme *sc, const char *s, s7_pointer port)
29169 {
29170   simple_wrong_type_argument_with_type(sc, sc->display_symbol, port, an_open_port_string);
29171 }
29172 
29173 static void stdout_write_string(s7_scheme *sc, const char *str, s7_int len, s7_pointer port)
29174 {
29175   if (str[len] == '\0')
29176     fputs(str, stdout);
29177   else
29178     {
29179       s7_int i;
29180       for (i = 0; i < len; i++)
29181 	fputc(str[i], stdout);
29182     }
29183 }
29184 
29185 static void stderr_write_string(s7_scheme *sc, const char *str, s7_int len, s7_pointer port)
29186 {
29187   if (str[len] == '\0')
29188     fputs(str, stderr);
29189   else
29190     {
29191       s7_int i;
29192       for (i = 0; i < len; i++)
29193 	fputc(str[i], stderr);
29194     }
29195 }
29196 
29197 static void string_write_string_resized(s7_scheme *sc, const char *str, s7_int len, s7_pointer pt)
29198 {
29199   s7_int new_len;  /* len is known to be non-zero, str might not be 0-terminated */
29200   new_len = port_position(pt) + len;
29201   resize_port_data(sc, pt, new_len * 2);
29202   memcpy((void *)(port_data(pt) + port_position(pt)), (void *)str, len);
29203   port_position(pt) = new_len;
29204 }
29205 
29206 static void string_write_string(s7_scheme *sc, const char *str, s7_int len, s7_pointer pt)
29207 {
29208 #if S7_DEBUGGING
29209   if (len == 0) {fprintf(stderr, "string_write_string len == 0\n"); abort();}
29210 #endif
29211   if (port_position(pt) + len < port_data_size(pt))
29212     {
29213       memcpy((void *)(port_data(pt) + port_position(pt)), (void *)str, len);
29214       /* memcpy is much faster than the equivalent while loop, and faster than using the 4-bytes-at-a-time shuffle */
29215       port_position(pt) += len;
29216     }
29217   else string_write_string_resized(sc, str, len, pt);
29218 }
29219 
29220 static void file_write_string(s7_scheme *sc, const char *str, s7_int len, s7_pointer pt)
29221 {
29222   s7_int new_len;
29223   new_len = port_position(pt) + len;
29224   if (new_len >= sc->output_port_data_size)
29225     {
29226       if (port_position(pt) > 0)
29227 	{
29228 	  if (fwrite((void *)(port_data(pt)), 1, port_position(pt), port_file(pt)) != (size_t)port_position(pt))
29229 	    s7_warn(sc, 64, "fwrite trouble in write-string\n");
29230 	  port_position(pt) = 0;
29231 	}
29232       if (fwrite((void *)str, 1, len, port_file(pt)) != (size_t)len)
29233 	s7_warn(sc, 64, "fwrite trouble in write-string\n");
29234     }
29235   else
29236     {
29237       memcpy((void *)(port_data(pt) + port_position(pt)), (void *)str, len);
29238       port_position(pt) = new_len;
29239     }
29240 }
29241 
29242 static void string_display(s7_scheme *sc, const char *s, s7_pointer port)
29243 {
29244   if (s)
29245     string_write_string(sc, s, safe_strlen(s), port);
29246 }
29247 
29248 static void file_display(s7_scheme *sc, const char *s, s7_pointer port)
29249 {
29250   if (s)
29251     {
29252       if (port_position(port) > 0)
29253 	{
29254 	  if (fwrite((void *)(port_data(port)), 1, port_position(port), port_file(port)) != (size_t)port_position(port))
29255 	    s7_warn(sc, 64, "fwrite trouble in display\n");
29256 	  port_position(port) = 0;
29257 	}
29258       if (fputs(s, port_file(port)) == EOF)
29259 	s7_warn(sc, 64, "write to %s: %s\n", port_filename(port), strerror(errno));
29260     }
29261 }
29262 
29263 static void function_display(s7_scheme *sc, const char *s, s7_pointer port)
29264 {
29265   if (s)
29266     for (; *s; s++)
29267       (*(port_output_function(port)))(sc, *s, port);
29268 }
29269 
29270 static void function_write_string(s7_scheme *sc, const char *str, s7_int len, s7_pointer pt)
29271 {
29272   s7_int i;
29273   for (i = 0; i < len; i++)
29274     (*(port_output_function(pt)))(sc, str[i], pt);
29275 }
29276 
29277 static void stdout_display(s7_scheme *sc, const char *s, s7_pointer port) {if (s) fputs(s, stdout);}
29278 static void stderr_display(s7_scheme *sc, const char *s, s7_pointer port) {if (s) fputs(s, stderr);}
29279 
29280 
29281 /* -------------------------------- write-string -------------------------------- */
29282 static s7_pointer g_write_string(s7_scheme *sc, s7_pointer args)
29283 {
29284   #define H_write_string "(write-string str port start end) writes str to port."
29285   #define Q_write_string s7_make_circular_signature(sc, 3, 4, sc->is_string_symbol, sc->is_string_symbol, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol), sc->is_integer_symbol)
29286   s7_pointer str, port;
29287   s7_int start = 0, end;
29288 
29289   str = car(args);
29290   if (!is_string(str))
29291     return(method_or_bust(sc, str, sc->write_string_symbol, args, T_STRING, 1));
29292 
29293   end = string_length(str);
29294   if (!is_null(cdr(args)))
29295     {
29296       s7_pointer inds;
29297       port = cadr(args);
29298       inds = cddr(args);
29299       if (!is_null(inds))
29300 	{
29301 	  s7_pointer p;
29302 	  p = start_and_end(sc, sc->write_string_symbol, args, 3, inds, &start, &end);
29303 	  if (p != sc->unused) return(p);
29304 	}}
29305   else port = current_output_port(sc);
29306   if (!is_output_port(port))
29307     {
29308       if (port == sc->F)
29309 	{
29310 	  s7_int len;
29311 	  if ((start == 0) && (end == string_length(str)))
29312 	    return(str);
29313 	  len = (s7_int)(end - start);
29314 	  return(make_string_with_length(sc, (char *)(string_value(str) + start), len));
29315 	}
29316       return(method_or_bust_with_type(sc, port, sc->write_string_symbol, args, an_output_port_string, 2));
29317     }
29318   if (start == end)
29319     return(str);
29320   port_write_string(port)(sc, (char *)(string_value(str) + start), (end - start), port);
29321   return(str);
29322 }
29323 
29324 static s7_pointer write_string_p_pp(s7_scheme *sc, s7_pointer str, s7_pointer port)
29325 {
29326   if (!is_string(str))
29327     return(method_or_bust_pp(sc, str, sc->write_string_symbol, str, port, T_STRING, 1));
29328   if (!is_output_port(port))
29329     {
29330       if (port == sc->F)
29331 	return(str);
29332       return(method_or_bust_with_type_pp(sc, port, sc->write_string_symbol, str, port, an_output_port_string, 2));
29333     }
29334   if (string_length(str) > 0)
29335     port_write_string(port)(sc, string_value(str), string_length(str), port);
29336   return(str);
29337 }
29338 
29339 
29340 /* -------- skip to newline readers -------- */
29341 static token_t token(s7_scheme *sc);
29342 
29343 static token_t file_read_semicolon(s7_scheme *sc, s7_pointer pt)
29344 {
29345   int32_t c;
29346   do (c = fgetc(port_file(pt))); while ((c != '\n') && (c != EOF));
29347   port_line_number(pt)++;
29348   return((c == EOF) ? TOKEN_EOF : token(sc));
29349 }
29350 
29351 static token_t string_read_semicolon(s7_scheme *sc, s7_pointer pt)
29352 {
29353   const char *orig_str, *str;
29354   str = (const char *)(port_data(pt) + port_position(pt));
29355   orig_str = strchr(str, (int)'\n');
29356   if (!orig_str)
29357     {
29358       port_position(pt) = port_data_size(pt);
29359       return(TOKEN_EOF);
29360     }
29361   port_position(pt) += (orig_str - str + 1); /* + 1 because strchr leaves orig_str pointing at the newline */
29362   port_line_number(pt)++;
29363   return(token(sc));
29364 }
29365 
29366 
29367 /* -------- white space readers -------- */
29368 
29369 static int32_t file_read_white_space(s7_scheme *sc, s7_pointer port)
29370 {
29371   int32_t c;
29372   while (is_white_space(c = fgetc(port_file(port))))
29373     if (c == '\n')
29374       port_line_number(port)++;
29375   return(c);
29376 }
29377 
29378 static int32_t terminated_string_read_white_space(s7_scheme *sc, s7_pointer pt)
29379 {
29380   const uint8_t *str;
29381   uint8_t c;
29382   /* here we know we have null termination and white_space[#\null] is false. */
29383 
29384   str = (const uint8_t *)(port_data(pt) + port_position(pt));
29385 
29386   while (white_space[c = *str++]) /* 255 is not -1 = EOF */
29387     if (c == '\n')
29388       port_line_number(pt)++;
29389   port_position(pt) = (c) ? str - port_data(pt) : port_data_size(pt);
29390   return((int32_t)c);
29391 }
29392 
29393 
29394 /* name (alphanumeric token) readers */
29395 
29396 #define BASE_10 10
29397 
29398 static s7_pointer file_read_name_or_sharp(s7_scheme *sc, s7_pointer pt, bool atom_case)
29399 {
29400   int32_t c;
29401   s7_int i = 1;
29402   /* sc->strbuf[0] has the first char of the string we're reading */
29403 
29404   do {
29405     c = fgetc(port_file(pt)); /* might return EOF */
29406     if (c == '\n')
29407       port_line_number(pt)++;
29408 
29409     sc->strbuf[i++] = (unsigned char)c;
29410     if (i >= sc->strbuf_size)
29411       resize_strbuf(sc, i);
29412   } while ((c != EOF) && (char_ok_in_a_name[c]));
29413 
29414   if ((i == 2) &&
29415       (sc->strbuf[0] == '\\'))
29416     sc->strbuf[2] = '\0';
29417   else
29418     {
29419       if (c != EOF)
29420 	{
29421 	  if (c == '\n')
29422 	    port_line_number(pt)--;
29423 	  ungetc(c, port_file(pt));
29424 	}
29425       sc->strbuf[i - 1] = '\0';
29426     }
29427 
29428   if (atom_case)
29429     return(make_atom(sc, sc->strbuf, BASE_10, SYMBOL_OK, WITH_OVERFLOW_ERROR));
29430 
29431   return(make_sharp_constant(sc, sc->strbuf, WITH_OVERFLOW_ERROR, pt, true));
29432 }
29433 
29434 static s7_pointer file_read_name(s7_scheme *sc, s7_pointer pt)  {return(file_read_name_or_sharp(sc, pt, true));}
29435 static s7_pointer file_read_sharp(s7_scheme *sc, s7_pointer pt) {return(file_read_name_or_sharp(sc, pt, false));}
29436 
29437 static s7_pointer string_read_name_no_free(s7_scheme *sc, s7_pointer pt)
29438 {
29439   /* sc->strbuf[0] has the first char of the string we're reading */
29440   s7_pointer result;
29441   char *str;
29442 
29443   str = (char *)(port_data(pt) + port_position(pt));
29444 
29445   if (char_ok_in_a_name[(uint8_t)*str])
29446     {
29447       s7_int k;
29448       char *orig_str;
29449 
29450       orig_str = (char *)(str - 1);
29451       str++;
29452       while (char_ok_in_a_name[(uint8_t)(*str)]) {str++;}
29453       k = str - orig_str;
29454       if (*str != 0)
29455 	port_position(pt) += (k - 1);
29456       else port_position(pt) = port_data_size(pt);
29457 
29458       /* this is equivalent to:
29459        *    str = strpbrk(str, "(); \"\t\r\n");
29460        *    if (!str)
29461        *      {
29462        *        k = strlen(orig_str);
29463        *        str = (char *)(orig_str + k);
29464        *      }
29465        *    else k = str - orig_str;
29466        * but slightly faster.
29467        */
29468 
29469       if (!number_table[(uint8_t)(*orig_str)])
29470 	return(make_symbol_with_length(sc, orig_str, k));
29471 
29472       /* eval_c_string string is a constant so we can't set and unset the token's end char */
29473       if ((k + 1) >= sc->strbuf_size)
29474 	resize_strbuf(sc, k + 1);
29475 
29476       memcpy((void *)(sc->strbuf), (void *)orig_str, k);
29477       sc->strbuf[k] = '\0';
29478       return(make_atom(sc, sc->strbuf, BASE_10, SYMBOL_OK, WITH_OVERFLOW_ERROR));
29479     }
29480 
29481   result = sc->singletons[(uint8_t)(sc->strbuf[0])];
29482   if (!result)
29483     {
29484       sc->strbuf[1] = '\0';
29485       result = make_symbol_with_length(sc, sc->strbuf, 1);
29486       sc->singletons[(uint8_t)(sc->strbuf[0])] = result;
29487     }
29488   return(result);
29489 }
29490 
29491 static s7_pointer string_read_sharp(s7_scheme *sc, s7_pointer pt)
29492 {
29493   /* sc->strbuf[0] has the first char of the string we're reading.
29494    *   since a *#readers* function might want to get further input, we can't mess with the input even when it is otherwise safe
29495    */
29496   char *str;
29497   str = (char *)(port_data(pt) + port_position(pt));
29498 
29499   if (char_ok_in_a_name[(uint8_t)*str])
29500     {
29501       s7_int k;
29502       char * orig_str;
29503       orig_str = (char *)(str - 1);
29504       str++;
29505       while (char_ok_in_a_name[(uint8_t)(*str)]) {str++;}
29506       k = str - orig_str;
29507       if (*str != 0)
29508 	port_position(pt) += (k - 1);
29509       else port_position(pt) += k;
29510 
29511       if ((k + 1) >= sc->strbuf_size)
29512 	resize_strbuf(sc, k + 1);
29513 
29514       memcpy((void *)(sc->strbuf), (void *)orig_str, k);
29515       sc->strbuf[k] = '\0';
29516       return(make_sharp_constant(sc, sc->strbuf, WITH_OVERFLOW_ERROR, pt, true));
29517     }
29518   if (sc->strbuf[0] == 'f')
29519     return(sc->F);
29520   if (sc->strbuf[0] == 't')
29521     return(sc->T);
29522   if (sc->strbuf[0] == '\\')
29523     {
29524       /* must be from #\( and friends -- a character that happens to be not ok-in-a-name */
29525       sc->strbuf[1] = str[0];
29526       sc->strbuf[2] = '\0';
29527       port_position(pt)++;
29528     }
29529   else sc->strbuf[1] = '\0';
29530   return(make_sharp_constant(sc, sc->strbuf, WITH_OVERFLOW_ERROR, pt, true));
29531 }
29532 
29533 static s7_pointer string_read_name(s7_scheme *sc, s7_pointer pt)
29534 {
29535   /* port_string was allocated (and read from a file) so we can mess with it directly */
29536   s7_pointer result;
29537   char *str;
29538 
29539   str = (char *)(port_data(pt) + port_position(pt));
29540   if (char_ok_in_a_name[(uint8_t)*str])
29541     {
29542       s7_int k;
29543       char endc;
29544       char *orig_str;
29545       orig_str = (char *)(str - 1);
29546       str++;
29547       while (char_ok_in_a_name[(uint8_t)(*str)]) {str++;}
29548       k = str - orig_str;
29549       if (*str != 0)
29550 	port_position(pt) += (k - 1);
29551       else port_position(pt) = port_data_size(pt);
29552 
29553       if (!number_table[(uint8_t)(*orig_str)])
29554 	return(make_symbol_with_length(sc, orig_str, k));
29555 
29556       endc = (*str);
29557       (*str) = '\0';
29558       result = make_atom(sc, orig_str, BASE_10, SYMBOL_OK, WITH_OVERFLOW_ERROR);
29559       (*str) = endc;
29560       return(result);
29561     }
29562   result = sc->singletons[(uint8_t)(sc->strbuf[0])];
29563   if (!result)
29564     {
29565       sc->strbuf[1] = '\0';
29566       result = make_symbol_with_length(sc, sc->strbuf, 1);
29567       sc->singletons[(uint8_t)(sc->strbuf[0])] = result;
29568     }
29569   return(result);
29570 }
29571 
29572 static inline void port_set_filename(s7_scheme *sc, s7_pointer p, const char *name, size_t len)
29573 {
29574   block_t *b;
29575   b = mallocate(sc, len + 1);
29576   port_filename_block(p) = b;
29577   port_filename(p) = (char *)block_data(b);
29578   memcpy((void *)block_data(b), (void *)name, len);
29579   port_filename(p)[len] = '\0';
29580 }
29581 
29582 static block_t *mallocate_port(s7_scheme *sc)
29583 {
29584   #define PORT_LIST 8 /* sizeof(port_t): 160 */
29585   block_t *p;
29586   p = sc->block_lists[PORT_LIST];
29587   if (p)
29588     sc->block_lists[PORT_LIST] = (block_t *)block_next(p);
29589   else
29590     { /* this is mallocate without the index calc */
29591       p = mallocate_block(sc);
29592       block_data(p) = (void *)permalloc(sc, (size_t)(1 << PORT_LIST));
29593       block_set_index(p, PORT_LIST);
29594     }
29595   block_set_size(p, sizeof(port_t));
29596   return(p);
29597 }
29598 
29599 static port_functions_t input_file_functions =
29600   {file_read_char, input_write_char, input_write_string, file_read_semicolon, file_read_white_space,
29601    file_read_name, file_read_sharp, file_read_line, input_display, close_input_file};
29602 
29603 static port_functions_t input_string_functions_1 =
29604   {string_read_char, input_write_char, input_write_string, string_read_semicolon, terminated_string_read_white_space,
29605    string_read_name, string_read_sharp, string_read_line, input_display, close_input_string};
29606 
29607 static s7_pointer read_file(s7_scheme *sc, FILE *fp, const char *name, s7_int max_size, const char *caller)
29608 {
29609   s7_pointer port;
29610 #if (!MS_WINDOWS)
29611   s7_int size;
29612 #endif
29613   s7_int port_loc;
29614   block_t *b;
29615 
29616   new_cell(sc, port, T_INPUT_PORT);
29617   port_loc = s7_gc_protect_1(sc, port);
29618   b = mallocate_port(sc);
29619   port_block(port) = b;
29620   port_port(port) = (port_t *)block_data(b);
29621   port_set_closed(port, false);
29622   port_original_input_string(port) = sc->nil;
29623   /* if we're constantly opening files, and each open saves the file name in permanent memory, we gradually core-up. */
29624   port_filename_length(port) = safe_strlen(name);
29625   port_set_filename(sc, port, name, port_filename_length(port));
29626   port_line_number(port) = 1;  /* first line is numbered 1 */
29627   port_file_number(port) = 0;
29628   add_input_port(sc, port);
29629 
29630 #if (!MS_WINDOWS)
29631   /* this doesn't work in MS C */
29632   fseek(fp, 0, SEEK_END);
29633   size = ftell(fp);
29634   rewind(fp);
29635 
29636   /* pseudo files (under /proc for example) have size=0, but we can read them, so don't assume a 0 length file is empty */
29637 
29638   if ((size > 0) &&                          /* if (size != 0) we get (open-input-file "/dev/tty") -> (open "/dev/tty") read 0 bytes of an expected -1? */
29639       ((max_size < 0) || (size < max_size))) /* load uses max_size = -1 */
29640     {
29641       size_t bytes;
29642       block_t *block;
29643       uint8_t *content;
29644 
29645       block = mallocate(sc, size + 2);
29646       content = (uint8_t *)(block_data(block));
29647       bytes = fread(content, sizeof(uint8_t), size, fp);
29648       if (bytes != (size_t)size)
29649 	{
29650 	  if (current_output_port(sc) != sc->F)
29651 	    {
29652 	      char tmp[256];
29653 	      int32_t len;
29654 	      len = snprintf(tmp, 256, "(%s \"%s\") read %ld bytes of an expected %" print_s7_int "?", caller, name, (long)bytes, size);
29655 	      port_write_string(current_output_port(sc))(sc, tmp, len, current_output_port(sc));
29656 	    }
29657 	  size = bytes;
29658 	}
29659       content[size] = '\0';
29660       content[size + 1] = '\0';
29661       fclose(fp);
29662 
29663       port_file(port) = NULL; /* make valgrind happy */
29664       port_type(port) = STRING_PORT;
29665       port_data(port) = content;
29666       port_data_block(port) = block;
29667       port_data_size(port) = size;
29668       port_position(port) = 0;
29669       port_needs_free(port) = true;
29670       port_port(port)->pf = &input_string_functions_1;
29671     }
29672   else
29673     {
29674       port_file(port) = fp;
29675       port_type(port) = FILE_PORT;
29676       port_data(port) = NULL;
29677       port_data_block(port) = NULL;
29678       port_data_size(port) = 0;
29679       port_position(port) = 0;
29680       port_needs_free(port) = false;
29681       port_port(port)->pf = &input_file_functions;
29682     }
29683 #else
29684   /* _stat64 is no better than the fseek/ftell route, and
29685    *    GetFileSizeEx and friends requires Windows.h which makes hash of everything else.
29686    *    fread until done takes too long on big files, so use a file port
29687    */
29688   port_file(port) = fp;
29689   port_type(port) = FILE_PORT;
29690   port_needs_free(port) = false;
29691   port_data(port) = NULL;
29692   port_data_block(port) = NULL;
29693   port_data_size(port) = 0;
29694   port_position(port) = 0;
29695   port_port(port)->pf = &input_file_functions;
29696 #endif
29697 
29698   s7_gc_unprotect_at(sc, port_loc);
29699   return(port);
29700 }
29701 
29702 
29703 /* -------------------------------- open-input-file -------------------------------- */
29704 static int32_t remember_file_name(s7_scheme *sc, const char *file)
29705 {
29706   int32_t i;
29707 
29708   for (i = 0; i <= sc->file_names_top; i++)
29709     if (safe_strcmp(file, string_value(sc->file_names[i])))
29710       return(i);
29711 
29712   sc->file_names_top++;
29713   if (sc->file_names_top >= sc->file_names_size)
29714     {
29715       int32_t old_size = 0;
29716       /* what if file_names_size is greater than file_bits in pair|profile_file? */
29717       if (sc->file_names_size == 0)
29718 	{
29719 	  sc->file_names_size = INITIAL_FILE_NAMES_SIZE;
29720 	  sc->file_names = (s7_pointer *)Malloc(sc->file_names_size * sizeof(s7_pointer));
29721 	}
29722       else
29723 	{
29724 	  old_size = sc->file_names_size;
29725 	  sc->file_names_size *= 2;
29726 	  sc->file_names = (s7_pointer *)Realloc(sc->file_names, sc->file_names_size * sizeof(s7_pointer));
29727 	}
29728       for (i = old_size; i < sc->file_names_size; i++)
29729 	sc->file_names[i] = sc->F;
29730     }
29731   sc->file_names[sc->file_names_top] = s7_make_permanent_string(sc, file);
29732   return(sc->file_names_top);
29733 }
29734 
29735 
29736 #ifndef MAX_SIZE_FOR_STRING_PORT
29737   #define MAX_SIZE_FOR_STRING_PORT 10000000
29738 #endif
29739 
29740 static s7_pointer make_input_file(s7_scheme *sc, const char *name, FILE *fp)
29741 {
29742   return(read_file(sc, fp, name, MAX_SIZE_FOR_STRING_PORT, "open"));
29743 }
29744 
29745 
29746 #if (!MS_WINDOWS)
29747 #include <sys/stat.h>
29748 #endif
29749 
29750 static bool is_directory(const char *filename)
29751 {
29752 #if (!MS_WINDOWS)
29753   #ifdef S_ISDIR
29754     struct stat statbuf;
29755     return((stat(filename, &statbuf) >= 0) &&
29756 	   (S_ISDIR(statbuf.st_mode)));
29757   #endif
29758 #endif
29759   return(false);
29760 }
29761 
29762 static s7_pointer file_error(s7_scheme *sc, const char *caller, const char *descr, const char *name);
29763 
29764 static s7_pointer open_input_file_1(s7_scheme *sc, const char *name, const char *mode, const char *caller)
29765 {
29766   FILE *fp;
29767   /* see if we can open this file before allocating a port */
29768 
29769   if (is_directory(name))
29770     return(file_error(sc, caller, "file is a directory:", name));
29771 
29772   errno = 0;
29773   fp = fopen(name, mode);
29774   if (!fp)
29775     {
29776 #if (!MS_WINDOWS)
29777       if (errno == EINVAL)
29778 	return(file_error(sc, caller, "invalid mode", mode));
29779   #if WITH_GCC
29780       /* catch one special case, "~/..." */
29781       if ((name[0] == '~') &&
29782 	  (name[1] == '/'))
29783 	{
29784 	  char *home;
29785 	  home = getenv("HOME");
29786 	  if (home)
29787 	    {
29788 	      block_t *b;
29789 	      char *filename;
29790 	      s7_int len;
29791 	      len = safe_strlen(name) + safe_strlen(home) + 1;
29792 	      b = mallocate(sc, len);
29793 	      filename = (char *)block_data(b);
29794 	      filename[0] = '\0';
29795 	      catstrs(filename, len, home, (char *)(name + 1), (char *)NULL);
29796 	      fp = fopen(filename, "r");
29797 	      liberate(sc, b);
29798 	      if (fp)
29799 		return(make_input_file(sc, name, fp));
29800 	    }}
29801   #endif
29802 #endif
29803       return(file_error(sc, caller, strerror(errno), name));
29804     }
29805   return(make_input_file(sc, name, fp));
29806 }
29807 
29808 s7_pointer s7_open_input_file(s7_scheme *sc, const char *name, const char *mode)
29809 {
29810   return(open_input_file_1(sc, name, mode, "open-input-file"));
29811 }
29812 
29813 static s7_pointer g_open_input_file(s7_scheme *sc, s7_pointer args)
29814 {
29815   #define H_open_input_file "(open-input-file filename (mode \"r\")) opens filename for reading"
29816   #define Q_open_input_file s7_make_signature(sc, 3, sc->is_input_port_symbol, sc->is_string_symbol, sc->is_string_symbol)
29817   s7_pointer name = car(args);
29818   /* open-input-file can create a new output file if the file to be opened does not exist, and the "a" mode is given */
29819 
29820   if (!is_string(name))
29821     return(method_or_bust(sc, name, sc->open_input_file_symbol, args, T_STRING, 1));
29822 
29823   if (is_pair(cdr(args)))
29824     {
29825       s7_pointer mode;
29826       mode = cadr(args);
29827       if (!is_string(mode))
29828 	return(method_or_bust_with_type(sc, mode, sc->open_input_file_symbol, args,
29829 					wrap_string(sc, "a string (a mode such as \"r\")", 29), 2));
29830       /* since scheme allows embedded nulls, dumb stuff is accepted here: (open-input-file file "a\x00b") -- should this be an error? */
29831       return(open_input_file_1(sc, string_value(name), string_value(mode), "open-input-file"));
29832     }
29833   return(open_input_file_1(sc, string_value(name), "r", "open-input-file"));
29834 }
29835 
29836 static void close_stdin(s7_scheme *sc, s7_pointer port) {return;}
29837 static void close_stdout(s7_scheme *sc, s7_pointer port) {return;}
29838 static void close_stderr(s7_scheme *sc, s7_pointer port) {return;}
29839 
29840 static port_functions_t stdin_functions =
29841   {file_read_char, input_write_char, input_write_string, file_read_semicolon, file_read_white_space,
29842    file_read_name, file_read_sharp, stdin_read_line, input_display, close_stdin};
29843 
29844 static port_functions_t stdout_functions =
29845   {output_read_char, stdout_write_char, stdout_write_string, NULL, NULL, NULL, NULL, output_read_line, stdout_display, close_stdout};
29846 
29847 static port_functions_t stderr_functions =
29848   {output_read_char, stderr_write_char, stderr_write_string, NULL, NULL, NULL, NULL, output_read_line, stderr_display, close_stderr};
29849 
29850 static void init_standard_ports(s7_scheme *sc)
29851 {
29852   s7_pointer x;
29853 
29854   /* standard output */
29855   x = alloc_pointer(sc);
29856   set_full_type(x, T_OUTPUT_PORT | T_IMMUTABLE | T_UNHEAP);
29857   port_port(x) = (port_t *)calloc(1, sizeof(port_t));
29858   port_type(x) = FILE_PORT;
29859   port_data(x) = NULL;
29860   port_data_block(x) = NULL;
29861   port_set_closed(x, false);
29862   port_filename_length(x) = 8;
29863   port_set_filename(sc, x, "*stdout*", 8);
29864   port_file_number(x) = remember_file_name(sc, port_filename(x)); /* these numbers need to be correct for the evaluator (*function* data) */
29865   port_line_number(x) = 0;
29866   port_file(x) = stdout;
29867   port_needs_free(x) = false;
29868   port_port(x)->pf = &stdout_functions;
29869   sc->standard_output = x;
29870 
29871   /* standard error */
29872   x = alloc_pointer(sc);
29873   set_full_type(x, T_OUTPUT_PORT | T_IMMUTABLE | T_UNHEAP);
29874   port_port(x) = (port_t *)calloc(1, sizeof(port_t));
29875   port_type(x) = FILE_PORT;
29876   port_data(x) = NULL;
29877   port_data_block(x) = NULL;
29878   port_set_closed(x, false);
29879   port_filename_length(x) = 8;
29880   port_set_filename(sc, x, "*stderr*", 8);
29881   port_file_number(x) = remember_file_name(sc, port_filename(x));
29882   port_line_number(x) = 0;
29883   port_file(x) = stderr;
29884   port_needs_free(x) = false;
29885   port_port(x)->pf = &stderr_functions;
29886   sc->standard_error = x;
29887 
29888   /* standard input */
29889   x = alloc_pointer(sc);
29890   set_full_type(x, T_INPUT_PORT | T_IMMUTABLE | T_UNHEAP);
29891   port_port(x) = (port_t *)calloc(1, sizeof(port_t));
29892   port_type(x) = FILE_PORT;
29893   port_set_closed(x, false);
29894   port_original_input_string(x) = sc->nil;
29895   port_filename_length(x) = 7;
29896   port_set_filename(sc, x, "*stdin*", 7);
29897   port_file_number(x) = remember_file_name(sc, port_filename(x));
29898   port_line_number(x) = 0;
29899   port_file(x) = stdin;
29900   port_data_block(x) = NULL;
29901   port_needs_free(x) = false;
29902   port_port(x)->pf = &stdin_functions;
29903   sc->standard_input = x;
29904 
29905   s7_define_variable_with_documentation(sc, "*stdin*", sc->standard_input, "*stdin* is the built-in input port, C's stdin");
29906   s7_define_variable_with_documentation(sc, "*stdout*", sc->standard_output, "*stdout* is the built-in buffered output port, C's stdout");
29907   s7_define_variable_with_documentation(sc, "*stderr*", sc->standard_error, "*stderr* is the built-in unbuffered output port, C's stderr");
29908 
29909   set_current_input_port(sc, sc->standard_input);
29910   set_current_output_port(sc, sc->standard_output);
29911   sc->error_port = sc->standard_error;
29912   sc->current_file = NULL;
29913   sc->current_line = -1;
29914 }
29915 
29916 
29917 /* -------------------------------- open-output-file -------------------------------- */
29918 static port_functions_t output_file_functions =
29919   {output_read_char, file_write_char, file_write_string, NULL, NULL, NULL, NULL, output_read_line, file_display, close_output_file};
29920 
29921 s7_pointer s7_open_output_file(s7_scheme *sc, const char *name, const char *mode)
29922 {
29923   FILE *fp;
29924   s7_pointer x;
29925   block_t *block, *b;
29926   /* see if we can open this file before allocating a port */
29927 
29928   errno = 0;
29929   fp = fopen(name, mode);
29930   if (!fp)
29931     {
29932 #if (!MS_WINDOWS)
29933       if (errno == EINVAL)
29934 	return(file_error(sc, "open-output-file", "invalid mode", mode));
29935 #endif
29936       return(file_error(sc, "open-output-file", strerror(errno), name));
29937     }
29938 
29939   new_cell(sc, x, T_OUTPUT_PORT);
29940   b = mallocate_port(sc);
29941   port_block(x) = b;
29942   port_port(x) = (port_t *)block_data(b);
29943   port_type(x) = FILE_PORT;
29944   port_set_closed(x, false);
29945   port_filename_length(x) = safe_strlen(name);
29946   port_set_filename(sc, x, name, port_filename_length(x));
29947   port_line_number(x) = 1;
29948   port_file_number(x) = 0;
29949   port_file(x) = fp;
29950   port_needs_free(x) = true;  /* hmm -- I think these are freed via s7_close_output_port -> close_output_port */
29951   port_position(x) = 0;
29952   port_data_size(x) = sc->output_port_data_size;
29953   block = mallocate(sc, sc->output_port_data_size);
29954   port_data_block(x) = block;
29955   port_data(x) = (uint8_t *)(block_data(block));
29956   port_port(x)->pf = &output_file_functions;
29957   add_output_port(sc, x);
29958   return(x);
29959 }
29960 
29961 static s7_pointer g_open_output_file(s7_scheme *sc, s7_pointer args)
29962 {
29963   #define H_open_output_file "(open-output-file filename (mode \"w\")) opens filename for writing"
29964   #define Q_open_output_file s7_make_signature(sc, 3, sc->is_output_port_symbol, sc->is_string_symbol, sc->is_string_symbol)
29965   s7_pointer name = car(args);
29966 
29967   if (!is_string(name))
29968     return(method_or_bust(sc, name, sc->open_output_file_symbol, args, T_STRING, 1));
29969 
29970   if (is_pair(cdr(args)))
29971     {
29972       if (!is_string(cadr(args)))
29973 	return(method_or_bust_with_type(sc, cadr(args), sc->open_output_file_symbol, args,
29974 				 wrap_string(sc, "a string (a mode such as \"w\")", 29), 2));
29975       return(s7_open_output_file(sc, string_value(name), string_value(cadr(args))));
29976     }
29977   return(s7_open_output_file(sc, string_value(name), "w"));
29978 }
29979 
29980 
29981 /* -------------------------------- open-input-string -------------------------------- */
29982       /* a version of string ports using a pointer to the current location and a pointer to the end
29983        *   (rather than an integer for both, indexing from the base string) was not faster.
29984        */
29985 
29986 static port_functions_t input_string_functions =
29987   {string_read_char, input_write_char, input_write_string, string_read_semicolon, terminated_string_read_white_space,
29988    string_read_name_no_free, string_read_sharp,	string_read_line, input_display, close_simple_input_string};
29989 
29990 static s7_pointer open_input_string(s7_scheme *sc, const char *input_string, s7_int len)
29991 {
29992   s7_pointer x;
29993   block_t *b;
29994   new_cell(sc, x, T_INPUT_PORT);
29995   b = mallocate_port(sc);
29996   port_block(x) = b;
29997   port_port(x) = (port_t *)block_data(b);
29998   port_type(x) = STRING_PORT;
29999   port_set_closed(x, false);
30000   port_original_input_string(x) = sc->nil;
30001   port_data(x) = (uint8_t *)input_string;
30002   port_data_block(x) = NULL;
30003   port_data_size(x) = len;
30004   port_position(x) = 0;
30005   port_filename_block(x) = NULL;
30006   port_filename_length(x) = 0;
30007   port_filename(x) = NULL;
30008   port_file_number(x) = 0;
30009   port_line_number(x) = 0;
30010   port_file(x) = NULL;
30011   port_needs_free(x) = false;
30012 #if S7_DEBUGGING
30013   if (input_string[len] != '\0')
30014     {
30015       fprintf(stderr, "%s[%d]: read_white_space string is not terminated: len: %" print_s7_int ", at end: %c%c, str: %s", __func__, __LINE__, len, input_string[len - 1], input_string[len], input_string);
30016       abort();
30017     }
30018 #endif
30019   port_port(x)->pf = &input_string_functions;
30020   add_input_string_port(sc, x);
30021   return(x);
30022 }
30023 
30024 static inline s7_pointer open_and_protect_input_string(s7_scheme *sc, s7_pointer str)
30025 {
30026   s7_pointer p;
30027   p = open_input_string(sc, string_value(str), string_length(str));
30028   port_original_input_string(p) = str;
30029   return(p);
30030 }
30031 
30032 s7_pointer s7_open_input_string(s7_scheme *sc, const char *input_string)
30033 {
30034   return(open_input_string(sc, input_string, safe_strlen(input_string)));
30035 }
30036 
30037 static s7_pointer g_open_input_string(s7_scheme *sc, s7_pointer args)
30038 {
30039   #define H_open_input_string "(open-input-string str) opens an input port reading str"
30040   #define Q_open_input_string s7_make_signature(sc, 2, sc->is_input_port_symbol, sc->is_string_symbol)
30041   s7_pointer input_string, port;
30042 
30043   input_string = car(args);
30044   if (!is_string(input_string))
30045     return(method_or_bust_one_arg(sc, input_string, sc->open_input_string_symbol, args, T_STRING));
30046   port = open_and_protect_input_string(sc, input_string);
30047   return(port);
30048 }
30049 
30050 
30051 /* -------------------------------- open-output-string -------------------------------- */
30052 #define FORMAT_PORT_LENGTH 128
30053 /* the large majority (> 99% in my tests) of the output strings have less than 128 chars when the port is finally closed
30054  *   256 is slightly slower (the calloc time below dominates the realloc time in string_write_string)
30055  *   64 is much slower (realloc dominates)
30056  */
30057 
30058 static port_functions_t output_string_functions =
30059   {output_read_char, string_write_char, string_write_string, NULL, NULL, NULL, NULL, output_read_line, string_display, close_output_string};
30060 
30061 static s7_pointer open_output_string(s7_scheme *sc, s7_int len)
30062 {
30063   s7_pointer x;
30064   block_t *block, *b;
30065   new_cell(sc, x, T_OUTPUT_PORT);
30066   b = mallocate_port(sc);
30067   port_block(x) = b;
30068   port_port(x) = (port_t *)block_data(b);
30069   port_type(x) = STRING_PORT;
30070   port_set_closed(x, false);
30071   port_data_size(x) = len;
30072   block = mallocate(sc, len);
30073   port_data_block(x) = block;
30074   port_data(x) = (uint8_t *)(block_data(block));
30075   port_data(x)[0] = '\0';        /* in case s7_get_output_string before any output */
30076   port_position(x) = 0;
30077   port_needs_free(x) = true;
30078   port_filename_block(x) = NULL;
30079   port_filename_length(x) = 0;   /* protect against (port-filename (open-output-string)) */
30080   port_filename(x) = NULL;
30081   port_port(x)->pf = &output_string_functions;
30082   add_output_port(sc, x);
30083   return(x);
30084 }
30085 
30086 s7_pointer s7_open_output_string(s7_scheme *sc) {return(open_output_string(sc, sc->initial_string_port_length));}
30087 
30088 static s7_pointer open_output_string_p(s7_scheme *sc) {return(s7_open_output_string(sc));}
30089 
30090 static s7_pointer g_open_output_string(s7_scheme *sc, s7_pointer args)
30091 {
30092   #define H_open_output_string "(open-output-string) opens an output string port"
30093   #define Q_open_output_string s7_make_signature(sc, 1, sc->is_output_port_symbol)
30094   return(s7_open_output_string(sc));
30095 }
30096 
30097 
30098 /* -------------------------------- get-output-string -------------------------------- */
30099 const char *s7_get_output_string(s7_scheme *sc, s7_pointer p)
30100 {
30101   port_data(p)[port_position(p)] = '\0';
30102   return((const char *)port_data(p));
30103 }
30104 
30105 static inline void check_get_output_string_port(s7_scheme *sc, s7_pointer p)
30106 {
30107   if (port_is_closed(p))
30108     simple_wrong_type_argument_with_type(sc, sc->get_output_string_symbol, p, wrap_string(sc, "an active (open) string port", 28));
30109 
30110   if (port_position(p) > sc->max_string_length)
30111     s7_error(sc, sc->out_of_range_symbol,
30112 	     set_elist_2(sc, wrap_string(sc, "port-position ~D is greater than (*s7* 'max-string-length)", 58), wrap_integer1(sc, port_position(p))));
30113 }
30114 
30115 static s7_pointer g_get_output_string(s7_scheme *sc, s7_pointer args)
30116 {
30117   #define H_get_output_string "(get-output-string port clear-port) returns the output accumulated in port.  \
30118 If the optional 'clear-port' is #t, the current string is flushed."
30119   #define Q_get_output_string s7_make_signature(sc, 3, sc->is_string_symbol, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol), sc->is_boolean_symbol)
30120 
30121   s7_pointer p;
30122   bool clear_port = false;
30123 
30124   if (is_pair(cdr(args)))
30125     {
30126       p = cadr(args);
30127       if (!s7_is_boolean(p))
30128 	return(wrong_type_argument(sc, sc->get_output_string_symbol, 2, p, T_BOOLEAN));
30129       clear_port = (p == sc->T);
30130     }
30131   p = car(args);
30132   if ((!is_output_port(p)) || (!is_string_port(p)))
30133     {
30134       if (p == sc->F) return(make_empty_string(sc, 0, 0));
30135       return(method_or_bust_with_type_one_arg(sc, p, sc->get_output_string_symbol, args, wrap_string(sc, "an output string port", 21)));
30136     }
30137   check_get_output_string_port(sc, p);
30138 
30139   if ((clear_port) &&
30140       (port_position(p) < port_data_size(p)))
30141     {
30142       block_t *block;
30143       s7_pointer result;
30144       result = block_to_string(sc, port_data_block(p), port_position(p));
30145       port_data_size(p) = sc->initial_string_port_length;
30146       block = mallocate(sc, port_data_size(p));
30147       port_data_block(p) = block;
30148       port_data(p) = (uint8_t *)(block_data(block));
30149       port_position(p) = 0;
30150       port_data(p)[0] = '\0';
30151       return(result);
30152     }
30153   return(make_string_with_length(sc, (const char *)port_data(p), port_position(p)));
30154 }
30155 
30156 static void op_get_output_string(s7_scheme *sc)
30157 {
30158   s7_pointer port;
30159 
30160   port = sc->code;
30161   if (!is_output_port(port))
30162     simple_wrong_type_argument_with_type(sc, sc->with_output_to_string_symbol, port, wrap_string(sc, "an open string output port", 26));
30163   check_get_output_string_port(sc, port);
30164 
30165   if (port_position(port) >= port_data_size(port)) /* can the > part happen? */
30166     sc->value = block_to_string(sc, reallocate(sc, port_data_block(port), port_position(port) + 1), port_position(port));
30167   else sc->value = block_to_string(sc, port_data_block(port), port_position(port));
30168 
30169   port_data(port) = NULL;
30170   port_data_size(port) = 0;
30171   port_data_block(port) = NULL;
30172   port_needs_free(port) = false;
30173 }
30174 
30175 static s7_pointer g_get_output_string_uncopied(s7_scheme *sc, s7_pointer args)
30176 {
30177   s7_pointer p;
30178   p = car(args);
30179   if ((!is_output_port(p)) || (!is_string_port(p)))
30180     {
30181       if (p == sc->F) return(make_empty_string(sc, 0, 0));
30182       return(method_or_bust_with_type_one_arg(sc, p, sc->get_output_string_symbol, args, wrap_string(sc, "an output string port", 21)));
30183     }
30184   check_get_output_string_port(sc, p);
30185   return(wrap_string(sc, (const char *)port_data(p), port_position(p)));
30186 }
30187 
30188 
30189 /* -------------------------------- open-input-function -------------------------------- */
30190 
30191 static s7_pointer g_closed_input_function_port(s7_scheme *sc, s7_pointer args)
30192 {
30193   return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_1(sc, wrap_string(sc, "attempt to read from a closed input-function port", 49))));
30194 }
30195 
30196 static void close_input_function(s7_scheme *sc, s7_pointer p)
30197 {
30198   port_port(p)->pf = &closed_port_functions;
30199   port_input_scheme_function(p) = sc->closed_input_function; /* from s7_make_function so it is GC-protected */
30200   port_set_closed(p, true);
30201 }
30202 
30203 static port_functions_t input_function_functions =
30204   {function_read_char, input_write_char, input_write_string, NULL, NULL, NULL, NULL, function_read_line, input_display, close_input_function};
30205 
30206 s7_pointer s7_open_input_function(s7_scheme *sc, s7_pointer (*function)(s7_scheme *sc, s7_read_t read_choice, s7_pointer port))
30207 {
30208   s7_pointer x;
30209   block_t *b;
30210   new_cell(sc, x, T_INPUT_PORT);
30211   b = mallocate_port(sc);
30212   port_block(x) = b;
30213   port_port(x) = (port_t *)block_data(b);
30214   port_type(x) = FUNCTION_PORT;
30215   port_set_closed(x, false);
30216   port_input_scheme_function(x) = sc->nil;
30217   port_data_block(x) = NULL;
30218   port_needs_free(x) = false;
30219   port_filename_block(x) = NULL;
30220   port_filename(x) = NULL;
30221   port_filename_length(x) = 0;
30222   port_file_number(x) = 0;
30223   port_line_number(x) = 0;
30224   port_file(x) = NULL;
30225   port_input_function(x) = function;
30226   port_port(x)->pf = &input_function_functions;
30227   add_input_port(sc, x);
30228   return(x);
30229 }
30230 
30231 static void init_open_input_function_choices(s7_scheme *sc)
30232 {
30233   sc->open_input_function_choices[S7_READ] = sc->read_symbol;
30234   sc->open_input_function_choices[S7_READ_CHAR] = sc->read_char_symbol;
30235   sc->open_input_function_choices[S7_READ_LINE] = sc->read_line_symbol;
30236   sc->open_input_function_choices[S7_PEEK_CHAR] = sc->peek_char_symbol;
30237 #if (!WITH_PURE_S7)
30238   sc->open_input_function_choices[S7_IS_CHAR_READY] = sc->is_char_ready_symbol;
30239 #endif
30240 }
30241 
30242 static s7_pointer input_scheme_function_wrapper(s7_scheme *sc, s7_read_t read_choice, s7_pointer port)
30243 {
30244   return(s7_apply_function(sc, port_input_scheme_function(port), set_plist_1(sc, sc->open_input_function_choices[(int)read_choice])));
30245 }
30246 
30247 static s7_pointer g_open_input_function(s7_scheme *sc, s7_pointer args)
30248 {
30249   #define H_open_input_function "(open-input-function func) opens an input function port"
30250   #define Q_open_input_function s7_make_signature(sc, 2, sc->is_input_port_symbol, sc->is_procedure_symbol)
30251 
30252   s7_pointer port, func;
30253   func = car(args);
30254 
30255   if (!is_any_procedure(func)) /* is_procedure is too lenient: we need to flag (open-input-function (block)) for example */
30256     return(wrong_type_argument_with_type(sc, sc->open_input_function_symbol, 0, func, a_procedure_string));
30257   if (!s7_is_aritable(sc, func, 1))
30258     return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "input-function-port function, ~A, should take one argument", 58), func)));
30259 
30260   port = s7_open_input_function(sc, input_scheme_function_wrapper);
30261   port_input_scheme_function(port) = func;
30262   return(port);
30263 }
30264 
30265 
30266 /* -------------------------------- open-output-function -------------------------------- */
30267 
30268 static s7_pointer g_closed_output_function_port(s7_scheme *sc, s7_pointer args)
30269 {
30270   return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_1(sc, wrap_string(sc, "attempt to write to a closed output-function port", 49))));
30271 }
30272 
30273 static void close_output_function(s7_scheme *sc, s7_pointer p)
30274 {
30275   port_port(p)->pf = &closed_port_functions;
30276   port_output_scheme_function(p) = sc->closed_output_function;
30277   port_set_closed(p, true);
30278 }
30279 
30280 static port_functions_t output_function_functions =
30281   {output_read_char, function_write_char, function_write_string, NULL, NULL, NULL, NULL, output_read_line, function_display, close_output_function};
30282 
30283 s7_pointer s7_open_output_function(s7_scheme *sc, void (*function)(s7_scheme *sc, uint8_t c, s7_pointer port))
30284 {
30285   s7_pointer x;
30286   block_t *b;
30287   new_cell(sc, x, T_OUTPUT_PORT);
30288   b = mallocate_port(sc);
30289   port_block(x) = b;
30290   port_port(x) = (port_t *)block_data(b);
30291   port_type(x) = FUNCTION_PORT;
30292   port_data(x) = NULL;
30293   port_data_block(x) = NULL;
30294   port_set_closed(x, false);
30295   port_needs_free(x) = false;
30296   port_output_function(x) = function;
30297   port_output_scheme_function(x) = sc->nil;
30298   port_port(x)->pf = &output_function_functions;
30299   add_output_port(sc, x);
30300   return(x);
30301 }
30302 
30303 static void output_scheme_function_wrapper(s7_scheme *sc, uint8_t c, s7_pointer port)
30304 {
30305   s7_apply_function(sc, port_output_scheme_function(port), set_plist_1(sc, make_integer(sc, c)));
30306 }
30307 
30308 static s7_pointer g_open_output_function(s7_scheme *sc, s7_pointer args)
30309 {
30310   #define H_open_output_function "(open-output-function func) opens an output function port"
30311   #define Q_open_output_function s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->is_procedure_symbol)
30312 
30313   s7_pointer port, func;
30314   func = car(args);
30315 
30316   if (!is_any_procedure(func))
30317     return(wrong_type_argument_with_type(sc, sc->open_output_function_symbol, 0, func, a_procedure_string));
30318   if (!s7_is_aritable(sc, func, 1))
30319     return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "output-function-port function, ~A, should take one argument", 59), func)));
30320 
30321   port = s7_open_output_function(sc, output_scheme_function_wrapper);
30322   port_output_scheme_function(port) = func;
30323   mark_function[T_OUTPUT_PORT] = mark_output_port;
30324 
30325   return(port);
30326 }
30327 
30328 
30329 /* -------- current-input-port stack -------- */
30330 #define INPUT_PORT_STACK_INITIAL_SIZE 4
30331 
30332 static inline void push_input_port(s7_scheme *sc, s7_pointer new_port)
30333 {
30334   if (sc->input_port_stack_loc >= sc->input_port_stack_size)
30335     {
30336       sc->input_port_stack_size *= 2;
30337       sc->input_port_stack = (s7_pointer *)Realloc(sc->input_port_stack, sc->input_port_stack_size * sizeof(s7_pointer));
30338     }
30339   sc->input_port_stack[sc->input_port_stack_loc++] = current_input_port(sc);
30340   set_current_input_port(sc, new_port);
30341 }
30342 
30343 static void pop_input_port(s7_scheme *sc)
30344 {
30345   if (sc->input_port_stack_loc > 0)
30346     set_current_input_port(sc, sc->input_port_stack[--(sc->input_port_stack_loc)]);
30347   else set_current_input_port(sc, sc->standard_input);
30348 }
30349 
30350 static s7_pointer input_port_if_not_loading(s7_scheme *sc)
30351 {
30352   s7_pointer port;
30353   port = current_input_port(sc);
30354   if (is_loader_port(port)) /* this flag is turned off by the reader macros, so we aren't in that context */
30355     {
30356       int32_t c;
30357       c = port_read_white_space(port)(sc, port);
30358       if (c > 0)            /* we can get either EOF or NULL at the end */
30359 	{
30360 	  backchar(c, port);
30361 	  return(NULL);
30362 	}
30363       return(sc->standard_input);
30364     }
30365   return(port);
30366 }
30367 
30368 
30369 /* -------------------------------- read-char -------------------------------- */
30370 s7_pointer s7_read_char(s7_scheme *sc, s7_pointer port)
30371 {
30372   int32_t c;
30373   c = port_read_character(port)(sc, port);
30374   return((c == EOF) ? eof_object : chars[c]);
30375 }
30376 
30377 static s7_pointer g_read_char(s7_scheme *sc, s7_pointer args)
30378 {
30379   #define H_read_char "(read-char (port (current-input-port))) returns the next character in the input port"
30380   #define Q_read_char s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_char_symbol, sc->is_eof_object_symbol), sc->is_input_port_symbol)
30381   s7_pointer port;
30382 
30383   if (is_not_null(args))
30384     port = car(args);
30385   else
30386     {
30387       port = input_port_if_not_loading(sc);
30388       if (!port) return(eof_object);
30389     }
30390   if (!is_input_port(port))
30391     return(method_or_bust_with_type_one_arg(sc, port, sc->read_char_symbol, args, an_input_port_string));
30392   return(chars[port_read_character(port)(sc, port)]);
30393 }
30394 
30395 static s7_pointer read_char_p_p(s7_scheme *sc, s7_pointer port)
30396 {
30397   if (!is_input_port(port))
30398     return(method_or_bust_with_type_one_arg_p(sc, port, sc->read_char_symbol, an_input_port_string));
30399   return(chars[port_read_character(port)(sc, port)]);
30400 }
30401 
30402 static s7_pointer g_read_char_1(s7_scheme *sc, s7_pointer args)
30403 {
30404   s7_pointer port;
30405   port = car(args);
30406   if (!is_input_port(port))
30407     return(method_or_bust_with_type_one_arg(sc, port, sc->read_char_symbol, args, an_input_port_string));
30408   return(chars[port_read_character(port)(sc, port)]);
30409 }
30410 
30411 static s7_pointer read_char_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
30412 {
30413   return((args == 1) ? sc->read_char_1 : f);
30414 }
30415 
30416 
30417 /* -------------------------------- write-char -------------------------------- */
30418 s7_pointer s7_write_char(s7_scheme *sc, s7_pointer c, s7_pointer pt)
30419 {
30420   if (pt != sc->F)
30421     port_write_character(pt)(sc, s7_character(c), pt);
30422   return(c);
30423 }
30424 
30425 static s7_pointer write_char_p_pp(s7_scheme *sc, s7_pointer c, s7_pointer port)
30426 {
30427   if (!s7_is_character(c))
30428     return(method_or_bust_pp(sc, c, sc->write_char_symbol, c, port, T_CHARACTER, 1));
30429   if (port == sc->F) return(c);
30430   if (!is_output_port(port))
30431     return(method_or_bust_with_type_pp(sc, port, sc->write_char_symbol, c, port, an_output_port_string, 2));
30432   port_write_character(port)(sc, s7_character(c), port);
30433   return(c);
30434 }
30435 
30436 static s7_pointer g_write_char(s7_scheme *sc, s7_pointer args)
30437 {
30438   #define H_write_char "(write-char char (port (current-output-port))) writes char to the output port"
30439   #define Q_write_char s7_make_signature(sc, 3, sc->is_char_symbol, sc->is_char_symbol, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
30440   return(write_char_p_pp(sc, car(args), (is_pair(cdr(args))) ? cadr(args) : current_output_port(sc)));
30441 }
30442 
30443 static s7_pointer write_char_p_p(s7_scheme *sc, s7_pointer c)
30444 {
30445   if (!s7_is_character(c))
30446     return(method_or_bust_p(sc, c, sc->write_char_symbol, T_CHARACTER));
30447   if (current_output_port(sc) == sc->F) return(c);
30448   port_write_character(current_output_port(sc))(sc, s7_character(c), current_output_port(sc));
30449   return(c);
30450 }
30451 
30452 /* (with-output-to-string (lambda () (write-char #\space))) -> " "
30453  * (with-output-to-string (lambda () (write #\space))) -> "#\\space"
30454  * (with-output-to-string (lambda () (display #\space))) -> " "
30455  * is this correct?  It's what Guile does.  write-char is actually display-char.
30456  */
30457 
30458 
30459 /* -------------------------------- peek-char -------------------------------- */
30460 s7_pointer s7_peek_char(s7_scheme *sc, s7_pointer port)
30461 {
30462   int32_t c;              /* needs to be an int32_t so EOF=-1, but not 255 */
30463   if (is_string_port(port))
30464     return((port_data_size(port) <= port_position(port)) ? chars[EOF] : chars[(uint8_t)port_data(port)[port_position(port)]]);
30465   c = port_read_character(port)(sc, port);
30466   if (c == EOF) return(eof_object);
30467   backchar(c, port);
30468   return(chars[c]);
30469 }
30470 
30471 static s7_pointer g_peek_char(s7_scheme *sc, s7_pointer args)
30472 {
30473   #define H_peek_char "(peek-char (port (current-input-port))) returns the next character in the input port, but does not remove it from the input stream"
30474   #define Q_peek_char s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_char_symbol, sc->is_eof_object_symbol), sc->is_input_port_symbol)
30475   s7_pointer port;
30476 
30477   port = (is_not_null(args)) ? car(args) : current_input_port(sc);
30478   if (!is_input_port(port))
30479     return(method_or_bust_with_type_one_arg(sc, port, sc->peek_char_symbol, args, an_input_port_string));
30480   if (port_is_closed(port))
30481     return(simple_wrong_type_argument_with_type(sc, sc->peek_char_symbol, port, an_open_port_string));
30482 
30483   if (is_function_port(port))
30484     {
30485       s7_pointer res;
30486       res = (*(port_input_function(port)))(sc, S7_PEEK_CHAR, port);
30487       if (is_multiple_value(res))
30488 	{
30489 	  clear_multiple_value(res);
30490 	  s7_error(sc, sc->bad_result_symbol, set_elist_2(sc, wrap_string(sc, "input-function-port peek-char returned: ~S", 42), res));
30491 	}
30492       if (!s7_is_character(res))
30493 	s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "input_function_port peek_char returned: ~S", 42), res));
30494       return(res);
30495     }
30496   return(s7_peek_char(sc, port));
30497 }
30498 
30499 
30500 /* -------------------------------- read-byte -------------------------------- */
30501 static s7_pointer g_read_byte(s7_scheme *sc, s7_pointer args)
30502 {
30503   #define H_read_byte "(read-byte (port (current-input-port))): reads a byte from the input port"
30504   #define Q_read_byte s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_byte_symbol, sc->is_eof_object_symbol), sc->is_input_port_symbol)
30505   s7_pointer port;
30506   int32_t c;
30507 
30508   if (is_not_null(args))
30509     port = car(args);
30510   else
30511     {
30512       port = input_port_if_not_loading(sc);
30513       if (!port) return(eof_object);
30514     }
30515   if (!is_input_port(port))
30516     return(method_or_bust_with_type_one_arg(sc, port, sc->read_byte_symbol, args, an_input_port_string));
30517 
30518   c = port_read_character(port)(sc, port);
30519   return((c == EOF) ? eof_object : small_int(c));
30520 }
30521 
30522 
30523 /* -------------------------------- write-byte -------------------------------- */
30524 static s7_pointer g_write_byte(s7_scheme *sc, s7_pointer args)
30525 {
30526   #define H_write_byte "(write-byte byte (port (current-output-port))): writes byte to the output port"
30527   #define Q_write_byte s7_make_signature(sc, 3, sc->is_byte_symbol, sc->is_byte_symbol, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
30528   s7_pointer port, b;
30529   s7_int val;
30530 
30531   b = car(args);
30532   if (!s7_is_integer(b))
30533     return(method_or_bust(sc, car(args), sc->write_byte_symbol, args, T_INTEGER, 1));
30534 
30535   val = s7_integer_checked(sc, b);
30536   if ((val < 0) || (val > 255)) /* need to check this before port==#f, else (write-byte most-positive-fixnum #f) is not an error */
30537     return(wrong_type_argument_with_type(sc, sc->write_byte_symbol, 1, b, an_unsigned_byte_string));
30538 
30539   port = (is_pair(cdr(args))) ? cadr(args) : current_output_port(sc);
30540   if (!is_output_port(port))
30541     {
30542       if (port == sc->F) return(car(args));
30543       return(method_or_bust_with_type_one_arg(sc, port, sc->write_byte_symbol, args, an_output_port_string));
30544     }
30545   port_write_character(port)(sc, (uint8_t)val, port);
30546   return(b);
30547 }
30548 
30549 
30550 /* -------------------------------- read-line -------------------------------- */
30551 static s7_pointer g_read_line(s7_scheme *sc, s7_pointer args)
30552 {
30553   #define H_read_line "(read-line port (with-eol #f)) returns the next line from port, or #<eof>. \
30554 If 'with-eol' is not #f, read-line includes the trailing end-of-line character."
30555   #define Q_read_line s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_eof_object_symbol), sc->is_input_port_symbol, sc->is_boolean_symbol)
30556 
30557   s7_pointer port;
30558   bool with_eol = false;
30559 
30560   if (is_not_null(args))
30561     {
30562       port = car(args);
30563       if (!is_input_port(port))
30564 	return(method_or_bust_with_type(sc, port, sc->read_line_symbol, args, an_input_port_string, 1));
30565 
30566       if (is_not_null(cdr(args)))
30567 	with_eol = (cadr(args) != sc->F); /* perhaps this should insist on #t: (read-line port (c-pointer 0)) */
30568     }
30569   else
30570     {
30571       port = input_port_if_not_loading(sc);
30572       if (!port) return(eof_object);
30573     }
30574   return(port_read_line(port)(sc, port, with_eol));
30575 }
30576 
30577 static s7_pointer read_line_p_pp(s7_scheme *sc, s7_pointer port, s7_pointer with_eol)
30578 {
30579   if (!is_input_port(port))
30580     return(method_or_bust_with_type_pp(sc, port, sc->read_line_symbol, port, with_eol, an_input_port_string, 1));
30581   return(port_read_line(port)(sc, port, with_eol != sc->F));
30582 }
30583 
30584 static s7_pointer read_line_p_p(s7_scheme *sc, s7_pointer port)
30585 {
30586   if (!is_input_port(port))
30587     return(method_or_bust_with_type_one_arg_p(sc, port, sc->read_line_symbol, an_input_port_string));
30588   return(port_read_line(port)(sc, port, false)); /* with_eol default is #f */
30589 }
30590 
30591 
30592 /* -------------------------------- read-string -------------------------------- */
30593 static s7_pointer g_read_string(s7_scheme *sc, s7_pointer args)
30594 {
30595   /* read-chars would be a better name -- read-string could mean CL-style read-from-string (like eval-string)
30596    *   similarly read-bytes could return a byte-vector (rather than r7rs's read-bytevector)
30597    *   and write-string -> write-chars, write-bytevector -> write-bytes
30598    */
30599   #define H_read_string "(read-string k port) reads k characters from port into a new string and returns it."
30600   #define Q_read_string s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_eof_object_symbol), sc->is_integer_symbol, sc->is_input_port_symbol)
30601   s7_pointer k, port, s;
30602   s7_int i, nchars;
30603   uint8_t *str;
30604 
30605   k = car(args);
30606   if (!s7_is_integer(k))
30607     return(method_or_bust(sc, k, sc->read_string_symbol, args, T_INTEGER, 1));
30608   nchars = s7_integer_checked(sc, k);
30609   if (nchars < 0)
30610     return(wrong_type_argument_with_type(sc, sc->read_string_symbol, 1, k, a_non_negative_integer_string));
30611   if (nchars > sc->max_string_length)
30612     return(out_of_range(sc, sc->read_string_symbol, int_one, k, its_too_large_string));
30613 
30614   if (!is_null(cdr(args)))
30615     port = cadr(args);
30616   else
30617     {
30618       port = input_port_if_not_loading(sc);
30619       if (!port) return(eof_object);
30620     }
30621   if (!is_input_port(port))
30622     return(method_or_bust_with_type_pp(sc, port, sc->read_string_symbol, k, port, an_input_port_string, 2));
30623   if (port_is_closed(port))
30624     return(simple_wrong_type_argument_with_type(sc, sc->read_string_symbol, port, an_open_port_string));
30625 
30626   if (nchars == 0)
30627     return(make_empty_string(sc, 0, 0));
30628 
30629   s = make_empty_string(sc, nchars, 0);
30630   str = (uint8_t *)string_value(s);
30631   if (is_string_port(port))
30632     {
30633       s7_int pos, end, len;
30634       pos = port_position(port);
30635       end = port_data_size(port);
30636       len = end - pos;
30637       if (len > nchars) len = nchars;
30638       if (len <= 0) return(eof_object);
30639       memcpy((void *)str, (void *)(port_data(port) + pos), len);
30640       string_length(s) = len;
30641       str[len] = '\0';
30642       port_position(port) += len;
30643       return(s);
30644     }
30645   if (is_file_port(port))
30646     {
30647       size_t len;
30648       len = fread((void *)str, 1, nchars, port_file(port));
30649       str[len] = '\0';
30650       string_length(s) = len;
30651       return(s);
30652     }
30653   for (i = 0; i < nchars; i++)
30654     {
30655       int32_t c;
30656       c = port_read_character(port)(sc, port);
30657       if (c == EOF)
30658 	{
30659 	  if (i == 0)
30660 	    return(eof_object);
30661 	  string_length(s) = i;
30662 	  return(s);
30663 	}
30664       str[i] = (uint8_t)c;
30665     }
30666   return(s);
30667 }
30668 
30669 
30670 /* -------------------------------- read -------------------------------- */
30671 #define declare_jump_info() bool old_longjmp; int32_t old_jump_loc, jump_loc; jmp_buf old_goto_start
30672 
30673 /* we need sigsetjmp, not setjmp for nrepl's interrupt (something to do with signal masks??)
30674  *   unfortunately sigsetjmp is noticeably slower than setjmp, especially when s7_optimize_1 is called a lot.
30675  *   In one case, the sigsetjmp version runs in 24 seconds, but the setjmp version takes 10 seconds, and
30676  *   yet callgrind says there is almost no difference, so I removed setjmp from s7_optimize.
30677  *   But there was still a problem with cache misses:  A bigger cache reduced the 24 seconds to 17 (cachegrind agrees).
30678  *   But how to optimize s7 for cache hits?  The culprits are eval and gc.  Looking at these numbers,
30679  *   I think the least affected are able to use opt_info optimization which makes everything local?
30680  */
30681 
30682 #if (defined(__FreeBSD__)) || (defined(__OpenBSD__)) || (defined(__NetBSD__))
30683 /* these need sigjmp_buf arg -- I think this is only sc->goto_start */
30684 #define Setjmp(A)     setjmp(A)
30685 #define Longjmp(A, B) longjmp(A, B)
30686 #else
30687 #define Setjmp(A)     sigsetjmp(A, 1)
30688 #define Longjmp(A, B) siglongjmp(A, B)
30689 #endif
30690 
30691 #define store_jump_info(Sc)						\
30692   do {									\
30693       old_longjmp = Sc->longjmp_ok;					\
30694       old_jump_loc = Sc->setjmp_loc;					\
30695       memcpy((void *)old_goto_start, (void *)(Sc->goto_start), sizeof(jmp_buf)); \
30696   } while (0)
30697 
30698 #define restore_jump_info(Sc)						\
30699   do {									\
30700     Sc->longjmp_ok = old_longjmp;					\
30701     Sc->setjmp_loc = old_jump_loc;					\
30702     memcpy((void *)(Sc->goto_start), (void *)old_goto_start, sizeof(jmp_buf)); \
30703     if ((jump_loc == ERROR_JUMP) &&					\
30704 	(sc->longjmp_ok))						\
30705       Longjmp(sc->goto_start, ERROR_JUMP);				\
30706   } while (0)
30707 
30708 #define set_jump_info(Sc, Tag)		\
30709   do {					\
30710     sc->longjmp_ok = true;		\
30711     sc->setjmp_loc = Tag;		\
30712     jump_loc = Setjmp(sc->goto_start);	\
30713   } while (0)
30714 
30715 s7_pointer s7_read(s7_scheme *sc, s7_pointer port)
30716 {
30717   if (is_input_port(port))
30718     {
30719       s7_pointer old_let;
30720       declare_jump_info();
30721 
30722       old_let = sc->curlet;
30723       sc->curlet = sc->nil;
30724       push_input_port(sc, port);
30725 
30726       store_jump_info(sc);
30727       set_jump_info(sc, READ_SET_JUMP);
30728       if (jump_loc != NO_JUMP)
30729 	{
30730 	  if (jump_loc != ERROR_JUMP)
30731 	    eval(sc, sc->cur_op);
30732 	}
30733       else
30734 	{
30735 	  push_stack_no_let_no_code(sc, OP_BARRIER, port);
30736 	  push_stack_direct(sc, OP_EVAL_DONE);
30737 
30738 	  eval(sc, OP_READ_INTERNAL);
30739 
30740 	  if (sc->tok == TOKEN_EOF)
30741 	    sc->value = eof_object;
30742 
30743 	  if ((sc->cur_op == OP_EVAL_DONE) &&
30744 	      (stack_op(sc->stack, current_stack_top(sc) - 1) == OP_BARRIER))
30745 	    pop_stack(sc);
30746 	}
30747       pop_input_port(sc);
30748       sc->curlet = old_let;
30749 
30750       restore_jump_info(sc);
30751       return(sc->value);
30752     }
30753   return(simple_wrong_type_argument_with_type(sc, sc->read_symbol, port, an_input_port_string));
30754 }
30755 
30756 static s7_pointer g_read(s7_scheme *sc, s7_pointer args)
30757 {
30758   #define H_read "(read (port (current-input-port))) returns the next object in the input port, or #<eof> at the end"
30759   #define Q_read s7_make_signature(sc, 2, sc->T, sc->is_input_port_symbol)
30760   s7_pointer port;
30761 
30762   if (is_not_null(args))
30763     port = car(args);
30764   else
30765     {
30766       port = input_port_if_not_loading(sc);
30767       if (!port) return(eof_object);
30768     }
30769 
30770   if (!is_input_port(port))
30771     return(method_or_bust_with_type_one_arg(sc, port, sc->read_symbol, args, an_input_port_string));
30772 
30773   if (is_function_port(port))
30774     {
30775       s7_pointer res;
30776       res = (*(port_input_function(port)))(sc, S7_READ, port);
30777       if (is_multiple_value(res))
30778 	{
30779 	  clear_multiple_value(res);
30780 	  s7_error(sc, sc->bad_result_symbol, set_elist_2(sc, wrap_string(sc, "input-function-port read returned: ~S", 37), res));
30781 	}
30782       return(res);
30783     }
30784 
30785   if ((is_string_port(port)) &&
30786       (port_data_size(port) <= port_position(port)))
30787     return(eof_object);
30788 
30789   push_input_port(sc, port);
30790   push_stack_op_let(sc, OP_READ_DONE); /* this stops the internal read process so we only get one form */
30791   push_stack_op_let(sc, OP_READ_INTERNAL);
30792 
30793   return(port);
30794 }
30795 
30796 
30797 /* -------------------------------- load -------------------------------- */
30798 
30799 #if WITH_MULTITHREAD_CHECKS
30800 typedef struct {
30801   s7_scheme* sc;
30802   const int32_t lock_count; /* Remember lock count in case we have skipped calls to leave_track_scope by longjmp-ing. */
30803 } lock_scope_t;
30804 
30805 static lock_scope_t enter_lock_scope(s7_scheme *sc)
30806 {
30807   int result = pthread_mutex_trylock(&sc->lock);
30808   if (result != 0)
30809     {
30810       fprintf(stderr, "pthread_mutex_trylock failed: %d (EBUSY: %d)", result, EBUSY);
30811       abort();
30812     }
30813 
30814   sc->lock_count++;
30815   {
30816     lock_scope_t st = {.sc = sc, .lock_count = sc->lock_count};
30817     return(st);
30818   }
30819 }
30820 
30821 static void leave_lock_scope(lock_scope_t *st)
30822 {
30823   while (st->sc->lock_count > st->lock_count)
30824     {
30825       st->sc->lock_count--;
30826       pthread_mutex_unlock(&st->sc->lock);
30827     }
30828 }
30829 
30830 #define TRACK(Sc) lock_scope_t lock_scope __attribute__ ((__cleanup__(leave_lock_scope))) = enter_lock_scope(Sc)
30831 #else
30832 #define TRACK(Sc)
30833 #endif
30834 
30835 /* various changes in this section courtesy of Woody Douglass 12-Jul-19 */
30836 
30837 static block_t *search_load_path(s7_scheme *sc, const char *name)
30838 {
30839   s7_pointer lst;
30840 
30841   lst = s7_load_path(sc);
30842   if (is_pair(lst))
30843     {
30844       block_t *b;
30845       char *filename;
30846       s7_pointer dir_names;
30847       /* linux: PATH_MAX: 4096, windows: MAX_PATH: unlimited?, Mac: 1016?, BSD: MAX_PATH_LENGTH: 1024 */
30848 #if MS_WINDOWS || defined(__linux__)
30849       #define S7_FILENAME_MAX 4096
30850 #else
30851       #define S7_FILENAME_MAX 1024
30852 #endif
30853       b = mallocate(sc, S7_FILENAME_MAX);
30854       filename = (char *)block_data(b);
30855 
30856       for (dir_names = lst; is_pair(dir_names); dir_names = cdr(dir_names))
30857 	{
30858 	  const char *new_dir;
30859 	  new_dir = string_value(car(dir_names));
30860 	  if (new_dir)
30861 	    {
30862 	      filename[0] = '\0';
30863 	      if (new_dir[strlen(new_dir) - 1] == '/')
30864 		catstrs(filename, S7_FILENAME_MAX, new_dir, name, (char *)NULL);
30865 	      else catstrs(filename, S7_FILENAME_MAX, new_dir, "/", name, (char *)NULL);
30866 #ifdef _MSC_VER
30867 	      if (_access(filename, 0) != -1)
30868 		return(b);
30869 #else
30870 	      if (access(filename, F_OK) == 0)
30871 		return(b);
30872 #endif
30873 	    }}
30874       liberate(sc, b);
30875     }
30876   return(NULL);
30877 }
30878 
30879 #if WITH_C_LOADER
30880 #include <dlfcn.h>
30881 
30882 static block_t *full_filename(s7_scheme *sc, const char *filename)
30883 {
30884   s7_int len;
30885   char *rtn;
30886   block_t *block;
30887   if (filename[0] == '/')
30888     {
30889       len = safe_strlen(filename);
30890       block = mallocate(sc, len + 1);
30891       rtn = (char *)block_data(block);
30892       memcpy((void *)rtn, (void *)filename, len);
30893       rtn[len] = '\0';
30894     }
30895   else
30896     {
30897       char *pwd = getcwd(NULL, 0); /* docs say this means it will return a new string of the right size */
30898       len = safe_strlen(pwd) + safe_strlen(filename) + 2; /* not 1! we need room for the '/' and the terminating 0 */
30899       block = mallocate(sc, len);
30900       rtn = (char *)block_data(block);
30901       if (pwd)
30902 	{
30903           rtn[0] = '\0';
30904           catstrs(rtn, len, pwd, "/", filename, (char *)NULL);
30905           free(pwd);
30906 	}
30907       else /* isn't this an error? -- perhaps warn about getcwd, strerror(errno) */
30908 	{
30909           memcpy((void *)rtn, (void *)filename, len);
30910           rtn[len] = '\0';
30911 	}}
30912   return(block);
30913 }
30914 
30915 static s7_pointer load_shared_object(s7_scheme *sc, const char *fname, s7_pointer let)
30916 {
30917   /* if fname ends in .so, try loading it as a c shared object: (load "/home/bil/cl/m_j0.so" (inlet 'init_func 'init_m_j0)) */
30918   s7_int fname_len;
30919 
30920   fname_len = safe_strlen(fname);
30921   if ((fname_len > 3) &&
30922       (local_strcmp((const char *)(fname + (fname_len - 3)), ".so")))
30923     {
30924       void *library;
30925       char *pwd_name = NULL;
30926       block_t *pname = NULL;
30927 
30928       if ((access(fname, F_OK) == 0) || (fname[0] == '/'))
30929 	{
30930 	  pname = full_filename(sc, fname);
30931 	  pwd_name = (char *)block_data(pname);
30932 	}
30933       else
30934 	{
30935 	  block_t *searched;
30936 	  searched = search_load_path(sc, fname); /* returns NULL if *load-path* is nil, or if nothing matches */
30937 	  if (searched)
30938 	    {
30939 	      if (((const char *)block_data(searched))[0] == '/')
30940 		pname = searched;
30941 	      else
30942 		{
30943 		  pname = full_filename(sc, (const char *)block_data(searched)); /* this is necessary, at least in Linux -- we can't blithely dlopen whatever is passed to us */
30944 		  liberate(sc, searched);
30945 		}
30946 	      pwd_name = (char *)block_data(pname);
30947 	    }
30948 	  else /* perhaps no *load-path* entries */
30949 	    {
30950 	      pname = full_filename(sc, fname);
30951 	      pwd_name = (char *)block_data(pname);
30952 	    }}
30953       /* else pname is NULL, so use fname -- can this happen? */
30954 #if S7_DEBUGGING
30955       if (!pname) fprintf(stderr, "pname is null\n");
30956 #endif
30957       library = dlopen((pname) ? pwd_name : fname, RTLD_NOW);
30958       if (library)
30959 	{
30960 	  if (let) /* look for 'init_func in let */
30961 	    {
30962 	      s7_pointer init;
30963 
30964 	      init = s7_let_ref(sc, let, make_symbol(sc, "init_func"));
30965 	      if (is_symbol(init))
30966 		{
30967 		  const char *init_name;
30968 		  void *init_func;
30969 
30970 		  if (hook_has_functions(sc->load_hook))
30971 		    s7_apply_function(sc, sc->load_hook, set_plist_1(sc, sc->temp6 = s7_make_string(sc, (pname) ? (const char *)pwd_name : fname)));
30972 
30973 		  init_name = symbol_name(init);
30974 		  init_func = dlsym(library, init_name);
30975 		  if (init_func)
30976 		    {
30977 		      typedef void (*dl_func)(s7_scheme *sc);
30978 		      typedef s7_pointer (*dl_func_with_args)(s7_scheme *sc, s7_pointer args);
30979 		      s7_pointer init_args, p;
30980 
30981 		      init_args = s7_let_ref(sc, let, make_symbol(sc, "init_args"));
30982 		      if (is_pair(init_args))
30983 			p = ((dl_func_with_args)init_func)(sc, init_args);
30984 		      /* if caller includes init_args, but init_func is actually a dl_func, it seems to be ok,
30985 		       *   but the returned value is whatever was last computed in the init_func.
30986 		       */
30987 		      else
30988 			{
30989 			  /* if the init_func is expecting args, but caller forgets init_args, this gives a segfault when
30990 			   *   init_func accesses the forgotten args. s7_is_valid can't catch this currently --
30991 			   *   we need a better way to tell that a random value can't be a cell pointer (scan permallocs and use heap_location?)
30992 			   */
30993 			  ((dl_func)init_func)(sc);
30994 			  p = sc->F;
30995 			}
30996 		      if (pname) liberate(sc, pname);
30997 		      return(p);
30998 		    }
30999 		  s7_warn(sc, 512, "loaded %s, but can't find init_func %s, dlerror: %s, let: %s\n", fname, init_name, dlerror(), display(let));
31000 		  dlclose(library);
31001 		}
31002 	      else s7_warn(sc, 512, "can't load %s: no init function\n", fname);
31003 #if S7_DEBUGGING
31004 	      fprintf(stderr, "init_func trouble in %s, %s\n", fname, display(init));
31005 #endif
31006 	      if (pname) liberate(sc, pname);
31007 	      return(sc->undefined);
31008 	    }}
31009       else s7_warn(sc, 512, "load %s failed: %s\n", (pname) ? pwd_name : fname, dlerror());
31010       if (pname) liberate(sc, pname);
31011     }
31012   return(NULL);
31013 }
31014 #endif
31015 
31016 #if WITH_GCC
31017 static FILE *expand_cwd(s7_scheme *sc, const char *fname)
31018 {
31019   /* catch one special case, "~/..." since it causes 99.9% of the "can't load ..." errors */
31020   if ((fname[0] == '~') &&
31021       (fname[1] == '/'))
31022     {
31023       char *home;
31024       home = getenv("HOME");
31025       if (home)
31026 	{
31027 	  block_t *b;
31028 	  char *filename;
31029 	  s7_int len;
31030 	  FILE *fp;
31031 
31032 	  len = safe_strlen(fname) + safe_strlen(home) + 1;
31033 	  b = mallocate(sc, len);
31034 	  filename = (char *)block_data(b);
31035 	  filename[0] = '\0';
31036 	  catstrs(filename, len, home, (char *)(fname + 1), (char *)NULL);
31037 	  fp = fopen(filename, "r");
31038 	  liberate(sc, b);
31039 
31040 	  return(fp);
31041 	}}
31042   return(NULL);
31043 }
31044 #endif
31045 
31046 static FILE *open_file_with_load_path(s7_scheme *sc, const char *fname)
31047 {
31048   block_t *b;
31049   b = search_load_path(sc, fname);
31050   if (b)
31051     {
31052       FILE *fp;
31053       fp = fopen((const char *)block_data(b), "r");
31054       if ((fp) && (hook_has_functions(sc->load_hook)))
31055 	s7_apply_function(sc, sc->load_hook, set_plist_1(sc, sc->temp6 = s7_make_string(sc, (const char *)block_data(b))));
31056       liberate(sc, b);
31057       return(fp);
31058     }
31059   return(NULL);
31060 }
31061 
31062 static s7_pointer read_scheme_file(s7_scheme *sc, FILE *fp, const char *fname)
31063 {
31064   s7_pointer port;
31065   port = read_file(sc, fp, fname, -1, "load"); /* -1 = read entire file into string, this is currently not tweakable */
31066   port_file_number(port) = remember_file_name(sc, fname);
31067   set_loader_port(port);
31068   sc->temp6 = port;
31069   push_input_port(sc, port);
31070   sc->temp6 = sc->nil;
31071   return(port);
31072 }
31073 
31074 s7_pointer s7_load_with_environment(s7_scheme *sc, const char *filename, s7_pointer e)
31075 {
31076   /* returns either the value of the load or NULL if filename not found */
31077   s7_pointer port;
31078   FILE *fp;
31079   declare_jump_info();
31080   TRACK(sc);
31081 
31082   if (e == sc->s7_let) return(NULL);
31083 
31084 #if WITH_C_LOADER
31085   {
31086     s7_pointer p;
31087     p = load_shared_object(sc, filename, (is_null(e)) ? sc->rootlet : e);
31088     if (p) return(p);
31089   }
31090 #endif
31091 
31092   if (is_directory(filename))
31093     return(NULL);
31094   fp = fopen(filename, "r");
31095 #if WITH_GCC
31096   if (!fp) fp = expand_cwd(sc, filename);
31097 #endif
31098   if (fp)
31099     {
31100       if (hook_has_functions(sc->load_hook))
31101 	s7_apply_function(sc, sc->load_hook, set_plist_1(sc, sc->temp6 = s7_make_string(sc, filename)));
31102     }
31103   else
31104     {
31105       fp = open_file_with_load_path(sc, filename);
31106       if (!fp) return(NULL);
31107     }
31108   port = read_scheme_file(sc, fp, filename);
31109 
31110   sc->curlet = e;
31111   push_stack(sc, OP_LOAD_RETURN_IF_EOF, port, sc->code);
31112 
31113   store_jump_info(sc);
31114   set_jump_info(sc, LOAD_SET_JUMP);
31115   if (jump_loc != NO_JUMP)
31116     {
31117       if (jump_loc != ERROR_JUMP)
31118 	eval(sc, sc->cur_op);
31119     }
31120   else eval(sc, OP_READ_INTERNAL);
31121 
31122   pop_input_port(sc);
31123   if (is_input_port(port))
31124     s7_close_input_port(sc, port);
31125 
31126   restore_jump_info(sc);
31127   if (is_multiple_value(sc->value))
31128     sc->value = splice_in_values(sc, multiple_value(sc->value));
31129   return(sc->value);
31130 }
31131 
31132 s7_pointer s7_load(s7_scheme *sc, const char *filename) {return(s7_load_with_environment(sc, filename, sc->nil));}
31133 
31134 s7_pointer s7_load_c_string_with_environment(s7_scheme *sc, const char *content, s7_int bytes, s7_pointer e)
31135 {
31136 #if (!MS_WINDOWS)
31137   s7_pointer port;
31138   s7_int port_loc;
31139   declare_jump_info();
31140   TRACK(sc);
31141 
31142   port = open_input_string(sc, content, bytes);
31143   port_loc = s7_gc_protect_1(sc, port);
31144   set_loader_port(port);
31145   push_input_port(sc, port);
31146   sc->curlet = e;
31147   push_stack(sc, OP_LOAD_RETURN_IF_EOF, port, sc->code);
31148   s7_gc_unprotect_at(sc, port_loc);
31149 
31150   store_jump_info(sc);
31151   set_jump_info(sc, LOAD_SET_JUMP);
31152   if (jump_loc != NO_JUMP)
31153     {
31154       if (jump_loc != ERROR_JUMP)
31155 	eval(sc, sc->cur_op);
31156     }
31157   else eval(sc, OP_READ_INTERNAL);
31158 
31159   pop_input_port(sc);
31160   if (is_input_port(port))
31161     s7_close_input_port(sc, port);
31162 
31163   restore_jump_info(sc);
31164   if (is_multiple_value(sc->value))
31165     sc->value = splice_in_values(sc, multiple_value(sc->value));
31166   return(sc->value);
31167 #else
31168   return(sc->F);
31169 #endif
31170 }
31171 
31172 s7_pointer s7_load_c_string(s7_scheme *sc, const char *content, s7_int bytes)
31173 {
31174   return(s7_load_c_string_with_environment(sc, content, bytes, sc->nil));
31175 }
31176 
31177 static s7_pointer g_load(s7_scheme *sc, s7_pointer args)
31178 {
31179   #define H_load "(load file (let (rootlet))) loads the scheme file 'file'. The 'let' argument \
31180 defaults to the rootlet.  To load into the current environment instead, pass (curlet)."
31181   #define Q_load s7_make_signature(sc, 3, sc->values_symbol, sc->is_string_symbol, sc->is_let_symbol)
31182 
31183   FILE *fp = NULL;
31184   s7_pointer name;
31185   const char *fname;
31186 
31187   name = car(args);
31188   if (!is_string(name))
31189     return(method_or_bust(sc, name, sc->load_symbol, args, T_STRING, 1));
31190 
31191   if (is_pair(cdr(args)))
31192     {
31193       s7_pointer e;
31194       e = cadr(args);
31195       if (!is_let(e))
31196 	return(wrong_type_argument_with_type(sc, sc->load_symbol, 2, e, a_let_string));
31197       if (e == sc->s7_let)
31198 	return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't load ~S into *s7*", 23), name)));
31199       sc->curlet = (e == sc->rootlet) ? sc->nil : e;
31200     }
31201   else sc->curlet = sc->nil;
31202 
31203   fname = string_value(name);
31204   if ((!fname) || (!(*fname)))                 /* fopen("", "r") returns a file pointer?? */
31205     return(s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, wrap_string(sc, "load's first argument, ~S, should be a filename", 47), name)));
31206 
31207   if (is_directory(fname))
31208     return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "load argument, ~S, is a directory", 33), name)));
31209 
31210 #if WITH_C_LOADER
31211   {
31212     s7_pointer p;
31213     p = load_shared_object(sc, fname, (is_null(sc->curlet)) ? sc->rootlet : sc->curlet);
31214     if (p) return(p);
31215   }
31216 #endif
31217 
31218   fp = fopen(fname, "r");
31219 #if WITH_GCC
31220   if (!fp) fp = expand_cwd(sc, fname);
31221 #endif
31222   if (fp)
31223     {
31224       if (hook_has_functions(sc->load_hook))
31225 	s7_apply_function(sc, sc->load_hook, set_plist_1(sc, sc->temp6 = s7_make_string(sc, fname)));
31226     }
31227   else
31228     {
31229       fp = open_file_with_load_path(sc, fname);
31230       if (!fp) return(file_error(sc, "load", "can't open", fname));
31231     }
31232   read_scheme_file(sc, fp, fname);
31233 
31234   push_stack_op_let(sc, OP_LOAD_CLOSE_AND_POP_IF_EOF);  /* was pushing args and code, but I don't think they're used later */
31235   push_stack_op_let(sc, OP_READ_INTERNAL);
31236 
31237   return(sc->unspecified);
31238 }
31239 
31240 
31241 /* -------- *load-path* -------- */
31242 s7_pointer s7_load_path(s7_scheme *sc)
31243 {
31244   return(s7_symbol_value(sc, sc->load_path_symbol));
31245 }
31246 
31247 s7_pointer s7_add_to_load_path(s7_scheme *sc, const char *dir)
31248 {
31249   s7_symbol_set_value(sc,
31250 		      sc->load_path_symbol,
31251 		      cons(sc,
31252 			   s7_make_string(sc, dir),
31253 			   s7_symbol_value(sc, sc->load_path_symbol)));
31254   return(s7_symbol_value(sc, sc->load_path_symbol));
31255 }
31256 
31257 static s7_pointer g_load_path_set(s7_scheme *sc, s7_pointer args)
31258 {
31259   /* new value must be either () or a proper list of strings */
31260   if (is_null(cadr(args))) return(cadr(args));
31261   if (is_pair(cadr(args)))
31262     {
31263       s7_pointer x;
31264       for (x = cadr(args); is_pair(x); x = cdr(x))
31265 	if (!is_string(car(x)))
31266 	  return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't set *load-path* to ~S", 27), cadr(args))));
31267       if (is_null(x))
31268 	return(cadr(args));
31269     }
31270   return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't set *load-path* to ~S", 27), cadr(args))));
31271 }
31272 
31273 /* -------- *cload-directory* -------- */
31274 static s7_pointer g_cload_directory_set(s7_scheme *sc, s7_pointer args)
31275 {
31276   /* this sets the directory for cload.scm's output */
31277   s7_pointer cl_dir;
31278   cl_dir = cadr(args);
31279   if (!is_string(cl_dir))
31280     return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't set *cload-directory* to ~S", 33), cadr(args))));
31281   s7_symbol_set_value(sc, sc->cload_directory_symbol, cl_dir);
31282   if (safe_strlen(string_value(cl_dir)) > 0)
31283     s7_add_to_load_path(sc, (const char *)(string_value(cl_dir)));
31284   /* should this remove the previous *cload-directory* name first? or not affect *load-path* at all? */
31285   return(cl_dir);
31286 }
31287 
31288 
31289 /* ---------------- autoload ---------------- */
31290 #define INITIAL_AUTOLOAD_NAMES_SIZE 4
31291 
31292 void s7_autoload_set_names(s7_scheme *sc, const char **names, s7_int size)
31293 {
31294   /* names should be sorted alphabetically by the symbol name (the even indexes in the names array)
31295    *   size is the number of symbol names (half the size of the names array(
31296    *
31297    * the idea here is that by sticking to string constants we can handle 90% of the work at compile-time,
31298    *   with less start-up memory.  Then eventually we'll add C libraries and every name in those libraries
31299    *   will come as an import once dlopen has picked up the library.
31300    *   So, hopefully, we can pre-declare as many names as we want from as many libraries as we want,
31301    *   without a bloated mess of a run-time image.  And new libraries are easy to accommodate --
31302    *   add the names to be auto-exported to this list with the name of the scheme file that cloads
31303    *   the library and exports the given name. So, we'll need a separate such file for each library?
31304    *
31305    * the environment variable could use the library base name in *: *libm* or *libgsl*
31306    *   (*libm* 'j0)
31307    * why not just predeclare these libraries?  The caller could import what he wants via require.
31308    * In fact, we only need to see *libm* -> libm.so etc, but we still need the arg/return types of each function, etc
31309    *
31310    * Also we need to decide how to handle name collisions (by order of autoload lib setup)
31311    * And (lastly?) how to handle different library versions?
31312    *
31313    * so autoload known libs here in s7 so we're indepentdent of snd
31314    *   (currently these are included in make-index.scm[line 575] -> snd-xref.c)
31315    * for each module, include an env in the lib env that has the names in that header
31316    * in autoload below, don't sort! -- just build a list of autoload tables and check each in order at autoload time (we want startup to be fast)
31317    * for versions, include wrapper macro at end of each c-define choice
31318    * in the xg case, there's no savings in delaying the defines
31319    */
31320   if (sc->safety > 1)
31321     {
31322       int32_t i, k;
31323       for (i = 0, k = 2; k < (size * 2); i += 2, k += 2)
31324 	if ((names[i]) && (names[k]) && (strcmp(names[i], names[k]) > 0))
31325 	  {
31326 	    s7_warn(sc, 256, "%s: names[%d]: %s is out of order\n", __func__, k, names[k]);
31327 	    break;
31328 	  }}
31329   if (!sc->autoload_names)
31330     {
31331       sc->autoload_names = (const char ***)Calloc(INITIAL_AUTOLOAD_NAMES_SIZE, sizeof(const char **));
31332       sc->autoload_names_sizes = (s7_int *)Calloc(INITIAL_AUTOLOAD_NAMES_SIZE, sizeof(s7_int));
31333       sc->autoloaded_already = (bool **)Calloc(INITIAL_AUTOLOAD_NAMES_SIZE, sizeof(bool *));
31334       sc->autoload_names_top = INITIAL_AUTOLOAD_NAMES_SIZE;
31335       sc->autoload_names_loc = 0;
31336     }
31337   else
31338     if (sc->autoload_names_loc >= sc->autoload_names_top)
31339       {
31340 	s7_int i;
31341 	sc->autoload_names_top *= 2;
31342 	sc->autoload_names = (const char ***)Realloc(sc->autoload_names, sc->autoload_names_top * sizeof(const char **));
31343 	sc->autoload_names_sizes = (s7_int *)Realloc(sc->autoload_names_sizes, sc->autoload_names_top * sizeof(s7_int));
31344 	sc->autoloaded_already = (bool **)Realloc(sc->autoloaded_already, sc->autoload_names_top * sizeof(bool *));
31345 	for (i = sc->autoload_names_loc; i < sc->autoload_names_top; i++)
31346 	  {
31347 	    sc->autoload_names[i] = NULL;
31348 	    sc->autoload_names_sizes[i] = 0;
31349 	    sc->autoloaded_already[i] = NULL;
31350 	  }}
31351   sc->autoload_names[sc->autoload_names_loc] = names;
31352   sc->autoload_names_sizes[sc->autoload_names_loc] = size;
31353   sc->autoloaded_already[sc->autoload_names_loc] = (bool *)Calloc(size, sizeof(bool));
31354   sc->autoload_names_loc++;
31355 }
31356 
31357 static const char *find_autoload_name(s7_scheme *sc, s7_pointer symbol, bool *already_loaded, bool loading)
31358 {
31359   s7_int l = 0, lib, libs;
31360   const char *name;
31361 
31362   name = symbol_name(symbol);
31363   libs = sc->autoload_names_loc;
31364 
31365   for (lib = 0; lib < libs; lib++)
31366     {
31367       const char **names;
31368       s7_int u;
31369       u = sc->autoload_names_sizes[lib] - 1;
31370       names = sc->autoload_names[lib];
31371 
31372       while (true)
31373 	{
31374 	  s7_int comp, pos;
31375 	  const char *this_name;
31376 	  if (u < l) break;
31377 	  pos = (l + u) / 2;
31378 	  this_name = names[pos * 2];
31379 	  comp = strcmp(this_name, name);
31380 	  if (comp == 0)
31381 	    {
31382 	      *already_loaded = sc->autoloaded_already[lib][pos];
31383 	      if (loading) sc->autoloaded_already[lib][pos] = true;
31384 	      return(names[pos * 2 + 1]);             /* file name given func name */
31385 	    }
31386 	  if (comp < 0)
31387 	    l = pos + 1;
31388 	  else u = pos - 1;
31389 	}}
31390   return(NULL);
31391 }
31392 
31393 s7_pointer s7_autoload(s7_scheme *sc, s7_pointer symbol, s7_pointer file_or_function)
31394 {
31395   /* add '(symbol . file) to s7's autoload table */
31396   if (is_null(sc->autoload_table))
31397     sc->autoload_table = s7_make_hash_table(sc, sc->default_hash_table_length);
31398   if (sc->safety >= MORE_SAFETY_WARNINGS)
31399     {
31400       s7_pointer p;
31401       p = s7_hash_table_ref(sc, sc->autoload_table, symbol);
31402       if ((p != sc->F) && (p != file_or_function))
31403 	s7_warn(sc, 256, "'%s autoload value changed\n", symbol_name(symbol));
31404     }
31405   s7_hash_table_set(sc, sc->autoload_table, symbol, file_or_function);
31406   return(file_or_function);
31407 }
31408 
31409 static s7_pointer g_autoload(s7_scheme *sc, s7_pointer args)
31410 {
31411   #define H_autoload "(autoload symbol file-or-function) adds the symbol to its table of autoloadable symbols. \
31412 If that symbol is encountered as an unbound variable, s7 either loads the file (following *load-path*), or calls \
31413 the function.  The function takes one argument, the calling environment.  Presumably the symbol is defined \
31414 in the file, or by the function."
31415   #define Q_autoload s7_make_signature(sc, 3, sc->T, sc->is_symbol_symbol, sc->T)
31416 
31417   s7_pointer sym, value;
31418 
31419   sym = car(args);
31420   if (is_string(sym))
31421     {
31422       if (string_length(sym) == 0)                   /* (autoload "" ...) */
31423 	return(s7_wrong_type_arg_error(sc, "autoload", 1, sym, "a symbol-name or a symbol"));
31424       sym = make_symbol_with_length(sc, string_value(sym), string_length(sym));
31425     }
31426   if (!is_symbol(sym))
31427     {
31428       check_method(sc, sym, sc->autoload_symbol, args);
31429       return(s7_wrong_type_arg_error(sc, "autoload", 1, sym, "a string (symbol-name) or a symbol"));
31430     }
31431   if (is_keyword(sym))
31432     return(s7_wrong_type_arg_error(sc, "autoload", 1, sym, "a normal symbol (a keyword is never unbound)"));
31433 
31434   value = cadr(args);
31435   if (is_string(value))
31436     return(s7_autoload(sc, sym, s7_immutable(make_string_with_length(sc, string_value(value), string_length(value)))));
31437   if (((is_closure(value)) || (is_closure_star(value))) &&
31438       (s7_is_aritable(sc, value, 1)))
31439     return(s7_autoload(sc, sym, value));
31440 
31441   check_method(sc, value, sc->autoload_symbol, args);
31442   return(s7_wrong_type_arg_error(sc, "autoload", 2, value, "a string (file-name) or a thunk"));
31443 }
31444 
31445 
31446 /* -------------------------------- *autoload* -------------------------------- */
31447 static s7_pointer g_autoloader(s7_scheme *sc, s7_pointer args)
31448 {
31449   #define H_autoloader "(*autoload* sym) returns the autoload info for the symbol sym, or #f."
31450   #define Q_autoloader s7_make_signature(sc, 2, sc->T, sc->is_symbol_symbol)
31451   s7_pointer sym;
31452 
31453   sym = car(args);
31454   if (!is_symbol(sym))
31455     {
31456       check_method(sc, sym, sc->autoloader_symbol, set_plist_1(sc, sym));
31457       return(s7_wrong_type_arg_error(sc, "*autoload*", 1, sym, "a symbol"));
31458     }
31459   if (sc->autoload_names)
31460     {
31461       const char *file;
31462       bool loaded = false;
31463       file = find_autoload_name(sc, sym, &loaded, false);
31464       if (file)
31465 	return(s7_make_string(sc, file));
31466     }
31467   if (is_hash_table(sc->autoload_table))
31468     return(s7_hash_table_ref(sc, sc->autoload_table, sym));
31469 
31470   return(sc->F);
31471 }
31472 
31473 
31474 /* ---------------- require ---------------- */
31475 static bool is_memq(s7_pointer sym, s7_pointer lst)
31476 {
31477   s7_pointer x;
31478   for (x = lst; is_pair(x); x = cdr(x))
31479     if (sym == car(x))
31480       return(true);
31481   return(false);
31482 }
31483 
31484 static s7_pointer g_require(s7_scheme *sc, s7_pointer args)
31485 {
31486   #define H_require "(require symbol . symbols) loads each file associated with each symbol if it has not been loaded already.\
31487 The symbols refer to the argument to \"provide\".  (require lint.scm)"
31488   /* #define Q_require s7_make_circular_signature(sc, 1, 2, sc->T, sc->is_symbol_symbol) */
31489 
31490   s7_pointer p;
31491   push_stack_no_let_no_code(sc, OP_GC_PROTECT, args);
31492   for (p = args; is_pair(p); p = cdr(p))
31493     {
31494       s7_pointer sym;
31495       if (is_symbol(car(p)))
31496 	sym = car(p);
31497       else
31498 	{
31499 	  if ((is_proper_quote(sc, car(p))) &&
31500 	      (is_symbol(cadar(p))))
31501 	    sym = cadar(p);
31502 	  else return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "require: ~S is not a symbol", 27), car(p))));
31503 	}
31504       if ((!is_memq(sym, s7_symbol_value(sc, sc->features_symbol))) &&
31505 	  (sc->is_autoloading))
31506 	{
31507 	  s7_pointer f;
31508 	  f = g_autoloader(sc, set_plist_1(sc, sym));
31509 	  if (is_string(f))
31510 	    {
31511 	      if (hook_has_functions(sc->autoload_hook))
31512 		s7_apply_function(sc, sc->autoload_hook, set_plist_2(sc, sym, f));
31513 	      s7_load_with_environment(sc, string_value(f), sc->curlet);
31514 	    }
31515 	  else return(s7_error(sc, sc->autoload_error_symbol, set_elist_2(sc, wrap_string(sc, "require: no autoload info for ~S", 32), sym)));
31516 	  /* it's possible to precede the error with: if (!s7_load_with_environment(sc, symbol_name(sym), sc->curlet))
31517 	   *   but loading the symbol as a string worries me.
31518 	   */
31519 	}}
31520 
31521   if (((opcode_t)sc->stack_end[-1]) == OP_GC_PROTECT)
31522     unstack(sc);
31523   return(sc->T);
31524 }
31525 
31526 
31527 /* ---------------- provided? ---------------- */
31528 static s7_pointer g_is_provided(s7_scheme *sc, s7_pointer args)
31529 {
31530   #define H_is_provided "(provided? symbol) returns #t if symbol is a member of the *features* list"
31531   #define Q_is_provided s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_symbol_symbol)
31532   s7_pointer sym, topf, x;
31533 
31534   sym = car(args);
31535   if (!is_symbol(sym))
31536     return(method_or_bust_one_arg_p(sc, sym, sc->is_provided_symbol, T_SYMBOL));
31537 
31538   /* here the *features* list is spread out (or can be anyway) along the curlet chain,
31539    *   so we need to travel back all the way to the top level checking each *features* list in turn.
31540    *   Since *features* grows via cons (newest first), we can stop the scan if we hit the shared
31541    *   top-level at least.
31542    */
31543   topf = global_value(sc->features_symbol);
31544   if (is_memq(sym, topf))
31545     return(sc->T);
31546 
31547   if (is_global(sc->features_symbol))
31548     return(sc->F);
31549   for (x = sc->curlet; symbol_id(sc->features_symbol) < let_id(x); x = let_outlet(x));
31550   for (; is_let(x); x = let_outlet(x))
31551     {
31552       s7_pointer y;
31553       for (y = let_slots(x); tis_slot(y); y = next_slot(y))
31554 	if ((slot_symbol(y) == sc->features_symbol) &&
31555 	    (slot_value(y) != topf) &&
31556 	    (is_memq(sym, slot_value(y))))
31557 	  return(sc->T);
31558     }
31559   return(sc->F);
31560 }
31561 
31562 bool s7_is_provided(s7_scheme *sc, const char *feature)
31563 {
31564   return(is_memq(make_symbol(sc, feature), s7_symbol_value(sc, sc->features_symbol))); /* this goes from local outward */
31565 }
31566 
31567 static bool is_provided_b_7p(s7_scheme *sc, s7_pointer sym)
31568 {
31569   if (!is_symbol(sym))
31570     simple_wrong_type_argument(sc, sc->is_provided_symbol, sym, T_SYMBOL);
31571   return(is_memq(sym, s7_symbol_value(sc, sc->features_symbol)));
31572 }
31573 
31574 
31575 /* ---------------- provide ---------------- */
31576 static s7_pointer c_provide(s7_scheme *sc, s7_pointer sym)
31577 {
31578   /* this has to be relative to the curlet: (load file env)
31579    *   the things loaded are only present in env, and go away with it, so should not be in the global *features* list
31580    */
31581   s7_pointer p;
31582   if (!is_symbol(sym))
31583     return(method_or_bust_one_arg_p(sc, sym, sc->provide_symbol, T_SYMBOL));
31584 
31585   if ((sc->curlet == sc->rootlet) || (sc->curlet == sc->shadow_rootlet))
31586     p = global_slot(sc->features_symbol);
31587   else p = symbol_to_local_slot(sc, sc->features_symbol, sc->curlet); /* if sc->curlet is nil, this returns the global slot, else local slot */
31588   if ((is_slot(p)) && (is_immutable(p)))
31589     s7_warn(sc, 256, "provide: *features* is immutable!\n");
31590   else
31591     {
31592       s7_pointer lst;
31593       lst = slot_value(lookup_slot_from(sc->features_symbol, sc->curlet)); /* in either case, we want the current *features* list */
31594       if (p == sc->undefined)
31595 	make_slot_1(sc, sc->curlet, sc->features_symbol, cons(sc, sym, lst));
31596       else
31597 	if ((!is_memq(sym, lst)) && (!is_memq(sym, slot_value(p))))
31598 	  slot_set_value(p, cons(sc, sym, slot_value(p)));
31599     }
31600   return(sym);
31601 }
31602 
31603 static s7_pointer g_provide(s7_scheme *sc, s7_pointer args)
31604 {
31605   #define H_provide "(provide symbol) adds symbol to the *features* list"
31606   #define Q_provide s7_make_signature(sc, 2, sc->is_symbol_symbol, sc->is_symbol_symbol)
31607 
31608   if ((is_immutable(sc->curlet)) &&
31609       (sc->curlet != sc->nil))
31610     s7_error(sc, sc->immutable_error_symbol,
31611 	     set_elist_2(sc, wrap_string(sc, "can't provide '~S (current environment is immutable)", 52), car(args)));
31612   return(c_provide(sc, car(args)));
31613 }
31614 
31615 void s7_provide(s7_scheme *sc, const char *feature) {c_provide(sc, s7_make_symbol(sc, feature));}
31616 
31617 
31618 static s7_pointer g_features_set(s7_scheme *sc, s7_pointer args) /* *features* setter */
31619 {
31620   s7_pointer nf;
31621   nf = cadr(args);
31622   if (is_null(nf))
31623     return(sc->nil);
31624   if (is_pair(nf))
31625     {
31626       s7_pointer p;
31627       if (s7_list_length(sc, nf) <= 0)
31628 	return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't set *features* to ~S", 26), nf)));
31629       for (p = nf; is_pair(p); p = cdr(p))
31630 	if (!is_symbol(car(p)))
31631 	  return(simple_wrong_type_argument(sc, sc->features_symbol, car(p), T_SYMBOL));
31632       return(nf);
31633     }
31634   return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't set *features* to ~S", 26), nf)));
31635 }
31636 
31637 static s7_pointer g_libraries_set(s7_scheme *sc, s7_pointer args) /* *libraries* setter */
31638 {
31639   s7_pointer nf;
31640   nf = cadr(args);
31641   if (is_null(nf))
31642     return(sc->nil);
31643   if (is_pair(nf))
31644     {
31645       s7_pointer p;
31646       if (s7_list_length(sc, nf) <= 0)
31647 	return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't set *libraries* to ~S", 27), nf)));
31648       for (p = nf; is_pair(p); p = cdr(p))
31649 	if ((!is_pair(car(p))) ||
31650 	    (!is_string(caar(p))) ||
31651 	    (!is_let(cdar(p))))
31652 	  return(simple_wrong_type_argument_with_type(sc, sc->libraries_symbol, car(p), wrap_string(sc, "a list of conses of the form (string . let)", 43)));
31653       return(nf);
31654     }
31655   return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't set *libraries* to ~S", 27), nf)));
31656 }
31657 
31658 
31659 /* -------------------------------- eval-string -------------------------------- */
31660 
31661 s7_pointer s7_eval_c_string_with_environment(s7_scheme *sc, const char *str, s7_pointer e)
31662 {
31663   s7_pointer code, port, result;
31664   TRACK(sc);
31665   push_stack_direct(sc, OP_GC_PROTECT);
31666   /* maybe this should just use locals? (GC protection is not the issue here),
31667    *   but this is way down in the noise -- read/eval below are 99% of the computing
31668    */
31669   port = s7_open_input_string(sc, str);
31670   code = s7_read(sc, port);
31671   s7_close_input_port(sc, port);
31672   result = s7_eval(sc, T_Pos(code), e);
31673   pop_stack(sc);
31674   return(result);
31675 }
31676 
31677 s7_pointer s7_eval_c_string(s7_scheme *sc, const char *str)
31678 {
31679   return(s7_eval_c_string_with_environment(sc, str, sc->nil));
31680 }
31681 
31682 static s7_pointer g_eval_string(s7_scheme *sc, s7_pointer args)
31683 {
31684   #define H_eval_string "(eval-string str (let (curlet))) returns the result of evaluating the string str as Scheme code"
31685   #define Q_eval_string s7_make_signature(sc, 3, sc->values_symbol, sc->is_string_symbol, sc->is_let_symbol)
31686   s7_pointer port, str;
31687 
31688   str = car(args);
31689   if (!is_string(str))
31690     return(method_or_bust(sc, str, sc->eval_string_symbol, args, T_STRING, 1));
31691 
31692   if (is_not_null(cdr(args)))
31693     {
31694       s7_pointer e;
31695       e = cadr(args);
31696       if (!is_let(e))
31697  	return(wrong_type_argument_with_type(sc, sc->eval_string_symbol, 2, e, a_let_string));
31698       sc->curlet = (e == sc->rootlet) ? sc->nil : e;
31699     }
31700 
31701   sc->temp3 = sc->args;
31702   push_stack(sc, OP_EVAL_STRING, args, sc->code);
31703   port = open_and_protect_input_string(sc, str);
31704   push_input_port(sc, port);
31705   push_stack_op_let(sc, OP_READ_INTERNAL);
31706 
31707   return(sc->F);  /* I think this means that sc->value defaults to #f in op_eval_string below, so (eval-string "") mimics (eval) -> #f */
31708 }
31709 
31710 static s7_pointer eval_string_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
31711 {
31712   check_for_substring_temp(sc, expr);
31713   return(f);
31714 }
31715 
31716 static s7_pointer op_eval_string(s7_scheme *sc)
31717 {
31718   while (s7_peek_char(sc, current_input_port(sc)) != eof_object) /* (eval-string "(+ 1 2) this is a mistake") */
31719     {
31720       int32_t tk;
31721       tk = token(sc);                             /* (eval-string "(+ 1 2) ; a comment (not a mistake)") */
31722       if (tk != TOKEN_EOF)
31723 	{
31724 	  s7_int trail_len;
31725 	  s7_pointer trail_data;
31726 	  trail_len = port_data_size(current_input_port(sc)) - port_position(current_input_port(sc)) + 1;
31727 	  if (trail_len > 32) trail_len = 32;
31728 	  trail_data = make_string_with_length(sc, (const char *)(port_data(current_input_port(sc)) + port_position(current_input_port(sc)) - 1), trail_len);
31729 	  s7_close_input_port(sc, current_input_port(sc));
31730 	  pop_input_port(sc);
31731 	  s7_error(sc, sc->read_error_symbol, set_elist_2(sc, wrap_string(sc, "eval-string trailing junk: ~S", 29), trail_data));
31732 	}}
31733   s7_close_input_port(sc, current_input_port(sc));
31734   pop_input_port(sc);
31735   sc->code = sc->value;
31736   set_current_code(sc, sc->code);
31737   return(NULL);
31738 }
31739 
31740 
31741 /* -------------------------------- call-with-input-string -------------------------------- */
31742 
31743 static s7_pointer call_with_input(s7_scheme *sc, s7_pointer port, s7_pointer args)
31744 {
31745   s7_pointer p;
31746   p = cadr(args);
31747   port_original_input_string(port) = car(args);
31748   push_stack(sc, OP_UNWIND_INPUT, sc->unused, port); /* #<unused> here is a marker (needed) */
31749   push_stack(sc, OP_APPLY, list_1(sc, port), p);
31750   return(sc->F);
31751 }
31752 
31753 static s7_pointer g_call_with_input_string(s7_scheme *sc, s7_pointer args)
31754 {
31755   s7_pointer str, proc;
31756   #define H_call_with_input_string "(call-with-input-string str proc) opens a string port for str and applies proc to it"
31757   #define Q_call_with_input_string sc->pl_sf
31758   /* (call-with-input-string "44" (lambda (p) (+ 1 (read p)))) -> 45 */
31759 
31760   str = car(args);
31761   if (!is_string(str))
31762     return(method_or_bust(sc, str, sc->call_with_input_string_symbol, args, T_STRING, 1));
31763 
31764   proc = cadr(args);
31765   if (is_let(proc))
31766     check_method(sc, proc, sc->call_with_input_string_symbol, args);
31767 
31768   if (!s7_is_aritable(sc, proc, 1))
31769     return(wrong_type_argument_with_type(sc, sc->call_with_input_string_symbol, 2, proc,
31770 					 wrap_string(sc, "a procedure of one argument (the port)", 38)));
31771 
31772   if ((is_continuation(proc)) || (is_goto(proc)))
31773     return(wrong_type_argument_with_type(sc, sc->call_with_input_string_symbol, 2, proc, a_normal_procedure_string));
31774 
31775   return(call_with_input(sc, open_and_protect_input_string(sc, str), args));
31776 }
31777 
31778 
31779 /* -------------------------------- call-with-input-file -------------------------------- */
31780 
31781 static s7_pointer g_call_with_input_file(s7_scheme *sc, s7_pointer args)
31782 {
31783   #define H_call_with_input_file "(call-with-input-file filename proc) opens filename and calls proc with the input port as its argument"
31784   #define Q_call_with_input_file sc->pl_sf
31785   s7_pointer str, proc;
31786 
31787   str = car(args);
31788   if (!is_string(str))
31789     return(method_or_bust(sc, str, sc->call_with_input_file_symbol, args, T_STRING, 1));
31790 
31791   proc = cadr(args);
31792   if (!s7_is_aritable(sc, proc, 1))
31793     return(wrong_type_argument_with_type(sc, sc->call_with_input_file_symbol, 2, proc,
31794 					 wrap_string(sc, "a procedure of one argument (the port)", 38)));
31795   if ((is_continuation(proc)) || (is_goto(proc)))
31796     return(wrong_type_argument_with_type(sc, sc->call_with_input_file_symbol, 2, proc, a_normal_procedure_string));
31797 
31798   return(call_with_input(sc, open_input_file_1(sc, string_value(str), "r", "call-with-input-file"), args));
31799 }
31800 
31801 
31802 /* -------------------------------- with-input-from-string -------------------------------- */
31803 
31804 static s7_pointer with_input(s7_scheme *sc, s7_pointer port, s7_pointer args)
31805 {
31806   s7_pointer old_input_port, p;
31807   old_input_port = current_input_port(sc);
31808   set_current_input_port(sc, port);
31809   port_original_input_string(port) = car(args);
31810   push_stack(sc, OP_UNWIND_INPUT, old_input_port, port);
31811   p = cadr(args);
31812   push_stack(sc, OP_APPLY, sc->nil, p);
31813   return(sc->F);
31814 }
31815 
31816 static s7_pointer g_with_input_from_string(s7_scheme *sc, s7_pointer args)
31817 {
31818   #define H_with_input_from_string "(with-input-from-string str thunk) opens str as the temporary current-input-port and calls thunk"
31819   #define Q_with_input_from_string sc->pl_sf
31820   s7_pointer str;
31821 
31822   str = car(args);
31823   if (!is_string(str))
31824     return(method_or_bust(sc, str, sc->with_input_from_string_symbol, args, T_STRING, 1));
31825 
31826   if (cadr(args) == global_value(sc->read_symbol))
31827     {
31828       if (string_length(str) == 0)
31829 	return(eof_object);
31830       push_input_port(sc, current_input_port(sc));
31831       set_current_input_port(sc, open_and_protect_input_string(sc, str));
31832       port_original_input_string(current_input_port(sc)) = str;
31833       push_stack(sc, OP_UNWIND_INPUT, sc->unused, current_input_port(sc));
31834       push_stack_op_let(sc, OP_READ_DONE);
31835       push_stack_op_let(sc, OP_READ_INTERNAL);
31836       return(current_input_port(sc));
31837     }
31838 
31839   if (!is_thunk(sc, cadr(args)))
31840     return(method_or_bust_with_type(sc, cadr(args), sc->with_input_from_string_symbol, args, a_thunk_string, 2));
31841 
31842   /* since the arguments are evaluated before we get here, we can get some confusing situations:
31843    *   (with-input-from-string "#x2.1" (read))
31844    *     (read) -> whatever it can get from the current input port!
31845    *     ";with-input-from-string argument 2, #<eof>, is untyped but should be a thunk"
31846    *   (with-input-from-string "" (read-line)) -> hangs awaiting stdin input
31847    */
31848   return(with_input(sc, open_and_protect_input_string(sc, str), args));
31849 }
31850 
31851 
31852 /* -------------------------------- with-input-from-file -------------------------------- */
31853 
31854 static s7_pointer g_with_input_from_file(s7_scheme *sc, s7_pointer args)
31855 {
31856   #define H_with_input_from_file "(with-input-from-file filename thunk) opens filename as the temporary current-input-port and calls thunk"
31857   #define Q_with_input_from_file sc->pl_sf
31858 
31859   if (!is_string(car(args)))
31860     return(method_or_bust(sc, car(args), sc->with_input_from_file_symbol, args, T_STRING, 1));
31861 
31862   if (!is_thunk(sc, cadr(args)))
31863     return(method_or_bust_with_type(sc, cadr(args), sc->with_input_from_file_symbol, args, a_thunk_string, 2));
31864 
31865   return(with_input(sc, open_input_file_1(sc, string_value(car(args)), "r", "with-input-from-file"), args));
31866 }
31867 
31868 static s7_pointer with_string_in(s7_scheme *sc, s7_pointer args)
31869 {
31870   s7_pointer old_port;
31871   old_port = current_input_port(sc);
31872   set_current_input_port(sc, open_and_protect_input_string(sc, sc->value));
31873   push_stack(sc, OP_UNWIND_INPUT, old_port, current_input_port(sc));
31874   sc->curlet = make_let(sc, sc->curlet);
31875   return(opt2_pair(sc->code));
31876 }
31877 
31878 static s7_pointer with_file_in(s7_scheme *sc, s7_pointer args)
31879 {
31880   s7_pointer old_port;
31881   old_port = current_input_port(sc);
31882   set_current_input_port(sc, open_input_file_1(sc, string_value(sc->value), "r", "with-input-from-file"));
31883   push_stack(sc, OP_UNWIND_INPUT, old_port, current_input_port(sc));
31884   sc->curlet = make_let(sc, sc->curlet);
31885   return(opt2_pair(sc->code));
31886 }
31887 
31888 static s7_pointer with_file_out(s7_scheme *sc, s7_pointer args)
31889 {
31890   s7_pointer old_port;
31891   old_port = current_output_port(sc);
31892   set_current_output_port(sc, s7_open_output_file(sc, string_value(sc->value), "w"));
31893   push_stack(sc, OP_UNWIND_OUTPUT, old_port, current_output_port(sc));
31894   sc->curlet = make_let(sc, sc->curlet);
31895   return(opt2_pair(sc->code));
31896 }
31897 
31898 static s7_pointer call_string_in(s7_scheme *sc, s7_pointer args)
31899 {
31900   s7_pointer port;
31901   port = open_and_protect_input_string(sc, sc->value);
31902   push_stack(sc, OP_UNWIND_INPUT, sc->unused, port);
31903   sc->curlet = make_let_with_slot(sc, sc->curlet, opt3_sym(sc->code), port);
31904   return(opt2_pair(sc->code));
31905 }
31906 
31907 static s7_pointer call_file_in(s7_scheme *sc, s7_pointer args)
31908 {
31909   s7_pointer port;
31910   port = open_input_file_1(sc, string_value(sc->value), "r", "with-input-from-file");
31911   push_stack(sc, OP_UNWIND_INPUT, sc->unused, port);
31912   sc->curlet = make_let_with_slot(sc, sc->curlet, opt3_sym(sc->code), port);
31913   return(opt2_pair(sc->code));
31914 }
31915 
31916 static s7_pointer call_file_out(s7_scheme *sc, s7_pointer args)
31917 {
31918   s7_pointer port;
31919   port = s7_open_output_file(sc, string_value(sc->value), "w");
31920   push_stack(sc, OP_UNWIND_OUTPUT, sc->unused, port);
31921   sc->curlet = make_let_with_slot(sc, sc->curlet, opt3_sym(sc->code), port);
31922   return(opt2_pair(sc->code));
31923 }
31924 
31925 #define op_with_io_1(Sc) (((s7_function)((sc->code)->object.cons.opt1))(Sc, Sc->nil))
31926 
31927 static void op_lambda(s7_scheme *sc);
31928 
31929 static void op_with_io_1_method(s7_scheme *sc)
31930 {
31931   s7_pointer lt;
31932   lt = sc->value;
31933   if (has_active_methods(sc, lt))
31934     {
31935       s7_pointer method;
31936       method = car(sc->code);
31937       if (is_c_function(method))            /* #_call-with-input-string et al */
31938 	method = make_symbol(sc, c_function_name(method));
31939       push_stack(sc, OP_GC_PROTECT, lt, sc->code);
31940       sc->code = caddr(sc->code);
31941       op_lambda(sc);                        /* -> sc->value -- don't unstack */
31942       sc->value = find_and_apply_method(sc, lt, method, list_2(sc, lt, sc->value));
31943     }
31944   else
31945     {
31946       if (is_symbol(car(sc->code)))         /* might be e.g. #_call-with-input-string so use c_function_name */
31947 	wrong_type_argument(sc, car(sc->code), 1, lt, T_STRING);
31948       else wrong_type_arg_error_prepackaged(sc, wrap_string(sc, c_function_name(car(sc->code)), strlen(c_function_name(car(sc->code)))),
31949 					    int_one, lt, sc->unused, sc->prepackaged_type_names[T_STRING]);
31950     }
31951 }
31952 
31953 static bool op_with_io_op(s7_scheme *sc)
31954 {
31955   sc->value = cadr(sc->code);
31956   if (is_string(sc->value))
31957     {
31958       sc->code = op_with_io_1(sc);
31959       return(false);
31960     }
31961   push_stack_no_args(sc, OP_WITH_IO_1, sc->code);
31962   sc->code = sc->value;
31963   return(true);
31964 }
31965 
31966 static void op_with_output_to_string(s7_scheme *sc)
31967 {
31968   s7_pointer old_port;
31969   old_port = current_output_port(sc);
31970   set_current_output_port(sc, open_output_string(sc, sc->initial_string_port_length));
31971   push_stack(sc, OP_UNWIND_OUTPUT, old_port, current_output_port(sc));
31972   sc->curlet = make_let(sc, sc->curlet);
31973   push_stack(sc, OP_GET_OUTPUT_STRING, old_port, current_output_port(sc));
31974   sc->code = opt2_pair(sc->code);
31975 }
31976 
31977 static void op_call_with_output_string(s7_scheme *sc)
31978 {
31979   s7_pointer port;
31980   port = open_output_string(sc, sc->initial_string_port_length);
31981   push_stack(sc, OP_UNWIND_OUTPUT, sc->unused, port);
31982   sc->curlet = make_let_with_slot(sc, sc->curlet, opt3_sym(sc->code), port);
31983   push_stack(sc, OP_GET_OUTPUT_STRING, sc->unused, port);
31984   sc->code = opt2_pair(sc->code);
31985 }
31986 
31987 
31988 /* -------------------------------- iterators -------------------------------- */
31989 
31990 #if S7_DEBUGGING
31991 static s7_pointer titr_let(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
31992 {
31993   if (!is_let(iterator_sequence(p)))
31994     {
31995       fprintf(stderr, "%s%s[%d]: let iterator sequence is %s%s\n", BOLD_TEXT, func, line, check_name(sc, unchecked_type(iterator_sequence(p))), UNBOLD_TEXT);
31996       if (sc->stop_at_error) abort();
31997     }
31998   return(p);
31999 }
32000 
32001 static s7_pointer titr_pair(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
32002 {
32003   if (!is_pair(iterator_sequence(p)))
32004     {
32005       fprintf(stderr, "%s%s[%d]: pair iterator sequence is %s%s\n", BOLD_TEXT, func, line, check_name(sc, unchecked_type(iterator_sequence(p))), UNBOLD_TEXT);
32006       if (sc->stop_at_error) abort();
32007     }
32008   return(p);
32009 }
32010 
32011 static s7_pointer titr_hash(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
32012 {
32013   if (!is_hash_table(iterator_sequence(p)))
32014     {
32015       fprintf(stderr, "%s%s[%d]: hash iterator sequence is %s%s\n", BOLD_TEXT, func, line, check_name(sc, unchecked_type(iterator_sequence(p))), UNBOLD_TEXT);
32016       if (sc->stop_at_error) abort();
32017     }
32018   return(p);
32019 }
32020 
32021 static s7_pointer titr_len(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
32022 {
32023   if ((is_hash_table(iterator_sequence(p))) ||
32024       (is_pair(iterator_sequence(p))))
32025     {
32026       fprintf(stderr, "%s%s[%d]: iterator length sequence is %s%s\n", BOLD_TEXT, func, line, check_name(sc, unchecked_type(iterator_sequence(p))), UNBOLD_TEXT);
32027       if (sc->stop_at_error) abort();
32028     }
32029   return(p);
32030 }
32031 
32032 static s7_pointer titr_pos(s7_scheme *sc, s7_pointer p, const char *func, int32_t line)
32033 {
32034   if (((is_let(iterator_sequence(p))) &&
32035        (iterator_sequence(p) != sc->rootlet) &&
32036        (iterator_sequence(p) != sc->s7_let)) ||
32037       (is_pair(iterator_sequence(p))))
32038     {
32039       fprintf(stderr, "%s%s[%d]: iterator-position sequence is %s%s\n", BOLD_TEXT, func, line, check_name(sc, unchecked_type(iterator_sequence(p))), UNBOLD_TEXT);
32040       if (sc->stop_at_error) abort();
32041     }
32042   return(p);
32043 }
32044 #endif
32045 
32046 
32047 /* -------------------------------- iterator? -------------------------------- */
32048 static s7_pointer g_is_iterator(s7_scheme *sc, s7_pointer args)
32049 {
32050   #define H_is_iterator "(iterator? obj) returns #t if obj is an iterator."
32051   #define Q_is_iterator sc->pl_bt
32052   s7_pointer x;
32053 
32054   x = car(args);
32055   if (is_iterator(x)) return(sc->T);
32056   /* closure itself is not an iterator: (let ((c1 (let ((+iterator+ #t) (a 0)) (lambda () (set! a (+ a 1)))))) (iterate c1)): error (a function not an iterator) */
32057   check_boolean_method(sc, is_iterator, sc->is_iterator_symbol, args);
32058   return(sc->F);
32059 }
32060 
32061 bool s7_is_iterator(s7_pointer obj) {return(is_iterator(obj));}
32062 static bool is_iterator_b_7p(s7_scheme *sc, s7_pointer obj) {return(g_is_iterator(sc, set_plist_1(sc, obj)) != sc->F);}
32063 
32064 
32065 static s7_pointer iterator_copy(s7_scheme *sc, s7_pointer p)
32066 {
32067   /* fields are obj cur [loc|lcur] [len|slow|hcur] next, but untangling them in debugging case is a pain */
32068   s7_pointer iter;
32069   new_cell(sc, iter, T_ITERATOR | T_SAFE_PROCEDURE);
32070   memcpy((void *)iter, (void *)p, sizeof(s7_cell));
32071   return(iter);
32072 }
32073 
32074 static s7_pointer iterator_finished(s7_scheme *sc, s7_pointer iterator)
32075 {
32076   return(ITERATOR_END);
32077 }
32078 
32079 static s7_pointer iterator_quit(s7_pointer iterator)
32080 {
32081   iterator_next(iterator) = iterator_finished;
32082   clear_iter_ok(iterator);
32083   return(ITERATOR_END);
32084 }
32085 
32086 static s7_pointer let_iterate(s7_scheme *sc, s7_pointer iterator)
32087 {
32088   s7_pointer slot;
32089   slot = iterator_current_slot(iterator);
32090   if (tis_slot(slot))
32091     {
32092       iterator_set_current_slot(iterator, next_slot(slot));
32093       if (iterator_let_cons(iterator))
32094 	{
32095 	  s7_pointer p;
32096 	  p = iterator_let_cons(iterator);
32097 	  set_car(p, slot_symbol(slot));
32098 	  set_cdr(p, slot_value(slot));
32099 	  return(p);
32100 	}
32101       return(cons(sc, slot_symbol(slot), slot_value(slot)));
32102     }
32103   return(iterator_quit(iterator));
32104 }
32105 
32106 static s7_pointer rootlet_iterate(s7_scheme *sc, s7_pointer iterator)
32107 {
32108   s7_pointer slot;
32109   slot = iterator_current(iterator);
32110   if (is_slot(slot))
32111     {
32112       if (iterator_position(iterator) < sc->rootlet_entries)
32113 	{
32114 	  iterator_position(iterator)++;
32115 	  iterator_current(iterator) = rootlet_element(sc->rootlet, iterator_position(iterator));
32116 	}
32117       else iterator_current(iterator) = sc->nil;
32118       return(cons(sc, slot_symbol(slot), slot_value(slot)));
32119     }
32120   return(iterator_quit(iterator));
32121 }
32122 
32123 static s7_pointer hash_entry_to_cons(s7_scheme *sc, hash_entry_t *entry, s7_pointer p)
32124 {
32125   if (p)
32126     {
32127       set_car(p, hash_entry_key(entry));
32128       set_cdr(p, hash_entry_value(entry));
32129       return(p);
32130     }
32131   return(cons(sc, hash_entry_key(entry), hash_entry_value(entry)));
32132 }
32133 
32134 static s7_pointer hash_table_iterate(s7_scheme *sc, s7_pointer iterator)
32135 {
32136   s7_pointer table;
32137   s7_int loc, len;
32138   hash_entry_t **elements;
32139   hash_entry_t *lst;
32140 
32141   lst = iterator_hash_current(iterator);
32142   if (lst)
32143     {
32144       iterator_hash_current(iterator) = hash_entry_next(lst);
32145       return(hash_entry_to_cons(sc, lst, iterator_current(iterator)));
32146     }
32147   table = iterator_sequence(iterator); /* using iterator_length and hash_table_entries here was slightly slower */
32148   len = hash_table_mask(table) + 1;
32149   elements = hash_table_elements(table);
32150 
32151   for (loc = iterator_position(iterator) + 1; loc < len;  loc++)
32152     {
32153       hash_entry_t *x;
32154       x = elements[loc];
32155       if (x)
32156 	{
32157 	  iterator_position(iterator) = loc;
32158 	  iterator_hash_current(iterator) = hash_entry_next(x);
32159 	  return(hash_entry_to_cons(sc, x, iterator_current(iterator)));
32160 	}}
32161   if (is_weak_hash_table(table))
32162     {
32163       clear_weak_hash_iterator(iterator);
32164       weak_hash_iters(table)--;
32165     }
32166   return(iterator_quit(iterator));
32167 }
32168 
32169 static s7_pointer string_iterate(s7_scheme *sc, s7_pointer obj)
32170 {
32171   if (iterator_position(obj) < iterator_length(obj))
32172     return(chars[(uint8_t)(string_value(iterator_sequence(obj))[iterator_position(obj)++])]);
32173   return(iterator_quit(obj));
32174 }
32175 
32176 static s7_pointer byte_vector_iterate(s7_scheme *sc, s7_pointer obj)
32177 {
32178   if (iterator_position(obj) < iterator_length(obj))
32179     return(small_int(byte_vector(iterator_sequence(obj), iterator_position(obj)++)));
32180   return(iterator_quit(obj));
32181 }
32182 
32183 static s7_pointer float_vector_iterate(s7_scheme *sc, s7_pointer obj)
32184 {
32185   if (iterator_position(obj) < iterator_length(obj))
32186     return(make_real(sc, float_vector(iterator_sequence(obj), iterator_position(obj)++)));
32187   return(iterator_quit(obj));
32188 }
32189 
32190 static s7_pointer int_vector_iterate(s7_scheme *sc, s7_pointer obj)
32191 {
32192   if (iterator_position(obj) < iterator_length(obj))
32193     return(make_integer(sc, int_vector(iterator_sequence(obj), iterator_position(obj)++)));
32194   return(iterator_quit(obj));
32195 }
32196 
32197 static s7_pointer vector_iterate(s7_scheme *sc, s7_pointer obj)
32198 {
32199   if (iterator_position(obj) < iterator_length(obj))
32200     return(vector_element(iterator_sequence(obj), iterator_position(obj)++));
32201   return(iterator_quit(obj));
32202 }
32203 
32204 static s7_pointer closure_iterate(s7_scheme *sc, s7_pointer obj)
32205 {
32206   s7_pointer result;
32207   result = s7_call(sc, iterator_sequence(obj), sc->nil);
32208   /* this can't use s7_apply_function -- we need to catch the error handler's longjmp here */
32209   if (result == ITERATOR_END)
32210     {
32211       iterator_next(obj) = iterator_finished;
32212       clear_iter_ok(obj);
32213     }
32214   return(result);
32215 }
32216 
32217 static s7_pointer c_object_iterate(s7_scheme *sc, s7_pointer obj)
32218 {
32219   if (iterator_position(obj) < iterator_length(obj))
32220     {
32221       s7_pointer result, p, cur;
32222       p = iterator_sequence(obj);
32223       cur = iterator_current(obj);
32224       set_car(sc->z2_1, sc->x);
32225       set_car(sc->z2_2, sc->z); /* is this necessary? (save/restore sc->x/y across c_object iteration) */
32226       set_car(cur, p);
32227       set_car(cdr(cur), make_integer(sc, iterator_position(obj)));
32228       result = (*(c_object_ref(sc, p)))(sc, cur);
32229       sc->x = car(sc->z2_1);
32230       sc->z = car(sc->z2_2);
32231       iterator_position(obj)++;
32232       if (result == ITERATOR_END)
32233 	{
32234 	  iterator_next(obj) = iterator_finished;
32235 	  clear_iter_ok(obj);
32236 	}
32237       return(result);
32238     }
32239   return(iterator_quit(obj));
32240 }
32241 
32242 static s7_pointer pair_iterate_1(s7_scheme *sc, s7_pointer obj);
32243 static s7_pointer pair_iterate(s7_scheme *sc, s7_pointer obj)
32244 {
32245   if (is_pair(iterator_current(obj)))
32246     {
32247       s7_pointer result;
32248       result = car(iterator_current(obj));
32249       iterator_current(obj) = cdr(iterator_current(obj));
32250       if (iterator_current(obj) == iterator_slow(obj))
32251 	iterator_current(obj) = sc->nil;
32252       iterator_next(obj) = pair_iterate_1;
32253       return(result);
32254     }
32255   return(iterator_quit(obj));
32256 }
32257 
32258 static s7_pointer pair_iterate_1(s7_scheme *sc, s7_pointer obj)
32259 {
32260   if (is_pair(iterator_current(obj)))
32261     {
32262       s7_pointer result;
32263       result = car(iterator_current(obj));
32264       iterator_current(obj) = cdr(iterator_current(obj));
32265       if (iterator_current(obj) == iterator_slow(obj))
32266 	iterator_current(obj) = sc->nil;
32267       else iterator_set_slow(obj, cdr(iterator_slow(obj)));
32268       iterator_next(obj) = pair_iterate;
32269       return(result);
32270     }
32271   return(iterator_quit(obj));
32272 }
32273 
32274 static s7_pointer find_make_iterator_method(s7_scheme *sc, s7_pointer e)
32275 {
32276   s7_pointer func;
32277   if ((has_active_methods(sc, e)) &&
32278       ((func = find_method_with_let(sc, e, sc->make_iterator_symbol)) != sc->undefined))
32279     {
32280       s7_pointer it;
32281       it = call_method(sc, e, func, set_plist_1(sc, e));
32282       if (!is_iterator(it))
32283 	return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "make-iterator method must return an iterator: ~S", 48), it)));
32284       return(it);
32285     }
32286   return(NULL);
32287 }
32288 
32289 
32290 /* -------------------------------- make-iterator -------------------------------- */
32291 static s7_pointer funclet_entry(s7_scheme *sc, s7_pointer x, s7_pointer sym)
32292 {
32293   if ((has_closure_let(x)) && (is_let(closure_let(x))))
32294     {
32295       s7_pointer val;
32296       val = symbol_to_local_slot(sc, sym, closure_let(x));
32297       if ((!is_slot(val)) && (is_let(let_outlet(closure_let(x)))))
32298 	val = symbol_to_local_slot(sc, sym, let_outlet(closure_let(x)));
32299       if (is_slot(val))
32300 	return(slot_value(val));
32301     }
32302   return(NULL);
32303 }
32304 
32305 static bool is_iterable_closure(s7_scheme *sc, s7_pointer x)
32306 {
32307   s7_pointer iter;
32308   if (!is_thunk(sc, x))
32309     wrong_type_argument_with_type(sc, sc->make_iterator_symbol, 1, x, a_thunk_string);
32310   iter = funclet_entry(sc, x, sc->local_iterator_symbol);
32311   return((iter) && (iter != sc->F));
32312 }
32313 
32314 static s7_pointer s7_let_make_iterator(s7_scheme *sc, s7_pointer iter);
32315 static s7_int c_object_length_to_int(s7_scheme *sc, s7_pointer obj);
32316 
32317 s7_pointer s7_make_iterator(s7_scheme *sc, s7_pointer e)
32318 {
32319   s7_pointer iter, p;
32320 
32321   new_cell(sc, iter, T_ITERATOR | T_SAFE_PROCEDURE | T_ITER_OK);
32322   iterator_sequence(iter) = e;
32323 
32324   if (is_pair(e)) /* by far the most common case */
32325     {
32326       iterator_current(iter) = e;
32327       iterator_next(iter) = pair_iterate;
32328       iterator_set_slow(iter, e);
32329       return(iter);
32330     }
32331   if (!is_let(e))
32332     iterator_position(iter) = 0;
32333 
32334   switch (type(e))
32335     {
32336     case T_LET:
32337       if (e == sc->rootlet)
32338 	{
32339 	  iterator_current(iter) = rootlet_element(e, 0); /* unfortunately tricky -- let_iterate uses different fields */
32340 	  iterator_position(iter) = 0;
32341 	  iterator_next(iter) = rootlet_iterate;
32342 	  return(iter);
32343 	}
32344       if (e == sc->s7_let)
32345 	return(s7_let_make_iterator(sc, iter));
32346 
32347       sc->temp6 = iter;
32348       p = find_make_iterator_method(sc, e);
32349       sc->temp6 = sc->nil;
32350       if (p) {free_cell(sc, iter); return(p);}
32351       iterator_set_current_slot(iter, let_slots(e));
32352       iterator_next(iter) = let_iterate;
32353       iterator_let_cons(iter) = NULL;
32354       break;
32355 
32356     case T_HASH_TABLE:
32357       iterator_hash_current(iter) = NULL;
32358       iterator_current(iter) = NULL;
32359       iterator_position(iter) = -1;
32360       iterator_next(iter) = hash_table_iterate;
32361       if (is_weak_hash_table(e))
32362 	{
32363 	  set_weak_hash_iterator(iter);
32364 	  weak_hash_iters(e)++;
32365 	  add_weak_hash_iterator(sc, iter);
32366 	}
32367       break;
32368 
32369     case T_STRING:
32370       iterator_length(iter) = string_length(e);
32371       iterator_next(iter) = string_iterate;
32372       break;
32373 
32374     case T_BYTE_VECTOR:
32375       iterator_length(iter) = byte_vector_length(e);
32376       iterator_next(iter) = byte_vector_iterate;
32377       break;
32378 
32379     case T_VECTOR:
32380       iterator_length(iter) = vector_length(e);
32381       iterator_next(iter) = vector_iterate;
32382       break;
32383 
32384     case T_INT_VECTOR:
32385       iterator_length(iter) = vector_length(e);
32386       iterator_next(iter) = int_vector_iterate;
32387       break;
32388 
32389     case T_FLOAT_VECTOR:
32390       iterator_length(iter) = vector_length(e);
32391       iterator_next(iter) = float_vector_iterate;
32392       break;
32393 
32394     case T_NIL: /* (make-iterator #()) -> #<iterator: vector>, so I guess () should also work */
32395       iterator_length(iter) = 0;
32396       iterator_next(iter) = iterator_finished;
32397       clear_iter_ok(iter);
32398       break;
32399 
32400     case T_MACRO:   case T_MACRO_STAR:
32401     case T_BACRO:   case T_BACRO_STAR:
32402     case T_CLOSURE: case T_CLOSURE_STAR:
32403       if (is_iterable_closure(sc, e))
32404 	{
32405 	  p = list_1(sc, int_zero);
32406 	  iterator_current(iter) = p;
32407 	  set_mark_seq(iter);
32408 	  iterator_next(iter) = closure_iterate;
32409 	  iterator_length(iter) = (has_active_methods(sc, e)) ? closure_length(sc, e) : S7_INT64_MAX;
32410 	}
32411       else
32412 	{
32413 	  free_cell(sc, iter);
32414 	  return(simple_wrong_type_argument_with_type(sc, sc->make_iterator_symbol, e,
32415 						      wrap_string(sc, "a function or macro with a '+iterator+ local that is not #f", 59)));
32416 	}
32417       break;
32418 
32419     case T_C_OBJECT:
32420       iterator_length(iter) = c_object_length_to_int(sc, e);
32421       sc->temp6 = iter;
32422       p = find_make_iterator_method(sc, e);
32423       sc->temp6 = sc->nil;
32424       if (p) {free_cell(sc, iter); return(p);}
32425       iterator_current(iter) = list_2(sc, e, int_zero);
32426       set_mark_seq(iter);
32427       iterator_next(iter) = c_object_iterate;
32428       break;
32429 
32430     default:
32431       return(simple_wrong_type_argument_with_type(sc, sc->make_iterator_symbol, e, a_sequence_string));
32432     }
32433   return(iter);
32434 }
32435 
32436 static s7_pointer g_make_iterator(s7_scheme *sc, s7_pointer args)
32437 {
32438   #define H_make_iterator "(make-iterator sequence carrier) returns an iterator object that returns the next value \
32439 in the sequence each time it is called.  When it reaches the end, it returns " ITERATOR_END_NAME "."
32440   #define Q_make_iterator s7_make_signature(sc, 3, sc->is_iterator_symbol, sc->is_sequence_symbol, sc->is_pair_symbol)
32441 
32442   s7_pointer iter, seq, carrier;
32443   /* we need to call s7_make_iterator before fixing up the optional second arg in case let->method */
32444 
32445   seq = car(args);
32446   carrier = (is_pair(cdr(args))) ? cadr(args) : NULL;
32447   iter = s7_make_iterator(sc, seq);
32448 
32449   if (carrier)
32450     {
32451       if (!is_pair(carrier))
32452 	return(simple_wrong_type_argument(sc, sc->make_iterator_symbol, carrier, T_PAIR));
32453       if (is_immutable_pair(carrier))
32454 	return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->make_iterator_symbol, carrier)));
32455 
32456       if (is_hash_table(iterator_sequence(iter)))
32457 	{
32458 	  iterator_current(iter) = carrier;
32459 	  set_mark_seq(iter);
32460 	}
32461       else
32462 	{
32463 	  if ((is_let(iterator_sequence(iter))) &&
32464 	      (iterator_sequence(iter) != sc->rootlet))
32465 	    {
32466 	      iterator_let_cons(iter) = carrier;
32467 	      set_mark_seq(iter);
32468 	    }
32469 	  else         /* (let-temporarily (((*s7* 'safety) 1)) (make-iterator "asdf" (cons 1 2))) */
32470 	    if (sc->safety > MORE_SAFETY_WARNINGS)
32471 	      s7_warn(sc, 256, "(make-iterator %s %s) does not need the second argument\n", display_80(seq), display_80(carrier));
32472 	}}
32473   return(iter);
32474 }
32475 
32476 
32477 /* -------------------------------- iterate -------------------------------- */
32478 static s7_pointer g_iterate(s7_scheme *sc, s7_pointer args)
32479 {
32480   #define H_iterate "(iterate obj) returns the next element from the iterator obj, or " ITERATOR_END_NAME "."
32481   #define Q_iterate s7_make_signature(sc, 2, sc->T, sc->is_iterator_symbol)
32482 
32483   s7_pointer iter;
32484   iter = car(args);
32485   if (!is_iterator(iter))
32486     return(method_or_bust_one_arg(sc, iter, sc->iterate_symbol, args, T_ITERATOR));
32487   return((iterator_next(iter))(sc, iter));
32488 }
32489 
32490 static s7_pointer iterate_p_p(s7_scheme *sc, s7_pointer iter)
32491 {
32492   if (!is_iterator(iter))
32493     return(method_or_bust_one_arg_p(sc, iter, sc->iterate_symbol, T_ITERATOR));
32494   return((iterator_next(iter))(sc, iter));
32495 }
32496 
32497 s7_pointer s7_iterate(s7_scheme *sc, s7_pointer obj)
32498 {
32499   return((iterator_next(obj))(sc, obj));
32500 }
32501 
32502 bool s7_iterator_is_at_end(s7_scheme *sc, s7_pointer obj)
32503 {
32504   if (iter_ok(obj))
32505     return(false);
32506   if (!is_iterator(obj))
32507     simple_wrong_type_argument(sc, sc->iterator_is_at_end_symbol, obj, T_ITERATOR);
32508   return(true);
32509 }
32510 
32511 static bool op_implicit_iterate(s7_scheme *sc)
32512 {
32513   s7_pointer s;
32514   s = lookup_checked(sc, car(sc->code));
32515   if (!is_iterator(s)) {sc->last_function = s; return(false);}
32516   sc->value = (iterator_next(s))(sc, s);
32517   return(true);
32518 }
32519 
32520 
32521 /* -------------------------------- iterator-at-end? -------------------------------- */
32522 static bool iterator_is_at_end_b_7p(s7_scheme *sc, s7_pointer obj)
32523 {
32524   if (iter_ok(obj))
32525     return(false);
32526   if (!is_iterator(obj))
32527     simple_wrong_type_argument(sc, sc->iterator_is_at_end_symbol, obj, T_ITERATOR);
32528   return(true);
32529 }
32530 
32531 static s7_pointer g_iterator_is_at_end(s7_scheme *sc, s7_pointer args)
32532 {
32533   #define H_iterator_is_at_end "(iterator-at-end? iter) returns #t if the iterator has reached the end of its sequence."
32534   #define Q_iterator_is_at_end s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_iterator_symbol)
32535   s7_pointer iter;
32536 
32537   iter = car(args);
32538   if (iter_ok(iter))
32539     return(sc->F);
32540   if (!is_iterator(iter))
32541     return(method_or_bust_one_arg(sc, iter, sc->iterator_is_at_end_symbol, args, T_ITERATOR));
32542   return(sc->T);
32543 }
32544 
32545 
32546 /* -------------------------------- iterator-sequence -------------------------------- */
32547 static s7_pointer g_iterator_sequence(s7_scheme *sc, s7_pointer args)
32548 {
32549   #define H_iterator_sequence "(iterator-sequence iterator) returns the sequence that iterator is traversing."
32550   #define Q_iterator_sequence s7_make_signature(sc, 2, sc->is_sequence_symbol, sc->is_iterator_symbol)
32551 
32552   s7_pointer iter;
32553 
32554   iter = car(args);
32555   if (!is_iterator(iter))
32556     return(method_or_bust_one_arg(sc, iter, sc->iterator_sequence_symbol, args, T_ITERATOR));
32557   return(iterator_sequence(iter));
32558 }
32559 
32560 
32561 /* -------- cycles -------- */
32562 
32563 #define INITIAL_SHARED_INFO_SIZE 8
32564 
32565 static int32_t shared_ref(shared_info_t *ci, s7_pointer p)
32566 {
32567   /* from print after collecting refs, not called by equality check, only called in object_to_port_with_circle_check_1 */
32568   int32_t i;
32569   s7_pointer *objs;
32570 
32571   objs = ci->objs;
32572   for (i = 0; i < ci->top; i++)
32573     if (objs[i] == p)
32574       {
32575 	int32_t val;
32576 	val = ci->refs[i];
32577 	if (val > 0)
32578 	  ci->refs[i] = -ci->refs[i];
32579 	return(val);
32580       }
32581   return(0);
32582 }
32583 
32584 static void flip_ref(shared_info_t *ci, s7_pointer p)
32585 {
32586   int32_t i;
32587   s7_pointer *objs;
32588 
32589   objs = ci->objs;
32590   for (i = 0; i < ci->top; i++)
32591     if (objs[i] == p)
32592       {
32593 	ci->refs[i] = -ci->refs[i];
32594 	break;
32595       }
32596 }
32597 
32598 static int32_t peek_shared_ref_1(shared_info_t *ci, s7_pointer p)
32599 {
32600   /* returns 0 if not found, otherwise the ref value for p */
32601   int32_t i;
32602   s7_pointer *objs;
32603 
32604   objs = ci->objs;
32605   for (i = 0; i < ci->top; i++)
32606     if (objs[i] == p)
32607       return(ci->refs[i]);
32608   return(0);
32609 }
32610 
32611 static int32_t peek_shared_ref(shared_info_t *ci, s7_pointer p)
32612 {
32613   /* returns 0 if not found, otherwise the ref value for p */
32614   return((is_collected_unchecked(p)) ? peek_shared_ref_1(ci, p) : 0);
32615 }
32616 
32617 static void enlarge_shared_info(shared_info_t *ci)
32618 {
32619   int32_t i;
32620   ci->size *= 2;
32621   ci->size2 = ci->size - 2;
32622   ci->objs = (s7_pointer *)Realloc(ci->objs, ci->size * sizeof(s7_pointer));
32623   ci->refs = (int32_t *)Realloc(ci->refs, ci->size * sizeof(int32_t));
32624   ci->defined = (bool *)Realloc(ci->defined, ci->size * sizeof(bool));
32625   /* this clearing is needed */
32626   for (i = ci->top; i < ci->size; i++)
32627     {
32628       ci->refs[i] = 0;
32629       ci->objs[i] = NULL;
32630     }
32631 }
32632 
32633 static bool collect_shared_info(s7_scheme *sc, shared_info_t *ci, s7_pointer top, bool stop_at_print_length);
32634 static hash_entry_t *hash_equal(s7_scheme *sc, s7_pointer table, s7_pointer key);
32635 static hash_entry_t *hash_equivalent(s7_scheme *sc, s7_pointer table, s7_pointer key);
32636 
32637 static bool check_collected(s7_pointer top, shared_info_t *ci)
32638 {
32639   s7_pointer *p, *objs_end;
32640   int32_t i;
32641 
32642   objs_end = (s7_pointer *)(ci->objs + ci->top);
32643   for (p = ci->objs; p < objs_end; p++)
32644     if ((*p) == top)
32645       {
32646 	i = (int32_t)(p - ci->objs);
32647 	if (ci->refs[i] == 0)
32648 	  {
32649 	    ci->has_hits = true;
32650 	    ci->refs[i] = ++ci->ref;  /* if found, set the ref number */
32651 	  }
32652 	break;
32653       }
32654   set_cyclic(top);
32655   return(true);
32656 }
32657 
32658 static bool collect_vector_info(s7_scheme *sc, shared_info_t *ci, s7_pointer top, bool stop_at_print_length)
32659 {
32660   s7_int i, plen;
32661   bool cyclic = false;
32662 
32663   if (stop_at_print_length)
32664     {
32665       plen = sc->print_length;
32666       if (plen > vector_length(top))
32667 	plen = vector_length(top);
32668     }
32669   else plen = vector_length(top);
32670 
32671   for (i = 0; i < plen; i++)
32672     {
32673       s7_pointer vel;
32674       vel = unchecked_vector_element(top, i);   /* "unchecked" because top might be rootlet, I think */
32675       if ((has_structure(vel)) &&
32676 	  (collect_shared_info(sc, ci, vel, stop_at_print_length)))
32677 	{
32678 	  set_cyclic(vel);
32679 	  cyclic = true;
32680 	  if ((is_c_pointer(vel)) ||
32681 	      (is_iterator(vel)) ||
32682 	      (is_c_object(vel)))
32683 	    check_collected(top, ci);
32684 	}}
32685   if (cyclic) set_cyclic(top);
32686   return(cyclic);
32687 }
32688 
32689 static bool collect_shared_info(s7_scheme *sc, shared_info_t *ci, s7_pointer top, bool stop_at_print_length)
32690 {
32691   /* look for top in current list.
32692    * As we collect objects (guaranteed to have structure) we set the collected bit.  If we ever
32693    *   encounter an object with that bit on, we've seen it before so we have a possible cycle.
32694    *   Once the collection pass is done, we run through our list, and clear all these bits.
32695    */
32696   bool top_cyclic;
32697 
32698   if (is_collected_or_shared(top))
32699     return((!is_shared(top)) && (check_collected(top, ci)));
32700 
32701   /* top not seen before -- add it to the list */
32702   set_collected(top);
32703 
32704   if (ci->top == ci->size)
32705     enlarge_shared_info(ci);
32706   ci->objs[ci->top++] = top;
32707 
32708   top_cyclic = false;
32709   /* now search the rest of this structure */
32710   if (is_pair(top))
32711     {
32712       s7_pointer p, cp;
32713       if ((has_structure(car(top))) &&
32714 	  (collect_shared_info(sc, ci, car(top), stop_at_print_length)))
32715 	top_cyclic = true;
32716 
32717       for (p = cdr(top); is_pair(p); p = cdr(p))
32718 	{
32719 	  if (is_collected_or_shared(p))
32720 	    {
32721 	      set_cyclic(top);
32722 	      set_cyclic(p);
32723 	      if (is_shared(p))
32724 		{
32725 		  if (!top_cyclic)
32726 		    for (cp = top; cp != p; cp = cdr(cp)) set_shared(cp);
32727 		  return(top_cyclic);
32728 		}
32729 	      return(check_collected(p, ci));
32730 	    }
32731 	  set_collected(p);
32732 	  if (ci->top == ci->size)
32733 	    enlarge_shared_info(ci);
32734 	  ci->objs[ci->top++] = p;
32735 	  if ((has_structure(car(p))) &&
32736 	      (collect_shared_info(sc, ci, car(p), stop_at_print_length)))
32737 	    top_cyclic = true;
32738 	}
32739       if ((has_structure(p)) &&
32740 	  (collect_shared_info(sc, ci, p, stop_at_print_length)))
32741 	{
32742 	  set_cyclic(top);
32743 	  return(true);
32744 	}
32745       if (!top_cyclic)
32746 	for (cp = top; is_pair(cp); cp = cdr(cp)) set_shared(cp);
32747       else set_cyclic(top);
32748       return(top_cyclic);
32749     }
32750 
32751   switch (type(top))
32752     {
32753     case T_VECTOR:
32754       if (collect_vector_info(sc, ci, top, stop_at_print_length))
32755 	top_cyclic = true;
32756       break;
32757 
32758     case T_ITERATOR:
32759       if ((is_sequence(iterator_sequence(top))) && /* might be a function with +iterator+ local */
32760 	  (collect_shared_info(sc, ci, iterator_sequence(top), stop_at_print_length)))
32761 	{
32762 	  if (peek_shared_ref(ci, iterator_sequence(top)) == 0)
32763 	    check_collected(iterator_sequence(top), ci);
32764 	  top_cyclic = true;
32765 	}
32766       break;
32767 
32768     case T_HASH_TABLE:
32769       if (hash_table_entries(top) > 0)
32770 	{
32771 	  s7_int i, len;
32772 	  hash_entry_t **entries;
32773 	  bool keys_safe;
32774 
32775 	  keys_safe = ((hash_table_checker(top) != hash_equal) &&
32776 		       (hash_table_checker(top) != hash_equivalent) &&
32777 		       (!hash_table_checker_locked(top)));
32778 	  entries = hash_table_elements(top);
32779 	  len = hash_table_mask(top) + 1;
32780 	  for (i = 0; i < len; i++)
32781 	    {
32782 	      hash_entry_t *p;
32783 	      for (p = entries[i]; p; p = hash_entry_next(p))
32784 		{
32785 		  if ((!keys_safe) &&
32786 		      (has_structure(hash_entry_key(p))) &&
32787 		      (collect_shared_info(sc, ci, hash_entry_key(p), stop_at_print_length)))
32788 		    top_cyclic = true;
32789 		  if ((has_structure(hash_entry_value(p))) &&
32790 		      (collect_shared_info(sc, ci, hash_entry_value(p), stop_at_print_length)))
32791 		    {
32792 		      if ((is_c_pointer(hash_entry_value(p))) ||
32793 			  (is_iterator(hash_entry_value(p))) ||
32794 			  (is_c_object(hash_entry_value(p))))
32795 			check_collected(top, ci);
32796 		      top_cyclic = true;
32797 		    }}}}
32798       break;
32799 
32800     case T_SLOT: /* this can be hit if we somehow collect_shared_info on sc->rootlet via collect_vector_info (see the let case below) */
32801       if ((has_structure(slot_value(top))) &&
32802 	  (collect_shared_info(sc, ci, slot_value(top), stop_at_print_length)))
32803 	top_cyclic = true;
32804       break;
32805 
32806     case T_LET:
32807       if (top == sc->rootlet)
32808 	{
32809 	  if (collect_vector_info(sc, ci, top, stop_at_print_length))
32810 	    top_cyclic = true;
32811 	}
32812       else
32813 	{
32814 	  s7_pointer p, q;
32815 	  for (q = top; is_let(q) && (q != sc->rootlet); q = let_outlet(q))
32816 	    for (p = let_slots(q); tis_slot(p); p = next_slot(p))
32817 	      if ((has_structure(slot_value(p))) &&
32818 		  (collect_shared_info(sc, ci, slot_value(p), stop_at_print_length)))
32819 		{
32820 		  top_cyclic = true;
32821 		  if ((is_c_pointer(slot_value(p))) ||
32822 		      (is_iterator(slot_value(p))) ||
32823 		      (is_c_object(slot_value(p))))
32824 		    check_collected(top, ci);
32825 		}}
32826       break;
32827 
32828     case T_CLOSURE:
32829     case T_CLOSURE_STAR:
32830       if (collect_shared_info(sc, ci, closure_body(top), stop_at_print_length))
32831 	{
32832 	  if (peek_shared_ref(ci, top) == 0)
32833 	    check_collected(top, ci);
32834 	  top_cyclic = true;
32835 	}
32836       break;
32837 
32838     case T_C_POINTER:
32839       if ((has_structure(c_pointer_type(top))) &&
32840 	  (collect_shared_info(sc, ci, c_pointer_type(top), stop_at_print_length)))
32841 	{
32842 	  if (peek_shared_ref(ci, c_pointer_type(top)) == 0)
32843 	    check_collected(c_pointer_type(top), ci);
32844 	  top_cyclic = true;
32845 	}
32846       if ((has_structure(c_pointer_info(top))) &&
32847 	  (collect_shared_info(sc, ci, c_pointer_info(top), stop_at_print_length)))
32848 	{
32849 	  if (peek_shared_ref(ci, c_pointer_info(top)) == 0)
32850 	    check_collected(c_pointer_info(top), ci);
32851 	  top_cyclic = true;
32852 	}
32853       break;
32854 
32855     case T_C_OBJECT:
32856       if ((c_object_to_list(sc, top)) &&
32857 	  (c_object_set(sc, top)) &&
32858 	  (collect_shared_info(sc, ci, (*(c_object_to_list(sc, top)))(sc, set_plist_1(sc, top)), stop_at_print_length)))
32859 	{
32860 	  if (peek_shared_ref(ci, top) == 0)
32861 	    check_collected(top, ci);
32862 	  top_cyclic = true;
32863 	}
32864       break;
32865     }
32866 
32867   if (!top_cyclic)
32868     set_shared(top);
32869   else set_cyclic(top);
32870   return(top_cyclic);
32871 }
32872 
32873 static shared_info_t *init_circle_info(s7_scheme *sc)
32874 {
32875   shared_info_t *ci;
32876   ci = (shared_info_t *)calloc(1, sizeof(shared_info_t));
32877   ci->size = INITIAL_SHARED_INFO_SIZE;
32878   ci->size2 = ci->size - 2;
32879   ci->objs = (s7_pointer *)malloc(ci->size * sizeof(s7_pointer));
32880   ci->refs = (int32_t *)calloc(ci->size, sizeof(int32_t));   /* finder expects 0 = unseen previously */
32881   ci->defined = (bool *)calloc(ci->size, sizeof(bool));
32882   ci->cycle_port = sc->F;
32883   ci->init_port = sc->F;
32884   return(ci);
32885 }
32886 
32887 static inline shared_info_t *new_shared_info(s7_scheme *sc)
32888 {
32889   shared_info_t *ci;
32890   ci = sc->circle_info;
32891   if (ci->top > 0)
32892     {
32893       int32_t i;
32894       memclr((void *)(ci->refs), ci->top * sizeof(int32_t));
32895       memclr((void *)(ci->defined), ci->top * sizeof(bool));
32896       for (i = 0; i < ci->top; i++)
32897 	clear_cyclic_bits(ci->objs[i]); /* LOOP_4 is not faster */
32898       ci->top = 0;
32899     }
32900   ci->ref = 0;
32901   ci->has_hits = false;
32902   return(ci);
32903 }
32904 
32905 static shared_info_t *make_shared_info(s7_scheme *sc, s7_pointer top, bool stop_at_print_length)
32906 {
32907   /* for the printer */
32908   shared_info_t *ci;
32909   int32_t i, refs;
32910   s7_pointer *ci_objs;
32911   int32_t *ci_refs;
32912   bool no_problem = true, cyclic = false;
32913   s7_int k, stop_len;
32914 
32915   /* check for simple cases first */
32916   if (is_pair(top))
32917     {
32918       s7_pointer x;
32919       x = top;
32920       if (stop_at_print_length)
32921 	{
32922 	  s7_pointer slow;
32923 	  stop_len = sc->print_length;
32924 	  slow = top;
32925 	  for (k = 0; k < stop_len; k += 2)
32926 	    {
32927 	      if (!is_pair(x))
32928 		break;
32929 	      if (has_structure(car(x)))
32930 		{
32931 		  no_problem = false;
32932 		  break;
32933 		}
32934 	      x = cdr(x);
32935 	      if (!is_pair(x))
32936 		break;
32937 	      if (has_structure(car(x)))
32938 		{
32939 		  no_problem = false;
32940 		  break;
32941 		}
32942 	      x = cdr(x);
32943 	      slow = cdr(slow);
32944 	      if (x == slow)
32945 		{
32946 		  no_problem = false;
32947 		  break;
32948 		}}}
32949       else
32950 	{
32951 	  if (s7_list_length(sc, top) == 0) /* it is circular at the top level (following cdr) */
32952 	    no_problem = false;
32953 	  else
32954 	    for (; is_pair(x); x = cdr(x))
32955 	      if (has_structure(car(x)))
32956 		{
32957 		  /* it can help a little in some cases to scan vectors here (and slots):
32958 		   *   if no element has structure, it's ok (maybe also hash_table_entries == 0)
32959 		   */
32960 		  no_problem = false;
32961 		  break;
32962 		}}
32963       if ((no_problem) &&
32964 	  (!is_null(x)) &&
32965 	  (has_structure(x)))
32966 	no_problem = false;
32967 
32968       if (no_problem)
32969 	return(NULL);
32970     }
32971   else
32972     if (is_any_vector(top))
32973       {
32974 	if (!is_normal_vector(top))
32975 	  return(NULL);
32976 
32977 	stop_len = vector_length(top);
32978 	if ((stop_at_print_length) &&
32979 	    (stop_len > sc->print_length))
32980 	  stop_len = sc->print_length;
32981 
32982 	for (k = 0; k < stop_len; k++)
32983 	  if (has_structure(vector_element(top, k)))
32984 	    {
32985 	      no_problem = false;
32986 	      break;
32987 	    }
32988 	if (no_problem)
32989 	  return(NULL);
32990       }
32991 
32992   ci = new_shared_info(sc);
32993 
32994   /* collect all pointers associated with top */
32995   cyclic = collect_shared_info(sc, ci, top, stop_at_print_length);
32996 
32997   ci_objs = ci->objs;
32998   for (i = 0; i < ci->top; i++)
32999     clear_collected_and_shared(ci_objs[i]);
33000 
33001   if (!cyclic)
33002     return(NULL);
33003 
33004   if (!(ci->has_hits))
33005     return(NULL);
33006 
33007   ci_refs = ci->refs;
33008   /* find if any were referenced twice (once for just being there, so twice=shared)
33009    *   we know there's at least one such reference because has_hits is true.
33010    */
33011   for (i = 0, refs = 0; i < ci->top; i++)
33012     if (ci_refs[i] > 0)
33013       {
33014 	set_collected(ci_objs[i]);
33015 	if (i == refs)
33016 	  refs++;
33017 	else
33018 	  {
33019 	    ci_objs[refs] = ci_objs[i];
33020 	    ci_refs[refs++] = ci_refs[i];
33021 	    ci_refs[i] = 0;
33022 	    ci_objs[i] = NULL;
33023 	  }}
33024   ci->top = refs;
33025   return(ci);
33026 }
33027 
33028 
33029 /* -------------------------------- cyclic-sequences -------------------------------- */
33030 
33031 static s7_pointer cyclic_sequences_p_p(s7_scheme *sc, s7_pointer obj)
33032 {
33033   if (has_structure(obj))
33034     {
33035       shared_info_t *ci;
33036       ci = (sc->object_out_locked) ? sc->circle_info : make_shared_info(sc, obj, false); /* false=don't stop at print length (vectors etc) */
33037       if (ci)
33038 	{
33039 	  int32_t i;
33040 	  s7_pointer lst;
33041 	  sc->w = sc->nil;
33042 	  check_free_heap_size(sc, ci->top);
33043 	  for (i = 0; i < ci->top; i++)
33044 	    sc->w = cons_unchecked(sc, ci->objs[i], sc->w);
33045 	  lst = sc->w;
33046 	  sc->w = sc->nil;
33047 	  return(lst);
33048 	}}
33049   return(sc->nil);
33050 }
33051 
33052 static s7_pointer g_cyclic_sequences(s7_scheme *sc, s7_pointer args)
33053 {
33054   #define H_cyclic_sequences "(cyclic-sequences obj) returns a list of elements that are cyclic."
33055   #define Q_cyclic_sequences s7_make_signature(sc, 2, sc->is_proper_list_symbol, sc->T)
33056   return(cyclic_sequences_p_p(sc, car(args)));
33057 }
33058 
33059 static int32_t circular_list_entries(s7_pointer lst)
33060 {
33061   int32_t i;
33062   s7_pointer x;
33063   for (i = 1, x = cdr(lst); ; i++, x = cdr(x))
33064     {
33065       int32_t j;
33066       s7_pointer y;
33067       for (y = lst, j = 0; j < i; y = cdr(y), j++)
33068 	if (x == y)
33069 	  return(i);
33070     }
33071 }
33072 
33073 static void object_to_port_with_circle_check_1(s7_scheme *sc, s7_pointer vr, s7_pointer port, use_write_t use_write, shared_info_t *ci);
33074 #define object_to_port_with_circle_check(Sc, Vr, Port, Use_Write, Ci) \
33075   do {								      \
33076     s7_pointer _V_ = Vr;						\
33077     if ((Ci) && (has_structure(_V_)))					\
33078       object_to_port_with_circle_check_1(Sc, _V_, Port, Use_Write, Ci); \
33079     else object_to_port(Sc, _V_, Port, Use_Write, Ci);			\
33080   } while (0)
33081 
33082 static void (*display_functions[256])(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci);
33083 #define object_to_port(Sc, Obj, Port, Use_Write, Ci) (*display_functions[unchecked_type(Obj)])(Sc, Obj, Port, Use_Write, Ci)
33084 
33085 static bool string_needs_slashification(const char *str, s7_int len)
33086 {
33087   /* we have to go by len (str len) not *s==0 because s7 strings can have embedded nulls */
33088   uint8_t *p, *pend;
33089   pend = (uint8_t *)(str + len);
33090   for (p = (uint8_t *)str; p < pend; p++)
33091     if (slashify_table[*p])
33092       return(true);
33093   return(false);
33094 }
33095 
33096 #define IN_QUOTES true
33097 #define NOT_IN_QUOTES false
33098 
33099 static void slashify_string_to_port(s7_scheme *sc, s7_pointer port, const char *p, s7_int len, bool quoted)
33100 {
33101   uint8_t *pcur, *pend, *pstart = NULL;
33102 
33103   if (len == 0)
33104     {
33105       if (quoted)
33106 	port_write_string(port)(sc, "\"\"", 2, port);
33107       return;
33108     }
33109   pend = (uint8_t *)(p + len);
33110 
33111   /* what about the trailing nulls? Guile writes them out (as does s7 currently)
33112    *    but that is not ideal.  I'd like to use ~S for error messages, so that
33113    *    strings are clearly identified via the double-quotes, but this way of
33114    *    writing them is ugly:
33115    *      (let ((str (make-string 8 #\null))) (set! (str 0) #\a) str) -> "a\x00\x00\x00\x00\x00\x00\x00"
33116    *    but it would be misleading to omit them because:
33117    *      (let ((str (make-string 8 #\null))) (set! (str 0) #\a) (string-append str "bc")) -> "a\x00\x00\x00\x00\x00\x00\x00bc"
33118    * also it is problematic to use sc->print_length here (rather than a separate string-print-length) because
33119    *    it is normally (say) 8 which truncates just about every string.  In CL, *print-length*
33120    *    does not affect strings, symbols, or bit-vectors.  But if the string is enormous,
33121    *    this function can bring us to a complete halt.  string-print-length (as a *s7* field) is
33122    *    also problematic -- it does not behave as expected in many cases if it is limited to this
33123    *    function and string_to_port below, and if set too low, disables the repl.
33124    */
33125   if (quoted) port_write_character(port)(sc, '"', port);
33126   for (pcur = (uint8_t *)p; pcur < pend; pcur++)
33127     {
33128       if (slashify_table[*pcur])
33129 	{
33130 	  if (pstart) pstart++; else pstart = (uint8_t *)p;
33131 	  if (pstart != pcur)
33132 	    {
33133 	      port_write_string(port)(sc, (char *)pstart, pcur - pstart, port);
33134 	      pstart = pcur;
33135 	    }
33136 	  port_write_character(port)(sc, '\\', port);
33137 	  switch (*pcur)
33138 	    {
33139 	    case '"':   port_write_character(port)(sc, '"', port);   break;
33140 	    case '\\':  port_write_character(port)(sc, '\\', port);  break;
33141 	    case '\'':  port_write_character(port)(sc, '\'', port);  break;
33142 	    case '\t':  port_write_character(port)(sc, 't', port);   break;
33143 	    case '\r':  port_write_character(port)(sc, 'r', port);   break;
33144 	    case '\b':  port_write_character(port)(sc, 'b', port);   break;
33145 	    case '\f':  port_write_character(port)(sc, 'f', port);   break;
33146 	    case '\?':  port_write_character(port)(sc, '?', port);   break;
33147 	    case 'x':   port_write_character(port)(sc, 'x', port);   break;
33148 	    default:
33149 	      {
33150 		s7_int n;
33151 		port_write_character(port)(sc, 'x', port);
33152 		n = (s7_int)(*pcur);
33153 		if (n < 16)
33154 		  port_write_character(port)(sc, '0', port);
33155 		else port_write_character(port)(sc, dignum[(n / 16) % 16], port);
33156 		port_write_character(port)(sc, dignum[n % 16], port);
33157 		port_write_character(port)(sc, ';', port);
33158 	      }
33159 	      break;
33160 	    }}}
33161   if (!pstart)
33162     port_write_string(port)(sc, (char *)p, len, port);
33163   else
33164     {
33165       pstart++;
33166       if (pstart != pcur)
33167 	port_write_string(port)(sc, (char *)pstart, pcur - pstart, port);
33168     }
33169   if (quoted) port_write_character(port)(sc, '"', port);
33170 }
33171 
33172 static void output_port_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
33173 {
33174   if ((obj == sc->standard_output) ||
33175       (obj == sc->standard_error))
33176     port_write_string(port)(sc, port_filename(obj), port_filename_length(obj), port);
33177   else
33178     {
33179       if (use_write == P_READABLE)
33180 	{
33181 	  if (port_is_closed(obj))
33182 	    port_write_string(port)(sc, "(let ((p (open-output-string))) (close-output-port p) p)", 56, port);
33183 	  else
33184 	    {
33185 	      if (is_string_port(obj))
33186 		{
33187 		  port_write_string(port)(sc, "(let ((p (open-output-string)))", 31, port);
33188 		  if (port_position(obj) > 0)
33189 		    {
33190 		      port_write_string(port)(sc, " (display ", 10, port);
33191 		      slashify_string_to_port(sc, port, (const char *)port_data(obj), port_position(obj), IN_QUOTES);
33192 		      port_write_string(port)(sc, " p)", 3, port);
33193 		    }
33194 		  port_write_string(port)(sc, " p)", 3, port);
33195 		}
33196 	      else
33197 		{
33198 		  if (is_file_port(obj))
33199 		    {
33200 		      char str[256];
33201 		      int32_t nlen;
33202 		      str[0] = '\0';
33203 		      nlen = catstrs(str, 256, "(open-output-file \"", port_filename(obj), "\" \"a\")", (char *)NULL);
33204 		      port_write_string(port)(sc, str, nlen, port);
33205 		    }
33206 		  else port_write_string(port)(sc, "#<output-function-port>", 23, port);
33207 		}}}
33208       else
33209 	{
33210 	  if (is_string_port(obj))
33211 	    port_write_string(port)(sc, "#<output-string-port", 20, port);
33212 	  else
33213 	    {
33214 	      if (is_file_port(obj))
33215 		port_write_string(port)(sc, "#<output-file-port", 18, port);
33216 	      else port_write_string(port)(sc, "#<output-function-port", 22, port);
33217 	    }
33218 	  if (port_is_closed(obj))
33219 	    port_write_string(port)(sc, ":closed>", 8, port);
33220 	  else port_write_character(port)(sc, '>', port);
33221 	}}
33222 }
33223 
33224 static void input_port_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
33225 {
33226   if (obj == sc->standard_input)
33227     port_write_string(port)(sc, port_filename(obj), port_filename_length(obj), port);
33228   else
33229     {
33230       if (use_write == P_READABLE)
33231 	{
33232 	  if (port_is_closed(obj))
33233 	    port_write_string(port)(sc, "(call-with-input-string \"\" (lambda (p) p))", 42, port);
33234 	  else
33235 	    {
33236 	      if (is_function_port(obj))
33237 		port_write_string(port)(sc, "#<input-function-port>", 22, port);
33238 	      else
33239 		{
33240 		  if (is_file_port(obj))
33241 		    {
33242 		      char str[256];
33243 		      int32_t nlen;
33244 		      str[0] = '\0';
33245 		      nlen = catstrs(str, 256, "(open-input-file \"", port_filename(obj), "\")", (char *)NULL);
33246 		      port_write_string(port)(sc, str, nlen, port);
33247 		    }
33248 		  else
33249 		    {
33250 		      s7_int data_len;
33251 		      data_len = port_data_size(obj) - port_position(obj);
33252 		      if (data_len > 100)
33253 			{
33254 			  const char *filename;
33255 			  filename = (const char *)s7_port_filename(sc, obj);
33256 			  if (filename)
33257 			    {
33258 			      #define DO_STR_LEN 1024
33259 			      char do_str[DO_STR_LEN];
33260 			      int32_t len;
33261 			      do_str[0] = '\0';
33262 			      if (port_position(obj) > 0)
33263 				{
33264 				  len = catstrs(do_str, DO_STR_LEN, "(let ((port (open-input-file \"", filename, "\")))", (char *)NULL);
33265 				  port_write_string(port)(sc, do_str, len, port);
33266 				  do_str[0] = '\0';
33267 				  len = catstrs(do_str, DO_STR_LEN, " (do ((i 0 (+ i 1)) (c (read-char port) (read-char port))) ((= i ",
33268 						pos_int_to_str_direct(sc, port_position(obj) - 1),
33269 						") port)))", (char *)NULL);
33270 				}
33271 			      else len = catstrs(do_str, DO_STR_LEN, "(open-input-file \"", filename, "\")", (char *)NULL);
33272 			      port_write_string(port)(sc, do_str, len, port);
33273 			      return;
33274 			    }}
33275 		      port_write_string(port)(sc, "(open-input-string ", 19, port);
33276 		      /* not port_write_string here because there might be embedded double-quotes */
33277 		      slashify_string_to_port(sc, port, (const char *)(port_data(obj) + port_position(obj)), port_data_size(obj) - port_position(obj), IN_QUOTES);
33278 		      port_write_character(port)(sc, ')', port);
33279 		    }}}}
33280       else
33281 	{
33282 	  if (is_string_port(obj))
33283 	    port_write_string(port)(sc, "#<input-string-port", 19, port);
33284 	  else
33285 	    {
33286 	      if (is_file_port(obj))
33287 		port_write_string(port)(sc, "#<input-file-port", 17, port);
33288 	      else port_write_string(port)(sc, "#<input-function-port", 21, port);
33289 	    }
33290 	  if (port_is_closed(obj))
33291 	    port_write_string(port)(sc, ":closed>", 8, port);
33292 	  else port_write_character(port)(sc, '>', port);
33293 	}}
33294 }
33295 
33296 static bool symbol_needs_slashification(s7_scheme *sc, s7_pointer obj)
33297 {
33298   uint8_t *p, *pend;
33299   const char *str;
33300   s7_int len;
33301 
33302   str = symbol_name(obj);
33303   if ((str[0] == '#') || (str[0] == '\'') || (str[0] == ','))
33304     return(true);
33305 
33306   if (s7_is_number(make_atom(sc, (char *)str, 10, NO_SYMBOLS, WITHOUT_OVERFLOW_ERROR)))
33307     return(true);
33308 
33309   len = symbol_name_length(obj);
33310   pend = (uint8_t *)(str + len);
33311   for (p = (uint8_t *)str; p < pend; p++)
33312     if (symbol_slashify_table[*p])
33313       return(true);
33314 
33315   set_clean_symbol(obj);
33316   return(false);
33317 }
33318 
33319 static inline void symbol_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
33320 {
33321   /* I think this is the only place we print a symbol's name */
33322   if ((!is_clean_symbol(obj)) &&
33323       (symbol_needs_slashification(sc, obj)))
33324     {
33325       port_write_string(port)(sc, "(symbol \"", 9, port);
33326       slashify_string_to_port(sc, port, symbol_name(obj), symbol_name_length(obj), NOT_IN_QUOTES);
33327       port_write_string(port)(sc, "\")", 2, port);
33328     }
33329   else
33330     {
33331       if (!is_keyword(obj))
33332 	{
33333 	  if (use_write == P_READABLE)
33334 	    port_write_character(port)(sc, '\'', port);
33335 	  else
33336 	    if (use_write == P_KEY)
33337 	      port_write_character(port)(sc, ':', port);
33338 	}
33339       if (is_string_port(port))
33340 	{
33341 	  s7_int new_len;
33342 	  new_len = port_position(port) + symbol_name_length(obj);
33343 	  if (new_len >= port_data_size(port))
33344 	    resize_port_data(sc, port, new_len * 2);
33345 	  memcpy((void *)(port_data(port) + port_position(port)), (void *)symbol_name(obj), symbol_name_length(obj));
33346 	  port_position(port) = new_len;
33347 	}
33348       else port_write_string(port)(sc, symbol_name(obj), symbol_name_length(obj), port);
33349     }
33350 }
33351 
33352 static char *multivector_indices_to_string(s7_scheme *sc, s7_int index, s7_pointer vect, char *str, int32_t str_len, int32_t cur_dim)
33353 {
33354   s7_int size, ind;
33355 
33356   size = vector_dimension(vect, cur_dim);
33357   ind = index % size;
33358   if (cur_dim > 0)
33359     multivector_indices_to_string(sc, (index - ind) / size, vect, str, str_len, cur_dim - 1);
33360   catstrs(str, str_len, " ", pos_int_to_str_direct(sc, ind), (char *)NULL);
33361   return(str);
33362 }
33363 
33364 #define NOT_P_DISPLAY(Choice) ((Choice == P_DISPLAY) ? P_WRITE : Choice)
33365 
33366 static int32_t multivector_to_port(s7_scheme *sc, s7_pointer vec, s7_pointer port,
33367 				   int32_t out_len, int32_t flat_ref, int32_t dimension, int32_t dimensions, bool *last,
33368 				   use_write_t use_write, shared_info_t *ci)
33369 {
33370   int32_t i;
33371   if (use_write != P_READABLE)
33372     {
33373       if (*last)
33374 	port_write_string(port)(sc, " (", 2, port);
33375       else port_write_character(port)(sc, '(', port);
33376       (*last) = false;
33377     }
33378 
33379   for (i = 0; i < vector_dimension(vec, dimension); i++)
33380     {
33381       if (dimension == (dimensions - 1))
33382 	{
33383 	  if (flat_ref < out_len)
33384 	    {
33385 	      object_to_port_with_circle_check(sc, vector_getter(vec)(sc, vec, flat_ref), port, NOT_P_DISPLAY(use_write), ci);
33386 
33387 	      if (use_write == P_READABLE)
33388 		port_write_string(port)(sc, ") ", 2, port);
33389 	      flat_ref++;
33390 	    }
33391 	  else
33392 	    {
33393 	      port_write_string(port)(sc, "...)", 4, port);
33394 	      return(flat_ref);
33395 	    }
33396 	  if ((use_write != P_READABLE) &&
33397 	      (i < (vector_dimension(vec, dimension) - 1)))
33398 	    port_write_character(port)(sc, ' ', port);
33399 	}
33400       else
33401 	{
33402 	  if (flat_ref < out_len)
33403 	    flat_ref = multivector_to_port(sc, vec, port, out_len, flat_ref, dimension + 1, dimensions, last, NOT_P_DISPLAY(use_write), ci);
33404 	  else
33405 	    {
33406 	      port_write_string(port)(sc, "...)", 4, port);
33407 	      return(flat_ref);
33408 	    }}}
33409   if (use_write != P_READABLE)
33410     port_write_character(port)(sc, ')', port);
33411   (*last) = true;
33412   return(flat_ref);
33413 }
33414 
33415 static void make_vector_to_port(s7_scheme *sc, s7_pointer vect, s7_pointer port)
33416 {
33417   s7_int vlen;
33418   int32_t plen;
33419   char buf[128];
33420   const char* vtyp = "";
33421 
33422   if (is_float_vector(vect))
33423     vtyp = "float-";
33424   else
33425     {
33426       if (is_int_vector(vect))
33427 	vtyp = "int-";
33428       else
33429 	if (is_byte_vector(vect))
33430 	  vtyp = "byte-";
33431     }
33432 
33433   vlen = vector_length(vect);
33434   if (vector_rank(vect) == 1)
33435     {
33436       plen = catstrs_direct(buf, "(make-", vtyp, "vector ", integer_to_string_no_length(sc, vlen), " ", (const char *)NULL);
33437       port_write_string(port)(sc, buf, plen, port);
33438     }
33439   else
33440     {
33441       s7_int dim;
33442       plen = catstrs_direct(buf, "(make-", vtyp, "vector '(", (const char *)NULL);
33443       port_write_string(port)(sc, buf, plen, port);
33444       for (dim = 0; dim < vector_ndims(vect) - 1; dim++)
33445 	{
33446 	  plen = catstrs_direct(buf, integer_to_string_no_length(sc, vector_dimension(vect, dim)), " ", (const char *)NULL);
33447 	  port_write_string(port)(sc, buf, plen, port);
33448 	}
33449       plen = catstrs_direct(buf, integer_to_string_no_length(sc, vector_dimension(vect, dim)), ") ", (const char *)NULL);
33450       port_write_string(port)(sc, buf, plen, port);
33451     }
33452 }
33453 
33454 static void write_vector_dimensions(s7_scheme *sc, s7_pointer vect, s7_pointer port)
33455 {
33456   char buf[128];
33457   s7_int dim, plen;
33458   port_write_string(port)(sc, " '(", 3, port);
33459   for (dim = 0; dim < vector_ndims(vect) - 1; dim++)
33460     {
33461       plen = catstrs_direct(buf, integer_to_string_no_length(sc, vector_dimension(vect, dim)), " ", (const char *)NULL);
33462       port_write_string(port)(sc, buf, plen, port);
33463     }
33464   plen = catstrs_direct(buf, integer_to_string_no_length(sc, vector_dimension(vect, dim)), "))", (const char *)NULL);
33465   port_write_string(port)(sc, buf, plen, port);
33466 }
33467 
33468 static void vector_to_port(s7_scheme *sc, s7_pointer vect, s7_pointer port, use_write_t use_write, shared_info_t *ci)
33469 {
33470   s7_int i, len, plen;
33471   bool too_long = false;
33472   char buf[2048]; /* 128 is too small -- this is the list of indices with a few minor flourishes */
33473 
33474   len = vector_length(vect);
33475   if (len == 0)
33476     {
33477       if (vector_rank(vect) > 1)
33478 	{
33479 	  plen = catstrs_direct(buf, "#", pos_int_to_str_direct(sc, vector_ndims(vect)), "d()", (const char *)NULL);
33480 	  port_write_string(port)(sc, buf, plen, port);
33481 	}
33482       else port_write_string(port)(sc, "#()", 3, port);
33483       return;
33484     }
33485 
33486   if (use_write != P_READABLE)
33487     {
33488       if (sc->print_length == 0)
33489 	{
33490 	  if (vector_rank(vect) > 1)
33491 	    {
33492 	      plen = catstrs_direct(buf, "#", pos_int_to_str_direct(sc, vector_ndims(vect)), "d(...)", (const char *)NULL);
33493 	      port_write_string(port)(sc, buf, plen, port);
33494 	    }
33495 	  else port_write_string(port)(sc, "#(...)", 6, port);
33496 	  return;
33497 	}
33498       if (len > sc->print_length)
33499 	{
33500 	  too_long = true;
33501 	  len = sc->print_length;
33502 	}}
33503   if ((!ci) &&
33504       (len > 1000))
33505     {
33506       s7_int vlen;
33507       s7_pointer p0;
33508       s7_pointer *els;
33509       vlen = vector_length(vect);
33510       els = vector_elements(vect);
33511       p0 = els[0];
33512       for (i = 1; i < vlen; i++)
33513 	if (els[i] != p0)
33514 	  break;
33515       if (i == vlen)
33516 	{
33517 	  make_vector_to_port(sc, vect, port);
33518 	  object_to_port(sc, p0, port, use_write, NULL);
33519 	  port_write_character(port)(sc, ')', port);
33520 	  return;
33521 	}}
33522 
33523   check_stack_size(sc);
33524   push_stack_no_let_no_code(sc, OP_GC_PROTECT, vect);
33525   if (use_write == P_READABLE)
33526     {
33527       int32_t vref;
33528       if ((ci) &&
33529 	  (is_cyclic(vect)) &&
33530 	  ((vref = peek_shared_ref(ci, vect)) != 0))
33531 	{
33532 	  s7_pointer *els;
33533 	  if (vref < 0) vref = -vref;
33534 	  els = vector_elements(vect);
33535 
33536 	  if ((ci->defined[vref]) || (port == ci->cycle_port))
33537 	    {
33538 	      plen = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, vref), ">", (const char *)NULL);
33539 	      port_write_string(port)(sc, buf, plen, port);
33540 	      unstack(sc);
33541 	      return;
33542 	    }
33543 
33544 	  if (vector_rank(vect) > 1)
33545 	    port_write_string(port)(sc, "(subvector ", 11, port);
33546 
33547 	  port_write_string(port)(sc, "(vector", 7, port); /* top level let */
33548 	  for (i = 0; i < len; i++)
33549 	    {
33550 	      if (has_structure(els[i]))
33551 		{
33552 		  char *indices;
33553 		  int32_t eref;
33554 		  port_write_string(port)(sc, " #f", 3, port);
33555 		  eref = peek_shared_ref(ci, els[i]);
33556 
33557 		  if (eref != 0)
33558 		    {
33559 		      if (eref < 0) eref = -eref;
33560 		      if (vector_rank(vect) > 1)
33561 			{
33562 			  s7_int dimension;
33563 			  int32_t str_len;
33564 			  block_t *b;
33565 			  dimension = vector_rank(vect) - 1;
33566 			  str_len = (dimension < 8) ? 128 : ((dimension + 1) * 16);
33567 			  b = callocate(sc, str_len);
33568 			  indices = (char *)block_data(b);
33569 			  multivector_indices_to_string(sc, i, vect, indices, str_len, dimension); /* calls pos_int_to_str_direct, writes to indices */
33570 			  plen = catstrs_direct(buf, "  (set! (<", pos_int_to_str_direct(sc, vref), ">",
33571 						indices, ") <", pos_int_to_str_direct_1(sc, eref), ">) ", (const char *)NULL);
33572 			  port_write_string(ci->cycle_port)(sc, buf, plen, ci->cycle_port);
33573 			  liberate(sc, b);
33574 			}
33575 		      else
33576 			{
33577 			  size_t len1;
33578 			  len1 = catstrs_direct(buf, "  (set! (<", pos_int_to_str_direct(sc, vref), "> ", integer_to_string(sc, i, &plen), ") <",
33579 						pos_int_to_str_direct_1(sc, eref), ">) ", (const char *)NULL);
33580 			  port_write_string(ci->cycle_port)(sc, buf, len1, ci->cycle_port);
33581 			}}
33582 		  else
33583 		    {
33584 		      if (vector_rank(vect) > 1)
33585 			{
33586 			  s7_int dimension;
33587 			  int32_t str_len;
33588 			  block_t *b;
33589 			  dimension = vector_rank(vect) - 1;
33590 			  str_len = (dimension < 8) ? 128 : ((dimension + 1) * 16);
33591 			  b = callocate(sc, str_len);
33592 			  indices = (char *)block_data(b);
33593 			  buf[0] = '\0';
33594 			  multivector_indices_to_string(sc, i, vect, indices, str_len, dimension); /* writes to indices */
33595 			  plen = catstrs(buf, 2048, "  (set! (<", pos_int_to_str_direct(sc, vref), ">", indices, ") ", (char *)NULL);
33596 			  port_write_string(ci->cycle_port)(sc, buf, plen, ci->cycle_port);
33597 			  liberate(sc, b);
33598 			}
33599 		      else
33600 			{
33601 			  size_t len1;
33602 			  len1 = catstrs_direct(buf, "  (set! (<", pos_int_to_str_direct(sc, vref), "> ", integer_to_string_no_length(sc, i), ") ", (const char *)NULL);
33603 			  port_write_string(ci->cycle_port)(sc, buf, len1, ci->cycle_port);
33604 			}
33605 		      object_to_port_with_circle_check(sc, els[i], ci->cycle_port, P_READABLE, ci);
33606 		      port_write_string(ci->cycle_port)(sc, ") ", 2, ci->cycle_port);
33607 		    }}
33608 	      else
33609 		{
33610 		  port_write_character(port)(sc, ' ', port);
33611 		  object_to_port_with_circle_check(sc, els[i], port, P_READABLE, ci);
33612 		}}
33613 	  port_write_character(port)(sc, ')', port);
33614 	  if (vector_rank(vect) > 1)
33615 	    {
33616 	      plen = catstrs_direct(buf, " 0 ", pos_int_to_str_direct(sc, len), (const char *)NULL);
33617 	      port_write_string(port)(sc, buf, plen, port);
33618 	      write_vector_dimensions(sc, vect, port);
33619 	    }}
33620       else
33621 	{
33622 	  if (vector_rank(vect) > 1)
33623 	    port_write_string(port)(sc, "(subvector ", 11, port);
33624 
33625 	  if (is_immutable_vector(vect))
33626 	    port_write_string(port)(sc, "(immutable! ", 12, port);
33627 
33628 	  port_write_string(port)(sc, "(vector", 7, port);
33629 	  for (i = 0; i < len; i++)
33630 	    {
33631 	      port_write_character(port)(sc, ' ', port);
33632 	      object_to_port_with_circle_check(sc, vector_element(vect, i), port, P_READABLE, ci);
33633 	    }
33634 	  port_write_character(port)(sc, ')', port);
33635 	  if (is_immutable_vector(vect))
33636 	    port_write_character(port)(sc, ')', port);
33637 
33638 	  if (vector_rank(vect) > 1)
33639 	    {
33640 	      plen = catstrs_direct(buf, " 0 ", pos_int_to_str_direct(sc, len), (const char *)NULL);
33641 	      port_write_string(port)(sc, buf, plen, port);
33642 	      write_vector_dimensions(sc, vect, port);
33643 	    }}}
33644   else /* not readable write */
33645     {
33646       if (vector_rank(vect) > 1)
33647 	{
33648 	  bool last = false;
33649 	  if (vector_ndims(vect) > 1)
33650 	    {
33651 	      plen = catstrs_direct(buf, "#", pos_int_to_str_direct(sc, vector_ndims(vect)), "d", (const char *)NULL);
33652 	      port_write_string(port)(sc, buf, plen, port);
33653 	    }
33654 	  else port_write_character(port)(sc, '#', port);
33655 	  multivector_to_port(sc, vect, port, len, 0, 0, vector_ndims(vect), &last, use_write, ci);
33656 	}
33657       else
33658 	{
33659 	  port_write_string(port)(sc, "#(", 2, port);
33660 	  for (i = 0; i < len - 1; i++)
33661 	    {
33662 	      object_to_port_with_circle_check(sc, vector_element(vect, i), port, NOT_P_DISPLAY(use_write), ci);
33663 	      port_write_character(port)(sc, ' ', port);
33664 	    }
33665 	  object_to_port_with_circle_check(sc, vector_element(vect, i), port, NOT_P_DISPLAY(use_write), ci);
33666 
33667 	  if (too_long)
33668 	    port_write_string(port)(sc, " ...)", 5, port);
33669 	  else port_write_character(port)(sc, ')', port);
33670 	}}
33671   unstack(sc);
33672 }
33673 
33674 static int32_t print_vector_length(s7_scheme *sc, s7_pointer vect, s7_pointer port, use_write_t use_write)
33675 {
33676   int32_t len, plen;
33677   char buf[128];
33678   const char *vtype = "r";
33679 
33680   if (is_int_vector(vect))
33681     vtype = "i";
33682   else
33683     if (is_byte_vector(vect))
33684       vtype = "u";
33685 
33686   len = vector_length(vect);
33687   if (len == 0)
33688     {
33689       if (vector_rank(vect) > 1)
33690 	plen = catstrs_direct(buf, "#", vtype, pos_int_to_str_direct(sc, vector_ndims(vect)), "d()", (const char *)(const char *)NULL);
33691       else plen = catstrs_direct(buf, "#", vtype, "()", (const char *)NULL);
33692       port_write_string(port)(sc, buf, plen, port);
33693       return(-1);
33694     }
33695 
33696   if (use_write == P_READABLE)
33697     return(len);
33698 
33699   if (sc->print_length == 0)
33700     {
33701       if (vector_rank(vect) > 1)
33702 	{
33703 	  plen = catstrs_direct(buf, "#", vtype, pos_int_to_str_direct(sc, vector_ndims(vect)), "d(...)", (const char *)NULL);
33704 	  port_write_string(port)(sc, buf, plen, port);
33705 	}
33706       else
33707 	{
33708 	  if (is_int_vector(vect))
33709 	    port_write_string(port)(sc, "#i(...)", 7, port);
33710 	  else
33711 	    {
33712 	      if (is_float_vector(vect))
33713 		port_write_string(port)(sc, "#r(...)", 7, port);
33714 	      else port_write_string(port)(sc, "#u(...)", 7, port);
33715 	    }}
33716       return(-1);
33717     }
33718   return((len > sc->print_length) ? sc->print_length : len);
33719 }
33720 
33721 static void int_vector_to_port(s7_scheme *sc, s7_pointer vect, s7_pointer port, use_write_t use_write, shared_info_t *ignored)
33722 {
33723   s7_int i, len, plen;
33724   bool too_long;
33725   char buf[128];
33726   char *p;
33727 
33728   len = print_vector_length(sc, vect, port, use_write);
33729   if (len < 0) return;
33730   too_long = (len < vector_length(vect));
33731 
33732   if ((use_write == P_READABLE) &&
33733       (is_immutable_vector(vect)))
33734     port_write_string(port)(sc, "(immutable! ", 12, port);
33735 
33736   if (len > 1000)
33737     {
33738       s7_int vlen;
33739       s7_int first;
33740       s7_int *els;
33741       vlen = vector_length(vect);
33742       els = int_vector_ints(vect);
33743       first = els[0];
33744       for (i = 1; i < vlen; i++)
33745 	if (els[i] != first)
33746 	  break;
33747       if (i == vlen)
33748 	{
33749 	  make_vector_to_port(sc, vect, port);
33750 	  p = integer_to_string(sc, int_vector(vect, 0), &plen);
33751 	  port_write_string(port)(sc, p, plen, port);
33752 	  port_write_character(port)(sc, ')', port);
33753 	  if ((use_write == P_READABLE) &&
33754 	      (is_immutable_vector(vect)))
33755 	    port_write_character(port)(sc, ')', port);
33756 	  return;
33757 	}}
33758 
33759   if (vector_rank(vect) == 1)
33760     {
33761       port_write_string(port)(sc, "#i(", 3, port);
33762       if (!is_string_port(port))
33763 	{
33764 	  p = integer_to_string(sc, int_vector(vect, 0), &plen);
33765 	  port_write_string(port)(sc, p, plen, port);
33766 	  for (i = 1; i < len; i++)
33767 	    {
33768 	      plen = catstrs_direct(buf, " ", integer_to_string_no_length(sc, int_vector(vect, i)), (const char *)NULL);
33769 	      port_write_string(port)(sc, buf, plen, port);
33770 	    }}
33771       else
33772 	{
33773 	  s7_int new_len, next_len;
33774 	  uint8_t *dbuf;
33775 	  new_len = port_position(port);
33776 	  next_len = port_data_size(port) - 128;
33777 	  dbuf = port_data(port);
33778 
33779 	  if (new_len >= next_len)
33780 	    {
33781 	      resize_port_data(sc, port, port_data_size(port) * 2);
33782 	      next_len = port_data_size(port) - 128;
33783 	      dbuf = port_data(port);
33784 	    }
33785 	  p = integer_to_string(sc, int_vector(vect, 0), &plen);
33786 	  memcpy((void *)(dbuf + new_len), (void *)p, plen);
33787 	  new_len += plen;
33788 	  for (i = 1; i < len; i++)
33789 	    {
33790 	      if (new_len >= next_len)
33791 		{
33792 		  resize_port_data(sc, port, port_data_size(port) * 2);
33793 		  next_len = port_data_size(port) - 128;
33794 		  dbuf = port_data(port);
33795 		}
33796 	      plen = catstrs_direct((char *)(dbuf + new_len), " ", integer_to_string_no_length(sc, int_vector(vect, i)), (const char *)NULL);
33797 	      new_len += plen;
33798 	    }
33799 	  port_position(port) = new_len;
33800 	}
33801 
33802       if (too_long)
33803 	port_write_string(port)(sc, " ...)", 5, port);
33804       else port_write_character(port)(sc, ')', port);
33805     }
33806   else
33807     {
33808       bool last = false;
33809       plen = catstrs_direct(buf, "#i", pos_int_to_str_direct(sc, vector_ndims(vect)), "d", (const char *)NULL);
33810       port_write_string(port)(sc, buf, plen, port);
33811       push_stack_no_let_no_code(sc, OP_GC_PROTECT, vect);
33812       multivector_to_port(sc, vect, port, len, 0, 0, vector_ndims(vect), &last, P_DISPLAY, NULL);
33813       unstack(sc);
33814     }
33815 
33816   if ((use_write == P_READABLE) &&
33817       (is_immutable_vector(vect)))
33818     port_write_character(port)(sc, ')', port);
33819 }
33820 
33821 static void float_vector_to_port(s7_scheme *sc, s7_pointer vect, s7_pointer port, use_write_t use_write, shared_info_t *ignored)
33822 {
33823   s7_int i, len, plen;
33824   bool too_long;
33825   #define FV_BUFSIZE 256
33826   char buf[FV_BUFSIZE];
33827   s7_double *els;
33828 
33829   len = print_vector_length(sc, vect, port, use_write);
33830   if (len < 0) return;
33831   too_long = (len < vector_length(vect));
33832   els = float_vector_floats(vect);
33833 
33834   if ((use_write == P_READABLE) &&
33835       (is_immutable_vector(vect)))
33836     port_write_string(port)(sc, "(immutable! ", 12, port);
33837 
33838   if (len > 1000)
33839     {
33840       s7_int vlen;
33841       s7_double first;
33842       vlen = vector_length(vect);
33843       first = els[0];
33844       for (i = 1; i < vlen; i++)
33845 	if (els[i] != first)
33846 	  break;
33847       if (i == vlen)
33848 	{
33849 	  make_vector_to_port(sc, vect, port);
33850 	  plen = snprintf(buf, FV_BUFSIZE, "%.*g)", sc->float_format_precision, first);
33851 	  port_write_string(port)(sc, buf, plen, port);
33852 	  if ((use_write == P_READABLE) &&
33853 	      (is_immutable_vector(vect)))
33854 	    port_write_character(port)(sc, ')', port);
33855 	  return;
33856 	}}
33857 
33858   if (vector_rank(vect) == 1)
33859     {
33860       port_write_string(port)(sc, "#r(", 3, port);
33861       plen = snprintf(buf, FV_BUFSIZE - 4, "%.*g", sc->float_format_precision, els[0]); /* -4 so floatify has room */
33862       floatify(buf, &plen);
33863       port_write_string(port)(sc, buf, plen, port);
33864       for (i = 1; i < len; i++)
33865 	{
33866 	  plen = snprintf(buf, FV_BUFSIZE - 4, " %.*g", sc->float_format_precision, els[i]);
33867 	  plen--; /* fixup for the initial #\space */
33868 	  floatify((char *)(buf + 1), &plen);
33869 	  port_write_string(port)(sc, buf, plen + 1, port);
33870 	}
33871       if (too_long)
33872 	port_write_string(port)(sc, " ...)", 5, port);
33873       else port_write_character(port)(sc, ')', port);
33874     }
33875   else
33876     {
33877       bool last = false;
33878       plen = catstrs_direct(buf, "#r", pos_int_to_str_direct(sc, vector_ndims(vect)), "d", (const char *)NULL);
33879       port_write_string(port)(sc, buf, plen, port);
33880       push_stack_no_let_no_code(sc, OP_GC_PROTECT, vect);
33881       multivector_to_port(sc, vect, port, len, 0, 0, vector_ndims(vect), &last, P_DISPLAY, NULL);
33882       unstack(sc);
33883     }
33884 
33885   if ((use_write == P_READABLE) &&
33886       (is_immutable_vector(vect)))
33887     port_write_character(port)(sc, ')', port);
33888 }
33889 
33890 static void byte_vector_to_port(s7_scheme *sc, s7_pointer vect, s7_pointer port, use_write_t use_write, shared_info_t *ignored)
33891 {
33892   s7_int i, len, plen;
33893   bool too_long;
33894   char buf[128];
33895   char *p;
33896 
33897   len = print_vector_length(sc, vect, port, use_write);
33898   if (len < 0) return;
33899   too_long = (len < vector_length(vect));
33900 
33901   if ((use_write == P_READABLE) &&
33902       (is_immutable_vector(vect)))
33903     port_write_string(port)(sc, "(immutable! ", 12, port);
33904 
33905   if (len > 1000)
33906     {
33907       s7_int vlen;
33908       uint8_t first;
33909       uint8_t *els;
33910       vlen = vector_length(vect);
33911       els = byte_vector_bytes(vect);
33912       first = els[0];
33913       for (i = 1; i < vlen; i++)
33914 	if (els[i] != first)
33915 	  break;
33916       if (i == vlen)
33917 	{
33918 	  make_vector_to_port(sc, vect, port);
33919 	  p = integer_to_string(sc, byte_vector(vect, 0), &plen);
33920 	  port_write_string(port)(sc, p, plen, port);
33921 	  port_write_character(port)(sc, ')', port);
33922 	  if ((use_write == P_READABLE) &&
33923 	      (is_immutable_vector(vect)))
33924 	    port_write_character(port)(sc, ')', port);
33925 	  return;
33926 	}}
33927 
33928   if (vector_rank(vect) == 1)
33929     {
33930       port_write_string(port)(sc, "#u(", 3, port);
33931       p = integer_to_string(sc, byte_vector(vect, 0), &plen);
33932       port_write_string(port)(sc, p, plen, port);
33933       for (i = 1; i < len; i++)
33934 	{
33935 	  plen = catstrs_direct(buf, " ", integer_to_string_no_length(sc, byte_vector(vect, i)), (const char *)NULL);
33936 	  port_write_string(port)(sc, buf, plen, port);
33937 	}
33938       if (too_long)
33939 	port_write_string(port)(sc, " ...)", 5, port);
33940       else port_write_character(port)(sc, ')', port);
33941     }
33942   else
33943     {
33944       bool last = false;
33945       plen = catstrs_direct(buf, "#u", pos_int_to_str_direct(sc, vector_ndims(vect)), "d", (const char *)NULL);
33946       port_write_string(port)(sc, buf, plen, port);
33947       multivector_to_port(sc, vect, port, len, 0, 0, vector_ndims(vect), &last, P_DISPLAY, NULL);
33948     }
33949 
33950   if ((use_write == P_READABLE) &&
33951       (is_immutable_vector(vect)))
33952     port_write_character(port)(sc, ')', port);
33953 }
33954 
33955 static void string_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ignored)
33956 {
33957   bool immutable;
33958   immutable = ((use_write == P_READABLE) &&
33959 	       (is_immutable_string(obj)) &&
33960 	       (string_length(obj) > 0));  /* (immutable "") looks dumb */
33961   if (immutable)
33962     port_write_string(port)(sc, "(immutable! ", 12, port);
33963 
33964   if (string_length(obj) > 0)
33965     {
33966       /* since string_length is a scheme length, not C, this write can embed nulls from C's point of view */
33967       if (string_length(obj) > 1000) /* was 10000 28-Feb-18 */
33968 	{
33969 	  size_t size;
33970 	  char buf[128];
33971 	  buf[0] = string_value(obj)[0];
33972 	  buf[1] = '\0';
33973 	  size = strspn((const char *)(string_value(obj) + 1), buf); /* if all #\null, this won't work */
33974 	  if (size == (size_t)(string_length(obj) - 1))
33975 	    {
33976 	      int32_t nlen;
33977 	      s7_pointer c;
33978 	      c = chars[(int32_t)((uint8_t)(buf[0]))];
33979 	      nlen = catstrs_direct(buf, "(make-string ", pos_int_to_str_direct(sc, string_length(obj)), " ", (const char *)NULL);
33980 	      port_write_string(port)(sc, buf, nlen, port);
33981 	      port_write_string(port)(sc, character_name(c), character_name_length(c), port);
33982 	      port_write_character(port)(sc, ')', port);
33983 	      if (immutable)
33984 		port_write_character(port)(sc, ')', port);
33985 	      return;
33986 	    }}
33987       if (use_write == P_DISPLAY)
33988 	port_write_string(port)(sc, string_value(obj), string_length(obj), port);
33989       else
33990 	{
33991 	  if (!string_needs_slashification(string_value(obj), string_length(obj)))
33992 	    {
33993 	      port_write_character(port)(sc, '"', port);
33994 	      port_write_string(port)(sc, string_value(obj), string_length(obj), port);
33995 	      port_write_character(port)(sc, '"', port);
33996 	    }
33997 	  else slashify_string_to_port(sc, port, string_value(obj), string_length(obj), IN_QUOTES);
33998 	}}
33999   else
34000     if (use_write != P_DISPLAY)
34001       port_write_string(port)(sc, "\"\"", 2, port);
34002 
34003   if (immutable)
34004     port_write_character(port)(sc, ')', port);
34005 }
34006 
34007 static void simple_list_readable_display(s7_scheme *sc, s7_pointer lst, s7_int true_len, s7_int len, s7_pointer port, shared_info_t *ci)
34008 {
34009   /* the easier cases: no circles or shared refs to patch up */
34010   s7_pointer x;
34011 
34012   if (is_immutable(lst))
34013     port_write_string(port)(sc, "immutable! (", 12, port);
34014 
34015   if (true_len > 0)
34016     {
34017       port_write_string(port)(sc, "list", 4, port);
34018       for (x = lst; is_pair(x); x = cdr(x))
34019 	{
34020 	  port_write_character(port)(sc, ' ', port);
34021 	  object_to_port_with_circle_check(sc, car(x), port, P_READABLE, ci);
34022 	}
34023       port_write_character(port)(sc, ')', port);
34024     }
34025   else
34026     {
34027       s7_int i;
34028       port_write_string(port)(sc, "cons ", 5, port);
34029       object_to_port_with_circle_check(sc, car(lst), port, P_READABLE, ci);
34030       for (x = cdr(lst); is_pair(x); x = cdr(x))
34031 	{
34032 	  port_write_string(port)(sc, " (cons ", 7, port);
34033 	  object_to_port_with_circle_check(sc, car(x), port, P_READABLE, ci);
34034 	}
34035       port_write_character(port)(sc, ' ', port);
34036       object_to_port_with_circle_check(sc, x, port, P_READABLE, ci);
34037       for (i = 1; i < len; i++)
34038 	port_write_character(port)(sc, ')', port);
34039     }
34040   if (is_immutable(lst))
34041     port_write_character(port)(sc, ')', port);
34042 }
34043 
34044 static void pair_to_port(s7_scheme *sc, s7_pointer lst, s7_pointer port, use_write_t use_write, shared_info_t *ci)
34045 {
34046   s7_pointer x;
34047   s7_int i, len, true_len;
34048 
34049   true_len = s7_list_length(sc, lst);
34050   if (true_len < 0)                    /* a dotted list -- handle cars, then final cdr */
34051     len = (-true_len + 1);
34052   else len = (true_len == 0) ? circular_list_entries(lst) : true_len; /* circular list (nil is handled by unique_to_port) */
34053 
34054   if ((use_write == P_READABLE) &&
34055       (ci))
34056     {
34057       int32_t href;
34058       href = peek_shared_ref(ci, lst);
34059       if (href != 0)
34060 	{
34061 	  if (href < 0) href = -href;
34062 	  if ((ci->defined[href]) || (port == ci->cycle_port))
34063 	    {
34064 	      char buf[128];
34065 	      int32_t plen;
34066 	      plen = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, href), ">", (const char *)NULL);
34067 	      port_write_string(port)(sc, buf, plen, port);
34068 	      return;
34069 	    }}}
34070 
34071   if ((use_write != P_READABLE) &&
34072       (car(lst) == sc->quote_symbol) &&
34073       (true_len == 2))
34074     {
34075       /* len == 1 is important, otherwise (list 'quote 1 2) -> '1 2 which looks weird
34076        *   or (object->string (apply . `''1)) -> "'quote 1"
34077        * so (quote x) = 'x but (quote x y z) should be left alone (if evaluated, it's an error)
34078        * :readable is tricky because the list might be something like (list 'quote (lambda () #f)) which needs to be evalable back to its original
34079        */
34080       port_write_character(port)(sc, '\'', port);
34081       object_to_port_with_circle_check(sc, cadr(lst), port, P_WRITE, ci);
34082       return;
34083     }
34084 
34085   port_write_character(port)(sc, '(', port);
34086   if (is_multiple_value(lst))
34087     port_write_string(port)(sc, "values ", 7, port);
34088 
34089   check_stack_size(sc);
34090   push_stack_no_let_no_code(sc, OP_GC_PROTECT, lst);
34091   /* (define (f) (display (make-list 1001 (mock-string #\h #\o #\h #\o))) (newline)) (do ((i 0 (+ i 1))) ((= i 1000)) (f)) */
34092 
34093   if (use_write == P_READABLE)
34094     {
34095       if (!is_cyclic(lst))
34096 	{
34097 	  simple_list_readable_display(sc, lst, true_len, len, port, ci);
34098 	  unstack(sc);
34099 	  return;
34100 	}
34101       if (ci)
34102 	{
34103 	  int32_t plen;
34104 	  char buf[128], lst_name[128];
34105 	  int32_t lst_ref;
34106 	  bool lst_local = false;
34107 	  s7_pointer local_port;
34108 
34109 	  lst_ref = peek_shared_ref(ci, lst);
34110 	  if (lst_ref == 0)
34111 	    {
34112 	      s7_pointer p;
34113 	      for (p = lst; is_pair(p); p = cdr(p))
34114 		if ((has_structure(car(p))) ||
34115 		    ((is_pair(cdr(p))) &&
34116 		     (peek_shared_ref(ci, cdr(p)) != 0)))
34117 		  {
34118 		    lst_name[0] = '<'; lst_name[1] = 'L'; lst_name[2] = '>'; lst_name[3] = '\0';
34119 		    lst_local = true;
34120 		    port_write_string(port)(sc, "let ((<L> (list", 15, port); /* '(' above */
34121 		    break;
34122 		  }
34123 	      if (!lst_local)
34124 		{
34125 		  if (has_structure(p))
34126 		    {
34127 		      lst_name[0] = '<'; lst_name[1] = 'L'; lst_name[2] = '>'; lst_name[3] = '\0';
34128 		      lst_local = true;
34129 		      port_write_string(port)(sc, "let ((<L> (list", 15, port); /* '(' above */
34130 		    }
34131 		  else
34132 		    {
34133 		      simple_list_readable_display(sc, lst, true_len, len, port, ci);
34134 		      unstack(sc);
34135 		      return;
34136 		    }}}
34137 	  else
34138 	    {
34139 	      if (lst_ref < 0) lst_ref = -lst_ref;
34140 	      catstrs_direct(lst_name, "<", pos_int_to_str_direct(sc, lst_ref), ">", (const char *)NULL);
34141 	      port_write_string(port)(sc, "list", 4, port); /* '(' above */
34142 	    }
34143 
34144 	  for (i = 0, x = lst; (i < len) && (is_pair(x)); x = cdr(x), i++)
34145 	    {
34146 	      if ((has_structure(car(x))) &&
34147 		  (is_cyclic(car(x))))
34148 		port_write_string(port)(sc, " #f", 3, port);
34149 	      else
34150 		{
34151 		  port_write_character(port)(sc, ' ', port);
34152 		  object_to_port_with_circle_check(sc, car(x), port, use_write, ci);
34153 		}
34154 	      if ((is_pair(cdr(x))) &&
34155 		  (peek_shared_ref(ci, cdr(x)) != 0))
34156 		break;
34157 	    }
34158 
34159 	  if (lst_local)
34160 	    port_write_string(port)(sc, "))) ", 4, port);
34161 	  else port_write_character(port)(sc, ')', port);
34162 
34163 	  /* fill in the cyclic entries */
34164 	  local_port = ((lst_local) || (ci->cycle_port == sc->F)) ? port : ci->cycle_port; /* (object->string (list-values `(x . 1) (signature (int-vector))) :readable) */
34165 	  for (x = lst, i = 0; (i < len) && (is_pair(x)); x = cdr(x), i++)
34166 	    {
34167 	      int32_t lref;
34168 	      if ((has_structure(car(x))) &&
34169 		  (is_cyclic(car(x))))
34170 		{
34171 		  if (i == 0)
34172 		    plen = catstrs_direct(buf, "  (set-car! ", lst_name, " ", (const char *)NULL);
34173 		  else plen = catstrs_direct(buf, "  (set! (", lst_name, " ", pos_int_to_str_direct(sc, i), ") ", (const char *)NULL);
34174 		  port_write_string(local_port)(sc, buf, plen, local_port);
34175 		  lref = peek_shared_ref(ci, car(x));
34176 		  if (lref == 0)
34177 		    object_to_port_with_circle_check(sc, car(x), local_port, use_write, ci);
34178 		  else
34179 		    {
34180 		      if (lref < 0) lref = -lref;
34181 		      plen = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, lref), ">", (const char *)NULL);
34182 		      port_write_string(local_port)(sc, buf, plen, local_port);
34183 		    }
34184 		  port_write_string(local_port)(sc, ") ", 2, local_port);
34185 		}
34186 	      if ((is_pair(cdr(x))) &&
34187 		  ((lref = peek_shared_ref(ci, cdr(x))) != 0))
34188 		{
34189 		  if (lref < 0) lref = -lref;
34190 		  if (i == 0)
34191 		    plen = catstrs_direct(buf, (lst_local) ? "    " : "  ", "(set-cdr! ", lst_name, " <", pos_int_to_str_direct(sc, lref), ">) ", (const char *)NULL);
34192 		  else
34193 		    {
34194 		      if (i == 1)
34195 			plen = catstrs_direct(buf, (lst_local) ? "    " : "  ", "(set-cdr! (cdr ", lst_name, ") <", pos_int_to_str_direct(sc, lref), ">) ", (const char *)NULL);
34196 		      else plen = catstrs_direct(buf, (lst_local) ? "    " : "  ",
34197 						 "(set-cdr! (list-tail ", lst_name, " ", pos_int_to_str_direct_1(sc, i),
34198 						 ") <", pos_int_to_str_direct(sc, lref), ">) ", (const char *)NULL);
34199 		    }
34200 		  port_write_string(local_port)(sc, buf, plen, local_port);
34201 		  break;
34202 		}}
34203 	  if (true_len < 0) /* dotted list */
34204 	    {
34205 	      s7_pointer end_x;
34206 	      for (end_x = lst; is_pair(end_x); end_x = cdr(end_x)); /* or maybe faster, start at x? */
34207 	      /* we can't depend on the loops above to set x to the last element because they sometimes break out */
34208 	      if (true_len == -1) /* cons cell */
34209 		plen = catstrs_direct(buf, (lst_local) ? "    " : "  ", "(set-cdr! ", lst_name, " ", (const char *)NULL);
34210 	      else
34211 		{
34212 		  if (true_len == -2)
34213 		    plen = catstrs_direct(buf, (lst_local) ? "    " : "  ", "(set-cdr! (cdr ", lst_name, ") ", (const char *)NULL);
34214 		  else plen = catstrs_direct(buf, "(set-cdr! (list-tail ", lst_name, " ", pos_int_to_str_direct(sc, len - 2), ") ", (const char *)NULL);
34215 		}
34216 	      port_write_string(local_port)(sc, buf, plen, local_port);
34217 	      object_to_port_with_circle_check(sc, end_x, local_port, use_write, ci);
34218 	      port_write_string(local_port)(sc, ") ", 2, local_port);
34219 	    }
34220 
34221 	  if (lst_local)
34222 	    port_write_string(local_port)(sc, "    <L>)", 8, local_port);
34223 	}
34224       else simple_list_readable_display(sc, lst, true_len, len, port, ci);
34225     }
34226   else /* not :readable */
34227     {
34228       s7_int plen;
34229       plen = (len > sc->print_length) ? sc->print_length : len;
34230       if (plen <= 0)
34231 	{
34232 	  port_write_string(port)(sc, "(...))", 6, port); /* open paren above about 150 lines, "list" here is wrong if it's a cons */
34233 	  unstack(sc);
34234 	  return;
34235 	}
34236 
34237       if (ci)
34238 	{
34239 	  for (x = lst, i = 0; (is_pair(x)) && (i < plen) && ((i == 0) || (peek_shared_ref(ci, x) == 0)); i++, x = cdr(x))
34240 	    {
34241 	      object_to_port_with_circle_check(sc, car(x), port, NOT_P_DISPLAY(use_write), ci);
34242 	      if (i < (len - 1))
34243 		port_write_character(port)(sc, ' ', port);
34244 	    }
34245 	  if (is_not_null(x))
34246 	    {
34247 	      if (plen < len)
34248 		port_write_string(port)(sc, " ...", 4, port);
34249 	      else
34250 		{
34251 		  if ((true_len == 0) &&
34252 		      (i == len))
34253 		    port_write_string(port)(sc, " . ", 3, port);
34254 		  else port_write_string(port)(sc, ". ", 2, port);
34255 		  object_to_port_with_circle_check(sc, x, port, NOT_P_DISPLAY(use_write), ci);
34256 		}}
34257 	  port_write_character(port)(sc, ')', port);
34258 	}
34259       else
34260 	{
34261 	  s7_int len1;
34262 	  len1 = plen - 1;
34263 	  if (is_string_port(port))
34264 	    {
34265 	      for (x = lst, i = 0; (is_pair(x)) && (i < len1); i++, x = cdr(x))
34266 		{
34267 		  object_to_port(sc, car(x), port, NOT_P_DISPLAY(use_write), ci);
34268 		  if (port_position(port) >= sc->objstr_max_len)
34269 		    {
34270 		      unstack(sc);
34271 		      return;
34272 		    }
34273 		  if (port_position(port) >= port_data_size(port))
34274 		    resize_port_data(sc, port, port_data_size(port) * 2);
34275 		  port_data(port)[port_position(port)++] = (uint8_t)' ';
34276 		}}
34277 	  else
34278 	    for (x = lst, i = 0; (is_pair(x)) && (i < len1); i++, x = cdr(x))
34279 	      {
34280 		object_to_port(sc, car(x), port, NOT_P_DISPLAY(use_write), ci);
34281 		port_write_character(port)(sc, ' ', port);
34282 	      }
34283 	  if (is_pair(x))
34284 	    {
34285 	      object_to_port(sc, car(x), port, NOT_P_DISPLAY(use_write), ci);
34286 	      x = cdr(x);
34287 	    }
34288 	  if (is_not_null(x))
34289 	    {
34290 	      if (plen < len)
34291 		port_write_string(port)(sc, " ...", 4, port);
34292 	      else
34293 		{
34294 		  port_write_string(port)(sc, ". ", 2, port);
34295 		  object_to_port(sc, x, port, NOT_P_DISPLAY(use_write), ci);
34296 		}}
34297 	  port_write_character(port)(sc, ')', port);
34298 	}}
34299   unstack(sc);
34300 }
34301 
34302 static void hash_table_to_port(s7_scheme *sc, s7_pointer hash, s7_pointer port, use_write_t use_write, shared_info_t *ci)
34303 {
34304   s7_int i, len, gc_iter;
34305   bool too_long = false;
34306   s7_pointer iterator, p;
34307   int32_t href;
34308 
34309   /* if hash is a member of ci, just print its number
34310    * (let ((ht (hash-table '(a . 1)))) (hash-table-set! ht 'b ht))
34311    *
34312    * since equal? does not care about the hash-table lengths, we can ignore that complication in the :readable case
34313    * there's no way to make a truly :readable version of a weak hash-table (or a normal hash-table that uses eq? with pairs, for example)
34314    */
34315   len = hash_table_entries(hash);
34316   if (len == 0)
34317     {
34318       if (is_weak_hash_table(hash))
34319 	port_write_string(port)(sc, "(weak-hash-table)", 17, port);
34320       else port_write_string(port)(sc, "(hash-table)", 12, port);
34321       return;
34322     }
34323 
34324   if (use_write != P_READABLE)
34325     {
34326       s7_int plen;
34327       plen = sc->print_length;
34328       if (plen <= 0)
34329 	{
34330 	  port_write_string(port)(sc, "(hash-table ...)", 16, port);
34331 	  return;
34332 	}
34333       if (len > plen)
34334 	{
34335 	  too_long = true;
34336 	  len = plen;
34337 	}}
34338 
34339   if ((use_write == P_READABLE) &&
34340       (ci))
34341     {
34342       href = peek_shared_ref(ci, hash);
34343       if (href != 0)
34344 	{
34345 	  if (href < 0) href = -href;
34346 	  if ((ci->defined[href]) || (port == ci->cycle_port))
34347 	    {
34348 	      char buf[128];
34349 	      int32_t plen;
34350 	      plen = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, href), ">", (const char *)NULL);
34351 	      port_write_string(port)(sc, buf, plen, port);
34352 	      return;
34353 	    }}}
34354 
34355   iterator = s7_make_iterator(sc, hash);
34356   gc_iter = s7_gc_protect_1(sc, iterator);
34357   p = cons(sc, sc->F, sc->F);
34358   iterator_current(iterator) = p;
34359   set_mark_seq(iterator);
34360 
34361   if ((use_write == P_READABLE) &&
34362       (is_immutable(hash)))
34363     port_write_string(port)(sc, "(immutable! ", 12, port);
34364 
34365   if ((use_write == P_READABLE) &&
34366       (ci) &&
34367       (is_cyclic(hash)) &&
34368       ((href = peek_shared_ref(ci, hash)) != 0))
34369     {
34370       if (href < 0) href = -href;
34371 
34372       if (is_weak_hash_table(hash))
34373 	port_write_string(port)(sc, "(weak-hash-table", 16, port);
34374       else port_write_string(port)(sc, "(hash-table", 11, port); /* top level let */
34375       for (i = 0; i < len; i++)
34376 	{
34377 	  s7_pointer key_val, key, val;
34378 
34379 	  key_val = hash_table_iterate(sc, iterator);
34380 	  key = car(key_val);
34381 	  val = cdr(key_val);
34382 	  if ((has_structure(val)) ||
34383 	      (has_structure(key)))
34384 	    {
34385 	      char buf[128];
34386 	      int32_t eref, kref, plen;
34387 	      eref = peek_shared_ref(ci, val);
34388 	      kref = peek_shared_ref(ci, key);
34389 	      plen = catstrs_direct(buf, "  (set! (<", pos_int_to_str_direct(sc, href), "> ", (const char *)NULL);
34390 	      port_write_string(ci->cycle_port)(sc, buf, plen, ci->cycle_port);
34391 
34392 	      if (kref != 0)
34393 		{
34394 		  if (kref < 0) kref = -kref;
34395 		  plen = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, kref), ">", (const char *)NULL);
34396 		  port_write_string(ci->cycle_port)(sc, buf, plen, ci->cycle_port);
34397 		}
34398 	      else object_to_port(sc, key, ci->cycle_port, P_READABLE, ci);
34399 
34400 	      if (eref != 0)
34401 		{
34402 		  if (eref < 0) eref = -eref;
34403 		  plen = catstrs_direct(buf, ") <", pos_int_to_str_direct(sc, eref), ">) ", (const char *)NULL);
34404 		  port_write_string(ci->cycle_port)(sc, buf, plen, ci->cycle_port);
34405 		}
34406 	      else
34407 		{
34408 		  port_write_string(ci->cycle_port)(sc, ") ", 2, ci->cycle_port);
34409 		  object_to_port_with_circle_check(sc, val, ci->cycle_port, P_READABLE, ci);
34410 		  port_write_string(ci->cycle_port)(sc, ") ", 2, ci->cycle_port);
34411 		}}
34412 	  else
34413 	    {
34414 	      port_write_character(port)(sc, ' ', port);
34415 	      object_to_port_with_circle_check(sc, key, port, P_READABLE, ci);
34416 	      port_write_character(port)(sc, ' ', port);
34417 	      object_to_port_with_circle_check(sc, val, port, P_READABLE, ci);
34418 	    }}
34419       port_write_character(port)(sc, ')', port);
34420     }
34421   else
34422     {
34423       if (is_weak_hash_table(hash))
34424 	port_write_string(port)(sc, "(weak-hash-table", 16, port);
34425       else port_write_string(port)(sc, "(hash-table", 11, port);
34426       for (i = 0; i < len; i++)
34427 	{
34428 	  s7_pointer key_val;
34429 	  port_write_character(port)(sc, ' ', port);
34430 	  key_val = hash_table_iterate(sc, iterator);
34431 	  if ((use_write != P_READABLE) &&
34432 	      (is_normal_symbol(car(key_val))))
34433 	    port_write_character(port)(sc, '\'', port);
34434 	  object_to_port_with_circle_check(sc, car(key_val), port, NOT_P_DISPLAY(use_write), ci);
34435 	  port_write_character(port)(sc, ' ', port);
34436 	  object_to_port_with_circle_check(sc, cdr(key_val), port, NOT_P_DISPLAY(use_write), ci);
34437 	}
34438       if (too_long)
34439 	port_write_string(port)(sc, " ...)", 5, port);
34440       else port_write_character(port)(sc, ')', port);
34441     }
34442 
34443   if ((use_write == P_READABLE) &&
34444       (is_immutable(hash)))
34445     port_write_character(port)(sc, ')', port);
34446 
34447   s7_gc_unprotect_at(sc, gc_iter);
34448   iterator_current(iterator) = sc->nil;
34449   free_cell(sc, p);  /* free_cell(sc, iterator); */ /* 18-Dec-18 removed */
34450 }
34451 
34452 static int32_t slot_to_port_1(s7_scheme *sc, s7_pointer x, s7_pointer port, use_write_t use_write, shared_info_t *ci, int32_t n)
34453 {
34454 #if S7_DEBUGGING
34455   if ((x) && (!is_slot(x))) fprintf(stderr, "%s: x is %s\n", __func__, s7_type_names[unchecked_type(x)]);
34456 #endif
34457   if (tis_slot(x))
34458     {
34459       n = slot_to_port_1(sc, next_slot(x), port, use_write, ci, n);
34460       if (n <= sc->print_length)
34461 	{
34462 	  port_write_character(port)(sc, ' ', port);
34463 	  object_to_port_with_circle_check(sc, x, port, use_write, ci);
34464 	}
34465       else
34466 	if (n == (sc->print_length + 1))
34467 	  port_write_string(port)(sc, " ...", 4, port);
34468     }
34469   return(n + 1);
34470 }
34471 
34472 static void funclet_slots_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
34473 {
34474   int32_t i;
34475   s7_pointer slot;
34476   for (i = 0, slot = let_slots(obj); tis_slot(slot); i++, slot = next_slot(slot))
34477     {
34478       port_write_character(port)(sc, ' ', port);
34479       object_to_port_with_circle_check(sc, slot, port, use_write, ci);
34480       if (i == (sc->print_length + 1))
34481 	{
34482 	  port_write_string(port)(sc, " ...", 4, port);
34483 	  break;
34484 	}}
34485 }
34486 
34487 static void slot_list_to_port(s7_scheme *sc, s7_pointer slot, s7_pointer port, shared_info_t *ci, bool bindings)
34488 {
34489   if (tis_slot(slot))
34490     {
34491       slot_list_to_port(sc, next_slot(slot), port, ci, bindings);
34492       if (bindings)
34493 	{
34494 	  if (tis_slot(next_slot(slot)))
34495 	    port_write_string(port)(sc, " (", 2, port);
34496 	  else port_write_character(port)(sc, '(', port);
34497 	}
34498       else port_write_character(port)(sc, ' ', port);
34499       symbol_to_port(sc, slot_symbol(slot), port, (bindings) ? P_DISPLAY : P_KEY, ci);  /* (object->string (inlet (symbol "(\")") 1) :readable) */
34500       port_write_character(port)(sc, ' ', port);
34501       object_to_port_with_circle_check(sc, slot_value(slot), port, P_READABLE, ci);
34502       if (bindings) port_write_character(port)(sc, ')', port);
34503     }
34504 }
34505 
34506 static void slot_list_to_port_with_cycle(s7_scheme *sc, s7_pointer obj, s7_pointer slot, s7_pointer port, shared_info_t *ci, bool bindings)
34507 {
34508   if (tis_slot(slot))
34509     {
34510       s7_pointer sym, val;
34511       slot_list_to_port_with_cycle(sc, obj, next_slot(slot), port, ci, bindings);
34512       sym = slot_symbol(slot);
34513       val = slot_value(slot);
34514 
34515       if (bindings)
34516 	{
34517 	  if (tis_slot(next_slot(slot)))
34518 	    port_write_string(port)(sc, " (", 2, port);
34519 	  else port_write_character(port)(sc, '(', port);
34520 	}
34521       else port_write_character(port)(sc, ' ', port);
34522       symbol_to_port(sc, sym, port, (bindings) ? P_DISPLAY : P_KEY, ci);
34523       if (has_structure(val))
34524 	{
34525 	  char buf[128];
34526 	  int32_t symref, len;
34527 	  port_write_string(port)(sc, " #f", 3, port);
34528 
34529 	  len = catstrs_direct(buf, "  (set! (<", pos_int_to_str_direct(sc, -peek_shared_ref(ci, obj)), "> ", (const char *)NULL);
34530 	  port_write_string(ci->cycle_port)(sc, buf, len, ci->cycle_port);
34531 	  symbol_to_port(sc, sym, ci->cycle_port, P_KEY, ci);
34532 
34533 	  symref = peek_shared_ref(ci, val);
34534 	  if (symref != 0)
34535 	    {
34536 	      if (symref < 0) symref = -symref;
34537 	      len = catstrs_direct(buf, ") <", pos_int_to_str_direct(sc, symref), ">) ", (const char *)NULL);
34538 	      port_write_string(ci->cycle_port)(sc, buf, len, ci->cycle_port);
34539 	    }
34540 	  else
34541 	    {
34542 	      port_write_string(ci->cycle_port)(sc, ") ", 2, ci->cycle_port);
34543 	      object_to_port_with_circle_check(sc, val, ci->cycle_port, P_READABLE, ci);
34544 	      port_write_string(ci->cycle_port)(sc, ") ", 2, ci->cycle_port);
34545 	    }}
34546       else
34547 	{
34548 	  port_write_character(port)(sc, ' ', port);
34549 	  object_to_port_with_circle_check(sc, val, port, P_READABLE, ci);
34550 	}
34551       if (bindings) port_write_character(port)(sc, ')', port);
34552       if (is_immutable(obj))
34553 	{
34554 	  char buf[128];
34555 	  int32_t len;
34556 	  len = catstrs_direct(buf, "  (immutable! <", pos_int_to_str_direct(sc, -peek_shared_ref(ci, obj)), ">) ", (const char *)NULL);
34557 	  port_write_string(ci->cycle_port)(sc, buf, len, ci->cycle_port);
34558 	}}
34559 }
34560 
34561 static bool let_has_setter(s7_pointer obj)
34562 {
34563   s7_pointer slot;
34564   for (slot = let_slots(obj); tis_slot(slot); slot = next_slot(slot))
34565     if (slot_has_setter(slot))
34566       return(true);
34567   return(false);
34568 }
34569 
34570 static void slot_setters_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, shared_info_t *ci)
34571 {
34572   s7_pointer slot;
34573   for (slot = let_slots(obj); tis_slot(slot); slot = next_slot(slot))
34574     if (slot_has_setter(slot))
34575       {
34576 	port_write_string(port)(sc, "(set! (setter '", 15, port);
34577 	symbol_to_port(sc, slot_symbol(slot), port, P_DISPLAY, ci);
34578 	port_write_string(port)(sc, ") ", 2, port);
34579 	object_to_port_with_circle_check(sc, slot_setter(slot), port, P_READABLE, ci);
34580 	port_write_character(port)(sc, ')', port);
34581       }
34582 }
34583 
34584 static void let_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
34585 {
34586   /* if outer env points to (say) method list, the object needs to specialize object->string itself */
34587   if (has_active_methods(sc, obj))
34588     {
34589       s7_pointer print_func;
34590       print_func = find_method(sc, obj, sc->object_to_string_symbol);
34591       if (print_func != sc->undefined)
34592 	{
34593 	  s7_pointer p;
34594 	  /* what needs to be protected here? for one, the function might not return a string! */
34595 
34596 	  clear_has_methods(obj);
34597 	  if (use_write == P_WRITE)
34598 	    p = call_method(sc, obj, print_func, set_plist_1(sc, obj));
34599 	  else p = call_method(sc, obj, print_func, set_plist_2(sc, obj, (use_write == P_DISPLAY) ? sc->F : sc->key_readable_symbol));
34600 	  set_has_methods(obj);
34601 
34602 	  if ((is_string(p)) &&
34603 	      (string_length(p) > 0))
34604 	    port_write_string(port)(sc, string_value(p), string_length(p), port);
34605 	  return;
34606 	}}
34607 
34608   if (obj == sc->rootlet)
34609     port_write_string(port)(sc, "(rootlet)", 9, port);
34610   else
34611     {
34612       if (obj == sc->s7_let)
34613 	port_write_string(port)(sc, "*s7*", 4, port);
34614       else
34615 	{
34616 	  if (sc->short_print)
34617 	    port_write_string(port)(sc, "#<let>", 6, port);
34618 	  else
34619 	    {
34620 	      /* circles can happen here:
34621 	       *    (let () (let ((b (curlet))) (curlet))):    #<let 'b #<let>>
34622 	       * or (let ((b #f)) (set! b (curlet)) (curlet)): #1=#<let 'b #1#>
34623 	       */
34624 	      if (use_write == P_READABLE)
34625 		{
34626 		  int32_t lref;
34627 		  if ((ci) &&
34628 		      (is_cyclic(obj)) &&
34629 		      ((lref = peek_shared_ref(ci, obj)) != 0))
34630 		    {
34631 		      if (lref < 0) lref = -lref;
34632 		      if ((ci->defined[lref]) || (port == ci->cycle_port))
34633 			{
34634 			  char buf[128];
34635 			  int32_t len;
34636 			  len = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, lref), ">", (const char *)NULL);
34637 			  port_write_string(ci->cycle_port)(sc, buf, len, ci->cycle_port);
34638 			  return;
34639 			}
34640 		      if ((let_outlet(obj) != sc->nil) &&
34641 			  (let_outlet(obj) != sc->rootlet))
34642 			{
34643 			  char buf[128];
34644 			  int32_t len;
34645 			  len = catstrs_direct(buf, "  (set! (outlet <", pos_int_to_str_direct(sc, lref), ">) ", (const char *)NULL);
34646 			  port_write_string(ci->cycle_port)(sc, buf, len, ci->cycle_port);
34647 			  let_to_port(sc, let_outlet(obj), ci->cycle_port, use_write, ci);
34648 			  port_write_string(ci->cycle_port)(sc, ") ", 2, ci->cycle_port);
34649 			}
34650 		      if (has_methods(obj))
34651 			port_write_string(port)(sc, "(openlet ", 9, port);
34652 		      /* not immutable here because we'll need to set the let fields below, then declare it immutable */
34653 		      if (let_has_setter(obj))
34654 			{
34655 			  port_write_string(port)(sc, "(let (", 6, port);
34656 			  slot_list_to_port_with_cycle(sc, obj, let_slots(obj), port, ci, true);
34657 			  port_write_string(port)(sc, ") ", 2, port);
34658 			  slot_setters_to_port(sc, obj, port, ci);
34659 			  port_write_string(port)(sc, " (curlet))", 10, port);
34660 			}
34661 		      else
34662 			{
34663 			  port_write_string(port)(sc, "(inlet", 6, port);
34664 			  slot_list_to_port_with_cycle(sc, obj, let_slots(obj), port, ci, false);
34665 			  port_write_character(port)(sc, ')', port);
34666 			}
34667 		      if (has_methods(obj))
34668 			port_write_character(port)(sc, ')', port);
34669 		    }
34670 		  else
34671 		    {
34672 		      if (has_methods(obj))
34673 			port_write_string(port)(sc, "(openlet ", 9, port);
34674 		      if (is_immutable(obj))
34675 			port_write_string(port)(sc, "(immutable! ", 12, port);
34676 
34677 		      /* this ignores outlet -- but is that a problem? */
34678 		      /* (object->string (let ((i 0)) (set! (setter 'i) integer?) (curlet)) :readable) -> "(let ((i 0)) (set! (setter 'i) #_integer?) (curlet))" */
34679 		      if (let_has_setter(obj))
34680 			{
34681 			  port_write_string(port)(sc, "(let (", 6, port);
34682 			  slot_list_to_port(sc, let_slots(obj), port, ci, true);
34683 			  port_write_string(port)(sc, ") ", 2, port);
34684 			  slot_setters_to_port(sc, obj, port, ci);
34685 			  /* perhaps set outlet here?? */
34686 			  port_write_string(port)(sc, " (curlet))", 10, port);
34687 			}
34688 		      else
34689 			{
34690 			  if ((let_outlet(obj) != sc->nil) &&
34691 			      (let_outlet(obj) != sc->rootlet))
34692 			    {
34693 			      int32_t ref;
34694 			      port_write_string(port)(sc, "(sublet ", 8, port);
34695 			      if ((ci) && ((ref = peek_shared_ref(ci, let_outlet(obj))) < 0))
34696 				{
34697 				  char buf[128];
34698 				  int32_t len;
34699 				  len = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, -ref), ">", (const char *)NULL);
34700 				  port_write_string(port)(sc, buf, len, port);
34701 				}
34702 			      else
34703 				{
34704 				  s7_pointer name;
34705 				  name = s7_let_ref(sc, obj, sc->class_name_symbol);
34706 				  if (is_symbol(name))
34707 				    symbol_to_port(sc, name, port, P_DISPLAY, ci);
34708 				  else let_to_port(sc, let_outlet(obj), port, use_write, ci);
34709 				}}
34710 			  else port_write_string(port)(sc, "(inlet", 6, port);
34711 			  slot_list_to_port(sc, let_slots(obj), port, ci, false);
34712 			  port_write_character(port)(sc, ')', port);
34713 			}
34714 		      if (is_immutable(obj))
34715 			port_write_character(port)(sc, ')', port);
34716 		      if (has_methods(obj))
34717 			port_write_character(port)(sc, ')', port);
34718 		    }}
34719 	      else /* not readable write */
34720 		{
34721 		  port_write_string(port)(sc, "(inlet", 6, port);
34722 		  if (is_funclet(obj))
34723 		    funclet_slots_to_port(sc, obj, port, use_write, ci);
34724 		  else slot_to_port_1(sc, let_slots(obj), port, use_write, ci, 0);
34725 		  port_write_character(port)(sc, ')', port);
34726 		}}}}
34727 }
34728 
34729 static void write_macro_readably(s7_scheme *sc, s7_pointer obj, s7_pointer port)
34730 {
34731   s7_pointer arglist, body, expr;
34732 
34733   body = closure_body(obj);
34734   arglist = closure_args(obj);
34735 
34736   port_write_string(port)(sc, (is_either_macro(obj)) ? "(macro" : "(bacro", 6, port);
34737   if ((is_macro_star(obj)) || (is_bacro_star(obj)))
34738     port_write_character(port)(sc, '*', port);
34739   if (is_symbol(arglist))
34740     {
34741       port_write_character(port)(sc, ' ', port);
34742       port_write_string(port)(sc, symbol_name(arglist), symbol_name_length(arglist), port);
34743       port_write_character(port)(sc, ' ', port);
34744     }
34745   else
34746     {
34747       if (is_pair(arglist))
34748 	{
34749 	  port_write_string(port)(sc, " (", 2, port);
34750 	  for (expr = arglist; is_pair(expr); expr = cdr(expr))
34751 	    {
34752 	      object_to_port(sc, car(expr), port, P_WRITE, NULL);
34753 	      if (is_pair(cdr(expr)))
34754 		port_write_character(port)(sc, ' ', port);
34755 	    }
34756 	  if (!is_null(expr))
34757 	    {
34758 	      port_write_string(port)(sc, " . ", 3, port);
34759 	      object_to_port(sc, expr, port, P_WRITE, NULL);
34760 	    }
34761 	  port_write_string(port)(sc, ") ", 2, port);
34762 	}
34763       else port_write_string(port)(sc, " () ", 4, port);
34764     }
34765   for (expr = body; is_pair(expr); expr = cdr(expr))
34766     object_to_port(sc, car(expr), port, P_WRITE, NULL);
34767   port_write_character(port)(sc, ')', port);
34768 }
34769 
34770 
34771 static s7_pointer match_symbol(s7_pointer symbol, s7_pointer e)
34772 {
34773   s7_pointer y, le;
34774   for (le = e; is_let(le); le = let_outlet(le))
34775     for (y = let_slots(le); tis_slot(y); y = next_slot(y))
34776       if (slot_symbol(y) == symbol)
34777 	return(y);
34778   return(NULL);
34779 }
34780 
34781 static bool slot_memq(s7_pointer symbol, s7_pointer symbols)
34782 {
34783   s7_pointer x;
34784   for (x = symbols; is_pair(x); x = cdr(x))
34785     if (slot_symbol(car(x)) == symbol)
34786       return(true);
34787   return(false);
34788 }
34789 
34790 static bool arg_memq(s7_pointer symbol, s7_pointer args)
34791 {
34792   s7_pointer x;
34793   for (x = args; is_pair(x); x = cdr(x))
34794     if ((car(x) == symbol) ||
34795 	((is_pair(car(x))) &&
34796 	 (caar(x) == symbol)))
34797       return(true);
34798   return(false);
34799 }
34800 
34801 static void collect_symbol(s7_scheme *sc, s7_pointer sym, s7_pointer e, s7_pointer args, s7_int gc_loc)
34802 {
34803   if ((!arg_memq(T_Sym(sym), args)) &&
34804       (!slot_memq(sym, gc_protected_at(sc, gc_loc))))
34805     {
34806       s7_pointer slot;
34807       slot = match_symbol(sym, e);
34808       if (slot)
34809 	gc_protected_at(sc, gc_loc) = cons(sc, slot, gc_protected_at(sc, gc_loc));
34810     }
34811 }
34812 
34813 static void collect_locals(s7_scheme *sc, s7_pointer body, s7_pointer e, s7_pointer args, s7_int gc_loc)
34814 {
34815   /* currently called only in write_closure_readably */
34816   if (is_pair(body))
34817     {
34818       collect_locals(sc, car(body), e, args, gc_loc);
34819       collect_locals(sc, cdr(body), e, args, gc_loc);
34820     }
34821   else
34822     if (is_symbol(body))
34823       collect_symbol(sc, body, e, args, gc_loc);
34824 }
34825 
34826 static void collect_specials(s7_scheme *sc, s7_pointer e, s7_pointer args, s7_int gc_loc)
34827 {
34828   collect_symbol(sc, sc->local_signature_symbol, e, args, gc_loc);
34829   collect_symbol(sc, sc->local_setter_symbol, e, args, gc_loc);
34830   collect_symbol(sc, sc->local_documentation_symbol, e, args, gc_loc);
34831   collect_symbol(sc, sc->local_iterator_symbol, e, args, gc_loc);
34832 }
34833 
34834 static s7_pointer find_closure(s7_scheme *sc, s7_pointer closure, s7_pointer current_let)
34835 {
34836   s7_pointer e, y;
34837   for (e = current_let; is_let(e); e = let_outlet(e))
34838     {
34839       if ((is_funclet(e)) || (is_maclet(e)))
34840 	{
34841 	  s7_pointer sym, f;
34842 	  sym = funclet_function(e);
34843 	  f = s7_symbol_local_value(sc, sym, e);
34844 	  if (f == closure)
34845 	    return(sym);
34846 	}
34847       for (y = let_slots(e); tis_slot(y); y = next_slot(y))
34848 	if (slot_value(y) == closure)
34849 	  return(slot_symbol(y));
34850     }
34851 
34852   if ((is_any_macro(closure)) && /* can't be a c_macro here */
34853       (has_pair_macro(closure))) /* maybe macro never called, so no maclet exists */
34854     return(pair_macro(closure_body(closure)));
34855 
34856   return(sc->nil);
34857 }
34858 
34859 static void write_closure_name(s7_scheme *sc, s7_pointer closure, s7_pointer port)
34860 {
34861   s7_pointer x;
34862   x = find_closure(sc, closure, closure_let(closure));
34863   /* this can be confusing!
34864    * (let ((a (lambda () 1))) a)
34865    * #<lambda ()>
34866    * (letrec ((a (lambda () 1))) a)
34867    * a
34868    * (let () (define (a) 1) a)
34869    * a
34870    * (let () (define a (lambda () 1)))
34871    * a
34872    * (let () (define a (lambda () 1)))
34873    * a
34874    * (let () (define (a) (lambda () 1)) (a))
34875    * #<lambda ()>
34876    */
34877   if (is_symbol(x)) /* after find_closure */
34878     {
34879       port_write_string(port)(sc, symbol_name(x), symbol_name_length(x), port);
34880       return;
34881     }
34882 
34883   /* names like #<closure> and #<macro> are useless -- try to be a bit more informative */
34884   switch (type(closure))
34885     {
34886     case T_CLOSURE:
34887       port_write_string(port)(sc, "#<lambda ", 9, port);
34888       break;
34889 
34890     case T_CLOSURE_STAR:
34891       port_write_string(port)(sc, "#<lambda* ", 10, port);
34892       break;
34893 
34894     case T_MACRO:
34895       if (is_expansion(closure))
34896 	port_write_string(port)(sc, "#<expansion ", 12, port);
34897       else port_write_string(port)(sc, "#<macro ", 8, port);
34898       break;
34899 
34900     case T_MACRO_STAR:
34901       if (is_expansion(closure))
34902 	port_write_string(port)(sc, "#<expansion* ", 13, port);
34903       else port_write_string(port)(sc, "#<macro* ", 9, port);
34904       break;
34905 
34906     case T_BACRO:
34907       port_write_string(port)(sc, "#<bacro ", 8, port);
34908       break;
34909 
34910     case T_BACRO_STAR:
34911       port_write_string(port)(sc, "#<bacro* ", 9, port);
34912       break;
34913     }
34914 
34915   if (is_null(closure_args(closure)))
34916     port_write_string(port)(sc, "()>", 3, port);
34917   else
34918     {
34919       s7_pointer args;
34920       args = closure_args(closure);
34921       if (is_symbol(args))
34922 	{
34923 	  port_write_string(port)(sc, symbol_name(args), symbol_name_length(args), port);
34924 	  port_write_character(port)(sc, '>', port);    /* (lambda a a) -> #<lambda a> */
34925 	}
34926       else
34927 	{
34928 	  port_write_character(port)(sc, '(', port);
34929 	  x = car(args);
34930 	  if (is_pair(x)) x = car(x);
34931 	  port_write_string(port)(sc, symbol_name(x), symbol_name_length(x), port);
34932 	  if (!is_null(cdr(args)))
34933 	    {
34934 	      s7_pointer y;
34935 	      port_write_character(port)(sc, ' ', port);
34936 	      if (is_pair(cdr(args)))
34937 		{
34938 		  y = cadr(args);
34939 		  if (is_pair(y))
34940 		    y = car(y);
34941 		  else
34942 		    if (y == sc->key_rest_symbol)
34943 		      {
34944 			port_write_string(port)(sc, ":rest ", 6, port);
34945 			args = cdr(args);
34946 			y = cadr(args);
34947 			if (is_pair(y)) y = car(y);
34948 		      }}
34949 	      else
34950 		{
34951 		  port_write_string(port)(sc, ". ", 2, port);
34952 		  y = cdr(args);
34953 		}
34954 	      port_write_string(port)(sc, symbol_name(y), symbol_name_length(y), port);
34955 	      if ((is_pair(cdr(args))) &&
34956 		  (!is_null(cddr(args))))
34957 		port_write_string(port)(sc, " ...", 4, port);
34958 	    }
34959 	  port_write_string(port)(sc, ")>", 2, port);
34960 	}}
34961 }
34962 
34963 static s7_pointer closure_name(s7_scheme *sc, s7_pointer closure)
34964 {
34965   /* this is used by the error handlers to get the current function name */
34966   s7_pointer x;
34967 
34968   x = find_closure(sc, closure, sc->curlet);
34969   if (is_symbol(x))
34970     return(x);
34971 
34972   if (is_pair(current_code(sc)))
34973     return(current_code(sc));
34974 
34975   return(closure); /* desperation -- the parameter list (caar here) will cause endless confusion in OP_APPLY errors! */
34976 }
34977 
34978 static s7_pointer pair_append(s7_scheme *sc, s7_pointer a, s7_pointer b)
34979 {
34980   s7_pointer p, tp, np;
34981   if (is_null(a)) return(b);
34982 
34983   tp = list_1(sc, car(a));
34984   sc->y = tp;
34985   for (p = cdr(a), np = tp; is_pair(p); p = cdr(p), np = cdr(np))
34986     set_cdr(np, list_1(sc, car(p)));
34987   set_cdr(np, b);
34988   sc->y = sc->nil;
34989 
34990   return(tp);
34991 }
34992 
34993 static void write_closure_readably_1(s7_scheme *sc, s7_pointer obj, s7_pointer arglist, s7_pointer body, s7_pointer port)
34994 {
34995   s7_int old_print_length;
34996   s7_pointer p;
34997 
34998   if (type(obj) == T_CLOSURE_STAR)
34999     port_write_string(port)(sc, "(lambda* ", 9, port);
35000   else port_write_string(port)(sc, "(lambda ", 8, port);
35001 
35002   if ((is_pair(arglist)) &&
35003       (allows_other_keys(arglist)))
35004     {
35005       sc->temp9 = pair_append(sc, arglist, list_1(sc, sc->key_allow_other_keys_symbol));
35006       object_to_port(sc, sc->temp9, port, P_WRITE, NULL);
35007       sc->temp9 = sc->nil;
35008     }
35009   else object_to_port(sc, arglist, port, P_WRITE, NULL); /* here we just want the straight output (a b) not (list 'a 'b) */
35010 
35011   old_print_length = sc->print_length;
35012   sc->print_length = 1048576;
35013   for (p = body; is_pair(p); p = cdr(p))
35014     {
35015       port_write_character(port)(sc, ' ', port);
35016       object_to_port(sc, car(p), port, P_WRITE, NULL);
35017     }
35018   port_write_character(port)(sc, ')', port);
35019   sc->print_length = old_print_length;
35020 }
35021 
35022 static void write_closure_readably(s7_scheme *sc, s7_pointer obj, s7_pointer port, shared_info_t *ci)
35023 {
35024   s7_pointer body, arglist, pe, local_slots, setter = NULL;
35025   s7_int gc_loc;
35026 
35027   body = closure_body(obj);
35028   if (sc->safety > NO_SAFETY)
35029     {
35030       if (tree_is_cyclic(sc, body))
35031 	{
35032 	  port_write_string(port)(sc, "#<write_closure: body is cyclic>", 32, port); /* not s7_error here! */
35033 	  return;
35034 	}
35035       /* perhaps: if any sequence in the closure_body is cyclic, complain, but how to check without clobbering ci?
35036        *   perhaps pass ci, and use make_shared_info if ci=null else continue_shared_info?
35037        *   this can happen only if (apply lambda ... cyclic-seq ...) I think
35038        *   long-term we need to include closure_body(obj) in the top object_out make_shared_info
35039        */
35040     }
35041 
35042   arglist = closure_args(obj);
35043   if (is_symbol(arglist)) arglist = list_1(sc, arglist);
35044   pe = closure_let(obj);
35045 
35046   gc_loc = s7_gc_protect_1(sc, sc->nil);
35047   collect_locals(sc, body, pe, arglist, gc_loc);   /* collect locals used only here (and below) */
35048   collect_specials(sc, pe, arglist, gc_loc);
35049 
35050   if (s7_is_dilambda(obj))
35051     {
35052       setter = closure_setter(obj);
35053       if (has_closure_let(setter))                 /* collect args etc so need the arglist */
35054 	{
35055 	  arglist = closure_args(setter);
35056 	  if (is_symbol(arglist)) arglist = list_1(sc, arglist);
35057 	  collect_locals(sc, closure_body(setter), pe, arglist, gc_loc);
35058 	}}
35059 
35060   local_slots = T_Lst(gc_protected_at(sc, gc_loc)); /* possibly a list of slots */
35061   if (!is_null(local_slots))
35062     {
35063       s7_pointer x;
35064       port_write_string(port)(sc, "(let (", 6, port);
35065       for (x = local_slots; is_pair(x); x = cdr(x))
35066 	{
35067 	  s7_pointer slot;
35068 	  slot = car(x);
35069 	  if ((!is_any_closure(slot_value(slot))) &&    /* mutually referencing closures? ./snd -l snd-test 24 hits this in the effects dialogs */
35070 	      ((!has_structure(slot_value(slot))) ||    /* see s7test example, vector has closure that refers to vector */
35071 	       (slot_symbol(slot) == sc->local_signature_symbol)))
35072 	    {
35073 	      port_write_character(port)(sc, '(', port);
35074 	      port_write_string(port)(sc, symbol_name(slot_symbol(slot)), symbol_name_length(slot_symbol(slot)), port);
35075 	      port_write_character(port)(sc, ' ', port);
35076 	      /* (object->string (list (let ((local 1)) (lambda (x) (+ x local)))) :readable) */
35077 	      object_to_port(sc, slot_value(slot), port, P_READABLE, NULL);
35078 	      if (is_null(cdr(x)))
35079 		port_write_character(port)(sc, ')', port);
35080 	      else port_write_string(port)(sc, ") ", 2, port);
35081 	    }}
35082       port_write_string(port)(sc, ") ", 2, port);
35083     }
35084 
35085   if (setter)
35086     port_write_string(port)(sc, "(dilambda ", 10, port);
35087 
35088   write_closure_readably_1(sc, obj, closure_args(obj), body, port);
35089 
35090   if (setter)
35091     {
35092       port_write_character(port)(sc, ' ', port);
35093       if (has_closure_let(setter))
35094 	write_closure_readably_1(sc, setter, closure_args(setter), closure_body(setter), port);
35095       else object_to_port_with_circle_check(sc, setter, port, P_READABLE, ci);
35096       port_write_character(port)(sc, ')', port);
35097     }
35098 
35099   if (!is_null(local_slots))
35100     port_write_character(port)(sc, ')', port);
35101   s7_gc_unprotect_at(sc, gc_loc);
35102 }
35103 
35104 static void iterator_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35105 {
35106   if (use_write == P_READABLE)
35107     {
35108       if (iterator_is_at_end(obj))
35109 	{
35110 	  switch (type(iterator_sequence(obj)))
35111 	    {
35112 	    case T_NIL:
35113 	    case T_PAIR:         port_write_string(port)(sc, "(make-iterator ())", 18, port);	        break;
35114 	    case T_STRING:       port_write_string(port)(sc, "(make-iterator \"\")", 18, port);	        break;
35115 	    case T_BYTE_VECTOR:  port_write_string(port)(sc, "(make-iterator #u())", 20, port);	        break;
35116 	    case T_VECTOR:       port_write_string(port)(sc, "(make-iterator #())", 19, port);	        break;
35117 	    case T_INT_VECTOR:	 port_write_string(port)(sc, "(make-iterator #i())", 20, port);	        break;
35118 	    case T_FLOAT_VECTOR: port_write_string(port)(sc, "(make-iterator #r())", 20, port);	        break;
35119 	    case T_LET:	         port_write_string(port)(sc, "(make-iterator (inlet))", 23, port);      break;
35120 
35121 	    case T_HASH_TABLE:
35122 	      if (is_weak_hash_table(iterator_sequence(obj)))
35123 		port_write_string(port)(sc, "(make-iterator (weak-hash-table))", 33, port);
35124 	      else port_write_string(port)(sc, "(make-iterator (hash-table))", 28, port);
35125 	      break;
35126 
35127 	    default:
35128 	      port_write_string(port)(sc, "(make-iterator ())", 18, port);	        break; /* c-object?? function? */
35129 	    }}
35130       else
35131 	{
35132 	  s7_pointer seq;
35133 	  int32_t iter_ref;
35134 	  seq = iterator_sequence(obj);
35135 	  if ((ci) &&
35136 	      (is_cyclic(obj)) &&
35137 	      ((iter_ref = peek_shared_ref(ci, obj)) != 0))
35138 	    {
35139 	      /* basically the same as c_pointer_to_port */
35140 	      if (!is_cyclic_set(obj))
35141 		{
35142 		  int32_t nlen;
35143 		  char buf[128];
35144 		  if (iter_ref < 0) iter_ref = -iter_ref;
35145 
35146 		  if (ci->init_port == sc->F)
35147 		    {
35148 		      ci->init_port = s7_open_output_string(sc);
35149 		      ci->init_loc = s7_gc_protect_1(sc, ci->init_port);
35150 		    }
35151 		  port_write_string(port)(sc, "#f", 2, port);
35152 		  nlen = catstrs_direct(buf, "  (set! <", pos_int_to_str_direct(sc, iter_ref), "> (make-iterator ", (const char *)NULL);
35153 		  port_write_string(ci->init_port)(sc, buf, nlen, ci->init_port);
35154 
35155 		  flip_ref(ci, seq);
35156 		  object_to_port_with_circle_check(sc, seq, ci->init_port, use_write, ci);
35157 		  flip_ref(ci, seq);
35158 
35159 		  port_write_string(ci->init_port)(sc, "))\n", 3, ci->init_port);
35160 		  set_cyclic_set(obj);
35161 		  return;
35162 		}}
35163 
35164 	  if (is_string(seq))
35165 	    {
35166 	      char *iter_str;
35167 	      s7_int len;
35168 	      iter_str = (char *)(string_value(seq) + iterator_position(obj));
35169 	      len = string_length(seq) - iterator_position(obj);
35170 	      if (len == 0)
35171 		port_write_string(port)(sc, "(make-iterator \"\")", 18, port);
35172 	      else
35173 		{
35174 		  port_write_string(port)(sc, "(make-iterator \"", 16, port);
35175 		  if (!string_needs_slashification(iter_str, len))
35176 		    port_write_string(port)(sc, iter_str, len, port);
35177 		  else slashify_string_to_port(sc, port, iter_str, len, NOT_IN_QUOTES);
35178 		  port_write_string(port)(sc, "\")", 2, port);
35179 		}}
35180 	  else
35181 	    {
35182 	      if (is_pair(seq))
35183 		{
35184 		  port_write_string(port)(sc, "(make-iterator ", 15, port);
35185 		  object_to_port_with_circle_check(sc, iterator_current(obj), port, use_write, ci);
35186 		  port_write_character(port)(sc, ')', port);
35187 		}
35188 	      else
35189 		{
35190 		  if ((is_let(seq)) && (seq != sc->rootlet))
35191 		    {
35192 		      s7_pointer slot;
35193 		      port_write_string(port)(sc, "(let ((iter (make-iterator ", 27, port);
35194 		      object_to_port_with_circle_check(sc, seq, port, use_write, ci);
35195 		      port_write_string(port)(sc, "))) ", 4, port);
35196 		      for (slot = let_slots(seq); slot != iterator_current_slot(obj); slot = next_slot(slot))
35197 			port_write_string(port)(sc, "(iter) ", 7, port);
35198 		      port_write_string(port)(sc, "iter)", 5, port);
35199 		    }
35200 		  else
35201 		    {
35202 		      if (iterator_position(obj) > 0)
35203 			port_write_string(port)(sc, "(let ((iter (make-iterator ", 27, port);
35204 		      else port_write_string(port)(sc, "(make-iterator ", 15, port);
35205 		      object_to_port_with_circle_check(sc, seq, port, use_write, ci);
35206 		      if (iterator_position(obj) > 0)
35207 			{
35208 			  if (iterator_position(obj) == 1)
35209 			    port_write_string(port)(sc, "))) (iter) iter)", 16, port);
35210 			  else
35211 			    {
35212 			      int32_t nlen;
35213 			      char str[128];
35214 			      nlen = catstrs_direct(str, "))) (do ((i 0 (+ i 1))) ((= i ",
35215 						    pos_int_to_str_direct(sc, iterator_position(obj)),
35216 						    ") iter) (iter)))", (const char *)NULL);
35217 			      port_write_string(port)(sc, str, nlen, port);
35218 			    }}
35219 		      else port_write_character(port)(sc, ')', port);
35220 		    }}}}}
35221   else
35222     {
35223       const char *str;
35224       if ((is_hash_table(iterator_sequence(obj))) && (is_weak_hash_table(iterator_sequence(obj))))
35225 	str = "weak-hash-table";
35226       else str = type_name(sc, iterator_sequence(obj), NO_ARTICLE);
35227       port_write_string(port)(sc, "#<iterator: ", 12, port);
35228       port_write_string(port)(sc, str, safe_strlen(str), port);
35229       port_write_character(port)(sc, '>', port);
35230     }
35231 }
35232 
35233 static void c_pointer_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35234 {
35235   int32_t nlen;
35236   char buf[128];
35237   /* c-pointer is special because we can't set the type or info fields from scheme except via the c-pointer function */
35238 
35239   if (use_write == P_READABLE)
35240     {
35241       int32_t ref;
35242       if ((ci) &&
35243 	  (is_cyclic(obj)) &&
35244 	  ((ref = peek_shared_ref(ci, obj)) != 0))
35245 	{
35246 	  port_write_string(port)(sc, "#f", 2, port);
35247 
35248 	  if (!is_cyclic_set(obj))
35249 	    {
35250 	      if (ci->init_port == sc->F)
35251 		{
35252 		  ci->init_port = s7_open_output_string(sc);
35253 		  ci->init_loc = s7_gc_protect_1(sc, ci->init_port);
35254 		}
35255 	      nlen = snprintf(buf, 128, "  (set! <%d> (c-pointer %" print_pointer, -ref, (intptr_t)c_pointer(obj));
35256 	      port_write_string(ci->init_port)(sc, buf, nlen, ci->init_port);
35257 
35258 	      if ((c_pointer_type(obj) != sc->F) ||
35259 		  (c_pointer_info(obj) != sc->F))
35260 		{
35261 		  flip_ref(ci, c_pointer_type(obj));
35262 
35263 		  port_write_character(ci->init_port)(sc, ' ', ci->init_port);
35264 		  object_to_port_with_circle_check(sc, c_pointer_type(obj), ci->init_port, use_write, ci);
35265 
35266 		  flip_ref(ci, c_pointer_type(obj));
35267 		  flip_ref(ci, c_pointer_info(obj));
35268 
35269 		  port_write_character(ci->init_port)(sc, ' ', ci->init_port);
35270 		  object_to_port_with_circle_check(sc, c_pointer_info(obj), ci->init_port, use_write, ci);
35271 
35272 		  flip_ref(ci, c_pointer_info(obj));
35273 		}
35274 	      port_write_string(ci->init_port)(sc, "))\n", 3, ci->init_port);
35275 	      set_cyclic_set(obj);
35276 	    }}
35277       else
35278 	{
35279 	  nlen = snprintf(buf, 128, "(c-pointer %" print_pointer, (intptr_t)c_pointer(obj));
35280 	  port_write_string(port)(sc, buf, nlen, port);
35281 	  if ((c_pointer_type(obj) != sc->F) ||
35282 	      (c_pointer_info(obj) != sc->F))
35283 	    {
35284 	      port_write_character(port)(sc, ' ', port);
35285 	      object_to_port_with_circle_check(sc, c_pointer_type(obj), port, use_write, ci);
35286 	      port_write_character(port)(sc, ' ', port);
35287 	      object_to_port_with_circle_check(sc, c_pointer_info(obj), port, use_write, ci);
35288 	    }
35289 	  port_write_character(port)(sc, ')', port);
35290 	}}
35291   else
35292     {
35293       if (is_symbol(c_pointer_type(obj)))
35294 	nlen = snprintf(buf, 128, "#<%s %p>", symbol_name(c_pointer_type(obj)), c_pointer(obj));
35295       else nlen = snprintf(buf, 128, "#<c_pointer %p>", c_pointer(obj));
35296       port_write_string(port)(sc, buf, nlen, port);
35297     }
35298 }
35299 
35300 static void rng_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35301 {
35302   int32_t nlen;
35303   char buf[128];
35304 #if WITH_GMP
35305   if (use_write == P_READABLE)
35306     nlen = snprintf(buf, 128, "#<bignum random-state>");
35307   else nlen = snprintf(buf, 128, "#<rng %p>", obj);
35308 #else
35309   if (use_write == P_READABLE)
35310     nlen = snprintf(buf, 128, "(random-state %" PRIu64 " %" PRIu64 ")", random_seed(obj), random_carry(obj));
35311   else nlen = snprintf(buf, 128, "#<rng %" PRIu64 " %" PRIu64 ">", random_seed(obj), random_carry(obj));
35312 #endif
35313   port_write_string(port)(sc, buf, nlen, port);
35314 }
35315 
35316 static void display_any(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35317 {
35318 #if S7_DEBUGGING
35319   print_debugging_state(sc, obj, port);
35320 #else
35321   {
35322     char *str, *tmp;
35323     block_t *b;
35324     s7_int nlen, len;
35325     tmp = describe_type_bits(sc, obj);
35326     len = 32 + safe_strlen(tmp);
35327     b = mallocate(sc, len);
35328     str = (char *)block_data(b);
35329     if (is_free(obj))
35330       nlen = catstrs_direct(str, "<free cell! ", tmp, ">", (const char *)NULL);
35331     else nlen = catstrs_direct(str, "<unknown object! ", tmp, ">", (const char *)NULL);
35332     port_write_string(port)(sc, str, nlen, port);
35333     free(tmp);
35334     liberate(sc, b);
35335   }
35336 #endif
35337 }
35338 
35339 static void unique_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35340 {
35341   port_write_string(port)(sc, unique_name(obj), unique_name_length(obj), port);
35342 }
35343 
35344 static void undefined_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35345 {
35346   if ((obj != sc->undefined) &&
35347       (use_write == P_READABLE))
35348     {
35349       port_write_string(port)(sc, "(with-input-from-string \"",25, port);
35350       port_write_string(port)(sc, undefined_name(obj), undefined_name_length(obj), port);
35351       port_write_string(port)(sc, "\" read)", 7, port);
35352     }
35353   else port_write_string(port)(sc, undefined_name(obj), undefined_name_length(obj), port);
35354 }
35355 
35356 static void eof_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35357 {
35358   if (use_write == P_READABLE)
35359     port_write_string(port)(sc, "(begin #<eof>)", 14, port);
35360   else port_write_string(port)(sc, eof_name(obj), eof_name_length(obj), port);
35361 }
35362 
35363 static void counter_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35364 {
35365   port_write_string(port)(sc, "#<counter>", 10, port);
35366 }
35367 
35368 static void integer_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35369 {
35370   if (has_number_name(obj))
35371     {
35372       if (is_string_port(port))
35373 	{
35374 	  if (port_position(port) + number_name_length(obj) < port_data_size(port))
35375 	    {
35376 	      memcpy((void *)(port_data(port) + port_position(port)), (void *)number_name(obj), number_name_length(obj));
35377 	      port_position(port) += number_name_length(obj);
35378 	    }
35379 	  else string_write_string_resized(sc, number_name(obj), number_name_length(obj), port);
35380 	}
35381       else port_write_string(port)(sc, number_name(obj), number_name_length(obj), port);
35382     }
35383   else
35384     {
35385       s7_int nlen;
35386       char *str;
35387       str = integer_to_string(sc, integer(obj), &nlen);
35388       set_number_name(obj, str, nlen);
35389       port_write_string(port)(sc, str, nlen, port);
35390     }
35391 }
35392 
35393 static void number_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35394 {
35395   if (has_number_name(obj))
35396     port_write_string(port)(sc, number_name(obj), number_name_length(obj), port);
35397   else
35398     {
35399       s7_int nlen;
35400       char *str;
35401       nlen = 0;
35402       str = number_to_string_base_10(sc, obj, 0, sc->float_format_precision, 'g', &nlen, use_write); /* was 14 */
35403       if ((nlen < NUMBER_NAME_SIZE) &&
35404 	  (str[0] != 'n') && (str[0] != 'i') &&
35405 	  ((!(is_t_complex(obj))) ||
35406 	   ((!is_NaN(imag_part(obj))) && (!is_inf(imag_part(obj))))))
35407 	set_number_name(obj, str, nlen);
35408       port_write_string(port)(sc, str, nlen, port);
35409     }
35410 }
35411 
35412 #if WITH_GMP
35413 static void big_number_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35414 {
35415   s7_int nlen;
35416   block_t *str;
35417   nlen = 0;
35418   str = big_number_to_string_with_radix(sc, obj, BASE_10, 0, &nlen, use_write);
35419   port_write_string(port)(sc, (char *)block_data(str), nlen, port);
35420   liberate(sc, str);
35421 }
35422 #endif
35423 
35424 static void syntax_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35425 {
35426   port_display(port)(sc, symbol_name(syntax_symbol(obj)), port);
35427 }
35428 
35429 static void character_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35430 {
35431   if (use_write == P_DISPLAY)
35432     port_write_character(port)(sc, character(obj), port);
35433   else port_write_string(port)(sc, character_name(obj), character_name_length(obj), port);
35434 }
35435 
35436 static void closure_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35437 {
35438   if (has_active_methods(sc, obj))
35439     {
35440       /* look for object->string method else fallback on ordinary case.
35441        * can't use recursion on closure_let here because then the fallback name is #<let>.
35442        * this is tricky!: (display (openlet (with-let (mock-c-pointer 0) (lambda () 1))))
35443        *   calls object->string on the closure whose closure_let is the mock-c-pointer;
35444        *   it has an object->string method that clears mock-c-pointers and tries again...
35445        *   so, display methods need to use coverlet/openlet.
35446        */
35447       s7_pointer print_func;
35448       print_func = find_method(sc, closure_let(obj), sc->object_to_string_symbol);
35449       if (print_func != sc->undefined)
35450 	{
35451 	  s7_pointer p;
35452 	  p = call_method(sc, obj, print_func, set_plist_1(sc, obj));
35453 	  if (string_length(p) > 0)
35454 	    port_write_string(port)(sc, string_value(p), string_length(p), port);
35455 	  return;
35456 	}}
35457   if (use_write == P_READABLE)
35458     write_closure_readably(sc, obj, port, ci);
35459   else write_closure_name(sc, obj, port);
35460 }
35461 
35462 static void macro_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35463 {
35464   if (use_write == P_READABLE)
35465     write_macro_readably(sc, obj, port);
35466   else write_closure_name(sc, obj, port);
35467 }
35468 
35469 static void c_function_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35470 {
35471   s7_pointer sym;
35472   sym = make_symbol(sc, c_function_name(obj));
35473   if ((!is_global(sym)) &&
35474       (is_slot(initial_slot(sym))) &&
35475       ((use_write == P_READABLE) || (lookup(sc, sym) != initial_value(sym))))
35476     {
35477       port_write_string(port)(sc, "#_", 2, port);
35478       port_write_string(port)(sc, c_function_name(obj), c_function_name_length(obj), port);
35479       return;
35480     }
35481   if (c_function_name_length(obj) > 0)
35482     port_write_string(port)(sc, c_function_name(obj), c_function_name_length(obj), port);
35483   else port_write_string(port)(sc, "#<c-function>", 13, port);
35484 }
35485 
35486 static void c_macro_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35487 {
35488   if (c_macro_name_length(obj) > 0)
35489     port_write_string(port)(sc, c_macro_name(obj), c_macro_name_length(obj), port);
35490   else port_write_string(port)(sc, "#<c-macro>", 10, port);
35491 }
35492 
35493 static void continuation_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35494 {
35495   if (is_symbol(continuation_name(obj)))
35496     {
35497       port_write_string(port)(sc, "#<continuation ", 15, port);
35498       symbol_to_port(sc, continuation_name(obj), port, P_DISPLAY, ci);
35499       port_write_character(port)(sc, '>', port);
35500     }
35501   else port_write_string(port)(sc, "#<continuation>", 15, port);
35502 }
35503 
35504 static void goto_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35505 {
35506   if (is_symbol(call_exit_name(obj)))
35507     {
35508       port_write_string(port)(sc, "#<goto ", 7, port);
35509       symbol_to_port(sc, call_exit_name(obj), port, P_DISPLAY, ci);
35510       port_write_character(port)(sc, '>', port);
35511     }
35512   else port_write_string(port)(sc, "#<goto>", 7, port);
35513 }
35514 
35515 static void catch_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35516 {
35517   port_write_string(port)(sc, "#<catch>", 8, port);
35518 }
35519 
35520 static void dynamic_wind_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35521 {
35522   /* this can happen because (*s7* 'stack) can involve dynamic-wind markers */
35523   port_write_string(port)(sc, "#<dynamic-wind>", 15, port);
35524 }
35525 
35526 static void c_object_name_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port)
35527 {
35528   port_write_string(port)(sc, string_value(c_object_scheme_name(sc, obj)),
35529 			  string_length(c_object_scheme_name(sc, obj)),
35530 			  port);
35531 }
35532 
35533 static void c_object_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35534 {
35535 #if (!DISABLE_DEPRECATED)
35536   if (c_object_print(sc, obj))
35537     {
35538       char *str;
35539       str = ((*(c_object_print(sc, obj)))(sc, c_object_value(obj)));
35540       port_display(port)(sc, str, port);
35541       free(str);
35542       return;
35543     }
35544 #endif
35545   if (c_object_to_string(sc, obj))
35546     port_display(port)(sc, s7_string((*(c_object_to_string(sc, obj)))(sc, set_plist_2(sc, obj, (use_write == P_READABLE) ? sc->key_readable_symbol : sc->T))), port);
35547   else
35548     {
35549       if ((use_write == P_READABLE) &&
35550 	  (c_object_to_list(sc, obj)) &&  /* to_list and (implicit) set are needed to reconstruct a cyclic c-object, as well as the maker (via type name) */
35551 	  (c_object_set(sc, obj)))
35552 	{
35553 	  s7_pointer obj_list, old_w, p;
35554 	  int32_t href;
35555 
35556 	  obj_list = ((*(c_object_to_list(sc, obj)))(sc, set_plist_1(sc, obj)));
35557 	  old_w = sc->w;
35558 	  sc->w = obj_list;
35559 
35560 	  if ((ci) &&
35561 	      (is_cyclic(obj)) &&
35562 	      ((href = peek_shared_ref(ci, obj)) != 0))
35563 	    {
35564 	      int32_t i;
35565 	      if (href < 0) href = -href;
35566 	      if ((ci->defined[href]) || (port == ci->cycle_port))
35567 		{
35568 		  int32_t nlen;
35569 		  char buf[128];
35570 		  nlen = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, href), ">", (const char *)NULL);
35571 		  port_write_string(port)(sc, buf, nlen, port);
35572 		  return;
35573 		}
35574 
35575 	      port_write_character(port)(sc, '(', port);
35576 	      c_object_name_to_port(sc, obj, port);
35577 	      for (i = 0, p = obj_list; is_pair(p); i++, p = cdr(p))
35578 		{
35579 		  s7_pointer val;
35580 		  val = car(p);
35581 		  if (has_structure(val))
35582 		    {
35583 		      char buf[128];
35584 		      int32_t symref, len;
35585 
35586 		      port_write_string(port)(sc, " #f", 3, port);
35587 		      len = catstrs_direct(buf, "  (set! (<", pos_int_to_str_direct(sc, href), "> ", pos_int_to_str_direct_1(sc, i), ") ", (const char *)NULL);
35588 		      port_write_string(ci->cycle_port)(sc, buf, len, ci->cycle_port);
35589 
35590 		      symref = peek_shared_ref(ci, val);
35591 		      if (symref != 0)
35592 			{
35593 			  if (symref < 0) symref = -symref;
35594 			  len = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, symref), ">)\n", (const char *)NULL);
35595 			  port_write_string(ci->cycle_port)(sc, buf, len, ci->cycle_port);
35596 			}
35597 		      else
35598 			{
35599 			  object_to_port_with_circle_check(sc, val, ci->cycle_port, P_READABLE, ci);
35600 			  port_write_string(ci->cycle_port)(sc, ")\n", 2, ci->cycle_port);
35601 			}}
35602 		  else
35603 		    {
35604 		      port_write_character(port)(sc, ' ', port);
35605 		      object_to_port_with_circle_check(sc, val, port, P_READABLE, ci);
35606 		    }}}
35607 	  else
35608 	    {
35609 	      port_write_character(port)(sc, '(', port);
35610 	      c_object_name_to_port(sc, obj, port);
35611 	      for (p = obj_list; is_pair(p); p = cdr(p))
35612 		{
35613 		  s7_pointer val;
35614 		  val = car(p);
35615 		  port_write_character(port)(sc, ' ', port);
35616 		  object_to_port_with_circle_check(sc, val, port, P_READABLE, ci);
35617 		}}
35618 	  port_write_character(port)(sc, ')', port);
35619 	  sc->w = old_w;
35620 	}
35621       else
35622 	{
35623 	  char buf[128];
35624 	  int32_t nlen;
35625 	  port_write_string(port)(sc, "#<", 2, port);
35626 	  c_object_name_to_port(sc, obj, port);
35627 	  nlen = snprintf(buf, 128, " %p>", obj);
35628 	  port_write_string(port)(sc, buf, nlen, port);
35629 	}}
35630 }
35631 
35632 static void slot_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35633 {
35634   /* the slot symbol might need (symbol...) in which case we don't want the preceding quote */
35635   symbol_to_port(sc, slot_symbol(obj), port, P_READABLE, ci);
35636   port_write_character(port)(sc, ' ', port);
35637   object_to_port_with_circle_check(sc, slot_value(obj), port, use_write, ci);
35638 }
35639 
35640 static void stack_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35641 {
35642   port_write_string(port)(sc, "#<stack>", 8, port);
35643 }
35644 
35645 static void init_display_functions(void)
35646 {
35647   int32_t i;
35648   for (i = 0; i < 256; i++) display_functions[i] = display_any;
35649   display_functions[T_FLOAT_VECTOR] = float_vector_to_port;
35650   display_functions[T_INT_VECTOR] =   int_vector_to_port;
35651   display_functions[T_BYTE_VECTOR] =  byte_vector_to_port;
35652   display_functions[T_VECTOR] =       vector_to_port;
35653   display_functions[T_PAIR] =         pair_to_port;
35654   display_functions[T_HASH_TABLE] =   hash_table_to_port;
35655   display_functions[T_ITERATOR] =     iterator_to_port;
35656   display_functions[T_LET] =          let_to_port;
35657   display_functions[T_BOOLEAN] =      unique_to_port;
35658   display_functions[T_NIL] =          unique_to_port;
35659   display_functions[T_UNUSED] =       unique_to_port;
35660   display_functions[T_UNSPECIFIED] =  unique_to_port;
35661   display_functions[T_UNDEFINED] =    undefined_to_port;
35662   display_functions[T_EOF] =          eof_to_port;
35663   display_functions[T_INPUT_PORT] =   input_port_to_port;
35664   display_functions[T_OUTPUT_PORT] =  output_port_to_port;
35665   display_functions[T_COUNTER] =      counter_to_port;
35666   display_functions[T_STACK] =        stack_to_port;
35667   display_functions[T_INTEGER] =      integer_to_port;
35668   display_functions[T_RATIO] =        number_to_port;
35669   display_functions[T_REAL] =         number_to_port;
35670   display_functions[T_COMPLEX] =      number_to_port;
35671 #if WITH_GMP
35672   display_functions[T_BIG_INTEGER] =  big_number_to_port;
35673   display_functions[T_BIG_RATIO] =    big_number_to_port;
35674   display_functions[T_BIG_REAL] =     big_number_to_port;
35675   display_functions[T_BIG_COMPLEX] =  big_number_to_port;
35676 #endif
35677   display_functions[T_SYMBOL] =       symbol_to_port;
35678   display_functions[T_SYNTAX] =       syntax_to_port;
35679   display_functions[T_STRING] =       string_to_port;
35680   display_functions[T_CHARACTER] =    character_to_port;
35681   display_functions[T_CLOSURE] =      closure_to_port;
35682   display_functions[T_CLOSURE_STAR] = closure_to_port;
35683   display_functions[T_MACRO] =        macro_to_port;
35684   display_functions[T_MACRO_STAR] =   macro_to_port;
35685   display_functions[T_BACRO] =        macro_to_port;
35686   display_functions[T_BACRO_STAR] =   macro_to_port;
35687   display_functions[T_C_OPT_ARGS_FUNCTION] = c_function_to_port;
35688   display_functions[T_C_RST_ARGS_FUNCTION] = c_function_to_port;
35689   display_functions[T_C_ANY_ARGS_FUNCTION] = c_function_to_port;
35690   display_functions[T_C_FUNCTION] =   c_function_to_port;
35691   display_functions[T_C_FUNCTION_STAR] = c_function_to_port;
35692   display_functions[T_C_MACRO] =      c_macro_to_port;
35693   display_functions[T_C_POINTER] =    c_pointer_to_port;
35694   display_functions[T_RANDOM_STATE] = rng_to_port;
35695   display_functions[T_CONTINUATION] = continuation_to_port;
35696   display_functions[T_GOTO] =         goto_to_port;
35697   display_functions[T_CATCH] =        catch_to_port;
35698   display_functions[T_DYNAMIC_WIND] = dynamic_wind_to_port;
35699   display_functions[T_C_OBJECT] =     c_object_to_port;
35700   display_functions[T_SLOT] =         slot_to_port;
35701 }
35702 
35703 static void object_to_port_with_circle_check_1(s7_scheme *sc, s7_pointer vr, s7_pointer port, use_write_t use_write, shared_info_t *ci)
35704 {
35705   int32_t ref;
35706   ref = (is_collected(vr)) ? shared_ref(ci, vr) : 0;
35707   if (ref != 0)
35708     {
35709       char buf[32];
35710       int32_t nlen;
35711       char *p;
35712       s7_int len;
35713 
35714       if (ref > 0)
35715 	{
35716 	  if (use_write == P_READABLE)
35717 	    {
35718 	      if (ci->defined[ref])
35719 		{
35720 		  flip_ref(ci, vr);
35721 		  nlen = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, ref), ">", (const char *)NULL);
35722 		  port_write_string(port)(sc, buf, nlen, port);
35723 		  return;
35724 		}
35725 	      object_to_port(sc, vr, port, P_READABLE, ci);
35726 	    }
35727 	  else
35728 	    {
35729 	      /* "normal" printout involving #n= and #n# */
35730 	      p = pos_int_to_str(sc, (s7_int)ref, &len, '=');
35731 	      *--p = '#';
35732 	      port_write_string(port)(sc, p, len, port);
35733 	      object_to_port(sc, vr, port, NOT_P_DISPLAY(use_write), ci);
35734 	    }}
35735       else
35736 	{
35737 	  if (use_write == P_READABLE)
35738 	    {
35739 	      nlen = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, -ref), ">", (const char *)NULL);
35740 	      port_write_string(port)(sc, buf, nlen, port);
35741 	    }
35742 	  else
35743 	    {
35744 	      p = pos_int_to_str(sc, (s7_int)(-ref), &len, '#');
35745 	      *--p = '#';
35746 	      port_write_string(port)(sc, p, len, port);
35747 	    }}}
35748   else object_to_port(sc, vr, port, use_write, ci);
35749 }
35750 
35751 static s7_pointer cyclic_out(s7_scheme *sc, s7_pointer obj, s7_pointer port, shared_info_t *ci)
35752 {
35753   int32_t i, ref, len;
35754   char buf[128];
35755 
35756   ci->cycle_port = s7_open_output_string(sc);
35757   ci->cycle_loc = s7_gc_protect_1(sc, ci->cycle_port);
35758 
35759   port_write_string(port)(sc, "(let (", 6, port);
35760   for (i = 0; i < ci->top; i++)
35761     {
35762       ref = peek_shared_ref(ci, ci->objs[i]); /* refs may be in any order */
35763       if (ref < 0) {ref = -ref; flip_ref(ci, ci->objs[i]);}
35764       len = catstrs_direct(buf, (i == 0) ? "(<" : "\n      (<", pos_int_to_str_direct(sc, ref), "> ", (const char *)NULL);
35765       port_write_string(port)(sc, buf, len, port);
35766       ci->defined[ref] = false;
35767       object_to_port_with_circle_check(sc, ci->objs[i], port, P_READABLE, ci);
35768       port_write_character(port)(sc, ')', port);
35769       ci->defined[ref] = true;
35770       if (peek_shared_ref(ci, ci->objs[i]) > 0) flip_ref(ci, ci->objs[i]); /* ref < 0 -> use <%d> in object_to_port */
35771     }
35772   port_write_string(port)(sc, ")\n", 2, port);
35773 
35774   if (ci->init_port != sc->F)
35775     {
35776       port_write_string(port)(sc, (const char *)(port_data(ci->init_port)), port_position(ci->init_port), port);
35777       s7_close_output_port(sc, ci->init_port);
35778       s7_gc_unprotect_at(sc, ci->init_loc);
35779       ci->init_port = sc->F;
35780     }
35781 
35782   if (port_position(ci->cycle_port) > 0)     /* 0 if e.g. (object->string (object->let (rootlet)) :readable) */
35783     port_write_string(port)(sc, (const char *)(port_data(ci->cycle_port)), port_position(ci->cycle_port), port);
35784   s7_close_output_port(sc, ci->cycle_port);
35785   s7_gc_unprotect_at(sc, ci->cycle_loc);
35786   ci->cycle_port = sc->F;
35787 
35788   if ((is_immutable(obj)) && (!is_let(obj)))
35789     port_write_string(port)(sc, "  (immutable! ", 14, port);
35790   else port_write_string(port)(sc, "  ", 2, port);
35791 
35792   ref = peek_shared_ref(ci, obj);
35793   if (ref == 0)
35794     object_to_port_with_circle_check(sc, obj, port, P_READABLE, ci);
35795   else
35796     {
35797       len = catstrs_direct(buf, "<", pos_int_to_str_direct(sc, (ref < 0) ? -ref : ref), ">", (const char *)NULL);
35798       port_write_string(port)(sc, buf, len, port);
35799     }
35800 
35801   if ((is_immutable(obj)) && (!is_let(obj)))
35802     port_write_string(port)(sc, "))\n", 3, port);
35803   else port_write_string(port)(sc, ")\n", 2, port);
35804 
35805   return(obj);
35806 }
35807 
35808 static void object_out_1(s7_scheme *sc, s7_pointer obj, s7_pointer strport, use_write_t choice)
35809 {
35810   if (sc->object_out_locked)
35811     object_to_port_with_circle_check(sc, T_Any(obj), strport, choice, sc->circle_info);
35812   else
35813     {
35814       shared_info_t *ci;
35815       ci = make_shared_info(sc, T_Any(obj), choice != P_READABLE);
35816       if (ci)
35817 	{
35818 	  sc->object_out_locked = true;
35819 	  if (choice == P_READABLE)
35820 	    cyclic_out(sc, obj, strport, ci);
35821 	  else object_to_port_with_circle_check(sc, obj, strport, choice, ci);
35822 	  sc->object_out_locked = false;
35823 	}
35824       else object_to_port(sc, obj, strport, choice, NULL);
35825     }
35826 }
35827 
35828 static inline s7_pointer object_out(s7_scheme *sc, s7_pointer obj, s7_pointer strport, use_write_t choice)
35829 {
35830   if ((has_structure(obj)) &&
35831       (obj != sc->rootlet))
35832     object_out_1(sc, obj, strport, choice);
35833   else object_to_port(sc, obj, strport, choice, NULL);
35834   return(obj);
35835 }
35836 
35837 static s7_pointer new_format_port(s7_scheme *sc)
35838 {
35839   s7_pointer x;
35840   s7_int len;
35841   block_t *block, *b;
35842 
35843   len = FORMAT_PORT_LENGTH;
35844   x = alloc_pointer(sc);
35845   set_full_type(x, T_OUTPUT_PORT);
35846   b = mallocate_port(sc);
35847   port_block(x) = b;
35848   port_port(x) = (port_t *)block_data(b);
35849   port_type(x) = STRING_PORT;
35850   port_set_closed(x, false);
35851   port_data_size(x) = len;
35852   port_next(x) = NULL;
35853   block = mallocate(sc, len);
35854   port_data(x) = (uint8_t *)(block_data(block));
35855   port_data_block(x) = block;
35856   port_data(x)[0] = '\0';
35857   port_position(x) = 0;
35858   port_needs_free(x) = false;
35859   port_port(x)->pf = &output_string_functions;
35860   return(x);
35861 }
35862 
35863 static inline s7_pointer open_format_port(s7_scheme *sc)
35864 {
35865   if (sc->format_ports)
35866     {
35867       s7_pointer x;
35868       x = sc->format_ports;
35869       sc->format_ports = (s7_pointer)(port_next(x));
35870       port_position(x) = 0;
35871       port_data(x)[0] = '\0';
35872       return(x);
35873     }
35874   return(new_format_port(sc));
35875 }
35876 
35877 static void close_format_port(s7_scheme *sc, s7_pointer port)
35878 {
35879   port_next(port) = (struct block_t *)(sc->format_ports);
35880   sc->format_ports = port;
35881 }
35882 
35883 char *s7_object_to_c_string(s7_scheme *sc, s7_pointer obj)
35884 {
35885   char *str;
35886   s7_pointer strport;
35887   s7_int len;
35888 
35889   TRACK(sc);
35890   if ((sc->safety > NO_SAFETY) &&
35891       (!s7_is_valid(sc, obj)))
35892     s7_warn(sc, 256, "bad arg to %s: %p\n", __func__, obj);
35893 
35894   strport = open_format_port(sc);
35895   object_out(sc, obj, strport, P_WRITE);
35896   len = port_position(strport);
35897   if (len == 0) {close_format_port(sc, strport); return(NULL);} /* probably never happens */
35898   str = (char *)Malloc(len + 1);
35899   memcpy((void *)str, (void *)port_data(strport), len);
35900   str[len] = '\0';
35901   close_format_port(sc, strport);
35902 
35903   return(str);
35904 }
35905 
35906 static inline void restore_format_port(s7_scheme *sc, s7_pointer strport)
35907 {
35908   block_t *block;
35909   block = mallocate(sc, FORMAT_PORT_LENGTH);
35910   port_data(strport) = (uint8_t *)(block_data(block));
35911   port_data_block(strport) = block;
35912   port_data(strport)[0] = '\0';
35913   port_position(strport) = 0;
35914   port_data_size(strport) = FORMAT_PORT_LENGTH;
35915   port_needs_free(strport) = false;
35916   close_format_port(sc, strport);
35917 }
35918 
35919 
35920 /* -------------------------------- object->string -------------------------------- */
35921 
35922 s7_pointer s7_object_to_string(s7_scheme *sc, s7_pointer obj, bool use_write) /* unavoidable backwards compatibility rigidity here */
35923 {
35924   s7_pointer strport, res;
35925 
35926   if ((sc->safety > NO_SAFETY) &&
35927       (!s7_is_valid(sc, obj)))
35928     s7_warn(sc, 256, "bad arg to %s: %p\n", __func__, obj);
35929 
35930   strport = open_format_port(sc);
35931   object_out(sc, obj, strport, (use_write) ? P_WRITE : P_DISPLAY);
35932 
35933   if (port_position(strport) >= port_data_size(strport))
35934     res = block_to_string(sc, reallocate(sc, port_data_block(strport), port_position(strport) + 1), port_position(strport));
35935   else res = block_to_string(sc, port_data_block(strport), port_position(strport));
35936   restore_format_port(sc, strport);
35937   return(res);
35938 }
35939 
35940 static s7_pointer g_object_to_string(s7_scheme *sc, s7_pointer args)
35941 {
35942   #define H_object_to_string "(object->string obj (write #t) (max-len most-positive-fixnum)) returns a string representation of obj."
35943   #define Q_object_to_string s7_make_signature(sc, 4, sc->is_string_symbol, sc->T, s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_keyword_symbol), sc->is_integer_symbol)
35944 
35945   use_write_t choice;
35946   s7_pointer obj, strport, res;
35947   s7_int out_len, pending_max;
35948   bool old_openlets;
35949 
35950   pending_max = S7_INT64_MAX;
35951   old_openlets = sc->has_openlets;
35952   obj = car(args);
35953 
35954   if (is_not_null(cdr(args)))
35955     {
35956       s7_pointer arg;
35957       arg = cadr(args);
35958       if (arg == sc->F) choice = P_DISPLAY;
35959       else {if (arg == sc->T) choice = P_WRITE;
35960 	else {if (arg == sc->key_readable_symbol) choice = P_READABLE;
35961 	  else {if (arg == sc->key_display_symbol) choice = P_DISPLAY;
35962 	    else {if (arg == sc->key_write_symbol) choice = P_WRITE;
35963 	      else return(wrong_type_argument_with_type(sc, sc->object_to_string_symbol, 2, arg, wrap_string(sc, "a boolean or :readable", 22)));}}}}
35964 
35965       if (is_not_null(cddr(args)))
35966 	{
35967 	  arg = caddr(args);
35968 	  if (!s7_is_integer(arg))
35969 	    {
35970 	      if (choice == P_READABLE) /* (object->string #r(1 2 3) :readable "hi") */
35971 		return(wrong_type_argument(sc, sc->object_to_string_symbol, 3, arg, T_INTEGER));
35972 	      return(method_or_bust(sc, arg, sc->object_to_string_symbol, args, T_INTEGER, 3));
35973 	    }
35974 	  if (s7_integer_checked(sc, arg) < 0)
35975 	    return(out_of_range(sc, sc->object_to_string_symbol, int_three, arg, a_non_negative_integer_string));
35976 	  pending_max = s7_integer_checked(sc, arg);
35977 	}}
35978   else choice = P_WRITE;
35979   /* can't use s7_object_to_string here anymore because it assumes use_write arg is a boolean */
35980 
35981   if (choice == P_READABLE)
35982     sc->has_openlets = false;
35983   else check_method(sc, obj, sc->object_to_string_symbol, args);
35984 
35985   strport = open_format_port(sc);
35986   sc->objstr_max_len = pending_max;
35987   object_out(sc, obj, strport, choice);
35988   sc->objstr_max_len = S7_INT64_MAX;
35989   out_len = port_position(strport);
35990 
35991   if ((pending_max >= 0) &&
35992       (out_len > pending_max))
35993     {
35994       s7_int i;
35995       if (choice == P_READABLE)  /* (object->string #r(1 2 3) :readable 4) */
35996 	{
35997 	  close_format_port(sc, strport);
35998 	  sc->has_openlets = old_openlets;
35999 	  return(out_of_range(sc, sc->object_to_string_symbol, int_three, wrap_integer1(sc, out_len), wrap_string(sc, "the readable string is too long", 31)));
36000 	}
36001       out_len = pending_max;
36002       if (out_len < 3)
36003 	{
36004 	  close_format_port(sc, strport);
36005 	  sc->has_openlets = old_openlets;
36006 	  return(make_string_with_length(sc, "...", 3));
36007 	}
36008       for (i = out_len - 3; i < out_len; i++)
36009 	port_data(strport)[i] = (uint8_t)'.';
36010     }
36011 
36012   if (out_len >= port_data_size(strport)) /* this can happen (but only == I think) */
36013     res = block_to_string(sc, reallocate(sc, port_data_block(strport), out_len + 1), out_len);
36014   else res = block_to_string(sc, port_data_block(strport), out_len);
36015   restore_format_port(sc, strport);
36016   sc->has_openlets = old_openlets;
36017   return(res);
36018 }
36019 
36020 
36021 /* -------------------------------- newline -------------------------------- */
36022 void s7_newline(s7_scheme *sc, s7_pointer port)
36023 {
36024   if (port != sc->F)
36025     port_write_character(port)(sc, (uint8_t)'\n', port);
36026 }
36027 
36028 #define newline_char chars[(uint8_t)'\n']
36029 
36030 static s7_pointer g_newline(s7_scheme *sc, s7_pointer args)
36031 {
36032   #define H_newline "(newline (port (current-output-port))) writes a carriage return to the port"
36033   #define Q_newline s7_make_signature(sc, 2, sc->is_char_symbol, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
36034   s7_pointer port;
36035 
36036   port = (is_not_null(args)) ? car(args) : current_output_port(sc);
36037   if (port == sc->F) return(newline_char);
36038   if (!is_output_port(port))
36039     return(method_or_bust_with_type_one_arg(sc, port, sc->newline_symbol, args, an_output_port_string));
36040   if (port_is_closed(port))
36041     s7_wrong_type_arg_error(sc, "newline", 1, port, "an open output port");
36042   s7_newline(sc, port);
36043   return(newline_char);  /* return(sc->unspecified) until 28-Sep-17, but for example (display c) returns c */
36044 }
36045 
36046 static s7_pointer newline_p(s7_scheme *sc)
36047 {
36048   s7_newline(sc, current_output_port(sc));
36049   return(newline_char);
36050 }
36051 
36052 static s7_pointer newline_p_p(s7_scheme *sc, s7_pointer port)
36053 {
36054   if (!is_output_port(port))
36055     {
36056       if (port == sc->F) return(newline_char);
36057       return(method_or_bust_with_type_one_arg_p(sc, port, sc->newline_symbol, an_output_port_string));
36058     }
36059   s7_newline(sc, port);
36060   return(newline_char);
36061 }
36062 
36063 
36064 /* -------------------------------- write -------------------------------- */
36065 s7_pointer s7_write(s7_scheme *sc, s7_pointer obj, s7_pointer port)
36066 {
36067   if (port != sc->F)
36068     {
36069       if (port_is_closed(port))
36070 	s7_wrong_type_arg_error(sc, "write", 2, port, "an open output port");
36071       object_out(sc, obj, port, P_WRITE);
36072     }
36073   return(obj);
36074 }
36075 
36076 static s7_pointer write_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer port)
36077 {
36078   if (port == sc->F) return(x);
36079   if (!is_output_port(port))
36080     return(method_or_bust_with_type_pp(sc, port, sc->write_symbol, x, port, an_output_port_string, 2));
36081   if (port_is_closed(port))
36082     s7_wrong_type_arg_error(sc, "write", 2, port, "an open output port");
36083   return(object_out(sc, x, port, P_WRITE));
36084 }
36085 
36086 static s7_pointer g_write(s7_scheme *sc, s7_pointer args)
36087 {
36088   #define H_write "(write obj (port (current-output-port))) writes (object->string obj) to the output port"
36089   #define Q_write s7_make_signature(sc, 3, sc->T, sc->T, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
36090 
36091   check_method(sc, car(args), sc->write_symbol, args);
36092   return(write_p_pp(sc, car(args), (is_pair(cdr(args))) ? cadr(args) : current_output_port(sc)));
36093 }
36094 
36095 static s7_pointer write_p_p(s7_scheme *sc, s7_pointer x)
36096 {
36097   return((current_output_port(sc) == sc->F) ? x : object_out(sc, x, current_output_port(sc), P_WRITE));
36098 }
36099 
36100 
36101 /* -------------------------------- display -------------------------------- */
36102 s7_pointer s7_display(s7_scheme *sc, s7_pointer obj, s7_pointer port)
36103 {
36104   if (port != sc->F)
36105     {
36106       if (port_is_closed(port))
36107 	s7_wrong_type_arg_error(sc, "display", 2, port, "an open output port");
36108       object_out(sc, obj, port, P_DISPLAY);
36109     }
36110   return(obj);
36111 }
36112 
36113 static s7_pointer display_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer port)
36114 {
36115   if (port == sc->F) return(x);
36116   if (!is_output_port(port))
36117     return(method_or_bust_with_type_pp(sc, port, sc->display_symbol, x, port, an_output_port_string, 2));
36118   if (port_is_closed(port))
36119     s7_wrong_type_arg_error(sc, "display", 2, port, "an open output port");
36120   check_method(sc, x, sc->display_symbol, set_plist_2(sc, x, port));
36121   return(object_out(sc, x, port, P_DISPLAY));
36122 }
36123 
36124 static s7_pointer g_display(s7_scheme *sc, s7_pointer args)
36125 {
36126   #define H_display "(display obj (port (current-output-port))) prints obj"
36127   #define Q_display s7_make_signature(sc, 3, sc->T, sc->T, s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->not_symbol))
36128 
36129   return(display_p_pp(sc, car(args), (is_pair(cdr(args))) ? cadr(args) : current_output_port(sc)));
36130 }
36131 
36132 static s7_pointer g_display_2(s7_scheme *sc, s7_pointer args)
36133 {
36134   /* calling display_p_pp here is much slower */
36135   s7_pointer port;
36136   port = cadr(args);
36137   if (port == sc->F) return(car(args));
36138   if (!is_output_port(port))
36139     return(method_or_bust_with_type(sc, port, sc->display_symbol, args, an_output_port_string, 2));
36140   if (port_is_closed(port))
36141     return(s7_wrong_type_arg_error(sc, "display", 2, port, "an open output port"));
36142   check_method(sc, car(args), sc->display_symbol, args);
36143   return(object_out(sc, car(args), port, P_DISPLAY));
36144 }
36145 
36146 static s7_pointer g_display_f(s7_scheme *sc, s7_pointer args) {return(car(args));}
36147 
36148 static s7_pointer display_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
36149 {
36150   if (args == 2) /* not check_for_substring_temp(sc, expr) here -- display returns arg so can be immutable if substring_uncopied */
36151     return((caddr(expr) == sc->F) ? sc->display_f : sc->display_2);
36152   return(f);
36153 }
36154 
36155 static s7_pointer display_p_p(s7_scheme *sc, s7_pointer x)
36156 {
36157   if (current_output_port(sc) == sc->F) return(x);
36158   check_method(sc, x, sc->display_symbol, set_plist_1(sc, x));
36159   return(object_out(sc, x, current_output_port(sc), P_DISPLAY));
36160 }
36161 
36162 
36163 /* -------------------------------- call-with-output-string -------------------------------- */
36164 static s7_pointer g_call_with_output_string(s7_scheme *sc, s7_pointer args)
36165 {
36166   #define H_call_with_output_string "(call-with-output-string proc) opens a string port applies proc to it, then returns the collected output"
36167   #define Q_call_with_output_string s7_make_signature(sc, 2, sc->is_string_symbol, s7_make_signature(sc, 2, sc->is_procedure_symbol, sc->is_macro_symbol))
36168   s7_pointer port, proc;
36169 
36170   proc = car(args);
36171   if (is_let(proc))
36172     check_method(sc, proc, sc->call_with_output_string_symbol, args);
36173   if ((!is_any_procedure(proc)) ||        /* this disallows goto/continuation */
36174       (!s7_is_aritable(sc, proc, 1)))
36175     return(method_or_bust_with_type(sc, proc, sc->call_with_output_string_symbol, args, wrap_string(sc, "a procedure of one argument (the port)", 38), 1));
36176 
36177   port = s7_open_output_string(sc);
36178   push_stack(sc, OP_UNWIND_OUTPUT, sc->unused, port);     /* #<unused> here is a marker (needed) */
36179   push_stack(sc, OP_GET_OUTPUT_STRING, sc->unused, port); /* args checked in call_with_exit */
36180   push_stack(sc, OP_APPLY, list_1(sc, port), proc);
36181   return(sc->F);
36182 }
36183 
36184 
36185 /* -------------------------------- call-with-output-file -------------------------------- */
36186 static s7_pointer g_call_with_output_file(s7_scheme *sc, s7_pointer args)
36187 {
36188   #define H_call_with_output_file "(call-with-output-file filename proc) opens filename and calls proc with the output port as its argument"
36189   #define Q_call_with_output_file sc->pl_sf
36190   s7_pointer port, file, proc;
36191 
36192   file = car(args);
36193   if (!is_string(file))
36194     return(method_or_bust(sc, file, sc->call_with_output_file_symbol, args, T_STRING, 1));
36195 
36196   proc = cadr(args);
36197   if ((!is_any_procedure(proc)) ||
36198       (!s7_is_aritable(sc, proc, 1)))
36199     return(method_or_bust_with_type(sc, proc, sc->call_with_output_file_symbol, args, wrap_string(sc, "a procedure of one argument (the port)", 38), 2));
36200 
36201   port = s7_open_output_file(sc, string_value(file), "w");
36202   push_stack(sc, OP_UNWIND_OUTPUT, sc->unused, port); /* #<unused> here is a marker (needed) */
36203   push_stack(sc, OP_APPLY, list_1(sc, port), proc);
36204   return(sc->F);
36205 }
36206 
36207 
36208 /* -------------------------------- with-output-to-string -------------------------------- */
36209 static s7_pointer g_with_output_to_string(s7_scheme *sc, s7_pointer args)
36210 {
36211   #define H_with_output_to_string "(with-output-to-string thunk) opens a string as a temporary current-output-port, calls thunk, then returns the collected output"
36212   #define Q_with_output_to_string s7_make_signature(sc, 2, sc->is_string_symbol, s7_make_signature(sc, 2, sc->is_procedure_symbol, sc->is_macro_symbol))
36213   s7_pointer old_output_port, p;
36214 
36215   p = car(args);
36216   if (!is_thunk(sc, p))
36217     return(method_or_bust_with_type(sc, p, sc->with_output_to_string_symbol, args, a_thunk_string, 1));
36218 
36219   if ((is_continuation(p)) || (is_goto(p)))
36220     return(wrong_type_argument_with_type(sc, sc->with_output_to_string_symbol, 1, p, a_normal_procedure_string));
36221 
36222   old_output_port = current_output_port(sc);
36223   set_current_output_port(sc, s7_open_output_string(sc));
36224   push_stack(sc, OP_UNWIND_OUTPUT, old_output_port, current_output_port(sc));
36225   push_stack(sc, OP_GET_OUTPUT_STRING, old_output_port, current_output_port(sc));
36226   push_stack(sc, OP_APPLY, sc->nil, p);
36227   return(sc->F);
36228 }
36229 
36230 /* (let () (define-macro (mac) (write "123")) (with-output-to-string mac))
36231  * (string-ref (with-output-to-string (lambda () (write "1234") (values (get-output-string) 1))))
36232  */
36233 
36234 
36235 /* -------------------------------- with-output-to-file -------------------------------- */
36236 static s7_pointer g_with_output_to_file(s7_scheme *sc, s7_pointer args)
36237 {
36238   #define H_with_output_to_file "(with-output-to-file filename thunk) opens filename as the temporary current-output-port and calls thunk"
36239   #define Q_with_output_to_file sc->pl_sf
36240   s7_pointer old_output_port, file, proc;
36241 
36242   file = car(args);
36243   if (!is_string(file))
36244     return(method_or_bust(sc, file, sc->with_output_to_file_symbol, args, T_STRING, 1));
36245 
36246   proc = cadr(args);
36247   if (!is_thunk(sc, proc))
36248     return(method_or_bust_with_type(sc, proc, sc->with_output_to_file_symbol, args, a_thunk_string, 2));
36249 
36250   if ((is_continuation(proc)) || (is_goto(proc)))
36251     return(wrong_type_argument_with_type(sc, sc->with_output_to_file_symbol, 1, proc, a_normal_procedure_string));
36252 
36253   old_output_port = current_output_port(sc);
36254   set_current_output_port(sc, s7_open_output_file(sc, string_value(file), "w"));
36255   push_stack(sc, OP_UNWIND_OUTPUT, old_output_port, current_output_port(sc));
36256   push_stack(sc, OP_APPLY, sc->nil, proc);
36257   return(sc->F);
36258 }
36259 
36260 
36261 /* -------------------------------- format -------------------------------- */
36262 
36263 static s7_pointer format_error_1(s7_scheme *sc, s7_pointer msg, const char *str, s7_pointer args, format_data_t *fdat)
36264 {
36265   s7_pointer x = NULL, ctrl_str;
36266 
36267   ctrl_str = (fdat->orig_str) ? fdat->orig_str : s7_make_string_wrapper(sc, str);
36268   if (fdat->loc == 0)
36269     {
36270       if (is_pair(args))
36271 	x = set_elist_4(sc, format_string_1, ctrl_str, args, msg);
36272       else x = set_elist_3(sc, format_string_2, ctrl_str, msg);
36273     }
36274   else
36275     {
36276       if (is_pair(args))
36277 	x = set_elist_5(sc, format_string_3, ctrl_str, args, wrap_integer1(sc, fdat->loc + 20), msg);
36278       else x = set_elist_4(sc, format_string_4, ctrl_str, wrap_integer1(sc, fdat->loc + 20), msg);
36279     }
36280   if (fdat->port)
36281     {
36282       close_format_port(sc, fdat->port);
36283       fdat->port = NULL;
36284     }
36285   return(s7_error(sc, sc->format_error_symbol, x));
36286 }
36287 
36288 #define format_error(Sc, Msg, Len, Str, Args, Fdat) return(format_error_1(Sc, wrap_string(Sc, Msg, Len), Str, Args, Fdat))
36289 #define just_format_error(Sc, Msg, Len, Str, Args, Fdat) format_error_1(Sc, wrap_string(Sc, Msg, Len), Str, Args, Fdat)
36290 
36291 static void format_append_char(s7_scheme *sc, char c, s7_pointer port)
36292 {
36293   port_write_character(port)(sc, c, port);
36294   sc->format_column++;
36295 
36296   /* if c is #\null, is this the right thing to do?
36297    * We used to return "1 2 3 4" because ~C was first turned into a string (empty in this case)
36298    *   (format #f "1 2~C3 4" #\null) -> "1 2"
36299    * Clisp does this:
36300    *   (format nil "1 2~C3 4" (int-char 0)) -> "1 23 4"
36301    * whereas sbcl says int-char is undefined, and Guile returns "1 2\x003 4"
36302    *
36303    * if -O3 compiler flag, we hit a segfault here during s7test
36304    */
36305 }
36306 
36307 static void format_append_newline(s7_scheme *sc, s7_pointer port)
36308 {
36309   port_write_character(port)(sc, '\n', port);
36310   sc->format_column = 0;
36311 }
36312 
36313 static void format_append_string(s7_scheme *sc, format_data_t *fdat, const char *str, s7_int len, s7_pointer port)
36314 {
36315   port_write_string(port)(sc, str, len, port);
36316   fdat->loc += len;
36317   sc->format_column += len;
36318 }
36319 
36320 static void format_append_chars(s7_scheme *sc, format_data_t *fdat, char pad, s7_int chars, s7_pointer port)
36321 {
36322   if (is_string_port(port))
36323     {
36324       if ((port_position(port) + chars) < port_data_size(port))
36325 	{
36326 	  local_memset((char *)port_data(port) + port_position(port), pad, chars);
36327 	  port_position(port) += chars;
36328 	}
36329       else
36330 	{
36331 	  s7_int new_len;
36332 	  new_len = port_position(port) + chars;
36333 	  resize_port_data(sc, port, new_len * 2);
36334 	  local_memset((char *)port_data(port) + port_position(port), pad, chars);
36335 	  port_position(port) = new_len;
36336 	}
36337       fdat->loc += chars;
36338       sc->format_column += chars;
36339     }
36340   else
36341     {
36342       block_t *b;
36343       char *str;
36344       b = mallocate(sc, chars + 1);
36345       str = (char *)block_data(b);
36346       local_memset((void *)str, pad, chars);
36347       str[chars] = '\0';
36348       format_append_string(sc, fdat, str, chars, port);
36349       liberate(sc, b);
36350     }
36351 }
36352 
36353 static s7_int format_read_integer(s7_int *cur_i, s7_int str_len, const char *str)
36354 {
36355   /* we know that str[*cur_i] is a digit */
36356   s7_int i, lval = 0;
36357   for (i = *cur_i; i < str_len - 1; i++)
36358     {
36359       int32_t dig;
36360       dig = digits[(uint8_t)str[i]];
36361       if (dig < 10)
36362 	{
36363 #if HAVE_OVERFLOW_CHECKS
36364 	  if ((multiply_overflow(lval, 10, &lval)) ||
36365 	      (add_overflow(lval, dig, &lval)))
36366 	    break;
36367 #else
36368 	  lval = dig + (lval * 10);
36369 #endif
36370 	}
36371       else break;
36372     }
36373   *cur_i = i;
36374   return(lval);
36375 }
36376 
36377 static void format_number(s7_scheme *sc, format_data_t *fdat, int32_t radix, s7_int width, s7_int precision, char float_choice, char pad, s7_pointer port)
36378 {
36379   char *tmp;
36380   block_t *b = NULL;
36381   s7_int nlen = 0;
36382   if (width < 0) width = 0;
36383 
36384   /* precision choice depends on float_choice if it's -1 */
36385   if (precision < 0)
36386     {
36387       if ((float_choice == 'e') ||
36388 	  (float_choice == 'f') ||
36389 	  (float_choice == 'g'))
36390 	precision = 6;
36391       else
36392 	/* in the "int" cases, precision depends on the arg type */
36393 	switch (type(car(fdat->args)))
36394 	  {
36395 	  case T_INTEGER:
36396 	  case T_RATIO:
36397 	    precision = 0;
36398 	    break;
36399 
36400 	  default:
36401 	    precision = 6;
36402 	    break;
36403 	  }}
36404   /* should (format #f "~F" 1/3) return "1/3"?? in CL it's "0.33333334" */
36405 
36406   if (pad != ' ')
36407     {
36408       char *padtmp;
36409 #if (!WITH_GMP)
36410       if (radix == 10)
36411 	tmp = number_to_string_base_10(sc, car(fdat->args), width, precision, float_choice, &nlen, P_WRITE);
36412       else
36413 #endif
36414 	{
36415 	  b = number_to_string_with_radix(sc, car(fdat->args), radix, width, precision, float_choice, &nlen);
36416 	  tmp = (char *)block_data(b);
36417 	}
36418       padtmp = tmp;
36419       while (*padtmp == ' ') (*(padtmp++)) = pad;
36420       format_append_string(sc, fdat, tmp, nlen, port);
36421       if ((WITH_GMP) || (radix != 10)) liberate(sc, b);
36422     }
36423   else
36424     {
36425 #if (!WITH_GMP)
36426       if (radix == 10)
36427 	tmp = number_to_string_base_10(sc, car(fdat->args), width, precision, float_choice, &nlen, P_WRITE);
36428       else
36429 #endif
36430 	{
36431 	  b = number_to_string_with_radix(sc, car(fdat->args), radix, width, precision, float_choice, &nlen);
36432 	  tmp = (char *)block_data(b);
36433 	}
36434       format_append_string(sc, fdat, tmp, nlen, port);
36435       if ((WITH_GMP) || (radix != 10)) liberate(sc, b);
36436     }
36437   fdat->args = cdr(fdat->args);
36438   fdat->ctr++;
36439 }
36440 
36441 static s7_int format_nesting(const char *str, char opener, char closer, s7_int start, s7_int end) /* start=i, end=str_len-1 */
36442 {
36443   s7_int k, nesting = 1;
36444   for (k = start + 2; k < end; k++)
36445     if (str[k] == '~')
36446       {
36447 	if (str[k + 1] == closer)
36448 	  {
36449 	    nesting--;
36450 	    if (nesting == 0)
36451 	      return(k - start - 1);
36452 	  }
36453 	else
36454 	  if (str[k + 1] == opener)
36455 	    nesting++;
36456       }
36457   return(-1);
36458 }
36459 
36460 static bool format_method(s7_scheme *sc, const char *str, format_data_t *fdat, s7_pointer port)
36461 {
36462   s7_pointer func, obj;
36463   char ctrl_str[3];
36464 
36465   obj = car(fdat->args);
36466   if ((!has_active_methods(sc, obj)) ||
36467       ((func = find_method_with_let(sc, obj, sc->format_symbol)) == sc->undefined))
36468     return(false);
36469 
36470   ctrl_str[0] = '~';
36471   ctrl_str[1] = str[0];
36472   ctrl_str[2] = '\0';
36473 
36474   if (port == obj)    /* a problem! we need the openlet port for format, but that's an infinite loop when it calls format again as obj */
36475     call_method(sc, obj, func, set_plist_3(sc, port, s7_make_string_wrapper(sc, ctrl_str), s7_make_string_wrapper(sc, "#<format port>")));
36476   else call_method(sc, obj, func, set_plist_3(sc, port, s7_make_string_wrapper(sc, ctrl_str), obj));
36477 
36478   fdat->args = cdr(fdat->args);
36479   fdat->ctr++;
36480   return(true);
36481 }
36482 
36483 static s7_int format_n_arg(s7_scheme *sc, const char *str, format_data_t *fdat, s7_pointer args)
36484 {
36485   s7_int n;
36486 
36487   if (is_null(fdat->args))          /* (format #f "~nT") */
36488     just_format_error(sc, "~~N: missing argument", 21, str, args, fdat);
36489   if (!s7_is_integer(car(fdat->args)))
36490     just_format_error(sc, "~~N: integer argument required", 30, str, args, fdat);
36491   n = s7_integer_checked(sc, car(fdat->args));
36492 
36493   if (n < 0)
36494     just_format_error(sc, "~~N value is negative?", 22, str, args, fdat);
36495   else
36496     if (n > sc->max_format_length)
36497       just_format_error(sc, "~~N value is too big", 20, str, args, fdat);
36498 
36499   fdat->args = cdr(fdat->args);    /* I don't think fdat->ctr should be incremented here -- it's for *vector-print-length* etc */
36500   return(n);
36501 }
36502 
36503 static s7_int format_numeric_arg(s7_scheme *sc, const char *str, s7_int str_len, format_data_t *fdat, s7_int *i)
36504 {
36505   s7_int width, old_i;
36506   old_i = *i;
36507   width = format_read_integer(i, str_len, str);
36508   if (width < 0)
36509     {
36510       if (str[old_i - 1] != ',') /* need branches here, not if-expr because just_format_error creates the permanent string */
36511 	just_format_error(sc, "width is negative?", 18, str, fdat->args, fdat);
36512       else just_format_error(sc, "precision is negative?", 22, str, fdat->args, fdat);
36513     }
36514   else
36515     if (width > sc->max_format_length)
36516       {
36517 	if (str[old_i - 1] != ',')
36518 	  just_format_error(sc, "width is too big", 16, str, fdat->args, fdat);
36519 	else just_format_error(sc, "precision is too big", 20, str, fdat->args, fdat);
36520       }
36521   return(width);
36522 }
36523 
36524 static format_data_t *open_format_data(s7_scheme *sc)
36525 {
36526   format_data_t *fdat;
36527   sc->format_depth++;
36528   if (sc->format_depth >= sc->num_fdats)
36529     {
36530       int32_t k, new_num_fdats;
36531       new_num_fdats = sc->format_depth * 2;
36532       sc->fdats = (format_data_t **)Realloc(sc->fdats, sizeof(format_data_t *) * new_num_fdats);
36533       for (k = sc->num_fdats; k < new_num_fdats; k++) sc->fdats[k] = NULL;
36534       sc->num_fdats = new_num_fdats;
36535     }
36536 
36537   fdat = sc->fdats[sc->format_depth];
36538   if (!fdat)
36539     {
36540       fdat = (format_data_t *)Malloc(sizeof(format_data_t));
36541       sc->fdats[sc->format_depth] = fdat;
36542       fdat->curly_len = 0;
36543       fdat->curly_str = NULL;
36544       fdat->ctr = 0;
36545     }
36546   else
36547     {
36548       if (fdat->port)
36549 	close_format_port(sc, fdat->port);
36550       if (fdat->strport)
36551 	close_format_port(sc, fdat->strport);
36552     }
36553   fdat->port = NULL;
36554   fdat->strport = NULL;
36555   fdat->loc = 0;
36556   fdat->curly_arg = sc->nil;
36557   return(fdat);
36558 }
36559 
36560 #if WITH_GMP
36561 static bool s7_is_one_or_big_one(s7_scheme *sc, s7_pointer p)
36562 {
36563   if (!is_big_number(p))
36564     return(s7_is_one(p));
36565 
36566   if (is_t_big_integer(p))
36567     return(mpz_cmp_ui(big_integer(p), 1) == 0);
36568 
36569   if (is_t_big_real(p))
36570     return(mpfr_cmp_d(big_real(p), 1.0) == 0);
36571 
36572   return(false);
36573 }
36574 #else
36575 #define s7_is_one_or_big_one(Sc, Num) s7_is_one(Num)
36576 #endif
36577 
36578 static s7_pointer object_to_list(s7_scheme *sc, s7_pointer obj);
36579 
36580 static s7_pointer format_to_port_1(s7_scheme *sc, s7_pointer port, const char *str, s7_pointer args,
36581 				   s7_pointer *next_arg, bool with_result, bool columnized, s7_int len, s7_pointer orig_str)
36582 {
36583   s7_int i, str_len;
36584   format_data_t *fdat;
36585   s7_pointer deferred_port;
36586 
36587   if (len <= 0)
36588     {
36589       str_len = safe_strlen(str);
36590       if (str_len == 0)
36591 	{
36592 	  if (is_not_null(args))
36593 	    return(s7_error(sc, sc->format_error_symbol,
36594 			    set_elist_2(sc, wrap_string(sc, "format control string is null, but there are arguments: ~S", 58), args)));
36595 	  return((with_result) ? make_empty_string(sc, 0, 0) : sc->F);
36596 	}}
36597   else str_len = len;
36598 
36599   fdat = open_format_data(sc);
36600   fdat->args = args;
36601   fdat->orig_str = orig_str;
36602 
36603   if (with_result)
36604     {
36605       deferred_port = port;
36606       port = open_format_port(sc);
36607       fdat->port = port;
36608     }
36609   else deferred_port = sc->F;
36610 
36611   for (i = 0; i < str_len - 1; i++)
36612     {
36613       if ((uint8_t)(str[i]) == (uint8_t)'~')
36614 	{
36615 	  use_write_t use_write;
36616 	  switch (str[i + 1])
36617 	    {
36618 	    case '%':                           /* -------- newline -------- */
36619 	      /* sbcl apparently accepts numeric args here (including 0) */
36620 
36621 	      if ((port_data(port)) &&
36622 		  (port_position(port) < port_data_size(port)))
36623 		{
36624 		  port_data(port)[port_position(port)++] = '\n';
36625 		  /* which is actually a bad idea, but as a desperate stopgap, I simply padded
36626 		   *  the string port string with 8 chars that are not in the length.
36627 		   */
36628 		  sc->format_column = 0;
36629 		}
36630 	      else format_append_newline(sc, port);
36631 	      i++;
36632 	      break;
36633 
36634 	    case '&':                           /* -------- conditional newline -------- */
36635 	      /* this only works if all output goes through format -- display/write for example do not update format_column */
36636 	      if (sc->format_column > 0)
36637 		format_append_newline(sc, port);
36638 	      i++;
36639 	      break;
36640 
36641 	    case '~':                           /* -------- tilde -------- */
36642 	      format_append_char(sc, '~', port);
36643 	      i++;
36644 	      break;
36645 
36646 	    case '\n':                          /* -------- trim white-space --------  so (format #f "hiho~\n") -> "hiho"! */
36647 	      for (i = i + 2; i <str_len - 1; i++)
36648 		if (!(white_space[(uint8_t)(str[i])]))
36649 		  {
36650 		    i--;
36651 		    break;
36652 		  }
36653 	      break;
36654 
36655 	    case '*':                           /* -------- ignore arg -------- */
36656 	      i++;
36657 	      if (is_null(fdat->args))          /* (format #f "~*~A") */
36658 		format_error(sc, "can't skip argument!", 20, str, args, fdat);
36659 	      fdat->args = cdr(fdat->args);
36660 	      break;
36661 
36662 	    case '|':                           /* -------- exit if args nil or ctr > (*s7* 'print-length) -------- */
36663 	      if ((is_pair(fdat->args)) &&
36664 		  (fdat->ctr >= sc->print_length))
36665 		{
36666 		  format_append_string(sc, fdat, " ...", 4, port);
36667 		  fdat->args = sc->nil;
36668 		}
36669 	      /* fall through */
36670 
36671 	    case '^':                           /* -------- exit -------- */
36672 	      if (is_null(fdat->args))
36673 		{
36674 		  i = str_len;
36675 		  goto ALL_DONE;
36676 		}
36677 	      i++;
36678 	      break;
36679 
36680 	    case '@':                           /* -------- plural, 'y' or 'ies' -------- */
36681 	      i += 2;
36682 	      if ((str[i] != 'P') && (str[i] != 'p'))
36683 		format_error(sc, "unknown '@' directive", 21, str, args, fdat);
36684 	      if (!is_pair(fdat->args))
36685 		format_error(sc, "'@' directive argument missing", 30, str, args, fdat);
36686 	      if (!s7_is_real(car(fdat->args)))        /* CL accepts non numbers here */
36687 		format_error(sc, "'@P' directive argument is not a real number", 44, str, args, fdat);
36688 
36689 	      if (!s7_is_one_or_big_one(sc, car(fdat->args)))
36690 		format_append_string(sc, fdat, "ies", 3, port);
36691 	      else format_append_char(sc, 'y', port);
36692 
36693 	      fdat->args = cdr(fdat->args);
36694 	      break;
36695 
36696 	    case 'P': case 'p':                 /* -------- plural in 's' -------- */
36697 	      if (!is_pair(fdat->args))
36698 		format_error(sc, "'P' directive argument missing", 30, str, args, fdat);
36699 	      if (!s7_is_real(car(fdat->args)))
36700 		format_error(sc, "'P' directive argument is not a real number", 43, str, args, fdat);
36701 	      if (!s7_is_one_or_big_one(sc, car(fdat->args)))
36702 		format_append_char(sc, 's', port);
36703 	      i++;
36704 	      fdat->args = cdr(fdat->args);
36705 	      break;
36706 
36707 	    case '{':                           /* -------- iteration -------- */
36708 	      {
36709 		s7_int curly_len;
36710 
36711 		if (is_null(fdat->args))
36712 		  format_error(sc, "missing argument", 16, str, args, fdat);
36713 
36714 		if ((is_pair(car(fdat->args))) &&               /* any sequence is possible here */
36715 		    (s7_list_length(sc, car(fdat->args)) < 0))  /* (format #f "~{~a~e~}" (cons 1 2)) */
36716 		  format_error(sc, "~{ argument is a dotted list", 28, str, args, fdat);
36717 
36718 		curly_len = format_nesting(str, '{', '}', i, str_len - 1);
36719 
36720 		if (curly_len == -1)
36721 		  format_error(sc, "'{' directive, but no matching '}'", 34, str, args, fdat);
36722 		if (curly_len == 1)
36723 		  format_error(sc, "~{~}' doesn't consume any arguments!", 36, str, args, fdat);
36724 
36725 		/* what about cons's here?  I can't see any way in CL either to specify the car or cdr of a cons within the format string
36726 		 *   (cons 1 2) is applicable: ((cons 1 2) 0) -> 1
36727 		 *   also there can be applicable objects that won't work in the map context (arg not integer etc)
36728 		 */
36729 		if (is_not_null(car(fdat->args)))               /* (format #f "~{~A ~}" ()) -> "" */
36730 		  {
36731 		    s7_pointer curly_arg;
36732 		    /* perhaps use an iterator here -- rootlet->list is expensive! */
36733 		    curly_arg = object_to_list(sc, car(fdat->args)); /* if a pair (or non-sequence), this simply returns the original */
36734 		    if (is_pair(curly_arg))                    /* (format #f "~{~A ~}" #()) -> "" */
36735 		      {
36736 			char *curly_str = NULL;                /* this is the local (nested) format control string */
36737 			s7_pointer orig_arg, cycle_arg;
36738 
36739 			fdat->curly_arg = curly_arg;
36740 			orig_arg = (curly_arg != car(fdat->args)) ? curly_arg : sc->nil;
36741 			if (curly_len > fdat->curly_len)
36742 			  {
36743 			    if (fdat->curly_str) free(fdat->curly_str);
36744 			    fdat->curly_len = curly_len;
36745 			    fdat->curly_str = (char *)Malloc(curly_len);
36746 			  }
36747 			curly_str = fdat->curly_str;
36748 			memcpy((void *)curly_str, (void *)(str + i + 2), curly_len - 1);
36749 			curly_str[curly_len - 1] = '\0';
36750 
36751 			if ((sc->format_depth < sc->num_fdats - 1) &&
36752 			    (sc->fdats[sc->format_depth + 1]))
36753 			  sc->fdats[sc->format_depth + 1]->ctr = 0;
36754 
36755 			/* it's not easy to use an iterator here instead of a list (so object->list isn't needed above),
36756 			 *   because the curly brackets may enclose multiple arguments -- we would need to use
36757 			 *   iterators throughout this function.
36758 			 */
36759 			cycle_arg = curly_arg;
36760 			while (is_pair(curly_arg))
36761 			  {
36762 			    s7_pointer new_arg = sc->nil;
36763 			    format_to_port_1(sc, port, curly_str, curly_arg, &new_arg, false, columnized, curly_len - 1, NULL);
36764 			    if (curly_arg == new_arg)
36765 			      {
36766 				if (cdr(curly_arg) == curly_arg) break;
36767 				fdat->curly_arg = sc->nil;
36768 				format_error(sc, "'{...}' doesn't consume any arguments!", 38, str, args, fdat);
36769 			      }
36770 			    curly_arg = new_arg;
36771 			    if ((!is_pair(curly_arg)) || (curly_arg == cycle_arg))
36772 			      break;
36773 			    cycle_arg = cdr(cycle_arg);
36774 			    format_to_port_1(sc, port, curly_str, curly_arg, &new_arg, false, columnized, curly_len - 1, NULL);
36775 			    curly_arg = new_arg;
36776 			  }
36777 			fdat->curly_arg = sc->nil;
36778 			while (is_pair(orig_arg)) /* free_cell below clears the type, so a circular list here is ok */
36779  			  {
36780  			    s7_pointer p;
36781  			    p = orig_arg;
36782  			    orig_arg = cdr(orig_arg);
36783  			    free_cell(sc, p);   /* if car(fdar->args) is a hash-table, we could also free_cell(car(p)), but not in any other case */
36784 			  }}
36785 		    else
36786 		      if (!is_null(curly_arg))
36787 			format_error(sc, "'{' directive argument should be a list or something we can turn into a list", 76, str, args, fdat);
36788 		  }
36789 
36790 		i += (curly_len + 2); /* jump past the ending '}' too */
36791 		fdat->args = cdr(fdat->args);
36792 		fdat->ctr++;
36793 	      }
36794 	      break;
36795 
36796 	    case '}':
36797 	      format_error(sc, "unmatched '}'", 13, str, args, fdat);
36798 
36799 	    case 'W': case 'w':
36800 	      use_write = P_READABLE;
36801 	      goto OBJSTR;
36802 
36803 	    case 'S': case 's':
36804 	      use_write = P_WRITE;
36805 	      goto OBJSTR;
36806 
36807 	    case 'A': case 'a':
36808 	      use_write = P_DISPLAY;
36809 	    OBJSTR:                        /* object->string */
36810 	      {
36811 		s7_pointer obj, strport;
36812 		if (is_null(fdat->args))
36813 		  format_error(sc, "missing argument", 16, str, args, fdat);
36814 
36815 		i++;
36816 		obj = car(fdat->args);
36817 		if ((use_write == P_READABLE) ||
36818 		    (!has_active_methods(sc, obj)) ||
36819 		    (!format_method(sc, (char *)(str + i), fdat, port)))
36820 		  {
36821 		    bool old_openlets;
36822 		    old_openlets = sc->has_openlets;
36823 		    /* for the column check, we need to know the length of the object->string output */
36824 		    if (columnized)
36825 		      {
36826 			strport = open_format_port(sc);
36827 			fdat->strport = strport;
36828 		      }
36829 		    else strport = port;
36830 		    if (use_write == P_READABLE)
36831 		      sc->has_openlets = false;
36832 		    object_out(sc, obj, strport, use_write);
36833 		    if (use_write == P_READABLE)
36834 		      sc->has_openlets = old_openlets;
36835 		    if (columnized)
36836 		      {
36837 			if (port_position(strport) >= port_data_size(strport))
36838 			  resize_port_data(sc, strport, port_data_size(strport) * 2);
36839 
36840 			port_data(strport)[port_position(strport)] = '\0';
36841 			if (port_position(strport) > 0)
36842 			  format_append_string(sc, fdat, (const char *)port_data(strport), port_position(strport), port);
36843 			close_format_port(sc, strport);
36844 			fdat->strport = NULL;
36845 		      }
36846 
36847 		    fdat->args = cdr(fdat->args);
36848 		    fdat->ctr++;
36849 		  }}
36850 	      break;
36851 
36852 	      /* -------- numeric args -------- */
36853 	    case '0': case '1': case '2': case '3': case '4': case '5':
36854 	    case '6': case '7': case '8': case '9': case ',':
36855 	    case 'N': case 'n':
36856 
36857 	    case 'B': case 'b':
36858 	    case 'D': case 'd':
36859 	    case 'E': case 'e':
36860 	    case 'F': case 'f':
36861 	    case 'G': case 'g':
36862 	    case 'O': case 'o':
36863 	    case 'X': case 'x':
36864 
36865 	    case 'T': case 't':
36866 	    case 'C': case 'c':
36867 	      {
36868 		s7_int width = -1, precision = -1;
36869 		char pad = ' ';
36870 		i++;                                      /* str[i] == '~' */
36871 
36872 		if (isdigit((int32_t)(str[i])))
36873 		  width = format_numeric_arg(sc, str, str_len, fdat, &i);
36874 		else
36875 		  if ((str[i] == 'N') || (str[i] == 'n'))
36876 		    {
36877 		      i++;
36878 		      width = format_n_arg(sc, str, fdat, args);
36879 		    }
36880 		if (str[i] == ',')
36881 		  {
36882 		    i++;                                  /* is (format #f "~12,12D" 1) an error?  The precision (or is it the width?) has no use here. */
36883 		    if (isdigit((int32_t)(str[i])))
36884 		      precision = format_numeric_arg(sc, str, str_len, fdat, &i);
36885 		    else
36886 		      {
36887 			if ((str[i] == 'N') || (str[i] == 'n'))
36888 			  {
36889 			    i++;
36890 			    precision = format_n_arg(sc, str, fdat, args);
36891 			  }
36892 			else
36893 			  if (str[i] == '\'')              /* (format #f "~12,'xD" 1) -> "xxxxxxxxxxx1" */
36894 			    {
36895 			      pad = str[i + 1];
36896 			      i += 2;
36897 			      if (i >= str_len)            /* (format #f "~,'") */
36898 				format_error(sc, "incomplete numeric argument", 27, str, args, fdat);
36899 			    }
36900 			/* is (let ((str "~12,'xD")) (set! (str 5) #\null) (format #f str 1)) an error? */
36901 		      }}
36902 
36903 		switch (str[i])
36904 		  {
36905 		    /* -------- pad to column --------
36906 		     *   are columns numbered from 1 or 0?  there seems to be disagreement about this directive
36907 		     *   does "space over to" mean including?
36908 		     */
36909 
36910 		  case 'T': case 't':
36911 		    if (width == -1) width = 0;
36912 		    if (precision == -1) precision = 0;
36913 		    if ((width > 0) || (precision > 0))         /* (format #f "a~8Tb") */
36914 		      {
36915 			/* (length (substring (format #f "~%~10T.") 1)) == (length (format #f "~10T."))
36916 			 * (length (substring (format #f "~%-~10T.~%") 1)) == (length (format #f "-~10T.~%"))
36917 			 */
36918 			if (precision > 0)
36919 			  {
36920 			    int32_t mult;
36921 			    mult = (int32_t)(ceil((s7_double)(sc->format_column + 1 - width) / (s7_double)precision)); /* CLtL2 ("least positive int") */
36922 			    if (mult < 1) mult = 1;
36923 			    width += (precision * mult);
36924 			  }
36925 			width -= (sc->format_column + 1);
36926 			if (width > 0)
36927 			  format_append_chars(sc, fdat, pad, width, port);
36928 		      }
36929 		    break;
36930 
36931 		  case 'C': case 'c':
36932 		    {
36933 		      s7_pointer obj;
36934 
36935 		      if (is_null(fdat->args))
36936 			format_error(sc, "~~C: missing argument", 21, str, args, fdat);
36937 		      /* the "~~" here and below protects against "~C" being treated as a directive */
36938 		      obj = car(fdat->args);
36939 
36940 		      if (!s7_is_character(obj))
36941 			{
36942 			  if (!format_method(sc, (char *)(str + i), fdat, port)) /* i stepped forward above */
36943 			    format_error(sc, "'C' directive requires a character argument", 43, str, args, fdat);
36944 			}
36945 		      else
36946 			{
36947 			  /* here use_write is false, so we just add the char, not its name */
36948 			  if (width == -1)
36949 			    format_append_char(sc, character(obj), port);
36950 			  else
36951 			    if (width > 0)
36952 			      format_append_chars(sc, fdat, character(obj), width, port);
36953 
36954 			  fdat->args = cdr(fdat->args);
36955 			  fdat->ctr++;
36956 			}}
36957 		    break;
36958 
36959 		    /* -------- numbers -------- */
36960 		  case 'F': case 'f':
36961 		    if (is_null(fdat->args))
36962 		      format_error(sc, "~~F: missing argument", 21, str, args, fdat);
36963 		    if (!(s7_is_number(car(fdat->args))))
36964 		      {
36965 			if (!format_method(sc, (char *)(str + i), fdat, port))
36966 			  format_error(sc, "~~F: numeric argument required", 30, str, args, fdat);
36967 		      }
36968 		    else format_number(sc, fdat, 10, width, precision, 'f', pad, port);
36969 		    break;
36970 
36971 		  case 'G': case 'g':
36972 		    if (is_null(fdat->args))
36973 		      format_error(sc, "~~G: missing argument", 21, str, args, fdat);
36974 		    if (!(s7_is_number(car(fdat->args))))
36975 		      {
36976 			if (!format_method(sc, (char *)(str + i), fdat, port))
36977 			  format_error(sc, "~~G: numeric argument required", 30, str, args, fdat);
36978 		      }
36979 		    else format_number(sc, fdat, 10, width, precision, 'g', pad, port);
36980 		    break;
36981 
36982 		  case 'E': case 'e':
36983 		    if (is_null(fdat->args))
36984 		      format_error(sc, "~~E: missing argument", 21, str, args, fdat);
36985 		    if (!(s7_is_number(car(fdat->args))))
36986 		      {
36987 			if (!format_method(sc, (char *)(str + i), fdat, port))
36988 			  format_error(sc, "~~E: numeric argument required", 30, str, args, fdat);
36989 		      }
36990 		    else format_number(sc, fdat, 10, width, precision, 'e', pad, port);
36991 		    break;
36992 
36993 		    /* how to handle non-integer arguments in the next 4 cases?  clisp just returns
36994 		     *   the argument: (format nil "~X" 1.25) -> "1.25" which is perverse (ClTl2 p 581:
36995 		     *   "if arg is not an integer, it is printed in ~A format and decimal base")!!
36996 		     *   I think I'll use the type of the number to choose the output format.
36997 		     */
36998 		  case 'D': case 'd':
36999 		    if (is_null(fdat->args))
37000 		      format_error(sc, "~~D: missing argument", 21, str, args, fdat);
37001 		    if (!(s7_is_number(car(fdat->args))))
37002 		      {
37003 			/* (let () (require mockery.scm) (format #f "~D" ((*mock-number* 'mock-number) 123)))
37004 			 *    port here is a string-port, str has the width/precision data if the caller wants it,
37005 			 *    args is the current arg.  But format_number handles fdat->args and so on, so
37006 			 *    I think I'll pass the format method the current control string (str), the
37007 			 *    current object (car(fdat->args)), and the arglist (args), and assume it will
37008 			 *    return a (scheme) string.
37009 			 */
37010 			if (!format_method(sc, (char *)(str + i), fdat, port))
37011 			  format_error(sc, "~~D: numeric argument required", 30, str, args, fdat);
37012 		      }
37013 		    else format_number(sc, fdat, 10, width, precision, 'd', pad, port);
37014 		    break;
37015 
37016 		  case 'O': case 'o':
37017 		    if (is_null(fdat->args))
37018 		      format_error(sc, "~~O: missing argument", 21, str, args, fdat);
37019 		    if (!(s7_is_number(car(fdat->args))))
37020 		      {
37021 			if (!format_method(sc, (char *)(str + i), fdat, port))
37022 			  format_error(sc, "~~O: numeric argument required", 30, str, args, fdat);
37023 		      }
37024 		    else format_number(sc, fdat, 8, width, precision, 'o', pad, port);
37025 		    break;
37026 
37027 		  case 'X': case 'x':
37028 		    if (is_null(fdat->args))
37029 		      format_error(sc, "~~X: missing argument", 21, str, args, fdat);
37030 		    if (!(s7_is_number(car(fdat->args))))
37031 		      {
37032 			if (!format_method(sc, (char *)(str + i), fdat, port))
37033 			  format_error(sc, "~~X: numeric argument required", 30, str, args, fdat);
37034 		      }
37035 		    else format_number(sc, fdat, 16, width, precision, 'x', pad, port);
37036 		    break;
37037 
37038 		  case 'B': case 'b':
37039 		    if (is_null(fdat->args))
37040 		      format_error(sc, "~~B: missing argument", 21, str, args, fdat);
37041 		    if (!(s7_is_number(car(fdat->args))))
37042 		      {
37043 			if (!format_method(sc, (char *)(str + i), fdat, port))
37044 			  format_error(sc, "~~B: numeric argument required", 30, str, args, fdat);
37045 		      }
37046 		    else format_number(sc, fdat, 2, width, precision, 'b', pad, port);
37047 		    break;
37048 
37049 		  default:
37050 		    if (width > 0)
37051 		      format_error(sc, "unused numeric argument", 23, str, args, fdat);
37052 		    format_error(sc, "unimplemented format directive", 30, str, args, fdat);
37053 		  }}
37054 	      break;
37055 
37056 	    default:
37057 	      format_error(sc, "unimplemented format directive", 30, str, args, fdat);
37058 	    }}
37059       else /* str[i] is not #\~ */
37060 	{
37061 	  s7_int j, new_len;
37062 	  const char *p;
37063 
37064 	  p = (char *)strchr((const char *)(str + i + 1), (int)'~');
37065 	  j = (p) ? p - str : str_len;
37066 	  new_len = j - i;
37067 
37068 	  if ((port_data(port)) &&
37069 	      ((port_position(port) + new_len) < port_data_size(port)))
37070 	    {
37071 	      memcpy((void *)(port_data(port) + port_position(port)), (void *)(str + i), new_len);
37072 	      port_position(port) += new_len;
37073 	    }
37074 	  else port_write_string(port)(sc, (char *)(str + i), new_len, port);
37075 	  fdat->loc += new_len;
37076 	  sc->format_column += new_len;
37077 	  i = j - 1;
37078 	}}
37079 
37080  ALL_DONE:
37081   if (next_arg)
37082     (*next_arg) = fdat->args;
37083   else
37084     if (is_not_null(fdat->args))
37085       format_error(sc, "too many arguments", 18, str, args, fdat);
37086 
37087   if (i < str_len)
37088     {
37089       if (str[i] == '~')
37090 	format_error(sc, "control string ends in tilde", 28, str, args, fdat);
37091       format_append_char(sc, str[i], port);
37092     }
37093 
37094   sc->format_depth--;
37095 
37096   if (with_result)
37097     {
37098       s7_pointer result;
37099       if ((is_output_port(deferred_port)) &&
37100 	  (port_position(port) > 0))
37101 	{
37102 	  if (port_position(port) < port_data_size(port))
37103 	    port_data(port)[port_position(port)] = '\0';
37104 	  port_write_string(deferred_port)(sc, (const char *)port_data(port), port_position(port), deferred_port);
37105 	}
37106       if (port_position(port) < port_data_size(port))
37107 	{
37108 	  block_t *block;
37109 	  result = block_to_string(sc, port_data_block(port), port_position(port));
37110 	  port_data_size(port) = FORMAT_PORT_LENGTH;
37111 	  block = mallocate(sc, FORMAT_PORT_LENGTH);
37112 	  port_data_block(port) = block;
37113 	  port_data(port) = (uint8_t *)(block_data(block));
37114 	  port_data(port)[0] = '\0';
37115 	  port_position(port) = 0;
37116 	}
37117       else result = make_string_with_length(sc, (char *)port_data(port), port_position(port));
37118       close_format_port(sc, port);
37119       fdat->port = NULL;
37120       return(result);
37121     }
37122   return(sc->F);
37123 }
37124 
37125 static bool is_columnizing(const char *str)
37126 {
37127   /* look for ~t ~,<int>T ~<int>,<int>t */
37128   char *p;
37129 
37130   for (p = (char *)str; (*p);)
37131     if (*p++ == '~') /* this is faster than strchr */
37132       {
37133 	char c;
37134 	c = *p++;
37135 	if ((c == 't') || (c == 'T')) return(true);
37136 	if (!c) return(false);
37137 	if ((c == ',') || ((c >= '0') && (c <= '9')) || (c == 'n') || (c == 'N'))
37138 	  {
37139 	    while (((c >= '0') && (c <= '9')) || (c == 'n') || (c == 'N')) c = *p++;
37140 	    if ((c == 't') || (c == 'T')) return(true);
37141 	    if (!c) return(false);                       /* ~,1 for example */
37142 	    if (c == ',')
37143 	      {
37144 		c = *p++;
37145 		while (((c >= '0') && (c <= '9')) || (c == 'n') || (c == 'N')) c = *p++;
37146 		if ((c == 't') || (c == 'T')) return(true);
37147 		if (!c) return(false);
37148 	      }}}
37149   return(false);
37150 }
37151 
37152 static s7_pointer format_to_port(s7_scheme *sc, s7_pointer port, const char *str, s7_pointer args, bool with_result, s7_int len)
37153 {
37154   if ((with_result) ||
37155       (port != sc->F))
37156     return(format_to_port_1(sc, port, str, args, NULL, with_result, true /* is_columnizing(str) */, len, NULL));
37157   /* is_columnizing on every call is much slower than ignoring the issue */
37158   return(sc->F);
37159 }
37160 
37161 static s7_pointer g_format(s7_scheme *sc, s7_pointer args)
37162 {
37163   #define H_format "(format out str . args) substitutes args into str sending the result to out. Most of \
37164 s7's format directives are taken from CL: ~% = newline, ~& = newline if the preceding output character was \
37165 no a newline, ~~ = ~, ~<newline> trims white space, ~* skips an argument, ~^ exits {} iteration if the arg list is exhausted, \
37166 ~nT spaces over to column n, ~A prints a representation of any object, ~S is the same, but puts strings in double quotes, \
37167 ~C prints a character, numbers are handled by ~F, ~E, ~G, ~B, ~O, ~D, and ~X with preceding numbers giving \
37168 spacing (and spacing character) and precision.  ~{ starts an embedded format directive which is ended by ~}: \n\
37169 \n\
37170   >(format #f \"dashed: ~{~A~^-~}\" '(1 2 3))\n\
37171   \"dashed: 1-2-3\"\n\
37172 \n\
37173 ~P inserts \"s\" if the current it is not 1 or 1.0 (use ~@P for \"ies\" or \"y\").\n\
37174 ~B is number->string in base 2, ~O in base 8, ~D base 10, ~X base 16,\n\
37175 ~E: (format #f \"~E\" 100.1) -&gt; \"1.001000e+02\" (%e in C)\n\
37176 ~F: (format #f \"~F\" 100.1) -&gt; \"100.100000\"   (%f in C)\n\
37177 ~G: (format #f \"~G\" 100.1) -&gt; \"100.1\"        (%g in C)\n\
37178 \n\
37179 If the 'out' it is not an output port, the resultant string is returned.  If it \
37180 is #t, the string is also sent to the current-output-port."
37181 
37182   #define Q_format s7_make_circular_signature(sc, 2, 3, s7_make_signature(sc, 2, sc->is_string_symbol, sc->not_symbol), s7_make_signature(sc, 3, sc->is_output_port_symbol, sc->is_boolean_symbol, sc->is_null_symbol), sc->T)
37183 
37184   s7_pointer pt, str;
37185   sc->format_column = 0;
37186   pt = car(args);
37187   if (is_null(pt))
37188     {
37189       pt = current_output_port(sc);          /* () -> (current-output-port) */
37190       if (pt == sc->F)                       /*   otherwise () -> #f so we get a returned string, which is confusing */
37191 	return(pt);                          /*   but this means some error checks are skipped? */
37192     }
37193 
37194   if (!((s7_is_boolean(pt)) ||               /* #f or #t */
37195 	((is_output_port(pt)) &&             /* (current-output-port) or call-with-open-file arg, etc */
37196 	 (!port_is_closed(pt)))))
37197     return(method_or_bust_with_type(sc, pt, sc->format_symbol, args, an_output_port_string, 1));
37198 
37199   str = cadr(args);
37200   if (!is_string(str))
37201     return(method_or_bust(sc, str, sc->format_symbol, args, T_STRING, 2));
37202 
37203   return(format_to_port_1(sc, (pt == sc->T) ? current_output_port(sc) : pt,
37204 			  string_value(str), cddr(args), NULL, !is_output_port(pt), true, string_length(str), str));
37205 }
37206 
37207 const char *s7_format(s7_scheme *sc, s7_pointer args)
37208 {
37209   s7_pointer result;
37210   result = g_format(sc, args);
37211   return((is_string(result)) ? string_value(result) : NULL);
37212 }
37213 
37214 static s7_pointer g_format_f(s7_scheme *sc, s7_pointer args)
37215 {
37216   /* port == #f, there are other args */
37217   s7_pointer str;
37218   sc->format_column = 0;
37219   str = cadr(args);
37220   if (!is_string(str))
37221     return(method_or_bust(sc, str, sc->format_symbol, args, T_STRING, 2));
37222   return(format_to_port_1(sc, sc->F, string_value(str), cddr(args), NULL, true, true, string_length(str), str));
37223 }
37224 
37225 static s7_pointer g_format_just_control_string(s7_scheme *sc, s7_pointer args)
37226 {
37227   s7_pointer pt, str;
37228   pt = car(args);
37229   str = cadr(args);
37230 
37231   if (pt == sc->F)
37232     return(str);
37233 
37234   if (is_null(pt))
37235     {
37236       pt = current_output_port(sc);
37237       if (pt == sc->F)
37238 	return(sc->F);
37239     }
37240   if (pt == sc->T)
37241     {
37242       if ((current_output_port(sc) != sc->F) && (string_length(str) != 0))
37243 	port_write_string(sc->output_port)(sc, string_value(str), string_length(str), current_output_port(sc));
37244       return(str);
37245     }
37246 
37247   if ((!is_output_port(pt)) ||
37248       (port_is_closed(pt)))
37249     return(method_or_bust_with_type(sc, pt, sc->format_symbol, args, a_format_port_string, 1));
37250 
37251   if (string_length(str) == 0)
37252     return((is_output_port(pt)) ? sc->F : make_empty_string(sc, 0, 0));
37253 
37254   port_write_string(pt)(sc, string_value(str), string_length(str), pt);
37255   return(sc->F);
37256 }
37257 
37258 static s7_pointer g_format_as_objstr(s7_scheme *sc, s7_pointer args)
37259 {
37260   s7_pointer func, obj;
37261 
37262   obj = caddr(args);
37263   if ((!has_active_methods(sc, obj)) ||
37264       ((func = find_method_with_let(sc, obj, sc->format_symbol)) == sc->undefined))
37265     return(s7_object_to_string(sc, obj, false));
37266 
37267   return(call_method(sc, obj, func, set_plist_3(sc, sc->F, cadr(args), obj)));
37268 }
37269 
37270 static s7_pointer g_format_no_column(s7_scheme *sc, s7_pointer args)
37271 {
37272   s7_pointer pt, str;
37273   pt = car(args);
37274   if (is_null(pt))
37275     {
37276       pt = current_output_port(sc);
37277       if (pt == sc->F)
37278 	return(sc->F);
37279     }
37280 
37281   if (!((s7_is_boolean(pt)) ||
37282 	((is_output_port(pt)) &&             /* (current-output-port) or call-with-open-file arg, etc */
37283 	 (!port_is_closed(pt)))))
37284     return(method_or_bust_with_type(sc, pt, sc->format_symbol, args, a_format_port_string, 1));
37285 
37286   str = cadr(args);
37287   sc->format_column = 0;
37288   return(format_to_port_1(sc, (pt == sc->T) ? current_output_port(sc) : pt,
37289 			  string_value(str), cddr(args), NULL,
37290 			  !is_output_port(pt),   /* i.e. is boolean port so we're returning a string */
37291 			  false,                 /* we checked in advance that it is not columnized */
37292 			  string_length(str),
37293 			  str));
37294 }
37295 
37296 static s7_pointer format_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
37297 {
37298   if (args > 1)
37299     {
37300       s7_pointer port, str_arg;
37301       port = cadr(expr);
37302       str_arg = caddr(expr);
37303       if (is_string(str_arg))
37304 	{
37305 	  if ((ops) && ((args == 2) || (args == 3)))
37306 	    {
37307 	      s7_int len;
37308 	      char *orig;
37309 	      const char *p;
37310 
37311 	      orig = string_value(str_arg);
37312 	      p = strchr((const char *)orig, (int)'~');
37313 	      if (!p)
37314 		return((args == 2) ? sc->format_just_control_string : f);
37315 
37316 	      len = string_length(str_arg);
37317 	      if ((args == 2) &&
37318 		  (len > 1) &&
37319 		  (orig[len - 1] == '%') &&
37320 		  ((p - orig) == len - 2))
37321 		{
37322 		  orig[len - 2] = '\n';
37323 		  orig[len - 1] = '\0';
37324 		  string_length(str_arg) = len - 1;
37325 		  return(sc->format_just_control_string);
37326 		}
37327 
37328 	      if ((args == 3) &&
37329 		  (len == 2) &&
37330 		  (port == sc->F) &&
37331 		  (orig[0] == '~') &&
37332 		  ((orig[1] == 'A') || (orig[1] == 'a')))
37333 		return(sc->format_as_objstr);
37334 	    }
37335 
37336 	  /* this used to worry about optimized expr and particular cases -- why? I can't find a broken case */
37337 	  if (!is_columnizing(string_value(str_arg)))
37338 	    return(sc->format_no_column);
37339 	}
37340       if (port == sc->F)
37341 	return(sc->format_f);
37342     }
37343   return(f);
37344 }
37345 
37346 
37347 /* -------------------------------- system extras -------------------------------- */
37348 
37349 #if WITH_SYSTEM_EXTRAS
37350 #include <fcntl.h>
37351 
37352 /* -------------------------------- directory? -------------------------------- */
37353 static s7_pointer g_is_directory(s7_scheme *sc, s7_pointer args)
37354 {
37355   #define H_is_directory "(directory? str) returns #t if str is the name of a directory"
37356   #define Q_is_directory s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_string_symbol)
37357   s7_pointer name;
37358   name = car(args);
37359 
37360   if (!is_string(name))
37361     return(method_or_bust_one_arg(sc, name, sc->is_directory_symbol, args, T_STRING));
37362   return(s7_make_boolean(sc, is_directory(string_value(name))));
37363 }
37364 
37365 static bool is_directory_b_7p(s7_scheme *sc, s7_pointer p)
37366 {
37367   if (!is_string(p))
37368     simple_wrong_type_argument(sc, sc->is_directory_symbol, p, T_STRING);
37369   return(is_directory(string_value(p)));
37370 }
37371 
37372 static bool file_probe(const char *arg)
37373 {
37374 #if (!MS_WINDOWS)
37375   return(access(arg, F_OK) == 0);
37376 #else
37377   int32_t fd;
37378   fd = open(arg, O_RDONLY, 0);
37379   if (fd == -1) return(false);
37380   close(fd);
37381   return(true);
37382 #endif
37383 }
37384 
37385 /* -------------------------------- file-exists? -------------------------------- */
37386 static s7_pointer g_file_exists(s7_scheme *sc, s7_pointer args)
37387 {
37388   #define H_file_exists "(file-exists? filename) returns #t if the file exists"
37389   #define Q_file_exists s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_string_symbol)
37390 
37391   s7_pointer name;
37392   name = car(args);
37393 
37394   if (!is_string(name))
37395     return(method_or_bust_one_arg(sc, name, sc->file_exists_symbol, args, T_STRING));
37396   return(s7_make_boolean(sc, file_probe(string_value(name))));
37397 }
37398 
37399 static bool file_exists_b_7p(s7_scheme *sc, s7_pointer p)
37400 {
37401   if (!is_string(p))
37402     simple_wrong_type_argument(sc, sc->file_exists_symbol, p, T_STRING);
37403   return(file_probe(string_value(p)));
37404 }
37405 
37406 /* -------------------------------- delete-file -------------------------------- */
37407 static s7_pointer g_delete_file(s7_scheme *sc, s7_pointer args)
37408 {
37409   #define H_delete_file "(delete-file filename) deletes the file filename."
37410   #define Q_delete_file s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_string_symbol)
37411 
37412   s7_pointer name;
37413   name = car(args);
37414 
37415   if (!is_string(name))
37416     return(method_or_bust_one_arg(sc, name, sc->delete_file_symbol, args, T_STRING));
37417   return(make_integer(sc, unlink(string_value(name))));
37418 }
37419 
37420 /* -------------------------------- getenv -------------------------------- */
37421 static s7_pointer g_getenv(s7_scheme *sc, s7_pointer args)
37422 {
37423   #define H_getenv "(getenv var) returns the value of an environment variable."
37424   #define Q_getenv sc->pcl_s
37425 
37426   s7_pointer name;
37427   name = car(args);
37428 
37429   if (!is_string(name))
37430     return(method_or_bust_one_arg(sc, name, sc->getenv_symbol, args, T_STRING));
37431   return(s7_make_string(sc, getenv(string_value(name))));
37432 }
37433 
37434 /* -------------------------------- system -------------------------------- */
37435 static s7_pointer g_system(s7_scheme *sc, s7_pointer args)
37436 {
37437   #define H_system "(system command) executes the command.  If the optional second argument is #t, \
37438 system captures the output as a string and returns it."
37439   #define Q_system s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_string_symbol), sc->is_string_symbol, sc->is_boolean_symbol)
37440 
37441 #ifdef __EMSCRIPTEN__
37442   return s7_nil(sc);
37443 #else
37444   s7_pointer name;
37445   name = car(args);
37446 
37447   if (!is_string(name))
37448     return(method_or_bust_one_arg(sc, name, sc->system_symbol, args, T_STRING));
37449 
37450   if ((is_pair(cdr(args))) &&
37451       (cadr(args) == sc->T))
37452     {
37453       #define BUF_SIZE 256
37454       char buf[BUF_SIZE];
37455       char *str = NULL;
37456       int32_t cur_len = 0, full_len = 0;
37457       FILE *fd;
37458 
37459       fd = popen(string_value(name), "r");
37460       while (fgets(buf, BUF_SIZE, fd))
37461 	{
37462 	  s7_int buf_len;
37463 	  buf_len = safe_strlen(buf);
37464 	  if (cur_len + buf_len >= full_len)
37465 	    {
37466 	      full_len += BUF_SIZE * 2;
37467 	      str = (str) ? (char *)Realloc(str, full_len) : (char *)Malloc(full_len);
37468 	    }
37469 	  memcpy((void *)(str + cur_len), (void *)buf, buf_len);
37470 	  cur_len += buf_len;
37471 	}
37472       pclose(fd);
37473       if (str)
37474 	{
37475 	  block_t *b;
37476 	  b = mallocate_block(sc);
37477 	  block_data(b) = (void *)str;
37478 	  block_set_index(b, TOP_BLOCK_LIST);
37479 	  return(block_to_string(sc, b, cur_len));
37480 	}
37481       return(make_empty_string(sc, 0, 0));
37482     }
37483   return(make_integer(sc, system(string_value(name))));
37484 #endif
37485 }
37486 
37487 
37488 #if (!MS_WINDOWS)
37489 #include <dirent.h>
37490 
37491 /* -------------------------------- directory->list -------------------------------- */
37492 static s7_pointer g_directory_to_list(s7_scheme *sc, s7_pointer args)
37493 {
37494   s7_pointer name;
37495   DIR *dpos;
37496   s7_pointer result;
37497 
37498   #define H_directory_to_list "(directory->list directory) returns the contents of the directory as a list of strings (filenames)."
37499   #define Q_directory_to_list s7_make_signature(sc, 2, sc->is_list_symbol, sc->is_string_symbol)   /* can return nil */
37500 
37501   name = car(args);
37502   if (!is_string(name))
37503     return(method_or_bust_one_arg_p(sc, name, sc->directory_to_list_symbol, T_STRING));
37504 
37505   sc->w = sc->nil;
37506   if ((dpos = opendir(string_value(name))))
37507     {
37508       struct dirent *dirp;
37509       while ((dirp = readdir(dpos)))
37510 	sc->w = cons(sc, s7_make_string(sc, dirp->d_name), sc->w);
37511       closedir(dpos);
37512     }
37513 
37514   result = sc->w;
37515   sc->w = sc->nil;
37516   return(result);
37517 }
37518 
37519 /* -------------------------------- file-mtime -------------------------------- */
37520 static s7_pointer g_file_mtime(s7_scheme *sc, s7_pointer args)
37521 {
37522   #define H_file_mtime "(file-mtime file): return the write date of file"
37523   #define Q_file_mtime s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_string_symbol)
37524 
37525   struct stat statbuf;
37526   int32_t err;
37527   s7_pointer name;
37528 
37529   name = car(args);
37530   if (!is_string(name))
37531     return(method_or_bust_one_arg(sc, name, sc->file_mtime_symbol, args, T_STRING));
37532 
37533   err = stat(string_value(name), &statbuf);
37534   if (err < 0)
37535     return(file_error(sc, "file-mtime", strerror(errno), string_value(name)));
37536 
37537   return(make_integer(sc, (s7_int)(statbuf.st_mtime)));
37538 }
37539 #endif
37540 #endif /* with_system_extras */
37541 
37542 
37543 /* -------------------------------- lists -------------------------------- */
37544 
37545 s7_pointer s7_cons(s7_scheme *sc, s7_pointer a, s7_pointer b)
37546 {
37547   s7_pointer x;
37548   new_cell(sc, x, T_PAIR | T_SAFE_PROCEDURE);
37549   set_car(x, a);
37550   set_cdr(x, b);
37551   return(x);
37552 }
37553 
37554 static s7_pointer cons_unchecked(s7_scheme *sc, s7_pointer a, s7_pointer b)
37555 {
37556   /* apparently slightly faster as a function? */
37557   s7_pointer x;
37558   new_cell_no_check(sc, x, T_PAIR | T_SAFE_PROCEDURE);
37559   set_car(x, a);
37560   set_cdr(x, b);
37561   return(x);
37562 }
37563 
37564 static s7_pointer cons_unchecked_with_type(s7_scheme *sc, s7_pointer p, s7_pointer a, s7_pointer b)
37565 {
37566   /* apparently slightly faster as a function? (used only in copy_tree_with_type) */
37567   s7_pointer x;
37568   new_cell_no_check(sc, x, full_type(p) & (TYPE_MASK | T_IMMUTABLE | T_SAFE_PROCEDURE));
37569   set_car(x, a);
37570   set_cdr(x, b);
37571   return(x);
37572 }
37573 
37574 static s7_pointer permanent_cons(s7_scheme *sc, s7_pointer a, s7_pointer b, uint64_t type)
37575 {
37576   s7_pointer x;
37577   x = alloc_pointer(sc);
37578   set_full_type(x, type | T_UNHEAP);
37579   set_car(x, a);
37580   set_cdr(x, b);
37581   return(x);
37582 }
37583 
37584 static s7_pointer permanent_list(s7_scheme *sc, s7_int len)
37585 {
37586   s7_int j;
37587   s7_pointer p;
37588   p = sc->nil;
37589   for (j = 0; j < len; j++)
37590     p = permanent_cons(sc, sc->nil, p, T_PAIR | T_IMMUTABLE);
37591   return(p);
37592 }
37593 
37594 static void check_sig_entry(s7_scheme *sc, s7_pointer p, s7_int pos, bool circle)
37595 {
37596   if ((!is_normal_symbol(car(p))) &&
37597       (!s7_is_boolean(car(p))) &&
37598       (!is_pair(car(p))))
37599     {
37600       s7_warn(sc, 512, "s7_make_%ssignature got an invalid entry at position %" print_s7_int ": (", (circle) ? "circular_" : "", pos);
37601       set_car(p, sc->nil);
37602     }
37603 }
37604 
37605 s7_pointer s7_make_signature(s7_scheme *sc, s7_int len, ...)
37606 {
37607   va_list ap;
37608   s7_int i;
37609   s7_pointer p, res;
37610 
37611   res = permanent_list(sc, len);
37612   va_start(ap, len);
37613   for (p = res, i = 0; is_pair(p); p = cdr(p), i++)
37614     {
37615       set_car(p, va_arg(ap, s7_pointer));
37616       check_sig_entry(sc, p, i, false);
37617     }
37618   va_end(ap);
37619 
37620   return((s7_pointer)res);
37621 }
37622 
37623 s7_pointer s7_make_circular_signature(s7_scheme *sc, s7_int cycle_point, s7_int len, ...)
37624 {
37625   va_list ap;
37626   s7_int i;
37627   s7_pointer p, res, back = NULL, end = NULL;
37628 
37629   res = permanent_list(sc, len);
37630   va_start(ap, len);
37631   for (p = res, i = 0; is_pair(p); p = cdr(p), i++)
37632     {
37633       set_car(p, va_arg(ap, s7_pointer));
37634       check_sig_entry(sc, p, i, true);
37635       if (i == cycle_point) back = p;
37636       if (i == (len - 1)) end = p;
37637     }
37638   va_end(ap);
37639   if (end) set_cdr(end, back);
37640   if (i < len)
37641     s7_warn(sc, 256, "s7_make_circular_signature got too few entries: %s\n", s7_object_to_c_string(sc, res));
37642   return((s7_pointer)res);
37643 }
37644 
37645 
37646 bool s7_is_pair(s7_pointer p) {return(is_pair(p));}
37647 static s7_pointer is_pair_p_p(s7_scheme *sc, s7_pointer p) {return((is_pair(p)) ? sc->T : sc->F);}
37648 
37649 s7_pointer s7_car(s7_pointer p) {return(car(p));}
37650 s7_pointer s7_cdr(s7_pointer p) {return(cdr(p));}
37651 
37652 s7_pointer s7_cadr(s7_pointer p) {return(cadr(p));}
37653 s7_pointer s7_cddr(s7_pointer p) {return(cddr(p));}
37654 s7_pointer s7_cdar(s7_pointer p) {return(cdar(p));}
37655 s7_pointer s7_caar(s7_pointer p) {return(caar(p));}
37656 
37657 s7_pointer s7_caadr(s7_pointer p) {return(caadr(p));}
37658 s7_pointer s7_caddr(s7_pointer p) {return(caddr(p));}
37659 s7_pointer s7_cadar(s7_pointer p) {return(cadar(p));}
37660 s7_pointer s7_caaar(s7_pointer p) {return(caaar(p));}
37661 s7_pointer s7_cdadr(s7_pointer p) {return(cdadr(p));}
37662 s7_pointer s7_cdddr(s7_pointer p) {return(cdddr(p));}
37663 s7_pointer s7_cddar(s7_pointer p) {return(cddar(p));}
37664 s7_pointer s7_cdaar(s7_pointer p) {return(cdaar(p));}
37665 
37666 s7_pointer s7_caaadr(s7_pointer p) {return(caaadr(p));}
37667 s7_pointer s7_caaddr(s7_pointer p) {return(caaddr(p));}
37668 s7_pointer s7_caadar(s7_pointer p) {return(caadar(p));}
37669 s7_pointer s7_caaaar(s7_pointer p) {return(caaaar(p));}
37670 s7_pointer s7_cadadr(s7_pointer p) {return(cadadr(p));}
37671 s7_pointer s7_cadddr(s7_pointer p) {return(cadddr(p));}
37672 s7_pointer s7_caddar(s7_pointer p) {return(caddar(p));}
37673 s7_pointer s7_cadaar(s7_pointer p) {return(cadaar(p));}
37674 
37675 s7_pointer s7_cdaadr(s7_pointer p) {return(cdaadr(p));}
37676 s7_pointer s7_cdaddr(s7_pointer p) {return(cdaddr(p));}
37677 s7_pointer s7_cdadar(s7_pointer p) {return(cdadar(p));}
37678 s7_pointer s7_cdaaar(s7_pointer p) {return(cdaaar(p));}
37679 s7_pointer s7_cddadr(s7_pointer p) {return(cddadr(p));}
37680 s7_pointer s7_cddddr(s7_pointer p) {return(cddddr(p));}
37681 s7_pointer s7_cdddar(s7_pointer p) {return(cdddar(p));}
37682 s7_pointer s7_cddaar(s7_pointer p) {return(cddaar(p));}
37683 
37684 s7_pointer s7_set_car(s7_pointer p, s7_pointer q)
37685 {
37686   set_car(p, q);
37687   return(q);  /* was p? 5-Aug-17 */
37688 }
37689 
37690 s7_pointer s7_set_cdr(s7_pointer p, s7_pointer q)
37691 {
37692   set_cdr(p, q);
37693   return(q);  /* was p? 5-Aug-17 */
37694 }
37695 
37696 
37697 /* -------------------------------------------------------------------------------- */
37698 
37699 s7_pointer s7_apply_1(s7_scheme *sc, s7_pointer args, s7_pointer (*f1)(s7_pointer a1))
37700 {
37701   /* not currently used */
37702   return(f1(car(args)));
37703 }
37704 
37705 s7_pointer s7_apply_2(s7_scheme *sc, s7_pointer args, s7_pointer (*f2)(s7_pointer a1, s7_pointer a2))
37706 {
37707   return(f2(car(args), cadr(args)));
37708 }
37709 
37710 s7_pointer s7_apply_3(s7_scheme *sc, s7_pointer args, s7_pointer (*f3)(s7_pointer a1, s7_pointer a2, s7_pointer a3))
37711 {
37712   s7_pointer a1;
37713   a1 = car(args);  args = cdr(args);
37714   return(f3(a1, car(args), cadr(args)));
37715 }
37716 
37717 s7_pointer s7_apply_4(s7_scheme *sc, s7_pointer args, s7_pointer (*f4)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4))
37718 {
37719   s7_pointer a1, a2;
37720   a1 = car(args);  a2 = cadr(args);  args = cddr(args);
37721   return(f4(a1, a2, car(args), cadr(args)));
37722 }
37723 
37724 s7_pointer s7_apply_5(s7_scheme *sc, s7_pointer args, s7_pointer (*f5)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4, s7_pointer a5))
37725 {
37726   s7_pointer a1, a2, a3, a4;
37727   a1 = car(args);  a2 = cadr(args);  args = cddr(args); a3 = car(args);  a4 = cadr(args);  args = cddr(args);
37728   return(f5(a1, a2, a3, a4, car(args)));
37729 }
37730 
37731 s7_pointer s7_apply_6(s7_scheme *sc, s7_pointer args, s7_pointer (*f6)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4, s7_pointer a5, s7_pointer a6))
37732 {
37733   s7_pointer a1, a2, a3, a4;
37734   a1 = car(args);  a2 = cadr(args);  args = cddr(args); a3 = car(args);  a4 = cadr(args);  args = cddr(args);
37735   return(f6(a1, a2, a3, a4, car(args), cadr(args)));
37736 }
37737 
37738 s7_pointer s7_apply_7(s7_scheme *sc, s7_pointer args,
37739 		      s7_pointer (*f7)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4, s7_pointer a5, s7_pointer a6, s7_pointer a7))
37740 {
37741   s7_pointer a1, a2, a3, a4, a5, a6;
37742   a1 = car(args);  a2 = cadr(args);  args = cddr(args); a3 = car(args);  a4 = cadr(args);  args = cddr(args); a5 = car(args);  a6 = cadr(args);  args = cddr(args);
37743   return(f7(a1, a2, a3, a4, a5, a6, car(args)));
37744 }
37745 
37746 s7_pointer s7_apply_8(s7_scheme *sc, s7_pointer args,
37747 		      s7_pointer (*f8)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4, s7_pointer a5, s7_pointer a6, s7_pointer a7, s7_pointer a8))
37748 {
37749   s7_pointer a1, a2, a3, a4, a5, a6;
37750   a1 = car(args);  a2 = cadr(args);  args = cddr(args); a3 = car(args);  a4 = cadr(args);  args = cddr(args); a5 = car(args);  a6 = cadr(args);  args = cddr(args);
37751   return(f8(a1, a2, a3, a4, a5, a6, car(args), cadr(args)));
37752 }
37753 
37754 s7_pointer s7_apply_9(s7_scheme *sc, s7_pointer args, s7_pointer (*f9)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4,
37755 								       s7_pointer a5, s7_pointer a6, s7_pointer a7, s7_pointer a8, s7_pointer a9))
37756 {
37757   s7_pointer a1, a2, a3, a4, a5, a6;
37758   a1 = car(args);  a2 = cadr(args);  args = cddr(args); a3 = car(args);  a4 = cadr(args);  args = cddr(args); a5 = car(args);  a6 = cadr(args);  args = cddr(args);
37759   return(f9(a1, a2, a3, a4, a5, a6, car(args), cadr(args), caddr(args)));
37760 }
37761 
37762 s7_pointer s7_apply_n_1(s7_scheme *sc, s7_pointer args, s7_pointer (*f1)(s7_pointer a1))
37763 {
37764   if (is_pair(args))
37765     return(f1(car(args)));
37766   return(f1(sc->undefined));
37767 }
37768 
37769 s7_pointer s7_apply_n_2(s7_scheme *sc, s7_pointer args, s7_pointer (*f2)(s7_pointer a1, s7_pointer a2))
37770 {
37771   if (is_pair(args))
37772     return((is_pair(cdr(args))) ? f2(car(args), cadr(args)) : f2(car(args), sc->undefined));
37773   return(f2(sc->undefined, sc->undefined));
37774 }
37775 
37776 s7_pointer s7_apply_n_3(s7_scheme *sc, s7_pointer args, s7_pointer (*f3)(s7_pointer a1, s7_pointer a2, s7_pointer a3))
37777 {
37778   if (is_pair(args))
37779     {
37780       s7_pointer a1;
37781       a1 = car(args); args = cdr(args);
37782       if (is_pair(args))
37783 	{
37784 	  s7_pointer a2;
37785 	  a2 = car(args);
37786 	  return((is_pair(cdr(args))) ? f3(a1, a2, cadr(args)) : f3(a1, a2, sc->undefined));
37787 	}
37788       return(f3(a1, sc->undefined, sc->undefined));
37789     }
37790   return(f3(sc->undefined, sc->undefined, sc->undefined));
37791 }
37792 
37793 #define apply_n_args(N) \
37794   do {int32_t i; s7_pointer p; for (i = 0, p = args; is_pair(p); p = cdr(p), i++) a[i] = car(p); for (; i < N; i++) a[i] = sc->undefined;} while (0)
37795 
37796 s7_pointer s7_apply_n_4(s7_scheme *sc, s7_pointer args, s7_pointer (*f4)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4))
37797 {
37798   s7_pointer a[4];
37799   apply_n_args(4);
37800   return(f4(a[0], a[1], a[2], a[3]));
37801 }
37802 
37803 s7_pointer s7_apply_n_5(s7_scheme *sc, s7_pointer args,
37804 			s7_pointer (*f5)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4, s7_pointer a5))
37805 {
37806   s7_pointer a[5];
37807   apply_n_args(5);
37808   return(f5(a[0], a[1], a[2], a[3], a[4]));
37809 }
37810 
37811 s7_pointer s7_apply_n_6(s7_scheme *sc, s7_pointer args,
37812 			s7_pointer (*f6)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4, s7_pointer a5, s7_pointer a6))
37813 {
37814   s7_pointer a[6];
37815   apply_n_args(6);
37816   return(f6(a[0], a[1], a[2], a[3], a[4], a[5]));
37817 }
37818 
37819 s7_pointer s7_apply_n_7(s7_scheme *sc, s7_pointer args,
37820 			s7_pointer (*f7)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4,
37821 					 s7_pointer a5, s7_pointer a6, s7_pointer a7))
37822 {
37823   s7_pointer a[7];
37824   apply_n_args(7);
37825   return(f7(a[0], a[1], a[2], a[3], a[4], a[5], a[6]));
37826 }
37827 
37828 s7_pointer s7_apply_n_8(s7_scheme *sc, s7_pointer args,
37829 			s7_pointer (*f8)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4,
37830 					 s7_pointer a5, s7_pointer a6, s7_pointer a7, s7_pointer a8))
37831 {
37832   s7_pointer a[8];
37833   apply_n_args(8);
37834   return(f8(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]));
37835 }
37836 
37837 s7_pointer s7_apply_n_9(s7_scheme *sc, s7_pointer args,
37838 			s7_pointer (*f9)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4,
37839 					 s7_pointer a5, s7_pointer a6, s7_pointer a7, s7_pointer a8, s7_pointer a9))
37840 {
37841   s7_pointer a[9];
37842   apply_n_args(9);
37843   return(f9(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]));
37844 }
37845 
37846 
37847 /* ---------------- tree-leaves ---------------- */
37848 static inline s7_int tree_len_1(s7_scheme *sc, s7_pointer p)
37849 {
37850   s7_int sum;
37851   for (sum = 0; is_pair(p); p = cdr(p))
37852     {
37853       s7_pointer cp;
37854       cp = car(p);
37855       if ((!is_pair(cp)) ||
37856 	  (car(cp) == sc->quote_symbol))
37857 	sum++;
37858       else
37859 	{
37860 	  do {
37861 	    s7_pointer ccp;
37862 	    ccp = car(cp);
37863 	    if ((!is_pair(ccp)) ||
37864 		(car(ccp) == sc->quote_symbol))
37865 	      sum++;
37866 	    else
37867 	      {
37868 		do {
37869 		  s7_pointer cccp;
37870 		  cccp = car(ccp);
37871 		  if ((!is_pair(cccp)) ||
37872 		      (car(cccp) == sc->quote_symbol))
37873 		    sum++;
37874 		  else sum += tree_len_1(sc, cccp);
37875 		  ccp = cdr(ccp);
37876 		} while (is_pair(ccp));
37877 		if (!is_null(ccp)) sum++;
37878 	      }
37879 	    cp = cdr(cp);
37880 	    } while (is_pair(cp));
37881 	  if (!is_null(cp)) sum++;
37882 	}}
37883   return((is_null(p)) ? sum : sum + 1);
37884 }
37885 
37886 static inline s7_int tree_len(s7_scheme *sc, s7_pointer p)
37887 {
37888   if (is_null(p))
37889     return(0);
37890   if ((!is_pair(p)) ||
37891       (car(p) == sc->quote_symbol))
37892     return(1);
37893   return(tree_len_1(sc, p));
37894 }
37895 
37896 static s7_int tree_leaves_i_7p(s7_scheme *sc, s7_pointer p)
37897 {
37898   if ((sc->safety > NO_SAFETY) &&
37899       (tree_is_cyclic(sc, p)))
37900     s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "tree-leaves: tree is cyclic", 27));
37901   return(tree_len(sc, p));
37902 }
37903 
37904 static s7_pointer tree_leaves_p_p(s7_scheme *sc, s7_pointer tree)
37905 {
37906   if ((sc->safety > NO_SAFETY) && /* repeat code to avoid extra call overhead */
37907       (tree_is_cyclic(sc, tree)))
37908     s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "tree-leaves: tree is cyclic", 27));
37909   return(make_integer(sc, tree_len(sc, tree)));
37910 }
37911 
37912 static s7_pointer g_tree_leaves(s7_scheme *sc, s7_pointer args)
37913 {
37914   #define H_tree_leaves "(tree-leaves tree) returns the number of leaves in the tree"
37915   #define Q_tree_leaves s7_make_signature(sc, 2, sc->is_integer_symbol, sc->T)
37916   return(tree_leaves_p_p(sc, car(args)));
37917 }
37918 
37919 
37920 /* ---------------- tree-memq ---------------- */
37921 
37922 static inline bool tree_memq_1(s7_scheme *sc, s7_pointer sym, s7_pointer tree)    /* sym need not be a symbol */
37923 {
37924   if (car(tree) == sc->quote_symbol)
37925     return((!is_symbol(sym)) && (!is_pair(sym)) && (is_pair(cdr(tree))) && (sym == cadr(tree)));
37926 
37927   do {
37928     if (sym == car(tree))
37929       return(true);
37930 
37931     if (is_pair(car(tree)))
37932       {
37933 	s7_pointer cp;
37934 	cp = car(tree);
37935 	if (car(cp) == sc->quote_symbol)
37936 	  {
37937 	    if ((!is_symbol(sym)) && (!is_pair(sym)) && (is_pair(cdr(cp))) && (sym == cadr(cp)))
37938 	      return(true);
37939 	  }
37940 	else
37941 	  do {
37942 	      if (sym == car(cp))
37943 		return(true);
37944 	      if ((is_pair(car(cp))) &&
37945 		  (tree_memq_1(sc, sym, car(cp))))
37946 		return(true);
37947 	      cp = cdr(cp);
37948 	      if (sym == cp)
37949 		return(true);
37950 	    } while (is_pair(cp));
37951       }
37952     tree = cdr(tree);
37953     if (sym == tree)
37954       return(true);
37955   } while (is_pair(tree));
37956   return(false);
37957 }
37958 
37959 bool s7_tree_memq(s7_scheme *sc, s7_pointer sym, s7_pointer tree)
37960 {
37961   if (sym == tree) return(true);
37962   if (!is_pair(tree)) return(false);
37963   if ((sc->safety > NO_SAFETY) &&
37964       (tree_is_cyclic(sc, tree)))
37965     s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "tree-memq: tree is cyclic", 25));
37966   return(tree_memq_1(sc, sym, tree));
37967 }
37968 
37969 static s7_pointer g_tree_memq(s7_scheme *sc, s7_pointer args)
37970 {
37971   #define H_tree_memq "(tree-memq obj tree) is a tree-oriented version of memq, but returning #t if the object is in the tree."
37972   #define Q_tree_memq s7_make_signature(sc, 3, sc->is_boolean_symbol, sc->T, sc->T)
37973 
37974   return(make_boolean(sc, s7_tree_memq(sc, car(args), cadr(args))));
37975 }
37976 
37977 
37978 /* ---------------- tree-set-memq ---------------- */
37979 static inline bool pair_set_memq(s7_scheme *sc, s7_pointer tree)
37980 {
37981   while (true)
37982     {
37983       s7_pointer p;
37984       p = car(tree);
37985       if (is_symbol(p))
37986 	{
37987 	  if (symbol_is_in_list(sc, p))
37988 	    return(true);
37989 	}
37990       else
37991 	if ((is_unquoted_pair(p)) &&
37992 	    (pair_set_memq(sc, p)))
37993 	  return(true);
37994       tree = cdr(tree);
37995       if (!is_pair(tree)) break;
37996     }
37997   return((is_symbol(tree)) && (symbol_is_in_list(sc, tree)));
37998 }
37999 
38000 static bool tree_set_memq(s7_scheme *sc, s7_pointer tree)
38001 {
38002   if (is_symbol(tree))
38003     return(symbol_is_in_list(sc, tree));
38004   if ((!is_pair(tree)) ||
38005       (car(tree) == sc->quote_symbol))
38006     return(false);
38007   return(pair_set_memq(sc, tree));
38008 }
38009 
38010 static bool tree_set_memq_b_7pp(s7_scheme *sc, s7_pointer syms, s7_pointer tree)
38011 {
38012   s7_pointer p;
38013   if (!is_pair(syms)) return(false);
38014   if (sc->safety > NO_SAFETY)
38015     {
38016       if (tree_is_cyclic(sc, syms))
38017 	s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "tree-set-memq: symbol list is cyclic", 36));
38018       if (tree_is_cyclic(sc, tree))
38019 	s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "tree-set-memq: tree is cyclic", 29));
38020     }
38021   clear_symbol_list(sc);
38022   for (p = syms; is_pair(p); p = cdr(p))
38023     if (is_symbol(car(p)))
38024       add_symbol_to_list(sc, car(p));
38025   return(tree_set_memq(sc, tree));
38026 }
38027 
38028 static s7_pointer tree_set_memq_p_pp(s7_scheme *sc, s7_pointer syms, s7_pointer tree)
38029 {
38030   return(make_boolean(sc, tree_set_memq_b_7pp(sc, syms, tree)));
38031 }
38032 
38033 static s7_pointer g_tree_set_memq(s7_scheme *sc, s7_pointer args)
38034 {
38035   #define H_tree_set_memq "(tree-set-memq symbols tree) returns #t if any of the list of symbols is in the tree"
38036   #define Q_tree_set_memq s7_make_signature(sc, 3, sc->is_boolean_symbol, sc->T, sc->T)
38037 
38038   return(make_boolean(sc, tree_set_memq_b_7pp(sc, car(args), cadr(args))));
38039 }
38040 
38041 static s7_pointer tree_set_memq_direct(s7_scheme *sc, s7_pointer syms, s7_pointer tree)
38042 {
38043   s7_pointer p;
38044   if ((sc->safety > NO_SAFETY) &&
38045       (tree_is_cyclic(sc, tree)))
38046     s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "tree-set-memq: tree is cyclic", 29));
38047   clear_symbol_list(sc);
38048   for (p = syms; is_pair(p); p = cdr(p))
38049     add_symbol_to_list(sc, car(p));
38050   return(make_boolean(sc, tree_set_memq(sc, tree)));
38051 }
38052 
38053 static s7_pointer g_tree_set_memq_1(s7_scheme *sc, s7_pointer args)
38054 {
38055   return(tree_set_memq_direct(sc, car(args), cadr(args)));
38056 }
38057 
38058 static s7_pointer tree_set_memq_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
38059 {
38060   if ((is_proper_quote(sc, cadr(expr))) &&   /* not (tree-set-memq (quote) ... */
38061       (is_pair(cadadr(expr))))
38062     {
38063       s7_pointer p;
38064       for (p = cadadr(expr); is_pair(p); p = cdr(p))
38065 	if (!is_symbol(car(p)))
38066 	  return(f);
38067       return(sc->tree_set_memq_syms); /* this is tree_set_memq_1 */
38068     }
38069   return(f);
38070 }
38071 
38072 
38073 /* ---------------- tree-count ---------------- */
38074 static s7_int tree_count(s7_scheme *sc, s7_pointer x, s7_pointer p, s7_int count)
38075 {
38076   if (p == x)
38077     return(count + 1);
38078   if ((!is_pair(p)) || (car(p) == sc->quote_symbol))
38079     return(count);
38080   return(tree_count(sc, x, cdr(p), tree_count(sc, x, car(p), count)));
38081 }
38082 
38083 static inline s7_int tree_count_at_least(s7_scheme *sc, s7_pointer x, s7_pointer p, s7_int count, s7_int top)
38084 {
38085   if (p == x) return(count + 1);
38086   if (!is_pair(p)) return(count);
38087   if (car(p) == sc->quote_symbol) return(count);
38088   do {
38089     count = tree_count_at_least(sc, x, car(p), count, top);
38090     if (count >= top) return(count);
38091     p = cdr(p);
38092     if (p == x) return(count + 1);
38093   } while (is_pair(p));
38094   return(count);
38095 }
38096 
38097 static s7_pointer g_tree_count(s7_scheme *sc, s7_pointer args)
38098 {
38099   #define H_tree_count "(tree-count obj tree max-count) returns how many times obj is in tree (using eq?), stopping at max-count (if specified)"
38100   #define Q_tree_count s7_make_signature(sc, 4, sc->is_integer_symbol, sc->T, sc->T, sc->is_integer_symbol)
38101   s7_pointer obj, tree, count;
38102 
38103   obj = car(args);
38104   tree = cadr(args);
38105   if (!is_pair(tree))
38106     {
38107       if ((is_pair(cddr(args))) &&
38108 	  (!s7_is_integer(caddr(args))))
38109 	return(wrong_type_argument(sc, sc->tree_count_symbol, 3, caddr(args), T_INTEGER));
38110       /* here we need eqv? not eq? for integers: (tree-count <0-int-zero> <0-not-int-zero>)
38111        *   perhaps split tree_count|_at_least into eq?/eqv?/equal?/equivalent? cases?
38112        *   this is used primarily for symbol counts in lint.scm
38113        */
38114       return((obj == tree) ? int_one : int_zero);
38115     }
38116   if ((sc->safety > NO_SAFETY) &&
38117       (tree_is_cyclic(sc, tree)))
38118     s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "tree-count: tree is cyclic", 26));
38119   if (is_null(cddr(args)))
38120     return(make_integer(sc, tree_count(sc, obj, tree, 0)));
38121   count = caddr(args);
38122   if (!s7_is_integer(count))
38123     return(wrong_type_argument(sc, sc->tree_count_symbol, 3, count, T_INTEGER));
38124   return(make_integer(sc, tree_count_at_least(sc, obj, tree, 0, s7_integer_checked(sc, count))));
38125 }
38126 
38127 
38128 /* -------------------------------- null? pair? -------------------------------- */
38129 static s7_pointer g_is_null(s7_scheme *sc, s7_pointer args)
38130 {
38131   #define H_is_null "(null? obj) returns #t if obj is the empty list"
38132   #define Q_is_null sc->pl_bt
38133   check_boolean_method(sc, is_null, sc->is_null_symbol, args);
38134 }
38135 
38136 static s7_pointer g_is_pair(s7_scheme *sc, s7_pointer args)
38137 {
38138   #define H_is_pair "(pair? obj) returns #t if obj is a pair (a non-empty list)"
38139   #define Q_is_pair sc->pl_bt
38140   check_boolean_method(sc, is_pair, sc->is_pair_symbol, args);
38141 }
38142 
38143 
38144 /* -------------------------------- list? -------------------------------- */
38145 bool s7_is_list(s7_scheme *sc, s7_pointer p) {return(is_list(p));}
38146 
38147 static bool is_list_b(s7_pointer p) {return((is_pair(p)) || (type(p) == T_NIL));}
38148 
38149 static s7_pointer g_is_list(s7_scheme *sc, s7_pointer args)
38150 {
38151   #define H_is_list "(list? obj) returns #t if obj is a pair or null"
38152   #define Q_is_list sc->pl_bt
38153   #define is_a_list(p) s7_is_list(sc, p)
38154   check_boolean_method(sc, is_a_list, sc->is_list_symbol, args);
38155 }
38156 
38157 static s7_int proper_list_length(s7_pointer a)
38158 {
38159   s7_int i = 0;
38160   s7_pointer b;
38161   for (b = a; is_pair(b); i++, b = cdr(b)) {};
38162   return(i);
38163 }
38164 
38165 s7_int s7_list_length(s7_scheme *sc, s7_pointer a)
38166 {
38167   /* returns -len if list is dotted, 0 if it's (directly) circular */
38168   s7_int i;
38169   s7_pointer slow, fast;
38170 
38171   slow = fast = a;
38172   for (i = 0; ; i += 2)
38173     {
38174       if (!is_pair(fast))
38175 	return((is_null(fast)) ? i : -i);
38176 
38177       fast = cdr(fast);
38178       if (!is_pair(fast))
38179 	return((is_null(fast)) ? (i + 1) : (-i - 1));
38180       /* if unrolled further, it's a lot slower? */
38181 
38182       fast = cdr(fast);
38183       slow = cdr(slow);
38184       if (fast == slow)
38185 	return(0);
38186     }
38187   return(0);
38188 }
38189 
38190 static inline s7_pointer copy_proper_list(s7_scheme *sc, s7_pointer lst)
38191 {
38192   s7_pointer p, tp, np;
38193   if (!is_pair(lst)) return(sc->nil);
38194   sc->u = lst;
38195   tp = list_1(sc, car(lst));
38196   sc->y = tp;
38197   for (p = cdr(lst), np = tp; is_pair(p); p = cdr(p), np = cdr(np))
38198     set_cdr(np, list_1(sc, car(p)));
38199   sc->y = sc->nil;
38200   sc->u = sc->nil;
38201   return(tp);
38202 }
38203 
38204 static s7_pointer copy_proper_list_with_arglist_error(s7_scheme *sc, s7_pointer lst)
38205 {
38206   s7_pointer p, tp, np;
38207   if (is_null(lst)) return(sc->nil);
38208   if (!is_pair(lst))
38209     s7_error(sc, sc->syntax_error_symbol, set_elist_2(sc, wrap_string(sc, "stray dot?: ~S", 14), lst));
38210   sc->u = lst;
38211   tp = list_1(sc, car(lst));
38212   sc->y = tp;
38213   for (p = cdr(lst), np = tp; is_pair(p); p = cdr(p), np = cdr(np))
38214     set_cdr(np, list_1(sc, car(p)));
38215   sc->y = sc->nil;
38216   sc->u = sc->nil;
38217   if (!is_null(p))
38218     s7_error(sc, sc->syntax_error_symbol, set_elist_2(sc, wrap_string(sc, "improper list of arguments: ~S", 30), lst));
38219   return(tp);
38220 }
38221 
38222 /* -------------------------------- proper-list? -------------------------------- */
38223 bool s7_is_proper_list(s7_scheme *sc, s7_pointer lst)
38224 {
38225   /* #t if () or undotted/non-circular pair */
38226   s7_pointer slow, fast;
38227 
38228   fast = lst;
38229   slow = lst;
38230   while (true)
38231     {
38232       if (!is_pair(fast))
38233 	return(is_null(fast)); /* else it's an improper list */
38234       LOOP_4(fast = cdr(fast); if (!is_pair(fast)) return(is_null(fast)));
38235       fast = cdr(fast);
38236       slow = cdr(slow);
38237       if (fast == slow) return(false);
38238     }
38239   return(true);
38240 }
38241 
38242 static s7_pointer g_is_proper_list(s7_scheme *sc, s7_pointer args)
38243 {
38244   #define H_is_proper_list "(proper-list? x) returns #t is x is a list that is neither circular nor dotted."
38245   #define Q_is_proper_list sc->pl_bt
38246   s7_pointer p;
38247   p = car(args);
38248   return(make_boolean(sc, s7_is_proper_list(sc, p)));
38249 }
38250 
38251 static bool is_proper_list_1(s7_scheme *sc, s7_pointer p) {return((is_pair(p)) && (is_null(cdr(p))));}
38252 static bool is_proper_list_2(s7_scheme *sc, s7_pointer p) {return((is_pair(p)) && (is_pair(cdr(p))) && (is_null(cddr(p))));}
38253 static bool is_proper_list_3(s7_scheme *sc, s7_pointer p) {return((is_pair(p)) && (is_pair(cdr(p))) && (is_pair(cddr(p))) && (is_null(cdddr(p))));}
38254 static bool is_proper_list_4(s7_scheme *sc, s7_pointer p) {return(proper_list_length(p) == 4);}
38255 
38256 
38257 /* -------------------------------- make-list -------------------------------- */
38258 static s7_pointer make_big_list(s7_scheme *sc, s7_int len, s7_pointer init)
38259 {
38260   s7_pointer result;
38261   s7_int i;
38262   check_free_heap_size(sc, len);
38263   sc->v = sc->nil;
38264   for (i = 0; i < len; i++)
38265     sc->v = cons_unchecked(sc, init, sc->v);
38266   result = sc->v;
38267   sc->v = sc->nil;
38268   return(result);
38269 }
38270 
38271 static inline s7_pointer make_list(s7_scheme *sc, s7_int len, s7_pointer init)
38272 {
38273   switch (len)
38274     {
38275     case 0: return(sc->nil);
38276     case 1: return(T_Pair(cons(sc, init, sc->nil)));
38277     case 2: return(T_Pair(cons_unchecked(sc, init, cons(sc, init, sc->nil))));
38278     case 3: return(T_Pair(cons_unchecked(sc, init, cons_unchecked(sc, init, cons(sc, init, sc->nil)))));
38279     case 4: return(T_Pair(cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init, cons(sc, init, sc->nil))))));
38280     case 5: return(T_Pair(cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init, cons(sc, init, sc->nil)))))));
38281     case 6: return(T_Pair(cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init,
38282                     cons_unchecked(sc, init, cons_unchecked(sc, init, cons(sc, init, sc->nil))))))));
38283     case 7: return(T_Pair(cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init,
38284 		    cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init, cons(sc, init, sc->nil)))))))));
38285     default:
38286       return(make_big_list(sc, len, init));
38287     }
38288   return(sc->nil); /* never happens, I hope */
38289 }
38290 
38291 s7_pointer s7_make_list(s7_scheme *sc, s7_int len, s7_pointer init) {return(make_list(sc, len, init));}
38292 
38293 static s7_pointer protected_make_list(s7_scheme *sc, s7_int len, s7_pointer init)
38294 {
38295   sc->temp6 = make_list(sc, len, init);
38296   return(sc->temp6);
38297 }
38298 
38299 static s7_pointer g_make_list(s7_scheme *sc, s7_pointer args)
38300 {
38301   #define H_make_list "(make-list length (initial-element #f)) returns a list of 'length' elements whose value is 'initial-element'."
38302   #define Q_make_list s7_make_signature(sc, 3, sc->is_proper_list_symbol, sc->is_integer_symbol, sc->T)
38303 
38304   s7_pointer n;
38305   s7_int len;
38306 
38307   n = car(args);
38308   if (!s7_is_integer(n))
38309     return(method_or_bust(sc, n, sc->make_list_symbol, args, T_INTEGER, 1));
38310 
38311   len = s7_integer_checked(sc, n);
38312 #if WITH_GMP
38313   if ((len == 0) && (!s7_is_zero(n)))
38314     return(s7_out_of_range_error(sc, "make-list", 1, n, "big integer is too big for s7_int"));
38315 #endif
38316   if ((len < 0) || (len > sc->max_list_length))
38317     return(out_of_range(sc, sc->make_list_symbol, int_one, n, (len < 0) ? its_negative_string : its_too_large_string));
38318   if (len == 0) return(sc->nil);          /* what about (make-list 0 123)? */
38319 
38320   return(make_list(sc, len, (is_pair(cdr(args))) ? cadr(args) : sc->F));
38321 }
38322 
38323 
38324 /* -------------------------------- list-ref -------------------------------- */
38325 
38326 s7_pointer s7_list_ref(s7_scheme *sc, s7_pointer lst, s7_int num)
38327 {
38328   s7_int i;
38329   s7_pointer x;
38330   for (x = lst, i = 0; (i < num) && (is_pair(x)); i++, x = cdr(x)) {}
38331   if ((i == num) && (is_pair(x)))
38332     return(car(x));
38333   return(sc->nil);
38334 }
38335 
38336 static s7_pointer list_ref_1(s7_scheme *sc, s7_pointer lst, s7_pointer ind)
38337 {
38338   s7_int i, index;
38339   s7_pointer p;
38340 
38341   if (!s7_is_integer(ind))
38342     return(method_or_bust_pp(sc, ind, sc->list_ref_symbol, lst, ind, T_INTEGER, 2));
38343   index = s7_integer_checked(sc, ind);
38344   if ((index < 0) || (index > sc->max_list_length))
38345     return(out_of_range(sc, sc->list_ref_symbol, int_two, ind, (index < 0) ? its_negative_string : its_too_large_string));
38346 
38347   for (i = 0, p = lst; (i < index) && is_pair(p); i++, p = cdr(p)) {}
38348 
38349   if (!is_pair(p))
38350     {
38351       if (is_null(p))
38352 	return(out_of_range(sc, sc->list_ref_symbol, int_two, ind, its_too_large_string));
38353       return(wrong_type_argument_with_type(sc, sc->list_ref_symbol, 1, lst, a_proper_list_string));
38354     }
38355   return(car(p));
38356 }
38357 
38358 static s7_pointer implicit_index(s7_scheme *sc, s7_pointer obj, s7_pointer indices);
38359 
38360 static s7_pointer g_list_ref(s7_scheme *sc, s7_pointer args)
38361 {
38362   #define H_list_ref "(list-ref lst i ...) returns the i-th element (0-based) of the list"
38363   #define Q_list_ref s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_pair_symbol, sc->is_integer_symbol)
38364 
38365   /* (let ((L '((1 2 3) (4 5 6)))) (list-ref L 1 2))
38366     (define (lref L . args)
38367       (if (null? (cdr args))
38368           (list-ref L (car args))
38369           (apply lref (list-ref L (car args)) (cdr args))))
38370   */
38371   s7_pointer lst, inds;
38372 
38373   lst = car(args);
38374   if (!is_pair(lst))
38375     return(method_or_bust(sc, lst, sc->list_ref_symbol, args, T_PAIR, 1));
38376 
38377   inds = cdr(args);
38378   while (true)
38379     {
38380       lst = list_ref_1(sc, lst, car(inds));
38381       if (is_null(cdr(inds)))
38382 	return(lst);
38383       inds = cdr(inds);
38384       if (!is_pair(lst))
38385 	return(implicit_index(sc, lst, inds)); /* 9-Jan-19 */
38386     }
38387 }
38388 
38389 static bool op_implicit_pair_ref_a(s7_scheme *sc)
38390 {
38391   s7_pointer s, x;
38392   s = lookup_checked(sc, car(sc->code));
38393   if (!is_pair(s)) {sc->last_function = s; return(false);}
38394   x = fx_call(sc, cdr(sc->code));
38395   sc->value = list_ref_1(sc, s, x);
38396   return(true);
38397 }
38398 
38399 static s7_pointer g_list_ref_0(s7_scheme *sc, s7_pointer args)
38400 {
38401   if (is_pair(car(args))) return(caar(args));
38402   return(method_or_bust(sc, car(args), sc->list_ref_symbol, args, T_PAIR, 1)); /* 1=arg num if error */
38403 }
38404 
38405 static s7_pointer g_list_ref_1(s7_scheme *sc, s7_pointer args)
38406 {
38407   s7_pointer lst;
38408   lst = car(args);
38409   if (is_pair(lst))
38410     {
38411       if (is_pair(cdr(lst))) return(cadr(lst));
38412       return(out_of_range(sc, sc->list_ref_symbol, int_two, cadr(args), its_too_large_string));
38413     }
38414   return(method_or_bust(sc, lst, sc->list_ref_symbol, args, T_PAIR, 1));
38415 }
38416 
38417 static s7_pointer g_list_ref_2(s7_scheme *sc, s7_pointer args)
38418 {
38419   s7_pointer lst;
38420   lst = car(args);
38421   if (is_pair(lst))
38422     {
38423       if ((is_pair(cdr(lst))) && (is_pair(cddr(lst)))) return(caddr(lst));
38424       return(out_of_range(sc, sc->list_ref_symbol, int_two, cadr(args), its_too_large_string));
38425     }
38426   return(method_or_bust(sc, lst, sc->list_ref_symbol, args, T_PAIR, 1));
38427 }
38428 
38429 static s7_pointer list_ref_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
38430 {
38431   if (args == 2)
38432     {
38433       s7_pointer index;
38434       index = caddr(expr);
38435       if (is_t_integer(index))
38436 	{
38437 	  if (integer(index) == 0) return(sc->list_ref_0);
38438 	  if (integer(index) == 1) return(sc->list_ref_1);
38439 	  if (integer(index) == 2) return(sc->list_ref_2);
38440 	}}
38441   return(f);
38442 }
38443 
38444 
38445 /* -------------------------------- list-set! -------------------------------- */
38446 s7_pointer s7_list_set(s7_scheme *sc, s7_pointer lst, s7_int num, s7_pointer val)
38447 {
38448   s7_int i;
38449   s7_pointer x;
38450   for (x = lst, i = 0; (i < num) && (is_pair(x)); i++, x = cdr(x)) {}
38451   if ((i == num) &&
38452       (is_pair(x)))
38453     set_car(x, T_Pos(val));
38454   return(val);
38455 }
38456 
38457 static s7_pointer g_list_set_1(s7_scheme *sc, s7_pointer lst, s7_pointer args, int32_t arg_num)
38458 {
38459   #define H_list_set "(list-set! lst i ... val) sets the i-th element (0-based) of the list to val"
38460   #define Q_list_set s7_make_circular_signature(sc, 3, 4, sc->T, sc->is_pair_symbol, sc->is_integer_symbol, sc->is_integer_or_any_at_end_symbol)
38461 
38462   int32_t i;
38463   s7_int index;
38464   s7_pointer p, ind;
38465   /* (let ((L '((1 2 3) (4 5 6)))) (list-set! L 1 2 32) L) */
38466 
38467   if (!is_mutable_pair(lst))
38468     return(mutable_method_or_bust(sc, lst, sc->list_set_symbol, set_ulist_1(sc, lst, args), T_PAIR, 1));
38469 
38470   ind = car(args);
38471   if ((arg_num > 2) && (is_null(cdr(args))))
38472     {
38473       set_car(lst, ind);
38474       return(ind);
38475     }
38476   if (!s7_is_integer(ind))
38477     return(method_or_bust(sc, ind, sc->list_set_symbol, set_ulist_1(sc, lst, args), T_INTEGER, 2));
38478   index = s7_integer_checked(sc, ind);
38479   if ((index < 0) || (index > sc->max_list_length))
38480     return(out_of_range(sc, sc->list_set_symbol, wrap_integer1(sc, arg_num), ind, (index < 0) ? its_negative_string : its_too_large_string));
38481 
38482   for (i = 0, p = lst; (i < index) && is_pair(p); i++, p = cdr(p)) {}
38483 
38484   if (!is_pair(p))
38485     {
38486       if (is_null(p))
38487 	return(out_of_range(sc, sc->list_set_symbol, wrap_integer1(sc, arg_num), ind, its_too_large_string));
38488       return(wrong_type_argument_with_type(sc, sc->list_set_symbol, 1, lst, a_proper_list_string));
38489     }
38490   if (is_null(cddr(args)))
38491     set_car(p, cadr(args));
38492   else
38493     {
38494       if (!s7_is_pair(car(p)))
38495 	return(s7_wrong_number_of_args_error(sc, "too many arguments for list-set!: ~S", args));
38496       return(g_list_set_1(sc, car(p), cdr(args), arg_num + 1));
38497     }
38498   return(cadr(args));
38499 }
38500 
38501 static s7_pointer g_list_set(s7_scheme *sc, s7_pointer args) {return(g_list_set_1(sc, car(args), cdr(args), 2));}
38502 
38503 static s7_pointer list_ref_p_pi_unchecked(s7_scheme *sc, s7_pointer p1, s7_int i1)
38504 {
38505   s7_pointer p;
38506   s7_int i;
38507   if ((i1 < 0) || (i1 > sc->max_list_length))
38508     out_of_range(sc, sc->list_ref_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
38509   for (i = 0, p = p1; ((is_pair(p)) && (i < i1)); i++, p = cdr(p));
38510   if (!is_pair(p))
38511     {
38512       if (is_null(p))
38513 	out_of_range(sc, sc->list_ref_symbol, int_two, wrap_integer1(sc, i1), its_too_large_string);
38514       else simple_wrong_type_argument_with_type(sc, sc->list_ref_symbol, p1, a_proper_list_string);
38515     }
38516   return(car(p));
38517 }
38518 
38519 static s7_pointer list_ref_p_pi(s7_scheme *sc, s7_pointer p1, s7_int i1)
38520 {
38521   if (!is_pair(p1))
38522     simple_wrong_type_argument(sc, sc->list_ref_symbol, p1, T_PAIR);
38523   return(list_ref_p_pi_unchecked(sc, p1, i1));
38524 }
38525 
38526 static s7_pointer list_set_p_pip_unchecked(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_pointer p2)
38527 {
38528   s7_pointer p;
38529   s7_int i;
38530   if ((i1 < 0) || (i1 > sc->max_list_length))
38531     out_of_range(sc, sc->list_set_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
38532   for (i = 0, p = p1; ((is_pair(p)) && (i < i1)); i++, p = cdr(p));
38533   if (!is_pair(p))
38534     {
38535       if (is_null(p))
38536 	out_of_range(sc, sc->list_set_symbol, int_two, wrap_integer1(sc, i1), its_too_large_string);
38537       else simple_wrong_type_argument_with_type(sc, sc->list_set_symbol, p1, a_proper_list_string);
38538     }
38539   set_car(p, p2);
38540   return(p2);
38541 }
38542 
38543 static s7_pointer list_increment_p_pip_unchecked(opt_info *o)
38544 {
38545   s7_scheme *sc;
38546   s7_pointer p, p1, p2;
38547   s7_int i, index;
38548   sc = opt_sc(o);
38549   p = slot_value(o->v[2].p);
38550   index = integer(p);
38551   if ((index < 0) || (index > sc->max_list_length))
38552     out_of_range(sc, sc->list_set_symbol, int_two, p, (index < 0) ? its_negative_string : its_too_large_string);
38553   p1 = slot_value(o->v[1].p);
38554   for (i = 0, p = p1; ((is_pair(p)) && (i < index)); i++, p = cdr(p));
38555   if (!is_pair(p))
38556     {
38557       if (is_null(p))
38558 	out_of_range(sc, sc->list_set_symbol, int_two, wrap_integer1(sc, index), its_too_large_string);
38559       else simple_wrong_type_argument_with_type(sc, sc->list_set_symbol, p1, a_proper_list_string);
38560     }
38561   p2 = g_add_xi(sc, car(p), integer(o->v[3].p));
38562   set_car(p, p2);
38563   return(p2);
38564 }
38565 
38566 static s7_pointer list_set_p_pip(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_pointer p2)
38567 {
38568   if (!is_pair(p1))
38569     simple_wrong_type_argument(sc, sc->list_set_symbol, p1, T_PAIR);
38570   return(list_set_p_pip_unchecked(sc, p1, i1, p2));
38571 }
38572 
38573 static s7_pointer g_list_set_i(s7_scheme *sc, s7_pointer args)
38574 {
38575   s7_pointer p, lst, val;
38576   s7_int i, index;
38577   lst = car(args);
38578   if (!is_mutable_pair(lst))
38579     return(mutable_method_or_bust(sc, lst, sc->list_set_symbol, args, T_PAIR, 1));
38580 
38581   index = s7_integer_checked(sc, cadr(args));
38582   if ((index < 0) || (index > sc->max_list_length))
38583     return(out_of_range(sc, sc->list_set_symbol, int_two, wrap_integer1(sc, index), (index < 0) ? its_negative_string : its_too_large_string));
38584 
38585   for (i = 0, p = lst; (i < index) && is_pair(p); i++, p = cdr(p)) {}
38586   if (!is_pair(p))
38587     {
38588       if (is_null(p))
38589 	return(out_of_range(sc, sc->list_set_symbol, int_two, wrap_integer1(sc, index), its_too_large_string));
38590       return(wrong_type_argument_with_type(sc, sc->list_set_symbol, 1, lst, a_proper_list_string));
38591     }
38592 
38593   val = caddr(args);
38594   set_car(p, val);
38595   return(val);
38596 }
38597 
38598 static s7_pointer list_set_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
38599 {
38600   if ((args == 3) &&
38601       (s7_is_integer(caddr(expr))) &&
38602       (s7_integer_checked(sc, caddr(expr)) >= 0) &&
38603       (s7_integer_checked(sc, caddr(expr)) < sc->max_list_length))
38604     return(sc->list_set_i);
38605   return(f);
38606 }
38607 
38608 
38609 /* -------------------------------- list-tail -------------------------------- */
38610 
38611 static s7_pointer list_tail_p_pp(s7_scheme *sc, s7_pointer lst, s7_pointer p)
38612 {
38613   s7_int i, index;
38614   if (!s7_is_integer(p))
38615     return(method_or_bust_pp(sc, p, sc->list_tail_symbol, lst, p, T_INTEGER, 2));
38616   index = s7_integer_checked(sc, p);
38617 
38618   if (!is_list(lst))
38619     return(method_or_bust_with_type_pi(sc, lst, sc->list_tail_symbol, lst, index, a_list_string));
38620 
38621   if ((index < 0) || (index > sc->max_list_length))
38622     return(out_of_range(sc, sc->list_tail_symbol, int_two, wrap_integer1(sc, index), (index < 0) ? its_negative_string : its_too_large_string));
38623 
38624   for (i = 0, p = lst; (i < index) && (is_pair(p)); i++, p = cdr(p)) {}
38625   if (i < index)
38626     return(out_of_range(sc, sc->list_tail_symbol, int_two, wrap_integer1(sc, index), its_too_large_string));
38627   return(p);
38628 }
38629 
38630 static s7_pointer g_list_tail(s7_scheme *sc, s7_pointer args)
38631 {
38632   #define H_list_tail "(list-tail lst i) returns the list from the i-th element on"
38633   #define Q_list_tail s7_make_signature(sc, 3, sc->T, sc->is_pair_symbol, sc->is_integer_symbol) /* #t: (list-tail '(1 . 2) 1) -> 2 */
38634   return(list_tail_p_pp(sc, car(args), cadr(args)));
38635 }
38636 
38637 
38638 /* -------------------------------- cons -------------------------------- */
38639 static s7_pointer g_cons(s7_scheme *sc, s7_pointer args)
38640 {
38641   #define H_cons "(cons a b) returns a pair containing a and b"
38642   #define Q_cons s7_make_signature(sc, 3, sc->is_pair_symbol, sc->T, sc->T)
38643 
38644   s7_pointer x;
38645   new_cell(sc, x, T_PAIR | T_SAFE_PROCEDURE);
38646   set_car(x, car(args));
38647   set_cdr(x, cadr(args));
38648   return(x);
38649 }
38650 
38651 static s7_pointer cons_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
38652 {
38653   s7_pointer x;
38654   new_cell(sc, x, T_PAIR | T_SAFE_PROCEDURE);
38655   set_car(x, p1);
38656   set_cdr(x, p2);
38657   return(x);
38658 }
38659 
38660 
38661 /* -------- car -------- */
38662 
38663 static s7_pointer g_car(s7_scheme *sc, s7_pointer args)
38664 {
38665   #define H_car "(car pair) returns the first element of the pair"
38666   #define Q_car sc->pl_p
38667 
38668   s7_pointer lst;
38669   lst = car(args);
38670   if (is_pair(lst))
38671     return(car(lst));
38672   return(method_or_bust_one_arg(sc, lst, sc->car_symbol, args, T_PAIR));
38673 }
38674 
38675 static s7_pointer car_p_p(s7_scheme *sc, s7_pointer p)
38676 {
38677   if (is_pair(p))
38678     return(car(p));
38679   return(simple_wrong_type_argument(sc, sc->car_symbol, p, T_PAIR));
38680 }
38681 
38682 
38683 static s7_pointer g_set_car(s7_scheme *sc, s7_pointer args)
38684 {
38685   #define H_set_car "(set-car! pair val) sets the pair's first element to val"
38686   #define Q_set_car s7_make_signature(sc, 3, sc->T, sc->is_pair_symbol, sc->T)
38687   s7_pointer p;
38688 
38689   p = car(args);
38690   if (!is_mutable_pair(p)) /* this is currently 2.5x slower than is_pair */
38691     return(mutable_method_or_bust(sc, p, sc->set_car_symbol, args, T_PAIR, 1));
38692   set_car(p, cadr(args));
38693   return(car(p));
38694 }
38695 
38696 static Inline s7_pointer inline_set_car(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
38697 {
38698   if (!is_mutable_pair(p1))
38699     simple_wrong_type_argument(sc, sc->set_car_symbol, p1, T_PAIR);
38700   set_car(p1, p2);
38701   return(p2);
38702 }
38703 
38704 static s7_pointer set_car_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2) {return(inline_set_car(sc, p1, p2));}
38705 
38706 
38707 /* -------- cdr -------- */
38708 static s7_pointer g_cdr(s7_scheme *sc, s7_pointer args)
38709 {
38710   #define H_cdr "(cdr pair) returns the second element of the pair"
38711   #define Q_cdr sc->pl_p
38712 
38713   s7_pointer lst;
38714   lst = car(args);
38715   if (is_pair(lst))
38716     return(cdr(lst));
38717   return(method_or_bust_one_arg(sc, lst, sc->cdr_symbol, args, T_PAIR));
38718 }
38719 
38720 static s7_pointer cdr_p_p(s7_scheme *sc, s7_pointer p)
38721 {
38722   if (is_pair(p))
38723     return(cdr(p));
38724   return(simple_wrong_type_argument(sc, sc->cdr_symbol, p, T_PAIR));
38725 }
38726 
38727 
38728 static s7_pointer g_set_cdr(s7_scheme *sc, s7_pointer args)
38729 {
38730   #define H_set_cdr "(set-cdr! pair val) sets the pair's second element to val"
38731   #define Q_set_cdr s7_make_signature(sc, 3, sc->T, sc->is_pair_symbol, sc->T)
38732   s7_pointer p;
38733 
38734   p = car(args);
38735   if (!is_mutable_pair(p))
38736     return(mutable_method_or_bust(sc, p, sc->set_cdr_symbol, args, T_PAIR, 1));
38737 
38738   set_cdr(p, cadr(args));
38739   return(cdr(p));
38740 }
38741 
38742 static s7_pointer set_cdr_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
38743 {
38744   if (!is_mutable_pair(p1))
38745     simple_wrong_type_argument(sc, sc->set_cdr_symbol, p1, T_PAIR);
38746   set_cdr(p1, p2);
38747   return(p2);
38748 }
38749 
38750 
38751 /* -------- caar --------*/
38752 static s7_pointer g_caar(s7_scheme *sc, s7_pointer args)
38753 {
38754   #define H_caar "(caar lst) returns (car (car lst)): (caar '((1 2))) -> 1"
38755   #define Q_caar sc->pl_p
38756 
38757   s7_pointer lst;
38758   lst = car(args);
38759   /* it makes no difference in timing to move lst here or below (i.e. lst=car(lst) then return(car(lst)) and so on) */
38760   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->caar_symbol, args, T_PAIR));
38761   return((is_pair(car(lst))) ? caar(lst) : simple_wrong_type_argument_with_type(sc, sc->caar_symbol, lst, car_a_list_string));
38762 }
38763 
38764 static s7_pointer caar_p_p(s7_scheme *sc, s7_pointer p)
38765 {
38766   if ((is_pair(p)) && (is_pair(car(p)))) return(caar(p));
38767   if (!is_pair(p)) return(simple_wrong_type_argument(sc, sc->caar_symbol, p, T_PAIR));
38768   return(simple_wrong_type_argument_with_type(sc, sc->caar_symbol, p, car_a_list_string));
38769 }
38770 
38771 
38772 /* -------- cadr --------*/
38773 static s7_pointer g_cadr(s7_scheme *sc, s7_pointer args)
38774 {
38775   #define H_cadr "(cadr lst) returns (car (cdr lst)): (cadr '(1 2 3)) -> 2"
38776   #define Q_cadr sc->pl_p
38777 
38778   s7_pointer lst;
38779   lst = car(args);
38780   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cadr_symbol, args, T_PAIR));
38781   return((is_pair(cdr(lst))) ? cadr(lst) : simple_wrong_type_argument_with_type(sc, sc->cadr_symbol, lst, cdr_a_list_string));
38782 }
38783 
38784 static s7_pointer cadr_p_p(s7_scheme *sc, s7_pointer p)
38785 {
38786   if ((is_pair(p)) && (is_pair(cdr(p)))) return(cadr(p));
38787   if (!is_pair(p)) return(simple_wrong_type_argument(sc, sc->cadr_symbol, p, T_PAIR));
38788   return(simple_wrong_type_argument_with_type(sc, sc->cadr_symbol, p, cdr_a_list_string));
38789 }
38790 
38791 
38792 /* -------- cdar -------- */
38793 static s7_pointer g_cdar(s7_scheme *sc, s7_pointer args)
38794 {
38795   #define H_cdar "(cdar lst) returns (cdr (car lst)): (cdar '((1 2 3))) -> '(2 3)"
38796   #define Q_cdar sc->pl_p
38797 
38798   s7_pointer lst;
38799   lst = car(args);
38800   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cdar_symbol, args, T_PAIR));
38801   return((is_pair(car(lst))) ? cdar(lst) : simple_wrong_type_argument_with_type(sc, sc->cdar_symbol, lst, car_a_list_string));
38802 }
38803 
38804 static s7_pointer cdar_p_p(s7_scheme *sc, s7_pointer p)
38805 {
38806   if ((is_pair(p)) && (is_pair(car(p)))) return(cdar(p));
38807   if (!is_pair(p)) return(simple_wrong_type_argument(sc, sc->cdar_symbol, p, T_PAIR));
38808   return(simple_wrong_type_argument_with_type(sc, sc->cdar_symbol, p, car_a_list_string));
38809 }
38810 
38811 
38812 /* -------- cddr -------- */
38813 static s7_pointer g_cddr(s7_scheme *sc, s7_pointer args)
38814 {
38815   #define H_cddr "(cddr lst) returns (cdr (cdr lst)): (cddr '(1 2 3 4)) -> '(3 4)"
38816   #define Q_cddr sc->pl_p
38817 
38818   s7_pointer lst;
38819   lst = car(args);
38820   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cddr_symbol, args, T_PAIR));
38821   return((is_pair(cdr(lst))) ? cddr(lst) : simple_wrong_type_argument_with_type(sc, sc->cddr_symbol, lst, cdr_a_list_string));
38822 }
38823 
38824 static s7_pointer cddr_p_p(s7_scheme *sc, s7_pointer p)
38825 {
38826   if ((is_pair(p)) && (is_pair(cdr(p)))) return(cddr(p));
38827   if (!is_pair(p)) return(simple_wrong_type_argument(sc, sc->cddr_symbol, p, T_PAIR));
38828   return(simple_wrong_type_argument_with_type(sc, sc->cddr_symbol, p, cdr_a_list_string));
38829 }
38830 
38831 /* -------- caaar -------- */
38832 static s7_pointer g_caaar(s7_scheme *sc, s7_pointer args)
38833 {
38834   s7_pointer lst;
38835   #define H_caaar "(caaar lst) returns (car (car (car lst))): (caaar '(((1 2)))) -> 1"
38836   #define Q_caaar sc->pl_p
38837 
38838   lst = car(args);
38839   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->caaar_symbol, args, T_PAIR));
38840   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaar_symbol, lst, car_a_list_string));
38841   return((is_pair(caar(lst))) ? caaar(lst) : simple_wrong_type_argument_with_type(sc, sc->caaar_symbol, lst, caar_a_list_string));
38842 }
38843 
38844 /* -------- caadr -------- */
38845 static s7_pointer g_caadr(s7_scheme *sc, s7_pointer args)
38846 {
38847   s7_pointer lst;
38848   #define H_caadr "(caadr lst) returns (car (car (cdr lst))): (caadr '(1 (2 3))) -> 2"
38849   #define Q_caadr sc->pl_p
38850 
38851   lst = car(args);
38852   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->caadr_symbol, args, T_PAIR));
38853   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caadr_symbol, lst, cdr_a_list_string));
38854   return((is_pair(cadr(lst))) ? caadr(lst) : simple_wrong_type_argument_with_type(sc, sc->caadr_symbol, lst, cadr_a_list_string));
38855 }
38856 
38857 static s7_pointer caadr_p_p(s7_scheme *sc, s7_pointer p)
38858 {
38859   if ((is_pair(p)) && (is_pair(cdr(p))) && (is_pair(cadr(p)))) return(caadr(p));
38860   if (!is_pair(p)) return(simple_wrong_type_argument(sc, sc->caadr_symbol, p, T_PAIR));
38861   if (!is_pair(cdr(p))) return(simple_wrong_type_argument_with_type(sc, sc->caadr_symbol, p, cdr_a_list_string));
38862   return(simple_wrong_type_argument_with_type(sc, sc->caadr_symbol, p, cadr_a_list_string));
38863 }
38864 
38865 /* -------- cadar -------- */
38866 static s7_pointer g_cadar(s7_scheme *sc, s7_pointer args)
38867 {
38868   s7_pointer lst;
38869   #define H_cadar "(cadar lst) returns (car (cdr (car lst))): (cadar '((1 2 3))) -> 2"
38870   #define Q_cadar sc->pl_p
38871 
38872   lst = car(args);
38873   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cadar_symbol, args, T_PAIR));
38874   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadar_symbol, lst, car_a_list_string));
38875   return((is_pair(cdar(lst))) ? cadar(lst) : simple_wrong_type_argument_with_type(sc, sc->cadar_symbol, lst, cdar_a_list_string));
38876 }
38877 
38878 static s7_pointer cadar_p_p(s7_scheme *sc, s7_pointer p)
38879 {
38880   if ((is_pair(p)) && (is_pair(car(p))) && (is_pair(cdar(p)))) return(cadar(p));
38881   if (!is_pair(p)) return(simple_wrong_type_argument(sc, sc->cadar_symbol, p, T_PAIR));
38882   if (!is_pair(car(p))) return(simple_wrong_type_argument_with_type(sc, sc->cadar_symbol, p, car_a_list_string));
38883   return(simple_wrong_type_argument_with_type(sc, sc->cadar_symbol, p, cdar_a_list_string));
38884 }
38885 
38886 /* -------- cdaar -------- */
38887 static s7_pointer g_cdaar(s7_scheme *sc, s7_pointer args)
38888 {
38889   s7_pointer lst;
38890   #define H_cdaar "(cdaar lst) returns (cdr (car (car lst))): (cdaar '(((1 2 3)))) -> '(2 3)"
38891   #define Q_cdaar sc->pl_p
38892 
38893   lst = car(args);
38894   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cdaar_symbol, args, T_PAIR));
38895   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaar_symbol, lst, car_a_list_string));
38896   return((is_pair(caar(lst))) ? cdaar(lst) : simple_wrong_type_argument_with_type(sc, sc->cdaar_symbol, lst, caar_a_list_string));
38897 }
38898 
38899 /* -------- caddr -------- */
38900 static s7_pointer g_caddr(s7_scheme *sc, s7_pointer args)
38901 {
38902   s7_pointer lst;
38903   #define H_caddr "(caddr lst) returns (car (cdr (cdr lst))): (caddr '(1 2 3 4)) -> 3"
38904   #define Q_caddr sc->pl_p
38905 
38906   lst = car(args);
38907   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->caddr_symbol, args, T_PAIR));
38908   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caddr_symbol, lst, cdr_a_list_string));
38909   return((is_pair(cddr(lst))) ? caddr(lst): simple_wrong_type_argument_with_type(sc, sc->caddr_symbol, lst, cddr_a_list_string));
38910 }
38911 
38912 static s7_pointer caddr_p_p(s7_scheme *sc, s7_pointer p)
38913 {
38914   if ((is_pair(p)) && (is_pair(cdr(p))) && (is_pair(cddr(p)))) return(caddr(p));
38915   if (!is_pair(p)) return(simple_wrong_type_argument(sc, sc->caddr_symbol, p, T_PAIR));
38916   if (!is_pair(cdr(p))) return(simple_wrong_type_argument_with_type(sc, sc->caddr_symbol, p, cdr_a_list_string));
38917   return(simple_wrong_type_argument_with_type(sc, sc->caddr_symbol, p, cddr_a_list_string));
38918 }
38919 
38920 /* -------- cdddr -------- */
38921 static s7_pointer g_cdddr(s7_scheme *sc, s7_pointer args)
38922 {
38923   s7_pointer lst;
38924   #define H_cdddr "(cdddr lst) returns (cdr (cdr (cdr lst))): (cdddr '(1 2 3 4)) -> '(4)"
38925   #define Q_cdddr sc->pl_p
38926 
38927   lst = car(args);
38928   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cdddr_symbol, args, T_PAIR));
38929   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdddr_symbol, lst, cdr_a_list_string));
38930   return((is_pair(cddr(lst))) ? cdddr(lst) : simple_wrong_type_argument_with_type(sc, sc->cdddr_symbol, lst, cddr_a_list_string));
38931 }
38932 
38933 /* -------- cdadr -------- */
38934 static s7_pointer cdadr_p_p(s7_scheme *sc, s7_pointer lst)
38935 {
38936   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cdadr_symbol, list_1(sc, lst), T_PAIR));
38937   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdadr_symbol, lst, cdr_a_list_string));
38938   return((is_pair(cadr(lst))) ? cdadr(lst) : simple_wrong_type_argument_with_type(sc, sc->cdadr_symbol, lst, cadr_a_list_string));
38939 }
38940 
38941 static s7_pointer g_cdadr(s7_scheme *sc, s7_pointer args)
38942 {
38943   #define H_cdadr "(cdadr lst) returns (cdr (car (cdr lst))): (cdadr '(1 (2 3 4))) -> '(3 4)"
38944   #define Q_cdadr sc->pl_p
38945   return(cdadr_p_p(sc, car(args)));
38946 }
38947 
38948 /* -------- cddar -------- */
38949 static s7_pointer g_cddar(s7_scheme *sc, s7_pointer args)
38950 {
38951   s7_pointer lst;
38952   #define H_cddar "(cddar lst) returns (cdr (cdr (car lst))): (cddar '((1 2 3 4))) -> '(3 4)"
38953   #define Q_cddar sc->pl_p
38954 
38955   lst = car(args);
38956   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cddar_symbol, args, T_PAIR));
38957   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddar_symbol, lst, car_a_list_string));
38958   return((is_pair(cdar(lst))) ? cddar(lst) : simple_wrong_type_argument_with_type(sc, sc->cddar_symbol, lst, cdar_a_list_string));
38959 }
38960 
38961 /* -------- caaaar -------- */
38962 static s7_pointer g_caaaar(s7_scheme *sc, s7_pointer args)
38963 {
38964   s7_pointer lst;
38965   #define H_caaaar "(caaaar lst) returns (car (car (car (car lst)))): (caaaar '((((1 2))))) -> 1"
38966   #define Q_caaaar sc->pl_p
38967 
38968   lst = car(args);
38969   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->caaaar_symbol, args, T_PAIR));
38970   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaaar_symbol, lst, car_a_list_string));
38971   if (!is_pair(caar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaaar_symbol, lst, caar_a_list_string));
38972   return((is_pair(caaar(lst))) ? caaaar(lst) : simple_wrong_type_argument_with_type(sc, sc->caaaar_symbol, lst, caaar_a_list_string));
38973 }
38974 
38975 /* -------- caaadr -------- */
38976 static s7_pointer g_caaadr(s7_scheme *sc, s7_pointer args)
38977 {
38978   s7_pointer lst;
38979   #define H_caaadr "(caaadr lst) returns (car (car (car (cdr lst)))): (caaadr '(1 ((2 3)))) -> 2"
38980   #define Q_caaadr sc->pl_p
38981 
38982   lst = car(args);
38983   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->caaadr_symbol, args, T_PAIR));
38984   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaadr_symbol, lst, cdr_a_list_string));
38985   if (!is_pair(cadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaadr_symbol, lst, cadr_a_list_string));
38986   return((is_pair(caadr(lst))) ? caaadr(lst) : simple_wrong_type_argument_with_type(sc, sc->caaadr_symbol, lst, caadr_a_list_string));
38987 }
38988 
38989 /* -------- caadar -------- */
38990 static s7_pointer g_caadar(s7_scheme *sc, s7_pointer args)
38991 {
38992   s7_pointer lst;
38993   #define H_caadar "(caadar lst) returns (car (car (cdr (car lst)))): (caadar '((1 (2 3)))) -> 2"
38994   #define Q_caadar sc->pl_p
38995 
38996   lst = car(args);
38997   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->caadar_symbol, args, T_PAIR));
38998   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caadar_symbol, lst, car_a_list_string));
38999   if (!is_pair(cdar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caadar_symbol, lst, cdar_a_list_string));
39000   return((is_pair(cadar(lst))) ? caadar(lst) : simple_wrong_type_argument_with_type(sc, sc->caadar_symbol, lst, cadar_a_list_string));
39001 }
39002 
39003 /* -------- cadaar -------- */
39004 static s7_pointer g_cadaar(s7_scheme *sc, s7_pointer args)
39005 {
39006   s7_pointer lst;
39007   #define H_cadaar "(cadaar lst) returns (car (cdr (car (car lst)))): (cadaar '(((1 2 3)))) -> 2"
39008   #define Q_cadaar sc->pl_p
39009 
39010   lst = car(args);
39011   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cadaar_symbol, args, T_PAIR));
39012   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadaar_symbol, lst, car_a_list_string));
39013   if (!is_pair(caar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadaar_symbol, lst, caar_a_list_string));
39014   return((is_pair(cdaar(lst))) ? cadaar(lst) : simple_wrong_type_argument_with_type(sc, sc->cadaar_symbol, lst, cdaar_a_list_string));
39015 }
39016 
39017 /* -------- caaddr -------- */
39018 
39019 static s7_pointer caaddr_p_p(s7_scheme *sc, s7_pointer lst)
39020 {
39021   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->caaddr_symbol, list_1(sc, lst), T_PAIR));
39022   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaddr_symbol, lst, cdr_a_list_string));
39023   if (!is_pair(cddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaddr_symbol, lst, cddr_a_list_string));
39024   return((is_pair(caddr(lst))) ? caaddr(lst) : simple_wrong_type_argument_with_type(sc, sc->caaddr_symbol, lst, caddr_a_list_string));
39025 }
39026 
39027 static s7_pointer g_caaddr(s7_scheme *sc, s7_pointer args)
39028 {
39029   #define H_caaddr "(caaddr lst) returns (car (car (cdr (cdr lst)))): (caaddr '(1 2 (3 4))) -> 3"
39030   #define Q_caaddr sc->pl_p
39031   return(caaddr_p_p(sc, car(args)));
39032 }
39033 
39034 /* -------- cadddr -------- */
39035 static s7_pointer cadddr_p_p(s7_scheme *sc, s7_pointer lst)
39036 {
39037   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cadddr_symbol, list_1(sc, lst), T_PAIR));
39038   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadddr_symbol, lst, cdr_a_list_string));
39039   if (!is_pair(cddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadddr_symbol, lst, cddr_a_list_string));
39040   return((is_pair(cdddr(lst))) ? cadddr(lst) : simple_wrong_type_argument_with_type(sc, sc->cadddr_symbol, lst, cdddr_a_list_string));
39041 }
39042 
39043 static s7_pointer g_cadddr(s7_scheme *sc, s7_pointer args)
39044 {
39045   #define H_cadddr "(cadddr lst) returns (car (cdr (cdr (cdr lst)))): (cadddr '(1 2 3 4 5)) -> 4"
39046   #define Q_cadddr sc->pl_p
39047   return(cadddr_p_p(sc, car(args)));
39048 }
39049 
39050 /* -------- cadadr -------- */
39051 static s7_pointer cadadr_p_p(s7_scheme *sc, s7_pointer lst)
39052 {
39053   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cadadr_symbol, list_1(sc, lst), T_PAIR));
39054   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadadr_symbol, lst, cdr_a_list_string));
39055   if (!is_pair(cadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadadr_symbol, lst, cadr_a_list_string));
39056   return((is_pair(cdadr(lst))) ? cadadr(lst) : simple_wrong_type_argument_with_type(sc, sc->cadadr_symbol, lst, cdadr_a_list_string));
39057 }
39058 
39059 static s7_pointer g_cadadr(s7_scheme *sc, s7_pointer args)
39060 {
39061   #define H_cadadr "(cadadr lst) returns (car (cdr (car (cdr lst)))): (cadadr '(1 (2 3 4))) -> 3"
39062   #define Q_cadadr sc->pl_p
39063   return(cadadr_p_p(sc, car(args)));
39064 }
39065 
39066 /* -------- caddar -------- */
39067 static s7_pointer caddar_p_p(s7_scheme *sc, s7_pointer lst)
39068 {
39069   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->caddar_symbol, list_1(sc, lst), T_PAIR));
39070   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caddar_symbol, lst, car_a_list_string));
39071   if (!is_pair(cdar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caddar_symbol, lst, cdar_a_list_string));
39072   return((is_pair(cddar(lst))) ? caddar(lst) : simple_wrong_type_argument_with_type(sc, sc->caddar_symbol, lst, cddar_a_list_string));
39073 }
39074 
39075 static s7_pointer g_caddar(s7_scheme *sc, s7_pointer args)
39076 {
39077   #define H_caddar "(caddar lst) returns (car (cdr (cdr (car lst)))): (caddar '((1 2 3 4))) -> 3"
39078   #define Q_caddar sc->pl_p
39079   return(caddar_p_p(sc, car(args)));
39080 }
39081 
39082 /* -------- cdaaar -------- */
39083 static s7_pointer g_cdaaar(s7_scheme *sc, s7_pointer args)
39084 {
39085   s7_pointer lst;
39086   #define H_cdaaar "(cdaaar lst) returns (cdr (car (car (car lst)))): (cdaaar '((((1 2 3))))) -> '(2 3)"
39087   #define Q_cdaaar sc->pl_p
39088 
39089   lst = car(args);
39090   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cdaaar_symbol, args, T_PAIR));
39091   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaaar_symbol, lst, car_a_list_string));
39092   if (!is_pair(caar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaaar_symbol, lst, caar_a_list_string));
39093   return((is_pair(caaar(lst))) ? cdaaar(lst) : simple_wrong_type_argument_with_type(sc, sc->cdaaar_symbol, lst, caaar_a_list_string));
39094 }
39095 
39096 /* -------- cdaadr -------- */
39097 static s7_pointer g_cdaadr(s7_scheme *sc, s7_pointer args)
39098 {
39099   s7_pointer lst;
39100   #define H_cdaadr "(cdaadr lst) returns (cdr (car (car (cdr lst)))): (cdaadr '(1 ((2 3 4)))) -> '(3 4)"
39101   #define Q_cdaadr sc->pl_p
39102 
39103   lst = car(args);
39104   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cdaadr_symbol, args, T_PAIR));
39105   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaadr_symbol, lst, cdr_a_list_string));
39106   if (!is_pair(cadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaadr_symbol, lst, cadr_a_list_string));
39107   return((is_pair(caadr(lst))) ? cdaadr(lst) : simple_wrong_type_argument_with_type(sc, sc->cdaadr_symbol, lst, caadr_a_list_string));
39108 }
39109 
39110 /* -------- cdadar -------- */
39111 static s7_pointer g_cdadar(s7_scheme *sc, s7_pointer args)
39112 {
39113   s7_pointer lst;
39114   #define H_cdadar "(cdadar lst) returns (cdr (car (cdr (car lst)))): (cdadar '((1 (2 3 4)))) -> '(3 4)"
39115   #define Q_cdadar sc->pl_p
39116 
39117   lst = car(args);
39118   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cdadar_symbol, args, T_PAIR));
39119   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdadar_symbol, lst, car_a_list_string));
39120   if (!is_pair(cdar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdadar_symbol, lst, cdar_a_list_string));
39121   return((is_pair(cadar(lst))) ? cdadar(lst) : simple_wrong_type_argument_with_type(sc, sc->cdadar_symbol, lst, cadar_a_list_string));
39122 }
39123 
39124 /* -------- cddaar -------- */
39125 static s7_pointer g_cddaar(s7_scheme *sc, s7_pointer args)
39126 {
39127   s7_pointer lst;
39128   #define H_cddaar "(cddaar lst) returns (cdr (cdr (car (car lst)))): (cddaar '(((1 2 3 4)))) -> '(3 4)"
39129   #define Q_cddaar sc->pl_p
39130 
39131   lst = car(args);
39132   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cddaar_symbol, args, T_PAIR));
39133   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddaar_symbol, lst, car_a_list_string));
39134   if (!is_pair(caar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddaar_symbol, lst, caar_a_list_string));
39135   return((is_pair(cdaar(lst))) ? cddaar(lst) : simple_wrong_type_argument_with_type(sc, sc->cddaar_symbol, lst, cdaar_a_list_string));
39136 }
39137 
39138 /* -------- cdaddr -------- */
39139 static s7_pointer g_cdaddr(s7_scheme *sc, s7_pointer args)
39140 {
39141   s7_pointer lst;
39142   #define H_cdaddr "(cdaddr lst) returns (cdr (car (cdr (cdr lst)))): (cdaddr '(1 2 (3 4 5))) -> '(4 5)"
39143   #define Q_cdaddr sc->pl_p
39144 
39145   lst = car(args);
39146   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cdaddr_symbol, args, T_PAIR));
39147   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaddr_symbol, lst, cdr_a_list_string));
39148   if (!is_pair(cddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaddr_symbol, lst, cddr_a_list_string));
39149   return((is_pair(caddr(lst))) ? cdaddr(lst) : simple_wrong_type_argument_with_type(sc, sc->cdaddr_symbol, lst, caddr_a_list_string));
39150 }
39151 
39152 /* -------- cddddr -------- */
39153 static s7_pointer g_cddddr(s7_scheme *sc, s7_pointer args)
39154 {
39155   s7_pointer lst;
39156   #define H_cddddr "(cddddr lst) returns (cdr (cdr (cdr (cdr lst)))): (cddddr '(1 2 3 4 5)) -> '(5)"
39157   #define Q_cddddr sc->pl_p
39158 
39159   lst = car(args);
39160   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cddddr_symbol, args, T_PAIR));
39161   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddddr_symbol, lst, cdr_a_list_string));
39162   if (!is_pair(cddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddddr_symbol, lst, cddr_a_list_string));
39163   return((is_pair(cdddr(lst))) ? cddddr(lst) : simple_wrong_type_argument_with_type(sc, sc->cddddr_symbol, lst, cdddr_a_list_string));
39164 }
39165 
39166 /* -------- cddadr -------- */
39167 static s7_pointer g_cddadr(s7_scheme *sc, s7_pointer args)
39168 {
39169   s7_pointer lst;
39170   #define H_cddadr "(cddadr lst) returns (cdr (cdr (car (cdr lst)))): (cddadr '(1 (2 3 4 5))) -> '(4 5)"
39171   #define Q_cddadr sc->pl_p
39172 
39173   lst = car(args);
39174   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cddadr_symbol, args, T_PAIR));
39175   if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddadr_symbol, lst, cdr_a_list_string));
39176   if (!is_pair(cadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddadr_symbol, lst, cadr_a_list_string));
39177   return((is_pair(cdadr(lst))) ? cddadr(lst) : simple_wrong_type_argument_with_type(sc, sc->cddadr_symbol, lst, cdadr_a_list_string));
39178 }
39179 
39180 /* -------- cdddar -------- */
39181 static s7_pointer g_cdddar(s7_scheme *sc, s7_pointer args)
39182 {
39183   s7_pointer lst;
39184   #define H_cdddar "(cdddar lst) returns (cdr (cdr (cdr (car lst)))): (cdddar '((1 2 3 4 5))) -> '(4 5)"
39185   #define Q_cdddar sc->pl_p
39186 
39187   lst = car(args);
39188   if (!is_pair(lst)) return(method_or_bust_one_arg(sc, lst, sc->cdddar_symbol, args, T_PAIR));
39189   if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdddar_symbol, lst, car_a_list_string));
39190   if (!is_pair(cdar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdddar_symbol, lst, cdar_a_list_string));
39191   return((is_pair(cddar(lst))) ? cdddar(lst) : simple_wrong_type_argument_with_type(sc, sc->cdddar_symbol, lst, cddar_a_list_string));
39192 }
39193 
39194 
39195 /* -------------------------------- assoc assv assq -------------------------------- */
39196 s7_pointer s7_assq(s7_scheme *sc, s7_pointer obj, s7_pointer x)
39197 {
39198   s7_pointer y;
39199   y = x;
39200   while (true)
39201     {
39202       /* we can blithely take the car of anything, since we're not treating it as an object,
39203        *   then if we get a bogus match, the following check that caar made sense ought to catch it.
39204        * if car(#<unspecified>) = #<unspecified> (initialization time), then cdr(nil)->unspec
39205        *   and subsequent caar(unspec)->unspec so we could forgo half the is_pair checks below.
39206        *   This breaks if "x" is a dotted list -- the last cdr is not nil, so we lose.
39207        */
39208       LOOP_8(if ((obj == unchecked_car(car(x))) && (is_pair(car(x)))) return(car(x)); x = cdr(x); if (!is_pair(x)) return(sc->F));
39209 
39210       y = cdr(y);
39211       if (x == y) return(sc->F);
39212     }
39213   return(sc->F); /* not reached */
39214 }
39215 
39216 static s7_pointer assq_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
39217 {
39218   return((is_pair(y)) ? s7_assq(sc, x, y) :
39219 	 ((is_null(y)) ? sc->F :
39220 	  method_or_bust_with_type_pp(sc, y, sc->assq_symbol, x, y, an_association_list_string, 2)));
39221 }
39222 
39223 static s7_pointer g_assq(s7_scheme *sc, s7_pointer args)
39224 {
39225   #define H_assq "(assq obj alist) returns the key-value pair associated (via eq?) with the key obj in the association list alist"
39226   #define Q_assq s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->not_symbol), sc->T, sc->is_list_symbol)
39227 
39228   return(assq_p_pp(sc, car(args), cadr(args)));
39229   /* we don't check for (pair? (car x)) here (or in assv) so we get some inconsistency with assoc:
39230    *  (assq #f '(#f 2 . 3)) -> #f
39231    *  (assoc #f '(#f 2 . 3)) -> 'error
39232    */
39233 }
39234 
39235 static s7_pointer assv_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
39236 {
39237   s7_pointer z;
39238   if (!is_pair(y))
39239     {
39240       if (is_null(y)) return(sc->F);
39241       return(method_or_bust_with_type_pp(sc, y, sc->assv_symbol, x, y, an_association_list_string, 2));
39242     }
39243 
39244   if (is_simple(x))
39245     return(s7_assq(sc, x, y));
39246 
39247   z = y;
39248   while (true)
39249     {
39250       /* here we can't play the assq == game because s7_is_eqv thinks it's getting a legit s7 object */
39251       if ((is_pair(car(y))) && (s7_is_eqv(sc, x, caar(y)))) return(car(y));
39252       y = cdr(y);
39253       if (!is_pair(y)) return(sc->F);
39254 
39255       if ((is_pair(car(y))) && (s7_is_eqv(sc, x, caar(y)))) return(car(y));
39256       y = cdr(y);
39257       if (!is_pair(y)) return(sc->F);
39258 
39259       z = cdr(z);
39260       if (z == y) return(sc->F);
39261     }
39262   return(sc->F); /* not reached */
39263 }
39264 
39265 static s7_pointer g_assv(s7_scheme *sc, s7_pointer args)        /* g_assv is called by g_assoc below */
39266 {
39267   #define H_assv "(assv obj alist) returns the key-value pair associated (via eqv?) with the key obj in the association list alist"
39268   #define Q_assv Q_assq
39269   return(assv_p_pp(sc, car(args), cadr(args)));
39270 }
39271 
39272 s7_pointer s7_assoc(s7_scheme *sc, s7_pointer sym, s7_pointer lst)
39273 {
39274   s7_pointer x, y;
39275 
39276   if (!is_pair(lst))
39277     return(sc->F);
39278 
39279   x = lst;
39280   y = lst;
39281   while (true)
39282     {
39283       if ((is_pair(car(x))) && (s7_is_equal(sc, sym, caar(x)))) return(car(x));
39284       x = cdr(x);
39285       if (!is_pair(x)) return(sc->F);
39286 
39287       if ((is_pair(car(x))) && (s7_is_equal(sc, sym, caar(x)))) return(car(x));
39288       x = cdr(x);
39289       if (!is_pair(x)) return(sc->F);
39290 
39291       y = cdr(y);
39292       if (x == y) return(sc->F);
39293     }
39294   return(sc->F);
39295 }
39296 
39297 static s7_pointer g_is_eq(s7_scheme *sc, s7_pointer args);
39298 static s7_pointer g_is_eqv(s7_scheme *sc, s7_pointer args);
39299 static s7_function s7_bool_optimize(s7_scheme *sc, s7_pointer expr);
39300 static s7_pointer opt_bool_any(s7_scheme *sc, s7_pointer expr);
39301 
39302 static s7_pointer g_assoc(s7_scheme *sc, s7_pointer args)
39303 {
39304   #define H_assoc "(assoc obj alist (func #f)) returns the key-value pair associated (via equal?) with the key obj in the association list alist.\
39305 If 'func' is a function of 2 arguments, it is used for the comparison instead of 'equal?"
39306   #define Q_assoc s7_make_signature(sc, 4, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_boolean_symbol), sc->T, sc->is_list_symbol, sc->is_procedure_symbol)
39307 
39308   s7_pointer x, y, obj, eq_func = NULL;
39309 
39310   x = cadr(args);
39311   if (!is_null(x))
39312     {
39313       if (!is_pair(x))
39314 	return(method_or_bust_with_type(sc, x, sc->assoc_symbol, args, an_association_list_string, 2));
39315 
39316       if ((is_pair(x)) && (!is_pair(car(x))))
39317 	return(wrong_type_argument_with_type(sc, sc->assoc_symbol, 2, x, an_association_list_string)); /* we're assuming caar below so it better exist */
39318     }
39319 
39320   if (is_not_null(cddr(args)))
39321     {
39322       /* check third arg before second (trailing arg error check) */
39323       eq_func = caddr(args);
39324 
39325       if (type(eq_func) < T_CONTINUATION)
39326 	return(method_or_bust_with_type_one_arg(sc, eq_func, sc->assoc_symbol, args, a_procedure_string));
39327 
39328       if (!s7_is_aritable(sc, eq_func, 2))
39329 	return(wrong_type_argument_with_type(sc, sc->assoc_symbol, 3, eq_func, an_eq_func_string));
39330     }
39331   if (is_null(x)) return(sc->F);
39332 
39333   if (eq_func)
39334     {
39335       /* here we know x is a pair, but need to protect against circular lists */
39336       if (s7_list_length(sc, x) != 0)
39337 	{
39338 	  /* now maybe there's a simple case */
39339 	  if ((is_safe_procedure(eq_func)) &&
39340 	      (is_c_function(eq_func)))
39341 	    {
39342 	      s7_function func;
39343 
39344 	      func = c_function_call(eq_func);
39345 	      if (func == g_is_eq) return(s7_assq(sc, car(args), x));
39346 	      if (func == g_is_eqv) return(assv_p_pp(sc, car(args), x));
39347 	      set_car(sc->t2_1, car(args));
39348 
39349 	      for (; is_pair(x); x = cdr(x))
39350 		{
39351 		  if (!is_pair(car(x)))
39352 		    return(wrong_type_argument_with_type(sc, sc->assoc_symbol, 2, cadr(args), an_association_list_string));
39353 		  set_car(sc->t2_2, caar(x));
39354 		  if (is_true(sc, func(sc, sc->t2_1)))
39355 		    return(car(x));
39356 		  /* I wonder if the assoc equality function should get the cons, not just caar? */
39357 		}
39358 	      return(sc->F);
39359 	    }
39360 
39361 	  if ((is_closure(eq_func)) &&
39362 	      (is_pair(closure_args(eq_func))) &&
39363 	      (is_pair(cdr(closure_args(eq_func))))) /* not dotted arg list */
39364 	    {
39365 	      s7_pointer body;
39366 	      body = closure_body(eq_func);
39367 	      if (is_null(cdr(body)))
39368 		{
39369 		  s7_function func;
39370 
39371 		  sc->curlet = make_let_with_two_slots(sc, sc->curlet, car(closure_args(eq_func)), car(args), cadr(closure_args(eq_func)), sc->F);
39372 		  func = s7_bool_optimize(sc, body);
39373 		  if (func)
39374 		    {
39375 		      s7_pointer b;
39376 		      b = next_slot(let_slots(sc->curlet));
39377 
39378 		      if (func == opt_bool_any)
39379 			{
39380 			  opt_info *o;
39381 			  o = sc->opts[0];
39382 			  for (; is_pair(x); x = cdr(x))
39383 			    {
39384 			      slot_set_value(b, caar(x));
39385 			      if (o->v[0].fb(o))
39386 				return(car(x));
39387 			    }
39388 			  return(sc->F);
39389 			}}}}}
39390 
39391       /* member_if is similar.  Do not call eval here with op_eval_done to return!  An error will longjmp past the
39392        *   assoc point, leaving the op_eval_done on the stack, causing s7 to quit.
39393        */
39394       y = list_1(sc, args);
39395       set_opt1_fast(y, x);
39396       set_opt2_slow(y, x);
39397       push_stack(sc, OP_ASSOC_IF, list_1(sc, y), eq_func);
39398       if (needs_copied_args(eq_func))
39399 	push_stack(sc, OP_APPLY, list_2(sc, car(args), caar(x)), eq_func);
39400       else
39401 	{
39402 	  set_car(sc->t2_1, car(args));
39403 	  set_car(sc->t2_2, caar(x));
39404 	  push_stack(sc, OP_APPLY, sc->t2_1, eq_func);
39405 	}
39406       return(sc->unspecified);
39407     }
39408 
39409   x = cadr(args);
39410   obj = car(args);
39411   if (is_simple(obj))
39412     return(s7_assq(sc, obj, x));
39413 
39414   y = x;
39415   if (is_string(obj))
39416     {
39417       s7_pointer val;
39418       while (true)
39419 	{
39420 	  if (is_pair(car(x)))
39421 	    {
39422 	      val = caar(x);
39423 	      if ((val == obj) ||
39424 		  ((is_string(val)) &&
39425 		   (scheme_strings_are_equal(obj, val))))
39426 		return(car(x));
39427 	    }
39428 	  x = cdr(x);
39429 	  if (!is_pair(x)) return(sc->F);
39430 
39431 	  if (is_pair(car(x)))
39432 	    {
39433 	      val = caar(x);
39434 	      if ((val == obj) ||
39435 		  ((is_string(val)) &&
39436 		   (scheme_strings_are_equal(obj, val))))
39437 		return(car(x));
39438 	    }
39439 	  x = cdr(x);
39440 	  if (!is_pair(x)) return(sc->F);
39441 
39442 	  y = cdr(y);
39443 	  if (x == y) return(sc->F);
39444 	}
39445       return(sc->F);
39446     }
39447 
39448   while (true)
39449     {
39450       if ((is_pair(car(x))) && (s7_is_equal(sc, obj, caar(x)))) return(car(x));
39451       x = cdr(x);
39452       if (!is_pair(x)) return(sc->F);
39453 
39454       if ((is_pair(car(x))) && (s7_is_equal(sc, obj, caar(x)))) return(car(x));
39455       x = cdr(x);
39456       if (!is_pair(x)) return(sc->F);
39457 
39458       y = cdr(y);
39459       if (x == y) return(sc->F);
39460     }
39461   return(sc->F); /* not reached */
39462 }
39463 
39464 static s7_pointer assoc_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2) {return(g_assoc(sc, set_plist_2(sc, p1, p2)));}
39465 
39466 static bool assoc_if(s7_scheme *sc)
39467 {
39468   s7_pointer orig_args;
39469   orig_args = car(sc->args);
39470   /* code=func, args=(list (list args)) with f/opt1_fast=list, value=result of comparison
39471    *   (assoc 3 '((1 . a) (2 . b) (3 . c) (4 . d)) =)
39472    */
39473   if (sc->value != sc->F)            /* previous comparison was not #f -- return (car list) */
39474     {
39475       sc->value = car(opt1_fast(orig_args));
39476       return(true);
39477     }
39478   if (!is_pair(cdr(opt1_fast(orig_args))))             /* (assoc 3 '((1 . 2) . 3) =) or nil */
39479     {
39480       sc->value = sc->F;
39481       return(true);
39482     }
39483   set_opt1_fast(orig_args, cdr(opt1_fast(orig_args)));  /* cdr down arg list */
39484 
39485   if (sc->cur_op == OP_ASSOC_IF1)
39486     {
39487       /* circular list check */
39488       if (opt1_fast(orig_args) == opt2_slow(orig_args))
39489 	{
39490 	  sc->value = sc->F;
39491 	  return(true);
39492 	}
39493       set_opt2_slow(orig_args, cdr(opt2_slow(orig_args))); /* cdr down the slow list */
39494       push_stack_direct(sc, OP_ASSOC_IF);
39495     }
39496   else push_stack_direct(sc, OP_ASSOC_IF1);
39497 
39498   if (!is_pair(car(opt1_fast(orig_args))))     /* (assoc 1 '((2 . 2) 3) =) -- we access caaadr below */
39499     eval_error_any(sc, sc->wrong_type_arg_symbol, "assoc: second arg is not an alist: ~S", 37, orig_args);
39500   /* not sure about this -- we could simply skip the entry both here and in g_assoc
39501    *   (assoc 1 '((2 . 2) 3)) -> #f
39502    *   (assoc 1 '((2 . 2) 3) =) -> error currently
39503    */
39504   if (needs_copied_args(sc->code))
39505     sc->args = list_2(sc, caar(orig_args), caar(opt1_fast(orig_args)));
39506   else sc->args = set_plist_2(sc, caar(orig_args), caar(opt1_fast(orig_args)));
39507   return(false);
39508 }
39509 
39510 
39511 /* ---------------- member, memv, memq ---------------- */
39512 
39513 s7_pointer s7_memq(s7_scheme *sc, s7_pointer obj, s7_pointer x)
39514 {
39515   s7_pointer y;
39516   y = x;
39517   while (true)
39518     {
39519       LOOP_4(if (obj == car(x)) return(x); x = cdr(x); if (!is_pair(x)) return(sc->F));
39520       y = cdr(y);
39521       if (x == y) return(sc->F);
39522     }
39523   return(sc->F);
39524 }
39525 
39526 static s7_pointer memq_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
39527 {
39528   return((is_pair(y)) ? s7_memq(sc, x, y) :
39529 	 ((is_null(y)) ? sc->F :
39530 	  method_or_bust_with_type_pp(sc, y, sc->memq_symbol, x, y, a_list_string, 2)));
39531 }
39532 
39533 static s7_pointer g_memq(s7_scheme *sc, s7_pointer args)
39534 {
39535   s7_pointer x, y;
39536   #define H_memq "(memq obj list) looks for obj in list and returns the list from that point if it is found, otherwise #f. memq uses eq?"
39537   #define Q_memq sc->pl_tl
39538 
39539   x = car(args);
39540   y = cadr(args);
39541   if (is_pair(y))
39542     return(s7_memq(sc, x, y));
39543   if (is_null(y))
39544     return(sc->F);
39545   return(method_or_bust_with_type_pp(sc, y, sc->memq_symbol, x, y, a_list_string, 2));
39546 }
39547 
39548 /* I think (memq 'c '(a b . c)) should return #f because otherwise (memq () ...) would return the () at the end. */
39549 /* if memq's list is a quoted list, it won't be changing, so we can tell ahead of time that it is a proper list, and what its length is. */
39550 
39551 static s7_pointer g_memq_2(s7_scheme *sc, s7_pointer args)
39552 {
39553   s7_pointer x, obj;
39554   x = cadr(args);
39555   obj = car(args);
39556   if (obj == car(x)) return(x);
39557   return((obj == cadr(x)) ? cdr(x) : sc->F);
39558 }
39559 
39560 static s7_pointer memq_2_p_pp(s7_scheme *sc, s7_pointer obj, s7_pointer x)
39561 {
39562   if (obj == car(x)) return(x);
39563   return((obj == cadr(x)) ? cdr(x) : sc->F);
39564 }
39565 
39566 static s7_pointer memq_3_p_pp(s7_scheme *sc, s7_pointer obj, s7_pointer x)
39567 {
39568   if (obj == car(x)) return(x);
39569   if (obj == cadr(x)) return(cdr(x));
39570   return((obj == caddr(x)) ? cddr(x) : sc->F);
39571 }
39572 
39573 static s7_pointer g_memq_3(s7_scheme *sc, s7_pointer args)
39574 {
39575   s7_pointer x, obj;
39576   x = cadr(args);
39577   obj = car(args);
39578   while (true)
39579     {
39580       if (obj == car(x)) return(x);
39581       x = cdr(x);
39582       if (obj == car(x)) return(x);
39583       x = cdr(x);
39584       if (obj == car(x)) return(x);
39585       x = cdr(x);
39586       if (!is_pair(x)) return(sc->F);
39587     }
39588   return(sc->F);
39589 }
39590 
39591 static s7_pointer g_memq_4(s7_scheme *sc, s7_pointer args)
39592 {
39593   s7_pointer x, obj;
39594   x = cadr(args);
39595   obj = car(args);
39596   while (true)
39597     {
39598       LOOP_4(if (obj == car(x)) return(x); x = cdr(x));
39599       if (!is_pair(x)) return(sc->F);
39600     }
39601   return(sc->F);
39602 }
39603 
39604 static s7_pointer g_memq_any(s7_scheme *sc, s7_pointer args)
39605 {
39606   /* no circular list check needed in this case */
39607   s7_pointer x, obj;
39608   x = cadr(args);
39609   obj = car(args);
39610   while (true)
39611     {
39612       LOOP_4(if (obj == car(x)) return(x); x = cdr(x); if (!is_pair(x)) return(sc->F));
39613     }
39614   return(sc->F);
39615 }
39616 
39617 static s7_pointer memq_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
39618 {
39619   s7_pointer lst;
39620   lst = caddr(expr);
39621   if ((is_proper_quote(sc, lst)) &&
39622       (is_pair(cadr(lst))))
39623     {
39624       s7_int len;
39625       len = s7_list_length(sc, cadr(lst));
39626       if (len > 0)
39627 	{
39628 	  if (len == 2) /* this used to set opt3_any to cadr, but that doesn't survive call/cc's copy_stack */
39629 	    return(sc->memq_2);
39630 	  if ((len % 4) == 0)
39631 	    return(sc->memq_4);
39632 	  return(((len % 3) == 0) ? sc->memq_3 : sc->memq_any);
39633 	}}
39634   return(f);
39635 }
39636 
39637 static bool numbers_are_eqv(s7_scheme *sc, s7_pointer a, s7_pointer b)
39638 {
39639 #if WITH_GMP
39640   if ((is_big_number(a)) || (is_big_number(b)))
39641     return(big_numbers_are_eqv(sc, a, b));
39642 #endif
39643 
39644   if (type(a) != type(b)) return(false);    /* (eqv? 1 1.0) -> #f! */
39645 
39646   /* switch is apparently as expensive as 3-4 if's! so this only loses if every call involves complex numbers? */
39647   if (is_t_integer(a)) return(integer(a) == integer(b));
39648   if (is_t_real(a)) return((!is_NaN(real(a))) && (real(a) == real(b)));
39649   if (is_t_ratio(a)) return((numerator(a) == numerator(b)) && (denominator(a) == denominator(b)));
39650   if (!is_t_complex(a)) return(false);
39651   if ((is_NaN(real_part(a))) || (is_NaN(imag_part(a)))) return(false);
39652   return((real_part(a) == real_part(b)) && (imag_part(a) == imag_part(b)));
39653 }
39654 
39655 static s7_pointer memv_number(s7_scheme *sc, s7_pointer obj, s7_pointer x)
39656 {
39657   s7_pointer y;
39658   y = x;
39659   while (true)
39660     {
39661       LOOP_4(if ((s7_is_number(car(x))) && (numbers_are_eqv(sc, obj, car(x)))) return(x); x = cdr(x); if (!is_pair(x)) return(sc->F));
39662       y = cdr(y);
39663       if (x == y) return(sc->F);
39664     }
39665   return(sc->F);
39666 }
39667 
39668 static s7_pointer memv_p_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
39669 {
39670   s7_pointer z;
39671   if (!is_pair(y))
39672     {
39673       if (is_null(y)) return(sc->F);
39674       return(method_or_bust_with_type_pp(sc, y, sc->memv_symbol, x, y, a_list_string, 2));
39675     }
39676 
39677   if (is_simple(x)) return(s7_memq(sc, x, y));
39678   if (s7_is_number(x)) return(memv_number(sc, x, y));
39679 
39680   z = y;
39681   while (true)
39682     {
39683       if (s7_is_eqv(sc, x, car(y))) return(y);
39684       y = cdr(y);
39685       if (!is_pair(y)) return(sc->F);
39686 
39687       if (s7_is_eqv(sc, x, car(y))) return(y);
39688       y = cdr(y);
39689       if (!is_pair(y)) return(sc->F);
39690 
39691       z = cdr(z);
39692       if (z == y) return(sc->F);
39693     }
39694   return(sc->F); /* not reached */
39695 }
39696 
39697 
39698 static s7_pointer g_memv(s7_scheme *sc, s7_pointer args)
39699 {
39700   #define H_memv "(memv obj list) looks for obj in list and returns the list from that point if it is found, otherwise #f. memv uses eqv?"
39701   #define Q_memv sc->pl_tl
39702   return(memv_p_pp(sc, car(args), cadr(args)));
39703 }
39704 
39705 
39706 s7_pointer s7_member(s7_scheme *sc, s7_pointer sym, s7_pointer lst)
39707 {
39708   s7_pointer x;
39709   for (x = lst; is_pair(x); x = cdr(x))
39710     if (s7_is_equal(sc, sym, car(x)))
39711       return(x);
39712   return(sc->F);
39713 }
39714 
39715 static s7_pointer member(s7_scheme *sc, s7_pointer obj, s7_pointer x)
39716 {
39717   s7_pointer y;
39718 
39719   y = x;
39720   if (is_string(obj))
39721     {
39722       while (true)
39723 	{
39724 	  if ((obj == car(x)) ||
39725 	      ((is_string(car(x))) &&
39726 	       (scheme_strings_are_equal(obj, car(x)))))
39727 	    return(x);
39728 	  x = cdr(x);
39729 	  if (!is_pair(x)) return(sc->F);
39730 
39731 	  if ((obj == car(x)) ||
39732 	      ((is_string(car(x))) &&
39733 	       (scheme_strings_are_equal(obj, car(x)))))
39734 	    return(x);
39735 	  x = cdr(x);
39736 	  if (!is_pair(x)) return(sc->F);
39737 
39738 	  y = cdr(y);
39739 	  if (x == y) return(sc->F);
39740 	}
39741       return(sc->F);
39742     }
39743 
39744   while (true)
39745     {
39746       LOOP_4(if (s7_is_equal(sc, obj, car(x))) return(x); x = cdr(x); if (!is_pair(x)) return(sc->F));
39747       y = cdr(y);
39748       if (x == y) return(sc->F);
39749     }
39750   return(sc->F); /* not reached */
39751 }
39752 
39753 static bool p_to_b(opt_info *p);
39754 
39755 static s7_pointer g_member(s7_scheme *sc, s7_pointer args)
39756 {
39757   #define H_member "(member obj list (func #f)) looks for obj in list and returns the list from that point if it is found, otherwise #f. \
39758 member uses equal?  If 'func' is a function of 2 arguments, it is used for the comparison instead of 'equal?"
39759   #define Q_member s7_make_signature(sc, 4, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->not_symbol), sc->T, sc->is_list_symbol, sc->is_procedure_symbol)
39760 
39761   /* this could be extended to accept sequences:
39762    *    (member #\a "123123abnfc" char=?) -> "abnfc"
39763    *    (member "abc" "123abc321" string=?) -> "abc321" but there's the string length complication
39764    *    (member 1 #(0 1 2) =) -> #(1 2) etc but what would it do for a hash-table?
39765    * the third arg can be weird: (member #f (list #t) cons) -> (#t) -- cons returns '(#f . #t) which is true, so we get '(#t)
39766    * should this be an error: (member '(1 2 3) () '(1 . 2)) -- the third arg is bogus, but the second is nil
39767    *
39768    * here as in assoc, sort, and make-hash-table we accept macros, but I can't think of a good reason to do so.
39769    */
39770 
39771   s7_pointer x, obj, eq_func = NULL;
39772   x = cadr(args);
39773 
39774   if ((!is_pair(x)) && (!is_null(x)))
39775     return(method_or_bust_with_type(sc, x, sc->member_symbol, args, a_list_string, 2));
39776 
39777   if (is_not_null(cddr(args)))
39778     {
39779       /* check third arg before second (trailing arg error check) */
39780       eq_func = caddr(args);
39781 
39782       if (type(eq_func) < T_CONTINUATION)
39783 	return(method_or_bust_with_type(sc, eq_func, sc->member_symbol, args, a_procedure_string, 3));
39784 
39785       if (!s7_is_aritable(sc, eq_func, 2))
39786 	return(wrong_type_argument_with_type(sc, sc->member_symbol, 3, eq_func, an_eq_func_string));
39787     }
39788 
39789   if (is_null(x)) return(sc->F);
39790   if (eq_func)
39791     {
39792       s7_pointer y, slow;
39793 
39794       if ((is_safe_procedure(eq_func)) &&
39795 	  (is_c_function(eq_func)))
39796 	{
39797 	  s7_function func;
39798 	  func = c_function_call(eq_func);
39799 	  if (func == g_is_eq) return(s7_memq(sc, car(args), x));
39800 	  if (func == g_is_eqv) return(g_memv(sc, args));
39801 	  if (func == g_less) func = g_less_2;
39802 	  if (func == g_greater) func = g_greater_2;
39803 	  set_car(sc->t2_1, car(args));
39804 
39805 	  for (slow = x; is_pair(x); x = cdr(x), slow = cdr(slow))
39806 	    {
39807 	      set_car(sc->t2_2, car(x));
39808 	      if (is_true(sc, func(sc, sc->t2_1)))
39809 		return(x);
39810 
39811 	      if (!is_pair(cdr(x)))
39812 		return(sc->F);
39813 	      x = cdr(x);
39814 	      if (x == slow)
39815 		return(sc->F);
39816 
39817 	      set_car(sc->t2_2, car(x));
39818 	      if (is_true(sc, func(sc, sc->t2_1)))
39819 		return(x);
39820 	    }
39821 	  return(sc->F);
39822 	}
39823 
39824       if ((is_closure(eq_func)) &&
39825 	  (is_pair(closure_args(eq_func))) &&
39826 	  (is_pair(cdr(closure_args(eq_func))))) /* not dotted arg list */
39827 	{
39828 	  s7_pointer body;
39829 	  body = closure_body(eq_func);
39830 	  if ((!no_bool_opt(body)) &&
39831 	      (is_null(cdr(body))))
39832 	    {
39833 	      s7_function func;
39834 	      sc->curlet = make_let_with_two_slots(sc, sc->curlet, car(closure_args(eq_func)), car(args), cadr(closure_args(eq_func)), sc->F);
39835 	      func = s7_bool_optimize(sc, body);
39836 	      if (func == opt_bool_any)
39837 		{
39838 		  opt_info *o;
39839 		  s7_pointer b;
39840 		  o = sc->opts[0];
39841 		  b = next_slot(let_slots(sc->curlet));
39842 		  if (o->v[0].fb == p_to_b)
39843 		    {
39844 		      s7_pointer (*fp)(opt_info *o);
39845 		      fp = o->v[O_WRAP].fp;
39846 		      for (slow = x; is_pair(x); x = cdr(x), slow = cdr(slow))
39847 			{
39848 			  slot_set_value(b, car(x));
39849 			  if (fp(o) != sc->F) return(x);
39850 			  if (!is_pair(cdr(x))) return(sc->F);
39851 			  x = cdr(x);
39852 			  if (x == slow) return(sc->F);
39853 			  slot_set_value(b, car(x));
39854 			  if (fp(o) != sc->F) return(x);
39855 			}}
39856 		  else
39857 		    for (slow = x; is_pair(x); x = cdr(x), slow = cdr(slow))
39858 		      {
39859 			slot_set_value(b, car(x));
39860 			if (o->v[0].fb(o)) return(x);
39861 			if (!is_pair(cdr(x))) return(sc->F);
39862 			x = cdr(x);
39863 			if (x == slow) return(sc->F);
39864 			slot_set_value(b, car(x));
39865 			if (o->v[0].fb(o)) return(x);
39866 		      }
39867 		  return(sc->F);
39868 		}
39869 	      set_no_bool_opt(body);
39870 	    }}
39871 
39872       y = list_1(sc, args); /* this could probably be handled with a counter cell (cdr here is unused) */
39873       set_opt1_fast(y, x);
39874       set_opt2_slow(y, x);
39875       push_stack(sc, OP_MEMBER_IF, list_1(sc, y), eq_func);
39876       if (needs_copied_args(eq_func))
39877 	push_stack(sc, OP_APPLY, list_2(sc, car(args), car(x)), eq_func);
39878       else
39879 	{
39880 	  set_car(sc->t2_1, car(args));
39881 	  set_car(sc->t2_2, car(x));
39882 	  push_stack(sc, OP_APPLY, sc->t2_1, eq_func);
39883 	}
39884       return(sc->unspecified);
39885     }
39886 
39887   obj = car(args);
39888   if (is_simple(obj))
39889     return(s7_memq(sc, obj, x));
39890 
39891   /* the only things that aren't simply == here are c_object, string, number, vector, hash-table, pair, and c_pointer
39892    *   but all the other cases are unlikely.
39893    */
39894   if (s7_is_number(obj))
39895     return(memv_number(sc, obj, x));
39896 
39897   return(member(sc, obj, x));
39898 }
39899 
39900 static s7_pointer member_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2) {return(g_member(sc, set_plist_2(sc, p1, p2)));}
39901 
39902 static s7_pointer member_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
39903 {
39904   if (!ops) return(f);
39905   if ((args == 3) &&
39906       (is_normal_symbol(cadddr(expr))) &&
39907       (cadddr(expr) == sc->is_eq_symbol))
39908     return(memq_chooser(sc, f, 2, expr, ops));
39909   return(f);
39910 }
39911 
39912 static bool member_if(s7_scheme *sc)
39913 {
39914   s7_pointer orig_args;
39915   orig_args = car(sc->args);
39916   /* code=func, args = (list (list original args)) with opt1_fast->position in cadr (the list),
39917    *   the extra indirection (list (list...)) is needed because call/cc copies arg lists
39918    * value = result of comparison
39919    */
39920   if (sc->value != sc->F)                      /* previous comparison was not #f -- return list */
39921     {
39922       sc->value = opt1_fast(orig_args);
39923       return(true);
39924     }
39925   if (!is_pair(cdr(opt1_fast(orig_args))))      /* no more args -- return #f */
39926     {
39927       sc->value = sc->F;
39928       return(true);
39929     }
39930   set_opt1_fast(orig_args, cdr(opt1_fast(orig_args))); /* cdr down arg list */
39931 
39932   if (sc->cur_op == OP_MEMBER_IF1)
39933     {
39934       /* circular list check */
39935       if (opt1_fast(orig_args) == opt2_slow(orig_args))
39936 	{
39937 	  sc->value = sc->F;
39938 	  return(true);
39939 	}
39940       set_opt2_slow(orig_args, cdr(opt2_slow(orig_args))); /* cdr down the slow list (check for circular list) */
39941       push_stack_direct(sc, OP_MEMBER_IF);
39942     }
39943   else push_stack_direct(sc, OP_MEMBER_IF1);
39944 
39945   if (needs_copied_args(sc->code))
39946     sc->args = list_2(sc, caar(orig_args), car(opt1_fast(orig_args)));
39947   else sc->args = set_plist_2(sc, caar(orig_args), car(opt1_fast(orig_args)));
39948   return(false);
39949 }
39950 
39951 
39952 /* -------------------------------- list -------------------------------- */
39953 static s7_pointer g_list(s7_scheme *sc, s7_pointer args)
39954 {
39955   #define H_list "(list ...) returns its arguments in a list"
39956   #define Q_list s7_make_circular_signature(sc, 1, 2, sc->is_proper_list_symbol, sc->T)
39957   return(copy_proper_list(sc, args));
39958 }
39959 
39960 static s7_pointer g_list_0(s7_scheme *sc, s7_pointer args) {return(sc->nil);}
39961 static s7_pointer g_list_1(s7_scheme *sc, s7_pointer args) {return(list_1(sc, car(args)));}
39962 static s7_pointer g_list_2(s7_scheme *sc, s7_pointer args) {return(list_2(sc, car(args), cadr(args)));}
39963 static s7_pointer g_list_3(s7_scheme *sc, s7_pointer args) {return(list_3(sc, car(args), cadr(args), caddr(args)));}
39964 
39965 static s7_pointer list_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
39966 {
39967   if (args == 0) return(sc->list_0);
39968   if (args == 1) return(sc->list_1);
39969   if (args == 2) return(sc->list_2);
39970   return((args == 3) ? sc->list_3 : f);
39971 }
39972 
39973 static s7_pointer list_p_p(s7_scheme *sc, s7_pointer p1) {return(list_1(sc, sc->temp5 = p1));}
39974 static s7_pointer list_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2) {return(list_2(sc, p1, sc->temp5 = p2));} /* does p1 need GC protection? */
39975 /* list_p_ppp got few hits and I'm unsure about the GC here */
39976 
39977 static void check_list_validity(s7_scheme *sc, const char *caller, s7_pointer lst)
39978 {
39979   s7_pointer p;
39980   int32_t i;
39981   for (i = 1, p = lst; is_pair(p); p = cdr(p), i++)
39982     if (!s7_is_valid(sc, car(p)))
39983       s7_warn(sc, 256, "bad arg (#%d) to %s: %p\n", i, caller, car(p));
39984 }
39985 
39986 s7_pointer s7_list(s7_scheme *sc, s7_int num_values, ...)
39987 {
39988   s7_int i;
39989   va_list ap;
39990   s7_pointer p;
39991 
39992   if (num_values == 0)
39993     return(sc->nil);
39994 
39995   sc->w = make_list(sc, num_values, sc->nil);
39996   va_start(ap, num_values);
39997   for (i = 0, p = sc->w; i < num_values; i++, p = cdr(p))
39998     set_car(p, va_arg(ap, s7_pointer));
39999   va_end(ap);
40000 
40001   if (sc->safety > NO_SAFETY)
40002     check_list_validity(sc, "s7_list", sc->w);
40003 
40004   p = sc->w;
40005   sc->w = sc->nil;
40006   return(p);
40007 }
40008 
40009 static s7_pointer reverse_in_place_unchecked(s7_scheme *sc, s7_pointer term, s7_pointer list)
40010 {
40011   s7_pointer p = list, result = term;
40012   while (true)
40013     {
40014       s7_pointer q;
40015       LOOP_4(if (is_null(p)) return(result); q = cdr(p); set_cdr(p, result); result = p; p = q); /* return, not break because LOOP_4 is itself a do loop */
40016     }
40017   return(result);
40018 }
40019 
40020 static s7_pointer proper_list_reverse_in_place(s7_scheme *sc, s7_pointer list)
40021 {
40022   return(reverse_in_place_unchecked(sc, sc->nil, list));
40023 }
40024 
40025 s7_pointer s7_list_nl(s7_scheme *sc, s7_int num_values, ...) /* arglist should be NULL terminated */
40026 {
40027   s7_int i;
40028   va_list ap;
40029   s7_pointer p;
40030 
40031   if (num_values == 0)
40032     return(sc->nil);
40033 
40034   sc->w = sc->nil;
40035   va_start(ap, num_values);
40036   for (i = 0; i < num_values; i++)
40037     {
40038       p = va_arg(ap, s7_pointer);
40039       if (!p)
40040 	{
40041 	  va_end(ap);
40042 	  return(s7_wrong_number_of_args_error(sc, "not enough arguments for s7_list_nl: ~S", proper_list_reverse_in_place(sc, sc->w)));
40043 	}
40044       sc->w = cons(sc, p, sc->w);
40045     }
40046   p = va_arg(ap, s7_pointer);
40047   va_end(ap);
40048   if (p)
40049     return(s7_wrong_number_of_args_error(sc, "too many arguments for s7_list_nl: ~S", proper_list_reverse_in_place(sc, sc->w)));
40050 
40051   if (sc->safety > NO_SAFETY)
40052     check_list_validity(sc, "s7_list_nl", sc->w);
40053 
40054   p = sc->w;
40055   sc->w = sc->nil;
40056   return(proper_list_reverse_in_place(sc, p));
40057 }
40058 
40059 static s7_pointer safe_list_1(s7_scheme *sc)
40060 {
40061   if (!list_is_in_use(sc->safe_lists[1]))
40062     {
40063       sc->current_safe_list = 1;
40064       set_list_in_use(sc->safe_lists[1]);
40065       return(sc->safe_lists[1]);
40066     }
40067   return(cons(sc, sc->nil, sc->nil));
40068 }
40069 
40070 static s7_pointer safe_list_2(s7_scheme *sc)
40071 {
40072   if (!list_is_in_use(sc->safe_lists[2]))
40073     {
40074       sc->current_safe_list = 2;
40075       set_list_in_use(sc->safe_lists[2]);
40076       return(sc->safe_lists[2]);
40077     }
40078   return(cons_unchecked(sc, sc->nil, list_1(sc, sc->nil)));
40079 }
40080 
40081 static s7_pointer make_safe_list(s7_scheme *sc, s7_int num_args)
40082 {
40083   if (num_args < NUM_SAFE_LISTS)
40084     {
40085       sc->current_safe_list = num_args;
40086       if (!is_pair(sc->safe_lists[num_args]))
40087 	sc->safe_lists[num_args] = permanent_list(sc, num_args);
40088       if (!list_is_in_use(sc->safe_lists[num_args]))
40089 	{
40090 	  set_list_in_use(sc->safe_lists[num_args]);
40091 	  return(sc->safe_lists[num_args]);
40092 	}}
40093   return(make_big_list(sc, num_args, sc->nil));
40094 }
40095 
40096 static inline s7_pointer safe_list_if_possible(s7_scheme *sc, s7_int num_args)
40097 {
40098   if ((num_args < NUM_SAFE_PRELISTS) &&
40099       (!list_is_in_use(sc->safe_lists[num_args])))
40100     {
40101       sc->current_safe_list = num_args;
40102       set_list_in_use(sc->safe_lists[num_args]);
40103       return(sc->safe_lists[num_args]);
40104     }
40105   return(make_safe_list(sc, num_args));
40106 }
40107 
40108 static s7_int sequence_length(s7_scheme *sc, s7_pointer lst);
40109 static s7_pointer s7_copy_1(s7_scheme *sc, s7_pointer caller, s7_pointer args);
40110 
40111 static s7_pointer g_list_append(s7_scheme *sc, s7_pointer args)
40112 {
40113   s7_pointer y, tp, np = NULL, pp;
40114   bool all_args_are_lists = true;
40115 
40116   /* we know here that car(args) is a list and cdr(args) is not nil; this function does not check sc->max_list_length; called only in g_append */
40117   tp = sc->nil;
40118   push_stack_no_let_no_code(sc, OP_GC_PROTECT, args);
40119   for (y = args; is_pair(y); y = cdr(y)) /* arglist so not dotted */
40120     {
40121       s7_pointer p, func;
40122       p = car(y);
40123 
40124       if ((has_active_methods(sc, p)) &&
40125 	  ((func = find_method_with_let(sc, p, sc->append_symbol)) != sc->undefined))
40126 	{
40127 	  unstack(sc);
40128 	  return(call_method(sc, p, func, (is_null(tp)) ? y : set_ulist_1(sc, tp, y)));
40129 	}
40130 
40131       if (is_null(cdr(y)))
40132 	{
40133 	  if (is_null(tp))
40134 	    {
40135 	      unstack(sc);
40136 	      return(p);
40137 	    }
40138 	  /* (append (list 1) "hi") should return '(1 . "hi") not '(1 #\h #\i)
40139 	   *   but this is inconsistent with (append (list 1) "hi" "hi") -> '(1 #\h #\i . "hi") ?
40140 	   *   Perhaps if all args but last are lists, returned dotted list?
40141 	   */
40142 	  if ((all_args_are_lists) || (is_null(p)))
40143 	    set_cdr(np, p);
40144 	  else
40145 	    {
40146 	      s7_int len;
40147 	      len = sequence_length(sc, p);
40148 	      if (len > 0)
40149 		set_cdr(np, s7_copy_1(sc, sc->append_symbol, set_plist_2(sc, p, protected_make_list(sc, len, sc->F))));
40150 	      else
40151 		if (len < 0)
40152 		  set_cdr(np, p);
40153 	    }
40154 	  sc->y = sc->nil;
40155 	  unstack(sc);
40156 	  return(tp);
40157 	}
40158 
40159       if (!is_sequence(p))
40160 	return(wrong_type_argument_with_type(sc, sc->append_symbol, position_of(y, args), p, a_sequence_string));
40161 
40162       if (!is_null(p))
40163 	{
40164 	  if (is_pair(p))
40165 	    {
40166 	      if (!s7_is_proper_list(sc, p))
40167 		{
40168 		  sc->y = sc->nil;
40169 		  return(wrong_type_argument_with_type(sc, sc->append_symbol, position_of(y, args), p, a_proper_list_string));
40170 		}
40171 	      if (is_null(tp))
40172 		{
40173 		  tp = list_1(sc, car(p));
40174 		  np = tp;
40175 		  sc->y = tp; /* GC protect? */
40176 		  pp = cdr(p);
40177 		}
40178 	      else pp = p;
40179 	      for (; is_pair(pp); pp = cdr(pp), np = cdr(np))
40180 		set_cdr(np, list_1(sc, car(pp)));
40181 	    }
40182 	  else
40183 	    {
40184 	      s7_int len;
40185 	      len = sequence_length(sc, p);
40186 	      all_args_are_lists = false;
40187 	      if (len > 0)
40188 		{
40189 		  if (is_null(tp))
40190 		    {
40191 		      tp = s7_copy_1(sc, sc->append_symbol, set_plist_2(sc, p, protected_make_list(sc, len, sc->F)));
40192 		      np = tp;
40193 		      sc->y = tp;
40194 		    }
40195 		  else set_cdr(np, s7_copy_1(sc, sc->append_symbol, set_plist_2(sc, p, protected_make_list(sc, len, sc->F))));
40196 		  for (; is_pair(cdr(np)); np = cdr(np));
40197 		}
40198 	      else
40199 		if (len < 0)
40200 		  return(wrong_type_argument_with_type(sc, sc->append_symbol, position_of(y, args), p, a_sequence_string));
40201 	    }}}
40202   unstack(sc);
40203   return(tp);
40204 }
40205 
40206 static s7_pointer append_in_place(s7_scheme *sc, s7_pointer a, s7_pointer b)
40207 {
40208   /* tack b onto the end of a without copying either -- 'a' is changed! */
40209   s7_pointer p;
40210   if (is_null(a))
40211     return(b);
40212   p = a;
40213   while (is_not_null(cdr(p))) p = cdr(p);
40214   set_cdr(p, b);
40215   return(a);
40216 }
40217 
40218 
40219 /* -------------------------------- vectors -------------------------------- */
40220 
40221 bool s7_is_vector(s7_pointer p)             {return(is_any_vector(p));}
40222 bool s7_is_float_vector(s7_pointer p)       {return(is_float_vector(p));}
40223 bool s7_is_int_vector(s7_pointer p)         {return(is_int_vector(p));}
40224 static bool s7_is_byte_vector(s7_pointer b) {return(is_byte_vector(b));}
40225 
40226 s7_int s7_vector_length(s7_pointer vec) {return(vector_length(vec));}
40227 
40228 static s7_pointer default_vector_setter(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val)
40229 {
40230   vector_element(vec, loc) = val;
40231   return(val);
40232 }
40233 
40234 static s7_pointer typed_vector_typer_symbol(s7_scheme *sc, s7_pointer p)
40235 {
40236   s7_pointer typer;
40237   typer = typed_vector_typer(p);
40238   return((is_c_function(typer)) ? c_function_symbol(typer) : find_closure(sc, typer, closure_let(typer)));
40239 }
40240 
40241 static const char *typed_vector_typer_name(s7_scheme *sc, s7_pointer p)
40242 {
40243   s7_pointer typer;
40244   typer = typed_vector_typer(p);
40245   return((is_c_function(typer)) ? c_function_name(typer) : symbol_name(typed_vector_typer_symbol(sc, p)));
40246 }
40247 
40248 static const char *make_type_name(s7_scheme *sc, const char *name, article_t article);
40249 
40250 static inline s7_pointer typed_vector_setter(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val)
40251 {
40252   if ((sc->safety < NO_SAFETY) || /* or == NO_SAFETY?? */
40253       (typed_vector_typer_call(sc, vec, set_plist_1(sc, val)) != sc->F))
40254     {
40255       vector_element(vec, loc) = val;
40256       return(val);
40257     }
40258   return(s7_wrong_type_arg_error(sc, "vector-set!", 3, val, make_type_name(sc, typed_vector_typer_name(sc, vec), INDEFINITE_ARTICLE)));
40259 }
40260 
40261 static s7_pointer default_vector_getter(s7_scheme *sc, s7_pointer vec, s7_int loc)
40262 {
40263   return(vector_element(vec, loc));
40264 }
40265 
40266 static s7_pointer int_vector_setter(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val)
40267 {
40268   if (s7_is_integer(val))
40269     int_vector(vec, loc) = s7_integer_checked(sc, val);
40270   else s7_wrong_type_arg_error(sc, "int-vector-set!", 3, val, "an integer");
40271   return(val);
40272 }
40273 
40274 static s7_pointer int_vector_getter(s7_scheme *sc, s7_pointer vec, s7_int loc)
40275 {
40276   return(make_integer(sc, int_vector(vec, loc)));
40277 }
40278 
40279 static s7_pointer float_vector_setter(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val)
40280 {
40281   float_vector(vec, loc) = real_to_double(sc, val, "float-vector-set!");
40282   return(val);
40283 }
40284 
40285 static s7_pointer float_vector_getter(s7_scheme *sc, s7_pointer vec, s7_int loc)
40286 {
40287   return(make_real(sc, float_vector(vec, loc)));
40288 }
40289 
40290 static s7_pointer byte_vector_getter(s7_scheme *sc, s7_pointer bv, s7_int loc)
40291 {
40292   return(make_integer(sc, (uint8_t)(byte_vector(bv, loc))));
40293 }
40294 
40295 static s7_pointer byte_vector_setter(s7_scheme *sc, s7_pointer str, s7_int loc, s7_pointer val)
40296 {
40297   if (s7_is_integer(val))
40298     {
40299       s7_int byte;
40300       byte = s7_integer_checked(sc, val);
40301       if ((byte >= 0) && (byte < 256))
40302 	{
40303 	  byte_vector(str, loc) = (uint8_t)byte;
40304 	  return(val);
40305 	}
40306       return(s7_wrong_type_arg_error(sc, "byte-vector-set!", 3, val, "a byte"));
40307     }
40308   return(s7_wrong_type_arg_error(sc, "byte-vector-set!", 3, val, "an integer"));
40309 }
40310 
40311 static Inline block_t *mallocate_vector(s7_scheme *sc, s7_int len)
40312 {
40313   block_t *b;
40314   if (len > 0)
40315     return(mallocate(sc, len));
40316   b = mallocate_block(sc);
40317   block_data(b) = NULL;
40318   block_info(b) = NULL;
40319   return(b);
40320 }
40321 
40322 static inline s7_pointer make_simple_vector(s7_scheme *sc, s7_int len) /* len >= 0 and < max */
40323 {
40324   s7_pointer x;
40325   block_t *b;
40326   new_cell(sc, x, T_VECTOR | T_SAFE_PROCEDURE);
40327   vector_length(x) = len;
40328   b = mallocate_vector(sc, len * sizeof(s7_pointer));
40329   vector_block(x) = b;
40330   vector_elements(x) = (s7_pointer *)block_data(b);
40331   vector_set_dimension_info(x, NULL);
40332   vector_getter(x) = default_vector_getter;
40333   vector_setter(x) = default_vector_setter;
40334   add_vector(sc, x);
40335   return(x);
40336 }
40337 
40338 static inline s7_pointer make_simple_float_vector(s7_scheme *sc, s7_int len) /* len >= 0 and < max */
40339 {
40340   s7_pointer x;
40341   block_t *b;
40342   new_cell(sc, x, T_FLOAT_VECTOR | T_SAFE_PROCEDURE);
40343   vector_length(x) = len;
40344   b = mallocate_vector(sc, len * sizeof(s7_double));
40345   vector_block(x) = b;
40346   float_vector_floats(x) = (s7_double *)block_data(b);
40347   vector_set_dimension_info(x, NULL);
40348   vector_getter(x) = float_vector_getter;
40349   vector_setter(x) = float_vector_setter;
40350   add_vector(sc, x);
40351   return(x);
40352 }
40353 
40354 static inline s7_pointer make_simple_int_vector(s7_scheme *sc, s7_int len) /* len >= 0 and < max */
40355 {
40356   s7_pointer x;
40357   block_t *b;
40358   new_cell(sc, x, T_INT_VECTOR | T_SAFE_PROCEDURE);
40359   vector_length(x) = len;
40360   b = mallocate_vector(sc, len * sizeof(s7_int));
40361   vector_block(x) = b;
40362   int_vector_ints(x) = (s7_int *)block_data(b);
40363   vector_set_dimension_info(x, NULL);
40364   vector_getter(x) = int_vector_getter;
40365   vector_setter(x) = int_vector_setter;
40366   add_vector(sc, x);
40367   return(x);
40368 }
40369 
40370 static s7_pointer make_simple_byte_vector(s7_scheme *sc, s7_int len)
40371 {
40372   s7_pointer x;
40373   block_t *b;
40374   new_cell(sc, x, T_BYTE_VECTOR | T_SAFE_PROCEDURE);
40375   b = mallocate(sc, len);
40376   vector_block(x) = b;
40377   byte_vector_bytes(x) = (uint8_t *)block_data(b);
40378   vector_length(x) = len;
40379   vector_set_dimension_info(x, NULL);
40380   vector_getter(x) = byte_vector_getter;
40381   vector_setter(x) = byte_vector_setter;
40382   add_vector(sc, x);
40383   return(x);
40384 }
40385 
40386 static s7_pointer make_vector_1(s7_scheme *sc, s7_int len, bool filled, uint8_t typ)
40387 {
40388   s7_pointer x;
40389 
40390   if (len < 0)
40391     return(wrong_type_argument_with_type(sc, sc->make_vector_symbol, 1, wrap_integer1(sc, len), a_non_negative_integer_string));
40392   if (len > sc->max_vector_length)
40393     return(out_of_range(sc, sc->make_vector_symbol, int_one, wrap_integer1(sc, len), its_too_large_string));
40394 
40395   /* this has to follow the error checks! (else garbage in free_heap temps portion confuses GC when "vector" is finalized) */
40396 
40397   new_cell(sc, x, typ | T_SAFE_PROCEDURE);
40398   vector_length(x) = len;
40399   if (len == 0)
40400     {
40401       vector_block(x) = mallocate_vector(sc, 0);
40402       vector_elements(x) = NULL;
40403       if (typ == T_VECTOR) set_has_simple_elements(x);
40404     }
40405   else
40406     {
40407       block_t *b;
40408       if (typ == T_VECTOR)
40409 	{
40410 	  b = mallocate_vector(sc, len * sizeof(s7_pointer));
40411 	  vector_block(x) = b;
40412 	  vector_elements(x) = (s7_pointer *)block_data(b);
40413 	  vector_getter(x) = default_vector_getter;
40414 	  vector_setter(x) = default_vector_setter;
40415 	  if (filled)
40416 	    s7_vector_fill(sc, x, sc->nil);
40417 	}
40418       else
40419 	{
40420 	  if (typ == T_FLOAT_VECTOR)
40421 	    {
40422 	      b = mallocate_vector(sc, len * sizeof(s7_double));
40423 	      vector_block(x) = b;
40424 	      float_vector_floats(x) = (s7_double *)block_data(b);
40425 	      if (filled)
40426 		{
40427 		  if (STEP_8(len))
40428 		    memclr64((void *)vector_elements(x), len * sizeof(s7_double));
40429 		  else memclr((void *)vector_elements(x), len * sizeof(s7_double));
40430 		}
40431 	      vector_getter(x) = float_vector_getter;
40432 	      vector_setter(x) = float_vector_setter;
40433 	    }
40434 	  else
40435 	    {
40436 	      if (typ == T_INT_VECTOR)
40437 		{
40438 		  b = mallocate_vector(sc, len * sizeof(s7_int));
40439 		  vector_block(x) = b;
40440 		  int_vector_ints(x) = (s7_int *)block_data(b);
40441 		  if (filled)
40442 		    {
40443 		      if (STEP_8(len))
40444 			memclr64((void *)vector_elements(x), len * sizeof(s7_int));
40445 		      else memclr((void *)vector_elements(x), len * sizeof(s7_int));
40446 		    }
40447 		  vector_getter(x) = int_vector_getter;
40448 		  vector_setter(x) = int_vector_setter;
40449 		}
40450 	      else
40451 		{
40452 		  b = mallocate(sc, len);
40453 		  vector_block(x) = b;
40454 		  byte_vector_bytes(x) = (uint8_t *)block_data(b);
40455 		  vector_getter(x) = byte_vector_getter;
40456 		  vector_setter(x) = byte_vector_setter;
40457 		  if (filled)
40458 		    {
40459 		      if (STEP_8(len))
40460 			memclr64((void *)(byte_vector_bytes(x)), len);
40461 		      else memclr((void *)(byte_vector_bytes(x)), len);
40462 		    }}}}}
40463   vector_set_dimension_info(x, NULL);
40464   return(x);
40465 }
40466 
40467 s7_pointer s7_make_vector(s7_scheme *sc, s7_int len)
40468 {
40469   s7_pointer v;
40470   v = make_vector_1(sc, len, FILLED, T_VECTOR);
40471   add_vector(sc, v);
40472   return(v);
40473 }
40474 
40475 s7_pointer s7_make_and_fill_vector(s7_scheme *sc, s7_int len, s7_pointer fill)
40476 {
40477   s7_pointer vect;
40478   vect = make_simple_vector(sc, len);
40479   s7_vector_fill(sc, vect, fill);
40480   return(vect);
40481 }
40482 
40483 static vdims_t *make_wrap_only(s7_scheme *sc) /* this makes sc->wrap_only */
40484 {
40485   vdims_t *v;
40486   v = (vdims_t *)mallocate_block(sc);
40487   vdims_original(v) = sc->F;
40488   vector_elements_should_be_freed(v) = false;
40489   vdims_rank(v) = 1;
40490   vdims_dims(v) = NULL;
40491   vdims_offsets(v) = NULL;
40492   return(v);
40493 }
40494 
40495 static vdims_t *make_vdims(s7_scheme *sc, bool elements_should_be_freed, s7_int dims, s7_int *dim_info)
40496 {
40497   vdims_t *v;
40498 
40499   if ((dims == 1) && (!elements_should_be_freed))
40500     return(sc->wrap_only);
40501 
40502   if (dims > 1)
40503     {
40504       s7_int i, offset = 1;
40505       v = (vdims_t *)mallocate(sc, dims * 2 * sizeof(s7_int));
40506       vdims_original(v) = sc->F;
40507       vector_elements_should_be_freed(v) = elements_should_be_freed;
40508       vdims_rank(v) = dims;
40509       vdims_offsets(v) = (s7_int *)(vdims_dims(v) + dims);
40510 
40511       for (i = 0; i < dims; i++)
40512 	vdims_dims(v)[i] = dim_info[i];
40513       for (i = dims - 1; i >= 0; i--)
40514 	{
40515 	  vdims_offsets(v)[i] = offset;
40516 	  offset *= vdims_dims(v)[i];
40517 	}}
40518   else
40519     {
40520       v = (vdims_t *)mallocate_block(sc);
40521       vdims_original(v) = sc->F;
40522       vector_elements_should_be_freed(v) = elements_should_be_freed;
40523       vdims_rank(v) = 1;
40524       vdims_dims(v) = NULL;
40525       vdims_offsets(v) = NULL;
40526     }
40527   return(v);
40528 }
40529 
40530 s7_pointer s7_make_int_vector(s7_scheme *sc, s7_int len, s7_int dims, s7_int *dim_info)
40531 {
40532   s7_pointer p;
40533   p = make_vector_1(sc, len, FILLED, T_INT_VECTOR);
40534   if (dim_info)
40535     {
40536       vector_set_dimension_info(p, make_vdims(sc, false, dims, dim_info));
40537       add_multivector(sc, p);
40538     }
40539   else add_vector(sc, p);
40540   return(p);
40541 }
40542 
40543 s7_pointer s7_make_float_vector(s7_scheme *sc, s7_int len, s7_int dims, s7_int *dim_info)
40544 {
40545   s7_pointer p;
40546   p = make_vector_1(sc, len, FILLED, T_FLOAT_VECTOR);
40547   if (dim_info)
40548     {
40549       vector_set_dimension_info(p, make_vdims(sc, false, dims, dim_info));
40550       add_multivector(sc, p);
40551     }
40552   else add_vector(sc, p);
40553   return(p);
40554 }
40555 
40556 s7_pointer s7_make_float_vector_wrapper(s7_scheme *sc, s7_int len, s7_double *data, s7_int dims, s7_int *dim_info, bool free_data)
40557 {
40558   /* this wraps up a C-allocated/freed double array as an s7 vector. */
40559   s7_pointer x;
40560   block_t *b;
40561 
40562   new_cell(sc, x, T_FLOAT_VECTOR | T_SAFE_PROCEDURE);
40563   b = mallocate_vector(sc, 0);
40564   vector_block(x) = b;
40565   /* block_data(b) = data; */
40566   float_vector_floats(x) = data;
40567   vector_getter(x) = float_vector_getter;
40568   vector_setter(x) = float_vector_setter;
40569   vector_length(x) = len;
40570   if (!dim_info)
40571     {
40572       s7_int di[1];
40573       di[0] = len;
40574       vector_set_dimension_info(x, make_vdims(sc, free_data, 1, di));
40575     }
40576   else vector_set_dimension_info(x, make_vdims(sc, free_data, dims, dim_info));
40577   add_multivector(sc, x);
40578   return(x);
40579 }
40580 
40581 
40582 /* -------------------------------- vector-fill! -------------------------------- */
40583 static Vectorized void float_vector_fill(s7_scheme *sc, s7_pointer vec, s7_double x)
40584 {
40585   s7_int len;
40586   len = vector_length(vec);
40587   if (len == 0) return;
40588   if (x == 0.0)
40589     {
40590       if (STEP_8(len))
40591 	memclr64((void *)float_vector_floats(vec), len * sizeof(s7_double));
40592       else memclr((void *)float_vector_floats(vec), len * sizeof(s7_double));
40593     }
40594   else
40595     {
40596       s7_int i, left;
40597       s7_double *orig;
40598       left = len - 8;
40599       i = 0;
40600       orig = float_vector_floats(vec);
40601       while (i <= left)
40602 	LOOP_8(orig[i++] = x);
40603       for (; i < len; i++)
40604 	orig[i] = x;
40605     }
40606 }
40607 
40608 static Vectorized void int_vector_fill(s7_scheme *sc, s7_pointer vec, s7_int k)
40609 {
40610   s7_int len;
40611   len = vector_length(vec);
40612   if (len == 0) return;
40613   if (k == 0)
40614     {
40615       if (STEP_8(len))
40616 	memclr64((void *)int_vector_ints(vec), len * sizeof(s7_int));
40617       else memclr((void *)int_vector_ints(vec), len * sizeof(s7_int));
40618     }
40619   else
40620     {
40621       s7_int i, left;
40622       s7_int* orig;
40623       left = len - 8;
40624       i = 0;
40625       orig = int_vector_ints(vec);
40626       while (i <= left)
40627 	LOOP_8(orig[i++] = k);
40628       for (; i < len; i++)
40629 	orig[i] = k;
40630     }
40631 }
40632 
40633 static void byte_vector_fill(s7_scheme *sc, s7_pointer vec, uint8_t byte)
40634 {
40635   s7_int len;
40636   len = vector_length(vec);
40637   if (len == 0) return;
40638   if (byte == 0)
40639     memclr((void *)(byte_vector_bytes(vec)), len);
40640   else local_memset((void *)(byte_vector_bytes(vec)), byte, len);
40641 }
40642 
40643 static Vectorized void normal_vector_fill(s7_scheme *sc, s7_pointer vec, s7_pointer obj)
40644 {
40645   s7_pointer *orig;
40646   s7_int len, i, left;
40647 
40648   len = vector_length(vec);
40649   if (len == 0) return;
40650 
40651   /* splitting out this part made no difference in speed; type check of obj is handled elsewhere */
40652   orig = vector_elements(vec);
40653   left = len - 8;
40654   i = 0;
40655   while (i <= left)
40656     LOOP_8(orig[i++] = obj);
40657   for (; i < len; i++)
40658     orig[i] = obj;
40659 }
40660 
40661 void s7_vector_fill(s7_scheme *sc, s7_pointer vec, s7_pointer obj)
40662 {
40663   switch (type(vec))
40664     {
40665     case T_FLOAT_VECTOR:
40666       if (!s7_is_real(obj))
40667 	s7_wrong_type_arg_error(sc, "float-vector fill!", 2, obj, "a real");
40668       else float_vector_fill(sc, vec, s7_real(obj));
40669       break;
40670 
40671     case T_INT_VECTOR:
40672       if (!s7_is_integer(obj)) /* possibly a bignum */
40673 	s7_wrong_type_arg_error(sc, "int-vector fill!", 2, obj, "an integer");
40674       else int_vector_fill(sc, vec, s7_integer_checked(sc, obj));
40675       break;
40676 
40677     case T_BYTE_VECTOR:
40678       if (!is_byte(obj))
40679 	s7_wrong_type_arg_error(sc, "byte-vector fill!", 2, obj, "a byte");
40680       else byte_vector_fill(sc, vec, (uint8_t)s7_integer_checked(sc, obj));
40681       break;
40682 
40683     case T_VECTOR:
40684     default:
40685       normal_vector_fill(sc, vec, obj);
40686     }
40687 }
40688 
40689 static s7_pointer g_vector_fill_1(s7_scheme *sc, s7_pointer caller, s7_pointer args)
40690 {
40691   s7_pointer x, fill;
40692   s7_int start = 0, end;
40693 
40694   x = car(args);
40695   if (!is_any_vector(x))
40696     {
40697       check_method(sc, x, sc->vector_fill_symbol, args);
40698       /* not two_methods (and fill!) here else we get stuff like:
40699        *   (let ((e (openlet (inlet 'fill! (lambda (obj val) (string-fill! (obj 'value) val)) 'value "01234")))) (vector-fill! e #\a) (e 'value)) -> "aaaaa"
40700        */
40701       return(wrong_type_argument(sc, caller, 1, x, T_VECTOR));
40702     }
40703   if (is_immutable_vector(x))
40704     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, caller, x)));
40705 
40706   fill = cadr(args);
40707 
40708   if ((is_typed_vector(x)) &&
40709       (typed_vector_typer_call(sc, x, set_plist_1(sc, fill)) == sc->F))
40710     s7_wrong_type_arg_error(sc, "vector fill!", 2, fill, make_type_name(sc, typed_vector_typer_name(sc, x), INDEFINITE_ARTICLE));
40711 
40712   if (is_float_vector(x))
40713     {
40714       if (!s7_is_real(fill)) /* possibly a bignum */
40715 	return(method_or_bust(sc, fill, caller, args, T_REAL, 2));
40716     }
40717   else
40718     if ((is_int_vector(x)) || (is_byte_vector(x)))
40719       {
40720 	if (!s7_is_integer(fill))
40721 	  return(method_or_bust(sc, fill, caller, args, T_INTEGER, 2));
40722 	if ((is_byte_vector(x)) &&
40723 	    ((s7_integer_checked(sc, fill) < 0) || (s7_integer_checked(sc, fill) > 255)))
40724 	  return(out_of_range(sc, caller, int_two, fill, an_unsigned_byte_string));
40725       }
40726 
40727   end = vector_length(x);
40728   if (!is_null(cddr(args)))
40729     {
40730       s7_pointer p;
40731       p = start_and_end(sc, caller, args, 3, cddr(args), &start, &end);
40732       if (p != sc->unused) return(p);
40733       if (start == end) return(fill);
40734     }
40735   if (end == 0) return(fill);
40736 
40737   if ((start == 0) && (end == vector_length(x)))
40738     s7_vector_fill(sc, x, fill);
40739   else
40740     {
40741       s7_int i;
40742       if (is_normal_vector(x))
40743 	for (i = start; i < end; i++)
40744 	  vector_element(x, i) = fill;
40745       else
40746 	{
40747 	  if (is_int_vector(x))
40748 	    {
40749 	      s7_int k;
40750 	      k = s7_integer_checked(sc, fill);
40751 	      if (k == 0)
40752 		memclr((void *)(int_vector_ints(x) + start), (end - start) * sizeof(s7_int));
40753 	      else
40754 		for (i = start; i < end; i++)
40755 		  int_vector(x, i) = k;
40756 	    }
40757 	  else
40758 	    {
40759 	      if (is_float_vector(x))
40760 		{
40761 		  s7_double y;
40762 		  y = s7_real(fill);
40763 		  if (y == 0.0)
40764 		    memclr((void *)(float_vector_floats(x) + start), (end - start) * sizeof(s7_double));
40765 		  else
40766 		    {
40767 		      s7_double *orig;
40768 		      s7_int left;
40769 		      orig = float_vector_floats(x);
40770 		      left = end - 8;
40771 		      i = start;
40772 		      while (i <= left)
40773 			LOOP_8(orig[i++] = y);
40774 		      for (; i < end; i++)
40775 			orig[i] = y;
40776 		    }}
40777 	      else
40778 		if (is_byte_vector(x))
40779 		  {
40780 		    uint8_t k;
40781 		    k = (uint8_t)s7_integer_checked(sc, fill);
40782 		    if (k == 0)
40783 		      memclr((void *)(byte_vector_bytes(x) + start), end - start);
40784 		    else local_memset((void *)(byte_vector_bytes(x) + start), k, end - start);
40785 		  }}}}
40786   return(fill);
40787 }
40788 
40789 #if (!WITH_PURE_S7)
40790 /* -------------------------------- vector-fill! -------------------------------- */
40791 static s7_pointer g_vector_fill(s7_scheme *sc, s7_pointer args)
40792 {
40793   #define H_vector_fill "(vector-fill! v val start end) sets all elements of the vector v between start and end to val"
40794   #define Q_vector_fill s7_make_circular_signature(sc, 3, 4, sc->T, sc->is_vector_symbol, sc->T, sc->is_integer_symbol)
40795   return(g_vector_fill_1(sc, sc->vector_fill_symbol, args));
40796 }
40797 #endif
40798 
40799 
40800 /* -------------------------------- vector-ref|set! -------------------------------- */
40801 s7_pointer s7_vector_ref(s7_scheme *sc, s7_pointer vec, s7_int index)
40802 {
40803   if (index >= vector_length(vec))
40804     return(out_of_range(sc, sc->vector_ref_symbol, int_two, wrap_integer1(sc, index), its_too_large_string));
40805 
40806   return(vector_getter(vec)(sc, vec, index));
40807 }
40808 
40809 s7_pointer s7_vector_set(s7_scheme *sc, s7_pointer vec, s7_int index, s7_pointer a)
40810 {
40811   if (index >= vector_length(vec))
40812     return(out_of_range(sc, sc->vector_set_symbol, int_two, wrap_integer1(sc, index), its_too_large_string));
40813 
40814   if (is_typed_vector(vec))
40815     return(typed_vector_setter(sc, vec, index, a));
40816   vector_setter(vec)(sc, vec, index, T_Pos(a));
40817   return(a);
40818 }
40819 
40820 
40821 s7_pointer *s7_vector_elements(s7_pointer vec) {return(vector_elements(vec));}
40822 
40823 /* these are for s7.h */
40824 s7_int *s7_int_vector_elements(s7_pointer vec) {return(int_vector_ints(vec));}
40825 s7_int s7_int_vector_ref(s7_pointer vec, s7_int index) {return(int_vector_ints(vec)[index]);}
40826 s7_int s7_int_vector_set(s7_pointer vec, s7_int index, s7_int value) {int_vector_ints(vec)[index] = value; return(value);}
40827 
40828 s7_double *s7_float_vector_elements(s7_pointer vec) {return(float_vector_floats(vec));}
40829 s7_double s7_float_vector_ref(s7_pointer vec, s7_int index) {return(float_vector_floats(vec)[index]);}
40830 s7_double s7_float_vector_set(s7_pointer vec, s7_int index, s7_double value) {float_vector_floats(vec)[index] = value; return(value);}
40831 
40832 s7_int s7_vector_dimensions(s7_pointer vec, s7_int *dims, s7_int dims_size)
40833 {
40834   if (dims_size <= 0) return(0);
40835   if (vector_dimension_info(vec))
40836     {
40837       s7_int i, lim;
40838       lim = vector_ndims(vec);
40839       if (lim > dims_size) lim = dims_size;
40840       for (i = 0; i < lim; i++)
40841 	dims[i] = vector_dimension(vec, i);
40842       return(lim);
40843     }
40844   dims[0] = vector_length(vec);
40845   return(1);
40846 }
40847 
40848 s7_int s7_vector_dimension(s7_pointer vec, s7_int dim)
40849 {
40850   if (vector_dimension_info(vec))
40851     return(vector_dimension(vec, dim));
40852   return((dim == 0) ? vector_length(vec) : -1);
40853 }
40854 
40855 s7_int s7_vector_offsets(s7_pointer vec, s7_int *offs, s7_int offs_size)
40856 {
40857   if (offs_size <= 0) return(0);
40858   if (vector_dimension_info(vec))
40859     {
40860       s7_int i, lim;
40861       lim = vector_ndims(vec);
40862       if (lim > offs_size) lim = offs_size;
40863       for (i = 0; i < lim; i++)
40864 	offs[i] = vector_offset(vec, i);
40865       return(lim);
40866     }
40867   offs[0] = 1;
40868   return(1);
40869 }
40870 
40871 
40872 #if (!WITH_PURE_S7)
40873 /* -------------------------------- vector-append -------------------------------- */
40874 static s7_pointer vector_append(s7_scheme *sc, s7_pointer args, uint8_t typ, s7_pointer caller);
40875 static s7_pointer copy_source_no_dest(s7_scheme *sc, s7_pointer caller, s7_pointer source, s7_pointer args);
40876 
40877 static s7_pointer g_vector_append(s7_scheme *sc, s7_pointer args)
40878 {
40879   /* returns a one-dimensional vector.  To handle multidimensional vectors, we'd need to
40880    *   ensure all the dimensional data matches (rank, size of each dimension except the last etc),
40881    *   which is too much trouble.
40882    */
40883   #define H_vector_append "(vector-append . vectors) returns a new (1-dimensional) vector containing the elements of its vector arguments."
40884   #define Q_vector_append sc->pcl_v
40885 
40886   s7_pointer p;
40887   int32_t i;
40888 
40889   if (is_null(args))
40890     return(make_simple_vector(sc, 0));
40891 
40892   if ((is_null(cdr(args))) &&
40893       (is_any_vector(car(args))))
40894     return(copy_source_no_dest(sc, sc->vector_append_symbol, car(args), args));
40895 
40896   for (i = 0, p = args; is_pair(p); p = cdr(p), i++)
40897     {
40898       s7_pointer x;
40899       x = car(p);
40900       if (!is_any_vector(x))
40901 	{
40902 	  if (has_active_methods(sc, x))
40903 	    {
40904 	      s7_pointer func;
40905 	      func = find_method_with_let(sc, x, sc->vector_append_symbol);
40906 	      if (func != sc->undefined)
40907 		{
40908 		  int32_t k;
40909 		  s7_pointer v, y;
40910 		  if (i == 0)
40911 		    return(call_method(sc, x, func, args));
40912 		  /* we have to copy the arglist here */
40913 		  sc->temp9 = make_list(sc, i, sc->F);
40914 		  for (k = 0, y = args, v = sc->temp9; k < i; k++, y = cdr(y), v = cdr(v))
40915 		    set_car(v, car(y));
40916 		  v = g_vector_append(sc, sc->temp9);
40917 		  y = call_method(sc, x, func, set_ulist_1(sc, v, p));
40918 		  sc->temp9 = sc->nil;
40919 		  return(y);
40920 		}}
40921 	  return(wrong_type_argument(sc, sc->vector_append_symbol, i + 1, x, T_VECTOR));
40922 	}}
40923   return(vector_append(sc, args, type(car(args)), sc->vector_append_symbol));
40924 }
40925 
40926 static s7_pointer vector_append_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
40927 {
40928   s7_pointer val;
40929   sc->temp7 = list_2(sc, p1, p2);
40930   val = g_vector_append(sc, sc->temp7);
40931   sc->temp7 = sc->nil;
40932   return(val);
40933 }
40934 
40935 static s7_pointer vector_append_p_ppp(s7_scheme *sc, s7_pointer p1, s7_pointer p2, s7_pointer p3)
40936 {
40937   s7_pointer val;
40938   sc->temp7 = list_3(sc, p1, p2, p3);
40939   val = g_vector_append(sc, sc->temp7);
40940   sc->temp7 = sc->nil;
40941   return(val);
40942 }
40943 #endif
40944 
40945 static s7_int flatten_multivector_indices(s7_scheme *sc, s7_pointer vector, s7_int indices, va_list ap)
40946 {
40947   s7_int rank, index;
40948 
40949   rank = vector_rank(vector);
40950   if (rank != indices)
40951     {
40952       va_end(ap);
40953       s7_wrong_number_of_args_error(sc, "s7_vector_ref_n: wrong number of indices: ~A", make_integer(sc, indices));
40954     }
40955   if (rank == 1)
40956     index = va_arg(ap, s7_int);
40957   else
40958     {
40959       s7_int i;
40960       s7_int *offsets, *dimensions;
40961       dimensions = vector_dimensions(vector);
40962       offsets = vector_offsets(vector);
40963       for (i = 0, index = 0; i < indices; i++)
40964 	{
40965 	  s7_int ind;
40966 	  ind = va_arg(ap, s7_int);
40967 	  if ((ind < 0) ||
40968 	      (ind >= dimensions[i]))
40969 	    {
40970 	      va_end(ap);
40971 	      out_of_range(sc, sc->vector_ref_symbol, make_integer(sc, i), wrap_integer1(sc, ind), (ind < 0) ? its_negative_string : its_too_large_string);
40972 	      return(-1);
40973 	    }
40974 	  index += (ind * offsets[i]);
40975 	}}
40976   va_end(ap);
40977   return(index);
40978 }
40979 
40980 s7_pointer s7_vector_ref_n(s7_scheme *sc, s7_pointer vector, s7_int indices, ...)
40981 {
40982   s7_int index;
40983   va_list ap;
40984   va_start(ap, indices);
40985   index = flatten_multivector_indices(sc, vector, indices, ap);
40986   return(vector_getter(vector)(sc, vector, index));
40987 }
40988 
40989 s7_pointer s7_vector_set_n(s7_scheme *sc, s7_pointer vector, s7_pointer value, s7_int indices, ...)
40990 {
40991   s7_int index;
40992   va_list ap;
40993   va_start(ap, indices);
40994   index = flatten_multivector_indices(sc, vector, indices, ap);
40995   if (is_typed_vector(vector))
40996     return(typed_vector_setter(sc, vector, index, value));
40997   return(vector_setter(vector)(sc, vector, index, value));
40998 }
40999 
41000 
41001 /* -------------------------------- vector->list -------------------------------- */
41002 s7_pointer s7_vector_to_list(s7_scheme *sc, s7_pointer vect)
41003 {
41004   s7_int i, len;
41005   s7_pointer result;
41006   len = vector_length(vect);
41007   if (len == 0)
41008     return(sc->nil);
41009   check_free_heap_size(sc, len);
41010   sc->v = sc->nil;
41011   s7_gc_protect_via_stack(sc, vect);
41012   for (i = len - 1; i >= 0; i--)
41013     sc->v = cons_unchecked(sc, vector_getter(vect)(sc, vect, i), sc->v); /* vector_getter can cause alloction/GC (int_vector_getter -> make_integer) */
41014   unstack(sc);
41015   result = sc->v;
41016   sc->v = sc->nil;
41017   return(result);
41018 }
41019 
41020 #if (!WITH_PURE_S7)
41021 static s7_pointer g_vector_to_list(s7_scheme *sc, s7_pointer args)
41022 {
41023   s7_int i, start = 0, end;
41024   s7_pointer p, vec;
41025   #define H_vector_to_list "(vector->list v (start 0) end) returns the elements of the vector v as a list; (map values v)"
41026   #define Q_vector_to_list s7_make_signature(sc, 4, sc->is_proper_list_symbol, sc->is_vector_symbol, sc->is_integer_symbol, sc->is_integer_symbol)
41027 
41028   vec = car(args);
41029   if (!is_any_vector(vec))
41030     return(method_or_bust_one_arg(sc, vec, sc->vector_to_list_symbol, args, T_VECTOR));
41031 
41032   end = vector_length(vec);
41033   if (!is_null(cdr(args)))
41034     {
41035       p = start_and_end(sc, sc->vector_to_list_symbol, args, 2, cdr(args), &start, &end);
41036       if (p != sc->unused) return(p);
41037       if (start == end) return(sc->nil);
41038     }
41039   if ((end - start) > sc->max_list_length)
41040     return(out_of_range(sc, sc->vector_to_list_symbol, int_one, car(args), its_too_large_string));
41041 
41042   check_free_heap_size(sc, end - start);
41043   sc->w = sc->nil;
41044   s7_gc_protect_via_stack(sc, vec);
41045   for (i = end - 1; i >= start; i--)
41046     sc->w = cons_unchecked(sc, vector_getter(vec)(sc, vec, i), sc->w);
41047   unstack(sc);
41048   p = sc->w;
41049   sc->w = sc->nil;
41050   return(p);
41051 }
41052 
41053 static s7_pointer vector_to_list_p_p(s7_scheme *sc, s7_pointer p)
41054 {
41055   if (!is_any_vector(p))
41056     return(method_or_bust_one_arg_p(sc, p, sc->vector_to_list_symbol, T_VECTOR));
41057   return(s7_vector_to_list(sc, p));
41058 }
41059 #endif
41060 
41061 
41062 /* -------------------------------- string->byte-vector -------------------------------- */
41063 static s7_pointer g_string_to_byte_vector(s7_scheme *sc, s7_pointer args)
41064 {
41065   #define H_string_to_byte_vector "(string->byte-vector obj) turns a string into a byte-vector."
41066   #define Q_string_to_byte_vector s7_make_signature(sc, 2, sc->is_byte_vector_symbol, sc->is_string_symbol)
41067   s7_pointer str;
41068   str = car(args);
41069   if (!is_string(str))
41070     return(method_or_bust_p(sc, str, sc->string_to_byte_vector_symbol, T_STRING));
41071   return(s7_copy_1(sc, sc->string_to_byte_vector_symbol, set_plist_2(sc, str, make_simple_byte_vector(sc, string_length(str)))));
41072 }
41073 
41074 
41075 /* -------------------------------- byte-vector->string -------------------------------- */
41076 static s7_pointer g_byte_vector_to_string(s7_scheme *sc, s7_pointer args)
41077 {
41078   #define H_byte_vector_to_string "(byte-vector->string obj) turns a byte-vector into a string."
41079   #define Q_byte_vector_to_string s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_byte_vector_symbol)
41080   s7_pointer v;
41081   v = car(args);
41082   if (!is_byte_vector(v))
41083     return(method_or_bust_p(sc, v, sc->byte_vector_to_string_symbol, T_BYTE_VECTOR));
41084   return(s7_copy_1(sc, sc->byte_vector_to_string_symbol, set_plist_2(sc, v, make_empty_string(sc, byte_vector_length(v), 0))));
41085 }
41086 
41087 
41088 /* -------------------------------- vector -------------------------------- */
41089 static s7_pointer g_vector(s7_scheme *sc, s7_pointer args)
41090 {
41091   #define H_vector "(vector ...) returns a vector whose elements are the arguments"
41092   #define Q_vector s7_make_circular_signature(sc, 1, 2, sc->is_vector_symbol, sc->T)
41093 
41094   s7_int len;
41095   s7_pointer vec;
41096 
41097   len = proper_list_length(args);
41098   vec = make_simple_vector(sc, len);
41099   if (len > 0)
41100     {
41101       s7_int i;
41102       s7_pointer x;
41103       for (x = args, i = 0; is_pair(x); x = cdr(x), i++)
41104 	vector_element(vec, i) = car(x);
41105     }
41106   return(vec);
41107 }
41108 
41109 static s7_pointer vector_p_pp(s7_scheme *sc, s7_pointer p1, s7_pointer p2)
41110 {
41111   s7_pointer vec;
41112   vec = make_simple_vector(sc, 2);
41113   vector_element(vec, 0) = p1;
41114   vector_element(vec, 1) = p2;
41115   return(vec);
41116 }
41117 
41118 /* expansion into g_vector_2 et al makes almost no difference */
41119 
41120 /* -------------------------------- float-vector? -------------------------------- */
41121 static s7_pointer g_is_float_vector(s7_scheme *sc, s7_pointer args)
41122 {
41123   #define H_is_float_vector "(float-vector? obj) returns #t if obj is an homogeneous float vector"
41124   #define Q_is_float_vector sc->pl_bt
41125   check_boolean_method(sc, s7_is_float_vector, sc->is_float_vector_symbol, args);
41126 }
41127 
41128 
41129 /* -------------------------------- float-vector -------------------------------- */
41130 static s7_pointer g_float_vector(s7_scheme *sc, s7_pointer args)
41131 {
41132   #define H_float_vector "(float-vector ...) returns an homogeneous float vector whose elements are the arguments"
41133   #define Q_float_vector s7_make_circular_signature(sc, 1, 2, sc->is_float_vector_symbol, sc->is_real_symbol)
41134 
41135   s7_int len;
41136   s7_pointer vec;
41137 
41138   len = proper_list_length(args);
41139   vec = make_simple_float_vector(sc, len);
41140   if (len > 0)
41141     {
41142       s7_int i;
41143       s7_pointer x;
41144       sc->w = vec;
41145       for (x = args, i = 0; is_pair(x); x = cdr(x), i++)
41146 	{
41147 	  s7_pointer p;
41148 	  p = car(x);
41149 	  if (is_t_real(p))
41150 	    float_vector(vec, i) = real(p);
41151 	  else
41152 	    {
41153 	      if (s7_is_real(p))                         /* bignum is ok here */
41154 		float_vector(vec, i) = s7_real(p);
41155 	      else
41156 		{
41157 		  sc->w = sc->nil;
41158 		  return(method_or_bust(sc, p, sc->float_vector_symbol, args, T_REAL, i + 1));
41159 		}}}
41160       sc->w = sc->nil;
41161     }
41162   return(vec);
41163 }
41164 
41165 static s7_pointer float_vector_p_d(s7_scheme *sc, s7_double x)
41166 {
41167   s7_pointer vec;
41168   vec = make_simple_float_vector(sc, 1);
41169   float_vector(vec, 0) = x;
41170   return(vec);
41171 }
41172 
41173 
41174 /* -------------------------------- int-vector? -------------------------------- */
41175 static s7_pointer g_is_int_vector(s7_scheme *sc, s7_pointer args)
41176 {
41177   #define H_is_int_vector "(int-vector? obj) returns #t if obj is an homogeneous s7_int vector"
41178   #define Q_is_int_vector sc->pl_bt
41179   check_boolean_method(sc, is_int_vector, sc->is_int_vector_symbol, args);
41180 }
41181 
41182 
41183 /* -------------------------------- int-vector -------------------------------- */
41184 static s7_pointer g_int_vector(s7_scheme *sc, s7_pointer args)
41185 {
41186   #define H_int_vector "(int-vector ...) returns an homogeneous s7_int vector whose elements are the arguments"
41187   #define Q_int_vector s7_make_circular_signature(sc, 1, 2, sc->is_int_vector_symbol, sc->is_integer_symbol)
41188 
41189   s7_int len;
41190   s7_pointer vec;
41191 
41192   len = proper_list_length(args);
41193   vec = make_simple_int_vector(sc, len);
41194   if (len > 0)
41195     {
41196       s7_int i;
41197       s7_pointer x;
41198       for (x = args, i = 0; is_pair(x); x = cdr(x), i++)
41199 	{
41200 	  s7_pointer p;
41201 	  p = car(x);
41202 	  if (s7_is_integer(p))
41203 	    int_vector(vec, i) = s7_integer_checked(sc, p);
41204 	  else return(method_or_bust(sc, p, sc->int_vector_symbol, args, T_INTEGER, i + 1));
41205 	}}
41206   return(vec);
41207 }
41208 
41209 static s7_pointer int_vector_p_i(s7_scheme *sc, s7_int x)
41210 {
41211   s7_pointer vec;
41212   vec = make_simple_int_vector(sc, 1);
41213   int_vector(vec, 0) = x;
41214   return(vec);
41215 }
41216 
41217 
41218 /* -------------------------------- byte-vector? -------------------------------- */
41219 static s7_pointer g_is_byte_vector(s7_scheme *sc, s7_pointer args)
41220 {
41221   #define H_is_byte_vector "(byte-vector? obj) returns #t if obj is a byte-vector"
41222   #define Q_is_byte_vector sc->pl_bt
41223 
41224   check_boolean_method(sc, s7_is_byte_vector, sc->is_byte_vector_symbol, args);
41225 }
41226 
41227 
41228 /* -------------------------------- byte-vector -------------------------------- */
41229 static s7_pointer g_byte_vector(s7_scheme *sc, s7_pointer args)
41230 {
41231   #define H_byte_vector "(byte-vector ...) returns a byte-vector whose elements are the arguments"
41232   #define Q_byte_vector s7_make_circular_signature(sc, 1, 2, sc->is_byte_vector_symbol, sc->is_byte_symbol)
41233 
41234   s7_int i, len;
41235   s7_pointer vec, x;
41236   uint8_t *str;
41237 
41238   len = s7_list_length(sc, args);
41239   vec = make_simple_byte_vector(sc, len);
41240   str = byte_vector_bytes(vec);
41241 
41242   for (i = 0, x = args; is_pair(x); i++, x = cdr(x))
41243     {
41244       s7_pointer byte;
41245       s7_int b;
41246       byte = car(x);
41247       if (is_t_integer(byte))
41248 	b = integer(byte);
41249       else
41250 	{
41251 #if WITH_GMP
41252 	  if (is_t_big_integer(byte))
41253 	    b = big_integer_to_s7_int(sc, big_integer(byte));
41254 	  else
41255 #endif
41256 	    return(method_or_bust(sc, byte, sc->byte_vector_symbol, args, T_INTEGER, i + 1));
41257 	}
41258       if ((b < 0) || (b > 255))
41259 	return(simple_wrong_type_argument_with_type(sc, sc->byte_vector_symbol, byte, an_unsigned_byte_string));
41260       str[i] = (uint8_t)b;
41261     }
41262   return(vec);
41263 }
41264 
41265 
41266 #if (!WITH_PURE_S7)
41267 /* -------------------------------- list->vector -------------------------------- */
41268 static s7_pointer g_list_to_vector(s7_scheme *sc, s7_pointer args)
41269 {
41270   s7_pointer p;
41271   #define H_list_to_vector "(list->vector lst) returns a vector containing the elements of lst; (apply vector lst)"
41272   #define Q_list_to_vector s7_make_signature(sc, 2, sc->is_vector_symbol, sc->is_proper_list_symbol)
41273 
41274   p = car(args);
41275   sc->temp3 = p;
41276   if (is_null(p))
41277     return(s7_make_vector(sc, 0));
41278 
41279   if (!s7_is_proper_list(sc, p))
41280     return(method_or_bust_with_type_one_arg_p(sc, p, sc->list_to_vector_symbol, a_proper_list_string));
41281 
41282   p = g_vector(sc, p);
41283   sc->temp3 = sc->nil;
41284   return(p);
41285 }
41286 
41287 /* -------------------------------- vector-length -------------------------------- */
41288 static s7_pointer g_vector_length(s7_scheme *sc, s7_pointer args)
41289 {
41290   s7_pointer vec;
41291   #define H_vector_length "(vector-length v) returns the length of vector v"
41292   #define Q_vector_length s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_vector_symbol)
41293 
41294   vec = car(args);
41295   if (!is_any_vector(vec))
41296     return(method_or_bust_one_arg(sc, vec, sc->vector_length_symbol, args, T_VECTOR));
41297 
41298   return(make_integer(sc, vector_length(vec)));
41299 }
41300 
41301 static s7_int vector_length_i_7p(s7_scheme *sc, s7_pointer p)
41302 {
41303   if (!is_any_vector(p))
41304     return(integer(method_or_bust_one_arg_p(sc, p, sc->vector_length_symbol, T_VECTOR)));
41305   return(vector_length(p));
41306 }
41307 
41308 static s7_pointer vector_length_p_p(s7_scheme *sc, s7_pointer vec)
41309 {
41310   if (!is_any_vector(vec))
41311     return(method_or_bust_one_arg_p(sc, vec, sc->vector_length_symbol, T_VECTOR));
41312   return(make_integer(sc, vector_length(vec)));
41313 }
41314 #endif
41315 
41316 
41317 /* -------------------------------- subvector subvector? subvector-vector subvector-position -------------------------------- */
41318 
41319 static bool s7_is_subvector(s7_pointer g) {return((is_any_vector(g)) && (is_subvector(g)));}
41320 
41321 static s7_pointer g_is_subvector(s7_scheme *sc, s7_pointer args)
41322 {
41323   #define H_is_subvector "(subvector? obj) returns #t if obj is a subvector"
41324   #define Q_is_subvector sc->pl_bt
41325 
41326   check_boolean_method(sc, s7_is_subvector, sc->is_subvector_symbol, args);
41327 }
41328 
41329 static s7_pointer g_subvector_position(s7_scheme *sc, s7_pointer args)
41330 {
41331   #define H_subvector_position "(subvector-position obj) returns obj's offset"
41332   #define Q_subvector_position s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_subvector_symbol)
41333 
41334   s7_pointer sv;
41335   sv = car(args);
41336   if (s7_is_subvector(sv))
41337     {
41338       /* we can't use vector_elements(sv) - vector_elements(subvector_vector(sv)) because that assumes we're looking at s7_pointer*,
41339        *   so a subvector of a byte_vector gets a bogus position (0 if position is less than 8 etc).
41340        *   Since we currently let the user reset s7_int and s7_double, all four cases have to be handled explicitly.
41341        *   See also vector_to_let -- same problem, segfault in gcc 10.2 if careless.
41342        */
41343       switch (type(sv))
41344 	{
41345 	case T_VECTOR:       return(make_integer(sc, (s7_int)(vector_elements(sv) - vector_elements(subvector_vector(sv)))));
41346 	case T_INT_VECTOR:   return(make_integer(sc, (s7_int)(int_vector_ints(sv) - int_vector_ints(subvector_vector(sv)))));
41347 	case T_FLOAT_VECTOR: return(make_integer(sc, (s7_int)(float_vector_floats(sv) - float_vector_floats(subvector_vector(sv)))));
41348 	case T_BYTE_VECTOR:  return(make_integer(sc, (s7_int)(byte_vector_bytes(sv) - byte_vector_bytes(subvector_vector(sv)))));
41349 	}}
41350   return(method_or_bust_one_arg(sc, sv, sc->subvector_position_symbol, args, T_VECTOR));
41351 }
41352 
41353 static s7_pointer g_subvector_vector(s7_scheme *sc, s7_pointer args)
41354 {
41355   #define H_subvector_vector "(subvector-vector obj) returns the vector underlying the subvector obj"
41356   #define Q_subvector_vector s7_make_signature(sc, 2, sc->is_vector_symbol, sc->is_subvector_symbol)
41357 
41358   if (s7_is_subvector(car(args)))
41359     return(subvector_vector(car(args)));
41360   return(method_or_bust_one_arg(sc, car(args), sc->subvector_vector_symbol, args, T_VECTOR));
41361 }
41362 
41363 static s7_pointer subvector(s7_scheme *sc, s7_pointer vect, s7_int skip_dims, s7_int index)
41364 {
41365   s7_pointer x;
41366   s7_int dims;
41367 
41368   new_cell(sc, x, (full_type(vect) & (~T_COLLECTED)) | T_SUBVECTOR | T_SAFE_PROCEDURE);
41369   vector_length(x) = 0;
41370   vector_block(x) = mallocate_vector(sc, 0);
41371   vector_elements(x) = NULL;
41372   vector_getter(x) = vector_getter(vect);
41373   vector_setter(x) = vector_setter(vect);
41374 
41375   dims = vector_ndims(vect) - skip_dims;
41376   if (dims > 1)
41377     {
41378       vdims_t *v;
41379       v = (vdims_t *)mallocate_block(sc);
41380       vdims_rank(v) = dims;
41381       vdims_dims(v) = (s7_int *)(vector_dimensions(vect) + skip_dims);
41382       vdims_offsets(v) = (s7_int *)(vector_offsets(vect) + skip_dims);
41383       vdims_original(v) = vect;
41384       vector_elements_should_be_freed(v) = false;
41385       vector_set_dimension_info(x, v);
41386     }
41387   else
41388     {
41389       vector_set_dimension_info(x, NULL);
41390       subvector_set_vector(x, vect);
41391     }
41392 
41393   if (is_normal_vector(vect))
41394     mark_function[T_VECTOR] = mark_vector_possibly_shared;
41395   else mark_function[type(vect)] = mark_int_or_float_vector_possibly_shared;
41396 
41397   if (skip_dims > 0)
41398     vector_length(x) = vector_offset(vect, skip_dims - 1);
41399   else vector_length(x) = vector_length(vect);
41400 
41401   if (is_int_vector(vect))
41402     int_vector_ints(x) = (s7_int *)(int_vector_ints(vect) + index);
41403   else
41404     {
41405       if (is_float_vector(vect))
41406 	float_vector_floats(x) = (s7_double *)(float_vector_floats(vect) + index);
41407       else
41408 	{
41409 	  if (is_normal_vector(vect))
41410 	    vector_elements(x) = (s7_pointer *)(vector_elements(vect) + index);
41411 	  else byte_vector_bytes(x) = (uint8_t *)(byte_vector_bytes(vect) + index);
41412 	}}
41413   add_multivector(sc, x);
41414   return(x);
41415 }
41416 
41417 static inline vdims_t *list_to_dims(s7_scheme *sc, s7_pointer x)
41418 {
41419   s7_int i, offset, len;
41420   s7_pointer y;
41421   vdims_t *v;
41422   s7_int *ds, *os;
41423 
41424   len = proper_list_length(x);
41425   v = (vdims_t *)mallocate(sc, len * 2 * sizeof(s7_int));
41426   vdims_rank(v) = len;
41427   vdims_offsets(v) = (s7_int *)(vdims_dims(v) + len);
41428   vector_elements_should_be_freed(v) = false;
41429   ds = vdims_dims(v);
41430   os = vdims_offsets(v);
41431 
41432   for (i = 0, y = x; is_not_null(y); i++, y = cdr(y))
41433     ds[i] = s7_integer_checked(sc, car(y));
41434 
41435   for (i = len - 1, offset = 1; i >= 0; i--)
41436     {
41437       os[i] = offset;
41438       offset *= ds[i];
41439     }
41440   return(v);
41441 }
41442 
41443 static s7_pointer g_subvector(s7_scheme *sc, s7_pointer args)
41444 {
41445   #define H_subvector "(subvector original-vector (start 0) (end original-vector-len) new-dimensions) returns \
41446 a vector that points to the same elements as the original-vector but with different starting point, end point, and dimensional info."
41447   #define Q_subvector s7_make_signature(sc, 5, sc->is_subvector_symbol, sc->is_vector_symbol, sc->is_integer_symbol, sc->is_integer_symbol, sc->is_pair_symbol)
41448 
41449   /* (let ((v1 #2d((1 2 3) (4 5 6)))) (let ((v2 (subvector v1 0 6))) v2)) -> #(1 2 3 4 5 6)
41450    * (let ((v1 #(1 2 3 4 5 6))) (let ((v2 (subvector v1 0 6 '(3 2)))) v2)) -> #2D((1 2) (3 4) (5 6))
41451    */
41452   /* for a long time subvector was (subvector vector new-length-or-dimensions (new-start 0))
41453    *   but that turned out to be confusing (start after end in effect, the reverse of substring and others)
41454    *   Here is a translation:
41455    *
41456     (define (old-subvector vect len (offset 0))
41457       (if (pair? len)
41458           (subvector vect offset (+ offset (apply * len)) len)
41459           (if (not len)
41460               (subvector vect offset (vector-length vect))
41461               (subvector vect offset (+ offset len)))))
41462    *
41463    */
41464   s7_pointer orig, x;
41465   vdims_t *v = NULL;
41466   s7_int new_len, orig_len, offset = 0;
41467 
41468   /* get the vector */
41469   orig = car(args);
41470   if (!is_any_vector(orig))
41471     return(method_or_bust(sc, orig, sc->subvector_symbol, args, T_VECTOR, 1));
41472 
41473   orig_len = vector_length(orig);
41474   new_len = orig_len;
41475 
41476   if (is_pair(cdr(args)))
41477     {
41478       /* get start point in vector */
41479       s7_pointer start;
41480       start = cadr(args);
41481       if (!s7_is_integer(start))
41482 	return(method_or_bust(sc, start, sc->subvector_symbol, args, T_INTEGER, 2));
41483       offset = s7_integer_checked(sc, start);
41484       if ((offset < 0) ||
41485 	  (offset > orig_len))  /* we need this if, for example, offset == 9223372036854775807 */
41486 	return(out_of_range(sc, sc->subvector_symbol, int_two, start, (offset < 0) ? its_negative_string : its_too_large_string));
41487       new_len -= offset;
41488 
41489       if (is_pair(cddr(args)))
41490 	{
41491 	  /* get end point in vector */
41492 	  s7_pointer end;
41493 	  s7_int new_end;
41494 	  end = caddr(args);
41495 	  if (!s7_is_integer(end))
41496 	    return(method_or_bust(sc, end, sc->subvector_symbol, args, T_INTEGER, 3));
41497 	  new_end = s7_integer_checked(sc, end);
41498 	  if ((new_end < 0) ||
41499 	      (new_end > orig_len))
41500 	    return(out_of_range(sc, sc->subvector_symbol, int_three, end, (new_end < 0) ? its_negative_string : its_too_large_string));
41501 	  if (offset > new_end)
41502 	    return(out_of_range(sc, sc->subvector_symbol, int_two, start, wrap_string(sc, "start point > end point", 23)));
41503 	  new_len = new_end - offset;
41504 
41505 	  if (is_pair(cdddr(args)))
41506 	    {
41507 	      s7_pointer y, dims;
41508 	      s7_int i;
41509 	      dims = cadddr(args);
41510 	      if ((is_null(dims)) ||
41511 		  (!s7_is_proper_list(sc, dims)))
41512 		return(method_or_bust(sc, dims, sc->subvector_symbol, args, T_PAIR, 4));
41513 
41514 	      for (y = dims; is_pair(y); y = cdr(y))
41515 		if ((!s7_is_integer(car(y)))        ||       /* (subvector v '((1 2) (3 4))) */
41516 		    (s7_integer_checked(sc, car(y)) > orig_len) ||
41517 		    (s7_integer_checked(sc, car(y)) < 0))
41518 		  return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_1(sc, wrap_string(sc, "a subvector must fit in the original vector", 43))));
41519 
41520 	      v = list_to_dims(sc, dims);
41521 	      new_len = vdims_dims(v)[0];
41522 	      for (i = 1; i < vdims_rank(v); i++)
41523 		new_len *= vdims_dims(v)[i];
41524 	      if (new_len != new_end - offset)
41525 		s7_error(sc, sc->wrong_type_arg_symbol,
41526 			 set_elist_4(sc, wrap_string(sc, "subvector dimensional length, ~S, does not match the start and end positions: ~S to ~S~%", 88),
41527 				     s7_make_integer(sc, new_len), start, end));
41528 	      vdims_original(v) = orig;
41529 	    }}}
41530 
41531   if (is_normal_vector(orig))
41532     mark_function[T_VECTOR] = mark_vector_possibly_shared;
41533   else mark_function[type(orig)] = mark_int_or_float_vector_possibly_shared; /* I think this works for byte-vectors also */
41534 
41535   new_cell(sc, x, (full_type(orig) & (~T_COLLECTED)) | T_SUBVECTOR | T_SAFE_PROCEDURE);
41536 
41537   vector_block(x) = mallocate_vector(sc, 0);
41538   vector_set_dimension_info(x, v);
41539   if (!v) subvector_set_vector(x, orig);
41540   vector_length(x) = new_len;                 /* might be less than original length */
41541   if ((new_len == 0) && (is_normal_vector(orig))) set_has_simple_elements(x);
41542   vector_getter(x) = vector_getter(orig);
41543   vector_setter(x) = vector_setter(orig);
41544 
41545   if (is_int_vector(orig))
41546     int_vector_ints(x) = (s7_int *)(int_vector_ints(orig) + offset);
41547   else
41548     {
41549       if (is_float_vector(orig))
41550 	float_vector_floats(x) = (s7_double *)(float_vector_floats(orig) + offset);
41551       else
41552 	{
41553 	  if (is_normal_vector(x))
41554 	    vector_elements(x) = (s7_pointer *)(vector_elements(orig) + offset);
41555 	  else byte_vector_bytes(x) = (uint8_t *)(byte_vector_bytes(orig) + offset);
41556 	}}
41557 
41558   add_multivector(sc, x);
41559   return(x);
41560 }
41561 
41562 
41563 /* -------------------------------- vector-ref -------------------------------- */
41564 static s7_pointer vector_ref_1(s7_scheme *sc, s7_pointer vect, s7_pointer indices)
41565 {
41566   s7_int index = 0;
41567   if (vector_length(vect) == 0)
41568     return(out_of_range(sc, sc->vector_ref_symbol, int_one, vect, its_too_large_string));
41569 
41570   if (vector_rank(vect) > 1)
41571     {
41572       s7_int i;
41573       s7_pointer x;
41574       for (x = indices, i = 0; (is_not_null(x)) && (i < vector_ndims(vect)); x = cdr(x), i++)
41575 	{
41576 	  s7_int n;
41577 	  s7_pointer p;
41578 	  p = car(x);
41579 	  if (!s7_is_integer(p))
41580 	    return(method_or_bust(sc, p, sc->vector_ref_symbol, set_ulist_1(sc, vect, indices), T_INTEGER, i + 2));
41581           n = s7_integer_checked(sc, p);
41582 	  if ((n < 0) ||
41583 	      (n >= vector_dimension(vect, i)))
41584 	    return(out_of_range(sc, sc->vector_ref_symbol, wrap_integer1(sc, i + 2), p, (n < 0) ? its_negative_string : its_too_large_string));
41585 
41586 	  index += n * vector_offset(vect, i);
41587 	}
41588       if (is_not_null(x))
41589 	{
41590 	  s7_pointer nv;
41591 	  if (!is_normal_vector(vect))
41592 	    return(out_of_range(sc, sc->vector_ref_symbol, int_two, indices, too_many_indices_string));
41593 	  nv = vector_element(vect, index);
41594 	  return(implicit_index(sc, nv, x));
41595 	}
41596 
41597       /* if not enough indices, return a subvector covering whatever is left */
41598       if (i < vector_ndims(vect))
41599 	return(subvector(sc, vect, i, index));
41600     }
41601   else
41602     {
41603       s7_pointer p;
41604       /* (let ((hi (make-vector 3 0.0)) (sum 0.0)) (do ((i 0 (+ i 1))) ((= i 3)) (set! sum (+ sum (hi i)))) sum) */
41605       p = car(indices);
41606 
41607       if (!s7_is_integer(p))
41608 	return(method_or_bust(sc, p, sc->vector_ref_symbol, set_ulist_1(sc, vect, indices), T_INTEGER, 2));
41609       index = s7_integer_checked(sc, p);
41610 
41611       if ((index < 0) ||
41612 	  (index >= vector_length(vect)))
41613 	return(out_of_range(sc, sc->vector_ref_symbol, int_two, p, (index < 0) ? its_negative_string : its_too_large_string));
41614 
41615       if (is_not_null(cdr(indices)))                /* (let ((L #(#(1 2 3) #(4 5 6)))) (vector-ref L 1 2)) */
41616 	{
41617 	  s7_pointer nv;
41618 	  if (!is_normal_vector(vect))
41619 	    return(out_of_range(sc, sc->vector_ref_symbol, int_two, indices, too_many_indices_string));
41620 	  nv = vector_element(vect, index);
41621 	  return(implicit_index(sc, nv, cdr(indices)));
41622 	}}
41623   return((vector_getter(vect))(sc, vect, index));
41624 }
41625 
41626 static s7_pointer g_vector_ref(s7_scheme *sc, s7_pointer args)
41627 {
41628   #define H_vector_ref "(vector-ref v ... i) returns the i-th element of vector v."
41629   #define Q_vector_ref s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_vector_symbol, sc->is_integer_symbol)
41630 
41631   s7_pointer vec;
41632 
41633   vec = car(args);
41634   if (!is_any_vector(vec))
41635     return(method_or_bust(sc, vec, sc->vector_ref_symbol, args, T_VECTOR, 1));
41636   return(vector_ref_1(sc, vec, cdr(args))); /* 19-Jan-19 */
41637 }
41638 
41639 static s7_pointer vector_ref_p_pi(s7_scheme *sc, s7_pointer v, s7_int i)
41640 {
41641   if ((!is_normal_vector(v)) ||
41642       (vector_rank(v) > 1) ||
41643       (i < 0) ||
41644       (i >= vector_length(v)))
41645     return(g_vector_ref(sc, set_plist_2(sc, v, make_integer(sc, i))));
41646   return(vector_element(v, i));
41647 }
41648 
41649 static s7_pointer vector_ref_p_pi_unchecked(s7_scheme *sc, s7_pointer v, s7_int i)
41650 {
41651   if ((i >= 0) && (i < vector_length(v)))
41652     return(vector_getter(v)(sc, v, i));
41653   out_of_range(sc, sc->vector_ref_symbol, int_two, wrap_integer1(sc, i), (i < 0) ? its_negative_string : its_too_large_string);
41654   return(v);
41655 }
41656 
41657 static s7_pointer normal_vector_ref_p_pi_unchecked(s7_scheme *sc, s7_pointer v, s7_int i)
41658 {
41659   if ((i >= 0) && (i < vector_length(v)))
41660     return(vector_element(v, i));
41661   out_of_range(sc, sc->vector_ref_symbol, int_two, wrap_integer1(sc, i), (i < 0) ? its_negative_string : its_too_large_string);
41662   return(v);
41663 }
41664 
41665 static s7_pointer vector_ref_p_pii(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2)
41666 {
41667   if ((!is_any_vector(v)) ||
41668       (vector_rank(v) != 2) ||
41669       (i1 < 0) || (i2 < 0) ||
41670       (i1 >= vector_dimension(v, 0)) ||
41671       (i2 >= vector_dimension(v, 1)))
41672     return(g_vector_ref(sc, set_plist_3(sc, v, make_integer(sc, i1), make_integer(sc, i2))));
41673   return(vector_getter(v)(sc, v, i2 + (i1 * vector_offset(v, 0))));
41674 }
41675 
41676 static s7_pointer vector_ref_p_pii_direct(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2)
41677 {
41678   if ((i1 < 0) || (i2 < 0) ||
41679       (i1 >= vector_dimension(v, 0)) ||
41680       (i2 >= vector_dimension(v, 1)))
41681     return(g_vector_ref(sc, set_plist_3(sc, v, make_integer(sc, i1), make_integer(sc, i2))));
41682   return(vector_element(v, i2 + (i1 * vector_offset(v, 0))));
41683 }
41684 
41685 /* this is specific to T_VECTOR */
41686 static s7_pointer vector_ref_unchecked(s7_scheme *sc, s7_pointer v, s7_int i)
41687 {
41688 #if S7_DEBUGGING
41689   if (!is_normal_vector(v)) fprintf(stderr, "%s[%d]: vector is not T_VECTOR\n", __func__, __LINE__);
41690 #endif
41691   return(vector_element(v, i));
41692 }
41693 
41694 static inline s7_pointer vector_ref_p_pp(s7_scheme *sc, s7_pointer vec, s7_pointer ind)
41695 {
41696   s7_int index;
41697   if ((!is_normal_vector(vec)) ||
41698       (vector_rank(vec) != 1) ||
41699       (!s7_is_integer(ind)))
41700     return(g_vector_ref(sc, set_plist_2(sc, vec, ind)));
41701   index = s7_integer_checked(sc, ind);
41702   if ((index < 0) || (index >= vector_length(vec)))
41703     return(out_of_range(sc, sc->vector_ref_symbol, int_two, ind, (index < 0) ? its_negative_string : its_too_large_string));
41704   return(vector_element(vec, index));
41705 }
41706 
41707 static s7_pointer g_vector_ref_2(s7_scheme *sc, s7_pointer args) {return(vector_ref_p_pp(sc, car(args), cadr(args)));}
41708 
41709 static s7_pointer g_vector_ref_3(s7_scheme *sc, s7_pointer args)
41710 {
41711   s7_pointer vec, i1, i2;
41712   s7_int ix, iy;
41713 
41714   vec = car(args);
41715   if (!is_any_vector(vec))
41716     return(g_vector_ref(sc, args));
41717   if (vector_rank(vec) != 2)
41718     return(g_vector_ref(sc, args));
41719 
41720   i1 = cadr(args);
41721   if (!s7_is_integer(i1))
41722     return(g_vector_ref(sc, args));
41723   i2 = caddr(args);
41724   if (!s7_is_integer(i2))
41725     return(g_vector_ref(sc, args));
41726   ix = s7_integer_checked(sc, i1);
41727   iy = s7_integer_checked(sc, i2);
41728   if ((ix >= 0) &&
41729       (iy >= 0) &&
41730       (ix < vector_dimension(vec, 0)) &&
41731       (iy < vector_dimension(vec, 1)))
41732     {
41733       s7_int index;
41734       index = (ix * vector_offset(vec, 0)) + iy; /* vector_offset(vec, 1) == 1 */
41735       return(vector_getter(vec)(sc, vec, index));
41736     }
41737   return(g_vector_ref(sc, args));
41738 }
41739 
41740 static s7_pointer vector_ref_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
41741 {
41742   if (args == 2)
41743     return(sc->vector_ref_2);
41744   return((args == 3) ? sc->vector_ref_3 : f);
41745 }
41746 
41747 
41748 /* -------------------------------- vector-set! -------------------------------- */
41749 static s7_pointer g_vector_set(s7_scheme *sc, s7_pointer args)
41750 {
41751   #define H_vector_set "(vector-set! v i ... value) sets the i-th element of vector v to value."
41752   #define Q_vector_set s7_make_circular_signature(sc, 3, 4, sc->T, sc->is_vector_symbol, sc->is_integer_symbol, sc->is_integer_or_any_at_end_symbol)
41753 
41754   s7_pointer vec, val;
41755   s7_int index;
41756 
41757   vec = car(args);
41758   if (!is_any_vector(vec))
41759     return(method_or_bust(sc, vec, sc->vector_set_symbol, args, T_VECTOR, 1));
41760   if (is_immutable_vector(vec))
41761     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->vector_set_symbol, vec)));
41762 
41763   if (vector_length(vec) == 0)
41764     return(out_of_range(sc, sc->vector_set_symbol, int_one, vec, its_too_large_string));
41765 
41766   if (vector_rank(vec) > 1)
41767     {
41768       s7_int i;
41769       s7_pointer x;
41770       index = 0;
41771       for (x = cdr(args), i = 0; (is_not_null(cdr(x))) && (i < vector_ndims(vec)); x = cdr(x), i++)
41772 	{
41773 	  s7_int n;
41774 	  s7_pointer p;
41775 	  p = car(x);
41776 	  if (!s7_is_integer(p))
41777 	    return(method_or_bust(sc, p, sc->vector_set_symbol, args, T_INTEGER, i + 2));
41778           n = s7_integer_checked(sc, p);
41779 	  if ((n < 0) ||
41780 	      (n >= vector_dimension(vec, i)))
41781 	    return(out_of_range(sc, sc->vector_set_symbol, wrap_integer1(sc, i + 2), p, (n < 0) ? its_negative_string : its_too_large_string));
41782 
41783 	  index += n * vector_offset(vec, i);
41784 	}
41785 
41786       if (is_not_null(cdr(x)))
41787 	return(s7_wrong_number_of_args_error(sc, "too many arguments for vector-set!: ~S", args));
41788       if (i != vector_ndims(vec))
41789 	return(s7_wrong_number_of_args_error(sc, "not enough arguments for vector-set!: ~S", args));
41790 
41791       val = car(x);
41792     }
41793   else
41794     {
41795       s7_pointer p;
41796       p = cadr(args);
41797       if (!s7_is_integer(p))
41798 	return(method_or_bust(sc, p, sc->vector_set_symbol, args, T_INTEGER, 2));
41799       index = s7_integer_checked(sc, p);
41800       if ((index < 0) ||
41801 	  (index >= vector_length(vec)))
41802 	return(out_of_range(sc, sc->vector_set_symbol, int_two, p, (index < 0) ? its_negative_string : its_too_large_string));
41803 
41804       if (is_not_null(cdddr(args)))
41805 	{
41806 	  set_car(sc->temp_cell_2, vector_getter(vec)(sc, vec, index));
41807 	  if (!is_any_vector(car(sc->temp_cell_2)))
41808 	    return(s7_wrong_number_of_args_error(sc, "too many arguments for vector-set!: ~S", args));
41809 	  set_cdr(sc->temp_cell_2, cddr(args));
41810 	  return(g_vector_set(sc, sc->temp_cell_2));
41811 	}
41812       val = caddr(args);
41813     }
41814 
41815   if (is_typed_vector(vec))
41816     {
41817       if ((sc->safety < NO_SAFETY) || /* or == NO_SAFETY?? */
41818 	  (typed_vector_typer_call(sc, vec, set_plist_1(sc, val)) != sc->F))
41819 	{
41820 	  vector_element(vec, index) = val;
41821 	  return(val);
41822 	}
41823       return(s7_wrong_type_arg_error(sc, "vector-set!", 3, val, make_type_name(sc, typed_vector_typer_name(sc, vec), INDEFINITE_ARTICLE)));
41824     }
41825 
41826   vector_setter(vec)(sc, vec, index, val);
41827   return(val);
41828 }
41829 
41830 static s7_pointer vector_set_p_pip(s7_scheme *sc, s7_pointer v, s7_int i, s7_pointer p)
41831 {
41832   if ((!is_any_vector(v)) ||
41833       (vector_rank(v) > 1) ||
41834       (i < 0) ||
41835       (i >= vector_length(v)))
41836     return(g_vector_set(sc, set_plist_3(sc, v, make_integer(sc, i), p)));
41837 
41838   if (is_typed_vector(v))
41839     return(typed_vector_setter(sc, v, i, p));
41840 
41841   vector_setter(v)(sc, v, i, p);
41842   return(p);
41843 }
41844 
41845 static s7_pointer vector_set_p_pip_unchecked(s7_scheme *sc, s7_pointer v, s7_int i, s7_pointer p)
41846 {
41847   if ((i >= 0) && (i < vector_length(v)))
41848     vector_element(v, i) = p;
41849   else out_of_range(sc, sc->vector_set_symbol, int_two, wrap_integer1(sc, i), (i < 0) ? its_negative_string : its_too_large_string);
41850   return(p);
41851 }
41852 
41853 static s7_pointer vector_set_p_piip(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2, s7_pointer p)
41854 {
41855   if ((!is_any_vector(v)) ||
41856       (vector_rank(v) != 2) ||
41857       (i1 < 0) || (i2 < 0) ||
41858       (i1 >= vector_dimension(v, 0)) ||
41859       (i2 >= vector_dimension(v, 1)))
41860     return(g_vector_set(sc, set_elist_4(sc, v, make_integer(sc, i1), make_integer(sc, i2), p)));
41861 
41862   if (is_typed_vector(v))
41863     return(typed_vector_setter(sc, v, i2 + (i1 * vector_offset(v, 0)), p));
41864 
41865   vector_setter(v)(sc, v, i2 + (i1 * vector_offset(v, 0)), p);
41866   return(p);
41867 }
41868 
41869 static s7_pointer vector_set_p_piip_direct(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2, s7_pointer p)
41870 {
41871   /* normal untyped vector, rank == 2 */
41872   if ((i1 < 0) || (i2 < 0) ||
41873       (i1 >= vector_dimension(v, 0)) ||
41874       (i2 >= vector_dimension(v, 1)))
41875     return(g_vector_set(sc, set_elist_4(sc, v, make_integer(sc, i1), make_integer(sc, i2), p)));
41876   vector_element(v, i2 + (i1 * vector_offset(v, 0))) = p;
41877   return(p);
41878 }
41879 
41880 static s7_pointer typed_vector_set_p_pip_unchecked(s7_scheme *sc, s7_pointer v, s7_int i, s7_pointer p)
41881 {
41882   if ((i >= 0) && (i < vector_length(v)))
41883     typed_vector_setter(sc, v, i, p);
41884   else out_of_range(sc, sc->vector_set_symbol, int_two, wrap_integer1(sc, i), (i < 0) ? its_negative_string : its_too_large_string);
41885   return(p);
41886 }
41887 
41888 static s7_pointer typed_vector_set_p_piip_direct(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2, s7_pointer p)
41889 {
41890   if ((i1 < 0) || (i2 < 0) ||
41891       (i1 >= vector_dimension(v, 0)) ||
41892       (i2 >= vector_dimension(v, 1)))
41893     return(g_vector_set(sc, set_elist_4(sc, v, make_integer(sc, i1), make_integer(sc, i2), p)));
41894   return(typed_vector_setter(sc, v, i2 + (i1 * vector_offset(v, 0)), p));
41895 }
41896 
41897 static s7_pointer vector_set_unchecked(s7_scheme *sc, s7_pointer v, s7_int i, s7_pointer p)
41898 {
41899   vector_element(v, i) = p;
41900   return(p);
41901 }
41902 
41903 static s7_pointer typed_vector_set_unchecked(s7_scheme *sc, s7_pointer v, s7_int i, s7_pointer p)
41904 {
41905   typed_vector_setter(sc, v, i, p);
41906   return(p);
41907 }
41908 
41909 static s7_pointer g_vector_set_3(s7_scheme *sc, s7_pointer args)
41910 {
41911   /* (vector-set! vector index value) */
41912   s7_pointer ind, vec, val;
41913   s7_int index;
41914 
41915   vec = car(args);
41916   if (!is_any_vector(vec))
41917     return(g_vector_set(sc, args));
41918   if (is_immutable_vector(vec))
41919     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->vector_set_symbol, vec)));
41920   if (vector_rank(vec) > 1)
41921     return(g_vector_set(sc, args));
41922 
41923   ind = cadr(args);
41924   if (!s7_is_integer(ind))
41925     return(g_vector_set(sc, args));
41926   index = s7_integer_checked(sc, ind);
41927   if ((index < 0) ||
41928       (index >= vector_length(vec)))
41929     return(out_of_range(sc, sc->vector_set_symbol, int_two, wrap_integer1(sc, index), (index < 0) ? its_negative_string : its_too_large_string));
41930 
41931   val = caddr(args);
41932   if (is_typed_vector(vec))
41933     return(typed_vector_setter(sc, vec, index, val));
41934 
41935   vector_setter(vec)(sc, vec, index, val);
41936   return(val);
41937 }
41938 
41939 static s7_pointer vector_set_p_ppp(s7_scheme *sc, s7_pointer vec, s7_pointer ind, s7_pointer val)
41940 {
41941   s7_int index;
41942 
41943   if ((!is_normal_vector(vec)) || (vector_rank(vec) > 1))
41944     return(g_vector_set(sc, set_plist_3(sc, vec, ind, val)));
41945   if (is_immutable_vector(vec))
41946     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->vector_set_symbol, vec)));
41947   if (!s7_is_integer(ind))
41948     return(g_vector_set(sc, set_plist_3(sc, vec, ind, val)));
41949   index = s7_integer_checked(sc, ind);
41950   if ((index < 0) ||
41951       (index >= vector_length(vec)))
41952     return(out_of_range(sc, sc->vector_set_symbol, int_two, wrap_integer1(sc, index), (index < 0) ? its_negative_string : its_too_large_string));
41953 
41954   if (is_typed_vector(vec))
41955     return(typed_vector_setter(sc, vec, index, val));
41956   vector_element(vec, index) = val;
41957   return(val);
41958 }
41959 
41960 static s7_pointer g_vector_set_4(s7_scheme *sc, s7_pointer args)
41961 {
41962   s7_pointer v, ip1, ip2, val;
41963   s7_int i1, i2;
41964   v = car(args);
41965   ip1 = cadr(args);
41966   ip2 = caddr(args);
41967   if ((!is_any_vector(v)) ||
41968       (vector_rank(v) != 2) ||
41969       (is_immutable(v)) ||
41970       (!s7_is_integer(ip1)) ||
41971       (!s7_is_integer(ip2)))
41972     return(g_vector_set(sc, args));
41973   i1 = s7_integer_checked(sc, ip1);
41974   i2 = s7_integer_checked(sc, ip2);
41975   if ((i1 < 0) || (i2 < 0) ||
41976       (i1 >= vector_dimension(v, 0)) ||
41977       (i2 >= vector_dimension(v, 1)))
41978     return(g_vector_set(sc, args));
41979   val = cadddr(args);
41980   if (is_typed_vector(v))
41981     return(typed_vector_setter(sc, v, i2 + (i1 * vector_offset(v, 0)), val));
41982   vector_setter(v)(sc, v, i2 + (i1 * vector_offset(v, 0)), val);
41983   return(val);
41984 }
41985 
41986 static s7_pointer vector_set_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
41987 {
41988   if (args == 3) return(sc->vector_set_3);
41989   return((args == 4) ? sc->vector_set_4 : f);
41990 }
41991 
41992 
41993 /* -------------------------------- make-vector -------------------------------- */
41994 
41995 static s7_int multivector_length(s7_scheme *sc, s7_pointer x, s7_pointer caller)
41996 {
41997   s7_int len, dims;
41998   s7_pointer y;
41999 
42000   dims = s7_list_length(sc, x);
42001   if (dims <= 0)                /* 0 if circular, negative if dotted */
42002     wrong_type_argument_with_type(sc, caller, 1, x, a_proper_list_string);
42003   if (dims > sc->max_vector_dimensions)
42004     out_of_range(sc, caller, int_one, x, its_too_large_string);
42005 
42006   for (len = 1, y = x; is_pair(y); y = cdr(y))
42007     {
42008       if (!s7_is_integer(car(y)))
42009 	wrong_type_argument(sc, caller, position_of(y, x), car(y), T_INTEGER);
42010 #if HAVE_OVERFLOW_CHECKS
42011       if (multiply_overflow(len, s7_integer_checked(sc, car(y)), &len)) /* or better perhaps len > sc->max_vector_length */
42012 	out_of_range(sc, caller, wrap_integer1(sc, position_of(y, x)), car(y), its_too_large_string);
42013 #else
42014       len *= s7_integer_checked(sc, car(y));
42015 #endif
42016       if (len < 0)
42017 	wrong_type_argument_with_type(sc, caller, position_of(y, x), car(y), a_non_negative_integer_string);
42018     }
42019   return(len);
42020 }
42021 
42022 static inline s7_pointer make_multivector(s7_scheme *sc, s7_pointer vec, s7_pointer x)
42023 {
42024   vdims_t *v;
42025   v = list_to_dims(sc, x);
42026   vdims_original(v) = sc->F;
42027   vector_set_dimension_info(vec, v);
42028   add_multivector(sc, vec);
42029   return(vec);
42030 }
42031 
42032 static s7_pointer g_make_vector_1(s7_scheme *sc, s7_pointer args, s7_pointer caller)
42033 {
42034   s7_int len;
42035   s7_pointer x, fill, vec, typf;
42036   int32_t result_type = T_VECTOR;
42037 
42038   fill = sc->unspecified;
42039   typf = sc->T;
42040   x = car(args);
42041   if (s7_is_integer(x))
42042     {
42043       len = s7_integer_checked(sc, x);
42044       if (len < 0)
42045 	return(wrong_type_argument_with_type(sc, caller, 1, x, a_non_negative_integer_string));
42046     }
42047   else
42048     {
42049       if (!(is_pair(x)))
42050 	return(method_or_bust_with_type(sc, x, caller, args, wrap_string(sc, "an integer or a list of integers", 32), 1));
42051 
42052       if (!s7_is_integer(car(x)))
42053 	return(wrong_type_argument(sc, caller, 1, car(x), T_INTEGER));
42054       len = (is_null(cdr(x))) ? s7_integer_checked(sc, car(x)) : multivector_length(sc, x, caller);
42055     }
42056 
42057   if (is_pair(cdr(args)))
42058     {
42059       fill = cadr(args);
42060       if (caller == sc->make_int_vector_symbol)
42061 	result_type = T_INT_VECTOR;
42062       else
42063 	{
42064 	  if (caller == sc->make_float_vector_symbol)
42065 	    result_type = T_FLOAT_VECTOR;
42066 	  else
42067 	    if (caller == sc->make_byte_vector_symbol)
42068 	      result_type = T_BYTE_VECTOR;
42069 	}
42070       if (is_pair(cddr(args)))
42071 	{
42072 	  typf = caddr(args);
42073 	  if ((!is_c_function(typf)) &&
42074 	      (!is_any_closure(typf)) &&
42075 	      (typf != sc->T))
42076 	    return(wrong_type_argument_with_type(sc, caller, 3, typf, wrap_string(sc, "a built-in procedure, a closure or #t", 37)));
42077 	  if (is_any_closure(typf))
42078 	    {
42079 	      if (!is_symbol(find_closure(sc, typf, closure_let(typf))))
42080 		return(wrong_type_argument_with_type(sc, caller, 3, typf, wrap_string(sc, "a named function", 16)));
42081 	      /* the name is needed primarily by the error handler: "vector-set! argument 3, ..., is a ... but should be a <...>" */
42082 	    }
42083 	  else
42084 	    {
42085 	      if (is_c_function(typf))
42086 		{
42087 		  if (typf == global_value(sc->is_float_symbol))
42088 		    result_type = T_FLOAT_VECTOR;
42089 		  else
42090 		    {
42091 		      if (typf == global_value(sc->is_integer_symbol))
42092 			result_type = (WITH_GMP) ? T_VECTOR : T_INT_VECTOR;
42093 		      else
42094 			{
42095 			  if (typf == global_value(sc->is_byte_symbol))
42096 			    result_type = T_BYTE_VECTOR;
42097 			  else
42098 			    {
42099 			      s7_pointer sig;
42100 			      if (!c_function_name(typf))
42101 				return(wrong_type_argument_with_type(sc, caller, 3, typf, wrap_string(sc, "a named procedure", 17)));
42102 			      if (!c_function_marker(typf))
42103 				c_function_set_marker(typf, mark_vector_1);
42104 			      if (!c_function_symbol(typf))
42105 				c_function_symbol(typf) = make_symbol(sc, c_function_name(typf));
42106 			      sig = c_function_signature(typf);
42107 			      if ((sig != sc->pl_bt) &&
42108 				  (is_pair(sig)))
42109 				{
42110 				  if ((car(sig) != sc->is_boolean_symbol) || (cadr(sig) != sc->T) || (!is_null(cddr(sig))))
42111 				    return(wrong_type_argument_with_type(sc, caller, 3, typf, wrap_string(sc, "a boolean procedure", 19)));
42112 				}}}}}}}}
42113   /* before making the new vector, if fill is specified and the vector is typed, we have to check for a type error.
42114    *    otherwise we can end up with a vector whose elements are NULL, causing a segfault in the  gc.
42115    */
42116   if ((result_type == T_VECTOR) &&  /* don't put this after the make_vector_1! */
42117       (!s7_is_boolean(typf)) &&
42118       (s7_apply_function(sc, typf, set_plist_1(sc, fill)) == sc->F))
42119     s7_wrong_type_arg_error(sc, "make-vector", 3, fill,
42120 			    (is_c_function(typf)) ? c_function_name(typf) : symbol_name(find_closure(sc, typf, closure_let(typf))));
42121 
42122 #if WITH_GMP
42123   if ((is_big_number(fill)) && (result_type == T_VECTOR)) /* see comment in s7_vector_fill, this prefills with sc->nil */
42124     vec = make_vector_1(sc, len, FILLED, result_type);
42125   else
42126 #endif
42127   vec = make_vector_1(sc, len, NOT_FILLED, result_type);
42128 
42129   if ((result_type == T_VECTOR) &&
42130       (!s7_is_boolean(typf)))
42131     {
42132       set_typed_vector(vec);
42133       typed_vector_set_typer(vec, typf);
42134 
42135       if ((is_c_function(typf)) &&
42136 	  (c_function_has_simple_elements(typf)))
42137 	set_has_simple_elements(vec);
42138     }
42139 
42140   s7_vector_fill(sc, vec, fill);
42141 
42142   if ((is_pair(x)) &&
42143       (is_pair(cdr(x))))
42144     return(make_multivector(sc, vec, x));
42145 
42146   add_vector(sc, vec);
42147   return(vec);
42148 }
42149 
42150 static s7_pointer g_make_vector(s7_scheme *sc, s7_pointer args)
42151 {
42152   #define H_make_vector "(make-vector len (value #<unspecified>) type) returns a vector of len elements initialized to value. \
42153 To create a multidimensional vector, put the dimension bounds in a list (this is to avoid ambiguities such as \
42154 (make-vector 1 2) where it's not clear whether the '2' is an initial value or a dimension size).  (make-vector '(2 3) 1.0) \
42155 returns a 2 dimensional vector of 6 total elements, all initialized to 1.0."
42156   #define Q_make_vector s7_make_signature(sc, 4, sc->is_vector_symbol, \
42157 					  s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_pair_symbol), sc->T, \
42158 					  s7_make_signature(sc, 2, sc->is_procedure_symbol, sc->is_boolean_symbol))
42159   return(g_make_vector_1(sc, args, sc->make_vector_symbol));
42160 }
42161 
42162 
42163 /* -------------------------------- make-float-vector -------------------------------- */
42164 static s7_pointer g_make_float_vector(s7_scheme *sc, s7_pointer args)
42165 {
42166   #define H_make_float_vector "(make-float-vector len (init 0.0)) returns a float-vector."
42167   #define Q_make_float_vector s7_make_signature(sc, 3, sc->is_float_vector_symbol, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_pair_symbol), sc->is_real_symbol)
42168   s7_int len;
42169   s7_pointer x, p;
42170   block_t *arr;
42171 
42172   p = car(args);
42173   if ((is_pair(cdr(args))) ||
42174       (!s7_is_integer(p)))      /* (make-float-vector (bignum "3")) */
42175     {
42176       s7_pointer init;
42177       if (is_pair(cdr(args)))
42178 	{
42179 	  init = cadr(args);
42180 	  if (!s7_is_real(init))
42181 	    return(method_or_bust(sc, init, sc->make_float_vector_symbol, args, T_REAL, 2));
42182 #if WITH_GMP
42183 	  if (s7_is_bignum(init))
42184 	    return(g_make_vector_1(sc, set_plist_2(sc, p, wrap_real1(sc, s7_real(init))), sc->make_float_vector_symbol));
42185 #endif
42186 	  if (is_rational(init))
42187 	    return(g_make_vector_1(sc, set_plist_2(sc, p, wrap_real1(sc, rational_to_double(sc, init))), sc->make_float_vector_symbol));
42188 	}
42189       else init = real_zero;
42190       if (s7_is_integer(p))
42191 	len = s7_integer_checked(sc, p);
42192       else
42193 	{
42194 	  if (!is_pair(p))
42195 	    return(method_or_bust_with_type(sc, p, sc->make_float_vector_symbol, args, wrap_string(sc, "an integer or a list of integers", 32), 1));
42196 	  len = multivector_length(sc, p, sc->make_float_vector_symbol);
42197 	}
42198       x = make_vector_1(sc, len, NOT_FILLED, T_FLOAT_VECTOR);
42199       float_vector_fill(sc, x, s7_real(init));
42200       if (s7_is_integer(p))
42201 	{
42202 	  add_vector(sc, x);
42203 	  return(x);
42204 	}
42205       return(make_multivector(sc, x, p));
42206     }
42207 
42208   len = s7_integer_checked(sc, p);
42209   if (len < 0)
42210     return(wrong_type_argument_with_type(sc, sc->make_float_vector_symbol, 1, p, a_non_negative_integer_string));
42211   if (len > sc->max_vector_length)
42212     return(out_of_range(sc, sc->make_float_vector_symbol, int_one, p, its_too_large_string));
42213 
42214   arr = mallocate_vector(sc, len * sizeof(s7_double));
42215   new_cell(sc, x, T_FLOAT_VECTOR | T_SAFE_PROCEDURE);
42216   vector_length(x) = len;
42217   vector_block(x) = arr;
42218   float_vector_floats(x) = (s7_double *)block_data(arr);
42219   if (len > 0)
42220     {
42221       if (STEP_8(len))
42222 	memclr64((void *)float_vector_floats(x), len * sizeof(s7_double));
42223       else memclr((void *)float_vector_floats(x), len * sizeof(s7_double));
42224     }
42225   vector_set_dimension_info(x, NULL);
42226   vector_getter(x) = float_vector_getter;
42227   vector_setter(x) = float_vector_setter;
42228 
42229   add_vector(sc, x);
42230   return(x);
42231 }
42232 
42233 
42234 /* -------------------------------- make-int-vector -------------------------------- */
42235 static s7_pointer g_make_int_vector(s7_scheme *sc, s7_pointer args)
42236 {
42237   #define H_make_int_vector "(make-int-vector len (init 0)) returns an int-vector."
42238   #define Q_make_int_vector s7_make_signature(sc, 3, sc->is_int_vector_symbol, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_pair_symbol), sc->is_integer_symbol)
42239 
42240   s7_int len;
42241   s7_pointer x, p;
42242   block_t *arr;
42243 
42244   p = car(args);
42245   if ((is_pair(cdr(args))) ||
42246       (!s7_is_integer(p)))
42247     {
42248       s7_pointer init;
42249       if (is_pair(cdr(args)))
42250 	{
42251 	  init = cadr(args);
42252 	  if (!s7_is_integer(init))
42253 	    return(method_or_bust(sc, init, sc->make_int_vector_symbol, args, T_INTEGER, 2));
42254 	}
42255       else init = int_zero;
42256       if (s7_is_integer(p))
42257 	len = s7_integer_checked(sc, p);
42258       else
42259 	{
42260 	  if (!is_pair(p))
42261 	    return(method_or_bust_with_type(sc, p, sc->make_int_vector_symbol, args, wrap_string(sc, "an integer or a list of integers", 32), 1));
42262 	  len = multivector_length(sc, p, sc->make_int_vector_symbol);
42263 	}
42264       x = make_vector_1(sc, len, NOT_FILLED, T_INT_VECTOR);
42265       int_vector_fill(sc, x, s7_integer_checked(sc, init));
42266       if (s7_is_integer(p))
42267 	{
42268 	  add_vector(sc, x);
42269 	  return(x);
42270 	}
42271       return(make_multivector(sc, x, p));
42272     }
42273 
42274   len = s7_integer_checked(sc, p);
42275   if (len < 0)
42276     return(wrong_type_argument_with_type(sc, sc->make_int_vector_symbol, 1, p, a_non_negative_integer_string));
42277   if (len > sc->max_vector_length)
42278     return(out_of_range(sc, sc->make_int_vector_symbol, int_one, p, its_too_large_string));
42279 
42280   arr = mallocate_vector(sc, len * sizeof(s7_int));
42281   new_cell(sc, x, T_INT_VECTOR | T_SAFE_PROCEDURE);
42282   vector_length(x) = len;
42283   vector_block(x) = arr;
42284   int_vector_ints(x) = (s7_int *)block_data(arr);
42285   if (len > 0)
42286     {
42287       if (STEP_8(len))
42288 	memclr64((void *)int_vector_ints(x), len * sizeof(s7_int));
42289       else memclr((void *)int_vector_ints(x), len * sizeof(s7_int));
42290     }
42291   vector_set_dimension_info(x, NULL);
42292   vector_getter(x) = int_vector_getter;
42293   vector_setter(x) = int_vector_setter;
42294 
42295   add_vector(sc, x);
42296   return(x);
42297 }
42298 
42299 static s7_pointer make_int_vector_p_ii(s7_scheme *sc, s7_int len, s7_int init)
42300 {
42301   s7_pointer x;
42302   x = make_vector_1(sc, len, NOT_FILLED, T_INT_VECTOR);
42303   int_vector_fill(sc, x, init);
42304   add_vector(sc, x);
42305   return(x);
42306 }
42307 
42308 
42309 /* -------------------------------- make-byte-vector -------------------------------- */
42310 static s7_pointer g_make_byte_vector(s7_scheme *sc, s7_pointer args)
42311 {
42312   #define H_make_byte_vector "(make-byte-vector len (byte 0)) makes a byte-vector of length len filled with byte."
42313   #define Q_make_byte_vector s7_make_signature(sc, 3, sc->is_byte_vector_symbol, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_pair_symbol), sc->is_byte_symbol)
42314 
42315   s7_int len = 0, ib = 0;
42316   s7_pointer p, init;
42317   p = car(args);
42318 
42319   if (!is_pair(p))
42320     {
42321       if (!s7_is_integer(p))
42322 	return(method_or_bust(sc, p, sc->make_byte_vector_symbol, args, T_INTEGER, 1));
42323       len = s7_integer_checked(sc, p);
42324       if ((len < 0) || (len > sc->max_vector_length))
42325 	return(out_of_range(sc, sc->make_byte_vector_symbol, int_one, p, (len < 0) ? its_negative_string : its_too_large_string));
42326     }
42327   if (is_pair(cdr(args)))
42328     {
42329       init = cadr(args);
42330       if (!s7_is_integer(init))
42331 	return(method_or_bust(sc, init, sc->make_byte_vector_symbol, args, T_INTEGER, 2));
42332       ib = s7_integer_checked(sc, init);
42333       if ((ib < 0) || (ib > 255))
42334 	return(simple_wrong_type_argument_with_type(sc, sc->make_byte_vector_symbol, init, an_unsigned_byte_string));
42335     }
42336   else init = int_zero;
42337 
42338  if (!s7_is_integer(p))
42339    return(g_make_vector_1(sc, set_plist_2(sc, p, init), sc->make_byte_vector_symbol));
42340 
42341   p = make_simple_byte_vector(sc, len);
42342   if ((len > 0) && (is_pair(cdr(args))))
42343     local_memset((void *)(byte_vector_bytes(p)), ib, len);
42344   return(p);
42345 }
42346 
42347 static s7_pointer make_byte_vector_p_ii(s7_scheme *sc, s7_int len, s7_int init)
42348 {
42349   s7_pointer p;
42350   if ((len < 0) || (len > sc->max_vector_length))
42351     return(out_of_range(sc, sc->make_byte_vector_symbol, int_one, wrap_integer1(sc, len), (len < 0) ? its_negative_string : its_too_large_string));
42352   if ((init < 0) || (init > 255))
42353     return(simple_wrong_type_argument_with_type(sc, sc->make_byte_vector_symbol, make_integer(sc, init), an_unsigned_byte_string));
42354   p = make_simple_byte_vector(sc, len);
42355   if (len > 0)
42356     local_memset((void *)(byte_vector_bytes(p)), init, len);
42357   return(p);
42358 }
42359 
42360 
42361 /* -------------------------------- vector? -------------------------------- */
42362 static s7_pointer g_is_vector(s7_scheme *sc, s7_pointer args)
42363 {
42364   #define H_is_vector "(vector? obj) returns #t if obj is a vector"
42365   #define Q_is_vector sc->pl_bt
42366   check_boolean_method(sc, is_any_vector, sc->is_vector_symbol, args);
42367 }
42368 
42369 
42370 /* -------------------------------- vector-rank -------------------------------- */
42371 s7_int s7_vector_rank(s7_pointer vect)
42372 {
42373   return((s7_int)(vector_rank(vect)));
42374 }
42375 
42376 
42377 /* -------------------------------- vector-dimensions -------------------------------- */
42378 static s7_pointer g_vector_dimensions(s7_scheme *sc, s7_pointer args)
42379 {
42380   #define H_vector_dimensions "(vector-dimensions vect) returns a list of vect's dimensions.  In srfi-63 terms:\n\
42381     (define array-dimensions vector-dimensions)\n\
42382     (define (array-rank v) (length (vector-dimensions v)))"
42383   #define Q_vector_dimensions s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_vector_symbol)
42384 
42385   s7_pointer x;
42386   x = car(args);
42387   if (!is_any_vector(x))
42388     return(method_or_bust_one_arg(sc, x, sc->vector_dimensions_symbol, args, T_VECTOR));
42389 
42390   if (vector_rank(x) > 1)
42391     {
42392       s7_int i;
42393       sc->w = sc->nil;
42394       for (i = vector_ndims(x) - 1; i >= 0; i--)
42395 	sc->w = cons(sc, make_integer(sc, vector_dimension(x, i)), sc->w);
42396       x = sc->w;
42397       sc->w = sc->nil;
42398       return(x);
42399     }
42400   return(list_1(sc, make_integer(sc, vector_length(x))));
42401 }
42402 
42403 
42404 #define MULTIVECTOR_TOO_MANY_ELEMENTS -1
42405 #define MULTIVECTOR_NOT_ENOUGH_ELEMENTS -2
42406 
42407 static int32_t traverse_vector_data(s7_scheme *sc, s7_pointer vec, s7_int flat_ref, s7_int dimension, s7_int dimensions, s7_int *sizes, s7_pointer lst)
42408 {
42409   /* we're filling vec, we're currently looking for element flat_ref,
42410    *   we're at ref in dimension of dimensions, where sizes gives the bounds, and lst is our data
42411    *   #3D(((1 2 3) (4 5 6)) ((7 8 9) (10 11 12)))
42412    */
42413   s7_int i;
42414   s7_pointer x;
42415 
42416   for (i = 0, x = lst; i < sizes[dimension]; i++, x = cdr(x))
42417     {
42418       if (!is_pair(x))
42419 	return(MULTIVECTOR_NOT_ENOUGH_ELEMENTS);
42420 
42421       if (dimension == (dimensions - 1))
42422 	vector_setter(vec)(sc, vec, flat_ref++, car(x));
42423       else
42424 	{
42425 	  flat_ref = traverse_vector_data(sc, vec, flat_ref, dimension + 1, dimensions, sizes, car(x));
42426 	  if (flat_ref < 0) return(flat_ref);
42427 	}}
42428   return((is_null(x)) ? flat_ref : MULTIVECTOR_TOO_MANY_ELEMENTS);
42429 }
42430 
42431 static s7_pointer s7_multivector_error(s7_scheme *sc, const char *message, s7_pointer data)
42432 {
42433   return(s7_error(sc, sc->read_error_symbol,
42434 		  set_elist_3(sc, wrap_string(sc, "reading constant vector, ~A: ~A", 31),
42435 			      s7_make_string_wrapper(sc, message), data)));
42436 }
42437 
42438 static s7_pointer g_multivector(s7_scheme *sc, s7_int dims, s7_pointer data)
42439 {
42440   /* get the dimension bounds from data, make the new vector, fill it from data
42441    * dims needs to be s7_int so we can at least give correct error messages.
42442    */
42443   s7_pointer vec, x;
42444   s7_int i, err, vec_loc;
42445   s7_int *sizes;
42446 
42447   /* (#2d((1 2 3) (4 5 6)) 0 0) -> 1
42448    * (#2d((1 2 3) (4 5 6)) 1 1) -> 5
42449    * (#3d(((1 2) (3 4)) ((5 6) (7 8))) 1 1 0) -> 7
42450    * #3d(((1 2) (3 4)) ((5 6) (7))) -> error, #3d(((1 2) (3 4)) ((5 6) (7 8 9))), #3d(((1 2) (3 4)) (5 (7 8 9))) etc
42451    * but a special case: #nd() is an n-dimensional empty vector
42452    */
42453 
42454   if (dims <= 0)      /* #0d(...) #2147483649D() [if dims is int32_t this is negative] */
42455     return(s7_out_of_range_error(sc, "#nD(...) dimensions", 1, wrap_integer2(sc, dims), "must be 1 or more")); /* out_of_range uses integer1 */
42456   if (dims > sc->max_vector_dimensions)
42457     return(s7_out_of_range_error(sc, "#nD(...) dimensions", 1, wrap_integer2(sc, dims), "must be < (*s7* 'max-vector-dimensions)"));
42458 
42459   sc->w = sc->nil;
42460   if (is_null(data))  /* dims are already 0 (calloc above) */
42461     return(g_make_vector(sc, set_plist_1(sc, protected_make_list(sc, dims, int_zero))));
42462 
42463   sizes = (s7_int *)Calloc(dims, sizeof(s7_int));
42464   for (x = data, i = 0; i < dims; i++)
42465     {
42466       sizes[i] = proper_list_length(x);
42467       sc->w = cons(sc, make_integer(sc, sizes[i]), sc->w);
42468       x = car(x);
42469       if ((i < (dims - 1)) &&
42470 	  (!is_pair(x)))
42471 	{
42472 	  free(sizes);
42473 	  return(s7_multivector_error(sc, "we need a list that fully specifies the vector's elements", data));
42474 	}}
42475 
42476   vec = g_make_vector(sc, set_plist_1(sc, sc->w = proper_list_reverse_in_place(sc, sc->w)));
42477   vec_loc = s7_gc_protect_1(sc, vec);
42478   sc->w = sc->nil;
42479 
42480   /* now fill the vector checking that all the lists match */
42481   err = traverse_vector_data(sc, vec, 0, 0, dims, sizes, data);
42482 
42483   free(sizes);
42484   s7_gc_unprotect_at(sc, vec_loc);
42485   if (err < 0)
42486     return(s7_multivector_error(sc, (err == MULTIVECTOR_TOO_MANY_ELEMENTS) ? "found too many elements" : "not enough elements found", data));
42487 
42488   return(vec);
42489 }
42490 
42491 static s7_pointer g_int_multivector(s7_scheme *sc, s7_int dims, s7_pointer data)
42492 {
42493   /* dims > 1, sc->value is a pair (not null) */
42494   s7_pointer *src;
42495   s7_int i, len;
42496   sc->value = g_multivector(sc, dims, data);
42497   src = (s7_pointer *)vector_elements(sc->value);
42498   len = vector_length(sc->value);
42499   for (i = 0; i < len; i++)
42500     if (!is_t_integer(src[i]))
42501       return(s7_wrong_type_arg_error(sc, "#i(...)", i + 1, src[i], "an integer"));
42502   sc->args = g_make_vector_1(sc, set_plist_2(sc, g_vector_dimensions(sc, set_plist_1(sc, sc->value)), int_zero), sc->make_int_vector_symbol);
42503   return(s7_copy_1(sc, sc->int_vector_symbol, set_plist_2(sc, sc->value, sc->args)));
42504 }
42505 
42506 static s7_pointer g_byte_multivector(s7_scheme *sc, s7_int dims, s7_pointer data)
42507 {
42508   /* dims > 1, sc->value is a pair (not null) */
42509   s7_pointer *src;
42510   s7_int i, len;
42511   sc->value = g_multivector(sc, dims, data);
42512   src = (s7_pointer *)vector_elements(sc->value);
42513   len = vector_length(sc->value);
42514   for (i = 0; i < len; i++)
42515     if (!is_byte(src[i]))
42516       return(s7_wrong_type_arg_error(sc, "#u(...)", i + 1, src[i], "a byte"));
42517   sc->args = g_make_vector_1(sc, set_plist_2(sc, g_vector_dimensions(sc, set_plist_1(sc, sc->value)), int_zero), sc->make_byte_vector_symbol);
42518   return(s7_copy_1(sc, sc->byte_vector_symbol, set_plist_2(sc, sc->value, sc->args)));
42519 }
42520 
42521 static s7_pointer g_float_multivector(s7_scheme *sc, s7_int dims, s7_pointer data)
42522 {
42523   /* dims > 1, sc->value is a pair (not null) */
42524   s7_pointer *src;
42525   s7_int i, len;
42526   sc->value = g_multivector(sc, dims, data);
42527   src = (s7_pointer *)vector_elements(sc->value);
42528   len = vector_length(sc->value);
42529   for (i = 0; i < len; i++)
42530     if (!s7_is_real(src[i]))
42531       return(s7_wrong_type_arg_error(sc, "#r(...)", i + 1, src[i], "a real"));
42532   sc->args = g_make_vector_1(sc, set_plist_2(sc, g_vector_dimensions(sc, set_plist_1(sc, sc->value)), real_zero), sc->make_float_vector_symbol);
42533   return(s7_copy_1(sc, sc->float_vector_symbol, set_plist_2(sc, sc->value, sc->args)));
42534 }
42535 
42536 static Vectorized s7_pointer s7_vector_copy_1(s7_scheme *sc, s7_pointer old_vect)
42537 {
42538   s7_int i, len;
42539   s7_pointer new_vect;
42540 
42541   len = vector_length(old_vect);
42542   if (is_normal_vector(old_vect))
42543     {
42544       s7_pointer *src, *dst;
42545       if ((is_typed_vector(old_vect)) && (len > 0)) /* preserve the type info as well */
42546 	{
42547 	  if (vector_rank(old_vect) > 1)
42548 	    new_vect = g_make_vector(sc, set_plist_3(sc, g_vector_dimensions(sc, set_plist_1(sc, old_vect)), vector_element(old_vect, 0), typed_vector_typer(old_vect)));
42549 	  else new_vect = g_make_vector(sc, set_plist_3(sc, make_integer(sc, len), vector_element(old_vect, 0), typed_vector_typer(old_vect)));
42550 	}
42551       else
42552 	{
42553 	  if (vector_rank(old_vect) > 1)
42554 	    new_vect = g_make_vector(sc, set_plist_1(sc, g_vector_dimensions(sc, set_plist_1(sc, old_vect))));
42555 	  else new_vect = make_simple_vector(sc, len);
42556 	}
42557       /* here and in vector-fill! we have a problem with bignums -- should new bignums be allocated? (copy_proper_list also) */
42558       src = (s7_pointer *)vector_elements(old_vect);
42559       dst = (s7_pointer *)vector_elements(new_vect);
42560       for (i = len; i > 0; i--) *dst++ = *src++;
42561       return(new_vect);
42562     }
42563 
42564   if (is_float_vector(old_vect))
42565     {
42566       s7_double *src, *dst;
42567       if (vector_rank(old_vect) > 1)
42568 	new_vect = g_make_vector_1(sc, set_plist_2(sc, g_vector_dimensions(sc, set_plist_1(sc, old_vect)), real_zero), sc->make_float_vector_symbol);
42569       else new_vect = make_simple_float_vector(sc, len);
42570       src = (s7_double *)float_vector_floats(old_vect);
42571       dst = (s7_double *)float_vector_floats(new_vect);
42572       for (i = len; i > 0; i--) *dst++ = *src++;  /* same speed as memcpy(dst, src, len * sizeof(s7_double)); */
42573       return(new_vect);
42574     }
42575 
42576   if (is_int_vector(old_vect))
42577     {
42578       s7_int *src, *dst;
42579       if (vector_rank(old_vect) > 1)
42580 	new_vect = g_make_vector_1(sc, set_plist_2(sc, g_vector_dimensions(sc, set_plist_1(sc, old_vect)), int_zero), sc->make_int_vector_symbol);
42581       else new_vect = make_simple_int_vector(sc, len);
42582       src = (s7_int *)int_vector_ints(old_vect);
42583       dst = (s7_int *)int_vector_ints(new_vect);
42584       for (i = len; i > 0; i--) *dst++ = *src++;
42585       return(new_vect);
42586     }
42587 
42588   if (is_byte_vector(old_vect))
42589     {
42590       uint8_t *src, *dst;
42591       if (vector_rank(old_vect) > 1)
42592 	new_vect = g_make_vector_1(sc, set_plist_2(sc, g_vector_dimensions(sc, set_plist_1(sc, old_vect)), int_zero), sc->make_byte_vector_symbol);
42593       else new_vect = make_simple_byte_vector(sc, len);
42594       src = (uint8_t *)byte_vector_bytes(old_vect);
42595       dst = (uint8_t *)byte_vector_bytes(new_vect);
42596       for (i = len; i > 0; i--) *dst++ = *src++;
42597       return(new_vect);
42598     }
42599   return(NULL);
42600 }
42601 
42602 s7_pointer s7_vector_copy(s7_scheme *sc, s7_pointer old_vect) {return(s7_vector_copy_1(sc, old_vect));}
42603 
42604 static s7_pointer univect_ref(s7_scheme *sc, s7_pointer args, s7_pointer caller, int32_t typ)
42605 {
42606   s7_pointer v, index;
42607   s7_int ind;
42608 
42609   v = car(args);
42610   if (type(v) != typ)
42611     return(method_or_bust(sc, v, caller, args, typ, 1));
42612 
42613   if (vector_rank(v) == 1)
42614     {
42615       index = cadr(args);
42616       if (!s7_is_integer(index))
42617 	return(method_or_bust(sc, index, caller, args, T_INTEGER, 2));
42618       ind = s7_integer_checked(sc, index);
42619       if ((ind < 0) || (ind >= vector_length(v)))
42620 	return(simple_out_of_range(sc, caller, index, (ind < 0) ? its_negative_string : its_too_large_string));
42621       if (!is_null(cddr(args)))
42622 	return(out_of_range(sc, caller, int_two, cdr(args), too_many_indices_string));
42623     }
42624   else
42625     {
42626       s7_int i;
42627       s7_pointer x;
42628       ind = 0;
42629       for (x = cdr(args), i = 0; (is_not_null(x)) && (i < vector_ndims(v)); x = cdr(x), i++)
42630 	{
42631 	  s7_int n;
42632 	  index = car(x);
42633 	  if (!s7_is_integer(index))
42634 	    return(method_or_bust(sc, index, caller, args, T_INTEGER, i + 2));
42635 	  n = s7_integer_checked(sc, index);
42636 	  if ((n < 0) ||
42637 	      (n >= vector_dimension(v, i)))
42638 	    return(out_of_range(sc, caller, wrap_integer1(sc, i + 2), index, (n < 0) ? its_negative_string : its_too_large_string));
42639 	  ind += n * vector_offset(v, i);
42640 	}
42641       if (is_not_null(x))
42642 	return(out_of_range(sc, caller, int_two, cdr(args), too_many_indices_string));
42643 
42644       /* if not enough indices, return a subvector covering whatever is left */
42645       if (i < vector_ndims(v))
42646 	return(subvector(sc, v, i, ind));
42647     }
42648   if (typ == T_FLOAT_VECTOR)
42649     return(make_real(sc, float_vector(v, ind)));
42650   return((typ == T_INT_VECTOR) ? make_integer(sc, int_vector(v, ind)) : small_int(byte_vector(v, ind)));
42651 }
42652 
42653 static s7_pointer univect_set(s7_scheme *sc, s7_pointer args, s7_pointer caller, int32_t typ)
42654 {
42655   s7_pointer vec, val, index;
42656   s7_int ind;
42657 
42658   vec = car(args);
42659   if (type(vec) != typ)
42660     return(method_or_bust(sc, vec, caller, args, typ, 1));
42661   if (is_immutable_vector(vec))
42662     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, caller, vec)));
42663 
42664   if (vector_rank(vec) > 1)
42665     {
42666       s7_int i;
42667       s7_pointer x;
42668       ind = 0;
42669       for (x = cdr(args), i = 0; (is_not_null(cdr(x))) && (i < vector_ndims(vec)); x = cdr(x), i++)
42670 	{
42671 	  s7_int n;
42672 	  index = car(x);
42673 	  if (!s7_is_integer(index))
42674 	    return(method_or_bust(sc, index, caller, args, T_INTEGER, i + 2));
42675 	  n = s7_integer_checked(sc, index);
42676 	  if ((n < 0) ||
42677 	      (n >= vector_dimension(vec, i)))
42678 	    return(out_of_range(sc, caller, wrap_integer1(sc, i + 2), index, (n < 0) ? its_negative_string : its_too_large_string));
42679 	  ind += n * vector_offset(vec, i);
42680 	}
42681       if (is_not_null(cdr(x)))
42682 	return(s7_wrong_number_of_args_error(sc, "too many arguments: ~S", args));
42683       if (i != vector_ndims(vec))
42684 	return(s7_wrong_number_of_args_error(sc, "not enough arguments: ~S", args));
42685       val = car(x);
42686     }
42687   else
42688     {
42689       s7_pointer p;
42690       p = cdr(args);
42691       index = car(p);
42692       if (!s7_is_integer(index))
42693 	return(method_or_bust(sc, index, caller, args, T_INTEGER, 2));
42694       ind = s7_integer_checked(sc, index);
42695       if ((ind < 0) ||
42696 	  (ind >= vector_length(vec)))
42697 	return(out_of_range(sc, caller, int_two, index, (ind < 0) ? its_negative_string : its_too_large_string));
42698       if (is_not_null(cddr(p)))
42699 	return(s7_wrong_number_of_args_error(sc, "too many arguments: ~S", args));
42700       val = cadr(p);
42701     }
42702 
42703   if (typ == T_FLOAT_VECTOR)
42704     {
42705       if (!s7_is_real(val))
42706 	return(method_or_bust(sc, val, caller, args, T_REAL, 3));
42707       float_vector(vec, ind) = s7_real(val);
42708     }
42709   else
42710     {
42711       if (typ == T_INT_VECTOR)
42712 	{
42713 	  if (!s7_is_integer(val))
42714 	    return(method_or_bust(sc, val, caller, args, T_INTEGER, 3));
42715 	  int_vector(vec, ind) = s7_integer_checked(sc, val);
42716 	}
42717       else
42718 	{
42719 	  if (!is_byte(val))
42720 	    return(method_or_bust(sc, val, caller, args, T_INTEGER, 3));
42721 	  byte_vector(vec, ind) = (uint8_t)s7_integer_checked(sc, val);
42722 	}}
42723   return(val);
42724 }
42725 
42726 
42727 /* -------------------------------- float-vector-ref -------------------------------- */
42728 static s7_pointer g_float_vector_ref(s7_scheme *sc, s7_pointer args)
42729 {
42730   #define H_float_vector_ref "(float-vector-ref v ...) returns an element of the float-vector v."
42731   #define Q_float_vector_ref s7_make_circular_signature(sc, 2, 3, s7_make_signature(sc, 2, sc->is_float_symbol, sc->is_float_vector_symbol), sc->is_float_vector_symbol, sc->is_integer_symbol)
42732   return(univect_ref(sc, args, sc->float_vector_ref_symbol, T_FLOAT_VECTOR));
42733 }
42734 
42735 static inline s7_pointer float_vector_ref_p_pp(s7_scheme *sc, s7_pointer v, s7_pointer index)
42736 {
42737   s7_int ind;
42738   if (!is_float_vector(v))
42739     return(method_or_bust_pp(sc, v, sc->float_vector_ref_symbol, v, index, T_FLOAT_VECTOR, 1));
42740   if (vector_rank(v) != 1)
42741     return(univect_ref(sc, set_plist_2(sc, v, index), sc->float_vector_ref_symbol, T_FLOAT_VECTOR));
42742   if (!s7_is_integer(index))
42743     return(method_or_bust_pp(sc, index, sc->float_vector_ref_symbol, v, index, T_INTEGER, 2));
42744   ind = s7_integer_checked(sc, index);
42745   if ((ind < 0) || (ind >= vector_length(v)))
42746     return(simple_out_of_range(sc, sc->float_vector_ref_symbol, index, (ind < 0) ? its_negative_string : its_too_large_string));
42747   return(make_real(sc, float_vector(v, ind)));
42748 }
42749 
42750 static s7_pointer g_fv_ref_2(s7_scheme *sc, s7_pointer args) {return(float_vector_ref_p_pp(sc, car(args), cadr(args)));}
42751 
42752 static s7_pointer g_fv_ref_3(s7_scheme *sc, s7_pointer args)
42753 {
42754   s7_pointer fv, index;
42755   s7_int ind1, ind2;
42756   fv = car(args);
42757   if (!is_float_vector(fv))
42758     return(method_or_bust(sc, fv, sc->float_vector_ref_symbol, args, T_FLOAT_VECTOR, 1));
42759   if (vector_rank(fv) != 2)
42760     return(univect_ref(sc, args, sc->float_vector_ref_symbol, T_FLOAT_VECTOR));
42761   index = cadr(args);
42762   if (!s7_is_integer(index))
42763     return(method_or_bust(sc, index, sc->float_vector_ref_symbol, args, T_INTEGER, 2));
42764   ind1 = s7_integer_checked(sc, index);
42765   if ((ind1 < 0) || (ind1 >= vector_dimension(fv, 0)))
42766     return(simple_out_of_range(sc, sc->float_vector_ref_symbol, index, (ind1 < 0) ? its_negative_string : its_too_large_string));
42767   index = caddr(args);
42768   if (!s7_is_integer(index))
42769     return(method_or_bust(sc, index, sc->float_vector_ref_symbol, args, T_INTEGER, 3));
42770   ind2 = s7_integer_checked(sc, index);
42771   if ((ind2 < 0) || (ind2 >= vector_dimension(fv, 1)))
42772     return(simple_out_of_range(sc, sc->float_vector_ref_symbol, index, (ind2 < 0) ? its_negative_string : its_too_large_string));
42773   ind1 = ind1 * vector_offset(fv, 0) + ind2;
42774   return(make_real(sc, float_vector(fv, ind1)));
42775 }
42776 
42777 static s7_double float_vector_ref_unchecked(s7_scheme *sc, s7_pointer v, s7_int i) {return(float_vector(v, i));}
42778 static inline s7_int ref_check_index(s7_scheme *sc, s7_pointer v, s7_int i)
42779 {
42780   /* according to valgrind, it is faster to split out the bounds check */
42781   if ((i < 0) || (i >= vector_length(v)))
42782     out_of_range(sc, sc->float_vector_ref_symbol, int_two, wrap_integer1(sc, i), (i < 0) ? its_negative_string : its_too_large_string);
42783   return(i);
42784 }
42785 static s7_double float_vector_ref_d_7pi(s7_scheme *sc, s7_pointer v, s7_int i) {return(float_vector(v, ref_check_index(sc, v, i)));}
42786 static s7_pointer float_vector_ref_unchecked_p(s7_scheme *sc, s7_pointer v, s7_int i) {return(make_real(sc, float_vector(v, i)));}
42787 
42788 static inline s7_double float_vector_ref_d_7pii(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2)
42789 {
42790   if ((i1 >= 0) && (i1 < vector_dimension(v, 0)))
42791     {
42792       if ((i2 >= 0) && (i2 < vector_dimension(v, 1)))
42793 	return(float_vector(v, i2 + (i1 * vector_offset(v, 0))));
42794       out_of_range(sc, sc->float_vector_ref_symbol, int_three, wrap_integer1(sc, i2), (i2 < 0) ? its_negative_string : its_too_large_string);
42795     }
42796   out_of_range(sc, sc->float_vector_ref_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
42797   return(0);
42798 }
42799 
42800 static s7_pointer float_vector_ref_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
42801 {
42802   return((args == 2) ? sc->fv_ref_2 : ((args == 3) ? sc->fv_ref_3 : f));
42803 }
42804 
42805 
42806 /* -------------------------------- float-vector-set! -------------------------------- */
42807 static s7_pointer g_float_vector_set(s7_scheme *sc, s7_pointer args)
42808 {
42809   #define H_float_vector_set "(float-vector-set! v i ... value) sets the i-th element of the float-vector v to value."
42810   #define Q_float_vector_set s7_make_circular_signature(sc, 3, 4, sc->is_real_symbol, sc->is_float_vector_symbol, sc->is_integer_symbol, sc->is_integer_or_real_at_end_symbol)
42811   return(univect_set(sc, args, sc->float_vector_set_symbol, T_FLOAT_VECTOR));
42812 }
42813 
42814 static s7_pointer g_fv_set_3(s7_scheme *sc, s7_pointer args)
42815 {
42816   s7_pointer fv, index, value;
42817   s7_int ind;
42818   fv = car(args);
42819   if (!is_float_vector(fv))
42820     return(method_or_bust(sc, fv, sc->float_vector_set_symbol, args, T_FLOAT_VECTOR, 1));
42821   if (vector_rank(fv) != 1)
42822     return(univect_set(sc, args, sc->float_vector_set_symbol, T_FLOAT_VECTOR));
42823   index = cadr(args);
42824   if (!s7_is_integer(index))
42825     return(method_or_bust(sc, index, sc->float_vector_set_symbol, args, T_INTEGER, 2));
42826   ind = s7_integer_checked(sc, index);
42827   if ((ind < 0) || (ind >= vector_length(fv)))
42828     return(simple_out_of_range(sc, sc->float_vector_set_symbol, index, (ind < 0) ? its_negative_string : its_too_large_string));
42829   value = caddr(args);
42830   if (!s7_is_real(value))
42831     return(method_or_bust(sc, value, sc->float_vector_set_symbol, args, T_REAL, 3));
42832   if (is_immutable_vector(fv))
42833     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->float_vector_set_symbol, fv)));
42834   float_vector(fv, ind) = s7_real(value);
42835   return(value);
42836 }
42837 
42838 static s7_pointer g_fv_set_unchecked(s7_scheme *sc, s7_pointer args)
42839 {
42840   s7_pointer fv, value;
42841   s7_int ind;
42842   value = caddr(args);
42843   if (!s7_is_real(value))
42844     return(wrong_type_argument(sc, sc->float_vector_set_symbol, 3, value, T_REAL));
42845   fv = car(args);
42846   if (is_immutable_vector(fv))
42847     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->float_vector_set_symbol, fv)));
42848   ind = s7_integer_checked(sc, cadr(args));
42849   float_vector(fv, ind) = s7_real(value);
42850   return(value);
42851 }
42852 
42853 static bool find_matching_ref(s7_scheme *sc, s7_pointer getter, s7_pointer expr)
42854 {
42855   /* expr: (*set! v i val), val exists (i.e. args=3, so cddddr is null) */
42856   s7_pointer v, ind;
42857   v = cadr(expr);
42858   ind = caddr(expr);
42859   if ((is_symbol(v)) && (!is_pair(ind)))
42860     {
42861       s7_pointer val;
42862       val = cadddr(expr);
42863       if (is_optimized(val)) /* includes is_pair */
42864 	{
42865 	  s7_pointer p;
42866 	  for (p = val; is_pair(p); p = cdr(p))
42867 	    if (is_pair(car(p)))
42868 	      {
42869 		s7_pointer ref;
42870 		ref = car(p);
42871 		if (((car(ref) == getter) &&
42872 		     (is_proper_list_2(sc, cdr(ref))) &&
42873 		     (cadr(ref) == v) &&
42874 		     (caddr(ref) == ind)) ||
42875 		    ((car(ref) == v) &&
42876 		     (is_proper_list_1(sc, cdr(ref))) &&
42877 		     (cadr(ref) == ind)))
42878 		  return(true);
42879 	      }}}
42880   return(false);
42881 }
42882 
42883 static s7_pointer float_vector_set_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
42884 {
42885   if (args == 3)
42886     return((find_matching_ref(sc, sc->float_vector_ref_symbol, expr)) ? sc->fv_set_unchecked : sc->fv_set_3);
42887   return(f);
42888 }
42889 
42890 static s7_double float_vector_set_unchecked(s7_scheme *sc, s7_pointer v, s7_int i, s7_double x) {float_vector(v, i) = x; return(x);}
42891 static s7_int set_check_index(s7_scheme *sc, s7_pointer v, s7_int i)
42892 {
42893   if ((i < 0) || (i >= vector_length(v)))
42894     out_of_range(sc, sc->float_vector_set_symbol, int_two, wrap_integer1(sc, i), (i < 0) ? its_negative_string : its_too_large_string);
42895   return(i);
42896 }
42897 
42898 static s7_double float_vector_set_d_7pid(s7_scheme *sc, s7_pointer v, s7_int i, s7_double x) {float_vector(v, (set_check_index(sc, v, i))) = x; return(x);}
42899 static s7_double float_vector_set_d_7piid(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2, s7_double x)
42900 {
42901   if ((i1 >= 0) && (i1 < vector_dimension(v, 0)))
42902     {
42903       if ((i2 >= 0) && (i2 < vector_dimension(v, 1)))
42904 	{
42905 	  float_vector(v, i2 + (i1 * vector_offset(v, 0))) = x;
42906 	  return(x);
42907 	}
42908       out_of_range(sc, sc->float_vector_set_symbol, int_three, wrap_integer1(sc, i2), (i2 < 0) ? its_negative_string : its_too_large_string);
42909     }
42910   out_of_range(sc, sc->float_vector_set_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
42911   return(x);
42912 }
42913 
42914 static s7_pointer float_vector_set_unchecked_p(s7_scheme *sc, s7_pointer v, s7_int i, s7_pointer p)
42915 {
42916   float_vector(v, i) = real_to_double(sc, p, "float-vector-set!");
42917   return(p);
42918 }
42919 
42920 
42921 /* -------------------------------- int-vector-ref -------------------------------- */
42922 static s7_pointer g_int_vector_ref(s7_scheme *sc, s7_pointer args)
42923 {
42924   #define H_int_vector_ref "(int-vector-ref v ...) returns an element of the int-vector v."
42925   #define Q_int_vector_ref s7_make_circular_signature(sc, 2, 3, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_int_vector_symbol), sc->is_int_vector_symbol, sc->is_integer_symbol)
42926   return(univect_ref(sc, args, sc->int_vector_ref_symbol, T_INT_VECTOR));
42927 }
42928 
42929 static s7_int int_vector_ref_unchecked(s7_scheme *sc, s7_pointer v, s7_int i) {return(int_vector(v, i));}
42930 static s7_int int_vector_ref_i_7pi(s7_scheme *sc, s7_pointer v, s7_int i)
42931 {
42932   if ((i >= 0) && (i < vector_length(v)))
42933     return(int_vector(v, i));
42934   out_of_range(sc, sc->int_vector_ref_symbol, int_two, wrap_integer1(sc, i), (i < 0) ? its_negative_string : its_too_large_string);
42935   return(0);
42936 }
42937 
42938 static s7_pointer int_vector_ref_unchecked_p(s7_scheme *sc, s7_pointer v, s7_int i) {return(make_integer(sc, int_vector(v, i)));}
42939 
42940 static s7_int int_vector_ref_i_7pii(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2)
42941 {
42942   if ((i1 >= 0) && (i1 < vector_dimension(v, 0)))
42943     {
42944       if ((i2 >= 0) && (i2 < vector_dimension(v, 1)))
42945 	return(int_vector(v, i2 + (i1 * vector_offset(v, 0))));
42946       out_of_range(sc, sc->int_vector_ref_symbol, int_three, wrap_integer1(sc, i2), (i2 < 0) ? its_negative_string : its_too_large_string);
42947     }
42948   out_of_range(sc, sc->int_vector_ref_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
42949   return(0);
42950 }
42951 
42952 static s7_int int_vector_ref_i_7piii(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2, s7_int i3)
42953 {
42954   if ((i1 >= 0) && (i1 < vector_dimension(v, 0)))
42955     {
42956       if ((i2 >= 0) && (i2 < vector_dimension(v, 1)))
42957 	{
42958 	  if ((i3 >= 0) && (i3 < vector_dimension(v, 2)))
42959 	    return(int_vector(v, i3 + (i2 * vector_offset(v, 1)) + (i1 * vector_offset(v, 0))));
42960 	  out_of_range(sc, sc->int_vector_ref_symbol, small_int(4), wrap_integer1(sc, i3), (i3 < 0) ? its_negative_string : its_too_large_string);
42961 	}
42962       out_of_range(sc, sc->int_vector_ref_symbol, int_three, wrap_integer1(sc, i2), (i2 < 0) ? its_negative_string : its_too_large_string);
42963     }
42964   out_of_range(sc, sc->int_vector_ref_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
42965   return(0);
42966 }
42967 
42968 static inline s7_pointer int_vector_ref_p_pp(s7_scheme *sc, s7_pointer v, s7_pointer index)
42969 {
42970   s7_int ind;
42971   if (!is_int_vector(v))
42972     return(method_or_bust_pp(sc, v, sc->int_vector_ref_symbol, v, index, T_INT_VECTOR, 1));
42973   if (vector_rank(v) != 1)
42974     return(univect_ref(sc, set_plist_2(sc, v, index), sc->int_vector_ref_symbol, T_INT_VECTOR));
42975   if (!s7_is_integer(index))
42976     return(method_or_bust_pp(sc, index, sc->int_vector_ref_symbol, v, index, T_INTEGER, 2));
42977   ind = s7_integer_checked(sc, index);
42978   if ((ind < 0) || (ind >= vector_length(v)))
42979     return(simple_out_of_range(sc, sc->int_vector_ref_symbol, index, (ind < 0) ? its_negative_string : its_too_large_string));
42980   return(make_integer(sc, int_vector(v, ind)));
42981 }
42982 
42983 static s7_pointer g_iv_ref_2(s7_scheme *sc, s7_pointer args) {return(int_vector_ref_p_pp(sc, car(args), cadr(args)));}
42984 
42985 static s7_pointer g_iv_ref_3(s7_scheme *sc, s7_pointer args)
42986 {
42987   s7_pointer iv, index;
42988   s7_int ind1, ind2;
42989   iv = car(args);
42990   if (!is_int_vector(iv))
42991     return(method_or_bust(sc, iv, sc->int_vector_ref_symbol, args, T_INT_VECTOR, 1));
42992   if (vector_rank(iv) != 2)
42993     return(univect_ref(sc, args, sc->int_vector_ref_symbol, T_INT_VECTOR));
42994   index = cadr(args);
42995   if (!s7_is_integer(index))
42996     return(method_or_bust(sc, index, sc->int_vector_ref_symbol, args, T_INTEGER, 2));
42997   ind1 = s7_integer_checked(sc, index);
42998   if ((ind1 < 0) || (ind1 >= vector_dimension(iv, 0)))
42999     return(simple_out_of_range(sc, sc->int_vector_ref_symbol, index, (ind1 < 0) ? its_negative_string : its_too_large_string));
43000   index = caddr(args);
43001   if (!s7_is_integer(index))
43002     return(method_or_bust(sc, index, sc->int_vector_ref_symbol, args, T_INTEGER, 3));
43003   ind2 = s7_integer_checked(sc, index);
43004   if ((ind2 < 0) || (ind2 >= vector_dimension(iv, 1)))
43005     return(simple_out_of_range(sc, sc->int_vector_ref_symbol, index, (ind2 < 0) ? its_negative_string : its_too_large_string));
43006   ind1 = ind1 * vector_offset(iv, 0) + ind2;
43007   return(make_integer(sc, int_vector(iv, ind1)));
43008 }
43009 
43010 static s7_pointer int_vector_ref_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
43011 {
43012   return((args == 2) ? sc->iv_ref_2 : ((args == 3) ? sc->iv_ref_3 : f));
43013 }
43014 
43015 
43016 /* -------------------------------- int-vector-set! -------------------------------- */
43017 static s7_pointer g_int_vector_set(s7_scheme *sc, s7_pointer args)
43018 {
43019   #define H_int_vector_set "(int-vector-set! v i ... value) sets the i-th element of the int-vector v to value."
43020   #define Q_int_vector_set s7_make_circular_signature(sc, 2, 3, sc->is_integer_symbol, sc->is_int_vector_symbol, sc->is_integer_symbol)
43021   return(univect_set(sc, args, sc->int_vector_set_symbol, T_INT_VECTOR));
43022 }
43023 
43024 static s7_int int_vector_set_unchecked(s7_scheme *sc, s7_pointer v, s7_int i, s7_int x) {int_vector(v, i) = x; return(x);}
43025 
43026 static s7_int int_vector_set_i_7pii(s7_scheme *sc, s7_pointer v, s7_int i, s7_int x)
43027 {
43028   if ((i < 0) || (i >= vector_length(v)))
43029     out_of_range(sc, sc->int_vector_set_symbol, int_two, wrap_integer1(sc, i), (i < 0) ? its_negative_string : its_too_large_string);
43030   int_vector(v, i) = x;
43031   return(x);
43032 }
43033 
43034 static s7_int int_vector_set_i_7piii(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2, s7_int i3)
43035 {
43036   if ((i1 >= 0) && (i1 < vector_dimension(v, 0)))
43037     {
43038       if ((i2 >= 0) && (i2 < vector_dimension(v, 1)))
43039 	{
43040 	  int_vector(v, i2 + (i1 * vector_offset(v, 0))) = i3;
43041 	  return(i3);
43042 	}
43043       out_of_range(sc, sc->int_vector_set_symbol, int_three, wrap_integer1(sc, i2), (i2 < 0) ? its_negative_string : its_too_large_string);
43044     }
43045   out_of_range(sc, sc->int_vector_set_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
43046   return(0);
43047 }
43048 
43049 static s7_pointer int_vector_set_p_ppp(s7_scheme *sc, s7_pointer v, s7_pointer index, s7_pointer val)
43050 {
43051   if ((is_int_vector(v)) && (vector_rank(v) == 1) && (!is_immutable_vector(v)) &&
43052       (is_t_integer(index)) && (is_t_integer(val)))
43053     {
43054       s7_int i;
43055       i = integer(index);
43056       if ((i < 0) || (i >= vector_length(v)))
43057 	out_of_range(sc, sc->int_vector_set_symbol, int_two, index, (i < 0) ? its_negative_string : its_too_large_string);
43058       int_vector(v, i) = integer(val);
43059     }
43060   else
43061     {
43062       if (!is_int_vector(v))
43063 	return(method_or_bust_ppp(sc, v, sc->int_vector_set_symbol, v, index, val, T_INT_VECTOR, 1));
43064       if (vector_rank(v) != 1)
43065 	return(univect_set(sc, list_3(sc, v, index, val), sc->int_vector_set_symbol, T_INT_VECTOR));
43066       if (is_immutable_vector(v))
43067 	return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->int_vector_set_symbol, v)));
43068       if (!s7_is_integer(index))
43069 	return(method_or_bust_ppp(sc, index, sc->int_vector_set_symbol, v, index, val, T_INTEGER, 2));
43070       if (!s7_is_integer(val))
43071 	return(method_or_bust_ppp(sc, val, sc->int_vector_set_symbol, v, index, val, T_INTEGER, 3));
43072 #if WITH_GMP
43073       {
43074 	s7_int i;
43075 	i = s7_integer_checked(sc, index);
43076 	if ((i < 0) || (i >= vector_length(v)))
43077 	  out_of_range(sc, sc->int_vector_set_symbol, int_two, index, (i < 0) ? its_negative_string : its_too_large_string);
43078 	int_vector(v, i) = s7_integer_checked(sc, val);
43079       }
43080 #else
43081 #if S7_DEBUGGING
43082       fprintf(stderr, "fell through %s[%d]\n", __func__, __LINE__);
43083 #endif
43084 #endif
43085     }
43086   return(val);
43087 }
43088 
43089 static s7_pointer int_vector_set_unchecked_p(s7_scheme *sc, s7_pointer v, s7_int i, s7_pointer p)
43090 {
43091   if (!s7_is_integer(p))
43092     s7_wrong_type_arg_error(sc, "int-vector-set!", 3, p, "an integer");
43093   int_vector(v, i) = s7_integer_checked(sc, p);
43094   return(p);
43095 }
43096 
43097 static s7_pointer g_iv_set_3(s7_scheme *sc, s7_pointer args)
43098 {
43099   s7_pointer v, index, value;
43100   s7_int ind;
43101   v = car(args);
43102   if (!is_int_vector(v))
43103     return(method_or_bust(sc, v, sc->int_vector_set_symbol, args, T_INT_VECTOR, 1));
43104   if (vector_rank(v) != 1)
43105     return(univect_set(sc, args, sc->int_vector_set_symbol, T_INT_VECTOR));
43106   index = cadr(args);
43107   if (!s7_is_integer(index))
43108     return(method_or_bust(sc, index, sc->int_vector_set_symbol, args, T_INTEGER, 2));
43109   ind = s7_integer_checked(sc, index);
43110   if ((ind < 0) || (ind >= vector_length(v)))
43111     return(simple_out_of_range(sc, sc->int_vector_set_symbol, index, (ind < 0) ? its_negative_string : its_too_large_string));
43112   value = caddr(args);
43113   if (!s7_is_integer(value))
43114     return(method_or_bust(sc, value, sc->int_vector_set_symbol, args, T_INTEGER, 3));
43115   if (is_immutable_vector(v))
43116     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->int_vector_set_symbol, v)));
43117   int_vector(v, ind) = s7_integer_checked(sc, value);
43118   return(value);
43119 }
43120 
43121 static s7_pointer int_vector_set_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
43122 {
43123   return((args == 3) ? sc->iv_set_3 : f);
43124 }
43125 
43126 
43127 /* -------------------------------- byte-vector-ref -------------------------------- */
43128 static s7_pointer g_byte_vector_ref(s7_scheme *sc, s7_pointer args)
43129 {
43130   #define H_byte_vector_ref "(byte-vector-ref vect index) returns the byte at the index-th element of the byte-vector vect"
43131   #define Q_byte_vector_ref s7_make_circular_signature(sc, 2, 3, s7_make_signature(sc, 2, sc->is_byte_symbol, sc->is_byte_vector_symbol), sc->is_byte_vector_symbol, sc->is_integer_symbol)
43132   return(univect_ref(sc, args, sc->byte_vector_ref_symbol, T_BYTE_VECTOR));
43133 }
43134 
43135 static s7_int byte_vector_ref_i_7pi(s7_scheme *sc, s7_pointer p1, s7_int i1)
43136 {
43137   if ((i1 >= 0) && (i1 < byte_vector_length(p1)))
43138     return((s7_int)((byte_vector(p1, i1))));
43139   out_of_range(sc, sc->byte_vector_ref_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
43140   return(0);
43141 }
43142 
43143 static s7_int byte_vector_ref_i_7pii(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2)
43144 {
43145   if ((i1 >= 0) && (i1 < vector_dimension(v, 0)))
43146     {
43147       if ((i2 >= 0) && (i2 < vector_dimension(v, 1)))
43148 	return((s7_int)byte_vector(v, i2 + (i1 * vector_offset(v, 0))));
43149       out_of_range(sc, sc->byte_vector_ref_symbol, int_three, wrap_integer1(sc, i2), (i2 < 0) ? its_negative_string : its_too_large_string);
43150     }
43151   out_of_range(sc, sc->byte_vector_ref_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
43152   return(0);
43153 }
43154 
43155 static s7_pointer byte_vector_ref_unchecked_p(s7_scheme *sc, s7_pointer p1, s7_int i1) {return(small_int((byte_vector(p1, i1))));}
43156 static s7_int byte_vector_ref_unchecked(s7_scheme *sc, s7_pointer p1, s7_int i1) {return(byte_vector(p1, i1));}
43157 
43158 static s7_pointer g_bv_ref_2(s7_scheme *sc, s7_pointer args)
43159 {
43160   s7_pointer v, index;
43161   s7_int ind;
43162   v = car(args);
43163   if (!is_byte_vector(v))
43164     return(method_or_bust(sc, v, sc->byte_vector_ref_symbol, args, T_BYTE_VECTOR, 1));
43165   if (vector_rank(v) != 1)
43166     return(univect_ref(sc, args, sc->byte_vector_ref_symbol, T_BYTE_VECTOR));
43167   index = cadr(args);
43168   if (!s7_is_integer(index))
43169     return(method_or_bust(sc, index, sc->byte_vector_ref_symbol, args, T_INTEGER, 2));
43170   ind = s7_integer_checked(sc, index);
43171   if ((ind < 0) || (ind >= vector_length(v)))
43172     return(simple_out_of_range(sc, sc->byte_vector_ref_symbol, index, (ind < 0) ? its_negative_string : its_too_large_string));
43173   return(make_integer(sc, byte_vector(v, ind)));
43174 }
43175 
43176 static s7_pointer g_bv_ref_3(s7_scheme *sc, s7_pointer args)
43177 {
43178   s7_pointer iv, index;
43179   s7_int ind1, ind2;
43180   iv = car(args);
43181   if (!is_byte_vector(iv))
43182     return(method_or_bust(sc, iv, sc->byte_vector_ref_symbol, args, T_BYTE_VECTOR, 1));
43183   if (vector_rank(iv) != 2)
43184     return(univect_ref(sc, args, sc->byte_vector_ref_symbol, T_BYTE_VECTOR));
43185   index = cadr(args);
43186   if (!s7_is_integer(index))
43187     return(method_or_bust(sc, index, sc->byte_vector_ref_symbol, args, T_INTEGER, 2));
43188   ind1 = s7_integer_checked(sc, index);
43189   if ((ind1 < 0) || (ind1 >= vector_dimension(iv, 0)))
43190     return(simple_out_of_range(sc, sc->byte_vector_ref_symbol, index, (ind1 < 0) ? its_negative_string : its_too_large_string));
43191   index = caddr(args);
43192   if (!s7_is_integer(index))
43193     return(method_or_bust(sc, index, sc->byte_vector_ref_symbol, args, T_INTEGER, 3));
43194   ind2 = s7_integer_checked(sc, index);
43195   if ((ind2 < 0) || (ind2 >= vector_dimension(iv, 1)))
43196     return(simple_out_of_range(sc, sc->byte_vector_ref_symbol, index, (ind2 < 0) ? its_negative_string : its_too_large_string));
43197   ind1 = ind1 * vector_offset(iv, 0) + ind2;
43198   return(make_integer(sc, byte_vector(iv, ind1)));
43199 }
43200 
43201 static s7_pointer byte_vector_ref_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
43202 {
43203   return((args == 2) ? sc->bv_ref_2 : ((args == 3) ? sc->bv_ref_3 : f));
43204 }
43205 
43206 
43207 /* -------------------------------- byte-vector-set -------------------------------- */
43208 static s7_pointer g_byte_vector_set(s7_scheme *sc, s7_pointer args)
43209 {
43210   #define H_byte_vector_set "(byte-vector-set! vect index byte) sets the index-th element of the byte-vector vect to the integer byte"
43211   #define Q_byte_vector_set s7_make_circular_signature(sc, 2, 3, sc->is_byte_symbol, sc->is_byte_vector_symbol, sc->is_integer_symbol)
43212   return(univect_set(sc, args, sc->byte_vector_set_symbol, T_BYTE_VECTOR));
43213 }
43214 
43215 static s7_int byte_vector_set_i_7pii(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_int i2)
43216 {
43217   if (!is_byte_vector(p1))
43218     simple_wrong_type_argument_with_type(sc, sc->byte_vector_set_symbol, p1, a_byte_vector_string);
43219   if ((i2 < 0) || (i2 > 255))
43220     simple_wrong_type_argument_with_type(sc, sc->byte_vector_set_symbol, wrap_integer1(sc, i2), an_unsigned_byte_string);
43221   if ((i1 >= 0) && (i1 < byte_vector_length(p1)))
43222     byte_vector(p1, i1) = (uint8_t)i2;
43223   else simple_out_of_range(sc, sc->byte_vector_set_symbol, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
43224   return(i2);
43225 }
43226 
43227 static s7_int byte_vector_set_unchecked(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_int i2) {byte_vector(p1, i1) = (uint8_t)i2; return(i2);}
43228 static s7_pointer byte_vector_set_unchecked_p(s7_scheme *sc, s7_pointer p1, s7_int i1, s7_pointer p2) {byte_vector(p1, i1) = (uint8_t)s7_integer_checked(sc, p2); return(p2);}
43229 
43230 static s7_int byte_vector_set_i_7piii(s7_scheme *sc, s7_pointer v, s7_int i1, s7_int i2, s7_int i3)
43231 {
43232   if ((i3 < 0) || (i3 > 255))
43233     simple_wrong_type_argument_with_type(sc, sc->byte_vector_set_symbol, wrap_integer1(sc, i3), an_unsigned_byte_string);
43234   if ((i1 >= 0) && (i1 < vector_dimension(v, 0)))
43235     {
43236       if ((i2 >= 0) && (i2 < vector_dimension(v, 1)))
43237 	{
43238 	  byte_vector(v, i2 + (i1 * vector_offset(v, 0))) = i3;
43239 	  return(i3);
43240 	}
43241       out_of_range(sc, sc->int_vector_set_symbol, int_three, wrap_integer1(sc, i2), (i2 < 0) ? its_negative_string : its_too_large_string);
43242     }
43243   out_of_range(sc, sc->int_vector_set_symbol, int_two, wrap_integer1(sc, i1), (i1 < 0) ? its_negative_string : its_too_large_string);
43244   return(0);
43245 }
43246 
43247 static s7_pointer g_bv_set_3(s7_scheme *sc, s7_pointer args)
43248 {
43249   s7_pointer v, index, value;
43250   s7_int ind, uval;
43251   v = car(args);
43252   if (!is_byte_vector(v))
43253     return(method_or_bust(sc, v, sc->byte_vector_set_symbol, args, T_BYTE_VECTOR, 1));
43254   if (vector_rank(v) != 1)
43255     return(univect_set(sc, args, sc->byte_vector_set_symbol, T_BYTE_VECTOR));
43256   index = cadr(args);
43257   if (!s7_is_integer(index))
43258     return(method_or_bust(sc, index, sc->byte_vector_set_symbol, args, T_INTEGER, 2));
43259   ind = s7_integer_checked(sc, index);
43260   if ((ind < 0) || (ind >= vector_length(v)))
43261     return(simple_out_of_range(sc, sc->byte_vector_set_symbol, index, (ind < 0) ? its_negative_string : its_too_large_string));
43262   value = caddr(args);
43263   if (!s7_is_integer(value))
43264     return(method_or_bust(sc, value, sc->byte_vector_set_symbol, args, T_INTEGER, 3));
43265   uval = s7_integer_checked(sc, value);
43266   if ((uval < 0) || (uval > 255))
43267     simple_wrong_type_argument_with_type(sc, sc->byte_vector_set_symbol, value, an_unsigned_byte_string);
43268   if (is_immutable_vector(v))
43269     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->byte_vector_set_symbol, v)));
43270   byte_vector(v, ind) = (uint8_t)uval;
43271   return(value);
43272 }
43273 
43274 static s7_pointer byte_vector_set_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
43275 {
43276   return((args == 3) ? sc->bv_set_3 : f);
43277 }
43278 
43279 
43280 /* -------------------------------------------------------------------------------- */
43281 static bool c_function_is_ok(s7_scheme *sc, s7_pointer x)
43282 {
43283   /* macro version of this is much slower! Since this is almost never false,
43284    *   I tried __builtin_expect throughout eval below.  The result was not faster.
43285    */
43286   s7_pointer p;
43287   p = lookup_global(sc, car(x)); /* uses global_slot if is_global(car(x)), else lookup_checked */
43288   /* this is nearly always global and p == opt1_cfunc(x)
43289    * p can be null if we evaluate some code, optimizing it, then eval it again in a context
43290    *   where the incoming p was undefined(!) -- explicit use of eval and so on.
43291    */
43292   if ((p == opt1_cfunc(x)) ||
43293       ((is_any_c_function(p)) &&
43294        (c_function_class(p) == c_function_class(opt1_cfunc(x)))))
43295     return(true);
43296   sc->last_function = p;
43297   return(false);
43298 }
43299 
43300 static bool cl_function_is_ok(s7_scheme *sc, s7_pointer x)
43301 {
43302   sc->last_function = lookup_global(sc, car(x));
43303   return(sc->last_function == opt1_cfunc(x));
43304 }
43305 
43306 static bool arglist_has_rest(s7_scheme *sc, s7_pointer args)
43307 {
43308   s7_pointer p;
43309   for (p = args; is_pair(p); p = cdr(p))
43310     if (car(p) == sc->key_rest_symbol)
43311       return(true);
43312   return(!is_null(p));
43313 }
43314 
43315 static bool bool_optimize(s7_scheme *sc, s7_pointer expr);
43316 static bool bool_optimize_nw(s7_scheme *sc, s7_pointer expr);
43317 static bool cell_optimize(s7_scheme *sc, s7_pointer expr);
43318 
43319 static void pc_fallback(s7_scheme *sc, int32_t new_pc) {sc->pc = new_pc;}
43320 
43321 
43322 /* -------------------------------- sort! -------------------------------- */
43323 
43324 static int32_t dbl_less(const void *f1, const void *f2)
43325 {
43326   if ((*((s7_double *)f1)) < (*((s7_double *)f2))) return(-1);
43327   return(((*((s7_double *)f1)) > (*((s7_double *)f2))) ? 1 : 0);
43328 }
43329 
43330 static int32_t int_less(const void *f1, const void *f2)
43331 {
43332   if ((*((s7_int *)f1)) < (*((s7_int *)f2))) return(-1);
43333   return(((*((s7_int *)f1)) > (*((s7_int *)f2))) ? 1 : 0);
43334 }
43335 
43336 static int32_t dbl_greater(const void *f1, const void *f2) {return(-dbl_less(f1, f2));}
43337 static int32_t int_greater(const void *f1, const void *f2) {return(-int_less(f1, f2));}
43338 
43339 static int32_t byte_less(const void *f1, const void *f2)
43340 {
43341   if ((*((uint8_t *)f1)) < (*((uint8_t *)f2))) return(-1);
43342   return(((*((uint8_t *)f1)) > (*((uint8_t *)f2))) ? 1 : 0);
43343 }
43344 
43345 static int32_t byte_greater(const void *f1, const void *f2) {return(-byte_less(f1, f2));}
43346 
43347 static int32_t dbl_less_2(const void *f1, const void *f2)
43348 {
43349   s7_pointer p1, p2;
43350   p1 = (*((s7_pointer *)f1));
43351   p2 = (*((s7_pointer *)f2));
43352   if (real(p1) < real(p2)) return(-1);
43353   return((real(p1) > real(p2)) ? 1 : 0);
43354 }
43355 
43356 static int32_t int_less_2(const void *f1, const void *f2)
43357 {
43358   s7_pointer p1, p2;
43359   p1 = (*((s7_pointer *)f1));
43360   p2 = (*((s7_pointer *)f2));
43361   if (integer(p1) < integer(p2)) return(-1);
43362   return((integer(p1) > integer(p2)) ? 1 : 0);
43363 }
43364 
43365 static int32_t dbl_greater_2(const void *f1, const void *f2) {return(-dbl_less_2(f1, f2));}
43366 static int32_t int_greater_2(const void *f1, const void *f2) {return(-int_less_2(f1, f2));}
43367 
43368 static int32_t str_less_2(const void *f1, const void *f2)
43369 {
43370   s7_pointer p1, p2;
43371   p1 = (*((s7_pointer *)f1));
43372   p2 = (*((s7_pointer *)f2));
43373   return(scheme_strcmp(p1, p2));
43374 }
43375 
43376 static int32_t str_greater_2(const void *f1, const void *f2) {return(-str_less_2(f1, f2));}
43377 
43378 static int32_t chr_less_2(const void *f1, const void *f2)
43379 {
43380   s7_pointer p1, p2;
43381   p1 = (*((s7_pointer *)f1));
43382   p2 = (*((s7_pointer *)f2));
43383   if (character(p1) < character(p2)) return(-1);
43384   return((character(p1) > character(p2)) ? 1 : 0);
43385 }
43386 
43387 static int32_t chr_greater_2(const void *f1, const void *f2) {return(-chr_less_2(f1, f2));}
43388 
43389 #if MS_WINDOWS || defined(__APPLE__) || defined(__FreeBSD__)
43390 struct sort_r_data /* from stackoverflow */
43391 {
43392   void *arg;
43393   int (*compar)(const void *a1, const void *a2, void *aarg);
43394 };
43395 
43396 static int sort_r_arg_swap(void *s, const void *aa, const void *bb)
43397 {
43398   struct sort_r_data *ss = (struct sort_r_data*)s;
43399   return (ss->compar)(aa, bb, ss->arg);
43400 }
43401 #endif
43402 
43403 /* qsort_r in Linux requires _GNU_SOURCE and is different from q_sort_r in FreeBSD, neither matches qsort_s in Windows
43404  *  this code tested only in Linux and the mac -- my virtualbox freebsd died, netbsd and openbsd run using fallback code.
43405  */
43406 static void local_qsort_r(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *arg)
43407 {
43408 #if (defined(__linux__)) && (defined(__GLIBC__)) /* __GLIBC__ because musl does not have qsort_r and has no way to detect it */
43409   qsort_r(base, nmemb, size, compar, arg);
43410 #else
43411 #if defined(__APPLE__) || defined(__FreeBSD__) /* not in OpenBSD or NetBSD as far as I can tell */
43412   struct sort_r_data tmp = {arg, compar};
43413   qsort_r(base, nmemb, size, &tmp, &sort_r_arg_swap);
43414 #else
43415 #if MS_WINDOWS
43416   struct sort_r_data tmp = {arg, compar};
43417   qsort_s(base, nmemb, size, sort_r_arg_swap, &tmp);
43418 #else
43419     /* from the Net somewhere, by "Pete", about 25 times slower than libc's qsort_r in this context */
43420   if (nmemb > 1)
43421     {
43422       uint8_t *array, *i, *j, *k, *after;
43423       size_t h, t;
43424       array = (uint8_t *)base;
43425       after = (uint8_t *)(nmemb * size + array);
43426       nmemb /= 4;
43427       h = nmemb + 1;
43428       for (t = 1; nmemb != 0; nmemb /= 4)
43429 	t *= 2;
43430       do {
43431 	size_t bytes;
43432 	bytes = h * size;
43433 	i = bytes + array;
43434 	do {
43435 	  j = i - bytes;
43436 	  if (compar(j, i, arg) > 0)
43437 	    {
43438 	      k = i;
43439 	      do {
43440 		uint8_t *end, *p1, *p2;
43441 		p1  = j;
43442 		p2  = k;
43443 		end = p2 + size;
43444 		do {
43445 		  uint8_t swap;
43446 		  swap  = *p1;
43447 		  *p1++ = *p2;
43448 		  *p2++ = swap;
43449 		} while (p2 != end);
43450 		if (bytes + array > j)
43451 		  break;
43452 		k = j;
43453 		j -= bytes;
43454 	      } while (compar(j, k, arg) > 0);
43455 	    }
43456 	  i += size;
43457 	} while (i != after);
43458 	t /= 2;
43459 	h = t * t - t * 3 / 2 + 1;
43460       } while (t != 0);
43461     }
43462 #endif
43463 #endif
43464 #endif
43465 }
43466 
43467 static int32_t vector_sort(const void *v1, const void *v2, void *arg)
43468 {
43469   s7_scheme *sc = (s7_scheme *)arg;
43470   return(((*(sc->sort_f))(sc, (*(s7_pointer *)v1), (*(s7_pointer *)v2))) ? -1 : 1);
43471 }
43472 
43473 static int32_t vector_sort_lt(const void *v1, const void *v2, void *arg) /* for qsort_r */
43474 {
43475   s7_pointer s1, s2;
43476   s1 = (*(s7_pointer *)v1);
43477   s2 = (*(s7_pointer *)v2);
43478   if ((is_t_integer(s1)) && (is_t_integer(s2)))
43479     return((integer(s1) < integer(s2)) ? -1 : 1);
43480   return((lt_b_7pp((s7_scheme *)arg, s1, s2)) ? -1 : 1);
43481 }
43482 
43483 static int32_t vector_car_sort(const void *v1, const void *v2, void *arg)
43484 {
43485   s7_scheme *sc = (s7_scheme *)arg;
43486   s7_pointer a, b;
43487   a = (*(s7_pointer *)v1);
43488   b = (*(s7_pointer *)v2);
43489   a = (is_pair(a)) ? car(a) : g_car(sc, set_plist_1(sc, a));
43490   b = (is_pair(b)) ? car(b) : g_car(sc, set_plist_1(sc, b));
43491   return(((*(sc->sort_f))(sc, a, b)) ? -1 : 1);
43492 }
43493 
43494 static int32_t vector_cdr_sort(const void *v1, const void *v2, void *arg)
43495 {
43496   s7_scheme *sc = (s7_scheme *)arg;
43497   s7_pointer a, b;
43498   a = (*(s7_pointer *)v1);
43499   b = (*(s7_pointer *)v2);
43500   a = (is_pair(a)) ? cdr(a) : g_cdr(sc, set_plist_1(sc, a));
43501   b = (is_pair(b)) ? cdr(b) : g_cdr(sc, set_plist_1(sc, b));
43502   return(((*(sc->sort_f))(sc, a, b)) ? -1 : 1);
43503 }
43504 
43505 static int32_t opt_bool_sort(const void *v1, const void *v2, void *arg)
43506 {
43507   s7_scheme *sc = (s7_scheme *)arg;
43508   slot_set_value(sc->sort_v1, (*(s7_pointer *)v1)); /* first slot in curlet */
43509   slot_set_value(sc->sort_v2, (*(s7_pointer *)v2)); /* second slot in curlet */
43510   return((sc->sort_fb(sc->sort_o)) ? -1 : 1);
43511 }
43512 
43513 static int32_t opt_bool_sort_0(const void *v1, const void *v2, void *arg)
43514 {
43515   s7_scheme *sc = (s7_scheme *)arg;
43516   slot_set_value(sc->sort_v1, (*(s7_pointer *)v1)); /* first slot in curlet */
43517   slot_set_value(sc->sort_v2, (*(s7_pointer *)v2)); /* second slot in curlet */
43518   return((sc->sort_fb(sc->sort_o)) ? -1 : 1);
43519 }
43520 
43521 static int32_t opt_bool_sort_p(const void *v1, const void *v2, void *arg)
43522 {
43523   s7_scheme *sc = (s7_scheme *)arg;
43524   slot_set_value(sc->sort_v1, (*(s7_pointer *)v1));
43525   slot_set_value(sc->sort_v2, (*(s7_pointer *)v2));
43526   return((sc->opts[0]->v[O_WRAP].fp(sc->opts[0]) == sc->F) ? 1 : -1);
43527 }
43528 
43529 #define SORT_O1 1
43530 #define begin_bool_sort_bp(End_Expr)			\
43531   do {							\
43532     s7_scheme *sc = (s7_scheme *)arg;			\
43533     s7_int i;						\
43534     opt_info *top, *o;					\
43535     slot_set_value(sc->sort_v1, (*(s7_pointer *)v1));	\
43536     slot_set_value(sc->sort_v2, (*(s7_pointer *)v2));	\
43537     top = sc->opts[0];					\
43538     for (i = 0; i < sc->sort_body_len - 1; i++)		\
43539       {							\
43540 	o = top->v[SORT_O1 + i].o1;			\
43541 	o->v[0].fp(o);					\
43542       }							\
43543     o = top->v[SORT_O1 + i].o1;				\
43544     return(End_Expr);					\
43545   } while (0)
43546 
43547 static int32_t opt_begin_bool_sort_b(const void *v1, const void *v2, void *arg) {begin_bool_sort_bp((o->v[0].fb(o)) ? -1 : 1);}
43548 static int32_t opt_begin_bool_sort_p(const void *v1, const void *v2, void *arg) {begin_bool_sort_bp((o->v[0].fp(o) != sc->F) ? -1 : 1);}
43549 
43550 static int32_t opt_begin_bool_sort_b2(const void *v1, const void *v2, void *arg)
43551 {
43552   s7_scheme *sc = (s7_scheme *)arg;
43553   opt_info *top, *o;
43554   slot_set_value(sc->sort_v1, (*(s7_pointer *)v1));
43555   slot_set_value(sc->sort_v2, (*(s7_pointer *)v2));
43556   top = sc->opts[0];
43557   o = top->v[SORT_O1].o1;
43558   o->v[0].fp(o);
43559   o = top->v[SORT_O1 + 1].o1;
43560   return((o->v[0].fb(o)) ? -1 : 1);
43561 }
43562 
43563 static int32_t closure_sort(const void *v1, const void *v2, void *arg)
43564 {
43565   s7_scheme *sc = (s7_scheme *)arg;
43566   slot_set_value(sc->sort_v1, (*(s7_pointer *)v1));
43567   slot_set_value(sc->sort_v2, (*(s7_pointer *)v2));
43568   push_stack(sc, OP_EVAL_DONE, sc->sort_body, sc->code);
43569   sc->code = sc->sort_body; /* this should be ok because we checked in advance that it is a safe closure (no sort! for example) */
43570   eval(sc, sc->sort_op);
43571   return((sc->value != sc->F) ? -1 : 1);
43572 }
43573 
43574 static int32_t closure_sort_begin(const void *v1, const void *v2, void *arg)
43575 {
43576   s7_scheme *sc = (s7_scheme *)arg;
43577   slot_set_value(sc->sort_v1, (*(s7_pointer *)v1));
43578   slot_set_value(sc->sort_v2, (*(s7_pointer *)v2));
43579   push_stack(sc, OP_EVAL_DONE, sc->sort_body, sc->code);
43580   push_stack_no_args(sc, OP_BEGIN_NO_HOOK, T_Pair(sc->sort_begin));
43581   sc->code = sc->sort_body;
43582   eval(sc, sc->sort_op);
43583   return((sc->value != sc->F) ? -1 : 1);
43584 }
43585 
43586 static s7_b_7pp_t s7_b_7pp_function(s7_pointer f);
43587 #if S7_DEBUGGING || OPT_SC_DEBUGGING
43588 #define alloc_opo(Sc) alloc_opo_1(Sc, __func__, __LINE__)
43589 static opt_info *alloc_opo_1(s7_scheme *sc, const char *func, int line);
43590 #else
43591 static opt_info *alloc_opo(s7_scheme *sc);
43592 #endif
43593 
43594 static s7_pointer g_sort(s7_scheme *sc, s7_pointer args)
43595 {
43596   #define H_sort "(sort! sequence less?) sorts a sequence using the function 'less?' to compare elements."
43597   #define Q_sort s7_make_signature(sc, 3, sc->is_sequence_symbol, sc->is_sequence_symbol, sc->is_procedure_symbol)
43598 
43599   s7_pointer data, lessp, lx;
43600   s7_int len = 0, n, k;
43601   int32_t (*sort_func)(const void *v1, const void *v2, void *arg);
43602   s7_pointer *elements;
43603 
43604   /* both the intermediate vector (if any) and the current args pointer need GC protection,
43605    *   but it is a real bother to unprotect args at every return statement, so I'll use temp3
43606    */
43607   sc->temp3 = args; /* this is needed but maybe insufficient... if sort is semisafe, we should protect the args, not the list: use OP_GC_PROTECT? */
43608   data = car(args);
43609   if (is_null(data))
43610     {
43611       /* (apply sort! () #f) should be an error I think */
43612       lessp = cadr(args);
43613       if (type(lessp) < T_CONTINUATION)
43614 	return(method_or_bust_with_type(sc, lessp, sc->sort_symbol, args, a_procedure_string, 2));
43615       if (!s7_is_aritable(sc, lessp, 2))
43616 	return(wrong_type_argument_with_type(sc, sc->sort_symbol, 2, lessp, an_eq_func_string));
43617       return(sc->nil);
43618     }
43619 
43620   if (is_immutable(data))
43621     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->sort_symbol, data)));
43622   if (!is_sequence(data))
43623     return(wrong_type_argument_with_type(sc, sc->sort_symbol, 1, data, a_sequence_string));
43624 
43625   lessp = cadr(args);
43626   if (type(lessp) <= T_GOTO)
43627     return(wrong_type_argument_with_type(sc, sc->sort_symbol, 2, lessp, a_normal_procedure_string));
43628   if (!s7_is_aritable(sc, lessp, 2))
43629     return(wrong_type_argument_with_type(sc, sc->sort_symbol, 2, lessp, an_eq_func_string));
43630 
43631   sort_func = NULL;
43632   sc->sort_f = NULL;
43633 
43634   if ((is_safe_procedure(lessp)) &&     /* (sort! a <) */
43635       (is_c_function(lessp)))
43636     {
43637       s7_pointer sig;
43638       sig = c_function_signature(lessp);
43639       if ((sig) &&
43640 	  (is_pair(sig)) &&
43641 	  (car(sig) != sc->is_boolean_symbol))
43642 	return(wrong_type_argument_with_type(sc, sc->sort_symbol, 2, lessp,
43643 					     wrap_string(sc, "sort! function should return a boolean", 38)));
43644       sc->sort_f = s7_b_7pp_function(lessp);
43645       if (sc->sort_f) sort_func = (sc->sort_f == lt_b_7pp) ? vector_sort_lt : vector_sort;
43646     }
43647   else
43648     {
43649       if (is_closure(lessp))
43650 	{
43651 	  s7_pointer expr, largs;
43652 	  expr = car(closure_body(lessp));
43653 	  largs = closure_args(lessp);
43654 
43655 	  if ((is_pair(largs)) &&       /* closure args not a symbol, etc */
43656 	      (!arglist_has_rest(sc, largs)))
43657 	    {
43658 	      if (is_null(cdr(closure_body(lessp))))
43659 		{
43660 		  if ((is_optimized(expr)) &&
43661 		      (is_safe_c_op(optimize_op(expr))) &&
43662 		      /* since (sort seq (lambda (a b) ...)) can't return a "safe closure" (the hop bit is off in
43663 		       *   optimize in this case, for some arcane reason), the optimized expression won't be hop_safe,
43664 		       *   but that is irrelevant at this point -- if c_function_is_ok, we're good to go.
43665 		       */
43666 		      ((op_has_hop(expr)) ||
43667 		       ((is_global(car(expr))) &&            /* (sort! x (lambda (car y) (car x)...))! */
43668 			(c_function_is_ok(sc, expr)))))
43669 		    {
43670 		      int32_t orig_data;
43671 		      s7_pointer lp;
43672 
43673 		      orig_data = optimize_op(expr);
43674 		      set_optimize_op(expr, optimize_op(expr) | 1);
43675 		      if ((optimize_op(expr) == HOP_SAFE_C_SS) &&
43676 			  (car(largs) == cadr(expr)) &&
43677 			  (cadr(largs) == caddr(expr)))
43678 			{
43679 			  lp = lookup(sc, car(expr));
43680 			  sc->sort_f = s7_b_7pp_function(lp);
43681 			  if (sc->sort_f)
43682 			    {
43683 			      sort_func = (sc->sort_f == lt_b_7pp) ? vector_sort_lt : vector_sort;
43684 			      lessp = lp;
43685 			    }}
43686 		      else
43687 			{
43688 			  if ((optimize_op(expr) == HOP_SAFE_C_opSq_opSq) &&
43689 			      ((caadr(expr) == sc->car_symbol) || (caadr(expr) == sc->cdr_symbol)) &&
43690 			      (caadr(expr) == caaddr(expr)) &&
43691 			      (car(largs) == cadadr(expr)) &&
43692 			      (cadr(largs) == cadaddr(expr)))
43693 			    {
43694 			      lp = lookup(sc, car(expr));
43695 			      sc->sort_f = s7_b_7pp_function(lp);
43696 			      if (sc->sort_f)
43697 				{
43698 				  sort_func = ((caadr(expr) == sc->car_symbol) ? vector_car_sort : vector_cdr_sort);
43699 				  lessp = lp;
43700 				}}}
43701 		      set_optimize_op(expr, orig_data);
43702 		    }}
43703 
43704 	      if (!sort_func)
43705 		{
43706 		  s7_pointer init_val, old_e;
43707 		  if (is_float_vector(data))
43708 		    init_val = real_zero;
43709 		  else init_val = ((is_int_vector(data)) || (is_byte_vector(data))) ? int_zero : sc->F;
43710 		  old_e = sc->curlet;
43711 		  sc->curlet = make_let_with_two_slots(sc, closure_let(lessp), car(largs), init_val, cadr(largs), init_val);
43712 		  sc->sort_body = expr;
43713 		  sc->sort_v1 = let_slots(sc->curlet);
43714 		  sc->sort_v2 = next_slot(let_slots(sc->curlet));
43715 		  if (is_null(cdr(closure_body(lessp))))
43716 		    {
43717 		      if (!no_bool_opt(closure_body(lessp)))
43718 			{
43719 			  s7_function sf1;
43720 			  sf1 = s7_bool_optimize(sc, closure_body(lessp));
43721 			  if (sf1 == opt_bool_any)
43722 			    {
43723 			      if (sc->opts[0]->v[0].fb == p_to_b)
43724 				sort_func = opt_bool_sort_p;
43725 			      else
43726 				{
43727 				  sc->sort_o = sc->opts[0];
43728 				  sc->sort_fb = sc->sort_o->v[0].fb;
43729 				  sort_func = (sc->pc == 1) ? opt_bool_sort_0 : opt_bool_sort;
43730 				}}
43731 			  else set_no_bool_opt(closure_body(lessp));
43732 			}}
43733 		  else
43734 		    {
43735 		      sc->sort_body_len = s7_list_length(sc, closure_body(lessp));
43736 		      if (sc->sort_body_len < (NUM_VUNIONS - SORT_O1))
43737 			{
43738 			  s7_pointer p;
43739 			  int32_t ctr;
43740 			  opt_info *top;
43741 			  sc->pc = 0;
43742 			  top = alloc_opo(sc);
43743 			  for (ctr = SORT_O1, p = closure_body(lessp); is_pair(cdr(p)); ctr++, p = cdr(p))
43744 			    {
43745 			      top->v[V_ind(ctr)].o1 = sc->opts[sc->pc];
43746 			      if (!cell_optimize(sc, p))
43747 				break;
43748 			    }
43749 			  if (is_null(cdr(p)))
43750 			    {
43751 			      int32_t start;
43752 			      start = sc->pc;
43753 			      top->v[V_ind(ctr)].o1 = sc->opts[start];
43754 			      if (bool_optimize_nw(sc, p))
43755 				sort_func = (sc->sort_body_len == 2) ? opt_begin_bool_sort_b2 : opt_begin_bool_sort_b;
43756 			      else
43757 				{
43758 				  pc_fallback(sc, start);
43759 				  if (cell_optimize(sc, p))
43760 				    sort_func = opt_begin_bool_sort_p;
43761 				}}}}
43762 		  if (!sort_func)
43763 		    sc->curlet = old_e;
43764 		}
43765 
43766 	      if ((!sort_func) &&
43767 		  (is_safe_closure(lessp))) /* no embedded sort! or call/cc, etc */
43768 		{
43769 		  sc->curlet = make_let_with_two_slots(sc, closure_let(lessp), car(largs), sc->F, cadr(largs), sc->F);
43770 		  sc->sort_body = car(closure_body(lessp));
43771 		  sc->sort_begin = cdr(closure_body(lessp));
43772 		  sort_func = (is_null(sc->sort_begin)) ? closure_sort : closure_sort_begin;
43773 		  sc->sort_op = (is_syntactic_pair(sc->sort_body)) ? (opcode_t)optimize_op(sc->sort_body) : (opcode_t)OP_EVAL;
43774 		  sc->sort_v1 = let_slots(sc->curlet);
43775 		  sc->sort_v2 = next_slot(let_slots(sc->curlet));
43776 		}}}}
43777 
43778   switch (type(data))
43779     {
43780     case T_PAIR:
43781       len = s7_list_length(sc, data);            /* 0 here == infinite */
43782       if (len <= 0)
43783 	return(s7_error(sc, sc->wrong_type_arg_symbol,
43784 			set_elist_2(sc, wrap_string(sc, "sort! argument 1 should be a proper list: ~S", 44), data)));
43785       if (len < 2)
43786 	return(data);
43787 
43788       if (sort_func)
43789 	{
43790 	  s7_int i;
43791 	  s7_pointer vec, p;
43792 
43793 	  vec = g_vector(sc, data);
43794 	  push_stack_no_let_no_code(sc, OP_GC_PROTECT, vec);
43795 	  elements = s7_vector_elements(vec);
43796 
43797 	  sc->v = vec;
43798 	  local_qsort_r((void *)elements, len, sizeof(s7_pointer), sort_func, (void *)sc);
43799 	  for (p = data, i = 0; i < len; i++, p = cdr(p))
43800 	    {
43801 	      if (is_immutable(p))
43802 		return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->sort_symbol, data)));
43803 	      set_car(p, elements[i]);
43804 	    }
43805 	  sc->v = sc->nil;
43806 	  unstack(sc); /* not pop_stack! */
43807 	  return(data);
43808 	}
43809 
43810       push_stack(sc, OP_SORT_PAIR_END, cons(sc, data, lessp), sc->code); /* save and gc protect the original list and func */
43811       set_car(args, g_vector(sc, data));
43812       break;
43813 
43814     case T_BYTE_VECTOR:
43815     case T_STRING:
43816       {
43817 	s7_int i;
43818 	s7_pointer vec;
43819 	uint8_t *chrs;
43820 
43821 	if (is_string(data))
43822 	  {
43823 	    len = string_length(data);
43824 	    chrs = (uint8_t *)string_value(data);
43825 	  }
43826 	else
43827 	  {
43828 	    len = byte_vector_length(data);
43829 	    chrs = byte_vector_bytes(data);
43830 	  }
43831 	if (len < 2) return(data);
43832 
43833 	if (is_c_function(lessp))
43834 	  {
43835 	    if (((is_string(data)) && (sc->sort_f == char_lt_b_7pp)) ||
43836 		((is_byte_vector(data)) && (sc->sort_f == lt_b_7pp)))
43837 	      {
43838 		qsort((void *)chrs, len, sizeof(uint8_t), byte_less);
43839 		return(data);
43840 	      }
43841 	    if (((is_string(data)) && (sc->sort_f == char_gt_b_7pp)) ||
43842 		((is_byte_vector(data)) && (sc->sort_f == gt_b_7pp)))
43843 	      {
43844 		qsort((void *)chrs, len, sizeof(uint8_t), byte_greater);
43845 		return(data);
43846 	      }}
43847 	vec = make_simple_vector(sc, len);
43848 	push_stack_no_let_no_code(sc, OP_GC_PROTECT, vec);
43849 	elements = s7_vector_elements(vec);
43850 
43851 	if (is_byte_vector(data))
43852 	  for (i = 0; i < len; i++)
43853 	    elements[i] = small_int(chrs[i]);
43854 	else
43855 	  for (i = 0; i < len; i++)
43856 	    elements[i] = chars[chrs[i]];
43857 
43858 	if (sort_func)
43859 	  {
43860 	    sc->v = vec;
43861 	    local_qsort_r((void *)elements, len, sizeof(s7_pointer), sort_func, (void *)sc);
43862 
43863 	    if (is_byte_vector(data))
43864 	      for (i = 0; i < len; i++)
43865 		chrs[i] = (char)integer(elements[i]);
43866 	    else
43867 	      for (i = 0; i < len; i++)
43868 		chrs[i] = character(elements[i]);
43869 	    sc->v = sc->nil;
43870 	    unstack(sc); /* not pop_stack! */
43871 	    return(data);
43872 	  }
43873 
43874 	unstack(sc); /* not pop_stack! */
43875 	push_stack(sc, OP_SORT_STRING_END, cons(sc, data, lessp), sc->code);
43876 	set_car(args, vec);
43877       }
43878       break;
43879 
43880     case T_INT_VECTOR:
43881     case T_FLOAT_VECTOR:
43882       {
43883 	s7_int i;
43884 	s7_pointer vec;
43885 
43886 	len = vector_length(data);
43887 	if (len < 2)
43888 	  return(data);
43889 	if (is_c_function(lessp))
43890 	  {
43891 	    if (sc->sort_f == lt_b_7pp)
43892 	      {
43893 		if (is_float_vector(data))
43894 		  qsort((void *)vector_elements(data), len, sizeof(s7_double), dbl_less);
43895 		else qsort((void *)vector_elements(data), len, sizeof(s7_int), int_less);
43896 		return(data);
43897 	      }
43898 	    if (sc->sort_f == gt_b_7pp)
43899 	      {
43900 		if (is_float_vector(data))
43901 		  qsort((void *)vector_elements(data), len, sizeof(s7_double), dbl_greater);
43902 		else qsort((void *)vector_elements(data), len, sizeof(s7_int), int_greater);
43903 		return(data);
43904 	      }}
43905 	/* currently we have to make the ordinary vector here even if not sf1
43906 	 *   because the sorter uses vector_element to access sort args (see SORT_DATA in eval).
43907 	 *   This is probably better than passing down getter/setter (fewer allocations).
43908 	 *   get/set macro in eval is SORT_DATA(k) then s7_vector_to_list if pair at start (sort_*_end)
43909 	 */
43910 	vec = make_vector_1(sc, len, FILLED, T_VECTOR);
43911 	/* we need this vector prefilled because make_real|integer below can cause a GC at any time during that loop,
43912 	 *   and the GC mark process expects the vector to have an s7_pointer at every element.
43913 	 */
43914 	add_vector(sc, vec);
43915 	push_stack_no_let_no_code(sc, OP_GC_PROTECT, vec);
43916 	elements = s7_vector_elements(vec);
43917 
43918 	if (is_float_vector(data))
43919 	  for (i = 0; i < len; i++)
43920 	    elements[i] = make_real(sc, float_vector(data, i));
43921 	else
43922 	  for (i = 0; i < len; i++)
43923 	    elements[i] = make_integer(sc, int_vector(data, i));
43924 
43925 	if (sort_func)
43926 	  {
43927 	    sc->v = vec;
43928 	    local_qsort_r((void *)elements, len, sizeof(s7_pointer), sort_func, (void *)sc);
43929 
43930 	    if (is_float_vector(data))
43931 	      for (i = 0; i < len; i++)
43932 		float_vector(data, i) = real(elements[i]);
43933 	    else
43934 	      for (i = 0; i < len; i++)
43935 		int_vector(data, i) = integer(elements[i]);
43936 
43937 	    sc->v = sc->nil;
43938 	    unstack(sc);
43939 	    return(data);
43940 	  }
43941 	unstack(sc);
43942 	set_car(args, vec);
43943 	push_stack(sc, OP_SORT_VECTOR_END, cons(sc, data, lessp), sc->code); /* save and gc protect the original homogeneous vector and func */
43944       }
43945       break;
43946 
43947     case T_VECTOR:
43948       len = vector_length(data);
43949       if (len < 2)
43950 	return(data);
43951       if (sort_func)
43952 	{
43953 	  int32_t typ;
43954 	  s7_pointer *els;
43955 	  els = s7_vector_elements(data);
43956 	  typ = type(els[0]);
43957 	  if ((typ == T_INTEGER) || (typ == T_REAL) || (typ == T_STRING) || (typ == T_CHARACTER))
43958 	    {
43959 	      s7_int i;
43960 	      for (i = 1; i < len; i++)
43961 		if (type(els[i]) != typ)
43962 		  {
43963 		    typ = T_FREE;
43964 		    break;
43965 		  }}
43966 	  if ((sc->sort_f == lt_b_7pp) || (sc->sort_f == gt_b_7pp))
43967 	    {
43968 	      if (typ == T_INTEGER)
43969 		{
43970 		  qsort((void *)els, len, sizeof(s7_pointer), ((sc->sort_f == lt_b_7pp) ? int_less_2 : int_greater_2));
43971 		  return(data);
43972 		}
43973 	      if (typ == T_REAL)
43974 		{
43975 		  qsort((void *)els, len, sizeof(s7_pointer), ((sc->sort_f == lt_b_7pp) ? dbl_less_2 : dbl_greater_2));
43976 		  return(data);
43977 		}}
43978 	  if ((typ == T_STRING) &&
43979 	      ((sc->sort_f == string_lt_b_7pp) || (sc->sort_f == string_gt_b_7pp)))
43980 	    {
43981 	      qsort((void *)els, len, sizeof(s7_pointer), ((sc->sort_f == string_lt_b_7pp) ? str_less_2 : str_greater_2));
43982 	      return(data);
43983 	    }
43984 	  if ((typ == T_CHARACTER) &&
43985 	      ((sc->sort_f == char_lt_b_7pp) || (sc->sort_f == char_gt_b_7pp)))
43986 	    {
43987 	      qsort((void *)els, len, sizeof(s7_pointer), ((sc->sort_f = char_lt_b_7pp) ? chr_less_2 : chr_greater_2));
43988 	      return(data);
43989 	    }
43990 	  local_qsort_r((void *)s7_vector_elements(data), len, sizeof(s7_pointer), sort_func, (void *)sc);
43991 	  return(data);
43992 	}
43993       break;
43994 
43995     default:
43996       return(method_or_bust_with_type(sc, data, sc->sort_symbol, args, a_sequence_string, 1));
43997     }
43998 
43999   n = len - 1;
44000   k = (n / 2) + 1;
44001 
44002   lx = s7_make_vector(sc, (sc->safety == NO_SAFETY) ? 4 : 6);
44003   sc->v = lx;
44004   vector_element(lx, 0) = make_mutable_integer(sc, n);
44005   vector_element(lx, 1) = make_mutable_integer(sc, k);
44006   vector_element(lx, 2) = make_mutable_integer(sc, 0);
44007   vector_element(lx, 3) = make_mutable_integer(sc, 0);
44008   if (sc->safety > NO_SAFETY)
44009     {
44010       vector_element(lx, 4) = make_mutable_integer(sc, 0);
44011       vector_element(lx, 5) = make_integer(sc, n * n);
44012     }
44013   push_stack(sc, OP_SORT, args, lx);
44014   sc->v = sc->nil;
44015 
44016   return(sc->F);
44017   /* if the comparison function waffles, sort! can hang: (sort! '(1 2 3) (lambda (a b) (= a b)))
44018    * set 'safety to 1 to add a check for this loop, but the "safe" procedures are direct, so unchecked.
44019    */
44020 }
44021 
44022 /* these are for the eval sort -- sort a vector, then if necessary put that data into the original sequence */
44023 static s7_pointer vector_into_list(s7_scheme *sc, s7_pointer vect, s7_pointer lst)
44024 {
44025   s7_pointer p;
44026   s7_pointer *elements;
44027   s7_int i, len;
44028 
44029   elements = s7_vector_elements(vect);
44030   len = vector_length(vect);
44031   for (i = 0, p = lst; i < len; i++, p = cdr(p))
44032     {
44033       if (is_immutable(p))
44034 	return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->sort_symbol, lst)));
44035       set_car(p, elements[i]);
44036     }
44037   return(lst);
44038 }
44039 
44040 static s7_pointer vector_into_fi_vector(s7_pointer source, s7_pointer dest)
44041 {
44042   s7_pointer *elements;
44043   s7_int i, len;
44044 
44045   elements = s7_vector_elements(source);
44046   len = vector_length(source);
44047 
44048   if (is_float_vector(dest))
44049     {
44050       s7_double *flts;
44051       flts = float_vector_floats(dest);
44052       for (i = 0; i < len; i++)
44053 	flts[i] = real(elements[i]);
44054     }
44055   else
44056     {
44057       s7_int *ints;
44058       ints = int_vector_ints(dest);
44059       for (i = 0; i < len; i++)
44060 	ints[i] = integer(elements[i]);
44061     }
44062   return(dest);
44063 }
44064 
44065 static s7_pointer vector_into_string(s7_pointer vect, s7_pointer dest)
44066 {
44067   s7_pointer *elements;
44068   s7_int i, len;
44069   uint8_t *str;
44070 
44071   elements = s7_vector_elements(vect);
44072   len = vector_length(vect);
44073 
44074   if (is_byte_vector(dest))
44075     {
44076       str = (uint8_t *)byte_vector_bytes(dest);
44077       for (i = 0; i < len; i++)
44078 	str[i] = (uint8_t)integer(elements[i]);
44079     }
44080   else
44081     {
44082       str = (uint8_t *)string_value(dest);
44083       for (i = 0; i < len; i++)
44084 	str[i] = character(elements[i]);
44085     }
44086   return(dest);
44087 }
44088 
44089 #define SORT_N integer(vector_element(sc->code, 0))
44090 #define SORT_K integer(vector_element(sc->code, 1))
44091 #define SORT_J integer(vector_element(sc->code, 2))
44092 #define SORT_K1 integer(vector_element(sc->code, 3))
44093 #define SORT_CALLS integer(vector_element(sc->code, 4))
44094 #define SORT_STOP integer(vector_element(sc->code, 5))
44095 #define SORT_DATA(K) vector_element(car(sc->args), K)
44096 #define SORT_LESSP cadr(sc->args)
44097 
44098 static s7_pointer op_heapsort(s7_scheme *sc)
44099 {
44100   s7_int n, j, k;
44101   s7_pointer lx;
44102   n = SORT_N;
44103   k = SORT_K1;
44104 
44105   if ((n == k) || (k > ((s7_int)(n / 2)))) /* k == n == 0 is the first case */
44106     return(sc->code);
44107 
44108   if (sc->safety > NO_SAFETY)
44109     {
44110       SORT_CALLS++;
44111       if (SORT_CALLS > SORT_STOP)
44112 	eval_error_any(sc, sc->out_of_range_symbol, "sort! is caught in an infinite loop, comparison: ~S", 51, SORT_LESSP);
44113     }
44114   j = 2 * k;
44115   SORT_J = j;
44116   if (j < n)
44117     {
44118       push_stack_direct(sc, OP_SORT1);
44119       lx = SORT_LESSP; /* cadr of sc->args */
44120       if (needs_copied_args(lx))
44121 	sc->args = list_2(sc, SORT_DATA(j), SORT_DATA(j + 1));
44122       else
44123 	{
44124 	  set_car(sc->t2_1, SORT_DATA(j));
44125 	  set_car(sc->t2_2, SORT_DATA(j + 1));
44126 	  sc->args = sc->t2_1;
44127 	}
44128       sc->code = lx;
44129       sc->value = sc->T; /* for eval */
44130     }
44131   else sc->value = sc->F;
44132   return(NULL);
44133 }
44134 
44135 static bool op_sort1(s7_scheme *sc)
44136 {
44137   s7_int j, k;
44138   s7_pointer lx;
44139   k = SORT_K1;
44140   j = SORT_J;
44141   if (is_true(sc, sc->value))
44142     {
44143       j = j + 1;
44144       SORT_J = j;
44145     }
44146   push_stack_direct(sc, OP_SORT2);
44147   lx = SORT_LESSP;
44148   if (needs_copied_args(lx))
44149     sc->args = list_2(sc, SORT_DATA(k), SORT_DATA(j));
44150   else
44151     {
44152       set_car(sc->t2_1, SORT_DATA(k));
44153       set_car(sc->t2_2, SORT_DATA(j));
44154       sc->args = sc->t2_1;
44155     }
44156   sc->code = lx;
44157   return(false);
44158 }
44159 
44160 static bool op_sort2(s7_scheme *sc)
44161 {
44162   s7_int j, k;
44163   k = SORT_K1;
44164   j = SORT_J;
44165   if (is_true(sc, sc->value))
44166     {
44167       s7_pointer lx;
44168       lx = SORT_DATA(j);
44169       SORT_DATA(j) = SORT_DATA(k);
44170       SORT_DATA(k) = lx;
44171     }
44172   else return(true);
44173   SORT_K1 = SORT_J;
44174   return(false);
44175 }
44176 
44177 static bool op_sort(s7_scheme *sc)
44178 {
44179   /* coming in sc->args is sort args (data less?), sc->code = #(n k 0 ...)
44180    * here we call the inner loop until k <= 0 [the local k! -- this is tricky because scheme passes args by value]
44181    */
44182   s7_int k;
44183   k = SORT_K;
44184   if (k > 0)
44185     {
44186       SORT_K = k - 1;
44187       SORT_K1 = k - 1;
44188       push_stack_direct(sc, OP_SORT);
44189       return(false);
44190     }
44191   return(true);
44192 }
44193 
44194 static bool op_sort3(s7_scheme *sc)
44195 {
44196   s7_int n;
44197   s7_pointer lx;
44198   n = SORT_N;
44199   if (n <= 0)
44200     {
44201       sc->value = car(sc->args);
44202       return(true);
44203     }
44204   lx = SORT_DATA(0);
44205   SORT_DATA(0) = SORT_DATA(n);
44206   SORT_DATA(n) = lx;
44207   SORT_N = n - 1;
44208   SORT_K1 = 0;
44209   push_stack_direct(sc, OP_SORT3);
44210   return(false);
44211 }
44212 
44213 
44214 /* -------- hash tables -------- */
44215 
44216 static void free_hash_table(s7_scheme *sc, s7_pointer table)
44217 {
44218   hash_entry_t **entries;
44219   entries = hash_table_elements(table);
44220 
44221   if (hash_table_entries(table) > 0)
44222     {
44223       s7_int i, len;
44224       len = hash_table_mask(table) + 1;
44225 
44226       for (i = 0; i < len; i++)
44227 	{
44228 	  hash_entry_t *p, *n;
44229 	  for (p = entries[i++]; p; p = n)
44230 	    {
44231 	      n = hash_entry_next(p);
44232 	      liberate_block(sc, p);
44233 	    }
44234 	  for (p = entries[i]; p; p = n)
44235 	    {
44236 	      n = hash_entry_next(p);
44237 	      liberate_block(sc, p);
44238 	    }}}
44239   liberate(sc, hash_table_block(table));
44240 }
44241 
44242 static hash_entry_t *make_hash_entry(s7_scheme *sc, s7_pointer key, s7_pointer value, s7_int raw_hash)
44243 {
44244   hash_entry_t *p;
44245   p = (hash_entry_t *)mallocate_block(sc);
44246   hash_entry_key(p) = key;
44247   hash_entry_set_value(p, value);
44248   hash_entry_set_raw_hash(p, raw_hash);
44249   return(p);
44250 }
44251 
44252 
44253 /* -------------------------------- hash-table? -------------------------------- */
44254 bool s7_is_hash_table(s7_pointer p) {return(is_hash_table(p));}
44255 
44256 static s7_pointer g_is_hash_table(s7_scheme *sc, s7_pointer args)
44257 {
44258   #define H_is_hash_table "(hash-table? obj) returns #t if obj is a hash-table"
44259   #define Q_is_hash_table sc->pl_bt
44260   check_boolean_method(sc, is_hash_table, sc->is_hash_table_symbol, args);
44261 }
44262 
44263 
44264 /* -------------------------------- hash-table-entries -------------------------------- */
44265 static s7_pointer g_hash_table_entries(s7_scheme *sc, s7_pointer args)
44266 {
44267   #define H_hash_table_entries "(hash-table-entries obj) returns the number of entries in the hash-table obj"
44268   #define Q_hash_table_entries s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_hash_table_symbol)
44269 
44270   if (!is_hash_table(car(args)))
44271     return(method_or_bust_one_arg(sc, car(args), sc->hash_table_entries_symbol, args, T_HASH_TABLE));
44272   return(make_integer(sc, hash_table_entries(car(args))));
44273 }
44274 
44275 static s7_int hash_table_entries_i_7p(s7_scheme *sc, s7_pointer p)
44276 {
44277   if (!is_hash_table(p))
44278     return(integer(method_or_bust_one_arg_p(sc, p, sc->hash_table_entries_symbol, T_HASH_TABLE)));
44279   return(hash_table_entries(p));
44280 }
44281 
44282 
44283 /* ---------------- hash map and equality tables ---------------- */
44284 /* built in hash loc tables for eq? eqv? equal? equivalent? = string=? string-ci=? char=? char-ci=? (default=equal?) */
44285 #define hash_loc(Sc, Table, Key) (*(hash_table_mapper(Table)[type(Key)]))(Sc, Table, Key)
44286 
44287 static hash_map_t eq_hash_map[NUM_TYPES];
44288 static hash_map_t string_eq_hash_map[NUM_TYPES];
44289 static hash_map_t char_eq_hash_map[NUM_TYPES];
44290 static hash_map_t closure_hash_map[NUM_TYPES];
44291 static hash_map_t equivalent_hash_map[NUM_TYPES];
44292 static hash_map_t c_function_hash_map[NUM_TYPES];
44293 #if (!WITH_PURE_S7)
44294 static hash_map_t string_ci_eq_hash_map[NUM_TYPES];
44295 static hash_map_t char_ci_eq_hash_map[NUM_TYPES];
44296 #endif
44297 /* also default_hash_map */
44298 
44299 
44300 /* ---------------- hash-code ---------------- */
44301 /* TODO: eqfunc handling which will require other dummy tables */
44302 
44303 static s7_pointer make_dummy_hash_table(s7_scheme *sc)
44304 {
44305   s7_pointer table;  /* make the absolute minimal hash-table that can support hash-code */
44306   table = (s7_pointer)Calloc(1, sizeof(s7_cell));
44307   set_type_bit(table, T_IMMUTABLE | T_HASH_TABLE | T_UNHEAP);
44308   hash_table_mapper(table) = default_hash_map;
44309   return(table);
44310 }
44311 
44312 s7_int s7_hash_code(s7_scheme *sc, s7_pointer obj, s7_pointer eqfunc)
44313 {
44314   return(default_hash_map[type(obj)](sc, sc->dummy_equal_hash_table, obj));
44315 }
44316 
44317 static s7_pointer g_hash_code(s7_scheme *sc, s7_pointer args)
44318 {
44319   #define H_hash_code "(hash-code obj (eqfunc)) returns an integer suitable for use as a hash code for obj."
44320   #define Q_hash_code s7_make_signature(sc, 3, sc->is_integer_symbol, sc->T, sc->T)
44321   s7_pointer obj;
44322   obj = car(args);
44323   return(make_integer(sc, default_hash_map[type(obj)](sc, sc->dummy_equal_hash_table, obj)));
44324 }
44325 
44326 
44327 static bool (*equals[NUM_TYPES])(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci);
44328 static bool (*equivalents[NUM_TYPES])(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci);
44329 
44330 static hash_entry_t *(*default_hash_checks[NUM_TYPES])(s7_scheme *sc, s7_pointer table, s7_pointer key);
44331 static hash_entry_t *(*equal_hash_checks[NUM_TYPES])(s7_scheme *sc, s7_pointer table, s7_pointer key);
44332 
44333 
44334 /* ---------------- hash empty ---------------- */
44335 static hash_entry_t *hash_empty(s7_scheme *sc, s7_pointer table, s7_pointer key)
44336 {
44337   return(sc->unentry);
44338 }
44339 
44340 /* ---------------- hash syntax ---------------- */
44341 static s7_int hash_map_syntax(s7_scheme *sc, s7_pointer table, s7_pointer key)  {return(pointer_map(syntax_symbol(key)));}
44342 
44343 static hash_entry_t *hash_equal_syntax(s7_scheme *sc, s7_pointer table, s7_pointer key)
44344 {
44345   hash_entry_t *x;
44346   s7_int loc;
44347   loc = hash_loc(sc, table, key) & hash_table_mask(table);
44348   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44349     if ((is_syntax(hash_entry_key(x))) &&
44350 	(syntax_symbol(hash_entry_key(x)) == syntax_symbol(key))) /* the opcodes might differ, but the symbols should not */
44351       return(x);
44352   return(sc->unentry);
44353 }
44354 
44355 /* ---------------- hash symbols ---------------- */
44356 static s7_int hash_map_symbol(s7_scheme *sc, s7_pointer table, s7_pointer key)  {return(pointer_map(key));}
44357 
44358 static hash_entry_t *hash_symbol(s7_scheme *sc, s7_pointer table, s7_pointer key)
44359 {
44360   hash_entry_t *x;
44361   for (x = hash_table_element(table, pointer_map(key) & hash_table_mask(table)); x; x = hash_entry_next(x))
44362     if (key == hash_entry_key(x))
44363       return(x);
44364   return(sc->unentry);
44365 }
44366 
44367 
44368 /* ---------------- hash numbers ---------------- */
44369 
44370 static s7_int hash_float_location(s7_double x)
44371 {
44372   return(((is_NaN(x)) || (is_inf(x))) ? 0 : (s7_int)floor(fabs(x)));
44373 }
44374 
44375 static s7_int hash_map_int(s7_scheme *sc, s7_pointer table, s7_pointer key)     {return(s7_int_abs(integer(key)));}
44376 static s7_int hash_map_real(s7_scheme *sc, s7_pointer table, s7_pointer key)    {return(hash_float_location(real(key)));}
44377 static s7_int hash_map_complex(s7_scheme *sc, s7_pointer table, s7_pointer key) {return(hash_float_location(real_part(key)));}
44378 
44379 static s7_int hash_map_ratio(s7_scheme *sc, s7_pointer table, s7_pointer key)
44380 {
44381   /* if numerator is -9223372036854775808, s7_int_abs overflows -- need to divide, then abs:  -9223372036854775808/3: -3074457345618258602 3074457345618258602
44382    * (s7_int)floorl(fabsl(fraction(key))) is no good here, 3441313796169221281/1720656898084610641: 1 2 (in valgrind),
44383    *    floor ratio is 1: (- (* 2 1720656898084610641) 3441313796169221281) -> 1
44384    *    or (gmp:) 1.999999999999999999418826611445214136431E0, so the floorl(fabsl) version is wrong
44385    */
44386   return(s7_int_abs(numerator(key) / denominator(key)));
44387 }
44388 
44389 #if WITH_GMP
44390 static s7_int hash_map_big_int(s7_scheme *sc, s7_pointer table, s7_pointer key)
44391 {
44392   /* may need to use quotient here */
44393   mpz_abs(sc->mpz_1, big_integer(key));
44394   return(mpz_get_si(sc->mpz_1)); /* returns the bits that fit */
44395 }
44396 
44397 static s7_int hash_map_big_ratio(s7_scheme *sc, s7_pointer table, s7_pointer key)
44398 {
44399   mpq_abs(sc->mpq_1, big_ratio(key));
44400   mpz_fdiv_q(sc->mpz_1, mpq_numref(sc->mpq_1), mpq_denref(sc->mpq_1));
44401   return(mpz_get_si(sc->mpz_1));
44402 }
44403 
44404 static s7_int hash_map_big_real_1(s7_scheme *sc, s7_pointer table, mpfr_t key)
44405 {
44406   if ((mpfr_nan_p(key)) || (mpfr_inf_p(key))) return(0);
44407   mpfr_abs(sc->mpfr_1, key, MPFR_RNDN);
44408   /* mpfr_get_si returns most-positive-int if > 2^63! luckily there aren't any more of these */
44409   mpfr_get_z(sc->mpz_1, sc->mpfr_1, MPFR_RNDD); /* floor not round */
44410   return(mpz_get_si(sc->mpz_1));
44411 }
44412 
44413 static s7_int hash_map_big_real(s7_scheme *sc, s7_pointer table, s7_pointer key)
44414 {
44415   return(hash_map_big_real_1(sc, table, big_real(key)));
44416 }
44417 
44418 static s7_int hash_map_big_complex(s7_scheme *sc, s7_pointer table, s7_pointer key)
44419 {
44420   return(hash_map_big_real_1(sc, table, mpc_realref(big_complex(key))));
44421 }
44422 #endif
44423 
44424 static hash_entry_t *find_number_in_bin(s7_scheme *sc, hash_entry_t *bin, s7_pointer key)
44425 {
44426   s7_double old_eps;
44427   bool (*equiv)(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci);
44428   old_eps = sc->equivalent_float_epsilon;
44429   equiv = equivalents[type(key)];
44430   sc->equivalent_float_epsilon = sc->hash_table_float_epsilon;
44431   for (; bin; bin = hash_entry_next(bin))
44432     if (equiv(sc, key, hash_entry_key(bin), NULL))
44433       {
44434 	sc->equivalent_float_epsilon = old_eps;
44435 	return(bin);
44436       }
44437   sc->equivalent_float_epsilon = old_eps;
44438   return(NULL);
44439 }
44440 
44441 static hash_entry_t *hash_number_equivalent(s7_scheme *sc, s7_pointer table, s7_pointer key)
44442 {
44443   /* for equivalent? and =, kind of complicated because two bins can be involved if the key is close to an integer */
44444 #if WITH_GMP
44445   /* first try loc from hash_loc, then get key-floor(key) [with abs], and check against
44446    *   epsilon: diff < eps call find big in bin-1, diff > 1.0-eps call same in bin+1
44447    */
44448   s7_int loc, loc1, hash_mask, hash_loc;
44449   hash_entry_t *i1;
44450 
44451   hash_mask = hash_table_mask(table);
44452   loc = hash_loc(sc, table, key);
44453   hash_loc = loc & hash_mask;
44454 
44455   i1 = find_number_in_bin(sc, hash_table_element(table, hash_loc), key);
44456   if (i1) return(i1);
44457 
44458   if (is_real(key))
44459     {
44460       s7_pointer res;
44461       res = any_real_to_mpfr(sc, key, sc->mpfr_1);
44462       if (res) return(sc->unentry);
44463     }
44464   else
44465     {
44466       if (is_t_complex(key))
44467 	mpfr_set_d(sc->mpfr_1, real_part(key), MPFR_RNDN);
44468       else mpfr_set(sc->mpfr_1, mpc_realref(big_complex(key)), MPFR_RNDN);
44469     }
44470 
44471   /* mpfr_1 is big_real, so we can use hash_loc of big_real (and can ignore NaN's): */
44472   mpfr_abs(sc->mpfr_1, sc->mpfr_1, MPFR_RNDN);
44473   mpfr_add_d(sc->mpfr_2, sc->mpfr_1, sc->hash_table_float_epsilon, MPFR_RNDN);
44474   mpfr_get_z(sc->mpz_1, sc->mpfr_2, MPFR_RNDD);
44475   loc1 = mpz_get_si(sc->mpz_1);
44476   if (loc1 != loc)
44477     {
44478       if (loc1 == hash_table_mask(table)) loc1 = 0;
44479       hash_loc = loc1 & hash_mask;
44480       i1 = find_number_in_bin(sc, hash_table_element(table, hash_loc), key);
44481       return((i1) ? i1 : sc->unentry);
44482     }
44483   mpfr_sub_d(sc->mpfr_2, sc->mpfr_1, sc->hash_table_float_epsilon, MPFR_RNDN);
44484   mpfr_get_z(sc->mpz_1, sc->mpfr_2, MPFR_RNDD);
44485   loc1 = mpz_get_si(sc->mpz_1);
44486   if (loc1 != loc)
44487     {
44488       if (loc1 < 0) loc1 = hash_table_mask(table);
44489       hash_loc = loc1 & hash_mask;
44490       i1 = find_number_in_bin(sc, hash_table_element(table, hash_loc), key);
44491       if (i1) return(i1);
44492     }
44493   return(sc->unentry);
44494 #else
44495   s7_int iprobe, loc;
44496   s7_double bin_dist, fprobe, keyval;
44497   hash_entry_t *i1;
44498 
44499   keyval = (is_real(key)) ? s7_real(key) : real_part(key);
44500   fprobe = fabs(keyval);
44501   iprobe = (s7_int)floor(fprobe);
44502   loc = iprobe & hash_table_mask(table);
44503 
44504   i1 = find_number_in_bin(sc, hash_table_element(table, loc), key);
44505   if (i1) return(i1);
44506 
44507   bin_dist = fprobe - iprobe;
44508   if (bin_dist <= sc->hash_table_float_epsilon)        /* maybe closest is below iprobe, key+eps>iprobe but key maps to iprobe-1 */
44509     i1 = find_number_in_bin(sc, hash_table_element(table, (loc > 0) ? loc - 1 : hash_table_mask(table)), key);
44510   else
44511     if (bin_dist >= (1.0 - sc->hash_table_float_epsilon))
44512       i1 = find_number_in_bin(sc, hash_table_element(table, (loc < hash_table_mask(table)) ? loc + 1 : 0), key);
44513 
44514   return((i1) ? i1 : sc->unentry);
44515 #endif
44516 }
44517 
44518 static hash_entry_t *hash_int(s7_scheme *sc, s7_pointer table, s7_pointer key)
44519 {
44520 #if WITH_GMP
44521   if ((is_t_integer(key)) || (is_t_big_integer(key)))
44522 #else
44523   if (is_t_integer(key))
44524 #endif
44525     {
44526       s7_int loc, hash_mask, kv;
44527       hash_entry_t *x;
44528 
44529       hash_mask = hash_table_mask(table);
44530 #if WITH_GMP
44531       kv = (is_t_integer(key)) ? integer(key) : mpz_get_si(big_integer(key));
44532 #else
44533       kv = integer(key);
44534 #endif
44535       loc = s7_int_abs(kv) & hash_mask;
44536       for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44537 #if WITH_GMP
44538 	{
44539 	  if (is_t_integer(hash_entry_key(x)))
44540 	    {
44541 	      if (integer(hash_entry_key(x)) == kv)
44542 		return(x);
44543 	    }
44544 	  else
44545 	    if ((is_t_big_integer(hash_entry_key(x))) &&
44546 		(mpz_get_si(big_integer(hash_entry_key(x))) == kv))
44547 	      return(x);
44548 	}
44549 #else
44550 	if (integer(hash_entry_key(x)) == kv)
44551 	  return(x);
44552 #endif
44553     }
44554   return(sc->unentry);
44555 }
44556 
44557 static hash_entry_t *hash_float(s7_scheme *sc, s7_pointer table, s7_pointer key)
44558 {
44559   /* if a hash-table has only t_real keys, its checker is hash_float, but we might use a t_big_real key */
44560 #if WITH_GMP
44561   if ((is_t_real(key)) || (is_t_big_real(key)))
44562 #else
44563   if (is_t_real(key))
44564 #endif
44565     {
44566       s7_double keyval;
44567       s7_int loc, hash_mask;
44568       hash_entry_t *x;
44569 #if WITH_GMP
44570       if (is_t_real(key))
44571 	{
44572 	  keyval = real(key);
44573 	  if (is_NaN(keyval)) return(sc->unentry);
44574 	}
44575       else
44576 	{
44577 	  if (mpfr_nan_p(big_real(key))) return(sc->unentry);
44578 	  keyval = mpfr_get_d(big_real(key), MPFR_RNDN);
44579 	}
44580 #else
44581       keyval = real(key);
44582       if (is_NaN(keyval)) return(sc->unentry);
44583 #endif
44584       hash_mask = hash_table_mask(table);
44585       loc = hash_float_location(keyval) & hash_mask;
44586 
44587       for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44588 	{
44589 	  if (is_t_real(hash_entry_key(x)))
44590 	    {
44591 	      s7_double val;
44592 	      val = real(hash_entry_key(x));
44593 	      if (val == keyval)
44594 		return(x);
44595 	    }
44596 #if WITH_GMP
44597 	  if (is_t_big_real(hash_entry_key(x)))
44598 	    if ((mpfr_cmp_d(big_real(hash_entry_key(x)), keyval) == 0) &&
44599 		(!mpfr_nan_p(big_real(hash_entry_key(x)))))
44600 	      return(x);
44601 #endif
44602 	}}
44603   return(sc->unentry);
44604 }
44605 
44606 static hash_entry_t *hash_num_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
44607 {
44608   hash_entry_t *x;
44609   s7_int hash_mask, loc;
44610 
44611   hash_mask = hash_table_mask(table);
44612   loc = hash_loc(sc, table, key) & hash_mask;
44613 
44614   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44615     if (num_eq_b_7pp(sc, key, hash_entry_key(x)))
44616       return(x);
44617   return(sc->unentry);
44618 }
44619 
44620 static hash_entry_t *hash_real_num_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
44621 {
44622   /* = compares keys */
44623 #if WITH_GMP
44624   if ((is_t_real(key)) && (is_NaN(real(key)))) return(sc->unentry);
44625   if ((is_t_big_real(key)) && (mpfr_nan_p(big_real(key)))) return(sc->unentry);
44626   return(hash_num_eq(sc, table, key));
44627 #else
44628   return((is_NaN(s7_real(key))) ? sc->unentry : hash_num_eq(sc, table, key));
44629 #endif
44630 }
44631 
44632 static hash_entry_t *hash_complex_num_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
44633 {
44634 #if WITH_GMP
44635   if ((is_t_complex(key)) && ((is_NaN(real_part(key))) || (is_NaN(imag_part(key))))) return(sc->unentry);
44636   if ((is_t_big_complex(key)) && ((mpfr_nan_p(mpc_realref(big_complex(key)))) || (mpfr_nan_p(mpc_imagref(big_complex(key)))))) return(sc->unentry);
44637   return(hash_num_eq(sc, table, key));
44638 #else
44639   return(((is_NaN(real_part(key))) || (is_NaN(imag_part(key)))) ? sc->unentry : hash_num_eq(sc, table, key));
44640 #endif
44641 }
44642 
44643 static hash_entry_t *hash_number_num_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
44644 {
44645   if (is_number(key))
44646     {
44647 #if (!WITH_GMP)
44648       hash_entry_t *x;
44649       s7_int hash_mask;
44650       hash_map_t map;
44651 
44652       hash_mask = hash_table_mask(table);
44653       map = hash_table_mapper(table)[type(key)];
44654       if (hash_table_checker(table) == hash_int)    /* surely by far the most common case? only ints */
44655 	{
44656 	  s7_int keyi, loc;
44657 	  keyi = integer(key);
44658 	  loc = map(sc, table, key) & hash_mask;
44659 	  for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44660 	    if (keyi == integer(hash_entry_key(x))) /* not in gmp, hash_int as eq_func, what else can key be but t_integer? */
44661 	      return(x);
44662 	}
44663       else
44664 #endif
44665 	return((is_real(key)) ? hash_real_num_eq(sc, table, key) : hash_complex_num_eq(sc, table, key));
44666     }
44667   return(sc->unentry);
44668 }
44669 
44670 
44671 /* ---------------- hash characters ---------------- */
44672 static s7_int hash_map_char(s7_scheme *sc, s7_pointer table, s7_pointer key)    {return(character(key));}
44673 
44674 static hash_entry_t *hash_char(s7_scheme *sc, s7_pointer table, s7_pointer key)
44675 {
44676   if (s7_is_character(key))
44677     {
44678       /* return(hash_eq(sc, table, key));
44679        *   but I think if we get here at all, we have to be using default_hash_checks|maps -- see hash_symbol above.
44680        */
44681       hash_entry_t *x;
44682       s7_int loc;
44683       loc = character(key) & hash_table_mask(table);
44684       for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44685 	if (key == hash_entry_key(x))
44686 	  return(x);
44687     }
44688   return(sc->unentry);
44689 }
44690 
44691 #if (!WITH_PURE_S7)
44692 static s7_int hash_map_ci_char(s7_scheme *sc, s7_pointer table, s7_pointer key) {return(upper_character(key));}
44693 
44694 static hash_entry_t *hash_ci_char(s7_scheme *sc, s7_pointer table, s7_pointer key)
44695 {
44696   if (s7_is_character(key))
44697     {
44698       hash_entry_t *x;
44699       s7_int hash_mask, loc;
44700 
44701       hash_mask = hash_table_mask(table);
44702       loc = hash_loc(sc, table, key) & hash_mask;
44703 
44704       for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44705 	if (upper_character(key) == upper_character(hash_entry_key(x)))
44706 	  return(x);
44707     }
44708   return(sc->unentry);
44709 }
44710 #endif
44711 
44712 
44713 /* ---------------- hash strings ---------------- */
44714 static s7_int hash_map_string(s7_scheme *sc, s7_pointer table, s7_pointer key)
44715 {
44716   if (string_hash(key) == 0)
44717     string_hash(key) = raw_string_hash((const uint8_t *)string_value(key), string_length(key));
44718   return(string_hash(key));
44719 }
44720 
44721 static hash_entry_t *hash_string(s7_scheme *sc, s7_pointer table, s7_pointer key)
44722 {
44723   if (is_string(key))
44724     {
44725       hash_entry_t *x;
44726       s7_int key_len, hash_mask;
44727       uint64_t hash;
44728       const char *key_str;
44729 
44730       key_len = string_length(key);
44731       key_str = string_value(key);
44732       if (string_hash(key) == 0)
44733 	string_hash(key) = raw_string_hash((const uint8_t *)string_value(key), string_length(key));
44734       hash = string_hash(key);
44735       hash_mask = hash_table_mask(table);
44736 
44737       if (key_len <= 8)
44738 	{
44739 	  for (x = hash_table_element(table, hash & hash_mask); x; x = hash_entry_next(x))
44740 	    if ((hash == string_hash(hash_entry_key(x))) &&
44741 		(key_len == string_length(hash_entry_key(x))))
44742 	      return(x);
44743 	}
44744       else
44745 	for (x = hash_table_element(table, hash & hash_mask); x; x = hash_entry_next(x))
44746 	  if ((hash == string_hash(hash_entry_key(x))) &&
44747 	      (key_len == string_length(hash_entry_key(x))) &&        /* these are scheme strings, so we can't assume 0=end of string */
44748 	      (strings_are_equal_with_length(key_str, string_value(hash_entry_key(x)), key_len)))
44749 	    return(x);
44750     }
44751   return(sc->unentry);
44752 }
44753 
44754 #if (!WITH_PURE_S7)
44755 static s7_int hash_map_ci_string(s7_scheme *sc, s7_pointer table, s7_pointer key)
44756 {
44757   s7_int len;
44758   len = string_length(key);
44759   return((len == 0) ? 0 : (len + (uppers[(int32_t)(string_value(key)[0])] << 4)));
44760 }
44761 
44762 static hash_entry_t *hash_ci_string(s7_scheme *sc, s7_pointer table, s7_pointer key)
44763 {
44764   if (is_string(key))
44765     {
44766       hash_entry_t *x;
44767       s7_int hash, hash_mask;
44768 
44769       hash_mask = hash_table_mask(table);
44770       hash = hash_map_ci_string(sc, table, key);
44771 
44772       for (x = hash_table_element(table, hash & hash_mask); x; x = hash_entry_next(x))
44773 	if (scheme_strequal_ci(key, hash_entry_key(x)))
44774 	  return(x);
44775     }
44776   return(sc->unentry);
44777 }
44778 #endif
44779 
44780 
44781 /* ---------------- hash eq? ---------------- */
44782 static s7_int hash_map_nil(s7_scheme *sc, s7_pointer table, s7_pointer key)     {return(type(key));}
44783 
44784 static s7_int hash_map_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
44785 {
44786   return(pointer_map(key));
44787 }
44788 
44789 static hash_entry_t *hash_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
44790 {
44791   /* explicit eq? as hash equality func or (for example) symbols as keys */
44792   hash_entry_t *x;
44793   s7_int hash_mask, loc;
44794 
44795   hash_mask = hash_table_mask(table);
44796   loc = pointer_map(key) & hash_mask; /* hash_map_eq */
44797 
44798   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44799     if (key == hash_entry_key(x))
44800       return(x);
44801 
44802   return(sc->unentry);
44803 }
44804 
44805 /* ---------------- hash eqv? ---------------- */
44806 
44807 static hash_entry_t *hash_eqv(s7_scheme *sc, s7_pointer table, s7_pointer key)
44808 {
44809   hash_entry_t *x;
44810   s7_int hash_mask, loc;
44811 
44812   hash_mask = hash_table_mask(table);
44813   loc = hash_loc(sc, table, key) & hash_mask;
44814 
44815   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44816     if (s7_is_eqv(sc, key, hash_entry_key(x)))
44817       return(x);
44818   return(sc->unentry);
44819 }
44820 
44821 /* ---------------- hash equal? ---------------- */
44822 
44823 static s7_int hash_map_hash_table(s7_scheme *sc, s7_pointer table, s7_pointer key)
44824 {
44825   /* hash-tables are equal if key/values match independent of table size and entry order.
44826    * if not using equivalent?, hash_table_checker|mapper must also be the same.
44827    * Keys are supposed to be constant while keys, so a hash-table shouldn't be a key of itself.
44828    */
44829   return(hash_table_entries(key));
44830 }
44831 
44832 static s7_int hash_map_int_vector(s7_scheme *sc, s7_pointer table, s7_pointer key)
44833 {
44834   if (vector_length(key) == 0)
44835     return(0);
44836   if (vector_length(key) == 1)
44837     return(s7_int_abs(int_vector(key, 0)));
44838   return(vector_length(key) + s7_int_abs(int_vector(key, 0)) + s7_int_abs(int_vector(key, 1))); /* overflow is ok here (in + or abs), I guess (as long as it's consistent) */
44839 }
44840 
44841 static s7_int hash_map_byte_vector(s7_scheme *sc, s7_pointer table, s7_pointer key)
44842 {
44843   if (byte_vector_length(key) == 0)
44844     return(0);
44845   if (byte_vector_length(key) == 1)
44846     return((s7_int)byte_vector(key, 0));
44847   return(byte_vector_length(key) + byte_vector(key, 0) + byte_vector(key, 1));
44848 }
44849 
44850 static s7_int hash_map_float_vector(s7_scheme *sc, s7_pointer table, s7_pointer key)
44851 {
44852   if (vector_length(key) == 0)
44853     return(0);
44854   if (vector_length(key) == 1)
44855     return(hash_float_location(float_vector(key, 0)));
44856   return(vector_length(key) + hash_float_location(float_vector(key, 0)) + hash_float_location(float_vector(key, 1)));
44857 }
44858 
44859 static s7_int hash_map_vector(s7_scheme *sc, s7_pointer table, s7_pointer key)
44860 {
44861   if ((vector_length(key) == 0) ||
44862       (is_sequence(vector_element(key, 0))))
44863     return(vector_length(key));
44864   if ((vector_length(key) == 1) ||
44865       (is_sequence(vector_element(key, 1))))
44866     return(hash_loc(sc, table, vector_element(key, 0)));
44867   return(vector_length(key) + hash_loc(sc, table, vector_element(key, 0)) + hash_loc(sc, table, vector_element(key, 1))); /* see above */
44868 }
44869 
44870 
44871 static s7_int hash_map_closure(s7_scheme *sc, s7_pointer table, s7_pointer key)
44872 {
44873   s7_pointer f, old_e, args, body;
44874 
44875   f = hash_table_procedures_mapper(table);
44876   if (f == sc->unused)
44877     s7_error(sc, make_symbol(sc, "hash-map-recursion"),
44878 	     set_elist_1(sc, wrap_string(sc, "hash-table map function called recursively", 42)));
44879   hash_table_set_procedures_mapper(table, sc->unused);
44880   old_e = sc->curlet;
44881   args = closure_args(f);
44882   body = closure_body(f);
44883   sc->curlet = make_let_with_slot(sc, closure_let(f), (is_symbol(car(args))) ? car(args) : caar(args), key);
44884   push_stack_direct(sc, OP_EVAL_DONE);
44885   if (is_pair(cdr(body)))
44886     push_stack_no_args(sc, sc->begin_op, cdr(body));
44887   sc->code = car(body);
44888   eval(sc, OP_EVAL);
44889   hash_table_set_procedures_mapper(table, f);
44890   sc->curlet = old_e;
44891   if (!s7_is_integer(sc->value))
44892     s7_error(sc, sc->wrong_type_arg_symbol,
44893 	     set_elist_2(sc, wrap_string(sc, "hash-table map function should return an integer: ~S", 52), sc->value));
44894   return(integer(sc->value));
44895 }
44896 
44897 static s7_int hash_map_let(s7_scheme *sc, s7_pointer table, s7_pointer key)
44898 {
44899   /* lets are equal if same symbol/value pairs, independent of order, taking into account shadowing
44900    *   (length (inlet 'a 1 'a 2)) = 2
44901    * but this counts as just one entry from equal?'s point of view, so if more than one entry, we have a problem.
44902    *   (equal? (inlet 'a 1) (inlet 'a 3 'a 2 'a 1)) = #t
44903    * also currently equal? follows outlet, but that is ridiculous here, so in this case hash equal?
44904    *   is not the same as equal?  Surely anyone using lets as keys wants eq?
44905    */
44906   s7_pointer slot;
44907   s7_int slots;
44908 
44909   if ((key == sc->rootlet) ||
44910       (!tis_slot(let_slots(key))))
44911     return(0);
44912   slot = let_slots(key);
44913   if (!tis_slot(next_slot(slot)))
44914     {
44915       if (is_sequence(slot_value(slot))) /* avoid loop if cycles */
44916 	return(pointer_map(slot_symbol(slot)));
44917       return(pointer_map(slot_symbol(slot)) + hash_loc(sc, table, slot_value(slot)));
44918     }
44919   slots = 0;
44920   for (; tis_slot(slot); slot = next_slot(slot))
44921     if (!is_matched_symbol(slot_symbol(slot)))
44922       {
44923 	set_match_symbol(slot_symbol(slot));
44924 	slots++;
44925       }
44926   for (slot = let_slots(key); tis_slot(slot); slot = next_slot(slot))
44927     clear_match_symbol(slot_symbol(slot));
44928 
44929   if (slots == 1)
44930     {
44931       slot = let_slots(key);
44932       if (is_sequence(slot_value(slot))) /* avoid loop if cycles */
44933 	return(pointer_map(slot_symbol(slot)));
44934       return(pointer_map(slot_symbol(slot)) + hash_loc(sc, table, slot_value(slot)));
44935     }
44936   return(slots);
44937 }
44938 
44939 static hash_entry_t *hash_equal_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
44940 {
44941   hash_entry_t *x;
44942   s7_int loc;
44943   loc = hash_loc(sc, table, key) & hash_table_mask(table);
44944   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44945     if (hash_entry_key(x) == key)
44946       return(x);
44947   return(sc->unentry);
44948 }
44949 
44950 static hash_entry_t *hash_equal_integer(s7_scheme *sc, s7_pointer table, s7_pointer key)
44951 {
44952   hash_entry_t *x;
44953   s7_int loc, keyint;
44954   keyint = integer(key);
44955   loc = s7_int_abs(keyint) & hash_table_mask(table);  /* hash_loc -> hash_map_integer */
44956   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44957     {
44958       if ((is_t_integer(hash_entry_key(x))) &&
44959 	  (keyint == integer(hash_entry_key(x))))
44960 	return(x);
44961 #if WITH_GMP
44962       if ((is_t_big_integer(hash_entry_key(x))) &&
44963 	  (mpz_cmp_si(big_integer(hash_entry_key(x)), keyint) == 0))
44964 	return(x);
44965 #endif
44966     }
44967   return(sc->unentry);
44968 }
44969 
44970 static hash_entry_t *hash_equal_ratio(s7_scheme *sc, s7_pointer table, s7_pointer key)
44971 {
44972   hash_entry_t *x;
44973   s7_int loc, keynum, keyden;
44974   keynum = numerator(key);
44975   keyden = denominator(key);
44976   loc = s7_int_abs(keynum / keyden) & hash_table_mask(table);  /* hash_loc -> hash_map_ratio */
44977   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
44978     {
44979       if ((is_t_ratio(hash_entry_key(x))) &&
44980 	  (keynum == numerator(hash_entry_key(x))) &&
44981 	  (keyden == denominator(hash_entry_key(x))))
44982 	return(x);
44983 #if WITH_GMP
44984       if ((is_t_big_ratio(hash_entry_key(x))) &&
44985 	  (keynum == mpz_get_si(mpq_numref(big_ratio(hash_entry_key(x))))) &&
44986 	  (keyden == mpz_get_si(mpq_denref(big_ratio(hash_entry_key(x))))))
44987 	return(x);
44988 #endif
44989     }
44990   return(sc->unentry);
44991 }
44992 
44993 static hash_entry_t *hash_equal_real(s7_scheme *sc, s7_pointer table, s7_pointer key)
44994 {
44995   hash_entry_t *x;
44996   s7_int loc;
44997   s7_double keydbl;
44998   keydbl = real(key);
44999   if (is_NaN(keydbl)) return(sc->unentry);
45000   loc = hash_float_location(keydbl) & hash_table_mask(table);
45001   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
45002     {
45003       if ((is_t_real(hash_entry_key(x))) &&
45004 	  (keydbl == real(hash_entry_key(x))))
45005 	return(x);
45006 #if WITH_GMP
45007       if ((is_t_big_real(hash_entry_key(x))) &&
45008 	  (mpfr_cmp_d(big_real(hash_entry_key(x)), keydbl) == 0) &&
45009 	  (!mpfr_nan_p(big_real(hash_entry_key(x)))))
45010 	return(x);
45011 #endif
45012     }
45013   return(sc->unentry);
45014 }
45015 
45016 static hash_entry_t *hash_equal_complex(s7_scheme *sc, s7_pointer table, s7_pointer key)
45017 {
45018   hash_entry_t *x;
45019   s7_int loc;
45020   s7_double keyrl, keyim;
45021   keyrl = real_part(key);
45022   keyim = imag_part(key);
45023 #if WITH_GMP
45024   if ((is_NaN(keyrl)) || (is_NaN(keyim))) return(sc->unentry);
45025 #endif
45026   loc = hash_float_location(keyrl) & hash_table_mask(table);
45027   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
45028     {
45029       if ((is_t_complex(hash_entry_key(x))) &&
45030 	  (keyrl == real_part(hash_entry_key(x))) &&
45031 	  (keyim == imag_part(hash_entry_key(x))))
45032 	return(x);
45033 #if WITH_GMP
45034       if ((is_t_big_complex(hash_entry_key(x))) &&
45035 	  (mpfr_cmp_d(mpc_realref(big_complex(hash_entry_key(x))), keyrl) == 0) &&
45036 	  (mpfr_cmp_d(mpc_imagref(big_complex(hash_entry_key(x))), keyim) == 0) &&
45037 	  (!mpfr_nan_p(mpc_realref(big_complex(hash_entry_key(x))))) &&
45038 	  (!mpfr_nan_p(mpc_imagref(big_complex(hash_entry_key(x))))))
45039 	return(x);
45040 #endif
45041     }
45042   return(sc->unentry);
45043 }
45044 
45045 static hash_entry_t *hash_equal_any(s7_scheme *sc, s7_pointer table, s7_pointer key)
45046 {
45047   hash_entry_t *x;
45048   s7_int hash, loc;
45049   bool (*equal)(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci);
45050 
45051   equal = equals[type(key)];
45052   hash = hash_loc(sc, table, key);
45053   loc = hash & hash_table_mask(table);
45054 
45055   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
45056     if (hash_entry_raw_hash(x) == hash)
45057       if (equal(sc, key, hash_entry_key(x), NULL))
45058 	return(x);
45059   return(sc->unentry);
45060 }
45061 
45062 
45063 /* ---------------- hash c_functions ---------------- */
45064 static s7_int hash_map_c_function(s7_scheme *sc, s7_pointer table, s7_pointer key)
45065 {
45066   s7_function f;
45067   f = c_function_call(hash_table_procedures_mapper(table));
45068   set_car(sc->t1_1, key);
45069   return(integer(f(sc, sc->t1_1)));
45070 }
45071 
45072 static hash_entry_t *hash_c_function(s7_scheme *sc, s7_pointer table, s7_pointer key)
45073 {
45074   hash_entry_t *x;
45075   s7_int hash_mask, hash, loc;
45076   s7_function f;
45077 
45078   f = c_function_call(hash_table_procedures_checker(table));
45079   hash_mask = hash_table_mask(table);
45080   hash = hash_loc(sc, table, key);
45081   loc = hash & hash_mask;
45082 
45083   set_car(sc->t2_1, key);
45084   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
45085     if (hash_entry_raw_hash(x) == hash)
45086       {
45087 	set_car(sc->t2_2, hash_entry_key(x));
45088 	if (is_true(sc, f(sc, sc->t2_1)))
45089 	  return(x);
45090       }
45091   return(sc->unentry);
45092 }
45093 
45094 static int32_t len_upto_8(s7_pointer p)
45095 {
45096   s7_pointer x;
45097   int32_t i;   /* unrolling this loop saves 10-15% */
45098   for (i = 0, x = p; (is_pair(x)) && (i < 8); i++, x = cdr(x));
45099   return(i);
45100 }
45101 
45102 static s7_int hash_map_pair(s7_scheme *sc, s7_pointer table, s7_pointer key)
45103 {
45104   /* len+loc(car) is not horrible, but it means (for example) every list '(set! ...) is hashed to the same location,
45105    *   so at least we need to take cadr into account if possible.  Better would combine the list_length
45106    *   with stats like symbols/pairs/constants at top level, then use those to spread it out over all the locs.
45107    */
45108   s7_pointer p1;
45109   s7_int loc = 0;
45110 
45111   if (!is_sequence(car(key)))
45112     loc = hash_loc(sc, table, car(key)) + 1;
45113   else
45114     if ((is_pair(car(key))) &&
45115 	(!is_sequence(caar(key))))
45116       loc = hash_loc(sc, table, caar(key)) + 1;
45117   p1 = cdr(key);
45118   if (is_pair(p1))
45119     {
45120       if (!is_sequence(car(p1)))
45121 	loc += hash_loc(sc, table, car(p1)) + 1;
45122       else
45123 	if ((is_pair(car(p1))) &&
45124 	    (!is_sequence(caar(p1))))
45125 	  loc += hash_loc(sc, table, caar(p1)) + 1;
45126     }
45127   loc = (loc << 3) | len_upto_8(key);
45128   return(loc);
45129 }
45130 
45131 
45132 static hash_entry_t *hash_closure(s7_scheme *sc, s7_pointer table, s7_pointer key)
45133 {
45134   hash_entry_t *x;
45135   s7_int hash_mask, hash, loc;
45136   s7_pointer f, args, body, old_e;
45137 
45138   f = hash_table_procedures_checker(table);
45139   hash_mask = hash_table_mask(table);
45140   hash = hash_loc(sc, table, key);
45141   loc = hash & hash_mask;
45142 
45143   old_e = sc->curlet;
45144   args = closure_args(f);    /* in lambda* case, car/cadr(args) can be lists */
45145   body = closure_body(f);
45146   sc->curlet = make_let_with_two_slots(sc, closure_let(f),
45147 				       (is_symbol(car(args))) ? car(args) : caar(args), key,
45148 				       (is_symbol(cadr(args))) ? cadr(args) : caadr(args), sc->F);
45149 
45150   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
45151     if (hash_entry_raw_hash(x) == hash)
45152       {
45153 	slot_set_value(next_slot(let_slots(sc->curlet)), hash_entry_key(x));
45154 	push_stack_direct(sc, OP_EVAL_DONE);
45155 	if (is_pair(cdr(body)))
45156 	  push_stack_no_args(sc, sc->begin_op, cdr(body));
45157 	sc->code = car(body);
45158 	eval(sc, OP_EVAL);
45159 	if (is_true(sc, sc->value))
45160 	  {
45161 	    sc->curlet = old_e;
45162 	    return(x);
45163 	  }}
45164   sc->curlet = old_e;
45165   return(sc->unentry);
45166 }
45167 
45168 static hash_entry_t *hash_equal(s7_scheme *sc, s7_pointer table, s7_pointer key)
45169 {
45170   return((*(equal_hash_checks[type(key)]))(sc, table, key));
45171 }
45172 
45173 /* ---------------- hash equivalent? ---------------- */
45174 static hash_entry_t *hash_equivalent(s7_scheme *sc, s7_pointer table, s7_pointer key)
45175 {
45176   hash_entry_t *x;
45177   s7_int hash, loc;
45178 
45179   if (is_number(key))
45180     {
45181       if (is_nan_b_7p(sc, key))
45182 	{
45183 	  for (x = hash_table_element(table, 0); x; x = hash_entry_next(x)) /* NaN is mapped to 0 */
45184 	    if (is_nan_b_7p(sc, hash_entry_key(x)))  /* all NaN's are the same to equivalent? */
45185 	      return(x);
45186 	  return(sc->unentry);
45187 	}
45188       return(hash_number_equivalent(sc, table, key));
45189     }
45190 
45191   hash = hash_loc(sc, table, key);
45192   loc = hash & hash_table_mask(table);
45193   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
45194     if (hash_entry_key(x) == key)
45195       return(x);
45196 
45197   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
45198     if ((hash_entry_raw_hash(x) == hash) &&
45199 	(s7_is_equivalent(sc, hash_entry_key(x), key)))
45200       return(x);
45201   return(sc->unentry);
45202 }
45203 
45204 
45205 
45206 /* -------------------------------- make-hash-table -------------------------------- */
45207 
45208 s7_pointer s7_make_hash_table(s7_scheme *sc, s7_int size)
45209 {
45210   s7_pointer table;
45211   block_t *els;
45212   /* size is rounded up to the next power of 2 */
45213 
45214   if (size < 2)
45215     size = 2;
45216   else
45217     if ((size & (size - 1)) != 0)          /* already 2^n ? */
45218       {
45219 	if ((size & (size + 1)) != 0)      /* already 2^n - 1 ? */
45220 	  {
45221 	    size--;
45222 	    size |= (size >> 1);
45223 	    size |= (size >> 2);
45224 	    size |= (size >> 4);
45225 	    size |= (size >> 8);
45226 	    size |= (size >> 16);
45227 	    size |= (size >> 32);
45228 	  }
45229 	size++;
45230       }
45231 
45232   els = (block_t *)callocate(sc, size * sizeof(hash_entry_t *));
45233   new_cell(sc, table, T_HASH_TABLE | T_SAFE_PROCEDURE);
45234   hash_table_mask(table) = size - 1;
45235   hash_table_set_block(table, els);
45236   hash_table_elements(table) = (hash_entry_t **)(block_data(els));
45237   if (!hash_table_elements(table))
45238     s7_error(sc, make_symbol(sc, "memory-error"),
45239 	     set_elist_2(sc, wrap_string(sc, "hash-table not allocated! size: ~D bytes", 40), make_integer(sc, size * sizeof(hash_entry_t *))));
45240   hash_table_checker(table) = hash_empty;
45241   hash_table_mapper(table) = default_hash_map;
45242   hash_table_entries(table) = 0;
45243   hash_table_set_procedures(table, sc->nil);
45244   add_hash_table(sc, table);
45245 
45246   return(table);
45247 }
45248 
45249 static bool compatible_types(s7_scheme *sc, s7_pointer eq_type, s7_pointer value_type)
45250 {
45251   if (eq_type == sc->T) return(true);
45252   if (eq_type == value_type) return(true);
45253 
45254   if (eq_type == sc->is_number_symbol)              /* only = among built-ins, so otherr cases aren't needed */
45255     return((value_type == sc->is_integer_symbol) ||
45256 	   (value_type == sc->is_real_symbol) ||
45257 	   (value_type == sc->is_complex_symbol) ||
45258 	   (value_type == sc->is_rational_symbol));
45259 
45260   return(false);
45261 }
45262 
45263 static s7_pointer g_is_equal(s7_scheme *sc, s7_pointer args);
45264 static s7_pointer g_is_equivalent(s7_scheme *sc, s7_pointer args);
45265 static s7_pointer type_name_string(s7_scheme *sc, s7_pointer arg);
45266 
45267 static s7_pointer g_make_hash_table_1(s7_scheme *sc, s7_pointer args, s7_pointer caller)
45268 {
45269   #define H_make_hash_table "(make-hash-table (size 8) eq-func typer) returns a new hash table. eq-func is the function \
45270 used to check equality of keys; it usually defaults to equal?. typer sets the types of the keys and values that are allowed \
45271 in the table; it is a cons, defaulting to (cons #t #t) which means any types are allowed.\n"
45272   #define Q_make_hash_table s7_make_signature(sc, 4, sc->is_hash_table_symbol, sc->is_integer_symbol, \
45273 					      s7_make_signature(sc, 3, sc->is_procedure_symbol, sc->is_pair_symbol, sc->not_symbol), \
45274 					      s7_make_signature(sc, 2, sc->is_pair_symbol, sc->not_symbol))
45275   s7_int size;
45276   size = sc->default_hash_table_length;
45277 
45278   if (is_not_null(args))
45279     {
45280       s7_pointer p;
45281       p = car(args);
45282       if (!s7_is_integer(p))
45283 	return(method_or_bust(sc, p, caller, args, T_INTEGER, 1));
45284       size = s7_integer_checked(sc, p);
45285       if (size <= 0)                      /* we need s7_int here to catch (make-hash-table most-negative-fixnum) etc */
45286 	return(simple_out_of_range(sc, caller, p, wrap_string(sc, "should be a positive integer", 28)));
45287       if ((size > sc->max_vector_length) ||
45288 	  (size >= (1LL << 32LL)))
45289 	return(simple_out_of_range(sc, caller, p, its_too_large_string));
45290 
45291       if (is_not_null(cdr(args)))
45292 	{
45293 	  s7_pointer ht, proc, dproc;
45294 
45295 	  ht = s7_make_hash_table(sc, size);
45296 	  /* look for key/value type functions */
45297 	  dproc = sc->nil;
45298 
45299 	  /* check for typers */
45300 	  if (is_pair(cddr(args)))
45301 	    {
45302 	      s7_pointer typers;
45303 	      typers = caddr(args);
45304 	      if (is_pair(typers))
45305 		{
45306 		  s7_pointer keyp, valp;
45307 		  keyp = car(typers);
45308 		  valp = cdr(typers);
45309 		  if ((keyp != sc->T) || (valp != sc->T)) /* one of them is a type checker */
45310 		    {
45311 		      if (((keyp != sc->T) && (!is_c_function(keyp)) && (!is_any_closure(keyp))) ||
45312 			  ((valp != sc->T) && (!is_c_function(valp)) && (!is_any_closure(valp))))
45313 			return(wrong_type_argument_with_type(sc, caller, 3, typers, wrap_string(sc, "(key-type . value-type)", 23)));
45314 		      dproc = cons(sc, sc->T, sc->T);
45315 		      hash_table_set_procedures(ht, dproc);
45316 		      hash_table_set_key_typer(dproc, keyp);
45317 		      hash_table_set_value_typer(dproc, valp);
45318 		      if (is_c_function(keyp))
45319 			{
45320 			  if (!c_function_name(keyp))
45321 			    return(wrong_type_argument_with_type(sc, caller, 3, keyp, wrap_string(sc, "a named procedure", 17)));
45322 			  if (c_function_has_simple_elements(keyp))
45323 			    set_has_simple_keys(ht);
45324 			  if (!c_function_symbol(keyp))
45325 			    c_function_symbol(keyp) = make_symbol(sc, c_function_name(keyp));
45326 			  if (symbol_type(c_function_symbol(keyp)) != T_FREE)
45327 			    set_has_hash_key_type(ht);
45328 			  /* c_function_marker is not currently used in this context */
45329 
45330 			  /* now a consistency check for eq-func and key type */
45331 			  proc = cadr(args);
45332 			  if (is_c_function(proc))
45333 			    {
45334 			      s7_pointer eq_sig;
45335 			      eq_sig = c_function_signature(proc);
45336 			      if ((eq_sig) &&
45337 				  (is_pair(eq_sig)) &&
45338 				  (is_pair(cdr(eq_sig))) &&
45339 				  (!compatible_types(sc, cadr(eq_sig), c_function_symbol(keyp))))
45340 				return(wrong_type_argument_with_type(sc, caller, 2, proc, wrap_string(sc, "a function that matches the key type function", 45)));
45341 			    }}
45342 		      else
45343 			if ((is_any_closure(keyp)) &&
45344 			    (!is_symbol(find_closure(sc, keyp, closure_let(keyp)))))
45345 			  return(wrong_type_argument_with_type(sc, caller, 3, keyp, wrap_string(sc, "a named function", 16)));
45346 		      if (is_c_function(valp))
45347 			{
45348 			  if (!c_function_name(valp))
45349 			    return(wrong_type_argument_with_type(sc, caller, 3, valp, wrap_string(sc, "a named procedure", 17)));
45350 			  if (c_function_has_simple_elements(valp))
45351 			    set_has_simple_values(ht);
45352 			  if (!c_function_symbol(valp))
45353 			    c_function_symbol(valp) = make_symbol(sc, c_function_name(valp));
45354 			  if (symbol_type(c_function_symbol(valp)) != T_FREE)
45355 			    set_has_hash_value_type(ht);
45356 			}
45357 		      else
45358 			if ((is_any_closure(valp)) &&
45359 			    (!is_symbol(find_closure(sc, valp, closure_let(valp)))))
45360 			  return(wrong_type_argument_with_type(sc, caller, 3, valp, wrap_string(sc, "a named function", 16)));
45361 		      set_typed_hash_table(ht);
45362 		    }}
45363 	      else
45364 		if (typers != sc->F)
45365 		  return(wrong_type_argument_with_type(sc, caller, 3, typers, wrap_string(sc, "(key-type . value-type)", 23)));
45366 	    }
45367 
45368 	  /* check eq_func */
45369 	  proc = cadr(args);
45370 
45371 	  if (is_c_function(proc))
45372 	    {
45373 	      hash_set_chosen(ht);
45374 
45375 	      if (!s7_is_aritable(sc, proc, 2))
45376 		return(wrong_type_argument_with_type(sc, caller, 2, proc, an_eq_func_string));
45377 
45378 	      if (c_function_call(proc) == g_is_equal)
45379 		{
45380 		  hash_table_checker(ht) = hash_equal;
45381 		  return(ht);
45382 		}
45383 	      if (c_function_call(proc) == g_is_equivalent)
45384 		{
45385 		  hash_table_checker(ht) = hash_equivalent;
45386 		  hash_table_mapper(ht) = equivalent_hash_map; /* needed only by hash_table_equal_1 (checker_locked looks at mapper?!) */
45387 		  return(ht);
45388 		}
45389 	      if (c_function_call(proc) == g_is_eq)
45390 		{
45391 		  hash_table_checker(ht) = hash_eq;
45392 		  hash_table_mapper(ht) = eq_hash_map;
45393 		  return(ht);
45394 		}
45395 	      if (c_function_call(proc) == g_strings_are_equal)
45396 		{
45397 		  hash_table_checker(ht) = hash_string;
45398 		  hash_table_mapper(ht) = string_eq_hash_map;
45399 		  return(ht);
45400 		}
45401 #if (!WITH_PURE_S7)
45402 	      if (c_function_call(proc) == g_strings_are_ci_equal)
45403 		{
45404 		  hash_table_checker(ht) = hash_ci_string;
45405 		  hash_table_mapper(ht) = string_ci_eq_hash_map;
45406 		  return(ht);
45407 		}
45408 	      if (c_function_call(proc) == g_chars_are_ci_equal)
45409 		{
45410 		  hash_table_checker(ht) = hash_ci_char;
45411 		  hash_table_mapper(ht) = char_ci_eq_hash_map;
45412 		  return(ht);
45413 		}
45414 #endif
45415 	      if (c_function_call(proc) == g_chars_are_equal)
45416 		{
45417 		  hash_table_checker(ht) = hash_char;
45418 		  hash_table_mapper(ht) = char_eq_hash_map;
45419 		  return(ht);
45420 		}
45421 	      if (c_function_call(proc) == g_num_eq)
45422 		{
45423 		  if ((is_typed_hash_table(ht)) &&
45424 		      (hash_table_key_typer(ht) == global_value(sc->is_integer_symbol)))
45425 		    hash_table_checker(ht) = hash_int;
45426 		  else hash_table_checker(ht) = hash_number_num_eq;
45427 		  return(ht);
45428 		}
45429 	      if (c_function_call(proc) == g_is_eqv)
45430 		{
45431 		  hash_table_checker(ht) = hash_eqv;
45432 		  return(ht);
45433 		}
45434 	      return(s7_error(sc, sc->out_of_range_symbol,
45435 			      set_elist_2(sc, wrap_string(sc, "make-hash-table argument 2, ~S, is not a built-in function it can handle", 72), proc)));
45436 	    }
45437 	  /* proc not c_function */
45438 	  else
45439 	    {
45440 	      if (is_pair(proc))
45441 		{
45442 		  s7_pointer checker, mapper, sig;
45443 
45444 		  checker = car(proc);
45445 		  mapper = cdr(proc);
45446 		  hash_set_chosen(ht);
45447 
45448 		  if (!((is_any_c_function(checker)) ||
45449 			(is_any_closure(checker))))
45450 		    return(s7_error(sc, sc->wrong_type_arg_symbol,
45451 				    set_elist_4(sc, wrap_string(sc, "~A: first entry of type info, ~A, is ~A, but should be a function", 65),
45452 						caller, checker, type_name_string(sc, checker))));
45453 		  if (!((is_any_c_function(mapper)) ||
45454 			(is_any_closure(mapper))))
45455 		    return(s7_error(sc, sc->wrong_type_arg_symbol,
45456 				    set_elist_4(sc, wrap_string(sc, "~A: second entry of type info, ~A, is ~A, but should be a function", 66),
45457 						caller, mapper, type_name_string(sc, mapper))));
45458 
45459 		  if (!(s7_is_aritable(sc, checker, 2)))
45460 		    return(wrong_type_argument_with_type(sc, caller, 2, checker, wrap_string(sc, "a function of 2 args", 20)));
45461 		  if (!(s7_is_aritable(sc, mapper, 1)))
45462 		    return(wrong_type_argument_with_type(sc, caller, 2, mapper, wrap_string(sc, "a function of 1 arg", 19)));
45463 
45464 		  if (is_any_c_function(checker))
45465 		    {
45466 		      sig = c_function_signature(checker);
45467 		      if ((sig) &&
45468 			  (is_pair(sig)) &&
45469 			  (car(sig) != sc->is_boolean_symbol))
45470 			s7_error(sc, sc->wrong_type_arg_symbol,
45471 				 set_elist_2(sc, wrap_string(sc, "make-hash-table checker function, ~S, should return a boolean value", 67), checker));
45472 		      hash_table_checker(ht) = hash_c_function;
45473 		    }
45474 		  else hash_table_checker(ht) = hash_closure;
45475 
45476 		  if (is_any_c_function(mapper))
45477 		    {
45478 		      sig = c_function_signature(mapper);
45479 		      if ((sig) &&
45480 			  (is_pair(sig)) &&
45481 			  (car(sig) != sc->is_integer_symbol))
45482 			s7_error(sc, sc->wrong_type_arg_symbol,
45483 				 set_elist_2(sc, wrap_string(sc, "make-hash-table mapper function, ~S, should return an integer", 61), mapper));
45484 		      hash_table_mapper(ht) = c_function_hash_map;
45485 		    }
45486 		  else hash_table_mapper(ht) = closure_hash_map;
45487 
45488 		  if (is_null(dproc))
45489 		    hash_table_set_procedures(ht, proc); /* only place this is newly set (as opposed to preserved in copy) */
45490 		  else
45491 		    {
45492 		      set_car(dproc, car(proc));
45493 		      set_cdr(dproc, cdr(proc));
45494 		    }
45495 		  return(ht);
45496 		}
45497 	      return((proc == sc->F) ? ht : wrong_type_argument_with_type(sc, caller, 2, proc, wrap_string(sc, "a cons of two functions", 23)));
45498 	    }}}
45499   return(s7_make_hash_table(sc, size));
45500 }
45501 
45502 static s7_pointer g_make_hash_table(s7_scheme *sc, s7_pointer args)
45503 {
45504   return(g_make_hash_table_1(sc, args, sc->make_hash_table_symbol));
45505 }
45506 
45507 
45508 /* -------------------------------- make-weak-hash-table -------------------------------- */
45509 static s7_pointer g_make_weak_hash_table(s7_scheme *sc, s7_pointer args)
45510 {
45511   #define H_make_weak_hash_table "(make-weak-hash-table (size 8) eq-func typers) returns a new weak hash table"
45512   #define Q_make_weak_hash_table s7_make_signature(sc, 4, sc->is_weak_hash_table_symbol, sc->is_integer_symbol, \
45513 						   s7_make_signature(sc, 3, sc->is_procedure_symbol, sc->is_pair_symbol, sc->not_symbol), \
45514 						   s7_make_signature(sc, 2, sc->is_pair_symbol, sc->not_symbol))
45515   s7_pointer table;
45516   table = g_make_hash_table_1(sc, args, sc->make_weak_hash_table_symbol);
45517   set_weak_hash_table(table);
45518   weak_hash_iters(table) = 0;
45519   return(table);
45520 }
45521 
45522 
45523 /* -------------------------------- weak-hash-table? -------------------------------- */
45524 static s7_pointer g_is_weak_hash_table(s7_scheme *sc, s7_pointer args)
45525 {
45526   #define H_is_weak_hash_table "(weak-hash-table? obj) returns #t if obj is a weak hash-table"
45527   #define Q_is_weak_hash_table sc->pl_bt
45528   #define is_weak_hash(p) ((is_hash_table(p)) && (is_weak_hash_table(p)))
45529   check_boolean_method(sc, is_weak_hash, sc->is_weak_hash_table_symbol, args);
45530 }
45531 
45532 static void init_hash_maps(void)
45533 {
45534   int32_t i;
45535 
45536   for (i = 0; i < NUM_TYPES; i++)
45537     {
45538       default_hash_map[i] = hash_map_nil;
45539       string_eq_hash_map[i] = hash_map_nil;
45540       char_eq_hash_map[i] = hash_map_nil;
45541 #if (!WITH_PURE_S7)
45542       string_ci_eq_hash_map[i] = hash_map_nil;
45543       char_ci_eq_hash_map[i] = hash_map_nil;
45544 #endif
45545       closure_hash_map[i] = hash_map_closure;
45546       c_function_hash_map[i] = hash_map_c_function;
45547       eq_hash_map[i] = hash_map_eq;
45548 
45549       equal_hash_checks[i] = hash_equal_any;
45550       default_hash_checks[i] = hash_equal;
45551     }
45552   default_hash_map[T_CHARACTER] =     hash_map_char;
45553   default_hash_map[T_SYMBOL] =        hash_map_symbol;
45554   default_hash_map[T_SYNTAX] =        hash_map_syntax;
45555   default_hash_map[T_STRING] =        hash_map_string;
45556   default_hash_map[T_BYTE_VECTOR] =   hash_map_byte_vector;
45557   default_hash_map[T_HASH_TABLE] =    hash_map_hash_table;
45558   default_hash_map[T_VECTOR] =        hash_map_vector;
45559   default_hash_map[T_INT_VECTOR] =    hash_map_int_vector;
45560   default_hash_map[T_FLOAT_VECTOR] =  hash_map_float_vector;
45561   default_hash_map[T_LET] =           hash_map_let;
45562   default_hash_map[T_PAIR] =          hash_map_pair;
45563 
45564   default_hash_map[T_INTEGER] =       hash_map_int;
45565   default_hash_map[T_RATIO] =         hash_map_ratio;
45566   default_hash_map[T_REAL] =          hash_map_real;
45567   default_hash_map[T_COMPLEX] =       hash_map_complex;
45568 #if WITH_GMP
45569   default_hash_map[T_BIG_INTEGER] =   hash_map_big_int;
45570   default_hash_map[T_BIG_RATIO] =     hash_map_big_ratio;
45571   default_hash_map[T_BIG_REAL] =      hash_map_big_real;
45572   default_hash_map[T_BIG_COMPLEX] =   hash_map_big_complex;
45573 #endif
45574 
45575   string_eq_hash_map[T_STRING] =      hash_map_string;
45576   string_eq_hash_map[T_BYTE_VECTOR] = hash_map_byte_vector;
45577   char_eq_hash_map[T_CHARACTER] =     hash_map_char;
45578 #if (!WITH_PURE_S7)
45579   string_ci_eq_hash_map[T_STRING] =   hash_map_ci_string;
45580   char_ci_eq_hash_map[T_CHARACTER] =  hash_map_ci_char;
45581 #endif
45582 
45583   for (i = 0; i < NUM_TYPES; i++) equivalent_hash_map[i] = default_hash_map[i];
45584 
45585   equal_hash_checks[T_SYNTAX] =       hash_equal_syntax;
45586   equal_hash_checks[T_SYMBOL] =       hash_equal_eq;
45587   equal_hash_checks[T_CHARACTER] =    hash_equal_eq;
45588   equal_hash_checks[T_INTEGER] =      hash_equal_integer;
45589   equal_hash_checks[T_RATIO] =        hash_equal_ratio;
45590   equal_hash_checks[T_REAL] =         hash_equal_real;
45591   equal_hash_checks[T_COMPLEX] =      hash_equal_complex;
45592 
45593   default_hash_checks[T_STRING] =     hash_string;
45594   default_hash_checks[T_INTEGER] =    hash_int;
45595   default_hash_checks[T_REAL] =       hash_float;
45596   default_hash_checks[T_SYMBOL] =     hash_symbol;
45597   default_hash_checks[T_CHARACTER] =  hash_char;
45598 }
45599 
45600 static void resize_hash_table(s7_scheme *sc, s7_pointer table)
45601 {
45602   s7_int hash_mask, loc, i, old_size, new_size;
45603   hash_entry_t **new_els, **old_els;
45604   block_t *np;
45605   s7_pointer dproc;
45606   s7_int entries;
45607 
45608   dproc = hash_table_procedures(table); /* new block_t so we need to pass this across */
45609   entries = hash_table_entries(table);
45610   old_size = hash_table_mask(table) + 1;
45611   new_size = old_size * 4;
45612   hash_mask = new_size - 1;
45613   np = (block_t *)callocate(sc, new_size * sizeof(hash_entry_t *));
45614   new_els = (hash_entry_t **)(block_data(np));
45615   old_els = hash_table_elements(table);
45616 
45617   for (i = 0; i < old_size; i++)
45618     {
45619       hash_entry_t *x, *n;
45620       for (x = old_els[i]; x; x = n)
45621 	{
45622 	  n = hash_entry_next(x);
45623 	  loc = hash_entry_raw_hash(x) & hash_mask;
45624 	  hash_entry_next(x) = new_els[loc];
45625 	  new_els[loc] = x;
45626 	}}
45627   liberate(sc, hash_table_block(table));
45628   hash_table_set_block(table, np);
45629   hash_table_elements(table) = new_els;
45630   hash_table_mask(table) = new_size - 1;
45631   hash_table_set_procedures(table, dproc);
45632   hash_table_entries(table) = entries;
45633 }
45634 
45635 
45636 /* -------------------------------- hash-table-ref -------------------------------- */
45637 
45638 s7_pointer s7_hash_table_ref(s7_scheme *sc, s7_pointer table, s7_pointer key)
45639 {
45640   return(hash_entry_value((*hash_table_checker(table))(sc, table, key)));
45641 }
45642 
45643 static s7_pointer g_hash_table_ref(s7_scheme *sc, s7_pointer args)
45644 {
45645   #define H_hash_table_ref "(hash-table-ref table key) returns the value associated with key in the hash table"
45646   #define Q_hash_table_ref s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_hash_table_symbol, sc->T)
45647 
45648   s7_pointer table, nt;
45649   table = car(args);
45650   if (!is_hash_table(table))
45651     return(method_or_bust(sc, table, sc->hash_table_ref_symbol, args, T_HASH_TABLE, 1));
45652   nt = s7_hash_table_ref(sc, table, cadr(args));
45653   if (is_null(cddr(args))) /* implicit args */
45654     return(nt);
45655   if (nt == sc->F) /* need the error here, not in implicit_index because table should be in the error message, not nt */
45656     return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, table, args)));
45657   return(implicit_index(sc, nt, cddr(args))); /* 9-Jan-19 */
45658 }
45659 
45660 static s7_pointer g_hash_table_ref_2(s7_scheme *sc, s7_pointer args)
45661 {
45662   s7_pointer table;
45663   table = car(args);
45664   if (!is_hash_table(table))
45665     return(method_or_bust(sc, table, sc->hash_table_ref_symbol, args, T_HASH_TABLE, 1));
45666   return(hash_entry_value((*hash_table_checker(table))(sc, table, cadr(args))));
45667 }
45668 
45669 static s7_pointer hash_table_ref_p_pp(s7_scheme *sc, s7_pointer table, s7_pointer key)
45670 {
45671   if (!is_hash_table(table))
45672     simple_wrong_type_argument(sc, sc->hash_table_ref_symbol, table, T_HASH_TABLE);
45673   return(hash_entry_value((*hash_table_checker(table))(sc, table, key)));
45674 }
45675 
45676 static bool op_implicit_hash_table_ref_a(s7_scheme *sc)
45677 {
45678   s7_pointer s;
45679   s = lookup_checked(sc, car(sc->code));
45680   if (!is_hash_table(s)) {sc->last_function = s; return(false);}
45681   sc->value = s7_hash_table_ref(sc, s, fx_call(sc, cdr(sc->code)));
45682   return(true);
45683 }
45684 
45685 static s7_pointer hash_table_ref_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
45686 {
45687   if (args == 2)
45688     {
45689       s7_pointer key;
45690       key = caddr(expr);
45691       if ((is_pair(key)) && (car(key) == sc->substring_symbol) && (is_global(sc->substring_symbol)))
45692 	set_c_function(key, sc->substring_uncopied);
45693       return(sc->hash_table_ref_2);
45694     }
45695  return(f);
45696 }
45697 
45698 
45699 /* -------------------------------- hash-table-set! -------------------------------- */
45700 
45701 static s7_pointer remove_from_hash_table(s7_scheme *sc, s7_pointer table, s7_pointer key, hash_entry_t *p)
45702 {
45703   hash_entry_t *x;
45704   s7_int hash_mask, loc;
45705 
45706   if (p == sc->unentry) return(sc->F);
45707   hash_mask = hash_table_mask(table);
45708   loc = hash_entry_raw_hash(p) & hash_mask;
45709   x = hash_table_element(table, loc);
45710   if (x == p)
45711     hash_table_element(table, loc) = hash_entry_next(x);
45712   else
45713     {
45714       hash_entry_t *y;
45715       for (y = x, x = hash_entry_next(x); x; y = x, x = hash_entry_next(x))
45716 	if (x == p)
45717 	  {
45718 	    hash_entry_next(y) = hash_entry_next(x);
45719 	    break;
45720 	  }}
45721   hash_table_entries(table)--;
45722   if ((hash_table_entries(table) == 0) &&
45723       (!hash_table_checker_locked(table)))
45724     {
45725       hash_table_checker(table) = hash_empty;
45726       hash_clear_chosen(table);
45727     }
45728   liberate_block(sc, x);
45729   return(sc->F);
45730 }
45731 
45732 static void cull_weak_hash_table(s7_scheme *sc, s7_pointer table)
45733 {
45734   if (hash_table_entries(table) > 0)
45735     {
45736       s7_int i, len;
45737       hash_entry_t **entries;
45738 
45739       entries = hash_table_elements(table);
45740       len = hash_table_mask(table) + 1;
45741 
45742       for (i = 0; i < len; i++)
45743 	{
45744 	  hash_entry_t *xp, *nxp, *lxp;
45745 	  lxp = entries[i];
45746 	  for (xp = entries[i]; xp; xp = nxp)
45747 	    {
45748 	      nxp = hash_entry_next(xp);
45749 	      if (is_free_and_clear(hash_entry_key(xp)))
45750 		{
45751 		  if (xp == entries[i])
45752 		    {
45753 		      entries[i] = nxp;
45754 		      lxp = nxp;
45755 		    }
45756 		  else hash_entry_next(lxp) = nxp;
45757                   liberate_block(sc, xp);
45758 		  hash_table_entries(table)--;
45759 		  if (hash_table_entries(table) == 0)
45760 		    {
45761 		      if (!hash_table_checker_locked(table))
45762 			{
45763 			  hash_table_checker(table) = hash_empty;
45764 			  hash_clear_chosen(table);
45765 			}
45766 		      return;
45767 		    }}
45768 	      else lxp = xp;
45769 	    }}}
45770 }
45771 
45772 static void hash_table_set_checker(s7_pointer table, uint8_t typ)
45773 {
45774   if (hash_table_checker(table) != default_hash_checks[typ])
45775     {
45776       if (hash_table_checker(table) == hash_empty)
45777 	hash_table_checker(table) = default_hash_checks[typ];
45778       else
45779 	{
45780 	  hash_table_checker(table) = hash_equal;
45781 	  hash_set_chosen(table);
45782 	}}
45783 }
45784 
45785 static s7_pointer hash_table_typer_symbol(s7_scheme *sc, s7_pointer typer)
45786 {
45787   if (typer == sc->T)
45788     return(sc->T);
45789   return((is_c_function(typer)) ? c_function_symbol(typer) : find_closure(sc, typer, closure_let(typer)));
45790 }
45791 
45792 static const char *hash_table_typer_name(s7_scheme *sc, s7_pointer typer)
45793 {
45794   return((is_c_function(typer)) ? c_function_name(typer) : symbol_name(find_closure(sc, typer, closure_let(typer))));
45795 }
45796 
45797 static void check_hash_types(s7_scheme *sc, s7_pointer table, s7_pointer key, s7_pointer value)
45798 {
45799   if (has_hash_key_type(table)) /* symbol_type and c_function_symbol exist and symbol_type is not T_FREE */
45800     {
45801       if ((uint8_t)symbol_type(c_function_symbol(hash_table_key_typer(table))) != type(key))
45802 	s7_wrong_type_arg_error(sc, "hash-table-set! key", 2, key,
45803 				make_type_name(sc, hash_table_typer_name(sc, hash_table_key_typer(table)), INDEFINITE_ARTICLE));
45804     }
45805   else
45806     {
45807       s7_pointer kf;
45808       kf = hash_table_key_typer(table);
45809       if (kf != sc->T)
45810 	{
45811 	  s7_pointer type_ok;
45812 	  if (is_c_function(kf))
45813 	    type_ok = c_function_call(kf)(sc, set_plist_1(sc, key));
45814 	  else type_ok = s7_apply_function(sc, kf, set_plist_1(sc, key));
45815 	  if (type_ok == sc->F)
45816 	    s7_wrong_type_arg_error(sc, "hash-table-set! key", 2, key,
45817 				    make_type_name(sc, hash_table_typer_name(sc, hash_table_key_typer(table)), INDEFINITE_ARTICLE));
45818 	}}
45819   if (has_hash_value_type(table))
45820     {
45821       if ((uint8_t)symbol_type(c_function_symbol(hash_table_value_typer(table))) != type(value))
45822 	s7_wrong_type_arg_error(sc, "hash-table-set! value", 3, value,
45823 				make_type_name(sc, hash_table_typer_name(sc, hash_table_value_typer(table)), INDEFINITE_ARTICLE));
45824     }
45825   else
45826     {
45827       s7_pointer vf;
45828       vf = hash_table_value_typer(table);
45829       if (vf != sc->T)
45830 	{
45831 	  s7_pointer type_ok;
45832 	  if (is_c_function(vf))
45833 	    type_ok = c_function_call(vf)(sc, set_plist_1(sc, value));
45834 	  else type_ok = s7_apply_function(sc, vf, set_plist_1(sc, value));
45835 	  if (type_ok == sc->F)
45836 	    s7_wrong_type_arg_error(sc, "hash-table-set! value", 3, value,
45837 				    make_type_name(sc, hash_table_typer_name(sc, hash_table_value_typer(table)), INDEFINITE_ARTICLE));
45838 	}}
45839 }
45840 
45841 s7_pointer s7_hash_table_set(s7_scheme *sc, s7_pointer table, s7_pointer key, s7_pointer value)
45842 {
45843   s7_int hash_mask, loc;
45844   hash_entry_t *p, *x;
45845 
45846   if (value == sc->F)
45847     return(remove_from_hash_table(sc, table, key, (*hash_table_checker(table))(sc, table, key)));
45848 
45849   if ((is_typed_hash_table(table)) &&
45850       (sc->safety >= NO_SAFETY))
45851     check_hash_types(sc, table, key, value);
45852 
45853   x = (*hash_table_checker(table))(sc, table, key);
45854   if (x != sc->unentry)
45855     {
45856       hash_entry_set_value(x, T_Pos(value));
45857       return(value);
45858     }
45859   /* hash_entry_raw_hash(x) can save the hash_loc from the lookup operations, but at some added complexity in
45860    *   all the preceding code.  This saves about 5% compute time best case in this function.
45861    */
45862 
45863   if (!hash_chosen(table))
45864     hash_table_set_checker(table, type(key)); /* raw_hash value (hash_loc(sc, table, key)) does not change via hash_table_set_checker etc */
45865   else
45866     {
45867       /* check type -- raise error if incompatible with eq func set by make-hash-table */
45868       if (hash_table_checker(table) == hash_number_num_eq)
45869 	{
45870 	  if (!is_number(key))
45871 	    return(s7_error(sc, sc->wrong_type_arg_symbol,
45872 			    set_elist_3(sc, wrap_string(sc, "hash-table-set! key ~S, is ~A, but the hash-table's key function is =", 69),
45873 					key, type_name_string(sc, key))));
45874 	}
45875       else
45876 	{
45877 	  if (hash_table_checker(table) == hash_eq)
45878 	    {
45879 	      if (is_number(key)) /* (((type(key) >= T_INTEGER) && (type(key) < T_C_MACRO)) || (type(key) == T_PAIR)), but we might want eq? */
45880 		return(s7_error(sc, sc->wrong_type_arg_symbol,
45881 				set_elist_3(sc, wrap_string(sc, "hash-table-set! key ~S, is ~A, but the hash-table's key function is eq?", 71),
45882 					    key, type_name_string(sc, key))));
45883 	    }
45884 	  else
45885 	    {
45886 #if WITH_PURE_S7
45887 	      if (((hash_table_checker(table) == hash_string) && (!is_string(key))) ||
45888 		  ((hash_table_checker(table) == hash_char) && (!s7_is_character(key))))
45889 		return(s7_error(sc, sc->wrong_type_arg_symbol,
45890 				set_elist_4(sc, wrap_string(sc, "hash-table-set! key ~S, is ~A, but the hash-table's key function is ~A", 70),
45891 					    key, type_name_string(sc, key),
45892 					    (hash_table_checker(table) == hash_string) ? sc->string_eq_symbol : sc->char_eq_symbol)));
45893 #else
45894 	      if ((((hash_table_checker(table) == hash_string) || (hash_table_checker(table) == hash_ci_string)) &&
45895 		   (!is_string(key))) ||
45896 		  (((hash_table_checker(table) == hash_char) || (hash_table_checker(table) == hash_ci_char)) &&
45897 		   (!s7_is_character(key))))
45898 		return(s7_error(sc, sc->wrong_type_arg_symbol,
45899 				set_elist_4(sc, wrap_string(sc, "hash-table-set! key ~S, is ~A, but the hash-table's key function is ~A", 70),
45900 					    key, type_name_string(sc, key),
45901 					    (hash_table_checker(table) == hash_string) ? sc->string_eq_symbol :
45902 					    ((hash_table_checker(table) == hash_ci_string) ? sc->string_ci_eq_symbol :
45903 					     ((hash_table_checker(table) == hash_char) ? sc->char_eq_symbol : sc->char_ci_eq_symbol)))));
45904 #endif
45905 	    }}}
45906 
45907   p = mallocate_block(sc);
45908   hash_entry_key(p) = key;
45909   hash_entry_set_value(p, T_Pos(value));
45910   hash_entry_set_raw_hash(p, hash_loc(sc, table, key));
45911   hash_mask = hash_table_mask(table);
45912   loc = hash_entry_raw_hash(p) & hash_mask;
45913   hash_entry_next(p) = hash_table_element(table, loc);
45914   hash_table_element(table, loc) = p;
45915   hash_table_entries(table)++;
45916   if (hash_table_entries(table) > hash_mask)
45917     resize_hash_table(sc, table);
45918 
45919   return(value);
45920 }
45921 
45922 static s7_pointer g_hash_table_set(s7_scheme *sc, s7_pointer args)
45923 {
45924   #define H_hash_table_set "(hash-table-set! table key value) sets the value associated with key in the hash table to value"
45925   #define Q_hash_table_set s7_make_signature(sc, 4, sc->T, sc->is_hash_table_symbol, sc->T, sc->T)
45926 
45927   s7_pointer table;
45928   table = car(args);
45929   if (!is_mutable_hash_table(table))
45930     return(mutable_method_or_bust(sc, table, sc->hash_table_set_symbol, args, T_HASH_TABLE, 1));
45931   return(s7_hash_table_set(sc, table, cadr(args), caddr(args)));
45932 }
45933 
45934 static s7_pointer hash_table_set_p_ppp(s7_scheme *sc, s7_pointer p1, s7_pointer p2, s7_pointer p3)
45935 {
45936   if (!is_mutable_hash_table(p1))  /* is_hash_table(p1) is here */
45937     return(mutable_method_or_bust_ppp(sc, p1, sc->hash_table_set_symbol, p1, p2, p3, T_HASH_TABLE, 1));
45938   return(s7_hash_table_set(sc, p1, p2, p3));
45939 }
45940 
45941 static s7_pointer hash_table_set_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
45942 {
45943  if ((args == 3) && (optimize_op(expr) == HOP_SSA_DIRECT)) /* a tedious experiment... */ /* this could be HOP_FX_C_SSA if no SSA_DIRECT */
45944    {
45945      s7_pointer val;
45946      val = cadddr(expr);
45947      if ((is_pair(val)) && (car(val) == sc->add_symbol) && (is_proper_list_3(sc, val)) &&
45948 	 ((cadr(val) == int_one) || (caddr(val) == int_one)))
45949        {
45950 	 s7_pointer add1;
45951 	 add1 = (cadr(val) == int_one) ? caddr(val) : cadr(val);
45952 	 if ((is_pair(add1)) && (car(add1) == sc->or_symbol) && (is_proper_list_3(sc, add1)) &&
45953 	     (caddr(add1) == int_zero))
45954 	   {
45955 	     s7_pointer or1;
45956 	     or1 = cadr(add1);
45957 	     if ((is_pair(or1)) && (car(or1) == sc->hash_table_ref_symbol) && (is_proper_list_3(sc, or1)) &&
45958 		 (cadr(or1) == cadr(expr)) && (caddr(or1) == caddr(expr)))
45959 	       /* (hash-table-set! counts p (+ (or (hash-table-ref counts p) 0) 1)) -- ssa_direct and hop_safe_c_ss */
45960 	       set_optimize_op(expr, HOP_HASH_TABLE_INCREMENT);
45961 	   }}}
45962  return(f);
45963 }
45964 
45965 
45966 /* -------------------------------- hash-table -------------------------------- */
45967 
45968 static inline s7_pointer hash_table_add(s7_scheme *sc, s7_pointer table, s7_pointer key, s7_pointer value)
45969 {
45970   s7_int hash, hash_mask, loc;
45971   hash_entry_t *x, *p;
45972 
45973   if (!hash_chosen(table))
45974     hash_table_set_checker(table, type(key)); /* raw_hash value (hash_loc(sc, table, key)) does not change via hash_table_set_checker etc */
45975 
45976   hash_mask = hash_table_mask(table);
45977   hash = hash_loc(sc, table, key);
45978   loc = hash & hash_mask;
45979 
45980   for (x = hash_table_element(table, loc); x; x = hash_entry_next(x))
45981     if ((hash_entry_raw_hash(x) == hash) &&
45982 	(s7_is_equal(sc, hash_entry_key(x), key)))
45983       return(value);
45984 
45985   p = mallocate_block(sc);
45986   hash_entry_key(p) = key;
45987   hash_entry_set_value(p, T_Pos(value));
45988   hash_entry_set_raw_hash(p, hash);
45989   hash_entry_next(p) = hash_table_element(table, loc);
45990   hash_table_element(table, loc) = p;
45991 
45992   hash_table_entries(table)++;
45993   if (hash_table_entries(table) > hash_mask)
45994     resize_hash_table(sc, table);
45995 
45996   return(value);
45997 }
45998 
45999 static s7_pointer g_hash_table(s7_scheme *sc, s7_pointer args)
46000 {
46001   #define H_hash_table "(hash-table ...) returns a hash-table containing the symbol/value pairs passed as its arguments. \
46002 That is, (hash-table 'a 1 'b 2) returns a new hash-table with the two key/value pairs preinstalled."
46003   #define Q_hash_table s7_make_circular_signature(sc, 1, 2, sc->is_hash_table_symbol, sc->T)
46004 
46005   s7_int len;
46006   s7_pointer ht;
46007 
46008   len = proper_list_length(args);
46009   if (len & 1)
46010     return(s7_error(sc, sc->wrong_number_of_args_symbol,
46011 		    set_elist_2(sc, wrap_string(sc, "hash-table got an odd number of arguments: ~S", 45), args)));
46012   len /= 2;
46013   ht = s7_make_hash_table(sc, (len > sc->default_hash_table_length) ? len : sc->default_hash_table_length);
46014   if (len > 0)
46015     {
46016       s7_pointer x, y;
46017       for (x = args, y = cdr(args); is_pair(x); x = cddr(x), y = unchecked_cdr(cdr(y)))
46018 	if (car(y) != sc->F)
46019 	  hash_table_add(sc, ht, car(x), car(y));
46020     }
46021   return(ht);
46022 }
46023 
46024 static s7_pointer g_hash_table_2(s7_scheme *sc, s7_pointer args)
46025 {
46026   s7_pointer ht;
46027   ht = s7_make_hash_table(sc, sc->default_hash_table_length);
46028   if (cadr(args) != sc->F)
46029     hash_table_add(sc, ht, car(args), cadr(args));
46030   return(ht);
46031 }
46032 
46033 
46034 /* -------------------------------- weak-hash-table -------------------------------- */
46035 static s7_pointer g_weak_hash_table(s7_scheme *sc, s7_pointer args)
46036 {
46037   #define H_weak_hash_table "(weak-hash-table ...) returns a weak-hash-table containing the symbol/value pairs passed as its arguments. \
46038 That is, (weak-hash-table 'a 1 'b 2) returns a new weak-hash-table with the two key/value pairs preinstalled."
46039   #define Q_weak_hash_table Q_hash_table
46040 
46041   s7_pointer table;
46042   table = g_hash_table(sc, args);
46043   set_weak_hash_table(table);
46044   weak_hash_iters(table) = 0;
46045   return(table);
46046 }
46047 
46048 static s7_pointer hash_table_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
46049 {
46050   return((args == 2) ? sc->hash_table_2 : f);
46051 }
46052 
46053 static void check_old_hash(s7_scheme *sc, s7_pointer old_hash, s7_pointer new_hash, s7_int start, s7_int end)
46054 {
46055   s7_int i, old_len, count = 0;
46056   hash_entry_t **old_lists;
46057   hash_entry_t *x;
46058 
46059   old_len = hash_table_mask(old_hash) + 1;
46060   old_lists = hash_table_elements(old_hash);
46061 
46062   for (i = 0; i < old_len; i++)
46063     for (x = old_lists[i]; x; x = hash_entry_next(x))
46064       {
46065 	if (count >= end)
46066 	  return;
46067 	if (count >= start)
46068 	  check_hash_types(sc, new_hash, hash_entry_key(x), hash_entry_value(x));
46069       }
46070 }
46071 
46072 static s7_pointer hash_table_copy(s7_scheme *sc, s7_pointer old_hash, s7_pointer new_hash, s7_int start, s7_int end)
46073 {
46074   s7_int i, old_len, new_mask, count = 0;
46075   hash_entry_t **old_lists, **new_lists;
46076   hash_entry_t *x, *p;
46077 
46078   if ((is_typed_hash_table(new_hash)) &&
46079       (sc->safety >= NO_SAFETY) &&
46080       ((!is_typed_hash_table(old_hash)) ||
46081        (hash_table_key_typer(old_hash) != hash_table_key_typer(new_hash)) ||
46082        (hash_table_value_typer(old_hash) != hash_table_value_typer(new_hash))))
46083     check_old_hash(sc, old_hash, new_hash, start, end);
46084 
46085   old_len = hash_table_mask(old_hash) + 1;
46086   new_mask = hash_table_mask(new_hash);
46087   old_lists = hash_table_elements(old_hash);
46088   new_lists = hash_table_elements(new_hash);
46089 
46090   if (hash_table_entries(new_hash) == 0)
46091     {
46092       hash_table_checker(new_hash) = hash_table_checker(old_hash);
46093       if (hash_chosen(old_hash)) hash_set_chosen(new_hash);
46094       if ((start == 0) &&
46095 	  (end >= hash_table_entries(old_hash)))
46096 	{
46097 	  for (i = 0; i < old_len; i++)
46098 	    for (x = old_lists[i]; x; x = hash_entry_next(x))
46099 	      {
46100 		s7_int loc;
46101 		loc = hash_entry_raw_hash(x) & new_mask;
46102 		p = make_hash_entry(sc, hash_entry_key(x), hash_entry_value(x), hash_entry_raw_hash(x));
46103 		hash_entry_next(p) = new_lists[loc];
46104 		new_lists[loc] = p;
46105 	      }
46106 	  hash_table_entries(new_hash) = hash_table_entries(old_hash);
46107 	  return(new_hash);
46108 	}
46109       for (i = 0; i < old_len; i++)
46110 	for (x = old_lists[i]; x; x = hash_entry_next(x))
46111 	  {
46112 	    if (count >= end)
46113 	      {
46114 		hash_table_entries(new_hash) = end - start;
46115 		return(new_hash);
46116 	      }
46117 	    if (count >= start)
46118 	      {
46119 		s7_int loc;
46120 		loc = hash_entry_raw_hash(x) & new_mask;
46121 		p = make_hash_entry(sc, hash_entry_key(x), hash_entry_value(x), hash_entry_raw_hash(x));
46122 		hash_entry_next(p) = new_lists[loc];
46123 		new_lists[loc] = p;
46124 	      }
46125 	    count++;
46126 	  }
46127       hash_table_entries(new_hash) = count - start;
46128       return(new_hash);
46129     }
46130 
46131   /* this can't be optimized much because we have to look for key matches (we're copying old_hash into the existing, non-empty new_hash) */
46132   for (i = 0; i < old_len; i++)
46133     for (x = old_lists[i]; x; x = hash_entry_next(x))
46134       {
46135 	if (count >= end)
46136 	  return(new_hash);
46137 	if (count >= start)
46138 	  {
46139 	    hash_entry_t *y;
46140 	    y = (*hash_table_checker(new_hash))(sc, new_hash, hash_entry_key(x));
46141 	    if (y != sc->unentry)
46142 	      hash_entry_set_value(y, hash_entry_value(x));
46143 	    else
46144 	      {
46145 		s7_int loc;
46146 		loc = hash_entry_raw_hash(x) & new_mask;
46147 		p = make_hash_entry(sc, hash_entry_key(x), hash_entry_value(x), hash_entry_raw_hash(x));
46148 		hash_entry_next(p) = new_lists[loc];
46149 		new_lists[loc] = p;
46150 		hash_table_entries(new_hash)++;
46151 		if (!hash_chosen(new_hash))
46152 		  hash_table_set_checker(new_hash, type(hash_entry_key(x)));
46153 	      }}
46154 	count++;
46155       }
46156   return(new_hash);
46157 }
46158 
46159 static s7_pointer hash_table_fill(s7_scheme *sc, s7_pointer args)
46160 {
46161   s7_pointer val, table;
46162   table = car(args);
46163   if (is_immutable(table))
46164     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->fill_symbol, table)));
46165 
46166   val = cadr(args);
46167   if (hash_table_entries(table) > 0)
46168     {
46169       s7_int len;
46170       hash_entry_t **entries;
46171       entries = hash_table_elements(table);
46172       len = hash_table_mask(table) + 1;      /* minimum len is 2 (see s7_make_hash_table) */
46173       if (val == sc->F)                      /* hash-table-ref returns #f if it can't find a key, so val == #f here means empty the table */
46174 	{
46175 	  hash_entry_t **hp, **hn;
46176 	  hash_entry_t *p;
46177 	  hp = entries;
46178 	  hn = (hash_entry_t **)(hp + len);
46179 	  for (; hp < hn; hp++)
46180 	    {
46181 	      if (*hp)
46182 		{
46183 		  p = *hp;
46184 		  while (hash_entry_next(p)) p = hash_entry_next(p);
46185 		  hash_entry_next(p) = sc->block_lists[BLOCK_LIST];
46186 		  sc->block_lists[BLOCK_LIST] = *hp;
46187 		}
46188 	      hp++;
46189 	      if (*hp)
46190 		{
46191 		  p = *hp;
46192 		  while (hash_entry_next(p)) p = hash_entry_next(p);
46193 		  hash_entry_next(p) = sc->block_lists[BLOCK_LIST];
46194 		  sc->block_lists[BLOCK_LIST] = *hp;
46195 		}}
46196 	  if (len >= 8)
46197 	    memclr64(entries, len * sizeof(hash_entry_t *));
46198 	  else memclr(entries, len * sizeof(hash_entry_t *));
46199 	  if (!hash_table_checker_locked(table))
46200 	    {
46201 	      hash_table_checker(table) = hash_empty;
46202 	      hash_clear_chosen(table);
46203 	    }
46204 	  hash_table_entries(table) = 0;
46205 	}
46206       else
46207 	{
46208 	  s7_int i;
46209 	  hash_entry_t *x;
46210 
46211 	  if ((is_typed_hash_table(table)) &&
46212 	      (((is_c_function(hash_table_value_typer(table))) &&
46213 		(c_function_call(hash_table_value_typer(table))(sc, set_plist_1(sc, val)) == sc->F)) ||
46214 	       ((is_any_closure(hash_table_value_typer(table))) &&
46215 		(s7_apply_function(sc, hash_table_value_typer(table), set_plist_1(sc, val)) == sc->F))))
46216 	    s7_wrong_type_arg_error(sc, "fill!", 2, val,
46217 				    make_type_name(sc, hash_table_typer_name(sc, hash_table_value_typer(table)), INDEFINITE_ARTICLE));
46218 	  for (i = 0; i < len; i++)
46219 	    for (x = entries[i]; x; x = hash_entry_next(x))
46220 	      hash_entry_set_value(x, val);
46221 	  /* keys haven't changed, so no need to mess with hash_table_checker */
46222 	}}
46223   return(val);
46224 }
46225 
46226 static s7_pointer hash_table_reverse(s7_scheme *sc, s7_pointer old_hash)
46227 {
46228   s7_int i, len;
46229   s7_pointer new_hash;
46230   hash_entry_t **old_lists;
46231   s7_int gc_loc;
46232 
46233   len = hash_table_mask(old_hash) + 1;
46234   new_hash = s7_make_hash_table(sc, len);
46235   gc_loc = s7_gc_protect_1(sc, new_hash);
46236 
46237   /* I don't think the original hash functions can make any sense in general, so ignore them */
46238   old_lists = hash_table_elements(old_hash);
46239   for (i = 0; i < len; i++)
46240     {
46241       hash_entry_t *x;
46242       for (x = old_lists[i]; x; x = hash_entry_next(x))
46243 	s7_hash_table_set(sc, new_hash, hash_entry_value(x), hash_entry_key(x));
46244     }
46245   s7_gc_unprotect_at(sc, gc_loc);
46246   return(new_hash);
46247 }
46248 
46249 
46250 /* -------------------------------- functions -------------------------------- */
46251 
46252 bool s7_is_function(s7_pointer p) {return(is_c_function(p));}
46253 
46254 static s7_pointer fallback_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
46255 {
46256   return(f);
46257 }
46258 
46259 static void s7_function_set_class(s7_scheme *sc, s7_pointer f, s7_pointer base_f)
46260 {
46261   c_function_class(f) = c_function_class(base_f);
46262   c_function_set_base(f, base_f);
46263 }
46264 
46265 static s7_pointer make_function(s7_scheme *sc, const char *name, s7_function f, s7_int req, s7_int opt, bool rst, const char *doc, s7_pointer x, c_proc_t *ptr)
46266 {
46267   uint32_t ftype = T_C_FUNCTION;
46268   if (req == 0)
46269     {
46270       if (rst)
46271 	ftype = T_C_ANY_ARGS_FUNCTION;
46272       else
46273 	if (opt != 0)
46274 	  ftype = T_C_OPT_ARGS_FUNCTION;
46275     }
46276   else
46277     if (rst)
46278       ftype = T_C_RST_ARGS_FUNCTION;
46279 
46280   set_full_type(x, ftype);
46281 
46282   c_function_data(x) = ptr;
46283   c_function_call(x) = f;               /* f is T_App but needs cast */
46284   c_function_set_base(x, x);
46285   c_function_set_setter(x, sc->F);
46286   c_function_name(x) = name;            /* (procedure-name proc) => (format #f "~A" proc) */
46287   c_function_name_length(x) = safe_strlen(name);
46288   c_function_documentation(x) = (doc) ? make_permanent_c_string(sc, doc) : NULL;
46289   c_function_signature(x) = sc->F;
46290 
46291   c_function_required_args(x) = req;
46292   c_function_optional_args(x) = opt;    /* T_C_FUNCTION_STAR type may be set later, so T_Fst not usable here */
46293   c_function_all_args(x) = (rst) ? MAX_ARITY : req + opt;
46294 
46295   c_function_class(x) = ++sc->f_class;
46296   c_function_chooser(x) = fallback_chooser;
46297   c_function_opt_data(x) = NULL;
46298   c_function_marker(x) = NULL;
46299   c_function_symbol(x) = NULL;
46300 
46301   return(x);
46302 }
46303 
46304 static s7_pointer s7_lambda(s7_scheme *sc, s7_function f, s7_int required_args, s7_int optional_args, bool rest_arg)
46305 {
46306   /* same as s7_make_function but the new function is not global and permanent; it can be GC'd */
46307   s7_pointer fnc;
46308   block_t *block;
46309   new_cell(sc, fnc, T_PAIR);  /* just a place-holder, make_function will set its type and return it */
46310   block = mallocate(sc, sizeof(c_proc_t));
46311   fnc = make_function(sc, "#<c-function>", f, required_args, optional_args, rest_arg, NULL, fnc, (c_proc_t *)block_data(block));
46312   c_function_block(fnc) = block;
46313   add_lambda(sc, fnc);
46314   return(fnc);
46315 }
46316 
46317 static c_proc_t *alloc_permanent_function(s7_scheme *sc)
46318 {
46319   #define ALLOC_FUNCTION_SIZE 128
46320   if (sc->alloc_function_k == ALLOC_FUNCTION_SIZE)
46321     {
46322       sc->alloc_function_cells = (c_proc_t *)malloc(ALLOC_FUNCTION_SIZE * sizeof(c_proc_t));
46323       add_saved_pointer(sc, sc->alloc_function_cells);
46324       sc->alloc_function_k = 0;
46325     }
46326   return(&(sc->alloc_function_cells[sc->alloc_function_k++]));
46327 }
46328 
46329 s7_pointer s7_make_function(s7_scheme *sc, const char *name, s7_function f, s7_int required_args, s7_int optional_args, bool rest_arg, const char *doc)
46330 {
46331   s7_pointer x;
46332   x = alloc_pointer(sc);
46333   x = make_function(sc, name, f, required_args, optional_args, rest_arg, doc, x, alloc_permanent_function(sc));
46334   unheap(sc, x);
46335   return(x);
46336 }
46337 
46338 s7_pointer s7_make_safe_function(s7_scheme *sc, const char *name, s7_function f,
46339 				 s7_int required_args, s7_int optional_args, bool rest_arg, const char *doc)
46340 {
46341   s7_pointer p;
46342   p = s7_make_function(sc, name, f, required_args, optional_args, rest_arg, doc);
46343   set_type_bit(p, T_SAFE_PROCEDURE);
46344   return(p);
46345 }
46346 
46347 s7_pointer s7_make_typed_function(s7_scheme *sc, const char *name, s7_function f,
46348 				  s7_int required_args, s7_int optional_args, bool rest_arg, const char *doc, s7_pointer signature)
46349 {
46350   s7_pointer func;
46351   func = s7_make_function(sc, name, f, required_args, optional_args, rest_arg, doc);
46352   set_type_bit(func, T_SAFE_PROCEDURE);
46353   if (signature) c_function_signature(func) = signature;
46354   return(func);
46355 }
46356 
46357 
46358 /* -------------------------------- procedure? -------------------------------- */
46359 bool s7_is_procedure(s7_pointer x) {return(is_procedure(x));}
46360 
46361 static s7_pointer g_is_procedure(s7_scheme *sc, s7_pointer args)
46362 {
46363   #define H_is_procedure "(procedure? obj) returns #t if obj is a procedure"
46364   #define Q_is_procedure sc->pl_bt
46365 
46366   return(make_boolean(sc, is_procedure(car(args))));
46367 }
46368 
46369 
46370 static void s7_function_set_setter(s7_scheme *sc, const char *getter, const char *setter)
46371 {
46372   /* this is internal, used only with c_function setters, so we don't need to worry about the GC mark choice */
46373   c_function_set_setter(s7_name_to_value(sc, getter), s7_name_to_value(sc, setter));
46374 }
46375 
46376 s7_pointer s7_closure_body(s7_scheme *sc, s7_pointer p) {return((has_closure_let(p)) ? closure_body(p) : sc->nil);}
46377 s7_pointer s7_closure_let(s7_scheme *sc, s7_pointer p)  {return((has_closure_let(p)) ? closure_let(p)  : sc->nil);}
46378 s7_pointer s7_closure_args(s7_scheme *sc, s7_pointer p) {return((has_closure_let(p)) ? closure_args(p) : sc->nil);}
46379 
46380 
46381 /* -------------------------------- procedure-source -------------------------------- */
46382 static s7_pointer procedure_type_to_symbol(s7_scheme *sc, int32_t type)
46383 {
46384   switch (type)
46385     {
46386     case T_CLOSURE:      return(sc->lambda_symbol);
46387     case T_CLOSURE_STAR: return(sc->lambda_star_symbol);
46388     case T_MACRO:        return(sc->macro_symbol);
46389     case T_MACRO_STAR:   return(sc->macro_star_symbol);
46390     case T_BACRO:        return(sc->bacro_symbol);
46391     case T_BACRO_STAR:   return(sc->bacro_star_symbol);
46392 #if S7_DEBUGGING
46393     default: fprintf(stderr, "%s[%d] wants %d symbol\n", __func__, __LINE__, type);
46394 #endif
46395     }
46396   return(sc->lambda_symbol);
46397 }
46398 
46399 static s7_pointer g_procedure_source(s7_scheme *sc, s7_pointer args)
46400 {
46401   /* make it look like a scheme-level lambda */
46402   s7_pointer p;
46403   #define H_procedure_source "(procedure-source func) tries to return the definition of func"
46404   #define Q_procedure_source s7_make_signature(sc, 2, sc->is_list_symbol, s7_make_signature(sc, 2, sc->is_procedure_symbol, sc->is_macro_symbol))
46405 
46406   p = car(args);
46407   if (is_symbol(p))
46408     {
46409       p = s7_symbol_value(sc, p);
46410       if (p == sc->undefined)
46411 	return(s7_error(sc, sc->wrong_type_arg_symbol,
46412 			set_elist_2(sc, wrap_string(sc, "procedure-source arg, '~S, is unbound", 37), p)));
46413     }
46414 
46415   if ((is_c_function(p)) || (is_c_macro(p)))
46416     return(sc->nil);
46417 
46418   check_method(sc, p, sc->procedure_source_symbol, set_plist_1(sc, p));
46419   if (has_closure_let(p))
46420     {
46421       s7_pointer body;
46422       body = closure_body(p);
46423       /* perhaps if this function has been removed from the heap, it would be better to use copy_body (as in s7_copy)? */
46424       if (is_safe_closure_body(body))
46425 	clear_safe_closure_body(body);
46426       return(append_in_place(sc, list_2(sc, procedure_type_to_symbol(sc, type(p)), closure_args(p)), body));
46427     }
46428 
46429   if (!is_procedure(p))
46430     return(simple_wrong_type_argument_with_type(sc, sc->procedure_source_symbol, p,
46431 						wrap_string(sc, "a procedure or a macro", 22)));
46432   return(sc->nil);
46433 }
46434 
46435 
46436 /* -------------------------------- *current-function* -------------------------------- */
46437 
46438 static s7_pointer g_function(s7_scheme *sc, s7_pointer args)
46439 {
46440   #define H_function "(*function* e) returns the current function in e"
46441   #define Q_function s7_make_signature(sc, 3, sc->T, sc->is_let_symbol, sc->is_symbol_symbol)
46442 
46443   s7_pointer e, sym, fname, fval;
46444 
46445   if (is_null(args))
46446     {
46447       for (e = sc->curlet; is_let(e); e = let_outlet(e))
46448 	if ((is_funclet(e)) || (is_maclet(e)))
46449 	  break;
46450     }
46451   else
46452     {
46453       e = car(args);
46454       if (!is_let(e))
46455 	return(simple_wrong_type_argument(sc, sc->_function__symbol, e, T_LET));
46456       if (e == sc->rootlet)
46457 	return(sc->F);
46458       if (!((is_funclet(e)) || (is_maclet(e))))
46459 	e = let_outlet(e);
46460     }
46461   if ((e == sc->rootlet) || (!is_let(e)))
46462     return(sc->F);
46463   if (!((is_funclet(e)) || (is_maclet(e))))
46464     return(sc->F);
46465 
46466   /* for C-defined things like hooks and dilambda, let_file and let_line are 0 */
46467   if ((is_null(args)) || (is_null(cdr(args))))
46468     {
46469       if ((has_let_file(e)) &&
46470 	  (let_file(e) <= (s7_int)sc->file_names_top) &&
46471 	  (let_line(e) > 0))
46472 	return(list_3(sc, funclet_function(e), sc->file_names[let_file(e)], make_integer(sc, let_line(e))));
46473       return(funclet_function(e));
46474     }
46475 
46476   sym = cadr(args);
46477   if (!is_symbol(sym))
46478     return(simple_wrong_type_argument(sc, sc->_function__symbol, sym, T_SYMBOL));
46479   if (is_keyword(sym))
46480     sym = keyword_symbol(sym);
46481   fname = funclet_function(e);
46482   fval = s7_symbol_local_value(sc, fname, e);
46483 
46484   if (sym == sc->name_symbol) return(fname);
46485   if (sym == sc->signature_symbol) return(s7_signature(sc, fval));
46486   if (sym == sc->arity_symbol) return(s7_arity(sc, fval));
46487   if (sym == sc->documentation_symbol) return(s7_make_string(sc, s7_documentation(sc, fval)));
46488   if (sym == sc->value_symbol) return(fval);
46489   if ((sym == sc->line_symbol) && (has_let_file(e))) return(make_integer(sc, let_line(e)));
46490   if ((sym == sc->file_symbol) && (has_let_file(e))) return(sc->file_names[let_file(e)]);
46491   if (sym == make_symbol(sc, "funclet")) return(e);
46492   if (sym == make_symbol(sc, "source")) return(g_procedure_source(sc, set_plist_1(sc, fval)));
46493   if ((sym == make_symbol(sc, "arglist")) && ((is_any_closure(fval)) || (is_any_macro(fval)))) return(closure_args(fval));
46494   return(sc->F);
46495 }
46496 
46497 
46498 /* -------------------------------- funclet -------------------------------- */
46499 s7_pointer s7_funclet(s7_scheme *sc, s7_pointer p) {return((has_closure_let(p)) ? closure_let(p) : sc->rootlet);}
46500 
46501 static s7_pointer g_funclet(s7_scheme *sc, s7_pointer args)
46502 {
46503   s7_pointer p, e;
46504   #define H_funclet "(funclet func) tries to return a function's definition environment"
46505   #define Q_funclet s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_let_symbol, sc->is_null_symbol), \
46506 				      s7_make_signature(sc, 3, sc->is_procedure_symbol, sc->is_macro_symbol, sc->is_symbol_symbol))
46507   p = car(args);
46508   if (is_symbol(p))
46509     {
46510       p = s7_symbol_value(sc, p);
46511       if (p == sc->undefined)
46512 	return(s7_error(sc, sc->wrong_type_arg_symbol,
46513 			set_elist_2(sc, wrap_string(sc, "funclet arg, '~S, is unbound", 28), car(args)))); /* not p here */
46514     }
46515   check_method(sc, p, sc->funclet_symbol, args);
46516 
46517   if (!((is_any_procedure(p)) || (is_c_object(p))))
46518     return(simple_wrong_type_argument_with_type(sc, sc->funclet_symbol, p,
46519 						wrap_string(sc, "a procedure or a macro", 22)));
46520   e = find_let(sc, p);
46521   if ((is_null(e)) &&
46522       (!is_c_object(p))) /* why this complication? */
46523     return(sc->rootlet);
46524 
46525   return(e);
46526 }
46527 
46528 s7_pointer s7_define_function(s7_scheme *sc, const char *name, s7_function fnc,
46529 			      s7_int required_args, s7_int optional_args, bool rest_arg, const char *doc)
46530 {
46531   s7_pointer func, sym;
46532   func = s7_make_function(sc, name, fnc, required_args, optional_args, rest_arg, doc);
46533   sym = make_symbol(sc, name);
46534   s7_define(sc, sc->nil, sym, func);
46535   return(sym);
46536 }
46537 
46538 s7_pointer s7_define_safe_function(s7_scheme *sc, const char *name, s7_function fnc,
46539 				   s7_int required_args, s7_int optional_args, bool rest_arg, const char *doc)
46540 {
46541   /* returns (string->symbol name), not the c_proc_t func */
46542   s7_pointer func, sym;
46543   func = s7_make_safe_function(sc, name, fnc, required_args, optional_args, rest_arg, doc);
46544   sym = make_symbol(sc, name);
46545   s7_define(sc, sc->nil, sym, func);
46546   return(sym);
46547 }
46548 
46549 s7_pointer s7_define_typed_function(s7_scheme *sc, const char *name, s7_function fnc,
46550 				    s7_int required_args, s7_int optional_args, bool rest_arg,
46551 				    const char *doc, s7_pointer signature)
46552 {
46553   /* returns (string->symbol name), not the c_proc_t func */
46554   s7_pointer func, sym;
46555   func = s7_make_typed_function(sc, name, fnc, required_args, optional_args, rest_arg, doc, signature);
46556   sym = make_symbol(sc, name);
46557   s7_define(sc, sc->nil, sym, func);
46558   c_function_set_marker(func, NULL);
46559   return(sym);
46560 }
46561 
46562 static s7_pointer define_bool_function(s7_scheme *sc, const char *name, s7_function fnc,
46563 				       s7_int optional_args, const char *doc, s7_pointer signature, int32_t sym_to_type,
46564 				       void (*marker)(s7_pointer p, s7_int top),
46565 				       bool simple, s7_function bool_setter)
46566 {
46567   s7_pointer func, sym;
46568   func = s7_make_typed_function(sc, name, fnc, 1, optional_args, false, doc, signature);
46569   sym = make_symbol(sc, name);
46570   s7_define(sc, sc->nil, sym, func);
46571   if (sym_to_type != T_FREE)
46572     symbol_set_type(sym, sym_to_type);
46573   c_function_symbol(func) = sym;
46574   c_function_set_marker(func, marker);
46575   if (simple) c_function_set_has_simple_elements(func);
46576   c_function_set_bool_setter(func, s7_make_function(sc, name, bool_setter, 2, 0, false, NULL));
46577   c_function_set_has_bool_setter(func);
46578   return(sym);
46579 }
46580 
46581 s7_pointer s7_define_unsafe_typed_function(s7_scheme *sc, const char *name, s7_function fnc,
46582 					   s7_int required_args, s7_int optional_args, bool rest_arg,
46583 					   const char *doc, s7_pointer signature)
46584 {
46585   /* returns (string->symbol name), not the c_proc_t func */
46586   s7_pointer func, sym;
46587   func = s7_make_function(sc, name, fnc, required_args, optional_args, rest_arg, doc);
46588   if (signature) c_function_signature(func) = signature;
46589   sym = make_symbol(sc, name);
46590   s7_define(sc, sc->nil, sym, func);
46591   return(sym);
46592 }
46593 
46594 s7_pointer s7_define_semisafe_typed_function(s7_scheme *sc, const char *name, s7_function fnc,
46595 					     s7_int required_args, s7_int optional_args, bool rest_arg,
46596 					     const char *doc, s7_pointer signature)
46597 {
46598   s7_pointer func, sym;
46599   func = s7_make_function(sc, name, fnc, required_args, optional_args, rest_arg, doc);
46600   if (signature) c_function_signature(func) = signature;
46601   set_has_safe_args(func);
46602   sym = make_symbol(sc, name);
46603   s7_define(sc, sc->nil, sym, func);
46604   return(sym);
46605 }
46606 
46607 s7_pointer s7_make_function_star(s7_scheme *sc, const char *name, s7_function fnc, const char *arglist, const char *doc)
46608 {
46609   s7_pointer func, local_args;
46610   char *internal_arglist;
46611   s7_int len, n_args;
46612   s7_int gc_loc;
46613   s7_pointer *names, *defaults;
46614   block_t *b;
46615 
46616   len = safe_strlen(arglist) + 8;
46617   b = mallocate(sc, len);
46618   internal_arglist = (char *)block_data(b);
46619   catstrs_direct(internal_arglist, "'(", arglist, ")", (const char *)NULL);
46620   local_args = s7_eval_c_string(sc, internal_arglist);
46621   gc_loc = s7_gc_protect_1(sc, local_args);
46622   liberate(sc, b);
46623   n_args = s7_list_length(sc, local_args);
46624   if (n_args < 0)
46625     {
46626       s7_warn(sc, 256, "%s rest arg is not supported in C-side define*: %s\n", name, arglist);
46627       n_args = -n_args;
46628     }
46629   func = s7_make_function(sc, name, fnc, 0, n_args, false, doc);
46630 
46631   if (n_args > 0)
46632     {
46633       s7_pointer p;
46634       s7_int i;
46635       set_full_type(func, T_C_FUNCTION_STAR | T_UNHEAP); /* unheap from s7_make_function */
46636       c_function_call_args(func) = NULL;
46637 
46638       names = (s7_pointer *)Malloc(n_args * sizeof(s7_pointer));
46639       add_saved_pointer(sc, names);
46640       c_function_arg_names(func) = names;
46641 
46642       defaults = (s7_pointer *)Malloc(n_args * sizeof(s7_pointer));
46643       add_saved_pointer(sc, defaults);
46644       c_function_arg_defaults(func) = defaults;
46645       c_func_set_simple_defaults(func);
46646       /* (define* (f :allow-other-keys) 32) -> :allow-other-keys can't be the only parameter: (:allow-other-keys) */
46647 
46648       for (p = local_args, i = 0; i < n_args; p = cdr(p), i++)
46649 	{
46650 	  s7_pointer arg;
46651 	  arg = car(p);
46652 	  if (arg == sc->key_allow_other_keys_symbol)
46653 	    {
46654 	      if (is_not_null(cdr(p)))
46655 		s7_warn(sc, 256, "%s :allow-other-keys should be the last parameter: %s\n", name, arglist);
46656 	      if (p == local_args)
46657 		s7_warn(sc, 256, "%s :allow-other-keys can't be the only parameter: %s\n", name, arglist);
46658 	      c_function_set_allow_other_keys(func); /* local_args is local, so it can't carry the bit */
46659 	      n_args--;
46660 	      c_function_optional_args(func) = n_args;
46661 	      c_function_all_args(func) = n_args; /* apparently not counting keywords */
46662 	    }
46663 	  else
46664 	    {
46665 	      if (is_pair(arg)) /* there is a default */
46666 		{
46667 		  names[i] = symbol_to_keyword(sc, car(arg));
46668 		  defaults[i] = cadr(arg);
46669 		  s7_remove_from_heap(sc, cadr(arg));
46670 		  if ((is_pair(defaults[i])) ||
46671 		      (is_normal_symbol(defaults[i])))
46672 		    {
46673 		      c_func_clear_simple_defaults(func);
46674 		      mark_function[T_C_FUNCTION_STAR] = mark_c_proc_star;
46675 		    }}
46676 	      else
46677 		{
46678 		  if (arg == sc->key_rest_symbol)
46679 		    s7_warn(sc, 256, "%s :rest is not supported in C-side define*: %s\n", name, arglist);
46680 		  names[i] = symbol_to_keyword(sc, arg);
46681 		  defaults[i] = sc->F;
46682 		}}}}
46683   else set_full_type(func, T_C_FUNCTION | T_UNHEAP);
46684 
46685   s7_gc_unprotect_at(sc, gc_loc);
46686   return(func);
46687 }
46688 
46689 s7_pointer s7_make_safe_function_star(s7_scheme *sc, const char *name, s7_function fnc, const char *arglist, const char *doc)
46690 {
46691   s7_pointer func;
46692   func = s7_make_function_star(sc, name, fnc, arglist, doc);
46693   set_full_type(func, full_type(func) | T_SAFE_PROCEDURE);   /* don't step on the c_func_has_simple_defaults flag */
46694   if (is_c_function_star(func))                        /* thunk -> c_function */
46695     c_function_call_args(func) = permanent_list(sc, c_function_optional_args(func));
46696   return(func);
46697 }
46698 
46699 static void define_function_star_1(s7_scheme *sc, const char *name, s7_function fnc, const char *arglist, const char *doc, bool safe, s7_pointer signature)
46700 {
46701   s7_pointer func, sym;
46702   if (safe)
46703     func = s7_make_safe_function_star(sc, name, fnc, arglist, doc);
46704   else func = s7_make_function_star(sc, name, fnc, arglist, doc);
46705   sym = make_symbol(sc, name);
46706   s7_define(sc, sc->nil, sym, func);
46707   if (signature) c_function_signature(func) = signature;
46708 }
46709 
46710 void s7_define_function_star(s7_scheme *sc, const char *name, s7_function fnc, const char *arglist, const char *doc)
46711 {
46712   define_function_star_1(sc, name, fnc, arglist, doc, false, NULL);
46713 }
46714 
46715 void s7_define_safe_function_star(s7_scheme *sc, const char *name, s7_function fnc, const char *arglist, const char *doc)
46716 {
46717   define_function_star_1(sc, name, fnc, arglist, doc, true, NULL);
46718 }
46719 
46720 void s7_define_typed_function_star(s7_scheme *sc, const char *name, s7_function fnc, const char *arglist, const char *doc, s7_pointer signature)
46721 {
46722   define_function_star_1(sc, name, fnc, arglist, doc, true, signature);
46723 }
46724 
46725 
46726 s7_pointer s7_define_macro(s7_scheme *sc, const char *name, s7_function fnc,
46727 			   s7_int required_args, s7_int optional_args, bool rest_arg, const char *doc)
46728 {
46729   s7_pointer func, sym;
46730   func = s7_make_function(sc, name, fnc, required_args, optional_args, rest_arg, doc);
46731   set_full_type(func, T_C_MACRO | T_DONT_EVAL_ARGS | T_UNHEAP); /* s7_make_function includes T_UNHEAP */
46732   sym = make_symbol(sc, name);
46733   s7_define(sc, sc->nil, sym, func);
46734   return(sym);
46735 }
46736 
46737 
46738 /* -------------------------------- macro? -------------------------------- */
46739 bool s7_is_macro(s7_scheme *sc, s7_pointer x) {return(is_any_macro(x));}
46740 static bool is_macro_b(s7_pointer x) {return(is_any_macro(x));}
46741 
46742 static s7_pointer g_is_macro(s7_scheme *sc, s7_pointer args)
46743 {
46744   #define H_is_macro "(macro? arg) returns #t if 'arg' is a macro or a bacro"
46745   #define Q_is_macro sc->pl_bt
46746   check_boolean_method(sc, is_any_macro, sc->is_macro_symbol, args);
46747 }
46748 
46749 static s7_pointer s7_macroexpand(s7_scheme *sc, s7_pointer mac, s7_pointer args)
46750 {
46751   push_stack_direct(sc, OP_EVAL_DONE);
46752   sc->code = mac;
46753   sc->args = copy_proper_list_with_arglist_error(sc, args);
46754   sc->curlet = make_let(sc, closure_let(sc->code));
46755   eval(sc, OP_APPLY_LAMBDA);
46756   return(sc->value);
46757 }
46758 
46759 
46760 /* -------------------------------- documentation -------------------------------- */
46761 const char *s7_documentation(s7_scheme *sc, s7_pointer x)
46762 {
46763   s7_pointer val;
46764   if (is_symbol(x))
46765     {
46766       if (is_keyword(x)) return(NULL);
46767       if (symbol_has_help(x))
46768 	return(symbol_help(x));
46769       x = s7_symbol_value(sc, x); /* this is needed by Snd */
46770     }
46771 
46772   if ((is_any_c_function(x)) ||
46773       (is_c_macro(x)))
46774     return((char *)c_function_documentation(x));
46775 
46776   if (is_syntax(x))
46777     return(syntax_documentation(x));
46778 
46779   val = funclet_entry(sc, x, sc->local_documentation_symbol);
46780   if ((val) && (is_string(val)))
46781     return(string_value(val));
46782 
46783   return(NULL);
46784 }
46785 
46786 static s7_pointer g_documentation(s7_scheme *sc, s7_pointer args)
46787 {
46788   s7_pointer p;
46789   #define H_documentation "(documentation obj) returns obj's documentation string"
46790   #define Q_documentation s7_make_signature(sc, 2, sc->is_string_symbol, sc->T) /* should (documentation 1) be an error? */
46791 
46792   p = car(args);
46793   if (is_symbol(p))
46794     {
46795       if ((symbol_has_help(p)) &&
46796 	  (is_global(p)))
46797 	return(s7_make_string(sc, symbol_help(p)));
46798       p = s7_symbol_value(sc, p);
46799     }
46800 
46801   /* (documentation func) should act like (documentation abs) -- available without (openlet (funclet func)) or (openlet func)
46802    *   so we check that case ahead of time here, rather than going through check_method which does not
46803    *   call find_let unless has_active_methods(sc, func).  Adding T_HAS_METHODS to all closures causes other troubles.
46804    */
46805   if (has_closure_let(p))
46806     {
46807       s7_pointer func;
46808       func = funclet_entry(sc, p, sc->documentation_symbol);
46809       if (func)
46810 	return(call_method(sc, p, func, args));
46811     }
46812 
46813   /* it would be neat if this would work (define x (let ((+documentation+ "hio")) (vector 1 2 3))) (documentation x) */
46814   check_method(sc, p, sc->documentation_symbol, args);
46815   return(s7_make_string(sc, s7_documentation(sc, p)));
46816 }
46817 
46818 const char *s7_set_documentation(s7_scheme *sc, s7_pointer sym, const char *new_doc)
46819 {
46820   if (is_keyword(sym)) return(NULL);
46821   if (is_symbol(sym))
46822     {
46823       symbol_set_has_help(sym);
46824       symbol_set_help(sym, copy_string(new_doc));
46825     }
46826   return(new_doc);
46827 }
46828 
46829 
46830 /* -------------------------------- help -------------------------------- */
46831 const char *s7_help(s7_scheme *sc, s7_pointer obj)
46832 {
46833   if (is_syntax(obj))
46834     return(syntax_documentation(obj));
46835 
46836   if (is_symbol(obj))
46837     {
46838       /* here look for name */
46839       if (s7_documentation(sc, obj))
46840 	return(s7_documentation(sc, obj));
46841       obj = s7_symbol_value(sc, obj);
46842     }
46843 
46844   if (is_any_procedure(obj))
46845     return(s7_documentation(sc, obj));
46846 
46847   if (obj == sc->s7_let)
46848     return("*s7* is a let that gives access to s7's internal state: e.g. (*s7* 'print-length)");
46849 
46850   /* if is string, apropos? (can scan symbol table) */
46851   return(NULL);
46852 }
46853 
46854 static s7_pointer g_help(s7_scheme *sc, s7_pointer args)
46855 {
46856   #define H_help "(help obj) returns obj's documentation"
46857   #define Q_help s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_boolean_symbol), sc->T)
46858   const char *doc;
46859 
46860   check_method(sc, car(args), sc->help_symbol, args);
46861   doc = s7_help(sc, car(args));
46862   return((doc) ? s7_make_string(sc, doc) : sc->F);
46863 }
46864 
46865 
46866 /* -------------------------------- signature -------------------------------- */
46867 static void init_signatures(s7_scheme *sc)
46868 {
46869   sc->string_signature =       s7_make_signature(sc, 3, sc->is_char_symbol, sc->is_string_symbol, sc->is_integer_symbol);
46870   sc->byte_vector_signature =  s7_make_circular_signature(sc, 2, 3, sc->is_byte_symbol, sc->is_byte_vector_symbol, sc->is_integer_symbol);
46871   sc->vector_signature =       s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_vector_symbol, sc->is_integer_symbol);
46872   sc->float_vector_signature = s7_make_circular_signature(sc, 2, 3, sc->is_float_symbol, sc->is_float_vector_symbol, sc->is_integer_symbol);
46873   sc->int_vector_signature =   s7_make_circular_signature(sc, 2, 3, sc->is_integer_symbol, sc->is_int_vector_symbol, sc->is_integer_symbol);
46874   sc->c_object_signature =     s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_c_object_symbol, sc->T);
46875   sc->let_signature =          s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_let_symbol, sc->is_symbol_symbol);
46876   sc->hash_table_signature =   s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_hash_table_symbol, sc->T);
46877   sc->pair_signature =         s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_pair_symbol, sc->is_integer_symbol);
46878 }
46879 
46880 static s7_pointer g_signature(s7_scheme *sc, s7_pointer args)
46881 {
46882   s7_pointer p;
46883   #define H_signature "(signature obj) returns obj's signature"
46884   #define Q_signature s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_boolean_symbol), sc->T)
46885 
46886   p = car(args);
46887   switch (type(p))
46888     {
46889     case T_C_FUNCTION:
46890     case T_C_FUNCTION_STAR:
46891     case T_C_ANY_ARGS_FUNCTION:
46892     case T_C_OPT_ARGS_FUNCTION:
46893     case T_C_RST_ARGS_FUNCTION:
46894     case T_C_MACRO:
46895       return((s7_pointer)c_function_signature(p));
46896 
46897     case T_MACRO:   case T_MACRO_STAR:
46898     case T_BACRO:   case T_BACRO_STAR:
46899     case T_CLOSURE: case T_CLOSURE_STAR:
46900       {
46901 	s7_pointer func;
46902 	func = funclet_entry(sc, p, sc->local_signature_symbol);
46903 	if (func) return(func);
46904 	func = funclet_entry(sc, p, sc->signature_symbol);
46905 	return((func) ? call_method(sc, p, func, args) : sc->F);
46906       }
46907 
46908     case T_VECTOR:
46909       if (vector_length(p) == 0) return(sc->F); /* sig () is #f so sig #() should be #f */
46910       if (!is_typed_vector(p))
46911 	return(sc->vector_signature);
46912       {
46913 	s7_pointer lst;
46914 	lst = list_3(sc, typed_vector_typer_symbol(sc, p), sc->is_vector_symbol, sc->is_integer_symbol);
46915 	cdddr(lst) = cddr(lst);
46916 	return(lst);
46917       }
46918 
46919     case T_FLOAT_VECTOR: return((vector_length(p) == 0) ? sc->F : sc->float_vector_signature);
46920     case T_INT_VECTOR:   return((vector_length(p) == 0) ? sc->F : sc->int_vector_signature);
46921     case T_BYTE_VECTOR:  return((vector_length(p) == 0) ? sc->F : sc->byte_vector_signature);
46922     case T_PAIR:         return(sc->pair_signature);
46923     case T_STRING:       return(sc->string_signature);
46924 
46925     case T_HASH_TABLE:
46926       if (is_typed_hash_table(p))
46927 	return(list_3(sc,
46928 		      hash_table_typer_symbol(sc, hash_table_value_typer(p)),
46929 		      sc->is_hash_table_symbol,
46930 		      hash_table_typer_symbol(sc, hash_table_key_typer(p))));
46931       return(sc->hash_table_signature);
46932 
46933     case T_ITERATOR:
46934       p = iterator_sequence(p);
46935       if ((is_hash_table(p)) || (is_let(p)))   /* cons returned -- would be nice to include the car/cdr types if known */
46936 	return(list_1(sc, sc->is_pair_symbol));
46937       p = g_signature(sc, set_plist_1(sc, p));
46938       return((is_pair(p)) ? list_1(sc, car(p)) : list_1(sc, sc->T));
46939 
46940     case T_C_OBJECT:
46941       check_method(sc, p, sc->signature_symbol, args);
46942       return(sc->c_object_signature);
46943 
46944     case T_LET:
46945       check_method(sc, p, sc->signature_symbol, args);
46946       return(sc->let_signature);
46947 
46948     case T_SYMBOL:
46949       /* this used to get the symbol's value and call g_signature on that */
46950       {
46951 	s7_pointer slot;
46952 	slot = lookup_slot_from(p, sc->curlet);
46953 	if ((is_slot(slot)) && (slot_has_setter(slot)))
46954 	  {
46955 	    s7_pointer setter;
46956 	    setter = slot_setter(slot);
46957 	    p = g_signature(sc, set_plist_1(sc, setter));
46958 	    if (is_pair(p))
46959 	      return(list_1(sc, car(p)));
46960 	  }}
46961       break;
46962 
46963     default:
46964       break;
46965     }
46966   return(sc->F);
46967 }
46968 
46969 s7_pointer s7_signature(s7_scheme *sc, s7_pointer func)
46970 {
46971   return(g_signature(sc, set_plist_1(sc, func)));
46972 }
46973 
46974 
46975 /* -------------------------------- dynamic-wind -------------------------------- */
46976 static s7_pointer closure_or_f(s7_scheme *sc, s7_pointer p)
46977 {
46978   s7_pointer body;
46979   if (!is_closure(p)) return(p);
46980   body = closure_body(p);
46981   if (is_pair(cdr(body))) return(p);
46982   if (!is_pair(car(body))) return(sc->F);
46983   return((caar(body) == sc->quote_symbol) ? sc->F : p);
46984 }
46985 
46986 static s7_pointer make_baffled_closure(s7_scheme *sc, s7_pointer inp)
46987 {
46988   /* for dynamic-wind to protect initial and final functions from call/cc */
46989   s7_pointer nclo, let;
46990   nclo = make_closure(sc, sc->nil, closure_body(inp), type(inp), 0);
46991   let = make_let_slowly(sc, closure_let(inp)); /* let_outlet(let) = closure_let(inp) */
46992   set_baffle_let(let);
46993   set_let_baffle_key(let, sc->baffle_ctr++);
46994   closure_set_let(nclo, let);
46995   return(nclo);
46996 }
46997 
46998 static bool is_dwind_thunk(s7_scheme *sc, s7_pointer x)
46999 {
47000   switch (type(x))
47001     {
47002     case T_MACRO: case T_BACRO: case T_CLOSURE: case T_MACRO_STAR: case T_BACRO_STAR:  case T_CLOSURE_STAR:
47003       return(is_null(closure_args(x))); /* this is the case that does not match is_aritable -- it could be loosened -- arity=0 below would need fixup */
47004 
47005     case T_C_RST_ARGS_FUNCTION: case T_C_FUNCTION:
47006       return((c_function_required_args(x) <= 0) && (c_function_all_args(x) >= 0));
47007 
47008     case T_C_OPT_ARGS_FUNCTION: case T_C_ANY_ARGS_FUNCTION: case T_C_FUNCTION_STAR:
47009       return(c_function_all_args(x) >= 0);
47010 
47011     case T_C_MACRO:
47012       return((c_macro_required_args(x) <= 0) && (c_macro_all_args(x) >= 0));
47013 
47014     case T_GOTO: case T_CONTINUATION:
47015       return(true);
47016     }
47017   return(false);
47018 }
47019 
47020 static s7_pointer g_dynamic_wind_unchecked(s7_scheme *sc, s7_pointer args)
47021 {
47022   s7_pointer p, inp, outp;
47023 
47024   new_cell(sc, p, T_DYNAMIC_WIND);                          /* don't mark car/cdr, don't copy */
47025   dynamic_wind_in(p) = closure_or_f(sc, car(args));
47026   dynamic_wind_body(p) = cadr(args);
47027   dynamic_wind_out(p) = closure_or_f(sc, caddr(args));
47028 
47029   inp = dynamic_wind_in(p);
47030   if ((is_any_closure(inp)) && (!is_safe_closure(inp)))    /* wrap this use of inp in a with-baffle */
47031     dynamic_wind_in(p) = make_baffled_closure(sc, inp);
47032 
47033   outp = dynamic_wind_out(p);
47034   if ((is_any_closure(outp)) && (!is_safe_closure(outp)))
47035     dynamic_wind_out(p) = make_baffled_closure(sc, outp);
47036 
47037   /* since we don't care about the in and out results, and they are thunks, if the body is not a pair,
47038    *   or is a quoted thing, we just ignore that function.
47039    */
47040   push_stack(sc, OP_DYNAMIC_WIND, sc->nil, p);             /* args will be the saved result, code = s7_dynwind_t obj */
47041   if (inp != sc->F)
47042     {
47043       dynamic_wind_state(p) = DWIND_INIT;
47044       push_stack(sc, OP_APPLY, sc->nil, dynamic_wind_in(p));
47045     }
47046   else
47047     {
47048       dynamic_wind_state(p) = DWIND_BODY;
47049       push_stack(sc, OP_APPLY, sc->nil, dynamic_wind_body(p));
47050     }
47051   return(sc->F);
47052 }
47053 
47054 static s7_pointer g_dynamic_wind(s7_scheme *sc, s7_pointer args)
47055 {
47056   #define H_dynamic_wind "(dynamic-wind init body finish) calls init, then body, then finish, \
47057 each a function of no arguments, guaranteeing that finish is called even if body is exited"
47058   #define Q_dynamic_wind s7_make_circular_signature(sc, 1, 2, sc->values_symbol, sc->is_procedure_symbol)
47059 
47060   if (!is_dwind_thunk(sc, car(args)))
47061     return(method_or_bust_with_type(sc, car(args), sc->dynamic_wind_symbol, args, a_thunk_string, 1));
47062   if (!is_thunk(sc, cadr(args)))
47063     return(method_or_bust_with_type(sc, cadr(args), sc->dynamic_wind_symbol, args, a_thunk_string, 2));
47064   if (!is_dwind_thunk(sc, caddr(args)))
47065     return(method_or_bust_with_type(sc, caddr(args), sc->dynamic_wind_symbol, args, a_thunk_string, 3));
47066 
47067   /* this won't work:
47068        (let ((final (lambda (a b c) (list a b c))))
47069          (dynamic-wind
47070            (lambda () #f)
47071            (lambda () (set! final (lambda () (display "in final"))))
47072            final))
47073    * but why not?  'final' is a thunk by the time it is evaluated. catch (the error handler) is similar.
47074    * It can't work here because we set up the dynamic_wind_out slot below and
47075    *   even if the thunk check was removed, we'd still be trying to apply the original function.
47076    */
47077   return(g_dynamic_wind_unchecked(sc, args));
47078 }
47079 
47080 static bool is_lambda(s7_scheme *sc, s7_pointer sym)
47081 {
47082   return((sym == sc->lambda_symbol) && (symbol_id(sym) == 0)); /* do we need (!sc->in_with_let) ? */
47083   /* symbol_id=0 means it has never been rebound (T_GLOBAL might not be set for initial stuff) */
47084 }
47085 
47086 static bool is_ok_thunk(s7_scheme *sc, s7_pointer arg)
47087 {
47088  return((is_pair(arg)) &&
47089 	(is_lambda(sc, car(arg))) &&
47090 	(is_pair(cdr(arg))) &&
47091 	(is_null(cadr(arg))) &&
47092 	(is_pair(cddr(arg))) &&
47093 	(s7_is_proper_list(sc, cddr(arg))));
47094 }
47095 
47096 static s7_pointer dynamic_wind_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
47097 {
47098   if ((args == 3) &&
47099       (is_ok_thunk(sc, cadr(expr))) &&
47100       (is_ok_thunk(sc, caddr(expr))) &&
47101       (is_ok_thunk(sc, cadddr(expr))))
47102     return(sc->dynamic_wind_unchecked);
47103   return(f);
47104 }
47105 
47106 s7_pointer s7_dynamic_wind(s7_scheme *sc, s7_pointer init, s7_pointer body, s7_pointer finish)
47107 {
47108   /* this is essentially s7_call with a dynamic-wind wrapper around "body" */
47109   s7_pointer p;
47110   declare_jump_info();
47111 
47112   store_jump_info(sc);
47113   set_jump_info(sc, DYNAMIC_WIND_SET_JUMP);
47114   if (jump_loc != NO_JUMP)
47115     {
47116       if (jump_loc != ERROR_JUMP)
47117 	eval(sc, sc->cur_op);
47118     }
47119   else
47120     {
47121       push_stack_direct(sc, OP_EVAL_DONE);
47122       sc->args = sc->nil;
47123 
47124       new_cell(sc, p, T_DYNAMIC_WIND);
47125       dynamic_wind_in(p) = T_Pos(init);
47126       dynamic_wind_body(p) = T_Pos(body);
47127       dynamic_wind_out(p) = T_Pos(finish);
47128       push_stack(sc, OP_DYNAMIC_WIND, sc->nil, p);
47129       if (init != sc->F)
47130 	{
47131 	  dynamic_wind_state(p) = DWIND_INIT;
47132 	  sc->code = init;
47133 	}
47134       else
47135 	{
47136 	  dynamic_wind_state(p) = DWIND_BODY;
47137 	  sc->code = body;
47138 	}
47139       eval(sc, OP_APPLY);
47140     }
47141   restore_jump_info(sc);
47142 
47143   if (is_multiple_value(sc->value))
47144     sc->value = splice_in_values(sc, multiple_value(sc->value));
47145  return(sc->value);
47146 }
47147 
47148 
47149 /* -------------------------------- c-object? -------------------------------- */
47150 bool s7_is_c_object(s7_pointer p) {return(is_c_object(p));}
47151 
47152 static s7_pointer g_is_c_object(s7_scheme *sc, s7_pointer args)
47153 {
47154   #define H_is_c_object "(c-object? obj) returns #t is obj is a c-object."
47155   #define Q_is_c_object sc->pl_bt
47156   s7_pointer obj;
47157   obj = car(args);
47158   if (is_c_object(obj)) return(sc->T);
47159   if (!has_active_methods(sc, obj)) return(sc->F);
47160   return(apply_boolean_method(sc, obj, sc->is_c_object_symbol));
47161 }
47162 
47163 
47164 /* -------------------------------- c-object-type -------------------------------- */
47165 static void fallback_free(void *value) {}
47166 static void fallback_mark(void *value) {}
47167 
47168 static s7_pointer apply_error(s7_scheme *sc, s7_pointer obj, s7_pointer args);
47169 
47170 static s7_pointer fallback_ref(s7_scheme *sc, s7_pointer args)   {return(apply_error(sc, car(args), cdr(args)));}
47171 static s7_pointer fallback_set(s7_scheme *sc, s7_pointer args)   {return(eval_error(sc, "attempt to set ~S?", 18, car(args)));}
47172 static s7_pointer fallback_length(s7_scheme *sc, s7_pointer obj) {return(sc->F);}
47173 s7_int s7_c_object_type(s7_pointer obj) {return((is_c_object(obj)) ? c_object_type(obj) : -1);}
47174 
47175 static s7_pointer g_c_object_type(s7_scheme *sc, s7_pointer args)
47176 {
47177   #define H_c_object_type "(c-object-type obj) returns the c_object's type tag."
47178   #define Q_c_object_type s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_c_object_symbol)
47179 
47180   s7_pointer p;
47181   p = car(args);
47182   if (is_c_object(p))
47183     return(make_integer(sc, c_object_type(p))); /* this is the c_object_types table index = tag */
47184   return(method_or_bust(sc, p, sc->c_object_type_symbol, args, T_C_OBJECT, 0));
47185 }
47186 
47187 static s7_pointer g_c_object_set(s7_scheme *sc, s7_pointer args) /* called in c_object_set_function */
47188 {
47189   s7_pointer obj;
47190   obj = car(args);
47191   if (!is_c_object(obj))
47192     return(simple_wrong_type_argument(sc, make_symbol(sc, "c-object-set!"), obj, T_C_OBJECT));
47193   return((*(c_object_set(sc, obj)))(sc, args));
47194 }
47195 
47196 s7_int s7_make_c_type(s7_scheme *sc, const char *name)
47197 {
47198   s7_int tag;
47199   c_object_t *c_type;
47200   tag = sc->num_c_object_types++;
47201   if (tag >= sc->c_object_types_size)
47202     {
47203       if (sc->c_object_types_size == 0)
47204 	{
47205 	  sc->c_object_types_size = 8;
47206 	  sc->c_object_types = (c_object_t **)Calloc(sc->c_object_types_size, sizeof(c_object_t *));
47207 	}
47208       else
47209 	{
47210 	  sc->c_object_types_size = tag + 8;
47211 	  sc->c_object_types = (c_object_t **)Realloc((void *)(sc->c_object_types), sc->c_object_types_size * sizeof(c_object_t *));
47212 	}}
47213   c_type = (c_object_t *)Calloc(1, sizeof(c_object_t));
47214   sc->c_object_types[tag] = c_type;
47215   c_type->type = tag;
47216   c_type->scheme_name = s7_make_permanent_string(sc, name);
47217   c_type->getter = sc->F;
47218   c_type->setter = sc->F;
47219   c_type->free = fallback_free;
47220   c_type->mark = fallback_mark;
47221   c_type->ref = fallback_ref;
47222   c_type->set = fallback_set;
47223   c_type->outer_type = T_C_OBJECT;
47224   c_type->length = fallback_length;
47225   /* all other fields are NULL */
47226   return(tag);
47227 }
47228 
47229 void s7_c_type_set_free(s7_scheme *sc, s7_int tag, void (*gc_free)(void *value))                               {sc->c_object_types[tag]->free = gc_free;}
47230 void s7_c_type_set_mark(s7_scheme *sc, s7_int tag, void (*mark)(void *value))                                  {sc->c_object_types[tag]->mark = mark;}
47231 void s7_c_type_set_equal(s7_scheme *sc, s7_int tag, bool (*equal)(void *value1, void *value2))                 {sc->c_object_types[tag]->eql = equal;}
47232 void s7_c_type_set_gc_free(s7_scheme *sc, s7_int tag, s7_pointer (*gc_free)(s7_scheme *sc, s7_pointer obj))    {sc->c_object_types[tag]->gc_free = gc_free;}
47233 void s7_c_type_set_gc_mark(s7_scheme *sc, s7_int tag, s7_pointer (*gc_mark)(s7_scheme *sc, s7_pointer obj))    {sc->c_object_types[tag]->gc_mark = gc_mark;}
47234 void s7_c_type_set_is_equal(s7_scheme *sc, s7_int tag, s7_pointer (*is_equal)(s7_scheme *sc, s7_pointer args)) {sc->c_object_types[tag]->equal = is_equal;}
47235 void s7_c_type_set_set(s7_scheme *sc, s7_int tag, s7_pointer (*set)(s7_scheme *sc, s7_pointer args))           {sc->c_object_types[tag]->set = set;}
47236 void s7_c_type_set_length(s7_scheme *sc, s7_int tag, s7_pointer (*length)(s7_scheme *sc, s7_pointer args))     {sc->c_object_types[tag]->length = length;}
47237 void s7_c_type_set_copy(s7_scheme *sc, s7_int tag, s7_pointer (*copy)(s7_scheme *sc, s7_pointer args))         {sc->c_object_types[tag]->copy = copy;}
47238 void s7_c_type_set_fill(s7_scheme *sc, s7_int tag, s7_pointer (*fill)(s7_scheme *sc, s7_pointer args))         {sc->c_object_types[tag]->fill = fill;}
47239 void s7_c_type_set_reverse(s7_scheme *sc, s7_int tag, s7_pointer (*reverse)(s7_scheme *sc, s7_pointer args))   {sc->c_object_types[tag]->reverse = reverse;}
47240 void s7_c_type_set_to_list(s7_scheme *sc, s7_int tag, s7_pointer (*to_list)(s7_scheme *sc, s7_pointer args))   {sc->c_object_types[tag]->to_list = to_list;}
47241 void s7_c_type_set_to_string(s7_scheme *sc, s7_int tag, s7_pointer (*to_string)(s7_scheme *sc, s7_pointer args)) {sc->c_object_types[tag]->to_string = to_string;}
47242 
47243 void s7_c_type_set_is_equivalent(s7_scheme *sc, s7_int tag, s7_pointer (*is_equivalent)(s7_scheme *sc, s7_pointer args))
47244 {
47245   sc->c_object_types[tag]->equivalent = is_equivalent;
47246 }
47247 
47248 void s7_c_type_set_ref(s7_scheme *sc, s7_int tag, s7_pointer (*ref)(s7_scheme *sc, s7_pointer args))
47249 {
47250   sc->c_object_types[tag]->ref = ref;
47251   if (sc->c_object_types[tag]->ref != fallback_ref)
47252     sc->c_object_types[tag]->outer_type = (T_C_OBJECT | T_SAFE_PROCEDURE);
47253 }
47254 
47255 void s7_c_type_set_getter(s7_scheme *sc, s7_int tag, s7_pointer getter)
47256 {
47257 #if S7_DEBUGGING
47258   if (!is_c_function(getter)) fprintf(stderr, "%s[%d]: %p is not a c_function\n", __func__, __LINE__, getter);
47259 #endif
47260   sc->c_object_types[tag]->getter = getter;
47261 }
47262 
47263 void s7_c_type_set_setter(s7_scheme *sc, s7_int tag, s7_pointer setter)
47264 {
47265 #if S7_DEBUGGING
47266   if (!is_c_function(setter)) fprintf(stderr, "%s[%d]: %p is not a c_function\n", __func__, __LINE__, setter);
47267 #endif
47268   sc->c_object_types[tag]->setter = setter;
47269 }
47270 
47271 void *s7_c_object_value(s7_pointer obj) {return(c_object_value(obj));}
47272 
47273 void *s7_c_object_value_checked(s7_pointer obj, s7_int type)
47274 {
47275   if ((is_c_object(obj)) &&
47276       (c_object_type(obj) == type))
47277     return(c_object_value(obj));
47278   return(NULL);
47279 }
47280 
47281 s7_pointer s7_make_c_object_with_let(s7_scheme *sc, s7_int type, void *value, s7_pointer let)
47282 {
47283   s7_pointer x;
47284   new_cell(sc, x, sc->c_object_types[type]->outer_type);
47285 
47286   /* c_object_info(x) = &(sc->c_object_types[type]); */
47287   /* that won't work because c_object_types can move when it is realloc'd and the old stuff is freed by realloc
47288    *   and since we're checking (for example) ref_2 existence as not null, we can't use a table of c_object_t's!
47289    */
47290   c_object_type(x) = type;
47291   c_object_value(x) = value;
47292   c_object_set_let(x, (let == sc->rootlet) ? sc->nil : let);
47293   c_object_s7(x) = sc;
47294   add_c_object(sc, x);
47295   return(x);
47296 }
47297 
47298 s7_pointer s7_make_c_object(s7_scheme *sc, s7_int type, void *value) {return(s7_make_c_object_with_let(sc, type, value, sc->nil));}
47299 
47300 s7_pointer s7_c_object_let(s7_pointer obj) {return(c_object_let(obj));}
47301 
47302 s7_pointer s7_c_object_set_let(s7_scheme *sc, s7_pointer obj, s7_pointer e)
47303 {
47304   if ((!is_immutable(obj)) &&
47305       (is_let(e)))
47306     c_object_set_let(obj, (e == sc->rootlet) ? sc->nil : e);
47307   return(e);
47308 }
47309 
47310 static s7_pointer c_object_length(s7_scheme *sc, s7_pointer obj)
47311 {
47312   if (c_object_len(sc, obj))
47313     return((*(c_object_len(sc, obj)))(sc, set_clist_1(sc, obj)));
47314   return(eval_error(sc, "attempt to get length of ~S?", 28, obj));
47315 }
47316 
47317 static s7_int c_object_length_to_int(s7_scheme *sc, s7_pointer obj)
47318 {
47319   if (c_object_len(sc, obj))
47320     {
47321       s7_pointer res;
47322       res = (*(c_object_len(sc, obj)))(sc, set_clist_1(sc, obj));
47323       if (s7_is_integer(res))
47324 	return(s7_integer_checked(sc, res));
47325     }
47326   return(-1);
47327 }
47328 
47329 static s7_pointer copy_c_object(s7_scheme *sc, s7_pointer args)
47330 {
47331   s7_pointer obj;
47332   obj = car(args);
47333   check_method(sc, obj, sc->copy_symbol, args);
47334   if (c_object_copy(sc, obj))
47335     return((*(c_object_copy(sc, obj)))(sc, args));
47336   return(eval_error(sc, "attempt to copy ~S?", 19, obj));
47337 }
47338 
47339 static s7_pointer c_object_type_to_let(s7_scheme *sc, s7_pointer cobj)
47340 {
47341   return(g_local_inlet(sc, 4,
47342 		       sc->name_symbol, c_object_scheme_name(sc, cobj),
47343 		       sc->setter_symbol, (c_object_set(sc, cobj) != fallback_set) ? sc->c_object_set_function : sc->F));
47344   /* should we make new wrappers every time this is called? or save the let somewhere and reuse it? */
47345 }
47346 
47347 static void apply_c_object(s7_scheme *sc)  /* -------- applicable c_object -------- */
47348 {
47349   sc->value = (*(c_object_ref(sc, sc->code)))(sc, set_ulist_1(sc, sc->code, sc->args));
47350   set_car(sc->u1_1, sc->F);
47351 }
47352 
47353 static bool op_implicit_c_object_ref_a(s7_scheme *sc)
47354 {
47355   s7_pointer c;
47356   c = lookup_checked(sc, car(sc->code));
47357   if (!is_c_object(c)) {sc->last_function = c; return(false);}
47358   set_car(sc->t2_2, fx_call(sc, cdr(sc->code)));
47359   set_car(sc->t2_1, c); /* fx_call above might use sc->t2* */
47360   sc->value = (*(c_object_ref(sc, c)))(sc, sc->t2_1);
47361   return(true);
47362 }
47363 
47364 
47365 /* -------- dilambda -------- */
47366 
47367 s7_pointer s7_dilambda_with_environment(s7_scheme *sc, s7_pointer envir,
47368 					const char *name,
47369 					s7_pointer (*getter)(s7_scheme *sc, s7_pointer args),
47370 					s7_int get_req_args, s7_int get_opt_args,
47371 					s7_pointer (*setter)(s7_scheme *sc, s7_pointer args),
47372 					s7_int set_req_args, s7_int set_opt_args,
47373 					const char *documentation)
47374 {
47375   s7_pointer get_func, set_func;
47376   char *internal_set_name;
47377   s7_int len;
47378 
47379   if (!name) return(sc->F);
47380   len = 16 + safe_strlen(name);
47381   internal_set_name = (char *)Malloc(len);
47382   internal_set_name[0] = '\0';
47383   catstrs_direct(internal_set_name, "[set-", name, "]", (const char *)NULL);
47384   add_saved_pointer(sc, internal_set_name);
47385   get_func = s7_make_safe_function(sc, name, getter, get_req_args, get_opt_args, false, documentation);
47386   s7_define(sc, envir, make_symbol(sc, name), get_func);
47387   set_func = s7_make_function(sc, internal_set_name, setter, set_req_args, set_opt_args, false, documentation);
47388   c_function_set_setter(get_func, set_func);
47389 
47390   return(get_func);
47391 }
47392 
47393 s7_pointer s7_dilambda(s7_scheme *sc,
47394 		       const char *name,
47395 		       s7_pointer (*getter)(s7_scheme *sc, s7_pointer args),
47396 		       s7_int get_req_args, s7_int get_opt_args,
47397 		       s7_pointer (*setter)(s7_scheme *sc, s7_pointer args),
47398 		       s7_int set_req_args, s7_int set_opt_args,
47399 		       const char *documentation)
47400 {
47401   return(s7_dilambda_with_environment(sc, sc->nil, name, getter, get_req_args, get_opt_args, setter, set_req_args, set_opt_args, documentation));
47402 }
47403 
47404 s7_pointer s7_typed_dilambda(s7_scheme *sc,
47405 			     const char *name,
47406 			     s7_pointer (*getter)(s7_scheme *sc, s7_pointer args),
47407 			     s7_int get_req_args, s7_int get_opt_args,
47408 			     s7_pointer (*setter)(s7_scheme *sc, s7_pointer args),
47409 			     s7_int set_req_args, s7_int set_opt_args,
47410 			     const char *documentation,
47411 			     s7_pointer get_sig, s7_pointer set_sig)
47412 {
47413   s7_pointer get_func, set_func;
47414   get_func = s7_dilambda(sc, name, getter, get_req_args, get_opt_args, setter, set_req_args, set_opt_args, documentation);
47415   set_func = c_function_setter(get_func);
47416   if (get_sig) c_function_signature(get_func) = get_sig;
47417   if (set_sig) c_function_signature(set_func) = set_sig;
47418   return(get_func);
47419 }
47420 
47421 static void op_set_dilambda_p(s7_scheme *sc)
47422 {
47423   push_stack_no_args(sc, OP_SET_DILAMBDA_P_1, cdr(sc->code));
47424   sc->code = caddr(sc->code);
47425 }
47426 
47427 static void op_set_dilambda(s7_scheme *sc) /* ([set!] (dilambda-setter g) s) */
47428 {
47429   sc->code = cdr(sc->code);
47430   sc->value = cadr(sc->code);
47431   if (is_symbol(sc->value))
47432     sc->value = lookup_checked(sc, sc->value);
47433 }
47434 
47435 static void op_set_dilambda_sa_a(s7_scheme *sc)
47436 {
47437   s7_pointer code, obj, func, setter;
47438   code = cdr(sc->code);
47439   func = lookup(sc, caar(code));
47440   obj = lookup(sc, cadar(code));
47441   setter = closure_setter(func);
47442   sc->curlet = update_let_with_two_slots(sc, closure_let(setter), obj, fx_call(sc, cdr(code)));
47443   sc->value = fx_call(sc, closure_body(setter));
47444 }
47445 
47446 
47447 /* -------------------------------- dilambda? -------------------------------- */
47448 bool s7_is_dilambda(s7_pointer obj)
47449 {
47450   switch (type(obj))
47451     {
47452     case T_MACRO:   case T_MACRO_STAR:
47453     case T_BACRO:   case T_BACRO_STAR:
47454     case T_CLOSURE: case T_CLOSURE_STAR:
47455       return(is_any_procedure(closure_setter_or_map_list(obj))); /* type >= T_CLOSURE (excludes goto/continuation) */
47456 
47457     case T_C_FUNCTION:
47458     case T_C_ANY_ARGS_FUNCTION:
47459     case T_C_OPT_ARGS_FUNCTION:
47460     case T_C_RST_ARGS_FUNCTION:
47461     case T_C_FUNCTION_STAR:
47462       return(is_any_procedure(c_function_setter(obj)));
47463 
47464     case T_C_MACRO:
47465       return(is_any_procedure(c_macro_setter(obj)));
47466     }
47467   return(false);
47468 }
47469 
47470 static s7_pointer g_is_dilambda(s7_scheme *sc, s7_pointer args)
47471 {
47472   #define H_is_dilambda "(dilambda? obj) returns #t if obj is a procedure with setter."
47473   #define Q_is_dilambda sc->pl_bt
47474   check_boolean_method(sc, s7_is_dilambda, sc->is_dilambda_symbol, args);
47475 }
47476 
47477 
47478 /* -------------------------------- dilambda -------------------------------- */
47479 static s7_pointer g_dilambda(s7_scheme *sc, s7_pointer args)
47480 {
47481   #define H_dilambda "(dilambda getter setter) sets getter's setter to be setter."
47482   #define Q_dilambda s7_make_signature(sc, 3, sc->is_procedure_symbol, sc->is_procedure_symbol, sc->is_procedure_symbol)
47483   s7_pointer getter, setter;
47484 
47485   getter = car(args);
47486   if (!is_any_procedure(getter))
47487     return(wrong_type_argument_with_type(sc, sc->dilambda_symbol, 1, getter, wrap_string(sc, "a procedure or a macro", 22)));
47488 
47489   setter = cadr(args);
47490   if (!is_any_procedure(setter))
47491     return(wrong_type_argument_with_type(sc, sc->dilambda_symbol, 2, setter, wrap_string(sc, "a procedure or a macro", 22)));
47492 
47493   s7_set_setter(sc, getter, setter);
47494   return(getter);
47495 }
47496 
47497 
47498 /* -------------------------------- arity -------------------------------- */
47499 
47500 static s7_pointer closure_arity_to_cons(s7_scheme *sc, s7_pointer x, s7_pointer x_args)
47501 {
47502   /* x_args is unprocessed -- it is exactly the list as used in the closure[*] definition */
47503   int32_t len;
47504 
47505   if (is_symbol(x_args))                    /* any number of args is ok */
47506     return(s7_cons(sc, int_zero, max_arity));
47507 
47508   if (closure_arity_unknown(x))
47509     closure_set_arity(x, s7_list_length(sc, x_args));
47510   len = closure_arity(x);
47511   if (len < 0)                               /* dotted list => rest arg, (length '(a b . c)) is -2 */
47512     return(s7_cons(sc, make_integer(sc, -len), max_arity));
47513   return(s7_cons(sc, make_integer(sc, len), make_integer(sc, len)));
47514 }
47515 
47516 static void closure_star_arity_1(s7_scheme *sc, s7_pointer x, s7_pointer args)
47517 {
47518   if (closure_arity_unknown(x))
47519     {
47520       if (is_null(args))
47521 	closure_set_arity(x, 0);
47522       else
47523 	{
47524 	  if ((is_symbol(args)) || (allows_other_keys(args)))
47525 	    closure_set_arity(x, -1);
47526 	  else
47527 	    {
47528 	      s7_pointer p;
47529 	      int32_t i;
47530 	      for (i = 0, p = args; is_pair(p); i++, p = cdr(p)) /* is_pair(p) so (f1 a . b) will end with b not null */
47531 		{
47532 		  s7_pointer arg;
47533 		  arg = car(p);
47534 		  if (arg == sc->key_rest_symbol)
47535 		    break;
47536 		}
47537 	      closure_set_arity(x, ((is_null(p)) ? i : -1));  /* see below */
47538 	    }}}
47539 }
47540 
47541 static s7_pointer closure_star_arity_to_cons(s7_scheme *sc, s7_pointer x, s7_pointer x_args)
47542 {
47543   closure_star_arity_1(sc, x, x_args);
47544   return((closure_arity(x) == -1) ? s7_cons(sc, int_zero, max_arity) : s7_cons(sc, int_zero, make_integer(sc, closure_arity(x))));
47545 }
47546 
47547 static int32_t closure_arity_to_int(s7_scheme *sc, s7_pointer x)
47548 {
47549   /* not lambda* here */
47550   if (closure_arity_unknown(x))
47551     {
47552       int32_t i;
47553       s7_pointer b;
47554       for (i = 0, b = closure_args(x); is_pair(b); i++, b = cdr(b)) {};
47555       if (is_null(b))
47556 	closure_set_arity(x, i);
47557       else
47558 	{
47559 	  if (i == 0)
47560 	    return(-1);
47561 	  closure_set_arity(x, -i);
47562 	}}
47563   return(closure_arity(x));
47564 }
47565 
47566 static int32_t closure_star_arity_to_int(s7_scheme *sc, s7_pointer x)
47567 {
47568   /* not lambda here */
47569   closure_star_arity_1(sc, x, closure_args(x));
47570   return(closure_arity(x));
47571 }
47572 
47573 s7_pointer s7_arity(s7_scheme *sc, s7_pointer x)
47574 {
47575   switch (type(x))
47576     {
47577     case T_C_OPT_ARGS_FUNCTION:
47578     case T_C_RST_ARGS_FUNCTION:
47579     case T_C_FUNCTION:
47580       return(s7_cons(sc, make_integer(sc, c_function_required_args(x)), make_integer(sc, c_function_all_args(x))));
47581 
47582     case T_C_ANY_ARGS_FUNCTION:
47583     case T_C_FUNCTION_STAR:
47584       return(s7_cons(sc, int_zero, make_integer(sc, c_function_all_args(x))));
47585 
47586     case T_MACRO:
47587     case T_BACRO:
47588     case T_CLOSURE:
47589       return(closure_arity_to_cons(sc, x, closure_args(x)));
47590 
47591     case T_MACRO_STAR:
47592     case T_BACRO_STAR:
47593     case T_CLOSURE_STAR:
47594       return(closure_star_arity_to_cons(sc, x, closure_args(x)));
47595 
47596     case T_C_MACRO:
47597       return(s7_cons(sc, make_integer(sc, c_macro_required_args(x)), make_integer(sc, c_macro_all_args(x))));
47598 
47599     case T_GOTO:
47600     case T_CONTINUATION:
47601       return(s7_cons(sc, int_zero, max_arity));
47602 
47603     case T_STRING:
47604       return((string_length(x) == 0) ? sc->F : cons(sc, int_one, int_one));
47605 
47606     case T_LET:
47607       return(s7_cons(sc, int_one, int_one));
47608 
47609     case T_C_OBJECT:
47610       check_method(sc, x, sc->arity_symbol, set_plist_1(sc, x));
47611       return((is_safe_procedure(x)) ? cons(sc, int_zero, max_arity) : sc->F);
47612 
47613     case T_VECTOR:
47614       if (vector_length(x) == 0) return(sc->F);
47615       if (has_simple_elements(x)) return(cons(sc, int_one, make_integer(sc, vector_rank(x))));
47616       return(s7_cons(sc, int_one, max_arity));
47617 
47618     case T_INT_VECTOR:
47619     case T_FLOAT_VECTOR:
47620     case T_BYTE_VECTOR:
47621       return((vector_length(x) == 0) ? sc->F : cons(sc, int_one, make_integer(sc, vector_rank(x))));
47622 
47623     case T_PAIR:
47624     case T_HASH_TABLE:
47625       return(s7_cons(sc, int_one, max_arity));
47626 
47627     case T_ITERATOR:
47628       return(s7_cons(sc, int_zero, int_zero));
47629 
47630     case T_SYNTAX:
47631       return(s7_cons(sc, small_int(syntax_min_args(x)), (syntax_max_args(x) == -1) ? max_arity : small_int(syntax_max_args(x))));
47632     }
47633   return(sc->F);
47634 }
47635 
47636 static s7_pointer g_arity(s7_scheme *sc, s7_pointer args)
47637 {
47638   #define H_arity "(arity obj) the min and max acceptable args for obj if it is applicable, otherwise #f."
47639   #define Q_arity s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->not_symbol), sc->T)
47640   /* check_method(sc, p, sc->arity_symbol, args); */
47641   return(s7_arity(sc, car(args)));
47642 }
47643 
47644 
47645 /* -------------------------------- aritable? -------------------------------- */
47646 static bool closure_is_aritable(s7_scheme *sc, s7_pointer x, s7_pointer x_args, int32_t args)
47647 {
47648   /* x_args is unprocessed -- it is exactly the list as used in the closure definition */
47649   s7_int len;
47650 
47651   if (args == 0)
47652     return(!is_pair(x_args));
47653 
47654   if (is_symbol(x_args))                    /* any number of args is ok */
47655     return(true);
47656 
47657   len = closure_arity(x);
47658   if (len == CLOSURE_ARITY_NOT_SET)
47659     {
47660       len = s7_list_length(sc, x_args);
47661       closure_set_arity(x, len);
47662     }
47663   if (len < 0)                               /* dotted list => rest arg, (length '(a b . c)) is -2 */
47664     return((-len) <= args);                  /*   so we have enough to take care of the required args */
47665   return(args == len);                       /* in a normal lambda list, there are no other possibilities */
47666 }
47667 
47668 static bool closure_star_is_aritable(s7_scheme *sc, s7_pointer x, s7_pointer x_args, int32_t args)
47669 {
47670   if (is_symbol(x_args))
47671     return(true);
47672 
47673   closure_star_arity_1(sc, x, x_args);
47674   return((closure_arity(x) == -1) ||
47675 	 (args <= closure_arity(x)));
47676 }
47677 
47678 bool s7_is_aritable(s7_scheme *sc, s7_pointer x, s7_int args)
47679 {
47680   switch (type(x))
47681     {
47682     case T_C_RST_ARGS_FUNCTION:
47683     case T_C_FUNCTION:
47684       return((c_function_required_args(x) <= args) &&
47685 	     (c_function_all_args(x) >= args));
47686 
47687     case T_C_OPT_ARGS_FUNCTION: /* any/opt req args == 0 */
47688     case T_C_ANY_ARGS_FUNCTION:
47689     case T_C_FUNCTION_STAR:
47690       return(c_function_all_args(x) >= args);
47691 
47692     case T_MACRO:
47693     case T_BACRO:
47694     case T_CLOSURE:
47695       return(closure_is_aritable(sc, x, closure_args(x), args));
47696 
47697     case T_MACRO_STAR:
47698     case T_BACRO_STAR:
47699     case T_CLOSURE_STAR:
47700       return(closure_star_is_aritable(sc, x, closure_args(x), args));
47701 
47702     case T_C_MACRO:
47703       return((c_macro_required_args(x) <= args) &&
47704 	     (c_macro_all_args(x) >= args));
47705 
47706     case T_GOTO:
47707     case T_CONTINUATION:
47708       return(true);
47709 
47710     case T_STRING:
47711       return((args == 1) && (string_length(x) > 0)); /* ("" 0) -> error */
47712 
47713     case T_C_OBJECT:
47714       {
47715 	s7_pointer func;
47716 	if ((has_active_methods(sc, x)) &&
47717 	    ((func = find_method_with_let(sc, x, sc->is_aritable_symbol)) != sc->undefined))
47718 	  return(call_method(sc, x, func, set_plist_2(sc, x, make_integer(sc, args))) != sc->F);
47719 	return(is_safe_procedure(x));
47720       }
47721 
47722     case T_VECTOR: case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_BYTE_VECTOR:
47723       return((args > 0) &&
47724 	     (vector_length(x) > 0) &&   /* (#() 0) -> error */
47725 	     (args <= vector_rank(x)));
47726 
47727     case T_LET:
47728     case T_HASH_TABLE:
47729     case T_PAIR:
47730       return(args == 1);
47731 
47732     case T_ITERATOR:
47733       return(args == 0);
47734 
47735     case T_SYNTAX:
47736       return((args >= syntax_min_args(x)) && ((args <= syntax_max_args(x)) || (syntax_max_args(x) == -1)));
47737     }
47738   return(false);
47739 }
47740 
47741 static s7_pointer g_is_aritable(s7_scheme *sc, s7_pointer args)
47742 {
47743   #define H_is_aritable "(aritable? obj num-args) returns #t if 'obj can be applied to 'num-args arguments."
47744   #define Q_is_aritable s7_make_signature(sc, 3, sc->is_boolean_symbol, sc->T, sc->is_integer_symbol)
47745 
47746   s7_pointer n;
47747   s7_int num;
47748 
47749   n = cadr(args);
47750   if (!s7_is_integer(n)) /* remember gmp case! */
47751     return(method_or_bust(sc, n, sc->is_aritable_symbol, args, T_INTEGER, 2));
47752 
47753   num = s7_integer_checked(sc, n);
47754   if (num < 0)
47755     return(out_of_range(sc, sc->is_aritable_symbol, int_two, n, its_negative_string));
47756   if (num > MAX_ARITY) num = MAX_ARITY;
47757 
47758   return(make_boolean(sc, s7_is_aritable(sc, car(args), num)));
47759 }
47760 
47761 static bool is_aritable_b_7pp(s7_scheme *sc, s7_pointer f, s7_pointer i)
47762 {
47763   return(g_is_aritable(sc, set_plist_2(sc, f, i)) != sc->F);
47764 }
47765 
47766 static int32_t arity_to_int(s7_scheme *sc, s7_pointer x)
47767 {
47768   int32_t args;
47769   switch (type(x))
47770     {
47771     case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION: case T_C_FUNCTION: case T_C_ANY_ARGS_FUNCTION: case T_C_FUNCTION_STAR:
47772       return(c_function_all_args(x));
47773 
47774     case T_MACRO: case T_BACRO: case T_CLOSURE:
47775       args = closure_arity_to_int(sc, x);
47776       return((args < 0) ? MAX_ARITY : args);
47777 
47778     case T_MACRO_STAR: case T_BACRO_STAR: case T_CLOSURE_STAR:
47779       args = closure_star_arity_to_int(sc, x);
47780       return((args < 0) ? MAX_ARITY : args);
47781 
47782     case T_C_MACRO: return(c_macro_all_args(x));
47783     case T_C_OBJECT: return(MAX_ARITY);
47784 
47785       /* do vectors et al make sense here? */
47786     }
47787   return(-1);
47788 }
47789 
47790 
47791 /* -------------------------------- sequence? -------------------------------- */
47792 static s7_pointer g_is_sequence(s7_scheme *sc, s7_pointer args)
47793 {
47794   #define H_is_sequence "(sequence? obj) returns #t if obj is a sequence (vector, string, pair, etc)"
47795   #define Q_is_sequence sc->pl_bt
47796   check_boolean_method(sc, is_simple_sequence, sc->is_sequence_symbol, args);
47797 }
47798 
47799 static bool is_sequence_b(s7_pointer p) {return(is_simple_sequence(p));}
47800 
47801 
47802 /* -------------------------------- setter ------------------------------------------------ */
47803 
47804 static s7_pointer b_simple_setter(s7_scheme *sc, int typer, s7_pointer args)
47805 {
47806   if (type(cadr(args)) == typer)
47807     return(cadr(args));
47808   return(s7_error(sc, sc->wrong_type_arg_symbol,
47809 		  set_elist_5(sc, wrap_string(sc, "set! ~S, ~S is ~A but should be ~A", 34),
47810 			      car(args), cadr(args), sc->prepackaged_type_names[type(cadr(args))], sc->prepackaged_type_names[typer])));
47811 }
47812 
47813 static s7_pointer b_is_symbol_setter(s7_scheme *sc, s7_pointer args)       {return(b_simple_setter(sc, T_SYMBOL, args));}
47814 static s7_pointer b_is_syntax_setter(s7_scheme *sc, s7_pointer args)       {return(b_simple_setter(sc, T_SYNTAX, args));}
47815 static s7_pointer b_is_let_setter(s7_scheme *sc, s7_pointer args)          {return(b_simple_setter(sc, T_LET, args));}
47816 static s7_pointer b_is_iterator_setter(s7_scheme *sc, s7_pointer args)     {return(b_simple_setter(sc, T_ITERATOR, args));}
47817 static s7_pointer b_is_c_pointer_setter(s7_scheme *sc, s7_pointer args)    {return(b_simple_setter(sc, T_C_POINTER, args));}
47818 static s7_pointer b_is_input_port_setter(s7_scheme *sc, s7_pointer args)   {return(b_simple_setter(sc, T_INPUT_PORT, args));}
47819 static s7_pointer b_is_output_port_setter(s7_scheme *sc, s7_pointer args)  {return(b_simple_setter(sc, T_OUTPUT_PORT, args));}
47820 static s7_pointer b_is_eof_object_setter(s7_scheme *sc, s7_pointer args)   {return(b_simple_setter(sc, T_EOF, args));}
47821 static s7_pointer b_is_random_state_setter(s7_scheme *sc, s7_pointer args) {return(b_simple_setter(sc, T_RANDOM_STATE, args));}
47822 static s7_pointer b_is_char_setter(s7_scheme *sc, s7_pointer args)         {return(b_simple_setter(sc, T_CHARACTER, args));}
47823 static s7_pointer b_is_string_setter(s7_scheme *sc, s7_pointer args)       {return(b_simple_setter(sc, T_STRING, args));}
47824 static s7_pointer b_is_float_vector_setter(s7_scheme *sc, s7_pointer args) {return(b_simple_setter(sc, T_FLOAT_VECTOR, args));}
47825 static s7_pointer b_is_int_vector_setter(s7_scheme *sc, s7_pointer args)   {return(b_simple_setter(sc, T_INT_VECTOR, args));}
47826 static s7_pointer b_is_byte_vector_setter(s7_scheme *sc, s7_pointer args)  {return(b_simple_setter(sc, T_BYTE_VECTOR, args));}
47827 static s7_pointer b_is_hash_table_setter(s7_scheme *sc, s7_pointer args)   {return(b_simple_setter(sc, T_HASH_TABLE, args));}
47828 static s7_pointer b_is_continuation_setter(s7_scheme *sc, s7_pointer args) {return(b_simple_setter(sc, T_CONTINUATION, args));}
47829 static s7_pointer b_is_null_setter(s7_scheme *sc, s7_pointer args)         {return(b_simple_setter(sc, T_NIL, args));}
47830 static s7_pointer b_is_pair_setter(s7_scheme *sc, s7_pointer args)         {return(b_simple_setter(sc, T_PAIR, args));}
47831 static s7_pointer b_is_boolean_setter(s7_scheme *sc, s7_pointer args)      {return(b_simple_setter(sc, T_BOOLEAN, args));}
47832 static s7_pointer b_is_undefined_setter(s7_scheme *sc, s7_pointer args)    {return(b_simple_setter(sc, T_UNDEFINED, args));}
47833 static s7_pointer b_is_unspecified_setter(s7_scheme *sc, s7_pointer args)  {return(b_simple_setter(sc, T_UNSPECIFIED, args));}
47834 static s7_pointer b_is_c_object_setter(s7_scheme *sc, s7_pointer args)     {return(b_simple_setter(sc, T_C_OBJECT, args));}
47835 static s7_pointer b_is_goto_setter(s7_scheme *sc, s7_pointer args)         {return(b_simple_setter(sc, T_GOTO, args));}
47836 
47837 #define b_setter(sc, typer, args, str, len)	\
47838   do {						\
47839     if (typer(cadr(args)))			\
47840       return(cadr(args));			      \
47841     return(s7_error(sc, sc->wrong_type_arg_symbol,			\
47842 		    set_elist_5(sc, wrap_string(sc, "set! ~S, ~S is ~A but should be ~A", 34), \
47843 				car(args), cadr(args), sc->prepackaged_type_names[type(cadr(args))], wrap_string(sc, str, len)))); \
47844   } while (0)
47845 
47846 static s7_pointer b_is_number_setter(s7_scheme *sc, s7_pointer args)      {b_setter(sc, s7_is_complex, args, "a number", 8);}
47847 static s7_pointer b_is_complex_setter(s7_scheme *sc, s7_pointer args)     {b_setter(sc, s7_is_complex, args, "a number", 8);}
47848 static s7_pointer b_is_gensym_setter(s7_scheme *sc, s7_pointer args)      {b_setter(sc, is_gensym, args, "a gensym", 8);}
47849 static s7_pointer b_is_keyword_setter(s7_scheme *sc, s7_pointer args)     {b_setter(sc, is_keyword, args, "a keyword", 9);}
47850 static s7_pointer b_is_openlet_setter(s7_scheme *sc, s7_pointer args)     {b_setter(sc, has_methods, args, "an open let", 11);}
47851 static s7_pointer b_is_macro_setter(s7_scheme *sc, s7_pointer args)       {b_setter(sc, is_any_macro, args, "a macro", 7);}
47852 static s7_pointer b_is_integer_setter(s7_scheme *sc, s7_pointer args)     {b_setter(sc, s7_is_integer, args, "an integer", 10);}
47853 static s7_pointer b_is_byte_setter(s7_scheme *sc, s7_pointer args)        {b_setter(sc, is_byte, args, "an unsigned byte", 16);}
47854 static s7_pointer b_is_real_setter(s7_scheme *sc, s7_pointer args)        {b_setter(sc, s7_is_real, args, "a real", 6);}
47855 static s7_pointer b_is_float_setter(s7_scheme *sc, s7_pointer args)       {b_setter(sc, is_t_real, args, "a float", 7);}
47856 static s7_pointer b_is_rational_setter(s7_scheme *sc, s7_pointer args)    {b_setter(sc, is_rational, args, "a rational", 10);}
47857 static s7_pointer b_is_list_setter(s7_scheme *sc, s7_pointer args)        {b_setter(sc, is_list, args, "a list", 6);}
47858 static s7_pointer b_is_vector_setter(s7_scheme *sc, s7_pointer args)      {b_setter(sc, is_any_vector, args, "a vector", 8);}
47859 static s7_pointer b_is_procedure_setter(s7_scheme *sc, s7_pointer args)   {b_setter(sc, is_any_procedure, args, "a procedure", 11);}
47860 static s7_pointer b_is_dilambda_setter(s7_scheme *sc, s7_pointer args)    {b_setter(sc, s7_is_dilambda, args, "a dilambda", 10);}
47861 static s7_pointer b_is_sequence_setter(s7_scheme *sc, s7_pointer args)    {b_setter(sc, is_sequence, args, "a sequence", 10);}
47862 static s7_pointer b_is_subvector_setter(s7_scheme *sc, s7_pointer args)   {b_setter(sc, is_subvector, args, "a subvector", 11);}
47863 static s7_pointer b_is_weak_hash_table_setter(s7_scheme *sc, s7_pointer args) {b_setter(sc, is_weak_hash_table, args, "a weak hash-table", 17);}
47864 
47865 static s7_pointer b_is_proper_list_setter(s7_scheme *sc, s7_pointer args)
47866 {
47867   if (s7_is_proper_list(sc, car(args)))
47868     return(cadr(args));
47869   return(s7_error(sc, sc->wrong_type_arg_symbol,
47870 	  set_elist_5(sc, wrap_string(sc, "set! ~S, ~S is ~A but should be ~A", 34),
47871 	    car(args), cadr(args), sc->prepackaged_type_names[type(cadr(args))], wrap_string(sc, "a proper list", 13))));
47872 }
47873 
47874 static s7_pointer g_setter(s7_scheme *sc, s7_pointer args)
47875 {
47876   #define H_setter "(setter obj let) returns the setter associated with obj"
47877   #define Q_setter s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->not_symbol, sc->is_procedure_symbol), sc->T, sc->is_let_symbol)
47878   s7_pointer p, e;
47879 
47880   p = car(args);
47881   if (is_pair(cdr(args)))
47882     {
47883       e = cadr(args);
47884       if (!((is_let(e)) || (e == sc->rootlet) || (e == sc->nil)))
47885 	return(wrong_type_argument(sc, sc->setter_symbol, 2, e, T_LET));
47886     }
47887   else e = sc->curlet;
47888 
47889   switch (type(p))
47890     {
47891     case T_MACRO:   case T_MACRO_STAR:
47892     case T_BACRO:   case T_BACRO_STAR:
47893     case T_CLOSURE: case T_CLOSURE_STAR:
47894       if (is_any_procedure(closure_setter(p)))                /* setter already known */
47895 	return(closure_setter(p));
47896       if (!closure_no_setter(p))
47897 	{
47898 	  s7_pointer f;
47899 	  f = funclet_entry(sc, p, sc->local_setter_symbol); /* look for +setter+, save value as closure_setter(p) */
47900 	  if (f)
47901 	    {
47902 	      if (f == sc->F)
47903 		{
47904 		  closure_set_no_setter(p);
47905 		  return(sc->F);
47906 		}
47907 	      if (!is_any_procedure(f))
47908 		return(s7_wrong_type_arg_error(sc, "setter", 0, p, "a procedure or a reasonable facsimile thereof"));
47909 	      closure_set_setter(p, f);
47910 	      return(f);
47911 	    }
47912 	  /* we used to search for setter here, but that can find the built-in setter causing an infinite loop (maybe check for that??) */
47913 	  closure_set_no_setter(p);
47914 	}
47915       return(sc->F);
47916 
47917     case T_C_FUNCTION:
47918     case T_C_FUNCTION_STAR:
47919     case T_C_ANY_ARGS_FUNCTION:
47920     case T_C_OPT_ARGS_FUNCTION:
47921     case T_C_RST_ARGS_FUNCTION:
47922       return(c_function_setter(p));
47923 
47924     case T_C_MACRO:
47925       return(c_macro_setter(p));
47926 
47927     case T_GOTO:
47928     case T_CONTINUATION:
47929       return(sc->F);
47930 
47931     case T_C_OBJECT:
47932       check_method(sc, p, sc->setter_symbol, args);
47933       return((c_object_set(sc, p) == fallback_set) ? sc->F : sc->c_object_set_function); /* for example ((setter obj) obj 0 1.0) if s7test block */
47934       /* this could wrap the setter as an s7_function giving p's class-name etc */
47935 
47936     case T_LET:
47937       check_method(sc, p, sc->setter_symbol, args);
47938       return(global_value(sc->let_set_symbol));
47939 
47940     case T_ITERATOR:                           /* (set! (iter) val) doesn't fit the other setters */
47941       return((is_any_closure(iterator_sequence(p))) ? closure_setter(iterator_sequence(p)) : sc->F);
47942 
47943     case T_PAIR:         return(global_value(sc->list_set_symbol));
47944     case T_HASH_TABLE:   return(global_value(sc->hash_table_set_symbol));
47945     case T_STRING:       return(global_value(sc->string_set_symbol));
47946     case T_BYTE_VECTOR:  return(global_value(sc->byte_vector_set_symbol));
47947     case T_VECTOR:       return(global_value(sc->vector_set_symbol));
47948     case T_INT_VECTOR:   return(global_value(sc->int_vector_set_symbol));
47949     case T_FLOAT_VECTOR: return(global_value(sc->float_vector_set_symbol));
47950     case T_SLOT:         return((slot_has_setter(p)) ? slot_setter(p) : sc->F);
47951 
47952     case T_SYMBOL:                             /* (setter symbol let) */
47953       {
47954 	s7_pointer sym, slot;
47955 	sym = car(args);
47956 	if (is_keyword(sym))
47957 	  return(sc->F);
47958 
47959 	if ((e == sc->rootlet) || (e == sc->nil))
47960 	  slot = global_slot(sym);
47961 	else
47962 	  {
47963 	    s7_pointer old_e;
47964 	    old_e = sc->curlet;
47965 	    sc->curlet = e;
47966 	    slot = lookup_slot_from(sym, sc->curlet);
47967 	    sc->curlet = old_e;
47968 	  }
47969 	if (!is_slot(slot))
47970 	  return(sc->F);
47971 	return((slot_has_setter(slot)) ? slot_setter(slot) : sc->F);
47972       }}
47973   return(s7_wrong_type_arg_error(sc, "setter", 0, p, "something that might have a setter"));
47974 }
47975 
47976 s7_pointer s7_setter(s7_scheme *sc, s7_pointer obj) {return(g_setter(sc, set_plist_1(sc, obj)));}
47977 
47978 
47979 /* -------------------------------- set-setter -------------------------------- */
47980 static void protect_setter(s7_scheme *sc, s7_pointer sym, s7_pointer acc)
47981 {
47982   s7_int loc;
47983   if (sc->protected_setters_size == sc->protected_setters_loc)
47984     {
47985       s7_int i, new_size, size;
47986       block_t *ob, *nb;
47987 
47988       size = sc->protected_setters_size;
47989       new_size = 2 * size;
47990 
47991       ob = vector_block(sc->protected_setters);
47992       nb = reallocate(sc, ob, new_size * sizeof(s7_pointer));
47993       block_info(nb) = NULL;
47994       vector_block(sc->protected_setters) = nb;
47995       vector_elements(sc->protected_setters) = (s7_pointer *)block_data(nb);
47996       vector_length(sc->protected_setters) = new_size;
47997 
47998       ob = vector_block(sc->protected_setter_symbols);
47999       nb = reallocate(sc, ob, new_size * sizeof(s7_pointer));
48000       vector_block(sc->protected_setter_symbols) = nb;
48001       vector_elements(sc->protected_setter_symbols) = (s7_pointer *)block_data(nb);
48002       vector_length(sc->protected_setter_symbols) = new_size;
48003 
48004       for (i = size; i < new_size; i++)
48005 	{
48006 	  vector_element(sc->protected_setters, i) = sc->unused;
48007 	  vector_element(sc->protected_setter_symbols, i) = sc->unused;
48008 	}
48009       sc->protected_setters_size = new_size;
48010     }
48011   loc = sc->protected_setters_loc++;
48012   vector_element(sc->protected_setters, loc) = acc;
48013   vector_element(sc->protected_setter_symbols, loc) = sym;
48014 }
48015 
48016 static s7_pointer g_set_setter(s7_scheme *sc, s7_pointer args)
48017 {
48018   s7_pointer p, setter;
48019 
48020   p = car(args);
48021   if (is_symbol(p))
48022     {
48023       s7_pointer sym, func, slot;
48024       sym = p;
48025       if (is_keyword(sym))
48026 	return(s7_wrong_type_arg_error(sc, "set! setter", 1, sym, "a normal symbol (a keyword can't be set)"));
48027 
48028       if (is_pair(cddr(args)))
48029 	{
48030 	  s7_pointer e, old_e;
48031 	  e = cadr(args);                /* (let ((x 1)) (set! (setter 'x (curlet)) (lambda (s v e) ...))) */
48032 	  func = caddr(args);
48033 	  if ((e == sc->rootlet) || (e == sc->nil))
48034 	    slot = global_slot(sym);
48035 	  else
48036 	    {
48037 	      if (!is_let(e))
48038 		return(s7_wrong_type_arg_error(sc, "set! setter", 2, e, "a let"));
48039 	      old_e = sc->curlet;
48040 	      sc->curlet = e;
48041 	      slot = lookup_slot_from(sym, sc->curlet);
48042 	      sc->curlet = old_e;
48043 	    }}
48044       else
48045 	{
48046 	  slot = lookup_slot_from(sym, sc->curlet); /* (set! (setter 'x) (lambda (s v) ...)) */
48047 	  func = cadr(args);
48048 	}
48049       if (!is_slot(slot))
48050 	return(sc->F);
48051 
48052       if (func != sc->F)
48053 	{
48054 	  if (sym == sc->setter_symbol)
48055 	    return(immutable_object_error(sc, set_elist_2(sc, wrap_string(sc, "can't set (setter setter) to ~S", 31), func)));
48056 
48057 	  if (!is_any_procedure(func))   /* disallow continuation/goto here */
48058 	    return(s7_wrong_type_arg_error(sc, "set! setter", 3, func, "a function or #f"));
48059 
48060 	  if ((!is_c_function(func)) || (!c_function_has_bool_setter(func)))
48061 	    {
48062 	      if (s7_is_aritable(sc, func, 3))
48063 		set_has_let_arg(func);
48064 	      else
48065 		if (!s7_is_aritable(sc, func, 2))
48066 		  return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "setter function, ~A, should take 2 or 3 arguments", 49), func)));
48067 	    }}
48068 
48069       if (slot == global_slot(sym))
48070 	s7_set_setter(sc, sym, func); /* special GC protection for global vars */
48071       else slot_set_setter(slot, func); /* func might be #f */
48072       if (func != sc->F)
48073 	{
48074 	  slot_set_has_setter(slot);
48075 	  symbol_set_has_setter(sym);
48076 	}
48077       return(func);
48078     }
48079 
48080   if (p == sc->s7_let)
48081     return(s7_wrong_type_arg_error(sc, "set! setter", 1, p, "something other than *s7*"));
48082 
48083   setter = cadr(args);
48084   if (setter != sc->F)
48085     {
48086       if (!is_any_procedure(setter))
48087 	return(s7_wrong_type_arg_error(sc, "set! setter", 2, setter, "a procedure or #f"));
48088       if (arity_to_int(sc, setter) < 1)          /* we need at least an arg for the set! value */
48089 	return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "setter function, ~A, should take at least 1 argument", 52), setter)));
48090     }
48091 
48092   switch (type(p))
48093     {
48094     case T_MACRO:   case T_MACRO_STAR:
48095     case T_BACRO:   case T_BACRO_STAR:
48096     case T_CLOSURE: case T_CLOSURE_STAR:
48097       closure_set_setter(p, setter);
48098       if (setter == sc->F)
48099 	closure_set_no_setter(p);
48100       break;
48101 
48102     case T_C_FUNCTION: case T_C_ANY_ARGS_FUNCTION: case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION:
48103     case T_C_FUNCTION_STAR:
48104       if (p == global_value(sc->setter_symbol))
48105 	return(immutable_object_error(sc, set_elist_2(sc, wrap_string(sc, "can't set (setter setter) to ~S", 31), setter)));
48106       c_function_set_setter(p, setter);
48107       if ((is_any_closure(setter)) ||
48108 	  (is_any_macro(setter)))
48109 	add_setter(sc, p, setter);
48110       break;
48111 
48112     case T_C_MACRO:
48113       c_macro_set_setter(p, setter);
48114       if ((is_any_closure(setter)) ||
48115 	  (is_any_macro(setter)))
48116 	add_setter(sc, p, setter);
48117       break;
48118 
48119     default:  /* (set! (setter 4) ...) or p==continuation etc */
48120       return(s7_wrong_type_arg_error(sc, "set! setter", 1, p, "a normal procedure or a macro"));
48121     }
48122   return(setter);
48123 }
48124 
48125 s7_pointer s7_set_setter(s7_scheme *sc, s7_pointer p, s7_pointer setter)
48126 {
48127   if (is_symbol(p))
48128     {
48129       if (slot_has_setter(global_slot(p)))
48130 	{
48131 	  s7_int index;
48132 	  for (index = 0; index < sc->protected_setters_loc; index++)
48133 	    if (vector_element(sc->protected_setter_symbols, index) == p)
48134 	      {
48135 		s7_pointer old_func;
48136 		old_func = vector_element(sc->protected_setters, index);
48137 		if ((is_any_procedure(old_func)) && /* i.e. not #f! */
48138 		    (is_immutable(old_func)))
48139 		  return(setter);
48140 		vector_element(sc->protected_setters, index) = setter;
48141 		slot_set_setter(global_slot(p), setter);
48142 		if ((setter != sc->F) && (s7_is_aritable(sc, setter, 3)))
48143 		  set_has_let_arg(setter);
48144 		return(setter);
48145 	      }}
48146       if (setter != sc->F)
48147 	{
48148 	  slot_set_has_setter(global_slot(p));
48149 	  symbol_set_has_setter(p);
48150 	  slot_set_has_setter(global_slot(p));
48151 	  protect_setter(sc, p, setter);
48152 	  slot_set_setter(global_slot(p), setter);
48153 	  if (s7_is_aritable(sc, setter, 3))
48154 	    set_has_let_arg(setter);
48155 	  return(setter);
48156 	}
48157       slot_set_setter(global_slot(p), setter);
48158       return(setter);
48159     }
48160   return(g_set_setter(sc, set_plist_2(sc, p, setter)));
48161 }
48162 
48163 /* (let () (define xxx 23) (define (hix) (set! xxx 24)) (hix) (set! (setter 'xxx) (lambda (sym val) (format *stderr* "val: ~A~%" val) val)) (hix))
48164  *    so set setter before use!
48165  */
48166 
48167 static s7_pointer call_c_function_setter(s7_scheme *sc, s7_pointer func, s7_pointer symbol, s7_pointer new_value)
48168 {
48169   if (has_let_arg(func))
48170     {
48171       set_car(sc->t3_1, symbol);
48172       set_car(sc->t3_2, new_value);
48173       set_car(sc->t3_3, sc->curlet);
48174       return(c_function_call(func)(sc, sc->t3_1));
48175     }
48176   set_car(sc->t2_1, symbol);
48177   set_car(sc->t2_2, new_value);
48178   return(c_function_call(func)(sc, sc->t2_1));
48179 }
48180 
48181 static s7_pointer call_setter(s7_scheme *sc, s7_pointer slot, s7_pointer new_value) /* see also op_set1 */
48182 {
48183   s7_pointer func;
48184 
48185   func = slot_setter(slot);
48186   if (!is_any_procedure(func))
48187     return(new_value);
48188 
48189   if (is_c_function(func))
48190     return(call_c_function_setter(sc, func, slot_symbol(slot), new_value));
48191 
48192   push_stack_direct(sc, OP_EVAL_DONE);
48193   if (has_let_arg(func))
48194     sc->args = list_3(sc, slot_symbol(slot), new_value, sc->curlet);
48195   else sc->args = list_2(sc, slot_symbol(slot), new_value);
48196   sc->code = func;
48197   eval(sc, OP_APPLY);
48198   return(sc->value);
48199 }
48200 
48201 static s7_pointer bind_symbol_with_setter(s7_scheme *sc, opcode_t op, s7_pointer symbol, s7_pointer new_value)
48202 {
48203   s7_pointer func;
48204 
48205   func = g_setter(sc, set_plist_2(sc, symbol, sc->curlet));
48206   if (!is_any_procedure(func))
48207     return(new_value);
48208 
48209   if (is_c_function(func))
48210     return(call_c_function_setter(sc, func, symbol, new_value));
48211 
48212   sc->args = (has_let_arg(func)) ? list_3(sc, symbol, new_value, sc->curlet) : list_2(sc, symbol, new_value);
48213   push_stack_direct(sc, op);
48214   sc->code = func;
48215   return(sc->no_value); /* this means the setter in set! needs to goto APPLY to get the new value */
48216 }
48217 
48218 
48219 /* -------------------------------- hooks -------------------------------- */
48220 
48221 s7_pointer s7_hook_functions(s7_scheme *sc, s7_pointer hook)
48222 {
48223   return(s7_symbol_local_value(sc, sc->body_symbol, closure_let(hook)));
48224 }
48225 
48226 s7_pointer s7_hook_set_functions(s7_scheme *sc, s7_pointer hook, s7_pointer functions)
48227 {
48228   if (is_list(functions))
48229     s7_let_set(sc, closure_let(hook), sc->body_symbol, functions);
48230   return(functions);
48231 }
48232 
48233 
48234 /* -------------------------------- eq? eqv? equal? equivalent? -------------------------------- */
48235 
48236 bool s7_is_eq(s7_pointer obj1, s7_pointer obj2)
48237 {
48238   return((obj1 == obj2) ||                                     /* so floats and NaNs might be eq? but not eqv? */
48239 	 ((is_unspecified(obj1)) && (is_unspecified(obj2))));  /* this is needed because this function is used by s7_b_pp */
48240 }
48241 
48242 static s7_pointer is_eq_p_pp(s7_scheme *sc, s7_pointer obj1, s7_pointer obj2)
48243 {
48244   return(make_boolean(sc, ((obj1 == obj2) || ((is_unspecified(obj1)) && (is_unspecified(obj2))))));
48245 }
48246 
48247 static s7_pointer g_is_eq(s7_scheme *sc, s7_pointer args)
48248 {
48249   #define H_is_eq "(eq? obj1 obj2) returns #t if obj1 is eq to (the same object as) obj2"
48250   #define Q_is_eq sc->pcl_bt
48251   return(make_boolean(sc, ((car(args) == cadr(args)) ||
48252 			   ((is_unspecified(car(args))) && (is_unspecified(cadr(args)))))));
48253   /* (eq? (apply apply apply values '(())) #<unspecified>) should return #t */
48254 }
48255 
48256 bool s7_is_eqv(s7_scheme *sc, s7_pointer a, s7_pointer b)
48257 {
48258 #if WITH_GMP
48259   if ((is_big_number(a)) || (is_big_number(b)))
48260     return(big_numbers_are_eqv(sc, a, b));
48261 #endif
48262 
48263   if (type(a) != type(b))
48264     return(false);
48265 
48266   if ((a == b) && (!is_number(a)))                   /* if a is NaN, a == b doesn't mean (eqv? a b) */
48267     return(true);                                    /* a == b means (let ((x "a")) (let ((y x)) (eqv? x y))) is #t */
48268 
48269   if (s7_is_number(a))
48270     return(numbers_are_eqv(sc, a, b));
48271 
48272   if (is_unspecified(a))                             /* types are the same so we know b is also unspecified */
48273     return(true);
48274 
48275   return(false);
48276 }
48277 
48278 static s7_pointer g_is_eqv(s7_scheme *sc, s7_pointer args)
48279 {
48280   #define H_is_eqv "(eqv? obj1 obj2) returns #t if obj1 is equivalent to obj2"
48281   #define Q_is_eqv sc->pcl_bt
48282   return(make_boolean(sc, s7_is_eqv(sc, car(args), cadr(args))));
48283 }
48284 
48285 static s7_pointer is_eqv_p_pp(s7_scheme *sc, s7_pointer obj1, s7_pointer obj2) {return(make_boolean(sc, s7_is_eqv(sc, obj1, obj2)));}
48286 
48287 static bool floats_are_equivalent_1(s7_scheme *sc, s7_double x, s7_double y, s7_double eps)
48288 {
48289   s7_double diff;
48290   if (x == y) return(true);
48291   diff = fabs(x - y);
48292   if (diff <= eps) return(true);
48293   return(((is_NaN(x)) || (is_NaN(y))) &&
48294 	 ((is_NaN(x)) && (is_NaN(y))));
48295 }
48296 
48297 static bool floats_are_equivalent(s7_scheme *sc, s7_double x, s7_double y)
48298 {
48299   return(floats_are_equivalent_1(sc, x, y, sc->equivalent_float_epsilon));
48300 }
48301 
48302 #if WITH_GMP
48303 static bool big_floats_are_equivalent(s7_scheme *sc, mpfr_t x, mpfr_t y)
48304 {
48305   /* protect mpfr_1 */
48306   if ((mpfr_nan_p(x)) || (mpfr_nan_p(y)))
48307     return((mpfr_nan_p(x)) && (mpfr_nan_p(y)));
48308   mpfr_sub(sc->mpfr_3, x, y, MPFR_RNDN);
48309   mpfr_abs(sc->mpfr_3, sc->mpfr_3, MPFR_RNDN);
48310   return(mpfr_cmp_d(sc->mpfr_3, sc->equivalent_float_epsilon) <= 0);
48311 }
48312 #endif
48313 
48314 static bool eq_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci) {return(x == y);}
48315 
48316 static bool symbol_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48317 {
48318   if (x == y) return(true);
48319   if (!is_normal_symbol(y)) return(false);            /* (equivalent? ''(1) '(1)) */
48320   return((is_slot(global_slot(x))) &&                 /* the optimizer can replace the original symbol with its own */
48321 	 (is_syntax(global_value(x))) &&
48322 	 (is_slot(global_slot(y))) &&
48323 	 (is_syntax(global_value(y))) &&
48324 	 (syntax_symbol(global_value(x)) == syntax_symbol(global_value(y))));
48325 }
48326 
48327 static bool unspecified_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48328 {
48329   return(is_unspecified(y));
48330 }
48331 
48332 static bool undefined_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48333 {
48334   if (x == y) return(true);
48335   if ((!is_undefined(y)) || (undefined_name_length(x) != undefined_name_length(y))) return(false);
48336   return(safe_strcmp(undefined_name(x), undefined_name(y)));
48337 }
48338 
48339 static bool s7_is_equal_1(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci);
48340 static bool s7_is_equivalent_1(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci);
48341 
48342 static bool c_pointer_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48343 {
48344   shared_info_t *nci = ci;
48345   if (x == y) return(true);
48346   if (!s7_is_c_pointer(y)) return(false);
48347   if (c_pointer(x) != c_pointer(y)) return(false);
48348   if (c_pointer_type(x) != c_pointer_type(y))
48349     {
48350       if (!nci) nci = new_shared_info(sc);
48351       if (!s7_is_equivalent_1(sc, c_pointer_type(x), c_pointer_type(y), nci))
48352 	return(false);
48353     }
48354   if (c_pointer_info(x) != c_pointer_info(y))
48355     {
48356       if (!nci) nci = new_shared_info(sc);
48357       if (!s7_is_equivalent_1(sc, c_pointer_info(x), c_pointer_info(y), nci))
48358 	return(false);
48359     }
48360   return(true);
48361 }
48362 
48363 static bool c_pointer_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48364 {
48365   shared_info_t *nci = ci;
48366   if (x == y) return(true);
48367   if (!s7_is_c_pointer(y)) return(false);
48368   if (c_pointer(x) != c_pointer(y)) return(false);
48369   if (c_pointer_type(x) != c_pointer_type(y))
48370     {
48371       if (!nci) nci = new_shared_info(sc);
48372       if (!s7_is_equal_1(sc, c_pointer_type(x), c_pointer_type(y), nci))
48373 	return(false);
48374     }
48375   if (c_pointer_info(x) != c_pointer_info(y))
48376     {
48377       if (!nci) nci = new_shared_info(sc);
48378       if (!s7_is_equal_1(sc, c_pointer_info(x), c_pointer_info(y), nci))
48379 	return(false);
48380     }
48381   return(true);
48382 }
48383 
48384 static bool string_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48385 {
48386   return((is_string(y)) && (scheme_strings_are_equal(x, y)));
48387 }
48388 
48389 static bool syntax_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48390 {
48391   return((is_syntax(y)) && (syntax_symbol(x) == syntax_symbol(y)));
48392 }
48393 
48394 static bool port_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48395 {
48396   return(x == y);
48397 }
48398 
48399 static bool port_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48400 {
48401   if (x == y) return(true);
48402   if (type(x) != type(y)) return(false);
48403   if ((port_is_closed(x)) && (port_is_closed(y))) return(true);
48404   if ((port_is_closed(x)) || (port_is_closed(y))) return(false); /* if either is closed, port_port (below) might be null */
48405   if (port_type(x) != port_type(y)) return(false);
48406   switch (port_type(x))
48407     {
48408     case STRING_PORT:
48409       return((port_position(x) == port_position(y)) &&
48410 	     (port_data_size(x) == port_data_size(y)) &&
48411 	     (local_strncmp((const char *)port_data(x), (const char *)port_data(y), (is_input_port(x)) ? port_data_size(x) : port_position(x))));
48412     case FILE_PORT:
48413       return((is_input_port(x)) &&
48414 	     (port_position(x) == port_position(y)) &&
48415 	     (local_strncmp((const char *)port_filename(x), (const char *)port_filename(y), port_filename_length(x))));
48416     case FUNCTION_PORT:
48417       if (is_input_port(x))
48418 	return(port_input_function(x) == port_input_function(y));
48419       return(port_output_function(x) == port_output_function(y));
48420     }
48421   return(false);
48422 }
48423 
48424 static void add_shared_ref(shared_info_t *ci, s7_pointer x, int32_t ref_x)
48425 {
48426   /* called only in equality check, not printer */
48427   if (ci->top == ci->size)
48428     enlarge_shared_info(ci);
48429   set_collected(x);
48430   ci->objs[ci->top] = x;
48431   ci->refs[ci->top++] = ref_x;
48432 }
48433 
48434 static Inline bool equal_ref(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48435 {
48436   /* here we know x and y are pointers to the same type of structure */
48437   int32_t ref_y;
48438   ref_y = (is_collected(y)) ? peek_shared_ref_1(ci, y) : 0;
48439   if (is_collected(x))
48440     {
48441       int32_t ref_x;
48442       ref_x = peek_shared_ref_1(ci, x);
48443       if (ref_y != 0)
48444 	return(ref_x == ref_y);	/* this is a change from the macro version 16-Jan-20 -- only true returns from the caller */
48445       /* try to harmonize the new guy -- there can be more than one structure equal to the current one */
48446       if (ref_x != 0)
48447 	add_shared_ref(ci, y, ref_x);
48448     }
48449   else
48450     {
48451       if (ref_y != 0)
48452 	add_shared_ref(ci, x, ref_y);
48453       else
48454 	{
48455 	  /* assume neither x nor y is in the table, and that they should share a ref value, called only in equality check, not printer. */
48456 	  if (ci->top >= ci->size2) enlarge_shared_info(ci);
48457 	  set_collected(x);
48458 	  set_collected(y);
48459 	  ci->objs[ci->top] = x;
48460 	  ci->refs[ci->top++] = ++ci->ref;
48461 	  ci->objs[ci->top] = y;
48462 	  ci->refs[ci->top++] = ci->ref;
48463 	}}
48464   return(false);
48465 }
48466 
48467 static bool c_objects_are_equal(s7_scheme *sc, s7_pointer a, s7_pointer b, shared_info_t *ci)
48468 {
48469   s7_pointer (*to_list)(s7_scheme *sc, s7_pointer args);
48470   shared_info_t *nci = ci;
48471   s7_pointer pa, pb;
48472 
48473   if (a == b)
48474     return(true);
48475   if (!is_c_object(b))
48476     return(false);
48477   if (c_object_type(a) != c_object_type(b))
48478     return(false);
48479 
48480   if (c_object_equal(sc, a))
48481     return(((*(c_object_equal(sc, a)))(sc, set_plist_2(sc, a, b))) != sc->F);
48482   if (c_object_eql(sc, a))
48483     return((*(c_object_eql(sc, a)))(c_object_value(a), c_object_value(b)));
48484 
48485   to_list = c_object_to_list(sc, a);
48486   if (!to_list)
48487     return(false);
48488   if (ci)
48489     {
48490       if (equal_ref(sc, a, b, ci)) return(true); /* and nci == ci above */
48491     }
48492   else nci = new_shared_info(sc);
48493 
48494   for (pa = to_list(sc, set_plist_1(sc, a)), pb = to_list(sc, set_plist_1(sc, b)); is_pair(pa) && (is_pair(pb)); pa = cdr(pa), pb = cdr(pb))
48495     if (!(s7_is_equal_1(sc, car(pa), car(pb), nci)))
48496       return(false);
48497 
48498   return(pa == pb); /* presumably both are nil if successful */
48499 }
48500 
48501 #define check_equivalent_method(Sc, X, Y) \
48502   do {						 \
48503     if (has_active_methods(sc, X))					\
48504       {									\
48505 	s7_pointer equal_func;						\
48506 	equal_func = find_method_with_let(Sc, X, Sc->is_equivalent_symbol); \
48507 	if (equal_func != Sc->undefined)				\
48508 	  return(s7_boolean(Sc, call_method(Sc, X, equal_func, set_plist_2(Sc, X, Y)))); \
48509       }}								\
48510     while (0)
48511 
48512 static bool c_objects_are_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48513 {
48514   check_equivalent_method(sc, x, y);
48515   if (c_object_equivalent(sc, x))
48516     return(((*(c_object_equivalent(sc, x)))(sc, set_plist_2(sc, x, y))) != sc->F);
48517   return(c_objects_are_equal(sc, x, y, ci));
48518 }
48519 
48520 static bool hash_table_equal_1(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci, bool equivalent)
48521 {
48522   hash_entry_t **lists;
48523   s7_int i, len;
48524   shared_info_t *nci = ci;
48525   hash_check_t hf;
48526   bool (*eqf)(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci);
48527 
48528   if (x == y)
48529     return(true);
48530   if (!is_hash_table(y))
48531     {
48532       if (equivalent)
48533 	check_equivalent_method(sc, y, x);
48534       return(false);
48535     }
48536   if ((ci) && (equal_ref(sc, x, y, ci))) return(true);
48537 
48538   if (hash_table_entries(x) != hash_table_entries(y))
48539     return(false);
48540   if (hash_table_entries(x) == 0)
48541     return(true);
48542   if ((!equivalent) && ((hash_table_checker_locked(x)) || (hash_table_checker_locked(y))))
48543     {
48544       if (hash_table_checker(x) != hash_table_checker(y))
48545 	return(false);
48546       if (hash_table_mapper(x) != hash_table_mapper(y))
48547 	return(false);
48548     }
48549 
48550   len = hash_table_mask(x) + 1;
48551   lists = hash_table_elements(x);
48552   if (!nci) nci = new_shared_info(sc);
48553   eqf = (equivalent) ? s7_is_equivalent_1 : s7_is_equal_1;
48554 
48555   hf = hash_table_checker(y);
48556   if ((hf != hash_equal) && (hf != hash_equivalent))
48557     {
48558       for (i = 0; i < len; i++)
48559 	{
48560 	  hash_entry_t *p;
48561 	  for (p = lists[i]; p; p = hash_entry_next(p))
48562 	    {
48563 	      hash_entry_t *y_val;
48564 	      y_val = hf(sc, y, hash_entry_key(p));
48565 	      if (y_val == sc->unentry)
48566 		return(false);
48567 	      if (!eqf(sc, hash_entry_value(p), hash_entry_value(y_val), nci))
48568 		return(false);
48569 	    }}
48570       /* if we get here, every key/value in x has a corresponding key/value in y, and the number of entries match,
48571        *   so surely the tables are equal??
48572        * if ci not null or hash-table-checker is equal/eqivalent, can't use hf?
48573        */
48574       return(true);
48575     }
48576 
48577   /* we need to protect the current shared_info data (nci) here so the current hash_table_checker won't work --
48578    *   outside equal?/eqivalent? they can safely assume that they can start a new shared_info process.
48579    */
48580   for (i = 0; i < len; i++)
48581     {
48582       hash_entry_t *p;
48583       for (p = lists[i]; p; p = hash_entry_next(p))
48584 	{
48585 	  hash_entry_t *xe;
48586 	  s7_int hash, loc;
48587 	  s7_pointer key;
48588 
48589 	  key = hash_entry_key(p);
48590 	  hash = hash_loc(sc, y, key);
48591 	  loc = hash & hash_table_mask(y);
48592 
48593 	  for (xe = hash_table_element(y, loc); xe; xe = hash_entry_next(xe))
48594 	    if (hash_entry_raw_hash(xe) == hash)
48595 	      if (eqf(sc, hash_entry_key(xe), key, nci))
48596 		break;
48597 	  if (!xe)
48598 	    return(false);
48599 	  if (!eqf(sc, hash_entry_value(p), hash_entry_value(xe), nci))
48600 	    return(false);
48601 	}}
48602   return(true);
48603 }
48604 
48605 static bool hash_table_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48606 {
48607   return(hash_table_equal_1(sc, x, y, ci, false));
48608 }
48609 
48610 static bool hash_table_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48611 {
48612   return(hash_table_equal_1(sc, x, y, ci, true));
48613 }
48614 
48615 static bool slots_match(s7_scheme *sc, s7_pointer px, s7_pointer y, shared_info_t *nci)
48616 {
48617   s7_pointer ey, py;
48618   for (ey = y; is_let(T_Lid(ey)); ey = let_outlet(ey))
48619     for (py = let_slots(ey); tis_slot(py); py = next_slot(py))
48620       if (slot_symbol(px) == slot_symbol(py)) /* we know something will match */
48621 	return(s7_is_equal_1(sc, slot_value(px), slot_value(py), nci));
48622   return(false);
48623 }
48624 
48625 static bool slots_equivalent_match(s7_scheme *sc, s7_pointer px, s7_pointer y, shared_info_t *nci)
48626 {
48627   s7_pointer ey, py;
48628   for (ey = y; is_let(T_Lid(ey)); ey = let_outlet(ey))
48629     for (py = let_slots(ey); tis_slot(py); py = next_slot(py))
48630       if (slot_symbol(px) == slot_symbol(py)) /* we know something will match */
48631 	return(s7_is_equivalent_1(sc, slot_value(px), slot_value(py), nci));
48632   return(false);
48633 }
48634 
48635 static bool let_equal_1(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci, bool equivalent)
48636 {
48637   s7_pointer ex, ey, px, py;
48638   shared_info_t *nci = ci;
48639   int32_t x_len, y_len;
48640 
48641   if (!is_let(y))
48642     return(false);
48643 
48644   if ((x == sc->rootlet) || (y == sc->rootlet))
48645     return(false);
48646 
48647   if ((ci) && (equal_ref(sc, x, y, ci))) return(true);
48648 
48649   clear_symbol_list(sc);
48650   for (x_len = 0, ex = x; is_let(T_Lid(ex)); ex = let_outlet(ex))
48651     for (px = let_slots(ex); tis_slot(px); px = next_slot(px))
48652       if (!symbol_is_in_list(sc, slot_symbol(px)))
48653 	{
48654 	  add_symbol_to_list(sc, slot_symbol(px));
48655 	  x_len++;
48656 	}
48657 
48658   for (ey = y; is_let(T_Lid(ey)); ey = let_outlet(ey))
48659     for (py = let_slots(ey); tis_slot(py); py = next_slot(py))
48660       if (!symbol_is_in_list(sc, slot_symbol(py)))          /* symbol in y, not in x */
48661 	return(false);
48662 
48663   for (y_len = 0, ey = y; is_let(T_Lid(ey)); ey = let_outlet(ey))
48664     for (py = let_slots(ey); tis_slot(py); py = next_slot(py))
48665       if (symbol_tag(slot_symbol(py)) != 0)
48666 	{
48667 	  y_len++;
48668 	  symbol_set_tag(slot_symbol(py), 0);
48669 	}
48670 
48671   if (x_len != y_len)                                        /* symbol in x, not in y */
48672     return(false);
48673 
48674   if (!nci) nci = new_shared_info(sc);
48675 
48676   for (ex = x; is_let(T_Lid(ex)); ex = let_outlet(ex))
48677     for (px = let_slots(ex); tis_slot(px); px = next_slot(px))
48678       if (symbol_tag(slot_symbol(px)) == 0)                  /* unshadowed */
48679 	{
48680 	  symbol_set_tag(slot_symbol(px), sc->syms_tag);     /* values don't match */
48681 	  if (((!equivalent) && (!slots_match(sc, px, y, nci))) ||
48682 	      ((equivalent) && (!slots_equivalent_match(sc, px, y, nci))))
48683 	    return(false);
48684 	}
48685   return(true);
48686 }
48687 
48688 static bool let_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48689 {
48690   /* x == y if all unshadowed vars match, leaving aside the rootlet, so that for any local variable, we get the same value in either x or y. */
48691   return((x == y) || (let_equal_1(sc, x, y, ci, false)));
48692 }
48693 
48694 /* what should these do if there are setters? */
48695 static bool let_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48696 {
48697   if (x == y) return(true);
48698   if (!is_global(sc->is_equivalent_symbol))
48699     {
48700       check_equivalent_method(sc, x, y);
48701       check_equivalent_method(sc, y, x);
48702     }
48703   return(let_equal_1(sc, x, y, ci, true));
48704 }
48705 
48706 static bool closure_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48707 {
48708   if (x == y)
48709     return(true);
48710   if (type(x) != type(y))
48711     return(false);
48712   if ((has_active_methods(sc, x)) &&
48713       (has_active_methods(sc, y)))
48714     {
48715       s7_pointer equal_func;
48716       equal_func = find_method(sc, closure_let(x), sc->is_equal_symbol);
48717       if (equal_func != sc->undefined)
48718 	return(s7_boolean(sc, call_method(sc, x, equal_func, set_plist_2(sc, x, y))));
48719     }
48720   return(false);
48721 }
48722 
48723 static bool closure_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48724 {
48725   if (x == y)
48726     return(true);
48727   if (type(x) != type(y))
48728     return(false);
48729   if (has_active_methods(sc, y))
48730     check_equivalent_method(sc, x, y);
48731   /* not sure about this -- we can't simply check let_equal(closure_let(x), closure_let(y))
48732    *   because locally defined constant functions on the second pass find the outer let.
48733    */
48734   return((s7_is_equivalent_1(sc, closure_args(x), closure_args(y), ci)) &&
48735 	 (s7_is_equivalent_1(sc, closure_body(x), closure_body(y), ci)));
48736 }
48737 
48738 static bool pair_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48739 {
48740   s7_pointer px, py;
48741 
48742   if (x == y)
48743     return(true);
48744   if (!is_pair(y))
48745     return(false);
48746   if (ci)
48747     {
48748       if (equal_ref(sc, x, y, ci)) return(true);
48749     }
48750   else ci = new_shared_info(sc);
48751 
48752   if (!s7_is_equal_1(sc, car(x), car(y), ci)) return(false);
48753   for (px = cdr(x), py = cdr(y); (is_pair(px)) && (is_pair(py)); px = cdr(px), py = cdr(py))
48754     {
48755       if (!s7_is_equal_1(sc, car(px), car(py), ci)) return(false);
48756       if (equal_ref(sc, px, py, ci)) return(true);
48757     }
48758   return((px == py) || (s7_is_equal_1(sc, px, py, ci)));
48759 }
48760 
48761 static bool pair_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48762 {
48763   s7_pointer px, py;
48764 
48765   if (x == y)
48766     return(true);
48767   if (!is_pair(y))
48768     {
48769       check_equivalent_method(sc, y, x);
48770       return(false);
48771     }
48772   if (ci)
48773     {
48774       if (equal_ref(sc, x, y, ci)) return(true);
48775     }
48776   else ci = new_shared_info(sc);
48777 
48778   if (!s7_is_equivalent_1(sc, car(x), car(y), ci)) return(false);
48779   for (px = cdr(x), py = cdr(y); (is_pair(px)) && (is_pair(py)); px = cdr(px), py = cdr(py))
48780     {
48781       if (!s7_is_equivalent_1(sc, car(px), car(py), ci)) return(false);
48782       if (equal_ref(sc, px, py, ci)) return(true);
48783     }
48784   return((px == py) || ((s7_is_equivalent_1(sc, px, py, ci))));
48785 }
48786 
48787 static bool vector_rank_match(s7_scheme *sc, s7_pointer x, s7_pointer y)
48788 {
48789   s7_int x_dims;
48790   s7_int j;
48791 
48792   if (vector_has_dimensional_info(x))
48793     x_dims = vector_ndims(x);
48794   else return((!vector_has_dimensional_info(y)) || (vector_ndims(y) == 1));
48795   if (x_dims == 1)
48796     return((!vector_has_dimensional_info(y)) || (vector_ndims(y) == 1));
48797 
48798   if ((!vector_has_dimensional_info(y)) ||
48799       (x_dims != vector_ndims(y)))
48800     return(false);
48801 
48802   for (j = 0; j < x_dims; j++)
48803     if (vector_dimension(x, j) != vector_dimension(y, j))
48804       return(false);
48805 
48806   return(true);
48807 }
48808 
48809 static bool iv_meq(s7_int *ex, s7_int *ey, s7_int len)
48810 {
48811   s7_int i, left;
48812   left = len - 8;
48813   i = 0;
48814   while (i <= left)
48815     LOOP_8(if (ex[i] != ey[i]) return(false); i++);
48816   for (; i < len; i++)
48817     if (ex[i] != ey[i])
48818       return(false);
48819   return(true);
48820 }
48821 
48822 static bool byte_vector_equal_1(s7_scheme *sc, s7_pointer x, s7_pointer y)
48823 {
48824   s7_int i, len;
48825   uint8_t *xp, *yp;
48826   xp = byte_vector_bytes(x);
48827   yp = byte_vector_bytes(y);
48828   len = vector_length(x);
48829   for (i = 0; i < len; i++)
48830     if (xp[i] != yp[i])
48831       return(false);
48832   return(true);
48833 }
48834 
48835 static bool biv_meq(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48836 {
48837   s7_int i, len;
48838   uint8_t *xp;
48839   s7_int *yp;
48840   len = vector_length(x);
48841   if (len != vector_length(y)) return(false);
48842   xp = byte_vector_bytes(x);
48843   yp = int_vector_ints(y);
48844   for (i = 0; i < len; i++)
48845     if ((s7_int)(xp[i]) != yp[i])
48846       return(false);
48847   return(true);
48848 }
48849 
48850 #define base_vector_equal(sc, x, y)			\
48851   do {							\
48852     if (x == y) return(true);				\
48853     len = vector_length(x);				\
48854     if (len != vector_length(y)) return(false);		\
48855     if (!vector_rank_match(sc, x, y)) return(false);	\
48856     if (len == 0) return(true);				\
48857   } while (0)
48858 
48859 static bool vector_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48860 {
48861   s7_int i, len;
48862   shared_info_t *nci = ci;
48863 
48864   if (!is_any_vector(y)) return(false);
48865   base_vector_equal(sc, x, y);
48866   if (type(x) != type(y))
48867     {
48868       if ((is_int_vector(x)) && (is_byte_vector(y)))
48869 	return(biv_meq(sc, y, x, NULL));
48870       if ((is_byte_vector(x)) && (is_int_vector(y)))
48871 	return(biv_meq(sc, x, y, NULL));
48872       for (i = 0; i < len; i++)
48873 	if (!s7_is_equal_1(sc, vector_getter(x)(sc, x, i), vector_getter(y)(sc, y, i), NULL)) /* this could be greatly optimized */
48874 	  return(false);
48875       return(true);
48876     }
48877   if (!has_simple_elements(x))
48878     {
48879       if (ci)
48880 	{
48881 	  if (equal_ref(sc, x, y, ci)) return(true);
48882 	}
48883       else nci = new_shared_info(sc);
48884     }
48885   for (i = 0; i < len; i++)
48886     if (!(s7_is_equal_1(sc, vector_element(x, i), vector_element(y, i), nci)))
48887       return(false);
48888   return(true);
48889 }
48890 
48891 static bool byte_vector_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48892 {
48893   s7_int len;
48894   if (!is_byte_vector(y))
48895     return(vector_equal(sc, x, y, ci));
48896   base_vector_equal(sc, x, y);
48897   return(byte_vector_equal_1(sc, x, y));
48898 }
48899 
48900 static bool int_vector_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48901 {
48902   s7_int len;
48903   if (!is_int_vector(y))
48904     return(vector_equal(sc, x, y, ci));
48905   base_vector_equal(sc, x, y);
48906   return(iv_meq(int_vector_ints(x), int_vector_ints(y), len));
48907 }
48908 
48909 static bool float_vector_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48910 {
48911   s7_int i, len;
48912   if (!is_float_vector(y))
48913     return(vector_equal(sc, x, y, ci));
48914   base_vector_equal(sc, x, y);
48915   for (i = 0; i < len; i++)
48916     {
48917       s7_double z;
48918       z = float_vector(x, i);
48919       if ((is_NaN(z)) ||
48920 	  (z != float_vector(y, i)))
48921 	return(false);
48922     }
48923   return(true);
48924 }
48925 
48926 static bool vector_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
48927 {
48928   /* if this is split like vector_equal above, remember it is called by iterator_equal_1 below */
48929   s7_int i, len;
48930   shared_info_t *nci = ci;
48931 
48932   if (x == y)
48933     return(true);
48934   if (!is_any_vector(y))
48935     {
48936       check_equivalent_method(sc, y, x);
48937       return(false);
48938     }
48939   len = vector_length(x);
48940   if (len != vector_length(y)) return(false);
48941   if (len == 0) return(true);
48942   if (!vector_rank_match(sc, x, y)) return(false);
48943 
48944   if (type(x) != type(y))
48945     {
48946       /* (equivalent? (make-int-vector 3 0) (make-vector 3 0)) -> #t
48947        * (equivalent? (make-float-vector 3 1.0) (vector 1 1 1)) -> #t
48948        */
48949       if ((is_int_vector(x)) && (is_byte_vector(y)))
48950 	return(biv_meq(sc, y, x, NULL));
48951       if ((is_byte_vector(x)) && (is_int_vector(y)))
48952 	return(biv_meq(sc, x, y, NULL));
48953       for (i = 0; i < len; i++)
48954 	if (!s7_is_equivalent_1(sc, vector_getter(x)(sc, x, i), vector_getter(y)(sc, y, i), NULL)) /* this could be greatly optimized */
48955 	  return(false);
48956       return(true);
48957     }
48958 
48959   if (is_float_vector(x))
48960     {
48961       s7_double *arr1, *arr2;
48962       s7_double fudge;
48963       arr1 = float_vector_floats(x);
48964       arr2 = float_vector_floats(y);
48965       fudge = sc->equivalent_float_epsilon;
48966       if (fudge == 0.0)
48967 	{
48968 	  for (i = 0; i < len; i++)
48969 	    if ((arr1[i] != arr2[i]) &&
48970 		((!is_NaN(arr1[i])) || (!is_NaN(arr2[i]))))
48971 	      return(false);
48972 	}
48973       else
48974 	for (i = 0; i < len; i++)
48975 	  if (!floats_are_equivalent(sc, arr1[i], arr2[i]))
48976 	    return(false);
48977       return(true);
48978     }
48979   if (is_int_vector(x))
48980     return(iv_meq(int_vector_ints(x), int_vector_ints(y), len));
48981   if (is_byte_vector(x))
48982     return(byte_vector_equal_1(sc, x, y));
48983 
48984   if (!has_simple_elements(x))
48985     {
48986       if (ci)
48987 	{
48988 	  if (equal_ref(sc, x, y, ci)) return(true);
48989 	}
48990       else nci = new_shared_info(sc);
48991     }
48992   for (i = 0; i < len; i++)
48993     if (!(s7_is_equivalent_1(sc, vector_element(x, i), vector_element(y, i), nci)))
48994       return(false);
48995   return(true);
48996 }
48997 
48998 static bool iterator_equal_1(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci, bool equivalent)
48999 {
49000   s7_pointer x_seq, y_seq, xs, ys;
49001 
49002   if (x == y) return(true);
49003   if (!is_iterator(y)) return(false);
49004 
49005   x_seq = iterator_sequence(x);
49006   y_seq = iterator_sequence(y);
49007 
49008   switch (type(x_seq))
49009     {
49010     case T_STRING:
49011       return((is_string(y_seq)) &&
49012 	     (iterator_position(x) == iterator_position(y)) &&
49013 	     (iterator_length(x) == iterator_length(y)) &&
49014 	     (string_equal(sc, x_seq, y_seq, ci)));
49015 
49016     case T_VECTOR: case T_INT_VECTOR: case T_BYTE_VECTOR: case T_FLOAT_VECTOR:
49017       return((is_any_vector(y_seq)) &&
49018 	     (iterator_position(x) == iterator_position(y)) &&
49019 	     (iterator_length(x) == iterator_length(y)) &&
49020 	     ((equivalent) ? (vector_equivalent(sc, x_seq, y_seq, ci)) :
49021 	      ((is_normal_vector(x_seq)) ? (vector_equal(sc, x_seq, y_seq, ci)) :
49022 	       ((is_float_vector(x_seq)) ? (float_vector_equal(sc, x_seq, y_seq, ci)) :
49023 		((is_int_vector(x_seq)) ? (int_vector_equal(sc, x_seq, y_seq, ci)) :
49024 		 (byte_vector_equal(sc, x_seq, y_seq, ci)))))));
49025 
49026       /* iterator_next is a function (pair_iterate, iterator_finished etc) */
49027     case T_PAIR:
49028       if (iterator_next(x) != iterator_next(y)) return(false);     /* even if seqs are equal, one might be at end */
49029       if (equivalent)
49030 	{
49031 	  if (!pair_equivalent(sc, x_seq, y_seq, ci))
49032 	    return(false);
49033 	}
49034       else
49035 	if (!pair_equal(sc, x_seq, y_seq, ci))
49036 	  return(false);
49037 
49038       for (xs = x_seq, ys = y_seq; is_pair(xs) && is_pair(ys); xs = cdr(xs), ys = cdr(ys))
49039 	if (xs == iterator_current(x))
49040 	  return(ys == iterator_current(y));
49041       return(is_null(xs) && is_null(ys));
49042 
49043     case T_NIL:                                                    /* (make-iterator #()) works, so () should too */
49044       return(is_null(y_seq));   /* perhaps for equivalent case, check position in y as well as pair(seq(y))? */
49045 
49046     case T_C_OBJECT:
49047       if ((is_c_object(y_seq)) &&
49048 	  (iterator_position(x) == iterator_position(y)) &&
49049 	  (iterator_length(x) == iterator_length(y)))
49050 	{
49051 	  if (equivalent)
49052 	    return(c_objects_are_equivalent(sc, x_seq, y_seq, ci));
49053 	  return(c_objects_are_equal(sc, x_seq, y_seq, ci));
49054 	}
49055       return(false);
49056 
49057     case T_LET:
49058       if (!is_let(y_seq)) return(false);
49059       if (iterator_next(x) != iterator_next(y)) return(false);
49060       if (x_seq == sc->rootlet)
49061 	return(iterator_position(x) == iterator_position(y)); /* y_seq must also be sc->rootlet since nexts are the same (rootlet_iterate) */
49062       if (equivalent)
49063 	{
49064 	  if (!let_equivalent(sc, x_seq, y_seq, ci))
49065 	    return(false);
49066 	}
49067       else
49068 	if (!let_equal(sc, x_seq, y_seq, ci))
49069 	  return(false);
49070 
49071       for (xs = let_slots(x_seq), ys = let_slots(y_seq); tis_slot(xs) && tis_slot(ys); xs = next_slot(xs), ys = next_slot(ys))
49072 	if (xs == iterator_current_slot(x))
49073 	  return(ys == iterator_current_slot(y));
49074       return(is_slot_end(xs) && is_slot_end(ys));
49075 
49076     case T_HASH_TABLE:
49077       if (!is_hash_table(y_seq)) return(false);
49078       if (hash_table_entries(x_seq) != hash_table_entries(y_seq)) return(false);
49079       if (hash_table_entries(x_seq) == 0) return(true);
49080       if (iterator_position(x) != iterator_position(y)) return(false);
49081       if (!equivalent)
49082 	return(hash_table_equal(sc, x_seq, y_seq, ci));
49083       return(hash_table_equivalent(sc, x_seq, y_seq, ci));
49084 
49085     case T_CLOSURE: case T_CLOSURE_STAR:
49086       return(x_seq == y_seq); /* or closure_equal/equivalent? */
49087 
49088     default:
49089       break;
49090     }
49091   return(false);
49092 }
49093 
49094 static bool iterator_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49095 {
49096   return(iterator_equal_1(sc, x, y, ci, false));
49097 }
49098 
49099 static bool iterator_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49100 {
49101   return(iterator_equal_1(sc, x, y, ci, true));
49102 }
49103 
49104 #if WITH_GMP
49105 static bool big_integer_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49106 {
49107   /* (equal? 1 1.0) -> #f */
49108   if (is_t_big_integer(y))
49109     return(mpz_cmp(big_integer(x), big_integer(y)) == 0);
49110   return((is_t_integer(y)) && (mpz_cmp_si(big_integer(x), integer(y)) == 0));
49111 }
49112 
49113 static bool big_ratio_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49114 {
49115   if (is_t_big_ratio(y))
49116     return(mpq_equal(big_ratio(x), big_ratio(y)));
49117   if (is_t_ratio(y))
49118     return((numerator(y) == mpz_get_si(mpq_numref(big_ratio(x)))) &&
49119 	   (denominator(y) == mpz_get_si(mpq_denref(big_ratio(x)))));
49120   return(false);
49121 }
49122 
49123 static bool big_real_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49124 {
49125   if (is_t_big_real(y))
49126     return(mpfr_equal_p(big_real(x), big_real(y)));
49127   if (is_t_real(y))
49128     {
49129       if (mpfr_nan_p(big_real(x))) return(false);
49130       return((!is_NaN(real(y))) &&
49131 	     (mpfr_cmp_d(big_real(x), real(y)) == 0));
49132     }
49133   return(false);
49134 }
49135 
49136 static bool big_complex_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49137 {
49138   if ((mpfr_nan_p(mpc_realref(big_complex(x)))) || (mpfr_nan_p(mpc_imagref(big_complex(x)))))
49139     return(false);
49140   if (is_t_big_complex(y))
49141     return((!mpfr_nan_p(mpc_realref(big_complex(y)))) &&
49142 	   (!mpfr_nan_p(mpc_imagref(big_complex(y)))) &&
49143 	   (mpc_cmp(big_complex(x), big_complex(y)) == 0));
49144   if (is_t_complex(y))
49145     return((!is_NaN(real_part(y))) &&
49146 	   (!is_NaN(imag_part(y))) &&
49147 	   (mpfr_cmp_d(mpc_realref(big_complex(x)), real_part(y)) == 0) &&
49148 	   (mpfr_cmp_d(mpc_imagref(big_complex(x)), imag_part(y)) == 0));
49149   return(false);
49150 }
49151 #endif
49152 
49153 static bool integer_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49154 {
49155   if (is_t_integer(y))
49156     return(integer(x) == integer(y));
49157 #if WITH_GMP
49158   if (is_t_big_integer(y))
49159     return(mpz_cmp_si(big_integer(y), integer(x)) == 0);
49160 #endif
49161   return(false);
49162 }
49163 
49164 /* apparently ratio_equal is predefined in g++ -- name collision on mac */
49165 static bool fraction_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49166 {
49167   if (is_t_ratio(y))
49168     return((numerator(x) == numerator(y)) &&
49169 	   (denominator(x) == denominator(y)));
49170 #if WITH_GMP
49171   if (is_t_big_ratio(y))
49172     return((numerator(x) == mpz_get_si(mpq_numref(big_ratio(y)))) &&
49173 	   (denominator(x) == mpz_get_si(mpq_denref(big_ratio(y)))));
49174 #endif
49175   return(false);
49176 }
49177 
49178 static bool real_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49179 {
49180   if (is_t_real(y))
49181     return(real(x) == real(y));
49182 #if WITH_GMP
49183   if (is_t_big_real(y))
49184     return((!is_NaN(real(x))) &&
49185 	   (!mpfr_nan_p(big_real(y))) &&
49186 	   (mpfr_cmp_d(big_real(y), real(x)) == 0));
49187 #endif
49188   return(false);
49189 }
49190 
49191 static bool complex_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49192 {
49193   if (is_t_complex(y))
49194     return((real_part(x) == real_part(y)) &&
49195 	   (imag_part(x) == imag_part(y)));
49196 #if WITH_GMP
49197   if (is_t_big_complex(y))
49198     {
49199       if ((is_NaN(real_part(x))) || (is_NaN(imag_part(x))) ||
49200 	  (mpfr_nan_p(mpc_realref(big_complex(y)))) || (mpfr_nan_p(mpc_imagref(big_complex(y)))))
49201 	return(false);
49202       return((mpfr_cmp_d(mpc_realref(big_complex(y)), real_part(x)) == 0) &&
49203 	     (mpfr_cmp_d(mpc_imagref(big_complex(y)), imag_part(x)) == 0));
49204     }
49205 #endif
49206   return(false);
49207 }
49208 
49209 #if WITH_GMP
49210 static bool big_integer_or_ratio_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci, bool int_case)
49211 {
49212   if (int_case)
49213     mpfr_set_z(sc->mpfr_1, big_integer(x), MPFR_RNDN);
49214   else mpfr_set_q(sc->mpfr_1, big_ratio(x), MPFR_RNDN);
49215 
49216   switch (type(y))
49217     {
49218     case T_INTEGER:
49219       if (int_case)
49220 	return(mpz_cmp_si(big_integer(x), integer(y)) == 0);
49221       mpfr_set_si(sc->mpfr_2, integer(y), MPFR_RNDN);
49222       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49223     case T_RATIO:
49224       mpfr_set_d(sc->mpfr_2, fraction(y), MPFR_RNDN);
49225       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49226     case T_REAL:
49227       mpfr_set_d(sc->mpfr_2, real(y), MPFR_RNDN);
49228       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49229     case T_COMPLEX:
49230       mpfr_set_d(sc->mpfr_2, real_part(y), MPC_RNDNN);
49231       if (big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2))
49232 	{
49233 	  if (is_NaN(imag_part(y))) return(false);
49234 	  mpfr_set_d(sc->mpfr_1, sc->equivalent_float_epsilon, MPFR_RNDN);
49235 	  mpfr_set_d(sc->mpfr_2, imag_part(y), MPFR_RNDN);
49236 	  return(mpfr_cmpabs(sc->mpfr_2, sc->mpfr_1) <= 0);
49237 	}
49238       return(false);
49239     case T_BIG_INTEGER:
49240       if (int_case)
49241 	return(mpz_cmp(big_integer(x), big_integer(y)) == 0);
49242       mpfr_set_z(sc->mpfr_2, big_integer(y), MPFR_RNDN);
49243       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49244     case T_BIG_RATIO:
49245       mpfr_set_q(sc->mpfr_2, big_ratio(y), MPFR_RNDN);
49246       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49247     case T_BIG_REAL:
49248       return(big_floats_are_equivalent(sc, sc->mpfr_1, big_real(y)));
49249     case T_BIG_COMPLEX:
49250       if (big_floats_are_equivalent(sc, sc->mpfr_1, mpc_realref(big_complex(y))))
49251 	{
49252 	  if (mpfr_nan_p(mpc_imagref(big_complex(y)))) return(false);
49253 	  mpfr_set_d(sc->mpfr_1, sc->equivalent_float_epsilon, MPFR_RNDN);
49254 	  return(mpfr_cmpabs(mpc_imagref(big_complex(y)), sc->mpfr_1) <= 0);
49255 	}}
49256   return(false);
49257 }
49258 
49259 static bool big_integer_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49260 {
49261   return(big_integer_or_ratio_equivalent(sc, x, y, ci, true));
49262 }
49263 
49264 static bool big_ratio_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49265 {
49266   return(big_integer_or_ratio_equivalent(sc, x, y, ci, false));
49267 }
49268 
49269 
49270 static bool big_real_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49271 {
49272   switch (type(y))
49273     {
49274     case T_INTEGER:
49275       mpfr_set_si(sc->mpfr_2, integer(y), MPFR_RNDN);
49276       return(big_floats_are_equivalent(sc, big_real(x), sc->mpfr_2));
49277     case T_RATIO:
49278       mpfr_set_d(sc->mpfr_2, fraction(y), MPFR_RNDN);
49279       return(big_floats_are_equivalent(sc, big_real(x), sc->mpfr_2));
49280     case T_REAL:
49281       mpfr_set_d(sc->mpfr_2, real(y), MPFR_RNDN);
49282       return(big_floats_are_equivalent(sc, big_real(x), sc->mpfr_2));
49283     case T_COMPLEX:
49284       mpfr_set_d(sc->mpfr_2, real_part(y), MPC_RNDNN);
49285       if (big_floats_are_equivalent(sc, big_real(x), sc->mpfr_2))
49286 	{
49287 	  if (is_NaN(imag_part(y))) return(false);
49288 	  mpfr_set_d(sc->mpfr_1, sc->equivalent_float_epsilon, MPFR_RNDN);
49289 	  mpfr_set_d(sc->mpfr_2, imag_part(y), MPFR_RNDN);
49290 	  return(mpfr_cmpabs(sc->mpfr_2, sc->mpfr_1) <= 0);
49291 	}
49292       return(false);
49293     case T_BIG_INTEGER:
49294       mpfr_set_z(sc->mpfr_2, big_integer(y), MPFR_RNDN);
49295       return(big_floats_are_equivalent(sc, big_real(x), sc->mpfr_2));
49296     case T_BIG_RATIO:
49297       mpfr_set_q(sc->mpfr_2, big_ratio(y), MPFR_RNDN);
49298       return(big_floats_are_equivalent(sc, big_real(x), sc->mpfr_2));
49299     case T_BIG_REAL:
49300       return(big_floats_are_equivalent(sc, big_real(x), big_real(y)));
49301     case T_BIG_COMPLEX:
49302       if (big_floats_are_equivalent(sc, big_real(x), mpc_realref(big_complex(y))))
49303 	{
49304 	  if (mpfr_nan_p(mpc_imagref(big_complex(y)))) return(false);
49305 	  mpfr_set_d(sc->mpfr_1, sc->equivalent_float_epsilon, MPFR_RNDN);
49306 	  return(mpfr_cmpabs(mpc_imagref(big_complex(y)), sc->mpfr_1) <= 0);
49307 	}}
49308   return(false);
49309 }
49310 
49311 static bool big_complex_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49312 {
49313   mpfr_set_d(sc->mpfr_1, sc->equivalent_float_epsilon, MPFR_RNDN);
49314   switch (type(y))
49315     {
49316     case T_INTEGER:
49317       mpfr_set_si(sc->mpfr_2, integer(y), MPFR_RNDN);
49318       return((big_floats_are_equivalent(sc, mpc_realref(big_complex(x)), sc->mpfr_2)) &&
49319 	     (big_floats_are_equivalent(sc, mpc_imagref(big_complex(x)), sc->mpfr_1)));
49320     case T_RATIO:
49321       mpfr_set_d(sc->mpfr_2, fraction(y), MPFR_RNDN);
49322       return((big_floats_are_equivalent(sc, mpc_realref(big_complex(x)), sc->mpfr_2)) &&
49323 	     (big_floats_are_equivalent(sc, mpc_imagref(big_complex(x)), sc->mpfr_1)));
49324     case T_REAL:
49325       mpfr_set_d(sc->mpfr_2, real(y), MPFR_RNDN);
49326       return((big_floats_are_equivalent(sc, mpc_realref(big_complex(x)), sc->mpfr_2)) &&
49327 	     (big_floats_are_equivalent(sc, mpc_imagref(big_complex(x)), sc->mpfr_1)));
49328     case T_COMPLEX:
49329       mpfr_set_d(sc->mpfr_1, imag_part(y), MPC_RNDNN);
49330       mpfr_set_d(sc->mpfr_2, real_part(y), MPC_RNDNN);
49331       return((big_floats_are_equivalent(sc, mpc_realref(big_complex(x)), sc->mpfr_2)) &&
49332 	     (big_floats_are_equivalent(sc, mpc_imagref(big_complex(x)), sc->mpfr_1)));
49333     case T_BIG_INTEGER:
49334       mpfr_set_z(sc->mpfr_2, big_integer(y), MPFR_RNDN);
49335       return((big_floats_are_equivalent(sc, mpc_realref(big_complex(x)), sc->mpfr_2)) &&
49336 	     (big_floats_are_equivalent(sc, mpc_imagref(big_complex(x)), sc->mpfr_1)));
49337     case T_BIG_RATIO:
49338       mpfr_set_q(sc->mpfr_2, big_ratio(y), MPFR_RNDN);
49339       return((big_floats_are_equivalent(sc, mpc_realref(big_complex(x)), sc->mpfr_2)) &&
49340 	     (big_floats_are_equivalent(sc, mpc_imagref(big_complex(x)), sc->mpfr_1)));
49341     case T_BIG_REAL:
49342       return((big_floats_are_equivalent(sc, mpc_realref(big_complex(x)), big_real(y))) &&
49343 	     (big_floats_are_equivalent(sc, mpc_imagref(big_complex(x)), sc->mpfr_1)));
49344     case T_BIG_COMPLEX:
49345       return((big_floats_are_equivalent(sc, mpc_realref(big_complex(x)), mpc_realref(big_complex(y)))) &&
49346 	     (big_floats_are_equivalent(sc, mpc_imagref(big_complex(x)), mpc_imagref(big_complex(y)))));
49347     }
49348   return(false);
49349 }
49350 
49351 static bool both_floats_are_equivalent(s7_scheme *sc, s7_pointer y)
49352 {
49353   if (big_floats_are_equivalent(sc, sc->mpfr_1, mpc_realref(big_complex(y))))
49354     {
49355       if (mpfr_nan_p(mpc_imagref(big_complex(y)))) return(false);
49356       mpfr_set_d(sc->mpfr_1, sc->equivalent_float_epsilon, MPFR_RNDN);
49357       return(mpfr_cmpabs(mpc_imagref(big_complex(y)), sc->mpfr_1) <= 0);
49358     }
49359   return(false);
49360 }
49361 #endif
49362 
49363 static bool integer_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49364 {
49365   switch (type(y))
49366     {
49367     case T_INTEGER:
49368       return(integer(x) == integer(y));
49369     case T_RATIO:
49370       return(floats_are_equivalent(sc, (double)integer(x), fraction(y)));
49371     case T_REAL:
49372       return(floats_are_equivalent(sc, (double)integer(x), real(y)));
49373     case T_COMPLEX:
49374       return((fabs(imag_part(y)) <= sc->equivalent_float_epsilon) &&
49375 	     (floats_are_equivalent(sc, (double)integer(x), real_part(y))));
49376 #if WITH_GMP
49377     case T_BIG_INTEGER:
49378       return(mpz_cmp_si(big_integer(y), integer(x)) == 0);
49379     case T_BIG_RATIO:
49380       mpfr_set_si(sc->mpfr_1, integer(x), MPFR_RNDN);
49381       mpfr_set_q(sc->mpfr_2, big_ratio(y), MPFR_RNDN);
49382       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49383     case T_BIG_REAL:
49384       mpfr_set_si(sc->mpfr_1, integer(x), MPFR_RNDN);
49385       return(big_floats_are_equivalent(sc, sc->mpfr_1, big_real(y)));
49386     case T_BIG_COMPLEX:
49387       mpfr_set_si(sc->mpfr_1, integer(x), MPFR_RNDN);
49388       return(both_floats_are_equivalent(sc, y));
49389 #endif
49390     }
49391   return(false);
49392 }
49393 
49394 static bool fraction_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49395 {
49396   switch (type(y))
49397     {
49398     case T_INTEGER:
49399       return(floats_are_equivalent(sc, (double)fraction(x), integer(y)));
49400     case T_RATIO:
49401       return(floats_are_equivalent(sc, (double)fraction(x), fraction(y)));
49402     case T_REAL:
49403       return(floats_are_equivalent(sc, (double)fraction(x), real(y)));
49404     case T_COMPLEX:
49405       return((fabs(imag_part(y)) <= sc->equivalent_float_epsilon) &&
49406 	     (floats_are_equivalent(sc, fraction(x), real_part(y))));
49407 #if WITH_GMP
49408     case T_BIG_INTEGER:
49409       mpfr_set_z(sc->mpfr_1, big_integer(y), MPFR_RNDN);
49410       mpfr_set_d(sc->mpfr_2, fraction(x), MPFR_RNDN);
49411       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49412     case T_BIG_RATIO:
49413       mpfr_set_d(sc->mpfr_1, fraction(x), MPFR_RNDN);
49414       mpfr_set_q(sc->mpfr_2, big_ratio(y), MPFR_RNDN);
49415       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49416     case T_BIG_REAL:
49417       mpfr_set_d(sc->mpfr_1, fraction(x), MPFR_RNDN);
49418       return(big_floats_are_equivalent(sc, sc->mpfr_1, big_real(y)));
49419     case T_BIG_COMPLEX:
49420       mpfr_set_d(sc->mpfr_1, fraction(x), MPFR_RNDN);
49421       return(both_floats_are_equivalent(sc, y));
49422 #endif
49423     }
49424   return(false);
49425 }
49426 
49427 static bool real_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49428 {
49429   switch (type(y))
49430     {
49431     case T_INTEGER:
49432       return(floats_are_equivalent(sc, real(x), integer(y)));
49433     case T_RATIO:
49434       return(floats_are_equivalent(sc, real(x), fraction(y)));
49435     case T_REAL:
49436       return(floats_are_equivalent(sc, real(x), real(y)));
49437     case T_COMPLEX:
49438       return((fabs(imag_part(y)) <= sc->equivalent_float_epsilon) &&
49439 	     (floats_are_equivalent(sc, real(x), real_part(y))));
49440 #if WITH_GMP
49441     case T_BIG_INTEGER:
49442       mpfr_set_z(sc->mpfr_1, big_integer(y), MPFR_RNDN);
49443       mpfr_set_d(sc->mpfr_2, real(x), MPFR_RNDN);
49444       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49445     case T_BIG_RATIO:
49446       mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
49447       mpfr_set_q(sc->mpfr_2, big_ratio(y), MPFR_RNDN);
49448       return(big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2));
49449     case T_BIG_REAL:
49450       mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
49451       return(big_floats_are_equivalent(sc, sc->mpfr_1, big_real(y)));
49452     case T_BIG_COMPLEX:
49453       mpfr_set_d(sc->mpfr_1, real(x), MPFR_RNDN);
49454       return(both_floats_are_equivalent(sc, y));
49455 #endif
49456     }
49457   return(false);
49458 }
49459 
49460 static bool complex_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49461 {
49462   switch (type(y))
49463     {
49464     case T_INTEGER:
49465       return((floats_are_equivalent(sc, real_part(x), integer(y))) &&
49466 	     (floats_are_equivalent(sc, imag_part(x), 0.0)));
49467     case T_RATIO:
49468       return((floats_are_equivalent(sc, real_part(x), fraction(y))) &&
49469 	     (floats_are_equivalent(sc, imag_part(x), 0.0)));
49470     case T_REAL:
49471       return((floats_are_equivalent(sc, real_part(x), real(y))) &&
49472 	     (floats_are_equivalent(sc, imag_part(x), 0.0)));
49473     case T_COMPLEX:
49474       return((floats_are_equivalent(sc, real_part(x), real_part(y))) &&
49475 	     (floats_are_equivalent(sc, imag_part(x), imag_part(y))));
49476 #if WITH_GMP
49477     case T_BIG_INTEGER:
49478       mpfr_set_z(sc->mpfr_1, big_integer(y), MPFR_RNDN);
49479       mpfr_set_d(sc->mpfr_2, real_part(x), MPFR_RNDN);
49480       return((big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2)) &&
49481 	     (floats_are_equivalent(sc, imag_part(x), 0.0)));
49482     case T_BIG_RATIO:
49483       mpfr_set_d(sc->mpfr_1, real_part(x), MPFR_RNDN);
49484       mpfr_set_q(sc->mpfr_2, big_ratio(y), MPFR_RNDN);
49485       return((big_floats_are_equivalent(sc, sc->mpfr_1, sc->mpfr_2)) &&
49486 	     (floats_are_equivalent(sc, imag_part(x), 0.0)));
49487     case T_BIG_REAL:
49488       mpfr_set_d(sc->mpfr_1, real_part(x), MPFR_RNDN);
49489       return((big_floats_are_equivalent(sc, sc->mpfr_1, big_real(y))) &&
49490 	     (floats_are_equivalent(sc, imag_part(x), 0.0)));
49491     case T_BIG_COMPLEX:
49492       mpfr_set_d(sc->mpfr_1, real_part(x), MPFR_RNDN);
49493       mpfr_set_d(sc->mpfr_2, imag_part(x), MPFR_RNDN);
49494       return((big_floats_are_equivalent(sc, sc->mpfr_1, mpc_realref(big_complex(y)))) &&
49495 	     (big_floats_are_equivalent(sc, sc->mpfr_2, mpc_imagref(big_complex(y)))));
49496 #endif
49497     }
49498   return(false);
49499 }
49500 
49501 static bool rng_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49502 {
49503 #if WITH_GMP
49504   return(x == y);
49505 #else
49506   return((x == y) ||
49507 	 ((is_random_state(y)) &&
49508 	  (random_seed(x) == random_seed(y)) &&
49509 	  (random_carry(x) == random_carry(y))));
49510 #endif
49511 }
49512 
49513 static void init_equals(void)
49514 {
49515   int32_t i;
49516   for (i = 0; i < NUM_TYPES; i++) {equals[i] = eq_equal; equivalents[i] = eq_equal;}
49517   equals[T_SYMBOL] =       eq_equal;
49518   equals[T_C_POINTER] =    c_pointer_equal;
49519   equals[T_UNSPECIFIED] =  unspecified_equal;
49520   equals[T_UNDEFINED] =    undefined_equal;
49521   equals[T_STRING] =       string_equal;
49522   equals[T_SYNTAX] =       syntax_equal;
49523   equals[T_C_OBJECT] =     c_objects_are_equal;
49524   equals[T_RANDOM_STATE] = rng_equal;
49525   equals[T_ITERATOR] =     iterator_equal;
49526   equals[T_INPUT_PORT] =   port_equal;
49527   equals[T_OUTPUT_PORT] =  port_equal;
49528   equals[T_MACRO] =        closure_equal;
49529   equals[T_MACRO_STAR] =   closure_equal;
49530   equals[T_BACRO] =        closure_equal;
49531   equals[T_BACRO_STAR] =   closure_equal;
49532   equals[T_CLOSURE] =      closure_equal;
49533   equals[T_CLOSURE_STAR] = closure_equal;
49534   equals[T_HASH_TABLE] =   hash_table_equal;
49535   equals[T_LET] =          let_equal;
49536   equals[T_PAIR] =         pair_equal;
49537   equals[T_VECTOR] =       vector_equal;
49538   equals[T_INT_VECTOR] =   int_vector_equal;
49539   equals[T_BYTE_VECTOR] =  byte_vector_equal;
49540   equals[T_FLOAT_VECTOR] = float_vector_equal;
49541   equals[T_INTEGER] =      integer_equal;
49542   equals[T_RATIO] =        fraction_equal;
49543   equals[T_REAL] =         real_equal;
49544   equals[T_COMPLEX] =      complex_equal;
49545 #if WITH_GMP
49546   equals[T_BIG_INTEGER] =  big_integer_equal;
49547   equals[T_BIG_RATIO] =    big_ratio_equal;
49548   equals[T_BIG_REAL] =     big_real_equal;
49549   equals[T_BIG_COMPLEX] =  big_complex_equal;
49550 #endif
49551   equivalents[T_SYMBOL] =       symbol_equivalent;
49552   equivalents[T_C_POINTER] =    c_pointer_equivalent;
49553   equivalents[T_UNSPECIFIED] =  unspecified_equal;
49554   equivalents[T_UNDEFINED] =    undefined_equal;
49555   equivalents[T_STRING] =       string_equal;
49556   equivalents[T_SYNTAX] =       syntax_equal;
49557   equivalents[T_C_OBJECT] =     c_objects_are_equivalent;
49558   equivalents[T_RANDOM_STATE] = rng_equal;
49559   equivalents[T_ITERATOR] =     iterator_equivalent;
49560   equivalents[T_INPUT_PORT] =   port_equivalent;
49561   equivalents[T_OUTPUT_PORT] =  port_equivalent;
49562   equivalents[T_MACRO] =        closure_equivalent;
49563   equivalents[T_MACRO_STAR] =   closure_equivalent;
49564   equivalents[T_BACRO] =        closure_equivalent;
49565   equivalents[T_BACRO_STAR] =   closure_equivalent;
49566   equivalents[T_CLOSURE] =      closure_equivalent;
49567   equivalents[T_CLOSURE_STAR] = closure_equivalent;
49568   equivalents[T_HASH_TABLE] =   hash_table_equivalent;
49569   equivalents[T_LET] =          let_equivalent;
49570   equivalents[T_PAIR] =         pair_equivalent;
49571   equivalents[T_VECTOR] =       vector_equivalent;
49572   equivalents[T_INT_VECTOR] =   vector_equivalent;
49573   equivalents[T_FLOAT_VECTOR] = vector_equivalent;
49574   equivalents[T_BYTE_VECTOR] =  vector_equivalent;
49575   equivalents[T_INTEGER] =      integer_equivalent;
49576   equivalents[T_RATIO] =        fraction_equivalent;
49577   equivalents[T_REAL] =         real_equivalent;
49578   equivalents[T_COMPLEX] =      complex_equivalent;
49579 #if WITH_GMP
49580   equivalents[T_BIG_INTEGER] =  big_integer_equivalent;
49581   equivalents[T_BIG_RATIO] =    big_ratio_equivalent;
49582   equivalents[T_BIG_REAL] =     big_real_equivalent;
49583   equivalents[T_BIG_COMPLEX] =  big_complex_equivalent;
49584 #endif
49585 }
49586 
49587 static bool s7_is_equal_1(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49588 {
49589   return((*(equals[type(x)]))(sc, x, y, ci));
49590 }
49591 
49592 bool s7_is_equal(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(s7_is_equal_1(sc, x, y, NULL));}
49593 
49594 static bool s7_is_equivalent_1(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info_t *ci)
49595 {
49596   return((*(equivalents[type(x)]))(sc, x, y, ci));
49597 }
49598 
49599 bool s7_is_equivalent(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(s7_is_equivalent_1(sc, x, y, NULL));}
49600 
49601 static s7_pointer g_is_equal(s7_scheme *sc, s7_pointer args)
49602 {
49603   #define H_is_equal "(equal? obj1 obj2) returns #t if obj1 is equal to obj2"
49604   #define Q_is_equal sc->pcl_bt
49605   return(make_boolean(sc, s7_is_equal_1(sc, car(args), cadr(args), NULL)));
49606 }
49607 
49608 static s7_pointer g_is_equivalent(s7_scheme *sc, s7_pointer args)
49609 {
49610   #define H_is_equivalent "(equivalent? obj1 obj2) returns #t if obj1 is close enough to obj2."
49611   #define Q_is_equivalent sc->pcl_bt
49612   return(make_boolean(sc, s7_is_equivalent_1(sc, car(args), cadr(args), NULL)));
49613 }
49614 
49615 static s7_pointer is_equal_p_pp(s7_scheme *sc, s7_pointer a, s7_pointer b) {return((s7_is_equal_1(sc, a, b, NULL)) ? sc->T : sc->F);}
49616 static s7_pointer is_equivalent_p_pp(s7_scheme *sc, s7_pointer a, s7_pointer b) {return((s7_is_equivalent_1(sc, a, b, NULL)) ? sc->T : sc->F);}
49617 
49618 
49619 /* ---------------------------------------- length, copy, fill ---------------------------------------- */
49620 static s7_pointer s7_length(s7_scheme *sc, s7_pointer lst);
49621 
49622 static s7_pointer (*length_functions[256])(s7_scheme *sc, s7_pointer obj);
49623 static s7_pointer any_length(s7_scheme *sc, s7_pointer obj) {return(sc->F);}
49624 
49625 static s7_pointer pair_length(s7_scheme *sc, s7_pointer a)
49626 {
49627   s7_int i;
49628   s7_pointer slow, fast;
49629   slow = a;
49630   fast = a; /* we know a is a pair, don't start with fast = cdr(a)! else if a len = 3, we never match */
49631   i = 0;
49632   while (true)
49633     {
49634       LOOP_4(fast = cdr(fast); i++; if (!is_pair(fast)) return(make_integer(sc, (is_null(fast)) ? i : -i)));
49635       slow = cdr(slow);
49636       if (fast == slow)	return(real_infinity);
49637     }
49638   return(real_infinity);
49639 }
49640 
49641 static s7_pointer nil_length(s7_scheme *sc, s7_pointer lst)  {return(int_zero);}
49642 static s7_pointer v_length(s7_scheme *sc, s7_pointer v)      {return(make_integer(sc, vector_length(v)));}
49643 static s7_pointer str_length(s7_scheme *sc, s7_pointer v)    {return(make_integer(sc, string_length(v)));}
49644 static s7_pointer bv_length(s7_scheme *sc, s7_pointer v)     {return(make_integer(sc, byte_vector_length(v)));}
49645 static s7_pointer h_length(s7_scheme *sc, s7_pointer lst)    {return(make_integer(sc, hash_table_mask(lst) + 1));}
49646 static s7_pointer iter_length(s7_scheme *sc, s7_pointer lst) {return(s7_length(sc, iterator_sequence(lst)));}
49647 
49648 static s7_pointer c_obj_length(s7_scheme *sc, s7_pointer lst)
49649 {
49650   if (!is_global(sc->length_symbol))
49651     check_method(sc, lst, sc->length_symbol, set_plist_1(sc, lst));
49652   return(c_object_length(sc, lst));
49653 }
49654 
49655 static s7_pointer lt_length(s7_scheme *sc, s7_pointer lst)
49656 {
49657   if (!is_global(sc->length_symbol))
49658     check_method(sc, lst, sc->length_symbol, set_plist_1(sc, lst));
49659   return(make_integer(sc, let_length(sc, lst)));
49660 }
49661 
49662 static s7_pointer fnc_length(s7_scheme *sc, s7_pointer lst)
49663 {
49664   return((has_active_methods(sc, lst)) ? make_integer(sc, closure_length(sc, lst)) : sc->F);
49665 }
49666 
49667 static s7_pointer ip_length(s7_scheme *sc, s7_pointer port)
49668 {
49669   if (port_is_closed(port))
49670     return(sc->F);             /* or 0? */
49671   if (is_string_port(port))
49672     return(make_integer(sc, port_data_size(port))); /* length of string we're reading */
49673 #if (!MS_WINDOWS)
49674   if (is_file_port(port))
49675     {
49676       long cur_pos, len;
49677       cur_pos = ftell(port_file(port));
49678       fseek(port_file(port), 0, SEEK_END);
49679       len = ftell(port_file(port));
49680       rewind(port_file(port));
49681       fseek(port_file(port), cur_pos, SEEK_SET);
49682       return(make_integer(sc, len));
49683     }
49684 #endif
49685   return(sc->F);
49686 }
49687 
49688 static s7_pointer op_length(s7_scheme *sc, s7_pointer port)
49689 {
49690   if (port_is_closed(port))
49691     return(sc->F);             /* or 0? */
49692   return((is_string_port(port)) ? make_integer(sc, port_position(port)) : sc->F); /* length of string we've written */
49693 }
49694 
49695 static void init_length_functions(void)
49696 {
49697   int32_t i;
49698   for (i = 0; i < 256; i++) length_functions[i] = any_length;
49699   length_functions[T_NIL]          = nil_length;
49700   length_functions[T_PAIR]         = pair_length;
49701   length_functions[T_VECTOR]       = v_length;
49702   length_functions[T_FLOAT_VECTOR] = v_length;
49703   length_functions[T_INT_VECTOR]   = v_length;
49704   length_functions[T_STRING]       = str_length;
49705   length_functions[T_BYTE_VECTOR]  = bv_length;
49706   length_functions[T_ITERATOR]     = iter_length;
49707   length_functions[T_HASH_TABLE]   = h_length;
49708   length_functions[T_C_OBJECT]     = c_obj_length;
49709   length_functions[T_LET]          = lt_length;
49710   length_functions[T_CLOSURE]      = fnc_length;
49711   length_functions[T_CLOSURE_STAR] = fnc_length;
49712   length_functions[T_INPUT_PORT]   = ip_length;
49713   length_functions[T_OUTPUT_PORT]  = op_length;
49714 }
49715 
49716 static s7_pointer s7_length(s7_scheme *sc, s7_pointer lst) {return((*length_functions[unchecked_type(lst)])(sc, lst));}
49717 
49718 static s7_pointer g_length(s7_scheme *sc, s7_pointer args)
49719 {
49720   #define H_length "(length obj) returns the length of obj, which can be a list, vector, string, input-port, or hash-table. \
49721 The length of a dotted list does not include the final cdr, and is returned as a negative number.  A circular \
49722 list has infinite length.  Length of anything else returns #f."
49723   #define Q_length s7_make_signature(sc, 2, s7_make_signature(sc, 3, sc->is_integer_symbol, sc->is_infinite_symbol, sc->not_symbol), sc->T)
49724   return((*length_functions[unchecked_type(car(args))])(sc, car(args)));
49725 }
49726 
49727 
49728 /* -------------------------------- copy -------------------------------- */
49729 
49730 static s7_pointer string_setter(s7_scheme *sc, s7_pointer str, s7_int loc, s7_pointer val)
49731 {
49732   if (s7_is_character(val))
49733     {
49734       string_value(str)[loc] = s7_character(val);
49735       return(val);
49736     }
49737   set_car(sc->elist_3, wrap_string(sc, "~S: ~S is not a character", 25));
49738   set_caddr(sc->elist_3, val);
49739   return(s7_error(sc, sc->wrong_type_arg_symbol, sc->elist_3));
49740 }
49741 
49742 static s7_pointer string_getter(s7_scheme *sc, s7_pointer str, s7_int loc)
49743 {
49744   return(s7_make_character(sc, (uint8_t)(string_value(str)[loc]))); /* cast needed else (copy (string (integer->char 255))...) is trouble */
49745 }
49746 
49747 static s7_pointer c_object_setter(s7_scheme *sc, s7_pointer obj, s7_int loc, s7_pointer val)
49748 {
49749   set_car(sc->t3_1, obj);
49750   set_car(sc->t3_2, make_integer(sc, loc));
49751   set_car(sc->t3_3, val);
49752   return((*(c_object_set(sc, obj)))(sc, sc->t3_1));
49753 }
49754 
49755 static s7_pointer c_object_getter(s7_scheme *sc, s7_pointer obj, s7_int loc)
49756 {
49757   return((*(c_object_ref(sc, obj)))(sc, set_plist_2(sc, obj, make_integer(sc, loc))));
49758 }
49759 
49760 static s7_pointer let_setter(s7_scheme *sc, s7_pointer e, s7_int loc, s7_pointer val)
49761 {
49762   /* loc is irrelevant here
49763    * val has to be of the form (cons symbol value)
49764    * if symbol is already in e, its value is changed, otherwise a new slot is added to e
49765    */
49766   if (is_pair(val))
49767     {
49768       s7_pointer sym;
49769       sym = car(val);
49770       if (is_symbol(sym))
49771 	{
49772 	  s7_pointer slot;
49773 	  if (is_keyword(sym)) sym = keyword_symbol(sym); /* else make_slot will mark the keyword as local confusing odd_bits etc */
49774 	  slot = slot_in_let(sc, e, sym);
49775 	  if (is_slot(slot))
49776 	    checked_slot_set_value(sc, slot, cdr(val));
49777 	  else make_slot_1(sc, e, sym, cdr(val));
49778 	  return(cdr(val));
49779 	}}
49780   set_car(sc->elist_3, wrap_string(sc, "~S: ~S is not (cons symbol value)", 33));
49781   set_caddr(sc->elist_3, val);
49782   return(s7_error(sc, sc->wrong_type_arg_symbol, sc->elist_3));
49783 }
49784 
49785 static s7_pointer hash_table_setter(s7_scheme *sc, s7_pointer e, s7_int loc, s7_pointer val)
49786 {
49787   /* loc is irrelevant here, e is the hash-table, val has to be of the form (cons key value)
49788    * if key is already in e, its value is changed, otherwise a new slot is added to e
49789    */
49790   if (is_pair(val))
49791     return(s7_hash_table_set(sc, e, car(val), cdr(val)));
49792 
49793   set_car(sc->elist_3, wrap_string(sc, "~S: ~S is not (cons key value)", 30));
49794   set_caddr(sc->elist_3, val);
49795   return(s7_error(sc, sc->wrong_type_arg_symbol, sc->elist_3));
49796 }
49797 
49798 
49799 static s7_pointer copy_source_no_dest(s7_scheme *sc, s7_pointer caller, s7_pointer source, s7_pointer args)
49800 {
49801   s7_pointer dest;
49802   switch (type(source))
49803     {
49804     case T_STRING:
49805       return(make_string_with_length(sc, string_value(source), string_length(source)));
49806 
49807     case T_C_OBJECT:
49808       return(copy_c_object(sc, args));
49809 
49810     case T_RANDOM_STATE:
49811       return(rng_copy(sc, args));
49812 
49813     case T_HASH_TABLE:              /* this has to copy nearly everything */
49814       {
49815 	s7_int gc_loc;
49816 	s7_pointer new_hash;
49817 	new_hash = s7_make_hash_table(sc, hash_table_mask(source) + 1);
49818 	gc_loc = s7_gc_protect_1(sc, new_hash);
49819 	hash_table_checker(new_hash) = hash_table_checker(source);
49820 	if (hash_chosen(source)) hash_set_chosen(new_hash);
49821 	hash_table_mapper(new_hash) = hash_table_mapper(source);
49822 	hash_table_set_procedures(new_hash, hash_table_procedures(source));
49823 	hash_table_copy(sc, source, new_hash, 0, hash_table_entries(source));
49824 	if (is_typed_hash_table(source))
49825 	  {
49826 	    set_typed_hash_table(new_hash);
49827 	    if (has_simple_keys(source))
49828 	      set_has_simple_keys(new_hash);
49829 	    if (has_simple_values(source))
49830 	      set_has_simple_values(new_hash);
49831 	  }
49832 	s7_gc_unprotect_at(sc, gc_loc);
49833 	return(new_hash);
49834       }
49835 
49836     case T_ITERATOR:
49837       return(iterator_copy(sc, source));
49838 
49839     case T_LET:
49840       check_method(sc, source, sc->copy_symbol, args);
49841       return(let_copy(sc, source));   /* this copies only the local let and points to outer lets */
49842 
49843     case T_CLOSURE: case T_CLOSURE_STAR:
49844     case T_MACRO:   case T_MACRO_STAR:
49845     case T_BACRO:   case T_BACRO_STAR:
49846       check_method(sc, source, sc->copy_symbol, args);
49847       return(copy_closure(sc, source));
49848 
49849     case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_VECTOR: case T_BYTE_VECTOR:
49850       return(s7_vector_copy(sc, source)); /* "shallow" copy */
49851 
49852     case T_PAIR:                    /* top level only, as in the other cases, checks for circles */
49853       return(copy_any_list(sc, source));
49854 
49855     case T_INTEGER:
49856       new_cell(sc, dest, T_INTEGER);
49857       integer(dest) = integer(source);
49858       return(dest);
49859 
49860     case T_RATIO:
49861       new_cell(sc, dest, T_RATIO);
49862       numerator(dest) = numerator(source);
49863       denominator(dest) = denominator(source);
49864       return(dest);
49865 
49866     case T_REAL:
49867       new_cell(sc, dest, T_REAL);
49868       set_real(dest, real(source));
49869       return(dest);
49870 
49871     case T_COMPLEX:
49872       new_cell(sc, dest, T_COMPLEX);
49873       set_real_part(dest, real_part(source));
49874       set_imag_part(dest, imag_part(source));
49875       return(dest);
49876 
49877 #if WITH_GMP
49878     case T_BIG_INTEGER: return(mpz_to_big_integer(sc, big_integer(source)));
49879     case T_BIG_RATIO:   return(mpq_to_big_ratio(sc, big_ratio(source)));
49880     case T_BIG_REAL:    return(mpfr_to_big_real(sc, big_real(source)));
49881     case T_BIG_COMPLEX: return(mpc_to_number(sc, big_complex(source)));
49882 #endif
49883 
49884     case T_C_POINTER:
49885       dest = s7_make_c_pointer_with_type(sc, c_pointer(source), c_pointer_type(source), c_pointer_info(source));
49886       c_pointer_weak1(dest) = c_pointer_weak1(source);
49887       c_pointer_weak2(dest) = c_pointer_weak2(source);
49888       return(dest);
49889     }
49890   return(source);
49891 }
49892 
49893 static s7_pointer copy_to_same_type(s7_scheme *sc, s7_pointer dest, s7_pointer source, s7_int dest_start, s7_int dest_end, s7_int source_start)
49894 {
49895   /* types equal, but not a let (handled in s7_copy_1), returns NULL if not copied here */
49896   s7_int i, j, source_len;
49897   source_len = dest_end - dest_start;
49898   switch (type(source))
49899     {
49900     case T_PAIR:
49901       {
49902 	s7_pointer pd, ps;
49903 	for (ps = source, i = 0; i < source_start; i++)
49904 	  ps = cdr(ps);
49905 	for (pd = dest, i = 0; i < dest_start; i++)
49906 	  pd = cdr(pd);
49907 	for (; (i < dest_end) && is_pair(ps) && is_pair(pd); i++, ps = cdr(ps), pd = cdr(pd))
49908 	  set_car(pd, car(ps));
49909 	return(dest);
49910       }
49911 
49912     case T_VECTOR:
49913       if (is_typed_vector(dest))
49914 	{
49915 	  s7_pointer *els;
49916 	  els = vector_elements(source);
49917 	  for (i = source_start, j = dest_start; j < dest_end; i++, j++)
49918 	    typed_vector_setter(sc, dest, j, els[i]);                     /* types are equal, so source is a normal vector */
49919 	}
49920       else memcpy((void *)((vector_elements(dest)) + dest_start), (void *)((vector_elements(source)) + source_start), source_len * sizeof(s7_pointer));
49921       return(dest);
49922 
49923     case T_INT_VECTOR:
49924       memcpy((void *)((int_vector_ints(dest)) + dest_start), (void *)((int_vector_ints(source)) + source_start), source_len * sizeof(s7_int));
49925       return(dest);
49926 
49927     case T_FLOAT_VECTOR:
49928       memcpy((void *)((float_vector_floats(dest)) + dest_start), (void *)((float_vector_floats(source)) + source_start), source_len * sizeof(s7_double));
49929       return(dest);
49930 
49931     case T_BYTE_VECTOR:
49932       if (is_string(dest))
49933 	memcpy((void *)(string_value(dest) + dest_start), (void *)((byte_vector_bytes(source)) + source_start), source_len * sizeof(uint8_t));
49934       else memcpy((void *)(byte_vector_bytes(dest) + dest_start), (void *)((byte_vector_bytes(source)) + source_start), source_len * sizeof(uint8_t));
49935       return(dest);
49936 
49937     case T_STRING:
49938       if (is_string(dest))
49939 	memcpy((void *)(string_value(dest) + dest_start), (void *)((string_value(source)) + source_start), source_len);
49940       else memcpy((void *)(byte_vector_bytes(dest) + dest_start), (void *)((string_value(source)) + source_start), source_len);
49941       return(dest);
49942 
49943     case T_C_OBJECT:
49944       {
49945 	s7_pointer mi, mj;
49946 	s7_int gc_loc1, gc_loc2;
49947 	s7_pointer (*cref)(s7_scheme *sc, s7_pointer args);
49948 	s7_pointer (*cset)(s7_scheme *sc, s7_pointer args);
49949 
49950 	mi = make_mutable_integer(sc, 0);
49951 	mj = make_mutable_integer(sc, 0);
49952 	gc_loc1 = s7_gc_protect_1(sc, mi);
49953 	gc_loc2 = s7_gc_protect_1(sc, mj);
49954 	cref = c_object_ref(sc, source);
49955 	cset = c_object_set(sc, dest);
49956 
49957 	for (i = source_start, j = dest_start; i < dest_end; i++, j++)
49958 	  {
49959 	    integer(mi) = i;
49960 	    integer(mj) = j;
49961 	    set_car(sc->t2_1, source);
49962 	    set_car(sc->t2_2, mi);
49963 	    set_car(sc->t3_3, cref(sc, sc->t2_1));
49964 	    set_car(sc->t3_1, dest);
49965 	    set_car(sc->t3_2, mj);
49966 	    cset(sc, sc->t3_1);
49967 	  }
49968 	s7_gc_unprotect_at(sc, gc_loc1);
49969 	s7_gc_unprotect_at(sc, gc_loc2);
49970 	free_cell(sc, mi);
49971 	free_cell(sc, mj);
49972 	return(dest);
49973       }
49974 
49975     case T_LET:
49976       return(NULL);
49977 
49978     case T_HASH_TABLE:
49979       {
49980 	s7_pointer p;
49981 	p = hash_table_copy(sc, source, dest, source_start, source_start + source_len);
49982 	if ((hash_table_checker(source) != hash_table_checker(dest)) &&
49983 	    (!hash_table_checker_locked(dest)))
49984 	  {
49985 	    if (hash_table_checker(dest) == hash_empty)
49986 	      hash_table_checker(dest) = hash_table_checker(source);
49987 	    else
49988 	      {
49989 		hash_table_checker(dest) = hash_equal;
49990 		hash_set_chosen(dest);
49991 	      }}
49992 	return(p);
49993       }
49994 
49995     default:
49996       return(dest);
49997     }
49998   return(NULL);
49999 }
50000 
50001 static s7_pointer s7_copy_1(s7_scheme *sc, s7_pointer caller, s7_pointer args)
50002 {
50003   #define H_copy "(copy obj) returns a copy of obj, (copy src dest) copies src into dest, (copy src dest start end) copies src from start to end."
50004   /* #define Q_copy s7_make_circular_signature(sc, 3, 4, sc->T, sc->is_sequence_symbol, sc->is_sequence_symbol, sc->is_integer_symbol) */
50005   /* this is not right when c-object types are handled in lint -- a generator or Snd object need not consider itself a sequence,
50006    *   but it can provide a copy method.  So, I think I'll just use #t
50007    */
50008   #define Q_copy s7_make_circular_signature(sc, 3, 4, sc->T, sc->T, sc->T, sc->is_integer_symbol)
50009 
50010   s7_pointer source, dest;
50011   s7_int i, j, dest_len, start, end, source_len;
50012   s7_pointer (*set)(s7_scheme *sc, s7_pointer obj, s7_int loc, s7_pointer val) = NULL;
50013   s7_pointer (*get)(s7_scheme *sc, s7_pointer obj, s7_int loc) = NULL;
50014   bool have_indices;
50015 
50016   source = T_Pos(car(args));
50017   if (is_null(cdr(args)))                  /* (copy obj) */
50018     return(copy_source_no_dest(sc, caller, source, args));
50019 
50020   dest = T_Pos(cadr(args));
50021   if ((dest == sc->key_readable_symbol) && (!is_pair(source)))
50022     return(s7_error(sc, sc->out_of_range_symbol, set_elist_1(sc, wrap_string(sc, "copy argument 2, :readable, only works if the source is a pair", 62))));
50023 
50024   if ((is_immutable(dest)) &&
50025       (dest != sc->key_readable_symbol) &&
50026       (dest != sc->nil))                                                      /* error_hook copies with cadr(args) :readable, so it's currently NULL */
50027     return(s7_wrong_type_arg_error(sc, symbol_name(caller), 2, dest, "a mutable object")); /*    so this segfaults if not checking for :readable */
50028 
50029   have_indices = (is_pair(cddr(args)));
50030   if ((source == dest) && (!have_indices))
50031     return(dest);
50032 
50033   switch (type(source))
50034     {
50035     case T_PAIR:
50036       if (dest == sc->key_readable_symbol)  /* a kludge, but I can't think of anything less stupid */
50037 	{
50038 	  if (have_indices)                 /* it seems to me that the start/end args here don't make any sense so... */
50039 	    return(s7_error(sc, sc->wrong_number_of_args_symbol,
50040 			    set_elist_3(sc, wrap_string(sc, "~S: start/end indices make no sense with :readable: ~S", 54), caller, args)));
50041 	  return(copy_body(sc, source));
50042 	}
50043       end = s7_list_length(sc, source);
50044       if (end == 0)
50045 	end = circular_list_entries(source);
50046       else
50047 	if (end < 0) end = -end;
50048       break;
50049 
50050     case T_INT_VECTOR:  case T_FLOAT_VECTOR: case T_VECTOR: case T_BYTE_VECTOR:
50051       get = vector_getter(source);
50052       end = vector_length(source);
50053       break;
50054 
50055     case T_STRING:
50056       get = string_getter;
50057       end = string_length(source);
50058       break;
50059 
50060     case T_HASH_TABLE:
50061       if (source == dest) return(dest);
50062       end = hash_table_entries(source);
50063       break;
50064 
50065     case T_C_OBJECT:
50066       if (c_object_copy(sc, source))
50067 	{
50068 	  s7_pointer x;
50069 	  x = (*(c_object_copy(sc, source)))(sc, args);
50070 	  if (x == dest)
50071 	    return(dest);
50072 	}
50073       check_method(sc, source, sc->copy_symbol, args);
50074       get = c_object_getter;
50075       end = c_object_length_to_int(sc, source);
50076       break;
50077 
50078     case T_LET:
50079       if (source == dest) return(dest);
50080       check_method(sc, source, sc->copy_symbol, args);
50081       if (source == sc->rootlet)
50082 	return(wrong_type_argument_with_type(sc, caller, 1, source, wrap_string(sc, "a sequence other than the rootlet", 33)));
50083       if ((!have_indices) && (is_let(dest)) && (dest != sc->s7_let))
50084 	{
50085 	  s7_pointer slot;
50086 	  if (dest == sc->rootlet) /* (copy (inlet 'a 1) (rootlet)) */
50087 	    for (slot = let_slots(source); tis_slot(slot); slot = next_slot(slot))
50088 	      s7_make_slot(sc, dest, slot_symbol(slot), slot_value(slot));
50089 	  else
50090 	    {
50091 	      if ((has_let_fallback(source)) &&
50092 		  (has_let_fallback(dest)))
50093 		{
50094 		  for (slot = let_slots(source); tis_slot(slot); slot = next_slot(slot))
50095 		    if ((slot_symbol(slot) != sc->let_ref_fallback_symbol) &&
50096 			(slot_symbol(slot) != sc->let_set_fallback_symbol))
50097 		      make_slot_1(sc, dest, slot_symbol(slot), slot_value(slot));
50098 		}
50099 	      else
50100 		for (slot = let_slots(source); tis_slot(slot); slot = next_slot(slot))
50101 		  make_slot_1(sc, dest, slot_symbol(slot), slot_value(slot));
50102 	    }
50103 	  return(dest);
50104 	}
50105       end = let_length(sc, source);
50106       break;
50107 
50108     case T_NIL:
50109       end = 0;
50110       if (is_sequence(dest))
50111 	break;
50112 
50113     default:
50114       return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_4(sc, wrap_string(sc, "can't ~S ~S to ~S", 17), caller, source, dest)));
50115     }
50116 
50117   start = 0;
50118   if (have_indices)
50119     {
50120       s7_pointer p;
50121       p = start_and_end(sc, caller, args, 3, cddr(args), &start, &end);
50122       if (p != sc->unused) return(p);
50123     }
50124   if ((start == 0) && (source == dest))
50125     return(dest);
50126   source_len = end - start;
50127   if (source_len == 0)
50128     {
50129       if (!is_sequence(dest))
50130 	return(wrong_type_argument_with_type(sc, caller, 2, dest, a_sequence_string));
50131       return(dest);
50132     }
50133 
50134   switch (type(dest))
50135     {
50136     case T_PAIR:
50137       dest_len = source_len;
50138       break;
50139 
50140     case T_INT_VECTOR:
50141     case T_FLOAT_VECTOR:
50142     case T_BYTE_VECTOR:
50143       set = vector_setter(dest);
50144       dest_len = vector_length(dest);
50145       break;
50146 
50147     case T_VECTOR:
50148       set = (is_typed_vector(dest)) ? typed_vector_setter : vector_setter(dest);
50149       dest_len = vector_length(dest);
50150       break;
50151 
50152     case T_STRING:
50153       set = string_setter;
50154       dest_len = string_length(dest);
50155       set_cadr(sc->elist_3, caller);   /* for possible error handling in string_setter */
50156       break;
50157 
50158     case T_HASH_TABLE:
50159       set = hash_table_setter;
50160       dest_len = source_len;
50161       set_cadr(sc->elist_3, caller);   /* for possible error handling in hash_table_setter */
50162       break;
50163 
50164     case T_C_OBJECT:
50165       /* if source or dest is c_object, call its copy function before falling back on the get/set functions */
50166       if (c_object_copy(sc, dest))
50167 	{
50168 	  s7_pointer x;
50169 	  x = (*(c_object_copy(sc, dest)))(sc, args);
50170 	  if (x == dest)
50171 	    return(dest);
50172 	}
50173       set = c_object_setter;
50174       dest_len = c_object_length_to_int(sc, dest);
50175       break;
50176 
50177     case T_LET:
50178       if ((dest == sc->rootlet) || (dest == sc->s7_let))
50179 	return(wrong_type_argument_with_type(sc, caller, 2, dest, wrap_string(sc, "a sequence other than the rootlet or *s7*", 41)));
50180       set = let_setter;
50181       dest_len = source_len;          /* grows via set, so dest_len isn't relevant */
50182       set_cadr(sc->elist_3, caller);  /* for possible error handling in let_setter */
50183       break;
50184 
50185     case T_NIL:
50186       return(sc->nil);
50187 
50188     default:
50189       return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_4(sc, wrap_string(sc, "can't ~S ~S to ~S", 17), caller, source, dest)));
50190     }
50191 
50192   if (dest_len == 0)
50193     return(dest);
50194 
50195   /* end is source_len if not set explicitly */
50196   if (dest_len < source_len)
50197     {
50198       end = dest_len + start;
50199       source_len = dest_len;
50200     }
50201 
50202   if ((source != dest) &&
50203       ((type(source) == type(dest)) ||
50204        ((is_string_or_byte_vector(source)) &&
50205 	(is_string_or_byte_vector(dest)))))
50206     {
50207       s7_pointer res;
50208       res = copy_to_same_type(sc, dest, source, 0, source_len, start);
50209       if (res) return(res);
50210     }
50211 
50212   switch (type(source))
50213     {
50214     case T_PAIR:
50215       {
50216 	s7_pointer p;
50217 	p = source;
50218 	if (start > 0)
50219 	  for (i = 0; i < start; i++)
50220 	    p = cdr(p);
50221 	/* dest won't be a pair here if source != dest -- the pair->pair case was caught above */
50222 	if (source == dest) /* here start != 0 (see above) */
50223 	  {
50224 	    s7_pointer dp;
50225 	    for (dp = source, i = start; i < end; i++, p = cdr(p), dp = cdr(dp))
50226 	      set_car(dp, car(p));
50227 	  }
50228 	else
50229 	  {
50230 	    if (is_string(dest))
50231 	      {
50232 		char *dst;
50233 		dst = (char *)string_value(dest);
50234 		for (i = start, j = 0; i < end; i++, j++, p = cdr(p))
50235 		  {
50236 		    if (!s7_is_character(car(p)))
50237 		      return(simple_wrong_type_argument(sc, caller, car(p), T_CHARACTER));
50238 		    dst[j] = character(car(p));
50239 		  }}
50240 	    else
50241 	      for (i = start, j = 0; i < end; i++, j++, p = cdr(p))
50242 		set(sc, dest, j, car(p));
50243 	  }
50244 	return(dest);
50245       }
50246 
50247     case T_LET:
50248       /* implicit index can give n-way reality check (ht growth by new entries)
50249        * if shadowed entries are they unshadowed by reversal?
50250        */
50251       if (source == sc->s7_let)
50252 	{
50253 	  s7_pointer iter;
50254 	  s7_int gc_loc;
50255 	  iter = s7_make_iterator(sc, sc->s7_let);
50256 	  gc_loc = s7_gc_protect(sc, iter);
50257 	  for (i = 0; i < start; i++)
50258 	    {
50259 	      s7_iterate(sc, iter);
50260 	      if (iterator_is_at_end(iter))
50261 		{
50262 		  s7_gc_unprotect_at(sc, gc_loc);
50263 		  return(dest);
50264 		}}
50265 	  for (i = start, j = 0; i < end; i++, j++)
50266 	    {
50267 	      s7_pointer val;
50268 	      val =  s7_iterate(sc, iter);
50269 	      if (iterator_is_at_end(iter)) break;
50270 	      set(sc, dest, j, val);
50271 	    }
50272 	  s7_gc_unprotect_at(sc, gc_loc);
50273 	}
50274       else
50275 	{
50276 	  /* source and dest can't be rootlet (checked above), dest also can't be *s7* */
50277 	  s7_pointer slot;
50278 	  slot = let_slots(source);
50279 	  for (i = 0; i < start; i++) slot = next_slot(slot);
50280 	  if (is_pair(dest))
50281 	    {
50282 	      s7_pointer p;
50283 	      for (i = start, p = dest; (i < end) && (is_pair(p)); i++, p = cdr(p), slot = next_slot(slot))
50284 		set_car(p, cons(sc, slot_symbol(slot), slot_value(slot)));
50285 	    }
50286 	  else
50287 	    {
50288 	      if (is_let(dest))
50289 		{
50290 		  if ((has_let_fallback(source)) &&
50291 		      (has_let_fallback(dest)))
50292 		    {
50293 		      for (slot = let_slots(source); tis_slot(slot); slot = next_slot(slot))
50294 			if ((slot_symbol(slot) != sc->let_ref_fallback_symbol) &&
50295 			    (slot_symbol(slot) != sc->let_set_fallback_symbol))
50296 			  make_slot_1(sc, dest, slot_symbol(slot), slot_value(slot));
50297 		    }
50298 		  else
50299 		    for (i = start; i < end; i++, slot = next_slot(slot))
50300 		      make_slot_1(sc, dest, slot_symbol(slot), slot_value(slot));
50301 		}
50302 	      else
50303 		{
50304 		  if (is_hash_table(dest))
50305 		    for (i = start; i < end; i++, slot = next_slot(slot))
50306 		      s7_hash_table_set(sc, dest, slot_symbol(slot), slot_value(slot));
50307 		  else
50308 		    for (i = start, j = 0; i < end; i++, j++, slot = next_slot(slot))
50309 		      set(sc, dest, j, cons(sc, slot_symbol(slot), slot_value(slot)));
50310 		}}}
50311       return(dest);
50312 
50313     case T_HASH_TABLE:
50314       {
50315 	s7_int loc, skip;
50316 	hash_entry_t **elements;
50317 	hash_entry_t *x = NULL;
50318 	elements = hash_table_elements(source);
50319 	loc = -1;
50320 
50321 	skip = start;
50322 	while (skip > 0)
50323 	  {
50324 	    while (!x) x = elements[++loc];
50325 	    skip--;
50326 	    x = hash_entry_next(x);
50327 	  }
50328 
50329       if (is_pair(dest))
50330 	{
50331 	  s7_pointer p;
50332 	  for (i = start, p = dest; (i < end) && (is_pair(p)); i++, p = cdr(p))
50333 	    {
50334 	      while (!x) x = elements[++loc];
50335 	      set_car(p, cons(sc, hash_entry_key(x), hash_entry_value(x)));
50336 	      x = hash_entry_next(x);
50337 	    }}
50338       else
50339 	{
50340 	  if (is_let(dest))
50341 	    {
50342 	      for (i = start; i < end; i++)
50343 		{
50344 		  s7_pointer symbol;
50345 		  while (!x) x = elements[++loc];
50346 		  symbol = hash_entry_key(x);
50347 		  if (!is_symbol(symbol))
50348 		    return(simple_wrong_type_argument(sc, caller, symbol, T_SYMBOL));
50349 		  if (is_constant_symbol(sc, symbol))
50350 		    return(s7_error(sc, sc->wrong_type_arg_symbol,
50351 				    set_elist_4(sc, wrap_string(sc, "~A into ~A: ~A is a constant", 28), caller, dest, symbol)));
50352 		  if ((symbol != sc->let_ref_fallback_symbol) &&
50353 		      (symbol != sc->let_set_fallback_symbol))
50354 		    make_slot_1(sc, dest, symbol, hash_entry_value(x));
50355 		  x = hash_entry_next(x);
50356 		}}
50357 	  else
50358 	    for (i = start, j = 0; i < end; i++, j++)
50359 	      {
50360 		while (!x) x = elements[++loc];
50361 		set(sc, dest, j, cons(sc, hash_entry_key(x), hash_entry_value(x)));
50362 		x = hash_entry_next(x);
50363 	      }}
50364       return(dest);
50365       }
50366 
50367     case T_VECTOR:
50368       {
50369 	s7_pointer *vals;
50370 	vals = vector_elements(source);
50371 	if (is_float_vector(dest))
50372 	  {
50373 	    s7_double *dst;
50374 	    dst = float_vector_floats(dest);
50375 	    for (i = start, j = 0; i < end; i++, j++)
50376 	      dst[j] = real_to_double(sc, vals[i], "copy");
50377 	    return(dest);
50378 	  }
50379 	if (is_int_vector(dest))
50380 	  {
50381 	    s7_int *dst;
50382 	    dst = int_vector_ints(dest);
50383 	    for (i = start, j = 0; i < end; i++, j++)
50384 	      {
50385 		if (!s7_is_integer(vals[i]))
50386 		  return(simple_wrong_type_argument(sc, caller, vals[i], T_INTEGER));
50387 		dst[j] = s7_integer_checked(sc, vals[i]);
50388 	      }
50389 	    return(dest);
50390 	  }
50391 	if (is_string(dest))
50392 	  {
50393 	    char *dst;
50394 	    dst = (char *)string_value(dest);
50395 	    for (i = start, j = 0; i < end; i++, j++)
50396 	      {
50397 		if (!s7_is_character(vals[i]))
50398 		  return(simple_wrong_type_argument(sc, caller, vals[i], T_CHARACTER));
50399 		dst[j] = character(vals[i]);
50400 	      }
50401 	    return(dest);
50402 	  }
50403 	if (is_byte_vector(dest))
50404 	  {
50405 	    uint8_t *dst;
50406 	    dst = (uint8_t *)byte_vector_bytes(dest);
50407 	    for (i = start, j = 0; i < end; i++, j++)
50408 	      {
50409 		s7_int byte;
50410 		if (!s7_is_integer(vals[i]))
50411 		  return(simple_wrong_type_argument_with_type(sc, caller, vals[i], an_unsigned_byte_string));
50412 		byte = s7_integer_checked(sc, vals[i]);
50413 		if ((byte >= 0) && (byte < 256))
50414 		  dst[j] = (uint8_t)byte;
50415 		else return(simple_wrong_type_argument_with_type(sc, caller, vals[i], an_unsigned_byte_string));
50416 	      }
50417 	    return(dest);
50418 	  }}
50419       break;
50420 
50421     case T_FLOAT_VECTOR:
50422       {
50423 	s7_double *src;
50424 	src = float_vector_floats(source);
50425 	if (is_int_vector(dest))
50426 	  {
50427 	    s7_int *dst;
50428 	    dst = int_vector_ints(dest);
50429 	    for (i = start, j = 0; i < end; i++, j++)
50430 	      dst[j] = (s7_int)(src[i]);
50431 	    return(dest);
50432 	  }
50433 	if ((is_normal_vector(dest)) && (!is_typed_vector(dest)))
50434 	  {
50435 	    s7_pointer *dst;
50436 	    dst = vector_elements(dest);
50437 	    for (i = start, j = 0; i < end; i++, j++)
50438 	      dst[j] = make_real(sc, src[i]);
50439 	    return(dest);
50440 	  }}
50441       break;
50442 
50443     case T_INT_VECTOR:
50444       {
50445 	s7_int *src;
50446 	src = int_vector_ints(source);
50447 	if (is_float_vector(dest))
50448 	  {
50449 	    s7_double *dst;
50450 	    dst = float_vector_floats(dest);
50451 	    for (i = start, j = 0; i < end; i++, j++)
50452 	      dst[j] = (s7_double)(src[i]);
50453 	    return(dest);
50454 	  }
50455 	if ((is_normal_vector(dest)) && (!is_typed_vector(dest)))
50456 	  /* this could check that the typer is integer? (similarly elsewhere):
50457 	   *   (typed_vector_typer(dest) != global_value(sc->is_integer_symbol)) ?
50458 	   */
50459 	  {
50460 	    s7_pointer *dst;
50461 	    dst = vector_elements(dest);
50462 	    for (i = start, j = 0; i < end; i++, j++)
50463 	      dst[j] = make_integer(sc, src[i]);
50464 	    return(dest);
50465 	  }
50466 	if (is_string(dest))
50467 	  {
50468 	    for (i = start, j = 0; i < end; i++, j++)
50469 	      {
50470 		if ((src[i] < 0) || (src[i] > 255))
50471 		  return(out_of_range(sc, caller, int_one, wrap_integer1(sc, src[i]), an_unsigned_byte_string));
50472 		string_value(dest)[j] = (uint8_t)(src[i]);
50473 	      }
50474 	    return(dest);
50475 	  }
50476 	if (is_byte_vector(dest))
50477 	  {
50478 	    for (i = start, j = 0; i < end; i++, j++)
50479 	      {
50480 		if ((src[i] < 0) || (src[i] > 255))
50481 		  return(out_of_range(sc, caller, int_one, wrap_integer1(sc, src[i]), an_unsigned_byte_string));
50482 		byte_vector(dest, j) = (uint8_t)(src[i]);
50483 	      }
50484 	    return(dest);
50485 	  }}
50486       break;
50487 
50488     case T_BYTE_VECTOR:
50489       if ((is_normal_vector(dest)) && (!is_typed_vector(dest)))
50490 	{
50491 	  s7_pointer *dst;
50492 	  dst = vector_elements(dest);
50493 	  for (i = start, j = 0; i < end; i++, j++)
50494 	    dst[j] = make_integer(sc, (s7_int)(byte_vector(source, i)));
50495 	  return(dest);
50496 	}
50497       if (is_int_vector(dest))
50498 	{
50499 	  s7_int *els;
50500 	  els = int_vector_ints(dest);
50501 	  for (i = start, j = 0; i < end; i++, j++)
50502 	    els[j] = (s7_int)((uint8_t)(byte_vector(source, i)));
50503 	  return(dest);
50504 	}
50505       if (is_float_vector(dest))
50506 	{
50507 	  s7_double *els;
50508 	  els = float_vector_floats(dest);
50509 	  for (i = start, j = 0; i < end; i++, j++)
50510 	    els[j] = (s7_double)((uint8_t)(byte_vector(source, i)));
50511 	  return(dest);
50512 	}
50513       break;
50514 
50515     case T_STRING:
50516       if ((is_normal_vector(dest))  && (!is_typed_vector(dest)))
50517 	{
50518 	  s7_pointer *dst;
50519 	  dst = vector_elements(dest);
50520 	  for (i = start, j = 0; i < end; i++, j++)
50521 	    dst[j] = s7_make_character(sc, (uint8_t)string_value(source)[i]);
50522 	  return(dest);
50523 	}
50524       if (is_int_vector(dest))
50525 	{
50526 	  s7_int *els;
50527 	  els = int_vector_ints(dest);
50528 	  for (i = start, j = 0; i < end; i++, j++)
50529 	    els[j] = (s7_int)((uint8_t)(string_value(source)[i]));
50530 	  return(dest);
50531 	}
50532       if (is_float_vector(dest))
50533 	{
50534 	  s7_double *els;
50535 	  els = float_vector_floats(dest);
50536 	  for (i = start, j = 0; i < end; i++, j++)
50537 	    els[j] = (s7_double)((uint8_t)(string_value(source)[i]));
50538 	  return(dest);
50539 	}
50540       break;
50541     }
50542 
50543   if (is_pair(dest))
50544     {
50545       s7_pointer p;
50546       if (is_float_vector(source))
50547 	{
50548 	  s7_double *els;
50549 	  els = float_vector_floats(source);
50550 	  for (i = start, p = dest; (i < end) && (is_pair(p)); i++, p = cdr(p))
50551 	    set_car(p, make_real(sc, els[i]));
50552 	}
50553       else
50554 	{
50555 	  if (is_int_vector(source))
50556 	    {
50557 	      s7_int *els;
50558 	      els = int_vector_ints(source);
50559 	      for (i = start, p = dest; (i < end) && (is_pair(p)); i++, p = cdr(p))
50560 		set_car(p, make_integer(sc, els[i]));
50561 	    }
50562 	  else
50563 	    for (i = start, p = dest; (i < end) && (is_pair(p)); i++, p = cdr(p))
50564 	      set_car(p, get(sc, source, i));
50565 	}}
50566   else /* if source == dest here, we're moving data backwards, so this is safe in either case */
50567     for (i = start, j = 0; i < end; i++, j++)
50568       set(sc, dest, j, get(sc, source, i));
50569 
50570   /* some choices probably should raise an error, but don't:
50571    *   (copy (make-hash-table) "1") ; nothing to copy (empty hash table), so no error
50572    */
50573   return(dest);
50574 }
50575 
50576 s7_pointer s7_copy(s7_scheme *sc, s7_pointer args) {return(s7_copy_1(sc, sc->copy_symbol, args));}
50577 
50578 #define g_copy s7_copy
50579 
50580 
50581 /* -------------------------------- reverse -------------------------------- */
50582 
50583 s7_pointer s7_reverse(s7_scheme *sc, s7_pointer a)
50584 {
50585   /* reverse list -- produce new list (other code assumes this function does not return the original!) */
50586   s7_pointer x, p;
50587 
50588   if (is_null(a)) return(a);
50589 
50590   if (!is_pair(cdr(a)))
50591     return((is_null(cdr(a))) ? list_1(sc, car(a)) : cons(sc, cdr(a), car(a)));  /* don't return 'a' itself */
50592 
50593   sc->w = list_1(sc, car(a));
50594   for (x = cdr(a), p = a; is_pair(x); x = cdr(x), p = cdr(p))
50595     {
50596       sc->w = cons(sc, car(x), sc->w);
50597       if (is_pair(cdr(x)))
50598 	{
50599 	  x = cdr(x);
50600 	  sc->w = cons(sc, car(x), sc->w);
50601 	}
50602       if (x == p) /* this can take awhile to notice there's a cycle, but what does the caller expect? */
50603 	break;
50604     }
50605 
50606   if (is_not_null(x))
50607     p = cons(sc, x, sc->w);    /* ?? this means that (reverse '(1 2 . 3)) returns '(3 2 1) -- we used to return () here */
50608   else p = sc->w;
50609 
50610   sc->w = sc->nil;
50611   return(p);
50612 }
50613 
50614 /* s7_reverse sometimes tacks extra nodes on the end of a reversed circular list (it detects the cycle too late)
50615  *  (let ((lst (list 0))) (set! (cdr lst) lst) (reverse lst)) -> (#1=(0 . #1#) 0 0 0)
50616  */
50617 
50618 static s7_pointer g_reverse(s7_scheme *sc, s7_pointer args)
50619 {
50620   #define H_reverse "(reverse lst) returns a list with the elements of lst in reverse order.  reverse \
50621 also accepts a string or vector argument."
50622   #define Q_reverse s7_make_signature(sc, 2, sc->is_sequence_symbol, sc->is_sequence_symbol)
50623 
50624   s7_pointer p, np;
50625 
50626   p = car(args);
50627   sc->temp3 = p;
50628   np = sc->nil;
50629 
50630   switch (type(p))
50631     {
50632     case T_NIL:
50633       return(sc->nil);
50634 
50635     case T_PAIR:
50636       return(s7_reverse(sc, p));
50637 
50638     case T_STRING:
50639       {
50640 	char *source, *dest, *end;
50641 	s7_int len;
50642 	len = string_length(p);
50643 	source = string_value(p);
50644 	end = (char *)(source + len);
50645 	np = make_empty_string(sc, len, '\0');
50646 	dest = (char *)(string_value(np) + len);
50647 	while (source < end) *(--dest) = *source++;
50648       }
50649       break;
50650 
50651     case T_BYTE_VECTOR:
50652       {
50653 	uint8_t *source, *dest, *end;
50654 	s7_int len;
50655 	len = byte_vector_length(p);
50656 	source = byte_vector_bytes(p);
50657 	end = (uint8_t *)(source + len);
50658 	np = make_simple_byte_vector(sc, len);
50659 	dest = (uint8_t *)(byte_vector_bytes(np) + len);
50660 	while (source < end) *(--dest) = *source++;
50661       }
50662       break;
50663 
50664     case T_INT_VECTOR:
50665       {
50666 	s7_int *source, *dest, *end;
50667 	s7_int len;
50668 	len = vector_length(p);
50669 	if (vector_rank(p) > 1)
50670 	  np = g_make_vector_1(sc, set_plist_2(sc, g_vector_dimensions(sc, set_plist_1(sc, p)), int_zero), sc->make_int_vector_symbol);
50671 	else np = make_simple_int_vector(sc, len);
50672 	source = int_vector_ints(p);
50673 	end = (s7_int *)(source + len);
50674 	dest = (s7_int *)(int_vector_ints(np) + len);
50675 	while (source < end) *(--dest) = *source++;
50676       }
50677       break;
50678 
50679     case T_FLOAT_VECTOR:
50680       {
50681 	s7_double *source, *dest, *end;
50682 	s7_int len;
50683 	len = vector_length(p);
50684 	if (vector_rank(p) > 1)
50685 	  np = g_make_vector_1(sc, set_plist_2(sc, g_vector_dimensions(sc, set_plist_1(sc, p)), real_zero), sc->make_float_vector_symbol);
50686 	else np = make_simple_float_vector(sc, len);
50687 	source = float_vector_floats(p);
50688 	end = (s7_double *)(source + len);
50689 	dest = (s7_double *)(float_vector_floats(np) + len);
50690 	while (source < end) *(--dest) = *source++;
50691       }
50692       break;
50693 
50694     case T_VECTOR:
50695       {
50696 	s7_pointer *source, *dest, *end;
50697 	s7_int len;
50698 	len = vector_length(p);
50699 	if (vector_rank(p) > 1)
50700 	  np = g_make_vector(sc, set_plist_1(sc, g_vector_dimensions(sc, set_plist_1(sc, p))));
50701 	else np = make_simple_vector(sc, len);
50702 	source = vector_elements(p);
50703 	end = (s7_pointer *)(source + len);
50704 	dest = (s7_pointer *)(vector_elements(np) + len);
50705 	while (source < end) *(--dest) = *source++;
50706       }
50707       break;
50708 
50709     case T_HASH_TABLE:
50710       return(hash_table_reverse(sc, p));
50711 
50712     case T_C_OBJECT:
50713       check_method(sc, p, sc->reverse_symbol, args);
50714       if (c_object_reverse(sc, p))
50715 	return((*(c_object_reverse(sc, p)))(sc, args));
50716       eval_error(sc, "attempt to reverse ~S?", 22, p);
50717 
50718     case T_LET:
50719       check_method(sc, p, sc->reverse_symbol, args);
50720       return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, wrap_string(sc, "can't reverse let: ~S", 21), p)));
50721 
50722     default:
50723       return(method_or_bust_with_type_one_arg(sc, p, sc->reverse_symbol, args, a_sequence_string));
50724     }
50725   return(np);
50726 }
50727 
50728 static s7_pointer reverse_in_place(s7_scheme *sc, s7_pointer term, s7_pointer list)
50729 {
50730   s7_pointer p, result;
50731 
50732   if (is_null(list)) return(term);
50733   p = list;
50734   result = term;
50735   while (true)
50736     {
50737       s7_pointer q;
50738       q = cdr(p);
50739       if (is_null(q))
50740 	{
50741 	  set_cdr(p, result);
50742 	  return(p);
50743 	}
50744       if ((is_pair(q)) && (!is_immutable_pair(q)))
50745 	{
50746 	  set_cdr(p, result);
50747 	  result = p;
50748 	  p = q;
50749 	}
50750       else return(sc->nil); /* improper or immutable */
50751     }
50752   return(result);
50753 }
50754 
50755 static s7_pointer g_reverse_in_place(s7_scheme *sc, s7_pointer args)
50756 {
50757   s7_pointer p;
50758   #define H_reverse_in_place "(reverse! lst) reverses lst in place"
50759   #define Q_reverse_in_place Q_reverse
50760 
50761   p = car(args);
50762   switch (type(p))
50763     {
50764     case T_NIL:
50765       return(sc->nil);
50766 
50767     case T_PAIR:
50768       {
50769 	s7_pointer np;
50770 	if (is_immutable_pair(p))
50771 	  return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->reverseb_symbol, p)));
50772 	np = reverse_in_place(sc, sc->nil, p);
50773 	if (is_null(np))
50774 	  return(s7_wrong_type_arg_error(sc, "reverse!", 1, car(args), "a mutable, proper list"));
50775 	return(np);
50776       }
50777       /* (reverse! p) is supposed to change p directly and lisp programmers expect reverse! to be fast
50778        * so in a sense this is different from the other cases: it assumes (set! p (reverse! p))
50779        * To make (reverse! p) direct:
50780        *    for (l = p, r = cdr(p); is_pair(r); l = r, r = cdr(r)) opt1(r) = l;
50781        *    if (!is_null(r)) return(simple_wrong_type_argument_with_type(sc, sc->reverseb_symbol, p, a_proper_list_string));
50782        *    for (r = l, l = p; l != r; l = cdr(l)) {t = car(l); set_car(l, car(r)); set_car(r, t); if (cdr(l) != r) r = opt1(r);}
50783        * immutable check is needed else (reverse! (catch #t 1 cons)) clobbers sc->wrong_type_arg_info
50784        */
50785 
50786     case T_BYTE_VECTOR:
50787     case T_STRING:
50788       {
50789 	s7_int len;
50790 	uint8_t *bytes;
50791 	if (is_immutable(p))
50792 	  return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->reverseb_symbol, p)));
50793 
50794 	if (is_string(p))
50795 	  {
50796 	    len = string_length(p);
50797 	    bytes = (uint8_t *)string_value(p);
50798 	  }
50799 	else
50800 	  {
50801 	    len = byte_vector_length(p);
50802 	    bytes = byte_vector_bytes(p);
50803 	  }
50804 	if (len < 2) return(p);
50805 
50806 #if (defined(__linux__)) && (defined(__GLIBC__)) /* need byteswp.h */
50807 	/* this code (from StackOverflow) is much faster: */
50808 	if ((len & 0x1f) == 0)
50809 	  {
50810 	    #include <byteswap.h>
50811 	    uint32_t *dst = (uint32_t *)(bytes + len - 4);
50812 	    uint32_t *src = (uint32_t *)bytes;
50813 	    while (src < dst)
50814 	      {
50815 		uint32_t a, b;
50816 		LOOP_4(a = *src; b = *dst; *src++ = bswap_32(b); *dst-- = bswap_32(a));
50817 	      }}
50818 	else
50819 #endif
50820 	  {
50821 	    char *s1, *s2;
50822 	    s1 = (char *)bytes;
50823 	    s2 = (char *)(s1 + len - 1);
50824 	    while (s1 < s2) {char c; c = *s1; *s1++ = *s2; *s2-- = c;}
50825 	  }}
50826       break;
50827 
50828     case T_INT_VECTOR:
50829       {
50830 	s7_int len;
50831 	s7_int *s1, *s2;
50832 	if (is_immutable_vector(p))
50833 	  return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->reverseb_symbol, p)));
50834 	len = vector_length(p);
50835 	if (len < 2) return(p);
50836 	s1 = int_vector_ints(p);
50837 	s2 = (s7_int *)(s1 + len - 1);
50838 	if ((len & 0xf) == 0) /* not 0x7 -- odd multiple of 8 will leave center ints unreversed */
50839 	  while (s1 < s2)
50840 	    {
50841 	      s7_int c;
50842 	      LOOP_8(c = *s1; *s1++ = *s2; *s2-- = c);
50843 	    }
50844 	else while (s1 < s2) {s7_int c; c = *s1; *s1++ = *s2; *s2-- = c;}
50845       }
50846       break;
50847 
50848     case T_FLOAT_VECTOR:
50849       {
50850 	s7_int len;
50851 	s7_double *s1, *s2;
50852 	if (is_immutable_vector(p))
50853 	  return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->reverseb_symbol, p)));
50854 	len = vector_length(p);
50855 	if (len < 2) return(p);
50856 	s1 = float_vector_floats(p);
50857 	s2 = (s7_double *)(s1 + len - 1);
50858 	if ((len & 0xf) == 0)
50859 	  while (s1 < s2)
50860 	    {
50861 	      s7_double c;
50862 	      LOOP_8(c = *s1; *s1++ = *s2; *s2-- = c);
50863 	    }
50864 	else while (s1 < s2) {s7_double c; c = *s1; *s1++ = *s2; *s2-- = c;}
50865       }
50866       break;
50867 
50868     case T_VECTOR:
50869       {
50870 	s7_int len;
50871 	s7_pointer *s1, *s2;
50872 	if (is_immutable_vector(p))
50873 	  return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->reverseb_symbol, p)));
50874 	len = vector_length(p);
50875 	if (len < 2) return(p);
50876 	s1 = vector_elements(p);
50877 	s2 = (s7_pointer *)(s1 + len - 1);
50878 	if ((len & 0xf) == 0)
50879 	  while (s1 < s2)
50880 	    {
50881 	      s7_pointer c;
50882 	      LOOP_8(c = *s1; *s1++ = *s2; *s2-- = c);
50883 	    }
50884 	else while (s1 < s2) {s7_pointer c; c = *s1; *s1++ = *s2; *s2-- = c;}
50885       }
50886       break;
50887 
50888     default:
50889       if (is_immutable(p))
50890 	{
50891 	  if (is_simple_sequence(p))
50892 	    return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->reverseb_symbol, p)));
50893 	  return(simple_wrong_type_argument_with_type(sc, sc->reverseb_symbol, p, a_sequence_string));
50894 	}
50895       if ((is_simple_sequence(p)) &&
50896 	  (!has_active_methods(sc, p)))
50897 	return(simple_wrong_type_argument_with_type(sc, sc->reverseb_symbol, p, wrap_string(sc, "a vector, string, or list", 25)));
50898       return(method_or_bust_with_type_one_arg_p(sc, p, sc->reverseb_symbol, a_sequence_string));
50899     }
50900   return(p);
50901 }
50902 
50903 
50904 /* -------------------------------- fill! -------------------------------- */
50905 
50906 static s7_pointer pair_fill(s7_scheme *sc, s7_pointer args)
50907 {
50908   /* ambiguous ("tree-fill"?) but if it's like vector-fill, we just stomp on the top level */
50909   s7_pointer x, y, obj, val, p;
50910   s7_int i, start = 0, end, len;
50911 
50912   obj = car(args);
50913 #if WITH_HISTORY
50914   if ((is_immutable_pair(obj)) && (obj != sc->eval_history1) && (obj != sc->eval_history2))
50915 #else
50916     if (is_immutable_pair(obj))
50917 #endif
50918     return(immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->fill_symbol, obj)));
50919   if (obj == global_value(sc->features_symbol))
50920     return(s7_error(sc, sc->out_of_range_symbol, set_elist_1(sc, wrap_string(sc, "can't fill! *features*", 22))));
50921   if (obj == global_value(sc->libraries_symbol))
50922     return(s7_error(sc, sc->out_of_range_symbol, set_elist_1(sc, wrap_string(sc, "can't fill! *libraries*", 23))));
50923 
50924   val = cadr(args);
50925   len = s7_list_length(sc, obj);
50926   end = len;
50927   if (end < 0) end = -end; else {if (end == 0) end = 123123123;}
50928   if (!is_null(cddr(args)))
50929     {
50930       p = start_and_end(sc, sc->fill_symbol, args, 3, cddr(args), &start, &end);
50931       if (p != sc->unused) return(p);
50932       if (start == end) return(val);
50933     }
50934   if (len > 0)
50935     {
50936       if (end < len) len = end;
50937       for (i = 0, p = obj; i < start; p = cdr(p), i++);
50938       for (; i < len; p = cdr(p), i++) set_car(p, val);
50939       return(val);
50940     }
50941 
50942   for (x = obj, y = obj, i = 0; ;i++)
50943     {
50944       if ((end > 0) && (i >= end))
50945 	return(val);
50946       if (i >= start) set_car(x, val);
50947       if (!is_pair(cdr(x)))
50948 	{
50949 	  if (!is_null(cdr(x)))
50950 	    set_cdr(x, val);
50951 	  return(val);
50952 	}
50953       x = cdr(x);
50954       if ((i & 1) != 0) y = cdr(y);
50955       if (x == y)
50956 	return(val);
50957     }
50958   return(val);
50959 }
50960 
50961 s7_pointer s7_fill(s7_scheme *sc, s7_pointer args)
50962 {
50963   #define H_fill "(fill! obj val (start 0) end) fills obj with val"
50964   #define Q_fill s7_make_circular_signature(sc, 3, 4, sc->T, sc->is_sequence_symbol, sc->T, sc->is_integer_symbol)
50965   s7_pointer p;
50966 
50967   p = car(args);
50968   switch (type(p))
50969     {
50970     case T_STRING:
50971       return(g_string_fill_1(sc, sc->fill_symbol, args)); /* redundant type check here and below */
50972 
50973     case T_BYTE_VECTOR: case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_VECTOR:
50974       return(g_vector_fill_1(sc, sc->fill_symbol, args));
50975 
50976     case T_PAIR:
50977       return(pair_fill(sc, args));
50978 
50979     case T_NIL:
50980       if (!is_null(cddr(args)))  /* (fill! () 1 21 #\a)? */
50981 	eval_error(sc, "fill! () ... includes indices: ~S?", 34, cddr(args));
50982       return(cadr(args));        /* this parallels the empty vector case */
50983 
50984     case T_HASH_TABLE:
50985       return(hash_table_fill(sc, args));
50986 
50987     case T_LET:
50988       check_method(sc, p, sc->fill_symbol, args);
50989       return(let_fill(sc, args));
50990 
50991     case T_C_OBJECT:
50992       check_method(sc, p, sc->fill_symbol, args);
50993       if (c_object_fill(sc, p)) /* default is NULL (s7_make_c_type) */
50994 	return((*(c_object_fill(sc, p)))(sc, args));
50995       eval_error(sc, "attempt to fill ~S?", 19, p);
50996 
50997     default:
50998       check_method(sc, p, sc->fill_symbol, args);
50999     }
51000   return(wrong_type_argument_with_type(sc, sc->fill_symbol, 1, p, a_sequence_string)); /* (fill! 1 0) */
51001 }
51002 
51003 #define g_fill s7_fill
51004 /* perhaps (fill iterator obj) could fill the underlying sequence (if any) -- not let/closure
51005  *   similarly for length, reverse etc
51006  */
51007 
51008 
51009 /* -------------------------------- append -------------------------------- */
51010 
51011 static s7_int sequence_length(s7_scheme *sc, s7_pointer lst)
51012 {
51013   switch (type(lst))
51014     {
51015     case T_PAIR:
51016       {
51017 	s7_int len;
51018 	len = s7_list_length(sc, lst);
51019 	return((len == 0) ? -1 : len);
51020       }
51021     case T_NIL:         return(0);
51022     case T_BYTE_VECTOR:
51023     case T_INT_VECTOR:
51024     case T_FLOAT_VECTOR:
51025     case T_VECTOR:      return(vector_length(lst));
51026     case T_STRING:      return(string_length(lst));
51027     case T_HASH_TABLE:  return(hash_table_entries(lst));
51028     case T_LET:         return(let_length(sc, lst));
51029     case T_C_OBJECT:
51030       {
51031 	s7_pointer x;
51032 	x = c_object_length(sc, lst);
51033 	if (s7_is_integer(x))
51034 	  return(s7_integer_checked(sc, x));
51035       }}
51036   return(-1);
51037 }
51038 
51039 static s7_int total_sequence_length(s7_scheme *sc, s7_pointer args, s7_pointer caller, uint8_t typ)
51040 {
51041   s7_pointer p;
51042   s7_int i, len = 0;
51043 
51044   for (i = 1, p = args; is_pair(p); p = cdr(p), i++)
51045     {
51046       s7_pointer seq;
51047       s7_int n;
51048       seq = car(p);
51049       n = sequence_length(sc, seq);
51050       if ((n > 0) &&
51051 	  (typ != T_FREE) &&
51052 	  ((type(seq) == T_HASH_TABLE) ||  /* can't append hash-tables (no obvious meaning to the operation) */
51053 	   ((type(seq) == T_LET) &&        /*   similarly for lets, unless this is a mock-string or something similar */
51054 	    ((!has_active_methods(sc, seq)) || (find_method(sc, seq, caller) == sc->undefined)))))
51055 	{
51056 	  wrong_type_argument(sc, caller, i, seq, typ);
51057 	  return(0);
51058 	}
51059       if (n < 0)
51060 	{
51061 	  wrong_type_argument_with_type(sc, caller, i, seq, (is_pair(seq)) ? a_proper_list_string : a_sequence_string);
51062 	  return(0);
51063 	}
51064       len += n;
51065     }
51066   return(len);
51067 }
51068 
51069 static s7_pointer vector_append(s7_scheme *sc, s7_pointer args, uint8_t typ, s7_pointer caller)
51070 {
51071   s7_pointer new_vec;
51072   s7_pointer *v_elements = NULL;
51073   s7_double *fv_elements = NULL;
51074   s7_int *iv_elements = NULL;
51075   uint8_t *byte_elements = NULL;
51076   s7_int len;
51077 
51078   push_stack_no_let_no_code(sc, OP_GC_PROTECT, args);
51079   len = total_sequence_length(sc, args, caller, (typ == T_VECTOR) ? T_FREE : ((typ == T_FLOAT_VECTOR) ? T_REAL : T_INTEGER));
51080   if (len > sc->max_vector_length)
51081     {
51082       unstack(sc);
51083       return(s7_error(sc, sc->out_of_range_symbol,
51084 		      set_elist_4(sc, wrap_string(sc, "~S new vector length, ~D, is larger than (*s7* 'max-vector-length): ~D", 70),
51085 				  caller,
51086 				  wrap_integer1(sc, len),
51087 				  wrap_integer2(sc, sc->max_vector_length))));
51088     }
51089   new_vec = make_vector_1(sc, len, (typ == T_VECTOR) ? FILLED : NOT_FILLED, typ);  /* might hit GC in loop below so we can't use NOT_FILLED here (??) */
51090   add_vector(sc, new_vec);
51091 
51092   if (typ == T_VECTOR)
51093     v_elements = vector_elements(new_vec);
51094   else
51095     {
51096       if (typ == T_FLOAT_VECTOR)
51097 	fv_elements = float_vector_floats(new_vec);
51098       else
51099 	{
51100 	  if (typ == T_INT_VECTOR)
51101 	    iv_elements = int_vector_ints(new_vec);
51102 	  else byte_elements = byte_vector_bytes(new_vec);
51103 	}}
51104 
51105   if (len > 0)
51106     {
51107       s7_pointer p, pargs;
51108       s7_int i;
51109 
51110       pargs = list_2(sc, sc->F, new_vec); /* car set below */
51111       push_stack_no_let(sc, OP_GC_PROTECT, new_vec, pargs);
51112 
51113       for (i = 0, p = args; is_pair(p); p = cdr(p))    /* in-place copy by goofing with new_vec's elements pointer */
51114 	{
51115 	  s7_int n;
51116 	  s7_pointer x;
51117 	  x = car(p);
51118 	  n = sequence_length(sc, x);
51119 	  if (n > 0)
51120 	    {
51121 	      vector_length(new_vec) = n;
51122 	      set_car(pargs, x);
51123 	      s7_copy_1(sc, caller, pargs);  /* not set_plist_2 here! */
51124 	      vector_length(new_vec) = 0;               /* so GC doesn't march off the end */
51125 	      i += n;
51126 	      if (typ == T_VECTOR)
51127 		vector_elements(new_vec) = (s7_pointer *)(v_elements + i);
51128 	      else
51129 		{
51130 		  if (typ == T_FLOAT_VECTOR)
51131 		    float_vector_floats(new_vec) = (s7_double *)(fv_elements + i);
51132 		  else
51133 		    {
51134 		      if (typ == T_INT_VECTOR)
51135 			int_vector_ints(new_vec) = (s7_int *)(iv_elements + i);
51136 		      else byte_vector_bytes(new_vec) = (uint8_t *)(byte_elements + i);
51137 		    }}}}
51138       unstack(sc);
51139       /* free_cell(sc, pargs); */ /* this is trouble if any arg is openlet with append method -- e.g. block */
51140 
51141       if (typ == T_VECTOR)
51142 	vector_elements(new_vec) = v_elements;
51143       else
51144 	{
51145 	  if (typ == T_FLOAT_VECTOR)
51146 	    float_vector_floats(new_vec) = fv_elements;
51147 	  else
51148 	    {
51149 	      if (typ == T_INT_VECTOR)
51150 		int_vector_ints(new_vec) = iv_elements;
51151 	      else byte_vector_bytes(new_vec) = byte_elements;
51152 	    }}
51153       vector_length(new_vec) = len;
51154     }
51155   unstack(sc);
51156   return(new_vec);
51157 }
51158 
51159 static s7_pointer hash_table_append(s7_scheme *sc, s7_pointer args)
51160 {
51161   s7_pointer new_hash, p;
51162   new_hash = s7_make_hash_table(sc, sc->default_hash_table_length);
51163   push_stack_no_let(sc, OP_GC_PROTECT, args, new_hash);
51164   for (p = args; is_pair(p); p = cdr(p))
51165     s7_copy_1(sc, sc->append_symbol, set_plist_2(sc, car(p), new_hash));
51166   set_plist_2(sc, sc->nil, sc->nil);
51167   unstack(sc);
51168   return(new_hash);
51169 }
51170 
51171 static s7_pointer let_append(s7_scheme *sc, s7_pointer args)
51172 {
51173   s7_pointer new_let, p, e;
51174   e = car(args);
51175   check_method(sc, e, sc->append_symbol, args);
51176   push_stack_no_let_no_code(sc, OP_GC_PROTECT, args);
51177   new_let = make_let_slowly(sc, sc->nil);
51178   for (p = args; is_pair(p); p = cdr(p))
51179     s7_copy_1(sc, sc->append_symbol, set_plist_2(sc, car(p), new_let));
51180   set_plist_2(sc, sc->nil, sc->nil);
51181   unstack(sc);
51182   return(new_let);
51183 }
51184 
51185 static s7_pointer g_append(s7_scheme *sc, s7_pointer args)
51186 {
51187   #define H_append "(append ...) returns its argument sequences appended into one sequence"
51188   #define Q_append s7_make_circular_signature(sc, 0, 1, sc->T)
51189   s7_pointer a1;
51190 
51191   if (is_null(args)) return(sc->nil);  /* (append) -> () */
51192   a1 = car(args);                      /* first arg determines result type unless all args but last are empty (sigh) */
51193   if (is_null(cdr(args))) return(a1);  /* (append <anything>) -> <anything> */
51194 
51195   args = copy_proper_list(sc, args);   /* if any arg calls the append method, args might be stepped on */
51196   switch (type(a1))
51197     {
51198     case T_NIL: case T_PAIR: return(g_list_append(sc, args));
51199     case T_STRING:           return(g_string_append_1(sc, args, sc->append_symbol));
51200     case T_HASH_TABLE:       return(hash_table_append(sc, args));
51201     case T_LET:              return(let_append(sc, args));
51202     case T_VECTOR: case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_BYTE_VECTOR:
51203       return(vector_append(sc, args, type(a1), sc->append_symbol));
51204     default:
51205       check_method(sc, a1, sc->append_symbol, args);
51206     }
51207   return(wrong_type_argument_with_type(sc, sc->append_symbol, 1, a1, a_sequence_string)); /* (append 1 0) */
51208 }
51209 
51210 static s7_pointer append_p_ppp(s7_scheme *sc, s7_pointer p1, s7_pointer p2, s7_pointer p3) {return(g_append(sc, set_plist_3(sc, p1, p2, p3)));}
51211 
51212 static inline s7_pointer copy_proper_pair_and_append(s7_scheme *sc, s7_pointer lst, s7_pointer rest)
51213 {
51214   s7_pointer p, tp, np;
51215   tp = list_1(sc, car(lst));
51216   sc->y = tp;
51217   for (p = cdr(lst), np = tp; is_pair(p); p = cdr(p), np = cdr(np))
51218     set_cdr(np, list_1(sc, car(p)));
51219   set_cdr(np, rest);
51220   sc->y = sc->nil;
51221   return(tp);
51222 }
51223 
51224 s7_pointer s7_append(s7_scheme *sc, s7_pointer a, s7_pointer b)
51225 {
51226   if (is_pair(a))
51227     {
51228       s7_pointer q;
51229       if (!s7_is_proper_list(sc, a))
51230 	return(wrong_type_argument_with_type(sc, sc->append_symbol, 1, a, a_proper_list_string));
51231       if (is_null(b))
51232 	return(copy_proper_list(sc, a));  /* (append p ()) was the old-fashioned way to copy p */
51233       if (!is_pair(b))
51234 	return(g_list_append(sc, list_2(sc, a, b)));
51235       q = copy_proper_pair_and_append(sc, a, b);
51236       return(q);
51237     }
51238   if (is_null(a)) return(b);
51239   return(g_append(sc, set_plist_2(sc, a, b)));
51240 }
51241 
51242 static s7_pointer g_append_2(s7_scheme *sc, s7_pointer args) {return(s7_append(sc, car(args), cadr(args)));}
51243 
51244 static s7_pointer append_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
51245 {
51246   if (args == 2) return(sc->append_2);
51247   return(f);
51248 }
51249 
51250 
51251 /* -------------------------------- object->let -------------------------------- */
51252 
51253 static s7_pointer byte_vector_to_list(s7_scheme *sc, const uint8_t *str, s7_int len)
51254 {
51255   s7_int i;
51256   s7_pointer p;
51257   if (len == 0) return(sc->nil);
51258   check_free_heap_size(sc, len);
51259   sc->w = sc->nil;
51260   for (i = len - 1; i >= 0; i--)
51261     sc->w = cons_unchecked(sc, small_int((uint32_t)(str[i])), sc->w);
51262   p = sc->w;
51263   sc->w = sc->nil;
51264   return(p);
51265 }
51266 
51267 static s7_pointer object_to_list(s7_scheme *sc, s7_pointer obj)
51268 {
51269   /* used only in format_to_port_1 and (map values ...) */
51270   switch (type(obj))
51271     {
51272     case T_INT_VECTOR:
51273     case T_FLOAT_VECTOR:
51274     case T_VECTOR:
51275       return(s7_vector_to_list(sc, obj));
51276 
51277     case T_STRING:
51278       return(s7_string_to_list(sc, string_value(obj), string_length(obj)));
51279 
51280     case T_BYTE_VECTOR:
51281       return(byte_vector_to_list(sc, byte_vector_bytes(obj), byte_vector_length(obj)));
51282 
51283     case T_HASH_TABLE:
51284       if (hash_table_entries(obj) > 0)
51285 	{
51286 	  s7_pointer x, iterator;
51287 	  iterator = s7_make_iterator(sc, obj);
51288 	  sc->temp8 = iterator;
51289 	  sc->w = sc->nil;
51290 	  while (true)
51291 	    {
51292 	      x = s7_iterate(sc, iterator);
51293 	      if (iterator_is_at_end(iterator)) break;
51294 	      sc->w = cons(sc, x, sc->w);
51295 	    }
51296 	  x = sc->w;
51297 	  sc->w = sc->nil;
51298 	  sc->temp8 = sc->nil;	  /* free_cell(sc, iterator); */ /* 16-Nov-18 but then 18-Dec-18 got free cell that was iterator */
51299 	  return(x);
51300 	}
51301       return(sc->nil);
51302 
51303     case T_LET:
51304 #if (!WITH_PURE_S7)
51305       check_method(sc, obj, sc->let_to_list_symbol, set_plist_1(sc, obj));
51306 #endif
51307       return(s7_let_to_list(sc, obj));
51308 
51309     case T_ITERATOR:
51310       {
51311 	s7_pointer result, p = NULL;
51312 	s7_int results = 0;
51313 	result = sc->nil;
51314 	while (true)
51315 	  {
51316 	    s7_pointer val;
51317 	    val = s7_iterate(sc, obj);
51318 	    if ((val == ITERATOR_END) &&
51319 		(iterator_is_at_end(obj)))
51320 	      {
51321 		sc->temp8 = sc->nil;
51322 		return(result);
51323 	      }
51324 	    if (sc->safety > NO_SAFETY)
51325 	      {
51326 		results++;
51327 		if (results > 10000)
51328 		  {
51329 		    s7_warn(sc, 256, "iterator is creating a very long list!\n");
51330 		    results = S7_INT32_MIN;
51331 		  }}
51332 	    if (val != sc->no_value)
51333 	      {
51334 		if (is_null(result))
51335 		  {
51336 		    if (is_multiple_value(val))
51337 		      {
51338 			result = multiple_value(val);
51339 			clear_multiple_value(val);
51340 			for (p = result; is_pair(cdr(p)); p = cdr(p));
51341 		      }
51342 		    else
51343 		      {
51344 			result = list_1(sc, val);
51345 			p = result;
51346 		      }
51347 		    sc->temp8 = result;
51348 		  }
51349 		else
51350 		  {
51351 		    if (is_multiple_value(val))
51352 		      {
51353 			set_cdr(p, multiple_value(val));
51354 			clear_multiple_value(val);
51355 			for (; is_pair(cdr(p)); p = cdr(p));
51356 		      }
51357 		    else
51358 		      {
51359 			set_cdr(p, list_1(sc, val));
51360 			p = cdr(p);
51361 		      }}}}}
51362 
51363     case T_C_OBJECT:
51364       {
51365 	int64_t i, len;
51366 	s7_pointer x, z, zc, result;
51367 	s7_int gc_z;
51368 
51369 	if (c_object_to_list(sc, obj))
51370 	  return((*(c_object_to_list(sc, obj)))(sc, set_plist_1(sc, obj)));
51371 
51372 	x = c_object_length(sc, obj);
51373 	if (s7_is_integer(x))
51374 	  len = s7_integer_checked(sc, x);
51375 	else return(sc->F);
51376 
51377 	if (len < 0)
51378 	  return(sc->F);
51379 	if (len == 0)
51380 	  return(sc->nil);
51381 
51382 	result = make_list(sc, len, sc->nil);
51383 	sc->temp8 = result;
51384 	z = list_2(sc, obj, zc = make_mutable_integer(sc, 0));
51385 	gc_z = s7_gc_protect_1(sc, z);
51386 
51387 	set_car(sc->z2_1, sc->x);
51388 	set_car(sc->z2_2, sc->z);
51389 	for (i = 0, x = result; i < len; i++, x = cdr(x))
51390 	  {
51391 	    integer(zc) = i;
51392 	    set_car(x, (*(c_object_ref(sc, obj)))(sc, z));
51393 	  }
51394 	sc->x = car(sc->z2_1);
51395 	sc->z = car(sc->z2_2);
51396 	s7_gc_unprotect_at(sc, gc_z);
51397 	sc->temp8 = sc->nil;
51398 	return(result);
51399       }}
51400   return(obj);
51401 }
51402 
51403 static s7_pointer symbol_to_let(s7_scheme *sc, s7_pointer obj, s7_pointer args)
51404 {
51405   s7_pointer let;
51406   let = g_local_inlet(sc, 4, sc->value_symbol, obj,
51407 		      sc->type_symbol, (is_keyword(obj)) ? sc->is_keyword_symbol : ((is_gensym(obj)) ? sc->is_gensym_symbol : sc->is_symbol_symbol));
51408   if (!is_keyword(obj))
51409     {
51410       s7_pointer val;
51411       s7_int gc_loc;
51412       gc_loc = s7_gc_protect_1(sc, let);
51413       if (!sc->current_value_symbol)
51414 	sc->current_value_symbol = make_symbol(sc, "current-value");
51415       val = s7_symbol_value(sc, obj);
51416       s7_varlet(sc, let, sc->current_value_symbol, val);
51417       s7_varlet(sc, let, sc->setter_symbol, g_setter(sc, args));
51418       s7_varlet(sc, let, sc->mutable_symbol, s7_make_boolean(sc, !is_immutable_symbol(obj)));
51419       if (!is_undefined(val))
51420 	{
51421 	  const char *doc;
51422 	  doc = s7_documentation(sc, obj);
51423 	  if (doc)
51424 	    s7_varlet(sc, let, sc->local_documentation_symbol, s7_make_string(sc, doc));
51425 	}
51426       s7_gc_unprotect_at(sc, gc_loc);
51427     }
51428   return(let);
51429 }
51430 
51431 static s7_pointer random_state_to_let(s7_scheme *sc, s7_pointer obj)
51432 {
51433 #if WITH_GMP
51434   return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_random_state_symbol));
51435 #else
51436   if (!sc->seed_symbol)
51437     {
51438       sc->seed_symbol = make_symbol(sc, "seed");
51439       sc->carry_symbol = make_symbol(sc, "carry");
51440     }
51441   return(g_local_inlet(sc, 8, sc->value_symbol, obj,
51442 		       sc->type_symbol, sc->is_random_state_symbol,
51443 		       sc->seed_symbol, make_integer(sc, random_seed(obj)),
51444 		       sc->carry_symbol, make_integer(sc, random_carry(obj))));
51445 #endif
51446 }
51447 
51448 static s7_pointer vector_to_let(s7_scheme *sc, s7_pointer obj)
51449 {
51450   s7_pointer let;
51451   s7_int gc_loc;
51452 
51453   if (!sc->dimensions_symbol) sc->dimensions_symbol = make_symbol(sc, "dimensions");
51454   if (!sc->original_vector_symbol) sc->original_vector_symbol = make_symbol(sc, "original-vector");
51455   let = g_local_inlet(sc, 10, sc->value_symbol, obj,
51456 		      sc->type_symbol, (is_subvector(obj)) ? cons(sc, sc->is_subvector_symbol, s7_type_of(sc, subvector_vector(obj))) : s7_type_of(sc, obj),
51457 		      sc->size_symbol, s7_length(sc, obj),
51458 		      sc->dimensions_symbol, g_vector_dimensions(sc, set_plist_1(sc, obj)),
51459 		      sc->mutable_symbol, s7_make_boolean(sc, !is_immutable_vector(obj)));
51460   gc_loc = s7_gc_protect_1(sc, let);
51461   if (is_subvector(obj))
51462     {
51463       s7_int pos = 0;
51464       switch (type(obj)) /* correct type matters here: gcc 10.2 with -O2 segfaults otherwise, cast to intptr_t has a similar role in earlier gcc's */
51465 	{
51466 	  case T_VECTOR:       pos = (s7_int)((intptr_t)(vector_elements(obj) - vector_elements(subvector_vector(obj))));         break;
51467 	  case T_INT_VECTOR:   pos = (s7_int)((intptr_t)(int_vector_ints(obj) - int_vector_ints(subvector_vector(obj))));         break;
51468 	  case T_FLOAT_VECTOR: pos = (s7_int)((intptr_t)(float_vector_floats(obj) - float_vector_floats(subvector_vector(obj)))); break;
51469 	  case T_BYTE_VECTOR:  pos = (s7_int)((intptr_t)(byte_vector_bytes(obj) - byte_vector_bytes(subvector_vector(obj))));     break;
51470 	}
51471       s7_varlet(sc, let, sc->position_symbol, make_integer(sc, pos));
51472       s7_varlet(sc, let, sc->original_vector_symbol, subvector_vector(obj));
51473     }
51474   if (is_typed_vector(obj))
51475     s7_varlet(sc, let, sc->signature_symbol, g_signature(sc, set_plist_1(sc, obj)));
51476   s7_gc_unprotect_at(sc, gc_loc);
51477   return(let);
51478 }
51479 
51480 static s7_pointer hash_table_to_let(s7_scheme *sc, s7_pointer obj)
51481 {
51482   s7_pointer let;
51483   s7_int gc_loc;
51484   if (!sc->entries_symbol)
51485     {
51486       sc->entries_symbol = make_symbol(sc, "entries");
51487       sc->locked_symbol = make_symbol(sc, "locked");
51488       sc->weak_symbol = make_symbol(sc, "weak");
51489     }
51490   let = g_local_inlet(sc, 12, sc->value_symbol, obj,
51491 		      sc->type_symbol, sc->is_hash_table_symbol,
51492 		      sc->size_symbol, s7_length(sc, obj),
51493 		      sc->entries_symbol, make_integer(sc, hash_table_entries(obj)),
51494 		      sc->locked_symbol, s7_make_boolean(sc, hash_table_checker_locked(obj)),
51495 		      sc->mutable_symbol, s7_make_boolean(sc, !is_immutable(obj)));
51496   gc_loc = s7_gc_protect_1(sc, let);
51497   if (is_weak_hash_table(obj))
51498     s7_varlet(sc, let, sc->weak_symbol, sc->T);
51499   if ((hash_table_checker(obj) == hash_eq) ||
51500       (hash_table_checker(obj) == hash_c_function) ||
51501       (hash_table_checker(obj) == hash_closure) ||
51502       (hash_table_checker(obj) == hash_equal_eq) ||
51503       (hash_table_checker(obj) == hash_equal_syntax) ||
51504       (hash_table_checker(obj) == hash_symbol))
51505     s7_varlet(sc, let, sc->function_symbol, sc->is_eq_symbol);
51506   else
51507     {
51508       if (hash_table_checker(obj) == hash_eqv)
51509 	s7_varlet(sc, let, sc->function_symbol, sc->is_eqv_symbol);
51510       else
51511 	{
51512 	  if ((hash_table_checker(obj) == hash_equal) ||
51513 	      (hash_table_checker(obj) == hash_empty))
51514 	    s7_varlet(sc, let, sc->function_symbol, sc->is_equal_symbol);
51515 	  else
51516 	    {
51517 	      if (hash_table_checker(obj) == hash_equivalent)
51518 		s7_varlet(sc, let, sc->function_symbol, sc->is_equivalent_symbol);
51519 	      else
51520 		{
51521 		  if ((hash_table_checker(obj) == hash_number_num_eq) ||
51522 		      (hash_table_checker(obj) == hash_int) ||
51523 		      (hash_table_checker(obj) == hash_float))
51524 		    s7_varlet(sc, let, sc->function_symbol, sc->num_eq_symbol);
51525 		  else
51526 		    {
51527 		      if (hash_table_checker(obj) == hash_string)
51528 			s7_varlet(sc, let, sc->function_symbol, sc->string_eq_symbol);
51529 		      else
51530 			{
51531 			  if (hash_table_checker(obj) == hash_char)
51532 			    s7_varlet(sc, let, sc->function_symbol, sc->char_eq_symbol);
51533 #if (!WITH_PURE_S7)
51534 			  else
51535 			    {
51536 			      if (hash_table_checker(obj) == hash_ci_char)
51537 				s7_varlet(sc, let, sc->function_symbol, sc->char_ci_eq_symbol);
51538 			      else
51539 				if (hash_table_checker(obj) == hash_ci_string)
51540 				  s7_varlet(sc, let, sc->function_symbol, sc->string_ci_eq_symbol);
51541 			    }
51542 #endif
51543 			}}}}}}
51544   if (is_typed_hash_table(obj))
51545     s7_varlet(sc, let, sc->signature_symbol, g_signature(sc, set_plist_1(sc, obj)));
51546   s7_gc_unprotect_at(sc, gc_loc);
51547   return(let);
51548 }
51549 
51550 static s7_pointer iterator_to_let(s7_scheme *sc, s7_pointer obj)
51551 {
51552   s7_pointer let, seq;
51553   s7_int gc_loc;
51554   if (!sc->at_end_symbol)
51555     {
51556       sc->at_end_symbol = make_symbol(sc, "at-end");
51557       sc->sequence_symbol = make_symbol(sc, "sequence");
51558     }
51559   seq = iterator_sequence(obj);
51560   let = g_local_inlet(sc, 8, sc->value_symbol, obj,
51561 		      sc->type_symbol, sc->is_iterator_symbol,
51562 		      sc->at_end_symbol, s7_make_boolean(sc, iterator_is_at_end(obj)),
51563 		      sc->sequence_symbol, iterator_sequence(obj));
51564   gc_loc = s7_gc_protect_1(sc, let);
51565   if (is_pair(seq))
51566     s7_varlet(sc, let, sc->size_symbol, s7_length(sc, seq));
51567   else
51568     {
51569       if (is_hash_table(seq))
51570 	s7_varlet(sc, let, sc->size_symbol, make_integer(sc, hash_table_entries(seq)));
51571       else s7_varlet(sc, let, sc->size_symbol, s7_length(sc, obj));
51572     }
51573   if ((is_string(seq)) ||
51574       (is_any_vector(seq)) ||
51575       (seq == sc->rootlet) ||
51576       (is_c_object(seq)) ||
51577       (is_hash_table(seq)))
51578     s7_varlet(sc, let, sc->position_symbol, make_integer(sc, iterator_position(obj)));
51579   else
51580     if (is_pair(seq))
51581       s7_varlet(sc, let, sc->position_symbol, iterator_current(obj));
51582 
51583   s7_gc_unprotect_at(sc, gc_loc);
51584   return(let);
51585 }
51586 
51587 static s7_pointer let_to_let(s7_scheme *sc, s7_pointer obj)
51588 {
51589   /* how to handle setters?
51590    *   (display (let ((e (let ((i 0)) (set! (setter 'i) integer?) (curlet)))) (object->let e))):
51591    *   "(inlet 'value (inlet 'i 0) 'type let? 'length 1 'open #f 'outlet () 'immutable? #f)"
51592    */
51593   s7_pointer let;
51594   s7_int gc_loc;
51595   if (!sc->open_symbol)
51596     {
51597       sc->open_symbol = make_symbol(sc, "open");
51598       sc->alias_symbol = make_symbol(sc, "alias");
51599     }
51600   let = g_local_inlet(sc, 12, sc->value_symbol, obj,
51601 		      sc->type_symbol, sc->is_let_symbol,
51602 		      sc->size_symbol, s7_length(sc, obj),
51603 		      sc->open_symbol, s7_make_boolean(sc, has_methods(obj)),
51604 		      sc->outlet_symbol, (obj == sc->rootlet) ? sc->nil : let_outlet(obj),
51605 		      sc->mutable_symbol, s7_make_boolean(sc, !is_immutable(obj)));
51606   gc_loc = s7_gc_protect_1(sc, let);
51607   if (obj == sc->rootlet)
51608     s7_varlet(sc, let, sc->alias_symbol, sc->rootlet_symbol);
51609   else
51610     {
51611       if (obj == sc->owlet) /* this can't happen, I think -- owlet is always copied first */
51612 	s7_varlet(sc, let, sc->alias_symbol, sc->owlet_symbol);
51613       else
51614 	{
51615 	  if (is_funclet(obj))
51616 	    {
51617 	      s7_varlet(sc, let, sc->function_symbol, funclet_function(obj));
51618 	      if ((has_let_file(obj)) &&
51619 		  (let_file(obj) <= (s7_int)sc->file_names_top) &&
51620 		  (let_line(obj) > 0) &&
51621 		  (let_line(obj) < 1000000))
51622 		{
51623 		  s7_varlet(sc, let, sc->file_symbol, sc->file_names[let_file(obj)]);
51624 		  s7_varlet(sc, let, sc->line_symbol, make_integer(sc, let_line(obj)));
51625 		}}
51626 	    else
51627 	      if (obj == sc->s7_let)
51628 		{
51629 		  s7_pointer iter;
51630 		  s7_int gc_loc1;
51631 		  iter = s7_make_iterator(sc, obj);
51632 		  gc_loc1 = s7_gc_protect(sc, iter);
51633 		  while (true)
51634 		    {
51635 		      s7_pointer x;
51636 		      x = s7_iterate(sc, iter);
51637 		      if (iterator_is_at_end(iter)) break;
51638 		      s7_varlet(sc, let, car(x), cdr(x));
51639 		    }
51640 		  s7_gc_unprotect_at(sc, gc_loc1);
51641 		}}}
51642   if (has_active_methods(sc, obj))
51643     {
51644       s7_pointer func;
51645       func = find_method(sc, obj, sc->object_to_let_symbol);
51646       if (func != sc->undefined)
51647 	call_method(sc, obj, func, set_plist_2(sc, obj, let));
51648     }
51649   s7_gc_unprotect_at(sc, gc_loc);
51650   return(let);
51651 }
51652 
51653 static s7_pointer c_object_to_let(s7_scheme *sc, s7_pointer obj)
51654 {
51655   s7_pointer let, clet;
51656   s7_int gc_loc;
51657   if (!sc->class_symbol)
51658     {
51659       sc->class_symbol = make_symbol(sc, "class");
51660       sc->c_object_length_symbol = make_symbol(sc, "c-object-length");
51661       sc->c_object_ref_symbol = make_symbol(sc, "c-object-ref");
51662       sc->c_object_let_symbol = make_symbol(sc, "c-object-let");
51663       sc->c_object_set_symbol = make_symbol(sc, "c-object-set!");
51664       sc->c_object_copy_symbol = make_symbol(sc, "c-object-copy");
51665       sc->c_object_fill_symbol = make_symbol(sc, "c-object-fill!");
51666       sc->c_object_reverse_symbol = make_symbol(sc, "c-object-reverse");
51667       sc->c_object_to_list_symbol = make_symbol(sc, "c-object->list");
51668       sc->c_object_to_string_symbol = make_symbol(sc, "c-object->string");
51669     }
51670   clet = c_object_let(obj);
51671   let = g_local_inlet(sc, 10, sc->value_symbol, obj,
51672 		      sc->type_symbol, sc->is_c_object_symbol,
51673 		      sc->c_object_type_symbol, make_integer(sc, c_object_type(obj)),
51674 		      sc->c_object_let_symbol, clet,
51675 		      sc->class_symbol, c_object_type_to_let(sc, obj));
51676   gc_loc = s7_gc_protect_1(sc, let);
51677   /* not sure these are useful */
51678   if (c_object_len(sc, obj))   /* c_object_length is the object length, not the procedure */
51679     s7_varlet(sc, let, sc->c_object_length_symbol, s7_lambda(sc, c_object_len(sc, obj), 1, 0, false));
51680   if (c_object_ref(sc, obj))
51681     s7_varlet(sc, let, sc->c_object_ref_symbol, s7_lambda(sc, c_object_ref(sc, obj), 1, 0, true));
51682   if (c_object_set(sc, obj))
51683     s7_varlet(sc, let, sc->c_object_set_symbol, s7_lambda(sc, c_object_set(sc, obj), 2, 0, true));
51684   if (c_object_copy(sc, obj))
51685     s7_varlet(sc, let, sc->c_object_copy_symbol, s7_lambda(sc, c_object_copy(sc, obj), 1, 0, true));
51686   if (c_object_fill(sc, obj))
51687     s7_varlet(sc, let, sc->c_object_fill_symbol, s7_lambda(sc, c_object_fill(sc, obj), 1, 0, true));
51688   if (c_object_reverse(sc, obj))
51689     s7_varlet(sc, let, sc->c_object_reverse_symbol, s7_lambda(sc, c_object_reverse(sc, obj), 1, 0, true));
51690   if (c_object_to_list(sc, obj))
51691     s7_varlet(sc, let, sc->c_object_to_list_symbol, s7_lambda(sc, c_object_to_list(sc, obj), 1, 0, true));
51692   if (c_object_to_string(sc, obj))
51693     s7_varlet(sc, let, sc->c_object_to_string_symbol, s7_lambda(sc, c_object_to_string(sc, obj), 1, 1, false));
51694 
51695   if ((is_let(clet)) &&
51696       ((has_active_methods(sc, clet)) || (has_active_methods(sc, obj))))
51697     {
51698       s7_pointer func;
51699       func = find_method(sc, clet, sc->object_to_let_symbol);
51700       if (func != sc->undefined)
51701 	call_method(sc, clet, func, set_plist_2(sc, obj, let));
51702     }
51703   s7_gc_unprotect_at(sc, gc_loc);
51704   return(let);
51705 }
51706 
51707 static s7_pointer port_to_let(s7_scheme *sc, s7_pointer obj) /* note the underbars! */
51708 {
51709   s7_pointer let;
51710   s7_int gc_loc;
51711   if (!sc->data_symbol)
51712     {
51713       sc->data_symbol = make_symbol(sc, "data");
51714       sc->port_type_symbol = make_symbol(sc, "port-type");
51715       sc->closed_symbol = make_symbol(sc, "closed");
51716       sc->file_info_symbol = make_symbol(sc, "file-info");
51717     }
51718   let = g_local_inlet(sc, 10, sc->value_symbol, obj,
51719 		      /* obj as 'value means it will say "(closed)" when subsequently the let is displayed */
51720 		      sc->type_symbol, (is_input_port(obj)) ? sc->is_input_port_symbol : sc->is_output_port_symbol,
51721 		      sc->port_type_symbol, (is_string_port(obj)) ? sc->string_symbol : ((is_file_port(obj)) ? sc->file_symbol : sc->function_symbol),
51722 		      sc->closed_symbol, s7_make_boolean(sc, port_is_closed(obj)),
51723 		      sc->mutable_symbol, s7_make_boolean(sc, !is_immutable_port(obj)));
51724   gc_loc = s7_gc_protect_1(sc, let);
51725   if (is_file_port(obj))
51726     {
51727       s7_varlet(sc, let, sc->file_symbol, g_port_filename(sc, set_plist_1(sc, obj)));
51728       if (is_input_port(obj))
51729 	s7_varlet(sc, let, sc->line_symbol, g_port_line_number(sc, set_plist_1(sc, obj)));
51730 #if (!MS_WINDOWS)
51731       if ((!port_is_closed(obj)) && (obj != sc->standard_error) && (obj != sc->standard_input) && (obj != sc->standard_output))
51732 	{
51733 	  struct stat sb;
51734 	  s7_varlet(sc, let, sc->file_symbol, make_integer(sc, fileno(port_file(obj))));
51735 	  if (fstat(fileno(port_file(obj)), &sb) != -1)
51736 	    {
51737 	      char c1[64], c2[64], str[512];
51738 	      int bytes;
51739 	      strftime(c1, 64, "%a %d-%b-%Y %H:%M", localtime(&sb.st_atime));
51740 	      strftime(c2, 64, "%a %d-%b-%Y %H:%M", localtime(&sb.st_mtime));
51741 	      bytes = snprintf(str, 512, "mode: #o%d, links: %ld, owner uid: %d gid: %d, size: %ld bytes, last file access: %s, last file modification: %s",
51742 			       sb.st_mode,
51743 			       (long)sb.st_nlink,
51744 			       (int)sb.st_uid, (int)sb.st_gid,
51745 			       (long)sb.st_size,
51746 			       c1, c2);
51747 	      s7_varlet(sc, let, sc->file_info_symbol, make_string_with_length(sc, (const char *)str, bytes));
51748 	    }}
51749 #endif
51750     }
51751   if ((is_string_port(obj)) && /* file port might not have a data buffer */
51752       (port_data(obj)) &&
51753       (port_data_size(obj) > 0))
51754     {
51755       s7_varlet(sc, let, sc->size_symbol, make_integer(sc, port_data_size(obj)));
51756       s7_varlet(sc, let, sc->position_symbol, make_integer(sc, port_position(obj)));
51757       /* I think port_data need not be null-terminated, but s7_make_string assumes it is:
51758        *   both valgrind and lib*san complain about the uninitialized data during strlen.
51759        */
51760       s7_varlet(sc, let, sc->data_symbol,
51761 		make_string_with_length(sc, (const char *)port_data(obj), ((port_position(obj)) > 16) ? 16 : port_position(obj)));
51762     }
51763   if (is_function_port(obj))
51764     s7_varlet(sc, let, sc->function_symbol, (is_input_port(obj)) ? port_input_scheme_function(obj) : port_output_scheme_function(obj));
51765   s7_gc_unprotect_at(sc, gc_loc);
51766   return(let);
51767 }
51768 
51769 static s7_pointer closure_to_let(s7_scheme *sc, s7_pointer obj)
51770 {
51771   s7_pointer let, sig;
51772   const char* doc;
51773   s7_int gc_loc;
51774   if (!sc->source_symbol)
51775     sc->source_symbol = make_symbol(sc, "source");
51776   let = g_local_inlet(sc, 8, sc->value_symbol, obj,
51777 		      sc->type_symbol, (is_t_procedure(obj)) ? sc->is_procedure_symbol : sc->is_macro_symbol,
51778 		      sc->arity_symbol, s7_arity(sc, obj),
51779 		      sc->mutable_symbol, s7_make_boolean(sc, !is_immutable(obj)));
51780   gc_loc = s7_gc_protect_1(sc, let);
51781 
51782   sig = s7_signature(sc, obj);
51783   if (is_pair(sig))
51784     s7_varlet(sc, let, sc->local_signature_symbol, sig);
51785 
51786   doc = s7_documentation(sc, obj);
51787   if (doc)
51788     s7_varlet(sc, let, sc->local_documentation_symbol, s7_make_string(sc, doc));
51789 
51790   if (is_let(closure_let(obj)))
51791     {
51792       s7_pointer flet;
51793       flet = closure_let(obj);
51794       if ((has_let_file(flet)) &&
51795 	  (let_file(flet) <= (s7_int)sc->file_names_top) &&
51796 	  (let_line(flet) > 0))
51797 	{
51798 	  s7_varlet(sc, let, sc->file_symbol, sc->file_names[let_file(flet)]);
51799 	  s7_varlet(sc, let, sc->line_symbol, make_integer(sc, let_line(flet)));
51800 	}}
51801 
51802   if (closure_setter(obj) != sc->F)
51803     s7_varlet(sc, let, sc->local_setter_symbol, closure_setter(obj));
51804 
51805   s7_varlet(sc, let, sc->source_symbol,
51806 	    append_in_place(sc, list_2(sc, procedure_type_to_symbol(sc, type(obj)), closure_args(obj)),
51807 			    closure_body(obj)));
51808   s7_gc_unprotect_at(sc, gc_loc);
51809   return(let);
51810 }
51811 
51812 static s7_pointer c_pointer_to_let(s7_scheme *sc, s7_pointer obj)
51813 {
51814   /* c_pointer_info can be a let and might have an object->let method (see c_object below) */
51815   if (!sc->c_type_symbol)
51816     {
51817       sc->c_type_symbol = make_symbol(sc, "c-type");
51818       sc->info_symbol = make_symbol(sc, "info");
51819     }
51820   if (!sc->pointer_symbol) sc->pointer_symbol = make_symbol(sc, "pointer");
51821   return(g_local_inlet(sc, 10, sc->value_symbol, obj,
51822 		       sc->type_symbol, sc->is_c_pointer_symbol,
51823 		       sc->pointer_symbol, make_integer(sc, (s7_int)((intptr_t)c_pointer(obj))),
51824 		       sc->c_type_symbol, c_pointer_type(obj),
51825 		       sc->info_symbol, c_pointer_info(obj)));
51826 }
51827 
51828 static s7_pointer c_function_to_let(s7_scheme *sc, s7_pointer obj)
51829 {
51830   s7_pointer let, sig;
51831   const char* doc;
51832   s7_int gc_loc;
51833   let = g_local_inlet(sc, 8, sc->value_symbol, obj,
51834 		      sc->type_symbol, (is_t_procedure(obj)) ? sc->is_procedure_symbol : sc->is_macro_symbol,
51835 		      sc->arity_symbol, s7_arity(sc, obj),
51836 		      sc->mutable_symbol, s7_make_boolean(sc, !is_immutable(obj)));
51837   gc_loc = s7_gc_protect_1(sc, let);
51838   sig = c_function_signature(obj);
51839   if (is_pair(sig))
51840     s7_varlet(sc, let, sc->local_signature_symbol, sig);
51841 
51842   doc = s7_documentation(sc, obj);
51843   if (doc)
51844     s7_varlet(sc, let, sc->local_documentation_symbol, s7_make_string(sc, doc));
51845 
51846   if (c_function_setter(obj) != sc->F) /* c_macro_setter is the same underlying field */
51847     s7_varlet(sc, let, sc->local_setter_symbol, c_function_setter(obj));
51848   s7_gc_unprotect_at(sc, gc_loc);
51849   return(let);
51850 }
51851 
51852 static s7_pointer goto_to_let(s7_scheme *sc, s7_pointer obj)
51853 {
51854   /* there's room in s7_cell to store the procedure, but we would have to mark it (goto escapes, context GC'd) */
51855   if (!sc->active_symbol)
51856     {
51857       sc->active_symbol = make_symbol(sc, "active");
51858       sc->goto_symbol = make_symbol(sc, "goto?");
51859     }
51860   if (is_symbol(call_exit_name(obj)))
51861     return(g_local_inlet(sc, 8, sc->value_symbol, obj, sc->type_symbol, sc->goto_symbol,
51862 			 sc->active_symbol, s7_make_boolean(sc, call_exit_active(obj)),
51863 			 sc->name_symbol, call_exit_name(obj)));
51864   return(g_local_inlet(sc, 6, sc->value_symbol, obj, sc->type_symbol, sc->goto_symbol,
51865 		       sc->active_symbol, s7_make_boolean(sc, call_exit_active(obj))));
51866 }
51867 
51868 static s7_pointer g_object_to_let(s7_scheme *sc, s7_pointer args)
51869 {
51870   #define H_object_to_let "(object->let obj) returns a let (namespace) describing obj."
51871   #define Q_object_to_let s7_make_signature(sc, 2, sc->is_let_symbol, sc->T)
51872 
51873   s7_pointer obj;
51874   /* object->let localizes length vector arity outlet c-pointer immutable?, but does it matter? */
51875 
51876   obj = car(args);
51877 
51878   switch (type(obj))
51879     {
51880     case T_NIL:
51881       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_null_symbol));
51882 
51883     case T_UNSPECIFIED:
51884       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_unspecified_symbol));
51885 
51886     case T_UNDEFINED:
51887       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_undefined_symbol));
51888 
51889     case T_SYNTAX:
51890       return(g_local_inlet(sc, 6, sc->value_symbol, obj,
51891 			   sc->type_symbol, sc->is_syntax_symbol,
51892 			   sc->documentation_symbol, s7_make_string(sc, syntax_documentation(obj))));
51893 
51894     case T_EOF:
51895       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_eof_object_symbol));
51896 
51897     case T_BOOLEAN:
51898       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_boolean_symbol));
51899 
51900     case T_CHARACTER:
51901       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_char_symbol));
51902 
51903     case T_INTEGER: case T_BIG_INTEGER:
51904       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_integer_symbol));
51905 
51906     case T_RATIO: case T_BIG_RATIO:
51907       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_rational_symbol));
51908 
51909     case T_REAL: case T_BIG_REAL:
51910       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_real_symbol));
51911 
51912     case T_COMPLEX: case T_BIG_COMPLEX:
51913       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_complex_symbol));
51914 
51915     case T_SYMBOL:
51916       return(symbol_to_let(sc, obj, args));
51917 
51918     case T_STRING:
51919       return(g_local_inlet(sc, 8, sc->value_symbol, obj,
51920 			   sc->type_symbol, sc->is_string_symbol,
51921 			   sc->size_symbol, s7_length(sc, obj),
51922 			   sc->mutable_symbol, s7_make_boolean(sc, !is_immutable_string(obj))));
51923 
51924     case T_PAIR:
51925       return(g_local_inlet(sc, 6, sc->value_symbol, obj,
51926 			   sc->type_symbol, sc->is_pair_symbol,
51927 			   sc->size_symbol, s7_length(sc, obj)));
51928 
51929     case T_RANDOM_STATE:
51930       return(random_state_to_let(sc, obj));
51931 
51932     case T_GOTO:
51933       return(goto_to_let(sc, obj));
51934 
51935     case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_BYTE_VECTOR: case T_VECTOR:
51936       return(vector_to_let(sc, obj));
51937 
51938     case T_C_POINTER:
51939       return(c_pointer_to_let(sc, obj));
51940 
51941     case T_CONTINUATION:
51942       /* perhaps include the continuation-key */
51943       if (is_symbol(continuation_name(obj)))
51944 	return(g_local_inlet(sc, 6, sc->value_symbol, obj, sc->type_symbol, sc->is_continuation_symbol, sc->name_symbol, continuation_name(obj)));
51945       return(g_local_inlet(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_continuation_symbol));
51946 
51947     case T_ITERATOR:
51948       return(iterator_to_let(sc, obj));
51949 
51950     case T_HASH_TABLE:
51951       return(hash_table_to_let(sc, obj));
51952 
51953     case T_LET:
51954       return(let_to_let(sc, obj));
51955 
51956     case T_C_OBJECT:
51957       return(c_object_to_let(sc, obj));
51958 
51959     case T_INPUT_PORT:
51960     case T_OUTPUT_PORT:
51961       return(port_to_let(sc, obj));
51962 
51963     case T_CLOSURE: case T_CLOSURE_STAR: case T_MACRO: case T_MACRO_STAR: case T_BACRO: case T_BACRO_STAR:
51964       return(closure_to_let(sc, obj));
51965 
51966     case T_C_MACRO: case T_C_FUNCTION_STAR: case T_C_FUNCTION: case T_C_ANY_ARGS_FUNCTION: case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION:
51967       return(c_function_to_let(sc, obj));
51968 
51969     default:
51970       return(sc->F);
51971     }
51972   return(sc->F);
51973 }
51974 
51975 
51976 /* ---------------- stacktrace ---------------- */
51977 
51978 static s7_pointer stacktrace_find_caller(s7_scheme *sc, s7_pointer e)
51979 {
51980   if ((is_let(e)) && (e != sc->rootlet))
51981     return(((is_funclet(e)) || (is_maclet(e))) ? funclet_function(e) : stacktrace_find_caller(sc, let_outlet(e)));
51982   return(sc->F);
51983 }
51984 
51985 static bool stacktrace_find_let(s7_scheme *sc, int64_t loc, s7_pointer e)
51986 {
51987   return((loc > 0) &&
51988 	 ((stack_let(sc->stack, loc) == e) ||
51989 	  (stacktrace_find_let(sc, loc - 4, e))));
51990 }
51991 
51992 static int64_t stacktrace_find_error_hook_quit(s7_scheme *sc)
51993 {
51994   int64_t i;
51995   for (i = current_stack_top(sc) - 1; i >= 3; i -= 4)
51996     if (stack_op(sc->stack, i) == OP_ERROR_HOOK_QUIT)
51997       return(i);
51998   return(-1);
51999 }
52000 
52001 static bool stacktrace_in_error_handler(s7_scheme *sc, int64_t loc)
52002 {
52003   return((let_outlet(sc->owlet) == sc->curlet) ||
52004 	 (stacktrace_find_let(sc, loc * 4, let_outlet(sc->owlet))) ||
52005 	 (stacktrace_find_error_hook_quit(sc) > 0));
52006 }
52007 
52008 static bool stacktrace_error_hook_function(s7_scheme *sc, s7_pointer sym)
52009 {
52010   if (is_symbol(sym))
52011     {
52012       s7_pointer f;
52013       f = s7_symbol_value(sc, sym);
52014       return((is_procedure(f)) &&
52015 	     (is_procedure(sc->error_hook)) &&
52016 	     (hook_has_functions(sc->error_hook)) &&
52017 	     (direct_memq(f, s7_hook_functions(sc, sc->error_hook))));
52018     }
52019   return(false);
52020 }
52021 
52022 static char *stacktrace_walker(s7_scheme *sc, s7_pointer code, s7_pointer e, char *notes,
52023 			       s7_int code_cols, s7_int total_cols, s7_int notes_start_col,
52024 			       bool as_comment, int32_t depth)
52025 {
52026   if (is_symbol(code))
52027     {
52028       if ((!symbol_is_in_list(sc, code)) &&
52029 	  (!is_slot(global_slot(code))))
52030 	{
52031 	  s7_pointer val;
52032 
52033 	  add_symbol_to_list(sc, code);
52034 	  val = s7_symbol_local_value(sc, code, e);
52035 	  if ((val) &&
52036 	      (val != sc->undefined) &&
52037 	      (!is_any_macro(val)))
52038 	    {
52039 	      int32_t typ;
52040 
52041 	      typ = type(val);
52042 	      if (typ < T_CONTINUATION)
52043 		{
52044 		  char *objstr, *str;
52045 		  s7_pointer objp;
52046 		  const char *spaces;
52047 		  s7_int new_note_len, notes_max, spaces_len;
52048 		  bool new_notes_line = false, old_short_print;
52049 		  s7_int old_len, objlen;
52050 
52051 		  spaces = "                                                                                ";
52052 		  spaces_len = 80;
52053 
52054 		  if (notes_start_col < 0) notes_start_col = 50;
52055 		  if (notes_start_col > total_cols) notes_start_col = 0;
52056 		  notes_max = total_cols - notes_start_col;
52057 
52058 		  old_short_print = sc->short_print;
52059 		  sc->short_print = true;
52060 		  old_len = sc->print_length;
52061 		  if (sc->print_length > 4) sc->print_length = 4;
52062 		  objp = s7_object_to_string(sc, val, true);
52063 		  objstr = string_value(objp);
52064 		  objlen = string_length(objp);
52065 		  if ((objlen > notes_max) &&
52066 		      (notes_max > 5))
52067 		    {
52068 		      objstr[notes_max - 4] = '.';
52069 		      objstr[notes_max - 3] = '.';
52070 		      objstr[notes_max - 2] = '.';
52071 		      objstr[notes_max - 1] = '\0';
52072 		      objlen = notes_max;
52073 		    }
52074 		  sc->short_print = old_short_print;
52075 		  sc->print_length = old_len;
52076 
52077 		  new_note_len = symbol_name_length(code) + 3 + objlen;
52078 		  /* we want to append this much info to the notes, but does it need a new line? */
52079 		  if (notes_start_col < code_cols)
52080 		    new_notes_line = true;
52081 		  else
52082 		    if (notes)
52083 		      {
52084 			char *last_newline;
52085 			s7_int cur_line_len;
52086 			last_newline = strrchr(notes, (int)'\n'); /* returns ptr to end if none = nil if not found? */
52087 			cur_line_len = (last_newline) ? (strlen(notes) - strlen(last_newline)) : strlen(notes);
52088 			new_notes_line = ((cur_line_len + new_note_len) > notes_max);
52089 		      }
52090 
52091 		  if (new_notes_line)
52092 		    {
52093 		      new_note_len += (4 + notes_start_col + ((notes) ? strlen(notes) : 0));
52094 		      str = (char *)Malloc(new_note_len);
52095 		      /* str[0] = '\0'; */
52096 		      catstrs_direct(str,
52097 			      (notes) ? notes : "",
52098 			      "\n",
52099 			      (as_comment) ? "; " : "",
52100 			      (spaces_len >= notes_start_col) ? (char *)(spaces + spaces_len - notes_start_col) : "",
52101 			      (as_comment) ? "" : " ; ",
52102 			      symbol_name(code),
52103 			      ": ",
52104 			      objstr, (const char *)NULL);
52105 		    }
52106 		  else
52107 		    {
52108 		      new_note_len += ((notes) ? strlen(notes) : 0) + 4;
52109 		      str = (char *)Malloc(new_note_len);
52110 		      /* str[0] = '\0'; */
52111 		      catstrs_direct(str,
52112 			      (notes) ? notes : "",
52113 			      (notes) ? ", " : " ; ",
52114 			      symbol_name(code),
52115 			      ": ",
52116 			      objstr, (const char *)NULL);
52117 		    }
52118 		  if (notes) free(notes);
52119 		  return(str);
52120 		}}}
52121       return(notes);
52122     }
52123   if ((is_pair(code)) &&
52124       (s7_list_length(sc, code) > 0) &&
52125       (depth < 32))
52126     {
52127       notes = stacktrace_walker(sc, car(code), e, notes, code_cols, total_cols, notes_start_col, as_comment, depth + 1);
52128       return(stacktrace_walker(sc, cdr(code), e, notes, code_cols, total_cols, notes_start_col, as_comment, depth + 2));
52129     }
52130   return(notes);
52131 }
52132 
52133 static block_t *stacktrace_add_func(s7_scheme *sc, s7_pointer f, s7_pointer code, char *errstr, char *notes, s7_int code_max, bool as_comment)
52134 {
52135   s7_int newlen, errlen;
52136   char *newstr, *str;
52137   block_t *newp, *b;
52138 
52139   errlen = strlen(errstr);
52140   if ((is_symbol(f)) &&
52141       (f != car(code)))
52142     {
52143       newlen = symbol_name_length(f) + errlen + 10;
52144       newp = mallocate(sc, newlen);
52145       newstr = (char *)block_data(newp);
52146       /* newstr[0] = '\0'; */
52147       errlen = catstrs_direct(newstr, symbol_name(f), ": ", errstr, (const char *)NULL);
52148     }
52149   else
52150     {
52151       newlen = errlen + 8;
52152       newp = mallocate(sc, newlen);
52153       newstr = (char *)block_data(newp);
52154       /* newstr[0] = '\0'; */
52155       if ((errlen > 2) && (errstr[2] == '('))
52156         errlen = catstrs_direct(newstr, "  ", errstr, (const char *)NULL);
52157       else
52158 	{
52159 	  memcpy((void *)newstr, (void *)errstr, errlen);
52160 	  newstr[errlen] = '\0';
52161 	}}
52162 
52163   newlen = code_max + 8 + ((notes) ? strlen(notes) : 0);
52164   b = mallocate(sc, newlen);
52165   str = (char *)block_data(b);
52166   /* str[0] = '\0'; */
52167 
52168   if (errlen >= code_max)
52169     {
52170       newstr[code_max - 4] = '.';
52171       newstr[code_max - 3] = '.';
52172       newstr[code_max - 2] = '.';
52173       newstr[code_max - 1] = '\0';
52174       catstrs_direct(str, (as_comment) ? "; " : "", newstr, (notes) ? notes : "", "\n", (const char *)NULL);
52175     }
52176   else
52177     {
52178       /* send out newstr, pad with spaces to code_max, then notes */
52179       s7_int len;
52180       len = catstrs_direct(str, (as_comment) ? "; " : "", newstr, (const char *)NULL);
52181       if (notes)
52182 	{
52183 	  s7_int i;
52184 	  for (i = len; i < code_max - 1; i++)
52185 	    str[i] = ' ';
52186 	  str[i] = '\0';
52187 	  catstrs(str, newlen, notes, "\n", (char *)NULL);
52188 	}
52189       else catstrs(str, newlen, "\n", (char *)NULL);
52190     }
52191   liberate(sc, newp);
52192   return(b);
52193 }
52194 
52195 static s7_pointer stacktrace_1(s7_scheme *sc, s7_int frames_max, s7_int code_cols, s7_int total_cols, s7_int notes_start_col, bool as_comment)
52196 {
52197   char *str = NULL;
52198   block_t *strp = NULL;
52199   int64_t loc, top, frames = 0;
52200 
52201   clear_symbol_list(sc);
52202   top = (sc->stack_end - sc->stack_start) / 4; /* (*s7* 'stack_top), not current_stack_top! */
52203 
52204   if (stacktrace_in_error_handler(sc, top))
52205     {
52206       s7_pointer err_code;
52207       err_code = slot_value(sc->error_code);
52208       if ((is_pair(err_code)) &&
52209 	  (!tree_is_cyclic(sc, err_code)))
52210 	{
52211 	  char *notes = NULL;
52212 	  s7_pointer current_let, f, errstr;
52213 
52214 	  errstr = s7_object_to_string(sc, err_code, false);
52215 	  current_let = let_outlet(sc->owlet);
52216 	  f = stacktrace_find_caller(sc, current_let); /* this is a symbol */
52217 	  if ((is_let(current_let)) &&
52218 	      (current_let != sc->rootlet))
52219 	    notes = stacktrace_walker(sc, err_code, current_let, NULL, code_cols, total_cols, notes_start_col, as_comment, 0);
52220 	  strp = stacktrace_add_func(sc, f, err_code, string_value(errstr), notes, code_cols, as_comment);
52221 	  str = (char *)block_data(strp);
52222 	}
52223 
52224       /* now if OP_ERROR_HOOK_QUIT is in the stack, jump past it! */
52225       loc = stacktrace_find_error_hook_quit(sc);
52226       if (loc > 0) top = (loc + 1) / 4;
52227     }
52228 
52229   for (loc = top - 1; loc > 0; loc--)
52230     {
52231       s7_pointer code;
52232       s7_int true_loc;
52233 
52234       true_loc = (loc + 1) * 4 - 1;
52235       code = stack_code(sc->stack, true_loc);
52236       if ((is_pair(code)) &&
52237 	  (!tree_is_cyclic(sc, code)))
52238 	{
52239 	  s7_pointer codep;
52240 	  codep = s7_object_to_string(sc, code, false);
52241 	  if (string_length(codep) > 0)
52242 	    {
52243 	      char *codestr;
52244 	      codestr = string_value(codep);
52245 	      if ((!local_strcmp(codestr, "(result)")) &&
52246 		  (!local_strcmp(codestr, "(#f)")) &&
52247 		  (!strstr(codestr, "(stacktrace)")) &&
52248 		  (!strstr(codestr, "(stacktrace ")))
52249 		{
52250 		  s7_pointer e, f;
52251 
52252 		  e = stack_let(sc->stack, true_loc);
52253 		  f = stacktrace_find_caller(sc, e);
52254 		  if (!stacktrace_error_hook_function(sc, f))
52255 		    {
52256 		      char *notes = NULL, *newstr, *catstr;
52257 		      block_t *newp, *catp;
52258 		      s7_int newlen;
52259 
52260 		      frames++;
52261 		      if (frames > frames_max)
52262 			return(block_to_string(sc, strp, safe_strlen((char *)block_data(strp))));
52263 
52264 		      if ((is_let(e)) && (e != sc->rootlet))
52265 			notes = stacktrace_walker(sc, code, e, NULL, code_cols, total_cols, notes_start_col, as_comment, 0);
52266 		      newp = stacktrace_add_func(sc, f, code, codestr, notes, code_cols, as_comment);
52267 		      newstr = (char *)block_data(newp);
52268 
52269 		      if ((notes) && (notes != newstr) && (is_let(e)) && (e != sc->rootlet))
52270 			free(notes);
52271 
52272 		      newlen = strlen(newstr) + 1 + ((str) ? strlen(str) : 0);
52273 		      catp = mallocate(sc, newlen);
52274 		      catstr = (char *)block_data(catp);
52275 		      catstrs_direct(catstr, (str) ? str : "", newstr, (const char *)NULL);
52276 		      liberate(sc, newp);
52277 		      if (strp) liberate(sc, strp);
52278 		      strp = catp;
52279 		      str = (char *)block_data(strp);
52280 		    }}}}}
52281   return((strp) ? block_to_string(sc, strp, safe_strlen((char *)block_data(strp))) : make_empty_string(sc, 0, 0));
52282 }
52283 
52284 s7_pointer s7_stacktrace(s7_scheme *sc)
52285 {
52286   return(stacktrace_1(sc, 30, 45, 80, 45, false));
52287 }
52288 
52289 static s7_pointer g_stacktrace(s7_scheme *sc, s7_pointer args)
52290 {
52291   #define H_stacktrace "(stacktrace (max-frames 30) (code-cols 50) (total-cols 80) (note-col 50) as-comment) returns \
52292 a stacktrace as a string.  Each line has two portions, the code being evaluated and a note giving \
52293 the value of local variables in that code.  The first argument sets how many lines are displayed. \
52294 The next three arguments set the length and layout of those lines.  'as-comment' if #t causes each \
52295 line to be preceded by a semicolon."
52296   #define Q_stacktrace s7_make_signature(sc, 6, sc->is_string_symbol, sc->is_integer_symbol, sc->is_integer_symbol, sc->is_integer_symbol, sc->is_integer_symbol, sc->is_boolean_symbol)
52297 
52298   s7_int max_frames = 30, code_cols = 50, total_cols = 80, notes_start_col = 50;
52299   bool as_comment = false;
52300 
52301   if (!is_null(args))
52302     {
52303       if (!s7_is_integer(car(args)))
52304 	return(method_or_bust(sc, car(args), sc->stacktrace_symbol, args, T_INTEGER, 1));
52305       max_frames = s7_integer_checked(sc, car(args));
52306       if ((max_frames <= 0) || (max_frames > S7_INT32_MAX))
52307 	max_frames = 30;
52308       args = cdr(args);
52309       if (!is_null(args))
52310 	{
52311 	  if (!s7_is_integer(car(args)))
52312 	    return(wrong_type_argument(sc, sc->stacktrace_symbol, 2, car(args), T_INTEGER));
52313 	  code_cols = s7_integer_checked(sc, car(args));
52314 	  if ((code_cols <= 8) || (code_cols > 1024))
52315 	    code_cols = 50;
52316 	  args = cdr(args);
52317 	  if (!is_null(args))
52318 	    {
52319 	      if (!s7_is_integer(car(args)))
52320 		return(wrong_type_argument(sc, sc->stacktrace_symbol, 3, car(args), T_INTEGER));
52321 	      total_cols = s7_integer_checked(sc, car(args));
52322 	      if ((total_cols <= code_cols) || (total_cols > S7_INT32_MAX))
52323 		total_cols = 80;
52324 	      args = cdr(args);
52325 	      if (!is_null(args))
52326 		{
52327 		  if (!s7_is_integer(car(args)))
52328 		    return(wrong_type_argument(sc, sc->stacktrace_symbol, 4, car(args), T_INTEGER));
52329 		  notes_start_col = s7_integer_checked(sc, car(args));
52330 		  if ((notes_start_col <= 0) || (notes_start_col > S7_INT32_MAX))
52331 		    notes_start_col = 50;
52332 		  args = cdr(args);
52333 		  if (!is_null(args))
52334 		    {
52335 		      if (!s7_is_boolean(car(args)))
52336 			return(wrong_type_argument(sc, sc->stacktrace_symbol, 5, car(args), T_BOOLEAN));
52337 		      as_comment = s7_boolean(sc, car(args));
52338 		    }}}}}
52339   return(stacktrace_1(sc, max_frames, code_cols, total_cols, notes_start_col, as_comment));
52340 }
52341 
52342 
52343 /* -------- s7_history, s7_add_to_history, s7_history_enabled -------- */
52344 
52345 s7_pointer s7_add_to_history(s7_scheme *sc, s7_pointer entry)
52346 {
52347 #if WITH_HISTORY
52348   set_current_code(sc, entry);
52349 #endif
52350   return(entry);
52351 }
52352 
52353 s7_pointer s7_history(s7_scheme *sc)
52354 {
52355 #if WITH_HISTORY
52356   if (sc->cur_code == sc->history_sink)
52357     return(sc->old_cur_code);
52358 #endif
52359   return(sc->cur_code);
52360 }
52361 
52362 bool s7_history_enabled(s7_scheme *sc)
52363 {
52364 #if WITH_HISTORY
52365   return(sc->cur_code != sc->history_sink);
52366 #else
52367   return(false);
52368 #endif
52369 }
52370 
52371 bool s7_set_history_enabled(s7_scheme *sc, bool enabled)
52372 {
52373 #if WITH_HISTORY
52374   bool old_enabled;
52375   old_enabled = (sc->cur_code == sc->history_sink);
52376   if (enabled) /* this needs to restore the old cur_code (saving its position in the history_buffer) */
52377     sc->cur_code = sc->old_cur_code;
52378   else
52379     if (sc->cur_code != sc->history_sink)
52380       {
52381 	sc->old_cur_code = sc->cur_code;
52382 	sc->cur_code = sc->history_sink;
52383       }
52384   return(old_enabled);
52385 #else
52386   return(false);
52387 #endif
52388 }
52389 
52390 #if WITH_HISTORY
52391 static s7_pointer history_cons(s7_scheme *sc, s7_pointer code, s7_pointer args)
52392 {
52393   s7_pointer p;
52394   p = car(sc->history_pairs);
52395   sc->history_pairs = cdr(sc->history_pairs);
52396   set_car(p, code);
52397   set_cdr(p, args);
52398   return(p);
52399 }
52400 #else
52401 #define history_cons(Sc, Code, Args) Code
52402 #endif
52403 
52404 
52405 /* -------- error handlers -------- */
52406 
52407 static const char *make_type_name(s7_scheme *sc, const char *name, article_t article)
52408 {
52409   s7_int i, slen, len;
52410 
52411   slen = safe_strlen(name);
52412   len = slen + 8;
52413   if (len > sc->typnam_len)
52414     {
52415       if (sc->typnam) free(sc->typnam);
52416       sc->typnam = (char *)Malloc(len);
52417       sc->typnam_len = len;
52418     }
52419   if (article == INDEFINITE_ARTICLE)
52420     {
52421       i = 1;
52422       sc->typnam[0] = 'a';
52423       if ((name[0] == 'a') || (name[0] == 'e') || (name[0] == 'i') || (name[0] == 'o') || (name[0] == 'u'))
52424 	sc->typnam[i++] = 'n';
52425       sc->typnam[i++] = ' ';
52426     }
52427   else i = 0;
52428   memcpy((void *)(sc->typnam + i), (void *)name, slen);
52429   sc->typnam[i + slen] = '\0';
52430   return(sc->typnam);
52431 }
52432 
52433 static const char *type_name_from_type(int32_t typ, article_t article)
52434 {
52435   switch (typ)
52436     {
52437     case T_FREE:            return((article == NO_ARTICLE) ? "free-cell"         : "a free cell");
52438     case T_NIL:             return("nil");
52439     case T_UNUSED:          return((article == NO_ARTICLE) ? "#<unused>"         : "the unused object");
52440     case T_EOF:             return((article == NO_ARTICLE) ? "#<eof>"            : "the end-of-file object");
52441     case T_UNSPECIFIED:     return((article == NO_ARTICLE) ? "#<unspecified>"    : "the unspecified object");
52442     case T_UNDEFINED:       return((article == NO_ARTICLE) ? "undefined"         : "an undefined object");
52443     case T_BOOLEAN:         return("boolean");
52444     case T_STRING:          return((article == NO_ARTICLE) ? "string"            : "a string");
52445     case T_BYTE_VECTOR:     return((article == NO_ARTICLE) ? "byte-vector"       : "a byte-vector");
52446     case T_SYMBOL:          return((article == NO_ARTICLE) ? "symbol"            : "a symbol");
52447     case T_SYNTAX:          return((article == NO_ARTICLE) ? "syntax"            : "syntactic");
52448     case T_PAIR:            return((article == NO_ARTICLE) ? "pair"              : "a pair");
52449     case T_GOTO:            return((article == NO_ARTICLE) ? "goto"              : "a goto (from call-with-exit)");
52450     case T_CONTINUATION:    return((article == NO_ARTICLE) ? "continuation"      : "a continuation");
52451     case T_C_OPT_ARGS_FUNCTION:
52452     case T_C_RST_ARGS_FUNCTION:
52453     case T_C_ANY_ARGS_FUNCTION:
52454     case T_C_FUNCTION:      return((article == NO_ARTICLE) ? "c-function"        : "a c-function");
52455     case T_C_FUNCTION_STAR: return((article == NO_ARTICLE) ? "c-function*"       : "a c-function*");
52456     case T_CLOSURE:         return((article == NO_ARTICLE) ? "function"          : "a function");
52457     case T_CLOSURE_STAR:    return((article == NO_ARTICLE) ? "function*"         : "a function*");
52458     case T_C_MACRO:         return((article == NO_ARTICLE) ? "c-macro"           : "a c-macro");
52459     case T_C_POINTER:       return((article == NO_ARTICLE) ? "c-pointer"         : "a c-pointer");
52460     case T_CHARACTER:       return((article == NO_ARTICLE) ? "character"         : "a character");
52461     case T_VECTOR:          return((article == NO_ARTICLE) ? "vector"            : "a vector");
52462     case T_INT_VECTOR:      return((article == NO_ARTICLE) ? "int-vector"        : "an int-vector");
52463     case T_FLOAT_VECTOR:    return((article == NO_ARTICLE) ? "float-vector"      : "a float-vector");
52464     case T_MACRO_STAR:      return((article == NO_ARTICLE) ? "macro*"            : "a macro*");
52465     case T_MACRO:           return((article == NO_ARTICLE) ? "macro"             : "a macro");
52466     case T_BACRO_STAR:      return((article == NO_ARTICLE) ? "bacro*"            : "a bacro*");
52467     case T_BACRO:           return((article == NO_ARTICLE) ? "bacro"             : "a bacro");
52468     case T_CATCH:           return((article == NO_ARTICLE) ? "catch"             : "a catch");
52469     case T_STACK:           return((article == NO_ARTICLE) ? "stack"             : "a stack");
52470     case T_DYNAMIC_WIND:    return((article == NO_ARTICLE) ? "dynamic-wind"      : "a dynamic-wind");
52471     case T_HASH_TABLE:      return((article == NO_ARTICLE) ? "hash-table"        : "a hash-table");
52472     case T_ITERATOR:        return((article == NO_ARTICLE) ? "iterator"          : "an iterator");
52473     case T_LET:             return((article == NO_ARTICLE) ? "let"               : "a let");
52474     case T_COUNTER:         return((article == NO_ARTICLE) ? "internal-counter"  : "an internal counter");
52475     case T_RANDOM_STATE:    return((article == NO_ARTICLE) ? "random-state"      : "a random-state");
52476     case T_SLOT:            return((article == NO_ARTICLE) ? "slot"              : "a slot (variable binding)");
52477     case T_INTEGER:         return((article == NO_ARTICLE) ? "integer"           : "an integer");
52478     case T_RATIO:           return((article == NO_ARTICLE) ? "ratio"             : "a ratio");
52479     case T_REAL:            return((article == NO_ARTICLE) ? "real"              : "a real");
52480     case T_COMPLEX:         return((article == NO_ARTICLE) ? "complex-number"    : "a complex number");
52481     case T_BIG_INTEGER:     return((article == NO_ARTICLE) ? "big-integer"       : "a big integer");
52482     case T_BIG_RATIO:       return((article == NO_ARTICLE) ? "big-ratio"         : "a big ratio");
52483     case T_BIG_REAL:        return((article == NO_ARTICLE) ? "big-real"          : "a big real");
52484     case T_BIG_COMPLEX:     return((article == NO_ARTICLE) ? "big-complex-number": "a big complex number");
52485     case T_INPUT_PORT:      return((article == NO_ARTICLE) ? "input-port"        : "an input port");
52486     case T_OUTPUT_PORT:     return((article == NO_ARTICLE) ? "output-port"       : "an output port");
52487     case T_C_OBJECT:        return((article == NO_ARTICLE) ? "c-object"          : "a c_object");
52488     }
52489   return(NULL);
52490 }
52491 
52492 static const char *type_name(s7_scheme *sc, s7_pointer arg, article_t article)
52493 {
52494   switch (unchecked_type(arg))
52495     {
52496     case T_C_OBJECT:    return(make_type_name(sc, string_value(c_object_scheme_name(sc, arg)), article));
52497     case T_INPUT_PORT:  return(make_type_name(sc, (is_file_port(arg)) ? "input file port" : ((is_string_port(arg)) ? "input string port" : "input port"), article));
52498     case T_OUTPUT_PORT: return(make_type_name(sc, (is_file_port(arg)) ? "output file port" : ((is_string_port(arg)) ? "output string port" : "output port"), article));
52499     case T_LET:
52500       if (has_active_methods(sc, arg))
52501 	{
52502 	  s7_pointer class_name;
52503 	  class_name = find_method(sc, arg, sc->class_name_symbol);
52504 	  if (is_symbol(class_name))
52505 	    return(make_type_name(sc, symbol_name(class_name), article));
52506 	}
52507     default:
52508       {
52509 	const char *str;
52510 	str = type_name_from_type(unchecked_type(arg), article);
52511 	if (str) return(str);
52512       }}
52513   return("messed up object");
52514 }
52515 
52516 static s7_pointer prepackaged_type_name(s7_scheme *sc, s7_pointer x)
52517 {
52518   s7_pointer p;
52519   uint8_t typ;
52520 
52521   if (has_active_methods(sc, x))
52522     {
52523       p = find_method_with_let(sc, x, sc->class_name_symbol);
52524       if (is_symbol(p))
52525 	return(symbol_name_cell(p));
52526     }
52527   typ = type(x);
52528   switch (typ)
52529     {
52530     case T_C_OBJECT:    return(c_object_scheme_name(sc, x));
52531     case T_INPUT_PORT:  return((is_file_port(x)) ? an_input_file_port_string : ((is_string_port(x)) ? an_input_string_port_string : an_input_port_string));
52532     case T_OUTPUT_PORT: return((is_file_port(x)) ? an_output_file_port_string : ((is_string_port(x)) ? an_output_string_port_string : an_output_port_string));
52533     default:
52534       p = sc->prepackaged_type_names[type(x)];
52535       if (is_string(p)) return(p);
52536     }
52537   return(wrap_string(sc, "unknown type!", 13));
52538 }
52539 
52540 static s7_pointer type_name_string(s7_scheme *sc, s7_pointer arg)
52541 {
52542   if (type(arg) < NUM_TYPES)
52543     {
52544       s7_pointer p;
52545       p = sc->prepackaged_type_names[type(arg)]; /* these use INDEFINITE_ARTICLE */
52546       if (is_string(p)) return(p);
52547     }
52548   return(s7_make_string_wrapper(sc, type_name(sc, arg, INDEFINITE_ARTICLE)));
52549 }
52550 
52551 static s7_pointer wrong_type_arg_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg_n, s7_pointer arg, s7_pointer typnam, s7_pointer descr)
52552 {
52553   s7_pointer p;
52554   p = cdr(sc->wrong_type_arg_info);  /* info list is '(format_string caller arg_n arg type_name descr) */
52555   set_car(p, caller);  p = cdr(p);
52556   set_car(p, arg_n);   p = cdr(p);
52557   set_car(p, arg);     p = cdr(p);
52558   set_car(p, (typnam == sc->unused) ? prepackaged_type_name(sc, arg) : typnam);
52559   p = cdr(p);
52560   set_car(p, descr);
52561   return(s7_error(sc, sc->wrong_type_arg_symbol, sc->wrong_type_arg_info));
52562 }
52563 
52564 static s7_pointer simple_wrong_type_arg_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg, s7_pointer typnam, s7_pointer descr)
52565 {
52566   set_wlist_4(cdr(sc->simple_wrong_type_arg_info), caller, arg, (typnam == sc->unused) ? prepackaged_type_name(sc, arg) : typnam, descr);
52567   return(s7_error(sc, sc->wrong_type_arg_symbol, sc->simple_wrong_type_arg_info));
52568 }
52569 
52570 s7_pointer s7_wrong_type_arg_error(s7_scheme *sc, const char *caller, s7_int arg_n, s7_pointer arg, const char *descr)
52571 {
52572   if (arg_n > 0)
52573     return(wrong_type_arg_error_prepackaged(sc, wrap_string(sc, caller, safe_strlen(caller)), wrap_integer1(sc, arg_n),
52574 					    arg, type_name_string(sc, arg), wrap_string(sc, descr, safe_strlen(descr))));
52575   return(simple_wrong_type_arg_error_prepackaged(sc, wrap_string(sc, caller, safe_strlen(caller)), arg,
52576 						 type_name_string(sc, arg), wrap_string(sc, descr, safe_strlen(descr))));
52577 }
52578 
52579 static s7_pointer out_of_range_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg_n, s7_pointer arg, s7_pointer descr)
52580 {
52581   set_wlist_4(cdr(sc->out_of_range_info), caller, arg_n, arg, descr);
52582   return(s7_error(sc, sc->out_of_range_symbol, sc->out_of_range_info));
52583 }
52584 
52585 static s7_pointer simple_out_of_range_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg, s7_pointer descr)
52586 {
52587   set_wlist_3(cdr(sc->simple_out_of_range_info), caller, arg, descr);
52588   return(s7_error(sc, sc->out_of_range_symbol, sc->simple_out_of_range_info));
52589 }
52590 
52591 s7_pointer s7_out_of_range_error(s7_scheme *sc, const char *caller, s7_int arg_n, s7_pointer arg, const char *descr)
52592 {
52593   if (arg_n > 0)
52594     return(out_of_range_error_prepackaged(sc, wrap_string(sc, caller, safe_strlen(caller)), wrap_integer1(sc, arg_n), arg,
52595 					  wrap_string(sc, descr, safe_strlen(descr))));
52596   return(simple_out_of_range_error_prepackaged(sc, wrap_string(sc, caller, safe_strlen(caller)),
52597 					       arg, wrap_string(sc, descr, safe_strlen(descr))));
52598 }
52599 
52600 s7_pointer s7_wrong_number_of_args_error(s7_scheme *sc, const char *caller, s7_pointer args)
52601 {
52602   return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_2(sc, s7_make_string_wrapper(sc, caller), args))); /* "caller" includes the format directives */
52603 }
52604 
52605 static s7_pointer division_by_zero_error(s7_scheme *sc, s7_pointer caller, s7_pointer arg)
52606 {
52607   return(s7_error(sc, sc->division_by_zero_symbol, set_elist_3(sc, wrap_string(sc, "~A: division by zero, ~S", 24), caller, arg)));
52608 }
52609 
52610 static s7_pointer file_error(s7_scheme *sc, const char *caller, const char *descr, const char *name)
52611 {
52612   return(s7_error(sc, sc->io_error_symbol,
52613 		  set_elist_4(sc, wrap_string(sc, "~A: ~A ~S", 9),
52614 				  s7_make_string_wrapper(sc, caller),
52615 				  s7_make_string_wrapper(sc, descr),
52616 				  s7_make_string_wrapper(sc, name))));
52617 }
52618 
52619 
52620 /* -------------------------------- profile -------------------------------- */
52621 
52622 static void swap_stack(s7_scheme *sc, opcode_t new_op, s7_pointer new_code, s7_pointer new_args)
52623 {
52624   s7_pointer code, args, e;
52625   opcode_t op;
52626 
52627   sc->stack_end -= 4;
52628   code = sc->stack_end[0];
52629   e = sc->stack_end[1];
52630   args = sc->stack_end[2];
52631   op = (opcode_t)(sc->stack_end[3]); /* this should be begin1 */
52632 #if S7_DEBUGGING
52633   if ((op != OP_BEGIN_NO_HOOK) && (op != OP_BEGIN_HOOK)) fprintf(stderr, "swap %s\n", op_names[op]);
52634 #endif
52635   push_stack(sc, new_op, new_args, new_code);
52636 
52637   sc->stack_end[0] = code;
52638   sc->stack_end[1] = e;
52639   sc->stack_end[2] = args;
52640   sc->stack_end[3] = (s7_pointer)op;
52641   sc->stack_end += 4;
52642 }
52643 
52644 static s7_pointer find_funclet(s7_scheme *sc, s7_pointer e)
52645 {
52646   if ((e == sc->rootlet) || (!is_let(e))) return(sc->F);
52647   if (!((is_funclet(e)) || (is_maclet(e)))) e = let_outlet(e);
52648   if ((e == sc->rootlet) || (!is_let(e))) return(sc->F);
52649   return(((is_funclet(e)) || (is_maclet(e))) ? e : sc->F);
52650 }
52651 
52652 #define PD_INITIAL_SIZE 16
52653 enum {PD_CALLS = 0, PD_RECUR, PD_START, PD_ITOTAL, PD_ETOTAL, PD_BLOCK_SIZE};
52654 
52655 static s7_pointer g_profile_out(s7_scheme *sc, s7_pointer args)
52656 {
52657   s7_int pos;
52658   s7_int *v;
52659   profile_data_t *pd;
52660 
52661   pd = sc->profile_data;
52662   pos = symbol_position(car(args));
52663   v = (s7_int *)(pd->data + pos);
52664   v[PD_RECUR]--;
52665   if (v[PD_RECUR] == 0)
52666     {
52667       s7_int cur_time;
52668       cur_time = (my_clock() - v[PD_START]);
52669       v[PD_ITOTAL] += cur_time;
52670       v[PD_ETOTAL] += (cur_time - pd->excl[pd->excl_top]);
52671       pd->excl_top--;
52672       pd->excl[pd->excl_top] += cur_time;
52673     }
52674   return(sc->F);
52675 }
52676 
52677 static s7_pointer g_profile_in(s7_scheme *sc, s7_pointer args) /* only external func -- added to each profiled func by add_profile above */
52678 {
52679   #define H_profile_in "(profile-in e) is the profiler's hook into closures"
52680   #define Q_profile_in s7_make_signature(sc, 2, sc->T, sc->is_let_symbol)
52681 
52682   s7_pointer e;
52683   if (sc->profile == 0) return(sc-> F);
52684 
52685   e = find_funclet(sc, car(args));
52686   if ((is_let(e)) &&
52687       (is_symbol(funclet_function(e))))
52688     {
52689       s7_pointer func_name;
52690       s7_int pos;
52691       s7_int *v;
52692       profile_data_t *pd;
52693 
52694       pd = sc->profile_data;
52695       func_name = funclet_function(e);
52696       pos = symbol_position(func_name);
52697 
52698       if (pos == PD_POSITION_UNSET)
52699 	{
52700 	  if (pd->top == pd->size)
52701 	    {
52702 	      s7_int i;
52703 	      pd->size *= 2;
52704 	      pd->funcs = (s7_pointer *)Realloc(pd->funcs, pd->size * sizeof(s7_pointer));
52705 	      pd->data = (s7_int *)Realloc(pd->data, pd->size * PD_BLOCK_SIZE * sizeof(s7_int));
52706 	      for (i = pd->top * PD_BLOCK_SIZE; i < pd->size * PD_BLOCK_SIZE; i++) pd->data[i] = 0;
52707 	    }
52708 	  pos = pd->top * PD_BLOCK_SIZE;
52709 	  symbol_set_position(func_name, pos);
52710 	  pd->funcs[pd->top] = func_name;
52711 	  pd->top++;
52712 	  if (is_gensym(func_name)) sc->profiling_gensyms = true;
52713 	}
52714 
52715       v = (s7_int *)(sc->profile_data->data + pos);
52716       v[PD_CALLS]++;
52717       if (v[PD_RECUR] == 0)
52718 	{
52719 	  v[PD_START] = my_clock();
52720 	  pd->excl_top++;
52721 	  if (pd->excl_top == pd->excl_size)
52722 	    {
52723 	      pd->excl_size *= 2;
52724 	      pd->excl = (s7_int *)Realloc(pd->excl, pd->excl_size * sizeof(s7_int));
52725 	    }
52726 	  pd->excl[pd->excl_top] = 0;
52727 	}
52728       v[PD_RECUR]++;
52729 
52730       /* this doesn't work in "continuation passing" code (e.g. cpstak.scm in the so-called standard benchmarks).
52731        *   swap_stack pushes dynamic_unwind, but we don't pop back to it, so the stack grows to the recursion depth.
52732        */
52733       if (sc->stack_end >= sc->stack_resize_trigger)
52734 	{
52735 	  #define PROFILE_MAX_STACK_SIZE 10000000  /* around 5G counting lets/arglists/slots, maybe an *s7* field for this? */
52736 	  if (sc->stack_size > PROFILE_MAX_STACK_SIZE)
52737 	    s7_error(sc, make_symbol(sc, "stack-too-big"),
52738 		     set_elist_2(sc, wrap_string(sc, "profiling stack size has grown past ~D", 38), make_integer(sc, PROFILE_MAX_STACK_SIZE)));
52739 	  /* rather than raise an error, we could unwind the stack here, popping off all unwind entries, but this is
52740 	   *   a very rare problem, and the results will be confusing anyway.
52741 	   */
52742 	  resize_stack(sc);
52743 	}
52744       swap_stack(sc, OP_DYNAMIC_UNWIND_PROFILE, sc->profile_out, func_name);
52745     }
52746   return(sc->F);
52747 }
52748 
52749 static s7_pointer profile_info_out(s7_scheme *sc)
52750 {
52751   s7_pointer p, vs, vi;
52752   profile_data_t *pd;
52753 
52754   pd = sc->profile_data;
52755   if ((!pd) || (pd->top == 0))
52756     return(sc->F);
52757 
52758   p = list_3(sc, sc->F, sc->F, make_integer(sc, ticks_per_second()));
52759   sc->w = p;
52760 
52761   set_car(p, vs = make_simple_vector(sc, pd->top));
52762   memcpy((void *)(vector_elements(vs)), (void *)(pd->funcs), pd->top * sizeof(s7_pointer));
52763 
52764   set_car(cdr(p), vi = make_simple_int_vector(sc, pd->top * PD_BLOCK_SIZE));
52765   memcpy((void *)int_vector_ints(vi), (void *)pd->data, pd->top * PD_BLOCK_SIZE * sizeof(s7_int));
52766 
52767   sc->w = sc->nil;
52768   return(p);
52769 }
52770 
52771 static s7_pointer clear_profile_info(s7_scheme *sc)
52772 {
52773   if (sc->profile_data)
52774     {
52775       profile_data_t *pd;
52776       int32_t i;
52777       pd = sc->profile_data;
52778       for (i = 0; i < pd->top; i++)
52779 	symbol_set_position(pd->funcs[i], PD_POSITION_UNSET);
52780       memclr64(pd->data, pd->top * PD_BLOCK_SIZE * sizeof(s7_int)); /* memclr64 ok because init_size is 16 and we double when resizing */
52781       pd->top = 0;
52782       for (i = 0; i < pd->excl_top; i++)
52783 	pd->excl[i] = 0;
52784       pd->excl_top = 0;
52785       sc->profiling_gensyms = false;
52786     }
52787   return(sc->F);
52788 }
52789 
52790 static s7_pointer make_profile_info(s7_scheme *sc)
52791 {
52792   if (!sc->profile_data)
52793     {
52794       profile_data_t *pd;
52795       pd = (profile_data_t *)Malloc(sizeof(profile_data_t));
52796       pd->size = PD_INITIAL_SIZE;
52797       pd->excl_size = PD_INITIAL_SIZE;
52798       pd->top = 0;
52799       pd->excl_top = 0;
52800       pd->funcs = (s7_pointer *)Calloc(pd->size, sizeof(s7_pointer));
52801       pd->excl = (s7_int *)Calloc(pd->excl_size, sizeof(s7_int));
52802       pd->data = (s7_int *)Calloc(pd->size * PD_BLOCK_SIZE, sizeof(s7_int));
52803       sc->profile_data = pd;
52804     }
52805   return(sc->F);
52806 }
52807 
52808 
52809 /* -------------------------------- dynamic-unwind -------------------------------- */
52810 
52811 static s7_pointer dynamic_unwind(s7_scheme *sc, s7_pointer func, s7_pointer e)
52812 {
52813 #if S7_DEBUGGING
52814   if (is_multiple_value(sc->value))
52815     fprintf(stderr, "%s[%d]: unexpected multiple-value! %s %s %s\n", __func__, __LINE__, display(func), display(e), display(sc->value));
52816 #endif
52817   return(s7_apply_function(sc, func, set_plist_2(sc, e, sc->value))); /* s7_apply_function returns sc->value */
52818 }
52819 
52820 static s7_pointer g_dynamic_unwind(s7_scheme *sc, s7_pointer args)
52821 {
52822   #define H_dynamic_unwind "(dynamic-unwind func arg) pushes func and arg on the stack, then (func arg) is called when the stack unwinds."
52823   #define Q_dynamic_unwind s7_make_signature(sc, 3, sc->is_procedure_symbol, sc->is_procedure_symbol, sc->T)
52824 
52825   check_stack_size(sc);
52826   swap_stack(sc, OP_DYNAMIC_UNWIND, car(args), cadr(args));
52827   return(cadr(args));
52828 }
52829 
52830 
52831 /* -------------------------------- catch -------------------------------- */
52832 static s7_pointer g_catch(s7_scheme *sc, s7_pointer args)
52833 {
52834   #define H_catch "(catch tag thunk handler) evaluates thunk; if an error occurs that matches the tag (#t matches all), the handler is called"
52835   #define Q_catch s7_make_signature(sc, 4, sc->values_symbol, s7_make_signature(sc, 2, sc->is_symbol_symbol, sc->is_boolean_symbol), sc->is_procedure_symbol, sc->is_procedure_symbol)
52836 
52837   s7_pointer p, proc, err;
52838 
52839   /* Guile sets up the catch before looking for arg errors:
52840    *   (catch #t log (lambda args "hiho")) -> "hiho"
52841    * which is consistent in that (catch #t (lambda () (log))...) should probably be the same as (catch #t log ...)
52842    * but what if the error handler arg is messed up?  Seems weird to handle args in reverse order with an intervening let etc.
52843    */
52844 
52845   proc = cadr(args);
52846   err = caddr(args);
52847   /* if (is_let(err)) check_method(sc, err, sc->catch_symbol, args); */ /* causes exit from s7! */
52848 
52849   new_cell(sc, p, T_CATCH);
52850   catch_tag(p) = car(args);
52851   catch_goto_loc(p) = current_stack_top(sc);
52852   catch_op_loc(p) = (int32_t)(sc->op_stack_now - sc->op_stack);
52853   catch_set_handler(p, err);
52854 
52855   if (is_any_macro(err))
52856     push_stack(sc, OP_CATCH_2, args, p);
52857   else push_stack(sc, OP_CATCH, args, p);      /* args ignored but maybe safer for GC? */
52858 
52859   /* not sure about these error checks -- they can be omitted */
52860   if (!is_thunk(sc, proc))
52861     return(wrong_type_argument_with_type(sc, sc->catch_symbol, 2, proc, a_thunk_string));
52862 
52863   if (!is_applicable(err))
52864     return(wrong_type_argument_with_type(sc, sc->catch_symbol, 3, err, something_applicable_string));
52865 
52866   /* should we check here for (aritable? err 2)?
52867    *  (catch #t (lambda () 1) "hiho") -> 1
52868    * currently this is checked only if the error handler is called
52869    */
52870 
52871   if (is_closure(proc))                        /* not also lambda* here because we need to handle the arg defaults */
52872     {
52873       /* is_thunk above checks is_aritable(proc, 0), but if it's (lambda args ...) we have to set up the let with args=()
52874        *    the case that caught this: (catch #t make-hook ...)
52875        */
52876       sc->code = closure_body(proc);
52877       if (is_symbol(closure_args(proc)))
52878 	sc->curlet = make_let_with_slot(sc, closure_let(proc), closure_args(proc), sc->nil);
52879       else sc->curlet = make_let(sc, closure_let(proc));
52880       push_stack_no_args_direct(sc, sc->begin_op);
52881     }
52882   else push_stack(sc, OP_APPLY, sc->nil, proc);
52883 
52884   return(sc->F);
52885 }
52886 
52887 s7_pointer s7_call_with_catch(s7_scheme *sc, s7_pointer tag, s7_pointer body, s7_pointer error_handler)
52888 {
52889   s7_pointer p, result;
52890 
52891   new_cell(sc, p, T_CATCH);
52892   catch_tag(p) = tag;
52893   catch_goto_loc(p) = current_stack_top(sc);
52894   catch_op_loc(p) = (int32_t)(sc->op_stack_now - sc->op_stack);
52895   catch_set_handler(p, error_handler);
52896 
52897   push_stack(sc, OP_CATCH, error_handler, p);
52898   result = s7_call(sc, body, sc->nil);
52899   /* don't unstack here -- if error caught, catch has been popped off already */
52900 
52901   return(result);
52902 }
52903 
52904 static void op_c_catch(s7_scheme *sc)
52905 {
52906   /* (catch #t (lambda () (set! ("hi") #\a)) (lambda args args))
52907    *    code is (catch #t (lambda () ....) (lambda args ....))
52908    */
52909   s7_pointer p, f, args, tag;
52910   args = cddr(sc->code);
52911 
52912   /* defer making the error lambda */
52913   /* check catch tag */
52914   f = cadr(sc->code);
52915   if (!is_pair(f))                     /* (catch #t ...) or (catch sym ...) */
52916     tag = (is_symbol(f)) ? lookup_checked(sc, f) : f;
52917   else tag = cadr(f);                  /* (catch 'sym ...) */
52918 
52919   new_cell(sc, p, T_CATCH);            /* the catch object sitting on the stack */
52920   catch_tag(p) = tag;
52921   catch_goto_loc(p) = current_stack_top(sc);
52922   catch_op_loc(p) = sc->op_stack_now - sc->op_stack;
52923   catch_set_handler(p, cdadr(args));       /* not yet a closure... */
52924 
52925   push_stack(sc, OP_CATCH_1, sc->code, p); /* code ignored here, except by GC */
52926   sc->curlet = make_let(sc, sc->curlet);
52927   sc->code = T_Pair(cddar(args));
52928 }
52929 
52930 static void op_c_catch_all(s7_scheme *sc)
52931 {
52932   sc->curlet = make_let(sc, sc->curlet);
52933   catch_all_set_goto_loc(sc->curlet, current_stack_top(sc));
52934   catch_all_set_op_loc(sc->curlet, sc->op_stack_now - sc->op_stack);
52935   push_stack_direct(sc, OP_CATCH_ALL);
52936   sc->code = T_Pair(opt1_pair(cdr(sc->code)));       /* the body of the first lambda (or car of it if catch_all_o) */
52937 }
52938 
52939 static Inline void op_c_catch_all_a(s7_scheme *sc)
52940 {
52941   sc->curlet = make_let(sc, sc->curlet);
52942   catch_all_set_goto_loc(sc->curlet, current_stack_top(sc));
52943   catch_all_set_op_loc(sc->curlet, sc->op_stack_now - sc->op_stack);
52944   push_stack_direct(sc, OP_CATCH_ALL);
52945   sc->value = fx_call(sc, opt1_pair(cdr(sc->code)));
52946 }
52947 
52948 
52949 /* -------------------------------- owlet -------------------------------- */
52950 /* error reporting info -- save filename and line number */
52951 
52952 static s7_pointer init_owlet(s7_scheme *sc)
52953 {
52954   s7_pointer e, p;
52955   e = make_let_slowly(sc, sc->nil);
52956   sc->temp3 = e;
52957   sc->error_type = make_slot_1(sc, e, make_symbol(sc, "error-type"), sc->F);  /* the error type or tag ('division-by-zero) */
52958   sc->error_data = make_slot_1(sc, e, make_symbol(sc, "error-data"), sc->F);  /* the message or information passed by the error function */
52959   sc->error_code = make_slot_1(sc, e, make_symbol(sc, "error-code"), sc->F);  /* the code that s7 thinks triggered the error */
52960   sc->error_line = make_slot_1(sc, e, make_symbol(sc, "error-line"), p = make_permanent_integer_unchecked(0));  /* the line number of that code */
52961   add_saved_pointer(sc, p);
52962   sc->error_file = make_slot_1(sc, e, make_symbol(sc, "error-file"), sc->F);  /* the file name of that code */
52963   sc->error_position = make_slot_1(sc, e, make_symbol(sc, "error-position"), p = make_permanent_integer_unchecked(0));  /* the file-byte position of that code */
52964   add_saved_pointer(sc, p);
52965 #if WITH_HISTORY
52966   sc->error_history = make_slot_1(sc, e, make_symbol(sc, "error-history"), sc->F); /* buffer of previous evaluations */
52967 #endif
52968   sc->temp3 = sc->nil;
52969   return(e);
52970 }
52971 
52972 #if WITH_HISTORY
52973 static s7_pointer cull_history(s7_scheme *sc, s7_pointer code)
52974 {
52975   s7_pointer p;
52976   clear_symbol_list(sc); /* make a list of words banned from the history */
52977   add_symbol_to_list(sc, sc->s7_let_symbol);
52978   add_symbol_to_list(sc, sc->eval_symbol);
52979   add_symbol_to_list(sc, make_symbol(sc, "debug"));
52980   add_symbol_to_list(sc, make_symbol(sc, "trace-in"));
52981   add_symbol_to_list(sc, make_symbol(sc, "trace-out"));
52982   add_symbol_to_list(sc, sc->dynamic_unwind_symbol);
52983   add_symbol_to_list(sc, make_symbol(sc, "history-enabled"));
52984   for (p = code; is_pair(p); p = cdr(p))
52985     {
52986       if (tree_set_memq(sc, car(p)))
52987 	set_car(p, sc->nil);
52988       if (cdr(p) == code) break;
52989     }
52990   return(code);
52991 }
52992 #endif
52993 
52994 static s7_pointer g_owlet(s7_scheme *sc, s7_pointer args)
52995 {
52996 #if WITH_HISTORY
52997   #define H_owlet "(owlet) returns the environment at the point of the last error. \
52998 It has the additional local variables: error-type, error-data, error-code, error-line, error-file, and error-history."
52999 #else
53000   #define H_owlet "(owlet) returns the environment at the point of the last error. \
53001 It has the additional local variables: error-type, error-data, error-code, error-line, and error-file."
53002 #endif
53003   #define Q_owlet s7_make_signature(sc, 1, sc->is_let_symbol)
53004   /* if owlet is not copied, (define e (owlet)), e changes as owlet does! */
53005 
53006   s7_pointer e, x;
53007   s7_int gc_loc;
53008 
53009 #if WITH_HISTORY
53010   slot_set_value(sc->error_history, cull_history(sc, slot_value(sc->error_history)));
53011 #endif
53012 
53013   e = let_copy(sc, sc->owlet);
53014   gc_loc = s7_gc_protect_1(sc, e);
53015 
53016   /* make sure the pairs/reals/strings/integers are copied: should be error-data, error-code, and error-history */
53017   sc->gc_off = true;
53018 
53019   for (x = let_slots(e); tis_slot(x); x = next_slot(x))
53020     if (is_pair(slot_value(x)))
53021       {
53022 	s7_pointer new_list, p, sp;
53023 	new_list = copy_any_list(sc, slot_value(x));
53024 	slot_set_value(x, new_list);
53025 	for (p = new_list, sp = p; is_pair(p); p = cdr(p), sp = cdr(sp))
53026 	  {
53027 	    s7_pointer val;
53028 	    val = car(p);
53029 	    if (is_t_real(val))
53030 	      set_car(p, make_real(sc, real(val)));
53031 	    else
53032 	      {
53033 		if (is_string(val))
53034 		  set_car(p, make_string_with_length(sc, string_value(val), string_length(val)));
53035 		else
53036 		  if (is_t_integer(val))
53037 		    set_car(p, make_integer(sc, integer(val)));
53038 	      }
53039 	    p = cdr(p);
53040 	    if ((!is_pair(p)) || (p == sp)) break;
53041 	    val = car(p);
53042 	    if (is_t_real(val))
53043 	      set_car(p, make_real(sc, real(val)));
53044 	    else
53045 	      if (is_string(val))
53046 		set_car(p, make_string_with_length(sc, string_value(val), string_length(val)));
53047 	  }}
53048   sc->gc_off = false;
53049   s7_gc_unprotect_at(sc, gc_loc);
53050   return(e);
53051 }
53052 
53053 static s7_pointer active_catches(s7_scheme *sc)
53054 {
53055   int64_t i;
53056   s7_pointer x, lst;
53057   lst = sc->nil;
53058   for (i = current_stack_top(sc) - 1; i >= 3; i -= 4)
53059     switch (stack_op(sc->stack, i))
53060       {
53061       case OP_CATCH_ALL:
53062 	lst = cons(sc, sc->T, lst);
53063 	break;
53064 
53065       case OP_CATCH_2: case OP_CATCH_1: case OP_CATCH:
53066 	x = stack_code(sc->stack, i);
53067 	lst = cons(sc, catch_tag(x), lst);
53068 	break;
53069       }
53070   return(reverse_in_place_unchecked(sc, sc->nil, lst));
53071 }
53072 
53073 static s7_pointer stack_entries(s7_scheme *sc, s7_pointer stack, int64_t top)
53074 {
53075   int64_t i;
53076   s7_pointer lst;
53077   lst = sc->nil;
53078   for (i = top - 1; i >= 3; i -= 4)
53079     {
53080       s7_pointer func, args, e;
53081       opcode_t op;
53082       func = stack_code(stack, i);
53083       args = stack_args(stack, i);
53084       e = stack_let(stack, i);
53085       op = stack_op(stack, i);
53086       if ((s7_is_valid(sc, func)) &&
53087 	  (s7_is_valid(sc, args)) &&
53088 	  (s7_is_valid(sc, e)) &&
53089 	  (op < NUM_OPS))
53090 	{
53091 #if S7_DEBUGGING
53092 	  if (op < NUM_OPS)
53093 	    lst = cons(sc, list_4(sc, func, args, e, s7_make_string_wrapper(sc, op_names[op])), lst);
53094 	  else lst = cons(sc, list_4(sc, func, args, e, make_integer(sc, op)), lst);
53095 #else
53096 	  lst = cons(sc, list_4(sc, func, args, e, make_integer(sc, op)), lst);
53097 #endif
53098 	  sc->w = lst;
53099 	}}
53100   return(reverse_in_place_unchecked(sc, sc->nil, lst));
53101 }
53102 
53103 
53104 /* catch handlers */
53105 /* here and below, don't free the catcher */
53106 
53107 static bool catch_all_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53108 {
53109   s7_pointer catcher;
53110   catcher = stack_let(sc->stack, i);
53111   sc->value = opt2_con(stack_code(sc->stack, i));
53112   sc->op_stack_now = (s7_pointer *)(sc->op_stack + catch_all_op_loc(catcher));
53113   sc->stack_end = (s7_pointer *)(sc->stack_start + catch_all_goto_loc(catcher));
53114   pop_stack(sc);
53115   if (is_pair(sc->value))
53116     sc->value = (car(sc->value) == sc->quote_symbol) ? cadr(sc->value) : type;
53117   else
53118     if (is_symbol(sc->value))
53119       sc->value = type;
53120   return(true);
53121 }
53122 
53123 static bool catch_2_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53124 {
53125   /* this is the macro-error-handler case from g_catch
53126    *    (let () (define-macro (m . args) (apply (car args) (cadr args))) (catch #t (lambda () (error abs -1)) m))
53127    */
53128   s7_pointer x;
53129   x = stack_code(sc->stack, i);
53130   if ((catch_tag(x) == sc->T) ||
53131       (catch_tag(x) == type) ||
53132       (type == sc->T))
53133     {
53134       int64_t loc;
53135       loc = catch_goto_loc(x);
53136       sc->op_stack_now = (s7_pointer *)(sc->op_stack + catch_op_loc(x));
53137       sc->stack_end = (s7_pointer *)(sc->stack_start + loc);
53138       sc->code = catch_handler(x);
53139 
53140       if (needs_copied_args(sc->code))
53141 	sc->args = list_2(sc, type, info);
53142       else           /* very unlikely: need c_macro as error catcher: (catch #t (lambda () (error 'oops)) require) */
53143 	{
53144 	  set_car(sc->t2_1, type);
53145 	  set_car(sc->t2_2, info);
53146 	  sc->args = sc->t2_1;
53147 	}
53148       sc->cur_op = OP_APPLY;
53149       return(true);
53150     }
53151   return(false);
53152 }
53153 
53154 static bool catch_1_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53155 {
53156   s7_pointer x;
53157   x = stack_code(sc->stack, i);
53158   if ((catch_tag(x) == sc->T) ||
53159       (catch_tag(x) == type) ||
53160       (type == sc->T))
53161     {
53162       uint64_t loc;
53163       opcode_t op;
53164       s7_pointer catcher, error_func, error_body, error_args;
53165 
53166       op = stack_op(sc->stack, i);
53167       sc->temp4 = stack_let(sc->stack, i); /* GC protect this, since we're moving the stack top below */
53168       catcher = x;
53169       loc = catch_goto_loc(catcher);
53170       sc->op_stack_now = (s7_pointer *)(sc->op_stack + catch_op_loc(catcher));
53171       sc->stack_end = (s7_pointer *)(sc->stack_start + loc);
53172       error_func = catch_handler(catcher);
53173 
53174       /* very often the error handler just returns either a constant ('error or #f), or
53175        *   the args passed to it, so there's no need to laboriously make a closure,
53176        *   and apply it -- just set sc->value to the closure body (or the args) and return.
53177        * so first examine closure_body(error_func)
53178        *   if it is a constant, or quoted symbol, return that,
53179        *   if it is the args symbol, return (list type info)
53180        */
53181 
53182       /* if OP_CATCH_1, we deferred making the error handler until it is actually needed */
53183       if (op == OP_CATCH_1)
53184 	{
53185 	  error_body = cdr(error_func);
53186 	  error_args = car(error_func);
53187 	}
53188       else
53189 	{
53190 	  if (is_closure(error_func))
53191 	    {
53192 	      error_body = closure_body(error_func);
53193 	      error_args = closure_args(error_func);
53194 	    }
53195 	  else
53196 	    {
53197 	      error_body = NULL;
53198 	      error_args = NULL;
53199 	    }}
53200 
53201       if ((error_body) && (is_null(cdr(error_body))))
53202 	{
53203 	  s7_pointer y = NULL;
53204 	  error_body = car(error_body);
53205 	  if (is_pair(error_body))
53206 	    {
53207 	      if (car(error_body) == sc->quote_symbol)
53208 		y = cadr(error_body);
53209 	      else
53210 		if ((car(error_body) == sc->car_symbol) &&
53211 		    (cadr(error_body) == error_args))
53212 		  y = type;
53213 	    }
53214 	  else
53215 	    {
53216 	      if (is_symbol(error_body))
53217 		{
53218 		  if (error_body == error_args)
53219 		    y = list_2(sc, type, info);
53220 		  else
53221 		    {
53222 		      if (is_keyword(error_body))
53223 			y = error_body;
53224 		      else
53225 			if ((is_pair(error_args)) &&
53226 			    (error_body == car(error_args)))
53227 			  y = type;
53228 		    }}
53229 	      else y = error_body; /* not pair or symbol */
53230 	    }
53231 	  if (y)
53232 	    {
53233 	      if (loc > 4)
53234 		pop_stack(sc);
53235 	      /* we're at OP_CATCH, normally we want to pop that away, but (handwaving...) if we're coming
53236 	       *   from s7_eval (indirectly perhaps through s7_eval_c_string), we might push the OP_EVAL_DONE
53237 	       *   to end that call, but it's pushed at the precatch stack end (far beyond the catch loc).
53238 	       *   If we catch an error, catch unwinds to its starting point, and the pop_stack above
53239 	       *   puts us at the bottom of the stack (i.e. stack_end == stack_start), OP_EVAL_DONE.
53240 	       *   Now we return true, ending up back in eval, because the error handler jumped out of eval,
53241 	       *   back to wherever we were in eval when we hit the error.  eval jumps back to the start
53242 	       *   of its loop, and pops the stack to see what to do next!  So the (loc > 4) at least
53243 	       *   protects against stack underflow, but ideally we'd know we came from OP_CATCH+s7_eval.
53244 	       *   We can't do anything fancy here because we have to unwind the C stack as well as s7's stack.
53245 	       *   s7_eval doesn't know anything about the catches on the stack.  We can't look back for
53246 	       *   OP_EVAL_DONE -- segfault in OP_BEGIN.  Hmmmm.  Perhaps catch should not unwind until the
53247 	       *   end?  But we want the error handler to run as a part of the calling expression, and
53248 	       *   in any case the OP_EVAL_DONE is not useful (it marks the end of the no-error case).
53249 	       */
53250 	      sc->value = y;
53251 	      sc->temp4 = sc->nil;
53252 	      if (loc == 4)
53253 		sc->code = cons(sc, sc->value, sc->nil); /* if we end up at op_begin, give it something it can handle */
53254 	      return(true);
53255 	    }}
53256       if (op == OP_CATCH_1)
53257 	{
53258 	  s7_pointer p;
53259 	  new_cell(sc, p, T_CLOSURE | T_COPY_ARGS); /* never a safe_closure, apparently */
53260 	  closure_set_args(p, car(error_func));
53261 	  closure_set_body(p, cdr(error_func));
53262 	  closure_set_setter(p, sc->F);
53263 	  closure_set_arity(p, CLOSURE_ARITY_NOT_SET);
53264 	  closure_set_let(p, sc->temp4);
53265 	  sc->code = p;
53266 	}
53267       else sc->code = error_func;
53268       sc->temp4 = sc->nil;
53269 
53270       /* if user (i.e. yers truly!) copies/pastes the preceding lambda () into the
53271        *   error handler portion of the catch, he gets the inexplicable message:
53272        *       ;(): too many arguments: (a1 ())
53273        *   when this apply tries to call the handler.  So, we need a special case error check here!
53274        */
53275 
53276       if (!s7_is_aritable(sc, sc->code, 2))
53277 	s7_wrong_number_of_args_error(sc, "catch error handler should accept 2 args: ~S", sc->code);
53278 
53279       sc->args = list_2(sc, type, info); /* almost never able to skip this -- costs more to check! */
53280       sc->cur_op = OP_APPLY;
53281       /* explicit eval needed if s7_call called into scheme where a caught error occurred (ex6 in exs7.c)
53282        *  but putting it here (via eval(sc, OP_APPLY)) means the C stack is not cleared correctly in non-s7-call cases,
53283        *  so defer it until s7_call
53284        */
53285       return(true);
53286     }
53287   return(false);
53288 }
53289 
53290 static bool catch_dynamic_wind_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53291 {
53292   s7_pointer x;
53293   x = stack_code(sc->stack, i);
53294   if (dynamic_wind_state(x) == DWIND_BODY)
53295     {
53296       dynamic_wind_state(x) = DWIND_FINISH;    /* make sure an uncaught error in the exit thunk doesn't cause us to loop */
53297       if (dynamic_wind_out(x) != sc->F)
53298 	{
53299 	  push_stack_direct(sc, OP_EVAL_DONE);
53300 	  sc->code = dynamic_wind_out(x);
53301 	  sc->args = sc->nil;
53302 	  eval(sc, OP_APPLY);                  /* I guess this means no call/cc out of the exit thunk in an error-catching context */
53303 	}}
53304   return(false);
53305 }
53306 
53307 static bool catch_out_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53308 {
53309   s7_pointer x;
53310   x = stack_code(sc->stack, i);                /* "code" = port that we opened */
53311   s7_close_output_port(sc, x);
53312   x = stack_args(sc->stack, i);                /* "args" = port that we shadowed, if not #<unused> */
53313   if (x != sc->unused)
53314     set_current_output_port(sc, x);
53315   return(false);
53316 }
53317 
53318 static bool catch_in_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53319 {
53320   s7_close_input_port(sc, stack_code(sc->stack, i));            /* "code" = port that we opened */
53321   if (stack_args(sc->stack, i) != sc->unused)
53322     set_current_input_port(sc, stack_args(sc->stack, i));       /* "args" = port that we shadowed */
53323   return(false);
53324 }
53325 
53326 static bool catch_read_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53327 {
53328   pop_input_port(sc);
53329   return(false);
53330 }
53331 
53332 static bool catch_eval_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53333 {
53334   s7_close_input_port(sc, current_input_port(sc));
53335   pop_input_port(sc);
53336   return(false);
53337 }
53338 
53339 static bool catch_barrier_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53340 {
53341   if (is_input_port(stack_args(sc->stack, i)))      /* (eval-string "'(1 .)") */
53342     {
53343       if (current_input_port(sc) == stack_args(sc->stack, i))
53344 	pop_input_port(sc);
53345       s7_close_input_port(sc, stack_args(sc->stack, i));
53346     }
53347   return(false);
53348 }
53349 
53350 static bool catch_hook_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53351 {
53352   sc->error_hook = stack_code(sc->stack, i);
53353   /* apparently there was an error during *error-hook* evaluation, but Rick wants the hook re-established anyway */
53354   (*reset_hook) = true;
53355   /* avoid infinite loop -- don't try to (re-)evaluate (buggy) *error-hook*! */
53356   return(false);
53357 }
53358 
53359 static bool catch_goto_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53360 {
53361   call_exit_active(stack_args(sc->stack, i)) = false;
53362   return(false);
53363 }
53364 
53365 static bool catch_let_temporarily_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53366 {
53367   let_temp_done(sc, stack_args(sc->stack, i), stack_code(sc->stack, i), stack_let(sc->stack, i));
53368   return(false);
53369 }
53370 
53371 static bool catch_let_temp_unwind_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53372 {
53373   slot_set_value(stack_code(sc->stack, i), stack_args(sc->stack, i));
53374   return(false);
53375 }
53376 
53377 static bool catch_let_temp_s7_unwind_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53378 {
53379   g_s7_let_set_fallback(sc, set_plist_3(sc, sc->s7_let, stack_code(sc->stack, i), stack_args(sc->stack, i)));
53380   return(false);
53381 }
53382 
53383 static bool catch_dynamic_unwind_function(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook)
53384 {
53385   /* if func has an error, s7_error will call it as it unwinds the stack -- an infinite loop. So, cancel the unwind first. */
53386   stack_element(sc->stack, i) = (s7_pointer)OP_GC_PROTECT;
53387 
53388   /* we're in an error or throw, so there is no return value to report, but we need to decrement *debug-spaces* (if in debug)
53389    *    stack_let is the trace-in let at the point of the dynamic_unwind call
53390    */
53391   if (sc->debug > 0)
53392     {
53393       s7_pointer spaces;
53394       spaces = lookup_slot_from(make_symbol(sc, "*debug-spaces*"), stack_let(sc->stack, i));
53395       if (is_slot(spaces))
53396 	slot_set_value(spaces, make_integer(sc, max_i_ii(0LL, integer(slot_value(spaces)) - 2))); /* should involve only small_ints */
53397     }
53398   return(false);
53399 }
53400 
53401 typedef bool (*catch_function_t)(s7_scheme *sc, s7_int i, s7_pointer type, s7_pointer info, bool *reset_hook);
53402 static catch_function_t catchers[NUM_OPS];
53403 
53404 static void init_catchers(void)
53405 {
53406   int32_t i;
53407   for (i = 0; i < NUM_OPS; i++) catchers[i] = NULL;
53408   catchers[OP_CATCH_ALL] =          catch_all_function;
53409   catchers[OP_CATCH_2] =            catch_2_function;
53410   catchers[OP_CATCH_1] =            catch_1_function;
53411   catchers[OP_CATCH] =              catch_1_function;
53412   catchers[OP_DYNAMIC_WIND] =       catch_dynamic_wind_function;
53413   catchers[OP_DYNAMIC_UNWIND] =     catch_dynamic_unwind_function;
53414   catchers[OP_GET_OUTPUT_STRING] =  catch_out_function;
53415   catchers[OP_UNWIND_OUTPUT] =      catch_out_function;
53416   catchers[OP_UNWIND_INPUT] =       catch_in_function;
53417   catchers[OP_READ_DONE] =          catch_read_function;      /* perhaps an error during (read) */
53418   catchers[OP_EVAL_STRING] =        catch_eval_function;
53419   catchers[OP_BARRIER] =            catch_barrier_function;
53420   catchers[OP_DEACTIVATE_GOTO] =    catch_goto_function;
53421   catchers[OP_LET_TEMP_DONE] =      catch_let_temporarily_function;
53422   catchers[OP_LET_TEMP_UNWIND] =    catch_let_temp_unwind_function;
53423   catchers[OP_LET_TEMP_S7_UNWIND] = catch_let_temp_s7_unwind_function;
53424   catchers[OP_ERROR_HOOK_QUIT] =    catch_hook_function;
53425 }
53426 
53427 /* -------------------------------- throw -------------------------------- */
53428 static s7_pointer g_throw(s7_scheme *sc, s7_pointer args)
53429 {
53430   #define H_throw "(throw tag . info) is like (error ...) but it does not affect the owlet. \
53431 It looks for an existing catch with a matching tag, and jumps to it if found.  Otherwise it raises an error."
53432   #define Q_throw s7_make_circular_signature(sc, 1, 2, sc->values_symbol, sc->T)
53433 
53434   bool ignored_flag = false;
53435   int64_t i;
53436   s7_pointer type, info;
53437 
53438   type = car(args);
53439   info = cdr(args);
53440 
53441   /* look for a catcher */
53442   for (i = current_stack_top(sc) - 1; i >= 3; i -= 4)
53443     {
53444       catch_function_t catcher;
53445       catcher = catchers[stack_op(sc->stack, i)];
53446       if ((catcher) &&
53447 	  (catcher(sc, i, type, info, &ignored_flag)))
53448 	{
53449 	  if (sc->longjmp_ok) Longjmp(sc->goto_start, THROW_JUMP);
53450 	  return(sc->value);
53451 	}}
53452   if (is_let(car(args)))
53453     check_method(sc, car(args), sc->throw_symbol, args);
53454   return(s7_error(sc, make_symbol(sc, "uncaught-throw"),
53455 		  set_elist_3(sc, wrap_string(sc, "no catch found for (throw ~W~{~^ ~S~})", 38), type, info)));
53456 }
53457 
53458 static void s7_warn(s7_scheme *sc, s7_int len, const char *ctrl, ...) /* len = max size of output string (for vsnprintf) */
53459 {
53460   if (sc->error_port != sc->F)
53461     {
53462       va_list ap;
53463       s7_pointer warning;
53464       char *str;
53465 
53466       warning = make_empty_string(sc, len, 0);
53467       string_value(warning)[0] = '\0';
53468       str = (char *)string_value(warning);
53469       va_start(ap, ctrl);
53470       vsnprintf(str, len, ctrl, ap);
53471       va_end(ap);
53472 
53473       if (port_is_closed(sc->error_port))
53474 	sc->error_port = sc->standard_error;
53475       s7_display(sc, warning, sc->error_port);
53476     }
53477 }
53478 
53479 static void fill_error_location(s7_scheme *sc)
53480 {
53481   if (((is_input_port(current_input_port(sc))) && (is_loader_port(current_input_port(sc)))) ||
53482       (((sc->cur_op >= OP_READ_LIST) && (sc->cur_op <= OP_READ_DONE))))
53483     {
53484       integer(slot_value(sc->error_line)) = port_line_number(current_input_port(sc));
53485       integer(slot_value(sc->error_position)) = port_position(current_input_port(sc));
53486       slot_set_value(sc->error_file, wrap_string(sc, port_filename(current_input_port(sc)), port_filename_length(current_input_port(sc))));
53487     }
53488   else
53489     {
53490       integer(slot_value(sc->error_line)) = 0;
53491       integer(slot_value(sc->error_position)) = 0;
53492       slot_set_value(sc->error_file, sc->F);
53493     }
53494 }
53495 
53496 s7_pointer s7_error(s7_scheme *sc, s7_pointer type, s7_pointer info)
53497 {
53498   bool reset_error_hook = false;
53499   s7_pointer cur_code;
53500 
53501   /* type is a symbol normally, and info is compatible with format: (apply format #f info) --
53502    *    car(info) is the control string, cdr(info) its args
53503    *    type/range errors have cadr(info)=caller, caddr(info)=offending arg number
53504    *    null info can mean symbol table is locked so make-symbol uses s7_error to get out
53505    *
53506    * set up (owlet), look for a catch that matches 'type', if found
53507    *   call its error-handler, else if *error-hook* is bound, call it,
53508    *   else send out the error info ourselves.
53509    */
53510 
53511   sc->format_depth = -1;
53512   sc->gc_off = false;             /* this is in case we were triggered from the sort function -- clumsy! */
53513   sc->object_out_locked = false;  /* possible error in obj->str method after object_out has set this flag */
53514   sc->has_openlets = true;        /*   same problem -- we need a cleaner way to handle this */
53515 
53516   if (sc->current_safe_list > 0)
53517     clear_list_in_use(sc->safe_lists[sc->current_safe_list]);
53518   slot_set_value(sc->error_type, type);
53519   slot_set_value(sc->error_data, info);
53520 
53521   if ((unchecked_type(sc->curlet) != T_LET) &&
53522       (sc->curlet != sc->nil))
53523     sc->curlet = sc->nil;          /* in the reader, the sc->curlet stack entry is mostly ignored, so it can be (and usually is) garbage */
53524   let_set_outlet(sc->owlet, sc->curlet);
53525 
53526   cur_code = current_code(sc);
53527   slot_set_value(sc->error_code, cur_code);
53528 
53529 #if WITH_HISTORY
53530   slot_set_value(sc->error_history, sc->cur_code);
53531   if (sc->cur_code != sc->history_sink)
53532     {
53533       sc->cur_code = (sc->using_history1) ? sc->eval_history2 : sc->eval_history1;
53534       sc->using_history1 = (!sc->using_history1);
53535       pair_fill(sc, set_plist_2(sc, sc->cur_code, sc->nil));
53536     }
53537 #endif
53538 
53539   if (is_pair(cur_code))
53540     {
53541       int32_t line = -1, file, position;
53542       if (has_location(cur_code))
53543 	{
53544 	  line = (int32_t)pair_line_number(cur_code); /* cast to int32_t (from uint32_t) for sc->last_error_line */
53545 	  file = (int32_t)pair_file_number(cur_code);
53546 	  position = (int32_t)pair_position(cur_code);
53547 	}
53548       else
53549 	{
53550 	  /* try to find a plausible line number! */
53551 	  s7_pointer p, sp;
53552 	  for (p = cur_code, sp = cur_code; is_pair(p); p = cdr(p), sp = cdr(sp))
53553 	    {
53554 	      if ((is_pair(car(p))) &&
53555 		  (has_location(car(p))))
53556 		{
53557 		  line = (int32_t)pair_line_number(car(p));
53558 		  file = (int32_t)pair_file_number(car(p));
53559 		  position = (int32_t)pair_position(car(p));
53560 		  break;
53561 		}
53562 	      p = cdr(p);
53563 	      if ((!is_pair(p)) || (p == sp)) break;
53564 	      if ((is_pair(car(p))) &&
53565 		  (has_location(car(p))))
53566 		{
53567 		  line = (int32_t)pair_line_number(car(p));
53568 		  file = (int32_t)pair_file_number(car(p));
53569 		  position = (int32_t)pair_position(car(p));
53570 		  break;
53571 		}}}
53572 
53573       if ((line > 0) &&
53574 	  (line != sc->last_error_line))
53575 	{
53576 	  sc->last_error_line = line;
53577 	  if (file >= 0)
53578 	    {
53579 	      integer(slot_value(sc->error_line)) = line;
53580 	      integer(slot_value(sc->error_position)) = position;
53581 	      slot_set_value(sc->error_file, sc->file_names[file]);
53582 	    }
53583 	  else fill_error_location(sc);
53584 	}
53585       else fill_error_location(sc);
53586     }
53587   else fill_error_location(sc);
53588 
53589   { /* look for a catcher, call catch*function in the error context (before unwinding the stack), outlet(owlet) is curlet */
53590     int64_t i;
53591     /* top is 1 past actual top, top - 1 is op, if op = OP_CATCH, top - 4 is the cell containing the catch struct */
53592     for (i = current_stack_top(sc) - 1; i >= 3; i -= 4)
53593       {
53594 	catch_function_t catcher;
53595 	catcher = catchers[stack_op(sc->stack, i)];
53596 	if ((catcher) &&
53597 	    (catcher(sc, i, type, info, &reset_error_hook)))
53598 	  {
53599 	    if (sc->longjmp_ok) Longjmp(sc->goto_start, CATCH_JUMP);
53600 	    /* all the rest of the code expects s7_error to jump, not return, so presumably if we get here, we're in trouble */
53601 #if S7_DEBUGGING
53602 	    fprintf(stderr, "fall through in s7_error!\n");
53603 #endif
53604 	  }}}
53605   /* error not caught */
53606   /* (set! *error-hook* (list (lambda (hook) (apply format #t (hook 'args))))) */
53607 
53608   if ((!reset_error_hook) &&
53609       (is_procedure(sc->error_hook)) &&
53610       (hook_has_functions(sc->error_hook)))
53611     {
53612       s7_pointer error_hook_func;
53613       /* (set! (hook-functions *error-hook*) (list (lambda (h) (format *stderr* "got error ~A~%" (h 'args))))) */
53614 
53615       error_hook_func = sc->error_hook;
53616       sc->error_hook = sc->nil;
53617       /* if the *error-hook* functions trigger an error, we had better not have *error-hook* still set! */
53618 
53619       push_stack(sc, OP_ERROR_HOOK_QUIT, sc->nil, error_hook_func); /* restore *error-hook* upon successful (or any!) evaluation */
53620       sc->code = error_hook_func;
53621       sc->args = list_2(sc, type, info);
53622 
53623       /* if we drop into the longjmp below, the hook functions are not called!
53624        *   OP_ERROR_HOOK_QUIT performs the longjmp, so it should be safe to go to eval.
53625        */
53626       eval(sc, OP_APPLY);
53627     }
53628   else
53629     {
53630       s7_int op;
53631       op = sc->print_length;
53632       if (op < 32) sc->print_length = 32;
53633 
53634       if ((!is_output_port(sc->error_port)) || /* error-port can be #f */
53635 	  (port_is_closed(sc->error_port)))
53636 	sc->error_port = sc->standard_error;
53637       /* if info is not a list, send object->string to current error port,
53638        *   else assume car(info) is a format control string, and cdr(info) are its args
53639        * if at all possible, get some indication of where we are!
53640        */
53641 
53642       if ((!is_pair(info)) ||
53643 	  (!is_string(car(info))))
53644 	format_to_port(sc, sc->error_port, "\n;~S ~S", set_plist_2(sc, type, info), false, 7);
53645       else
53646 	{
53647 	  /* it's possible that the error string is just a string -- not intended for format */
53648 	  if ((type != sc->format_error_symbol) &&      /* avoid an infinite loop of format errors */
53649 	      (strchr(string_value(car(info)), '~')))
53650 	    {
53651 	      char *errstr;
53652 	      block_t *b;
53653 	      s7_int len, str_len;
53654 	      len = string_length(car(info)) + 8;
53655 	      b = mallocate(sc, len);
53656 	      errstr = (char *)block_data(b);
53657 	      str_len = catstrs_direct(errstr, "\n;", string_value(car(info)), (const char *)NULL);
53658 	      format_to_port(sc, sc->error_port, errstr, cdr(info), false, str_len);
53659 	      liberate(sc, b);
53660 	    }
53661 	  else format_to_port(sc, sc->error_port, "\n;~S ~S", set_plist_2(sc, type, info), false, 7); /* 7 = ctrl str len */
53662 	}
53663       if (op < 32) sc->print_length = op;
53664 
53665       /* now display location at end */
53666 
53667       if (is_string(slot_value(sc->error_file)))
53668 	{
53669 	  s7_newline(sc, sc->error_port);
53670 	  format_to_port(sc, sc->error_port, ";    ~A\n",
53671 			 set_plist_1(sc, object_to_truncated_string(sc, cur_code, 40)),
53672 			 false, 8);
53673 	  format_to_port(sc, sc->error_port, ";    ~A, line ~D, position: ~D\n",
53674 			 set_plist_3(sc, slot_value(sc->error_file), slot_value(sc->error_line), slot_value(sc->error_position)),
53675 			 false, 31);
53676 	}
53677       else
53678 	{
53679 	  if ((is_input_port(current_input_port(sc))) &&
53680 	      (port_file(current_input_port(sc)) != stdin) &&
53681 	      (!port_is_closed(current_input_port(sc))))
53682 	    {
53683 	      const char *filename;
53684 	      int32_t line;
53685 
53686 	      filename = port_filename(current_input_port(sc));
53687 	      line = port_line_number(current_input_port(sc));
53688 
53689 	      if (filename)
53690 		format_to_port(sc, sc->error_port, "\n;  ~A[~D]",
53691 			       set_plist_2(sc, wrap_string(sc, filename, port_filename_length(current_input_port(sc))),
53692 					   wrap_integer3(sc, line)), false, 10);
53693 	      else
53694 		{
53695 		  if ((line > 0) &&
53696 		      (integer(slot_value(sc->error_line)) > 0))
53697 		    format_to_port(sc, sc->error_port, "\n;  line ~D", set_plist_1(sc, wrap_integer3(sc, line)), false, 11);
53698 		  else
53699 		    if (sc->input_port_stack_loc > 0)
53700 		      {
53701 			s7_pointer p;
53702 			p = sc->input_port_stack[sc->input_port_stack_loc - 1];
53703 			if ((is_input_port(p)) &&
53704 			    (port_file(p) != stdin) &&
53705 			    (!port_is_closed(p)))
53706 			  {
53707 			    filename = port_filename(p);
53708 			    line = port_line_number(p);
53709 			    if (filename)
53710 			      format_to_port(sc, sc->error_port, "\n;  ~A[~D]",
53711 					     set_plist_2(sc, wrap_string(sc, filename, port_filename_length(current_input_port(sc))),
53712 							 wrap_integer3(sc, line)), false, 10);
53713 			  }}}}
53714 	  else
53715 	    {
53716 	      const char *call_name;
53717 	      call_name = sc->s7_call_name;
53718 	      if (call_name)
53719 		{
53720 		  sc->s7_call_name = NULL;
53721 		  if ((sc->s7_call_file) &&
53722 		      (sc->s7_call_line >= 0))
53723 		    format_to_port(sc, sc->error_port, "\n;  ~A ~A[~D]",
53724 				   set_plist_3(sc,
53725 					       s7_make_string_wrapper(sc, call_name),
53726 					       s7_make_string_wrapper(sc, sc->s7_call_file),
53727 					       make_integer(sc, sc->s7_call_line)),
53728 				   false, 13);
53729 		}}
53730 	  s7_newline(sc, sc->error_port);
53731 	}
53732 
53733       /* look for __func__ in the error environment etc */
53734       if (sc->error_port != sc->F)
53735 	{
53736 	  s7_pointer errp;
53737 	  errp = stacktrace_1(sc,
53738 			      s7_integer_checked(sc, car(sc->stacktrace_defaults)),
53739 			      s7_integer_checked(sc, cadr(sc->stacktrace_defaults)),
53740 			      s7_integer_checked(sc, caddr(sc->stacktrace_defaults)),
53741 			      s7_integer_checked(sc, cadddr(sc->stacktrace_defaults)),
53742 			      s7_boolean(sc, s7_list_ref(sc, sc->stacktrace_defaults, 4)));
53743 	  if (string_length(errp) > 0)
53744 	    {
53745 	      port_write_string(sc->error_port)(sc, string_value(errp), string_length(errp), sc->error_port);
53746 	      port_write_character(sc->error_port)(sc, '\n', sc->error_port);
53747 	    }}
53748       else
53749 	{
53750 	  if (is_pair(slot_value(sc->error_code)))
53751 	    {
53752 	      format_to_port(sc, sc->error_port, ";    ~S", set_plist_1(sc, slot_value(sc->error_code)), false, 7);
53753 	      s7_newline(sc, sc->error_port);
53754 	    }}
53755 
53756       /* if (is_continuation(type))
53757        *   go into repl here with access to continuation?  Or expect *error-handler* to deal with it?
53758        */
53759       sc->value = type;
53760       sc->cur_op = OP_ERROR_QUIT;
53761     }
53762 
53763   if (sc->longjmp_ok) Longjmp(sc->goto_start, ERROR_JUMP);
53764   return(type);
53765 }
53766 
53767 static s7_pointer apply_error(s7_scheme *sc, s7_pointer obj, s7_pointer args)
53768 {
53769   /* the operator type is needed here else the error message is confusing:
53770    *    (apply '+ (list 1 2))) -> ;attempt to apply + to (1 2)?
53771    */
53772   if (is_null(obj))
53773     return(s7_error(sc, sc->syntax_error_symbol,
53774 		    set_elist_3(sc, wrap_string(sc, "attempt to apply nil to ~S in ~S?", 33),
53775 				args, current_code(sc))));
53776   return(s7_error(sc, sc->syntax_error_symbol,
53777 		  set_elist_5(sc, wrap_string(sc, "attempt to apply ~A ~S to ~S in ~S?", 35),
53778 			      type_name_string(sc, obj), obj, args, current_code(sc))));
53779 }
53780 
53781 static s7_pointer read_error_1(s7_scheme *sc, const char *errmsg, bool string_error)
53782 {
53783   /* reader errors happen before the evaluator gets involved, so forms such as:
53784    *   (catch #t (lambda () (car '( . ))) (lambda arg 'error))
53785    * do not catch the error if we simply signal an error when we encounter it.
53786    */
53787   char *msg;
53788   s7_int len;
53789   s7_pointer pt;
53790 
53791   pt = current_input_port(sc);
53792   if (!string_error)
53793     {
53794       /* make an heroic effort to find where we slid off the tracks */
53795 
53796       if (is_string_port(current_input_port(sc)))
53797 	{
53798           #define QUOTE_SIZE 40
53799 	  s7_int i, j, start = 0, end, slen, size, nlen;
53800 	  char *recent_input = NULL;
53801 	  s7_pointer p;
53802 
53803 	  /* we can run off the end in cases like (eval-string "(. . ,.)") or (eval-string " (@ . ,.)") */
53804 	  if (port_position(pt) >= port_data_size(pt))
53805 	    port_position(pt) = port_data_size(pt) - 1;
53806 
53807 	  /* start at current position and look back a few chars */
53808 	  for (i = port_position(pt), j = 0; (i > 0) && (j < QUOTE_SIZE); i--, j++)
53809 	    if ((port_data(pt)[i] == '\0') ||
53810 		(port_data(pt)[i] == '\n') ||
53811 		(port_data(pt)[i] == '\r'))
53812 	      break;
53813 	  start = i;
53814 
53815 	  /* start at current position and look ahead a few chars */
53816 	  size = port_data_size(pt);
53817 	  for (i = port_position(pt), j = 0; (i < size) && (j < QUOTE_SIZE); i++, j++)
53818 	    if ((port_data(pt)[i] == '\0') ||
53819 		(port_data(pt)[i] == '\n') ||
53820 		(port_data(pt)[i] == '\r'))
53821 	      break;
53822 
53823 	  end = i;
53824 	  slen = end - start;
53825 	  /* hopefully this is more or less the current line where the read error happened */
53826 
53827 	  if (slen > 0)
53828 	    {
53829 	      recent_input = (char *)Calloc(slen + 9, 1);
53830 	      for (i = 0; i < (slen + 8); i++) recent_input[i] = '.';
53831 	      recent_input[3] = ' ';
53832 	      recent_input[slen + 4] = ' ';
53833 	      for (i = 0; i < slen; i++) recent_input[i + 4] = port_data(pt)[start + i];
53834 	    }
53835 
53836 	  nlen = 0;
53837 	  if ((port_line_number(pt) > 0) &&
53838 	      (port_filename(pt)))
53839 	    {
53840 	      len = safe_strlen(recent_input) + safe_strlen(errmsg) + port_filename_length(pt) + safe_strlen(sc->current_file) + 64;
53841 	      p = make_empty_string(sc, len, '\0');
53842 	      msg = string_value(p);
53843 	      nlen = snprintf(msg, len, "%s: %s %s[%u], last top-level form at: %s[%" print_s7_int "]",
53844 			     errmsg, (recent_input) ? recent_input : "", port_filename(pt), port_line_number(pt),
53845 			     sc->current_file, sc->current_line);
53846 	    }
53847 	  else
53848 	    {
53849 	      len = safe_strlen(recent_input) + safe_strlen(errmsg) + safe_strlen(sc->current_file) + 64;
53850 	      p = make_empty_string(sc, len, '\0');
53851 	      msg = string_value(p);
53852 	      if ((sc->current_file) &&
53853 		  (sc->current_line >= 0))
53854 		nlen = snprintf(msg, len, "%s: %s, last top-level form at %s[%" print_s7_int "]",
53855 			       errmsg, (recent_input) ? recent_input : "",
53856 			       sc->current_file, sc->current_line);
53857 	      else nlen = snprintf(msg, len, "%s: %s", errmsg, (recent_input) ? recent_input : "");
53858 	    }
53859 	  string_length(p) = nlen;
53860 	  if (recent_input) free(recent_input);
53861 	  return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, p)));
53862 	}}
53863 
53864   if ((port_line_number(pt) > 0) &&
53865       (port_filename(pt)))
53866     {
53867       s7_pointer p;
53868       s7_int nlen = 0;
53869       len = safe_strlen(errmsg) + port_filename_length(pt) + safe_strlen(sc->current_file) + 128;
53870       p = make_empty_string(sc, len, '\0');
53871       msg = string_value(p);
53872       if (string_error)
53873 	nlen = snprintf(msg, len, "%s %s[%u],\n;  possible culprit: \"%s...\"\n;  last top-level form at %s[%" print_s7_int "]",
53874 		       errmsg, port_filename(pt), port_line_number(pt),
53875 		       sc->strbuf, sc->current_file, sc->current_line);
53876       else nlen = snprintf(msg, len, "%s %s[%u], last top-level form at %s[%" print_s7_int "]",
53877 			  errmsg, port_filename(pt), port_line_number(pt),
53878 			  sc->current_file, sc->current_line);
53879       string_length(p) = nlen;
53880       return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, p)));
53881     }
53882   return(s7_error(sc, (string_error) ? sc->string_read_error_symbol : sc->read_error_symbol, set_elist_1(sc, s7_make_string_wrapper(sc, (char *)errmsg))));
53883 }
53884 
53885 static s7_pointer read_error(s7_scheme *sc, const char *errmsg)
53886 {
53887   return(read_error_1(sc, errmsg, false));
53888 }
53889 
53890 static s7_pointer string_read_error(s7_scheme *sc, const char *errmsg)
53891 {
53892   return(read_error_1(sc, errmsg, true));
53893 }
53894 
53895 static s7_pointer g_error(s7_scheme *sc, s7_pointer args)
53896 {
53897   #define H_error "(error type ...) signals an error.  The 'type' can be used with catch to trap \
53898 particular errors.  If the error is not caught, s7 treats the second argument as a format control string, \
53899 and applies it to the rest of the arguments."
53900   #define Q_error s7_make_circular_signature(sc, 1, 2, sc->values_symbol, sc->T)
53901 
53902   if (is_not_null(args))
53903     {
53904       if (is_string(car(args)))                     /* CL-style error? -- use tag = 'no-catch */
53905 	{
53906 	  s7_error(sc, sc->no_catch_symbol, args);  /* this can have trailing args (implicit format) */
53907 	  return(sc->unspecified);
53908 	}
53909       return(s7_error(sc, car(args), cdr(args)));
53910     }
53911   return(s7_error(sc, sc->nil, sc->nil));
53912 }
53913 
53914 static char *truncate_string(char *form, s7_int len, use_write_t use_write)
53915 {
53916   uint8_t *f;
53917   f = (uint8_t *)form;
53918 
53919   if (use_write != P_DISPLAY)
53920     {
53921       /* I guess we need to protect the outer double quotes in this case */
53922       s7_int i;
53923       for (i = len - 5; i >= (len / 2); i--)
53924 	if (is_white_space((int32_t)f[i]))
53925 	  {
53926 	    form[i] = '.'; form[i + 1] = '.'; form[i + 2] = '.'; form[i + 3] = '"'; form[i + 4] = '\0';
53927 	    return(form);
53928 	  }
53929       i = len - 5;
53930       if (i > 0)
53931 	{
53932 	  form[i] = '.'; form[i + 1] = '.'; form[i + 2] = '.'; form[i + 3] = '"'; form[i + 4] = '\0';
53933 	}
53934       else
53935 	if (len >= 2)
53936 	  {
53937 	    form[len - 1] = '"';
53938 	    form[len] = '\0';
53939 	  }}
53940   else
53941     {
53942       s7_int i;
53943       for (i = len - 4; i >= (len / 2); i--)
53944 	if (is_white_space((int32_t)f[i]))
53945 	  {
53946 	    form[i] = '.'; form[i + 1] = '.'; form[i + 2] = '.'; form[i + 3] = '\0';
53947 	    return(form);
53948 	  }
53949       i = len - 4;
53950       if (i >= 0)
53951 	{
53952 	  form[i] = '.'; form[i + 1] = '.'; form[i + 2] = '.'; form[i + 3] = '\0';
53953 	}
53954       else form[len] = '\0';
53955     }
53956   return(form);
53957 }
53958 
53959 static s7_pointer object_to_truncated_string(s7_scheme *sc, s7_pointer p, s7_int len)
53960 {
53961   char *s;
53962   s7_int s_len;
53963   s7_pointer strp;
53964   sc->objstr_max_len = len + 2;
53965   strp = s7_object_to_string(sc, p, false);
53966   s = string_value(strp);
53967   sc->objstr_max_len = S7_INT64_MAX;
53968   s_len = string_length(strp);
53969   if (s_len > len)
53970     truncate_string(s, len, P_DISPLAY);
53971   return(strp);
53972 }
53973 
53974 static s7_pointer tree_descend(s7_scheme *sc, s7_pointer p, uint32_t line)
53975 {
53976   s7_pointer tp;
53977   if (!is_pair(p)) return(NULL);
53978   if (has_location(p))
53979     {
53980       uint32_t x;
53981       x = (uint32_t)pair_line_number(p);
53982       if (x > 0)
53983 	{
53984 	  if (line == 0) /* first line number we encounter will be the current reader location (i.e. the end of the form) */
53985 	    line = x;
53986 	  else
53987 	    if (x < line)
53988 	      return(p);
53989 	}}
53990   tp = tree_descend(sc, car(p), line);
53991   return((tp) ? tp : tree_descend(sc, cdr(p), line));
53992 }
53993 
53994 static s7_pointer missing_close_paren_error(s7_scheme *sc)
53995 {
53996   s7_int len;
53997   char *msg, *syntax_msg = NULL;
53998   s7_pointer pt;
53999 
54000   if ((unchecked_type(sc->curlet) != T_LET) &&
54001       (sc->curlet != sc->nil))
54002     sc->curlet = sc->nil;
54003 
54004   pt = current_input_port(sc);
54005 
54006   /* check *missing-close-paren-hook* */
54007   if (hook_has_functions(sc->missing_close_paren_hook))
54008     {
54009       s7_pointer result;
54010       if ((port_line_number(pt) > 0) &&
54011 	  (port_filename(pt)))
54012 	{
54013 	  integer(slot_value(sc->error_line)) = port_line_number(pt);
54014 	  integer(slot_value(sc->error_position)) = port_position(pt);
54015 	  slot_set_value(sc->error_file, wrap_string(sc, port_filename(pt), port_filename_length(pt)));
54016 	}
54017       result = s7_call(sc, sc->missing_close_paren_hook, sc->nil);
54018       if (result != sc->unspecified)
54019 	return(g_throw(sc, list_1(sc, result)));
54020     }
54021 
54022   if (is_pair(sc->args))
54023     {
54024       s7_pointer p;
54025       p = tree_descend(sc, sc->args, 0);
54026       if ((p) && (is_pair(p)) &&
54027 	  (has_location(p)))
54028 	{
54029 	  s7_int msg_len, form_len;
54030 	  s7_pointer strp;
54031 	  char *form;
54032 	  strp = object_to_truncated_string(sc, p, 40);
54033 	  form = string_value(strp);
54034 	  form_len = string_length(strp);
54035 	  msg_len = form_len + 128;
54036 	  syntax_msg = (char *)Malloc(msg_len);
54037 	  snprintf(syntax_msg, msg_len, ";  current form awaiting a close paren starts around line %u: %s", (uint32_t)pair_line_number(p), form);
54038 	}}
54039 
54040   if ((port_line_number(pt) > 0) &&
54041       (port_filename(pt)))
54042     {
54043       s7_pointer p;
54044       s7_int nlen;
54045       len = port_filename_length(pt) + safe_strlen(sc->current_file) + safe_strlen(syntax_msg) + 128;
54046       p = make_empty_string(sc, len, '\0');
54047       msg = string_value(p);
54048       if (syntax_msg)
54049 	{
54050 	  nlen = snprintf(msg, len, "missing close paren, %s[%u], last top-level form at %s[%" print_s7_int "]\n%s",
54051 			 port_filename(pt), port_line_number(pt),
54052 			 sc->current_file, sc->current_line, syntax_msg);
54053 	  free(syntax_msg);
54054 	}
54055       else nlen = snprintf(msg, len, "missing close paren, %s[%u], last top-level form at %s[%" print_s7_int "]",
54056 			  port_filename(pt), port_line_number(pt),
54057 			  sc->current_file, sc->current_line);
54058       string_length(p) = nlen;
54059       return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, p)));
54060     }
54061 
54062   if (syntax_msg)
54063     {
54064       s7_pointer p;
54065       len = safe_strlen(syntax_msg) + 128;
54066       p = make_empty_string(sc, len, '\0');
54067       msg = string_value(p);
54068       len = catstrs(msg, len, "missing close paren\n", syntax_msg, "\n", (char *)NULL);
54069       free(syntax_msg);
54070       string_length(p) = len;
54071       return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, p)));
54072     }
54073 
54074   if ((is_input_port(pt)) &&
54075       (!port_is_closed(pt)) &&
54076       (port_data(pt)) &&
54077       (port_position(pt) > 0))
54078     {
54079       s7_pointer p;
54080       s7_int start, pos;
54081 
54082       p = make_empty_string(sc, 128, '\0');
54083       msg = string_value(p);
54084       memcpy((void *)msg, (void *)"missing close paren: ", 21);
54085 
54086       pos = port_position(pt);
54087       start = pos - 40;
54088       if (start < 0) start = 0;
54089       memcpy((void *)(msg + 21), (void *)(port_data(pt) + start), pos - start);
54090       string_length(p) = 21 + pos - start;
54091       return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, p)));
54092     }
54093   return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, wrap_string(sc, "missing close paren", 19))));
54094 }
54095 
54096 static void improper_arglist_error(s7_scheme *sc)
54097 {
54098   /* sc->code is the last (dotted) arg, sc->args is the arglist reversed not including sc->code
54099    *   the original was `(func ,@(reverse args) . ,code) essentially where func is sc->value or pop_op_stack(sc)
54100    */
54101   s7_pointer func;
54102   func = pop_op_stack(sc);
54103   if (sc->args == sc->nil)               /* (abs . 1) */
54104     s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, wrap_string(sc, "attempt to evaluate (~S . ~S)?", 30), func, sc->code));
54105   else s7_error(sc, sc->syntax_error_symbol,
54106 		set_elist_4(sc, wrap_string(sc, "attempt to evaluate (~S ~S . ~S)?", 33),
54107 			    func, sc->args = proper_list_reverse_in_place(sc, sc->args), sc->code));
54108 }
54109 
54110 static void op_error_hook_quit(s7_scheme *sc)
54111 {
54112   sc->error_hook = sc->code;  /* restore old value */
54113   /* now mimic the end of the normal error handler.  Since this error hook evaluation can happen
54114    *   in an arbitrary s7_call nesting, we can't just return from the current evaluation --
54115    *   we have to jump to the original (top-level) call.  Otherwise '#<unspecified> or whatever
54116    *   is simply treated as the (non-error) return value, and the higher level evaluations
54117    *   get confused.
54118    */
54119   stack_reset(sc);                                 /* is this necessary? is it a good idea?? */
54120   push_stack_op(sc, OP_ERROR_QUIT);                /* added 3-Dec-16: try to make sure we actually exit! */
54121   sc->cur_op = OP_ERROR_QUIT;
54122   if (sc->longjmp_ok)
54123     Longjmp(sc->goto_start, ERROR_QUIT_JUMP);
54124 }
54125 
54126 
54127 /* -------------------------------- leftovers -------------------------------- */
54128 
54129 void (*s7_begin_hook(s7_scheme *sc))(s7_scheme *sc, bool *val)
54130 {
54131   return(sc->begin_hook);
54132 }
54133 
54134 void s7_set_begin_hook(s7_scheme *sc, void (*hook)(s7_scheme *sc, bool *val))
54135 {
54136   sc->begin_hook = hook;
54137   sc->begin_op = (hook) ? OP_BEGIN_HOOK : OP_BEGIN_NO_HOOK;
54138 }
54139 
54140 static bool call_begin_hook(s7_scheme *sc)
54141 {
54142   bool result = false;
54143   /* originally begin_hook was bool (*hook)(s7_scheme *sc): the value was returned directly,
54144    *   rather than going through a *bool arg (&result below).  That works in gcc (Linux/OSX),
54145    *   but does not work in MS Visual C++.  In the latter, the compiler apparently completely
54146    *   eliminates any local, returning (for example) a thread-relative stack-allocated value
54147    *   directly, but then by the time we get here, that variable has vanished, and we get
54148    *   garbage.  We had to thwart the optimization by adding if ((flag) && (!flag)) fprintf(...);
54149    *   So, in the new form (26-Jun-13), the value is passed directly into an s7 variable
54150    *   that I hope can't be optimized out of existence.
54151    *
54152    * cm/src/Scheme.cpp, used in Snd (listener looking for C-g I think)
54153    *   originally this facility was aimed at interrupting infinite loops, and the expected usage was:
54154    *     set begin_hook, eval-string(...), unset begin_hook
54155    */
54156   opcode_t op;
54157   s7_pointer cur_code;
54158   op = sc->cur_op;
54159 
54160   push_stack_direct(sc, OP_BARRIER);
54161   sc->begin_hook(sc, &result);
54162   if (result)
54163     {
54164       /* set (owlet) in case we were interrupted and need to see why something was hung */
54165       slot_set_value(sc->error_type, sc->F);
54166       slot_set_value(sc->error_data, sc->value); /* was sc->F but we now clobber this below */
54167       cur_code = current_code(sc);
54168       slot_set_value(sc->error_code, cur_code);
54169 
54170       if (has_location(cur_code))
54171 	{
54172 	  integer(slot_value(sc->error_line)) = (s7_int)pair_line_number(cur_code);
54173 	  slot_set_value(sc->error_file, sc->file_names[pair_file_number(cur_code)]);
54174 	  integer(slot_value(sc->error_position)) = (s7_int)pair_position(cur_code);
54175 	}
54176       else
54177 	{
54178 	  integer(slot_value(sc->error_line)) = 0;
54179 	  integer(slot_value(sc->error_position)) = 0;
54180 	  slot_set_value(sc->error_file, sc->F);
54181 	}
54182 #if WITH_HISTORY
54183       slot_set_value(sc->error_history, sc->F);
54184 #endif
54185       let_set_outlet(sc->owlet, sc->curlet);
54186 
54187       sc->value = make_symbol(sc, "begin-hook-interrupt");
54188       /* otherwise the evaluator returns whatever random thing is in sc->value (normally #<closure>)
54189        *   which makes debugging unnecessarily difficult. ?? why not return something useful? make return s7_pointer*, not bool*
54190        */
54191       s7_quit(sc);     /* don't call gc here -- eval_c_string is the context -- allows interrupt of infinite loop */
54192       return(true);
54193     }
54194   pop_stack_no_op(sc);
54195   sc->cur_op = op;     /* for better error handling.  otherwise we get "barrier" as the offending function name in eval_error */
54196   return(false);
54197 }
54198 
54199 
54200 /* -------------------------------- apply -------------------------------- */
54201 static s7_pointer apply_list_star(s7_scheme *sc, s7_pointer d)
54202 {
54203   s7_pointer p;
54204   /* we check this ahead of time: if (is_null(cdr(d))) return(car(d)); */
54205   p = cons(sc, car(d), cdr(d));
54206   sc->w = p;
54207   while (is_not_null(cddr(p)))
54208     {
54209       d = cdr(d);
54210       set_cdr(p, cons(sc, car(d), cdr(d)));
54211       if (is_not_null(cdr(d)))
54212 	p = cdr(p);
54213     }
54214   set_cdr(p, cadr(p));
54215   return(sc->w);
54216 }
54217 
54218 static s7_pointer apply_list_error(s7_scheme *sc, s7_pointer lst)
54219 {
54220   return(s7_error(sc, sc->wrong_type_arg_symbol,
54221 		  set_elist_2(sc, wrap_string(sc, "apply's last argument should be a proper list: ~S", 49), lst)));
54222 }
54223 
54224 static s7_pointer g_apply(s7_scheme *sc, s7_pointer args)
54225 {
54226   #define H_apply "(apply func ...) applies func to the rest of the arguments"
54227   #define Q_apply s7_make_circular_signature(sc, 2, 3, sc->values_symbol, s7_make_signature(sc, 2, sc->is_procedure_symbol, sc->is_sequence_symbol), sc->T)
54228 
54229   /* can apply always be replaced with apply values?
54230    *   (apply + '(1 2 3)) is the same as (+ (apply values '(1 2 3)))
54231    * not if apply* in disguise, I think:
54232    *   (apply + 1 2 ()) -> 3
54233    *   (apply + 1 2 (apply values ())) -> error
54234    */
54235   sc->code = car(args);
54236   if (is_null(cdr(args)))
54237     {
54238       sc->args = sc->nil;
54239       push_stack_direct(sc, OP_APPLY);
54240       return(sc->nil);
54241     }
54242 
54243   if (is_safe_procedure(sc->code))
54244     {
54245       s7_pointer p, q;
54246 
54247       for (q = args, p = cdr(args); is_not_null(cdr(p)); q = p, p = cdr(p));
54248       /* the last arg is supposed to be a list, it will be spliced onto the end of the previous arg list (if any) below */
54249 
54250       if (!s7_is_proper_list(sc, car(p)))        /* (apply + #f) etc */
54251 	return(apply_list_error(sc, args));
54252       set_cdr(q, car(p));
54253       /* this would work: if (is_c_function(sc->code)) return(c_function_call(sc->code)(sc, cdr(args)));
54254        *   but it omits the arg number check, but if we copy the APPLY table here (returning sc->value)
54255        *   the overhead from the now non-inline function calls is greater than the fewer-eval-jumps savings.
54256        */
54257       push_stack(sc, OP_APPLY, cdr(args), sc->code);
54258       return(sc->nil);
54259     }
54260 
54261   /* here we may have to copy the arg list */
54262   sc->args = (is_null(cddr(args))) ? cadr(args) : apply_list_star(sc, cdr(args));
54263   if (!s7_is_proper_list(sc, sc->args))
54264     return(apply_list_error(sc, args));
54265 
54266   sc->args = (needs_copied_args(sc->code)) ? copy_proper_list(sc, sc->args) : sc->args;
54267   push_stack_direct(sc, OP_APPLY);
54268   return(sc->nil);
54269 }
54270 
54271 s7_pointer s7_apply_function(s7_scheme *sc, s7_pointer fnc, s7_pointer args)
54272 {
54273   TRACK(sc);
54274 
54275   if (is_c_function(fnc))
54276     return(c_function_call(fnc)(sc, args));
54277 
54278   push_stack_direct(sc, OP_EVAL_DONE);
54279   sc->code = fnc;
54280   sc->args = (needs_copied_args(sc->code)) ? copy_proper_list(sc, args) : args;
54281   eval(sc, OP_APPLY);
54282   /* we're limited in choices here -- the caller might be (say) car(sc->t1_1) = fn_proc(...) where the fn_proc
54283    *   happens to fallback on a method -- we can't just push OP_APPLY and drop back into the evaluator normally.
54284    */
54285   return(sc->value);
54286 }
54287 
54288 
54289 static s7_pointer implicit_index(s7_scheme *sc, s7_pointer obj, s7_pointer indices)
54290 {
54291   s7_pointer res;
54292   /* (let ((lst '("12" "34"))) (lst 0 1)) -> #\2
54293    * (let ((lst (list #(1 2) #(3 4)))) (lst 0 1)) -> 2
54294    *
54295    * this can get tricky:
54296    *   ((list (lambda (a) (+ a 1)) (lambda (b) (* b 2))) 1 2) -> 4
54297    * but what if func takes rest/optional args, etc?
54298    *   ((list (lambda args (car args))) 0 "hi" 0)
54299    *   should this return #\h or "hi"?? currently it is "hi" which is consistent with ((lambda args (car args)) "hi" 0)
54300    * but ((lambda (arg) arg) "hi" 0) is currently an error (too many arguments)
54301    * maybe it should be (((lambda (arg) arg) "hi") 0) -> #\h
54302    */
54303 
54304   switch (type(obj))
54305     {
54306     case T_VECTOR:                       /* (#(#(1 2) #(3 4)) 1 1) -> 4 */
54307       return(vector_ref_1(sc, obj, indices));
54308 
54309     case T_FLOAT_VECTOR:
54310       res = univect_ref(sc, set_ulist_1(sc, obj, indices), sc->float_vector_ref_symbol, T_FLOAT_VECTOR);
54311       set_car(sc->u1_1, sc->F);
54312       return(res);
54313 
54314     case T_INT_VECTOR:
54315       res = univect_ref(sc, set_ulist_1(sc, obj, indices), sc->int_vector_ref_symbol, T_INT_VECTOR);
54316       set_car(sc->u1_1, sc->F);
54317       return(res);
54318 
54319     case T_BYTE_VECTOR:
54320       res = univect_ref(sc, set_ulist_1(sc, obj, indices), sc->byte_vector_ref_symbol, T_BYTE_VECTOR);
54321       set_car(sc->u1_1, sc->F);
54322       return(res);
54323 
54324     case T_STRING:                       /* (#("12" "34") 0 1) -> #\2 */
54325       if (is_null(cdr(indices)))
54326 	{
54327 	  if (!is_t_integer(car(indices)))
54328 	    return(wrong_type_argument(sc, sc->string_ref_symbol, 2, car(indices), T_INTEGER));
54329 	  return(string_ref_p_pi_unchecked(sc, obj, integer(car(indices))));
54330 	}
54331       return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, obj, indices)));
54332 
54333     case T_PAIR:                         /* (#((1 2) (3 4)) 1 0) -> 3, (#((1 (2 3))) 0 1 0) -> 2 */
54334       obj = list_ref_1(sc, obj, car(indices));
54335       return((is_pair(cdr(indices))) ? implicit_index(sc, obj, cdr(indices)) : obj);
54336 
54337     case T_HASH_TABLE:                   /* ((vector (hash-table '(a . 1) '(b . 2))) 0 'a) -> 1 */
54338       obj = s7_hash_table_ref(sc, obj, car(indices));
54339       return((is_pair(cdr(indices))) ? implicit_index(sc, obj, cdr(indices)) : obj);
54340 
54341     case T_C_OBJECT:
54342       res = (*(c_object_ref(sc, obj)))(sc, set_ulist_1(sc, obj, indices));
54343       set_car(sc->u1_1, sc->F);
54344       return(res);
54345 
54346     case T_LET:
54347       obj = s7_let_ref(sc, obj, car(indices));
54348       return((is_pair(cdr(indices))) ? implicit_index(sc, obj, cdr(indices)) : obj);
54349 
54350     case T_ITERATOR: /* indices is not nil, so this is an error */
54351       return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, obj, indices)));
54352 
54353     default:                             /* (#(a b c) 0 1) -> error, but ((list (lambda (x) x)) 0 "hi") -> "hi" */
54354       if (is_applicable(obj))            /* (apply (list cons cons) (list 1 2)) needs the argnum check mentioned below */
54355 	{
54356 	  if ((is_c_function(obj)) &&
54357 	      (is_safe_procedure(obj)))
54358 	    {
54359 	      s7_int len;
54360 	      len = proper_list_length(indices);
54361 	      if ((c_function_required_args(obj) <= len) &&
54362 		  (c_function_all_args(obj) >= len))
54363 		return(c_function_call(obj)(sc, indices));
54364 	    }
54365 	  push_stack_direct(sc, OP_EVAL_DONE);
54366 	  sc->code = obj;
54367 	  sc->args = (needs_copied_args(obj)) ? copy_proper_list(sc, indices) : indices;
54368 	  eval(sc, OP_APPLY);
54369 	  /* here sc->values can be multiple-values: (list (list-ref (list (lambda (a) (values a (+ a 1)))) 0 1)) -> '((values 1 2)), but should be '(1 2) */
54370 	  if (is_multiple_value(sc->value))
54371 	    sc->value = splice_in_values(sc, multiple_value(sc->value));
54372 	  return(sc->value);
54373 	  /* return(s7_apply_function(sc, obj, indices)); -- needs argnum check */ /* was g_apply 23-Jan-19 which assumes we're not in map */
54374 	}
54375       return(apply_error(sc, obj, indices));
54376     }
54377 }
54378 
54379 static inline void fill_star_defaults(s7_scheme *sc, s7_pointer func, int32_t start_arg, int32_t n_args, s7_pointer par)
54380 {
54381   int32_t i;
54382   s7_pointer *df;
54383   df = c_function_arg_defaults(func);
54384 
54385   if (c_func_has_simple_defaults(func))
54386     {
54387       for (i = start_arg; i < n_args; i++, par = cdr(par))
54388 	set_car(par, df[i]);
54389     }
54390   else
54391     for (i = start_arg; i < n_args; i++, par = cdr(par))
54392       {
54393 	s7_pointer defval;
54394 	defval = df[i];
54395 	if (is_symbol(defval))
54396 	  set_car(par, lookup_checked(sc, defval));
54397 	else
54398 	  {
54399 	    if (is_pair(defval))
54400 	      set_car(par, s7_eval(sc, defval, sc->nil));
54401 	    else set_car(par, defval);
54402 	  }}
54403 }
54404 
54405 static s7_pointer set_c_function_star_args(s7_scheme *sc)
54406 {
54407   int32_t i, j, n_args;
54408   s7_pointer arg, par, call_args, func;
54409   s7_pointer *df;
54410 
54411   func = sc->code;
54412   n_args = c_function_all_args(func);     /* not counting keywords, I think */
54413   call_args = (is_safe_procedure(func)) ? c_function_call_args(func) : protected_make_list(sc, c_function_optional_args(func), sc->F);
54414 
54415   /* assume at the start that there are no keywords */
54416   for (i = 0, arg = sc->args, par = call_args; (i < n_args) && (is_pair(arg)); i++, arg = cdr(arg), par = cdr(par))
54417     {
54418       if (!is_keyword(car(arg)))
54419 	set_car(par, car(arg));
54420       else
54421 	{
54422 	  s7_pointer kpar, karg;
54423 	  int32_t ki;
54424 	  /* oops -- there are keywords, change scanners (much duplicated code...)
54425 	   *   setting checked on the call_args here rather than parsing the parameters to use add_symbol_to_list
54426 	   */
54427 	  for (kpar = call_args; kpar != par; kpar = cdr(kpar))
54428 	    set_checked(kpar);
54429 	  for (; is_pair(kpar); kpar = cdr(kpar))
54430 	    clear_checked(kpar);
54431 	  df = c_function_arg_names(func);
54432 	  for (ki = i, karg = arg, kpar = par; (ki < n_args) && (is_pair(karg)); ki++, karg = cdr(karg))
54433 	    {
54434 	      if (!is_keyword(car(karg)))
54435 		{
54436 		  if (is_checked(kpar))
54437 		    return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, parameter_set_twice_string, car(kpar), sc->args)));
54438 		  set_checked(kpar);
54439 		  set_car(kpar, car(karg));
54440 		  kpar = cdr(kpar);
54441 		}
54442 	      else
54443 		{
54444 		  s7_pointer p;
54445 		  for (j = 0, p = call_args; j < n_args; j++, p = cdr(p))
54446 		    if (df[j] == car(karg))
54447 		      break;
54448 
54449 		  if (j == n_args)
54450 		    {
54451 		      if (c_function_allows_other_keys(func))
54452 			{
54453 			  karg = cdr(karg);
54454 			  if (is_null(karg)) /* (f* :x) where f* arglist includes :allow-other-keys */
54455 			    return(s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, value_is_missing_string, func, car(arg))));
54456 			  ki--;
54457 			}
54458 		      else return(s7_error(sc, sc->wrong_type_arg_symbol,
54459 					   set_elist_2(sc, wrap_string(sc, "~A: not a parameter name?", 25), car(karg))));
54460 		    }
54461 		  else
54462 		    {
54463 		      if (is_checked(p))
54464 			return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, parameter_set_twice_string, car(p), sc->args)));
54465 		      if (!is_pair(cdr(karg)))
54466 			return(s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, value_is_missing_string, func, car(karg))));
54467 		      set_checked(p);
54468 		      karg = cdr(karg);
54469 		      set_car(p, car(karg));
54470 		      kpar = cdr(kpar);
54471 		    }}}
54472 	  if ((!is_null(karg)) && (!c_function_allows_other_keys(func)))
54473 	    return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, func, sc->args)));
54474 	  if (ki < n_args)
54475 	    {
54476 	      df = c_function_arg_defaults(func);
54477 	      if (c_func_has_simple_defaults(func))
54478 		{
54479 		  for (ki = i, kpar = par; ki < n_args; ki++, kpar = cdr(kpar))
54480 		    if (!is_checked(kpar))
54481 		      set_car(kpar, df[ki]);
54482 		}
54483 	      else
54484 		for (ki = i, kpar = par; ki < n_args; ki++, kpar = cdr(kpar))
54485 		  if (!is_checked(kpar))
54486 		    {
54487 		      s7_pointer defval;
54488 		      defval = df[ki];
54489 		      if (is_symbol(defval))
54490 			set_car(kpar, lookup_checked(sc, defval));
54491 		      else
54492 			{
54493 			  if (is_pair(defval))
54494 			    set_car(kpar, s7_eval(sc, defval, sc->nil));
54495 			  else set_car(kpar, defval);
54496 			}}}
54497 	  return(call_args);
54498 	}}
54499   if (!is_null(arg))
54500     return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, func, sc->args)));
54501   if (i < n_args)
54502     fill_star_defaults(sc, func, i, n_args, par);
54503   return(call_args);
54504 }
54505 
54506 static s7_pointer set_c_function_star_defaults(s7_scheme *sc, int32_t num)
54507 {
54508   s7_pointer call_args, func, par;
54509   int32_t n_args;
54510 
54511   func = sc->code;
54512   n_args = c_function_all_args(func);
54513   call_args = (is_safe_procedure(func)) ? c_function_call_args(func) : protected_make_list(sc, n_args, sc->F);
54514   par = call_args;
54515   if (num == 1)
54516     {
54517       set_car(par, car(sc->args));
54518       par = cdr(par);
54519     }
54520   fill_star_defaults(sc, func, num, n_args, par);
54521   return(call_args);
54522 }
54523 
54524 #define apply_c_function_star(Sc) Sc->value = c_function_call(Sc->code)(Sc, set_c_function_star_args(Sc))
54525 #define apply_c_function_star_fill_defaults(Sc, Num) Sc->value = c_function_call(Sc->code)(Sc, set_c_function_star_defaults(Sc, Num))
54526 
54527 s7_pointer s7_apply_function_star(s7_scheme *sc, s7_pointer fnc, s7_pointer args)
54528 {
54529   TRACK(sc);
54530   if (is_c_function_star(fnc))
54531     {
54532       sc->w = sc->args;
54533       sc->z = sc->code;
54534       sc->args = T_Pos(args);
54535       sc->code = fnc;
54536       apply_c_function_star(sc);
54537       sc->args = sc->w;
54538       sc->code = sc->z;
54539       return(sc->value);
54540     }
54541   push_stack_direct(sc, OP_EVAL_DONE);
54542   sc->code = fnc;
54543   sc->args = (needs_copied_args(sc->code)) ? copy_proper_list(sc, args) : args;
54544   eval(sc, OP_APPLY);
54545   return(sc->value);
54546 }
54547 
54548 /* -------------------------------- eval -------------------------------- */
54549 s7_pointer s7_eval(s7_scheme *sc, s7_pointer code, s7_pointer e)
54550 {
54551   declare_jump_info();
54552   TRACK(sc);
54553 
54554   if (sc->safety > NO_SAFETY)
54555     {
54556       if (!s7_is_valid(sc, code))
54557 	s7_warn(sc, 256, "bad code arg to %s: %p\n", __func__, code);
54558       if (!s7_is_valid(sc, e))
54559 	s7_warn(sc, 256, "bad environment arg to %s: %p\n", __func__, e);
54560     }
54561 
54562   store_jump_info(sc);
54563   set_jump_info(sc, EVAL_SET_JUMP);
54564   if (jump_loc != NO_JUMP)
54565     {
54566       if (jump_loc != ERROR_JUMP)
54567 	eval(sc, sc->cur_op);
54568     }
54569   else
54570     {
54571       push_stack_direct(sc, OP_EVAL_DONE);
54572       sc->code = code;
54573       if ((e != sc->rootlet) &&
54574 	  (is_let(e)))
54575 	sc->curlet = e;
54576       else sc->curlet = sc->nil;
54577       eval(sc, OP_EVAL);
54578     }
54579   restore_jump_info(sc);
54580 
54581   if (is_multiple_value(sc->value))
54582     sc->value = splice_in_values(sc, multiple_value(sc->value));
54583   return(sc->value);
54584 }
54585 
54586 
54587 static s7_pointer g_eval(s7_scheme *sc, s7_pointer args)
54588 {
54589   #define H_eval "(eval code (let (curlet))) evaluates code in the environment let. 'let' \
54590 defaults to the curlet; to evaluate something in the top-level environment instead, \
54591 pass (rootlet):\n\
54592 \n\
54593   (define x 32) \n\
54594   (let ((x 3))\n\
54595     (eval 'x (rootlet)))\n\
54596 \n\
54597   returns 32"
54598   #define Q_eval s7_make_signature(sc, 3, sc->values_symbol, sc->T, sc->is_let_symbol)
54599 
54600   if (is_not_null(cdr(args)))
54601     {
54602       s7_pointer e;
54603       e = cadr(args);
54604       if (!is_let(e))
54605 	return(wrong_type_argument_with_type(sc, sc->eval_symbol, 2, e, a_let_string));
54606       sc->curlet = (e == sc->rootlet) ? sc->nil : e;
54607     }
54608   sc->code = car(args);
54609 
54610   if ((sc->safety > NO_SAFETY) &&
54611       (is_pair(sc->code)))
54612     {
54613       check_free_heap_size(sc, 8192);
54614       sc->code = copy_body(sc, sc->code);
54615     }
54616   else
54617     if (is_optimized(sc->code))
54618       clear_all_optimizations(sc, sc->code);
54619 
54620   set_current_code(sc, sc->code);
54621   if (current_stack_top(sc) < 12)
54622     push_stack_op(sc, OP_BARRIER);
54623   push_stack_direct(sc, OP_EVAL);
54624 
54625   return(sc->nil);
54626 }
54627 
54628 s7_pointer s7_call(s7_scheme *sc, s7_pointer func, s7_pointer args)
54629 {
54630   declare_jump_info();
54631   TRACK(sc);
54632   set_current_code(sc, history_cons(sc, func, args));
54633 
54634 #if SHOW_EVAL_OPS
54635   safe_print(fprintf(stderr, "%s: %s %s\n", __func__, display(func), display_80(args)));
54636 #endif
54637 
54638   if (is_c_function(func))
54639     return(c_function_call(func)(sc, args));         /* no check for wrong-number-of-args -- is that reasonable? */
54640 
54641   sc->temp4 = T_App(func);                           /* this is feeble GC protection */
54642   sc->temp2 = T_Lst(args);
54643 
54644   store_jump_info(sc);
54645   set_jump_info(sc, S7_CALL_SET_JUMP);
54646   if (jump_loc != NO_JUMP)
54647     {
54648       if (jump_loc != ERROR_JUMP)
54649 	eval(sc, sc->cur_op);
54650 
54651       if ((jump_loc == CATCH_JUMP) &&                /* we're returning (back to eval) from an error in catch */
54652 	  (sc->stack_end == sc->stack_start))
54653 	push_stack_op(sc, OP_ERROR_QUIT);
54654     }
54655   else
54656     {
54657       if (sc->safety > NO_SAFETY)
54658 	check_list_validity(sc, "s7_call", args);
54659 
54660       push_stack_direct(sc, OP_EVAL_DONE); /* this saves the current evaluation and will eventually finish this (possibly) nested call */
54661       sc->code = func;
54662       sc->args = (needs_copied_args(func)) ? copy_proper_list(sc, args) : args;
54663       /* besides a closure, "func" can also be an object (T_C_OBJECT) -- in Snd, a generator for example  */
54664       eval(sc, OP_APPLY);
54665     }
54666   restore_jump_info(sc);
54667   /* don't clear temp4 or temp2 here -- lots of (Snd) code calls s7_call repeatedly and assumes the "func" arg is protected between calls. */
54668   return(sc->value);
54669 }
54670 
54671 s7_pointer s7_call_with_location(s7_scheme *sc, s7_pointer func, s7_pointer args, const char *caller, const char *file, s7_int line)
54672 {
54673   s7_pointer result;
54674 
54675   if (caller)
54676     {
54677       sc->s7_call_name = caller;
54678       sc->s7_call_file = file;
54679       sc->s7_call_line = line;
54680     }
54681   result = s7_call(sc, func, args);
54682   if (caller)
54683     {
54684       sc->s7_call_name = NULL;
54685       sc->s7_call_file = NULL;
54686       sc->s7_call_line = -1;
54687     }
54688   return(result);
54689 }
54690 
54691 
54692 /* -------------------------------- type-of -------------------------------- */
54693 
54694 #if (!WITH_GCC)
54695 static inline bool gen_type_match(s7_scheme *sc, s7_pointer val, uint8_t typ)  /* opt3_byte = uint8_t */
54696 {
54697   return((type(val) == typ) ||
54698 	 ((has_active_methods(sc, val)) &&
54699 	  (apply_boolean_method(sc, val, sc->type_to_typers[typ]) != sc->F)));
54700 }
54701 #else
54702 #define gen_type_match(Sc, Val, Typ) ({s7_pointer _val_ = Val; ((type(_val_) == Typ) || ((has_active_methods(Sc, _val_)) && (apply_boolean_method(Sc, _val_, Sc->type_to_typers[Typ]) != Sc->F)));})
54703 #endif
54704 
54705 static void init_typers(s7_scheme *sc)
54706 {
54707   sc->type_to_typers[T_FREE] =                sc->F;
54708   sc->type_to_typers[T_PAIR] =                sc->is_pair_symbol;
54709   sc->type_to_typers[T_NIL] =                 sc->is_null_symbol;
54710   sc->type_to_typers[T_EOF] =                 sc->is_eof_object_symbol;
54711   sc->type_to_typers[T_UNDEFINED] =           sc->is_undefined_symbol;
54712   sc->type_to_typers[T_UNSPECIFIED] =         sc->is_unspecified_symbol;
54713   sc->type_to_typers[T_BOOLEAN] =             sc->is_boolean_symbol;
54714   sc->type_to_typers[T_CHARACTER] =           sc->is_char_symbol;
54715   sc->type_to_typers[T_SYMBOL] =              sc->is_symbol_symbol;      /* and keyword? */
54716   sc->type_to_typers[T_SYNTAX] =              sc->is_syntax_symbol;
54717   sc->type_to_typers[T_INTEGER] =             sc->is_integer_symbol;
54718   sc->type_to_typers[T_RATIO] =               sc->is_rational_symbol;
54719   sc->type_to_typers[T_REAL] =                sc->is_float_symbol;
54720   sc->type_to_typers[T_COMPLEX] =             sc->is_complex_symbol;
54721   sc->type_to_typers[T_BIG_INTEGER] =         sc->is_integer_symbol;
54722   sc->type_to_typers[T_BIG_RATIO] =           sc->is_rational_symbol;
54723   sc->type_to_typers[T_BIG_REAL] =            sc->is_float_symbol;
54724   sc->type_to_typers[T_BIG_COMPLEX] =         sc->is_complex_symbol;
54725   sc->type_to_typers[T_STRING] =              sc->is_string_symbol;
54726   sc->type_to_typers[T_BYTE_VECTOR] =         sc->is_byte_vector_symbol;
54727   sc->type_to_typers[T_C_OBJECT] =            sc->is_c_object_symbol;
54728   sc->type_to_typers[T_VECTOR] =              sc->is_vector_symbol;
54729   sc->type_to_typers[T_INT_VECTOR] =          sc->is_int_vector_symbol;
54730   sc->type_to_typers[T_FLOAT_VECTOR] =        sc->is_float_vector_symbol;
54731   sc->type_to_typers[T_CATCH] =               sc->F;
54732   sc->type_to_typers[T_DYNAMIC_WIND] =        sc->F;
54733   sc->type_to_typers[T_HASH_TABLE] =          sc->is_hash_table_symbol;
54734   sc->type_to_typers[T_LET] =                 sc->is_let_symbol;
54735   sc->type_to_typers[T_ITERATOR] =            sc->is_iterator_symbol;
54736   sc->type_to_typers[T_STACK] =               sc->F;
54737   sc->type_to_typers[T_COUNTER] =             sc->F;
54738   sc->type_to_typers[T_SLOT] =                sc->F;
54739   sc->type_to_typers[T_C_POINTER] =           sc->is_c_pointer_symbol;
54740   sc->type_to_typers[T_OUTPUT_PORT] =         sc->is_output_port_symbol;
54741   sc->type_to_typers[T_INPUT_PORT] =          sc->is_input_port_symbol;
54742   sc->type_to_typers[T_RANDOM_STATE] =        sc->is_random_state_symbol;
54743   sc->type_to_typers[T_GOTO] =                sc->is_goto_symbol;
54744   sc->type_to_typers[T_CONTINUATION] =        sc->is_continuation_symbol;
54745   sc->type_to_typers[T_CLOSURE] =             sc->is_procedure_symbol;
54746   sc->type_to_typers[T_CLOSURE_STAR] =        sc->is_procedure_symbol;
54747   sc->type_to_typers[T_C_MACRO] =             sc->is_macro_symbol;
54748   sc->type_to_typers[T_MACRO] =               sc->is_macro_symbol;
54749   sc->type_to_typers[T_MACRO_STAR] =          sc->is_macro_symbol;
54750   sc->type_to_typers[T_BACRO] =               sc->is_macro_symbol;
54751   sc->type_to_typers[T_BACRO_STAR] =          sc->is_macro_symbol;
54752   sc->type_to_typers[T_C_FUNCTION] =          sc->is_procedure_symbol;
54753   sc->type_to_typers[T_C_FUNCTION_STAR] =     sc->is_procedure_symbol;
54754   sc->type_to_typers[T_C_ANY_ARGS_FUNCTION] = sc->is_procedure_symbol;
54755   sc->type_to_typers[T_C_OPT_ARGS_FUNCTION] = sc->is_procedure_symbol;
54756   sc->type_to_typers[T_C_RST_ARGS_FUNCTION] = sc->is_procedure_symbol;
54757 }
54758 
54759 s7_pointer s7_type_of(s7_scheme *sc, s7_pointer arg) {return(sc->type_to_typers[type(arg)]);}
54760 
54761 static s7_pointer g_type_of(s7_scheme *sc, s7_pointer args)
54762 {
54763   #define H_type_of "(type-of obj) returns a symbol describing obj's type"
54764   #define Q_type_of s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_symbol_symbol, sc->not_symbol), sc->T)
54765 
54766   return(sc->type_to_typers[type(car(args))]);
54767 }
54768 
54769 
54770 /* -------------------------------- exit emergency-exit -------------------------------- */
54771 void s7_quit(s7_scheme *sc)
54772 {
54773   sc->longjmp_ok = false;
54774   pop_input_port(sc);
54775   stack_reset(sc);
54776   push_stack_op_let(sc, OP_EVAL_DONE);
54777 }
54778 
54779 static s7_pointer g_emergency_exit(s7_scheme *sc, s7_pointer args)
54780 {
54781   #define H_emergency_exit "(emergency-exit obj) exits s7 immediately"
54782   #define Q_emergency_exit s7_make_signature(sc, 2, sc->T, sc->T)
54783 
54784   s7_pointer obj;
54785 #ifndef EXIT_SUCCESS
54786   #define EXIT_SUCCESS 0
54787   #define EXIT_FAILURE 1
54788 #endif
54789 
54790   if (is_null(args))
54791     _exit(EXIT_SUCCESS);          /* r7rs spec says use _exit here */
54792   obj = car(args);
54793   if (obj == sc->F)
54794     _exit(EXIT_FAILURE);
54795   if ((obj == sc->T) || (!s7_is_integer(obj)))
54796     _exit(EXIT_SUCCESS);
54797   _exit((int)s7_integer_checked(sc, obj));
54798   return(sc->F);
54799 }
54800 
54801 static s7_pointer g_exit(s7_scheme *sc, s7_pointer args)
54802 {
54803   #define H_exit "(exit obj) exits s7"
54804   #define Q_exit s7_make_signature(sc, 2, sc->T, sc->T)
54805   /* calling s7_eval_c_string in an atexit function seems to be problematic -- it works, but args can be changed? longjmp perhaps? */
54806 
54807   s7_quit(sc);
54808   if (show_gc_stats(sc))
54809     s7_warn(sc, 256, "gc calls %" print_s7_int " total time: %f\n", sc->gc_calls, (double)(sc->gc_total_time) / ticks_per_second());
54810 
54811   return(g_emergency_exit(sc, args));
54812 }
54813 
54814 #if WITH_GCC
54815 static s7_pointer g_abort(s7_scheme *sc, s7_pointer args) {abort();}
54816 #endif
54817 
54818 
54819 /* -------------------------------- optimizer stuff -------------------------------- */
54820 
54821 #if S7_DEBUGGING
54822 static void check_t_1(s7_scheme *sc, s7_pointer e, const char* func, s7_pointer expr, s7_pointer var)
54823 {
54824   if (let_slots(e) != lookup_slot_from(var, sc->curlet))
54825     {
54826       fprintf(stderr, "%s %s is out of date (%s in %s -> %s)\n",
54827 	      func,
54828 	      display(expr),
54829 	      display(var),
54830 	      display(sc->curlet),
54831 	      (tis_slot(let_slots(e))) ? display(let_slots(e)) : "no slots");
54832       if (sc->stop_at_error) abort();
54833     }
54834 }
54835 
54836 static void check_u_1(s7_scheme *sc, s7_pointer e, const char* func, s7_pointer expr, s7_pointer var)
54837 {
54838   if (next_slot(let_slots(e)) != lookup_slot_from(var, sc->curlet))
54839     {
54840       fprintf(stderr, "%s %s is out of date (%s in %s -> %s)\n",
54841 	      func,
54842 	      display(expr),
54843 	      display(var),
54844 	      display(e),
54845 	      (tis_slot(next_slot(let_slots(e)))) ? display(next_slot(let_slots(e))) : "no next slot");
54846       if (sc->stop_at_error) abort();
54847     }
54848 }
54849 
54850 static void check_v_1(s7_scheme *sc, s7_pointer e, const char* func, s7_pointer expr, s7_pointer var)
54851 {
54852   if (next_slot(next_slot(let_slots(e))) != lookup_slot_from(var, sc->curlet))
54853     {
54854       fprintf(stderr, "%s %s is out of date (%s in %s -> %s)\n",
54855 	      func,
54856 	      display(expr),
54857 	      display(var),
54858 	      display(e),
54859 	      (tis_slot(next_slot(next_slot(let_slots(e))))) ? display(next_slot(next_slot(let_slots(e)))) : "no next slot");
54860       if (sc->stop_at_error) abort();
54861     }
54862 }
54863 
54864 static s7_pointer t_lookup_1(s7_scheme *sc, s7_pointer symbol, const char *func, s7_pointer expr)
54865 {
54866   check_t_1(sc, sc->curlet, func, expr, symbol);
54867   return(slot_value(let_slots(sc->curlet)));
54868 }
54869 
54870 static s7_pointer u_lookup_1(s7_scheme *sc, s7_pointer symbol, const char *func, s7_pointer expr)
54871 {
54872   check_u_1(sc, sc->curlet, func, expr, symbol);
54873   return(slot_value(next_slot(let_slots(sc->curlet))));
54874 }
54875 
54876 static s7_pointer T_lookup_1(s7_scheme *sc, s7_pointer symbol, const char *func, s7_pointer expr)
54877 {
54878   check_t_1(sc, let_outlet(sc->curlet), func, expr, symbol);
54879   return(slot_value(let_slots(let_outlet(sc->curlet))));
54880 }
54881 
54882 static s7_pointer U_lookup_1(s7_scheme *sc, s7_pointer symbol, const char *func, s7_pointer expr)
54883 {
54884   check_u_1(sc, let_outlet(sc->curlet), func, expr, symbol);
54885   return(slot_value(next_slot(let_slots(let_outlet(sc->curlet)))));
54886 }
54887 
54888 static s7_pointer V_lookup_1(s7_scheme *sc, s7_pointer symbol, const char *func, s7_pointer expr)
54889 {
54890   check_v_1(sc, let_outlet(sc->curlet), func, expr, symbol);
54891   return(slot_value(next_slot(next_slot(let_slots(let_outlet(sc->curlet))))));
54892 }
54893 
54894 #define t_lookup(Sc, Symbol, Expr) t_lookup_1(Sc, Symbol, __func__, Expr)
54895 #define u_lookup(Sc, Symbol, Expr) u_lookup_1(Sc, Symbol, __func__, Expr)
54896 #define T_lookup(Sc, Symbol, Expr) T_lookup_1(Sc, Symbol, __func__, Expr)
54897 #define U_lookup(Sc, Symbol, Expr) U_lookup_1(Sc, Symbol, __func__, Expr)
54898 #define V_lookup(Sc, Symbol, Expr) V_lookup_1(Sc, Symbol, __func__, Expr)
54899 #else
54900 #define t_lookup(Sc, Symbol, Expr) slot_value(let_slots(sc->curlet))
54901 #define u_lookup(Sc, Symbol, Expr) slot_value(next_slot(let_slots(sc->curlet)))
54902 #define T_lookup(Sc, Symbol, Expr) slot_value(let_slots(let_outlet(sc->curlet)))
54903 #define U_lookup(Sc, Symbol, Expr) slot_value(next_slot(let_slots(let_outlet(sc->curlet))))
54904 #define V_lookup(Sc, Symbol, Expr) slot_value(next_slot(next_slot(let_slots(let_outlet(sc->curlet)))))
54905 #endif
54906 
54907 /* arg here is the full expression */
54908 static s7_pointer fx_c(s7_scheme *sc, s7_pointer arg)        {return(arg);}
54909 static s7_pointer fx_q(s7_scheme *sc, s7_pointer arg)        {return(cadr(arg));}
54910 static s7_pointer fx_unsafe_s(s7_scheme *sc, s7_pointer arg) {return(lookup_checked(sc, T_Sym(arg)));}
54911 
54912 static s7_pointer fx_s(s7_scheme *sc, s7_pointer arg) {return(lookup(sc, T_Sym(arg)));}
54913 static s7_pointer fx_g(s7_scheme *sc, s7_pointer arg) {return((is_global(arg)) ? global_value(arg) : lookup(sc, arg));}
54914 
54915 static s7_pointer fx_t(s7_scheme *sc, s7_pointer arg) {return(t_lookup(sc, T_Sym(arg), arg));}
54916 static s7_pointer fx_u(s7_scheme *sc, s7_pointer arg) {return(u_lookup(sc, T_Sym(arg), arg));}
54917 static s7_pointer fx_T(s7_scheme *sc, s7_pointer arg) {return(T_lookup(sc, T_Sym(arg), arg));}
54918 static s7_pointer fx_U(s7_scheme *sc, s7_pointer arg) {return(U_lookup(sc, T_Sym(arg), arg));}
54919 
54920 static s7_pointer fx_c_d(s7_scheme *sc, s7_pointer arg) {return(d_call(sc, arg));}
54921 
54922 static s7_pointer fx_random_i(s7_scheme *sc, s7_pointer arg)
54923 {
54924 #if WITH_GMP
54925   return(g_random_i(sc, cdr(arg)));
54926 #else
54927   return(make_integer(sc, (s7_int)(integer(cadr(arg)) * next_random(sc->default_rng))));
54928 #endif
54929 }
54930 
54931 static s7_pointer fx_num_eq_xi_1(s7_scheme *sc, s7_pointer args, s7_pointer val, s7_int y)
54932 {
54933 #if S7_DEBUGGING
54934   if (is_t_integer(val)) fprintf(stderr, "%s[%d]: %s is an integer\n", __func__, __LINE__, display(val));
54935 #endif
54936   switch (type(val))
54937     {
54938     case T_REAL:    return(make_boolean(sc, real(val) == y));
54939     case T_RATIO:
54940     case T_COMPLEX: return(sc->F);
54941 #if WITH_GMP
54942     case T_BIG_INTEGER:
54943       return(make_boolean(sc, mpz_cmp_si(big_integer(val), y) == 0));
54944     case T_BIG_REAL:
54945       return(make_boolean(sc, mpfr_cmp_si(big_real(val), y) == 0));
54946     case T_BIG_RATIO:
54947     case T_BIG_COMPLEX: return(sc->F);
54948 #endif
54949     default: return(method_or_bust_with_type_pp(sc, val, sc->num_eq_symbol, val, cadr(args), a_number_string, 1));
54950     }
54951   return(sc->T);
54952 }
54953 
54954 static s7_pointer fx_add_i_random(s7_scheme *sc, s7_pointer arg)
54955 {
54956 #if WITH_GMP
54957   return(add_p_pp(sc, cadr(arg), random_p_p(sc, opt3_int(cdr(arg)))));
54958 #else
54959   s7_int x, y;
54960   x = integer(cadr(arg));
54961   y = integer(opt3_int(cdr(arg))); /* cadadr */
54962   return(make_integer(sc, x + (s7_int)(y * next_random(sc->default_rng)))); /* (+ -1 (random 1)) -- placement of the (s7_int) cast matters! */
54963 #endif
54964 }
54965 
54966 static s7_pointer fx_num_eq_si(s7_scheme *sc, s7_pointer arg)
54967 {
54968   s7_int y;
54969   s7_pointer val, args;
54970   args = cdr(arg);
54971   val = lookup(sc, car(args));
54972   y = integer(cadr(args));
54973   return((is_t_integer(val)) ? make_boolean(sc, integer(val) == y) :
54974 	 ((is_t_real(val)) ? make_boolean(sc, real(val) == y) : fx_num_eq_xi_1(sc, args, val, y)));
54975 }
54976 
54977 static s7_pointer fx_num_eq_ti(s7_scheme *sc, s7_pointer arg)
54978 {
54979   s7_int y;
54980   s7_pointer val, args;
54981   args = cdr(arg);
54982   val = t_lookup(sc, cadr(arg), arg);
54983   y = integer(cadr(args));
54984   return((is_t_integer(val)) ? make_boolean(sc, integer(val) == y) : fx_num_eq_xi_1(sc, args, val, y));
54985 }
54986 
54987 static s7_pointer fx_num_eq_ui(s7_scheme *sc, s7_pointer arg)
54988 {
54989   s7_int y;
54990   s7_pointer val, args;
54991   args = cdr(arg);
54992   val = u_lookup(sc, cadr(arg), arg);
54993   y = integer(cadr(args));
54994   return((is_t_integer(val)) ? make_boolean(sc, integer(val) == y) : fx_num_eq_xi_1(sc, args, val, y));
54995 }
54996 
54997 static s7_pointer fx_num_eq_Ti(s7_scheme *sc, s7_pointer arg)
54998 {
54999   s7_int y;
55000   s7_pointer val, args;
55001   args = cdr(arg);
55002   val = T_lookup(sc, cadr(arg), arg);
55003   y = integer(cadr(args));
55004   return((is_t_integer(val)) ? make_boolean(sc, integer(val) == y) : fx_num_eq_xi_1(sc, args, val, y));
55005 }
55006 
55007 static s7_pointer fx_add_s1(s7_scheme *sc, s7_pointer arg)
55008 {
55009   s7_pointer x;
55010   x = lookup(sc, cadr(arg));
55011 #if (!WITH_GMP)
55012   if (is_t_integer(x))
55013     return(make_integer(sc, integer(x) + 1));
55014 #endif
55015   return(g_add_x1_1(sc, x, 1)); /* arg=(+ x 1) */
55016 }
55017 
55018 static s7_pointer fx_add_t1(s7_scheme *sc, s7_pointer arg) /* sub_t1 was not useful */
55019 {
55020   s7_pointer x;
55021   x = t_lookup(sc, cadr(arg), arg);
55022 #if (!WITH_GMP)
55023   if (is_t_integer(x))
55024     return(make_integer(sc, integer(x) + 1));
55025 #endif
55026   return(g_add_x1_1(sc, x, 1));
55027 }
55028 
55029 static s7_pointer fx_add_u1(s7_scheme *sc, s7_pointer arg)
55030 {
55031   s7_pointer x;
55032   x = u_lookup(sc, cadr(arg), arg);
55033 #if (!WITH_GMP)
55034   if (is_t_integer(x))
55035     return(make_integer(sc, integer(x) + 1));
55036 #endif
55037   return(g_add_x1_1(sc, x, 1));
55038 }
55039 
55040 static s7_pointer fx_add_T1(s7_scheme *sc, s7_pointer arg)
55041 {
55042   s7_pointer x;
55043   x = T_lookup(sc, cadr(arg), arg);
55044 #if (!WITH_GMP)
55045   if (is_t_integer(x))
55046     return(make_integer(sc, integer(x) + 1));
55047 #endif
55048   return(g_add_x1_1(sc, x, 1)); /* arg=(+ x 1) */
55049 }
55050 
55051 static s7_pointer fx_add_U1(s7_scheme *sc, s7_pointer arg)
55052 {
55053   s7_pointer x;
55054   x = U_lookup(sc, cadr(arg), arg);
55055 #if (!WITH_GMP)
55056   if (is_t_integer(x))
55057     return(make_integer(sc, integer(x) + 1));
55058 #endif
55059   return(g_add_x1_1(sc, x, 1));
55060 }
55061 
55062 static s7_pointer fx_add_V1(s7_scheme *sc, s7_pointer arg)
55063 {
55064   s7_pointer x;
55065   x = V_lookup(sc, cadr(arg), arg);
55066 #if (!WITH_GMP)
55067   if (is_t_integer(x))
55068     return(make_integer(sc, integer(x) + 1));
55069 #endif
55070   return(g_add_x1_1(sc, x, 1));
55071 }
55072 
55073 static s7_pointer fx_add_sf(s7_scheme *sc, s7_pointer arg) {return(g_add_xf(sc, lookup(sc, cadr(arg)), real(opt2_con(cdr(arg)))));}
55074 static s7_pointer fx_add_fs(s7_scheme *sc, s7_pointer arg) {return(g_add_xf(sc, lookup(sc, opt2_sym(cdr(arg))), real(cadr(arg))));}
55075 static s7_pointer fx_add_tf(s7_scheme *sc, s7_pointer arg) {return(g_add_xf(sc, t_lookup(sc, cadr(arg), arg), real(opt2_con(cdr(arg)))));}
55076 
55077 static s7_pointer fx_add_si(s7_scheme *sc, s7_pointer arg)
55078 {
55079   s7_pointer x;
55080   x = lookup(sc, cadr(arg));
55081 #if (!WITH_GMP)
55082   if (is_t_integer(x))
55083     {
55084 #if HAVE_OVERFLOW_CHECKS
55085       s7_int val;
55086       if (!add_overflow(integer(x), integer(opt2_con(cdr(arg))), &val))
55087 	return(make_integer(sc, val));
55088       /* else fall into add_p_pp below */
55089 #else
55090       return(make_integer(sc, integer(x) + integer(opt2_con(cdr(arg)))));
55091 #endif
55092       /* return(add_if_overflow_to_real_or_big_integer(sc, integer(x), integer(opt2_con(cdr(arg))))); -- slightly slower than the add_overflow code above */
55093     }
55094 #endif
55095   return(add_p_pp(sc, x, opt2_con(cdr(arg)))); /* caddr(arg) */
55096 }
55097 
55098 static s7_pointer fx_add_ti(s7_scheme *sc, s7_pointer arg)
55099 {
55100   s7_pointer x;
55101   x = t_lookup(sc, cadr(arg), arg);
55102 #if (!WITH_GMP)
55103   if (is_t_integer(x))
55104     {
55105 #if HAVE_OVERFLOW_CHECKS
55106       s7_int val;
55107       if (!add_overflow(integer(x), integer(opt2_con(cdr(arg))), &val))
55108 	return(make_integer(sc, val));
55109 #else
55110       return(make_integer(sc, integer(x) + integer(opt2_con(cdr(arg)))));
55111 #endif
55112     }
55113 #endif
55114   return(add_p_pp(sc, x, opt2_con(cdr(arg)))); /* caddr(arg) */
55115 }
55116 
55117 static s7_pointer fx_add_ss(s7_scheme *sc, s7_pointer arg) {return(add_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55118 static s7_pointer fx_add_ts(s7_scheme *sc, s7_pointer arg) {return(add_p_pp(sc, t_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55119 static s7_pointer fx_add_tu(s7_scheme *sc, s7_pointer arg) {return(add_p_pp(sc, t_lookup(sc, cadr(arg), arg), u_lookup(sc, caddr(arg), arg)));}
55120 static s7_pointer fx_add_ut(s7_scheme *sc, s7_pointer arg) {return(add_p_pp(sc, u_lookup(sc, cadr(arg), arg), t_lookup(sc, caddr(arg), arg)));}
55121 static s7_pointer fx_add_us(s7_scheme *sc, s7_pointer arg) {return(add_p_pp(sc, u_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55122 
55123 static s7_pointer fx_subtract_s1(s7_scheme *sc, s7_pointer arg)
55124 {
55125   s7_pointer x;
55126   x = lookup(sc, cadr(arg));
55127 #if (!WITH_GMP)
55128   if (is_t_integer(x))
55129     return(make_integer(sc, integer(x) - 1));
55130 #endif
55131   return(minus_c1(sc, x));
55132 }
55133 
55134 static s7_pointer fx_subtract_t1(s7_scheme *sc, s7_pointer arg)
55135 {
55136   s7_pointer x;
55137   x = t_lookup(sc, cadr(arg), arg);
55138 #if (!WITH_GMP)
55139   if (is_t_integer(x))
55140     return(make_integer(sc, integer(x) - 1));
55141 #endif
55142   return(minus_c1(sc, x));
55143 }
55144 
55145 static s7_pointer fx_subtract_T1(s7_scheme *sc, s7_pointer arg)
55146 {
55147   s7_pointer x;
55148   x = T_lookup(sc, cadr(arg), arg);
55149 #if (!WITH_GMP)
55150   if (is_t_integer(x))
55151     return(make_integer(sc, integer(x) - 1));
55152 #endif
55153   return(minus_c1(sc, x));
55154 }
55155 
55156 static s7_pointer fx_subtract_U1(s7_scheme *sc, s7_pointer arg)
55157 {
55158   s7_pointer x;
55159   x = U_lookup(sc, cadr(arg), arg);
55160 #if (!WITH_GMP)
55161   if (is_t_integer(x))
55162     return(make_integer(sc, integer(x) - 1));
55163 #endif
55164   return(minus_c1(sc, x));
55165 }
55166 
55167 static s7_pointer fx_subtract_u1(s7_scheme *sc, s7_pointer arg)
55168 {
55169   s7_pointer x;
55170   x = u_lookup(sc, cadr(arg), arg);
55171 #if (!WITH_GMP)
55172   if (is_t_integer(x))
55173     return(make_integer(sc, integer(x) - 1));
55174 #endif
55175   return(minus_c1(sc, x));
55176 }
55177 
55178 static s7_pointer fx_subtract_si(s7_scheme *sc, s7_pointer arg)
55179 {
55180   s7_pointer x;
55181   x = lookup(sc, cadr(arg));
55182 #if (!WITH_GMP)
55183   if (is_t_integer(x))
55184     {
55185 #if HAVE_OVERFLOW_CHECKS
55186       s7_int val;
55187       if (!subtract_overflow(integer(x), integer(opt2_con(cdr(arg))), &val))
55188 	return(make_integer(sc, val));
55189 #else
55190       return(make_integer(sc, integer(x) - integer(opt2_con(cdr(arg)))));
55191 #endif
55192     }
55193 #endif
55194   return(subtract_p_pp(sc, x, opt2_con(cdr(arg)))); /* caddr(arg) */
55195 }
55196 
55197 static s7_pointer fx_subtract_ti(s7_scheme *sc, s7_pointer arg)
55198 {
55199   s7_pointer x;
55200   x = t_lookup(sc, cadr(arg), arg);
55201 #if (!WITH_GMP)
55202   if (is_t_integer(x))
55203     {
55204 #if HAVE_OVERFLOW_CHECKS
55205       s7_int val;
55206       if (!subtract_overflow(integer(x), integer(opt2_con(cdr(arg))), &val))
55207 	return(make_integer(sc, val));
55208 #else
55209       return(make_integer(sc, integer(x) - integer(opt2_con(cdr(arg)))));
55210 #endif
55211     }
55212 #endif
55213   return(subtract_p_pp(sc, x, opt2_con(cdr(arg)))); /* caddr(arg) */
55214 }
55215 
55216 static s7_pointer fx_subtract_sf(s7_scheme *sc, s7_pointer arg)
55217 {
55218   s7_pointer x;
55219   x = lookup(sc, cadr(arg));
55220   if (is_t_real(x))
55221     return(make_real(sc, real(x) - real(opt2_con(cdr(arg)))));                 /* caddr(arg) */
55222   return(g_subtract_2f(sc, set_plist_2(sc, x, opt2_con(cdr(arg)))));           /* caddr(arg) */
55223 }
55224 
55225 static s7_pointer fx_subtract_tf(s7_scheme *sc, s7_pointer arg)
55226 {
55227   s7_pointer x;
55228   x = t_lookup(sc, cadr(arg), arg);
55229   if (is_t_real(x))
55230     return(make_real(sc, real(x) - real(opt2_con(cdr(arg)))));       /* caddr(arg) */
55231   return(g_subtract_2f(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
55232 }
55233 
55234 static s7_pointer fx_subtract_ss(s7_scheme *sc, s7_pointer arg) {return(subtract_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55235 static s7_pointer fx_subtract_ts(s7_scheme *sc, s7_pointer arg) {return(subtract_p_pp(sc, t_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55236 static s7_pointer fx_subtract_tu(s7_scheme *sc, s7_pointer arg) {return(subtract_p_pp(sc, t_lookup(sc, cadr(arg), arg), u_lookup(sc, caddr(arg), arg)));}
55237 static s7_pointer fx_subtract_ut(s7_scheme *sc, s7_pointer arg) {return(subtract_p_pp(sc, u_lookup(sc, cadr(arg), arg), t_lookup(sc, caddr(arg), arg)));}
55238 static s7_pointer fx_subtract_us(s7_scheme *sc, s7_pointer arg) {return(subtract_p_pp(sc, u_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55239 
55240 static s7_pointer fx_subtract_fs(s7_scheme *sc, s7_pointer arg)
55241 {
55242   s7_pointer x;
55243   s7_double n;
55244 
55245   x = lookup(sc, opt2_sym(cdr(arg))); /* caddr(arg) */
55246   n = real(cadr(arg));
55247   switch (type(x))
55248     {
55249     case T_INTEGER: return(make_real(sc, n - integer(x)));
55250     case T_RATIO:   return(make_real(sc, n - fraction(x)));
55251     case T_REAL:    return(make_real(sc, n - real(x)));
55252     case T_COMPLEX: return(s7_make_complex(sc, n - real_part(x), -imag_part(x)));
55253 #if WITH_GMP
55254     case T_BIG_INTEGER: case T_BIG_RATIO: case T_BIG_REAL: case T_BIG_COMPLEX:
55255       return(subtract_p_pp(sc, wrap_real1(sc, n), x));
55256 #endif
55257     default:
55258       return(method_or_bust_with_type_pp(sc, x, sc->subtract_symbol, cadr(arg), x, a_number_string, 2));
55259     }
55260   return(x);
55261 }
55262 
55263 static s7_pointer fx_is_eq_sc(s7_scheme *sc, s7_pointer arg)
55264 {
55265   return(make_boolean(sc, lookup(sc, cadr(arg)) == opt2_con(cdr(arg)))); /* fx_choose checks that the second arg is not unspecified */
55266 }
55267 
55268 static s7_pointer fx_is_eq_tc(s7_scheme *sc, s7_pointer arg) {return(make_boolean(sc, t_lookup(sc, cadr(arg), arg) == opt2_con(cdr(arg))));}
55269 
55270 static s7_pointer fx_is_eq_car_q(s7_scheme *sc, s7_pointer arg)
55271 {
55272   s7_pointer lst, a;
55273   a = cdr(arg);
55274   lst = lookup(sc, opt3_sym(a));
55275   return(make_boolean(sc, (is_pair(lst)) ? (car(lst) == opt2_con(a)) : s7_is_eq(g_car(sc, set_plist_1(sc, lst)), opt2_con(a))));
55276 }
55277 
55278 static s7_pointer fx_is_eq_car_t_q(s7_scheme *sc, s7_pointer arg)
55279 {
55280   s7_pointer lst, a;
55281   a = cdr(arg);
55282   lst = t_lookup(sc, opt3_sym(a), arg);
55283   return(make_boolean(sc, (is_pair(lst)) ? (car(lst) == opt2_con(a)) : s7_is_eq(g_car(sc, set_plist_1(sc, lst)), opt2_con(a))));
55284 }
55285 
55286 static s7_pointer fx_is_eq_caar_q(s7_scheme *sc, s7_pointer arg)
55287 {
55288   s7_pointer lst, a;
55289   a = cdr(arg);
55290   lst = lookup(sc, opt3_sym(a));
55291   if ((is_pair(lst)) && (is_pair(car(lst))))
55292     return(make_boolean(sc, caar(lst) == opt2_con(a)));
55293   return(make_boolean(sc, s7_is_eq(g_caar(sc, set_plist_1(sc, lst)), opt2_con(a))));
55294 }
55295 
55296 static s7_pointer fx_not_is_eq_car_q(s7_scheme *sc, s7_pointer arg)
55297 {
55298   s7_pointer lst;
55299   lst = lookup(sc, opt1_sym(cdr(arg)));
55300   if (is_pair(lst))
55301     return(make_boolean(sc, car(lst) != opt3_con(cdr(arg))));
55302   return(make_boolean(sc, !s7_is_eq(g_car(sc, set_plist_1(sc, lst)), opt3_con(cdr(arg)))));
55303 }
55304 
55305 static s7_pointer fx_is_pair_car_s(s7_scheme *sc, s7_pointer arg)
55306 {
55307   s7_pointer p;
55308   p = lookup(sc, opt2_sym(cdr(arg)));
55309   if (is_pair(p))
55310     return(make_boolean(sc, is_pair(car(p))));
55311 
55312   if (has_active_methods(sc, p))
55313     {
55314       s7_pointer func;
55315       func = find_method_with_let(sc, p, sc->car_symbol);
55316       if (func != sc->undefined)
55317 	return(make_boolean(sc, is_pair(call_method(sc, p, func, set_plist_1(sc, p)))));
55318     }
55319   return(wrong_type_argument(sc, sc->car_symbol, 1, p, T_PAIR));
55320 }
55321 
55322 static s7_pointer fx_is_pair_car_t(s7_scheme *sc, s7_pointer arg)
55323 {
55324   s7_pointer p;
55325   p = t_lookup(sc, opt2_sym(cdr(arg)), arg);
55326   return((is_pair(p)) ? make_boolean(sc, is_pair(car(p))) : g_is_pair(sc, set_plist_1(sc, g_car(sc, set_plist_1(sc, p)))));
55327 }
55328 
55329 static s7_pointer fx_is_pair_cdr_s(s7_scheme *sc, s7_pointer arg)
55330 {
55331   s7_pointer p;
55332   p = lookup(sc, opt2_sym(cdr(arg)));
55333   return((is_pair(p)) ? make_boolean(sc, is_pair(cdr(p))) : g_is_pair(sc, set_plist_1(sc, g_cdr(sc, set_plist_1(sc, p)))));
55334 }
55335 
55336 static s7_pointer fx_is_pair_cdr_t(s7_scheme *sc, s7_pointer arg)
55337 {
55338   s7_pointer p;
55339   p = t_lookup(sc, opt2_sym(cdr(arg)), arg);
55340   return((is_pair(p)) ? make_boolean(sc, is_pair(cdr(p))) : g_is_pair(sc, set_plist_1(sc, g_cdr(sc, set_plist_1(sc, p)))));
55341 }
55342 
55343 static s7_pointer fx_is_pair_cadr_s(s7_scheme *sc, s7_pointer arg)
55344 {
55345   s7_pointer p;
55346   p = lookup(sc, opt2_sym(cdr(arg)));
55347   return(((is_pair(p)) && (is_pair(cdr(p)))) ? make_boolean(sc, is_pair(cadr(p))) : g_is_pair(sc, set_plist_1(sc, g_cadr(sc, set_plist_1(sc, p)))));
55348 }
55349 
55350 static s7_pointer fx_is_pair_cadr_t(s7_scheme *sc, s7_pointer arg)
55351 {
55352   s7_pointer p;
55353   p = t_lookup(sc, opt2_sym(cdr(arg)), arg);
55354   return((is_pair(p)) ? make_boolean(sc, is_pair(cadr(p))) : g_is_pair(sc, set_plist_1(sc, g_cadr(sc, set_plist_1(sc, p)))));
55355 }
55356 
55357 static s7_pointer fx_is_pair_cddr_s(s7_scheme *sc, s7_pointer arg)
55358 {
55359   s7_pointer p;
55360   p = lookup(sc, opt2_sym(cdr(arg)));
55361   return(((is_pair(p)) && (is_pair(cdr(p)))) ? make_boolean(sc, is_pair(cddr(p))) : g_is_pair(sc, set_plist_1(sc, g_cddr(sc, set_plist_1(sc, p)))));
55362 }
55363 
55364 static s7_pointer fx_is_pair_cddr_t(s7_scheme *sc, s7_pointer arg)
55365 {
55366   s7_pointer p;
55367   p = t_lookup(sc, opt2_sym(cdr(arg)), arg);
55368   return((is_pair(p)) ? make_boolean(sc, is_pair(cddr(p))) : g_is_pair(sc, set_plist_1(sc, g_cddr(sc, set_plist_1(sc, p)))));
55369 }
55370 
55371 static s7_pointer fx_is_null_cdr_s(s7_scheme *sc, s7_pointer arg)
55372 {
55373   s7_pointer p;
55374   p = lookup(sc, opt2_sym(cdr(arg)));
55375   return((is_pair(p)) ? make_boolean(sc, is_null(cdr(p))) : g_is_null(sc, set_plist_1(sc, g_cdr(sc, set_plist_1(sc, p)))));
55376 }
55377 
55378 static s7_pointer fx_is_null_cdr_t(s7_scheme *sc, s7_pointer arg)
55379 {
55380   s7_pointer p;
55381   p = t_lookup(sc, opt2_sym(cdr(arg)), arg);
55382   return((is_pair(p)) ? make_boolean(sc, is_null(cdr(p))) : g_is_null(sc, set_plist_1(sc, g_cdr(sc, set_plist_1(sc, p)))));
55383 }
55384 
55385 static s7_pointer fx_is_null_cddr_s(s7_scheme *sc, s7_pointer arg)
55386 {
55387   s7_pointer p;
55388   p = lookup(sc, opt2_sym(cdr(arg)));
55389   return(((is_pair(p)) && (is_pair(cdr(p)))) ? make_boolean(sc, is_null(cddr(p))) : g_is_null(sc, set_plist_1(sc, g_cddr(sc, set_plist_1(sc, p)))));
55390 }
55391 
55392 static s7_pointer fx_is_null_cddr_t(s7_scheme *sc, s7_pointer arg)
55393 {
55394   s7_pointer p;
55395   p = t_lookup(sc, opt2_sym(cdr(arg)), arg);
55396   return(((is_pair(p)) && (is_pair(cdr(p)))) ? make_boolean(sc, is_null(cddr(p))) : g_is_null(sc, set_plist_1(sc, g_cddr(sc, set_plist_1(sc, p)))));
55397 }
55398 
55399 static s7_pointer fx_is_null_cadr_s(s7_scheme *sc, s7_pointer arg)
55400 {
55401   s7_pointer p;
55402   p = lookup(sc, opt2_sym(cdr(arg)));
55403   return(((is_pair(p)) && (is_pair(cdr(p)))) ? make_boolean(sc, is_null(cadr(p))) : g_is_null(sc, set_plist_1(sc, g_cadr(sc, set_plist_1(sc, p)))));
55404 }
55405 
55406 static s7_pointer fx_is_symbol_cadr_s(s7_scheme *sc, s7_pointer arg)
55407 {
55408   s7_pointer p;
55409   p = lookup(sc, opt2_sym(cdr(arg)));
55410   return(((is_pair(p)) && (is_pair(cdr(p)))) ? make_boolean(sc, is_symbol(cadr(p))) : g_is_symbol(sc, set_plist_1(sc, g_cadr(sc, set_plist_1(sc, p)))));
55411 }
55412 
55413 static s7_pointer fx_is_symbol_cadr_t(s7_scheme *sc, s7_pointer arg)
55414 {
55415   s7_pointer p;
55416   p = t_lookup(sc, opt2_sym(cdr(arg)), arg);
55417   return(((is_pair(p)) && (is_pair(cdr(p)))) ? make_boolean(sc, is_symbol(cadr(p))) : g_is_symbol(sc, set_plist_1(sc, g_cadr(sc, set_plist_1(sc, p)))));
55418 }
55419 
55420 static s7_pointer fx_is_symbol_car_t(s7_scheme *sc, s7_pointer arg)
55421 {
55422   s7_pointer val;
55423   val = t_lookup(sc, opt2_sym(cdr(arg)), arg);
55424   return(make_boolean(sc, (is_pair(val)) ? is_symbol(car(val)) : is_symbol(g_car(sc, set_plist_1(sc, val)))));
55425 }
55426 
55427 #if WITH_GMP
55428 static s7_pointer fx_floor_sqrt_s(s7_scheme *sc, s7_pointer arg)
55429 {
55430   s7_pointer p;
55431   p = lookup(sc, opt2_sym(cdr(arg)));
55432   if (is_t_big_integer(p))
55433     {
55434       if (mpz_cmp_ui(big_integer(p), 0) >= 0) /* p >= 0 */
55435 	{
55436 	  mpz_sqrt(sc->mpz_1, big_integer(p));
55437 	  return(mpz_to_integer(sc, sc->mpz_1));
55438 	}}
55439   return(floor_p_p(sc, sqrt_p_p(sc, p)));
55440 }
55441 #endif
55442 
55443 static s7_pointer fx_c_s(s7_scheme *sc, s7_pointer arg)
55444 {
55445   set_car(sc->t1_1, lookup(sc, cadr(arg)));
55446   return(fn_proc(arg)(sc, sc->t1_1));
55447 }
55448 
55449 static s7_pointer fx_c_g(s7_scheme *sc, s7_pointer arg)
55450 {
55451   set_car(sc->t1_1, lookup_global(sc, cadr(arg)));
55452   return(fn_proc(arg)(sc, sc->t1_1));
55453 }
55454 
55455 static s7_pointer fx_c_g_direct(s7_scheme *sc, s7_pointer arg) {return(((s7_p_p_t)opt2_direct(cdr(arg)))(sc, lookup_global(sc, cadr(arg))));}
55456 
55457 static s7_pointer fx_c_t(s7_scheme *sc, s7_pointer arg)
55458 {
55459   set_car(sc->t1_1, t_lookup(sc, cadr(arg), arg));
55460   return(fn_proc(arg)(sc, sc->t1_1));
55461 }
55462 
55463 static s7_pointer fx_c_T(s7_scheme *sc, s7_pointer arg)
55464 {
55465   set_car(sc->t1_1, T_lookup(sc, cadr(arg), arg));
55466   return(fn_proc(arg)(sc, sc->t1_1));
55467 }
55468 
55469 static s7_pointer fx_c_u(s7_scheme *sc, s7_pointer arg)
55470 {
55471   set_car(sc->t1_1, u_lookup(sc, cadr(arg), arg));
55472   return(fn_proc(arg)(sc, sc->t1_1));
55473 }
55474 
55475 static s7_pointer fx_c_s_direct(s7_scheme *sc, s7_pointer arg) {return(((s7_p_p_t)opt2_direct(cdr(arg)))(sc, lookup(sc, cadr(arg))));}
55476 static s7_pointer fx_c_t_direct(s7_scheme *sc, s7_pointer arg) {return(((s7_p_p_t)opt2_direct(cdr(arg)))(sc, t_lookup(sc, cadr(arg), arg)));}
55477 static s7_pointer fx_c_u_direct(s7_scheme *sc, s7_pointer arg) {return(((s7_p_p_t)opt2_direct(cdr(arg)))(sc, u_lookup(sc, cadr(arg), arg)));}
55478 
55479 static s7_pointer fx_is_positive_u(s7_scheme *sc, s7_pointer arg)
55480 {
55481   s7_pointer p1;
55482   p1 = u_lookup(sc, cadr(arg), arg);
55483   if (is_t_integer(p1)) return(make_boolean(sc, integer(p1) > 0));
55484   return((is_t_real(p1)) ? make_boolean(sc, real(p1) > 0.0) : is_positive_p_p(sc, p1));
55485 }
55486 
55487 static s7_pointer fx_is_zero_u(s7_scheme *sc, s7_pointer arg)
55488 {
55489   s7_pointer p1;
55490   p1 = u_lookup(sc, cadr(arg), arg);
55491   return((is_t_integer(p1)) ? make_boolean(sc, integer(p1) == 0) : is_zero_p_p(sc, p1));
55492 }
55493 
55494 static s7_pointer fx_real_part_s(s7_scheme *sc, s7_pointer arg)
55495 {
55496   s7_pointer z;
55497   z = lookup(sc, cadr(arg));
55498   return((is_t_complex(z)) ? make_real(sc, real_part(z)) : real_part_p_p(sc, z));
55499 }
55500 
55501 static s7_pointer fx_imag_part_s(s7_scheme *sc, s7_pointer arg)
55502 {
55503   s7_pointer z;
55504   z = lookup(sc, cadr(arg));
55505   return((is_t_complex(z)) ? make_real(sc, imag_part(z)) : imag_part_p_p(sc, z));
55506 }
55507 
55508 static s7_pointer fx_iterate_p_p(s7_scheme *sc, s7_pointer arg)
55509 {
55510   s7_pointer iter;
55511   iter = lookup(sc, cadr(arg));
55512   if (is_iterator(iter))
55513     return((iterator_next(iter))(sc, iter));
55514   return(method_or_bust_one_arg_p(sc, iter, sc->iterate_symbol, T_ITERATOR));
55515 }
55516 
55517 static s7_pointer fx_length_s(s7_scheme *sc, s7_pointer arg) {return(s7_length(sc, lookup(sc, cadr(arg))));}
55518 static s7_pointer fx_length_t(s7_scheme *sc, s7_pointer arg) {return(s7_length(sc, t_lookup(sc, cadr(arg), arg)));}
55519 
55520 static s7_pointer fx_num_eq_length_i(s7_scheme *sc, s7_pointer arg)
55521 {
55522   /* avoid make_integer (and telescope opts), we get here with car=length expr, cadr=int */
55523   s7_int ilen;
55524   s7_pointer val;
55525 
55526   val = lookup(sc, opt3_sym(cdr(arg)));
55527   ilen = integer(opt2_con(cdr(arg))); /* is_t_integer checked in fx_choose */
55528 
55529   switch (type(val))
55530     {
55531     case T_PAIR:       return(make_boolean(sc, s7_list_length(sc, val) == ilen));
55532     case T_NIL:        return(make_boolean(sc, ilen == 0));
55533     case T_STRING:     return(make_boolean(sc, string_length(val) == ilen));
55534     case T_HASH_TABLE: return(make_boolean(sc, (hash_table_mask(val) + 1) == ilen));
55535     case T_C_OBJECT:   return(make_boolean(sc, c_object_length_to_int(sc, val) == ilen));
55536     case T_LET:        return(make_boolean(sc, let_length(sc, val) == ilen));
55537 
55538     case T_BYTE_VECTOR: case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_VECTOR:
55539       return(make_boolean(sc, vector_length(val) == ilen));
55540 
55541     case T_ITERATOR:
55542       {
55543 	s7_pointer len;
55544 	len = s7_length(sc, iterator_sequence(val));
55545 	return(make_boolean(sc, (is_t_integer(len)) && (integer(len) == ilen)));
55546       }
55547 
55548     case T_CLOSURE:
55549     case T_CLOSURE_STAR:
55550       if (has_active_methods(sc, val))
55551 	return(make_boolean(sc, closure_length(sc, val) == ilen));
55552       /* fall through */
55553 
55554     default:
55555       return(simple_wrong_type_argument_with_type(sc, sc->length_symbol, val, a_sequence_string));
55556       /* here we already lost because we checked for the length above */
55557     }
55558   return(sc->F);
55559 }
55560 
55561 static s7_pointer fx_less_length_i(s7_scheme *sc, s7_pointer arg)
55562 {
55563   s7_int ilen;
55564   s7_pointer val;
55565 
55566   val = lookup(sc, opt3_sym(cdr(arg)));  /* cadadr(arg) */
55567   ilen = integer(opt2_con(cdr(arg)));    /* caddr(arg) */
55568 
55569   switch (type(val))
55570     {
55571     case T_PAIR:       return(make_boolean(sc, s7_list_length(sc, val) < ilen));
55572     case T_NIL:        return(make_boolean(sc, ilen > 0));
55573     case T_STRING:     return(make_boolean(sc, string_length(val) < ilen));
55574     case T_HASH_TABLE: return(make_boolean(sc, (hash_table_mask(val) + 1) < ilen)); /* was <=? -- changed 15-Dec-15, then again 6-Jan-17: mask is len-1 */
55575     case T_C_OBJECT:   return(make_boolean(sc, c_object_length_to_int(sc, val) < ilen));
55576     case T_LET:        return(make_boolean(sc, let_length(sc, val) < ilen));  /* this works because let_length handles the length method itself! */
55577 
55578     case T_BYTE_VECTOR: case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_VECTOR:
55579       return(make_boolean(sc, vector_length(val) < ilen));
55580 
55581     case T_ITERATOR:
55582       {
55583 	s7_pointer len;
55584 	len = s7_length(sc, iterator_sequence(val));
55585 	return(make_boolean(sc, (is_t_integer(len)) && (integer(len) < ilen)));
55586       }
55587 
55588     case T_CLOSURE:
55589     case T_CLOSURE_STAR:
55590       if (has_active_methods(sc, val))
55591 	return(make_boolean(sc, closure_length(sc, val) < ilen));
55592       /* fall through */
55593 
55594     default:
55595       return(simple_wrong_type_argument_with_type(sc, sc->length_symbol, val, a_sequence_string)); /* no check method here because we checked above */
55596     }
55597   return(sc->F);
55598 }
55599 
55600 static s7_pointer fx_cdr_s(s7_scheme *sc, s7_pointer arg)
55601 {
55602   s7_pointer val;
55603   val = lookup(sc, cadr(arg));
55604   return((is_pair(val)) ? cdr(val) : g_cdr(sc, set_plist_1(sc, val)));
55605 }
55606 
55607 static s7_pointer fx_cdr_t(s7_scheme *sc, s7_pointer arg)
55608 {
55609   s7_pointer val;
55610   val = t_lookup(sc, cadr(arg), arg);
55611   return((is_pair(val)) ? cdr(val) : g_cdr(sc, set_plist_1(sc, val)));
55612 }
55613 
55614 static s7_pointer fx_cdr_u(s7_scheme *sc, s7_pointer arg)
55615 {
55616   s7_pointer val;
55617   val = u_lookup(sc, cadr(arg), arg);
55618   return((is_pair(val)) ? cdr(val) : g_cdr(sc, set_plist_1(sc, val)));
55619 }
55620 
55621 static s7_pointer fx_car_s(s7_scheme *sc, s7_pointer arg)
55622 {
55623   s7_pointer val;
55624   val = lookup(sc, cadr(arg));
55625   return((is_pair(val)) ? car(val) : g_car(sc, set_plist_1(sc, val)));
55626 }
55627 
55628 static s7_pointer fx_car_t(s7_scheme *sc, s7_pointer arg)
55629 {
55630   s7_pointer val;
55631   val = t_lookup(sc, cadr(arg), arg);
55632   return((is_pair(val)) ? car(val) : g_car(sc, set_plist_1(sc, val)));
55633 }
55634 
55635 static s7_pointer fx_car_u(s7_scheme *sc, s7_pointer arg)
55636 {
55637   s7_pointer val;
55638   val = u_lookup(sc, cadr(arg), arg);
55639   return((is_pair(val)) ? car(val) : g_car(sc, set_plist_1(sc, val)));
55640 }
55641 
55642 static s7_pointer fx_cadr_s(s7_scheme *sc, s7_pointer arg)
55643 {
55644   s7_pointer val;
55645   val = lookup(sc, cadr(arg));
55646   return(((is_pair(val)) && (is_pair(cdr(val)))) ? cadr(val) : g_cadr(sc, set_plist_1(sc, val)));
55647 }
55648 
55649 static s7_pointer fx_cadr_t(s7_scheme *sc, s7_pointer arg)
55650 {
55651   s7_pointer val;
55652   val = t_lookup(sc, cadr(arg), arg);
55653   return(((is_pair(val)) && (is_pair(cdr(val)))) ? cadr(val) : g_cadr(sc, set_plist_1(sc, val)));
55654 }
55655 
55656 static s7_pointer fx_cddr_s(s7_scheme *sc, s7_pointer arg)
55657 {
55658   s7_pointer val;
55659   val = lookup(sc, cadr(arg));
55660   return(((is_pair(val)) && (is_pair(cdr(val)))) ? cddr(val) : g_cddr(sc, set_plist_1(sc, val)));
55661 }
55662 
55663 static s7_pointer fx_cddr_t(s7_scheme *sc, s7_pointer arg)
55664 {
55665   s7_pointer p;
55666   p = t_lookup(sc, cadr(arg), arg);
55667   return(((is_pair(p)) && (is_pair(cdr(p)))) ? cddr(p) : g_cddr(sc, set_plist_1(sc, p)));
55668 }
55669 
55670 static s7_pointer fx_cddr_u(s7_scheme *sc, s7_pointer arg)
55671 {
55672   s7_pointer p;
55673   p = u_lookup(sc, cadr(arg), arg);
55674   return(((is_pair(p)) && (is_pair(cdr(p)))) ? cddr(p) : g_cddr(sc, set_plist_1(sc, p)));
55675 }
55676 
55677 static s7_pointer fx_is_null_s(s7_scheme *sc, s7_pointer arg)   {return((is_null(lookup(sc, cadr(arg)))) ? sc->T : sc->F);}
55678 static s7_pointer fx_is_null_t(s7_scheme *sc, s7_pointer arg)   {return((is_null(t_lookup(sc, cadr(arg), arg))) ? sc->T : sc->F);}
55679 static s7_pointer fx_is_null_u(s7_scheme *sc, s7_pointer arg)   {return((is_null(u_lookup(sc, cadr(arg), arg))) ? sc->T : sc->F);}
55680 static s7_pointer fx_is_symbol_s(s7_scheme *sc, s7_pointer arg) {return((is_symbol(lookup(sc, cadr(arg)))) ? sc->T : sc->F);}
55681 static s7_pointer fx_is_symbol_t(s7_scheme *sc, s7_pointer arg) {return((is_symbol(t_lookup(sc, cadr(arg), arg))) ? sc->T : sc->F);}
55682 static s7_pointer fx_is_eof_s(s7_scheme *sc, s7_pointer arg)    {return((lookup(sc, cadr(arg)) == eof_object) ? sc->T : sc->F);}
55683 static s7_pointer fx_is_eof_t(s7_scheme *sc, s7_pointer arg)    {return((t_lookup(sc, cadr(arg), arg) == eof_object) ? sc->T : sc->F);}
55684 static s7_pointer fx_is_type_s(s7_scheme *sc, s7_pointer arg)   {return(make_boolean(sc, (uint8_t)(opt3_byte(cdr(arg))) == type(lookup(sc, cadr(arg)))));}
55685 static s7_pointer fx_is_type_t(s7_scheme *sc, s7_pointer arg)   {return(make_boolean(sc, (uint8_t)(opt3_byte(cdr(arg))) == type(t_lookup(sc, cadr(arg), arg))));}
55686 static s7_pointer fx_is_type_u(s7_scheme *sc, s7_pointer arg)   {return(make_boolean(sc, (uint8_t)(opt3_byte(cdr(arg))) == type(u_lookup(sc, cadr(arg), arg))));}
55687 
55688 static s7_pointer fx_is_integer_s(s7_scheme *sc, s7_pointer arg)
55689 {
55690 #if WITH_GMP
55691   return((s7_is_integer(lookup(sc, cadr(arg)))) ? sc->T : sc->F);
55692 #else
55693   return((is_t_integer(lookup(sc, cadr(arg)))) ? sc->T : sc->F);
55694 #endif
55695 }
55696 
55697 static s7_pointer fx_is_string_s(s7_scheme *sc, s7_pointer arg)    {return((is_string(lookup(sc, cadr(arg)))) ? sc->T : sc->F);}
55698 static s7_pointer fx_is_string_t(s7_scheme *sc, s7_pointer arg)    {return((is_string(t_lookup(sc, cadr(arg), arg))) ? sc->T : sc->F);}
55699 static s7_pointer fx_is_procedure_s(s7_scheme *sc, s7_pointer arg) {return((is_procedure(lookup(sc, cadr(arg)))) ? sc->T : sc->F);}
55700 static s7_pointer fx_is_pair_s(s7_scheme *sc, s7_pointer arg)      {return((is_pair(lookup(sc, cadr(arg)))) ? sc->T : sc->F);}
55701 static s7_pointer fx_is_pair_t(s7_scheme *sc, s7_pointer arg)      {return((is_pair(t_lookup(sc, cadr(arg), arg))) ? sc->T : sc->F);}
55702 static s7_pointer fx_is_pair_u(s7_scheme *sc, s7_pointer arg)      {return((is_pair(u_lookup(sc, cadr(arg), arg))) ? sc->T : sc->F);}
55703 static s7_pointer fx_is_keyword_s(s7_scheme *sc, s7_pointer arg)   {return((is_keyword(lookup(sc, cadr(arg)))) ? sc->T : sc->F);}
55704 static s7_pointer fx_is_vector_s(s7_scheme *sc, s7_pointer arg)    {return((is_any_vector(lookup(sc, cadr(arg)))) ? sc->T : sc->F);}
55705 static s7_pointer fx_is_vector_t(s7_scheme *sc, s7_pointer arg)    {return((is_any_vector(t_lookup(sc, cadr(arg), arg))) ? sc->T : sc->F);}
55706 static s7_pointer fx_is_proper_list_s(s7_scheme *sc, s7_pointer arg) {return((s7_is_proper_list(sc, lookup(sc, cadr(arg)))) ? sc->T : sc->F);}
55707 static s7_pointer fx_not_s(s7_scheme *sc, s7_pointer arg) {return(make_boolean(sc, is_false(sc, lookup(sc, cadr(arg)))));}
55708 static s7_pointer fx_not_t(s7_scheme *sc, s7_pointer arg) {return(make_boolean(sc, is_false(sc, t_lookup(sc, cadr(arg), arg))));}
55709 static s7_pointer fx_not_is_pair_s(s7_scheme *sc, s7_pointer arg)  {return((is_pair(lookup(sc, opt3_sym(arg)))) ? sc->F : sc->T);}
55710 static s7_pointer fx_not_is_pair_t(s7_scheme *sc, s7_pointer arg)  {return((is_pair(t_lookup(sc, opt3_sym(arg), arg))) ? sc->F : sc->T);}
55711 static s7_pointer fx_not_is_null_s(s7_scheme *sc, s7_pointer arg)  {return((is_null(lookup(sc, opt3_sym(arg)))) ? sc->F : sc->T);}
55712 static s7_pointer fx_not_is_null_t(s7_scheme *sc, s7_pointer arg)  {return((is_null(t_lookup(sc, opt3_sym(arg), arg))) ? sc->F : sc->T);}
55713 static s7_pointer fx_not_is_null_u(s7_scheme *sc, s7_pointer arg)  {return((is_null(u_lookup(sc, opt3_sym(arg), arg))) ? sc->F : sc->T);}
55714 static s7_pointer fx_not_is_symbol_s(s7_scheme *sc, s7_pointer arg) {return((is_symbol(lookup(sc, opt3_sym(arg)))) ? sc->F : sc->T);}
55715 static s7_pointer fx_not_is_symbol_t(s7_scheme *sc, s7_pointer arg) {return((is_symbol(t_lookup(sc, opt3_sym(arg), arg))) ? sc->F : sc->T);}
55716 
55717 static s7_pointer fx_c_sc(s7_scheme *sc, s7_pointer arg)
55718 {
55719   set_car(sc->t2_1, lookup(sc, cadr(arg)));
55720   set_car(sc->t2_2, opt2_con(cdr(arg)));
55721   return(fn_proc(arg)(sc, sc->t2_1));
55722 }
55723 
55724 static s7_pointer fx_c_tc(s7_scheme *sc, s7_pointer arg)
55725 {
55726   set_car(sc->t2_1, t_lookup(sc, cadr(arg), arg));
55727   set_car(sc->t2_2, T_Pos(opt2_con(cdr(arg))));
55728   return(fn_proc(arg)(sc, sc->t2_1));
55729 }
55730 
55731 static s7_pointer fx_c_sc_direct(s7_scheme *sc, s7_pointer arg) {return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)), opt2_con(cdr(arg))));}
55732 static s7_pointer fx_c_si_direct(s7_scheme *sc, s7_pointer arg) {return(((s7_p_pi_t)opt3_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)), integer(opt2_con(cdr(arg)))));}
55733 
55734 static s7_pointer fx_c_ti_direct(s7_scheme *sc, s7_pointer arg)
55735 {
55736   return(((s7_p_pi_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, cadr(arg), arg), integer(opt2_con(cdr(arg)))));
55737 }
55738 
55739 static s7_pointer fx_memq_sc(s7_scheme *sc, s7_pointer arg)   {return(memq_p_pp(sc, lookup(sc, cadr(arg)), opt2_con(cdr(arg))));}
55740 static s7_pointer fx_memq_sc_3(s7_scheme *sc, s7_pointer arg) {return(memq_3_p_pp(sc, lookup(sc, cadr(arg)), opt2_con(cdr(arg))));}
55741 static s7_pointer fx_leq_sc(s7_scheme *sc, s7_pointer arg)  {return(leq_p_pp(sc, lookup(sc, cadr(arg)), opt2_con(cdr(arg))));}
55742 static s7_pointer fx_lt_sc(s7_scheme *sc, s7_pointer arg)   {return(lt_p_pp(sc, lookup(sc, cadr(arg)), opt2_con(cdr(arg))));}
55743 static s7_pointer fx_gt_sc(s7_scheme *sc, s7_pointer arg)   {return(gt_p_pp(sc, lookup(sc, cadr(arg)), opt2_con(cdr(arg))));}
55744 static s7_pointer fx_geq_sc(s7_scheme *sc, s7_pointer arg)  {return(geq_p_pp(sc, lookup(sc, cadr(arg)), opt2_con(cdr(arg))));}
55745 static s7_pointer fx_char_eq_sc(s7_scheme *sc, s7_pointer arg)
55746 {
55747   s7_pointer c;
55748   c = lookup(sc, cadr(arg));
55749   if (s7_is_character(c))
55750     return(make_boolean(sc, character(c) == character(opt2_con(cdr(arg)))));
55751   return(simple_wrong_type_argument(sc, sc->char_eq_symbol, cadr(arg), T_CHARACTER));
55752 }
55753 
55754 static s7_pointer fx_c_tc_direct(s7_scheme *sc, s7_pointer arg) {return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, cadr(arg), arg), opt2_con(cdr(arg))));}
55755 static s7_pointer fx_vector_ref_direct(s7_scheme *sc, s7_pointer arg) {return(vector_ref_p_pi(sc, t_lookup(sc, cadr(arg), arg), integer(opt2_con(cdr(arg)))));}
55756 
55757 static s7_pointer fx_c_uc(s7_scheme *sc, s7_pointer arg) /* few hits */
55758 {
55759   set_car(sc->t2_1, u_lookup(sc, cadr(arg), arg));
55760   set_car(sc->t2_2, opt2_con(cdr(arg)));
55761   return(fn_proc(arg)(sc, sc->t2_1));
55762 }
55763 
55764 static s7_pointer fx_char_eq_tc(s7_scheme *sc, s7_pointer arg)
55765 {
55766   s7_pointer c;
55767   c = t_lookup(sc, cadr(arg), arg);
55768   if (c == opt2_con(cdr(arg)))
55769     return(sc->T);
55770   if (s7_is_character(c))
55771     return(sc->F);
55772   return(method_or_bust(sc, cadr(arg), sc->char_eq_symbol, cdr(arg), T_CHARACTER, 1));
55773 }
55774 
55775 static s7_pointer fx_c_cs(s7_scheme *sc, s7_pointer arg)
55776 {
55777   set_car(sc->t2_1, opt1_con(cdr(arg))); /* cadr(arg) or cadadr */
55778   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(arg)))); /* caddr(arg) */
55779   return(fn_proc(arg)(sc, sc->t2_1));
55780 }
55781 
55782 static s7_pointer fx_c_ct(s7_scheme *sc, s7_pointer arg)
55783 {
55784   set_car(sc->t2_1, opt1_con(cdr(arg))); /* cadr(arg) or cadadr */
55785   set_car(sc->t2_2, t_lookup(sc, caddr(arg), arg));
55786   return(fn_proc(arg)(sc, sc->t2_1));
55787 }
55788 
55789 static s7_pointer fx_c_ct_direct(s7_scheme *sc, s7_pointer arg)
55790 {
55791   return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, opt1_con(cdr(arg)), t_lookup(sc, caddr(arg), arg)));
55792 }
55793 
55794 static s7_pointer fx_c_ct_cons(s7_scheme *sc, s7_pointer arg) {return(cons_p_pp(sc, opt1_con(cdr(arg)), t_lookup(sc, caddr(arg), arg)));}
55795 
55796 static s7_pointer fx_c_cu(s7_scheme *sc, s7_pointer arg)
55797 {
55798   set_car(sc->t2_1, opt1_con(cdr(arg))); /* cadr(arg) or cadadr */
55799   set_car(sc->t2_2, u_lookup(sc, caddr(arg), arg));
55800   return(fn_proc(arg)(sc, sc->t2_1));
55801 }
55802 
55803 static s7_pointer fx_c_ss(s7_scheme *sc, s7_pointer arg)
55804 {
55805   set_car(sc->t2_1, lookup(sc, cadr(arg)));
55806   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(arg))));
55807   return(fn_proc(arg)(sc, sc->t2_1));
55808 }
55809 
55810 static s7_pointer fx_c_ss_direct(s7_scheme *sc, s7_pointer arg)
55811 {
55812   return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));
55813 }
55814 
55815 static s7_pointer fx_memq_ss(s7_scheme *sc, s7_pointer arg) {return(memq_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55816 static s7_pointer fx_assq_ss(s7_scheme *sc, s7_pointer arg) {return(assq_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55817 static s7_pointer fx_vref_ss(s7_scheme *sc, s7_pointer arg) {return(vector_ref_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55818 static s7_pointer fx_vref_st(s7_scheme *sc, s7_pointer arg) {return(vector_ref_p_pp(sc, lookup(sc, cadr(arg)), t_lookup(sc, opt2_sym(cdr(arg)), arg)));}
55819 static s7_pointer fx_vref_gt(s7_scheme *sc, s7_pointer arg) {return(vector_ref_p_pp(sc, lookup_global(sc, cadr(arg)), t_lookup(sc, opt2_sym(cdr(arg)), arg)));}
55820 static s7_pointer fx_string_ref_ss(s7_scheme *sc, s7_pointer arg) {return(string_ref_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55821 
55822 static s7_pointer fx_c_ts_direct(s7_scheme *sc, s7_pointer arg)
55823 {
55824   return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));
55825 }
55826 
55827 static s7_pointer fx_c_st_direct(s7_scheme *sc, s7_pointer arg)
55828 {
55829   return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)), t_lookup(sc, caddr(arg), arg)));
55830 }
55831 
55832 static s7_pointer fx_c_gt_direct(s7_scheme *sc, s7_pointer arg)
55833 {
55834   return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup_global(sc, cadr(arg)), t_lookup(sc, caddr(arg), arg)));
55835 }
55836 
55837 static s7_pointer fx_c_st(s7_scheme *sc, s7_pointer arg)
55838 {
55839   set_car(sc->t2_1, lookup(sc, cadr(arg)));
55840   set_car(sc->t2_2, t_lookup(sc, opt2_sym(cdr(arg)), arg));
55841   return(fn_proc(arg)(sc, sc->t2_1));
55842 }
55843 
55844 static s7_pointer fx_c_ts(s7_scheme *sc, s7_pointer arg)
55845 {
55846   set_car(sc->t2_1, t_lookup(sc, cadr(arg), arg));
55847   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(arg))));
55848   return(fn_proc(arg)(sc, sc->t2_1));
55849 }
55850 
55851 static s7_pointer fx_c_tu(s7_scheme *sc, s7_pointer arg)
55852 {
55853   set_car(sc->t2_1, t_lookup(sc, cadr(arg), arg));
55854   set_car(sc->t2_2, u_lookup(sc, caddr(arg), arg));
55855   return(fn_proc(arg)(sc, sc->t2_1));
55856 }
55857 
55858 static s7_pointer fx_c_tU(s7_scheme *sc, s7_pointer arg)
55859 {
55860   set_car(sc->t2_1, t_lookup(sc, cadr(arg), arg));
55861   set_car(sc->t2_2, U_lookup(sc, caddr(arg), arg));
55862   return(fn_proc(arg)(sc, sc->t2_1));
55863 }
55864 
55865 static s7_pointer fx_c_tU_direct(s7_scheme *sc, s7_pointer arg)
55866 {
55867   return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, cadr(arg), arg), U_lookup(sc, caddr(arg), arg)));
55868 }
55869 
55870 static s7_pointer fx_cons_ss(s7_scheme *sc, s7_pointer arg) {return(cons(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55871 static s7_pointer fx_cons_ts(s7_scheme *sc, s7_pointer arg) {return(cons(sc, t_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55872 static s7_pointer fx_cons_tU(s7_scheme *sc, s7_pointer arg) {return(cons(sc, t_lookup(sc, cadr(arg), arg), U_lookup(sc, caddr(arg), arg)));}
55873 
55874 static s7_pointer fx_multiply_ss(s7_scheme *sc, s7_pointer arg) {return(multiply_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55875 static s7_pointer fx_multiply_ts(s7_scheme *sc, s7_pointer arg) {return(multiply_p_pp(sc, t_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55876 static s7_pointer fx_multiply_Ts(s7_scheme *sc, s7_pointer arg) {return(multiply_p_pp(sc, T_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55877 static s7_pointer fx_multiply_fs(s7_scheme *sc, s7_pointer arg) {return(g_mul_xf(sc, lookup(sc, opt2_sym(cdr(arg))), real(cadr(arg))));}
55878 static s7_pointer fx_multiply_sf(s7_scheme *sc, s7_pointer arg) {return(g_mul_xf(sc, lookup(sc, cadr(arg)), real(opt2_con(cdr(arg)))));}
55879 static s7_pointer fx_multiply_tf(s7_scheme *sc, s7_pointer arg) {return(g_mul_xf(sc, t_lookup(sc, cadr(arg), arg), real(opt2_con(cdr(arg)))));}
55880 static s7_pointer fx_multiply_si(s7_scheme *sc, s7_pointer arg) {return(g_mul_xi(sc, lookup(sc, cadr(arg)), integer(opt2_con(cdr(arg)))));}
55881 static s7_pointer fx_multiply_is(s7_scheme *sc, s7_pointer arg) {return(g_mul_xi(sc, lookup(sc, opt2_sym(cdr(arg))), integer(cadr(arg))));}
55882 static s7_pointer fx_multiply_tu(s7_scheme *sc, s7_pointer arg) {return(multiply_p_pp(sc, t_lookup(sc, cadr(arg), arg), u_lookup(sc, caddr(arg), arg)));}
55883 
55884 static inline s7_pointer fx_sqr_1(s7_scheme *sc, s7_pointer x)
55885 {
55886   if (is_t_real(x)) return(make_real(sc, real(x) * real(x)));
55887 
55888 #if WITH_GMP
55889   return(multiply_p_pp(sc, x, x));
55890 #else
55891   switch (type(x))
55892     {
55893 #if HAVE_OVERFLOW_CHECKS
55894     case T_INTEGER:
55895       {
55896 	s7_int val;
55897 	if (multiply_overflow(integer(x), integer(x), &val))
55898 	  return(make_real(sc, (long_double)integer(x) * (long_double)integer(x)));
55899 	return(make_integer(sc, val));
55900       }
55901     case T_RATIO:
55902       {
55903 	s7_int num, den;
55904 	if ((multiply_overflow(numerator(x), numerator(x), &num)) ||
55905 	    (multiply_overflow(denominator(x), denominator(x), &den)))
55906 	  return(make_real(sc, fraction(x) * fraction(x)));
55907 	return(s7_make_ratio(sc, num, den));
55908       }
55909 #else
55910     case T_INTEGER: return(make_integer(sc, integer(x) * integer(x)));
55911     case T_RATIO:   return(s7_make_ratio(sc, numerator(x) * numerator(x), denominator(x) * denominator(x)));
55912 #endif
55913     case T_REAL:    return(make_real(sc, real(x) * real(x)));
55914     case T_COMPLEX: return(s7_make_complex(sc, real_part(x) * real_part(x) - imag_part(x) * imag_part(x), 2.0 * real_part(x) * imag_part(x)));
55915     default:        return(method_or_bust_with_type_pp(sc, x, sc->multiply_symbol, x, x, a_number_string, 1));
55916     }
55917   return(x);
55918 #endif
55919 }
55920 
55921 static s7_pointer fx_sqr_s(s7_scheme *sc, s7_pointer arg) {return(fx_sqr_1(sc, lookup(sc, cadr(arg))));}
55922 static s7_pointer fx_sqr_t(s7_scheme *sc, s7_pointer arg) {return(fx_sqr_1(sc, t_lookup(sc, cadr(arg), arg)));}
55923 
55924 static s7_pointer fx_c_sqr_sqr(s7_scheme *sc, s7_pointer arg)  /* tbig -- need t case here */
55925 {
55926   set_car(sc->t2_1, fx_sqr_1(sc, lookup(sc, cadr(cadr(arg)))));
55927   set_car(sc->t2_2, fx_sqr_1(sc, lookup(sc, car(opt3_pair(arg))))); /* cadaddr(arg)))); */
55928   return(fn_proc(arg)(sc, sc->t2_1));
55929 }
55930 
55931 static s7_pointer fx_c_s_sqr(s7_scheme *sc, s7_pointer arg) /* call */
55932 {
55933   set_car(sc->t2_1, lookup(sc, cadr(arg)));
55934   set_car(sc->t2_2, fx_sqr_1(sc, lookup(sc, opt2_sym(cdr(arg))))); /* cadaddr(arg) */
55935   return(fn_proc(arg)(sc, sc->t2_1));
55936 }
55937 
55938 static s7_pointer fx_c_c_sqr(s7_scheme *sc, s7_pointer arg) /* fb */
55939 {
55940   set_car(sc->t2_2, fx_sqr_1(sc, lookup(sc, opt1_sym(cdr(arg))))); /* cadaddr(arg) */
55941   set_car(sc->t2_1, cadr(arg));
55942   return(fn_proc(arg)(sc, sc->t2_1));
55943 }
55944 
55945 static s7_pointer fx_geq_ss(s7_scheme *sc, s7_pointer arg) {return(geq_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55946 static s7_pointer fx_geq_ts(s7_scheme *sc, s7_pointer arg) {return(geq_p_pp(sc, t_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55947 static s7_pointer fx_geq_us(s7_scheme *sc, s7_pointer arg) {return(geq_p_pp(sc, u_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55948 static s7_pointer fx_geq_tT(s7_scheme *sc, s7_pointer arg) {return(geq_p_pp(sc, t_lookup(sc, cadr(arg), arg), T_lookup(sc, caddr(arg), arg)));}
55949 static s7_pointer fx_geq_tu(s7_scheme *sc, s7_pointer arg) {return(geq_p_pp(sc, t_lookup(sc, cadr(arg), arg), u_lookup(sc, caddr(arg), arg)));}
55950 
55951 static s7_pointer fx_gt_ss(s7_scheme *sc, s7_pointer arg) {return(gt_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55952 static s7_pointer fx_gt_ts(s7_scheme *sc, s7_pointer arg) {return(gt_p_pp(sc, t_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55953 static s7_pointer fx_gt_tu(s7_scheme *sc, s7_pointer arg) {return(gt_p_pp(sc, t_lookup(sc, cadr(arg), arg), u_lookup(sc, caddr(arg), arg)));}
55954 static s7_pointer fx_gt_ut(s7_scheme *sc, s7_pointer arg) {return(gt_p_pp(sc, u_lookup(sc, cadr(arg), arg), t_lookup(sc, caddr(arg), arg)));}
55955 static s7_pointer fx_gt_tg(s7_scheme *sc, s7_pointer arg) {return(gt_p_pp(sc, t_lookup(sc, cadr(arg), arg), global_value(opt2_sym(cdr(arg)))));}
55956 
55957 static s7_pointer fx_gt_tT(s7_scheme *sc, s7_pointer arg)
55958 {
55959   s7_pointer p1, p2;
55960   p1 = t_lookup(sc, cadr(arg), arg);
55961   p2 = T_lookup(sc, caddr(arg), arg);
55962   return(((is_t_integer(p1)) && (is_t_integer(p2))) ? make_boolean(sc, integer(p1) > integer(p2)) : gt_p_pp(sc, p1, p2));
55963 }
55964 
55965 static s7_pointer fx_gt_ti(s7_scheme *sc, s7_pointer arg)
55966 {
55967   s7_pointer x;
55968   x = t_lookup(sc, cadr(arg), arg);
55969   if (is_t_integer(x)) return(make_boolean(sc, integer(x) > integer(opt2_con(cdr(arg)))));
55970   return(g_greater_xi(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
55971 }
55972 
55973 static s7_pointer fx_gt_si(s7_scheme *sc, s7_pointer arg)
55974 {
55975   s7_pointer x;
55976   x = lookup(sc, cadr(arg));
55977   if (is_t_integer(x)) return(make_boolean(sc, integer(x) > integer(opt2_con(cdr(arg)))));
55978   if (is_t_real(x)) return(make_boolean(sc, real(x) > integer(opt2_con(cdr(arg)))));
55979   return(g_greater_xi(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
55980 }
55981 
55982 static s7_pointer fx_leq_ss(s7_scheme *sc, s7_pointer arg) {return(leq_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55983 static s7_pointer fx_leq_ts(s7_scheme *sc, s7_pointer arg) {return(leq_p_pp(sc, t_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
55984 static s7_pointer fx_leq_tu(s7_scheme *sc, s7_pointer arg) {return(leq_p_pp(sc, t_lookup(sc, cadr(arg), arg), u_lookup(sc, caddr(arg), arg)));}
55985 
55986 static s7_pointer fx_leq_ti(s7_scheme *sc, s7_pointer arg)
55987 {
55988   s7_pointer x;
55989   x = t_lookup(sc, cadr(arg), arg);
55990   if (is_t_integer(x)) return(make_boolean(sc, integer(x) <= integer(opt2_con(cdr(arg)))));
55991   return(g_leq_xi(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
55992 }
55993 
55994 static s7_pointer fx_lt_ss(s7_scheme *sc, s7_pointer arg) {return(lt_p_pp(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
55995 static s7_pointer fx_lt_sg(s7_scheme *sc, s7_pointer arg) {return(lt_p_pp(sc, lookup(sc, cadr(arg)), lookup_global(sc, opt2_sym(cdr(arg)))));}
55996 static s7_pointer fx_lt_tg(s7_scheme *sc, s7_pointer arg) {return(lt_p_pp(sc, t_lookup(sc, cadr(arg), arg), lookup_global(sc, opt2_sym(cdr(arg)))));}
55997 
55998 static s7_pointer fx_lt_gsg(s7_scheme *sc, s7_pointer arg)
55999 {
56000   s7_pointer v1, v2, v3;
56001   v1 = lookup_global(sc, cadr(arg));
56002   v2 = lookup(sc, opt1_sym(cdr(arg)));        /* caddr(arg) */
56003   v3 = lookup_global(sc, opt2_sym(cdr(arg))); /* cadddr(arg) */
56004   if ((is_t_integer(v1)) && (is_t_integer(v2)) && (is_t_integer(v3)))
56005     return(make_boolean(sc, ((v1 < v2) && (v2 < v3))));
56006   if (!is_real(v3)) wrong_type_argument(sc, sc->lt_symbol, 3, v3, T_REAL); /* else (< 2 1 1+i) returns #f */
56007   return(make_boolean(sc, (lt_b_7pp(sc, v1, v2)) && (lt_b_7pp(sc, v2, v3))));
56008 }
56009 
56010 static s7_pointer fx_lt_ts(s7_scheme *sc, s7_pointer arg) {return(lt_p_pp(sc, t_lookup(sc, cadr(arg), arg), lookup(sc, opt2_sym(cdr(arg)))));}
56011 static s7_pointer fx_lt_tu(s7_scheme *sc, s7_pointer arg) {return(lt_p_pp(sc, t_lookup(sc, cadr(arg), arg), u_lookup(sc, caddr(arg), arg)));}
56012 static s7_pointer fx_lt_tU(s7_scheme *sc, s7_pointer arg) {return(lt_p_pp(sc, t_lookup(sc, cadr(arg), arg), U_lookup(sc, caddr(arg), arg)));}
56013 static s7_pointer fx_lt_ut(s7_scheme *sc, s7_pointer arg) {return(lt_p_pp(sc, u_lookup(sc, cadr(arg), arg), t_lookup(sc, caddr(arg), arg)));}
56014 
56015 static s7_pointer fx_lt_tf(s7_scheme *sc, s7_pointer arg)
56016 {
56017   s7_pointer x;
56018   x = t_lookup(sc, cadr(arg), arg);
56019   if (is_t_real(x)) return(make_boolean(sc, real(x) < real(opt2_con(cdr(arg)))));
56020   return(g_less_xf(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
56021 }
56022 
56023 static s7_pointer fx_lt_ti(s7_scheme *sc, s7_pointer arg)
56024 {
56025   s7_pointer x;
56026   x = t_lookup(sc, cadr(arg), arg);
56027   if (is_t_integer(x)) return(make_boolean(sc, integer(x) < integer(opt2_con(cdr(arg)))));
56028   return(g_less_xi(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
56029 }
56030 
56031 static s7_pointer fx_lt_si(s7_scheme *sc, s7_pointer arg)
56032 {
56033   s7_pointer x;
56034   x = lookup(sc, cadr(arg));
56035   if (is_t_integer(x)) return(make_boolean(sc, integer(x) < integer(opt2_con(cdr(arg)))));
56036   return(g_less_xi(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
56037 }
56038 
56039 static s7_pointer fx_leq_si(s7_scheme *sc, s7_pointer arg)
56040 {
56041   s7_pointer x;
56042   x = lookup(sc, cadr(arg));
56043   if (is_t_integer(x)) return(make_boolean(sc, integer(x) <= integer(opt2_con(cdr(arg)))));
56044   return(g_leq_xi(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
56045 }
56046 
56047 static s7_pointer fx_geq_tf(s7_scheme *sc, s7_pointer arg)
56048 {
56049   s7_pointer x;
56050   x = t_lookup(sc, cadr(arg), arg);
56051   if (is_t_real(x)) return(make_boolean(sc, real(x) >= real(opt2_con(cdr(arg)))));
56052   return(g_geq_xf(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
56053 }
56054 
56055 static s7_pointer fx_geq_si(s7_scheme *sc, s7_pointer arg)
56056 {
56057   s7_pointer x;
56058   x = lookup(sc, cadr(arg));
56059   if (is_t_integer(x)) return(make_boolean(sc, integer(x) >= integer(opt2_con(cdr(arg)))));
56060   return(g_geq_xi(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
56061 }
56062 
56063 static s7_pointer fx_geq_ti(s7_scheme *sc, s7_pointer arg)
56064 {
56065   s7_pointer x;
56066   x = t_lookup(sc, cadr(arg), arg);
56067   if (is_t_integer(x)) return(make_boolean(sc, integer(x) >= integer(opt2_con(cdr(arg)))));
56068   return(g_geq_xi(sc, set_plist_2(sc, x, opt2_con(cdr(arg))))); /* caddr(arg) */
56069 }
56070 
56071 static s7_pointer fx_num_eq_ss(s7_scheme *sc, s7_pointer arg)
56072 {
56073   s7_pointer x, y;
56074   x = lookup(sc, cadr(arg));
56075   y = lookup(sc, opt2_sym(cdr(arg)));
56076   return(make_boolean(sc, ((is_t_integer(x)) && (is_t_integer(y))) ? (integer(x) == integer(y)) : num_eq_b_7pp(sc, x, y)));
56077 }
56078 
56079 static s7_pointer fx_num_eq_ts(s7_scheme *sc, s7_pointer arg)
56080 {
56081   s7_pointer x, y;
56082   x = t_lookup(sc, cadr(arg), arg);
56083   y = lookup(sc, opt2_sym(cdr(arg)));
56084   return(make_boolean(sc, ((is_t_integer(x)) && (is_t_integer(y))) ? (integer(x) == integer(y)) : num_eq_b_7pp(sc, x, y)));
56085 }
56086 
56087 static s7_pointer fx_num_eq_tg(s7_scheme *sc, s7_pointer arg)
56088 {
56089   s7_pointer x, y;
56090   x = t_lookup(sc, cadr(arg), arg);
56091   y = global_value(opt2_sym(cdr(arg)));
56092   return(make_boolean(sc, ((is_t_integer(x)) && (is_t_integer(y))) ? (integer(x) == integer(y)) : num_eq_b_7pp(sc, x, y)));
56093 }
56094 
56095 static s7_pointer fx_num_eq_tT(s7_scheme *sc, s7_pointer arg)
56096 {
56097   s7_pointer x, y;
56098   x = t_lookup(sc, cadr(arg), arg);
56099   y = T_lookup(sc, caddr(arg), arg);
56100   return(make_boolean(sc, ((is_t_integer(x)) && (is_t_integer(y))) ? (integer(x) == integer(y)) : num_eq_b_7pp(sc, x, y)));
56101 }
56102 
56103 static s7_pointer fx_num_eq_tu(s7_scheme *sc, s7_pointer arg)
56104 {
56105   s7_pointer x, y;
56106   x = t_lookup(sc, cadr(arg), arg);
56107   y = u_lookup(sc, caddr(arg), arg);
56108   return(make_boolean(sc, ((is_t_integer(x)) && (is_t_integer(y))) ? (integer(x) == integer(y)) : num_eq_b_7pp(sc, x, y)));
56109 }
56110 
56111 static s7_pointer fx_num_eq_us(s7_scheme *sc, s7_pointer arg)
56112 {
56113   s7_pointer x, y;
56114   x = u_lookup(sc, cadr(arg), arg);
56115   y = lookup(sc, opt2_sym(cdr(arg)));
56116   return(make_boolean(sc, ((is_t_integer(x)) && (is_t_integer(y))) ? (integer(x) == integer(y)) : num_eq_b_7pp(sc, x, y)));
56117 }
56118 
56119 static s7_pointer fx_is_eq_ss(s7_scheme *sc, s7_pointer arg)
56120 {
56121   s7_pointer x, y;
56122   x = lookup(sc, cadr(arg));
56123   y = lookup(sc, opt2_sym(cdr(arg)));
56124   return(make_boolean(sc, (x == y) || ((is_unspecified(x)) && (is_unspecified(y)))));
56125 }
56126 
56127 static s7_pointer fx_is_eq_ts(s7_scheme *sc, s7_pointer arg)
56128 {
56129   s7_pointer x, y;
56130   x = t_lookup(sc, cadr(arg), arg);
56131   y = lookup(sc, opt2_sym(cdr(arg)));
56132   return(make_boolean(sc, (x == y) || ((is_unspecified(x)) && (is_unspecified(y)))));
56133 }
56134 
56135 static s7_pointer fx_is_eq_tu(s7_scheme *sc, s7_pointer arg)
56136 {
56137   s7_pointer x, y;
56138   x = t_lookup(sc, cadr(arg), arg);
56139   y = u_lookup(sc, caddr(arg), arg);
56140   return(make_boolean(sc, (x == y) || ((is_unspecified(x)) && (is_unspecified(y)))));
56141 }
56142 
56143 static s7_pointer fx_not_is_eq_ss(s7_scheme *sc, s7_pointer arg)
56144 {
56145   s7_pointer x, y;
56146   x = lookup(sc, opt2_sym(cdr(arg)));
56147   y = lookup(sc, opt3_sym(cdr(arg)));
56148   return(make_boolean(sc, (x != y) && ((!is_unspecified(x)) || (!is_unspecified(y)))));
56149 }
56150 
56151 static s7_pointer fx_not_is_eq_sq(s7_scheme *sc, s7_pointer arg)
56152 {
56153   s7_pointer x, y;
56154   x = lookup(sc, opt2_sym(cdr(arg)));
56155   y = opt3_con(cdr(arg));
56156   return(make_boolean(sc, (x != y) && ((!is_unspecified(x)) || (!is_unspecified(y)))));
56157 }
56158 
56159 static s7_pointer x_hash_table_ref_ss(s7_scheme *sc, s7_pointer table, s7_pointer key)
56160 {
56161   return((is_hash_table(table)) ? hash_entry_value((*hash_table_checker(table))(sc, table, key)) : g_hash_table_ref(sc, set_plist_2(sc, table, key)));
56162 
56163 }
56164 
56165 static s7_pointer fx_hash_table_ref_ss(s7_scheme *sc, s7_pointer arg) {return(x_hash_table_ref_ss(sc, lookup(sc, cadr(arg)), lookup(sc, opt2_sym(cdr(arg)))));}
56166 static s7_pointer fx_hash_table_ref_st(s7_scheme *sc, s7_pointer arg) {return(x_hash_table_ref_ss(sc, lookup(sc, cadr(arg)), t_lookup(sc, opt2_sym(cdr(arg)), arg)));}
56167 
56168 static s7_pointer fx_hash_table_ref_car(s7_scheme *sc, s7_pointer arg)
56169 {
56170   s7_pointer table, lst;
56171   table = lookup(sc, cadr(arg));
56172   lst = lookup(sc, opt2_sym(cdr(arg)));
56173   if (!is_pair(lst))
56174     return(simple_wrong_type_argument(sc, sc->car_symbol, lst, T_PAIR));
56175   return((is_hash_table(table)) ? hash_entry_value((*hash_table_checker(table))(sc, table, car(lst))) : g_hash_table_ref(sc, set_plist_2(sc, table, car(lst))));
56176 }
56177 
56178 static inline s7_pointer fx_hash_table_increment_1(s7_scheme *sc, s7_pointer table, s7_pointer key, s7_pointer arg)
56179 {
56180   hash_entry_t *val;
56181   if (!is_hash_table(table))
56182     return(((s7_p_ppp_t)opt2_direct(cdr(arg)))(sc, table, key, fx_call(sc, cdddr(arg))));
56183   val = (*hash_table_checker(table))(sc, table, key);
56184   if (val != sc->unentry)
56185     {
56186       if (!is_t_integer(hash_entry_value(val)))
56187 	simple_wrong_type_argument(sc, sc->add_symbol, cadddr(arg), T_INTEGER);
56188       hash_entry_set_value(val, make_integer(sc, integer(hash_entry_value(val)) + 1));
56189       return(hash_entry_value(val));
56190     }
56191   s7_hash_table_set(sc, table, key, int_one);
56192   return(int_one);
56193 }
56194 
56195 static s7_pointer fx_hash_table_increment(s7_scheme *sc, s7_pointer arg)
56196 {
56197   return(fx_hash_table_increment_1(sc, lookup(sc, cadr(arg)), lookup(sc, caddr(arg)), arg));
56198 }
56199 
56200 static s7_pointer fx_lint_let_ref(s7_scheme *sc, s7_pointer arg)
56201 {
56202   s7_pointer lt, sym, y;
56203   lt = cdr(lookup(sc, opt2_sym(arg)));  /* (var-ref local-var) -> local-var, opt_sym2(arg) == cadr(arg) */
56204   if (!is_let(lt))
56205     return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 1, lt, a_let_string));
56206   sym = opt2_sym(cdr(arg));             /* (let-ref (cdr v) 'ref) -> ref == opt3_sym(cdar(closure_body(opt1_lambda(arg)))); */
56207   for (y = let_slots(lt); tis_slot(y); y = next_slot(y))
56208     if (slot_symbol(y) == sym)
56209       return(slot_value(y));
56210   return(lint_let_ref_p_pp(sc, let_outlet(lt), sym));
56211 }
56212 
56213 static s7_pointer fx_lint_let_ref_t(s7_scheme *sc, s7_pointer arg)
56214 {
56215   s7_pointer lt, sym, y;
56216   lt = cdr(t_lookup(sc, opt2_sym(arg), arg));
56217   if (!is_let(lt))
56218     return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 1, lt, a_let_string));
56219   sym = opt2_sym(cdr(arg));
56220   for (y = let_slots(lt); tis_slot(y); y = next_slot(y))
56221     if (slot_symbol(y) == sym)
56222       return(slot_value(y));
56223   return(lint_let_ref_p_pp(sc, let_outlet(lt), sym));
56224 }
56225 
56226 static s7_pointer fx_memq_sq_2(s7_scheme *sc, s7_pointer arg)
56227 {
56228   s7_pointer p, obj;
56229   obj = lookup(sc, cadr(arg));
56230   p = opt2_con(cdr(arg));
56231   if (obj == car(p)) return(p);
56232   return((obj == cadr(p)) ? cdr(p) : sc->F);
56233 }
56234 
56235 static s7_pointer fx_c_cq(s7_scheme *sc, s7_pointer arg)
56236 {
56237   set_car(sc->t2_1, cadr(arg));
56238   set_car(sc->t2_2, opt2_con(cdr(arg)));
56239   return(fn_proc(arg)(sc, sc->t2_1));
56240 }
56241 
56242 static s7_pointer fx_c_sss(s7_scheme *sc, s7_pointer arg)
56243 {
56244   set_car(sc->t3_1, lookup(sc, cadr(arg)));
56245   set_car(sc->t3_2, lookup(sc, opt1_sym(cdr(arg)))); /* caddr(arg) */
56246   set_car(sc->t3_3, lookup(sc, opt2_sym(cdr(arg)))); /* cadddr(arg) */
56247   return(fn_proc(arg)(sc, sc->t3_1));
56248 }
56249 
56250 static s7_pointer fx_c_sss_direct(s7_scheme *sc, s7_pointer arg)
56251 {
56252   return(((s7_p_ppp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)), lookup(sc, opt1_sym(cdr(arg))), lookup(sc, opt2_sym(cdr(arg)))));
56253 }
56254 
56255 static s7_pointer fx_c_sts(s7_scheme *sc, s7_pointer arg)
56256 {
56257   set_car(sc->t3_1, lookup(sc, cadr(arg)));
56258   set_car(sc->t3_2, t_lookup(sc, opt1_sym(cdr(arg)), arg)); /* caddr(arg) */
56259   set_car(sc->t3_3, lookup(sc, opt2_sym(cdr(arg)))); /* cadddr(arg) */
56260   return(fn_proc(arg)(sc, sc->t3_1));
56261 }
56262 
56263 static s7_pointer fx_vset_sts(s7_scheme *sc, s7_pointer arg)
56264 {
56265   return(vector_set_p_ppp(sc, lookup(sc, cadr(arg)), t_lookup(sc, opt1_sym(cdr(arg)), arg), lookup(sc, opt2_sym(cdr(arg)))));
56266 }
56267 
56268 static s7_pointer fx_c_tus(s7_scheme *sc, s7_pointer arg)
56269 {
56270   set_car(sc->t3_1, t_lookup(sc, cadr(arg), arg));
56271   set_car(sc->t3_2, u_lookup(sc, opt1_sym(cdr(arg)), arg)); /* caddr(arg), arg)); */
56272   set_car(sc->t3_3, lookup(sc, opt2_sym(cdr(arg)))); /* cadddr(arg) */
56273   return(fn_proc(arg)(sc, sc->t3_1));
56274 }
56275 
56276 static s7_pointer fx_c_scs(s7_scheme *sc, s7_pointer arg)
56277 {
56278   set_car(sc->t3_1, lookup(sc, cadr(arg)));
56279   set_car(sc->t3_3, lookup(sc, opt2_sym(cdr(arg)))); /* cadddr(arg) */
56280   set_car(sc->t3_2, opt1_con(cdr(arg)));             /* caddr(arg) */
56281   return(fn_proc(arg)(sc, sc->t3_1));
56282 }
56283 
56284 static s7_pointer fx_c_scs_direct(s7_scheme *sc, s7_pointer arg)
56285 {
56286   return(((s7_p_ppp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)), opt1_con(cdr(arg)), lookup(sc, opt2_sym(cdr(arg)))));
56287 }
56288 
56289 static s7_pointer fx_c_tcu_direct(s7_scheme *sc, s7_pointer arg)
56290 {
56291   return(((s7_p_ppp_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, cadr(arg), arg), opt1_con(cdr(arg)), u_lookup(sc, cadddr(arg), arg)));
56292 }
56293 
56294 static s7_pointer fx_c_tcs_direct(s7_scheme *sc, s7_pointer arg)
56295 {
56296   return(((s7_p_ppp_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, cadr(arg), arg), opt1_con(cdr(arg)), lookup(sc, opt2_sym(cdr(arg)))));
56297 }
56298 
56299 static s7_pointer fx_c_tcs(s7_scheme *sc, s7_pointer arg)
56300 {
56301   set_car(sc->t3_1, t_lookup(sc, cadr(arg), arg));
56302   set_car(sc->t3_3, lookup(sc, opt2_sym(cdr(arg)))); /* cadddr(arg) */
56303   set_car(sc->t3_2, opt1_con(cdr(arg)));             /* caddr(arg) */
56304   return(fn_proc(arg)(sc, sc->t3_1));
56305 }
56306 
56307 static s7_pointer fx_c_scc(s7_scheme *sc, s7_pointer arg)
56308 {
56309   set_car(sc->t3_1, lookup(sc, cadr(arg)));
56310   set_car(sc->t3_2, opt1_con(cdr(arg))); /* caddr(arg) */
56311   set_car(sc->t3_3, opt2_con(cdr(arg))); /* cadddr(arg) */
56312   return(fn_proc(arg)(sc, sc->t3_1));
56313 }
56314 
56315 static s7_pointer fx_c_css(s7_scheme *sc, s7_pointer arg)
56316 {
56317   set_car(sc->t3_2, lookup(sc, opt1_sym(cdr(arg)))); /* caddr(arg) */
56318   set_car(sc->t3_3, lookup(sc, opt2_sym(cdr(arg)))); /* cadddr(arg) */
56319   set_car(sc->t3_1, cadr(arg));
56320   return(fn_proc(arg)(sc, sc->t3_1));
56321 }
56322 
56323 static s7_pointer fx_c_csc(s7_scheme *sc, s7_pointer arg)
56324 {
56325   set_car(sc->t3_2, lookup(sc, opt1_sym(cdr(arg)))); /* caddr(arg) */
56326   set_car(sc->t3_1, opt3_con(cdr(arg)));             /* cadr(arg) or maybe cadadr if quoted? */
56327   set_car(sc->t3_3, opt2_con(cdr(arg)));             /* cadddr(arg) */
56328   return(fn_proc(arg)(sc, sc->t3_1));
56329 }
56330 
56331 static s7_pointer fx_c_ccs(s7_scheme *sc, s7_pointer arg)
56332 {
56333   set_car(sc->t3_3, lookup(sc, opt1_sym(cdr(arg)))); /* cadddr(arg) */
56334   set_car(sc->t3_1, cadr(arg)); /* maybe opt3_con? */
56335   set_car(sc->t3_2, opt2_con(cdr(arg)));             /* caddr(arg) */
56336   return(fn_proc(arg)(sc, sc->t3_1));
56337 }
56338 
56339 static s7_pointer fx_c_ssc(s7_scheme *sc, s7_pointer arg)
56340 {
56341   set_car(sc->t3_1, lookup(sc, cadr(arg)));
56342   set_car(sc->t3_2, lookup(sc, opt1_sym(cdr(arg)))); /* caddr(arg) */
56343   set_car(sc->t3_3, opt2_con(cdr(arg)));             /* cadddr(arg) */
56344   return(fn_proc(arg)(sc, sc->t3_1));
56345 }
56346 
56347 static s7_pointer fx_c_tuc(s7_scheme *sc, s7_pointer arg)
56348 {
56349   set_car(sc->t3_1, t_lookup(sc, cadr(arg), arg));
56350   set_car(sc->t3_2, u_lookup(sc, opt1_sym(cdr(arg)), arg)); /* caddr(arg) */
56351   set_car(sc->t3_3, opt2_con(cdr(arg)));             /* cadddr(arg) */
56352   return(fn_proc(arg)(sc, sc->t3_1));
56353 }
56354 
56355 static s7_pointer fx_c_opdq(s7_scheme *sc, s7_pointer arg)
56356 {
56357   set_car(sc->t1_1, d_call(sc, cadr(arg)));
56358   return(fn_proc(arg)(sc, sc->t1_1));
56359 }
56360 
56361 static inline void gc_protect_via_stack(s7_scheme *sc, s7_pointer val)
56362 {
56363   sc->stack_end[2] = val;
56364   sc->stack_end[3] = (s7_pointer)OP_GC_PROTECT;
56365   sc->stack_end += 4;
56366   /* sc->stack_end[-2] = val; */
56367   /* op_stack might also be usable in this context */
56368 }
56369 
56370 static s7_pointer fx_c_opsq(s7_scheme *sc, s7_pointer arg)
56371 {
56372   s7_pointer largs;
56373   largs = cadr(arg);
56374   set_car(sc->t1_1, lookup(sc, cadr(largs)));
56375   set_car(sc->t1_1, fn_proc(largs)(sc, sc->t1_1));
56376   return(fn_proc(arg)(sc, sc->t1_1));
56377 }
56378 
56379 static s7_pointer fx_c_optq(s7_scheme *sc, s7_pointer arg)
56380 {
56381   set_car(sc->t1_1, t_lookup(sc, opt1_sym(cdr(arg)), arg)); /* cadadr */
56382   set_car(sc->t1_1, fn_proc(cadr(arg))(sc, sc->t1_1));
56383   return(fn_proc(arg)(sc, sc->t1_1));
56384 }
56385 
56386 static s7_pointer fx_c_optq_direct(s7_scheme *sc, s7_pointer arg)
56387 {
56388   return(((s7_p_p_t)opt2_direct(cdr(arg)))(sc, ((s7_p_p_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, opt1_sym(cdr(arg)), arg))));
56389 }
56390 
56391 static s7_pointer fx_c_car_s(s7_scheme *sc, s7_pointer arg)
56392 {
56393   s7_pointer val;
56394   val = lookup(sc, opt2_sym(cdr(arg)));
56395   set_car(sc->t1_1, (is_pair(val)) ? car(val) : g_car(sc, set_plist_1(sc, val)));
56396   return(fn_proc(arg)(sc, sc->t1_1));
56397 }
56398 
56399 static s7_pointer fx_c_car_t(s7_scheme *sc, s7_pointer arg)
56400 {
56401   s7_pointer val;
56402   val = t_lookup(sc, opt2_sym(cdr(arg)), arg);
56403   set_car(sc->t1_1, (is_pair(val)) ? car(val) : g_car(sc, set_plist_1(sc, val)));
56404   return(fn_proc(arg)(sc, sc->t1_1));
56405 }
56406 
56407 static s7_pointer fx_c_car_u(s7_scheme *sc, s7_pointer arg)
56408 {
56409   s7_pointer val;
56410   val = u_lookup(sc, opt2_sym(cdr(arg)), arg);
56411   set_car(sc->t1_1, (is_pair(val)) ? car(val) : g_car(sc, set_plist_1(sc, val)));
56412   return(fn_proc(arg)(sc, sc->t1_1));
56413 }
56414 
56415 static s7_pointer fx_c_cdr_s(s7_scheme *sc, s7_pointer arg)
56416 {
56417   s7_pointer val;
56418   val = lookup(sc, opt2_sym(cdr(arg)));
56419   set_car(sc->t1_1, (is_pair(val)) ? cdr(val) : g_cdr(sc, set_plist_1(sc, val)));
56420   return(fn_proc(arg)(sc, sc->t1_1));
56421 }
56422 
56423 static s7_pointer fx_c_cdr_t(s7_scheme *sc, s7_pointer arg)
56424 {
56425   s7_pointer val;
56426   val = t_lookup(sc, opt2_sym(cdr(arg)), arg);
56427   set_car(sc->t1_1, (is_pair(val)) ? cdr(val) : g_cdr(sc, set_plist_1(sc, val)));
56428   return(fn_proc(arg)(sc, sc->t1_1));
56429 }
56430 
56431 static s7_pointer fx_is_type_opsq(s7_scheme *sc, s7_pointer arg)
56432 {
56433   set_car(sc->t1_1, lookup(sc, opt2_sym(cdr(arg))));
56434   return(make_boolean(sc, (uint8_t)(opt3_byte(cdr(arg))) == type(fn_proc(cadr(arg))(sc, sc->t1_1))));
56435 }
56436 
56437 static s7_pointer fx_is_type_optq(s7_scheme *sc, s7_pointer arg)
56438 {
56439   set_car(sc->t1_1, t_lookup(sc, opt2_sym(cdr(arg)), arg));
56440   return(make_boolean(sc, (uint8_t)(opt3_byte(cdr(arg))) == type(fn_proc(cadr(arg))(sc, sc->t1_1))));
56441 }
56442 
56443 static s7_pointer fx_is_type_car_s(s7_scheme *sc, s7_pointer arg)
56444 {
56445   s7_pointer val;
56446   val = lookup(sc, opt2_sym(cdr(arg)));
56447   return(make_boolean(sc, (is_pair(val)) ?
56448 		            ((uint8_t)(opt3_byte(cdr(arg))) == type(car(val))) :
56449 		            ((uint8_t)(opt3_byte(cdr(arg))) == type(g_car(sc, set_plist_1(sc, val))))));
56450 }
56451 
56452 static s7_pointer fx_is_type_car_t(s7_scheme *sc, s7_pointer arg)
56453 {
56454   s7_pointer val;
56455   val = t_lookup(sc, opt2_sym(cdr(arg)), arg);
56456   if (is_pair(val))
56457     return(make_boolean(sc, (uint8_t)(opt3_byte(cdr(arg))) == type(car(val))));
56458   if (has_active_methods(sc, val)) /* this verbosity saves 1/3 total compute time (overhead!) */
56459     {
56460       s7_pointer func;
56461       func = find_method_with_let(sc, val, sc->car_symbol);
56462       if (func != sc->undefined)
56463 	return(make_boolean(sc, type(call_method(sc, val, func, set_plist_1(sc, val))) == (uint8_t)opt3_byte(cdr(arg))));
56464     }
56465   return(wrong_type_argument(sc, sc->car_symbol, 1, val, T_PAIR));
56466 }
56467 
56468 static s7_pointer fx_c_weak1_type_s(s7_scheme *sc, s7_pointer arg)
56469 {
56470   s7_pointer val;
56471   val = lookup(sc, opt2_sym(cdr(arg)));
56472   if (is_c_pointer(val))                /* (let? (c-pointer-weak1 val)) etc */
56473     return(make_boolean(sc, (uint8_t)(opt3_byte(cdr(arg))) == type(c_pointer_weak1(val))));
56474   if (has_active_methods(sc, val)) /* calling g_c_pointer_weak1 here instead is much slower, error by itself is much faster! splitting out does not help */
56475     {
56476       s7_pointer func;
56477       func = find_method_with_let(sc, val, sc->c_pointer_weak1_symbol);
56478       if (func != sc->undefined)
56479 	return(make_boolean(sc, type(call_method(sc, val, func, set_plist_1(sc, val))) == (uint8_t)opt3_byte(cdr(arg))));
56480     }
56481   return(wrong_type_argument(sc, sc->c_pointer_weak1_symbol, 1, val, T_C_POINTER));
56482 }
56483 
56484 static s7_pointer fx_not_opsq(s7_scheme *sc, s7_pointer arg)
56485 {
56486   s7_pointer largs;
56487   largs = cadr(arg);
56488   set_car(sc->t1_1, lookup(sc, cadr(largs)));
56489   return((fn_proc(largs)(sc, sc->t1_1) == sc->F) ? sc->T : sc->F);
56490 }
56491 
56492 static s7_pointer fx_c_opssq(s7_scheme *sc, s7_pointer arg)
56493 {
56494   s7_pointer largs;
56495   largs = cadr(arg);
56496   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56497   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(largs)))); /* caddr(largs) */
56498   set_car(sc->t1_1, fn_proc(largs)(sc, sc->t2_1));
56499   return(fn_proc(arg)(sc, sc->t1_1));
56500 }
56501 
56502 static s7_pointer fx_c_opssq_direct(s7_scheme *sc, s7_pointer arg)
56503 {
56504   return(((s7_p_p_t)opt2_direct(cdr(arg)))(sc, ((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt3_sym(arg)), lookup(sc, opt1_sym(cdr(arg))))));
56505 }
56506 
56507 static s7_pointer fx_c_optuq_direct(s7_scheme *sc, s7_pointer arg)
56508 {
56509   return(((s7_p_p_t)opt2_direct(cdr(arg)))(sc, ((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, opt3_sym(arg), arg), u_lookup(sc, opt1_sym(cdr(arg)), arg))));
56510 }
56511 
56512 static s7_pointer fx_c_optuq(s7_scheme *sc, s7_pointer arg)
56513 {
56514   set_car(sc->t2_1, t_lookup(sc, opt3_sym(arg), arg));
56515   set_car(sc->t2_2, u_lookup(sc, opt1_sym(cdr(arg)), arg));
56516   set_car(sc->t1_1, fn_proc(cadr(arg))(sc, sc->t2_1));
56517   return(fn_proc(arg)(sc, sc->t1_1));
56518 }
56519 
56520 static s7_pointer fx_c_opstq(s7_scheme *sc, s7_pointer arg)
56521 {
56522   s7_pointer largs;
56523   largs = cadr(arg);
56524   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56525   set_car(sc->t2_2, t_lookup(sc, caddr(largs), arg));
56526   set_car(sc->t1_1, fn_proc(largs)(sc, sc->t2_1));
56527   return(fn_proc(arg)(sc, sc->t1_1));
56528 }
56529 
56530 static s7_pointer fx_c_opstq_direct(s7_scheme *sc, s7_pointer arg)
56531 {
56532   return(((s7_p_p_t)opt2_direct(cdr(arg)))(sc, ((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt3_sym(arg)), t_lookup(sc, opt1_sym(cdr(arg)), arg))));
56533 }
56534 
56535 static s7_pointer fx_is_zero_remainder_car(s7_scheme *sc, s7_pointer arg)
56536 {
56537   s7_pointer u, t;
56538   u = u_lookup(sc, opt3_sym(arg), arg);
56539   u = (is_pair(u)) ? car(u) : g_car(sc, set_plist_1(sc, u)); /* g_car much less overhead than car_p_p or simple_error(?) */
56540   t = t_lookup(sc, opt1_sym(cdr(arg)), arg);
56541   if ((is_t_integer(u)) && (is_t_integer(t)))
56542     return(make_boolean(sc, remainder_i_7ii(sc, integer(u), integer(t)) == 0));
56543   return(is_zero_p_p(sc, remainder_p_pp(sc, u, t)));
56544 }
56545 
56546 static s7_pointer fx_is_zero_remainder_s(s7_scheme *sc, s7_pointer arg)
56547 {
56548   s7_pointer s, t;
56549   s = lookup(sc, opt3_sym(arg));
56550   t = t_lookup(sc, opt1_sym(cdr(arg)), arg);
56551   if ((is_t_integer(s)) && (is_t_integer(t)))
56552     return(make_boolean(sc, remainder_i_7ii(sc, integer(s), integer(t)) == 0));
56553   return(is_zero_p_p(sc, remainder_p_pp(sc, s, t)));
56554 }
56555 
56556 static s7_pointer fx_not_opssq(s7_scheme *sc, s7_pointer arg)
56557 {
56558   s7_pointer largs;
56559   largs = cadr(arg);
56560   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56561   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(largs))));
56562   return((fn_proc(largs)(sc, sc->t2_1) == sc->F) ? sc->T : sc->F);
56563 }
56564 
56565 static s7_pointer fx_not_oputq(s7_scheme *sc, s7_pointer arg)
56566 {
56567   s7_pointer largs;
56568   largs = cadr(arg);
56569   set_car(sc->t2_1, u_lookup(sc, cadr(largs), arg));
56570   set_car(sc->t2_2, t_lookup(sc, caddr(largs), arg));
56571   return((fn_proc(largs)(sc, sc->t2_1) == sc->F) ? sc->T : sc->F);
56572 }
56573 
56574 static s7_pointer fx_not_lt_ut(s7_scheme *sc, s7_pointer arg)
56575 {
56576   s7_pointer x, y;
56577   y = u_lookup(sc, opt3_sym(arg), arg);
56578   x = t_lookup(sc, opt1_sym(cdr(arg)), arg);
56579   return(make_boolean(sc, ((is_t_integer(x)) && (is_t_integer(y))) ? (integer(y) >= integer(x)) : geq_b_7pp(sc, y, x)));
56580 }
56581 
56582 static s7_pointer fx_c_opscq(s7_scheme *sc, s7_pointer arg)
56583 {
56584   s7_pointer largs;
56585   largs = cadr(arg);
56586   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56587   set_car(sc->t2_2, opt2_con(cdr(largs)));
56588   set_car(sc->t1_1, fn_proc(largs)(sc, sc->t2_1));
56589   return(fn_proc(arg)(sc, sc->t1_1));
56590 }
56591 
56592 static s7_pointer fx_not_opscq(s7_scheme *sc, s7_pointer arg)
56593 {
56594   s7_pointer largs;
56595   largs = cadr(arg);
56596   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56597   set_car(sc->t2_2, opt2_con(cdr(largs)));
56598   return((fn_proc(largs)(sc, sc->t2_1) == sc->F) ? sc->T : sc->F);
56599 }
56600 
56601 static s7_pointer fx_c_optcq(s7_scheme *sc, s7_pointer arg)
56602 {
56603   s7_pointer largs;
56604   largs = cadr(arg);
56605   set_car(sc->t2_1, t_lookup(sc, cadr(largs), arg));
56606   set_car(sc->t2_2, opt2_con(cdr(largs)));
56607   set_car(sc->t1_1, fn_proc(largs)(sc, sc->t2_1));
56608   return(fn_proc(arg)(sc, sc->t1_1));
56609 }
56610 
56611 static s7_pointer fx_c_opcsq(s7_scheme *sc, s7_pointer arg)
56612 {
56613   s7_pointer largs;
56614   largs = cadr(arg);
56615   set_car(sc->t2_2, lookup(sc, caddr(largs)));
56616   set_car(sc->t2_1, opt1_con(cdr(largs)));  /* cadr(largs) or cadadr */
56617   set_car(sc->t1_1, fn_proc(largs)(sc, sc->t2_1));
56618   return(fn_proc(arg)(sc, sc->t1_1));
56619 }
56620 
56621 static s7_pointer fx_c_opcsq_c(s7_scheme *sc, s7_pointer arg)
56622 {
56623   s7_pointer largs;
56624   largs = cadr(arg);
56625   set_car(sc->t2_2, lookup(sc, caddr(largs)));
56626   set_car(sc->t2_1, opt1_con(cdr(largs))); /* cadr(largs) or cadadr */
56627   set_car(sc->t2_1, fn_proc(largs)(sc, sc->t2_1));
56628   set_car(sc->t2_2, caddr(arg));
56629   return(fn_proc(arg)(sc, sc->t2_1));
56630 }
56631 
56632 static s7_pointer fx_c_opcsq_s(s7_scheme *sc, s7_pointer arg)
56633 {
56634   s7_pointer largs;
56635   largs = cadr(arg);
56636   set_car(sc->t2_2, lookup(sc, caddr(largs)));
56637   set_car(sc->t2_1, opt1_con(cdr(largs))); /* cadr(largs) or cadadr */
56638   set_car(sc->t2_1, fn_proc(largs)(sc, sc->t2_1));
56639   set_car(sc->t2_2, lookup(sc, caddr(arg)));
56640   return(fn_proc(arg)(sc, sc->t2_1));
56641 }
56642 
56643 static s7_pointer fx_c_opssq_s(s7_scheme *sc, s7_pointer arg)
56644 {
56645   s7_pointer largs;
56646   largs = cadr(arg);
56647   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56648   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(largs))));
56649   set_car(sc->t2_1, fn_proc(largs)(sc, sc->t2_1));
56650   set_car(sc->t2_2, lookup(sc, caddr(arg)));
56651   return(fn_proc(arg)(sc, sc->t2_1));
56652 }
56653 
56654 static s7_pointer fx_c_opssq_s_direct(s7_scheme *sc, s7_pointer arg)
56655 {
56656   s7_pointer largs;
56657   largs = opt3_pair(arg); /* cdadr(arg) */
56658   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc,
56659 	   ((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs))),
56660 	   lookup(sc, caddr(arg))));
56661 }
56662 
56663 static s7_pointer fx_add_vref_s(s7_scheme *sc, s7_pointer arg)
56664 {
56665   s7_pointer largs;
56666   largs = opt3_pair(arg); /* cdadr(arg) */
56667   return(add_p_pp(sc, vector_ref_p_pp(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs))), lookup(sc, caddr(arg))));
56668 }
56669 
56670 static s7_pointer fx_add_s_vref(s7_scheme *sc, s7_pointer arg)
56671 {
56672   s7_pointer largs;
56673   largs = opt3_pair(arg); /* cdaddr(arg) */
56674   return(add_p_pp(sc, lookup(sc, cadr(arg)), vector_ref_p_pp(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs)))));
56675 }
56676 
56677 static s7_pointer fx_subtract_vref_s(s7_scheme *sc, s7_pointer arg)
56678 {
56679   s7_pointer largs;
56680   largs = opt3_pair(arg); /* cdadr(arg) */
56681   return(subtract_p_pp(sc, vector_ref_p_pp(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs))), lookup(sc, caddr(arg))));
56682 }
56683 
56684 static s7_pointer fx_subtract_s_vref(s7_scheme *sc, s7_pointer arg)
56685 {
56686   s7_pointer largs;
56687   largs = opt3_pair(arg); /* cdaddr(arg) */
56688   return(subtract_p_pp(sc, lookup(sc, cadr(arg)), vector_ref_p_pp(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs)))));
56689 }
56690 
56691 static s7_pointer fx_multiply_s_vref(s7_scheme *sc, s7_pointer arg)
56692 {
56693   s7_pointer largs;
56694   largs = opt3_pair(arg); /* cdaddr(arg) */
56695   return(multiply_p_pp(sc, lookup(sc, cadr(arg)), vector_ref_p_pp(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs)))));
56696 }
56697 
56698 static s7_pointer fx_add_sqr_s(s7_scheme *sc, s7_pointer arg)
56699 {
56700   s7_pointer largs, p1, p3;
56701   largs = opt3_pair(arg); /* cdadr(arg) */
56702   p1 = lookup(sc, car(largs));
56703   p3 = lookup(sc, caddr(arg));
56704   if ((is_t_complex(p1)) && (is_t_complex(p3)))
56705     {
56706       s7_double r, i;
56707       r = real_part(p1);
56708       i = imag_part(p1);
56709       return(make_complex(sc, real_part(p3) + r * r - i * i, imag_part(p3) + 2.0 * r * i));
56710     }
56711   return(add_p_pp(sc, fx_sqr_1(sc, p1), p3));
56712 }
56713 
56714 static s7_pointer fx_add_sub_s(s7_scheme *sc, s7_pointer arg)
56715 {
56716   s7_pointer largs, p1, p2, p3;
56717   largs = opt3_pair(arg); /* cdadr(arg) */
56718   p1 = lookup(sc, car(largs));
56719   p2 = lookup(sc, opt2_sym(largs));
56720   p3 = lookup(sc, caddr(arg));
56721   if ((is_t_real(p1)) && (is_t_real(p2)) && (is_t_real(p3)))
56722     return(make_real(sc, real(p3) + real(p1) - real(p2)));
56723   return(add_p_pp(sc, subtract_p_pp(sc, p1, p2), p3));
56724 }
56725 
56726 static s7_pointer fx_gt_add_s(s7_scheme *sc, s7_pointer arg)
56727 {
56728   s7_pointer largs, x1, x2, x3;
56729   largs = opt3_pair(arg); /* cdadr(arg) */
56730   x1 = lookup(sc, car(largs));
56731   x2 = lookup(sc, opt2_sym(largs));
56732   x3 = lookup(sc, caddr(arg));
56733   if ((is_t_real(x1)) && (is_t_real(x2)) && (is_t_real(x3)))
56734     return(make_boolean(sc, (real(x1) + real(x2)) > real(x3)));
56735   return(gt_p_pp(sc, add_p_pp(sc, x1, x2), x3));
56736 }
56737 
56738 static s7_pointer fx_gt_vref_s(s7_scheme *sc, s7_pointer arg)
56739 {
56740   s7_pointer largs;
56741   largs = opt3_pair(arg); /* cdadr(arg) */
56742   return(gt_p_pp(sc, vector_ref_p_pp(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs))), lookup(sc, caddr(arg))));
56743 }
56744 
56745 static s7_pointer fx_geq_s_vref(s7_scheme *sc, s7_pointer arg)
56746 {
56747   s7_pointer largs;
56748   largs = opt3_pair(arg); /* cdaddr(arg) */
56749   return(geq_p_pp(sc, lookup(sc, cadr(arg)), vector_ref_p_pp(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs)))));
56750 }
56751 
56752 static s7_pointer fx_is_eq_s_vref(s7_scheme *sc, s7_pointer arg)
56753 {
56754   s7_pointer largs;
56755   largs = opt3_pair(arg); /* cdaddr(arg) */
56756   return(make_boolean(sc, lookup(sc, cadr(arg)) == vector_ref_p_pp(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs)))));
56757 }
56758 
56759 static s7_pointer fx_vref_s_add(s7_scheme *sc, s7_pointer arg)
56760 {
56761   s7_pointer largs;
56762   largs = opt3_pair(arg); /* cdaddr(arg) */
56763   return(vector_ref_p_pp(sc, lookup(sc, cadr(arg)), add_p_pp(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs)))));
56764 }
56765 
56766 static inline s7_pointer fx_vref_vref_3(s7_scheme *sc, s7_pointer v1, s7_pointer p1, s7_pointer p2)
56767 {
56768   if ((is_t_integer(p1)) && (is_t_integer(p2)) && ((is_normal_vector(v1)) && (vector_rank(v1) == 1)))
56769     {
56770       s7_int i1, i2;
56771       i1 = integer(p1);
56772       i2 = integer(p2);
56773       if ((i1 >= 0) && (i2 >= 0) && (i1 < vector_length(v1)))
56774 	{
56775 	  s7_pointer v2;
56776 	  v2 = vector_element(v1, i1);
56777 	  if ((is_normal_vector(v2)) && (vector_rank(v2) == 1) && (i2 < vector_length(v2)))
56778 	    return(vector_element(v2, i2));
56779 	}}
56780   return(vector_ref_p_pp(sc, vector_ref_p_pp(sc, v1, p1), p2));
56781 }
56782 
56783 static s7_pointer fx_vref_vref_3_no_let(s7_scheme *sc, s7_pointer code)
56784 {
56785   return(fx_vref_vref_3(sc, lookup(sc, cadr(code)), lookup(sc, opt2_sym(code)), lookup(sc, opt3_sym(code))));
56786 }
56787 
56788 static s7_pointer fx_vref_vref_ss_s(s7_scheme *sc, s7_pointer arg)
56789 {
56790   s7_pointer largs;
56791   largs = opt3_pair(arg); /* cdadr(arg); */
56792   return(fx_vref_vref_3(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs)), lookup(sc, caddr(arg))));
56793 }
56794 
56795 /* need var3 here */
56796 static s7_pointer fx_vref_vref_tu_s(s7_scheme *sc, s7_pointer arg)
56797 {
56798   s7_pointer slot;
56799   slot = let_slots(sc->curlet);
56800   return(fx_vref_vref_3(sc, slot_value(slot), slot_value(next_slot(slot)), lookup(sc, caddr(arg))));
56801 }
56802 
56803 static s7_pointer fx_vref_vref_gs_t(s7_scheme *sc, s7_pointer arg)
56804 {
56805   s7_pointer largs;
56806   largs = opt3_pair(arg); /* cdadr(arg); */
56807   return(fx_vref_vref_3(sc, lookup_global(sc, car(largs)), lookup(sc, opt2_sym(largs)), t_lookup(sc, caddr(arg), arg)));
56808 }
56809 
56810 static s7_pointer fx_c_opscq_c(s7_scheme *sc, s7_pointer arg)
56811 {
56812   s7_pointer largs;
56813   largs = cadr(arg);
56814   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56815   set_car(sc->t2_2, opt2_con(cdr(largs)));
56816   set_car(sc->t2_1, fn_proc(largs)(sc, sc->t2_1));
56817   set_car(sc->t2_2, caddr(arg));
56818   return(fn_proc(arg)(sc, sc->t2_1));
56819 }
56820 
56821 static s7_pointer fx_c_opssq_c(s7_scheme *sc, s7_pointer arg)
56822 {
56823   s7_pointer largs;
56824   largs = cadr(arg);
56825   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56826   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(largs))));
56827   set_car(sc->t2_1, fn_proc(largs)(sc, sc->t2_1));
56828   set_car(sc->t2_2, caddr(arg));
56829   return(fn_proc(arg)(sc, sc->t2_1));
56830 }
56831 
56832 static s7_pointer fx_c_opstq_c(s7_scheme *sc, s7_pointer arg)
56833 {
56834   s7_pointer largs;
56835   largs = cadr(arg);
56836   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56837   set_car(sc->t2_2, t_lookup(sc, caddr(largs), arg));
56838   set_car(sc->t2_1, fn_proc(largs)(sc, sc->t2_1));
56839   set_car(sc->t2_2, caddr(arg));
56840   return(fn_proc(arg)(sc, sc->t2_1));
56841 }
56842 
56843 static s7_pointer fx_c_opstq_c_direct(s7_scheme *sc, s7_pointer arg)
56844 {
56845   s7_pointer largs;
56846   largs = cadr(arg);
56847   return(((s7_p_pp_t)opt3_direct(arg))(sc, fn_proc(largs)(sc, set_plist_2(sc, lookup(sc, cadr(largs)), t_lookup(sc, caddr(largs), arg))), caddr(arg)));
56848 }
56849 
56850 static s7_pointer fx_c_opsq_s(s7_scheme *sc, s7_pointer arg)
56851 {
56852   s7_pointer largs;
56853   largs = cadr(arg);
56854   set_car(sc->t1_1, lookup(sc, cadr(largs)));
56855   set_car(sc->t2_1, fn_proc(largs)(sc, sc->t1_1));
56856   set_car(sc->t2_2, lookup(sc, caddr(arg)));
56857   return(fn_proc(arg)(sc, sc->t2_1));
56858 }
56859 
56860 static s7_pointer fx_c_opsq_s_direct(s7_scheme *sc, s7_pointer arg)
56861 {
56862   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc,
56863 	    ((s7_p_p_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt1_sym(cdr(arg)))),
56864 	    lookup(sc, caddr(arg))));
56865 }
56866 
56867 static s7_pointer fx_cons_car_s_s(s7_scheme *sc, s7_pointer arg) {return(cons(sc, car_p_p(sc, lookup(sc, opt1_sym(cdr(arg)))), lookup(sc, caddr(arg))));}
56868 static s7_pointer fx_cons_car_t_s(s7_scheme *sc, s7_pointer arg) {return(cons(sc, car_p_p(sc, t_lookup(sc, opt1_sym(cdr(arg)), arg)), lookup(sc, caddr(arg))));}
56869 static s7_pointer fx_cons_car_u_t(s7_scheme *sc, s7_pointer arg) {return(cons(sc, car_p_p(sc, u_lookup(sc, opt1_sym(cdr(arg)), arg)), t_lookup(sc, caddr(arg), arg)));}
56870 
56871 static s7_pointer fx_c_optq_s(s7_scheme *sc, s7_pointer arg)
56872 {
56873   s7_pointer largs;
56874   largs = cadr(arg);
56875   set_car(sc->t1_1, t_lookup(sc, cadr(largs), arg));
56876   set_car(sc->t2_1, fn_proc(largs)(sc, sc->t1_1));
56877   set_car(sc->t2_2, lookup(sc, caddr(arg)));
56878   return(fn_proc(arg)(sc, sc->t2_1));
56879 }
56880 
56881 static s7_pointer fx_c_optq_s_direct(s7_scheme *sc, s7_pointer arg)
56882 {
56883   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc,
56884             ((s7_p_p_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, opt1_sym(cdr(arg)), arg)), /* cadadr */
56885             lookup(sc, caddr(arg))));
56886 }
56887 
56888 static s7_pointer fx_c_opuq_t(s7_scheme *sc, s7_pointer arg)
56889 {
56890   s7_pointer largs;
56891   largs = cadr(arg);
56892   set_car(sc->t1_1, u_lookup(sc, cadr(largs), largs));
56893   set_car(sc->t2_1, fn_proc(largs)(sc, sc->t1_1));
56894   set_car(sc->t2_2, t_lookup(sc, caddr(arg), arg));
56895   return(fn_proc(arg)(sc, sc->t2_1));
56896 }
56897 
56898 static s7_pointer fx_c_opuq_t_direct(s7_scheme *sc, s7_pointer arg)
56899 {
56900   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc,
56901             ((s7_p_p_t)opt3_direct(cdr(arg)))(sc, u_lookup(sc, opt1_sym(cdr(arg)), arg)),
56902             t_lookup(sc, caddr(arg), arg)));
56903 }
56904 
56905 static s7_pointer fx_cons_opuq_t(s7_scheme *sc, s7_pointer arg)
56906 {
56907   return(cons(sc, ((s7_p_p_t)opt3_direct(cdr(arg)))(sc, u_lookup(sc, opt1_sym(cdr(arg)), arg)), t_lookup(sc, caddr(arg), arg)));
56908 }
56909 
56910 static s7_pointer fx_c_opsq_cs(s7_scheme *sc, s7_pointer arg)
56911 {
56912   set_car(sc->t1_1, lookup(sc, opt3_sym(cdr(arg))));  /* cadadr(arg); */
56913   set_car(sc->t3_1, fn_proc(cadr(arg))(sc, sc->t1_1));
56914   set_car(sc->t3_2, opt1_con(cdr(arg)));              /* caddr(arg) or cadaddr(arg) */
56915   set_car(sc->t3_3, lookup(sc, opt2_sym(cdr(arg))));  /* cadddr(arg); */
56916   return(fn_proc(arg)(sc, sc->t3_1));
56917 }
56918 
56919 static s7_pointer fx_c_optq_cu(s7_scheme *sc, s7_pointer arg)
56920 {
56921   set_car(sc->t1_1, t_lookup(sc, opt3_sym(cdr(arg)), arg));
56922   set_car(sc->t3_1, fn_proc(cadr(arg))(sc, sc->t1_1));
56923   set_car(sc->t3_2, opt1_con(cdr(arg)));
56924   set_car(sc->t3_3, u_lookup(sc, opt2_sym(cdr(arg)), arg));
56925   return(fn_proc(arg)(sc, sc->t3_1));
56926 }
56927 
56928 static s7_pointer fx_c_opsq_c(s7_scheme *sc, s7_pointer arg)
56929 {
56930   set_car(sc->t1_1, lookup(sc, opt1_sym(cdr(arg)))); /* cadadr */
56931   set_car(sc->t2_1, fn_proc(cadr(arg))(sc, sc->t1_1));
56932   set_car(sc->t2_2, opt2_con(cdr(arg)));
56933   return(fn_proc(arg)(sc, sc->t2_1));
56934 }
56935 
56936 static s7_pointer fx_c_optq_c(s7_scheme *sc, s7_pointer arg)
56937 {
56938   set_car(sc->t1_1, t_lookup(sc, opt1_sym(cdr(arg)), arg));
56939   set_car(sc->t2_1, fn_proc(cadr(arg))(sc, sc->t1_1));
56940   set_car(sc->t2_2, opt2_con(cdr(arg)));
56941   return(fn_proc(arg)(sc, sc->t2_1));
56942 }
56943 
56944 static s7_pointer fx_c_optq_c_direct(s7_scheme *sc, s7_pointer arg)
56945 {
56946   return(((s7_p_pp_t)opt3_direct(arg))(sc, ((s7_p_p_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, opt1_sym(cdr(arg)), arg)), opt2_con(cdr(arg))));
56947 }
56948 
56949 static s7_pointer fx_c_optq_i_direct(s7_scheme *sc, s7_pointer arg)
56950 {
56951   return(((s7_p_ii_t)opt3_direct(arg))(sc, ((s7_i_7p_t)opt3_direct(cdr(arg)))(sc, t_lookup(sc, opt1_sym(cdr(arg)), arg)), integer(opt2_con(cdr(arg)))));
56952 }
56953 
56954 static s7_pointer fx_memq_car_s(s7_scheme *sc, s7_pointer arg)
56955 {
56956   s7_pointer x, obj;
56957   obj = lookup(sc, opt1_sym(cdr(arg)));
56958   obj = (is_pair(obj)) ? car(obj) : g_car(sc, set_plist_1(sc, obj));
56959   x = opt2_con(cdr(arg));
56960   while (true) {LOOP_4(if (obj == car(x)) return(x); x = cdr(x); if (!is_pair(x)) return(sc->F));}
56961   return(sc->F);
56962 }
56963 
56964 static s7_pointer fx_memq_car_s_2(s7_scheme *sc, s7_pointer arg)
56965 {
56966   s7_pointer x, obj;
56967   obj = lookup(sc, opt1_sym(cdr(arg)));
56968   obj = (is_pair(obj)) ? car(obj) : g_car(sc, set_plist_1(sc, obj));
56969   x = opt2_con(cdr(arg));
56970   if (obj == car(x)) return(x);
56971   return((obj == cadr(x)) ? cdr(x) : sc->F);
56972 }
56973 
56974 static s7_pointer fx_c_s_opssq(s7_scheme *sc, s7_pointer arg)
56975 {
56976   s7_pointer largs;
56977   largs = caddr(arg);
56978   set_car(sc->t2_1, lookup(sc, cadr(largs)));
56979   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(largs))));
56980   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t2_1));
56981   set_car(sc->t2_1, lookup(sc, cadr(arg)));
56982   return(fn_proc(arg)(sc, sc->t2_1));
56983 }
56984 
56985 static s7_pointer fx_c_s_opssq_direct(s7_scheme *sc, s7_pointer arg)
56986 {
56987   s7_pointer largs;
56988   largs = opt3_pair(arg); /* cdaddr(arg) */
56989   arg = cdr(arg);
56990   return(((s7_p_pp_t)opt2_direct(arg))(sc, lookup(sc, car(arg)), ((s7_p_pp_t)opt3_direct(arg))(sc, lookup(sc, car(largs)), lookup(sc, opt2_sym(largs)))));
56991 }
56992 
56993 static s7_pointer fx_c_s_opstq_direct(s7_scheme *sc, s7_pointer arg)
56994 {
56995   s7_pointer largs;
56996   largs = opt3_pair(arg); /* cdaddr(arg) */
56997   arg = cdr(arg);
56998   return(((s7_p_pp_t)opt2_direct(arg))(sc, lookup(sc, car(arg)), ((s7_p_pp_t)opt3_direct(arg))(sc, lookup(sc, car(largs)), t_lookup(sc, opt2_sym(largs), arg))));
56999 }
57000 
57001 static s7_pointer fx_vref_g_vref_gs(s7_scheme *sc, s7_pointer arg)
57002 {
57003   s7_pointer largs;
57004   largs = opt3_pair(arg); /* cdaddr(arg); */
57005   return(vector_ref_p_pp(sc, lookup_global(sc, cadr(arg)), vector_ref_p_pp(sc, lookup_global(sc, car(largs)), lookup(sc, opt2_sym(largs)))));
57006 }
57007 
57008 static s7_pointer fx_vref_g_vref_gt(s7_scheme *sc, s7_pointer arg)
57009 {
57010   s7_pointer largs;
57011   largs = opt3_pair(arg); /* cdaddr(arg); */
57012   return(vector_ref_p_pp(sc, lookup_global(sc, cadr(arg)), vector_ref_p_pp(sc, lookup_global(sc, car(largs)), t_lookup(sc, opt2_sym(largs), arg))));
57013 }
57014 
57015 static s7_pointer fx_c_c_opssq(s7_scheme *sc, s7_pointer arg)
57016 {
57017   s7_pointer largs;
57018   largs = caddr(arg);
57019   set_car(sc->t2_1, lookup(sc, cadr(largs)));
57020   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(largs))));
57021   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t2_1));
57022   set_car(sc->t2_1, cadr(arg));      /* currently (<safe-f> 'a <opssq>) goes to safe_c_ca so this works by inadvertence */
57023   return(fn_proc(arg)(sc, sc->t2_1));
57024 }
57025 
57026 static s7_pointer fx_c_c_opssq_direct(s7_scheme *sc, s7_pointer arg)
57027 {
57028   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc, cadr(arg), /* see above */
57029 	   ((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt3_sym(arg)), lookup(sc, opt1_sym(cdr(arg))))));
57030 }
57031 
57032 static s7_pointer fx_c_d_opssq_direct(s7_scheme *sc, s7_pointer arg) /* clm2xen (* 1.0 (oscil g2 x2)) */
57033 {
57034   s7_double x2;
57035   x2 = ((s7_d_pd_t)opt3_direct(cdr(arg)))(lookup(sc, opt3_sym(arg)), real_to_double(sc, lookup(sc, opt1_sym(cdr(arg))), "number_to_double"));
57036   return(((s7_p_dd_t)opt2_direct(cdr(arg)))(sc, real_to_double(sc, cadr(arg), "*"), x2));
57037 }
57038 
57039 static s7_pointer fx_c_d_opssq_multiply(s7_scheme *sc, s7_pointer arg)
57040 {
57041   s7_pointer x1, x2;
57042   x1 = lookup(sc, opt3_sym(arg));
57043   x2 = lookup(sc, opt1_sym(cdr(arg)));
57044   if ((is_t_real(x1)) && (is_t_real(x2))) return(make_real(sc, real(cadr(arg)) * real(x1) * real(x2)));
57045   return(multiply_p_pp(sc, cadr(arg), multiply_p_pp(sc, x1, x2)));
57046 }
57047 
57048 static s7_pointer fx_c_s_opscq(s7_scheme *sc, s7_pointer arg)
57049 {
57050   s7_pointer largs;
57051   largs = caddr(arg);
57052   set_car(sc->t2_1, lookup(sc, cadr(largs)));
57053   set_car(sc->t2_2, opt2_con(cdr(largs)));
57054   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t2_1));
57055   set_car(sc->t2_1, lookup(sc, cadr(arg)));
57056   return(fn_proc(arg)(sc, sc->t2_1));
57057 }
57058 
57059 static s7_pointer fx_c_s_opscq_direct(s7_scheme *sc, s7_pointer arg)
57060 {
57061   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)), ((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt3_sym(arg)), opt1_con(cdr(arg)))));
57062 }
57063 
57064 static s7_pointer fx_c_s_opsiq_direct(s7_scheme *sc, s7_pointer arg)
57065 {
57066   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)),
57067 	   ((s7_p_pi_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt3_sym(arg)), integer(opt1_con(cdr(arg))))));
57068 }
57069 
57070 static s7_pointer fx_vref_p1(s7_scheme *sc, s7_pointer arg)
57071 {
57072   s7_pointer v, i;
57073   i = lookup(sc, opt3_sym(arg));
57074   v = lookup(sc, cadr(arg));
57075   if ((is_t_integer(i)) && (is_normal_vector(v)) && (vector_rank(v) == 1))
57076     {
57077       s7_int index;
57078       index = integer(i) + 1;
57079       if ((index >= 0) && (vector_length(v) > index))
57080 	return(vector_element(v, index));
57081     }
57082   return(vector_ref_p_pp(sc, v, g_add_xi(sc, i, 1)));
57083 }
57084 
57085 static s7_pointer fx_num_eq_add_s_si(s7_scheme *sc, s7_pointer arg)
57086 {
57087   s7_pointer i1, i2;
57088   i1 = lookup(sc, cadr(arg));
57089   i2 = lookup(sc, opt3_sym(arg));
57090   if ((is_t_integer(i1)) && (is_t_integer(i2)))
57091     return(make_boolean(sc, integer(i1) == (integer(i2) + integer(opt1_con(cdr(arg))))));
57092   return(make_boolean(sc, num_eq_b_7pp(sc, i1, g_add_xi(sc, i2, integer(opt1_con(cdr(arg)))))));
57093 }
57094 
57095 static s7_pointer fx_num_eq_subtract_s_si(s7_scheme *sc, s7_pointer arg)
57096 {
57097   s7_pointer i1, i2;
57098   i1 = lookup(sc, cadr(arg));
57099   i2 = lookup(sc, opt3_sym(arg));
57100   if ((is_t_integer(i1)) && (is_t_integer(i2)))
57101     return(make_boolean(sc, integer(i1) == (integer(i2) - integer(opt1_con(cdr(arg))))));
57102   return(make_boolean(sc, num_eq_b_7pp(sc, i1, g_sub_xi(sc, i2, integer(opt1_con(cdr(arg)))))));
57103 }
57104 
57105 static s7_pointer fx_c_t_opscq_direct(s7_scheme *sc, s7_pointer arg)
57106 {
57107   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc, t_lookup(sc, cadr(arg), arg),
57108 	   ((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt3_sym(arg)), opt1_con(cdr(arg)))));
57109 }
57110 
57111 static s7_pointer fx_c_t_opucq_direct(s7_scheme *sc, s7_pointer arg)
57112 {
57113   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc, t_lookup(sc, cadr(arg), arg),
57114 	   ((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, u_lookup(sc, opt3_sym(arg), arg), opt1_con(cdr(arg)))));
57115 }
57116 
57117 static s7_pointer fx_c_s_opsq(s7_scheme *sc, s7_pointer arg)
57118 {
57119   s7_pointer largs;
57120   largs = caddr(arg);
57121   set_car(sc->t1_1, lookup(sc, cadr(largs)));
57122   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t1_1));
57123   set_car(sc->t2_1, lookup(sc, cadr(arg)));
57124   return(fn_proc(arg)(sc, sc->t2_1));
57125 }
57126 
57127 static s7_pointer fx_c_s_opsq_direct(s7_scheme *sc, s7_pointer arg)
57128 {
57129   arg = cdr(arg);
57130   return(((s7_p_pp_t)opt2_direct(arg))(sc, lookup(sc, car(arg)), ((s7_p_p_t)opt3_direct(arg))(sc, lookup(sc, opt1_sym(arg))))); /* cadadr */
57131 }
57132 
57133 static s7_pointer fx_c_t_opuq_direct(s7_scheme *sc, s7_pointer arg)
57134 {
57135   arg = cdr(arg);
57136   return(((s7_p_pp_t)opt2_direct(arg))(sc, t_lookup(sc, car(arg), arg), ((s7_p_p_t)opt3_direct(arg))(sc, u_lookup(sc, opt1_sym(arg), arg))));
57137 }
57138 
57139 static s7_pointer fx_c_s_car_s(s7_scheme *sc, s7_pointer arg)
57140 {
57141   s7_pointer val;
57142   val = lookup(sc, opt2_sym(cdr(arg)));
57143   set_car(sc->t2_2, (is_pair(val)) ? car(val) : g_car(sc, set_plist_1(sc, val)));
57144   set_car(sc->t2_1, lookup(sc, cadr(arg)));
57145   return(fn_proc(arg)(sc, sc->t2_1));
57146 }
57147 
57148 static s7_pointer fx_c_t_car_u(s7_scheme *sc, s7_pointer arg)
57149 {
57150   s7_pointer val;
57151   val = u_lookup(sc, opt2_sym(cdr(arg)), arg);
57152   set_car(sc->t2_2, (is_pair(val)) ? car(val) : g_car(sc, set_plist_1(sc, val)));
57153   set_car(sc->t2_1, t_lookup(sc, cadr(arg), arg));
57154   return(fn_proc(arg)(sc, sc->t2_1));
57155 }
57156 
57157 static s7_pointer fx_add_s_car_s(s7_scheme *sc, s7_pointer arg) /* tshoot prime? */
57158 {
57159   s7_pointer val1, val2;
57160   val2 = lookup(sc, opt2_sym(cdr(arg)));
57161   val2 = (is_pair(val2)) ? car(val2) : g_car(sc, set_plist_1(sc, val2));
57162   val1 = lookup(sc, cadr(arg));
57163   return(((is_t_integer(val1)) && (is_t_integer(val2))) ? make_integer(sc, integer(val1) + integer(val2)) : add_p_pp(sc, val1, val2));
57164 }
57165 
57166 static s7_pointer fx_add_u_car_t(s7_scheme *sc, s7_pointer arg)
57167 {
57168   s7_pointer val1, val2;
57169   val2 = t_lookup(sc, opt2_sym(cdr(arg)), arg);
57170   val2 = (is_pair(val2)) ? car(val2) : g_car(sc, set_plist_1(sc, val2));
57171   val1 = u_lookup(sc, cadr(arg), arg);
57172   return(((is_t_integer(val1)) && (is_t_integer(val2))) ? make_integer(sc, integer(val1) + integer(val2)) : add_p_pp(sc, val1, val2));
57173 }
57174 
57175 static s7_pointer fx_c_op_s_opsqq(s7_scheme *sc, s7_pointer arg)
57176 {
57177   s7_pointer outer, args;
57178   outer = cadr(arg);
57179   args = caddr(outer);
57180   set_car(sc->t1_1, lookup(sc, cadr(args)));
57181   set_car(sc->t2_2, fn_proc(args)(sc, sc->t1_1));
57182   set_car(sc->t2_1, lookup(sc, cadr(outer)));
57183   set_car(sc->t1_1, fn_proc(outer)(sc, sc->t2_1));
57184   return(fn_proc(arg)(sc, sc->t1_1));
57185 }
57186 
57187 static s7_pointer fx_not_op_s_opsqq(s7_scheme *sc, s7_pointer arg)
57188 {
57189   s7_pointer outer, args;
57190   outer = cadr(arg);
57191   args = caddr(outer);
57192   set_car(sc->t1_1, lookup(sc, cadr(args)));
57193   set_car(sc->t2_2, fn_proc(args)(sc, sc->t1_1));
57194   set_car(sc->t2_1, lookup(sc, cadr(outer)));
57195   return(((fn_proc(outer)(sc, sc->t2_1)) == sc->F) ? sc->T : sc->F);
57196 }
57197 
57198 static s7_pointer fx_c_op_opsq_sq(s7_scheme *sc, s7_pointer arg)
57199 {
57200   s7_pointer outer, args;
57201   outer = cadr(arg);
57202   args = cadr(outer);
57203   set_car(sc->t1_1, lookup(sc, cadr(args)));
57204   set_car(sc->t2_1, fn_proc(args)(sc, sc->t1_1));
57205   set_car(sc->t2_2, lookup(sc, caddr(outer)));
57206   set_car(sc->t1_1, fn_proc(outer)(sc, sc->t2_1));
57207   return(fn_proc(arg)(sc, sc->t1_1));
57208 }
57209 
57210 static s7_pointer fx_not_op_optq_sq(s7_scheme *sc, s7_pointer arg)
57211 {
57212   s7_pointer outer, args;
57213   outer = cadr(arg);
57214   args = cadr(outer);
57215   set_car(sc->t1_1, t_lookup(sc, cadr(args), arg));
57216   set_car(sc->t2_1, fn_proc(args)(sc, sc->t1_1));
57217   set_car(sc->t2_2, lookup(sc, caddr(outer)));
57218   return((fn_proc(outer)(sc, sc->t2_1) == sc->F) ? sc->T : sc->F);
57219 }
57220 
57221 static s7_pointer fx_c_c_opsq(s7_scheme *sc, s7_pointer arg)
57222 {
57223   s7_pointer largs;
57224   largs = opt3_pair(arg); /* caddr(arg); */
57225   set_car(sc->t1_1, lookup(sc, cadr(largs)));
57226   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t1_1));
57227   set_car(sc->t2_1, cadr(arg));
57228   return(fn_proc(arg)(sc, sc->t2_1));
57229 }
57230 
57231 static s7_pointer fx_c_c_opsq_direct(s7_scheme *sc, s7_pointer arg)
57232 {
57233   return(((s7_p_pp_t)opt2_direct(cdr(arg)))(sc, cadr(arg), ((s7_p_p_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt1_sym(cdr(arg))))));
57234 }
57235 
57236 static s7_pointer fx_c_opsq_opsq(s7_scheme *sc, s7_pointer arg)
57237 {
57238   s7_pointer largs;
57239   largs = cdr(arg);
57240   set_car(sc->t1_1, lookup(sc, cadar(largs)));
57241   gc_protect_via_stack(sc, fn_proc(car(largs))(sc, sc->t1_1));
57242   largs = cadr(largs);
57243   set_car(sc->t1_1, lookup(sc, cadr(largs)));
57244   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t1_1));
57245   set_car(sc->t2_1, sc->stack_end[-2]);
57246   sc->stack_end -= 4;
57247   return(fn_proc(arg)(sc, sc->t2_1));
57248 }
57249 
57250 static s7_pointer fx_c_opsq_opsq_direct(s7_scheme *sc, s7_pointer arg)
57251 {
57252   return(((s7_p_pp_t)opt3_direct(arg))(sc,
57253 	    ((s7_p_p_t)opt2_direct(cdr(arg)))(sc, lookup(sc, cadadr(arg))),
57254             ((s7_p_p_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt1_sym(cdr(arg)))))); /* cadaddr(arg) */
57255 }
57256 
57257 static s7_pointer fx_car_car(s7_scheme *sc, s7_pointer arg)
57258 {
57259   s7_pointer p1, p2;
57260   p1 = lookup(sc, opt1_sym(cdr(arg)));
57261   p2 = lookup(sc, opt2_sym(cdr(arg)));  /* cadaddr(arg) */
57262   return(((s7_p_pp_t)opt3_direct(arg))(sc, (is_pair(p1)) ? car(p1) : g_car(sc, set_plist_1(sc, p1)), (is_pair(p2)) ? car(p2) : g_car(sc, set_plist_1(sc, p2))));
57263 }
57264 
57265 static s7_pointer fx_cdr_cdr(s7_scheme *sc, s7_pointer arg)
57266 {
57267   s7_pointer p1, p2;
57268   p1 = lookup(sc, opt1_sym(cdr(arg)));
57269   p2 = lookup(sc, opt2_sym(cdr(arg)));  /* cadaddr(arg) */
57270   return(((s7_p_pp_t)opt3_direct(arg))(sc, (is_pair(p1)) ? cdr(p1) : g_cdr(sc, set_plist_1(sc, p1)), (is_pair(p2)) ? cdr(p2) : g_cdr(sc, set_plist_1(sc, p2))));
57271 }
57272 
57273 static s7_pointer fx_car_car_tu(s7_scheme *sc, s7_pointer arg)
57274 {
57275   s7_pointer p1, p2;
57276   p1 = t_lookup(sc, opt1_sym(cdr(arg)), arg);
57277   p2 = u_lookup(sc, opt2_sym(cdr(arg)), arg);
57278   return(((s7_p_pp_t)opt3_direct(arg))(sc, (is_pair(p1)) ? car(p1) : g_car(sc, set_plist_1(sc, p1)), (is_pair(p2)) ? car(p2) : g_car(sc, set_plist_1(sc, p2))));
57279 }
57280 
57281 static s7_pointer fx_c_optq_optq_direct(s7_scheme *sc, s7_pointer arg)
57282 {
57283   s7_pointer x;
57284   x = t_lookup(sc, opt1_sym(cdr(arg)), arg); /* cadadr and cadaddr */
57285   return(((s7_p_pp_t)opt3_direct(arg))(sc, ((s7_p_p_t)opt2_direct(cdr(arg)))(sc, x), ((s7_p_p_t)opt3_direct(cdr(arg)))(sc, x)));
57286 }
57287 
57288 static s7_pointer fx_c_opsq_opssq(s7_scheme *sc, s7_pointer arg)
57289 {
57290   s7_pointer largs;
57291   largs = cdr(arg);
57292   set_car(sc->t1_1, lookup(sc, cadar(largs)));
57293   gc_protect_via_stack(sc, fn_proc(car(largs))(sc, sc->t1_1));
57294   largs = cadr(largs);
57295   set_car(sc->t2_1, lookup(sc, cadr(largs)));
57296   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(largs)))); /* caddr(largs) */
57297   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t2_1));
57298   set_car(sc->t2_1, sc->stack_end[-2]);
57299   sc->stack_end -= 4;
57300   return(fn_proc(arg)(sc, sc->t2_1));
57301 }
57302 
57303 static s7_pointer fx_c_opsq_optuq_direct(s7_scheme *sc, s7_pointer arg)
57304 {
57305   s7_pointer largs;
57306   largs = cdr(arg);
57307   return(((s7_p_pp_t)opt3_direct(arg))(sc,
57308 	    ((s7_p_p_t)opt2_direct(largs))(sc, lookup(sc, cadar(largs))),
57309             ((s7_p_pp_t)opt3_direct(largs))(sc, t_lookup(sc, opt2_sym(cdr(largs)), arg), u_lookup(sc, opt1_sym(largs), arg))));
57310 }
57311 
57312 static s7_pointer fx_num_eq_car_s_add_tu(s7_scheme *sc, s7_pointer arg)
57313 {
57314   s7_pointer largs, p1, p2, p3;
57315   largs = cdr(arg);
57316   p1 = car_p_p(sc, lookup(sc, cadar(largs)));
57317   p2 = t_lookup(sc, opt2_sym(cdr(largs)), arg);
57318   p3 = u_lookup(sc, opt1_sym(largs), arg);
57319   if ((is_t_integer(p1)) && (is_t_integer(p2)) && (is_t_integer(p3)))
57320     return(make_boolean(sc, integer(p1) == (integer(p2) + integer(p3))));
57321   return(make_boolean(sc, num_eq_b_7pp(sc, p1, add_p_pp(sc, p2, p3))));
57322 }
57323 
57324 static s7_pointer fx_num_eq_car_s_subtract_tu(s7_scheme *sc, s7_pointer arg)
57325 {
57326   s7_pointer largs, p1, p2, p3;
57327   largs = cdr(arg);
57328   p1 = car_p_p(sc, lookup(sc, cadar(largs)));
57329   p2 = t_lookup(sc, opt2_sym(cdr(largs)), arg);
57330   p3 = u_lookup(sc, opt1_sym(largs), arg);
57331   if ((is_t_integer(p1)) && (is_t_integer(p2)) && (is_t_integer(p3)))
57332     return(make_boolean(sc, integer(p1) == (integer(p2) - integer(p3))));
57333   return(make_boolean(sc, num_eq_b_7pp(sc, p1, subtract_p_pp(sc, p2, p3))));
57334 }
57335 
57336 static s7_pointer fx_c_opssq_opsq(s7_scheme *sc, s7_pointer arg)
57337 {
57338   s7_pointer largs;
57339   largs = cdr(arg);
57340   set_car(sc->t2_1, lookup(sc, cadar(largs)));
57341   set_car(sc->t2_2, lookup(sc, opt2_sym(cdar(largs))));
57342   gc_protect_via_stack(sc, fn_proc(car(largs))(sc, sc->t2_1));
57343   largs = cadr(largs);
57344   set_car(sc->t1_1, lookup(sc, cadr(largs)));
57345   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t1_1));
57346   set_car(sc->t2_1, sc->stack_end[-2]);
57347   sc->stack_end -= 4;
57348   return(fn_proc(arg)(sc, sc->t2_1));
57349 }
57350 
57351 static s7_pointer fx_c_opssq_opssq(s7_scheme *sc, s7_pointer arg)
57352 {
57353   s7_pointer largs;
57354   largs = cdr(arg);
57355   set_car(sc->t2_1, lookup(sc, cadar(largs)));
57356   set_car(sc->t2_2, lookup(sc, opt2_sym(cdar(largs))));
57357   gc_protect_via_stack(sc, fn_proc(car(largs))(sc, sc->t2_1));
57358   largs = cadr(largs);
57359   set_car(sc->t2_1, lookup(sc, cadr(largs)));
57360   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(largs))));
57361   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t2_1));
57362   set_car(sc->t2_1, sc->stack_end[-2]);
57363   sc->stack_end -= 4;
57364   return(fn_proc(arg)(sc, sc->t2_1));
57365 }
57366 
57367 static s7_pointer fx_sub_mul2(s7_scheme *sc, s7_pointer arg)
57368 {
57369   s7_pointer a1;
57370   a1 = opt3_pair(arg); /* cdaddr(arg); */
57371   sc->u = multiply_p_pp(sc, lookup(sc, car(a1)), lookup(sc, cadr(a1)));
57372   a1 = cdadr(arg);
57373   return(subtract_p_pp(sc, multiply_p_pp(sc, lookup(sc, car(a1)), lookup(sc, cadr(a1))), sc->u));
57374 }
57375 
57376 static s7_pointer fx_add_mul2(s7_scheme *sc, s7_pointer arg)
57377 {
57378   s7_pointer a1;
57379   a1 = opt3_pair(arg); /* cdaddr(arg); */
57380   sc->u = multiply_p_pp(sc, lookup(sc, car(a1)), lookup(sc, cadr(a1)));
57381   a1 = cdadr(arg);
57382   return(add_p_pp(sc, multiply_p_pp(sc, lookup(sc, car(a1)), lookup(sc, cadr(a1))), sc->u));
57383 }
57384 
57385 static s7_pointer fx_lt_sub2(s7_scheme *sc, s7_pointer arg)
57386 {
57387   s7_pointer a1;
57388   a1 = opt3_pair(arg); /* cdaddr(arg); */
57389   sc->u = subtract_p_pp(sc, lookup(sc, car(a1)), lookup(sc, cadr(a1)));
57390   a1 = cdadr(arg);
57391   return(lt_p_pp(sc, subtract_p_pp(sc, lookup(sc, car(a1)), lookup(sc, cadr(a1))), sc->u));
57392 }
57393 
57394 static s7_pointer fx_sub_vref2(s7_scheme *sc, s7_pointer arg)
57395 {
57396   s7_pointer p1, p2, v1, a1;
57397   a1 = cdadr(arg);
57398   v1 = lookup(sc, car(a1));
57399   p1 = lookup(sc, cadr(a1));
57400   p2 = lookup(sc, opt3_sym(arg)); /* caddaddr(arg)); */
57401   if ((is_t_integer(p1)) && (is_t_integer(p2)) && ((is_normal_vector(v1)) && (vector_rank(v1) == 1)))
57402     {
57403       s7_int i1, i2;
57404       i1 = integer(p1);
57405       i2 = integer(p2);
57406       if ((i1 >= 0) && (i1 <= vector_length(v1)) && (i2 >= 0) && (i2 < vector_length(v1)))
57407 	return(subtract_p_pp(sc, vector_ref_p_pi(sc, v1, i1), vector_ref_p_pi(sc, v1, i2)));
57408     }
57409   return(subtract_p_pp(sc, vector_ref_p_pp(sc, v1, p1), vector_ref_p_pp(sc, v1, p2)));
57410 }
57411 
57412 static s7_pointer fx_c_op_opsqq(s7_scheme *sc, s7_pointer code)
57413 {
57414   s7_pointer arg;
57415   arg = cadadr(code);
57416   set_car(sc->t1_1, lookup(sc, cadr(arg)));
57417   set_car(sc->t1_1, fn_proc(arg)(sc, sc->t1_1));
57418   set_car(sc->t1_1, fn_proc(cadr(code))(sc, sc->t1_1));
57419   return(fn_proc(code)(sc, sc->t1_1));
57420 }
57421 
57422 static s7_pointer fx_not_op_opsqq(s7_scheme *sc, s7_pointer code)
57423 {
57424   s7_pointer arg;
57425   arg = cadadr(code);
57426   set_car(sc->t1_1, lookup(sc, cadr(arg)));
57427   set_car(sc->t1_1, fn_proc(arg)(sc, sc->t1_1));
57428   return((fn_proc(cadr(code))(sc, sc->t1_1) == sc->F) ? sc->T : sc->F);
57429 }
57430 
57431 static s7_pointer fx_string_ref_t_last(s7_scheme *sc, s7_pointer arg) {return(string_ref_p_plast(sc, t_lookup(sc, cadr(arg), arg), int_zero));}
57432 
57433 static s7_pointer fx_c_a(s7_scheme *sc, s7_pointer arg)
57434 {
57435   set_car(sc->t1_1, fx_call(sc, cdr(arg)));
57436   return(fn_proc(arg)(sc, sc->t1_1));
57437 }
57438 
57439 static s7_pointer fx_c_a_direct(s7_scheme *sc, s7_pointer arg) {return(((s7_p_p_t)opt3_direct(arg))(sc, fx_call(sc, cdr(arg))));}
57440 static s7_pointer fx_not_a(s7_scheme *sc, s7_pointer arg)      {return((fx_call(sc, cdr(arg)) == sc->F) ? sc->T : sc->F);}
57441 
57442 static s7_pointer fx_c_saa(s7_scheme *sc, s7_pointer arg)
57443 {
57444   gc_protect_via_stack(sc, fx_call(sc, opt3_pair(arg))); /* opt3_pair=cddr */
57445   set_car(sc->t3_3, fx_call(sc, cdr(opt3_pair(arg))));
57446   set_car(sc->t3_1, lookup(sc, cadr(arg)));
57447   set_car(sc->t3_2, sc->stack_end[-2]);
57448   sc->stack_end -= 4;
57449   return(fn_proc(arg)(sc, sc->t3_1));
57450 }
57451 
57452 static s7_pointer fx_c_ssa(s7_scheme *sc, s7_pointer arg)
57453 {
57454   set_car(sc->t3_3, fx_call(sc, cdr(opt3_pair(arg))));
57455   set_car(sc->t3_1, lookup(sc, cadr(arg)));
57456   set_car(sc->t3_2, lookup(sc, car(opt3_pair(arg))));
57457   return(fn_proc(arg)(sc, sc->t3_1));
57458 }
57459 
57460 static s7_pointer fx_c_ssa_direct(s7_scheme *sc, s7_pointer arg)
57461 {
57462   return(((s7_p_ppp_t)opt2_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)), lookup(sc, car(opt3_pair(arg))), fx_call(sc, cdr(opt3_pair(arg)))));
57463 }
57464 
57465 static Inline s7_pointer op_ssa_direct(s7_scheme *sc, s7_pointer arg)
57466 {
57467   return(((s7_p_ppp_t)opt2_direct(cdr(arg)))(sc, lookup(sc, cadr(arg)), lookup(sc, car(opt3_pair(arg))), fx_call(sc, cdr(opt3_pair(arg)))));
57468 }
57469 
57470 static s7_pointer fx_c_ass(s7_scheme *sc, s7_pointer arg)
57471 {
57472   set_car(sc->t3_1, fx_call(sc, cdr(arg)));
57473   set_car(sc->t3_2, lookup(sc, car(opt3_pair(arg))));
57474   set_car(sc->t3_3, lookup(sc, cadr(opt3_pair(arg))));
57475   return(fn_proc(arg)(sc, sc->t3_1));
57476 }
57477 
57478 static s7_pointer fx_c_sas(s7_scheme *sc, s7_pointer arg)
57479 {
57480   set_car(sc->t3_2, fx_call(sc, opt3_pair(arg)));
57481   set_car(sc->t3_1, lookup(sc, cadr(arg)));
57482   set_car(sc->t3_3, lookup(sc, cadr(opt3_pair(arg))));
57483   return(fn_proc(arg)(sc, sc->t3_1));
57484 }
57485 
57486 static s7_pointer fx_c_sca(s7_scheme *sc, s7_pointer arg)
57487 {
57488   set_car(sc->t3_3, fx_call(sc, cdr(opt3_pair(arg))));
57489   set_car(sc->t3_1, lookup(sc, cadr(arg)));
57490   set_car(sc->t3_2, car(opt3_pair(arg)));
57491   return(fn_proc(arg)(sc, sc->t3_1));
57492 }
57493 
57494 static s7_pointer fx_c_Tca(s7_scheme *sc, s7_pointer arg)
57495 {
57496   set_car(sc->t3_3, fx_call(sc, cdr(opt3_pair(arg))));
57497   set_car(sc->t3_1, T_lookup(sc, cadr(arg), arg));
57498   set_car(sc->t3_2, car(opt3_pair(arg)));
57499   return(fn_proc(arg)(sc, sc->t3_1));
57500 }
57501 
57502 static s7_pointer fx_c_csa(s7_scheme *sc, s7_pointer arg)
57503 {
57504   set_car(sc->t3_3, fx_call(sc, cdr(opt3_pair(arg))));
57505   set_car(sc->t3_1, cadr(arg));
57506   set_car(sc->t3_2, lookup(sc, car(opt3_pair(arg))));
57507   return(fn_proc(arg)(sc, sc->t3_1));
57508 }
57509 
57510 static s7_pointer fx_c_cac(s7_scheme *sc, s7_pointer arg)
57511 {
57512   set_car(sc->t3_2, fx_call(sc, opt3_pair(arg)));
57513   set_car(sc->t3_1, cadr(arg));
57514   set_car(sc->t3_3, cadr(opt3_pair(arg)));
57515   return(fn_proc(arg)(sc, sc->t3_1));
57516 }
57517 
57518 static s7_pointer fx_c_aa(s7_scheme *sc, s7_pointer arg)
57519 {
57520   check_stack_size(sc); /* needed in t101-aux-18.scm */
57521   gc_protect_via_stack(sc, fx_call(sc, cdr(arg)));
57522   set_car(sc->t2_2, fx_call(sc, cddr(arg)));
57523   set_car(sc->t2_1, T_Pos(sc->stack_end[-2]));
57524   sc->stack_end -= 4;
57525   return(fn_proc(arg)(sc, sc->t2_1));
57526 }
57527 
57528 static s7_pointer fx_c_ca(s7_scheme *sc, s7_pointer arg)
57529 {
57530   set_car(sc->t2_2, fx_call(sc, cddr(arg)));
57531   set_car(sc->t2_1, opt3_con(arg));
57532   return(fn_proc(arg)(sc, sc->t2_1));
57533 }
57534 
57535 static s7_pointer fx_c_ac(s7_scheme *sc, s7_pointer arg)
57536 {
57537   check_stack_size(sc); /* see test-all */
57538   set_car(sc->t2_1, fx_call(sc, cdr(arg)));
57539   set_car(sc->t2_2, opt3_con(arg));
57540   return(fn_proc(arg)(sc, sc->t2_1));
57541 }
57542 
57543 static s7_pointer fx_is_eq_ac(s7_scheme *sc, s7_pointer arg)
57544 {
57545   s7_pointer x, y;
57546   x = fx_call(sc, cdr(arg));
57547   y = opt3_con(arg);
57548   return(make_boolean(sc, (x == y) || ((is_unspecified(x)) && (is_unspecified(y)))));
57549 }
57550 
57551 static s7_pointer fx_c_sa(s7_scheme *sc, s7_pointer arg)
57552 {
57553   set_car(sc->t2_2, fx_call(sc, cddr(arg)));
57554   set_car(sc->t2_1, lookup(sc, opt3_sym(arg)));
57555   return(fn_proc(arg)(sc, sc->t2_1));
57556 }
57557 
57558 static s7_pointer fx_c_sa_direct(s7_scheme *sc, s7_pointer arg)
57559 {
57560   return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, lookup(sc, opt3_sym(arg)), fx_call(sc, cddr(arg))));
57561 }
57562 
57563 static s7_pointer fx_c_za(s7_scheme *sc, s7_pointer arg) /* "z"=unsafe_s */
57564 {
57565   s7_pointer val;
57566   val = lookup_checked(sc, opt3_sym(arg)); /* this can call an autoload function that steps on sc->t2_1 */
57567   set_car(sc->t2_2, fx_call(sc, cddr(arg)));
57568   set_car(sc->t2_1, val);
57569   return(fn_proc(arg)(sc, sc->t2_1));
57570 }
57571 
57572 static s7_pointer fx_c_as(s7_scheme *sc, s7_pointer arg)
57573 {
57574   set_car(sc->t2_1, fx_call(sc, cdr(arg)));
57575   set_car(sc->t2_2, lookup(sc, opt3_sym(arg)));
57576   return(fn_proc(arg)(sc, sc->t2_1));
57577 }
57578 
57579 static s7_pointer fx_c_as_direct(s7_scheme *sc, s7_pointer arg)
57580 {
57581   return(((s7_p_pp_t)opt3_direct(cdr(arg)))(sc, fx_call(sc, cdr(arg)), lookup(sc, opt3_sym(arg))));
57582 }
57583 
57584 static s7_pointer fx_c_ta(s7_scheme *sc, s7_pointer arg)
57585 {
57586   set_car(sc->t2_2, fx_call(sc, cddr(arg)));
57587   set_car(sc->t2_1, t_lookup(sc, opt3_sym(arg), arg));
57588   return(fn_proc(arg)(sc, sc->t2_1));
57589 }
57590 
57591 static s7_pointer fx_c_at(s7_scheme *sc, s7_pointer arg)
57592 {
57593   set_car(sc->t2_1, fx_call(sc, cdr(arg)));
57594   set_car(sc->t2_2, t_lookup(sc, opt3_sym(arg), arg));
57595   return(fn_proc(arg)(sc, sc->t2_1));
57596 }
57597 
57598 static s7_pointer fx_add_as(s7_scheme *sc, s7_pointer arg) {return(add_p_pp(sc, fx_call(sc, cdr(arg)), lookup(sc, opt3_sym(arg))));}
57599 static s7_pointer fx_add_sa(s7_scheme *sc, s7_pointer arg) {return(add_p_pp(sc, lookup(sc, opt3_sym(arg)), fx_call(sc, cddr(arg))));}
57600 
57601 static s7_pointer fx_add_aa(s7_scheme *sc, s7_pointer arg)
57602 {
57603   s7_pointer a1, a2;
57604   a1 = cdr(arg);
57605   a2 = cdr(a1);
57606   return(add_p_pp(sc, fx_call(sc, a1), fx_call(sc, a2)));
57607 }
57608 
57609 static s7_pointer fx_subtract_aa(s7_scheme *sc, s7_pointer arg)
57610 {
57611   s7_pointer a1, a2;
57612   a1 = cdr(arg);
57613   a2 = cdr(a1);
57614   return(subtract_p_pp(sc, fx_call(sc, a1), fx_call(sc, a2)));
57615 }
57616 
57617 static s7_pointer fx_multiply_aa(s7_scheme *sc, s7_pointer arg)
57618 {
57619   s7_pointer a1, a2;
57620   a1 = cdr(arg);
57621   a2 = cdr(a1);
57622   return(multiply_p_pp(sc, fx_call(sc, a1), fx_call(sc, a2)));
57623 }
57624 
57625 static s7_pointer fx_multiply_sa(s7_scheme *sc, s7_pointer arg)
57626 {
57627   s7_pointer a1;
57628   a1 = cdr(arg);
57629   return(multiply_p_pp(sc, lookup(sc, car(a1)), fx_call(sc, cdr(a1))));
57630 }
57631 
57632 static s7_pointer fx_number_to_string_aa(s7_scheme *sc, s7_pointer arg) /* tbig */
57633 {
57634   s7_pointer a1, a2;
57635   a1 = cdr(arg);
57636   a2 = cdr(a1);
57637   return(number_to_string_p_pp(sc, fx_call(sc, a1), fx_call(sc, a2)));
57638 }
57639 
57640 static s7_pointer fx_c_3g(s7_scheme *sc, s7_pointer arg)
57641 {
57642   set_car(sc->t3_1, fx_call(sc, cdr(arg)));
57643   set_car(sc->t3_2, fx_call(sc, opt3_pair(arg)));
57644   set_car(sc->t3_3, fx_call(sc, cdr(opt3_pair(arg))));
57645   return(fn_proc(arg)(sc, sc->t3_1));
57646 }
57647 
57648 static s7_pointer fx_c_aaa(s7_scheme *sc, s7_pointer arg)
57649 {
57650   check_stack_size(sc);
57651   gc_protect_via_stack(sc, fx_call(sc, cdr(arg)));
57652   sc->stack_end[-4] = fx_call(sc, opt3_pair(arg));
57653   set_car(sc->t3_3, fx_call(sc, cdr(opt3_pair(arg))));
57654   set_car(sc->t3_2, sc->stack_end[-4]);
57655   set_car(sc->t3_1, sc->stack_end[-2]);
57656   sc->stack_end -= 4;
57657   return(fn_proc(arg)(sc, sc->t3_1));
57658 }
57659 
57660 static s7_pointer fx_c_gac(s7_scheme *sc, s7_pointer arg)
57661 {
57662   set_car(sc->t3_2, fx_call(sc, opt3_pair(arg)));
57663   set_car(sc->t3_3, cadr(opt3_pair(arg)));
57664   set_car(sc->t3_1, lookup_global(sc, cadr(arg)));
57665   return(fn_proc(arg)(sc, sc->t3_1));
57666 }
57667 
57668 static s7_pointer fx_c_opaq_s(s7_scheme *sc, s7_pointer arg)
57669 {
57670   s7_pointer arg2, val;
57671   arg2 = cdadr(arg);
57672   val = lookup_checked(sc, caddr(arg));
57673   set_car(sc->t1_1, fx_call(sc, arg2));
57674   set_car(sc->t2_1, fn_proc(cadr(arg))(sc, sc->t1_1));
57675   set_car(sc->t2_2, val);
57676   return(fn_proc(arg)(sc, sc->t2_1));
57677 }
57678 
57679 static s7_pointer fx_c_s_opaq(s7_scheme *sc, s7_pointer arg)
57680 {
57681   s7_pointer arg2, val;
57682   arg2 = opt3_pair(arg); /* cdaddr(arg); */
57683   val = lookup_checked(sc, cadr(arg));
57684   set_car(sc->t1_1, fx_call(sc, arg2));
57685   set_car(sc->t2_2, fn_proc(caddr(arg))(sc, sc->t1_1));
57686   set_car(sc->t2_1, val);
57687   return(fn_proc(arg)(sc, sc->t2_1));
57688 }
57689 
57690 static s7_pointer fx_c_opaq(s7_scheme *sc, s7_pointer arg)
57691 {
57692   s7_pointer p;
57693   p = cadr(arg);
57694   set_car(sc->t1_1, fx_call(sc, cdr(p)));
57695   set_car(sc->t1_1, fn_proc(p)(sc, sc->t1_1));
57696   return(fn_proc(arg)(sc, sc->t1_1));
57697 }
57698 
57699 static s7_pointer fx_c_opaaq(s7_scheme *sc, s7_pointer arg)
57700 {
57701   s7_pointer p;
57702   check_stack_size(sc); /* t101 + s7test full */
57703   p = cadr(arg);
57704   sc->stack_end[3] = (s7_pointer)OP_GC_PROTECT;
57705   sc->stack_end += 4;
57706   sc->stack_end[-2] = fx_call(sc, cdr(p));
57707   set_car(sc->t2_2, fx_call(sc, cddr(p)));
57708   set_car(sc->t2_1, sc->stack_end[-2]);
57709   sc->stack_end -= 4;
57710   set_car(sc->t1_1, fn_proc(p)(sc, sc->t2_1));
57711   return(fn_proc(arg)(sc, sc->t1_1));
57712 }
57713 
57714 static s7_pointer fx_c_opsaq(s7_scheme *sc, s7_pointer arg)
57715 {
57716   s7_pointer p;
57717   p = cadr(arg);
57718   set_car(sc->t2_2, fx_call(sc, cddr(p)));
57719   set_car(sc->t2_1, lookup(sc, cadr(p)));
57720   set_car(sc->t1_1, fn_proc(p)(sc, sc->t2_1));
57721   return(fn_proc(arg)(sc, sc->t1_1));
57722 }
57723 
57724 static s7_pointer fx_c_opaaaq(s7_scheme *sc, s7_pointer code)
57725 {
57726   s7_pointer arg;
57727   arg = cadr(code);
57728   gc_protect_via_stack(sc, fx_call(sc, cdr(arg)));
57729   sc->stack_end[-4] = fx_call(sc, opt3_pair(arg));      /* cddr(arg) */
57730   set_car(sc->t3_3, fx_call(sc, cdr(opt3_pair(arg))));
57731   set_car(sc->t3_1, sc->stack_end[-2]);
57732   set_car(sc->t3_2, sc->stack_end[-4]);
57733   sc->stack_end -= 4;
57734   set_car(sc->t1_1, fn_proc(arg)(sc, sc->t3_1));
57735   return(fn_proc(code)(sc, sc->t1_1));
57736 }
57737 
57738 static s7_pointer fx_c_s_opaaq(s7_scheme *sc, s7_pointer code)
57739 {
57740   s7_pointer arg;
57741   arg = caddr(code);
57742   gc_protect_via_stack(sc, fx_call(sc, cdr(arg)));
57743   set_car(sc->t2_2, fx_call(sc, cddr(arg)));
57744   set_car(sc->t2_1, sc->stack_end[-2]);
57745   set_car(sc->t2_2, fn_proc(arg)(sc, sc->t2_1));
57746   set_car(sc->t2_1, lookup(sc, cadr(code)));
57747   sc->stack_end -= 4;
57748   return(fn_proc(code)(sc, sc->t2_1));
57749 }
57750 
57751 static s7_pointer fx_c_s_opaaaq(s7_scheme *sc, s7_pointer code)
57752 {
57753   s7_pointer arg;
57754   arg = caddr(code);
57755   gc_protect_via_stack(sc, fx_call(sc, cdr(arg)));
57756   sc->stack_end[-4] = fx_call(sc, opt3_pair(arg));      /* cddr(arg) */
57757   set_car(sc->t3_3, fx_call(sc, cdr(opt3_pair(arg))));
57758   set_car(sc->t3_1, sc->stack_end[-2]);
57759   set_car(sc->t3_2, sc->stack_end[-4]);
57760   sc->stack_end -= 4;
57761   set_car(sc->t2_2, fn_proc(arg)(sc, sc->t3_1));
57762   set_car(sc->t2_1, lookup(sc, cadr(code)));
57763   return(fn_proc(code)(sc, sc->t2_1));
57764 }
57765 
57766 static s7_pointer fx_c_4a(s7_scheme *sc, s7_pointer code)
57767 {
57768   s7_pointer res;
57769   check_stack_size(sc); /* t101 + s7test + debug=2 */
57770   res = cdr(code);
57771   gc_protect_via_stack(sc, fx_call(sc, res));
57772   sc->stack_end[-4] = fx_call(sc, cdr(res));
57773   res = cddr(res);
57774   sc->stack_end[-3] = fx_call(sc, res);
57775   set_car(sc->t3_3, fx_call(sc, cdr(res)));
57776   set_car(sc->t3_2, sc->stack_end[-3]);
57777   set_car(sc->t3_1, sc->stack_end[-4]);
57778   set_car(sc->t4_1, sc->stack_end[-2]);
57779   sc->stack_end -= 4;
57780   res = fn_proc(code)(sc, sc->t4_1);
57781   set_car(sc->t4_1, sc->F);
57782   return(res);
57783 }
57784 
57785 static s7_pointer fx_c_4g(s7_scheme *sc, s7_pointer code) /* all opts in use for code, opt1 free cdr(code), code opt3 is line_number, cdr(code) opt3 is arglen?? */
57786 {
57787   s7_pointer res;
57788   res = cdr(code);
57789   set_car(sc->t4_1, fx_call(sc, res));
57790   set_car(sc->t3_1, fx_call(sc, cdr(res)));
57791   set_car(sc->t3_2, fx_call(sc, cddr(res)));
57792   set_car(sc->t3_3, fx_call(sc, cdddr(res)));
57793   res = fn_proc(code)(sc, sc->t4_1);
57794   set_car(sc->t4_1, sc->F);
57795   return(res);
57796 }
57797 
57798 static s7_pointer fx_c_c_opscq(s7_scheme *sc, s7_pointer arg)
57799 {
57800   s7_pointer largs;
57801   largs = caddr(arg);
57802   set_car(sc->t2_1, lookup(sc, cadr(largs)));
57803   set_car(sc->t2_2, opt2_con(cdr(largs)));
57804   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t2_1));
57805   set_car(sc->t2_1, cadr(arg));
57806   return(fn_proc(arg)(sc, sc->t2_1));
57807 }
57808 
57809 static s7_pointer fx_c_s_opcsq(s7_scheme *sc, s7_pointer arg)
57810 {
57811   s7_pointer largs;
57812   largs = caddr(arg);
57813   set_car(sc->t2_2, lookup(sc, caddr(largs)));
57814   set_car(sc->t2_1, opt1_con(cdr(largs))); /* cadr(largs) or cadadr */
57815   set_car(sc->t2_2, fn_proc(largs)(sc, sc->t2_1));
57816   set_car(sc->t2_1, lookup(sc, cadr(arg)));
57817   return(fn_proc(arg)(sc, sc->t2_1));
57818 }
57819 
57820 static s7_pointer fx_c_op_opssqq_s(s7_scheme *sc, s7_pointer code)
57821 {
57822   s7_pointer arg;
57823   arg = opt1_pair(cdr(code));
57824   set_car(sc->t2_1, lookup(sc, cadr(arg)));
57825   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(arg))));
57826   set_car(sc->t1_1, fn_proc(arg)(sc, sc->t2_1));
57827   set_car(sc->t2_1, fn_proc(cadr(code))(sc, sc->t1_1));
57828   set_car(sc->t2_2, lookup(sc, caddr(code)));
57829   return(fn_proc(code)(sc, sc->t2_1));
57830 }
57831 
57832 static s7_pointer fx_c_op_opssqq_s_direct(s7_scheme *sc, s7_pointer code)
57833 {
57834   s7_pointer arg;
57835   arg = opt1_pair(cdr(code));
57836   return(((s7_p_pp_t)opt3_direct(code))(sc,
57837             ((s7_p_p_t)opt2_direct(cdr(code)))(sc,
57838                ((s7_p_pp_t)opt3_direct(cdr(code)))(sc, lookup(sc, cadr(arg)), lookup(sc, caddr(arg)))),
57839 	    lookup(sc, caddr(code))));
57840 }
57841 
57842 static s7_pointer fx_c_all_s(s7_scheme *sc, s7_pointer arg)
57843 {
57844   s7_pointer args, p, lst;
57845   lst = safe_list_if_possible(sc, integer(opt3_arglen(cdr(arg))));
57846   if (in_heap(lst))
57847     gc_protect_via_stack(sc, lst);
57848   for (args = cdr(arg), p = lst; is_pair(args); args = cdr(args), p = cdr(p))
57849     set_car(p, lookup(sc, car(args)));
57850   p = fn_proc(arg)(sc, lst);
57851   if (in_heap(lst))
57852     sc->stack_end -= 4;
57853   else clear_list_in_use(lst);
57854   return(p);
57855 }
57856 
57857 static s7_pointer fx_c_all_ca(s7_scheme *sc, s7_pointer code)
57858 {
57859   s7_pointer args, p, lst;
57860   lst = safe_list_if_possible(sc, integer(opt3_arglen(cdr(code))));
57861   if (in_heap(lst))
57862     gc_protect_via_stack(sc, lst);
57863   for (args = cdr(code), p = lst; is_pair(args); args = cdr(args), p = cddr(p))
57864     {
57865       set_car(p, opt2_con(args));
57866       args = cdr(args);
57867       set_car(cdr(p), fx_call(sc, args));
57868     }
57869   p = fn_proc(code)(sc, lst);
57870   if (in_heap(lst))
57871     sc->stack_end -= 4;
57872   else clear_list_in_use(lst);
57873   return(p);
57874 }
57875 
57876 static s7_pointer fx_inlet_ca(s7_scheme *sc, s7_pointer code)
57877 {
57878   s7_pointer new_e, x;
57879   int64_t id;
57880 
57881   new_cell(sc, new_e, T_LET | T_SAFE_PROCEDURE);
57882   let_set_slots(new_e, slot_end(sc));
57883   let_set_outlet(new_e, sc->nil);
57884   gc_protect_via_stack(sc, new_e);
57885 
57886   /* as in let, we need to call the var inits before making the new let, but a simpler equivalent is to make the new let
57887    *    but don't set its id yet.
57888    */
57889   for (x = cdr(code); is_pair(x); x = cddr(x))
57890     {
57891       s7_pointer symbol, value;
57892       symbol = car(x);
57893       symbol = (is_keyword(symbol)) ? keyword_symbol(symbol) : cadar(x);  /* (inlet ':allow-other-keys 3) */
57894       if (is_constant_symbol(sc, symbol))     /* (inlet 'pi 1) */
57895 	return(wrong_type_argument_with_type(sc, sc->inlet_symbol, 1, symbol, a_non_constant_symbol_string));
57896       value = fx_call(sc, cdr(x));            /* it's necessary to do this first, before another_slot */
57897       another_slot(sc, new_e, symbol, value, symbol_id(symbol));
57898     }
57899 
57900   id = ++sc->let_number;
57901   let_set_id(new_e, id);
57902   for (x = let_slots(new_e); tis_slot(x); x = next_slot(x))
57903     symbol_set_id(slot_symbol(x), id);
57904 
57905   sc->stack_end -= 4;
57906   return(new_e);
57907 }
57908 
57909 static s7_pointer fx_c_all_a(s7_scheme *sc, s7_pointer arg)
57910 {
57911   s7_pointer args, p, val;
57912   val = safe_list_if_possible(sc, integer(opt3_arglen(cdr(arg))));
57913   if (in_heap(val))
57914     gc_protect_via_stack(sc, val);
57915   for (args = cdr(arg), p = val; is_pair(args); args = cdr(args), p = cdr(p))
57916     set_car(p, fx_call(sc, args));
57917   p = fn_proc(arg)(sc, val);
57918   if (in_heap(val))
57919     sc->stack_end -= 4;
57920   else clear_list_in_use(val);
57921   return(p);
57922 }
57923 
57924 static s7_pointer fx_vector_all_a(s7_scheme *sc, s7_pointer arg)
57925 {
57926   s7_pointer v, args;
57927   s7_pointer *els;
57928   s7_int i, len;
57929   len = integer(opt3_arglen(cdr(arg)));
57930   v = make_simple_vector(sc, len);
57931   /* we have at least 5 args here (4->_4a etc), so its faster to set the vector type (to turn off the GC mark of the currently unset vector elements) */
57932   set_full_type(v, T_FLOAT_VECTOR);   /* just_mark */
57933   els = vector_elements(v);
57934   gc_protect_via_stack(sc, v);
57935   for (i = 0, args = cdr(arg); i < len; args = cdr(args), i++)
57936     els[i] = fx_call(sc, args);
57937   sc->stack_end -= 4;
57938   set_full_type(v, T_VECTOR);         /* reset the type changes above */
57939   return(v);
57940 }
57941 
57942 static s7_pointer fx_if_a_a(s7_scheme *sc, s7_pointer arg)
57943 {
57944   return((is_true(sc, fx_call(sc, cdr(arg)))) ? fx_call(sc, opt1_pair(arg)) : sc->unspecified);
57945 }
57946 
57947 static s7_pointer fx_if_not_a_a(s7_scheme *sc, s7_pointer arg)
57948 {
57949   return((is_false(sc, fx_call(sc, opt1_pair(arg)))) ? fx_call(sc, opt2_pair(arg)) : sc->unspecified);
57950 }
57951 
57952 static s7_pointer fx_if_a_a_a(s7_scheme *sc, s7_pointer arg)
57953 {
57954   return((is_true(sc, fx_call(sc, cdr(arg)))) ? fx_call(sc, opt1_pair(arg)) : fx_call(sc, opt2_pair(arg)));
57955 }
57956 
57957 static s7_pointer fx_if_s_a_a(s7_scheme *sc, s7_pointer arg)
57958 {
57959   return((lookup(sc, cadr(arg)) != sc->F) ? fx_call(sc, opt1_pair(arg)) : fx_call(sc, opt2_pair(arg)));
57960 }
57961 
57962 static s7_pointer fx_if_and2_s_a(s7_scheme *sc, s7_pointer arg)
57963 {
57964   return(((fx_call(sc, opt1_pair(arg)) == sc->F) || (fx_call(sc, opt2_pair(arg)) == sc->F)) ? fx_call(sc, cdddr(arg)) : lookup(sc, opt3_sym(arg)));
57965 }
57966 
57967 static s7_pointer fx_if_not_a_a_a(s7_scheme *sc, s7_pointer arg)
57968 {
57969   return((is_false(sc, fx_call(sc, opt1_pair(arg)))) ? fx_call(sc, opt2_pair(arg)) : fx_call(sc, opt3_pair(arg)));
57970 }
57971 
57972 static s7_pointer fx_if_a_c_c(s7_scheme *sc, s7_pointer arg)
57973 {
57974   return((is_true(sc, fx_call(sc, cdr(arg)))) ? opt1_con(arg) : opt2_con(arg));
57975 }
57976 
57977 static s7_pointer fx_if_is_type_s_a_a(s7_scheme *sc, s7_pointer arg)
57978 {
57979   if (gen_type_match(sc, lookup(sc, opt2_sym(cdr(arg))), opt3_byte(cdr(arg))))
57980     return(fx_call(sc, cddr(arg)));
57981   return(fx_call(sc, opt2_pair(arg))); /* cdddr(arg) */
57982 }
57983 
57984 static inline s7_pointer fx_and_2(s7_scheme *sc, s7_pointer arg)   /* arg is the full expr: (and ...) */
57985 {
57986   return((fx_call(sc, cdr(arg)) == sc->F) ? sc->F : fx_call(sc, cddr(arg)));
57987 }
57988 
57989 static inline s7_pointer fx_and_s_2(s7_scheme *sc, s7_pointer arg)
57990 {
57991   set_car(sc->t1_1, lookup(sc, opt3_sym(cdr(arg))));  /* cadadr(arg) */
57992   return((fn_proc(cadr(arg))(sc, sc->t1_1) == sc->F) ? sc->F : fn_proc(caddr(arg))(sc, sc->t1_1));
57993 }
57994 
57995 static s7_pointer fx_and_or_2_vref(s7_scheme *sc, s7_pointer arg)
57996 {
57997   s7_pointer or1, arg11, v;
57998   or1 = cadr(arg);
57999   arg11 = cadr(or1);
58000   v = lookup(sc, cadadr(arg11));
58001   if ((is_normal_vector(v)) && (vector_rank(v) == 1))
58002     {
58003       s7_pointer ip, jp, arg12;
58004       arg12 = caddr(or1);
58005       ip = lookup(sc, caddadr(arg11));
58006       jp = lookup(sc, caddaddr(arg12));
58007       if ((is_t_integer(ip)) && (is_t_integer(jp)))
58008 	{
58009 	  s7_int i, j;
58010 	  i = integer(ip);
58011 	  j = integer(jp);
58012 	  if ((i >= 0) && (j >= 0) &&
58013 	      (i < vector_length(v)) && (j < vector_length(v)) &&
58014 	      (is_t_real(vector_element(v, i))) && (is_t_real(vector_element(v, j))))
58015 	    {
58016 	      s7_pointer xp;
58017 	      xp = lookup(sc, caddr(arg11));
58018 	      if (is_t_real(xp))
58019 		{
58020 		  s7_double xf, vi, vj;
58021 		  vi = real(vector_element(v, i));
58022 		  vj = real(vector_element(v, j));
58023 		  xf = real(xp);
58024 		  return(make_boolean(sc, ((vi > xf) || (xf >= vj)) && ((vj > xf) || (xf >= vi))));
58025 		}}}}
58026   return(fx_and_2(sc, arg));
58027 }
58028 
58029 static s7_pointer fx_len2(s7_scheme *sc, s7_pointer arg)
58030 {
58031   s7_pointer val;
58032   val = t_lookup(sc, cadadr(arg), arg);
58033   return(make_boolean(sc, is_pair(val) && (is_pair(cdr(val))) && (is_null(cddr(val)))));
58034 }
58035 
58036 static s7_pointer fx_len3(s7_scheme *sc, s7_pointer arg)
58037 {
58038   s7_pointer val;
58039   val = t_lookup(sc, cadadr(arg), arg);
58040   return(make_boolean(sc, is_pair(val) && (is_pair(cdr(val))) && (is_pair(cddr(val)))));
58041 }
58042 
58043 static s7_pointer fx_and_3(s7_scheme *sc, s7_pointer arg)
58044 {
58045   s7_pointer p, val;
58046   p = cdr(arg);
58047   val = fx_call(sc, p);
58048   if (val == sc->F) return(val);
58049   p = cdr(p);
58050   val = fx_call(sc, p);
58051   return((val == sc->F) ? val : fx_call(sc, cdr(p)));
58052 }
58053 
58054 static s7_pointer fx_and_n(s7_scheme *sc, s7_pointer arg)
58055 {
58056   s7_pointer p, x;
58057   x = sc->T;
58058   for (p = cdr(arg); is_pair(p); p = cdr(p)) /* in lg, 5/6 args appears to predominate */
58059     {
58060       x = fx_call(sc, p);
58061       if (is_false(sc, x))
58062 	return(x);
58063     }
58064   return(x);
58065 }
58066 
58067 static s7_pointer fx_or_2(s7_scheme *sc, s7_pointer arg)
58068 {
58069   s7_pointer p, val;
58070   p = cdr(arg);
58071   val = fx_call(sc, p);
58072   return((val != sc->F) ? val : fx_call(sc, cdr(p)));
58073 }
58074 
58075 static s7_pointer fx_or_s_2(s7_scheme *sc, s7_pointer arg)
58076 {
58077   /* the "s" is looked up once here -- not obvious how to use fx_call anyway */
58078   s7_pointer x;
58079   set_car(sc->t1_1, lookup(sc, opt3_sym(cdr(arg)))); /* cadadr(arg); */
58080   x = fn_proc(cadr(arg))(sc, sc->t1_1);
58081   return((x != sc->F) ? x : fn_proc(caddr(arg))(sc, sc->t1_1));
58082 }
58083 
58084 static s7_pointer fx_or_s_type_2(s7_scheme *sc, s7_pointer arg)
58085 {
58086   s7_pointer x;
58087   x = lookup(sc, opt3_sym(cdr(arg))); /* cadadr(arg)); */
58088   return(make_boolean(sc, (type(x) == integer(opt3_int(arg))) || (type(x) == integer(opt2_int(cdr(arg))))));
58089 }
58090 
58091 static s7_pointer fx_not_symbol_or_keyword(s7_scheme *sc, s7_pointer arg)
58092 {
58093   s7_pointer val;
58094   val = lookup(sc, opt3_sym(arg));
58095   return(make_boolean(sc, (!is_symbol(val)) || (is_keyword(val))));
58096 }
58097 
58098 static s7_pointer fx_or_and_2(s7_scheme *sc, s7_pointer arg)
58099 {
58100   s7_pointer p, val;
58101   p = cdr(arg);
58102   val = fx_call(sc, p);
58103   if (val != sc->F) return(val);
58104   p = opt3_pair(arg); /* cdadr(p); */
58105   val = fx_call(sc, p);
58106   return((val == sc->F) ? val : fx_call(sc, cdr(p)));
58107 }
58108 
58109 static s7_pointer fx_or_and_3(s7_scheme *sc, s7_pointer arg)
58110 {
58111   s7_pointer p, val;
58112   p = cdr(arg);
58113   val = fx_call(sc, p);
58114   if (val != sc->F) return(val);
58115   p = opt3_pair(arg); /* cdadr(p); */
58116   val = fx_call(sc, p);
58117   if (val == sc->F) return(val);
58118   p = cdr(p);
58119   val = fx_call(sc, p);
58120   return((val == sc->F) ? val : fx_call(sc, cdr(p)));
58121 }
58122 
58123 static s7_pointer fx_or_3(s7_scheme *sc, s7_pointer arg)
58124 {
58125   s7_pointer p, val;
58126   p = cdr(arg);
58127   val = fx_call(sc, p);
58128   if (val != sc->F) return(val);
58129   p = cdr(p);
58130   val = fx_call(sc, p);
58131   return((val != sc->F) ? val : fx_call(sc, cdr(p)));
58132 }
58133 
58134 static s7_pointer fx_or_n(s7_scheme *sc, s7_pointer arg)
58135 {
58136   s7_pointer p;
58137   for (p = cdr(arg); is_pair(p); p = cdr(p))
58138     {
58139       s7_pointer x;
58140       x = fx_call(sc, p);
58141       if (is_true(sc, x))
58142 	return(x);
58143     }
58144   return(sc->F);
58145 }
58146 
58147 static s7_pointer fx_begin_aa(s7_scheme *sc, s7_pointer arg)
58148 {
58149   arg = cdr(arg);
58150   fx_call(sc, arg);
58151   return(fx_call(sc, cdr(arg)));
58152 }
58153 
58154 static s7_pointer fx_begin_all_a(s7_scheme *sc, s7_pointer arg)
58155 {
58156   s7_pointer p;
58157   for (p = cdr(arg); is_pair(cdr(p)); p = cdr(p))
58158     fx_call(sc, p);
58159   return(fx_call(sc, p));
58160 }
58161 
58162 static s7_pointer fx_safe_thunk_a(s7_scheme *sc, s7_pointer code)
58163 {
58164   s7_pointer f, result;
58165   gc_protect_via_stack(sc, sc->curlet);
58166   f = opt1_lambda(code);
58167   sc->curlet = closure_let(f);
58168   result = fx_call(sc, closure_body(f));
58169   sc->curlet = sc->stack_end[-2];
58170   sc->stack_end -= 4;
58171   return(result);
58172 }
58173 
58174 static s7_pointer op_safe_thunk_a(s7_scheme *sc, s7_pointer code)
58175 {
58176   s7_pointer f;
58177   f = opt1_lambda(code);
58178 #if S7_DEBUGGING
58179   if (!f) fprintf(stderr, "%s[%d]: opt1_lambda null?\n", __func__, __LINE__);
58180   if (!has_fx(closure_body(f))) fprintf(stderr, "%s[%d]: closure_body no fx?\n", __func__, __LINE__);
58181   if (!fx_proc(closure_body(f))) fprintf(stderr, "%s[%d]: closure_body no fx_proc?\n", __func__, __LINE__);
58182 #endif
58183   sc->curlet = closure_let(f);
58184   return(fx_call(sc, closure_body(f)));
58185 }
58186 
58187 static s7_pointer fx_safe_closure_s_a(s7_scheme *sc, s7_pointer code) /* also called from h_safe_closure_s_a in eval */
58188 {
58189   s7_pointer result;
58190   gc_protect_via_stack(sc, sc->curlet);
58191   sc->curlet = update_let_with_slot(sc, closure_let(opt1_lambda(code)), lookup(sc, opt2_sym(code)));
58192   result = fx_call(sc, closure_body(opt1_lambda(code)));
58193   sc->curlet = sc->stack_end[-2];
58194   sc->stack_end -= 4;
58195   return(result);
58196 }
58197 
58198 static s7_pointer op_safe_closure_s_a(s7_scheme *sc, s7_pointer code) /* also called from h_safe_closure_s_a in eval */
58199 {
58200   sc->curlet = update_let_with_slot(sc, closure_let(opt1_lambda(code)), lookup(sc, opt2_sym(code)));
58201   return(fx_call(sc, closure_body(opt1_lambda(code))));
58202 }
58203 
58204 static s7_pointer fx_safe_closure_t_a(s7_scheme *sc, s7_pointer code)
58205 {
58206   s7_pointer result;
58207   gc_protect_via_stack(sc, sc->curlet);
58208   sc->curlet = update_let_with_slot(sc, closure_let(opt1_lambda(code)), t_lookup(sc, opt2_sym(code), code));
58209   result = fx_call(sc, closure_body(opt1_lambda(code)));
58210   sc->curlet = sc->stack_end[-2];
58211   sc->stack_end -= 4;
58212   return(result);
58213 }
58214 
58215 static s7_pointer fx_safe_closure_s_to_s(s7_scheme *sc, s7_pointer arg)
58216 {
58217   set_car(sc->t1_1, lookup(sc, opt2_sym(arg)));
58218   return(fn_proc(car(closure_body(opt1_lambda(arg))))(sc, sc->t1_1));
58219 }
58220 
58221 static s7_pointer fx_safe_closure_s_to_sc(s7_scheme *sc, s7_pointer arg)
58222 {
58223   set_car(sc->t2_2, opt3_con(cdr(arg)));
58224   set_car(sc->t2_1, lookup(sc, opt2_sym(arg)));
58225   return(fn_proc(car(closure_body(opt1_lambda(arg))))(sc, sc->t2_1));
58226 }
58227 
58228 static s7_pointer fx_safe_closure_s_to_vref(s7_scheme *sc, s7_pointer arg) {return(vector_ref_p_pp(sc, lookup(sc, opt2_sym(arg)), opt3_con(cdr(arg))));}
58229 
58230 static s7_pointer fx_safe_closure_s_to_sub1(s7_scheme *sc, s7_pointer arg)
58231 {
58232   s7_pointer p;
58233   p = lookup(sc, opt2_sym(arg));
58234 #if (!WITH_GMP)
58235   if (is_t_integer(p))
58236     return(make_integer(sc, integer(p) - 1));
58237 #endif
58238   return(minus_c1(sc, p));
58239 }
58240 
58241 static s7_pointer fx_safe_closure_s_to_add1(s7_scheme *sc, s7_pointer arg)
58242 {
58243   s7_pointer p;
58244   p = lookup(sc, opt2_sym(arg));
58245 #if (!WITH_GMP)
58246   if (is_t_integer(p))
58247     return(make_integer(sc, integer(p) + 1));
58248 #endif
58249   return(g_add_x1_1(sc, p, 1));
58250 }
58251 
58252 static s7_pointer fx_c_ff(s7_scheme *sc, s7_pointer arg)
58253 {
58254   s7_pointer x, p;
58255   p = cdr(arg);
58256   x = fx_proc(cdar(p))(sc, car(p));
58257   set_car(sc->t2_2, fx_proc(cdadr(p))(sc, cadr(p)));
58258   set_car(sc->t2_1, x);
58259   return(fn_proc(arg)(sc, sc->t2_1));
58260 }
58261 
58262 static s7_pointer fx_safe_closure_a_to_sc(s7_scheme *sc, s7_pointer arg)
58263 {
58264   set_car(sc->t2_1, fx_call(sc, cdr(arg)));
58265   set_car(sc->t2_2, opt3_con(cdr(arg)));
58266   return(fn_proc(car(closure_body(opt1_lambda(arg))))(sc, sc->t2_1));
58267 }
58268 
58269 static s7_pointer fx_safe_closure_a_to_vref(s7_scheme *sc, s7_pointer arg) {return(vector_ref_p_pp(sc, fx_call(sc, cdr(arg)), opt3_con(cdr(arg))));}
58270 
58271 static s7_pointer fx_closure_s_and_2(s7_scheme *sc, s7_pointer code) /* safe_closure_s_a where "a" is fx_and_2 */
58272 {
58273   s7_pointer result;
58274   gc_protect_via_stack(sc, sc->curlet);
58275   sc->curlet = update_let_with_slot(sc, closure_let(opt1_lambda(code)), lookup(sc, opt2_sym(code)));
58276   code = cdar(closure_body(opt1_lambda(code)));
58277   result = fx_call(sc, code);  /* have to unwind the stack so this can't return */
58278   if (result != sc->F)
58279     result = fx_call(sc, cdr(code));
58280   sc->curlet = sc->stack_end[-2];
58281   sc->stack_end -= 4;
58282   return(result);
58283 }
58284 
58285 static s7_pointer fx_closure_s_and_pair(s7_scheme *sc, s7_pointer code) /* safe_closure_s_a where "a" is fx_and_2 with is_pair as first clause */
58286 {
58287   s7_pointer result;
58288   gc_protect_via_stack(sc, sc->curlet);
58289   sc->curlet = update_let_with_slot(sc, closure_let(opt1_lambda(code)), lookup(sc, opt2_sym(code)));
58290   code = cdar(closure_body(opt1_lambda(code)));
58291   if (is_pair(t_lookup(sc, cadar(code), code))) /* pair? arg = func par, pair? is global, symbol_id=0 */
58292     result = fx_call(sc, cdr(code));
58293   else result = sc->F;
58294   sc->curlet = sc->stack_end[-2];
58295   sc->stack_end -= 4;
58296   return(result);
58297 }
58298 
58299 static s7_pointer fx_safe_closure_a_a(s7_scheme *sc, s7_pointer code)
58300 {
58301   s7_pointer result;
58302   gc_protect_via_stack(sc, sc->curlet);
58303   sc->curlet = update_let_with_slot(sc, closure_let(opt1_lambda(code)), fx_call(sc, cdr(code)));
58304   result = fx_call(sc, closure_body(opt1_lambda(code)));
58305   sc->curlet = sc->stack_end[-2];
58306   sc->stack_end -= 4;
58307   return(result);
58308 }
58309 
58310 static s7_pointer op_safe_closure_a_a(s7_scheme *sc, s7_pointer code)
58311 {
58312   sc->curlet = update_let_with_slot(sc, closure_let(opt1_lambda(code)), fx_call(sc, cdr(code)));
58313   return(fx_call(sc, closure_body(opt1_lambda(code))));
58314 }
58315 
58316 static s7_pointer fx_safe_closure_a_sqr(s7_scheme *sc, s7_pointer code) {return(fx_sqr_1(sc, fx_call(sc, cdr(code))));}
58317 static s7_pointer fx_safe_closure_s_sqr(s7_scheme *sc, s7_pointer code) {return(fx_sqr_1(sc, lookup(sc, opt2_sym(code))));}
58318 
58319 static s7_pointer fx_safe_closure_a_and_2(s7_scheme *sc, s7_pointer code)
58320 {
58321   s7_pointer and_arg, result;
58322   gc_protect_via_stack(sc, sc->curlet);
58323   sc->curlet = update_let_with_slot(sc, closure_let(opt1_lambda(code)), fx_call(sc, cdr(code)));
58324   and_arg = cdar(closure_body(opt1_lambda(code)));
58325   result = fx_call(sc, and_arg);
58326   if (result != sc->F) result = fx_call(sc, cdr(and_arg));
58327   sc->curlet = sc->stack_end[-2];
58328   sc->stack_end -= 4;
58329   return(result);
58330 }
58331 
58332 static s7_pointer fx_safe_closure_ss_a(s7_scheme *sc, s7_pointer code)
58333 {
58334   s7_pointer result;
58335   gc_protect_via_stack(sc, sc->curlet);
58336   sc->curlet = update_let_with_two_slots(sc, closure_let(opt1_lambda(code)), lookup(sc, cadr(code)), lookup(sc, opt2_sym(code)));
58337   result = fx_call(sc, closure_body(opt1_lambda(code)));
58338   sc->curlet = sc->stack_end[-2];
58339   sc->stack_end -= 4;
58340   return(result);
58341 }
58342 
58343 static s7_pointer op_safe_closure_ss_a(s7_scheme *sc, s7_pointer code)
58344 {
58345   sc->curlet = update_let_with_two_slots(sc, closure_let(opt1_lambda(code)), lookup(sc, cadr(code)), lookup(sc, opt2_sym(code)));
58346   return(fx_call(sc, closure_body(opt1_lambda(code))));
58347 }
58348 
58349 static s7_pointer fx_safe_closure_3s_a(s7_scheme *sc, s7_pointer code)
58350 {
58351   s7_pointer result;
58352   gc_protect_via_stack(sc, sc->curlet);
58353   sc->curlet = update_let_with_three_slots(sc, closure_let(opt1_lambda(code)), lookup(sc, cadr(code)), lookup(sc, opt2_sym(code)), lookup(sc, opt3_sym(code)));
58354   result = fx_call(sc, closure_body(opt1_lambda(code)));
58355   sc->curlet = sc->stack_end[-2];
58356   sc->stack_end -= 4;
58357   return(result);
58358 }
58359 
58360 static s7_pointer op_safe_closure_3s_a(s7_scheme *sc, s7_pointer code)
58361 {
58362   sc->curlet = update_let_with_three_slots(sc, closure_let(opt1_lambda(code)), lookup(sc, cadr(code)), lookup(sc, opt2_sym(code)), lookup(sc, opt3_sym(code)));
58363   return(fx_call(sc, closure_body(opt1_lambda(code))));
58364 }
58365 
58366 static s7_pointer fx_safe_closure_aa_a(s7_scheme *sc, s7_pointer code)
58367 {
58368   s7_pointer f, p;
58369   p = cdr(code);
58370   gc_protect_via_stack(sc, sc->curlet); /* this is needed even if one of the args is a symbol, so nothing is saved by splitting out that case */
58371   sc->stack_end[-4] = fx_call(sc, cdr(p));
58372   f = opt1_lambda(code);
58373   sc->curlet = update_let_with_two_slots(sc, closure_let(f), fx_call(sc, p), sc->stack_end[-4]);
58374   p = fx_call(sc, closure_body(f));
58375   sc->curlet = sc->stack_end[-2];
58376   sc->stack_end -= 4;
58377   return(p);
58378 }
58379 
58380 static inline s7_pointer fx_cond_fx_fx(s7_scheme *sc, s7_pointer code)  /* all tests are fxable, results are all fx, no =>, no missing results */
58381 {
58382   s7_pointer p;
58383   for (p = cdr(code); is_pair(p); p = cdr(p))
58384     if (is_true(sc, fx_call(sc, car(p))))
58385       {
58386 	for (p = cdar(p); is_pair(cdr(p)); p = cdr(p))
58387 	  fx_call(sc, p);
58388 	return(fx_call(sc, p));
58389       }
58390   return(sc->unspecified);
58391 }
58392 
58393 static s7_pointer s7_let_field(s7_scheme *sc, s7_pointer sym);
58394 
58395 static s7_pointer fx_implicit_s7_let_ref_s(s7_scheme *sc, s7_pointer arg) {return(s7_let_field(sc, opt3_sym(arg)));}
58396 static s7_pointer fx_implicit_s7_let_set_sa(s7_scheme *sc, s7_pointer arg) {return(s7_let_field_set(sc, opt3_sym(cdr(arg)), fx_call(sc, cddr(arg))));}
58397 
58398 static s7_function fx_function[NUM_OPS];
58399 
58400 static bool is_fxable(s7_scheme *sc, s7_pointer p)
58401 {
58402   if (!is_pair(p)) return(true);
58403   if ((is_optimized(p)) &&  /* this is needed, why? */
58404       (fx_function[optimize_op(p)]))
58405     return(true);
58406   return(is_proper_quote(sc, p));
58407 }
58408 
58409 static bool is_gxable(s7_pointer p)
58410 {
58411   opcode_t op;
58412   if (!is_optimized(p)) return(false);
58413   op = optimize_op(p);
58414   return((is_symbol(car(p))) && (symbol_ctr(car(p)) == 1) &&
58415 	 (op < FIRST_UNHOPPABLE_OP) &&
58416 	 (op > OP_GC_PROTECT) &&
58417 	 (fx_function[op | 1]));
58418 }
58419 
58420 static int32_t fx_count(s7_scheme *sc, s7_pointer x)
58421 {
58422   int32_t count = 0;
58423   s7_pointer p;
58424   for (p = cdr(x); is_pair(p); p = cdr(p))
58425     if (is_fxable(sc, car(p)))
58426       count++;
58427   return(count);
58428 }
58429 
58430 static bool is_code_constant(s7_scheme *sc, s7_pointer p) {return((is_pair(p)) ? (car(p) == sc->quote_symbol) : is_constant(sc, p));}
58431 
58432 static inline s7_pointer check_quote(s7_scheme *sc, s7_pointer code);
58433 
58434 static s7_p_p_t s7_p_p_function(s7_pointer f);
58435 static s7_p_pp_t s7_p_pp_function(s7_pointer f);
58436 static s7_p_ppp_t s7_p_ppp_function(s7_pointer f);
58437 static s7_p_dd_t s7_p_dd_function(s7_pointer f);
58438 static s7_p_pi_t s7_p_pi_function(s7_pointer f);
58439 static s7_p_ii_t s7_p_ii_function(s7_pointer f);
58440 
58441 #define is_unchanged_global(P) \
58442   ((is_symbol(P)) && (is_global(P)) && (symbol_id(P) == 0) && \
58443   (is_slot(initial_slot(P))) && \
58444   (initial_value(P) == global_value(P)))
58445 
58446 #define is_global_and_has_func(P, Func) ((is_unchanged_global(P)) && (Func(global_value(P)))) /* Func = s7_p_pp_function and friends */
58447 
58448 static bool fx_matches(s7_pointer symbol, s7_pointer target_symbol)
58449 {
58450   return((symbol == target_symbol) &&
58451 	 (is_unchanged_global(symbol)));
58452 }
58453 
58454 /* #define fx_choose(Sc, Holder, E, Checker) fx_choose_1(Sc, Holder, E, Checker, __func__, __LINE__) */
58455 static s7_function fx_choose(s7_scheme *sc, s7_pointer holder, s7_pointer e, safe_sym_t *checker) /* , const char *func, int line) */
58456 {
58457   s7_pointer arg;
58458   arg = car(holder);
58459   if (!is_pair(arg))
58460     {
58461       if (is_symbol(arg))
58462 	{
58463 	  if ((is_keyword(arg)) || ((arg == sc->else_symbol) && (is_global(arg)))) return(fx_c);
58464 	  return((is_global(arg)) ? fx_g : ((checker(sc, arg, e)) ? fx_s : fx_unsafe_s));
58465 	}
58466       return(fx_c);
58467     }
58468 
58469   if (is_optimized(arg))
58470     {
58471       switch (optimize_op(arg))
58472 	{
58473 	case HOP_SAFE_C_D:
58474 	  if (fn_proc(arg) == g_add_i_random) return(fx_add_i_random);
58475 	  return((fn_proc(arg) == g_random_i) ? fx_random_i : fx_c_d);
58476 
58477 	case OP_OR_2:
58478 	  if (fx_proc(cddr(arg)) == fx_and_2) {set_opt3_pair(arg, cdaddr(arg)); return(fx_or_and_2);}
58479 	  if (fx_proc(cddr(arg)) == fx_and_3) {set_opt3_pair(arg, cdaddr(arg)); return(fx_or_and_3);}
58480 	  if ((fx_proc(cdr(arg)) == fx_not_is_symbol_s) && (fx_proc(cddr(arg)) == fx_is_keyword_s) && (cadr(cadadr(arg)) == cadaddr(arg)))
58481 	    {
58482 	      /* (or (not (symbol? body)) (keyword? body)) */
58483 	      set_opt3_sym(arg, cadaddr(arg));
58484 	      return(fx_not_symbol_or_keyword);
58485 	    }
58486 	  return(fx_or_2);
58487 
58488 	case OP_AND_2:
58489 	  if ((fx_proc(cdr(arg)) == fx_or_2) && (fx_proc(cddr(arg)) == fx_or_2))
58490 	    {
58491 	      s7_pointer o1, o2;
58492 	      o1 = cadr(arg);
58493 	      o2 = caddr(arg);
58494 	      if ((fx_proc(cdr(o1)) == fx_gt_vref_s) && (fx_proc(cddr(o1)) == fx_geq_s_vref) && (fx_proc(cdr(o2)) == fx_gt_vref_s) && (fx_proc(cddr(o2)) == fx_geq_s_vref))
58495 		{
58496 		  s7_pointer v;
58497 		  v = cadr(cadadr(o1));
58498 		  if ((v == cadr(cadadr(o2))) && (v == (cadr(caddaddr(o1)))) && (v == (cadr(caddaddr(o2)))))
58499 		    {
58500 		      s7_pointer x;
58501 		      x = caddadr(o1);
58502 		      if ((x == caddadr(o2)) && (x == cadr(caddr(o1))) && (x == cadr(caddr(o2))))
58503 			{
58504 			  s7_pointer i, j;
58505 			  i = caddr(cadadr(o1));
58506 			  j = caddaddr(caddr(o1));
58507 			  if ((j == caddr(cadadr(o2))) && (i == caddaddr(caddr(o2))))
58508 			    return(fx_and_or_2_vref);
58509 			}}}}
58510 	  return(fx_and_2);
58511 
58512 	case HOP_SAFE_C_S:
58513 	  if (is_unchanged_global(car(arg)))
58514 	    {
58515 	      uint8_t typ;
58516 	      if (car(arg) == sc->cdr_symbol) return(fx_cdr_s);
58517 	      if (car(arg) == sc->car_symbol) return(fx_car_s);
58518 	      if (car(arg) == sc->cadr_symbol) return(fx_cadr_s);
58519 	      if (car(arg) == sc->cddr_symbol) return(fx_cddr_s);
58520 	      if (car(arg) == sc->is_null_symbol) return(fx_is_null_s);
58521 	      if (car(arg) == sc->is_pair_symbol) return(fx_is_pair_s);
58522 	      if (car(arg) == sc->is_symbol_symbol) return(fx_is_symbol_s);
58523 	      if (car(arg) == sc->is_eof_object_symbol) return(fx_is_eof_s);
58524 	      if (car(arg) == sc->is_integer_symbol) return(fx_is_integer_s);
58525 	      if (car(arg) == sc->is_string_symbol) return(fx_is_string_s);
58526 	      if (car(arg) == sc->not_symbol) return(fx_not_s);
58527 	      if (car(arg) == sc->is_proper_list_symbol) return(fx_is_proper_list_s);
58528 	      if (car(arg) == sc->is_vector_symbol) return(fx_is_vector_s);
58529 	      if (car(arg) == sc->is_keyword_symbol) return(fx_is_keyword_s);
58530 	      if (car(arg) == sc->is_procedure_symbol) return(fx_is_procedure_s);
58531 	      if (car(arg) == sc->length_symbol) return(fx_length_s);
58532 	      typ = symbol_type(car(arg));
58533 	      if (typ > 0)
58534 		{
58535 		  set_opt3_byte(cdr(arg), typ);
58536 		  return(fx_is_type_s);
58537 		}
58538 	      /* car_p_p (et al) does not look for a method so in:
58539 	       *    (define kar car) (load "mockery.scm") (let ((p (mock-pair '(1 2 3)))) (call-with-exit (lambda (x) (x (kar p)))))
58540 	       *  "kar" fails but not "car" because symbol_id(kar) == 0!  symbol_id(car) > 0 because mockery provides a method for it.
58541 	       */
58542 	      if (symbol_id(make_symbol(sc, c_function_name(global_value(car(arg))))) == 0) /* yow! */
58543 		{
58544 		  s7_p_p_t f;
58545 		  f = s7_p_p_function(global_value(car(arg)));
58546 		  if (f)
58547 		    {
58548 		      set_opt2_direct(cdr(arg), (s7_pointer)f);
58549 		      if (f == real_part_p_p) return(fx_real_part_s);
58550 		      if (f == imag_part_p_p) return(fx_imag_part_s);
58551 		      if (f == iterate_p_p) return(fx_iterate_p_p);
58552 		      if (f == car_p_p) return(fx_car_s);          /* can happen if (define var-name car) etc */
58553 		      return((is_global(cadr(arg))) ? fx_c_g_direct : fx_c_s_direct);
58554 		    }}}
58555 	  return((is_global(cadr(arg))) ? fx_c_g : fx_c_s);
58556 
58557 	case HOP_SAFE_C_SS:
58558 	  if (fn_proc(arg) == g_cons) return(fx_cons_ss);
58559 	  if (fx_matches(car(arg), sc->num_eq_symbol)) return(fx_num_eq_ss);
58560 	  if (fn_proc(arg) == g_geq_2) return(fx_geq_ss);
58561 	  if (fn_proc(arg) == g_greater_2) return(fx_gt_ss);
58562 	  if (fn_proc(arg) == g_leq_2) return(fx_leq_ss);
58563 	  if (fn_proc(arg) == g_less_2) return((is_global(caddr(arg))) ? fx_lt_sg : fx_lt_ss);
58564 	  if ((fx_matches(car(arg), sc->multiply_symbol)) && (cadr(arg) == caddr(arg))) return(fx_sqr_s);
58565 	  if (fn_proc(arg) == g_multiply_2) return(fx_multiply_ss);
58566 	  if (fn_proc(arg) == g_is_eq) return(fx_is_eq_ss);
58567 	  if (fn_proc(arg) == g_add_2) return(fx_add_ss);
58568 	  if (fn_proc(arg) == g_subtract_2) return(fx_subtract_ss);
58569 
58570 	  if ((fn_proc(arg) == g_hash_table_ref_2) && (is_symbol(car(arg))) && (is_symbol(cadr(arg))))
58571 	    return(fx_hash_table_ref_ss);
58572 
58573 	  if (is_global_and_has_func(car(arg), s7_p_pp_function))
58574 	    {
58575 	      if (car(arg) == sc->assq_symbol) return(fx_assq_ss);
58576 	      if (car(arg) == sc->memq_symbol) return(fx_memq_ss);
58577 	      if (car(arg) == sc->vector_ref_symbol) return(fx_vref_ss);
58578 	      if (car(arg) == sc->string_ref_symbol) return(fx_string_ref_ss);
58579 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58580 	      return(fx_c_ss_direct);
58581 	    }
58582 	  /* fx_c_ss_direct via b_7pp is slower than fx_c_ss + g_<> */
58583 	  return(fx_c_ss);
58584 
58585 	case HOP_SAFE_C_opSq_S:
58586 	  if ((is_global_and_has_func(car(arg), s7_p_pp_function)) &&
58587 	      (is_global_and_has_func(caadr(arg), s7_p_p_function)))
58588 	    {
58589 	      set_opt1_sym(cdr(arg), cadadr(arg));
58590 	      set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58591 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_p_function(global_value(caadr(arg)))));
58592 	      return(((car(arg) == sc->cons_symbol) && (caadr(arg) == sc->car_symbol)) ? fx_cons_car_s_s : fx_c_opsq_s_direct);
58593 	    }
58594 	  return(fx_c_opsq_s);
58595 
58596 	case HOP_SAFE_C_SSS:
58597 	  if ((fn_proc(arg) == g_less) && (is_global(cadr(arg))) && (is_global(cadddr(arg)))) return(fx_lt_gsg);
58598 	  if (is_global_and_has_func(car(arg), s7_p_ppp_function))
58599 	    {
58600 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_ppp_function(global_value(car(arg)))));
58601 	      return(fx_c_sss_direct);
58602 	    }
58603 	  return(fx_c_sss);
58604 
58605 	case HOP_SAFE_C_SSA:
58606 	  if (is_global_and_has_func(car(arg), s7_p_ppp_function))
58607 	    {
58608 	      set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_ppp_function(global_value(car(arg)))));
58609 	      set_opt3_pair(arg, cddr(arg));
58610 	      return(fx_c_ssa_direct);
58611 	    }
58612 	  return(fx_c_ssa);
58613 
58614 	case HOP_SAFE_C_SCS:
58615 	  if (is_global_and_has_func(car(arg), s7_p_ppp_function))
58616 	    {
58617 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_ppp_function(global_value(car(arg)))));
58618 	      return(fx_c_scs_direct);
58619 	    }
58620 	  return(fx_c_scs);
58621 
58622 	case HOP_SAFE_C_AAA:
58623 	  if ((fx_proc(cdr(arg)) == fx_g) && (fx_proc(cdddr(arg)) == fx_c)) return(fx_c_gac);
58624 	  if ((is_unquoted_pair(cadr(arg))) || (is_unquoted_pair(caddr(arg))) || (is_unquoted_pair(cadddr(arg))))
58625 	    return(fx_c_aaa);
58626 	  return(fx_c_3g);
58627 
58628 	case HOP_SAFE_C_4A:
58629 	  {
58630 	    s7_pointer p;
58631 	    for (p = cdr(arg); is_pair(p); p = cdr(p))
58632 	      if (is_unquoted_pair(car(p))) break;
58633 	    return((is_null(p)) ? fx_c_4g : fx_c_4a); /* fx_c_ssaa doesn't save much */
58634 	  }
58635 
58636 	case HOP_SAFE_C_S_opSSq:
58637 	  {
58638 	    s7_pointer s2;
58639 	    s2 = caddr(arg);
58640 	    if ((fx_matches(car(s2), sc->multiply_symbol)) && (cadr(s2) == caddr(s2))) return(fx_c_s_sqr);
58641 	  }
58642 	  if ((is_global_and_has_func(car(arg), s7_p_pp_function)) &&
58643 	      (is_global_and_has_func(caaddr(arg), s7_p_pp_function)))
58644 	    {
58645 	      set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58646 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(caaddr(arg)))));
58647 	      set_opt3_pair(arg, cdaddr(arg));
58648 	      if (caaddr(arg) == sc->vector_ref_symbol)
58649 		{
58650 		  if (car(arg) == sc->add_symbol) return(fx_add_s_vref);
58651 		  if (car(arg) == sc->subtract_symbol) return(fx_subtract_s_vref);
58652 		  if (car(arg) == sc->multiply_symbol) return(fx_multiply_s_vref);
58653 		  if (car(arg) == sc->geq_symbol) return(fx_geq_s_vref);
58654 		  if (car(arg) == sc->is_eq_symbol) return(fx_is_eq_s_vref);
58655 		  if ((is_global(cadr(arg))) && (is_global(cadaddr(arg))) && (car(arg) == sc->vector_ref_symbol)) return(fx_vref_g_vref_gs);
58656 		}
58657 	      if ((car(arg) == sc->vector_ref_symbol) && (caaddr(arg) == sc->add_symbol)) return(fx_vref_s_add);
58658 	      return(fx_c_s_opssq_direct);
58659 	    }
58660 	  return(fx_c_s_opssq);
58661 
58662 	case HOP_SAFE_C_opSSq_S:
58663 	  if ((is_global_and_has_func(car(arg), s7_p_pp_function)) &&
58664 	      (is_global_and_has_func(caadr(arg), s7_p_pp_function)))
58665 	    {
58666 	      /* op_c_opgsq_t */
58667 	      set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58668 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(caadr(arg)))));
58669 	      set_opt3_pair(arg, cdadr(arg));
58670 	      if (caadr(arg) == sc->vector_ref_symbol)
58671 		{
58672 		  if (car(arg) == sc->subtract_symbol) return(fx_subtract_vref_s);
58673 		  if (car(arg) == sc->gt_symbol) return(fx_gt_vref_s);
58674 		  if (car(arg) == sc->vector_ref_symbol) return(fx_vref_vref_ss_s);
58675 		  if (car(arg) == sc->add_symbol) return(fx_add_vref_s);
58676 		}
58677 	      if (car(arg) == sc->add_symbol)
58678 		{
58679 		  if ((caadr(arg) == sc->multiply_symbol) && (cadadr(arg) == caddadr(arg))) return(fx_add_sqr_s);
58680 		  if (caadr(arg) == sc->subtract_symbol) return(fx_add_sub_s);
58681 		}
58682 	      return(((car(arg) == sc->gt_symbol) && (caadr(arg) == sc->add_symbol)) ? fx_gt_add_s : fx_c_opssq_s_direct);
58683 	    }
58684 	  return(fx_c_opssq_s);
58685 
58686 	case HOP_SAFE_C_opSSq_opSSq:
58687 	  {
58688 	    s7_pointer s1, s2;
58689 	    s1 = cadr(arg);
58690 	    s2 = caddr(arg);
58691 	    set_opt3_pair(arg, cdaddr(arg));
58692 	    if ((fx_matches(car(s1), sc->multiply_symbol)) && (car(s2) == sc->multiply_symbol))
58693 	      {
58694 		if ((cadr(s1) == caddr(s1)) && (cadr(s2) == caddr(s2))) return(fx_c_sqr_sqr);
58695 		if (car(arg) == sc->subtract_symbol) return(fx_sub_mul2);
58696 		if (car(arg) == sc->add_symbol) return(fx_add_mul2);
58697 	      }
58698 	    if ((fx_matches(car(arg), sc->lt_symbol)) && (fx_matches(car(s1), sc->subtract_symbol)) && (car(s2) == sc->subtract_symbol)) return(fx_lt_sub2);
58699 	    if ((fx_matches(car(arg), sc->subtract_symbol)) && (fx_matches(car(s1), sc->vector_ref_symbol)) && (car(s2) == sc->vector_ref_symbol) && (cadr(s1) == cadr(s2)))
58700 	      {
58701 		set_opt3_sym(arg, cadr(cdaddr(arg)));
58702 		return(fx_sub_vref2);
58703 	      }
58704 	    return(fx_c_opssq_opssq);
58705 	  }
58706 
58707 	case HOP_SAFE_C_opSq:
58708 	  if (is_unchanged_global(caadr(arg)))
58709 	    {
58710 	      if (fx_matches(car(arg), sc->is_pair_symbol))
58711 		{
58712 		  if (caadr(arg) == sc->car_symbol)  {set_opt2_sym(cdr(arg), cadadr(arg)); return(fx_is_pair_car_s);}
58713 		  if (caadr(arg) == sc->cdr_symbol)  {set_opt2_sym(cdr(arg), cadadr(arg)); return(fx_is_pair_cdr_s);}
58714 		  if (caadr(arg) == sc->cadr_symbol) {set_opt2_sym(cdr(arg), cadadr(arg)); return(fx_is_pair_cadr_s);}
58715 		  if (caadr(arg) == sc->cddr_symbol) {set_opt2_sym(cdr(arg), cadadr(arg)); return(fx_is_pair_cddr_s);}
58716 		}
58717 	      if (fx_matches(car(arg), sc->is_null_symbol))
58718 		{
58719 		  if (caadr(arg) == sc->cdr_symbol)  {set_opt2_sym(cdr(arg), cadadr(arg)); return(fx_is_null_cdr_s);}
58720 		  if (caadr(arg) == sc->cadr_symbol) {set_opt2_sym(cdr(arg), cadadr(arg)); return(fx_is_null_cadr_s);}
58721 		  if (caadr(arg) == sc->cddr_symbol) {set_opt2_sym(cdr(arg), cadadr(arg)); return(fx_is_null_cddr_s);}
58722 		}
58723 	      if ((fx_matches(car(arg), sc->is_symbol_symbol)) &&
58724 		  (caadr(arg) == sc->cadr_symbol))
58725 		{set_opt2_sym(cdr(arg), cadadr(arg)); return(fx_is_symbol_cadr_s);}
58726 
58727 	      if (fx_matches(car(arg), sc->not_symbol))
58728 		{
58729 		  if (caadr(arg) == sc->is_pair_symbol)   {set_opt3_sym(arg, cadadr(arg)); return(fx_not_is_pair_s);}
58730 		  if (caadr(arg) == sc->is_null_symbol)   {set_opt3_sym(arg, cadadr(arg)); return(fx_not_is_null_s);}
58731 		  if (caadr(arg) == sc->is_symbol_symbol) {set_opt3_sym(arg, cadadr(arg)); return(fx_not_is_symbol_s);}
58732 		  return(fx_not_opsq);
58733 		}
58734 #if WITH_GMP
58735 	      if ((fx_matches(car(arg), sc->floor_symbol)) && (caadr(arg) == sc->sqrt_symbol))
58736 		{set_opt2_sym(cdr(arg), cadadr(arg)); return(fx_floor_sqrt_s);}
58737 #endif
58738 	    }
58739 	  if (is_unchanged_global(car(arg)))     /* (? (op arg)) where (op arg) might return a let with a ? method etc */
58740 	    {                          /*    other possibility: fx_c_a */
58741 	      uint8_t typ;
58742 	      typ = symbol_type(car(arg));
58743 	      if (typ > 0)             /* h_safe_c here so the type checker isn't shadowed */
58744 		{
58745 		  set_opt2_sym(cdr(arg), cadadr(arg));
58746 		  set_opt3_byte(cdr(arg), typ);
58747 		  if (fn_proc(cadr(arg)) == (s7_function)g_c_pointer_weak1)
58748 		    return(fx_c_weak1_type_s);
58749 		  return(fx_matches(caadr(arg), sc->car_symbol) ? fx_is_type_car_s : fx_is_type_opsq);
58750 		}}
58751 	  /* this should follow the is_type* check above */
58752 	  if (fx_matches(caadr(arg), sc->car_symbol))
58753 	    {
58754 	      set_opt2_sym(cdr(arg), cadadr(arg));
58755 	      return(fx_c_car_s);
58756 	    }
58757 	  if (fx_matches(caadr(arg), sc->cdr_symbol))
58758 	    {
58759 	      set_opt2_sym(cdr(arg), cadadr(arg));
58760 	      return(fx_c_cdr_s);
58761 	    }
58762 	  return(fx_c_opsq);
58763 
58764 	case HOP_SAFE_C_SC:
58765 	  if (is_unchanged_global(car(arg)))
58766 	    {
58767 	      if (car(arg) == sc->add_symbol)
58768 		{
58769 		  if (is_t_real(caddr(arg))) return(fx_add_sf);
58770 		  if (is_t_integer(caddr(arg))) return((integer(caddr(arg)) == 1) ? fx_add_s1 : fx_add_si);
58771 		}
58772 	      if (car(arg) == sc->subtract_symbol)
58773 		{
58774 		  if (is_t_real(caddr(arg))) return(fx_subtract_sf);
58775 		  if (is_t_integer(caddr(arg))) return((integer(caddr(arg)) == 1) ? fx_subtract_s1 : fx_subtract_si);
58776 		}
58777 	      if (car(arg) == sc->multiply_symbol)
58778 		{
58779 		  if (is_t_real(caddr(arg))) return(fx_multiply_sf);
58780 		  if (is_t_integer(caddr(arg))) return(fx_multiply_si);
58781 		}
58782 	      if ((car(arg) == sc->num_eq_symbol) && (is_t_integer(caddr(arg)))) return(fx_num_eq_si);
58783 	      if ((fn_proc(arg) == g_memq_2) && (is_pair(caddr(arg)))) return(fx_memq_sq_2);
58784 	      if ((fn_proc(arg) == g_is_eq) && (!is_unspecified(caddr(arg)))) return(fx_is_eq_sc);
58785 
58786 	      if ((is_t_integer(caddr(arg))) && (s7_p_pi_function(global_value(car(arg)))))
58787 		{
58788 		  if (car(arg) == sc->lt_symbol) return(fx_lt_si);
58789 		  if (car(arg) == sc->leq_symbol) return(fx_leq_si);
58790 		  if (car(arg) == sc->gt_symbol) return(fx_gt_si);
58791 		  if (car(arg) == sc->geq_symbol) return(fx_geq_si);
58792 		  set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pi_function(global_value(car(arg)))));
58793 		  return(fx_c_si_direct);
58794 		}
58795 	      if ((s7_p_pp_function(global_value(car(arg)))) && (fn_proc(arg) != g_divide_by_2))
58796 		{
58797 		  if (car(arg) == sc->memq_symbol)
58798 		    {
58799 		      if ((is_pair(caddr(arg))) && (is_proper_list_3(sc, cadr(caddr(arg))))) return(fx_memq_sc_3);
58800 		      return(fx_memq_sc);
58801 		    }
58802 		  if ((car(arg) == sc->char_eq_symbol) && (s7_is_character(caddr(arg)))) return(fx_char_eq_sc);
58803 		  if (car(arg) == sc->lt_symbol) return(fx_lt_sc); /* integer case handled above */
58804 		  if (car(arg) == sc->leq_symbol) return(fx_leq_sc);
58805 		  if (car(arg) == sc->gt_symbol) return(fx_gt_sc);
58806 		  if (car(arg) == sc->geq_symbol) return(fx_geq_sc);
58807 		  set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58808 		  return(fx_c_sc_direct);
58809 		}}
58810 	  return(fx_c_sc);
58811 
58812 	case HOP_SAFE_C_CS:
58813 	  if (is_unchanged_global(car(arg)))
58814 	    {
58815 	      if ((car(arg) == sc->add_symbol) && (is_t_real(cadr(arg)))) return(fx_add_fs);
58816 	      if ((car(arg) == sc->subtract_symbol) && (is_t_real(cadr(arg)))) return(fx_subtract_fs);
58817 	      if (car(arg) == sc->multiply_symbol)
58818 		{
58819 		  if (is_t_real(cadr(arg))) return(fx_multiply_fs);
58820 		  if (is_t_integer(cadr(arg))) return(fx_multiply_is);
58821 		}}
58822 	  return(fx_c_cs);
58823 
58824 	case HOP_SAFE_C_S_opSq:
58825 	  if (fx_matches(car(caddr(arg)), sc->car_symbol))
58826 	    {
58827 	      if (fx_matches(car(arg), sc->hash_table_ref_symbol))
58828 		{
58829 		  set_opt2_sym(cdr(arg), cadaddr(arg));
58830 		  return(fx_hash_table_ref_car);
58831 		}
58832 	      set_opt2_sym(cdr(arg), cadaddr(arg));
58833 	      return(fx_matches(car(arg), sc->add_symbol) ? fx_add_s_car_s : fx_c_s_car_s);
58834 	    }
58835 
58836 	  if ((is_global_and_has_func(car(arg), s7_p_pp_function)) &&
58837 	      (is_global_and_has_func(caaddr(arg), s7_p_p_function)))
58838 	    {
58839 	      set_opt1_sym(cdr(arg), cadaddr(arg));
58840 	      set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58841 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_p_function(global_value(caaddr(arg)))));
58842 	      return(fx_c_s_opsq_direct);
58843 	    }
58844 	  return(fx_c_s_opsq);
58845 
58846 	case HOP_SAFE_C_C_opSq:
58847 	  if (is_global_and_has_func(car(arg), s7_p_pp_function))
58848 	    {
58849 	      s7_pointer arg2;
58850 	      arg2 = caddr(arg);
58851 	      if (is_global_and_has_func(car(arg2), s7_p_p_function))
58852 		{
58853 		  set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58854 		  set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_p_function(global_value(car(arg2)))));
58855 		  set_opt1_sym(cdr(arg), cadr(arg2));
58856 		  return(fx_c_c_opsq_direct);
58857 		}}
58858 	  return(fx_c_c_opsq);
58859 
58860 	case HOP_SAFE_C_opSq_C:
58861 	  if (is_unchanged_global(car(arg)))
58862 	    {
58863 	      if ((car(arg) == sc->memq_symbol) &&
58864 		  (fx_matches(caadr(arg), sc->car_symbol)) &&
58865 		  (is_proper_quote(sc, caddr(arg))) &&
58866 		  (is_pair(cadaddr(arg))))
58867 		return((s7_list_length(sc, opt2_con(cdr(arg))) == 2) ? fx_memq_car_s_2 : fx_memq_car_s);
58868 
58869 	      if (car(arg) == sc->is_eq_symbol)
58870 		{
58871 		  if (((fx_matches(caadr(arg), sc->car_symbol)) || (fx_matches(caadr(arg), sc->caar_symbol))) &&
58872 		      (is_proper_quote(sc, caddr(arg))))
58873 		    {
58874 		      set_opt3_sym(cdr(arg), cadadr(arg));
58875 		      set_opt2_con(cdr(arg), cadaddr(arg));
58876 		      return((caadr(arg) == sc->car_symbol) ? fx_is_eq_car_q : fx_is_eq_caar_q);
58877 		    }}
58878 	      if (((car(arg) == sc->lt_symbol) || (car(arg) == sc->num_eq_symbol)) &&
58879 		  (is_t_integer(caddr(arg))) &&
58880 		  (fx_matches(caadr(arg), sc->length_symbol)))
58881 		{
58882 		  set_opt3_sym(cdr(arg), cadadr(arg));
58883 		  set_opt2_con(cdr(arg), caddr(arg));
58884 		  return((car(arg) == sc->lt_symbol) ? fx_less_length_i : fx_num_eq_length_i);
58885 		}}
58886 	  set_opt1_sym(cdr(arg), cadadr(arg));
58887 	  return(fx_c_opsq_c);
58888 
58889 	case HOP_SAFE_C_op_opSqq:
58890 	  return((fx_matches(car(arg), sc->not_symbol)) ? fx_not_op_opsqq : fx_c_op_opsqq);
58891 
58892 	case HOP_SAFE_C_opSCq:
58893 	  if (fx_matches(car(arg), sc->not_symbol))
58894 	    {
58895 	      if (fn_proc(cadr(arg)) == g_is_eq)
58896 		{
58897 		  set_opt2_sym(cdr(arg), cadr(cadr(arg)));
58898 		  set_opt3_con(cdr(arg), (is_pair(caddadr(arg))) ? cadaddr(cadr(arg)) : caddadr(arg));
58899 		  return(fx_not_is_eq_sq);
58900 		}
58901 	      return(fx_not_opscq);
58902 	    }
58903 	  return(fx_c_opscq);
58904 
58905 	case HOP_SAFE_C_S_opSCq:
58906 	  if (is_global_and_has_func(car(arg), s7_p_pp_function))
58907 	    {
58908 	      s7_pointer arg2;
58909 	      arg2 = caddr(arg);
58910 	      if ((is_global_and_has_func(car(arg2), s7_p_pi_function)) &&
58911 		  (is_t_integer(caddr(arg2))))
58912 		{
58913 		  set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58914 		  set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pi_function(global_value(car(arg2)))));
58915 		  set_opt3_sym(arg, cadr(arg2));
58916 		  set_opt1_con(cdr(arg), caddr(arg2));
58917 		  if (car(arg) == sc->num_eq_symbol)
58918 		    {
58919 		      if (car(arg2) == sc->add_symbol) return(fx_num_eq_add_s_si);
58920 		      if (car(arg2) == sc->subtract_symbol) return(fx_num_eq_subtract_s_si);
58921 		    }
58922 		  if ((car(arg) == sc->vector_ref_symbol) && (car(arg2) == sc->add_symbol) && (integer(caddr(arg2)) == 1))
58923 		    return(fx_vref_p1);
58924 		  return(fx_c_s_opsiq_direct);
58925 		}
58926 	      if (is_global_and_has_func(car(arg2), s7_p_pp_function))
58927 		{
58928 		  set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58929 		  set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg2)))));
58930 		  set_opt3_sym(arg, cadr(arg2));
58931 		  set_opt1_con(cdr(arg), (is_pair(caddr(arg2))) ? cadr(caddr(arg2)) : caddr(arg2));
58932 		  return(fx_c_s_opscq_direct);
58933 		}}
58934 	  return(fx_c_s_opscq);
58935 
58936 	case HOP_SAFE_C_opSSq:
58937 	  if (fx_matches(car(arg), sc->not_symbol))
58938 	    {
58939 	      if (fn_proc(cadr(arg)) == g_is_eq)
58940 		{
58941 		  set_opt2_sym(cdr(arg), cadr(cadr(arg)));
58942 		  set_opt3_sym(cdr(arg), caddadr(arg));
58943 		  return(fx_not_is_eq_ss);
58944 		}
58945 	      return(fx_not_opssq);
58946 	    }
58947 	  if ((is_global_and_has_func(car(arg), s7_p_p_function)) &&
58948 	      (is_global_and_has_func(caadr(arg), s7_p_pp_function)))
58949 	    {
58950 	      set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_p_function(global_value(car(arg)))));
58951 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(caadr(arg)))));
58952 	      set_opt3_sym(arg, cadadr(arg));
58953 	      set_opt1_sym(cdr(arg), caddadr(arg));
58954 	      return(fx_c_opssq_direct);
58955 	    }
58956 	  return(fx_c_opssq);
58957 
58958 	case HOP_SAFE_C_C_opSSq:
58959 	  {
58960 	    s7_pointer s2;
58961 	    s2 = caddr(arg);
58962 	    if ((fx_matches(car(s2), sc->multiply_symbol)) && (cadr(s2) == caddr(s2)))
58963 	      return(fx_c_c_sqr);
58964 	  }
58965 	  if ((is_small_real(cadr(arg))) &&
58966 	      (is_global_and_has_func(car(arg), s7_p_dd_function)) &&
58967 	      (is_global_and_has_func(caaddr(arg), s7_d_pd_function))) /* not * currently (this is for clm) */
58968 	    {
58969 	      set_opt3_direct(cdr(arg), s7_d_pd_function(global_value(caaddr(arg))));
58970 	      set_opt2_direct(cdr(arg), s7_p_dd_function(global_value(car(arg))));
58971 	      set_opt3_sym(arg, cadaddr(arg));
58972 	      set_opt1_sym(cdr(arg), caddaddr(arg));
58973 	      return(fx_c_d_opssq_direct);
58974 	    }
58975 	  if ((is_global_and_has_func(car(arg), s7_p_pp_function)) &&
58976 	      (is_global_and_has_func(caaddr(arg), s7_p_pp_function)))
58977 	    {
58978 	      set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58979 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(caaddr(arg)))));
58980 	      set_opt3_sym(arg, cadaddr(arg));
58981 	      set_opt1_sym(cdr(arg), caddaddr(arg));
58982 	      if ((is_t_real(cadr(arg))) && (car(arg) == caaddr(arg)) && (car(arg) == sc->multiply_symbol)) return(fx_c_d_opssq_multiply);
58983 	      return(fx_c_c_opssq_direct);
58984 	    }
58985 	  return(fx_c_c_opssq);
58986 
58987 	case HOP_SAFE_C_opSq_opSq:
58988 	  if ((is_global_and_has_func(car(arg), s7_p_pp_function)) &&
58989 	      (is_global_and_has_func(caadr(arg), s7_p_p_function)) &&
58990 	      (is_global_and_has_func(caaddr(arg), s7_p_p_function)))
58991 	    {
58992 	      set_opt3_direct(arg, (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
58993 	      set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_p_function(global_value(caadr(arg)))));
58994 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_p_function(global_value(caaddr(arg)))));
58995 	      if ((caadr(arg) == caaddr(arg)) && (caadr(arg) == sc->cdr_symbol))
58996 		{
58997 		  set_opt1_sym(cdr(arg), cadadr(arg));
58998 		  set_opt2_sym(cdr(arg), cadaddr(arg));
58999 		  return(fx_cdr_cdr);
59000 		}
59001 	      set_opt1_sym(cdr(arg), cadaddr(arg)); /* opt2 is taken by second func */
59002 	      return(fx_c_opsq_opsq_direct);
59003 	    }
59004 	  return(fx_c_opsq_opsq);
59005 
59006 	case HOP_SAFE_C_op_S_opSqq:
59007 	  return((fx_matches(car(arg), sc->not_symbol)) ? fx_not_op_s_opsqq : fx_c_op_s_opsqq);
59008 
59009 	case HOP_SAFE_C_op_opSSqq_S:
59010 	  if ((is_global_and_has_func(car(arg), s7_p_pp_function)) &&
59011 	      (is_global_and_has_func(caadr(arg), s7_p_p_function)) &&
59012 	      (is_global_and_has_func(car(cadr(cadr(arg))), s7_p_pp_function)))
59013 	    {
59014 	      set_opt3_direct(arg, (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
59015 	      set_opt2_direct(cdr(arg), (s7_pointer)(s7_p_p_function(global_value(caadr(arg)))));
59016 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(caadr(cadr(arg))))));
59017 	      return(fx_c_op_opssqq_s_direct);
59018 	    }
59019 	  return(fx_c_op_opssqq_s);
59020 
59021 	case HOP_SAFE_C_A:
59022 	  if (fx_matches(car(arg), sc->not_symbol))
59023 	    {
59024 	      if (fx_proc(cdr(arg)) == fx_is_eq_car_q)
59025 		{
59026 		  set_opt1_sym(cdr(arg), cadadr(cadr(arg)));
59027 		  set_opt3_con(cdr(arg), cadaddr(cadr(arg)));
59028 		  return(fx_not_is_eq_car_q);
59029 		}
59030 	      return(fx_not_a);
59031 	    }
59032 	  if (is_global_and_has_func(car(arg), s7_p_p_function))
59033 	    {
59034 	      set_opt3_direct(arg, (s7_pointer)(s7_p_p_function(global_value(car(arg)))));
59035 	      return(fx_c_a_direct);
59036 	    }
59037 	  return(fx_c_a);
59038 
59039 	case HOP_SAFE_C_AC:
59040 	  return((fx_matches(car(arg), sc->is_eq_symbol)) ? fx_is_eq_ac : fx_c_ac);
59041 
59042 	case HOP_SAFE_C_SA:
59043 	  if (fn_proc(arg) == g_multiply_2) return(fx_multiply_sa);
59044 	  if (fn_proc(arg) == g_add_2) return(fx_add_sa);
59045 	  if (is_global_and_has_func(car(arg), s7_p_pp_function))
59046 	    {
59047 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
59048 	      return(fx_c_sa_direct);
59049 	    }
59050 	  return(fx_c_sa);
59051 
59052 	case HOP_SAFE_C_AS:
59053 	  if (fn_proc(arg) == g_add_2) return(fx_add_as);
59054 	  if (is_global_and_has_func(car(arg), s7_p_pp_function))
59055 	    {
59056 	      set_opt3_direct(cdr(arg), (s7_pointer)(s7_p_pp_function(global_value(car(arg)))));
59057 	      return(fx_c_as_direct);
59058 	    }
59059 	  return(fx_c_as);
59060 
59061 	case HOP_SAFE_C_AA:
59062 	  /* (* wr (float-vector-ref rl 0 j)) (* wr (block-ref (vector-ref rl j) 0)) (- (float-vector-ref rl 0 i) tempr)  */
59063 	  if (fn_proc(arg) == g_add_2) return(fx_add_aa);
59064 	  if (fn_proc(arg) == g_subtract_2) return(fx_subtract_aa);
59065 	  if (fn_proc(arg) == g_number_to_string) return(fx_number_to_string_aa);
59066 	  /* we can get here from gx_annotate which does not call fx_tree, where A=fx_unsafe_s */
59067 	  if (fx_proc(cdr(arg)) == fx_unsafe_s) {set_opt3_sym(arg, cadr(arg)); return(fx_c_za);}
59068 	  return((fn_proc(arg) == g_multiply_2) ? fx_multiply_aa : fx_c_aa);
59069 
59070 	case HOP_SAFE_C_opAAq:
59071 	  return((fx_proc(cdadr(arg)) == fx_s) ? fx_c_opsaq : fx_c_opaaq);
59072 
59073 	case HOP_SAFE_C_ALL_A:
59074 	  return((fn_proc(arg) == g_vector) ? fx_vector_all_a : fx_c_all_a);
59075 
59076 	case HOP_SAFE_CLOSURE_S_A:
59077 	  {
59078 	    s7_pointer body;
59079 	    body = car(closure_body(opt1_lambda(arg)));
59080 	    if (is_pair(body))
59081 	      {
59082 		if (optimize_op(body) == OP_AND_2)
59083 		  {
59084 		    if ((fx_matches(caadr(body), sc->is_pair_symbol)) &&
59085 			(cadadr(body) == car(closure_args(opt1_lambda(arg)))))
59086 		      return(fx_closure_s_and_pair);       /* lint arg: (len>1? init), args: (x) body: (and (pair? x) (pair? (cdr x))) */
59087 		    return(fx_closure_s_and_2);
59088 		  }
59089 		if (optimize_op(body) == HOP_SAFE_C_opSq_C)
59090 		  {
59091 		    if ((fn_proc(body) == g_lint_let_ref) &&
59092 			(cadadr(body) == car(closure_args(opt1_lambda(arg)))))
59093 		      {
59094 			set_opt2_sym(cdr(arg), cadaddr(body));
59095 			return(fx_lint_let_ref); /* (var-ref local-var) -> (let-ref (cdr v=local_var) 'ref) */
59096 		      }}}
59097 	    return((fx_proc(closure_body(opt1_lambda(arg))) == fx_sqr_t) ? fx_safe_closure_s_sqr : fx_safe_closure_s_a);
59098 	  }
59099 
59100 	case HOP_SAFE_CLOSURE_S_TO_SC:
59101 	  {
59102 	    s7_pointer body;
59103 	    body = car(closure_body(opt1_lambda(arg)));
59104 	    if (fn_proc(body) == g_vector_ref_2) return(fx_safe_closure_s_to_vref);
59105 	    if ((is_t_integer(caddr(body))) && (integer(caddr(body)) == 1))
59106 	      {
59107 		if (car(body) == sc->subtract_symbol) return(fx_safe_closure_s_to_sub1);
59108 		if (car(body) == sc->add_symbol) return(fx_safe_closure_s_to_add1);
59109 	      }
59110 	    return(fx_safe_closure_s_to_sc);
59111 	  }
59112 
59113 	case HOP_SAFE_CLOSURE_A_TO_SC:
59114 	  return((fn_proc(car(closure_body(opt1_lambda(arg)))) == g_vector_ref_2) ? fx_safe_closure_a_to_vref : fx_safe_closure_a_to_sc);
59115 
59116 	case HOP_SAFE_CLOSURE_A_A:
59117 	  if (fx_proc(closure_body(opt1_lambda(arg))) == fx_and_2)
59118 	    return(fx_safe_closure_a_and_2);
59119 	  return((fx_proc(closure_body(opt1_lambda(arg))) == fx_sqr_t) ? fx_safe_closure_a_sqr : fx_safe_closure_a_a);
59120 
59121 	case HOP_SAFE_CLOSURE_3S_A:
59122 	  {
59123 	    s7_pointer body;
59124 	    body = closure_body(opt1_lambda(arg));
59125 	    if ((has_fx(body)) && (fx_proc(body) == fx_vref_vref_tu_s))
59126 	      return(fx_vref_vref_3_no_let);
59127 	  }
59128 
59129 	default:
59130 	  /* if ((!fx_function[optimize_op(arg)]) && (is_h_optimized(arg))) fprintf(stderr, "fx_choose %s %s\n", op_names[optimize_op(arg)], display(arg)); */
59131 	  return(fx_function[optimize_op(arg)]);
59132 	}} /* is_optimized */
59133 
59134   if ((car(arg) == sc->quote_symbol) &&
59135       (is_global(sc->quote_symbol)))
59136     {
59137       check_quote(sc, arg);
59138       return(fx_q);
59139     }
59140   return(NULL);
59141 }
59142 
59143 #if S7_DEBUGGING
59144 #define with_fx(P, F) with_fx_1(sc, P, F)
59145 static bool with_fx_1(s7_scheme *sc, s7_pointer p, s7_function f) /* sc needed for set_opt2 under debugger = set_opt2_1(sc,...) */
59146 #else
59147 static bool with_fx(s7_pointer p, s7_function f)
59148 #endif
59149 {
59150   set_fx_direct(p, f);
59151   return(true);
59152 }
59153 
59154 static bool fx_tree_out(s7_scheme *sc, s7_pointer tree, s7_pointer var1, s7_pointer var2)
59155 {
59156   s7_pointer p;
59157   /* fprintf(stderr, "%s[%d] %s %s %d: %s\n", __func__, __LINE__, display(var1), (var2) ? display(var2) : "", has_fx(tree), display(tree)); */
59158   p = car(tree);
59159   if (is_symbol(p))
59160     {
59161       if (fx_proc(tree) == fx_s)
59162 	{
59163 	  if (p == var1) return(with_fx(tree, fx_T));
59164 	  if (p == var2) return(with_fx(tree, fx_U));
59165 	}
59166       return(false);
59167     }
59168   if ((is_pair(p)) && (is_pair(cdr(p))))
59169     {
59170       if (cadr(p) == var1)
59171 	{
59172 	  if (fx_proc(tree) == fx_c_s) return(with_fx(tree, fx_c_T)); /* fx_c_T_direct got no hits */
59173 	  if (fx_proc(tree) == fx_subtract_s1) return(with_fx(tree, fx_subtract_T1));
59174 	  if (fx_proc(tree) == fx_add_s1) return(with_fx(tree, fx_add_T1));
59175 	  if (fx_proc(tree) == fx_c_sca) return(with_fx(tree, fx_c_Tca));
59176 	  if (fx_proc(tree) == fx_num_eq_si) return(with_fx(tree, fx_num_eq_Ti));
59177 	  if (fx_proc(tree) == fx_multiply_ss) return(with_fx(tree, fx_multiply_Ts));
59178 	}
59179       else
59180 	{
59181 	  if (cadr(p) == var2)
59182 	    {
59183 	      if (fx_proc(tree) == fx_subtract_s1) return(with_fx(tree, fx_subtract_U1));
59184 	      if (fx_proc(tree) == fx_add_s1) return(with_fx(tree, fx_add_U1));
59185 	    }
59186 	  else
59187 	    if (is_pair(cddr(p)))
59188 	      {
59189 		if (caddr(p) == var1)
59190 		  {
59191 		    if (fx_proc(tree) == fx_num_eq_ts) return(with_fx(tree, fx_num_eq_tT));
59192 		    if (fx_proc(tree) == fx_gt_ts) return(with_fx(tree, fx_gt_tT));
59193 		    if (fx_proc(tree) == fx_geq_ts) return(with_fx(tree, fx_geq_tT));
59194 		  }
59195 		else
59196 		  if (caddr(p) == var2)
59197 		    {
59198 		      if (fx_proc(tree) == fx_c_ts) return(with_fx(tree, fx_c_tU));
59199 		      if (fx_proc(tree) == fx_cons_ts) return(with_fx(tree, fx_cons_tU));
59200 		      if (fx_proc(tree) == fx_c_ts_direct) return(with_fx(tree, fx_c_tU_direct));
59201 		      if (fx_proc(tree) == fx_lt_ts) return(with_fx(tree, fx_lt_tU));
59202 		    }}}}
59203   return(false);
59204 }
59205 
59206 static s7_b_7p_t s7_b_7p_function(s7_pointer f);
59207 
59208 #define SHOW_FX_TREE 0
59209 #if SHOW_FX_TREE
59210 #define fx_tree_in(Sc, Tree, Var1, Var2) fx_tree_in_1(Sc, Tree, Var1, Var2, __func__, __LINE__)
59211 static bool fx_tree_in_1(s7_scheme *sc, s7_pointer tree, s7_pointer var1, s7_pointer var2, const char *func, int line)
59212 #else
59213 static bool fx_tree_in(s7_scheme *sc, s7_pointer tree, s7_pointer var1, s7_pointer var2) /* const char *func, int line) */ /* var2 can be NULL */
59214 #endif
59215 {
59216   /* extending this to a third variable did not get many hits */
59217   s7_pointer p;
59218 #if SHOW_FX_TREE
59219   if (is_pair(car(tree)))
59220     fprintf(stderr, "  %s[%d] %s %s %d %s: %s\n", func, line, display(var1), (var2) ? display(var2) : "", has_fx(tree), op_names[optimize_op(car(tree))], display(car(tree)));
59221 #endif
59222 #if S7_DEBUGGING
59223   if ((!is_symbol(var1)) || ((var2) && (!is_symbol(var2))))
59224     {
59225       fprintf(stderr, "%s %s %s\n", __func__, display(var1), (var2) ? display(var2) : "");
59226       if (sc->stop_at_error) abort();
59227     }
59228 #endif
59229   p = car(tree);
59230   if (is_symbol(p))
59231     {
59232       if (fx_proc(tree) == fx_s)
59233 	{
59234 	  if (p == var1) return(with_fx(tree, fx_t));
59235 	  if (p == var2) return(with_fx(tree, fx_u));
59236 	}
59237       return(false);
59238     }
59239 #if S7_DEBUGGING
59240   if (!has_fx(tree)) fprintf(stderr, "%s[%d]: no fx! %s\n", __func__, __LINE__, display_80(p));
59241 #endif
59242   if (!is_pair(p)) return(false);
59243   switch (optimize_op(p))
59244     {
59245     case HOP_SAFE_C_S:
59246       if (cadr(p) == var1)
59247 	{
59248 	  if (fx_proc(tree) == fx_c_s) return(with_fx(tree, fx_c_t));
59249 	  if (fx_proc(tree) == fx_c_s_direct) return(with_fx(tree, (opt2_direct(cdr(p)) == (s7_pointer)cddr_p_p) ? fx_cddr_t : fx_c_t_direct));
59250 	  if (fx_proc(tree) == fx_car_s) return(with_fx(tree, fx_car_t));
59251 	  if (fx_proc(tree) == fx_cdr_s) return(with_fx(tree, fx_cdr_t));
59252 	  if (fx_proc(tree) == fx_cddr_s) return(with_fx(tree, fx_cddr_t));
59253 	  if (fx_proc(tree) == fx_cadr_s) return(with_fx(tree, fx_cadr_t));
59254 	  if (fx_proc(tree) == fx_not_s) return(with_fx(tree, fx_not_t));
59255 	  if (fx_proc(tree) == fx_is_null_s) return(with_fx(tree, fx_is_null_t));
59256 	  if (fx_proc(tree) == fx_is_pair_s) return(with_fx(tree, fx_is_pair_t));
59257 	  if (fx_proc(tree) == fx_is_symbol_s) return(with_fx(tree, fx_is_symbol_t));
59258 	  if (fx_proc(tree) == fx_is_eof_s) return(with_fx(tree, fx_is_eof_t));
59259 	  if (fx_proc(tree) == fx_is_string_s) return(with_fx(tree, fx_is_string_t));
59260 	  if (fx_proc(tree) == fx_is_vector_s) return(with_fx(tree, fx_is_vector_t));
59261 	  if (fx_proc(tree) == fx_is_type_s) return(with_fx(tree, fx_is_type_t));
59262 	  if (fx_proc(tree) == fx_length_s) return(with_fx(tree, fx_length_t));
59263 	}
59264       if (cadr(p) == var2)
59265 	{
59266 	  if (fx_proc(tree) == fx_c_s)
59267 	    {
59268 	      if (is_global_and_has_func(car(p), s7_p_p_function))
59269 		{
59270 		  set_opt2_direct(cdr(p), (s7_pointer)(s7_p_p_function(global_value(car(p)))));
59271 		  return(with_fx(tree, (car(p) == sc->cddr_symbol) ? fx_cddr_u :
59272 				     ((car(p) == sc->is_positive_symbol) ? fx_is_positive_u :
59273 				      ((car(p) == sc->is_zero_symbol) ? fx_is_zero_u : fx_c_u_direct))));
59274 		}
59275 	      return(with_fx(tree, fx_c_u));
59276 	    }
59277 	  if (fx_proc(tree) == fx_c_s_direct)
59278 	    return(with_fx(tree, (car(p) == sc->cddr_symbol) ? fx_cddr_u :
59279 			       ((car(p) == sc->is_positive_symbol) ? fx_is_positive_u :
59280 				((car(p) == sc->is_zero_symbol) ? fx_is_zero_u : fx_c_u_direct))));
59281 
59282 	  if (fx_proc(tree) == fx_cdr_s) return(with_fx(tree, fx_cdr_u));
59283 	  if (fx_proc(tree) == fx_cddr_s) return(with_fx(tree, fx_cddr_u));
59284 	  if (fx_proc(tree) == fx_car_s) return(with_fx(tree, fx_car_u));
59285 	  if (fx_proc(tree) == fx_is_null_s) return(with_fx(tree, fx_is_null_u));
59286 	  if (fx_proc(tree) == fx_is_type_s) return(with_fx(tree, fx_is_type_u));
59287 	  if (fx_proc(tree) == fx_is_pair_s) return(with_fx(tree, fx_is_pair_u));
59288 	}
59289       break;
59290 
59291     case HOP_SAFE_C_SC:
59292       if (cadr(p) == var1)
59293 	{
59294 	  if ((fx_proc(tree) == fx_char_eq_sc) || (fn_proc(p) == g_char_equal_2)) return(with_fx(tree, fx_char_eq_tc));
59295 	  if (fx_proc(tree) == fx_c_sc) return(with_fx(tree, fx_c_tc));
59296 	  if (fx_proc(tree) == fx_add_sf) return(with_fx(tree, fx_add_tf));
59297 
59298 	  if (fn_proc(p) == g_less_xf) return(with_fx(tree, fx_lt_tf));
59299 	  if ((fn_proc(p) == g_less_xi) || (fn_proc(p) == g_less_x0)) return(with_fx(tree, fx_lt_ti));
59300 	  if (fn_proc(p) == g_geq_xf) return(with_fx(tree, fx_geq_tf));
59301 	  if (fn_proc(p) == g_geq_xi) return(with_fx(tree, fx_geq_ti));
59302 	  if (fn_proc(p) == g_leq_xi) return(with_fx(tree, fx_leq_ti));
59303 	  if (fn_proc(p) == g_greater_xi) return(with_fx(tree, fx_gt_ti));
59304 
59305 	  if (fx_proc(tree) == fx_c_sc_direct) /* p_pp cases */
59306 	    {
59307 	      if ((opt3_direct(cdr(p)) == (s7_pointer)vector_ref_p_pp) && (is_t_integer(caddr(p))))
59308 		return(with_fx(tree, fx_vector_ref_direct));
59309 	      if ((opt3_direct(cdr(p)) == (s7_pointer)string_ref_p_pp) && (is_t_integer(caddr(p))) && (integer(caddr(p)) == 0))
59310 		set_opt3_direct(cdr(p), string_ref_p_p0);
59311 	      return(with_fx(tree, fx_c_tc_direct));
59312 	    }
59313 	  if (fx_proc(tree) == fx_c_si_direct) /* p_pi cases */
59314 	    {
59315 	      if (opt3_direct(cdr(p)) == (s7_pointer)vector_ref_p_pi)
59316 		return(with_fx(tree, fx_vector_ref_direct));
59317 	      if ((opt3_direct(cdr(p)) == (s7_pointer)string_ref_p_pi) && (integer(caddr(p)) == 0))
59318 		set_opt3_direct(cdr(p), string_ref_p_p0);
59319 	      return(with_fx(tree, fx_c_ti_direct));
59320 	    }
59321 
59322 	  if (fx_proc(tree) == fx_is_eq_sc) return(with_fx(tree, fx_is_eq_tc));
59323 	  if (fx_proc(tree) == fx_add_si) return(with_fx(tree, fx_add_ti));
59324 	  if (fx_proc(tree) == fx_add_s1) return(with_fx(tree, fx_add_t1));
59325 	  if (fx_proc(tree) == fx_subtract_s1) return(with_fx(tree, fx_subtract_t1));
59326 	  if (fx_proc(tree) == fx_subtract_si) return(with_fx(tree, fx_subtract_ti));
59327 	  if (fx_proc(tree) == fx_subtract_sf) return(with_fx(tree, fx_subtract_tf));
59328 	  if (fx_proc(tree) == fx_multiply_sf) return(with_fx(tree, fx_multiply_tf));
59329 	  if (fx_proc(tree) == fx_lt_si) return(with_fx(tree, fx_lt_ti));
59330 	  if (fx_proc(tree) == fx_leq_si) return(with_fx(tree, fx_leq_ti));
59331 	  if (fx_proc(tree) == fx_gt_si) return(with_fx(tree, fx_gt_ti));
59332 	  if (fx_proc(tree) == fx_num_eq_si) return(with_fx(tree, fx_num_eq_ti));
59333 	}
59334       if (cadr(p) == var2)
59335 	{
59336 	  if (fx_proc(tree) == fx_c_sc) return(with_fx(tree, fx_c_uc));
59337 	  if (fx_proc(tree) == fx_num_eq_si) return(with_fx(tree, fx_num_eq_ui));
59338 	  if (fx_proc(tree) == fx_add_s1) return(with_fx(tree, fx_add_u1));
59339 	  if (fx_proc(tree) == fx_subtract_s1) return(with_fx(tree, fx_subtract_u1));
59340 	}
59341       break;
59342 
59343     case HOP_SAFE_C_CS:
59344       if (caddr(p) == var1)
59345 	{
59346 	  if (fx_proc(tree) == fx_c_cs)
59347 	    {
59348 	      if (is_global_and_has_func(car(p), s7_p_pp_function))
59349 		{
59350 		  if (fn_proc(p) == g_tree_set_memq_1)
59351 		    set_opt3_direct(cdr(p), (s7_pointer)tree_set_memq_direct);
59352 		  else
59353 		    {
59354 		      if (car(p) == sc->cons_symbol)
59355 			return(with_fx(tree, fx_c_ct_cons));
59356 		      set_opt3_direct(cdr(p), (s7_pointer)(s7_p_pp_function(global_value(car(p)))));
59357 		    }
59358 		  set_fx_direct(tree, fx_c_ct_direct);
59359 		}
59360 	      else set_fx_direct(tree, fx_c_ct);
59361 	      return(true);
59362 	    }}
59363       if ((caddr(p) == var2) && (fx_proc(tree) == fx_c_cs)) return(with_fx(tree, fx_c_cu));
59364       break;
59365 
59366     case HOP_SAFE_C_SS:
59367       if (cadr(p) == var1)
59368 	{
59369 	  if (fx_proc(tree) == fx_c_ss) return(with_fx(tree, (caddr(p) == var2) ? fx_c_tu : fx_c_ts));
59370 	  if (fx_proc(tree) == fx_c_ss_direct) return(with_fx(tree, fx_c_ts_direct));
59371 	  if (fx_proc(tree) == fx_is_eq_ss) return(with_fx(tree, (caddr(p) == var2) ? fx_is_eq_tu : fx_is_eq_ts));
59372 	  if (fx_proc(tree) == fx_add_ss) return(with_fx(tree, (caddr(p) == var2) ? fx_add_tu : fx_add_ts));
59373 	  if (fx_proc(tree) == fx_subtract_ss) return(with_fx(tree, (caddr(p) == var2) ? fx_subtract_tu : fx_subtract_ts));
59374 	  if (fx_proc(tree) == fx_cons_ss) return(with_fx(tree, fx_cons_ts));
59375 	  if (caddr(p) == var2)
59376 	    {
59377 	      if (fx_proc(tree) == fx_gt_ss) return(with_fx(tree, fx_gt_tu));
59378 	      if (fx_proc(tree) == fx_lt_ss) return(with_fx(tree, fx_lt_tu));
59379 	      if (fx_proc(tree) == fx_leq_ss) return(with_fx(tree, fx_leq_tu));
59380 	      if (fx_proc(tree) == fx_geq_ss) return(with_fx(tree, fx_geq_tu));
59381 	      if (fx_proc(tree) == fx_multiply_ss) return(with_fx(tree, fx_multiply_tu));
59382 	      if (fx_proc(tree) == fx_num_eq_ss) return(with_fx(tree, fx_num_eq_tu));
59383 	    }
59384 	  if (fx_proc(tree) == fx_multiply_ss) return(with_fx(tree, fx_multiply_ts));
59385 	  if (fx_proc(tree) == fx_num_eq_ss) return(with_fx(tree, (is_global(caddr(p))) ? fx_num_eq_tg : fx_num_eq_ts));
59386 	  if (fx_proc(tree) == fx_geq_ss) return(with_fx(tree, fx_geq_ts));
59387 	  if (fx_proc(tree) == fx_leq_ss) return(with_fx(tree, fx_leq_ts));
59388 	  if (fx_proc(tree) == fx_lt_ss) return(with_fx(tree, fx_lt_ts));
59389 	  if (fx_proc(tree) == fx_lt_sg) return(with_fx(tree, fx_lt_tg));
59390 	  if (fx_proc(tree) == fx_gt_ss) return(with_fx(tree, (is_global(caddr(p))) ? fx_gt_tg : fx_gt_ts));
59391 	  if (fx_proc(tree) == fx_sqr_s) return(with_fx(tree, fx_sqr_t));
59392 	}
59393       if (caddr(p) == var1)
59394 	{
59395 	  if (fx_proc(tree) == fx_c_ss) return(with_fx(tree, fx_c_st));
59396 	  if (fx_proc(tree) == fx_c_ss_direct) {return(with_fx(tree, (is_global(cadr(p))) ? fx_c_gt_direct : fx_c_st_direct));}
59397 	  if (fx_proc(tree) == fx_hash_table_ref_ss) return(with_fx(tree, fx_hash_table_ref_st));
59398 	  if (fx_proc(tree) == fx_vref_ss) return(with_fx(tree, (is_global(cadr(p))) ? fx_vref_gt : fx_vref_st));
59399 	  if ((fx_proc(tree) == fx_gt_ss) && (cadr(p) == var2)) return(with_fx(tree, fx_gt_ut));
59400 	  if ((fx_proc(tree) == fx_lt_ss) && (cadr(p) == var2)) return(with_fx(tree, fx_lt_ut));
59401 	}
59402       if (cadr(p) == var2)
59403 	{
59404 	  if (fx_proc(tree) == fx_num_eq_ss) return(with_fx(tree, fx_num_eq_us));
59405 	  if (fx_proc(tree) == fx_geq_ss) return(with_fx(tree, fx_geq_us));
59406 	  if (fx_proc(tree) == fx_add_ss) return(with_fx(tree, (caddr(p) == var1) ? fx_add_ut : fx_add_us));
59407 	  if (fx_proc(tree) == fx_subtract_ss) return(with_fx(tree, (caddr(p) == var1) ? fx_subtract_ut : fx_subtract_us));
59408 	}
59409       break;
59410 
59411     case HOP_SAFE_C_AS:
59412       if (caddr(p) == var1) return(with_fx(tree, fx_c_at));
59413       break;
59414 
59415     case HOP_SAFE_C_SA:
59416       if (cadr(p) == var1)
59417 	{
59418 	  if ((fx_proc(cddr(p)) == fx_c_opsq_c) &&
59419 	      (cadadr(caddr(p)) == var1) &&
59420 	      (is_t_integer(caddaddr(p))) &&
59421 	      (integer(caddaddr(p)) == 1) &&
59422 	      (car(p) == sc->string_ref_symbol) &&
59423 	      (caaddr(p) == sc->subtract_symbol) &&
59424 #if (!WITH_PURE_S7)
59425 	      ((caadr(caddr(p)) == sc->string_length_symbol) || (caadr(caddr(p)) == sc->length_symbol)))
59426 #else
59427 	      (caadr(caddr(p)) == sc->length_symbol))
59428 #endif
59429 	    return(with_fx(tree, fx_string_ref_t_last));
59430 	  return(with_fx(tree, fx_c_ta));
59431 	}
59432       break;
59433 
59434     case HOP_SAFE_C_SCS:
59435       if (cadr(p) == var1)
59436 	{
59437 	  if (fx_proc(tree) == fx_c_scs) return(with_fx(tree, fx_c_tcs));
59438 	  if (fx_proc(tree) == fx_c_scs_direct) return(with_fx(tree, (cadddr(p) == var2) ? fx_c_tcu_direct : fx_c_tcs_direct));
59439 	}
59440       break;
59441 
59442     case HOP_SAFE_C_SSC:
59443       if ((cadr(p) == var1) && (caddr(p) == var2)) return(with_fx(tree, fx_c_tuc));
59444       break;
59445 
59446     case HOP_SAFE_C_SSS:
59447       if ((cadr(p) == var1) &&
59448 	  ((caddr(p) == var2) && ((fx_proc(tree) == fx_c_sss) || (fx_proc(tree) == fx_c_sss_direct))))
59449 	return(with_fx(tree, fx_c_tus));
59450       if (caddr(p) == var1) return(with_fx(tree, (car(p) == sc->vector_set_symbol) ? fx_vset_sts : fx_c_sts));
59451       break;
59452 
59453     case HOP_SAFE_C_opSq:
59454       if (cadadr(p) == var1)
59455 	{
59456 	  if (fx_proc(tree) == fx_is_pair_car_s) return(with_fx(tree, fx_is_pair_car_t));
59457 	  if (fx_proc(tree) == fx_is_pair_cdr_s) return(with_fx(tree, fx_is_pair_cdr_t));
59458 	  if (fx_proc(tree) == fx_is_pair_cadr_s) return(with_fx(tree, fx_is_pair_cadr_t));
59459 	  if (fx_proc(tree) == fx_is_symbol_cadr_s) return(with_fx(tree, fx_is_symbol_cadr_t));
59460 	  if (fx_proc(tree) == fx_is_pair_cddr_s) return(with_fx(tree, fx_is_pair_cddr_t));
59461 	  if (fx_proc(tree) == fx_is_null_cdr_s) return(with_fx(tree, fx_is_null_cdr_t));
59462 	  if (fx_proc(tree) == fx_is_null_cddr_s) return(with_fx(tree, fx_is_null_cddr_t));
59463 	  if (fx_proc(tree) == fx_not_is_pair_s) return(with_fx(tree, fx_not_is_pair_t));
59464 	  if (fx_proc(tree) == fx_not_is_null_s) return(with_fx(tree, fx_not_is_null_t));
59465 	  if (fx_proc(tree) == fx_not_is_symbol_s) return(with_fx(tree, fx_not_is_symbol_t));
59466 	  if (fx_proc(tree) == fx_is_type_car_s)
59467 	    return(with_fx(tree, (car(p) == sc->is_symbol_symbol) ? fx_is_symbol_car_t : fx_is_type_car_t));
59468 	  if (fx_proc(tree) == fx_c_opsq)
59469 	    {
59470 	      set_opt1_sym(cdr(p), cadadr(p));
59471 	      if ((is_global_and_has_func(car(p), s7_p_p_function)) &&
59472 		  (is_global_and_has_func(caadr(p), s7_p_p_function)))
59473 		{
59474 		  set_opt2_direct(cdr(p), (s7_pointer)(s7_p_p_function(global_value(car(p)))));
59475 		  set_opt3_direct(cdr(p), (s7_pointer)(s7_p_p_function(global_value(caadr(p)))));
59476 		  return(with_fx(tree, fx_c_optq_direct));
59477 		}
59478 	      return(with_fx(tree, fx_c_optq));
59479 	    }
59480 	  if (fx_proc(tree) == fx_c_car_s) return(with_fx(tree, fx_c_car_t));
59481 	  if (fx_proc(tree) == fx_c_cdr_s) return(with_fx(tree, fx_c_cdr_t));
59482 	  if (fx_proc(tree) == fx_is_type_opsq) return(with_fx(tree, fx_is_type_optq));
59483 	}
59484       if (cadadr(p) == var2)
59485 	{
59486 	  if (fx_proc(tree) == fx_c_car_s) return(with_fx(tree, fx_c_car_u));
59487 	  if (fx_proc(tree) == fx_not_is_null_s) return(with_fx(tree, fx_not_is_null_u));
59488 	}
59489       break;
59490 
59491     case HOP_SAFE_C_opSq_S:
59492       if (cadadr(p) == var1)
59493 	{
59494 	  if (fx_proc(tree) == fx_c_opsq_s)
59495 	    {
59496 	      if ((is_global_and_has_func(car(p), s7_p_pp_function)) &&
59497 		  (is_global_and_has_func(caadr(p), s7_p_p_function)))
59498 		{
59499 		  set_opt1_sym(p, cadadr(p));
59500 		  set_opt2_direct(cdr(p), (s7_pointer)(s7_p_pp_function(global_value(car(p)))));
59501 		  set_opt3_direct(cdr(p), (s7_pointer)(s7_p_p_function(global_value(caadr(p)))));
59502 		  return(with_fx(tree, fx_c_optq_s_direct));
59503 		}
59504 	      return(with_fx(tree, fx_c_optq_s));
59505 	    }
59506 	  if (fx_proc(tree) == fx_c_opsq_s_direct) return(with_fx(tree, fx_c_optq_s_direct));
59507 	  if (fx_proc(tree) == fx_cons_car_s_s) {set_opt1_sym(cdr(p), var1); return(with_fx(tree, fx_cons_car_t_s));}
59508 	}
59509       if (cadadr(p) == var2)
59510 	{
59511 	  if ((fx_proc(tree) == fx_c_opsq_s) && (caddr(p) == var1))
59512 	    {
59513 	      if ((is_global_and_has_func(car(p), s7_p_pp_function)) &&
59514 		  (is_global_and_has_func(caadr(p), s7_p_p_function))) /* (memq (car sequence) items) lint */
59515 		{
59516 		  set_opt2_direct(cdr(p), (s7_pointer)(s7_p_pp_function(global_value(car(p)))));
59517 		  set_opt3_direct(cdr(p), (s7_pointer)(s7_p_p_function(global_value(caadr(p)))));
59518 		  set_opt1_sym(cdr(p), var2);
59519 		  return(with_fx(tree, (car(p) == sc->cons_symbol) ?
59520 				     ((caadr(p) == sc->car_symbol) ? fx_cons_car_u_t : fx_cons_opuq_t) : fx_c_opuq_t_direct));
59521 		}
59522 	      return(with_fx(tree, fx_c_opuq_t));
59523 	    }
59524 	  if (((fx_proc(tree) == fx_c_opsq_s_direct) || (fx_proc(tree) == fx_cons_car_s_s)) &&
59525 	      (caddr(p) == var1))
59526 	    {
59527 	      set_opt1_sym(cdr(p), var2);
59528 	      return(with_fx(tree, (car(p) == sc->cons_symbol) ?
59529 				 ((caadr(p) == sc->car_symbol) ? fx_cons_car_u_t : fx_cons_opuq_t) : fx_c_opuq_t_direct));
59530 	    }}
59531       break;
59532 
59533     case HOP_SAFE_C_S_opSq:
59534       if (cadr(p) == var1)
59535 	{
59536 	  if (cadaddr(p) == var2)
59537 	    {
59538 	      if (fx_proc(tree) == fx_c_s_car_s) return(with_fx(tree, fx_c_t_car_u));
59539 	      if (fx_proc(tree) == fx_c_s_opsq_direct) return(with_fx(tree, fx_c_t_opuq_direct));
59540 	    }}
59541       if ((cadr(p) == var2) && (fx_proc(tree) == fx_add_s_car_s) && (cadaddr(p) == var1)) return(with_fx(tree, fx_add_u_car_t));
59542       break;
59543 
59544     case HOP_SAFE_C_opSq_opSq:
59545       if (fx_proc(tree) == fx_c_opsq_opsq_direct)
59546 	{
59547 	  if ((cadadr(p) == var1) && (cadadr(p) == cadaddr(p)))
59548 	    {
59549 	      set_opt1_sym(cdr(p), cadadr(p));
59550 	      return(with_fx(tree, fx_c_optq_optq_direct));   /* opuq got few hits */
59551 	    }
59552 	  if ((caadr(p) == caaddr(p)) && (caadr(p) == sc->car_symbol))
59553 	    {
59554 	      set_opt1_sym(cdr(p), cadadr(p));
59555 	      set_opt2_sym(cdr(p), cadaddr(p));
59556 	      return(with_fx(tree, ((cadadr(p) == var1) && (cadaddr(p) == var2)) ? fx_car_car_tu : fx_car_car));
59557 	    }}
59558       break;
59559 
59560     case HOP_SAFE_C_opSq_C:
59561       if (cadadr(p) == var1)
59562 	{
59563 	  if (fx_proc(tree) == fx_is_eq_car_q) return(with_fx(tree, fx_is_eq_car_t_q));
59564 	  if ((fx_proc(tree) == fx_c_opsq_c) || (fx_proc(tree) == fx_c_optq_c))
59565 	    {
59566 	      if (fn_proc(p) != g_lint_let_ref) /* don't step on opt3_sym */
59567 		{
59568 		  if ((is_global_and_has_func(car(p), s7_p_pp_function)) &&
59569 		      (is_global_and_has_func(caadr(p), s7_p_p_function)))
59570 		    {
59571 		      if (fn_proc(p) == g_memq_2)
59572 			set_opt3_direct(p, (s7_pointer)memq_2_p_pp);
59573 		      else set_opt3_direct(p, (s7_pointer)(s7_p_pp_function(global_value(car(p)))));
59574 		      set_opt3_direct(cdr(p), (s7_pointer)(s7_p_p_function(global_value(caadr(p)))));
59575 		      set_fx_direct(tree, fx_c_optq_c_direct);
59576 		      return(true);
59577 		    }
59578 		  if ((is_t_integer(caddr(p))) &&
59579 		      (is_global_and_has_func(caadr(p), s7_i_7p_function)) &&
59580 		      (is_global_and_has_func(car(p), s7_p_ii_function)))
59581 		    {
59582 		      set_opt3_direct(p, (s7_pointer)(s7_p_ii_function(global_value(car(p)))));
59583 		      set_opt3_direct(cdr(p), (s7_pointer)(s7_i_7p_function(global_value(caadr(p)))));
59584 		      set_fx_direct(tree, fx_c_optq_i_direct);
59585 		    }
59586 		  else set_fx_direct(tree, fx_c_optq_c);
59587 		}
59588 	      return(true);
59589 	    }}
59590       break;
59591 
59592     case HOP_SAFE_C_opSSq:
59593       if (fx_proc(tree) == fx_c_opssq)
59594 	{
59595 	  if (caddadr(p) == var1) return(with_fx(tree, fx_c_opstq));
59596 	  if ((cadadr(p) == var1) && (caddadr(p) == var2))
59597 	    {
59598 	      set_opt3_sym(p, var1);
59599 	      set_opt1_sym(cdr(p), var2);
59600 	      return(with_fx(tree, fx_c_optuq));
59601 	    }}
59602       if (fx_proc(tree) == fx_c_opssq_direct)
59603 	{
59604 	  if ((cadadr(p) == var1) && (caddadr(p) == var2)) return(with_fx(tree, fx_c_optuq_direct));
59605 	  if (caddadr(p) == var1)
59606 	    {
59607 	      set_opt1_sym(cdr(p), var1);
59608 	      if ((opt2_direct(cdr(p)) == (s7_pointer)is_zero_p_p) && (opt3_direct(cdr(p)) == (s7_pointer)remainder_p_pp))
59609 		return(with_fx(tree, fx_is_zero_remainder_s));
59610 	      return(with_fx(tree, fx_c_opstq_direct));
59611 	    }}
59612       if ((cadadr(p) == var2) && (fx_proc(tree) == fx_not_opssq) && (caddadr(p) == var1))
59613 	{
59614 	  if (fn_proc(cadr(p)) == g_less_2)
59615 	    {
59616 	      set_opt3_sym(p, var2);
59617 	      set_opt1_sym(cdr(p), var1);
59618 	      set_fx_direct(tree, fx_not_lt_ut);
59619 	    }
59620 	  else set_fx_direct(tree, fx_not_oputq);
59621 	  return(true);
59622 	}
59623       break;
59624 
59625     case HOP_SAFE_C_opSCq:
59626       if (cadr(p) == var1)
59627 	return(with_fx(tree, fx_c_optcq)); /* there currently isn't any fx_c_opscq_direct */
59628       break;
59629 
59630     case HOP_SAFE_C_opSSq_C:
59631       if ((fx_proc(tree) == fx_c_opssq_c) && (caddadr(p) == var1))
59632 	{
59633 	  if (is_global_and_has_func(car(p), s7_p_pp_function))
59634 	    {
59635 	      set_opt3_direct(p, (s7_pointer)(s7_p_pp_function(global_value(car(p)))));
59636 	      return(with_fx(tree, fx_c_opstq_c_direct));
59637 	    }
59638 	  return(with_fx(tree, fx_c_opstq_c));
59639 	}
59640       break;
59641 
59642     case HOP_SAFE_C_S_opSCq:
59643       if ((cadr(p) == var1) && (fx_proc(tree) == fx_c_s_opscq_direct))
59644 	return(with_fx(tree, (cadaddr(p) == var2) ? fx_c_t_opucq_direct : fx_c_t_opscq_direct));
59645       break;
59646 
59647     case HOP_SAFE_C_opSq_CS:
59648       if ((cadadr(p) == var1) && (fx_proc(tree) == fx_c_opsq_cs) && (cadddr(p) == var2)) return(with_fx(tree, fx_c_optq_cu));
59649       break;
59650 
59651     case HOP_SAFE_C_opSq_opSSq:
59652       if ((fx_proc(tree) == fx_c_opsq_opssq) && (cadaddr(p) == var1) && (caddaddr(p) == var2))
59653 	{
59654 	  if ((is_global_and_has_func(car(p), s7_p_pp_function)) &&
59655 	      (is_global_and_has_func(caadr(p), s7_p_p_function)) &&
59656 	      (is_global_and_has_func(caaddr(p), s7_p_pp_function)))
59657 	    {
59658 	      set_opt3_direct(p, (s7_pointer)(s7_p_pp_function(global_value(car(p)))));
59659 	      set_opt2_direct(cdr(p), (s7_pointer)(s7_p_p_function(global_value(caadr(p)))));
59660 	      set_opt3_direct(cdr(p), (s7_pointer)(s7_p_pp_function(global_value(caaddr(p)))));
59661 	      set_opt1_sym(cdr(p), var2); /* caddaddr(p) */
59662 	      if ((car(p) == sc->num_eq_symbol) && (caadr(p) == sc->car_symbol))
59663 		{
59664 		  if (caaddr(p) == sc->add_symbol) {set_opt2_sym(cddr(p), var1); return(with_fx(tree, fx_num_eq_car_s_add_tu));}
59665 		  if (caaddr(p) == sc->subtract_symbol) {set_opt2_sym(cddr(p), var1); return(with_fx(tree, fx_num_eq_car_s_subtract_tu));}
59666 		}
59667 	      return(with_fx(tree, fx_c_opsq_optuq_direct));
59668 	    }}
59669       break;
59670 
59671     case HOP_SAFE_C_opSSq_S:
59672       if (fx_proc(tree) == fx_vref_vref_ss_s)
59673 	{
59674 	  if ((caddr(p) == var1) && (is_global(cadadr(p)))) return(with_fx(tree, fx_vref_vref_gs_t));
59675 	  if ((cadadr(p) == var1) && (caddadr(p) == var2)) return(with_fx(tree, fx_vref_vref_tu_s));
59676 	}
59677       break;
59678 
59679     case HOP_SAFE_C_S_opSSq:
59680       if (caddr(caddr(p)) == var1)
59681 	{
59682 	  if ((fn_proc(p) == g_vector_ref_2) && (is_global(cadr(p)) && (is_global(cadr(caddr(p))))))
59683 	    {
59684 	      set_opt3_pair(p, cdaddr(p));
59685 	      return(with_fx(tree, fx_vref_g_vref_gt));
59686 	    }
59687 	  if (fx_proc(tree) == fx_c_s_opssq_direct)
59688 	    return(with_fx(tree, fx_c_s_opstq_direct));
59689 	}
59690       break;
59691 
59692     case HOP_SAFE_C_op_opSq_Sq:
59693       if ((car(p) == sc->not_symbol) && (is_global(sc->not_symbol)) && (var1 == cadr(cadadr(p))))
59694 	return(with_fx(tree, fx_not_op_optq_sq));
59695       break;
59696 
59697     case HOP_SAFE_C_AC:
59698       if ((fx_proc(tree) == fx_c_ac) && (fn_proc(p) == g_num_eq_xi) && (caddr(p) == int_zero) &&
59699 	  (fx_proc(cdr(p)) == fx_c_opuq_t_direct) && (caadr(p) == sc->remainder_symbol) && (fn_proc(cadadr(p)) == g_car))
59700 	{
59701 	  set_opt3_sym(p, cadr(cadr(cadr(p))));
59702 	  set_opt1_sym(cdr(p), caddr(cadr(p)));
59703 	  return(with_fx(tree, fx_is_zero_remainder_car));
59704 	}
59705       break;
59706 
59707     case HOP_SAFE_CLOSURE_S_A:
59708       if (cadr(p) == var1)
59709 	{
59710 	  if (fx_proc(tree) == fx_safe_closure_s_a) return(with_fx(tree, fx_safe_closure_t_a));
59711 	  if (fx_proc(tree) == fx_lint_let_ref) return(with_fx(tree, fx_lint_let_ref_t));
59712 	}
59713       break;
59714 
59715     case OP_AND_3:
59716       if ((fx_proc(tree) == fx_and_3) &&
59717 	  (is_pair(cadr(p))) &&
59718 	  (is_pair(cdadr(p))) && (cadadr(p) == var1))
59719 	{
59720 	  if (((fx_proc(cdr(p)) == fx_is_pair_t) && (fx_proc(cddr(p)) == fx_is_pair_cdr_t)) ||
59721 	      ((fx_proc(cdr(p)) == fx_is_pair_s) && (fx_proc(cddr(p)) == fx_is_pair_cdr_s)))
59722 	    {
59723 	      if ((fx_proc(cdddr(p)) == fx_is_null_cddr_t) || (fx_proc(cdddr(p)) == fx_is_null_cddr_s))
59724 		return(with_fx(tree, fx_len2));
59725 	      if ((fx_proc(cdddr(p)) == fx_is_pair_cddr_t) || (fx_proc(cdddr(p)) == fx_is_pair_cddr_s))
59726 		return(with_fx(tree, fx_len3));
59727 	    }}
59728       break;
59729      }
59730   return(false);
59731 }
59732 
59733 #if SHOW_FX_TREE
59734 #define fx_tree(Sc, Tree, Var1, Var2) fx_tree_1(Sc, Tree, Var1, Var2, __func__, __LINE__)
59735 static void fx_tree_1(s7_scheme *sc, s7_pointer tree, s7_pointer var1, s7_pointer var2, const char *func, int line)
59736 #else
59737 static void fx_tree(s7_scheme *sc, s7_pointer tree, s7_pointer var1, s7_pointer var2) /* const char *func, int line) */
59738 #endif
59739 {
59740 #if SHOW_FX_TREE
59741   if (is_pair(tree))
59742     fprintf(stderr, "%s[%d] fx_tree %s, has_fx: %d, vars: %s %s\n", func, line, display_80(tree), has_fx(tree), display(var1), (var2) ? display(var2) : "");
59743 #endif
59744 
59745   if (!is_pair(tree)) return;
59746   if ((is_symbol(car(tree))) &&
59747       (is_definer_or_binder(car(tree))))
59748     {
59749       if ((car(tree) == sc->let_symbol) && (is_pair(cdr(tree))) && (is_pair(cadr(tree))) && (is_null(cdadr(tree))))
59750 	fx_tree(sc, cddr(tree), caaadr(tree), NULL);
59751       return;
59752     }
59753   if (is_syntax(car(tree))) return; /* someday let #_when/#_if etc through -- the symbol 'if, for example, is not syntax */
59754 
59755   if ((!has_fx(tree)) ||
59756       (!fx_tree_in(sc, tree, var1, var2)))
59757     fx_tree(sc, car(tree), var1, var2);
59758   fx_tree(sc, cdr(tree), var1, var2);
59759 }
59760 
59761 static void fx_tree_outer(s7_scheme *sc, s7_pointer tree, s7_pointer var1, s7_pointer var2)
59762 {
59763   /* if (is_pair(tree)) fprintf(stderr, "%s[%d]: %s %d %s %s\n", __func__, __LINE__, display_80(tree), has_fx(tree), display(var1), (var2) ? display(var2) : ""); */
59764 
59765   if ((!is_pair(tree)) ||
59766       ((is_symbol(car(tree))) && (is_definer_or_binder(car(tree)))) ||
59767       (is_syntax(car(tree))))
59768     return;
59769 
59770   if ((!has_fx(tree)) ||
59771       (!fx_tree_out(sc, tree, var1, var2)))
59772     fx_tree_outer(sc, car(tree), var1, var2);
59773   fx_tree_outer(sc, cdr(tree), var1, var2);
59774 }
59775 
59776 
59777 /* -------------------------------------------------------------------------------- */
59778 
59779 static opt_funcs_t *alloc_permanent_opt_func(s7_scheme *sc)
59780 {
59781   if (sc->alloc_opt_func_k == ALLOC_FUNCTION_SIZE)
59782     {
59783       sc->alloc_opt_func_cells = (opt_funcs_t *)malloc(ALLOC_FUNCTION_SIZE * sizeof(opt_funcs_t));
59784       add_saved_pointer(sc, sc->alloc_opt_func_cells);
59785       sc->alloc_opt_func_k = 0;
59786     }
59787   return(&(sc->alloc_opt_func_cells[sc->alloc_opt_func_k++]));
59788 }
59789 
59790 static void add_opt_func(s7_scheme *sc, s7_pointer f, opt_func_t typ, void *func)
59791 {
59792   opt_funcs_t *op;
59793 #if S7_DEBUGGING
59794   static const char *o_names[] = {"o_d_v", "o_d_vd", "o_d_vdd", "o_d_vid", "o_d_id", "o_d_7pi", "o_d_7pii", "o_d_7piid",
59795 				"o_d_ip", "o_d_pd", "o_d_7pid",	"o_d", "o_d_d", "o_d_dd", "o_d_7dd", "o_d_ddd", "o_d_dddd",
59796 				"o_i_i", "o_i_7i", "o_i_ii", "o_i_7ii", "o_i_iii", "o_i_7pi", "o_i_7pii", "o_i_7_piii", "o_d_p",
59797 				"o_b_p", "o_b_7p", "o_b_pp", "o_b_7pp", "o_b_pp_unchecked", "o_b_pi", "o_b_ii", "o_b_7ii", "o_b_dd",
59798 				"o_p", "o_p_p", "o_p_ii", "o_p_d", "o_p_dd", "o_i_7d", "o_i_7p", "o_d_7d", "o_p_pp", "o_p_ppp", "o_p_pi", "o_p_pi_unchecked",
59799 				"o_p_ppi", "o_p_i", "o_p_pii", "o_p_pip", "o_p_pip_unchecked", "o_p_piip", "o_b_i", "o_b_d"};
59800   if (!is_c_function(f))
59801     {
59802       fprintf(stderr, "%s[%d]: %s is not a c_function\n", __func__, __LINE__, s7_object_to_c_string(sc, f));
59803       if (sc->stop_at_error) abort();
59804     }
59805   else
59806     if (c_function_opt_data(f))
59807       {
59808 	opt_funcs_t *p;
59809 	for (p = c_function_opt_data(f); p; p = p->next)
59810 	  {
59811 	    if (p->typ == typ)
59812 	      fprintf(stderr, "%s[%d]: %s has a function of type %d (%s)\n",
59813 		      __func__, __LINE__, s7_object_to_c_string(sc, f), typ, o_names[typ]);
59814 	    if (p->func == func)
59815 	      fprintf(stderr, "%s[%d]: %s already has this function as type %d %s (current: %d %s)\n",
59816 		      __func__, __LINE__, s7_object_to_c_string(sc, f), p->typ, o_names[p->typ], typ, o_names[typ]);
59817 	  }}
59818 #endif
59819   op = alloc_permanent_opt_func(sc);
59820   op->typ = typ;
59821   op->func = func;
59822   op->next = c_function_opt_data(f);
59823   c_function_opt_data(f) = op;
59824 }
59825 
59826 static void *opt_func(s7_pointer f, opt_func_t typ)
59827 {
59828   if (is_c_function(f))
59829     {
59830       opt_funcs_t *p;
59831       for (p = c_function_opt_data(f); p; p = p->next)
59832 	if (p->typ == typ)
59833 	  return(p->func);
59834     }
59835   return(NULL);
59836 }
59837 
59838 /* clm2xen.c */
59839 void s7_set_d_function(s7_scheme *sc, s7_pointer f, s7_d_t df) {add_opt_func(sc, f, o_d, (void *)df);}
59840 s7_d_t s7_d_function(s7_pointer f) {return((s7_d_t)opt_func(f, o_d));}
59841 
59842 void s7_set_d_d_function(s7_scheme *sc, s7_pointer f, s7_d_d_t df) {add_opt_func(sc, f, o_d_d, (void *)df);}
59843 s7_d_d_t s7_d_d_function(s7_pointer f) {return((s7_d_d_t)opt_func(f, o_d_d));}
59844 
59845 void s7_set_d_dd_function(s7_scheme *sc, s7_pointer f, s7_d_dd_t df) {add_opt_func(sc, f, o_d_dd, (void *)df);}
59846 s7_d_dd_t s7_d_dd_function(s7_pointer f) {return((s7_d_dd_t)opt_func(f, o_d_dd));}
59847 
59848 void s7_set_d_v_function(s7_scheme *sc, s7_pointer f, s7_d_v_t df) {add_opt_func(sc, f, o_d_v, (void *)df);}
59849 s7_d_v_t s7_d_v_function(s7_pointer f) {return((s7_d_v_t)opt_func(f, o_d_v));}
59850 
59851 void s7_set_d_vd_function(s7_scheme *sc, s7_pointer f, s7_d_vd_t df) {add_opt_func(sc, f, o_d_vd, (void *)df);}
59852 s7_d_vd_t s7_d_vd_function(s7_pointer f) {return((s7_d_vd_t)opt_func(f, o_d_vd));}
59853 
59854 void s7_set_d_vdd_function(s7_scheme *sc, s7_pointer f, s7_d_vdd_t df) {add_opt_func(sc, f, o_d_vdd, (void *)df);}
59855 s7_d_vdd_t s7_d_vdd_function(s7_pointer f) {return((s7_d_vdd_t)opt_func(f, o_d_vdd));}
59856 
59857 void s7_set_d_vid_function(s7_scheme *sc, s7_pointer f, s7_d_vid_t df) {add_opt_func(sc, f, o_d_vid, (void *)df);}
59858 s7_d_vid_t s7_d_vid_function(s7_pointer f) {return((s7_d_vid_t)opt_func(f, o_d_vid));}
59859 
59860 void s7_set_d_id_function(s7_scheme *sc, s7_pointer f, s7_d_id_t df) {add_opt_func(sc, f, o_d_id, (void *)df);}
59861 s7_d_id_t s7_d_id_function(s7_pointer f) {return((s7_d_id_t)opt_func(f, o_d_id));}
59862 
59863 void s7_set_d_7pid_function(s7_scheme *sc, s7_pointer f, s7_d_7pid_t df) {add_opt_func(sc, f, o_d_7pid, (void *)df);}
59864 s7_d_7pid_t s7_d_7pid_function(s7_pointer f) {return((s7_d_7pid_t)opt_func(f, o_d_7pid));}
59865 
59866 void s7_set_d_ip_function(s7_scheme *sc, s7_pointer f, s7_d_ip_t df) {add_opt_func(sc, f, o_d_ip, (void *)df);}
59867 s7_d_ip_t s7_d_ip_function(s7_pointer f) {return((s7_d_ip_t)opt_func(f, o_d_ip));}
59868 
59869 void s7_set_d_pd_function(s7_scheme *sc, s7_pointer f, s7_d_pd_t df) {add_opt_func(sc, f, o_d_pd, (void *)df);}
59870 s7_d_pd_t s7_d_pd_function(s7_pointer f) {return((s7_d_pd_t)opt_func(f, o_d_pd));}
59871 
59872 void s7_set_d_p_function(s7_scheme *sc, s7_pointer f, s7_d_p_t df) {add_opt_func(sc, f, o_d_p, (void *)df);}
59873 s7_d_p_t s7_d_p_function(s7_pointer f) {return((s7_d_p_t)opt_func(f, o_d_p));}
59874 
59875 void s7_set_b_p_function(s7_scheme *sc, s7_pointer f, s7_b_p_t df) {add_opt_func(sc, f, o_b_p, (void *)df);}
59876 s7_b_p_t s7_b_p_function(s7_pointer f) {return((s7_b_p_t)opt_func(f, o_b_p));}
59877 
59878 void s7_set_d_7pi_function(s7_scheme *sc, s7_pointer f, s7_d_7pi_t df) {add_opt_func(sc, f, o_d_7pi, (void *)df);}
59879 s7_d_7pi_t s7_d_7pi_function(s7_pointer f) {return((s7_d_7pi_t)opt_func(f, o_d_7pi));}
59880 
59881 static void s7_set_d_7pii_function(s7_scheme *sc, s7_pointer f, s7_d_7pii_t df) {add_opt_func(sc, f, o_d_7pii, (void *)df);}
59882 static s7_d_7pii_t s7_d_7pii_function(s7_pointer f) {return((s7_d_7pii_t)opt_func(f, o_d_7pii));}
59883 
59884 void s7_set_i_7p_function(s7_scheme *sc, s7_pointer f, s7_i_7p_t df) {add_opt_func(sc, f, o_i_7p, (void *)df);}
59885 s7_i_7p_t s7_i_7p_function(s7_pointer f) {return((s7_i_7p_t)opt_func(f, o_i_7p));}
59886 
59887 /* cload.scm */
59888 void s7_set_d_ddd_function(s7_scheme *sc, s7_pointer f, s7_d_ddd_t df) {add_opt_func(sc, f, o_d_ddd, (void *)df);}
59889 s7_d_ddd_t s7_d_ddd_function(s7_pointer f) {return((s7_d_ddd_t)opt_func(f, o_d_ddd));}
59890 
59891 void s7_set_d_dddd_function(s7_scheme *sc, s7_pointer f, s7_d_dddd_t df) {add_opt_func(sc, f, o_d_dddd, (void *)df);}
59892 s7_d_dddd_t s7_d_dddd_function(s7_pointer f) {return((s7_d_dddd_t)opt_func(f, o_d_dddd));}
59893 
59894 void s7_set_i_i_function(s7_scheme *sc, s7_pointer f, s7_i_i_t df) {add_opt_func(sc, f, o_i_i, (void *)df);}
59895 s7_i_i_t s7_i_i_function(s7_pointer f) {return((s7_i_i_t)opt_func(f, o_i_i));}
59896 
59897 void s7_set_i_ii_function(s7_scheme *sc, s7_pointer f, s7_i_ii_t df) {add_opt_func(sc, f, o_i_ii, (void *)df);}
59898 s7_i_ii_t s7_i_ii_function(s7_pointer f) {return((s7_i_ii_t)opt_func(f, o_i_ii));}
59899 
59900 void s7_set_i_7d_function(s7_scheme *sc, s7_pointer f, s7_i_7d_t df) {add_opt_func(sc, f, o_i_7d, (void *)df);}
59901 s7_i_7d_t s7_i_7d_function(s7_pointer f) {return((s7_i_7d_t)opt_func(f, o_i_7d));}
59902 
59903 /* s7test.scm */
59904 void s7_set_p_d_function(s7_scheme *sc, s7_pointer f, s7_p_d_t df) {add_opt_func(sc, f, o_p_d, (void *)df);}
59905 s7_p_d_t s7_p_d_function(s7_pointer f) {return((s7_p_d_t)opt_func(f, o_p_d));}
59906 
59907 static void s7_set_d_7dd_function(s7_scheme *sc, s7_pointer f, s7_d_7dd_t df) {add_opt_func(sc, f, o_d_7dd, (void *)df);}
59908 static s7_d_7dd_t s7_d_7dd_function(s7_pointer f) {return((s7_d_7dd_t)opt_func(f, o_d_7dd));}
59909 
59910 static void s7_set_i_7i_function(s7_scheme *sc, s7_pointer f, s7_i_7i_t df) {add_opt_func(sc, f, o_i_7i, (void *)df);}
59911 static s7_i_7i_t s7_i_7i_function(s7_pointer f) {return((s7_i_7i_t)opt_func(f, o_i_7i));}
59912 
59913 static void s7_set_i_7ii_function(s7_scheme *sc, s7_pointer f, s7_i_7ii_t df) {add_opt_func(sc, f, o_i_7ii, (void *)df);}
59914 static s7_i_7ii_t s7_i_7ii_function(s7_pointer f) {return((s7_i_7ii_t)opt_func(f, o_i_7ii));}
59915 
59916 static void s7_set_i_iii_function(s7_scheme *sc, s7_pointer f, s7_i_iii_t df) {add_opt_func(sc, f, o_i_iii, (void *)df);}
59917 s7_i_iii_t s7_i_iii_function(s7_pointer f) {return((s7_i_iii_t)opt_func(f, o_i_iii));}
59918 
59919 static void s7_set_p_pi_function(s7_scheme *sc, s7_pointer f, s7_p_pi_t df) {add_opt_func(sc, f, o_p_pi, (void *)df);}
59920 static s7_p_pi_t s7_p_pi_function(s7_pointer f) {return((s7_p_pi_t)opt_func(f, o_p_pi));}
59921 
59922 static void s7_set_p_ppi_function(s7_scheme *sc, s7_pointer f, s7_p_ppi_t df) {add_opt_func(sc, f, o_p_ppi, (void *)df);}
59923 static s7_p_ppi_t s7_p_ppi_function(s7_pointer f) {return((s7_p_ppi_t)opt_func(f, o_p_ppi));}
59924 
59925 static void s7_set_i_7pi_function(s7_scheme *sc, s7_pointer f, s7_i_7pi_t df) {add_opt_func(sc, f, o_i_7pi, (void *)df);}
59926 static s7_i_7pi_t s7_i_7pi_function(s7_pointer f) {return((s7_i_7pi_t)opt_func(f, o_i_7pi));}
59927 
59928 static void s7_set_i_7pii_function(s7_scheme *sc, s7_pointer f, s7_i_7pii_t df) {add_opt_func(sc, f, o_i_7pii, (void *)df);}
59929 static s7_i_7pii_t s7_i_7pii_function(s7_pointer f) {return((s7_i_7pii_t)opt_func(f, o_i_7pii));}
59930 
59931 static void s7_set_i_7piii_function(s7_scheme *sc, s7_pointer f, s7_i_7piii_t df) {add_opt_func(sc, f, o_i_7piii, (void *)df);}
59932 static s7_i_7piii_t s7_i_7piii_function(s7_pointer f) {return((s7_i_7piii_t)opt_func(f, o_i_7piii));}
59933 
59934 static void s7_set_b_d_function(s7_scheme *sc, s7_pointer f, s7_b_d_t df) {add_opt_func(sc, f, o_b_d, (void *)df);}
59935 static s7_b_d_t s7_b_d_function(s7_pointer f) {return((s7_b_d_t)opt_func(f, o_b_d));}
59936 
59937 static void s7_set_b_i_function(s7_scheme *sc, s7_pointer f, s7_b_i_t df) {add_opt_func(sc, f, o_b_i, (void *)df);}
59938 static s7_b_i_t s7_b_i_function(s7_pointer f) {return((s7_b_i_t)opt_func(f, o_b_i));}
59939 
59940 static void s7_set_b_7p_function(s7_scheme *sc, s7_pointer f, s7_b_7p_t df) {add_opt_func(sc, f, o_b_7p, (void *)df);}
59941 static s7_b_7p_t s7_b_7p_function(s7_pointer f) {return((s7_b_7p_t)opt_func(f, o_b_7p));}
59942 
59943 static void s7_set_b_pp_function(s7_scheme *sc, s7_pointer f, s7_b_pp_t df) {add_opt_func(sc, f, o_b_pp, (void *)df);}
59944 static s7_b_pp_t s7_b_pp_function(s7_pointer f) {return((s7_b_pp_t)opt_func(f, o_b_pp));}
59945 
59946 static void s7_set_b_7pp_function(s7_scheme *sc, s7_pointer f, s7_b_7pp_t df) {add_opt_func(sc, f, o_b_7pp, (void *)df);}
59947 static s7_b_7pp_t s7_b_7pp_function(s7_pointer f) {return((s7_b_7pp_t)opt_func(f, o_b_7pp));}
59948 
59949 static void s7_set_d_7d_function(s7_scheme *sc, s7_pointer f, s7_d_7d_t df) {add_opt_func(sc, f, o_d_7d, (void *)df);}
59950 static s7_d_7d_t s7_d_7d_function(s7_pointer f) {return((s7_d_7d_t)opt_func(f, o_d_7d));}
59951 
59952 static void s7_set_b_pi_function(s7_scheme *sc, s7_pointer f, s7_b_pi_t df) {add_opt_func(sc, f, o_b_pi, (void *)df);}
59953 static s7_b_pi_t s7_b_pi_function(s7_pointer f) {return((s7_b_pi_t)opt_func(f, o_b_pi));}
59954 
59955 static void s7_set_b_ii_function(s7_scheme *sc, s7_pointer f, s7_b_ii_t df) {add_opt_func(sc, f, o_b_ii, (void *)df);}
59956 static s7_b_ii_t s7_b_ii_function(s7_pointer f) {return((s7_b_ii_t)opt_func(f, o_b_ii));}
59957 
59958 static void s7_set_b_7ii_function(s7_scheme *sc, s7_pointer f, s7_b_7ii_t df) {add_opt_func(sc, f, o_b_7ii, (void *)df);}
59959 static s7_b_7ii_t s7_b_7ii_function(s7_pointer f) {return((s7_b_7ii_t)opt_func(f, o_b_7ii));}
59960 
59961 static void s7_set_b_dd_function(s7_scheme *sc, s7_pointer f, s7_b_dd_t df) {add_opt_func(sc, f, o_b_dd, (void *)df);}
59962 static s7_b_dd_t s7_b_dd_function(s7_pointer f) {return((s7_b_dd_t)opt_func(f, o_b_dd));}
59963 
59964 static void s7_set_p_p_function(s7_scheme *sc, s7_pointer f, s7_p_p_t df) {add_opt_func(sc, f, o_p_p, (void *)df);}
59965 static s7_p_p_t s7_p_p_function(s7_pointer f) {return((s7_p_p_t)opt_func(f, o_p_p));}
59966 
59967 static void s7_set_p_function(s7_scheme *sc, s7_pointer f, s7_p_t df) {add_opt_func(sc, f, o_p, (void *)df);}
59968 static s7_p_t s7_p_function(s7_pointer f) {return((s7_p_t)opt_func(f, o_p));}
59969 
59970 static void s7_set_p_pp_function(s7_scheme *sc, s7_pointer f, s7_p_pp_t df) {add_opt_func(sc, f, o_p_pp, (void *)df);}
59971 static s7_p_pp_t s7_p_pp_function(s7_pointer f) {return((s7_p_pp_t)opt_func(f, o_p_pp));}
59972 
59973 static void s7_set_p_ppp_function(s7_scheme *sc, s7_pointer f, s7_p_ppp_t df) {add_opt_func(sc, f, o_p_ppp, (void *)df);}
59974 static s7_p_ppp_t s7_p_ppp_function(s7_pointer f) {return((s7_p_ppp_t)opt_func(f, o_p_ppp));}
59975 
59976 static void s7_set_p_pip_function(s7_scheme *sc, s7_pointer f, s7_p_pip_t df) {add_opt_func(sc, f, o_p_pip, (void *)df);}
59977 static s7_p_pip_t s7_p_pip_function(s7_pointer f) {return((s7_p_pip_t)opt_func(f, o_p_pip));}
59978 
59979 static void s7_set_p_pii_function(s7_scheme *sc, s7_pointer f, s7_p_pii_t df) {add_opt_func(sc, f, o_p_pii, (void *)df);}
59980 static s7_p_pii_t s7_p_pii_function(s7_pointer f) {return((s7_p_pii_t)opt_func(f, o_p_pii));}
59981 
59982 static void s7_set_p_piip_function(s7_scheme *sc, s7_pointer f, s7_p_piip_t df) {add_opt_func(sc, f, o_p_piip, (void *)df);}
59983 static s7_p_piip_t s7_p_piip_function(s7_pointer f) {return((s7_p_piip_t)opt_func(f, o_p_piip));}
59984 
59985 static void s7_set_p_pi_unchecked_function(s7_scheme *sc, s7_pointer f, s7_p_pi_t df) {add_opt_func(sc, f, o_p_pi_unchecked, (void *)df);}
59986 static s7_p_pi_t s7_p_pi_unchecked_function(s7_pointer f) {return((s7_p_pi_t)opt_func(f, o_p_pi_unchecked));}
59987 
59988 static void s7_set_p_pip_unchecked_function(s7_scheme *sc, s7_pointer f, s7_p_pip_t df) {add_opt_func(sc, f, o_p_pip_unchecked, (void *)df);}
59989 static s7_p_pip_t s7_p_pip_unchecked_function(s7_pointer f) {return((s7_p_pip_t)opt_func(f, o_p_pip_unchecked));}
59990 
59991 static void s7_set_b_pp_unchecked_function(s7_scheme *sc, s7_pointer f, s7_b_pp_t df) {add_opt_func(sc, f, o_b_pp_unchecked, (void *)df);}
59992 static s7_b_pp_t s7_b_pp_unchecked_function(s7_pointer f) {return((s7_b_pp_t)opt_func(f, o_b_pp_unchecked));}
59993 
59994 static void s7_set_p_i_function(s7_scheme *sc, s7_pointer f, s7_p_i_t df) {add_opt_func(sc, f, o_p_i, (void *)df);}
59995 static s7_p_i_t s7_p_i_function(s7_pointer f) {return((s7_p_i_t)opt_func(f, o_p_i));}
59996 
59997 static void s7_set_p_ii_function(s7_scheme *sc, s7_pointer f, s7_p_ii_t df) {add_opt_func(sc, f, o_p_ii, (void *)df);}
59998 static s7_p_ii_t s7_p_ii_function(s7_pointer f) {return((s7_p_ii_t)opt_func(f, o_p_ii));}
59999 
60000 static void s7_set_d_7piid_function(s7_scheme *sc, s7_pointer f, s7_d_7piid_t df) {add_opt_func(sc, f, o_d_7piid, (void *)df);}
60001 static s7_d_7piid_t s7_d_7piid_function(s7_pointer f) {return((s7_d_7piid_t)opt_func(f, o_d_7piid));}
60002 
60003 static void s7_set_p_dd_function(s7_scheme *sc, s7_pointer f, s7_p_dd_t df) {add_opt_func(sc, f, o_p_dd, (void *)df);}
60004 static s7_p_dd_t s7_p_dd_function(s7_pointer f) {return((s7_p_dd_t)opt_func(f, o_p_dd));}
60005 
60006 #if S7_DEBUGGING || OPT_SC_DEBUGGING
60007 static opt_info *alloc_opo_1(s7_scheme *sc, const char *func, int line)
60008 #else
60009 static opt_info *alloc_opo(s7_scheme *sc)
60010 #endif
60011 {
60012   opt_info *o;
60013   if (sc->pc >= OPTS_SIZE)
60014     sc->pc = OPTS_SIZE - 1;
60015   o = sc->opts[sc->pc++];
60016   o->v[O_WRAP].fd = NULL; /* see bool_optimize -- this is a kludge */
60017 #if S7_DEBUGGING || OPT_SC_DEBUGGING
60018   o->opo_func = func;
60019   o->opo_line = line;
60020 #endif
60021   return(o);
60022 }
60023 
60024 #define backup_pc(sc) sc->pc--
60025 
60026 #define OPT_PRINT 0
60027 
60028 #if OPT_PRINT
60029 #define return_false(Sc, Expr) return(return_false_1(Sc, Expr, __func__, __LINE__))
60030 static bool return_false_1(s7_scheme *sc, s7_pointer expr, const char *func, int32_t line)
60031 {
60032   if (expr)
60033     fprintf(stderr, "   %s%s[%d]%s: %s\n", BOLD_TEXT, func, line, UNBOLD_TEXT, display_80(expr));
60034   else fprintf(stderr, "   %s%s[%d]%s: false\n", BOLD_TEXT, func, line, UNBOLD_TEXT);
60035   return(false);
60036 }
60037 #else
60038 #define return_false(Sc, Expr) return(false)
60039 #endif
60040 
60041 static s7_pointer opt_integer_symbol(s7_scheme *sc, s7_pointer sym)
60042 {
60043   if (is_symbol(sym))
60044     {
60045       s7_pointer p;
60046       p = lookup_slot_from(sym, sc->curlet);
60047       if ((is_slot(p)) &&
60048 	  (is_t_integer(slot_value(p))))
60049 	return(p);
60050     }
60051   return(NULL);
60052 }
60053 
60054 static s7_pointer opt_real_symbol(s7_scheme *sc, s7_pointer sym)
60055 {
60056   if (is_symbol(sym))
60057     {
60058       s7_pointer p;
60059       p = lookup_slot_from(sym, sc->curlet);
60060       if ((is_slot(p)) &&
60061 	  (is_small_real(slot_value(p))))
60062 	return(p);
60063     }
60064   return(NULL);
60065 }
60066 
60067 static s7_pointer opt_float_symbol(s7_scheme *sc, s7_pointer sym)
60068 {
60069   if (is_symbol(sym))
60070     {
60071       s7_pointer p;
60072       p = lookup_slot_from(sym, sc->curlet);
60073       if ((is_slot(p)) &&
60074 	  (is_t_real(slot_value(p))))
60075 	return(p);
60076     }
60077   return(NULL);
60078 }
60079 
60080 static s7_pointer opt_simple_symbol(s7_scheme *sc, s7_pointer sym)
60081 {
60082   s7_pointer p;
60083   p = lookup_slot_from(sym, sc->curlet);
60084   if ((is_slot(p)) &&
60085       (!has_methods(slot_value(p))))
60086     return(p);
60087   return(NULL);
60088 }
60089 
60090 static s7_pointer opt_types_match(s7_scheme *sc, s7_pointer check, s7_pointer sym)
60091 {
60092   s7_pointer slot, checker;
60093   checker = s7_symbol_value(sc, check);
60094   slot = lookup_slot_from(sym, sc->curlet);
60095   if (is_slot(slot))
60096     {
60097       s7_pointer obj;
60098       obj = slot_value(slot);
60099       if (s7_apply_function(sc, checker, set_plist_1(sc, obj)) == sc->T)
60100 	return(slot);
60101     }
60102   return(NULL);
60103 }
60104 
60105 static s7_double opt_float_any(s7_scheme *sc, s7_pointer expr)     {return(sc->opts[0]->v[0].fd(sc->opts[0]));}
60106 static s7_pointer opt_bool_any(s7_scheme *sc, s7_pointer expr)     {return((sc->opts[0]->v[0].fb(sc->opts[0])) ? sc->T : sc->F);}
60107 static s7_pointer opt_float_any_nr(s7_scheme *sc, s7_pointer expr) {sc->opts[0]->v[0].fd(sc->opts[0]); return(NULL);}
60108 static s7_pointer opt_int_any_nr(s7_scheme *sc, s7_pointer expr)   {sc->opts[0]->v[0].fi(sc->opts[0]); return(NULL);}
60109 static s7_pointer opt_cell_any_nr(s7_scheme *sc, s7_pointer expr)  {return(sc->opts[0]->v[0].fp(sc->opts[0]));}
60110 static s7_pointer opt_bool_any_nr(s7_scheme *sc, s7_pointer expr)  {sc->opts[0]->v[0].fb(sc->opts[0]); return(NULL);}
60111 
60112 /* callers for s7_optimize */
60113 static s7_pointer opt_wrap_float(s7_scheme *sc, s7_pointer expr) {return(make_real(sc, sc->opts[0]->v[0].fd(sc->opts[0])));}
60114 static s7_pointer opt_wrap_int(s7_scheme *sc, s7_pointer expr)   {return(make_integer(sc, sc->opts[0]->v[0].fi(sc->opts[0])));}
60115 static s7_pointer opt_wrap_cell(s7_scheme *sc, s7_pointer expr)  {return(sc->opts[0]->v[0].fp(sc->opts[0]));}
60116 static s7_pointer opt_wrap_bool(s7_scheme *sc, s7_pointer expr)  {return((sc->opts[0]->v[0].fb(sc->opts[0])) ? sc->T : sc->F);}
60117 
60118 static bool p_to_b(opt_info *o)          {return(o->v[O_WRAP].fp(o) != opt_sc(o)->F);}
60119 static s7_pointer d_to_p(opt_info *o)    {return(make_real(opt_sc(o), o->v[O_WRAP].fd(o)));}
60120 static s7_pointer d_to_p_nr(opt_info *o) {o->v[O_WRAP].fd(o); return(NULL);}
60121 static s7_pointer i_to_p(opt_info *o)    {return(make_integer(opt_sc(o), o->v[O_WRAP].fi(o)));}
60122 static s7_pointer i_to_p_nr(opt_info *o) {o->v[O_WRAP].fi(o); return(NULL);}
60123 
60124 
60125 /* -------------------------------- int opts -------------------------------- */
60126 
60127 static bool int_optimize(s7_scheme *sc, s7_pointer expr);
60128 static bool float_optimize(s7_scheme *sc, s7_pointer expr);
60129 
60130 static s7_int opt_i_c(opt_info *o) {return(o->v[1].i);}
60131 static s7_int opt_i_s(opt_info *o) {return(integer(slot_value(o->v[1].p)));}
60132 
60133 static bool opt_int_not_pair(s7_scheme *sc, s7_pointer car_x)
60134 {
60135   opt_info *opc;
60136   s7_pointer p;
60137   if (is_t_integer(car_x))
60138     {
60139       opc = alloc_opo(sc);
60140       opc->v[1].i = integer(car_x);
60141       opc->v[0].fi = opt_i_c;
60142       return(true);
60143     }
60144   p = opt_integer_symbol(sc, car_x);
60145   if (p)
60146     {
60147       opc = alloc_opo(sc);
60148       opc->v[1].p = p;
60149       opc->v[0].fi = opt_i_s;
60150       return(true);
60151     }
60152   return_false(sc, car_x);
60153 }
60154 
60155 /* -------- i_i|d|p -------- */
60156 static s7_int opt_i_i_c(opt_info *o)  {return(o->v[2].i_i_f(o->v[1].i));}
60157 static s7_int opt_i_i_s(opt_info *o)  {return(o->v[2].i_i_f(integer(slot_value(o->v[1].p))));}
60158 static s7_int opt_i_7i_c(opt_info *o) {return(o->v[2].i_7i_f(opt_sc(o), o->v[1].i));}
60159 static s7_int opt_i_7i_s(opt_info *o) {return(o->v[2].i_7i_f(opt_sc(o), integer(slot_value(o->v[1].p))));}
60160 static s7_int opt_i_d_c(opt_info *o)  {return(o->v[2].i_7d_f(opt_sc(o), o->v[1].x));}
60161 static s7_int opt_i_d_s(opt_info *o)  {return(o->v[2].i_7d_f(opt_sc(o), real(slot_value(o->v[1].p))));}
60162 
60163 static s7_int opt_i_i_f(opt_info *o)  {return(o->v[2].i_i_f(o->v[4].fi(o->v[3].o1)));}
60164 static s7_int opt_i_i_abs(opt_info *o) {return(abs_i_i(o->v[4].fi(o->v[3].o1)));}
60165 static s7_int opt_i_7i_f(opt_info *o) {return(o->v[2].i_7i_f(opt_sc(o), o->v[4].fi(o->v[3].o1)));}
60166 static s7_int opt_i_7d_f(opt_info *o) {return(o->v[2].i_7d_f(opt_sc(o), o->v[4].fd(o->v[3].o1)));}
60167 static s7_int opt_i_7p_f(opt_info *o) {return(o->v[2].i_7p_f(opt_sc(o), o->v[4].fp(o->v[3].o1)));}
60168 static s7_int opt_i_7p_f_cint(opt_info *o) {return(char_to_integer_i_7p(opt_sc(o), o->v[4].fp(o->v[3].o1)));}
60169 
60170 static bool i_idp_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
60171 {
60172   s7_i_i_t func;
60173   s7_i_7i_t func7 = NULL;
60174   s7_i_7d_t idf;
60175   s7_i_7p_t ipf;
60176   s7_pointer p;
60177   int32_t start;
60178 
60179   start = sc->pc;
60180   opc->v[3].o1 = sc->opts[start];
60181 
60182   func = s7_i_i_function(s_func);
60183   if (!func)
60184     func7 = s7_i_7i_function(s_func);
60185   if ((func) || (func7))
60186     {
60187       if (func)
60188 	opc->v[2].i_i_f = func;
60189       else opc->v[2].i_7i_f = func7;
60190       if (is_t_integer(cadr(car_x)))
60191 	{
60192 	  opc->v[1].i = integer(cadr(car_x));
60193 	  opc->v[0].fi = (func) ? opt_i_i_c : opt_i_7i_c;
60194 	  return(true);
60195 	}
60196       p = opt_integer_symbol(sc, cadr(car_x));
60197       if (p)
60198 	{
60199 	  opc->v[1].p = p;
60200 	  opc->v[0].fi = (func) ? opt_i_i_s : opt_i_7i_s;
60201 	  return(true);
60202 	}
60203       if (int_optimize(sc, cdr(car_x)))
60204 	{
60205 	  opc->v[4].fi = sc->opts[start]->v[0].fi;
60206 	  opc->v[0].fi = (func) ? ((func == abs_i_i) ? opt_i_i_abs : opt_i_i_f) : opt_i_7i_f;
60207 	  return(true);
60208 	}
60209       pc_fallback(sc, start);
60210     }
60211   if (!is_t_ratio(cadr(car_x)))
60212     {
60213       idf = s7_i_7d_function(s_func);
60214       if (idf)
60215 	{
60216 	  opc->v[2].i_7d_f = idf;
60217 	  if (is_small_real(cadr(car_x)))
60218 	    {
60219 	      opc->v[1].x = s7_number_to_real(sc, cadr(car_x));
60220 	      opc->v[0].fi = opt_i_d_c;
60221 	      return(true);
60222 	    }
60223 	  p = opt_float_symbol(sc, cadr(car_x));
60224 	  if (p)
60225 	    {
60226 	      opc->v[1].p = p;
60227 	      opc->v[0].fi = opt_i_d_s;
60228 	      return(true);
60229 	    }
60230 	  if (float_optimize(sc, cdr(car_x)))
60231 	    {
60232 	      opc->v[0].fi = opt_i_7d_f;
60233 	      opc->v[4].fd = sc->opts[start]->v[0].fd;
60234 	      return(true);
60235 	    }
60236 	  pc_fallback(sc, start);
60237 	}}
60238   ipf = s7_i_7p_function(s_func);
60239   if (ipf)
60240     {
60241       opc->v[2].i_7p_f = ipf;
60242       if (cell_optimize(sc, cdr(car_x)))
60243 	{
60244 	  opc->v[0].fi = (ipf == char_to_integer_i_7p) ? opt_i_7p_f_cint : opt_i_7p_f;
60245 	  opc->v[4].fp = sc->opts[start]->v[0].fp;
60246 	  return(true);
60247 	}
60248       pc_fallback(sc, start);
60249     }
60250   return_false(sc, car_x);
60251 }
60252 
60253 
60254 /* -------- i_pi -------- */
60255 
60256 static s7_int opt_i_7pi_ss(opt_info *o) {return(o->v[3].i_7pi_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p))));}
60257 static s7_int ivref_7pi_ss(opt_info *o) {return(int_vector(slot_value(o->v[1].p), integer(slot_value(o->v[2].p))));}
60258 static s7_int opt_i_7pi_sf(opt_info *o) {return(o->v[3].i_7pi_f(opt_sc(o), slot_value(o->v[1].p), o->v[5].fi(o->v[4].o1)));}
60259 
60260 static bool i_7pi_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
60261 {
60262   s7_i_7pi_t pfunc;
60263   pfunc = s7_i_7pi_function(s_func);
60264   if (pfunc)
60265     {
60266       s7_pointer sig;
60267       sig = c_function_signature(s_func);
60268       if (is_pair(sig))
60269 	{
60270 	  s7_pointer arg1, arg2, slot;
60271 	  int32_t start;
60272 	  start = sc->pc;
60273 	  arg1 = cadr(car_x);
60274 	  arg2 = caddr(car_x);
60275 
60276 	  if ((is_symbol(cadr(sig))) &&
60277 	      (is_symbol(arg1)) &&
60278 	      (slot = opt_types_match(sc, cadr(sig), arg1)))
60279 	    {
60280 	      s7_pointer p;
60281 	      opc->v[1].p = slot;
60282 	      if ((car(car_x) == sc->int_vector_ref_symbol) &&
60283 		  ((!is_int_vector(slot_value(slot))) ||
60284 		   (vector_rank(slot_value(slot)) > 1)))
60285 		return_false(sc, car_x);
60286 
60287 	      opc->v[3].i_7pi_f = pfunc;
60288 	      p = opt_integer_symbol(sc, arg2);
60289 	      if (p)
60290 		{
60291 		  opc->v[2].p = p;
60292 		  opc->v[0].fi = opt_i_7pi_ss;
60293 		  if ((car(car_x) == sc->int_vector_ref_symbol) &&
60294 		      (is_step_end(opc->v[2].p)) &&
60295 		      (denominator(slot_value(opc->v[2].p)) <= vector_length(slot_value(opc->v[1].p))))
60296 		    {
60297 		      opc->v[0].fi = ivref_7pi_ss;
60298 		      opc->v[3].i_7pi_f = int_vector_ref_unchecked;
60299 		    }
60300 		  return(true);
60301 		}
60302 	      opc->v[4].o1 = sc->opts[sc->pc];
60303 	      if (int_optimize(sc, cddr(car_x)))
60304 		{
60305 		  opc->v[0].fi = opt_i_7pi_sf;
60306 		  opc->v[5].fi = opc->v[4].o1->v[0].fi;
60307 		  return(true);
60308 		}
60309 	      pc_fallback(sc, start);
60310 	    }}}
60311   return_false(sc, car_x);
60312 }
60313 
60314 /* -------- i_ii -------- */
60315 static s7_int opt_i_ii_cc(opt_info *o)     {return(o->v[3].i_ii_f(o->v[1].i, o->v[2].i));}
60316 static s7_int opt_i_ii_cs(opt_info *o)     {return(o->v[3].i_ii_f(o->v[1].i, integer(slot_value(o->v[2].p))));}
60317 static s7_int opt_i_ii_cs_mul(opt_info *o) {return(o->v[1].i * integer(slot_value(o->v[2].p)));}
60318 static s7_int opt_i_ii_sc(opt_info *o)     {return(o->v[3].i_ii_f(integer(slot_value(o->v[1].p)), o->v[2].i));}
60319 static s7_int opt_i_ii_sc_add(opt_info *o) {return(integer(slot_value(o->v[1].p)) + o->v[2].i);}
60320 static s7_int opt_i_ii_sc_sub(opt_info *o) {return(integer(slot_value(o->v[1].p)) - o->v[2].i);}
60321 static s7_int opt_i_ii_ss(opt_info *o)     {return(o->v[3].i_ii_f(integer(slot_value(o->v[1].p)), integer(slot_value(o->v[2].p))));}
60322 static s7_int opt_i_ii_ss_add(opt_info *o) {return(integer(slot_value(o->v[1].p)) + integer(slot_value(o->v[2].p)));}
60323 static s7_pointer opt_p_ii_ss_add(opt_info *o) {return(make_integer(opt_sc(o), integer(slot_value(o->v[1].p)) + integer(slot_value(o->v[2].p))));}
60324 static s7_int opt_i_ii_cf(opt_info *o)     {return(o->v[3].i_ii_f(o->v[1].i, o->v[5].fi(o->v[4].o1)));}
60325 static s7_int opt_i_ii_cf_mul(opt_info *o) {return(o->v[1].i * o->v[5].fi(o->v[4].o1));}
60326 static s7_int opt_i_ii_sf(opt_info *o)     {return(o->v[3].i_ii_f(integer(slot_value(o->v[1].p)), o->v[5].fi(o->v[4].o1)));}
60327 static s7_int opt_i_ii_sf_add(opt_info *o) {return(integer(slot_value(o->v[1].p)) + o->v[5].fi(o->v[4].o1));}
60328 
60329 static s7_int opt_i_ii_ff(opt_info *o)
60330 {
60331   s7_int i1, i2;
60332   i1 = o->v[11].fi(o->v[10].o1);
60333   i2 = o->v[9].fi(o->v[8].o1);
60334   return(o->v[3].i_ii_f(i1, i2));
60335 }
60336 
60337 static s7_int opt_i_ii_fc(opt_info *o)     {return(o->v[3].i_ii_f(o->v[11].fi(o->v[10].o1), o->v[2].i));}
60338 static s7_int opt_i_ii_fc_add(opt_info *o) {return(o->v[11].fi(o->v[10].o1) + o->v[2].i);}
60339 static s7_int opt_i_ii_fc_mul(opt_info *o) {return(o->v[11].fi(o->v[10].o1) * o->v[2].i);}
60340 static s7_int opt_i_7ii_fc(opt_info *o)    {return(o->v[3].i_7ii_f(opt_sc(o), o->v[11].fi(o->v[10].o1), o->v[2].i));}
60341 static s7_int opt_i_ii_fco(opt_info *o)    {return(o->v[3].i_ii_f(o->v[4].i_7pi_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p))), o->v[5].i));}
60342 static s7_int opt_i_ii_fco_add(opt_info *o){return(o->v[4].i_7pi_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p))) + o->v[5].i);}  /* tref */
60343 static s7_int opt_i_7ii_fco(opt_info *o)   {return(o->v[3].i_7ii_f(opt_sc(o), o->v[4].i_7pi_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p))), o->v[5].i));}
60344 
60345 static bool i_ii_fc_combinable(s7_scheme *sc, opt_info *opc, s7_i_ii_t func)
60346 {
60347   if ((sc->pc > 1) &&
60348       (opc == sc->opts[sc->pc - 2]))
60349     {
60350       opt_info *o1;
60351       o1 = sc->opts[sc->pc - 1];
60352       if ((o1->v[0].fi == opt_i_7pi_ss) || (o1->v[0].fi == ivref_7pi_ss))
60353 	{
60354 	  opc->v[5].i = opc->v[2].i; /* move v2.i ("c" in fc = arg2) out of the symbols' way */
60355 	  opc->v[4].i_7pi_f = o1->v[3].i_7pi_f;
60356 	  opc->v[1].p = o1->v[1].p;
60357 	  opc->v[2].p = o1->v[2].p;
60358 	  if (func)
60359 	    opc->v[0].fi = (opc->v[3].i_ii_f == add_i_ii) ? opt_i_ii_fco_add : opt_i_ii_fco;
60360 	  else opc->v[0].fi = opt_i_7ii_fco;
60361 	  backup_pc(sc);
60362 	  return(true);
60363 	}}
60364   return_false(sc, NULL);
60365 }
60366 
60367 static s7_int opt_i_7ii_cc(opt_info *o) {return(o->v[3].i_7ii_f(opt_sc(o), o->v[1].i, o->v[2].i));}
60368 static s7_int opt_i_7ii_cs(opt_info *o) {return(o->v[3].i_7ii_f(opt_sc(o), o->v[1].i, integer(slot_value(o->v[2].p))));}
60369 static s7_int opt_i_7ii_sc(opt_info *o) {return(o->v[3].i_7ii_f(opt_sc(o), integer(slot_value(o->v[1].p)), o->v[2].i));} /* currently unhittable I think */
60370 static s7_int opt_i_7ii_ss(opt_info *o) {return(o->v[3].i_7ii_f(opt_sc(o), integer(slot_value(o->v[1].p)), integer(slot_value(o->v[2].p))));}
60371 static s7_int opt_i_7ii_cf(opt_info *o) {return(o->v[3].i_7ii_f(opt_sc(o), o->v[1].i, o->v[5].fi(o->v[4].o1)));}
60372 static s7_int opt_i_7ii_sf(opt_info *o) {return(o->v[3].i_7ii_f(opt_sc(o), integer(slot_value(o->v[1].p)), o->v[5].fi(o->v[4].o1)));}
60373 
60374 static s7_int opt_i_7ii_ff(opt_info *o)
60375 {
60376   s7_int i1, i2;
60377   i1 = o->v[11].fi(o->v[10].o1);
60378   i2 = o->v[9].fi(o->v[8].o1);
60379   return(o->v[3].i_7ii_f(opt_sc(o), i1, i2));
60380 }
60381 
60382 #if WITH_GMP
60383 static s7_int opt_add_i_random_i(opt_info *o)      {return(o->v[1].i + (s7_int)(o->v[2].i * next_random(opt_sc(o))));}
60384 static s7_int opt_subtract_random_i_i(opt_info *o) {return((s7_int)(o->v[1].i * next_random(opt_sc(o))) - o->v[2].i);}
60385 #else
60386 static s7_int opt_add_i_random_i(opt_info *o)      {return(o->v[1].i + (s7_int)(o->v[2].i * next_random(opt_sc(o)->default_rng)));}
60387 static s7_int opt_subtract_random_i_i(opt_info *o) {return((s7_int)(o->v[1].i * next_random(opt_sc(o)->default_rng)) - o->v[2].i);}
60388 #endif
60389 
60390 static bool i_ii_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
60391 {
60392   s7_i_ii_t ifunc;
60393   s7_i_7ii_t ifunc7 = NULL;
60394   s7_pointer p;
60395   ifunc = s7_i_ii_function(s_func);
60396   if (!ifunc) ifunc7 = s7_i_7ii_function(s_func);
60397   if ((ifunc) || (ifunc7))
60398     {
60399       s7_pointer sig;
60400       sig = c_function_signature(s_func);
60401       if (is_pair(sig))
60402 	{
60403 	  s7_pointer arg1, arg2;
60404 	  int32_t start;
60405 	  start = sc->pc;
60406 	  arg1 = cadr(car_x);
60407 	  arg2 = caddr(car_x);
60408 	  if (ifunc)
60409 	    opc->v[3].i_ii_f = ifunc;
60410 	  else opc->v[3].i_7ii_f = ifunc7;
60411 
60412 	  if (is_t_integer(arg1))
60413 	    {
60414 	      opc->v[1].i = integer(arg1);
60415 	      if (is_t_integer(arg2))
60416 		{
60417 		  opc->v[2].i = integer(arg2);
60418 		  opc->v[0].fi = (ifunc) ? opt_i_ii_cc : opt_i_7ii_cc;
60419 		  return(true);
60420 		}
60421 	      p = opt_integer_symbol(sc, arg2);
60422 	      if (p)
60423 		{
60424 		  opc->v[2].p = p;
60425 		  if (ifunc)
60426 		    opc->v[0].fi = (opc->v[3].i_ii_f == multiply_i_ii) ? opt_i_ii_cs_mul : opt_i_ii_cs;
60427 		  else opc->v[0].fi = opt_i_7ii_cs;
60428 		  return(true);
60429 		}
60430 	      opc->v[4].o1 = sc->opts[sc->pc];
60431 	      if (int_optimize(sc, cddr(car_x)))
60432 		{
60433 		  if (ifunc)
60434 		    {
60435 		      opc->v[0].fi = opt_i_ii_cf;       /* sc->opts[start]->v[0].fi -> opt_i_7i_c -> same_opt->v[2].i_7i_f = random_i_7i tmap */
60436 		      if ((ifunc == add_i_ii) && (opc == sc->opts[sc->pc - 2]) &&
60437 			  (sc->opts[start]->v[0].fi == opt_i_7i_c) &&
60438 			  (sc->opts[start]->v[2].i_7i_f == random_i_7i))
60439 			{
60440 			  opc->v[0].fi = opt_add_i_random_i;
60441 			  opc->v[2].i = sc->opts[start]->v[1].i;
60442 			  backup_pc(sc);
60443 			}
60444 		      else if (ifunc == multiply_i_ii) opc->v[0].fi = opt_i_ii_cf_mul;
60445 		    }
60446 		  else opc->v[0].fi = opt_i_7ii_cf;
60447 		  opc->v[5].fi = opc->v[4].o1->v[0].fi;
60448 		  return(true);
60449 		}
60450 	      pc_fallback(sc, start);
60451 	    }
60452 	  else
60453 	    {
60454 	      p = opt_integer_symbol(sc, arg1);
60455 	      if (p)
60456 		{
60457 		  opc->v[1].p = p;
60458 		  if (is_t_integer(arg2))
60459 		    {
60460 		      opc->v[2].i = integer(arg2);
60461 		      if (ifunc)
60462 			{
60463 			  if (opc->v[3].i_ii_f == add_i_ii)
60464 			    opc->v[0].fi = opt_i_ii_sc_add;
60465 			  else opc->v[0].fi = (opc->v[3].i_ii_f == subtract_i_ii) ? opt_i_ii_sc_sub : opt_i_ii_sc; /* sub1 is not faster */
60466 			}
60467 		      else opc->v[0].fi = opt_i_7ii_sc;
60468 		      if ((car(car_x) == sc->modulo_symbol) &&
60469 			  (integer(arg2) > 1))
60470 			opc->v[3].i_ii_f = modulo_i_ii_unchecked;
60471 		      else
60472 			{
60473 			  if (car(car_x) == sc->ash_symbol)
60474 			    {
60475 			      if (opc->v[2].i < 0)
60476 				{
60477 				  opc->v[3].i_ii_f = (opc->v[2].i == -1) ? rsh_i_i2_direct : rsh_i_ii_unchecked;
60478 				  opc->v[0].fi = opt_i_ii_sc;
60479 				}
60480 			      else
60481 				if (opc->v[2].i < S7_INT_BITS)
60482 				  {
60483 				    opc->v[3].i_ii_f = lsh_i_ii_unchecked;
60484 				    opc->v[0].fi = opt_i_ii_sc;
60485 				  }}
60486 			  else
60487 			    {
60488 			      if (opc->v[2].i > 0)
60489 				{
60490 				  /* these assume vunion is a union, not a struct; i_7ii_f otherwise might be leftover from a previous use */
60491 				  if (opc->v[3].i_7ii_f == quotient_i_7ii)
60492 				    {
60493 				      opc->v[3].i_ii_f = quotient_i_ii_unchecked;
60494 				      opc->v[0].fi = opt_i_ii_sc;
60495 				    }
60496 				  else
60497 				    if ((opc->v[2].i > 1) && (opc->v[3].i_7ii_f == remainder_i_7ii))
60498 				      {
60499 					opc->v[3].i_ii_f = remainder_i_ii_unchecked;
60500 					opc->v[0].fi = opt_i_ii_sc;
60501 				      }}}}
60502 		      return(true);
60503 		    } /* opt_int arg2 */
60504 		  p = opt_integer_symbol(sc, arg2);
60505 		  if (p)
60506 		    {
60507 		      opc->v[2].p = p;
60508 		      if (ifunc)
60509 			opc->v[0].fi = (opc->v[3].i_ii_f == add_i_ii) ? opt_i_ii_ss_add : opt_i_ii_ss;
60510 		      else opc->v[0].fi = opt_i_7ii_ss;
60511 		      return(true);
60512 		    }
60513 		  if (int_optimize(sc, cddr(car_x)))
60514 		    {
60515 		      opc->v[4].o1 = sc->opts[start];
60516 		      opc->v[5].fi = sc->opts[start]->v[0].fi;
60517 		      if (ifunc)
60518 			opc->v[0].fi = (opc->v[3].i_ii_f == add_i_ii) ? opt_i_ii_sf_add : opt_i_ii_sf;
60519 		      else opc->v[0].fi = opt_i_7ii_sf;
60520 		      return(true);
60521 		    }
60522 		  pc_fallback(sc, start);
60523 		}
60524 	      else
60525 		{
60526 		  if (is_t_integer(arg2))
60527 		    {
60528 		      opc->v[2].i = integer(arg2);
60529 		      opc->v[10].o1 = sc->opts[sc->pc];
60530 		      if (int_optimize(sc, cdr(car_x)))
60531 			{
60532 			  opc->v[11].fi = opc->v[10].o1->v[0].fi;
60533 			  if (!i_ii_fc_combinable(sc, opc, ifunc))
60534 			    {
60535 			      if (ifunc)
60536 				{
60537 				  if (opc->v[3].i_ii_f == add_i_ii) {opc->v[0].fi = opt_i_ii_fc_add; return(true);}
60538 				  if (opc->v[3].i_ii_f == multiply_i_ii) {opc->v[0].fi = opt_i_ii_fc_mul; return(true);}
60539 				  opc->v[0].fi = opt_i_ii_fc;
60540 
60541 				  if ((opc->v[3].i_ii_f == subtract_i_ii) && (opc == sc->opts[sc->pc - 2]) &&
60542 				      (sc->opts[start]->v[0].fi == opt_i_7i_c) &&
60543 				      (sc->opts[start]->v[2].i_7i_f == random_i_7i))
60544 				    {
60545 				      opc->v[0].fi = opt_subtract_random_i_i;
60546 				      opc->v[1].i = sc->opts[start]->v[1].i;
60547 				      backup_pc(sc);
60548 				    }}
60549 			      else opc->v[0].fi = opt_i_7ii_fc;
60550 			      if (opc->v[2].i > 0)
60551 				{
60552 				  if (opc->v[3].i_7ii_f == quotient_i_7ii)
60553 				    {
60554 				      opc->v[3].i_ii_f = quotient_i_ii_unchecked;
60555 				      opc->v[0].fi = opt_i_ii_fc;
60556 				    }
60557 				  else
60558 				    if ((opc->v[2].i > 1) && (opc->v[3].i_7ii_f == remainder_i_7ii))
60559 				      {
60560 					opc->v[3].i_ii_f = remainder_i_ii_unchecked;
60561 					opc->v[0].fi = opt_i_ii_fc;
60562 				      }}}
60563 			  return(true);
60564 			}
60565 		      pc_fallback(sc, start);
60566 		    }
60567 		  else
60568 		    {
60569 		      opc->v[10].o1 = sc->opts[sc->pc];
60570 		      if (int_optimize(sc, cdr(car_x)))
60571 			{
60572 			  opc->v[11].fi = opc->v[10].o1->v[0].fi;
60573 			  opc->v[8].o1 = sc->opts[sc->pc];
60574 			  if (int_optimize(sc, cddr(car_x)))
60575 			    {
60576 			      opc->v[9].fi = opc->v[8].o1->v[0].fi;
60577 			      opc->v[0].fi = (ifunc) ? opt_i_ii_ff : opt_i_7ii_ff;
60578 			      return(true);
60579 			    }
60580 			  pc_fallback(sc, start);
60581 			}}}}}}
60582   return_false(sc, car_x);
60583 }
60584 
60585 /* -------- i_iii -------- */
60586 static s7_int opt_i_iii_fff(opt_info *o)
60587 {
60588   s7_int i1, i2, i3;
60589   i1 = o->v[11].fi(o->v[10].o1);
60590   i2 = o->v[9].fi(o->v[8].o1);
60591   i3 = o->v[5].fi(o->v[4].o1);
60592   return(o->v[3].i_iii_f(i1, i2, i3));
60593 }
60594 
60595 static bool i_iii_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
60596 {
60597   s7_i_iii_t ifunc;
60598   ifunc = s7_i_iii_function(s_func);
60599   if (ifunc)
60600     {
60601       int32_t start;
60602       start = sc->pc;
60603       opc->v[10].o1 = sc->opts[start];
60604       if (int_optimize(sc, cdr(car_x)))
60605 	{
60606 	  opc->v[8].o1 = sc->opts[sc->pc];
60607 	  if (int_optimize(sc, cddr(car_x)))
60608 	    {
60609 	      opc->v[4].o1 = sc->opts[sc->pc];
60610 	      if (int_optimize(sc, cdddr(car_x)))
60611 		{
60612 		  opc->v[3].i_iii_f = ifunc;
60613 		  opc->v[0].fi = opt_i_iii_fff;
60614 		  opc->v[11].fi = opc->v[10].o1->v[0].fi;
60615 		  opc->v[9].fi = opc->v[8].o1->v[0].fi;
60616 		  opc->v[5].fi = opc->v[4].o1->v[0].fi;
60617 		  return(true);
60618 		}}}
60619       pc_fallback(sc, start);
60620       return_false(sc, car_x);
60621     }
60622   return_false(sc, car_x);
60623 }
60624 
60625 /* -------- i_7pii -------- */
60626 static s7_int opt_i_7pii_ssf(opt_info *o) {return(o->v[3].i_7pii_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[5].fi(o->v[4].o1)));}
60627 static s7_int opt_i_7pii_ssf_vset(opt_info *o) {return(int_vector_set_unchecked(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[5].fi(o->v[4].o1)));}
60628 static s7_int opt_i_7pii_ssc(opt_info *o) {return(o->v[3].i_7pii_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[4].i));}
60629 static s7_int opt_i_7pii_sss(opt_info *o) {return(o->v[4].i_7pii_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p))));}
60630 
60631 static s7_int opt_i_7pii_sff(opt_info *o)
60632 {
60633   s7_int i1, i2;
60634   i1 = o->v[11].fi(o->v[10].o1);
60635   i2 = o->v[9].fi(o->v[8].o1);
60636   return(o->v[3].i_7pii_f(opt_sc(o), slot_value(o->v[1].p), i1, i2));
60637 }
60638 
60639 
60640 /* -------- i_7piii -------- */
60641 static s7_int opt_i_7piii_sssf(opt_info *o)
60642 {
60643   return(o->v[5].i_7piii_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p)), o->v[11].fi(o->v[10].o1)));
60644 }
60645 
60646 static s7_int opt_i_7piii_sssc(opt_info *o)
60647 {
60648   return(o->v[5].i_7piii_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p)), o->v[4].i));
60649 }
60650 
60651 static s7_int opt_i_7piii_ssss(opt_info *o)
60652 {
60653   return(o->v[5].i_7piii_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p)), integer(slot_value(o->v[4].p))));
60654 }
60655 
60656 static s7_int opt_i_7piii_sfff(opt_info *o)
60657 {
60658   s7_int i1, i2, i3;
60659   i1 = o->v[11].fi(o->v[10].o1);
60660   i2 = o->v[9].fi(o->v[8].o1);
60661   i3 = o->v[6].fi(o->v[4].o1);
60662   return(o->v[5].i_7piii_f(opt_sc(o), slot_value(o->v[1].p), i1, i2, i3));
60663 }
60664 
60665 static bool opt_i_7piii_args(s7_scheme *sc, opt_info *opc, s7_pointer indexp1, s7_pointer indexp2, s7_pointer valp)
60666 {
60667   /* opc->v[5] is the called function (int-vector-set! etc) */
60668   s7_pointer slot;
60669   slot = opt_integer_symbol(sc, car(indexp2));
60670   if (slot)
60671     {
60672       opc->v[3].p = slot;
60673       slot = opt_integer_symbol(sc, car(indexp1));
60674       if (slot)
60675 	{
60676 	  opc->v[2].p = slot;
60677 	  if (is_t_integer(car(valp)))
60678 	    {
60679 	      opc->v[0].fi = opt_i_7piii_sssc;
60680 	      opc->v[4].i = integer(car(valp));
60681 	      return(true);
60682 	    }
60683 	  slot = opt_integer_symbol(sc, car(valp));
60684 	  if (slot)
60685 	    {
60686 	      opc->v[4].p = slot;
60687 	      opc->v[0].fi = opt_i_7piii_ssss;
60688 	      return(true);
60689 	    }
60690 	  opc->v[10].o1 = sc->opts[sc->pc];
60691 	  if (int_optimize(sc, valp))
60692 	    {
60693 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
60694 	      opc->v[0].fi = opt_i_7piii_sssf;
60695 	      return(true);
60696 	    }}
60697       return_false(sc, NULL);
60698     }
60699   opc->v[10].o1 = sc->opts[sc->pc];
60700   if (int_optimize(sc, indexp1))
60701     {
60702       opc->v[8].o1 = sc->opts[sc->pc];
60703       if (int_optimize(sc, indexp2))
60704 	{
60705 	  opc->v[4].o1 = sc->opts[sc->pc];
60706 	  if (int_optimize(sc, valp))
60707 	    {
60708 	      opc->v[0].fi = opt_i_7piii_sfff;
60709 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
60710 	      opc->v[9].fi = opc->v[8].o1->v[0].fi;
60711 	      opc->v[6].fi = opc->v[4].o1->v[0].fi; /* v[5] is in use */
60712 	      return(true);
60713 	    }}}
60714   return_false(sc, indexp1);
60715 }
60716 
60717 static bool opt_int_vector_set(s7_scheme *sc, int otype, opt_info *opc, s7_pointer v, s7_pointer indexp1, s7_pointer indexp2, s7_pointer valp)
60718 {
60719   s7_pointer settee;
60720   settee = lookup_slot_from(v, sc->curlet);
60721   if ((is_slot(settee)) &&
60722       (!is_immutable(slot_value(settee))))
60723     {
60724       bool int_case;
60725       s7_pointer vect, slot;
60726       vect = slot_value(settee);
60727       int_case = (is_int_vector(vect));
60728       opc->v[1].p = settee;
60729       if ((int_case) || (is_byte_vector(vect)))
60730 	{
60731 	  if ((otype >= 0) && (otype != ((int_case) ? 1 : 0)))
60732 	    return_false(sc, indexp1);
60733 	  if ((!indexp2) &&
60734 	      (vector_rank(vect) == 1))
60735 	    {
60736 	      opc->v[3].i_7pii_f = (int_case) ? int_vector_set_i_7pii : byte_vector_set_i_7pii;
60737 	      slot = opt_integer_symbol(sc, car(indexp1));
60738 	      if (slot)
60739 		{
60740 		  int32_t start;
60741 		  start = sc->pc;
60742 		  opc->v[2].p = slot;
60743 		  if ((is_step_end(opc->v[2].p)) &&
60744 		      (denominator(slot_value(opc->v[2].p)) <= vector_length(vect)))
60745 		    opc->v[3].i_7pii_f = (int_case) ? int_vector_set_unchecked : byte_vector_set_unchecked;
60746 		  if ((is_pair(valp)) &&
60747 		      (is_null(cdr(valp))) &&
60748 		      (is_t_integer(car(valp))))
60749 		    {
60750 		      opc->v[4].i = integer(car(valp));
60751 		      opc->v[0].fi = opt_i_7pii_ssc;
60752 		      return(true);
60753 		    }
60754 		  if (int_optimize(sc, valp))
60755 		    {
60756 		      opc->v[0].fi = (opc->v[3].i_7pii_f == int_vector_set_unchecked) ? opt_i_7pii_ssf_vset : opt_i_7pii_ssf;
60757 		      opc->v[4].o1 = sc->opts[start];
60758 		      opc->v[5].fi = sc->opts[start]->v[0].fi;
60759 		      return(true);
60760 		    }
60761 		  return_false(sc, NULL);
60762 		}
60763 	      opc->v[10].o1 = sc->opts[sc->pc];
60764 	      if (int_optimize(sc, indexp1))
60765 		{
60766 		  opc->v[8].o1 = sc->opts[sc->pc];
60767 		  if (int_optimize(sc, valp))
60768 		    {
60769 		      opc->v[0].fi = opt_i_7pii_sff;
60770 		      opc->v[11].fi = opc->v[10].o1->v[0].fi;
60771 		      opc->v[9].fi = opc->v[8].o1->v[0].fi;
60772 		      return(true);
60773 		    }}
60774 	      return_false(sc, NULL);
60775 	    }
60776 
60777 	  if ((indexp2) &&
60778 	      (vector_rank(vect) == 2))
60779 	    {
60780 	      opc->v[5].i_7piii_f = (int_case) ? int_vector_set_i_7piii : byte_vector_set_i_7piii;
60781 	      return(opt_i_7piii_args(sc, opc, indexp1, indexp2, valp));
60782 	    }}}
60783   return_false(sc, v);
60784 }
60785 
60786 static bool i_7pii_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
60787 {
60788   s7_i_7pii_t pfunc;
60789   pfunc = s7_i_7pii_function(s_func);
60790   if (pfunc)
60791     {
60792       s7_pointer sig;
60793       sig = c_function_signature(s_func);
60794       if ((is_pair(sig)) &&
60795 	  (is_symbol(cadr(car_x))))
60796 	{
60797 	  s7_pointer fname, slot;
60798 	  fname = car(car_x);
60799 
60800 	  if ((fname == sc->int_vector_set_symbol) || (fname == sc->byte_vector_set_symbol) ||
60801 	      (s_func == initial_value(sc->int_vector_set_symbol)) ||
60802 	      (s_func == initial_value(sc->byte_vector_set_symbol)))
60803 	    return(opt_int_vector_set(sc, (fname == sc->int_vector_set_symbol) ? 1 : 0, opc, cadr(car_x), cddr(car_x), NULL, cdddr(car_x)));
60804 
60805 	  slot = opt_types_match(sc, cadr(sig), cadr(car_x));
60806 	  if (slot)
60807 	    {
60808 	      s7_pointer arg2, p;
60809 	      int32_t start;
60810 	      start = sc->pc;
60811 	      opc->v[1].p = slot;
60812 
60813 	      if (((fname == sc->int_vector_ref_symbol) || (fname == sc->byte_vector_ref_symbol) ||
60814 		   (s_func == initial_value(sc->int_vector_ref_symbol)) ||
60815 		   (s_func == initial_value(sc->byte_vector_ref_symbol))) &&
60816 		  (vector_rank(slot_value(slot)) != 2))
60817 		return_false(sc, car_x);
60818 
60819 	      arg2 = caddr(car_x);
60820 	      p = opt_integer_symbol(sc, arg2);
60821 	      if (p)
60822 		{
60823 		  opc->v[2].p = p;
60824 		  p = opt_integer_symbol(sc, cadddr(car_x));
60825 		  if (p)
60826 		    {
60827 		      opc->v[3].p = p;
60828 		      opc->v[4].i_7pii_f = pfunc;
60829 		      opc->v[0].fi = opt_i_7pii_sss;
60830 		      return(true);
60831 		    }
60832 		  if (int_optimize(sc, cdddr(car_x)))
60833 		    {
60834 		      opc->v[3].i_7pii_f = pfunc;
60835 		      opc->v[0].fi = opt_i_7pii_ssf;
60836 		      opc->v[4].o1 = sc->opts[start];
60837 		      opc->v[5].fi = sc->opts[start]->v[0].fi;
60838 		      return(true);
60839 		    }
60840 		  return_false(sc, car_x);
60841 		}
60842 	      opc->v[10].o1 = sc->opts[sc->pc];
60843 	      if (int_optimize(sc, cddr(car_x)))
60844 		{
60845 		  opc->v[8].o1 = sc->opts[sc->pc];
60846 		  if (int_optimize(sc, cdddr(car_x)))
60847 		    {
60848 		      opc->v[3].i_7pii_f = pfunc;
60849 		      opc->v[0].fi = opt_i_7pii_sff;
60850 		      opc->v[11].fi = opc->v[10].o1->v[0].fi;
60851 		      opc->v[9].fi = opc->v[8].o1->v[0].fi;
60852 		      return(true);
60853 		    }}
60854 	      pc_fallback(sc, start);
60855 	    }}}
60856   return_false(sc, car_x);
60857 }
60858 
60859 static bool i_7piii_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
60860 {
60861   s7_i_7piii_t f;
60862   f = s7_i_7piii_function(s_func);
60863   if ((f) &&
60864       (is_symbol(cadr(car_x))))
60865     {
60866       s7_pointer settee;
60867       if ((car(car_x) == sc->int_vector_set_symbol) || (car(car_x) == sc->byte_vector_set_symbol) ||
60868 	  (s_func == initial_value(sc->int_vector_set_symbol)) ||
60869 	  (s_func == initial_value(sc->byte_vector_set_symbol)))
60870 	return(opt_int_vector_set(sc, (car(car_x) == sc->int_vector_set_symbol) ? 1 : 0, opc, cadr(car_x), cddr(car_x), cdddr(car_x), cddddr(car_x)));
60871 
60872       settee = lookup_slot_from(cadr(car_x), sc->curlet);
60873       if (is_slot(settee))
60874 	{
60875 	  s7_pointer vect;
60876 	  vect = slot_value(settee);
60877 	  if ((is_int_vector(vect)) && (vector_rank(vect) == 3))
60878 	    {
60879 	      opc->v[5].i_7piii_f = f;
60880 	      opc->v[1].p = settee;
60881 	      return(opt_i_7piii_args(sc, opc, cddr(car_x), cdddr(car_x), cddddr(car_x)));
60882 	    }}}
60883   return_false(sc, car_x);
60884 }
60885 
60886 /* -------- i_add|multiply_any -------- */
60887 static s7_int opt_i_add_any_f(opt_info *o)
60888 {
60889   s7_int sum = 0;
60890   int32_t i;
60891   for (i = 0; i < o->v[1].i; i++)
60892     {
60893       opt_info *o1;
60894       o1 = o->v[i + 2].o1;
60895       sum += o1->v[0].fi(o1);
60896     }
60897   return(sum);
60898 }
60899 
60900 static s7_int opt_i_add2(opt_info *o)
60901 {
60902   s7_int sum;
60903   sum = o->v[6].fi(o->v[2].o1);
60904   return(sum + o->v[7].fi(o->v[3].o1));
60905 }
60906 
60907 static s7_int opt_i_mul2(opt_info *o)
60908 {
60909   s7_int sum;
60910   sum = o->v[6].fi(o->v[2].o1);
60911   return(sum * o->v[7].fi(o->v[3].o1));
60912 }
60913 
60914 static s7_int opt_i_add3(opt_info *o)
60915 {
60916   s7_int sum;
60917   sum = o->v[6].fi(o->v[2].o1);
60918   sum += o->v[7].fi(o->v[3].o1);
60919   return(sum + o->v[8].fi(o->v[4].o1));
60920 }
60921 
60922 static s7_int opt_i_mul3(opt_info *o)
60923 {
60924   s7_int sum;
60925   sum = o->v[6].fi(o->v[2].o1);
60926   sum *= o->v[7].fi(o->v[3].o1);
60927   return(sum * o->v[8].fi(o->v[4].o1));
60928 }
60929 
60930 static s7_int opt_i_add4(opt_info *o)
60931 {
60932   s7_int sum;
60933   sum = o->v[6].fi(o->v[2].o1);
60934   sum += o->v[7].fi(o->v[3].o1);
60935   sum += o->v[8].fi(o->v[4].o1);
60936   return(sum + o->v[9].fi(o->v[5].o1));
60937 }
60938 
60939 static s7_int opt_i_mul4(opt_info *o)
60940 {
60941   s7_int sum;
60942   sum = o->v[6].fi(o->v[2].o1);
60943   sum *= o->v[7].fi(o->v[3].o1);
60944   sum *= o->v[8].fi(o->v[4].o1);
60945   return(sum * o->v[9].fi(o->v[5].o1));
60946 }
60947 
60948 static s7_int opt_i_multiply_any_f(opt_info *o)
60949 {
60950   s7_int sum = 1;
60951   int32_t i;
60952   for (i = 0; i < o->v[1].i; i++)
60953     {
60954       opt_info *o1;
60955       o1 = o->v[i + 2].o1;
60956       sum *= o1->v[0].fi(o1);
60957     }
60958   return(sum);
60959 }
60960 
60961 static bool i_add_any_ok(s7_scheme *sc, opt_info *opc, s7_pointer car_x)
60962 {
60963   s7_pointer p, head;
60964   int32_t cur_len, start;
60965   start = sc->pc;
60966   head = car(car_x);
60967   for (cur_len = 0, p = cdr(car_x); (is_pair(p)) && (cur_len < 12); p = cdr(p), cur_len++)
60968     {
60969       opc->v[V_ind(cur_len + 2)].o1 = sc->opts[sc->pc];
60970       if (!int_optimize(sc, p))
60971 	break;
60972     }
60973   if (is_null(p))
60974     {
60975       opc->v[1].i = cur_len;
60976       if (cur_len <= 4)
60977 	{
60978 	  int32_t i;
60979 	  for (i = 0; i < cur_len; i++)
60980 	    opc->v[V_ind(i + 6)].fi = opc->v[i + 2].o1->v[0].fi;
60981 	}
60982       if (cur_len == 2)
60983 	opc->v[0].fi = (head == sc->add_symbol) ? opt_i_add2 : opt_i_mul2;
60984       else
60985 	{
60986 	  if (cur_len == 3)
60987 	    opc->v[0].fi = (head == sc->add_symbol) ? opt_i_add3 : opt_i_mul3;
60988 	  else
60989 	    {
60990 	      if (cur_len == 4)
60991 		opc->v[0].fi = (head == sc->add_symbol) ? opt_i_add4 : opt_i_mul4;
60992 	      else opc->v[0].fi = (head == sc->add_symbol) ? opt_i_add_any_f : opt_i_multiply_any_f;
60993 	    }}
60994       /* all v[1].i = cur_len */
60995       return(true);
60996     }
60997   pc_fallback(sc, start);
60998   return_false(sc, car_x);
60999 }
61000 
61001 
61002 /* -------- set_i_i -------- */
61003 static s7_int opt_set_i_i_f(opt_info *o)
61004 {
61005   s7_int x;
61006   x = o->v[3].fi(o->v[2].o1);
61007   slot_set_value(o->v[1].p, make_integer(opt_sc(o), x));
61008   return(x);
61009 }
61010 
61011 static s7_int opt_set_i_i_fm(opt_info *o) /* called in increment: (set! sum (+ sum (...))) where are all ints */
61012 {
61013   s7_int x;
61014   x = o->v[3].fi(o->v[2].o1);
61015   integer(slot_value(o->v[1].p)) = x;
61016   return(x);
61017 }
61018 
61019 static s7_int opt_set_i_i_fo(opt_info *o)
61020 {
61021   s7_int x;
61022   x = integer(slot_value(o->v[3].p)) + o->v[2].i;
61023   slot_set_value(o->v[1].p, make_integer(opt_sc(o), x));
61024   return(x);
61025 }
61026 
61027 static bool set_i_i_f_combinable(s7_scheme *sc, opt_info *opc)
61028 {
61029   if ((sc->pc > 1) &&
61030       (opc == sc->opts[sc->pc - 2]))
61031     {
61032       opt_info *o1;
61033       o1 = sc->opts[sc->pc - 1];
61034       if (o1->v[0].fi == opt_i_ii_sc_add)
61035 	{
61036 	  /* opc->v[4].i_ii_f = o1->v[3].i_ii_f; */
61037 	  opc->v[3].p = o1->v[1].p;
61038 	  opc->v[2].i = o1->v[2].i;
61039 	  opc->v[0].fi = opt_set_i_i_fo;
61040 	  backup_pc(sc);
61041 	  return(true); /* ii_sc v[1].p is a slot */
61042 	}}
61043   return_false(sc, NULL);
61044 }
61045 
61046 static bool i_syntax_ok(s7_scheme *sc, s7_pointer car_x, int32_t len)
61047 {
61048   if ((car(car_x) == sc->set_symbol) &&
61049       (len == 3))
61050     {
61051       opt_info *opc;
61052       opc = alloc_opo(sc);
61053       if (is_symbol(cadr(car_x)))  /* (set! i 3) */
61054 	{
61055 	  s7_pointer settee;
61056 	  if ((is_immutable(cadr(car_x))) ||
61057 	      (symbol_has_setter(cadr(car_x))))
61058 	    return_false(sc, car_x);
61059 	  settee = lookup_slot_from(cadr(car_x), sc->curlet);
61060 	  if ((is_slot(settee)) &&
61061 	      (!is_immutable(settee)))
61062 	    {
61063 	      opt_info *o1;
61064 	      o1 = sc->opts[sc->pc];
61065 	      opc->v[1].p = settee;
61066 	      if ((is_t_integer(slot_value(settee))) &&
61067 		  (int_optimize(sc, cddr(car_x))))
61068 		{
61069 		  if (set_i_i_f_combinable(sc, opc))
61070 		    return(true);
61071 		  opc->v[0].fi = (is_mutable_integer(slot_value(opc->v[1].p))) ? opt_set_i_i_fm : opt_set_i_i_f;
61072 		  opc->v[2].o1 = o1;
61073 		  opc->v[3].fi = o1->v[0].fi;
61074 		  return(true); /* or OO_I? */
61075 		}}}
61076       else
61077 	if ((is_pair(cadr(car_x))) &&    /* if is_pair(settee) get setter */
61078 	    (is_symbol(caadr(car_x))) &&
61079 	    (is_pair(cdadr(car_x))))
61080 	  {
61081 	    if (is_null(cddadr(car_x)))
61082 	      return(opt_int_vector_set(sc, -1, opc, caadr(car_x), cdadr(car_x), NULL, cddr(car_x)));
61083 	    if (is_null(cdddr(cadr(car_x))))
61084 	      return(opt_int_vector_set(sc, -1, opc, caadr(car_x), cdadr(car_x), cddadr(car_x), cddr(car_x)));
61085 	  }}
61086   return_false(sc, car_x);
61087 }
61088 
61089 static bool i_implicit_ok(s7_scheme *sc, s7_pointer car_x, int32_t len)
61090 {
61091   s7_pointer s_slot, head;
61092   head = car(car_x);
61093   s_slot = lookup_slot_from(head, sc->curlet);
61094   if ((is_slot(s_slot)) &&
61095       ((is_int_vector(slot_value(s_slot))) || (is_byte_vector(slot_value(s_slot)))))
61096     {
61097       bool int_case;
61098       s7_pointer slot;
61099       int_case = (is_int_vector(slot_value(s_slot)));
61100 
61101       if ((len == 2) &&
61102 	  (vector_rank(slot_value(s_slot)) == 1))
61103 	{
61104 	  /* implicit int|byte-vector-ref */
61105 	  opt_info *opc;
61106 	  opc = alloc_opo(sc);
61107 	  opc->v[1].p = s_slot;
61108 	  slot = opt_integer_symbol(sc, cadr(car_x));
61109 	  if (slot)
61110 	    {
61111 	      opc->v[0].fi = opt_i_7pi_ss;
61112 	      opc->v[3].i_7pi_f = (int_case) ? int_vector_ref_i_7pi : byte_vector_ref_i_7pi;
61113 	      opc->v[2].p = slot;
61114 	      if ((is_step_end(opc->v[2].p)) &&
61115 		  (denominator(slot_value(opc->v[2].p)) <= vector_length(slot_value(opc->v[1].p))))
61116 		opc->v[3].i_7pi_f = (int_case) ? int_vector_ref_unchecked : byte_vector_ref_unchecked;
61117 		  /* not opc->v[0].fi = ivref_7pi_ss -- this causes a huge slowdown in dup.scm?? */
61118 	      return(true);
61119 	    }
61120 	  opc->v[4].o1 = sc->opts[sc->pc];
61121 	  if (int_optimize(sc, cdr(car_x)))
61122 	    {
61123 	      opc->v[0].fi = opt_i_7pi_sf;
61124 	      opc->v[3].i_7pi_f = (int_case) ? int_vector_ref_i_7pi : byte_vector_ref_i_7pi;
61125 	      opc->v[5].fi = opc->v[4].o1->v[0].fi;
61126 	      return(true);
61127 	    }
61128 	  return_false(sc, car_x);
61129 	}
61130 
61131       if ((len == 3) &&
61132 	  (vector_rank(slot_value(s_slot)) == 2))
61133 	{
61134 	  opt_info *opc;
61135 	  opc = alloc_opo(sc);
61136 	  opc->v[1].p = s_slot;
61137 
61138 	  slot = opt_integer_symbol(sc, cadr(car_x));
61139 	  if (slot)
61140 	    {
61141 	      opc->v[2].p = slot;
61142 	      slot = opt_integer_symbol(sc, caddr(car_x));
61143 	      if (slot)
61144 		{
61145 		  opc->v[4].i_7pii_f = (int_case) ? int_vector_ref_i_7pii : byte_vector_ref_i_7pii;
61146 		  opc->v[3].p = slot;
61147 		  opc->v[0].fi = opt_i_7pii_sss;
61148 		  return(true);
61149 		}
61150 	      return_false(sc, car_x);
61151 	    }
61152 
61153 	  opc->v[10].o1 = sc->opts[sc->pc];
61154 	  if (int_optimize(sc, cdr(car_x)))
61155 	    {
61156 	      opc->v[8].o1 = sc->opts[sc->pc];
61157 	      if (int_optimize(sc, cddr(car_x)))
61158 		{
61159 		  opc->v[3].i_7pii_f = (int_case) ? int_vector_ref_i_7pii : byte_vector_ref_i_7pii;
61160 		  opc->v[0].fi = opt_i_7pii_sff;
61161 		  opc->v[11].fi = opc->v[10].o1->v[0].fi;
61162 		  opc->v[9].fi = opc->v[8].o1->v[0].fi;
61163 		  return(true);
61164 		}}}}
61165   return_false(sc, car_x);
61166 }
61167 
61168 
61169 /* ------------------------------------- float opts ------------------------------------------- */
61170 
61171 static s7_double opt_d_c(opt_info *o) {return(o->v[1].x);}
61172 static s7_double opt_d_s(opt_info *o) {return(real(slot_value(o->v[1].p)));}
61173 
61174 static s7_double opt_D_s(opt_info *o)
61175 {
61176   s7_pointer x;
61177   x = slot_value(o->v[1].p);
61178   return((is_t_integer(x)) ? (s7_double)(integer(x)) : s7_number_to_real(opt_sc(o), x));
61179 }
61180 
61181 static bool opt_float_not_pair(s7_scheme *sc, s7_pointer car_x)
61182 {
61183   opt_info *opc;
61184   s7_pointer p;
61185   if (is_small_real(car_x))
61186     {
61187       if ((s7_is_ratio(car_x)) ||
61188 	  (!is_small_real(car_x)))
61189 	return_false(sc, car_x);
61190       opc = alloc_opo(sc);
61191       opc->v[1].x = s7_number_to_real(sc, car_x);
61192       opc->v[0].fd = opt_d_c;
61193       return(true);
61194     }
61195   p = opt_real_symbol(sc, car_x);
61196   if (p)
61197     {
61198       if (s7_is_ratio(slot_value(p)))
61199 	return_false(sc, car_x);
61200       opc = alloc_opo(sc);
61201       opc->v[1].p = p;
61202       opc->v[0].fd = (is_t_real(slot_value(p))) ? opt_d_s : opt_D_s;
61203       return(true);
61204     }
61205   return_false(sc, car_x);
61206 }
61207 
61208 /* -------- d -------- */
61209 static s7_double opt_d_f(opt_info *o) {return(o->v[1].d_f());}
61210 
61211 static bool d_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func)
61212 {
61213   s7_d_t func;                   /* (f): (mus-srate) */
61214   func = s7_d_function(s_func);
61215   if (func)
61216     {
61217       opc->v[0].fd = opt_d_f;
61218       opc->v[1].d_f = func;
61219       return(true);
61220     }
61221   return_false(sc, NULL);
61222 }
61223 
61224 /* -------- d_d -------- */
61225 static s7_double opt_d_d_c(opt_info *o)  {return(o->v[3].d_d_f(o->v[1].x));}
61226 static s7_double opt_d_d_s(opt_info *o)  {return(o->v[3].d_d_f(real(slot_value(o->v[1].p))));}
61227 static s7_double opt_d_d_s_abs(opt_info *o) {return(abs_d_d(real(slot_value(o->v[1].p))));}
61228 static s7_double opt_d_7d_c(opt_info *o) {return(o->v[3].d_7d_f(opt_sc(o), o->v[1].x));}
61229 static s7_double opt_d_7d_s(opt_info *o) {return(o->v[3].d_7d_f(opt_sc(o), real(slot_value(o->v[1].p))));}
61230 static s7_double opt_d_d_f(opt_info *o)  {return(o->v[3].d_d_f(o->v[5].fd(o->v[4].o1)));}
61231 static s7_double opt_d_d_f_abs(opt_info *o) {return(abs_d_d(o->v[5].fd(o->v[4].o1)));}
61232 static s7_double opt_d_7d_f(opt_info *o) {return(o->v[3].d_7d_f(opt_sc(o), o->v[5].fd(o->v[4].o1)));}
61233 
61234 static bool d_d_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
61235 {
61236   s7_d_d_t func;
61237   s7_d_7d_t func7 = NULL;
61238   int32_t start;
61239   start = sc->pc;
61240 
61241   func = s7_d_d_function(s_func);
61242   if (!func) func7 = s7_d_7d_function(s_func);
61243   if ((func) || (func7))
61244     {
61245       s7_pointer p;
61246       if (func)
61247 	opc->v[3].d_d_f = func;
61248       else opc->v[3].d_7d_f = func7;
61249       if (is_small_real(cadr(car_x)))
61250 	{
61251 	  if ((!is_t_real(cadr(car_x))) &&                          /* (random 1) != (random 1.0) */
61252 	      ((car(car_x) == sc->random_symbol) ||
61253 	       (car(car_x) == sc->sin_symbol) ||
61254 	       (car(car_x) == sc->cos_symbol)))
61255 	    return_false(sc, car_x);
61256 	  opc->v[1].x = s7_number_to_real(sc, cadr(car_x));
61257 	  opc->v[0].fd = (func) ? opt_d_d_c : opt_d_7d_c;
61258 	  return(true);
61259 	}
61260       p = opt_float_symbol(sc, cadr(car_x));
61261       if ((p) &&
61262 	  (!has_methods(slot_value(p))))
61263 	{
61264 	  opc->v[1].p = p;
61265 	  opc->v[0].fd = (func) ? ((func == abs_d_d) ? opt_d_d_s_abs : opt_d_d_s) : opt_d_7d_s;
61266 	  return(true);
61267 	}
61268       opc->v[4].o1 = sc->opts[sc->pc];
61269       if (float_optimize(sc, cdr(car_x)))
61270 	{
61271 	  opc->v[0].fd = (func) ? ((func == abs_d_d) ? opt_d_d_f_abs : opt_d_d_f) : opt_d_7d_f;
61272 	  opc->v[5].fd = opc->v[4].o1->v[0].fd;
61273 	  return(true);
61274 	}
61275       pc_fallback(sc, start);
61276     }
61277   return_false(sc, car_x);
61278 }
61279 
61280 /* -------- d_v -------- */
61281 static s7_double opt_d_v(opt_info *o) {return(o->v[3].d_v_f(o->v[5].obj));}
61282 
61283 static bool d_v_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
61284 {
61285   s7_d_v_t flt_func;
61286   flt_func = s7_d_v_function(s_func);
61287   if (flt_func)
61288     {
61289       s7_pointer sig;
61290       sig = c_function_signature(s_func);
61291       if ((is_pair(sig)) &&
61292 	  (is_symbol(cadr(sig))) &&
61293 	  (is_symbol(cadr(car_x))))           /* look for (oscil g) */
61294 	{
61295 	  s7_pointer slot;
61296 	  slot = opt_types_match(sc, cadr(sig), cadr(car_x));
61297 	  if (slot)
61298 	    {
61299 	      opc->v[1].p = slot;
61300 	      opc->v[5].obj = (void *)c_object_value(slot_value(slot));
61301 	      opc->v[3].d_v_f = flt_func;
61302 	      opc->v[0].fd = opt_d_v;
61303 	      return(true);
61304 	    }}}
61305   return_false(sc, car_x);
61306 }
61307 
61308 /* -------- d_p -------- */
61309 static s7_double opt_d_p_s(opt_info *o) {return(o->v[3].d_p_f(slot_value(o->v[1].p)));}
61310 static s7_double opt_d_p_f(opt_info *o) {return(o->v[3].d_p_f(o->v[5].fp(o->v[4].o1)));}
61311 
61312 static bool d_p_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
61313 {
61314   s7_d_p_t dpf;
61315   int32_t start;
61316   start = sc->pc;
61317   dpf = s7_d_p_function(s_func);
61318   if (dpf)
61319     {
61320       opc->v[3].d_p_f = dpf;
61321       if (is_symbol(cadr(car_x)))
61322 	{
61323 	  s7_pointer slot;
61324 	  slot = opt_simple_symbol(sc, cadr(car_x));
61325 	  if (slot)
61326 	    {
61327 	      opc->v[1].p = slot;
61328 	      opc->v[0].fd = opt_d_p_s;
61329 	      return(true);
61330 	    }
61331 	  return_false(sc, car_x);
61332 	}
61333       opc->v[4].o1 = sc->opts[sc->pc];
61334       if (cell_optimize(sc, cdr(car_x)))
61335 	{
61336 	  opc->v[0].fd = opt_d_p_f;
61337 	  opc->v[5].fp = opc->v[4].o1->v[0].fp;
61338 	  return(true);
61339 	}
61340       pc_fallback(sc, start);
61341     }
61342   return_false(sc, car_x);
61343 }
61344 
61345 /* -------- d_7pi -------- */
61346 
61347 static s7_double opt_d_7pi_sc(opt_info *o) {return(o->v[3].d_7pi_f(opt_sc(o), slot_value(o->v[1].p), o->v[2].i));}
61348 static s7_double opt_d_7pi_ss(opt_info *o) {return(o->v[3].d_7pi_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p))));}
61349 static s7_double opt_d_7pi_sf(opt_info *o) {return(o->v[3].d_7pi_f(opt_sc(o), slot_value(o->v[1].p), o->v[11].fi(o->v[10].o1)));}
61350 
61351 static s7_double opt_d_7pi_ff(opt_info *o)
61352 {
61353   s7_pointer seq;
61354   seq = o->v[5].fp(o->v[4].o1);
61355   return(o->v[3].d_7pi_f(opt_sc(o), seq, o->v[9].fi(o->v[8].o1)));
61356 }
61357 
61358 static bool d_7pi_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
61359 {
61360   /* float-vector-ref is checked for a 1D float-vector arg, but other callers should do type checking */
61361   s7_d_7pi_t ifunc;
61362   ifunc = s7_d_7pi_function(s_func);
61363   if (ifunc)
61364     {
61365       int32_t start;
61366       start = sc->pc;
61367       opc->v[3].d_7pi_f = ifunc;
61368       if (is_symbol(cadr(car_x)))  /* (float-vector-ref v i) */
61369 	{
61370 	  s7_pointer arg2, p, obj;
61371 	  opc->v[1].p = lookup_slot_from(cadr(car_x), sc->curlet);
61372 	  if (!is_slot(opc->v[1].p))
61373 	    return_false(sc, car_x);
61374 
61375 	  obj = slot_value(opc->v[1].p);
61376 	  if ((car(car_x) == sc->float_vector_ref_symbol) &&
61377 	      ((!is_float_vector(obj)) ||
61378 	       (vector_rank(obj) > 1)))
61379 	    return_false(sc, car_x);
61380 
61381 	  arg2 = caddr(car_x);
61382 	  if (!is_pair(arg2))
61383 	    {
61384 	      if (is_t_integer(arg2))
61385 		{
61386 		  opc->v[2].i = integer(arg2);
61387 		  opc->v[0].fd = opt_d_7pi_sc;
61388 		  return(true);
61389 		}
61390 	      p = opt_integer_symbol(sc, arg2);
61391 	      if (p)
61392 		{
61393 		  opc->v[2].p = p;
61394 		  opc->v[0].fd = opt_d_7pi_ss;
61395 		  if ((car(car_x) == sc->float_vector_ref_symbol) &&
61396 		      (is_step_end(opc->v[2].p)) &&
61397 		      (denominator(slot_value(opc->v[2].p)) <= vector_length(slot_value(opc->v[1].p))))
61398 		    {
61399 		      opc->v[3].d_7pi_f = float_vector_ref_unchecked;
61400 		      return(true);
61401 		    }
61402 		  return(true);
61403 		}
61404 	      return_false(sc, car_x);
61405 	    }
61406 	  if (int_optimize(sc, cddr(car_x)))
61407 	    {
61408 	      opc->v[0].fd = opt_d_7pi_sf;
61409 	      opc->v[10].o1 = sc->opts[start];
61410 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
61411 	      return(true);
61412 	    }
61413 	  pc_fallback(sc, start);
61414 	  return_false(sc, car_x);
61415 	}
61416 
61417       if ((car(car_x) == sc->float_vector_ref_symbol) &&
61418 	  ((!is_float_vector(cadr(car_x))) ||
61419 	   (vector_rank(cadr(car_x)) > 1)))          /* (float-vector-ref #r2d((.1 .2) (.3 .4)) 3) */
61420 	return_false(sc, car_x);
61421 
61422       if (cell_optimize(sc, cdr(car_x)))
61423 	{
61424 	  opt_info *o2;
61425 	  o2 = sc->opts[sc->pc];
61426 	  if (int_optimize(sc, cddr(car_x)))
61427 	    {
61428 	      opc->v[0].fd = opt_d_7pi_ff;
61429 	      opc->v[4].o1 = sc->opts[start];
61430 	      opc->v[5].fp = sc->opts[start]->v[0].fp;
61431 	      opc->v[8].o1 = o2;
61432 	      opc->v[9].fi = o2->v[0].fi;
61433 	      return(true);
61434 	    }}
61435       pc_fallback(sc, start);
61436     }
61437   return_false(sc, car_x);
61438 }
61439 
61440 /* -------- d_ip -------- */
61441 static s7_double opt_d_ip_ss(opt_info *o) {return(o->v[3].d_ip_f(integer(slot_value(o->v[1].p)), slot_value(o->v[2].p)));}
61442 
61443 static bool d_ip_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
61444 {
61445   s7_d_ip_t pfunc;
61446   pfunc = s7_d_ip_function(s_func);
61447   if ((pfunc) &&
61448       (is_symbol(caddr(car_x))))
61449     {
61450       s7_pointer p;
61451       p = opt_integer_symbol(sc, cadr(car_x));
61452       if (p)
61453 	{
61454 	  opc->v[3].d_ip_f = pfunc;
61455 	  opc->v[1].p = p;
61456 	  opc->v[2].p = lookup_slot_from(caddr(car_x), sc->curlet);
61457 	  if (is_slot(opc->v[2].p))    /* (with-sound (:reverb jc-reverb) (fm-violin 0 .1 440 .4 :reverb-amount .5)) */
61458 	    {
61459 	      opc->v[0].fd = opt_d_ip_ss;
61460 	      return(true);
61461 	    }}}
61462   return_false(sc, car_x);
61463 }
61464 
61465 /* -------- d_pd -------- */
61466 static s7_double opt_d_pd_sf(opt_info *o) {return(o->v[3].d_pd_f(slot_value(o->v[1].p), o->v[11].fd(o->v[10].o1)));}
61467 static s7_double opt_d_pd_ss(opt_info *o) {return(o->v[3].d_pd_f(slot_value(o->v[1].p), real(slot_value(o->v[2].p))));}
61468 
61469 static bool d_pd_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
61470 {
61471   if (is_symbol(cadr(car_x)))
61472     {
61473       s7_d_pd_t func;
61474       func = s7_d_pd_function(s_func);
61475       if (func)
61476 	{
61477 	  s7_pointer arg2, p;
61478 	  int32_t start;
61479 	  start = sc->pc;
61480 	  arg2 = caddr(car_x);
61481 	  opc->v[3].d_pd_f = func;
61482 	  opc->v[1].p = lookup_slot_from(cadr(car_x), sc->curlet);
61483 	  if (!is_slot(opc->v[1].p))
61484 	    return_false(sc, car_x);
61485 	  p = opt_float_symbol(sc, arg2);
61486 	  if (p)
61487 	    {
61488 	      opc->v[2].p = p;
61489 	      opc->v[0].fd = opt_d_pd_ss;
61490 	      return(true);
61491 	    }
61492 	  opc->v[10].o1 = sc->opts[sc->pc];
61493 	  if (float_optimize(sc, cddr(car_x)))
61494 	    {
61495 	      opc->v[0].fd = opt_d_pd_sf;
61496 	      opc->v[11].fd = opc->v[10].o1->v[0].fd;
61497 	      return(true);
61498 	    }
61499 	  pc_fallback(sc, start);
61500 	}}
61501   return_false(sc, car_x);
61502 }
61503 
61504 /* -------- d_vd -------- */
61505 static s7_double opt_d_vd_c(opt_info *o) {return(o->v[3].d_vd_f(o->v[5].obj, o->v[2].x));}
61506 static s7_double opt_d_vd_s(opt_info *o) {return(o->v[3].d_vd_f(o->v[5].obj, real(slot_value(o->v[2].p))));}
61507 static s7_double opt_d_vd_f(opt_info *o) {return(o->v[3].d_vd_f(o->v[5].obj, o->v[9].fd(o->v[8].o1)));}
61508 static s7_double opt_d_vd_o(opt_info *o) {return(o->v[3].d_vd_f(o->v[5].obj, o->v[4].d_v_f(o->v[6].obj)));}
61509 static s7_double opt_d_vd_o1_mul(opt_info *o) {return(o->v[3].d_vd_f(o->v[5].obj, real(slot_value(o->v[2].p)) * o->v[11].fd(o->v[10].o1)));}
61510 static s7_double opt_d_vd_o1(opt_info *o) {return(o->v[3].d_vd_f(o->v[5].obj, o->v[4].d_dd_f(real(slot_value(o->v[2].p)), o->v[11].fd(o->v[10].o1))));}
61511 static s7_double opt_d_vd_o2(opt_info *o) {return(o->v[4].d_vd_f(o->v[6].obj, o->v[5].d_vd_f(o->v[2].obj, real(slot_value(o->v[3].p)))));}
61512 static s7_double opt_d_vd_o3(opt_info *o) {return(o->v[3].d_vd_f(o->v[5].obj, o->v[4].d_dd_f(o->v[6].x, real(slot_value(o->v[2].p)))));}
61513 static s7_double opt_d_vd_ff(opt_info *o) {return(o->v[3].d_vd_f(o->v[5].obj, o->v[2].d_vd_f(o->v[4].obj, o->v[11].fd(o->v[10].o1))));}
61514 
61515 static s7_double opt_d_dd_cs(opt_info *o);
61516 static s7_double opt_d_dd_sf_mul(opt_info *o);
61517 static s7_double opt_d_dd_sf_add(opt_info *o);
61518 static s7_double opt_d_dd_sf(opt_info *o);
61519 
61520 static bool d_vd_f_combinable(s7_scheme *sc, int32_t start)
61521 {
61522   opt_info *opc, *o1;
61523   opc = sc->opts[start - 1];
61524   o1 = sc->opts[start];
61525   if (o1->v[0].fd == opt_d_v)
61526     {
61527       opc->v[2].p = o1->v[1].p;
61528       opc->v[6].obj = o1->v[5].obj;
61529       opc->v[4].d_v_f = o1->v[3].d_v_f;
61530       opc->v[0].fd = opt_d_vd_o;
61531       backup_pc(sc);
61532       return(true);
61533     }
61534   if (o1->v[0].fd == opt_d_vd_s)
61535     {
61536       opc->v[6].obj = opc->v[5].obj;
61537       opc->v[4].d_vd_f = opc->v[3].d_vd_f; /* room for symbols */
61538       opc->v[2].obj = o1->v[5].obj;
61539       opc->v[5].d_vd_f = o1->v[3].d_vd_f;
61540       opc->v[3].p = o1->v[2].p;
61541       opc->v[7].p = o1->v[1].p;
61542       opc->v[0].fd = opt_d_vd_o2;
61543       backup_pc(sc);
61544       return(true);
61545     }
61546   if (o1->v[0].fd == opt_d_dd_cs)
61547     {
61548       opc->v[4].d_dd_f = o1->v[3].d_dd_f;
61549       opc->v[6].x = o1->v[2].x;
61550       opc->v[2].p = o1->v[1].p;
61551       opc->v[0].fd = opt_d_vd_o3;
61552       backup_pc(sc);
61553       return(true);
61554     }
61555   if ((o1->v[0].fd == opt_d_dd_sf_mul) || (o1->v[0].fd == opt_d_dd_sf) || (o1->v[0].fd == opt_d_dd_sf_add))
61556     {
61557       opc->v[2].p = o1->v[1].p;
61558       opc->v[4].d_dd_f = o1->v[3].d_dd_f;
61559       opc->v[0].fd = (o1->v[0].fd == opt_d_dd_sf_mul) ? opt_d_vd_o1_mul : opt_d_vd_o1;
61560       opc->v[11].fd = o1->v[5].fd;
61561       opc->v[10].o1 = o1->v[4].o1;
61562       return(true);
61563     }
61564   if (o1->v[0].fd == opt_d_vd_f)
61565     {
61566       opc->v[2].d_vd_f = o1->v[3].d_vd_f;
61567       opc->v[4].obj = o1->v[5].obj;
61568       opc->v[6].p = o1->v[1].p;
61569       opc->v[0].fd = opt_d_vd_ff;
61570       opc->v[11].fd = o1->v[9].fd;
61571       opc->v[10].o1 = o1->v[8].o1;
61572       return(true);
61573     }
61574   return_false(sc, NULL);
61575 }
61576 
61577 static bool d_vd_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
61578 {
61579   if (is_symbol(cadr(car_x)))
61580     {
61581       s7_d_vd_t vfunc;
61582       vfunc = s7_d_vd_function(s_func);
61583       if (vfunc)
61584 	{
61585 	  s7_pointer sig;
61586 	  sig = c_function_signature(s_func);
61587 	  if ((is_pair(sig)) &&
61588 	      (is_symbol(cadr(sig))))
61589 	    {
61590 	      s7_pointer slot;
61591 	      slot = opt_types_match(sc, cadr(sig), cadr(car_x));
61592 	      if (slot)
61593 		{
61594 		  s7_pointer arg2;
61595 		  int32_t start;
61596 		  start = sc->pc;
61597 		  arg2 = caddr(car_x);
61598 		  opc->v[3].d_vd_f = vfunc;
61599 		  if (!is_pair(arg2))
61600 		    {
61601 		      opc->v[1].p = slot;
61602 		      opc->v[5].obj = (void *)c_object_value(slot_value(slot));
61603 		      if (is_small_real(arg2))
61604 			{
61605 			  opc->v[2].x = s7_number_to_real(sc, arg2);
61606 			  opc->v[0].fd = opt_d_vd_c;
61607 			  return(true);
61608 			}
61609 		      opc->v[2].p = lookup_slot_from(arg2, sc->curlet);
61610 		      if (is_slot(opc->v[2].p))
61611 			{
61612 			  if (is_t_real(slot_value(opc->v[2].p)))
61613 			    {
61614 			      opc->v[0].fd = opt_d_vd_s;
61615 			      return(true);
61616 			    }
61617 			  if (float_optimize(sc, cddr(car_x)))
61618 			    {
61619 			      if (d_vd_f_combinable(sc, start))
61620 				return(true);
61621 			      opc->v[0].fd = opt_d_vd_f;
61622 			      opc->v[8].o1 = sc->opts[start];
61623 			      opc->v[9].fd = sc->opts[start]->v[0].fd;
61624 			      return(true);
61625 			    }
61626 			  return_false(sc, car_x);
61627 			}}
61628 		  else /* is pair arg2 */
61629 		    {
61630 		      if (float_optimize(sc, cddr(car_x)))
61631 			{
61632 			  opc->v[1].p = slot;
61633 			  opc->v[5].obj = (void *)c_object_value(slot_value(slot));
61634 			  if (d_vd_f_combinable(sc, start))
61635 			    return(true);
61636 			  opc->v[0].fd = opt_d_vd_f;
61637 			  opc->v[8].o1 = sc->opts[start];
61638 			  opc->v[9].fd = sc->opts[start]->v[0].fd;
61639 			  return(true);
61640 			}
61641 		      pc_fallback(sc, start);
61642 		    }}}}}
61643   return_false(sc, car_x);
61644 }
61645 
61646 /* -------- d_id -------- */
61647 static s7_double opt_d_id_sf(opt_info *o)   {return(o->v[3].d_id_f(integer(slot_value(o->v[1].p)), o->v[5].fd(o->v[4].o1)));}
61648 static s7_double opt_d_id_sc(opt_info *o)   {return(o->v[3].d_id_f(integer(slot_value(o->v[1].p)), o->v[2].x));}
61649 static s7_double opt_d_id_sfo1(opt_info *o) {return(o->v[3].d_id_f(integer(slot_value(o->v[1].p)), o->v[5].d_v_f(o->v[2].obj)));}
61650 static s7_double opt_d_id_sfo(opt_info *o)  {return(o->v[4].d_id_f(integer(slot_value(o->v[1].p)), o->v[5].d_vd_f(o->v[6].obj, real(slot_value(o->v[3].p)))));}
61651 
61652 static bool d_id_sf_combinable(s7_scheme *sc, opt_info *opc)
61653 {
61654   if ((sc->pc > 1) &&
61655       (opc == sc->opts[sc->pc - 2]))
61656     {
61657       opt_info *o1;
61658       o1 = sc->opts[sc->pc - 1];
61659       if (o1->v[0].fd == opt_d_vd_s)
61660 	{
61661 	  opc->v[4].d_id_f = opc->v[3].d_id_f;
61662 	  opc->v[2].p = o1->v[1].p;
61663 	  opc->v[6].obj = o1->v[5].obj;
61664 	  opc->v[5].d_vd_f = o1->v[3].d_vd_f;
61665 	  opc->v[3].p = o1->v[2].p;
61666 	  opc->v[0].fd = opt_d_id_sfo;
61667 	  backup_pc(sc);
61668 	  return(true);
61669 	}
61670       if (o1->v[0].fd == opt_d_v)
61671 	{
61672 	  opc->v[6].p = o1->v[1].p;
61673 	  opc->v[2].obj = o1->v[5].obj;
61674 	  opc->v[5].d_v_f = o1->v[3].d_v_f;
61675 	  opc->v[0].fd = opt_d_id_sfo1;
61676 	  backup_pc(sc);
61677 	  return(true);
61678 	}}
61679   return_false(sc, NULL);
61680 }
61681 
61682 static bool d_id_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
61683 {
61684   s7_d_id_t flt_func;
61685   flt_func = s7_d_id_function(s_func);
61686   if (flt_func)
61687     {
61688       s7_pointer p;
61689       p = opt_integer_symbol(sc, cadr(car_x));
61690       if (p)
61691 	{
61692 	  int32_t start;
61693 	  start = sc->pc;
61694 	  opc->v[3].d_id_f = flt_func;
61695 	  opc->v[1].p = p;
61696 	  if (is_t_real(caddr(car_x)))
61697 	    {
61698 	      opc->v[0].fd = opt_d_id_sc;
61699 	      opc->v[2].x = real(caddr(car_x));
61700 	      return(true);
61701 	    }
61702 	  if (float_optimize(sc, cddr(car_x)))
61703 	    {
61704 	      if (d_id_sf_combinable(sc, opc))
61705 		return(true);
61706 	      opc->v[0].fd = opt_d_id_sf;
61707 	      opc->v[4].o1 = sc->opts[start];
61708 	      opc->v[5].fd = sc->opts[start]->v[0].fd;
61709 	      return(true);
61710 	    }
61711 	  pc_fallback(sc, start);
61712 	}}
61713   return_false(sc, car_x);
61714 }
61715 
61716 /* -------- d_dd -------- */
61717 
61718 static s7_double opt_d_dd_cc(opt_info *o)     {return(o->v[3].d_dd_f(o->v[1].x, o->v[2].x));}
61719 static s7_double opt_d_dd_cs(opt_info *o)     {return(o->v[3].d_dd_f(o->v[2].x, real(slot_value(o->v[1].p))));}
61720 static s7_double opt_d_dd_sc(opt_info *o)     {return(o->v[3].d_dd_f(real(slot_value(o->v[1].p)), o->v[2].x));}
61721 static s7_double opt_d_dd_sc_sub(opt_info *o) {return(real(slot_value(o->v[1].p)) - o->v[2].x);}
61722 static s7_double opt_d_dd_ss(opt_info *o)     {return(o->v[3].d_dd_f(real(slot_value(o->v[1].p)), real(slot_value(o->v[2].p))));}
61723 static s7_double opt_d_dd_ss_add(opt_info *o) {return(real(slot_value(o->v[1].p)) + real(slot_value(o->v[2].p)));}
61724 static s7_double opt_d_dd_ss_mul(opt_info *o) {return(real(slot_value(o->v[1].p)) * real(slot_value(o->v[2].p)));}
61725 
61726 static s7_double opt_d_dd_cf(opt_info *o) {return(o->v[3].d_dd_f(o->v[1].x, o->v[5].fd(o->v[4].o1)));}
61727 static s7_double opt_d_dd_1f_subtract(opt_info *o) {return(1.0 - o->v[5].fd(o->v[4].o1));}
61728 static s7_double opt_d_dd_fc(opt_info *o) {return(o->v[3].d_dd_f(o->v[5].fd(o->v[4].o1), o->v[2].x));}
61729 
61730 #if WITH_GMP
61731 static s7_double opt_subtract_random_f_f(opt_info *o) {return(o->v[1].x * next_random(opt_sc(o)) - o->v[2].x);}
61732 #else
61733 static s7_double opt_subtract_random_f_f(opt_info *o) {return(o->v[1].x * next_random(opt_sc(o)->default_rng) - o->v[2].x);}
61734 #endif
61735 
61736 static s7_double opt_d_dd_fc_add(opt_info *o) {return(o->v[5].fd(o->v[4].o1) + o->v[2].x);}
61737 static s7_double opt_d_dd_fc_subtract(opt_info *o) {return(o->v[5].fd(o->v[4].o1) - o->v[2].x);}
61738 static s7_double opt_d_dd_sf(opt_info *o) {return(o->v[3].d_dd_f(real(slot_value(o->v[1].p)), o->v[5].fd(o->v[4].o1)));}
61739 static s7_double opt_d_dd_sf_mul(opt_info *o) {return(real(slot_value(o->v[1].p)) * o->v[5].fd(o->v[4].o1));}
61740 static s7_double opt_d_dd_sf_add(opt_info *o) {return(real(slot_value(o->v[1].p)) + o->v[5].fd(o->v[4].o1));}
61741 static s7_double opt_d_dd_sf_sub(opt_info *o) {return(real(slot_value(o->v[1].p)) - o->v[5].fd(o->v[4].o1));}
61742 
61743 static s7_double opt_d_7dd_cc(opt_info *o) {return(o->v[3].d_7dd_f(opt_sc(o), o->v[1].x, o->v[2].x));}
61744 static s7_double opt_d_7dd_cs(opt_info *o) {return(o->v[3].d_7dd_f(opt_sc(o), o->v[2].x, real(slot_value(o->v[1].p))));}
61745 static s7_double opt_d_7dd_sc(opt_info *o) {return(o->v[3].d_7dd_f(opt_sc(o), real(slot_value(o->v[1].p)), o->v[2].x));}
61746 static s7_double opt_d_7dd_ss(opt_info *o) {return(o->v[3].d_7dd_f(opt_sc(o), real(slot_value(o->v[1].p)), real(slot_value(o->v[2].p))));}
61747 static s7_double opt_d_7dd_cf(opt_info *o) {return(o->v[3].d_7dd_f(opt_sc(o), o->v[1].x, o->v[5].fd(o->v[4].o1)));}
61748 static s7_double opt_d_7dd_fc(opt_info *o) {return(o->v[3].d_7dd_f(opt_sc(o), o->v[5].fd(o->v[4].o1), o->v[2].x));}
61749 static s7_double opt_d_7dd_sf(opt_info *o) {return(o->v[3].d_7dd_f(opt_sc(o), real(slot_value(o->v[1].p)), o->v[5].fd(o->v[4].o1)));}
61750 
61751 static s7_double opt_d_dd_sfo(opt_info *o)
61752 {
61753   return(o->v[4].d_dd_f(real(slot_value(o->v[1].p)), o->v[5].d_7pi_f(opt_sc(o), slot_value(o->v[2].p), integer(slot_value(o->v[3].p)))));
61754 }
61755 
61756 static s7_double opt_d_7dd_sfo(opt_info *o)
61757 {
61758   return(o->v[4].d_7dd_f(opt_sc(o), real(slot_value(o->v[1].p)), o->v[5].d_7pi_f(opt_sc(o), slot_value(o->v[2].p), integer(slot_value(o->v[3].p)))));
61759 }
61760 
61761 static bool d_dd_sf_combinable(s7_scheme *sc, opt_info *opc, s7_d_dd_t func)
61762 {
61763   if ((sc->pc > 1) &&
61764       (opc == sc->opts[sc->pc - 2]))
61765     {
61766       opt_info *o1;
61767       o1 = sc->opts[sc->pc - 1];
61768       if (o1->v[0].fd == opt_d_7pi_ss)
61769 	{
61770 	  if (func)
61771 	    {
61772 	      opc->v[4].d_dd_f = opc->v[3].d_dd_f; /* need room for 3 symbols */
61773 	      opc->v[0].fd = opt_d_dd_sfo;
61774 	    }
61775 	  else
61776 	    {
61777 	      opc->v[4].d_7dd_f = opc->v[3].d_7dd_f; /* need room for 3 symbols */
61778 	      opc->v[0].fd = opt_d_7dd_sfo;
61779 	    }
61780 	  opc->v[2].p = o1->v[1].p;
61781 	  opc->v[3].p = o1->v[2].p;
61782 	  opc->v[5].d_7pi_f = o1->v[3].d_7pi_f;
61783 	  backup_pc(sc);
61784 	  return(true);
61785 	}}
61786   return_false(sc, NULL);
61787 }
61788 
61789 static s7_double opt_d_dd_fs(opt_info *o) {return(o->v[3].d_dd_f(o->v[5].fd(o->v[4].o1), real(slot_value(o->v[1].p))));}
61790 static s7_double opt_d_dd_fs_mul(opt_info *o) {return(o->v[5].fd(o->v[4].o1) * real(slot_value(o->v[1].p)));}
61791 static s7_double opt_d_dd_fs_add(opt_info *o) {return(o->v[5].fd(o->v[4].o1) + real(slot_value(o->v[1].p)));}
61792 static s7_double opt_d_dd_fs_sub(opt_info *o) {return(o->v[5].fd(o->v[4].o1) - real(slot_value(o->v[1].p)));}
61793 static s7_double opt_d_7dd_fs(opt_info *o) {return(o->v[3].d_7dd_f(opt_sc(o), o->v[5].fd(o->v[4].o1), real(slot_value(o->v[1].p))));}
61794 
61795 static s7_double opt_d_dd_fso(opt_info *o)
61796 {
61797   return(o->v[4].d_dd_f(o->v[5].d_7pi_f(opt_sc(o), slot_value(o->v[2].p), integer(slot_value(o->v[3].p))), real(slot_value(o->v[1].p))));
61798 }
61799 
61800 static s7_double opt_d_7dd_fso(opt_info *o)
61801 {
61802   return(o->v[4].d_7dd_f(opt_sc(o), o->v[5].d_7pi_f(opt_sc(o), slot_value(o->v[2].p), integer(slot_value(o->v[3].p))), real(slot_value(o->v[1].p))));
61803 }
61804 
61805 static bool d_dd_fs_combinable(s7_scheme *sc, opt_info *opc, s7_d_dd_t func)
61806 {
61807   if ((sc->pc > 1) &&
61808       (opc == sc->opts[sc->pc - 2]))
61809     {
61810       opt_info *o1;
61811       o1 = sc->opts[sc->pc - 1];
61812       if (o1->v[0].fd == opt_d_7pi_ss)
61813 	{
61814 	  if (func)
61815 	    {
61816 	      opc->v[4].d_dd_f = opc->v[3].d_dd_f; /* need room for 3 symbols */
61817 	      opc->v[0].fd = opt_d_dd_fso;
61818 	    }
61819 	  else
61820 	    {
61821 	      opc->v[4].d_7dd_f = opc->v[3].d_7dd_f;
61822 	      opc->v[0].fd = opt_d_7dd_fso;
61823 	    }
61824 	  opc->v[2].p = o1->v[1].p;
61825 	  opc->v[3].p = o1->v[2].p;
61826 	  opc->v[5].d_7pi_f = o1->v[3].d_7pi_f;
61827 	  backup_pc(sc);
61828 	  return(true);
61829 	}}
61830   return_false(sc, NULL);
61831 }
61832 
61833 static s7_double opt_d_dd_ff(opt_info *o)
61834 {
61835   s7_double x1;
61836   x1 = o->v[9].fd(o->v[8].o1);
61837   return(o->v[3].d_dd_f(x1, o->v[11].fd(o->v[10].o1)));
61838 }
61839 
61840 static s7_double opt_d_dd_ff_mul(opt_info *o)
61841 {
61842   s7_double x1;
61843   x1 = o->v[9].fd(o->v[8].o1);
61844   return(x1 * o->v[11].fd(o->v[10].o1));
61845 }
61846 
61847 static s7_double opt_d_dd_ff_square(opt_info *o)
61848 {
61849   s7_double x1;
61850   x1 = o->v[9].fd(o->v[8].o1);
61851   return(x1 * x1);
61852 }
61853 
61854 static s7_double opt_d_dd_ff_add(opt_info *o)
61855 {
61856   s7_double x1;
61857   x1 = o->v[5].fd(o->v[4].o1);
61858   return(x1 + o->v[11].fd(o->v[10].o1));
61859 }
61860 
61861 static s7_double opt_d_dd_ff_add_mul(opt_info *o)
61862 {
61863   s7_double x1, x2;
61864   x1 = o->v[5].fd(o->v[4].o1);
61865   x2 = o->v[9].fd(o->v[8].o1);
61866   return(x1 + (x2 * o->v[11].fd(o->v[10].o1)));
61867 }
61868 
61869 static s7_double opt_d_dd_ff_add_fv_ref(opt_info *o)
61870 {
61871   s7_double x1;
61872   x1 = o->v[5].fd(o->v[4].o1);
61873   return(x1 + float_vector_ref_d_7pi(opt_sc(o), slot_value(o->v[6].p), o->v[9].fi(o->v[8].o1)));
61874 }
61875 
61876 static s7_double opt_d_dd_ff_sub(opt_info *o)
61877 {
61878   s7_double x1;
61879   x1 = o->v[5].fd(o->v[4].o1);
61880   return(x1 - o->v[11].fd(o->v[10].o1));
61881 }
61882 
61883 static s7_double opt_d_7dd_ff(opt_info *o)
61884 {
61885   s7_double x1;
61886   x1 = o->v[9].fd(o->v[8].o1);
61887   return(o->v[3].d_7dd_f(opt_sc(o), x1, o->v[11].fd(o->v[10].o1)));
61888 }
61889 
61890 static s7_double opt_d_dd_ff_o1(opt_info *o)
61891 {
61892   s7_double x1;
61893   x1 = o->v[2].d_v_f(o->v[1].obj);
61894   return(o->v[3].d_dd_f(x1, o->v[11].fd(o->v[10].o1)));
61895 }
61896 
61897 static s7_double opt_d_dd_ff_mul1(opt_info *o) {return(o->v[2].d_v_f(o->v[1].obj) * o->v[11].fd(o->v[10].o1));}
61898 
61899 static s7_double opt_d_dd_ff_o2(opt_info *o)
61900 {
61901   s7_double x1;
61902   x1 = o->v[4].d_v_f(o->v[1].obj);
61903   return(o->v[3].d_dd_f(x1, o->v[5].d_v_f(o->v[2].obj)));
61904 }
61905 
61906 static s7_double opt_d_dd_ff_mul2(opt_info *o) {return(o->v[4].d_v_f(o->v[1].obj) * o->v[5].d_v_f(o->v[2].obj));}
61907 
61908 static s7_double opt_d_dd_ff_o3(opt_info *o)
61909 {
61910   s7_double x1;
61911   x1 = o->v[5].d_v_f(o->v[1].obj);
61912   return(o->v[4].d_dd_f(x1, o->v[6].d_vd_f(o->v[2].obj, real(slot_value(o->v[3].p)))));
61913 }
61914 
61915 static s7_double opt_d_dd_fff(opt_info *o)
61916 {
61917   s7_double x1, x2;
61918   x1 = o->v[3+4].d_dd_f(o->v[3+5].d_7pi_f(opt_sc(o), slot_value(o->v[3+2].p), integer(slot_value(o->v[3+3].p))), real(slot_value(o->v[3+1].p))); /* dd_fso */
61919   x2 = o->v[8+4].d_dd_f(o->v[8+5].d_7pi_f(opt_sc(o), slot_value(o->v[8+2].p), integer(slot_value(o->v[8+3].p))), real(slot_value(o->v[8+1].p))); /* dd_fso */
61920   return(o->v[3].d_dd_f(x1, x2));
61921 }
61922 
61923 static s7_double opt_d_mm_fff(opt_info *o)
61924 {
61925   s7_double x1, x2;
61926   x1 = float_vector_ref_d_7pi(opt_sc(o), slot_value(o->v[3+2].p), integer(slot_value(o->v[3+3].p))) * real(slot_value(o->v[3+1].p));
61927   x2 = float_vector_ref_d_7pi(opt_sc(o), slot_value(o->v[8+2].p), integer(slot_value(o->v[8+3].p))) * real(slot_value(o->v[8+1].p));
61928   return(o->v[3].d_dd_f(x1, x2));
61929 }
61930 
61931 static s7_double opt_d_dd_fff_rev(opt_info *o) /* faster with opt_sc(o)? */
61932 {
61933   s7_double x1, x2;
61934   x1 = o->v[3+4].d_dd_f(real(slot_value(o->v[3+1].p)), o->v[3+5].d_7pi_f(opt_sc(o), slot_value(o->v[3+2].p), integer(slot_value(o->v[3+3].p))));
61935   x2 = o->v[8+4].d_dd_f(real(slot_value(o->v[8+1].p)), o->v[8+5].d_7pi_f(opt_sc(o), slot_value(o->v[8+2].p), integer(slot_value(o->v[8+3].p))));
61936   return(o->v[3].d_dd_f(x1, x2));
61937 }
61938 
61939 static s7_double opt_d_dd_ff_o4(opt_info *o)
61940 {
61941   s7_double x1;
61942   x1 = o->v[2].d_v_f(o->v[1].obj);
61943   return(o->v[3].d_dd_f(x1, o->v[7].d_vd_f(o->v[5].obj, o->v[4].d_v_f(o->v[6].obj))));
61944 }
61945 
61946 static s7_double opt_d_dd_ff_mul4(opt_info *o) {return(o->v[2].d_v_f(o->v[1].obj) * o->v[7].d_vd_f(o->v[5].obj, o->v[4].d_v_f(o->v[6].obj)));}
61947 
61948 static s7_double opt_d_7pii_sss(opt_info *o);
61949 static s7_double opt_d_dd_ff_mul_sss(opt_info *o)
61950 {
61951   s7_double x1;
61952   s7_int i1, i2;
61953   s7_pointer v;
61954   opt_info *o1;
61955   o1 = o->v[8].o1;
61956   v = slot_value(o1->v[1].p);
61957   i1 = integer(slot_value(o1->v[2].p));
61958   i2 = integer(slot_value(o1->v[3].p));
61959   x1 = float_vector_ref_d_7pii(opt_sc(o1), v, i1, i2);
61960   o1 = o->v[10].o1;
61961   v = slot_value(o1->v[1].p);
61962   i1 = integer(slot_value(o1->v[2].p));                /* in (* (A i j) (B j k)) we could reuse i2->i1 (flipping args below) */
61963   i2 = integer(slot_value(o1->v[3].p));
61964   return(x1 * float_vector_ref_d_7pii(opt_sc(o1), v, i1, i2));
61965 }
61966 
61967 static bool finish_dd_fso(opt_info *opc, opt_info *o1, opt_info *o2)
61968 {
61969   opc->v[3+1].p = o1->v[1].p;
61970   opc->v[3+2].p = o1->v[2].p;
61971   opc->v[3+3].p = o1->v[3].p;
61972   opc->v[3+4].d_dd_f = o1->v[4].d_dd_f;
61973   opc->v[3+5].d_7pi_f = o1->v[5].d_7pi_f;
61974   opc->v[8+1].p = o2->v[1].p;
61975   opc->v[8+2].p = o2->v[2].p;
61976   opc->v[8+3].p = o2->v[3].p;
61977   opc->v[8+4].d_dd_f = o2->v[4].d_dd_f;
61978   opc->v[8+5].d_7pi_f = o2->v[5].d_7pi_f;
61979   return(true);
61980 }
61981 
61982 static bool d_dd_ff_combinable(s7_scheme *sc, opt_info *opc, int32_t start)
61983 {
61984   opt_info *o1, *o2;
61985   o1 = opc->v[8].o1;
61986   o2 = opc->v[10].o1;
61987   if (o1->v[0].fd == opt_d_v)
61988     {
61989       /* opc->v[3] is in use */
61990       if ((o2->v[0].fd == opt_d_v) &&
61991 	  (sc->pc == start + 2))
61992 	{
61993 	  opc->v[1].obj = o1->v[5].obj;
61994 	  opc->v[6].p = o1->v[1].p;
61995 	  opc->v[4].d_v_f = o1->v[3].d_v_f;
61996 	  opc->v[2].obj = o2->v[5].obj;
61997 	  opc->v[7].p = o2->v[1].p;
61998 	  opc->v[5].d_v_f = o2->v[3].d_v_f;
61999 	  opc->v[0].fd = (opc->v[3].d_dd_f == multiply_d_dd) ? opt_d_dd_ff_mul2 : opt_d_dd_ff_o2;
62000 	  sc->pc -= 2;
62001 	  return(true);
62002 	}
62003       if ((o2->v[0].fd == opt_d_vd_s) &&
62004 	  (sc->pc == start + 2))
62005 	{
62006 	  opc->v[4].d_dd_f = opc->v[3].d_dd_f; /* make room for symbols */
62007 	  opc->v[1].obj = o1->v[5].obj;
62008 	  opc->v[7].p = o1->v[1].p;
62009 	  opc->v[5].d_v_f = o1->v[3].d_v_f;
62010 	  opc->v[2].obj = o2->v[5].obj;
62011 	  opc->v[8].p = o2->v[1].p;
62012 	  opc->v[6].d_vd_f = o2->v[3].d_vd_f;
62013 	  opc->v[3].p = o2->v[2].p;
62014 	  opc->v[0].fd = opt_d_dd_ff_o3;
62015 	  sc->pc -= 2;
62016 	  return(true);
62017 	}
62018       if ((o2->v[0].fd == opt_d_vd_o) &&
62019 	  (sc->pc == start + 2))
62020 	{
62021 	  opc->v[1].obj = o1->v[5].obj;
62022 	  opc->v[8].p = o1->v[1].p;
62023 	  opc->v[2].d_v_f = o1->v[3].d_v_f;
62024 	  opc->v[7].d_vd_f = o2->v[3].d_vd_f;
62025 	  opc->v[4].d_v_f = o2->v[4].d_v_f;
62026 	  opc->v[5].obj = o2->v[5].obj;
62027 	  opc->v[9].p = o2->v[1].p;
62028 	  opc->v[6].obj = o2->v[6].obj;
62029 	  opc->v[10].p = o2->v[2].p;
62030 	  opc->v[0].fd = (opc->v[3].d_dd_f == multiply_d_dd) ? opt_d_dd_ff_mul4 : opt_d_dd_ff_o4;
62031 	  sc->pc -= 2;
62032 	  return(true);
62033 	}
62034       opc->v[1].obj = o1->v[5].obj;
62035       opc->v[4].p = o1->v[1].p;
62036       opc->v[2].d_v_f = o1->v[3].d_v_f;
62037       opc->v[0].fd = (opc->v[3].d_dd_f == multiply_d_dd) ? opt_d_dd_ff_mul1 : opt_d_dd_ff_o1;
62038       return(true);
62039     }
62040 
62041   if (o1->v[0].fd == opt_d_dd_fso)
62042     {
62043       if (o2->v[0].fd == opt_d_dd_fso)
62044 	{
62045 	  if ((o1->v[4].d_dd_f == multiply_d_dd) &&
62046 	      (o2->v[4].d_dd_f == multiply_d_dd) &&
62047 	      (o1->v[5].d_7pi_f == float_vector_ref_d_7pi) &&
62048 	      (o2->v[5].d_7pi_f == float_vector_ref_d_7pi))
62049 	    opc->v[0].fd = opt_d_mm_fff; /* a placeholder (never called) */
62050 	  else opc->v[0].fd = opt_d_dd_fff;
62051 	  return(finish_dd_fso(opc, o1, o2));
62052 	}}
62053   if (o1->v[0].fd == opt_d_dd_sfo)
62054     {
62055       if (o2->v[0].fd == opt_d_dd_sfo)
62056 	{
62057 	  if ((o1->v[4].d_dd_f == multiply_d_dd) &&
62058 	      (o2->v[4].d_dd_f == multiply_d_dd) &&
62059 	      (o1->v[5].d_7pi_f == float_vector_ref_d_7pi) &&
62060 	      (o2->v[5].d_7pi_f == float_vector_ref_d_7pi))
62061 	    opc->v[0].fd = opt_d_mm_fff; /* multiply is commutative */
62062 	  else opc->v[0].fd = opt_d_dd_fff_rev;
62063 	  return(finish_dd_fso(opc, o1, o2));
62064 	}}
62065   return_false(sc, NULL);
62066 }
62067 
62068 static s7_double opt_d_dd_cfo(opt_info *o)  {return(o->v[3].d_dd_f(o->v[2].x, o->v[4].d_v_f(o->v[1].obj)));}
62069 static s7_double opt_d_7dd_cfo(opt_info *o) {return(o->v[3].d_7dd_f(opt_sc(o), o->v[2].x, o->v[4].d_v_f(o->v[1].obj)));}
62070 static s7_double opt_d_dd_cfo1(opt_info *o) {return(o->v[3].d_dd_f(o->v[4].x, o->v[5].d_vd_f(o->v[6].obj, real(slot_value(o->v[2].p)))));}
62071 static s7_double opt_d_7dd_cfo1(opt_info *o){return(o->v[3].d_7dd_f(opt_sc(o), o->v[4].x, o->v[5].d_vd_f(o->v[6].obj, real(slot_value(o->v[2].p)))));}
62072 
62073 static bool d_dd_call_combinable(s7_scheme *sc, opt_info *opc, s7_d_dd_t func)
62074 {
62075   if ((sc->pc > 1) &&
62076       (opc == sc->opts[sc->pc - 2]))
62077     {
62078       opt_info *o1;
62079       o1 = sc->opts[sc->pc - 1];
62080       if (o1->v[0].fd == opt_d_v)
62081 	{
62082 	  opc->v[2].x = opc->v[1].x;
62083 	  opc->v[6].p = o1->v[1].p;
62084 	  opc->v[1].obj = o1->v[5].obj;
62085 	  opc->v[4].d_v_f = o1->v[3].d_v_f;
62086 	  opc->v[0].fd = (func) ? opt_d_dd_cfo : opt_d_7dd_cfo;
62087 	  backup_pc(sc);
62088 	  return(true);
62089 	}
62090       if (o1->v[0].fd == opt_d_vd_s)
62091 	{
62092 	  opc->v[4].x = opc->v[1].x;
62093 	  opc->v[1].p = o1->v[1].p;
62094 	  opc->v[6].obj = o1->v[5].obj;
62095 	  opc->v[2].p = o1->v[2].p;
62096 	  opc->v[5].d_vd_f = o1->v[3].d_vd_f;
62097 	  opc->v[0].fd = (func) ? opt_d_dd_cfo1 : opt_d_7dd_cfo1;
62098 	  backup_pc(sc);
62099 	  return(true);
62100 	}}
62101   return_false(sc, NULL);
62102 }
62103 
62104 static bool d_dd_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
62105 {
62106   s7_d_dd_t func;
62107   s7_d_7dd_t func7 = NULL;
62108   func = s7_d_dd_function(s_func);
62109   if (!func) func7 = s7_d_7dd_function(s_func);
62110   if ((func) || (func7))
62111     {
62112       s7_pointer arg1, arg2, slot;
62113       int32_t start;
62114       opt_info *o1;
62115       start = sc->pc;
62116       arg1 = cadr(car_x);
62117       arg2 = caddr(car_x);
62118       if (func)
62119 	opc->v[3].d_dd_f = func;
62120       else opc->v[3].d_7dd_f = func7;
62121 
62122       /* arg1 = real constant */
62123       if (is_small_real(arg1))
62124 	{
62125 	  if (is_small_real(arg2))
62126 	    {
62127 	      if ((!is_t_real(arg1)) && (!is_t_real(arg2)))
62128 		return_false(sc, car_x);
62129 	      opc->v[1].x = s7_number_to_real(sc, arg1);
62130 	      opc->v[2].x = s7_number_to_real(sc, arg2);
62131 	      opc->v[0].fd = (func) ? opt_d_dd_cc : opt_d_7dd_cc;
62132 	      return(true);
62133 	    }
62134 	  slot = opt_float_symbol(sc, arg2);
62135 	  if (slot)
62136 	    {
62137 	      opc->v[1].p = slot;
62138 	      opc->v[2].x = s7_number_to_real(sc, arg1); /* move arg1? */
62139 	      opc->v[0].fd = (func) ? opt_d_dd_cs : opt_d_7dd_cs;
62140 	      return(true);
62141 	    }
62142 	  if (float_optimize(sc, cddr(car_x)))
62143 	    {
62144 	      opc->v[1].x = s7_number_to_real(sc, arg1);
62145 	      if (d_dd_call_combinable(sc, opc, func))
62146 		return(true);
62147 	      opc->v[4].o1 = sc->opts[start];
62148 	      opc->v[5].fd = sc->opts[start]->v[0].fd;
62149 	      opc->v[0].fd = (func) ? opt_d_dd_cf : opt_d_7dd_cf;
62150 	      if ((opc->v[1].x == 1.0) && (func == subtract_d_dd)) opc->v[0].fd = opt_d_dd_1f_subtract;
62151 	      return(true);
62152 	    }
62153 	  pc_fallback(sc, start);
62154 	  return_false(sc, car_x);
62155 	}
62156 
62157       /* arg1 = float symbol */
62158       slot = opt_float_symbol(sc, arg1);
62159       if (slot)
62160 	{
62161 	  opc->v[1].p = slot;
62162 	  if (is_small_real(arg2))
62163 	    {
62164 	      opc->v[2].x = s7_number_to_real(sc, arg2);
62165 	      if (func)
62166 		opc->v[0].fd = (func == subtract_d_dd) ? opt_d_dd_sc_sub : opt_d_dd_sc;
62167 	      else opc->v[0].fd = opt_d_7dd_sc;
62168 	      return(true);
62169 	    }
62170 	  slot = opt_float_symbol(sc, arg2);
62171 	  if (slot)
62172 	    {
62173 	      opc->v[2].p = slot;
62174 	      if (func)
62175 		{
62176 		  if (func == multiply_d_dd)
62177 		    opc->v[0].fd = opt_d_dd_ss_mul;
62178 		  else opc->v[0].fd = (func == add_d_dd) ? opt_d_dd_ss_add : opt_d_dd_ss;
62179 		}
62180 	      else opc->v[0].fd = opt_d_7dd_ss;
62181 	      return(true);
62182 	    }
62183 	  if (float_optimize(sc, cddr(car_x)))
62184 	    {
62185 	      if (d_dd_sf_combinable(sc, opc, func))
62186 		return(true);
62187 	      opc->v[4].o1 = sc->opts[start];
62188 	      opc->v[5].fd = sc->opts[start]->v[0].fd;
62189 	      if (func)
62190 		opc->v[0].fd = (func == multiply_d_dd) ? opt_d_dd_sf_mul :
62191                                 ((func == add_d_dd) ? opt_d_dd_sf_add :
62192 				 ((func == subtract_d_dd) ? opt_d_dd_sf_sub : opt_d_dd_sf));
62193 	      else opc->v[0].fd = opt_d_7dd_sf;
62194 	      return(true);
62195 	    }
62196 	  pc_fallback(sc, start);
62197 	  return_false(sc, car_x);
62198 	}
62199 
62200       /* arg1 = float expr or non-float */
62201       o1 = sc->opts[sc->pc];
62202       if (float_optimize(sc, cdr(car_x)))
62203 	{
62204 	  int32_t start2;
62205 	  start2 = sc->pc;
62206 	  if (is_small_real(arg2))
62207 	    {
62208 	      opc->v[2].x = s7_number_to_real(sc, arg2);
62209 	      opc->v[4].o1 = sc->opts[start];
62210 	      opc->v[5].fd = sc->opts[start]->v[0].fd;
62211 	      if (func)
62212 		{
62213 		  if (func == add_d_dd)
62214 		    {
62215 		      opc->v[0].fd = opt_d_dd_fc_add; /* opt_i_7i_c o->v[2].i_7i_f = random_i_7i else as below except add_i_ii in opt_i_ii_cf = (+ i1 (random i2)) */
62216 		      return(true);
62217 		    }
62218 		  if (func == subtract_d_dd)
62219 		    {
62220 		      opc->v[0].fd = opt_d_dd_fc_subtract;
62221 		      /* if o1->v[0].fd = opt_d_7d_c and its o->v[3].d_7d_f = random_d_7d it's (- (random f1) f2) */
62222 		      if ((opc == sc->opts[sc->pc - 2]) &&
62223 			  (sc->opts[start]->v[0].fd == opt_d_7d_c) &&
62224 			  (sc->opts[start]->v[3].d_7d_f == random_d_7d))
62225 			{
62226 			  opc->v[0].fd = opt_subtract_random_f_f;
62227 			  opc->v[1].x = sc->opts[start]->v[1].x; /* random arg */
62228 			  backup_pc(sc);
62229 			}}
62230 		  else opc->v[0].fd = opt_d_dd_fc;
62231 		}
62232 	      else opc->v[0].fd = opt_d_7dd_fc;
62233 	      return(true);
62234 	    }
62235 	  slot = opt_float_symbol(sc, arg2);
62236 	  if (slot)
62237 	    {
62238 	      opc->v[1].p = slot;
62239 	      if (d_dd_fs_combinable(sc, opc, func))
62240 		return(true);
62241 	      opc->v[4].o1 = sc->opts[start];
62242 	      opc->v[5].fd = sc->opts[start]->v[0].fd;
62243 	      if (func)
62244 		opc->v[0].fd = (func == multiply_d_dd) ? opt_d_dd_fs_mul :
62245 		                ((func == add_d_dd) ? opt_d_dd_fs_add :
62246 				 ((func == subtract_d_dd) ? opt_d_dd_fs_sub : opt_d_dd_fs));
62247 	      else opc->v[0].fd = opt_d_7dd_fs;
62248 	      return(true);
62249 	    }
62250 	  opc->v[10].o1 = sc->opts[sc->pc];
62251 	  if (float_optimize(sc, cddr(car_x)))
62252 	    {
62253 	      opc->v[8].o1 = o1;
62254 	      opc->v[9].fd = o1->v[0].fd;
62255 	      opc->v[11].fd = opc->v[10].o1->v[0].fd;
62256 	      if (func)
62257 		{
62258 		  if (d_dd_ff_combinable(sc, opc, start))
62259 		    return(true);
62260 		  opc->v[0].fd = opt_d_dd_ff;
62261 		  if (func == multiply_d_dd)
62262 		    {
62263 		      if (arg1 == arg2)
62264 			opc->v[0].fd = opt_d_dd_ff_square;
62265 		      else
62266 			{
62267 			  if ((opc->v[9].fd == opt_d_7pii_sss) && (opc->v[11].fd == opt_d_7pii_sss) &&
62268 			      (o1->v[4].d_7pii_f == float_vector_ref_d_7pii)) /* currently redundant */
62269 			    opc->v[0].fd = opt_d_dd_ff_mul_sss;
62270 			  else opc->v[0].fd = opt_d_dd_ff_mul;
62271 			}
62272 		      return(true);
62273 		    }
62274 		  else
62275 		    {
62276 		      opt_info *o2;
62277 		      o2 = sc->opts[start2]; /* this is opc->v[10].o1 */
62278 		      if (func == add_d_dd)
62279 			{
62280 			  if (o2->v[0].fd == opt_d_dd_ff_mul)
62281 			    {
62282 			      opc->v[0].fd = opt_d_dd_ff_add_mul;
62283 			      opc->v[4].o1 = o1;            /* add first arg */
62284 			      opc->v[5].fd = o1->v[0].fd;
62285 			      opc->v[8].o1 = o2->v[8].o1;   /* mul first arg */
62286 			      opc->v[9].fd = o2->v[9].fd;
62287 			      opc->v[10].o1 = o2->v[10].o1; /* mul second arg */
62288 			      opc->v[11].fd = o2->v[11].fd;
62289 			      return(true);
62290 			    }
62291 			  if ((o2->v[0].fd == opt_d_7pi_sf) &&
62292 			      (o2->v[3].d_7pi_f == float_vector_ref_d_7pi))
62293 			    {
62294 			      opc->v[0].fd = opt_d_dd_ff_add_fv_ref;
62295 			      opc->v[6].p = o2->v[1].p;
62296 			      opc->v[8].o1 = o2->v[10].o1; /* sc->opts[start2 + 1]; */
62297 			      opc->v[9].fi = o2->v[11].fi; /* sc->opts[start2 + 1]->v[0].fi; */
62298 			    }
62299 			  else
62300 			    {
62301 			      opc->v[0].fd = opt_d_dd_ff_add;
62302 			      opc->v[10].o1 = o2;
62303 			      opc->v[11].fd = o2->v[0].fd;
62304 			    }
62305 			  opc->v[4].o1 = o1;              /* sc->opts[start]; */
62306 			  opc->v[5].fd = o1->v[0].fd;     /* sc->opts[start]->v[0].fd; */
62307 			  return(true);
62308 			}
62309 		      if (func == subtract_d_dd)
62310 			{
62311 			  opc->v[0].fd = opt_d_dd_ff_sub;
62312 			  opc->v[4].o1 = o1;          /* sc->opts[start]; */
62313 			  opc->v[5].fd = o1->v[0].fd; /* sc->opts[start]->v[0].fd; */
62314 			  opc->v[10].o1 = o2;
62315 			  opc->v[11].fd = o2->v[0].fd;
62316 			  return(true);
62317 			}}}
62318 	      else opc->v[0].fd = opt_d_7dd_ff;
62319 	      return(true);
62320 	    }}
62321       pc_fallback(sc, start);
62322     }
62323   return_false(sc, car_x);
62324 }
62325 
62326 /* -------- d_ddd -------- */
62327 static s7_double opt_d_ddd_sss(opt_info *o) {return(o->v[4].d_ddd_f(real(slot_value(o->v[1].p)), real(slot_value(o->v[2].p)), real(slot_value(o->v[3].p))));}
62328 static s7_double opt_d_ddd_ssf(opt_info *o) {return(o->v[4].d_ddd_f(real(slot_value(o->v[1].p)), real(slot_value(o->v[2].p)), o->v[11].fd(o->v[10].o1)));}
62329 
62330 static s7_double opt_d_ddd_sff(opt_info *o)
62331 {
62332   s7_double x1, x2;
62333   x1 = o->v[11].fd(o->v[10].o1);
62334   x2 = o->v[9].fd(o->v[8].o1);
62335   return(o->v[4].d_ddd_f(real(slot_value(o->v[1].p)), x1, x2));
62336 }
62337 
62338 static s7_double opt_d_ddd_fff(opt_info *o)
62339 {
62340   s7_double x1, x2, x3;
62341   x1 = o->v[11].fd(o->v[10].o1);
62342   x2 = o->v[9].fd(o->v[8].o1);
62343   x3 = o->v[6].fd(o->v[5].o1);
62344   return(o->v[4].d_ddd_f(x1, x2, x3));
62345 }
62346 
62347 static s7_double opt_d_ddd_fff1(opt_info *o)
62348 {
62349   s7_double x1, x2, x3;
62350   x1 = o->v[1].d_v_f(o->v[2].obj);
62351   x2 = o->v[3].d_v_f(o->v[4].obj);
62352   x3 = o->v[5].d_v_f(o->v[6].obj);
62353   return(o->v[7].d_ddd_f(x1, x2, x3));
62354 }
62355 
62356 static s7_double opt_d_ddd_fff2(opt_info *o)
62357 {
62358   s7_double x1, x2, x3;
62359   x1 = o->v[1].d_v_f(o->v[2].obj);
62360   x2 = o->v[9].fd(o->v[12].o1);
62361   x3 = o->v[6].fd(o->v[5].o1);
62362   return(o->v[7].d_ddd_f(x1, x2, x3));
62363 }
62364 
62365 static bool d_ddd_fff_combinable(s7_scheme *sc, opt_info *opc, int32_t start)
62366 {
62367   if (sc->opts[start]->v[0].fd == opt_d_v)
62368     {
62369       opt_info *o1;
62370       opc->v[12].o1 = opc->v[8].o1;
62371       opc->v[7].d_ddd_f = opc->v[4].d_ddd_f;
62372       o1 = sc->opts[start];
62373       opc->v[1].d_v_f = o1->v[3].d_v_f;
62374       opc->v[2].obj = o1->v[5].obj;
62375       opc->v[8].p = o1->v[1].p;
62376       if ((sc->opts[start + 1]->v[0].fd == opt_d_v) &&
62377 	  (sc->opts[start + 2]->v[0].fd == opt_d_v))
62378 	{
62379 	  opc->v[0].fd = opt_d_ddd_fff1;
62380 	  o1 = sc->opts[start + 1];
62381 	  opc->v[3].d_v_f = o1->v[3].d_v_f;
62382 	  opc->v[4].obj = o1->v[5].obj;
62383 	  opc->v[9].p = o1->v[1].p;
62384 	  o1 = sc->opts[start + 2];
62385 	  opc->v[5].d_v_f = o1->v[3].d_v_f;
62386 	  opc->v[6].obj = o1->v[5].obj;
62387 	  opc->v[10].p = o1->v[1].p;
62388 	  sc->pc -= 3;
62389 	  return(true);
62390 	}
62391       opc->v[0].fd = opt_d_ddd_fff2;
62392       opc->v[9].fd = opc->v[12].o1->v[0].fd;
62393       opc->v[6].fd = opc->v[5].o1->v[0].fd;
62394       return(true);
62395     }
62396   return_false(sc, NULL);
62397 }
62398 
62399 static bool d_ddd_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
62400 {
62401   s7_d_ddd_t f;
62402 
62403   f = s7_d_ddd_function(s_func);
62404   if (f)
62405     {
62406       int32_t start;
62407       s7_pointer arg1, arg2, slot;
62408       arg1 = cadr(car_x);
62409       arg2 = caddr(car_x);
62410       start = sc->pc;
62411       opc->v[4].d_ddd_f = f;
62412       slot = opt_float_symbol(sc, arg1);
62413       opc->v[10].o1 = sc->opts[start];
62414       if (slot)
62415 	{
62416 	  opc->v[1].p = slot;
62417 	  slot = opt_float_symbol(sc, arg2);
62418 	  if (slot)
62419 	    {
62420 	      s7_pointer arg3;
62421 	      opc->v[2].p = slot;
62422 	      arg3 = cadddr(car_x);
62423 	      slot = opt_float_symbol(sc, arg3);
62424 	      if (slot)
62425 		{
62426 		  opc->v[3].p = slot;
62427 		  opc->v[0].fd = opt_d_ddd_sss;
62428 		  return(true);
62429 		}
62430 	      if (float_optimize(sc, cdddr(car_x)))
62431 		{
62432 		  opc->v[11].fd = opc->v[10].o1->v[0].fd;
62433 		  opc->v[0].fd = opt_d_ddd_ssf;
62434 		  return(true);
62435 		}
62436 	      pc_fallback(sc, start);
62437 	    }
62438 	  if (float_optimize(sc, cddr(car_x)))
62439 	    {
62440 	      opc->v[8].o1 = sc->opts[sc->pc];
62441 	      if (float_optimize(sc, cdddr(car_x)))
62442 		{
62443 		  opc->v[0].fd = opt_d_ddd_sff;
62444 		  opc->v[11].fd = opc->v[10].o1->v[0].fd;
62445 		  opc->v[9].fd = opc->v[8].o1->v[0].fd;
62446 		  return(true);
62447 		}}
62448 	  pc_fallback(sc, start);
62449 	}
62450       if (float_optimize(sc, cdr(car_x)))
62451 	{
62452 	  opc->v[8].o1 = sc->opts[sc->pc];
62453 	  if (float_optimize(sc, cddr(car_x)))
62454 	    {
62455 	      opc->v[5].o1 = sc->opts[sc->pc];
62456 	      if (float_optimize(sc, cdddr(car_x)))
62457 		{
62458 		  if (d_ddd_fff_combinable(sc, opc, start))
62459 		    return(true);
62460 		  opc->v[0].fd = opt_d_ddd_fff;
62461 		  opc->v[11].fd = opc->v[10].o1->v[0].fd;
62462 		  opc->v[9].fd = opc->v[8].o1->v[0].fd;
62463 		  opc->v[6].fd = opc->v[5].o1->v[0].fd;
62464 		  return(true);
62465 		  }}}
62466       pc_fallback(sc, start);
62467     }
62468   return_false(sc, car_x);
62469 }
62470 
62471 /* -------- d_7pid -------- */
62472 static s7_double opt_d_7pid_ssf(opt_info *o)
62473 {
62474   return(o->v[4].d_7pid_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[11].fd(o->v[10].o1)));
62475 }
62476 
62477 static s7_pointer opt_d_7pid_ssf_nr(opt_info *o)
62478 {
62479   o->v[4].d_7pid_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[11].fd(o->v[10].o1));
62480   return(NULL);
62481 }
62482 
62483 static s7_double opt_d_7pid_sss(opt_info *o)
62484 {
62485   return(o->v[4].d_7pid_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), real(slot_value(o->v[3].p))));
62486 }
62487 
62488 static s7_double opt_d_7pid_ssc(opt_info *o)
62489 {
62490   return(o->v[4].d_7pid_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[3].x));
62491 }
62492 
62493 static s7_double opt_d_7pid_sff(opt_info *o)
62494 {
62495   s7_int pos;
62496   pos = o->v[11].fi(o->v[10].o1);
62497   return(o->v[4].d_7pid_f(opt_sc(o), slot_value(o->v[1].p), pos, o->v[9].fd(o->v[8].o1)));
62498 }
62499 
62500 static s7_double opt_d_7pid_sso(opt_info *o)
62501 {
62502   return(o->v[4].d_7pid_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[5].d_v_f(o->v[3].obj)));
62503 }
62504 
62505 static s7_double opt_d_7pid_ss_ss(opt_info *o)
62506 {
62507   return(o->v[4].d_7pid_f(opt_sc(o), slot_value(o->v[1].p),
62508 			  integer(slot_value(o->v[2].p)),
62509 			  o->v[3].d_7pi_f(opt_sc(o), slot_value(o->v[5].p),
62510 					  integer(slot_value(o->v[6].p)))));
62511 }
62512 
62513 static s7_double opt_d_7pid_ssfo(opt_info *o)
62514 {
62515   s7_pointer fv;
62516   fv = slot_value(o->v[1].p);
62517   return(o->v[4].d_7pid_f(opt_sc(o), fv, integer(slot_value(o->v[2].p)),
62518 	    o->v[6].d_dd_f(o->v[5].d_7pi_f(opt_sc(o), fv, integer(slot_value(o->v[3].p))), real(slot_value(o->v[8].p)))));
62519 }
62520 
62521 static s7_double opt_d_7pid_ssfo_fv(opt_info *o)
62522 {
62523   s7_double val;
62524   s7_double *els;
62525   els = float_vector_floats(slot_value(o->v[1].p));
62526   val = o->v[6].d_dd_f(els[integer(slot_value(o->v[3].p))], real(slot_value(o->v[8].p)));
62527   els[integer(slot_value(o->v[2].p))] = val;
62528   return(val);
62529 }
62530 
62531 static s7_pointer opt_d_7pid_ssfo_fv_nr(opt_info *o)
62532 {
62533   s7_double *els;
62534   els = float_vector_floats(slot_value(o->v[1].p));
62535   els[integer(slot_value(o->v[2].p))] = o->v[6].d_dd_f(els[integer(slot_value(o->v[3].p))], real(slot_value(o->v[8].p)));
62536   return(NULL);
62537 }
62538 
62539 static s7_pointer opt_d_7pid_ssfo_fv_add_nr(opt_info *o)
62540 {
62541   s7_double *els;
62542   els = float_vector_floats(slot_value(o->v[1].p));
62543   els[integer(slot_value(o->v[2].p))] = els[integer(slot_value(o->v[3].p))] + real(slot_value(o->v[8].p));
62544   return(NULL);
62545 }
62546 
62547 static s7_pointer opt_d_7pid_ssfo_fv_sub_nr(opt_info *o)
62548 {
62549   s7_double *els;
62550   els = float_vector_floats(slot_value(o->v[1].p));
62551   els[integer(slot_value(o->v[2].p))] = els[integer(slot_value(o->v[3].p))] - real(slot_value(o->v[8].p));
62552   return(NULL);
62553 }
62554 
62555 static bool d_7pid_ssf_combinable(s7_scheme *sc, opt_info *opc)
62556 {
62557   if ((sc->pc > 1) &&
62558       (opc == sc->opts[sc->pc - 2]))
62559     {
62560       opt_info *o1;
62561       o1 = sc->opts[sc->pc - 1];
62562       if (o1->v[0].fd == opt_d_v)
62563 	{
62564 	  opc->v[6].p = o1->v[1].p;
62565 	  opc->v[3].obj = o1->v[5].obj;
62566 	  opc->v[5].d_v_f = o1->v[3].d_v_f;
62567 	  opc->v[0].fd = opt_d_7pid_sso;
62568 	  backup_pc(sc);
62569 	  return(true);
62570 	}
62571       if (o1->v[0].fd == opt_d_7pi_ss)
62572 	{
62573 	  opc->v[3].d_7pi_f = o1->v[3].d_7pi_f;
62574 	  opc->v[5].p = o1->v[1].p;
62575 	  opc->v[6].p = o1->v[2].p;
62576 	  opc->v[0].fd = opt_d_7pid_ss_ss;
62577 	  backup_pc(sc);
62578 	  return(true);
62579 	}
62580       if ((o1->v[0].fd == opt_d_dd_fso) &&
62581 	  (opc->v[1].p == o1->v[2].p))
62582 	{
62583 	  /* opc: pid_ssf: o->v[4].d_7pid_f(slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o1->v[0].fd(o1))
62584 	   * o1: d_dd_fso: o->v[4].d_dd_f(o->v[5].d_7pi_f(slot_value(o->v[2].p), integer(slot_value(o->v[3].p))), real(slot_value(o->v[1].p))))
62585 	   */
62586 	  opc->v[6].d_dd_f = o1->v[4].d_dd_f;
62587 	  opc->v[5].d_7pi_f = o1->v[5].d_7pi_f;
62588 	  opc->v[3].p = o1->v[3].p;
62589 	  opc->v[8].p = o1->v[1].p;
62590 	  opc->v[0].fd = opt_d_7pid_ssfo;
62591 	  if (((opc->v[5].d_7pi_f == float_vector_ref_unchecked) ||
62592 	       (opc->v[5].d_7pi_f == float_vector_ref_d_7pi)) &&
62593 	      ((opc->v[4].d_7pid_f == float_vector_set_unchecked) ||
62594 	       (opc->v[4].d_7pid_f == float_vector_set_d_7pid)))
62595 	    opc->v[0].fd = opt_d_7pid_ssfo_fv; /* actually if either is *_d, we need to check the indices */
62596 	  backup_pc(sc);
62597 	  return(true);
62598 	}}
62599   return_false(sc, NULL);
62600 }
62601 
62602 /* -------- d_7piid -------- */
62603 /* currently only float_vector_set */
62604 static s7_double opt_d_7piid_sssf(opt_info *o)
62605 { /*     o->v[5].d_7piid_f and below */
62606   return(float_vector_set_d_7piid(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p)), o->v[9].fd(o->v[8].o1)));
62607 }
62608 
62609 static s7_double opt_d_7piid_sssc(opt_info *o)
62610 {
62611   return(float_vector_set_d_7piid(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p)), o->v[4].x));
62612 }
62613 
62614 static s7_double opt_d_7piid_scsf(opt_info *o)
62615 {
62616   return(float_vector_set_d_7piid(opt_sc(o), slot_value(o->v[1].p), o->v[2].i, integer(slot_value(o->v[3].p)), o->v[11].fd(o->v[10].o1)));
62617 }
62618 
62619 static s7_double opt_d_7piid_sfff(opt_info *o)
62620 {
62621   s7_int i1, i2;
62622   i1 = o->v[11].fi(o->v[10].o1);
62623   i2 = o->v[9].fi(o->v[8].o1);
62624   return(float_vector_set_d_7piid(opt_sc(o), slot_value(o->v[1].p), i1, i2, o->v[4].fd(o->v[3].o1)));
62625 }
62626 
62627 static bool opt_float_vector_set(s7_scheme *sc, opt_info *opc, s7_pointer v, s7_pointer indexp1, s7_pointer indexp2, s7_pointer valp)
62628 {
62629   s7_pointer settee;
62630   settee = lookup_slot_from(v, sc->curlet);
62631   if ((is_slot(settee)) &&
62632       (!is_immutable(slot_value(settee))))
62633     {
62634       s7_pointer slot;
62635       int32_t start;
62636       opc->v[1].p = settee;
62637       start = sc->pc;
62638       if (is_float_vector(slot_value(settee)))
62639 	{
62640 	  opc->v[10].o1 = sc->opts[start];
62641 	  if ((!indexp2) &&
62642 	      (vector_rank(slot_value(settee)) == 1))
62643 	    {
62644 	      opc->v[4].d_7pid_f = float_vector_set_d_7pid;
62645 	      slot = opt_integer_symbol(sc, car(indexp1));
62646 	      if (slot)
62647 		{
62648 		  opc->v[2].p = slot;
62649 		  if ((is_step_end(opc->v[2].p)) &&
62650 		      (denominator(slot_value(opc->v[2].p)) <= vector_length(slot_value(settee))))
62651 		    opc->v[4].d_7pid_f = float_vector_set_unchecked;
62652 		  slot = opt_float_symbol(sc, car(valp));
62653 		  if (slot)
62654 		    {
62655 		      opc->v[3].p = slot;
62656 		      opc->v[0].fd = opt_d_7pid_sss;
62657 		      return(true);
62658 		    }
62659 		  if (is_small_real(car(valp)))
62660 		    {
62661 		      opc->v[3].x = s7_real(car(valp));
62662 		      opc->v[0].fd = opt_d_7pid_ssc;
62663 		      return(true);
62664 		    }
62665 		  if (float_optimize(sc, valp))
62666 		    {
62667 		      opc->v[11].fd = sc->opts[start]->v[0].fd;
62668 		      if (d_7pid_ssf_combinable(sc, opc))
62669 			return(true);
62670 		      opc->v[0].fd = opt_d_7pid_ssf;
62671 		      return(true);
62672 		    }
62673 		  pc_fallback(sc, start);
62674 		}
62675 	      if (int_optimize(sc, indexp1))
62676 		{
62677 		  opc->v[8].o1 = sc->opts[sc->pc];
62678 		  if (float_optimize(sc, valp))
62679 		    {
62680 		      opc->v[0].fd = opt_d_7pid_sff;
62681 		      opc->v[11].fi = opc->v[10].o1->v[0].fi;
62682 		      opc->v[9].fd = opc->v[8].o1->v[0].fd;
62683 		      return(true);
62684 		    }}
62685 	      return_false(sc, NULL);
62686 	    }
62687 
62688 	  if ((indexp2) &&
62689 	      (vector_rank(slot_value(settee)) == 2))
62690 	    {
62691 	      opc->v[5].d_7piid_f = float_vector_set_d_7piid;
62692 	      slot = opt_integer_symbol(sc, car(indexp2));
62693 	      if (slot)
62694 		{
62695 		  opc->v[3].p = slot;
62696 		  if (is_t_integer(car(indexp1)))
62697 		    {
62698 		      if (float_optimize(sc, valp))
62699 			{
62700 			  opc->v[0].fd = opt_d_7piid_scsf;
62701 			  opc->v[2].i = integer(car(indexp1));
62702 			  opc->v[11].fd = opc->v[10].o1->v[0].fd;
62703 			  return(true);
62704 			}
62705 		      return_false(sc, NULL);
62706 		    }
62707 		  slot = opt_integer_symbol(sc, car(indexp1));
62708 		  if (slot)
62709 		    {
62710 		      opc->v[2].p = slot;
62711 		      if (is_small_real(car(valp)))
62712 			{
62713 			  opc->v[0].fd = opt_d_7piid_sssc;
62714 			  opc->v[4].x = s7_real(car(valp));
62715 			  return(true);
62716 			}
62717 		      opc->v[8].o1 = sc->opts[sc->pc];
62718 		      if (float_optimize(sc, valp))
62719 			{
62720 			  opc->v[0].fd = opt_d_7piid_sssf;
62721 			  opc->v[9].fd = opc->v[8].o1->v[0].fd;
62722 			  return(true);
62723 			}
62724 		      pc_fallback(sc, start);
62725 		    }}
62726 	      if (int_optimize(sc, indexp1))
62727 		{
62728 		  opc->v[8].o1 = sc->opts[sc->pc];
62729 		  if (int_optimize(sc, indexp2))
62730 		    {
62731 		      opc->v[3].o1 = sc->opts[sc->pc];
62732 		      if (float_optimize(sc, valp))
62733 			{
62734 			  opc->v[0].fd = opt_d_7piid_sfff;
62735 			  opc->v[11].fi = opc->v[10].o1->v[0].fi;
62736 			  opc->v[9].fi = opc->v[8].o1->v[0].fi;
62737 			  opc->v[4].fd = opc->v[3].o1->v[0].fd;
62738 			  return(true);
62739 			}}}}}}
62740   return_false(sc, NULL);
62741 }
62742 
62743 /* -------- d_7pii -------- */
62744 /* currently this can only be float_vector_ref_d_7pii (d_7pii is not exported at this time) */
62745 
62746 static s7_double opt_d_7pii_sss(opt_info *o)
62747 { /*     o->v[4].d_7pii_f */
62748   return(float_vector_ref_d_7pii(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p))));
62749 }
62750 
62751 static s7_double opt_d_7pii_scs(opt_info *o)
62752 {
62753   return(float_vector_ref_d_7pii(opt_sc(o), slot_value(o->v[1].p), o->v[2].i, integer(slot_value(o->v[3].p))));
62754 }
62755 
62756 static s7_double opt_d_7pii_sff(opt_info *o)
62757 {
62758   return(float_vector_ref_d_7pii(opt_sc(o), slot_value(o->v[1].p), o->v[11].fi(o->v[10].o1), o->v[9].fi(o->v[8].o1)));
62759 }
62760 
62761 static bool d_7pii_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
62762 {
62763   if (is_symbol(cadr(car_x)))
62764     {
62765       s7_d_7pii_t ifunc;
62766       ifunc = s7_d_7pii_function(s_func);
62767       if ((ifunc == float_vector_ref_d_7pii) &&
62768 	  (is_symbol(cadr(car_x))))
62769 	{
62770 	  s7_pointer slot;
62771 	  int32_t start;
62772 	  start = sc->pc;
62773 	  opc->v[1].p = lookup_slot_from(cadr(car_x), sc->curlet);
62774 	  if ((!is_slot(opc->v[1].p)) ||
62775 	      (!is_float_vector(slot_value(opc->v[1].p))) ||
62776 	      (vector_rank(slot_value(opc->v[1].p)) != 2))
62777 	    return_false(sc, car_x);
62778 
62779 	  opc->v[4].d_7pii_f = ifunc; /* currently pointless */
62780 	  slot = opt_integer_symbol(sc, cadddr(car_x));
62781 	  if (slot)
62782 	    {
62783 	      opc->v[3].p = slot;
62784 	      slot = opt_integer_symbol(sc, caddr(car_x));
62785 	      if (slot)
62786 		{
62787 		  opc->v[2].p = slot;
62788 		  opc->v[0].fd = opt_d_7pii_sss;
62789 		  return(true);
62790 		}
62791 	      if (is_t_integer(caddr(car_x)))
62792 		{
62793 		  opc->v[2].i = integer(caddr(car_x));
62794 		  opc->v[0].fd = opt_d_7pii_scs;
62795 		  return(true);
62796 		}}
62797 	  opc->v[10].o1 = sc->opts[start];
62798 	  if (int_optimize(sc, cddr(car_x)))
62799 	    {
62800 	      opc->v[8].o1 = sc->opts[sc->pc];
62801 	      if (int_optimize(sc, cdddr(car_x)))
62802 		{
62803 		  opc->v[0].fd = opt_d_7pii_sff;
62804 		  opc->v[11].fi = opc->v[10].o1->v[0].fi;
62805 		  opc->v[9].fi = opc->v[8].o1->v[0].fi;
62806 		  return(true);
62807 		}}
62808 	  pc_fallback(sc, start);
62809 	}}
62810   return_false(sc, car_x);
62811 }
62812 
62813 static bool d_7pid_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
62814 {
62815   s7_d_7pid_t f;
62816   f = s7_d_7pid_function(s_func);
62817   if ((f) &&
62818       (is_symbol(cadr(car_x))))
62819     {
62820       s7_pointer head, slot;
62821       int32_t start;
62822       start = sc->pc;
62823       head = car(car_x);
62824       opc->v[4].d_7pid_f = f;
62825 
62826       if ((head == sc->float_vector_set_symbol) || (s_func == initial_value(sc->float_vector_set_symbol)))
62827 	return(opt_float_vector_set(sc, opc, cadr(car_x), cddr(car_x), NULL, cdddr(car_x)));
62828 
62829       opc->v[1].p = lookup_slot_from(cadr(car_x), sc->curlet);
62830       opc->v[10].o1 = sc->opts[start];
62831       if (is_slot(opc->v[1].p))
62832 	{
62833 	  slot = opt_integer_symbol(sc, caddr(car_x));
62834 	  if (slot)
62835 	    {
62836 	      opc->v[2].p = slot;
62837 	      slot = opt_float_symbol(sc, cadddr(car_x));
62838 	      if (slot)
62839 		{
62840 		  opc->v[3].p = slot;
62841 		  opc->v[0].fd = opt_d_7pid_sss;
62842 		  return(true);
62843 		}
62844 	      if (float_optimize(sc, cdddr(car_x)))
62845 		{
62846 		  opc->v[11].fd = sc->opts[start]->v[0].fd;
62847 		  if (d_7pid_ssf_combinable(sc, opc))
62848 		    return(true);
62849 		  opc->v[0].fd = opt_d_7pid_ssf;
62850 		  return(true);
62851 		}
62852 	      pc_fallback(sc, start);
62853 	    }
62854 	  if (int_optimize(sc, cddr(car_x)))
62855 	    {
62856 	      opc->v[8].o1 = sc->opts[sc->pc];
62857 	      if (float_optimize(sc, cdddr(car_x)))
62858 		{
62859 		  opc->v[0].fd = opt_d_7pid_sff;
62860 		  opc->v[11].fi = opc->v[10].o1->v[0].fi;
62861 		  opc->v[9].fd = opc->v[8].o1->v[0].fd;
62862 		  return(true);
62863 		}}
62864 	  pc_fallback(sc, start);
62865 	}}
62866   return_false(sc, car_x);
62867 }
62868 
62869 static bool d_7piid_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
62870 {
62871   s7_d_7piid_t f;
62872   f = s7_d_7piid_function(s_func);
62873   if ((f) &&
62874       (is_symbol(cadr(car_x))))
62875     {
62876       opc->v[4].d_7piid_f = f;
62877       if ((car(car_x) == sc->float_vector_set_symbol) || (s_func == initial_value(sc->float_vector_set_symbol)))
62878 	return(opt_float_vector_set(sc, opc, cadr(car_x), cddr(car_x), cdddr(car_x), cddddr(car_x)));
62879     }
62880   return_false(sc, car_x);
62881 }
62882 
62883 /* -------- d_vid -------- */
62884 static s7_double opt_d_vid_ssf(opt_info *o) {return(o->v[4].d_vid_f(o->v[5].obj, integer(slot_value(o->v[2].p)), o->v[11].fd(o->v[10].o1)));}
62885 
62886 static inline s7_double opt_fmv(opt_info *o)
62887 {
62888   /* d_vid_ssf -> d_dd_ff_o1 -> d_vd_o1 -> d_dd_ff_o3, this is a placeholder */
62889   opt_info *o1, *o2, *o3;
62890   s7_double amp_env, index_env, vib;
62891   o1 = o->v[12].o1;           /* o2 below */
62892   o2 = o->v[13].o1;           /* o3 below */
62893   o3 = o->v[14].o1;           /* o1 below */
62894   amp_env = o1->v[2].d_v_f(o1->v[1].obj);
62895   vib = real(slot_value(o2->v[2].p));
62896   index_env = o3->v[5].d_v_f(o3->v[1].obj);
62897   return(o->v[4].d_vid_f(o->v[5].obj,
62898 			 integer(slot_value(o->v[2].p)),
62899 			 amp_env * o2->v[3].d_vd_f(o2->v[5].obj,
62900 						   vib + (index_env * o3->v[6].d_vd_f(o3->v[2].obj, vib)))));
62901 }
62902 
62903 static bool d_vid_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
62904 {
62905   if ((is_symbol(cadr(car_x))) &&
62906       (is_symbol(caddr(car_x))))
62907     {
62908       s7_d_vid_t flt;
62909       flt = s7_d_vid_function(s_func);
62910       if (flt)
62911 	{
62912 	  s7_pointer sig;
62913 	  opc->v[4].d_vid_f = flt;
62914 	  sig = c_function_signature(s_func);
62915 	  if (is_pair(sig))
62916 	    {
62917 	      int32_t start;
62918 	      s7_pointer vslot;
62919 	      start = sc->pc;
62920 	      vslot = opt_types_match(sc, cadr(sig), cadr(car_x));
62921 	      if (vslot)
62922 		{
62923 		  s7_pointer slot;
62924 		  opc->v[0].fd = opt_d_vid_ssf;
62925 		  opc->v[1].p = vslot;
62926 		  opc->v[10].o1 = sc->opts[start];
62927 		  slot = opt_integer_symbol(sc, caddr(car_x));
62928 		  if ((slot) &&
62929 		      (float_optimize(sc, cdddr(car_x))))
62930 		    {
62931 		      opt_info *o2;
62932 		      opc->v[2].p = slot;
62933 		      opc->v[5].obj = (void *)c_object_value(slot_value(vslot));
62934 		      opc->v[11].fd = opc->v[10].o1->v[0].fd;
62935 		      o2 = sc->opts[start];
62936 		      if (o2->v[0].fd == opt_d_dd_ff_mul1)
62937 			{
62938 			  opt_info *o3;
62939 			  o3 = sc->opts[start + 2];
62940 			  if (o3->v[0].fd == opt_d_vd_o1)
62941 			    {
62942 			      opt_info *o1;
62943 			      o1 = sc->opts[start + 4];
62944 			      if ((o1->v[0].fd == opt_d_dd_ff_o3) &&
62945 				  (o1->v[4].d_dd_f == multiply_d_dd) &&
62946 				  (o3->v[4].d_dd_f == add_d_dd))
62947 				{
62948 				  opc->v[0].fd = opt_fmv; /* a placeholder -- see below */
62949 				  opc->v[12].o1 = o2;
62950 				  opc->v[13].o1 = o3;
62951 				  opc->v[14].o1 = o1;
62952 				}}}
62953 		      return(true);
62954 		    }}
62955 	      pc_fallback(sc, start);
62956 	    }}}
62957   return_false(sc, car_x);
62958 }
62959 
62960 /* -------- d_vdd -------- */
62961 static s7_double opt_d_vdd_ff(opt_info *o)
62962 {
62963   s7_double x1, x2;
62964   x1 = o->v[11].fd(o->v[10].o1);
62965   x2 = o->v[9].fd(o->v[8].o1);
62966   return(o->v[4].d_vdd_f(o->v[5].obj, x1, x2));
62967 }
62968 
62969 static bool d_vdd_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
62970 {
62971   s7_d_vdd_t flt;
62972   flt = s7_d_vdd_function(s_func);
62973   if (flt)
62974     {
62975       s7_pointer sig;
62976       opc->v[4].d_vdd_f = flt;
62977       sig = c_function_signature(s_func);
62978       if (is_pair(sig))
62979 	{
62980 	  s7_pointer slot;
62981 	  slot = opt_types_match(sc, cadr(sig), cadr(car_x));
62982 	  if (slot)
62983 	    {
62984 	      int32_t start;
62985 	      start = sc->pc;
62986 	      opc->v[10].o1 = sc->opts[start];
62987 	      if (float_optimize(sc, cddr(car_x)))
62988 		{
62989 		  opc->v[8].o1 = sc->opts[sc->pc];
62990 		  if (float_optimize(sc, cdddr(car_x)))
62991 		    {
62992 		      opc->v[11].fd = opc->v[10].o1->v[0].fd;
62993 		      opc->v[9].fd = opc->v[8].o1->v[0].fd;
62994 		      opc->v[1].p = slot;
62995 		      opc->v[5].obj = (void *)c_object_value(slot_value(slot));
62996 		      opc->v[0].fd = opt_d_vdd_ff;
62997 		      return(true);
62998 		    }}
62999 	      pc_fallback(sc, start);
63000 	    }}}
63001   return_false(sc, car_x);
63002 }
63003 
63004 
63005 /* -------- d_dddd -------- */
63006 static s7_double opt_d_dddd_ffff(opt_info *o)
63007 {
63008   s7_double x1, x2, x3, x4;
63009   x1 = o->v[11].fd(o->v[10].o1);
63010   x2 = o->v[9].fd(o->v[8].o1);
63011   x3 = o->v[5].fd(o->v[4].o1);
63012   x4 = o->v[3].fd(o->v[2].o1);
63013   return(o->v[1].d_dddd_f(x1, x2, x3, x4));
63014 }
63015 
63016 static bool d_dddd_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
63017 {
63018   s7_d_dddd_t f;
63019   f = s7_d_dddd_function(s_func);
63020   if (f)
63021     {
63022       opc->v[10].o1 = sc->opts[sc->pc];
63023       if (float_optimize(sc, cdr(car_x)))
63024 	{
63025 	  opc->v[8].o1 = sc->opts[sc->pc];
63026 	  if (float_optimize(sc, cddr(car_x)))
63027 	    {
63028 	      opc->v[4].o1 = sc->opts[sc->pc];
63029 	      if (float_optimize(sc, cdddr(car_x)))
63030 		{
63031 		  opc->v[2].o1 = sc->opts[sc->pc];
63032 		  if (float_optimize(sc, cddddr(car_x)))
63033 		    {
63034 		      opc->v[1].d_dddd_f = f;
63035 		      opc->v[0].fd = opt_d_dddd_ffff;
63036 		      opc->v[11].fd = opc->v[10].o1->v[0].fd;
63037 		      opc->v[9].fd = opc->v[8].o1->v[0].fd;
63038 		      opc->v[5].fd = opc->v[4].o1->v[0].fd;
63039 		      opc->v[3].fd = opc->v[2].o1->v[0].fd;
63040 		      return(true);
63041 		    }}}}}
63042   return_false(sc, car_x);
63043 }
63044 
63045 /* -------- d_add|multiply|subtract_any ------- */
63046 static s7_double opt_d_add_any_f(opt_info *o)
63047 {
63048   s7_double sum = 0.0;
63049   int32_t i;
63050   for (i = 0; i < o->v[1].i; i++)
63051     {
63052       opt_info *o1;
63053       o1 = o->v[i + 2].o1;
63054       sum += o1->v[0].fd(o1);
63055     }
63056   return(sum);
63057 }
63058 
63059 static s7_double opt_d_multiply_any_f(opt_info *o)
63060 {
63061   s7_double sum = 1.0;
63062   int32_t i;
63063   for (i = 0; i < o->v[1].i; i++)
63064     {
63065       opt_info *o1;
63066       o1 = o->v[i + 2].o1;
63067       sum *= o1->v[0].fd(o1);
63068     }
63069   return(sum);
63070 }
63071 
63072 static bool d_add_any_ok(s7_scheme *sc, opt_info *opc, s7_pointer car_x, int32_t len)
63073 {
63074   s7_pointer head;
63075   int32_t start;
63076   start = sc->pc;
63077   head = car(car_x);
63078   if ((head == sc->add_symbol) ||
63079       (head == sc->multiply_symbol))
63080     {
63081       s7_pointer p;
63082       int32_t cur_len;
63083       for (cur_len = 0, p = cdr(car_x); (is_pair(p)) && (cur_len < 12); p = cdr(p), cur_len++)
63084 	{
63085 	  opc->v[V_ind(cur_len + 2)].o1 = sc->opts[sc->pc];
63086 	  if (!float_optimize(sc, p))
63087 	    break;
63088 	}
63089       if (is_null(p))
63090 	{
63091 	  opc->v[1].i = cur_len;
63092 	  opc->v[0].fd = (head == sc->add_symbol) ? opt_d_add_any_f : opt_d_multiply_any_f;
63093 	  return(true);
63094 	}}
63095   pc_fallback(sc, start);
63096   return_false(sc, car_x);
63097 }
63098 
63099 
63100 /* -------- d_syntax -------- */
63101 static s7_double opt_set_d_d_f(opt_info *o)
63102 {
63103   s7_double x;
63104   x = o->v[3].fd(o->v[2].o1);
63105   slot_set_value(o->v[1].p, make_real(opt_sc(o), x));
63106   return(x);
63107 }
63108 
63109 static s7_double opt_set_d_d_fm(opt_info *o)
63110 {
63111   s7_double x;
63112   x = o->v[3].fd(o->v[2].o1);
63113   real(slot_value(o->v[1].p)) = x;
63114   return(x);
63115 }
63116 
63117 static bool d_syntax_ok(s7_scheme *sc, s7_pointer car_x, int32_t len)
63118 {
63119   if ((len == 3) &&
63120       (car(car_x) == sc->set_symbol))
63121     {
63122       opt_info *opc;
63123       opc = alloc_opo(sc);
63124       if (is_symbol(cadr(car_x)))
63125 	{
63126 	  s7_pointer settee;
63127 	  if ((is_immutable(cadr(car_x))) ||
63128 	      (symbol_has_setter(cadr(car_x))))
63129 	    return_false(sc, car_x);
63130 	  settee = lookup_slot_from(cadr(car_x), sc->curlet);
63131 	  if ((is_slot(settee)) &&
63132 	      (!is_immutable(settee)))
63133 	    {
63134 	      opt_info *o1;
63135 	      o1 = sc->opts[sc->pc];
63136 	      opc->v[1].p = settee;
63137 	      if ((!is_t_integer(caddr(car_x))) &&
63138 		  (is_t_real(slot_value(settee))) &&
63139 		  (float_optimize(sc, cddr(car_x))))
63140 		{
63141 		  opc->v[0].fd = (is_mutable_number(slot_value(opc->v[1].p))) ? opt_set_d_d_fm : opt_set_d_d_f;
63142 		  opc->v[2].o1 = o1;
63143 		  opc->v[3].fd = o1->v[0].fd;
63144 		  return(true);
63145 		}}}
63146       else
63147 	/* if is_pair(settee) get setter */
63148 	if ((is_pair(cadr(car_x))) &&
63149 	    (is_symbol(caadr(car_x))) &&
63150 	    (is_pair(cdadr(car_x))))
63151 	  {
63152 	    if (is_null(cddadr(car_x)))
63153 	      return(opt_float_vector_set(sc, opc, caadr(car_x), cdadr(car_x), NULL, cddr(car_x)));
63154 	    if (is_null(cdddr(cadr(car_x))))
63155 	      return(opt_float_vector_set(sc, opc, caadr(car_x), cdadr(car_x), cddadr(car_x), cddr(car_x)));
63156 	  }}
63157   return_false(sc, car_x);
63158 }
63159 
63160 static bool d_implicit_ok(s7_scheme *sc, s7_pointer car_x, int32_t len)
63161 {
63162   s7_pointer s_slot, slot;
63163   opt_info *opc;
63164   s_slot = lookup_slot_from(car(car_x), sc->curlet);
63165 
63166   if (!is_slot(s_slot))
63167     return_false(sc, car_x);
63168 
63169   if (is_float_vector(slot_value(s_slot)))
63170     {
63171       /* implicit float-vector-ref */
63172       if ((len == 2) &&
63173 	  (vector_rank(slot_value(s_slot)) == 1))
63174 	{
63175 	  opc = alloc_opo(sc);
63176 	  opc->v[1].p = s_slot;
63177 	  opc->v[3].d_7pi_f = float_vector_ref_d_7pi;
63178 	  slot = opt_integer_symbol(sc, cadr(car_x));
63179 	  if (slot)
63180 	    {
63181 	      opc->v[0].fd = opt_d_7pi_ss;
63182 	      opc->v[2].p = slot;
63183 	      if ((is_step_end(opc->v[2].p)) &&
63184 		  (denominator(slot_value(opc->v[2].p)) <= vector_length(slot_value(opc->v[1].p))))
63185 		opc->v[3].d_7pi_f = float_vector_ref_unchecked;
63186 	      return(true);
63187 	    }
63188 	  opc->v[10].o1 = sc->opts[sc->pc];
63189 	  if (int_optimize(sc, cdr(car_x)))
63190 	    {
63191 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
63192 	      opc->v[0].fd = opt_d_7pi_sf;
63193 	      return(true);
63194 	    }
63195 	  return_false(sc, car_x);
63196 	}
63197 
63198       if ((len == 3) &&
63199 	  (vector_rank(slot_value(s_slot)) == 2))
63200 	{
63201 	  opc = alloc_opo(sc);
63202 	  opc->v[1].p = s_slot;
63203 	  opc->v[4].d_7pii_f = float_vector_ref_d_7pii;
63204 	  slot = opt_integer_symbol(sc, cadr(car_x));
63205 	  if (slot)
63206 	    {
63207 	      opc->v[2].p = slot;
63208 	      slot = opt_integer_symbol(sc, caddr(car_x));
63209 	      if (slot)
63210 		{
63211 		  opc->v[3].p = slot;
63212 		  opc->v[0].fd = opt_d_7pii_sss;
63213 		  return(true);
63214 		}}
63215 	  opc->v[10].o1 = sc->opts[sc->pc];
63216 	  if (int_optimize(sc, cdr(car_x)))
63217 	    {
63218 	      opc->v[8].o1 = sc->opts[sc->pc];
63219 	      if (int_optimize(sc, cddr(car_x)))
63220 		{
63221 		  opc->v[0].fd = opt_d_7pii_sff;
63222 		  opc->v[11].fi = opc->v[10].o1->v[0].fi;
63223 		  opc->v[9].fi = opc->v[8].o1->v[0].fi;
63224 		  return(true);
63225 		}}}}
63226 
63227   if ((is_c_object(slot_value(s_slot))) &&
63228       (len == 2))
63229     {
63230       s7_d_7pi_t func;
63231       s7_pointer getf;
63232       getf = c_object_getf(sc, slot_value(s_slot));
63233       if (is_c_function(getf)) /* default is #f */
63234 	{
63235 	  func = s7_d_7pi_function(getf);
63236 	  if (func)
63237 	    {
63238 	      opc = alloc_opo(sc);
63239 	      opc->v[1].p = s_slot;
63240 	      opc->v[4].obj = (void *)c_object_value(slot_value(s_slot));
63241 	      opc->v[3].d_7pi_f = func;
63242 	      slot = opt_integer_symbol(sc, cadr(car_x));
63243 	      if (slot)
63244 		{
63245 		  opc->v[0].fd = opt_d_7pi_ss;
63246 		  opc->v[2].p = slot;
63247 		  return(true);
63248 		}
63249 	      opc->v[10].o1 = sc->opts[sc->pc];
63250 	      if (int_optimize(sc, cdr(car_x)))
63251 		{
63252 		  opc->v[11].fi = opc->v[10].o1->v[0].fi;
63253 		  opc->v[0].fd = opt_d_7pi_sf;
63254 		  return(true);
63255 		}}}}
63256   return_false(sc, car_x);
63257 }
63258 
63259 
63260 /* -------------------------------- bool opts -------------------------------- */
63261 static bool opt_b_s(opt_info *o) {return(slot_value(o->v[1].p) != opt_sc(o)->F);}
63262 
63263 static bool opt_bool_not_pair(s7_scheme *sc, s7_pointer car_x)
63264 {
63265   s7_pointer p;
63266   if (!is_symbol(car_x))
63267     return_false(sc, car_x); /* i.e. use cell_optimize */
63268   p = opt_simple_symbol(sc, car_x);
63269   if ((p) &&
63270       (s7_is_boolean(slot_value(p))))
63271     {
63272       opt_info *opc;
63273       opc = alloc_opo(sc);
63274       opc->v[1].p = p;
63275       opc->v[0].fb = opt_b_s;
63276       return(true);
63277     }
63278   return_false(sc, car_x);
63279 }
63280 
63281 /* -------- b_idp -------- */
63282 static bool opt_b_i_s(opt_info *o)  {return(o->v[2].b_i_f(integer(slot_value(o->v[1].p))));}
63283 static bool opt_b_i_f(opt_info *o)  {return(o->v[2].b_i_f(o->v[11].fi(o->v[10].o1)));}
63284 static bool opt_b_d_s(opt_info *o)  {return(o->v[2].b_d_f(real(slot_value(o->v[1].p))));}
63285 static bool opt_b_d_f(opt_info *o)  {return(o->v[2].b_d_f(o->v[11].fd(o->v[10].o1)));}
63286 static bool opt_b_p_s(opt_info *o)  {return(o->v[2].b_p_f(slot_value(o->v[1].p)));}
63287 static bool opt_b_p_f(opt_info *o)  {return(o->v[2].b_p_f(o->v[4].fp(o->v[3].o1)));}
63288 static bool opt_b_p_f_is_string(opt_info *o) {return(s7_is_string(o->v[4].fp(o->v[3].o1)));}
63289 static bool opt_b_7p_s(opt_info *o) {return(o->v[2].b_7p_f(opt_sc(o), slot_value(o->v[1].p)));}
63290 static bool opt_b_7p_f(opt_info *o) {return(o->v[2].b_7p_f(opt_sc(o), o->v[4].fp(o->v[3].o1)));}
63291 
63292 static bool opt_zero_mod(opt_info *o)
63293 {
63294   s7_int x;
63295   x = integer(slot_value(o->v[1].p));
63296   return((x % o->v[2].i) == 0);
63297 }
63298 
63299 static bool b_idp_ok(s7_scheme *sc, s7_pointer s_func, s7_pointer car_x, s7_pointer arg_type)
63300 {
63301   int32_t cur_index;
63302   s7_b_p_t bpf = NULL;
63303   s7_b_7p_t bpf7 = NULL;
63304   opt_info *opc;
63305 
63306   opc = alloc_opo(sc);
63307   cur_index = sc->pc;
63308 
63309   if (arg_type == sc->is_integer_symbol)
63310     {
63311       s7_b_i_t bif;
63312       bif = s7_b_i_function(s_func);
63313       if (bif)
63314 	{
63315 	  opc->v[2].b_i_f = bif;
63316 	  if (is_symbol(cadr(car_x)))
63317 	    {
63318 	      opc->v[1].p = lookup_slot_from(cadr(car_x), sc->curlet);
63319 	      opc->v[0].fb = opt_b_i_s;
63320 	      return(true);
63321 	    }
63322 	  opc->v[10].o1 = sc->opts[sc->pc];
63323 	  if (int_optimize(sc, cdr(car_x)))
63324 	    {
63325 	      opt_info *o1;
63326 	      o1 = sc->opts[sc->pc - 1];
63327 	      if ((car(car_x) == sc->is_zero_symbol) &&
63328 		  (o1->v[0].fi == opt_i_ii_sc) &&
63329 		  (o1->v[3].i_ii_f == modulo_i_ii_unchecked))
63330 		{
63331 		  opc->v[0].fb = opt_zero_mod;
63332 		  opc->v[1].p = o1->v[1].p;
63333 		  opc->v[2].i = o1->v[2].i;
63334 		  backup_pc(sc);
63335 		  return(true);
63336 		}
63337 	      opc->v[0].fb = opt_b_i_f;
63338 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
63339 	      return(true);
63340 	    }}}
63341   else
63342     {
63343       if (arg_type == sc->is_float_symbol)
63344 	{
63345 	  s7_b_d_t bdf;
63346 	  bdf = s7_b_d_function(s_func);
63347 	  if (bdf)
63348 	    {
63349 	      opc->v[2].b_d_f = bdf;
63350 	      if (is_symbol(cadr(car_x)))
63351 		{
63352 		  opc->v[1].p = lookup_slot_from(cadr(car_x), sc->curlet);
63353 		  opc->v[0].fb = opt_b_d_s;
63354 		  return(true);
63355 		}
63356 	      opc->v[10].o1 = sc->opts[sc->pc];
63357 	      if (float_optimize(sc, cdr(car_x)))
63358 		{
63359 		  opc->v[0].fb = opt_b_d_f;
63360 		  opc->v[11].fd = opc->v[10].o1->v[0].fd;
63361 		  return(true);
63362 		}}}}
63363   pc_fallback(sc, cur_index);
63364 
63365   bpf = s7_b_p_function(s_func);
63366   if (!bpf) bpf7 = s7_b_7p_function(s_func);
63367   if ((bpf) || (bpf7))
63368     {
63369       if (bpf)
63370 	opc->v[2].b_p_f = bpf;
63371       else opc->v[2].b_7p_f = bpf7;
63372       if (is_symbol(cadr(car_x)))
63373 	{
63374 	  s7_pointer p;
63375 	  p = opt_simple_symbol(sc, cadr(car_x));
63376 	  if (!p) return_false(sc, car_x);
63377 	  opc->v[1].p = p;
63378 	  opc->v[0].fb = (bpf) ? opt_b_p_s : opt_b_7p_s;
63379 	  return(true);
63380 	}
63381       opc->v[3].o1 = sc->opts[sc->pc];
63382       if (cell_optimize(sc, cdr(car_x)))
63383 	{
63384 	  opc->v[0].fb = (bpf) ? ((bpf == s7_is_string) ? opt_b_p_f_is_string : opt_b_p_f) : opt_b_7p_f;
63385 	  opc->v[4].fp = opc->v[3].o1->v[0].fp;
63386 	  return(true);
63387 	}}
63388   return_false(sc, car_x);
63389 }
63390 
63391 
63392 /* -------- b_pp -------- */
63393 static s7_pointer opt_arg_type(s7_scheme *sc, s7_pointer argp)
63394 {
63395   s7_pointer arg, slot;
63396   arg = car(argp);
63397   if (is_pair(arg))
63398     {
63399       if (is_symbol(car(arg)))
63400 	{
63401 	  if ((is_global(car(arg))) ||
63402 	      ((is_slot(global_slot(car(arg)))) &&
63403 	       (lookup_slot_from(car(arg), sc->curlet) == global_slot(car(arg)))))
63404 	    {
63405 	      s7_pointer a_func;
63406 	      a_func = global_value(car(arg));
63407 	      if (is_c_function(a_func))
63408 		{
63409 		  s7_pointer sig;
63410 		  sig = c_function_signature(a_func);
63411 		  if (is_pair(sig))
63412 		    {
63413 		      if ((car(sig) == sc->is_integer_symbol) ||
63414 			  ((is_pair(car(sig))) && (direct_memq(sc->is_integer_symbol, car(sig)))))
63415 			return(sc->is_integer_symbol);
63416 		      if ((car(sig) == sc->is_float_symbol) ||
63417 			  ((is_pair(car(sig))) && (direct_memq(sc->is_float_symbol, car(sig)))))
63418 			return(sc->is_float_symbol);
63419 		      if ((car(sig) == sc->is_real_symbol) ||
63420 			  (car(sig) == sc->is_number_symbol))
63421 			{
63422 			  int32_t start;
63423 			  start = sc->pc;
63424 			  if (int_optimize(sc, argp))
63425 			    {
63426 			      pc_fallback(sc, start);
63427 			      return(sc->is_integer_symbol);
63428 			    }
63429 			  if (float_optimize(sc, argp))
63430 			    {
63431 			      pc_fallback(sc, start);
63432 			      return(sc->is_float_symbol);
63433 			    }
63434 			  pc_fallback(sc, start);
63435 			}
63436 		      return(car(sig)); /* we want the function's return type in this context */
63437 		    }}}
63438 	  slot = lookup_slot_from(car(arg), sc->curlet);
63439 	  if ((is_slot(slot)) &&
63440 	      (is_sequence(slot_value(slot))))
63441 	    {
63442 	      s7_pointer sig;
63443 	      sig = s7_signature(sc, slot_value(slot));
63444 	      if (is_pair(sig))
63445 		return(car(sig));
63446 	    }}
63447       return(sc->T);
63448     }
63449   if (is_symbol(arg))
63450     {
63451       slot = opt_simple_symbol(sc, arg);
63452       if (!slot) return(sc->T);
63453 #if WITH_GMP
63454       if (is_big_number(slot_value(slot)))
63455 	return(sc->T);
63456       if ((is_t_integer(slot_value(slot))) &&
63457 	  (integer(slot_value(slot)) > QUOTIENT_INT_LIMIT))
63458 	return(sc->T);
63459       if ((is_t_real(slot_value(slot))) &&
63460 	  (real(slot_value(slot)) > QUOTIENT_FLOAT_LIMIT))
63461 	return(sc->T);
63462 #endif
63463       return(s7_type_of(sc, slot_value(slot)));
63464     }
63465   return(s7_type_of(sc, arg));
63466 }
63467 
63468 static bool opt_b_pp_ff(opt_info *o)
63469 {
63470   s7_pointer p1;
63471   p1 = o->v[9].fp(o->v[8].o1);
63472   return(o->v[3].b_pp_f(p1, o->v[11].fp(o->v[10].o1)));
63473 }
63474 
63475 static bool opt_b_7pp_ff(opt_info *o)
63476 {
63477   s7_pointer p1;
63478   p1 = o->v[9].fp(o->v[8].o1);
63479   return(o->v[3].b_7pp_f(opt_sc(o), p1, o->v[11].fp(o->v[10].o1)));
63480 }
63481 
63482 static bool opt_b_pp_sf(opt_info *o)      {return(o->v[3].b_pp_f(slot_value(o->v[1].p), o->v[11].fp(o->v[10].o1)));}
63483 static bool opt_b_pp_fs(opt_info *o)      {return(o->v[3].b_pp_f(o->v[11].fp(o->v[10].o1), slot_value(o->v[1].p)));}
63484 static bool opt_b_pp_ss(opt_info *o)      {return(o->v[3].b_pp_f(slot_value(o->v[1].p), slot_value(o->v[2].p)));}
63485 static bool opt_b_pp_sc(opt_info *o)      {return(o->v[3].b_pp_f(slot_value(o->v[1].p), o->v[2].p));}
63486 static bool opt_b_pp_sfo(opt_info *o)     {return(o->v[3].b_pp_f(slot_value(o->v[1].p), o->v[4].p_p_f(opt_sc(o), slot_value(o->v[2].p))));}
63487 static bool opt_b_7pp_sf(opt_info *o)     {return(o->v[3].b_7pp_f(opt_sc(o), slot_value(o->v[1].p), o->v[11].fp(o->v[10].o1)));}
63488 static bool opt_b_7pp_fs(opt_info *o)     {return(o->v[3].b_7pp_f(opt_sc(o), o->v[11].fp(o->v[10].o1), slot_value(o->v[1].p)));}
63489 static bool opt_b_7pp_ss(opt_info *o)     {return(o->v[3].b_7pp_f(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p)));}
63490 static bool opt_b_7pp_ss_lt(opt_info *o)  {return(lt_b_7pp(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p)));}
63491 static bool opt_b_7pp_ss_gt(opt_info *o)  {return(gt_b_7pp(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p)));}
63492 static bool opt_b_7pp_ss_char_lt(opt_info *o) {return(char_lt_b_7pp(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p)));}
63493 static bool opt_b_7pp_sc(opt_info *o)     {return(o->v[3].b_7pp_f(opt_sc(o), slot_value(o->v[1].p), o->v[2].p));}
63494 static bool opt_b_7pp_sfo(opt_info *o)    {return(o->v[3].b_7pp_f(opt_sc(o), slot_value(o->v[1].p), o->v[4].p_p_f(opt_sc(o), slot_value(o->v[2].p))));}
63495 static bool opt_is_equal_sfo(opt_info *o) {return(s7_is_equal(opt_sc(o), slot_value(o->v[1].p), o->v[4].p_p_f(opt_sc(o), slot_value(o->v[2].p))));}
63496 static bool opt_is_equivalent_sfo(opt_info *o) {return(s7_is_equivalent_1(opt_sc(o), slot_value(o->v[1].p), o->v[4].p_p_f(opt_sc(o), slot_value(o->v[2].p)), NULL));}
63497 static bool opt_b_pp_sf_char_eq(opt_info *o) {return(character(slot_value(o->v[1].p)) == character(o->v[11].fp(o->v[10].o1)));}
63498 
63499 static bool opt_car_equal_sf(opt_info *o)
63500 {
63501   s7_pointer p;
63502   p = slot_value(o->v[2].p);
63503   return(s7_is_equal(opt_sc(o), slot_value(o->v[1].p), (is_pair(p)) ? car(p) : g_car(opt_sc(o), set_plist_1(opt_sc(o), p))));
63504 }
63505 
63506 static bool opt_car_equivalent_sf(opt_info *o)
63507 {
63508   s7_pointer p;
63509   p = slot_value(o->v[2].p);
63510   return(s7_is_equivalent_1(opt_sc(o), slot_value(o->v[1].p), (is_pair(p)) ? car(p) : g_car(opt_sc(o), set_plist_1(opt_sc(o), p)), NULL));
63511 }
63512 
63513 static bool opt_b_7pp_car_sf(opt_info *o)
63514 {
63515   s7_pointer p;
63516   p = slot_value(o->v[2].p);
63517   return(o->v[3].b_7pp_f(opt_sc(o), slot_value(o->v[1].p), (is_pair(p)) ? car(p) : g_car(opt_sc(o), set_plist_1(opt_sc(o), p))));
63518 }
63519 
63520 static s7_pointer opt_p_p_s(opt_info *o);
63521 
63522 static s7_pointer opt_p_substring_uncopied_ssf(opt_info *o)
63523 {
63524   return(substring_uncopied_p_pii(opt_sc(o), slot_value(o->v[1].p),
63525 				  s7_integer_checked(opt_sc(o), slot_value(o->v[2].p)),
63526 				  s7_integer_checked(opt_sc(o), o->v[6].fp(o->v[5].o1))));
63527 }
63528 
63529 static bool opt_substring_equal_sf(opt_info *o) {return(scheme_strings_are_equal(slot_value(o->v[1].p), opt_p_substring_uncopied_ssf(o->v[10].o1)));}
63530 
63531 static bool b_pp_sf_combinable(s7_scheme *sc, opt_info *opc, bool bpf_case)
63532 {
63533   if ((sc->pc > 1) &&
63534       (opc == sc->opts[sc->pc - 2]))
63535     {
63536       opt_info *o1;
63537       o1 = sc->opts[sc->pc - 1];
63538       if (o1->v[0].fp == opt_p_p_s)
63539 	{
63540 	  opc->v[2].p = o1->v[1].p;
63541 	  opc->v[4].p_p_f = o1->v[2].p_p_f;
63542 	  if (bpf_case)
63543 	    opc->v[0].fb = opt_b_pp_sfo;
63544 	  else
63545 	    {
63546 	      if (opc->v[4].p_p_f == car_p_p)
63547 		opc->v[0].fb = ((opc->v[3].b_7pp_f == s7_is_equal) ? opt_car_equal_sf :
63548 				((opc->v[3].b_7pp_f == s7_is_equivalent) ? opt_car_equivalent_sf : opt_b_7pp_car_sf));
63549 	      else opc->v[0].fb = ((opc->v[3].b_7pp_f == s7_is_equal) ? opt_is_equal_sfo :
63550 				   ((opc->v[3].b_7pp_f == s7_is_equivalent) ? opt_is_equivalent_sfo : opt_b_7pp_sfo));
63551 	    }
63552 	  backup_pc(sc);
63553 	  return(true);
63554 	}}
63555   return_false(sc, NULL);
63556 }
63557 
63558 static bool opt_b_pp_ffo(opt_info *o)
63559 {
63560   s7_pointer b1;
63561   b1 = o->v[4].p_p_f(opt_sc(o), slot_value(o->v[1].p));
63562   return(o->v[3].b_pp_f(b1, o->v[5].p_p_f(opt_sc(o), slot_value(o->v[2].p))));
63563 }
63564 
63565 static bool opt_b_7pp_ffo(opt_info *o)
63566 {
63567   s7_pointer b1;
63568   b1 = o->v[4].p_p_f(opt_sc(o), slot_value(o->v[1].p));
63569   return(o->v[3].b_7pp_f(opt_sc(o), b1, o->v[5].p_p_f(opt_sc(o), slot_value(o->v[2].p))));
63570 }
63571 
63572 static bool opt_b_cadr_cadr(opt_info *o)
63573 {
63574   s7_pointer p1, p2;
63575   p1 = slot_value(o->v[1].p);
63576   p1 = ((is_pair(p1)) && (is_pair(cdr(p1)))) ? cadr(p1) : g_cadr(opt_sc(o), set_plist_1(opt_sc(o), p1));
63577   p2 = slot_value(o->v[2].p);
63578   p2 = ((is_pair(p2)) && (is_pair(cdr(p2)))) ? cadr(p2) : g_cadr(opt_sc(o), set_plist_1(opt_sc(o), p2));
63579   return(o->v[3].b_7pp_f(opt_sc(o), p1, p2));
63580 }
63581 
63582 static bool b_pp_ff_combinable(s7_scheme *sc, opt_info *opc, bool bpf_case)
63583 {
63584   if ((sc->pc > 2) &&
63585       (opc == sc->opts[sc->pc - 3]))
63586     {
63587       opt_info *o1, *o2;
63588       o1 = sc->opts[sc->pc - 2];
63589       o2 = sc->opts[sc->pc - 1];
63590       if ((o1->v[0].fp == opt_p_p_s) &&
63591 	  (o2->v[0].fp == opt_p_p_s))
63592 	{
63593 	  opc->v[1].p = o1->v[1].p;
63594 	  opc->v[4].p_p_f = o1->v[2].p_p_f;
63595 	  opc->v[2].p = o2->v[1].p;
63596 	  opc->v[5].p_p_f = o2->v[2].p_p_f;
63597 	  opc->v[0].fb = (bpf_case) ? opt_b_pp_ffo : (((opc->v[4].p_p_f == cadr_p_p) && (opc->v[5].p_p_f = cadr_p_p)) ? opt_b_cadr_cadr : opt_b_7pp_ffo);
63598 	  sc->pc -= 2;
63599 	  return(true);
63600 	}}
63601   return_false(sc, NULL);
63602 }
63603 
63604 static void check_b_types(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, bool (*fb)(opt_info *o))
63605 {
63606   if (s7_b_pp_unchecked_function(s_func))
63607     {
63608       s7_pointer call_sig, arg1_type, arg2_type;
63609       call_sig = c_function_signature(s_func);
63610       arg1_type = opt_arg_type(sc, cdr(car_x));
63611       arg2_type = opt_arg_type(sc, cddr(car_x));
63612       if ((cadr(call_sig) == arg1_type) &&                   /* not car(arg1_type) here: (string>? (string) (read-line)) */
63613 	  (caddr(call_sig) == arg2_type))
63614 	{
63615 	  opc->v[0].fb = fb;
63616 	  opc->v[3].b_pp_f = s7_b_pp_unchecked_function(s_func);
63617 	}}
63618 }
63619 
63620 static bool b_pp_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, s7_pointer arg1, s7_pointer arg2, bool bpf_case)
63621 {
63622   int32_t cur_index;
63623   opt_info *o1;
63624   cur_index = sc->pc;
63625   /* v[3] is set when we get here */
63626 
63627   if ((is_symbol(arg1)) &&
63628       (is_symbol(arg2)))
63629     {
63630       opc->v[1].p = opt_simple_symbol(sc, arg1);
63631       opc->v[2].p = opt_simple_symbol(sc, arg2);
63632       if ((opc->v[1].p) &&
63633 	  (opc->v[2].p))
63634 	{
63635 	  s7_b_7pp_t b7f;
63636 	  b7f = (bpf_case) ? NULL : opc->v[3].b_7pp_f;
63637 	  opc->v[0].fb = (bpf_case) ? opt_b_pp_ss :
63638 	                  ((b7f == lt_b_7pp) ? opt_b_7pp_ss_lt : ((b7f == gt_b_7pp) ? opt_b_7pp_ss_gt :
63639                            ((b7f == char_lt_b_7pp) ? opt_b_7pp_ss_char_lt : opt_b_7pp_ss)));
63640 	  return(true);
63641 	}}
63642   if (is_symbol(arg1))
63643     {
63644       opc->v[1].p = opt_simple_symbol(sc, arg1);
63645       if (!opc->v[1].p)
63646 	return_false(sc, car_x);
63647       if ((!is_symbol(arg2)) &&
63648 	  (!is_pair(arg2)))
63649 	{
63650 	  opc->v[2].p = arg2;
63651 	  opc->v[0].fb = (bpf_case) ? opt_b_pp_sc : opt_b_7pp_sc;
63652 	  check_b_types(sc, opc, s_func, car_x, opt_b_pp_sc);
63653 	  return(true);
63654 	}
63655       if (cell_optimize(sc, cddr(car_x)))
63656 	{
63657 	  if (!b_pp_sf_combinable(sc, opc, bpf_case))
63658 	    {
63659 	      opc->v[10].o1 = sc->opts[cur_index];
63660 	      opc->v[11].fp = opc->v[10].o1->v[0].fp;
63661 	      opc->v[0].fb = (bpf_case) ? opt_b_pp_sf : opt_b_7pp_sf;
63662 	      check_b_types(sc, opc, s_func, car_x, opt_b_pp_sf); /* this finds b_pp_unchecked cases */
63663 	      if ((opc->v[11].fp == opt_p_substring_uncopied_ssf) && (opc->v[3].b_pp_f == string_eq_b_unchecked))
63664 		opc->v[0].fb = opt_substring_equal_sf;
63665 	      if (opc->v[3].b_pp_f == char_eq_b_unchecked) opc->v[0].fb = opt_b_pp_sf_char_eq;
63666 	      return(true);
63667 	    }
63668 	  return(true);
63669 	}
63670       pc_fallback(sc, cur_index);
63671     }
63672   else
63673     if ((is_symbol(arg2)) &&
63674 	(is_pair(arg1)))
63675       {
63676 	opc->v[10].o1 = sc->opts[sc->pc];
63677 	if (cell_optimize(sc, cdr(car_x)))
63678 	  {
63679 	    opc->v[1].p = lookup_slot_from(arg2, sc->curlet);
63680 	    if ((!is_slot(opc->v[1].p)) ||
63681 		(has_methods(slot_value(opc->v[1].p))))
63682 	      return_false(sc, car_x);
63683 	    opc->v[11].fp = opc->v[10].o1->v[0].fp;
63684 	    opc->v[0].fb = (bpf_case) ? opt_b_pp_fs : opt_b_7pp_fs;
63685 	    check_b_types(sc, opc, s_func, car_x, opt_b_pp_fs);
63686 	    return(true);
63687 	  }
63688 	pc_fallback(sc, cur_index);
63689       }
63690   o1 = sc->opts[sc->pc];
63691   if (cell_optimize(sc, cdr(car_x)))
63692     {
63693       opc->v[10].o1 = sc->opts[sc->pc];
63694       if (cell_optimize(sc, cddr(car_x)))
63695 	{
63696 	  if (b_pp_ff_combinable(sc, opc, bpf_case))
63697 	    return(true);
63698 	  opc->v[0].fb = (bpf_case) ? opt_b_pp_ff : opt_b_7pp_ff;
63699 	  opc->v[8].o1 = o1;
63700 	  opc->v[9].fp = o1->v[0].fp;
63701 	  opc->v[11].fp = opc->v[10].o1->v[0].fp;
63702 	  check_b_types(sc, opc, s_func, car_x, opt_b_pp_ff);
63703 	  return(true);
63704 	}}
63705   return_false(sc, car_x);
63706 }
63707 
63708 /* -------- b_pi -------- */
63709 static bool opt_b_pi_fs(opt_info *o) {return(o->v[2].b_pi_f(opt_sc(o), o->v[11].fp(o->v[10].o1), integer(slot_value(o->v[1].p))));}
63710 static bool opt_b_pi_fs_num_eq(opt_info *o) {return(num_eq_b_pi(opt_sc(o), o->v[11].fp(o->v[10].o1), integer(slot_value(o->v[1].p))));}
63711 
63712 static bool b_pi_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, s7_pointer arg2)
63713 {
63714   s7_b_pi_t bpif;
63715   bpif = s7_b_pi_function(s_func);
63716   if (bpif)
63717     {
63718       opc->v[1].p = lookup_slot_from(arg2, sc->curlet); /* slot checked in opt_arg_type */
63719       opc->v[10].o1 = sc->opts[sc->pc];
63720       if (cell_optimize(sc, cdr(car_x)))
63721 	{
63722 	  opc->v[2].b_pi_f = bpif;
63723 	  opc->v[0].fb = (bpif == num_eq_b_pi) ? opt_b_pi_fs_num_eq : opt_b_pi_fs;
63724 	  opc->v[11].fp = opc->v[10].o1->v[0].fp;
63725 	  return(true);
63726 	}}
63727   return_false(sc, car_x);
63728 }
63729 
63730 
63731 /* -------- b_dd -------- */
63732 static bool opt_b_dd_ss(opt_info *o) {return(o->v[3].b_dd_f(real(slot_value(o->v[1].p)), real(slot_value(o->v[2].p))));}
63733 static bool opt_b_dd_ss_lt(opt_info *o) {return(real(slot_value(o->v[1].p)) < real(slot_value(o->v[2].p)));}
63734 static bool opt_b_dd_ss_gt(opt_info *o) {return(real(slot_value(o->v[1].p)) > real(slot_value(o->v[2].p)));}
63735 
63736 static bool opt_b_dd_sc(opt_info *o) {return(o->v[3].b_dd_f(real(slot_value(o->v[1].p)), o->v[2].x));}
63737 static bool opt_b_dd_sc_lt(opt_info *o) {return(real(slot_value(o->v[1].p)) < o->v[2].x);}
63738 static bool opt_b_dd_sc_geq(opt_info *o) {return(real(slot_value(o->v[1].p)) >= o->v[2].x);}
63739 static bool opt_b_dd_sc_eq(opt_info *o) {return(real(slot_value(o->v[1].p)) == o->v[2].x);}
63740 
63741 static bool opt_b_dd_sf(opt_info *o) {return(o->v[3].b_dd_f(real(slot_value(o->v[1].p)), o->v[11].fd(o->v[10].o1)));}
63742 static bool opt_b_dd_fs(opt_info *o) {return(o->v[3].b_dd_f(o->v[11].fd(o->v[10].o1), real(slot_value(o->v[1].p))));}
63743 static bool opt_b_dd_fs_gt(opt_info *o) {return(o->v[11].fd(o->v[10].o1) > real(slot_value(o->v[1].p)));}
63744 static bool opt_b_dd_fc(opt_info *o) {return(o->v[3].b_dd_f(o->v[11].fd(o->v[10].o1), o->v[1].x));}
63745 
63746 static bool opt_b_dd_ff(opt_info *o)
63747 {
63748   s7_double x1, x2;
63749   x1 = o->v[11].fd(o->v[10].o1);
63750   x2 = o->v[9].fd(o->v[8].o1);
63751   return(o->v[3].b_dd_f(x1, x2));
63752 }
63753 
63754 static bool b_dd_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, s7_pointer arg1, s7_pointer arg2)
63755 {
63756   s7_b_dd_t bif;
63757   int32_t cur_index;
63758   cur_index = sc->pc;
63759   bif = s7_b_dd_function(s_func);
63760   if (bif)
63761     {
63762       opc->v[3].b_dd_f = bif;
63763       if (is_symbol(arg1))
63764 	{
63765 	  opc->v[1].p = lookup_slot_from(arg1, sc->curlet);
63766 	  if (is_symbol(arg2))
63767 	    {
63768 	      opc->v[2].p = lookup_slot_from(arg2, sc->curlet);
63769 	      opc->v[0].fb = (bif == lt_b_dd) ? opt_b_dd_ss_lt : ((bif == gt_b_dd) ? opt_b_dd_ss_gt : opt_b_dd_ss);
63770 	      return(true);
63771 	    }
63772 	  if (is_t_real(arg2))
63773 	    {
63774 	      opc->v[2].x = s7_number_to_real(sc, arg2);
63775 	      opc->v[0].fb = (bif == lt_b_dd) ? opt_b_dd_sc_lt : ((bif == geq_b_dd) ? opt_b_dd_sc_geq : ((bif == num_eq_b_dd) ? opt_b_dd_sc_eq : opt_b_dd_sc));
63776 	      return(true);
63777 	    }
63778 	  opc->v[10].o1 = sc->opts[sc->pc];
63779 	  if (float_optimize(sc, cddr(car_x)))
63780 	    {
63781 	      opc->v[11].fd = opc->v[10].o1->v[0].fd;
63782 	      opc->v[0].fb = opt_b_dd_sf;
63783 	      return(true);
63784 	    }}
63785       pc_fallback(sc, cur_index);
63786       opc->v[10].o1 = sc->opts[sc->pc];
63787       if (float_optimize(sc, cdr(car_x)))
63788 	{
63789 	  opc->v[11].fd = opc->v[10].o1->v[0].fd;
63790 	  if (is_symbol(arg2))
63791 	    {
63792 	      opc->v[1].p = lookup_slot_from(arg2, sc->curlet);
63793 	      opc->v[0].fb = (bif == gt_b_dd) ? opt_b_dd_fs_gt : opt_b_dd_fs;
63794 	      return(true);
63795 	    }
63796 	  if (is_small_real(arg2))
63797 	    {
63798 	      opc->v[1].x = s7_number_to_real(sc, arg2);
63799 	      opc->v[0].fb = opt_b_dd_fc;
63800 	      return(true);
63801 	    }
63802 	  opc->v[8].o1 = sc->opts[sc->pc];
63803 	  if (float_optimize(sc, cddr(car_x)))
63804 	    {
63805 	      opc->v[9].fd = opc->v[8].o1->v[0].fd;
63806 	      opc->v[0].fb = opt_b_dd_ff;
63807 	      return(true);
63808 	    }}}
63809   pc_fallback(sc, cur_index);
63810   return_false(sc, car_x);
63811 }
63812 
63813 
63814 /* -------- b_ii -------- */
63815 static bool opt_b_ii_ss(opt_info *o)     {return(o->v[3].b_ii_f(integer(slot_value(o->v[1].p)), integer(slot_value(o->v[2].p))));}
63816 static bool opt_b_ii_ss_lt(opt_info *o)  {return(integer(slot_value(o->v[1].p)) < integer(slot_value(o->v[2].p)));}
63817 static bool opt_b_ii_ss_gt(opt_info *o)  {return(integer(slot_value(o->v[1].p)) > integer(slot_value(o->v[2].p)));}
63818 static bool opt_b_ii_ss_leq(opt_info *o) {return(integer(slot_value(o->v[1].p)) <= integer(slot_value(o->v[2].p)));}
63819 static bool opt_b_ii_ss_geq(opt_info *o) {return(integer(slot_value(o->v[1].p)) >= integer(slot_value(o->v[2].p)));}
63820 static bool opt_b_ii_ss_eq(opt_info *o)  {return(integer(slot_value(o->v[1].p)) == integer(slot_value(o->v[2].p)));}
63821 static bool opt_b_ii_sc(opt_info *o)     {return(o->v[3].b_ii_f(integer(slot_value(o->v[1].p)), o->v[2].i));}
63822 static bool opt_b_ii_sc_lt(opt_info *o)  {return(integer(slot_value(o->v[1].p)) < o->v[2].i);}
63823 static bool opt_b_ii_sc_leq(opt_info *o) {return(integer(slot_value(o->v[1].p)) <= o->v[2].i);}
63824 static bool opt_b_ii_sc_gt(opt_info *o)  {return(integer(slot_value(o->v[1].p)) > o->v[2].i);}
63825 static bool opt_b_ii_sc_geq(opt_info *o) {return(integer(slot_value(o->v[1].p)) >= o->v[2].i);}
63826 static bool opt_b_ii_sc_eq(opt_info *o)  {return(integer(slot_value(o->v[1].p)) == o->v[2].i);}
63827 
63828 static bool opt_b_7ii_ss(opt_info *o)    {return(o->v[3].b_7ii_f(opt_sc(o), integer(slot_value(o->v[1].p)), integer(slot_value(o->v[2].p))));}
63829 static bool opt_b_7ii_sc(opt_info *o)    {return(o->v[3].b_7ii_f(opt_sc(o), integer(slot_value(o->v[1].p)), o->v[2].i));}
63830 static bool opt_b_7ii_sc_bit(opt_info *o) {return((integer(slot_value(o->v[1].p)) & ((int64_t)(1LL << o->v[2].i))) != 0);}
63831 
63832 static bool opt_b_ii_ff(opt_info *o)
63833 {
63834   s7_int i1, i2;
63835   i1 = o->v[11].fi(o->v[10].o1);
63836   i2 = o->v[9].fi(o->v[8].o1);
63837   return(o->v[3].b_ii_f(i1, i2));
63838 }
63839 
63840 static bool opt_b_ii_fs(opt_info *o) {return(o->v[3].b_ii_f(o->v[11].fi(o->v[10].o1), integer(slot_value(o->v[2].p))));}
63841 static bool opt_b_ii_sf(opt_info *o) {return(o->v[3].b_ii_f(integer(slot_value(o->v[1].p)), o->v[11].fi(o->v[10].o1)));}
63842 static bool opt_b_ii_sf_eq(opt_info *o) {return(integer(slot_value(o->v[1].p)) == o->v[11].fi(o->v[10].o1));}
63843 static bool opt_b_ii_fc(opt_info *o) {return(o->v[3].b_ii_f(o->v[11].fi(o->v[10].o1), o->v[2].i));}
63844 static bool opt_b_ii_fc_eq(opt_info *o) {return(o->v[11].fi(o->v[10].o1) == o->v[2].i);}
63845 
63846 static bool b_ii_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, s7_pointer arg1, s7_pointer arg2)
63847 {
63848   s7_b_ii_t bif;
63849   s7_b_7ii_t b7if = NULL;
63850   bif = s7_b_ii_function(s_func);
63851   if (!bif) b7if = s7_b_7ii_function(s_func);
63852   if ((bif) || (b7if))
63853     {
63854       if (bif) opc->v[3].b_ii_f = bif; else opc->v[3].b_7ii_f = b7if;
63855       if (is_symbol(arg1))
63856 	{
63857 	  opc->v[1].p = lookup_slot_from(arg1, sc->curlet);
63858 	  if (is_symbol(arg2))
63859 	    {
63860 	      opc->v[2].p = lookup_slot_from(arg2, sc->curlet);
63861 
63862 	      opc->v[0].fb = (bif == lt_b_ii) ? opt_b_ii_ss_lt :
63863 		              ((bif == leq_b_ii) ? opt_b_ii_ss_leq :
63864 			       ((bif == gt_b_ii) ? opt_b_ii_ss_gt :
63865 				((bif == geq_b_ii) ? opt_b_ii_ss_geq :
63866 				 ((bif == num_eq_b_ii) ? opt_b_ii_ss_eq :
63867 				  ((bif) ? opt_b_ii_ss : opt_b_7ii_ss)))));
63868 	      return(true);
63869 	    }
63870 	  if (is_t_integer(arg2))
63871 	    {
63872 	      opc->v[2].i = integer(arg2);
63873 	      opc->v[0].fb = (bif == lt_b_ii) ? opt_b_ii_sc_lt :
63874 		              ((bif == leq_b_ii) ? opt_b_ii_sc_leq :
63875 			       ((bif == gt_b_ii) ? opt_b_ii_sc_gt :
63876 				((bif == geq_b_ii) ? opt_b_ii_sc_geq :
63877 				 ((bif == num_eq_b_ii) ? opt_b_ii_sc_eq :
63878 				  (((b7if == logbit_b_7ii) && (integer(arg2) >= 0) && (integer(arg2) < S7_INT_BITS)) ? opt_b_7ii_sc_bit :
63879 				   ((bif) ? opt_b_ii_sc : opt_b_7ii_sc))))));
63880 	      return(true);
63881 	    }
63882 	  opc->v[10].o1 = sc->opts[sc->pc];
63883 	  if ((bif) && (int_optimize(sc, cddr(car_x))))
63884 	    {
63885 	      opc->v[0].fb = (bif == num_eq_b_ii) ? opt_b_ii_sf_eq : opt_b_ii_sf;
63886 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
63887 	      return(true);
63888 	    }
63889 	  return_false(sc, car_x);
63890 	}
63891       if (!bif) return_false(sc, car_x);
63892 
63893       if (is_symbol(arg2))
63894 	{
63895 	  opc->v[10].o1 = sc->opts[sc->pc];
63896 	  if (int_optimize(sc, cdr(car_x)))
63897 	    {
63898 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
63899 	      opc->v[2].p = lookup_slot_from(arg2, sc->curlet);
63900 	      opc->v[0].fb = opt_b_ii_fs;
63901 	      return(true);
63902 	    }
63903 	  return_false(sc, car_x);
63904 	}
63905       opc->v[10].o1 = sc->opts[sc->pc];
63906       if (int_optimize(sc, cdr(car_x)))
63907 	{
63908 	  opc->v[11].fi = opc->v[10].o1->v[0].fi;
63909 	  if (is_t_integer(arg2))
63910 	    {
63911 	      opc->v[2].i = integer(arg2);
63912 	      opc->v[0].fb = (bif == num_eq_b_ii) ? opt_b_ii_fc_eq : opt_b_ii_fc;
63913 	      return(true);
63914 	    }
63915 	  opc->v[8].o1 = sc->opts[sc->pc];
63916 	  if (int_optimize(sc, cddr(car_x)))
63917 	    {
63918 	      opc->v[9].fi = opc->v[8].o1->v[0].fi;
63919 	      opc->v[0].fb = opt_b_ii_ff;
63920 	      return(true);
63921 	    }}}
63922   return_false(sc, car_x);
63923 }
63924 
63925 /* -------- b_or|and -------- */
63926 static bool opt_and_bb(opt_info *o) {return((o->v[3].fb(o->v[2].o1)) ? o->v[11].fb(o->v[10].o1) : false);}
63927 
63928 static bool opt_and_any_b(opt_info *o)
63929 {
63930   int32_t i;
63931   for (i = 0; i < o->v[1].i; i++)
63932     {
63933       opt_info *o1;
63934       o1 = o->v[i + 3].o1;
63935       if (!o1->v[0].fb(o1))
63936 	return(false);
63937     }
63938   return(true);
63939 }
63940 
63941 static bool opt_or_bb(opt_info *o) {return((o->v[3].fb(o->v[2].o1)) ? true : o->v[11].fb(o->v[10].o1));}
63942 
63943 static bool opt_or_any_b(opt_info *o)
63944 {
63945   int32_t i;
63946   for (i = 0; i < o->v[1].i; i++)
63947     {
63948       opt_info *o1;
63949       o1 = o->v[i + 3].o1;
63950       if (o1->v[0].fb(o1))
63951 	return(true);
63952     }
63953   return(false);
63954 }
63955 
63956 static bool opt_b_or_and(s7_scheme *sc, s7_pointer car_x, int32_t len, int32_t is_and)
63957 {
63958   opt_info *opc;
63959   s7_pointer p;
63960   int32_t i;
63961 
63962   opc = alloc_opo(sc);
63963   if (len == 3)
63964     {
63965       opt_info *o1;
63966       o1 = sc->opts[sc->pc];
63967       if (bool_optimize_nw(sc, cdr(car_x)))
63968 	{
63969 	  opt_info *o2;
63970 	  o2 = sc->opts[sc->pc];
63971 	  if (bool_optimize_nw(sc, cddr(car_x)))
63972 	    {
63973 	      opc->v[10].o1 = o2;
63974 	      opc->v[11].fb = o2->v[0].fb;
63975 	      opc->v[0].fb = (is_and) ? opt_and_bb : opt_or_bb;
63976 	      opc->v[2].o1 = o1;
63977 	      opc->v[3].fb = o1->v[0].fb;
63978 	      return(true);
63979 	    }}
63980       return_false(sc, car_x);
63981     }
63982   opc->v[1].i = (len - 1);
63983   for (i = 0, p = cdr(car_x); (is_pair(p)) && (i < 12); i++, p = cdr(p))
63984     {
63985       opc->v[V_ind(i + 3)].o1 = sc->opts[sc->pc];
63986       if (!bool_optimize_nw(sc, p))
63987 	break;
63988     }
63989   if (is_null(p))
63990     {
63991       opc->v[0].fb = (is_and) ? opt_and_any_b : opt_or_any_b;
63992       return(true);
63993     }
63994   return_false(sc, car_x);
63995 }
63996 
63997 static bool opt_b_and(s7_scheme *sc, s7_pointer car_x, int32_t len) {return(opt_b_or_and(sc, car_x, len, true));}
63998 static bool opt_b_or(s7_scheme *sc, s7_pointer car_x, int32_t len)  {return(opt_b_or_and(sc, car_x, len, false));}
63999 
64000 
64001 /* ---------------------------------------- cell opts ---------------------------------------- */
64002 
64003 static s7_pointer opt_p_c(opt_info *o) {return(o->v[1].p);}
64004 static s7_pointer opt_p_s(opt_info *o) {return(slot_value(o->v[1].p));}
64005 
64006 static bool opt_cell_not_pair(s7_scheme *sc, s7_pointer car_x)
64007 {
64008   s7_pointer p;
64009   opt_info *opc;
64010   if (!is_symbol(car_x))
64011     {
64012       opc = alloc_opo(sc);
64013       opc->v[1].p = car_x;
64014       opc->v[0].fp = opt_p_c;
64015       return(true);
64016     }
64017   p = opt_simple_symbol(sc, car_x);
64018   if (p)
64019     {
64020       opc = alloc_opo(sc);
64021       opc->v[1].p = p;
64022       opc->v[0].fp = opt_p_s;
64023       return(true);
64024     }
64025   return_false(sc, car_x);
64026 }
64027 
64028 /* -------- p -------- */
64029 #define is_opt_safe(P) ((optimize_op(P) >= OP_SAFE_C_S) && (!is_unknown_op(optimize_op(P))))
64030 
64031 #define cf_call(Sc, Car_x, S_func, Num) \
64032    (((is_optimized(Car_x)) && (is_opt_safe(Car_x))) ? fn_proc(Car_x) : c_function_call(c_function_chooser(S_func)(Sc, S_func, Num, Car_x, false)))
64033 
64034 static s7_pointer opt_p_f(opt_info *o)  {return(o->v[1].p_f(opt_sc(o)));}
64035 static s7_pointer opt_p_call(opt_info *o) {return(o->v[1].call(opt_sc(o), opt_sc(o)->nil));}
64036 
64037 static bool p_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
64038 {
64039   s7_p_t func;
64040   func = s7_p_function(s_func);
64041   if (func)
64042     {
64043       opc->v[1].p_f = func;
64044       opc->v[0].fp = opt_p_f;
64045       return(true);
64046     }
64047   if ((is_safe_procedure(s_func)) &&
64048       (c_function_required_args(s_func) == 0))
64049     {
64050       opc->v[1].call = cf_call(sc, car_x, s_func, 0);
64051       opc->v[0].fp = opt_p_call;
64052       return(true);
64053     }
64054   return_false(sc, car_x);
64055 }
64056 
64057 /* -------- p_p -------- */
64058 static s7_pointer opt_p_p_c(opt_info *o)  {return(o->v[2].p_p_f(opt_sc(o), o->v[1].p));}
64059 static s7_pointer opt_p_i_c(opt_info *o)  {return(make_integer(opt_sc(o), o->v[2].i_i_f(o->v[1].i)));}
64060 static s7_pointer opt_p_7i_c(opt_info *o) {return(make_integer(opt_sc(o), o->v[2].i_7i_f(opt_sc(o), o->v[1].i)));}
64061 static s7_pointer opt_p_d_c(opt_info *o)  {return(make_real(opt_sc(o), o->v[2].d_d_f(o->v[1].x)));}
64062 static s7_pointer opt_p_7d_c(opt_info *o) {return(make_real(opt_sc(o), o->v[2].d_7d_f(opt_sc(o), o->v[1].x)));}
64063 static s7_pointer opt_p_p_s(opt_info *o)  {return(o->v[2].p_p_f(opt_sc(o), slot_value(o->v[1].p)));}
64064 static s7_pointer opt_p_p_s_abs(opt_info *o) {return(abs_p_p(opt_sc(o), slot_value(o->v[1].p)));}
64065 static s7_pointer opt_p_p_f(opt_info *o)  {return(o->v[2].p_p_f(opt_sc(o), o->v[4].fp(o->v[3].o1)));}
64066 static s7_pointer opt_p_p_f1(opt_info *o) {return(o->v[2].p_p_f(opt_sc(o), o->v[3].p_p_f(opt_sc(o), slot_value(o->v[1].p))));}
64067 
64068 static bool p_p_f_combinable(s7_scheme *sc, opt_info *opc)
64069 {
64070   if ((sc->pc > 1) &&
64071       (opc == sc->opts[sc->pc - 2]))
64072     {
64073       opt_info *o1;
64074       o1 = sc->opts[sc->pc - 1];
64075       if (o1->v[0].fp == opt_p_p_s)
64076 	{
64077 	  opc->v[3].p_p_f = o1->v[2].p_p_f;
64078 	  opc->v[1].p = o1->v[1].p;
64079 	  opc->v[0].fp = opt_p_p_f1;
64080 	  backup_pc(sc);
64081 	  return(true);
64082 	}}
64083   return_false(sc, NULL);
64084 }
64085 
64086 static s7_pointer opt_p_call_f(opt_info *o) {return(o->v[2].call(opt_sc(o), set_plist_1(opt_sc(o), o->v[5].fp(o->v[4].o1))));}
64087 static s7_pointer opt_p_call_s(opt_info *o) {return(o->v[2].call(opt_sc(o), set_plist_1(opt_sc(o), slot_value(o->v[1].p))));}
64088 static s7_pointer opt_p_call_c(opt_info *o) {return(o->v[2].call(opt_sc(o), set_plist_1(opt_sc(o), o->v[1].p)));}
64089 
64090 static bool p_p_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
64091 {
64092   s7_p_p_t ppf;
64093   int32_t start;
64094   start = sc->pc;
64095   if (is_t_integer(cadr(car_x)))
64096     {
64097       s7_i_i_t iif;
64098       s7_i_7i_t i7if;
64099       opc->v[1].i = integer(cadr(car_x));
64100       iif = s7_i_i_function(s_func);
64101       if (iif)
64102 	{
64103 	  opc->v[2].i_i_f = iif;
64104 	  opc->v[0].fp = opt_p_i_c;
64105 	  return(true);
64106 	}
64107       i7if = s7_i_7i_function(s_func);
64108       if (i7if)
64109 	{
64110 	  opc->v[2].i_7i_f = i7if;
64111 	  opc->v[0].fp = opt_p_7i_c;
64112 	  return(true);
64113 	}}
64114   if (is_t_real(cadr(car_x)))
64115     {
64116       s7_d_d_t ddf;
64117       s7_d_7d_t d7df;
64118       opc->v[1].x = real(cadr(car_x));
64119       ddf = s7_d_d_function(s_func);
64120       if (ddf)
64121 	{
64122 	  opc->v[2].d_d_f = ddf;
64123 	  opc->v[0].fp = opt_p_d_c;
64124 	  return(true);
64125 	}
64126       d7df = s7_d_7d_function(s_func);
64127       if (d7df)
64128 	{
64129 	  opc->v[2].d_7d_f = d7df;
64130 	  opc->v[0].fp = opt_p_7d_c;
64131 	  return(true);
64132 	}}
64133   ppf = s7_p_p_function(s_func);
64134   if (ppf)
64135     {
64136       opt_info *o1;
64137       opc->v[2].p_p_f = ppf;
64138       if ((ppf == symbol_to_string_p_p) &&
64139 	  (is_optimized(car_x)) &&
64140 	  (fn_proc(car_x) == g_symbol_to_string_uncopied))
64141 	opc->v[2].p_p_f = symbol_to_string_uncopied_p;
64142 
64143       if (is_symbol(cadr(car_x)))
64144 	{
64145 	  opc->v[1].p = opt_simple_symbol(sc, cadr(car_x));
64146 	  if (!opc->v[1].p)
64147 	    return_false(sc, car_x);
64148 	  opc->v[0].fp = (ppf == abs_p_p) ? opt_p_p_s_abs : opt_p_p_s;
64149 	  return(true);
64150 	}
64151       if (!is_pair(cadr(car_x)))
64152 	{
64153 	  opc->v[1].p = cadr(car_x);
64154 	  opc->v[0].fp = opt_p_p_c;
64155 	  return(true);
64156 	}
64157       o1 = sc->opts[sc->pc];
64158       if (cell_optimize(sc, cdr(car_x)))
64159 	{
64160 	  if (!p_p_f_combinable(sc, opc))
64161 	    {
64162 	      opc->v[0].fp = opt_p_p_f;
64163 	      if (caadr(car_x) == sc->string_ref_symbol)
64164 		{
64165 		  if (opc->v[2].p_p_f == char_upcase_p_p)
64166 		    opc->v[2].p_p_f = char_upcase_p_p_unchecked;
64167 		  else
64168 		    if (opc->v[2].p_p_f == is_char_whitespace_p_p)
64169 		      opc->v[2].p_p_f = is_char_whitespace_p_p_unchecked;
64170 		}
64171 	      opc->v[3].o1 = o1;
64172 	      opc->v[4].fp = o1->v[0].fp;
64173 	      return(true);
64174 	    }
64175 	  return(true);
64176 	}}
64177   pc_fallback(sc, start);
64178   if ((is_safe_procedure(s_func)) &&
64179       (c_function_required_args(s_func) <= 1) &&
64180       (c_function_all_args(s_func) >= 1))
64181     {
64182       s7_pointer slot;
64183       opc->v[2].call = cf_call(sc, car_x, s_func, 1);
64184       if (is_symbol(cadr(car_x)))
64185 	{
64186 	  slot = opt_simple_symbol(sc, cadr(car_x));
64187 	  if (slot)
64188 	    {
64189 	      opc->v[1].p = slot;
64190 	      opc->v[0].fp = opt_p_call_s;
64191 	      return(true);
64192 	    }}
64193       else
64194 	{
64195 	  opt_info *o1;
64196 	  if (!is_pair(cadr(car_x)))
64197 	    {
64198 	      opc->v[1].p = cadr(car_x);
64199 	      opc->v[0].fp = opt_p_call_c;
64200 	      return(true);
64201 	    }
64202 	  o1 = sc->opts[sc->pc];
64203 	  if (cell_optimize(sc, cdr(car_x)))
64204 	    {
64205 	      opc->v[0].fp = opt_p_call_f;
64206 	      opc->v[4].o1 = o1;
64207 	      opc->v[5].fp = o1->v[0].fp;
64208 	      return(true);
64209 	    }}}
64210   return_false(sc, car_x);
64211 }
64212 
64213 /* -------- p_i -------- */
64214 static s7_pointer opt_p_i_s(opt_info *o) {return(o->v[2].p_i_f(opt_sc(o), integer(slot_value(o->v[1].p))));}
64215 static s7_pointer opt_p_i_f(opt_info *o) {return(o->v[2].p_i_f(opt_sc(o), o->v[4].fi(o->v[3].o1)));}
64216 static s7_pointer opt_p_i_f_intc(opt_info *o) {return(integer_to_char_p_i(opt_sc(o), o->v[4].fi(o->v[3].o1)));}
64217 
64218 static bool p_i_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, int32_t pstart)
64219 {
64220   s7_p_i_t ifunc;
64221   ifunc = s7_p_i_function(s_func);
64222   if (ifunc)
64223     {
64224       s7_pointer p;
64225       p = opt_integer_symbol(sc, cadr(car_x));
64226       if (p)
64227 	{
64228 	  opc->v[1].p = p;
64229 	  opc->v[2].p_i_f = ifunc;
64230 	  opc->v[0].fp = opt_p_i_s;
64231 	  return(true);
64232 	}
64233       if (int_optimize(sc, cdr(car_x)))
64234 	{
64235 	  opc->v[2].p_i_f = ifunc;
64236 	  opc->v[0].fp = (ifunc == integer_to_char_p_i) ? opt_p_i_f_intc : opt_p_i_f;
64237 	  opc->v[3].o1 = sc->opts[pstart];
64238 	  opc->v[4].fi = sc->opts[pstart]->v[0].fi;
64239 	  return(true);
64240 	}}
64241   pc_fallback(sc, pstart);
64242   return_false(sc, car_x);
64243 }
64244 
64245 /* -------- p_ii -------- */
64246 static s7_pointer opt_p_ii_ss(opt_info *o) {return(o->v[3].p_ii_f(opt_sc(o), integer(slot_value(o->v[1].p)), integer(slot_value(o->v[2].p))));}
64247 static s7_pointer opt_p_ii_fs(opt_info *o) {return(o->v[3].p_ii_f(opt_sc(o), o->v[11].fi(o->v[10].o1), integer(slot_value(o->v[2].p))));}
64248 
64249 static s7_pointer opt_p_ii_ff(opt_info *o)
64250 {
64251   s7_int i1;
64252   i1 = o->v[11].fi(o->v[10].o1);
64253   return(o->v[3].p_ii_f(opt_sc(o), i1, o->v[9].fi(o->v[8].o1)));
64254 }
64255 
64256 static bool p_ii_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, int32_t pstart)
64257 {
64258   s7_p_ii_t ifunc;
64259   ifunc = s7_p_ii_function(s_func);
64260   if (ifunc)
64261     {
64262       s7_pointer p2;
64263       p2 = opt_integer_symbol(sc, caddr(car_x));
64264       if (p2)
64265 	{
64266 	  s7_pointer p1;
64267 	  p1 = opt_integer_symbol(sc, cadr(car_x));
64268 	  if (p1)
64269 	    {
64270 	      opc->v[1].p = p1;
64271 	      opc->v[2].p = p2;
64272 	      opc->v[3].p_ii_f = ifunc;
64273 	      opc->v[0].fp = opt_p_ii_ss;
64274 	      return(true);
64275 	    }
64276 	  opc->v[10].o1 = sc->opts[sc->pc];
64277 	  if (int_optimize(sc, cdr(car_x)))
64278 	    {
64279 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
64280 	      opc->v[2].p = p2;
64281 	      opc->v[3].p_ii_f = ifunc;
64282 	      opc->v[0].fp = opt_p_ii_fs;
64283 	      return(true);
64284 	    }
64285 	  pc_fallback(sc, pstart);
64286 	  return_false(sc, car_x);
64287 	}
64288       opc->v[10].o1 = sc->opts[sc->pc];
64289       if (int_optimize(sc, cdr(car_x)))
64290 	{
64291 	  opc->v[8].o1 = sc->opts[sc->pc];
64292 	  if (int_optimize(sc, cddr(car_x)))
64293 	    {
64294 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
64295 	      opc->v[9].fi = opc->v[8].o1->v[0].fi;
64296 	      opc->v[3].p_ii_f = ifunc;
64297 	      opc->v[0].fp = opt_p_ii_ff;
64298 	      return(true);
64299 	    }}}
64300   pc_fallback(sc, pstart);
64301   return_false(sc, car_x);
64302 }
64303 
64304 /* -------- p_d -------- */
64305 static s7_pointer opt_p_d_s(opt_info *o) {return(o->v[2].p_d_f(opt_sc(o), real_to_double(opt_sc(o), slot_value(o->v[1].p), "p_d")));}
64306 static s7_pointer opt_p_d_f(opt_info *o) {return(o->v[2].p_d_f(opt_sc(o), o->v[4].fd(o->v[3].o1)));}
64307 
64308 static bool p_d_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, int32_t pstart)
64309 {
64310   s7_p_d_t ifunc;
64311   ifunc = s7_p_d_function(s_func);
64312   if (ifunc)
64313     {
64314       s7_pointer p;
64315       opt_info *o1;
64316       p = opt_float_symbol(sc, cadr(car_x));
64317       if (p)
64318 	{
64319 	  opc->v[1].p = p;
64320 	  opc->v[2].p_d_f = ifunc;
64321 	  opc->v[0].fp = opt_p_d_s;
64322 	  return(true);
64323 	}
64324       if ((is_number(cadr(car_x))) && (!is_t_real(cadr(car_x))))
64325 	return_false(sc, car_x);
64326       o1 = sc->opts[sc->pc];
64327       if (float_optimize(sc, cdr(car_x)))
64328 	{
64329 	  opc->v[2].p_d_f = ifunc;
64330 	  opc->v[0].fp = opt_p_d_f;
64331 	  opc->v[3].o1 = o1;
64332 	  opc->v[4].fd = o1->v[0].fd;
64333 	  return(true);
64334 	}}
64335   pc_fallback(sc, pstart);
64336   return_false(sc, car_x);
64337 }
64338 
64339 /* -------- p_dd -------- */
64340 static s7_pointer opt_p_dd_sc(opt_info *o) {return(o->v[3].p_dd_f(opt_sc(o), real_to_double(opt_sc(o), slot_value(o->v[1].p), "p_dd"), o->v[2].x));}
64341 static s7_pointer opt_p_dd_cs(opt_info *o) {return(o->v[3].p_dd_f(opt_sc(o), o->v[2].x, real_to_double(opt_sc(o), slot_value(o->v[1].p), "p_dd")));}
64342 static s7_pointer opt_p_dd_cc(opt_info *o) {return(o->v[3].p_dd_f(opt_sc(o), o->v[1].x, o->v[2].x));}
64343 
64344 static bool p_dd_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, int32_t pstart)
64345 {
64346   s7_p_dd_t ifunc;
64347   ifunc = s7_p_dd_function(s_func);
64348   if (ifunc)
64349     {
64350       s7_pointer arg1, arg2, slot;
64351       arg1 = cadr(car_x);
64352       arg2 = caddr(car_x);
64353       if (is_t_real(arg2))
64354 	{
64355 	  if (is_t_real(arg1))
64356 	    {
64357 	      opc->v[1].x = real(arg1);
64358 	      opc->v[2].x = real(arg2);
64359 	      opc->v[3].p_dd_f = ifunc;
64360 	      opc->v[0].fp = opt_p_dd_cc;
64361 	      return(true);
64362 	    }
64363 	  slot = opt_real_symbol(sc, arg1);
64364 	  if (slot)
64365 	    {
64366 	      opc->v[2].x = real(arg2);
64367 	      opc->v[1].p = slot;
64368 	      opc->v[3].p_dd_f = ifunc;
64369 	      opc->v[0].fp = opt_p_dd_sc;
64370 	      return(true);
64371 	    }}
64372       if (is_t_real(arg1))
64373 	{
64374 	  slot = opt_real_symbol(sc, arg2);
64375 	  if (slot)
64376 	    {
64377 	      opc->v[2].x = real(arg1);
64378 	      opc->v[1].p = slot;
64379 	      opc->v[3].p_dd_f = ifunc;
64380 	      opc->v[0].fp = opt_p_dd_cs;
64381 	      return(true);
64382 	    }}}
64383   pc_fallback(sc, pstart);
64384   return_false(sc, car_x);
64385 }
64386 
64387 /* -------- p_pi -------- */
64388 static s7_pointer opt_p_pi_ss(opt_info *o) {return(o->v[3].p_pi_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p))));}
64389 static s7_pointer opt_p_pi_ss_sref(opt_info *o) {return(string_ref_p_pi_unchecked(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p))));}
64390 static s7_pointer opt_p_pi_ss_vref(opt_info *o) {return(normal_vector_ref_p_pi_unchecked(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p))));}
64391 static s7_pointer opt_p_pi_sc(opt_info *o) {return(o->v[3].p_pi_f(opt_sc(o), slot_value(o->v[1].p), o->v[2].i));}
64392 static s7_pointer opt_p_pi_sf(opt_info *o) {return(o->v[3].p_pi_f(opt_sc(o), slot_value(o->v[1].p), o->v[5].fi(o->v[4].o1)));}
64393 static s7_pointer opt_p_pi_sf_sref(opt_info *o) {return(string_ref_p_pi_unchecked(opt_sc(o), slot_value(o->v[1].p), o->v[5].fi(o->v[4].o1)));}
64394 static s7_pointer opt_p_pi_fc(opt_info *o) {return(o->v[3].p_pi_f(opt_sc(o), o->v[5].fp(o->v[4].o1), o->v[2].i));}
64395 
64396 static bool p_pi_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer sig, s7_pointer car_x)
64397 {
64398   s7_p_pi_t func;
64399   func = s7_p_pi_function(s_func);
64400   if (func)
64401     {
64402       s7_pointer obj = NULL, slot1, checker = NULL;
64403       opt_info *o1;
64404 
64405       /* here we know cadr is a symbol */
64406       slot1 = opt_simple_symbol(sc, cadr(car_x));
64407       if (!slot1)
64408 	return_false(sc, car_x);
64409       if ((is_any_vector(slot_value(slot1))) &&
64410 	  (vector_rank(slot_value(slot1)) > 1))
64411 	return_false(sc, car_x);
64412 
64413       opc->v[3].p_pi_f = func;
64414       opc->v[1].p = slot1;
64415 
64416       if (is_symbol(cadr(sig)))
64417 	checker = cadr(sig);
64418 
64419       if ((s7_p_pi_unchecked_function(s_func)) &&
64420 	  (checker))
64421 	{
64422 	  obj = slot_value(opc->v[1].p);
64423 	  if ((is_string(obj)) ||
64424 	      (is_pair(obj)) ||
64425 	      (is_any_vector(obj)))
64426 	    {
64427 	      if (((is_string(obj)) && (checker == sc->is_string_symbol)) ||
64428 		  ((is_any_vector(obj)) && (checker == sc->is_vector_symbol)) ||
64429 		  ((is_pair(obj)) && (checker == sc->is_pair_symbol)) ||
64430 		  ((is_byte_vector(obj)) && (checker == sc->is_byte_vector_symbol)))
64431 		opc->v[3].p_pi_f = (is_normal_vector(obj)) ? normal_vector_ref_p_pi_unchecked : s7_p_pi_unchecked_function(s_func);
64432 	    }}
64433       slot1 = opt_integer_symbol(sc, caddr(car_x));
64434       if (slot1)
64435 	{
64436 	  opc->v[0].fp = (opc->v[3].p_pi_f == string_ref_p_pi_unchecked) ? opt_p_pi_ss_sref :
64437 	                   ((opc->v[3].p_pi_f == normal_vector_ref_p_pi_unchecked) ? opt_p_pi_ss_vref : opt_p_pi_ss);
64438 	  opc->v[2].p = slot1;
64439 	  if ((obj) &&
64440 	      (is_step_end(slot1)))
64441 	    switch (type(obj))
64442 	      {
64443 	      case T_VECTOR:
64444 		if (denominator(slot_value(slot1)) <= vector_length(obj))
64445 		  opc->v[3].p_pi_f = vector_ref_unchecked;
64446 		return(true);
64447 
64448 	      case T_INT_VECTOR:
64449 		if (denominator(slot_value(slot1)) <= vector_length(obj))
64450 		  opc->v[3].p_pi_f = int_vector_ref_unchecked_p;
64451 		return(true);
64452 
64453 	      case T_FLOAT_VECTOR:
64454 		if (denominator(slot_value(slot1)) <= vector_length(obj))
64455 		  opc->v[3].p_pi_f = float_vector_ref_unchecked_p;
64456 		return(true);
64457 
64458 	      case T_STRING:
64459 		if (denominator(slot_value(slot1)) <= string_length(obj))
64460 		  opc->v[3].p_pi_f = string_ref_unchecked;
64461 		return(true);
64462 
64463 	      case T_BYTE_VECTOR:
64464 		if (denominator(slot_value(slot1)) <= string_length(obj))
64465 		  opc->v[3].p_pi_f = byte_vector_ref_unchecked_p;
64466 		return(true);
64467 	      }
64468 	  return(true);
64469 	}
64470       if (is_t_integer(caddr(car_x)))
64471 	{
64472 	  opc->v[2].i = integer(caddr(car_x));
64473 	  opc->v[0].fp = opt_p_pi_sc;
64474 	  return(true);
64475 	}
64476       o1 = sc->opts[sc->pc];
64477       if (int_optimize(sc, cddr(car_x)))
64478 	{
64479 	  opc->v[0].fp = (opc->v[3].p_pi_f == string_ref_p_pi_unchecked) ? opt_p_pi_sf_sref : opt_p_pi_sf;
64480 	  opc->v[4].o1 = o1;
64481 	  opc->v[5].fi = o1->v[0].fi;
64482 	  return(true);
64483 	}}
64484   return_false(sc, car_x);
64485 }
64486 
64487 static s7_pointer opt_p_pi_fco(opt_info *o) {return(o->v[3].p_pi_f(opt_sc(o), o->v[4].p_p_f(opt_sc(o), slot_value(o->v[1].p)), o->v[2].i));}
64488 
64489 static bool p_pi_fc_combinable(s7_scheme *sc, opt_info *opc)
64490 {
64491   if ((sc->pc > 1) &&
64492       (opc == sc->opts[sc->pc - 2]))
64493     {
64494       opt_info *o1;
64495       o1 = sc->opts[sc->pc - 1];
64496       if (o1->v[0].fp == opt_p_p_s)
64497 	{
64498 	  opc->v[4].p_p_f = o1->v[2].p_p_f;
64499 	  opc->v[1].p = o1->v[1].p;
64500 	  opc->v[0].fp = opt_p_pi_fco;
64501 	  backup_pc(sc);
64502 	  return(true);
64503 	}}
64504   return_false(sc, NULL);
64505 }
64506 
64507 /* -------- p_pp -------- */
64508 static s7_pointer opt_p_pp_ss(opt_info *o) {return(o->v[3].p_pp_f(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p)));}
64509 static s7_pointer opt_p_pp_sc(opt_info *o) {return(o->v[3].p_pp_f(opt_sc(o), slot_value(o->v[1].p), o->v[2].p));}
64510 static s7_pointer opt_p_pp_cs(opt_info *o) {return(o->v[3].p_pp_f(opt_sc(o), o->v[2].p, slot_value(o->v[1].p)));}
64511 static s7_pointer opt_p_pp_sf(opt_info *o) {return(o->v[3].p_pp_f(opt_sc(o), slot_value(o->v[1].p), o->v[5].fp(o->v[4].o1)));}
64512 static s7_pointer opt_p_pp_fs(opt_info *o) {return(o->v[3].p_pp_f(opt_sc(o), o->v[5].fp(o->v[4].o1), slot_value(o->v[1].p)));}
64513 static s7_pointer opt_p_pp_fs_vref(opt_info *o) {return(vector_ref_p_pp(opt_sc(o), o->v[5].fp(o->v[4].o1), slot_value(o->v[1].p)));}
64514 static s7_pointer opt_p_pp_fc(opt_info *o) {return(o->v[3].p_pp_f(opt_sc(o), o->v[5].fp(o->v[4].o1), o->v[2].p));}
64515 static s7_pointer opt_p_pp_cc(opt_info *o) {return(o->v[3].p_pp_f(opt_sc(o), o->v[1].p, o->v[2].p));}
64516 static s7_pointer opt_p_pp_ff(opt_info *o) {s7_pointer p1; p1 = o->v[11].fp(o->v[10].o1); return(o->v[3].p_pp_f(opt_sc(o), p1, o->v[9].fp(o->v[8].o1)));}
64517 static s7_pointer opt_set_car_pp_ss(opt_info *o) {return(inline_set_car(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p)));}
64518 static s7_pointer opt_p_pp_sf_href(opt_info *o) {return(s7_hash_table_ref(opt_sc(o), slot_value(o->v[1].p), o->v[5].fp(o->v[4].o1)));}
64519 
64520 static bool p_pp_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, int32_t pstart)
64521 {
64522   s7_p_pp_t func;
64523 
64524   func = s7_p_pp_function(s_func);
64525   if (func)
64526     {
64527       s7_pointer slot;
64528 
64529       opc->v[3].p_pp_f = func;
64530       if (is_symbol(cadr(car_x)))
64531 	{
64532 	  slot = opt_simple_symbol(sc, cadr(car_x));
64533 	  if (!slot)
64534 	    {
64535 	      pc_fallback(sc, pstart);
64536 	      return_false(sc, car_x);
64537 	    }
64538 	  if ((is_any_vector(slot_value(slot))) &&
64539 	      (vector_rank(slot_value(slot)) > 1))
64540 	    {
64541 	      pc_fallback(sc, pstart);
64542 	      return_false(sc, car_x);
64543 	    }
64544 	  opc->v[1].p = slot;
64545 
64546 	  if ((func == hash_table_ref_p_pp) && (is_hash_table(slot_value(slot))))
64547 	    opc->v[3].p_pp_f = s7_hash_table_ref;
64548 
64549 	  if (is_symbol(caddr(car_x)))
64550 	    {
64551 	      opc->v[2].p = opt_simple_symbol(sc, caddr(car_x));
64552 	      if (opc->v[2].p)
64553 		{
64554 		  opc->v[0].fp = (func == set_car_p_pp) ? opt_set_car_pp_ss : opt_p_pp_ss;
64555 		  return(true);
64556 		}
64557 	      pc_fallback(sc, pstart);
64558 	      return_false(sc, car_x);
64559 	    }
64560 	  if ((!is_pair(caddr(car_x))) ||
64561 	      (is_proper_quote(sc, caddr(car_x))))
64562 	    {
64563 	      opc->v[2].p = (!is_pair(caddr(car_x))) ? caddr(car_x) : cadaddr(car_x);
64564 	      opc->v[0].fp = opt_p_pp_sc;
64565 	      return(true);
64566 	    }
64567 	  if (cell_optimize(sc, cddr(car_x)))
64568 	    {
64569 	      opc->v[0].fp = (opc->v[3].p_pp_f == s7_hash_table_ref) ? opt_p_pp_sf_href : opt_p_pp_sf;
64570 	      opc->v[4].o1 = sc->opts[pstart];
64571 	      opc->v[5].fp = sc->opts[pstart]->v[0].fp;
64572 	      return(true);
64573 	    }}
64574       else
64575 	{
64576 	  opt_info *o1;
64577 	  o1 = sc->opts[sc->pc];
64578 	  if ((!is_pair(cadr(car_x))) ||
64579 	      (is_proper_quote(sc, cadr(car_x))))
64580 	    {
64581 	      opc->v[1].p = (!is_pair(cadr(car_x))) ? cadr(car_x) : cadadr(car_x);
64582 	      if ((!is_symbol(caddr(car_x))) &&
64583 		  ((!is_pair(caddr(car_x))) ||
64584 		   (is_proper_quote(sc, caddr(car_x)))))
64585 		{
64586 		  opc->v[2].p = (!is_pair(caddr(car_x))) ? caddr(car_x) : cadaddr(car_x);
64587 		  opc->v[0].fp = opt_p_pp_cc;
64588 		  return(true);
64589 		}
64590 	      if (is_symbol(caddr(car_x)))
64591 		{
64592 		  opc->v[2].p = opc->v[1].p;
64593 		  opc->v[1].p = opt_simple_symbol(sc, caddr(car_x));
64594 		  if (opc->v[1].p)
64595 		    {
64596 		      opc->v[0].fp = opt_p_pp_cs;
64597 		      return(true);
64598 		    }
64599 		  pc_fallback(sc, pstart);
64600 		  return_false(sc, car_x);
64601 		}}
64602 	  if (cell_optimize(sc, cdr(car_x)))
64603 	    {
64604 	      if (is_symbol(caddr(car_x)))
64605 		{
64606 		  opc->v[1].p = opt_simple_symbol(sc, caddr(car_x));
64607 		  if (opc->v[1].p)
64608 		    {
64609 		      opc->v[0].fp = (func == vector_ref_p_pp) ? opt_p_pp_fs_vref : opt_p_pp_fs;
64610 		      opc->v[4].o1 = o1;
64611 		      opc->v[5].fp = o1->v[0].fp;
64612 		      return(true);
64613 		    }
64614 		  pc_fallback(sc, pstart);
64615 		  return_false(sc, car_x);
64616 		}
64617 	      if ((!is_pair(caddr(car_x))) ||
64618 		  (is_proper_quote(sc, caddr(car_x))))
64619 		{
64620 		  if (is_t_integer(caddr(car_x)))
64621 		    {
64622 		      s7_p_pi_t ifunc;
64623 		      ifunc = s7_p_pi_function(s_func);
64624 		      if (ifunc)
64625 			{
64626 			  opc->v[2].i = integer(caddr(car_x));
64627 			  opc->v[3].p_pi_f = ifunc;
64628 			  if (!p_pi_fc_combinable(sc, opc))
64629 			    {
64630 			      opc->v[0].fp = opt_p_pi_fc;
64631 			      opc->v[4].o1 = o1;
64632 			      opc->v[5].fp = o1->v[0].fp;
64633 			      return(true);
64634 			    }
64635 			  return(true);
64636 			}}
64637 		  opc->v[2].p = (!is_pair(caddr(car_x))) ? caddr(car_x) : cadaddr(car_x);
64638 		  opc->v[0].fp = opt_p_pp_fc;
64639 		  opc->v[4].o1 = o1;
64640 		  opc->v[5].fp = o1->v[0].fp;
64641 		  return(true);
64642 		}
64643 	      opc->v[8].o1 = sc->opts[sc->pc];
64644 	      if (cell_optimize(sc, cddr(car_x)))
64645 		{
64646 		  opc->v[10].o1 = o1;
64647 		  opc->v[11].fp = o1->v[0].fp;
64648 		  opc->v[9].fp = opc->v[8].o1->v[0].fp;
64649 		  opc->v[0].fp = opt_p_pp_ff;
64650 		  return(true);
64651 		}}}}
64652   pc_fallback(sc, pstart);
64653   return_false(sc, car_x);
64654 }
64655 
64656 /* -------- p_call_pp -------- */
64657 static s7_pointer opt_p_call_ff(opt_info *o)
64658 {
64659   s7_pointer po2;
64660   s7_scheme *sc;
64661   sc = opt_sc(o);
64662   gc_protect_via_stack(sc, o->v[11].fp(o->v[10].o1));
64663   po2 = o->v[9].fp(o->v[8].o1);
64664   po2 = o->v[3].call(sc, set_plist_2(sc, sc->stack_end[-2], po2));
64665   sc->stack_end -= 4;
64666   return(po2);
64667 }
64668 
64669 static s7_pointer opt_p_call_fs(opt_info *o)
64670 {
64671   s7_pointer po1;
64672   po1 = o->v[11].fp(o->v[10].o1);
64673   return(o->v[3].call(opt_sc(o), set_plist_2(opt_sc(o), po1, slot_value(o->v[1].p))));
64674 }
64675 
64676 static s7_pointer opt_p_call_sf(opt_info *o)
64677 {
64678   s7_pointer po1;
64679   po1 = o->v[11].fp(o->v[10].o1);
64680   return(o->v[3].call(opt_sc(o), set_plist_2(opt_sc(o), slot_value(o->v[1].p), po1)));
64681 }
64682 
64683 static s7_pointer opt_p_call_sc(opt_info *o) {return(o->v[3].call(opt_sc(o), set_plist_2(opt_sc(o), slot_value(o->v[1].p), o->v[2].p)));}
64684 static s7_pointer opt_p_call_ss(opt_info *o) {return(o->v[3].call(opt_sc(o), set_plist_2(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p))));}
64685 
64686 static bool p_call_pp_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, int32_t pstart)
64687 {
64688   if ((is_safe_procedure(s_func)) &&
64689       (c_function_required_args(s_func) <= 2) &&
64690       (c_function_all_args(s_func) >= 2))
64691     {
64692       /* if optimized, we want to use the current fn_proc (to take advantage of fixups like substring_temp),
64693        *   but those same fixups are incorrect for this context if op_safe_c_c related.
64694        */
64695       opc->v[3].call = cf_call(sc, car_x, s_func, 2);
64696       if (is_symbol(cadr(car_x)))
64697 	{
64698 	  opc->v[1].p = lookup_slot_from(cadr(car_x), sc->curlet);
64699 	  if ((is_slot(opc->v[1].p)) &&
64700 	      (!has_methods(slot_value(opc->v[1].p))))
64701 	    {
64702 	      if (is_symbol(caddr(car_x)))
64703 		{
64704 		  opc->v[2].p = opt_simple_symbol(sc, caddr(car_x));
64705 		  if (opc->v[2].p)
64706 		    {
64707 		      opc->v[0].fp = opt_p_call_ss;
64708 		      return(true);
64709 		    }
64710 		  pc_fallback(sc, pstart);
64711 		  return_false(sc, car_x);
64712 		}
64713 	      if (!is_pair(caddr(car_x)))
64714 		{
64715 		  opc->v[2].p = caddr(car_x);
64716 		  opc->v[0].fp = opt_p_call_sc;
64717 		  return(true);
64718 		}
64719 	      if (cell_optimize(sc, cddr(car_x)))
64720 		{
64721 		  opc->v[10].o1 = sc->opts[pstart];
64722 		  opc->v[11].fp = opc->v[10].o1->v[0].fp;
64723 		  opc->v[0].fp = opt_p_call_sf;
64724 		  return(true);
64725 		}}
64726 	  else
64727 	    {
64728 	      pc_fallback(sc, pstart);
64729 	      return_false(sc, car_x);
64730 	    }}
64731       opc->v[10].o1 = sc->opts[sc->pc];
64732       if (cell_optimize(sc, cdr(car_x)))
64733 	{
64734 	  opc->v[11].fp = opc->v[10].o1->v[0].fp;
64735 	  if (is_symbol(caddr(car_x)))
64736 	    {
64737 	      opc->v[1].p = opt_simple_symbol(sc, caddr(car_x));
64738 	      if (opc->v[1].p)
64739 		{
64740 		  opc->v[0].fp = opt_p_call_fs;
64741 		  return(true);
64742 		}
64743 	      pc_fallback(sc, pstart);
64744 	      return_false(sc, car_x);
64745 	    }
64746 	  opc->v[8].o1 = sc->opts[sc->pc];
64747 	  if (cell_optimize(sc, cddr(car_x)))
64748 	    {
64749 	      opc->v[9].fp = opc->v[8].o1->v[0].fp;
64750 	      opc->v[0].fp = opt_p_call_ff;
64751 	      return(true);
64752 	    }}}
64753   pc_fallback(sc, pstart);
64754   return_false(sc, car_x);
64755 }
64756 
64757 
64758 /* -------- p_pip --------*/
64759 
64760 static s7_pointer opt_p_pip_ssf(opt_info *o) {return(o->v[3].p_pip_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[5].fp(o->v[4].o1)));}
64761 static s7_pointer opt_p_pip_ssf_sset(opt_info *o) {return(string_set_unchecked(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[5].fp(o->v[4].o1)));}
64762 static s7_pointer opt_p_pip_ssf_vset(opt_info *o) {return(vector_set_p_pip_unchecked(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[5].fp(o->v[4].o1)));}
64763 static s7_pointer opt_p_pip_sss(opt_info *o) {return(o->v[4].p_pip_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), slot_value(o->v[3].p)));}
64764 static s7_pointer opt_p_pip_sss_vset(opt_info *o) {return(vector_set_p_pip_unchecked(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), slot_value(o->v[3].p)));}
64765 static s7_pointer opt_p_pip_ssc(opt_info *o) {return(o->v[3].p_pip_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[4].p));}
64766 static s7_pointer opt_p_pip_c(opt_info *o) {return(o->v[3].p_pip_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[5].p_p_f(opt_sc(o), o->v[4].p)));}
64767 
64768 static s7_pointer opt_p_pip_sff(opt_info *o)
64769 {
64770   s7_int i1;
64771   i1 = o->v[11].fi(o->v[10].o1);
64772   return(o->v[3].p_pip_f(opt_sc(o), slot_value(o->v[1].p), i1, o->v[9].fp(o->v[8].o1)));
64773 }
64774 
64775 static s7_pointer opt_p_pip_sso(opt_info *o)
64776 {
64777   return(o->v[5].p_pip_f(opt_sc(o), slot_value(o->v[1].p),
64778 			integer(slot_value(o->v[2].p)),
64779 			o->v[6].p_pi_f(opt_sc(o), slot_value(o->v[3].p),
64780 				       integer(slot_value(o->v[4].p)))));
64781 }
64782 
64783 static s7_pointer opt_p_pip_ssf1(opt_info *o)
64784 {
64785   return(o->v[3].p_pip_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), o->v[4].p_p_f(opt_sc(o), o->v[6].fp(o->v[5].o1))));
64786 }
64787 
64788 static bool p_pip_ssf_combinable(s7_scheme *sc, opt_info *opc, int32_t start)
64789 {
64790   opt_info *o1;
64791   if ((sc->pc > 1) &&
64792       (opc == sc->opts[sc->pc - 2]))
64793     {
64794       o1 = sc->opts[sc->pc - 1];
64795       if ((o1->v[0].fp == opt_p_pi_ss) || (o1->v[0].fp == opt_p_pi_ss_sref) || (o1->v[0].fp == opt_p_pi_ss_vref))
64796 	{
64797 	  opc->v[5].p_pip_f = opc->v[3].p_pip_f;
64798 	  opc->v[6].p_pi_f = o1->v[3].p_pi_f;
64799 	  opc->v[3].p = o1->v[1].p;
64800 	  opc->v[4].p = o1->v[2].p;
64801 	  opc->v[0].fp = opt_p_pip_sso;
64802 	  backup_pc(sc);
64803 	  return(true);
64804 	}
64805       if (o1->v[0].fp == opt_p_p_c)
64806 	{
64807 	  opc->v[5].p_p_f = o1->v[2].p_p_f;
64808 	  opc->v[4].p = o1->v[1].p;
64809 	  backup_pc(sc);
64810 	  opc->v[0].fp = opt_p_pip_c;
64811 	  return(true);
64812 	}}
64813 
64814   o1 = sc->opts[start];
64815   if (o1->v[0].fp == opt_p_p_f)
64816     {
64817       opc->v[4].p_p_f = o1->v[2].p_p_f;
64818       opc->v[5].o1 = sc->opts[start + 1];
64819       opc->v[6].fp = sc->opts[start + 1]->v[0].fp;
64820       opc->v[0].fp = opt_p_pip_ssf1;
64821       return(true);
64822     }
64823   return_false(sc, NULL);
64824 }
64825 
64826 static bool p_pip_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
64827 {
64828   s7_p_pip_t func;
64829   s7_pointer obj, slot1, sig, checker = NULL;
64830 
64831   func = s7_p_pip_function(s_func);
64832   if (!func)
64833     return_false(sc, car_x);
64834 
64835   sig = c_function_signature(s_func);
64836   if ((is_pair(sig)) &&
64837       (is_pair(cdr(sig))) &&
64838       (is_symbol(cadr(sig))))
64839     checker = cadr(sig);
64840 
64841   /* here we know cadr is a symbol */
64842   slot1 = lookup_slot_from(cadr(car_x), sc->curlet);
64843   if ((!is_slot(slot1)) ||
64844       (has_methods(slot_value(slot1))) ||
64845       (is_immutable(slot_value(slot1))))
64846     return_false(sc, car_x);
64847   if ((is_any_vector(slot_value(slot1))) &&
64848       (vector_rank(slot_value(slot1)) > 1))
64849     return_false(sc, car_x);
64850 
64851   opc->v[1].p = slot1;
64852   obj = slot_value(opc->v[1].p);
64853   opc->v[3].p_pip_f = func;
64854   if ((s7_p_pip_unchecked_function(s_func)) &&
64855       (checker))
64856     {
64857       if ((is_normal_vector(obj)) && (checker == sc->is_vector_symbol))
64858 	opc->v[3].p_pip_f = (is_typed_vector(obj)) ? typed_vector_set_p_pip_unchecked : vector_set_p_pip_unchecked;
64859       else
64860 	{
64861 	  if ((is_pair(obj)) && (checker == sc->is_pair_symbol))
64862 	    opc->v[3].p_pip_f = s7_p_pip_unchecked_function(s_func);
64863 	  else
64864 	    {
64865 	      s7_pointer val_type;
64866 	      val_type = opt_arg_type(sc, cdddr(car_x));
64867 	      if ((val_type == cadddr(sig)) &&
64868 		  (((is_string(obj)) && (checker == sc->is_string_symbol)) ||
64869 		   ((is_float_vector(obj)) && (checker == sc->is_float_vector_symbol)) ||
64870 		   ((is_int_vector(obj)) && (checker == sc->is_int_vector_symbol)) ||
64871 		   ((is_byte_vector(obj)) && (checker == sc->is_byte_vector_symbol))))
64872 		opc->v[3].p_pip_f = s7_p_pip_unchecked_function(s_func);
64873 	    }}}
64874   if (is_symbol(caddr(car_x)))
64875     {
64876       s7_pointer slot2;
64877       int32_t start;
64878       start = sc->pc;
64879       slot2 = opt_integer_symbol(sc, caddr(car_x));
64880       if (slot2)
64881 	{
64882 	  opc->v[2].p = slot2;
64883 	  if (is_step_end(slot2))
64884 	    switch (type(obj))
64885 	      {
64886 	      case T_VECTOR:
64887 		if (denominator(slot_value(slot2)) <= vector_length(obj))
64888 		  opc->v[3].p_pip_f = (is_typed_vector(obj)) ? typed_vector_set_unchecked : vector_set_unchecked;
64889 		break;
64890 
64891 	      case T_INT_VECTOR:
64892 		if (denominator(slot_value(slot2)) <= vector_length(obj))
64893 		  opc->v[3].p_pip_f = int_vector_set_unchecked_p;
64894 		break;
64895 
64896 	      case T_FLOAT_VECTOR:
64897 		if (denominator(slot_value(slot2)) <= vector_length(obj))
64898 		  opc->v[3].p_pip_f = float_vector_set_unchecked_p;
64899 		break;
64900 
64901 	      case T_STRING:
64902 		if (denominator(slot_value(slot2)) <= string_length(obj))
64903 		  opc->v[3].p_pip_f = string_set_unchecked;
64904 		break;
64905 
64906 	      case T_BYTE_VECTOR:
64907 		if (denominator(slot_value(slot2)) <= string_length(obj))
64908 		  opc->v[3].p_pip_f = byte_vector_set_unchecked_p;
64909 		break;
64910 	      }
64911 
64912 	  if (is_symbol(cadddr(car_x)))
64913 	    {
64914 	      s7_pointer val_slot;
64915 	      val_slot = opt_simple_symbol(sc, cadddr(car_x));
64916 	      if (val_slot)
64917 		{
64918 		  opc->v[4].p_pip_f = opc->v[3].p_pip_f;
64919 		  opc->v[3].p = val_slot;
64920 		  opc->v[0].fp = (opc->v[4].p_pip_f == vector_set_p_pip_unchecked) ? opt_p_pip_sss_vset : opt_p_pip_sss;
64921 		  return(true);
64922 		}}
64923 	  else
64924 	    if ((!is_pair(cadddr(car_x))) ||
64925 		(is_proper_quote(sc, cadddr(car_x))))
64926 	      {
64927 		opc->v[4].p = (is_pair(cadddr(car_x))) ? cadr(cadddr(car_x)) : cadddr(car_x);
64928 		opc->v[0].fp = opt_p_pip_ssc;
64929 		return(true);
64930 	      }
64931 	  if (cell_optimize(sc, cdddr(car_x)))
64932 	    {
64933 	      if (p_pip_ssf_combinable(sc, opc, start))
64934 		return(true);
64935 	      opc->v[0].fp = (opc->v[3].p_pip_f == string_set_unchecked) ? opt_p_pip_ssf_sset :
64936                                ((opc->v[3].p_pip_f == vector_set_p_pip_unchecked) ? opt_p_pip_ssf_vset : opt_p_pip_ssf);
64937 	      opc->v[4].o1 = sc->opts[start];
64938 	      opc->v[5].fp = sc->opts[start]->v[0].fp;
64939 	      return(true);
64940 	    }}}
64941   else /* not symbol caddr */
64942     {
64943       opc->v[10].o1 = sc->opts[sc->pc];
64944       if (int_optimize(sc, cddr(car_x)))
64945 	{
64946 	  opc->v[8].o1 = sc->opts[sc->pc];
64947 	  if (cell_optimize(sc, cdddr(car_x)))
64948 	    {
64949 	      opc->v[0].fp = opt_p_pip_sff;
64950 	      opc->v[11].fi = opc->v[10].o1->v[0].fi;
64951 	      opc->v[9].fp = opc->v[8].o1->v[0].fp;
64952 	      return(true);
64953 	    }}}
64954   return_false(sc, car_x);
64955 }
64956 
64957 /* -------- p_piip -------- */
64958 static s7_pointer opt_p_piip_sssf(opt_info *o)
64959 {
64960   return(o->v[5].p_piip_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p)), o->v[11].fp(o->v[10].o1)));
64961 }
64962 
64963 static s7_pointer opt_p_piip_sssc(opt_info *o)
64964 {
64965   return(o->v[5].p_piip_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p)), o->v[4].p));
64966 }
64967 
64968 static s7_pointer opt_p_piip_sfff(opt_info *o)
64969 {
64970   s7_int i1, i2;
64971   i1 = o->v[11].fi(o->v[10].o1);
64972   i2 = o->v[9].fi(o->v[8].o1);
64973   return(o->v[5].p_piip_f(opt_sc(o), slot_value(o->v[1].p), i1, i2, o->v[3].fp(o->v[4].o1))); /* v[3] because v[5] is already in use */
64974 }
64975 
64976 static bool p_piip_to_sx(s7_scheme *sc, opt_info *opc, s7_pointer indexp1, s7_pointer indexp2, s7_pointer valp, s7_pointer obj)
64977 {
64978   s7_pointer slot;
64979   slot = opt_integer_symbol(sc, car(indexp2));
64980   if (slot)
64981     {
64982       opc->v[3].p = slot;
64983       slot = opt_integer_symbol(sc, car(indexp1));
64984       if (slot)
64985 	{
64986 	  opc->v[2].p = slot;
64987 	  if ((is_symbol(car(valp))) ||
64988 	      (is_unquoted_pair(car(valp))))
64989 	    {
64990 	      opc->v[10].o1 = sc->opts[sc->pc];
64991 	      if (cell_optimize(sc, valp))
64992 		{
64993 		  opc->v[11].fp = opc->v[10].o1->v[0].fp;
64994 		  opc->v[0].fp = opt_p_piip_sssf;
64995 		  return(true);
64996 		}
64997 	      return_false(sc, indexp1);
64998 	    }
64999 	  opc->v[0].fp = opt_p_piip_sssc;
65000 	  opc->v[4].p = (is_pair(car(valp))) ? cadar(valp) : car(valp);
65001 	  return(true);
65002 	}
65003       opc->v[10].o1 = sc->opts[sc->pc];
65004       if (int_optimize(sc, indexp1))
65005 	{
65006 	  opc->v[8].o1 = sc->opts[sc->pc];
65007 	  if (int_optimize(sc, indexp2))
65008 	    {
65009 	      opc->v[4].o1 = sc->opts[sc->pc];
65010 	      if (cell_optimize(sc, valp))
65011 		{
65012 		  opc->v[11].fi = opc->v[10].o1->v[0].fi;
65013 		  opc->v[9].fi = opc->v[8].o1->v[0].fi;
65014 		  opc->v[3].fp = opc->v[4].o1->v[0].fp;
65015 		  opc->v[0].fp = opt_p_piip_sfff;
65016 		  return(true);
65017 		  }}}}
65018   return_false(sc, indexp1);
65019 }
65020 
65021 static bool p_piip_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
65022 {
65023   /* this currently assumes s_func == vector-set! because there aren't any other p_piip functions(!) */
65024   s7_p_piip_t func;
65025   func = s7_p_piip_function(s_func);
65026   if ((func) &&
65027       (is_symbol(cadr(car_x))))
65028     {
65029       s7_pointer slot1, obj;
65030       slot1 = lookup_slot_from(cadr(car_x), sc->curlet);
65031       if (!is_slot(slot1))
65032 	return_false(sc, car_x);
65033       obj = slot_value(slot1);
65034       if ((has_methods(obj)) || (is_immutable(obj)))
65035 	return_false(sc, car_x);
65036       if ((is_any_vector(obj)) && /* vector_set_p_piip calls vector_setter(obj) */
65037 	  (vector_rank(obj) == 2))
65038 	{
65039 	  opc->v[1].p = slot1;
65040 	  opc->v[5].p_piip_f = vector_set_p_piip;
65041 	  return(p_piip_to_sx(sc, opc, cddr(car_x), cdddr(car_x), cddddr(car_x), obj));
65042 	}}
65043   return_false(sc, car_x);
65044 }
65045 
65046 /* -------- p_pii -------- */
65047 static s7_pointer opt_p_pii_sss(opt_info *o)
65048 {
65049   return(o->v[4].p_pii_f(opt_sc(o), slot_value(o->v[1].p), integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p))));
65050 }
65051 
65052 static s7_pointer opt_p_pii_sff(opt_info *o)
65053 {
65054   s7_int i1, i2;
65055   i1 = o->v[11].fi(o->v[10].o1);
65056   i2 = o->v[9].fi(o->v[8].o1);
65057   return(o->v[4].p_pii_f(opt_sc(o), slot_value(o->v[1].p), i1, i2));
65058 }
65059 
65060 static bool p_pii_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
65061 {
65062   s7_p_pii_t func;
65063   func = s7_p_pii_function(s_func);
65064   if ((func) &&
65065       (is_symbol(cadr(car_x))))
65066     {
65067       s7_pointer slot1, obj;
65068       slot1 = lookup_slot_from(cadr(car_x), sc->curlet);
65069       if (!is_slot(slot1))
65070 	return_false(sc, car_x);
65071       obj = slot_value(slot1);
65072       if ((has_methods(obj)) || (is_immutable(obj)))
65073 	return_false(sc, car_x);
65074       if ((is_normal_vector(obj)) &&
65075 	  (vector_rank(obj) == 2))
65076 	{
65077 	  s7_pointer indexp1, indexp2, slot;
65078 	  indexp1 = cddr(car_x);
65079 	  indexp2 = cdddr(car_x);
65080 	  opc->v[1].p = slot1;
65081 	  opc->v[4].p_pii_f = vector_ref_p_pii;
65082 	  slot = opt_integer_symbol(sc, car(indexp2));
65083 	  if (slot)
65084 	    {
65085 	      opc->v[3].p = slot;
65086 	      slot = opt_integer_symbol(sc, car(indexp1));
65087 	      if (slot)
65088 		{
65089 		  opc->v[2].p = slot;
65090 		  opc->v[0].fp = opt_p_pii_sss;
65091 		  return(true);
65092 		}}
65093 	  opc->v[10].o1 = sc->opts[sc->pc];
65094 	  if (int_optimize(sc, indexp1))
65095 	    {
65096 	      opc->v[8].o1 = sc->opts[sc->pc];
65097 	      if (int_optimize(sc, indexp2))
65098 		{
65099 		  opc->v[0].fp = opt_p_pii_sff;
65100 		  opc->v[11].fi = opc->v[10].o1->v[0].fi;
65101 		  opc->v[9].fi = opc->v[8].o1->v[0].fi;
65102 		  return(true);
65103 		}}}}
65104   return_false(sc, car_x);
65105 }
65106 
65107 /* -------- p_ppi -------- */
65108 static s7_pointer opt_p_ppi_psf(opt_info *o) {return(o->v[3].p_ppi_f(opt_sc(o), o->v[2].p, slot_value(o->v[1].p), o->v[5].fi(o->v[4].o1)));}
65109 static s7_pointer opt_p_ppi_psf_cpos(opt_info *o) {return(char_position_p_ppi(opt_sc(o), o->v[2].p, slot_value(o->v[1].p), o->v[5].fi(o->v[4].o1)));}
65110 
65111 static bool p_ppi_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
65112 {
65113   s7_p_ppi_t ifunc;
65114   ifunc = s7_p_ppi_function(s_func);
65115   if (ifunc)
65116     {
65117       int32_t start;
65118       start = sc->pc;
65119       opc->v[3].p_ppi_f = ifunc;
65120       if ((s7_is_character(cadr(car_x))) &&
65121 	  (is_symbol(caddr(car_x))) &&
65122 	  (int_optimize(sc, cdddr(car_x))))
65123 	{
65124 	  s7_pointer slot;
65125 	  slot = opt_simple_symbol(sc, caddr(car_x));
65126 	  if (slot)
65127 	    {
65128 	      opc->v[2].p = cadr(car_x);
65129 	      opc->v[1].p = slot;
65130 	      opc->v[0].fp = (ifunc == char_position_p_ppi) ? opt_p_ppi_psf_cpos : opt_p_ppi_psf;
65131 	      opc->v[4].o1 = sc->opts[start];
65132 	      opc->v[5].fi = sc->opts[start]->v[0].fi;
65133 	      return(true);
65134 	    }}
65135       pc_fallback(sc, start);
65136     }
65137   return_false(sc, car_x);
65138 }
65139 
65140 /* -------- p_ppp -------- */
65141 static s7_pointer opt_p_ppp_ssf(opt_info *o) {return(o->v[3].p_ppp_f(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p), o->v[5].fp(o->v[4].o1)));}
65142 static s7_pointer opt_p_ppp_hash_table_increment(opt_info *o) {return(fx_hash_table_increment_1(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p), o->v[5].p));}
65143 static s7_pointer opt_p_ppp_sfs(opt_info *o) {return(o->v[3].p_ppp_f(opt_sc(o), slot_value(o->v[1].p), o->v[5].fp(o->v[4].o1), slot_value(o->v[2].p)));}
65144 static s7_pointer opt_p_ppp_scs(opt_info *o) {return(o->v[3].p_ppp_f(opt_sc(o), slot_value(o->v[1].p), o->v[4].p, slot_value(o->v[2].p)));}
65145 static s7_pointer opt_p_ppp_scs_eset(opt_info *o) {return(let_set_1(opt_sc(o), slot_value(o->v[1].p), o->v[4].p, slot_value(o->v[2].p)));}
65146 static s7_pointer opt_p_ppp_sss(opt_info *o) {return(o->v[4].p_ppp_f(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p), slot_value(o->v[3].p)));}
65147 static s7_pointer opt_p_ppp_sss_mul(opt_info *o) {return(multiply_p_ppp(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p), slot_value(o->v[3].p)));}
65148 static s7_pointer opt_p_ppp_sss_hset(opt_info *o) {return(s7_hash_table_set(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p), slot_value(o->v[3].p)));}
65149 static s7_pointer opt_p_ppp_ssc(opt_info *o) {return(o->v[3].p_ppp_f(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p), o->v[4].p));}
65150 
65151 static s7_pointer opt_p_ppp_sff(opt_info *o)
65152 {
65153   s7_pointer po1;
65154   po1 = o->v[11].fp(o->v[10].o1);
65155   return(o->v[3].p_ppp_f(opt_sc(o), slot_value(o->v[1].p), po1, o->v[9].fp(o->v[8].o1)));
65156 }
65157 
65158 static s7_pointer opt_p_ppp_fff(opt_info *o)
65159 {
65160   s7_pointer res;
65161   s7_scheme *sc;
65162   sc = opt_sc(o);
65163   gc_protect_via_stack(sc, T_Pos(o->v[11].fp(o->v[10].o1)));
65164   sc->stack_end[-4] = T_Pos(o->v[9].fp(o->v[8].o1));
65165   res = o->v[3].p_ppp_f(sc, sc->stack_end[-2], sc->stack_end[-4], o->v[5].fp(o->v[4].o1));
65166   sc->stack_end -= 4;
65167   return(res);
65168 }
65169 
65170 static bool p_ppp_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
65171 {
65172   s7_p_ppp_t func;
65173   func = s7_p_ppp_function(s_func);
65174   if (func)
65175     {
65176       s7_pointer arg1, arg2, arg3;
65177       int32_t start;
65178       start = sc->pc;
65179 
65180       opc->v[3].p_ppp_f = func;
65181       arg1 = cadr(car_x);
65182       arg2 = caddr(car_x);
65183       arg3 = cadddr(car_x);
65184       if (is_symbol(arg1)) /* dealt with at the top -> p1 */
65185 	{
65186 	  s7_pointer slot, obj;
65187 	  opt_info *o1;
65188 
65189 	  slot = lookup_slot_from(arg1, sc->curlet);
65190 	  if ((!is_slot(slot)) ||
65191 	      (has_methods(slot_value(slot))))
65192 	    return_false(sc, car_x);
65193 
65194 	  obj = slot_value(slot);
65195 	  if ((is_any_vector(obj)) &&
65196 	      (vector_rank(obj) > 1))
65197 	    return_false(sc, car_x);
65198 
65199 	  if ((car(car_x) == sc->hash_table_set_symbol) || /* the other setters (than nash-table/let) won't happen here -- no p_ppp function */
65200 	      (s_func == initial_value(sc->hash_table_set_symbol)))
65201 	    {
65202 	      if ((!is_hash_table(obj)) || (is_immutable(obj)))
65203 		return_false(sc, car_x);
65204 	    }
65205 	  else
65206 	    if (((car(car_x) == sc->let_set_symbol) || (s_func == initial_value(sc->let_set_symbol))) &&
65207 		((!is_let(obj)) || (is_immutable(obj))))
65208 	      return_false(sc, car_x);
65209 
65210 	  opc->v[1].p = slot;
65211 
65212 	  if ((func == hash_table_set_p_ppp) && (is_hash_table(obj)))
65213 	    opc->v[3].p_ppp_f = s7_hash_table_set;
65214 
65215 	  if (is_symbol(arg2))
65216 	    {
65217 	      slot = opt_simple_symbol(sc, arg2);
65218 	      if (slot)
65219 		{
65220 		  opc->v[2].p = slot;
65221 		  if (is_symbol(arg3))
65222 		    {
65223 		      slot = opt_simple_symbol(sc, arg3);
65224 		      if (slot)
65225 			{
65226 			  s7_p_ppp_t func1;
65227 			  func1 = opc->v[3].p_ppp_f;
65228 			  opc->v[4].p_ppp_f = func1;
65229 			  opc->v[3].p = slot;
65230 			  opc->v[0].fp = (func1 == multiply_p_ppp) ? opt_p_ppp_sss_mul : ((func1 == s7_hash_table_set) ? opt_p_ppp_sss_hset : opt_p_ppp_sss);
65231 			  return(true);
65232 			}}
65233 		  else
65234 		    if ((!is_pair(arg3)) ||
65235 			(is_proper_quote(sc, arg3)))
65236 		      {
65237 			opc->v[4].p = (is_pair(arg3)) ? cadr(arg3) : arg3;
65238 			opc->v[0].fp = opt_p_ppp_ssc;
65239 			return(true);
65240 		      }
65241 		  if (optimize_op(car_x) == HOP_HASH_TABLE_INCREMENT)
65242 		    {
65243 		      opc->v[0].fp = opt_p_ppp_hash_table_increment;
65244 		      opc->v[5].p = car_x;
65245 		      return(true);
65246 		    }
65247 		  if (cell_optimize(sc, cdddr(car_x)))
65248 		    {
65249 		      opc->v[4].o1 = sc->opts[start];
65250 		      opc->v[5].fp = opc->v[4].o1->v[0].fp;
65251 		      opc->v[0].fp = opt_p_ppp_ssf;
65252 		      return(true);
65253 		    }
65254 		  pc_fallback(sc, start);
65255 		}}
65256 	  if ((is_proper_quote(sc, arg2)) &&
65257 	      (is_symbol(arg3)))
65258 	    {
65259 	      s7_pointer val_slot;
65260 	      val_slot = opt_simple_symbol(sc, arg3);
65261 	      if (val_slot)
65262 		{
65263 		  opc->v[4].p = cadr(arg2);
65264 		  opc->v[2].p = val_slot;
65265 		  opc->v[0].fp = opt_p_ppp_scs;
65266 		  if (opc->v[3].p_ppp_f == s7_let_set)
65267 		    {
65268 		      if (is_symbol(cadr(arg2))) /* checked is_let, has_methods and is_immutable above */
65269 			opc->v[0].fp = opt_p_ppp_scs_eset;
65270 		      else return_false(sc, car_x);
65271 		    }
65272 		  return(true);
65273 		}}
65274 	  o1 = sc->opts[sc->pc];
65275 	  if (cell_optimize(sc, cddr(car_x)))
65276 	    {
65277 	      opt_info *o2;
65278 	      o2 = sc->opts[sc->pc];
65279 	      if (is_symbol(arg3))
65280 		{
65281 		  s7_pointer val_slot;
65282 		  val_slot = opt_simple_symbol(sc, arg3);
65283 		  if (val_slot)
65284 		    {
65285 		      opc->v[2].p = val_slot;
65286 		      opc->v[0].fp = opt_p_ppp_sfs;
65287 		      opc->v[4].o1 = o1;
65288 		      opc->v[5].fp = o1->v[0].fp;
65289 		      return(true);
65290 		    }}
65291 	      if (cell_optimize(sc, cdddr(car_x)))
65292 		{
65293 		  opc->v[0].fp = opt_p_ppp_sff;
65294 		  opc->v[10].o1 = o1;
65295 		  opc->v[11].fp = o1->v[0].fp;
65296 		  opc->v[8].o1 = o2;
65297 		  opc->v[9].fp = o2->v[0].fp;
65298 		  return(true);
65299 		}}}
65300       else
65301 	{
65302 	  opc->v[10].o1 = sc->opts[start];
65303 	  if (cell_optimize(sc, cdr(car_x)))
65304 	    {
65305 	      opc->v[8].o1 = sc->opts[sc->pc];
65306 	      if (cell_optimize(sc, cddr(car_x)))
65307 		{
65308 		  opc->v[4].o1 = sc->opts[sc->pc];
65309 		  if (cell_optimize(sc, cdddr(car_x)))
65310 		    {
65311 		      opc->v[0].fp = opt_p_ppp_fff;
65312 		      opc->v[11].fp = opc->v[10].o1->v[0].fp;
65313 		      opc->v[9].fp = opc->v[8].o1->v[0].fp;
65314 		      opc->v[5].fp = opc->v[4].o1->v[0].fp;
65315 		      return(true);
65316 		    }}}}
65317       pc_fallback(sc, start);
65318     }
65319   return_false(sc, car_x);
65320 }
65321 
65322 /* -------- p_call_ppp -------- */
65323 static s7_pointer opt_p_call_sss(opt_info *o)
65324 {
65325   return(o->v[4].call(opt_sc(o), set_plist_3(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p), slot_value(o->v[3].p))));
65326 }
65327 
65328 static s7_pointer opt_p_call_css(opt_info *o)
65329 {
65330   return(o->v[4].call(opt_sc(o), set_plist_3(opt_sc(o), o->v[1].p, slot_value(o->v[2].p), slot_value(o->v[3].p))));
65331 }
65332 
65333 static s7_pointer opt_p_call_ssf(opt_info *o)
65334 {
65335   return(o->v[4].call(opt_sc(o), set_plist_3(opt_sc(o), slot_value(o->v[1].p), slot_value(o->v[2].p), o->v[6].fp(o->v[5].o1))));
65336 }
65337 
65338 static s7_pointer opt_p_call_ppp(opt_info *o)
65339 {
65340   s7_pointer res;
65341   s7_scheme *sc;
65342   sc = opt_sc(o);
65343   gc_protect_via_stack(sc, o->v[4].fp(o->v[3].o1));
65344   sc->stack_end[-4] = o->v[6].fp(o->v[5].o1);
65345   res = o->v[11].fp(o->v[10].o1); /* not combinable into next */
65346   res = o->v[2].call(sc, set_plist_3(sc, sc->stack_end[-2], sc->stack_end[-4], res));
65347   sc->stack_end -= 4;
65348   return(res);
65349 }
65350 
65351 static bool p_call_ppp_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x)
65352 {
65353   int32_t start;
65354   start = sc->pc;
65355   if ((is_safe_procedure(s_func)) &&
65356       (c_function_required_args(s_func) <= 3) &&
65357       (c_function_all_args(s_func) >= 3))
65358     {
65359       s7_pointer slot, arg;
65360       opt_info *o1;
65361       o1 = sc->opts[sc->pc];
65362       arg = cadr(car_x);
65363 
65364       if (!is_pair(arg))
65365 	{
65366 	  if (is_symbol(arg))
65367 	    {
65368 	      slot = opt_simple_symbol(sc, arg);
65369 	      if (slot)
65370 		opc->v[1].p = slot;
65371 	      else return_false(sc, car_x); /* no need for pc_fallback here, I think */
65372 	    }
65373 	  else opc->v[1].p = arg;
65374 	  arg = caddr(car_x);
65375 	  if (is_symbol(arg))
65376 	    {
65377 	      slot = opt_simple_symbol(sc, arg);
65378 	      if (slot)
65379 		{
65380 		  opc->v[2].p = slot;
65381 		  arg = cadddr(car_x);
65382 		  if (is_symbol(arg))
65383 		    {
65384 		      slot = opt_simple_symbol(sc, arg);
65385 		      if (slot)
65386 			{
65387 			  opc->v[3].p = slot;
65388 			  opc->v[4].call = cf_call(sc, car_x, s_func, 3);
65389 			  opc->v[0].fp = (is_slot(opc->v[1].p)) ? opt_p_call_sss : opt_p_call_css;
65390 			  return(true);
65391 			}}
65392 		  else
65393 		    if ((is_slot(opc->v[1].p)) && (cell_optimize(sc, cdddr(car_x))))
65394 		      {
65395 			opc->v[4].call = cf_call(sc, car_x, s_func, 3);
65396 			opc->v[0].fp = (opc->v[4].call == g_substring_uncopied) ? opt_p_substring_uncopied_ssf : opt_p_call_ssf;
65397 			opc->v[5].o1 = o1;
65398 			opc->v[6].fp = o1->v[0].fp;
65399 			return(true);
65400 		      }}}}
65401       if (cell_optimize(sc, cdr(car_x)))
65402 	{
65403 	  opt_info *o2;
65404 	  o2 = sc->opts[sc->pc];
65405 	  if (cell_optimize(sc, cddr(car_x)))
65406 	    {
65407 	      opt_info *o3;
65408 	      o3 = sc->opts[sc->pc];
65409 	      if (cell_optimize(sc, cdddr(car_x)))
65410 		{
65411 		  opc->v[2].call = cf_call(sc, car_x, s_func, 3);
65412 		  opc->v[0].fp = opt_p_call_ppp;
65413 		  opc->v[3].o1 = o1;
65414 		  opc->v[4].fp = o1->v[0].fp;
65415 		  opc->v[5].o1 = o2;
65416 		  opc->v[6].fp = o2->v[0].fp;
65417 		  opc->v[10].o1 = o3;
65418 		  opc->v[11].fp = o3->v[0].fp;
65419 		  return(true);
65420 		}}}}
65421   pc_fallback(sc, start);
65422   return_false(sc, car_x);
65423 }
65424 
65425 
65426 /* -------- p_call_any -------- */
65427 #define P_CALL_O1 3
65428 
65429 static s7_pointer opt_p_call_any(opt_info *o)
65430 {
65431   s7_pointer arg, val;
65432   int32_t i;
65433   s7_scheme *sc;
65434   sc = opt_sc(o);
65435   val = safe_list_if_possible(sc, o->v[1].i);
65436   if (in_heap(val))
65437     gc_protect_via_stack(sc, val);
65438   for (i = 0, arg = val; i < o->v[1].i; i++, arg = cdr(arg))
65439     {
65440       opt_info *o1;
65441       o1 = o->v[i + P_CALL_O1].o1;
65442       set_car(arg, o1->v[0].fp(o1));
65443     }
65444   arg = o->v[2].call(sc, val);
65445   if (in_heap(val))
65446     sc->stack_end -= 4;
65447   else
65448     {
65449       clear_type_bit(T_Pair(val), T_LIST_IN_USE);
65450       sc->current_safe_list = 0;
65451     }
65452   return(arg);
65453 }
65454 
65455 static bool p_call_any_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer car_x, int32_t len)
65456 {
65457   if ((len < (NUM_VUNIONS - P_CALL_O1)) &&
65458       (is_safe_procedure(s_func)) &&
65459       (c_function_required_args(s_func) <= (len - 1)) &&
65460       (c_function_all_args(s_func) >= (len - 1)))
65461     {
65462       s7_pointer p;      /* (vector-set! v k i 2) gets here */
65463       int32_t pctr;
65464       opc->v[1].i = (len - 1);
65465       for (pctr = P_CALL_O1, p = cdr(car_x); is_pair(p); pctr++, p = cdr(p))
65466 	{
65467 	  opc->v[V_ind(pctr)].o1 = sc->opts[sc->pc];
65468 	  if (!cell_optimize(sc, p))
65469 	    break;
65470 	}
65471       if (is_null(p))
65472 	{
65473 	  opc->v[0].fp = opt_p_call_any;
65474 	  opc->v[2].call = cf_call(sc, car_x, s_func, len - 1);
65475 	  return(true);
65476 	}}
65477   return_false(sc, car_x);
65478 }
65479 
65480 
65481 /* -------- p_fx_any -------- */
65482 
65483 static s7_pointer opt_p_fx_any(opt_info *o) {return(o->v[1].call(opt_sc(o), o->v[2].p));}
65484 
65485 static bool p_fx_any_ok(s7_scheme *sc, opt_info *opc, s7_pointer s_func, s7_pointer x)
65486 {
65487   s7_function f;
65488   f = (has_fx(x)) ? fx_proc(x) : fx_choose(sc, x, sc->curlet, let_symbol_is_safe);
65489   if (f)
65490     {
65491       opc->v[0].fp = opt_p_fx_any;
65492       opc->v[1].call = f;
65493       opc->v[2].p = car(x);
65494       return(true);
65495     }
65496   return_false(sc, x);
65497 }
65498 
65499 
65500 /* -------- p_implicit -------- */
65501 
65502 static bool p_implicit(s7_scheme *sc, s7_pointer car_x, int32_t len)
65503 {
65504   s7_pointer s_slot;
65505   s_slot = lookup_slot_from(car(car_x), sc->curlet);
65506 
65507   if (is_slot(s_slot))
65508     {
65509       s7_pointer obj;
65510       obj = slot_value(s_slot);
65511 
65512       if (is_sequence(obj))
65513 	{
65514 	  opt_info *opc;
65515 	  int32_t start;
65516 	  opc = alloc_opo(sc);
65517 	  opc->v[1].p = s_slot;
65518 	  start = sc->pc;
65519 	  if (len == 2)
65520 	    {
65521 	      switch (type(obj))
65522 		{
65523 		case T_PAIR:       opc->v[3].p_pi_f = list_ref_p_pi_unchecked;   break;
65524 		case T_HASH_TABLE: opc->v[3].p_pp_f = s7_hash_table_ref;         break;
65525 		case T_LET:        opc->v[3].p_pp_f = s7_let_ref;	         break;
65526 		case T_STRING:     opc->v[3].p_pi_f = string_ref_p_pi_unchecked; break;
65527 
65528 		case T_VECTOR:
65529 		  if (vector_rank(obj) != 1)
65530 		    return_false(sc, car_x);
65531 		  opc->v[3].p_pi_f = normal_vector_ref_p_pi_unchecked;
65532 		  break;
65533 
65534 		case T_BYTE_VECTOR:
65535 		case T_INT_VECTOR:
65536 		case T_FLOAT_VECTOR:
65537 		  if (vector_rank(obj) != 1)
65538 		    return_false(sc, car_x);
65539 		  opc->v[3].p_pi_f = vector_ref_p_pi_unchecked;
65540 		  break;
65541 
65542 		case T_C_OBJECT:
65543 		  return_false(sc, car_x); /* no pi_ref because ref assumes pp */
65544 		  break;
65545 
65546 		default:
65547 		  return_false(sc, car_x);
65548 		}
65549 	      /* now v3.p_pi|pp.f is set */
65550 	      if (is_symbol(cadr(car_x)))
65551 		{
65552 		  s7_pointer slot;
65553 		  slot = lookup_slot_from(cadr(car_x), sc->curlet);
65554 		  if (is_slot(slot))
65555 		    {
65556 		      opc->v[2].p = slot;
65557 		      if ((!is_hash_table(obj)) && /* these because opt_int below */
65558 			  (!is_let(obj)))
65559 			{
65560 			  if (is_t_integer(slot_value(slot)))
65561 			    {
65562 			      opc->v[0].fp = opt_p_pi_ss;
65563 			      if (is_step_end(opc->v[2].p))
65564 				{
65565 				  switch (type(obj))
65566 				    {
65567 				    case T_STRING:
65568 				      if (denominator(slot_value(opc->v[2].p)) <= string_length(obj))
65569 					opc->v[3].p_pi_f = string_ref_unchecked;
65570 				      break;
65571 
65572 				    case T_BYTE_VECTOR:
65573 				      if (denominator(slot_value(opc->v[2].p)) <= byte_vector_length(obj))
65574 					opc->v[3].p_pi_f = byte_vector_ref_unchecked_p;
65575 				      break;
65576 
65577 				    case T_VECTOR:
65578 				      if (denominator(slot_value(opc->v[2].p)) <= vector_length(obj))
65579 					opc->v[3].p_pi_f = vector_ref_unchecked;
65580 				      break;
65581 
65582 				    case T_FLOAT_VECTOR:
65583 				      if (denominator(slot_value(opc->v[2].p)) <= vector_length(obj))
65584 					opc->v[3].p_pi_f = float_vector_ref_unchecked_p;
65585 				      break;
65586 
65587 				    case T_INT_VECTOR:
65588 				      if (denominator(slot_value(opc->v[2].p)) <= vector_length(obj))
65589 					opc->v[3].p_pi_f = int_vector_ref_unchecked_p;
65590 				      break;
65591 				    }}
65592 			      return(true);
65593 			    }
65594 			  return_false(sc, car_x); /* I think this reflects that a non-int index is an error for list-ref et al */
65595 			}
65596 		      opc->v[0].fp = opt_p_pp_ss;
65597 		      return(true);
65598 		    }}
65599 	      else
65600 		{
65601 		  if ((!is_hash_table(obj)) &&
65602 		      (!is_let(obj)))
65603 		    {
65604 		      opt_info *o1;
65605 		      if (is_t_integer(cadr(car_x)))
65606 			{
65607 			  opc->v[2].i = integer(cadr(car_x));
65608 			  opc->v[0].fp = opt_p_pi_sc;
65609 			  return(true);
65610 			}
65611 		      o1 = sc->opts[sc->pc];
65612 		      if (int_optimize(sc, cdr(car_x)))
65613 			{
65614 			  opc->v[0].fp = opt_p_pi_sf;
65615 			  opc->v[4].o1 = o1;
65616 			  opc->v[5].fi = o1->v[0].fi;
65617 			  return(true);
65618 			}
65619 		      return_false(sc, car_x);
65620 		    }
65621 		  if (cell_optimize(sc, cdr(car_x)))
65622 		    {
65623 		      opc->v[0].fp = opt_p_pp_sf;
65624 		      opc->v[4].o1 = sc->opts[start];
65625 		      opc->v[5].fp = sc->opts[start]->v[0].fp;
65626 		      return(true);
65627 		    }}} /* len==2 */
65628 	  else
65629 	    {
65630 	      if (len > 2)
65631 		{
65632 		  if ((is_normal_vector(obj)) &&
65633 		      (len == 3) && (vector_rank(obj) == 2))
65634 		    {
65635 		      opc->v[10].o1 = sc->opts[sc->pc];
65636 		      if (int_optimize(sc, cdr(car_x)))
65637 			{
65638 			  opc->v[8].o1 = sc->opts[sc->pc];
65639 			  if (int_optimize(sc, cddr(car_x)))
65640 			    {
65641 			      opc->v[0].fp = opt_p_pii_sff;
65642 			      opc->v[11].fi = opc->v[10].o1->v[0].fi;
65643 			      opc->v[9].fi = opc->v[8].o1->v[0].fi;
65644 			      /* opc->v[1].p set above */
65645 			      opc->v[4].p_pii_f = vector_ref_p_pii_direct;
65646 			      return(true);
65647 			    }}
65648 		      pc_fallback(sc, start);
65649 		    }
65650 
65651 		  if (len < (NUM_VUNIONS - 4))  /* mimic p_call_any_ok */
65652 		    {
65653 		      int32_t pctr;
65654 		      s7_pointer p;
65655 		      opc->v[1].i = len;
65656 		      for (pctr = 3, p = car_x; is_pair(p); pctr++, p = cdr(p))
65657 			{
65658 			  opc->v[V_ind(pctr)].o1 = sc->opts[sc->pc];
65659 			  if (!cell_optimize(sc, p))
65660 			    break;
65661 			}
65662 		      if (is_null(p))
65663 			{
65664 			  /* todo??: here we know the vector rank/type, probably can handle the new value type, and maybe indices/dimensions,
65665 			   *   so at least forgo the vec type/rank + immutable checks, the *_set cases are from p_call_any_ok called in cell_optimize
65666 			   */
65667 			  opc->v[0].fp = opt_p_call_any;
65668 			  switch (type(obj))     /* string can't happen here (no multidimensional strings) */
65669 			    {
65670 			    case T_PAIR:         opc->v[2].call = g_list_ref;           break;
65671 			    case T_HASH_TABLE:   opc->v[2].call = g_hash_table_ref;     break;
65672 			    /* case T_LET:       opc->v[2].call = g_let_ref;            break; */ /* this doesn't handle implicit indices via g_let_ref! apply_let */
65673 			    case T_INT_VECTOR:   opc->v[2].call = g_int_vector_ref;     break;
65674 			    case T_BYTE_VECTOR:  opc->v[2].call = g_byte_vector_ref;    break;
65675 			    case T_FLOAT_VECTOR: opc->v[2].call = g_float_vector_ref;   break;
65676 			    case T_VECTOR:       opc->v[2].call = g_vector_ref;         break;
65677 			    default:             return_false(sc, car_x);
65678 			    }
65679 			  return(true);
65680 			}}}}}} /* obj is sequence */
65681   return_false(sc, car_x);
65682 }
65683 
65684 /* -------- cell_quote -------- */
65685 static bool opt_cell_quote(s7_scheme *sc, s7_pointer car_x)
65686 {
65687   opt_info *opc;
65688   if (!is_null(cddr(car_x)))
65689     return_false(sc, car_x);
65690   opc = alloc_opo(sc);
65691   opc->v[1].p = cadr(car_x);
65692   opc->v[0].fp = opt_p_c;
65693   return(true);
65694 }
65695 
65696 /* -------- cell_set -------- */
65697 static s7_pointer opt_set_p_p_f(opt_info *o)
65698 {
65699   s7_pointer x;
65700   x = o->v[4].fp(o->v[3].o1);
65701   slot_set_value(o->v[1].p, x);
65702   return(x);
65703 }
65704 
65705 static s7_pointer opt_set_p_i_s(opt_info *o)
65706 {
65707   s7_pointer val;
65708   val = slot_value(o->v[2].p);
65709   if (is_mutable_integer(val))
65710     val = make_integer(opt_sc(o), integer(val));
65711   slot_set_value(o->v[1].p, val);
65712   return(val);
65713 }
65714 
65715 static s7_pointer opt_set_p_i_f(opt_info *o)
65716 {
65717   s7_pointer x;
65718   x = make_integer(opt_sc(o), o->v[6].fi(o->v[5].o1));
65719   slot_set_value(o->v[1].p, x);
65720   return(x);
65721 }
65722 
65723 static s7_pointer opt_set_p_d_s(opt_info *o)
65724 {
65725   s7_pointer val;
65726   val = slot_value(o->v[2].p);
65727   if (is_mutable_number(val))
65728     val = make_real(opt_sc(o), real(val));
65729   slot_set_value(o->v[1].p, val);
65730   return(val);
65731 }
65732 
65733 static s7_pointer opt_set_p_d_f(opt_info *o)
65734 {
65735   s7_pointer x;
65736   x = make_real(opt_sc(o), o->v[5].fd(o->v[4].o1));
65737   slot_set_value(o->v[1].p, x);
65738   return(x);
65739 }
65740 
65741 static s7_pointer opt_set_p_d_f_sf_add(opt_info *o)
65742 {
65743   s7_pointer x;
65744   x = make_real(opt_sc(o), opt_d_dd_sf_add(o->v[4].o1));
65745   slot_set_value(o->v[1].p, x);
65746   return(x);
65747 }
65748 
65749 static s7_pointer opt_set_p_d_f_mm_add(opt_info *o)
65750 {
65751   s7_double x1, x2;
65752   x1 = float_vector_ref_d_7pi(opt_sc(o), slot_value(o->v[4].p), integer(slot_value(o->v[5].p))) * real(slot_value(o->v[3].p));
65753   x2 = float_vector_ref_d_7pi(opt_sc(o), slot_value(o->v[10].p), integer(slot_value(o->v[11].p))) * real(slot_value(o->v[9].p));
65754   slot_set_value(o->v[1].p, make_real(opt_sc(o), x1 + x2));
65755   return(slot_value(o->v[1].p));
65756 }
65757 
65758 static s7_pointer opt_set_p_d_f_mm_subtract(opt_info *o)
65759 {
65760   s7_double x1, x2;
65761   x1 = float_vector_ref_d_7pi(opt_sc(o), slot_value(o->v[4].p), integer(slot_value(o->v[5].p))) * real(slot_value(o->v[3].p));
65762   x2 = float_vector_ref_d_7pi(opt_sc(o), slot_value(o->v[10].p), integer(slot_value(o->v[11].p))) * real(slot_value(o->v[9].p));
65763   slot_set_value(o->v[1].p, make_real(opt_sc(o), x1 - x2));
65764   return(slot_value(o->v[1].p));
65765 }
65766 
65767 static s7_pointer opt_set_p_c(opt_info *o)
65768 {
65769   slot_set_value(o->v[1].p, o->v[2].p);
65770   return(o->v[2].p);
65771 }
65772 
65773 static s7_pointer opt_set_p_i_fo(opt_info *o)
65774 {
65775   s7_pointer x;
65776   s7_int i;
65777   i = o->v[4].i_ii_f(integer(slot_value(o->v[2].p)), integer(slot_value(o->v[3].p)));
65778   x = make_integer(opt_sc(o), i);
65779   slot_set_value(o->v[1].p, x);
65780   return(x);
65781 }
65782 
65783 static s7_pointer opt_set_p_i_fo_add(opt_info *o)
65784 {
65785   s7_pointer x;
65786   s7_int i;
65787   i = integer(slot_value(o->v[2].p)) + integer(slot_value(o->v[3].p));
65788   x = make_integer(opt_sc(o), i);
65789   slot_set_value(o->v[1].p, x);
65790   return(x);
65791 }
65792 
65793 static s7_pointer opt_set_p_i_fo1(opt_info *o)
65794 {
65795   s7_pointer x;
65796   s7_int i;
65797   i = o->v[4].i_ii_f(integer(slot_value(o->v[2].p)), o->v[3].i);
65798   x = make_integer(opt_sc(o), i);
65799   slot_set_value(o->v[1].p, x);
65800   return(x);
65801 }
65802 
65803 static s7_pointer opt_set_p_i_fo1_add(opt_info *o)
65804 {
65805   s7_pointer x;
65806   s7_int i;
65807   i = integer(slot_value(o->v[2].p)) + o->v[3].i;
65808   x = make_integer(opt_sc(o), i);
65809   slot_set_value(o->v[1].p, x);
65810   return(x);
65811 }
65812 
65813 static bool set_p_i_f_combinable(s7_scheme *sc, opt_info *opc)
65814 {
65815   if ((sc->pc > 1) &&
65816       (opc == sc->opts[sc->pc - 2]))
65817     {
65818       opt_info *o1;
65819       o1 = sc->opts[sc->pc - 1];
65820       if ((o1->v[0].fi == opt_i_ii_ss) ||
65821 	  (o1->v[0].fi == opt_i_ii_ss_add))
65822 	{
65823 	  opc->v[4].i_ii_f = o1->v[3].i_ii_f;
65824 	  opc->v[2].p = o1->v[1].p;
65825 	  opc->v[3].p = o1->v[2].p;
65826 	  opc->v[0].fp = (o1->v[0].fi == opt_i_ii_ss_add) ? opt_set_p_i_fo_add : opt_set_p_i_fo;
65827 	  backup_pc(sc);
65828 	  return(true);
65829 	}
65830       if ((o1->v[0].fi == opt_i_ii_sc) || (o1->v[0].fi == opt_i_ii_sc_add) || (o1->v[0].fi == opt_i_ii_sc_sub))
65831 	{
65832 	  opc->v[4].i_ii_f = o1->v[3].i_ii_f;
65833 	  opc->v[2].p = o1->v[1].p;
65834 	  opc->v[3].i = o1->v[2].i;
65835 	  opc->v[0].fp = (o1->v[0].fi == opt_i_ii_sc_add) ? opt_set_p_i_fo1_add : opt_set_p_i_fo1;
65836 	  backup_pc(sc);
65837 	  return(true);
65838 	}}
65839   return_false(sc, NULL);
65840 }
65841 
65842 static bool set_p_d_f_combinable(s7_scheme *sc, opt_info *opc)
65843 {
65844   if ((sc->pc > 3) &&
65845       (opc == sc->opts[sc->pc - 4]))
65846     {
65847       opt_info *o1;
65848       o1 = sc->opts[sc->pc - 3];
65849       if ((o1->v[0].fd == opt_d_mm_fff) &&
65850 	  ((o1->v[3].d_dd_f == add_d_dd) || (o1->v[3].d_dd_f == subtract_d_dd)))
65851 	{
65852 	  opc->v[0].fp = (o1->v[3].d_dd_f == add_d_dd) ? opt_set_p_d_f_mm_add : opt_set_p_d_f_mm_subtract;
65853 	  o1 = sc->opts[sc->pc - 2];
65854 	  opc->v[3].p = o1->v[1].p;
65855 	  opc->v[4].p = o1->v[2].p;
65856 	  opc->v[5].p = o1->v[3].p;
65857 	  o1 = sc->opts[sc->pc - 1];
65858 	  opc->v[9].p = o1->v[1].p;
65859 	  opc->v[10].p = o1->v[2].p;
65860 	  opc->v[11].p = o1->v[3].p;
65861 	  sc->pc -= 3;
65862 	  return(true);
65863 	}}
65864   return_false(sc, NULL);
65865 }
65866 
65867 static bool is_some_number(s7_scheme *sc, s7_pointer tp)
65868 {
65869   return((tp == sc->is_integer_symbol) ||
65870 	 (tp == sc->is_float_symbol) ||
65871 	 (tp == sc->is_real_symbol) ||
65872 	 (tp == sc->is_complex_symbol) ||
65873 	 (tp == sc->is_number_symbol) ||
65874 	 (tp == sc->is_rational_symbol));
65875 }
65876 
65877 static bool check_type_uncertainty(s7_scheme *sc, s7_pointer target, s7_pointer car_x, opt_info *opc, int32_t start_pc)
65878 {
65879   s7_pointer code;
65880   /* if we're optimizing do, sc->code is (sometimes) ((vars...) (end...) car_x) where car_x is the do body, but it can also be for-each etc */
65881 
65882   code = sc->code;
65883   /* maybe the type uncertainty is not a problem */
65884   if ((is_pair(code)) &&      /* t101-aux-14: (vector-set! !v! 0 (do ((x (list 1 2 3) (cdr x)) (j -1)) ((null? x) j) (set! j (car x)))) */
65885       (is_pair(car(code))) &&
65886       (is_pair(cdr(code))) && /* weird that code sometimes has nothing to do with car_x -- tree_memq below for reality check */
65887       (is_pair(cadr(code))))
65888     {
65889       s7_int counts;
65890       if ((!has_high_c(code)) && /* only set below */
65891 	  (s7_tree_memq(sc, car_x, code)))
65892 	{
65893 	  if (is_pair(caar(code)))
65894 	    {
65895 	      s7_pointer p;
65896 	      counts = tree_count(sc, target, car(code), 0) +
65897 		       tree_count(sc, target, caadr(code), 0) +
65898 	               tree_count(sc, target, cddr(code), 0);
65899 	      for (p = car(code); is_pair(p); p = cdr(p))
65900 		{
65901 		  s7_pointer var;
65902 		  var = car(p);
65903 		  if ((is_proper_list_2(sc, var)) &&
65904 		      (car(var) == target))
65905 		    counts--;
65906 		}}
65907 	  else counts = tree_count(sc, target, code, 0);
65908 	}
65909       else counts = 2;
65910       /* can be from lambda: (lambda (n)...): ((n) (set! sum (+ sum n))) etc */
65911       if (counts <= 2)
65912 	{
65913 	  set_has_high_c(code);
65914 	  pc_fallback(sc, start_pc);
65915 	  if (cell_optimize(sc, cddr(car_x)))
65916 	    {
65917 	      opc->v[0].fp = opt_set_p_p_f;
65918 	      opc->v[3].o1 = sc->opts[start_pc];
65919 	      opc->v[4].fp = sc->opts[start_pc]->v[0].fp;
65920 	      return(true);
65921 	    }}}
65922   return_false(sc, car_x);
65923 }
65924 
65925 static bool opt_cell_set(s7_scheme *sc, s7_pointer car_x) /* len == 3 here (p_syntax) */
65926 {
65927   opt_info *opc;
65928   s7_pointer target;
65929 
65930   opc = alloc_opo(sc);
65931   target = cadr(car_x);
65932   if (is_symbol(target))
65933     {
65934       s7_pointer settee;
65935       if ((is_constant_symbol(sc, target)) ||
65936 	  (symbol_has_setter(target)))
65937 	return_false(sc, car_x);
65938       settee = lookup_slot_from(target, sc->curlet);
65939 
65940       if ((is_slot(settee)) &&
65941 	  (!is_immutable(settee)) &&
65942 	  (!is_syntax(slot_value(settee))))
65943 	{
65944 	  s7_pointer atype, stype;
65945  	  int32_t start_pc;
65946  	  start_pc = sc->pc;
65947 
65948 	  opc->v[1].p = settee;
65949 	  stype = s7_type_of(sc, slot_value(settee));
65950 
65951 	  if (stype == sc->is_integer_symbol)
65952 	    {
65953 	      if (is_symbol(caddr(car_x)))
65954 		{
65955 		  s7_pointer val_slot;
65956 		  val_slot = opt_integer_symbol(sc, caddr(car_x));
65957 		  if (val_slot)
65958 		    {
65959 		      opc->v[2].p = val_slot;
65960 		      opc->v[0].fp = opt_set_p_i_s;
65961 		      return(true);
65962 		    }}
65963 	      else
65964 		{
65965 		  opc->v[5].o1 = sc->opts[sc->pc];
65966 		  if (int_optimize(sc, cddr(car_x)))
65967 		    {
65968 		      if (!set_p_i_f_combinable(sc, opc))
65969 			{
65970 			  opc->v[0].fp = opt_set_p_i_f;
65971 			  opc->v[6].fi = opc->v[5].o1->v[0].fi;
65972 			  return(true);
65973 			}
65974 		      return(true);
65975 		    }
65976 		  return(check_type_uncertainty(sc, target, car_x, opc, start_pc));
65977 		}}
65978 	  if (stype == sc->is_float_symbol)
65979 	    {
65980 	      if (is_t_real(caddr(car_x)))
65981 		{
65982 		  opc->v[2].p = caddr(car_x);
65983 		  opc->v[0].fp = opt_set_p_c;
65984 		  return(true);
65985 		}
65986 	      if (is_symbol(caddr(car_x)))
65987 		{
65988 		  s7_pointer val_slot;
65989 		  val_slot = opt_float_symbol(sc, caddr(car_x));
65990 		  if (val_slot)
65991 		    {
65992 		      opc->v[2].p = val_slot;
65993 		      opc->v[0].fp = opt_set_p_d_s;
65994 		      return(true);
65995 		    }}
65996 	      else
65997 		{
65998 		  if ((is_pair(caddr(car_x))) &&
65999 		      (float_optimize(sc, cddr(car_x))))
66000 		    {
66001 		      if (!set_p_d_f_combinable(sc, opc))
66002 			{
66003 			  opc->v[4].o1 = sc->opts[start_pc];
66004 			  opc->v[5].fd = sc->opts[start_pc]->v[0].fd;
66005 			  opc->v[0].fp = (opc->v[5].fd == opt_d_dd_sf_add) ? opt_set_p_d_f_sf_add : opt_set_p_d_f;
66006 			  return(true);
66007 			}
66008 		      return(true);
66009 		    }
66010 		  return(check_type_uncertainty(sc, target, car_x, opc, start_pc));
66011 		}}
66012 	  atype = opt_arg_type(sc, cddr(car_x));
66013 	  if ((is_some_number(sc, atype)) &&
66014 	      (!is_some_number(sc, stype)))
66015 	    return_false(sc, car_x);
66016 	  if (cell_optimize(sc, cddr(car_x)))
66017 	    {
66018 	      opc->v[0].fp = opt_set_p_p_f;
66019 	      opc->v[3].o1 = sc->opts[start_pc];
66020 	      opc->v[4].fp = sc->opts[start_pc]->v[0].fp;
66021 	      return(true);
66022 	    }}}
66023   else
66024     {
66025       if ((is_pair(target)) &&
66026 	  (is_symbol(car(target))) &&
66027 	  (is_pair(cdr(target))) &&
66028 	  ((is_null(cddr(target))) || (is_null(cdddr(target)))))
66029 	{
66030 	  s7_pointer s_slot;
66031 	  s_slot = lookup_slot_from(car(target), sc->curlet);
66032 	  if (is_slot(s_slot))
66033 	    {
66034 	      s7_pointer obj;
66035 	      opc->v[1].p = s_slot;
66036 	      obj = slot_value(s_slot);
66037 	      if (/* (!has_methods(obj)) && */ /* not mentioned in d_impicit */
66038 		  (is_mutable_sequence(obj)))
66039 		{
66040 		  s7_pointer index;
66041 		  switch (type(obj))
66042 		    {
66043 		    case T_STRING:
66044 		      {
66045 			s7_pointer val_type;
66046 			if (is_pair(cddr(target))) return_false(sc, car_x);
66047 			val_type = opt_arg_type(sc, cddr(car_x));
66048 			if (val_type != sc->is_char_symbol)
66049 			  return_false(sc, car_x);
66050 			opc->v[3].p_pip_f = string_set_p_pip_unchecked;
66051 		      }
66052 		      break;
66053 
66054 		    case T_VECTOR:
66055 		      /* is_t_integer below to handle the index */
66056 		      if (is_null(cddr(target)))
66057 			{
66058 			  if (vector_rank(obj) != 1) return_false(sc, car_x);
66059 			  opc->v[3].p_pip_f = (is_typed_vector(obj)) ? typed_vector_set_p_pip_unchecked : vector_set_p_pip_unchecked;
66060 			}
66061 		      else
66062 			{
66063 			  if (vector_rank(obj) != 2)
66064 			    return_false(sc, car_x);
66065 			  opc->v[5].p_piip_f = (is_typed_vector(obj)) ? typed_vector_set_p_piip_direct : vector_set_p_piip_direct;
66066 			  return(p_piip_to_sx(sc, opc, cdr(target), cddr(target), cddr(car_x), obj));
66067 			}
66068 		      break;
66069 
66070 		    case T_FLOAT_VECTOR:
66071 		      if (opt_float_vector_set(sc, opc, car(target), cdr(target), (is_null(cddr(target))) ? NULL : cddr(target), cddr(car_x)))
66072 			{
66073 			  opc->v[O_WRAP].fd = opc->v[0].fd;
66074 			  opc->v[0].fp = d_to_p;
66075 			  return(true);
66076 			}
66077 		      return_false(sc, car_x);
66078 
66079 		    case T_BYTE_VECTOR:
66080 		    case T_INT_VECTOR:
66081 		      if (opt_int_vector_set(sc, -1, opc, car(target), cdr(target), (is_null(cddr(target))) ? NULL : cddr(target), cddr(car_x)))
66082 			{
66083 			  opc->v[O_WRAP].fi = opc->v[0].fi;
66084 			  opc->v[0].fp = i_to_p;
66085 			  return(true);
66086 			}
66087 		      return_false(sc, car_x);
66088 
66089 		    case T_C_OBJECT:
66090 		      if ((is_null(cddr(target))) &&
66091 			  (is_c_function(c_object_setf(sc, obj))))
66092 			{
66093 			  /* d_7pid_ok assumes cadr is the target, not car etc */
66094 			  s7_d_7pid_t func;
66095 			  func = s7_d_7pid_function(c_object_setf(sc, obj));
66096 			  if (func)
66097 			    {
66098 			      s7_pointer slot;
66099 			      opc->v[4].d_7pid_f = func;
66100 			      slot = opt_integer_symbol(sc, cadr(target));
66101 			      opc->v[10].o1 = sc->opts[sc->pc];
66102 			      if (slot)
66103 				{
66104 				  if (float_optimize(sc, cddr(car_x)))
66105 				    {
66106 				      opc->v[O_WRAP].fd = opt_d_7pid_ssf;
66107 				      opc->v[0].fp = d_to_p; /* cell_optimize, so need to return s7_pointer */
66108 				      opc->v[2].p = slot;
66109 				      opc->v[11].fd = opc->v[10].o1->v[0].fd;
66110 				      return(true);
66111 				    }}
66112 			      else
66113 				if (int_optimize(sc, cdr(target)))
66114 				  {
66115 				    opc->v[8].o1 = sc->opts[sc->pc];
66116 				    if (float_optimize(sc, cddr(car_x)))
66117 				      {
66118 					opc->v[O_WRAP].fd = opt_d_7pid_sff;
66119 					opc->v[11].fi = opc->v[10].o1->v[0].fi;
66120 					opc->v[9].fd = opc->v[8].o1->v[0].fd;
66121 					opc->v[0].fp = d_to_p;
66122 					return(true);
66123 				      }}}}
66124 		      return_false(sc, car_x);
66125 
66126 		    case T_PAIR:
66127 		      if (is_pair(cddr(target))) return_false(sc, car_x);
66128 		      opc->v[3].p_pip_f = list_set_p_pip_unchecked;
66129 
66130 		      /* an experiment -- is this ever hit in normal code? */
66131 		      {
66132 			s7_pointer val;
66133 			val = caddr(car_x);
66134 			if ((is_pair(val)) && (car(val) == sc->add_symbol) && (is_t_integer(caddr(val))) && (is_null(cdddr(val))) && (is_symbol(cadr(target))) &&
66135 			    (car(target) == (caadr(val))) && (is_pair(cdadr(val))) && (is_null(cddadr(val))) && (cadr(target) == cadadr(val)))
66136 			  {
66137 			    s7_pointer slot;
66138 			    index = cadr(target);
66139 			    slot = opt_simple_symbol(sc, index);
66140 			    if ((slot) && (is_t_integer(slot_value(slot))))
66141 			      {
66142 				opc->v[2].p = slot;
66143 				opc->v[3].p = caddr(val);
66144 				opc->v[0].fp = list_increment_p_pip_unchecked;
66145 				return(true);
66146 			      }}}
66147 		      break;
66148 
66149 		    case T_HASH_TABLE:
66150 		      if (is_pair(cddr(target))) return_false(sc, car_x);
66151 		      opc->v[3].p_ppp_f = s7_hash_table_set;
66152 		      break;
66153 
66154 		    case T_LET:
66155 		      /* here we know the let is a covered mutable let -- ?? not true if s7-optimize called explicitly */
66156 		      if ((is_pair(cddr(target))) || (has_methods(obj)))
66157 			return_false(sc, car_x);
66158 		      if ((is_keyword(cadr(target))) ||
66159 			  ((is_quoted_symbol(cadr(target)))))
66160 			opc->v[3].p_ppp_f = let_set_1;
66161 		      else opc->v[3].p_ppp_f = let_set_p_ppp_2;
66162 		      break;
66163 
66164 		    default:
66165 		      return_false(sc, car_x);
66166 		    }
66167 		  index = cadr(target);
66168 		  if (is_symbol(index))
66169 		    {
66170 		      s7_pointer slot;
66171 		      int32_t start;
66172 		      start = sc->pc;
66173 		      slot = opt_simple_symbol(sc, index);
66174 		      if (slot)
66175 			{
66176 			  opc->v[2].p = slot;
66177 			  if ((is_t_integer(slot_value(slot))) &&
66178 			      (is_step_end(opc->v[2].p)))
66179 			    {
66180 			      if (is_string(obj))
66181 				{
66182 				  if (denominator(slot_value(opc->v[2].p)) <= string_length(obj))
66183 				    opc->v[3].p_pip_f = string_set_unchecked;
66184 				}
66185 			      else
66186 				{
66187 				  if (is_byte_vector(obj))
66188 				    {
66189 				      if (denominator(slot_value(opc->v[2].p)) <= byte_vector_length(obj))
66190 					opc->v[3].p_pip_f = byte_vector_set_unchecked_p;
66191 				    }
66192 				  else
66193 				    if (is_any_vector(obj)) /* true for all 3 vectors */
66194 				      {
66195 					if ((is_any_vector(obj)) &&
66196 					    (denominator(slot_value(opc->v[2].p)) <= vector_length(obj)))
66197 					  {
66198 					    if ((is_normal_vector(obj)) && (is_typed_vector(obj)))
66199 					      opc->v[3].p_pip_f = typed_vector_set_unchecked;
66200 					    else opc->v[3].p_pip_f = vector_set_unchecked;
66201 					  }}}}
66202 			  if (is_symbol(caddr(car_x)))
66203 			    {
66204 			      s7_pointer val_slot;
66205 			      s7_p_ppp_t func1;
66206 			      val_slot = opt_simple_symbol(sc, caddr(car_x));
66207 			      if (val_slot)
66208 				{
66209 				  if ((is_string(obj)) ||
66210 				      (is_any_vector(obj)) ||
66211 				      (is_pair(obj)))
66212 				    {
66213 				      opc->v[4].p_pip_f = opc->v[3].p_pip_f;
66214 				      opc->v[3].p = val_slot;
66215 				      opc->v[0].fp = opt_p_pip_sss;
66216 				      return(true);
66217 				    }
66218 				  func1 = opc->v[3].p_ppp_f;
66219 				  opc->v[4].p_ppp_f = func1;
66220 				  opc->v[3].p = val_slot;
66221 				  opc->v[0].fp = (func1 == multiply_p_ppp) ? opt_p_ppp_sss_mul : ((func1 == s7_hash_table_set) ? opt_p_ppp_sss_hset : opt_p_ppp_sss);
66222 				  return(true);
66223 				}}
66224 			  else
66225 			    {
66226 			      if ((!is_pair(caddr(car_x))) ||
66227 				  (is_proper_quote(sc, caddr(car_x))))
66228 				{
66229 				  if (!is_pair(caddr(car_x)))
66230 				    opc->v[4].p = caddr(car_x);
66231 				  else opc->v[4].p = cadaddr(car_x);
66232 				  if ((is_string(obj)) ||
66233 				      (is_any_vector(obj)) ||
66234 				      (is_pair(obj)))
66235 				    {
66236 				      opc->v[0].fp = opt_p_pip_ssc;
66237 				      return(true);
66238 				    }
66239 				  opc->v[0].fp = opt_p_ppp_ssc;
66240 				  return(true);
66241 				}}
66242 			  if (cell_optimize(sc, cddr(car_x)))
66243 			    {
66244 			      opc->v[4].o1 = sc->opts[start];
66245 			      opc->v[5].fp = sc->opts[start]->v[0].fp;
66246 			      if ((is_string(obj)) ||
66247 				  (is_any_vector(obj)) ||
66248 				  (is_pair(obj)))
66249 				{
66250 				  if (p_pip_ssf_combinable(sc, opc, start))
66251 				    return(true);
66252 				  opc->v[0].fp = opt_p_pip_ssf;
66253 				  return(true);
66254 				}
66255 			      opc->v[0].fp = opt_p_ppp_ssf;
66256 			      return(true);
66257 			    }}}
66258 		  else
66259 		    {
66260 		      opt_info *o1;
66261 		      if ((is_string(obj)) ||
66262 			  (is_pair(obj)) ||
66263 			  (is_any_vector(obj)))
66264 			{
66265 			  opc->v[10].o1 = sc->opts[sc->pc];
66266 			  if (int_optimize(sc, cdr(target)))
66267 			    {
66268 			      opc->v[8].o1 = sc->opts[sc->pc];
66269 			      if (cell_optimize(sc, cddr(car_x)))
66270 				{
66271 				  opc->v[0].fp = opt_p_pip_sff;
66272 				  opc->v[11].fi = opc->v[10].o1->v[0].fi;
66273 				  opc->v[9].fp = opc->v[8].o1->v[0].fp;
66274 				  return(true);
66275 				}}
66276 			  return_false(sc, car_x);
66277 			}
66278 		      if ((is_proper_quote(sc, cadr(target))) &&
66279 			  (is_symbol(caddr(car_x))))
66280 			{
66281 			  s7_pointer val_slot;
66282 			  val_slot = opt_simple_symbol(sc, caddr(car_x));
66283 			  if (val_slot)
66284 			    {
66285 			      opc->v[4].p = cadr(cadr(target));
66286 			      opc->v[2].p = val_slot;
66287 			      opc->v[0].fp = (opc->v[3].p_ppp_f = let_set_1) ? opt_p_ppp_scs_eset : opt_p_ppp_scs;
66288 			      return(true);
66289 			    }}
66290 		      o1 = sc->opts[sc->pc];
66291 		      if (cell_optimize(sc, cdr(target)))
66292 			{
66293 			  opt_info *o2;
66294 			  if (is_symbol(caddr(car_x)))
66295 			    {
66296 			      s7_pointer val_slot;
66297 			      val_slot = opt_simple_symbol(sc, caddr(car_x));
66298 			      if (val_slot)
66299 				{
66300 				  opc->v[2].p = val_slot;
66301 				  opc->v[0].fp = opt_p_ppp_sfs;
66302 				  opc->v[4].o1 = o1;
66303 				  opc->v[5].fp = o1->v[0].fp;
66304 				  return(true);
66305 				}}
66306 			  o2 = sc->opts[sc->pc];
66307 			  if (cell_optimize(sc, cddr(car_x)))
66308 			    {
66309 			      opc->v[0].fp = opt_p_ppp_sff;
66310 			      opc->v[10].o1 = o1;
66311 			      opc->v[11].fp = o1->v[0].fp;
66312 			      opc->v[8].o1 = o2;
66313 			      opc->v[9].fp = o2->v[0].fp;
66314 			      return(true);
66315 			    }}}}}}}
66316   return_false(sc, car_x);
66317 }
66318 
66319 
66320 /* -------- cell_begin -------- */
66321 static s7_pointer opt_begin_p(opt_info *o)
66322 {
66323   opt_info *o1;
66324   s7_int i, len;
66325   len = o->v[1].i;            /* len = 1 if 2 exprs, etc */
66326   for (i = 0; i < len; i++)
66327     {
66328       o1 = o->v[i + 2].o1;
66329       o1->v[0].fp(o1);
66330     }
66331   o1 = o->v[i + 2].o1;
66332   return(o1->v[0].fp(o1));
66333 }
66334 
66335 static s7_pointer opt_begin_p_1(opt_info *o)
66336 {
66337   o->v[3].fp(o->v[2].o1);
66338   return(o->v[5].fp(o->v[4].o1));
66339 }
66340 
66341 static void oo_idp_nr_fixup(opt_info *start)
66342 {
66343   if (start->v[0].fp == d_to_p)
66344     {
66345       start->v[0].fp = d_to_p_nr;
66346       if (start->v[O_WRAP].fd == opt_d_7pid_ssf)
66347 	start->v[0].fp = opt_d_7pid_ssf_nr;
66348       else
66349 	if (start->v[O_WRAP].fd == opt_d_7pid_ssfo_fv)
66350 	  {
66351 	    start->v[0].fp = opt_d_7pid_ssfo_fv_nr;
66352 	    if (start->v[6].d_dd_f == add_d_dd)
66353 	      start->v[0].fp = opt_d_7pid_ssfo_fv_add_nr;
66354 	    else
66355 	      if (start->v[6].d_dd_f == subtract_d_dd)
66356 		start->v[0].fp = opt_d_7pid_ssfo_fv_sub_nr;
66357 	  }}
66358   else
66359     if (start->v[0].fp == i_to_p)
66360       start->v[0].fp = i_to_p_nr;
66361 }
66362 
66363 static bool opt_cell_begin(s7_scheme *sc, s7_pointer car_x, int32_t len)
66364 {
66365   int32_t i;
66366   opt_info *opc;
66367   s7_pointer p;
66368   if (len > (NUM_VUNIONS - 3))
66369     return_false(sc, car_x);
66370   opc = alloc_opo(sc);
66371   for (i = 2, p = cdr(car_x); is_pair(p); i++, p = cdr(p))
66372     {
66373       opt_info *start;
66374       start = sc->opts[sc->pc];
66375       if (!cell_optimize(sc, p))
66376 	return_false(sc, car_x);
66377       if (is_pair(cdr(p)))
66378 	oo_idp_nr_fixup(start);
66379       opc->v[V_ind(i)].o1 = start;
66380     }
66381   opc->v[1].i = len - 2;
66382   if (len == 3)
66383     {
66384       opc->v[0].fp = opt_begin_p_1;
66385       opc->v[4].o1 = opc->v[3].o1;
66386       opc->v[5].fp = opc->v[4].o1->v[0].fp;
66387       opc->v[3].fp = opc->v[2].o1->v[0].fp;
66388     }
66389   else opc->v[0].fp = opt_begin_p;
66390   return(true);
66391 }
66392 
66393 /* -------- cell_when|unless -------- */
66394 static s7_pointer opt_when_p_2(opt_info *o)
66395 {
66396   if (o->v[4].fb(o->v[3].o1))
66397     {
66398       o->v[6].fp(o->v[5].o1);
66399       return(o->v[8].fp(o->v[7].o1));
66400     }
66401   return(opt_sc(o)->unspecified);
66402 }
66403 
66404 static s7_pointer opt_when_p(opt_info *o)
66405 {
66406   if (o->v[4].fb(o->v[3].o1))
66407     {
66408       int32_t i, len;
66409       opt_info *o1;
66410       len = o->v[1].i - 1;
66411       for (i = 0; i < len; i++)
66412 	{
66413 	  o1 = o->v[i + 5].o1;
66414 	  o1->v[0].fp(o1);
66415 	}
66416       o1 = o->v[i + 5].o1;
66417       return(o1->v[0].fp(o1));
66418     }
66419   return(opt_sc(o)->unspecified);
66420 }
66421 
66422 static s7_pointer opt_unless_p(opt_info *o)
66423 {
66424   opt_info *o1;
66425   int32_t i, len;
66426 
66427   if (o->v[4].fb(o->v[3].o1))
66428     return(opt_sc(o)->unspecified);
66429   len = o->v[1].i - 1;
66430   for (i = 0; i < len; i++)
66431     {
66432       o1 = o->v[i + 5].o1;
66433       o1->v[0].fp(o1);
66434     }
66435   o1 = o->v[i + 5].o1;
66436   return(o1->v[0].fp(o1));
66437 }
66438 
66439 static bool opt_cell_when(s7_scheme *sc, s7_pointer car_x, int32_t len)
66440 {
66441   s7_pointer p;
66442   int32_t k;
66443   opt_info *opc;
66444   if (len > (NUM_VUNIONS - 6))
66445     return_false(sc, car_x);
66446   opc = alloc_opo(sc);
66447   opc->v[3].o1 = sc->opts[sc->pc];
66448   if (!bool_optimize(sc, cdr(car_x)))
66449     return_false(sc, car_x);
66450   for (k = 5, p = cddr(car_x); is_pair(p); k++, p = cdr(p))
66451     {
66452       opt_info *start;
66453       start = sc->opts[sc->pc];
66454       if (!cell_optimize(sc, p))
66455 	return_false(sc, car_x);
66456       if (is_pair(cdr(p)))
66457 	oo_idp_nr_fixup(start);
66458       opc->v[V_ind(k)].o1 = start;
66459     }
66460   opc->v[4].fb = opc->v[3].o1->v[0].fb;
66461   opc->v[1].i = len - 2;
66462   if (car(car_x) == sc->when_symbol)
66463     {
66464       if (len == 4)
66465 	{
66466 	  opc->v[0].fp = opt_when_p_2;
66467 	  opc->v[7].o1 = opc->v[6].o1;
66468 	  opc->v[8].fp = opc->v[7].o1->v[0].fp;
66469 	  opc->v[6].fp = opc->v[5].o1->v[0].fp;
66470 	}
66471       else opc->v[0].fp = opt_when_p;
66472     }
66473   else opc->v[0].fp = opt_unless_p;
66474   return(true);
66475 }
66476 
66477 /* -------- cell_cond -------- */
66478 
66479 #define COND_O1 3
66480 #define COND_CLAUSE_O1 5
66481 
66482 static s7_pointer cond_value(opt_info *o)
66483 {
66484   opt_info *o1;
66485   int32_t i, len;
66486   len = o->v[1].i - 1;
66487   for (i = 0; i < len; i++)
66488     {
66489       o1 = o->v[i + COND_CLAUSE_O1].o1;
66490       o1->v[0].fp(o1);
66491     }
66492   o1 = o->v[i + COND_CLAUSE_O1].o1;
66493   return(o1->v[0].fp(o1));
66494 }
66495 
66496 static s7_pointer opt_cond(opt_info *top)
66497 {
66498   int32_t clause, len;
66499   len = top->v[2].i;
66500   for (clause = 0; clause < len; clause++)
66501     {
66502       opt_info *o1, *o2;
66503       o1 = top->v[clause + COND_O1].o1;
66504       o2 = o1->v[4].o1;
66505       if (o2->v[0].fb(o2))
66506 	{
66507 	  s7_pointer res;
66508 	  res = cond_value(o1);
66509 	  return(res);
66510 	}}
66511   return(top->sc->unspecified);
66512 }
66513 
66514 static s7_pointer opt_cond_1(opt_info *o) {return((o->v[5].fb(o->v[4].o1)) ? cond_value(o->v[6].o1) : opt_sc(o)->unspecified);} /* cond as when */
66515 static s7_pointer opt_cond_1b(opt_info *o) {return((o->v[4].o1->v[O_WRAP].fp(o->v[4].o1) != opt_sc(o)->F) ? cond_value(o->v[6].o1) : opt_sc(o)->unspecified);}
66516 
66517 static s7_pointer opt_cond_2(opt_info *o)  /* 2 branches, results 1 expr, else */
66518 {
66519   opt_info *o1;
66520   s7_pointer res;
66521   o1 = (o->v[5].fb(o->v[4].o1)) ? o->v[6].o1 : o->v[7].o1;
66522   res = o1->v[0].fp(o1);
66523   return(res);
66524 }
66525 
66526 static bool opt_cell_cond(s7_scheme *sc, s7_pointer car_x)
66527 {
66528   /* top->v[1].i is end index, clause->v[3].i is end of current clause, clause->v[1].i = clause result len */
66529   s7_pointer p, last_clause = NULL;
66530   opt_info *top;
66531   int32_t branches = 0, max_blen = 0, start_pc;
66532 
66533   top = alloc_opo(sc);
66534   start_pc = sc->pc;
66535   for (p = cdr(car_x); is_pair(p); p = cdr(p), branches++)
66536     {
66537       opt_info *opc;
66538       s7_pointer clause, cp;
66539       int32_t blen;
66540       clause = car(p);
66541       if ((branches >= (NUM_VUNIONS - COND_O1)) ||
66542 	  (!is_pair(clause)) ||
66543 	  (!is_pair(cdr(clause))) || /* leave the test->result case for later */
66544 	  (cadr(clause) == sc->feed_to_symbol))
66545 	return_false(sc, clause);
66546 
66547       last_clause = clause;
66548       top->v[V_ind(branches + COND_O1)].o1 = sc->opts[sc->pc];
66549       opc = alloc_opo(sc);
66550       opc->v[4].o1 = sc->opts[sc->pc];
66551       if (!bool_optimize(sc, clause))
66552 	return_false(sc, clause);
66553 
66554       for (blen = 0, cp = cdr(clause); is_pair(cp); blen++, cp = cdr(cp))
66555 	{
66556 	  if (blen >= NUM_VUNIONS - COND_CLAUSE_O1)
66557 	    return_false(sc, cp);
66558 	  opc->v[V_ind(blen + COND_CLAUSE_O1)].o1 = sc->opts[sc->pc];
66559 	  if (!cell_optimize(sc, cp))
66560 	    return_false(sc, cp);
66561 	}
66562       if (!is_null(cp))
66563 	return_false(sc, cp);
66564       opc->v[1].i = blen;
66565       if (max_blen < blen) max_blen = blen;
66566       opc->v[0].fp = opt_cond; /* a placeholder */
66567     }
66568   if (branches == 1)
66569     {
66570       opt_info *o1;
66571       o1 = sc->opts[start_pc + 1];
66572       top->v[0].fp = (o1->v[0].fb == p_to_b) ? opt_cond_1b : opt_cond_1;
66573       top->v[4].o1 = o1;
66574       top->v[5].fb = o1->v[0].fb;
66575       top->v[6].o1 = sc->opts[start_pc];
66576       return(true);
66577     }
66578   if (branches == 2)
66579     {
66580       if ((max_blen == 1) &&
66581 	  ((car(last_clause) == sc->else_symbol) ||
66582 	   (car(last_clause) == sc->T)))
66583 	{
66584 	  opt_info *o1;
66585 	  top->v[6].o1 = top->v[COND_O1].o1->v[COND_CLAUSE_O1].o1;
66586 	  top->v[7].o1 = top->v[COND_O1 + 1].o1->v[COND_CLAUSE_O1].o1;
66587 
66588 	  o1 = sc->opts[start_pc + 1];
66589 	  top->v[4].o1 = o1;
66590 	  top->v[5].fb = o1->v[0].fb;
66591 	  top->v[0].fp = opt_cond_2;
66592 	  return(true);
66593 	}}
66594   top->v[2].i = branches;
66595   top->v[0].fp = opt_cond;
66596   return(true);
66597 }
66598 
66599 /* -------- cell_and|or -------- */
66600 static s7_pointer opt_and_pp(opt_info *o) {return((o->v[11].fp(o->v[10].o1) == opt_sc(o)->F) ? opt_sc(o)->F : o->v[9].fp(o->v[8].o1));}
66601 
66602 static s7_pointer opt_and_any_p(opt_info *o)
66603 {
66604   int32_t i;
66605   s7_pointer val;
66606   val = opt_sc(o)->T; /* (and) -> #t */
66607   for (i = 0; i < o->v[1].i; i++)
66608     {
66609       opt_info *o1;
66610       o1 = o->v[i + 3].o1;
66611       val = o1->v[0].fp(o1);
66612       if (val == opt_sc(o)->F)
66613 	return(opt_sc(o)->F);
66614     }
66615   return(val);
66616 }
66617 
66618 static s7_pointer opt_or_pp(opt_info *o)
66619 {
66620   s7_pointer val;
66621   val = o->v[11].fp(o->v[10].o1);
66622   return((val != opt_sc(o)->F) ? val : o->v[9].fp(o->v[8].o1));
66623 }
66624 
66625 static s7_pointer opt_or_any_p(opt_info *o)
66626 {
66627   int32_t i;
66628   for (i = 0; i < o->v[1].i; i++)
66629     {
66630       s7_pointer val;
66631       opt_info *o1;
66632       o1 = o->v[i + 3].o1;
66633       val = o1->v[0].fp(o1);
66634       if (val != opt_sc(o)->F)
66635 	return(val);
66636     }
66637   return(opt_sc(o)->F);
66638 }
66639 
66640 static bool opt_cell_and(s7_scheme *sc, s7_pointer car_x, int32_t len)
66641 {
66642   opt_info *opc;
66643   opc = alloc_opo(sc);
66644   if (len == 3)
66645     {
66646       opc->v[0].fp = ((car(car_x) == sc->or_symbol) ? opt_or_pp : opt_and_pp);
66647 
66648       opc->v[10].o1 = sc->opts[sc->pc];
66649       if (!cell_optimize(sc, cdr(car_x)))
66650 	return_false(sc, car_x);
66651       opc->v[11].fp = opc->v[10].o1->v[0].fp;
66652 
66653       opc->v[8].o1 = sc->opts[sc->pc];
66654       if (!cell_optimize(sc, cddr(car_x)))
66655 	return_false(sc, car_x);
66656       opc->v[9].fp = opc->v[8].o1->v[0].fp;
66657       return(true);
66658     }
66659 
66660   if ((len > 1) && (len < (NUM_VUNIONS - 4)))
66661     {
66662       s7_pointer p;
66663       int32_t i;
66664       opc->v[1].i = (len - 1);
66665       opc->v[0].fp = ((car(car_x) == sc->or_symbol) ? opt_or_any_p : opt_and_any_p);
66666 
66667       for (i = 3, p = cdr(car_x); is_pair(p); i++, p = cdr(p))
66668 	{
66669 	  opc->v[V_ind(i)].o1 = sc->opts[sc->pc];
66670 	  if (!cell_optimize(sc, p))
66671 	    return_false(sc, car_x);
66672 	}
66673       return(true);
66674     }
66675   return_false(sc, car_x);
66676 }
66677 
66678 /* -------- cell_if -------- */
66679 static s7_pointer opt_if_bp(opt_info *o) {return((o->v[3].fb(o->v[2].o1)) ? o->v[5].fp(o->v[4].o1) : opt_sc(o)->unspecified);}
66680 static s7_pointer opt_if_bp_nr(opt_info *o) {return((o->v[3].fb(o->v[2].o1)) ? o->v[5].fp(o->v[4].o1) : NULL);}
66681 static s7_pointer opt_if_nbp(opt_info *o) {return((o->v[5].fb(o->v[4].o1)) ? opt_sc(o)->unspecified : o->v[11].fp(o->v[10].o1));}
66682 
66683 static s7_pointer opt_if_bp_pb(opt_info *o) /* p_to_b at outer, p_to_b expanded and moved to o[3] */
66684 {
66685   return((o->v[3].fp(o->v[2].o1) != opt_sc(o)->F) ? o->v[5].fp(o->v[4].o1) : opt_sc(o)->unspecified);
66686 }
66687 
66688 static s7_pointer opt_if_bp_ii_fc(opt_info *o)
66689 {
66690   return((o->v[3].b_ii_f(o->v[11].fi(o->v[10].o1), o->v[2].i)) ? o->v[5].fp(o->v[4].o1) : opt_sc(o)->unspecified);
66691 }
66692 
66693 static s7_pointer opt_if_nbp_s(opt_info *o)
66694 {
66695   return((o->v[2].b_p_f(slot_value(o->v[3].p))) ? opt_sc(o)->unspecified : o->v[11].fp(o->v[10].o1));
66696 }
66697 
66698 static s7_pointer opt_if_nbp_sc(opt_info *o)    /* b_pp_sc */
66699 {
66700   return((o->v[3].b_pp_f(slot_value(o->v[2].p), o->v[4].p)) ? opt_sc(o)->unspecified : o->v[11].fp(o->v[10].o1));
66701 }
66702 
66703 static s7_pointer opt_if_nbp_7sc(opt_info *o)   /* b_7pp_sc */
66704 {
66705   return((o->v[3].b_7pp_f(opt_sc(o), slot_value(o->v[2].p), o->v[4].p)) ? opt_sc(o)->unspecified : o->v[11].fp(o->v[10].o1));
66706 }
66707 
66708 static s7_pointer opt_if_nbp_ss(opt_info *o)    /* b_ii_ss */
66709 {
66710   return((o->v[3].b_ii_f(integer(slot_value(o->v[2].p)), integer(slot_value(o->v[4].p)))) ? opt_sc(o)->unspecified : o->v[11].fp(o->v[10].o1));
66711 }
66712 
66713 static s7_pointer opt_if_nbp_fs(opt_info *o)    /* b_pi_fs */
66714 {
66715   return((o->v[2].b_pi_f(opt_sc(o), o->v[5].fp(o->v[4].o1), integer(slot_value(o->v[3].p)))) ? opt_sc(o)->unspecified : o->v[11].fp(o->v[10].o1));
66716 }
66717 
66718 static s7_pointer opt_if_nbp_fs_nr(opt_info *o) /* b_pi_fs */
66719 {
66720   return((o->v[2].b_pi_f(opt_sc(o), o->v[5].fp(o->v[4].o1), integer(slot_value(o->v[3].p)))) ? NULL : o->v[11].fp(o->v[10].o1));
66721 }
66722 
66723 static s7_pointer opt_if_nbp_sf(opt_info *o)    /* b_pp_sf */
66724 {
66725   return((o->v[2].b_pp_f(slot_value(o->v[3].p), o->v[5].fp(o->v[4].o1))) ? opt_sc(o)->unspecified : o->v[11].fp(o->v[10].o1));
66726 }
66727 
66728 static s7_pointer opt_if_nbp_7sf(opt_info *o)   /* b_7pp_sf */
66729 {
66730   return((o->v[2].b_7pp_f(opt_sc(o), slot_value(o->v[3].p), o->v[5].fp(o->v[4].o1))) ? opt_sc(o)->unspecified : o->v[11].fp(o->v[10].o1));
66731 }
66732 
66733 static s7_pointer opt_if_bpp(opt_info *o)
66734 {
66735   return((o->v[5].fb(o->v[4].o1)) ? o->v[9].fp(o->v[8].o1) : o->v[11].fp(o->v[10].o1));
66736 }
66737 
66738 static bool opt_cell_if(s7_scheme *sc, s7_pointer car_x, int32_t len)
66739 {
66740   opt_info *opc, *bop, *top;
66741   opc = alloc_opo(sc);
66742   bop = sc->opts[sc->pc];
66743   if (len == 3)
66744     {
66745       if ((is_proper_list_2(sc, cadr(car_x))) && /* (not arg) */
66746 	  (caadr(car_x) == sc->not_symbol))
66747 	{
66748 	  if (bool_optimize(sc, cdadr(car_x)))
66749 	    {
66750 	      top = sc->opts[sc->pc];
66751 	      if (cell_optimize(sc, cddr(car_x)))
66752 		{
66753 		  opc->v[10].o1 = top;
66754 		  opc->v[11].fp = top->v[0].fp;
66755 		  if (bop->v[0].fb == opt_b_p_s)
66756 		    {
66757 		      opc->v[2].b_p_f = bop->v[2].b_p_f;
66758 		      opc->v[3].p = bop->v[1].p;
66759 		      opc->v[0].fp = opt_if_nbp_s;
66760 		      return(true);
66761 		    }
66762 		  if ((bop->v[0].fb == opt_b_pi_fs) || (bop->v[0].fb == opt_b_pi_fs_num_eq))
66763 		    {
66764 		      opc->v[2].b_pi_f = bop->v[2].b_pi_f;
66765 		      opc->v[3].p = bop->v[1].p;
66766 		      opc->v[4].o1 = bop->v[10].o1;
66767 		      opc->v[5].fp = bop->v[11].fp;
66768 		      opc->v[0].fp = opt_if_nbp_fs;
66769 		      return(true);
66770 		    }
66771 		  if ((bop->v[0].fb == opt_b_pp_sf) ||
66772 		      (bop->v[0].fb == opt_b_7pp_sf))
66773 		    {
66774 		      opc->v[4].o1 = bop->v[10].o1;
66775 		      opc->v[5].fp = bop->v[11].fp;
66776 		      if (bop->v[0].fb == opt_b_pp_sf)
66777 			{
66778 			  opc->v[2].b_pp_f = bop->v[3].b_pp_f;
66779 			  opc->v[0].fp = opt_if_nbp_sf;
66780 			}
66781 		      else
66782 			{
66783 			  opc->v[2].b_7pp_f = bop->v[3].b_7pp_f;
66784 			  opc->v[0].fp = opt_if_nbp_7sf;
66785 			}
66786 		      opc->v[3].p = bop->v[1].p;
66787 		      return(true);
66788 		    }
66789 		  if ((bop->v[0].fb == opt_b_pp_sc) ||
66790 		      (bop->v[0].fb == opt_b_7pp_sc))
66791 		    {
66792 		      if (bop->v[0].fb == opt_b_pp_sc)
66793 			{
66794 			  opc->v[3].b_pp_f = bop->v[3].b_pp_f;
66795 			  opc->v[0].fp = opt_if_nbp_sc;
66796 			}
66797 		      else
66798 			{
66799 			  opc->v[3].b_7pp_f = bop->v[3].b_7pp_f;
66800 			  opc->v[0].fp = opt_if_nbp_7sc;
66801 			}
66802 		      opc->v[2].p = bop->v[1].p;
66803 		      opc->v[4].p = bop->v[2].p;
66804 		      return(true);
66805 		    }
66806 		  if ((bop->v[0].fb == opt_b_ii_ss) || (bop->v[0].fb == opt_b_ii_ss_eq) ||
66807 		      (bop->v[0].fb == opt_b_ii_ss_lt) || (bop->v[0].fb == opt_b_ii_ss_gt) ||
66808 		      (bop->v[0].fb == opt_b_ii_ss_leq) || (bop->v[0].fb == opt_b_ii_ss_geq))
66809 		    {
66810 		      opc->v[3].b_ii_f = bop->v[3].b_ii_f;
66811 		      opc->v[2].p = bop->v[1].p;
66812 		      opc->v[4].p = bop->v[2].p;
66813 		      opc->v[0].fp = opt_if_nbp_ss;
66814 		      return(true);
66815 		    }
66816 		  opc->v[4].o1 = bop;
66817 		  opc->v[5].fb = bop->v[0].fb;
66818 		  opc->v[0].fp = opt_if_nbp;
66819 		  return(true);
66820 		}}}
66821       else
66822 	{
66823 	  if (bool_optimize(sc, cdr(car_x)))
66824 	    {
66825 	      top = sc->opts[sc->pc];
66826 	      if (cell_optimize(sc, cddr(car_x)))
66827 		{
66828 		  opc->v[2].o1 = bop;
66829 		  opc->v[4].o1 = top;
66830 		  opc->v[5].fp = top->v[0].fp;
66831 		  if (bop->v[0].fb == p_to_b)
66832 		    {
66833 		      opc->v[0].fp = opt_if_bp_pb;
66834 		      opc->v[3].fp = bop->v[O_WRAP].fp;
66835 		      return(true);
66836 		    }
66837 		  if (bop->v[0].fb == opt_b_ii_fc)
66838 		    {
66839 		      opc->v[2].i = bop->v[2].i;
66840 		      opc->v[3].b_ii_f = bop->v[3].b_ii_f;
66841 		      opc->v[11].fi = bop->v[11].fi;
66842 		      opc->v[10].o1 = bop->v[10].o1;
66843 		      opc->v[0].fp = opt_if_bp_ii_fc;
66844 		      return(true);
66845 		    }
66846 		  opc->v[0].fp = opt_if_bp;
66847 		  opc->v[3].fb = bop->v[0].fb;
66848 		  return(true);
66849 		}}}
66850       return_false(sc, car_x);
66851     }
66852   if (len == 4)
66853     {
66854       if (bool_optimize(sc, cdr(car_x)))
66855 	{
66856 	  top = sc->opts[sc->pc];
66857 	  if (cell_optimize(sc, cddr(car_x)))
66858 	    {
66859 	      opt_info *o3;
66860 	      o3 = sc->opts[sc->pc];
66861 	      opc->v[0].fp = opt_if_bpp;
66862 	      if (cell_optimize(sc, cdddr(car_x)))
66863 		{
66864 		  opc->v[4].o1 = bop;
66865 		  opc->v[5].fb = bop->v[0].fb;
66866 		  opc->v[8].o1 = top;
66867 		  opc->v[9].fp = top->v[0].fp;
66868 		  opc->v[10].o1 = o3;
66869 		  opc->v[11].fp = o3->v[0].fp;
66870 		  return(true);
66871 		}}}}
66872   return_false(sc, car_x);
66873 }
66874 
66875 /* -------- cell_case -------- */
66876 static bool case_memv(s7_scheme *sc, s7_pointer x, s7_pointer y)
66877 {
66878   s7_pointer z;
66879   if (is_simple(x))
66880     {
66881       for (z = y; is_pair(z); z = cdr(z))
66882 	if (x == car(z))
66883 	  return(true);
66884       return(false);
66885     }
66886   for (z = y; is_pair(z); z = cdr(z))
66887     if (s7_is_eqv(sc, x, car(z))) return(true);
66888   return(false);
66889 }
66890 
66891 #define CASE_O1 3
66892 #define CASE_SEL 2
66893 #define CASE_CLAUSE_O1 4
66894 #define CASE_CLAUSE_KEYS 2
66895 
66896 static s7_pointer case_value(s7_scheme *sc, opt_info *top, opt_info *o)
66897 {
66898   opt_info *o1;
66899   int32_t i, len;
66900   len = o->v[1].i - 1;
66901   for (i = 0; i < len; i++)
66902     {
66903       o1 = o->v[i + CASE_CLAUSE_O1].o1;
66904       o1->v[0].fp(o1);
66905     }
66906   o1 = o->v[i + CASE_CLAUSE_O1].o1;
66907   return(o1->v[0].fp(o1));
66908 }
66909 
66910 static s7_pointer opt_case(opt_info *o)
66911 {
66912   opt_info *o1;
66913   int32_t ctr, lim;
66914   s7_pointer selector;
66915 
66916   o1 = o->v[CASE_SEL].o1;
66917   selector = o1->v[0].fp(o1);
66918   lim = o->v[1].i;
66919 
66920   for (ctr = CASE_O1; ctr < lim; ctr++)
66921     {
66922       o1 = o->v[ctr].o1;
66923       if ((o1->v[CASE_CLAUSE_KEYS].p == opt_sc(o)->else_symbol) ||
66924 	  (case_memv(opt_sc(o), selector, o1->v[CASE_CLAUSE_KEYS].p)))
66925 	return(case_value(opt_sc(o), o, o1));
66926     }
66927   return(opt_sc(o)->unspecified);
66928 }
66929 
66930 static bool opt_cell_case(s7_scheme *sc, s7_pointer car_x)
66931 {
66932   /* top->v[1].i is end index, clause->v[3].i is end of current clause, clause->v[1].i = clause result len */
66933   opt_info *top;
66934   top = alloc_opo(sc);
66935   top->v[CASE_SEL].o1 = sc->opts[sc->pc];
66936   if (cell_optimize(sc, cdr(car_x))) /* selector */
66937     {
66938       s7_pointer p;
66939       int32_t ctr;
66940       for (ctr = CASE_O1, p = cddr(car_x); (is_pair(p)) && (ctr < NUM_VUNIONS); ctr++, p = cdr(p))
66941 	{
66942 	  opt_info *opc;
66943 	  s7_pointer clause, cp;
66944 	  int32_t blen;
66945 	  clause = car(p);
66946 	  if ((!is_pair(clause)) ||
66947 	      ((!is_pair(car(clause))) && (car(clause) != sc->else_symbol)) ||
66948 	      (!is_pair(cdr(clause))) ||
66949 	      (cadr(clause) == sc->feed_to_symbol))
66950 	    return_false(sc, clause);
66951 
66952 	  opc = alloc_opo(sc);
66953 	  top->v[V_ind(ctr)].o1 = opc;
66954 	  if (car(clause) == sc->else_symbol)
66955 	    {
66956 	      if (!is_null(cdr(p)))
66957 		return_false(sc, clause);
66958 	      opc->v[CASE_CLAUSE_KEYS].p = sc->else_symbol;
66959 	    }
66960 	  else
66961 	    {
66962 	      if (!s7_is_proper_list(sc, car(clause)))
66963 		return_false(sc, clause);
66964 	      opc->v[CASE_CLAUSE_KEYS].p = car(clause);
66965 	    }
66966 
66967 	  for (blen = 0, cp = cdr(clause); (is_pair(cp)) && (blen < (NUM_VUNIONS - 3)); blen++, cp = cdr(cp))
66968 	    {
66969 	      opc->v[V_ind(blen + CASE_CLAUSE_O1)].o1 = sc->opts[sc->pc];
66970 	      if (!cell_optimize(sc, cp))
66971 		return_false(sc, cp);
66972 	    }
66973 	  if (!is_null(cp))
66974 	    return_false(sc, cp);
66975 	  opc->v[1].i = blen;
66976 	  opc->v[0].fp = opt_case; /* just a placeholder I hope */
66977 	}
66978       if (!is_null(p))
66979 	return_false(sc, p);
66980       top->v[1].i = ctr;
66981       top->v[0].fp = opt_case;
66982       return(true);
66983     }
66984   return_false(sc, car_x);
66985 }
66986 
66987 /* -------- cell_let_temporarily -------- */
66988 
66989 #define LET_TEMP_O1 5
66990 
66991 static s7_pointer opt_let_temporarily(opt_info *o)
66992 {
66993   opt_info *o1;
66994   int32_t i, len;
66995   s7_pointer result;
66996 
66997   if (is_immutable_slot(o->v[1].p))
66998     immutable_object_error(opt_sc(o), set_elist_3(opt_sc(o), immutable_error_string, opt_sc(o)->let_temporarily_symbol, slot_symbol(o->v[1].p)));
66999 
67000   o1 = o->v[4].o1;
67001   o->v[3].p = slot_value(o->v[1].p);         /* save and protect old value */
67002   gc_protect_via_stack(opt_sc(o), o->v[3].p);
67003   slot_set_value(o->v[1].p, o1->v[0].fp(o1)); /* set new value */
67004   len = o->v[2].i - 1;
67005   for (i = 0; i < len; i++)
67006     {
67007       o1 = o->v[i + LET_TEMP_O1].o1;
67008       o1->v[0].fp(o1);
67009     }
67010   o1 = o->v[i + LET_TEMP_O1].o1;
67011   result = o1->v[0].fp(o1);
67012   slot_set_value(o->v[1].p, o->v[3].p);      /* restore old */
67013   opt_sc(o)->stack_end -= 4;
67014   return(result);
67015 }
67016 
67017 static bool opt_cell_let_temporarily(s7_scheme *sc, s7_pointer car_x, int32_t len)
67018 {
67019   s7_pointer vars;
67020   if (len <= 2)
67021     return_false(sc, car_x);
67022 
67023   vars = cadr(car_x);
67024   if ((len < (NUM_VUNIONS - LET_TEMP_O1)) &&
67025       (is_proper_list_1(sc, vars)) &&       /* just one var for now */
67026       (is_proper_list_2(sc, car(vars))) &&  /*   and var is (sym val) */
67027       (is_symbol(caar(vars))) &&
67028       (!is_immutable(caar(vars))) &&
67029       (!is_syntactic_symbol(caar(vars))))
67030     {
67031       s7_pointer p;
67032       opt_info *opc;
67033       int32_t i;
67034       opc = alloc_opo(sc);
67035       opc->v[1].p = lookup_slot_from(caaadr(car_x), sc->curlet);
67036       if (!is_slot(opc->v[1].p))
67037 	return_false(sc, car_x);
67038 
67039       opc->v[4].o1 = sc->opts[sc->pc];
67040       if (!cell_optimize(sc, cdaadr(car_x)))
67041 	return_false(sc, car_x);
67042 
67043       for (i = LET_TEMP_O1, p = cddr(car_x); is_pair(p); i++, p = cdr(p))
67044 	{
67045 	  opc->v[V_ind(i)].o1 = sc->opts[sc->pc];
67046 	  if (!cell_optimize(sc, p))
67047 	    return_false(sc, car_x);
67048 	}
67049 
67050       opc->v[2].i = len - 2;
67051       opc->v[0].fp = opt_let_temporarily;
67052       return(true);
67053     }
67054   return_false(sc, car_x);
67055 }
67056 
67057 /* -------- cell_do -------- */
67058 
67059 static void let_set_has_pending_value(s7_pointer lt)
67060 {
67061   s7_pointer vp;
67062   for (vp = let_slots(lt); tis_slot(vp); vp = next_slot(vp))
67063     if (!slot_pending_value_unchecked(vp))
67064       slot_set_pending_value(vp, eof_object);
67065     else slot_set_has_pending_value(vp);
67066 }
67067 
67068 static void let_clear_has_pending_value(s7_pointer lt)
67069 {
67070   s7_pointer vp;
67071   for (vp = let_slots(lt); tis_slot(vp); vp = next_slot(vp))
67072     slot_clear_has_pending_value(vp);
67073 }
67074 
67075 static s7_pointer opt_do_any(opt_info *o)
67076 {
67077   /* o->v[2].p=let, o->v[1].i=body end index, o->v[3].i=body length, o->v[4].i=return length, o->v[5].i=end index */
67078 
67079   opt_info *o1, *ostart, *body, *inits, *steps, *results;
67080   int32_t i, k;
67081   s7_pointer vp, old_e, result;
67082   s7_scheme *sc;
67083 
67084   sc = opt_sc(o);
67085   old_e = sc->curlet;
67086   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67087   sc->curlet = T_Let(o->v[2].p);
67088 
67089   /* init */
67090   inits = o->v[7].o1;
67091   for (k = 0, vp = let_slots(sc->curlet); tis_slot(vp); k++, vp = next_slot(vp))
67092     {
67093       o1 = inits->v[k].o1;
67094       slot_set_value(vp, o1->v[0].fp(o1));
67095     }
67096 
67097   ostart = o->v[12].o1;
67098   body = o->v[10].o1;
67099   results = o->v[11].o1;
67100   steps = o->v[13].o1;
67101   let_set_has_pending_value(sc->curlet);
67102 
67103   while (true)
67104     {
67105       /* end */
67106       if (ostart->v[0].fb(ostart))
67107 	break;
67108 
67109       /* body */
67110       for (i = 0; i < o->v[3].i; i++)
67111 	{
67112 	  o1 = body->v[i].o1;
67113 	  o1->v[0].fp(o1);
67114 	}
67115 
67116       /* step (let not let*) */
67117       for (k = 0, vp = let_slots(sc->curlet); tis_slot(vp); k++, vp = next_slot(vp))
67118 	if (has_stepper(vp))
67119 	  {
67120 	    o1 = steps->v[k].o1;
67121 	    slot_simply_set_pending_value(vp, o1->v[0].fp(o1));
67122 	  }
67123       for (vp = let_slots(sc->curlet); tis_slot(vp); vp = next_slot(vp))
67124 	if (has_stepper(vp))
67125 	  slot_set_value(vp, slot_pending_value(vp));
67126     }
67127 
67128   /* result */
67129   result = sc->T;
67130   for (i = 0; i < o->v[4].i; i++)
67131     {
67132       o1 = results->v[i].o1;
67133       result = o1->v[0].fp(o1);
67134     }
67135   let_clear_has_pending_value(sc->curlet);
67136   unstack(sc);
67137   sc->curlet = old_e;
67138   return(result);
67139 }
67140 
67141 static s7_pointer opt_do_step_1(opt_info *o)
67142 {
67143   /* 1 stepper (multi inits perhaps), 1 body, 1 rtn */
67144   opt_info *o1, *ostart, *ostep, *inits, *body;
67145   int32_t k;
67146   s7_pointer vp, old_e, result, stepper = NULL;
67147   s7_scheme *sc;
67148 
67149   sc = opt_sc(o);
67150   ostep = o->v[9].o1;
67151   old_e = sc->curlet;
67152   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67153   sc->curlet = T_Let(o->v[2].p);
67154 
67155   inits = o->v[7].o1;
67156   for (k = 0, vp = let_slots(sc->curlet); tis_slot(vp); k++, vp = next_slot(vp))
67157     {
67158       o1 = inits->v[k].o1;
67159       slot_set_value(vp, o1->v[0].fp(o1));
67160       if (has_stepper(vp)) stepper = vp;
67161     }
67162   ostart = o->v[12].o1;
67163   body = o->v[10].o1;
67164 
67165   while (!(ostart->v[0].fb(ostart)))
67166     {
67167       body->v[0].fp(body);
67168       slot_set_value(stepper, ostep->v[0].fp(ostep));
67169     }
67170   o1 = o->v[11].o1;
67171   result = o1->v[0].fp(o1);
67172 
67173   unstack(sc);
67174   sc->curlet = old_e;
67175   return(result);
67176 }
67177 
67178 static s7_pointer opt_do_step_i(opt_info *o)
67179 {
67180   /* 1 stepper (multi inits perhaps), 1 body, 1 rtn */
67181   opt_info *o1, *ostart, *ostep, *inits, *body;
67182   int32_t k;
67183   s7_pointer vp, old_e, result, stepper = NULL, si;
67184   s7_scheme *sc;
67185   s7_int end, incr;
67186 
67187   sc = opt_sc(o);
67188   ostep = o->v[9].o1;
67189   old_e = sc->curlet;
67190   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67191   sc->curlet = T_Let(o->v[2].p);
67192 
67193   inits = o->v[7].o1;
67194   for (k = 0, vp = let_slots(sc->curlet); tis_slot(vp); k++, vp = next_slot(vp))
67195     {
67196       o1 = inits->v[k].o1;
67197       slot_set_value(vp, o1->v[0].fp(o1));
67198       if (has_stepper(vp)) stepper = vp;
67199     }
67200   ostart = o->v[12].o1;
67201   body = o->v[10].o1;
67202 
67203   end = integer(slot_value(ostart->v[2].p));
67204   incr = ostep->v[2].i;
67205   si = make_mutable_integer(sc, integer(slot_value(ostart->v[1].p)));
67206   slot_set_value(stepper, si);
67207 
67208   while (integer(si) != end)
67209     {
67210       body->v[0].fp(body);
67211       integer(si) += incr;
67212     }
67213   clear_mutable_integer(si);
67214 
67215   o1 = o->v[11].o1;
67216   result = o1->v[0].fp(o1);
67217 
67218   unstack(sc);
67219   sc->curlet = old_e;
67220   return(result);
67221 }
67222 
67223 static s7_pointer opt_do_no_vars(opt_info *o)
67224 {
67225   /* no vars, no return, o->v[2].p=let, o->v[1].i=body end index, o->v[3].i=body length, o->v[4].i=return length=0, o->v[5].i=end index, 6=end test */
67226   opt_info *ostart;
67227   int32_t len;
67228   s7_pointer old_e;
67229   s7_scheme *sc;
67230   bool (*fb)(opt_info *o);
67231   sc = opt_sc(o);
67232 
67233   old_e = sc->curlet;
67234   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67235   sc->curlet = o->v[2].p;
67236   len = o->v[3].i;
67237   ostart = o->v[6].o1;
67238   fb = ostart->v[0].fb;
67239 
67240   if (len == 0)       /* titer */
67241     while (!(fb(ostart)));
67242   else
67243     {
67244       opt_info *body;
67245       body = o->v[7].o1;
67246       while (!(fb(ostart)))   /* tshoot, tfft */
67247 	{
67248 	  int32_t i;
67249 	  for (i = 0; i < len; i++)
67250 	    {
67251 	      opt_info *o1;
67252 	      o1 = body->v[i].o1;
67253 	      o1->v[0].fp(o1);
67254 	    }}}
67255   unstack(sc);
67256   sc->curlet = old_e;
67257   return(sc->T);
67258 }
67259 
67260 static s7_pointer opt_do_1(opt_info *o)
67261 {
67262   /* 1 var, 1 expr, no return */
67263   opt_info *o1, *ostart, *ostep, *body; /* o->v[2].p=let, o->v[5].i=end index */
67264   s7_pointer vp, old_e;
67265   s7_scheme *sc;
67266   sc = opt_sc(o);
67267 
67268   old_e = sc->curlet;
67269   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67270   sc->curlet = o->v[2].p;
67271 
67272   ostep = o->v[9].o1;
67273   vp = let_slots(o->v[2].p);
67274   o1 = o->v[11].o1;
67275   slot_set_value(vp, o1->v[0].fp(o1));
67276   ostart = o->v[12].o1;
67277   body = o->v[10].o1;
67278 
67279   if ((o->v[8].i == 1) &&
67280       (is_t_integer(slot_value(vp))))
67281     {
67282       if ((ostep->v[0].fp == opt_p_ii_ss_add) || /* tmap */
67283 	  (ostep->v[0].fp == i_to_p))
67284 	{
67285 	  s7_pointer step_val;
67286 	  step_val = make_mutable_integer(sc, integer(slot_value(vp)));
67287 	  slot_set_value(vp, step_val);
67288 	  if (ostep->v[0].fp == opt_p_ii_ss_add)
67289 	    while (!ostart->v[0].fb(ostart))
67290 	      {
67291 		body->v[0].fp(body);
67292 		integer(step_val) = opt_i_ii_ss_add(ostep);
67293 	      }
67294 	  else
67295 	    while (!ostart->v[0].fb(ostart))
67296 	      {
67297 		body->v[0].fp(body);
67298 		integer(step_val) = ostep->v[O_WRAP].fi(ostep);
67299 	      }
67300 	  unstack(sc);
67301 	  sc->curlet = old_e;
67302 	  return(sc->T);
67303 	}
67304       o->v[8].i = 2;
67305     }
67306   while (!(ostart->v[0].fb(ostart)))   /* s7test tref */
67307     {
67308       body->v[0].fp(body);
67309       slot_set_value(vp, ostep->v[0].fp(ostep));
67310     }
67311   unstack(sc);
67312   sc->curlet = old_e;
67313   return(sc->T);
67314 }
67315 
67316 static s7_pointer opt_do_n(opt_info *o)
67317 {
67318   /* 1 var, no return */
67319   opt_info *o1, *ostart, *ostep, *body; /* o->v[2].p=let, o->v[3].i=body length, o->v[5].i=end index */
67320   int32_t len;
67321   s7_pointer vp, old_e;
67322   s7_scheme *sc;
67323   sc = opt_sc(o);
67324 
67325   old_e = sc->curlet;
67326   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67327   sc->curlet = o->v[2].p;
67328   ostep = o->v[9].o1;
67329   len = o->v[3].i;
67330 
67331   vp = let_slots(o->v[2].p);
67332   o1 = o->v[11].o1;
67333   slot_set_value(vp, o1->v[0].fp(o1));
67334   ostart = o->v[12].o1;
67335   body = o->v[7].o1;
67336 
67337   if (len == 2) /* tmac tshoot */
67338     {
67339       opt_info *e1, *e2;
67340       e1 = body->v[0].o1;
67341       e2 = body->v[1].o1;
67342       while (!(ostart->v[0].fb(ostart)))
67343 	{
67344 	  e1->v[0].fp(e1);
67345 	  e2->v[0].fp(e2);
67346 	  slot_set_value(vp, ostep->v[0].fp(ostep));
67347 	}}
67348   else
67349     while (!ostart->v[0].fb(ostart)) /* tfft teq */
67350       {
67351 	int32_t i;
67352 	for (i = 0; i < len; i++)
67353 	  {
67354 	    o1 = body->v[i].o1;
67355 	    o1->v[0].fp(o1);
67356 	  }
67357 	slot_set_value(vp, ostep->v[0].fp(ostep));
67358       }
67359   unstack(sc);
67360   sc->curlet = old_e;
67361   return(sc->T);
67362 }
67363 
67364 static s7_pointer opt_dotimes_2(opt_info *o)
67365 {
67366   /* 1 var, no return */
67367   opt_info *o1, *body; /* o->v[2].p=let, o->v[3].i=body length, o->v[4].i=return length=0, o->v[5].i=end index, v6.i=end, v7=init */
67368   int32_t len;
67369   s7_int end;
67370   s7_pointer vp, old_e;
67371   s7_scheme *sc;
67372   sc = opt_sc(o);
67373 
67374   old_e = sc->curlet;
67375   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67376   sc->curlet = o->v[2].p;
67377   len = o->v[3].i;
67378 
67379   vp = let_dox1_value(o->v[2].p);
67380   if (is_slot(let_dox_slot2_unchecked(o->v[2].p)))
67381     end = integer(slot_value(let_dox_slot2(o->v[2].p)));
67382   else end = o->v[6].i;
67383 
67384   o1 = o->v[11].o1;
67385   integer(vp) = integer(o1->v[0].fp(o1));
67386   body = o->v[7].o1;
67387 
67388   if (len == 2)                 /* tmac tmisc */
67389     {
67390       opt_info *e1, *e2;
67391       e1 = body->v[0].o1;
67392       e2 = body->v[1].o1;
67393       while (integer(vp) < end)
67394 	{
67395 	  e1->v[0].fp(e1);
67396 	  e2->v[0].fp(e2);
67397 	  integer(vp)++;
67398 	}}
67399   else
67400     while (integer(vp) < end)  /* tbig sg */
67401       {
67402 	int32_t i;
67403 	for (i = 0; i < len; i++)
67404 	  {
67405 	    o1 = body->v[i].o1;
67406 	    o1->v[0].fp(o1);
67407 	  }
67408 	integer(vp)++;
67409       }
67410   unstack(sc);
67411   sc->curlet = old_e;
67412   return(sc->T);
67413 }
67414 
67415 static s7_pointer opt_do_list_simple(opt_info *o)
67416 {
67417   /* 1 var, 1 expr, no return, step by cdr, end=null? */
67418   opt_info *o1; /* o->v[2].p=let, o->v[5].i=end index */
67419   s7_pointer vp, old_e;
67420   s7_scheme *sc;
67421   s7_pointer (*fp)(opt_info *o);
67422   sc = opt_sc(o);
67423 
67424   old_e = sc->curlet;
67425   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67426   sc->curlet = o->v[2].p;
67427 
67428   vp = let_slots(o->v[2].p);
67429   o1 = o->v[11].o1;
67430   slot_set_value(vp, o1->v[0].fp(o1));
67431   o1 = o->v[10].o1;
67432 
67433   fp = o1->v[0].fp;
67434   if (fp == opt_if_bp) fp = opt_if_bp_nr;
67435   while (!is_null(slot_value(vp)))
67436     {
67437       fp(o1);
67438       slot_set_value(vp, cdr(slot_value(vp)));
67439     }
67440   unstack(sc);
67441   sc->curlet = old_e;
67442   return(sc->T);
67443 }
67444 
67445 static s7_pointer opt_do_very_simple(opt_info *o)
67446 {
67447   /* like simple but step can be direct, v[2].p is a let */
67448   opt_info *o1;
67449   s7_int end;
67450   s7_pointer vp, old_e;
67451   s7_pointer (*f)(opt_info *o);
67452   s7_scheme *sc;
67453   sc = opt_sc(o);
67454   old_e = sc->curlet;
67455   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67456   sc->curlet = o->v[2].p;
67457 
67458   vp = let_dox1_value(o->v[2].p);
67459   if (is_slot(let_dox_slot2_unchecked(o->v[2].p)))
67460     end = integer(slot_value(let_dox_slot2(o->v[2].p)));
67461   else end = o->v[3].i;
67462 
67463   o1 = o->v[11].o1;
67464   integer(vp) = integer(o1->v[0].fp(o1));
67465 
67466   o1 = o->v[10].o1;
67467   f = o1->v[0].fp;
67468   if (f == opt_p_pip_ssf)                            /* tref.scm */
67469     {
67470       opt_info *o2;
67471       o2 = o1;
67472       o1 = o2->v[4].o1;
67473       while (integer(vp) < end)
67474 	{
67475 	  o2->v[3].p_pip_f(o2->sc, slot_value(o2->v[1].p), integer(slot_value(o2->v[2].p)), o1->v[0].fp(o1));
67476 	  integer(vp)++;
67477 	}}
67478   else
67479     {
67480       if (f == opt_p_pip_sso)
67481 	{
67482 	  if ((let_dox_slot1(o->v[2].p) == o1->v[2].p) && (o1->v[2].p == o1->v[4].p))
67483 	    {
67484 	      if (((o1->v[5].p_pip_f == float_vector_set_unchecked_p) &&
67485 		   (o1->v[6].p_pi_f == float_vector_ref_unchecked_p)) ||
67486 		  ((o1->v[5].p_pip_f == int_vector_set_unchecked_p) &&
67487 		   (o1->v[6].p_pi_f == int_vector_ref_unchecked_p)))
67488 		{
67489 		  copy_to_same_type(sc, slot_value(o1->v[1].p), slot_value(o1->v[3].p), integer(vp), end, integer(vp));
67490 		  unstack(sc);
67491 		  sc->curlet = old_e;
67492 		  return(sc->T);
67493 		}}
67494 	  while (integer(vp) < end)
67495 	    {
67496 	      o1->v[5].p_pip_f(o1->sc, slot_value(o1->v[1].p), integer(slot_value(o1->v[2].p)),
67497 			       o1->v[6].p_pi_f(o1->sc, slot_value(o1->v[3].p), integer(slot_value(o1->v[4].p))));
67498 	      integer(vp)++;
67499 	    }}
67500       else
67501 	{
67502 	  if ((f == opt_set_p_i_f) &&                      /* tvect.scm */
67503 	      (is_t_integer(slot_value(o1->v[1].p))) &&
67504 	      (o1->v[1].p != let_dox_slot1(o->v[2].p)))
67505 	    {
67506 	      s7_pointer ival;
67507 	      opt_info *o2;
67508 	      s7_int (*fi)(opt_info *o);
67509 	      ival = make_mutable_integer(sc, integer(slot_value(o1->v[1].p)));
67510 	      slot_set_value(o1->v[1].p, ival);
67511 	      o2 = o1->v[5].o1;                  /* set_p_i_f: x = make_integer(opt_sc(o), o->v[6].fi(o->v[5].o1)); */
67512 	      fi = o2->v[0].fi;
67513 	      while (integer(vp) < end)
67514 		{
67515 		  integer(ival) = fi(o2);
67516 		  integer(vp)++;
67517 		}
67518 	      slot_set_value(o1->v[1].p, make_integer(sc, integer(slot_value(o1->v[1].p))));
67519 	    }
67520 	  else
67521 	    {
67522 	      if ((f == opt_d_7pid_ssf_nr) &&           /* tref.scm */
67523 		  (o1->v[4].d_7pid_f == float_vector_set_unchecked))
67524 		{
67525 		  s7_pointer fv, ind;
67526 		  opt_info *o2;
67527 		  s7_double (*fd)(opt_info *o);
67528 		  o2 = o1->v[10].o1;
67529 		  fv = slot_value(o1->v[1].p);
67530 		  ind = o1->v[2].p;
67531 		  fd = o2->v[0].fd;
67532 		  while (integer(vp) < end)
67533 		    {
67534 		      float_vector_set_unchecked(sc, fv, integer(slot_value(ind)), fd(o2));
67535 		      integer(vp)++;
67536 		    }}
67537 	      else
67538 		while (integer(vp) < end)
67539 		  {
67540 		    f(o1);
67541 		    integer(vp)++;
67542 		  }}}}
67543   unstack(sc);
67544   sc->curlet = old_e;
67545   return(sc->T);
67546 }
67547 
67548 static s7_pointer opt_do_prepackaged(opt_info *o)
67549 {
67550   opt_info *o1;
67551   s7_int end;
67552   s7_pointer vp, old_e;
67553   s7_scheme *sc;
67554   sc = opt_sc(o);
67555 
67556   old_e = sc->curlet;
67557   push_stack_no_let_no_code(sc, OP_GC_PROTECT, old_e);
67558   sc->curlet = o->v[2].p;
67559 
67560   vp = let_dox1_value(o->v[2].p);
67561   if (is_slot(let_dox_slot2_unchecked(o->v[2].p)))
67562     end = integer(slot_value(let_dox_slot2(o->v[2].p)));
67563   else end = o->v[3].i;
67564 
67565   o1 = o->v[11].o1;
67566   integer(vp) = integer(o1->v[0].fp(o1));
67567 
67568   o->v[6].p = vp;
67569   o->v[1].i = end;
67570   o->v[7].fp(o);  /* call opt_do_i|dpnr below */
67571 
67572   unstack(sc);
67573   sc->curlet = old_e;
67574   return(sc->T);
67575 }
67576 
67577 static s7_pointer opt_do_dpnr(opt_info *o)
67578 {
67579   opt_info *o1;
67580   s7_pointer vp;
67581   s7_int end;
67582   s7_double (*f)(opt_info *o);
67583 
67584   end = o->v[1].i;
67585   vp = o->v[6].p;
67586   o1 = o->v[10].o1; /* the body */
67587   f = o1->v[O_WRAP].fd;
67588   while (integer(vp) < end)
67589     {
67590       f(o1);
67591       integer(vp)++;
67592     }
67593   return(NULL);
67594 }
67595 
67596 static s7_pointer opt_do_ipnr(opt_info *o)
67597 {
67598   opt_info *o1;
67599   s7_pointer vp;
67600   s7_int end;
67601   s7_int (*f)(opt_info *o);
67602 
67603   end = o->v[1].i;
67604   vp = o->v[6].p;
67605   o1 = o->v[10].o1; /* the body */
67606   f = o1->v[O_WRAP].fi;
67607   while (integer(vp) < end)
67608     {
67609       f(o1);
67610       integer(vp)++;
67611     }
67612   return(NULL);
67613 }
67614 
67615 static bool stop_is_safe(s7_scheme *sc, s7_pointer stop, s7_pointer body)
67616 {
67617   /* this could be folded into the cell_optimize traveral */
67618   s7_pointer p;
67619   for (p = body; is_pair(p); p = cdr(p))
67620     if ((is_pair(car(p))) &&
67621 	(caar(p) == sc->set_symbol) &&
67622 	(is_pair(cdar(p))) &&
67623 	(cadar(p) == stop))
67624       return(!s7_tree_memq(sc, stop, cdr(p)));
67625   return(true);
67626 }
67627 
67628 static bool tree_has_setters(s7_scheme *sc, s7_pointer tree)
67629 {
67630   clear_symbol_list(sc);
67631   add_symbol_to_list(sc, sc->set_symbol);
67632   add_symbol_to_list(sc, sc->vector_set_symbol);
67633   add_symbol_to_list(sc, sc->list_set_symbol);
67634   add_symbol_to_list(sc, sc->let_set_symbol);
67635   add_symbol_to_list(sc, sc->hash_table_set_symbol);
67636   add_symbol_to_list(sc, sc->set_car_symbol);
67637   add_symbol_to_list(sc, sc->set_cdr_symbol);
67638   return(tree_set_memq(sc, tree));
67639 }
67640 
67641 static bool do_is_safe(s7_scheme *sc, s7_pointer body, s7_pointer steppers, s7_pointer var_list, bool *has_set);
67642 
67643 static bool do_passes_safety_check(s7_scheme *sc, s7_pointer body, s7_pointer stepper, bool *has_set)
67644 {
67645   if (!is_pair(body)) return(true);
67646   if (!is_safety_checked(body))
67647     {
67648       set_safety_checked(body);
67649       if (!(do_is_safe(sc, body, (stepper != sc->nil) ? list_1(sc, stepper) : sc->nil, sc->nil, has_set)))
67650 	set_unsafe_do(body);
67651     }
67652   return(!is_unsafe_do(body));
67653 }
67654 
67655 #define SIZE_O NUM_VUNIONS
67656 
67657 static bool all_integers(s7_scheme *sc, s7_pointer expr)
67658 {
67659   if ((is_symbol(car(expr))) && (is_all_integer(car(expr))))
67660     {
67661       s7_pointer p;
67662       for (p = cdr(expr); is_pair(p); p = cdr(p))
67663 	if (!((is_t_integer(car(p))) ||
67664 	      ((is_symbol(car(p))) && (is_t_integer(slot_value(lookup_slot_from(car(p), sc->curlet))))) ||
67665 	      ((is_pair(car(p))) && (all_integers(sc, car(p))))))
67666 	  break;
67667       return(is_null(p));
67668     }
67669   return(false);
67670 }
67671 
67672 static bool all_floats(s7_scheme *sc, s7_pointer expr)
67673 {
67674   if ((is_symbol(car(expr))) && (is_all_float(car(expr))))
67675     {
67676       s7_pointer p;
67677       for (p = cdr(expr); is_pair(p); p = cdr(p))
67678 	if (!((is_t_real(car(p))) ||
67679 	      ((is_symbol(car(p))) && (is_t_real(slot_value(lookup_slot_from(car(p), sc->curlet))))) ||
67680 	      ((is_pair(car(p))) && (all_floats(sc, car(p))))))
67681 	  break;
67682       return(is_null(p));
67683     }
67684   return(false);
67685 }
67686 
67687 static bool opt_cell_do(s7_scheme *sc, s7_pointer car_x, int32_t len)
67688 {
67689   opt_info *opc;
67690   s7_pointer p, end, let = NULL, old_e, stop, ind, ind_step;
67691   int32_t i, k, var_len, body_len, body_index, step_len, rtn_len, step_pc, init_pc, end_test_pc;
67692   bool has_set = false;
67693   opt_info *init_o[SIZE_O], *step_o[SIZE_O], *body_o[SIZE_O], *return_o[SIZE_O];
67694 
67695   if (len < 3)
67696     return_false(sc, car_x);
67697 
67698   if (!s7_is_proper_list(sc, cadr(car_x)))
67699     return_false(sc, car_x);
67700   var_len = proper_list_length(cadr(car_x));
67701   step_len = var_len;
67702   body_len = len - 3;
67703   if (body_len > SIZE_O)
67704     return_false(sc, car_x);
67705   end = caddr(car_x);
67706   if (!is_pair(end))
67707     return_false(sc, car_x);
67708 
67709   old_e = sc->curlet;
67710   opc = alloc_opo(sc);
67711 
67712   let = make_let(sc, sc->curlet);
67713   push_stack(sc, OP_GC_PROTECT, old_e, let);
67714 
67715   /* the vars have to be added to the let before evaluating the inits
67716    *    else symbol_id can be > let_id (see "(test (do ((i (do ((i (do ((i 0 (+ i 1)))...")
67717    */
67718   clear_symbol_list(sc);
67719   for (p = cadr(car_x); is_pair(p); p = cdr(p))
67720     {
67721       s7_pointer var;
67722       var = car(p);
67723       if ((is_pair(var)) &&
67724 	  (is_symbol(car(var))) &&
67725 	  (is_pair(cdr(var))))
67726 	{
67727 	  s7_pointer sym;
67728 	  sym = car(var);
67729 
67730 	  if ((is_constant_symbol(sc, sym)) ||
67731 	      (symbol_has_setter(sym)))
67732 	    return_false(sc, car_x);
67733 	  if (symbol_is_in_list(sc, sym))
67734 	    eval_error(sc, "duplicate identifier in do: ~A", 30, var);
67735 	  add_symbol_to_list(sc, sym);
67736 	  add_slot(sc, let, sym, sc->undefined);
67737 	}
67738       else return_false(sc, car_x);
67739     }
67740 
67741   if (tis_slot(let_slots(let)))
67742     let_set_slots(let, reverse_slots(sc, let_slots(let)));
67743 
67744   /* inits */
67745   {
67746     s7_pointer slot;
67747     init_pc = sc->pc;
67748 
67749     for (k = 0, p = cadr(car_x), slot = let_slots(let); (is_pair(p)) && (k < SIZE_O); k++, p = cdr(p), slot = next_slot(slot))
67750       {
67751 	s7_pointer var;
67752 	var = car(p);
67753 
67754 	init_o[k] = sc->opts[sc->pc];
67755 	if (!cell_optimize(sc, cdr(var))) /* opt init in outer let */
67756 	  return_false(sc, car_x);
67757 	if (is_pair(cddr(var)))
67758 	  {
67759 	    set_has_stepper(slot);
67760 	    if (!is_null(cdddr(var)))
67761 	      return_false(sc, car_x);
67762 	  }
67763 	else
67764 	  {
67765 	    step_len--;
67766 	    if (!is_null(cddr(var)))
67767 	      return_false(sc, car_x);
67768 	  }
67769 	/* we can't use slot_set_value(slot, init_o[k]->v[0].fp(init_o[k])) to get the init value here: it might involve side-effects,
67770 	 *   and in some contexts might access variables that aren't set up yet.  So, we kludge around...
67771 	 */
67772 	if (is_symbol(cadr(var)))
67773 	  slot_set_value(slot, slot_value(lookup_slot_from(cadr(var), sc->curlet)));
67774 	else
67775 	  {
67776 	    if (!is_pair(cadr(var)))
67777 	      slot_set_value(slot, cadr(var));
67778 	    else
67779 	      {
67780 		if (is_proper_quote(sc, cadr(var)))
67781 		  slot_set_value(slot, cadadr(var));
67782 		else
67783 		  {
67784 		    s7_pointer sf;
67785 		    sf = lookup_checked(sc, caadr(var));
67786 		    if (is_c_function(sf))
67787 		      {
67788 			s7_pointer sig;
67789 			sig = c_function_signature(sf);
67790 			if (is_pair(sig))
67791 			  {
67792 			    if ((car(sig) == sc->is_integer_symbol) ||
67793 				((is_pair(car(sig))) &&
67794 				 (direct_memq(sc->is_integer_symbol, car(sig)))) ||
67795 				(all_integers(sc, cadr(var))))
67796 			      slot_set_value(slot, int_zero);
67797 			    else
67798 			      if ((car(sig) == sc->is_float_symbol) ||
67799 				  ((is_pair(car(sig))) &&
67800 				   (direct_memq(sc->is_float_symbol, car(sig)))) ||
67801 				  (all_floats(sc, cadr(var))))
67802 				slot_set_value(slot, real_zero);
67803 			    /* need for stepper too -- how does it know (+ x 0.1) is float? try (i 0 (floor (+ i 1))) etc */
67804 			  }}}}}}
67805     sc->curlet = let;
67806     for (p = cadr(car_x); is_pair(p); p = cdr(p))
67807       {
67808 	s7_pointer var;
67809 	var = car(p);
67810 	if (is_pair(cddr(var)))
67811 	  {
67812 	    s7_pointer init_type;
67813 	    init_type = opt_arg_type(sc, cdr(var));
67814 	    if (((init_type == sc->is_integer_symbol) ||
67815 		 (init_type == sc->is_float_symbol)) &&
67816 		(opt_arg_type(sc, cddr(var)) != init_type))
67817 	      {
67818 		unstack(sc); /* not pop_stack! */
67819 		sc->curlet = old_e;
67820 		return_false(sc, car_x);
67821 	      }}}}
67822 
67823   /* end test */
67824   end_test_pc = sc->pc;
67825   if (!bool_optimize_nw(sc, end))
67826     {
67827       unstack(sc); /* not pop_stack! */
67828       sc->curlet = old_e;
67829       return_false(sc, car_x);
67830     }
67831 
67832   stop = car(end);
67833   if ((is_proper_list_3(sc, stop)) &&
67834       ((car(stop) == sc->num_eq_symbol) || (car(stop) == sc->geq_symbol) || (car(stop) == sc->gt_symbol)) &&
67835       (is_symbol(cadr(stop))) &&
67836       ((is_t_integer(caddr(stop))) || (is_symbol(caddr(stop)))))
67837     {
67838       s7_pointer stop_slot;
67839       stop_slot = (is_symbol(caddr(stop))) ? opt_integer_symbol(sc, caddr(stop)) : sc->nil;
67840       if (stop_slot)
67841 	{
67842 	  s7_int lim;
67843 	  bool set_stop = false;
67844 	  s7_pointer slot;
67845 
67846 	  lim = (is_slot(stop_slot)) ? integer(slot_value(stop_slot)) : integer(caddr(stop));
67847 	  if (car(stop) == sc->gt_symbol) lim++;
67848 
67849 	  for (p = cadr(car_x), slot = let_slots(let); is_pair(p); p = cdr(p), slot = next_slot(slot))
67850 	    {
67851 	      /* this could be put off until it is needed (ref/set), but this code is not called much
67852 	       *    another choice: go from init downto 0: init is lim
67853 	       */
67854 	      if (slot_symbol(slot) == cadr(stop))
67855 		set_stop = true; /* don't overrule this decision below */
67856 	      if (has_stepper(slot))
67857 		{
67858 		  s7_pointer var, step;
67859 		  var = car(p);
67860 		  step = caddr(var);
67861 		  if ((is_t_integer(slot_value(slot))) &&
67862 		      (is_pair(step)) &&
67863 		      (is_pair(cdr(step))) &&
67864 		      (car(var) == cadr(stop)) &&
67865 		      (car(var) == cadr(step)) &&
67866 		      ((car(stop) != sc->num_eq_symbol) || /* else > protects at least the top */
67867 		       ((caddr(step) == int_one) && (car(step) == sc->add_symbol))))
67868 		    {
67869 		      set_step_end(slot);
67870 		      denominator(slot_value(slot)) = lim;
67871 		    }}}
67872 
67873 	  if (!set_stop)
67874 	    {
67875 	      s7_pointer slot2;
67876 	      slot2 = opt_integer_symbol(sc, cadr(stop));
67877 	      if ((slot2) &&
67878 		  (stop_is_safe(sc, cadr(stop), cddr(car_x))))
67879 		{
67880 		  set_step_end(slot2);
67881 		  denominator(slot_value(slot2)) = lim;
67882 		}}}}
67883 
67884   /* body */
67885   body_index = sc->pc;
67886   for (k = 0, i = 3, p = cdddr(car_x); i < len; k++, i++, p = cdr(p))
67887     {
67888       opt_info *start;
67889       start = sc->opts[sc->pc];
67890       body_o[k] = start;
67891       if (i < 5) opc->v[V_ind(i + 7)].o1 = start;
67892       if (!cell_optimize(sc, p))
67893 	break;
67894       oo_idp_nr_fixup(start);
67895     }
67896   if (!is_null(p))
67897     {
67898       unstack(sc);
67899       sc->curlet = old_e;
67900       return_false(sc, car_x);
67901     }
67902 
67903   /* we faked up sc->curlet above, so s7_optimize_1 (float_optimize) isn't safe here
67904    *    this means if clm nested loops get here, they aren't fully optimized -- fallback into dox would be better
67905    */
67906   /* steps */
67907   step_pc = sc->pc;
67908   for (k = 0, p = cadr(car_x); is_pair(p); k++, p = cdr(p))
67909     {
67910       s7_pointer var;
67911       var = car(p);
67912       step_o[k] = sc->opts[sc->pc];
67913       if ((is_pair(cddr(var))) &&
67914 	  (!cell_optimize(sc, cddr(var))))
67915 	break;
67916     }
67917   if (!is_null(p))
67918     {
67919       unstack(sc);
67920       sc->curlet = old_e;
67921       return_false(sc, car_x);
67922     }
67923 
67924   /* result */
67925   /* rtn_len = 0; */
67926   if (!is_list(cdr(end)))
67927     {
67928       unstack(sc);
67929       sc->curlet = old_e;
67930       return_false(sc, car_x);
67931     }
67932   for (rtn_len = 0, p = cdr(end); (is_pair(p)) && (rtn_len < SIZE_O); p = cdr(p), rtn_len++)
67933     {
67934       return_o[rtn_len] = sc->opts[sc->pc];
67935       if (!cell_optimize(sc, p))
67936 	break;
67937     }
67938   if (!is_null(p))
67939     {
67940       unstack(sc);
67941       sc->curlet = old_e;
67942       return_false(sc, car_x);
67943     }
67944 
67945   opc->v[2].p = let;
67946   opc->v[3].i = len - 3; /* body_len */
67947   opc->v[4].i = rtn_len;
67948   opc->v[9].o1 = sc->opts[step_pc];
67949   sc->curlet = old_e;
67950 
67951   if ((var_len == 0) && (rtn_len == 0))
67952     {
67953       opt_info *body;
67954       opc->v[6].o1 = sc->opts[end_test_pc];
67955       opc->v[0].fp = opt_do_no_vars;
67956       if (body_len > 0)
67957 	{
67958 	  body = alloc_opo(sc);
67959 	  for (k = 0; k < body_len; k++)
67960 	    body->v[V_ind(k)].o1 = body_o[k];
67961 	  opc->v[7].o1 = body;
67962 	}
67963       return(true);
67964     }
67965 
67966   opc->v[8].i = 0;
67967   if (body_len == 1)
67968     {
67969       s7_pointer expr;
67970       expr = cadddr(car_x);
67971       if ((is_pair(expr)) &&
67972 	  ((is_safe_setter(car(expr))) ||
67973 	   ((car(expr) == sc->set_symbol) &&
67974 	    (cadr(expr) != caaadr(car_x))) || /* caadr: (stepper init ...) */
67975 	   ((car(expr) == sc->vector_set_symbol) &&
67976 	    (is_null(cddddr(expr))) &&
67977 	    (is_code_constant(sc, cadddr(expr))))))
67978 	opc->v[8].i = 1;
67979     }
67980   if ((var_len != 1) || (step_len != 1) || (rtn_len != 0))
67981     {
67982       opt_info *inits;
67983 
67984       opc->v[0].fp = ((step_len == 1) && (body_len == 1) && (rtn_len == 1)) ? opt_do_step_1 : opt_do_any;
67985       /* (do ((sum 0.0) (k 0 (+ k 1))) ((= k size) (set! (C i j) sum)) (set! sum (+ sum (* (A i k) (B k j))))) tmat */
67986 
67987       opc->v[12].o1 = sc->opts[end_test_pc];
67988 
67989       if ((opc->v[0].fp == opt_do_step_1) &&
67990 	  (opc->v[9].o1->v[0].fp == i_to_p) &&
67991 	  (opc->v[9].o1->v[O_WRAP].fi == opt_i_ii_sc_add) &&
67992 	  (opc->v[12].o1->v[0].fb == opt_b_ii_ss_eq))
67993 	opc->v[0].fp = opt_do_step_i;
67994 
67995       inits = alloc_opo(sc);
67996       for (k = 0; k < var_len; k++)
67997 	inits->v[V_ind(k)].o1 = init_o[k];
67998       opc->v[7].o1 = inits;
67999 
68000       if (opc->v[0].fp == opt_do_any)
68001 	{
68002 	  opt_info *body, *result, *step;
68003 
68004 	  body = alloc_opo(sc);
68005 	  for (k = 0; k < body_len; k++)
68006 	    body->v[V_ind(k)].o1 = body_o[k];
68007 	  opc->v[10].o1 = body;
68008 
68009 	  result = alloc_opo(sc);
68010 	  for (k = 0; k < rtn_len; k++)
68011 	    result->v[V_ind(k)].o1 = return_o[k];
68012 	  opc->v[11].o1 = result;
68013 
68014 	  step = alloc_opo(sc);
68015 	  for (k = 0; k < var_len; k++)
68016 	    step->v[V_ind(k)].o1 = step_o[k];
68017 	  opc->v[13].o1 = step;
68018 	}
68019       else
68020 	{
68021 	  opc->v[10].o1 = sc->opts[body_index];
68022 	  opc->v[11].o1 = return_o[0];
68023 	}
68024       return(true);
68025     }
68026 
68027   opc->v[0].fp = (body_len == 1) ? opt_do_1 : opt_do_n;
68028   p = caadr(car_x);
68029   ind = car(p);
68030   ind_step = caddr(p);
68031   end = caaddr(car_x);
68032 
68033   if (body_len == 1)
68034     opc->v[10].o1 = sc->opts[body_index];
68035   else
68036     {
68037       opt_info *body;
68038       body = alloc_opo(sc);
68039       for (k = 0; k < body_len; k++)
68040 	body->v[V_ind(k)].o1 = body_o[k];
68041       opc->v[7].o1 = body;
68042     }
68043   opc->v[11].o1 = sc->opts[init_pc];
68044   opc->v[12].o1 = sc->opts[end_test_pc];
68045   opc->v[13].o1 = sc->opts[step_pc];
68046 
68047   if ((is_pair(end)) &&                      /* (= i len|100) */
68048       (cadr(end) == ind) &&
68049       (is_pair(ind_step)))                   /* (+ i 1) */
68050     {
68051       if (((car(end) == sc->num_eq_symbol) || (car(end) == sc->geq_symbol)) &&
68052 	  ((is_symbol(caddr(end))) || (is_t_integer(caddr(end)))) &&
68053 	  (is_null(cdddr(end))) &&
68054 	  (car(ind_step) == sc->add_symbol) &&
68055 	  (cadr(ind_step) == ind) &&
68056 	  (caddr(ind_step) == int_one) &&
68057 	  (is_null(cdddr(ind_step))) &&
68058 	  (do_passes_safety_check(sc, cdddr(car_x), ind, &has_set)))
68059 	{
68060 	  s7_pointer slot;
68061 	  slot = let_slots(let);
68062 	  let_set_dox_slot1(let, slot);
68063 	  let_set_dox_slot2_unchecked(let, (is_symbol(caddr(end))) ? lookup_slot_from(caddr(end), sc->curlet) : sc->undefined);
68064 	  slot_set_value(slot, make_mutable_integer(sc, integer(slot_value(slot))));
68065 	  opc->v[4].i = body_index;
68066 	  if (body_len == 1)
68067 	    {
68068 	      opt_info *o1;
68069 	      opc->v[0].fp = opt_do_very_simple;
68070 	      if (is_t_integer(caddr(end)))
68071 		opc->v[3].i = integer(caddr(end));
68072 	      o1 = sc->opts[body_index];
68073 	      if (o1->v[0].fp == d_to_p_nr) /* snd-test: (do ((k 0 (+ k 1))) ((= k N)) (float-vector-set! rl k (read-sample rd))) */
68074 		{
68075 		  opc->v[0].fp = opt_do_prepackaged;
68076 		  opc->v[7].fp = opt_do_dpnr;
68077 		}
68078 	      else
68079 		{
68080 		  if (o1->v[0].fp == i_to_p_nr)
68081 		    {
68082 		      opc->v[0].fp = opt_do_prepackaged;
68083 		      opc->v[7].fp = opt_do_ipnr;
68084 		    }}}
68085 	  else
68086 	    {
68087 	      opc->v[0].fp = opt_dotimes_2;
68088 	      if (is_t_integer(caddr(end)))
68089 		opc->v[6].i = integer(caddr(end));
68090 	    }}
68091       else
68092 	if ((car(end) == sc->is_null_symbol) &&
68093 	    (is_null(cddr(end))) &&
68094 	    (car(ind_step) == sc->cdr_symbol) &&
68095 	    (cadr(ind_step) == ind) &&
68096 	    (is_null(cddr(ind_step))) &&
68097 	    (body_len == 1) &&
68098 	    (do_passes_safety_check(sc, cdddr(car_x), ind, &has_set)))
68099 	  opc->v[0].fp = opt_do_list_simple;
68100     }
68101   return(true);
68102 }
68103 
68104 static bool p_syntax(s7_scheme *sc, s7_pointer car_x, int32_t len)
68105 {
68106   opcode_t op;
68107   s7_pointer func;
68108   func = lookup_global(sc, car(car_x));
68109   op = (opcode_t)syntax_opcode(func);
68110   switch (op)
68111     {
68112     case OP_QUOTE:  if ((is_pair(cdr(car_x))) && (is_null(cddr(car_x)))) return(opt_cell_quote(sc, car_x)); break;
68113     case OP_SET:    if (len == 3) return(opt_cell_set(sc, car_x));       break;
68114     case OP_BEGIN:  if (len > 1) return(opt_cell_begin(sc, car_x, len)); break;
68115     case OP_WHEN:
68116     case OP_UNLESS: if (len > 2) return(opt_cell_when(sc, car_x, len));  break;
68117     case OP_COND:   if (len > 1) return(opt_cell_cond(sc, car_x));       break;
68118     case OP_CASE:   if (len > 2) return(opt_cell_case(sc, car_x));       break;
68119     case OP_AND:
68120     case OP_OR:     return(opt_cell_and(sc, car_x, len));
68121     case OP_IF:     return(opt_cell_if(sc, car_x, len));
68122     case OP_DO:     return(opt_cell_do(sc, car_x, len));
68123     case OP_LET_TEMPORARILY:
68124       return(opt_cell_let_temporarily(sc, car_x, len));
68125     default: /* lambda let with-let define etc */
68126       break;
68127     }
68128   return_false(sc, car_x);
68129 }
68130 
68131 
68132 /* -------------------------------------------------------------------------------- */
68133 static bool float_optimize_1(s7_scheme *sc, s7_pointer expr)
68134 {
68135   s7_pointer car_x, head;
68136 
68137   car_x = car(expr);
68138   if (!is_pair(car_x)) /* wrap constants/symbols */
68139     return(opt_float_not_pair(sc, car_x));
68140 
68141   head = car(car_x);
68142   if (is_symbol(head))
68143     {
68144       /* get func, check sig, check all args */
68145       s7_pointer s_func;
68146       s7_int len;
68147 
68148       len = s7_list_length(sc, car_x);
68149       /* need to check int_opt here */
68150 
68151       if ((is_syntactic_symbol(head)) ||
68152 	  (is_syntactic_pair(car_x)))
68153 	return(d_syntax_ok(sc, car_x, len));
68154 
68155       if ((is_global(head)) ||
68156 	  ((is_slot(global_slot(head))) &&
68157 	   (lookup_slot_from(head, sc->curlet) == global_slot(head))))
68158 	s_func = global_value(head);
68159       else return(d_implicit_ok(sc, car_x, len));
68160 
68161       if (is_c_function(s_func))
68162 	{
68163 	  opt_info *opc;
68164 	  opc = alloc_opo(sc);
68165 	  switch (len)
68166 	    {
68167 	    case 1:
68168 	      if (d_ok(sc, opc, s_func))
68169 		return(true);
68170 	      break;
68171 
68172 	    case 2:                            /* (f v) or (f d): (env e) or (abs x) */
68173 	      if ((d_d_ok(sc, opc, s_func, car_x)) ||
68174 		  (d_v_ok(sc, opc, s_func, car_x)) ||
68175 		  (d_p_ok(sc, opc, s_func, car_x)))
68176 		return(true);
68177 	      break;
68178 
68179 	    case 3:
68180 	      if ((d_dd_ok(sc, opc, s_func, car_x)) ||
68181 		  (d_vd_ok(sc, opc, s_func, car_x)) ||
68182 		  (d_id_ok(sc, opc, s_func, car_x)) ||
68183 		  (d_pd_ok(sc, opc, s_func, car_x)) ||
68184 		  (d_ip_ok(sc, opc, s_func, car_x)) ||
68185 		  (d_7pi_ok(sc, opc, s_func, car_x)))
68186 		return(true);
68187 	      break;
68188 
68189 	    case 4:
68190 	      if ((d_ddd_ok(sc, opc, s_func, car_x)) ||
68191 		  (d_7pid_ok(sc, opc, s_func, car_x)) ||
68192 		  (d_vid_ok(sc, opc, s_func, car_x)) ||
68193 		  (d_vdd_ok(sc, opc, s_func, car_x)) ||
68194 		  (d_7pii_ok(sc, opc, s_func, car_x)))
68195 		return(true);
68196 
68197 	      break;
68198 
68199 	    case 5:
68200 	      if ((d_dddd_ok(sc, opc, s_func, car_x)) ||
68201 		  (d_7piid_ok(sc, opc, s_func, car_x)))
68202 		return(true);
68203 	      break;
68204 
68205 	    default:
68206 	      if (d_add_any_ok(sc, opc, car_x, len))
68207 		return(true);
68208 	      break;
68209 	    }}
68210       else
68211 	if ((is_macro(s_func)) &&
68212 	    (!no_cell_opt(expr)))
68213 	  return(float_optimize(sc, set_plist_1(sc, s7_macroexpand(sc, s_func, cdar(expr))))); /* is this use of plist safe? */
68214     }
68215   return_false(sc, car_x);
68216 }
68217 
68218 static bool float_optimize(s7_scheme *sc, s7_pointer expr) {return((float_optimize_1(sc, expr)) && (sc->pc < OPTS_SIZE));}
68219 
68220 static bool int_optimize_1(s7_scheme *sc, s7_pointer expr)
68221 {
68222   s7_pointer car_x, head;
68223   car_x = car(expr);
68224 
68225   if (!is_pair(car_x)) /* wrap constants/symbols */
68226     return(opt_int_not_pair(sc, car_x));
68227 
68228   head = car(car_x);
68229   if (is_symbol(head))
68230     {
68231       s7_pointer s_func;
68232       s7_int len;
68233       len = s7_list_length(sc, car_x);
68234       if ((is_syntactic_symbol(head)) ||
68235 	  (is_syntactic_pair(car_x)))
68236 	return(i_syntax_ok(sc, car_x, len));
68237       if ((is_global(head)) ||
68238 	  ((is_slot(global_slot(head))) &&
68239 	   (lookup_slot_from(head, sc->curlet) == global_slot(head))))
68240 	s_func = global_value(head);
68241       else return(i_implicit_ok(sc, car_x, len));
68242 
68243       if (is_c_function(s_func))
68244 	{
68245 	  opt_info *opc;
68246 	  opc = alloc_opo(sc);
68247 	  switch (len)
68248 	    {
68249 	    case 2:
68250 	      if (i_idp_ok(sc, opc, s_func, car_x))
68251 		return(true);
68252 	      break;
68253 
68254 	    case 3:
68255 	      if ((i_ii_ok(sc, opc, s_func, car_x)) ||
68256 		  (i_7pi_ok(sc, opc, s_func, car_x)))
68257 		return(true);
68258 	      break;
68259 
68260 	    case 4:
68261 	      if ((i_iii_ok(sc, opc, s_func, car_x)) ||
68262 		  (i_7pii_ok(sc, opc, s_func, car_x)))
68263 		return(true);
68264 	      break;
68265 
68266 	    case 5:
68267 	      {
68268 		int32_t pstart;
68269 		pstart = sc->pc;
68270 		if (i_7piii_ok(sc, opc, s_func, car_x))
68271 		  return(true);
68272 		pc_fallback(sc, pstart);
68273 	      }
68274 	      /* break; */
68275 
68276 	    default:
68277 	      if (((head == sc->add_symbol) ||
68278 		   (head == sc->multiply_symbol)) &&
68279 		  (i_add_any_ok(sc, opc, car_x)))
68280 		return(true);
68281 	      break;
68282 	    }}
68283       else
68284 	if ((is_macro(s_func)) &&
68285 	    (!no_cell_opt(expr)))
68286 	  return(int_optimize(sc, set_plist_1(sc, s7_macroexpand(sc, s_func, cdar(expr)))));
68287     }
68288   return_false(sc, car_x);
68289 }
68290 
68291 static bool int_optimize(s7_scheme *sc, s7_pointer expr) {return((int_optimize_1(sc, expr)) && (sc->pc < OPTS_SIZE));}
68292 
68293 static bool cell_optimize_1(s7_scheme *sc, s7_pointer expr)
68294 {
68295   s7_pointer car_x, head;
68296 
68297   car_x = car(expr);
68298   if (!is_pair(car_x)) /* wrap constants/symbols */
68299     return(opt_cell_not_pair(sc, car_x));
68300 
68301   head = car(car_x);
68302   if (is_symbol(head))
68303     {
68304       s7_pointer s_func = NULL;
68305       s7_int len;
68306       len = s7_list_length(sc, car_x);
68307 
68308       if ((is_syntactic_symbol(head)) ||
68309 	  (is_syntactic_pair(car_x)))
68310 	return(p_syntax(sc, car_x, len));
68311 
68312       if ((is_global(head)) ||
68313 	  ((is_slot(global_slot(head))) &&
68314 	   (lookup_slot_from(head, sc->curlet) == global_slot(head))))
68315 	s_func = global_value(head);
68316       else return(p_implicit(sc, car_x, len));
68317 
68318       if (is_c_function(s_func))
68319 	{
68320 	  opt_info *opc;
68321 	  s7_pointer sig;
68322 	  int32_t pstart;
68323 
68324 	  sig = c_function_signature(s_func);
68325 	  opc = alloc_opo(sc);
68326 	  pstart = sc->pc;
68327 
68328 	  switch (len)
68329 	    {
68330 	    case 1:
68331 	      if (p_ok(sc, opc, s_func, car_x))
68332 		return(true);
68333 	      break;
68334 
68335 	    case 2:
68336 	      if ((p_i_ok(sc, opc, s_func, car_x, sc->pc)) ||
68337 		  (p_d_ok(sc, opc, s_func, car_x, sc->pc)) ||
68338 		  (p_p_ok(sc, opc, s_func, car_x)))
68339 		return(true);
68340 	      break;
68341 
68342 	    case 3:
68343 	      {
68344 		s7_i_ii_t ifunc;
68345 		if (is_symbol(cadr(car_x)))
68346 		  {
68347 		    if ((is_pair(sig)) &&
68348 			(is_pair(cdr(sig))) &&
68349 			(is_pair(cddr(sig))) &&
68350 			(caddr(sig) == sc->is_integer_symbol))
68351 		      {
68352 			if (p_pi_ok(sc, opc, s_func, sig, car_x))
68353 			  return(true);
68354 
68355 			if ((car(sig) == sc->is_float_symbol) ||
68356 			    (car(sig) == sc->is_real_symbol))
68357 			  {
68358 			    s7_d_7pi_t f;
68359 			    f = s7_d_7pi_function(s_func);
68360 			    if (f)
68361 			      {
68362 				sc->pc = pstart - 1;
68363 				if (float_optimize(sc, expr))
68364 				  {
68365 				    opc->v[O_WRAP].fd = opc->v[0].fd;
68366 				    opc->v[0].fp = d_to_p;
68367 				    return(true);
68368 				  }}}}
68369 		    pc_fallback(sc, pstart);
68370 		  }
68371 
68372 		ifunc = s7_i_ii_function(s_func);
68373 		sc->pc = pstart - 1;
68374 		if ((ifunc) &&
68375 		    (int_optimize(sc, expr)))
68376 		  {
68377 		    opc->v[O_WRAP].fi = opc->v[0].fi;
68378 		    opc->v[0].fp = i_to_p;
68379 		    if (opc->v[O_WRAP].fi == opt_i_ii_ss_add)
68380 		      opc->v[0].fp = opt_p_ii_ss_add;
68381 		    return(true);
68382 		  }
68383 		pc_fallback(sc, pstart);
68384 
68385 		if ((p_ii_ok(sc, opc, s_func, car_x, pstart)) ||
68386 		    (p_dd_ok(sc, opc, s_func, car_x, pstart)) ||
68387 		    (p_pp_ok(sc, opc, s_func, car_x, pstart)) ||
68388 		    (p_call_pp_ok(sc, opc, s_func, car_x, pstart)))
68389 		  return(true);
68390 	      }
68391 	      break;
68392 
68393 	    case 4:
68394 	      if (is_symbol(cadr(car_x)))
68395 		{
68396 		  if ((is_pair(sig)) &&
68397 		      (is_pair(cdr(sig))) &&
68398 		      (is_pair(cddr(sig))) &&
68399 		      (caddr(sig) == sc->is_integer_symbol))
68400 		    {
68401 		      if (p_pii_ok(sc, opc, s_func, car_x))
68402 			return(true);
68403 		      if (p_pip_ok(sc, opc, s_func, car_x))
68404 			return(true);
68405 
68406 		      if (((car(sig) == sc->is_float_symbol) ||
68407 			   (car(sig) == sc->is_real_symbol)) &&
68408 			  (s7_d_7pid_function(s_func)) &&
68409 			  (d_7pid_ok(sc, opc, s_func, car_x)))
68410 			{
68411 			  /* if d_7pid is ok, we need d_to_p for cell_optimize */
68412 			  opc->v[O_WRAP].fd = opc->v[0].fd;
68413 			  opc->v[0].fp = d_to_p;
68414 			  return(true);
68415 			}
68416 
68417 		      sc->pc = pstart - 1;
68418 		      if ((car(sig) == sc->is_integer_symbol) &&
68419 			  (s7_i_7pii_function(s_func)) &&
68420 			  (i_7pii_ok(sc, alloc_opo(sc), s_func, car_x)))
68421 			{
68422 			  opc->v[O_WRAP].fi = opc->v[0].fi;
68423 			  opc->v[0].fp = i_to_p;
68424 			  return(true);
68425 			}}
68426 		  pc_fallback(sc, pstart);
68427 		}
68428 
68429 	      if ((p_ppi_ok(sc, opc, s_func, car_x)) ||
68430 		  (p_ppp_ok(sc, opc, s_func, car_x)) ||
68431 		  (p_call_ppp_ok(sc, opc, s_func, car_x)))
68432 		return(true);
68433 	      break;
68434 
68435 	    case 5:
68436 	      if (((head == sc->float_vector_set_symbol) || (s_func == initial_value(sc->float_vector_set_symbol))) &&
68437 		  (d_7piid_ok(sc, opc, s_func, car_x)))
68438 		{
68439 		  opc->v[O_WRAP].fd = opc->v[0].fd;
68440 		  opc->v[0].fp = d_to_p;         /* as above, if d_7piid is ok, we need d_to_p for cell_optimize */
68441 		  return(true);
68442 		}
68443 	      if (i_7piii_ok(sc, opc, s_func, car_x))
68444 		{
68445 		  opc->v[O_WRAP].fi = opc->v[0].fi;
68446 		  opc->v[0].fp = i_to_p;
68447 		  return(true);
68448 		}
68449 	      if ((head == sc->int_vector_set_symbol) || (s_func == initial_value(sc->int_vector_set_symbol)))
68450 		return_false(sc, car_x);
68451 	      if (p_piip_ok(sc, opc, s_func, car_x))
68452 		return(true);
68453 	      pc_fallback(sc, pstart);
68454 
68455 	    default:  /* 3D vector-set etc */
68456 	      if (p_call_any_ok(sc, opc, s_func, car_x, len))
68457 		return(true);
68458 	      break;
68459 	    }}
68460       else
68461 	{
68462 	  if (is_closure(s_func))
68463 	    {
68464 	      opt_info *opc;
68465 	      opc = alloc_opo(sc);
68466 	      if (p_fx_any_ok(sc, opc, s_func, expr))
68467 		return(true);
68468 	    }
68469 	  if (is_macro(s_func))
68470 	    return_false(sc, car_x); /* macroexpand+cell_optimize here restarts the optimize process */
68471 	}}
68472   return_false(sc, car_x);
68473 }
68474 
68475 static bool cell_optimize(s7_scheme *sc, s7_pointer expr) {return((cell_optimize_1(sc, expr)) && (sc->pc < OPTS_SIZE));}
68476 
68477 static bool bool_optimize_nw_1(s7_scheme *sc, s7_pointer expr)
68478 {
68479   s7_pointer car_x, head;
68480 
68481   car_x = car(expr);
68482   if (!is_pair(car_x)) /* wrap constants/symbols */
68483     return(opt_bool_not_pair(sc, car_x));
68484 
68485   head = car(car_x);
68486   if (is_symbol(head))
68487     {
68488       s7_pointer s_func;
68489       s7_int len;
68490       len = s7_list_length(sc, car_x);
68491 
68492       if ((is_syntactic_symbol(head)) ||
68493 	  (is_syntactic_pair(car_x)))
68494 	{
68495 	  if (head == sc->and_symbol)
68496 	    return(opt_b_and(sc, car_x, len));
68497 	  if (head == sc->or_symbol)
68498 	    return(opt_b_or(sc, car_x, len));
68499 	  return_false(sc, car_x);
68500 	}
68501 
68502       if ((is_global(head)) ||
68503 	  ((is_slot(global_slot(head))) &&
68504 	   (lookup_slot_from(head, sc->curlet) == global_slot(head))))
68505 	s_func = global_value(head);
68506       else return_false(sc, car_x);
68507 
68508       if (is_c_function(s_func))
68509 	{
68510 	  if (symbol_id(head) != 0)             /* (float-vector? (block)) -- both safe c_funcs, but this is a method invocation */
68511 	    return_false(sc, car_x);
68512 	  switch (len)
68513 	    {
68514 	    case 2:
68515 	      return(b_idp_ok(sc, s_func, car_x, opt_arg_type(sc, cdr(car_x))));
68516 
68517 	    case 3:
68518 	      {
68519 		s7_b_pp_t bpf;
68520 		s7_b_7pp_t bpf7 = NULL;
68521 		bpf = s7_b_pp_function(s_func);
68522 		if (!bpf) bpf7 = s7_b_7pp_function(s_func);
68523 		if ((bpf) || (bpf7))
68524 		  {
68525 		    opt_info *opc;
68526 		    s7_pointer sig1, sig2, arg1, arg2;
68527 		    opc = alloc_opo(sc);
68528 
68529 		    arg1 = cadr(car_x);
68530 		    arg2 = caddr(car_x);
68531 		    sig1 = opt_arg_type(sc, cdr(car_x));
68532 		    sig2 = opt_arg_type(sc, cddr(car_x));
68533 
68534 		    if (sig2 == sc->is_integer_symbol)
68535 		      {
68536 			int32_t cur_index;
68537 			cur_index = sc->pc;
68538 
68539 			if ((sig1 == sc->is_integer_symbol) &&
68540 			    (b_ii_ok(sc, opc, s_func, car_x, arg1, arg2)))
68541 			  return(true);
68542 			pc_fallback(sc, cur_index);
68543 
68544 			if ((is_symbol(arg2)) &&
68545 			    (b_pi_ok(sc, opc, s_func, car_x, arg2)))
68546 			  return(true);
68547 			pc_fallback(sc, cur_index);
68548 		      }
68549 
68550 		    if ((sig1 == sc->is_float_symbol) &&
68551 			(sig2 == sc->is_float_symbol) &&
68552 			(b_dd_ok(sc, opc, s_func, car_x, arg1, arg2)))
68553 		      return(true);
68554 
68555 		    if (bpf)
68556 		      opc->v[3].b_pp_f = bpf;
68557 		    else opc->v[3].b_7pp_f = bpf7;
68558 		    return(b_pp_ok(sc, opc, s_func, car_x, arg1, arg2, bpf != NULL));
68559 		  }}
68560 	      break;
68561 
68562 	    default:
68563 	      break;
68564 	    }}
68565       else
68566 	if (is_macro(s_func))
68567 	  return_false(sc, car_x);
68568     }
68569   return_false(sc, car_x);
68570 }
68571 
68572 static bool bool_optimize_nw(s7_scheme *sc, s7_pointer expr) {return((bool_optimize_nw_1(sc, expr)) && (sc->pc < OPTS_SIZE));}
68573 
68574 static bool bool_optimize(s7_scheme *sc, s7_pointer expr)
68575 {
68576   int32_t start;
68577   opt_info *wrapper;
68578   start = sc->pc;
68579   if (bool_optimize_nw(sc, expr))
68580     return(true);
68581   pc_fallback(sc, start);
68582   wrapper = sc->opts[start];
68583   if (cell_optimize(sc, expr))
68584     {
68585       if (wrapper->v[O_WRAP].fp) /* (when (+ i 1) ...) */
68586 	return_false(sc, NULL);
68587       wrapper->v[O_WRAP].fp = wrapper->v[0].fp;
68588       wrapper->v[0].fb = p_to_b;
68589       return(true);
68590     }
68591   return_false(sc, NULL);
68592 }
68593 
68594 static s7_function s7_bool_optimize(s7_scheme *sc, s7_pointer expr)
68595 {
68596   sc->pc = 0;
68597   if ((bool_optimize(sc, expr)) && (sc->pc < OPTS_SIZE))
68598     return(opt_bool_any);
68599   return(NULL);
68600 }
68601 
68602 s7_float_function s7_float_optimize(s7_scheme *sc, s7_pointer expr)
68603 {
68604   sc->pc = 0;
68605   if ((float_optimize(sc, expr)) && (sc->pc < OPTS_SIZE))
68606     return(opt_float_any);
68607   return(NULL);
68608 }
68609 
68610 static s7_function s7_optimize_1(s7_scheme *sc, s7_pointer expr, bool nr)
68611 {
68612   if ((!is_pair(expr)) || (no_cell_opt(expr)) || (sc->debug != 0))
68613     return(NULL);
68614   sc->pc = 0;
68615   if (!no_int_opt(expr))
68616     {
68617       if (int_optimize(sc, expr))
68618 	return((nr) ? opt_int_any_nr : opt_wrap_int);
68619       pc_fallback(sc, 0);
68620       set_no_int_opt(expr);
68621     }
68622   if (!no_float_opt(expr))
68623     {
68624       if (float_optimize(sc, expr))
68625 	return((nr) ? opt_float_any_nr : opt_wrap_float);
68626       pc_fallback(sc, 0);
68627       set_no_float_opt(expr);
68628     }
68629   if (!no_bool_opt(expr))
68630     {
68631       if (bool_optimize_nw(sc, expr))
68632 	return((nr) ? opt_bool_any_nr : opt_wrap_bool);
68633       pc_fallback(sc, 0);
68634       set_no_bool_opt(expr);
68635     }
68636   if (cell_optimize(sc, expr))
68637     return((nr) ? opt_cell_any_nr : opt_wrap_cell);
68638   set_no_cell_opt(expr); /* checked above */
68639   return(NULL);
68640 }
68641 
68642 s7_function s7_optimize(s7_scheme *sc, s7_pointer expr)    {return(s7_optimize_1(sc, expr, false));}
68643 s7_function s7_optimize_nr(s7_scheme *sc, s7_pointer expr) {return(s7_optimize_1(sc, expr, true));}
68644 
68645 static s7_pointer g_optimize(s7_scheme *sc, s7_pointer args)
68646 {
68647   s7_function f;
68648   s7_pointer code;
68649   code = car(args);
68650 #if S7_DEBUGGING || OPT_SC_DEBUGGING
68651   scan_opts(sc, 17);
68652 #endif
68653   f = s7_optimize(sc, code);
68654 #if S7_DEBUGGING || OPT_SC_DEBUGGING
68655   if (f)
68656     {
68657       s7_pointer result;
68658       result = f(sc, car(code));
68659       scan_opts(sc, 16);
68660       return(result);
68661     }
68662   return(sc->undefined);
68663 #else
68664   return((f) ? f(sc, car(code)) : sc->undefined);
68665 #endif
68666 }
68667 
68668 static s7_function s7_cell_optimize(s7_scheme *sc, s7_pointer expr, bool nr)
68669 {
68670   sc->pc = 0;
68671   if ((cell_optimize(sc, expr)) && (sc->pc < OPTS_SIZE))
68672     return((nr) ? opt_cell_any_nr : opt_wrap_cell);
68673   return(NULL);
68674 }
68675 
68676 /* caller: s7_float_optimize(sc, expr, let) to return a function that when called evaluates expr in let
68677  *   s7_float_optimize returns an s7_float_function (s7_double opt_float_any(s7_scheme *sc, s7_pointer expr) normally)
68678  *   s7_float_any evaluates the program stored in sc->opts by calling opts[0]->f(opts[0])
68679  *   each portion of expr resides in an opt_info struct, evalled by calling its "fd" function on itself
68680  *   fd chooses the basic form of the expr, calling one of the underlying functions in opts[n] such as opt_d_c
68681  *   finally that calls the actual function such as abs_d
68682  */
68683 
68684 /* ---------------------------------------- for-each ---------------------------------------- */
68685 
68686 static Inline s7_pointer make_counter(s7_scheme *sc, s7_pointer iter)
68687 {
68688   s7_pointer x;
68689   new_cell(sc, x, T_COUNTER);
68690   counter_set_result(x, sc->nil);
68691   counter_set_list(x, iter);     /* iterator -- here it's always either an iterator or a pair */
68692   counter_set_capture(x, 0);     /* will be capture_let_counter */
68693   counter_set_let(x, sc->nil);   /* will be the saved let */
68694   counter_set_slots(x, sc->nil); /* local let slots before body is evalled */
68695   stack_set_has_counters(sc->stack);
68696   return(x);
68697 }
68698 
68699 static s7_pointer make_iterators(s7_scheme *sc, s7_pointer args)
68700 {
68701   s7_pointer p;
68702   sc->temp3 = args;
68703   sc->z = sc->nil;               /* don't use sc->args here -- it needs GC protection until we get the iterators */
68704   for (p = cdr(args); is_pair(p); p = cdr(p))
68705     {
68706       s7_pointer iter;
68707       iter = car(p);
68708       if (!is_iterator(car(p)))
68709 	iter = s7_make_iterator(sc, iter);
68710       sc->z = cons(sc, iter, sc->z);
68711     }
68712   sc->temp3 = sc->nil;
68713   return(proper_list_reverse_in_place(sc, sc->z));
68714 }
68715 
68716 static s7_pointer g_for_each_closure(s7_scheme *sc, s7_pointer f, s7_pointer seq)
68717 {
68718   s7_pointer body;
68719 
68720   body = closure_body(f);
68721   if (!no_cell_opt(body)) /* if at top level we often get an unoptimized (not safe) function here that can be cell_optimized below */
68722     {
68723       s7_function func;
68724       s7_pointer old_e, expr, pars, val, slot;
68725 
68726       old_e = sc->curlet;
68727       pars = closure_args(f);
68728       if (is_float_vector(seq))
68729 	val = real_zero;
68730       else val = ((is_int_vector(seq)) || (is_byte_vector(seq))) ? int_zero : sc->F;
68731       sc->curlet = make_let_with_slot(sc, closure_let(f), car(pars), val);
68732       slot = let_slots(sc->curlet);
68733 
68734       if (is_null(cdr(body)))
68735 	{
68736 	  expr = car(body);
68737 	  func = s7_optimize_nr(sc, body);
68738 	}
68739       else
68740 	{
68741 	  expr = cons(sc, sc->begin_symbol, body);
68742 	  sc->v = expr; /* GC protection? */
68743 	  func = s7_cell_optimize(sc, cons(sc, expr, sc->nil), true);
68744 	}
68745 
68746       if (func)
68747 	{
68748 	  s7_int (*fi)(opt_info *o);
68749 	  opt_info *o;
68750 
68751 	  if (is_pair(seq))
68752 	    {
68753 	      s7_pointer x, y;
68754 	      for (x = seq, y = x; is_pair(x); )
68755 		{
68756 		  slot_set_value(slot, car(x));
68757 		  func(sc, expr);
68758 		  x = cdr(x);
68759 		  if (is_pair(x))
68760 		    {
68761 		      slot_set_value(slot, car(x));
68762 		      func(sc, expr);
68763 		      y = cdr(y);
68764 		      x = cdr(x);
68765 		      if (x == y) return(sc->unspecified);
68766 		    }}
68767 	      return(sc->unspecified);
68768 	    }
68769 
68770 	  if (is_float_vector(seq))
68771 	    {
68772 	      s7_double *vals;
68773 	      s7_int i, len;
68774 	      len = vector_length(seq);
68775 	      vals = float_vector_floats(seq);
68776 
68777 	      if ((len > 1000) &&
68778 		  (!tree_has_setters(sc, body)))
68779 		{
68780 		  s7_pointer sv;
68781 		  sv = s7_make_mutable_real(sc, 0.0);
68782 		  slot_set_value(slot, sv);
68783 		  if (func == opt_float_any_nr)
68784 		    {
68785 		      s7_double (*fd)(opt_info *o);
68786 		      o = sc->opts[0];
68787 		      fd = o->v[0].fd;
68788 		      for (i = 0; i < len; i++)
68789 			{
68790 			  real(sv) = vals[i];
68791 			  fd(o);
68792 			}}
68793 		  else
68794 		    for (i = 0; i < len; i++)
68795 		      {
68796 			real(sv) = vals[i];
68797 			func(sc, expr);
68798 		      }
68799 		  return(sc->unspecified);
68800 		}
68801 	      for (i = 0; i < len; i++)
68802 		{
68803 		  slot_set_value(slot, make_real(sc, vals[i]));
68804 		  func(sc, expr);
68805 		}
68806 	      return(sc->unspecified);
68807 	    }
68808 
68809 	  /* if no set! vector|list|let|hash-table-set! set-car!|cdr! mutable arg? */
68810 	  if (is_int_vector(seq))
68811 	    {
68812 	      s7_int *vals;
68813 	      s7_int i, len;
68814 	      len = vector_length(seq);
68815 	      vals = int_vector_ints(seq);
68816 
68817 	      if ((len > 1000) &&
68818 		  (!tree_has_setters(sc, body)))
68819 		{
68820 		  s7_pointer sv;
68821 		  sv = make_mutable_integer(sc, 0);
68822 		  slot_set_value(slot, sv);
68823 		  /* since there are no setters, the inner step is also mutable if there is one
68824 		   *    func=opt_cell_any_nr, sc->opts[0]->v[0].fp(sc->opts[0]) fp=opt_do_1 -> mutable version
68825 		   *    see opt_do_1
68826 		   */
68827 		  if (func == opt_int_any_nr)
68828 		    {
68829 		      o = sc->opts[0];
68830 		      fi = o->v[0].fi;
68831 		      for (i = 0; i < len; i++)
68832 			{
68833 			  integer(sv) = vals[i];
68834 			  fi(o);
68835 			}}
68836 		  else
68837 		    for (i = 0; i < len; i++)
68838 		      {
68839 			integer(sv) = vals[i];
68840 			func(sc, expr);
68841 		      }
68842 		  return(sc->unspecified);
68843 		}
68844 
68845 	      for (i = 0; i < len; i++)
68846 		{
68847 		  slot_set_value(slot, make_integer(sc, vals[i]));
68848 		  func(sc, expr);
68849 		}
68850 	      return(sc->unspecified);
68851 	    }
68852 
68853 	  sc->z = seq;
68854 	  if (!is_iterator(sc->z))
68855 	    sc->z = s7_make_iterator(sc, sc->z);
68856 	  seq = sc->z;
68857 	  push_stack_no_let(sc, OP_GC_PROTECT, seq, f);
68858 	  sc->z = sc->nil;
68859 	  if (func == opt_cell_any_nr)
68860 	    {
68861 	      s7_pointer (*fp)(opt_info *o);
68862 	      o = sc->opts[0];
68863 	      fp = o->v[0].fp;
68864 	      while (true)
68865 		{
68866 		  slot_set_value(slot, s7_iterate(sc, seq));
68867 		  if (iterator_is_at_end(seq))
68868 		    {
68869 		      unstack(sc);
68870 		      return(sc->unspecified);
68871 		    }
68872 		  fp(o);
68873 		}}
68874 	  if (func == opt_int_any_nr)
68875 	    {
68876 	      o = sc->opts[0];
68877 	      fi = o->v[0].fi;
68878 	      while (true)
68879 		{
68880 		  slot_set_value(slot, s7_iterate(sc, seq));
68881 		  if (iterator_is_at_end(seq))
68882 		    {
68883 		      unstack(sc);
68884 		      return(sc->unspecified);
68885 		    }
68886 		  fi(o);
68887 		}}
68888 	  while (true)
68889 	    {
68890 	      slot_set_value(slot, s7_iterate(sc, seq));
68891 	      if (iterator_is_at_end(seq))
68892 		{
68893 		  unstack(sc);	  /* free_cell(sc, seq); */ /* 16-Jan-19 */
68894 		  return(sc->unspecified);
68895 		}
68896 	      func(sc, expr);
68897 	    }}
68898       set_no_cell_opt(body);
68899       sc->curlet = old_e;
68900     }
68901 
68902   if ((is_null(cdr(body))) &&
68903       (is_pair(seq)))
68904     {
68905       s7_pointer c;
68906       c = make_counter(sc, seq);
68907       counter_set_result(c, seq);
68908       push_stack(sc, OP_FOR_EACH_2, c, f);
68909       return(sc->unspecified);
68910     }
68911 
68912   sc->z = seq;
68913   if (!is_iterator(sc->z))
68914     sc->z = s7_make_iterator(sc, sc->z);
68915   push_stack(sc, OP_FOR_EACH_1, make_counter(sc, sc->z), f);
68916   sc->z = sc->nil;
68917   return(sc->unspecified);
68918 }
68919 
68920 static inline bool for_each_arg_is_null(s7_scheme *sc, s7_pointer args)
68921 {
68922   s7_pointer p;
68923   bool got_nil = false;
68924   for (p = args; is_pair(p); p = cdr(p))
68925     {
68926       s7_pointer obj;
68927       obj = car(p);
68928       if (!is_mappable(obj))
68929 	{
68930 	  if (is_null(obj))
68931 	    got_nil = true;
68932 	  else return(simple_wrong_type_argument_with_type(sc, sc->for_each_symbol, obj, a_sequence_string));
68933 	}}
68934   return(got_nil);
68935 }
68936 
68937 static s7_pointer g_for_each(s7_scheme *sc, s7_pointer args)
68938 {
68939   #define H_for_each "(for-each proc object . objects) applies proc to each element of the objects traversed in parallel. \
68940 Each object can be a list, string, vector, hash-table, or any other sequence."
68941   #define Q_for_each s7_make_circular_signature(sc, 2, 3, sc->is_unspecified_symbol, sc->is_procedure_symbol, sc->is_sequence_symbol)
68942 
68943   s7_pointer f;
68944   s7_int len;
68945   bool arity_ok = false;
68946 
68947   /* try the normal case first */
68948   f = car(args);                                /* the function */
68949   len = proper_list_length(cdr(args));
68950 
68951   if (is_closure(f))                            /* not lambda* that might get confused about arg names */
68952     {
68953       if ((len == 1) &&
68954 	  (is_pair(closure_args(f))) &&
68955 	  (is_null(cdr(closure_args(f)))))
68956 	arity_ok = true;
68957     }
68958   else
68959     if (!is_applicable(f))
68960       return(method_or_bust_with_type(sc, f, sc->for_each_symbol, args, something_applicable_string, 1));
68961 
68962   if ((!arity_ok) &&
68963       (!s7_is_aritable(sc, f, len)))
68964     return(s7_error(sc, sc->wrong_number_of_args_symbol,
68965 		    set_elist_4(sc, wrap_string(sc, "for-each ~A: ~A argument~P?", 27), f, make_integer(sc, len), make_integer(sc, len))));
68966 
68967   /* if function is safe c func, do the for-each locally */
68968   if ((is_safe_procedure(f)) &&
68969       (is_c_function(f)))
68970     {
68971       s7_function func;
68972       s7_pointer iters;
68973 
68974       if (for_each_arg_is_null(sc, cdr(args))) return(sc->unspecified);
68975 
68976       func = c_function_call(f);    /* presumably this is either display/write, or method call? */
68977       sc->z = make_iterators(sc, args);
68978       sc->z = cons(sc, sc->z, make_list(sc, len, sc->nil));
68979       push_stack_no_let(sc, OP_GC_PROTECT, sc->args, sc->z); /* temporary GC protection */
68980       if (len == 1)
68981 	{
68982 	  s7_pointer x, y;
68983 	  x = caar(sc->z);
68984 	  y = cdr(sc->z);
68985 	  sc->z = sc->nil;
68986 	  while (true)
68987 	    {
68988 	      set_car(y, s7_iterate(sc, x));
68989 	      if (iterator_is_at_end(x))
68990 		{
68991 		  /* not pop_stack here since that can clobber sc->code et al, and if this for-each call is
68992 		   *   being treated as safe, fn_proc(for-each) assumes everywhere that sc->code is left alone.
68993 		   */
68994 		  unstack(sc);		  /* free_cell(sc, x); */ /* 16-Jan-19 */
68995 		  return(sc->unspecified);
68996 		}
68997 	      func(sc, y);
68998 	    }}
68999       iters = sc->z;
69000       sc->z = sc->nil;
69001       while (true)
69002 	{
69003 	  s7_pointer x, y;
69004 	  for (x = car(iters), y = cdr(iters); is_pair(x); x = cdr(x), y = cdr(y))
69005 	    {
69006 	      set_car(y, s7_iterate(sc, car(x)));
69007 	      if (iterator_is_at_end(car(x)))
69008 		{
69009 		  unstack(sc);
69010 		  return(sc->unspecified);
69011 		}}
69012 	  func(sc, cdr(iters));
69013 	}}
69014 
69015   /* if closure call is straightforward, use OP_FOR_EACH_1 */
69016   if (len == 1)
69017     {
69018       if (is_null(cadr(args))) return(sc->unspecified);
69019       if ((is_closure(f)) &&                        /* not lambda* that might get confused about arg names */
69020 	  (closure_arity_to_int(sc, f) == 1) &&     /* not a rest arg: not is_pair: (lambda (x . args) arg) */
69021 	  (!is_constant_symbol(sc, car(closure_args(f)))))
69022 	return(g_for_each_closure(sc, f, cadr(args)));
69023     }
69024   if (for_each_arg_is_null(sc, cdr(args))) return(sc->unspecified);
69025 
69026   push_stack(sc, OP_FOR_EACH, cons(sc, make_iterators(sc, args), make_list(sc, len, sc->nil)), f);
69027   sc->z = sc->nil;
69028   return(sc->unspecified);
69029 }
69030 
69031 static bool op_for_each(s7_scheme *sc)
69032 {
69033   s7_pointer x, y, iterators, saved_args;
69034   iterators = car(sc->args);
69035   saved_args = cdr(sc->args);
69036   for (x = saved_args, y = iterators; is_pair(x); x = cdr(x), y = cdr(y))
69037     {
69038       set_car(x, s7_iterate(sc, car(y)));
69039       if (iterator_is_at_end(car(y)))
69040 	{
69041 	  sc->value = sc->unspecified;
69042 	  free_cell(sc, sc->args);
69043 	  return(true);
69044 	}}
69045   push_stack_direct(sc, OP_FOR_EACH);
69046   sc->args = saved_args;
69047   if (needs_copied_args(sc->code))
69048     sc->args = copy_proper_list(sc, sc->args);
69049   return(false);
69050 }
69051 
69052 /* for-each et al remake the local let, but that's only needed if the local let is exported,
69053  *   and that can only happen through make-closure in various guises and curlet.
69054  *   owlet captures, but it would require a deliberate error to use it in this context.
69055  *   c_objects call object_set_let but that requires a prior curlet or sublet.  So we have
69056  *   sc->capture_let_counter that is incremented every time an environment is captured, then
69057  *   here we save that ctr, call body, on rerun check ctr, if it has not changed we are safe and
69058  *   can reuse let.  But that reuse assumes no new slots were added (by define etc), because
69059  *   update_let* only update the symbol_id's they expect, and that can happen even in op_for_each_2.
69060  */
69061 
69062 static Inline bool op_for_each_1(s7_scheme *sc)
69063 {
69064   s7_pointer counter, p, arg, code;
69065   counter = sc->args;
69066   p = counter_list(counter);
69067   arg = s7_iterate(sc, p);
69068   if (iterator_is_at_end(p))
69069     {
69070       sc->value = sc->unspecified;
69071       free_cell(sc, counter);
69072       return(true);
69073     }
69074   code = T_Clo(sc->code);
69075   if (counter_capture(counter) != sc->capture_let_counter)
69076     {
69077       sc->curlet = make_let_with_slot(sc, closure_let(code), car(closure_args(code)), arg);
69078       counter_set_let(counter, sc->curlet);
69079       counter_set_slots(counter, let_slots(sc->curlet));
69080       counter_set_capture(counter, sc->capture_let_counter);
69081     }
69082   else
69083     {
69084       let_set_slots(counter_let(counter), counter_slots(counter)); /* this is needed (unless safe_closure but that costs more to check than this set) */
69085       sc->curlet = update_let_with_slot(sc, counter_let(counter), arg);
69086     }
69087   push_stack(sc, OP_FOR_EACH_1, counter, code);
69088   sc->code = T_Pair(closure_body(code));
69089   return(false);
69090 }
69091 
69092 static Inline bool op_for_each_2(s7_scheme *sc)
69093 {
69094   s7_pointer c, lst;
69095   c = sc->args; /* the counter */
69096   lst = counter_list(c);
69097   if (!is_pair(lst))  /* '(1 2 . 3) as arg? -- counter_list can be anything here */
69098     {
69099       sc->value = sc->unspecified;
69100       free_cell(sc, c);  /* not sc->args = sc->nil; */
69101       return(true);
69102     }
69103   counter_set_list(c, cdr(lst));
69104   if (sc->cur_op == OP_FOR_EACH_3)
69105     {
69106       counter_set_result(c, cdr(counter_result(c)));
69107       if (counter_result(c) == counter_list(c))
69108 	{
69109 	  sc->value = sc->unspecified;
69110 	  free_cell(sc, c);  /* not sc->args = sc->nil; */
69111 	  return(true);
69112 	}
69113       push_stack_direct(sc, OP_FOR_EACH_2);
69114     }
69115   else push_stack_direct(sc, OP_FOR_EACH_3);
69116   if (counter_capture(c) != sc->capture_let_counter)
69117     {
69118       sc->curlet = make_let_with_slot(sc, closure_let(sc->code), car(closure_args(sc->code)), car(lst));
69119       counter_set_let(c, sc->curlet);
69120       counter_set_slots(c, let_slots(sc->curlet));
69121       counter_set_capture(c, sc->capture_let_counter);
69122     }
69123   else
69124     {
69125       let_set_slots(counter_let(c), counter_slots(c));
69126       sc->curlet = update_let_with_slot(sc, counter_let(c), car(lst));
69127     }
69128   sc->code = car(closure_body(sc->code));
69129   return(false);
69130 }
69131 
69132 
69133 /* ---------------------------------------- map ---------------------------------------- */
69134 
69135 static s7_pointer slookup(s7_scheme *sc, s7_pointer s) {return(slot_value(s));}
69136 
69137 static s7_pointer g_map_closure(s7_scheme *sc, s7_pointer f, s7_pointer seq)
69138 {
69139   s7_pointer body;
69140 
69141   body = closure_body(f);
69142   if ((is_pair(seq)) &&
69143       (!no_cell_opt(body)) &&
69144       (is_optimized(car(body)))) /* for index.scm? */
69145     {
69146       s7_function func;
69147       s7_pointer slot, old_e, expr;
69148 
69149       old_e = sc->curlet;
69150       sc->curlet = make_let_slowly(sc, closure_let(f));
69151       slot = make_slot_2(sc, sc->curlet, car(closure_args(f)), sc->F);
69152 
69153       if (is_null(cdr(body)))
69154 	{
69155 	  expr = car(body);
69156 	  if (is_symbol(expr))
69157 	    {
69158 	      expr = lookup_slot_from(expr, sc->curlet);
69159 	      func = slookup;
69160 	    }
69161 	  else func = s7_optimize(sc, body);
69162 	}
69163       else
69164 	{
69165 	  expr = cons(sc, sc->begin_symbol, body);
69166 	  sc->w = expr; /* GC protection? */
69167 	  func = s7_cell_optimize(sc, list_1(sc, expr), false);
69168 	}
69169       if (func)
69170 	{
69171 	  s7_pointer fast, slow;
69172 	  sc->v = sc->nil;
69173 	  push_stack_no_let(sc, OP_GC_PROTECT, f, seq);
69174 	  for (fast = seq, slow = seq; is_pair(fast); fast = cdr(fast), slow = cdr(slow))
69175 	    {
69176 	      s7_pointer z;
69177 	      slot_set_value(slot, car(fast));
69178 	      z = func(sc, expr);
69179 	      if (z != sc->no_value)
69180 		sc->v = cons(sc, z, sc->v);
69181 	      if (is_pair(cdr(fast)))
69182 		{
69183 		  fast = cdr(fast);
69184 		  if (fast == slow)
69185 		    break;
69186 		  slot_set_value(slot, car(fast));
69187 		  z = func(sc, expr);
69188 		  if (z != sc->no_value)
69189 		    sc->v = cons(sc, z, sc->v);
69190 		}}
69191 	  unstack(sc);
69192 	  return(proper_list_reverse_in_place(sc, sc->v));
69193 	}
69194       set_no_cell_opt(body);
69195       sc->curlet = old_e;
69196     }
69197 
69198   if ((is_null(cdr(body))) &&
69199       (is_pair(seq)))
69200     {
69201       closure_set_map_list(f, seq);
69202       push_stack(sc, OP_MAP_2, make_counter(sc, seq), f);
69203       return(sc->unspecified);
69204     }
69205 
69206   sc->z = (!is_iterator(seq)) ? s7_make_iterator(sc, seq) : seq;
69207   push_stack(sc, OP_MAP_1, make_counter(sc, sc->z), f);
69208   sc->z = sc->nil;
69209   return(sc->nil);
69210 }
69211 
69212 static s7_pointer g_map(s7_scheme *sc, s7_pointer args)
69213 {
69214   #define H_map "(map proc object . objects) applies proc to a list made up of the next element of each of its arguments, returning \
69215 a list of the results.  Its arguments can be lists, vectors, strings, hash-tables, or any applicable objects."
69216   #define Q_map s7_make_circular_signature(sc, 2, 3, sc->is_proper_list_symbol, sc->is_procedure_symbol, sc->is_sequence_symbol)
69217 
69218   s7_pointer p, f;
69219   s7_int len;
69220   bool got_nil = false;
69221 
69222   f = car(args);                                /* the function */
69223   for (len = 0, p = cdr(args); is_not_null(p); p = cdr(p), len++)
69224     if (!is_mappable(car(p)))
69225       {
69226 	if (is_null(car(p)))
69227 	  got_nil = true;
69228 	else return(simple_wrong_type_argument_with_type(sc, sc->map_symbol, car(p), a_sequence_string));
69229       }
69230 
69231   switch (type(f))
69232     {
69233     case T_C_FUNCTION:
69234     case T_C_RST_ARGS_FUNCTION:
69235       if ((c_function_required_args(f) > len) ||
69236 	  (c_function_all_args(f) < len))
69237 	return(s7_error(sc, sc->wrong_number_of_args_symbol,
69238 			set_elist_4(sc, wrap_string(sc, "map ~A: ~A argument~P?", 22), f, make_integer(sc, len), make_integer(sc, len))));
69239 
69240     case T_C_OPT_ARGS_FUNCTION:
69241     case T_C_ANY_ARGS_FUNCTION:
69242       /* if function is safe c func, do the map locally */
69243       if (got_nil) return(sc->nil);
69244       if (is_safe_procedure(f))
69245 	{
69246 	  s7_function func;
69247 	  func = c_function_call(f);
69248 	  if ((is_pair(cadr(args))) &&
69249 	      (len == 1))
69250 	    {
69251 	      s7_pointer f_args, val, fast, slow;
69252 	      f_args = list_1(sc, sc->F);
69253 	      val = list_1(sc, sc->nil);
69254 	      push_stack_no_let(sc, OP_GC_PROTECT, f_args, val);
69255 	      for (fast = cadr(args), slow = cadr(args); is_pair(fast); fast = cdr(fast), slow = cdr(slow))
69256 		{
69257 		  s7_pointer z;
69258 		  set_car(f_args, car(fast));
69259 		  z = func(sc, f_args);
69260 		  if (z != sc->no_value)
69261 		    set_car(val, cons(sc, z, car(val)));
69262 		  if (is_pair(cdr(fast)))
69263 		    {
69264 		      fast = cdr(fast);
69265 		      if (fast == slow)
69266 			break;
69267 		      set_car(f_args, car(fast));
69268 		      z = func(sc, f_args);
69269 		      if (z != sc->no_value)
69270 			set_car(val, cons(sc, z, car(val)));
69271 		    }}
69272 	      unstack(sc);
69273 	      return(proper_list_reverse_in_place(sc, car(val)));
69274 	    }
69275 	  else
69276 	    {
69277 	      s7_pointer val, val1, old_args, iter_list;
69278 	      sc->z = make_iterators(sc, args);
69279 	      val1 = cons(sc, sc->z, make_list(sc, len, sc->nil));
69280 	      iter_list = sc->z;
69281 	      old_args = sc->args;
69282 	      func = c_function_call(f);
69283 	      push_stack_no_let(sc, OP_GC_PROTECT, val1, val = cons(sc, sc->nil, sc->code)); /* temporary GC protection: need to protect val1, iter_list, val */
69284 	      sc->z = sc->nil;
69285 	      while (true)
69286 		{
69287 		  s7_pointer x, y, z;
69288 		  for (x = iter_list, y = cdr(val1); is_pair(x); x = cdr(x), y = cdr(y))
69289 		    {
69290 		      set_car(y, s7_iterate(sc, car(x)));
69291 		      if (iterator_is_at_end(car(x)))
69292 			{
69293 			  unstack(sc);
69294 			  /* free_cell(sc, car(x)); */ /* 16-Jan-19 iterator in circular list -- see s7test */
69295 			  sc->args = T_Pos(old_args);
69296 			  return(proper_list_reverse_in_place(sc, car(val)));
69297 			}}
69298 		  z = func(sc, cdr(val1)); /* can this contain multiple-values? */
69299 		  if (z != sc->no_value)
69300 		    set_car(val, cons(sc, z, car(val)));
69301 		}}}
69302       else /* not safe procedure */
69303 	/* to mimic map values handling elsewhere:
69304 	 *   ((lambda args (format *stderr* "~A~%" (map values args))) (values)):   ()
69305 	 *   ((lambda args (format *stderr* "~A~%" (map values args))) (values #<unspecified>)): #<unspecified> etc
69306 	 */
69307 	if ((f == global_value(sc->values_symbol)) &&
69308 	    (len == 1) &&
69309 	    (!has_methods(cadr(args)))) /* iterator should be ok here -- object_to_list can handle it */
69310 	  {
69311 	    p = object_to_list(sc, cadr(args));
69312 	    if (p != cadr(args))
69313 	      return(p);
69314 	  }
69315       break;
69316 
69317       case T_CLOSURE:
69318 	{
69319 	  int32_t fargs;
69320 	  fargs = closure_arity_to_int(sc, f);
69321 	  /* if closure call is straightforward, use OP_MAP_1 */
69322 	  if ((len == 1) &&
69323 	      (fargs == 1) &&
69324 	      (!is_constant_symbol(sc, car(closure_args(f)))))
69325 	    {
69326 	      /* g_map_closure here if not s7_tree_memq 'map takes more time than it saves */
69327 	      if (got_nil) return(sc->nil);
69328 	      /* don't go to OP_MAP_2 here! It assumes no recursion */
69329 	      sc->z = (!is_iterator(cadr(args))) ? s7_make_iterator(sc, cadr(args)) : cadr(args);
69330 	      push_stack(sc, OP_MAP_1, make_counter(sc, sc->z), f);
69331 	      sc->z = sc->nil;
69332 	      symbol_increment_ctr(car(closure_args(f)));
69333 
69334 	      return(sc->nil);
69335 	    }
69336 	  if ((fargs > len) ||
69337 	       ((fargs < len) &&
69338 		((fargs >= 0) ||
69339 		 (abs(fargs) > len))))
69340 	    return(s7_error(sc, sc->wrong_number_of_args_symbol,
69341 			    set_elist_4(sc, wrap_string(sc, "map ~A: ~A argument~P?", 22), f, make_integer(sc, len), make_integer(sc, len))));
69342 	  if (got_nil) return(sc->nil);
69343 	}
69344 	break;
69345 
69346     default:
69347       if (!is_applicable(f))
69348 	return(method_or_bust_with_type(sc, f, sc->map_symbol, args, something_applicable_string, 1));
69349 
69350       if ((!is_pair(f)) &&
69351 	  (!s7_is_aritable(sc, f, len)))
69352 	return(s7_error(sc, sc->wrong_number_of_args_symbol,
69353 			set_elist_4(sc, wrap_string(sc, "map ~A: ~A argument~P?", 22), f, make_integer(sc, len), make_integer(sc, len))));
69354 
69355       if (got_nil) return(sc->nil);
69356       break;
69357     }
69358 
69359   sc->z = make_iterators(sc, args);
69360   push_stack(sc, OP_MAP, make_counter(sc, sc->z), f);
69361   sc->z = sc->nil;
69362   return(sc->nil);
69363 }
69364 
69365 static bool op_map(s7_scheme *sc)
69366 {
69367   s7_pointer y, iterators;
69368   iterators = counter_list(sc->args);
69369   sc->x = sc->nil;                     /* can't use preset args list here (as in for-each): (map list '(a b c)) */
69370   for (y = iterators; is_pair(y); y = cdr(y))
69371     {
69372       s7_pointer x;
69373       x = s7_iterate(sc, car(y));
69374       if (iterator_is_at_end(car(y)))
69375 	{
69376 	  sc->value = proper_list_reverse_in_place(sc, counter_result(sc->args));
69377 	  free_cell(sc, sc->args);  /* not sc->args = sc->nil; */
69378 	  return(true);
69379 	}
69380       sc->x = cons(sc, x, sc->x);
69381     }
69382   sc->x = proper_list_reverse_in_place(sc, sc->x);
69383   push_stack_direct(sc, OP_MAP_GATHER);
69384   sc->args = sc->x;
69385   sc->x = sc->nil;
69386 
69387   if (needs_copied_args(sc->code))
69388     sc->args = copy_proper_list(sc, sc->args);
69389   return(false);
69390 }
69391 
69392 static bool op_map_1(s7_scheme *sc)
69393 {
69394   s7_pointer x, args, p, code;
69395   code = sc->code;
69396   args = sc->args;
69397   p = counter_list(args);
69398   x = s7_iterate(sc, p);
69399 
69400   if (iterator_is_at_end(p))
69401     {
69402       sc->value = proper_list_reverse_in_place(sc, counter_result(args));
69403       free_cell(sc, sc->args);  /* not sc->args = sc->nil; */
69404       return(true);
69405     }
69406   push_stack_direct(sc, OP_MAP_GATHER_1);
69407   if (counter_capture(args) != sc->capture_let_counter)
69408     {
69409       sc->curlet = make_let_with_slot(sc, closure_let(code), car(closure_args(code)), x);
69410       counter_set_let(args, sc->curlet);
69411       counter_set_slots(args, let_slots(sc->curlet));
69412       counter_set_capture(args, sc->capture_let_counter);
69413     }
69414   else
69415     {
69416       /* the counter_slots field saves the original local let slot(s) representing the function
69417        *   argument.  If the function has internal defines, they get added to the front of the
69418        *   slots list, but update_let_with_slot (maybe stupidly) assumes only the one original
69419        *   slot exists when it updates its symbol_id from the (possibly changed) let_id.  So,
69420        *   a subsequent reference to the parameter name causes "unbound variable", or a segfault
69421        *   if the check has been optimized away.  I think each function call should start with
69422        *   the original let slots, so counter_slots saves that pointer, and resets it here.
69423        */
69424       let_set_slots(counter_let(args), counter_slots(args));
69425       sc->curlet = update_let_with_slot(sc, counter_let(args), x);
69426     }
69427   sc->code = T_Pair(closure_body(code));
69428   return(false);
69429 }
69430 
69431 static bool op_map_2(s7_scheme *sc)
69432 {
69433   s7_pointer x, c, p, code;
69434   code = sc->code;
69435   c = sc->args;
69436   p = counter_list(c);
69437   if (!is_pair(p))
69438     {
69439       sc->value = proper_list_reverse_in_place(sc, counter_result(c));
69440       free_cell(sc, sc->args);  /* not sc->args = sc->nil; */
69441       return(true);
69442     }
69443   x = car(p);
69444   counter_set_list(c, cdr(p));
69445 
69446   if (sc->cur_op == OP_MAP_GATHER_3)
69447     {
69448       closure_set_map_list(code, cdr(closure_map_list(code)));
69449       /* this depends on code (the function) being non-recursive, else closure_setter gets stepped on */
69450       if (closure_map_list(code) == counter_list(c))
69451 	{
69452 	  sc->value = proper_list_reverse_in_place(sc, counter_result(c));
69453 	  free_cell(sc, c);  /* not sc->args = sc->nil; */
69454 	  return(true);
69455 	}
69456       push_stack_direct(sc, OP_MAP_GATHER_2);
69457     }
69458   else push_stack_direct(sc, OP_MAP_GATHER_3);
69459 
69460   if (counter_capture(c) != sc->capture_let_counter)
69461     {
69462       sc->curlet = make_let_with_slot(sc, closure_let(code), car(closure_args(code)), x);
69463       counter_set_let(c, sc->curlet);
69464       counter_set_slots(c, let_slots(sc->curlet));
69465       counter_set_capture(c, sc->capture_let_counter);
69466     }
69467   else
69468     {
69469       let_set_slots(counter_let(c), counter_slots(c)); /* needed -- see comment under for-each above */
69470       sc->curlet = update_let_with_slot(sc, counter_let(c), x);
69471     }
69472   sc->code = car(closure_body(code));
69473   return(false);
69474 }
69475 
69476 
69477 /* -------------------------------- multiple-values -------------------------------- */
69478 #if S7_DEBUGGING
69479 #define T_Mut(p) T_Mut_1(p, __func__, __LINE__)
69480 static s7_pointer T_Mut_1(s7_pointer p, const char *func, int line)
69481 {
69482   if ((is_pair(p)) && ((is_immutable(p)) || (not_in_heap(p)))) /* might be nil */
69483     fprintf(stderr, "%s[%d]: immutable list: %p\n", func, line, p);
69484   return(p);
69485 }
69486 #else
69487 #define T_Mut(p) p
69488 #endif
69489 
69490 static s7_pointer splice_in_values(s7_scheme *sc, s7_pointer args)
69491 {
69492   int64_t top;
69493   s7_pointer x;
69494   top = current_stack_top(sc) - 1; /* stack_end - stack_start if negative, we're in big trouble */
69495 #if SHOW_EVAL_OPS
69496   safe_print(fprintf(stderr, "%s[%d]: splice %s %s\n", __func__, __LINE__, op_names[stack_op(sc->stack, top)], display_80(args)));
69497 #endif
69498 
69499   switch (stack_op(sc->stack, top))
69500     {
69501       /* the normal case -- splice values into caller's args */
69502     case OP_EVAL_ARGS1:
69503     case OP_EVAL_ARGS2:
69504     case OP_EVAL_ARGS3:
69505     case OP_EVAL_ARGS4:
69506       /* code = args yet to eval in order, args = evalled args reversed
69507        *
69508        * it's not safe to simply reverse args and tack the current stacked args onto its (new) end,
69509        *   setting stacked args to cdr of reversed-args and returning car because the list (args)
69510        *   can be some variable's value in a macro expansion via ,@ and reversing it in place
69511        *   (all this to avoid consing), clobbers the variable's value.
69512        */
69513       for (x = args; is_not_null(cdr(x)); x = cdr(x))
69514 	stack_args(sc->stack, top) = cons(sc, car(x), T_Mut(stack_args(sc->stack, top)));
69515       return(car(x));
69516 
69517       /* in the next set, the main evaluator branches blithely assume no multiple-values,
69518        *   and if it happens anyway, we go to a different branch here
69519        */
69520     case OP_ANY_CLOSURE_FP_2:
69521       stack_element(sc->stack, top) = (s7_pointer)OP_ANY_CLOSURE_FP_MV_1;
69522       goto FP_MV;
69523 
69524     case OP_ANY_C_FP_2:
69525       stack_element(sc->stack, top) = (s7_pointer)OP_ANY_C_FP_MV_1;
69526       goto FP_MV;
69527 
69528     case OP_ANY_C_FP_1:
69529     case OP_ANY_CLOSURE_FP_1:
69530       stack_element(sc->stack, top) = (s7_pointer)(stack_op(sc->stack, top) + 1); /* replace with mv version */
69531 
69532     case OP_ANY_C_FP_MV_1:
69533     case OP_ANY_CLOSURE_FP_MV_1:
69534     FP_MV:
69535       if ((is_immutable(args)) || /* (let () (define (func) (with-output-to-string (lambda () (apply-values (write '(1 2)))))) (func) (func)) */
69536 	  (needs_copied_args(args)))
69537 	{
69538 	  clear_needs_copied_args(args);
69539 	  args = copy_proper_list(sc, args);
69540 	}
69541       set_multiple_value(args);
69542       return(args);
69543 
69544     case OP_SAFE_C_SSP_1:
69545       stack_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_SSP_MV_1;
69546       return(args);
69547 
69548     case OP_SAFE_C_SP_1:  case OP_SAFE_CONS_SP_1: case OP_SAFE_VECTOR_SP_1:
69549     case OP_SAFE_ADD_SP_1: case OP_SAFE_SUBTRACT_SP_1: case OP_SAFE_MULTIPLY_SP_1:
69550       stack_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_SP_MV;
69551       return(args);
69552 
69553     case OP_SAFE_C_PS_1:
69554       stack_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_PS_MV;
69555       return(args);
69556 
69557     case OP_SAFE_C_PC_1:
69558       stack_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_PC_MV;
69559       return(args);
69560 
69561     case OP_SAFE_C_PA_1:
69562       stack_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_PA_MV;
69563       return(args);
69564 
69565     case OP_C_P_1:
69566     case OP_SAFE_C_P_1:
69567       stack_element(sc->stack, top) = (s7_pointer)OP_C_P_MV;
69568       return(args);
69569 
69570     case OP_C_AP_1:
69571       stack_element(sc->stack, top) = (s7_pointer)OP_C_AP_MV;
69572       sc->value = args;
69573       return(args);
69574 
69575     case OP_SAFE_CLOSURE_P_1:  case OP_CLOSURE_P_1: case OP_SAFE_CLOSURE_P_A_1:
69576     case OP_SAFE_CLOSURE_AP_1: case OP_CLOSURE_AP_1:
69577     case OP_SAFE_CLOSURE_PP_1: case OP_CLOSURE_PP_1:
69578     case OP_SAFE_CLOSURE_PA_1: case OP_CLOSURE_PA_1:      /* arity is 2, we have 2 args, this has to be an error (see optimize_closure_dotted_args) */
69579     case OP_ANY_CLOSURE_3P_1: case OP_ANY_CLOSURE_3P_2: case OP_ANY_CLOSURE_3P_3:
69580     case OP_ANY_CLOSURE_4P_1: case OP_ANY_CLOSURE_4P_2: case OP_ANY_CLOSURE_4P_3: case OP_ANY_CLOSURE_4P_4:
69581       return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, stack_code(sc->stack, top), sc->value)));
69582 
69583     case OP_SAFE_C_PP_1:
69584       stack_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_PP_3_MV;
69585       return(args);
69586 
69587     case OP_SAFE_C_PP_5:
69588       stack_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_PP_6_MV;
69589       return(args);
69590 
69591     case OP_EVAL_ARGS5:
69592       /* code = previous arg saved, args = ante-previous args reversed
69593        *   we'll take value->code->args and reverse in args5
69594        *   if one value, return it, else
69595        *      put code onto args, splice as above until there are 2 left
69596        *      set code to first and value to last
69597        */
69598       if (is_null(args))
69599 	return(sc->unspecified);
69600 
69601       if (is_null(cdr(args)))
69602 	return(car(args));
69603 
69604       stack_args(sc->stack, top) = cons(sc, stack_code(sc->stack, top), T_Mut(stack_args(sc->stack, top)));
69605       for (x = args; is_not_null(cddr(x)); x = cdr(x))
69606 	stack_args(sc->stack, top) = cons(sc, car(x), stack_args(sc->stack, top));
69607       stack_code(sc->stack, top) = car(x);
69608       return(cadr(x));
69609 
69610       /* look for errors here rather than glomming up the set! and let code. */
69611     case OP_SET_SAFE:             /* symbol is sc->code after pop */
69612     case OP_SET1:                 /* (set! var (values 1 2 3)) */
69613       eval_error_with_caller2(sc, "~A: can't set ~A to ~S", 22, sc->set_symbol, stack_code(sc->stack, top), set_ulist_1(sc, sc->values_symbol, args));
69614 
69615     case OP_SET_PAIR_P_1:
69616       eval_error(sc, "too many values to set! ~S", 26, set_ulist_1(sc, sc->values_symbol, args));
69617 
69618     case OP_INCREMENT_SP_1:       /* slot is in stack_args(top), args is the values list */
69619       stack_element(sc->stack, top) = (s7_pointer)OP_INCREMENT_SP_MV;
69620       return(args);
69621 
69622     case OP_LET1:                                             /* (let ((var (values 1 2 3))) ...) */
69623       {
69624 	s7_pointer p, let_code, vars, sym;
69625 	p = stack_args(sc->stack, top);
69626 	for (let_code = p; is_pair(cdr(let_code)); let_code = cdr(let_code));
69627 	for (vars = caar(let_code); is_pair(cdr(p)); p = cdr(p), vars = cdr(vars));
69628 	sym = caar(vars);
69629 	eval_error_with_caller2(sc, "~A: can't bind ~A to ~S", 23, sc->let_symbol, sym, set_ulist_1(sc, sc->values_symbol, args));
69630 	/* stack_args: ((((x (values 1 2))) x)) in (let ((x (values 1 2))) x)
69631 	 *             (1 (((x 1) (y (values 1 2))) x)) in (let ((x 1) (y (values 1 2))) x)
69632 	 */
69633       }
69634 
69635     case OP_LET_ONE_NEW_1:
69636     case OP_LET_ONE_P_NEW_1:
69637       eval_error_with_caller2(sc, "~A: can't bind ~A to ~S", 23, sc->let_symbol,
69638 			      opt2_sym(stack_code(sc->stack, top)), set_ulist_1(sc, sc->values_symbol, args));
69639 
69640     case OP_LET_ONE_OLD_1: /* can these happen? */
69641     case OP_LET_ONE_P_OLD_1:
69642       eval_error_with_caller2(sc, "~A: can't bind ~A to ~S", 23, sc->let_symbol,
69643 			      opt2_sym(cdr(stack_code(sc->stack, top))), set_ulist_1(sc, sc->values_symbol, args));
69644 
69645     case OP_LET_STAR1:             /* here caar(sc->code) is bound to sc->value */
69646       eval_error_with_caller2(sc, "~A: can't bind ~A to ~S", 23, sc->let_star_symbol,
69647 			      caar(stack_code(sc->stack, top)), set_ulist_1(sc, sc->values_symbol, args));
69648 
69649     case OP_LETREC1:               /* here sc->args is the slot about to receive a value */
69650       eval_error_with_caller2(sc, "~A: can't bind ~A to ~S", 23, sc->letrec_symbol,
69651 			      slot_symbol(stack_args(sc->stack, top)), set_ulist_1(sc, sc->values_symbol, args));
69652 
69653     case OP_LETREC_STAR1:
69654       eval_error_with_caller2(sc, "~A: can't bind ~A to ~S", 23, sc->letrec_star_symbol,
69655 			      slot_symbol(stack_args(sc->stack, top)), set_ulist_1(sc, sc->values_symbol, args));
69656 
69657       /* handle 'and' and 'or' specially */
69658     case OP_AND_P1:
69659     case OP_AND_SAFE_P_REST: /* from OP_AND_SAFE_P1 or P2 */
69660       for (x = args; is_not_null(cdr(x)); x = cdr(x))
69661 	if (car(x) == sc->F)
69662 	  return(sc->F);
69663       return(car(x));
69664 
69665     case OP_OR_P1:
69666       for (x = args; is_not_null(cdr(x)); x = cdr(x))
69667 	if (car(x) != sc->F)
69668 	  return(car(x));
69669       return(car(x));
69670 
69671     case OP_IF1:    /* (if (values ...) ...) */
69672     case OP_IF_PP: case OP_IF_PPP: case OP_IF_PR: case OP_IF_PRR:
69673     case OP_WHEN_PP: case OP_UNLESS_PP: case OP_WITH_LET1:
69674     case OP_CASE_G_G: case OP_CASE_G_S: case OP_CASE_E_G: case OP_CASE_E_S: case OP_CASE_S_G: case OP_CASE_S_S: case OP_CASE_I_S:
69675     case OP_COND1: case OP_COND1_SIMPLE:
69676       return(car(args));
69677 
69678     case OP_DYNAMIC_UNWIND:
69679     case OP_DYNAMIC_UNWIND_PROFILE:
69680       {
69681 	s7_pointer old_value;
69682 	old_value = sc->value;
69683 	clear_multiple_value(args);
69684 	sc->value = cons(sc, sc->values_symbol, args);
69685 	dynamic_unwind(sc, stack_code(sc->stack, top), stack_args(sc->stack, top)); /* func (curlet) */
69686 	sc->value = old_value;
69687 	set_multiple_value(args);
69688 	sc->stack_end -= 4;
69689 	return(splice_in_values(sc, args));
69690       }
69691 
69692     case OP_BARRIER:
69693       pop_stack(sc);
69694       return(splice_in_values(sc, args));
69695 
69696     case OP_GC_PROTECT:
69697       sc->stack_end -= 4;
69698       return(splice_in_values(sc, args));
69699 
69700     case OP_BEGIN_HOOK: case OP_BEGIN_NO_HOOK: case OP_BEGIN_1_UNCHECKED: case OP_BEGIN_2_UNCHECKED:
69701       /* here we have a values call with nothing to splice into.  So flush it...
69702        *   otherwise the multiple-values bit gets set in some innocent list and never unset:
69703        *     (let ((x '((1 2)))) (eval `(apply apply values x)) x) -> ((values 1 2))
69704        * other cases: (+ 1 (begin (values 5 6) (values 2 3)) 4) -> 10 -- the (5 6) is dropped
69705        *              (let () (values 1 2 3) 4) but (+ (let () (values 1 2))) -> 3
69706        */
69707       return(args);
69708 
69709     case OP_DEACTIVATE_GOTO:  /* (+ (call-with-exit (lambda (ret) (values 1 2 3)))) */
69710       call_exit_active(stack_args(sc->stack, top)) = false;
69711 
69712     case OP_CATCH: case OP_CATCH_1: case OP_CATCH_2: case OP_CATCH_ALL: /* (+ (catch #t (lambda () (values 3 4)) (lambda args args))) */
69713       pop_stack(sc);
69714       return(splice_in_values(sc, args));
69715 
69716     case OP_EXPANSION:
69717       /* we get here if a reader-macro (define-expansion) returns multiple values.
69718        *    these need to be read in order into the current reader lists (we'll assume OP_READ_LIST is next in the stack.
69719        *    and that it will be expecting the next arg entry in sc->value).
69720        */
69721       top -= 4;
69722       for (x = args; is_not_null(cdr(x)); x = cdr(x))
69723 	stack_args(sc->stack, top) = cons(sc, car(x), T_Mut(stack_args(sc->stack, top)));
69724       pop_stack(sc);               /* need GC protection in loop above, so do this afterwards */
69725       return(car(x));              /* sc->value from OP_READ_LIST point of view */
69726 
69727     case OP_EVAL_DONE:
69728       stack_element(sc->stack, top) = (s7_pointer)OP_SPLICE_VALUES; /* tricky -- continue from eval_done with the current splice */
69729       stack_args(sc->stack, top) = args;
69730       push_stack_op(sc, OP_EVAL_DONE);
69731       return(args);
69732 
69733     default:
69734       /* fprintf(stderr, "%s[%d]: splice on: %s\n", __func__, __LINE__, op_names[stack_op(sc->stack, top)]); */
69735       break;
69736     }
69737 
69738   /* let it meander back up the call chain until someone knows where to splice it
69739    *   the is_immutable check protects against setting the multiple value bit on (say) sc->hash_table_signature
69740    */
69741   if (is_immutable(args))
69742     args = copy_proper_list(sc, args); /* copy needed else (apply values x) where x is a list can leave the mv bit on for x's value */
69743   if (needs_copied_args(args))
69744     {
69745       clear_needs_copied_args(args);
69746       args = copy_proper_list(sc, args);
69747     }
69748   set_multiple_value(args);
69749   return(args);
69750 }
69751 
69752 
69753 /* -------------------------------- values -------------------------------- */
69754 s7_pointer s7_values(s7_scheme *sc, s7_pointer args)
69755 {
69756   #define H_values "(values obj ...) splices its arguments into whatever list holds it (its 'continuation')"
69757   #define Q_values s7_make_circular_signature(sc, 1, 2, sc->values_symbol, sc->T)
69758 
69759   if (is_null(args))         /* ((lambda () (let ((x 1)) (set! x (boolean? (values)))))) */
69760     return(sc->no_value);
69761   if (is_null(cdr(args)))
69762     return(car(args));
69763   set_needs_copied_args(args);
69764   /* copy needed: see s7test (test `(,x ,@y ,x) '(3 a b c 3)) -> (append (list-values x (apply-values y)) x), and apply_values calls s7_values directly */
69765   return(splice_in_values(sc, args));
69766 }
69767 
69768 #define g_values s7_values
69769 
69770 static s7_pointer values_p(s7_scheme *sc) {return(sc->no_value);}
69771 static s7_pointer values_p_p(s7_scheme *sc, s7_pointer p) {return(p);}
69772 
69773 static s7_pointer values_chooser(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops)
69774 {
69775   if (args > 1) return(sc->values_uncopied);
69776   return(f);
69777 }
69778 
69779 
69780 /* -------------------------------- list-values -------------------------------- */
69781 static s7_pointer g_list_values(s7_scheme *sc, s7_pointer args)
69782 {
69783   #define H_list_values "(list-values ...) returns its arguments in a list (internal to quasiquote)"
69784   #define Q_list_values s7_make_circular_signature(sc, 1, 2, sc->is_list_symbol, sc->T)
69785 
69786   /* list-values can't be replaced by list(-n) because (list-values (values)) -> () and anything can be #<no-values> (see s7test) */
69787   /* but (list-values <circular-list>) will complain or get into an infinite recursion in copy_tree, so it should not use copy_tree */
69788 
69789   s7_pointer x;
69790   bool checked = false;
69791 
69792   for (x = args; is_pair(x); x = cdr(x))
69793     {
69794       if (is_pair(car(x)))
69795 	{
69796 	  if (is_checked(car(x)))
69797 	    checked = true;
69798 	}
69799       else
69800 	if (car(x) == sc->no_value) /* unchecked_car|cdr unrolled here is not faster */
69801 	  break;
69802     }
69803   if (is_null(x))
69804     {
69805       if (checked)
69806 	{
69807 	  sc->u = args;
69808 	  check_free_heap_size(sc, 8192);
69809 	  if (sc->safety > NO_SAFETY)
69810 	    {
69811 	      if (tree_is_cyclic(sc, args)) /* we're copying to clear optimizations I think, and a cyclic list here can't be optimized */
69812 		return(args);
69813 	      return(cons_unchecked(sc,     /* since list-values is a safe function, args can be immutable, which should not be passed through the copy */
69814 				    (is_unquoted_pair(car(args))) ? copy_tree_with_type(sc, car(args)) : car(args),
69815 				    (is_unquoted_pair(cdr(args))) ? copy_tree_with_type(sc, cdr(args)) : cdr(args)));
69816 	    }
69817 	  return(copy_tree(sc, args));
69818 	  /* not copy_any_list here -- see comment below */
69819 	}
69820       return((is_immutable(args)) ? copy_proper_list(sc, args) : args);
69821     }
69822   /* if a macro expands into a recursive function with a macro argument as its body (or reasonable facsimile thereof),
69823    *   and the safety (as in safe_closure) of the body changes from safe to unsafe, then (due to the checked bits
69824    *   protecting against cycles in optimize_expression|syntax), the possible safe_closure call will not be fixed,
69825    *   the safe_closure's assumption about the saved local let will be violated, and we'll get "<arg> unbound" (see tgen.scm).
69826    * clear_all_optimizations assumes its argument has no cycles, and automatically calling copy_tree slows
69827    *   everything down intolerably, so if the checked bit is on in a macro expansion, that means we're re-expanding this macro,
69828    *   and therefore have to copy the tree.  But isn't that only the case if the macro expands into closures?
69829    */
69830   {
69831     s7_pointer p, tp, np;
69832     if (is_null(args)) return(sc->nil);
69833     while (car(args) == sc->no_value) {args = cdr(args); if (is_null(args)) return(sc->nil);}
69834     tp = list_1(sc, car(args));
69835     sc->y = tp;
69836     for (p = cdr(args), np = tp; is_pair(p); p = cdr(p))
69837       if (car(p) != sc->no_value)
69838 	{
69839 	  set_cdr(np, list_1(sc, car(p)));
69840 	  np = cdr(np);
69841 	}
69842     sc->y = sc->nil;
69843     return(tp);
69844   }
69845 }
69846 
69847 
69848 /* -------------------------------- apply-values -------------------------------- */
69849 static s7_pointer g_apply_values(s7_scheme *sc, s7_pointer args)
69850 {
69851   #define H_apply_values "(apply-values var) applies values to var.  This is an internal function."
69852   #define Q_apply_values s7_make_signature(sc, 2, sc->T, sc->is_list_symbol)
69853   s7_pointer x;
69854   /* apply-values takes 1 arg: ,@a -> (apply-values a) */
69855   if (is_null(args))
69856     return(sc->no_value);
69857 
69858   x = car(args);
69859   if (is_null(x))
69860     return(sc->no_value);
69861 
69862   if (!s7_is_proper_list(sc, x))
69863     return(apply_list_error(sc, args));
69864 
69865   return(g_values(sc, x));
69866 }
69867 
69868 /* (apply values ...) replaces (unquote_splicing ...)
69869  *   (define-macro (hi a) `(+ 1 ,a) == (list '+ 1 a)
69870  *   (define-macro (hi a) ``(+ 1 ,,a) == (list list '+ 1 (list quote a)))
69871  *   (define-macro (hi a) `(+ 1 ,@a) == (list '+ 1 (apply values a))
69872  *   (define-macro (hi a) ``(+ 1 ,,@a) == (list list '+ 1 (apply values a))
69873  *
69874  * this is not the same as CL's quasiquote; for example:
69875  *   [1]> (let ((a 1) (b 2)) `(,a ,@b)) -> '(1 . 2)
69876  *   in s7 this is an error.
69877  *
69878  * also in CL the target of ,@ can apparently be a circular list
69879  * one surprising twist: write/display return their first argument directly, so (apply-values (write `(+ x 1))) is the same as (apply-values `(+ x 1))
69880  *   If this is in a function body, and the function is called twice, it is self-modifying code and behaves in unexpected ways.
69881  */
69882 
69883 
69884 /* -------------------------------- quasiquote -------------------------------- */
69885 static bool is_simple_code(s7_scheme *sc, s7_pointer form)
69886 {
69887   /* if nested with quasiquotes say 20 levels, this is really slow, but to tag intermediate results burns up 2 type bits */
69888   s7_pointer tmp, slow;
69889   for (tmp = form, slow = form; is_pair(tmp); tmp = cdr(tmp), slow = cdr(slow))
69890     {
69891       if (is_pair(car(tmp)))
69892 	{
69893 	  if (!is_simple_code(sc, car(tmp)))
69894 	    return(false);
69895 	}
69896       else
69897 	if (car(tmp) == sc->unquote_symbol)
69898 	  return(false);
69899       tmp = cdr(tmp);
69900       if (!is_pair(tmp)) return(is_null(tmp));
69901       if (tmp == slow) return(false);
69902       if (is_pair(car(tmp)))
69903 	{
69904 	  if (!is_simple_code(sc, car(tmp)))
69905 	    return(false);
69906 	}
69907       else
69908 	if (car(tmp) == sc->unquote_symbol)
69909 	  return(false);
69910     }
69911   return(is_null(tmp));
69912 }
69913 
69914 /* since the reader expands unquote et al, and the printer does not unexpand them, the standard scheme quine in s7 is:
69915  *   ((lambda (x) (list-values x (list-values 'quote x))) '(lambda (x) (list-values x (list-values 'quote x))))
69916  * but that depends on the "p" in repl...
69917  */
69918 
69919 static s7_pointer g_quasiquote_1(s7_scheme *sc, s7_pointer form, bool check_cycles)
69920 {
69921   #define H_quasiquote "(quasiquote arg) is the same as `arg.  If arg is a list, it can contain \
69922 comma (\"unquote\") and comma-atsign (\"apply values\") to pre-evaluate portions of the list. \
69923 unquoted expressions are evaluated and plugged into the list, apply-values evaluates the expression \
69924 and splices the resultant list into the outer list. `(1 ,(+ 1 1) ,@(list 3 4)) -> (1 2 3 4)."
69925 
69926   if (!is_pair(form))
69927     {
69928       if (is_normal_symbol(form))
69929 	return(list_2(sc, sc->quote_symbol, form));
69930       /* things that evaluate to themselves don't need to be quoted. */
69931       return(form);
69932     }
69933 
69934   if (car(form) == sc->unquote_symbol)
69935     {
69936       if (!is_pair(cdr(form)))             /* (unquote) or (unquote . 1) */
69937 	{
69938 	  if (is_null(cdr(form)))
69939 	    eval_error(sc, "unquote: no argument, ~S", 24, form);
69940 	  else eval_error(sc, "unquote: stray dot, ~S", 22, form);
69941 	}
69942       if (is_not_null(cddr(form)))
69943 	eval_error(sc, "unquote: too many arguments, ~S", 31, form);
69944       return(cadr(form));
69945     }
69946 
69947   /* it's a list, so return the list with each element handled as above.
69948    *    we try to support dotted lists which makes the code much messier.
69949    * if no element of the list is a list or unquote, just return the original quoted
69950    */
69951   if (((check_cycles) && (tree_is_cyclic(sc, form))) ||
69952       (is_simple_code(sc, form)))
69953     {
69954       if ((!is_global(sc->quote_symbol)) && (is_let(sc->curlet))) /* in the reader sc->curlet can be junk */
69955 	{
69956 	  s7_pointer quote_val;
69957 	  quote_val = lookup(sc, sc->quote_symbol);
69958 	  if (((is_global(sc->quasiquote_symbol)) &&
69959 	       (quote_val == global_value(sc->quasiquote_symbol))) ||
69960 	      (quote_val == lookup(sc, sc->quasiquote_symbol)))
69961 	    s7_error(sc, s7_make_symbol(sc, "infinite loop"),
69962 		     set_elist_2(sc, wrap_string(sc, "quote's value is quasiquote, so '~S is trouble", 46), form));
69963 	  /* (member quasiquote (list 1) (lambda 'ho '(1 2))) so '(1 2) -> `(1 2) -> '(1 2)...
69964 	   *   but if we use #_quote above, cycle checks elsewhere get confused (they ignore pairs starting with sc->quote_symbol).
69965 	   * to be more explicit: (assoc val (list (list 1 2)) (lambda (x y)...)) x=val y=1, so
69966 	   *   (assoc 1 (list (list quasiquote +)) (lambda* (a 'b) 'oops))
69967 	   * sets quote to quasiquote, qq returns 'oops etc.
69968 	   */
69969 	}
69970       return(list_2(sc, sc->quote_symbol, form));
69971     }
69972 
69973   {
69974     s7_int len, i;
69975     s7_pointer orig, bq, old_scw;
69976     bool dotted = false;
69977 
69978     len = s7_list_length(sc, form);
69979     if (len < 0)
69980       {
69981 	len = -len;
69982 	dotted = true;
69983       }
69984     old_scw = sc->w;
69985     push_stack_no_let_no_code(sc, OP_GC_PROTECT, sc->w);
69986 
69987     check_free_heap_size(sc, len);
69988     sc->w = sc->nil;
69989     for (i = 0; i <= len; i++)
69990       sc->w = cons_unchecked(sc, sc->nil, sc->w);
69991 
69992     set_car(sc->w, sc->list_values_symbol);
69993     if (!dotted)
69994       {
69995 	for (orig = form, bq = cdr(sc->w), i = 0; i < len; i++, orig = cdr(orig), bq = cdr(bq))
69996 	  {
69997 	    if ((is_pair(cdr(orig))) &&             /* this was is_pair(orig) which seems to be always the case */
69998 		(cadr(orig) == sc->unquote_symbol)) /* `(1 . ,(+ 1 1)) -> '(1 unquote (+ 1 1)) -> '(1 . 2) etc */
69999 	      {
70000 		if (!is_pair(cddr(orig)))
70001 		  {
70002 		    sc->w = old_scw;
70003 		    unstack(sc);
70004 		    eval_error(sc, "unquote: no argument, ~S", 24, form);
70005 		  }
70006 		set_car(bq, g_quasiquote_1(sc, car(orig), false));
70007 		set_cdr(bq, sc->nil);
70008 		sc->w = list_3(sc, sc->append_symbol, sc->w, caddr(orig));
70009 		break;
70010 	      }
70011 	    else set_car(bq, g_quasiquote_1(sc, car(orig), false));
70012 	  }}
70013     else
70014       {
70015 	/* `(1 2 . 3) */
70016 	len--;
70017 	for (orig = form, bq = cdr(sc->w), i = 0; i < len; i++, orig = cdr(orig), bq = cdr(bq))
70018 	  set_car(bq, g_quasiquote_1(sc, car(orig), false));
70019 	set_car(bq, g_quasiquote_1(sc, car(orig), false));
70020 
70021 	sc->w = list_3(sc, sc->append_symbol, sc->w, g_quasiquote_1(sc, cdr(orig), false));
70022 	/* quasiquote might quote a symbol in cdr(orig), so it's not completely pointless */
70023       }
70024     bq = sc->w;
70025     sc->w = old_scw;
70026     unstack(sc);
70027     return(bq);
70028   }
70029 }
70030 
70031 static s7_pointer g_quasiquote(s7_scheme *sc, s7_pointer args)
70032 {
70033   /* this is for explicit quasiquote support, not the backquote stuff in macros
70034    *   but it is problematic.  g_quasiquote_1 above expands (for example) `(+ ,x) into (list (quote +) x),
70035    *   so (multiple-value-bind (quote) quasiquote `(+ ,x)) expands to ((lambda (quote) (list '+ x)) quasiquote)
70036    *   which is an infinite loop.  Guile says syntax error (because it thinks "quote" can't be a parameter name, I think).
70037    */
70038   return(g_quasiquote_1(sc, car(args), true));
70039 }
70040 
70041 
70042 /* -------------------------------- choosers -------------------------------- */
70043 static s7_pointer make_function_with_class(s7_scheme *sc, s7_pointer cls, const char *name, s7_function f,
70044 					   int32_t required_args, int32_t optional_args, bool rest_arg)
70045 {
70046   s7_pointer uf;
70047 #if S7_DEBUGGING
70048   if (!is_safe_procedure(global_value(s7_make_symbol(sc, name)))) fprintf(stderr, "%s unsafe: %s\n", __func__, name);
70049 #endif
70050   uf = s7_make_safe_function(sc, name, f, required_args, optional_args, rest_arg, NULL);
70051   s7_function_set_class(sc, uf, cls);
70052   c_function_signature(uf) = c_function_signature(cls);
70053   return(uf);
70054 }
70055 
70056 static s7_pointer make_unsafe_function_with_class(s7_scheme *sc, s7_pointer cls, const char *name, s7_function f,
70057 					   int32_t required_args, int32_t optional_args, bool rest_arg)
70058 {
70059   s7_pointer uf;
70060   uf = s7_make_function(sc, name, f, required_args, optional_args, rest_arg, NULL); /* was s7_make_safe_function! 14-Dec-20 */
70061   s7_function_set_class(sc, uf, cls);
70062   c_function_signature(uf) = c_function_signature(cls);
70063   return(uf);
70064 }
70065 
70066 static s7_pointer set_function_chooser(s7_scheme *sc, s7_pointer sym, s7_pointer (*chooser)(s7_scheme *sc, s7_pointer f, int32_t args, s7_pointer expr, bool ops))
70067 {
70068   s7_pointer f;
70069   f = global_value(sym);
70070 #if S7_DEBUGGING
70071   if (c_function_chooser(f) != fallback_chooser) fprintf(stderr, "%s[%d]: reset %s chooser\n", __func__, __LINE__, display(sym));
70072 #endif
70073   c_function_chooser(f) = chooser;
70074   return(f);
70075 }
70076 
70077 static void init_choosers(s7_scheme *sc)
70078 {
70079   s7_pointer f;
70080 
70081   /* + */
70082   f = set_function_chooser(sc, sc->add_symbol, add_chooser);
70083   sc->add_class = c_function_class(f);
70084 
70085   sc->add_2 = make_function_with_class(sc, f, "+", g_add_2, 2, 0, false);
70086   sc->add_3 = make_function_with_class(sc, f, "+", g_add_3, 3, 0, false);
70087   sc->add_1x = make_function_with_class(sc, f, "+", g_add_1x, 2, 0, false);
70088   sc->add_x1 = make_function_with_class(sc, f, "+", g_add_x1, 2, 0, false);
70089   sc->add_i_random = make_function_with_class(sc, f, "+", g_add_i_random, 2, 0, false);
70090   sc->add_2_ff = make_function_with_class(sc, f, "+", g_add_2_ff, 2, 0, false);
70091   sc->add_2_ii = make_function_with_class(sc, f, "+", g_add_2_ii, 2, 0, false);
70092   sc->add_2_if = make_function_with_class(sc, f, "+", g_add_2_if, 2, 0, false);
70093   sc->add_2_fi = make_function_with_class(sc, f, "+", g_add_2_fi, 2, 0, false);
70094   sc->add_2_xi = make_function_with_class(sc, f, "+", g_add_2_xi, 2, 0, false);
70095   sc->add_2_ix = make_function_with_class(sc, f, "+", g_add_2_ix, 2, 0, false);
70096   sc->add_2_fx = make_function_with_class(sc, f, "+", g_add_2_fx, 2, 0, false);
70097   sc->add_2_xf = make_function_with_class(sc, f, "+", g_add_2_xf, 2, 0, false);
70098 
70099   /* - */
70100   f = set_function_chooser(sc, sc->subtract_symbol, subtract_chooser);
70101   sc->subtract_class = c_function_class(f);
70102   sc->subtract_1 = make_function_with_class(sc, f, "-", g_subtract_1, 1, 0, false);
70103   sc->subtract_2 = make_function_with_class(sc, f, "-", g_subtract_2, 2, 0, false);
70104   sc->subtract_3 = make_function_with_class(sc, f, "-", g_subtract_3, 3, 0, false);
70105   sc->subtract_x1 = make_function_with_class(sc, f, "-", g_subtract_x1, 2, 0, false);
70106   sc->subtract_2f = make_function_with_class(sc, f, "-", g_subtract_2f, 2, 0, false);
70107   sc->subtract_f2 = make_function_with_class(sc, f, "-", g_subtract_f2, 2, 0, false);
70108 
70109   /* * */
70110   f = set_function_chooser(sc, sc->multiply_symbol, multiply_chooser);
70111   sc->multiply_class = c_function_class(f);
70112   sc->multiply_2 = make_function_with_class(sc, f, "*", g_multiply_2, 2, 0, false);
70113   sc->mul_2_ff = make_function_with_class(sc, f, "*", g_mul_2_ff, 2, 0, false);
70114   sc->mul_2_ii = make_function_with_class(sc, f, "*", g_mul_2_ii, 2, 0, false);
70115   sc->mul_2_if = make_function_with_class(sc, f, "*", g_mul_2_if, 2, 0, false);
70116   sc->mul_2_fi = make_function_with_class(sc, f, "*", g_mul_2_fi, 2, 0, false);
70117   sc->mul_2_xi = make_function_with_class(sc, f, "*", g_mul_2_xi, 2, 0, false);
70118   sc->mul_2_ix = make_function_with_class(sc, f, "*", g_mul_2_ix, 2, 0, false);
70119   sc->mul_2_fx = make_function_with_class(sc, f, "*", g_mul_2_fx, 2, 0, false);
70120   sc->mul_2_xf = make_function_with_class(sc, f, "*", g_mul_2_xf, 2, 0, false);
70121 
70122   /* / */
70123   f = set_function_chooser(sc, sc->divide_symbol, divide_chooser);
70124   sc->invert_1 = make_function_with_class(sc, f, "/", g_invert_1, 1, 0, false);
70125   sc->divide_2 = make_function_with_class(sc, f, "/", g_divide_2, 2, 0, false);
70126   sc->invert_x = make_function_with_class(sc, f, "/", g_invert_x, 2, 0, false);
70127   sc->divide_by_2 = make_function_with_class(sc, f, "/", g_divide_by_2, 2, 0, false);
70128 
70129   /* = */
70130   f = set_function_chooser(sc, sc->num_eq_symbol, num_eq_chooser);
70131   sc->num_eq_class = c_function_class(f);
70132   sc->num_eq_2 = make_function_with_class(sc, f, "=", g_num_eq_2, 2, 0, false);
70133   sc->num_eq_xi = make_function_with_class(sc, f, "=", g_num_eq_xi, 2, 0, false);
70134   sc->num_eq_ix = make_function_with_class(sc, f, "=", g_num_eq_ix, 2, 0, false);
70135 
70136   /* < */
70137   f = set_function_chooser(sc, sc->lt_symbol, less_chooser);
70138   sc->less_xi = make_function_with_class(sc, f, "<", g_less_xi, 2, 0, false);
70139   sc->less_x0 = make_function_with_class(sc, f, "<", g_less_x0, 2, 0, false);
70140   sc->less_xf = make_function_with_class(sc, f, "<", g_less_xf, 2, 0, false);
70141   sc->less_2 = make_function_with_class(sc, f, "<", g_less_2, 2, 0, false);
70142 
70143   /* > */
70144   f = set_function_chooser(sc, sc->gt_symbol, greater_chooser);
70145   sc->greater_xi = make_function_with_class(sc, f, ">", g_greater_xi, 2, 0, false);
70146   sc->greater_xf = make_function_with_class(sc, f, ">", g_greater_xf, 2, 0, false);
70147   sc->greater_2 = make_function_with_class(sc, f, ">", g_greater_2, 2, 0, false);
70148 
70149   /* <= */
70150   f = set_function_chooser(sc, sc->leq_symbol, leq_chooser);
70151   sc->leq_xi = make_function_with_class(sc, f, "<=", g_leq_xi, 2, 0, false);
70152   sc->leq_2 = make_function_with_class(sc, f, "<=", g_leq_2, 2, 0, false);
70153 
70154   /* >= */
70155   f = set_function_chooser(sc, sc->geq_symbol, geq_chooser);
70156   sc->geq_xi = make_function_with_class(sc, f, ">=", g_geq_xi, 2, 0, false);
70157   sc->geq_xf = make_function_with_class(sc, f, ">=", g_geq_xf, 2, 0, false);
70158   sc->geq_2 = make_function_with_class(sc, f, ">=", g_geq_2, 2, 0, false);
70159 
70160   /* random */
70161   f = set_function_chooser(sc, sc->random_symbol, random_chooser);
70162   sc->random_1 = make_function_with_class(sc, f, "random", g_random_1, 1, 0, false);
70163   sc->random_i = make_function_with_class(sc, f, "random", g_random_i, 1, 0, false);
70164   sc->random_f = make_function_with_class(sc, f, "random", g_random_f, 1, 0, false);
70165 
70166   /* defined? */
70167   f = set_function_chooser(sc, sc->is_defined_symbol, is_defined_chooser);
70168   sc->is_defined_in_rootlet = make_function_with_class(sc, f, "defined?", g_is_defined_in_rootlet, 2, 0, false);
70169 
70170   /* char=? */
70171   f = set_function_chooser(sc, sc->char_eq_symbol, char_equal_chooser);
70172   sc->simple_char_eq = make_function_with_class(sc, f, "char=?", g_simple_char_eq, 2, 0, false);
70173   sc->char_equal_2 = make_function_with_class(sc, f, "char=?", g_char_equal_2, 2, 0, false);
70174 
70175   /* char>? */
70176   f = set_function_chooser(sc, sc->char_gt_symbol, char_greater_chooser);
70177   sc->char_greater_2 = make_function_with_class(sc, f, "char>?", g_char_greater_2, 2, 0, false);
70178 
70179   /* char<? */
70180   f = set_function_chooser(sc, sc->char_lt_symbol, char_less_chooser);
70181   sc->char_less_2 = make_function_with_class(sc, f, "char<?", g_char_less_2, 2, 0, false);
70182 
70183   /* read-char */
70184   f = set_function_chooser(sc, sc->read_char_symbol, read_char_chooser);
70185   sc->read_char_1 = make_function_with_class(sc, f, "read-char", g_read_char_1, 1, 0, false);
70186 
70187   /* char-position */
70188   f = set_function_chooser(sc, sc->char_position_symbol, char_position_chooser);
70189   sc->char_position_csi = make_function_with_class(sc, f, "char-position", g_char_position_csi, 2, 1, false);
70190 
70191   /* string=? */
70192   f = set_function_chooser(sc, sc->string_eq_symbol, string_equal_chooser);
70193   sc->string_equal_2 = make_function_with_class(sc, f, "string=?", g_string_equal_2, 2, 0, false);
70194   sc->string_equal_2c = make_function_with_class(sc, f, "string=?", g_string_equal_2c, 2, 0, false);
70195 
70196   /* substring */
70197   sc->substring_uncopied = s7_make_function(sc, "substring", g_substring_uncopied, 2, 1, false, NULL);
70198   s7_function_set_class(sc, sc->substring_uncopied, global_value(sc->substring_symbol));
70199 
70200   /* string>? */
70201   f = set_function_chooser(sc, sc->string_gt_symbol, string_greater_chooser);
70202   sc->string_greater_2 = make_function_with_class(sc, f, "string>?", g_string_greater_2, 2, 0, false);
70203 
70204   /* string<? */
70205   f = set_function_chooser(sc, sc->string_lt_symbol, string_less_chooser);
70206   sc->string_less_2 = make_function_with_class(sc, f, "string<?", g_string_less_2, 2, 0, false);
70207 
70208   /* string */
70209   f = set_function_chooser(sc, sc->string_symbol, string_chooser);
70210   sc->string_c1 = make_function_with_class(sc, f, "string", g_string_c1, 1, 0, false);
70211 
70212   /* string-append */
70213   f = set_function_chooser(sc, sc->string_append_symbol, string_append_chooser);
70214   sc->string_append_2 = make_function_with_class(sc, f, "string-append", g_string_append_2, 2, 0, false);
70215 
70216   /* string-ref et al */
70217   set_function_chooser(sc, sc->string_ref_symbol, string_substring_chooser);
70218   set_function_chooser(sc, sc->string_to_symbol_symbol, string_substring_chooser); /* not string_to_number here */
70219   set_function_chooser(sc, sc->string_to_keyword_symbol, string_substring_chooser);
70220   set_function_chooser(sc, sc->string_downcase_symbol, string_substring_chooser);
70221   set_function_chooser(sc, sc->string_upcase_symbol, string_substring_chooser);
70222   /* if the function assumes a null-terminated string, substring needs to return a copy */
70223 #if (!WITH_PURE_S7)
70224   set_function_chooser(sc, sc->string_length_symbol, string_substring_chooser);
70225   set_function_chooser(sc, sc->string_to_list_symbol, string_substring_chooser);
70226 #endif
70227   set_function_chooser(sc, sc->string_copy_symbol, string_copy_chooser);
70228 
70229   /* symbol->string */
70230   f = global_value(sc->symbol_to_string_symbol);
70231   sc->symbol_to_string_uncopied = s7_make_function(sc, "symbol->string", g_symbol_to_string_uncopied, 1, 0, false, NULL);
70232   s7_function_set_class(sc, sc->symbol_to_string_uncopied, f);
70233 
70234   /* display */
70235   f = set_function_chooser(sc, sc->display_symbol, display_chooser);
70236   sc->display_f = make_function_with_class(sc, f, "display", g_display_f, 2, 0, false);
70237   sc->display_2 = make_function_with_class(sc, f, "display", g_display_2, 2, 0, false);
70238 
70239   /* vector-ref */
70240   f = set_function_chooser(sc, sc->vector_ref_symbol, vector_ref_chooser);
70241   sc->vector_ref_2 = make_function_with_class(sc, f, "vector-ref", g_vector_ref_2, 2, 0, false);
70242   sc->vector_ref_3 = make_function_with_class(sc, f, "vector-ref", g_vector_ref_3, 3, 0, false);
70243 
70244   /* vector-set! */
70245   f = set_function_chooser(sc, sc->vector_set_symbol, vector_set_chooser);
70246   sc->vector_set_3 = make_function_with_class(sc, f, "vector-set!", g_vector_set_3, 3, 0, false);
70247   sc->vector_set_4 = make_function_with_class(sc, f, "vector-set!", g_vector_set_4, 4, 0, false);
70248 
70249   /* float-vector-ref */
70250   f = set_function_chooser(sc, sc->float_vector_ref_symbol, float_vector_ref_chooser);
70251   sc->fv_ref_2 = make_function_with_class(sc, f, "float-vector-ref", g_fv_ref_2, 2, 0, false);
70252   sc->fv_ref_3 = make_function_with_class(sc, f, "float-vector-ref", g_fv_ref_3, 3, 0, false);
70253 
70254   /* float-vector-set */
70255   f = set_function_chooser(sc, sc->float_vector_set_symbol, float_vector_set_chooser);
70256   sc->fv_set_3 = make_function_with_class(sc, f, "float-vector-set!", g_fv_set_3, 3, 0, false);
70257   sc->fv_set_unchecked = make_function_with_class(sc, f, "float-vector-set!", g_fv_set_unchecked, 3, 0, false);
70258 
70259   /* int-vector-ref */
70260   f = set_function_chooser(sc, sc->int_vector_ref_symbol, int_vector_ref_chooser);
70261   sc->iv_ref_2 = make_function_with_class(sc, f, "int-vector-ref", g_iv_ref_2, 2, 0, false);
70262   sc->iv_ref_3 = make_function_with_class(sc, f, "int-vector-ref", g_iv_ref_3, 3, 0, false);
70263 
70264   /* int-vector-set */
70265   f = set_function_chooser(sc, sc->int_vector_set_symbol, int_vector_set_chooser);
70266   sc->iv_set_3 = make_function_with_class(sc, f, "int-vector-set!", g_iv_set_3, 3, 0, false);
70267 
70268   /* byte-vector-ref */
70269   f = set_function_chooser(sc, sc->byte_vector_ref_symbol, byte_vector_ref_chooser);
70270   sc->bv_ref_2 = make_function_with_class(sc, f, "byte-vector-ref", g_bv_ref_2, 2, 0, false);
70271   sc->bv_ref_3 = make_function_with_class(sc, f, "byte-vector-ref", g_bv_ref_3, 3, 0, false);
70272 
70273   /* byte-vector-set */
70274   f = set_function_chooser(sc, sc->byte_vector_set_symbol, byte_vector_set_chooser);
70275   sc->bv_set_3 = make_function_with_class(sc, f, "byte-vector-set!", g_bv_set_3, 3, 0, false);
70276 
70277   /* list-set! */
70278   f = set_function_chooser(sc, sc->list_set_symbol, list_set_chooser);
70279   sc->list_set_i = make_function_with_class(sc, f, "list-set!", g_list_set_i, 3, 0, false);
70280 
70281   /* hash-table-ref */
70282   f = set_function_chooser(sc, sc->hash_table_ref_symbol, hash_table_ref_chooser);
70283   sc->hash_table_ref_2 = make_function_with_class(sc, f, "hash-table-ref", g_hash_table_ref_2, 2, 0, false);
70284 
70285   /* hash-table-set! */
70286   set_function_chooser(sc, sc->hash_table_set_symbol, hash_table_set_chooser);
70287 
70288   /* hash-table */
70289   f = set_function_chooser(sc, sc->hash_table_symbol, hash_table_chooser);
70290   sc->hash_table_2 = make_function_with_class(sc, f, "hash-table", g_hash_table_2, 2, 0, false);
70291 
70292   /* format */
70293   f = set_function_chooser(sc, sc->format_symbol, format_chooser);
70294   sc->format_f = make_function_with_class(sc, f, "format", g_format_f, 1, 0, true);
70295   sc->format_no_column = make_function_with_class(sc, f, "format", g_format_no_column, 1, 0, true);
70296   sc->format_just_control_string = make_function_with_class(sc, f, "format", g_format_just_control_string, 2, 0, false);
70297   sc->format_as_objstr = make_function_with_class(sc, f, "format", g_format_as_objstr, 3, 0, true);
70298 
70299   /* list */
70300   f = set_function_chooser(sc, sc->list_symbol, list_chooser);
70301   sc->list_0 = make_function_with_class(sc, f, "list", g_list_0, 0, 0, false);
70302   sc->list_1 = make_function_with_class(sc, f, "list", g_list_1, 1, 0, false);
70303   sc->list_2 = make_function_with_class(sc, f, "list", g_list_2, 2, 0, false);
70304   sc->list_3 = make_function_with_class(sc, f, "list", g_list_3, 3, 0, false);
70305 
70306   /* append */
70307   f = set_function_chooser(sc, sc->append_symbol, append_chooser);
70308   sc->append_2 = make_function_with_class(sc, f, "append", g_append_2, 2, 0, false);
70309 
70310   /* list-ref */
70311   f = set_function_chooser(sc, sc->list_ref_symbol, list_ref_chooser);
70312   sc->list_ref_0 = make_function_with_class(sc, f, "list", g_list_ref_0, 2, 0, false);
70313   sc->list_ref_1 = make_function_with_class(sc, f, "list", g_list_ref_1, 2, 0, false);
70314   sc->list_ref_2 = make_function_with_class(sc, f, "list", g_list_ref_2, 2, 0, false);
70315 
70316   /* member */
70317   set_function_chooser(sc, sc->member_symbol, member_chooser);
70318 
70319   /* memq */
70320   f = set_function_chooser(sc, sc->memq_symbol, memq_chooser);  /* is pure-s7, use member here */
70321   sc->memq_2 = make_function_with_class(sc, f, "memq", g_memq_2, 2, 0, false);
70322   sc->memq_3 = make_function_with_class(sc, f, "memq", g_memq_3, 2, 0, false);
70323   sc->memq_4 = make_function_with_class(sc, f, "memq", g_memq_4, 2, 0, false);
70324   sc->memq_any = make_function_with_class(sc, f, "memq", g_memq_any, 2, 0, false);
70325 
70326   /* tree-set-memq */
70327   f = set_function_chooser(sc, sc->tree_set_memq_symbol, tree_set_memq_chooser);
70328   sc->tree_set_memq_syms = make_function_with_class(sc, f, "tree-set-memq", g_tree_set_memq_1, 2, 0, false);
70329 
70330   /* eval-string */
70331   set_function_chooser(sc, sc->eval_string_symbol, eval_string_chooser);
70332 
70333   /* dynamic-wind */
70334   f = set_function_chooser(sc, sc->dynamic_wind_symbol, dynamic_wind_chooser);
70335   sc->dynamic_wind_unchecked = make_unsafe_function_with_class(sc, f, "dynamic-wind", g_dynamic_wind_unchecked, 3, 0, false);
70336 
70337   /* inlet */
70338   f = set_function_chooser(sc, sc->inlet_symbol, inlet_chooser);
70339   sc->simple_inlet = make_function_with_class(sc, f, "inlet", g_simple_inlet, 0, 0, true);
70340 
70341   /* let-ref */
70342   f = set_function_chooser(sc, sc->let_ref_symbol, let_ref_chooser);
70343   sc->lint_let_ref = make_function_with_class(sc, f, "let-ref", g_lint_let_ref, 2, 0, false);
70344 
70345   /* let-set */
70346   f = set_function_chooser(sc, sc->let_set_symbol, let_set_chooser);
70347   sc->lint_let_set = make_function_with_class(sc, f, "let-set!", g_lint_let_set, 3, 0, false);
70348 
70349   /* values */
70350   f = set_function_chooser(sc, sc->values_symbol, values_chooser);
70351   sc->values_uncopied = make_unsafe_function_with_class(sc, f, "values", splice_in_values, 0, 0, true);
70352 }
70353 
70354 
70355 /* ---------------- reader funcs for eval ---------------- */
70356 
70357 static void back_up_stack(s7_scheme *sc)
70358 {
70359   opcode_t top_op;
70360   top_op = stack_op(sc->stack, current_stack_top(sc) - 1);
70361   if (top_op == OP_READ_DOT)
70362     {
70363       pop_stack(sc);
70364       top_op = stack_op(sc->stack, current_stack_top(sc) - 1);
70365     }
70366   if ((top_op == OP_READ_VECTOR) ||
70367       (top_op == OP_READ_BYTE_VECTOR) ||
70368       (top_op == OP_READ_INT_VECTOR) ||
70369       (top_op == OP_READ_FLOAT_VECTOR))
70370    {
70371       pop_stack(sc);
70372       top_op = stack_op(sc->stack, current_stack_top(sc) - 1);
70373     }
70374   if (top_op == OP_READ_QUOTE)
70375     pop_stack(sc);
70376 }
70377 
70378 static token_t read_sharp(s7_scheme *sc, s7_pointer pt)
70379 {
70380   int32_t c;
70381   /* inchar can return EOF, so it can't be used directly as an index into the digits array */
70382   c = inchar(pt);
70383   switch (c)
70384     {
70385     case EOF:
70386       s7_error(sc, sc->read_error_symbol, set_elist_1(sc, wrap_string(sc, "unexpected '#' at end of input", 30)));
70387       break;
70388 
70389     case '(':
70390       sc->w = int_one;
70391       return(TOKEN_VECTOR);
70392 
70393     case 'i':
70394       if (read_sharp(sc, pt) == TOKEN_VECTOR)
70395 	return(TOKEN_INT_VECTOR);
70396       backchar('i', pt);
70397       break;
70398 
70399     case 'r':
70400       if (read_sharp(sc, pt) == TOKEN_VECTOR)
70401 	return(TOKEN_FLOAT_VECTOR);
70402       backchar('r', pt);
70403       break;
70404 
70405     case 'u':
70406       if (s7_peek_char(sc, pt) == chars[(int32_t)('8')]) /* backwards compatibility: #u8(...) == #u(...) */
70407 	{
70408 	  int32_t bc;
70409 	  bc = inchar(pt);
70410 	  if (s7_peek_char(sc, pt) == chars[(int32_t)('(')])
70411 	    {
70412 	      inchar(pt);
70413 	      sc->w = int_one;
70414 	      return(TOKEN_BYTE_VECTOR);
70415 	    }
70416 	  backchar(bc, pt);
70417 	}
70418       if (read_sharp(sc, pt) == TOKEN_VECTOR)
70419 	return(TOKEN_BYTE_VECTOR);
70420       backchar('u', pt);
70421       break;
70422 
70423     case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
70424       {
70425 	/* here we can get an overflow: #1231231231231232131D() */
70426 	s7_int dims;
70427 	int32_t d, loc = 0;
70428 	sc->strbuf[loc++] = (unsigned char)c;
70429 	dims = digits[c];
70430 
70431 	while (true)
70432 	  {
70433 	    s7_int dig;
70434 	    d = inchar(pt);
70435 	    if (d == EOF)
70436 	      s7_error(sc, sc->read_error_symbol,
70437 		       set_elist_1(sc, wrap_string(sc, "unexpected end of input while reading #n...", 43)));
70438 
70439 	    dig = digits[d];
70440 	    if (dig >= 10) break;
70441 	    dims = dig + (dims * 10);
70442 	    if (dims <= 0)
70443 	      {
70444 		sc->strbuf[loc++] = (unsigned char)d;
70445 		s7_error(sc, sc->read_error_symbol,
70446 			 set_elist_3(sc, wrap_string(sc, "reading #~A...: ~A must be a positive integer", 37),
70447 				     wrap_string(sc, sc->strbuf, loc),
70448 				     wrap_integer1(sc, dims)));
70449 	      }
70450 	    if (dims > sc->max_vector_dimensions)
70451 	      {
70452 		sc->strbuf[loc++] = (unsigned char)d;
70453 		sc->strbuf[loc + 1] = '\0';
70454 		s7_error(sc, sc->read_error_symbol,
70455 			 set_elist_4(sc, wrap_string(sc, "reading #~A...: ~A is too large, (*s7* 'max-vector-dimensions): ~A", 66),
70456 				     wrap_string(sc, sc->strbuf, loc),
70457 				     wrap_integer1(sc, dims),
70458 				     wrap_integer2(sc, sc->max_vector_dimensions)));
70459 	      }
70460 	    sc->strbuf[loc++] = (unsigned char)d;
70461 	  }
70462 	sc->strbuf[loc++] = d;
70463 	if ((d == 'd') || (d == 'i') || (d == 'r') || (d == 'u'))
70464 	  {
70465 	    int32_t e;
70466 	    e = inchar(pt);
70467 	    if (e == EOF)
70468 	      s7_error(sc, sc->read_error_symbol,
70469 		       set_elist_1(sc, wrap_string(sc, "unexpected end of input while reading #n()", 42)));
70470 	    sc->strbuf[loc++] = (unsigned char)e;
70471 	    if (e == '(')
70472 	      {
70473 		sc->w = make_integer(sc, dims);
70474 		if (d == 'd') return(TOKEN_VECTOR);
70475 		if (d == 'r') return(TOKEN_FLOAT_VECTOR);
70476 		return((d == 'u') ? TOKEN_BYTE_VECTOR : TOKEN_INT_VECTOR);
70477 	      }}
70478 	/* try to back out */
70479 	for (d = loc - 1; d > 0; d--)
70480 	  backchar(sc->strbuf[d], pt);
70481       }
70482       break;
70483 
70484     case ':':  /* turn #: into : -- this is for compatibility with Guile, sigh.
70485 		*   I just noticed that Rick is using this -- I'll just leave it alone.
70486 		*   but that means : readers need to handle this case specially.
70487 		* I don't think #! is special anymore -- maybe remove that code?
70488 		*/
70489       sc->strbuf[0] = ':';
70490       return(TOKEN_ATOM);
70491 
70492       /* block comments in #! ... !# */
70493       /* this is needed when an input file is treated as a script:
70494 	 #!/home/bil/cl/snd
70495 	 !#
70496 	 (format #t "a test~%")
70497 	 (exit)
70498       * but very often the closing !# is omitted which is too bad
70499       */
70500     case '!':
70501       {
70502 	char last_char;
70503 	s7_pointer reader;
70504 
70505 	/* make it possible to override #! handling */
70506 	for (reader = slot_value(sc->sharp_readers); is_pair(reader); reader = cdr(reader))
70507 	  if (s7_character(caar(reader)) == '!')
70508 	    {
70509 	      sc->strbuf[0] = (unsigned char)c;
70510 	      return(TOKEN_SHARP_CONST); /* next stage notices any errors */
70511 	    }
70512 
70513 	/* not #! as block comment (for Guile I guess) */
70514 	last_char = ' ';
70515 	while ((c = inchar(pt)) != EOF)
70516 	  {
70517 	    if ((c == '#') &&
70518 		(last_char == '!'))
70519 	      break;
70520 	    last_char = c;
70521 	  }
70522 	if (c == EOF)
70523 	  s7_error(sc, sc->read_error_symbol,
70524 		   set_elist_1(sc, wrap_string(sc, "unexpected end of input while reading #!", 40)));
70525 	return(token(sc));
70526       }
70527 
70528       /* block comments in #| ... |#
70529        *   since we ignore everything until the |#, internal semicolon comments are ignored,
70530        *   meaning that ;|# is as effective as |#
70531        */
70532     case '|':
70533       {
70534 	const char *str, *orig_str, *p, *pend;
70535 	if (is_file_port(pt))
70536 	  {
70537 	    char last_char;
70538 	    last_char = ' ';
70539 	    while (true)
70540 	      {
70541 		c = fgetc(port_file(pt));
70542 		if (c == EOF)
70543 		  s7_error(sc, sc->read_error_symbol,
70544 			   set_elist_1(sc, wrap_string(sc, "unexpected end of input while reading #|", 40)));
70545 		if ((c == '#') &&
70546 		    (last_char == '|'))
70547 		  break;
70548 		last_char = c;
70549 		if (c == '\n')
70550 		  port_line_number(pt)++;
70551 	      }
70552 	    return(token(sc));
70553 	  }
70554 
70555 	orig_str = (const char *)(port_data(pt) + port_position(pt));
70556 	pend = (const char *)(port_data(pt) + port_data_size(pt));
70557 	str = orig_str;
70558 
70559 	while (true)
70560 	  {
70561 	    p = strchr(str, (int)'|');
70562 	    if ((!p) || (p >= pend))
70563 	      {
70564 		port_position(pt) = port_data_size(pt);
70565 		s7_error(sc, sc->read_error_symbol,
70566 			 set_elist_1(sc, wrap_string(sc, "unexpected end of input while reading #|", 40)));
70567 	      }
70568 	    if (p[1] == '#')
70569 	      break;
70570 	    str = (const char *)(p + 1);
70571 	  }
70572 	port_position(pt) += (p - orig_str + 2);
70573 
70574 	/* now count newline inside the comment */
70575 	str = (const char *)orig_str;
70576 	pend = p;
70577 	while (true)
70578 	  {
70579 	    p = strchr(str, (int)'\n');
70580 	    if ((p) && (p < pend))
70581 	      {
70582 		port_line_number(pt)++;
70583 		str = (char *)(p + 1);
70584 	      }
70585 	    else break;
70586 	  }
70587 	return(token(sc));
70588       }}
70589   sc->strbuf[0] = (unsigned char)c;
70590   return(TOKEN_SHARP_CONST); /* next stage notices any errors */
70591 }
70592 
70593 static token_t read_comma(s7_scheme *sc, s7_pointer pt)
70594 {
70595   int32_t c;
70596   /* here we probably should check for symbol names that start with "@":
70597        (define-macro (hi @foo) `(+ ,@foo 1)) -> hi
70598        (hi 2) -> ;foo: unbound variable
70599      but
70600        (define-macro (hi .foo) `(+ ,.foo 1)) -> hi
70601        (hi 2) -> 3
70602      and ambiguous:
70603        (define-macro (hi @foo . foo) `(list ,@foo))
70604      what about , @foo -- is the space significant?  We accept ,@ foo.
70605   */
70606 
70607   if ((c = inchar(pt)) == '@')
70608     return(TOKEN_AT_MARK);
70609 
70610   if (c == EOF)
70611     {
70612       sc->strbuf[0] = ',';  /* was '@' which doesn't make any sense */
70613       return(TOKEN_COMMA);  /* was TOKEN_ATOM, which also doesn't seem sensible */
70614     }
70615 
70616   backchar(c, pt);
70617   return(TOKEN_COMMA);
70618 }
70619 
70620 static token_t read_dot(s7_scheme *sc, s7_pointer pt)
70621 {
70622   int32_t c;
70623   c = inchar(pt);
70624   if (c != EOF)
70625     {
70626       backchar(c, pt);
70627       if ((!char_ok_in_a_name[c]) && (c != 0))
70628 	return(TOKEN_DOT);
70629     }
70630   else
70631     {
70632       sc->strbuf[0] = '.';
70633       return(TOKEN_DOT);
70634     }
70635   sc->strbuf[0] = '.';
70636   return(TOKEN_ATOM);  /* i.e. something that can start with a dot like a number */
70637 }
70638 
70639 static token_t token(s7_scheme *sc) /* inline here is slower */
70640 {
70641   int32_t c;
70642   c = port_read_white_space(current_input_port(sc))(sc, current_input_port(sc));
70643   switch (c)
70644     {
70645     case '(':  return(TOKEN_LEFT_PAREN);
70646     case ')':  return(TOKEN_RIGHT_PAREN);
70647     case '.':  return(read_dot(sc, current_input_port(sc)));
70648     case '\'': return(TOKEN_QUOTE);
70649     case ';':  return(port_read_semicolon(current_input_port(sc))(sc, current_input_port(sc)));
70650     case '"':  return(TOKEN_DOUBLE_QUOTE);
70651     case '`':  return(TOKEN_BACK_QUOTE);
70652     case ',':  return(read_comma(sc, current_input_port(sc)));
70653     case '#':  return(read_sharp(sc, current_input_port(sc)));
70654     case '\0':
70655     case EOF:  return(TOKEN_EOF);
70656     default:
70657       sc->strbuf[0] = (unsigned char)c; /* every TOKEN_ATOM return goes to port_read_name, so we save a backchar/inchar shuffle by starting the read here */
70658       return(TOKEN_ATOM);
70659     }
70660 }
70661 
70662 static int32_t read_x_char(s7_scheme *sc, int32_t i, s7_pointer pt)
70663 {
70664   /* possible "\xn...;" char (write creates these things, so we have to read them)
70665    *   but we could have crazy input like "\x -- with no trailing double quote
70666    */
70667   while (true)
70668     {
70669       int32_t d1, d2, c;
70670       c = inchar(pt);
70671       if (c == '"')
70672 	{
70673 	  backchar(c, pt);
70674 	  return(i);
70675 	}
70676       if (c == ';') return(i);
70677       if (c == EOF)
70678 	{
70679 	  read_error(sc, "#<eof> in midst of hex-char");
70680 	  return(i);
70681 	}
70682       d1 = digits[c];
70683       if (d1 >= 16)
70684 	{
70685 	  sc->strbuf[i++] = (unsigned char)c; /* just go on -- maybe a special char is not intended */
70686 	  return(i);
70687 	}
70688       c = inchar(pt);
70689       if (c == '"')
70690 	{
70691 	  sc->strbuf[i++] = (unsigned char)d1;
70692 	  backchar((char)c, pt);
70693 	  return(i);
70694 	}
70695       if (c == EOF)
70696 	{
70697 	  read_error(sc, "#<eof> in midst of hex-char");
70698 	  return(i);
70699 	}
70700       if (c == ';')
70701 	{
70702 	  sc->strbuf[i++] = (unsigned char)d1;
70703 	  return(i);
70704 	}
70705       d2 = digits[c];
70706       if (d2 >= 16)
70707 	{
70708 	  sc->strbuf[i++] = (unsigned char)c; /* just go on -- maybe a special char is not intended */
70709 	  return(i);
70710 	}
70711       sc->strbuf[i++] = (unsigned char)(16 * d1 + d2);
70712     }
70713   return(i);
70714 }
70715 
70716 static s7_pointer unknown_string_constant(s7_scheme *sc, int32_t c)
70717 {
70718   /* check *read-error-hook* */
70719   if (hook_has_functions(sc->read_error_hook))
70720     {
70721       s7_pointer result;
70722       result = s7_call(sc, sc->read_error_hook, set_plist_2(sc, sc->F, s7_make_character(sc, (uint8_t)c)));
70723       if (s7_is_character(result))
70724 	return(result);
70725     }
70726   return(sc->T);
70727 }
70728 
70729 static s7_pointer read_string_constant(s7_scheme *sc, s7_pointer pt)
70730 {
70731   /* sc->F => error
70732    *   no check needed here for bad input port and so on
70733    */
70734   s7_int i = 0;
70735 
70736   if (is_string_port(pt))
70737     {
70738       /* try the most common case first */
70739       char *s, *start, *end;
70740       start = (char *)(port_data(pt) + port_position(pt));
70741       if (*start == '"')
70742 	{
70743 	  port_position(pt)++;
70744 	  return(make_empty_string(sc, 0, 0));
70745 	}
70746 
70747       end = (char *)(port_data(pt) + port_data_size(pt));
70748       s = strpbrk(start, "\"\n\\");
70749       if ((!s) || (s >= end))                     /* can this read a huge string constant from a file? */
70750 	{
70751 	  if (start == end)
70752 	    sc->strbuf[0] = '\0';
70753 	  else memcpy((void *)(sc->strbuf), (void *)start, (end - start > 8) ? 8 : (end - start));
70754 	  sc->strbuf[8] = '\0';
70755 	  return(sc->F);
70756 	}
70757       if (*s == '"')
70758 	{
70759 	  s7_int len;
70760 	  len = s - start;
70761 	  port_position(pt) += (len + 1);
70762 	  return(make_string_with_length(sc, start, len));
70763 	}
70764 
70765       for (; s < end; s++)
70766 	{
70767 	  if (*s == '"')                         /* switch here no faster */
70768 	    {
70769 	      s7_int len;
70770 	      len = s - start;
70771 	      port_position(pt) += (len + 1);
70772 	      return(make_string_with_length(sc, start, len));
70773 	    }
70774 	  if (*s == '\\')
70775 	    {
70776 	      /* all kinds of special cases here (resultant string is not the current string), so drop to loop below (setting "i") */
70777 	      s7_int len;
70778 	      len = (s7_int)(s - start);
70779 	      if (len > 0)
70780 		{
70781 		  if (len >= sc->strbuf_size)
70782 		    resize_strbuf(sc, len);
70783 		  /* for (i = 0; i < len; i++) sc->strbuf[i] = port_data(pt)[port_position(pt)++]; */
70784 		  memcpy((void *)(sc->strbuf), (void *)(port_data(pt) + port_position(pt)), len);
70785 		  port_position(pt) += len;
70786 		}
70787 	      i = len;
70788 	      break;
70789 	    }
70790 	  else
70791 	    if (*s == '\n')
70792 	      port_line_number(pt)++;
70793 	}}
70794 
70795   while (true)
70796     {
70797       /* splitting this check out and duplicating the loop was slower?!? */
70798       int32_t c;
70799       c = port_read_character(pt)(sc, pt);
70800 
70801       switch (c)
70802 	{
70803 	case '\n':
70804 	  port_line_number(pt)++;
70805 	  sc->strbuf[i++] = (unsigned char)c;
70806 	  break;
70807 
70808 	case EOF:
70809 	  sc->strbuf[(i > 8) ? 8 : i] = '\0';
70810 	  return(sc->F);
70811 
70812 	case '"':
70813 	  return(make_string_with_length(sc, sc->strbuf, i));
70814 
70815 	case '\\':
70816 	  c = inchar(pt);
70817 
70818 	  switch (c)
70819 	    {
70820 	    case EOF:
70821 	      sc->strbuf[(i > 8) ? 8 : i] = '\0';
70822 	      return(sc->F);
70823 
70824 	    case '\\': case '"': case '|':
70825 	      sc->strbuf[i++] = (unsigned char)c;
70826               break;
70827 
70828 	    case 'n': sc->strbuf[i++] = '\n'; break;
70829 	    case 't': sc->strbuf[i++] = '\t'; break;
70830 	    case 'r': sc->strbuf[i++] = '\r'; break;
70831 	    case '/': sc->strbuf[i++] = '/';  break;
70832 	    case 'b': sc->strbuf[i++] = (unsigned char)8;    break;
70833 	    case 'f': sc->strbuf[i++] = (unsigned char)12;   break;
70834 
70835 	    case 'x':
70836 	      i = read_x_char(sc, i, pt);
70837               break;
70838 
70839             default:	      /* if (!is_white_space(c)) */ /* changed 8-Apr-12 */
70840 	      if ((c != '\n') && (c != '\r')) /* i.e. line continuation via #\\ at end of line */
70841 		{
70842 		  s7_pointer result;
70843 		  result = unknown_string_constant(sc, c);
70844 		  if (s7_is_character(result))
70845 		    sc->strbuf[i++] = character(result);
70846 		  else return(result);
70847 		}
70848 	      /* #f here would give confusing error message "end of input", so return #t=bad backslash.
70849 	       *     this is not optimal. It's easy to forget that backslash needs to be backslashed.
70850 	       * the white_space business half-implements Scheme's \<newline>...<eol>... or \<space>...<eol>...
70851 	       *   feature -- the characters after \ are flushed if they're all white space and include a newline.
70852 	       *   (string->number "1\   2") is 12??  Too bizarre.
70853 	       */
70854 	    }
70855 	  break;
70856 
70857 	default:
70858 	  sc->strbuf[i++] = (unsigned char)c;
70859 	  break;
70860 	}
70861 
70862       if (i >= sc->strbuf_size)
70863 	resize_strbuf(sc, i);
70864     }
70865 }
70866 
70867 static void read_double_quote(s7_scheme *sc)
70868 {
70869   sc->value = read_string_constant(sc, current_input_port(sc));
70870   if (sc->value == sc->F)                                /* can happen if input code ends in the middle of a string */
70871     string_read_error(sc, "end of input encountered while in a string");
70872   if (sc->value == sc->T)
70873     read_error(sc, "unknown backslash usage -- perhaps you meant two backslashes?");
70874   if (sc->safety > IMMUTABLE_VECTOR_SAFETY) set_immutable(sc->value);
70875 }
70876 
70877 static inline bool read_sharp_const(s7_scheme *sc)
70878 {
70879   sc->value = port_read_sharp(current_input_port(sc))(sc, current_input_port(sc));
70880   if (sc->value == sc->no_value)
70881     {
70882       /* (set! *#readers* (cons (cons #\; (lambda (s) (read) (values))) *#readers*))
70883        * (+ 1 #;(* 2 3) 4)
70884        * so we need to get the next token, act on it without any assumptions about read list
70885        */
70886       sc->tok = token(sc);
70887       return(true);
70888     }
70889   return(false);
70890 }
70891 
70892 static s7_pointer read_expression_read_error(s7_scheme *sc)
70893 {
70894   s7_pointer pt;
70895   pop_stack(sc);
70896   pt = current_input_port(sc);
70897   if ((is_input_port(pt)) &&
70898       (!port_is_closed(pt)) &&
70899       (port_data(pt)) &&
70900       (port_position(pt) > 0))
70901     {
70902       s7_int start, pos;
70903       s7_pointer p;
70904       char *msg;
70905 
70906       pos = port_position(pt);
70907       start = pos - 40;
70908       if (start < 0) start = 0;
70909 
70910       p = make_empty_string(sc, 128, '\0');
70911       msg = string_value(p);
70912       memcpy((void *)msg, (void *)"at \"...", 7);
70913       memcpy((void *)(msg + 7), (void *)(port_data(pt) + start), pos - start);
70914       memcpy((void *)(msg + 7 + pos - start), (void *)"...", 3);
70915       string_length(p) = 7 + pos - start + 3;
70916       return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, p)));
70917     }
70918   return(read_error(sc, "stray comma before ')'?"));         /* '("a" "b",) */
70919 }
70920 
70921 static s7_pointer read_expression(s7_scheme *sc)
70922 {
70923   while (true)
70924     {
70925       int32_t c;
70926       switch (sc->tok)
70927 	{
70928 	case TOKEN_EOF:
70929 	  return(eof_object);
70930 
70931 	case TOKEN_BYTE_VECTOR:
70932 	  push_stack_no_let_no_code(sc, OP_READ_BYTE_VECTOR, sc->w);
70933 	  sc->tok = TOKEN_LEFT_PAREN;
70934 	  break;
70935 
70936 	case TOKEN_INT_VECTOR:
70937 	  push_stack_no_let_no_code(sc, OP_READ_INT_VECTOR, sc->w);
70938 	  sc->tok = TOKEN_LEFT_PAREN;
70939 	  break;
70940 
70941 	case TOKEN_FLOAT_VECTOR:
70942 	  push_stack_no_let_no_code(sc, OP_READ_FLOAT_VECTOR, sc->w);
70943 	  sc->tok = TOKEN_LEFT_PAREN;
70944 	  break;
70945 
70946 	case TOKEN_VECTOR:         /* already read #( -- TOKEN_VECTOR is triggered by #( */
70947 	  push_stack_no_let_no_code(sc, OP_READ_VECTOR, sc->w);   /* sc->w is the dimensions */
70948 	  /* fall through */
70949 
70950 	case TOKEN_LEFT_PAREN:
70951 	  sc->tok = token(sc);
70952 
70953 	  if (sc->tok == TOKEN_RIGHT_PAREN)
70954 	    return(sc->nil);
70955 
70956 	  if (sc->tok == TOKEN_DOT)
70957 	    {
70958 	      back_up_stack(sc);
70959 	      do {c = inchar(current_input_port(sc));} while ((c != ')') && (c != EOF));
70960 	      return(read_error(sc, "stray dot after '('?"));         /* (car '( . )) */
70961 	    }
70962 
70963 	  if (sc->tok == TOKEN_EOF)
70964 	    return(missing_close_paren_error(sc));
70965 
70966 	  push_stack_no_let_no_code(sc, OP_READ_LIST, sc->nil);
70967 	  /* here we need to clear args, but code is ignored */
70968 
70969 	  check_stack_size(sc);
70970 	  break;
70971 
70972 	case TOKEN_QUOTE:
70973 	  push_stack_no_let_no_code(sc, OP_READ_QUOTE, sc->nil);
70974 	  sc->tok = token(sc);
70975 	  break;
70976 
70977 	case TOKEN_BACK_QUOTE:
70978 	  sc->tok = token(sc);
70979 	  push_stack_no_let_no_code(sc, OP_READ_QUASIQUOTE, sc->nil);
70980 	  break;
70981 
70982 	case TOKEN_COMMA:
70983 	  push_stack_no_let_no_code(sc, OP_READ_UNQUOTE, sc->nil);
70984 	  sc->tok = token(sc);
70985 	  switch (sc->tok)
70986 	    {
70987 	    case TOKEN_EOF:
70988 	      pop_stack(sc);
70989 	      return(read_error(sc, "stray comma at the end of the input?"));
70990 
70991 	    case TOKEN_RIGHT_PAREN:
70992 	      return(read_expression_read_error(sc));
70993 
70994 	    default:
70995 	      break;
70996 	    }
70997 	  break;
70998 
70999 	case TOKEN_AT_MARK:
71000 	  push_stack_no_let_no_code(sc, OP_READ_APPLY_VALUES, sc->nil);
71001 	  sc->tok = token(sc);
71002 	  break;
71003 
71004 	case TOKEN_ATOM:
71005 	  return(port_read_name(current_input_port(sc))(sc, current_input_port(sc)));
71006 	  /* If reading list (from lparen), this will finally get us to op_read_list */
71007 
71008 	case TOKEN_DOUBLE_QUOTE:
71009 	  read_double_quote(sc);
71010 	  return(sc->value);
71011 
71012 	case TOKEN_SHARP_CONST:
71013 	  return(port_read_sharp(current_input_port(sc))(sc, current_input_port(sc)));
71014 
71015 	case TOKEN_DOT:                                             /* (catch #t (lambda () (+ 1 . . )) (lambda args 'hiho)) */
71016 	  back_up_stack(sc);
71017 	  do {c = inchar(current_input_port(sc));} while ((c != ')') && (c != EOF));
71018 	  return(read_error(sc, "stray dot in list?"));             /* (+ 1 . . ) */
71019 
71020 	case TOKEN_RIGHT_PAREN:                                     /* (catch #t (lambda () '(1 2 . )) (lambda args 'hiho)) */
71021 	  back_up_stack(sc);
71022 	  return(read_error(sc, "unexpected close paren"));         /* (+ 1 2)) or (+ 1 . ) */
71023 	}}
71024   /* we never get here */
71025   return(sc->nil);
71026 }
71027 
71028 static void read_dot_and_expression(s7_scheme *sc)
71029 {
71030   push_stack_no_let_no_code(sc, OP_READ_DOT, sc->args);
71031   sc->tok = token(sc);
71032   sc->value = read_expression(sc);
71033 }
71034 
71035 static void read_tok_default(s7_scheme *sc)
71036 {
71037   /* by far the main case here is TOKEN_LEFT_PAREN, but it doesn't save anything to move it to this level */
71038   push_stack_no_let_no_code(sc, OP_READ_LIST, sc->args);
71039   sc->value = read_expression(sc);
71040   /* check for op_read_list here and explicit pop_stack are slower */
71041 }
71042 
71043 static void pair_set_current_input_location(s7_scheme *sc, s7_pointer p)
71044 {
71045   if (current_input_port(sc) != sc->standard_input) /* (port_file_number(current_input_port(sc)) > 1) -- maybe 0 is legit? */
71046     {
71047       pair_set_location(p, port_location(current_input_port(sc)));
71048       set_has_location(p);	      /* current_input_port(sc) above can't be nil(?) -- it falls back on stdin now */
71049     }
71050 }
71051 
71052 static int32_t read_atom(s7_scheme *sc, s7_pointer pt)
71053 {
71054   push_stack_no_let_no_code(sc, OP_READ_LIST, sc->args);
71055   check_stack_size(sc);
71056   sc->value = port_read_name(pt)(sc, pt);
71057   sc->args = list_1(sc, sc->value);
71058   pair_set_current_input_location(sc, sc->args);
71059   return(port_read_white_space(pt)(sc, pt));
71060 }
71061 
71062 
71063 /* ---------------- *unbound-variable-hook* ---------------- */
71064 
71065 static s7_pointer loaded_library(s7_scheme *sc, const char *file)
71066 {
71067   s7_pointer p;
71068   for (p = global_value(sc->libraries_symbol); is_pair(p); p = cdr(p))
71069     if (local_strcmp(file, string_value(caar(p))))
71070       return(cdar(p));
71071   return(sc->nil);
71072 }
71073 
71074 static s7_pointer unbound_variable_error(s7_scheme *sc, s7_pointer sym)
71075 {
71076   if (s7_tree_memq(sc, sym, current_code(sc)))
71077     return(s7_error(sc, sc->unbound_variable_symbol, set_elist_3(sc, wrap_string(sc, "unbound variable ~S in ~S", 25), sym, current_code(sc))));
71078   if ((symbol_name(sym)[symbol_name_length(sym) - 1] == ',') &&
71079       (lookup_unexamined(sc, make_symbol_with_length(sc, symbol_name(sym), symbol_name_length(sym) - 1))))
71080     return(s7_error(sc, sc->unbound_variable_symbol, set_elist_2(sc, wrap_string(sc, "unbound variable ~S (perhaps a stray comma?)", 44), sym)));
71081   return(s7_error(sc, sc->unbound_variable_symbol, set_elist_2(sc, wrap_string(sc, "unbound variable ~S", 19), sym)));
71082 }
71083 
71084 static s7_pointer unbound_variable(s7_scheme *sc, s7_pointer sym)
71085 {
71086   /* this always occurs in a context where we're trying to find anything, so I'll move a couple of those checks here */
71087   if (has_let_ref_fallback(sc->curlet)) /* an experiment -- see s7test (with-let *db* (+ int32_t (length str))) */
71088     return(call_let_ref_fallback(sc, sc->curlet, sym));
71089   /* but if the thing we want to hit this fallback happens to exist at a higher level, oops... */
71090 
71091   if (sym == sc->unquote_symbol)
71092     eval_error(sc, "unquote (',') occurred outside quasiquote: ~S", 45, current_code(sc));
71093 
71094   if (safe_strcmp(symbol_name(sym), "|#"))
71095     return(read_error(sc, "unmatched |#"));
71096 
71097   /* check *autoload*, autoload_names, then *unbound-variable-hook* */
71098   if ((sc->autoload_names) ||
71099       (is_hash_table(sc->autoload_table)) ||
71100       (hook_has_functions(sc->unbound_variable_hook)))
71101     {
71102       s7_pointer result, cur_code, value, code, args, current_let, x, z;
71103       /* sc->args and sc->code are pushed on the stack by s7_call, then
71104        *   restored by eval, so they are normally protected, but sc->value and current_code(sc) are
71105        *   not protected (yet).  We need current_code(sc) so that the possible eventual error
71106        *   call can tell where the error occurred, and we need sc->value because it might
71107        *   be awaiting addition to sc->args in e.g. OP_EVAL_ARGS5, and then be clobbered
71108        *   by the hook function.  (+ 1 asdf) will end up evaluating (+ asdf asdf) if sc->value
71109        *   is not protected.  We also need to save/restore sc->curlet in case s7_load is called.
71110        */
71111 
71112       args = (sc->args) ? sc->args : sc->nil;
71113       code = sc->code;
71114       value = sc->value;
71115       cur_code = current_code(sc);
71116       current_let = sc->curlet;
71117       result = sc->undefined;
71118       x = sc->x;
71119       z = sc->z;
71120       sc->temp7 = cons(sc, code, cons(sc, args, list_4(sc, value, cur_code, x, z))); /* not s7_list (debugger checks) */
71121 
71122       if (!is_pair(cur_code))
71123 	{
71124 	  /* isolated typo perhaps -- no pair to hold the position info, so make one. current_code(sc) is GC-protected, so this should be safe. */
71125 	  cur_code = list_1(sc, sym);     /* the error will say "(sym)" which is not too misleading */
71126 	  pair_set_current_input_location(sc, cur_code);
71127 	}
71128 
71129 #if (!DISABLE_AUTOLOAD)
71130       /* check sc->autoload_names */
71131       if ((sc->is_autoloading) &&
71132 	  (sc->autoload_names))
71133 	{
71134 	  const char *file;
71135 	  bool loaded = false;
71136 	  file = find_autoload_name(sc, sym, &loaded, true);
71137 	  if ((file) && (!loaded))
71138 	    {
71139 	      s7_pointer e;
71140 	      /* if we've already loaded this file, we can get the library (e) from a table [(file lib) ...]
71141 	       * here it was possible to get caught in a loop:
71142 	       *   change file, reload, unbound var seen, check autoload, it says "load file"... (where file does not get added to *libraries*)
71143 	       *   so the "loaded" arg tries to catch such cases
71144 	       */
71145 	      e = loaded_library(sc, file);
71146 	      if ((!e) || (!is_let(e)))
71147 		{
71148 		  if (hook_has_functions(sc->autoload_hook))
71149 		    s7_apply_function(sc, sc->autoload_hook, set_plist_2(sc, sym, sc->temp6 = s7_make_string(sc, file)));
71150 		  e = s7_load(sc, file);           /* s7_load can return NULL */
71151 		}
71152 	      result = s7_symbol_value(sc, sym); /* calls lookup, does not trigger unbound_variable search */
71153 	      if ((result == sc->undefined) &&
71154 		  (e) && (is_let(e)))
71155 		{
71156 		  result = s7_let_ref(sc, e, sym);
71157 		  /* I think to be consistent we should add '(sym . result) to the global let */
71158 		  if (result != sc->undefined)
71159 		    s7_define(sc, sc->nil, sym, result);
71160 		}}}
71161 #endif
71162       if (result == sc->undefined)
71163 	{
71164 #if (!DISABLE_AUTOLOAD)
71165 	  /* check the *autoload* hash table */
71166 	  if ((sc->is_autoloading) &&
71167 	      (is_hash_table(sc->autoload_table)))
71168 	    {
71169 	      s7_pointer val;
71170 	      /* it was possible to get in a loop here: missing paren in x.scm, checks last symbol, sees
71171 	       *   autoload sym -> x.scm, loads x.scm, missing paren...
71172 	       */
71173 	      val = s7_hash_table_ref(sc, sc->autoload_table, sym);
71174 	      if (is_string(val))                /* val should be a filename. *load-path* is searched if necessary. */
71175 		{
71176 		  if (hook_has_functions(sc->autoload_hook))
71177 		    s7_apply_function(sc, sc->autoload_hook, set_plist_2(sc, sym, val));
71178 		  s7_load(sc, string_value(val));
71179 		}
71180 	      else
71181 		if (is_closure(val))           /* val should be a function of one argument, the current (calling) environment */
71182 		  {
71183 		    if (hook_has_functions(sc->autoload_hook))
71184 		      s7_apply_function(sc, sc->autoload_hook, set_plist_2(sc, sym, val));
71185 		    s7_call(sc, val, set_ulist_1(sc, sc->curlet, sc->nil));
71186 		  }
71187 	      result = s7_symbol_value(sc, sym); /* calls lookup, does not trigger unbound_variable search */
71188 	    }
71189 #endif
71190 	  /* check *unbound-variable-hook* */
71191 	  if ((result == sc->undefined) &&
71192 	      (is_procedure(sc->unbound_variable_hook)) &&
71193 	      (hook_has_functions(sc->unbound_variable_hook)))
71194 	    {
71195 	      /* (let () (set! (hook-functions *unbound-variable-hook*) (list (lambda (v) _asdf_))) _asdf_) */
71196 	      s7_pointer old_hook;
71197 	      bool old_history_enabled;
71198 
71199 	      old_history_enabled = s7_set_history_enabled(sc, false);
71200 	      old_hook = sc->unbound_variable_hook;
71201 	      set_car(sc->z2_1, old_hook);
71202 	      sc->unbound_variable_hook = sc->error_hook;      /* avoid the infinite loop mentioned above -- error_hook might be () or #f if we're in error-hook now */
71203 	      result = s7_call(sc, old_hook, set_plist_1(sc, sym)); /* not s7_apply_function */
71204 	      sc->unbound_variable_hook = old_hook;
71205 	      s7_set_history_enabled(sc, old_history_enabled);
71206 	    }}
71207 
71208       sc->value = T_Pos(value);
71209       sc->args = T_Pos(args);
71210       sc->code = code;
71211       sc->curlet = current_let;
71212       sc->x = x;
71213       sc->z = z;
71214       sc->temp7 = sc->nil;
71215       if ((result != sc->undefined) &&
71216 	  (result != sc->unspecified))
71217 	return(result);
71218     }
71219   return(unbound_variable_error(sc, sym));
71220 }
71221 
71222 static bool gx_annotate_arg(s7_scheme *sc, s7_pointer p, s7_pointer e)
71223 {
71224   if (is_gxable(car(p)))
71225     {
71226       opcode_t old_op;
71227       s7_pointer fxf;
71228       old_op = optimize_op(car(p));
71229       set_optimize_op(car(p), old_op + 1);
71230       fxf = (s7_pointer)fx_choose(sc, p, e, (is_list(e)) ? pair_symbol_is_safe : let_symbol_is_safe);
71231       if (fxf)
71232 	{
71233 	  set_has_gx(p);
71234 	  set_opt2(p, fxf, OPT2_FX);
71235 	}
71236       set_optimize_op(car(p), old_op);
71237       return(fxf);
71238     }
71239   return(false);
71240 }
71241 
71242 static void gx_annotate_args(s7_scheme *sc, s7_pointer args, s7_pointer e)
71243 {
71244   s7_pointer p;
71245   for (p = args; is_pair(p); p = cdr(p))
71246     gx_annotate_arg(sc, p, e);
71247 }
71248 
71249 #define choose_c_function(Sc, Expr, Func, Args) set_c_function(Expr, c_function_chooser(Func)(Sc, Func, Args, Expr, true))
71250 
71251 static void fx_annotate_arg(s7_scheme *sc, s7_pointer arg, s7_pointer e)
71252 {
71253 #if S7_DEBUGGING
71254   s7_function fx;
71255   if (has_fx(arg)) return;
71256   fx = fx_choose(sc, arg, e, (is_list(e)) ? pair_symbol_is_safe : let_symbol_is_safe);
71257   if (fx) set_fx_direct(arg, fx);
71258 #else
71259   if (has_fx(arg)) return;
71260   set_fx(arg, fx_choose(sc, arg, e, (is_list(e)) ? pair_symbol_is_safe : let_symbol_is_safe));
71261 #endif
71262 }
71263 
71264 static void fx_annotate_args(s7_scheme *sc, s7_pointer args, s7_pointer e)
71265 {
71266   s7_pointer p;
71267   for (p = args; is_pair(p); p = cdr(p))
71268 #if S7_DEBUGGING
71269     fx_annotate_arg(sc, p, e); /* checks has_fx */
71270 #else
71271     if (!has_fx(p))
71272       set_fx(p, fx_choose(sc, p, e, (is_list(e)) ? pair_symbol_is_safe : let_symbol_is_safe));
71273 #endif
71274 }
71275 
71276 static opt_t optimize_thunk(s7_scheme *sc, s7_pointer expr, s7_pointer func, int32_t hop, s7_pointer e)
71277 {
71278   if ((hop != 1) && (is_constant_symbol(sc, car(expr)))) hop = 1;
71279 
71280   if ((is_closure(func)) || (is_closure_star(func)))
71281     {
71282       bool safe_case;
71283       safe_case = is_safe_closure(func);
71284       if (is_immutable(func)) hop = 1;
71285       if (is_null(closure_args(func)))               /* no rest arg funny business */
71286 	{
71287 	  s7_pointer body;
71288 	  set_optimized(expr);
71289 	  body = closure_body(func);
71290 	  if (is_null(cdr(body)))
71291 	    {
71292 	      if ((safe_case) && (is_fxable(sc, car(body))))          /* fx stuff is not set yet */
71293 		{
71294 		  fx_annotate_arg(sc, body, e);
71295 		  set_optimize_op(expr, hop + OP_SAFE_THUNK_A);
71296 		  set_closure_one_form_fx_arg(func);
71297 		  set_opt1_lambda_add(expr, func);
71298 		  return(OPT_T);
71299 		}}
71300 	  /* thunks with fully fxable bodies are rare apparently, and the time spent here overwhelms run time gains */
71301 	  set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_THUNK : OP_THUNK));
71302 	  set_opt1_lambda_add(expr, func);
71303 	  return(OPT_F);
71304 	}
71305       if (is_symbol(closure_args(func))) /* (define* (f1 . a) ...) called (f1) -- called a closure (not closure*) in define_unchecked */
71306 	{
71307 	  set_opt1_lambda_add(expr, func);
71308 	  set_unsafe_optimize_op(expr, hop + OP_THUNK_ANY); /* "thunk" because here it is called with no args, I guess */
71309 	  return(OPT_F);
71310 	}
71311       if (is_closure_star(func))
71312 	{
71313 	  set_opt1_lambda_add(expr, func);
71314 	  set_safe_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_ALL_A_0 : OP_CLOSURE_STAR_ALL_A));
71315 	}
71316       return(OPT_F);
71317     }
71318 
71319   if (is_c_function(func))
71320     {
71321       if (c_function_required_args(func) != 0)
71322 	return(OPT_F);
71323       if ((hop == 0) && (symbol_id(car(expr)) == 0)) hop = 1;
71324 
71325       if ((is_safe_procedure(func)) ||
71326 	  (c_function_call(func) == g_list))          /* (list) is safe, (values) is not (in this context -- possibly used as list-values arg) */
71327 	{
71328 	  set_safe_optimize_op(expr, hop + OP_SAFE_C_D);
71329 	  choose_c_function(sc, expr, func, 0);
71330 	  return(OPT_T);
71331 	}
71332       set_unsafe_optimize_op(expr, hop + OP_C);
71333       choose_c_function(sc, expr, func, 0);
71334       return(OPT_F);
71335     }
71336 
71337   if (is_c_function_star(func))
71338     {
71339       set_safe_optimize_op(expr, hop + OP_SAFE_C_FUNCTION_STAR);
71340       set_c_function(expr, func);
71341       return(OPT_T);
71342     }
71343 
71344   return(OPT_F);
71345 }
71346 
71347 static opt_t optimize_closure_dotted_args(s7_scheme *sc, s7_pointer expr, s7_pointer func, int32_t hop, int32_t args, s7_pointer e)
71348 {
71349 #if S7_DEBUGGING
71350   if (!is_symbol(closure_args(func))) fprintf(stderr, "%s[%d]: %s but %s\n", __func__, __LINE__, display_80(expr), display(func));
71351 #endif
71352   if (fx_count(sc, expr) == args) /* fx_count starts at cdr, args here is the number of exprs in cdr(expr) -- so this means "are all args fxable" */
71353     {
71354       fx_annotate_args(sc, cdr(expr), e);
71355       set_opt3_arglen(cdr(expr), small_int(args));
71356       set_unsafe_optimize_op(expr, hop + OP_CLOSURE_ANY_ALL_A);
71357       set_opt1_lambda_add(expr, func);
71358       return(OPT_F);
71359     }
71360   return(OPT_F);
71361 }
71362 
71363 static int32_t combine_ops(s7_scheme *sc, s7_pointer func, s7_pointer expr, combine_op_t cop, s7_pointer e1, s7_pointer e2) /* sc needed for debugger stuff */
71364 {
71365   int32_t arg_op;
71366   s7_pointer arg;
71367 
71368   switch (cop)
71369     {
71370     case E_C_P:
71371       arg_op = op_no_hop(e1);
71372       switch (arg_op)
71373 	{
71374 	case OP_SAFE_C_S:      return(OP_SAFE_C_opSq);
71375 	case OP_SAFE_C_D:      return(OP_SAFE_C_opDq);
71376 	case OP_SAFE_C_SS:     return(OP_SAFE_C_opSSq);
71377 	case OP_SAFE_C_SC:     return(OP_SAFE_C_opSCq);
71378 	case OP_SAFE_C_CS:     return(OP_SAFE_C_opCSq);
71379 	case OP_SAFE_C_opSq:   return(OP_SAFE_C_op_opSqq);
71380 	case OP_SAFE_C_S_opSq: return(OP_SAFE_C_op_S_opSqq);
71381 	case OP_SAFE_C_opSq_S: return(OP_SAFE_C_op_opSq_Sq);
71382 	case OP_SAFE_C_A:      return(OP_SAFE_C_opAq);
71383 	case OP_SAFE_C_AA:     return(OP_SAFE_C_opAAq);
71384 	case OP_SAFE_C_AAA:    return(OP_SAFE_C_opAAAq);
71385 	}
71386       return(OP_SAFE_C_P); /* this splits out to A in optimize_func one_arg */
71387 
71388     case E_C_SP:
71389       arg = e2;
71390       arg_op = op_no_hop(arg);
71391       switch (arg_op)
71392 	{
71393 	case OP_SAFE_C_S:   return(OP_SAFE_C_S_opSq);
71394 	case OP_SAFE_C_AA:  return(OP_SAFE_C_S_opAAq);
71395 	case OP_SAFE_C_AAA: return(OP_SAFE_C_S_opAAAq);
71396 
71397 	case OP_SAFE_C_SC:
71398 	  set_opt2_con(cdr(expr), caddr(arg));
71399 	  return(OP_SAFE_C_S_opSCq);
71400 
71401 	case OP_SAFE_C_CS:	  /* expr is (* a (- 1 b)), e2 is (- 1 b) */
71402 	  set_opt2_sym(cdr(expr), caddr(arg));
71403 	  return(OP_SAFE_C_S_opCSq);
71404 
71405 	case OP_SAFE_C_SS:	  /* (* a (- b c)) */
71406 	  set_opt2_sym(cdr(expr), caddr(arg));
71407 	  return(OP_SAFE_C_S_opSSq);
71408 
71409 	case OP_SAFE_C_A:
71410 	  set_opt3_pair(expr, cdaddr(expr));
71411 	  return(OP_SAFE_C_S_opAq);
71412 	}
71413       return(OP_SAFE_C_SP); /* if fxable -> AA later */
71414 
71415     case E_C_PS:
71416       arg = e1;
71417       arg_op = op_no_hop(arg);
71418       switch (arg_op)
71419 	{
71420 	case OP_SAFE_C_S:     return(OP_SAFE_C_opSq_S);
71421 	case OP_SAFE_C_SS:    return(OP_SAFE_C_opSSq_S);
71422 	case OP_SAFE_C_CS:    return(OP_SAFE_C_opCSq_S);
71423 	case OP_SAFE_C_A:     return(OP_SAFE_C_opAq_S);
71424 	case OP_SAFE_C_opSSq: set_opt1_pair(cdr(expr), cadadr(expr)); return(OP_SAFE_C_op_opSSqq_S);
71425 	}
71426       return(OP_SAFE_C_PS);
71427 
71428     case E_C_PC:
71429       arg = e1;
71430       arg_op = op_no_hop(arg);
71431       switch (arg_op)
71432 	{
71433 	case OP_SAFE_C_S:
71434 	  set_opt1_sym(cdr(expr), cadr(e1));
71435 	  set_opt2_con(cdr(expr), e2);
71436 	  return(OP_SAFE_C_opSq_C);
71437 	case OP_SAFE_C_CS:    return(OP_SAFE_C_opCSq_C);
71438 	case OP_SAFE_C_SC:    return(OP_SAFE_C_opSCq_C);
71439 	case OP_SAFE_C_SS:    return(OP_SAFE_C_opSSq_C);
71440 	}
71441       set_opt3_con(cdr(expr), caddr(expr));
71442       return(OP_SAFE_C_PC);
71443 
71444     case E_C_CP:
71445       arg = e2;
71446       arg_op = op_no_hop(arg);
71447       switch (arg_op)
71448 	{
71449 	case OP_SAFE_C_S:
71450 	  set_opt3_pair(expr, arg);
71451 	  return(OP_SAFE_C_C_opSq);
71452 
71453 	case OP_SAFE_C_SC:
71454 	  set_opt1_sym(cdr(expr), cadr(arg));
71455 	  set_opt2_con(cdr(expr), caddr(arg));
71456 	  return(OP_SAFE_C_C_opSCq);
71457 
71458 	case OP_SAFE_C_SS:
71459 	  set_opt1_sym(cdr(expr), cadr(arg));
71460 	  return(OP_SAFE_C_C_opSSq);
71461 	}
71462       return(OP_SAFE_C_CP);
71463 
71464     case E_C_PP:
71465       arg = e2;
71466       arg_op = op_no_hop(arg);
71467       switch (arg_op)
71468 	{
71469 	case OP_SAFE_C_S:
71470 	  if (is_safe_c_s(e1))
71471 	    return(OP_SAFE_C_opSq_opSq);
71472 	  if (optimize_op_match(e1, OP_SAFE_C_SS))
71473 	    return(OP_SAFE_C_opSSq_opSq);
71474 	  break;
71475 
71476 	case OP_SAFE_C_SS:
71477 	  if (optimize_op_match(e1, OP_SAFE_C_SS))
71478 	    return(OP_SAFE_C_opSSq_opSSq);
71479 	  if (is_safe_c_s(e1))
71480 	    return(OP_SAFE_C_opSq_opSSq);
71481 	  break;
71482 	}
71483       return(OP_SAFE_C_PP);
71484 
71485     default:
71486       break;
71487     }
71488   return(OP_UNOPT);
71489 }
71490 
71491 static bool arg_findable(s7_scheme *sc, s7_pointer arg1, s7_pointer e)
71492 {
71493   if (pair_symbol_is_safe(sc, arg1, e)) return(true); /* includes global_slot check */
71494   return((!sc->in_with_let) &&
71495 	 (is_slot(lookup_slot_from(arg1, sc->curlet))));
71496 }
71497 
71498 static bool safe_c_aa_to_ag_ga(s7_scheme *sc, s7_pointer arg, int hop)
71499 {
71500   if (fx_proc(cddr(arg)) == fx_s) {set_opt3_sym(arg, caddr(arg));   set_safe_optimize_op(arg, hop + OP_SAFE_C_AS); return(true);}
71501   if (fx_proc(cdr(arg)) == fx_s)  {set_opt3_sym(arg, cadr(arg));    set_safe_optimize_op(arg, hop + OP_SAFE_C_SA); return(true);}
71502   if (fx_proc(cddr(arg)) == fx_c) {set_opt3_con(arg, caddr(arg));   set_safe_optimize_op(arg, hop + OP_SAFE_C_AC); return(true);}
71503   if (fx_proc(cdr(arg)) == fx_c)  {set_opt3_con(arg, cadr(arg));    set_safe_optimize_op(arg, hop + OP_SAFE_C_CA); return(true);}
71504   if (fx_proc(cddr(arg)) == fx_q) {set_opt3_con(arg, cadaddr(arg)); set_safe_optimize_op(arg, hop + OP_SAFE_C_AC); return(true);}
71505   if (fx_proc(cdr(arg)) == fx_q)  {set_opt3_con(arg, cadadr(arg));  set_safe_optimize_op(arg, hop + OP_SAFE_C_CA); return(true);}
71506   return(false);
71507 }
71508 
71509 static opt_t check_c_aa(s7_scheme *sc, s7_pointer expr, s7_pointer func, int32_t hop, s7_pointer e)
71510 {
71511   fx_annotate_args(sc, cdr(expr), e);
71512   if (!safe_c_aa_to_ag_ga(sc, expr, hop))
71513     {
71514       set_optimize_op(expr, hop + OP_SAFE_C_AA);
71515       set_opt3_arglen(cdr(expr), int_two);
71516     }
71517   choose_c_function(sc, expr, func, 2);
71518   return(OPT_T);
71519 }
71520 
71521 static opt_t wrap_bad_args(s7_scheme *sc, s7_pointer func, s7_pointer expr, int32_t n_args, int32_t hop, s7_pointer e)
71522 {
71523   set_opt3_arglen(cdr(expr), small_int(n_args));
71524   if (is_c_function(func))
71525     {
71526       set_safe_optimize_op(expr, hop + ((is_safe_procedure(func)) ?
71527 					((n_args == 1) ? OP_SAFE_C_A : OP_SAFE_C_AA) :
71528 					((n_args == 1) ? ((has_safe_args(func)) ? OP_CL_A : OP_C_A) : ((has_safe_args(func)) ? OP_CL_AA : OP_C_AA))));
71529       if (optimize_op(expr) == HOP_SAFE_C_AA)
71530 	return(check_c_aa(sc, expr, func, hop, e));
71531 
71532       set_c_function(expr, func);
71533       return(OPT_T);
71534     }
71535   if ((is_closure(func)) &&
71536       (!arglist_has_rest(sc, closure_args(func))))
71537     {
71538       s7_pointer body;
71539       bool one_form, safe_case;
71540 
71541       body = closure_body(func);
71542       one_form = is_null(cdr(body));
71543       safe_case = is_safe_closure(func);
71544       set_unsafely_optimized(expr);
71545       set_opt1_lambda_add(expr, func);
71546 
71547       if (one_form)
71548 	set_optimize_op(expr, hop + ((safe_case) ?
71549 				     ((n_args == 1) ? OP_SAFE_CLOSURE_A_O : OP_SAFE_CLOSURE_AA_O) :
71550 				     ((n_args == 1) ? OP_CLOSURE_A_O : OP_CLOSURE_AA_O)));
71551       else
71552 	set_optimize_op(expr, hop + ((safe_case) ?
71553 				     ((n_args == 1) ? OP_SAFE_CLOSURE_A : OP_SAFE_CLOSURE_AA) :
71554 				     ((n_args == 1) ? OP_CLOSURE_A : OP_CLOSURE_AA)));
71555       return(OPT_F);
71556     }
71557   if ((is_closure_star(func)) &&
71558       (lambda_has_simple_defaults(func)) &&
71559       (closure_star_arity_to_int(sc, func) >= n_args) &&
71560       (!arglist_has_rest(sc, closure_args(func))))
71561     {
71562       set_unsafely_optimized(expr);
71563       if (n_args == 1)
71564 	set_optimize_op(expr, ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_STAR_A : OP_CLOSURE_STAR_A));
71565       else
71566 	{
71567 	  if (closure_star_arity_to_int(sc, func) == 2)
71568 	    set_optimize_op(expr, ((is_safe_closure(func)) ? ((is_null(cdr(closure_body(func)))) ? OP_SAFE_CLOSURE_STAR_AA_O :
71569 							      OP_SAFE_CLOSURE_STAR_AA) : OP_CLOSURE_STAR_ALL_A));
71570 	  else set_optimize_op(expr, ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_STAR_ALL_A : OP_CLOSURE_STAR_ALL_A));
71571 	}
71572       set_opt1_lambda_add(expr, func);
71573     }
71574   return(OPT_F);
71575 }
71576 
71577 static inline s7_pointer find_uncomplicated_symbol(s7_scheme *sc, s7_pointer symbol, s7_pointer e)
71578 {
71579   s7_pointer x;
71580   int64_t id;
71581 
71582   if ((symbol_is_in_list(sc, symbol)) &&
71583       (direct_memq(symbol, e)))   /* it's probably a local variable reference */
71584     return(sc->nil);
71585   /* ((!symbol_is_in_list(sc, symbol)) && (direct_memq(symbol, e))) can happen if there's an intervening lambda:
71586    *   (let loop () (with-let (for-each (lambda (a) a) (list))) (loop))
71587    * misses 'loop (it's not in symbol_list when recursive call is encountered) -- tricky to fix
71588    */
71589 
71590   if (is_global(symbol))
71591     return(global_slot(symbol));
71592 
71593   /* see 59108 (OP_DEFINE_* in optimize_syntax) -- keyword version of name is used if a definition is
71594    *   contingent on some run-time decision, so we're looking here for local defines that might not happen.
71595    *   s7test.scm has a test case using acos.
71596    */
71597   if ((has_keyword(symbol)) &&
71598       (symbol_is_in_list(sc, symbol_to_keyword(sc, symbol))))
71599     return(sc->nil);
71600 
71601   id = symbol_id(symbol);
71602   for (x = sc->curlet; id < let_id(x); x = let_outlet(x));
71603   for (; is_let(x); x = let_outlet(x))
71604     {
71605       s7_pointer y;
71606       if (let_id(x) == id)
71607 	return(local_slot(symbol));
71608 
71609       for (y = let_slots(x); tis_slot(y); y = next_slot(y))
71610 	if (slot_symbol(y) == symbol)
71611 	  return(y);
71612     }
71613   return(global_slot(symbol)); /* it's no longer global perhaps (local definition now inaccessible) */
71614 }
71615 
71616 static bool is_ok_lambda(s7_scheme *sc, s7_pointer arg2)
71617 {
71618  return((is_pair(arg2)) &&
71619 	(is_lambda(sc, car(arg2))) &&
71620 	(is_pair(cdr(arg2))) &&
71621 	(is_pair(cddr(arg2))) &&
71622 	(s7_is_proper_list(sc, cddr(arg2))));
71623 }
71624 
71625 static opt_t optimize_c_function_one_arg(s7_scheme *sc, s7_pointer expr, s7_pointer func,
71626 					 int32_t hop, int32_t pairs, int32_t symbols, int32_t quotes, int32_t bad_pairs, s7_pointer e)
71627 {
71628   s7_pointer arg1;
71629   bool func_is_safe;
71630 
71631   arg1 = cadr(expr);
71632   func_is_safe = is_safe_procedure(func);
71633   if ((hop == 0) && (symbol_id(car(expr)) == 0) && (!sc->in_with_let)) hop = 1;
71634 
71635   if (pairs == 0)
71636     {
71637       if (func_is_safe)                  /* safe c function */
71638 	{
71639 	  set_safe_optimize_op(expr, hop + ((symbols == 0) ? OP_SAFE_C_D : OP_SAFE_C_S));
71640 	  choose_c_function(sc, expr, func, 1);
71641 	  return(OPT_T);
71642 	}
71643       /* c function is not safe */
71644       if (symbols == 0)
71645 	{
71646 	  set_unsafe_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_A : OP_C_A)); /* OP_C_C never happens */
71647 	  fx_annotate_arg(sc, cdr(expr), e);
71648 	  set_opt3_arglen(cdr(expr), int_one);
71649 	}
71650       else
71651 	{
71652 	  set_unsafely_optimized(expr);
71653 	  if (c_function_call(func) == g_read)
71654 	    set_optimize_op(expr, hop + OP_READ_S);
71655 	  else set_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_S : OP_C_S));
71656 	}
71657       choose_c_function(sc, expr, func, 1);
71658       return(OPT_F);
71659     }
71660   /* pairs == 1 */
71661   if (bad_pairs == 0)
71662     {
71663       if (func_is_safe)
71664 	{
71665 	  int32_t op;
71666 	  op = combine_ops(sc, func, expr, E_C_P, arg1, NULL);
71667 	  set_safe_optimize_op(expr, hop + op);
71668 	  if ((op == OP_SAFE_C_P) &&
71669 	      (is_fxable(sc, arg1)))
71670 	    {
71671 	      set_optimize_op(expr, hop + OP_SAFE_C_A);
71672 	      fx_annotate_arg(sc, cdr(expr), e);
71673 	    }
71674 	  choose_c_function(sc, expr, func, 1);
71675 	  return(OPT_T);
71676 	}
71677       if (is_fxable(sc, arg1))
71678 	{
71679 	  set_unsafe_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_A : OP_C_A));
71680 	  fx_annotate_arg(sc, cdr(expr), e);
71681 	  set_opt3_arglen(cdr(expr), int_one);
71682 	  choose_c_function(sc, expr, func, 1);
71683 	  return(OPT_F);
71684 	}}
71685   else /* bad_pairs == 1 */
71686     {
71687       if (quotes == 1)
71688 	{
71689 	  fx_annotate_arg(sc, cdr(expr), e);
71690 	  set_opt3_arglen(cdr(expr), int_one);
71691 	  if (func_is_safe)
71692 	    {
71693 	      set_safe_optimize_op(expr, hop + OP_SAFE_C_A);
71694 	      choose_c_function(sc, expr, func, 1);
71695 	      return(OPT_T);
71696 	    }
71697 	  set_unsafe_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_A : OP_C_A));
71698 	  choose_c_function(sc, expr, func, 1);
71699 	  return(OPT_F);
71700 	}
71701       /* quotes == 0 */
71702       if (!func_is_safe)
71703 	{
71704 	  s7_pointer lambda_expr;
71705 	  lambda_expr = arg1;
71706 	  if ((is_ok_lambda(sc, lambda_expr)) &&
71707 	      (!direct_memq(car(lambda_expr), e)))            /* (let ((lambda #f)) (call-with-exit (lambda ...))) */
71708 	    {
71709 	      if (((c_function_call(func) == g_call_with_exit) ||
71710 		   (c_function_call(func) == g_call_cc) ||
71711 		   (c_function_call(func) == g_call_with_output_string)) &&
71712 		  (is_proper_list_1(sc, cadr(lambda_expr))) &&
71713 		  (is_symbol(caadr(lambda_expr))) &&
71714 		  (!is_probably_constant(caadr(lambda_expr)))) /* (call-with-exit (lambda (pi) ...) */
71715 		{
71716 		  if (c_function_call(func) == g_call_cc)
71717 		    set_unsafe_optimize_op(expr, OP_CALL_CC);
71718 		  else
71719 		    {
71720 		      if (c_function_call(func) == g_call_with_exit)
71721 			{
71722 			  if (is_null(cdddr(lambda_expr)))
71723 			    set_unsafe_optimize_op(expr, hop + OP_CALL_WITH_EXIT_O);
71724 			  else set_unsafe_optimize_op(expr, hop + OP_CALL_WITH_EXIT);
71725 			}
71726 		      else
71727 			{
71728 			  set_unsafe_optimize_op(expr, OP_CALL_WITH_OUTPUT_STRING);
71729 			  set_opt2_pair(expr, cddr(lambda_expr));
71730 			  set_opt3_sym(expr, caadr(lambda_expr));
71731 			  set_local(caadr(lambda_expr));
71732 			  return(OPT_F);
71733 			}}
71734 		  choose_c_function(sc, expr, func, 1);
71735 		  set_opt2_pair(expr, cdr(lambda_expr));
71736 		  set_local(caadr(lambda_expr)); /* check_lambda_args normally handles this, but if hop==1, we'll skip that step */
71737 		  return(OPT_F);
71738 		}
71739 	      if ((c_function_call(func) == g_with_output_to_string) &&
71740 		  (is_null(cadr(lambda_expr))))
71741 		{
71742 		  set_unsafe_optimize_op(expr, OP_WITH_OUTPUT_TO_STRING);
71743 		  set_opt2_pair(expr, cddr(lambda_expr));
71744 		  return(OPT_F);
71745 		}}}}
71746   set_unsafe_optimize_op(expr, hop + ((func_is_safe) ? OP_SAFE_C_P : OP_C_P));
71747   choose_c_function(sc, expr, func, 1);
71748   return(OPT_F);
71749 }
71750 
71751 static bool walk_fxable(s7_scheme *sc, s7_pointer tree)
71752 {
71753   s7_pointer p;
71754   for (p = cdr(tree); is_pair(p); p = cdr(p))
71755     {
71756       s7_pointer q;
71757       q = car(p);
71758       if ((is_pair(q)) &&
71759 	  (is_optimized(q)))
71760 	{
71761 	  opcode_t op;
71762 	  op = optimize_op(q);
71763 	  if (is_safe_c_op(op)) return(true);
71764 	  if ((op >= OP_TC_AND_A_OR_A_LA) ||
71765 	      ((op >= OP_THUNK) && (op < OP_BEGIN)) ||
71766 	      (!walk_fxable(sc, q)))
71767 	    return(false);
71768 	}}
71769   return(true);
71770 }
71771 
71772 static bool is_safe_fxable(s7_scheme *sc, s7_pointer p)
71773 {
71774   if (!is_pair(p)) return(true);
71775   if (is_optimized(p))
71776     {
71777       if ((fx_function[optimize_op(p)]) &&
71778 	  (walk_fxable(sc, (p))))
71779 	return(true);
71780     }
71781   if (is_proper_quote(sc, p)) return(true);
71782 #if S7_DEBUGGING
71783   if ((is_optimized(p)) && (fx_function[optimize_op(p)]))
71784     fprintf(stderr, "omit %s: %s\n", op_names[optimize_op(p)], display(p));
71785 #endif
71786   return(false);
71787 }
71788 
71789 static bool check_tc_case(s7_scheme *sc, s7_pointer name, s7_pointer args, s7_pointer body)
71790 {
71791   /* opt1_any(clause) = key, has_tc(arg) = is tc call, opt2_any(clause) = result: has_tc(la arg) has_fx(val) or ((...)...) */
71792   s7_pointer clauses;
71793   s7_int len;
71794   bool got_else = false, results_fxable = true;
71795   for (clauses = cddr(body), len = 0; is_pair(clauses); clauses = cdr(clauses), len++)
71796     {
71797       s7_pointer clause, result;
71798       clause = car(clauses);
71799       if (is_proper_list_1(sc, car(clause)))
71800 	{
71801 	  if (!is_simple(caar(clause)))
71802 	    return(false); /* even if key is a small int, selector might be a mutable alias of that, so = will fail */
71803 	  set_opt1_any(clauses, caar(clause));
71804 	}
71805       else
71806 	{
71807 	  if ((car(clause) != sc->else_symbol) ||
71808 	      (!is_null(cdr(clauses))))
71809 	    return(false);
71810 	  got_else = true;
71811 	}
71812       set_opt2_any(clauses, NULL);
71813       result = cdr(clause);
71814       if (is_null(result))
71815 	return(false);
71816       if (is_proper_list_1(sc, result))
71817 	{
71818 	  if (is_fxable(sc, car(result)))
71819 	    {
71820 	      fx_annotate_arg(sc, result, args);
71821 	      set_opt2_any(clauses, result);
71822 	    }
71823 	  else
71824 	    {
71825 	      if ((is_proper_list_2(sc, car(result))) &&
71826 		  (caar(result) == name) &&
71827 		  (is_fxable(sc, cadar(result))))
71828 		{
71829 		  set_has_tc(car(result));
71830 		  set_opt2_any(clauses, car(result));
71831 		  fx_annotate_arg(sc, cdar(result), args);
71832 		}
71833 	      else results_fxable = false;
71834 	    }}
71835       else results_fxable = false;
71836       if (!opt2_any(clauses))
71837 	{
71838 	  if (car(result) == sc->feed_to_symbol)
71839 	    return(false);
71840 	  if (tree_count(sc, name, result, 0) != 0)
71841 	    return(false);
71842 	  set_opt2_any(clauses, result);
71843 	}}
71844   if ((!got_else) || (!is_null(clauses)))
71845     return(false);
71846   set_optimize_op(body, OP_TC_CASE_LA);
71847   set_opt3_arglen(cdr(body), small_int((len < 6) ? len : 0));
71848   fx_annotate_arg(sc, cdr(body), args);
71849   fx_tree(sc, cdr(body), car(args), NULL);
71850   if (results_fxable) set_optimized(body);
71851   return(results_fxable);
71852 }
71853 
71854 static bool check_tc_cond(s7_scheme *sc, s7_pointer name, int32_t vars, s7_pointer args, s7_pointer body)
71855 {
71856   s7_pointer p, clause1;
71857   p = cdr(body);
71858   clause1 = car(p);
71859   if ((is_proper_list_2(sc, clause1)) && (is_fxable(sc, car(clause1)))) /* cond_a... */
71860     {
71861       s7_pointer clause2;
71862       p = cdr(p);
71863       if ((is_pair(p)) && (is_null(cdr(p))) && ((caar(p) == sc->else_symbol) || (caar(p) == sc->T)))
71864 	{
71865 	  s7_pointer else_clause;
71866 	  if (((vars != 1) && (vars != 2)) || (tree_count(sc, name, body, 0) != 1)) return(false);
71867 	  else_clause = cdar(p);
71868 	  if (is_proper_list_1(sc, else_clause))
71869 	    {
71870 	      bool zs_fxable;
71871 	      s7_pointer la;
71872 	      la = car(else_clause);
71873 	      fx_annotate_arg(sc, clause1, args);
71874 	      if ((is_pair(la)) && (car(la) == name) && (is_pair(cdr(la))))
71875 		{
71876 		  if ((is_fxable(sc, cadr(la))) &&
71877 		      ((((vars == 1) && (is_null(cddr(la)))) ||
71878 			((vars == 2) && (is_pair(cddr(la))) && (is_null(cdddr(la))) && (is_fxable(sc, caddr(la)))))))
71879 		    {
71880 		      zs_fxable = is_fxable(sc, cadr(clause1));
71881 		      set_optimize_op(body, (vars == 1) ? OP_TC_COND_A_Z_LA : OP_TC_COND_A_Z_LAA);
71882 		      if (zs_fxable) fx_annotate_arg(sc, cdr(clause1), args);
71883 		      fx_annotate_args(sc, cdr(la), args);
71884 		      fx_tree(sc, cdr(body), car(args), (vars == 1) ? NULL : cadr(args));
71885 		      if (zs_fxable) set_optimized(body);
71886 		      set_opt1_pair(cdr(body), cdadr(body));
71887 		      set_opt3_pair(cdr(body), cdadr(caddr(body)));
71888 		      return(zs_fxable);
71889 		    }}
71890 	      else
71891 		{
71892 		  la = cadr(clause1);
71893 		  if ((is_pair(la)) && (car(la) == name) && (is_pair(cdr(la))))
71894 		    {
71895 		      if ((is_fxable(sc, cadr(la))) &&
71896 			  (((vars == 1) && (is_null(cddr(la)))) ||
71897 			   ((vars == 2) && (is_pair(cddr(la))) && (is_null(cdddr(la))) && (is_fxable(sc, caddr(la))))))
71898 			{
71899 			  zs_fxable = is_fxable(sc, car(else_clause));
71900 			  set_optimize_op(body, (vars == 1) ? OP_TC_COND_A_LA_Z : OP_TC_COND_A_LAA_Z);
71901 			  if (zs_fxable) fx_annotate_arg(sc, else_clause, args);
71902 			  fx_annotate_args(sc, cdr(la), args);
71903 			  fx_tree(sc, cdr(body), car(args), (vars == 1) ? NULL : cadr(args));
71904 			  if (zs_fxable) set_optimized(body);
71905 			  set_opt1_pair(cdr(body), cdaddr(body));
71906 			  set_opt3_pair(cdr(body), cdadr(cadr(body)));
71907 			  return(zs_fxable);
71908 			}}}}
71909 	  return(false);
71910 	}
71911       if (is_proper_list_2(sc, p))
71912 	{
71913 	  clause2 = car(p);
71914 	  if ((is_proper_list_2(sc, clause2)) &&
71915 	      (is_fxable(sc, car(clause2))))
71916 	    {
71917 	      s7_pointer else_clause, else_p;
71918 	      else_p = cdr(p);
71919 	      else_clause = car(else_p);
71920 
71921 	      if ((is_proper_list_2(sc, else_clause)) &&
71922 		  ((car(else_clause) == sc->else_symbol) || (car(else_clause) == sc->T)))
71923 		{
71924 		  bool zs_fxable = true;
71925 		  if ((vars == 2) && /* ...laa_laa case */
71926 		      (is_proper_list_3(sc, cadr(clause2))) && (caadr(clause2) == name) &&
71927 		      (is_fxable(sc, cadadr(clause2))) && (is_safe_fxable(sc, caddadr(clause2))) &&
71928 		      (is_proper_list_3(sc, cadr(else_clause))) && (caadr(else_clause) == name) &&
71929 		      (is_fxable(sc, cadadr(else_clause))) && (is_safe_fxable(sc, caddadr(else_clause))))
71930 		    {
71931 		      set_optimize_op(body, OP_TC_COND_A_Z_A_LAA_LAA);
71932 		      if (is_fxable(sc, cadr(clause1)))
71933 			fx_annotate_args(sc, clause1, args);
71934 		      else
71935 			{
71936 			  fx_annotate_arg(sc, clause1, args);
71937 			  zs_fxable = false;
71938 			}
71939 		      fx_annotate_arg(sc, clause2, args);
71940 		      fx_annotate_args(sc, cdadr(clause2), args);
71941 		      fx_annotate_args(sc, cdadr(else_clause), args);
71942 		      fx_tree(sc, cdr(body), car(args), cadr(args));
71943 		      set_opt3_pair(body, cadr(else_clause));
71944 		      if (zs_fxable) set_optimized(body);
71945 		      return(zs_fxable);
71946 		    }
71947 
71948 		  if ((tree_count(sc, name, body, 0) == 1) && /* needed to filter out cond_a_a_a_laa_opa_laa */
71949 
71950 		      (((is_pair(cadr(else_clause))) && (caadr(else_clause) == name) &&
71951 			(is_pair(cdadr(else_clause))) && (is_fxable(sc, cadadr(else_clause))) &&
71952 			(((vars == 1) && (is_null(cddadr(else_clause)))) ||
71953 			 ((vars == 2) && (is_proper_list_3(sc, cadr(else_clause))) && (is_fxable(sc, caddadr(else_clause)))))) ||
71954 
71955 		       ((is_pair(cadr(clause2))) && (caadr(clause2) == name) &&
71956 			(is_pair(cdadr(clause2))) && (is_fxable(sc, cadadr(clause2))) &&
71957 			(((vars == 1) && (is_null(cddadr(clause2)))) ||
71958 			 ((vars == 2) && (is_pair(cddadr(clause2))) && (is_fxable(sc, caddadr(clause2))) && (is_null(cdddr(cadr(clause2)))))))))
71959 		    {
71960 		      s7_pointer test2, la_test;
71961 		      test2 = clause2;
71962 		      la_test = else_clause;
71963 		      if (vars == 1)
71964 			{
71965 			  if ((is_pair(cadr(else_clause))) && (caadr(else_clause) == name))
71966 			    set_optimize_op(body, OP_TC_COND_A_Z_A_Z_LA);
71967 			  else
71968 			    {
71969 			      set_optimize_op(body, OP_TC_COND_A_Z_A_LA_Z);
71970 			      test2 = else_clause;
71971 			      la_test = clause2;
71972 			      fx_annotate_arg(sc, clause2, args);
71973 			    }}
71974 		      else
71975 			{
71976 			  if ((is_pair(cadr(else_clause))) && (caadr(else_clause) == name))
71977 			    {
71978 			      set_opt3_pair(body, cdadr(else_clause));
71979 			      set_optimize_op(body, OP_TC_COND_A_Z_A_Z_LAA);
71980 			    }
71981 			  else
71982 			    {
71983 			      set_optimize_op(body, OP_TC_COND_A_Z_A_LAA_Z);
71984 			      test2 = else_clause;
71985 			      la_test = clause2;
71986 			      set_opt3_pair(body, cdadr(la_test));
71987 			      fx_annotate_arg(sc, clause2, args);
71988 			    }}
71989 		      if (is_fxable(sc, cadr(clause1)))
71990 			fx_annotate_args(sc, clause1, args);
71991 		      else
71992 			{
71993 			  fx_annotate_arg(sc, clause1, args);
71994 			  zs_fxable = false;
71995 			}
71996 		      if (is_fxable(sc, cadr(test2)))
71997 			fx_annotate_args(sc, test2, args);
71998 		      else
71999 			{
72000 			  fx_annotate_arg(sc, test2, args);
72001 			  zs_fxable = false;
72002 			}
72003 		      fx_annotate_args(sc, cdadr(la_test), args);
72004 		      fx_tree(sc, cdr(body), car(args), (vars == 2) ? cadr(args) : NULL);
72005 		      if (zs_fxable) set_optimized(body);
72006 		      return(zs_fxable);
72007 		    }}}}}
72008   return(false);
72009 }
72010 
72011 static bool check_tc_let(s7_scheme *sc, s7_pointer name, int32_t vars, s7_pointer args, s7_pointer body)
72012 {
72013   s7_pointer let_body;
72014   let_body = caddr(body); /* body: (let ((x (- y 1))) (if (<= x 0) 0 (f1 (- x 1)))) etc */
72015   if (((vars == 2) && ((car(let_body) == sc->if_symbol) || (car(let_body) == sc->when_symbol) || (car(let_body) == sc->unless_symbol))) ||
72016       ((vars == 1) && (car(let_body) == sc->if_symbol)))
72017     {
72018       s7_pointer test_expr;
72019       test_expr = cadr(let_body);
72020       if (is_fxable(sc, test_expr))
72021 	{
72022 	  if ((car(let_body) == sc->if_symbol) && (is_pair(cdddr(let_body))))
72023 	    {
72024 	      s7_pointer laa;
72025 	      laa = cadddr(let_body);
72026 	      if ((is_pair(laa)) && /* else caddr is laa and cadddr is z */
72027 		  (car(laa) == name) &&
72028 		  (((vars == 1) && (is_proper_list_2(sc, laa))) ||
72029 		   ((vars == 2) && (is_proper_list_3(sc, laa)) && (is_safe_fxable(sc, caddr(laa))))) &&
72030 		  (is_fxable(sc, cadr(laa))))
72031 		{
72032 		  bool z_fxable;
72033 		  set_optimize_op(body, (vars == 1) ? OP_TC_LET_IF_A_Z_LA : OP_TC_LET_IF_A_Z_LAA);
72034 		  fx_annotate_arg(sc, cdaadr(body), args);  /* let var binding, caadr: (x (- y 1)) etc */
72035 		  fx_annotate_arg(sc, cdr(let_body), args); /* test_expr */
72036 		  fx_annotate_args(sc, cdr(laa), args);
72037 		  z_fxable = is_fxable(sc, caddr(let_body));
72038 		  if (z_fxable) fx_annotate_arg(sc, cddr(let_body), args);
72039 		  fx_tree(sc, cdaadr(body), car(args), (vars == 1) ? NULL : cadr(args)); /* these are references to laa args, applied to the let var binding */
72040 		  fx_tree(sc, cdr(let_body), car(caadr(body)), NULL);
72041 		  fx_tree_outer(sc, cdr(let_body), car(args), (vars == 1) ? NULL : cadr(args));
72042 		  if (z_fxable) set_optimized(body);
72043 		  return(z_fxable);
72044 		}}
72045 	  else
72046 	    {
72047 	      s7_pointer p;
72048 	      for (p = cddr(let_body); is_pair(cdr(p)); p = cdr(p))
72049 		if (!is_fxable(sc, car(p)))
72050 		  break;
72051 	      if ((is_proper_list_1(sc, p)) &&
72052 		  (is_proper_list_3(sc, car(p))) &&
72053 		  (caar(p) == name))
72054 		{
72055 		  s7_pointer laa;
72056 		  laa = car(p);
72057 		  if ((is_fxable(sc, cadr(laa))) &&
72058 		      (is_safe_fxable(sc, caddr(laa))))
72059 		    {
72060 		      set_optimize_op(body, (car(let_body) == sc->when_symbol) ? OP_TC_LET_WHEN_LAA : OP_TC_LET_UNLESS_LAA);
72061 		      fx_annotate_arg(sc, cdaadr(body), args);  /* outer var */
72062 		      fx_annotate_arg(sc, cdr(let_body), args); /* test */
72063 		      for (p = cddr(let_body); is_pair(cdr(p)); p = cdr(p))
72064 			fx_annotate_arg(sc, p, args);
72065 		      fx_annotate_args(sc, cdr(laa), args);
72066 		      fx_tree(sc, cdaadr(body), car(args), cadr(args)); /* these are references to the outer let */
72067 		      fx_tree(sc, cdr(let_body), car(caadr(body)), NULL);
72068 		      fx_tree_outer(sc, cdr(let_body), car(args), cadr(args));
72069 		      set_optimized(body);
72070 		      return(true);
72071 		    }}}}}
72072   else
72073     {
72074       if (car(let_body) == sc->cond_symbol)
72075 	{
72076 	  s7_pointer p, var_name;
72077 	  bool all_fxable = true;
72078 	  for (p = cdr(let_body); is_pair(p); p = cdr(p))
72079 	    {
72080 	      s7_pointer clause;
72081 	      clause = car(p);
72082 	      if ((is_proper_list_2(sc, clause)) &&
72083 		  (is_fxable(sc, car(clause)))) /* test is ok */
72084 		{
72085 		  s7_pointer result;
72086 
72087 		  if ((!is_pair(cdr(p))) &&
72088 		      (car(clause) != sc->else_symbol) && (car(clause) != sc->T))
72089 		    return(false);
72090 
72091 		  result = cadr(clause);
72092 		  if ((is_pair(result)) &&
72093 		      (car(result) == name))    /* result is recursive call */
72094 		    {
72095 		      s7_pointer arg;
72096 		      s7_int i;
72097 		      for (i = 0, arg = cdr(result); is_pair(arg); i++, arg = cdr(arg))
72098 			if (!is_fxable(sc, car(arg)))
72099 			  return(false);
72100 		      if (i != vars)
72101 			return(false);
72102 		    }}
72103 	      else return(false);
72104 	    }
72105 	  /* cond form looks ok */
72106 	  set_optimize_op(body, OP_TC_LET_COND);
72107 	  set_opt3_arglen(cdr(body), small_int(vars));
72108 	  fx_annotate_arg(sc, cdaadr(body), args);   /* let var */
72109 	  if (vars > 0)
72110 	    fx_tree(sc, cdaadr(body), car(args), (vars > 1) ? cadr(args) : NULL);
72111 	  var_name = caaadr(body);
72112 	  for (p = cdr(let_body); is_pair(p); p = cdr(p))
72113 	    {
72114 	      s7_pointer clause, result;
72115 	      clause = car(p);
72116 	      result = cadr(clause);
72117 	      fx_annotate_arg(sc, clause, args);
72118 	      if ((is_pair(result)) && (car(result) == name))
72119 		{
72120 		  set_has_tc(cdr(clause));
72121 		  fx_annotate_args(sc, cdr(result), args);
72122 		}
72123 	      else
72124 		{
72125 		  if (is_fxable(sc, result))
72126 		    fx_annotate_arg(sc, cdr(clause), args);
72127 		  else all_fxable = false;
72128 		}
72129 	      fx_tree(sc, clause, var_name, NULL);
72130 	      if (vars > 0)
72131 		{
72132 		  fx_tree_outer(sc, clause, car(args), (vars > 1) ? cadr(args) : NULL);
72133 		  if ((vars > 2) && (has_tc(cdr(clause))))
72134 		    {
72135 		      s7_pointer q;
72136 		      for (q = cdr(result); is_pair(q); q = cdr(q))
72137 			if ((is_pair(car(q))) && (fx_proc(q) == fx_add_s1) && (cadar(q) == caddr(args)))
72138 			  set_fx_direct(q, fx_add_V1);
72139 		    }}}
72140 	  if (all_fxable) set_optimized(body);
72141 	  return(all_fxable);
72142 	}}
72143   return(false);
72144 }
72145 
72146 /* tc lets can be let* or let+vars that don't refer to previous names, and there are more cond/if choices */
72147 
72148 static bool check_tc(s7_scheme *sc, s7_pointer name, int32_t vars, s7_pointer args, s7_pointer body)
72149 {
72150   if (!is_pair(body)) return(false);
72151 
72152   if (((vars == 1) || (vars == 2)) &&
72153       ((car(body) == sc->and_symbol) || (car(body) == sc->or_symbol)) &&
72154       (is_pair(cdr(body))) &&
72155       (is_fxable(sc, cadr(body))) &&
72156       (is_pair(cddr(body))))
72157     {
72158       s7_pointer orx;
72159       orx = caddr(body);
72160       if (((car(orx) == sc->or_symbol) || (car(orx) == sc->and_symbol)) &&
72161 	  (car(body) != car(orx)) &&
72162 	  (is_fxable(sc, cadr(orx))))
72163 	{
72164 	  s7_int len;
72165 	  len = proper_list_length(orx);
72166 	  if ((len == 3) || ((vars == 1) && (len == 4) && (tree_count(sc, name, orx, 0) == 1)))
72167 	    {
72168 	      s7_pointer tc;
72169 	      tc = (len == 3) ? caddr(orx) : cadddr(orx);
72170 	      if ((is_pair(tc)) &&
72171 		  (car(tc) == name) &&
72172 		  (is_pair(cdr(tc))) &&
72173 		  (is_fxable(sc, cadr(tc))) &&
72174 		  (((vars == 1) && (is_null(cddr(tc)))) ||
72175 		   ((vars == 2) && (is_pair(cddr(tc))) && (is_null(cdddr(tc))) && (is_safe_fxable(sc, caddr(tc))))))
72176 		{
72177 		  if (vars == 1)
72178 		    set_safe_optimize_op(body, (car(body) == sc->and_symbol) ?
72179 					 ((len == 3) ? OP_TC_AND_A_OR_A_LA : OP_TC_AND_A_OR_A_A_LA) :
72180 					 ((len == 3) ? OP_TC_OR_A_AND_A_LA : OP_TC_OR_A_AND_A_A_LA));
72181 		  else set_safe_optimize_op(body, (car(body) == sc->and_symbol) ? OP_TC_AND_A_OR_A_LAA : OP_TC_OR_A_AND_A_LAA);
72182 		  fx_annotate_arg(sc, cdr(body), args);
72183 		  fx_annotate_arg(sc, cdr(orx), args);
72184 		  if (len == 4) fx_annotate_arg(sc, cddr(orx), args);
72185 		  fx_annotate_args(sc, cdr(tc), args);
72186 		  /* if ((fx_proc(cdr(tc)) == fx_c_sca) && (fn_proc(cadr(tc)) == g_substring)) -> g_substring_uncopied); */
72187 		  /*   for that to be safe we need to be sure nothing in the body looks for null-termination (e.g.. string->number) */
72188 		  fx_tree(sc, cdr(body), car(args), (vars == 1) ? NULL : cadr(args));
72189 		  return(true);
72190 		}}}
72191       else
72192 	{
72193 	  if ((vars == 1) &&
72194 	      (car(body) == sc->or_symbol) &&
72195 	      (is_fxable(sc, orx)) &&
72196 	      (is_pair(cdddr(body))) &&
72197 	      (is_pair(cadddr(body))))
72198 	    {
72199 	      s7_pointer and_p;
72200 	      and_p = cadddr(body);
72201 	      if ((is_proper_list_4(sc, and_p)) &&
72202 		  (car(and_p) == sc->and_symbol) &&
72203 		  (is_fxable(sc, cadr(and_p))) &&
72204 		  (is_fxable(sc, caddr(and_p))))
72205 		{
72206 		  s7_pointer la;
72207 		  la = cadddr(and_p);
72208 		  if ((is_proper_list_2(sc, la)) &&
72209 		      (car(la) == name) &&
72210 		      (is_fxable(sc, cadr(la))))
72211 		    {
72212 		      set_safe_optimize_op(body, OP_TC_OR_A_A_AND_A_A_LA);
72213 		      fx_annotate_arg(sc, cdr(body), args);
72214 		      fx_annotate_arg(sc, cddr(body), args);
72215 		      fx_annotate_arg(sc, cdr(and_p), args);
72216 		      fx_annotate_arg(sc, cddr(and_p), args);
72217 		      fx_annotate_args(sc, cdr(la), args);
72218 		      fx_tree(sc, cdr(body), car(args), NULL);
72219 		      return(true);
72220 		    }}}
72221 	  else
72222  	    {
72223  	      if ((vars == 1) && (car(body) == sc->and_symbol) && (car(orx) == sc->if_symbol) &&
72224  		  (is_proper_list_4(sc, orx)) && (is_fxable(sc, cadr(orx))) && (tree_count(sc, name, orx, 0) == 1))
72225  		{
72226  		  s7_pointer la;
72227 		  bool z_first;
72228 		  z_first = ((is_pair(cadddr(orx))) && (car(cadddr(orx)) == name));
72229  		  la = (z_first) ? cadddr(orx) : caddr(orx);
72230  		  if ((car(la) == name) && (is_proper_list_2(sc, la)) && (is_fxable(sc, cadr(la))))
72231  		    {
72232 		      bool z_fxable = true;
72233 		      s7_pointer z;
72234 		      z = (z_first) ? cddr(orx) : cdddr(orx);
72235  		      set_optimize_op(body, (z_first) ? OP_TC_AND_A_IF_A_Z_LA : OP_TC_AND_A_IF_A_LA_Z);
72236  		      fx_annotate_arg(sc, cdr(body), args);
72237  		      fx_annotate_arg(sc, cdr(orx), args);
72238  		      fx_annotate_arg(sc, cdr(la), args);
72239  		      if (is_fxable(sc, car(z))) fx_annotate_arg(sc, z, args); else z_fxable = false;
72240  		      fx_tree(sc, cdr(body), car(args), NULL);
72241 		      if (z_fxable) set_optimized(body);
72242  		      return(z_fxable);
72243 		    }}}}}
72244 
72245   if ((vars == 3) &&
72246       (((car(body) == sc->or_symbol) && (is_proper_list_2(sc, cdr(body)))) ||
72247        ((car(body) == sc->if_symbol) && (is_proper_list_3(sc, cdr(body))) && (caddr(body) == sc->T))) &&
72248       (is_fxable(sc, cadr(body))))
72249     {
72250       s7_pointer and_p;
72251       and_p = (car(body) == sc->or_symbol) ? caddr(body) : cadddr(body);
72252       if ((is_proper_list_4(sc, and_p)) &&
72253 	  (car(and_p) == sc->and_symbol) &&
72254 	  (is_fxable(sc, cadr(and_p))) &&
72255 	  (is_fxable(sc, caddr(and_p))))
72256 	{
72257 	  s7_pointer la;
72258 	  la = cadddr(and_p);
72259 	  if ((is_proper_list_4(sc, la)) &&
72260 	      (car(la) == name) &&
72261 	      (is_fxable(sc, cadr(la))) &&
72262 	      (is_safe_fxable(sc, caddr(la))) &&
72263 	      (is_safe_fxable(sc, cadddr(la))))
72264 	    {
72265 	      set_safe_optimize_op(body, OP_TC_OR_A_AND_A_A_L3A);
72266 	      set_opt3_pair(cdr(body), (car(body) == sc->or_symbol) ? cdaddr(body) : cdr(cadddr(body)));
72267 	      fx_annotate_arg(sc, cdr(body), args);
72268 	      fx_annotate_arg(sc, cdr(and_p), args);
72269 	      fx_annotate_arg(sc, cddr(and_p), args);
72270 	      fx_annotate_args(sc, cdr(la), args);
72271 	      fx_tree(sc, cdr(body), car(args), cadr(args));
72272 	      return(true);
72273 	    }}}
72274 
72275   if (((vars >= 1) && (vars <= 3)) &&
72276       (car(body) == sc->if_symbol) &&
72277       (proper_list_length(body) == 4))
72278     {
72279       s7_pointer test;
72280       test = cadr(body);
72281       if (is_fxable(sc, test))
72282 	{
72283 	  s7_pointer true_p, false_p;
72284 	  s7_int false_len, true_len;
72285 
72286 	  true_p = caddr(body);
72287 	  true_len = proper_list_length(true_p);
72288 	  false_p = cadddr(body);
72289 	  false_len = proper_list_length(false_p);
72290 	  fx_annotate_arg(sc, cdr(body), args);
72291 
72292 	  if (vars == 1)
72293 	    {
72294 	      if ((false_len == 2) &&
72295 		  (car(false_p) == name) &&
72296 		  (is_fxable(sc, cadr(false_p))))
72297 		{
72298 		  set_optimize_op(body, OP_TC_IF_A_Z_LA);
72299 		  fx_annotate_arg(sc, cdr(false_p), args);  /* arg */
72300 		  set_opt1_pair(cdr(body), cddr(body));
72301 		  set_opt3_pair(cdr(body), cdar(cdddr(body)));
72302 		  if (!is_fxable(sc, true_p)) return(false);
72303 		  fx_annotate_arg(sc, cddr(body), args);    /* result */
72304 		  fx_tree(sc, cdr(body), car(args), NULL);
72305 		  set_optimized(body);
72306 		  return(true);
72307 		}
72308 	      if ((true_len == 2) &&
72309 		  (car(true_p) == name) &&
72310 		  (is_fxable(sc, cadr(true_p))))
72311 		{
72312 		  set_optimize_op(body, OP_TC_IF_A_LA_Z);
72313 		  fx_annotate_arg(sc, cdr(true_p), args);   /* arg */
72314 		  set_opt1_pair(cdr(body), cdddr(body));
72315 		  set_opt3_pair(cdr(body), cdar(cddr(body)));
72316 		  if (!is_fxable(sc, false_p)) return(false);
72317 		  fx_annotate_arg(sc, cdddr(body), args);    /* result */
72318 		  fx_tree(sc, cdr(body), car(args), NULL);
72319 		  set_optimized(body);
72320 		  return(true);
72321 		}}
72322 
72323 	  if (vars == 2)
72324 	    {
72325 	      if ((false_len == 3) &&
72326 		  (car(false_p) == name) &&
72327 		  (is_fxable(sc, cadr(false_p))) &&
72328 		  (is_safe_fxable(sc, caddr(false_p))))
72329 		{
72330 		  set_optimize_op(body, OP_TC_IF_A_Z_LAA);
72331 		  fx_annotate_args(sc, cdr(false_p), args);
72332 		  set_opt1_pair(cdr(body), cddr(body)); /* body == code in op, if_z */
72333 		  set_opt3_pair(cdr(body), cdar(cdddr(body))); /* la */
72334 		  if (!is_fxable(sc, true_p)) return(false);
72335 		  fx_annotate_arg(sc, cddr(body), args);
72336 		  fx_tree(sc, cdr(body), car(args), cadr(args));
72337 		  set_optimized(body);
72338 		  return(true);
72339 		}
72340 	      if ((true_len == 3) &&
72341 		  (car(true_p) == name) &&
72342 		  (is_fxable(sc, cadr(true_p))) &&
72343 		  (is_safe_fxable(sc, caddr(true_p))))
72344 		{
72345 		  set_optimize_op(body, OP_TC_IF_A_LAA_Z);
72346 		  fx_annotate_args(sc, cdr(true_p), args);
72347 		  set_opt1_pair(cdr(body), cdddr(body));
72348 		  set_opt3_pair(cdr(body), cdar(cddr(body)));
72349 		  if (!is_fxable(sc, false_p)) return(false);
72350 		  fx_annotate_arg(sc, cdddr(body), args);
72351 		  fx_tree(sc, cdr(body), car(args), cadr(args));
72352 		  set_optimized(body);
72353 		  return(true);
72354 		}}
72355 
72356 	  if (vars == 3)
72357 	    {
72358 	      if ((false_len == 4) &&
72359 		  (car(false_p) == name) &&
72360 		  (is_fxable(sc, cadr(false_p))) && (is_safe_fxable(sc, caddr(false_p))) && (is_safe_fxable(sc, cadddr(false_p))))
72361 		{
72362 		  set_optimize_op(body, OP_TC_IF_A_Z_L3A);
72363 		  fx_annotate_args(sc, cdr(false_p), args);
72364 		  set_opt1_pair(cdr(body), cddr(body));
72365 		  set_opt3_pair(cdr(body), cdar(cdddr(body)));
72366 		  if (!is_fxable(sc, true_p)) return(false);
72367 		  fx_annotate_arg(sc, cddr(body), args);
72368 		  fx_tree(sc, cdr(body), car(args), cadr(args));
72369 		  set_optimized(body);
72370 		  return(true);
72371 		}
72372 	      if ((true_len == 4) &&
72373 		  (car(true_p) == name) &&
72374 		  (is_fxable(sc, cadr(true_p))) && (is_safe_fxable(sc, caddr(true_p))) && (is_safe_fxable(sc, cadddr(true_p))))
72375 		{
72376 		  set_optimize_op(body, OP_TC_IF_A_L3A_Z);
72377 		  fx_annotate_args(sc, cdr(true_p), args);
72378 		  set_opt1_pair(cdr(body), cdddr(body));
72379 		  set_opt3_pair(cdr(body), cdar(cddr(body)));
72380 		  if (!is_fxable(sc, false_p)) return(false);
72381 		  fx_annotate_arg(sc, cdddr(body), args);
72382 		  fx_tree(sc, cdr(body), car(args), cadr(args));
72383 		  set_optimized(body);
72384 		  return(true);
72385 		}}
72386 
72387  	  if ((false_len == 4) &&
72388  	      (car(false_p) == sc->if_symbol))
72389  	    {
72390  	      s7_pointer in_test, in_true, in_false;
72391  	      in_test = cadr(false_p);
72392  	      in_true = caddr(false_p);
72393  	      in_false = cadddr(false_p);
72394 
72395  	      if (is_fxable(sc, in_test))
72396 		{
72397 		  s7_pointer la = NULL, z;
72398 		  if ((is_pair(in_false)) &&
72399 		      (car(in_false) == name) &&
72400 		      (is_pair(cdr(in_false))) &&
72401 		      (is_fxable(sc, cadr(in_false))))
72402 		    {
72403 		      la = in_false;
72404 		      z = cddr(false_p);
72405 		    }
72406 		  else
72407 		    if ((is_pair(in_true)) &&
72408 			(car(in_true) == name) &&
72409 			(is_pair(cdr(in_true))) &&
72410 			(is_fxable(sc, cadr(in_true))))
72411 		      {
72412 			la = in_true;
72413 			z = cdddr(false_p);
72414 		      }
72415 		  if ((la) && ((vars == 3) || (!s7_tree_memq(sc, name, car(z)))))
72416 		    {
72417 		      if (((vars == 1) && (is_null(cddr(la)))) ||
72418 			  ((vars == 2) && (is_pair(cddr(la))) && (is_null(cdddr(la))) && (is_safe_fxable(sc, caddr(la)))) ||
72419 			  ((vars == 3) && (is_proper_list_4(sc, in_true)) && (car(in_true) == name) &&
72420 			   (is_proper_list_4(sc, in_false)) && (is_safe_fxable(sc, caddr(la))) && (is_safe_fxable(sc, cadddr(la))) &&
72421 			   (is_fxable(sc, cadr(in_true))) && (is_safe_fxable(sc, caddr(in_true))) && (is_safe_fxable(sc, cadddr(in_true)))))
72422 			{
72423 			  bool zs_fxable = true;
72424 			  if (vars == 1)
72425 			    set_optimize_op(body, (la == in_false) ? OP_TC_IF_A_Z_IF_A_Z_LA : OP_TC_IF_A_Z_IF_A_LA_Z);
72426 			  else
72427 			    {
72428 			      if (vars == 2)
72429 				set_optimize_op(body, (la == in_false) ? OP_TC_IF_A_Z_IF_A_Z_LAA : OP_TC_IF_A_Z_IF_A_LAA_Z);
72430 			      else set_optimize_op(body, OP_TC_IF_A_Z_IF_A_L3A_L3A);
72431 			    }
72432 			  if (is_fxable(sc, true_p))             /* outer (z) result */
72433 			    fx_annotate_arg(sc, cddr(body), args);
72434 			  else zs_fxable = false;
72435 			  fx_annotate_arg(sc, cdr(false_p), args);  /* inner test */
72436 			  fx_annotate_args(sc, cdr(la), args);      /* la arg(s) */
72437 			  if (vars == 3)
72438 			    fx_annotate_args(sc, cdr(in_true), args);
72439 			  else
72440 			    {
72441 			      if (is_fxable(sc, car(z)))
72442 				fx_annotate_arg(sc, z, args);       /* inner (z) result */
72443 			      else zs_fxable = false;
72444 			    }
72445 			  if ((has_fx(cddr(body))) && (has_fx(z)))
72446 			    fx_tree(sc, cdr(body), car(args), (vars == 1) ? NULL : cadr(args));
72447 			  if (zs_fxable) set_optimized(body);
72448 			  return(zs_fxable);
72449 			}}}}
72450 
72451 	  if ((vars == 2) &&
72452 	      (false_len == 3) &&
72453 	      (car(false_p) == sc->let_star_symbol))
72454 	    {
72455 	      s7_pointer letv, letb, v;
72456 
72457 	      letv = cadr(false_p);
72458 	      if (!is_pair(letv)) return(false);
72459 	      letb = caddr(false_p);
72460 	      for (v = letv; is_pair(v); v = cdr(v))
72461 		if (!is_fxable(sc, cadar(v)))
72462 		  return(false);
72463 	      if ((is_proper_list_4(sc, letb)) &&
72464 		  (car(letb) == sc->if_symbol) &&
72465 		  (is_fxable(sc, cadr(letb))))
72466 		{
72467 		  s7_pointer laa;
72468 
72469 		  laa = cadddr(letb);
72470 		  if ((car(laa) == name) &&
72471 		      (is_proper_list_3(sc, laa)) &&
72472 		      (is_fxable(sc, cadr(laa))) &&
72473 		      (is_safe_fxable(sc, caddr(laa))))
72474 		    {
72475 		      bool zs_fxable;
72476 		      set_safe_optimize_op(body, OP_TC_IF_A_Z_LET_IF_A_Z_LAA);
72477 		      fx_annotate_args(sc, cdr(laa), args);
72478 		      zs_fxable = is_fxable(sc, caddr(letb));
72479 		      fx_annotate_args(sc, cdr(letb), args);
72480 		      for (v = letv; is_pair(v); v = cdr(v))
72481 			fx_annotate_arg(sc, cdar(v), args);
72482 		      fx_tree(sc, cdar(letv), car(args), cadr(args)); /* first var of let* */
72483 		      fx_tree(sc, cdr(body), car(args), cadr(args));  /* these are references to the outer let */
72484 		      fx_tree(sc, cdr(laa), caar(letv), (is_pair(cdr(letv))) ? caadr(letv) : NULL);
72485 		      fx_tree(sc, cdr(letb), caar(letv), (is_pair(cdr(letv))) ? caadr(letv) : NULL);
72486 		      fx_tree_outer(sc, cddr(letb), car(args), cadr(args));
72487 		      if (!is_fxable(sc, caddr(body)))
72488 			return(false);
72489 		      fx_annotate_arg(sc, cddr(body), args);
72490 		      return(zs_fxable);
72491 		    }}}}}
72492 
72493   /* let */
72494   if ((is_proper_list_3(sc, body)) &&
72495       (car(body) == sc->let_symbol) &&
72496       (is_proper_list_1(sc, cadr(body))) &&
72497       (is_fxable(sc, cadr(caadr(body)))) && /* let one var is fxable */
72498       (is_pair(caddr(body))))
72499     return(check_tc_let(sc, name, vars, args, body));
72500 
72501   /* cond */
72502   if ((car(body) == sc->cond_symbol) &&
72503       (vars <= 2))
72504     return(check_tc_cond(sc, name, vars, args, body));
72505 
72506   /* case */
72507   if ((vars == 1) &&
72508       (car(body) == sc->case_symbol) &&
72509       (is_pair(cdr(body))) &&
72510       (is_fxable(sc, cadr(body))))
72511     return(check_tc_case(sc, name, args, body));
72512 
72513   return(false);
72514 }
72515 
72516 static bool check_recur_if(s7_scheme *sc, s7_pointer name, int32_t vars, s7_pointer args, s7_pointer body)
72517 {
72518   s7_pointer test;
72519   test = cadr(body);
72520   if (is_fxable(sc, test))        /* if_(A)... */
72521     {
72522       s7_pointer true_p, false_p, obody, orig = NULL;
72523       obody = cddr(body);
72524       true_p = car(obody);        /* if_a_(A)... */
72525       false_p = cadr(obody);      /* if_a_a_(if...) */
72526 
72527       if ((vars <= 2) &&
72528 	  (is_fxable(sc, true_p)) &&
72529 	  (is_proper_list_4(sc, false_p)))
72530 	{
72531 	  if (car(false_p) == sc->if_symbol)
72532 	    {
72533 	      s7_pointer test2, true2, false2;
72534 	      test2 = cadr(false_p);
72535 	      true2 = caddr(false_p);
72536 	      false2 = cadddr(false_p);
72537 	      if ((is_fxable(sc, test2)) &&
72538 		  (is_proper_list_3(sc, false2)) &&  /* opa_laaq or oplaa_laaq */
72539 		  (is_h_optimized(false2)))          /* the c-op */
72540 		{
72541 		  s7_pointer la1, la2;
72542 		  la1 = cadr(false2);
72543 		  la2 = caddr(false2);
72544 		  if ((is_fxable(sc, true2)) &&
72545 		      (((vars == 1) && (is_proper_list_2(sc, la1)) && (is_proper_list_2(sc, la2))) ||
72546 		       (((vars == 2) && (is_proper_list_3(sc, la1)) && (is_proper_list_3(sc, la2))))) &&
72547 		      (car(la1) == name) &&  	     (car(la2) == name) &&
72548 		      (is_fxable(sc, cadr(la1))) &&  (is_fxable(sc, cadr(la2))) &&
72549 		      ((vars == 1) || ((is_fxable(sc, caddr(la1))) && (is_fxable(sc, caddr(la2))))))
72550 		    {
72551 		      set_safe_optimize_op(body, (vars == 1) ? OP_RECUR_IF_A_A_IF_A_A_opLA_LAq : OP_RECUR_IF_A_A_IF_A_A_opLAA_LAAq);
72552 		      fx_annotate_arg(sc, cdr(body), args);
72553 		      fx_annotate_arg(sc, obody, args);
72554 		      fx_annotate_args(sc, cdr(false_p), args);
72555 		      fx_annotate_args(sc, cdr(la1), args);
72556 		      fx_annotate_args(sc, cdr(la2), args);
72557 		      fx_tree(sc, cdr(body), car(args), (vars == 2) ? cadr(args) : NULL);
72558 		      set_opt1_pair(body, cdr(false_p));
72559 		      set_opt3_pair(body, false2);
72560 		      set_opt3_pair(false2, cdr(la2));
72561 		      return(true);
72562 		    }
72563 		  if ((vars == 2) && (is_proper_list_3(sc, true2)) &&
72564 		      (car(true2) == name) &&
72565 		      (is_fxable(sc, cadr(true2))) && (is_fxable(sc, caddr(true2))) &&
72566 		      (is_fxable(sc, cadr(false2))) &&
72567 		      (is_proper_list_3(sc, la2)) &&
72568 		      (car(la2) == name) &&          /* actually, not needed because func is TC (not RECUR) if not == name */
72569 		      (is_fxable(sc, cadr(la2))) &&
72570 		      (is_fxable(sc, caddr(la2))))
72571 		    {
72572 		      set_safe_optimize_op(body, OP_RECUR_IF_A_A_IF_A_LAA_opA_LAAq);
72573 		      fx_annotate_arg(sc, cdr(body), args);       /* if_(A)... */
72574 		      fx_annotate_arg(sc, obody, args);           /* if_a_(A)... */
72575 		      fx_annotate_arg(sc, cdr(false_p), args);    /* if_a_a_if_(A)... */
72576 		      fx_annotate_args(sc, cdr(true2), args);     /* if_a_a_if_a_l(AA)... */
72577 		      fx_annotate_arg(sc, cdr(false2), args);     /* if_a_a_if_a_laa_op(A).. */
72578 		      fx_annotate_args(sc, cdr(la2), args);       /* if_a_a_if_a_laa_opa_l(AA)q */
72579 		      fx_tree(sc, cdr(body), car(args), cadr(args));
72580 		      set_opt3_pair(body, false2);
72581 		      set_opt3_pair(false2, la2);
72582 		      return(true);
72583 		    }}}
72584 
72585 	  if (car(false_p) == sc->and_symbol)
72586 	    {
72587 	      s7_pointer a1, a2, a3;
72588 	      a1 = cadr(false_p);
72589 	      a2 = caddr(false_p);
72590 	      a3 = cadddr(false_p);
72591 	      if ((is_fxable(sc, a1)) &&
72592 		  (is_proper_list_3(sc, a2)) && (is_proper_list_3(sc, a3)) &&
72593 		  (car(a2) == name) && (car(a3) == name) &&
72594 		  (is_fxable(sc, cadr(a2))) && (is_fxable(sc, cadr(a3))) &&
72595 		  (is_fxable(sc, caddr(a2))) && (is_fxable(sc, caddr(a3))))
72596 		{
72597 		  set_safe_optimize_op(body, OP_RECUR_IF_A_A_AND_A_LAA_LAA);
72598 		  fx_annotate_arg(sc, cdr(body), args);       /* if_(A)... */
72599 		  fx_annotate_arg(sc, cddr(body), args);      /* if_a_(A)... */
72600 		  fx_annotate_arg(sc, cdr(false_p), args);    /* if_a_a_and_(A)... */
72601 		  fx_annotate_args(sc, cdr(a2), args);        /* if_a_a_and_a_l(AA)... */
72602 		  fx_annotate_args(sc, cdr(a3), args);        /* if_a_a_and_a_laa_l(AA) */
72603 		  fx_tree(sc, cdr(body), car(args), cadr(args));
72604 		  set_opt3_pair(body, false_p);
72605 		  return(true);
72606 		}}}
72607 
72608       if ((is_fxable(sc, true_p)) &&
72609 	  (is_pair(false_p)) &&
72610 	  (is_h_optimized(false_p)) &&
72611 	  (is_pair(cdr(false_p))) &&
72612 	  (is_pair(cddr(false_p))))
72613 	orig = false_p;
72614       else
72615 	if ((is_fxable(sc, false_p)) &&
72616 	    (is_pair(true_p)) &&
72617 	    (is_h_optimized(true_p)) &&
72618 	    (is_pair(cdr(true_p))) &&
72619 	    (is_pair(cddr(true_p))))
72620 	  {
72621 	    orig = true_p;
72622 	    /* true_p = false_p; */
72623 	    false_p = orig;
72624 	    obody = cdr(obody);
72625 	  }
72626 
72627       if (orig)
72628 	{
72629 	  if (is_null(cdddr(false_p))) /* 2 args to outer (c) func */
72630 	    {
72631 	      if ((is_fxable(sc, cadr(false_p))) || (is_fxable(sc, caddr(false_p))))
72632 		{
72633 		  s7_pointer la;
72634 		  la = (is_fxable(sc, cadr(false_p))) ? caddr(false_p) : cadr(false_p);
72635 		  if ((is_pair(la)) &&
72636 		      (car(la) == name) &&
72637 		      (is_pair(cdr(la))) &&
72638 		      (is_fxable(sc, cadr(la))))
72639 		    {
72640 		      if ((vars == 1) && (is_null(cddr(la))))
72641 			set_safe_optimize_op(body, (orig == cadddr(body)) ?
72642 					     ((la == cadr(false_p)) ? OP_RECUR_IF_A_A_opLA_Aq : OP_RECUR_IF_A_A_opA_LAq) :
72643 					     ((la == cadr(false_p)) ? OP_RECUR_IF_A_opLA_Aq_A : OP_RECUR_IF_A_opA_LAq_A));
72644 		      else
72645 			{
72646 			  if ((vars == 2) &&
72647 			      (is_pair(cddr(la))) && (is_fxable(sc, caddr(la))) &&
72648 			      (is_null(cdddr(la))))
72649 			    set_safe_optimize_op(body, (orig == cadddr(body)) ? OP_RECUR_IF_A_A_opA_LAAq : OP_RECUR_IF_A_opA_LAAq_A);
72650 			  else
72651 			    {
72652 			      if ((vars == 3) &&
72653 				  (is_pair(cddr(la))) && (is_fxable(sc, caddr(la))) &&
72654 				  (is_pair(cdddr(la))) && (is_fxable(sc, cadddr(la))) &&
72655 				  (is_null(cddddr(la))) &&
72656 				  (orig == cadddr(body)))
72657 				set_safe_optimize_op(body, OP_RECUR_IF_A_A_opA_L3Aq);
72658 			      else return(false);
72659 			    }}
72660 		      fx_annotate_arg(sc, cdr(body), args);
72661 		      fx_annotate_arg(sc, obody, args);
72662 		      fx_annotate_arg(sc, (la == cadr(false_p)) ? cddr(false_p) : cdr(false_p), args);
72663 		      fx_annotate_args(sc, cdr(la), args);
72664 		      fx_tree(sc, cdr(body), car(args), (vars > 1) ? cadr(args) : NULL);
72665 		      set_opt3_pair(body, false_p);
72666 		      set_opt3_pair(false_p, la);
72667 		      return(true);
72668 		    }}
72669 	      else
72670 		{
72671 		  s7_pointer la1, la2;
72672 		  la1 = cadr(false_p);
72673 		  la2 = caddr(false_p);
72674 		  if ((vars == 1) &&
72675 		      (is_proper_list_2(sc, la1)) && (is_proper_list_2(sc, la2)) &&
72676 		      (car(la1) == name) && (car(la2) == name) &&
72677 		      (is_fxable(sc, cadr(la1))) && (is_fxable(sc, cadr(la2))))
72678 		    {
72679 		      set_safe_optimize_op(body, (orig == cadddr(body)) ? OP_RECUR_IF_A_A_opLA_LAq : OP_RECUR_IF_A_opLA_LAq_A);
72680 		      fx_annotate_arg(sc, cdr(body), args);
72681 		      fx_annotate_arg(sc, obody, args);
72682 		      fx_annotate_arg(sc, cdr(la1), args);
72683 		      fx_annotate_arg(sc, cdr(la2), args);
72684 		      fx_tree(sc, cdr(body), car(args), NULL);
72685 		      set_opt3_pair(body, false_p);
72686 		      set_opt3_pair(false_p, la2);
72687 		      return(true);
72688 		    }}}
72689 	  else /* 3 args to c func */
72690 	    {
72691 	      if ((vars == 1) &&
72692 		  (is_pair(cdddr(false_p))) &&
72693 		  (is_null(cddddr(false_p))))
72694 		{
72695 		  s7_pointer la1, la2, la3;
72696 		  la1 = cadr(false_p);
72697 		  la2 = caddr(false_p);
72698 		  la3 = cadddr(false_p);
72699 		  if ((is_proper_list_2(sc, la2)) && (is_proper_list_2(sc, la3)) &&
72700 		      (car(la2) == name) && (car(la3) == name) &&
72701 		      (is_fxable(sc, cadr(la2))) && (is_fxable(sc, cadr(la3))))
72702 		    {
72703 		      if ((is_proper_list_2(sc, la1)) && (car(la1) == name) && (is_fxable(sc, cadr(la1))))
72704 			{
72705 			  if (orig != cadddr(body))
72706 			    return(false);
72707 			  set_safe_optimize_op(body, OP_RECUR_IF_A_A_opLA_LA_LAq);
72708 			  fx_annotate_arg(sc, cdr(la1), args);
72709 			}
72710 		      else
72711 			{
72712 			  if (is_fxable(sc, la1))
72713 			    {
72714 			      set_safe_optimize_op(body, (orig == cadddr(body)) ? OP_RECUR_IF_A_A_opA_LA_LAq : OP_RECUR_IF_A_opA_LA_LAq_A);
72715 			      fx_annotate_arg(sc, cdr(false_p), args);
72716 			    }
72717 			  else return(false);
72718 			}
72719 		      fx_annotate_arg(sc, cdr(body), args);
72720 		      fx_annotate_arg(sc, obody, args);
72721 		      fx_annotate_arg(sc, cdr(la2), args);
72722 		      fx_annotate_arg(sc, cdr(la3), args);
72723 		      fx_tree(sc, cdr(body), car(args), NULL);
72724 		      set_opt3_pair(body, false_p);
72725 		      set_opt3_pair(false_p, la3);
72726 		      return(true);
72727 		    }}}}}
72728 
72729       if ((vars == 3) &&
72730 	  (is_fxable(sc, test)))
72731 	{
72732 	  s7_pointer true_p, false_p;
72733 	  true_p = caddr(body);
72734 	  false_p = cadddr(body);
72735 	  if ((is_fxable(sc, true_p)) &&
72736 	      (is_proper_list_4(sc, false_p)) &&
72737 	      (car(false_p) == name))
72738 	    {
72739 	      s7_pointer l3a, la1, la2, la3;
72740 	      l3a = cdr(false_p);
72741 	      la1 = car(l3a);
72742 	      la2 = cadr(l3a);
72743 	      la3 = caddr(l3a);
72744 	      if ((is_proper_list_4(sc, la1)) && (is_proper_list_4(sc, la2)) && (is_proper_list_4(sc, la3)) &&
72745 		  (car(la1) == name) && (car(la2) == name) && (car(la3) == name) &&
72746 		  (is_fxable(sc, cadr(la1))) && (is_fxable(sc, cadr(la2))) && (is_fxable(sc, cadr(la3))) &&
72747 		  (is_fxable(sc, caddr(la1))) && (is_fxable(sc, caddr(la2))) && (is_fxable(sc, caddr(la3))) &&
72748 		  (is_fxable(sc, cadddr(la1))) && (is_fxable(sc, cadddr(la2))) && (is_fxable(sc, cadddr(la3))))
72749 		{
72750 		  set_safe_optimize_op(body, OP_RECUR_IF_A_A_LopL3A_L3A_L3Aq);
72751 		  fx_annotate_args(sc, cdr(la1), args);
72752 		  fx_annotate_args(sc, cdr(la2), args);
72753 		  fx_annotate_args(sc, cdr(la3), args);
72754 		  fx_annotate_arg(sc, cdr(body), args);
72755 		  fx_annotate_arg(sc, cddr(body), args);
72756 		  fx_tree(sc, cdr(body), car(args), cadr(args));
72757 		  set_opt3_pair(body, false_p);
72758 		  set_opt3_pair(false_p, la3);
72759 		  return(true);
72760 		}}}
72761   return(false);
72762 }
72763 
72764 static bool check_recur(s7_scheme *sc, s7_pointer name, int32_t vars, s7_pointer args, s7_pointer body)
72765 {
72766   if ((car(body) == sc->if_symbol) &&
72767       (proper_list_length(body) == 4))
72768     return(check_recur_if(sc, name, vars, args, body));
72769 
72770   if ((car(body) == sc->and_symbol) &&
72771       (vars == 2) &&
72772       (proper_list_length(body) == 3) &&
72773       (proper_list_length(caddr(body)) == 4) &&
72774       (caaddr(body) == sc->or_symbol) &&
72775       (is_fxable(sc, cadr(body))))
72776     {
72777       s7_pointer or_p, la1, la2;
72778       or_p = caddr(body);
72779       la1 = caddr(or_p);
72780       la2 = cadddr(or_p);
72781       if ((is_fxable(sc, cadr(or_p))) &&
72782 	  (proper_list_length(la1) == 3) &&
72783 	  (proper_list_length(la2) == 3) &&
72784 	  (car(la1) == name) &&
72785 	  (car(la2) == name) &&
72786 	  (is_fxable(sc, cadr(la1))) &&
72787 	  (is_fxable(sc, caddr(la1))) &&
72788 	  (is_fxable(sc, cadr(la2))) &&
72789 	  (is_fxable(sc, caddr(la2))))
72790 	{
72791 	  set_safe_optimize_op(body, OP_RECUR_AND_A_OR_A_LAA_LAA);
72792 	  fx_annotate_args(sc, cdr(la1), args);
72793 	  fx_annotate_args(sc, cdr(la2), args);
72794 	  fx_annotate_arg(sc, cdr(body), args);
72795 	  fx_annotate_arg(sc, cdr(or_p), args);
72796 	  fx_tree(sc, cdr(body), car(args), cadr(args));
72797 	  set_opt3_pair(body, or_p);
72798 	  return(true);
72799 	}}
72800 
72801   if (car(body) == sc->cond_symbol)
72802     {
72803       s7_pointer clause, clause2 = NULL;
72804       clause = cadr(body);
72805       if ((is_proper_list_1(sc, (cdr(clause)))) &&
72806 	  (is_fxable(sc, car(clause))) &&
72807 	  (is_fxable(sc, cadr(clause))))
72808 	{
72809 	  s7_pointer la_clause;
72810 	  s7_int len;
72811 	  len = proper_list_length(body);
72812 	  la_clause = caddr(body);
72813 	  if (len == 4)
72814 	    {
72815 	      if ((is_proper_list_2(sc, la_clause)) &&
72816 		  (is_fxable(sc, car(la_clause))))
72817 		{
72818 		  clause2 = la_clause;
72819 		  la_clause = cadddr(body);
72820 		}
72821 	      else return(false);
72822 	    }
72823 	  if ((is_proper_list_2(sc, la_clause)) &&
72824 	      ((car(la_clause) == sc->else_symbol) || (car(la_clause) == sc->T)) &&
72825 	      (is_pair(cadr(la_clause))))
72826 	    {
72827 	      la_clause = cadr(la_clause); /* (c_op arg (recur par)) or (c_op (recur) (recur)) or (op|l a laa) */
72828 	      if (is_proper_list_2(sc, cdr(la_clause)))
72829 		{
72830 		  if (is_h_optimized(la_clause))
72831 		    {
72832 		      if ((is_fxable(sc, cadr(la_clause))) &&
72833 			  ((len == 3) ||
72834 			   ((len == 4) && (vars == 2) &&
72835 			    (is_proper_list_3(sc, cadr(clause2))) &&
72836 			    (caadr(clause2) == name))))
72837 			{
72838 			  s7_pointer la;
72839 			  la = caddr(la_clause);
72840 			  if ((is_pair(la)) &&
72841 			      (car(la) == name) &&
72842 			      (is_pair(cdr(la))) &&
72843 			      (is_fxable(sc, cadr(la))) &&
72844 			      (((vars == 1) && (is_null(cddr(la)))) ||
72845 			       ((vars == 2) &&
72846 				(is_pair(cddr(la))) &&
72847 				(is_fxable(sc, caddr(la))) &&
72848 				(is_null(cdddr(la))))))
72849 			    {
72850 			      if (len == 3)
72851 				set_safe_optimize_op(body, (vars == 1) ? OP_RECUR_COND_A_A_opA_LAq : OP_RECUR_COND_A_A_opA_LAAq);
72852 			      else
72853 				{
72854 				  s7_pointer laa;
72855 				  laa = cadr(clause2);
72856 				  if ((is_fxable(sc, cadr(laa))) && /* args to first laa */
72857 				      (is_fxable(sc, caddr(laa))))
72858 				    {
72859 				      set_safe_optimize_op(body, OP_RECUR_COND_A_A_A_LAA_opA_LAAq);
72860 				      fx_annotate_arg(sc, clause2, args);
72861 				      fx_annotate_args(sc, cdr(laa), args);
72862 				    }
72863 				  else return(false);
72864 				}
72865 			      fx_annotate_args(sc, clause, args);
72866 			      fx_annotate_arg(sc, cdr(la_clause), args);
72867 			      fx_annotate_args(sc, cdr(la), args);
72868 			      fx_tree(sc, cdr(body), car(args), (vars == 1) ? NULL : cadr(args));
72869 			      set_opt3_pair(body, la_clause);
72870 			      set_opt3_pair(la_clause, la);
72871 			      return(true);
72872 			    }}
72873 		      else
72874 			{
72875 			  if ((len == 4) &&
72876 			      (is_fxable(sc, cadr(clause2))))
72877 			    {
72878 			      s7_pointer la1, la2;
72879 			      bool happy = false;
72880 			      la1 = cadr(la_clause);
72881 			      la2 = caddr(la_clause);
72882 
72883 			      if ((vars == 1) &&
72884 				  (is_proper_list_2(sc, la1)) && (is_proper_list_2(sc, la2)) &&
72885 				  (car(la1) == name) && (car(la2) == name) && (is_fxable(sc, cadr(la1))) && (is_fxable(sc, cadr(la2))))
72886 				{
72887 				  set_safe_optimize_op(body, OP_RECUR_COND_A_A_A_A_opLA_LAq);
72888 				  fx_annotate_arg(sc, cdr(la1), args);
72889 				  happy = true;
72890 				}
72891 			      else
72892 				{
72893 				  if ((vars == 2) &&
72894 				      /* (is_fxable(sc, cadr(clause2))) && */
72895 				      (is_proper_list_3(sc, la2)) && (car(la2) == name) && (is_fxable(sc, cadr(la2))) && (is_fxable(sc, caddr(la2))))
72896 				    {
72897 				      if (is_fxable(sc, la1))
72898 					{
72899 					  set_safe_optimize_op(body, OP_RECUR_COND_A_A_A_A_opA_LAAq);
72900 					  fx_annotate_arg(sc, cdr(la_clause), args);
72901 					  happy = true;
72902 					}
72903 				      else
72904 					if ((is_proper_list_3(sc, la1)) &&
72905 					    (car(la1) == name) &&
72906 					    (is_fxable(sc, cadr(la1))) &&
72907 					    (is_fxable(sc, caddr(la1))))
72908 					  {
72909 					    set_safe_optimize_op(body, OP_RECUR_COND_A_A_A_A_opLAA_LAAq);
72910 					    fx_annotate_args(sc, cdr(la1), args);
72911 					    happy = true;
72912 					  }}}
72913 			      if (happy)
72914 				{
72915 				  set_opt3_pair(la_clause, cdr(la2));
72916 				  fx_annotate_args(sc, clause, args);
72917 				  fx_annotate_args(sc, clause2, args);
72918 				  fx_annotate_args(sc, cdr(la2), args);
72919 				  fx_tree(sc, cdr(body), car(args), (vars == 1) ? NULL : cadr(args));
72920 				  set_opt3_pair(body, la_clause);
72921 				  return(true);
72922 				}}}}
72923 		  else
72924 		    {
72925 		      if (clause2)
72926 			{
72927 			  s7_pointer laa;
72928 			  laa = cadr(clause2);
72929 
72930 			  if ((vars == 2) && (len == 4) &&
72931 			      (is_proper_list_3(sc, laa)) && (car(laa) == name) && (is_fxable(sc, cadr(laa))) && (is_fxable(sc, caddr(laa))))
72932 			    {
72933 			      s7_pointer la1, la2;
72934 			      la1 = cadr(la_clause);
72935 			      la2 = caddr(la_clause);
72936 			      if ((is_fxable(sc, la1)) &&
72937 				  (is_proper_list_3(sc, la2)) && (car(la2) == name) && (is_fxable(sc, cadr(la2))) && (is_fxable(sc, caddr(la2))))
72938 				{
72939 				  set_safe_optimize_op(body, OP_RECUR_COND_A_A_A_LAA_LopA_LAAq);
72940 				  fx_annotate_args(sc, clause, args);
72941 				  fx_annotate_arg(sc, clause2, args);
72942 				  fx_annotate_args(sc, cdr(laa), args);
72943 				  fx_annotate_arg(sc, cdr(la_clause), args);
72944 				  fx_annotate_args(sc, cdr(la2), args);
72945 				  fx_tree(sc, cdr(body), car(args), cadr(args));
72946 				  set_opt3_pair(body, la_clause);
72947 				  set_opt3_pair(la_clause, cdr(la2));
72948 				  return(true);
72949 				}}}}}}}}
72950   return(false);
72951 }
72952 
72953 static opt_t fxify_closure_s(s7_scheme *sc, s7_pointer func, s7_pointer expr, s7_pointer e, bool sym, int32_t hop)
72954 {
72955   s7_pointer body;
72956   body = closure_body(func);
72957   fx_annotate_arg(sc, body, e);
72958   if (sym)
72959     {
72960       set_safe_optimize_op(expr, hop + OP_SAFE_CLOSURE_S_A);
72961       if ((is_pair(car(body))) && (is_pair(cdar(body))) && (car(closure_args(func)) == cadar(body)))
72962 	{
72963 	  if (optimize_op(car(body)) == HOP_SAFE_C_S)
72964 	    set_safe_optimize_op(expr, hop + OP_SAFE_CLOSURE_S_TO_S);
72965 	  else
72966 	    {
72967 	      if (optimize_op(car(body)) == HOP_SAFE_C_SC)
72968 		{
72969 		  s7_pointer body_arg2;
72970 		  body_arg2 = caddar(body);
72971 		  set_opt3_con(cdr(expr), (is_pair(body_arg2)) ? cadr(body_arg2) : body_arg2);
72972 		  set_safe_optimize_op(expr, hop + OP_SAFE_CLOSURE_S_TO_SC);
72973 		  if ((caar(body) == sc->vector_ref_symbol) && (is_global(sc->vector_ref_symbol)))
72974 		    set_fx_direct(cdr(expr), fx_safe_closure_s_to_vref);
72975 		  else
72976 		    {
72977 		      set_fx_direct(cdr(expr), fx_safe_closure_s_to_sc);
72978 		      if ((is_t_integer(body_arg2)) && (integer(body_arg2) == 1))
72979 			{
72980 			  if (caar(body) == sc->subtract_symbol) set_fx_direct(cdr(expr), fx_safe_closure_s_to_sub1);
72981 			  if (caar(body) == sc->add_symbol) set_fx_direct(cdr(expr), fx_safe_closure_s_to_add1);
72982 			}}}}}}
72983   else set_safe_optimize_op(expr, hop + OP_SAFE_CLOSURE_C_A);
72984   set_closure_one_form_fx_arg(func);
72985   fx_tree(sc, body, car(closure_args(func)), NULL);
72986   return(OPT_T);
72987 }
72988 
72989 static bool fxify_closure_a(s7_scheme *sc, s7_pointer func, bool one_form, bool safe_case, int32_t hop, s7_pointer expr, s7_pointer e)
72990 {
72991   if (one_form)
72992     {
72993       if (safe_case)
72994 	{
72995 	  s7_pointer body;
72996 	  body = closure_body(func);
72997 	  if (is_fxable(sc, car(body)))
72998 	    {
72999 	      fx_annotate_arg(sc, body, e);
73000 	      set_safe_optimize_op(expr, hop + OP_SAFE_CLOSURE_A_A);
73001 
73002 	      if ((is_pair(car(body))) &&
73003 		  (optimize_op(car(body)) == HOP_SAFE_C_SC) &&
73004 		  (car(closure_args(func)) == cadar(body)))
73005 		{
73006 		  s7_pointer body_arg2;
73007 		  body_arg2 = caddar(body);
73008 		  set_opt3_con(cdr(expr), (is_pair(body_arg2)) ? cadr(body_arg2) : body_arg2);
73009 		  set_safe_optimize_op(expr, hop + OP_SAFE_CLOSURE_A_TO_SC);
73010 		  if ((caar(body) == sc->vector_ref_symbol) && (is_global(sc->vector_ref_symbol)))
73011 		    set_fx_direct(expr, fx_safe_closure_a_to_vref);
73012 		  else set_fx_direct(expr, fx_safe_closure_a_to_sc);
73013 		}
73014 	      set_closure_one_form_fx_arg(func);
73015 	      fx_tree(sc, body, car(closure_args(func)), NULL);
73016 	      return(true);
73017 	    }
73018 	  set_optimize_op(expr, hop + OP_SAFE_CLOSURE_A_O);
73019 	}
73020       else set_optimize_op(expr, hop + OP_CLOSURE_A_O);
73021     }
73022   else set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_A : OP_CLOSURE_A));
73023   return(false);
73024 }
73025 
73026 static opt_t optimize_closure_one_arg(s7_scheme *sc, s7_pointer expr, s7_pointer func,
73027 				      int32_t hop, int32_t pairs, int32_t symbols, int32_t quotes, int32_t bad_pairs, s7_pointer e)
73028 {
73029   bool one_form, safe_case;
73030   s7_pointer body, arg1;
73031   int32_t arit;
73032 
73033   arg1 = cadr(expr);
73034   arit = closure_arity_to_int(sc, func);
73035   if (arit != 1)
73036     {
73037       if ((arit == -1) &&
73038 	  (is_symbol(closure_args(func))))
73039 	return(optimize_closure_dotted_args(sc, expr, func, hop, 1, e));
73040       return(OPT_F);
73041     }
73042 
73043   safe_case = is_safe_closure(func);
73044   body = closure_body(func);
73045   one_form = is_null(cdr(body));
73046   if (is_immutable(func)) hop = 1;
73047 
73048   if (pairs == 0)
73049     {
73050       bool sym;
73051       sym = (symbols == 1);
73052       if (sym)
73053 	set_opt2_sym(expr, arg1);
73054       else set_opt2_con(expr, arg1);
73055       set_opt1_lambda_add(expr, func);
73056 
73057       if (one_form)
73058 	{
73059 	  if (safe_case)
73060 	    {
73061 	      if (is_fxable(sc, car(body)))
73062 		return(fxify_closure_s(sc, func, expr, e, sym, hop));
73063 	      set_optimize_op(expr, hop + ((sym) ? OP_SAFE_CLOSURE_S_O : OP_SAFE_CLOSURE_C_O));
73064 	    }
73065 	  else set_optimize_op(expr, hop + ((sym) ? OP_CLOSURE_S_O : OP_CLOSURE_C_O));
73066 	}
73067       else set_optimize_op(expr, hop + ((sym) ? ((safe_case) ? OP_SAFE_CLOSURE_S : OP_CLOSURE_S) : ((safe_case) ? OP_SAFE_CLOSURE_C : OP_CLOSURE_C)));
73068       set_unsafely_optimized(expr);
73069       return(OPT_F);
73070     }
73071 
73072   if (fx_count(sc, expr) == 1)
73073     {
73074       set_unsafely_optimized(expr);
73075       set_opt1_lambda_add(expr, func);
73076       fx_annotate_arg(sc, cdr(expr), e);
73077       set_opt3_arglen(cdr(expr), int_one);
73078       if (fxify_closure_a(sc, func, one_form, safe_case, hop, expr, e)) return(OPT_T);
73079       set_unsafely_optimized(expr);
73080       return(OPT_F);
73081     }
73082   set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_P : OP_CLOSURE_P));
73083   set_opt1_lambda_add(expr, func);
73084   set_opt3_arglen(cdr(expr), int_one);
73085   set_unsafely_optimized(expr);
73086   if ((safe_case) && (one_form) && (is_fxable(sc, car(closure_body(func)))))
73087     {
73088       set_optimize_op(expr, hop + OP_SAFE_CLOSURE_P_A); /* other possibilities: 3p fp (ap|pa only get a few hits), but none of these matter much */
73089       fx_annotate_arg(sc, closure_body(func), e);
73090     }
73091   return(OPT_F);  /* don't check is_optimized here for OPT_T */
73092 }
73093 
73094 static opt_t optimize_func_one_arg(s7_scheme *sc, s7_pointer expr, s7_pointer func,
73095 				   int32_t hop, int32_t pairs, int32_t symbols, int32_t quotes, int32_t bad_pairs, s7_pointer e)
73096 {
73097   s7_pointer arg1;
73098   /* very often, expr is already optimized, quoted stuff is counted under "bad_pairs"! as well as quotes */
73099 
73100   if (quotes > 0)
73101     {
73102       if (direct_memq(sc->quote_symbol, e))
73103 	return(OPT_OOPS);
73104       if ((bad_pairs == quotes) &&
73105 	  (is_symbol(car(expr))) &&
73106 	  (is_constant_symbol(sc, car(expr))))
73107 	hop = 1;
73108     }
73109 
73110   arg1 = cadr(expr);
73111   /* need in_with_let -> search only rootlet not lookup */
73112   if ((symbols == 1) &&
73113       (!arg_findable(sc, arg1, e)))
73114     {
73115       /* wrap the bad arg in a check symbol lookup */
73116       if (s7_is_aritable(sc, func, 1))
73117 	{
73118 	  set_fx_direct(cdr(expr), fx_unsafe_s);
73119 	  return(wrap_bad_args(sc, func, expr, 1, hop, e));
73120 	}
73121       return(OPT_F);
73122     }
73123 
73124   if ((is_c_function(func)) &&
73125        (c_function_required_args(func) <= 1) &&
73126        (c_function_all_args(func) >= 1))
73127     return(optimize_c_function_one_arg(sc, expr, func, hop, pairs, symbols, quotes, bad_pairs, e));
73128 
73129   if (is_closure(func))
73130     return(optimize_closure_one_arg(sc, expr, func, hop, pairs, symbols, quotes, bad_pairs, e));
73131 
73132   if (is_closure_star(func))
73133     {
73134       if (is_null(closure_args(func)))
73135 	return(OPT_F);
73136       if (fx_count(sc, expr) == 1)
73137 	{
73138 	  bool safe_case;
73139 	  safe_case = is_safe_closure(func);
73140 	  if (is_immutable(func)) hop = 1;
73141 	  fx_annotate_arg(sc, cdr(expr), e);
73142 	  set_opt1_lambda_add(expr, func);
73143 	  set_opt3_arglen(cdr(expr), int_one);
73144 	  set_unsafely_optimized(expr);
73145 
73146 	  if ((safe_case) && (is_null(cdr(closure_args(func)))))
73147 	    set_optimize_op(expr, hop + OP_SAFE_CLOSURE_STAR_A1);
73148 	  else
73149 	    {
73150 	      if (lambda_has_simple_defaults(func))
73151 		{
73152 		  if (arglist_has_rest(sc, closure_args(func)))
73153 		    set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_ALL_A_1 : OP_CLOSURE_STAR_ALL_A));
73154 		  else set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_A : OP_CLOSURE_STAR_A));
73155 		}
73156 	      else set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_ALL_A_1 : OP_CLOSURE_STAR_ALL_A));
73157 	    }}
73158       return(OPT_F);
73159     }
73160 
73161   if ((is_c_function_star(func)) &&
73162       (fx_count(sc, expr) == 1) &&
73163       (c_function_all_args(func) >= 1) &&
73164       (!is_keyword(arg1)))           /* the only arg should not be a keyword (needs error checks later) */
73165     {
73166       if ((hop == 0) && (symbol_id(car(expr)) == 0) && (!sc->in_with_let)) hop = 1;
73167       set_safe_optimize_op(expr, hop + OP_SAFE_C_FUNCTION_STAR_A);
73168       fx_annotate_arg(sc, cdr(expr), e);
73169       set_opt3_arglen(cdr(expr), int_one);
73170       set_c_function(expr, func);
73171       return(OPT_T);
73172     }
73173 
73174   if ((is_any_vector(func)) &&
73175       (is_fxable(sc, arg1)))
73176     {
73177       set_unsafe_optimize_op(expr, OP_IMPLICIT_VECTOR_REF_A);
73178       fx_annotate_arg(sc, cdr(expr), e);
73179       set_opt3_arglen(cdr(expr), int_one);
73180       return(OPT_T);
73181     }
73182 
73183   if ((func == sc->s7_let) &&         /* (*s7* ...) */
73184       (((quotes == 1) && (is_symbol(cadr(arg1)))) ||
73185        (is_keyword(arg1))))
73186     {
73187       s7_pointer sym;
73188       sym = (quotes == 1) ? cadr(arg1) : arg1;
73189       if (is_keyword(sym)) sym = keyword_symbol(sym); /* might even be ':print-length */
73190       set_safe_optimize_op(expr, OP_IMPLICIT_S7_LET_REF_S);
73191       set_opt3_sym(expr, sym);
73192       return(OPT_T);
73193     }
73194 
73195   if (is_let(func))
73196     {
73197       if ((is_pair(arg1)) && (car(arg1) == sc->quote_symbol))
73198 	{
73199 	  set_opt3_con(expr, cadr(arg1));
73200 	  set_unsafe_optimize_op(expr, OP_IMPLICIT_LET_REF_C);
73201 	  return(OPT_T);
73202 	}
73203       if (is_fxable(sc, arg1))
73204 	{
73205 	  set_unsafe_optimize_op(expr, OP_IMPLICIT_LET_REF_A);
73206 	  set_opt3_any(expr, arg1);
73207 	  fx_annotate_arg(sc, cdr(expr), e);
73208 	  set_opt3_arglen(cdr(expr), int_one);
73209 	  return(OPT_T);
73210 	}}
73211 
73212   /* unknown_* for other cases is set later(? -- we're getting eval-args...) */
73213   /* op_safe_c_p for (< (values 1 2 3)) op_s_s for (op arg) op_s_c for (op 'x) or (op 1) also op_s_a
73214    *   but is it better to wait for unknown* ?  These are not hit often at this point (except in s7test).
73215    *   do they end up in op_s_a or whatever after unknown*?
73216    */
73217   return((is_optimized(expr)) ? OPT_T : OPT_F);
73218 }
73219 
73220 static bool unsafe_is_safe(s7_scheme *sc, s7_pointer f, s7_pointer e)
73221 {
73222   if (!is_symbol(f)) return(false);
73223   f = find_uncomplicated_symbol(sc, f, e); /* how to catch local c-funcs here? */
73224   if (is_slot(f))
73225     {
73226       f = slot_value(f);
73227       return((is_c_function(f)) &&
73228 	     (is_safe_procedure(f)));
73229     }
73230   return(false);
73231 }
73232 
73233 static opt_t set_any_closure_fp(s7_scheme *sc, s7_pointer func, s7_pointer expr, s7_pointer e, int32_t num_args, opcode_t op)
73234 {
73235   s7_pointer p;
73236   for (p = cdr(expr); is_pair(p); p = cdr(p))
73237     set_fx(p, fx_choose(sc, p, e, (is_list(e)) ? pair_symbol_is_safe : let_symbol_is_safe));
73238   set_opt3_arglen(cdr(expr), make_permanent_integer(num_args));
73239   set_unsafe_optimize_op(expr, op);
73240   set_opt1_lambda_add(expr, func);
73241   return(OPT_F);
73242 }
73243 
73244 static bool two_args_ok(s7_scheme *sc, s7_pointer expr, s7_pointer e)
73245 {
73246   if ((is_symbol(car(expr))) && ((car(expr) == sc->member_symbol) || (car(expr) == sc->assoc_symbol))) return(true);
73247   return(unsafe_is_safe(sc, cadr(expr), e));
73248 }
73249 
73250 static void opt_sp_1(s7_scheme *sc, s7_function g, s7_pointer expr)
73251 {
73252   set_opt1_any(cdr(expr),
73253 	       (s7_pointer)((intptr_t)((g == g_cons) ? OP_SAFE_CONS_SP_1 :
73254 				       ((g == g_vector) ? OP_SAFE_VECTOR_SP_1 :
73255 					(((g == g_multiply) || (g == g_multiply_2)) ? OP_SAFE_MULTIPLY_SP_1 :
73256 					 (((g == g_add) || (g == g_add_2)) ? OP_SAFE_ADD_SP_1 :
73257 					  (((g == g_subtract) || (g == g_subtract_2)) ? OP_SAFE_SUBTRACT_SP_1 :
73258 					   OP_SAFE_C_SP_1)))))));
73259 }
73260 
73261 static opt_t set_any_c_fp(s7_scheme *sc, s7_pointer func, s7_pointer expr, s7_pointer e, int32_t num_args, opcode_t op)
73262 {
73263   s7_pointer p;
73264   for (p = cdr(expr); is_pair(p); p = cdr(p))
73265     {
73266       set_fx(p, fx_choose(sc, p, e, (is_list(e)) ? pair_symbol_is_safe : let_symbol_is_safe));
73267       if (!has_fx(p))
73268 	gx_annotate_arg(sc, p, e);
73269     }
73270   set_opt3_arglen(cdr(expr), make_permanent_integer(num_args)); /* for op_unknown_fp */
73271   set_unsafe_optimize_op(expr, op);
73272   choose_c_function(sc, expr, func, num_args); /* we can use num_args -- mv will redirect to generic call */
73273   return(OPT_F);
73274 }
73275 
73276 static s7_function io_function(s7_scheme *sc, s7_function func)
73277 {
73278   if (func == g_with_input_from_string) return(with_string_in);
73279   if (func == g_with_input_from_file) return(with_file_in);
73280   if (func == g_with_output_to_file)  return(with_file_out);
73281   if (func == g_call_with_input_string) return(call_string_in);
73282   if (func == g_call_with_input_file) return(call_file_in);
73283   return(call_file_out); /* call_with_output_to_file */
73284 }
73285 
73286 static int32_t check_lambda(s7_scheme *sc, s7_pointer form, bool optl);
73287 
73288 static opt_t optimize_func_two_args(s7_scheme *sc, s7_pointer expr, s7_pointer func, int32_t hop, int32_t pairs, int32_t symbols, int32_t quotes, int32_t bad_pairs, s7_pointer e)
73289 {
73290   s7_pointer arg1, arg2;
73291 
73292   if (quotes > 0)
73293     {
73294       if (direct_memq(sc->quote_symbol, e))
73295 	return(OPT_OOPS);
73296       if ((bad_pairs == quotes) &&
73297 	  (is_symbol(car(expr))) &&
73298 	  (is_constant_symbol(sc, car(expr))))
73299 	hop = 1;
73300     }
73301 
73302   arg1 = cadr(expr);
73303   arg2 = caddr(expr);
73304   if (((is_symbol(arg1)) &&
73305        (!arg_findable(sc, arg1, e))) ||
73306       ((is_symbol(arg2)) &&
73307        (!arg_findable(sc, arg2, e))))
73308     {
73309       /* wrap bad args */
73310       if ((is_fxable(sc, arg1)) &&
73311 	  (is_fxable(sc, arg2)) &&
73312 	  (s7_is_aritable(sc, func, 2)))
73313 	{
73314 	  fx_annotate_args(sc, cdr(expr), e);
73315 	  return(wrap_bad_args(sc, func, expr, 2, hop, e));
73316 	}
73317       return(OPT_F);
73318     }
73319   /* end of bad symbol wrappers */
73320 
73321   if (is_c_function(func) &&
73322       (c_function_required_args(func) <= 2) &&
73323       (c_function_all_args(func) >= 2))
73324     {
73325       /* this is a mess */
73326       bool func_is_safe;
73327 
73328       if ((hop == 0) && (symbol_id(car(expr)) == 0) && (!sc->in_with_let)) hop = 1;
73329       func_is_safe = is_safe_procedure(func);
73330       if (pairs == 0)
73331 	{
73332 	  if ((func_is_safe) ||
73333 	      ((is_maybe_safe(func)) && (two_args_ok(sc, expr, e))))
73334 	    {
73335 	      /* another case here: set-car! and set-cdr! are safe if symbols==1 and arg1 is the symbol (i.e. arg2 is a constant) */
73336 	      if (symbols == 0)
73337 		set_optimize_op(expr, hop + OP_SAFE_C_D);
73338 	      else
73339 		{
73340 		  if (symbols == 2) /* these two symbols are almost never the same, (sqrt (+ (* x x) (* y y))) */
73341 		    {
73342 		      set_optimize_op(expr, hop + OP_SAFE_C_SS);
73343 		      set_opt2_sym(cdr(expr), arg2);
73344 		    }
73345 		  else
73346 		    {
73347 		      if (is_normal_symbol(arg1))
73348 			{
73349 			  set_opt2_con(cdr(expr), arg2);
73350 			  set_optimize_op(expr, hop + OP_SAFE_C_SC);
73351 			}
73352 		      else
73353 			{
73354 			  set_opt1_con(cdr(expr), arg1);
73355 			  set_opt2_sym(cdr(expr), arg2);
73356 			  set_optimize_op(expr, hop + OP_SAFE_C_CS);
73357 			}}}
73358 	      set_optimized(expr);
73359 	      choose_c_function(sc, expr, func, 2);
73360 	      return(OPT_T);
73361 	    }
73362 
73363 	  set_unsafely_optimized(expr);
73364 	  if (symbols == 2)
73365 	    {
73366 	      if (c_function_call(func) == g_apply)
73367 		{
73368 		  set_optimize_op(expr, OP_APPLY_SS);
73369 		  set_opt1_cfunc(expr, func); /* not quite set_c_function */
73370 		  set_opt2_sym(expr, arg2);
73371 		}
73372 	      else
73373 		{
73374 		  if (has_safe_args(func))
73375 		    {
73376 		      set_opt2_sym(cdr(expr), arg2);
73377 		      set_optimize_op(expr, hop + OP_CL_SS);
73378 		    }
73379 		  else set_optimize_op(expr, hop + OP_C_SS);
73380 		  choose_c_function(sc, expr, func, 2);
73381 		}}
73382 	  else
73383 	    {
73384 	      set_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_AA : OP_C_AA));
73385 	      fx_annotate_args(sc, cdr(expr), e);
73386 	      set_opt3_arglen(cdr(expr), int_two);
73387 	      choose_c_function(sc, expr, func, 2);
73388 	      if (is_safe_procedure(opt1_cfunc(expr)))
73389 		{
73390 		  clear_unsafe(expr);
73391 		  /* symbols can be 0..2 here, no pairs */
73392 		  set_optimized(expr);
73393 		  if (symbols == 1)
73394 		    {
73395 		      if (is_normal_symbol(arg1))
73396 			{
73397 			  set_optimize_op(expr, hop + OP_SAFE_C_SC);
73398 			  set_opt2_con(cdr(expr), arg2);
73399 			}
73400 		      else
73401 			{
73402 			  set_opt1_con(cdr(expr), arg1);
73403 			  set_opt2_sym(cdr(expr), arg2);
73404 			  set_optimize_op(expr, hop + OP_SAFE_C_CS);
73405 			}}
73406 		  return(OPT_T);
73407 		}}
73408 	  return(OPT_F);
73409 	}
73410 
73411       /* pairs != 0 */
73412       if ((bad_pairs == 0) &&
73413 	  (pairs == 2))
73414 	{
73415 	  if ((func_is_safe) ||
73416 	      ((is_maybe_safe(func)) && (two_args_ok(sc, expr, e))))
73417 	    {
73418 	      int32_t op;
73419 	      op = combine_ops(sc, func, expr, E_C_PP, arg1, arg2);
73420 	      set_safe_optimize_op(expr, hop + op);
73421 	      if (op == OP_SAFE_C_PP)
73422 		{
73423 		  if (((op_no_hop(cadr(expr))) == OP_SAFE_CLOSURE_S_TO_SC) &&
73424 		      ((op_no_hop(caddr(expr))) == OP_SAFE_CLOSURE_S_TO_SC) &&
73425 		      (is_global(caadr(expr))) && (is_global(caaddr(expr))))
73426 		    {
73427 		      /* ideally this would be OP not HOP, but safe_closure_s_to_sc is too picky */
73428 		      /* set_opt3_pair(expr, caddr(expr)); */
73429 		      set_opt3_arglen(cdr(expr), int_two);
73430 		      set_safe_optimize_op(expr, HOP_SAFE_C_FF);
73431 		    }
73432 
73433 		  opt_sp_1(sc, c_function_call(func), expr); /* calls set_opt1_any, sets opt1(cdr(expr)) to OP_SAFE_CONS_SP_1 and friends */
73434 		  if (is_fxable(sc, arg1))
73435 		    {
73436 		      if (is_fxable(sc, arg2))
73437 			return(check_c_aa(sc, expr, func, hop, e)); /* AA case */
73438 		      set_optimize_op(expr, hop + OP_SAFE_C_AP);
73439 		      fx_annotate_arg(sc, cdr(expr), e);
73440 		      gx_annotate_arg(sc, cddr(expr), e);
73441 		      set_opt3_arglen(cdr(expr), int_two);
73442 		    }
73443 		  else
73444 		    {
73445 		      if (is_fxable(sc, arg2))
73446 			{
73447 			  set_optimize_op(expr, hop + OP_SAFE_C_PA);
73448 			  fx_annotate_arg(sc, cddr(expr), e);
73449 			  gx_annotate_arg(sc, cdr(expr), e);
73450 			  set_opt3_arglen(cdr(expr), int_two);
73451 			}
73452 		      else gx_annotate_args(sc, cdr(expr), e);
73453 		    }}
73454 	      choose_c_function(sc, expr, func, 2); /* this might change the op to safe_c_c, so it has to be last */
73455 	      return(OPT_T);
73456 	    }}
73457 
73458       if ((bad_pairs == 0) &&
73459 	  (pairs == 1))
73460 	{
73461 	  if ((func_is_safe) ||
73462 	      ((is_maybe_safe(func)) && (two_args_ok(sc, expr, e))))
73463 	    {
73464 	      combine_op_t orig_op;
73465 	      int32_t op;
73466 
73467 	      if (is_pair(arg1))
73468 		{
73469 		  orig_op = (is_normal_symbol(arg2)) ? E_C_PS : E_C_PC;
73470 		  op = combine_ops(sc, func, expr, orig_op, arg1, arg2);
73471 		}
73472 	      else
73473 		{
73474 		  orig_op = (is_normal_symbol(arg1)) ? E_C_SP : E_C_CP;
73475 		  op = combine_ops(sc, func, expr, orig_op, arg1, arg2);
73476 		}
73477 	      if ((((op == OP_SAFE_C_SP) || (op == OP_SAFE_C_CP)) &&
73478 		   (is_fxable(sc, arg2))) ||
73479 		  (((op == OP_SAFE_C_PS) || (op == OP_SAFE_C_PC)) &&
73480 		   (is_fxable(sc, arg1))))
73481 		{
73482 		  fx_annotate_args(sc, cdr(expr), e);
73483 		  if (!safe_c_aa_to_ag_ga(sc, expr, hop))
73484 		    {
73485 		      set_safe_optimize_op(expr, hop + OP_SAFE_C_AA);
73486 		      set_opt3_arglen(cdr(expr), int_two);
73487 		    }}
73488 	      else
73489 		{
73490 		  set_safe_optimize_op(expr, hop + op);
73491 		  if ((op == OP_SAFE_C_SP) || (op == OP_SAFE_C_CP))
73492 		    {
73493 		      opt_sp_1(sc, c_function_call(func), expr);
73494 		      set_opt3_any(cdr(expr), arg1);
73495 		    }
73496 		  else
73497 		    if (op == OP_SAFE_C_PC)
73498 		      set_opt3_con(cdr(expr), arg2);
73499 		}
73500 	      choose_c_function(sc, expr, func, 2);
73501 	      return(OPT_T);
73502 	    }
73503 
73504 	  if ((symbols == 1) &&
73505 	      (is_normal_symbol(arg1)))
73506 	    {
73507 	      if (is_safe_c_s(arg2))
73508 		{
73509 		  set_unsafe_optimize_op(expr, hop + OP_C_S_opSq);
73510 		  set_opt1_sym(cdr(expr), cadr(arg2));
73511 		  choose_c_function(sc, expr, func, 2);
73512 		  return(OPT_F);
73513 		}}}
73514 
73515       if ((bad_pairs == 1) && (quotes == 1))
73516 	{
73517 	  if ((func_is_safe) ||
73518 	      ((is_maybe_safe(func)) && (two_args_ok(sc, expr, e))))
73519 	    {
73520 	      if  (symbols == 1)
73521 		{
73522 		  set_optimized(expr);
73523 		  if (is_normal_symbol(arg1))
73524 		    {
73525 		      set_opt2_con(cdr(expr), cadr(arg2));
73526 		      set_optimize_op(expr, hop + OP_SAFE_C_SC);
73527 		    }
73528 		  else
73529 		    {
73530 		      set_opt1_con(cdr(expr), cadr(arg1));
73531 		      set_opt2_sym(cdr(expr), arg2);
73532 		      set_optimize_op(expr, hop + OP_SAFE_C_CS);
73533 		    }
73534 		  choose_c_function(sc, expr, func, 2);
73535 		  return(OPT_T);
73536 		}
73537 	      if ((pairs == 1) && (is_pair(arg2))) /* QC never happens */
73538 		{
73539 		  set_safe_optimize_op(expr, hop + OP_SAFE_C_CQ);
73540 		  set_opt2_con(cdr(expr), cadr(arg2));
73541 		  choose_c_function(sc, expr, func, 2);
73542 		  return(OPT_T);
73543 		}
73544 
73545 	      if (!is_safe_c_s(arg1))
73546 		{
73547 		  if ((is_fxable(sc, arg1)) && (is_fxable(sc, arg2)))
73548 		    return(check_c_aa(sc, expr, func, hop, e));
73549 		}}
73550 	  else
73551 	    if (pairs == 1)
73552 	      {
73553 		set_unsafe_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_AA : OP_C_AA));
73554 		fx_annotate_args(sc, cdr(expr), e);
73555 		set_opt3_arglen(cdr(expr), int_two);
73556 		choose_c_function(sc, expr, func, 2);
73557 		return(OPT_F);
73558 	      }}
73559 
73560       if (quotes == 2)
73561 	{
73562 	  if (func_is_safe)
73563 	    set_safe_optimize_op(expr, hop + OP_SAFE_C_AA); /* op_safe_c_d -> fx_c_d appears to leave quoted pairs quoted? */
73564 	  else set_unsafe_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_AA : OP_C_AA));
73565 	  fx_annotate_args(sc, cdr(expr), e);
73566 	  set_opt3_arglen(cdr(expr), int_two);
73567 	  choose_c_function(sc, expr, func, 2);
73568 	  return((func_is_safe) ? OPT_T : OPT_F);
73569 	}
73570 
73571       if ((pairs == 1) &&
73572 	  (quotes == 0) &&
73573 	  ((func_is_safe) ||
73574 	   ((is_maybe_safe(func)) && (two_args_ok(sc, expr, e)))))
73575 	{
73576 	  if (symbols == 1)
73577 	    {
73578 	      set_optimized(expr);
73579 	      if (is_normal_symbol(arg1)) /* this is what optimize_expression uses to count symbols */
73580 		{
73581 		  set_optimize_op(expr, hop + OP_SAFE_C_SP);
73582 		  opt_sp_1(sc, c_function_call(func), expr);
73583 		}
73584 	      else set_optimize_op(expr, hop + OP_SAFE_C_PS);
73585 	      choose_c_function(sc, expr, func, 2);
73586 	      if (bad_pairs == 0)
73587 		return(OPT_T);
73588 	      set_unsafe(expr);
73589 	      return(OPT_F);
73590 	    }
73591 	  if (symbols == 0)
73592 	    {
73593 	      set_optimized(expr);
73594 	      if ((is_fxable(sc, arg1)) && (is_fxable(sc, arg2)))
73595 		return(check_c_aa(sc, expr, func, hop, e));
73596 	      if (is_pair(arg1))
73597 		{
73598 		  set_optimize_op(expr, hop + OP_SAFE_C_PC);
73599 		  set_opt3_con(cdr(expr), arg2);
73600 		}
73601 	      else
73602 		{
73603 		  set_optimize_op(expr, hop + OP_SAFE_C_CP);
73604 		  opt_sp_1(sc, c_function_call(func), expr);
73605 		  set_opt3_any(cdr(expr), arg1);
73606 		}
73607 	      choose_c_function(sc, expr, func, 2);
73608 	      if (bad_pairs == 0)
73609 		return(OPT_T);
73610 	      set_unsafe(expr);
73611 	      return(OPT_F);
73612 	    }}
73613 
73614       if ((pairs == 2) &&
73615 	  ((func_is_safe) ||
73616 	   ((is_maybe_safe(func)) && (two_args_ok(sc, expr, e)))))
73617 	{
73618 	  if ((bad_pairs == 1) &&
73619 	      (is_safe_c_s(arg1)))
73620 	    {
73621 	      /* unsafe func here won't work unless we check that later and make the new arg list (for list-values etc)
73622 	       *   (and it has to be the last pair else the unknown_g stuff can mess up)
73623 	       */
73624 	      if ((car(arg2) == sc->quote_symbol) &&
73625 		  (is_global(sc->quote_symbol)))
73626 		{
73627 		  if (!is_proper_list_1(sc, cdr(arg2)))
73628 		    return(OPT_OOPS);
73629 		  set_safe_optimize_op(expr, hop + OP_SAFE_C_opSq_C);
73630 		  set_opt1_sym(cdr(expr), cadr(arg1));
73631 		  set_opt2_con(cdr(expr), cadr(arg2));
73632 		  choose_c_function(sc, expr, func, 2);
73633 		  return(OPT_T);
73634 		}
73635 	      set_unsafe_optimize_op(expr, hop + OP_SAFE_C_opSq_P);
73636 	      opt_sp_1(sc, c_function_call(func), expr);
73637 	      choose_c_function(sc, expr, func, 2);
73638 	      return(OPT_F);
73639 	    }
73640 	  if (quotes == 0)
73641 	    {
73642 	      set_unsafely_optimized(expr);
73643 	      if (is_fxable(sc, arg1))
73644 		{
73645 		  if (is_fxable(sc, arg2))
73646 		    return(check_c_aa(sc, expr, func, hop, e));
73647 		  set_optimize_op(expr, hop + OP_SAFE_C_AP);
73648 		  opt_sp_1(sc, c_function_call(func), expr);
73649 		  fx_annotate_arg(sc, cdr(expr), e);
73650 		  gx_annotate_arg(sc, cddr(expr), e);
73651 		}
73652 	      else
73653 		{
73654 		  if (is_fxable(sc, arg2))
73655 		    {
73656 		      set_optimize_op(expr, hop + OP_SAFE_C_PA);
73657 		      fx_annotate_arg(sc, cddr(expr), e);
73658 		      gx_annotate_arg(sc, cdr(expr), e);
73659 		    }
73660 		  else
73661 		    {
73662 		      set_optimize_op(expr, hop + OP_SAFE_C_PP);
73663 		      opt_sp_1(sc, c_function_call(func), expr);
73664 		      gx_annotate_args(sc, cdr(expr), e);
73665 		    }}
73666 	      choose_c_function(sc, expr, func, 2);
73667 	      return(OPT_F);
73668 	    }
73669 	  if (quotes == 1)
73670 	    {
73671 	      if ((car(arg1) == sc->quote_symbol) &&
73672 		  (is_global(sc->quote_symbol)))
73673 		{
73674 		  if (!is_proper_list_1(sc, cdr(arg1)))
73675 		    return(OPT_OOPS);
73676 		  set_optimize_op(expr, hop + OP_SAFE_C_CP);
73677 		  opt_sp_1(sc, c_function_call(func), expr);
73678 		  set_opt3_any(cdr(expr), cadr(arg1));
73679 		}
73680 	      else
73681 		{
73682 		  set_optimize_op(expr, hop + OP_SAFE_C_PC);
73683 		  set_opt3_con(cdr(expr), cadr(arg2));
73684 		}
73685 	      set_unsafely_optimized(expr);
73686 	      choose_c_function(sc, expr, func, 2);
73687 	      return(OPT_F);
73688 	    }}
73689 
73690       if (func_is_safe)
73691 	{
73692 	  if (fx_count(sc, expr) == 2)
73693 	    return(check_c_aa(sc, expr, func, hop, e));
73694 	}
73695        else
73696 	{
73697 	  if (is_fxable(sc, arg1))
73698 	    {
73699 	      if (is_fxable(sc, arg2))
73700 		{
73701 		  if ((c_function_call(func) == g_apply) &&
73702 		      (is_normal_symbol(arg1)))
73703 		    {
73704 		      set_optimize_op(expr, OP_APPLY_SA);
73705 		      if ((is_pair(arg2)) &&
73706 			  (is_normal_symbol(car(arg2)))) /* arg2 might be ((if expr op1 op2) ...) */
73707 			{
73708 			  s7_pointer lister;
73709 			  lister = lookup(sc, car(arg2));
73710 			  if ((is_c_function(lister)) &&
73711 			      (is_pair(c_function_signature(lister))) &&
73712 			      (car(c_function_signature(lister)) == sc->is_proper_list_symbol))
73713 			    set_optimize_op(expr, OP_APPLY_SL);
73714 			}
73715 		      set_opt1_cfunc(expr, func); /* not quite set_c_function */
73716 		    }
73717 		  else set_unsafe_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_AA : OP_C_AA));
73718 		  fx_annotate_args(sc, cdr(expr), e);
73719 		  set_opt3_arglen(cdr(expr), int_two);
73720 		}
73721 	      else
73722 		{
73723 		  if (((c_function_call(func) == g_with_input_from_string) ||
73724 		       (c_function_call(func) == g_with_input_from_file) ||
73725 		       (c_function_call(func) == g_with_output_to_file)) &&
73726 		      (is_ok_lambda(sc, arg2)) &&
73727 		      (is_null(cadr(arg2))) &&
73728 		      (!direct_memq(car(arg2), e)))   /* lambda is redefined?? */
73729 		    {
73730 		      set_unsafe_optimize_op(expr, (is_string(arg1)) ? OP_WITH_IO_C : OP_WITH_IO);
73731 		      set_opt2_pair(expr, cddr(arg2));
73732 		      set_opt1_any(expr, (s7_pointer)io_function(sc, c_function_call(func)));
73733 		      return(OPT_F);
73734 		    }
73735 		  if (((c_function_call(func) == g_call_with_input_string) ||
73736 		       (c_function_call(func) == g_call_with_input_file) ||
73737 		       (c_function_call(func) == g_call_with_output_file)) &&
73738 		      (is_ok_lambda(sc, arg2)) &&
73739 		      (is_proper_list_1(sc, cadr(arg2))) &&
73740 		      (is_symbol(caadr(arg2))) &&
73741 		      (!is_probably_constant(caadr(arg2))) &&
73742 		      (!direct_memq(sc->lambda_symbol, e)))   /* lambda is redefined?? */
73743 		    {
73744 		      set_unsafe_optimize_op(expr, (is_string(arg1)) ? OP_WITH_IO_C : OP_WITH_IO);
73745 		      set_opt2_pair(expr, cddr(arg2));
73746 		      set_opt3_sym(expr, caadr(arg2));
73747 		      set_opt1_any(expr, (s7_pointer)io_function(sc, c_function_call(func)));
73748 		      return(OPT_F);
73749 		    }
73750 		  set_unsafe_optimize_op(expr, hop + OP_C_AP);
73751 		  fx_annotate_arg(sc, cdr(expr), e);
73752 		}
73753 	      choose_c_function(sc, expr, func, 2);
73754 	      return(OPT_F);
73755 	    }
73756 
73757 	  if ((has_safe_args(func)) &&
73758 	      (is_symbol(car(expr))) &&
73759 	      (car(expr) != sc->values_symbol) &&
73760 	      (is_fxable(sc, arg2)))
73761 	    {
73762 	      if ((is_pair(arg1)) &&
73763 		  (car(arg1) == sc->lambda_symbol))
73764 		{
73765 		  s7_pointer p;
73766 		  fx_annotate_arg(sc, cddr(expr), e);
73767 		  set_unsafe_optimize_op(expr, hop + OP_CL_FA);
73768 		  check_lambda(sc, arg1, true);      /* this changes symbol_list */
73769 
73770 		  clear_symbol_list(sc);               /* so restore it */
73771 		  for (p = e; is_pair(p); p = cdr(p))
73772 		    if (is_normal_symbol(car(p)))
73773 		      add_symbol_to_list(sc, car(p));
73774 
73775 		  choose_c_function(sc, expr, func, 2);
73776 		  if (((fn_proc(expr) == g_for_each) || (fn_proc(expr) == g_map)) &&
73777 		      (is_proper_list_1(sc, cadr(arg1))) &&
73778 		      (is_proper_list_1(sc, cddr(arg1))) &&
73779 		      (!is_possibly_constant(caadr(arg1))))
73780 		    {
73781 		      /* built-in permanent closure here was not much faster */
73782 		      set_fn(expr, (fn_proc(expr) == g_for_each) ? g_for_each_closure : NULL);
73783 		      set_opt3_pair(expr, cdr(arg1));
73784 		      set_unsafe_optimize_op(expr, OP_MAP_FA);
73785 		    }
73786 		  return(OPT_F);
73787 		}}}
73788       return(set_any_c_fp(sc, func, expr, e, 2, hop + OP_ANY_C_FP));
73789     }
73790 
73791   if (is_closure(func))
73792     {
73793       int32_t arit;
73794       bool one_form, safe_case;
73795       s7_pointer body;
73796 
73797       arit = closure_arity_to_int(sc, func);
73798       if (arit != 2)
73799 	{
73800 	  if ((arit == -1) &&
73801 	      (is_symbol(closure_args(func))))
73802 	    return(optimize_closure_dotted_args(sc, expr, func, hop, 2, e));
73803 	  return(OPT_F);
73804 	}
73805       if (is_immutable(func)) hop = 1;
73806 
73807       body = closure_body(func);
73808       one_form = is_null(cdr(body));
73809       safe_case = is_safe_closure(func);
73810 
73811       if ((pairs == 0) &&
73812 	  (symbols >= 1))
73813 	{
73814 	  set_unsafely_optimized(expr);
73815 	  set_opt1_lambda_add(expr, func);
73816 	  if (symbols == 2)
73817 	    {
73818 	      set_opt2_sym(expr, arg2);
73819 	      if (one_form)
73820 		{
73821 		  if (safe_case)
73822 		    {
73823 		      if (is_fxable(sc, car(body)))
73824 			{
73825 			  fx_annotate_arg(sc, body, e);
73826 			  fx_tree(sc, body, car(closure_args(func)), cadr(closure_args(func)));
73827 			  set_safe_optimize_op(expr, hop + OP_SAFE_CLOSURE_SS_A);
73828 			  /* fx_annotate_args(sc, cdr(expr), e); */
73829 			  set_closure_one_form_fx_arg(func);
73830 			  return(OPT_T);
73831 			}
73832 		      set_optimize_op(expr, hop + OP_SAFE_CLOSURE_SS_O);
73833 		    }
73834 		  else set_optimize_op(expr, hop + OP_CLOSURE_SS_O);
73835 		}
73836 	      else set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_SS : OP_CLOSURE_SS));
73837 	      return(OPT_F);
73838 	    }
73839 	  if (is_normal_symbol(arg1))
73840 	    {
73841 	      if (one_form)
73842 		set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_SC_O : OP_CLOSURE_SC_O)); /* _A case is very rare */
73843 	      else set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_SC : OP_CLOSURE_SC));
73844 	      set_opt2_con(expr, arg2);
73845 	      return(OPT_F);
73846 	    }}
73847 
73848       if ((!arglist_has_rest(sc, closure_args(func))) &&
73849 	  (fx_count(sc, expr) == 2))
73850 	{
73851 	  if (one_form)
73852 	    {
73853 	      if (safe_case)
73854 		{
73855 		  if (is_fxable(sc, car(body)))
73856 		    {
73857 		      fx_annotate_arg(sc, body, e);
73858 		      set_safe_optimize_op(expr, hop + OP_SAFE_CLOSURE_AA_A); /* safe_closure_as|sa_a? */
73859 		      set_closure_one_form_fx_arg(func);
73860 		      fx_annotate_args(sc, cdr(expr), e);
73861 		      set_opt1_lambda_add(expr, func);
73862 		      set_opt3_arglen(cdr(expr), int_two);
73863 		      return(OPT_T);
73864 		    }
73865 		  set_optimize_op(expr, hop + OP_SAFE_CLOSURE_AA_O);
73866 		}
73867 	      else set_optimize_op(expr, hop + OP_CLOSURE_AA_O);
73868 	    }
73869 	  else set_safe_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_AA : OP_CLOSURE_AA));
73870 	  fx_annotate_args(sc, cdr(expr), e);
73871 	  set_opt1_lambda_add(expr, func);
73872 	  set_opt3_arglen(cdr(expr), int_two);
73873 	  return(OPT_F);
73874 	}
73875 
73876       if (is_fxable(sc, arg1))
73877 	{
73878 	  set_unsafely_optimized(expr);
73879 	  fx_annotate_arg(sc, cdr(expr), e);
73880 	  set_safe_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_AP : OP_CLOSURE_AP));
73881 	  set_opt1_lambda_add(expr, func);
73882 	  set_opt3_arglen(cdr(expr), int_two); /* for op_unknown_fp */
73883 	  return(OPT_F);
73884 	}
73885 
73886       if ((is_pair(arg1)) &&
73887 	  (car(arg1) == sc->lambda_symbol) &&
73888 	  (is_pair(cdr(arg1))) &&              /* not (lambda) */
73889 	  (is_fxable(sc, arg2)) &&
73890 	  (is_null(cdr(closure_body(func)))))
73891 	{
73892 	  s7_pointer p;
73893 	  fx_annotate_arg(sc, cddr(expr), e);
73894 	  set_opt2_pair(expr, cdr(arg1));
73895 	  set_unsafe_optimize_op(expr, hop + OP_CLOSURE_FA);
73896 	  check_lambda(sc, arg1, false);
73897 
73898 	  clear_symbol_list(sc);
73899 	  for (p = e; is_pair(p); p = cdr(p))
73900 	    if (is_normal_symbol(car(p)))
73901 	      add_symbol_to_list(sc, car(p));
73902 
73903 	  /* check_lambda calls optimize_lambda if define in progress, else just optimize on the body */
73904 	  clear_safe_closure_body(cddr(arg1)); /* otherwise we need to fixup the local let for the optimizer -- what is this about? */
73905 	  set_opt1_lambda_add(expr, func);
73906 	  return(OPT_F);
73907 	}
73908 
73909       if (is_fxable(sc, arg2))
73910 	{
73911 	  set_unsafely_optimized(expr);
73912 	  fx_annotate_arg(sc, cddr(expr), e);
73913 	  set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_PA : OP_CLOSURE_PA));
73914 	  set_opt1_lambda_add(expr, func);
73915 	  set_opt3_arglen(cdr(expr), int_two); /* for op_unknown_fp */
73916 	  return(OPT_F);
73917 	}
73918 
73919       if (is_safe_closure(func)) /* clo* too */
73920 	return(set_any_closure_fp(sc, func, expr, e, 2, hop + OP_SAFE_CLOSURE_PP));
73921 
73922       set_unsafely_optimized(expr);
73923       set_optimize_op(expr, hop + OP_CLOSURE_PP);
73924       set_opt1_lambda_add(expr, func);
73925       set_opt3_arglen(cdr(expr), int_two); /* for op_unknown_fp */
73926       return(OPT_F);
73927     }
73928 
73929   if (is_closure_star(func))
73930     {
73931       if (is_immutable(func)) hop = 1;
73932       if (fx_count(sc, expr) == 2)
73933 	{
73934 	  int32_t arity;
73935 	  bool safe_case;
73936 	  s7_pointer par1;
73937 
73938 	  safe_case = is_safe_closure(func);
73939 	  arity = closure_star_arity_to_int(sc, func);
73940 	  set_unsafely_optimized(expr);
73941 	  par1 = car(closure_args(func));
73942 	  if (is_pair(par1)) par1 = car(par1);
73943 
73944 	  if ((arity == 1) && (is_keyword(arg1)) && (keyword_symbol(arg1) == par1))
73945 	    set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_KA : OP_CLOSURE_STAR_KA));
73946 	  else
73947 	    {
73948 	      if ((lambda_has_simple_defaults(func)) && (arity == 2))
73949 		set_optimize_op(expr, hop + ((is_safe_closure(func)) ? ((is_null(cdr(closure_body(func)))) ? OP_SAFE_CLOSURE_STAR_AA_O :
73950 									OP_SAFE_CLOSURE_STAR_AA) : OP_CLOSURE_STAR_ALL_A));
73951 	      else set_optimize_op(expr, hop + ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_STAR_ALL_A_2 : OP_CLOSURE_STAR_ALL_A));
73952 	    }
73953 	  fx_annotate_args(sc, cdr(expr), e);
73954 	  set_opt1_lambda_add(expr, func);
73955 	  set_opt3_arglen(cdr(expr), int_two);
73956 	  return(OPT_F);
73957 	}}
73958 
73959   if ((is_c_function_star(func)) &&
73960       (fx_count(sc, expr) == 2) &&
73961       (c_function_all_args(func) >= 1) &&
73962       (!is_keyword(arg2)))
73963     {
73964       if ((hop == 0) && (symbol_id(car(expr)) == 0) && (!sc->in_with_let)) hop = 1;
73965       set_optimized(expr);
73966       set_optimize_op(expr, hop + OP_SAFE_C_FUNCTION_STAR_AA); /* k+c? = cc */
73967       fx_annotate_args(sc, cdr(expr), e);
73968       set_opt3_arglen(cdr(expr), int_two);
73969       set_c_function(expr, func);
73970       return(OPT_T);
73971     }
73972 
73973   if ((is_any_vector(func)) &&
73974       (is_fxable(sc, arg1)) &&
73975       (is_fxable(sc, arg2)))
73976     {
73977       set_unsafe_optimize_op(expr, OP_IMPLICIT_VECTOR_REF_AA);
73978       fx_annotate_args(sc, cdr(expr), e);
73979       set_opt3_arglen(cdr(expr), int_two);
73980       return(OPT_T);
73981     }
73982   return((is_optimized(expr)) ? OPT_T : OPT_F);
73983 }
73984 
73985 static opt_t optimize_safe_c_func_three_args(s7_scheme *sc, s7_pointer expr, s7_pointer func, int32_t hop, int32_t pairs, int32_t symbols, int32_t quotes, s7_pointer e)
73986 {
73987   s7_pointer arg1, arg2, arg3;
73988   arg1 = cadr(expr);
73989   arg2 = caddr(expr);
73990   arg3 = cadddr(expr);
73991   if (pairs == 0)
73992     {
73993       set_optimized(expr);
73994       if (symbols == 0)
73995 	set_optimize_op(expr, hop + OP_SAFE_C_D);
73996       else
73997 	{
73998 	  if (symbols == 3)
73999 	    {
74000 	      set_optimize_op(expr, hop + OP_SAFE_C_SSS);
74001 	      set_opt1_sym(cdr(expr), arg2);
74002 	      set_opt2_sym(cdr(expr), arg3);
74003 	    }
74004 	  else
74005 	    {
74006 	      if (symbols == 2)
74007 		{
74008 		  if (!is_normal_symbol(arg1))
74009 		    {
74010 		      set_optimize_op(expr, hop + OP_SAFE_C_CSS);
74011 		      set_opt1_sym(cdr(expr), arg2);
74012 		      set_opt2_sym(cdr(expr), arg3);
74013 		    }
74014 		  else
74015 		    {
74016 		      if (!is_normal_symbol(arg3))
74017 			{
74018 			  set_opt2_con(cdr(expr), arg3);
74019 			  set_opt1_sym(cdr(expr), arg2);
74020 			  set_optimize_op(expr, hop + OP_SAFE_C_SSC);
74021 			}
74022 		      else
74023 			{
74024 			  set_opt1_con(cdr(expr), arg2);
74025 			  set_opt2_sym(cdr(expr), arg3);
74026 			  set_optimize_op(expr, hop + OP_SAFE_C_SCS);
74027 			}}}
74028 	      else
74029 		{
74030 		  if (is_normal_symbol(arg1))
74031 		    {
74032 		      set_opt1_con(cdr(expr), arg2);
74033 		      set_opt2_con(cdr(expr), arg3);
74034 		      set_optimize_op(expr, hop + OP_SAFE_C_SCC);
74035 		    }
74036 		  else
74037 		    {
74038 		      if (is_normal_symbol(arg2))
74039 			{
74040 			  set_opt1_sym(cdr(expr), arg2);
74041 			  set_opt2_con(cdr(expr), arg3);
74042 			  set_opt3_con(cdr(expr), arg1);
74043 			  set_optimize_op(expr, hop + OP_SAFE_C_CSC);
74044 			}
74045 		      else
74046 			{
74047 			  set_opt1_sym(cdr(expr), arg3);
74048 			  set_opt2_con(cdr(expr), arg2);
74049 			  set_opt3_con(cdr(expr), arg1);
74050 			  set_optimize_op(expr, hop + OP_SAFE_C_CCS);
74051 			}}}}}
74052       choose_c_function(sc, expr, func, 3);
74053       return(OPT_T);
74054     }
74055 
74056   /* pairs != 0 */
74057   if (fx_count(sc, expr) == 3)
74058     {
74059       set_optimized(expr);
74060       if (quotes == 1)
74061 	{
74062 	  if ((symbols == 2) &&
74063 	      (is_normal_symbol(arg1)) &&
74064 	      (is_normal_symbol(arg3)))
74065 	    {
74066 	      set_opt1_con(cdr(expr), cadr(arg2));        /* fx_c_scs uses opt1_con */
74067 	      set_opt2_sym(cdr(expr), arg3);
74068 	      set_optimize_op(expr, hop + OP_SAFE_C_SCS); /* used to be SQS */
74069 	      choose_c_function(sc, expr, func, 3);
74070 	      return(OPT_T);
74071 	    }
74072 	  if (symbols == 1)
74073 	    {
74074 	      if ((is_normal_symbol(arg3)) &&
74075 		  (is_proper_quote(sc, arg2)) &&
74076 		  (is_safe_c_s(arg1)))
74077 		{
74078 		  set_safe_optimize_op(expr, hop + OP_SAFE_C_opSq_CS);
74079 		  set_opt1_con(cdr(expr), cadr(arg2)); /* opt1_con is T_Pos (unchecked) */
74080 		  set_opt2_sym(cdr(expr), arg3);
74081 		  set_opt3_sym(cdr(expr), cadr(arg1));
74082 		  choose_c_function(sc, expr, func, 3);
74083 		  return(OPT_T);
74084 		}
74085 	      if ((is_normal_symbol(arg2)) &&
74086 		  (is_proper_quote(sc, arg1)) &&
74087 		  (!is_pair(arg3)))
74088 		{
74089 		  set_optimize_op(expr, hop + OP_SAFE_C_CSC);
74090 		  set_opt1_sym(cdr(expr), arg2);
74091 		  set_opt2_con(cdr(expr), arg3);
74092 		  set_opt3_con(cdr(expr), cadr(arg1));
74093 		  choose_c_function(sc, expr, func, 3);
74094 		  return(OPT_T);
74095 		}}}
74096 
74097       fx_annotate_args(sc, cdr(expr), e);
74098       set_opt3_arglen(cdr(expr), int_three);
74099       set_opt3_pair(expr, cddr(expr));
74100       set_optimize_op(expr, hop + OP_SAFE_C_AAA);
74101 
74102       if (pairs == 1)
74103 	{
74104 	  if ((symbols == 0) && (is_pair(arg2)))
74105 	    set_optimize_op(expr, hop + OP_SAFE_C_CAC);
74106 	  else
74107 	    {
74108 	      if ((symbols == 1) && (is_pair(arg3)))
74109 		set_optimize_op(expr, hop + ((is_normal_symbol(arg2)) ? OP_SAFE_C_CSA : OP_SAFE_C_SCA));
74110 	      else
74111 		{
74112 		  if (symbols == 2)
74113 		    {
74114 		      if (is_normal_symbol(arg1))
74115 			{
74116 			  if (is_normal_symbol(arg2))
74117 			    {
74118 			      if ((hop == 1) && (s7_p_ppp_function(func)))
74119 				{
74120 				  set_optimize_op(expr, HOP_SSA_DIRECT);
74121 				  clear_has_fx(cdr(expr));
74122 				  set_opt2_direct(cdr(expr), (s7_pointer)(s7_p_ppp_function(func)));
74123 				}
74124 			      else set_optimize_op(expr, hop + OP_SAFE_C_SSA);
74125 			    }
74126 			  else set_optimize_op(expr, hop + OP_SAFE_C_SAS);
74127 			}
74128 		      else
74129 			if (is_pair(arg1))
74130 			  set_optimize_op(expr, hop + OP_SAFE_C_ASS);
74131 		    }}}}
74132       else
74133 	if ((is_normal_symbol(arg1)) && (pairs == 2))
74134 	  set_optimize_op(expr, hop + OP_SAFE_C_SAA);
74135 
74136       choose_c_function(sc, expr, func, 3);
74137       return(OPT_T);
74138     }
74139   return(OPT_F); /* tell caller to try something else */
74140 }
74141 
74142 static opt_t optimize_func_three_args(s7_scheme *sc, s7_pointer expr, s7_pointer func, int32_t hop,
74143 				      int32_t pairs, int32_t symbols, int32_t quotes, int32_t bad_pairs, s7_pointer e)
74144 {
74145   s7_pointer arg1, arg2, arg3;
74146 
74147   if ((quotes > 0) &&
74148       (direct_memq(sc->quote_symbol, e)))
74149     return(OPT_OOPS);
74150 
74151   arg1 = cadr(expr);
74152   arg2 = caddr(expr);
74153   arg3 = cadddr(expr);
74154 
74155   if (((is_symbol(arg1)) &&
74156        (!arg_findable(sc, arg1, e))) ||
74157       ((is_symbol(arg2)) &&
74158        (!arg_findable(sc, arg2, e))) ||
74159       ((is_symbol(arg3)) &&
74160        (!arg_findable(sc, arg3, e))))
74161     {
74162       /* wrap bad args */
74163       if ((is_fxable(sc, arg1)) &&
74164 	  (is_fxable(sc, arg2)) &&
74165 	  (is_fxable(sc, arg3)) &&
74166 	  (s7_is_aritable(sc, func, 3)))
74167 	{
74168 	  fx_annotate_args(sc, cdr(expr), e);
74169 	  set_opt3_arglen(cdr(expr), int_three);
74170 	  if (is_c_function(func))
74171 	    {
74172 	      if (is_safe_procedure(func))
74173 		{
74174 		  set_safe_optimize_op(expr, hop + OP_SAFE_C_AAA);
74175 		  set_opt3_pair(cdr(expr), cdddr(expr));
74176 		  set_opt3_pair(expr, cddr(expr));
74177 		}
74178 	      else set_safe_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_ALL_A : OP_C_ALL_A));
74179 	      set_c_function(expr, func);
74180 	      return(OPT_T);
74181 	    }
74182 	  if ((is_closure(func)) &&
74183 	      (closure_arity_to_int(sc, func) == 3) &&
74184 	      (!arglist_has_rest(sc, closure_args(func))))
74185 	    {
74186 	      set_unsafely_optimized(expr);
74187 	      set_optimize_op(expr, hop + ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_ALL_A : OP_CLOSURE_3A));
74188 	      set_opt1_lambda_add(expr, func);
74189 	      return(OPT_F);
74190 	    }
74191 	  if ((is_closure_star(func)) &&
74192 	      (lambda_has_simple_defaults(func)) &&
74193 	      (closure_star_arity_to_int(sc, func) != 0) &&
74194 	      (closure_star_arity_to_int(sc, func) != 1))
74195 	    {
74196 	      set_unsafely_optimized(expr);
74197 	      set_optimize_op(expr, ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_STAR_ALL_A : OP_CLOSURE_STAR_ALL_A));
74198 	      set_opt1_lambda_add(expr, func);
74199 	    }}
74200       return(OPT_F);
74201     }  /* end of bad symbol wrappers */
74202 
74203   if ((bad_pairs == quotes) &&
74204       (is_symbol(car(expr))) &&
74205       (is_constant_symbol(sc, car(expr))))
74206     hop = 1;
74207 
74208   if (is_c_function(func) &&
74209       (c_function_required_args(func) <= 3) &&
74210       (c_function_all_args(func) >= 3))
74211     {
74212       if ((hop == 0) && (symbol_id(car(expr)) == 0) && (!sc->in_with_let)) hop = 1;
74213       if ((is_safe_procedure(func)) ||
74214 	  ((is_maybe_safe(func)) && (unsafe_is_safe(sc, arg3, e))))
74215 	{
74216 	  if (optimize_safe_c_func_three_args(sc, expr, func, hop, pairs, symbols, quotes, e) == OPT_T)
74217 	    return(OPT_T);
74218 	  if ((is_normal_symbol(arg1)) && (is_normal_symbol(arg2)))
74219 	    {
74220 	      set_opt3_pair(expr, arg3);
74221 	      set_unsafe_optimize_op(expr, hop + OP_SAFE_C_SSP);
74222 	      choose_c_function(sc, expr, func, 3);
74223 	      return(OPT_F);
74224 	    }
74225 	  return(set_any_c_fp(sc, func, expr, e, 3, hop + OP_ANY_C_FP));
74226 	}
74227       /* func is not safe */
74228       if (fx_count(sc, expr) == 3)
74229 	{
74230 	  set_optimized(expr);
74231 	  fx_annotate_args(sc, cdr(expr), e);
74232 	  set_opt3_arglen(cdr(expr), int_three);
74233 	  if (has_safe_args(func))
74234 	    set_optimize_op(expr, hop + (((is_normal_symbol(arg1)) && (is_normal_symbol(arg3))) ? OP_CL_SAS : OP_CL_ALL_A));
74235 	  else set_optimize_op(expr, hop + OP_C_ALL_A);
74236 	  choose_c_function(sc, expr, func, 3);
74237 	  set_unsafe(expr);
74238 	  return(OPT_F);
74239 	}
74240 
74241       /* (define (hi) (catch #t (lambda () 1) (lambda args 2)))
74242        *   first arg list must be (), second a symbol
74243        */
74244       if (c_function_call(func) == g_catch)
74245 	{
74246 	  if (((bad_pairs == 2) && (!is_pair(arg1))) ||
74247 	      ((bad_pairs == 3) && (car(arg1) == sc->quote_symbol)))
74248 	    {
74249 	      s7_pointer body_lambda, error_lambda;
74250 	      body_lambda = arg2;
74251 	      error_lambda = arg3;
74252 	      if ((is_ok_lambda(sc, body_lambda)) &&
74253 		  (is_ok_lambda(sc, error_lambda)) &&
74254 		  (is_null(cadr(body_lambda))) &&
74255 		  (((is_symbol(cadr(error_lambda))) &&              /* (lambda args ... */
74256 		    (!is_probably_constant(cadr(error_lambda)))) ||
74257 		   ((is_pair(cadr(error_lambda))) &&                /* (lambda (type info) ... */
74258 		    (is_pair(cdadr(error_lambda))) &&
74259 		    (is_null(cddadr(error_lambda))) &&
74260 		    (!is_probably_constant(caadr(error_lambda))) && /* (lambda (pi ...) ...) */
74261 		    (!is_probably_constant(cadadr(error_lambda))))))
74262 		{
74263 		  s7_pointer error_result;
74264 		  error_result = caddr(error_lambda);
74265 		  set_unsafely_optimized(expr);
74266 		  if ((arg1 == sc->T) &&                              /* tag is #t */
74267 		      (is_null(cdddr(error_lambda))) &&               /* error lambda body is one expr */
74268 		      ((!is_symbol(error_result)) ||                  /* (lambda args #f) */
74269 		       ((is_pair(cadr(error_lambda))) &&
74270 			(error_result == caadr(error_lambda)))) &&    /* (lambda (type info) type) */
74271 		      ((!is_pair(error_result)) ||
74272 		       (car(error_result) == sc->quote_symbol) ||     /* (lambda args 'a) */
74273 		       ((car(error_result) == sc->car_symbol) &&
74274 			(cadr(error_result) == cadr(error_lambda))))) /* (lambda args (car args) -> error-type */
74275 		    {
74276 		      set_optimize_op(expr, hop + OP_C_CATCH_ALL);    /* catch_all* = #t tag, error handling can skip to the simple lambda body */
74277 		      set_c_function(expr, func);
74278 		      set_opt2_con(expr, error_result);
74279 		      set_opt1_pair(cdr(expr), cddr(body_lambda));
74280 		      if (is_null(cdddr(body_lambda)))
74281 			{
74282 			  if (is_fxable(sc, caddr(body_lambda)))
74283 			    {
74284 			      set_optimize_op(expr, hop + OP_C_CATCH_ALL_A);
74285 			      set_fx_direct(cddr(body_lambda), fx_choose(sc, cddr(body_lambda), sc->curlet, let_symbol_is_safe));
74286 			    }
74287 			  else
74288 			    {
74289 			      set_opt1_pair(cdr(expr), caddr(body_lambda));
74290 			      set_optimize_op(expr, hop + OP_C_CATCH_ALL_O);
74291 			      /* fn got no hits */
74292 			    }}}
74293 		  else
74294 		    {
74295 		      set_optimize_op(expr, hop + OP_C_CATCH); /* mainly c_catch_p, but this is not a common case */
74296 		      choose_c_function(sc, expr, func, 3);
74297 		    }
74298 		  return(OPT_F);
74299 		}}}
74300       return(set_any_c_fp(sc, func, expr, e, 3, hop + OP_ANY_C_FP)); /* safe == unsafe here */
74301     }
74302 
74303   /* not c func */
74304   if (is_closure(func))
74305     {
74306       int32_t arit;
74307 
74308       arit = closure_arity_to_int(sc, func);
74309       if (arit != 3)
74310 	{
74311 	  if ((arit == -1) &&
74312 	      (is_symbol(closure_args(func))))
74313 	    return(optimize_closure_dotted_args(sc, expr, func, hop, 3, e));
74314 	  return(OPT_F);
74315 	}
74316       if (is_immutable(func)) hop = 1;
74317 
74318       if (symbols == 3)
74319 	{
74320 	  s7_pointer body;
74321 	  body = closure_body(func);
74322 	  set_opt1_lambda_add(expr, func);
74323 	  set_opt3_arglen(cdr(expr), int_three);
74324 
74325 	  if (is_safe_closure(func))
74326 	    {
74327 	      if ((is_null(cdr(body))) &&
74328 		  (is_fxable(sc, car(body))))
74329 		{
74330 		  set_opt2_sym(expr, arg2);
74331 		  set_opt3_sym(expr, arg3);
74332 		  fx_annotate_arg(sc, body, e);
74333 		  fx_tree(sc, body, car(closure_args(func)), cadr(closure_args(func)));
74334 		  set_safe_optimize_op(expr, hop + OP_SAFE_CLOSURE_3S_A);
74335 		  set_closure_one_form_fx_arg(func);
74336 		}
74337 	      else set_optimize_op(expr, hop + OP_SAFE_CLOSURE_3S);
74338 	      return(OPT_T);
74339 	    }
74340 	  set_unsafe_optimize_op(expr, hop + OP_CLOSURE_3S);
74341 	  return(OPT_F);
74342 	}
74343 
74344       if (fx_count(sc, expr) == 3)
74345 	{
74346 	  if (is_safe_closure(func))
74347 	    {
74348 	      if ((!is_pair(arg2)) && (!is_pair(arg3)))
74349 		set_optimize_op(expr, hop + OP_SAFE_CLOSURE_AGG);
74350 	      else
74351 		{
74352 		  if (is_normal_symbol(arg1))
74353 		    set_optimize_op(expr, hop + ((is_normal_symbol(arg2)) ? OP_SAFE_CLOSURE_SSA : OP_SAFE_CLOSURE_SAA));
74354 		  else set_optimize_op(expr, hop + OP_SAFE_CLOSURE_ALL_A);
74355 		}}
74356 	  else
74357 	    {
74358 	      if ((is_normal_symbol(arg2)) && (is_normal_symbol(arg3)))
74359 		set_optimize_op(expr, hop + OP_CLOSURE_ASS);
74360 	      else
74361 		{
74362 		  if (is_normal_symbol(arg1))
74363 		    set_optimize_op(expr, hop + ((is_normal_symbol(arg3)) ? OP_CLOSURE_SAS : OP_CLOSURE_SAA));
74364 		  else
74365 		    {
74366 		      if (is_normal_symbol(arg3))
74367 			set_optimize_op(expr, hop + OP_CLOSURE_AAS);
74368 		      else
74369 			{
74370 			  if (is_normal_symbol(arg2))
74371 			    set_optimize_op(expr, hop + OP_CLOSURE_ASA);
74372 			  else set_optimize_op(expr, hop + OP_CLOSURE_3A);
74373 			}}}}
74374 	  set_unsafely_optimized(expr);
74375 	  fx_annotate_args(sc, cdr(expr), e);
74376 	  set_opt1_lambda_add(expr, func);
74377 	  set_opt3_arglen(cdr(expr), int_three);
74378 	  return(OPT_F);
74379 	}
74380       return(set_any_closure_fp(sc, func, expr, e, 3, hop + OP_ANY_CLOSURE_3P));
74381     }
74382 
74383   if (is_closure_star(func))
74384     {
74385       if ((!lambda_has_simple_defaults(func)) ||
74386 	  (closure_star_arity_to_int(sc, func) == 0) ||
74387 	  (closure_star_arity_to_int(sc, func) == 1))
74388 	return(OPT_F);
74389       if (fx_count(sc, expr) == 3)
74390 	{
74391 	  if (is_immutable(func)) hop = 1;
74392 	  set_unsafe_optimize_op(expr, hop + ((is_safe_closure(func) ? OP_SAFE_CLOSURE_STAR_ALL_A : OP_CLOSURE_STAR_ALL_A)));
74393 	  fx_annotate_args(sc, cdr(expr), e);
74394 	  set_opt1_lambda_add(expr, func);
74395 	  set_opt3_arglen(cdr(expr), int_three);
74396 	  return(OPT_F);
74397 	}}
74398 
74399   if ((is_c_function_star(func)) &&
74400       (fx_count(sc, expr) == 3) &&
74401       (c_function_all_args(func) >= 2))
74402     {
74403       set_safe_optimize_op(expr, hop + OP_SAFE_C_FUNCTION_STAR_ALL_A);
74404       fx_annotate_args(sc, cdr(expr), e);
74405       set_opt3_arglen(cdr(expr), int_three);
74406       set_c_function(expr, func);
74407       return(OPT_T);
74408     }
74409 
74410   if (bad_pairs > quotes) return(OPT_F);
74411   return((is_optimized(expr)) ? OPT_T : OPT_F);
74412 }
74413 
74414 static bool symbols_are_safe(s7_scheme *sc, s7_pointer args, s7_pointer e)
74415 {
74416   s7_pointer p;
74417   for (p = args; is_pair(p); p = cdr(p))
74418     {
74419       s7_pointer arg;
74420       arg = car(p);
74421       if ((is_normal_symbol(arg)) &&
74422 	  (!arg_findable(sc, arg, e)))
74423 	return(false);
74424     }
74425   return(true);
74426 }
74427 
74428 static opt_t optimize_func_many_args(s7_scheme *sc, s7_pointer expr, s7_pointer func, int32_t hop, int32_t args, int32_t pairs, int32_t symbols, int32_t quotes, int32_t bad_pairs, s7_pointer e)
74429 {
74430   bool func_is_closure;
74431   if (quotes > 0)
74432     {
74433       if (direct_memq(sc->quote_symbol, e))
74434 	return(OPT_OOPS);
74435       if ((bad_pairs == quotes) &&
74436 	  (is_symbol(car(expr))) &&
74437 	  (is_constant_symbol(sc, car(expr))))
74438 	hop = 1;
74439     }
74440 
74441   if ((is_c_function(func)) &&
74442       (c_function_required_args(func) <= args) &&
74443       (c_function_all_args(func) >= args))
74444     {
74445       if ((hop == 0) && (symbol_id(car(expr)) == 0) && (!sc->in_with_let)) hop = 1;
74446       if (is_safe_procedure(func))
74447 	{
74448 	  if (pairs == 0)
74449 	    {
74450 	      if (symbols == 0)
74451 		{
74452 		  set_safe_optimize_op(expr, hop + OP_SAFE_C_D);
74453 		  choose_c_function(sc, expr, func, args);
74454 		  return(OPT_T);
74455 		}
74456 	      if (symbols == args)
74457 		{
74458 		  if (symbols_are_safe(sc, cdr(expr), e))
74459 		    set_safe_optimize_op(expr, hop + OP_SAFE_C_ALL_S);
74460 		  else
74461 		    {
74462 		      set_safe_optimize_op(expr, hop + ((args == 4) ? OP_SAFE_C_4A : OP_SAFE_C_ALL_A));
74463 		      fx_annotate_args(sc, cdr(expr), e);
74464 		    }
74465 		  set_opt3_arglen(cdr(expr), make_permanent_integer(args));
74466 		  choose_c_function(sc, expr, func, args);
74467 		  return(OPT_T);
74468 		}}
74469 
74470 	  if (fx_count(sc, expr) == args)
74471 	    {
74472 	      s7_pointer p;
74473 	      set_optimized(expr);
74474 	      set_optimize_op(expr, hop + ((args == 4) ? OP_SAFE_C_4A : OP_SAFE_C_ALL_A));
74475 	      fx_annotate_args(sc, cdr(expr), e);
74476 	      set_opt3_arglen(cdr(expr), make_permanent_integer(args));
74477 	      choose_c_function(sc, expr, func, args);
74478 
74479 	      for (p = cdr(expr); (is_pair(p)) && (is_pair(cdr(p))); p = cddr(p))
74480 		{
74481 		  if (is_normal_symbol(car(p)))
74482 		    break;
74483 		  if ((is_pair(car(p))) &&
74484 		      ((!is_pair(cdar(p))) || (caar(p) != sc->quote_symbol)))
74485 		    break;
74486 		}
74487 	      if (is_null(p))
74488 		{
74489 		  set_optimize_op(expr, hop + ((fn_proc(expr) == g_simple_inlet) ? OP_SAFE_C_INLET_CA : OP_SAFE_C_ALL_CA));
74490 		  for (p = cdr(expr); is_pair(p); p = cddr(p))
74491 		    {
74492 		      clear_has_fx(p);
74493 		      set_opt2_con(p, (is_pair(car(p))) ? cadar(p) : car(p));
74494 		    }}
74495 	      return(OPT_T);
74496 	    }
74497 	  if (args < GC_TRIGGER_SIZE)
74498 	    return(set_any_c_fp(sc, func, expr, e, args, hop + OP_ANY_C_FP));
74499 	}
74500       else /* c_func is not safe */
74501 	{
74502 	  if (fx_count(sc, expr) == args) /* trigger_size doesn't matter for unsafe funcs */
74503 	    {
74504 	      set_unsafe_optimize_op(expr, hop + ((has_safe_args(func)) ? OP_CL_ALL_A : OP_C_ALL_A));
74505 	      fx_annotate_args(sc, cdr(expr), e);
74506 	      set_opt3_arglen(cdr(expr), make_permanent_integer(args));
74507 	      choose_c_function(sc, expr, func, args);
74508 	      return(OPT_F);
74509 	    }
74510 	  return(set_any_c_fp(sc, func, expr, e, args, hop + OP_ANY_C_FP)); /* was num_args=3! 2-Sep-20 */
74511 	}
74512       return((is_optimized(expr)) ? OPT_T : OPT_F);
74513     }
74514 
74515   func_is_closure = is_closure(func);
74516   if (func_is_closure)
74517     {
74518       int32_t arit;
74519 
74520       arit = closure_arity_to_int(sc, func);
74521       if (arit != args)
74522 	{
74523 	  if ((arit == -1) &&
74524 	      (is_symbol(closure_args(func))))
74525 	    return(optimize_closure_dotted_args(sc, expr, func, hop, args, e));
74526 	  return(OPT_F);
74527 	}
74528       if (is_immutable(func)) hop = 1;
74529 
74530       if ((fx_count(sc, expr) == args) &&
74531 	  (args < GC_TRIGGER_SIZE))
74532 	{
74533 	  bool safe_case;
74534 	  set_unsafely_optimized(expr);
74535 	  safe_case = is_safe_closure(func);
74536 	  set_unsafe_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_ALL_A : ((args == 4) ? OP_CLOSURE_4A : OP_CLOSURE_ALL_A)));
74537 	  fx_annotate_args(sc, cdr(expr), e);
74538 	  set_opt3_arglen(cdr(expr), make_permanent_integer(args));
74539 	  set_opt1_lambda_add(expr, func);
74540 
74541 	  if ((symbols == args) &&
74542 	      (symbols_are_safe(sc, cdr(expr), e)))
74543 	    {
74544 	      if (safe_case)
74545 		set_optimize_op(expr, hop + OP_SAFE_CLOSURE_ALL_S);
74546 	      else set_optimize_op(expr, hop + ((args == 4) ? OP_CLOSURE_4S : OP_CLOSURE_ALL_S));
74547 	    }
74548 	  return(OPT_F);
74549 	}
74550 
74551       if (args == 4)
74552 	return(set_any_closure_fp(sc, func, expr, e, 4, hop + OP_ANY_CLOSURE_4P));
74553       if (args < GC_TRIGGER_SIZE)
74554 	return(set_any_closure_fp(sc, func, expr, e, args, hop + OP_ANY_CLOSURE_FP));
74555     }
74556 
74557   if ((is_closure_star(func)) &&
74558       ((!lambda_has_simple_defaults(func)) ||
74559        (closure_star_arity_to_int(sc, func) == 0) ||
74560        (closure_star_arity_to_int(sc, func) == 1)))
74561     return(OPT_F);
74562 
74563   if ((is_c_function_star(func)) &&
74564       (fx_count(sc, expr) == args) &&
74565       (c_function_all_args(func) >= (args / 2)))
74566     {
74567       if (is_immutable(func)) hop = 1;
74568       set_safe_optimize_op(expr, hop + OP_SAFE_C_FUNCTION_STAR_ALL_A);
74569       fx_annotate_args(sc, cdr(expr), e);
74570       set_opt3_arglen(cdr(expr), make_permanent_integer(args));
74571       set_c_function(expr, func);
74572       return(OPT_T);
74573     }
74574 
74575   if (args < GC_TRIGGER_SIZE)
74576     {
74577       if (((func_is_closure) ||
74578 	   (is_closure_star(func))) &&
74579 	  (fx_count(sc, expr) == args))
74580 	{
74581 	  set_unsafely_optimized(expr);
74582 	  if (func_is_closure)
74583 	    set_optimize_op(expr, hop + ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_ALL_A : ((args == 4) ? OP_CLOSURE_4A : OP_CLOSURE_ALL_A)));
74584 	  else set_optimize_op(expr, hop + ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_STAR_ALL_A : OP_CLOSURE_STAR_ALL_A));
74585 	  fx_annotate_args(sc, cdr(expr), e);
74586 	  set_opt3_arglen(cdr(expr), make_permanent_integer(args));
74587 	  set_opt1_lambda_add(expr, func);
74588 	  return(OPT_F);
74589 	}}
74590   return((is_optimized(expr)) ? OPT_T : OPT_F);
74591 }
74592 
74593 static bool vars_syntax_ok(s7_pointer vars)
74594 {
74595   s7_pointer p;
74596   for (p = vars; is_pair(p); p = cdr(p))
74597     {
74598       s7_pointer var;
74599       var = car(p);
74600       if ((!is_pair(var)) ||
74601 	  (!is_symbol(car(var))) ||
74602 	  (!is_pair(cdr(var))))
74603 	return(false);
74604     }
74605   return(true);
74606 }
74607 
74608 static opt_t optimize_expression(s7_scheme *sc, s7_pointer expr, int32_t hop, s7_pointer e, bool export_ok);
74609 
74610 static bool vars_opt_ok(s7_scheme *sc, s7_pointer vars, int32_t hop, s7_pointer e)
74611 {
74612   s7_pointer p;
74613   for (p = vars; is_pair(p); p = cdr(p))
74614     {
74615       s7_pointer init;
74616       init = cadar(p);
74617       if ((is_pair(init)) &&
74618 	  (!is_checked(init)) &&
74619 	  (optimize_expression(sc, init, hop, e, false) == OPT_OOPS))
74620 	return(false);
74621     }
74622   return(true);
74623 }
74624 
74625 static opt_t optimize_syntax(s7_scheme *sc, s7_pointer expr, s7_pointer func, int32_t hop, s7_pointer e, bool export_ok)
74626 {
74627   opcode_t op;
74628   s7_pointer p, body, vars;
74629   bool body_export_ok = true;
74630 
74631   op = (opcode_t)syntax_opcode(func);
74632   sc->w = e;
74633   body = cdr(expr);
74634 
74635   switch (op)
74636     {
74637     case OP_QUOTE:
74638     case OP_MACROEXPAND:
74639       return((is_proper_list_1(sc, body)) ? OPT_F : OPT_OOPS);
74640 
74641     case OP_LET:
74642     case OP_LETREC:
74643     case OP_LET_STAR:
74644     case OP_LETREC_STAR:
74645       if (is_symbol(cadr(expr)))
74646 	{
74647 	  if (!is_pair(cddr(expr))) /* (let name . x) */
74648 	    return(OPT_F);
74649 	  vars = caddr(expr);
74650 	  if (!is_list(vars)) return(OPT_OOPS);
74651 	  body = cdddr(expr);
74652 	}
74653       else
74654 	{
74655 	  vars = cadr(expr);
74656 	  body = cddr(expr);
74657 	  if (is_null(vars))
74658 	    e = cons(sc, sc->nil, e); /* () in e = empty let */
74659 	  else
74660 	    if (!is_pair(vars))
74661 	      return(OPT_OOPS);
74662 	}
74663       if (!is_pair(body)) return(OPT_OOPS);
74664 
74665       if (!vars_syntax_ok(vars))
74666 	return(OPT_OOPS);
74667 
74668       if ((op == OP_LETREC) || (op == OP_LETREC_STAR))
74669 	{
74670 	  e = collect_variables(sc, vars, e);
74671 	  if (!vars_opt_ok(sc, vars, hop, e))
74672 	    return(OPT_OOPS);
74673 	}
74674       else
74675 	{
74676 	  if (op == OP_LET)
74677 	    {
74678 	      if (!vars_opt_ok(sc, vars, hop, e))
74679 		return(OPT_OOPS);
74680 	      e = collect_variables(sc, vars, e);
74681 	    }
74682 	  else
74683 	    for (p = vars; is_pair(p); p = cdr(p))
74684 	      {
74685 		s7_pointer var;
74686 		var = car(p);
74687 		if ((is_pair(cadr(var))) &&
74688 		    (!is_checked(cadr(var))) &&
74689 		    (optimize_expression(sc, cadr(var), hop, e, false) == OPT_OOPS))
74690 		  return(OPT_OOPS);
74691 		e = cons(sc, add_symbol_to_list(sc, car(var)), e);
74692 		sc->w = e;
74693 	      }}
74694       if (is_symbol(cadr(expr)))
74695 	{
74696 	  e = cons(sc, add_symbol_to_list(sc, cadr(expr)), e);
74697 	  sc->w = e;
74698 	}
74699       break;
74700 
74701     case OP_LET_TEMPORARILY:
74702       vars = cadr(expr);
74703       if (!is_list(vars)) return(OPT_OOPS);
74704       body = cddr(expr);
74705       for (p = vars; is_pair(p); p = cdr(p))
74706 	{
74707 	  s7_pointer var;
74708 	  var = car(vars);
74709 	  if ((is_pair(var)) &&
74710 	      (is_pair(cdr(var))) &&
74711 	      (is_pair(cadr(var))) &&
74712 	      (!is_checked(cadr(var))) &&
74713 	      (optimize_expression(sc, cadr(var), hop, e, false) == OPT_OOPS))
74714 	    return(OPT_OOPS);
74715 	}
74716       /* e = cons(sc, sc->nil, e); */ /* !? currently let-temporarily does not make a new let, so it is like begin? */
74717       body_export_ok = export_ok;     /* (list x (let-temporarily () (define x 0))) just as in begin */
74718       break;
74719 
74720     case OP_DO:
74721       vars = cadr(expr);
74722       if (is_null(vars))
74723 	e = cons(sc, sc->nil, e);
74724       else
74725 	if (!is_pair(vars))
74726 	  return(OPT_OOPS);
74727       body = cddr(expr);
74728 
74729       for (p = vars; is_pair(p); p = cdr(p))
74730 	{
74731 	  s7_pointer var;
74732 	  var = car(p);
74733 	  if ((!is_pair(var)) ||
74734 	      (!is_symbol(car(var))) ||
74735 	      (!is_pair(cdr(var))))
74736 	    return(OPT_OOPS);
74737 	  if ((is_pair(cadr(var))) &&
74738 	      (!is_checked(cadr(var))) &&
74739 	      (optimize_expression(sc, cadr(var), hop, e, false) == OPT_OOPS)) /* the init field -- locals are not defined yet */
74740 	    return(OPT_OOPS);
74741 	}
74742       e = collect_variables(sc, vars, e);
74743       for (p = vars; is_pair(p); p = cdr(p))
74744 	{
74745 	  s7_pointer var;
74746 	  var = cddar(p);
74747 	  if ((is_pair(var)) &&
74748 	      (is_pair(car(var))) &&
74749 	      (!is_checked(car(var))) &&
74750 	      (optimize_expression(sc, car(var), hop, e, false) == OPT_OOPS)) /* the step field -- locals are defined */
74751 	    return(OPT_OOPS);
74752 	}
74753       break;
74754 
74755     case OP_BEGIN:
74756       body_export_ok = export_ok; /* (list x (begin (define x 0))) */
74757       break;
74758 
74759     case OP_WITH_BAFFLE:
74760       e = cons(sc, sc->nil, e);
74761       break;
74762 
74763     case OP_DEFINE_BACRO: case OP_DEFINE_BACRO_STAR:
74764     case OP_BACRO:  case OP_BACRO_STAR:
74765       return(OPT_F);
74766 
74767     case OP_DEFINE_MACRO:    case OP_DEFINE_MACRO_STAR:
74768     case OP_DEFINE_CONSTANT: case OP_DEFINE_EXPANSION: case OP_DEFINE_EXPANSION_STAR:
74769     case OP_DEFINE:          case OP_DEFINE_STAR:
74770       /* define adds a name to the incoming let (e), the added name is inserted into e after the first, so the caller
74771        *   can flush added symbols by maintaining its own pointer into the list if blockers set the car.
74772        * the list is used both to see local symbols and to catch "complicated" functions (find_uncomplicated_symbol).
74773        * In cases like (if expr (define...)) we can't tell at this level whether the define takes place, so
74774        *   its name should not be in "e", but it needs to be marked for find_uncomplicated_symbol in a way
74775        *   that can be distinguished from members of "e".  So in that (rare) case, we use the associated keyword.
74776        *   Then find_uncomplicated_symbol can use has_keyword to tell if the keyword search is needed.
74777        * export_ok is trying to protect against optimizing (list x (define x 0)) as op_safe_c_sp and all related cases
74778        */
74779       vars = cadr(expr);
74780       body = cddr(expr);
74781       if (is_pair(vars))
74782 	{
74783 	  if ((export_ok) &&
74784 	      (is_symbol(car(vars))))
74785 	    {
74786 	      add_symbol_to_list(sc, car(vars));
74787 	      if (is_pair(e))
74788 		{
74789 		  if (car(e) != sc->key_if_symbol)
74790 		    set_cdr(e, cons(sc, car(vars), cdr(e))); /* export it */
74791 		  else add_symbol_to_list(sc, symbol_to_keyword(sc, car(vars)));
74792 		}
74793 	      else e = cons(sc, car(vars), e);
74794 	    }
74795 	  e = collect_parameters(sc, cdr(vars), e);
74796 	  body_export_ok = export_ok;
74797 	}
74798       else
74799 	{
74800 	  if ((export_ok) &&
74801 	      (is_symbol(vars)))
74802 	    {
74803 	      /* actually if this is defining a function, the name should probably be included in the local let
74804 	       *   but that's next-to-impossible to guarantee unless it's (define x (lambda...)) of course.
74805 	       */
74806 	      sc->temp9 = e;
74807 	      for (p = body; is_pair(p); p = cdr(p))
74808 		if ((is_pair(car(p))) &&
74809 		    (!is_checked(car(p))) && /* ((full_type(p) & (TYPE_MASK | T_CHECKED)) == T_PAIR) is not faster */
74810 		    (optimize_expression(sc, car(p), hop, e, false) == OPT_OOPS)) /* "body" here is not body in terms of export_ok */
74811 		  return(OPT_OOPS);
74812 	      sc->temp9 = sc->nil;
74813 
74814 	      add_symbol_to_list(sc, vars);
74815 	      if (is_pair(e))
74816 		{
74817 		  if (car(e) != sc->key_if_symbol)
74818 		    set_cdr(e, cons(sc, vars, cdr(e)));     /* export it */
74819 		  else add_symbol_to_list(sc, symbol_to_keyword(sc, vars));
74820 		}
74821 	      /* else e = cons(sc, vars, e); */ /* ?? should this be set-cdr etc? */
74822 	      return(OPT_F);
74823 	    }
74824 	  body_export_ok = false;
74825 	}
74826       break;
74827 
74828     case OP_LAMBDA: case OP_LAMBDA_STAR:
74829     case OP_MACRO:  case OP_MACRO_STAR:
74830       vars = cadr(expr);
74831       if (is_null(vars))
74832 	e = cons(sc, sc->nil, e);
74833       else
74834 	if ((!is_pair(vars)) && (!is_symbol(vars)))
74835 	  return(OPT_OOPS);
74836       e = collect_parameters(sc, vars, e);
74837       body = cddr(expr);
74838       break;
74839 
74840     case OP_SET:
74841       if ((is_pair(cadr(expr))) &&
74842 	  (caadr(expr) == sc->outlet_symbol))
74843 	return(OPT_OOPS);
74844 
74845       if (!is_pair(cddr(expr)))
74846 	return(OPT_OOPS);
74847 
74848       if ((is_pair(cadr(expr))) &&
74849 	  (!is_checked(cadr(expr))))
74850 	{
74851 	  s7_pointer lp;
74852 	  set_checked(cadr(expr));
74853 	  for (lp = cdadr(expr); is_pair(lp); lp = cdr(lp))
74854 	    if ((is_pair(car(lp))) &&
74855 		(!is_checked(car(lp))) &&
74856 		(optimize_expression(sc, car(lp), hop, e, body_export_ok) == OPT_OOPS))
74857 	      return(OPT_OOPS);
74858 	}
74859 
74860       if ((is_pair(caddr(expr))) &&
74861 	  (!is_checked(caddr(expr))) &&
74862 	  (optimize_expression(sc, caddr(expr), hop, e, body_export_ok) == OPT_OOPS))
74863 	return(OPT_OOPS);
74864       return(OPT_F);
74865 
74866     case OP_WITH_LET:
74867       /* we usually can't trust anything here, so hop ought to be off.  For example,
74868        *   (define (hi) (let ((e (sublet (curlet) :abs (lambda (a) (- a 1))))) (with-let e (abs -1))))
74869        * returns 1 if hop is 1, but -2 otherwise.  (with-let (unlet)...) is safe however.
74870        */
74871       {
74872 	bool old_with_let;
74873 	old_with_let = sc->in_with_let;
74874 	sc->in_with_let = (old_with_let) || (!is_pair(body)) || (!is_pair(car(body))) ||
74875 	                  ((caar(body) != sc->unlet_symbol) && (caar(body) != sc->rootlet_symbol) && (caar(body) != sc->curlet_symbol));
74876 	for (p = body; is_pair(p); p = cdr(p))
74877 	  if ((is_pair(car(p))) &&
74878 	      (!is_checked(car(p))) &&
74879 	      (optimize_expression(sc, car(p), 0, sc->nil, body_export_ok) == OPT_OOPS))
74880 	    {
74881 	      sc->in_with_let = old_with_let;
74882 	      return(OPT_OOPS);
74883 	    }
74884 	sc->in_with_let = old_with_let;
74885 	return(OPT_F);
74886       }
74887 
74888     case OP_CASE:
74889       if ((is_pair(cadr(expr))) &&
74890 	  (!is_checked(cadr(expr))) &&
74891 	  (optimize_expression(sc, cadr(expr), hop, e, false) == OPT_OOPS))
74892 	return(OPT_OOPS);
74893       for (p = cddr(expr); is_pair(p); p = cdr(p))
74894 	if ((is_pair(car(p))) &&
74895 	    (is_pair(cdar(p))))
74896 	  {
74897 	    s7_pointer rst;
74898 	    for (rst = cdar(p); is_pair(rst); rst = cdr(rst))
74899 	      if ((is_pair(car(rst))) &&
74900 		  (!is_checked(car(rst))) &&
74901 		  (optimize_expression(sc, car(rst), hop, e, false) == OPT_OOPS))
74902 		return(OPT_OOPS);
74903 	  }
74904       return(OPT_F);
74905 
74906     case OP_COND: /* split opt is necessary: (cond (lambda (x) ...)) */
74907       for (p = cdr(expr); is_pair(p); p = cdr(p))
74908 	if (is_pair(car(p)))
74909 	  {
74910 	    s7_pointer test, rst;
74911 	    test = caar(p);
74912 	    e = cons(sc, sc->key_if_symbol, e);  /* I think this is a marker in case define is encountered? (see above) */
74913 	    if ((is_pair(test)) &&
74914 		(!is_checked(test)) &&
74915 		(optimize_expression(sc, test, hop, e, false) == OPT_OOPS))
74916 	      return(OPT_OOPS);
74917 	    for (rst = cdar(p); is_pair(rst); rst = cdr(rst))
74918 	      if ((is_pair(car(rst))) &&
74919 		  (!is_checked(car(rst))) &&
74920 		  (optimize_expression(sc, car(rst), hop, e, false) == OPT_OOPS))
74921 		return(OPT_OOPS);
74922 	  }
74923       for (p = cdr(expr); is_pair(p); p = cdr(p))
74924 	{
74925 	  s7_pointer q;
74926 	  if ((!is_pair(car(p))) || (!is_fxable(sc, caar(p))))
74927 	    break;
74928 	  if (!is_pair(cdar(p)))
74929 	    break;
74930 	  for (q = cdar(p); is_pair(q); q = cdr(q))
74931 	    if ((car(q) == sc->feed_to_symbol) || (!is_fxable(sc, car(q))))
74932 	      break;
74933 	  if (!is_null(q)) break;
74934 	}
74935       if (is_null(p))
74936 	{
74937 	  set_safe_optimize_op(expr, OP_COND_FX_FX);
74938 	  for (p = cdr(expr); is_pair(p); p = cdr(p))
74939 	    {
74940 	      s7_pointer q;
74941 	      set_fx_direct(car(p), fx_choose(sc, car(p), e, pair_symbol_is_safe));
74942 	      for (q = cdar(p); is_pair(q); q = cdr(q))
74943 		set_fx_direct(q, fx_choose(sc, q, e, pair_symbol_is_safe));
74944 	    }
74945 	  return(OPT_T);
74946 	}
74947       return(OPT_F);
74948 
74949     case OP_IF:
74950     case OP_WHEN:
74951     case OP_UNLESS:
74952       if ((!is_pair(cdr(expr))) || (!is_pair(cddr(expr))))
74953 	return(OPT_OOPS);
74954     case OP_OR:
74955     case OP_AND:
74956       e = cons(sc, sc->key_if_symbol, e);
74957       break;
74958 
74959     default:
74960       break;
74961     }
74962 
74963   sc->temp9 = e;
74964   for (p = body; is_pair(p); p = cdr(p))
74965     if ((is_pair(car(p))) &&
74966 	(!is_checked(car(p))) && /* ((full_type(p) & (TYPE_MASK | T_CHECKED)) == T_PAIR) is not faster */
74967 	(optimize_expression(sc, car(p), hop, e, body_export_ok) == OPT_OOPS))
74968       {
74969 	sc->temp9 = sc->nil;
74970 	return(OPT_OOPS);
74971       }
74972   sc->temp9 = sc->nil;
74973 
74974   if ((hop == 1) &&
74975       ((is_syntax(car(expr))) ||
74976        (symbol_id(car(expr)) == 0)))
74977     {
74978       if (op == OP_IF)
74979 	{
74980 	  for (p = cdr(expr); is_pair(p); p = cdr(p))
74981 	    if (!is_fxable(sc, car(p)))
74982 	      break;
74983 
74984 	  if (is_null(p))
74985 	    {
74986 	      s7_pointer test, b1, b2;
74987 	      test = cdr(expr);
74988 	      if ((is_pair(cdr(test))) && (is_pair(cddr(test))) && (!is_null(cdddr(test))))
74989 		return(OPT_OOPS);
74990 
74991 	      for (p = cdr(expr); is_pair(p); p = cdr(p))
74992 		set_fx_direct(p, fx_choose(sc, p, e, pair_symbol_is_safe));
74993 
74994 	      b1 = cdr(test);
74995 	      b2 = cdr(b1);
74996 	      if ((fx_proc(b1) == fx_q) &&
74997 		  (is_pair(b2)))
74998 		{
74999 		  set_opt3_con(test, cadar(b1));
75000 		  if (fx_proc(b2) == fx_q)
75001 		    {
75002 		      set_safe_optimize_op(expr, OP_IF_A_C_C);
75003 		      set_opt1_con(expr, cadar(b1));
75004 		      set_opt2_con(expr, cadar(b2));
75005 		      return(OPT_T);
75006 		    }
75007 		  set_opt1_pair(expr, b1);
75008 		  set_opt2_pair(expr, b2);
75009 		  set_safe_optimize_op(expr, OP_IF_A_A_A);
75010 		}
75011 	      else
75012 		{
75013 		  if ((is_pair(car(test))) &&
75014 		      (caar(test) == sc->not_symbol) &&
75015 		      (is_fxable(sc, cadar(test))))
75016 		    {
75017 		      set_fx_direct(cdar(test), fx_choose(sc, cdar(test), e, pair_symbol_is_safe));
75018 		      set_opt1_pair(expr, cdar(test));
75019 		      set_opt2_pair(expr, b1);
75020 		      if (is_pair(b2)) set_opt3_pair(expr, b2);
75021 		      set_safe_optimize_op(expr, (is_null(b2)) ? OP_IF_NOT_A_A : OP_IF_NOT_A_A_A);
75022 		    }
75023 		  else
75024 		    {
75025 		      if ((is_pair(b2)) && (fx_proc(b1) == fx_c) && (fx_proc(b2) == fx_c))
75026 			{
75027 			  set_safe_optimize_op(expr, OP_IF_A_C_C);
75028 			  set_opt1_con(expr, car(b1));
75029 			  set_opt2_con(expr, car(b2));
75030 			  return(OPT_T);
75031 			}
75032 		      if ((fx_proc(test) == fx_and_2) && (fx_proc(b1) == fx_s))
75033 			{
75034 			  set_opt1_pair(expr, cdadr(expr));
75035 			  set_opt2_pair(expr, cddadr(expr));
75036 			  set_opt3_sym(expr, car(b1));
75037 			  set_safe_optimize_op(expr, OP_IF_AND2_S_A);
75038 			  return(OPT_T);
75039 			}
75040 		      set_opt1_pair(expr, b1);
75041 		      if (is_pair(b2)) set_opt2_pair(expr, b2);
75042 		      set_safe_optimize_op(expr, (is_null(b2)) ? OP_IF_A_A : ((fx_proc(test) == fx_s) ? OP_IF_S_A_A : OP_IF_A_A_A));
75043 		    }}
75044 	      return(OPT_T);
75045 	    }}
75046       else
75047 	{
75048 	  if ((op == OP_OR) || (op == OP_AND))
75049 	    {
75050 	      for (p = cdr(expr); is_pair(p); p = cdr(p))
75051 		if (!is_fxable(sc, car(p)))
75052 		  break;
75053 
75054 	      if (is_null(p))    /* catch the syntax error later: (or #f . 2) etc */
75055 		{
75056 		  int32_t args, pairs = 0;
75057 		  s7_pointer sym = NULL;
75058 		  bool c_s_is_ok = true;
75059 
75060 		  for (args = 0, p = cdr(expr); is_pair(p); p = cdr(p), args++) /* this only applies to or/and */
75061 		    if (is_pair(car(p)))
75062 		      {
75063 			pairs++;
75064 			if ((c_s_is_ok) &&
75065 			    ((!is_h_safe_c_s(car(p))) ||
75066 			     ((sym) && (sym != cadar(p)))))
75067 			  c_s_is_ok = false;
75068 			else sym = (is_pair(cdar(p))) ? cadar(p) : sc->unspecified;
75069 		      }
75070 
75071 		  if ((c_s_is_ok) && (args == 2) && (pairs == 2))
75072 		    {
75073 		      if (op == OP_OR)
75074 			{
75075 			  set_opt3_sym(cdr(expr), cadadr(expr));
75076 			  if ((is_symbol(caadr(expr))) && (symbol_type(caadr(expr)) > 0) && (is_global(caadr(expr))) &&
75077 			      ((is_symbol(caaddr(expr))) && (symbol_type(caaddr(expr)) > 0) && (is_global(caaddr(expr)))))
75078 			    {
75079 			      set_opt3_int(expr, small_int(symbol_type(caadr(expr))));
75080 			      set_opt2_int(cdr(expr), small_int(symbol_type(caaddr(expr))));
75081 			      set_safe_optimize_op(expr, OP_OR_S_TYPE_2);
75082 			    }
75083 			  else set_safe_optimize_op(expr, OP_OR_S_2);
75084 			}
75085 		      else
75086 			{
75087 			  set_opt3_sym(cdr(expr), cadadr(expr));
75088 			  set_safe_optimize_op(expr, OP_AND_S_2);
75089 			}
75090 		      return(OPT_T);
75091 		    }
75092 
75093 		  for (p = cdr(expr); is_pair(p); p = cdr(p))
75094 		    set_fx_direct(p, fx_choose(sc, p, e, pair_symbol_is_safe));
75095 		  if (op == OP_OR)
75096 		    {
75097 		      if (args == 2)
75098 			set_safe_optimize_op(expr, OP_OR_2);
75099 		      else
75100 			{
75101 			  if (args == 3)
75102 			    set_safe_optimize_op(expr, OP_OR_3);
75103 			  else set_safe_optimize_op(expr, OP_OR_N);
75104 			}
75105 		      return(OPT_T);
75106 		    }
75107 		  if (args == 2)
75108 		    set_safe_optimize_op(expr, OP_AND_2);
75109 		  else
75110 		    {
75111 		      if (args == 3)
75112 			set_safe_optimize_op(expr, OP_AND_3);
75113 		      else set_safe_optimize_op(expr, OP_AND_N);
75114 		    }
75115 		  return(OPT_T);
75116 		}}
75117 	  else
75118 	    {
75119 	      if (op == OP_BEGIN)
75120 		{
75121 		  if (!is_pair(cdr(expr))) return(OPT_F);
75122 
75123 		  for (p = cdr(expr); is_pair(p); p = cdr(p))
75124 		    if (!is_fxable(sc, car(p)))
75125 		      break;
75126 		  if (is_null(p))
75127 		    {
75128 		      for (p = cdr(expr); is_pair(p); p = cdr(p))
75129 			set_fx_direct(p, fx_choose(sc, p, e, pair_symbol_is_safe));
75130 
75131 		      if ((is_pair(cddr(expr))) && (is_null(cdddr(expr))))
75132 			set_safe_optimize_op(expr, OP_BEGIN_AA);
75133 		      else set_safe_optimize_op(expr, OP_BEGIN_ALL_A);
75134 		      return(OPT_T);
75135 		    }}}}}   /* fully fxable lets don't happen much: even op_let_2a_a is scarcely used */
75136   return(OPT_F);
75137 }
75138 
75139 
75140 static opt_t optimize_funcs(s7_scheme *sc, s7_pointer expr, s7_pointer func, int32_t hop, int32_t orig_hop, s7_pointer e)
75141 {
75142   int32_t pairs = 0, symbols = 0, args = 0, bad_pairs = 0, quotes = 0;
75143   s7_pointer p;
75144   for (p = cdr(expr); is_pair(p); p = cdr(p), args++) /* check the args (the calling expression) */
75145     {
75146       s7_pointer car_p;
75147       car_p = car(p);
75148       if (is_normal_symbol(car_p)) /* for opt func */
75149 	symbols++;
75150       else
75151 	if (is_pair(car_p))
75152 	  {
75153 	    pairs++;
75154 	    if (!is_checked(car_p))
75155 	      {
75156 		opt_t res;
75157 		res = optimize_expression(sc, car_p, orig_hop, e, false);
75158 		if (res == OPT_F)
75159 		  {
75160 		    bad_pairs++;
75161 		    if (is_proper_quote(sc, car_p))
75162 		      quotes++;
75163 		  }
75164 		else
75165 		  if (res == OPT_OOPS)
75166 		    return(OPT_OOPS);
75167 	      }
75168 	    else
75169 	      if ((!is_optimized(car_p)) ||
75170 		  (is_unsafe(car_p)))
75171 		{
75172 		  bad_pairs++;
75173 		  if (is_proper_quote(sc, car_p))
75174 		    quotes++;
75175 		}}}
75176   if (is_null(p))                    /* if not null, dotted list of args? */
75177     {
75178       switch (args)
75179 	{
75180 	case 0:  return(optimize_thunk(sc, expr, func, hop, e));
75181 	case 1:  return(optimize_func_one_arg(sc, expr, func, hop, pairs, symbols, quotes, bad_pairs, e));
75182 	case 2:  return(optimize_func_two_args(sc, expr, func, hop, pairs, symbols, quotes, bad_pairs, e));
75183 	case 3:  return(optimize_func_three_args(sc, expr, func, hop, pairs, symbols, quotes, bad_pairs, e));
75184 	default: return(optimize_func_many_args(sc, expr, func, hop, args, pairs, symbols, quotes, bad_pairs, e));
75185 	}}
75186   return(OPT_F);
75187 }
75188 
75189 static opt_t optimize_expression(s7_scheme *sc, s7_pointer expr, int32_t hop, s7_pointer e, bool export_ok)
75190 {
75191   s7_pointer car_expr;
75192   int32_t orig_hop;
75193   orig_hop = hop;
75194   set_checked(expr);
75195   car_expr = car(expr);
75196 
75197   if (is_symbol(car_expr))
75198     {
75199       s7_pointer slot;
75200       if (is_syntactic_symbol(car_expr))
75201 	{
75202 	  if (!is_pair(cdr(expr)))
75203 	    return(OPT_OOPS);
75204 	  return(optimize_syntax(sc, expr, T_Syn(global_value(car_expr)), hop, e, export_ok));
75205 	}
75206       slot = find_uncomplicated_symbol(sc, car_expr, e); /* local vars (recursive calls too??) are considered "complicated" */
75207       if (is_slot(slot))
75208 	{
75209 	  s7_pointer func;
75210 	  func = slot_value(slot);
75211 	  if (is_syntax(func))                           /* 12-8-16 was is_syntactic, but that is only appropriate above -- here we have the value */
75212 	    return((is_pair(cdr(expr))) ? optimize_syntax(sc, expr, func, hop, e, export_ok) : OPT_OOPS);  /* e can be extended via set-cdr! here */
75213 
75214 	  if (is_any_macro(func))
75215 	    return(OPT_F);
75216 
75217 	  /* we miss implicit indexing here because at this time, the data are not set */
75218 	  if ((is_t_procedure(func)) ||                  /* t_procedure_p: c_funcs, closures, etc */
75219 	      (is_any_closure(func)) ||                  /* added 11-Mar-20 */
75220 	      (is_safe_procedure(func)))                 /* built-in applicable objects like vectors */
75221 	    {
75222 	      if ((hop != 0) &&
75223 		  ((is_any_closure(func)) ||             /* see use-redef in s7test -- I'm not sure about this */
75224 		   ((!is_global(car_expr)) &&
75225 		    ((!is_slot(global_slot(car_expr))) ||
75226 		     (global_value(car_expr) != func)))) &&
75227 		  (!is_immutable(car_expr)) && /* list|apply-values -- can't depend on opt1 here because it might not be global, or might be redefined locally */
75228 		  (!is_immutable(slot)))       /* (define-constant...) */
75229 		{
75230 		  /* (let () (define (f2 a) (+ a 1)) (define (f1 a) (f2 a)) (define (f2 a) (- a)) (f1 12))
75231 		   * (let () (define (f2 a) (+ a 1)) (define (f1 a) (f2 a)) (define (f2 a) (- a 1)) (f1 12))
75232 		   * and similar define* cases
75233 		   */
75234 		  hop = 0;
75235 		  /* this is very tricky!  See s7test for some cases.  Basically, we need to protect a recursive call
75236 		   *   of the current function being optimized from being confused with some previous definition
75237 		   *   of the same name.  But method lists have global names so the global bit is off even though the
75238 		   *   thing is actually a safe global.  But no closure can be considered safe in the hop sense --
75239 		   *   even a global function might be redefined at any time, and previous uses of it in other functions
75240 		   *   need to reflect its new value.
75241 		   *   So, closures are always checked, but built-in functions are used as if never redefined until that redefinition.
75242 		   * Syntax handling is already impure in s7, so the special handling of built-in functions doesn't
75243 		   *   offend me much.  Consider each a sort of reader macro until someone redefines it -- previous
75244 		   *   uses might not be affected because they might have been optimized away -- the result depends on the
75245 		   *   current optimizer.
75246 		   * Another case (from K Matheussen):
75247 		   *   (define (call-func func arg1 arg2) (define (call) (func arg1 arg2)) (call)) (call-func + 1 2.5) (call-func - 5 2)
75248 		   *   when we get here originally "func" is +, hop=1, but just checking for !is_global(car_expr) is
75249 		   *   not good enough -- if we load mockery.scm, nothing is global!
75250 		   * Yet another case (define (test-abs) (define (abs x) (+ x 1)) (format *stderr* "abs ~A~%" (abs -1)))
75251 		   *   when optimize_syntax sees the (define abs ...), it inserts abs into e so that the caller's e is extended (set-cdr!)
75252 		   *   so that find_uncomplicated_symbol above will be unhappy when we reach (abs -1) as the format arg.
75253 		   *   This can be confused if lambda is redefined at some point, but...
75254 		   */
75255 		}
75256 	      return(optimize_funcs(sc, expr, func, hop, orig_hop, e));
75257 	    }}
75258       else
75259 	{
75260 	  if ((sc->undefined_identifier_warnings) &&
75261 	      (slot == sc->undefined) &&           /* car_expr is not in e or global */
75262 	      (symbol_tag(car_expr) == 0))         /*    and we haven't looked it up earlier */
75263 	    {
75264 	      s7_pointer p;
75265 	      p = current_input_port(sc);
75266 	      if ((is_input_port(p)) &&
75267 		  (port_file(p) != stdin) &&
75268 		  (!port_is_closed(p)) &&
75269 		  (port_filename(p)))
75270 		s7_warn(sc, 1024, "%s might be undefined (%s %u)\n", display(car_expr), port_filename(p), port_line_number(p));
75271 	      else s7_warn(sc, 1024, "; %s might be undefined\n", display(car_expr));
75272 	      symbol_set_tag(car_expr, 1);        /* one warning is enough */
75273 	    }}
75274 
75275       /* car_expr is a symbol but it's not a built-in procedure or a "safe" case = vector etc */
75276       {
75277 	/* else maybe it's something like a let variable binding: (sqrtfreq (sqrt frequency)) */
75278 	s7_pointer p;
75279 	int32_t len = 0, pairs = 0, symbols = 0;
75280 
75281 	for (p = cdr(expr); is_pair(p); p = cdr(p), len++)
75282 	  {
75283 	    s7_pointer car_p;
75284 	    car_p = car(p);
75285 	    if (is_pair(car_p))
75286 	      {
75287 		pairs++;
75288 		if ((!is_checked(car_p)) &&
75289 		    (optimize_expression(sc, car_p, hop, e, false) == OPT_OOPS))
75290 		  return(OPT_OOPS);
75291 	      }
75292 	    else
75293 	      if (is_symbol(car_p))
75294 		  symbols++;
75295 	  }
75296 
75297 	if ((is_null(p)) &&              /* (+ 1 . 2) */
75298 	    (!is_optimized(expr)))
75299 	  {
75300 	    /* len=0 case is almost entirely arglists */
75301 	    set_opt1_con(expr, sc->unused);
75302 
75303 	    if (pairs == 0)
75304 	      {
75305 		if (len == 0)
75306 		  {
75307 		    /* hoping to catch object application here, as in readers in Snd */
75308 		    set_unsafe_optimize_op(expr, OP_UNKNOWN);
75309 		    return(OPT_F);
75310 		  }
75311 
75312 		if (len == 1)
75313 		  {
75314 		    if (car_expr != sc->quote_symbol) /* !! quote can be redefined locally, unsetting the T_SYNTACTIC flag -- can this happen elsewhere? */
75315 		      set_unsafe_optimize_op(expr, OP_UNKNOWN_G);
75316 		    return(OPT_F);
75317 		  }
75318 
75319 		if (len == 2)
75320 		  {
75321 		    set_unsafely_optimized(expr);
75322 		    set_optimize_op(expr, OP_UNKNOWN_GG);
75323 		    return(OPT_F);
75324 		  }
75325 
75326 		if (len >= 3)
75327 		  {
75328 		    if (len == symbols)
75329 		      {
75330 			set_unsafe_optimize_op(expr, OP_UNKNOWN_ALL_S);
75331 			set_opt3_arglen(cdr(expr), make_permanent_integer(len));
75332 			return(OPT_F);
75333 		      }
75334 		    if ((fx_count(sc, expr) == len) &&
75335 			(len < GC_TRIGGER_SIZE))
75336 		      {
75337 			set_unsafe_optimize_op(expr, OP_UNKNOWN_ALL_A);
75338 			set_opt3_arglen(cdr(expr), make_permanent_integer(len));
75339 			return(OPT_F);
75340 		      }}}
75341 	    else /* pairs != 0 */
75342 	      {
75343 		s7_pointer arg1;
75344 		arg1 = cadr(expr);
75345 		if ((pairs == 1) &&
75346 		    (len == 1))
75347 		  {
75348 		    if ((car(expr) == sc->quote_symbol) &&
75349 			(direct_memq(sc->quote_symbol, e)))
75350 		      return(OPT_OOPS);
75351 
75352 		    if (is_fxable(sc, arg1))
75353 		      {
75354 			set_opt3_arglen(cdr(expr), int_one);
75355 			fx_annotate_arg(sc, cdr(expr), e);
75356 			set_unsafe_optimize_op(expr, OP_UNKNOWN_A);
75357 			return(OPT_F);
75358 		      }}
75359 
75360 		if ((len == 2) &&
75361 		    (is_fxable(sc, arg1)) &&
75362 		    (is_fxable(sc, caddr(expr))))
75363 		  {
75364 		    set_opt3_arglen(cdr(expr), int_two);
75365 		    set_unsafe_optimize_op(expr, OP_UNKNOWN_AA);
75366 		    return(OPT_F);
75367 		  }
75368 
75369 		if ((fx_count(sc, expr) == len) &&
75370 		    (len < GC_TRIGGER_SIZE))
75371 		  {
75372 		    if ((len == 1) &&
75373 			(car(expr) == sc->quote_symbol) &&
75374 			(direct_memq(sc->quote_symbol, e)))
75375 		      return(OPT_OOPS);
75376 
75377 		    set_unsafe_optimize_op(expr, (len == 1) ? OP_UNKNOWN_A : OP_UNKNOWN_ALL_A);
75378 		    set_opt3_arglen(cdr(expr), make_permanent_integer(len));
75379 		    if (len == 1)
75380 		      fx_annotate_arg(sc, cdr(expr), e);
75381 		    return(OPT_F);
75382 		  }
75383 		set_unsafe_optimize_op(expr, OP_UNKNOWN_FP);
75384 		set_opt3_arglen(cdr(expr), make_permanent_integer(len));
75385 		return(OPT_F);
75386 	      }}}}
75387   else
75388     {
75389       /* car(expr) is not a symbol, but there might be interesting stuff here */
75390       /* (define (hi a) (case 1 ((1) (if (> a 2) a 2)))) */
75391       s7_pointer p;
75392 
75393       if (is_c_function(car_expr)) /* (#_abs x) etc */
75394 	return(optimize_funcs(sc, expr, car_expr, 1, orig_hop, e));
75395 
75396       if (is_syntax(car_expr))     /* (#_cond ...) */
75397 	{
75398 	  if (!is_pair(cdr(expr)))
75399 	    return(OPT_OOPS);
75400 	  return(optimize_syntax(sc, expr, car_expr, orig_hop, e, export_ok));
75401 	}
75402       if (is_any_macro(car_expr))
75403 	return(OPT_F);
75404 
75405       /* if car is a pair, we can't easily tell whether its value is (say) + or cond, so we need to catch this case and fixup fx settings */
75406       for (p = expr; is_pair(p); p = cdr(p))
75407 	if ((is_pair(car(p))) &&
75408 	    (!is_checked(car(p))) &&
75409 	    (optimize_expression(sc, car(p), hop, e, false) == OPT_OOPS))
75410 	  return(OPT_OOPS);
75411       /* here we get for example:
75412        *  ((if (not (let? p)) write write-to-vector) obj p) ; not uncomplicated/c-function [((if 3d fourth third) p) in index]
75413        *  ((if (symbol? (cadr f)) cadr (if (pair? (cadr f)) caadr not)) f) ; fx not symbol -- opif_a_aaq_a
75414        *  ((if (input-port? port) call-with-input-file call-with-output-file) port proc) ; not safe I guess
75415        */
75416     }
75417   return(OPT_F);
75418 }
75419 
75420 static opt_t optimize(s7_scheme *sc, s7_pointer code, int32_t hop, s7_pointer e)
75421 {
75422   s7_pointer x;
75423   for (x = code; (is_pair(x)) && (!is_checked(x)); x = cdr(x))
75424     {
75425       s7_pointer obj;
75426       obj = car(x);
75427       set_checked(x);
75428       if (is_pair(obj))
75429 	{
75430 	  if ((!is_checked(obj)) &&
75431 	      (optimize_expression(sc, obj, hop, e, true) == OPT_OOPS))
75432 	    {
75433 	      s7_pointer p;
75434 	      for (p = cdr(x); is_pair(p); p = cdr(p));
75435 	      if (!is_null(p))
75436 		eval_error(sc, "stray dot in function body: ~S", 30, code);
75437 	      return(OPT_OOPS);
75438 	    }}
75439       else
75440 	{
75441 	  /* new 22-Sep-19, but I don't think this saves anything over falling into trailers */
75442 	  if (is_symbol(obj))
75443 	    set_optimize_op(obj, (is_keyword(obj)) ? OP_CON : ((is_global(obj)) ? OP_GLOBAL_SYM : OP_SYM));
75444 	  else set_optimize_op(obj, OP_CON);
75445 	}}
75446   if (!is_list(x))
75447     eval_error(sc, "stray dot in function body: ~S", 30, code);
75448   return(OPT_F);
75449 }
75450 
75451 
75452 static bool symbol_is_in_arg_list(s7_pointer sym, s7_pointer lst)
75453 {
75454   s7_pointer x;
75455   for (x = lst; is_pair(x); x = cdr(x))
75456     if ((sym == car(x)) ||
75457 	((is_pair(car(x))) &&
75458 	 (sym == caar(x))))
75459 	return(true);
75460   return(sym == x);
75461 }
75462 
75463 static void check_lambda_args(s7_scheme *sc, s7_pointer args, int32_t *arity)
75464 {
75465   s7_pointer x;
75466   int32_t i;
75467 
75468   if (!is_list(args))
75469     {
75470       if (is_constant(sc, args))                       /* (lambda :a ...) */
75471 	eval_error(sc, "lambda parameter '~S is a constant", 34, args); /* not ~A here, (lambda #\null do) for example */
75472 
75473       /* we currently accept (lambda i i . i) (lambda quote i)  (lambda : : . #()) (lambda : 1 . "")
75474        *   at this level, but when the lambda form is evaluated, it will trigger an error.
75475        */
75476       if (is_symbol(args))
75477 	set_local(args);
75478 
75479       if (arity) (*arity) = -1;
75480       return;
75481     }
75482 
75483   for (i = 0, x = args; is_pair(x); i++, x = cdr(x))
75484     {
75485       s7_pointer car_x;
75486       car_x = car(x);
75487       if (is_constant(sc, car_x))                      /* (lambda (pi) pi), constant here means not a symbol */
75488 	{
75489 	  if (is_pair(car_x))                          /* (lambda ((:hi . "hi") . "hi") 1) */
75490 	    eval_error(sc, "lambda parameter '~S is a pair (perhaps you want define* or lambda*?)", 69, car_x);
75491 	  eval_error(sc, "lambda parameter '~S is a constant", 34, car_x);
75492 	}
75493       if (symbol_is_in_arg_list(car_x, cdr(x)))       /* (lambda (a a) ...) or (lambda (a . a) ...) */
75494 	eval_error(sc, "lambda parameter '~S is used twice in the parameter list", 56, car_x);
75495       set_local(car_x);
75496     }
75497   if (is_not_null(x))
75498     {
75499       if (is_constant(sc, x))                         /* (lambda (a . 0.0) a) or (lambda (a . :b) a) */
75500 	eval_error(sc, "lambda :rest parameter '~S is a constant", 40, x);
75501       i = -i - 1;
75502     }
75503 
75504   if (arity) (*arity) = i;
75505 }
75506 
75507 static s7_pointer check_lambda_star_args(s7_scheme *sc, s7_pointer args, s7_pointer body) /* checks closure*, macro*, and bacro* */
75508 {
75509   s7_pointer top, v, w;
75510   int32_t i;
75511   bool has_defaults;
75512 
75513   if (!is_list(args))
75514     {
75515       if (is_constant(sc, args))                                   /* (lambda* :a ...) */
75516 	eval_error(sc, "lambda* parameter '~S is a constant", 35, args);
75517       if (is_symbol(args))
75518 	set_local(args);
75519       return(args);
75520     }
75521 
75522   has_defaults = false;
75523   top = args;
75524   for (i = 0, v = args, w = args; is_pair(w); i++, v = w, w = cdr(w))
75525     {
75526       s7_pointer car_w;
75527       car_w = car(w);
75528       if (is_pair(car_w))
75529 	{
75530 	  has_defaults = true;
75531 	  if (is_constant(sc, car(car_w)))                         /* (lambda* ((:a 1)) ...) */
75532 	    eval_error(sc, "lambda* parameter '~A is a constant", 35, car(car_w));
75533 	  if (symbol_is_in_arg_list(caar(w), cdr(w)))              /* (lambda* ((a 1) a) ...) */
75534 	    eval_error(sc, "lambda* parameter '~A is used twice in the argument list", 56, car(car_w));
75535 
75536 	  if (!is_pair(cdr(car_w)))                               /* (lambda* ((a . 0.0)) a) */
75537 	    {
75538 	      if (is_null(cdr(car_w)))                            /* (lambda* ((a)) ...) */
75539 		eval_error(sc, "lambda* parameter default value missing? '~A", 44, car_w);
75540 	      eval_error(sc, "lambda* parameter is a dotted pair? '~A",39,  car_w);
75541 	    }
75542 	  if ((is_pair(cadr(car_w))) &&                           /* (lambda* ((a (quote . -1))) ...) */
75543 	      (s7_list_length(sc, cadr(car_w)) < 0))
75544 	    eval_error(sc, "lambda* parameter default value is improper? ~A", 47, car_w);
75545 
75546 	  if (is_not_null(cddr(car_w)))                           /* (lambda* ((a 0.0 'hi)) a) */
75547 	    eval_error(sc, "lambda* parameter has multiple default values? '~A", 50, car_w);
75548 
75549 	  set_local(car(car_w));
75550 	}
75551       else
75552 	{
75553 	  if (car_w != sc->key_rest_symbol)
75554 	    {
75555 	      if (is_constant(sc, car_w))
75556 		{
75557 		  if (car_w == sc->key_allow_other_keys_symbol)
75558 		    {
75559 		      if (is_not_null(cdr(w)))                    /* (lambda* (:allow-other-keys x) x) */
75560 			eval_error(sc, ":allow-other-keys should be the last parameter: ~A", 50, args);
75561 		      if (w == top)
75562 			eval_error(sc, ":allow-other-keys can't be the only parameter: ~A", 49, args);
75563 		      set_allow_other_keys(top);
75564 		      set_cdr(v, sc->nil);
75565 		    }
75566 		  else                                            /* (lambda* (pi) ...) */
75567 		    eval_error(sc, "lambda* parameter '~A is a constant", 35, car_w);
75568 		}
75569 	      if (symbol_is_in_arg_list(car_w, cdr(w)))           /* (lambda* (a a) ...) or (lambda* (a . a) ...) */
75570 		eval_error(sc, "lambda* parameter '~A is used twice in the argument list", 56, car_w);
75571 
75572 	      if (!is_keyword(car_w)) set_local(car_w);
75573 	    }
75574 	  else
75575 	    {
75576 	      has_defaults = true;
75577 	      if (!is_pair(cdr(w)))                               /* (lambda* (:rest) ...) */
75578 		eval_error(sc, "lambda* :rest parameter missing? ~A", 35, w);
75579 	      if (!is_symbol(cadr(w)))                            /* (lambda* (:rest (a 1)) ...) */
75580 		{
75581 		  if (!is_pair(cadr(w)))                          /* (lambda* (:rest 1) ...) */
75582 		    eval_error(sc, "lambda* :rest parameter is not a symbol? ~A", 43, w);
75583 		  eval_error(sc, "lambda* :rest parameter can't have a default value. ~A", 54, w);
75584 		}
75585 	      if (is_constant(sc, cadr(w)))                       /* (lambda* (a :rest x)...) where x is locally a constant */
75586 		return(s7_error(sc, sc->wrong_type_arg_symbol,
75587 				set_elist_2(sc, wrap_string(sc, "can't bind an immutable object: ~S", 34), w)));
75588 	      set_local(cadr(w));
75589 	    }}}
75590   if (is_not_null(w))
75591     {
75592       if (is_constant(sc, w))                                     /* (lambda* (a . 0.0) a) or (lambda* (a . :b) a) */
75593 	eval_error(sc, "lambda* :rest parameter '~A is a constant", 41, w);
75594       if (is_symbol(w))
75595 	set_local(w);
75596     }
75597   else
75598     if ((body) && (!has_defaults) && (is_pair(args)))
75599       set_has_no_defaults(body);
75600   return(top);
75601 }
75602 
75603 static void set_rec_tc_args(s7_scheme *sc, s7_int args)
75604 {
75605   if (sc->rec_tc_args == -1)
75606     sc->rec_tc_args = args;
75607   else
75608     if (sc->rec_tc_args != args)
75609       sc->rec_tc_args = -2;
75610 }
75611 
75612 typedef enum {UNSAFE_BODY=0, RECUR_BODY, SAFE_BODY, VERY_SAFE_BODY} body_t;
75613 static body_t min_body(body_t b1, body_t b2) {return((b1 < b2) ? b1 : b2);}
75614 static body_t body_is_safe(s7_scheme *sc, s7_pointer func, s7_pointer body, bool at_end);
75615 
75616 static body_t form_is_safe(s7_scheme *sc, s7_pointer func, s7_pointer x, bool at_end) /* called only from body_is_safe */
75617 {
75618   s7_pointer expr;
75619   body_t result = VERY_SAFE_BODY;
75620 
75621 #if S7_DEBUGGING
75622   if (!is_pair(x)) {fprintf(stderr, "form_is_safe x is not a pair! %s\n", display(x)); abort();}
75623 #endif
75624   expr = car(x);
75625   if (is_syntactic_symbol(expr))
75626     {
75627       if (!is_pair(cdr(x))) return(UNSAFE_BODY);
75628       /* lambda_unchecked, if_d_p_p define_funchecked */
75629       switch (symbol_syntax_op_checked(x))
75630 	{
75631 	case OP_OR:
75632 	case OP_AND:
75633 	case OP_BEGIN:
75634 	case OP_WITH_BAFFLE:
75635 	  return(body_is_safe(sc, func, cdr(x), at_end));
75636 
75637 	case OP_MACROEXPAND:
75638 	  return(UNSAFE_BODY);
75639 
75640 	case OP_QUOTE:
75641 	  return(((!is_pair(cdr(x))) || (!is_null(cddr(x)))) ? UNSAFE_BODY : VERY_SAFE_BODY);  /* (quote . 1) or (quote 1 2) etc */
75642 
75643 	case OP_IF:
75644 	  if (!is_pair(cddr(x))) return(UNSAFE_BODY);
75645 	  if (is_pair(cadr(x)))
75646 	    {
75647 	      result = form_is_safe(sc, func, cadr(x), false);
75648 	      if (result == UNSAFE_BODY)
75649 		return(UNSAFE_BODY);
75650 	    }
75651 	  if (is_pair(caddr(x)))
75652 	    {
75653 	      result = min_body(result, form_is_safe(sc, func, caddr(x), at_end));
75654 	      if (result == UNSAFE_BODY)
75655 		return(UNSAFE_BODY);
75656 	    }
75657 	  if ((is_pair(cdddr(x))) &&
75658 	      (is_pair(cadddr(x))))
75659 	    return(min_body(result, form_is_safe(sc, func, cadddr(x), at_end)));
75660 	  return(result);
75661 
75662 	case OP_WHEN:
75663 	case OP_UNLESS:
75664 	  if (!is_pair(cddr(x))) return(UNSAFE_BODY);
75665 	  if (is_pair(cadr(x)))
75666 	    {
75667 	      result = form_is_safe(sc, func, cadr(x), false);
75668 	      if (result == UNSAFE_BODY)
75669 		return(UNSAFE_BODY);
75670 	    }
75671 	  return(min_body(result, body_is_safe(sc, func, cddr(x), at_end)));
75672 
75673 	case OP_COND:
75674 	  {
75675 	    bool follow = false;
75676 	    s7_pointer sp, p;
75677 	    for (p = cdr(x), sp = x; is_pair(p); p = cdr(p))
75678 	      {
75679 		s7_pointer ex;
75680 		ex = car(p);
75681 		if (!is_pair(ex))
75682 		  return(UNSAFE_BODY);
75683 		if (is_pair(car(ex)))
75684 		  {
75685 		    result = min_body(result, form_is_safe(sc, func, car(ex), false));
75686 		    if (result == UNSAFE_BODY)
75687 		      return(UNSAFE_BODY);
75688 		  }
75689 		if (is_pair(cdr(ex)))
75690 		  {
75691 		    result = min_body(result, body_is_safe(sc, func, cdr(ex), at_end));
75692 		    if (result == UNSAFE_BODY)
75693 		      return(UNSAFE_BODY);
75694 		  }
75695 		if (follow) {sp = cdr(sp); if (p == sp) return(UNSAFE_BODY);}
75696 		follow = (!follow);
75697 	      }
75698 	    return((is_null(p)) ? result : UNSAFE_BODY);
75699 	  }
75700 
75701 	case OP_CASE:
75702 	  {
75703 	    bool follow = false;
75704 	    s7_pointer sp, p;
75705 	    if (!is_pair(cddr(x))) return(UNSAFE_BODY);
75706 	    if (is_pair(cadr(x)))
75707 	      {
75708 		result = form_is_safe(sc, func, cadr(x), false);
75709 		if (result == UNSAFE_BODY)
75710 		  return(UNSAFE_BODY);
75711 	      }
75712 	    sp = cdr(x);
75713 	    p = cdr(sp);
75714 	    for (; is_pair(p); p = cdr(p))
75715 	      {
75716 		if (!is_pair(car(p))) return(UNSAFE_BODY);
75717 		if (is_pair(cdar(p)))
75718 		  {
75719 		    result = min_body(result, body_is_safe(sc, func, cdar(p), at_end)); /* null cdar(p) ok here */
75720 		    if (result == UNSAFE_BODY)
75721 		      return(UNSAFE_BODY);
75722 		  }
75723 		if (follow) {sp = cdr(sp); if (p == sp) return(UNSAFE_BODY);}
75724 		follow = (!follow);
75725 	      }
75726 	    return(result);
75727 	  }
75728 
75729 	case OP_SET:
75730 	  /* if we set func, we have to abandon the tail call scan: (let () (define (hi a) (let ((v (vector 1 2 3))) (set! hi v) (hi a))) (hi 1)) */
75731 	  if (!is_pair(cddr(x))) return(UNSAFE_BODY);
75732 	  if (cadr(x) == func)
75733 	    return(UNSAFE_BODY);
75734 
75735 	  /* car(x) is set!, cadr(x) is settee or obj, caddr(x) is val */
75736 	  if (is_pair(caddr(x)))
75737 	    {
75738 	      result = form_is_safe(sc, func, caddr(x), false);
75739 	      if (result == UNSAFE_BODY)
75740 		return(UNSAFE_BODY);
75741 	    }
75742 	  return((is_pair(cadr(x))) ? min_body(result, form_is_safe(sc, func, cadr(x), false)) : result);
75743 	  /* not OP_DEFINE even in simple cases (safe_closure assumes constant funclet) */
75744 
75745 	case OP_WITH_LET:
75746 	  if (!is_pair(cddr(x))) return(UNSAFE_BODY);
75747 	  return((is_pair(cadr(x))) ? UNSAFE_BODY : min_body(body_is_safe(sc, sc->F, cddr(x), at_end), SAFE_BODY));
75748 	  /* shadowing can happen in with-let -- symbols are global so local_slots are shadowable */
75749 
75750 	case OP_LET_TEMPORARILY:
75751 	  {
75752 	    s7_pointer p;
75753 	    if (!is_pair(cadr(x))) return(UNSAFE_BODY);
75754 	    for (p = cadr(x); is_pair(p); p = cdr(p))
75755 	      {
75756 		if ((!is_pair(car(p))) ||
75757 		    (!is_pair(cdar(p))))
75758 		  return(UNSAFE_BODY);
75759 		if (is_pair(cadar(p)))
75760 		  {
75761 		    result = min_body(result, form_is_safe(sc, sc->F, cadar(p), false));
75762 		    if (result == UNSAFE_BODY)
75763 		      return(UNSAFE_BODY);
75764 		  }}
75765 	    return(min_body(result, body_is_safe(sc, sc->F, cddr(x), at_end)));
75766 	  }
75767 
75768 	  /* in the name binders, we first have to check that "func" actually is the same thing as the caller's func */
75769 	case OP_LET:
75770 	case OP_LET_STAR:
75771 	case OP_LETREC:
75772 	case OP_LETREC_STAR:
75773 	  {
75774 	    bool follow = false;
75775 	    s7_pointer vars, body, let_name, sp;
75776 
75777 	    vars = cadr(x);
75778 	    body = cddr(x);
75779 	    if (is_symbol(vars))
75780 	      {
75781 		if (!is_pair(body))
75782 		  return(UNSAFE_BODY);        /* (let name . res) */
75783 		if (vars == func)             /* named let shadows caller */
75784 		  return(UNSAFE_BODY);
75785 		let_name = vars;
75786 		vars = caddr(x);
75787 		body = cdddr(x);
75788 		if (is_symbol(func))
75789 		  add_symbol_to_list(sc, func);
75790 	      }
75791 	    else let_name = func;
75792 
75793 	    for (sp = NULL; is_pair(vars); vars = cdr(vars))
75794 	      {
75795 		s7_pointer let_var, var_name;
75796 
75797 		let_var = car(vars);
75798 		if ((!is_pair(let_var)) ||
75799 		    (!is_pair(cdr(let_var))))
75800 		  return(UNSAFE_BODY);
75801 		var_name = car(let_var);
75802 		if ((!is_symbol(var_name)) ||
75803 		    (var_name == let_name) || /* let var shadows caller */
75804 		    (var_name == func))
75805 		  return(UNSAFE_BODY);
75806 		add_symbol_to_list(sc, var_name);
75807 
75808 		if (is_pair(cadr(let_var)))
75809 		  {
75810 		    result = min_body(result, form_is_safe(sc, let_name, cadr(let_var), false));
75811 		    if (result == UNSAFE_BODY)
75812 		      return(UNSAFE_BODY);
75813 		  }
75814 		follow = (!follow);
75815 		if (follow)
75816 		  {
75817 		    if (!sp)
75818 		      sp = vars;
75819 		    else
75820 		      {
75821 			sp = cdr(sp);
75822 			if (vars == sp) return(UNSAFE_BODY);
75823 		      }}}
75824 	    return(min_body(result, body_is_safe(sc, let_name, body, (let_name != func) || at_end)));
75825 	  }
75826 
75827 	case OP_DO:	  /* (do (...) (...) ...) */
75828 	  {
75829 	    if (!is_pair(cddr(x))) return(UNSAFE_BODY);
75830 	    if (is_pair(cadr(x)))
75831 	      {
75832 		bool follow = false;
75833 		s7_pointer vars, sp;
75834 		vars = cadr(x);
75835 		sp = vars;
75836 		for (; is_pair(vars); vars = cdr(vars))
75837 		  {
75838 		    s7_pointer do_var;
75839 		    do_var = car(vars);
75840 		    if ((!is_pair(do_var)) ||
75841 			(!is_pair(cdr(do_var))) ||   /* (do ((a . 1) (b . 2)) ...) */
75842 			(car(do_var) == func) ||
75843 			(!is_symbol(car(do_var))))
75844 		      return(UNSAFE_BODY);
75845 
75846 		    add_symbol_to_list(sc, car(do_var));
75847 
75848 		    if (is_pair(cadr(do_var)))
75849 		      result = min_body(result, form_is_safe(sc, func, cadr(do_var), false));
75850 		    if ((is_pair(cddr(do_var))) &&
75851 			(is_pair(caddr(do_var))))
75852 		      result = min_body(result, form_is_safe(sc, func, caddr(do_var), false));
75853 		    if (result == UNSAFE_BODY)
75854 		      return(UNSAFE_BODY);
75855 		    if (sp != vars)
75856 		      {
75857 			if (follow) {sp = cdr(sp); if (vars == sp) return(UNSAFE_BODY);}
75858 			follow = (!follow);
75859 		      }}}
75860 	    if (is_pair(caddr(x)))
75861 	      result = min_body(result, body_is_safe(sc, func, caddr(x), at_end));
75862 	    return(min_body(result, body_is_safe(sc, func, cdddr(x), false)));
75863 	  }
75864 
75865 	  /* define and friends are not safe: (define (a) (define b 3)...) tries to put b in the current let,
75866 	   *   but in a safe func, that's a constant.  See s7test L 1865 for an example.
75867 	   */
75868 	default:
75869 	  /* try to catch weird cases like:
75870 	   * (let () (define (hi1 a) (define (hi1 b) (+ b 1)) (hi1 a)) (hi1 1))
75871 	   * (let () (define (hi1 a) (define (ho1 b) b) (define (hi1 b) (+ b 1)) (hi1 a)) (hi1 1))
75872 	   */
75873 	  return(UNSAFE_BODY);
75874 	}}
75875   else /* car(x) is not syntactic */
75876     {
75877       if (expr == func) /* try to catch tail call, expr is car(x) */
75878 	{
75879 	  bool follow = false;
75880 	  s7_pointer sp, p;
75881 	  sc->got_rec = true; /* (walk (car tree)) lint and almost all others in s7test */
75882 	  set_rec_tc_args(sc, proper_list_length(cdr(x)));
75883 	  if (!at_end) {result = RECUR_BODY; sc->not_tc = true;}
75884 	  sp = x;
75885 	  for (p = cdr(x); is_pair(p); p = cdr(p))
75886 	    {
75887 	      if (is_pair(car(p)))
75888 		{
75889 		  if (caar(p) == func)    /* func called as arg, so not tail call */
75890 		    {
75891 		      sc->not_tc = true;
75892 		      result = RECUR_BODY;
75893 		    }
75894 		  result = min_body(result, form_is_safe(sc, func, car(p), false));
75895 		  if (result == UNSAFE_BODY)
75896 		    return(UNSAFE_BODY);
75897 		}
75898 	      else
75899 		if (car(p) == func) /* func itself as arg */
75900 		  return(UNSAFE_BODY);
75901 
75902 	      if (follow) {sp = cdr(sp); if (p == sp) return(UNSAFE_BODY);}
75903 	      follow = (!follow);
75904 	    }
75905 	  if ((at_end) && (!sc->not_tc) && (is_null(p))) /* tail call, so safe */
75906 	    {
75907 	      sc->got_tc = true;
75908 	      set_rec_tc_args(sc, proper_list_length(cdr(x)));
75909 	      return(result);
75910 	    }
75911 	  if (result != UNSAFE_BODY) result = RECUR_BODY;
75912 	  return(result);
75913 	}
75914 
75915       if (is_symbol(expr)) /* expr=car(x) */
75916 	{
75917 	  s7_pointer f, f_slot;
75918 	  bool c_safe;
75919 
75920 	  if (symbol_is_in_list(sc, expr))
75921 	    return(UNSAFE_BODY);
75922 
75923 	  f_slot = lookup_slot_from(expr, sc->curlet);
75924 	  if (!is_slot(f_slot))
75925 	    return(UNSAFE_BODY);
75926 	  f = slot_value(f_slot);
75927 	  c_safe = (is_c_function(f)) && (is_safe_or_scope_safe_procedure(f));
75928 	  result = ((is_sequence(f)) ||
75929 		    ((is_closure(f)) && (is_very_safe_closure(f))) ||
75930 		    ((c_safe) && ((is_immutable(f_slot)) || (is_global(expr))))) ? VERY_SAFE_BODY : SAFE_BODY;
75931 
75932 	  if ((c_safe) ||
75933 	      ((is_any_closure(f)) && (is_safe_closure(f))) ||
75934 	      (is_sequence(f)))
75935 	    {
75936 	      bool follow = false;
75937 	      s7_pointer sp, p;
75938 	      p = cdr(x);
75939 	      sp = x;
75940 
75941 	      for (; is_pair(p); p = cdr(p))
75942 		{
75943 		  if (is_unquoted_pair(car(p)))
75944 		    {
75945 		      if (caar(p) == func)
75946 			{
75947 			  sc->got_rec = true; /* (+ 1 (recur (- x 1))) t123 (and others) */
75948 			  set_rec_tc_args(sc, proper_list_length(cdar(p)));
75949 			  return(RECUR_BODY);
75950 			}
75951 		      if ((is_c_function(f)) && (is_scope_safe(f)) &&
75952 			  (caar(p) == sc->lambda_symbol))
75953 			{
75954 			  s7_pointer largs, lbody, q;
75955 			  body_t lresult;
75956 
75957 			  if (!is_pair(cdar(p))) /* (lambda . /) */
75958 			    return(UNSAFE_BODY);
75959 			  largs = cadar(p);
75960 			  lbody = cddar(p);
75961 			  for (q = largs; is_pair(q); q = cdr(q))
75962 			    {
75963 			      if (!is_symbol(car(q)))
75964 				return(UNSAFE_BODY);
75965 			      add_symbol_to_list(sc, car(q));
75966 			    }
75967 			  lresult = body_is_safe(sc, func, lbody, false);
75968 			  result = min_body(result, lresult);
75969 			}
75970 		      else result = min_body(result, form_is_safe(sc, func, car(p), false));
75971 		      if (result == UNSAFE_BODY)
75972 			return(UNSAFE_BODY);
75973 		    }
75974 		  else
75975 		    if (car(p) == func)          /* the current function passed as an argument to something */
75976 		      return(UNSAFE_BODY);
75977 
75978 		  if (follow) {sp = cdr(sp); if (p == sp) return(UNSAFE_BODY);}
75979 		  follow = (!follow);
75980 		}
75981 	      return((is_null(p)) ? result : UNSAFE_BODY);
75982 	    }
75983 	  if ((expr == sc->quote_symbol) &&
75984 	      (is_proper_list_1(sc, cdr(x))) &&
75985 	      (is_global(sc->quote_symbol)))
75986 	    return(result);
75987 
75988 	  if (expr == sc->values_symbol)      /* (values) is safe, as is (values x) if x is: (values (define...)) */
75989 	    {
75990 	      if (is_null(cdr(x)))
75991 		return(result);
75992 	      if ((is_pair(cdr(x))) && (is_null(cddr(x))))
75993 		return((is_pair(cadr(x))) ? min_body(result, form_is_safe(sc, func, cadr(x), false)) : result);
75994 	    }
75995 
75996 	  if ((expr == sc->apply_symbol) &&        /* (apply + ints) */
75997 	      (is_pair(cdr(x))) &&
75998 	      (is_pair(cddr(x))) &&
75999 	      (is_null(cdddr(x))) &&
76000 	      ((!is_pair(caddr(x))) ||
76001 	       (form_is_safe(sc, func, caddr(x), false))))
76002 	    {
76003 	      s7_pointer fn;
76004 	      fn = cadr(x);
76005 	      if (is_symbol(fn))
76006 		{
76007 		  s7_pointer fn_slot;
76008 		  if (symbol_is_in_list(sc, fn))
76009 		    return(UNSAFE_BODY);
76010 		  fn_slot = lookup_slot_from(fn, sc->curlet);
76011 		  if (!is_slot(fn_slot))
76012 		    return(UNSAFE_BODY);
76013 		  fn = slot_value(fn_slot);
76014 		  if ((is_c_function(fn)) && (is_safe_procedure(fn)))
76015 		    return(result);
76016 		  if ((is_closure(fn)) && (is_very_safe_closure(fn)))
76017 		    return(result);
76018 		}}}
76019       return(UNSAFE_BODY); /* not recur_body here if at_end -- possible defines in body etc */
76020     }
76021   return(result);
76022 }
76023 
76024 static body_t body_is_safe(s7_scheme *sc, s7_pointer func, s7_pointer body, bool at_end)
76025 {
76026   bool follow = false;
76027   s7_pointer p, sp;
76028   body_t result = VERY_SAFE_BODY;
76029   for (p = body, sp = body; is_pair(p); p = cdr(p))
76030     {
76031       if (is_pair(car(p)))
76032 	{
76033 	  result = min_body(result, form_is_safe(sc, func, car(p), (at_end) && (is_null(cdr(p)))));
76034 	  if (result == UNSAFE_BODY) return(UNSAFE_BODY);
76035 	}
76036       if (p != body)
76037 	{
76038 	  if (follow) {sp = cdr(sp); if (p == sp) return(UNSAFE_BODY);}
76039 	  follow = (!follow);
76040 	}}
76041   return((is_null(p)) ? result : UNSAFE_BODY);
76042 }
76043 
76044 static bool tree_has_definers_or_binders(s7_scheme *sc, s7_pointer tree)
76045 {
76046   s7_pointer p;
76047   for (p = tree; is_pair(p); p = cdr(p))
76048     if (tree_has_definers_or_binders(sc, car(p)))
76049       return(true);
76050   return((is_symbol(tree)) &&
76051 	 (is_definer_or_binder(tree)));
76052 }
76053 
76054 static void optimize_lambda(s7_scheme *sc, bool unstarred_lambda, s7_pointer func, s7_pointer args, s7_pointer body)
76055 {                                                                 /* func is either sc->unused or a symbol */
76056   s7_int len;
76057   len = s7_list_length(sc, body);
76058 
76059   if (len < 0)                /* (define (hi) 1 . 2) */
76060     s7_error(sc, sc->syntax_error_symbol,
76061 	     set_elist_3(sc, wrap_string(sc, "~A: function body messed up, ~A", 31),
76062 			 (unstarred_lambda) ? sc->lambda_symbol : sc->lambda_star_symbol,
76063 			 sc->code));
76064 
76065   if (len > 0)  /* i.e. not circular */
76066     {
76067       body_t result;
76068       s7_pointer p, lst, cleared_args;
76069 
76070       clear_symbol_list(sc);
76071       for (p = args; is_pair(p); p = cdr(p))
76072 	add_symbol_to_list(sc, (is_symbol(car(p))) ? car(p) : caar(p));
76073       if (!is_null(p))
76074 	add_symbol_to_list(sc, p);
76075       sc->got_tc = false;
76076       sc->not_tc = false;
76077       sc->got_rec = false;
76078       sc->rec_tc_args = -1;
76079       result = ((is_symbol(func)) && (symbol_is_in_list(sc, func))) ? UNSAFE_BODY : body_is_safe(sc, func, body, true);  /* (define (f f)...) */
76080       clear_symbol_list(sc);
76081 
76082       /* if the body is safe, we can optimize the calling sequence */
76083       if (!unstarred_lambda)
76084 	{
76085 	  bool happy = true;
76086 	  /* check default vals -- if none is an expression or symbol, set simple args */
76087 	  for (p = args; is_pair(p); p = cdr(p))
76088 	    {
76089 	      s7_pointer arg;
76090 	      arg = car(p);
76091 	      if ((is_pair(arg)) &&                   /* has default value */
76092 		  (is_pair(cdr(arg))) &&              /*   is not a ridiculous improper list */
76093 		  ((is_symbol(cadr(arg))) ||          /*   if default value might involve eval in any way, it isn't simple */
76094 		   (is_unquoted_pair(cadr(arg)))))    /*   pair as default only ok if it is (quote ...) */
76095 		{
76096 		  happy = false;
76097 		  if ((result > UNSAFE_BODY) &&
76098 		      (tree_has_definers_or_binders(sc, cadr(arg)))) /* if the default has a definer, body is not safe (funclet is not stable) */
76099 		    result = UNSAFE_BODY;
76100 		  break;
76101 		}}
76102 	  if (happy)
76103 	    lambda_set_simple_defaults(body);
76104 	}
76105       if (result >= SAFE_BODY) /* not RECUR_BODY here (need new let for one thing: cons-r in s7test) */
76106 	{
76107 	  set_safe_closure_body(body);
76108 	  if (result == VERY_SAFE_BODY)
76109 	    set_very_safe_closure_body(body);
76110 	}
76111 
76112       if (is_symbol(func))
76113 	{
76114 	  lst = list_1(sc, add_symbol_to_list(sc, func));
76115 	  sc->temp1 = lst;
76116 	}
76117       else lst = sc->nil;
76118 
76119       if (optimize(sc, body, 1, cleared_args = collect_parameters(sc, args, lst)) == OPT_OOPS)
76120 	clear_all_optimizations(sc, body);
76121       else
76122 	{
76123 	  if (result >= RECUR_BODY) /* (is_safe_closure_body(body)) */
76124 	    {
76125 	      int32_t nvars;
76126 	      for (nvars = 0, p = args; is_pair(p); nvars++, p = cdr(p));
76127 	      if ((is_null(p)) &&
76128 		  (nvars > 0))
76129 		{
76130 		  fx_annotate_args(sc, body, cleared_args);
76131 		  fx_tree(sc, body,
76132 			  (is_pair(car(args))) ? caar(args) : car(args),
76133 			  (nvars > 1) ? ((is_pair(cadr(args))) ? caadr(args) : cadr(args)) : NULL);
76134 		  /* fx_tree_outer using sc->curlet? */
76135 		  /* local is args (cleared_args has func as last), out(loc) runtime is funclet+func
76136 		   *   so let_outlet(let_outlet(local)) is sc->curlet?
76137 		   */
76138 		  /* macros confuse this */
76139 		}
76140 	      if (((unstarred_lambda) || ((is_null(p)) && (nvars == sc->rec_tc_args))) &&
76141 		  (is_null(cdr(body))))
76142 		{ /* (if <a> #t|#f...) happens only rarely */
76143 		  if (sc->got_tc)
76144 		    {
76145 		      if (check_tc(sc, func, nvars, args, car(body)))
76146 			set_safe_closure_body(body);	      /* (very_)safe_closure set above if > RECUR_BODY */
76147 		      /* if not check_tc, car(body) is either not a tc op or it is not optimized so that is_fxable will return false */
76148 		    }
76149 		  if ((sc->got_rec) &&
76150 		      (!is_tc_op(optimize_op(car(body)))) &&
76151 		      (check_recur(sc, func, nvars, args, car(body))))
76152 		    set_safe_closure_body(body);
76153 		}}}
76154       if (is_symbol(func))
76155 	{
76156 	  sc->temp1 = sc->nil;
76157 	  free_cell(sc, lst);
76158 	}
76159       sc->got_tc = false;
76160       sc->not_tc = false;
76161       sc->got_rec = false;
76162     }
76163 }
76164 
76165 static int32_t check_lambda(s7_scheme *sc, s7_pointer form, bool opt)
76166 {
76167   /* code is a lambda form: (lambda (a b) (+ a b)) */
76168   /* this includes unevaluated symbols (direct symbol table refs) in macro arg list */
76169   s7_pointer code, body;
76170   int32_t arity = 0;
76171 
76172   if ((sc->safety > NO_SAFETY) &&
76173       (tree_is_cyclic(sc, form)))
76174     s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "lambda: body is cyclic", 22));
76175 
76176   code = cdr(form);
76177   if (!is_pair(code))                                 /* (lambda) or (lambda . 1) */
76178     eval_error(sc, "lambda: no args? ~A", 19, form);
76179 
76180   body = cdr(code);
76181   if (!is_pair(body))                                 /* (lambda #f) */
76182     eval_error(sc, "lambda: no body? ~A", 19, form);
76183 
76184   /* in many cases, this is a no-op -- we already checked at define */
76185   check_lambda_args(sc, car(code), &arity);
76186   /* clear_symbol_list(sc); */ /* not used in check_lambda_args and clobbers optimize_expression find_uncomplicated_symbol check */
76187 
76188   /* look for (define f (let (...) (lambda ...))) and treat as equivalent to (define (f ...)...)
76189    *   one problem the hop=0 fixes is that safe closures assume the old let exists, so we need to check for define below
76190    *   I wonder about apply define...
76191    */
76192   /* OP_LET1 should work here also, (let ((f (lambda...)))), but subsequent calls assume a saved let if safe
76193    *   to mimic define, we need to parallel op_define_with_setter + make_funclet, I think
76194    */
76195   if ((opt) ||
76196       (main_stack_op(sc) == OP_DEFINE1) ||
76197       (((sc->stack_end - sc->stack_start) > 4) &&
76198        (((opcode_t)(sc->stack_end[-5])) == OP_DEFINE1) &&  /* surely if define is ok, so is define dilambda? 16-Apr-16 */
76199        (sc->op_stack_now > sc->op_stack) &&
76200        ((*(sc->op_stack_now - 1)) == (s7_pointer)global_value(sc->dilambda_symbol))))
76201     optimize_lambda(sc, true, sc->unused, car(code), body);
76202   else
76203     if (optimize(sc, body, 0,
76204 		 /* ((sc->op_stack_now > sc->op_stack) && (is_c_function((*(sc->op_stack_now - 1)))) && (is_scope_safe((*(sc->op_stack_now - 1))))) ? 1 : 0, */
76205 		 /* this works except when someone resets outlet(curlet) after defining a local function! */
76206 		 collect_parameters(sc, car(code), sc->nil)) == OPT_OOPS)
76207       clear_all_optimizations(sc, body);
76208   pair_set_syntax_op(form, OP_LAMBDA_UNCHECKED);
76209   if (arity < -1) arity++; /* confusing! at least 0 = (), but (lambda arg...) has same "arity" here as (lambda (a . b)...)? */
76210   set_opt3_any(code, (s7_pointer)((intptr_t)arity));
76211   return(arity);
76212 }
76213 
76214 static void op_lambda(s7_scheme *sc)
76215 {
76216   int32_t arity;
76217   arity = check_lambda(sc, sc->code, false);
76218   sc->code = cdr(sc->code);
76219   set_opt3_any(sc->code, (s7_pointer)((intptr_t)arity));
76220   sc->value = make_closure(sc, car(sc->code), cdr(sc->code), T_CLOSURE | T_COPY_ARGS, arity);
76221 }
76222 
76223 #define op_lambda_unchecked(sc) sc->value = inline_make_closure(sc, cadr(sc->code), cddr(sc->code), T_CLOSURE | T_COPY_ARGS, (int32_t)((intptr_t)opt3_any(cdr(sc->code))))
76224 
76225 static void check_lambda_star(s7_scheme *sc)
76226 {
76227   s7_pointer code;
76228   if ((sc->safety > NO_SAFETY) &&
76229       (tree_is_cyclic(sc, sc->code)))
76230     s7_error(sc, sc->wrong_type_arg_symbol, wrap_string(sc, "lambda*: body is cyclic", 23));
76231 
76232   code = cdr(sc->code);
76233   if ((!is_pair(code)) ||
76234       (!is_pair(cdr(code))))                                          /* (lambda*) or (lambda* #f) */
76235     eval_error(sc, "lambda*: no args or no body? ~A", 31, sc->code);
76236 
76237   set_car(code, check_lambda_star_args(sc, car(code), NULL));
76238 
76239   if ((sc->safety > NO_SAFETY) ||
76240       (main_stack_op(sc) != OP_DEFINE1))
76241     {
76242       if (optimize(sc, cdr(code), 0, collect_parameters(sc, car(code), sc->nil)) == OPT_OOPS)
76243 	clear_all_optimizations(sc, cdr(code));
76244     }
76245   else optimize_lambda(sc, false, sc->unused, car(code), cdr(code));
76246 
76247   pair_set_syntax_op(sc->code, OP_LAMBDA_STAR_UNCHECKED);
76248   sc->code = code;
76249 }
76250 
76251 
76252 /* -------------------------------- case -------------------------------- */
76253 static s7_pointer check_case(s7_scheme *sc)
76254 {
76255   /* we're not checking repeated or ridiculous (non-eqv?) keys here because they aren't errors */
76256   bool keys_simple = true, has_feed_to = false, keys_single = true, bodies_simple = true, has_else = false;
76257   int32_t key_type = T_FREE;
76258   s7_pointer x, carc, code;
76259 
76260   code = cdr(sc->code);
76261   if (!is_pair(code))                                            /* (case) or (case . 1) */
76262     eval_error(sc, "case has no selector:  ~A", 25, sc->code);
76263   if (!is_pair(cdr(code)))                                       /* (case 1) or (case 1 . 1) */
76264     eval_error(sc, "case has no clauses?:  ~A", 25, sc->code);
76265   if (!is_pair(cadr(code)))                                      /* (case 1 1) */
76266     eval_error(sc, "case clause is not a list? ~A", 29, sc->code);
76267   set_opt3_any(code, sc->unspecified);
76268 
76269   for (x = cdr(code); is_pair(x); x = cdr(x))
76270     {
76271       s7_pointer y, car_x;
76272       if ((!is_pair(x)) ||                                           /* (case 1 ((2) 1) . 1) */
76273 	  (!is_pair(car(x))))
76274 	eval_error(sc, "case clause ~A messed up", 24, x);
76275       car_x = car(x);
76276 
76277       if (!is_list(cdr(car_x)))                                      /* (case 1 ((1))) */
76278 	eval_error(sc, "case clause result messed up: ~A", 32, car_x);
76279 
76280       if ((bodies_simple) &&
76281 	  ((is_null(cdr(car_x))) || (!is_null(cddr(car_x)))))
76282 	bodies_simple = false;
76283 
76284       y = car(car_x);
76285       if (!is_pair(y))
76286 	{
76287 	  if ((y != sc->else_symbol) &&                              /* (case 1 (2 1)) */
76288 	      ((!is_symbol(y)) ||
76289 	       (s7_symbol_value(sc, y) != sc->else_symbol)))         /* "proper list" below because: (case 1 (() 2) ... */
76290 	    eval_error(sc, "case clause key list ~A is not a proper list or 'else'", 54, y);
76291 	  else has_else = true;
76292 	  if (is_not_null(cdr(x)))                                  /* (case 1 (else 1) ((2) 1)) */
76293 	    eval_error(sc, "case 'else' clause, ~A, is not the last clause", 46, x);
76294 	  if (!is_null(cdr(car_x)))                                  /* else (else) so return selector */
76295 	    {
76296 	      if (is_pair(cddr(car_x)))
76297 		{
76298 		  set_opt3_any(code, cdr(car_x));
76299 		  bodies_simple = false;
76300 		}
76301 	      else
76302 		{
76303 		  if ((bodies_simple) &&
76304 		      (keys_single))
76305 		    set_opt3_any(code, cadr(car_x));
76306 		  else set_opt3_any(code, cdr(car_x));
76307 		  set_opt1_clause(x, cadr(car_x));
76308 		}}}
76309       else
76310 	{
76311 	  if (!is_simple(car(y)))
76312 	    keys_simple = false;
76313 	  if (!is_null(cdr(y)))
76314 	    keys_single = false;
76315 	  if (key_type == T_FREE)
76316 	    key_type = type(car(y));
76317 	  else
76318 	    if (key_type != type(car(y)))
76319 	      key_type = NUM_TYPES;
76320 	  if (key_type == T_SYMBOL) set_case_key(car(y));
76321 
76322 	  for (y = cdr(y); is_pair(y); y = cdr(y))
76323 	    {
76324 	      if (!is_simple(car(y)))
76325 		keys_simple = false;
76326 	      if (key_type != type(car(y)))
76327 		key_type = NUM_TYPES;
76328 	      if (key_type == T_SYMBOL) set_case_key(car(y));
76329 	    }
76330 	  if (!is_null(y))                                        /* (case () ((1 . 2) . hi) . hi) */
76331 	    eval_error(sc, "case key list is improper? ~A", 29, x);
76332 	}
76333       y = car_x;
76334       if (!s7_is_proper_list(sc, cdr(y)))
76335 	eval_error(sc, "case: stray dot? ~A", 19, y);
76336       if ((is_pair(cdr(y))) &&
76337 	  (cadr(y) == sc->feed_to_symbol) &&
76338 	  (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
76339 	{
76340 	  has_feed_to = true;
76341 	  if (!is_pair(cddr(y)))                                  /* (case 1 (else =>)) */
76342 	    eval_error(sc, "case: '=>' target missing?  ~A", 30, y);
76343 	  if (is_pair(cdddr(y)))                                  /* (case 1 (else => + - *)) */
76344 	    eval_error(sc, "case: '=>' has too many targets: ~A", 35, y);
76345 	}}
76346   if (is_not_null(x))                                             /* (case x ((1 2)) . 1) */
76347     eval_error(sc, "case: stray dot? ~A", 19, sc->code);
76348 
76349   if ((keys_single) &&
76350       (bodies_simple))
76351     {
76352       for (x = cdr(code); is_not_null(x); x = cdr(x))
76353 	{
76354 	  set_opt2_any(x, caar(x));
76355 	  if (is_pair(opt2_any(x)))
76356 	    {
76357 	      set_opt2_any(x, car(opt2_any(x)));
76358 	      if (is_pair(cdar(x)))
76359 		set_opt1_clause(x, cadar(x));
76360 	    }}}
76361   else
76362     for (x = cdr(code); is_not_null(x); x = cdr(x))
76363       {
76364 	set_opt2_any(x, caar(x));
76365 	if ((is_pair(opt2_any(x))) &&
76366 	    (is_pair(cdar(x))))
76367 	  set_opt1_clause(x, cadar(x));
76368       }
76369   if (key_type == T_INTEGER)
76370     set_has_integer_keys(sc->code);
76371 
76372   pair_set_syntax_op(sc->code, OP_CASE_P_G_G); /* fallback on this */
76373   if ((has_feed_to) ||
76374       (!bodies_simple) ||  /* x_x_g g=general keys or bodies */
76375       (!keys_single))
76376     {
76377       if (!keys_simple)  /* x_g_g (no int32_t case here) */
76378 	{
76379 	  if (is_symbol(car(code)))
76380 	    pair_set_syntax_op(sc->code, OP_CASE_S_G_G);
76381 	  else
76382 	    {
76383 	      if (is_fxable(sc, car(code)))
76384 		{
76385 		  pair_set_syntax_op(sc->code, OP_CASE_A_G_G);
76386 		  set_fx_direct(code, fx_choose(sc, code, sc->curlet, let_symbol_is_safe));
76387 		}
76388 	      else pair_set_syntax_op(sc->code, OP_CASE_P_G_G);
76389 	    }}
76390       else             /* x_e_g */
76391 	{
76392 	  if (!has_else) set_opt3_any(code, sc->unused); /* affects all that goto CASE_E_G */
76393 	  if (is_symbol(car(code)))
76394 	    pair_set_syntax_op(sc->code, (key_type == T_SYMBOL) ? OP_CASE_S_S_G : OP_CASE_S_E_G);
76395 	  else
76396 	    {
76397 	      if (is_fxable(sc, car(code)))
76398 		{
76399 		  pair_set_syntax_op(sc->code, (key_type == T_SYMBOL) ? OP_CASE_A_S_G : OP_CASE_A_E_G);
76400 		  set_fx_direct(code, fx_choose(sc, code, sc->curlet, let_symbol_is_safe));
76401 		}
76402 	      else pair_set_syntax_op(sc->code, (key_type == T_SYMBOL) ? OP_CASE_P_S_G: OP_CASE_P_E_G);
76403 	    }}}
76404   else                /* x_x_s */
76405     {
76406       if (!keys_simple)  /* x_g|i_s */
76407 	{
76408 	  if (is_symbol(car(code)))
76409 	    pair_set_syntax_op(sc->code, ((!WITH_GMP) && (key_type == T_INTEGER)) ? OP_CASE_S_I_S : OP_CASE_S_G_S);
76410 	  else
76411 	    {
76412 	      if (is_fxable(sc, car(code)))
76413 		{
76414 		  pair_set_syntax_op(sc->code, ((!WITH_GMP) && (key_type == T_INTEGER)) ? OP_CASE_A_I_S : OP_CASE_A_G_S);
76415 		  set_fx_direct(code, fx_choose(sc, code, sc->curlet, let_symbol_is_safe));
76416 		}
76417 	      else pair_set_syntax_op(sc->code, ((!WITH_GMP) && (key_type == T_INTEGER)) ? OP_CASE_P_I_S : OP_CASE_P_G_S);
76418 	    }}
76419       else             /* x_e_s */
76420 	{
76421 	  if (is_symbol(car(code)))
76422 	    pair_set_syntax_op(sc->code, (key_type == T_SYMBOL) ? OP_CASE_S_S_S : OP_CASE_S_E_S);
76423 	  else
76424 	    {
76425 	      if (is_fxable(sc, car(code)))
76426 		{
76427 		  pair_set_syntax_op(sc->code, (key_type == T_SYMBOL) ? OP_CASE_A_S_S : OP_CASE_A_E_S);
76428 		  set_fx_direct(code, fx_choose(sc, code, sc->curlet, let_symbol_is_safe));
76429 		}
76430 	      else pair_set_syntax_op(sc->code, (key_type == T_SYMBOL) ? OP_CASE_P_S_S : OP_CASE_P_E_S);
76431 	    }}}
76432 
76433   carc = cadr(sc->code);
76434   if (!is_pair(carc))
76435     {
76436       sc->value = (is_symbol(carc)) ? lookup_checked(sc, carc) : carc;
76437       return(NULL);
76438     }
76439   push_stack_no_args_direct(sc, OP_CASE_G_G);
76440   sc->code = carc;
76441   return(carc);
76442 }
76443 
76444 #if (!WITH_GMP)
76445 static bool op_case_i_s(s7_scheme *sc)
76446 {
76447   s7_pointer x, selector, else_clause;
76448   selector = sc->value;
76449   else_clause = opt3_any(cdr(sc->code));
76450   if (else_clause != sc->unspecified)
76451     {
76452       if (is_t_integer(selector))
76453 	{
76454 	  s7_int val;
76455 	  val = integer(selector);
76456 	  for (x = cddr(sc->code); is_pair(x); x = cdr(x))
76457 	    if (is_t_integer(opt2_any(x)))
76458 	      {
76459 		if (integer(opt2_any(x)) == val)
76460 		  {
76461 		    sc->code = opt1_clause(x);
76462 		    return(false);
76463 		  }}
76464 	    else break;
76465 	}
76466       sc->code = else_clause;
76467       return(false);
76468     }
76469   if (is_t_integer(selector))
76470     {
76471       s7_int val;
76472       val = integer(selector);
76473       for (x = cddr(sc->code); is_pair(x); x = cdr(x))
76474 	if (integer(opt2_any(x)) == val)
76475 	  {
76476 	    sc->code = opt1_clause(x);
76477 	    return(false);
76478 	  }}
76479   sc->value = sc->unspecified;
76480   return(true);
76481 }
76482 #endif
76483 
76484 static bool op_case_e_g_1(s7_scheme *sc, s7_pointer selector, bool ok)
76485 {
76486   s7_pointer x, y;
76487   if (ok)
76488     {
76489       for (x = cddr(sc->code); is_pair(x); x = cdr(x))
76490 	{
76491 	  y = opt2_any(x);
76492 	  if (!is_pair(y)) /* i.e. else? */
76493 	    goto ELSE_CASE_1;
76494 	  do {
76495 	    if (car(y) == selector)
76496 	      goto ELSE_CASE_1;
76497 	    y = cdr(y);
76498 	  } while (is_pair(y));
76499 	}
76500       sc->value = sc->unspecified;
76501       pop_stack(sc);
76502       return(true);
76503     }
76504 
76505   sc->code = opt3_any(cdr(sc->code));
76506   if (sc->code == sc->unused)    /* set in check_case if no else clause */
76507     sc->value = sc->unspecified;
76508   else
76509     if (is_pair(sc->code))
76510       goto ELSE_CASE_2;
76511   pop_stack(sc);
76512   return(true);
76513 
76514  ELSE_CASE_1:
76515   /* x is the entire matching clause, (case 2 ((2) 3)), x: (((2) 3)) */
76516   sc->code = T_Lst(cdar(x));
76517   if (is_null(sc->code))  /* sc->value is already the selector */
76518     {
76519       pop_stack(sc);
76520       return(true);
76521     }
76522 
76523  ELSE_CASE_2:
76524   if (is_null(cdr(sc->code)))
76525     {
76526       sc->code = car(sc->code);
76527       sc->cur_op = optimize_op(sc->code);
76528       return(true);
76529     }
76530 
76531   if ((car(sc->code) == sc->feed_to_symbol) &&
76532       (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
76533     return(false);
76534 
76535   push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(sc->code)));
76536   sc->code = car(sc->code);
76537   sc->cur_op = optimize_op(sc->code);
76538   return(true);
76539 }
76540 
76541 static bool op_case_g_g(s7_scheme *sc)
76542 {
76543   s7_pointer x, y;
76544   if (has_integer_keys(sc->code))
76545     {
76546       s7_int selector;
76547       sc->code = cddr(sc->code);
76548       if (is_t_integer(sc->value))
76549 	selector = integer(sc->value);
76550       else
76551 	{
76552 #if WITH_GMP
76553 	  if ((is_t_big_integer(sc->value)) && (mpz_fits_slong_p(big_integer(sc->value))))
76554 	    selector = mpz_get_si(big_integer(sc->value));
76555 	  else
76556 #endif
76557 	    {
76558 	      for (x = sc->code; is_pair(x); x = cdr(x)) /* maybe preset the else case */
76559 		if (!is_pair(caar(x)))
76560 		  goto ELSE_CASE;
76561 	      sc->value = sc->unspecified;
76562 	      pop_stack(sc);
76563 	      return(true);
76564 	    }}
76565       for (x = sc->code; is_pair(x); x = cdr(x))
76566 	{
76567 	  y = caar(x);
76568 	  if (!is_pair(y))
76569 	    goto ELSE_CASE;
76570 	  for (; is_pair(y); y = cdr(y))
76571 	    if (integer(car(y)) == selector)
76572 	      goto ELSE_CASE;
76573 	}
76574       sc->value = sc->unspecified;
76575       pop_stack(sc);
76576       return(true);
76577     }
76578   sc->code = cddr(sc->code);
76579   if (is_simple(sc->value))
76580     {
76581       for (x = sc->code; is_pair(x); x = cdr(x))
76582 	{
76583 	  y = caar(x);
76584 	  if (!is_pair(y))
76585 	    goto ELSE_CASE;
76586 	  do {
76587 	    if (car(y) == sc->value)
76588 	      goto ELSE_CASE;
76589 	    y = cdr(y);
76590 	  } while (is_pair(y));
76591 	}
76592       sc->value = sc->unspecified;
76593       pop_stack(sc);
76594       return(true);
76595     }
76596 
76597   for (x = sc->code; is_pair(x); x = cdr(x))
76598     {
76599       y = caar(x);
76600       if (!is_pair(y))
76601 	goto ELSE_CASE;
76602       for (; is_pair(y); y = cdr(y))
76603 	if (s7_is_eqv(sc, car(y), sc->value))
76604 	  goto ELSE_CASE;
76605     }
76606   sc->value = sc->unspecified; /* this was sc->nil but the spec says case value is unspecified if no clauses match */
76607   pop_stack(sc);
76608   return(true);
76609 
76610  ELSE_CASE:
76611   /* x is the entire matching clause, (case 2 ((2) 3)), x: (((2) 3)) */
76612   sc->code = T_Lst(cdar(x));
76613   if (is_null(sc->code))  /* sc->value is already the selector */
76614     {
76615       pop_stack(sc);
76616       return(true);
76617     }
76618   if (is_null(cdr(sc->code)))
76619     {
76620       sc->code = car(sc->code);
76621       sc->cur_op = optimize_op(sc->code);
76622       return(true);
76623     }
76624   if ((car(sc->code) == sc->feed_to_symbol) &&
76625       (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
76626     return(false);
76627   if (is_pair(cdr(T_Pair(sc->code))))
76628     push_stack_no_args(sc, sc->begin_op, cdr(sc->code));
76629   sc->code = car(sc->code);
76630   sc->cur_op = optimize_op(sc->code);
76631   return(true);
76632 }
76633 
76634 static void op_case_e_s(s7_scheme *sc)
76635 {
76636   s7_pointer selector;
76637   selector = sc->value;
76638   if (is_simple(selector))
76639     {
76640       s7_pointer x;
76641       for (x = cddr(sc->code); is_pair(x); x = cdr(x))
76642 	if (opt2_any(x) == selector)
76643 	  {
76644 	    sc->code = opt1_clause(x);
76645 	    return;
76646 	  }}
76647   sc->code = opt3_any(cdr(sc->code));
76648 }
76649 
76650 static void op_case_s_s(s7_scheme *sc)
76651 {
76652   s7_pointer selector;
76653   selector = sc->value;
76654   if (is_symbol(selector))
76655     {
76656       s7_pointer x;
76657       for (x = cddr(sc->code); is_pair(x); x = cdr(x))
76658 	if (opt2_any(x) == selector)
76659 	  {
76660 	    sc->code = opt1_clause(x);
76661 	    return;
76662 	  }}
76663   sc->code = opt3_any(cdr(sc->code));
76664 }
76665 
76666 static void op_case_g_s(s7_scheme *sc)
76667 {
76668   s7_pointer x, selector;
76669   selector = sc->value;
76670   for (x = cddr(sc->code); is_pair(x); x = cdr(x))
76671     if (s7_is_eqv(sc, opt2_any(x), selector))
76672       {
76673 	sc->code = opt1_clause(x);
76674 	return;
76675       }
76676   sc->code = opt3_any(cdr(sc->code));
76677 }
76678 
76679 
76680 /* -------------------------------- let -------------------------------- */
76681 static void check_let_a_body(s7_scheme *sc, s7_pointer form)
76682 {
76683   s7_pointer code;
76684   code = cdr(form);
76685   if (is_fxable(sc, cadr(code)))
76686     {
76687       fx_annotate_arg(sc, cdr(code), set_plist_1(sc, caaar(code))); /* was sc->curlet) ? */
76688       fx_tree(sc, cdr(code), caaar(code), NULL);
76689       pair_set_syntax_op(form, OP_LET_A_A_OLD);
76690     }
76691   else
76692     if (is_pair(cadr(code)))
76693       pair_set_syntax_op(form, OP_LET_A_P_OLD);
76694 }
76695 
76696 static void check_let_one_var(s7_scheme *sc, s7_pointer form, s7_pointer start)
76697 {
76698   s7_pointer binding, code;
76699   code = cdr(form);
76700   binding = car(start);
76701   if (is_pair(cadr(binding)))
76702     {
76703       /* this is not a named let */
76704       pair_set_syntax_op(form, ((is_pair(cdr(code))) && (is_null(cddr(code)))) ? OP_LET_ONE_P_OLD : OP_LET_ONE_OLD);
76705       set_opt2_sym(cdr(code), car(binding)); /* these don't collide -- cdr(code) and code */
76706       set_opt2_pair(code, cadr(binding));
76707 
76708       if (is_optimized(cadr(binding)))
76709 	{
76710 	  if (is_null(cddr(code)))                   /* one statement body */
76711 	    {
76712 	      if (optimize_op(cadr(binding)) == HOP_SAFE_C_SS)
76713 		{
76714 		  /* no lt fx here, 4 s7test */
76715 		  if (fn_proc(cadr(binding)) == g_assq)
76716 		    {
76717 		      set_opt2_sym(code, cadadr(binding));
76718 		      pair_set_syntax_op(form, OP_LET_opaSSq_E_OLD);
76719 		    }
76720 		  else pair_set_syntax_op(form, OP_LET_opSSq_E_OLD);
76721 		  set_opt3_sym(cdr(code), caddadr(binding));
76722 		  set_opt1_sym(code, car(binding));
76723 		  return;
76724 		}
76725 	      if (is_fxable(sc, cadr(binding)))
76726 		{
76727 		  set_opt2_pair(code, binding);
76728 		  pair_set_syntax_op(form, OP_LET_A_OLD);
76729 		  fx_annotate_arg(sc, cdr(binding), sc->curlet);
76730 		  check_let_a_body(sc, form);
76731 		  return;
76732 		}}
76733 	  if (optimize_op(cadr(binding)) == HOP_SAFE_C_SS)
76734 	    {
76735 	      if (fn_proc(cadr(binding)) == g_assq)
76736 		{
76737 		  set_opt2_sym(code, cadadr(binding));
76738 		  pair_set_syntax_op(form, OP_LET_opaSSq_OLD);
76739 		}
76740 	      else pair_set_syntax_op(form, OP_LET_opSSq_OLD);
76741 	      set_opt3_sym(cdr(code), caddadr(binding));
76742 	      set_opt1_sym(code, car(binding));
76743 	    }
76744 	  else
76745 	    {
76746 	      if (is_fxable(sc, cadr(binding)))
76747 		{
76748 		  set_opt2_pair(code, binding);
76749 		  pair_set_syntax_op(form, OP_LET_A_OLD);
76750 		  fx_annotate_arg(sc, cdr(binding), sc->curlet);
76751 		  if (is_null(cddr(code)))
76752 		    check_let_a_body(sc, form);
76753 		  else
76754 		    {
76755 		      s7_pointer p;
76756 		      for (p = cdr(code); is_pair(p); p = cdr(p))
76757 			if (!is_fxable(sc, car(p)))
76758 			  break;
76759 		      if (is_null(p))
76760 			{
76761 			  pair_set_syntax_op(form, OP_LET_A_FX_OLD);
76762 			  fx_annotate_args(sc, cdr(code), set_plist_1(sc, car(binding)));
76763 			  fx_tree(sc, cdr(code), car(binding), NULL);
76764 			  return;
76765 			}}}}}}
76766   else
76767     {
76768       set_opt2_pair(code, binding);
76769       pair_set_syntax_op(form, OP_LET_A_OLD);
76770       fx_annotate_arg(sc, cdr(binding), sc->curlet);
76771       if (is_null(cddr(code))) check_let_a_body(sc, form);
76772     }
76773   if ((optimize_op(form) == OP_LET_A_OLD) &&
76774       (is_pair(cddr(code))) && (is_null(cdddr(code))))
76775     pair_set_syntax_op(form, OP_LET_A_OLD_2);
76776 }
76777 
76778 static s7_pointer check_named_let(s7_scheme *sc, int32_t vars)
76779 {
76780   s7_pointer code;
76781   code = cdr(sc->code);
76782   set_opt2_int(code, make_permanent_integer(vars));
76783   if (vars == 0)
76784     {
76785       pair_set_syntax_op(sc->code, OP_NAMED_LET_NO_VARS);
76786       optimize_lambda(sc, true, car(code), sc->nil, cddr(code));
76787     }
76788   else
76789     {
76790       s7_pointer ex, exp;
76791       bool fx_ok = true;
76792       pair_set_syntax_op(sc->code, OP_NAMED_LET);
76793       /* this is (let name ...) so the initial values need to be removed from the closure arg list */
76794 
76795       sc->args = T_Pair(safe_list_if_possible(sc, vars));
76796       for (ex = cadr(code), exp = sc->args; is_pair(ex); ex = cdr(ex), exp = cdr(exp))
76797 	{
76798 	  s7_function fx;
76799 	  s7_pointer val;
76800 	  val = cdar(ex);
76801 	  fx = fx_choose(sc, val, sc->curlet, let_symbol_is_safe);
76802 	  if (fx) set_fx_direct(val, fx); else fx_ok = false;
76803 	  car(exp) = caar(ex);
76804 	}
76805       if (fx_ok)
76806 	pair_set_syntax_op(sc->code, OP_NAMED_LET_FX);
76807 
76808       optimize_lambda(sc, true, car(code), sc->args, cddr(code)); /* car(code) is the name */
76809       clear_list_in_use(sc->args);
76810       sc->args = sc->nil;
76811     }
76812   return(code);
76813 }
76814 
76815 static s7_pointer check_let(s7_scheme *sc) /* called only from op_let */
76816 {
76817   s7_pointer x, start, code;
76818   bool named_let;
76819   int32_t vars;
76820 
76821   code = cdr(sc->code);
76822   if (!is_pair(code))               /* (let . 1) */
76823     {
76824       if (is_null(code))            /* (let) */
76825 	eval_error(sc, "let has no variables or body: ~A", 32, sc->code);
76826       eval_error(sc, "let form is an improper list? ~A", 32, sc->code);
76827     }
76828 
76829   if (!is_pair(cdr(code)))          /* (let () ) or (let () . 1) */
76830     eval_error(sc, "let has no body: ~A", 19, sc->code);
76831 
76832   if ((!is_list(car(code))) &&      /* (let 1 ...) */
76833       (!is_normal_symbol(car(code))))
76834     eval_error(sc, "let variable list is messed up or missing: ~A", 45, sc->code);
76835 
76836   named_let = (is_symbol(car(code)));
76837   if (named_let)
76838     {
76839       if (!is_list(cadr(code)))             /* (let hi #t) */
76840 	eval_error(sc, "let variable list is messed up: ~A", 34, sc->code);
76841       if (!is_pair(cddr(code)))             /* (let hi () . =>) or (let hi () ) */
76842 	{
76843 	  if (is_null(cddr(code)))
76844 	    eval_error(sc, "named let has no body: ~A", 25 , sc->code);
76845 	  else eval_error(sc, "named let stray dot? ~A", 23, sc->code);
76846 	}
76847       if (is_constant_symbol(sc, car(code)))
76848 	return(s7_error(sc, sc->wrong_type_arg_symbol,
76849 			set_elist_2(sc, wrap_string(sc, "can't bind an immutable object: ~S", 34), sc->code)));
76850       set_local(car(code));
76851       start = cadr(code);
76852     }
76853   else start = car(code);
76854 
76855   clear_symbol_list(sc);
76856   for (vars = 0, x = start; is_pair(x); vars++, x = cdr(x))
76857     {
76858       s7_pointer y, carx;
76859       carx = car(x);
76860 
76861       if ((!is_pair(carx)) || (is_null(cdr(carx))))  /* (let ((x)) ...) or (let ((x 1) . (y 2)) ...) */
76862 	eval_error(sc, "let variable declaration, but no value?: ~A", 43, x);
76863 
76864       if (!(is_pair(cdr(carx))))                     /* (let ((x . 1))...) */
76865 	eval_error(sc, "let variable declaration is not a proper list?: ~A", 50, x);
76866 
76867       if (is_not_null(cddr(carx)))                   /* (let ((x 1 2 3)) ...) */
76868 	eval_error(sc, "let variable declaration has more than one value?: ~A", 53, x);
76869 
76870       y = car(carx);
76871       if (!(is_symbol(y)))
76872 	eval_error(sc, "bad variable ~S in let (it is not a symbol)", 43, carx);
76873 
76874       if (is_constant_symbol(sc, y))
76875 	return(s7_error(sc, sc->wrong_type_arg_symbol,
76876 			set_elist_2(sc, wrap_string(sc, "can't bind an immutable object: ~S", 34), x)));
76877 
76878       /* check for name collisions -- not sure this is required by Scheme */
76879       if (symbol_is_in_list(sc, y))
76880 	s7_error(sc, sc->syntax_error_symbol,
76881 		 set_elist_3(sc, wrap_string(sc, "duplicate identifier in let: ~S in ~S", 37), y, sc->code));
76882       add_symbol_to_list(sc, y);
76883       set_local(y);
76884     }
76885   /* (let ('1) quote) -> 1 */
76886 
76887   if (is_not_null(x))                     /* (let* ((a 1) . b) a) */
76888     eval_error(sc, "let variable list improper?: ~A", 31, sc->code);
76889 
76890   if (!s7_is_proper_list(sc, cdr(code))) /* (let ((a 1)) a . 1) */
76891     eval_error(sc, "stray dot in let body: ~S", 25, cdr(code));
76892 
76893   if (named_let)
76894     return(check_named_let(sc, vars));
76895 
76896   if (vars == 0)        /* not_in_heap does not happen much here */
76897     pair_set_syntax_op(sc->code, OP_LET_NO_VARS);
76898   else
76899     {
76900       pair_set_syntax_op(sc->code, OP_LET_UNCHECKED);
76901       if (vars == 1)
76902 	check_let_one_var(sc, sc->code, start);
76903       else
76904 	{
76905 	  s7_pointer p;
76906 	  if (vars < GC_TRIGGER_SIZE)
76907 	    {
76908 	      opcode_t opt = OP_UNOPT;
76909 	      for (p = start; is_pair(p); p = cdr(p))
76910 		{
76911 		  x = car(p);
76912 		  if (is_fxable(sc, cadr(x)))
76913 		    {
76914 		      set_fx_direct(cdr(x), fx_choose(sc, cdr(x), sc->curlet, let_symbol_is_safe));
76915 		      if (opt == OP_UNOPT)
76916 			opt = OP_LET_FX_OLD;
76917 		    }
76918 		  else opt = OP_LET_UNCHECKED;
76919 		}
76920 	      pair_set_syntax_op(sc->code, opt);
76921 	      if ((opt == OP_LET_FX_OLD) &&
76922 		  (is_null(cddr(code))))        /* 1 form in body */
76923 		{
76924 		  if (vars == 2)
76925 		    {
76926 		      pair_set_syntax_op(sc->code, OP_LET_2A_OLD);
76927 		      set_opt1_pair(code, caar(code));
76928 		      set_opt2_pair(code, cadar(code));
76929 		    }
76930 		  else
76931 		    if (vars == 3)
76932 		      {
76933 			pair_set_syntax_op(sc->code, OP_LET_3A_OLD);
76934 			set_opt1_pair(code, cadar(code));
76935 			set_opt2_pair(code, caddar(code));
76936 		      }}}
76937 	  else
76938 	    {
76939 	      pair_set_syntax_op(sc->code, OP_LET_UNCHECKED);
76940 	      for (p = start; is_pair(p); p = cdr(p))
76941 		{
76942 		  x = car(p);
76943 		  if (is_fxable(sc, cadr(x)))
76944 		    set_fx_direct(cdr(x), fx_choose(sc, cdr(x), sc->curlet, let_symbol_is_safe));
76945 		}}}}
76946 
76947 
76948   /* if safe_c or safe_closure as car(body), null cdr(body), see if only vars as args
76949    *   symbol_list is intact??
76950    */
76951   if (optimize_op(sc->code) >= OP_LET_FX_OLD)
76952     {
76953       if ((not_in_heap(sc->code)) &&
76954 	  (body_is_safe(sc, sc->unused, cdr(code), true) >= SAFE_BODY)) /* recur_body is apparently never hit */
76955 	set_opt3_let(code, make_permanent_let(sc, car(code)));
76956       else
76957 	{
76958 	  set_optimize_op(sc->code, optimize_op(sc->code) + 1); /* *_old -> *_new */
76959 	  set_opt3_let(code, sc->nil);
76960 	}}
76961 
76962   if ((is_pair(car(code))) &&
76963       (is_let(sc->curlet)) && (is_funclet(sc->curlet)) && (tis_slot(let_slots(sc->curlet))))
76964     {
76965       /* apparently works because a safe closure will have old-let -> funclet?? */
76966       s7_pointer p, s1, s2 = NULL;
76967       s1 = let_slots(sc->curlet);
76968       if (tis_slot(next_slot(s1))) s2 = slot_symbol(next_slot(s1));
76969       s1 = slot_symbol(s1);
76970       for (p = car(code); is_pair(p); p = cdr(p))
76971 	{
76972 	  s7_pointer init;
76973 	  init = cdar(p);
76974 	  fx_tree(sc, init, s1, s2);
76975 	}}
76976   return(code);
76977 }
76978 
76979 static bool op_named_let_1(s7_scheme *sc, s7_pointer args) /* args = vals in decl order */
76980 {
76981   s7_pointer body, x;
76982   s7_int n;
76983 
76984   body = cddr(sc->code);
76985   sc->w = sc->nil;
76986   n = integer(opt2_int(sc->code));
76987   for (x = cadr(sc->code); is_pair(x); x = cdr(x))
76988     sc->w = cons(sc, caar(x), sc->w);
76989   sc->w = proper_list_reverse_in_place(sc, sc->w); /* init values (args) are also in "reversed" order */
76990   sc->curlet = make_let_slowly(sc, sc->curlet);
76991   sc->x = make_closure(sc, sc->w, body, T_CLOSURE | T_COPY_ARGS, n);
76992   add_slot(sc, sc->curlet, car(sc->code), sc->x);
76993   sc->curlet = make_let_slowly(sc, sc->curlet);
76994 
76995   for (x = sc->w; is_not_null(args); x = cdr(x)) /* reuse the value cells as the new let slots */
76996     {
76997       s7_pointer sym, new_args;
76998       sym = car(x);
76999       new_args = cdr(args);
77000       reuse_as_slot(sc, args, sym, unchecked_car(args)); /* args=slot, sym=symbol, car(args)=value */
77001       slot_set_next(args, let_slots(sc->curlet));
77002       let_set_slots(sc->curlet, args);
77003       symbol_set_local_slot(sym, let_id(sc->curlet), args);
77004       args = new_args;
77005     }
77006   closure_set_let(sc->x, sc->curlet);
77007   let_set_slots(sc->curlet, reverse_slots(sc, let_slots(sc->curlet)));
77008   sc->x = sc->nil;
77009   sc->code = T_Pair(body);
77010   sc->w = sc->nil;
77011   return(true);
77012 }
77013 
77014 static bool op_let1(s7_scheme *sc)
77015 {
77016   s7_pointer x, y, e;
77017   uint64_t id;
77018   /* building a list, then reusing it below as the let/slots seems stupid, but if we make the let first, and
77019    *   add slots, there are other problems.  The let/slot ids (and symbol_set_local_slot) need to wait
77020    *   until the args are evaluated, if an arg invokes call/cc, the let on the stack needs to be copied
77021    *   including let_dox_code if it is used to save sc->code (there are 3 things that need to be protected),
77022    *   (we win currently because copy_stack copies the list), and make-circular-iterator if called twice (s7test)
77023    *   hangs -- I can't see why!  Otherwise, the let/slots approach is slightly faster (less than 1% however).
77024    */
77025   while (true)
77026     {
77027       sc->args = cons(sc, sc->value, sc->args);
77028       if (is_pair(sc->code))
77029 	{
77030 	  x = cdar(sc->code);
77031 	  if (has_fx(x))
77032 	    sc->value = fx_call(sc, x);
77033 	  else
77034 	    {
77035 	      check_stack_size(sc); /* replaces check in op_closure_aa_o? */
77036 	      push_stack(sc, OP_LET1, sc->args, cdr(sc->code));
77037 	      sc->code = car(x);
77038 	      return(false);
77039 	    }
77040 	  sc->code = cdr(sc->code);
77041 	}
77042       else break;
77043     }
77044 
77045   x = proper_list_reverse_in_place(sc, sc->args);
77046   sc->code = car(x); /* restore the original form */
77047   y = cdr(x);        /* use sc->args as the new let */
77048   sc->y = y;
77049   sc->curlet = reuse_as_let(sc, x, sc->curlet);
77050 
77051   if (is_symbol(car(sc->code)))
77052     return(op_named_let_1(sc, y));
77053 
77054   e = sc->curlet;
77055   id = let_id(e);
77056 
77057   for (x = car(sc->code); is_not_null(y); x = cdr(x))
77058     {
77059       s7_pointer sym, args;
77060       /* reuse the value cells as the new let slots */
77061 
77062       sym = caar(x);
77063       args = cdr(y);
77064       reuse_as_slot(sc, y, sym, unchecked_car(y));
77065       symbol_set_local_slot(sym, id, y);
77066       slot_set_next(y, let_slots(e));
77067       let_set_slots(e, y);
77068 
77069       y = args;
77070     }
77071   sc->code = T_Pair(cdr(sc->code));
77072   sc->y = sc->nil;
77073   return(true);
77074 }
77075 
77076 static bool op_let(s7_scheme *sc)
77077 {
77078   /* sc->code is everything after the let: (let ((a 1)) a) so sc->code is (((a 1)) a) */
77079   /*   car can be either a list or a symbol ("named let") */
77080   bool named_let;
77081 
77082   sc->code = check_let(sc);
77083   sc->value = sc->code;
77084   named_let = is_symbol(car(sc->code));
77085   sc->code = (named_let) ? cadr(sc->code) : car(sc->code);
77086   if (is_null(sc->code))                    /* (let [name] () ...):  no bindings, so skip that step */
77087     {
77088       sc->code = sc->value;
77089       sc->curlet = make_let(sc, sc->curlet);
77090       if (named_let)  /* see also below -- there are 3 cases */
77091 	{
77092 	  s7_pointer body;
77093 	  set_opt2_int(cdr(sc->code), int_zero);
77094 	  body = cddr(sc->code);
77095 	  sc->x = make_closure(sc, sc->nil, body, T_CLOSURE, 0);
77096 	  /* args = () in new closure, see NAMED_LET_NO_VARS above */
77097 	  /* if this is a safe closure, we can build its let in advance and name it (a thunk in this case) */
77098 	  set_funclet(closure_let(sc->x));
77099 	  funclet_set_function(closure_let(sc->x), car(sc->code));
77100 	  make_slot_2(sc, sc->curlet, car(sc->code), sc->x);
77101 	  sc->code = T_Pair(body);
77102 	  sc->x = sc->nil;
77103 	}
77104       else sc->code = T_Pair(cdr(sc->code));
77105       return(true);
77106     }
77107   sc->args = sc->nil;
77108   return(op_let1(sc));
77109 }
77110 
77111 static bool op_let_unchecked(s7_scheme *sc)     /* not named, but has vars */
77112 {
77113   s7_pointer x, code;
77114   sc->args = list_1(sc, cdr(sc->code));
77115   code = cadr(sc->code);
77116   x = cdar(code);
77117   if (has_fx(x))
77118     sc->value = fx_call(sc, x);
77119   else
77120     {
77121       push_stack(sc, OP_LET1, sc->args, cdr(code));
77122       sc->code = car(x);
77123       return(false); /* goto EVAL */
77124     }
77125   sc->code = cdr(code);
77126   return(op_let1(sc));
77127 }
77128 
77129 static bool op_named_let(s7_scheme *sc)
77130 {
77131   sc->args = sc->nil;
77132   sc->value = cdr(sc->code);
77133   sc->code = cadr(sc->value);
77134   return(op_let1(sc));
77135 }
77136 
77137 static void op_named_let_no_vars(s7_scheme *sc)
77138 {
77139   s7_pointer body;
77140   sc->curlet = make_let(sc, sc->curlet);
77141   body = cdddr(sc->code);
77142   sc->args = make_closure(sc, sc->nil, body, T_CLOSURE, 0);  /* sc->args is a temp here */
77143   make_slot_2(sc, sc->curlet, cadr(sc->code), sc->args);
77144   sc->code = T_Pair(body);
77145 }
77146 
77147 static bool op_named_let_fx(s7_scheme *sc)
77148 {
77149   s7_pointer p;
77150   sc->args = sc->nil;
77151   for (p = caddr(sc->code); is_pair(p); p = cdr(p))
77152     sc->args = cons(sc, fx_call(sc, cdar(p)), sc->args);
77153   sc->args = proper_list_reverse_in_place(sc, sc->args);
77154   sc->code = cdr(sc->code);
77155   return(op_named_let_1(sc, sc->args)); /* sc->code = (name vars . body),  args = vals in decl order */
77156 }
77157 
77158 static void op_let_no_vars(s7_scheme *sc)
77159 {
77160   sc->curlet = make_let(sc, sc->curlet);
77161   sc->code = T_Pair(cddr(sc->code));         /* ignore the () */
77162 }
77163 
77164 static void op_let_one_new(s7_scheme *sc)
77165 {
77166   sc->code = cdr(sc->code);
77167   push_stack_no_args(sc, OP_LET_ONE_NEW_1, cdr(sc->code));
77168   sc->code = opt2_pair(sc->code);
77169 }
77170 
77171 static void op_let_one_old(s7_scheme *sc)
77172 {
77173   sc->code = cdr(sc->code);
77174   push_stack_no_args_direct(sc, OP_LET_ONE_OLD_1);
77175   sc->code = opt2_pair(sc->code);
77176 }
77177 
77178 static void op_let_one_p_new(s7_scheme *sc)
77179 {
77180   sc->code = cdr(sc->code);
77181   push_stack_no_args(sc, OP_LET_ONE_P_NEW_1, cdr(sc->code));
77182   sc->code = T_Pair(opt2_pair(sc->code));
77183 }
77184 
77185 static void op_let_one_p_old(s7_scheme *sc)
77186 {
77187   sc->code = cdr(sc->code);
77188   push_stack_no_args_direct(sc, OP_LET_ONE_P_OLD_1);
77189   sc->code = T_Pair(opt2_pair(sc->code));
77190 }
77191 
77192 static void op_let_one_old_1(s7_scheme *sc)
77193 {
77194   s7_pointer let;
77195   let = update_let_with_slot(sc, opt3_let(sc->code), sc->value);
77196   let_set_outlet(let, sc->curlet);
77197   sc->curlet = let;
77198   sc->code = cdr(sc->code);
77199 }
77200 
77201 static void op_let_one_p_old_1(s7_scheme *sc)
77202 {
77203   s7_pointer let;
77204   let = update_let_with_slot(sc, opt3_let(sc->code), sc->value);
77205   let_set_outlet(let, sc->curlet);
77206   sc->curlet = let;
77207   sc->code = cadr(sc->code);
77208 }
77209 
77210 static Inline void op_let_a_new(s7_scheme *sc)
77211 {
77212   sc->code = cdr(sc->code);
77213   sc->curlet = make_let_with_slot(sc, sc->curlet, car(opt2_pair(sc->code)), fx_call(sc, cdr(opt2_pair(sc->code))));
77214 }
77215 
77216 static Inline void op_let_a_old(s7_scheme *sc)
77217 {
77218   s7_pointer let, f;
77219   f = cdr(sc->code);
77220   let = update_let_with_slot(sc, opt3_let(f), fx_call(sc, cdr(opt2_pair(f))));
77221   let_set_outlet(let, sc->curlet);
77222   sc->curlet = let;
77223   sc->code = f;
77224 }
77225 
77226 static void op_let_a_a_new(s7_scheme *sc)
77227 {
77228   s7_pointer binding;
77229   sc->code = cdr(sc->code);
77230   binding = opt2_pair(sc->code);
77231   sc->curlet = make_let_with_slot(sc, sc->curlet, car(binding), fx_call(sc, cdr(binding)));
77232   sc->value = fx_call(sc, cdr(sc->code));
77233   free_cell(sc, let_slots(sc->curlet));
77234   free_cell(sc, sc->curlet);
77235   /* upon return, we goto START, so sc->curlet should be ok */
77236 }
77237 
77238 static void op_let_a_a_old(s7_scheme *sc) /* these are not called as fx*, and restoring sc->curlet has noticeable cost (e.g. 8 in thash) */
77239 {
77240   s7_pointer let;
77241   sc->code = cdr(sc->code);
77242   let = update_let_with_slot(sc, opt3_let(sc->code), fx_call(sc, cdr(opt2_pair(sc->code))));
77243   let_set_outlet(let, sc->curlet);
77244   sc->curlet = let;
77245   sc->value = fx_call(sc, cdr(sc->code));
77246 }
77247 
77248 static void op_let_a_fx_new(s7_scheme *sc)
77249 {
77250   s7_pointer binding, p;
77251   sc->code = cdr(sc->code);
77252   binding = opt2_pair(sc->code);
77253   sc->curlet = make_let_with_slot(sc, sc->curlet, car(binding), fx_call(sc, cdr(binding)));
77254   for (p = cdr(sc->code); is_pair(cdr(p)); p = cdr(p))
77255     fx_call(sc, p);
77256   sc->value = fx_call(sc, p);
77257   free_cell(sc, let_slots(sc->curlet));
77258   free_cell(sc, sc->curlet);
77259 }
77260 
77261 /* this and others like it could easily be fx funcs, but check_let is called too late, so it's never seen as fxable */
77262 static void op_let_a_fx_old(s7_scheme *sc)
77263 {
77264   s7_pointer let, p;
77265   sc->code = cdr(sc->code);
77266   let = update_let_with_slot(sc, opt3_let(sc->code), fx_call(sc, cdr(opt2_pair(sc->code))));
77267   let_set_outlet(let, sc->curlet);
77268   sc->curlet = let;
77269   for (p = cdr(sc->code); is_pair(cdr(p)); p = cdr(p))
77270     fx_call(sc, p);
77271   sc->value = fx_call(sc, p);
77272 }
77273 
77274 static inline void op_let_opssq(s7_scheme *sc)
77275 {
77276   s7_pointer largs, in_val;
77277   sc->code = cdr(sc->code);
77278   largs = T_Pair(opt2_pair(sc->code));                      /* cadr(caar(sc->code)); */
77279   in_val = lookup(sc, cadr(largs));
77280   set_car(sc->t2_2, lookup(sc, opt3_sym(cdr(sc->code))));   /* caddr(largs)); */
77281   set_car(sc->t2_1, in_val);
77282   sc->value = fn_proc(largs)(sc, sc->t2_1);
77283 }
77284 
77285 static inline void op_let_opassq(s7_scheme *sc)
77286 {
77287   s7_pointer in_val, lst;
77288   sc->code = cdr(sc->code);
77289   in_val = lookup(sc, opt2_sym(sc->code));                  /* cadadr(caar(sc->code)); */
77290   lst = lookup(sc, opt3_sym(cdr(sc->code)));
77291   if (is_pair(lst))
77292     sc->value = s7_assq(sc, in_val, lst);
77293   else sc->value = (is_null(lst)) ? sc->F : g_assq(sc, set_plist_2(sc, in_val, lst));
77294 }
77295 
77296 static void op_let_opssq_old(s7_scheme *sc)
77297 {
77298   s7_pointer let;
77299   op_let_opssq(sc);
77300   let = update_let_with_slot(sc, opt3_let(sc->code), sc->value);
77301   let_set_outlet(let, sc->curlet);
77302   sc->curlet = let;
77303   sc->code = T_Pair(cdr(sc->code));
77304 }
77305 
77306 static void op_let_opssq_new(s7_scheme *sc)
77307 {
77308   op_let_opssq(sc);
77309   sc->curlet = make_let_with_slot(sc, sc->curlet, opt1_sym(sc->code), sc->value);
77310   sc->code = T_Pair(cdr(sc->code));
77311 }
77312 
77313 static void op_let_opssq_e_old(s7_scheme *sc)
77314 {
77315   s7_pointer let;
77316   op_let_opssq(sc);
77317   let = update_let_with_slot(sc, opt3_let(sc->code), sc->value);
77318   let_set_outlet(let, sc->curlet);
77319   sc->curlet = let;
77320   sc->code = cadr(sc->code);
77321 }
77322 
77323 static void op_let_opssq_e_new(s7_scheme *sc)
77324 {
77325   op_let_opssq(sc);
77326   sc->curlet = make_let_with_slot(sc, sc->curlet, opt1_sym(sc->code), sc->value);
77327   sc->code = cadr(sc->code);
77328 }
77329 
77330 static void op_let_opassq_old(s7_scheme *sc)
77331 {
77332   s7_pointer let;
77333   op_let_opassq(sc);
77334   let = update_let_with_slot(sc, opt3_let(sc->code), sc->value);
77335   let_set_outlet(let, sc->curlet);
77336   sc->curlet = let;
77337   sc->code = T_Pair(cdr(sc->code));
77338 }
77339 
77340 static void op_let_opassq_new(s7_scheme *sc)
77341 {
77342   op_let_opassq(sc);
77343   sc->curlet = make_let_with_slot(sc, sc->curlet, opt1_sym(sc->code), sc->value);
77344   sc->code = T_Pair(cdr(sc->code));
77345 }
77346 
77347 static void op_let_opassq_e_old(s7_scheme *sc)
77348 {
77349   s7_pointer let;
77350   op_let_opassq(sc);
77351   let = update_let_with_slot(sc, opt3_let(sc->code), sc->value);
77352   let_set_outlet(let, sc->curlet);
77353   sc->curlet = let;
77354   sc->code = cadr(sc->code);
77355 }
77356 
77357 static void op_let_opassq_e_new(s7_scheme *sc)
77358 {
77359   op_let_opassq(sc);
77360   sc->curlet = make_let_with_slot(sc, sc->curlet, opt1_sym(sc->code), sc->value); /* caaar(sc->code) = local variable name */
77361   sc->code = cadr(sc->code);
77362 }
77363 
77364 static Inline void op_let_fx_new(s7_scheme *sc)
77365 {
77366   s7_pointer p, let;
77367   let = make_simple_let(sc);
77368   sc->args = let;
77369   for (p = cadr(sc->code); is_pair(p); p = cdr(p))
77370     {
77371       s7_pointer arg;
77372       arg = cdar(p);
77373       sc->value = fx_call(sc, arg);
77374       add_slot(sc, let, caar(p), sc->value);
77375     }
77376   sc->let_number++;
77377   sc->curlet = let;
77378   sc->code = T_Pair(cddr(sc->code));
77379 }
77380 
77381 static void op_let_fx_old(s7_scheme *sc)
77382 {
77383   s7_pointer p, let, slot;
77384   uint64_t id;
77385   let = opt3_let(cdr(sc->code));
77386   sc->args = let;
77387   id = ++sc->let_number;
77388   let_set_id(let, id);
77389 
77390   for (p = cadr(sc->code), slot = let_slots(let); is_pair(p); p = cdr(p), slot = next_slot(slot))
77391     {
77392       /* GC protected because it's a permanent let? or perhaps use sc->args? */
77393       slot_set_value(slot, fx_call(sc, cdar(p)));
77394       symbol_set_local_slot_unincremented(slot_symbol(slot), id, slot);
77395     }
77396   let_set_outlet(let, sc->curlet);
77397   sc->curlet = let;
77398   sc->code = T_Pair(cddr(sc->code));
77399 }
77400 
77401 static void op_let_2a_new(s7_scheme *sc) /* 2 vars, 1 expr in body */
77402 {
77403   /* opt1|2 free */
77404   s7_pointer a1, a2, code;
77405   code = cdr(sc->code);
77406   a1 = opt1_pair(code); /* caar(code) */
77407   a2 = opt2_pair(code); /* cadar(code) */
77408   sc->curlet = make_let_with_two_slots(sc, sc->curlet, car(a1), fx_call(sc, cdr(a1)), car(a2), fx_call(sc, cdr(a2)));
77409   sc->code = cadr(code);
77410 }
77411 
77412 static void op_let_2a_old(s7_scheme *sc) /* 2 vars, 1 expr in body */
77413 {
77414   s7_pointer let, code;
77415   code = cdr(sc->code);
77416   let = update_let_with_two_slots(sc, opt3_let(code), fx_call(sc, cdr(opt1_pair(code))), fx_call(sc, cdr(opt2_pair(code))));
77417   let_set_outlet(let, sc->curlet);
77418   sc->curlet = let;
77419   sc->code = cadr(code);
77420 }
77421 
77422 static void op_let_3a_new(s7_scheme *sc) /* 3 vars, 1 expr in body */
77423 {
77424   s7_pointer a1, a2, a3, code;
77425   code = cdr(sc->code);
77426   a1 = caar(code);
77427   a2 = opt1_pair(code); /* cadar */
77428   a3 = opt2_pair(code); /* caddar */
77429   sc->curlet = make_let_with_two_slots(sc, sc->curlet, car(a1), fx_call(sc, cdr(a1)), car(a2), fx_call(sc, cdr(a2)));
77430   add_slot(sc, sc->curlet, car(a3), fx_call(sc, cdr(a3)));
77431   sc->code = cadr(code);
77432 }
77433 
77434 static void op_let_3a_old(s7_scheme *sc) /* 3 vars, 1 expr in body */
77435 {
77436   s7_pointer let, code;
77437   code = cdr(sc->code);
77438   let = update_let_with_three_slots(sc, opt3_let(code), fx_call(sc, cdr(caar(code))), fx_call(sc, cdr(opt1_pair(code))), fx_call(sc, cdr(opt2_pair(code))));
77439   let_set_outlet(let, sc->curlet);
77440   sc->curlet = let;
77441   sc->code = cadr(code);
77442 }
77443 
77444 
77445 /* -------------------------------- let* -------------------------------- */
77446 static bool check_let_star(s7_scheme *sc)
77447 {
77448   s7_pointer vars, form, code;
77449   bool named_let, fxable = true;
77450 
77451   form = sc->code;
77452   code = cdr(form);
77453 
77454   if (!is_pair(code))                           /* (let* . 1) */
77455     eval_error(sc, "let* variable list is messed up: ~A", 35, form);
77456   if (!is_pair(cdr(code)))                      /* (let* ()) */
77457     eval_error(sc, "let* has no body: ~A", 20, form);
77458 
77459   named_let = (is_symbol(car(code)));
77460 
77461   if (named_let)
77462     {
77463       if (!is_list(cadr(code)))                 /* (let* hi #t) */
77464 	eval_error(sc, "let* variable list is messed up: ~A", 35, form);
77465       if (!is_pair(cddr(code)))                 /* (let* hi () . =>) or (let* hi () ) */
77466 	{
77467 	  if (is_null(cddr(code)))
77468 	    eval_error(sc, "named let* has no body: ~A", 26, form);
77469 	  else eval_error(sc, "named let* stray dot? ~A", 24, form);
77470 	}
77471       if (is_constant_symbol(sc, car(code)))
77472 	s7_error(sc, sc->wrong_type_arg_symbol,
77473 		 set_elist_2(sc, wrap_string(sc, "can't bind an immutable object: ~S", 34), form));
77474       set_local(car(code));
77475     }
77476   else
77477     if (!is_list(car(code)))                        /* (let* x ... ) */
77478       eval_error(sc, "let* variable declaration value is missing: ~A", 46, form);
77479 
77480   for (vars = ((named_let) ? cadr(code) : car(code)); is_pair(vars); vars = cdr(vars))
77481     {
77482       s7_pointer var_and_val, var;
77483       var_and_val = car(vars);
77484 
77485       if (!is_pair(var_and_val))                    /* (let* (3) ... */
77486 	eval_error(sc, "let* variable list is messed up? ~A", 35, var_and_val);
77487 
77488       /* no check for repeated var (unlike lambda* and named let*) */
77489       if (!(is_pair(cdr(var_and_val))))             /* (let* ((x . 1))...) */
77490 	{
77491 	  if (is_null(cdr(var_and_val)))
77492 	    eval_error(sc, "let* variable declaration, but no value?: ~A", 44, var_and_val);
77493 	  else eval_error(sc, "let* variable declaration is not a proper list?: ~A", 51, var_and_val);
77494 	}
77495       if (!is_null(cddr(var_and_val)))              /* (let* ((c 1 2)) ...) */
77496 	eval_error(sc, "let* variable declaration has more than one value?: ~A", 54, var_and_val);
77497 
77498       var = car(var_and_val);
77499 
77500       if (!(is_symbol(var)))                        /* (let* ((3 1)) 1) */
77501 	eval_error(sc, "bad variable ~S in let* (it is not a symbol)", 44, var);
77502 
77503       if (is_constant_symbol(sc, var))              /* (let* ((pi 3)) ...) */
77504 	s7_error(sc, sc->wrong_type_arg_symbol,
77505 		 set_elist_2(sc, wrap_string(sc, "can't bind an immutable object: ~S", 34), var_and_val));
77506 
77507       if ((named_let) && (symbol_is_in_arg_list(var, cdr(vars)))) /* (let* loop ((a 1) (a 2)) ...) -- added 2-Dec-19 */
77508 	eval_error(sc, "named let* parameter '~A is used twice in the parameter list", 60, var);
77509       /* currently (let* ((a 1) (a (+ a 1))) a) is 2, not an error. */
77510 
77511       set_local(var);
77512     }
77513   if (!is_null(vars))
77514     eval_error(sc, "let* variable list is not a proper list?: ~A", 44, vars);
77515 
77516   if (!s7_is_proper_list(sc, cdr(code)))
77517     eval_error(sc, "stray dot in let* body: ~S", 26, cdr(code));
77518 
77519   for (vars = (named_let) ? cadr(code) : car(code); is_pair(vars); vars = cdr(vars))
77520     if (is_fxable(sc, cadar(vars)))
77521       set_fx_direct(cdar(vars), fx_choose(sc, cdar(vars), sc->curlet, let_star_symbol_is_safe));
77522     else fxable = false;
77523 
77524   if (named_let)
77525     {
77526       if (is_null(cadr(code)))
77527 	pair_set_syntax_op(form, OP_NAMED_LET_NO_VARS);
77528       else
77529 	{
77530 	  pair_set_syntax_op(form, OP_NAMED_LET_STAR);
77531 	  set_opt2_con(code, cadr(caadr(code)));
77532 	}}
77533   else
77534     {
77535       if (is_null(car(code)))
77536 	pair_set_syntax_op(form, OP_LET_NO_VARS);       /* (let* () ...) */
77537       else
77538 	{
77539 	  if (is_null(cdar(code)))
77540 	    {
77541 	      check_let_one_var(sc, form, car(code)); /* (let* ((var...))...) -> (let ((var...))...) */
77542 	      if (optimize_op(form) >= OP_LET_FX_OLD)
77543 		{
77544 		  if ((not_in_heap(form)) &&
77545 		      (body_is_safe(sc, sc->unused, cdr(code), true) >= SAFE_BODY))
77546 		    set_opt3_let(code, make_permanent_let(sc, car(code)));
77547 		  else
77548 		    {
77549 		      set_optimize_op(form, optimize_op(form) + 1); /* *_old -> *_new */
77550 		      set_opt3_let(code, sc->nil);
77551 		    }}}
77552 	  else  /* multiple variables */
77553 	    {
77554 	      s7_pointer last_var;
77555 	      if (fxable)
77556 		{
77557 		  pair_set_syntax_op(form, OP_LET_STAR_FX);
77558 		  if ((is_null(cddr(code))) &&
77559 		      (is_fxable(sc, cadr(code))))
77560 		    {
77561 		      fx_annotate_arg(sc, cdr(code), sc->curlet);
77562 		      pair_set_syntax_op(form, OP_LET_STAR_FX_A); /* does this ever happen? */
77563 		    }}
77564 	      else pair_set_syntax_op(form, OP_LET_STAR2);
77565 	      set_opt2_con(code, cadaar(code));
77566 
77567 	      for (last_var = caaar(code), vars = cdar(code); is_pair(vars); last_var = caar(vars), vars = cdr(vars))
77568 		if (has_fx(cdar(vars)))
77569 		  fx_tree(sc, cdar(vars), last_var, NULL);
77570 	    }}}
77571 
77572   /* let_star_unchecked... */
77573   if (named_let) /* (is_symbol(car(code))) */
77574     {
77575       sc->value = cdr(code);
77576       if (is_null(car(sc->value)))
77577 	{
77578 	  s7_pointer cx;
77579 	  cx = car(code);
77580 	  sc->curlet = make_let_slowly(sc, sc->curlet);
77581 	  sc->code = T_Pair(cdr(sc->value));
77582 	  make_slot_2(sc, sc->curlet, cx, make_closure(sc, sc->nil, sc->code, T_CLOSURE_STAR, 0));
77583 	  return(false);
77584 	}}
77585   else
77586     if (is_null(car(code)))
77587       {
77588 	sc->curlet = make_let_slowly(sc, sc->curlet);
77589 	sc->code = T_Pair(cdr(code));
77590 	return(false);
77591       }
77592 
77593   if (named_let) /* is_symbol(car(code))) */
77594     {
77595       push_stack(sc, OP_LET_STAR1, code, cadr(code));
77596       sc->code = cadr(caadr(code));
77597     }
77598   else
77599     {
77600       push_stack(sc, OP_LET_STAR1, code, car(code));
77601       /* args is the let body, saved for later, code is the list of vars+initial-values */
77602       sc->code = cadr(caar(code));
77603       /* caar(code) = first var/val pair, we've checked that all these guys are legit, so cadr of that is the value */
77604     }
77605   return(true);
77606 }
77607 
77608 static inline bool op_let_star1(s7_scheme *sc)
77609 {
77610   uint64_t let_counter = S7_INT64_MAX;
77611   while (true)
77612     {
77613       if (let_counter == sc->capture_let_counter)
77614 	make_slot_2(sc, sc->curlet, caar(sc->code), sc->value);
77615       else
77616 	{
77617 	  sc->curlet = make_let_with_slot(sc, sc->curlet, caar(sc->code), sc->value);
77618 	  let_counter = sc->capture_let_counter;
77619 	}
77620 
77621       sc->code = cdr(sc->code);
77622       if (is_pair(sc->code))
77623 	{
77624 	  s7_pointer x;
77625 	  x = cdar(sc->code);
77626 	  if (has_fx(x))
77627 	    sc->value = fx_call(sc, x);
77628 	  else
77629 	    {
77630 	      push_stack_direct(sc, OP_LET_STAR1);
77631 	      sc->code = car(x);
77632 	      return(true);
77633 	    }}
77634       else break;
77635     }
77636   sc->code = sc->args; /* original sc->code set in push_stack above */
77637   if (is_symbol(car(sc->code)))
77638     {
77639       /* now we need to declare the new function */
77640       s7_pointer body, args;
77641       body = cddr(sc->code);
77642       args = cadr(sc->code);
77643       make_slot_2(sc, sc->curlet, car(sc->code), make_closure(sc, args, body, T_CLOSURE_STAR, (is_null(args)) ? 0 : CLOSURE_ARITY_NOT_SET));
77644       sc->code = body;
77645     }
77646   else sc->code = T_Pair(cdr(sc->code));
77647   return(false);
77648 }
77649 
77650 static void op_let_star_fx(s7_scheme *sc)
77651 {
77652   /* fx safe does not mean we can dispense with the inner lets (curlet is safe for example) */
77653   s7_pointer p;
77654   uint64_t let_counter = S7_INT64_MAX;
77655   sc->code = cdr(sc->code);
77656   for (p = car(sc->code); is_pair(p); p = cdr(p))
77657     {
77658       s7_pointer val;
77659       val = fx_call(sc, cdar(p)); /* eval in outer let */
77660       if (let_counter == sc->capture_let_counter)
77661 	add_slot_checked(sc, sc->curlet, caar(p), val);
77662       else
77663 	{
77664 	  sc->curlet = make_let_with_slot(sc, sc->curlet, caar(p), val);
77665 	  let_counter = sc->capture_let_counter;
77666 	}}
77667   sc->code = T_Pair(cdr(sc->code));
77668 }
77669 
77670 static void op_let_star_fx_a(s7_scheme *sc)
77671 {
77672   s7_pointer p;
77673   uint64_t let_counter = S7_INT64_MAX;
77674   sc->code = cdr(sc->code);
77675   for (p = car(sc->code); is_pair(p); p = cdr(p))
77676     {
77677       s7_pointer val;
77678       val = fx_call(sc, cdar(p));
77679       if (let_counter == sc->capture_let_counter)
77680 	make_slot_2(sc, sc->curlet, caar(p), val);
77681       else
77682 	{
77683 	  sc->curlet = make_let_with_slot(sc, sc->curlet, caar(p), val);
77684 	  let_counter = sc->capture_let_counter;
77685 	}}
77686   sc->value = fx_call(sc, cdr(sc->code));
77687 }
77688 
77689 static void op_named_let_star(s7_scheme *sc)
77690 {
77691   s7_pointer code;
77692   code = cdr(sc->code);
77693   push_stack(sc, OP_LET_STAR1, code, cadr(code));
77694   sc->code = opt2_con(code);
77695 }
77696 
77697 static void op_let_star2(s7_scheme *sc)
77698 {
77699   s7_pointer code;
77700   code = cdr(sc->code);
77701   push_stack(sc, OP_LET_STAR1, code, car(code));
77702   sc->code = opt2_con(code);
77703 }
77704 
77705 
77706 /* -------------------------------- letrec, letrec* -------------------------------- */
77707 static void check_letrec(s7_scheme *sc, bool letrec)
77708 {
77709   s7_pointer x, caller, code;
77710   code = cdr(sc->code);
77711   caller = (letrec) ? sc->letrec_symbol : sc->letrec_star_symbol;
77712 
77713   if ((!is_pair(code)) ||                     /* (letrec . 1) */
77714       (!is_list(car(code))))                  /* (letrec 1 ...) */
77715     eval_error_with_caller(sc, "~A: variable list is messed up: ~A", 34, caller, sc->code);
77716 
77717   if (!is_pair(cdr(code)))                    /* (letrec ()) */
77718     eval_error_with_caller(sc, "~A has no body: ~A", 18, caller, sc->code);
77719 
77720   clear_symbol_list(sc);
77721   for (x = car(code); is_not_null(x); x = cdr(x))
77722     {
77723       s7_pointer y, carx;
77724       if (!is_pair(x))                        /* (letrec ((a 1) . 2) ...) */
77725 	eval_error_with_caller(sc, "~A: improper list of variables? ~A", 34, caller, sc->code);
77726 
77727       carx = car(x);
77728       if (!is_pair(carx))                     /* (letrec (1 2) #t) */
77729 	eval_error_with_caller(sc, "~A: bad variable ~S (should be a pair (name value))", 51, caller, carx);
77730       if (!(is_symbol(car(carx))))
77731 	eval_error_with_caller(sc, "~A: bad variable ~S (it is not a symbol)", 40, caller, carx);
77732 
77733       y = car(carx);
77734       if (is_constant_symbol(sc, y))
77735 	s7_error(sc, sc->wrong_type_arg_symbol,
77736 		 set_elist_2(sc, wrap_string(sc, "can't bind an immutable object: ~S", 34), x));
77737 
77738       if (!is_pair(cdr(carx)))                /* (letrec ((x . 1))...) */
77739 	{
77740 	  if (is_null(cdr(carx)))             /* (letrec ((x)) x) -- perhaps this is legal? */
77741 	    eval_error_with_caller(sc, "~A: variable declaration has no value?: ~A", 42, caller, carx);
77742 	  eval_error_with_caller(sc, "~A: variable declaration is not a proper list?: ~A", 50, caller, carx);
77743 	}
77744       if (is_not_null(cddr(carx)))            /* (letrec ((x 1 2 3)) ...) */
77745 	eval_error_with_caller(sc, "~A: variable declaration has more than one value?: ~A", 53, caller, carx);
77746 
77747       /* check for name collisions -- this is needed in letrec* else which of the two legit values does our "rec" refer to, so to speak */
77748       if (symbol_is_in_list(sc, y))
77749 	eval_error_with_caller(sc, "~A: duplicate identifier: ~A", 28, caller, y);
77750       add_symbol_to_list(sc, y);
77751       set_local(y);
77752     }
77753 
77754   if (!s7_is_proper_list(sc, cdr(code)))
77755     eval_error_with_caller(sc, "stray dot in ~A body: ~S", 24, caller, cdr(code));
77756 
77757   for (x = car(code); is_pair(x); x = cdr(x))
77758     if (is_fxable(sc, cadar(x)))
77759       set_fx_direct(cdar(x), fx_choose(sc, cdar(x), sc->curlet, let_symbol_is_safe_or_listed));
77760 
77761   pair_set_syntax_op(sc->code, (letrec) ? OP_LETREC_UNCHECKED : OP_LETREC_STAR_UNCHECKED);
77762 }
77763 
77764 static s7_pointer make_funclet(s7_scheme *sc, s7_pointer new_func, s7_pointer func_name, s7_pointer outer_let);
77765 
77766 static void letrec_setup_closures(s7_scheme *sc)
77767 {
77768   s7_pointer slot;
77769   for (slot = let_slots(sc->curlet); tis_slot(slot); slot = next_slot(slot))
77770     if (is_closure(slot_value(slot)))
77771       {
77772 	s7_pointer func;
77773 	func = slot_value(slot);
77774 	if ((!is_safe_closure(func)) ||
77775 	    (!is_optimized(car(closure_body(func)))))
77776 	  optimize_lambda(sc, true, slot_symbol(slot), closure_args(func), closure_body(func));
77777 	if (is_safe_closure_body(closure_body(func)))
77778 	  {
77779 	    set_safe_closure(func);
77780 	    if (is_very_safe_closure_body(closure_body(func)))
77781 	      set_very_safe_closure(func);
77782 	  }
77783 	make_funclet(sc, func, slot_symbol(slot), closure_let(func));
77784 	/*  else closure_set_let(new_func, sc->curlet); -- maybe funclet not needed here? */
77785       }
77786 }
77787 
77788 static void op_letrec2(s7_scheme *sc)
77789 {
77790   s7_pointer slot;
77791   for (slot = let_slots(sc->curlet); tis_slot(slot); slot = next_slot(slot))
77792     if (is_checked_slot(slot))
77793       slot_set_value(slot, slot_pending_value(slot));
77794   letrec_setup_closures(sc);
77795 }
77796 
77797 static bool op_letrec_unchecked(s7_scheme *sc)
77798 {
77799   s7_pointer code;
77800   code = cdr(sc->code);
77801   /*   get all local vars and set to #<undefined>
77802    *   get parallel list of values
77803    *   eval each member of values list with let still full of #<undefined>'s
77804    *   assign each value to its variable
77805    *   eval body
77806    * which means that (letrec ((x x)) x) is not an error!
77807    * but this assumes the environment is not changed by evaluating the exprs?
77808    * (letrec ((a (define b 1))) b) -- if let, the define takes place in the calling let, not the current let
77809    * (letrec ((f1 (lambda (x) (f2 (* 2 x))))) (define (f2 y) (- y 1)) (f1 3)) -> 5 (Guile says unbound f2)
77810    * I think I need to check here that slot_pending_value is set (using the is_checked bit below):
77811    *   (letrec ((i (begin (define xyz 37) 0))) (curlet)): (inlet 'i 0 'xyz 37) -- is this correct?
77812    */
77813   sc->curlet = make_let_slowly(sc, sc->curlet);
77814   if (is_pair(car(code)))
77815     {
77816       s7_pointer x, slot;
77817       for (x = car(code); is_not_null(x); x = cdr(x))
77818 	{
77819 	  slot = make_slot_2(sc, sc->curlet, caar(x), sc->undefined);
77820 	  slot_set_pending_value(slot, sc->undefined);
77821 	  slot_set_expression(slot, cdar(x));
77822 	  set_checked_slot(slot);
77823 	}
77824       for (slot = let_slots(sc->curlet); tis_slot(slot) && (has_fx(slot_expression(slot))); slot = next_slot(slot))
77825 	slot_set_pending_value(slot, fx_call(sc, slot_expression(slot)));
77826       if (tis_slot(slot))
77827 	{
77828 	  push_stack(sc, OP_LETREC1, slot, code);
77829 	  sc->code = car(slot_expression(slot));
77830 	  return(true);
77831 	}
77832       op_letrec2(sc);
77833     }
77834   sc->code = T_Pair(cdr(code));
77835   return(false);
77836 }
77837 
77838 static bool op_letrec1(s7_scheme *sc)
77839 {
77840   s7_pointer slot;
77841   slot_set_pending_value(sc->args, sc->value);
77842   for (slot = next_slot(sc->args); tis_slot(slot) && (has_fx(slot_expression(slot))); slot = next_slot(slot))
77843     slot_set_pending_value(slot, fx_call(sc, slot_expression(slot)));
77844   if (tis_slot(slot))
77845     {
77846       push_stack(sc, OP_LETREC1, slot, sc->code);
77847       sc->code = car(slot_expression(slot));
77848       return(true);
77849     }
77850   op_letrec2(sc);
77851   sc->code = T_Pair(cdr(sc->code));
77852   return(false);
77853 }
77854 
77855 
77856 static bool op_letrec_star_unchecked(s7_scheme *sc)
77857 {
77858   s7_pointer slot, code;
77859   code = cdr(sc->code);
77860   /* get all local vars and set to #<undefined>
77861    * eval each member of values list and assign immediately, as in let*
77862    * eval body
77863    */
77864   sc->curlet = make_let_slowly(sc, sc->curlet);
77865   if (is_pair(car(code)))
77866     {
77867       s7_pointer x;
77868       for (x = car(code); is_not_null(x); x = cdr(x))
77869 	{
77870 	  slot = make_slot_2(sc, sc->curlet, caar(x), sc->undefined);
77871 	  slot_set_expression(slot, cdar(x));
77872 	}
77873       let_set_slots(sc->curlet, reverse_slots(sc, let_slots(sc->curlet)));
77874 
77875       for (slot = let_slots(sc->curlet); tis_slot(slot) && (has_fx(slot_expression(slot))); slot = next_slot(slot))
77876 	slot_set_value(slot, fx_call(sc, slot_expression(slot)));
77877       if (tis_slot(slot))
77878 	{
77879 	  push_stack(sc, OP_LETREC_STAR1, slot, code);
77880 	  sc->code = car(slot_expression(slot));
77881 	  return(true);
77882 	}}
77883   sc->code = T_Pair(cdr(code));
77884   return(false);
77885 }
77886 
77887 static bool op_letrec_star1(s7_scheme *sc)
77888 {
77889   s7_pointer slot;
77890   slot = sc->args;
77891   slot_set_value(slot, sc->value);
77892 
77893   for (slot = next_slot(slot); tis_slot(slot) && (has_fx(slot_expression(slot))); slot = next_slot(slot))
77894     slot_set_value(slot, fx_call(sc, slot_expression(slot)));
77895   if (tis_slot(slot))
77896     {
77897       push_stack(sc, OP_LETREC_STAR1, slot, sc->code);
77898       sc->code = car(slot_expression(slot));
77899       return(true);
77900     }
77901   letrec_setup_closures(sc);
77902   sc->code = T_Pair(cdr(sc->code));
77903   return(false);
77904 }
77905 
77906 
77907 /* -------------------------------- let-temporarily -------------------------------- */
77908 static void check_let_temporarily(s7_scheme *sc)
77909 {
77910   s7_pointer x, form, code;
77911   bool all_fx, all_s7;
77912   form = sc->code;
77913   code = cdr(form);
77914 
77915   if ((!is_pair(code)) ||                 /* (let-temporarily . 1) */
77916       (!is_list(car(code))))              /* (let-temporarily 1 ...) */
77917     eval_error(sc, "let-temporarily: variable list is messed up: ~A", 47, form);
77918   /* cdr(code) = body can be nil */
77919 
77920   all_fx = is_pair(car(code));
77921   all_s7 = all_fx;
77922 
77923   for (x = car(code); is_not_null(x); x = cdr(x))
77924     {
77925       s7_pointer carx;
77926       if (!is_pair(x))                        /* (let-temporarily ((a 1) . 2) ...) */
77927 	eval_error(sc, "let-temporarily: improper list of variables? ~A", 47, form);
77928 
77929       carx = car(x);
77930       if (!is_pair(carx))                     /* (let-temporarily (1 2) #t) */
77931 	eval_error(sc, "let-temporarily: bad variable ~S (it should be a pair (name value))", 67, carx);
77932 
77933       if (is_symbol(car(carx)))
77934 	{
77935 	  if (is_constant_symbol(sc, car(carx))) /* (let-temporarily ((pi 3)) ...) */
77936 	    s7_error(sc, sc->wrong_type_arg_symbol,
77937 		     set_elist_2(sc, wrap_string(sc, "can't bind an immutable object: ~S", 34), x));
77938 	  if (is_syntactic_symbol(car(carx)))    /* (let-temporarily ((if 3)) ...) */
77939 	    s7_error(sc, sc->wrong_type_arg_symbol,
77940 		     set_elist_2(sc, wrap_string(sc, "can't set! ~A", 13), car(carx)));
77941 	}
77942       else
77943 	if (!is_pair(car(carx)))              /* (let-temporarily ((1 2)) ...) */
77944 	  eval_error(sc, "let-temporarily: bad variable ~S (the name should be a symbol  or a pair)", 73, carx);
77945 
77946       if (!is_pair(cdr(carx)))                /* (let-temporarily ((x . 1))...) */
77947 	eval_error(sc, "let-temporarily: variable declaration value is messed up: ~S", 60, carx);
77948 
77949       if (is_not_null(cddr(carx)))            /* (let-temporarily ((x 1 2 3)) ...) */
77950 	eval_error(sc, "let-temporarily: variable declaration has more than one value?: ~A", 66, carx);
77951 
77952       if ((all_fx) &&
77953 	  ((!is_symbol(car(carx))) || (!is_fxable(sc, cadr(carx)))))
77954 	all_fx = false;
77955       if ((all_s7) &&
77956 	  ((!is_pair(car(carx))) || (caar(carx) != sc->s7_let_symbol) ||
77957 	   (!is_quoted_symbol(cadar(carx))) || (is_keyword(cadr(cadar(carx)))) ||
77958 	   (!is_fxable(sc, cadr(carx)))))
77959 	all_s7 = false;
77960     }
77961   if (!s7_is_proper_list(sc, cdr(code)))
77962     eval_error(sc, "stray dot in let-temporarily body: ~S", 37, cdr(code));
77963 
77964   if ((all_fx) || (all_s7))
77965     {
77966       pair_set_syntax_op(form, (all_fx) ? ((is_null(cdar(code))) ? OP_LET_TEMP_FX_1 : OP_LET_TEMP_FX) : OP_LET_TEMP_S7);
77967       for (x = car(code); is_pair(x); x = cdr(x))
77968 	fx_annotate_arg(sc, cdar(x), sc->curlet);
77969 
77970       if ((optimize_op(form) == OP_LET_TEMP_FX_1) && (is_pair(cdr(code))) && (is_null(cddr(code))) && (is_fxable(sc, cadr(code))))
77971 	{
77972 	  fx_annotate_arg(sc, cdr(code), sc->curlet);
77973 	  pair_set_syntax_op(form, OP_LET_TEMP_A_A);
77974 	}}
77975   else
77976     {
77977       pair_set_syntax_op(form, OP_LET_TEMP_UNCHECKED);
77978       if ((is_pair(car(code))) && (is_null(cdar(code))) && (is_pair(caar(code))))
77979 	{
77980 	  s7_pointer var, val;
77981 	  var = caar(code);
77982 	  val = cadr(var);
77983 	  var = car(var);
77984 	  if ((is_pair(var)) && (car(var) == sc->setter_symbol) && (is_pair(cdr(var))) && (is_pair(cddr(var))) && (val == sc->F))
77985 	    {
77986 	      optimize_expression(sc, cadr(var), 0, sc->curlet, false);
77987 	      optimize_expression(sc, caddr(var), 0, sc->curlet, false);
77988 	      if ((is_fxable(sc, cadr(var))) && (is_fxable(sc, caddr(var))))
77989 		{
77990 		  fx_annotate_args(sc, cdr(var), sc->curlet);
77991 		  pair_set_syntax_op(form, OP_LET_TEMP_SETTER);
77992 		}}}}
77993 }
77994 
77995 static void op_let_temp_unchecked(s7_scheme *sc)
77996 {
77997   sc->code = cdr(sc->code); /* step past let-temporarily */
77998   sc->args = list_4(sc, car(sc->code), sc->nil, sc->nil, sc->nil);
77999   push_stack_direct(sc, OP_GC_PROTECT);
78000   /* sc->args: varlist, settees, old_values, new_values */
78001 }
78002 
78003 static bool op_let_temp_init1(s7_scheme *sc)
78004 {
78005   while (is_pair(car(sc->args)))
78006     {
78007       /* eval car, add result to old-vals list, if any vars undefined, error */
78008       s7_pointer binding, settee, new_value;
78009       binding = caar(sc->args);
78010       settee = car(binding);
78011       new_value = cadr(binding);
78012       cadr(sc->args) = cons(sc, settee, cadr(sc->args));
78013       cadddr(sc->args) = cons(sc, new_value, cadddr(sc->args));
78014       car(sc->args) = cdar(sc->args);
78015       if (is_symbol(settee))                    /* get initial values */
78016 	caddr(sc->args) = cons(sc, lookup_checked(sc, settee), caddr(sc->args));
78017       else
78018 	{
78019 	  if (is_pair(settee))
78020 	    {
78021 	      push_stack_direct(sc, OP_LET_TEMP_INIT1);
78022 	      sc->code = settee;
78023 	      return(true);
78024 	    }
78025 	  caddr(sc->args) = cons(sc, new_value, caddr(sc->args));
78026 	}}
78027   car(sc->args) = cadr(sc->args);
78028   return(false);
78029 }
78030 
78031 typedef enum {goto_start, goto_begin, fall_through, goto_do_end_clauses, goto_safe_do_end_clauses,
78032 	      goto_eval, goto_apply_lambda, goto_do_end, goto_top_no_pop, goto_apply,
78033 	      goto_eval_args, goto_eval_args_top, goto_do_unchecked, goto_pop_read_list, goto_read_tok, goto_feed_to} goto_t;
78034 
78035 static goto_t op_let_temp_init2(s7_scheme *sc)
78036 {
78037   /* now eval set car new-val, cadr=settees, cadddr=new_values */
78038   while (is_pair(car(sc->args)))
78039     {
78040       s7_pointer settee, new_value, slot;
78041       settee = caar(sc->args);
78042       new_value = car(cadddr(sc->args));
78043       cadddr(sc->args) = cdr(cadddr(sc->args));
78044       car(sc->args) = cdar(sc->args);
78045       if ((!is_symbol(settee)) ||                /* (let-temporarily (((*s7* 'print-length) 32)) ...) */
78046 	  (symbol_has_setter(settee)) ||         /*                  ((*features* #f))... */
78047 	  (is_pair(new_value)))                  /*                  ((line-number (if (eq? caller top-level:) -1 line-number)))... */
78048 	{
78049 	  push_stack_direct(sc, OP_LET_TEMP_INIT2);
78050 	  sc->code = list_3(sc, sc->set_symbol, settee, new_value);
78051 	  return(goto_top_no_pop);
78052 	}
78053       slot = lookup_slot_from(settee, sc->curlet);
78054       if (!is_slot(slot))
78055 	unbound_variable_error(sc, settee);
78056       if (is_immutable_slot(slot))
78057 	immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->let_temporarily_symbol, settee));
78058       if (is_symbol(new_value))
78059 	new_value = lookup_checked(sc, new_value);
78060       slot_set_value(slot, new_value);
78061     }
78062   car(sc->args) = cadr(sc->args);
78063   pop_stack(sc);
78064   /* push_stack_direct(sc, OP_LET_TEMP_DONE); */ /* we fall into LET_TEMP_DONE below so this seems redundant */
78065   sc->code = cdr(sc->code);
78066   if (is_pair(sc->code))
78067     {
78068       push_stack_direct(sc, OP_LET_TEMP_DONE);
78069       return(goto_begin);
78070     }
78071   sc->value = sc->nil; /* so (let-temporarily (<vars)) -> () like begin I guess */
78072   return(fall_through);
78073 }
78074 
78075 static bool op_let_temp_done1(s7_scheme *sc)
78076 {
78077   while (is_pair(car(sc->args)))
78078     {
78079       s7_pointer settee;
78080       settee = caar(sc->args);
78081       sc->value = caaddr(sc->args);
78082       caddr(sc->args) = cdaddr(sc->args);
78083       car(sc->args) = cdar(sc->args);
78084 
78085       if ((is_pair(settee)) && (car(settee) == sc->s7_let_symbol) &&  /* (let-temporarily (((*s7* (symbol "print-length")) 43))...) */
78086 	  ((is_keyword(cadr(settee))) ||
78087 	   ((is_pair(cadr(settee))) && (caadr(settee) == sc->quote_symbol) && (is_symbol(cadadr(settee))))))
78088 	{
78089 	  s7_pointer sym;
78090 	  sym = cadr(settee);
78091 	  if (is_pair(sym)) sym = cadr(sym);
78092 	  g_s7_let_set_fallback(sc, set_plist_3(sc, sc->s7_let, sym, sc->value));
78093 	}
78094       else
78095 	{
78096 	  s7_pointer slot;
78097 	  if ((!is_symbol(settee)) ||
78098 	      (symbol_has_setter(settee)))                                   /* (let-temporarily ((x 1))...) -> (set! x 0) if x has a setter */
78099 	    {
78100 	      push_stack_direct(sc, OP_LET_TEMP_DONE1);
78101 	      if ((is_pair(sc->value)) || (is_symbol(sc->value)))            /* (let-temporarily ((*load-path* ())) 32) here: (set! *load-path* '(".")) */
78102 		sc->code = list_3(sc, sc->set_symbol, settee, list_2(sc, sc->quote_symbol, sc->value));
78103 	      else sc->code = list_3(sc, sc->set_symbol, settee, sc->value);
78104 	      return(false); /* goto eval */
78105 	    }
78106 	  slot = lookup_slot_from(settee, sc->curlet);
78107 	  if (is_immutable_slot(slot))
78108 	    immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->let_temporarily_symbol, settee));
78109 	  slot_set_value(slot, sc->value);
78110 	}}
78111   pop_stack(sc);   /* remove the gc_protect */
78112   sc->value = sc->code;
78113   if (is_multiple_value(sc->value))
78114     sc->value = splice_in_values(sc, multiple_value(sc->value));
78115   return(true);          /* goto start */
78116 }
78117 
78118 static bool op_let_temp_s7(s7_scheme *sc) /* all entries are of the form ((*s7* 'field) fx-able-value) */
78119 {
78120   s7_pointer p;
78121   s7_pointer *end;
78122 
78123   sc->code = cdr(sc->code);
78124   end = sc->stack_end;
78125 
78126   for (p = car(sc->code); is_pair(p); p = cdr(p))
78127     {
78128       s7_pointer old_value, field;
78129       field = cadadr(caar(p));         /* p: (((*s7* 'expansions?) #f)) -- no keywords here (see check_let_temporarily) */
78130       old_value = g_s7_let_ref_fallback(sc, set_plist_2(sc, sc->s7_let, field));
78131       push_stack(sc, OP_LET_TEMP_S7_UNWIND, old_value, field);
78132     }
78133   for (p = car(sc->code); is_pair(p); p = cdr(p), end += 4)
78134     g_s7_let_set_fallback(sc, set_plist_3(sc, sc->s7_let, end[0], fx_call(sc, cdar(p))));
78135   sc->code = cdr(sc->code);
78136   return(is_pair(sc->code)); /* sc->code can be null if no body */
78137 }
78138 
78139 static void let_temp_done(s7_scheme *sc, s7_pointer args, s7_pointer code, s7_pointer let)
78140 {
78141   /* called in call/cc, call-with-exit and, catch (unwind to catch) */
78142   push_stack_direct(sc, OP_EVAL_DONE);
78143   sc->args = T_Pos(args);
78144   sc->code = code;
78145   sc->curlet = let;
78146   eval(sc, OP_LET_TEMP_DONE);
78147 }
78148 
78149 static void let_temp_unwind(s7_scheme *sc, s7_pointer slot, s7_pointer new_value)
78150 {
78151   if (slot_has_setter(slot)) /* setter has to be called because it might affect other vars (*clm-srate* -> mus-srate etc), but it should not change sc->value */
78152     {
78153       s7_pointer old_value;
78154       old_value = sc->value;
78155       slot_set_value(slot, s7_apply_function(sc, slot_setter(slot), set_plist_2(sc, slot_symbol(slot), new_value)));
78156       sc->value = old_value;
78157     }
78158   else slot_set_value(slot, new_value);
78159 }
78160 
78161 static bool op_let_temp_fx(s7_scheme *sc) /* all entries are of the form (symbol fx-able-value) */
78162 {
78163   s7_pointer p, var, settee, new_val, slot;
78164   s7_pointer *end;
78165 
78166   sc->code = cdr(sc->code);
78167   end = sc->stack_end;
78168   for (p = car(sc->code); is_pair(p); p = cdr(p))
78169     {
78170       var = car(p);
78171       settee = car(var);
78172       slot = lookup_slot_from(settee, sc->curlet);
78173       if (!is_slot(slot))
78174 	unbound_variable_error(sc, settee);
78175       if (is_immutable_slot(slot))
78176 	immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->let_temporarily_symbol, settee));
78177       push_stack(sc, OP_LET_TEMP_UNWIND, slot_value(slot), slot);
78178     }
78179   for (p = car(sc->code); is_pair(p); p = cdr(p), end += 4)
78180     {
78181       var = car(p);
78182       settee = car(var);
78183       new_val = fx_call(sc, cdr(var));
78184       slot = end[0];
78185       if (slot_has_setter(slot))
78186 	slot_set_value(slot, s7_apply_function(sc, slot_setter(slot), set_plist_2(sc, settee, new_val)));
78187       else slot_set_value(slot, new_val);
78188     }
78189   sc->code = cdr(sc->code);
78190   return(is_pair(sc->code)); /* sc->code can be null if no body */
78191 }
78192 
78193 static bool op_let_temp_fx_1(s7_scheme *sc) /* one entry */
78194 {
78195   s7_pointer var, settee, new_val, slot;
78196   sc->code = cdr(sc->code);
78197   var = caar(sc->code);
78198   settee = car(var);
78199   slot = lookup_slot_from(settee, sc->curlet);
78200   if (!is_slot(slot))
78201     unbound_variable_error(sc, settee);
78202   if (is_immutable_slot(slot))
78203     immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->let_temporarily_symbol, settee));
78204   push_stack(sc, OP_LET_TEMP_UNWIND, slot_value(slot), slot);
78205   new_val = fx_call(sc, cdr(var));
78206   if (slot_has_setter(slot))
78207     slot_set_value(slot, s7_apply_function(sc, slot_setter(slot), set_plist_2(sc, settee, new_val)));
78208   else slot_set_value(slot, new_val);
78209   sc->code = cdr(sc->code);
78210   return(is_pair(sc->code)); /* sc->code can be null if no body */
78211 }
78212 
78213 static s7_pointer fx_let_temp_a_a(s7_scheme *sc, s7_pointer code)
78214 {
78215   s7_pointer result;
78216   op_let_temp_fx_1(sc);
78217   result = fx_call(sc, sc->code);
78218   pop_stack(sc);
78219   let_temp_unwind(sc, sc->code, sc->args);
78220   return(result);
78221 }
78222 
78223 static bool op_let_temp_setter(s7_scheme *sc)
78224 {
78225   s7_pointer var, slot, sym, e;
78226   sc->code = cdr(sc->code);
78227   var = caaar(sc->code);
78228   sym = fx_call(sc, cdr(var));
78229   e = sc->curlet;
78230   sc->curlet = fx_call(sc, cddr(var));
78231   slot = lookup_slot_from(sym, sc->curlet);
78232   sc->curlet = e;
78233   push_stack(sc, OP_LET_TEMP_SETTER_UNWIND, slot_setter(slot), slot);
78234   slot_set_setter(slot, sc->F);
78235   sc->code = cdr(sc->code);
78236   return(is_pair(sc->code)); /* sc->code can be null if no body */
78237 }
78238 
78239 static void op_let_temp_unwind(s7_scheme *sc)
78240 {
78241   let_temp_unwind(sc, sc->code, sc->args);
78242   if (is_multiple_value(sc->value))
78243     sc->value = splice_in_values(sc, multiple_value(sc->value));
78244 }
78245 
78246 static void op_let_temp_s7_unwind(s7_scheme *sc)
78247 {
78248   g_s7_let_set_fallback(sc, set_plist_3(sc, sc->s7_let, sc->code, sc->args));
78249   if (is_multiple_value(sc->value))
78250     sc->value = splice_in_values(sc, multiple_value(sc->value));
78251 }
78252 
78253 static void op_let_temp_setter_unwind(s7_scheme *sc)
78254 {
78255   slot_set_setter(sc->code, sc->args);
78256   if (is_multiple_value(sc->value))
78257     sc->value = splice_in_values(sc, multiple_value(sc->value));
78258 }
78259 
78260 
78261 /* -------------------------------- quote -------------------------------- */
78262 static inline s7_pointer check_quote(s7_scheme *sc, s7_pointer code)
78263 {
78264   if (!is_pair(cdr(code)))                    /* (quote . -1) */
78265     {
78266       if (is_null(cdr(code)))
78267 	eval_error(sc, "quote: not enough arguments: ~A", 31, code);
78268       eval_error(sc, "quote: stray dot?: ~A", 21, code);
78269     }
78270   if (is_not_null(cddr(code)))             /* (quote . (1 2)) or (quote 1 1) */
78271     eval_error(sc, "quote: too many arguments ~A", 28, code);
78272 
78273   pair_set_syntax_op(code, OP_QUOTE_UNCHECKED);
78274   return(cadr(code));
78275 }
78276 
78277 
78278 /* -------------------------------- and -------------------------------- */
78279 static bool check_and(s7_scheme *sc, s7_pointer expr)
78280 {
78281   /* this and check_or and check_if might not be called -- optimize_syntax can short-circuit it to return fx* choices */
78282   s7_pointer p, code;
78283   int32_t any_nils = 0, len;
78284 
78285   code = cdr(expr);
78286   if (is_null(code))
78287     {
78288       sc->value = sc->T;
78289       return(true);
78290     }
78291   for (len = 0, p = code; is_pair(p); p = cdr(p), len++)
78292     {
78293       s7_function callee;
78294       callee = (has_fx(p)) ? fx_proc(p) : fx_choose(sc, p, sc->curlet, let_symbol_is_safe);  /* fx_proc can be nil! */
78295       if (!callee) any_nils++;
78296       set_fx(p, callee);
78297     }
78298 
78299   if (is_not_null(p))                                    /* (and . 1) (and #t . 1) */
78300     eval_error(sc, "and: stray dot?: ~A", 19, expr);
78301 
78302   if ((fx_proc(code)) &&
78303       (is_proper_list_1(sc, cdr(code))))
78304     {
78305       if ((fx_proc(code) == fx_is_pair_s) || (fx_proc(code) == fx_is_pair_t))
78306 	{
78307 	  pair_set_syntax_op(expr, OP_AND_PAIR_P);
78308 	  set_opt3_sym(expr, cadar(code));
78309 	  set_opt2_con(expr, cadr(code));
78310 	}
78311       else pair_set_syntax_op(expr, (any_nils > 0) ? OP_AND_AP : OP_AND_2);
78312     }
78313   else
78314     {
78315       pair_set_syntax_op(expr, (any_nils > 0) ? OP_AND_P : OP_AND_N);
78316       if ((any_nils == 1) && (len > 2))
78317 	{
78318 	  if (!has_fx(code))
78319 	    pair_set_syntax_op(expr, OP_AND_SAFE_P1);
78320 	  else
78321 	    {
78322 	      if (!has_fx(cdr(code)))
78323 		pair_set_syntax_op(expr, OP_AND_SAFE_P2);
78324 	      else
78325 		if ((!has_fx(cddr(code))) && (len == 3))
78326 		  pair_set_syntax_op(expr, OP_AND_SAFE_P3);
78327 		}}}
78328   return(false);
78329 }
78330 
78331 static bool op_and_pair_p(s7_scheme *sc)
78332 {
78333   if (!is_pair(lookup(sc, opt3_sym(sc->code)))) /* cadadr(sc->code) */
78334     {
78335       sc->value = sc->F;
78336       return(true);
78337     }
78338   sc->code = opt2_con(sc->code);                /* caddr(sc->code); */
78339   return(false);
78340 }
78341 
78342 static bool op_and_ap(s7_scheme *sc)
78343 {
78344   /* we know fx_proc is set on sc->code, and there are only two branches */
78345   if (is_false(sc, fx_call(sc, cdr(sc->code))))
78346     {
78347       sc->value = sc->F;
78348       return(true);
78349     }
78350   sc->code = caddr(sc->code);
78351   return(false);
78352 }
78353 
78354 static void op_and_safe_p1(s7_scheme *sc) /* sc->code: (and (func...) (fx...)...) */
78355 {
78356   sc->code = cdr(sc->code); /* new value will be pushed below */
78357   push_stack_no_args_direct(sc, OP_AND_SAFE_P_REST);
78358   sc->code = car(sc->code);
78359 }
78360 
78361 static bool op_and_safe_p2(s7_scheme *sc)
78362 {
78363   sc->value = fx_call(sc, cdr(sc->code));
78364   if (is_false(sc, sc->value)) return(true);
78365   sc->code = cddr(sc->code);
78366   push_stack_no_args_direct(sc, OP_AND_SAFE_P_REST);
78367   sc->code = car(sc->code);
78368   return(false);
78369 }
78370 
78371 static bool op_and_safe_p3(s7_scheme *sc)
78372 {
78373   sc->value = fx_call(sc, cdr(sc->code));
78374   if (is_false(sc, sc->value)) return(true);
78375   sc->code = cddr(sc->code);
78376   sc->value = fx_call(sc, sc->code);
78377   if (is_false(sc, sc->value)) return(true);
78378   sc->code = cadr(sc->code);
78379   return(false);
78380 }
78381 
78382 
78383 /* -------------------------------- or -------------------------------- */
78384 static bool check_or(s7_scheme *sc, s7_pointer expr)
78385 {
78386   s7_pointer p, code;
78387   bool any_nils = false;
78388 
78389   code = cdr(expr);
78390   if (is_null(code))
78391     {
78392       sc->value = sc->F;
78393       return(true);
78394     }
78395 
78396   for (p = code; is_pair(p); p = cdr(p))
78397     {
78398       s7_function callee;
78399       callee = (has_fx(p)) ? fx_proc(p) : fx_choose(sc, p, sc->curlet, let_symbol_is_safe);
78400       if (!callee) any_nils = true;
78401       set_fx(p, callee);
78402     }
78403   if (is_not_null(p))
78404     eval_error(sc, "or: stray dot?: ~A", 18, expr);
78405 
78406   if ((fx_proc(code)) &&
78407       (is_proper_list_1(sc, cdr(code)))) /* list_1 of cdr so there are 2 exprs */
78408     pair_set_syntax_op(expr, (any_nils) ? OP_OR_AP : OP_OR_2);
78409   else pair_set_syntax_op(expr, (any_nils) ? OP_OR_P : OP_OR_N);
78410 
78411   return(false);
78412 }
78413 
78414 static bool op_or_ap(s7_scheme *sc)
78415 {
78416   /* we know fx_proc is set on sc->code, and there are only two branches */
78417   sc->value = fx_call(sc, cdr(sc->code));
78418   if (is_true(sc, sc->value))
78419     return(true);
78420   sc->code = caddr(sc->code);
78421   return(false);
78422 }
78423 
78424 
78425 /* -------------------------------- if -------------------------------- */
78426 
78427 static void fx_safe_closure_tree(s7_scheme *sc)
78428 {
78429   s7_pointer e;
78430   e = sc->curlet;
78431   if ((is_let(e)) &&              /* e might be sc->nil */
78432       (is_funclet(e)) &&
78433       (tis_slot(let_slots(e))))   /* let_slots might be NULL */
78434     {
78435       s7_pointer f;
78436       f = lookup(sc, funclet_function(e));
78437       if (is_safe_closure(f))
78438 	fx_tree(sc, closure_body(f),
78439 		slot_symbol(let_slots(e)),
78440 		(tis_slot(next_slot(let_slots(e)))) ? slot_symbol(next_slot(let_slots(e))) : NULL);
78441     }
78442 }
78443 
78444 #define choose_if_optc(Opc, One, Reversed, Not) ((One) ? ((Reversed) ? OP_ ## Opc ## _R : ((Not) ? OP_ ## Opc ## _N : OP_ ## Opc ## _P)) :  ((Not) ? OP_ ## Opc ## _N_N : OP_ ## Opc ## _P_P))
78445 
78446 static void set_if_opts(s7_scheme *sc, s7_pointer form, bool one_branch, bool reversed) /* cdr(form) == sc->code */
78447 {
78448   s7_pointer test, code;
78449   bool not_case = false;
78450 
78451   code = cdr(form);
78452   test = car(code);
78453   if ((!reversed) &&
78454       (is_pair(test)) &&
78455       (car(test) == sc->not_symbol))
78456     {
78457       if (!is_proper_list_1(sc, cdr(test))) return; /* (not) or (not a b) */
78458       not_case = true;
78459       test = cadr(test);
78460     }
78461 
78462   set_opt1_any(form, cadr(code));
78463   if (!one_branch) set_opt2_any(form, caddr(code));
78464 
78465   if (is_pair(test))
78466     {
78467       if (is_optimized(test))
78468 	{
78469 	  if (is_h_safe_c_d(test)) /* replace these with fx_and* */
78470 	    {
78471 	      pair_set_syntax_op(form, choose_if_optc(IF_A, one_branch, reversed, not_case));
78472 	      if (not_case)
78473 		set_fx(cdar(code), fx_choose(sc, cdar(code), sc->curlet, let_symbol_is_safe));
78474 	      else set_fx(code, fx_choose(sc, code, sc->curlet, let_symbol_is_safe));
78475 	      return;
78476 	    }
78477 
78478 	  if ((is_h_safe_c_s(test)) &&
78479 	      (is_symbol(car(test)))) /* TODO: c_func itself here -- can we get type? */
78480 	    {
78481 	      uint8_t typ;
78482 	      typ = symbol_type(car(test));
78483 	      if (typ > 0)
78484 		{
78485 		  pair_set_syntax_op(form, choose_if_optc(IF_IS_TYPE_S, one_branch, reversed, not_case));
78486 		  set_opt3_byte(code, typ);
78487 
78488 		  if ((optimize_op(form) == OP_IF_IS_TYPE_S_P_P) &&
78489 		      (is_fxable(sc, caddr(code))))
78490 		    {
78491 		      set_opt2_pair(form, cddr(code));
78492 		      if (is_fxable(sc, cadr(code)))
78493 			{
78494 			  fx_annotate_arg(sc, cdr(code), sc->curlet);
78495 			  pair_set_syntax_op(form, OP_IF_IS_TYPE_S_A_A);
78496 			}
78497 		      else pair_set_syntax_op(form, OP_IF_IS_TYPE_S_P_A);
78498 		      fx_annotate_arg(sc, cddr(code), sc->curlet);
78499 		      fx_safe_closure_tree(sc);
78500 		    }}
78501 	      else
78502 		{
78503 		  pair_set_syntax_op(form, choose_if_optc(IF_opSq, one_branch, reversed, not_case));
78504 		  if (not_case) set_opt1_pair(code, cadar(code)); /* code is cdr(if...): ((not (f sym)) ...) */
78505 		}
78506 	      clear_has_fx(code);
78507 	      set_opt2_sym(code, cadr(test));
78508 	      return;
78509 	    }
78510 	  if (is_fxable(sc, test))
78511 	    {
78512 	      if (optimize_op(test) == OP_OR_2)
78513 		{
78514 		  pair_set_syntax_op(form, choose_if_optc(IF_OR2, one_branch, reversed, not_case));
78515 		  clear_has_fx(code);
78516 		  set_opt2_pair(code, cdr(test));
78517 		  set_opt3_pair(code, cddr(test));
78518 		  return;
78519 		}
78520 	      if (optimize_op(test) == OP_AND_2)
78521 		{
78522 		  pair_set_syntax_op(form, choose_if_optc(IF_AND2, one_branch, reversed, not_case));
78523 		  clear_has_fx(code);
78524 		  set_opt2_pair(code, cdr(test));
78525 		  set_opt3_pair(code, cddr(test));
78526 		  return;
78527 		}
78528 	      if (optimize_op(test) == OP_AND_3)
78529 		{
78530 		  pair_set_syntax_op(form, choose_if_optc(IF_AND3, one_branch, reversed, not_case));
78531 		  clear_has_fx(code);
78532 		  set_opt2_pair(code, cdr(test));
78533 		  set_opt3_pair(code, cddr(test));
78534 		  set_opt1_pair(code, cdddr(test));
78535 		  return;
78536 		}
78537 
78538 	      pair_set_syntax_op(form, choose_if_optc(IF_A, one_branch, reversed, not_case));
78539 
78540 	      if (not_case)
78541 		set_fx_direct(cdar(code), fx_choose(sc, cdar(code), sc->curlet, let_symbol_is_safe));
78542 	      else set_fx_direct(code, fx_choose(sc, code, sc->curlet, let_symbol_is_safe));
78543 
78544 	      if ((optimize_op(form) == OP_IF_A_P) &&
78545 		  (is_fxable(sc, cadr(code))))
78546 		{
78547 		  pair_set_syntax_op(form, OP_IF_A_A);
78548 		  fx_annotate_arg(sc, cdr(code), sc->curlet);
78549 		  set_opt1_pair(form, cdr(code));
78550 		  fx_safe_closure_tree(sc);
78551 		}
78552 	      if (optimize_op(form) == OP_IF_A_P_P)
78553 		{
78554 		  if (is_fxable(sc, cadr(code)))
78555 		    {
78556 		      set_opt1_pair(form, cdr(code));
78557 		      if (is_fxable(sc, caddr(code)))
78558 			{
78559 			  pair_set_syntax_op(form, OP_IF_A_A_A);
78560 			  set_opt2_pair(form, cddr(code));
78561 			}
78562 		      else pair_set_syntax_op(form, OP_IF_A_A_P);
78563 		      fx_annotate_args(sc, cdr(code), sc->curlet);
78564 		      fx_safe_closure_tree(sc);
78565 		    }
78566 		  else
78567 		    if (is_fxable(sc, caddr(code)))
78568 		      {
78569 			pair_set_syntax_op(form, OP_IF_A_P_A);
78570 			fx_annotate_args(sc, cdr(code), sc->curlet);
78571 			set_opt2_pair(form, cddr(code));
78572 			fx_safe_closure_tree(sc);
78573 		      }}}
78574 	  else
78575 	    {
78576 	      pair_set_syntax_op(form, choose_if_optc(IF_P, one_branch, reversed, not_case));
78577 	      set_opt2_any(code, (one_branch) ? cadr(code) : cdr(code));
78578 	      set_opt3_any(code, (not_case) ? cadar(code) : car(code));
78579 	    }}
78580       else
78581 	{
78582 	  pair_set_syntax_op(form, choose_if_optc(IF_P, one_branch, reversed, not_case));
78583 	  clear_has_fx(code);
78584 	  set_opt2_any(code, (one_branch) ? cadr(code) : cdr(code));
78585 	  set_opt3_any(code, (not_case) ? cadar(code) : car(code));
78586 	  if (is_syntactic_symbol(car(test)))
78587 	    {
78588 	      pair_set_syntax_op(test, symbol_syntax_op_checked(test));
78589 	      if ((symbol_syntax_op(car(test)) == OP_AND) ||
78590 		  (symbol_syntax_op(car(test)) == OP_OR))
78591 		{
78592 		  opcode_t new_op;
78593 		  if (symbol_syntax_op(car(test)) == OP_AND)
78594 		    check_and(sc, test);
78595 		  else check_or(sc, test);
78596 		  new_op = symbol_syntax_op_checked(test);
78597 		  if ((new_op == OP_AND_P) || (new_op == OP_AND_AP) || (new_op == OP_AND_PAIR_P) ||
78598 		      (new_op == OP_AND_N) || (new_op == OP_AND_SAFE_P1) || (new_op == OP_AND_SAFE_P2) || (new_op == OP_AND_SAFE_P3))
78599 		    {
78600 		      pair_set_syntax_op(form, choose_if_optc(IF_ANDP, one_branch, reversed, not_case));
78601 		      set_opt2_any(code, (one_branch) ? cadr(code) : cdr(code));
78602 		      set_opt3_pair(code, (not_case) ? cdadar(code) : cdar(code));
78603 		    }
78604 		  else
78605 		    if ((new_op == OP_OR_P) || (new_op == OP_OR_AP))
78606 		      {
78607 			pair_set_syntax_op(form, choose_if_optc(IF_ORP, one_branch, reversed, not_case));
78608 			set_opt2_any(code, (one_branch) ? cadr(code) : cdr(code));
78609 			set_opt3_pair(code, (not_case) ? cdadar(code) : cdar(code));
78610 		      }}}}}
78611   else /* test is symbol or constant, but constant here is nutty */
78612     {
78613       if (is_safe_symbol(test))
78614 	{
78615 	  pair_set_syntax_op(form, choose_if_optc(IF_S, one_branch, reversed, not_case));
78616 	  if (not_case) set_opt1_sym(code, cadar(code)); /* code is cdr(if...): ((not sym) ...) */
78617 	  if ((optimize_op(form) == OP_IF_S_P_P) &&
78618 	      (is_fxable(sc, caddr(code))))
78619 	    {
78620 	      pair_set_syntax_op(form, OP_IF_S_P_A);
78621 	      fx_annotate_arg(sc, cddr(code), sc->curlet);
78622 	      set_opt2_pair(form, cddr(code));
78623 	      fx_safe_closure_tree(sc);
78624 	    }}}
78625 }
78626 
78627 /* (cond <> (else <>)) only happens in old-fashioned code, so set_if_opts covers if/when/unless but not cond */
78628 
78629 static s7_pointer check_if(s7_scheme *sc, s7_pointer form)
78630 {
78631   s7_pointer cdr_code, code;
78632   code = cdr(form);
78633 
78634   if (!is_pair(code))                                /* (if) or (if . 1) */
78635     eval_error(sc, "(if): if needs at least 2 expressions: ~A", 41, form);
78636 
78637   cdr_code = cdr(code);
78638   if (!is_pair(cdr_code))                            /* (if 1) */
78639     eval_error(sc, "~S: if needs another clause", 27, form);
78640 
78641   if (is_pair(cdr(cdr_code)))
78642     {
78643       if (is_not_null(cddr(cdr_code)))               /* (if 1 2 3 4) */
78644 	eval_error(sc, "too many clauses for if: ~A", 27, form);
78645     }
78646   else
78647     if (is_not_null(cdr(cdr_code)))                  /* (if 1 2 . 3) */
78648       eval_error(sc, "if: ~A has improper list?", 25, form);
78649 
78650   pair_set_syntax_op(form, OP_IF_UNCHECKED);
78651   set_if_opts(sc, form, is_null(cdr(cdr_code)), false);
78652   return(code);
78653 }
78654 
78655 static void op_if(s7_scheme *sc)
78656 {
78657   sc->code = check_if(sc, sc->code);
78658   push_stack_no_args(sc, OP_IF1, cdr(sc->code));
78659   sc->code = car(sc->code);
78660 }
78661 
78662 static void op_if_unchecked(s7_scheme *sc)
78663 {
78664   push_stack_no_args(sc, OP_IF1, cddr(sc->code));
78665   sc->code = cadr(sc->code);
78666 }
78667 
78668 static bool op_if1(s7_scheme *sc)
78669 {
78670   sc->code = (is_true(sc, sc->value)) ? car(sc->code) : unchecked_car(cdr(sc->code));
78671   /* even pre-optimization, (if #f #f) ==> #<unspecified> because unique_car(sc->nil) = sc->unspecified */
78672   if (is_pair(sc->code))
78673     return(true);
78674   sc->value = (is_symbol(sc->code)) ? lookup_checked(sc, sc->code) : sc->code;
78675   return(false);
78676 }
78677 
78678 
78679 
78680 /* -------------------------------- when -------------------------------- */
78681 static void check_when(s7_scheme *sc)
78682 {
78683   s7_pointer form, code;
78684   form = sc->code;
78685   code = cdr(sc->code);
78686 
78687   if (!is_pair(code))                                            /* (when) or (when . 1) */
78688     eval_error(sc, "when has no expression or body:  ~A", 35, form);
78689   if (!is_pair(cdr(code)))                                       /* (when 1) or (when 1 . 1) */
78690     eval_error(sc, "when has no body?:  ~A", 22, form);
78691   else
78692     if (!s7_is_proper_list(sc, cddr(code)))
78693       eval_error(sc, "when: stray dot?", 16, form);
78694 
78695   pair_set_syntax_op(form, OP_WHEN_P);
78696   if (is_null(cddr(code)))
78697     set_if_opts(sc, form, true, false);
78698   else
78699     {
78700       s7_pointer test;
78701       test = car(code);
78702       if (is_safe_symbol(test))
78703 	{
78704 	  pair_set_syntax_op(form, OP_WHEN_S);
78705 	  set_opt2_con(form, cadr(code));
78706 	  set_opt3_pair(form, cddr(code));
78707 	}
78708       else
78709 	{
78710 	  /* fxable body doesn't happen very often -- a dozen or so hits in the standard tests */
78711 	  if (is_fxable(sc, test))
78712 	    {
78713 	      pair_set_syntax_op(form, OP_WHEN_A);
78714 	      if (is_pair(car(code))) set_opt2_pair(form, cdar(code));
78715 	      set_opt3_pair(form, cdr(code));
78716 	      set_fx_direct(code, fx_choose(sc, code, sc->curlet, let_symbol_is_safe)); /* "A" in when_a */
78717 
78718 	      if (fx_proc(code) == fx_and_2)
78719 		pair_set_syntax_op(form, OP_WHEN_AND_2);
78720 	      else
78721 		if (fx_proc(code) == fx_and_3)
78722 		  pair_set_syntax_op(form, OP_WHEN_AND_3);
78723 	    }
78724 	  else
78725 	    {
78726 	      if ((is_pair(test)) && (car(test) == sc->and_symbol))
78727 		{
78728 		  opcode_t new_op;
78729 		  pair_set_syntax_op(test, symbol_syntax_op_checked(test));
78730 		  check_and(sc, test);
78731 		  new_op = symbol_syntax_op_checked(test);
78732 		  if (new_op == OP_AND_AP)
78733 		    pair_set_syntax_op(form, OP_WHEN_AND_AP);
78734 		}}}}
78735   push_stack_no_args(sc, OP_WHEN_PP, cdr(code));
78736   sc->code = car(code);
78737 }
78738 
78739 static bool op_when_s(s7_scheme *sc)
78740 {
78741   if (is_true(sc, lookup(sc, cadr(sc->code))))
78742     {
78743       push_stack_no_args(sc, sc->begin_op, opt3_pair(sc->code)); /* cdddr(sc->code) */
78744       sc->code = opt2_con(sc->code);                             /* caddr(sc->code) */
78745       return(false);
78746     }
78747   sc->value = sc->unspecified;
78748   return(true);
78749 }
78750 
78751 static bool op_when_a(s7_scheme *sc)
78752 {
78753   if (is_true(sc, fx_call(sc, cdr(sc->code))))
78754     {
78755       push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(opt3_pair(sc->code)))); /* cdddr(sc->code) */
78756       sc->code = car(opt3_pair(sc->code));                                    /* caddr(sc->code) */
78757       return(false);
78758     }
78759   sc->value = sc->unspecified;
78760   return(true);
78761 }
78762 
78763 static bool op_when_and_2(s7_scheme *sc)
78764 {
78765   if ((is_true(sc, fx_call(sc, opt2_pair(sc->code)))) && (is_true(sc, fx_call(sc, cdr(opt2_pair(sc->code))))))
78766     {
78767       push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(opt3_pair(sc->code)))); /* cdddr(sc->code) */
78768       sc->code = car(opt3_pair(sc->code));                                    /* caddr(sc->code) */
78769       return(false);
78770     }
78771   sc->value = sc->unspecified;
78772   return(true);
78773 }
78774 
78775 static bool op_when_and_3(s7_scheme *sc)
78776 {
78777   if ((is_true(sc, fx_call(sc, opt2_pair(sc->code)))) && (is_true(sc, fx_call(sc, cdr(opt2_pair(sc->code))))) && (is_true(sc, fx_call(sc, cddr(opt2_pair(sc->code))))))
78778     {
78779       push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(opt3_pair(sc->code)))); /* cdddr(sc->code) */
78780       sc->code = car(opt3_pair(sc->code));                                    /* caddr(sc->code) */
78781       return(false);
78782     }
78783   sc->value = sc->unspecified;
78784   return(true);
78785 }
78786 
78787 static void op_when_p(s7_scheme *sc)
78788 {
78789   push_stack_no_args(sc, OP_WHEN_PP, cddr(sc->code));
78790   sc->code = cadr(sc->code);
78791 }
78792 
78793 static bool op_when_and_ap(s7_scheme *sc)
78794 {
78795   s7_pointer andp;
78796   andp = cdadr(sc->code);
78797   if (is_true(sc, fx_call(sc, andp)))
78798     {
78799       push_stack_no_args(sc, OP_WHEN_PP, cddr(sc->code));
78800       sc->code = cadr(andp);
78801       return(false);
78802     }
78803   sc->value = sc->unspecified;
78804   return(true);
78805 }
78806 
78807 static bool op_when_pp(s7_scheme *sc)
78808 {
78809   if (is_true(sc, sc->value))
78810     {
78811       if (is_pair(cdr(sc->code)))
78812 	push_stack_no_args(sc, sc->begin_op, cdr(sc->code));
78813       sc->code = car(sc->code);
78814       return(false);
78815     }
78816   sc->value = sc->unspecified;
78817   return(true);
78818 }
78819 
78820 
78821 /* -------------------------------- unless -------------------------------- */
78822 static void check_unless(s7_scheme *sc)
78823 {
78824   s7_pointer form, code;
78825   form = sc->code;
78826   code = cdr(sc->code);
78827 
78828   if (!is_pair(code))                                            /* (unless) or (unless . 1) */
78829     eval_error(sc, "unless has no expression or body:  ~A", 37, form);
78830   if (!is_pair(cdr(code)))                                       /* (unless 1) or (unless 1 . 1) */
78831     eval_error(sc, "unless has no body?:  ~A", 24, form);
78832   else
78833     if (!s7_is_proper_list(sc, cddr(code)))
78834       eval_error(sc, "unless: stray dot?", 18, form);
78835 
78836   pair_set_syntax_op(form, OP_UNLESS_P);
78837   if (is_null(cddr(code)))
78838     set_if_opts(sc, form, true, true);
78839   else
78840     {
78841       if (is_safe_symbol(car(code)))
78842 	{
78843 	  pair_set_syntax_op(form, OP_UNLESS_S);
78844 	  set_opt2_con(form, cadr(code));
78845 	  set_opt3_pair(form, cddr(code));
78846 	}
78847       else
78848 	if (is_fxable(sc, car(code)))
78849 	  {
78850 	    pair_set_syntax_op(form, OP_UNLESS_A);
78851 	    set_opt2_con(form, cadr(code));
78852 	    set_opt3_pair(form, cddr(code));
78853 	    set_fx_direct(code, fx_choose(sc, code, sc->curlet, let_symbol_is_safe));
78854 	  }}
78855   push_stack_no_args(sc, OP_UNLESS_PP, cdr(code));
78856   sc->code = car(code);
78857 }
78858 
78859 static bool op_unless_s(s7_scheme *sc)
78860 {
78861   if (is_false(sc, lookup(sc, cadr(sc->code))))
78862     {
78863       push_stack_no_args(sc, sc->begin_op, opt3_pair(sc->code)); /* cdddr(sc->code) */
78864       sc->code = opt2_con(sc->code);                             /* caddr(sc->code) */
78865       return(false);
78866     }
78867   sc->value = sc->unspecified;
78868   return(true);
78869 }
78870 
78871 static bool op_unless_a(s7_scheme *sc)
78872 {
78873   if (is_false(sc, fx_call(sc, cdr(sc->code))))
78874     {
78875       push_stack_no_args(sc, sc->begin_op, opt3_pair(sc->code)); /* cdddr(sc->code) */
78876       sc->code = opt2_con(sc->code);                             /* caddr(sc->code) */
78877       return(false);
78878     }
78879   sc->value = sc->unspecified;
78880   return(true);
78881 }
78882 
78883 static void op_unless_p(s7_scheme *sc)
78884 {
78885   push_stack_no_args(sc, OP_UNLESS_PP, cddr(sc->code));
78886   sc->code = cadr(sc->code);
78887 }
78888 
78889 static bool op_unless_pp(s7_scheme *sc)
78890 {
78891   if (is_false(sc, sc->value))
78892     {
78893       if (is_pair(cdr(sc->code)))
78894 	push_stack_no_args(sc, sc->begin_op, cdr(sc->code));
78895       sc->code = car(sc->code);
78896       return(false);
78897     }
78898   sc->value = sc->unspecified;
78899   return(true);
78900 }
78901 
78902 
78903 /* -------------------------------- begin -------------------------------- */
78904 static bool op_begin(s7_scheme *sc, s7_pointer code)
78905 {
78906   s7_pointer form;
78907   form = cdr(code);
78908   if (!s7_is_proper_list(sc, form))    /* proper list includes () */
78909     eval_error(sc, "unexpected dot? ~A", 18, code);
78910   if (is_null(form))                   /* (begin) -> () */
78911     {
78912       sc->value = sc->nil;
78913       return(true);
78914     }
78915   if (is_null(cdr(form)))
78916     pair_set_syntax_op(code, OP_BEGIN_1_UNCHECKED);
78917   else
78918     {
78919       if (is_null(cddr(form)))
78920 	pair_set_syntax_op(code, OP_BEGIN_2_UNCHECKED);
78921       else pair_set_syntax_op(code, OP_BEGIN_UNCHECKED);
78922     }
78923   return(false);
78924 }
78925 
78926 
78927 /* -------------------------------- define -------------------------------- */
78928 static s7_pointer print_truncate(s7_scheme *sc, s7_pointer code)
78929 {
78930   if (tree_len(sc, code) > sc->print_length)
78931     return(object_to_truncated_string(sc, code, sc->print_length * 10));
78932   return(code);
78933 }
78934 
78935 static void check_define(s7_scheme *sc)
78936 {
78937   s7_pointer func, caller, code;
78938   bool starred;
78939 
78940   code = cdr(sc->code);
78941   starred = (sc->cur_op == OP_DEFINE_STAR);
78942   if (starred)
78943     {
78944       caller = sc->define_star_symbol;
78945       sc->cur_op = OP_DEFINE_STAR_UNCHECKED;
78946     }
78947   else caller = (sc->cur_op == OP_DEFINE) ? sc->define_symbol : sc->define_constant_symbol;
78948 
78949   if (!is_pair(code))
78950     eval_error_with_caller(sc, "~A: nothing to define? ~A", 25, caller, sc->code);     /* (define) */
78951 
78952   if (!is_pair(cdr(code)))
78953     {
78954       if (is_null(cdr(code)))
78955 	eval_error_with_caller(sc, "~A: no value? ~A", 16, caller, sc->code);    /* (define var) */
78956       eval_error_with_caller(sc, "~A: stray dot? ~A", 17, caller, sc->code);     /* (define var . 1) */
78957     }
78958   if (!is_pair(car(code)))
78959     {
78960       if (is_not_null(cddr(code)))                                               /* (define var 1 . 2) */
78961 	s7_error(sc, sc->syntax_error_symbol,
78962 		 set_elist_3(sc, wrap_string(sc, "~A: more than one value? ~A", 27), caller, print_truncate(sc, sc->code)));
78963       if (starred)
78964 	eval_error(sc, "define* is restricted to functions: (define* ~{~S~^ ~})", 55, sc->code);
78965 
78966       func = car(code);
78967       if (!is_symbol(func))                                                      /* (define 3 a) */
78968 	eval_error_with_caller2(sc, "~A: can't define ~S, ~A (should be a symbol)", 44, caller, func, prepackaged_type_name(sc, func));
78969       if (is_keyword(func))                                                      /* (define :hi 1) */
78970 	eval_error_with_caller(sc, "~A ~A: keywords are constants", 29, caller, func);
78971       if (is_syntactic_symbol(func))                                             /* (define and a) */
78972 	{
78973 	  if (sc->safety > NO_SAFETY)
78974 	    s7_warn(sc, 128, "%s: syntactic keywords tend to behave badly if redefined\n", display(func));
78975 	  set_local(func);
78976 	}
78977       if ((is_pair(cadr(code))) &&               /* look for (define sym (lambda ...)) and treat it like (define (sym ...)...) */
78978 	  ((caadr(code) == sc->lambda_symbol) ||
78979 	   (caadr(code) == sc->lambda_star_symbol)) &&
78980 	  (symbol_id(caadr(code)) == 0))
78981 	{
78982 	  /* not is_global here because that bit might not be set for initial symbols (why not? -- redef as method etc) */
78983 	  if (!is_pair(cdadr(code)))                                             /* (define x (lambda . 1)) */
78984 	    eval_error_with_caller(sc, "~A: stray dot? ~A", 17, caller, sc->code);
78985 	  if (!is_pair(cddr(cadr(code))))                                        /* (define f (lambda (arg))) */
78986 	    eval_error_with_caller(sc, "~A: no body: ~A", 15, caller, sc->code);
78987 	  if (caadr(code) == sc->lambda_star_symbol)
78988 	    check_lambda_star_args(sc, cadadr(code), cddr(cadr(code)));
78989 	  else check_lambda_args(sc, cadadr(code), NULL);
78990 	  optimize_lambda(sc, caadr(code) == sc->lambda_symbol, func, cadadr(code), cddr(cadr(code)));
78991 	}}
78992   else
78993     {
78994       func = caar(code);
78995       if (!is_symbol(func))                                                      /* (define (3 a) a) */
78996 	eval_error_with_caller2(sc, "~A: can't define ~S, ~A (should be a symbol)", 44, caller, func, prepackaged_type_name(sc, func));
78997       if (is_syntactic_symbol(func))                                             /* (define (and a) a) */
78998 	{
78999 	  if (sc->safety > NO_SAFETY)
79000 	    s7_warn(sc, 128, "%s: syntactic keywords tend to behave badly if redefined\n", display(func));
79001 	  set_local(func);
79002 	}
79003       if (starred)
79004 	set_cdar(code, check_lambda_star_args(sc, cdar(code), cdr(code)));
79005       else check_lambda_args(sc, cdar(code), NULL);
79006       optimize_lambda(sc, !starred, func, cdar(code), cdr(code));
79007     }
79008 
79009   if ((sc->cur_op == OP_DEFINE) ||
79010       (sc->cur_op == OP_DEFINE_CONSTANT)) /* ?? 10-May-18 */
79011     {
79012       if ((is_pair(car(code))) &&
79013 	  (!symbol_has_setter(func)) &&
79014 	  (!is_possibly_constant(func)))
79015 	pair_set_syntax_op(sc->code, OP_DEFINE_FUNCHECKED);
79016       else pair_set_syntax_op(sc->code, OP_DEFINE_UNCHECKED);
79017     }
79018   else
79019     {
79020       if (starred)
79021 	pair_set_syntax_op(sc->code, OP_DEFINE_STAR_UNCHECKED);
79022       else pair_set_syntax_op(sc->code, OP_DEFINE_CONSTANT_UNCHECKED);
79023     }
79024 }
79025 
79026 static bool op_define_unchecked(s7_scheme *sc)
79027 {
79028   s7_pointer code, locp;
79029   code = cdr(sc->code);
79030 
79031   if ((is_pair(car(code))) && (has_location(car(code))))
79032     locp = car(code);
79033   else
79034     for (locp = cdr(code); is_pair(locp); locp = cdr(locp))
79035       if ((is_pair(car(locp))) && (has_location(car(locp))))
79036 	{
79037 	  locp = car(locp);
79038 	  break;
79039 	}
79040 
79041   if ((sc->cur_op == OP_DEFINE_STAR_UNCHECKED) && /* sc->cur_op changed above if define* */
79042       (is_pair(cdar(code))))
79043     {
79044       sc->value = make_closure(sc, cdar(code), cdr(code), T_CLOSURE_STAR, CLOSURE_ARITY_NOT_SET);
79045       /* closure_body might not be cdr(code) after make_closure (add_trace) */
79046       if ((is_pair(locp)) && (has_location(locp)))
79047 	{
79048 	  pair_set_location(closure_body(sc->value), pair_location(locp));
79049 	  set_has_location(closure_body(sc->value));
79050 	}
79051       sc->code = caar(code);
79052       return(false);
79053     }
79054 
79055   if (!is_pair(car(code)))
79056     {
79057       s7_pointer x;
79058       x = car(code);
79059       sc->code = cadr(code);
79060       if (is_pair(sc->code))
79061 	{
79062 	  push_stack(sc, OP_DEFINE1, sc->nil, x);
79063 	  sc->cur_op = optimize_op(sc->code);
79064 	  return(true);
79065 	}
79066       sc->value = (is_symbol(sc->code)) ? lookup_global(sc, sc->code) : sc->code;
79067       sc->code = x;
79068     }
79069   else
79070     {
79071       s7_pointer x, args;
79072       /* a closure.  If we called this same code earlier (a local define), the only thing
79073        *   that is new here is the environment -- we can't blithely save the closure object
79074        *   in opt2 somewhere, and pick it up the next time around (since call/cc might take
79075        *   us back to the previous case).  We also can't re-use opt2(sc->code) because opt2
79076        *   is not cleared in the gc.
79077        */
79078       args = cdar(code);
79079       x = make_closure(sc, args, cdr(code), T_CLOSURE | T_COPY_ARGS, (is_null(args)) ? 0 : CLOSURE_ARITY_NOT_SET);
79080       if ((is_pair(locp)) && (has_location(locp)))
79081 	{
79082 	  pair_set_location(closure_body(x), pair_location(locp));
79083 	  set_has_location(closure_body(x));
79084 	}
79085       sc->value = T_Pos(x);
79086       sc->code = caar(code);
79087     }
79088   return(false);
79089 }
79090 
79091 static s7_pointer make_funclet(s7_scheme *sc, s7_pointer new_func, s7_pointer func_name, s7_pointer outer_let)
79092 {
79093   s7_pointer new_let, arg;
79094   new_cell_no_check(sc, new_let, T_LET | T_FUNCLET);
79095   let_set_id(new_let, ++sc->let_number);
79096   let_set_outlet(new_let, outer_let);
79097   closure_set_let(new_func, new_let);
79098   funclet_set_function(new_let, func_name); /* *function* returns at least funclet_function */
79099   let_set_slots(new_let, slot_end(sc));
79100 
79101   arg = closure_args(new_func);
79102   if (is_null(arg))
79103     {
79104       let_set_slots(new_let, slot_end(sc));
79105       return(new_let);
79106     }
79107 
79108   if (is_safe_closure(new_func))
79109     {
79110       s7_pointer last_slot = NULL;
79111       if (is_closure(new_func))
79112 	{
79113 	  if (is_pair(arg))
79114 	    {
79115 	      last_slot = make_slot(sc, car(arg), sc->nil);
79116 	      slot_set_next(last_slot, slot_end(sc));
79117 	      let_set_slots(new_let, last_slot);
79118 	      symbol_set_local_slot(car(arg), let_id(new_let), last_slot);
79119 	      for (arg = cdr(arg); is_pair(arg); arg = cdr(arg))
79120 		last_slot = add_slot_at_end(sc, let_id(new_let), last_slot, car(arg), sc->nil);
79121 	    }
79122 	  if (is_symbol(arg))
79123 	    {
79124 	      if (last_slot)
79125 		last_slot = add_slot_at_end(sc, let_id(new_let), last_slot, arg, sc->nil);
79126 	      else
79127 		{
79128 		  last_slot = make_slot(sc, arg, sc->nil);
79129 		  slot_set_next(last_slot, slot_end(sc));
79130 		  let_set_slots(new_let, last_slot);
79131 		  symbol_set_local_slot(arg, let_id(new_let), last_slot);
79132 		}
79133 	      set_is_rest_slot(last_slot);
79134 	    }}
79135       else /* closure_star */
79136 	{
79137 	  s7_pointer slot, first_default;
79138 	  first_default = sc->nil;
79139 	  let_set_slots(new_let, slot_end(sc));
79140 	  for (; is_pair(arg); arg = cdr(arg))
79141 	    {
79142 	      s7_pointer par;
79143 	      par = car(arg);
79144 	      if (is_pair(par))
79145 		{
79146 		  s7_pointer val;
79147 		  val = cadr(par);
79148 		  slot = make_slot_2(sc, new_let, car(par), sc->nil);
79149 		  slot_set_expression(slot, val);
79150 		  if ((is_symbol(val)) || (is_pair(val)))
79151 		    {
79152 		      if (is_null(first_default))
79153 			first_default = slot;
79154 		      set_slot_defaults(slot);
79155 		    }}
79156 	      else
79157 		{
79158 		  if (is_keyword(par))
79159 		    {
79160 		      if (par == sc->key_rest_symbol)
79161 			{
79162 			  arg = cdr(arg);
79163 			  slot = make_slot_2(sc, new_let, car(arg), sc->nil);
79164 			  slot_set_expression(slot, sc->nil);
79165 			}}
79166 		  else
79167 		    {
79168 		      slot = make_slot_2(sc, new_let, par, sc->nil);
79169 		      slot_set_expression(slot, sc->F);
79170 		    }}}
79171 	  if (is_symbol(arg))
79172 	    {
79173 	      slot = make_slot_2(sc, new_let, arg, sc->nil);     /* set up rest arg */
79174 	      set_is_rest_slot(slot);
79175 	      slot_set_expression(slot, sc->nil);
79176 	    }
79177 	  if (tis_slot(let_slots(new_let)))
79178 	    {
79179 	      let_set_slots(new_let, reverse_slots(sc, let_slots(new_let)));
79180 	      slot_set_pending_value(let_slots(new_let), first_default);
79181 	    }}
79182       set_immutable_let(new_let);
79183     }
79184   else let_set_slots(new_let, slot_end(sc)); /* if unsafe closure, arg-holding-let will be created on each call */
79185   return(new_let);
79186 }
79187 
79188 static bool op_define_constant(s7_scheme *sc)
79189 {
79190   s7_pointer code;
79191   code = cdr(sc->code);
79192   if ((!is_pair(code)) || (!is_pair(cdr(code)))) /* (define-constant) */
79193     eval_error(sc, "define-constant: not enough arguments: ~S", 41, sc->code);
79194 
79195   if (is_keyword(car(code)))                   /* (define-constant :rest :allow-other-keys) */
79196     {
79197       if (car(code) == cadr(code))             /* (define-constant pi pi) returns pi */
79198 	{
79199 	  sc->value = car(code);
79200 	  return(true);
79201 	}
79202       eval_error_with_caller(sc, "~A ~A: keywords are constants", 29, sc->define_constant_symbol, car(code));
79203     }
79204 
79205   if ((is_symbol(car(code))) &&                /* (define-constant abs abs): "abs will not be touched" */
79206       (car(code) == cadr(code)) &&
79207       (symbol_id(car(code)) == 0) &&           /* else (let iter ... (define-constant iter iter) ...) -> segfault on later calls */
79208       (is_null(cddr(code))))
79209     {
79210       s7_pointer sym;
79211       sym = car(code);
79212       set_immutable(global_slot(sym)); /* id == 0 so its global */
79213       set_possibly_constant(sym);
79214       sc->value = lookup_checked(sc, car(code));
79215       return(true);
79216     }
79217   push_stack_no_args(sc, OP_DEFINE_CONSTANT1, car(code));
79218   return(false);
79219 }
79220 
79221 static void op_define_constant1(s7_scheme *sc)
79222 {
79223   if (is_pair(sc->code))
79224     sc->code = car(sc->code); /* (define-constant (ex3 a)...) */
79225   if (is_symbol(sc->code))
79226     {
79227       s7_pointer slot;
79228       slot = lookup_slot_from(sc->code, sc->curlet);
79229       set_possibly_constant(sc->code);
79230       set_immutable(slot);
79231       if (is_any_closure(slot_value(slot)))
79232 	set_immutable(slot_value(slot)); /* for the optimizer mainly */
79233     }
79234 }
79235 
79236 static inline void define_funchecked(s7_scheme *sc)
79237 {
79238   s7_pointer new_func, code;
79239   code = cdr(sc->code);
79240   sc->value = caar(code); /* func name */
79241 
79242   new_cell(sc, new_func, T_CLOSURE | T_COPY_ARGS);
79243   closure_set_args(new_func, cdar(code));
79244   closure_set_body(new_func, cdr(code));
79245   if (is_pair(cddr(code))) set_closure_has_multiform(new_func); else set_closure_has_one_form(new_func);
79246   closure_set_setter(new_func, sc->F);
79247   closure_set_arity(new_func, CLOSURE_ARITY_NOT_SET);
79248   sc->capture_let_counter++;
79249 
79250   if (is_safe_closure_body(cdr(code)))
79251     {
79252       set_safe_closure(new_func);
79253       if (is_very_safe_closure_body(cdr(code)))
79254 	set_very_safe_closure(new_func);
79255       make_funclet(sc, new_func, sc->value, sc->curlet);
79256     }
79257   else closure_set_let(new_func, sc->curlet);  /* unsafe closures created by other functions do not support *function* */
79258 
79259   if (let_id(sc->curlet) < symbol_id(sc->value))
79260     sc->let_number++; /* dummy let, force symbol lookup */
79261   another_slot(sc, sc->curlet, sc->value, new_func, sc->let_number);
79262   sc->value = new_func;
79263 }
79264 
79265 static s7_pointer cur_op_to_caller(s7_scheme *sc, opcode_t op)
79266 {
79267   switch (op)
79268     {
79269     case OP_DEFINE_MACRO:          return(sc->define_macro_symbol);
79270     case OP_DEFINE_MACRO_STAR:     return(sc->define_macro_star_symbol);
79271     case OP_DEFINE_BACRO:          return(sc->define_bacro_symbol);
79272     case OP_DEFINE_BACRO_STAR:     return(sc->define_bacro_star_symbol);
79273     case OP_DEFINE_EXPANSION:      return(sc->define_expansion_symbol);
79274     case OP_DEFINE_EXPANSION_STAR: return(sc->define_expansion_star_symbol);
79275     case OP_MACRO:                 return(sc->macro_symbol);
79276     case OP_MACRO_STAR:            return(sc->macro_star_symbol);
79277     case OP_BACRO:                 return(sc->bacro_symbol);
79278     case OP_BACRO_STAR:            return(sc->bacro_star_symbol);
79279     }
79280   return(sc->define_macro_symbol);
79281 }
79282 
79283 static s7_pointer check_define_macro(s7_scheme *sc, opcode_t op)
79284 {
79285   s7_pointer mac_name, args, caller;
79286   caller = cur_op_to_caller(sc, op);
79287 
79288   if (!is_pair(sc->code))                                           /* (define-macro . 1) */
79289     eval_error_with_caller(sc, "~A name missing (stray dot?): ~A", 32, caller, sc->code);
79290   if (!is_pair(car(sc->code)))                                      /* (define-macro a ...) */
79291     return(wrong_type_argument_with_type(sc, caller, 1, car(sc->code), wrap_string(sc, "a list: (name ...)", 18)));
79292 
79293   mac_name = caar(sc->code);
79294   if (!is_symbol(mac_name))
79295     eval_error_with_caller(sc, "~A: ~S is not a symbol?", 23, caller, mac_name);
79296   if (is_syntactic_symbol(mac_name))
79297     {
79298       if (sc->safety > NO_SAFETY)
79299 	s7_warn(sc, 128, "%s: syntactic keywords tend to behave badly if redefined\n", display(mac_name));
79300       set_local(mac_name);
79301     }
79302   if (is_constant_symbol(sc, mac_name))
79303     eval_error_with_caller(sc, "~A: ~S is constant", 18, caller, mac_name);
79304 
79305   if (!is_pair(cdr(sc->code)))                                        /* (define-macro (...)) */
79306     eval_error_with_caller(sc, "~A ~A, but no body?", 19, caller, mac_name);
79307 
79308   args = cdar(sc->code);
79309   if ((!is_list(args)) &&
79310       (!is_symbol(args)))
79311     return(s7_error(sc, sc->syntax_error_symbol,                      /* (define-macro (mac . 1) ...) */
79312 		    set_elist_3(sc, wrap_string(sc, "macro ~A argument list is ~S?", 29), mac_name, args)));
79313 
79314   if ((op == OP_DEFINE_MACRO) || (op == OP_DEFINE_BACRO) || (op == OP_DEFINE_EXPANSION))
79315     {
79316       for ( ; is_pair(args); args = cdr(args))
79317 	if (!is_symbol(car(args)))
79318 	  return(s7_error(sc, sc->syntax_error_symbol,                /* (define-macro (mac 1) ...) */
79319 			  set_elist_3(sc, wrap_string(sc, "~A parameter name, ~A, is not a symbol", 38), caller, car(args))));
79320       check_lambda_args(sc, cdar(sc->code), NULL);
79321     }
79322   else set_cdar(sc->code, check_lambda_star_args(sc, cdar(sc->code), NULL));
79323   return(sc->code);
79324 }
79325 
79326 static s7_pointer check_macro(s7_scheme *sc, opcode_t op)
79327 {
79328   s7_pointer args, caller;
79329   caller = cur_op_to_caller(sc, op);
79330 
79331   if (!is_pair(sc->code))                                             /* (define-macro . 1) */
79332     eval_error_with_caller(sc, "~A name missing (stray dot?): ~A", 32, caller, sc->code);
79333   if (!is_pair(cdr(sc->code)))                                        /* (define-macro (...)) */
79334     eval_error_with_caller(sc, "(~A ~A) has no body?", 20, caller, car(sc->code));
79335 
79336   args = car(sc->code);
79337   if ((!is_list(args)) &&
79338       (!is_symbol(args)))
79339     return(s7_error(sc, sc->syntax_error_symbol,                      /* (define-macro (mac . 1) ...) */
79340 		    set_elist_2(sc, wrap_string(sc, "macro argument list is ~S?", 26), args)));
79341 
79342   if ((op == OP_MACRO) || (op == OP_BACRO))
79343     {
79344       for ( ; is_pair(args); args = cdr(args))
79345 	if (!is_symbol(car(args)))
79346 	  return(s7_error(sc, sc->syntax_error_symbol,                /* (define-macro (mac 1) ...) */
79347 			  set_elist_3(sc, wrap_string(sc, "~A parameter name, ~A, is not a symbol", 38), caller, car(args))));
79348       check_lambda_args(sc, car(sc->code), NULL);
79349     }
79350   else set_car(sc->code, check_lambda_star_args(sc, car(sc->code), NULL));
79351   return(sc->code);
79352 }
79353 
79354 static bool op_define_macro(s7_scheme *sc)
79355 {
79356   sc->code = cdr(sc->code);
79357   check_define_macro(sc, sc->cur_op);
79358   if ((is_immutable(sc->curlet)) &&
79359       (is_let(sc->curlet))) /* not () */
79360     eval_error(sc, "define-macro ~S: let is immutable", 33, caar(sc->code)); /* need eval_error_any_with_caller? */
79361   sc->value = make_macro(sc, sc->cur_op, false);
79362   return(true);
79363 }
79364 
79365 static bool op_macro(s7_scheme *sc) /* (macro (x) `(+ ,x 1)) */
79366 {
79367   sc->code = cdr(sc->code);
79368   if ((!is_pair(sc->code)) || (!mac_is_ok(sc->code))) /* (macro)? or (macro . #\a)? */
79369     {
79370       check_macro(sc, sc->cur_op);
79371       if (is_pair(sc->code)) set_mac_is_ok(sc->code);
79372     }
79373   sc->value = make_macro(sc, sc->cur_op, true);
79374   return(true);
79375 }
79376 
79377 static inline bool op_macro_d(s7_scheme *sc)
79378 {
79379   sc->value = lookup(sc, car(sc->code));
79380   if (!is_macro(sc->value))   /* for-each (etc) called a macro before, now it's something else -- a very rare case */
79381     {
79382       set_unsafe_optimize_op(sc->code, OP_PAIR_SYM); /* or op_unknown* based on args? */
79383       return(true);
79384     }
79385   sc->args = copy_proper_list(sc, cdr(sc->code));
79386   sc->code = sc->value;                       /* the macro */
79387   push_stack_op_let(sc, OP_EVAL_MACRO);
79388   sc->curlet = make_let(sc, closure_let(sc->code));
79389   return(false);
79390 }
79391 
79392 static void apply_macro_star_1(s7_scheme *sc);
79393 
79394 static bool op_macro_star_d(s7_scheme *sc)
79395 {
79396   sc->value = lookup(sc, car(sc->code));
79397   if (!is_macro_star(sc->value))
79398     {
79399       set_unsafe_optimize_op(sc->code, OP_PAIR_SYM);
79400       return(true);
79401     }
79402   sc->args = copy_proper_list(sc, cdr(sc->code));
79403   sc->code = sc->value;
79404   push_stack_op_let(sc, OP_EVAL_MACRO);
79405   sc->curlet = make_let(sc, closure_let(sc->code));
79406   apply_macro_star_1(sc);
79407   return(false);
79408 }
79409 
79410 static void transfer_macro_info(s7_scheme *sc, s7_pointer mac)
79411 {
79412   s7_pointer body;
79413   body = closure_body(mac);
79414   if (has_pair_macro(mac))
79415     {
79416       set_maclet(sc->curlet);
79417       funclet_set_function(sc->curlet, pair_macro(body));
79418     }
79419   if (has_location(body))
79420     {
79421       let_set_file(sc->curlet, pair_file_number(body));
79422       let_set_line(sc->curlet, pair_line_number(body));
79423       set_has_let_file(sc->curlet);
79424     }
79425 }
79426 
79427 static goto_t op_expansion(s7_scheme *sc)
79428 {
79429   int64_t loc;
79430   s7_pointer caller;
79431 
79432   /* read-time macro expansion:
79433    *   (define-macro (hi a) (format #t "hi...") `(+ ,a 1))
79434    *   (define (ho b) (+ 1 (hi b)))
79435    * here sc->value is: (ho b), (hi b), (+ 1 (hi b)), (define (ho b) (+ 1 (hi b)))
79436    * but... first we can't tell for sure at this point that "hi" really is a macro
79437    *   (letrec ((hi ... (hi...))) will be confused about the second hi,
79438    *   or (call/cc (lambda (hi) (hi 1))) etc.
79439    * second, figuring out that we're quoted is not easy -- we have to march all the
79440    * way to the bottom of the stack looking for op_read_quote or op_read_vector
79441    *    #(((hi)) 2) or '(((hi)))
79442    * or op_read_list with args not equal (quote) or (macroexpand)
79443    *    '(hi 3) or (macroexpand (hi 3) or (quote (hi 3))
79444    * and those are only the problems I noticed!
79445    *
79446    * The hardest of these problems involve shadowing, so Rick asked for "define-expansion"
79447    *   which is like define-macro, but the programmer guarantees that the macro
79448    *   name will not be shadowed.
79449    *
79450    * to make expansion recognition fast here, define-expansion sets the T_EXPANSION
79451    *   bit in the symbol as well as the value:
79452    *   set_full_type(sc->code, T_EXPANSION | T_SYMBOL)
79453    * but this can lead to confusion because the expansion name is now globally identified as an expansion.
79454    *    (let () (define-expansion (ex1 a) `(+ ,a 1)) (display (ex1 3)))
79455    *    (define (ex1 b) (* b 2)) (display (ex1 3))
79456    * since this happens at the top level, the first line is evaluated, ex1 becomes an expansion.
79457    * but the reader has no idea about lets and whatnot, so in the second line, ex1 is still an expansion
79458    * to the reader, so it sees (define (+ b 1) ...) -- error!  To support tail-calls, there's no
79459    * way in eval to see the let close, so we can't clear the expansion flag when the let is done.
79460    * But we don't want define-expansion to mimic define-constant (via T_IMMUTABLE) because programs
79461    * like lint need to cancel reader-cond (for example).  So, we allow an expansion to be redefined,
79462    * and check here that the expander symbol still refers to an expansion.
79463    *
79464    * but in (define (ex1 b) b), the reader doesn't know we're in a define call (or it would be
79465    *   a bother to notice), so to redefine an expansion, first (set! ex1 #f) or (define ex1 #f),
79466    *   then (define (ex1 b) b).
79467    *
79468    * This is a mess!  Maybe we should insist that expansions are always global.
79469    *
79470    * run-time expansion and splicing into the code as in CL won't work in s7 because macros
79471    *   are first-class objects.  For example (define (f m) (m 1)), call it with a macro, say `(+ ,arg 1),
79472    *   and in CL-style, you'd now have f with the body (+ 1 1) or maybe even 2, now call f with a function,
79473    *   or some other macro -- oops!
79474    */
79475 
79476   loc = current_stack_top(sc) - 1;
79477   caller = (is_pair(stack_args(sc->stack, loc))) ? car(stack_args(sc->stack, loc)) : sc->F; /* this can be garbage */
79478 
79479   if ((loc >= 3) &&
79480       (stack_op(sc->stack, loc) != OP_READ_QUOTE) &&        /* '(expansion ...) */
79481       (stack_op(sc->stack, loc) != OP_READ_VECTOR) &&       /* #(expansion ...) */
79482       (caller != sc->quote_symbol) &&                       /* (quote (expansion ...)) */
79483       (caller != sc->macroexpand_symbol) &&                 /* (macroexpand (expansion ...)) */
79484       (caller != sc->define_expansion_symbol) &&            /* (define-expansion ...) being reloaded/redefined */
79485       (caller != sc->define_expansion_star_symbol))         /* (define-expansion* ...) being reloaded/redefined */
79486     {
79487       s7_pointer symbol, slot;
79488       /* we're playing fast and loose with sc->curlet in the reader, so here we need a disaster check */
79489 #if S7_DEBUGGING
79490       if (unchecked_type(sc->curlet) != T_LET) sc->curlet = sc->nil;
79491 #else
79492       if (!is_let(sc->curlet)) sc->curlet = sc->nil;
79493 #endif
79494       symbol = car(sc->value);
79495 
79496       if ((symbol_id(symbol) == 0) ||
79497 	  (sc->curlet == sc->nil))
79498 	slot = global_slot(symbol);
79499       else slot = lookup_slot_from(symbol, sc->curlet);
79500 
79501       sc->code = (is_slot(slot)) ? slot_value(slot) : sc->undefined;
79502       if ((!is_either_macro(sc->code)) || (!is_expansion(sc->code)))
79503 	clear_expansion(symbol);
79504       else
79505 	{
79506 	  /* call the reader macro */
79507 	  sc->args = copy_proper_list(sc, cdr(sc->value));
79508 	  push_stack_no_code(sc, OP_EXPANSION, sc->nil);
79509 	  sc->curlet = make_let(sc, closure_let(sc->code));
79510 	  transfer_macro_info(sc, sc->code);
79511 	  if (!is_macro_star(sc->code))
79512 	    return(goto_apply_lambda);
79513 	  apply_macro_star_1(sc);
79514 	  return(goto_begin);
79515 	  /* bacros don't seem to make sense here -- they are tied to the run-time environment,
79516 	   *   procedures would need to evaluate their arguments in rootlet
79517 	   */
79518 	}}
79519   return(fall_through);
79520 }
79521 
79522 static void macroexpand_c_macro(s7_scheme *sc) /* callgrind shows this when it's actually calling apply_c_function (code is identical) */
79523 {
79524   s7_int len;
79525   len = proper_list_length(sc->args);
79526   if (len < c_macro_required_args(sc->code))
79527     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, not_enough_arguments_string, sc->code, sc->args));
79528   if (c_macro_all_args(sc->code) < len)
79529     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, sc->code, sc->args));
79530   sc->value = c_macro_call(sc->code)(sc, sc->args);
79531 }
79532 
79533 static goto_t macroexpand(s7_scheme *sc)
79534 {
79535   switch (type(sc->code))
79536     {
79537     case T_MACRO:
79538       sc->curlet = make_let(sc, closure_let(sc->code));
79539       return(goto_apply_lambda);
79540 
79541     case T_BACRO:
79542       sc->curlet = make_let(sc, sc->curlet);
79543       return(goto_apply_lambda);
79544 
79545     case T_MACRO_STAR:
79546       sc->curlet = make_let(sc, closure_let(sc->code));
79547       apply_macro_star_1(sc);
79548       return(goto_begin);
79549 
79550     case T_BACRO_STAR:
79551       sc->curlet = make_let(sc, sc->curlet);
79552       apply_macro_star_1(sc);
79553       return(goto_begin);
79554 
79555     case T_C_MACRO:
79556       macroexpand_c_macro(sc);
79557       return(goto_start);
79558 
79559     default:
79560       eval_error(sc, "macroexpand argument is not a macro call: ~A", 44, sc->args);
79561     }
79562   return(fall_through); /* for the compiler */
79563 }
79564 
79565 static goto_t op_macroexpand(s7_scheme *sc)
79566 {
79567   s7_pointer form;
79568   form = sc->code;
79569   sc->code = cdr(sc->code);
79570   /* mimic APPLY, but don't push OP_EVAL_MACRO or OP_EXPANSION
79571    *   (define-macro (mac a) `(+ ,a 1)) (macroexpand (mac 3)), sc->code: ((mac 3))
79572    */
79573   if ((!is_pair(sc->code)) ||
79574       (!is_pair(car(sc->code))))
79575     eval_error(sc, "macroexpand argument is not a macro call: ~A", 44, form);
79576   if (!is_null(cdr(sc->code)))
79577     eval_error(sc, "macroexpand: too many arguments: ~A", 35, form);
79578 
79579   if (is_pair(caar(sc->code)))                            /* (macroexpand ((symbol->value 'mac) (+ 1 2))) */
79580     {
79581       push_stack_no_args_direct(sc, OP_MACROEXPAND_1);
79582       sc->code = caar(sc->code);
79583       return(goto_eval);
79584     }
79585 
79586   sc->args = copy_proper_list(sc, cdar(sc->code));        /* apply_lambda reuses args as slots, and these have not been copied yet */
79587   if (!is_symbol(caar(sc->code)))
79588     {
79589       if (is_any_macro(caar(sc->code)))
79590 	{
79591 	  sc->code = caar(sc->code);
79592 	  return(macroexpand(sc));
79593 	}
79594       eval_error(sc, "macroexpand argument is not a macro call: ~A", 44, sc->code);
79595     }
79596   sc->code = lookup_checked(sc, caar(sc->code));
79597   return(macroexpand(sc));
79598 }
79599 
79600 static goto_t op_macroexpand_1(s7_scheme *sc)
79601 {
79602   sc->args = copy_proper_list(sc, cdar(sc->code));
79603   sc->code = sc->value;
79604   return(macroexpand(sc));
79605 }
79606 
79607 static void op_eval_macro(s7_scheme *sc) /* after (scheme-side) macroexpansion, evaluate the resulting expression */
79608 {
79609   /* (define-macro (hi a) `(+ ,a 1))
79610    * (hi 2)
79611    * here with value: (+ 2 1)
79612    */
79613   if (is_multiple_value(sc->value))
79614     {
79615       /* a normal macro's result is evaluated (below) and its value replaces the macro invocation,
79616        *   so if a macro returns multiple values, evaluate each one, then replace the macro
79617        *   invocation with (apply values evaluated-results-in-a-list).  We need to save the
79618        *   new list of results, and where we are in the macro's output list, so code=macro output,
79619        *   args=new list.  If it returns (values), should we use #<unspecified>?  I think that
79620        *   happens now without generating a multiple_value object:
79621        *       (define-macro (hi) (values)) (hi) -> #<unspecified>
79622        *   (define-macro (ho) (values '(+ 1 2) '(* 3 4))) (+ 1 (ho) 3) -> 19
79623        *   (define-macro (ha) (values '(define a 1) '(define b 2))) (let () (ha) (+ a b)) -> 3
79624        */
79625       push_stack(sc, OP_EVAL_MACRO_MV, sc->nil, cdr(sc->value));
79626       sc->code = car(sc->value);
79627     }
79628   else sc->code = sc->value;
79629 }
79630 
79631 static bool op_eval_macro_mv(s7_scheme *sc)
79632 {
79633   if (is_null(sc->code)) /* end of values list */
79634     {
79635       sc->value = splice_in_values(sc, multiple_value(proper_list_reverse_in_place(sc, cons(sc, sc->value, sc->args))));
79636       return(true);
79637     }
79638   push_stack(sc, OP_EVAL_MACRO_MV, cons(sc, sc->value, sc->args), cdr(sc->code));
79639   sc->code = car(sc->code);
79640   return(false);
79641 }
79642 
79643 static void op_finish_expansion(s7_scheme *sc)
79644 {
79645   /* after the expander has finished, if a list was returned, we need to add some annotations.
79646    *   if the expander returned (values), the list-in-progress vanishes! (This mimics map and *#readers*).
79647    */
79648   if (sc->value == sc->no_value)
79649     sc->stack_end[-1] = (s7_pointer)OP_READ_NEXT;
79650   else
79651     if (is_pair(sc->value))
79652       sc->value = copy_body(sc, sc->value);
79653 }
79654 
79655 
79656 /* -------------------------------- with-let -------------------------------- */
79657 static void check_with_let(s7_scheme *sc)
79658 {
79659   s7_pointer form;
79660   form = cdr(sc->code);
79661 
79662   if (!is_pair(form))                            /* (with-let . "hi") */
79663     eval_error(sc, "with-let takes an environment argument: ~A", 42, sc->code);
79664   if (!is_pair(cdr(form)))                       /* (with-let e) -> an error? */
79665     eval_error(sc, "with-let body is messed up: ~A", 30, sc->code);
79666   if (!s7_is_proper_list(sc, cdr(form)))         /* (with-let e . 3) */
79667     eval_error(sc, "stray dot in with-let body: ~S", 30, sc->code);
79668 
79669   if ((is_pair(car(form))) &&
79670       (caar(form) == sc->unlet_symbol) &&        /* a constant, (with-let (unlet) ...) */
79671       (is_null(cdar(form))) &&
79672       (is_symbol(cadr(form))) &&
79673       (is_null(cddr(form))))                     /* (with-let (unlet) symbol) */
79674     pair_set_syntax_op(sc->code, OP_WITH_UNLET_S);
79675   else
79676     {
79677       if (is_symbol(car(form)))
79678 	pair_set_syntax_op(sc->code, OP_WITH_LET_S);
79679       else pair_set_syntax_op(sc->code, OP_WITH_LET_UNCHECKED);
79680     }
79681 }
79682 
79683 static bool op_with_let_unchecked(s7_scheme *sc)
79684 {
79685   sc->code = cdr(sc->code);
79686   sc->value = car(sc->code);
79687   if (!is_pair(sc->value))
79688     {
79689       if (is_symbol(sc->value))
79690 	sc->value = lookup_checked(sc, sc->value);
79691       sc->code = cdr(sc->code);
79692       return(false);
79693     }
79694   push_stack_no_args(sc, OP_WITH_LET1, cdr(sc->code));
79695   sc->code = sc->value;   /* eval let arg */
79696   return(true);
79697 }
79698 
79699 static inline bool op_with_let_s(s7_scheme *sc)
79700 {
79701   s7_pointer e;
79702   sc->code = cdr(sc->code);
79703   e = lookup_checked(sc, car(sc->code));
79704   if ((!is_let(e)) && (e != sc->rootlet))
79705     eval_error_any(sc, sc->wrong_type_arg_symbol, "with-let takes an environment argument: ~A", 42, e);
79706   if ((is_null(cddr(sc->code))) &&
79707       (is_symbol(cadr(sc->code))))
79708     {
79709       sc->value = s7_let_ref(sc, e, cadr(sc->code)); /* (with-let e s) -> (let-ref e s) */
79710       return(false);
79711     }
79712   if (e == sc->rootlet)
79713     sc->curlet = sc->nil;
79714   else
79715     {
79716       set_with_let_let(e);
79717       let_set_id(e, ++sc->let_number);
79718       sc->curlet = e;
79719       update_symbol_ids(sc, e);
79720     }
79721   sc->code = T_Pair(cdr(sc->code));
79722   return(true);
79723 }
79724 
79725 static s7_pointer with_unlet_s(s7_scheme *sc)
79726 {
79727   s7_pointer sym;
79728   sym = caddr(sc->code);
79729   if (is_slot(initial_slot(sym)))
79730     return(initial_value(sym));
79731   return(lookup(sc, sym));
79732 }
79733 
79734 
79735 /* -------------------------------- cond -------------------------------- */
79736 static void check_cond(s7_scheme *sc)
79737 {
79738   bool has_feed_to = false, result_fx = true, result_single = true;
79739   s7_pointer x, code, form;
79740 
79741   form = sc->code;
79742   code = cdr(form);
79743 
79744   if (!is_pair(code))                                             /* (cond) or (cond . 1) */
79745     eval_error(sc, "cond, but no body: ~A", 21, form);
79746 
79747   for (x = code; is_pair(x); x = cdr(x))
79748     {
79749       if (!is_pair(car(x)))                                       /* (cond 1) or (cond (#t 1) 3) */
79750 	eval_error(sc, "every clause in cond must be a list: ~A", 39, car(x));
79751       else
79752 	{
79753 	  s7_pointer y;
79754 	  y = car(x);
79755 	  if (!s7_is_proper_list(sc, cdr(y)))
79756 	    eval_error(sc, "stray dot? ~A", 13, y);
79757 	  if (is_pair(cdr(y)))
79758 	    {
79759 	      if (is_pair(cddr(y))) result_single = false;
79760 	      if ((cadr(y) == sc->feed_to_symbol) &&
79761 		  (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
79762 		{
79763 		  has_feed_to = true;
79764 		  if (!is_pair(cddr(y)))                         /* (cond (#t =>)) or (cond (#t => . 1)) */
79765 		    eval_error(sc, "cond: '=>' target missing?  ~A", 30, x);
79766 		  if (is_pair(cdddr(y)))                         /* (cond (1 => + abs)) */
79767 		    eval_error(sc, "cond: '=>' has too many targets: ~A", 35, x);
79768 		}}
79769 	  else result_single = false;
79770 	}}
79771   if (is_not_null(x))                                            /* (cond ((1 2)) . 1) */
79772     eval_error(sc, "cond: stray dot? ~A", 19, form);
79773 
79774   for (x = code; is_pair(x); x = cdr(x))
79775     {
79776       s7_pointer p;
79777       p = car(x);
79778       if (is_fxable(sc, car(p)))
79779 	fx_annotate_arg(sc, p, sc->curlet);
79780       for (p = cdr(p); is_pair(p); p = cdr(p))
79781 	if (!has_fx(p))
79782 	  {
79783 	    s7_function f;
79784 	    f = fx_choose(sc, p, sc->curlet, let_symbol_is_safe);
79785 	    if (f) set_fx_direct(p, f); else result_fx = false;
79786 	  }}
79787 
79788   if (has_feed_to)
79789     {
79790       pair_set_syntax_op(form, OP_COND_UNCHECKED);
79791       if (is_null(cdr(code)))
79792 	{
79793 	  s7_pointer expr, f;
79794 	  expr = car(code);
79795 	  f = caddr(expr);
79796 	  if ((is_proper_list_3(sc, f)) &&
79797 	      (car(f) == sc->lambda_symbol))
79798 	    {
79799 	      s7_pointer arg;
79800 	      arg = cadr(f);
79801 	      if ((is_pair(arg)) &&
79802 		  (is_null(cdr(arg))) &&
79803 		  (is_symbol(car(arg))))
79804 		{
79805 		  /* (define (hi) (cond (#t => (lambda (s) s)))) */
79806 		  set_opt2_lambda(code, caddar(code));  /* (lambda ...) above */
79807 		  pair_set_syntax_op(form, OP_COND_FEED);
79808 		}}}}
79809   else
79810     {
79811       s7_pointer p;
79812       bool xopt = true;
79813       int32_t i;
79814 
79815       pair_set_syntax_op(form, OP_COND_SIMPLE);
79816 
79817       for (i = 0, p = code; xopt && (is_pair(p)); i++, p = cdr(p))
79818 	xopt = ((has_fx(car(p))) && (is_pair(cdar(p))));
79819       if (xopt)
79820 	{
79821 	  pair_set_syntax_op(form, (result_fx) ? OP_COND_FX_FX : ((result_single) ? OP_COND_FX_FP_O : OP_COND_FX_FP));
79822           if (result_single)
79823 	    {
79824 	      if (i == 2)
79825 		{
79826 		  p = caadr(code);
79827 		  if ((p == sc->else_symbol) ||
79828 		      (p == sc->T))
79829 		    pair_set_syntax_op(form, OP_COND_FX_2E);
79830 		}
79831 	      else
79832 		if (i == 3)
79833 		  {
79834 		    p = caaddr(code);
79835 		    if ((p == sc->else_symbol) ||
79836 			(p == sc->T))
79837 		      pair_set_syntax_op(form, OP_COND_FX_3E);
79838 		  }}}
79839       else
79840 	if (result_single)
79841 	  pair_set_syntax_op(form, OP_COND_SIMPLE_O);
79842     }
79843   set_opt3_any(code, caar(code));
79844 }
79845 
79846 static bool op_cond_unchecked(s7_scheme *sc)
79847 {
79848   sc->code = cdr(sc->code);
79849   if (has_fx(car(sc->code)))
79850     {
79851       sc->value = fx_call(sc, car(sc->code)); /* false -> fall through into cond1 */
79852       return(false);
79853     }
79854   push_stack_no_args_direct(sc, OP_COND1);    /* true -> push cond1, goto eval */
79855   sc->code = opt3_any(sc->code);              /* caar */
79856   return(true);
79857 }
79858 
79859 static bool op_cond_simple(s7_scheme *sc)  /* no => */
79860 {
79861   sc->code = cdr(sc->code);
79862   if (has_fx(car(sc->code)))
79863     {
79864       sc->value = fx_call(sc, car(sc->code));
79865       return(false);
79866     }
79867   push_stack_no_args_direct(sc, OP_COND1_SIMPLE);
79868   sc->code = opt3_any(sc->code);  /* caar */
79869   return(true);
79870 }
79871 
79872 static bool op_cond_simple_o(s7_scheme *sc)  /* no =>, no null or multiform consequent */
79873 {
79874   sc->code = cdr(sc->code);
79875   if (has_fx(car(sc->code)))
79876     {
79877       sc->value = fx_call(sc, car(sc->code));
79878       return(false);
79879     }
79880   push_stack_no_args_direct(sc, OP_COND1_SIMPLE_O);
79881   sc->code = opt3_any(sc->code);  /* caar */
79882   return(true);
79883 }
79884 
79885 static bool op_cond1(s7_scheme *sc)
79886 {
79887   while (true)
79888     {
79889       if (is_true(sc, sc->value)) /* test is true, so evaluate result */
79890 	{
79891 	  sc->code = cdar(sc->code);
79892 	  if (is_pair(sc->code))
79893 	    {
79894 	      if (is_null(cdr(sc->code)))
79895 		{
79896 		  if (has_fx(sc->code))
79897 		    {
79898 		      sc->value = fx_call(sc, sc->code);
79899 		      pop_stack(sc);
79900 		      return(true); /* goto top_no_pop */
79901 		    }
79902 		  sc->code = car(sc->code);
79903 		  sc->cur_op = optimize_op(sc->code);
79904 		  return(true);
79905 		}
79906 	      /* check_cond catches stray dots */
79907 	      if ((car(sc->code) == sc->feed_to_symbol) &&
79908 		  (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
79909 		return(false);
79910 	      if (has_fx(sc->code))
79911 		{
79912 		  sc->value = fx_call(sc, sc->code);
79913 		  sc->code = cdr(sc->code);
79914 		  if (is_pair(cdr(sc->code)))
79915 		    push_stack_no_args(sc, sc->begin_op, cdr(sc->code));
79916 		}
79917 	      else push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(sc->code)));
79918 	      sc->code = car(sc->code);
79919 	      sc->cur_op = optimize_op(sc->code);
79920 	      return(true);
79921 	    }
79922 	  /* sc->code is () */
79923 	  if (is_multiple_value(sc->value))                             /* (+ 1 (cond ((values 2 3)))) */
79924 	    sc->value = splice_in_values(sc, multiple_value(sc->value));
79925 	  /* no result clause, so return test, (cond (#t)) -> #t, (cond ((+ 1 2))) -> 3 */
79926 	  pop_stack(sc);
79927 	  return(true);
79928 	}
79929       sc->code = cdr(sc->code);
79930       if (is_null(sc->code))
79931 	{
79932 	  sc->value = sc->unspecified; /* changed 31-Dec-15 */
79933 	  /* r7rs sez the value if no else clause is unspecified, and this choice makes cond consistent with if and case,
79934 	   *   and rewrite choices between the three are simpler if they are consistent.
79935 	   */
79936 	  pop_stack(sc);
79937 	  return(true);
79938 	}
79939       if (has_fx(car(sc->code)))
79940 	sc->value = fx_call(sc, car(sc->code));
79941       else
79942 	{
79943 	  push_stack_no_args_direct(sc, OP_COND1);
79944 	  sc->code = caar(sc->code);
79945 	  sc->cur_op = optimize_op(sc->code);
79946 	  return(true);
79947 	}}
79948   return(true); /* make the compiler happy */
79949 }
79950 
79951 static bool op_cond1_simple(s7_scheme *sc)
79952 {
79953   while (true)
79954     {
79955       if (is_true(sc, sc->value))
79956 	{
79957 	  sc->code = T_Lst(cdar(sc->code));
79958 	  if (is_null(sc->code))
79959 	    {
79960 	      if (is_multiple_value(sc->value))
79961 		sc->value = splice_in_values(sc, multiple_value(sc->value));
79962 	      pop_stack(sc);
79963 	      return(true);
79964 	    }
79965  	  if (has_fx(sc->code))
79966  	    {
79967  	      sc->value = fx_call(sc, sc->code);
79968 	      sc->code = cdr(sc->code);
79969 	      if (is_pair(sc->code)) return(false); /* goto begin */
79970  	      pop_stack(sc);
79971  	      return(true); /* goto top_no_pop */
79972  	    }
79973 	  return(false);
79974 	}
79975       sc->code = cdr(sc->code);
79976       if (is_null(sc->code))
79977 	{
79978 	  sc->value = sc->unspecified;
79979 	  pop_stack(sc);
79980 	  return(true);
79981 	}
79982       if (has_fx(car(sc->code)))
79983 	sc->value = fx_call(sc, car(sc->code));
79984       else
79985 	{
79986 	  push_stack_no_args_direct(sc, OP_COND1_SIMPLE);
79987 	  sc->code = caar(sc->code);
79988 	  sc->cur_op = optimize_op(sc->code);
79989 	  return(true);
79990 	}}
79991 }
79992 
79993 static bool op_cond1_simple_o(s7_scheme *sc)
79994 {
79995   while (true)
79996     {
79997       if (is_true(sc, sc->value))
79998 	{
79999  	  sc->code = cdar(sc->code);
80000  	  if (has_fx(sc->code))
80001  	    {
80002  	      sc->value = fx_call(sc, sc->code);
80003  	      return(true); /* goto start */
80004  	    }
80005  	  sc->code = car(sc->code);
80006 	  return(false);
80007 	}
80008       sc->code = cdr(sc->code);
80009       if (is_null(sc->code))
80010 	{
80011 	  sc->value = sc->unspecified;
80012 	  return(true);
80013 	}
80014       if (has_fx(car(sc->code)))
80015 	sc->value = fx_call(sc, car(sc->code));
80016       else
80017 	{
80018 	  push_stack_no_args_direct(sc, OP_COND1_SIMPLE_O);
80019 	  sc->code = caar(sc->code);
80020 	  return(false);
80021 	}}
80022 }
80023 
80024 static bool op_cond_fx_fp(s7_scheme *sc)  /* all tests are fxable, results may be a mixture, no =>, no missing results */
80025 {
80026   s7_pointer p;
80027   for (p = cdr(sc->code); is_pair(p); p = cdr(p))
80028     if (is_true(sc, fx_call(sc, car(p))))
80029       {
80030 	for (p = T_Lst(cdar(p)); is_pair(p); p = cdr(p))
80031 	  if (has_fx(T_Pair(p)))
80032 	    sc->value = fx_call(sc, p);
80033 	  else
80034 	    {
80035 	      if (is_pair(cdr(p)))
80036 		push_stack_no_args(sc, OP_COND_FX_FP_1, cdr(p));
80037 	      sc->code = car(p);
80038 	      return(false);
80039 	    }
80040 	return(true);
80041       }
80042   sc->value = sc->unspecified;
80043   return(true);
80044 }
80045 
80046 static bool op_cond_fx_fp_1(s7_scheme *sc)  /* continuing to handle a multi-statement result from cond_fx_fp */
80047 {
80048   s7_pointer p;
80049   for (p = sc->code; is_pair(p); p = cdr(p))
80050     if (has_fx(T_Pair(p)))
80051       sc->value = fx_call(sc, p);
80052     else
80053       {
80054 	if (is_pair(cdr(p)))
80055 	  push_stack_no_args(sc, OP_COND_FX_FP_1, cdr(p));
80056 	sc->code = car(p);
80057 	return(false);
80058       }
80059   return(true);
80060 }
80061 
80062 static Inline bool op_cond_fx_fp_o(s7_scheme *sc)  /* all tests are fxable, results may be a mixture, no =>, no missing results, all result one expr */
80063 {
80064   s7_pointer p;
80065   for (p = cdr(sc->code); is_pair(p); p = cdr(p))
80066     {
80067       if (is_true(sc, fx_call(sc, car(p))))
80068 	{
80069 	  p = cdar(p);
80070 	  if (has_fx(T_Pair(p)))
80071 	    {
80072 	      sc->value = fx_call(sc, p);
80073 	      return(true);
80074 	    }
80075 	  sc->code = car(p);
80076 	  return(false);
80077 	}}
80078   sc->value = sc->unspecified;
80079   return(true);
80080 }
80081 
80082 static inline bool fx_cond_value(s7_scheme *sc, s7_pointer p)
80083 {
80084   if (has_fx(p))
80085     {
80086       sc->value = fx_call(sc, p);
80087       return(true);
80088     }
80089   sc->code = car(p);
80090   return(false);
80091 }
80092 
80093 static bool op_cond_fx_2e(s7_scheme *sc)
80094 {
80095   s7_pointer p;
80096   p = cdr(sc->code);
80097   return(fx_cond_value(sc, (is_true(sc, fx_call(sc, car(p)))) ? cdar(p) : cdadr(p)));
80098 }
80099 
80100 static bool op_cond_fx_3e(s7_scheme *sc)
80101 {
80102   s7_pointer p;
80103   p = cdr(sc->code);
80104   if (is_true(sc, fx_call(sc, car(p))))
80105     return(fx_cond_value(sc, cdar(p)));
80106   p = cdr(p);
80107   return(fx_cond_value(sc, (is_true(sc, fx_call(sc, car(p)))) ? cdar(p) : cdadr(p)));
80108 }
80109 
80110 static bool op_cond_feed(s7_scheme *sc)
80111 {
80112   /* (cond (expr => p)) where p is (lambda (s) ...) -- see check_cond */
80113   sc->code = cdr(sc->code);
80114   if (has_fx(car(sc->code)))
80115     sc->value = fx_call(sc, car(sc->code));
80116   else
80117     {
80118       push_stack_no_args_direct(sc, OP_COND_FEED_1);
80119       sc->code = caar(sc->code);
80120       return(true);
80121     }
80122   return(false);
80123 }
80124 
80125 static bool op_cond_feed_1(s7_scheme *sc)
80126 {
80127   if (is_true(sc, sc->value))
80128     {
80129       if (is_multiple_value(sc->value))
80130 	sc->code = cons(sc, opt2_lambda(sc->code), multiple_value(sc->value));
80131       else
80132 	{
80133 	  sc->curlet = make_let_with_slot(sc, sc->curlet, caadr(opt2_lambda(sc->code)), sc->value);
80134 	  sc->code = caddr(opt2_lambda(sc->code));
80135 	}
80136       return(true);
80137     }
80138   sc->value = sc->unspecified; /* it's cond -- perhaps push as sc->args above; this was nil until 21-Feb-17! */
80139   return(false);
80140 }
80141 
80142 static bool feed_to(s7_scheme *sc)
80143 {
80144   if (is_multiple_value(sc->value))
80145     {
80146       sc->args = multiple_value(sc->value);
80147       clear_multiple_value(sc->args);
80148       if (is_symbol(cadr(sc->code)))
80149 	{
80150 	  sc->code = lookup_global(sc, cadr(sc->code));  /* car is => */
80151 	  return(true);
80152 	}}
80153   else
80154     {
80155       if (is_symbol(cadr(sc->code)))
80156 	{
80157 	  sc->code = lookup_global(sc, cadr(sc->code));  /* car is => */
80158 	  sc->args = (needs_copied_args(sc->code)) ? list_1(sc, sc->value) : set_plist_1(sc, sc->value);
80159 	  return(true);
80160 	}
80161       sc->args = list_1(sc, sc->value);                 /* not plist here */
80162     }
80163   push_stack_direct(sc, OP_FEED_TO_1);
80164   sc->code = cadr(sc->code);                            /* need to evaluate the target function */
80165   return(false);
80166 }
80167 
80168 
80169 /* -------------------------------- set! -------------------------------- */
80170 static void set_dilambda_opt(s7_scheme *sc, s7_pointer form, opcode_t opt, s7_pointer expr)
80171 {
80172   s7_pointer func;
80173   func = lookup_checked(sc, car(expr));
80174   if ((is_closure(func)) &&
80175       (is_closure(closure_setter(func))) &&
80176       (is_safe_closure(closure_setter(func))))
80177     {
80178       s7_pointer setter;
80179       setter = closure_setter(func);
80180       pair_set_syntax_op(form, opt);
80181       if ((!(is_let(closure_let(setter)))) ||
80182 	  (!(is_funclet(closure_let(setter)))))
80183 	make_funclet(sc, setter, car(expr), closure_let(setter));
80184     }
80185 }
80186 
80187 static inline void check_set(s7_scheme *sc)
80188 {
80189   s7_pointer form, code;
80190   form = sc->code;
80191   code = cdr(form);
80192 
80193   if (!is_pair(code))
80194     {
80195       if (is_null(code))                                             /* (set!) */
80196 	eval_error(sc, "set!: not enough arguments: ~A", 30, form);
80197       eval_error(sc, "set!: stray dot? ~A",19,  form);               /* (set! . 1) */
80198     }
80199   if (!is_pair(cdr(code)))
80200     {
80201       if (is_null(cdr(code)))                                        /* (set! var) */
80202 	eval_error(sc, "set!: not enough arguments: ~A", 30, form);
80203       eval_error(sc, "set!: stray dot? ~A", 19, form);               /* (set! var . 1) */
80204     }
80205   if (is_not_null(cddr(code)))                                       /* (set! var 1 2) */
80206     eval_error(sc, "~A: too many arguments to set!", 30, form);
80207 
80208   /* cadr (the value) has not yet been evaluated */
80209 
80210   if (is_pair(car(code)))
80211     {
80212       if ((is_pair(caar(code))) &&
80213 	  (!is_list(cdar(code))))                                   /* (set! ('(1 2) . 0) 1) */
80214 	eval_error(sc, "improper list of args to set!: ~A", 33, form);
80215       if (!s7_is_proper_list(sc, car(code)))                        /* (set! ("hi" . 1) #\a) or (set! (#(1 2) . 1) 0) */
80216 	eval_error(sc, "set! target is an improper list: (set! ~A ...)", 46, car(code));
80217     }
80218   else
80219     {
80220       if (!is_symbol(car(code)))                                    /* (set! 12345 1) */
80221 	eval_error(sc, "set! can't change ~S", 20, car(code));
80222       else
80223 	if (is_constant_symbol(sc, car(code)))                      /* (set! pi 3) */
80224 	  eval_error(sc, (is_keyword(car(code))) ? "set!: can't change keyword's value: ~S" : "set!: can't alter constant's value: ~S", 38, car(code));
80225     }
80226 
80227   if (is_pair(car(code)))
80228     {
80229       /* here we have (set! (...) ...) */
80230       s7_pointer inner, value;
80231       inner = car(code);
80232       value = cadr(code);
80233 
80234       pair_set_syntax_op(form, OP_SET_UNCHECKED);
80235       if (is_symbol(car(inner)))
80236 	{
80237 	  if ((is_null(cdr(inner))) &&
80238 	      (!is_pair(value)) &&
80239 	      (is_global(car(inner))) &&
80240 	      (is_c_function(global_value(car(inner)))) &&
80241 	      (c_function_required_args(global_value(car(inner))) == 0))
80242 	    pair_set_syntax_op(form, OP_SET_PWS);
80243 	  else
80244 	    {
80245 	      if ((is_pair(cdr(inner))) &&
80246 		  (!is_pair(cddr(inner)))) /* we check cddr(code) above */  /* this leaves (set! (vect i j) 1) unhandled so we go to OP_SET_UNCHECKED */
80247 		{
80248 		  if (!is_pair(cadr(inner)))
80249 		    {
80250 		      /* (set! (f s) ...) */
80251 		      if (!is_pair(value))
80252 			{
80253 			  pair_set_syntax_op(form, OP_SET_PAIR);
80254 			  if (is_symbol(car(inner)))
80255 			    set_dilambda_opt(sc, form, OP_SET_DILAMBDA, inner);
80256 			}
80257 		      else pair_set_syntax_op(form, OP_SET_PAIR_P);  /* splice_in_values protects us here from values */
80258 
80259 		      if (!is_fxable(sc, value))
80260 			{
80261 			  if (is_symbol(car(inner)))
80262 			    set_dilambda_opt(sc, form, OP_SET_DILAMBDA_P, inner);
80263 			}
80264 		      else
80265 			{
80266 			  s7_pointer obj;
80267 
80268 			  if ((car(inner) == sc->s7_let_symbol) &&
80269 			      (is_keyword(cadr(inner))))
80270 			    {
80271 			      pair_set_syntax_op(form, OP_IMPLICIT_S7_LET_SET_SA);
80272 			      fx_annotate_arg(sc, cdr(code), sc->curlet); /* cdr(code) -> value */
80273 			      set_opt3_sym(cdr(form), keyword_symbol(cadr(inner)));
80274 			      return;
80275 			    }
80276 
80277 			  obj = lookup_checked(sc, car(inner)); /* might be (set! (undefined-var ...)...) */
80278 			  if (((is_c_function(obj)) && (car(inner) != make_symbol(sc, c_function_name(obj)))) ||
80279 			      ((is_closure(obj)) && (car(inner) != closure_name(sc, obj))) ||
80280 			      ((!is_c_function(obj)) && (!is_closure(obj))))
80281 			    return;
80282 
80283 			  fx_annotate_arg(sc, cdr(code), sc->curlet);
80284 			  pair_set_syntax_op(form, OP_SET_PAIR_ZA);
80285 			  if ((is_c_function(obj)) &&
80286 			      (is_c_function(c_function_setter(obj))))
80287 			    pair_set_syntax_op(form, OP_SET_PAIR_A);
80288 			  else
80289 			    {
80290 			      if (is_symbol(cadr(inner)))
80291 				{
80292 				  if (!has_fx(cdr(code)))
80293 				    fx_annotate_arg(sc, cdr(code), sc->curlet);
80294 
80295 				  if ((is_closure(obj)) &&
80296 				      (is_closure(closure_setter(obj))) &&
80297 				      (is_safe_closure(closure_setter(obj))))
80298 				    {
80299 				      s7_pointer setter, body;
80300 				      setter = closure_setter(obj);
80301 				      body = closure_body(setter);
80302 				      if ((is_proper_list_1(sc, body)) &&
80303 					  ((has_fx(body)) || (is_fxable(sc, car(body)))))
80304 					{
80305 					  s7_pointer setter_args;
80306 					  if (!has_fx(body))
80307 					    {
80308 					      fx_annotate_arg(sc, body, sc->curlet);
80309 					      set_closure_one_form_fx_arg(setter);
80310 					    }
80311 					  setter_args = closure_args(setter);
80312 					  if ((is_pair(setter_args)) && (is_pair(cdr(setter_args))) && (is_null(cddr(setter_args))))
80313 					    fx_tree(sc, body, car(setter_args), cadr(setter_args));
80314 
80315 					  pair_set_syntax_op(form, OP_SET_DILAMBDA_SA_A);
80316 					  if ((!(is_let(closure_let(setter)))) || /* ?? not sure this can happen */
80317 					      (!(is_funclet(closure_let(setter)))))
80318 					    make_funclet(sc, setter, car(inner), closure_let(setter));
80319 					}}}}}}
80320 		  else /* is_pair(cadr(inner)) */
80321 		    {
80322 		      if ((caadr(inner) == sc->quote_symbol) &&
80323 			  (is_global(sc->quote_symbol)) && /* (call/cc (lambda* 'x) ... (set! (setter 'y) ...)...) should return y */
80324 			  (is_symbol(car(inner))) &&
80325 			  ((is_normal_symbol(value)) ||
80326 			   (is_fxable(sc, value))))
80327 			{
80328 			  if ((car(inner) == sc->s7_let_symbol) &&
80329 			      (is_symbol(cadadr(inner))))
80330 			    {
80331 			      pair_set_syntax_op(form, OP_IMPLICIT_S7_LET_SET_SA);
80332 			      fx_annotate_arg(sc, cdr(code), sc->curlet); /* cdr(code) -> value */
80333 			      set_opt3_sym(cdr(form), cadadr(inner));
80334 			      return;
80335 			    }
80336 			  if (is_safe_symbol(value))
80337 			    pair_set_syntax_op(form, OP_SET_LET_S);
80338 			  else
80339 			    {
80340 			      pair_set_syntax_op(form, OP_SET_LET_FX);
80341 			      set_fx(cdr(code), fx_choose(sc, cdr(code), sc->curlet, let_symbol_is_safe));
80342 			    }}}}}}
80343       return;
80344     }
80345 
80346   pair_set_syntax_op(form, OP_SET_NORMAL);
80347   if (is_symbol(car(code)))
80348     {
80349       s7_pointer settee, value;
80350       settee = car(code);
80351       value = cadr(code);
80352 
80353       if ((!symbol_has_setter(settee)) &&
80354 	  (!is_syntactic_symbol(settee)))
80355 	{
80356 	  if (is_normal_symbol(value))
80357 	    {
80358 	      if (is_slot(lookup_slot_from(value, sc->curlet)))
80359 		{
80360 		  pair_set_syntax_op(form, OP_SET_SYMBOL_S);
80361 		  set_opt2_sym(code, value);
80362 		}}
80363 	  else
80364 	    {
80365 	      if ((!is_pair(value)) ||
80366 		  ((car(value) == sc->quote_symbol) && (is_pair(cdr(value))))) /* (quote . 1) ? */
80367 		{
80368 		  pair_set_syntax_op(form, OP_SET_SYMBOL_C);
80369 		  set_opt2_con(code, (is_pair(value)) ? cadr(value) : value);
80370 		}
80371 	      else
80372 		{
80373 		  /* if cadr(cadr) == car, or cdr(cadr) not null and cadr(cadr) == car, and cddr(cadr) == null,
80374 		   *   it's (set! <var> (<op> <var> val)) or (<op> val <var>) or (<op> <var>)
80375 		   *   in the set code, we get the slot as usual, then in case 1 above,
80376 		   *   car(sc->t2_1) = slot_value(slot), car(sc->t2_2) = increment, call <op>, set slot_value(slot)
80377 		   * this can be done in all combined cases where a symbol is repeated (do in particular)
80378 		   */
80379 
80380 		  /* (define (hi) (let ((x 1)) (set! x (+ x 1))))
80381 		   *   but the value might be values:
80382 		   *   (let () (define (hi) (let ((x 0)) (set! x (values 1 2)) x)) (catch #t hi (lambda a a)) (hi))
80383 		   *   which is caught in splice_in_values
80384 		   */
80385 		  pair_set_syntax_op(form, OP_SET_SYMBOL_P);
80386 		  if (is_optimized(value))
80387 		    {
80388 		      if (optimize_op(value) == HOP_SAFE_C_D)
80389 			{
80390 			  pair_set_syntax_op(form, OP_SET_SYMBOL_A);
80391 			  fx_annotate_arg(sc, cdr(code), sc->curlet);
80392 			}
80393 		      else
80394 			{
80395 			  /* most of these special cases probably don't matter; set_symbol_opscq called 500k times barely registered in callgrind */
80396 			  if (optimize_op(value) == HOP_SAFE_C_SS)
80397 			    {
80398 			      if (settee == cadr(value))
80399 				{
80400 				  pair_set_syntax_op(form, OP_INCREMENT_SS);
80401 				  set_opt2_sym(code, caddr(value));
80402 				}
80403 			      else
80404 				{
80405 				  pair_set_syntax_op(form, OP_SET_SYMBOL_A);
80406 				  fx_annotate_arg(sc, cdr(code), sc->curlet);
80407 				}}
80408 			  else
80409 			    {
80410 			      if (is_fxable(sc, value)) /* value = cadr(code) */
80411 				{
80412 				  pair_set_syntax_op(form, OP_SET_SYMBOL_A);
80413 				  fx_annotate_arg(sc, cdr(code), sc->curlet);
80414 				}
80415 			      if ((is_safe_c_op(optimize_op(value))) &&
80416 				  (is_pair(cdr(value))) &&
80417 				  (settee == cadr(value)) &&
80418 				  (!is_null(cddr(value))))
80419 				{
80420 				  if (is_null(cdddr(value)))
80421 				    {
80422 				      if (is_fxable(sc, caddr(value)))
80423 					{
80424 					  pair_set_syntax_op(form, OP_INCREMENT_SA);
80425 					  fx_annotate_arg(sc, cddr(value), sc->curlet); /* this sets fx_proc(arg) */
80426 					  set_opt2_pair(code, cddr(value));
80427 					}
80428 				      else
80429 					{
80430 					  pair_set_syntax_op(form, OP_INCREMENT_SP);
80431 					  set_opt2_pair(code, caddr(value));
80432 					}}
80433 				  else
80434 				    if ((is_null(cddddr(value))) &&
80435 					(is_fxable(sc, caddr(value))) &&
80436 					(is_fxable(sc, cadddr(value))))
80437 				      {
80438 					pair_set_syntax_op(form, OP_INCREMENT_SAA);
80439 					fx_annotate_arg(sc, cddr(value), sc->curlet);
80440 					fx_annotate_arg(sc, cdddr(value), sc->curlet);
80441 					set_opt2_pair(code, cddr(value));
80442 				      }}}}}
80443 		  if ((is_h_optimized(value)) &&
80444 		      (!is_unsafe(value)) &&                   /* is_unsafe(value) can happen! */
80445 		      (is_not_null(cdr(value))))               /* (set! x (y)) */
80446 		    {
80447 		      if (is_not_null(cddr(value)))
80448 			{
80449 			  if ((caddr(value) == int_one) &&
80450 			      (cadr(value) == settee))
80451 			    {
80452 			      if (opt1_cfunc(value) == sc->add_x1)
80453 				pair_set_syntax_op(form, OP_INCREMENT_BY_1);
80454 			      else
80455 				if (opt1_cfunc(value) == sc->subtract_x1)
80456 				  pair_set_syntax_op(form, OP_DECREMENT_BY_1);
80457 			    }
80458 			  else
80459 			    {
80460 			      if ((cadr(value) == int_one) &&
80461 				  (caddr(value) == settee) &&
80462 				  (opt1_cfunc(value) == sc->add_1x))
80463 				pair_set_syntax_op(form, OP_INCREMENT_BY_1);
80464 			      else
80465 				if ((settee == caddr(value)) &&
80466 				    (is_safe_symbol(cadr(value))) &&
80467 				    (caadr(code) == sc->cons_symbol))
80468 				  {
80469 				    pair_set_syntax_op(form, OP_SET_CONS);
80470 				    set_opt2_sym(code, cadr(value));
80471 				  }}}}}}}}
80472 }
80473 
80474 static void op_set_symbol_c(s7_scheme *sc)
80475 {
80476   s7_pointer slot;
80477   slot = lookup_slot_from(cadr(sc->code), sc->curlet);
80478   slot_set_value(slot, sc->value = opt2_con(cdr(sc->code)));
80479 }
80480 
80481 static void op_set_symbol_s(s7_scheme *sc)
80482 {
80483   s7_pointer slot;
80484   slot = lookup_slot_from(cadr(sc->code), sc->curlet);
80485   slot_set_value(slot, sc->value = lookup(sc, opt2_sym(cdr(sc->code))));
80486 }
80487 
80488 static void op_set_symbol_a(s7_scheme *sc)
80489 {
80490   s7_pointer slot;
80491   slot = lookup_slot_from(cadr(sc->code), sc->curlet);
80492   slot_set_value(slot, sc->value = fx_call(sc, cddr(sc->code)));
80493 }
80494 
80495 static inline void op_set_cons(s7_scheme *sc)
80496 {
80497   s7_pointer slot;
80498   slot = lookup_slot_from(cadr(sc->code), sc->curlet);
80499   slot_set_value(slot, sc->value = cons(sc, lookup(sc, opt2_sym(cdr(sc->code))), slot_value(slot)));  /* ([set!] bindings (cons v bindings)) */
80500 }
80501 
80502 static void op_increment_ss(s7_scheme *sc)
80503 {
80504   s7_pointer slot;
80505   sc->code = cdr(sc->code);
80506   slot = lookup_slot_from(car(sc->code), sc->curlet);
80507   set_car(sc->t2_1, slot_value(slot));
80508   set_car(sc->t2_2, lookup(sc, opt2_sym(sc->code)));
80509   slot_set_value(slot, sc->value = fn_proc(cadr(sc->code))(sc, sc->t2_1));
80510 }
80511 
80512 static void op_increment_saa(s7_scheme *sc)
80513 {
80514   s7_pointer slot, arg, val;
80515   sc->code = cdr(sc->code);
80516   slot = lookup_slot_from(car(sc->code), sc->curlet);
80517   arg = opt2_pair(sc->code);               /* cddr(value) */
80518   val = fx_call(sc, cdr(arg));
80519   set_car(sc->t3_2, fx_call(sc, arg));
80520   set_car(sc->t3_3, val);
80521   set_car(sc->t3_1, slot_value(slot));
80522   slot_set_value(slot, sc->value = fn_proc(cadr(sc->code))(sc, sc->t3_1));
80523 }
80524 
80525 static void op_increment_sa(s7_scheme *sc)
80526 {
80527   s7_pointer slot, arg;
80528   sc->code = cdr(sc->code);
80529   slot = lookup_slot_from(car(sc->code), sc->curlet);
80530   arg = opt2_pair(sc->code);
80531   set_car(sc->t2_2, fx_call(sc, arg));
80532   set_car(sc->t2_1, slot_value(slot));
80533   slot_set_value(slot, sc->value = fn_proc(cadr(sc->code))(sc, sc->t2_1));
80534 }
80535 
80536 static inline void op_set_pair_a(s7_scheme *sc)
80537 {
80538   s7_pointer obj, setter, code;
80539   code = cdr(sc->code);
80540   obj = lookup_checked(sc, caar(code));
80541   setter = c_function_setter(obj);
80542   obj = fx_call(sc, cdr(code));
80543   set_car(sc->t2_1, cadar(code));              /* might be a constant: (set! (mus-sound-srate "oboe.snd") 12345) */
80544   if (is_symbol(car(sc->t2_1)))
80545     set_car(sc->t2_1, lookup_checked(sc, cadar(code)));
80546   set_car(sc->t2_2, obj);
80547   sc->value = c_function_call(setter)(sc, sc->t2_1);
80548 }
80549 
80550 static void op_set_pair_p(s7_scheme *sc)
80551 {
80552   /* ([set!] (car a) (cadr a)) */
80553   /* here the pair can't generate multiple values, or if it does, it's an error (caught below)
80554    *  splice_in_values will notice the OP_SET_PAIR_P_1 and complain.
80555    * (let () (define (hi) (let ((str "123")) (set! (str 0) (values #\a)) str)) (hi) (hi)) is "a23"
80556    * (let () (define (hi) (let ((str "123")) (set! (str 0) (values #\a #\b)) str)) (hi) (hi)) is an error from the first call (caught elsewhere)
80557    * (let () (define (hi) (let ((str "123")) (set! (str 0) (values #\a #\b)) str)) (catch #t hi (lambda a a)) (hi)) is an error from the second call
80558    * (let ((v (make-vector '(2 3) 0))) (set! (v (values 0 1)) 23) v) -> #2D((0 23 0) (0 0 0))
80559    */
80560   push_stack_no_args(sc, OP_SET_PAIR_P_1, cdr(sc->code));
80561   sc->code = caddr(sc->code);
80562 }
80563 
80564 static bool set_pair_p_3(s7_scheme *sc, s7_pointer obj, s7_pointer arg, s7_pointer value)
80565 {
80566   if (is_slot(obj))
80567     obj = slot_value(obj);
80568   else s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(sc->code), sc->prepackaged_type_names[type(obj)]));
80569 
80570   switch (type(obj))
80571     {
80572     case T_C_OBJECT:
80573       set_car(sc->t3_1, obj);
80574       set_car(sc->t3_2, arg);
80575       set_car(sc->t3_3, value);
80576       sc->value = (*(c_object_set(sc, obj)))(sc, sc->t3_1);
80577       break;
80578 
80579       /* some of these are wasteful -- we know the object type! (list hash-table) */
80580     case T_INT_VECTOR:
80581     case T_FLOAT_VECTOR:
80582     case T_VECTOR:
80583     case T_BYTE_VECTOR:
80584 #if WITH_GMP
80585       set_car(sc->t3_1, obj);
80586       set_car(sc->t3_2, arg);
80587       set_car(sc->t3_3, value);
80588       sc->value = g_vector_set(sc, sc->t3_1);
80589 #else
80590       if (vector_rank(obj) > 1)
80591 	{
80592 	  set_car(sc->t3_1, obj);
80593 	  set_car(sc->t3_2, arg);
80594 	  set_car(sc->t3_3, value);
80595 	  sc->value = g_vector_set(sc, sc->t3_1);
80596 	}
80597       else
80598 	{
80599 	  s7_int index;
80600 
80601 	  if (!is_t_integer(arg))
80602 	    eval_error_any(sc, sc->wrong_type_arg_symbol, "vector-set!: index must be an integer: ~S", 41, sc->code);
80603 	  index = integer(arg);
80604 	  if (index < 0)
80605 	    eval_error_any(sc, sc->out_of_range_symbol, "vector-set!: index must not be negative: ~S", 43, sc->code);
80606 	  if (index >= vector_length(obj))
80607 	    eval_error_any(sc, sc->out_of_range_symbol, "vector-set!: index must be less than vector length: ~S", 54, sc->code);
80608 	  if (is_immutable(obj))
80609 	    immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->vector_set_symbol, obj));
80610 	  if (is_typed_vector(obj))
80611 	    {
80612 	      if ((sc->safety < NO_SAFETY) || /* or == NO_SAFETY?? */
80613 		  (typed_vector_typer_call(sc, obj, set_plist_1(sc, value)) != sc->F))
80614 		vector_element(obj, index) = value;
80615 	      else return(s7_wrong_type_arg_error(sc, "vector-set!", 3, value, make_type_name(sc, typed_vector_typer_name(sc, obj), INDEFINITE_ARTICLE)));
80616 	    }
80617 	  else vector_setter(obj)(sc, obj, index, value);
80618 	  sc->value = T_Pos(value);
80619 	}
80620 #endif
80621       break;
80622 
80623     case T_STRING:
80624 #if WITH_GMP
80625       set_car(sc->t3_1, obj);
80626       set_car(sc->t3_2, arg);
80627       set_car(sc->t3_3, value);
80628       sc->value = g_string_set(sc, sc->t3_1);
80629 #else
80630       {
80631 	s7_int index;
80632 	if (!is_t_integer(arg))
80633 	  eval_error_any(sc, sc->wrong_type_arg_symbol, "index must be an integer: ~S", 28, sc->code);
80634 	index = integer(arg);
80635 	if (index < 0)
80636 	  eval_error_any(sc, sc->out_of_range_symbol, "index must not be negative: ~S", 30, sc->code);
80637 	if (index >= string_length(obj))
80638 	  eval_error_any(sc, sc->out_of_range_symbol, "index must be less than sequence length: ~S", 43, sc->code);
80639 	if (is_immutable(obj))
80640 	  immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->string_set_symbol, obj));
80641 
80642 	if (s7_is_character(value))
80643 	  {
80644 	    string_value(obj)[index] = (char)s7_character(value);
80645 	    sc->value = value;
80646 	  }
80647 	else eval_error_any(sc, sc->wrong_type_arg_symbol, "(string-)set!: value must be a character: ~S", 44, sc->code);
80648       }
80649 #endif
80650       break;
80651 
80652     case T_PAIR:
80653       set_car(sc->t3_1, obj);
80654       set_car(sc->t3_2, arg);
80655       set_car(sc->t3_3, value);
80656       sc->value = g_list_set(sc, sc->t3_1);
80657       break;
80658 
80659     case T_HASH_TABLE:
80660       if (is_immutable(obj))
80661 	immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->hash_table_set_symbol, obj));
80662       sc->value = s7_hash_table_set(sc, obj, arg, value);
80663       break;
80664 
80665     case T_LET:
80666       sc->value = s7_let_set(sc, obj, arg, value); /* this checks immutable */
80667       break;
80668 
80669     case T_C_OPT_ARGS_FUNCTION:
80670     case T_C_RST_ARGS_FUNCTION:
80671     case T_C_ANY_ARGS_FUNCTION:                       /* (let ((lst (list 1 2))) (set! (list-ref lst 1) 2) lst) */
80672     case T_C_FUNCTION:
80673     case T_C_FUNCTION_STAR:
80674       /* obj here is a c_function, but its setter could be a closure and vice versa below */
80675       if (is_any_procedure(c_function_setter(obj)))
80676 	{
80677 	  if (is_c_function(c_function_setter(obj)))
80678 	    {
80679 	      set_car(sc->t2_1, arg);
80680 	      set_car(sc->t2_2, value);
80681 	      sc->value = c_function_call(c_function_setter(obj))(sc, sc->t2_1);
80682 	    }
80683 	  else
80684 	    {
80685 	      sc->code = c_function_setter(obj);
80686 	      sc->args = (needs_copied_args(sc->code)) ? list_2(sc, arg, value) : set_plist_2(sc, arg, value);
80687 	      return(true); /* goto APPLY; */
80688 	    }}
80689       else s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(sc->code), sc->prepackaged_type_names[type(obj)]));
80690       break;
80691 
80692     case T_MACRO:   case T_MACRO_STAR:
80693     case T_BACRO:   case T_BACRO_STAR:
80694     case T_CLOSURE: case T_CLOSURE_STAR:
80695       if (is_any_procedure(closure_setter(obj)))
80696 	{
80697 	  if (is_c_function(closure_setter(obj)))
80698 	    {
80699 	      set_car(sc->t2_1, arg);
80700 	      set_car(sc->t2_2, value);
80701 	      sc->value = c_function_call(closure_setter(obj))(sc, sc->t2_1);
80702 	    }
80703 	  else
80704 	    {
80705 	      sc->code = closure_setter(obj);
80706 	      sc->args = (needs_copied_args(sc->code)) ? list_2(sc, arg, value) : set_plist_2(sc, arg, value);
80707 	      return(true); /* goto APPLY; */
80708 	    }}
80709       else s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(sc->code), sc->prepackaged_type_names[type(obj)]));
80710       break;
80711 
80712     default:                                         /* (set! (1 2) 3) */
80713       s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(sc->code), sc->prepackaged_type_names[type(obj)]));
80714     }
80715   return(false);
80716 }
80717 
80718 static Inline bool op_set_pair_p_1(s7_scheme *sc)
80719 {
80720   /* car(sc->code) is a pair, caar(code) is the object with a setter, it has one (safe) argument, and one safe value to set
80721    *   (set! (str i) #\a) in a function (both inner things need to be symbols (or the second can be a quoted symbol) to get here)
80722    *   the inner list is a proper list, with no embedded list at car.
80723    */
80724   s7_pointer arg, value;
80725   value = sc->value;
80726   arg = cadar(sc->code);
80727   if (is_symbol(arg))
80728     arg = lookup_checked(sc, arg);
80729   else
80730     if (is_pair(arg))
80731       arg = cadr(arg); /* can only be (quote ...) in this case */
80732 
80733   return(set_pair_p_3(sc, lookup_slot_from(caar(sc->code), sc->curlet), arg, value));
80734 }
80735 
80736 static bool op_set_pair(s7_scheme *sc)
80737 {
80738   /* ([set!] (setter g) s) or ([set!] (str 0) #\a) */
80739   s7_pointer obj, arg, value;
80740   sc->code = cdr(sc->code);
80741   value = cadr(sc->code);
80742   if (is_symbol(value))
80743     value = lookup_checked(sc, value);
80744 
80745   arg = cadar(sc->code);
80746   if (is_symbol(arg))
80747     arg = lookup_checked(sc, arg);
80748   else
80749     if (is_pair(arg))
80750       arg = cadr(arg); /* can only be (quote ...) in this case */
80751 
80752   obj = caar(sc->code);
80753   if (is_symbol(obj))
80754     obj = lookup_slot_from(obj, sc->curlet);
80755   return(set_pair_p_3(sc, obj, arg, value));
80756 }
80757 
80758 static void op_set_safe(s7_scheme *sc)
80759 {
80760   s7_pointer lx;
80761   lx = lookup_slot_from(sc->code, sc->curlet);   /* SET_CASE above looks for car(sc->code) */
80762   if (is_slot(lx))
80763     slot_set_value(lx, sc->value);
80764   else unbound_variable_error(sc, sc->code);
80765 }
80766 
80767 static s7_pointer op_set1(s7_scheme *sc)
80768 {
80769   s7_pointer lx;
80770   /* if unbound variable hook here, we need the binding, not the current value */
80771   lx = lookup_slot_from(sc->code, sc->curlet);
80772   if (is_slot(lx))
80773     {
80774       if (is_immutable(lx))
80775 	immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->set_symbol, lx));
80776       if (slot_has_setter(lx))
80777 	{
80778 	  s7_pointer func;
80779 	  func = slot_setter(lx);
80780 	  if (is_c_function(func))
80781 	    sc->value = call_c_function_setter(sc, func, sc->code, sc->value);
80782 	  else
80783 	    if (is_any_procedure(func))
80784 	      {
80785 		/* don't push OP_EVAL_DONE here and call eval(sc, OP_APPLY) below -- setter might hit an error */
80786 		push_stack_no_args(sc, OP_SET_FROM_SETTER, lx);
80787 		if (has_let_arg(func))
80788 		  sc->args = list_3(sc, sc->code, sc->value, sc->curlet);
80789 		else sc->args = list_2(sc, sc->code, sc->value);   /* these lists are reused as the closure_let slots in apply_lambda via apply_closure */
80790 		sc->code = func;
80791 		return(NULL); /* goto APPLY */
80792 	      }}
80793       else
80794 	if ((is_syntactic_symbol(sc->code)) ||              /* (set! case 3) */
80795 	    ((global_slot(sc->code) == lx) &&               /* (begin (let ((case 2)) case) (set! case 3)) */
80796 	     (is_syntax(slot_value(lx))) &&
80797 	     (sc->code == syntax_symbol(slot_value(lx)))))
80798 	  eval_error(sc, "can't set! ~A", 13, sc->code);
80799       slot_set_value(lx, sc->value);
80800       symbol_increment_ctr(sc->code);                         /* see define setfib example in s7test.scm -- I'm having second thoughts about this... */
80801       return(sc->value); /* goto START */
80802     }
80803 
80804   if (has_let_set_fallback(sc->curlet))                       /* (with-let (mock-hash-table 'b 2) (set! b 3)) */
80805     return(call_let_set_fallback(sc, sc->curlet, sc->code, sc->value));
80806 
80807   return(s7_error(sc, sc->unbound_variable_symbol, set_elist_4(sc, wrap_string(sc, "~S is unbound in (set! ~S ~S)", 29), sc->code, sc->code, sc->value)));
80808 }
80809 
80810 static goto_t set_implicit(s7_scheme *sc);
80811 
80812 static goto_t op_set2(s7_scheme *sc)
80813 {
80814   if (is_pair(sc->value))
80815     {
80816       /* (let ((L '((1 2 3)))) (set! ((L 0) 1) 32) L)
80817        * (let ((L '(((1 2 3))))) (set! ((L 0) 0 1) 32) L)
80818        * any deeper nesting was handled already by the first eval
80819        *   set! looks at its first argument, if it's a symbol, it sets the associated value,
80820        *   if it's a list, it looks at the car of that list to decide which setter to call,
80821        *   if it's a list of lists, it passes the embedded lists to eval, then looks at the
80822        *   car of the result.  This means that we can do crazy things like:
80823        *   (let ((x '(1)) (y '(2))) (set! ((if #t x y) 0) 32) x)
80824        * the other args need to be evaluated (but not the list as if it were code):
80825        *   (let ((L '((1 2 3))) (index 1)) (set! ((L 0) index) 32) L)
80826        */
80827       if (!s7_is_proper_list(sc, sc->args))                              /* (set! ('(1 2) 1 . 2) 1) */
80828 	eval_error(sc, "set! target arguments are an improper list: ~A", 46, sc->args);
80829 
80830       if (is_multiple_value(sc->value)) /* this has to be at least 2 args, sc->args and sc->code make 2 more, so... */
80831 	eval_error(sc, "set!: too many arguments: ~S", 28,
80832 			     set_ulist_1(sc, sc->set_symbol, pair_append(sc, multiple_value(sc->value), pair_append(sc, sc->args, sc->code))));
80833 
80834       if (sc->args == sc->nil)
80835 	eval_error(sc, "list set!: not enough arguments: ~S", 35, sc->code);
80836 
80837       push_op_stack(sc, sc->list_set_function);
80838       sc->code = pair_append(sc, cdr(sc->args), sc->code);
80839       push_stack(sc, OP_EVAL_ARGS1, list_1(sc, sc->value), sc->code);
80840       sc->code = car(sc->args);
80841       return(goto_eval);
80842     }
80843 
80844   if (is_any_vector(sc->value))
80845     {
80846       /* (let ((L #(#(1 2 3) #(4 5 6)))) (set! ((L 1) 0) 32) L)
80847        * bad case when args is nil: (let ((L #(#(1 2 3) #(4 5 6)))) (set! ((L 1)) 32) L)
80848        */
80849       if (sc->args == sc->nil)
80850 	eval_error(sc, "vector set!: not enough arguments: ~S", 37, sc->code);
80851 
80852       push_op_stack(sc, sc->vector_set_function);
80853       sc->code = pair_append(sc, cdr(sc->args), sc->code);
80854       push_stack(sc, OP_EVAL_ARGS1, list_1(sc, sc->value), sc->code);
80855       sc->code = car(sc->args);
80856       return(goto_eval);
80857     }
80858   sc->code = cons_unchecked(sc, sc->set_symbol, cons_unchecked(sc, cons(sc, sc->value, sc->args), sc->code)); /* (let ((x 32)) (set! ((curlet) 'x) 3) x) */
80859   return(set_implicit(sc));
80860 }
80861 
80862 static bool op_set_with_let_1(s7_scheme *sc)
80863 {
80864   s7_pointer e, b, x;
80865   /* from the T_SYNTAX branch of op_set_pair: (set! (with-let e b) x) as in let-temporarily
80866    *   here sc->value is the new value for the settee = x, args has the (as yet unevaluated) let and settee-expression.
80867    *   'b above can be a pair = generalized set in the 'e environment.
80868    */
80869   if (!is_pair(sc->args))                /* (set! (with-let) ...) */
80870     eval_error(sc, "set! (with-let)? ~A", 19, current_code(sc));
80871   if (!is_pair(cdr(sc->args)))           /* (set! (with-let e) ...) */
80872     eval_error(sc, "set! (with-let ...) has no symbol to set? ~A", 44, current_code(sc));
80873   e = car(sc->args);
80874   b = cadr(sc->args);
80875   x = sc->value;
80876   if (is_symbol(e))
80877     {
80878       if (is_symbol(b))
80879 	{
80880 	  e = lookup_checked(sc, e); /* the let */
80881 	  if (!is_let(e))
80882 	    wrong_type_argument_with_type(sc, sc->let_set_symbol, 1, e, a_let_string);
80883 	  sc->value = let_set_1(sc, e, b, x);
80884 	  pop_stack(sc);
80885 	  return(true);
80886 	}
80887       sc->value = lookup_checked(sc, e);
80888       sc->code = list_3(sc, sc->set_symbol, b, ((is_symbol(x)) || (is_pair(x))) ? set_plist_2(sc, sc->quote_symbol, x) : x);
80889       /* (let* ((x (vector 1 2)) (lt (curlet))) (set! (with-let lt (x 0)) 32) x) here: (set! (x 0) 32) */
80890       return(false); /* goto SET_WITH_LET */
80891     }
80892   sc->code = e;                       /* 'e above, an expression we need to evaluate */
80893   sc->args = list_2(sc, b, x);        /* can't reuse sc->args here via set-car! etc */
80894   push_stack_direct(sc, OP_SET_WITH_LET_2);
80895   sc->cur_op = optimize_op(sc->code);
80896   return(true); /* goto top_no_pop */
80897 }
80898 
80899 static bool op_set_with_let_2(s7_scheme *sc)
80900 {
80901   s7_pointer b, x;
80902   /* here sc->value = let = 'e, args = '(b x) where 'b might be a pair */
80903   if (!is_let(sc->value))
80904     wrong_type_argument_with_type(sc, sc->let_set_symbol, 1, sc->value, a_let_string);
80905   b = car(sc->args);
80906   x = cadr(sc->args);
80907   if (is_symbol(b))   /* b is a symbol -- everything else is ready so call let-set! */
80908     {
80909       sc->value = let_set_1(sc, sc->value, b, x);
80910       return(true); /* goto START */
80911     }
80912   if ((is_symbol(x)) || (is_pair(x)))                 /* (set! (with-let (inlet :v (vector 1 2)) (v 0)) 'a) */
80913     sc->code = list_3(sc, sc->set_symbol, b, ((is_symbol(x)) || (is_pair(x))) ? set_plist_2(sc, sc->quote_symbol, x) : x);
80914   else sc->code = cons(sc, sc->set_symbol, sc->args); /* (set! (with-let (curlet) (*s7* 'print-length)) 16), x=16 b=(*s7* 'print-length) */
80915   return(false); /* fall into SET_WITH_LET */
80916 }
80917 
80918 static bool op_set_normal(s7_scheme *sc)
80919 {
80920   s7_pointer x;
80921   sc->code = cdr(sc->code);
80922   x = cadr(sc->code);
80923   if (is_pair(x))
80924     {
80925       push_stack_no_args(sc, OP_SET1, car(sc->code));
80926       sc->code = x;
80927       return(true);
80928     }
80929   sc->value = (is_symbol(x)) ? lookup_checked(sc, x) : T_Pos(x);
80930   sc->code = car(sc->code);
80931   return(false);
80932 }
80933 
80934 static void op_set_symbol_p(s7_scheme *sc)
80935 {
80936   check_stack_size(sc);
80937   push_stack_no_args(sc, OP_SET_SAFE, cadr(sc->code));
80938   sc->code = caddr(sc->code);
80939 }
80940 
80941 static void op_increment_sp(s7_scheme *sc)
80942 {
80943   s7_pointer sym;
80944   sc->code = cdr(sc->code);
80945   sym = lookup_slot_from(car(sc->code), sc->curlet);
80946   push_stack(sc, OP_INCREMENT_SP_1, sym, sc->code);
80947   sc->code = T_Pair(opt2_pair(sc->code)); /* caddadr(sc->code); */
80948 }
80949 
80950 static void op_increment_sp_1(s7_scheme *sc)
80951 {
80952   set_car(sc->t2_1, slot_value(sc->args));
80953   set_car(sc->t2_2, sc->value);
80954   sc->value = fn_proc(cadr(sc->code))(sc, sc->t2_1);
80955   slot_set_value(sc->args, sc->value);
80956 }
80957 
80958 static void op_increment_sp_mv(s7_scheme *sc)
80959 {
80960   sc->value = fn_proc(cadr(sc->code))(sc, set_ulist_1(sc, slot_value(sc->args), sc->value));
80961   set_car(sc->u1_1, sc->F);
80962   slot_set_value(sc->args, sc->value);
80963 }
80964 
80965 static goto_t op_set_dilambda_p_1(s7_scheme *sc)
80966 {
80967   s7_pointer obj, func, arg;
80968   arg = cadar(sc->code);
80969   if (is_symbol(arg))
80970     arg = lookup_checked(sc, arg);
80971   else
80972     if (is_pair(arg))
80973       arg = cadr(arg); /* can only be (quote ...) in this case */
80974 
80975   obj = lookup_slot_from(caar(sc->code), sc->curlet);
80976   func = slot_value(obj);
80977   if ((is_closure(func)) &&
80978       (is_safe_closure(closure_setter(func))))
80979     {
80980       s7_pointer setter;
80981       setter = closure_setter(func);
80982       if (is_pair(closure_args(setter)))
80983 	{
80984 	  sc->curlet = update_let_with_two_slots(sc, closure_let(setter), arg, sc->value);
80985 	  sc->code = T_Pair(closure_body(setter));
80986 	  return(goto_begin);
80987 	}}
80988   return((set_pair_p_3(sc, obj, arg, sc->value)) ? goto_apply : goto_start);
80989 }
80990 
80991 
80992 /* -------------------------------- do -------------------------------- */
80993 static bool safe_stepper_expr(s7_pointer expr, s7_pointer vars)
80994 {
80995   /* for now, just look for stepper as last element of any list
80996    *    any embedded set is handled by do_is_safe, so we don't need to descend into the depths
80997    */
80998   s7_pointer p;
80999   if (direct_memq(cadr(expr), vars))
81000     return(false);
81001 
81002   for (p = cdr(expr); is_pair(cdr(p)); p = cdr(p));
81003 
81004   if (is_pair(p))
81005     {
81006       if ((is_optimized(p)) &&
81007 	  (op_has_hop(p)) &&
81008 	  (is_safe_c_op(optimize_op(p))))
81009 	return(true);
81010 
81011       if (direct_memq(car(p), vars))
81012 	return(false);
81013     }
81014   else
81015     if (direct_memq(p, vars))
81016       return(false);
81017   return(true);
81018 }
81019 
81020 static goto_t set_implicit_c_object(s7_scheme *sc, s7_pointer cx, s7_pointer form)
81021 {
81022   s7_pointer settee, index, val;
81023 
81024   if (is_null(cdr(sc->code)))
81025     s7_wrong_number_of_args_error(sc, "no value for object-set!: ~S", form);
81026   if (!is_null(cddr(sc->code)))
81027     s7_wrong_number_of_args_error(sc, "too many values for object-set!: ~S", form);
81028 
81029   settee = car(sc->code);
81030   if ((is_null(cdr(settee))) ||
81031       (!is_null(cddr(settee))))
81032     {
81033       push_op_stack(sc, sc->c_object_set_function);
81034       if (is_null(cdr(settee)))
81035 	{
81036 	  push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cddr(sc->code));
81037 	  sc->code = cadr(sc->code);
81038 	}
81039       else
81040 	{
81041 	  sc->code = pair_append(sc, cddr(settee), cdr(sc->code));
81042 	  push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), sc->code);
81043 	  sc->code = cadr(settee);
81044 	}
81045       sc->cur_op = optimize_op(sc->code);
81046       return(goto_top_no_pop);
81047     }
81048 
81049   index = cadr(settee);
81050   if (!is_pair(index))
81051     {
81052       if (is_symbol(index))
81053 	index = lookup_checked(sc, index);
81054 
81055       val = cadr(sc->code);
81056       if (!is_pair(val))
81057 	{
81058 	  if (is_symbol(val))
81059 	    val = lookup_checked(sc, val);
81060 	  set_car(sc->t3_1, cx);
81061 	  set_car(sc->t3_2, index);
81062 	  set_car(sc->t3_3, val);
81063 	  sc->value = (*(c_object_set(sc, cx)))(sc, sc->t3_1);
81064 	  return(goto_start);
81065 	}
81066       push_op_stack(sc, sc->c_object_set_function);
81067       sc->args = list_2(sc, index, cx);
81068       sc->code = cdr(sc->code);
81069       return(goto_eval_args);
81070     }
81071   push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
81072   push_op_stack(sc, sc->c_object_set_function);
81073   sc->code = cadr(settee);
81074   sc->cur_op = optimize_op(sc->code);
81075   return(goto_top_no_pop);
81076 }
81077 
81078 static goto_t set_implicit_vector(s7_scheme *sc, s7_pointer cx, s7_pointer form)
81079 {
81080   /* cx is the vector, sc->code is expr without the set!, form is the full expr,  args have not been evaluated! */
81081 
81082   s7_pointer settee, index;
81083   s7_int argnum;
81084 
81085   if (is_null(cdr(sc->code)))     /* (set! (v 0)) */
81086     s7_wrong_number_of_args_error(sc, "no value for vector-set!: ~S", form);
81087   if (!is_null(cddr(sc->code)))   /* (set! (v 0) 1 2) */
81088     s7_wrong_number_of_args_error(sc, "too many values for vector-set!: ~S", form);
81089 
81090   settee = car(sc->code);
81091   if (is_null(cdr(settee)))
81092     s7_wrong_number_of_args_error(sc, "no index for vector-set!: ~S", form);
81093   if (is_immutable(cx))
81094     immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->vector_set_symbol, cx));
81095 
81096   argnum = proper_list_length(cdr(settee));
81097   if ((argnum > 1) &&
81098       (is_normal_vector(cx)) &&
81099       (argnum != vector_rank(cx)))
81100     {
81101       /* this block needs to be first to handle (eg):
81102        *   (let ((v (vector (inlet 'a 0)))) (set! (v 0 'a) 32) v): #((inlet 'a 32))
81103        */
81104       push_stack(sc, OP_SET2, cddr(settee), cdr(sc->code));
81105       sc->code = list_2(sc, car(settee), cadr(settee));
81106       sc->cur_op = optimize_op(sc->code);
81107       return(goto_top_no_pop);
81108     }
81109 
81110   if ((argnum > 1) || (vector_rank(cx) > 1))
81111     {
81112       if ((argnum == 2) &&
81113 	  (is_fxable(sc, cadr(settee))) &&
81114 	  (is_fxable(sc, caddr(settee))) &&
81115 	  (is_fxable(sc, cadr(sc->code))))     /* (set! (v fx fx) fx) */
81116 	{
81117 	  fx_annotate_args(sc, cdr(settee), sc->curlet);
81118 	  fx_annotate_arg(sc, cdr(sc->code), sc->curlet);
81119 	  set_opt3_pair(form, cddr(settee));
81120 	  pair_set_syntax_op(form, OP_IMPLICIT_VECTOR_SET_4);
81121 	}
81122       if ((argnum == vector_rank(cx)) &&
81123 	  (!is_pair(cadr(sc->code))))
81124 	{
81125 	  s7_pointer p;
81126 	  for (p = cdr(settee); is_pair(p); p = cdr(p))
81127 	    if (is_pair(car(p))) break;
81128 	  if (is_null(p))
81129 	    {
81130 	      s7_pointer args, pa;
81131 	      args = safe_list_if_possible(sc, argnum + 2);
81132 	      if (in_heap(args)) gc_protect_via_stack(sc, args);
81133 	      car(args) = cx;
81134 	      for (p = cdr(settee), pa = cdr(args); is_pair(p); p = cdr(p), pa = cdr(pa))
81135 		{
81136 		  index = car(p);
81137 		  if (is_symbol(index))
81138 		    index = lookup_checked(sc, index);
81139 		  if (!s7_is_integer(index))
81140 		    eval_error_any(sc, sc->wrong_type_arg_symbol, "vector-set!: index must be an integer: ~S", 41, form);
81141 		  car(pa) = index;
81142 		}
81143 	      car(pa) = cadr(sc->code);
81144 	      if (is_symbol(car(pa)))
81145 		car(pa) = lookup_checked(sc, car(pa));
81146 	      sc->value = g_vector_set(sc, args);
81147 	      if (in_heap(args))
81148 		sc->stack_end -= 4;
81149 	      else clear_list_in_use(args);
81150 	      return(goto_start);
81151 	    }}
81152       push_op_stack(sc, sc->vector_set_function); /* vector_setter(cx) has wrong args */
81153       sc->code = pair_append(sc, cddr(settee), cdr(sc->code)); /* i.e. rest(args) + val */
81154       push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), sc->code);
81155       sc->code = cadr(settee);
81156       sc->cur_op = optimize_op(sc->code);
81157       return(goto_top_no_pop);
81158     }
81159 
81160   /* one index, rank == 1 */
81161   index = cadr(settee);
81162   if ((is_fxable(sc, index)) &&
81163       (is_fxable(sc, cadr(sc->code))))
81164     {
81165       fx_annotate_arg(sc, cdr(settee), sc->curlet);
81166       fx_annotate_arg(sc, cdr(sc->code), sc->curlet);
81167       pair_set_syntax_op(form, OP_IMPLICIT_VECTOR_SET_3);
81168     }
81169   if (!is_pair(index))
81170     {
81171       s7_int ind;
81172       s7_pointer val;
81173 
81174       if (is_symbol(index))
81175 	index = lookup_checked(sc, index);
81176       if (!s7_is_integer(index))
81177 	eval_error_any(sc, sc->wrong_type_arg_symbol, "vector-set!: index must be an integer: ~S", 41, sc->code);
81178       ind = s7_integer_checked(sc, index);
81179       if ((ind < 0) ||
81180 	  (ind >= vector_length(cx)))
81181 	out_of_range(sc, sc->vector_set_symbol, int_two, index, (ind < 0) ? its_negative_string : its_too_large_string);
81182       val = cadr(sc->code);
81183       if (!is_pair(val))
81184 	{
81185 	  if (is_symbol(val))
81186 	    val = lookup_checked(sc, val);
81187 	  if (is_typed_vector(cx))
81188 	    typed_vector_setter(sc, cx, ind, val);
81189 	  else vector_setter(cx)(sc, cx, ind, val);
81190 	  sc->value = T_Pos(val);
81191 	  return(goto_start);
81192 	}
81193       push_op_stack(sc, sc->vector_set_function);
81194       sc->args = list_2(sc, index, cx);
81195       sc->code = cdr(sc->code);
81196       return(goto_eval_args);
81197     }
81198   /* here the index calc might be trivial -- (+ i 1) or (- j 1) but this branch hardly ever happens */
81199   push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
81200   push_op_stack(sc, sc->vector_set_function);
81201   sc->code = cadr(settee);
81202   sc->cur_op = optimize_op(sc->code);
81203   return(goto_top_no_pop);
81204 }
81205 
81206 static goto_t set_implicit_string(s7_scheme *sc, s7_pointer cx, s7_pointer form)
81207 {
81208   /* sc->code = cons(sc, sc->string_set_function, pair_append(sc, car(sc->code), cdr(sc->code)));
81209    *
81210    * here only one index makes sense, and it is required, so
81211    *   (set! ("str") #\a), (set! ("str" . 1) #\a) and (set! ("str" 1 2) #\a)
81212    *   are all errors (but see below!).
81213    */
81214   s7_pointer settee, index, val;
81215 
81216   if (is_null(cdr(sc->code))) s7_wrong_number_of_args_error(sc, "no value for string-set!: ~S", form);
81217   if (!is_null(cddr(sc->code))) s7_wrong_number_of_args_error(sc, "too many values for string-set!: ~S", form);
81218 
81219   settee = car(sc->code);
81220   if (is_null(cdr(settee))) s7_wrong_number_of_args_error(sc, "no index for string-set!: ~S", form);
81221   if (!is_null(cddr(settee))) s7_wrong_number_of_args_error(sc, "too many indices for string-set!: ~S", form);
81222 
81223   /* if there's one index (the standard case), and it is not a pair, and there's one value (also standard)
81224    *    and it is not a pair, let's optimize this thing!
81225    *    cx is what we're setting, cadar is the index, cadr is the new value
81226    */
81227   index = cadr(settee);
81228   if (!is_pair(index))
81229     {
81230       s7_int ind;
81231 
81232       if (is_symbol(index))
81233 	index = lookup_checked(sc, index);
81234       if (!s7_is_integer(index))
81235 	eval_error_any(sc, sc->wrong_type_arg_symbol, "index must be an integer: ~S", 28, form);
81236       ind = s7_integer_checked(sc, index);
81237       if ((ind < 0) ||
81238 	  (ind >= string_length(cx)))
81239 	out_of_range(sc, sc->string_set_symbol, int_two, index, (ind < 0) ? its_negative_string : its_too_large_string);
81240       if (is_immutable(cx))
81241 	immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->string_set_symbol, cx));
81242 
81243       val = cadr(sc->code);
81244       if (!is_pair(val))
81245 	{
81246 	  if (is_symbol(val))
81247 	    val = lookup_checked(sc, val);
81248 	  if (s7_is_character(val))
81249 	    {
81250 	      string_value(cx)[ind] = character(val);
81251 	      sc->value = val;
81252 	      return(goto_start);
81253 	    }
81254 	  eval_error_any(sc, sc->wrong_type_arg_symbol, "value must be a character: ~S", 29, form);
81255 	}
81256       push_op_stack(sc, sc->string_set_function);
81257       sc->args = list_2(sc, index, cx);
81258       sc->code = cdr(sc->code);
81259       return(goto_eval_args);
81260     }
81261   push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
81262   push_op_stack(sc, sc->string_set_function);
81263   sc->code = cadar(sc->code);
81264   sc->cur_op = optimize_op(sc->code);
81265   return(goto_top_no_pop);
81266 }
81267 
81268 static goto_t set_implicit_pair(s7_scheme *sc, s7_pointer cx, s7_pointer form)      /* code: ((lst 1) 32) from (let ((lst (list 1 2 3))) (set! (lst 1) 32)) */
81269 {
81270   s7_pointer settee, index, val;
81271 
81272   if (is_null(cdr(sc->code)))
81273     s7_wrong_number_of_args_error(sc, "no value for list-set!: ~S", form);
81274   if (!is_null(cddr(sc->code)))
81275     s7_wrong_number_of_args_error(sc, "too many values for list-set!: ~S", form);
81276 
81277   settee = car(sc->code);
81278   if (is_null(cdr(settee)))
81279     s7_wrong_number_of_args_error(sc, "no index for list-set!: ~S", form);
81280 
81281   if (!is_null(cddr(settee)))
81282     {
81283       /* split (set! (a b c...) v) into (set! ((a b) c ...) v), eval (a b), return
81284        *    (let ((L (list (list 1 2)))) (set! (L 0 0) 3) L)
81285        */
81286       push_stack(sc, OP_SET2, cddr(settee), cdr(sc->code));
81287       sc->code = list_2(sc, car(settee), cadr(settee));
81288       sc->cur_op = optimize_op(sc->code);
81289       return(goto_top_no_pop);
81290     }
81291 
81292   index = cadr(settee);
81293   val = cadr(sc->code);
81294 
81295   if ((is_pair(index)) ||
81296       (is_pair(val)))
81297     {
81298       push_op_stack(sc, sc->list_set_function);
81299       sc->code = pair_append(sc, cddr(settee), cdr(sc->code));
81300       push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), sc->code);
81301       sc->code = index;
81302       sc->cur_op = optimize_op(sc->code);
81303       return(goto_top_no_pop);
81304     }
81305 
81306   if (is_symbol(index))
81307     index = lookup_checked(sc, index);
81308   if (is_symbol(val))
81309     val = lookup_checked(sc, val);
81310 
81311   set_car(sc->t2_1, index);
81312   set_car(sc->t2_2, val);
81313   sc->value = g_list_set_1(sc, cx, sc->t2_1, 2);
81314   return(goto_start);
81315 }
81316 
81317 static goto_t set_implicit_hash_table(s7_scheme *sc, s7_pointer cx, s7_pointer form)
81318 {
81319   s7_pointer settee, key;
81320 
81321   if (is_null(cdr(sc->code)))
81322     s7_wrong_number_of_args_error(sc, "no value for hash-table-set!: ~S", form);
81323   if (!is_null(cddr(sc->code)))
81324     s7_wrong_number_of_args_error(sc, "too many values for hash-table-set!: ~S", form);
81325 
81326   settee = car(sc->code);
81327   if (is_null(cdr(settee)))
81328     s7_wrong_number_of_args_error(sc, "no key for hash-table-set!: ~S", form);
81329   if (is_immutable(cx))
81330     immutable_object_error(sc, set_elist_3(sc, immutable_error_string, sc->hash_table_set_symbol, cx));
81331 
81332   if (!is_null(cddr(settee)))
81333     {
81334       push_stack(sc, OP_SET2, cddr(settee), cdr(sc->code));
81335       sc->code = list_2(sc, car(settee), cadr(settee));
81336       sc->cur_op = optimize_op(sc->code);
81337       return(goto_top_no_pop);
81338     }
81339 
81340   key = cadr(settee);
81341   if (!is_pair(key))
81342     {
81343       s7_pointer val;
81344       if (is_symbol(key))
81345 	key = lookup_checked(sc, key);
81346       val = cadr(sc->code);
81347       if (!is_pair(val))
81348 	{
81349 	  if (is_symbol(val))
81350 	    val = lookup_checked(sc, val);
81351 	  sc->value = s7_hash_table_set(sc, cx, key, val);
81352 	  return(goto_start);
81353 	}
81354       push_op_stack(sc, sc->hash_table_set_function);
81355       sc->args = list_2(sc, key, cx);
81356       sc->code = cdr(sc->code);
81357       return(goto_eval_args);
81358     }
81359   push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
81360   push_op_stack(sc, sc->hash_table_set_function);
81361   sc->code = cadar(sc->code);
81362   sc->cur_op = optimize_op(sc->code);
81363   return(goto_top_no_pop);
81364 }
81365 
81366 static goto_t set_implicit_let(s7_scheme *sc, s7_pointer cx, s7_pointer form)     /* sc->code = cons(sc, sc->let_set_function, pair_append(sc, car(sc->code), cdr(sc->code))); */
81367 {
81368   s7_pointer settee, key;
81369   /* code: ((gen 'input) input) from (set! (gen 'input) input) */
81370 
81371   if (is_null(cdr(sc->code)))
81372     s7_wrong_number_of_args_error(sc, "no value for let-set!: ~S", form);
81373   if (!is_null(cddr(sc->code)))
81374     s7_wrong_number_of_args_error(sc, "too many values for let-set!: ~S", form);
81375 
81376   settee = car(sc->code);
81377   if (is_null(cdr(settee)))
81378     s7_wrong_number_of_args_error(sc, "no symbol (variable name) for let-set!: ~S", form);
81379   if (!is_null(cddr(settee)))
81380     {
81381       push_stack(sc, OP_SET2, cddr(settee), cdr(sc->code));
81382       sc->code = list_2(sc, car(settee), cadr(settee));
81383       sc->cur_op = optimize_op(sc->code);
81384       return(goto_top_no_pop);
81385     }
81386 
81387   key = cadr(settee);
81388   if (is_proper_quote(sc, key))
81389     {
81390       s7_pointer val;
81391       key = cadr(key);
81392       val = cadr(sc->code);
81393       if (!is_pair(val))
81394 	{
81395 	  if (is_symbol(val))
81396 	    val = lookup_checked(sc, val);
81397 	  sc->value = s7_let_set(sc, cx, key, val);
81398 	  return(goto_start);
81399 	}
81400       push_op_stack(sc, sc->let_set_function);
81401       sc->args = list_2(sc, key, cx);
81402       sc->code = cdr(sc->code);
81403       return(goto_eval_args);
81404     }
81405   push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
81406   push_op_stack(sc, sc->let_set_function);
81407   sc->code = cadar(sc->code);
81408   sc->cur_op = optimize_op(sc->code);
81409   return(goto_top_no_pop);
81410 }
81411 
81412 static goto_t set_implicit_function(s7_scheme *sc, s7_pointer cx)  /* (let ((lst (list 1 2))) (set! (list-ref lst 0) 2) lst) */
81413 {
81414   /* perhaps it has a setter */
81415   if (is_t_procedure(c_function_setter(cx)))
81416     {
81417       /* here the setter can be anything, so we need to check the needs_copied_args bit
81418        *    (set! ((dilambda / (let ((x 3)) (lambda (y) (+ x y))))) 3)!
81419        */
81420       /* sc->code = cons(sc, c_function_setter(cx), pair_append(sc, cdar(sc->code), cdr(sc->code))); */
81421       if (is_pair(cdar(sc->code)))
81422 	{
81423 	  if ((is_symbol(cadr(sc->code))) &&
81424 	      (is_symbol(cadar(sc->code))))
81425 	    {
81426 	      if (is_null(cddar(sc->code)))
81427 		{
81428 		  if (needs_copied_args(c_function_setter(cx)))
81429 		    sc->args = list_2(sc, lookup_checked(sc, cadar(sc->code)), lookup_checked(sc, cadr(sc->code)));
81430 		  else
81431 		    {
81432 		      s7_pointer val1, val2;
81433 		      val1 = lookup_checked(sc, cadar(sc->code));
81434 		      val2 = lookup_checked(sc, cadr(sc->code));
81435 		      set_car(sc->t2_1, val1);
81436 		      set_car(sc->t2_2, val2);
81437 		      sc->args = sc->t2_1;
81438 		    }
81439 		  sc->code = c_function_setter(cx);
81440 		  return(goto_apply); /* check arg num etc */
81441 		}
81442 	      if ((is_symbol(caddar(sc->code))) &&
81443 		  (is_null(cdddar(sc->code))))
81444 		{
81445 		  if (needs_copied_args(c_function_setter(cx)))
81446 		    sc->args = list_3(sc,
81447 				      lookup_checked(sc, cadar(sc->code)),
81448 				      lookup_checked(sc, caddar(sc->code)),
81449 				      lookup_checked(sc, cadr(sc->code)));
81450 		  else
81451 		    {
81452 		      s7_pointer val1, val2, val3;
81453 		      val1 = lookup_checked(sc, cadar(sc->code));
81454 		      val2 = lookup_checked(sc, caddar(sc->code));
81455 		      val3 = lookup_checked(sc, cadr(sc->code));
81456 		      set_car(sc->t3_1, val1);
81457 		      set_car(sc->t3_2, val2);
81458 		      set_car(sc->t3_3, val3);
81459 		      sc->args = sc->t3_1;
81460 		    }
81461 		  sc->code = c_function_setter(cx);
81462 		  return(goto_apply); /* check arg num etc */
81463 		}}
81464 	  push_op_stack(sc, c_function_setter(cx));
81465 	  sc->value = pair_append(sc, cddar(sc->code), cdr(sc->code));
81466 	  push_stack(sc, OP_EVAL_ARGS1, sc->nil, sc->value);
81467 	  sc->code = cadar(sc->code);
81468 	}
81469       else
81470 	{
81471 	  if ((is_null(cddr(sc->code))) &&
81472 	      (!is_pair(cadr(sc->code))))
81473 	    {
81474 	      if (needs_copied_args(c_function_setter(cx)))
81475 		sc->args = list_1(sc, (is_symbol(cadr(sc->code))) ? lookup_checked(sc, cadr(sc->code)) : cadr(sc->code));
81476 	      else
81477 		{
81478 		  if (is_symbol(cadr(sc->code)))
81479 		    set_car(sc->t1_1, lookup_checked(sc, cadr(sc->code)));
81480 		  else set_car(sc->t1_1, cadr(sc->code));
81481 		  sc->args = sc->t1_1;
81482 		}
81483 	      sc->code = c_function_setter(cx);
81484 	      return(goto_apply); /* check arg num etc */
81485 	    }
81486 	  push_op_stack(sc, c_function_setter(cx));
81487 	  push_stack(sc, OP_EVAL_ARGS1, sc->nil, cddr(sc->code));
81488 	  sc->code = cadr(sc->code);
81489 	}}
81490   else
81491     {
81492       if (is_any_macro(c_function_setter(cx)))
81493 	{
81494 	  if (is_null(cdar(sc->code)))
81495 	    sc->args = copy_proper_list(sc, cdr(sc->code));
81496 	  else sc->args = pair_append(sc, cdar(sc->code), copy_proper_list(sc, cdr(sc->code)));
81497 	  /* append copies except for its last arg, but for macros, we have to copy everything, hence the extra copy_proper_list */
81498 	  sc->code = c_function_setter(cx);
81499 	  return(goto_apply);
81500 	}
81501       s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(sc->code), sc->prepackaged_type_names[type(cx)]));
81502     }
81503   sc->cur_op = optimize_op(sc->code);
81504   return(goto_top_no_pop);
81505 }
81506 
81507 static goto_t set_implicit_closure(s7_scheme *sc, s7_pointer cx)
81508 {
81509   s7_pointer setter;
81510   setter = closure_setter(cx);
81511   if ((setter == sc->F) &&
81512       (!closure_no_setter(cx)))
81513     setter = g_setter(sc, set_plist_1(sc, cx));
81514   if (is_t_procedure(setter))          /* appears to be caar_code */
81515     {
81516       /* (set! (o g) ...), here cx = o, sc->code = ((o g) ...) */
81517       push_op_stack(sc, setter);
81518       if (is_null(cdar(sc->code)))
81519 	{
81520 	  push_stack(sc, OP_EVAL_ARGS1, sc->nil, cddr(sc->code));
81521 	  sc->code = cadr(sc->code);
81522 	}
81523       else
81524 	{
81525 	  if (is_null(cddar(sc->code)))
81526 	    push_stack(sc, OP_EVAL_ARGS1, sc->nil, cdr(sc->code));
81527 	  else
81528 	    {
81529 	      sc->value = pair_append(sc, cddar(sc->code), cdr(sc->code));
81530 	      push_stack(sc, OP_EVAL_ARGS1, sc->nil, sc->value);
81531 	    }
81532 	  sc->code = cadar(sc->code);
81533 	}}
81534   else
81535     {
81536       if (is_any_macro(setter))
81537 	{
81538 	  if (is_null(cdar(sc->code)))
81539 	    sc->args = copy_proper_list(sc, cdr(sc->code));
81540 	  else sc->args = pair_append(sc, cdar(sc->code), copy_proper_list(sc, cdr(sc->code)));
81541 	  sc->code = setter;
81542 	  return(goto_apply);
81543 	}
81544       s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(sc->code), sc->prepackaged_type_names[type(cx)]));
81545     }
81546   sc->cur_op = optimize_op(sc->code);
81547   return(goto_top_no_pop);
81548 }
81549 
81550 static goto_t set_implicit_iterator(s7_scheme *sc, s7_pointer cx)
81551 {
81552   s7_pointer setter;
81553   setter = iterator_sequence(cx);
81554   if ((is_any_closure(setter)) || (is_any_macro(setter)))
81555     setter = closure_setter(iterator_sequence(cx));
81556   else setter = sc->F;
81557   if (is_procedure(setter))
81558     {
81559       push_op_stack(sc, setter);
81560       push_stack(sc, OP_EVAL_ARGS1, sc->nil, sc->nil);
81561       sc->code = cadr(sc->code);    /* the (as yet unevaluated) value, incoming code was ((obj) val) */
81562     }
81563   else
81564     {
81565       if (is_any_macro(setter))
81566 	{
81567 	  sc->args = list_1(sc, cadr(sc->code));
81568 	  sc->code = setter;
81569 	  return(goto_apply);
81570 	}
81571       s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(sc->code), sc->prepackaged_type_names[type(cx)]));
81572     }
81573   sc->cur_op = optimize_op(sc->code);
81574   return(goto_top_no_pop);
81575 }
81576 
81577 static goto_t set_implicit_syntax(s7_scheme *sc, s7_pointer cx)
81578 {
81579   if (cx == global_value(sc->with_let_symbol))
81580     {
81581       /* (set! (with-let a b) x), cx = with-let, sc->code = ((with-let a b) x)
81582        *   a and x are in the current let, b is in a, we need to evaluate a and x, then
81583        *   call (with-let a-value (set! b x-value))
81584        */
81585       sc->args = cdar(sc->code);
81586       sc->code = cadr(sc->code);
81587       push_stack_direct(sc, OP_SET_WITH_LET_1);
81588       sc->cur_op = optimize_op(sc->code);
81589       return(goto_top_no_pop);
81590     }
81591   s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(sc->code), sc->prepackaged_type_names[type(cx)]));
81592   return(goto_top_no_pop);
81593 }
81594 
81595 static goto_t set_implicit(s7_scheme *sc) /* sc->code incoming is (set! (...) ...) */
81596 {
81597   s7_pointer caar_code, cx, form;
81598 
81599   form = sc->code;
81600   sc->code = cdr(sc->code);
81601   caar_code = caar(sc->code);
81602   if (is_pair(caar_code))
81603     {
81604       push_stack(sc, OP_SET2, cdar(sc->code), cdr(sc->code));
81605       sc->code = caar_code;
81606       sc->cur_op = optimize_op(sc->code);
81607       return(goto_top_no_pop);
81608     }
81609 
81610   if (is_symbol(caar_code))
81611     {
81612       /* this was cx = s7_symbol_value(sc, caar_code) but the function call overhead is noticeable */
81613       cx = lookup_slot_from(caar_code, sc->curlet);
81614       if (is_slot(cx))
81615 	cx = slot_value(cx);
81616       else s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar_code, sc->prepackaged_type_names[type(cx)]));
81617     }
81618   else cx = caar_code;
81619 
81620   /* code here is the setter and the value without the "set!": ((window-width) 800) */
81621   /*    (set! (hi 0) (* 2 3)) -> ((hi 0) (* 2 3)) */
81622   /* for gmp case, indices need to be decoded via s7_integer, not just integer */
81623 
81624   switch (type(cx))
81625     {
81626     case T_STRING:     return(set_implicit_string(sc, cx, form));
81627     case T_PAIR:       return(set_implicit_pair(sc, cx, form));
81628     case T_HASH_TABLE: return(set_implicit_hash_table(sc, cx, form));
81629     case T_LET:        return(set_implicit_let(sc, cx, form));
81630     case T_C_OBJECT:   return(set_implicit_c_object(sc, cx, form));
81631     case T_ITERATOR:   return(set_implicit_iterator(sc, cx));    /* not sure this makes sense */
81632     case T_SYNTAX:     return(set_implicit_syntax(sc, cx));
81633 
81634     case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_VECTOR: case T_BYTE_VECTOR:
81635       return(set_implicit_vector(sc, cx, form));
81636 
81637     case T_C_MACRO: case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION:
81638     case T_C_ANY_ARGS_FUNCTION: case T_C_FUNCTION: case T_C_FUNCTION_STAR:
81639       return(set_implicit_function(sc, cx));
81640 
81641     case T_MACRO: case T_MACRO_STAR: case T_BACRO: case T_BACRO_STAR:
81642     case T_CLOSURE: case T_CLOSURE_STAR:
81643       return(set_implicit_closure(sc, cx));
81644 
81645     default:                                         /* (set! (1 2) 3) */
81646       s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar_code, sc->prepackaged_type_names[type(cx)]));
81647     }
81648   return(goto_top_no_pop);
81649 }
81650 
81651 static void activate_let(s7_scheme *sc, s7_pointer e)
81652 {
81653   if (!is_let(e))                    /* (with-let . "hi") */
81654     eval_error_any(sc, sc->wrong_type_arg_symbol, "with-let takes an environment argument: ~A", 42, e);
81655   if (e == sc->rootlet)
81656     sc->curlet = sc->nil;                             /* (with-let (rootlet) ...) */
81657   else
81658     {
81659       set_with_let_let(e);
81660       let_set_id(e, ++sc->let_number);
81661       sc->curlet = e;
81662       update_symbol_ids(sc, e);
81663     }
81664 }
81665 
81666 static bool tree_match(s7_pointer tree)
81667 {
81668   if (is_symbol(tree))
81669     return(is_matched_symbol(tree));
81670   return((is_pair(tree)) &&
81671 	 ((tree_match(car(tree))) || (tree_match(cdr(tree)))));
81672 }
81673 
81674 static bool do_is_safe(s7_scheme *sc, s7_pointer body, s7_pointer steppers, s7_pointer var_list, bool *has_set)
81675 {
81676   /* here any (unsafe?) closure or jumping-op (call/cc) or shadowed variable is trouble */
81677   s7_pointer p;
81678   /* sc->code is the complete do form (do ...) */
81679 
81680   for (p = body; is_pair(p); p = cdr(p))
81681     {
81682       s7_pointer expr;
81683       expr = car(p);
81684       if (is_pair(expr))
81685 	{
81686 	  s7_pointer x;
81687 	  x = car(expr);
81688 	  if (is_symbol(x))
81689 	    {
81690 	      if (is_syntactic_symbol(x))
81691 		{
81692 		  opcode_t op;
81693 		  s7_pointer func, vars;
81694 		  func = global_value(x);
81695 		  op = (opcode_t)syntax_opcode(func);
81696 		  switch (op)
81697 		    {
81698 		    case OP_MACROEXPAND:
81699 		      return(false);
81700 
81701 		    case OP_QUOTE:
81702 		      if ((!is_pair(cdr(expr))) || (!is_null(cddr(expr))))  /* (quote . 1) or (quote 1 2) etc */
81703 			return(false);
81704 		      break;
81705 
81706 		    case OP_LET:
81707 		    case OP_LET_STAR:
81708 		    case OP_LETREC:
81709 		    case OP_LETREC_STAR:
81710 		      {
81711 			s7_pointer nv;
81712 			nv = var_list;
81713 
81714 			if ((!is_pair(cdr(expr))) ||
81715 			    (!is_list(cadr(expr))) ||
81716 			    (!is_pair(cddr(expr))))
81717 			  return(false);
81718 
81719 			for (vars = cadr(expr); is_pair(vars); vars = cdr(vars))
81720 			  {
81721 			    s7_pointer var;
81722 			    if (!is_pair(car(vars)))
81723 			      return(false);
81724 			    var = caar(vars);
81725 			    if (direct_memq(var, ((op == OP_LET) || (op == OP_LETREC)) ? nv : var_list))
81726 			      return(false);
81727 			    if ((!is_symbol(var)) || (is_keyword(var)))
81728 			      return(false);
81729 			    nv = cons(sc, var, nv);
81730 			    sc->x = nv;
81731 			  }
81732 			sc->x = sc->nil;
81733 			if (!do_is_safe(sc, cddr(expr), steppers, nv, has_set))
81734 			  return(false);
81735 			break;
81736 		      }
81737 
81738 		    case OP_DO:
81739 		      {
81740 			s7_pointer nv;
81741 			if ((!is_pair(cdr(expr))) || (!is_pair(cddr(expr))))  /* (do) or (do (...)) */
81742 			  return(false);
81743 			nv = var_list;
81744 			for (vars = cadr(expr); is_pair(vars); vars = cdr(vars))
81745 			  {
81746 			    s7_pointer var;
81747 			    if (!is_pair(car(vars)))
81748 			      return(false);
81749 			    var = caar(vars);
81750 			    if ((direct_memq(var, nv)) ||
81751 				(direct_memq(var, steppers)))
81752 			      return(false);
81753 
81754 			    nv = cons(sc, var, nv);
81755 			    sc->x = nv;
81756 			    if ((is_pair(cdar(vars))) &&
81757 				(!do_is_safe(sc, cdar(vars), steppers, nv, has_set)))
81758 			      {
81759 				sc->x = sc->nil;
81760 				return(false);
81761 			      }}
81762 			sc->x = sc->nil;
81763 			if (!do_is_safe(sc, caddr(expr), steppers, nv, has_set))
81764 			  return(false);
81765 			if ((is_pair(cdddr(expr))) &&
81766 			    (!do_is_safe(sc, cdddr(expr), steppers, nv, has_set)))
81767 			  return(false);
81768 			break;
81769 		      }
81770 
81771 		    case OP_SET:
81772 		      {
81773 			s7_pointer settee;
81774 			if (!is_pair(cdr(expr)))            /* (set!) */
81775 			  return(false);
81776 			settee = cadr(expr);
81777 			if (!is_symbol(settee))             /* (set! (...) ...) which is tricky due to setter functions/macros */
81778 			  {
81779 			    s7_pointer setv;
81780 			    if ((!is_pair(settee)) ||
81781 				(!is_symbol(car(settee))))
81782 			      return(false);
81783 			    setv = lookup_unexamined(sc, car(settee));
81784 			    if (!((setv) &&
81785 				  ((is_sequence(setv)) ||
81786 				   ((is_c_function(setv)) &&
81787 				    (is_safe_procedure(c_function_setter(setv)))))))
81788 			      return(false);
81789 			    if (has_set) (*has_set) = true;
81790 			  }
81791 			else
81792 			  {
81793 			    if ((is_pair(caddr(sc->code))) &&        /* sc->code = do-form (formerly (cdr(do-form)) causing a bug here) */
81794 				(is_pair(caaddr(sc->code))))
81795 			      {
81796 				bool res;
81797 				set_match_symbol(settee);
81798 				res = tree_match(caaddr(sc->code));  /* (set! end ...) in some fashion */
81799 				clear_match_symbol(settee);
81800 				if (res)
81801 				  return(false);
81802 			      }
81803 
81804 			    if ((has_set) && (!direct_memq(cadr(expr), var_list))) /* is some non-local variable being set? */
81805 			      (*has_set) = true;
81806 			  }
81807 			if (!do_is_safe(sc, cddr(expr), steppers, var_list, has_set))
81808 			  return(false);
81809 			if (!safe_stepper_expr(expr, steppers))      /* is step var's value used as the stored value by set!? */
81810 			  return(false);
81811 		      }
81812 		      break;
81813 
81814 		    case OP_LET_TEMPORARILY:
81815 		      {
81816 			s7_pointer lp;
81817 			if ((!is_pair(cdr(expr))) ||
81818 			    (!is_pair(cadr(expr))) ||
81819 			    (!is_pair(cddr(expr))))
81820 			  return(false);
81821 			for (lp = cadr(expr); is_pair(lp); lp = cdr(lp))
81822 			  if ((!is_pair(car(lp))) ||
81823 			      (!is_pair(cdar(lp))) ||
81824 			      (!do_is_safe(sc, cdar(lp), steppers, var_list, has_set)))
81825 			    return(false);
81826 			if (!do_is_safe(sc, cddr(expr), steppers, var_list, has_set))
81827 			  return(false);
81828 			break;
81829 		      }
81830 
81831 		    case OP_COND:
81832 		      {
81833 			s7_pointer cp;
81834 			for (cp = cdr(expr); is_pair(cp); cp = cdr(cp))
81835 			  if (!do_is_safe(sc, car(cp), steppers, var_list, has_set))
81836 			    return(false);
81837 			break;
81838 		      }
81839 
81840 		    case OP_CASE:
81841 		      {
81842 			s7_pointer cp;
81843 			if (!is_pair(cdr(expr)))
81844 			  return(false);
81845 			if (!do_is_safe(sc, cadr(expr), steppers, var_list, has_set))
81846 			  return(false);
81847 			for (cp = cddr(expr); is_pair(cp); cp = cdr(cp))
81848 			  if ((!is_pair(car(cp))) ||      /* (case x #(123)...) */
81849 			      (!do_is_safe(sc, cdar(cp), steppers, var_list, has_set)))
81850 			    return(false);
81851 			break;
81852 		      }
81853 
81854 		    case OP_IF:
81855 		    case OP_WHEN:
81856 		    case OP_UNLESS:
81857 		    case OP_AND:
81858 		    case OP_OR:
81859 		    case OP_BEGIN:
81860 		    case OP_WITH_BAFFLE:
81861 		      if (!do_is_safe(sc, cdr(expr), steppers, var_list, has_set))
81862 			return(false);
81863 		      break;
81864 
81865 		    case OP_WITH_LET:
81866 		      return(true); /* ?? did I mean false here?? */
81867 
81868 		    default:
81869 		      return(false);
81870 		    }} /* is_syntactic(x=car(expr)) */
81871 	      else
81872 		{
81873 		  /* if a macro, we'll eventually expand it (if *_optimize), but that requires a symbol lookup here and s7_macroexpand */
81874 		  if ((!is_optimized(expr)) ||
81875 		      (optimize_op(expr) == OP_UNKNOWN_FP) ||
81876 		      (!do_is_safe(sc, cdr(expr), steppers, var_list, has_set)))
81877 		    return(false);
81878 
81879 		  if (is_setter(x))           /* "setter" includes stuff like cons and vector -- x is a symbol */
81880 		    {
81881 		      /* (hash-table-set! ht i 0) -- caddr is being saved, so this is not safe
81882 		       *   similarly (vector-set! v 0 i) etc
81883 		       */
81884 		      if (is_null(cdr(expr)))                         /* (vector) for example */
81885 			{
81886 			  return((x == sc->vector_symbol) ||
81887 				 (x == sc->list_symbol) ||
81888 				 (x == sc->string_symbol));
81889 			}
81890 		      if ((has_set) && (!direct_memq(cadr(expr), var_list)))         /* non-local is being changed */
81891 			{
81892 			  if ((direct_memq(cadr(expr), steppers)) ||  /* stepper is being set? */
81893 			      (!is_pair(cddr(expr))) ||
81894 			      (!is_pair(cdddr(expr))) ||
81895 			      (is_pair(cddddr(expr))) ||
81896 			      ((x == sc->hash_table_set_symbol) &&
81897 			       (is_symbol(caddr(expr))) &&
81898 			       (direct_memq(caddr(expr), steppers))) ||
81899 			      ((is_symbol(cadddr(expr))) &&
81900 			       (direct_memq(cadddr(expr), steppers))) ||
81901 			      ((is_pair(cadddr(expr))) &&
81902 			       (tree_set_memq_b_7pp(sc, steppers, cadddr(expr)))))
81903 			    (*has_set) = true;
81904 			}
81905 		      if (!do_is_safe(sc, cddr(expr), steppers, var_list, has_set))
81906 			return(false);
81907 		      if (!safe_stepper_expr(expr, steppers))
81908 			return(false);
81909 		    }}} /* is_symbol(x=car(expr)) */
81910 	  else return(false);
81911 	  /* car(expr) ("x") is not a symbol: ((mus-data loc) chan) for example
81912 	   *   but that's actually safe since it's just in effect vector-ref
81913 	   *   there are several examples in dlocsig: ((group-speakers group) i) etc
81914 	   */
81915 	}}
81916   return(true);
81917 }
81918 
81919 static bool preserves_type(s7_scheme *sc, uint32_t x)
81920 {
81921   return((x == sc->add_class) ||
81922 	 (x == sc->subtract_class) ||
81923 	 (x == sc->multiply_class));
81924 }
81925 
81926 static s7_pointer simple_stepper(s7_scheme *sc, s7_pointer v)
81927 {
81928   if ((is_proper_list_3(sc, v)) &&
81929       (is_fxable(sc, cadr(v))))
81930     {
81931       s7_pointer step_expr;
81932       step_expr = caddr(v);
81933       if ((is_optimized(step_expr)) &&
81934 	  (((optimize_op(step_expr) == HOP_SAFE_C_SC) && (car(v) == cadr(step_expr))) ||
81935 	   ((is_h_safe_c_d(step_expr)) && /* replace with is_fxable? */
81936 	    (is_pair(cdr(step_expr))) &&         /* ((v 0 (+))) */
81937 	    (car(v) == cadr(step_expr)) &&
81938 	    ((opt1_cfunc(step_expr) == sc->add_x1) || (opt1_cfunc(step_expr) == sc->subtract_x1))) ||
81939 	   ((optimize_op(step_expr) == HOP_SAFE_C_CS) && (car(v) == caddr(step_expr)))))
81940 	return(step_expr);
81941     }
81942   return(NULL);
81943 }
81944 
81945 static bool is_simple_end(s7_scheme *sc, s7_pointer end)
81946 {
81947   return((is_optimized(end)) &&
81948 	 (is_safe_c_op(optimize_op(end))) &&
81949 	 (is_pair(cddr(end))) &&      /* end: (zero? n) */
81950 	 (cadr(end) != caddr(end)) &&
81951 	 ((opt1_cfunc(end) == sc->num_eq_xi) ||
81952 	  (optimize_op(end) == HOP_SAFE_C_SS) || (optimize_op(end) == HOP_SAFE_C_SC)));
81953 }
81954 
81955 static s7_pointer fxify_step_exprs(s7_scheme *sc, s7_pointer code)
81956 {
81957   s7_pointer p, e, vars;
81958   vars = car(code);
81959   e = collect_variables(sc, vars, sc->nil); /* only valid in step exprs, not in inits */
81960 
81961   for (p = vars; is_pair(p); p = cdr(p))
81962     {
81963       s7_function callee = NULL;
81964       s7_pointer expr;
81965       expr = cdar(p);    /* init */
81966       if (is_pair(expr))
81967 	{
81968 	  callee = fx_choose(sc, expr, sc->nil, do_symbol_is_safe); /* not vars -- they aren't defined yet */
81969 	  if (callee) set_fx(expr, callee);
81970 	}
81971       expr = cddar(p);   /* step */
81972       if (is_pair(expr))
81973 	{
81974 	  if ((is_pair(car(expr))) &&
81975 	      (!is_checked(car(expr))))
81976 	    optimize_expression(sc, car(expr), 0, e, false);
81977 	  callee = fx_choose(sc, expr, vars, do_symbol_is_safe);  /* fx_proc can be nil! */
81978 	  if (callee) set_fx(expr, callee);
81979 	}}
81980   if ((is_pair(cdr(code))) &&
81981       (is_pair(cadr(code))))
81982     {
81983       s7_pointer result;
81984       result = cdadr(code);
81985       if ((is_pair(result)) &&
81986 	  (is_fxable(sc, car(result))))
81987 	set_fx_direct(result, fx_choose(sc, result, vars, do_symbol_is_safe));
81988     }
81989   return(code);
81990 }
81991 
81992 static bool do_vector_has_definers(s7_scheme *sc, s7_pointer v)
81993 {
81994   s7_int i, len;
81995   s7_pointer *els;
81996   len = vector_length(v);
81997   els = vector_elements(v);
81998   for (i = 0; i < len; i++)
81999     if ((is_pair(els[i])) &&
82000 	(is_symbol(car(els[i]))) &&
82001 	(is_definer(car(els[i])))) /* this is a desperate kludge */
82002       return(true);
82003   return(false);
82004 }
82005 
82006 static inline bool do_tree_has_definers(s7_scheme *sc, s7_pointer tree)
82007 {
82008   /* we can't be very fancy here because quote gloms up everything: (cond '(define x 0) ...) etc, and the tree here can
82009    *   be arbitrarily messed up, and we need to be reasonably fast.  So we accept some false positives: (case ((define)...)...) or '(define...)
82010    * but what about ((f...)...) where (f...) returns a macro that defines something? Or (for-each or ...) where for-each and or might be
82011    * obfuscated and the args might contain a definer?
82012    */
82013   s7_pointer p;
82014   for (p = tree; is_pair(p); p = cdr(p))
82015     {
82016       s7_pointer pp;
82017       pp = car(p);
82018       if (is_symbol(pp))
82019 	{
82020 	  if ((is_definer(pp)) &&
82021 	      ((pp != sc->varlet_symbol) ||
82022 	       ((is_pair(cdr(p))) &&         /* if varlet, is target let local? */
82023 		(is_symbol(cadr(p))) &&
82024 		(!symbol_is_in_list(sc, cadr(p))))))
82025 	    return(true);
82026 	}
82027       else
82028 	{
82029 	  if (is_pair(pp))
82030 	    {
82031 	      if (do_tree_has_definers(sc, pp))
82032 		return(true);
82033 	    }
82034 	  else
82035 	    if (is_applicable(pp))
82036 	      {
82037 		if ((is_normal_vector(pp)) && (do_vector_has_definers(sc, pp)))
82038 		  return(true);
82039 		if ((is_c_function(pp)) && (is_func_definer(pp)))
82040 		  return(true);
82041 		if ((is_syntax(pp)) && (is_syntax_definer(pp)))
82042 		  return(true);
82043 	      }}}
82044   return(false);
82045 }
82046 
82047 static void check_do_for_obvious_errors(s7_scheme *sc, s7_pointer form)
82048 {
82049   s7_pointer x, code;
82050   code = cdr(form);
82051 
82052   if ((!is_pair(code)) ||                             /* (do . 1) */
82053       ((!is_pair(car(code))) &&                       /* (do 123) */
82054        (is_not_null(car(code)))))                     /* (do () ...) is ok */
82055     eval_error(sc, "do: variable list is not a list: ~S", 35, form);
82056 
82057   if (!is_pair(cdr(code)))                            /* (do () . 1) */
82058     eval_error(sc, "do body is messed up: ~A", 24, form);
82059 
82060   if ((!is_pair(cadr(code))) &&                       /* (do ((i 0)) 123) */
82061       (is_not_null(cadr(code))))                      /* no end-test? */
82062     eval_error(sc, "do: end-test and end-value list is not a list: ~A", 49, form);
82063 
82064   if (is_pair(car(code)))
82065     {
82066       clear_symbol_list(sc);
82067       for (x = car(code); is_pair(x); x = cdr(x))
82068 	{
82069 	  s7_pointer y;
82070 	  y = car(x);
82071 	  if (!(is_pair(y)))                             /* (do (4) (= 3)) */
82072 	    eval_error(sc, "do: variable name missing? ~A", 29, form);
82073 
82074 	  if (!is_symbol(car(y)))                        /* (do ((3 2)) ()) */
82075 	    eval_error(sc, "do step variable: ~S is not a symbol?", 37, y);
82076 
82077 	  if (is_constant_symbol(sc, car(y)))            /* (do ((pi 3 (+ pi 1))) ((= pi 4)) pi) */
82078 	    eval_error(sc, "do step variable: ~S is immutable", 33, y);
82079 
82080 	  if (is_pair(cdr(y)))
82081 	    {
82082 	      if (!is_pair(cddr(y)))
82083 		{
82084 		  if (is_not_null(cddr(y)))             /* (do ((i 0 . 1)) ...) */
82085 		    eval_error(sc, "do: step variable info is an improper list?: ~A", 47, x);
82086 		}
82087 	      else
82088 		if (is_not_null(cdddr(y)))              /* (do ((i 0 1 (+ i 1))) ...) */
82089 		  eval_error(sc, "do: step variable info has extra stuff after the increment: ~A", 62, x);
82090 	    }
82091 	  else eval_error(sc, "do: step variable has no initial value: ~A", 42, x);
82092 	  set_local(car(y));
82093 
82094 	  if (symbol_is_in_list(sc, car(y)))            /* (do ((i 0 (+ i 1)) (i 2))...) */
82095 	    eval_error(sc, "duplicate identifier in do: ~A", 30, x);
82096 	  add_symbol_to_list(sc, car(y));
82097 	}
82098       if (is_not_null(x))                               /* (do ((i 0 i) . 1) ((= i 1))) */
82099 	eval_error(sc, "do: list of variables is improper: ~A", 37, form);
82100     }
82101 
82102   if (is_pair(cadr(code)))
82103     {
82104       for (x = cadr(code); is_pair(x); x = cdr(x));
82105       if (is_not_null(x))
82106 	eval_error(sc, "stray dot in do end section? ~A", 31, form);
82107     }
82108 
82109   for (x = cddr(code); is_pair(x); x = cdr(x));
82110   if (is_not_null(x))
82111     eval_error(sc, "stray dot in do body? ~A", 24, form);
82112 }
82113 
82114 static s7_pointer do_end_bad(s7_scheme *sc, s7_pointer form)
82115 {
82116   s7_pointer code;
82117   code = cdr(form);
82118   if (is_null(cddr(code)))
82119     {
82120       s7_pointer p;
82121       /* no body, end not fxable (if eval car(end) might be unopt) */
82122       for (p = car(code); is_pair(p); p = cdr(p))  /* gather var names */
82123 	{
82124 	  s7_pointer var;
82125 	  var = car(p);
82126 	  if (is_pair(cddr(var)))                  /* if no step expr it's safe in other step exprs 16-Apr-19 */
82127 	    set_match_symbol(car(var));
82128 	}
82129       for (p = car(code); is_pair(p); p = cdr(p))  /* look for stuff like (do ((i 0 j) (j 0 (+ j 1))) ((= j 3) i)) */
82130 	{
82131 	  s7_pointer var, val;
82132 	  var = car(p);
82133 	  val = cddr(var);
82134 	  if (is_pair(val))
82135 	    {
82136 	      clear_match_symbol(car(var));        /* ignore current var */
82137 	      if (tree_match(car(val)))
82138 		{
82139 		  s7_pointer q;
82140 		  for (q = car(code); is_pair(q); q = cdr(q))
82141 		    clear_match_symbol(caar(q));
82142 		  return(code);
82143 		}}
82144 	  set_match_symbol(car(var));
82145 	}
82146       for (p = car(code); is_pair(p); p = cdr(p))  /* clear var names */
82147 	clear_match_symbol(caar(p));
82148 
82149       if (is_null(p))
82150 	{
82151 	  if ((is_null(cadr(code))) && /* (do () ()) or (do (fxable vars) ()) */
82152 	      (is_null(cddr(code))))
82153 	    {
82154 	      if (sc->safety > 0)
82155 		s7_warn(sc, 256, "%s: infinite do loop: %s\n", __func__, display(form));
82156 	      return(code);
82157 	    }
82158 
82159 	  fxify_step_exprs(sc, code);
82160 	  for (p = car(code); is_pair(p); p = cdr(p))
82161 	    {
82162 	      s7_pointer var;
82163 	      var = car(p);
82164 	      if ((!has_fx(cdr(var))) ||
82165 		  ((is_pair(cddr(var))) && (!has_fx(cddr(var)))))
82166 		return(code);
82167 	    }
82168 	  pair_set_syntax_op(form, OP_DO_NO_BODY_FX_VARS);
82169 	  return(sc->nil);
82170 	}}
82171   return(fxify_step_exprs(sc, code));
82172 }
82173 
82174 static s7_pointer check_do(s7_scheme *sc)
82175 {
82176   /* returns nil if optimizable */
82177   s7_pointer form, code, vars, end, body, p, e;
82178 
82179   form = sc->code;
82180   check_do_for_obvious_errors(sc, form);
82181   pair_set_syntax_op(form, OP_DO_UNCHECKED);
82182 
82183   code = cdr(form);
82184   end = cadr(code);
82185 
82186   if ((!is_pair(end)) || (!is_fxable(sc, car(end))))
82187     return(do_end_bad(sc, form));
82188 
82189   set_fx_direct(end, fx_choose(sc, end, sc->curlet, let_symbol_is_safe_or_listed));
82190   if ((is_pair(cdr(end))) &&
82191       (is_fxable(sc, cadr(end))))
82192     set_fx_direct(cdr(end), fx_choose(sc, cdr(end), sc->curlet, let_symbol_is_safe_or_listed));
82193 
82194   vars = car(code);
82195   if (is_null(vars))
82196     {
82197       pair_set_syntax_op(form, OP_DO_NO_VARS);
82198       return(sc->nil);
82199     }
82200   if (do_tree_has_definers(sc, form))       /* we don't want definers in body, vars, or end test */
82201     return(fxify_step_exprs(sc, code));
82202 
82203   if ((is_pair(vars)) && (is_null(cdr(vars))))
82204     fx_tree(sc, end, caar(vars), NULL);
82205 
82206   for (e = sc->curlet; (is_let(e)) && (e != sc->rootlet); e = let_outlet(e))
82207     if ((is_funclet(e)) || (is_maclet(e)))
82208       {
82209 	s7_pointer fname, fval;
82210 	fname = funclet_function(e);
82211 	fval = s7_symbol_local_value(sc, fname, e);
82212 	if ((is_closure(fval)) && (is_safe_closure(fval)))
82213 	  {
82214 	    if ((is_pair(vars)) && (is_null(cdr(vars))) && /* so do var is always == t (see mk2 in s7test) */
82215 		(tis_slot(let_slots(sc->curlet))) &&        /* let + 1 var, or funclet (so var order is guaranteed */
82216 		((!tis_slot(next_slot(let_slots(sc->curlet)))) ||
82217 		 (is_funclet(sc->curlet))))
82218 	      {
82219 		s7_pointer var1, var2 = NULL;
82220 		var1 = slot_symbol(let_slots(sc->curlet));
82221 		if (tis_slot(next_slot(let_slots(sc->curlet))))
82222 		  var2 = slot_symbol(next_slot(let_slots(sc->curlet)));
82223 		fx_tree_outer(sc, end, var1, var2);
82224 
82225 		for (p = vars; is_pair(p); p = cdr(p))
82226 		  {
82227 		    s7_pointer var;
82228 		    var = car(p);
82229 		    if (is_pair(cdr(var)))
82230 		      {
82231 			fx_tree(sc, cadr(var), var1, var2);
82232 			if (is_pair(cddr(var)))
82233 			  fx_tree_outer(sc, caddr(var), var1, var2);
82234 		      }}}}
82235 	break;
82236       }
82237 
82238   body = cddr(code);
82239   if ((is_pair(end)) && (is_pair(car(end))) &&
82240       (is_pair(vars)) && (is_null(cdr(vars))) &&
82241       (is_pair(body)) && (is_pair(car(body))) && (is_symbol(caar(body))))
82242     {
82243       /* loop has one step variable, and normal-looking end test */
82244       s7_pointer v, step_expr;
82245 
82246       v = car(vars);
82247       step_expr = simple_stepper(sc, v);
82248       if (step_expr)
82249 	{
82250 	  s7_pointer orig_end;
82251 	  orig_end = end;
82252 	  set_fx(cdr(v), fx_choose(sc, cdr(v), vars, do_symbol_is_safe)); /* v is (i 0 (+ i 1)) or the like */
82253 
82254 	  /* step var is (var const|symbol (op var const)|(op const var)) */
82255 	  end = car(end);
82256 	  if ((is_simple_end(sc, end)) &&
82257 	      (car(v) == cadr(end)))
82258 	    {
82259 	      /* end var is (op var const|symbol) using same var as step so at least we can use SIMPLE_DO */
82260 	      bool has_set = false, one_line;
82261 	      one_line = ((is_null(cdr(body))) && (is_pair(car(body))));
82262 
82263 	      if ((car(end) == sc->num_eq_symbol) && (is_symbol(cadr(end))) && (is_t_integer(caddr(end))))
82264 		{
82265 		  set_c_function(end, sc->num_eq_2);
82266 		  set_opt2_con(cdr(end), caddr(end));
82267 		  set_fx_direct(orig_end, fx_num_eq_si);
82268 		}
82269 	      pair_set_syntax_op(form, OP_SIMPLE_DO);              /* simple_do: 1 var easy step/end */
82270 
82271 	      if ((c_function_class(opt1_cfunc(step_expr)) == sc->add_class) &&  /* we check above that (car(v) == cadr(step_expr)) and (car(v) == cadr(end)) */
82272 		  ((c_function_class(opt1_cfunc(end)) == sc->num_eq_class) || (opt1_cfunc(end) == sc->geq_2)))
82273 		{
82274 		  if ((one_line) &&
82275 		      ((!is_optimized(car(body))) || (op_no_hop(car(body)) != OP_SAFE_C_D)) && /* this does happen: (if (= i 3) (vector-set! j 0 i)) */
82276 		      (is_syntactic_symbol(caar(body))) &&
82277 		      (s7_is_integer(caddr(step_expr))) && (s7_integer_checked(sc, caddr(step_expr)) == 1))
82278 		    {
82279 		      pair_set_syntax_op(car(body), symbol_syntax_op_checked(car(body)));
82280 		      set_opt2_pair(code, caddr(caar(code)));
82281 		      pair_set_syntax_op(form, OP_DOTIMES_P);          /* dotimes_p: simple + syntax body + 1 expr */
82282 		    }
82283 
82284 		  if (((caddr(step_expr) == int_one) || (cadr(step_expr) == int_one)) &&
82285 		      (do_is_safe(sc, body, sc->w = list_1(sc, car(v)), sc->nil, &has_set)))
82286 		    {
82287 		      pair_set_syntax_op(form, OP_SAFE_DO);          /* safe_do: body is safe, step by 1 */
82288 		      /* no permanent let here because apparently do_is_safe accepts recursive calls? */
82289 		      if ((!has_set) &&
82290 			  (c_function_class(opt1_cfunc(end)) == sc->num_eq_class))
82291 			{
82292 			  pair_set_syntax_op(form, OP_SAFE_DOTIMES);   /* safe_dotimes: end is = */
82293 			  if (is_fxable(sc, car(body)))
82294 			    fx_annotate_arg(sc, body, collect_variables(sc, vars, sc->nil));
82295 			}
82296 		      fx_tree(sc, body, car(v), NULL); /* ?? */
82297 		      /* an experiment (this never works...) */
82298 		      if (stack_op(sc->stack, current_stack_top(sc) - 1) == OP_SAFE_DO_STEP)
82299 			fx_tree_outer(sc, body, caaar(stack_code(sc->stack, (current_stack_top(sc) - 1))), NULL);
82300 		    }}
82301 	      return(sc->nil);
82302 	    }}}
82303 
82304   /* we get here if there is more than one local var or anything "non-simple" about the rest */
82305   for (p = vars; is_pair(p); p = cdr(p))
82306     {
82307       s7_pointer var;
82308       var = car(p);
82309 
82310       if ((!is_fxable(sc, cadr(var))) ||
82311 	  ((is_pair(cddr(var))) &&
82312 	   (!is_fxable(sc, caddr(var)))) ||
82313 	  ((is_symbol(cadr(var))) &&
82314 	   (is_definer_or_binder(cadr(var)))))
82315 	{
82316 	  s7_pointer q;
82317 	  for (q = vars; q != p; q = cdr(q))
82318 	    clear_match_symbol(caar(q));
82319 	  return(fxify_step_exprs(sc, code));
82320 	}
82321       if (is_pair(cddr(var))) /* if no step expr it's safe in other step exprs 16-Apr-19 */
82322 	set_match_symbol(car(var));
82323     }
82324 
82325   {
82326     s7_pointer last_stepper = NULL, previous_stepper = NULL, last_expr = NULL, previous_expr = NULL;
82327     bool got_pending = false;
82328 
82329     for (p = vars; is_pair(p); p = cdr(p))
82330       {
82331 	s7_pointer var, val;
82332 	var = car(p);
82333 	previous_stepper = last_stepper;
82334 	previous_expr = last_expr;
82335 	last_stepper = car(var);
82336 	last_expr = cdr(var); /* inits refer to the outer let */
82337 	val = cdr(last_expr);
82338 	if (is_pair(val))
82339 	  {
82340 	    var = car(var);
82341 	    clear_match_symbol(var); /* ignore current var */
82342 	    if (tree_match(car(val)))
82343 	      {
82344 		s7_pointer q;
82345 		for (q = vars; is_pair(q); q = cdr(q))
82346 		  clear_match_symbol(caar(q));
82347 		if (is_null(body))
82348 		  got_pending = true;
82349 		else return(fxify_step_exprs(sc, code));
82350 	      }
82351 	    set_match_symbol(var);
82352 	  }}
82353     for (p = vars; is_pair(p); p = cdr(p))
82354       clear_match_symbol(caar(p));
82355 
82356     /* end and steps look ok! */
82357     for (p = vars; is_pair(p); p = cdr(p))
82358       {
82359 	s7_pointer var;
82360 	var = car(p);
82361 	set_fx_direct(cdr(var), fx_choose(sc, cdr(var), sc->curlet, let_symbol_is_safe)); /* init val */
82362 	if (is_pair(cddr(var)))
82363 	  {
82364 	    s7_pointer step_expr;
82365 	    step_expr = caddr(var);
82366 	    set_fx_direct(cddr(var), fx_choose(sc, cddr(var), vars, do_symbol_is_safe)); /* sets opt2(cddr(var)), not opt1 */
82367 	    if (!is_pair(step_expr))                /* (i 0 0) */
82368 	      {
82369 		if (cadr(var) == caddr(var))        /* not types match: (i x y) etc */
82370 		  set_safe_stepper_expr(cddr(var));
82371 	      }
82372 	    else
82373 	      if ((car(step_expr) != sc->quote_symbol) &&     /* opt1_cfunc(==opt1) might not be set in this case (sigh) */
82374 		  (is_safe_c_op(optimize_op(step_expr))) &&
82375 		  ((preserves_type(sc, c_function_class(opt1_cfunc(step_expr)))) || /* add etc */
82376 		   (car(step_expr) == sc->cdr_symbol) ||
82377 		   (car(step_expr) == sc->cddr_symbol) ||
82378 		   ((is_pair(cadr(var))) &&
82379 		    (is_pair(c_function_signature(c_function_base(opt1_cfunc(step_expr))))) &&
82380 		    (car(c_function_signature(c_function_base(opt1_cfunc(step_expr)))) != sc->T) &&
82381 		    (caadr(var) == car(step_expr)))))	       /* i.e. accept char-position as init/step, but not iterate */
82382 		set_safe_stepper_expr(cddr(var));
82383 	  }}
82384     pair_set_syntax_op(form, (got_pending) ? OP_DOX_PENDING_NO_BODY : OP_DOX);
82385     /* there are only a couple of cases in snd-test where a multi-statement do body is completely fx-able */
82386 
82387     if ((is_null(body)) &&
82388 	(is_null(cdr(vars))) &&
82389 	(is_pair(cdr(end))) &&
82390 	(is_null(cddr(end))) &&
82391 	(has_fx(cdr(end))) &&
82392 	(is_pair(cdar(vars))) &&
82393 	(is_pair(cddar(vars))))
82394       {
82395 	s7_pointer var, step;
82396 	if (not_in_heap(cdr(form)))
82397 	  set_opt3_any(cdr(form), make_permanent_let(sc, vars));
82398 	else set_opt3_any(cdr(form), sc->F);
82399 
82400 	if (!got_pending)
82401 	  pair_set_syntax_op(form, OP_DOX_NO_BODY);
82402 
82403 	var = caar(vars);
82404 	step = cddar(vars);
82405 
82406 	if (is_safe_stepper_expr(step))
82407 	  {
82408 	    step = car(step);
82409 	    if ((is_pair(step)) && (is_proper_list_3(sc, step)))
82410 	      {
82411 		if ((car(step) == sc->add_symbol) &&
82412 		    (((cadr(step) == var) && (caddr(step) == int_one)) ||
82413 		     (caddr(step) == var)) && (cadr(step) == int_one))
82414 		  set_opt2_con(cdr(form), int_one);
82415 		else
82416 		  {
82417 		    if ((car(step) == sc->subtract_symbol) &&
82418 			(cadr(step) == var) &&
82419 			(caddr(step) == int_one))
82420 		      set_opt2_con(cdr(form), minus_one);
82421 		    else set_opt2_con(cdr(form), int_zero);
82422 		  }}
82423 	    else set_opt2_con(cdr(form), int_zero);
82424 	  }
82425 	else set_opt2_con(cdr(form), int_zero);
82426       }
82427 
82428     if (do_passes_safety_check(sc, body, sc->nil, NULL))
82429       {
82430 	if (last_stepper)
82431 	  {
82432 	    if ((is_pair(car(end))) &&
82433 		(has_fx(end)) &&
82434 		(!(is_syntax(caar(end)))) &&
82435 		(!((is_symbol(caar(end))) && (is_definer_or_binder(caar(end))))))
82436 	      {
82437 		if (!fx_tree_in(sc, end, last_stepper, previous_stepper)) /* just the end-test, not the results */
82438 		  fx_tree(sc, car(end), last_stepper, previous_stepper);  /* car(end) might be (or ...) */
82439 	      }
82440 	    if ((is_pair(cdr(end))) &&
82441 		(is_pair(cadr(end))) &&
82442 		(is_null(cddr(end))) &&
82443 		(has_fx(cdr(end))))
82444 	      {
82445 		if (!fx_tree_in(sc, cdr(end), last_stepper, previous_stepper))
82446 		  fx_tree(sc, cadr(end), last_stepper, previous_stepper);
82447 	      }
82448 	    /* the bad case for results: (let ((vals3t with-baffle)) func+do+ (vals3t (* 2 i 3 4))) -> fx_t|u trouble */
82449 
82450 	    if ((last_expr) && (is_pair(last_expr)))
82451 	      {
82452 		if ((is_funclet(sc->curlet)) && (tis_slot(let_slots(sc->curlet))))
82453 		  {
82454 		    s7_pointer s1;
82455 		    s1 = let_slots(sc->curlet);
82456 		    fx_tree_in(sc, last_expr, slot_symbol(s1), (tis_slot(next_slot(s1))) ? slot_symbol(next_slot(s1)) : NULL);
82457 		  }
82458 		last_expr = cdr(last_expr);
82459 		if (is_pair(last_expr))
82460 		  fx_tree(sc, last_expr, last_stepper, previous_stepper);
82461 
82462 		if ((previous_expr) && (is_pair(previous_expr)))
82463 		  {
82464 		    if ((is_funclet(sc->curlet)) && (tis_slot(let_slots(sc->curlet))))
82465 		      {
82466 			s7_pointer s1;
82467 			s1 = let_slots(sc->curlet);
82468 			fx_tree_in(sc, previous_expr, slot_symbol(s1), (tis_slot(next_slot(s1))) ? slot_symbol(next_slot(s1)) : NULL);
82469 		      }
82470 		    previous_expr = cdr(previous_expr);
82471 		    if (is_pair(previous_expr))
82472 		      fx_tree(sc, previous_expr, last_stepper, previous_stepper);
82473 		  }}}
82474 	if ((is_pair(body)) && (is_null(cdr(body))) &&
82475 	    (is_fxable(sc, car(body))))
82476 	  {
82477 	    fx_annotate_arg(sc, body, collect_variables(sc, vars, sc->nil));
82478 	    fx_tree(sc, body, last_stepper, previous_stepper);
82479 	  }}}
82480   return(sc->nil);
82481 }
82482 
82483 static bool has_safe_steppers(s7_scheme *sc, s7_pointer let)
82484 {
82485   s7_pointer slot;
82486   for (slot = let_slots(let); tis_slot(slot); slot = next_slot(slot))
82487     {
82488       s7_pointer val;
82489       val = slot_value(slot);
82490       if (slot_has_expression(slot))
82491 	{
82492 	  s7_pointer step_expr;
82493 	  step_expr = slot_expression(slot);
82494 	  if (!is_pair(step_expr))
82495 	    {
82496 	      if ((is_null(step_expr)) ||
82497 		  (type(step_expr) == type(val)))
82498 		set_safe_stepper(slot);
82499 	      else clear_safe_stepper(slot);
82500 	    }
82501 	  else
82502 	    {
82503 	      if (is_safe_stepper_expr(step_expr))
82504 		{
82505 		  if (is_t_integer(val))
82506 		    {
82507 		      if (is_int_optable(step_expr))
82508 			set_safe_stepper(slot);
82509 		      else
82510 			{
82511 			  if (no_int_opt(step_expr))
82512 			    clear_safe_stepper(slot);
82513 			  else
82514 			    {
82515 			      sc->pc = 0;
82516 			      if (int_optimize(sc, step_expr))
82517 				{
82518 				  set_safe_stepper(slot);
82519 				  set_is_int_optable(step_expr);
82520 				}
82521 			      else
82522 				{
82523 				  clear_safe_stepper(slot);
82524 				  set_no_int_opt(step_expr);
82525 				}}}}
82526 		  else
82527 		    {
82528 		      if (is_small_real(val))
82529 			{
82530 			  if (is_float_optable(step_expr))
82531 			    set_safe_stepper(slot);
82532 			  else
82533 			    {
82534 			      if (no_float_opt(step_expr))
82535 				clear_safe_stepper(slot);
82536 			      else
82537 				{
82538 				  sc->pc = 0;
82539 				  if (float_optimize(sc, step_expr))
82540 				    {
82541 				      set_safe_stepper(slot);
82542 				      set_is_float_optable(step_expr);
82543 				    }
82544 				  else
82545 				    {
82546 				      clear_safe_stepper(slot);
82547 				      set_no_float_opt(step_expr);
82548 				    }}}}
82549 		      else set_safe_stepper(slot);  /* ?? shouldn't this check types ?? */
82550 		    }}}}
82551       else
82552 	{
82553 	  if (is_t_real(val))
82554 	    slot_set_value(slot, s7_make_mutable_real(sc, real(val)));
82555 	  if (is_t_integer(val))
82556 	    slot_set_value(slot, make_mutable_integer(sc, integer(val)));
82557 	  set_safe_stepper(slot);
82558 	}
82559       if (!is_safe_stepper(slot))
82560 	return(false);
82561     }
82562   return(true);
82563 }
82564 
82565 static bool op_dox_init(s7_scheme *sc)
82566 {
82567   s7_pointer let, vars, test, code;
82568   code = cdr(sc->code);
82569   let = make_let(sc, sc->curlet);
82570   sc->temp1 = let;
82571   for (vars = car(code); is_pair(vars); vars = cdr(vars))
82572     {
82573       add_slot(sc, let, caar(vars), fx_call(sc, cdar(vars)));
82574       if (is_pair(cddar(vars)))
82575 	slot_set_expression(let_slots(let), cddar(vars));
82576       else slot_just_set_expression(let_slots(let), sc->nil);
82577     }
82578   sc->curlet = let;
82579   sc->temp1 = sc->nil;
82580   test = cadr(code);
82581   if (is_true(sc, sc->value = fx_call(sc, test)))
82582     {
82583       sc->code = cdr(test);
82584       return(true); /* goto DO_END_CLAUSES */
82585     }
82586   sc->code = T_Pair(cddr(code));
82587   push_stack_no_args(sc, (intptr_t)((is_null(cdr(sc->code))) ? OP_DOX_STEP_O : OP_DOX_STEP), code);
82588   return(false); /* goto BEGIN */
82589 }
82590 
82591 static goto_t op_dox(s7_scheme *sc)
82592 {
82593   /* any number of steppers using dox exprs, end also dox, body and end result arbitrary.
82594    *    since all these exprs are local, we don't need to jump until the body
82595    */
82596   int64_t id, steppers = 0;
82597   s7_pointer let, vars, code, end, endp, stepper = NULL, form, slots;
82598   s7_function endf;
82599 #if WITH_GMP
82600   bool got_bignum = false;
82601 #endif
82602 
82603   form = sc->code;
82604   sc->code = cdr(sc->code);
82605 
82606   let = make_let(sc, sc->curlet);   /* new let is not tied into the symbol lookup process yet */
82607   sc->temp1 = let;
82608   for (vars = car(sc->code); is_pair(vars); vars = cdr(vars))
82609     {
82610       s7_pointer expr, val, stp, slot;
82611       expr = cdar(vars);
82612       val = fx_call(sc, expr);
82613 #if WITH_GMP
82614       if (!got_bignum) got_bignum = is_big_number(val);
82615 #endif
82616       new_cell_no_check(sc, slot, T_SLOT);
82617       slot_set_symbol(slot, caar(vars));
82618       slot_set_value(slot, val);
82619       stp = cdr(expr); /* cddar(vars) */
82620       if (is_pair(stp))
82621 	{
82622 	  steppers++;
82623 	  stepper = slot;
82624 	  slot_set_expression(slot, stp);
82625 	}
82626       else slot_just_set_expression(slot, sc->nil);
82627       slot_set_next(slot, let_slots(let));
82628       let_set_slots(let, slot);
82629     }
82630   sc->curlet = let;
82631   slots = let_slots(sc->curlet);
82632   sc->temp1 = sc->nil;
82633   id = let_id(let);
82634   /* the fn_calls above could have redefined a previous stepper, so that its symbol_id is > let let_id when we get here,
82635    *   so we use symbol_set_local_slot_unchecked below to sidestep the debugger (see zauto.scm: i is a stepper, but then mock-vector-ref uses i as its index)
82636    */
82637   {
82638     s7_pointer slot;
82639     for (slot = slots; tis_slot(slot); slot = next_slot(slot))
82640       symbol_set_local_slot_unchecked_and_unincremented(slot_symbol(slot), id, slot);
82641   }
82642   end = cadr(sc->code);
82643   endp = car(end);
82644   endf = fx_proc(end);
82645 
82646   if (is_true(sc, sc->value = endf(sc, endp)))
82647     {
82648       sc->code = cdr(end);
82649       return(goto_do_end_clauses);
82650     }
82651 
82652   code = cddr(sc->code);
82653   if (is_null(code)) /* no body? */
82654     {
82655       if (endf == fx_c_d)
82656 	{
82657 	  endf = fn_proc(endp);
82658 	  endp = cdr(endp);
82659 	}
82660       if (steppers == 1)
82661 	{
82662 	  s7_function f;
82663 	  s7_pointer a;
82664 
82665 	  f = fx_proc(slot_expression(stepper)); /* e.g. fx_add_s1 */
82666 	  a = car(slot_expression(stepper));
82667 	  if (f == fx_c_d)
82668 	    {
82669 	      f = fn_proc(a);
82670 	      a = cdr(a);
82671 	    }
82672 	  if (((f == fx_cdr_s) || (f == fx_cdr_t)) &&
82673 	      (cadr(a) == slot_symbol(stepper)))
82674 	    {
82675 	      do {slot_set_value(stepper, cdr(slot_value(stepper)));} while (endf(sc, endp) == sc->F);
82676 	      sc->value = sc->T;
82677 	    }
82678 	  else
82679 	    {
82680 	      /* (- n 1) tpeak dup */
82681 	      if (((f == fx_add_t1) || (f == fx_add_u1)) && (is_t_integer(slot_value(stepper))))
82682 		{
82683 		  s7_pointer p;
82684 		  p = make_mutable_integer(sc, integer(slot_value(stepper)));
82685 		  slot_set_value(stepper, p);
82686 		  if (!no_bool_opt(end))
82687 		    {
82688 		      sc->pc = 0;
82689 		      if (bool_optimize(sc, end))  /* in dup.scm this costs more than the fb(o) below saves (search is short) */
82690 			{                          /*    but tc is much slower (and bool|int_optimize dominates) */
82691 			  opt_info *o;
82692 			  bool (*fb)(opt_info *o);
82693 			  o = sc->opts[0];
82694 			  fb = o->v[0].fb;
82695 			  do {integer(p)++;} while (!fb(o)); /* do {integer(p)++;} while ((sc->value = optf(sc, endp)) == sc->F); */
82696 			  clear_mutable_integer(p);
82697 			  sc->value = sc->T;
82698 			  sc->code = cdr(end);
82699 			  return(goto_do_end_clauses);
82700 			}
82701 		      else set_no_bool_opt(end);
82702 		    }
82703 		  do {integer(p)++;} while ((sc->value = endf(sc, endp)) == sc->F);
82704 		  clear_mutable_integer(p);
82705 		}
82706 	      else do {slot_set_value(stepper, f(sc, a));} while ((sc->value = endf(sc, endp)) == sc->F);
82707 	    }
82708 	  sc->code = cdr(end);
82709 	  return(goto_do_end_clauses);
82710 	}
82711       else
82712 	{
82713 	  if ((steppers == 2) &&
82714 	      (!tis_slot(next_slot(next_slot(slots)))))
82715 	    {
82716 	      s7_pointer step1, step2, expr1, expr2;
82717 	      step1 = slots;
82718 	      expr1 = slot_expression(step1);
82719 	      step2 = next_slot(step1);
82720 	      expr2 = slot_expression(step2); /* presetting fx_proc/car(expr) is not faster */
82721 	      if ((fx_proc(expr2) == fx_subtract_u1) &&
82722 		  (is_t_integer(slot_value(step2))) &&
82723 		  (endf == fx_num_eq_ui))
82724 		{
82725 		  s7_int i, lim;
82726 		  lim = integer(caddr(endp));
82727 		  for (i = integer(slot_value(step2)) - 1; i >= lim; i--)
82728 		    slot_set_value(step1, fx_call(sc, expr1));
82729 		}
82730 	      else
82731 		do {
82732 		    slot_set_value(step1, fx_call(sc, expr1));
82733 		    slot_set_value(step2, fx_call(sc, expr2));
82734 		  } while ((sc->value = endf(sc, endp)) == sc->F);
82735 	      sc->code = cdr(end);
82736 	      if (is_symbol(car(sc->code)))
82737 		{
82738 		  step1 = lookup_slot_from(car(sc->code), sc->curlet);
82739 		  sc->value = slot_value(step1);
82740 		  if (is_t_real(sc->value))
82741 		    clear_mutable_number(sc->value);
82742 		  return(goto_start);
82743 		}
82744 	      return(goto_do_end_clauses);
82745 	    }
82746 	  do {
82747 	    s7_pointer slt;
82748 	    slt = slots;
82749 	    do {
82750 	      if (slot_has_expression(slt))
82751 		slot_set_value(slt, fx_call(sc, slot_expression(slt)));
82752 	      slt = next_slot(slt);
82753 	    } while (tis_slot(slt));
82754 	  } while ((sc->value = endf(sc, endp)) == sc->F);
82755 	  sc->code = cdr(end);
82756 	  return(goto_do_end_clauses);
82757 	}}
82758   else /* there is a body */
82759     {
82760       /* is let activated? also multiexpr body  and other fx? */
82761       if ((is_null(cdr(code))) && /* 1 expr, code is cdddr(form) here */
82762 	  (is_pair(car(code))))
82763 	{
82764 	  s7_pointer body;
82765 	  s7_function bodyf = NULL;
82766 	  body = car(code);
82767 
82768 	  if ((!no_cell_opt(code)) &&
82769 #if WITH_GMP
82770 	      (!got_bignum) &&
82771 #endif
82772 	      (has_safe_steppers(sc, sc->curlet)))
82773 	    bodyf = s7_optimize_nr(sc, code);
82774 
82775 	  if ((!bodyf) &&
82776 	      (is_fxable(sc, body)))
82777 	    bodyf = fx_choose(sc, code, sc->curlet, let_symbol_is_safe);
82778 
82779 	  if (bodyf)
82780 	    {
82781 	      if (steppers == 1)                                /* one expr body, 1 stepper */
82782 		{
82783 		  s7_pointer stepa;
82784 		  s7_function stepf;
82785 		  stepf = fx_proc(slot_expression(stepper));
82786 		  stepa = car(slot_expression(stepper));
82787 
82788 		  if (bodyf == opt_float_any_nr)
82789 		    {
82790 		      s7_double (*fd)(opt_info *o);
82791 		      opt_info *o;
82792 		      o = sc->opts[0];
82793 		      fd = o->v[0].fd;
82794 		      do {
82795 			fd(o);
82796 			slot_set_value(stepper, stepf(sc, stepa));
82797 		      } while ((sc->value = endf(sc, endp)) == sc->F);
82798 		      sc->code = cdr(end);
82799 		      return(goto_do_end_clauses);
82800 		    }
82801 		  /* a few + 1.0 here (s7test) */
82802 		  if (((stepf == fx_add_t1) || (stepf == fx_add_u1)) && (is_t_integer(slot_value(stepper))))
82803 		    {
82804 		      s7_int i;
82805 		      i = integer(slot_value(stepper));
82806 		      if (bodyf == opt_cell_any_nr)
82807 			{
82808 			  s7_pointer (*fp)(opt_info *o);
82809 			  opt_info *o;
82810 			  o = sc->opts[0];
82811 			  fp = o->v[0].fp;
82812 			  do {
82813 			    fp(o);
82814 			    slot_set_value(stepper, make_integer(sc, ++i));
82815 			  } while ((sc->value = endf(sc, endp)) == sc->F);
82816 			}
82817 		      else
82818 			do {
82819 			    bodyf(sc, body);
82820 			    slot_set_value(stepper, make_integer(sc, ++i));
82821 			  } while ((sc->value = endf(sc, endp)) == sc->F);
82822 		      sc->code = cdr(end);
82823 		      return(goto_do_end_clauses);
82824 		    }
82825 
82826 		  do {
82827 		    bodyf(sc, body);
82828 		    slot_set_value(stepper, stepf(sc, stepa));
82829 		  } while ((sc->value = endf(sc, endp)) == sc->F);
82830 		  sc->code = cdr(end);
82831 		  return(goto_do_end_clauses);
82832 		}
82833 
82834 	      if ((steppers == 2) &&
82835 		  (!tis_slot(next_slot(next_slot(slots)))))
82836 		{
82837 		  s7_pointer s1, s2, p1, p2;
82838 		  s7_function f1, f2;
82839 		  s1 = slots;
82840 		  s2 = next_slot(s1);
82841 		  f1 = fx_proc(slot_expression(s1));
82842 		  f2 = fx_proc(slot_expression(s2));
82843 		  p1 = car(slot_expression(s1));
82844 		  p2 = car(slot_expression(s2));
82845 		  /* split out opt_float_any_nr gained nothing (see tmp), same for opt_cell_any_nr */
82846 		  if (bodyf == opt_cell_any_nr)
82847 		    {
82848 		      s7_pointer (*fp)(opt_info *o);
82849 		      opt_info *o;
82850 		      o = sc->opts[0];
82851 		      fp = o->v[0].fp;
82852 		      do {
82853 			fp(o);
82854 			slot_set_value(s1, f1(sc, p1));
82855 			slot_set_value(s2, f2(sc, p2));
82856 		      } while ((sc->value = endf(sc, endp)) == sc->F);
82857 		    }
82858 		  else
82859 		    do {
82860 			bodyf(sc, body);
82861 			slot_set_value(s1, f1(sc, p1));
82862 			slot_set_value(s2, f2(sc, p2));
82863 		      } while ((sc->value = endf(sc, endp)) == sc->F);
82864 		  sc->code = cdr(end);
82865 		  return(goto_do_end_clauses);
82866 		}
82867 	      if (bodyf == opt_cell_any_nr)
82868 		{
82869 		  s7_pointer (*fp)(opt_info *o);
82870 		  opt_info *o;
82871 		  o = sc->opts[0];
82872 		  fp = o->v[0].fp;
82873 		  do {
82874 		    s7_pointer slot1;
82875 		    fp(o);
82876 		    slot1 = slots;
82877 		    do {
82878 		      if (slot_has_expression(slot1))
82879 			slot_set_value(slot1, fx_call(sc, slot_expression(slot1)));
82880 		      slot1 = next_slot(slot1);
82881 		    } while (tis_slot(slot1));
82882 		  } while ((sc->value = endf(sc, endp)) == sc->F);
82883 		}
82884 	      else
82885 		do {
82886 		    s7_pointer slot1;
82887 		    bodyf(sc, body);
82888 		    slot1 = slots;
82889 		    do {
82890 		      if (slot_has_expression(slot1))
82891 			slot_set_value(slot1, fx_call(sc, slot_expression(slot1)));
82892 		      slot1 = next_slot(slot1);
82893 		    } while (tis_slot(slot1));
82894 		  } while ((sc->value = endf(sc, endp)) == sc->F);
82895 	      sc->code = cdr(end);
82896 	      return(goto_do_end_clauses);
82897 	    }
82898 
82899 	  if ((steppers == 1) &&
82900 	      (car(body) == sc->set_symbol) &&
82901 	      (is_pair(cdr(body))) &&
82902 	      (is_symbol(cadr(body))) &&
82903 	      (is_pair(cddr(body))) &&
82904 	      ((has_fx(cddr(body))) || (is_fxable(sc, caddr(body)))) &&
82905 	      (is_null(cdddr(body))))
82906 	    {
82907 	      s7_pointer val, slot, stepa;
82908 	      s7_function stepf, valf;
82909 
82910 	      val = cddr(body);
82911 	      if (!has_fx(val))
82912 		set_fx(val, fx_choose(sc, val, sc->curlet, let_symbol_is_safe));
82913 	      valf = fx_proc(val);
82914 	      val = car(val);
82915 	      slot = lookup_slot_from(cadr(body), sc->curlet);
82916 	      if (slot == sc->undefined)
82917 		unbound_variable_error(sc, cadr(body));
82918 	      stepf = fx_proc(slot_expression(stepper));
82919 	      stepa = car(slot_expression(stepper));
82920 	      do {
82921 		slot_set_value(slot, valf(sc, val));
82922 		slot_set_value(stepper, stepf(sc, stepa));
82923 	      } while ((sc->value = endf(sc, endp)) == sc->F);
82924 	      sc->code = cdr(end);
82925 	      return(goto_do_end_clauses);
82926 	    }
82927 
82928 	  /* not fxable body (bodyf nil) but body might be gxable here: is_gxable(body) */
82929 	  if ((has_gx(body)) || (gx_annotate_arg(sc, code, sc->curlet)))
82930 	    {
82931 	      bodyf = fx_proc_unchecked(code);
82932 	      do {
82933 		s7_pointer slot1;
82934 		bodyf(sc, body);
82935 		slot1 = slots;
82936 		do {
82937 		  if (slot_has_expression(slot1))
82938 		    slot_set_value(slot1, fx_call(sc, slot_expression(slot1)));
82939 		  slot1 = next_slot(slot1);
82940 		} while (tis_slot(slot1));
82941 	      } while ((sc->value = endf(sc, endp)) == sc->F);
82942 	      sc->code = cdr(end);
82943 	      return(goto_do_end_clauses);
82944 	    }}
82945       else /* more than one expr */
82946 	{
82947 	  s7_pointer p;
82948 	  bool use_opts = false;
82949 	  int32_t body_len = 0;
82950 	  opt_info *body[32];
82951           #define MAX_OPT_BODY_SIZE 32
82952 	  p = code;
82953 
82954 	  if ((!no_cell_opt(code)) &&
82955 #if WITH_GMP
82956 	      (!got_bignum) &&
82957 #endif
82958 	      (has_safe_steppers(sc, sc->curlet)))
82959 	    {
82960 	      int32_t k;
82961 	      sc->pc = 0;
82962 	      for (k = 0; (is_pair(p)) && (k < MAX_OPT_BODY_SIZE); k++, p = cdr(p), body_len++)
82963 		{
82964 		  opt_info *start;
82965 		  start = sc->opts[sc->pc];
82966 		  if (!cell_optimize(sc, p))
82967 		    {
82968 		      set_no_cell_opt(code);
82969 		      p = code;
82970 		      break;
82971 		    }
82972 		  oo_idp_nr_fixup(start);
82973 		  body[k] = start;
82974 		}
82975 	      use_opts = is_null(p);
82976 	    }
82977 
82978 	  if (p == code)
82979 	    for (; is_pair(p); p = cdr(p))
82980 	      if (!is_fxable(sc, car(p)))
82981 		break;
82982 
82983 	  if (is_null(p))
82984 	    {
82985 	      int32_t i;
82986 	      s7_pointer stepa = NULL;
82987 	      s7_function stepf = NULL;
82988 	      if (!use_opts)
82989 		fx_annotate_args(sc, code, sc->curlet);
82990 
82991 	      if (stepper)
82992 		{
82993 		  stepf = fx_proc(slot_expression(stepper));
82994 		  stepa = car(slot_expression(stepper));
82995 		}
82996 
82997 	      while (true)
82998 		{
82999 		  if (use_opts)
83000 		    for (i = 0; i < body_len; i++)
83001 		      body[i]->v[0].fp(body[i]);
83002 		  else
83003 		    for (p = code; is_pair(p); p = cdr(p))
83004 		      fx_call(sc, p);
83005 
83006 		  if (steppers == 1)
83007 		    slot_set_value(stepper, stepf(sc, stepa));
83008 		  else
83009 		    {
83010 		      s7_pointer slot;
83011 		      slot = slots;
83012 		      do {
83013 			if (slot_has_expression(slot))
83014 			  slot_set_value(slot, fx_call(sc, slot_expression(slot)));
83015 			slot = next_slot(slot);
83016 		      } while (tis_slot(slot));
83017 		    }
83018 		  if (is_true(sc, sc->value = endf(sc, endp)))
83019 		    {
83020 		      sc->code = cdr(end);
83021 		      return(goto_do_end_clauses);
83022 		    }}}}}
83023 
83024   if ((is_null(cdr(code))) && /* one expr */
83025       (is_pair(car(code))))
83026     {
83027       code = car(code);
83028       if ((is_syntactic_pair(code)) ||
83029 	  (is_syntactic_symbol(car(code))))
83030 	{
83031 	  push_stack_no_args_direct(sc, OP_DOX_STEP_O);
83032 	  if (is_syntactic_pair(code))
83033 	    sc->cur_op = (opcode_t)optimize_op(code);
83034 	  else
83035 	    {
83036 	      sc->cur_op = (opcode_t)symbol_syntax_op_checked(code);
83037 	      pair_set_syntax_op(code, sc->cur_op);
83038 	    }
83039 	  sc->code = code;
83040 	  return(goto_top_no_pop);
83041 	}}
83042 
83043   pair_set_syntax_op(form, OP_DOX_INIT);
83044   sc->code = T_Pair(cddr(sc->code));
83045   push_stack_no_args(sc, (intptr_t)((is_null(cdr(sc->code))) ? OP_DOX_STEP_O : OP_DOX_STEP), cdr(form));
83046   return(goto_begin);
83047 }
83048 
83049 static bool op_dox_step(s7_scheme *sc)
83050 {
83051   s7_pointer slot;
83052   slot = let_slots(sc->curlet);
83053   do {
83054     if (slot_has_expression(slot))
83055       slot_set_value(slot, fx_call(sc, slot_expression(slot)));
83056     slot = next_slot(slot);
83057     } while (tis_slot(slot));
83058   sc->value = fx_call(sc, cadr(sc->code));
83059   if (is_true(sc, sc->value))
83060     {
83061       sc->code = cdadr(sc->code);
83062       return(true);
83063     }
83064   push_stack_no_args_direct(sc, OP_DOX_STEP);
83065   sc->code = T_Pair(cddr(sc->code));
83066   return(false);
83067 }
83068 
83069 static bool op_dox_step_o(s7_scheme *sc) /* every dox case has vars (else op_do_no_vars) */
83070 {
83071   s7_pointer slot;
83072   slot = let_slots(sc->curlet);
83073   do {
83074     if (slot_has_expression(slot))
83075       slot_set_value(slot, fx_call(sc, slot_expression(slot)));
83076     slot = next_slot(slot);
83077     } while (tis_slot(slot));
83078   sc->value = fx_call(sc, cadr(sc->code));
83079   if (is_true(sc, sc->value))
83080     {
83081       sc->code = cdadr(sc->code);
83082       return(true);
83083     }
83084   push_stack_no_args_direct(sc, OP_DOX_STEP_O);
83085   sc->code = caddr(sc->code);
83086   return(false);
83087 }
83088 
83089 static void op_dox_no_body(s7_scheme *sc)
83090 {
83091   s7_pointer slot, var, test, result;
83092   s7_function testf;
83093 
83094   sc->code = cdr(sc->code);
83095   var = caar(sc->code);
83096   testf = fx_proc(cadr(sc->code));
83097   test = caadr(sc->code);
83098   result = cdadr(sc->code);
83099 
83100   if (not_in_heap(sc->code))
83101     {
83102       s7_pointer let;
83103       let = update_let_with_slot(sc, opt3_any(sc->code), fx_call(sc, cdr(var)));
83104       let_set_outlet(let, sc->curlet);
83105       sc->curlet = let;
83106     }
83107   else sc->curlet = make_let_with_slot(sc, sc->curlet, car(var), fx_call(sc, cdr(var)));
83108 
83109   slot = let_slots(sc->curlet);
83110   if ((is_t_integer(slot_value(slot))) &&
83111       ((integer(opt2_con(sc->code))) != 0))
83112     {
83113       s7_int incr;
83114       s7_pointer istep;
83115       incr = integer(opt2_con(sc->code));
83116       istep = make_mutable_integer(sc, integer(slot_value(slot)));
83117       /* this can cause unexpected, but correct behavior: (do ((x 0) (i 0 (+ i 1))) ((= i 1) x) (set! x (memq x '(0)))) -> #f
83118        *   because (eq? 0 x) here is false -- memv will return '(0).  tree-count is similar.
83119        */
83120       slot_set_value(slot, istep);
83121       if (testf == fx_or_2)
83122 	{
83123 	  s7_pointer t1, t2;
83124 	  s7_function f1, f2;
83125 	  f1 = fx_proc(cdr(test));
83126 	  t1 = cadr(test);
83127 	  f2 = fx_proc(cddr(test));
83128 	  t2 = caddr(test);
83129 	  while ((f1(sc, t1) == sc->F) && (f2(sc, t2) == sc->F))
83130 	    integer(istep) += incr;
83131 	}
83132       else while (testf(sc, test) == sc->F) {integer(istep) += incr;}
83133       if (is_small_int(integer(istep)))
83134 	slot_set_value(slot, small_int(integer(istep)));
83135       else clear_mutable_integer(istep);
83136       sc->value = fx_call(sc, result);
83137     }
83138   else
83139     {
83140       s7_function stepf;
83141       s7_pointer step;
83142       stepf = fx_proc(cddr(var));
83143       step = caddr(var);
83144       if (testf == fx_or_and_2)
83145 	{
83146 	  s7_pointer f1_arg, p, f2_arg, f3_arg;
83147 	  s7_function f1, f2, f3;
83148 	  f1_arg = cadr(test);
83149 	  f1 = fx_proc(cdr(test));
83150 	  p = opt3_pair(test); /* cdadr(p); */
83151 	  f2_arg = car(p);
83152 	  f2 = fx_proc(p);
83153 	  f3_arg = cadr(p);
83154 	  f3 = fx_proc(cdr(p));
83155 	  if (((stepf == fx_add_t1) || (stepf == fx_add_u1)) && (is_t_integer(slot_value(slot))))
83156 	    {
83157 	      s7_pointer ip;
83158 	      ip = make_mutable_integer(sc, integer(slot_value(slot)));
83159 	      slot_set_value(slot, ip);
83160 	      while ((f1(sc, f1_arg) == sc->F) &&
83161 		     ((f2(sc, f2_arg) == sc->F) || (f3(sc, f3_arg) == sc->F)))
83162 		integer(ip)++;
83163 	      clear_mutable_integer(ip);
83164 	    }
83165 	  else
83166 	    while ((f1(sc, f1_arg) == sc->F) &&
83167 		   ((f2(sc, f2_arg) == sc->F) || (f3(sc, f3_arg) == sc->F)))
83168 	      slot_set_value(slot, stepf(sc, step));
83169 	}
83170       else while (testf(sc, test) == sc->F) {slot_set_value(slot, stepf(sc, step));}
83171       sc->value = fx_call(sc, result);
83172     }
83173 }
83174 
83175 static void op_dox_pending_no_body(s7_scheme *sc)
83176 {
83177   s7_pointer let, vars, test, slots;
83178   bool all_steps = true;
83179 
83180   sc->code = cdr(sc->code);
83181   let = make_let(sc, sc->curlet);
83182   sc->temp1 = let;
83183   for (vars = car(sc->code); is_pair(vars); vars = cdr(vars))
83184     {
83185       add_slot(sc, let, caar(vars), fx_call(sc, cdar(vars)));
83186       if (is_pair(cddar(vars)))
83187 	slot_set_expression(let_slots(let), cddar(vars));
83188       else
83189 	{
83190 	  all_steps = false;
83191 	  slot_just_set_expression(let_slots(let), sc->nil);
83192 	}}
83193   slots = let_slots(let);
83194   sc->curlet = let;
83195   sc->temp1 = sc->nil;
83196   test = cadr(sc->code);
83197 
83198   let_set_has_pending_value(sc->curlet);
83199   if ((all_steps) &&
83200       (!tis_slot(next_slot(next_slot(slots)))) &&
83201       (is_pair(cdr(test))))
83202     {
83203       s7_pointer slot1, slot2, expr1, expr2;
83204       slot1 = slots;
83205       expr1 = slot_expression(slot1);
83206       slot2 = next_slot(slot1);
83207       expr2 = slot_expression(slot2);
83208       while (fx_call(sc, test) == sc->F)
83209 	{
83210 	  slot_simply_set_pending_value(slot1, fx_call(sc, expr1)); /* use pending_value for GC protection */
83211 	  slot_set_value(slot2, fx_call(sc, expr2));
83212 	  slot_set_value(slot1, slot_pending_value(slot1));
83213 	}
83214       sc->code = cdr(test);
83215       let_clear_has_pending_value(sc->curlet);
83216       return;
83217     }
83218 
83219   while ((sc->value = fx_call(sc, test)) == sc->F)
83220     {
83221       s7_pointer slt;
83222       slt = slots;
83223       do {
83224 	if (slot_has_expression(slt))
83225 	  slot_simply_set_pending_value(slt, fx_call(sc, slot_expression(slt)));
83226 	slt = next_slot(slt);
83227       } while (tis_slot(slt));
83228       slt = slots;
83229       do {
83230 	if (slot_has_expression(slt))
83231 	  slot_set_value(slt, slot_pending_value(slt));
83232 	slt = next_slot(slt);
83233       } while (tis_slot(slt));
83234     }
83235   sc->code = cdr(test);
83236   let_clear_has_pending_value(sc->curlet);
83237 }
83238 
83239 static bool op_do_no_vars(s7_scheme *sc)
83240 {
83241   s7_pointer p, form;
83242   int32_t i;
83243   opt_info *body[32];
83244   form = sc->code;
83245   sc->code = cdr(sc->code);
83246   sc->pc = 0;
83247 
83248   for (i = 0, p = cddr(sc->code); (is_pair(p)) && (i < 32); i++, p = cdr(p))
83249     {
83250       body[i] = sc->opts[sc->pc];
83251       if (!cell_optimize(sc, p))
83252 	break;
83253     }
83254   if (is_null(p))
83255     {
83256       s7_pointer end;
83257       end = cadr(sc->code);
83258       sc->curlet = make_let(sc, sc->curlet);
83259       if (i == 1)
83260 	{
83261 	  while ((sc->value = fx_call(sc, end)) == sc->F)
83262 	    body[0]->v[0].fp(body[0]);
83263 	  sc->code = cdr(end);
83264 	  return(true);
83265 	}
83266       if (i == 0) /* null body! */
83267 	{
83268 	  s7_function endf;
83269 	  s7_pointer endp;
83270 	  endf = fx_proc(end);
83271 	  endp = car(end);
83272 	  while (!is_true(sc, sc->value = endf(sc, endp))); /* the assignment is (normally) in the noise */
83273 	  sc->code = cdr(end);
83274 	  return(true);
83275 	}
83276       while ((sc->value = fx_call(sc, end)) == sc->F)
83277 	{
83278 	  int32_t k;
83279 	  for (k = 0; k < i; k++)
83280 	    body[k]->v[0].fp(body[k]);
83281 	}
83282       sc->code = cdr(end);
83283       return(true);
83284     }
83285   /* back out */
83286   pair_set_syntax_op(form, OP_DO_NO_VARS_NO_OPT);
83287   sc->curlet = make_let_slowly(sc, sc->curlet);
83288   sc->value = fx_call(sc, cadr(sc->code));
83289   if (is_true(sc, sc->value))
83290     {
83291       sc->code = cdadr(sc->code);
83292       return(true);
83293     }
83294   push_stack_no_args_direct(sc, OP_DO_NO_VARS_NO_OPT_1);
83295   sc->code = T_Pair(cddr(sc->code));
83296   return(false);
83297 }
83298 
83299 static void op_do_no_vars_no_opt(s7_scheme *sc)
83300 {
83301   sc->code = cdr(sc->code);
83302   sc->curlet = make_let(sc, sc->curlet);
83303 }
83304 
83305 static bool op_do_no_vars_no_opt_1(s7_scheme *sc)
83306 {
83307   sc->value = fx_call(sc, cadr(sc->code));
83308   if (is_true(sc, sc->value))
83309     {
83310       sc->code = cdadr(sc->code);
83311       return(true);
83312     }
83313   push_stack_no_args_direct(sc, OP_DO_NO_VARS_NO_OPT_1);
83314   sc->code = T_Pair(cddr(sc->code));
83315   return(false);
83316 }
83317 
83318 static void op_do_no_body_fx_vars(s7_scheme *sc)
83319 {
83320   s7_pointer let, vars, stepper = NULL;
83321   s7_int steppers = 0;
83322   sc->code = cdr(sc->code);
83323   let = make_let(sc, sc->curlet);
83324   sc->temp1 = let;
83325   for (vars = car(sc->code); is_pair(vars); vars = cdr(vars))
83326     {
83327       add_slot(sc, let, caar(vars), fx_call(sc, cdar(vars)));
83328       if (is_pair(cddar(vars)))
83329 	{
83330 	  slot_set_expression(let_slots(let), cddar(vars));
83331 	  steppers++;
83332 	  stepper = let_slots(let);
83333 	}
83334       else slot_just_set_expression(let_slots(let), sc->nil);
83335     }
83336   if (steppers == 1) let_set_dox_slot1(let, stepper);
83337   sc->curlet = let;
83338   sc->temp1 = sc->nil;
83339   push_stack_no_args_direct(sc, (intptr_t)((steppers == 1) ? OP_DO_NO_BODY_FX_VARS_STEP_1 : OP_DO_NO_BODY_FX_VARS_STEP));
83340   sc->code = caadr(sc->code);
83341 }
83342 
83343 static bool op_do_no_body_fx_vars_step(s7_scheme *sc)
83344 {
83345   s7_pointer slot;
83346   if (sc->value != sc->F)
83347     {
83348       sc->code = cdadr(sc->code);
83349       return(true);
83350     }
83351   for (slot = let_slots(sc->curlet); tis_slot(slot); slot = next_slot(slot))
83352     if (slot_has_expression(slot))
83353       slot_set_value(slot, fx_call(sc, slot_expression(slot)));
83354 
83355   push_stack_no_args_direct(sc, OP_DO_NO_BODY_FX_VARS_STEP);
83356   sc->code = caadr(sc->code);
83357   return(false);
83358 }
83359 
83360 static bool op_do_no_body_fx_vars_step_1(s7_scheme *sc)
83361 {
83362   if (sc->value != sc->F)
83363     {
83364       sc->code = cdadr(sc->code);
83365       return(true);
83366     }
83367   slot_set_value(let_dox_slot1(sc->curlet), fx_call(sc, slot_expression(let_dox_slot1(sc->curlet))));
83368   push_stack_no_args_direct(sc, OP_DO_NO_BODY_FX_VARS_STEP_1);
83369   sc->code = caadr(sc->code);
83370   return(false);
83371 }
83372 
83373 static bool do_step1(s7_scheme *sc)
83374 {
83375   while (true)
83376     {
83377       s7_pointer code;
83378       if (is_null(sc->args))
83379 	{
83380 	  s7_pointer x;
83381 	  for (x = sc->code; is_pair(x); x = cdr(x))   /* sc->code here is the original sc->args list */
83382 	    {
83383 	      slot_set_value(car(x), slot_pending_value(car(x)));
83384 	      slot_clear_has_pending_value(car(x));
83385 	    }
83386 	  pop_stack_no_op(sc);
83387 	  return(true);
83388 	}
83389       code = slot_expression(car(sc->args));
83390       if (has_fx(code))
83391 	{
83392 	  sc->value = fx_call(sc, code);
83393 	  slot_set_pending_value(car(sc->args), sc->value); /* consistently slower if slot_simply_set... here? */
83394 	  sc->args = cdr(sc->args);                   /* go to next step var */
83395 	}
83396       else
83397 	{
83398 	  push_stack_direct(sc, OP_DO_STEP2);
83399 	  sc->code = car(code);
83400 	  return(false);
83401 	}}
83402 }
83403 
83404 static bool op_do_step2(s7_scheme *sc)
83405 {
83406   if (is_multiple_value(sc->value))
83407     eval_error(sc, "do: variable step value can't be ~S", 35, set_ulist_1(sc, sc->values_symbol, sc->value));
83408   slot_set_pending_value(car(sc->args), sc->value);  /* save current value */
83409   sc->args = cdr(sc->args);                   /* go to next step var */
83410   return(do_step1(sc));
83411 }
83412 
83413 static bool op_do_step(s7_scheme *sc)
83414 {
83415   /* increment all vars, return to endtest
83416    *   these are also updated in parallel at the end, so we gather all the incremented values first
83417    *
83418    * here we know car(sc->args) is not null, args is the list of steppable vars,
83419    *   any unstepped vars in the do var section are not in this list, so
83420    *   (do ((i 0 (+ i 1)) (j 2)) ...) arrives here with sc->args: '(slot<((+ i 1)=expr, 0=pending_value>))
83421    */
83422   push_stack_direct(sc, OP_DO_END);
83423   sc->args = car(sc->args);                /* the var data lists */
83424   sc->code = sc->args;                     /* save the top of the list */
83425   return(do_step1(sc));
83426 }
83427 
83428 static goto_t do_end_code(s7_scheme *sc)
83429 {
83430   if (is_pair(cdr(sc->code)))
83431     {
83432       if ((car(sc->code) == sc->feed_to_symbol) &&
83433 	  (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
83434 	return(goto_feed_to);
83435       /* never has_fx(sc->code) here (first of a body) */
83436       push_stack_no_args(sc, sc->begin_op, cdr(sc->code));
83437       sc->code = car(sc->code);
83438       return(goto_eval);
83439     }
83440   if (has_fx(sc->code))
83441     {
83442       sc->value = fx_call(sc, sc->code);
83443       return(goto_start);
83444     }
83445   sc->code = T_Pair(car(sc->code));
83446   return(goto_eval);
83447 }
83448 
83449 static bool do_end_clauses(s7_scheme *sc)
83450 {
83451   if (is_null(sc->code))
83452     {
83453       if (is_multiple_value(sc->value))
83454 	sc->value = splice_in_values(sc, multiple_value(sc->value));
83455       return(true);
83456     }
83457   return(false);
83458 }
83459 
83460 static bool opt_do_copy(s7_scheme *sc, opt_info *o, s7_int start, s7_int stop)
83461 {
83462   s7_pointer (*fp)(opt_info *o);
83463 
83464   if (start >= stop) return(true);
83465   fp = o->v[0].fp;                            /* o->v[6].p_pi_f is getter, o->v[5].p_pip_f is setter */
83466   if ((fp == opt_p_pip_sso) &&
83467       (type(slot_value(o->v[1].p)) == type(slot_value(o->v[3].p))) &&
83468       (o->v[2].p == o->v[4].p))
83469     {
83470       s7_pointer dest, source;
83471       dest = slot_value(o->v[1].p);
83472       source = slot_value(o->v[3].p);
83473       if ((is_normal_vector(dest)) &&
83474 	  ((o->v[5].p_pip_f == vector_set_p_pip_unchecked) &&
83475 	   ((o->v[6].p_pi_f == normal_vector_ref_p_pi_unchecked) || (o->v[6].p_pi_f == vector_ref_p_pi_unchecked))))
83476 	{
83477 	  if (start < 0)
83478 	    return(out_of_range(sc, sc->vector_set_symbol, wrap_integer1(sc, 2), wrap_integer2(sc, start), its_negative_string));
83479 	  if (stop > vector_length(source))
83480 	    return(out_of_range(sc, sc->vector_ref_symbol, wrap_integer1(sc, 2), wrap_integer2(sc, stop), its_too_large_string));
83481 	  if (stop > vector_length(dest))
83482 	    return(out_of_range(sc, sc->vector_set_symbol, wrap_integer1(sc, 2), wrap_integer2(sc, stop), its_too_large_string));
83483 	}
83484       else
83485 	{
83486 	  if ((is_string(dest)) &&
83487 	      ((o->v[5].p_pip_f == string_set_p_pip_unchecked) && (o->v[6].p_pi_f == string_ref_p_pi_unchecked)))
83488 	    {
83489 	      if (start < 0)
83490 		return(out_of_range(sc, sc->string_set_symbol, wrap_integer1(sc, 2), wrap_integer2(sc, start), its_negative_string));
83491 	      if (stop > string_length(source))
83492 		return(out_of_range(sc, sc->string_ref_symbol, wrap_integer1(sc, 2), wrap_integer2(sc, stop), its_too_large_string));
83493 	      if (stop > string_length(dest))
83494 		return(out_of_range(sc, sc->string_set_symbol, wrap_integer1(sc, 2), wrap_integer2(sc, stop), its_too_large_string));
83495 	    }
83496 	  else return(false); /* pair copy needs length here and is kinda stupid in this context */
83497 	}
83498       /* float|int|byte-vectors are in opt_dotimes below (opt_float|int_any_nr loops, but I don't think they matter -- s7 users know about copy! */
83499       if (copy_to_same_type(sc, dest, source, start, stop, start))
83500 	return(true);
83501     }
83502   return(false);
83503 }
83504 
83505 static bool op_simple_do_1(s7_scheme *sc, s7_pointer code)
83506 {
83507   s7_pointer body, step_expr, step_var, ctr_slot, end_slot;
83508   s7_function stepf, endf;
83509   s7_function func;
83510 
83511   code = cdr(code);
83512   body = caddr(code);
83513 
83514   if (no_cell_opt(cddr(code)))
83515     return(false);
83516 
83517   func = s7_optimize_nr(sc, cddr(code));
83518   if (!func)
83519     {
83520       set_no_cell_opt(cddr(code));
83521       return(false);
83522     }
83523 
83524   /* func must be set */
83525   step_expr = caddr(caar(code));
83526   stepf = fn_proc(step_expr);
83527   endf = fn_proc(caadr(code));
83528   ctr_slot = let_dox_slot1(sc->curlet);
83529   end_slot = let_dox_slot2(sc->curlet);
83530   step_var = caddr(step_expr);
83531   /* use g* funcs (not fx) because we're passing the actual values, not the expressions */
83532 
83533   if ((stepf == g_add_x1) &&
83534       (is_t_integer(slot_value(ctr_slot))) &&
83535       ((endf == g_num_eq_2) || (endf == g_num_eq_xi) || (endf == g_geq_2)) &&
83536       (is_t_integer(slot_value(end_slot))))
83537     {
83538       s7_int i, start, stop;
83539       start = integer(slot_value(ctr_slot));
83540       stop = integer(slot_value(end_slot));
83541 
83542       if (func == opt_cell_any_nr)
83543 	{
83544 	  opt_info *o;
83545 	  s7_pointer (*fp)(opt_info *o);
83546 	  o = sc->opts[0];
83547 	  fp = o->v[0].fp;
83548 	  if ((fp == opt_p_ppp_sss) || (fp == opt_p_ppp_sss_mul) || (fp == opt_p_ppp_sss_hset))
83549 	    {
83550 	      s7_p_ppp_t fpt;
83551 	      fpt = o->v[4].p_ppp_f;
83552 	      for (i = start; i < stop; i++)
83553 		{
83554 		  slot_set_value(ctr_slot, make_integer(sc, i));
83555 		  fpt(sc, slot_value(o->v[1].p), slot_value(o->v[2].p), slot_value(o->v[3].p));
83556 		}}
83557 	  else
83558 	    {
83559 	      if (fp == opt_p_ppp_sfs)
83560 		{
83561 		  s7_p_ppp_t fpt;
83562 		  fpt = o->v[3].p_ppp_f;
83563 		  for (i = start; i < stop; i++)
83564 		    {
83565 		      slot_set_value(ctr_slot, make_integer(sc, i));
83566 		      fpt(sc, slot_value(o->v[1].p), o->v[5].fp(o->v[4].o1), slot_value(o->v[2].p));
83567 		    }}
83568 	      else
83569 		for (i = start; i < stop; i++)
83570 		  {
83571 		    slot_set_value(ctr_slot, make_integer(sc, i));
83572 		    fp(o);
83573 		  }}}
83574       else
83575 	/* splitting out opt_float_any_nr here saves almost nothing */
83576 	for (i = start; i < stop; i++)
83577 	  {
83578 	    slot_set_value(ctr_slot, make_integer(sc, i));
83579 	    func(sc, body);
83580 	  }
83581       sc->value = sc->T;
83582       sc->code = cdadr(code);
83583       return(true);
83584     }
83585 
83586   if ((stepf == g_subtract_x1) &&
83587       (is_t_integer(slot_value(ctr_slot))) &&
83588       ((endf == g_less_x0) || (endf == g_less_2) || (endf == g_less_xi)) &&
83589       (is_t_integer(slot_value(end_slot))))
83590     {
83591       s7_int i, start, stop;
83592       start = integer(slot_value(ctr_slot));
83593       stop = integer(slot_value(end_slot));
83594 
83595       if (func == opt_cell_any_nr)
83596 	{
83597 	  opt_info *o;
83598 	  o = sc->opts[0];
83599 	  if (!opt_do_copy(sc, o, stop, start + 1))
83600 	    {
83601 	      s7_pointer (*fp)(opt_info *o);
83602 	      fp = o->v[0].fp;
83603 	      for (i = start; i >= stop; i--)
83604 		{
83605 		  slot_set_value(ctr_slot, make_integer(sc, i));
83606 		  fp(o);
83607 		}}}
83608       else
83609 	for (i = start; i >= stop; i--)
83610 	  {
83611 	    slot_set_value(ctr_slot, make_integer(sc, i));
83612 	    func(sc, body);
83613 	  }
83614       sc->value = sc->T;
83615       sc->code = cdadr(code);
83616       return(true);
83617     }
83618 
83619   if ((stepf == g_add_2_xi) &&
83620       (is_t_integer(slot_value(ctr_slot))) &&
83621       ((endf == g_num_eq_2) || (endf == g_num_eq_xi) || (endf == g_geq_2)) &&
83622       (is_t_integer(slot_value(end_slot))))
83623     {
83624       s7_int i, start, stop, incr;
83625       start = integer(slot_value(ctr_slot));
83626       stop = integer(slot_value(end_slot));
83627       incr = integer(caddr(step_expr));
83628       if (func == opt_cell_any_nr)
83629 	{
83630 	  s7_pointer (*fp)(opt_info *o);
83631 	  opt_info *o;
83632 	  o = sc->opts[0];
83633 	  fp = o->v[0].fp;
83634 	  for (i = start; i < stop; i += incr)
83635 	    {
83636 	      slot_set_value(ctr_slot, make_integer(sc, i));
83637 	      fp(o);
83638 	    }}
83639       else
83640 	for (i = start; i < stop; i += incr)
83641 	  {
83642 	    slot_set_value(ctr_slot, make_integer(sc, i));
83643 	    func(sc, body);
83644 	  }
83645       sc->value = sc->T;
83646       sc->code = cdadr(code);
83647       return(true);
83648     }
83649 
83650   if (func == opt_cell_any_nr)
83651     {
83652       opt_info *o;
83653       s7_pointer (*fp)(opt_info *o);
83654       o = sc->opts[0];
83655       fp = o->v[0].fp;
83656       if ((stepf == g_add_x1) && (is_t_integer(slot_value(ctr_slot))) &&
83657 	  (endf == g_greater_2) && (is_t_integer(slot_value(end_slot))))
83658 	{
83659 	  s7_int i, start, stop;
83660 	  start = integer(slot_value(ctr_slot));
83661 	  stop = integer(slot_value(end_slot));
83662 	  for (i = start; i <= stop; i++)
83663 	    {
83664 	      slot_set_value(ctr_slot, make_integer(sc, i));
83665 	      fp(o);
83666 	    }}
83667       else
83668 	{
83669 	  do {
83670 	    fp(o);
83671 
83672 	    set_car(sc->t2_1, slot_value(ctr_slot));
83673 	    set_car(sc->t2_2, step_var);
83674 	    slot_set_value(ctr_slot, stepf(sc, sc->t2_1));
83675 
83676 	    set_car(sc->t2_1, slot_value(ctr_slot));
83677 	    set_car(sc->t2_2, slot_value(end_slot));
83678 	  } while ((sc->value = endf(sc, sc->t2_1)) == sc->F);
83679 	}}
83680   else
83681     do {
83682 	func(sc, body);
83683 
83684 	set_car(sc->t2_1, slot_value(ctr_slot));
83685 	set_car(sc->t2_2, step_var);
83686 	slot_set_value(ctr_slot, stepf(sc, sc->t2_1));
83687 
83688 	set_car(sc->t2_1, slot_value(ctr_slot));
83689 	set_car(sc->t2_2, slot_value(end_slot));
83690       } while ((sc->value = endf(sc, sc->t2_1)) == sc->F);
83691 
83692   sc->code = cdadr(code);
83693   return(true);
83694 }
83695 
83696 static bool op_simple_do(s7_scheme *sc)
83697 {
83698   /* body might not be safe in this case, but the step and end exprs are easy
83699    * simple_do: set up local let, check end (c_c?), goto op_simple_do_1
83700    *   if latter gets s7_optimize, run locally, else goto simple_do_step.
83701    */
83702   s7_pointer end, code, body;
83703 
83704   code = cdr(sc->code);
83705   sc->curlet = make_let_slowly(sc, sc->curlet);
83706   sc->value = fx_call(sc, cdaar(code));
83707   let_set_dox_slot1(sc->curlet, make_slot_2(sc, sc->curlet, caaar(code), sc->value));
83708 
83709   end = caddr(caadr(code));
83710   if (is_symbol(end))
83711     let_set_dox_slot2(sc->curlet, lookup_slot_from(end, sc->curlet));
83712   else let_set_dox_slot2(sc->curlet, make_slot(sc, caaar(code), end));
83713 
83714   set_car(sc->t2_1, let_dox1_value(sc->curlet));
83715   set_car(sc->t2_2, let_dox2_value(sc->curlet));
83716   sc->value = fn_proc(caadr(code))(sc, sc->t2_1);
83717   if (is_true(sc, sc->value))
83718     {
83719       sc->code = cdadr(code);
83720       return(true); /* goto DO_END_CLAUSES */
83721     }
83722   body = cddr(code);
83723   if ((is_null(cdr(body))) &&             /* one expr in body */
83724       (is_pair(car(body))) &&             /*   and it is a pair */
83725       (is_symbol(cadaddr(caar(code)))) && /* caar=(i 0 (+ i 1)), caddr=(+ i 1), so this is apparently checking that the stepf is reasonable? */
83726       (is_t_integer(caddaddr(caar(code)))) &&
83727       (op_simple_do_1(sc, sc->code)))
83728     return(true);                         /* goto DO_END_CLAUSES */
83729 
83730   push_stack_no_args(sc, OP_SIMPLE_DO_STEP, code);
83731   sc->code = body;
83732   return(false); /* goto BEGIN */
83733 }
83734 
83735 static bool op_simple_do_step(s7_scheme *sc)
83736 {
83737   s7_pointer step, ctr, end, code;
83738   ctr = let_dox_slot1(sc->curlet);
83739   end = let_dox_slot2(sc->curlet);
83740   code = sc->code;
83741 
83742   step = caddr(caar(code));
83743   if (is_symbol(cadr(step)))
83744     {
83745       set_car(sc->t2_1, slot_value(ctr));
83746       set_car(sc->t2_2, caddr(step));
83747     }
83748   else
83749     {
83750       set_car(sc->t2_2, slot_value(ctr));
83751       set_car(sc->t2_1, cadr(step));
83752     }
83753   slot_set_value(ctr, fn_proc(step)(sc, sc->t2_1));
83754 
83755   set_car(sc->t2_1, slot_value(ctr));
83756   set_car(sc->t2_2, slot_value(end));
83757   end = cadr(code);
83758   sc->value = fn_proc(car(end))(sc, sc->t2_1);
83759 
83760   if (is_true(sc, sc->value))
83761     {
83762       sc->code = cdr(end);
83763       return(true);
83764     }
83765 
83766   push_stack_direct(sc, OP_SIMPLE_DO_STEP);
83767   sc->code = T_Pair(cddr(code));
83768   return(false);
83769 }
83770 
83771 static bool op_safe_do_step(s7_scheme *sc)
83772 {
83773   s7_int step, end;
83774   s7_pointer slot;
83775 
83776   slot = let_dox_slot1(sc->curlet);
83777   end = integer(let_dox2_value(sc->curlet));
83778 
83779   step = integer(slot_value(slot)) + 1;
83780   slot_set_value(slot, make_integer(sc, step));
83781   if ((step == end) ||
83782       ((step > end) &&
83783        (opt1_cfunc(caadr(sc->code)) == sc->geq_2)))
83784     {
83785       sc->value = sc->T;
83786       sc->code = cdadr(sc->code);
83787       return(true);
83788     }
83789   push_stack_direct(sc, OP_SAFE_DO_STEP);
83790   sc->code = T_Pair(opt2_pair(sc->code));
83791   return(false);
83792 }
83793 
83794 static bool op_safe_dotimes_step(s7_scheme *sc)
83795 {
83796   s7_pointer arg;
83797   arg = slot_value(sc->args);
83798   numerator(arg)++;
83799   if (numerator(arg) == denominator(arg))
83800     {
83801       sc->value = sc->T;
83802       sc->code = cdadr(sc->code);
83803       return(true);
83804     }
83805   push_stack_direct(sc, OP_SAFE_DOTIMES_STEP);
83806   sc->code = opt2_pair(sc->code); /* here we know the body has more than one form */
83807   push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(sc->code)));
83808   sc->code = car(sc->code);
83809   return(false);
83810 }
83811 
83812 static bool op_safe_dotimes_step_o(s7_scheme *sc)
83813 {
83814   s7_pointer arg;
83815   arg = slot_value(sc->args);
83816   numerator(arg)++;
83817   if (numerator(arg) == denominator(arg))
83818     {
83819       sc->value = sc->T;
83820       sc->code = cdadr(sc->code);
83821       return(true);
83822     }
83823   push_stack_direct(sc, OP_SAFE_DOTIMES_STEP_O);
83824   sc->code = opt2_pair(sc->code);
83825   return(false);
83826 }
83827 
83828 static Inline bool op_dotimes_step_o(s7_scheme *sc)
83829 {
83830   s7_pointer ctr, now, end, end_test, code;
83831   code = sc->code;
83832   ctr = let_dox_slot1(sc->curlet);
83833   now = slot_value(ctr);
83834   end = let_dox2_value(sc->curlet);
83835   end_test = opt2_pair(code);
83836 
83837   if (is_t_integer(now))
83838     {
83839       slot_set_value(ctr, make_integer(sc, integer(now) + 1));
83840       now = slot_value(ctr);
83841       if (is_t_integer(end))
83842 	{
83843 	  if ((integer(now) == integer(end)) ||
83844 	      ((integer(now) > integer(end)) &&
83845 	       (opt1_cfunc(end_test) == sc->geq_2)))
83846 	    {
83847 	      sc->value = sc->T;
83848 	      sc->code = cdadr(code);
83849 	      return(true);
83850 	    }}
83851       else
83852 	{
83853 	  set_car(sc->t2_1, now);
83854 	  set_car(sc->t2_2, end);
83855 	  end = cadr(code);
83856 	  sc->value = fn_proc(car(end))(sc, sc->t2_1);
83857 	  if (is_true(sc, sc->value))
83858 	    {
83859 	      sc->code = cdr(end);
83860 	      return(true);
83861 	    }}}
83862   else
83863     {
83864       set_car(sc->t1_1, now);
83865       slot_set_value(ctr, g_add_x1(sc, sc->t1_1));
83866       /* (define (hi) (let ((x 0.0) (y 1.0)) (do ((i y (+ i 1))) ((= i 6)) (do ((i i (+ i 1))) ((>= i 7)) (set! x (+ x i)))) x)) */
83867       set_car(sc->t2_1, slot_value(ctr));
83868       set_car(sc->t2_2, end);
83869       end = cadr(code);
83870       sc->value = fn_proc(car(end))(sc, sc->t2_1);
83871       if (is_true(sc, sc->value))
83872 	{
83873 	  sc->code = cdr(end);
83874 	  return(true);
83875 	}}
83876   push_stack_direct(sc, OP_DOTIMES_STEP_O);
83877   sc->code = caddr(code);
83878   return(false);
83879 }
83880 
83881 static bool opt_dotimes(s7_scheme *sc, s7_pointer code, s7_pointer scc, bool safe_step)
83882 {
83883   s7_int end;
83884   end = denominator(slot_value(sc->args)); /* s7_optimize below can step on this value! */
83885 
83886   if (safe_step)
83887     set_safe_stepper(sc->args);
83888   else set_safe_stepper(let_dox_slot1(sc->curlet));
83889   /* I think safe_step means the stepper is completely unproblematic */
83890 
83891   if (is_null(cdr(code)))
83892     {
83893       s7_function func;
83894 
83895       if (no_cell_opt(code)) return(false);
83896       func = s7_optimize_nr(sc, code);
83897       if (!func)
83898 	{
83899 	  set_no_cell_opt(code);
83900 	  return(false);
83901 	}
83902       if (safe_step)
83903 	{
83904 	  s7_pointer stepper;
83905 	  slot_set_value(sc->args, stepper = make_mutable_integer(sc, integer(slot_value(sc->args))));
83906 	  if ((func == opt_float_any_nr) ||
83907 	      (func == opt_cell_any_nr))
83908 	    {
83909 	      opt_info *o;
83910 	      o = sc->opts[0];
83911 	      if (func == opt_float_any_nr)
83912 		{
83913 		  s7_double (*fd)(opt_info *o);
83914 		  fd = o->v[0].fd;
83915 		  if ((fd == opt_d_id_sf) && /* by far the most common case in clm: (outa i ...) etc */
83916 		      (is_slot(o->v[1].p)) &&
83917 		      (stepper == slot_value(o->v[1].p)))
83918 		    {
83919 		      opt_info *o1;
83920 		      s7_int end8;
83921 		      s7_d_id_t f0;
83922 		      f0 = o->v[3].d_id_f;
83923 		      o1 = sc->opts[1];
83924 		      fd = o1->v[0].fd;
83925 		      end8 = end - 8;
83926 		      while (integer(stepper) < end8)
83927 			LOOP_8(f0(integer(stepper), fd(o1)); integer(stepper)++);
83928 		      while (integer(stepper) < end)
83929 			{
83930    			  f0(integer(stepper), fd(o1));
83931 			  integer(stepper)++;
83932 			}}
83933 		  else
83934 		    for (; integer(stepper) < end; integer(stepper)++)
83935 		      fd(o);
83936 		}
83937 	      else
83938 		{
83939 		  s7_pointer (*fp)(opt_info *o);
83940 		  fp = o->v[0].fp;
83941 		  if ((fp == opt_p_pip_ssc) &&                     /* or any opt without f? */
83942 		      (stepper == slot_value(o->v[2].p)) &&        /* i.e. index by do counter */
83943 		      (o->v[3].p_pip_f == string_set_unchecked) && /* or any similar setter? */
83944 		      (end <= string_length(slot_value(o->v[1].p))))
83945 		    {
83946 		      char *str;
83947 		      str = (char *)(string_value(slot_value(o->v[1].p) + integer(stepper)));
83948 		      local_memset((void *)str, character(o->v[4].p), end - integer(stepper));
83949 		      integer(stepper) = end;
83950 		    }
83951 		  else
83952 		    {
83953 		      if (fp == opt_if_bp)
83954 			fp = opt_if_bp_nr;
83955 		      else
83956 			if (fp == opt_if_nbp_fs)
83957 			  fp = opt_if_nbp_fs_nr;
83958 		      for (; integer(stepper) < end; integer(stepper)++)
83959 			fp(o);
83960 		    }}}
83961 	  else
83962 	    {
83963 	      if (func == opt_int_any_nr)
83964 		{
83965 		  s7_int (*fi)(opt_info *o);
83966 		  opt_info *o;
83967 		  o = sc->opts[0];
83968 		  fi = o->v[0].fi;
83969 		  if ((fi == opt_i_7pii_ssc) &&
83970 		      (stepper == slot_value(o->v[2].p)) &&
83971 		      (o->v[3].i_7pii_f == int_vector_set_unchecked) &&
83972 		      (end <= vector_length(slot_value(o->v[1].p))))
83973 		    {
83974 		      s7_int val;
83975 		      s7_int *ex;
83976 		      ex = int_vector_ints(slot_value(o->v[1].p));
83977 		      val = o->v[4].i;
83978 		      if (val == 0)
83979 			{
83980 			  memclr((void *)(ex + integer(stepper)), (end - integer(stepper)) * sizeof(s7_int)); /* memclr64 assumes multiple of 8 */
83981 			  integer(stepper) = end;
83982 			}
83983 		      else
83984 			for (; integer(stepper) < end; integer(stepper)++)
83985 			  ex[integer(stepper)] = val;
83986 		    }
83987 		  else
83988 		    for (; integer(stepper) < end; integer(stepper)++)
83989 		      fi(o);
83990 		  /* if fi = opt_i_i_s for example, -> o->v[2].i_i_f(integer(slot_value(o->v[1].p)))
83991 		   *   and o->v[2].i_i_f can be pulled out leaving a loop of ov2(integer(slot_value(o->v[1].p)));
83992 		   */
83993 		}
83994 	      else
83995 		for (; integer(stepper) < end; integer(stepper)++)
83996 		  func(sc, car(code));
83997 	    }
83998 	  clear_mutable_integer(stepper);
83999 	}
84000       else /* not safe_step */
84001 	{
84002 	  s7_int step;
84003 	  s7_pointer step_slot, end_slot;
84004 	  step_slot = let_dox_slot1(sc->curlet);
84005 	  end_slot = let_dox_slot2(sc->curlet);
84006 	  step = integer(slot_value(step_slot));
84007 
84008 	  if (func == opt_cell_any_nr)
84009 	    {
84010 	      opt_info *o;
84011 	      s7_pointer (*fp)(opt_info *o);
84012 	      o = sc->opts[0];
84013 	      fp = o->v[0].fp;
84014 	      if (!opt_do_copy(sc, o, step, integer(slot_value(end_slot))))
84015 		{
84016 		  if ((step >= 0) && (integer(slot_value(end_slot)) < NUM_SMALL_INTS))
84017 		    while (step < integer(slot_value(end_slot)))
84018 		      {
84019 			slot_set_value(step_slot, small_int(step));
84020 			fp(o);
84021 			step = integer(slot_value(step_slot)) + 1;
84022 		      }
84023 		  else
84024 		    while (step < integer(slot_value(end_slot)))
84025 		      {
84026 			slot_set_value(step_slot, make_integer(sc, step));
84027 			fp(o);
84028 			step = integer(slot_value(step_slot)) + 1;
84029 		      }}}
84030 	  else
84031 	    {
84032 	      if ((step >= 0) && (integer(slot_value(end_slot)) < NUM_SMALL_INTS))
84033 		while (step < integer(slot_value(end_slot)))
84034 		  {
84035 		    slot_set_value(step_slot, small_int(step));
84036 		    func(sc, car(code));
84037 		    step = integer(slot_value(step_slot)) + 1;
84038 		  }
84039 	      else
84040 		while (step < integer(slot_value(end_slot)))
84041 		  {
84042 		    slot_set_value(step_slot, make_integer(sc, step));
84043 		    func(sc, car(code));
84044 		    step = integer(slot_value(step_slot)) + 1;
84045 		  }}}
84046       sc->value = sc->T;
84047       sc->code = cdadr(scc);
84048       return(true);
84049     }
84050 
84051   {
84052     s7_pointer p;
84053     s7_int body_len;
84054     opt_info *body[32];
84055     int32_t k;
84056 
84057     body_len = s7_list_length(sc, code);
84058     sc->pc = 0;
84059     if (body_len >= 32) return(false);
84060 
84061     if (!no_float_opt(code))
84062       {
84063 	for (k = 0, p = code; is_pair(p); k++, p = cdr(p))
84064 	  {
84065 	    body[k] = sc->opts[sc->pc];
84066 	    if (!float_optimize(sc, p))
84067 	      break;
84068 	  }
84069 	if (is_pair(p))
84070 	  {
84071 	    pc_fallback(sc, 0);
84072 	    set_no_float_opt(code);
84073 	  }
84074 	else
84075 	  {
84076 	    int32_t i;
84077 	    end = denominator(slot_value(sc->args));
84078 	    if (safe_step)
84079 	      {
84080 		s7_pointer stepper;
84081 		slot_set_value(sc->args, stepper = make_mutable_integer(sc, integer(slot_value(sc->args))));
84082 		for (; integer(stepper) < end; integer(stepper)++)
84083 		  for (i = 0; i < body_len; i++)
84084 		    body[i]->v[0].fd(body[i]);
84085 		clear_mutable_integer(stepper);
84086 	      }
84087 	    else
84088 	      {
84089 		s7_pointer step_slot, end_slot;
84090 		s7_int step;
84091 		step_slot = let_dox_slot1(sc->curlet);
84092 		end_slot = let_dox_slot2(sc->curlet);
84093 		for (step = integer(slot_value(step_slot)); step < integer(slot_value(end_slot)); step = integer(slot_value(step_slot)) + 1)
84094 		  {
84095 		    slot_set_value(step_slot, make_integer(sc, step));
84096 		    for (i = 0; i < body_len; i++)
84097 		      body[i]->v[0].fd(body[i]);
84098 		  }}
84099 	    sc->value = sc->T;
84100 	    sc->code = cdadr(scc);
84101 	    return(true);
84102 	  }}
84103 
84104     /* not float opt */
84105     sc->pc = 0;
84106     for (k = 0, p = code; is_pair(p); k++, p = cdr(p))
84107       {
84108 	opt_info *start;
84109 	start = sc->opts[sc->pc];
84110 	if (!cell_optimize(sc, p))
84111 	  break;
84112 	if (start->v[0].fp == d_to_p)
84113 	  start->v[0].fp = d_to_p_nr;
84114 	body[k] = start;
84115       }
84116 
84117     if (is_null(p))
84118       {
84119 	int32_t i;
84120 	end = denominator(slot_value(sc->args));
84121 	if (safe_step)
84122 	  {
84123 	    s7_pointer stepper;
84124 	    slot_set_value(sc->args, stepper = make_mutable_integer(sc, integer(slot_value(sc->args))));
84125 	    for (; integer(stepper) < end; integer(stepper)++)
84126 	      for (i = 0; i < body_len; i++)
84127 		body[i]->v[0].fp(body[i]);
84128 	    clear_mutable_integer(stepper);
84129 	  }
84130 	else
84131 	  {
84132 	    s7_pointer step_slot, end_slot;
84133 	    s7_int step;
84134 	    step_slot = let_dox_slot1(sc->curlet);
84135 	    end_slot = let_dox_slot2(sc->curlet);
84136 	    for (step = integer(slot_value(step_slot)); step < integer(slot_value(end_slot)); step = integer(slot_value(step_slot)) + 1)
84137 	      {
84138 		slot_set_value(step_slot, make_integer(sc, step));
84139 		for (i = 0; i < body_len; i++)
84140 		  body[i]->v[0].fp(body[i]);
84141 	      }}
84142 	sc->value = sc->T;
84143 	sc->code = cdadr(scc);
84144 	return(true);
84145       }}
84146   return(false);
84147 }
84148 
84149 static goto_t do_let(s7_scheme *sc, s7_pointer step_slot, s7_pointer scc)
84150 {
84151   s7_pointer let_body, p = NULL, let_vars, let_code, ip;
84152   bool let_star;
84153   s7_pointer old_e, stepper;
84154   s7_int body_len, var_len, k, end;
84155   #define O_SIZE 32
84156   opt_info *body[O_SIZE], *vars[O_SIZE];
84157 
84158   memset((void *)body, 0, O_SIZE * sizeof(opt_info *)); /* placate the damned compiler */
84159   memset((void *)vars, 0, O_SIZE * sizeof(opt_info *));
84160 
84161   /* do_let with non-float vars doesn't get many fixable hits */
84162   let_code = caddr(scc);
84163   if ((!is_pair(cdr(let_code))) || (!is_list(cadr(let_code)))) /* (do ((j 0 (+ j 1))) ((= j 1)) (let name 123)) */
84164     return(fall_through);
84165   let_body = cddr(let_code);
84166   body_len = s7_list_length(sc, let_body);
84167   if ((body_len <= 0) || (body_len >= 32)) return(fall_through);
84168   let_star = (symbol_syntax_op_checked(let_code) == OP_LET_STAR);
84169   let_vars = cadr(let_code);
84170   set_safe_stepper(step_slot);
84171   stepper = slot_value(step_slot);
84172 
84173   old_e = sc->curlet;
84174   sc->curlet = make_let_slowly(sc, sc->curlet);
84175 
84176   sc->pc = 0;
84177   for (var_len = 0, p = let_vars; (is_pair(p)) && (var_len < 32); var_len++, p = cdr(p))
84178     {
84179       s7_pointer expr;
84180       if ((!is_pair(car(p))) ||
84181 	  (!is_normal_symbol(caar(p))) ||
84182 	  (!is_pair(cdar(p))))
84183 	return(fall_through);
84184       expr = cdar(p);
84185       vars[var_len] = sc->opts[sc->pc];
84186       if (!float_optimize(sc, expr))   /* each of these needs to set the associated variable */
84187 	{
84188 	  sc->curlet = old_e;
84189 	  return(fall_through);
84190 	}
84191       if (let_star)
84192 	make_slot_2(sc, sc->curlet, caar(p), s7_make_mutable_real(sc, 1.5));
84193     }
84194 
84195   if (!let_star)
84196     for (p = let_vars; is_pair(p); p = cdr(p))
84197       make_slot_2(sc, sc->curlet, caar(p), s7_make_mutable_real(sc, 1.5));
84198 
84199   for (k = 0, p = let_body; is_pair(p); k++, p = cdr(p))
84200     {
84201       body[k] = sc->opts[sc->pc];
84202       if (!float_optimize(sc, p))
84203 	{
84204 	  sc->curlet = old_e;
84205 	  return(fall_through);
84206 	}}
84207   if (!is_null(p)) /* no hits in s7test or snd-test */
84208     {
84209       sc->curlet = old_e;
84210       return(fall_through);
84211     }
84212 
84213   end = denominator(stepper);
84214   let_set_slots(sc->curlet, reverse_slots(sc, let_slots(sc->curlet)));
84215   ip = slot_value(step_slot);
84216 
84217   if (body_len == 1)
84218     {
84219       if (var_len == 1)
84220 	{
84221 	  s7_pointer xp;
84222 	  opt_info *first, *o;
84223 	  s7_double (*f1)(opt_info *o);
84224 	  s7_double (*f2)(opt_info *o);
84225 	  xp = t_lookup(sc, caar(let_vars), let_vars);
84226 	  first = sc->opts[0];
84227 	  f1 = first->v[0].fd;
84228 	  integer(ip) = numerator(stepper);
84229 	  set_real(xp, f1(first));
84230 	  o = body[0];
84231 	  f2 = o->v[0].fd;
84232 	  f2(o);
84233 	  if ((f2 == opt_fmv) &&
84234 	      (f1 == opt_d_dd_ff_o2) &&
84235 	      (first->v[3].d_dd_f == add_d_dd) &&
84236 	      (slot_symbol(step_slot) == slot_symbol(o->v[2].p)))
84237 	    {
84238 	      opt_info *o1, *o2, *o3;
84239 	      s7_d_v_t vf1, vf2, vf3, vf4;
84240 	      s7_d_vd_t vf5, vf6;
84241 	      s7_d_vid_t vf7;
84242 	      void *obj1, *obj2, *obj3, *obj4, *obj5, *obj6, *obj7;
84243 	      o1 = o->v[12].o1;
84244 	      o2 = o->v[13].o1;
84245 	      o3 = o->v[14].o1;
84246 	      vf1 = first->v[4].d_v_f;
84247 	      vf2 = first->v[5].d_v_f;
84248 	      vf3 = o1->v[2].d_v_f;
84249 	      vf4 = o3->v[5].d_v_f;
84250 	      vf5 = o2->v[3].d_vd_f;
84251 	      vf6 = o3->v[6].d_vd_f;
84252 	      vf7 = o->v[4].d_vid_f;
84253 	      obj1 = first->v[1].obj;
84254 	      obj2 = first->v[2].obj;
84255 	      obj3 = o1->v[1].obj;
84256 	      obj4 = o3->v[1].obj;
84257 	      obj5 = o->v[5].obj;
84258 	      obj6 = o2->v[5].obj;
84259 	      obj7 = o3->v[2].obj;
84260 
84261 	      for (k = numerator(stepper) + 1; k < end; k++)
84262 		{
84263 		  s7_double amp_env, vib;
84264 		  vib = vf1(obj1) + vf2(obj2);
84265 		  amp_env = vf3(obj3);
84266 		  vf7(obj5, k, amp_env * vf5(obj6, vib + (vf4(obj4) * vf6(obj7, vib))));
84267 		}}
84268 	  else
84269 	    for (k = numerator(stepper) + 1; k < end; k++)
84270 	      {
84271 		integer(ip) = k;
84272 		set_real(xp, f1(first));
84273 		f2(o);
84274 	      }} /* body_len == 1 and var_len == 1 */
84275       else
84276 	{
84277 	  if (var_len == 2)
84278 	    {
84279 	      s7_pointer s1, s2;
84280 	      s1 = let_slots(sc->curlet);
84281 	      s2 = next_slot(s1);
84282 	      for (k = numerator(stepper); k < end; k++)
84283 		{
84284 		  integer(ip) = k;
84285 		  set_real(slot_value(s1), vars[0]->v[0].fd(vars[0]));
84286 		  set_real(slot_value(s2), vars[1]->v[0].fd(vars[1]));
84287 		  body[0]->v[0].fd(body[0]);
84288 		}} /* body_len == 1 and var_len == 2 */
84289 	  else
84290 	    for (k = numerator(stepper); k < end; k++)
84291 	      {
84292 		int32_t n;
84293 		integer(ip) = k;
84294 		for (n = 0, p = let_slots(sc->curlet); tis_slot(p); n++, p = next_slot(p))
84295 		  set_real(slot_value(p), vars[n]->v[0].fd(vars[n]));
84296 		body[0]->v[0].fd(body[0]);
84297 	      }}} /* end body_len == 1 */
84298   else
84299     {
84300       if ((body_len == 2) && (var_len == 1))
84301 	{
84302 	  s7_pointer s1;
84303 	  s1 = let_slots(sc->curlet);
84304 	  for (k = numerator(stepper); k < end; k++)
84305 	    {
84306 	      integer(ip) = k;
84307 	      set_real(slot_value(s1), vars[0]->v[0].fd(vars[0]));
84308 	      body[0]->v[0].fd(body[0]);
84309 	      body[1]->v[0].fd(body[1]);
84310 	    }}
84311       else
84312 	for (k = numerator(stepper); k < end; k++)
84313 	  {
84314 	    int32_t i;
84315 	    integer(ip) = k;
84316 	    for (i = 0, p = let_slots(sc->curlet); tis_slot(p); i++, p = next_slot(p))
84317 	      set_real(slot_value(p), vars[i]->v[0].fd(vars[i]));
84318 	    for (i = 0; i < body_len; i++)
84319 	      body[i]->v[0].fd(body[i]);
84320 	  }}
84321   sc->curlet = old_e;
84322   sc->value = sc->T;
84323   sc->code = cdadr(scc);
84324   return(goto_safe_do_end_clauses);
84325 }
84326 
84327 static bool dotimes(s7_scheme *sc, s7_pointer code, bool safe_case)
84328 {
84329   s7_pointer body;
84330   body = caddr(code);   /* here we assume one expr in body */
84331   if (((is_syntactic_pair(body)) ||
84332        (is_syntactic_symbol(car(body)))) &&
84333       ((symbol_syntax_op_checked(body) == OP_LET) ||
84334        (symbol_syntax_op(car(body)) == OP_LET_STAR)))
84335     return(do_let(sc, sc->args, code) == goto_safe_do_end_clauses);
84336   return(opt_dotimes(sc, cddr(code), code, safe_case));
84337 }
84338 
84339 static goto_t op_safe_dotimes(s7_scheme *sc)
84340 {
84341   s7_pointer init_val, form;
84342   form = sc->code;
84343   sc->code = cdr(sc->code);
84344 
84345   init_val = fx_call(sc, cdaar(sc->code));
84346   if (s7_is_integer(init_val))
84347     {
84348       s7_pointer end_expr, end_val, code;
84349 
84350       code = sc->code;
84351       end_expr = caadr(code);
84352       end_val = caddr(end_expr);
84353       if (is_symbol(end_val))
84354 	end_val = lookup_checked(sc, end_val);
84355 
84356       if (s7_is_integer(end_val))
84357 	{
84358 	  sc->code = cddr(code);
84359 	  sc->curlet = make_let_slowly(sc, sc->curlet);
84360 	  sc->args = make_slot_2(sc, sc->curlet, caaar(code), make_mutable_integer(sc, s7_integer_checked(sc, init_val)));
84361 
84362 	  denominator(slot_value(sc->args)) = s7_integer_checked(sc, end_val);
84363 	  set_step_end(sc->args);  /* safe_dotimes step is by 1 */
84364 
84365 	  /* (define (hi) (do ((i 1 (+ 1 i))) ((= i 1) i))) -- we need the let even if the loop is not evaluated */
84366 
84367 	  /* safe_dotimes: (car(body) is known to be a pair here)
84368 	   *   if 1-expr body look for syntactic case, if let(*) goto do_let, else opt_dotimes
84369 	   *       if they are unhappy, got safe_dotimes_step_o
84370 	   *   else goto opt_dotimes then safe_dotimes_step_o
84371 	   *   if multi-line body, check opt_dotimes, then safe_dotimes_step
84372 	   */
84373 
84374 	  if (s7_integer_checked(sc, init_val) == s7_integer_checked(sc, end_val))
84375 	    {
84376 	      sc->value = sc->T;
84377 	      sc->code = cdadr(code);
84378 	      return(goto_safe_do_end_clauses);
84379 	    }
84380 
84381 	  if ((is_null(cdr(sc->code))) &&
84382 	      (is_pair(car(sc->code))))
84383 	    {
84384 	      sc->code = car(sc->code);
84385 	      set_opt2_pair(code, sc->code); /* is_pair above */
84386 
84387 	      if ((is_syntactic_pair(sc->code)) ||
84388 		  (is_syntactic_symbol(car(sc->code))))
84389 		{
84390 		  if (!is_unsafe_do(code))
84391 		    {
84392 		      if (dotimes(sc, code, true))
84393 			return(goto_safe_do_end_clauses);
84394 		      set_unsafe_do(code);
84395 		    }
84396 		  push_stack(sc, OP_SAFE_DOTIMES_STEP_O, sc->args, code);
84397 		  if (is_syntactic_pair(sc->code))
84398 		    sc->cur_op = (opcode_t)optimize_op(sc->code);
84399 		  else
84400 		    {
84401 		      sc->cur_op = (opcode_t)symbol_syntax_op_checked(sc->code);
84402 		      pair_set_syntax_op(sc->code, sc->cur_op);
84403 		    }
84404 		  return(goto_top_no_pop);
84405 		}
84406 	      /* car not syntactic? */
84407 	      if ((!is_unsafe_do(code)) &&
84408 		  (opt_dotimes(sc, cddr(code), code, true)))
84409 		return(goto_safe_do_end_clauses);
84410 	      set_unsafe_do(code);
84411 
84412 	      if (has_fx(cddr(code))) /* this almost never happens and the func case below is only in timing tests */
84413 		{
84414 		  s7_int end;
84415 		  s7_pointer body, stepper;
84416 		  end = s7_integer_checked(sc, end_val);
84417 		  body = cddr(code);
84418 		  stepper = slot_value(sc->args);
84419 		  for (; integer(stepper) < end; integer(stepper)++)
84420 		    fx_call(sc, body);
84421 		  sc->value = sc->T;
84422 		  sc->code = cdadr(code);
84423 		  return(goto_safe_do_end_clauses);
84424 		}
84425 	      push_stack(sc, OP_SAFE_DOTIMES_STEP_O, sc->args, code); /* arg is local step var slot, code is do form - do, sc->code is the body */
84426 	      return(goto_eval);
84427 	    }
84428 
84429 	  /* multi-line body */
84430 	  if ((!is_unsafe_do(code)) &&
84431 	      (opt_dotimes(sc, sc->code, code, true)))
84432 	    return(goto_safe_do_end_clauses);
84433 	  set_unsafe_do(code);
84434 	  set_opt2_pair(code, sc->code);
84435 	  push_stack(sc, OP_SAFE_DOTIMES_STEP, sc->args, code);
84436 	  return(goto_begin);
84437 	}}
84438   pair_set_syntax_op(form, OP_SIMPLE_DO);
84439   sc->code = form;
84440   if (op_simple_do(sc)) return(goto_do_end_clauses);
84441 
84442   return(goto_begin);
84443 }
84444 
84445 static goto_t op_safe_do(s7_scheme *sc)
84446 {
84447   /* body is safe, step = +1, end is = or >=, but stepper and end might be set (or at least indirectly exported) in the body:
84448    *    (let ((lst ())) (do ((i 0 (+ i 1))) ((= i 10)) (let ((j (min i 100))) (set! lst (cons j lst)))) lst)
84449    *  however, we're very restrictive about this in check_do and do_is_safe; even this is considered trouble:
84450    *    (let ((x 0)) (do ((i i (+ i 1))) ((= i 7)) (set! x (+ x i))) x)
84451    * but end might not be an integer -- need to catch this earlier.
84452    */
84453   s7_pointer end, init_val, end_val, code, form;
84454 
84455   /* inits, if not >= opt_dotimes else safe_do_step */
84456   form = sc->code;
84457   sc->code = cdr(sc->code);
84458   code = sc->code;
84459 
84460   init_val = fx_call(sc, cdaar(code));
84461   end = caddr(caadr(code));
84462   end_val = (is_symbol(end)) ? lookup_checked(sc, end) : end;
84463 
84464   if ((!s7_is_integer(init_val)) || (!s7_is_integer(end_val))) /* this almost never happens */
84465     {
84466       pair_set_syntax_op(form, OP_DO_UNCHECKED);
84467       return(goto_do_unchecked);
84468     }
84469 
84470   /* (let ((sum 0)) (define (hi) (do ((i 10 (+ i 1))) ((= i 10) i) (set! sum (+ sum i)))) (hi)) */
84471   sc->curlet = make_let_slowly(sc, sc->curlet);
84472   let_set_dox_slot1(sc->curlet, make_slot_2(sc, sc->curlet, caaar(code), init_val)); /* define the step var -- might be needed in the end clauses */
84473 
84474   if ((s7_integer_checked(sc, init_val) == s7_integer_checked(sc, end_val)) ||
84475       ((s7_integer_checked(sc, init_val) > s7_integer_checked(sc, end_val)) &&
84476        (opt1_cfunc(caadr(code)) == sc->geq_2)))
84477     {
84478       sc->value = sc->T;
84479       sc->code = cdadr(code);
84480       return(goto_safe_do_end_clauses);
84481     }
84482 
84483   if (is_symbol(end))
84484     let_set_dox_slot2(sc->curlet, lookup_slot_from(end, sc->curlet));
84485   else let_set_dox_slot2(sc->curlet, make_slot(sc, caaar(code), end));
84486   sc->args = let_dox_slot2(sc->curlet);  /* the various safe steps assume sc->args is the end slot */
84487 
84488   if (!is_unsafe_do(sc->code))
84489     {
84490       s7_pointer old_let;
84491       old_let = sc->curlet;
84492       sc->temp7 = old_let;
84493       if (opt_dotimes(sc, cddr(sc->code), sc->code, false))
84494 	return(goto_safe_do_end_clauses);
84495       sc->curlet = old_let;  /* apparently s7_optimize can step on sc->curlet? */
84496     }
84497   if (is_null(cdddr(sc->code)))
84498     {
84499       s7_pointer body;
84500       body = caddr(sc->code);
84501       if ((car(body) == sc->set_symbol) &&
84502 	  (is_pair(cdr(body))) &&
84503 	  (is_symbol(cadr(body))) &&
84504 	  (is_pair(cddr(body))) &&
84505 	  (has_fx(cddr(body))) &&
84506 	  (is_null(cdddr(body))))
84507 	{
84508 	  s7_pointer step_slot;
84509 	  step_slot = let_dox_slot1(sc->curlet);
84510 	  if (slot_symbol(step_slot) != cadr(body))
84511 	    {
84512 	      s7_int step, endi;
84513 	      s7_pointer val_slot, fx_p, step_val;
84514 
84515 	      endi = integer(let_dox2_value(sc->curlet));
84516 	      val_slot = lookup_slot_from(cadr(body), sc->curlet);
84517 	      fx_p = cddr(body);
84518 	      step = integer(slot_value(step_slot));
84519 	      slot_set_value(step_slot, step_val = make_mutable_integer(sc, step));
84520 
84521 	      do {
84522 		slot_set_value(val_slot, fx_call(sc, fx_p));
84523 		integer(step_val) = ++step;
84524 	      } while (step != endi); /* geq not needed here -- we're leq endi and stepping by +1 all ints */
84525 	      clear_mutable_integer(step_val);
84526 	      sc->value = sc->T;
84527 	      sc->code = cdadr(code);
84528 	      return(goto_safe_do_end_clauses);
84529 	    }}}
84530   sc->code = cddr(code);
84531   set_unsafe_do(sc->code);
84532   set_opt2_pair(code, sc->code);
84533   push_stack_no_args(sc, OP_SAFE_DO_STEP, code);  /* (do ((i 0 (+ i 1))) ((= i 2)) (set! (str i) #\a)) */
84534   return(goto_begin);
84535 }
84536 
84537 static goto_t op_dotimes_p(s7_scheme *sc)
84538 {
84539   s7_pointer end, code, init_val, end_val, slot, old_e;
84540   /* (do ... (set! args ...)) -- one line, syntactic */
84541 
84542   code = cdr(sc->code);
84543   init_val = fx_call(sc, cdaar(code));
84544   sc->value = init_val;
84545 
84546   set_opt2_pair(code, caadr(code));
84547   end = caddr(opt2_pair(code));
84548   if (is_symbol(end))
84549     {
84550       slot = lookup_slot_from(end, sc->curlet);
84551       end_val = slot_value(slot);
84552     }
84553   else
84554     {
84555       slot = make_slot(sc, make_symbol(sc, "_end_"), end);
84556       end_val = end;
84557     }
84558 
84559   if ((!s7_is_integer(init_val)) || (!s7_is_integer(end_val)))
84560     {
84561       pair_set_syntax_op(sc->code, OP_DO_UNCHECKED);
84562       sc->code = cdr(sc->code);
84563       return(goto_do_unchecked);
84564     }
84565 
84566   old_e = sc->curlet;
84567   sc->curlet = make_let_slowly(sc, sc->curlet);
84568   let_set_dox_slot1(sc->curlet, make_slot_2(sc, sc->curlet, caaar(code), init_val));
84569   let_set_dox_slot2(sc->curlet, slot);
84570 
84571   set_car(sc->t2_1, let_dox1_value(sc->curlet));
84572   set_car(sc->t2_2, let_dox2_value(sc->curlet));
84573   if (is_true(sc, sc->value = fn_proc(caadr(code))(sc, sc->t2_1)))
84574     {
84575       sc->code = cdadr(code);
84576       return(goto_do_end_clauses);
84577     }
84578   if ((!is_unsafe_do(code)) &&
84579       (opt1_cfunc(caadr(code)) != sc->geq_2))
84580     {
84581       s7_pointer old_args, old_init;
84582 
84583       old_args = sc->args;
84584       old_init = let_dox1_value(sc->curlet);
84585       sc->args = T_Slt(let_dox_slot1(sc->curlet));  /* used in opt_dotimes */
84586       slot_set_value(sc->args, make_mutable_integer(sc, integer(let_dox1_value(sc->curlet))));
84587       denominator(slot_value(sc->args)) = integer(let_dox2_value(sc->curlet));
84588       set_step_end(sc->args);                  /* dotimes step is by 1 */
84589 
84590       sc->code = cdr(sc->code);
84591       if (dotimes(sc, code, false))
84592 	return(goto_do_end_clauses); /* not safe_do here */
84593       slot_set_value(sc->args, old_init);
84594       sc->curlet = old_e; /* free_cell(sc, sc->curlet) beforehand is not safe */
84595       sc->args = old_args;
84596       set_unsafe_do(code);
84597       return(goto_do_unchecked);
84598     }
84599   push_stack_no_args(sc, OP_DOTIMES_STEP_O, code);
84600   sc->code = caddr(code);
84601   return(goto_eval);
84602 }
84603 
84604 static goto_t op_do_init_1(s7_scheme *sc)
84605 {
84606   s7_pointer x, y, z;
84607   while (true)  /* at start, first value is the loop (for GC protection?), returning sc->value is the next value */
84608     {
84609       s7_pointer init;
84610       sc->args = cons(sc, sc->value, sc->args);    /* code will be last element (first after reverse), these cons's will be used below for the new let/slots */
84611       if (!is_pair(sc->code)) break;
84612       /* here sc->code is a list like: ((i 0 (+ i 1)) ...) so cadar gets the init value. */
84613       init = cdar(sc->code);
84614       if (has_fx(init))
84615 	sc->value = fx_call(sc, init);
84616       else
84617 	{
84618 	  init = car(init);
84619 	  if (is_pair(init))
84620 	    {
84621 	      push_stack(sc, OP_DO_INIT, sc->args, cdr(sc->code));  /* OP_DO_INIT only used here */
84622 	      sc->code = init;
84623 	      return(goto_eval);
84624 	    }
84625 	  sc->value = (is_symbol(init)) ? lookup_checked(sc, init) : init;
84626 	}
84627       sc->code = cdr(sc->code);
84628     }
84629 
84630   /* all the initial values are now in the args list */
84631   sc->args = proper_list_reverse_in_place(sc, sc->args);
84632   sc->code = car(sc->args);                       /* saved at the start */
84633 
84634   z = sc->args;
84635   sc->args = cdr(sc->args);                       /* init values */
84636 
84637   /* sc->args was cons'd above, so it should be safe to reuse it as the new let */
84638   sc->curlet = reuse_as_let(sc, z, sc->curlet);     /* sc->curlet = make_let_slowly(sc, sc->curlet); */
84639 
84640   /* run through sc->code and sc->args adding '( caar(car(code)) . car(args) ) to sc->curlet, also reuse sc->args as the new let slots */
84641   sc->value = sc->nil;
84642   y = sc->args;
84643   for (x = car(sc->code); is_not_null(y); x = cdr(x))
84644     {
84645       s7_pointer sym, args;
84646       sym = caar(x);
84647       args = cdr(y);
84648       reuse_as_slot(sc, y, sym, unchecked_car(y));
84649       slot_set_next(y, let_slots(sc->curlet));
84650       let_set_slots(sc->curlet, y);
84651       symbol_set_local_slot(sym, let_id(sc->curlet), y);
84652 
84653       if (is_pair(cddar(x)))                   /* else no incr expr, so ignore it henceforth */
84654 	{
84655 	  slot_set_expression(y, cddar(x));
84656 	  sc->value = cons_unchecked(sc, y, sc->value);
84657 	}
84658       y = args;
84659     }
84660   sc->args = cons(sc, sc->value = proper_list_reverse_in_place(sc, sc->value), cadr(sc->code));
84661   sc->code = cddr(sc->code);
84662   return(fall_through);
84663 }
84664 
84665 static bool op_do_init(s7_scheme *sc)
84666 {
84667   if (is_multiple_value(sc->value))               /* (do ((i (values 1 2)))...) */
84668     eval_error_any(sc, sc->wrong_type_arg_symbol, "do: variable initial value can't be ~S", 38, set_ulist_1(sc, sc->values_symbol, sc->value));
84669   return(op_do_init_1(sc) != goto_eval);
84670 }
84671 
84672 static void op_do_unchecked(s7_scheme *sc)
84673 {
84674   push_stack_no_code(sc, OP_GC_PROTECT, sc->code);
84675   sc->code = cdr(sc->code);
84676 }
84677 
84678 static bool do_unchecked(s7_scheme *sc)
84679 {
84680   if (is_null(car(sc->code)))                     /* (do () ...) -- (let ((i 0)) (do () ((= i 1)) (set! i 1))) */
84681     {
84682       sc->curlet = make_let_slowly(sc, sc->curlet);
84683       sc->args = cons_unchecked(sc, sc->nil, cadr(sc->code));
84684       sc->code = cddr(sc->code);
84685       return(false);
84686     }
84687   /* eval each init value, then set up the new let (like let, not let*) */
84688   sc->args = sc->nil;                             /* the evaluated var-data */
84689   sc->value = sc->code;                           /* protect it */
84690   sc->code = car(sc->code);                       /* the vars */
84691   return(op_do_init_1(sc) == goto_eval);
84692 }
84693 
84694 static bool op_do_end(s7_scheme *sc)
84695 {
84696   /* car(sc->args) here is the var list used by do_end2 */
84697   if (is_pair(cdr(sc->args)))
84698     {
84699       if (!has_fx(cdr(sc->args)))
84700 	{
84701 	  push_stack_direct(sc, OP_DO_END1);
84702 	  sc->code = cadr(sc->args);              /* evaluate the end expr */
84703 	  return(true);
84704 	}
84705       sc->value = fx_call(sc, cdr(sc->args));
84706     }
84707   else sc->value = sc->F;                         /* goto "if (is_pair(sc->code))..." below */
84708   return(false);
84709 }
84710 
84711 static goto_t op_do_end1(s7_scheme *sc)
84712 {
84713   if (is_true(sc, sc->value))             /* sc->value is the result of end-test evaluation */
84714     {
84715       /* we're done -- deal with result exprs, if there isn't an end test, there also isn't a result (they're in the same list)
84716        * multiple-value end-test result is ok
84717        */
84718       sc->code = T_Lst(cddr(sc->args));   /* result expr (a list -- implicit begin) */
84719       free_cell(sc, sc->args);
84720       sc->args = sc->nil;
84721       if (is_null(sc->code))
84722 	{
84723 	  if (is_multiple_value(sc->value))  /* (define (f) (+ 1 (do ((i 2 (+ i 1))) ((values i (+ i 1)))))) -> 6 */
84724 	    sc->value = splice_in_values(sc, multiple_value(sc->value));
84725 	  /* similarly, if the result is a multiple value: (define (f) (+ 1 (do ((i 2 (+ i 1))) ((= i 3) (values i (+ i 1)))))) -> 8 */
84726 	  return(goto_start);
84727 	}
84728       /* might be => here as in cond and case */
84729       if (is_null(cdr(sc->code)))
84730 	{
84731 	  if (has_fx(sc->code))
84732 	    {
84733 	      sc->value = fx_call(sc, sc->code);
84734 	      return(goto_start);
84735 	    }
84736 	  sc->code = car(sc->code);
84737 	  return(goto_eval);
84738 	}
84739       if ((car(sc->code) == sc->feed_to_symbol) &&
84740 	  (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
84741 	return(goto_feed_to);
84742       push_stack_no_args(sc, sc->begin_op, cdr(sc->code));
84743       sc->code = car(sc->code);
84744       return(goto_eval);
84745     }
84746   if (is_pair(sc->code))
84747     {
84748       if (is_null(car(sc->args)))
84749 	push_stack_direct(sc, OP_DO_END);
84750       else push_stack_direct(sc, OP_DO_STEP);
84751       return(goto_begin);
84752     }
84753   return((is_null(car(sc->args))) ? /* no steppers */ goto_do_end : fall_through);
84754 }
84755 
84756 /* -------------------------------------------------------------------------------- */
84757 
84758 static void op_unwind_output(s7_scheme *sc)
84759 {
84760   bool is_file;
84761   is_file = is_file_port(sc->code);
84762 
84763   if ((is_output_port(sc->code)) &&
84764       (!port_is_closed(sc->code)))
84765     s7_close_output_port(sc, sc->code); /* may call fflush */
84766 
84767   if (((is_output_port(sc->args)) &&
84768        (!port_is_closed(sc->args))) ||
84769       (sc->args == sc->F))
84770     set_current_output_port(sc, sc->args);
84771 
84772   if ((is_file) &&
84773       (is_multiple_value(sc->value)))
84774     sc->value = splice_in_values(sc, multiple_value(sc->value));
84775 }
84776 
84777 static void op_unwind_input(s7_scheme *sc)
84778 {
84779   /* sc->code is an input port */
84780   if (!port_is_closed(sc->code))
84781     s7_close_input_port(sc, sc->code);
84782 
84783   if ((is_input_port(sc->args)) &&
84784       (!port_is_closed(sc->args)))
84785     set_current_input_port(sc, sc->args);
84786 
84787   if (is_multiple_value(sc->value))
84788     sc->value = splice_in_values(sc, multiple_value(sc->value));
84789 }
84790 
84791 static goto_t op_dynamic_wind(s7_scheme *sc)
84792 {
84793   if (dynamic_wind_state(sc->code) == DWIND_INIT)
84794     {
84795       dynamic_wind_state(sc->code) = DWIND_BODY;
84796       push_stack(sc, OP_DYNAMIC_WIND, sc->nil, sc->code);
84797       sc->code = dynamic_wind_body(sc->code);
84798       sc->args = sc->nil;
84799       return(goto_apply);
84800     }
84801   if (dynamic_wind_state(sc->code) == DWIND_BODY)
84802     {
84803       dynamic_wind_state(sc->code) = DWIND_FINISH;
84804       if (dynamic_wind_out(sc->code) != sc->F)
84805 	{
84806 	  push_stack(sc, OP_DYNAMIC_WIND, sc->value, sc->code);
84807 	  sc->code = dynamic_wind_out(sc->code);
84808 	  sc->args = sc->nil;
84809 	  return(goto_apply);
84810 	}
84811       if (is_multiple_value(sc->value))
84812 	sc->value = splice_in_values(sc, multiple_value(sc->value));
84813       return(goto_start);
84814     }
84815   if (is_multiple_value(sc->args))       /* (+ 1 (dynamic-wind (lambda () #f) (lambda () (values 2 3 4)) (lambda () #f)) 5) */
84816     sc->value = splice_in_values(sc, multiple_value(sc->args));
84817   else sc->value = sc->args;             /* value saved above */
84818   return(goto_start);
84819 }
84820 
84821 static goto_t op_read_s(s7_scheme *sc)
84822 {
84823   /* another lint opt */
84824   s7_pointer port;
84825 
84826   port = lookup(sc, cadr(sc->code));
84827 
84828   if (!is_input_port(port)) /* was also not stdin */
84829     {
84830       sc->value = g_read(sc, list_1(sc, port));
84831       return(goto_start);
84832     }
84833   if (port_is_closed(port))  /* I guess the port_is_closed check is needed because we're going down a level below */
84834     simple_wrong_type_argument_with_type(sc, sc->read_symbol, port, an_open_port_string);
84835 
84836   if (is_function_port(port))
84837     {
84838       sc->value = (*(port_input_function(port)))(sc, S7_READ, port);
84839       if (is_multiple_value(sc->value))
84840 	{
84841 	  clear_multiple_value(sc->value);
84842 	  s7_error(sc, sc->bad_result_symbol, set_elist_2(sc, wrap_string(sc, "input-function-port read returned: ~S", 37), sc->value));
84843 	}}
84844   else
84845     {
84846       if ((is_string_port(port)) &&
84847 	  (port_data_size(port) <= port_position(port)))
84848 	sc->value = eof_object;
84849       else
84850 	{
84851 	  push_input_port(sc, port);
84852 	  push_stack_op(sc, OP_READ_DONE); /* this stops the internal read process so we only get one form */
84853 	  sc->tok = token(sc);
84854 	  switch (sc->tok)
84855 	    {
84856 	    case TOKEN_EOF:	    return(goto_start);
84857 	    case TOKEN_RIGHT_PAREN: read_error(sc, "unexpected close paren");
84858 	    case TOKEN_COMMA:	    read_error(sc, "unexpected comma");
84859 	    default:
84860 	      sc->value = read_expression(sc);
84861 	      sc->current_line = port_line_number(current_input_port(sc));  /* this info is used to track down missing close parens */
84862 	      sc->current_file = port_filename(current_input_port(sc));
84863 	    }}}
84864   /* equally read-done and read-list here */
84865   return(goto_start);
84866 }
84867 
84868 static goto_t op_implicit_string_ref_a(s7_scheme *sc)
84869 {
84870   s7_int index;
84871   s7_pointer s, x;
84872 
84873   s = lookup_checked(sc, car(sc->code));
84874   x = fx_call(sc, cdr(sc->code));
84875   if (!is_string(s))
84876     {
84877       sc->last_function = s;
84878       return(fall_through);
84879     }
84880   if (!s7_is_integer(x))
84881     {
84882       sc->value = string_ref_1(sc, s, set_plist_1(sc, x));
84883       return(goto_start);
84884     }
84885   index = s7_integer_checked(sc, x);
84886   if ((index < string_length(s)) &&
84887       (index >= 0))
84888     {
84889       sc->value = s7_make_character(sc, ((uint8_t *)string_value(s))[index]);
84890       return(goto_start);
84891     }
84892   sc->value = string_ref_1(sc, s, x);
84893   return(goto_start);
84894 }
84895 
84896 static Inline goto_t op_implicit_vector_ref_a(s7_scheme *sc)
84897 {
84898   s7_pointer v, x;
84899 
84900   v = lookup_checked(sc, car(sc->code));
84901   if (!is_any_vector(v))
84902     {
84903       sc->last_function = v;
84904       return(fall_through);
84905     }
84906   x = fx_call(sc, cdr(sc->code));
84907   if ((s7_is_integer(x)) &&
84908       (vector_rank(v) == 1))
84909     {
84910       s7_int index;
84911       index = s7_integer_checked(sc, x);
84912       if ((index < vector_length(v)) &&
84913 	  (index >= 0))
84914 	{
84915 	  sc->value = (is_float_vector(v)) ? make_real(sc, float_vector(v, index)) : vector_getter(v)(sc, v, index);
84916 	  return(goto_start);
84917 	}}
84918   sc->value = vector_ref_1(sc, v, set_plist_1(sc, x));
84919   return(goto_start);
84920 }
84921 
84922 static goto_t op_implicit_vector_ref_aa(s7_scheme *sc)
84923 {
84924   s7_pointer v, x, y, code;
84925 
84926   v = lookup_checked(sc, car(sc->code));
84927   if (!is_any_vector(v))
84928     {
84929       sc->last_function = v;
84930       return(fall_through);
84931     }
84932   code = cdr(sc->code);
84933   x = fx_call(sc, code);
84934   y = fx_call(sc, cdr(code));
84935   if ((s7_is_integer(x)) &&
84936       (s7_is_integer(y)) &&
84937       (vector_rank(v) == 2))
84938     {
84939       s7_int ix, iy;
84940       ix = s7_integer_checked(sc, x);
84941       iy = s7_integer_checked(sc, y);
84942 
84943       if ((ix >= 0) &&
84944 	  (iy >= 0) &&
84945 	  (ix < vector_dimension(v, 0)) &&
84946 	  (iy < vector_dimension(v, 1)))
84947 	{
84948 	  s7_int index;
84949 	  index = (ix * vector_offset(v, 0)) + iy;
84950 	  sc->value = vector_getter(v)(sc, v, index);
84951 	  return(goto_start);
84952 	}}
84953   sc->value = vector_ref_1(sc, v, set_plist_2(sc, x, y));
84954   return(goto_start);
84955 }
84956 
84957 static inline bool op_implicit_vector_set_3(s7_scheme *sc)
84958 {
84959   s7_pointer v, i1, code;
84960   code = cdr(sc->code);
84961   v = lookup(sc, caar(code));
84962   if (!is_any_vector(v))
84963     {
84964       /* this could be improved -- set_pair_p_3 perhaps: pair_p_3 set opt3? but this calls g_vector_set_3 */
84965       pair_set_syntax_op(sc->code, OP_SET_UNCHECKED);
84966       return(true);
84967     }
84968   i1 = fx_call(sc, cdar(code));
84969   set_car(sc->t3_3, fx_call(sc, cdr(code)));
84970   set_car(sc->t3_1, v);
84971   set_car(sc->t3_2, i1);
84972   sc->value = g_vector_set_3(sc, sc->t3_1);
84973   return(false);
84974 }
84975 
84976 static bool op_implicit_vector_set_4(s7_scheme *sc)
84977 {
84978   s7_pointer v, i1, i2, code;
84979   code = cdr(sc->code);
84980   v = lookup(sc, caar(code));
84981   if (!is_any_vector(v))
84982     {
84983       pair_set_syntax_op(sc->code, OP_SET_UNCHECKED);
84984       return(true);
84985     }
84986   i1 = fx_call(sc, cdar(code));
84987   i2 = fx_call(sc, opt3_pair(sc->code)); /* cddar(code) */
84988   set_car(sc->t3_3, fx_call(sc, cdr(code)));
84989   set_car(sc->t4_1, v);
84990   set_car(sc->t3_1, i1);
84991   set_car(sc->t3_2, i2);
84992   sc->value = g_vector_set_4(sc, sc->t4_1);
84993   set_car(sc->t4_1, sc->F);
84994   return(false);
84995 }
84996 
84997 static Inline void op_increment_by_1(s7_scheme *sc)  /* ([set!] ctr (+ ctr 1)) */
84998 {
84999   s7_pointer val, y;
85000 
85001   y = lookup_slot_from(cadr(sc->code), sc->curlet);
85002   if (!is_slot(y))
85003     s7_error(sc, sc->unbound_variable_symbol, set_elist_3(sc, wrap_string(sc, "~S in ~S", 8), cadr(sc->code), sc->code));
85004   val = slot_value(y);
85005   if (is_t_integer(val))
85006     sc->value = make_integer(sc, integer(val) + 1);
85007   else
85008     switch (type(val))
85009       {
85010       case T_RATIO:
85011 	new_cell(sc, sc->value, T_RATIO);
85012 	numerator(sc->value) = numerator(val) + denominator(val);
85013 	denominator(sc->value) = denominator(val);
85014 	break;
85015 
85016       case T_REAL:
85017 	sc->value = make_real(sc, real(val) + 1.0);
85018 	break;
85019 
85020       case T_COMPLEX:
85021 	new_cell(sc, sc->value, T_COMPLEX);
85022 	set_real_part(sc->value, real_part(val) + 1.0);
85023 	set_imag_part(sc->value, imag_part(val));
85024 	break;
85025 
85026       default:
85027 	sc->value = add_p_pp(sc, val, int_one);
85028 	break;
85029       }
85030   slot_set_value(y, sc->value);
85031 }
85032 
85033 static void op_decrement_by_1(s7_scheme *sc)  /* ([set!] ctr (- ctr 1)) */
85034 {
85035   s7_pointer val, y;
85036 
85037   y = lookup_slot_from(cadr(sc->code), sc->curlet);
85038   if (!is_slot(y))
85039     s7_error(sc, sc->unbound_variable_symbol, set_elist_3(sc, wrap_string(sc, "~S in ~S", 8), cadr(sc->code), sc->code));
85040   val = slot_value(y);
85041   if (is_t_integer(val))
85042     sc->value = make_integer(sc, integer(val) - 1); /* increment (set!) returns the new value in sc->value */
85043   else
85044     switch (type(val))
85045       {
85046       case T_RATIO:
85047 	new_cell(sc, sc->value, T_RATIO);
85048 	numerator(sc->value) = numerator(val) - denominator(val);
85049 	denominator(sc->value) = denominator(val);
85050 	break;
85051 
85052       case T_REAL:
85053 	sc->value = make_real(sc, real(val) - 1.0);
85054 	break;
85055 
85056       case T_COMPLEX:
85057 	new_cell(sc, sc->value, T_COMPLEX);
85058 	set_real_part(sc->value, real_part(val) - 1.0);
85059 	set_imag_part(sc->value, imag_part(val));
85060 	break;
85061 
85062       default:
85063 	sc->value = g_subtract(sc, set_plist_2(sc, val, int_one));
85064 	break;
85065       }
85066   slot_set_value(y, sc->value);
85067 }
85068 
85069 static void op_set_pws(s7_scheme *sc)
85070 {
85071   /* this is (set! (getter) val) where getter is a global c_function (a built-in pws) and val is not a pair: (set! (mus-clipping) #f) */
85072   s7_pointer obj, code;
85073   code = cdr(sc->code);
85074   obj = caar(code);
85075   if (is_symbol(obj))
85076     {
85077       obj = lookup_slot_from(obj, sc->curlet);
85078       if (is_slot(obj))
85079 	obj = slot_value(obj);
85080       else s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(code), sc->prepackaged_type_names[type(obj)]));
85081     }
85082 
85083   if ((is_c_function(obj)) &&
85084       (is_procedure(c_function_setter(obj))))
85085     {
85086       s7_pointer value;
85087       value = cadr(code);
85088       if (is_symbol(value))
85089 	value = lookup_checked(sc, value);
85090 
85091       set_car(sc->t1_1, value);
85092       sc->value = c_function_call(c_function_setter(obj))(sc, sc->t1_1);
85093     }
85094   else s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, no_setter_string, caar(sc->code), sc->prepackaged_type_names[type(obj)]));
85095 }
85096 
85097 
85098 /* -------------------------------- apply functions -------------------------------- */
85099 
85100 static void apply_c_function(s7_scheme *sc) 	                    /* -------- C-based function -------- */
85101 {
85102   s7_int len;
85103   len = proper_list_length(sc->args);
85104   if (len < c_function_required_args(sc->code))
85105     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, not_enough_arguments_string, sc->code, sc->args));
85106   if (c_function_all_args(sc->code) < len)
85107     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, sc->code, sc->args));
85108   sc->value = c_function_call(sc->code)(sc, sc->args);
85109   /* just by chance, this code is identical to macroexpand_c_macro's code (after macro expansion)! So,
85110    *   gcc -O2 uses the macroexpand code, but then valgrind shows us calling macros all the time, and
85111    *   gdb with break apply_c_function breaks at macroexpand -- confusing!
85112    */
85113 }
85114 
85115 static void apply_c_opt_args_function(s7_scheme *sc)                /* -------- C-based function that has n optional arguments -------- */
85116 {
85117   s7_int len;
85118   len = proper_list_length(sc->args);
85119   if (c_function_all_args(sc->code) < len)
85120     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, sc->code, sc->args));
85121   sc->value = c_function_call(sc->code)(sc, sc->args);
85122 }
85123 
85124 static void apply_c_rst_args_function(s7_scheme *sc)                /* -------- C-based function that has n required args, then any others -------- */
85125 {
85126   s7_int len;
85127   len = proper_list_length(sc->args);
85128   if (len < c_function_required_args(sc->code))
85129     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, not_enough_arguments_string, sc->code, sc->args));
85130   sc->value = c_function_call(sc->code)(sc, sc->args);
85131   /* sc->code here need not match sc->code before the function call (map for example) */
85132 }
85133 
85134 static void apply_c_any_args_function(s7_scheme *sc)                /* -------- C-based function that can take any number of arguments -------- */
85135 {
85136   sc->value = c_function_call(sc->code)(sc, sc->args);
85137 }
85138 
85139 static void apply_c_macro(s7_scheme *sc)  	                    /* -------- C-based macro -------- */
85140 {
85141   s7_int len;
85142   len = proper_list_length(sc->args);
85143 
85144   if (len < c_macro_required_args(sc->code))
85145     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, not_enough_arguments_string, sc->code, sc->args));
85146 
85147   if (c_macro_all_args(sc->code) < len)
85148     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, sc->code, sc->args));
85149 
85150   sc->code = c_macro_call(sc->code)(sc, sc->args);
85151 }
85152 
85153 static void apply_syntax(s7_scheme *sc)                            /* -------- syntactic keyword as applicable object -------- */
85154 {                                                                  /* current reader-cond macro uses this via (map quote ...) */
85155   s7_int len;                                                      /*    ((apply lambda '((x) (+ x 1))) 4) */
85156   if (is_pair(sc->args))                                           /* this is ((pars) . body) */
85157     {
85158       len = s7_list_length(sc, sc->args);
85159       if (len == 0)
85160 	eval_error(sc, "attempt to evaluate a circular list: ~S", 39, sc->args);
85161 
85162       if ((sc->safety > NO_SAFETY) &&
85163 	  (tree_is_cyclic(sc, sc->args)))
85164 	s7_error(sc, sc->syntax_error_symbol,
85165 		 set_elist_3(sc, wrap_string(sc, "apply ~S: body is circular: ~S", 30), sc->code, sc->args));
85166     }
85167   else len = 0;
85168 
85169   if (len < syntax_min_args(sc->code))
85170     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, not_enough_arguments_string, sc->code, sc->args));
85171 
85172   if ((syntax_max_args(sc->code) < len) &&
85173       (syntax_max_args(sc->code) != -1))
85174     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, sc->code, sc->args));
85175 
85176   sc->cur_op = (opcode_t)syntax_opcode(sc->code);                  /* (apply begin '((define x 3) (+ x 2))) */
85177   /* I had elaborate checks here for embedded circular lists, but now I think that is the caller's problem */
85178   sc->code = cons(sc, sc->code, sc->args);
85179   pair_set_syntax_op(sc->code, sc->cur_op);
85180 }
85181 
85182 static void apply_vector(s7_scheme *sc)                            /* -------- vector as applicable object -------- */
85183 {
85184   /* sc->code is the vector, sc->args is the list of indices */
85185   if (is_null(sc->args))                  /* (#2d((1 2) (3 4))) */
85186     s7_wrong_number_of_args_error(sc, "not enough arguments for vector-ref: ~A", sc->args);
85187 
85188   if ((is_null(cdr(sc->args))) &&
85189       (s7_is_integer(car(sc->args))) &&
85190       (vector_rank(sc->code) == 1))
85191     {
85192       s7_int index;
85193       index = s7_integer_checked(sc, car(sc->args));
85194       if ((index >= 0) &&
85195 	  (index < vector_length(sc->code)))
85196 	sc->value = vector_getter(sc->code)(sc, sc->code, index);
85197       else out_of_range(sc, sc->vector_ref_symbol, int_two, car(sc->args), (index < 0) ? its_negative_string : its_too_large_string);
85198     }
85199   else sc->value = vector_ref_1(sc, sc->code, sc->args);
85200 }
85201 
85202 static void apply_string(s7_scheme *sc)                            /* -------- string as applicable object -------- */
85203 {
85204   if ((is_pair(sc->args)) &&
85205       (is_null(cdr(sc->args))))
85206     {
85207       if (s7_is_integer(car(sc->args)))
85208 	{
85209 	  s7_int index;                  /* not int: ("abs" most-negative-fixnum) */
85210 	  index = s7_integer_checked(sc, car(sc->args));
85211 	  if ((index >= 0) &&
85212 	      (index < string_length(sc->code)))
85213 	    {
85214 	      sc->value = s7_make_character(sc, ((uint8_t *)string_value(sc->code))[index]);
85215 	      return;
85216 	    }}
85217       sc->value = string_ref_1(sc, sc->code, car(sc->args));
85218       return;
85219     }
85220   s7_error(sc, sc->wrong_number_of_args_symbol,
85221 	   set_elist_3(sc, (is_null(sc->args)) ? not_enough_arguments_string : too_many_arguments_string, sc->code, sc->args));
85222 }
85223 
85224 static bool apply_pair(s7_scheme *sc)                               /* -------- list as applicable object -------- */
85225 {
85226   if (is_multiple_value(sc->code))                                  /* ((values 1 2 3) 0) */
85227     {
85228       /* car of values can be anything, so conjure up a new expression, and apply again */
85229       sc->x = multiple_value(sc->code);                             /* ((values + 1 2) 3) */
85230       sc->code = car(sc->x);
85231       sc->args = pair_append(sc, cdr(sc->x), sc->args);
85232       sc->x = sc->nil;
85233       return(false);
85234     }
85235   if (is_null(sc->args))
85236     s7_wrong_number_of_args_error(sc, "not enough arguments for list-ref (via list as applicable object): ~A", sc->args);
85237   sc->value = list_ref_1(sc, sc->code, car(sc->args));            /* (L 1) */
85238   if (!is_null(cdr(sc->args)))
85239     sc->value = implicit_index(sc, sc->value, cdr(sc->args));     /* (L 1 2) */
85240   return(true);
85241 }
85242 
85243 static void apply_hash_table(s7_scheme *sc)                        /* -------- hash-table as applicable object -------- */
85244 {
85245   if (is_null(sc->args))
85246     s7_wrong_number_of_args_error(sc, "not enough arguments for hash-table-ref (via hash table as applicable object): ~A", sc->args);
85247   sc->value = s7_hash_table_ref(sc, sc->code, car(sc->args));
85248   if (!is_null(cdr(sc->args)))
85249     sc->value = implicit_index(sc, sc->value, cdr(sc->args));
85250 }
85251 
85252 static void apply_let(s7_scheme *sc)                               /* -------- environment as applicable object -------- */
85253 {
85254   if (is_null(sc->args))
85255     wrong_type_argument_with_type(sc, sc->let_ref_symbol, 2, sc->args, a_symbol_string);
85256   else
85257     {
85258       sc->value = s7_let_ref(sc, sc->code, car(sc->args));
85259       if (is_pair(cdr(sc->args)))
85260 	sc->value = implicit_index(sc, sc->value, cdr(sc->args));
85261     }
85262   /*    (let ((v #(1 2 3))) (let ((e (curlet))) ((e 'v) 1))) -> 2
85263    * so (let ((v #(1 2 3))) (let ((e (curlet))) (e 'v 1))) -> 2
85264    */
85265 }
85266 
85267 static void apply_iterator(s7_scheme *sc)                          /* -------- iterator as applicable object -------- */
85268 {
85269   if (!is_null(sc->args))
85270     s7_wrong_number_of_args_error(sc, "too many arguments for iterator: ~A", sc->args);
85271   sc->value = s7_iterate(sc, sc->code);
85272 }
85273 
85274 static Inline void apply_lambda(s7_scheme *sc)                     /* -------- normal function (lambda), or macro -------- */
85275 {             /* load up the current args into the ((args) (lambda)) layout [via the current environment] */
85276   s7_pointer x, z, e, sym, slot, last_slot;
85277   uint64_t id;
85278 
85279   e = sc->curlet;
85280   id = let_id(e);
85281   last_slot = slot_end(sc);
85282 
85283   for (x = closure_args(sc->code), z = T_Lst(sc->args); is_pair(x); x = cdr(x), z = cdr(z)) /* closure_args can be a symbol, for example */
85284     {
85285       if (is_null(z))
85286 	s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, not_enough_arguments_string, sc->code, sc->args));
85287 
85288       sym = car(x);
85289       slot = make_slot(sc, sym, T_Pos(unchecked_car(z)));
85290 #if S7_DEBUGGING
85291       slot->debugger_bits = 0;
85292 #endif
85293       symbol_set_local_slot(sym, id, slot);
85294       if (tis_slot(last_slot))
85295 	slot_set_next(last_slot, slot);
85296       else let_set_slots(e, slot);
85297       last_slot = slot;
85298       slot_set_next(slot, slot_end(sc));
85299     }
85300   if (is_null(x))
85301     {
85302       if (is_not_null(z))
85303 	s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, sc->code, sc->args));
85304     }
85305   else
85306     {
85307       sym = x;
85308       slot = make_slot(sc, sym, z);
85309       symbol_set_local_slot(sym, id, slot);
85310       if (tis_slot(last_slot))
85311 	slot_set_next(last_slot, slot);
85312       else let_set_slots(e, slot);
85313       slot_set_next(slot, slot_end(sc));
85314     }
85315   sc->code = closure_body(sc->code);
85316 }
85317 
85318 
85319 /* lambda* */
85320 static void op_lambda_star(s7_scheme *sc)
85321 {
85322   check_lambda_star(sc);
85323   if (!is_pair(car(sc->code)))
85324     sc->value = make_closure(sc, car(sc->code), cdr(sc->code), (is_symbol(car(sc->code))) ? (T_CLOSURE | T_COPY_ARGS) : T_CLOSURE, CLOSURE_ARITY_NOT_SET);
85325   else sc->value = make_closure(sc, car(sc->code), cdr(sc->code), (!arglist_has_rest(sc, car(sc->code))) ? T_CLOSURE_STAR : (T_CLOSURE_STAR | T_COPY_ARGS), CLOSURE_ARITY_NOT_SET);
85326 }
85327 
85328 static void op_lambda_star_unchecked(s7_scheme *sc)
85329 {
85330   s7_pointer code;
85331   code = cdr(sc->code);
85332   if (!is_pair(car(code)))
85333     sc->value = make_closure(sc, car(code), cdr(code), (is_symbol(car(code))) ? (T_CLOSURE | T_COPY_ARGS) : T_CLOSURE, CLOSURE_ARITY_NOT_SET);
85334   else sc->value = make_closure(sc, car(code), cdr(code), (!arglist_has_rest(sc, car(code))) ? T_CLOSURE_STAR : (T_CLOSURE_STAR | T_COPY_ARGS), CLOSURE_ARITY_NOT_SET);
85335 }
85336 
85337 static s7_pointer star_set(s7_scheme *sc, s7_pointer slot, s7_pointer val, bool check_rest)
85338 {
85339   if (is_checked_slot(slot))
85340     return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, parameter_set_twice_string, slot_symbol(slot), sc->args)));
85341   if ((check_rest) && (is_rest_slot(slot)))
85342     return(s7_error(sc, sc->wrong_type_arg_symbol,
85343 		    set_elist_3(sc, wrap_string(sc, "can't set rest arg ~S to ~S via keyword", 39),
85344 				slot_symbol(slot), val)));
85345   set_checked_slot(slot);
85346   slot_set_value(slot, val);
85347   return(val);
85348 }
85349 
85350 static s7_pointer lambda_star_argument_set_value(s7_scheme *sc, s7_pointer sym, s7_pointer val, s7_pointer slot, bool check_rest)
85351 {
85352   s7_pointer x;
85353   if (val == sc->no_value) val = sc->unspecified;
85354   if (sym == slot_symbol(slot))
85355     return(star_set(sc, slot, val, check_rest));
85356   for (x = let_slots(sc->curlet) /* presumably the arglist */; tis_slot(x); x = next_slot(x))
85357     if (slot_symbol(x) == sym)
85358       return(star_set(sc, x, val, check_rest));
85359   return(sc->no_value);
85360 }
85361 
85362 static inline s7_pointer lambda_star_set_args(s7_scheme *sc)
85363 {
85364   bool allow_other_keys;
85365   s7_pointer lx, cx, zx, code, args, slot;
85366 
85367   code = sc->code;
85368   args = sc->args;
85369   cx = closure_args(code);
85370   slot = let_slots(sc->curlet);
85371   allow_other_keys = ((is_pair(cx)) && (allows_other_keys(cx)));
85372   lx = sc->args;
85373   zx = sc->nil;
85374   while ((is_pair(cx)) &&
85375 	 (is_pair(lx)))
85376     {
85377       if (car(cx) == sc->key_rest_symbol)           /* the rest arg: a default is not allowed here (see check_lambda_star_args) */
85378 	{
85379 	  /* next arg is bound to trailing args from this point as a list */
85380 	  zx = sc->key_rest_symbol;
85381 	  cx = cdr(cx);
85382 	  if ((is_keyword(car(lx))) &&
85383 	      (is_pair(cdr(lx))) &&
85384 	      (keyword_symbol(car(lx)) == car(cx)))
85385 	    return(s7_error(sc, sc->wrong_type_arg_symbol,
85386 			    set_elist_3(sc, wrap_string(sc, "can't set rest arg ~S to ~S via keyword", 39), car(cx), cadr(lx))));
85387 	  lambda_star_argument_set_value(sc, car(cx), lx, slot, false);
85388 	  lx = cdr(lx);
85389 	  cx = cdr(cx);
85390 	  slot = next_slot(slot);
85391 	}
85392       else
85393 	{
85394 	  s7_pointer car_lx;
85395 	  car_lx = car(lx);
85396 	  if (is_keyword(car_lx))
85397 	    {
85398 	      if (!is_pair(cdr(lx)))
85399 		{
85400 		  if (!sc->accept_all_keyword_arguments)
85401 		    return(s7_error(sc, sc->wrong_type_arg_symbol,
85402 				    set_elist_4(sc, wrap_string(sc, "~A: keyword argument's value is missing: ~S in ~S", 49), closure_name(sc, code), lx, args)));
85403 		  slot_set_value(slot, car_lx);
85404 		  set_checked_slot(slot);
85405 		  lx = cdr(lx);
85406 		}
85407 	      else
85408 		{
85409 		  s7_pointer sym;
85410 		  sym = keyword_symbol(car_lx);
85411 		  if (lambda_star_argument_set_value(sc, sym, cadr(lx), slot, true) == sc->no_value)
85412 		    {
85413 		      /* if default value is a key, go ahead and use this value.
85414 		       *    (define* (f (a :b)) a) (f :c)
85415 		       * this has become much trickier than I anticipated...
85416 		       */
85417 		      if (allow_other_keys)
85418 			{
85419 			  /* in CL: (defun hi (&key (a 1) &allow-other-keys) a) (hi :b :a :a 3) -> 3
85420 			   * in s7: (define* (hi (a 1) :allow-other-keys) a)    (hi :b :a :a 3) -> 3
85421 			   */
85422 			  lx = cddr(lx);
85423 			}
85424 		      else
85425 			{
85426 			  if (!sc->accept_all_keyword_arguments)
85427 			    return(s7_error(sc, sc->wrong_type_arg_symbol,
85428 					    set_elist_4(sc, wrap_string(sc, "~A: unknown key: ~S in ~S", 25), closure_name(sc, code), lx, args)));
85429 			  slot_set_value(slot, car_lx);
85430 			  set_checked_slot(slot);
85431 			  lx = cdr(lx);
85432 			  cx = cdr(cx);
85433 			  slot = next_slot(slot);
85434 			}
85435 		      continue;
85436 		    }
85437 		  lx = cddr(lx);
85438 		}
85439 	      slot = next_slot(slot);
85440 	    }
85441 	  else                                  /* not a key/value pair */
85442 	    {
85443 	      if (is_checked_slot(slot))
85444 		return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, parameter_set_twice_string, slot_symbol(slot), sc->args)));
85445 	      set_checked_slot(slot);
85446 	      slot_set_value(slot, car(lx));
85447 	      slot = next_slot(slot);
85448 	      lx = cdr(lx);
85449 	    }
85450 	  cx = cdr(cx);
85451 	}}
85452   /* (let () (define* (hi (a 1) :allow-other-keys) a) (hi :a 2 32)) -> 'error */
85453   /* (let () (define* (f (a :b)) a) (list (f) (f 1) (f :c) (f :a :c) (f :a 1) (f))) -> 'error */
85454 
85455   /* check for trailing args with no :rest arg */
85456   if (is_not_null(lx))
85457     {
85458       if ((is_not_null(cx)) ||
85459 	  (zx == sc->key_rest_symbol))
85460 	{
85461 	  if (is_symbol(cx))
85462 	    {
85463 	      if ((is_keyword(car(lx))) &&
85464 		  (is_pair(cdr(lx))) &&
85465 		  (keyword_symbol(car(lx)) == cx))
85466 		return(s7_error(sc, sc->wrong_type_arg_symbol,
85467 				set_elist_3(sc, wrap_string(sc, "can't set rest arg ~S to ~S via keyword", 39), cx, cadr(lx))));
85468 	      slot_set_value(slot, lx);
85469 	    }}
85470       else
85471 	{
85472 	  if (!allow_other_keys)                       /* ((lambda* (a) a) :a 1 2) */
85473 	    return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, closure_name(sc, code), args)));
85474 	  /* check trailing args for repeated keys or keys with no values or values with no keys */
85475 	  while (is_pair(lx))
85476 	    {
85477 	      if ((!is_keyword(car(lx))) ||     /* ((lambda* (a :allow-other-keys) a) :a 1 :b 2 3) */
85478 		  (!is_pair(cdr(lx))))          /* ((lambda* (a :allow-other-keys) a) :a 1 :b) */
85479 		return(s7_error(sc, sc->wrong_type_arg_symbol,
85480 				set_elist_3(sc, wrap_string(sc, "~A: not a key/value pair: ~S", 28), closure_name(sc, code), lx)));
85481 	      slot = symbol_to_local_slot(sc, keyword_symbol(car(lx)), sc->curlet);
85482 	      if ((is_slot(slot)) &&
85483 		  (is_checked_slot(slot)))
85484 		return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, parameter_set_twice_string, slot_symbol(slot), sc->args)));
85485 	      lx = cddr(lx);
85486 	    }}}
85487   return(sc->nil);
85488 }
85489 
85490 static inline goto_t lambda_star_default(s7_scheme *sc)
85491 {
85492   while (true)
85493     {
85494       s7_pointer z;
85495       z = sc->args;
85496 #if S7_DEBUGGING
85497       if ((z) && (!is_slot(z))) fprintf(stderr, "%s: z is %s\n", __func__, s7_type_names[unchecked_type(z)]);
85498 #endif
85499       if (tis_slot(z))
85500 	{
85501 	  if ((slot_value(z) == sc->undefined) &&    /* trouble: (lambda* ((e #<undefined>))...) */
85502 	      (slot_has_expression(z)) &&            /* if default val is not a pair or a symbol, this is false */
85503 	      (!is_checked_slot(z)))
85504 	    {
85505 	      s7_pointer val;
85506 	      val = slot_expression(z);
85507 	      if (is_symbol(val))
85508 		{
85509 		  slot_set_value(z, lookup_checked(sc, val));
85510 		  if (slot_value(z) == sc->undefined)
85511 		    {
85512 		      /* the current environment here contains the function parameters which
85513 		       *   defaulted to #<undefined> (or maybe #<unused>?) earlier in apply_*_closure_star_1,
85514 		       *   so (define (f f) (define* (f (f f)) f) (f)) (f 0) looks for the
85515 		       *   default f, finds itself currently undefined, and raises an error!
85516 		       *   So, before claiming it is unbound, we need to check outlet as well.
85517 		       *   But in the case above, the inner define* shadows the caller's
85518 		       *   parameter before checking the default arg values, so the default f
85519 		       *   refers to the define* -- I'm not sure this is a bug.  It means
85520 		       *   that (define* (f (a f)) a) returns f: (equal? f (f)) -> #t, so
85521 		       *   any outer f needs an extra let and endless outlets:
85522 		       *   (let ((f 3)) (let () (define* (f (a ((outlet (outlet (outlet (curlet)))) 'f))) a) (f))) -> 3
85523 		       *   We want the shadowing once the define* is done, so the current mess is simplest.
85524 		       */
85525 		      slot_set_value(z, s7_symbol_local_value(sc, val, let_outlet(sc->curlet)));
85526 		      if (slot_value(z) == sc->undefined)
85527 			eval_error(sc, "lambda* defaults: ~A is unbound", 31, slot_symbol(z));
85528 		    }}
85529 	      else
85530 		{
85531 		  if (is_pair(val))
85532 		    {
85533 		      if (car(val) == sc->quote_symbol)
85534 			{
85535 			  if ((!is_pair(cdr(val))) ||      /* (lambda* ((a (quote))) a) or (lambda* ((a (quote 1 1))) a) etc */
85536 			      (is_pair(cddr(val))))
85537 			    eval_error(sc, "lambda* default: ~A is messed up", 32, val);
85538 			  slot_set_value(z, cadr(val));
85539 			}
85540 		      else
85541 			{
85542 			  push_stack_direct(sc, OP_LAMBDA_STAR_DEFAULT);
85543 			  sc->code = val;
85544 			  return(goto_eval);
85545 			}}
85546 		  else slot_set_value(z, val);
85547 		}}
85548 	  sc->args = next_slot(z);
85549 	}
85550       else break;
85551     }
85552   sc->args = sc->nil;
85553   return(fall_through);
85554 }
85555 
85556 static bool op_lambda_star_default(s7_scheme *sc)
85557 {
85558   /* sc->args is the current let slots position, sc->value is the default expression's value */
85559   if (is_multiple_value(sc->value))
85560     eval_error(sc, "lambda*: argument default value can't be ~S", 43, set_ulist_1(sc, sc->values_symbol, sc->value));
85561   slot_set_value(sc->args, sc->value);
85562   sc->args = next_slot(sc->args);
85563   if (lambda_star_default(sc) == goto_eval) return(true);
85564   pop_stack_no_op(sc);
85565   sc->code = T_Pair(closure_body(sc->code));
85566   return(false);
85567 }
85568 
85569 static inline bool set_star_args(s7_scheme *sc, s7_pointer top)
85570 {
85571   lambda_star_set_args(sc);                     /* load up current arg vals */
85572   sc->args = top;
85573   if (is_slot(sc->args))
85574     {
85575       /* get default values, which may involve evaluation -- see also OP_LAMBDA_STAR_DEFAULT  */
85576       push_stack_direct(sc, OP_GC_PROTECT);
85577       if (lambda_star_default(sc) == goto_eval) return(true); /* else fall_through */
85578       pop_stack_no_op(sc);              /* get original args and code back */
85579     }
85580   sc->code = closure_body(sc->code);
85581   return(false);
85582 }
85583 
85584 static bool apply_safe_closure_star_1(s7_scheme *sc)                   /* -------- define* (lambda*) -------- */
85585 {
85586   s7_pointer z;
85587   /* slots are in "reverse order" -- in the same order as the args, despite let printout (which reverses the order!) */
85588 
85589   sc->curlet = closure_let(sc->code);
85590   if (has_no_defaults(sc->code))
85591     {
85592       for (z = let_slots(sc->curlet); tis_slot(z); z = next_slot(z))
85593 	{
85594 	  clear_checked_slot(z);
85595 	  slot_set_value(z, sc->F);
85596 	}
85597       if (!is_null(sc->args))
85598 	lambda_star_set_args(sc);                     /* load up current arg vals */
85599       sc->code = closure_body(sc->code);
85600       return(false); /* goto BEGIN */
85601     }
85602 
85603   for (z = let_slots(sc->curlet); tis_slot(z); z = next_slot(z))
85604     {
85605       clear_checked_slot(z);
85606       slot_set_value(z, (slot_defaults(z)) ? sc->undefined : slot_expression(z));
85607     }
85608   return(set_star_args(sc, slot_pending_value(let_slots(sc->curlet))));
85609 }
85610 
85611 static bool apply_unsafe_closure_star_1(s7_scheme *sc)
85612 {
85613   s7_pointer z, val, top;
85614   top = sc->nil;
85615   for (z = closure_args(sc->code); is_pair(z); z = cdr(z))
85616     {
85617       s7_pointer car_z;
85618       car_z = car(z);
85619       if (is_pair(car_z))           /* arg has a default value */
85620 	{
85621 	  s7_pointer slot;
85622 	  val = cadr(car_z);
85623 	  if ((!is_pair(val)) &&
85624 	      (!is_symbol(val)))
85625 	    slot = make_slot_2(sc, sc->curlet, car(car_z), val);
85626 	  else
85627 	    {
85628 	      add_slot(sc, sc->curlet, car(car_z), sc->undefined);
85629 	      slot = let_slots(sc->curlet);
85630 	      slot_set_expression(slot, val);
85631 	    }
85632 	  if (is_null(top))
85633 	    top = slot;
85634 	}
85635       else
85636 	{
85637 	  if (!is_keyword(car_z))
85638 	    /* make_slot_1(sc, sc->curlet, car_z, sc->F); */
85639 	    add_slot(sc, sc->curlet, car_z, sc->F);
85640 	  else
85641 	    if (car_z == sc->key_rest_symbol) /* else it's :allow-other-keys? */
85642 	      {
85643 		set_is_rest_slot(make_slot_2(sc, sc->curlet, cadr(z), sc->nil));
85644 		z = cdr(z);
85645 	      }}}
85646   if (is_symbol(z))
85647     set_is_rest_slot(make_slot_2(sc, sc->curlet, z, sc->nil));     /* set up rest arg */
85648   let_set_slots(sc->curlet, reverse_slots(sc, let_slots(sc->curlet)));
85649   return(set_star_args(sc, top));
85650 }
85651 
85652 static void apply_macro_star_1(s7_scheme *sc)
85653 {
85654   /* here the defaults (if any) are not evalled, and there is not existing let */
85655   s7_pointer p;
85656   for (p = closure_args(sc->code); is_pair(p); p = cdr(p))
85657     {
85658       s7_pointer par;
85659       par = car(p);
85660       if (is_pair(par))
85661 	make_slot_2(sc, sc->curlet, car(par), cadr(par));
85662       else
85663 	{
85664 	  if (!is_keyword(par))
85665 	    make_slot_2(sc, sc->curlet, par, sc->F);
85666 	  else
85667 	    if (par == sc->key_rest_symbol)
85668 	      {
85669 		set_is_rest_slot(make_slot_2(sc, sc->curlet, cadr(p), sc->nil));
85670 		p = cdr(p);
85671 	      }}}
85672   if (is_symbol(p))
85673     set_is_rest_slot(make_slot_2(sc, sc->curlet, p, sc->nil));
85674   let_set_slots(sc->curlet, reverse_slots(sc, let_slots(sc->curlet)));
85675   lambda_star_set_args(sc);
85676   sc->code = T_Pair(closure_body(sc->code));
85677 }
85678 
85679 static void apply_macro(s7_scheme *sc)
85680 {
85681   /* this is not from the reader, so treat expansions here as normal macros */
85682   push_stack_op_let(sc, OP_EVAL_MACRO);
85683   sc->curlet = make_let(sc, closure_let(sc->code)); /* closure_let -> sc->curlet, sc->code is the macro */
85684   transfer_macro_info(sc, sc->code);
85685 }
85686 
85687 static void apply_bacro(s7_scheme *sc)
85688 {
85689   push_stack_op_let(sc, OP_EVAL_MACRO);
85690   sc->curlet = make_let(sc, sc->curlet);       /* like let* -- we'll be adding macro args, so might as well sequester things here */
85691   transfer_macro_info(sc, sc->code);
85692 }
85693 
85694 static void apply_macro_star(s7_scheme *sc)
85695 {
85696   push_stack_op_let(sc, OP_EVAL_MACRO);
85697   sc->curlet = make_let(sc, closure_let(sc->code));
85698   transfer_macro_info(sc, sc->code);
85699   apply_macro_star_1(sc);
85700 }
85701 
85702 static void apply_bacro_star(s7_scheme *sc)
85703 {
85704   push_stack_op_let(sc, OP_EVAL_MACRO);
85705   sc->curlet = make_let(sc, sc->curlet);
85706   transfer_macro_info(sc, sc->code);
85707   apply_macro_star_1(sc);
85708 }
85709 
85710 static void apply_closure(s7_scheme *sc)
85711 {
85712   /* we can get safe_closures here, but can't easily determine whether we have the expected saved funclet -- see ~/old/safe-closure-s7.c */
85713   check_stack_size(sc);
85714   sc->curlet = make_let(sc, closure_let(sc->code));
85715 }
85716 
85717 static bool apply_closure_star(s7_scheme *sc)
85718 {
85719   if (is_safe_closure(sc->code))
85720     return(apply_safe_closure_star_1(sc));
85721   check_stack_size(sc);
85722   sc->curlet = make_let_slowly(sc, closure_let(sc->code));
85723   return(apply_unsafe_closure_star_1(sc));
85724 }
85725 
85726 static Inline s7_pointer op_safe_closure_star_a1(s7_scheme *sc, s7_pointer code)
85727 {
85728   s7_pointer val, func;
85729   func = opt1_lambda(code);
85730   val = fx_call(sc, cdr(code));
85731   if ((is_keyword(val)) &&
85732       (!sc->accept_all_keyword_arguments))
85733     s7_error(sc, sc->wrong_type_arg_symbol,
85734 	     set_elist_4(sc, wrap_string(sc, "~A: keyword argument's value is missing: ~S in ~S", 49),
85735 			 closure_name(sc, func), val, sc->args));
85736   sc->curlet = update_let_with_slot(sc, closure_let(func), val);
85737   sc->code = T_Pair(closure_body(func));
85738   return(func);
85739 }
85740 
85741 static void op_safe_closure_star_a(s7_scheme *sc, s7_pointer code)
85742 {
85743   s7_pointer p, func;
85744   func = op_safe_closure_star_a1(sc, code);
85745   p = cdr(closure_args(func));
85746   if (is_pair(p))
85747     {
85748       s7_pointer x;
85749       for (x = next_slot(let_slots(closure_let(func))); is_pair(p); p = cdr(p), x = next_slot(x))
85750 	{
85751 	  if (is_pair(car(p)))
85752 	    {
85753 	      s7_pointer defval;
85754 	      defval = cadar(p);
85755 	      if (is_pair(defval))
85756 		slot_set_value(x, cadr(defval));
85757 	      else slot_set_value(x, defval);
85758 	    }
85759 	  else slot_set_value(x, sc->F);
85760 	  symbol_set_local_slot(slot_symbol(x), let_id(sc->curlet), x);
85761 	}}
85762 }
85763 
85764 static void op_safe_closure_star_ka(s7_scheme *sc, s7_pointer code)
85765 {
85766   s7_pointer func;
85767   /* two args, but k=arg key, key has been checked. no trailing pars */
85768   func = opt1_lambda(code);
85769   sc->curlet = update_let_with_slot(sc, closure_let(func), fx_call(sc, cddr(code)));
85770   sc->code = T_Pair(closure_body(func));
85771 }
85772 
85773 static void op_safe_closure_star_aa(s7_scheme *sc, s7_pointer code)
85774 {
85775   /* here closure_arity == 2 and we have 2 args */
85776   s7_pointer arg1, arg2, func;
85777 
85778   func = opt1_lambda(code);
85779   arg1 = fx_call(sc, cdr(code));
85780   arg2 = fx_call(sc, cddr(code));
85781 
85782   if (is_keyword(arg1))
85783     {
85784       if (keyword_symbol(arg1) == slot_symbol(let_slots(closure_let(func))))
85785 	{
85786 	  arg1 = arg2;
85787 	  arg2 = cadr(closure_args(func));
85788 	  if (is_pair(arg2)) arg2 = (is_pair(cadr(arg2))) ? cadadr(arg2) : cadr(arg2); else arg2 = sc->F;
85789 	}
85790       else
85791 	{
85792 	  if (keyword_symbol(arg1) == slot_symbol(next_slot(let_slots(closure_let(func)))))
85793 	    {
85794 	      arg1 = car(closure_args(func));
85795 	      if (is_pair(arg1)) arg1 = (is_pair(cadr(arg1))) ? cadadr(arg1) : cadr(arg1); else arg1 = sc->F;
85796 	    }
85797 	  else
85798 	    if (!sc->accept_all_keyword_arguments)
85799 	      s7_error(sc, sc->wrong_type_arg_symbol,
85800 		       set_elist_4(sc, wrap_string(sc, "~A: unknown keyword argument: ~S in ~S", 38),
85801 				   closure_name(sc, func), arg1, code));  /* arg1 is already the value */
85802 	}}
85803   else
85804     if ((is_keyword(arg2)) &&
85805 	(!sc->accept_all_keyword_arguments))
85806       s7_error(sc, sc->wrong_type_arg_symbol,
85807 	       set_elist_4(sc, wrap_string(sc, "~A: keyword argument's value is missing: ~S in ~S", 49),
85808 			   closure_name(sc, func), arg2, code));
85809   sc->curlet = update_let_with_two_slots(sc, closure_let(func), arg1, arg2);
85810   sc->code = T_Pair(closure_body(func));
85811 }
85812 
85813 static bool op_safe_closure_star_all_a_0(s7_scheme *sc, s7_pointer code)
85814 {
85815   sc->args = sc->nil;
85816   sc->code = opt1_lambda(code);
85817   return(apply_safe_closure_star_1(sc));
85818 }
85819 
85820 #define call_lambda_star(sc) do {sc->code = opt1_lambda(code); target = apply_safe_closure_star_1(sc); clear_list_in_use(arglist);} while (0)
85821 
85822 static bool op_safe_closure_star_all_a_1(s7_scheme *sc, s7_pointer code)
85823 {
85824   bool target;
85825   s7_pointer arglist;
85826   sc->args = safe_list_1(sc);
85827   arglist = sc->args;
85828   set_car(sc->args, fx_call(sc, cdr(code)));
85829   call_lambda_star(sc);       /* this clears list_in_use, sets target */
85830   sc->args = sc->nil;
85831   return(target);
85832 }
85833 
85834 static bool op_safe_closure_star_all_a_2(s7_scheme *sc, s7_pointer code)
85835 {
85836   bool target;
85837   s7_pointer arglist, p;
85838   sc->args = safe_list_2(sc);
85839   arglist = sc->args;
85840   set_car(sc->args, fx_call(sc, cdr(code)));
85841   p = cddr(code);
85842   set_car(cdr(sc->args), fx_call(sc, p));
85843   call_lambda_star(sc);
85844   sc->args = sc->nil;
85845   return(target);
85846 }
85847 
85848 static Inline bool op_safe_closure_star_all_a(s7_scheme *sc, s7_pointer code)
85849 {
85850   s7_pointer old_args, p, arglist;
85851   bool target;
85852   sc->args = safe_list_if_possible(sc, integer(opt3_arglen(cdr(code))));
85853   arglist = sc->args;
85854   for (p = sc->args, old_args = cdr(code); is_pair(p); p = cdr(p), old_args = cdr(old_args))
85855     set_car(p, fx_call(sc, old_args));
85856   call_lambda_star(sc);
85857   sc->args = sc->nil;
85858   return(target);
85859 }
85860 
85861 static void op_closure_star_ka(s7_scheme *sc, s7_pointer code)
85862 {
85863   s7_pointer val, p, func;
85864   val = fx_call(sc, cddr(code));
85865   func = opt1_lambda(code);
85866   p = car(closure_args(func));
85867   sc->curlet = make_let_with_slot(sc, closure_let(func), (is_pair(p)) ? car(p) : p, val);
85868   sc->code = T_Pair(closure_body(func));
85869 }
85870 
85871 static void op_closure_star_a(s7_scheme *sc, s7_pointer code)
85872 {
85873   s7_pointer val, p, func;
85874   val = fx_call(sc, cdr(code));
85875   if ((is_keyword(val)) &&
85876       (!sc->accept_all_keyword_arguments))
85877     s7_error(sc, sc->wrong_type_arg_symbol,
85878 	     set_elist_4(sc, wrap_string(sc, "~A: keyword argument's value is missing: ~S in ~S", 49),
85879 			 closure_name(sc, opt1_lambda(code)), val, code));
85880 
85881   func = opt1_lambda(code);
85882   p = car(closure_args(func));
85883   sc->curlet = make_let_with_slot(sc, closure_let(func), (is_pair(p)) ? car(p) : p, val);
85884   if (closure_star_arity_to_int(sc, func) > 1)
85885     {
85886       s7_pointer last_slot;
85887       s7_int id;
85888       last_slot = let_slots(sc->curlet);
85889       id = let_id(sc->curlet);
85890       for (p = cdr(closure_args(func)); is_pair(p); p = cdr(p))
85891 	{
85892 	  s7_pointer par;
85893 	  par = car(p);
85894 	  if (is_pair(par))
85895 	    last_slot = add_slot_at_end(sc, id, last_slot, car(par), (is_pair(cadr(par))) ? cadadr(par) : cadr(par)); /* possible quoted list as default value */
85896 	  else last_slot = add_slot_at_end(sc, id, last_slot, par, sc->F);
85897 	}}
85898   sc->code = T_Pair(closure_body(func));
85899 }
85900 
85901 static inline bool op_closure_star_all_a(s7_scheme *sc, s7_pointer code)
85902 {
85903   check_stack_size(sc);
85904   if (is_pair(cdr(code)))
85905     {
85906       s7_pointer old_args, p;
85907       sc->w = cdr(code);               /* args aren't evaluated yet */
85908       sc->args = make_list(sc, integer(opt3_arglen(cdr(code))), sc->F);
85909       for (p = sc->args, old_args = sc->w; is_pair(p); p = cdr(p), old_args = cdr(old_args))
85910 	set_car(p, fx_call(sc, old_args));
85911       sc->w = sc->nil;
85912     }
85913   else sc->args = sc->nil;
85914   sc->code = opt1_lambda(code);
85915   sc->curlet = make_let(sc, closure_let(sc->code));
85916   return(apply_unsafe_closure_star_1(sc));
85917 }
85918 
85919 static goto_t op_define1(s7_scheme *sc)
85920 {
85921   /* sc->code is the symbol being defined, sc->value is its value
85922    *   if sc->value is a closure, car is of the form ((args...) body...)
85923    * it's not possible to expand and replace macros at this point without evaluating
85924    *   the body.  Just as examples, say we have a macro "mac",
85925    *   (define (hi) (call/cc (lambda (mac) (mac 1))))
85926    *   (define (hi) (quote (mac 1))) or macroexpand etc
85927    *   (define (hi mac) (mac 1)) assuming mac here is a function passed as an arg, etc...
85928    * the immutable constant check needs to wait until we have the actual new value because
85929    *   we want to ignore the rebinding (not raise an error) if it is the existing value.
85930    *   This happens when we reload a file that calls define-constant.
85931    */
85932   if (is_multiple_value(sc->value))                 /* (define x (values 1 2)) */
85933     eval_error(sc, "define: more than one value: ~S", 31, sc->value);
85934   if (is_constant_symbol(sc, sc->code))             /* (define pi 3) or (define (pi a) a) */
85935     {
85936       s7_pointer x;
85937       x = (is_slot(global_slot(sc->code))) ? global_slot(sc->code) : lookup_slot_from(sc->code, sc->curlet);
85938       /* local_slot can be free even if sc->code is immutable (local constant now defunct) */
85939 
85940       if (!((is_slot(x)) &&
85941 	    (type(sc->value) == unchecked_type(slot_value(x))) &&
85942 	    (s7_is_equivalent(sc, sc->value, slot_value(x)))))    /* if value is unchanged, just ignore this (re)definition */
85943 	eval_error(sc, "define: ~S is immutable", 23, sc->code);   /*   can't use s7_is_equal because value might be NaN, etc */
85944     }
85945   if (symbol_has_setter(sc->code))
85946     {
85947       s7_pointer x;
85948       x = lookup_slot_from(sc->code, sc->curlet);
85949       if ((is_slot(x)) &&
85950 	  (slot_has_setter(x)))
85951 	{
85952 	  sc->value = bind_symbol_with_setter(sc, OP_DEFINE_WITH_SETTER, sc->code, sc->value);
85953 	  if (sc->value == sc->no_value)
85954 	    return(goto_apply);
85955 	  /* if all goes well, OP_DEFINE_WITH_SETTER will jump to DEFINE2 */
85956 	}}
85957   return(fall_through);
85958 }
85959 
85960 static void set_let_file_and_line(s7_scheme *sc, s7_pointer new_let, s7_pointer new_func)
85961 {
85962   if (port_file(current_input_port(sc)) != stdin)
85963     {
85964       /* unbound_variable will be called if *function* is encountered, and will return this info as if *function* had some meaning */
85965       if ((is_pair(closure_args(new_func))) &&
85966 	  (has_location(closure_args(new_func))))
85967 	{
85968 	  let_set_file(new_let, pair_file_number(closure_args(new_func)));
85969 	  let_set_line(new_let, pair_line_number(closure_args(new_func)));
85970 	}
85971       else
85972 	{
85973 	  if (has_location(closure_body(new_func)))
85974 	    {
85975 	      let_set_file(new_let, pair_file_number(closure_body(new_func)));
85976 	      let_set_line(new_let, pair_line_number(closure_body(new_func)));
85977 	    }
85978 	  else
85979 	    {
85980 	      s7_pointer p;
85981 	      for (p = cdr(closure_body(new_func)); is_pair(p); p = cdr(p))
85982 		if ((is_pair(car(p))) && (has_location(car(p))))
85983 		  break;
85984 	      let_set_file(new_let, (is_pair(p)) ? pair_file_number(car(p)) : port_file_number(current_input_port(sc)));
85985 	      let_set_line(new_let, (is_pair(p)) ? pair_line_number(car(p)) : port_line_number(current_input_port(sc)));
85986 	    }}
85987       set_has_let_file(new_let);
85988     }
85989   else
85990     {
85991       let_set_file(new_let, 0);
85992       let_set_line(new_let, 0);
85993       clear_has_let_file(new_let);
85994     }
85995 }
85996 
85997 static void op_define_with_setter(s7_scheme *sc)
85998 {
85999   s7_pointer code;
86000   code = sc->code;
86001   if ((is_immutable(sc->curlet)) &&
86002       (is_let(sc->curlet))) /* not () */
86003     s7_error(sc, sc->immutable_error_symbol, set_elist_2(sc, wrap_string(sc, "can't define ~S: curlet is immutable", 36), code));
86004 
86005   if ((is_any_closure(sc->value)) &&
86006       ((!(is_let(closure_let(sc->value)))) ||
86007        (!(is_funclet(closure_let(sc->value))))))  /* otherwise it's (define f2 f1) or something similar */
86008     {
86009       s7_pointer new_func, new_let;
86010       new_func = sc->value;
86011 
86012       if (is_safe_closure_body(closure_body(new_func)))
86013 	{
86014 	  set_safe_closure(new_func);
86015 	  if (is_very_safe_closure_body(closure_body(new_func)))
86016 	    set_very_safe_closure(new_func);
86017 	}
86018       new_let = make_funclet(sc, new_func, code, closure_let(new_func));
86019 
86020       /*  else closure_set_let(new_func, sc->curlet); */
86021 
86022       /* this should happen only if the closure* default values do not refer in any way to
86023        *   the enclosing environment (else we can accidentally shadow something that happens
86024        *   to share an argument name that is being used as a default value -- kinda dumb!).
86025        *   I think I'll check this before setting the safe_closure bit.
86026        */
86027       set_let_file_and_line(sc, new_let, new_func);
86028       /* add the newly defined thing to the current environment */
86029       if (is_let(sc->curlet))
86030 	{
86031 	  if (let_id(sc->curlet) < symbol_id(code)) /* we're adding a later-bound symbol to an old let (?) */
86032 	    {
86033 	      s7_pointer slot;
86034 	      sc->let_number++; /* dummy let, force symbol lookup */
86035 
86036 	      for (slot = let_slots(sc->curlet); tis_slot(slot); slot = next_slot(slot))
86037 		if (slot_symbol(slot) == code)
86038 		  {
86039 		    if (is_immutable(slot))
86040 		      eval_error(sc, "define ~S, but it is immutable", 30, code);
86041 		    slot_set_value(slot, new_func);
86042 		    symbol_set_local_slot(code, sc->let_number, slot);
86043 		    set_local(code);
86044 		    sc->value = new_func; /* probably not needed? */
86045 		    return;
86046 		  }
86047 	      new_cell_no_check(sc, slot, T_SLOT);
86048 	      slot_set_symbol(slot, code);
86049 	      slot_set_value(slot, new_func);
86050 	      symbol_set_local_slot(code, sc->let_number, slot);
86051 	      slot_set_next(slot, let_slots(sc->curlet));
86052 	      let_set_slots(sc->curlet, slot);
86053 	    }
86054 	  else add_slot(sc, sc->curlet, code, new_func);
86055 	  set_local(code);
86056 	}
86057       else
86058 	{
86059 	  if ((is_slot(global_slot(code))) &&
86060 	      (is_immutable(global_slot(code))))
86061 	    {
86062 	      s7_pointer old_value, old_symbol;
86063 	      old_symbol = code;
86064 	      old_value = global_value(code);
86065 	      if ((type(old_value) != type(new_func)) ||
86066 		  (!s7_is_equivalent(sc, old_value, new_func)))    /* if value is unchanged, just ignore this (re)definition */
86067 		eval_error(sc, "define ~S, but it is immutable", 30, old_symbol);
86068 	    }
86069 	  s7_make_slot(sc, sc->curlet, code, new_func);
86070 	}
86071       sc->value = new_func; /* 25-Jul-14 so define returns the value not the name */
86072     }
86073   else
86074     {
86075       s7_pointer lx;
86076       lx = symbol_to_local_slot(sc, code, sc->curlet); /* add the newly defined thing to the current environment */
86077       if (is_slot(lx))
86078 	{
86079 	  if (is_immutable(lx))
86080 	    {
86081 	      s7_pointer old_value, old_symbol;
86082 	      old_symbol = code;
86083 	      old_value = slot_value(lx);
86084 	      if ((type(old_value) != type(sc->value)) ||
86085 		  (!s7_is_equivalent(sc, old_value, sc->value)))    /* if value is unchanged, just ignore this (re)definition */
86086 		eval_error(sc, "define ~S, but it is immutable", 30, old_symbol);
86087 	    }
86088 	  slot_set_value_with_hook(lx, sc->value);
86089 	  symbol_increment_ctr(code);
86090 	}
86091       else s7_make_slot(sc, sc->curlet, code, sc->value);
86092 
86093       if ((is_any_macro(sc->value)) && (!is_c_macro(sc->value)))
86094 	{
86095 	  set_pair_macro(closure_body(sc->value), code);
86096 	  set_has_pair_macro(sc->value);
86097 	}}
86098 }
86099 
86100 
86101 /* -------------------------------- eval -------------------------------- */
86102 
86103 static void check_for_cyclic_code(s7_scheme *sc, s7_pointer code)
86104 {
86105   if (tree_is_cyclic(sc, code))
86106     eval_error(sc, "attempt to evaluate a circular list: ~A", 39, code);
86107   resize_stack(sc); /* we've already checked that resize_stack is needed */
86108 }
86109 
86110 static void op_thunk(s7_scheme *sc)
86111 {
86112   s7_pointer p;
86113   check_stack_size(sc);
86114   /* this recursion check is consistent with the other unsafe closure calls, but we're probably in big trouble:
86115    *   (letrec ((a (lambda () (cons 1 (b)))) (b (lambda () (a)))) (b))
86116    */
86117   p = opt1_lambda(sc->code);
86118   sc->curlet = make_let(sc, closure_let(p));
86119   p = T_Pair(closure_body(p));
86120   if (is_pair(cdr(p)))
86121     push_stack_no_args(sc, sc->begin_op, cdr(p));
86122   sc->code = car(p);
86123 }
86124 
86125 static void op_thunk_any(s7_scheme *sc)
86126 {
86127   s7_pointer p;
86128   p = opt1_lambda(sc->code);
86129   sc->curlet = make_let_with_slot(sc, closure_let(p), closure_args(p), sc->nil);
86130   sc->code = closure_body(p);
86131 }
86132 
86133 static void op_safe_thunk(s7_scheme *sc) /* no let needed */
86134 {
86135   s7_pointer p;
86136   p = opt1_lambda(sc->code);
86137   sc->curlet = closure_let(p);
86138   p = T_Pair(closure_body(p));
86139   if (is_pair(cdr(p)))
86140     push_stack_no_args(sc, sc->begin_op, cdr(p));
86141   sc->code = car(p);
86142 }
86143 
86144 static void op_closure_s(s7_scheme *sc)
86145 {
86146   s7_pointer p;
86147   check_stack_size(sc);
86148   p = opt1_lambda(sc->code);
86149   sc->curlet = make_let_with_slot(sc, closure_let(p), car(closure_args(p)), lookup(sc, opt2_sym(sc->code)));
86150   p = T_Pair(closure_body(p));
86151   if (is_pair(cdr(p)))
86152     push_stack_no_args(sc, sc->begin_op, cdr(p));
86153   sc->code = car(p);
86154 }
86155 
86156 static inline void op_closure_s_o(s7_scheme *sc)
86157 {
86158   s7_pointer f;
86159   f = opt1_lambda(sc->code);
86160   sc->curlet = make_let_with_slot(sc, closure_let(f), car(closure_args(f)), lookup(sc, opt2_sym(sc->code)));
86161   sc->code = car(closure_body(f));
86162 }
86163 
86164 static void op_safe_closure_s(s7_scheme *sc)
86165 {
86166   s7_pointer p;
86167   p = opt1_lambda(sc->code);
86168   sc->curlet = update_let_with_slot(sc, closure_let(p), lookup(sc, opt2_sym(sc->code)));
86169   p = T_Pair(closure_body(p));
86170   if (is_pair(cdr(p)))
86171     push_stack_no_args(sc, sc->begin_op, cdr(p));
86172   sc->code = car(p);
86173 }
86174 
86175 static void op_safe_closure_s_o(s7_scheme *sc)
86176 {
86177   s7_pointer f;
86178   f = opt1_lambda(sc->code);
86179   sc->curlet = update_let_with_slot(sc, closure_let(f), lookup(sc, opt2_sym(sc->code)));
86180   sc->code = car(closure_body(f));
86181 }
86182 
86183 static void op_closure_c(s7_scheme *sc)
86184 {
86185   s7_pointer p;
86186   check_stack_size(sc);
86187   p = opt1_lambda(sc->code);
86188   sc->curlet = make_let_with_slot(sc, closure_let(p), car(closure_args(p)), cadr(sc->code));
86189   p = T_Pair(closure_body(p));
86190   if (is_pair(cdr(p)))
86191     push_stack_no_args(sc, sc->begin_op, cdr(p));
86192   sc->code = car(p);
86193 }
86194 
86195 static void op_closure_c_o(s7_scheme *sc)
86196 {
86197   s7_pointer f;
86198   f = opt1_lambda(sc->code);
86199   sc->curlet = make_let_with_slot(sc, closure_let(f), car(closure_args(f)), cadr(sc->code));
86200   sc->code = car(closure_body(f));
86201 }
86202 
86203 static void op_safe_closure_p(s7_scheme *sc)
86204 {
86205   check_stack_size(sc);
86206   push_stack_no_args(sc, OP_SAFE_CLOSURE_P_1, opt1_lambda(sc->code));
86207   sc->code = cadr(sc->code);
86208 }
86209 
86210 static void op_safe_closure_p_1(s7_scheme *sc)
86211 {
86212   sc->curlet = update_let_with_slot(sc, closure_let(sc->code), sc->value);
86213   sc->code = T_Pair(closure_body(sc->code));
86214 }
86215 
86216 static void op_safe_closure_p_a(s7_scheme *sc)
86217 {
86218   check_stack_size(sc);
86219   push_stack_no_args(sc, OP_SAFE_CLOSURE_P_A_1, opt1_lambda(sc->code));
86220   sc->code = cadr(sc->code);
86221 }
86222 
86223 static void op_safe_closure_p_a_1(s7_scheme *sc)
86224 {
86225   sc->curlet = update_let_with_slot(sc, closure_let(sc->code), sc->value);
86226   sc->value = fx_call(sc, closure_body(sc->code));
86227 }
86228 
86229 static Inline void op_closure_a(s7_scheme *sc)
86230 {
86231   s7_pointer f;
86232   sc->value = fx_call(sc, cdr(sc->code));
86233   f = opt1_lambda(sc->code);
86234   sc->curlet = make_let_with_slot(sc, closure_let(f), car(closure_args(f)), sc->value);
86235   sc->code = T_Pair(closure_body(f));
86236 }
86237 
86238 static void op_safe_closure_3s(s7_scheme *sc)
86239 {
86240   s7_pointer args, f;
86241   f = opt1_lambda(sc->code);
86242   args = cddr(sc->code);
86243   sc->curlet = update_let_with_three_slots(sc, closure_let(f), lookup(sc, cadr(sc->code)), lookup(sc, car(args)), lookup(sc, cadr(args)));
86244   sc->code = T_Pair(closure_body(f));
86245 }
86246 
86247 static void op_safe_closure_ssa(s7_scheme *sc)
86248 {
86249   s7_pointer f, args;
86250   args = cdr(sc->code);
86251   f = opt1_lambda(sc->code);
86252   sc->curlet = update_let_with_three_slots(sc, closure_let(f), lookup(sc, car(args)), lookup(sc, cadr(args)), fx_call(sc, cddr(args)));
86253   sc->code = T_Pair(closure_body(f));
86254 }
86255 
86256 static void op_safe_closure_saa(s7_scheme *sc)
86257 {
86258   s7_pointer args, f, arg2;
86259   f = opt1_lambda(sc->code);
86260   args = cddr(sc->code);
86261   arg2 = lookup(sc, cadr(sc->code)); /* I don't see fx_t|u here? */
86262   sc->code = fx_call(sc, args);
86263   sc->curlet = update_let_with_three_slots(sc, closure_let(f), arg2, sc->code, fx_call(sc, cdr(args)));
86264   sc->code = T_Pair(closure_body(f));
86265 }
86266 
86267 static void op_safe_closure_agg(s7_scheme *sc)
86268 {
86269   s7_pointer f, args;
86270   args = cdr(sc->code);
86271   f = opt1_lambda(sc->code);
86272   sc->curlet = update_let_with_three_slots(sc, closure_let(f), fx_call(sc, args), fx_call(sc, cdr(args)), fx_call(sc, cddr(args)));
86273   sc->code = T_Pair(closure_body(f));
86274 }
86275 
86276 static void op_closure_p(s7_scheme *sc)
86277 {
86278   check_stack_size(sc);
86279   push_stack_no_args(sc, OP_CLOSURE_P_1, opt1_lambda(sc->code));
86280   sc->code = cadr(sc->code);
86281 }
86282 
86283 static void op_closure_p_1(s7_scheme *sc)
86284 {
86285   sc->curlet = make_let_with_slot(sc, closure_let(sc->code), car(closure_args(sc->code)), sc->value);
86286   sc->code = T_Pair(closure_body(sc->code));
86287 }
86288 
86289 static void op_safe_closure_c(s7_scheme *sc)
86290 {
86291   s7_pointer f;
86292   f = opt1_lambda(sc->code);
86293   sc->curlet = update_let_with_slot(sc, closure_let(f), cadr(sc->code));
86294   f = T_Pair(closure_body(f));
86295   if (is_pair(cdr(f)))
86296     push_stack_no_args(sc, sc->begin_op, cdr(f));
86297   sc->code = car(f);
86298 }
86299 
86300 static void op_safe_closure_c_a(s7_scheme *sc)
86301 {
86302   s7_pointer f;
86303   f = opt1_lambda(sc->code);
86304   sc->curlet = update_let_with_slot(sc, closure_let(f), cadr(sc->code));
86305   sc->value = fx_call(sc, closure_body(f));
86306 }
86307 
86308 static void op_safe_closure_c_o(s7_scheme *sc)
86309 {
86310   s7_pointer f;
86311   f = opt1_lambda(sc->code);
86312   sc->curlet = update_let_with_slot(sc, closure_let(f), cadr(sc->code));
86313   sc->code = car(closure_body(f));
86314 }
86315 
86316 static void op_safe_closure_a(s7_scheme *sc)
86317 {
86318   s7_pointer f;
86319   f = opt1_lambda(sc->code);
86320   sc->curlet = update_let_with_slot(sc, closure_let(f), fx_call(sc, cdr(sc->code)));
86321   sc->code = T_Pair(closure_body(f));
86322   push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(sc->code)));
86323   sc->code = car(sc->code);
86324 }
86325 
86326 static void op_safe_closure_a_o(s7_scheme *sc)
86327 {
86328   s7_pointer f;
86329   f = opt1_lambda(sc->code);
86330   sc->curlet = update_let_with_slot(sc, closure_let(f), fx_call(sc, cdr(sc->code)));
86331   sc->code = car(closure_body(f));
86332 }
86333 
86334 static void op_closure_ap(s7_scheme *sc)
86335 {
86336   s7_pointer code;
86337   code = sc->code;
86338   sc->args = fx_call(sc, cdr(code));
86339   /* (hook-push (undo-hook ind 0) (lambda (hook) (set! u0 #t))) -> #<unused>
86340    *    g_undo_hook calls s7_eval_c_string so it obviously should be declared unsafe!
86341    */
86342   push_stack(sc, OP_CLOSURE_AP_1, opt1_lambda(sc->code), sc->args);
86343   sc->code = caddr(code);
86344 }
86345 
86346 static void op_closure_ap_1(s7_scheme *sc)
86347 {
86348   /* sc->value is presumably the "P" argument value, "A" is sc->args->sc->code above (sc->args here is opt1_lambda(original sc->code)) */
86349   sc->curlet = make_let_with_two_slots(sc, closure_let(sc->args), car(closure_args(sc->args)), sc->code, cadr(closure_args(sc->args)), sc->value);
86350   sc->code = T_Pair(closure_body(sc->args));
86351 }
86352 
86353 static void op_closure_pa(s7_scheme *sc)
86354 {
86355   s7_pointer code;
86356   code = sc->code;
86357   sc->args = fx_call(sc, cddr(code));
86358   push_stack(sc, OP_CLOSURE_PA_1, sc->args, opt1_lambda(sc->code)); /* "p" can be self-call changing func locally! so pass opt1_lambda(sc->code), not sc->code */
86359   sc->code = cadr(code);
86360 }
86361 
86362 static void op_closure_pa_1(s7_scheme *sc)
86363 {
86364   sc->curlet = make_let_with_two_slots(sc, closure_let(sc->code), car(closure_args(sc->code)), sc->value, cadr(closure_args(sc->code)), sc->args);
86365   sc->code = T_Pair(closure_body(sc->code));
86366 }
86367 
86368 static void op_closure_pp(s7_scheme *sc)
86369 {
86370   check_stack_size(sc);
86371   push_stack(sc, OP_CLOSURE_PP_1, opt1_lambda(sc->code), sc->code);
86372   sc->code = cadr(sc->code);
86373 }
86374 
86375 static void op_closure_pp_1(s7_scheme *sc)
86376 {
86377   push_stack(sc, OP_CLOSURE_AP_1, sc->args, sc->value);
86378   sc->code = caddr(sc->code);
86379 }
86380 
86381 static void op_safe_closure_ap(s7_scheme *sc)
86382 {
86383   check_stack_size(sc);
86384   sc->args = fx_call(sc, cdr(sc->code));
86385   push_stack(sc, OP_SAFE_CLOSURE_AP_1, sc->args, opt1_lambda(sc->code));
86386   sc->code = caddr(sc->code);
86387 }
86388 
86389 static void op_safe_closure_ap_1(s7_scheme *sc)
86390 {
86391   sc->curlet = update_let_with_two_slots(sc, closure_let(sc->code), sc->args, sc->value);
86392   sc->code = T_Pair(closure_body(sc->code));
86393 }
86394 
86395 static void op_safe_closure_pa(s7_scheme *sc)
86396 {
86397   check_stack_size(sc);
86398   sc->args = fx_call(sc, cddr(sc->code));
86399   push_stack(sc, OP_SAFE_CLOSURE_PA_1, sc->args, opt1_lambda(sc->code));
86400   sc->code = cadr(sc->code);
86401 }
86402 
86403 static void op_safe_closure_pa_1(s7_scheme *sc)
86404 {
86405   sc->curlet = update_let_with_two_slots(sc, closure_let(sc->code), sc->value, sc->args);
86406   sc->code = T_Pair(closure_body(sc->code));
86407 }
86408 
86409 static void op_safe_closure_pp(s7_scheme *sc)
86410 {
86411   check_stack_size(sc);
86412   push_stack(sc, OP_SAFE_CLOSURE_PP_1, opt1_lambda(sc->code), sc->code);
86413   sc->code = cadr(sc->code);
86414 }
86415 
86416 static void op_safe_closure_pp_1(s7_scheme *sc)
86417 {
86418   push_stack(sc, OP_SAFE_CLOSURE_AP_1, sc->value, sc->args);
86419   sc->code = caddr(sc->code);
86420 }
86421 
86422 static void op_any_closure_3p(s7_scheme *sc)
86423 {
86424   s7_pointer p;
86425   p = cdr(sc->code);
86426   if (has_fx(p))
86427     {
86428       sc->args = fx_call(sc, p);
86429       p = cdr(p);
86430       if (has_fx(p))
86431 	{
86432 	  s7_pointer val;
86433 	  val = sc->args; /* protect from fx_call? */
86434 	  sc->args = cons(sc, val, fx_call(sc, p));
86435 	  push_stack_direct(sc, OP_ANY_CLOSURE_3P_3);
86436 	  sc->code = cadr(p);
86437 	}
86438       else
86439 	{
86440 	  push_stack_direct(sc, OP_ANY_CLOSURE_3P_2);
86441 	  sc->code = car(p);
86442 	}}
86443   else
86444     {
86445       push_stack_no_args(sc, OP_ANY_CLOSURE_3P_1, sc->code);
86446       sc->code = car(p);
86447     }
86448 }
86449 
86450 static bool closure_3p_end(s7_scheme *sc, s7_pointer p)
86451 {
86452   if (has_fx(p))
86453     {
86454       s7_pointer func, arg1, arg2;
86455       arg1 = sc->value;
86456       arg2 = fx_call(sc, p);
86457       func = opt1_lambda(sc->code);
86458       if (is_safe_closure(func))
86459 	sc->curlet = update_let_with_three_slots(sc, closure_let(func), sc->args, arg1, arg2);
86460       else
86461 	{
86462 	  sc->value = arg1;
86463 	  sc->code = arg2;
86464 	  make_let_with_three_slots(sc, func, sc->args, arg1, arg2);
86465 	}
86466       sc->code = T_Pair(closure_body(func));
86467       return(true);
86468     }
86469   sc->args = cons(sc, sc->args, sc->value); /* freed below */
86470   push_stack_direct(sc, OP_ANY_CLOSURE_3P_3);
86471   sc->code = car(p);
86472   return(false);
86473 }
86474 
86475 static bool op_any_closure_3p_1(s7_scheme *sc)
86476 {
86477   s7_pointer p;
86478   sc->args = sc->value; /* sc->value can be clobbered by fx_call? */
86479   p = cddr(sc->code);
86480   if (has_fx(p))
86481     {
86482       sc->value = fx_call(sc, p);
86483       return(closure_3p_end(sc, cdr(p)));
86484     }
86485   push_stack_direct(sc, OP_ANY_CLOSURE_3P_2);
86486   sc->code = car(p);
86487   return(false);
86488 }
86489 
86490 static bool op_any_closure_3p_2(s7_scheme *sc)
86491 {
86492   return(closure_3p_end(sc, cdddr(sc->code)));
86493 }
86494 
86495 static void op_any_closure_3p_3(s7_scheme *sc)
86496 {
86497   s7_pointer func, p;
86498   p = sc->args;
86499   func = opt1_lambda(sc->code);
86500   if (is_safe_closure(func))
86501     sc->curlet = update_let_with_three_slots(sc, closure_let(func), car(p), cdr(p), sc->value);
86502   else make_let_with_three_slots(sc, func, car(p), cdr(p), sc->value);
86503   free_cell(sc, p);
86504 #if S7_DEBUGGING
86505   sc->args = sc->nil; /* needed if s7_debugging */
86506 #endif
86507   sc->code = T_Pair(closure_body(func));
86508 }
86509 
86510 static void op_any_closure_4p(s7_scheme *sc)
86511 {
86512   s7_pointer p;
86513   check_stack_size(sc);
86514   p = cdr(sc->code);
86515   if (has_fx(p))
86516     {
86517       gc_protect_via_stack(sc, fx_call(sc, p));
86518       p = cdr(p);
86519       if (has_fx(p))
86520 	{
86521 	  sc->stack_end[-4] = fx_call(sc, p);
86522 	  p = cdr(p);
86523 	  if (has_fx(p))
86524 	    {
86525 	      sc->stack_end[-3] = fx_call(sc, p);
86526 	      push_stack_no_args_direct(sc, OP_ANY_CLOSURE_4P_4);
86527 	      sc->code = cadr(p);
86528 	    }
86529 	  else
86530 	    {
86531 	      push_stack_no_args_direct(sc, OP_ANY_CLOSURE_4P_3);
86532 	      sc->code = car(p);
86533 	    }}
86534       else
86535 	{
86536 	  push_stack_no_args_direct(sc, OP_ANY_CLOSURE_4P_2);
86537 	  sc->code = car(p);
86538 	}}
86539   else
86540     {
86541       push_stack_no_args_direct(sc, OP_ANY_CLOSURE_4P_1);
86542       sc->code = car(p);
86543     }
86544 }
86545 
86546 static bool closure_4p_end(s7_scheme *sc, s7_pointer p)
86547 {
86548   if (has_fx(p))
86549     {
86550       s7_pointer func;
86551       sc->args = fx_call(sc, p);
86552       func = opt1_lambda(sc->code);
86553       if (is_safe_closure(func))
86554 	sc->curlet = update_let_with_four_slots(sc, closure_let(func), sc->stack_end[-2], sc->stack_end[-4], sc->stack_end[-3], sc->args);
86555       else make_let_with_four_slots(sc, func, sc->stack_end[-2], sc->stack_end[-4], sc->stack_end[-3], sc->args);
86556       sc->code = T_Pair(closure_body(func));
86557       sc->stack_end -= 4;
86558       return(true);
86559     }
86560   push_stack_no_args_direct(sc, OP_ANY_CLOSURE_4P_4);
86561   sc->code = car(p);
86562   return(false);
86563 }
86564 
86565 static bool op_any_closure_4p_1(s7_scheme *sc)
86566 {
86567   s7_pointer p;
86568   gc_protect_via_stack(sc, sc->value);
86569   p = cddr(sc->code);
86570   if (has_fx(p))
86571     {
86572       sc->stack_end[-4] = fx_call(sc, p);
86573       p = cdr(p);
86574       if (has_fx(p))
86575 	{
86576 	  sc->stack_end[-3] = fx_call(sc, p);
86577 	  return(closure_4p_end(sc, cdr(p)));
86578 	}
86579       push_stack_no_args_direct(sc, OP_ANY_CLOSURE_4P_3);
86580       sc->code = car(p);
86581     }
86582   else
86583     {
86584       push_stack_no_args_direct(sc, OP_ANY_CLOSURE_4P_2);
86585       sc->code = car(p);
86586     }
86587   return(false);
86588 }
86589 
86590 static bool op_any_closure_4p_2(s7_scheme *sc)
86591 {
86592   s7_pointer p;
86593   sc->stack_end[-4] = sc->value;
86594   p = cdddr(sc->code);
86595   if (has_fx(p))
86596     {
86597       sc->stack_end[-3] = fx_call(sc, p);
86598       return(closure_4p_end(sc, cdr(p)));
86599     }
86600   push_stack_no_args_direct(sc, OP_ANY_CLOSURE_4P_3);
86601   sc->code = car(p);
86602   return(false);
86603 }
86604 
86605 static bool op_any_closure_4p_3(s7_scheme *sc)
86606 {
86607   sc->stack_end[-3] = sc->value;
86608   return(closure_4p_end(sc, cddddr(sc->code)));
86609 }
86610 
86611 static void op_any_closure_4p_4(s7_scheme *sc)
86612 {
86613   s7_pointer func;
86614   func = opt1_lambda(sc->code);
86615   if (is_safe_closure(func))
86616     sc->curlet = update_let_with_four_slots(sc, closure_let(func), sc->stack_end[-2], sc->stack_end[-4], sc->stack_end[-3], sc->value);
86617   else make_let_with_four_slots(sc, func, sc->stack_end[-2], sc->stack_end[-4], sc->stack_end[-3], sc->value);
86618   sc->args = sc->nil; /* needed (where? -- stack trace clobbered twice while trying to find this!) */
86619   sc->code = T_Pair(closure_body(func));
86620   sc->stack_end -= 4;
86621 }
86622 
86623 
86624 static void op_safe_closure_ss(s7_scheme *sc)
86625 {
86626   s7_pointer f;
86627   f = opt1_lambda(sc->code);
86628   sc->curlet = update_let_with_two_slots(sc, closure_let(f), lookup(sc, cadr(sc->code)), lookup(sc, opt2_sym(sc->code)));
86629   sc->code = T_Pair(closure_body(f));
86630   push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(sc->code)));
86631   sc->code = car(sc->code);
86632 }
86633 
86634 static void op_safe_closure_ss_o(s7_scheme *sc)
86635 {
86636   s7_pointer f;
86637   f = opt1_lambda(sc->code);
86638   sc->curlet = update_let_with_two_slots(sc, closure_let(f), lookup(sc, cadr(sc->code)), lookup(sc, opt2_sym(sc->code)));
86639   sc->code = car(closure_body(f));
86640 }
86641 
86642 static inline void op_closure_ss(s7_scheme *sc)
86643 {
86644   s7_pointer f;
86645   check_stack_size(sc);
86646   f = opt1_lambda(sc->code);
86647   sc->curlet = make_let_with_two_slots(sc, closure_let(f), car(closure_args(f)), lookup(sc, cadr(sc->code)), cadr(closure_args(f)), lookup(sc, opt2_sym(sc->code)));
86648   sc->code = T_Pair(closure_body(f));
86649   push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(sc->code)));
86650   sc->code = car(sc->code);
86651 }
86652 
86653 static inline void op_closure_ss_o(s7_scheme *sc)
86654 {
86655   s7_pointer f;
86656   f = opt1_lambda(sc->code);
86657   sc->curlet = make_let_with_two_slots(sc, closure_let(f), car(closure_args(f)), lookup(sc, cadr(sc->code)), cadr(closure_args(f)), lookup(sc, opt2_sym(sc->code)));
86658   sc->code = car(closure_body(f));
86659 }
86660 
86661 static void op_safe_closure_sc(s7_scheme *sc)
86662 {
86663   s7_pointer f;
86664   f = opt1_lambda(sc->code);
86665   sc->curlet = update_let_with_two_slots(sc, closure_let(f), lookup(sc, cadr(sc->code)), opt2_con(sc->code));
86666   sc->code = T_Pair(closure_body(f));
86667   push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(sc->code)));
86668   sc->code = car(sc->code);
86669 }
86670 
86671 static void op_safe_closure_sc_o(s7_scheme *sc)
86672 {
86673   s7_pointer f;
86674   f = opt1_lambda(sc->code);
86675   sc->curlet = update_let_with_two_slots(sc, closure_let(f), lookup(sc, cadr(sc->code)), opt2_con(sc->code));
86676   sc->code = car(closure_body(f));
86677 }
86678 
86679 static void op_closure_sc(s7_scheme *sc)
86680 {
86681   s7_pointer f;
86682   check_stack_size(sc);
86683   f = opt1_lambda(sc->code);
86684   sc->curlet = make_let_with_two_slots(sc, closure_let(f), car(closure_args(f)), lookup(sc, cadr(sc->code)), cadr(closure_args(f)), opt2_con(sc->code));
86685   sc->code = T_Pair(closure_body(f));
86686   push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(sc->code)));
86687   sc->code = car(sc->code);
86688 }
86689 
86690 static void op_closure_sc_o(s7_scheme *sc)
86691 {
86692   s7_pointer f;
86693   check_stack_size(sc);
86694   f = opt1_lambda(sc->code);
86695   sc->curlet = make_let_with_two_slots(sc, closure_let(f), car(closure_args(f)), lookup(sc, cadr(sc->code)), cadr(closure_args(f)), opt2_con(sc->code));
86696   sc->code = car(closure_body(f));
86697 }
86698 
86699 #define if_pair_set_up_begin(Sc) if (is_pair(cdr(Sc->code))) {check_stack_size(Sc); push_stack_no_args(Sc, Sc->begin_op, cdr(Sc->code));} Sc->code = car(Sc->code);
86700 
86701 static void op_closure_3s(s7_scheme *sc)
86702 {
86703   s7_pointer args;
86704   args = cdr(sc->code);
86705   sc->code = opt1_lambda(sc->code);
86706   make_let_with_three_slots(sc, sc->code, lookup(sc, car(args)), lookup(sc, cadr(args)), lookup(sc, caddr(args)));
86707   sc->code = T_Pair(closure_body(sc->code));
86708   if_pair_set_up_begin(sc);
86709 }
86710 
86711 static void op_closure_4s(s7_scheme *sc)
86712 {
86713   s7_pointer p, args, last_slot, v1, v2, v3, v4;
86714   s7_int id;
86715 
86716   args = cdr(sc->code);
86717   v1 = lookup(sc, car(args));
86718   args = cdr(args);
86719   v2 = lookup(sc, car(args));
86720   args = cdr(args);
86721   v3 = lookup(sc, car(args));
86722   v4 = lookup(sc, cadr(args));
86723 
86724   sc->code = opt1_lambda(sc->code);
86725   sc->curlet = make_let(sc, closure_let(sc->code));
86726   id = let_id(sc->curlet);
86727   p = closure_args(sc->code);
86728   add_slot(sc, sc->curlet, car(p), v1);
86729   last_slot = let_slots(sc->curlet);
86730   p = cdr(p);
86731   last_slot = add_slot_at_end(sc, id, last_slot, car(p), v2);
86732   p = cdr(p);
86733   last_slot = add_slot_at_end(sc, id, last_slot, car(p), v3);
86734   add_slot_at_end(sc, id, last_slot, cadr(p), v4);
86735 
86736   sc->code = T_Pair(closure_body(sc->code));
86737   if_pair_set_up_begin(sc);
86738 }
86739 
86740 
86741 static void op_safe_closure_aa(s7_scheme *sc)
86742 {
86743   s7_pointer p, f;
86744   p = cdr(sc->code);
86745   f = opt1_lambda(sc->code);
86746   sc->code = fx_call(sc, cdr(p)); /* fx_call can affect sc->value, but not sc->code, I think */
86747   sc->curlet = update_let_with_two_slots(sc, closure_let(f), fx_call(sc, p), sc->code);
86748   p = T_Pair(closure_body(f));
86749   push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(p)));
86750   sc->code = car(p);
86751 }
86752 
86753 static inline void op_safe_closure_aa_o(s7_scheme *sc)
86754 {
86755   s7_pointer p, f;
86756   p = cdr(sc->code);
86757   f = opt1_lambda(sc->code);
86758   sc->code = fx_call(sc, cdr(p));
86759   sc->curlet = update_let_with_two_slots(sc, closure_let(f), fx_call(sc, p), sc->code);
86760   sc->code = car(closure_body(f));
86761 }
86762 
86763 static void op_closure_aa(s7_scheme *sc)
86764 {
86765   s7_pointer p, f;
86766   p = cdr(sc->code);
86767   f = opt1_lambda(sc->code);
86768   sc->code = fx_call(sc, cdr(p));
86769   sc->value = fx_call(sc, p);
86770   sc->curlet = make_let_with_two_slots(sc, closure_let(f), car(closure_args(f)), sc->value, cadr(closure_args(f)), sc->code);
86771   p = T_Pair(closure_body(f));
86772   check_stack_size(sc);
86773   push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(p)));
86774   sc->code = car(p);
86775 }
86776 
86777 static Inline void op_closure_aa_o(s7_scheme *sc)
86778 {
86779   s7_pointer p, f;
86780   p = cdr(sc->code);
86781   f = opt1_lambda(sc->code);
86782   sc->code = fx_call(sc, cdr(p));
86783   sc->value = fx_call(sc, p);
86784   sc->curlet = make_let_with_two_slots(sc, closure_let(f), car(closure_args(f)), sc->value, cadr(closure_args(f)), sc->code);
86785   sc->code = car(closure_body(f));
86786 }
86787 
86788 static inline void op_closure_fa(s7_scheme *sc)
86789 {
86790   s7_pointer farg, new_clo, aarg, func, func_args, code;
86791   code = sc->code;
86792   farg = opt2_pair(code);           /* cdadr(code); */
86793   aarg = fx_call(sc, cddr(code));
86794   new_clo = make_closure(sc, car(farg), cdr(farg), T_CLOSURE | T_COPY_ARGS, CLOSURE_ARITY_NOT_SET);
86795   func = opt1_lambda(code);         /* outer func */
86796   func_args = closure_args(func);
86797   sc->curlet = make_let_with_two_slots(sc, closure_let(func), car(func_args), new_clo, cadr(func_args), aarg);
86798   sc->code = car(closure_body(func));
86799 }
86800 
86801 static void op_safe_closure_all_s(s7_scheme *sc)
86802 {
86803   s7_pointer args, let, x;
86804   uint64_t id;
86805 
86806   args = cdr(sc->code);
86807   sc->code = opt1_lambda(sc->code);
86808   id = ++sc->let_number;
86809   let = closure_let(sc->code);
86810   let_set_id(let, id);
86811 
86812   for (x = let_slots(let); tis_slot(x); x = next_slot(x), args = cdr(args))
86813     {
86814       slot_set_value(x, lookup(sc, car(args)));
86815       symbol_set_local_slot(slot_symbol(x), id, x);
86816     }
86817 
86818   sc->curlet = let;
86819   sc->code = closure_body(sc->code);
86820   if (is_pair(cdr(sc->code)))
86821     push_stack_no_args(sc, sc->begin_op, cdr(sc->code));
86822   sc->code = car(sc->code);
86823 }
86824 
86825 static void op_safe_closure_all_a(s7_scheme *sc)
86826 {
86827   s7_pointer args, p, let, x, z;
86828   uint64_t id;
86829 
86830   sc->args = safe_list_if_possible(sc, integer(opt3_arglen(cdr(sc->code))));
86831   for (args = cdr(sc->code), p = sc->args; is_pair(args); args = cdr(args), p = cdr(p))
86832     set_car(p, fx_call(sc, args));
86833   sc->code = opt1_lambda(sc->code);
86834 
86835   id = ++sc->let_number;
86836   let = closure_let(sc->code);
86837   let_set_id(let, id);
86838 
86839   for (x = let_slots(let), z = sc->args; tis_slot(x); x = next_slot(x), z = cdr(z))
86840     {
86841       slot_set_value(x, car(z));
86842       symbol_set_local_slot(slot_symbol(x), id, x);
86843     }
86844 
86845   clear_list_in_use(sc->args);
86846   sc->args = sc->nil;
86847 
86848   sc->curlet = let;
86849   sc->code = closure_body(sc->code);
86850   if (is_pair(cdr(sc->code)))
86851     push_stack_no_args(sc, sc->begin_op, cdr(sc->code));
86852   sc->code = car(sc->code);
86853 }
86854 
86855 static Inline void op_closure_all_s(s7_scheme *sc)
86856 {
86857   s7_pointer args, p, e, last_slot;
86858   s7_int id;
86859   /* in this case, we have just lambda (not lambda*), and no dotted arglist,
86860    *   and no accessed symbols in the arglist, and we know the arglist matches the parameter list.
86861    */
86862   args = cdr(sc->code);
86863   sc->code = opt1_lambda(sc->code);
86864   e = make_let(sc, closure_let(sc->code));
86865   sc->z = e;
86866   id = let_id(e);
86867 
86868   p = closure_args(sc->code);
86869   add_slot(sc, e, car(p), lookup(sc, car(args)));
86870   last_slot = let_slots(e);
86871   for (p = cdr(p), args = cdr(args); is_pair(p); p = cdr(p), args = cdr(args))
86872     last_slot = add_slot_at_end(sc, id, last_slot, car(p), lookup(sc, car(args))); /* main such call in lt (fx_s is 1/2, this is 1/5 of all calls) */
86873 
86874   sc->curlet = e;
86875   sc->z = sc->nil;
86876   sc->code = T_Pair(closure_body(sc->code));
86877   if_pair_set_up_begin(sc);
86878 }
86879 
86880 static void just_another_slot(s7_scheme *sc, s7_pointer let, s7_pointer symbol)
86881 {
86882   s7_pointer slot;
86883   new_cell(sc, slot, T_SLOT);
86884   slot_set_symbol(slot, symbol);
86885   slot_set_value(slot, sc->F); /* needed if GC runs before true value is set */
86886   slot_set_next(slot, let_slots(let));
86887   let_set_slots(let, slot);
86888 }
86889 
86890 static s7_pointer just_add_slot_at_end(s7_scheme *sc, s7_pointer last_slot, s7_pointer symbol)
86891 {
86892   s7_pointer slot;
86893   new_cell(sc, slot, T_SLOT);
86894   slot_set_symbol(slot, symbol);
86895   slot_set_value(slot, sc->F);
86896   slot_set_next(slot, slot_end(sc));
86897   slot_set_next(last_slot, slot);
86898   return(slot);
86899 }
86900 
86901 static void op_closure_ass(s7_scheme *sc)
86902 {
86903   s7_pointer f, args;
86904   args = cdr(sc->code);
86905   f = opt1_lambda(sc->code);
86906   make_let_with_three_slots(sc, f, fx_call(sc, args), lookup(sc, cadr(args)), lookup(sc, caddr(args)));
86907   sc->code = T_Pair(closure_body(f));
86908   if_pair_set_up_begin(sc);
86909 }
86910 
86911 static void op_closure_aas(s7_scheme *sc)
86912 {
86913   s7_pointer f, args;
86914   args = cdr(sc->code);
86915   f = opt1_lambda(sc->code);
86916   sc->z = fx_call(sc, args);
86917   make_let_with_three_slots(sc, f, sc->z, fx_call(sc, cdr(args)), lookup(sc, caddr(args)));
86918   sc->code = T_Pair(closure_body(f));
86919   if_pair_set_up_begin(sc);
86920 }
86921 
86922 static void op_closure_saa(s7_scheme *sc)
86923 {
86924   s7_pointer f, args;
86925   args = cdr(sc->code);
86926   f = opt1_lambda(sc->code);
86927   sc->z = fx_call(sc, cdr(args));
86928   make_let_with_three_slots(sc, f, lookup(sc, car(args)), sc->z, fx_call(sc, cddr(args)));
86929   sc->code = T_Pair(closure_body(f));
86930   if_pair_set_up_begin(sc);
86931 }
86932 
86933 static void op_closure_asa(s7_scheme *sc)
86934 {
86935   s7_pointer f, args;
86936   args = cdr(sc->code);
86937   f = opt1_lambda(sc->code);
86938   sc->z = fx_call(sc, args);
86939   make_let_with_three_slots(sc, f, sc->z, lookup(sc, cadr(args)), fx_call(sc, cddr(args)));
86940   sc->code = T_Pair(closure_body(f));
86941   if_pair_set_up_begin(sc);
86942 }
86943 
86944 static void op_closure_sas(s7_scheme *sc)
86945 {
86946   s7_pointer f, args;
86947   args = cdr(sc->code);
86948   f = opt1_lambda(sc->code);
86949   make_let_with_three_slots(sc, f, lookup(sc, car(args)), fx_call(sc, cdr(args)), lookup(sc, caddr(args)));
86950   sc->code = T_Pair(closure_body(f));
86951   if_pair_set_up_begin(sc);
86952 }
86953 
86954 static void op_closure_3a(s7_scheme *sc)
86955 {
86956   s7_pointer f, args;
86957   args = cdr(sc->code);
86958   f = opt1_lambda(sc->code);
86959   gc_protect_via_stack(sc, fx_call(sc, args)); /* [-2]=first */
86960   sc->stack_end[-4] = fx_call(sc, cdr(args));  /* [-4]=second */
86961   make_let_with_three_slots(sc, f, sc->stack_end[-2], sc->stack_end[-4], fx_call(sc, cddr(args)));
86962   sc->stack_end -= 4;
86963   sc->code = T_Pair(closure_body(f));
86964   if_pair_set_up_begin(sc);
86965 }
86966 
86967 static void op_closure_4a(s7_scheme *sc) /* sass */
86968 {
86969   s7_pointer f, args;
86970   args = cdr(sc->code);
86971   f = opt1_lambda(sc->code);
86972   gc_protect_via_stack(sc, fx_call(sc, args)); /* [-2]=first */
86973   sc->stack_end[-3] = fx_call(sc, cdr(args));  /* [-3]=second */
86974   sc->stack_end[-4] = fx_call(sc, cddr(args)); /* [-4]=third */
86975   make_let_with_four_slots(sc, f, sc->stack_end[-2], sc->stack_end[-3], sc->stack_end[-4], fx_call(sc, cdddr(args)));
86976   sc->stack_end -= 4;
86977   sc->code = T_Pair(closure_body(f));
86978   if_pair_set_up_begin(sc);
86979 }
86980 
86981 /* op_closure_any_all_a could also be done this way, but it's not called very often */
86982 
86983 static void op_closure_all_a(s7_scheme *sc)
86984 {
86985   s7_pointer e, exprs, pars, func, slot, last_slot;
86986   s7_int id;
86987 
86988   exprs = cdr(sc->code);
86989   func = opt1_lambda(sc->code);
86990   e = make_let(sc, closure_let(func));
86991   sc->z = e;
86992 
86993   pars = closure_args(func);
86994   just_another_slot(sc, e, car(pars));
86995   last_slot = let_slots(e);
86996   slot_set_pending_value(last_slot, fx_call(sc, exprs));
86997 
86998   for (pars = cdr(pars), exprs = cdr(exprs); is_pair(pars); pars = cdr(pars), exprs = cdr(exprs))
86999     {
87000       last_slot = just_add_slot_at_end(sc, last_slot, car(pars));
87001       slot_set_pending_value(last_slot, fx_call(sc, exprs));
87002     }
87003   sc->curlet = e;
87004   sc->z = sc->nil;
87005   /* let_id set above can be out-of-date if setting up the let uses unrelated-but-same-name symbols,
87006    *   just_another_slot and just_add_slot do not set or use the id's
87007    */
87008   let_set_id(e, ++sc->let_number);
87009   id = let_id(e);
87010   for (slot = let_slots(e); tis_slot(slot); slot = next_slot(slot))
87011     {
87012       slot_set_value(slot, slot_pending_value(slot));
87013       /* symbol_set_id(slot_symbol(slot), id); */ /* included below */
87014       symbol_set_local_slot(slot_symbol(slot), id, slot);
87015       set_local(slot_symbol(slot));
87016     }
87017   sc->code = T_Pair(closure_body(func));
87018   if_pair_set_up_begin(sc);
87019 }
87020 
87021 static bool check_closure_any(s7_scheme *sc)
87022 {
87023   /* can't use closure_is_fine -- (lambda args 1) and (lambda (name . args) 1) are both arity -1 for the internal arity checkers! */
87024   if ((symbol_ctr(car(sc->code)) != 1) ||
87025       (unchecked_local_value(car(sc->code)) != opt1_lambda_unchecked(sc->code)))
87026     {
87027       s7_pointer f;
87028       f = lookup_unexamined(sc, car(sc->code));
87029       if ((f != opt1_lambda_unchecked(sc->code)) &&
87030 	  ((!f) ||
87031 	   ((typesflag(f) & (TYPE_MASK | T_SAFE_CLOSURE)) != T_CLOSURE) ||
87032 	   (!is_symbol(closure_args(f)))))
87033 	{
87034 	  sc->last_function = f;
87035 	  return(false);
87036 	}
87037       set_opt1_lambda(sc->code, f);
87038     }
87039   return(true);
87040 }
87041 
87042 static void op_closure_any_all_a(s7_scheme *sc) /* for (lambda a ...) ? */
87043 {
87044   s7_pointer p, old_args;
87045   sc->w = cdr(sc->code);               /* args aren't evaluated yet */
87046   sc->args = make_list(sc, integer(opt3_arglen(cdr(sc->code))), sc->F);
87047   for (p = sc->args, old_args = sc->w; is_pair(p); p = cdr(p), old_args = cdr(old_args))
87048     set_car(p, fx_call(sc, old_args));
87049   sc->w = sc->nil;
87050   p = opt1_lambda(sc->code);
87051   sc->curlet = make_let_with_slot(sc, closure_let(p), closure_args(p), sc->args);
87052   sc->code = T_Pair(closure_body(p));
87053 }
87054 
87055 /* -------- */
87056 #if S7_DEBUGGING
87057 #define TC_REC_SIZE NUM_OPS
87058 #define TC_REC_LOW_OP OP_TC_AND_A_OR_A_LA
87059 
87060 static void init_tc_rec(s7_scheme *sc)
87061 {
87062   sc->tc_rec_calls = (int *)calloc(TC_REC_SIZE, sizeof(int));
87063   add_saved_pointer(sc, sc->tc_rec_calls);
87064 }
87065 
87066 static s7_pointer g_report_missed_calls(s7_scheme *sc, s7_pointer args)
87067 {
87068   int i;
87069   for (i = TC_REC_LOW_OP; i < NUM_OPS; i++)
87070     if (sc->tc_rec_calls[i] == 0)
87071       fprintf(stderr, "%s missed\n", op_names[i]);
87072   return(sc->F);
87073 }
87074 
87075 static void tick_tc(s7_scheme *sc, int op)
87076 {
87077   sc->tc_rec_calls[op]++;
87078 }
87079 #else
87080 #define tick_tc(Sc, Op)
87081 #endif
87082 
87083 static bool op_tc_case_la(s7_scheme *sc, s7_pointer code)
87084 {
87085   /* opt1_any(clause) = key, has_tc(arg) = is tc call, opt2_any(clause) = result: has_tc(la arg) has_fx(val) or ((...)...) */
87086   s7_pointer clauses, la_slot, endp, selp;
87087   s7_int len;
87088 
87089   len = integer(opt3_arglen(cdr(code)));
87090   la_slot = let_slots(sc->curlet);
87091   selp = cdr(code);
87092   clauses = cddr(code);
87093 
87094   if (len == 3)
87095     {
87096       while (true)
87097 	{
87098 	  s7_pointer selector;
87099 	  selector = fx_call(sc, selp);
87100 	  if (selector == opt1_any(clauses))
87101 	    endp = opt2_any(clauses);
87102 	  else
87103 	    {
87104 	      s7_pointer p;
87105 	      p = cdr(clauses);
87106 	      endp = (selector == opt1_any(p)) ? opt2_any(p) : opt2_any(cdr(p));
87107 	    }
87108 	  if (has_tc(endp))
87109 	    slot_set_value(la_slot, fx_call(sc, cdr(endp)));
87110 	  else break;
87111 	}}
87112   else
87113     while (true)
87114       {
87115 	s7_pointer selector, p;
87116 	selector = fx_call(sc, selp);
87117 	for (p = clauses; is_pair(cdr(p)); p = cdr(p))
87118 	  if (selector == opt1_any(p)) {endp = opt2_any(p); goto CASE_ALA_END;}
87119 	endp = opt2_any(p);
87120       CASE_ALA_END:
87121 	if (has_tc(endp))
87122 	  slot_set_value(la_slot, fx_call(sc, cdr(endp)));
87123 	else break;
87124       }
87125   if (has_fx(endp))
87126     {
87127       sc->value = fx_call(sc, endp);
87128       return(true); /* goto START */
87129     }
87130   sc->code = endp;
87131   return(false);    /* goto BEGIN (not like op_tc_z below) */
87132 }
87133 
87134 static s7_pointer fx_tc_case_la(s7_scheme *sc, s7_pointer arg)
87135 {
87136   tick_tc(sc, OP_TC_CASE_LA);
87137   op_tc_case_la(sc, arg);
87138   return(sc->value);
87139 }
87140 
87141 static bool op_tc_z(s7_scheme *sc, s7_pointer expr)
87142 {
87143   if (has_fx(expr))
87144     {
87145       sc->value = fx_call(sc, expr);
87146       return(true);
87147     }
87148   sc->code = car(expr);
87149   return(false);
87150 }
87151 
87152 static void op_tc_and_a_or_a_la(s7_scheme *sc, s7_pointer code)
87153 {
87154   s7_pointer fx_and, fx_or, fx_la, la_slot;
87155 
87156   fx_and = cdr(code);           /* first clause of and */
87157   fx_or = cdadr(fx_and);        /* same or */
87158   fx_la = cdadr(fx_or);
87159   la_slot = let_slots(sc->curlet);
87160   /* cell_optimize here is slower! */
87161   while (true)
87162     {
87163       s7_pointer p;
87164       if (fx_call(sc, fx_and) == sc->F) {sc->value = sc->F; return;}
87165       p = fx_call(sc, fx_or);
87166       if (p != sc->F) {sc->value = p; return;}
87167       slot_set_value(la_slot, fx_call(sc, fx_la));
87168     }
87169 }
87170 
87171 static s7_pointer fx_tc_and_a_or_a_la(s7_scheme *sc, s7_pointer arg)
87172 {
87173   tick_tc(sc, OP_TC_AND_A_OR_A_LA);
87174   op_tc_and_a_or_a_la(sc, arg);
87175   return(sc->value);
87176 }
87177 
87178 static void op_tc_or_a_and_a_la(s7_scheme *sc, s7_pointer code)
87179 {
87180   s7_pointer fx_and, fx_or, fx_la, la_slot;
87181 
87182   fx_or = cdr(code);             /* first clause of or */
87183   fx_and = cdadr(fx_or);         /* same and */
87184   fx_la = cdadr(fx_and);
87185   la_slot = let_slots(sc->curlet);
87186 
87187   while (true)
87188     {
87189       s7_pointer p;
87190       p = fx_call(sc, fx_or);
87191       if (p != sc->F) {sc->value = p; return;}
87192       if (fx_call(sc, fx_and) == sc->F) {sc->value = sc->F; return;}
87193       slot_set_value(la_slot, fx_call(sc, fx_la));
87194     }
87195 }
87196 
87197 static s7_pointer fx_tc_or_a_and_a_la(s7_scheme *sc, s7_pointer arg)
87198 {
87199   tick_tc(sc, OP_TC_OR_A_AND_A_LA);
87200   op_tc_or_a_and_a_la(sc, arg);
87201   return(sc->value);
87202 }
87203 
87204 static void op_tc_and_a_or_a_a_la(s7_scheme *sc, s7_pointer code)
87205 {
87206   s7_pointer fx_and, fx_or1, fx_or2, fx_la, la_slot;
87207 
87208   fx_and = cdr(code);           /* first clause of and */
87209   fx_or1 = cdadr(fx_and);
87210   fx_or2 = cdr(fx_or1);
87211   fx_la = cdadr(fx_or2);
87212   la_slot = let_slots(sc->curlet);
87213   while (true)
87214     {
87215       s7_pointer p;
87216       if (fx_call(sc, fx_and) == sc->F) {sc->value = sc->F; return;}
87217       p = fx_call(sc, fx_or1);
87218       if (p != sc->F) {sc->value = p; return;}
87219       p = fx_call(sc, fx_or2);
87220       if (p != sc->F) {sc->value = p; return;}
87221       slot_set_value(la_slot, fx_call(sc, fx_la));
87222     }
87223 }
87224 
87225 static s7_pointer fx_tc_and_a_or_a_a_la(s7_scheme *sc, s7_pointer arg)
87226 {
87227   tick_tc(sc, OP_TC_AND_A_OR_A_A_LA);
87228   op_tc_and_a_or_a_a_la(sc, arg);
87229   return(sc->value);
87230 }
87231 
87232 static void op_tc_or_a_and_a_a_la(s7_scheme *sc, s7_pointer code)
87233 {
87234   s7_pointer fx_or, fx_and1, fx_and2, fx_la, la_slot;
87235 
87236   fx_or = cdr(code);           /* first clause of or */
87237   fx_and1 = cdadr(fx_or);
87238   fx_and2 = cdr(fx_and1);
87239   fx_la = cdadr(fx_and2);
87240   la_slot = let_slots(sc->curlet);
87241   while (true)
87242     {
87243       s7_pointer p;
87244       p = fx_call(sc, fx_or);
87245       if (p != sc->F) {sc->value = p; return;}
87246       if ((fx_call(sc, fx_and1) == sc->F) ||
87247 	  (fx_call(sc, fx_and2) == sc->F))
87248 	{sc->value = sc->F; return;}
87249       slot_set_value(la_slot, fx_call(sc, fx_la));
87250     }
87251 }
87252 
87253 static s7_pointer fx_tc_or_a_and_a_a_la(s7_scheme *sc, s7_pointer arg)
87254 {
87255   tick_tc(sc, OP_TC_OR_A_AND_A_A_LA);
87256   op_tc_or_a_and_a_a_la(sc, arg);
87257   return(sc->value);
87258 }
87259 
87260 static void op_tc_or_a_a_and_a_a_la(s7_scheme *sc, s7_pointer code)
87261 {
87262   s7_pointer fx_and1, fx_and2, fx_or1, fx_or2, fx_la, la_slot;
87263 
87264   fx_or1 = cdr(code);            /* first clause of or */
87265   fx_or2 = cdr(fx_or1);
87266   fx_and1 = cdadr(fx_or2);       /* same and */
87267   fx_and2 = cdr(fx_and1);
87268   fx_la = cdadr(fx_and2);
87269   la_slot = let_slots(sc->curlet);
87270   while (true)
87271     {
87272       s7_pointer p;
87273       p = fx_call(sc, fx_or1);
87274       if (p != sc->F) {sc->value = p; return;}
87275       p = fx_call(sc, fx_or2);
87276       if (p != sc->F) {sc->value = p; return;}
87277       if (fx_call(sc, fx_and1) == sc->F) {sc->value = sc->F; return;}
87278       if (fx_call(sc, fx_and2) == sc->F) {sc->value = sc->F; return;}
87279       slot_set_value(la_slot, fx_call(sc, fx_la));
87280     }
87281 }
87282 
87283 static s7_pointer fx_tc_or_a_a_and_a_a_la(s7_scheme *sc, s7_pointer arg)
87284 {
87285   tick_tc(sc, OP_TC_OR_A_A_AND_A_A_LA);
87286   op_tc_or_a_a_and_a_a_la(sc, arg);
87287   return(sc->value);
87288 }
87289 
87290 static void op_tc_and_a_or_a_laa(s7_scheme *sc, s7_pointer code)
87291 {
87292   s7_pointer fx_and, fx_or, fx_la, la_slot, fx_laa, laa_slot;
87293 
87294   fx_and = cdr(code);           /* first clause of and */
87295   fx_or = cdadr(fx_and);        /* same or */
87296   fx_la = cdadr(fx_or);
87297   la_slot = let_slots(sc->curlet);
87298   fx_laa = cdr(fx_la);
87299   laa_slot = next_slot(la_slot);
87300 
87301   if ((fx_proc(fx_and) == fx_not_is_null_u) && (fx_proc(fx_or) == fx_is_null_t) &&
87302       (fx_proc(fx_la) == fx_cdr_t) && (fx_proc(fx_laa) == fx_cdr_u))
87303     {
87304       s7_pointer la_val, laa_val;
87305       la_val = slot_value(la_slot);
87306       laa_val = slot_value(laa_slot);
87307       while (true)
87308 	{
87309 	  if (is_null(laa_val)) {sc->value = sc->F; return;}
87310 	  if (is_null(la_val)) {sc->value = sc->T; return;}
87311 	  la_val = cdr(la_val);
87312 	  laa_val = cdr(laa_val);
87313 	}}
87314 
87315   while (true)
87316     {
87317       s7_pointer p;
87318       if (fx_call(sc, fx_and) == sc->F) {sc->value = sc->F; return;}
87319       p = fx_call(sc, fx_or);
87320       if (p != sc->F) {sc->value = p; return;}
87321       sc->rec_p1 = fx_call(sc, fx_la);
87322       slot_set_value(laa_slot, fx_call(sc, fx_laa));
87323       slot_set_value(la_slot, sc->rec_p1);
87324     }
87325 }
87326 
87327 static s7_pointer fx_tc_and_a_or_a_laa(s7_scheme *sc, s7_pointer arg)
87328 {
87329   tick_tc(sc, OP_TC_AND_A_OR_A_LAA);
87330   op_tc_and_a_or_a_laa(sc, arg);
87331   sc->rec_p1 = sc->F;
87332   return(sc->value);
87333 }
87334 
87335 static void op_tc_or_a_and_a_laa(s7_scheme *sc, s7_pointer code)
87336 {
87337   s7_pointer fx_and, fx_or, fx_la, la_slot, fx_laa, laa_slot;
87338 
87339   fx_or = cdr(code);             /* first clause of or */
87340   fx_and = cdadr(fx_or);         /* same and */
87341   fx_la = cdadr(fx_and);
87342   la_slot = let_slots(sc->curlet);
87343   fx_laa = cdr(fx_la);
87344   laa_slot = next_slot(la_slot);
87345   while (true)
87346     {
87347       s7_pointer p;
87348       p = fx_call(sc, fx_or);
87349       if (p != sc->F) {sc->value = p; return;}
87350       if (fx_call(sc, fx_and) == sc->F) {sc->value = sc->F; return;}
87351       sc->rec_p1 = fx_call(sc, fx_la);
87352       slot_set_value(laa_slot, fx_call(sc, fx_laa));
87353       slot_set_value(la_slot, sc->rec_p1);
87354     }
87355 }
87356 
87357 static s7_pointer fx_tc_or_a_and_a_laa(s7_scheme *sc, s7_pointer arg)
87358 {
87359   tick_tc(sc, OP_TC_OR_A_AND_A_LAA);
87360   op_tc_or_a_and_a_laa(sc, arg);
87361   sc->rec_p1 = sc->F;
87362   return(sc->value);
87363 }
87364 
87365 static void op_tc_or_a_and_a_a_l3a(s7_scheme *sc, s7_pointer code)
87366 {
87367   s7_pointer fx_and1, fx_and2, fx_or, fx_la, la_slot, fx_laa, laa_slot, fx_l3a, l3a_slot;
87368 
87369   fx_or = cdr(code);             /* first clause of or */
87370   fx_and1 = opt3_pair(fx_or); /* (or_case) ? cdadr(fx_or) : cdaddr(fx_or); */
87371   fx_and2 = cdr(fx_and1);
87372   fx_la = cdadr(fx_and2);
87373   la_slot = let_slots(sc->curlet);
87374   fx_laa = cdr(fx_la);
87375   laa_slot = next_slot(la_slot);
87376   fx_l3a = cdr(fx_laa);
87377   l3a_slot = next_slot(laa_slot);
87378   if ((fx_proc(fx_and1) == fx_not_a) && (fx_proc(fx_and2) == fx_not_a))
87379     {
87380       fx_and1 = cdar(fx_and1);
87381       fx_and2 = cdar(fx_and2);
87382       while (true)
87383 	{
87384 	  s7_pointer p;
87385 	  p = fx_call(sc, fx_or);
87386 	  if (p != sc->F) {sc->value = p; return;}
87387 	  if ((fx_call(sc, fx_and1) != sc->F) || (fx_call(sc, fx_and2) != sc->F)) {sc->value = sc->F; return;}
87388 	  sc->rec_p1 = fx_call(sc, fx_la);
87389 	  sc->rec_p2 = fx_call(sc, fx_laa);
87390 	  slot_set_value(l3a_slot, fx_call(sc, fx_l3a));
87391 	  slot_set_value(la_slot, sc->rec_p1);
87392 	  slot_set_value(laa_slot, sc->rec_p2);
87393 	}}
87394   while (true)
87395     {
87396       s7_pointer p;
87397       p = fx_call(sc, fx_or);
87398       if (p != sc->F) {sc->value = p; return;}
87399       if ((fx_call(sc, fx_and1) == sc->F) || (fx_call(sc, fx_and2) == sc->F)) {sc->value = sc->F; return;}
87400       sc->rec_p1 = fx_call(sc, fx_la);
87401       sc->rec_p2 = fx_call(sc, fx_laa);
87402       slot_set_value(l3a_slot, fx_call(sc, fx_l3a));
87403       slot_set_value(la_slot, sc->rec_p1);
87404       slot_set_value(laa_slot, sc->rec_p2);
87405     }
87406 }
87407 
87408 static s7_pointer fx_tc_or_a_and_a_a_l3a(s7_scheme *sc, s7_pointer arg)
87409 {
87410   tick_tc(sc, OP_TC_OR_A_AND_A_A_L3A);
87411   op_tc_or_a_and_a_a_l3a(sc, arg);
87412   sc->rec_p1 = sc->F;
87413   sc->rec_p2 = sc->F;
87414   return(sc->value);
87415 }
87416 
87417 static bool op_tc_if_a_z_la(s7_scheme *sc, s7_pointer code, bool cond)
87418 {
87419   s7_pointer if_test, if_true, la, la_slot;
87420   if_test = (cond) ? cadr(code) : cdr(code);
87421   if_true = (cond) ? opt1_pair(cdr(code)) : opt1_pair(if_test);
87422   la = (cond) ? opt3_pair(cdr(code)) : opt3_pair(if_test);
87423   la_slot = let_slots(sc->curlet);
87424   if (is_t_integer(slot_value(la_slot)))
87425     {
87426       sc->pc = 0;
87427       if (bool_optimize(sc, if_test))
87428 	{
87429 	  opt_info *o, *o1;
87430 	  o = sc->opts[0];
87431 	  o1 = sc->opts[sc->pc];
87432 	  if (int_optimize(sc, la))
87433 	    {
87434 	      s7_pointer val;
87435 	      slot_set_value(la_slot, val = make_mutable_integer(sc, integer(slot_value(la_slot))));
87436 	      while (!(o->v[0].fb(o))){integer(val) = o1->v[0].fi(o1);}
87437 	      return(op_tc_z(sc, if_true));
87438 	    }}}
87439   while (fx_call(sc, if_test) == sc->F) {slot_set_value(la_slot, fx_call(sc, la));}
87440   return(op_tc_z(sc, if_true));
87441 }
87442 
87443 static s7_pointer fx_tc_if_a_z_la(s7_scheme *sc, s7_pointer arg)
87444 {
87445   tick_tc(sc, OP_TC_IF_A_Z_LA);
87446   op_tc_if_a_z_la(sc, arg, false);
87447   return(sc->value);
87448 }
87449 
87450 static s7_pointer fx_tc_cond_a_z_la(s7_scheme *sc, s7_pointer arg)
87451 {
87452   tick_tc(sc, OP_TC_COND_A_Z_LA);
87453   op_tc_if_a_z_la(sc, arg, true);
87454   return(sc->value);
87455 }
87456 
87457 static bool op_tc_if_a_la_z(s7_scheme *sc, s7_pointer code, bool cond)
87458 {
87459   s7_pointer if_test, if_false, la, la_slot;
87460   if_test = (cond) ? cadr(code) : cdr(code);
87461   if_false = (cond) ? opt1_pair(cdr(code)) : opt1_pair(if_test);
87462   la = (cond) ? opt3_pair(cdr(code)) : opt3_pair(if_test);
87463   la_slot = let_slots(sc->curlet);
87464   if (is_t_integer(slot_value(la_slot)))
87465     {
87466       sc->pc = 0;
87467       if (bool_optimize(sc, if_test))
87468 	{
87469 	  opt_info *o, *o1;
87470 	  o = sc->opts[0];
87471 	  o1 = sc->opts[sc->pc];
87472 	  if (int_optimize(sc, la))
87473 	    {
87474 	      s7_pointer val;
87475 	      slot_set_value(la_slot, val = make_mutable_integer(sc, integer(slot_value(la_slot))));
87476 	      while (o->v[0].fb(o)) {integer(val) = o1->v[0].fi(o1);}
87477 	      return(op_tc_z(sc, if_false));
87478 	    }}}
87479   while (fx_call(sc, if_test) != sc->F) {slot_set_value(la_slot, fx_call(sc, la));}
87480   return(op_tc_z(sc, if_false));
87481 }
87482 
87483 static s7_pointer fx_tc_if_a_la_z(s7_scheme *sc, s7_pointer arg)
87484 {
87485   tick_tc(sc, OP_TC_IF_A_LA_Z);
87486   op_tc_if_a_la_z(sc, arg, false);
87487   return(sc->value);
87488 }
87489 
87490 static s7_pointer fx_tc_cond_a_la_z(s7_scheme *sc, s7_pointer arg)
87491 {
87492   tick_tc(sc, OP_TC_COND_A_LA_Z);
87493   op_tc_if_a_la_z(sc, arg, true);
87494   return(sc->value);
87495 }
87496 
87497 typedef enum {TC_IF, TC_COND, TC_AND} tc_choice_t;
87498 
87499 static bool op_tc_if_a_z_laa(s7_scheme *sc, s7_pointer code, bool z_first, tc_choice_t cond)
87500 {
87501   s7_pointer if_test, if_z, la, laa, la_slot, laa_slot;
87502   s7_function tf;
87503   if (cond == TC_IF)
87504     {
87505       if_test = cdr(code);
87506       if_z = opt1_pair(if_test); /* if_z = (z_first) ? cdr(if_test) : cddr(if_test) */
87507       la = opt3_pair(if_test);   /* la = (z_first) ? cdaddr(if_test) : cdadr(if_test) */
87508     }
87509   else
87510     {
87511       if_test = cadr(code);
87512       if_z = opt1_pair(cdr(code)); /* if_z = (z_first) ? cdr(if_test) : cdr(caddr(code)) */
87513       la = opt3_pair(cdr(code));   /* la = (z_first) ? cdr(cadr(caddr(code))) : cdadr(if_test) */
87514     }
87515   laa = cdr(la);
87516   la_slot = let_slots(sc->curlet);
87517   laa_slot = next_slot(la_slot);
87518 #if (!WITH_GMP)
87519   if (!no_bool_opt(code))
87520     {
87521       sc->pc = 0;
87522       if (bool_optimize(sc, if_test))
87523 	{
87524 	  opt_info *o, *o1, *o2;
87525 	  int32_t start_pc;
87526 	  o = sc->opts[0];
87527 	  start_pc = sc->pc;
87528 	  o1 = sc->opts[sc->pc];
87529 	  if ((is_t_integer(slot_value(la_slot))) &&
87530 	      (is_t_integer(slot_value(laa_slot))))
87531 	    {
87532 	      if (int_optimize(sc, la))
87533 		{
87534 		  o2 = sc->opts[sc->pc];
87535 		  if (int_optimize(sc, laa))
87536 		    {
87537 		      s7_pointer val1, val2;
87538 		      s7_int (*fi1)(opt_info *o);
87539 		      s7_int (*fi2)(opt_info *o);
87540 		      bool (*fb)(opt_info *o);
87541 		      slot_set_value(la_slot, val1 = make_mutable_integer(sc, integer(slot_value(la_slot))));
87542 		      slot_set_value(laa_slot, val2 = make_mutable_integer(sc, integer(slot_value(laa_slot))));
87543 		      fb = o->v[0].fb;
87544 		      fi1 = o1->v[0].fi;
87545 		      fi2 = o2->v[0].fi;
87546 		      if ((z_first) &&
87547 			  (fb == opt_b_ii_sc_lt) &&
87548 			  (fi1 == opt_i_ii_sc_sub))
87549 			{
87550 			  s7_int lim, m;
87551 			  s7_pointer slot1, slot2;
87552 			  lim = o->v[2].i;
87553 			  m = o1->v[2].i;
87554 			  slot1 = o->v[1].p;
87555 			  slot2 = o1->v[1].p;
87556 			  while (integer(slot_value(slot1)) >= lim)
87557 			    {
87558 			      s7_int i1;
87559 			      i1 = integer(slot_value(slot2)) - m;
87560 			      integer(val2) = fi2(o2);
87561 			      integer(val1) = i1;
87562 			    }}
87563 		      else
87564 			while (fb(o) != z_first)
87565 			  {
87566 			    s7_int i1;
87567 			    i1 = fi1(o1);
87568 			    integer(val2) = fi2(o2);
87569 			    integer(val1) = i1;
87570 			  }
87571 		      return(op_tc_z(sc, if_z));
87572 		    }}}
87573 
87574 	  if ((is_t_real(slot_value(la_slot))) &&
87575 	      (is_t_real(slot_value(laa_slot))))
87576 	    {
87577 	      sc->pc = start_pc;
87578 	      if (float_optimize(sc, la))
87579 		{
87580 		  o2 = sc->opts[sc->pc];
87581 		  if (float_optimize(sc, laa))
87582 		    {
87583 		      s7_pointer val1, val2;
87584 		      s7_double (*fd1)(opt_info *o);
87585 		      s7_double (*fd2)(opt_info *o);
87586 		      bool (*fb)(opt_info *o);
87587 		      slot_set_value(la_slot, val1 = s7_make_mutable_real(sc, real(slot_value(la_slot))));
87588 		      slot_set_value(laa_slot, val2 = s7_make_mutable_real(sc, real(slot_value(laa_slot))));
87589 		      fb = o->v[0].fb;
87590 		      fd1 = o1->v[0].fd;
87591 		      fd2 = o2->v[0].fd;
87592 		      if ((z_first) &&
87593 			  (fb == opt_b_dd_sc_lt) &&
87594 			  (fd1 == opt_d_dd_sc_sub))
87595 			{
87596 			  s7_double lim, m;
87597 			  s7_pointer slot1, slot2;
87598 			  lim = o->v[2].x;
87599 			  m = o1->v[2].x;
87600 			  slot1 = o->v[1].p;
87601 			  slot2 = o1->v[1].p;
87602 			  while (real(slot_value(slot1)) >= lim)
87603 			    {
87604 			      s7_double x1;
87605 			      x1 = real(slot_value(slot2)) - m;
87606 			      real(val2) = fd2(o2);
87607 			      real(val1) = x1;
87608 			    }}
87609 		      else
87610 			while (fb(o) != z_first)
87611 			  {
87612 			    s7_double x1;
87613 			    x1 = fd1(o1);
87614 			    real(val2) = fd2(o2);
87615 			    real(val1) = x1;
87616 			  }
87617 		      return(op_tc_z(sc, if_z));
87618 		    }}}}
87619       set_no_bool_opt(code);
87620     }
87621 #endif
87622   tf = fx_proc(if_test);
87623   if_test = car(if_test);
87624   if (z_first)
87625     {
87626       if ((fx_proc(la) == fx_cdr_t) && (fx_proc(laa) == fx_subtract_u1) &&
87627 	  (fn_proc(if_test) == g_num_eq_xi) &&  /* was also (fx_proc(if_test) == fx_num_eq_ui) but we cloberred if_test above */
87628 	  (is_pair(slot_value(la_slot))) && (is_t_integer(slot_value(laa_slot))))
87629 	{ /* list-tail ferchrissake */
87630 	  s7_int start, end;
87631 	  s7_pointer lst;
87632 	  end = integer(caddr(if_test));
87633 	  lst = slot_value(la_slot);
87634 	  for (start = integer(slot_value(laa_slot)); start > end; start--)
87635 	    lst = cdr(lst);
87636 	  slot_set_value(la_slot, lst);
87637 	}
87638       else
87639 	while (tf(sc, if_test) == sc->F)
87640 	  {
87641 	    sc->rec_p1 = fx_call(sc, la);
87642 	    slot_set_value(laa_slot, fx_call(sc, laa));
87643 	    slot_set_value(la_slot, sc->rec_p1);
87644 	  }}
87645   else
87646     while (tf(sc, if_test) != sc->F)
87647       {
87648 	sc->rec_p1 = fx_call(sc, la);
87649 	slot_set_value(laa_slot, fx_call(sc, laa));
87650 	slot_set_value(la_slot, sc->rec_p1);
87651       }
87652   return(op_tc_z(sc, if_z));
87653 }
87654 
87655 static s7_pointer fx_tc_if_a_z_laa(s7_scheme *sc, s7_pointer arg)
87656 {
87657   tick_tc(sc, OP_TC_IF_A_Z_LAA);
87658   op_tc_if_a_z_laa(sc, arg, true, TC_IF);
87659   sc->rec_p1 = sc->F;
87660   return(sc->value);
87661 }
87662 
87663 static s7_pointer fx_tc_cond_a_z_laa(s7_scheme *sc, s7_pointer arg)
87664 {
87665   tick_tc(sc, OP_TC_COND_A_Z_LAA);
87666   op_tc_if_a_z_laa(sc, arg, true, TC_COND);
87667   sc->rec_p1 = sc->F;
87668   return(sc->value);
87669 }
87670 
87671 static s7_pointer fx_tc_if_a_laa_z(s7_scheme *sc, s7_pointer arg)
87672 {
87673   tick_tc(sc, OP_TC_IF_A_LAA_Z);
87674   op_tc_if_a_z_laa(sc, arg, false, TC_IF);
87675   sc->rec_p1 = sc->F;
87676   return(sc->value);
87677 }
87678 
87679 static s7_pointer fx_tc_cond_a_laa_z(s7_scheme *sc, s7_pointer arg)
87680 {
87681   tick_tc(sc, OP_TC_COND_A_LAA_Z);
87682   op_tc_if_a_z_laa(sc, arg, false, TC_COND);
87683   sc->rec_p1 = sc->F;
87684   return(sc->value);
87685 }
87686 
87687 static bool op_tc_if_a_z_l3a(s7_scheme *sc, s7_pointer code, bool z_first)
87688 {
87689   s7_pointer if_test, f_z, la, laa, l3a, la_slot, laa_slot, l3a_slot;
87690   s7_function tf;
87691   if_test = cdr(code);
87692   f_z = opt1_pair(if_test); /* if_z = (z_first) ? cdr(if_test) : cddr(if_test) */
87693   la = opt3_pair(if_test);   /* la = (z_first) ? cdaddr(if_test) : cdadr(if_test) */
87694   laa = cdr(la);
87695   l3a = cdr(laa);
87696   la_slot = let_slots(sc->curlet);
87697   laa_slot = next_slot(la_slot);
87698   l3a_slot = next_slot(laa_slot);
87699   tf = fx_proc(if_test);
87700   if_test = car(if_test);
87701   while ((tf(sc, if_test) == sc->F) == z_first)
87702     {
87703       sc->rec_p1 = fx_call(sc, la);
87704       sc->rec_p2 = fx_call(sc, laa);
87705       slot_set_value(l3a_slot, fx_call(sc, l3a));
87706       slot_set_value(laa_slot, sc->rec_p2);
87707       slot_set_value(la_slot, sc->rec_p1);
87708     }
87709   return(op_tc_z(sc, f_z));
87710 }
87711 
87712 static s7_pointer fx_tc_if_a_z_l3a(s7_scheme *sc, s7_pointer arg)
87713 {
87714   tick_tc(sc, OP_TC_IF_A_Z_L3A);
87715   op_tc_if_a_z_l3a(sc, arg, true);
87716   sc->rec_p1 = sc->F;
87717   sc->rec_p2 = sc->F;
87718   return(sc->value);
87719 }
87720 
87721 static s7_pointer fx_tc_if_a_l3a_z(s7_scheme *sc, s7_pointer arg)
87722 {
87723   tick_tc(sc, OP_TC_IF_A_L3A_Z);
87724   op_tc_if_a_z_l3a(sc, arg, false);
87725   sc->rec_p1 = sc->F;
87726   sc->rec_p2 = sc->F;
87727   return(sc->value);
87728 }
87729 
87730 static bool op_tc_if_a_z_if_a_z_la(s7_scheme *sc, s7_pointer code, bool z_first, tc_choice_t cond)
87731 {
87732   s7_pointer if_test, if_true, if_false, f_test, f_z, la, la_slot, endp;
87733   bool tc_and;
87734   tc_and = (cond == TC_AND);
87735   if (cond != TC_COND)
87736     {
87737       if_test = cdr(code);
87738       if_true = (!tc_and) ? cdr(if_test) : sc->F;
87739       if_false = (!tc_and) ? cadr(if_true) : cadr(if_test);
87740       f_test = cdr(if_false);
87741       f_z = (z_first) ? cdr(f_test) : cddr(f_test);
87742       la = (z_first) ? cdaddr(f_test) : cdadr(f_test);
87743     }
87744   else
87745     {
87746       if_test = cadr(code);    /* code: (cond (a1 z1) (a2 z2|la) (else la|z2)) */
87747       if_true = cdr(if_test);
87748       if_false = caddr(code);  /* (a2 z2|la) */
87749       f_test = if_false;
87750       f_z = (z_first) ? cdr(f_test) : cdr(cadddr(code));
87751       la = (z_first) ? cdadr(cadddr(code)) : cdadr(caddr(code));
87752     }
87753 
87754   la_slot = let_slots(sc->curlet);
87755 #if (!WITH_GMP)
87756   if (is_t_integer(slot_value(la_slot)))
87757     {
87758       opt_info *o;
87759       sc->pc = 0;
87760       o = sc->opts[0];
87761       if (bool_optimize_nw(sc, if_test))
87762  	{
87763 	  opt_info *o1;
87764 	  o1 = sc->opts[sc->pc];
87765  	  if (bool_optimize_nw(sc, f_test))
87766  	    {
87767 	      opt_info *o2;
87768 	      o2 = sc->opts[sc->pc];
87769  	      if (int_optimize(sc, la))
87770  		{
87771  		  s7_pointer val;
87772  		  slot_set_value(la_slot, val = make_mutable_integer(sc, integer(slot_value(la_slot))));
87773  		  if (tc_and)
87774 		    while (true)
87775 		      {
87776 			if (!o->v[0].fb(o)) {sc->value = sc->F; return(true);}
87777 			if (o1->v[0].fb(o1) == z_first) {endp = f_z; break;}
87778 			integer(val) = o2->v[0].fi(o2);
87779 		      }
87780  		  else
87781 		    while (true)
87782 		      {
87783 			if (o->v[0].fb(o)) {endp = if_true; break;}
87784 			if (o1->v[0].fb(o1) == z_first) {endp = f_z; break;}
87785 			integer(val) = o2->v[0].fi(o2);
87786 		      }
87787  		  return(op_tc_z(sc, endp));
87788  		}}}}
87789 #endif
87790   while (true)
87791     {
87792       if ((fx_call(sc, if_test) == sc->F) == tc_and) {if (tc_and) {sc->value = sc->F; return(true);} else {endp = if_true; break;}}
87793       if ((fx_call(sc, f_test) == sc->F) != z_first) {endp = f_z; break;}
87794       slot_set_value(la_slot, fx_call(sc, la));
87795     }
87796   return(op_tc_z(sc, endp));
87797 }
87798 
87799 static s7_pointer fx_tc_if_a_z_if_a_z_la(s7_scheme *sc, s7_pointer arg)
87800 {
87801   tick_tc(sc, OP_TC_IF_A_Z_IF_A_Z_LA);
87802   op_tc_if_a_z_if_a_z_la(sc, arg, true, TC_IF);
87803   return(sc->value);
87804 }
87805 
87806 static s7_pointer fx_tc_if_a_z_if_a_la_z(s7_scheme *sc, s7_pointer arg)
87807 {
87808   tick_tc(sc, OP_TC_IF_A_Z_IF_A_LA_Z);
87809   op_tc_if_a_z_if_a_z_la(sc, arg, false, TC_IF);
87810   return(sc->value);
87811 }
87812 
87813 static s7_pointer fx_tc_cond_a_z_a_z_la(s7_scheme *sc, s7_pointer arg)
87814 {
87815   tick_tc(sc, OP_TC_COND_A_Z_A_Z_LA);
87816   op_tc_if_a_z_if_a_z_la(sc, arg, true, TC_COND);
87817   return(sc->value);
87818 }
87819 
87820 static s7_pointer fx_tc_cond_a_z_a_la_z(s7_scheme *sc, s7_pointer arg)
87821 {
87822   tick_tc(sc, OP_TC_COND_A_Z_A_LA_Z);
87823   op_tc_if_a_z_if_a_z_la(sc, arg, false, TC_COND);
87824   return(sc->value);
87825 }
87826 
87827 static s7_pointer fx_tc_and_a_if_a_z_la(s7_scheme *sc, s7_pointer arg)
87828 {
87829   tick_tc(sc, OP_TC_AND_A_IF_A_Z_LA);
87830   op_tc_if_a_z_if_a_z_la(sc, arg, true, TC_AND);
87831   return(sc->value);
87832 }
87833 
87834 static s7_pointer fx_tc_and_a_if_a_la_z(s7_scheme *sc, s7_pointer arg)
87835 {
87836   tick_tc(sc, OP_TC_AND_A_IF_A_LA_Z);
87837   op_tc_if_a_z_if_a_z_la(sc, arg, false, TC_AND);
87838   return(sc->value);
87839 }
87840 
87841 static bool op_tc_if_a_z_if_a_z_laa(s7_scheme *sc, bool cond, s7_pointer code)
87842 {
87843   s7_pointer if_test, if_true, if_false, f_test, f_true, la, la_slot, laa, laa_slot, endp, slot1;
87844   if_test = (cond) ? cadr(code) : cdr(code);
87845   if_true = cdr(if_test);
87846   if (!cond) if_false = cadr(if_true);
87847   f_test = (cond) ? caddr(code) : cdr(if_false);
87848   f_true = cdr(f_test);
87849   la = (cond) ? opt3_pair(code) : cdadr(f_true);  /* cdadr(cadddr(code)) */
87850   la_slot = let_slots(sc->curlet);
87851   laa = cdr(la);
87852   laa_slot = next_slot(la_slot);
87853   slot1 = (fx_proc(if_test) == fx_is_null_t) ? la_slot : ((fx_proc(if_test) == fx_is_null_u) ? laa_slot : NULL);
87854   if (slot1)
87855     {
87856       if ((slot1 == laa_slot) && (fx_proc(f_test) == fx_is_null_t) && (fx_proc(la) == fx_cdr_t) && (fx_proc(laa) == fx_cdr_u) &&
87857 	  (s7_is_boolean(car(if_true))) && (s7_is_boolean(car(f_true))))
87858 	{
87859 	  s7_pointer la_val, laa_val;
87860 	  la_val = slot_value(la_slot);
87861 	  laa_val = slot_value(laa_slot);
87862 	  while (true)
87863 	    {
87864 	      if (is_null(laa_val)) {sc->value = car(if_true); return(true);}
87865 	      if (is_null(la_val)) {sc->value = car(f_true); return(true);}
87866 	      la_val = cdr(la_val);
87867 	      laa_val = cdr(laa_val);
87868 	    }}
87869       while (true)
87870 	{
87871 	  if (is_null(slot_value(slot1))) {endp = if_true; break;}
87872 	  if (fx_call(sc, f_test) != sc->F) {endp = f_true; break;}
87873 	  sc->rec_p1 = fx_call(sc, la);
87874 	  slot_set_value(laa_slot, fx_call(sc, laa));
87875 	  slot_set_value(la_slot, sc->rec_p1);
87876 	}}
87877   else
87878     while (true)
87879       {
87880 	if (fx_call(sc, if_test) != sc->F) {endp = if_true; break;}
87881 	if (fx_call(sc, f_test) != sc->F) {endp = f_true; break;}
87882 	sc->rec_p1 = fx_call(sc, la);
87883 	slot_set_value(laa_slot, fx_call(sc, laa));
87884 	slot_set_value(la_slot, sc->rec_p1);
87885       }
87886   return(op_tc_z(sc, endp));
87887 }
87888 
87889 static s7_pointer fx_tc_if_a_z_if_a_z_laa(s7_scheme *sc, s7_pointer arg)
87890 {
87891   tick_tc(sc, OP_TC_IF_A_Z_IF_A_Z_LAA);
87892   op_tc_if_a_z_if_a_z_laa(sc, false, arg);
87893   sc->rec_p1 = sc->F;
87894   return(sc->value);
87895 }
87896 
87897 static s7_pointer fx_tc_cond_a_z_a_z_laa(s7_scheme *sc, s7_pointer arg)
87898 {
87899   tick_tc(sc, OP_TC_COND_A_Z_A_Z_LAA);
87900   op_tc_if_a_z_if_a_z_laa(sc, true, arg);
87901   sc->rec_p1 = sc->F;
87902   return(sc->value);
87903 }
87904 
87905 static bool op_tc_if_a_z_if_a_laa_z(s7_scheme *sc, bool cond, s7_pointer code)
87906 {
87907   s7_pointer if_test, if_true, if_false, f_test, f_true, f_false, la, la_slot, laa, laa_slot, endp;
87908   if_test = (cond) ? cadr(code) : cdr(code);
87909   if_true = cdr(if_test);
87910   if (!cond) if_false = cadr(if_true);
87911   f_test = (cond) ? caddr(code) : cdr(if_false);
87912   f_true = cdr(f_test);
87913   f_false = (cond) ? cdr(cadddr(code)) : cdr(f_true);
87914   la = (cond) ? opt3_pair(code) : cdar(f_true); /* cdadr(caddr(code)) */
87915   la_slot = let_slots(sc->curlet);
87916   laa = cdr(la);
87917   laa_slot = next_slot(la_slot);
87918   while (true)
87919     {
87920       if (fx_call(sc, if_test) != sc->F) {endp = if_true; break;}
87921       if (fx_call(sc, f_test) == sc->F) {endp = f_false; break;}
87922       sc->rec_p1 = fx_call(sc, la);
87923       slot_set_value(laa_slot, fx_call(sc, laa));
87924       slot_set_value(la_slot, sc->rec_p1);
87925     }
87926   return(op_tc_z(sc, endp));
87927 }
87928 
87929 static s7_pointer fx_tc_if_a_z_if_a_laa_z(s7_scheme *sc, s7_pointer arg)
87930 {
87931   tick_tc(sc, OP_TC_IF_A_Z_IF_A_LAA_Z);
87932   op_tc_if_a_z_if_a_laa_z(sc, false, arg);
87933   sc->rec_p1 = sc->F;
87934   return(sc->value);
87935 }
87936 
87937 static s7_pointer fx_tc_cond_a_z_a_laa_z(s7_scheme *sc, s7_pointer arg)
87938 {
87939   tick_tc(sc, OP_TC_COND_A_Z_A_LAA_Z);
87940   op_tc_if_a_z_if_a_laa_z(sc, true, arg);
87941   sc->rec_p1 = sc->F;
87942   return(sc->value);
87943 }
87944 
87945 static bool op_tc_if_a_z_if_a_l3a_l3a(s7_scheme *sc, s7_pointer code)
87946 {
87947   s7_pointer if_test, if_true, if_false, f_test, f_true, f_false, la1, la2, la_slot, laa1, laa2, laa_slot, l3a1, l3a2, l3a_slot, endp;
87948   if_test = cdr(code);
87949   if_true = cdr(if_test);
87950   if_false = cadr(if_true);
87951   f_test = cdr(if_false);
87952   f_true = cdr(f_test);
87953   f_false = cdr(f_true);
87954   la1 = cdar(f_true);
87955   la2 = cdar(f_false);
87956   la_slot = let_slots(sc->curlet);
87957   laa1 = cdr(la1);
87958   laa2 = cdr(la2);
87959   laa_slot = next_slot(la_slot);
87960   l3a1 = cdr(laa1);
87961   l3a2 = cdr(laa2);
87962   l3a_slot = next_slot(laa_slot);
87963 
87964   while (true)
87965     {
87966       if (fx_call(sc, if_test) != sc->F) {endp = if_true; break;}
87967       if (fx_call(sc, f_test) != sc->F)
87968 	{
87969 	  sc->rec_p1 = fx_call(sc, la1);
87970 	  sc->rec_p2 = fx_call(sc, laa1);
87971 	  slot_set_value(l3a_slot, fx_call(sc, l3a1));
87972 	}
87973       else
87974 	{
87975 	  sc->rec_p1 = fx_call(sc, la2);
87976 	  sc->rec_p2 = fx_call(sc, laa2);
87977 	  slot_set_value(l3a_slot, fx_call(sc, l3a2));
87978 	}
87979       slot_set_value(laa_slot, sc->rec_p2);
87980       slot_set_value(la_slot, sc->rec_p1);
87981     }
87982   return(op_tc_z(sc, endp));
87983 }
87984 
87985 static s7_pointer fx_tc_if_a_z_if_a_l3a_l3a(s7_scheme *sc, s7_pointer arg)
87986 {
87987   tick_tc(sc, OP_TC_IF_A_Z_IF_A_L3A_L3A);
87988   op_tc_if_a_z_if_a_l3a_l3a(sc, arg);
87989   sc->rec_p1 = sc->F;
87990   sc->rec_p2 = sc->F;
87991   return(sc->value);
87992 }
87993 
87994 static bool op_tc_let_if_a_z_la(s7_scheme *sc, s7_pointer code)
87995 {
87996   s7_pointer body, if_test, if_true, if_false, la, la_slot, let_slot, let_var, outer_let, inner_let;
87997   let_var = caadr(code);
87998   body = caddr(code);
87999   outer_let = sc->curlet;
88000   sc->curlet = make_let_with_slot(sc, sc->curlet, car(let_var), fx_call(sc, cdr(let_var)));
88001   inner_let = sc->curlet;
88002   push_stack_no_let_no_code(sc, OP_GC_PROTECT, inner_let);
88003   let_slot = let_slots(sc->curlet);
88004   let_var = cdr(let_var);
88005 
88006   if_test = cdr(body);
88007   if_true = cddr(body);
88008   if_false = cadddr(body);
88009 
88010   la = cdr(if_false);
88011   la_slot = let_slots(outer_let);
88012 
88013   while (fx_call(sc, if_test) == sc->F)
88014     {
88015       slot_set_value(la_slot, fx_call(sc, la));
88016       sc->curlet = outer_let;
88017       slot_set_value(let_slot, fx_call(sc, let_var));
88018       sc->curlet = inner_let;
88019     }
88020   unstack(sc);
88021   if (op_tc_z(sc, if_true))
88022     {
88023       free_cell(sc, let_slots(inner_let));
88024       free_cell(sc, inner_let);
88025       return(true);
88026     }
88027   return(false);
88028 }
88029 
88030 static s7_pointer fx_tc_let_if_a_z_la(s7_scheme *sc, s7_pointer arg)
88031 {
88032   tick_tc(sc, OP_TC_LET_IF_A_Z_LA);
88033   op_tc_let_if_a_z_la(sc, arg);
88034   return(sc->value);
88035 }
88036 
88037 static bool op_tc_let_if_a_z_laa(s7_scheme *sc, s7_pointer code)
88038 {
88039   s7_pointer body, if_test, if_true, if_false, la, la_slot, let_slot, laa, laa_slot, let_var, outer_let, inner_let;
88040   let_var = caadr(code);
88041   body = caddr(code);
88042   outer_let = sc->curlet;
88043   sc->curlet = make_let_with_slot(sc, sc->curlet, car(let_var), fx_call(sc, cdr(let_var)));
88044   inner_let = sc->curlet;
88045   push_stack_no_let_no_code(sc, OP_GC_PROTECT, inner_let);
88046   let_slot = let_slots(sc->curlet);
88047   let_var = cdr(let_var);
88048 
88049   if_test = cdr(body);
88050   if_true = cddr(body);
88051   if_false = cadddr(body);
88052 
88053   la = cdr(if_false);
88054   la_slot = let_slots(outer_let);
88055   laa = cddr(if_false);
88056   laa_slot = next_slot(la_slot);
88057 #if (!WITH_GMP)
88058   if (!no_bool_opt(code))
88059     {
88060       sc->pc = 0;
88061       if (bool_optimize(sc, if_test))
88062 	{
88063 	  opt_info *o, *o1, *o2, *o3;
88064 	  o = sc->opts[0];
88065 	  o1 = sc->opts[sc->pc];
88066 	  if ((is_t_integer(slot_value(la_slot))) &&
88067 	      (is_t_integer(slot_value(laa_slot))))
88068 	    {
88069 	      if (int_optimize(sc, la))
88070 		{
88071 		  o2 = sc->opts[sc->pc];
88072 		  if (int_optimize(sc, laa))
88073 		    {
88074 		      o3 = sc->opts[sc->pc];
88075 		      sc->curlet = outer_let;
88076 		      if (int_optimize(sc, let_var))
88077 			{
88078 			  s7_pointer val1, val2, val3;
88079 			  sc->curlet = inner_let;
88080 			  slot_set_value(la_slot, val1 = make_mutable_integer(sc, integer(slot_value(la_slot))));
88081 			  slot_set_value(laa_slot, val2 = make_mutable_integer(sc, integer(slot_value(laa_slot))));
88082 			  slot_set_value(let_slot, val3 = make_mutable_integer(sc, integer(slot_value(let_slot))));
88083 			  while (!(o->v[0].fb(o)))
88084 			    {
88085 			      s7_int i1;
88086 			      i1 = o1->v[0].fi(o1);
88087 			      integer(val2) = o2->v[0].fi(o2);
88088 			      integer(val1) = i1;
88089 			      integer(val3) = o3->v[0].fi(o3);
88090 			    }
88091 			  unstack(sc);
88092 			  if (op_tc_z(sc, if_true))  /* sc->inner_let in effect here since it was the last set above */
88093 			    {
88094 			      free_cell(sc, let_slots(inner_let));
88095 			      free_cell(sc, inner_let);
88096 			      return(true);
88097 			    }
88098 			  return(false);
88099 			}}}}}
88100       set_no_bool_opt(code);
88101     }
88102 #endif
88103   while (fx_call(sc, if_test) == sc->F)
88104     {
88105       sc->rec_p1 = fx_call(sc, la);
88106       slot_set_value(laa_slot, fx_call(sc, laa));
88107       slot_set_value(la_slot, sc->rec_p1);
88108       sc->curlet = outer_let;
88109       slot_set_value(let_slot, fx_call(sc, let_var));
88110       sc->curlet = inner_let;
88111     }
88112   unstack(sc);
88113   if (op_tc_z(sc, if_true))
88114     {
88115       free_cell(sc, let_slots(inner_let));
88116       free_cell(sc, inner_let);
88117       return(true);
88118     }
88119   return(false);
88120 }
88121 
88122 static s7_pointer fx_tc_let_if_a_z_laa(s7_scheme *sc, s7_pointer arg)
88123 {
88124   tick_tc(sc, OP_TC_LET_IF_A_Z_LAA);
88125   op_tc_let_if_a_z_laa(sc, arg);
88126   sc->rec_p1 = sc->F;
88127   return(sc->value);
88128 }
88129 
88130 static void op_tc_let_when_laa(s7_scheme *sc, bool when, s7_pointer code)
88131 {
88132   s7_pointer p, body, if_test, if_true, la, let_slot, laa, let_var, outer_let, inner_let;
88133   let_var = caadr(code);
88134   body = caddr(code);
88135   outer_let = sc->curlet;
88136   sc->curlet = make_let_with_slot(sc, sc->curlet, car(let_var), fx_call(sc, cdr(let_var)));
88137   inner_let = sc->curlet;
88138   push_stack_no_let_no_code(sc, OP_GC_PROTECT, inner_let);
88139   let_slot = let_slots(sc->curlet);
88140   let_var = cdr(let_var);
88141 
88142   if_test = cdr(body);
88143   if_true = cddr(body);
88144   for (p = if_true; is_pair(cdr(p)); p = cdr(p));
88145   la = cdar(p);
88146   laa = cddar(p);
88147 
88148   if ((car(la) == slot_symbol(let_slots(outer_let))) &&
88149       (car(laa) == slot_symbol(next_slot(let_slots(outer_let)))))
88150     {
88151       if ((cdr(if_true) == p) && (!when))
88152 	{
88153 	  s7_pointer a1, a2;
88154 	  a1 = slot_value(let_slots(outer_let));
88155 	  a2 = slot_value(next_slot(let_slots(outer_let)));
88156 	  if ((is_input_port(a1)) && (is_output_port(a2)) && (is_string_port(a1)) && (is_file_port(a2)) &&
88157 	      (!port_is_closed(a1)) && (!port_is_closed(a2)) && (fx_proc(if_true) == fx_c_tU_direct) &&
88158 	      (fx_proc(let_var) == fx_c_t_direct) && (((s7_p_pp_t)opt3_direct(cdar(if_true))) == write_char_p_pp) &&
88159 	      (((s7_p_p_t)opt2_direct(cdar(let_var))) == read_char_p_p) && (fx_proc(if_test) == fx_is_eof_t))
88160 	    {
88161 	      int32_t c;
88162 	      a1 = slot_value(let_slots(outer_let));
88163 	      a2 = slot_value(next_slot(let_slots(outer_let)));
88164 	      c = (int32_t)s7_character(slot_value(let_slots(inner_let)));
88165 	      while (c != EOF)
88166 		{
88167 		  inline_file_write_char(sc, (uint8_t)c, a2);
88168 		  c = string_read_char(sc, a1);
88169 		}}
88170 	  else
88171 	    while (fx_call(sc, if_test) == sc->F)
88172 	      {
88173 		fx_call(sc, if_true);
88174 		sc->curlet = outer_let;
88175 		slot_set_value(let_slot, fx_call(sc, let_var));
88176 		sc->curlet = inner_let;
88177 	      }}
88178       else
88179 	while (true)
88180 	  {
88181 	    p = fx_call(sc, if_test);
88182 	    if (when) {if (p == sc->F) break;} else {if (p != sc->F) break;}
88183 	    for (p = if_true; is_pair(cdr(p)); p = cdr(p))
88184 	      fx_call(sc, p);
88185 	    sc->curlet = outer_let;
88186 	    slot_set_value(let_slot, fx_call(sc, let_var));
88187 	    sc->curlet = inner_let;
88188 	  }}
88189   else
88190     {
88191       s7_pointer la_slot, laa_slot;
88192       la_slot = let_slots(outer_let);
88193       laa_slot = next_slot(la_slot);
88194       while (true)
88195 	{
88196 	  p = fx_call(sc, if_test);
88197 	  if (when) {if (p == sc->F) break;} else {if (p != sc->F) break;}
88198 	  for (p = if_true; is_pair(cdr(p)); p = cdr(p))
88199 	    fx_call(sc, p);
88200 	  sc->rec_p1 = fx_call(sc, la);
88201 	  slot_set_value(laa_slot, fx_call(sc, laa));
88202 	  slot_set_value(la_slot, sc->rec_p1);
88203 	  sc->curlet = outer_let;
88204 	  slot_set_value(let_slot, fx_call(sc, let_var));
88205 	  sc->curlet = inner_let;
88206 	}}
88207   unstack(sc);
88208   free_cell(sc, let_slots(inner_let));
88209   free_cell(sc, inner_let);
88210   sc->value = sc->unspecified;
88211 }
88212 
88213 static s7_pointer fx_tc_let_when_laa(s7_scheme *sc, s7_pointer arg)
88214 {
88215   tick_tc(sc, OP_TC_LET_WHEN_LAA);
88216   op_tc_let_when_laa(sc, true, arg);
88217   sc->rec_p1 = sc->F;
88218   return(sc->value);
88219 }
88220 
88221 static s7_pointer fx_tc_let_unless_laa(s7_scheme *sc, s7_pointer arg)
88222 {
88223   tick_tc(sc, OP_TC_LET_WHEN_LAA);
88224   op_tc_let_when_laa(sc, false, arg);
88225   sc->rec_p1 = sc->F;
88226   return(sc->value);
88227 }
88228 
88229 static bool op_tc_if_a_z_let_if_a_z_laa(s7_scheme *sc, s7_pointer code)
88230 {
88231   s7_pointer if1_test, if1_true, if2, if2_test, if2_true, la, la_slot, laa, laa_slot, endp,
88232     let_expr, let_vars, inner_let, outer_let, slot, var;
88233   outer_let = sc->curlet;
88234   if1_test = cdr(code);
88235   if1_true = cdr(if1_test);  /*   cddr(code) */
88236   let_expr = cadr(if1_true); /* cadddr(code) */
88237   let_vars = cadr(let_expr);
88238   if2 = caddr(let_expr);
88239   if2_test = cdr(if2);
88240   if2_true = cdr(if2_test);  /*       cddr(if2) */
88241   la = cdadr(if2_true);      /* cdr(cadddr(if2)) */
88242   la_slot = let_slots(sc->curlet);
88243   laa = cdr(la);
88244   laa_slot = next_slot(la_slot);
88245 
88246   inner_let = make_let(sc, sc->curlet);
88247   push_stack_no_let_no_code(sc, OP_GC_PROTECT, inner_let);
88248   slot = make_slot(sc, caar(let_vars), sc->F);
88249   slot_set_next(slot, slot_end(sc));
88250   let_set_slots(inner_let, slot);
88251   symbol_set_local_slot_unincremented(caar(let_vars), let_id(inner_let), slot);
88252   for (var = cdr(let_vars); is_pair(var); var = cdr(var))
88253     slot = add_slot_at_end(sc, let_id(inner_let), slot, caar(var), sc->F);
88254 
88255   while (true)
88256     {
88257       if (fx_call(sc, if1_test) != sc->F) {endp = if1_true; break;}
88258 
88259       slot = let_slots(inner_let);
88260       slot_set_value(slot, fx_call(sc, cdar(let_vars)));
88261       sc->curlet = inner_let;
88262       for (var = cdr(let_vars), slot = next_slot(slot); is_pair(var); var = cdr(var), slot = next_slot(slot))
88263 	slot_set_value(slot, fx_call(sc, cdar(var)));
88264 
88265       if (fx_call(sc, if2_test) != sc->F) {endp = if2_true; break;}
88266       sc->rec_p1 = fx_call(sc, la);
88267       slot_set_value(laa_slot, fx_call(sc, laa));
88268       slot_set_value(la_slot, sc->rec_p1);
88269       sc->curlet = outer_let;
88270     }
88271   unstack(sc);
88272   if (op_tc_z(sc, endp))  /* might refer to inner_let slots */
88273     {
88274       free_cell(sc, let_slots(inner_let)); /* true = has_fx, so we should be done with the let */
88275       free_cell(sc, inner_let);
88276       return(true);
88277     }
88278   return(false);
88279 }
88280 
88281 static bool op_tc_let_cond(s7_scheme *sc, s7_pointer code)
88282 {
88283   s7_pointer outer_let, inner_let, let_var, let_slot, cond_body, slots, result;
88284   s7_function letf;
88285   bool read_case;
88286   /* code here == body in check_tc */
88287   let_var = caadr(code);
88288   outer_let = sc->curlet;
88289   sc->curlet = make_let_with_slot(sc, sc->curlet, car(let_var), fx_call(sc, cdr(let_var)));
88290   inner_let = sc->curlet;
88291   push_stack_no_let_no_code(sc, OP_GC_PROTECT, inner_let);
88292   let_slot = let_slots(sc->curlet);
88293   let_var = cdr(let_var);
88294   letf = fx_proc(let_var);
88295   let_var = car(let_var);
88296 
88297   if ((letf == fx_c_s_direct) &&                       /* an experiment */
88298       (symbol_id(cadr(let_var)) != let_id(outer_let))) /* i.e. not an argument to the recursive function, and not set! (safe closure body) */
88299     {
88300       letf = (s7_p_p_t)opt2_direct(cdr(let_var));
88301       let_var = lookup(sc, cadr(let_var));
88302     }
88303 
88304   cond_body = cdaddr(code);
88305   slots = let_slots(outer_let);
88306   /* in the named let no-var case slots may contain the let name (it's the funclet) */
88307 
88308   if (integer(opt3_arglen(cdr(code))) == 0) /* (loop) etc -- no args */
88309     while (true)
88310       {
88311 	s7_pointer p;
88312 	for (p = cond_body; is_pair(p); p = cdr(p))
88313 	  if (fx_call(sc, car(p)) != sc->F)
88314 	    {
88315 	      result = cdar(p);
88316 	      if (has_tc(result))
88317 		{
88318 		  sc->curlet = outer_let;
88319 		  slot_set_value(let_slot, letf(sc, let_var));
88320 		  sc->curlet = inner_let;
88321 		  break;
88322 		}
88323 	      else goto TC_LET_COND_DONE;
88324 	    }}
88325   if (integer(opt3_arglen(cdr(code))) == 1)
88326     while (true)
88327       {
88328 	s7_pointer p;
88329 	for (p = cond_body; is_pair(p); p = cdr(p))
88330 	  if (fx_call(sc, car(p)) != sc->F)
88331 	    {
88332 	      result = cdar(p);
88333 	      if (has_tc(result))
88334 		{
88335 		  slot_set_value(slots, fx_call(sc, cdar(result))); /* arg to recursion */
88336 		  sc->curlet = outer_let;
88337 		  slot_set_value(let_slot, letf(sc, let_var));   /* inner let var */
88338 		  sc->curlet = inner_let;
88339 		  break;
88340 		}
88341 	      else goto TC_LET_COND_DONE;
88342 	    }}
88343 
88344   let_set_has_pending_value(outer_let);
88345   read_case = ((letf == read_char_p_p) && (is_input_port(let_var)) && (is_string_port(let_var)) && (!port_is_closed(let_var)));
88346   while (true)
88347     {
88348       s7_pointer p;
88349       for (p = cond_body; is_pair(p); p = cdr(p))
88350 	if (fx_call(sc, car(p)) != sc->F)
88351 	  {
88352 	    result = cdar(p);
88353 	    if (has_tc(result))
88354 	      {
88355 		s7_pointer slot, arg;
88356 		for (slot = slots, arg = cdar(result); is_pair(arg); slot = next_slot(slot), arg = cdr(arg))
88357 		  slot_simply_set_pending_value(slot, fx_call(sc, arg));
88358 		for (slot = slots; tis_slot(slot); slot = next_slot(slot)) /* using two swapping lets instead is slightly slower */
88359 		  slot_set_value(slot, slot_pending_value(slot));
88360 
88361 		if (read_case)
88362 		  slot_set_value(let_slot, chars[string_read_char(sc, let_var)]);
88363 		else
88364 		  {
88365 		    sc->curlet = outer_let;
88366 		    slot_set_value(let_slot, letf(sc, let_var));
88367 		    sc->curlet = inner_let;
88368 		  }
88369 		break;
88370 	      }
88371 	    else goto TC_LET_COND_DONE;
88372 	  }}
88373   let_clear_has_pending_value(outer_let);
88374 
88375  TC_LET_COND_DONE:
88376   unstack(sc);
88377   if (has_fx(result))
88378     {
88379       sc->value = fx_call(sc, result);
88380       free_cell(sc, let_slots(inner_let));
88381       free_cell(sc, inner_let);
88382       return(true);
88383     }
88384   sc->code = car(result);
88385   return(false);
88386 }
88387 
88388 static s7_pointer fx_tc_let_cond(s7_scheme *sc, s7_pointer arg)
88389 {
88390   tick_tc(sc, OP_TC_LET_COND);
88391   op_tc_let_cond(sc, arg);
88392   return(sc->value);
88393 }
88394 
88395 static bool op_tc_cond_a_z_a_laa_laa(s7_scheme *sc, s7_pointer code)
88396 {
88397   s7_pointer c1, c2, c3, la1, la2, laa1, laa2, la_slot, laa_slot;
88398   c1 = cadr(code);
88399   c2 = caddr(code);
88400   la1 = cdadr(c2);
88401   laa1 = cddadr(c2);
88402   c3 = opt3_pair(code);  /* cadr(cadddr(code)) = cadr(else_clause) */
88403   la2 = cdr(c3);
88404   laa2 = cddr(c3);
88405   la_slot = let_slots(sc->curlet);
88406   laa_slot = next_slot(la_slot);
88407   while (true)
88408     {
88409       if (fx_call(sc, c1) != sc->F) {c1 = cdr(c1); break;}
88410       if (fx_call(sc, c2) != sc->F)
88411 	{
88412 	  sc->rec_p1 = fx_call(sc, la1);
88413 	  slot_set_value(laa_slot, fx_call(sc, laa1));
88414 	}
88415       else
88416 	{
88417 	  sc->rec_p1 = fx_call(sc, la2);
88418 	  slot_set_value(laa_slot, fx_call(sc, laa2));
88419 	}
88420       slot_set_value(la_slot, sc->rec_p1);
88421     }
88422   return(op_tc_z(sc, c1));
88423 }
88424 
88425 static s7_pointer fx_tc_cond_a_z_a_laa_laa(s7_scheme *sc, s7_pointer arg)
88426 {
88427   tick_tc(sc, OP_TC_COND_A_Z_A_LAA_LAA);
88428   op_tc_cond_a_z_a_laa_laa(sc, arg);
88429   sc->rec_p1 = sc->F;
88430   return(sc->value);
88431 }
88432 
88433 
88434 #define RECUR_INITIAL_STACK_SIZE 1024
88435 
88436 static void recur_resize(s7_scheme *sc)
88437 {
88438   s7_pointer stack;
88439   block_t *ob, *nb;
88440   stack = sc->rec_stack;
88441   vector_length(stack) = sc->rec_len * 2;
88442   ob = vector_block(stack);
88443   nb = reallocate(sc, ob, vector_length(stack) * sizeof(s7_pointer));
88444   block_info(nb) = NULL;
88445   vector_block(stack) = nb;
88446   vector_elements(stack) = (s7_pointer *)block_data(nb); /* GC looks only at elements within sc->rec_loc */
88447   sc->rec_len = vector_length(stack);
88448   sc->rec_els = vector_elements(stack);
88449 }
88450 
88451 static inline void recur_push(s7_scheme *sc, s7_pointer value)
88452 {
88453   if (sc->rec_loc == sc->rec_len)
88454     recur_resize(sc);
88455   sc->rec_els[sc->rec_loc] = value;
88456   sc->rec_loc++;
88457 }
88458 
88459 static inline void recur_push_unchecked(s7_scheme *sc, s7_pointer value)
88460 {
88461   sc->rec_els[sc->rec_loc++] = value;
88462 }
88463 
88464 static s7_pointer recur_pop(s7_scheme *sc)
88465 {
88466   return(sc->rec_els[--sc->rec_loc]);
88467 }
88468 
88469 static s7_pointer recur_pop2(s7_scheme *sc)
88470 {
88471   sc->rec_loc -= 2;
88472   return(sc->rec_els[sc->rec_loc + 1]);
88473 }
88474 
88475 static s7_pointer recur_ref(s7_scheme *sc, s7_int loc)
88476 {
88477   return(sc->rec_els[sc->rec_loc - loc]);
88478 }
88479 
88480 static s7_pointer recur_swap(s7_scheme *sc, s7_pointer value)
88481 {
88482   s7_pointer res;
88483   res = sc->rec_els[sc->rec_loc - 1];
88484   sc->rec_els[sc->rec_loc - 1] = value;
88485   return(res);
88486 }
88487 
88488 static s7_pointer recur_make_stack(s7_scheme *sc)
88489 {
88490   if (!sc->rec_stack)
88491     {
88492       sc->rec_stack = make_simple_vector(sc, RECUR_INITIAL_STACK_SIZE);
88493       sc->rec_els = vector_elements(sc->rec_stack);
88494       sc->rec_len = RECUR_INITIAL_STACK_SIZE;
88495     }
88496   sc->rec_loc = 0;
88497   return(sc->rec_stack);
88498 }
88499 
88500 static void rec_set_test(s7_scheme *sc, s7_pointer p)
88501 {
88502   sc->rec_testp = p;
88503   sc->rec_testf = fx_proc(sc->rec_testp);
88504   sc->rec_testp = car(sc->rec_testp);
88505 }
88506 
88507 static void rec_set_res(s7_scheme *sc, s7_pointer p)
88508 {
88509   sc->rec_resp = p;
88510   sc->rec_resf = fx_proc(sc->rec_resp);
88511   sc->rec_resp = car(sc->rec_resp);
88512 }
88513 
88514 static void rec_set_f1(s7_scheme *sc, s7_pointer p)
88515 {
88516   sc->rec_f1p = p;
88517   sc->rec_f1f = fx_proc(sc->rec_f1p);
88518   sc->rec_f1p = car(sc->rec_f1p);
88519 }
88520 
88521 static void rec_set_f2(s7_scheme *sc, s7_pointer p)
88522 {
88523   sc->rec_f2p = p;
88524   sc->rec_f2f = fx_proc(sc->rec_f2p);
88525   sc->rec_f2p = car(sc->rec_f2p);
88526 }
88527 
88528 static void rec_set_f3(s7_scheme *sc, s7_pointer p)
88529 {
88530   sc->rec_f3p = p;
88531   sc->rec_f3f = fx_proc(sc->rec_f3p);
88532   sc->rec_f3p = car(sc->rec_f3p);
88533 }
88534 
88535 static void rec_set_f4(s7_scheme *sc, s7_pointer p)
88536 {
88537   sc->rec_f4p = p;
88538   sc->rec_f4f = fx_proc(sc->rec_f4p);
88539   sc->rec_f4p = car(sc->rec_f4p);
88540 }
88541 
88542 static void rec_set_f5(s7_scheme *sc, s7_pointer p)
88543 {
88544   sc->rec_f5p = p;
88545   sc->rec_f5f = fx_proc(sc->rec_f5p);
88546   sc->rec_f5p = car(sc->rec_f5p);
88547 }
88548 
88549 static void rec_set_f6(s7_scheme *sc, s7_pointer p)
88550 {
88551   sc->rec_f6p = p;
88552   sc->rec_f6f = fx_proc(sc->rec_f6p);
88553   sc->rec_f6p = car(sc->rec_f6p);
88554 }
88555 
88556 /* -------- if_a_a_opa_laq and if_a_opa_laq_a -------- */
88557 typedef enum {OPT_PTR, OPT_INT, OPT_DBL, OPT_INT_0} opt_pid_t;
88558 
88559 static opt_pid_t opinit_if_a_a_opa_laq(s7_scheme *sc, bool a_op, bool la_op, s7_pointer code)
88560 {
88561   s7_pointer caller;
88562 #if (!WITH_GMP)
88563   s7_pointer c_op;
88564   caller = opt3_pair(code);
88565   c_op = car(caller);
88566   if ((is_symbol(c_op)) &&
88567       ((is_global(c_op)) ||
88568        ((is_slot(global_slot(c_op))) &&
88569 	(lookup_slot_from(c_op, sc->curlet) == global_slot(c_op)))))
88570     {
88571       s7_pointer s_func, slot;
88572       s_func = global_value(c_op);
88573       slot = let_slots(sc->curlet);
88574       if (is_c_function(s_func))
88575 	{
88576 	  sc->pc = 0;
88577 	  sc->rec_test_o = sc->opts[0];
88578 	  if (bool_optimize(sc, cdr(code)))
88579 	    {
88580 	      int32_t start_pc;
88581 	      start_pc = sc->pc;
88582 	      sc->rec_result_o = sc->opts[start_pc];
88583 	      if (is_t_integer(slot_value(slot)))
88584 		{
88585 		  sc->rec_i_ii_f = s7_i_ii_function(s_func);
88586 		  if ((sc->rec_i_ii_f) &&
88587 		      (int_optimize(sc, (a_op) ? cddr(code) : cdddr(code))))
88588 		    {
88589 		      sc->rec_a1_o = sc->opts[sc->pc];
88590 		      if (int_optimize(sc, (la_op) ? cdr(caller) : cddr(caller))) /* cdadr? */
88591 			{
88592 			  sc->rec_a2_o = sc->opts[sc->pc];
88593 			  if (int_optimize(sc, cdr(opt3_pair(caller))))
88594 			    {
88595 			      sc->rec_val1 = make_mutable_integer(sc, integer(slot_value(slot)));
88596 			      slot_set_value(slot, sc->rec_val1);
88597 			      return(OPT_INT);
88598 			    }}}}}}}
88599 #endif
88600   rec_set_test(sc, cdr(code));
88601   rec_set_res(sc, (a_op) ?  cddr(code) : cdddr(code));
88602   caller = opt3_pair(code); /* false_p in check_recur */
88603   rec_set_f1(sc, (la_op) ? cdr(caller) : cddr(caller));
88604   rec_set_f2(sc, cdr(opt3_pair(caller)));
88605   sc->rec_slot1 = let_slots(sc->curlet);
88606   sc->rec_fn = fn_proc(caller);
88607   return(OPT_PTR);
88608 }
88609 
88610 static s7_int oprec_i_if_a_a_opa_laq(s7_scheme *sc)
88611 {
88612   s7_int i1;
88613   if (sc->rec_test_o->v[0].fb(sc->rec_test_o)) return(sc->rec_result_o->v[0].fi(sc->rec_result_o));
88614   i1 = sc->rec_a1_o->v[0].fi(sc->rec_a1_o);
88615   integer(sc->rec_val1) = sc->rec_a2_o->v[0].fi(sc->rec_a2_o);
88616   return(sc->rec_i_ii_f(i1, oprec_i_if_a_a_opa_laq(sc)));
88617 }
88618 
88619 static s7_int oprec_i_if_a_opa_laq_a(s7_scheme *sc)
88620 {
88621   s7_int i1;
88622   if (!sc->rec_test_o->v[0].fb(sc->rec_test_o)) return(sc->rec_result_o->v[0].fi(sc->rec_result_o));
88623   i1 = sc->rec_a1_o->v[0].fi(sc->rec_a1_o);
88624   integer(sc->rec_val1) = sc->rec_a2_o->v[0].fi(sc->rec_a2_o);
88625   return(sc->rec_i_ii_f(i1, oprec_i_if_a_opa_laq_a(sc)));
88626 }
88627 
88628 static s7_pointer oprec_if_a_a_opa_laq(s7_scheme *sc)
88629 {
88630   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
88631   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88632   slot_set_value(sc->rec_slot1, sc->rec_f2f(sc, sc->rec_f2p));
88633 
88634   if (sc->rec_testf(sc, sc->rec_testp) != sc->F)
88635     set_car(sc->t2_2, sc->rec_resf(sc, sc->rec_resp));
88636   else
88637     {
88638       recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88639       slot_set_value(sc->rec_slot1, sc->rec_f2f(sc, sc->rec_f2p));
88640       set_car(sc->t2_2, oprec_if_a_a_opa_laq(sc));
88641       set_car(sc->t2_1, recur_pop(sc));
88642       set_car(sc->t2_2, sc->rec_fn(sc, sc->t2_1));
88643     }
88644   set_car(sc->t2_1, recur_pop(sc));
88645   return(sc->rec_fn(sc, sc->t2_1));
88646 }
88647 
88648 static s7_pointer oprec_if_a_a_opla_aq(s7_scheme *sc)
88649 {
88650   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
88651   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88652   slot_set_value(sc->rec_slot1, sc->rec_f2f(sc, sc->rec_f2p));
88653   set_car(sc->t2_1, oprec_if_a_a_opla_aq(sc));
88654   set_car(sc->t2_2, recur_pop(sc));
88655   return(sc->rec_fn(sc, sc->t2_1));
88656 }
88657 
88658 static s7_pointer oprec_if_a_opa_laq_a(s7_scheme *sc)
88659 {
88660   if (sc->rec_testf(sc, sc->rec_testp) == sc->F) return(sc->rec_resf(sc, sc->rec_resp));
88661   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88662   slot_set_value(sc->rec_slot1, sc->rec_f2f(sc, sc->rec_f2p));
88663 
88664   if (sc->rec_testf(sc, sc->rec_testp) == sc->F)
88665     set_car(sc->t2_2, sc->rec_resf(sc, sc->rec_resp));
88666   else
88667     {
88668       recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88669       slot_set_value(sc->rec_slot1, sc->rec_f2f(sc, sc->rec_f2p));
88670       set_car(sc->t2_2, oprec_if_a_opa_laq_a(sc));
88671       set_car(sc->t2_1, recur_pop(sc));
88672       set_car(sc->t2_2, sc->rec_fn(sc, sc->t2_1));
88673     }
88674   set_car(sc->t2_1, recur_pop(sc));
88675   return(sc->rec_fn(sc, sc->t2_1));
88676 }
88677 
88678 static s7_pointer oprec_if_a_opla_aq_a(s7_scheme *sc)
88679 {
88680   if (sc->rec_testf(sc, sc->rec_testp) == sc->F) return(sc->rec_resf(sc, sc->rec_resp));
88681   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88682   slot_set_value(sc->rec_slot1, sc->rec_f2f(sc, sc->rec_f2p));
88683   set_car(sc->t2_1, oprec_if_a_opla_aq_a(sc));
88684   set_car(sc->t2_2, recur_pop(sc));
88685   return(sc->rec_fn(sc, sc->t2_1));
88686 }
88687 
88688 static void wrap_recur_if_a_a_opa_laq(s7_scheme *sc, bool a_op, bool la_op)
88689 {
88690   opt_pid_t choice;
88691   tick_tc(sc, sc->cur_op);
88692   choice = opinit_if_a_a_opa_laq(sc, a_op, la_op, sc->code);
88693   if (choice == OPT_INT)
88694     sc->value = make_integer(sc, (a_op) ? oprec_i_if_a_a_opa_laq(sc) : oprec_i_if_a_opa_laq_a(sc));
88695   else
88696     {
88697       sc->rec_stack = recur_make_stack(sc);
88698       if (a_op)
88699 	sc->value = (la_op) ? oprec_if_a_a_opa_laq(sc) : oprec_if_a_a_opla_aq(sc);
88700       else sc->value = (la_op) ? oprec_if_a_opa_laq_a(sc) : oprec_if_a_opla_aq_a(sc);
88701       sc->rec_loc = 0;
88702     }
88703 }
88704 
88705 static s7_pointer fx_recur_if_a_a_opa_laq(s7_scheme *sc, s7_pointer arg)
88706 {
88707   tick_tc(sc, OP_RECUR_IF_A_A_opA_LAq);
88708   if (opinit_if_a_a_opa_laq(sc, true, true, arg) == OPT_INT)
88709     sc->value = make_integer(sc, oprec_i_if_a_a_opa_laq(sc));
88710   else
88711     {
88712       sc->rec_stack = recur_make_stack(sc);
88713       sc->value = oprec_if_a_a_opa_laq(sc);
88714       sc->rec_loc = 0;
88715     }
88716   return(sc->value);
88717 }
88718 
88719 static s7_pointer fx_recur_if_a_opa_laq_a(s7_scheme *sc, s7_pointer arg)
88720 {
88721   tick_tc(sc, OP_RECUR_IF_A_opA_LAq_A);
88722   if (opinit_if_a_a_opa_laq(sc, false, true, arg) == OPT_INT)
88723     sc->value = make_integer(sc, oprec_i_if_a_opa_laq_a(sc));
88724   else
88725     {
88726       sc->rec_stack = recur_make_stack(sc);
88727       sc->value = oprec_if_a_opa_laq_a(sc);
88728       sc->rec_loc = 0;
88729     }
88730   return(sc->value);
88731 }
88732 
88733 /* -------- cond_a_a_opa_laq -------- */
88734 static void opinit_cond_a_a_opa_laq(s7_scheme *sc)
88735 {
88736   s7_pointer caller;
88737   rec_set_test(sc, cadr(sc->code));
88738   rec_set_res(sc, cdadr(sc->code));
88739   caller = opt3_pair(sc->code);
88740   rec_set_f1(sc, cdr(caller));
88741   rec_set_f2(sc, cdr(opt3_pair(caller)));
88742   sc->rec_slot1 = let_slots(sc->curlet);
88743   sc->rec_fn = fn_proc(caller);
88744 }
88745 
88746 static s7_pointer op_recur_cond_a_a_opa_laq(s7_scheme *sc)
88747 {
88748   opinit_cond_a_a_opa_laq(sc);
88749   return(oprec_if_a_a_opa_laq(sc));
88750 }
88751 
88752 /* -------- if_a_a_opa_laaq and if_a_opa_laaq_a and cond_a_a_opa_laaq -------- */
88753 enum {IF1A_LA2, IF2A_LA2, COND2A_LA2};
88754 
88755 static void opinit_if_a_a_opa_laaq(s7_scheme *sc, int32_t a_op)
88756 {
88757   s7_pointer caller;
88758   rec_set_test(sc, (a_op == COND2A_LA2) ? cadr(sc->code) : cdr(sc->code));
88759   rec_set_res(sc, (a_op == IF2A_LA2) ?  cddr(sc->code) : ((a_op == IF1A_LA2) ? cdddr(sc->code) : cdadr(sc->code)));
88760   caller = opt3_pair(sc->code);
88761   rec_set_f1(sc, cdr(caller));
88762   rec_set_f2(sc, cdr(opt3_pair(caller)));
88763   rec_set_f3(sc, cddr(opt3_pair(caller)));
88764   sc->rec_slot1 = let_slots(sc->curlet);
88765   sc->rec_slot2 = next_slot(sc->rec_slot1);
88766   sc->rec_fn = fn_proc(caller);
88767 }
88768 
88769 static s7_pointer oprec_if_a_a_opa_laaq(s7_scheme *sc)
88770 {
88771   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
88772   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88773   recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
88774   slot_set_value(sc->rec_slot2, sc->rec_f3f(sc, sc->rec_f3p));
88775   slot_set_value(sc->rec_slot1, recur_pop(sc));
88776   if (sc->rec_testf(sc, sc->rec_testp) != sc->F)
88777     set_car(sc->t2_2, sc->rec_resf(sc, sc->rec_resp));
88778   else
88779     {
88780       recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88781       recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
88782       slot_set_value(sc->rec_slot2, sc->rec_f3f(sc, sc->rec_f3p));
88783       slot_set_value(sc->rec_slot1, recur_pop(sc));
88784       set_car(sc->t2_2, oprec_if_a_a_opa_laaq(sc));
88785       set_car(sc->t2_1, recur_pop(sc));
88786       set_car(sc->t2_2, sc->rec_fn(sc, sc->t2_1));
88787     }
88788   set_car(sc->t2_1, recur_pop(sc));
88789   return(sc->rec_fn(sc, sc->t2_1));
88790 }
88791 
88792 static s7_pointer oprec_if_a_opa_laaq_a(s7_scheme *sc)
88793 {
88794   if (sc->rec_testf(sc, sc->rec_testp) == sc->F) return(sc->rec_resf(sc, sc->rec_resp));
88795   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88796   recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
88797   slot_set_value(sc->rec_slot2, sc->rec_f3f(sc, sc->rec_f3p));
88798   slot_set_value(sc->rec_slot1, recur_pop(sc));
88799   set_car(sc->t2_2, oprec_if_a_opa_laaq_a(sc));
88800   set_car(sc->t2_1, recur_pop(sc));
88801   return(sc->rec_fn(sc, sc->t2_1));
88802 }
88803 
88804 static s7_pointer op_recur_if_a_a_opa_laaq(s7_scheme *sc)
88805 {
88806   opinit_if_a_a_opa_laaq(sc, IF2A_LA2);
88807   return(oprec_if_a_a_opa_laaq(sc));
88808 }
88809 
88810 static s7_pointer op_recur_if_a_opa_laaq_a(s7_scheme *sc)
88811 {
88812   opinit_if_a_a_opa_laaq(sc, IF1A_LA2);
88813   return(oprec_if_a_opa_laaq_a(sc));
88814 }
88815 
88816 static s7_pointer op_recur_cond_a_a_opa_laaq(s7_scheme *sc)
88817 {
88818   opinit_if_a_a_opa_laaq(sc, COND2A_LA2);
88819   return(oprec_if_a_a_opa_laaq(sc));
88820 }
88821 
88822 
88823 /* -------- if_a_a_opa_l3aq -------- */
88824 static void opinit_if_a_a_opa_l3aq(s7_scheme *sc)
88825 {
88826   s7_pointer caller, l3a;
88827   rec_set_test(sc, cdr(sc->code));
88828   rec_set_res(sc, cddr(sc->code));
88829   caller = opt3_pair(sc->code);
88830   rec_set_f1(sc, cdr(caller));
88831   l3a = cdr(opt3_pair(caller));
88832   rec_set_f2(sc, l3a);
88833   rec_set_f3(sc, cdr(l3a));
88834   rec_set_f4(sc, cddr(l3a));
88835   sc->rec_slot1 = let_slots(sc->curlet);
88836   sc->rec_slot2 = next_slot(sc->rec_slot1);
88837   sc->rec_slot3 = next_slot(sc->rec_slot2);
88838   sc->rec_fn = fn_proc(caller);
88839 }
88840 
88841 static s7_pointer oprec_if_a_a_opa_l3aq(s7_scheme *sc)
88842 {
88843   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
88844   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88845   recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
88846   recur_push(sc, sc->rec_f3f(sc, sc->rec_f3p));
88847   slot_set_value(sc->rec_slot3, sc->rec_f4f(sc, sc->rec_f4p));
88848   slot_set_value(sc->rec_slot2, recur_pop(sc));
88849   slot_set_value(sc->rec_slot1, recur_pop(sc));
88850   if (sc->rec_testf(sc, sc->rec_testp) != sc->F)
88851     set_car(sc->t2_2, sc->rec_resf(sc, sc->rec_resp));
88852   else
88853     {
88854       recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
88855       recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
88856       recur_push(sc, sc->rec_f3f(sc, sc->rec_f3p));
88857       slot_set_value(sc->rec_slot3, sc->rec_f4f(sc, sc->rec_f4p));
88858       slot_set_value(sc->rec_slot2, recur_pop(sc));
88859       slot_set_value(sc->rec_slot1, recur_pop(sc));
88860       set_car(sc->t2_2, oprec_if_a_a_opa_l3aq(sc));
88861       set_car(sc->t2_1, recur_pop(sc));
88862       set_car(sc->t2_2, sc->rec_fn(sc, sc->t2_1));
88863     }
88864   set_car(sc->t2_1, recur_pop(sc));
88865   return(sc->rec_fn(sc, sc->t2_1));
88866 }
88867 
88868 static s7_pointer op_recur_if_a_a_opa_l3aq(s7_scheme *sc)
88869 {
88870   opinit_if_a_a_opa_l3aq(sc);
88871   return(oprec_if_a_a_opa_l3aq(sc));
88872 }
88873 
88874 /* -------- if_a_a_opla_laq and if_a_opla_laq_a -------- */
88875 static opt_pid_t opinit_if_a_a_opla_laq(s7_scheme *sc, bool a_op)
88876 {
88877 #if WITH_GMP
88878   s7_pointer caller;
88879   caller = opt3_pair(sc->code);
88880 #else
88881   s7_pointer caller, c_op;
88882   caller = opt3_pair(sc->code);
88883 
88884   c_op = car(caller);
88885   if ((is_symbol(c_op)) &&
88886       ((is_global(c_op)) ||
88887        ((is_slot(global_slot(c_op))) &&
88888 	(lookup_slot_from(c_op, sc->curlet) == global_slot(c_op)))))
88889     {
88890       s7_pointer s_func, slot;
88891       s_func = global_value(c_op);
88892       slot = let_slots(sc->curlet);
88893       if (is_c_function(s_func))
88894 	{
88895 	  sc->pc = 0;
88896 	  sc->rec_test_o = sc->opts[0];
88897 	  if (bool_optimize(sc, cdr(sc->code)))
88898 	    {
88899 	      int32_t start_pc;
88900 	      start_pc = sc->pc;
88901 	      sc->rec_result_o = sc->opts[start_pc];
88902 	      if (is_t_integer(slot_value(slot)))
88903 		{
88904 		  sc->rec_i_ii_f = s7_i_ii_function(s_func);
88905 		  if ((sc->rec_i_ii_f) &&
88906 		      (int_optimize(sc, (a_op) ? cddr(sc->code) : cdddr(sc->code))))
88907 		    {
88908 		      sc->rec_a1_o = sc->opts[sc->pc];
88909 		      if (int_optimize(sc, cdadr(caller)))
88910 			{
88911 			  sc->rec_a2_o = sc->opts[sc->pc];
88912 			  if (int_optimize(sc, cdr(opt3_pair(caller))))
88913 			    {
88914 			      sc->rec_val1 = make_mutable_integer(sc, integer(slot_value(slot)));
88915 			      slot_set_value(slot, sc->rec_val1);
88916 			      if (sc->pc == 4)
88917 				{
88918 				  sc->rec_fb1 = sc->rec_test_o->v[0].fb;
88919 				  sc->rec_fi1 = sc->rec_result_o->v[0].fi;
88920 				  sc->rec_fi2 = sc->rec_a1_o->v[0].fi;
88921 				  sc->rec_fi3 = sc->rec_a2_o->v[0].fi;
88922 				  return(OPT_INT_0);
88923 				}
88924 			      return(OPT_INT);
88925 			    }}}}
88926 	      if (is_t_real(slot_value(slot)))
88927 		{
88928 		  sc->rec_d_dd_f = s7_d_dd_function(s_func);
88929 		  if (sc->rec_d_dd_f)
88930 		    {
88931 		      sc->pc = start_pc;
88932 		      sc->rec_result_o = sc->opts[start_pc];
88933 		      if (float_optimize(sc, (a_op) ? cddr(sc->code) : cdddr(sc->code)))
88934 			{
88935 			  sc->rec_a1_o = sc->opts[sc->pc];
88936 			  if (float_optimize(sc, cdadr(caller)))
88937 			    {
88938 			      sc->rec_a2_o = sc->opts[sc->pc];
88939 			      if (float_optimize(sc, cdr(opt3_pair(caller))))
88940 				{
88941 				  sc->rec_val1 = s7_make_mutable_real(sc, real(slot_value(slot)));
88942 				  slot_set_value(slot, sc->rec_val1);
88943 				  return(OPT_DBL);
88944 				}}}}}}}}
88945 #endif
88946   rec_set_test(sc, cdr(sc->code));
88947   rec_set_res(sc, (a_op) ?  cddr(sc->code) : cdddr(sc->code));
88948   rec_set_f1(sc, cdadr(caller));
88949   rec_set_f2(sc, cdr(opt3_pair(caller)));
88950   sc->rec_slot1 = let_slots(sc->curlet);
88951   sc->rec_fn = fn_proc(caller);
88952   return(OPT_PTR);
88953 }
88954 
88955 static s7_int oprec_i_if_a_a_opla_laq(s7_scheme *sc)
88956 {
88957   s7_int i1, i2;
88958   if (sc->rec_test_o->v[0].fb(sc->rec_test_o))                   /* if_(A) */
88959     return(sc->rec_result_o->v[0].fi(sc->rec_result_o));         /* if_a_(A) */
88960   i1 = sc->rec_a1_o->v[0].fi(sc->rec_a1_o);                      /* save a1 */
88961   integer(sc->rec_val1) = sc->rec_a2_o->v[0].fi(sc->rec_a2_o);   /* slot1 = a2 */
88962   i2 = oprec_i_if_a_a_opla_laq(sc);                              /* save la2 */
88963   integer(sc->rec_val1) = i1;                                    /* slot1 = a1 */
88964   return(sc->rec_i_ii_f(oprec_i_if_a_a_opla_laq(sc), i2));       /* call op(la1, la2) */
88965 }
88966 
88967 static s7_int oprec_i_if_a_a_opla_laq_0(s7_scheme *sc)
88968 {
88969   s7_int i1, i2;
88970   if (sc->rec_fb1(sc->rec_test_o)) return(sc->rec_fi1(sc->rec_result_o));
88971   i1 = sc->rec_fi2(sc->rec_a1_o);
88972   integer(sc->rec_val1) = sc->rec_fi3(sc->rec_a2_o);
88973   if (sc->rec_fb1(sc->rec_test_o))
88974     i2 = sc->rec_fi1(sc->rec_result_o);
88975   else
88976     {
88977       s7_int i3;
88978       i2 = sc->rec_fi2(sc->rec_a1_o);
88979       integer(sc->rec_val1) = sc->rec_fi3(sc->rec_a2_o);
88980       i3 = oprec_i_if_a_a_opla_laq_0(sc);
88981       integer(sc->rec_val1) = i2;
88982       i2 = sc->rec_i_ii_f(oprec_i_if_a_a_opla_laq_0(sc), i3);
88983     }
88984   integer(sc->rec_val1) = i1;
88985   return(sc->rec_i_ii_f(oprec_i_if_a_a_opla_laq_0(sc), i2));
88986 }
88987 
88988 static s7_double oprec_d_if_a_a_opla_laq(s7_scheme *sc)
88989 {
88990   s7_double x1, x2;
88991   if (sc->rec_test_o->v[0].fb(sc->rec_test_o)) return(sc->rec_result_o->v[0].fd(sc->rec_result_o));
88992   x1 = sc->rec_a1_o->v[0].fd(sc->rec_a1_o);
88993   real(sc->rec_val1) = sc->rec_a2_o->v[0].fd(sc->rec_a2_o);
88994   if (sc->rec_test_o->v[0].fb(sc->rec_test_o))
88995     x2 = sc->rec_result_o->v[0].fd(sc->rec_result_o);
88996   else
88997     {
88998       s7_double x3;
88999       x2 = sc->rec_a1_o->v[0].fd(sc->rec_a1_o);
89000       real(sc->rec_val1) = sc->rec_a2_o->v[0].fd(sc->rec_a2_o);
89001       x3 = oprec_d_if_a_a_opla_laq(sc);
89002       real(sc->rec_val1) = x2;
89003       x2 = sc->rec_d_dd_f(oprec_d_if_a_a_opla_laq(sc), x3);
89004     }
89005   real(sc->rec_val1) = x1;
89006   return(sc->rec_d_dd_f(oprec_d_if_a_a_opla_laq(sc), x2));
89007 }
89008 
89009 static s7_pointer oprec_if_a_a_opla_laq(s7_scheme *sc)
89010 {
89011   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89012   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
89013   slot_set_value(sc->rec_slot1, sc->rec_f2f(sc, sc->rec_f2p));
89014   slot_set_value(sc->rec_slot1, recur_swap(sc, oprec_if_a_a_opla_laq(sc)));
89015   set_car(sc->t2_1, oprec_if_a_a_opla_laq(sc));
89016   set_car(sc->t2_2, recur_pop(sc));
89017   return(sc->rec_fn(sc, sc->t2_1));
89018 }
89019 
89020 static s7_int oprec_i_if_a_opla_laq_a(s7_scheme *sc)
89021 {
89022   s7_int i1, i2;
89023   if (!(sc->rec_test_o->v[0].fb(sc->rec_test_o))) return(sc->rec_result_o->v[0].fi(sc->rec_result_o));
89024   i1 = sc->rec_a1_o->v[0].fi(sc->rec_a1_o);
89025   integer(sc->rec_val1) = sc->rec_a2_o->v[0].fi(sc->rec_a2_o);
89026   i2 = oprec_i_if_a_opla_laq_a(sc);
89027   integer(sc->rec_val1) = i1;
89028   return(sc->rec_i_ii_f(oprec_i_if_a_opla_laq_a(sc), i2));
89029 }
89030 
89031 static s7_int oprec_i_if_a_opla_laq_a_0(s7_scheme *sc)
89032 {
89033   s7_int i1, i2;
89034   if (!sc->rec_fb1(sc->rec_test_o)) return(sc->rec_fi1(sc->rec_result_o));
89035   i1 = sc->rec_fi2(sc->rec_a1_o);
89036   integer(sc->rec_val1) = sc->rec_fi3(sc->rec_a2_o);
89037   if (!sc->rec_fb1(sc->rec_test_o))
89038     i2 = sc->rec_fi1(sc->rec_result_o);
89039   else
89040     {
89041       s7_int i3;
89042       i2 = sc->rec_fi2(sc->rec_a1_o);
89043       integer(sc->rec_val1) = sc->rec_fi3(sc->rec_a2_o);
89044       i3 = oprec_i_if_a_opla_laq_a_0(sc);
89045       integer(sc->rec_val1) = i2;
89046       i2 = sc->rec_i_ii_f(oprec_i_if_a_opla_laq_a_0(sc), i3);
89047     }
89048   integer(sc->rec_val1) = i1;
89049   return(sc->rec_i_ii_f(oprec_i_if_a_opla_laq_a_0(sc), i2));
89050 }
89051 
89052 static s7_double oprec_d_if_a_opla_laq_a(s7_scheme *sc)
89053 {
89054   s7_double x1, x2;
89055   if (!(sc->rec_test_o->v[0].fb(sc->rec_test_o))) return(sc->rec_result_o->v[0].fd(sc->rec_result_o));
89056   x1 = sc->rec_a1_o->v[0].fd(sc->rec_a1_o);
89057   real(sc->rec_val1) = sc->rec_a2_o->v[0].fd(sc->rec_a2_o);
89058   x2 = oprec_d_if_a_opla_laq_a(sc);
89059   real(sc->rec_val1) = x1;
89060   return(sc->rec_d_dd_f(oprec_d_if_a_opla_laq_a(sc), x2));
89061 }
89062 
89063 static s7_pointer oprec_if_a_opla_laq_a(s7_scheme *sc)
89064 {
89065   if (sc->rec_testf(sc, sc->rec_testp) == sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89066   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
89067   slot_set_value(sc->rec_slot1, sc->rec_f2f(sc, sc->rec_f2p));
89068   slot_set_value(sc->rec_slot1, recur_swap(sc, oprec_if_a_opla_laq_a(sc)));
89069   set_car(sc->t2_1, oprec_if_a_opla_laq_a(sc));
89070   set_car(sc->t2_2, recur_pop(sc));
89071   return(sc->rec_fn(sc, sc->t2_1));
89072 }
89073 
89074 static void wrap_recur_if_a_a_opla_laq(s7_scheme *sc, bool a_op)
89075 {
89076   opt_pid_t choice;
89077   tick_tc(sc, sc->cur_op);
89078   choice = opinit_if_a_a_opla_laq(sc, a_op);
89079   if ((choice == OPT_INT) || (choice == OPT_INT_0))
89080     {
89081       if (choice == OPT_INT_0)
89082 	sc->value = make_integer(sc, (a_op) ? oprec_i_if_a_a_opla_laq_0(sc) : oprec_i_if_a_opla_laq_a_0(sc));
89083       else sc->value = make_integer(sc, (a_op) ? oprec_i_if_a_a_opla_laq(sc) : oprec_i_if_a_opla_laq_a(sc));
89084     }
89085   else
89086     {
89087       if (choice == OPT_PTR)
89088 	{
89089 	  sc->rec_stack = recur_make_stack(sc);
89090 	  sc->value = (a_op) ? oprec_if_a_a_opla_laq(sc) : oprec_if_a_opla_laq_a(sc);
89091 	  sc->rec_loc = 0;
89092 	}
89093       else sc->value = make_real(sc, (a_op) ? oprec_d_if_a_a_opla_laq(sc) : oprec_d_if_a_opla_laq_a(sc));
89094     }
89095 }
89096 
89097 
89098 /* -------- if_a_a_opa_la_laq and if_a_opa_la_laq_a -------- */
89099 static void opinit_if_a_a_opa_la_laq(s7_scheme *sc, bool a_op)
89100 {
89101   s7_pointer caller;
89102   rec_set_test(sc, cdr(sc->code));
89103   rec_set_res(sc, (a_op) ?  cddr(sc->code) : cdddr(sc->code));
89104   caller = opt3_pair(sc->code);
89105   rec_set_f1(sc, cdr(caller));
89106   rec_set_f2(sc, cdaddr(caller));
89107   rec_set_f3(sc, cdr(opt3_pair(caller)));
89108   sc->rec_slot1 = let_slots(sc->curlet);
89109   sc->rec_fn = fn_proc(caller);
89110 }
89111 
89112 static s7_pointer oprec_if_a_a_opa_la_laq(s7_scheme *sc)
89113 {
89114   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89115   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
89116   recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
89117   slot_set_value(sc->rec_slot1, sc->rec_f3f(sc, sc->rec_f3p));
89118   slot_set_value(sc->rec_slot1, recur_swap(sc, oprec_if_a_a_opa_la_laq(sc)));
89119   set_car(sc->t3_2, oprec_if_a_a_opa_la_laq(sc));
89120   set_car(sc->t3_3, recur_pop(sc));
89121   set_car(sc->t3_1, recur_pop(sc));
89122   return(sc->rec_fn(sc, sc->t3_1));
89123 }
89124 
89125 static s7_pointer oprec_if_a_opa_la_laq_a(s7_scheme *sc)
89126 {
89127   if (sc->rec_testf(sc, sc->rec_testp) == sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89128   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
89129   recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
89130   slot_set_value(sc->rec_slot1, sc->rec_f3f(sc, sc->rec_f3p));
89131   slot_set_value(sc->rec_slot1, recur_swap(sc, oprec_if_a_opa_la_laq_a(sc)));
89132   set_car(sc->t3_2, oprec_if_a_opa_la_laq_a(sc));
89133   set_car(sc->t3_3, recur_pop(sc));
89134   set_car(sc->t3_1, recur_pop(sc));
89135   return(sc->rec_fn(sc, sc->t3_1));
89136 }
89137 
89138 static s7_pointer op_recur_if_a_a_opa_la_laq(s7_scheme *sc)
89139 {
89140   opinit_if_a_a_opa_la_laq(sc, true);
89141   return(oprec_if_a_a_opa_la_laq(sc));
89142 }
89143 
89144 static s7_pointer op_recur_if_a_opa_la_laq_a(s7_scheme *sc)
89145 {
89146   opinit_if_a_a_opa_la_laq(sc, false);
89147   return(oprec_if_a_opa_la_laq_a(sc));
89148 }
89149 
89150 /* -------- if_a_a_opla_la_laq -------- */
89151 static void opinit_if_a_a_opla_la_laq(s7_scheme *sc, bool a_op)
89152 {
89153   s7_pointer caller;
89154   rec_set_test(sc, cdr(sc->code));
89155   rec_set_res(sc, (a_op) ?  cddr(sc->code) : cdddr(sc->code));
89156   caller = opt3_pair(sc->code);
89157   rec_set_f1(sc, cdadr(caller));
89158   rec_set_f2(sc, cdaddr(caller));
89159   rec_set_f3(sc, cdr(opt3_pair(caller)));
89160   sc->rec_slot1 = let_slots(sc->curlet);
89161   sc->rec_fn = fn_proc(caller);
89162 }
89163 
89164 static s7_pointer oprec_if_a_a_opla_la_laq(s7_scheme *sc)
89165 {
89166   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89167   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
89168   recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
89169   slot_set_value(sc->rec_slot1, sc->rec_f3f(sc, sc->rec_f3p));
89170   slot_set_value(sc->rec_slot1, recur_swap(sc, oprec_if_a_a_opla_la_laq(sc)));
89171   recur_push(sc, oprec_if_a_a_opla_la_laq(sc));
89172   slot_set_value(sc->rec_slot1, recur_ref(sc, 3));
89173   set_car(sc->t3_1, oprec_if_a_a_opla_la_laq(sc));
89174   set_car(sc->t3_2, recur_pop(sc));
89175   set_car(sc->t3_3, recur_pop2(sc));
89176   return(sc->rec_fn(sc, sc->t3_1));
89177 }
89178 
89179 static s7_pointer op_recur_if_a_a_opla_la_laq(s7_scheme *sc)
89180 {
89181   opinit_if_a_a_opla_la_laq(sc, true);
89182   return(oprec_if_a_a_opla_la_laq(sc));
89183 }
89184 
89185 /* -------- if_a_a_lopl3a_l3a_l3aq(s7_scheme *sc) --------
89186  * esteemed reader, please ignore this nonsense!
89187  *  The opt_info version was not a lot faster -- ~/old/tak-st.c: say 10% faster. The current fx-based
89188  *  version has immediate lookups, and since the data is (ahem) simple, the GC is not a factor.
89189  *  The opt version has its own overheads, and has to do the same amount of stack manipulations.
89190  */
89191 static s7_pointer rec_x(s7_scheme *sc, s7_pointer code) {return(slot_value(sc->rec_slot1));}
89192 static s7_pointer rec_y(s7_scheme *sc, s7_pointer code) {return(slot_value(sc->rec_slot2));}
89193 static s7_pointer rec_z(s7_scheme *sc, s7_pointer code) {return(slot_value(sc->rec_slot3));}
89194 static s7_pointer rec_sub_z1(s7_scheme *sc, s7_pointer code)
89195 {
89196   s7_pointer x;
89197   x = slot_value(sc->rec_slot3);
89198   return((is_t_integer(x)) ? make_integer(sc, integer(x) - 1) : minus_c1(sc, x));
89199 }
89200 
89201 static void opinit_if_a_a_lopl3a_l3a_l3aq(s7_scheme *sc)
89202 {
89203   s7_pointer caller, la1, la2, la3;
89204 
89205   rec_set_test(sc, cdr(sc->code));
89206   rec_set_res(sc, cddr(sc->code));
89207   caller = opt3_pair(sc->code);
89208   la1 = cadr(caller);
89209   la2 = caddr(caller);
89210   la3 = opt3_pair(caller);
89211 
89212   rec_set_f1(sc, cdr(la1));
89213   rec_set_f2(sc, cddr(la1));
89214   if (sc->rec_f2f == fx_u) sc->rec_f2f = rec_y;
89215   rec_set_f3(sc, cdddr(la1));
89216   rec_set_f4(sc, cdr(la2));
89217   rec_set_f5(sc, cddr(la2));
89218   rec_set_f6(sc, cdddr(la2));
89219   if (sc->rec_f6f == fx_t) sc->rec_f6f = rec_x;
89220 
89221   sc->rec_f7p = cdr(la3);
89222   sc->rec_f7f = fx_proc(sc->rec_f7p);
89223   sc->rec_f7p = car(sc->rec_f7p);
89224 
89225   sc->rec_f8p = cddr(la3);
89226   sc->rec_f8f = fx_proc(sc->rec_f8p);
89227   if (sc->rec_f8f == fx_t) sc->rec_f8f = rec_x;
89228   sc->rec_f8p = car(sc->rec_f8p);
89229 
89230   sc->rec_f9p = cdddr(la3);
89231   sc->rec_f9f = fx_proc(sc->rec_f9p);
89232   if (sc->rec_f9f == fx_u) sc->rec_f9f = rec_y;
89233   sc->rec_f9p = car(sc->rec_f9p);
89234 
89235   sc->rec_slot1 = let_slots(sc->curlet);
89236   sc->rec_slot2 = next_slot(sc->rec_slot1);
89237   sc->rec_slot3 = next_slot(sc->rec_slot2);
89238   if (cadddr(la1) == slot_symbol(sc->rec_slot3)) sc->rec_f3f = rec_z;
89239   if (caddr(la2) == slot_symbol(sc->rec_slot3)) sc->rec_f5f = rec_z;
89240   if ((sc->rec_f7f == fx_subtract_s1) && (cadadr(la3) == slot_symbol(sc->rec_slot3))) sc->rec_f7f = rec_sub_z1;
89241 }
89242 
89243 static s7_pointer oprec_if_a_a_lopl3a_l3a_l3aq(s7_scheme *sc)
89244 {
89245   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89246 
89247   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
89248   recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
89249   recur_push(sc, sc->rec_f3f(sc, sc->rec_f3p));
89250   recur_push(sc, sc->rec_f4f(sc, sc->rec_f4p));
89251   recur_push(sc, sc->rec_f5f(sc, sc->rec_f5p));
89252   recur_push(sc, sc->rec_f6f(sc, sc->rec_f6p));
89253   recur_push(sc, sc->rec_f7f(sc, sc->rec_f7p));
89254   recur_push(sc, sc->rec_f8f(sc, sc->rec_f8p));
89255   slot_set_value(sc->rec_slot3, sc->rec_f9f(sc, sc->rec_f9p));
89256   slot_set_value(sc->rec_slot2, recur_pop(sc));
89257   slot_set_value(sc->rec_slot1, recur_pop(sc));
89258   recur_push(sc, oprec_if_a_a_lopl3a_l3a_l3aq(sc));
89259   slot_set_value(sc->rec_slot3, recur_ref(sc, 2));
89260   slot_set_value(sc->rec_slot2, recur_ref(sc, 3));
89261   slot_set_value(sc->rec_slot1, recur_ref(sc, 4));
89262   recur_push(sc, oprec_if_a_a_lopl3a_l3a_l3aq(sc));
89263   slot_set_value(sc->rec_slot3, recur_ref(sc, 6));
89264   slot_set_value(sc->rec_slot2, recur_ref(sc, 7));
89265   slot_set_value(sc->rec_slot1, recur_ref(sc, 8));
89266   slot_set_value(sc->rec_slot1, oprec_if_a_a_lopl3a_l3a_l3aq(sc));
89267   slot_set_value(sc->rec_slot2, recur_pop(sc));
89268   slot_set_value(sc->rec_slot3, recur_pop(sc));
89269   sc->rec_loc -= 6;
89270   return(oprec_if_a_a_lopl3a_l3a_l3aq(sc));
89271 }
89272 
89273 static s7_pointer op_recur_if_a_a_lopl3a_l3a_l3aq(s7_scheme *sc)
89274 {
89275   opinit_if_a_a_lopl3a_l3a_l3aq(sc);
89276   return(oprec_if_a_a_lopl3a_l3a_l3aq(sc));
89277 }
89278 
89279 /* -------- if_a_a_and_a_laa_laa -------- */
89280 
89281 static void opinit_if_a_a_and_a_laa_laa(s7_scheme *sc, s7_pointer code)
89282 {
89283   s7_pointer caller, la1, la2;
89284 
89285   rec_set_test(sc, cdr(code));
89286   rec_set_res(sc, cddr(code));
89287 
89288   caller = opt3_pair(code);
89289   la1 = caddr(caller);
89290   la2 = cadddr(caller);
89291 
89292   rec_set_f1(sc, cdr(caller));
89293   rec_set_f2(sc, cdr(la1));
89294   rec_set_f3(sc, cddr(la1));
89295   rec_set_f4(sc, cdr(la2));
89296   rec_set_f5(sc, cddr(la2));
89297   sc->rec_slot1 = let_slots(sc->curlet);
89298   sc->rec_slot2 = next_slot(sc->rec_slot1);
89299 }
89300 
89301 static s7_pointer oprec_if_a_a_and_a_laa_laa(s7_scheme *sc)
89302 {
89303   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89304   if (sc->rec_f1f(sc, sc->rec_f1p) == sc->F) return(sc->F);
89305   recur_push(sc, slot_value(sc->rec_slot1));
89306   recur_push(sc, slot_value(sc->rec_slot2));
89307   recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
89308   slot_set_value(sc->rec_slot2, sc->rec_f3f(sc, sc->rec_f3p));
89309   slot_set_value(sc->rec_slot1, recur_pop(sc));
89310   if (oprec_if_a_a_and_a_laa_laa(sc) == sc->F)
89311     {
89312       sc->rec_loc -= 2;
89313       return(sc->F);
89314     }
89315   slot_set_value(sc->rec_slot2, recur_pop(sc));
89316   slot_set_value(sc->rec_slot1, recur_pop(sc));
89317   recur_push(sc, sc->rec_f4f(sc, sc->rec_f4p));
89318   slot_set_value(sc->rec_slot2, sc->rec_f5f(sc, sc->rec_f5p));
89319   slot_set_value(sc->rec_slot1, recur_pop(sc));
89320   return(oprec_if_a_a_and_a_laa_laa(sc));
89321 }
89322 
89323 static s7_pointer op_recur_if_a_a_and_a_laa_laa(s7_scheme *sc)
89324 {
89325   opinit_if_a_a_and_a_laa_laa(sc, sc->code);
89326   return(oprec_if_a_a_and_a_laa_laa(sc));
89327 }
89328 
89329 static s7_pointer fx_recur_if_a_a_and_a_laa_laa(s7_scheme *sc, s7_pointer arg)
89330 {
89331   tick_tc(sc, OP_RECUR_IF_A_A_AND_A_LAA_LAA);
89332   /* sc->curlet is set already and will be restored by the caller */
89333   sc->rec_stack = recur_make_stack(sc);
89334   opinit_if_a_a_and_a_laa_laa(sc, arg);
89335   sc->value = oprec_if_a_a_and_a_laa_laa(sc);
89336   sc->rec_loc = 0;
89337   return(sc->value);
89338 }
89339 
89340 /* -------- cond_a_a_a_a_opla_laq -------- */
89341 static void opinit_cond_a_a_a_a_opla_laq(s7_scheme *sc, s7_pointer code, bool cond_case)
89342 {
89343   s7_pointer caller;
89344   if (cond_case)
89345     {
89346       rec_set_test(sc, cadr(code));
89347       rec_set_res(sc, cdadr(code));
89348       rec_set_f1(sc, caddr(code));
89349       rec_set_f2(sc, cdaddr(code));
89350     }
89351   else
89352     {
89353       rec_set_test(sc, cdr(code));
89354       rec_set_res(sc, cddr(code));       /* (if a b...) */
89355       rec_set_f1(sc, opt1_pair(code));   /* cdr(cadddr(code)), (if a b (if c d...)) */
89356       rec_set_f2(sc, cdr(opt1_pair(code)));
89357     }
89358   caller = opt3_pair(code);
89359   rec_set_f3(sc, cdadr(caller));
89360   rec_set_f4(sc, opt3_pair(caller));
89361   sc->rec_slot1 = let_slots(sc->curlet);
89362   sc->rec_fn = fn_proc(caller);
89363 }
89364 
89365 static s7_pointer oprec_cond_a_a_a_a_opla_laq(s7_scheme *sc)
89366 {
89367   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89368   if (sc->rec_f1f(sc, sc->rec_f1p) != sc->F) return(sc->rec_f2f(sc, sc->rec_f2p));
89369   recur_push(sc, sc->rec_f3f(sc, sc->rec_f3p));
89370   slot_set_value(sc->rec_slot1, sc->rec_f4f(sc, sc->rec_f4p));
89371   slot_set_value(sc->rec_slot1, recur_swap(sc, oprec_cond_a_a_a_a_opla_laq(sc)));
89372   set_car(sc->t2_1, oprec_cond_a_a_a_a_opla_laq(sc));
89373   set_car(sc->t2_2, recur_pop(sc));
89374   return(sc->rec_fn(sc, sc->t2_1));
89375 }
89376 
89377 static s7_pointer op_recur_cond_a_a_a_a_opla_laq(s7_scheme *sc)
89378 {
89379   opinit_cond_a_a_a_a_opla_laq(sc, sc->code, true);
89380   return(oprec_cond_a_a_a_a_opla_laq(sc));
89381 }
89382 
89383 static s7_pointer op_recur_if_a_a_if_a_a_opla_laq(s7_scheme *sc)
89384 {
89385   opinit_cond_a_a_a_a_opla_laq(sc, sc->code, false);
89386   return(oprec_cond_a_a_a_a_opla_laq(sc));
89387 }
89388 
89389 static s7_pointer fx_recur_cond_a_a_a_a_opla_laq(s7_scheme *sc, s7_pointer arg)
89390 {
89391   tick_tc(sc, OP_RECUR_COND_A_A_A_A_opLA_LAq);
89392   sc->rec_stack = recur_make_stack(sc);
89393   opinit_cond_a_a_a_a_opla_laq(sc, arg, true);
89394   sc->value = oprec_cond_a_a_a_a_opla_laq(sc);
89395   sc->rec_loc = 0;
89396   return(sc->value);
89397 }
89398 
89399 
89400 /* -------- cond_a_a_a_a_oplaa_laaq -------- */
89401 
89402 static void opinit_cond_a_a_a_a_oplaa_laaq(s7_scheme *sc, bool cond_case)
89403 {
89404   s7_pointer caller;
89405   if (cond_case)
89406     {
89407       rec_set_test(sc, cadr(sc->code));
89408       rec_set_res(sc, cdadr(sc->code));
89409       rec_set_f1(sc, caddr(sc->code));
89410       rec_set_f2(sc, cdaddr(sc->code));
89411     }
89412   else
89413     {
89414       rec_set_test(sc, cdr(sc->code));
89415       rec_set_res(sc, cddr(sc->code));       /* (if a b...) */
89416       rec_set_f1(sc, opt1_pair(sc->code));   /* cdr(cadddr(sc->code)), (if a b (if c d...)) */
89417       rec_set_f2(sc, cdr(opt1_pair(sc->code)));
89418     }
89419   caller = opt3_pair(sc->code);              /* cadr(cadddr(sc->code)) = (cfunc laa laa) */
89420 
89421   sc->rec_f3p = cdadr(caller);
89422   rec_set_f4(sc, cdr(sc->rec_f3p));
89423   sc->rec_f3f = fx_proc(sc->rec_f3p);
89424   sc->rec_f3p = car(sc->rec_f3p);
89425   sc->rec_f5p = opt3_pair(caller);
89426   rec_set_f6(sc, cdr(sc->rec_f5p));
89427   sc->rec_f5f = fx_proc(sc->rec_f5p);
89428   sc->rec_f5p = car(sc->rec_f5p);
89429   sc->rec_slot1 = let_slots(sc->curlet);
89430   sc->rec_slot2 = next_slot(sc->rec_slot1);
89431   sc->rec_fn = fn_proc(caller);
89432 }
89433 
89434 static s7_pointer oprec_cond_a_a_a_a_oplaa_laaq(s7_scheme *sc)
89435 {
89436   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89437   if (sc->rec_f1f(sc, sc->rec_f1p) != sc->F) return(sc->rec_f2f(sc, sc->rec_f2p));
89438   recur_push(sc, sc->rec_f3f(sc, sc->rec_f3p));
89439   recur_push(sc, sc->rec_f4f(sc, sc->rec_f4p));
89440   recur_push(sc, sc->rec_f5f(sc, sc->rec_f5p));
89441   slot_set_value(sc->rec_slot2, sc->rec_f6f(sc, sc->rec_f6p));
89442   slot_set_value(sc->rec_slot1, recur_pop(sc));
89443   sc->value = oprec_cond_a_a_a_a_oplaa_laaq(sc);        /* second laa arg */
89444   slot_set_value(sc->rec_slot2, recur_pop(sc));
89445   slot_set_value(sc->rec_slot1, recur_pop(sc));
89446   recur_push_unchecked(sc, sc->value);
89447   set_car(sc->t2_1, oprec_cond_a_a_a_a_oplaa_laaq(sc)); /* first laa arg */
89448   set_car(sc->t2_2, recur_pop(sc));
89449   return(sc->rec_fn(sc, sc->t2_1));
89450 }
89451 
89452 static s7_pointer op_recur_cond_a_a_a_a_oplaa_laaq(s7_scheme *sc)
89453 {
89454   opinit_cond_a_a_a_a_oplaa_laaq(sc, true);
89455   return(oprec_cond_a_a_a_a_oplaa_laaq(sc));
89456 }
89457 
89458 static s7_pointer op_recur_if_a_a_if_a_a_oplaa_laaq(s7_scheme *sc)
89459 {
89460   opinit_cond_a_a_a_a_oplaa_laaq(sc, false);
89461   return(oprec_cond_a_a_a_a_oplaa_laaq(sc));
89462 }
89463 
89464 
89465 /* -------- cond_a_a_a_a_opa_laaq -------- */
89466 static void opinit_cond_a_a_a_a_opa_laaq(s7_scheme *sc)
89467 {
89468   s7_pointer caller;
89469   rec_set_test(sc, cadr(sc->code));
89470   rec_set_res(sc, cdadr(sc->code));
89471 
89472   sc->rec_f1p = caddr(sc->code);
89473   rec_set_f2(sc, cdr(sc->rec_f1p));
89474   sc->rec_f1f = fx_proc(sc->rec_f1p);
89475   sc->rec_f1p = car(sc->rec_f1p);
89476   caller = opt3_pair(sc->code);
89477   rec_set_f3(sc, cdr(caller));
89478   rec_set_f4(sc, opt3_pair(caller));
89479   rec_set_f5(sc, cdr(opt3_pair(caller)));
89480   sc->rec_slot1 = let_slots(sc->curlet);
89481   sc->rec_slot2 = next_slot(sc->rec_slot1);
89482   sc->rec_fn = fn_proc(caller);
89483 }
89484 
89485 static s7_pointer oprec_cond_a_a_a_a_opa_laaq(s7_scheme *sc)
89486 {
89487   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89488   if (sc->rec_f1f(sc, sc->rec_f1p) != sc->F) return(sc->rec_f2f(sc, sc->rec_f2p));
89489   recur_push(sc, sc->rec_f3f(sc, sc->rec_f3p));
89490   recur_push(sc, sc->rec_f4f(sc, sc->rec_f4p));
89491   slot_set_value(sc->rec_slot2, sc->rec_f5f(sc, sc->rec_f5p));
89492   slot_set_value(sc->rec_slot1, recur_pop(sc));
89493   set_car(sc->t2_2, oprec_cond_a_a_a_a_opa_laaq(sc));
89494   set_car(sc->t2_1, recur_pop(sc));
89495   return(sc->rec_fn(sc, sc->t2_1));
89496 }
89497 
89498 static s7_pointer op_recur_cond_a_a_a_a_opa_laaq(s7_scheme *sc)
89499 {
89500   opinit_cond_a_a_a_a_opa_laaq(sc);
89501   return(oprec_cond_a_a_a_a_opa_laaq(sc));
89502 }
89503 
89504 
89505 /* -------- cond_a_a_a_laa_opa_laaq -------- */
89506 
89507 static void opinit_cond_a_a_a_laa_opa_laaq(s7_scheme *sc, bool cond)
89508 {
89509   s7_pointer caller;
89510   rec_set_test(sc, (cond) ? cadr(sc->code) : cdr(sc->code));
89511   rec_set_res(sc, (cond) ? cdadr(sc->code) : cddr(sc->code));
89512 
89513   sc->rec_f1p = (cond) ? caddr(sc->code) : cdr(cadddr(sc->code));
89514   sc->rec_f2p = cdadr(sc->rec_f1p);
89515   rec_set_f3(sc, cdr(sc->rec_f2p));
89516 
89517   sc->rec_f1f = fx_proc(sc->rec_f1p);
89518   sc->rec_f1p = car(sc->rec_f1p);
89519   sc->rec_f2f = fx_proc(sc->rec_f2p);
89520   sc->rec_f2p = car(sc->rec_f2p);
89521 
89522   caller = opt3_pair(sc->code);          /* opA_LAA */
89523 
89524   rec_set_f4(sc, cdr(caller));
89525   sc->rec_f5p = cdr(opt3_pair(caller));  /* (L)AA */
89526   rec_set_f6(sc, cdr(sc->rec_f5p));
89527   sc->rec_f5f = fx_proc(sc->rec_f5p);
89528   sc->rec_f5p = car(sc->rec_f5p);
89529   sc->rec_fn = fn_proc(caller);
89530 
89531   sc->rec_slot1 = let_slots(sc->curlet);
89532   sc->rec_slot2 = next_slot(sc->rec_slot1);
89533 }
89534 
89535 static s7_pointer oprec_cond_a_a_a_laa_opa_laaq(s7_scheme *sc)
89536 {
89537   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89538   if (sc->rec_f1f(sc, sc->rec_f1p) != sc->F)
89539     {
89540       recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
89541       slot_set_value(sc->rec_slot2, sc->rec_f3f(sc, sc->rec_f3p));
89542       slot_set_value(sc->rec_slot1, recur_pop(sc));
89543       return(oprec_cond_a_a_a_laa_opa_laaq(sc)); /* first laa above */
89544     }
89545   recur_push(sc, sc->rec_f4f(sc, sc->rec_f4p));
89546   recur_push(sc, sc->rec_f5f(sc, sc->rec_f5p));
89547   slot_set_value(sc->rec_slot2, sc->rec_f6f(sc, sc->rec_f6p));
89548   slot_set_value(sc->rec_slot1, recur_pop(sc));
89549   if (sc->rec_testf(sc, sc->rec_testp) != sc->F)
89550     set_car(sc->t2_2, sc->rec_resf(sc, sc->rec_resp));
89551   else
89552     {
89553       if (sc->rec_f1f(sc, sc->rec_f1p) != sc->F)
89554 	{
89555 	  recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
89556 	  slot_set_value(sc->rec_slot2, sc->rec_f3f(sc, sc->rec_f3p));
89557 	  slot_set_value(sc->rec_slot1, recur_pop(sc));
89558 	  set_car(sc->t2_2, oprec_cond_a_a_a_laa_opa_laaq(sc)); /* first laa above */
89559 	}
89560       else
89561 	{
89562 	  recur_push(sc, sc->rec_f4f(sc, sc->rec_f4p));
89563 	  recur_push(sc, sc->rec_f5f(sc, sc->rec_f5p));
89564 	  slot_set_value(sc->rec_slot2, sc->rec_f6f(sc, sc->rec_f6p));
89565 	  slot_set_value(sc->rec_slot1, recur_pop(sc));
89566 	  set_car(sc->t2_2, oprec_cond_a_a_a_laa_opa_laaq(sc));
89567 	  set_car(sc->t2_1, recur_pop(sc));
89568 	  set_car(sc->t2_2, sc->rec_fn(sc, sc->t2_1));
89569 	}}
89570   set_car(sc->t2_1, recur_pop(sc));
89571   return(sc->rec_fn(sc, sc->t2_1));
89572 }
89573 
89574 static s7_pointer op_recur_cond_a_a_a_laa_opa_laaq(s7_scheme *sc)
89575 {
89576   opinit_cond_a_a_a_laa_opa_laaq(sc, true);
89577   return(oprec_cond_a_a_a_laa_opa_laaq(sc));
89578 }
89579 
89580 static s7_pointer op_recur_if_a_a_if_a_laa_opa_laaq(s7_scheme *sc) /* if version, same logic as cond above */
89581 {
89582   opinit_cond_a_a_a_laa_opa_laaq(sc, false);
89583   return(oprec_cond_a_a_a_laa_opa_laaq(sc));
89584 }
89585 
89586 /* -------- cond_a_a_a_laa_lopa_laaq -------- */
89587 
89588 static opt_pid_t opinit_cond_a_a_a_laa_lopa_laaq(s7_scheme *sc)
89589 {
89590   s7_pointer caller;
89591 
89592   sc->rec_slot1 = let_slots(sc->curlet);
89593   sc->rec_slot2 = next_slot(sc->rec_slot1);
89594 
89595 #if (!WITH_GMP)
89596   if ((is_t_integer(slot_value(sc->rec_slot1))) &&
89597       (is_t_integer(slot_value(sc->rec_slot2))))
89598     {
89599       sc->pc = 0;
89600       sc->rec_test_o = sc->opts[0];
89601       if (bool_optimize(sc, cadr(sc->code)))
89602 	{
89603 	  sc->rec_result_o = sc->opts[sc->pc];
89604 	  if (int_optimize(sc, cdadr(sc->code)))
89605 	    {
89606 	      s7_pointer laa1;
89607 	      sc->rec_a1_o = sc->opts[sc->pc];
89608 	      laa1 = caddr(sc->code);
89609 	      if (bool_optimize(sc, laa1))
89610 		{
89611 		  sc->rec_a2_o = sc->opts[sc->pc];
89612 	  	  if (int_optimize(sc, cdadr(laa1)))
89613 		    {
89614 		      sc->rec_a3_o = sc->opts[sc->pc];
89615 		      if (int_optimize(sc, cddadr(laa1)))
89616 			{
89617 			  s7_pointer laa2, laa3;
89618 			  sc->rec_a4_o = sc->opts[sc->pc];
89619 			  laa2 = cadr(cadddr(sc->code));
89620 			  laa3 = caddr(laa2);
89621 			  if (int_optimize(sc, cdr(laa2)))
89622 			    {
89623 			      sc->rec_a5_o = sc->opts[sc->pc];
89624 			      if (int_optimize(sc, cdr(laa3)))
89625 				{
89626 				  sc->rec_a6_o = sc->opts[sc->pc];
89627 				  if (int_optimize(sc, cddr(laa3)))
89628 				    {
89629 				      sc->rec_val1 = make_mutable_integer(sc, integer(slot_value(sc->rec_slot1)));
89630 				      slot_set_value(sc->rec_slot1, sc->rec_val1);
89631 				      sc->rec_val2 = make_mutable_integer(sc, integer(slot_value(sc->rec_slot2)));
89632 				      slot_set_value(sc->rec_slot2, sc->rec_val2);
89633 				      if (sc->pc == 8)
89634 					{
89635 					  sc->rec_fb1 = sc->rec_test_o->v[0].fb;
89636 					  sc->rec_fb2 = sc->rec_a1_o->v[0].fb;
89637 					  sc->rec_fi1 = sc->rec_result_o->v[0].fi;
89638 					  sc->rec_fi2 = sc->rec_a2_o->v[0].fi;
89639 					  sc->rec_fi3 = sc->rec_a3_o->v[0].fi;
89640 					  sc->rec_fi4 = sc->rec_a4_o->v[0].fi;
89641 					  sc->rec_fi5 = sc->rec_a5_o->v[0].fi;
89642 					  sc->rec_fi6 = sc->rec_a6_o->v[0].fi;
89643 					  return(OPT_INT_0);
89644 					}
89645 				      return(OPT_INT);
89646 				    }}}}}}}}}
89647 #endif
89648   rec_set_test(sc, cadr(sc->code));
89649   rec_set_res(sc, cdadr(sc->code));
89650 
89651   sc->rec_f1p = caddr(sc->code);
89652   sc->rec_f2p = cdadr(sc->rec_f1p);
89653   rec_set_f3(sc, cdr(sc->rec_f2p));
89654   sc->rec_f1f = fx_proc(sc->rec_f1p);
89655   sc->rec_f1p = car(sc->rec_f1p);
89656   sc->rec_f2f = fx_proc(sc->rec_f2p);
89657   sc->rec_f2p = car(sc->rec_f2p);
89658 
89659   caller = opt3_pair(sc->code);
89660   rec_set_f4(sc, cdr(caller));
89661   sc->rec_f5p = opt3_pair(caller);
89662   rec_set_f6(sc, cdr(sc->rec_f5p));
89663   sc->rec_f5f = fx_proc(sc->rec_f5p);
89664   sc->rec_f5p = car(sc->rec_f5p);
89665   return(OPT_PTR);
89666 }
89667 
89668 static s7_int oprec_i_cond_a_a_a_laa_lopa_laaq(s7_scheme *sc)
89669 {
89670   s7_int i1, i2;
89671   if (sc->rec_test_o->v[0].fb(sc->rec_test_o)) return(sc->rec_result_o->v[0].fi(sc->rec_result_o));
89672   if (sc->rec_a1_o->v[0].fb(sc->rec_a1_o))
89673     {
89674       i1 = sc->rec_a2_o->v[0].fi(sc->rec_a2_o);
89675       integer(sc->rec_val2) = sc->rec_a3_o->v[0].fi(sc->rec_a3_o);
89676       integer(sc->rec_val1) = i1;
89677       return(oprec_i_cond_a_a_a_laa_lopa_laaq(sc));
89678     }
89679   i1 = sc->rec_a4_o->v[0].fi(sc->rec_a4_o);
89680   i2 = sc->rec_a5_o->v[0].fi(sc->rec_a5_o);
89681   integer(sc->rec_val2) = sc->rec_a6_o->v[0].fi(sc->rec_a6_o);
89682   integer(sc->rec_val1) = i2;
89683   integer(sc->rec_val2) = oprec_i_cond_a_a_a_laa_lopa_laaq(sc);
89684   integer(sc->rec_val1) = i1;
89685   return(oprec_i_cond_a_a_a_laa_lopa_laaq(sc));
89686 }
89687 
89688 static s7_int oprec_i_cond_a_a_a_laa_lopa_laaq_0(s7_scheme *sc)
89689 {
89690   s7_int i1, i2;
89691   if (sc->rec_fb1(sc->rec_test_o)) return(sc->rec_fi1(sc->rec_result_o));
89692   if (sc->rec_fb2(sc->rec_a1_o))
89693     {
89694       i1 = sc->rec_fi2(sc->rec_a2_o);
89695       integer(sc->rec_val2) = sc->rec_fi3(sc->rec_a3_o);
89696       integer(sc->rec_val1) = i1;
89697       return(oprec_i_cond_a_a_a_laa_lopa_laaq_0(sc));
89698     }
89699   i1 = sc->rec_fi4(sc->rec_a4_o);
89700   i2 = sc->rec_fi5(sc->rec_a5_o);
89701   integer(sc->rec_val2) = sc->rec_fi6(sc->rec_a6_o);
89702   integer(sc->rec_val1) = i2;
89703   integer(sc->rec_val2) = oprec_i_cond_a_a_a_laa_lopa_laaq_0(sc);
89704   integer(sc->rec_val1) = i1;
89705   return(oprec_i_cond_a_a_a_laa_lopa_laaq_0(sc));
89706 }
89707 
89708 static s7_pointer oprec_cond_a_a_a_laa_lopa_laaq(s7_scheme *sc)
89709 {
89710   if (sc->rec_testf(sc, sc->rec_testp) != sc->F) return(sc->rec_resf(sc, sc->rec_resp));
89711   if (sc->rec_f1f(sc, sc->rec_f1p) != sc->F)
89712     {
89713       recur_push(sc, sc->rec_f2f(sc, sc->rec_f2p));
89714       slot_set_value(sc->rec_slot2, sc->rec_f3f(sc, sc->rec_f3p));
89715       slot_set_value(sc->rec_slot1, recur_pop(sc));
89716       return(oprec_cond_a_a_a_laa_lopa_laaq(sc));
89717     }
89718   recur_push(sc, sc->rec_f4f(sc, sc->rec_f4p));
89719   recur_push(sc, sc->rec_f5f(sc, sc->rec_f5p));
89720   slot_set_value(sc->rec_slot2, sc->rec_f6f(sc, sc->rec_f6p));
89721   slot_set_value(sc->rec_slot1, recur_pop(sc));
89722   slot_set_value(sc->rec_slot2, oprec_cond_a_a_a_laa_lopa_laaq(sc));
89723   slot_set_value(sc->rec_slot1, recur_pop(sc));
89724   return(oprec_cond_a_a_a_laa_lopa_laaq(sc));
89725 }
89726 
89727 static void wrap_recur_cond_a_a_a_laa_lopa_laaq(s7_scheme *sc)
89728 {
89729   opt_pid_t choice;
89730   tick_tc(sc, sc->cur_op);
89731   choice = opinit_cond_a_a_a_laa_lopa_laaq(sc);
89732   if (choice != OPT_PTR)
89733     sc->value = make_integer(sc, (choice == OPT_INT) ? oprec_i_cond_a_a_a_laa_lopa_laaq(sc) : oprec_i_cond_a_a_a_laa_lopa_laaq_0(sc));
89734   else
89735     {
89736       sc->rec_stack = recur_make_stack(sc);
89737       sc->value = oprec_cond_a_a_a_laa_lopa_laaq(sc);
89738       sc->rec_loc = 0;
89739     }
89740 }
89741 
89742 
89743 /* -------- and_a_or_a_laa_laa -------- */
89744 
89745 static void opinit_and_a_or_a_laa_laa(s7_scheme *sc, s7_pointer code)
89746 {
89747   s7_pointer orp;
89748   orp = cdr(opt3_pair(code));
89749   rec_set_test(sc, cdr(code));
89750   rec_set_res(sc, orp);
89751   rec_set_f1(sc, cdr(cadr(orp)));
89752   rec_set_f2(sc, cddr(cadr(orp)));
89753   rec_set_f3(sc, cdr(caddr(orp)));
89754   rec_set_f4(sc, cddr(caddr(orp)));
89755   sc->rec_slot1 = let_slots(sc->curlet);
89756   sc->rec_slot2 = next_slot(sc->rec_slot1);
89757 }
89758 
89759 static s7_pointer oprec_and_a_or_a_laa_laa(s7_scheme *sc)
89760 {
89761   s7_pointer p;
89762   if (sc->rec_testf(sc, sc->rec_testp) == sc->F) return(sc->F);
89763   p = sc->rec_resf(sc, sc->rec_resp);
89764   if (p != sc->F) return(p);
89765 
89766   recur_push(sc, slot_value(sc->rec_slot1));
89767   recur_push(sc, slot_value(sc->rec_slot2));
89768   recur_push(sc, sc->rec_f1f(sc, sc->rec_f1p));
89769   slot_set_value(sc->rec_slot2, sc->rec_f2f(sc, sc->rec_f2p));
89770   slot_set_value(sc->rec_slot1, recur_pop(sc));
89771   p = oprec_and_a_or_a_laa_laa(sc);
89772   if (p != sc->F)
89773     {
89774       sc->rec_loc -= 2;
89775       return(p);
89776     }
89777   slot_set_value(sc->rec_slot2, recur_pop(sc));
89778   slot_set_value(sc->rec_slot1, recur_pop(sc));
89779   recur_push(sc, sc->rec_f3f(sc, sc->rec_f3p));
89780   slot_set_value(sc->rec_slot2, sc->rec_f4f(sc, sc->rec_f4p));
89781   slot_set_value(sc->rec_slot1, recur_pop(sc));
89782   return(oprec_and_a_or_a_laa_laa(sc));
89783 }
89784 
89785 static s7_pointer op_recur_and_a_or_a_laa_laa(s7_scheme *sc)
89786 {
89787   opinit_and_a_or_a_laa_laa(sc, sc->code);
89788   return(oprec_and_a_or_a_laa_laa(sc));
89789 }
89790 
89791 static s7_pointer fx_recur_and_a_or_a_laa_laa(s7_scheme *sc, s7_pointer arg)
89792 {
89793   tick_tc(sc, OP_RECUR_AND_A_OR_A_LAA_LAA);
89794   sc->rec_stack = recur_make_stack(sc);
89795   opinit_and_a_or_a_laa_laa(sc, arg);
89796   sc->value = oprec_and_a_or_a_laa_laa(sc);
89797   sc->rec_loc = 0;
89798   return(sc->value);
89799 }
89800 
89801 
89802 static void wrap_recur(s7_scheme *sc, s7_pointer (*recur)(s7_scheme *sc))
89803 {
89804   tick_tc(sc, sc->cur_op);
89805   sc->rec_stack = recur_make_stack(sc);
89806   sc->value = recur(sc);
89807   sc->rec_loc = 0;
89808 }
89809 
89810 
89811 /* -------------------------------- */
89812 static void op_safe_c_p(s7_scheme *sc)
89813 {
89814   check_stack_size(sc);
89815   push_stack_no_args_direct(sc, OP_SAFE_C_P_1);
89816   sc->code = T_Pair(cadr(sc->code));
89817 }
89818 
89819 static void op_safe_c_p_1(s7_scheme *sc)
89820 {
89821   set_car(sc->t1_1, sc->value);
89822   sc->value = fn_proc(sc->code)(sc, sc->t1_1);
89823 }
89824 
89825 static void op_safe_c_ssp(s7_scheme *sc)
89826 {
89827   check_stack_size(sc);
89828   push_stack_no_args_direct(sc, OP_SAFE_C_SSP_1);
89829   sc->code = opt3_pair(sc->code);
89830 }
89831 
89832 static void op_safe_c_ssp_1(s7_scheme *sc)
89833 {
89834   set_car(sc->t3_3, sc->value);
89835   set_car(sc->t3_1, lookup(sc, cadr(sc->code)));
89836   set_car(sc->t3_2, lookup(sc, caddr(sc->code)));
89837   sc->value = fn_proc(sc->code)(sc, sc->t3_1);
89838 }
89839 
89840 static void op_safe_c_ssp_mv_1(s7_scheme *sc)
89841 {
89842   sc->args = cons_unchecked(sc, lookup(sc, cadr(sc->code)), cons(sc, lookup(sc, caddr(sc->code)), sc->value)); /* not ulist here */
89843   sc->code = c_function_base(opt1_cfunc(sc->code));
89844 }
89845 
89846 static s7_pointer op_c_s_opsq(s7_scheme *sc)
89847 {
89848   s7_pointer args, val;
89849   args = cdr(sc->code);
89850   val = lookup(sc, car(args));
89851   set_car(sc->t1_1, lookup(sc, opt1_sym(args)));
89852   sc->args = list_2(sc, val, fn_proc(cadr(args))(sc, sc->t1_1));
89853   return(fn_proc(sc->code)(sc, sc->args));
89854 }
89855 
89856 static inline void op_s(s7_scheme *sc)
89857 {
89858   sc->code = lookup(sc, car(sc->code));
89859   if (!is_applicable(sc->code))
89860     apply_error(sc, sc->code, sc->nil);
89861   sc->args = sc->nil;
89862 }
89863 
89864 static s7_pointer op_s_c(s7_scheme *sc)
89865 {
89866   s7_pointer code;
89867   code = sc->code;
89868   sc->code = lookup_checked(sc, car(code));
89869   if (!is_applicable(sc->code))
89870     apply_error(sc, sc->code, cdr(code));
89871   sc->args = list_1(sc, cadr(code));
89872   return(NULL);
89873 }
89874 
89875 static Inline bool op_s_s(s7_scheme *sc)
89876 {
89877   s7_pointer code;
89878   code = sc->code;
89879   sc->code = lookup_checked(sc, car(code));
89880   if ((is_c_function(sc->code)) &&
89881       (c_function_required_args(sc->code) == 1) &&
89882       (!needs_copied_args(sc->code)))
89883     {
89884       set_car(sc->t1_1, lookup(sc, cadr(code)));
89885       sc->value = c_function_call(sc->code)(sc, sc->t1_1);
89886       return(true); /* goto START; */
89887     }
89888   if (!is_applicable(sc->code))
89889     apply_error(sc, sc->code, cdr(code));
89890   sc->args = (dont_eval_args(sc->code)) ? list_1(sc, cadr(code)) : list_1(sc, lookup(sc, cadr(code)));
89891   return(false); /* goto APPLY; */
89892 }
89893 
89894 static void op_x_a(s7_scheme *sc, s7_pointer f)
89895 {
89896   s7_pointer code;
89897   code = sc->code;
89898   sc->code = f;
89899   if (!is_applicable(sc->code))
89900     apply_error(sc, sc->code, cdr(code));
89901   sc->args = (dont_eval_args(sc->code)) ? list_1(sc, cadr(code)) : list_1(sc, fx_call(sc, cdr(code)));
89902 }
89903 
89904 static void op_x_aa(s7_scheme *sc, s7_pointer f)
89905 {
89906   s7_pointer code;
89907   code = sc->code;
89908   sc->code = f;
89909   if (!is_applicable(sc->code))
89910     apply_error(sc, sc->code, cdr(code));
89911   if (dont_eval_args(sc->code))
89912     sc->args = list_2(sc, cadr(code), caddr(code));
89913   else
89914     {
89915       sc->args = list_1(sc, fx_call(sc, cddr(code)));
89916       sc->args = cons(sc, fx_call(sc, cdr(code)), sc->args);
89917     }
89918 }
89919 
89920 static void op_p_s_1(s7_scheme *sc)
89921 {
89922   /* we get multiple values here (from op calc = "p" not "s") but don't need to handle it ourselves:
89923    *   let v be #(#_abs), so ((v 0) -2), (v 0 -2), ((values v 0) -2), and (((values v 0)) -2) are all 2
89924    *      or: (define (f1) (values vector-ref (vector 1 2 3))) (define arg 1) (define (f2) ((f1) arg)) (f2) (f2)
89925    *   so apply calls apply_pair which handles multiple values explicitly.
89926    */
89927   if (dont_eval_args(sc->value))
89928     sc->args = cdr(sc->code);
89929   else
89930     {
89931       sc->args = lookup_checked(sc, cadr(sc->code));
89932       if (needs_copied_args(sc->value))
89933 	sc->args = list_1(sc, sc->args);
89934       else sc->args = set_plist_1(sc, sc->args);
89935     }
89936   sc->code = sc->value; /* goto APPLY */
89937 }
89938 
89939 static void op_safe_c_function_star_all_a(s7_scheme *sc)
89940 {
89941   s7_pointer args, p;
89942   sc->args = safe_list_if_possible(sc, integer(opt3_arglen(cdr(sc->code))));
89943   for (args = cdr(sc->code), p = sc->args; is_pair(args); args = cdr(args), p = cdr(p))
89944     set_car(p, fx_call(sc, args));
89945   sc->code = opt1_cfunc(sc->code);
89946   apply_c_function_star(sc);
89947   clear_list_in_use(sc->args);
89948   sc->args = sc->nil;
89949 }
89950 
89951 static void op_safe_c_function_star(s7_scheme *sc)
89952 {
89953   sc->code = opt1_cfunc(sc->code);
89954   apply_c_function_star_fill_defaults(sc, 0);
89955 }
89956 
89957 static void op_safe_c_function_star_a(s7_scheme *sc)
89958 {
89959   s7_pointer p;
89960   p = fx_call(sc, cdr(sc->code));
89961   if (is_keyword(p))
89962     s7_error(sc, sc->syntax_error_symbol, set_elist_3(sc, value_is_missing_string, car(sc->code), p));
89963   /* scheme-level define* here also gives "not a parameter name" */
89964   sc->args = list_1(sc, p);
89965   sc->code = opt1_cfunc(sc->code);
89966   /* one arg, so it's not a keyword; all we need to do is fill in defaults */
89967   apply_c_function_star_fill_defaults(sc, 1);
89968 }
89969 
89970 static void op_safe_c_function_star_aa(s7_scheme *sc)
89971 {
89972   sc->temp1 = fx_call(sc, cdr(sc->code)); /* temp1 use in optimizer, various do loops */
89973   set_car(sc->t2_2, fx_call(sc, cddr(sc->code)));
89974   set_car(sc->t2_1, sc->temp1);
89975   sc->temp1 = sc->nil;
89976   sc->args = sc->t2_1;
89977   sc->code = opt1_cfunc(sc->code);
89978   apply_c_function_star(sc);
89979 }
89980 
89981 
89982 static void op_safe_c_ps(s7_scheme *sc)
89983 {
89984   push_stack_no_args_direct(sc, OP_SAFE_C_PS_1); /* got to wait in this case */
89985   sc->code = cadr(sc->code);
89986 }
89987 
89988 static void op_safe_c_ps_1(s7_scheme *sc)
89989 {
89990   set_car(sc->t2_2, lookup(sc, caddr(sc->code)));
89991   set_car(sc->t2_1, sc->value);
89992   sc->value = fn_proc(sc->code)(sc, sc->t2_1);
89993 }
89994 
89995 static void op_safe_c_ps_mv(s7_scheme *sc)  /* (define (hi a) (+ (values 1 2) a)) */
89996 {
89997   sc->args = pair_append(sc, sc->value, list_1(sc, lookup(sc, caddr(sc->code))));
89998   sc->code = c_function_base(opt1_cfunc(sc->code));
89999 }
90000 
90001 static void op_safe_c_sp(s7_scheme *sc)
90002 {
90003   s7_pointer args;
90004   check_stack_size(sc);
90005   args = cdr(sc->code);
90006   push_stack(sc, (opcode_t)opt1_any(args), lookup(sc, car(args)), sc->code);
90007   sc->code = cadr(args);
90008 }
90009 
90010 static void op_safe_c_sp_1(s7_scheme *sc)
90011 {
90012   /* we get here from many places (op_safe_c_sp for example), but all are safe */
90013   set_car(sc->t2_1, sc->args);
90014   set_car(sc->t2_2, sc->value);
90015   sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90016 }
90017 
90018 static void op_safe_c_sp_mv(s7_scheme *sc)
90019 {
90020   sc->args = cons(sc, sc->args, sc->value); /* not ulist here */
90021   sc->code = c_function_base(opt1_cfunc(sc->code));
90022 }
90023 
90024 static void op_safe_add_sp_1(s7_scheme *sc)
90025 {
90026   if ((is_t_integer(sc->args)) && (is_t_integer(sc->value)))
90027     sc->value = add_if_overflow_to_real_or_big_integer(sc, integer(sc->args), integer(sc->value));
90028   else sc->value = add_p_pp(sc, sc->args, sc->value);
90029 }
90030 
90031 static void op_safe_multiply_sp_1(s7_scheme *sc)
90032 {
90033   if ((is_t_real(sc->args)) && (is_t_real(sc->value)))
90034     sc->value = make_real(sc, real(sc->args) * real(sc->value));
90035   else sc->value = multiply_p_pp(sc, sc->args, sc->value);
90036 }
90037 
90038 static void op_safe_c_pc(s7_scheme *sc)
90039 {
90040   s7_pointer args;
90041   check_stack_size(sc);
90042   args = cdr(sc->code);
90043   push_stack(sc, OP_SAFE_C_PC_1, opt3_con(args), sc->code);
90044   sc->code = car(args);
90045 }
90046 
90047 static void op_safe_c_pc_mv(s7_scheme *sc)
90048 {
90049   sc->args = pair_append(sc, sc->value, list_1(sc, sc->args)); /* not plist! */
90050   sc->code = c_function_base(opt1_cfunc(sc->code));
90051 }
90052 
90053 static void op_safe_c_pc_1(s7_scheme *sc)
90054 {
90055   set_car(sc->t2_1, sc->value);
90056   set_car(sc->t2_2, sc->args);
90057   sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90058 }
90059 
90060 static void op_safe_c_cp(s7_scheme *sc)
90061 {
90062   s7_pointer args;
90063   /* it's possible in a case like this to overflow the stack -- s7test has a deeply
90064    *   nested expression involving (+ c (+ c (+ ... ))) all opt'd as safe_c_cp -- if we're close
90065    *   to the stack end at the start, it runs off the end.  Normally the stack increase in
90066    *   the reader protects us, but a call/cc can replace the original stack with a much smaller one.
90067    */
90068   check_stack_size(sc);
90069   args = cdr(sc->code);
90070   push_stack(sc, (opcode_t)opt1_any(args), opt3_any(args), sc->code); /* to safe_add_sp_1 for example */
90071   sc->code = cadr(args);
90072 }
90073 
90074 static Inline void op_safe_c_s(s7_scheme *sc)
90075 {
90076   set_car(sc->t1_1, lookup(sc, cadr(sc->code)));
90077   sc->value = fn_proc(sc->code)(sc, sc->t1_1);
90078 }
90079 
90080 static Inline void op_safe_c_ss(s7_scheme *sc)
90081 {
90082   set_car(sc->t2_1, lookup(sc, cadr(sc->code)));
90083   set_car(sc->t2_2, lookup(sc, opt2_sym(cdr(sc->code))));
90084   sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90085 }
90086 
90087 static void op_safe_c_sc(s7_scheme *sc)
90088 {
90089   set_car(sc->t2_1, lookup(sc, cadr(sc->code)));
90090   set_car(sc->t2_2, opt2_con(cdr(sc->code)));
90091   sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90092 }
90093 
90094 static void op_cl_a(s7_scheme *sc)
90095 {
90096   set_car(sc->t1_1, fx_call(sc, cdr(sc->code)));
90097   sc->value = fn_proc(sc->code)(sc, sc->t1_1);
90098 }
90099 
90100 static void op_cl_aa(s7_scheme *sc)
90101 {
90102   gc_protect_via_stack(sc, fx_call(sc, cdr(sc->code)));
90103   set_car(sc->t2_2, fx_call(sc, cddr(sc->code)));
90104   set_car(sc->t2_1, T_Pos(sc->stack_end[-2]));
90105   sc->stack_end -= 4;
90106   sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90107 }
90108 
90109 static void op_cl_fa(s7_scheme *sc)
90110 {
90111   s7_pointer code;
90112   set_car(sc->t2_2, fx_call(sc, cddr(sc->code)));
90113   code = cdadr(sc->code);
90114   set_car(sc->t2_1, make_closure(sc, car(code), cdr(code), T_CLOSURE | T_COPY_ARGS, CLOSURE_ARITY_NOT_SET));
90115   sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90116 }
90117 
90118 static void op_map_fa(s7_scheme *sc)
90119 {
90120   s7_pointer f, code;
90121   code = sc->code;
90122   f = cddr(code);
90123   sc->value = fx_call(sc, f);
90124   if (is_null(sc->value))
90125     {
90126       if (fx_proc_unchecked(code)) /* can be null */
90127 	sc->value = sc->unspecified;
90128       return;
90129     }
90130   sc->code = opt3_pair(code); /* cdadr(code); */
90131   f = inline_make_closure(sc, car(sc->code), cdr(sc->code), T_CLOSURE | T_COPY_ARGS, 1);
90132   sc->value = (fn_proc_unchecked(code)) ? g_for_each_closure(sc, f, sc->value) : g_map_closure(sc, f, sc->value);
90133 }
90134 
90135 static void op_cl_all_a(s7_scheme *sc)
90136 {
90137   s7_pointer args, p, val;
90138   val = safe_list_if_possible(sc, integer(opt3_arglen(cdr(sc->code))));
90139   if (in_heap(val))
90140     gc_protect_via_stack(sc, val);
90141   for (args = cdr(sc->code), p = val; is_pair(args); args = cdr(args), p = cdr(p))
90142     set_car(p, fx_call(sc, args));
90143   sc->value = fn_proc(sc->code)(sc, val);
90144   if (in_heap(val))
90145     sc->stack_end -= 4;
90146   else clear_list_in_use(val);
90147 }
90148 
90149 static void op_cl_sas(s7_scheme *sc)
90150 {
90151   set_car(sc->t3_2, fx_call(sc, cddr(sc->code)));
90152   set_car(sc->t3_1, lookup(sc, cadr(sc->code)));
90153   set_car(sc->t3_3, lookup(sc, cadr(cddr(sc->code))));
90154   sc->value = fn_proc(sc->code)(sc, sc->t3_1);
90155 }
90156 
90157 static bool op_safe_c_pp(s7_scheme *sc)
90158 {
90159   s7_pointer args;
90160   args = cdr(sc->code);
90161   if ((has_gx(args)) && (symbol_ctr(caar(args)) == 1))
90162     {
90163       s7_pointer val;
90164       val = fx_proc(args)(sc, car(args));
90165       sc->value = val;
90166       if ((has_gx(cdr(args))) && (symbol_ctr(caadr(args)) == 1))
90167 	{
90168 	  set_car(sc->t2_2, fx_proc_unchecked(cdr(args))(sc, cadr(args)));
90169 	  set_car(sc->t2_1, val);
90170 	  sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90171 	  return(false);
90172 	}
90173       check_stack_size(sc);
90174       push_stack(sc, (opcode_t)opt1_any(cdr(sc->code)), sc->value, sc->code); /* mv -> 3, opt1 is OP_SAFE_CONS_SP_1 et al which assume no mv */
90175       sc->code = caddr(sc->code);
90176       return(true);
90177     }
90178   check_stack_size(sc);
90179   push_stack_no_args_direct(sc, OP_SAFE_C_PP_1);
90180   sc->code = car(args);
90181   return(true);
90182 }
90183 
90184 static void op_safe_c_pp_1(s7_scheme *sc)
90185 {
90186   /* unless multiple values from last call (first arg) we get here only from OP_SAFE_C_PP.
90187    *   splice_in_values changes the operator so if we get here, sc->value is the result of the first arg
90188    * safe_c_pp -> 1, but if mv, -> 3
90189    *   1: -> 2, if mv -> 4
90190    *   2: done (both normal)
90191    *   3: -> 5, but if mv, -> 6
90192    *   4: done (1 normal, 2 mv)
90193    *   5: done (1 mv, 2 normal)
90194    *   6: done (both mv)
90195    * I think safe_c_ppp would require 18 branches (or maybe just collect the args and concatenate at the end?)
90196    */
90197   push_stack(sc, (opcode_t)opt1_any(cdr(sc->code)), sc->value, sc->code); /* mv -> 3, opt1 is OP_SAFE_CONS_SP_1 et al which assume no mv */
90198   sc->code = caddr(sc->code);
90199 }
90200 
90201 static void op_safe_c_pp_3_mv(s7_scheme *sc)
90202 {
90203   /* we get here if the first arg returned multiple values */
90204   push_stack(sc, OP_SAFE_C_PP_5, copy_proper_list(sc, sc->value), sc->code); /* copy is needed here */
90205   sc->code = caddr(sc->code);
90206 }
90207 
90208 static void op_safe_c_pp_5(s7_scheme *sc)
90209 {
90210   /* 1 mv, 2 normal, sc->args was copied above (and this is a safe c function so its args are in no danger) */
90211   if (is_null(sc->args))
90212     sc->args = list_1(sc, sc->value);
90213   else
90214     {
90215       s7_pointer p;
90216       for (p = sc->args; is_pair(cdr(p)); p = cdr(p));
90217       set_cdr(p, list_1(sc, sc->value));
90218     }
90219   sc->code = c_function_base(opt1_cfunc(sc->code));
90220 }
90221 
90222 static void op_safe_c_pp_6_mv(s7_scheme *sc)
90223 {
90224   sc->args = pair_append(sc, sc->args, sc->value);
90225   /*
90226    * fn_proc(sc->code) here is g_add_2, but we have any number of args from a values call
90227    *   the original (unoptimized) function is (hopefully) c_function_base(opt1_cfunc(sc->code))?
90228    *   (let () (define (hi) (+ (values 1 2) (values 3 4))) (hi)) -> 10
90229    */
90230   sc->code = c_function_base(opt1_cfunc(sc->code));
90231 }
90232 
90233 static Inline bool collect_fp_args(s7_scheme *sc, opcode_t op, s7_pointer args)
90234 {
90235   s7_pointer p;
90236   sc->args = args;
90237   for (p = sc->code; is_pair(p); p = cdr(p))
90238     if (has_fx(p))
90239       sc->args = cons(sc, fx_call(sc, p), sc->args); /* reversed before apply in OP_ANY_C_FP_1 */
90240     else
90241       {
90242 	if ((has_gx(p)) && (symbol_ctr(caar(p)) == 1))
90243 	  sc->args = cons(sc, fx_proc_unchecked(p)(sc, car(p)), sc->args);
90244 	else
90245 	  {
90246 	    push_stack(sc, op, sc->args, cdr(p));
90247 	    sc->code = T_Pair(car(p));
90248 	    return(true);
90249 	  }}
90250   return(false);
90251 }
90252 
90253 static bool op_any_c_fp(s7_scheme *sc) /* code: (func . args) where at least one arg is not fxable */
90254 {
90255   s7_pointer p;
90256   sc->args = sc->nil;
90257   for (p = cdr(sc->code); is_pair(p); p = cdr(p))
90258     if (has_fx(p))
90259       sc->args = cons(sc, fx_call(sc, p), sc->args); /* reversed before apply in OP_ANY_C_FP_1 */
90260     else
90261       {
90262 	if ((has_gx(p)) && (symbol_ctr(caar(p)) == 1))
90263 	  sc->args = cons(sc, fx_proc_unchecked(p)(sc, car(p)), sc->args);
90264 	else
90265 	  {
90266 	    if (sc->op_stack_now >= sc->op_stack_end)
90267 	      resize_op_stack(sc);
90268 	    push_op_stack(sc, sc->code);
90269 	    check_stack_size(sc);
90270 	    push_stack(sc, ((intptr_t)((is_pair(cdr(p))) ? OP_ANY_C_FP_1 : OP_ANY_C_FP_2)), sc->args, cdr(p));
90271 	    sc->code = T_Pair(car(p));
90272 	    return(true);
90273 	  }}
90274   /* here fx/gx got all the args */
90275   sc->args = proper_list_reverse_in_place(sc, sc->args);
90276   sc->value = fn_proc(sc->code)(sc, sc->args);
90277   return(false);
90278 }
90279 
90280 static Inline bool op_any_c_fp_1(s7_scheme *sc)
90281 {
90282   /* in-coming sc->value has the current arg value, sc->args is all previous args, sc->code is on op-stack */
90283   if (collect_fp_args(sc, OP_ANY_C_FP_1, cons(sc, sc->value, sc->args)))
90284     return(true);
90285   sc->args = proper_list_reverse_in_place(sc, sc->args);
90286   sc->code = pop_op_stack(sc);
90287   sc->value = fn_proc(sc->code)(sc, sc->args);
90288   return(false);
90289 }
90290 
90291 static void op_any_c_fp_2(s7_scheme *sc)
90292 {
90293   sc->args = proper_list_reverse_in_place(sc, sc->args = cons(sc, sc->value, sc->args));
90294   sc->code = pop_op_stack(sc);
90295   sc->value = fn_proc(sc->code)(sc, sc->args);
90296 }
90297 
90298 static s7_pointer revappend(s7_scheme *sc, s7_pointer a, s7_pointer b)
90299 {
90300   /* (map (lambda (x) (if (odd? x) (apply values '(1 2 3)) (values))) (list 1 2 3 4)) is a bad case -- we have to copy the incoming list */
90301   s7_pointer p = b, q;
90302 
90303   if (is_not_null(a))
90304     {
90305       a = copy_proper_list(sc, a);
90306       do /* while (is_not_null(a)) */
90307 	{
90308 	  q = cdr(a);
90309 	  set_cdr(a, p);
90310 	  p = a;
90311 	  a = q;
90312 	}
90313       while (is_pair(a));
90314     }
90315   return(p);
90316 }
90317 
90318 static Inline bool op_any_c_fp_mv_1(s7_scheme *sc)
90319 {
90320   /* we're looping through fp cases here, so sc->value can be non-mv after the first */
90321   if (collect_fp_args(sc, OP_ANY_C_FP_MV_1, (is_multiple_value(sc->value)) ? revappend(sc, sc->value, sc->args) : cons(sc, sc->value, sc->args)))
90322     return(true);
90323   sc->args = proper_list_reverse_in_place(sc, sc->args);
90324   sc->code = pop_op_stack(sc);
90325   sc->code = c_function_base(opt1_cfunc(sc->code));
90326   return(false);
90327 }
90328 
90329 static void op_any_closure_fp(s7_scheme *sc)
90330 {
90331   s7_pointer p;
90332   check_stack_size(sc);
90333   if (sc->op_stack_now >= sc->op_stack_end)
90334     resize_op_stack(sc);
90335   push_op_stack(sc, sc->code);
90336   p = cdr(sc->code);
90337   if (has_fx(p))
90338     {
90339       sc->args = list_1(sc, fx_call(sc, p));
90340       for (p = cdr(p); (is_pair(p)) && (has_fx(p)); p = cdr(p))
90341 	sc->args = cons_unchecked(sc, fx_call(sc, p), sc->args);
90342     }
90343   else sc->args = sc->nil;
90344   push_stack(sc, ((intptr_t)((is_pair(cdr(p))) ? OP_ANY_CLOSURE_FP_1 : OP_ANY_CLOSURE_FP_2)), sc->args, cdr(p));
90345   sc->code = T_Pair(car(p));
90346 }
90347 
90348 static void op_any_closure_fp_end(s7_scheme *sc)
90349 {
90350   s7_pointer x, z, f;
90351   uint64_t id;
90352 
90353   sc->args = proper_list_reverse_in_place(sc, sc->args); /* needed in either case -- closure_args(f) is not reversed */
90354   sc->code = pop_op_stack(sc);
90355   f = opt1_lambda(sc->code);
90356 
90357   if (is_safe_closure(f))
90358     {
90359       id = ++sc->let_number;
90360       sc->curlet = closure_let(f);
90361       let_set_id(sc->curlet, id);
90362 
90363       for (x = let_slots(sc->curlet), z = sc->args; tis_slot(x); x = next_slot(x))
90364 	{
90365 	  s7_pointer nz;
90366 	  slot_set_value(x, car(z));
90367 	  symbol_set_local_slot(slot_symbol(x), id, x);
90368 	  nz = cdr(z);
90369 	  free_cell(sc, z);
90370 	  z = nz;
90371 	}
90372       if (tis_slot(x))
90373 	s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, not_enough_arguments_string, sc->code, sc->args));
90374     }
90375   else
90376     {
90377       s7_pointer e, p, last_slot;
90378       e = make_let(sc, closure_let(f));
90379       sc->z = e;
90380       id = let_id(e);
90381       p = closure_args(f);
90382       last_slot = make_slot(sc, car(p), car(sc->args));
90383       slot_set_next(last_slot, slot_end(sc));
90384       let_set_slots(e, last_slot);
90385       symbol_set_local_slot(car(p), id, last_slot);
90386 
90387       z = cdr(sc->args);
90388       free_cell(sc, sc->args);
90389       for (p = cdr(p); is_pair(p); p = cdr(p))
90390 	{
90391 	  s7_pointer nz;
90392 	  last_slot = add_slot_at_end(sc, id, last_slot, car(p), car(z)); /* sets last_slot */
90393 	  nz = cdr(z);
90394 	  free_cell(sc, z);
90395 	  z = nz;
90396 	}
90397       sc->curlet = e;
90398       sc->z = sc->nil;
90399       if (is_pair(p))
90400 	s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, not_enough_arguments_string, sc->code, sc->args));
90401     }
90402   if (is_pair(z))  /* these checks are needed because multiple-values might evade earlier arg num checks */
90403     s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, too_many_arguments_string, sc->code, sc->args));
90404 
90405   f = closure_body(f);
90406   if (is_pair(cdr(f)))
90407     push_stack_no_args(sc, sc->begin_op, cdr(f));
90408   sc->code = car(f);
90409 }
90410 
90411 static bool op_safe_c_ap(s7_scheme *sc)
90412 {
90413   s7_pointer val, code;
90414   code = cdr(sc->code);
90415   val = cdr(code);
90416   if ((has_gx(val)) && (symbol_ctr(caar(val)) == 1))
90417     {
90418       val = fx_proc_unchecked(val)(sc, car(val));
90419       sc->value = val;
90420       set_car(sc->t2_1, fx_call(sc, code));
90421       set_car(sc->t2_2, val);
90422       sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90423       return(false);
90424     }
90425   check_stack_size(sc);
90426   sc->args = fx_call(sc, code);
90427   push_stack_direct(sc, (opcode_t)opt1_any(code));
90428   sc->code = car(val);
90429   return(true);
90430 }
90431 
90432 static bool op_safe_c_pa(s7_scheme *sc)
90433 {
90434   s7_pointer args;
90435   args = cdr(sc->code);
90436   if ((has_gx(args)) && (symbol_ctr(caar(args)) == 1))
90437     {
90438       s7_pointer val;
90439       val = fx_proc_unchecked(args)(sc, car(args));
90440       sc->value = val;
90441       set_car(sc->t2_2, fx_call(sc, cdr(args)));
90442       set_car(sc->t2_1, val);
90443       sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90444       return(false);
90445     }
90446   check_stack_size(sc);
90447   push_stack(sc, OP_SAFE_C_PA_1, sc->nil, sc->code);
90448   sc->code = car(args);
90449   return(true);
90450 }
90451 
90452 static void op_safe_c_pa_1(s7_scheme *sc)
90453 {
90454   s7_pointer val;
90455   val = sc->value;
90456   set_car(sc->t2_2, fx_call(sc, cddr(sc->code)));
90457   set_car(sc->t2_1, val);
90458   sc->value = fn_proc(sc->code)(sc, sc->t2_1);
90459 }
90460 
90461 static void op_safe_c_pa_mv(s7_scheme *sc)
90462 {
90463   s7_pointer val;
90464   val = sc->value; /* this is necessary since the fx_proc below can clobber sc->value */
90465   sc->args = pair_append(sc, val, list_1(sc, fx_call(sc, cddr(sc->code)))); /* not plist here!  pair_append does not copy it */
90466   sc->code = c_function_base(opt1_cfunc(sc->code));
90467 }
90468 
90469 static void op_safe_c_opsq_p(s7_scheme *sc)
90470 {
90471   s7_pointer args;
90472   args = cadr(sc->code);
90473   check_stack_size(sc);
90474   set_car(sc->t1_1, lookup(sc, cadr(args)));
90475   sc->args = fn_proc(args)(sc, sc->t1_1);
90476   push_stack_direct(sc, (opcode_t)opt1_any(cdr(sc->code)));
90477   sc->code = caddr(sc->code);
90478 }
90479 
90480 static void op_c_all_a(s7_scheme *sc)
90481 { /* (set-cdr! lst ()) */
90482   s7_pointer args, p, new_args;
90483   new_args = make_list(sc, integer(opt3_arglen(cdr(sc->code))), sc->nil);
90484   sc->args = new_args;
90485   for (args = cdr(sc->code), p = new_args; is_pair(args); args = cdr(args), p = cdr(p))
90486     set_car(p, fx_call(sc, args));
90487   sc->value = fn_proc(sc->code)(sc, new_args);
90488 }
90489 
90490 static void op_c_p_mv(s7_scheme *sc) /* op_c_p_1 -> mv case: (define (hi) (format (values #f "~A ~D" 1 2))) */
90491 {
90492   sc->code = c_function_base(opt1_cfunc(sc->code)); /* see comment above */
90493   sc->args = copy_proper_list(sc, sc->value);
90494 }
90495 
90496 static void op_c_a(s7_scheme *sc)
90497 {
90498   sc->args = list_1(sc, fx_call(sc, cdr(sc->code)));
90499   sc->value = fn_proc(sc->code)(sc, sc->args);
90500 }
90501 
90502 static void op_c_p(s7_scheme *sc)
90503 {
90504   push_stack_no_args_direct(sc, OP_C_P_1);
90505   sc->code = T_Pair(cadr(sc->code));
90506 }
90507 
90508 static inline void op_c_ss(s7_scheme *sc)
90509 {
90510   sc->args = list_2(sc, lookup(sc, cadr(sc->code)), lookup(sc, caddr(sc->code)));
90511   sc->value = fn_proc(sc->code)(sc, sc->args);
90512 }
90513 
90514 static void op_c_ap(s7_scheme *sc)
90515 {
90516   sc->args = fx_call(sc, cdr(sc->code));
90517   push_stack_direct(sc, OP_C_AP_1); /* op_c_ap_1 sends us to apply which calls check_stack_size I think */
90518   sc->code = caddr(sc->code);
90519 }
90520 
90521 static void op_c_ap_mv(s7_scheme *sc)
90522 {
90523   clear_multiple_value(sc->value);
90524   sc->args = cons(sc, sc->args, sc->value);
90525   sc->code = c_function_base(opt1_cfunc(sc->code));
90526 }
90527 
90528 static void op_c_aa(s7_scheme *sc)
90529 {
90530   s7_pointer code;
90531   code = sc->code;
90532   sc->code = fx_call(sc, cdr(code));
90533   sc->value = fx_call(sc, cddr(code));
90534   sc->args = list_2(sc, sc->code, sc->value);
90535   sc->value = fn_proc(code)(sc, sc->args);
90536 }
90537 
90538 static inline void op_c_s(s7_scheme *sc)
90539 {
90540   sc->args = list_1(sc, lookup(sc, cadr(sc->code)));
90541   sc->value = fn_proc(sc->code)(sc, sc->args);
90542 }
90543 
90544 static Inline void op_apply_ss(s7_scheme *sc)
90545 {
90546   /* these used to check sc->code (i.e. "apply") if not h_optimized, but that still assumed we'd apply cadr to cddr.
90547    *   should we check that apply has not been set!?
90548    */
90549   sc->args = lookup(sc, opt2_sym(sc->code));  /* is this right if code=macro? */
90550   sc->code = lookup(sc, cadr(sc->code));      /* global search here was slower (e.g. tauto) */
90551   if (needs_copied_args(sc->code))
90552     sc->args = copy_proper_list_with_arglist_error(sc, sc->args);
90553   else
90554     if (!s7_is_proper_list(sc, sc->args))     /* (apply + #f) etc */
90555       apply_list_error(sc, sc->args);
90556 }
90557 
90558 static void op_apply_sa(s7_scheme *sc)
90559 {
90560   s7_pointer p;
90561   p = cdr(sc->code);
90562   sc->args = fx_call(sc, cdr(p));
90563   sc->code = lookup_global(sc, car(p));
90564   if (needs_copied_args(sc->code))
90565     sc->args = copy_proper_list_with_arglist_error(sc, sc->args);
90566   else
90567     if (!s7_is_proper_list(sc, sc->args))     /* (apply + #f) etc */
90568       apply_list_error(sc, sc->args);
90569 }
90570 
90571 static void op_apply_sl(s7_scheme *sc)
90572 {
90573   s7_pointer p;
90574   p = cdr(sc->code);
90575   sc->args = fx_call(sc, cdr(p));
90576   sc->code = lookup_global(sc, car(p));
90577 }
90578 
90579 static void op_eval_args2(s7_scheme *sc)
90580 {
90581   sc->code = pop_op_stack(sc);
90582   sc->args = (is_null(sc->args)) ? list_1(sc, sc->value) : proper_list_reverse_in_place(sc, cons(sc, sc->value, sc->args));
90583 }
90584 
90585 static void op_eval_args3(s7_scheme *sc)
90586 {
90587   s7_pointer val;
90588   val = sc->code;
90589   if (is_symbol(val))
90590     val = lookup_checked(sc, val);
90591   sc->args = proper_list_reverse_in_place(sc, cons_unchecked(sc, val, cons(sc, sc->value, sc->args)));
90592   sc->code = pop_op_stack(sc);
90593 }
90594 
90595 static void op_eval_args5(s7_scheme *sc)      /* sc->value is the last arg, sc->code is the previous */
90596 {
90597   sc->args = proper_list_reverse_in_place(sc, cons_unchecked(sc, sc->value, cons(sc, sc->code, sc->args)));
90598   sc->code = pop_op_stack(sc);
90599 }
90600 
90601 static bool eval_args_no_eval_args(s7_scheme *sc)
90602 {
90603   if ((is_any_macro(sc->value)) /* || (is_syntactic(sc->value))*/)
90604     {
90605       sc->args = copy_proper_list_with_arglist_error(sc, cdr(sc->code)); /* check the first time around */
90606       if (is_symbol(car(sc->code))) /* not ((f p) args...) where (f p) has returned a macro, op_macro_d assumes car is a symbol */
90607 	{
90608 	  if (is_macro(sc->value))
90609 	    set_optimize_op(sc->code, OP_MACRO_D);
90610 	  if (is_macro_star(sc->value))
90611 	    set_optimize_op(sc->code, OP_MACRO_STAR_D);
90612 	}
90613       sc->code = sc->value;
90614       return(true);
90615     }
90616   /* (define progn begin) (progn (display "hi") (+ 1 23)) */
90617   if (is_syntactic_pair(sc->code))
90618     sc->cur_op = optimize_op(sc->code);
90619   else
90620     {
90621       sc->cur_op = syntax_opcode(sc->value);
90622       pair_set_syntax_op(sc->code, sc->cur_op);
90623     }
90624   return(false);
90625 }
90626 
90627 static void op_read_internal(s7_scheme *sc)
90628 {
90629   /* if we're loading a file, and in the file we evaluate something like:
90630    *    (let ()
90631    *      (set-current-input-port (open-input-file "tmp2.r5rs"))
90632    *      (close-input-port (current-input-port)))
90633    *    ... (with no reset of input port to its original value)
90634    * the load process tries to read the loaded string, but the current-input-port is now closed,
90635    * and the original is inaccessible!  So we get a segfault in token.  We don't want to put
90636    * a port_is_closed check there because token only rarely is in this danger.  I think this
90637    * is the only place where we can be about to call token, and someone has screwed up our port.
90638    */
90639 
90640   if (port_is_closed(current_input_port(sc)))
90641     s7_error(sc, sc->read_error_symbol, /* not read_error here because it paws through the port string which doesn't exist here */
90642 	     set_elist_1(sc, wrap_string(sc, "our input port got clobbered!", 29)));
90643 
90644   sc->tok = token(sc);
90645   switch (sc->tok)
90646     {
90647     case TOKEN_EOF:         break;
90648     case TOKEN_RIGHT_PAREN: read_error(sc, "unexpected close paren");
90649     case TOKEN_COMMA:       read_error(sc, "unexpected comma");
90650     default:
90651       sc->value = read_expression(sc);
90652       sc->current_line = port_line_number(current_input_port(sc));  /* this info is used to track down missing close parens */
90653       sc->current_file = port_filename(current_input_port(sc));
90654       break;
90655     }
90656 }
90657 
90658 static void op_read_done(s7_scheme *sc)
90659 {
90660   pop_input_port(sc);
90661   if (sc->tok == TOKEN_EOF)
90662     sc->value = eof_object;
90663   sc->current_file = NULL; /* this is for error handling */
90664 }
90665 
90666 static bool op_read_quasiquote(s7_scheme *sc)
90667 {
90668   /* this was pushed when the backquote was seen, then eventually we popped back to it */
90669   sc->value = g_quasiquote_1(sc, sc->value, false);
90670   /* doing quasiquote at read time means there are minor inconsistencies in various combinations or quote/' and quasiquote/`.
90671    *   A quoted ` will expand but quoted quasiquote will not (` can't be redefined, but quasiquote can).  see s7test.scm for examples.
90672    */
90673   return(main_stack_op(sc) != OP_READ_LIST);
90674 }
90675 
90676 static bool pop_read_list(s7_scheme *sc)
90677 {
90678   /* push-stack OP_READ_LIST is always no_code and op is always OP_READ_LIST (and not used), sc->curlet is apparently not needed here */
90679   sc->stack_end -= 4;
90680   sc->args = sc->stack_end[2];
90681   if (is_null(sc->args))
90682     {
90683       sc->args = cons(sc, sc->value, sc->args);
90684       pair_set_current_input_location(sc, sc->args);
90685       return(true);
90686     }
90687   return(false);
90688 }
90689 
90690 static bool op_load_return_if_eof(s7_scheme *sc)
90691 {
90692   /* loop here until eof (via push stack below) */
90693   /* load("file"); from C (g_load) -- assume caller will clean up
90694    *   read and evaluate exprs until EOF that matches (stack reflects nesting)
90695    */
90696   if (sc->tok != TOKEN_EOF)
90697     {
90698       push_stack_op_let(sc, OP_LOAD_RETURN_IF_EOF);
90699       push_stack_op_let(sc, OP_READ_INTERNAL);
90700       sc->code = sc->value;
90701       return(true);             /* we read an expression, now evaluate it, and return to read the next */
90702     }
90703   sc->current_file = NULL;
90704   return(false);
90705 }
90706 
90707 static bool op_load_close_and_pop_if_eof(s7_scheme *sc)
90708 {
90709   /* (load "file") in scheme
90710    *    read and evaluate all exprs, then upon EOF, close current and pop input port stack
90711    */
90712   if (sc->tok != TOKEN_EOF)
90713     {
90714       push_stack_op_let(sc, OP_LOAD_CLOSE_AND_POP_IF_EOF); /* was push args, code */
90715       if ((!is_string_port(current_input_port(sc))) ||
90716 	  (port_position(current_input_port(sc)) < port_data_size(current_input_port(sc))))
90717 	push_stack_op_let(sc, OP_READ_INTERNAL);
90718       else sc->tok = TOKEN_EOF;
90719       sc->code = sc->value;
90720       return(true);             /* we read an expression, now evaluate it, and return to read the next */
90721     }
90722 #if S7_DEBUGGING
90723   if (!is_loader_port(current_input_port(sc)))
90724     fprintf(stderr, "%s not loading?\n", display(current_input_port(sc)));
90725   /* if *#readers* func hits error, clear_loader_port might not be undone? */
90726 #endif
90727   s7_close_input_port(sc, current_input_port(sc));
90728   pop_input_port(sc);
90729   sc->current_file = NULL;
90730   if (is_multiple_value(sc->value))                    /* (load "file") where "file" is (values 1 2 3) */
90731     sc->value = splice_in_values(sc, multiple_value(sc->value));
90732   return(false);
90733 }
90734 
90735 static bool op_read_apply_values(s7_scheme *sc)
90736 {
90737   sc->value = list_2(sc, sc->unquote_symbol, list_2(sc, sc->apply_values_symbol, sc->value));
90738   return(main_stack_op(sc) != OP_READ_LIST);
90739 }
90740 
90741 static goto_t op_read_dot(s7_scheme *sc)
90742 {
90743   token_t c;
90744   c = token(sc);
90745   if (c != TOKEN_RIGHT_PAREN) /* '(1 . (2) 3) -> '(1 2 3), Guile says "missing close paren" */
90746     {
90747       if (is_pair(sc->value))
90748 	{
90749 	  s7_pointer p;
90750 	  for (p = sc->value; is_pair(p); p = cdr(p))
90751 	    sc->args = cons(sc, car(p), sc->args);
90752 	  sc->tok = c;
90753 	  return(goto_read_tok);
90754 	}
90755       back_up_stack(sc);
90756       read_error(sc, "stray dot?");            /* (+ 1 . 2 3) or (list . ) */
90757     }
90758   /* args = previously read stuff, value = thing just after the dot and before the ')':
90759    *   (list 1 2 . 3) -> value: 3, args: (2 1 list)
90760    *   '(1 . 2) ->       value: 2, args: (1)
90761    * but we also get here in a lambda arg list:
90762    *   (lambda (a b . c) #f) -> value: c, args: (b a)
90763    * so we have to leave any error checks until later, I guess
90764    *   -- in eval_args1, if we end with non-pair-not-nil then something is fishy
90765    */
90766   sc->value = reverse_in_place(sc, sc->value, sc->args);
90767   pair_set_dotted(sc->value);
90768   return((main_stack_op(sc) == OP_READ_LIST) ? goto_pop_read_list : goto_start);
90769 }
90770 
90771 static bool op_read_quote(s7_scheme *sc)
90772 {
90773   /* can't check for sc->value = sc->nil here because we want ''() to be different from '() */
90774   if ((sc->safety > IMMUTABLE_VECTOR_SAFETY) &&
90775       ((is_pair(sc->value)) || (is_any_vector(sc->value)) || (is_string(sc->value))))
90776     set_immutable(sc->value);
90777   sc->value = list_2(sc, sc->quote_symbol, sc->value);
90778   return(main_stack_op(sc) != OP_READ_LIST);
90779 }
90780 
90781 static bool op_read_unquote(s7_scheme *sc)
90782 {
90783   /* here if sc->value is a constant, the unquote is pointless (should we complain?)
90784    *   also currently stray "," can be ignored: (abs , 1) -- scanning the stack for quasiquote or quote seems to be unreliable
90785    */
90786   if ((is_pair(sc->value)) ||
90787       (is_symbol(sc->value)))
90788     sc->value = list_2(sc, sc->unquote_symbol, sc->value);
90789   return(main_stack_op(sc) != OP_READ_LIST);
90790 }
90791 
90792 /* safety check is at read time, so (immutable? (let-temporarily (((*s7* 'safety) 2)) #(1 2 3))) is #f
90793  *    but (immutable? (let-temporarily (((*s7* 'safety) 2)) (eval-string "#(1 2 3)"))) is #t
90794  *    at run time we just see the vector
90795  */
90796 static bool op_read_vector(s7_scheme *sc)
90797 {
90798   if (is_dotted_pair(sc->value))            /* #(1 . 2) */
90799     read_error(sc, "vector constant data is not a proper list");
90800   sc->v = sc->value;
90801   sc->value = (sc->args == int_one) ? g_vector(sc, sc->value) : g_multivector(sc, integer(sc->args), sc->value); /* sc->args was sc->w earlier from read_sharp */
90802   /* here and below all of the sc->value list can be freed, but my tests showed no speed up even in large cases */
90803   if (sc->safety > IMMUTABLE_VECTOR_SAFETY) set_immutable(sc->value);
90804   return(main_stack_op(sc) != OP_READ_LIST);
90805 }
90806 
90807 static bool op_read_int_vector(s7_scheme *sc)
90808 {
90809   if (is_dotted_pair(sc->value))
90810     read_error(sc, "int-vector constant data is not a proper list");
90811   sc->v = sc->value;
90812   sc->value = (sc->args == int_one) ? g_int_vector(sc, sc->value) : g_int_multivector(sc, integer(sc->args), sc->value);
90813   if (sc->safety > IMMUTABLE_VECTOR_SAFETY) set_immutable(sc->value);
90814   return(main_stack_op(sc) != OP_READ_LIST);
90815 }
90816 
90817 static bool op_read_float_vector(s7_scheme *sc)
90818 {
90819   if (is_dotted_pair(sc->value))
90820     read_error(sc, "float-vector constant data is not a proper list");
90821   sc->v = sc->value;
90822   sc->value = (sc->args == int_one) ? g_float_vector(sc, sc->value) : g_float_multivector(sc, integer(sc->args), sc->value);
90823   if (sc->safety > IMMUTABLE_VECTOR_SAFETY) set_immutable(sc->value);
90824   return(main_stack_op(sc) != OP_READ_LIST);
90825 }
90826 
90827 static bool op_read_byte_vector(s7_scheme *sc)
90828 {
90829   if (is_dotted_pair(sc->value))
90830     read_error(sc, "byte-vector constant data is not a proper list");
90831   sc->v = sc->value;
90832   sc->value = (sc->args == int_one) ? g_byte_vector(sc, sc->value) : g_byte_multivector(sc, integer(sc->args), sc->value);
90833   if (sc->safety > IMMUTABLE_VECTOR_SAFETY) set_immutable(sc->value);
90834   return(main_stack_op(sc) != OP_READ_LIST);
90835 }
90836 
90837 
90838 static inline void eval_last_arg(s7_scheme *sc, s7_pointer car_code)
90839 {
90840   /* here we've reached the last arg (sc->code == nil), it is not a pair */
90841   if (!is_null(cdr(sc->code)))
90842     improper_arglist_error(sc);
90843   sc->code = (is_symbol(car_code)) ? lookup_checked(sc, car_code) : car_code; /* this has to precede the set_type below */
90844   sc->args = (is_null(sc->args)) ? list_1(sc, sc->code) : proper_list_reverse_in_place(sc, cons(sc, sc->code, sc->args));
90845   sc->code = pop_op_stack(sc);
90846 }
90847 
90848 static inline void eval_args_pair_car(s7_scheme *sc)
90849 {
90850   s7_pointer code;
90851   if (sc->stack_end >= sc->stack_resize_trigger)
90852     check_for_cyclic_code(sc, sc->code);
90853 
90854   code = cdr(sc->code);
90855   /* all 3 of these push_stacks can result in stack overflow, see above 64065 */
90856   if (is_null(code))
90857     push_stack_no_code(sc, OP_EVAL_ARGS2, sc->args);
90858   else
90859     {
90860       if (!is_pair(code))            /* (= 0 '(1 . 2) . 3) */
90861 	improper_arglist_error(sc);
90862 
90863       if ((is_null(cdr(code))) &&
90864 	  (!is_pair(car(code))))
90865 	push_stack(sc, OP_EVAL_ARGS3, sc->args, car(code));
90866       else push_stack(sc, OP_EVAL_ARGS4, sc->args, code);
90867     }
90868   sc->code = car(sc->code);
90869 }
90870 
90871 static bool eval_car_pair(s7_scheme *sc)
90872 {
90873   s7_pointer code, carc;
90874   code = sc->code;
90875   carc = car(code);
90876 
90877   /* evaluate the inner list but that list can be circular: carc: #1=(#1# #1#)!
90878    *   and the cycle can be well-hidden -- #1=((#1 2) . 2) and other such stuff
90879    */
90880   if (sc->stack_end >= sc->stack_resize_trigger)
90881     check_for_cyclic_code(sc, code);
90882   push_stack(sc, OP_EVAL_ARGS, sc->nil, code);
90883 
90884   if (is_syntactic_symbol(car(carc)))
90885     /* was checking for is_syntactic here but that can be confused by successive optimizer passes: (define (hi) (((lambda () list)) 1 2 3)) etc */
90886     {
90887       if ((car(carc) == sc->quote_symbol) &&        /* ('and #f) */
90888 	  ((!is_pair(cdr(carc))) ||                 /* ((quote . #\h) (2 . #\i)) ! */
90889 	   (is_syntactic(cadr(carc)))))
90890 	apply_error(sc, (is_pair(cdr(carc))) ? cadr(carc) : carc, cdr(code));
90891       sc->code = carc;
90892 
90893       /* an experiment (to replace op_if_a_ssq_a[_a]) */
90894       if (!no_cell_opt(carc))
90895 	{
90896 	  if ((car(carc) == sc->if_symbol) &&
90897 	      (is_pair(cdr(code))) &&       /* check that we got one or two args */
90898 	      ((is_null(cddr(code))) ||
90899 	       ((is_pair(cddr(code))) && (is_null(cdddr(code))))))
90900 	    {
90901 	      check_if(sc, carc);
90902 	      if ((fx_function[optimize_op(carc)]) &&
90903 		  (is_fxable(sc, cadr(code))) &&
90904 		  ((is_null(cddr(code))) || (is_fxable(sc, caddr(code))))) /* checked cdddr above */
90905 		{
90906 		  fx_annotate_args(sc, cdr(code), sc->curlet);
90907 		  set_fx_direct(code, fx_function[optimize_op(carc)]);
90908 		  set_optimize_op(code, (is_null(cddr(code))) ? OP_A_A : OP_A_AA);
90909 		  return(false);  /* goto eval in trailers */
90910 		}}
90911 	  set_no_cell_opt(carc);
90912 	}
90913 
90914       sc->cur_op = (opcode_t)symbol_syntax_op_checked(sc->code);
90915       pair_set_syntax_op(sc->code, sc->cur_op);
90916       return(true);
90917     }
90918 
90919   if ((is_pair(cdr(code))) && (is_optimized(carc)))
90920     {
90921       if ((fx_function[optimize_op(carc)]) &&
90922 	  (is_fxable(sc, cadr(code))) &&
90923 	  ((is_null(cddr(code))) ||
90924 	   ((is_fxable(sc, caddr(code))) && (is_null(cdddr(code))))))
90925 	{
90926 	  fx_annotate_args(sc, cdr(code), sc->curlet);
90927 	  set_fx_direct(code, fx_function[optimize_op(carc)]);
90928 	  set_optimize_op(code, (is_null(cddr(code))) ? OP_A_A : OP_A_AA);
90929 	  sc->code = carc;
90930 	  return(false);  /* goto eval in trailers */
90931 	}
90932       if ((is_null(cddr(code))) && (is_symbol(cadr(code))))
90933 	{
90934 	  set_optimize_op(code, OP_P_S);
90935 	  set_opt3_sym(code, cadr(code));
90936 	}
90937       /* OP_P_ALL_A runs into opt2 fx overwrites in a case like ((values set!) x 32) */
90938       else set_optimize_op(code, OP_PAIR_PAIR);
90939     }
90940   else set_optimize_op(code, OP_PAIR_PAIR);
90941 
90942   push_stack(sc, OP_EVAL_ARGS, sc->nil, carc);
90943   sc->code = car(carc);
90944   return(false);
90945 }
90946 
90947 static inline bool eval_args_last_arg(s7_scheme *sc)
90948 {
90949   s7_pointer car_code;
90950   /* we're at the last arg, sc->value is the previous one, not yet saved in the args list */
90951   car_code = car(sc->code);
90952   if (is_pair(car_code))
90953     {
90954       if (sc->stack_end >= sc->stack_resize_trigger)
90955 	check_for_cyclic_code(sc, sc->code);
90956       push_stack(sc, OP_EVAL_ARGS5, sc->args, sc->value);
90957       sc->code = car_code;
90958       return(true);
90959     }
90960 
90961   /* get the last arg */
90962   sc->code = (is_symbol(car_code)) ? lookup_checked(sc, car_code) : car_code;
90963 
90964   /* get the current arg, which is not a list */
90965   sc->args = proper_list_reverse_in_place(sc, cons_unchecked(sc, sc->code, cons(sc, sc->value, sc->args)));
90966   sc->code = pop_op_stack(sc);
90967   return(false);
90968 }
90969 
90970 static void op_pair_pair(s7_scheme *sc)
90971 {
90972   if (sc->stack_end >= sc->stack_resize_trigger)
90973     {
90974       check_for_cyclic_code(sc, sc->code);
90975       resize_stack(sc);
90976     }
90977   push_stack(sc, OP_EVAL_ARGS, sc->nil, sc->code); /* eval args goes immediately to cdr(sc->code) */
90978   /* don't put check_stack_size here! */
90979   push_stack(sc, OP_EVAL_ARGS, sc->nil, car(sc->code));
90980   sc->code = caar(sc->code);
90981 }
90982 
90983 static goto_t trailers(s7_scheme *sc)
90984 {
90985   s7_pointer code;
90986   code = sc->code;
90987 
90988   if (is_pair(code))
90989     {
90990       s7_pointer carc;
90991       carc = car(code);
90992       if (is_symbol(carc))
90993 	{
90994 	  /* car is a symbol, sc->code a list */
90995 	  if (is_syntactic_symbol(carc))
90996 	    {
90997 	      sc->cur_op = (opcode_t)symbol_syntax_op_checked(code);
90998 	      pair_set_syntax_op(sc->code, sc->cur_op);
90999 	      return(goto_top_no_pop);
91000 	    }
91001 	  sc->value = lookup_global(sc, carc);
91002 	  set_optimize_op(code, OP_PAIR_SYM);	  /* mostly stuff outside functions (unopt) */
91003 	  return(goto_eval_args_top);
91004 	}
91005 
91006       if (is_pair(carc))                          /* ((if x y z) a b) etc */
91007 	return((eval_car_pair(sc)) ? goto_top_no_pop : goto_eval);
91008 
91009       /* here we can get syntax objects like quote */
91010       if (is_syntax(carc))
91011 	{
91012 	  sc->cur_op = (opcode_t)syntax_opcode(carc);
91013 	  pair_set_syntax_op(sc->code, sc->cur_op);
91014 	  return(goto_top_no_pop);
91015 	}
91016       /* car must be the function to be applied, or (for example) a syntax variable like quote that has been used locally */
91017       set_optimize_op(code, OP_PAIR_ANY);        /* usually an error: (#\a) etc, might be (#(0) 0) */
91018       sc->value = T_Pos(carc);
91019       return(goto_eval_args_top);
91020     }
91021 
91022   if (is_symbol(code))
91023     {
91024       sc->value = lookup_checked(sc, code);
91025       set_optimize_op(code, (is_keyword(code)) ? OP_CON : ((is_global(code)) ? OP_GLOBAL_SYM : OP_SYM));
91026     }
91027   else
91028     {
91029       sc->value = T_Pos(code);
91030       set_optimize_op(code, OP_CON);
91031     }
91032   return(goto_start);
91033 }
91034 
91035 static Inline void op_map_gather(s7_scheme *sc)
91036 {
91037   if (sc->value != sc->no_value)
91038     {
91039       if (is_multiple_value(sc->value))
91040 	counter_set_result(sc->args, revappend(sc, multiple_value(sc->value), counter_result(sc->args)));
91041       else counter_set_result(sc->args, cons(sc, sc->value, counter_result(sc->args)));
91042     }
91043 }
91044 
91045 
91046 /* ---------------- unknown ops ---------------- */
91047 static bool fixup_unknown_op(s7_pointer code, s7_pointer func, opcode_t op)
91048 {
91049   set_optimize_op(code, op);
91050   if (is_any_closure(func))
91051     set_opt1_lambda(code, func);
91052   return(true);
91053 }
91054 
91055 static bool unknown_unknown(s7_scheme *sc, s7_pointer code, opcode_t op)
91056 {
91057   if ((is_symbol(car(code))) &&
91058       (!is_slot(lookup_slot_from(car(code), sc->curlet))))
91059     unbound_variable_error(sc, car(code));
91060   set_optimize_op(code, op);
91061   return(true);
91062 }
91063 
91064 static bool is_immutable_and_stable(s7_scheme *sc, s7_pointer func)
91065 {
91066   s7_pointer p;
91067   if (symbol_ctr(func) != 1) /* protect against (define-constant (p) (define-constant (p) ...)) */
91068     return(false);
91069   if ((is_global(func)) && (is_immutable_slot(global_slot(func))))
91070     return(true);
91071   for (p = sc->curlet; is_let(p); p = let_outlet(p))
91072     if ((is_funclet(p)) && (funclet_function(p) != func))
91073       return(false);
91074   p = lookup_slot_from(func, sc->curlet);
91075   return(is_immutable_slot(p));
91076 }
91077 
91078 static bool op_unknown(s7_scheme *sc)
91079 {
91080   s7_pointer code, f;
91081   f = sc->last_function;
91082   if (!f) /* can be NULL if unbound variable */
91083     unbound_variable_error(sc, car(sc->code));
91084   /* perhaps set op to OP_CLEAR_OPTS and return(true) above */
91085 
91086 #if SHOW_EVAL_OPS
91087   fprintf(stderr, "%s %s %s\n", __func__, display(f), s7_type_names[type(f)]);
91088 #endif
91089 
91090   code = sc->code;
91091   switch (type(f))
91092     {
91093     case T_CLOSURE:
91094     case T_CLOSURE_STAR:
91095       if (!has_methods(f))
91096 	{
91097 	  int32_t hop = 0;
91098 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91099 
91100 	  if (is_null(closure_args(f)))
91101 	    {
91102 	      s7_pointer body;
91103 	      bool safe_case;
91104 	      body = closure_body(f);
91105 	      safe_case = is_safe_closure(f);
91106 	      set_opt1_lambda(code, f);
91107 
91108 	      if (is_null(cdr(body)))
91109 		{
91110 		  if ((safe_case) && (is_fxable(sc, car(body))))
91111 		    {
91112 		      set_safe_closure(f);   /* safe because no args so no reference to funclet? needed because op_safe_thunk_a will check for it */
91113 		      fx_annotate_arg(sc, body, sc->curlet);
91114 		      set_safe_optimize_op(code, hop + OP_SAFE_THUNK_A);
91115 		      set_closure_one_form_fx_arg(f);
91116 		      sc->value = fx_safe_thunk_a(sc, sc->code);
91117 		      return(false);
91118 		    }
91119 		  clear_has_fx(code);
91120 		}
91121 	      set_safe_optimize_op(code, hop + ((safe_case) ? OP_SAFE_THUNK : OP_THUNK));
91122 	      return(true);
91123 	    }
91124 	  if (is_closure_star(f))
91125 	    {
91126 	      set_safe_optimize_op(code, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_STAR_ALL_A_0 : OP_CLOSURE_STAR_ALL_A));
91127 	      set_opt1_lambda(code, f);
91128 	      return(true);
91129 	    }}
91130       break;
91131 
91132     case T_GOTO:       return(fixup_unknown_op(code, f, OP_IMPLICIT_GOTO));
91133     case T_ITERATOR:   return(fixup_unknown_op(code, f, OP_IMPLICIT_ITERATE));
91134     case T_MACRO:      return(fixup_unknown_op(code, f, OP_MACRO_D));
91135     case T_MACRO_STAR: return(fixup_unknown_op(code, f, OP_MACRO_STAR_D));
91136 
91137     default:
91138       if ((is_symbol(car(code))) &&
91139 	  (!is_slot(lookup_slot_from(car(code), sc->curlet))))
91140 	unbound_variable_error(sc, car(code));
91141     }
91142   return(fixup_unknown_op(code, f, OP_S));
91143 }
91144 
91145 static bool fxify_closure_star_g(s7_scheme *sc, s7_pointer f, s7_pointer code)
91146 {
91147   if ((!has_methods(f)) &&
91148       (closure_star_arity_to_int(sc, f) != 0))
91149     {
91150       int32_t hop = 0;
91151       bool safe_case;
91152       if (is_immutable_and_stable(sc, car(code))) hop = 1;
91153 
91154       fx_annotate_arg(sc, cdr(code), sc->curlet);
91155       set_opt3_arglen(cdr(code), int_one);
91156       safe_case = is_safe_closure(f);
91157 
91158       if ((safe_case) && (is_null(cdr(closure_args(f)))))
91159 	set_optimize_op(code, hop + OP_SAFE_CLOSURE_STAR_A1);
91160       else
91161 	if (lambda_has_simple_defaults(f))
91162 	  {
91163 	    if (arglist_has_rest(sc, closure_args(f)))
91164 	      fixup_unknown_op(code, f, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_ALL_A_1 : OP_CLOSURE_STAR_ALL_A));
91165 	    else fixup_unknown_op(code, f, hop + ((safe_case) ?
91166 						  ((is_null(cdr(closure_args(f)))) ? OP_SAFE_CLOSURE_STAR_A1 : OP_SAFE_CLOSURE_STAR_A) : OP_CLOSURE_STAR_A));
91167 	    return(true);
91168 	  }
91169       fixup_unknown_op(code, f, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_ALL_A_1 : OP_CLOSURE_STAR_ALL_A));
91170       return(true);
91171     }
91172   return(false);
91173 }
91174 
91175 static bool op_unknown_g(s7_scheme *sc)
91176 {
91177   s7_pointer code, f;
91178   bool sym_case;
91179   f = sc->last_function;
91180   if (!f) unbound_variable_error(sc, car(sc->code));
91181 
91182 #if SHOW_EVAL_OPS
91183   fprintf(stderr, "%s %s\n", __func__, display(f));
91184 #endif
91185 
91186   code = sc->code;
91187 #if S7_DEBUGGING
91188   if (is_pair(cadr(code))) fprintf(stderr, "%s[%d]: arg is a pair: %s\n", __func__, __LINE__, display(code));
91189 #endif
91190   sym_case = is_normal_symbol(cadr(code));
91191 
91192   if ((sym_case) &&
91193       (!is_any_macro(f)) &&   /* if f is a macro, its argument can be unbound legitimately */
91194       (!is_slot(lookup_slot_from(cadr(code), sc->curlet))))
91195     return(unknown_unknown(sc, sc->code, (is_normal_symbol(cadr(sc->code))) ? OP_CLEAR_OPTS : OP_S_C)); /* not OP_S_S here! */
91196 
91197   if ((is_unknopt(code)) && (!is_closure(f)))
91198     return(fixup_unknown_op(code, f, (sym_case) ? OP_S_S : OP_S_C));
91199 
91200   switch (type(f))
91201     {
91202     case T_C_FUNCTION:
91203     case T_C_RST_ARGS_FUNCTION:
91204       if ((c_function_required_args(f) > 1) ||
91205 	  (c_function_all_args(f) == 0))
91206 	break;
91207 
91208     case T_C_OPT_ARGS_FUNCTION:
91209     case T_C_ANY_ARGS_FUNCTION:
91210       if (sym_case)
91211 	{
91212 	  set_c_function(code, f);
91213 	  if (is_safe_procedure(f))
91214 	    {
91215 	      set_optimize_op(code, OP_SAFE_C_S);
91216 	      sc->value = fx_c_s(sc, sc->code);
91217 	    }
91218 	  else
91219 	    {
91220 	      set_optimize_op(code, OP_C_S);
91221 	      op_c_s(sc);
91222 	    }
91223 	  return(false);
91224 	}
91225       if (is_safe_procedure(f))
91226 	{
91227 	  set_optimize_op(code, OP_SAFE_C_D);
91228 	  set_c_function(code, f);
91229 	  return(true);
91230 	}
91231       break;
91232 
91233     case T_CLOSURE:
91234       if ((!has_methods(f)) &&
91235 	  (closure_arity_to_int(sc, f) == 1))
91236 	{
91237 	  s7_pointer body;
91238 	  int32_t hop = 0;
91239 
91240 	  body = closure_body(f);
91241 	  if (sym_case)
91242 	    set_opt2_sym(code, cadr(code));
91243 	  else set_opt2_con(code, cadr(code));
91244 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91245 
91246 	  /* code here might be (f x) where f is passed elsewhere as a function parameter,
91247 	   *   first time through we look it up, find a safe-closure and optimize as (say) safe_closure_s_a,
91248 	   *   next time it is something else, etc.  Rather than keep optimizing it locally, we need to
91249 	   *   back out: safe_closure_s_* -> safe_closure_s -> closure_s -> op_s_s.  Ideally we'd know
91250 	   *   this was a parameter or whatever.  The tricky case is local letrec(f) calling f which initially
91251 	   *   thinks it is not safe, then later is set safe correctly, now outer func is called again,
91252 	   *   this time f is safe, and we're ok from then on.
91253 	   */
91254 	  if (is_unknopt(code))
91255 	    {
91256 	      /* fprintf(stderr, "unknopt %s %s %s %s %p %d %s\n",
91257 		 op_names[optimize_op(car(body))], display(f), display(car(body)), display(code), code, is_safe_closure(f), describe_type_bits(sc, f));
91258 	      */
91259 	      switch (op_no_hop(code))
91260 		{
91261 		case OP_CLOSURE_S:              set_optimize_op(code, (is_safe_closure(f)) ? OP_SAFE_CLOSURE_S :  OP_S_S); break;
91262 		case OP_CLOSURE_S_O:
91263 		case OP_SAFE_CLOSURE_S:         set_optimize_op(code, OP_CLOSURE_S); break;
91264 		case OP_SAFE_CLOSURE_S_O:
91265 		case OP_SAFE_CLOSURE_S_A:
91266 		case OP_SAFE_CLOSURE_S_TO_S:
91267 		case OP_SAFE_CLOSURE_S_TO_SC:   set_optimize_op(code, (is_safe_closure(f)) ? OP_SAFE_CLOSURE_S : OP_CLOSURE_S); break;
91268 		case OP_CLOSURE_C:              set_optimize_op(code, (is_safe_procedure(f)) ? OP_SAFE_CLOSURE_C : OP_S_C); break;
91269 		case OP_CLOSURE_C_O:
91270 		case OP_SAFE_CLOSURE_C:         set_optimize_op(code, OP_CLOSURE_C); break;
91271 		case OP_SAFE_CLOSURE_C_O:       set_optimize_op(code, (is_safe_closure(f)) ? OP_SAFE_CLOSURE_C : OP_CLOSURE_C); break;
91272 		default:                        set_optimize_op(code, (sym_case) ? OP_S_S : OP_S_C); break;
91273 		}
91274 	      set_opt1_lambda(code, f);
91275 	      return(true);
91276 	    }
91277 	  if (is_safe_closure(f))
91278 	    {
91279 	      if (is_null(cdr(body)))
91280 		{
91281 		  if (is_fxable(sc, car(body)))
91282 		    fxify_closure_s(sc, f, code, sc->curlet, sym_case, hop);
91283 		  else set_safe_optimize_op(code, hop + ((sym_case) ? OP_SAFE_CLOSURE_S_O : OP_SAFE_CLOSURE_C_O));
91284 		  /* hop if is_constant(sc, car(code)) is not foolproof here (see t967.scm):
91285 		   *    (define (f) (define-constant (f1) ... (f1))...) where each call on f makes a different f1
91286 		   */
91287 		}
91288 	      else set_safe_optimize_op(code, hop + ((sym_case) ? OP_SAFE_CLOSURE_S : OP_SAFE_CLOSURE_C));
91289 	    }
91290 	  else
91291 	    {
91292 	      if (is_null(cdr(body)))
91293 		set_optimize_op(code, hop + ((sym_case) ? OP_CLOSURE_S_O : OP_CLOSURE_C_O));
91294 	      else set_optimize_op(code, hop + ((sym_case) ? OP_CLOSURE_S : OP_CLOSURE_C));
91295 	    }
91296 	  set_is_unknopt(code);
91297 	  set_opt1_lambda(code, f);
91298 	  return(true);
91299 	}
91300       break;
91301 
91302     case T_CLOSURE_STAR:
91303       if (fxify_closure_star_g(sc, f, code)) return(true);
91304       break;
91305 
91306     case T_GOTO:
91307       fx_annotate_arg(sc, cdr(code), sc->curlet);
91308       set_opt3_arglen(cdr(code), int_one);
91309       return(fixup_unknown_op(code, f, OP_IMPLICIT_GOTO_A));
91310 
91311     case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_VECTOR: case T_BYTE_VECTOR:
91312       if ((sym_case) ||                    /* (v i) */
91313 	  (is_t_integer(cadr(code))))      /* (v 4/3) */
91314 	{
91315 	  fx_annotate_arg(sc, cdr(code), sc->curlet);
91316 	  return(fixup_unknown_op(code, f, OP_IMPLICIT_VECTOR_REF_A));
91317 	}
91318       break;
91319 
91320     case T_STRING:
91321       fx_annotate_arg(sc, cdr(code), sc->curlet);
91322       return(fixup_unknown_op(code, f, OP_IMPLICIT_STRING_REF_A));
91323 
91324     case T_PAIR:
91325       fx_annotate_arg(sc, cdr(code), sc->curlet);
91326       return(fixup_unknown_op(code, f, OP_IMPLICIT_PAIR_REF_A));
91327 
91328     case T_C_OBJECT:
91329       if (s7_is_aritable(sc, f, 1))
91330 	{
91331 	  fx_annotate_arg(sc, cdr(code), sc->curlet);
91332 	  return(fixup_unknown_op(code, f, OP_IMPLICIT_C_OBJECT_REF_A));
91333 	}
91334       break;
91335 
91336     case T_LET:
91337       if (sym_case)
91338 	{
91339 	  fx_annotate_arg(sc, cdr(code), sc->curlet);
91340 	  return(fixup_unknown_op(code, f, OP_IMPLICIT_LET_REF_A));
91341 	}
91342       set_opt3_con(code, cadr(code));
91343       return(fixup_unknown_op(code, f, OP_IMPLICIT_LET_REF_C));
91344 
91345     case T_HASH_TABLE:
91346       fx_annotate_arg(sc, cdr(code), sc->curlet);
91347       return(fixup_unknown_op(code, f, OP_IMPLICIT_HASH_TABLE_REF_A));
91348 
91349     case T_CONTINUATION:
91350       fx_annotate_arg(sc, cdr(code), sc->curlet);
91351       return(fixup_unknown_op(code, f, OP_IMPLICIT_CONTINUATION_A));
91352 
91353     case T_MACRO:      return(fixup_unknown_op(code, f, OP_MACRO_D));
91354     case T_MACRO_STAR: return(fixup_unknown_op(code, f, OP_MACRO_STAR_D));
91355 
91356     default:
91357       break;
91358     }
91359   if ((is_symbol(car(code))) &&
91360       (!is_slot(lookup_slot_from(car(code), sc->curlet))))
91361     unbound_variable_error(sc, car(code));
91362 
91363   return(fixup_unknown_op(code, f, (sym_case) ? OP_S_S : OP_S_C));
91364 }
91365 
91366 static bool op_unknown_a(s7_scheme *sc)
91367 {
91368   s7_pointer code, f;
91369   f = sc->last_function;
91370   if (!f) unbound_variable_error(sc, car(sc->code));
91371 #if SHOW_EVAL_OPS
91372   fprintf(stderr, "%s %s\n", __func__, display(f));
91373 #endif
91374 
91375   code = sc->code;
91376   switch (type(f))
91377     {
91378     case T_C_FUNCTION:
91379     case T_C_RST_ARGS_FUNCTION:
91380       if ((c_function_required_args(f) > 1) ||
91381 	  (c_function_all_args(f) == 0))
91382 	break;
91383     case T_C_OPT_ARGS_FUNCTION:
91384     case T_C_ANY_ARGS_FUNCTION:
91385       clear_has_fx(code);
91386       set_c_function(code, f);
91387       if (is_safe_procedure(f))
91388 	{
91389 	  set_optimize_op(code, OP_SAFE_C_A);
91390 	  sc->value = fx_c_a(sc, code);
91391 	}
91392       else
91393 	{
91394 	  set_optimize_op(code, OP_C_A);
91395 	  op_c_a(sc);
91396 	}
91397       return(false);
91398 
91399     case T_CLOSURE:
91400       if ((!has_methods(f)) &&
91401 	  (closure_arity_to_int(sc, f) == 1))
91402 	{
91403 	  s7_pointer body;
91404 	  bool one_form, safe_case;
91405 	  int32_t hop = 0;
91406 
91407 	  body = closure_body(f);
91408 	  safe_case = is_safe_closure(f);
91409 	  one_form = is_null(cdr(body));
91410 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91411 	  fxify_closure_a(sc, f, one_form, safe_case, hop, code, sc->curlet);
91412 
91413 	  /* we might not be in "f" I think, tree_memq(sc, code, body)?? */
91414 	  if ((safe_case) &&
91415 	      (!has_fx(cdr(code))) &&
91416 	      (is_very_safe_closure(f)) &&
91417 	      (!tree_has_definers_or_binders(sc, body)) &&
91418 	      (s7_tree_memq(sc, code, body)))
91419 	    fx_tree(sc, cdr(code), car(closure_args(f)), NULL);
91420 
91421 	  set_opt1_lambda(code, f);
91422 	  return(true);
91423 	}
91424       break;
91425 
91426     case T_CLOSURE_STAR:
91427       if (fxify_closure_star_g(sc, f, code)) return(true);
91428       break;
91429 
91430     case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_VECTOR: case T_BYTE_VECTOR:
91431       return(fixup_unknown_op(code, f, OP_IMPLICIT_VECTOR_REF_A));
91432 
91433     case T_STRING:       return(fixup_unknown_op(code, f, OP_IMPLICIT_STRING_REF_A));
91434     case T_PAIR:         return(fixup_unknown_op(code, f, OP_IMPLICIT_PAIR_REF_A));
91435     case T_C_OBJECT:     return(fixup_unknown_op(code, f, OP_IMPLICIT_C_OBJECT_REF_A));
91436     case T_HASH_TABLE:   return(fixup_unknown_op(code, f, OP_IMPLICIT_HASH_TABLE_REF_A));
91437     case T_GOTO:         return(fixup_unknown_op(code, f, OP_IMPLICIT_GOTO_A));
91438     case T_CONTINUATION: return(fixup_unknown_op(code, f, OP_IMPLICIT_CONTINUATION_A));
91439     case T_MACRO:        return(fixup_unknown_op(code, f, OP_MACRO_D));
91440     case T_MACRO_STAR:   return(fixup_unknown_op(code, f, OP_MACRO_STAR_D));
91441 
91442     case T_LET:
91443       {
91444 	s7_pointer arg1;
91445 	arg1 = cadr(code);
91446 	if ((is_pair(arg1)) && (car(arg1) == sc->quote_symbol))
91447 	  {
91448 	    set_opt3_con(code, cadadr(code));
91449 	    return(fixup_unknown_op(code, f, OP_IMPLICIT_LET_REF_C));
91450 	  }
91451 	set_opt3_any(code, cadr(code));
91452 	return(fixup_unknown_op(code, f, OP_IMPLICIT_LET_REF_A));
91453       }
91454 
91455     default:
91456       break;
91457     }
91458   if ((is_symbol(car(code))) &&
91459       (!is_slot(lookup_slot_from(car(code), sc->curlet))))
91460     unbound_variable_error(sc, car(code));
91461 
91462   return(fixup_unknown_op(code, f, OP_S_A)); /* closure with methods etc */
91463 }
91464 
91465 static bool fixup_closure_star_aa(s7_scheme *sc, s7_pointer f, s7_pointer code)
91466 {
91467   if (!has_methods(f))
91468     {
91469       int32_t hop = 0;
91470       int32_t arity;
91471       bool safe_case;
91472       s7_pointer arg1, par1;
91473 
91474       safe_case = is_safe_closure(f);
91475       arity = closure_star_arity_to_int(sc, f);
91476       arg1 = cadr(code);
91477       par1 = car(closure_args(f));
91478       if (is_pair(par1)) par1 = car(par1);
91479 
91480       if (is_immutable_and_stable(sc, car(code))) hop = 1;
91481       set_opt3_arglen(cdr(code), int_two);
91482 
91483       if ((arity == 1) && (is_keyword(arg1)) && (keyword_symbol(arg1) == par1))
91484 	return(fixup_unknown_op(code, f, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_KA : OP_CLOSURE_STAR_KA)));
91485 
91486       if (lambda_has_simple_defaults(f))
91487 	{
91488 	  if (arity == 2)
91489 	    return(fixup_unknown_op(code, f, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_AA : OP_CLOSURE_STAR_ALL_A)));
91490 	  return(fixup_unknown_op(code, f, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_ALL_A_2 : OP_CLOSURE_STAR_ALL_A)));
91491 	}
91492       return(fixup_unknown_op(code, f, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_ALL_A_2 : OP_CLOSURE_STAR_ALL_A)));
91493     }
91494   return(fixup_unknown_op(code, f, OP_S_AA));
91495 }
91496 
91497 static bool op_unknown_gg(s7_scheme *sc)
91498 {
91499   bool s1, s2;
91500   s7_pointer code, f;
91501   f = sc->last_function;
91502   if (!f) unbound_variable_error(sc, car(sc->code));
91503 
91504 #if SHOW_EVAL_OPS
91505   fprintf(stderr, "%s %s\n", __func__, display(f));
91506 #endif
91507 
91508   code = sc->code;
91509 #if S7_DEBUGGING
91510   if ((is_pair(cadr(code))) || (is_pair(caddr(code)))) fprintf(stderr, "%s[%d]: arg is a pair: %s\n", __func__, __LINE__, display(code));
91511 #endif
91512   s1 = is_normal_symbol(cadr(code));
91513   s2 = is_normal_symbol(caddr(code));
91514 
91515   if ((s1) &&
91516       (!is_slot(lookup_slot_from(cadr(code), sc->curlet))))
91517     return(unknown_unknown(sc, sc->code, OP_CLEAR_OPTS));
91518 
91519   if ((s2) &&
91520       (!is_slot(lookup_slot_from(caddr(code), sc->curlet))))
91521     return(unknown_unknown(sc, sc->code, OP_CLEAR_OPTS));
91522 
91523   switch (type(f))
91524     {
91525     case T_C_FUNCTION:
91526     case T_C_RST_ARGS_FUNCTION:
91527       if ((c_function_required_args(f) > 2) ||
91528 	  (c_function_all_args(f) < 2))
91529 	break;
91530     case T_C_OPT_ARGS_FUNCTION:
91531     case T_C_ANY_ARGS_FUNCTION:
91532       if (is_safe_procedure(f))
91533 	{
91534 	  if (s1)
91535 	    {
91536 	      set_optimize_op(code, (s2) ? OP_SAFE_C_SS : OP_SAFE_C_SC);
91537 	      if (s2)
91538 		set_opt2_sym(cdr(code), caddr(code));
91539 	      else set_opt2_con(cdr(code), caddr(code));
91540 	    }
91541 	  else
91542 	    {
91543 	      set_optimize_op(code, (s2) ? OP_SAFE_C_CS : OP_SAFE_C_D);
91544 	      if (s2)
91545 		{
91546 		  set_opt1_con(cdr(code), (is_pair(cadr(code))) ? cadadr(code) : cadr(code));
91547 		  set_opt2_sym(cdr(code), caddr(code));
91548 		}}}
91549       else
91550 	{
91551 	  set_optimize_op(code, (has_safe_args(f)) ? OP_CL_ALL_A : OP_C_ALL_A);
91552 	  fx_annotate_args(sc, cdr(code), sc->curlet);
91553 	}
91554       set_opt3_arglen(cdr(code), int_two);
91555       set_c_function(code, f);
91556       return(true);
91557 
91558     case T_CLOSURE:
91559       if (has_methods(f)) break;
91560       if (closure_arity_to_int(sc, f) == 2)
91561 	{
91562 	  s7_pointer body;
91563 	  bool one_form, safe_case;
91564 	  int32_t hop = 0;
91565 
91566 	  body = closure_body(f);
91567 	  one_form = is_null(cdr(body));
91568 	  safe_case = is_safe_closure(f);
91569 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91570 	  if ((s1) && (s2))
91571 	    {
91572 	      set_opt2_sym(code, caddr(code));
91573 	      if (one_form)
91574 		{
91575 		  if (safe_case)
91576 		    {
91577 		      if (is_fxable(sc, car(body)))
91578 			{
91579 			  fx_annotate_arg(sc, body, sc->curlet);
91580 			  fx_tree(sc, body, car(closure_args(f)), cadr(closure_args(f)));
91581 			  set_safe_optimize_op(code, hop + OP_SAFE_CLOSURE_SS_A);
91582 			  set_closure_one_form_fx_arg(f);
91583 			}
91584 		      else set_safe_optimize_op(code, hop + OP_SAFE_CLOSURE_SS_O);
91585 		    }
91586 		  else set_optimize_op(code, hop + OP_CLOSURE_SS_O);
91587 		}
91588 	      else set_optimize_op(code, hop + ((safe_case) ? OP_SAFE_CLOSURE_SS : OP_CLOSURE_SS));
91589 	    }
91590 	  else
91591 	    {
91592 	      if (s1)
91593 		{
91594 		  set_opt2_con(code, caddr(code));
91595 		  if (one_form)
91596 		    set_safe_optimize_op(code, hop + ((safe_case) ? OP_SAFE_CLOSURE_SC_O : OP_CLOSURE_SC_O));
91597 		  else set_optimize_op(code, hop + ((safe_case) ? OP_SAFE_CLOSURE_SC : OP_CLOSURE_SC));
91598 		}
91599 	      else
91600 		{
91601 		  fx_annotate_args(sc, cdr(code), sc->curlet);
91602 		  if (safe_case)
91603 		    set_safe_optimize_op(code, hop + ((one_form) ? OP_SAFE_CLOSURE_AA_O : OP_SAFE_CLOSURE_AA));
91604 		  else set_safe_optimize_op(code, hop + ((one_form) ? OP_CLOSURE_AA_O : OP_CLOSURE_AA));
91605 		}}
91606 	  set_opt1_lambda(code, f);
91607 	  return(true);
91608 	}
91609       break;
91610 
91611     case T_CLOSURE_STAR:
91612       if ((closure_star_arity_to_int(sc, f) != 0) &&
91613 	  (closure_star_arity_to_int(sc, f) != 1))
91614 	{
91615 	  fx_annotate_args(sc, cdr(code), sc->curlet);
91616 	  return(fixup_closure_star_aa(sc, f, code));
91617 	}
91618       break;
91619 
91620     case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_VECTOR: case T_BYTE_VECTOR:
91621       fx_annotate_args(sc, cdr(code), sc->curlet);
91622       return(fixup_unknown_op(code, f, OP_IMPLICIT_VECTOR_REF_AA));
91623 
91624     case T_MACRO:      return(fixup_unknown_op(code, f, OP_MACRO_D));
91625     case T_MACRO_STAR: return(fixup_unknown_op(code, f, OP_MACRO_STAR_D));
91626 
91627     default:
91628       break;
91629     }
91630 
91631   if ((is_symbol(car(code))) &&
91632       (!is_slot(lookup_slot_from(car(code), sc->curlet))))
91633     unbound_variable_error(sc, car(code));
91634 
91635   fx_annotate_args(sc, cdr(code), sc->curlet);
91636   return(fixup_unknown_op(code, f, OP_S_AA));
91637 }
91638 
91639 static bool op_unknown_all_s(s7_scheme *sc)
91640 {
91641   s7_pointer code, arg, f;
91642   int32_t num_args;
91643 
91644   f = sc->last_function;
91645   if (!f) unbound_variable_error(sc, car(sc->code));
91646 
91647 #if SHOW_EVAL_OPS
91648   fprintf(stderr, "%s %s\n", __func__, display(f));
91649 #endif
91650 
91651   code = sc->code;
91652   num_args = integer(opt3_arglen(cdr(code)));
91653   for (arg = cdr(code); is_pair(arg); arg = cdr(arg))
91654     if (!is_slot(lookup_slot_from(car(arg), sc->curlet)))
91655       unbound_variable_error(sc, car(arg));
91656 
91657   switch (type(f))
91658     {
91659     case T_C_FUNCTION:
91660     case T_C_RST_ARGS_FUNCTION:
91661       if ((c_function_required_args(f) > num_args) ||
91662 	  (c_function_all_args(f) < num_args))
91663 	break;
91664     case T_C_OPT_ARGS_FUNCTION:
91665     case T_C_ANY_ARGS_FUNCTION:
91666       if (is_safe_procedure(f))
91667 	{
91668 	  if (num_args == 3)
91669 	    {
91670 	      set_safe_optimize_op(code, OP_SAFE_C_SSS);
91671 	      set_opt1_sym(cdr(code), caddr(code));
91672 	      set_opt2_sym(cdr(code), cadddr(code));
91673 	    }
91674 	  else set_safe_optimize_op(code, OP_SAFE_C_ALL_S);
91675 	}
91676       else
91677 	{
91678 	  set_optimize_op(code, (has_safe_args(f)) ? OP_CL_ALL_A : OP_C_ALL_A);
91679 	  fx_annotate_args(sc, cdr(code), sc->curlet);
91680 	}
91681       set_c_function(code, f);
91682       return(true);
91683 
91684     case T_CLOSURE:
91685       if ((!has_methods(f)) &&
91686 	  (closure_arity_to_int(sc, f) == num_args))
91687 	{
91688 	  int32_t hop = 0;
91689 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91690 	  fx_annotate_args(sc, cdr(code), sc->curlet);
91691 	  if (num_args == 3)
91692 	    return(fixup_unknown_op(code, f, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_3S : OP_CLOSURE_3S)));
91693 	  if (num_args == 4)
91694 	    return(fixup_unknown_op(code, f, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_ALL_S : OP_CLOSURE_4S)));
91695 	  return(fixup_unknown_op(code, f, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_ALL_S : OP_CLOSURE_ALL_S)));
91696 	}
91697       /* if (is_symbol(closure_args(f))) closure_any in some form? this never happens */
91698       break;
91699 
91700     case T_CLOSURE_STAR:
91701       if ((!has_methods(f)) &&
91702 	  ((closure_star_arity_to_int(sc, f) < 0) || ((closure_star_arity_to_int(sc, f) * 2) >= num_args)))
91703 	{
91704 	  int32_t hop = 0;
91705 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91706 	  fx_annotate_args(sc, cdr(code), sc->curlet);
91707 	  return(fixup_unknown_op(code, f, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_STAR_ALL_A : OP_CLOSURE_STAR_ALL_A)));
91708 	}
91709       break;
91710 
91711     case T_MACRO:      return(fixup_unknown_op(code, f, OP_MACRO_D));
91712     case T_MACRO_STAR: return(fixup_unknown_op(code, f, OP_MACRO_STAR_D));
91713 
91714       /* vector/pair */
91715     default:
91716       break;
91717     }
91718   return(unknown_unknown(sc, sc->code, OP_CLEAR_OPTS));
91719 }
91720 
91721 static bool op_unknown_aa(s7_scheme *sc)
91722 {
91723   s7_pointer code, f;
91724 
91725   f = sc->last_function;
91726   if (!f) unbound_variable_error(sc, car(sc->code));
91727 #if SHOW_EVAL_OPS
91728   fprintf(stderr, "%s %s\n", __func__, display(f));
91729 #endif
91730 
91731   code = sc->code;
91732   set_opt3_arglen(cdr(code), int_two);
91733   fx_annotate_args(sc, cdr(code), sc->curlet);
91734 
91735   switch (type(f))
91736     {
91737     case T_C_FUNCTION:
91738     case T_C_RST_ARGS_FUNCTION:
91739       if ((c_function_required_args(f) > 2) ||
91740 	  (c_function_all_args(f) < 2))
91741 	break;
91742     case T_C_OPT_ARGS_FUNCTION:
91743     case T_C_ANY_ARGS_FUNCTION:
91744       if (is_safe_procedure(f))
91745 	{
91746 	  if (!safe_c_aa_to_ag_ga(sc, code, 0))
91747 	    {
91748 	      set_safe_optimize_op(code, OP_SAFE_C_AA);
91749 	      set_opt3_arglen(cdr(code), int_two);
91750 	    }}
91751       else set_optimize_op(code, (has_safe_args(f)) ? OP_CL_ALL_A : OP_C_ALL_A);
91752       set_c_function(code, f);
91753       return(true);
91754 
91755     case T_CLOSURE:
91756       if ((!has_methods(f)) &&
91757 	  (closure_arity_to_int(sc, f) == 2))
91758 	{
91759 	  s7_pointer body;
91760 	  bool one_form, safe_case;
91761 	  int32_t hop = 0;
91762 	  body = closure_body(f);
91763 	  one_form = is_null(cdr(body));
91764 	  safe_case = is_safe_closure(f);
91765 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91766 
91767 	  if (one_form)
91768 	    {
91769 	      if (safe_case)
91770 		{
91771 		  if (is_fxable(sc, car(body)))
91772 		    {
91773 		      fx_annotate_arg(sc, body, sc->curlet);
91774 		      set_safe_optimize_op(code, hop + OP_SAFE_CLOSURE_AA_A);
91775 		      set_closure_one_form_fx_arg(f);
91776 		    }
91777 		  else set_safe_optimize_op(code, hop + OP_SAFE_CLOSURE_AA_O);
91778 		}
91779 	      else set_optimize_op(code, hop + OP_CLOSURE_AA_O);
91780 	    }
91781 	  else set_safe_optimize_op(code, hop + ((safe_case) ? OP_SAFE_CLOSURE_AA : OP_CLOSURE_AA));
91782 	  set_opt1_lambda(code, f);
91783 	  return(true);
91784 	}
91785       break;
91786 
91787     case T_CLOSURE_STAR:
91788       return(fixup_closure_star_aa(sc, f, code));
91789 
91790     case T_INT_VECTOR: case T_FLOAT_VECTOR: case T_VECTOR: case T_BYTE_VECTOR:
91791       return(fixup_unknown_op(code, f, OP_IMPLICIT_VECTOR_REF_AA));
91792 
91793     case T_MACRO:      return(fixup_unknown_op(code, f, OP_MACRO_D));
91794     case T_MACRO_STAR: return(fixup_unknown_op(code, f, OP_MACRO_STAR_D));
91795 
91796     default:
91797       break;
91798     }
91799 
91800   if ((is_symbol(car(code))) &&
91801       (!is_slot(lookup_slot_from(car(code), sc->curlet))))
91802     unbound_variable_error(sc, car(code));
91803 
91804   return(fixup_unknown_op(code, f, OP_S_AA));
91805 }
91806 
91807 static bool is_normal_happy_symbol(s7_scheme *sc, s7_pointer sym)
91808 {
91809   if (is_normal_symbol(sym))
91810     {
91811       if (!is_slot(lookup_slot_from(sym, sc->curlet)))
91812 	unbound_variable_error(sc, sym);
91813       return(true);
91814     }
91815   return(false);
91816 }
91817 
91818 static bool op_unknown_all_a(s7_scheme *sc)
91819 {
91820   s7_pointer code, f;
91821   int32_t num_args;
91822 
91823   f = sc->last_function;
91824   if (!f) unbound_variable_error(sc, car(sc->code));
91825 
91826 #if SHOW_EVAL_OPS
91827   fprintf(stderr, "%s[%d]: %s %s\n", __func__, __LINE__, display(f), display(sc->code));
91828 #endif
91829 
91830   code = sc->code;
91831   num_args = (is_pair(cdr(code))) ? integer(opt3_arglen(cdr(code))) : 0;
91832   if (num_args == 0) return(fixup_unknown_op(code, f, OP_S));       /* via op_closure*-fx where original had 0 args, safe case -> op_safe_closure*_0 */
91833 
91834   switch (type(f))
91835     {
91836     case T_C_FUNCTION:
91837     case T_C_RST_ARGS_FUNCTION:
91838       if ((c_function_required_args(f) > num_args) ||
91839 	  (c_function_all_args(f) < num_args))
91840 	break;
91841     case T_C_OPT_ARGS_FUNCTION:
91842     case T_C_ANY_ARGS_FUNCTION:
91843       if (is_safe_procedure(f))
91844 	{
91845 	  if (num_args == 3)
91846 	    {
91847 	      int32_t pairs = 0, symbols = 0, quotes = 0; /* specialize aaa->ssc etc, this makes less difference than I expected */
91848 	      s7_pointer p;
91849 	      for (p = cdr(code); is_pair(p); p = cdr(p))
91850 		{
91851 		  s7_pointer car_p;
91852 		  car_p = car(p);
91853 		  if (is_normal_happy_symbol(sc, car_p))
91854 		    symbols++;
91855 		  else
91856 		    if (is_pair(car_p))
91857 		      {
91858 			pairs++;
91859 			if (is_proper_quote(sc, car_p))
91860 			  quotes++;
91861 		      }}
91862 	      if (optimize_safe_c_func_three_args(sc, code, f, 0 /* hop */, pairs, symbols, quotes, sc->curlet) == OPT_T)
91863 		return(true);
91864 	      set_opt3_pair(cdr(code), cdddr(code));
91865 	      set_opt3_pair(code, cddr(code));
91866 	      set_safe_optimize_op(code, OP_SAFE_C_AAA);
91867 	    }
91868 	  else set_safe_optimize_op(code, (num_args == 4) ? OP_SAFE_C_4A : OP_SAFE_C_ALL_A);
91869 	}
91870       else set_safe_optimize_op(code, (has_safe_args(f)) ? OP_CL_ALL_A : OP_C_ALL_A);
91871       fx_annotate_args(sc, cdr(code), sc->curlet);
91872       set_c_function(code, f);
91873       return(true);
91874 
91875     case T_CLOSURE:
91876       if ((!has_methods(f)) &&
91877 	  (closure_arity_to_int(sc, f) == num_args))
91878 	{
91879 	  int32_t hop = 0;
91880 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91881 	  fx_annotate_args(sc, cdr(code), sc->curlet);
91882 	  if (is_safe_closure(f))
91883 	    {
91884 	      if (num_args == 3)
91885 		{
91886 		  if (is_normal_happy_symbol(sc, cadr(code)))
91887 		    set_safe_optimize_op(code, hop + ((is_normal_happy_symbol(sc, caddr(code))) ? OP_SAFE_CLOSURE_SSA : OP_SAFE_CLOSURE_SAA));
91888 		  else
91889 		    {
91890 		      if ((!is_pair(caddr(code))) && (!is_pair(cadddr(code))))
91891 			set_safe_optimize_op(code, hop + OP_SAFE_CLOSURE_AGG);
91892 		      else set_safe_optimize_op(code, hop + OP_SAFE_CLOSURE_ALL_A);
91893 		    }}
91894 	      else set_safe_optimize_op(code, hop + OP_SAFE_CLOSURE_ALL_A);
91895 	    }
91896 	  else
91897 	    {
91898 	      if (num_args == 3)
91899 		{
91900 		  if ((is_normal_happy_symbol(sc, caddr(code))) && (is_normal_happy_symbol(sc, cadddr(code))))
91901 		    set_safe_optimize_op(code, hop + OP_CLOSURE_ASS);
91902 		  else
91903 		    {
91904 		      if (is_normal_happy_symbol(sc, cadr(code)))
91905 			set_safe_optimize_op(code, hop + ((is_normal_happy_symbol(sc, cadddr(code))) ? OP_CLOSURE_SAS : OP_CLOSURE_SAA));
91906 		      else
91907 			{
91908 			  if (is_normal_happy_symbol(sc, caddr(code)))
91909 			    set_safe_optimize_op(code, hop + OP_CLOSURE_ASA);
91910 			  else
91911 			    {
91912 			      if (is_normal_happy_symbol(sc, cadddr(code)))
91913 				set_safe_optimize_op(code, hop + OP_CLOSURE_AAS);
91914 			      else set_safe_optimize_op(code, hop + OP_CLOSURE_3A);
91915 			    }}}}
91916 	      else set_safe_optimize_op(code, hop + ((num_args == 4) ? OP_CLOSURE_4A : OP_CLOSURE_ALL_A));
91917 	    }
91918 	  set_opt1_lambda(code, f);
91919 	  return(true);
91920 	}
91921 
91922       if (is_symbol(closure_args(f)))
91923 	{
91924 	  optimize_closure_dotted_args(sc, code, f, 0, num_args, sc->curlet);
91925 	  if (optimize_op(code) == OP_CLOSURE_ANY_ALL_A) return(true);
91926 	}
91927       break;
91928 
91929     case T_CLOSURE_STAR:
91930       if ((!has_methods(f)) &&
91931 	  ((closure_star_arity_to_int(sc, f) < 0) || ((closure_star_arity_to_int(sc, f) * 2) >= num_args)))
91932 	{
91933 	  int32_t hop = 0;
91934 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91935 	  if (num_args > 0)
91936 	    {
91937 	      set_opt3_arglen(cdr(code), small_int(num_args));
91938 	      fx_annotate_args(sc, cdr(code), sc->curlet);
91939 	    }
91940 	  if (is_safe_closure(f))
91941 	    switch (num_args)
91942 	      {
91943 	      case 0: return(fixup_unknown_op(code, f, hop + OP_SAFE_CLOSURE_STAR_ALL_A_0));
91944 	      case 1: return(fixup_unknown_op(code, f, hop + OP_SAFE_CLOSURE_STAR_ALL_A_1));
91945 	      case 2: return(fixup_unknown_op(code, f, hop + OP_SAFE_CLOSURE_STAR_ALL_A_2));
91946 	      default: return(fixup_unknown_op(code, f, hop + OP_SAFE_CLOSURE_STAR_ALL_A));
91947 	      }
91948 	  return(fixup_unknown_op(code, f, hop + OP_CLOSURE_STAR_ALL_A));
91949 	}
91950       break;
91951 
91952     case T_MACRO:      return(fixup_unknown_op(code, f, OP_MACRO_D));
91953     case T_MACRO_STAR: return(fixup_unknown_op(code, f, OP_MACRO_STAR_D));
91954 
91955     default:
91956       break;
91957     }
91958   /* closure happens if wrong-number-of-args passed -- probably no need for op_s_all_a */
91959   return(unknown_unknown(sc, sc->code, OP_CLEAR_OPTS));
91960 }
91961 
91962 static bool op_unknown_fp(s7_scheme *sc)
91963 {
91964   s7_pointer code, f;
91965   int32_t num_args;
91966 
91967   f = sc->last_function;
91968   if (!f) unbound_variable_error(sc, car(sc->code));
91969 
91970 #if SHOW_EVAL_OPS
91971   fprintf(stderr, "%s[%d]: %s %s %s\n", __func__, __LINE__, display(f), type_name(sc, f, NO_ARTICLE), display(sc->code));
91972 #endif
91973 
91974   code = sc->code;
91975   num_args = (is_pair(cdr(code))) ? integer(opt3_arglen(cdr(code))) : 0;
91976 
91977   switch (type(f))
91978     {
91979     case T_C_FUNCTION:
91980     case T_C_RST_ARGS_FUNCTION:
91981       if ((c_function_required_args(f) > num_args) ||
91982 	  (c_function_all_args(f) < num_args))
91983 	break;
91984     case T_C_OPT_ARGS_FUNCTION:
91985     case T_C_ANY_ARGS_FUNCTION:
91986       if (num_args == 1)
91987 	set_any_c_fp(sc, f, code, sc->curlet, num_args, (is_safe_procedure(f)) ? OP_SAFE_C_P : OP_C_P);
91988       else set_any_c_fp(sc, f, code, sc->curlet, num_args, OP_ANY_C_FP);
91989       return(true);
91990 
91991     case T_CLOSURE:
91992       if ((!has_methods(f)) &&
91993 	  (closure_arity_to_int(sc, f) == num_args))
91994 	{
91995 	  int32_t hop = 0;
91996 	  if (is_immutable_and_stable(sc, car(code))) hop = 1;
91997 
91998 	  switch (num_args)
91999 	    {
92000 	    case 1:
92001 	      if (is_safe_closure(f))
92002 		{
92003 		  s7_pointer body;
92004 		  body = closure_body(f);
92005 		  if ((is_null(cdr(body))) && (is_fxable(sc, car(body))))
92006 		    {
92007 		      set_optimize_op(code, hop + OP_SAFE_CLOSURE_P_A);
92008 		      fx_annotate_arg(sc, body, sc->curlet);
92009 		    }
92010 		  else set_optimize_op(code, hop + OP_SAFE_CLOSURE_P);
92011 		}
92012 	      else set_optimize_op(code, hop + OP_CLOSURE_P);
92013 	      set_opt1_lambda(code, f);
92014 	      set_opt3_arglen(cdr(code), int_one);
92015 	      set_unsafely_optimized(code);
92016 	      break;
92017 
92018 	    case 2:
92019 	      if (is_fxable(sc, cadr(code)))
92020 		{
92021 		  fx_annotate_arg(sc, cdr(code), sc->curlet);
92022 		  set_optimize_op(code, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_AP : OP_CLOSURE_AP));
92023 		}
92024 	      else
92025 		{
92026 		  if (is_fxable(sc, caddr(code)))
92027 		    {
92028 		      fx_annotate_arg(sc, cddr(code), sc->curlet);
92029 		      set_optimize_op(code, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_PA : OP_CLOSURE_PA));
92030 		    }
92031 		  else set_optimize_op(code, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_PP : OP_CLOSURE_PP));
92032 		}
92033 	      set_opt1_lambda(code, f);
92034 	      set_opt3_arglen(cdr(code), int_two); /* for later op_unknown_fp */
92035 	      set_unsafely_optimized(code);
92036 	      break;
92037 
92038 	    case 3: set_any_closure_fp(sc, f, code, sc->curlet, 3, hop + OP_ANY_CLOSURE_3P); break;
92039 	    case 4: set_any_closure_fp(sc, f, code, sc->curlet, 4, hop + OP_ANY_CLOSURE_4P); break;
92040 	    default:
92041 	      set_any_closure_fp(sc, f, code, sc->curlet, num_args, hop + OP_ANY_CLOSURE_FP);
92042 	      break;
92043 	    }
92044 	  /* safe|closure|p*|fp|a*p* */
92045 	  return(true);
92046 	}
92047       break;
92048 
92049     case T_MACRO:      return(fixup_unknown_op(code, f, OP_MACRO_D));
92050     case T_MACRO_STAR: return(fixup_unknown_op(code, f, OP_MACRO_STAR_D));
92051     }
92052   return(unknown_unknown(sc, sc->code, OP_CLEAR_OPTS));
92053 }
92054 
92055 
92056 /* ---------------- eval type checkers ---------------- */
92057 #if WITH_GCC
92058 #define h_c_function_is_ok(Sc, P) ({s7_pointer _P_; _P_ = P; ((op_has_hop(_P_)) || (c_function_is_ok(Sc, _P_)));})
92059 #else
92060 #define h_c_function_is_ok(Sc, P) ((op_has_hop(P)) || (c_function_is_ok(Sc, P)))
92061 #endif
92062 
92063 #define c_function_is_ok_cadr(Sc, P) ((c_function_is_ok(Sc, P)) && (h_c_function_is_ok(Sc, cadr(P))))
92064 #define c_function_is_ok_caddr(Sc, P) ((c_function_is_ok(Sc, P)) && (h_c_function_is_ok(Sc, caddr(P))))
92065 #define c_function_is_ok_cadr_caddr(Sc, P) ((c_function_is_ok(Sc, P)) && (h_c_function_is_ok(Sc, cadr(P))) && (h_c_function_is_ok(Sc, caddr(P))))
92066 #define c_function_is_ok_cadr_cadadr(Sc, P) ((c_function_is_ok(Sc, P)) && (h_c_function_is_ok(Sc, cadr(P))) && (h_c_function_is_ok(Sc, cadadr(P))))
92067 #define c_function_is_ok_cadr_caddadr(Sc, P) ((c_function_is_ok(Sc, P)) && (h_c_function_is_ok(Sc, cadr(P))) && (h_c_function_is_ok(Sc, caddadr(P))))
92068 
92069 /* closure_is_ok_1 checks the type and the body length indications
92070  * closure_is_fine_1 just checks the type (safe or unsafe closure)
92071  * closure_is_ok calls _ok_1, closure_is_fine calls _fine_1
92072  * closure_fp_is_ok accepts safe/unsafe etc
92073  */
92074 
92075 static inline bool closure_is_ok_1(s7_scheme *sc, s7_pointer code, uint16_t type, int32_t args)
92076 {
92077   s7_pointer f;
92078 #if S7_DEBUGGING
92079   if (symbol_ctr(car(code)) == 1) fprintf(stderr, "%s ctr is 1, %p != %p\n", display(car(code)), unchecked_local_value(car(code)), opt1_lambda_unchecked(code));
92080 #endif
92081   f = lookup_unexamined(sc, car(code));
92082   if ((f == opt1_lambda_unchecked(code)) ||
92083       ((f) &&
92084        (typesflag(f) == type) &&
92085        ((closure_arity(f) == args) || (closure_arity_to_int(sc, f) == args)) && /* 3 type bits to replace this but not hit enough to warrant them */
92086        (set_opt1_lambda(code, f))))
92087     return(true);
92088   sc->last_function = f;
92089   return(false);
92090 }
92091 
92092 static inline bool closure_is_fine_1(s7_scheme *sc, s7_pointer code, uint16_t type, int32_t args)
92093 {
92094   s7_pointer f;
92095   f = lookup_unexamined(sc, car(code));
92096   if ((f == opt1_lambda_unchecked(code)) ||
92097       ((f) &&
92098        ((typesflag(f) & (TYPE_MASK | T_SAFE_CLOSURE)) == type) &&
92099        ((closure_arity(f) == args) || (closure_arity_to_int(sc, f) == args)) &&
92100        (set_opt1_lambda(code, f))))
92101     return(true);
92102   sc->last_function = f;
92103   return(false);
92104 }
92105 
92106 static inline bool closure_fp_is_ok_1(s7_scheme *sc, s7_pointer code, int32_t args)
92107 {
92108   s7_pointer f;
92109   f = lookup_unexamined(sc, car(code));
92110   if ((f == opt1_lambda_unchecked(code)) ||
92111       ((f) &&
92112        (is_closure(f)) &&
92113        (set_opt1_lambda(code, f))))
92114     return(true);
92115   sc->last_function = f;
92116   return(false);
92117 }
92118 
92119 #define closure_is_ok(Sc, Code, Type, Args)        ((symbol_ctr(car(Code)) == 1) || (closure_is_ok_1(Sc, Code, Type, Args)))
92120 #define closure_fp_is_ok(Sc, Code, Args)           ((symbol_ctr(car(Code)) == 1) || (closure_fp_is_ok_1(Sc, Code, Args)))
92121 #define closure_is_fine(Sc, Code, Type, Args)      ((symbol_ctr(car(Code)) == 1) || (closure_is_fine_1(Sc, Code, Type, Args)))
92122 #define closure_star_is_fine(Sc, Code, Type, Args) ((symbol_ctr(car(Code)) == 1) || (closure_star_is_fine_1(Sc, Code, Type, Args)))
92123 
92124 static inline bool closure_is_eq(s7_scheme *sc)
92125 {
92126   sc->last_function = lookup_unexamined(sc, car(sc->code));
92127   return(sc->last_function == opt1_lambda_unchecked(sc->code));
92128 }
92129 
92130 static bool star_arity_is_ok(s7_scheme *sc, s7_pointer val, int32_t args)
92131 {
92132   int32_t arity;
92133   arity = closure_star_arity_to_int(sc, val);
92134   return((arity < 0) || ((arity * 2) >= args));
92135 }
92136 
92137 static bool closure_star_is_fine_1(s7_scheme *sc, s7_pointer code, uint16_t type, int32_t args)
92138 {
92139   s7_pointer val;
92140   val = lookup_unexamined(sc, car(code));
92141   if ((val == opt1_lambda_unchecked(code)) ||
92142       ((val) &&
92143        ((typesflag(val) & (T_SAFE_CLOSURE | TYPE_MASK)) == type) &&
92144        (star_arity_is_ok(sc, val, args)) &&
92145        (set_opt1_lambda(code, val))))
92146     return(true);
92147   sc->last_function = val;
92148   return(false);
92149 }
92150 
92151 /* closure_is_fine: */
92152 #define FINE_UNSAFE_CLOSURE      (T_CLOSURE)
92153 #define FINE_SAFE_CLOSURE        (T_CLOSURE      | T_SAFE_CLOSURE)
92154 
92155 /* closure_star_is_fine: */
92156 #define FINE_UNSAFE_CLOSURE_STAR (T_CLOSURE_STAR)
92157 #define FINE_SAFE_CLOSURE_STAR   (T_CLOSURE_STAR | T_SAFE_CLOSURE)
92158 
92159 /* closure_is_ok: */
92160 #define OK_UNSAFE_CLOSURE_P      (T_CLOSURE                       | T_ONE_FORM)
92161 #define OK_SAFE_CLOSURE_P        (T_CLOSURE      | T_SAFE_CLOSURE | T_ONE_FORM)
92162 #define OK_UNSAFE_CLOSURE_M      (T_CLOSURE                       | T_MULTIFORM)
92163 #define OK_SAFE_CLOSURE_M        (T_CLOSURE      | T_SAFE_CLOSURE | T_MULTIFORM)
92164 #define OK_SAFE_CLOSURE_A        (T_CLOSURE      | T_SAFE_CLOSURE | T_ONE_FORM_FX_ARG)
92165 /* since T_HAS_METHODS is on if there might be methods, this can protect us from that case */
92166 
92167 
92168 /* ---------------- eval ---------------- */
92169 static s7_pointer eval(s7_scheme *sc, opcode_t first_op)
92170 {
92171 #if SHOW_EVAL_OPS
92172   safe_print(fprintf(stderr, "eval[%d]:, %s %s %s\n", __LINE__, op_names[first_op], display_80(sc->code), display_80(sc->args)));
92173 #endif
92174   sc->cur_op = first_op;
92175   goto TOP_NO_POP;
92176 
92177   while (true) /* "continue" in this procedure refers to this loop */
92178     {
92179       pop_stack(sc);
92180       goto TOP_NO_POP;
92181 
92182     BEGIN:
92183       if (is_pair(cdr(T_Pair(sc->code))))
92184 	push_stack_no_args(sc, sc->begin_op, cdr(sc->code));
92185       sc->code = car(sc->code);
92186       set_current_code(sc, sc->code);
92187 
92188     EVAL:
92189       sc->cur_op = optimize_op(sc->code); /* sc->code can be anything, optimize_op examines a type field (opt_choice) */
92190 
92191     TOP_NO_POP:
92192 #if SHOW_EVAL_OPS
92193       safe_print(fprintf(stderr, "%s (%d), code: %s\n", op_names[sc->cur_op], (int)(sc->cur_op), display_80(sc->code)));
92194 #endif
92195       /* it is only slightly faster to use labels as values (computed gotos) here. In my timing tests (June-2018), the best case speedup was in titer.scm
92196        *    callgrind numbers 4808 to 4669; another good case was tread.scm: 2410 to 2386.  Most timings were a draw.  computed-gotos-s7.c has the code,
92197        *    macroized so it will work if such gotos aren't available.  I think I'll stick with a switch statement.
92198        * Another seductive idea is to put the function in the tree, not an index to it (the optimize_op business above),
92199        *    then the switch below is not needed, and we free up 16 type bits.  C does not guarantee tail calls (I think)
92200        *    so we'd have each function return the next, and eval would be (while (true) f = f(sc) but would the function
92201        *    call overhead be less expensive than the switch? (We get most functions inlined in the current code).
92202        */
92203 
92204       switch (sc->cur_op)
92205 	{
92206 	  /* safe c_functions */
92207 	case OP_SAFE_C_D: if (!c_function_is_ok(sc, sc->code)) break;  /* break refers to the switch statement */
92208 	case HOP_SAFE_C_D: sc->value = d_call(sc, sc->code); continue; /* continue refers to the outer while loop -- unfortunate C ambiguity */
92209 
92210 	case OP_SAFE_C_S: if (!c_function_is_ok(sc, sc->code)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92211 	case HOP_SAFE_C_S: op_safe_c_s(sc); continue;
92212 
92213 	case OP_SAFE_C_SS: if (!c_function_is_ok(sc, sc->code)) break;
92214 	case HOP_SAFE_C_SS: op_safe_c_ss(sc); continue;
92215 
92216 	case OP_SAFE_C_ALL_S: if (!c_function_is_ok(sc, sc->code)) break;
92217 	case HOP_SAFE_C_ALL_S: sc->value = fx_c_all_s(sc, sc->code); continue;
92218 
92219 	case OP_SAFE_C_SC: if (!c_function_is_ok(sc, sc->code)) break;
92220 	case HOP_SAFE_C_SC: op_safe_c_sc(sc); continue;
92221 
92222 	case OP_SAFE_C_CS: if (!c_function_is_ok(sc, sc->code)) break;
92223 	case HOP_SAFE_C_CS: sc->value = fx_c_cs(sc, sc->code); continue;
92224 
92225 	case OP_SAFE_C_CQ: if (!c_function_is_ok(sc, sc->code)) break;
92226 	case HOP_SAFE_C_CQ: sc->value = fx_c_cq(sc, sc->code); continue;
92227 
92228 	case OP_SAFE_C_FF: if (!c_function_is_ok(sc, sc->code))  {if (op_unknown_fp(sc)) goto EVAL; continue;}
92229 	case HOP_SAFE_C_FF: sc->value = fx_c_ff(sc, sc->code); continue;
92230 
92231 	case OP_SAFE_C_P: if (!c_function_is_ok(sc, sc->code)) break;
92232 	case HOP_SAFE_C_P: op_safe_c_p(sc); goto EVAL;
92233 	case OP_SAFE_C_P_1: op_safe_c_p_1(sc); continue;
92234 
92235 	case OP_ANY_C_FP:      if (!c_function_is_ok(sc, sc->code))  {if (op_unknown_fp(sc)) goto EVAL; continue;}
92236 	case HOP_ANY_C_FP:     if (op_any_c_fp(sc)) goto EVAL; continue;
92237 	case OP_ANY_C_FP_1:    if (op_any_c_fp_1(sc)) goto EVAL; continue;
92238 	case OP_ANY_C_FP_2:    op_any_c_fp_2(sc); continue;
92239 	case OP_ANY_C_FP_MV_1: if (op_any_c_fp_mv_1(sc)) goto EVAL; goto APPLY;
92240 
92241 	case OP_SAFE_C_SSP:      if (!c_function_is_ok(sc, sc->code)) break;
92242 	case HOP_SAFE_C_SSP:     op_safe_c_ssp(sc); goto EVAL;
92243 	case OP_SAFE_C_SSP_1:    op_safe_c_ssp_1(sc); continue;
92244 	case OP_SAFE_C_SSP_MV_1: op_safe_c_ssp_mv_1(sc); goto APPLY;
92245 
92246 	case OP_SAFE_C_A: if (!c_function_is_ok(sc, sc->code)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92247 	case HOP_SAFE_C_A: sc->value = fx_c_a(sc, sc->code); continue;
92248 
92249 	case OP_SAFE_C_opAq: if (!c_function_is_ok(sc, sc->code)) break;
92250 	case HOP_SAFE_C_opAq: sc->value = fx_c_opaq(sc, sc->code); continue;
92251 
92252 	case OP_SAFE_C_opAAq: if (!c_function_is_ok(sc, sc->code)) break;
92253 	case HOP_SAFE_C_opAAq: sc->value = fx_c_opaaq(sc, sc->code); continue;
92254 
92255 	case OP_SAFE_C_opAAAq: if (!c_function_is_ok(sc, sc->code)) break;
92256 	case HOP_SAFE_C_opAAAq: sc->value = fx_c_opaaaq(sc, sc->code); continue;
92257 
92258 	case OP_SAFE_C_S_opAq: if (!c_function_is_ok(sc, sc->code)) break;
92259 	case HOP_SAFE_C_S_opAq: sc->value = fx_c_s_opaq(sc, sc->code); continue;
92260 
92261 	case OP_SAFE_C_opAq_S: if (!c_function_is_ok(sc, sc->code)) break;
92262 	case HOP_SAFE_C_opAq_S: sc->value = fx_c_opaq_s(sc, sc->code); continue;
92263 
92264 	case OP_SAFE_C_S_opAAq: if (!c_function_is_ok(sc, sc->code)) break;
92265 	case HOP_SAFE_C_S_opAAq: sc->value = fx_c_s_opaaq(sc, sc->code); continue;
92266 
92267 	case OP_SAFE_C_S_opAAAq: if (!c_function_is_ok(sc, sc->code)) break;
92268 	case HOP_SAFE_C_S_opAAAq: sc->value = fx_c_s_opaaaq(sc, sc->code); continue;
92269 
92270 	case OP_SAFE_C_AA: if (!c_function_is_ok(sc, sc->code)) break;
92271 	case HOP_SAFE_C_AA: sc->value = fx_c_aa(sc, sc->code); continue;
92272 
92273 	case OP_SAFE_C_SA: if (!c_function_is_ok(sc, sc->code)) break;
92274 	case HOP_SAFE_C_SA: sc->value = fx_c_sa(sc, sc->code); continue;
92275 
92276 	case OP_SAFE_C_AS: if (!c_function_is_ok(sc, sc->code)) break;
92277 	case HOP_SAFE_C_AS: sc->value = fx_c_as(sc, sc->code); continue;
92278 
92279 	case OP_SAFE_C_CA: if (!c_function_is_ok(sc, sc->code)) break;
92280 	case HOP_SAFE_C_CA: sc->value = fx_c_ca(sc, sc->code); continue;
92281 
92282 	case OP_SAFE_C_AC: if (!c_function_is_ok(sc, sc->code)) break;
92283 	case HOP_SAFE_C_AC: sc->value = fx_c_ac(sc, sc->code); continue;
92284 
92285 	case OP_SAFE_C_AAA: if (!c_function_is_ok(sc, sc->code)) break;
92286 	case HOP_SAFE_C_AAA: sc->value = fx_c_aaa(sc, sc->code); continue;
92287 
92288 	case OP_SAFE_C_SAA: if (!c_function_is_ok(sc, sc->code)) break;
92289 	case HOP_SAFE_C_SAA: sc->value = fx_c_saa(sc, sc->code); continue;
92290 
92291 	case OP_SAFE_C_SSA: if (!c_function_is_ok(sc, sc->code)) break;
92292 	case HOP_SAFE_C_SSA: sc->value = fx_c_ssa(sc, sc->code); continue;
92293 	case HOP_SSA_DIRECT: sc->value = op_ssa_direct(sc, sc->code); continue;
92294 	case HOP_HASH_TABLE_INCREMENT: sc->value = fx_hash_table_increment(sc, sc->code); continue; /* a placeholder, almost never called */
92295 
92296 	case OP_SAFE_C_SAS: if (!c_function_is_ok(sc, sc->code)) break;
92297 	case HOP_SAFE_C_SAS: sc->value = fx_c_sas(sc, sc->code); continue;
92298 
92299 	case OP_SAFE_C_ASS: if (!c_function_is_ok(sc, sc->code)) break;
92300 	case HOP_SAFE_C_ASS: sc->value = fx_c_ass(sc, sc->code); continue;
92301 
92302 	case OP_SAFE_C_CAC: if (!c_function_is_ok(sc, sc->code)) break;
92303 	case HOP_SAFE_C_CAC: sc->value = fx_c_cac(sc, sc->code); continue;
92304 
92305 	case OP_SAFE_C_CSA: if (!c_function_is_ok(sc, sc->code)) break;
92306 	case HOP_SAFE_C_CSA: sc->value = fx_c_csa(sc, sc->code); continue;
92307 
92308 	case OP_SAFE_C_SCA: if (!c_function_is_ok(sc, sc->code)) break;
92309 	case HOP_SAFE_C_SCA: sc->value = fx_c_sca(sc, sc->code); continue;
92310 
92311 	case OP_SAFE_C_4A: if (!c_function_is_ok(sc, sc->code)) break;
92312 	case HOP_SAFE_C_4A: sc->value = fx_c_4a(sc, sc->code); continue;
92313 
92314 	case OP_SAFE_C_ALL_A: if (!c_function_is_ok(sc, sc->code)) break;
92315 	case HOP_SAFE_C_ALL_A: sc->value = fx_c_all_a(sc, sc->code); continue;
92316 
92317 	case OP_SAFE_C_ALL_CA: if (!c_function_is_ok(sc, sc->code)) break;
92318 	case HOP_SAFE_C_ALL_CA: sc->value = fx_c_all_ca(sc, sc->code); continue;
92319 
92320 	case OP_SAFE_C_INLET_CA: if (!c_function_is_ok(sc, sc->code)) break;
92321 	case HOP_SAFE_C_INLET_CA: sc->value = fx_inlet_ca(sc, sc->code); continue;
92322 
92323 	case OP_SAFE_C_SCS: if (!c_function_is_ok(sc, sc->code)) break;
92324 	case HOP_SAFE_C_SCS: sc->value = fx_c_scs(sc, sc->code); continue;
92325 
92326 	case OP_SAFE_C_SSC: if (!c_function_is_ok(sc, sc->code)) break;
92327 	case HOP_SAFE_C_SSC: sc->value = fx_c_ssc(sc, sc->code); continue;
92328 
92329 	case OP_SAFE_C_SCC: if (!c_function_is_ok(sc, sc->code)) break;
92330 	case HOP_SAFE_C_SCC: sc->value = fx_c_scc(sc, sc->code); continue;
92331 
92332 	case OP_SAFE_C_CSC: if (!c_function_is_ok(sc, sc->code)) break;
92333 	case HOP_SAFE_C_CSC: sc->value = fx_c_csc(sc, sc->code); continue;
92334 
92335 	case OP_SAFE_C_CCS: if (!c_function_is_ok(sc, sc->code)) break;
92336 	case HOP_SAFE_C_CCS: sc->value = fx_c_ccs(sc, sc->code); continue;
92337 
92338 	case OP_SAFE_C_CSS: if (!c_function_is_ok(sc, sc->code)) break;
92339 	case HOP_SAFE_C_CSS: sc->value = fx_c_css(sc, sc->code); continue;
92340 
92341 	case OP_SAFE_C_SSS: if (!c_function_is_ok(sc, sc->code)) break;
92342 	case HOP_SAFE_C_SSS: sc->value = fx_c_sss(sc, sc->code); continue;
92343 
92344 	case OP_SAFE_C_opDq: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92345 	case HOP_SAFE_C_opDq: sc->value = fx_c_opdq(sc, sc->code); continue;
92346 
92347 	case OP_SAFE_C_opSq: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92348 	case HOP_SAFE_C_opSq: sc->value = fx_c_opsq(sc, sc->code); continue;
92349 
92350 	case OP_SAFE_C_op_opSqq: if (!c_function_is_ok_cadr_cadadr(sc, sc->code)) break;
92351 	case HOP_SAFE_C_op_opSqq: sc->value = fx_c_op_opsqq(sc, sc->code); continue;
92352 
92353 	case OP_SAFE_C_op_S_opSqq: if (!c_function_is_ok_cadr_caddadr(sc, sc->code)) break;
92354 	case HOP_SAFE_C_op_S_opSqq: sc->value = fx_c_op_s_opsqq(sc, sc->code); continue;
92355 
92356 	case OP_SAFE_C_op_opSq_Sq: if (!c_function_is_ok_cadr_cadadr(sc, sc->code)) break;
92357 	case HOP_SAFE_C_op_opSq_Sq: sc->value = fx_c_op_opsq_sq(sc, sc->code); continue;
92358 
92359 	case OP_SAFE_C_PS:    if (!c_function_is_ok(sc, sc->code)) break;
92360 	case HOP_SAFE_C_PS:   op_safe_c_ps(sc); goto EVAL;
92361 	case OP_SAFE_C_PS_1:  op_safe_c_ps_1(sc); continue;
92362 	case OP_SAFE_C_PS_MV: op_safe_c_ps_mv(sc); goto APPLY;
92363 
92364 	case OP_SAFE_C_PC:    if (!c_function_is_ok(sc, sc->code)) break;
92365 	case HOP_SAFE_C_PC:   op_safe_c_pc(sc); goto EVAL;
92366 	case OP_SAFE_C_PC_1:  op_safe_c_pc_1(sc); continue;
92367 	case OP_SAFE_C_PC_MV: op_safe_c_pc_mv(sc); goto APPLY;
92368 
92369 	case OP_SAFE_C_SP:    if (!c_function_is_ok(sc, sc->code)) break;
92370 	case HOP_SAFE_C_SP:   op_safe_c_sp(sc); goto EVAL;
92371 	case OP_SAFE_C_SP_1:  op_safe_c_sp_1(sc); continue;
92372 	case OP_SAFE_C_SP_MV: op_safe_c_sp_mv(sc); goto APPLY;
92373 
92374 	case OP_SAFE_CONS_SP_1:     sc->value = cons(sc, sc->args, sc->value); continue;
92375 	case OP_SAFE_VECTOR_SP_1:   sc->value = vector_p_pp(sc, sc->args, sc->value); continue;
92376 	case OP_SAFE_ADD_SP_1:      op_safe_add_sp_1(sc); continue;
92377 	case OP_SAFE_SUBTRACT_SP_1: sc->value = subtract_p_pp(sc, sc->args, sc->value); continue;
92378 	case OP_SAFE_MULTIPLY_SP_1: op_safe_multiply_sp_1(sc); continue;
92379 
92380 	case OP_SAFE_C_AP: if (!c_function_is_ok(sc, sc->code)) break;
92381 	case HOP_SAFE_C_AP: if (op_safe_c_ap(sc)) goto EVAL; continue;
92382 
92383 	case OP_SAFE_C_PA: if (!c_function_is_ok(sc, sc->code)) break;
92384 	case HOP_SAFE_C_PA: if (op_safe_c_pa(sc)) goto EVAL; continue;
92385 	case OP_SAFE_C_PA_1: op_safe_c_pa_1(sc); continue;
92386 	case OP_SAFE_C_PA_MV: op_safe_c_pa_mv(sc); goto APPLY;
92387 
92388  	case OP_SAFE_C_CP: if (!c_function_is_ok(sc, sc->code)) break;
92389 	case HOP_SAFE_C_CP: op_safe_c_cp(sc); goto EVAL;
92390 
92391 	case OP_SAFE_C_PP: if (!c_function_is_ok(sc, sc->code)) break;
92392 	case HOP_SAFE_C_PP: if (op_safe_c_pp(sc)) goto EVAL; continue;
92393 
92394 	case OP_SAFE_C_PP_1:    op_safe_c_pp_1(sc);    goto EVAL;
92395 	case OP_SAFE_C_PP_3_MV: op_safe_c_pp_3_mv(sc); goto EVAL;
92396 	case OP_SAFE_C_PP_5:    op_safe_c_pp_5(sc);    goto APPLY;
92397 	case OP_SAFE_C_PP_6_MV: op_safe_c_pp_6_mv(sc); goto APPLY;
92398 
92399 	case OP_SAFE_C_opSSq: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92400 	case HOP_SAFE_C_opSSq: sc->value = fx_c_opssq(sc, sc->code); continue;
92401 
92402 	case OP_SAFE_C_opSCq: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92403 	case HOP_SAFE_C_opSCq: sc->value = fx_c_opscq(sc, sc->code); continue;
92404 
92405 	case OP_SAFE_C_opCSq: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92406 	case HOP_SAFE_C_opCSq: sc->value = fx_c_opcsq(sc, sc->code); continue;
92407 
92408 	case OP_SAFE_C_S_opSq: if (!c_function_is_ok_caddr(sc, sc->code)) break;
92409 	case HOP_SAFE_C_S_opSq: sc->value = fx_c_s_opsq(sc, sc->code); continue;
92410 
92411 	case OP_SAFE_C_C_opSq: if (!c_function_is_ok_caddr(sc, sc->code)) break;
92412 	case HOP_SAFE_C_C_opSq: sc->value = fx_c_c_opsq(sc, sc->code); continue;
92413 
92414 	case OP_SAFE_C_C_opSSq: if (!c_function_is_ok_caddr(sc, sc->code)) break;
92415 	case HOP_SAFE_C_C_opSSq: sc->value = fx_c_c_opssq(sc, sc->code); continue;
92416 
92417 	case OP_SAFE_C_opCSq_C: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92418 	case HOP_SAFE_C_opCSq_C: sc->value = fx_c_opcsq_c(sc, sc->code); continue;
92419 
92420 	case OP_SAFE_C_opSSq_C: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92421 	case HOP_SAFE_C_opSSq_C: sc->value = fx_c_opssq_c(sc, sc->code); continue;
92422 
92423 	case OP_SAFE_C_opSSq_S: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92424 	case HOP_SAFE_C_opSSq_S: sc->value = fx_c_opssq_s(sc, sc->code); continue;
92425 
92426 	case OP_SAFE_C_op_opSSqq_S: if (!c_function_is_ok_cadr_cadadr(sc, sc->code)) break;
92427 	case HOP_SAFE_C_op_opSSqq_S: sc->value = fx_c_op_opssqq_s(sc, sc->code); continue;
92428 
92429 	case OP_SAFE_C_opSCq_C: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92430 	case HOP_SAFE_C_opSCq_C: sc->value = fx_c_opscq_c(sc, sc->code); continue;
92431 
92432 	case OP_SAFE_C_opCSq_S: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92433 	case HOP_SAFE_C_opCSq_S: sc->value = fx_c_opcsq_s(sc, sc->code); continue;
92434 
92435 	case OP_SAFE_C_S_opSCq: if (!c_function_is_ok_caddr(sc, sc->code)) break;
92436 	case HOP_SAFE_C_S_opSCq: sc->value = fx_c_s_opscq(sc, sc->code); continue;
92437 
92438 	case OP_SAFE_C_C_opSCq: if (!c_function_is_ok_caddr(sc, sc->code)) break;
92439 	case HOP_SAFE_C_C_opSCq: sc->value = fx_c_c_opscq(sc, sc->code); continue;
92440 
92441 	case OP_SAFE_C_S_opSSq: if (!c_function_is_ok_caddr(sc, sc->code)) break;
92442 	case HOP_SAFE_C_S_opSSq: sc->value = fx_c_s_opssq(sc, sc->code); continue;
92443 
92444 	case OP_SAFE_C_S_opCSq: if (!c_function_is_ok_caddr(sc, sc->code)) break;
92445 	case HOP_SAFE_C_S_opCSq: sc->value = fx_c_s_opcsq(sc, sc->code); continue;
92446 
92447 	case OP_SAFE_C_opSq_S: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92448 	case HOP_SAFE_C_opSq_S: sc->value = fx_c_opsq_s(sc, sc->code); continue;
92449 
92450 	case OP_SAFE_C_opSq_P: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92451 	case HOP_SAFE_C_opSq_P: op_safe_c_opsq_p(sc); goto EVAL;
92452 
92453 	case OP_SAFE_C_opSq_CS: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92454 	case HOP_SAFE_C_opSq_CS: sc->value = fx_c_opsq_cs(sc, sc->code); continue;
92455 
92456 	case OP_SAFE_C_opSq_C: if (!c_function_is_ok_cadr(sc, sc->code)) break;
92457 	case HOP_SAFE_C_opSq_C: sc->value = fx_c_opsq_c(sc, sc->code); continue;
92458 
92459 	case OP_SAFE_C_opSq_opSq: if (!c_function_is_ok_cadr_caddr(sc, sc->code)) break;
92460 	case HOP_SAFE_C_opSq_opSq: sc->value = fx_c_opsq_opsq(sc, sc->code); continue;
92461 
92462 	case OP_SAFE_C_opSSq_opSSq: if (!c_function_is_ok_cadr_caddr(sc, sc->code)) break;
92463 	case HOP_SAFE_C_opSSq_opSSq: sc->value = fx_c_opssq_opssq(sc, sc->code); continue;
92464 
92465 	case OP_SAFE_C_opSSq_opSq: if (!c_function_is_ok_cadr_caddr(sc, sc->code)) break;
92466 	case HOP_SAFE_C_opSSq_opSq: sc->value = fx_c_opssq_opsq(sc, sc->code); continue;
92467 
92468 	case OP_SAFE_C_opSq_opSSq: if (!c_function_is_ok_cadr_caddr(sc, sc->code)) break;
92469 	case HOP_SAFE_C_opSq_opSSq: sc->value = fx_c_opsq_opssq(sc, sc->code); continue;
92470 
92471 
92472 	  /* semisafe c_functions */
92473 	case OP_CL_S: if (!cl_function_is_ok(sc, sc->code)) break;
92474 	case HOP_CL_S: op_safe_c_s(sc); continue;
92475 
92476 	case OP_CL_SS: if (!cl_function_is_ok(sc, sc->code)) break;
92477 	case HOP_CL_SS: op_safe_c_ss(sc); continue; /* safe_c case has the code we want */
92478 
92479 	case OP_CL_A: if (!cl_function_is_ok(sc, sc->code)) {set_optimize_op(sc->code, OP_S_A); goto EVAL;}
92480 	case HOP_CL_A: op_cl_a(sc); continue;
92481 
92482 	case OP_CL_AA: if (!cl_function_is_ok(sc, sc->code)) break;
92483 	case HOP_CL_AA: op_cl_aa(sc); continue;
92484 
92485 	case OP_CL_SAS: if (!cl_function_is_ok(sc, sc->code)) break;
92486 	case HOP_CL_SAS: op_cl_sas(sc); continue;
92487 
92488 	case OP_CL_ALL_A: if (!cl_function_is_ok(sc, sc->code)) break;
92489 	case HOP_CL_ALL_A: op_cl_all_a(sc); continue;
92490 
92491 	case OP_CL_FA:  if (!cl_function_is_ok(sc, sc->code)) break;
92492 	case HOP_CL_FA: op_cl_fa(sc); continue;      /* op_c_fs was not faster if fx_s below */
92493 	case OP_MAP_FA: op_map_fa(sc); continue;     /* here only if for-each or map */
92494 
92495 
92496 	  /* unsafe c_functions */
92497 	case OP_C: if (!c_function_is_ok(sc, sc->code)) {set_optimize_op(sc->code, OP_S); goto EVAL;}
92498 	case HOP_C: sc->value = fn_proc(sc->code)(sc, sc->nil); continue;
92499 
92500 	case OP_C_S: if (!c_function_is_ok(sc, sc->code)) {set_optimize_op(sc->code, OP_S_S); goto EVAL;}
92501 	case HOP_C_S: op_c_s(sc); continue;
92502 
92503 	case OP_READ_S: if (!c_function_is_ok(sc, sc->code)) {set_optimize_op(sc->code, OP_S_S); goto EVAL;}
92504 	case HOP_READ_S: op_read_s(sc); continue;
92505 
92506 	case OP_C_A: if (!c_function_is_ok(sc, sc->code)) {set_optimize_op(sc->code, OP_S_A); goto EVAL;}
92507 	case HOP_C_A: op_c_a(sc); continue;
92508 
92509 	case OP_C_P: if (!c_function_is_ok(sc, sc->code)) break;
92510 	case HOP_C_P: op_c_p(sc); goto EVAL;
92511 
92512 	case OP_C_P_1: sc->value = fn_proc(sc->code)(sc, list_1(sc, sc->value)); continue;
92513 	case OP_C_P_MV: op_c_p_mv(sc); goto APPLY;
92514 
92515 	case OP_C_SS: if (!c_function_is_ok(sc, sc->code)) break;
92516 	case HOP_C_SS: op_c_ss(sc); continue;
92517 
92518 	case OP_C_AP: if (!c_function_is_ok(sc, sc->code)) break;
92519 	case HOP_C_AP: op_c_ap(sc); goto EVAL;
92520 	case OP_C_AP_1: sc->value = fn_proc(sc->code)(sc, sc->args = list_2(sc, sc->args, sc->value)); continue;
92521 	case OP_C_AP_MV: op_c_ap_mv(sc); goto APPLY;
92522 
92523 	case OP_C_AA: if (!c_function_is_ok(sc, sc->code)) break;
92524 	case HOP_C_AA: op_c_aa(sc); continue;
92525 
92526 	case OP_C_S_opSq: if (!c_function_is_ok_caddr(sc, sc->code))break;
92527 	case HOP_C_S_opSq: sc->value = op_c_s_opsq(sc); continue;
92528 
92529 	case OP_C_ALL_A: if (!c_function_is_ok(sc, sc->code)) break;
92530 	case HOP_C_ALL_A: op_c_all_a(sc); continue;
92531 
92532 	case OP_APPLY_SS: op_apply_ss(sc); goto APPLY;
92533 	case OP_APPLY_SA: op_apply_sa(sc); goto APPLY;
92534 	case OP_APPLY_SL: op_apply_sl(sc); goto APPLY;
92535 
92536 	case OP_CALL_WITH_EXIT: if (!c_function_is_ok(sc, sc->code)) break; check_lambda_args(sc, cadadr(sc->code), NULL);
92537 	case HOP_CALL_WITH_EXIT: op_call_with_exit(sc); goto BEGIN;
92538 	case OP_CALL_CC: op_call_cc(sc); goto BEGIN;
92539 
92540 	case OP_CALL_WITH_EXIT_O: if (!c_function_is_ok(sc, sc->code)) break; check_lambda_args(sc, cadadr(sc->code), NULL);
92541 	case HOP_CALL_WITH_EXIT_O: op_call_with_exit_o(sc); goto EVAL;
92542 
92543 	case OP_C_CATCH: if (!c_function_is_ok(sc, sc->code)) break; check_lambda_args(sc, cadr(cadddr(sc->code)), NULL);
92544 	case HOP_C_CATCH: op_c_catch(sc); goto BEGIN;
92545 
92546 	case OP_C_CATCH_ALL: if (!c_function_is_ok(sc, sc->code)) break;
92547 	case HOP_C_CATCH_ALL: op_c_catch_all(sc); goto BEGIN;
92548 
92549 	case OP_C_CATCH_ALL_O: if (!c_function_is_ok(sc, sc->code)) break;
92550 	case HOP_C_CATCH_ALL_O: op_c_catch_all(sc); goto EVAL;
92551 
92552 	case OP_C_CATCH_ALL_A: if (!c_function_is_ok(sc, sc->code)) break;
92553 	case HOP_C_CATCH_ALL_A: op_c_catch_all_a(sc); continue;
92554 
92555 	case OP_WITH_IO: if (op_with_io_op(sc)) goto EVAL; goto BEGIN;
92556 	case OP_WITH_IO_1:
92557 	  if (!is_string(sc->value)) {op_with_io_1_method(sc); continue;}
92558 	  sc->code = op_with_io_1(sc);
92559 	  goto BEGIN;
92560 
92561 	case OP_WITH_IO_C: sc->value = cadr(sc->code); sc->code = op_with_io_1(sc); goto BEGIN;
92562 	case OP_WITH_OUTPUT_TO_STRING:   op_with_output_to_string(sc);   goto BEGIN;
92563 	case OP_CALL_WITH_OUTPUT_STRING: op_call_with_output_string(sc); goto BEGIN;
92564 
92565 
92566 	case OP_S:    op_s(sc);       goto APPLY;
92567 	case OP_S_C:  op_s_c(sc);     goto APPLY;
92568 	case OP_S_S:  if (op_s_s(sc)) continue;  goto APPLY;
92569 
92570 	case OP_S_A:  op_x_a(sc, lookup_checked(sc, car(sc->code)));  goto APPLY;
92571 	case OP_A_A:  op_x_a(sc, fx_call(sc, sc->code));              goto APPLY;
92572 	case OP_S_AA: op_x_aa(sc, lookup_checked(sc, car(sc->code))); goto APPLY;
92573 	case OP_A_AA: op_x_aa(sc, fx_call(sc, sc->code));             goto APPLY;
92574 	case OP_P_S:  push_stack_no_args(sc, OP_P_S_1, sc->code); sc->code = car(sc->code); goto EVAL;
92575 	case OP_P_S_1: op_p_s_1(sc);                                  goto APPLY;
92576 
92577 	case OP_SAFE_C_FUNCTION_STAR: if (!c_function_is_ok(sc, sc->code)) break;
92578 	case HOP_SAFE_C_FUNCTION_STAR: op_safe_c_function_star(sc); continue;
92579 
92580 	case OP_SAFE_C_FUNCTION_STAR_A: if (!c_function_is_ok(sc, sc->code)) break;
92581 	case HOP_SAFE_C_FUNCTION_STAR_A: op_safe_c_function_star_a(sc); continue;
92582 
92583 	case OP_SAFE_C_FUNCTION_STAR_AA: if (!c_function_is_ok(sc, sc->code)) break;
92584 	case HOP_SAFE_C_FUNCTION_STAR_AA: op_safe_c_function_star_aa(sc); continue;
92585 
92586 	case OP_SAFE_C_FUNCTION_STAR_ALL_A: if (!c_function_is_ok(sc, sc->code)) break;
92587 	case HOP_SAFE_C_FUNCTION_STAR_ALL_A: op_safe_c_function_star_all_a(sc); continue;
92588 
92589 
92590 	case OP_THUNK: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 0)) {if (op_unknown(sc)) goto EVAL; continue;}
92591 	case HOP_THUNK: op_thunk(sc); goto EVAL;
92592 
92593 	case OP_SAFE_THUNK: if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 0)) {if (op_unknown(sc)) goto EVAL; continue;}
92594 	case HOP_SAFE_THUNK: op_safe_thunk(sc); goto EVAL;
92595 
92596 	case OP_THUNK_ANY: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 1)) break; /* symbol as arglist */
92597 	case HOP_THUNK_ANY: op_thunk_any(sc); goto BEGIN;
92598 
92599 	case OP_SAFE_THUNK_A: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_A, 0)) {if (op_unknown(sc)) goto EVAL; continue;}
92600 	case HOP_SAFE_THUNK_A: sc->value = op_safe_thunk_a(sc, sc->code); continue;
92601 
92602 	case OP_CLOSURE_S: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92603 	case HOP_CLOSURE_S: op_closure_s(sc); goto EVAL;
92604 
92605 	case OP_CLOSURE_S_O: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_P, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92606 	case HOP_CLOSURE_S_O: op_closure_s_o(sc); goto EVAL;
92607 
92608 	case OP_SAFE_CLOSURE_S: if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92609 	case HOP_SAFE_CLOSURE_S: op_safe_closure_s(sc); goto EVAL;
92610 
92611 	case OP_SAFE_CLOSURE_S_O: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_P, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92612 	case HOP_SAFE_CLOSURE_S_O: op_safe_closure_s_o(sc); goto EVAL;
92613 
92614 	case OP_SAFE_CLOSURE_S_A: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_A, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92615 	case HOP_SAFE_CLOSURE_S_A: sc->value = op_safe_closure_s_a(sc, sc->code); continue;
92616 
92617 	case OP_SAFE_CLOSURE_S_TO_S: if ((symbol_ctr(car(sc->code)) > 1) && (!closure_is_eq(sc))) {if (op_unknown_g(sc)) goto EVAL; continue;}
92618 	case HOP_SAFE_CLOSURE_S_TO_S: sc->value = fx_safe_closure_s_to_s(sc, sc->code); continue;
92619 
92620 	case OP_SAFE_CLOSURE_S_TO_SC: if ((symbol_ctr(car(sc->code)) > 1) && (!closure_is_eq(sc))) {if (op_unknown_g(sc)) goto EVAL; continue;}
92621 	case HOP_SAFE_CLOSURE_S_TO_SC: sc->value = fx_proc(cdr(sc->code))(sc, sc->code); continue;
92622 
92623 	case OP_SAFE_CLOSURE_A_TO_SC: if ((symbol_ctr(car(sc->code)) > 1) && (!closure_is_eq(sc))) {if (op_unknown_a(sc)) goto EVAL; continue;}
92624 	case HOP_SAFE_CLOSURE_A_TO_SC: sc->value = fx_proc(sc->code)(sc, sc->code); continue;
92625 
92626 	case OP_CLOSURE_C: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92627 	case HOP_CLOSURE_C: op_closure_c(sc); goto EVAL;
92628 
92629 	case OP_CLOSURE_C_O: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_P, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92630 	case HOP_CLOSURE_C_O: op_closure_c_o(sc); goto EVAL;
92631 
92632 	case OP_SAFE_CLOSURE_C: if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92633 	case HOP_SAFE_CLOSURE_C: op_safe_closure_c(sc); goto EVAL;
92634 
92635 	case OP_SAFE_CLOSURE_C_O: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_P, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92636 	case HOP_SAFE_CLOSURE_C_O: op_safe_closure_c_o(sc); goto EVAL;
92637 
92638 	case OP_SAFE_CLOSURE_C_A: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_A, 1)) {if (op_unknown_g(sc)) goto EVAL; continue;}
92639 	case HOP_SAFE_CLOSURE_C_A: op_safe_closure_c_a(sc); continue;
92640 
92641 	case OP_CLOSURE_P: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 1))  {if (op_unknown_fp(sc)) goto EVAL; continue;}
92642 	case HOP_CLOSURE_P: op_closure_p(sc); goto EVAL;
92643 	case OP_CLOSURE_P_1: op_closure_p_1(sc); goto BEGIN;
92644 
92645 	case OP_SAFE_CLOSURE_P:   if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 1))  {if (op_unknown_fp(sc)) goto EVAL; continue;}
92646 	case HOP_SAFE_CLOSURE_P:  op_safe_closure_p(sc);   goto EVAL;
92647 	case OP_SAFE_CLOSURE_P_1: op_safe_closure_p_1(sc); goto BEGIN;
92648 
92649 	case OP_SAFE_CLOSURE_P_A:   if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 1))  {if (op_unknown_fp(sc)) goto EVAL; continue;}
92650 	case HOP_SAFE_CLOSURE_P_A:  op_safe_closure_p_a(sc);   goto EVAL;
92651 	case OP_SAFE_CLOSURE_P_A_1: op_safe_closure_p_a_1(sc); continue;
92652 
92653 	case OP_CLOSURE_A: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_M, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92654 	case HOP_CLOSURE_A: op_closure_a(sc); push_stack_no_args(sc, sc->begin_op, T_Pair(cdr(sc->code))); sc->code = car(sc->code); goto EVAL;
92655 
92656 	case OP_CLOSURE_A_O: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_P, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92657 	case HOP_CLOSURE_A_O: op_closure_a(sc); sc->code = car(sc->code); goto EVAL;
92658 
92659 	case OP_SAFE_CLOSURE_A: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_M, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92660 	case HOP_SAFE_CLOSURE_A: op_safe_closure_a(sc); goto EVAL;
92661 
92662 	case OP_SAFE_CLOSURE_A_O: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_P, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92663 	case HOP_SAFE_CLOSURE_A_O: op_safe_closure_a_o(sc); goto EVAL;
92664 
92665 	case OP_SAFE_CLOSURE_A_A: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_A, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92666 	case HOP_SAFE_CLOSURE_A_A: sc->value = op_safe_closure_a_a(sc, sc->code); continue;
92667 
92668 	case OP_CLOSURE_AP: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 2)) {if (op_unknown_fp(sc)) goto EVAL; continue;}
92669 	case HOP_CLOSURE_AP: op_closure_ap(sc); goto EVAL;
92670 	case OP_CLOSURE_AP_1: op_closure_ap_1(sc); goto BEGIN;
92671 
92672 	case OP_CLOSURE_PA: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 2)) {if (op_unknown_fp(sc)) goto EVAL; continue;}
92673 	case HOP_CLOSURE_PA: op_closure_pa(sc); goto EVAL;
92674 	case OP_CLOSURE_PA_1: op_closure_pa_1(sc); goto BEGIN;
92675 
92676 	case OP_CLOSURE_PP: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 2))  {if (op_unknown_fp(sc)) goto EVAL; continue;}
92677 	case HOP_CLOSURE_PP: op_closure_pp(sc); goto EVAL;
92678 	case OP_CLOSURE_PP_1: op_closure_pp_1(sc); goto EVAL;
92679 
92680 	case OP_SAFE_CLOSURE_AP: if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 2)) {if (op_unknown_fp(sc)) goto EVAL; continue;}
92681 	case HOP_SAFE_CLOSURE_AP: op_safe_closure_ap(sc); goto EVAL;
92682 	case OP_SAFE_CLOSURE_AP_1: op_safe_closure_ap_1(sc); goto BEGIN;
92683 
92684 	case OP_SAFE_CLOSURE_PA: if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 2)) {if (op_unknown_fp(sc)) goto EVAL; continue;}
92685 	case HOP_SAFE_CLOSURE_PA: op_safe_closure_pa(sc); goto EVAL;
92686 	case OP_SAFE_CLOSURE_PA_1: op_safe_closure_pa_1(sc); goto BEGIN;
92687 
92688 	case OP_SAFE_CLOSURE_PP: if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 2))  {if (op_unknown_fp(sc)) goto EVAL; continue;}
92689 	case HOP_SAFE_CLOSURE_PP: op_safe_closure_pp(sc); goto EVAL;
92690 	case OP_SAFE_CLOSURE_PP_1: op_safe_closure_pp_1(sc); goto EVAL;
92691 
92692 	case OP_ANY_CLOSURE_3P:   if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 3)) {if (op_unknown_fp(sc)) goto EVAL; continue;}
92693 	case HOP_ANY_CLOSURE_3P:  op_any_closure_3p(sc); goto EVAL;
92694 	case OP_ANY_CLOSURE_3P_1: if (!op_any_closure_3p_1(sc)) goto EVAL; goto BEGIN;
92695 	case OP_ANY_CLOSURE_3P_2: if (!op_any_closure_3p_2(sc)) goto EVAL; goto BEGIN;
92696 	case OP_ANY_CLOSURE_3P_3: op_any_closure_3p_3(sc); goto BEGIN;
92697 
92698 	case OP_ANY_CLOSURE_4P:   if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 4))  {if (op_unknown_fp(sc)) goto EVAL; continue;}
92699 	case HOP_ANY_CLOSURE_4P:  op_any_closure_4p(sc); goto EVAL;
92700 	case OP_ANY_CLOSURE_4P_1: if (!op_any_closure_4p_1(sc)) goto EVAL; goto BEGIN;
92701 	case OP_ANY_CLOSURE_4P_2: if (!op_any_closure_4p_2(sc)) goto EVAL; goto BEGIN;
92702 	case OP_ANY_CLOSURE_4P_3: if (!op_any_closure_4p_3(sc)) goto EVAL; goto BEGIN;
92703 	case OP_ANY_CLOSURE_4P_4: op_any_closure_4p_4(sc); goto BEGIN;
92704 
92705 	case OP_CLOSURE_FA: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 2)) break;
92706 	case HOP_CLOSURE_FA: op_closure_fa(sc); goto EVAL;
92707 
92708 	case OP_CLOSURE_SS: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_M, 2)) {if (op_unknown_gg(sc)) goto EVAL; continue;}
92709 	case HOP_CLOSURE_SS: op_closure_ss(sc); goto EVAL;
92710 
92711 	case OP_CLOSURE_SS_O: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_P, 2)) {if (op_unknown_gg(sc)) goto EVAL; continue;}
92712 	case HOP_CLOSURE_SS_O: op_closure_ss_o(sc); goto EVAL;
92713 
92714 	case OP_SAFE_CLOSURE_SS: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_M, 2)) {if (op_unknown_gg(sc)) goto EVAL; continue;}
92715 	case HOP_SAFE_CLOSURE_SS: op_safe_closure_ss(sc); goto EVAL;
92716 
92717 	case OP_SAFE_CLOSURE_SS_O: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_P, 2)) {if (op_unknown_gg(sc)) goto EVAL; continue;}
92718 	case HOP_SAFE_CLOSURE_SS_O: op_safe_closure_ss_o(sc); goto EVAL;
92719 
92720 	case OP_SAFE_CLOSURE_SS_A: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_A, 2)) {if (op_unknown_gg(sc)) goto EVAL; continue;}
92721 	case HOP_SAFE_CLOSURE_SS_A: sc->value = op_safe_closure_ss_a(sc, sc->code); continue;
92722 
92723 	case OP_CLOSURE_3S: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 3)) {if (op_unknown_all_s(sc)) goto EVAL; continue;}
92724 	case HOP_CLOSURE_3S: op_closure_3s(sc); goto EVAL;
92725 
92726 	case OP_CLOSURE_4S: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 4)) {if (op_unknown_all_s(sc)) goto EVAL; continue;}
92727 	case HOP_CLOSURE_4S: op_closure_4s(sc); goto EVAL;
92728 
92729 	case OP_CLOSURE_SC: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_M, 2)) {if (op_unknown_gg(sc)) goto EVAL; continue;}
92730 	case HOP_CLOSURE_SC: op_closure_sc(sc); goto EVAL;
92731 
92732 	case OP_CLOSURE_SC_O: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_P, 2)) {if (op_unknown_gg(sc)) goto EVAL; continue;}
92733 	case HOP_CLOSURE_SC_O: op_closure_sc_o(sc); goto EVAL;
92734 
92735 	case OP_SAFE_CLOSURE_SC: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_M, 2)) {if (op_unknown_gg(sc)) goto EVAL; continue;}
92736 	case HOP_SAFE_CLOSURE_SC: op_safe_closure_sc(sc); goto EVAL;
92737 
92738 	case OP_SAFE_CLOSURE_SC_O: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_P, 2)) {if (op_unknown_gg(sc)) goto EVAL; continue;}
92739 	case HOP_SAFE_CLOSURE_SC_O: op_safe_closure_sc_o(sc); goto EVAL;
92740 
92741 	case OP_CLOSURE_AA: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_M, 2)) {if (op_unknown_aa(sc)) goto EVAL; continue;}
92742 	case HOP_CLOSURE_AA: op_closure_aa(sc); goto EVAL;
92743 
92744 	case OP_CLOSURE_AA_O: if (!closure_is_ok(sc, sc->code, OK_UNSAFE_CLOSURE_P, 2)) {if (op_unknown_aa(sc)) goto EVAL; continue;}
92745 	case HOP_CLOSURE_AA_O: op_closure_aa_o(sc); goto EVAL;
92746 
92747 	case OP_SAFE_CLOSURE_AA: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_M, 2)) {if (op_unknown_aa(sc)) goto EVAL; continue;}
92748 	case HOP_SAFE_CLOSURE_AA: op_safe_closure_aa(sc); goto EVAL;
92749 
92750 	case OP_SAFE_CLOSURE_AA_O: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_P, 2)) {if (op_unknown_aa(sc)) goto EVAL; continue;}
92751 	case HOP_SAFE_CLOSURE_AA_O: op_safe_closure_aa_o(sc); goto EVAL;
92752 
92753 	case OP_SAFE_CLOSURE_AA_A: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_A, 2)) {if (op_unknown_aa(sc)) goto EVAL; continue;}
92754 	case HOP_SAFE_CLOSURE_AA_A: sc->value = fx_safe_closure_aa_a(sc, sc->code); continue;
92755 
92756 	case OP_SAFE_CLOSURE_SSA: if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 3)) {if (op_unknown_fp(sc)) goto EVAL; continue;}
92757 	case HOP_SAFE_CLOSURE_SSA: op_safe_closure_ssa(sc); goto BEGIN;
92758 
92759 	case OP_SAFE_CLOSURE_SAA: if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 3)) {if (op_unknown_fp(sc)) goto EVAL; continue;}
92760 	case HOP_SAFE_CLOSURE_SAA: op_safe_closure_saa(sc); goto BEGIN;
92761 
92762 	case OP_SAFE_CLOSURE_AGG: if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 3)) {if (op_unknown_fp(sc)) goto EVAL; continue;}
92763 	case HOP_SAFE_CLOSURE_AGG: op_safe_closure_agg(sc); goto BEGIN;
92764 
92765 	case OP_SAFE_CLOSURE_ALL_S:  if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, integer(opt3_arglen(cdr(sc->code))))) {if (op_unknown_all_s(sc)) goto EVAL; continue;}
92766 	case HOP_SAFE_CLOSURE_ALL_S: op_safe_closure_all_s(sc); goto EVAL;
92767 
92768 	case OP_SAFE_CLOSURE_ALL_A:  if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, integer(opt3_arglen(cdr(sc->code))))) {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92769 	case HOP_SAFE_CLOSURE_ALL_A: op_safe_closure_all_a(sc); goto EVAL;
92770 
92771 	case OP_SAFE_CLOSURE_3S:  if (!closure_is_fine(sc, sc->code, FINE_SAFE_CLOSURE, 3)) {if (op_unknown_all_s(sc)) goto EVAL; continue;}
92772 	case HOP_SAFE_CLOSURE_3S: op_safe_closure_3s(sc); goto BEGIN;
92773 
92774 	case OP_SAFE_CLOSURE_3S_A: if (!closure_is_ok(sc, sc->code, OK_SAFE_CLOSURE_A, 3)) {if (op_unknown_all_s(sc)) goto EVAL; continue;}
92775 	case HOP_SAFE_CLOSURE_3S_A: sc->value = op_safe_closure_3s_a(sc, sc->code); continue;
92776 
92777 	case OP_CLOSURE_ALL_S:  if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, integer(opt3_arglen(cdr(sc->code))))) {if (op_unknown_all_s(sc)) goto EVAL; continue;}
92778 	case HOP_CLOSURE_ALL_S: op_closure_all_s(sc); goto EVAL;
92779 
92780 	case OP_CLOSURE_ASS:  if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 3)) {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92781 	case HOP_CLOSURE_ASS: op_closure_ass(sc); goto EVAL;
92782 
92783 	case OP_CLOSURE_AAS:  if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 3)) {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92784 	case HOP_CLOSURE_AAS: op_closure_aas(sc); goto EVAL;
92785 
92786 	case OP_CLOSURE_SAA:  if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 3)) {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92787 	case HOP_CLOSURE_SAA: op_closure_saa(sc); goto EVAL;
92788 
92789 	case OP_CLOSURE_ASA:  if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 3)) {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92790 	case HOP_CLOSURE_ASA: op_closure_asa(sc); goto EVAL;
92791 
92792 	case OP_CLOSURE_SAS:  if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 3)) {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92793 	case HOP_CLOSURE_SAS: op_closure_sas(sc); goto EVAL;
92794 
92795 	case OP_CLOSURE_3A:  if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 3)) {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92796 	case HOP_CLOSURE_3A: op_closure_3a(sc); goto EVAL;
92797 
92798  	case OP_CLOSURE_4A:  if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, 4)) {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92799  	case HOP_CLOSURE_4A: op_closure_4a(sc); goto EVAL;
92800 
92801 	case OP_CLOSURE_ALL_A: if (!closure_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE, integer(opt3_arglen(cdr(sc->code))))) {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92802 	case HOP_CLOSURE_ALL_A: op_closure_all_a(sc); goto EVAL;
92803 
92804 	case OP_CLOSURE_ANY_ALL_A: if (!check_closure_any(sc)) break;
92805 	case HOP_CLOSURE_ANY_ALL_A: op_closure_any_all_a(sc); goto BEGIN;
92806 
92807 	case OP_ANY_CLOSURE_FP: if (!closure_fp_is_ok(sc, sc->code, integer(opt3_arglen(cdr(sc->code))))) {if (op_unknown_fp(sc)) goto EVAL; continue;}
92808 	case HOP_ANY_CLOSURE_FP: op_any_closure_fp(sc); goto EVAL;
92809 	case OP_ANY_CLOSURE_FP_1:
92810 	  if (!(collect_fp_args(sc, OP_ANY_CLOSURE_FP_1, cons(sc, sc->value, sc->args))))
92811 	    op_any_closure_fp_end(sc);
92812 	  goto EVAL;
92813 	case OP_ANY_CLOSURE_FP_2:
92814 	  sc->args = cons(sc, sc->value, sc->args);
92815 	  op_any_closure_fp_end(sc);
92816 	  goto EVAL;
92817 	case OP_ANY_CLOSURE_FP_MV_1:
92818 	  if (!(collect_fp_args(sc, OP_ANY_CLOSURE_FP_MV_1, (is_multiple_value(sc->value)) ? revappend(sc, sc->value, sc->args) : cons(sc, sc->value, sc->args))))
92819 	    op_any_closure_fp_end(sc);
92820 	  goto EVAL;
92821 
92822 
92823 	case OP_TC_AND_A_OR_A_LA:         tick_tc(sc, sc->cur_op); op_tc_and_a_or_a_la(sc, sc->code);                       continue;
92824 	case OP_TC_OR_A_AND_A_LA:         tick_tc(sc, sc->cur_op); op_tc_or_a_and_a_la(sc, sc->code);                       continue;
92825 	case OP_TC_AND_A_OR_A_LAA:        tick_tc(sc, sc->cur_op); op_tc_and_a_or_a_laa(sc, sc->code);                      continue;
92826 	case OP_TC_OR_A_AND_A_LAA:        tick_tc(sc, sc->cur_op); op_tc_or_a_and_a_laa(sc, sc->code);                      continue;
92827 	case OP_TC_AND_A_OR_A_A_LA:       tick_tc(sc, sc->cur_op); op_tc_and_a_or_a_a_la(sc, sc->code);                     continue;
92828 	case OP_TC_OR_A_AND_A_A_LA:       tick_tc(sc, sc->cur_op); op_tc_or_a_and_a_a_la(sc, sc->code);                     continue;
92829 	case OP_TC_OR_A_A_AND_A_A_LA:     tick_tc(sc, sc->cur_op); op_tc_or_a_a_and_a_a_la(sc, sc->code);                   continue;
92830 	case OP_TC_OR_A_AND_A_A_L3A:      tick_tc(sc, sc->cur_op); op_tc_or_a_and_a_a_l3a(sc, sc->code);                    continue;
92831 
92832 	case OP_TC_IF_A_Z_LA:             tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_la(sc, sc->code, false))                continue; goto EVAL;
92833 	case OP_TC_IF_A_LA_Z:             tick_tc(sc, sc->cur_op); if (op_tc_if_a_la_z(sc, sc->code, false))                continue; goto EVAL;
92834 	case OP_TC_COND_A_Z_LA:           tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_la(sc, sc->code, true))                 continue; goto EVAL;
92835 	case OP_TC_COND_A_LA_Z:           tick_tc(sc, sc->cur_op); if (op_tc_if_a_la_z(sc, sc->code, true))                 continue; goto EVAL;
92836 
92837 	case OP_TC_IF_A_LAA_Z:            tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_laa(sc, sc->code, false, TC_IF))        continue; goto EVAL;
92838 	case OP_TC_IF_A_Z_LAA:            tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_laa(sc, sc->code, true, TC_IF))         continue; goto EVAL;
92839 	case OP_TC_COND_A_Z_LAA:          tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_laa(sc, sc->code, true, TC_COND))       continue; goto EVAL;
92840 	case OP_TC_COND_A_LAA_Z:          tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_laa(sc, sc->code, false, TC_COND))      continue; goto EVAL;
92841 
92842 	case OP_TC_IF_A_Z_L3A:            tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_l3a(sc, sc->code, true))                continue; goto EVAL;
92843 	case OP_TC_IF_A_L3A_Z:            tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_l3a(sc, sc->code, false))               continue; goto EVAL;
92844 
92845 	case OP_TC_IF_A_Z_IF_A_Z_LA:      tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_z_la(sc, sc->code, true, TC_IF))   continue; goto EVAL;
92846 	case OP_TC_IF_A_Z_IF_A_LA_Z:      tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_z_la(sc, sc->code, false, TC_IF))  continue; goto EVAL;
92847 	case OP_TC_COND_A_Z_A_Z_LA:       tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_z_la(sc, sc->code, true, TC_COND)) continue; goto EVAL;
92848 	case OP_TC_COND_A_Z_A_LA_Z:       tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_z_la(sc, sc->code, false, TC_COND))continue; goto EVAL;
92849  	case OP_TC_AND_A_IF_A_LA_Z:       tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_z_la(sc, sc->code, false, TC_AND)) continue; goto EVAL;
92850  	case OP_TC_AND_A_IF_A_Z_LA:       tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_z_la(sc, sc->code, true, TC_AND))  continue; goto EVAL;
92851 
92852 	case OP_TC_IF_A_Z_IF_A_Z_LAA:     tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_z_laa(sc, false, sc->code))        continue; goto EVAL;
92853 	case OP_TC_IF_A_Z_IF_A_LAA_Z:     tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_laa_z(sc, false, sc->code))        continue; goto EVAL;
92854 	case OP_TC_COND_A_Z_A_Z_LAA:      tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_z_laa(sc, true, sc->code))         continue; goto EVAL;
92855 	case OP_TC_COND_A_Z_A_LAA_Z:      tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_laa_z(sc, true, sc->code))         continue; goto EVAL;
92856 
92857 	case OP_TC_LET_IF_A_Z_LA:         tick_tc(sc, sc->cur_op); if (op_tc_let_if_a_z_la(sc, sc->code))                   continue; goto EVAL;
92858 	case OP_TC_LET_IF_A_Z_LAA:        tick_tc(sc, sc->cur_op); if (op_tc_let_if_a_z_laa(sc, sc->code))                  continue; goto EVAL;
92859 	case OP_TC_LET_WHEN_LAA:          tick_tc(sc, sc->cur_op); op_tc_let_when_laa(sc, true, sc->code);                  continue;
92860 	case OP_TC_LET_UNLESS_LAA:        tick_tc(sc, sc->cur_op); op_tc_let_when_laa(sc, false, sc->code);                 continue;
92861 
92862 	case OP_TC_COND_A_Z_A_LAA_LAA:    tick_tc(sc, sc->cur_op); if (op_tc_cond_a_z_a_laa_laa(sc, sc->code))              continue; goto EVAL;
92863 	case OP_TC_IF_A_Z_IF_A_L3A_L3A:   tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_if_a_l3a_l3a(sc, sc->code))             continue; goto EVAL;
92864 	case OP_TC_IF_A_Z_LET_IF_A_Z_LAA: tick_tc(sc, sc->cur_op); if (op_tc_if_a_z_let_if_a_z_laa(sc, sc->code))           continue; goto EVAL;
92865 	case OP_TC_CASE_LA:               tick_tc(sc, sc->cur_op); if (op_tc_case_la(sc, sc->code))                         continue; goto BEGIN;
92866 	case OP_TC_LET_COND:              tick_tc(sc, sc->cur_op); if (op_tc_let_cond(sc, sc->code))                        continue; goto EVAL;
92867 
92868 	case OP_RECUR_IF_A_A_opA_LAq:           wrap_recur_if_a_a_opa_laq(sc, true, true);         continue;
92869  	case OP_RECUR_IF_A_A_opLA_Aq:           wrap_recur_if_a_a_opa_laq(sc, true, false);        continue;
92870 	case OP_RECUR_IF_A_opA_LAq_A:           wrap_recur_if_a_a_opa_laq(sc, false, true);        continue;
92871 	case OP_RECUR_IF_A_opLA_Aq_A:           wrap_recur_if_a_a_opa_laq(sc, false, false);       continue;
92872 	case OP_RECUR_IF_A_A_opA_LAAq:          wrap_recur(sc, op_recur_if_a_a_opa_laaq);          continue;
92873 	case OP_RECUR_IF_A_A_opA_L3Aq:          wrap_recur(sc, op_recur_if_a_a_opa_l3aq);          continue;
92874 	case OP_RECUR_IF_A_opA_LAAq_A:          wrap_recur(sc, op_recur_if_a_opa_laaq_a);          continue;
92875 	case OP_RECUR_IF_A_A_opLA_LAq:          wrap_recur_if_a_a_opla_laq(sc, true);              continue;
92876 	case OP_RECUR_IF_A_opLA_LAq_A:          wrap_recur_if_a_a_opla_laq(sc, false);             continue;
92877 	case OP_RECUR_IF_A_A_opA_LA_LAq:        wrap_recur(sc, op_recur_if_a_a_opa_la_laq);        continue;
92878 	case OP_RECUR_IF_A_opA_LA_LAq_A:        wrap_recur(sc, op_recur_if_a_opa_la_laq_a);        continue;
92879 	case OP_RECUR_IF_A_A_LopL3A_L3A_L3Aq:   wrap_recur(sc, op_recur_if_a_a_lopl3a_l3a_l3aq);   continue;
92880 	case OP_RECUR_IF_A_A_AND_A_LAA_LAA:     wrap_recur(sc, op_recur_if_a_a_and_a_laa_laa);     continue;
92881 	case OP_RECUR_IF_A_A_opLA_LA_LAq:       wrap_recur(sc, op_recur_if_a_a_opla_la_laq);       continue;
92882 	case OP_RECUR_IF_A_A_IF_A_LAA_opA_LAAq: wrap_recur(sc, op_recur_if_a_a_if_a_laa_opa_laaq); continue;
92883 	case OP_RECUR_IF_A_A_IF_A_A_opLA_LAq:   wrap_recur(sc, op_recur_if_a_a_if_a_a_opla_laq);   continue;
92884 	case OP_RECUR_IF_A_A_IF_A_A_opLAA_LAAq: wrap_recur(sc, op_recur_if_a_a_if_a_a_oplaa_laaq); continue;
92885 	case OP_RECUR_COND_A_A_opA_LAq:         wrap_recur(sc, op_recur_cond_a_a_opa_laq);         continue;
92886 	case OP_RECUR_COND_A_A_opA_LAAq:        wrap_recur(sc, op_recur_cond_a_a_opa_laaq);        continue;
92887 	case OP_RECUR_COND_A_A_A_A_opLA_LAq:    wrap_recur(sc, op_recur_cond_a_a_a_a_opla_laq);    continue;
92888 	case OP_RECUR_COND_A_A_A_A_opA_LAAq:    wrap_recur(sc, op_recur_cond_a_a_a_a_opa_laaq);    continue;
92889 	case OP_RECUR_COND_A_A_A_A_opLAA_LAAq:  wrap_recur(sc, op_recur_cond_a_a_a_a_oplaa_laaq);  continue;
92890 	case OP_RECUR_COND_A_A_A_LAA_opA_LAAq:  wrap_recur(sc, op_recur_cond_a_a_a_laa_opa_laaq);  continue;
92891 	case OP_RECUR_COND_A_A_A_LAA_LopA_LAAq: wrap_recur_cond_a_a_a_laa_lopa_laaq(sc);           continue;
92892 	case OP_RECUR_AND_A_OR_A_LAA_LAA:       wrap_recur(sc, op_recur_and_a_or_a_laa_laa);       continue;
92893 
92894 
92895 	case OP_SAFE_CLOSURE_STAR_A: if (!closure_star_is_fine(sc, sc->code, FINE_SAFE_CLOSURE_STAR, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92896 	case HOP_SAFE_CLOSURE_STAR_A: op_safe_closure_star_a(sc, sc->code); goto BEGIN;
92897 
92898 	case OP_SAFE_CLOSURE_STAR_A1: if (!closure_star_is_fine(sc, sc->code, FINE_SAFE_CLOSURE_STAR, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92899 	case HOP_SAFE_CLOSURE_STAR_A1: op_safe_closure_star_a1(sc, sc->code); goto BEGIN;
92900 
92901 	case OP_SAFE_CLOSURE_STAR_KA: if (!closure_star_is_fine(sc, sc->code, FINE_SAFE_CLOSURE_STAR, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92902 	case HOP_SAFE_CLOSURE_STAR_KA: op_safe_closure_star_ka(sc, sc->code); goto BEGIN;
92903 
92904 	case OP_SAFE_CLOSURE_STAR_AA: if (!closure_star_is_fine(sc, sc->code, FINE_SAFE_CLOSURE_STAR, 2)) {if (op_unknown_aa(sc)) goto EVAL; continue;}
92905 	case HOP_SAFE_CLOSURE_STAR_AA: op_safe_closure_star_aa(sc, sc->code); goto BEGIN;
92906 
92907 	case OP_SAFE_CLOSURE_STAR_AA_O: if (!closure_star_is_fine(sc, sc->code, FINE_SAFE_CLOSURE_STAR, 2)) {if (op_unknown_aa(sc)) goto EVAL; continue;}
92908 	case HOP_SAFE_CLOSURE_STAR_AA_O: op_safe_closure_star_aa(sc, sc->code); sc->code = car(sc->code); goto EVAL;
92909 
92910 	case OP_SAFE_CLOSURE_STAR_ALL_A:
92911 	  if (!closure_star_is_fine(sc, sc->code, FINE_SAFE_CLOSURE_STAR, (is_pair(cdr(sc->code))) ? integer(opt3_arglen(cdr(sc->code))) : 0))
92912 	    {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92913 	case HOP_SAFE_CLOSURE_STAR_ALL_A: if (op_safe_closure_star_all_a(sc, sc->code)) goto EVAL; goto BEGIN;
92914 
92915 	case OP_SAFE_CLOSURE_STAR_ALL_A_0: if (!closure_star_is_fine(sc, sc->code, FINE_SAFE_CLOSURE_STAR, 0)) {if (op_unknown(sc)) goto EVAL; continue;}
92916 	case HOP_SAFE_CLOSURE_STAR_ALL_A_0: if (op_safe_closure_star_all_a_0(sc, sc->code)) goto EVAL; goto BEGIN;
92917 
92918 	case OP_SAFE_CLOSURE_STAR_ALL_A_1: if (!closure_star_is_fine(sc, sc->code, FINE_SAFE_CLOSURE_STAR, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92919 	case HOP_SAFE_CLOSURE_STAR_ALL_A_1: if (op_safe_closure_star_all_a_1(sc, sc->code)) goto EVAL; goto BEGIN;
92920 
92921 	case OP_SAFE_CLOSURE_STAR_ALL_A_2: if (!closure_star_is_fine(sc, sc->code, FINE_SAFE_CLOSURE_STAR, 2)) {if (op_unknown_aa(sc)) goto EVAL; continue;}
92922 	case HOP_SAFE_CLOSURE_STAR_ALL_A_2: if (op_safe_closure_star_all_a_2(sc, sc->code)) goto EVAL; goto BEGIN;
92923 
92924 
92925 	case OP_CLOSURE_STAR_A: if (!closure_star_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE_STAR, 1)) {if (op_unknown_a(sc)) goto EVAL; continue;}
92926 	case HOP_CLOSURE_STAR_A: op_closure_star_a(sc, sc->code); goto BEGIN;
92927 
92928 	case OP_CLOSURE_STAR_KA: if (!closure_star_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE_STAR, 1)) {if (op_unknown_aa(sc)) goto EVAL; continue;}
92929 	case HOP_CLOSURE_STAR_KA: op_closure_star_ka(sc, sc->code); goto BEGIN;
92930 
92931 	case OP_CLOSURE_STAR_ALL_A:
92932 	  if (!closure_star_is_fine(sc, sc->code, FINE_UNSAFE_CLOSURE_STAR, (is_pair(cdr(sc->code))) ? integer(opt3_arglen(cdr(sc->code))) : 0))
92933 	    {if (op_unknown_all_a(sc)) goto EVAL; continue;}
92934 	case HOP_CLOSURE_STAR_ALL_A: if (op_closure_star_all_a(sc, sc->code)) goto EVAL; goto BEGIN;
92935 
92936 
92937 	case OP_UNKNOWN:       sc->last_function = lookup_checked(sc, car(sc->code)); if (op_unknown(sc)) goto EVAL;       continue;
92938 	case OP_UNKNOWN_ALL_S: sc->last_function = lookup_checked(sc, car(sc->code)); if (op_unknown_all_s(sc)) goto EVAL; continue;
92939 	case OP_UNKNOWN_G:     sc->last_function = lookup_checked(sc, car(sc->code)); if (op_unknown_g(sc)) goto EVAL;     continue;
92940 	case OP_UNKNOWN_GG:    sc->last_function = lookup_checked(sc, car(sc->code)); if (op_unknown_gg(sc)) goto EVAL;    continue;
92941 	case OP_UNKNOWN_A:     sc->last_function = lookup_checked(sc, car(sc->code)); if (op_unknown_a(sc)) goto EVAL;     continue;
92942 	case OP_UNKNOWN_AA:    sc->last_function = lookup_checked(sc, car(sc->code)); if (op_unknown_aa(sc)) goto EVAL;    continue;
92943 	case OP_UNKNOWN_ALL_A: sc->last_function = lookup_checked(sc, car(sc->code)); if (op_unknown_all_a(sc)) goto EVAL; continue;
92944 	case OP_UNKNOWN_FP:    sc->last_function = lookup_checked(sc, car(sc->code)); if (op_unknown_fp(sc)) goto EVAL;    continue;
92945 
92946 
92947 	case OP_IMPLICIT_VECTOR_REF_A:     if (op_implicit_vector_ref_a(sc) != goto_start)  {if (op_unknown_a(sc)) goto EVAL;}  continue;
92948 	case OP_IMPLICIT_VECTOR_REF_AA:    if (op_implicit_vector_ref_aa(sc) != goto_start) {if (op_unknown_aa(sc)) goto EVAL;} continue;
92949 	case OP_IMPLICIT_STRING_REF_A:     if (op_implicit_string_ref_a(sc) != goto_start)  {if (op_unknown_a(sc)) goto EVAL;}  continue;
92950 	case OP_IMPLICIT_HASH_TABLE_REF_A: if (!op_implicit_hash_table_ref_a(sc)) {if (op_unknown_a(sc)) goto EVAL;}  continue;
92951 	case OP_IMPLICIT_CONTINUATION_A:   if (!op_implicit_continuation_a(sc))   {if (op_unknown_a(sc)) goto EVAL;}  continue;
92952 	case OP_IMPLICIT_ITERATE:          if (!op_implicit_iterate(sc))          {if (op_unknown(sc)) goto EVAL;}    continue;
92953 	case OP_IMPLICIT_LET_REF_C:        if (!op_implicit_let_ref_c(sc))        {if ((has_fx(cdr(sc->code))) && (op_unknown_a(sc))) goto EVAL;} continue;
92954 	case OP_IMPLICIT_LET_REF_A:        if (!op_implicit_let_ref_a(sc))        {if (op_unknown_a(sc)) goto EVAL;}  continue;
92955 	case OP_IMPLICIT_PAIR_REF_A:       if (!op_implicit_pair_ref_a(sc))       {if (op_unknown_a(sc)) goto EVAL;}  continue;
92956 	case OP_IMPLICIT_C_OBJECT_REF_A:   if (!op_implicit_c_object_ref_a(sc))   {if (op_unknown_a(sc)) goto EVAL;}  continue;
92957 	case OP_IMPLICIT_GOTO:             if (!op_implicit_goto(sc))             {if (op_unknown(sc)) goto EVAL;}    continue;
92958 	case OP_IMPLICIT_GOTO_A:           if (!op_implicit_goto_a(sc))           {if (op_unknown_a(sc)) goto EVAL;}  continue;
92959 	case OP_IMPLICIT_VECTOR_SET_3:     if (op_implicit_vector_set_3(sc)) goto EVAL; continue;
92960 	case OP_IMPLICIT_VECTOR_SET_4:     if (op_implicit_vector_set_4(sc)) goto EVAL; continue;
92961 	case OP_IMPLICIT_S7_LET_REF_S:	   sc->value = s7_let_field(sc, opt3_sym(sc->code)); continue;
92962 	case OP_IMPLICIT_S7_LET_SET_SA:	   sc->value = s7_let_field_set(sc, opt3_sym(cdr(sc->code)), fx_call(sc, cddr(sc->code))); continue;
92963 
92964 
92965 	case OP_UNOPT:       goto UNOPT;
92966 	case OP_SYM:         sc->value = lookup_checked(sc, sc->code);     continue;
92967 	case OP_GLOBAL_SYM:  sc->value = lookup_global(sc, sc->code);      continue;
92968 	case OP_CON:         sc->value = sc->code;                         continue;
92969 	case OP_PAIR_PAIR:   op_pair_pair(sc);                             goto EVAL;         /* car is pair ((if x car cadr) ...) */
92970 	case OP_PAIR_ANY:    sc->value = car(sc->code);                    goto EVAL_ARGS_TOP;
92971 	case OP_PAIR_SYM:    sc->value = lookup_global(sc, car(sc->code)); goto EVAL_ARGS_TOP;
92972 
92973 	case OP_EVAL_ARGS5: op_eval_args5(sc); goto APPLY;
92974 	case OP_EVAL_ARGS2: op_eval_args2(sc); goto APPLY; /* sc->value is the last arg, [so if is_null(cdr(sc->code) and current is pair, push args2] */
92975 	case OP_EVAL_ARGS3: op_eval_args3(sc); goto APPLY; /* sc->value is the next-to-last arg, and we know the last arg is not a list (so values can't mess us up!) */
92976 	case OP_EVAL_ARGS4: sc->args = cons(sc, sc->value, sc->args); goto EVAL_ARGS_PAIR;
92977 	case OP_EVAL_ARGS1: sc->args = cons(sc, sc->value, sc->args); goto EVAL_ARGS;
92978 
92979 	EVAL_ARGS_TOP:
92980 	case OP_EVAL_ARGS:
92981 	  if (dont_eval_args(sc->value))
92982 	    {
92983 	      if (eval_args_no_eval_args(sc)) goto APPLY;
92984 	      goto TOP_NO_POP;
92985 	    }
92986 	  sc->code = cdr(sc->code);
92987 	  /* sc->value is the func (but can be anything if the code is messed up: (#\a 3))
92988 	   *   we don't have to delay lookup of the func because arg evaluation order is not specified, so
92989 	   *     (let ((func +)) (func (let () (set! func -) 3) 2))
92990 	   *   can return 5.
92991 	   */
92992 	  push_op_stack(sc, sc->value);
92993 	  if (sc->op_stack_now >= sc->op_stack_end)
92994 	    resize_op_stack(sc);
92995 	  sc->args = sc->nil;
92996 
92997 	EVAL_ARGS:	          /* first time, value = op, args = nil, code is args */
92998 	  if (is_pair(sc->code))  /* evaluate current arg -- must check for pair here, not sc->nil (improper list as args) */
92999 	    {
93000 	      if ((sc->safety > NO_SAFETY) &&
93001 		  (tree_is_cyclic(sc, sc->code)))
93002 		eval_error(sc, "attempt to evaluate a circular list: ~A", 39, sc->code);
93003 
93004 	    EVAL_ARGS_PAIR:
93005 	      if (is_pair(car(sc->code)))
93006 		{
93007 		  eval_args_pair_car(sc);
93008 		  goto EVAL;
93009 		}
93010 	      if (is_pair(cdr(sc->code)))
93011 		{
93012 		  s7_pointer car_code;
93013 		  car_code = car(sc->code); /* not a pair */
93014 		  sc->code = cdr(sc->code);
93015 		  sc->value = (is_symbol(car_code)) ? lookup_checked(sc, car_code) : T_Pos(car_code);
93016 		  /* sc->value is the current arg's value, sc->code is pointing to the next */
93017 
93018 		  /* cdr(sc->code) might not be a pair or nil here! (eq? #f . 1) -> sc->code is 1 */
93019 		  if (is_null(cdr(sc->code)))
93020 		    {
93021 		      if (eval_args_last_arg(sc)) goto EVAL;
93022 		      /* drop into APPLY */
93023 		    }
93024 		  else
93025 		    {
93026 		      /* here we know sc->code is a pair, cdr(sc->code) is not null, sc->value is the previous arg's value */
93027 		      sc->args = cons(sc, sc->value, sc->args);
93028 		      goto EVAL_ARGS_PAIR;
93029 		    }}
93030 	      else eval_last_arg(sc, car(sc->code));
93031 	      /* drop into APPLY */
93032 	    }
93033 	  else                       /* got all args -- go to apply */
93034 	    { /* *(--sc->op_stack_now) is the "function" (sc->value perhaps), sc->code is the arglist end, sc->args might be the preceding args reversed? */
93035 	      if (is_not_null(sc->code))
93036 		improper_arglist_error(sc);
93037 	      else
93038 		{
93039 		  sc->code = pop_op_stack(sc);
93040 		  sc->args = proper_list_reverse_in_place(sc, sc->args);
93041 		}}
93042 
93043 	  /* turning this into a call on an array of functions was not a complete disaster, but tauto.scm was ~1.5% slower.
93044 	   *   the array-index overhead is the same as the current switch statement's, but there was also the boolean+jump overhead,
93045 	   *   and the function-local overhead currently otherwise 0 if inlined.
93046 	   */
93047 	APPLY:
93048 	case OP_APPLY:
93049 	  /* set_current_code(sc, history_cons(sc, sc->code, sc->args)); */
93050 #if SHOW_EVAL_OPS
93051 	  safe_print(fprintf(stderr, "  apply %s (%s) to %s\n", display_80(sc->code), s7_type_names[type(sc->code)], display_80(sc->args)));
93052 #endif
93053 	  switch (type(sc->code))
93054 	    {
93055 	    case T_C_FUNCTION:          apply_c_function(sc);           continue;
93056 	    case T_C_ANY_ARGS_FUNCTION: apply_c_any_args_function(sc);  continue;
93057 	    case T_C_FUNCTION_STAR:     apply_c_function_star(sc);      continue;
93058 	    case T_C_OPT_ARGS_FUNCTION: apply_c_opt_args_function(sc);  continue;
93059 	    case T_C_RST_ARGS_FUNCTION: apply_c_rst_args_function(sc);  continue;
93060 	    case T_CONTINUATION:        apply_continuation(sc);         continue;
93061 	    case T_GOTO:	        call_with_exit(sc);	        continue;
93062 	    case T_C_OBJECT:	        apply_c_object(sc);	        continue;
93063 	    case T_STRING:	        apply_string(sc);	        continue;
93064 	    case T_HASH_TABLE:	        apply_hash_table(sc);           continue;
93065 	    case T_ITERATOR:	        apply_iterator(sc);	        continue;
93066 	    case T_LET:	                apply_let(sc);	                continue;
93067 	    case T_INT_VECTOR:
93068 	    case T_BYTE_VECTOR:
93069 	    case T_FLOAT_VECTOR:
93070 	    case T_VECTOR: 	        apply_vector(sc);	        continue;
93071 	    case T_SYNTAX:	        apply_syntax(sc); 	        goto TOP_NO_POP;
93072 	    case T_PAIR:	        if (apply_pair(sc)) continue;   goto APPLY;
93073 	    case T_CLOSURE:             apply_closure(sc);              goto APPLY_LAMBDA;
93074 	    case T_CLOSURE_STAR:        if (apply_closure_star(sc)) goto EVAL; goto BEGIN;
93075 	    case T_C_MACRO:  	        apply_c_macro(sc);	        goto EVAL;
93076 	    case T_MACRO:               apply_macro(sc);                goto APPLY_LAMBDA;
93077 	    case T_BACRO:               apply_bacro(sc);                goto APPLY_LAMBDA;
93078 	    case T_MACRO_STAR:          apply_macro_star(sc);           goto BEGIN;
93079 	    case T_BACRO_STAR:          apply_bacro_star(sc);           goto BEGIN;
93080 	    default:	                apply_error(sc, sc->code, sc->args);
93081 	    }
93082 
93083 	case OP_MACRO_STAR_D: if (op_macro_star_d(sc)) goto EVAL_ARGS_TOP; goto BEGIN;
93084 	case OP_MACRO_D:      if (op_macro_d(sc)) goto EVAL_ARGS_TOP;
93085 
93086 	APPLY_LAMBDA:
93087 	case OP_APPLY_LAMBDA:
93088 	  apply_lambda(sc);
93089 	  goto BEGIN;
93090 
93091 	case OP_LAMBDA_STAR_DEFAULT: if (op_lambda_star_default(sc)) goto EVAL; goto BEGIN;
93092 
93093 	case OP_MACROEXPAND_1:
93094 	  switch (op_macroexpand_1(sc)) {case goto_begin: goto BEGIN; case goto_eval: goto EVAL; case goto_start: continue; default: goto APPLY_LAMBDA;}
93095 
93096 	case OP_MACROEXPAND:
93097 	  switch (op_macroexpand(sc)) {case goto_begin: goto BEGIN; case goto_eval: goto EVAL; case goto_start: continue; default: goto APPLY_LAMBDA;}
93098 
93099 
93100 	HEAPSORT: if (op_heapsort(sc)) continue; if (sc->value != sc->F) goto APPLY;
93101 	case OP_SORT1: op_sort1(sc); goto APPLY;
93102 	case OP_SORT2: if (op_sort2(sc)) continue; goto HEAPSORT;
93103 	case OP_SORT:  if (!op_sort(sc)) goto HEAPSORT;
93104 	case OP_SORT3: if (op_sort3(sc)) continue; goto HEAPSORT;
93105 	case OP_SORT_PAIR_END:   sc->value = vector_into_list(sc, sc->value, car(sc->args)); continue;
93106 	case OP_SORT_VECTOR_END: sc->value = vector_into_fi_vector(sc->value, car(sc->args)); continue;
93107 	case OP_SORT_STRING_END: sc->value = vector_into_string(sc->value, car(sc->args)); continue;
93108 
93109 
93110 	case OP_MAP_GATHER: op_map_gather(sc);
93111 	case OP_MAP: if (op_map(sc)) continue; goto APPLY;
93112 
93113 	case OP_MAP_GATHER_1: op_map_gather(sc);
93114 	case OP_MAP_1: if (op_map_1(sc)) continue; goto BEGIN;
93115 
93116 	case OP_MAP_GATHER_2:
93117 	case OP_MAP_GATHER_3: op_map_gather(sc);
93118 	case OP_MAP_2: if (op_map_2(sc)) continue; goto EVAL;
93119 
93120 	case OP_FOR_EACH:   if (op_for_each(sc)) continue;   goto APPLY;
93121 	case OP_FOR_EACH_1: if (op_for_each_1(sc)) continue; goto BEGIN;
93122 
93123 	case OP_FOR_EACH_2:
93124 	case OP_FOR_EACH_3: if (op_for_each_2(sc)) continue; goto EVAL;
93125 
93126 	case OP_MEMBER_IF:
93127 	case OP_MEMBER_IF1: if (member_if(sc)) continue; goto APPLY;
93128 
93129 	case OP_ASSOC_IF:
93130 	case OP_ASSOC_IF1:  if (assoc_if(sc)) continue;  goto APPLY;
93131 
93132 
93133 	case OP_SAFE_DOTIMES:
93134 	SAFE_DOTIMES:         /* check_do */
93135 	  switch (op_safe_dotimes(sc))
93136 	    {
93137 	    case goto_safe_do_end_clauses: if (is_null(sc->code)) continue; goto DO_END_CODE;
93138 	    case goto_do_end_clauses: goto DO_END_CLAUSES;
93139 	    case goto_eval:           goto EVAL;
93140 	    case goto_top_no_pop:     goto TOP_NO_POP;
93141 	    default:                  goto BEGIN;
93142 	    }
93143 
93144 	case OP_SAFE_DO:
93145 	SAFE_DO:             /* from check_do */
93146 	  switch (op_safe_do(sc))
93147 	    {
93148 	    case goto_safe_do_end_clauses:
93149 	      if (is_null(sc->code)) /* I don't think multiple values (as test result) can happen here -- all safe do loops involve counters by 1 to some integer end */
93150 		continue;
93151 	      goto DO_END_CODE;
93152 
93153 	    case goto_do_unchecked: goto DO_UNCHECKED;
93154 	    default: goto BEGIN;
93155 	    }
93156 
93157 	case OP_DOTIMES_P:
93158 	DOTIMES_P:           /* from check_do */
93159 	  switch (op_dotimes_p(sc))
93160 	    {
93161 	    case goto_do_end_clauses: goto DO_END_CLAUSES;
93162 	    case goto_do_unchecked:   goto DO_UNCHECKED;
93163 	    default: goto EVAL;
93164 	    }
93165 
93166 	case OP_DOX:
93167 	DOX:                 /* from check_do */
93168 	  switch (op_dox(sc))
93169 	    {
93170 	    case goto_do_end_clauses: goto DO_END_CLAUSES;
93171 	    case goto_start:          continue;
93172 	    case goto_top_no_pop:     goto TOP_NO_POP; /* includes dox_step_o */
93173 	    default:		      goto BEGIN;
93174 	  }
93175 
93176 	DO_NO_BODY:
93177 	case OP_DO_NO_BODY_FX_VARS:        op_do_no_body_fx_vars(sc); goto EVAL;
93178 	case OP_DO_NO_BODY_FX_VARS_STEP:   if (op_do_no_body_fx_vars_step(sc)) goto DO_END_CLAUSES; goto EVAL;
93179 	case OP_DO_NO_BODY_FX_VARS_STEP_1: if (op_do_no_body_fx_vars_step_1(sc)) goto DO_END_CLAUSES; goto EVAL;
93180 
93181 	case OP_DO_NO_VARS_NO_OPT:   op_do_no_vars_no_opt(sc); /* fall through */
93182 	case OP_DO_NO_VARS_NO_OPT_1: if (op_do_no_vars_no_opt_1(sc)) goto DO_END_CLAUSES; goto BEGIN;
93183 	case OP_DO_NO_VARS:	     if (op_do_no_vars(sc))          goto DO_END_CLAUSES; goto BEGIN;
93184 	case OP_SAFE_DOTIMES_STEP_O: if (op_safe_dotimes_step_o(sc)) goto DO_END_CLAUSES; goto EVAL;
93185 	case OP_SAFE_DOTIMES_STEP:   if (op_safe_dotimes_step(sc))   goto DO_END_CLAUSES; goto EVAL;
93186 	case OP_SAFE_DO_STEP:        if (op_safe_do_step(sc))        goto DO_END_CLAUSES; goto BEGIN;
93187 	case OP_SIMPLE_DO:           if (op_simple_do(sc))           goto DO_END_CLAUSES; goto BEGIN;
93188 	case OP_SIMPLE_DO_STEP:      if (op_simple_do_step(sc))      goto DO_END_CLAUSES; goto BEGIN;
93189 	case OP_DOTIMES_STEP_O:      if (op_dotimes_step_o(sc))      goto DO_END_CLAUSES; goto EVAL;
93190 	case OP_DOX_INIT:            if (op_dox_init(sc))            goto DO_END_CLAUSES; goto BEGIN;
93191 	case OP_DOX_STEP:            if (op_dox_step(sc))            goto DO_END_CLAUSES; goto BEGIN;
93192 	case OP_DOX_STEP_O:          if (op_dox_step_o(sc))          goto DO_END_CLAUSES; goto EVAL;
93193 	case OP_DOX_NO_BODY:         op_dox_no_body(sc);             continue;
93194 	case OP_DOX_PENDING_NO_BODY: op_dox_pending_no_body(sc);     goto DO_END_CLAUSES;
93195 
93196 	case OP_DO_INIT: if (op_do_init(sc)) goto DO_END; goto EVAL;
93197 
93198 	case OP_DO:
93199 	  if (is_null(check_do(sc)))
93200 	    switch (optimize_op(sc->code))
93201 	      {
93202  	      case OP_DOX:	    goto DOX;
93203  	      case OP_SAFE_DOTIMES: goto SAFE_DOTIMES;
93204  	      case OP_DOTIMES_P:    goto DOTIMES_P;
93205  	      case OP_SAFE_DO:	    goto SAFE_DO;
93206 	      case OP_DO_NO_BODY_FX_VARS: goto DO_NO_BODY;
93207  	      case OP_DO_NO_VARS:   if (op_do_no_vars(sc)) goto DO_END_CLAUSES; goto BEGIN;
93208 	      case OP_DOX_NO_BODY:  op_dox_no_body(sc); continue;
93209 	      case OP_DOX_PENDING_NO_BODY: op_dox_pending_no_body(sc); goto DO_END_CLAUSES;
93210 	      default:              if (op_simple_do(sc)) goto DO_END_CLAUSES; goto BEGIN;
93211 	      }
93212 
93213 	case OP_DO_UNCHECKED:
93214 	  op_do_unchecked(sc);
93215 
93216 	DO_UNCHECKED:
93217 	  if (do_unchecked(sc)) goto EVAL;
93218 
93219 	DO_END:
93220 	case OP_DO_END:
93221 	  if (op_do_end(sc)) goto EVAL;
93222 
93223 	case OP_DO_END1:
93224 	  switch (op_do_end1(sc))
93225 	    {
93226 	    case goto_start:   continue;
93227 	    case goto_eval:    goto EVAL;
93228 	    case goto_begin:   goto BEGIN;
93229 	    case goto_feed_to: goto FEED_TO;
93230 	    case goto_do_end:  goto DO_END;
93231 	    default: break;
93232 	    }
93233 
93234 	case OP_DO_STEP:  if (op_do_step(sc))  goto DO_END; goto EVAL;
93235 	case OP_DO_STEP2: if (op_do_step2(sc)) goto DO_END; goto EVAL;
93236 
93237 	DO_END_CLAUSES:
93238 	  if (do_end_clauses(sc)) continue;
93239 
93240 	DO_END_CODE:
93241 	  switch (do_end_code(sc))
93242 	    {
93243 	    case goto_feed_to: goto FEED_TO;
93244 	    case goto_eval:    goto EVAL;
93245 	    default:           continue;
93246 	    }
93247 
93248 
93249 	case OP_BEGIN_UNCHECKED:
93250 	  set_current_code(sc, sc->code);
93251 	  sc->code = T_Pair(cdr(sc->code));
93252 	  goto BEGIN;
93253 
93254 	case OP_BEGIN:
93255 	  if (op_begin(sc, sc->code)) continue;
93256 	  sc->code = T_Pair(cdr(sc->code));
93257 
93258 	case OP_BEGIN_HOOK:
93259 	  if (sc->begin_hook)
93260 	    {
93261 	      /* call_begin_hook might clobber sc->code? via s7_eval_string probably yes */
93262 	      set_current_code(sc, sc->code);
93263 	      if (call_begin_hook(sc))
93264 		return(sc->F);
93265 	    }
93266 	case OP_BEGIN_NO_HOOK:
93267 	  goto BEGIN;
93268 
93269 	case OP_BEGIN_1_UNCHECKED:
93270 	  sc->code = cadr(sc->code);
93271 	  goto EVAL;
93272 
93273 	case OP_BEGIN_2_UNCHECKED:
93274 	  push_stack_no_args(sc, OP_EVAL, caddr(sc->code));
93275 	  sc->code = cadr(sc->code);
93276 	  goto EVAL;
93277 
93278 	case OP_BEGIN_AA:
93279 	  sc->value = fx_begin_aa(sc, sc->code);
93280 	  continue;
93281 
93282 	case OP_BEGIN_ALL_A:
93283 	  sc->value = fx_begin_all_a(sc, sc->code);
93284 	  continue;
93285 
93286 	case OP_EVAL: goto EVAL;
93287 	case OP_EVAL_STRING: op_eval_string(sc); goto EVAL;
93288 
93289 	case OP_QUOTE: sc->value = check_quote(sc, sc->code); continue;
93290 	case OP_QUOTE_UNCHECKED: sc->value = cadr(sc->code); continue;
93291 
93292 	case OP_DEFINE_FUNCHECKED: define_funchecked(sc);   continue;
93293 	case OP_DEFINE_CONSTANT1:  op_define_constant1(sc); continue;
93294 
93295 	case OP_DEFINE_CONSTANT:
93296 	  if (op_define_constant(sc)) continue;
93297 
93298 	case OP_DEFINE_STAR:
93299 	case OP_DEFINE:
93300 	  check_define(sc);
93301 
93302 	case OP_DEFINE_CONSTANT_UNCHECKED:
93303 	case OP_DEFINE_STAR_UNCHECKED:
93304 	case OP_DEFINE_UNCHECKED:
93305 	  if (op_define_unchecked(sc)) goto TOP_NO_POP;
93306 
93307 	case OP_DEFINE1: if (op_define1(sc) == goto_apply) goto APPLY;
93308 	case OP_DEFINE_WITH_SETTER: op_define_with_setter(sc); continue;
93309 
93310 	case OP_SET_LET_S:        /* (set! (*s7* 'print-length) i) */
93311 	  sc->code = cdr(sc->code);
93312 	  if (set_pair_p_3(sc, lookup_slot_from(caar(sc->code), sc->curlet), cadr(cadar(sc->code)), lookup(sc, cadr(sc->code))))
93313 	    goto APPLY;
93314 	  continue;
93315 
93316 	case OP_SET_LET_FX:       /* (set! (hook 'result) 123) or (set! (H 'c) 32) */
93317 	  sc->code = cdr(sc->code);
93318 	  if (set_pair_p_3(sc, lookup_slot_from(caar(sc->code), sc->curlet), cadr(cadar(sc->code)), fx_call(sc, cdr(sc->code))))
93319 	    goto APPLY;
93320 	  continue;
93321 
93322 	case OP_SET_PAIR_ZA:      /* unknown setter pair, but value is easy */
93323 	  sc->code = cdr(sc->code);
93324 	  sc->value = fx_call(sc, cdr(sc->code));
93325 
93326 	case OP_SET_PAIR_P_1:      if (op_set_pair_p_1(sc)) goto APPLY; continue;
93327 	case OP_SET_PAIR:	   if (op_set_pair(sc))     goto APPLY; continue;
93328 
93329 	case OP_SET_PAIR_P:        op_set_pair_p(sc);        goto EVAL;
93330 	case OP_SET_PAIR_A:        op_set_pair_a(sc);        continue;
93331 
93332 	case OP_SET_PWS:           op_set_pws(sc);           continue;
93333 	case OP_SET_DILAMBDA_SA_A: op_set_dilambda_sa_a(sc); continue;
93334 	case OP_SET_DILAMBDA_P:    op_set_dilambda_p(sc);    goto EVAL;
93335 	case OP_SET_DILAMBDA:      op_set_dilambda(sc);      /* fall through */
93336 	case OP_SET_DILAMBDA_P_1:
93337 	  switch (op_set_dilambda_p_1(sc))
93338 	    {
93339 	    case goto_begin: goto BEGIN;
93340 	    case goto_apply: goto APPLY;
93341 	    default:         continue;
93342 	    }
93343 
93344 	case OP_INCREMENT_BY_1:   op_increment_by_1(sc);   continue;
93345 	case OP_DECREMENT_BY_1:   op_decrement_by_1(sc);   continue;
93346 	case OP_INCREMENT_SS:     op_increment_ss(sc);     continue;
93347 	case OP_INCREMENT_SA:     op_increment_sa(sc);     continue;
93348 	case OP_INCREMENT_SAA:    op_increment_saa(sc);    continue;
93349 	case OP_INCREMENT_SP:     op_increment_sp(sc);     goto EVAL;
93350 	case OP_INCREMENT_SP_1:   op_increment_sp_1(sc);   continue;
93351 	case OP_INCREMENT_SP_MV:  op_increment_sp_mv(sc);  continue;
93352 
93353 	case OP_SET_SYMBOL_C:     op_set_symbol_c(sc);     continue;
93354 	case OP_SET_SYMBOL_S:     op_set_symbol_s(sc);     continue;
93355 	case OP_SET_SYMBOL_A:     op_set_symbol_a(sc);     continue;
93356 	case OP_SET_SYMBOL_P:     op_set_symbol_p(sc);     goto EVAL;
93357 	case OP_SET_CONS:         op_set_cons(sc);         continue;
93358  	case OP_SET_SAFE:	  op_set_safe(sc);  	   continue;
93359 	case OP_SET_FROM_SETTER:  slot_set_value(sc->code, sc->value); continue;
93360 
93361 	case OP_SET2:
93362 	  switch (op_set2(sc))
93363 	    {
93364 	    case goto_eval:       goto EVAL;
93365 	    case goto_top_no_pop: goto TOP_NO_POP;
93366 	    case goto_start:      continue;
93367 	    case goto_apply:      goto APPLY;
93368 	    default:              goto EVAL_ARGS;
93369 	    }
93370 
93371 	case OP_SET:  check_set(sc);
93372 	case OP_SET_UNCHECKED:
93373 	  if (is_pair(cadr(sc->code)))             /* has setter */
93374 	    switch (set_implicit(sc))
93375 	      {
93376 	      case goto_top_no_pop: goto TOP_NO_POP;
93377 	      case goto_start:      continue;
93378 	      case goto_apply:      goto APPLY;
93379 	      default:              goto EVAL_ARGS;
93380 	      }
93381 
93382 	case OP_SET_NORMAL: if (op_set_normal(sc)) goto EVAL;
93383 	case OP_SET1:       if (op_set1(sc)) continue; goto APPLY;
93384 
93385 	case OP_SET_WITH_LET_1: if (op_set_with_let_1(sc)) goto TOP_NO_POP; goto SET_WITH_LET;
93386 	case OP_SET_WITH_LET_2: if (op_set_with_let_2(sc)) continue;
93387 
93388 	SET_WITH_LET:
93389 	  activate_let(sc, sc->value);  /* this activates sc->value, so the set! will happen in that environment */
93390 	  if (is_pair(cadr(sc->code)))
93391 	    switch (set_implicit(sc))
93392 	      {
93393 	      case goto_top_no_pop: goto TOP_NO_POP;
93394 	      case goto_start:      continue;
93395 	      case goto_apply:      goto APPLY;
93396 	      default:              goto EVAL_ARGS;
93397 	      }
93398 	  s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, wrap_string(sc, "can't set ~A", 12), sc->args));
93399 
93400 
93401 	case OP_IF:           op_if(sc);           goto EVAL;
93402 	case OP_IF_UNCHECKED: op_if_unchecked(sc); goto EVAL;
93403 	case OP_IF1:	      if (op_if1(sc)) goto EVAL; continue;
93404 
93405 	  #define if_a_p(sc) if (is_true(sc, fx_call(sc, cdr(sc->code))))
93406 	  #define if_not_a_p(sc) if (is_false(sc, fx_call(sc, cdadr(sc->code))))
93407 
93408 	case OP_IF_A_C_C:     sc->value = (is_true(sc, fx_call(sc, cdr(sc->code)))) ? opt1_con(sc->code) : opt2_con(sc->code); continue;
93409 	case OP_IF_A_A:       sc->value = (is_true(sc, fx_call(sc, cdr(sc->code)))) ? fx_call(sc, opt1_pair(sc->code)) : sc->unspecified; continue;
93410 	case OP_IF_S_A_A:     sc->value = (is_true(sc, lookup(sc, cadr(sc->code)))) ? fx_call(sc, opt1_pair(sc->code)) : fx_call(sc, opt2_pair(sc->code)); continue;
93411 	case OP_IF_A_A_A:     sc->value = (is_true(sc, fx_call(sc, cdr(sc->code)))) ? fx_call(sc, opt1_pair(sc->code)) : fx_call(sc, opt2_pair(sc->code)); continue;
93412 	case OP_IF_A_A_P:     if_a_p(sc) {sc->value = fx_call(sc, opt1_pair(sc->code)); continue;} sc->code = opt2_any(sc->code); goto EVAL;
93413 	case OP_IF_A_P_A:     if_a_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = fx_call(sc, opt2_pair(sc->code)); continue;
93414 	case OP_IF_NOT_A_A:   sc->value = (is_false(sc, fx_call(sc, opt1_pair(sc->code)))) ? fx_call(sc, opt2_pair(sc->code)) : sc->unspecified; continue;
93415 	case OP_IF_NOT_A_A_A: sc->value = (is_false(sc, fx_call(sc, opt1_pair(sc->code)))) ? fx_call(sc, opt2_pair(sc->code)) : fx_call(sc, opt3_pair(sc->code)); continue;
93416 	case OP_IF_AND2_S_A:  sc->value = fx_if_and2_s_a(sc, sc->code); continue;
93417 
93418 	  #define if_s_p(sc) if (is_true(sc, lookup(sc, cadr(sc->code))))
93419 	  #define if_not_s_p(sc) if (is_false(sc, lookup(sc, opt1_sym(cdr(sc->code))))) /* cadadr(sc->code) */
93420 
93421 	case OP_IF_S_P:   if_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93422 	case OP_IF_S_R:   if_s_p(sc) {sc->value = sc->unspecified; continue;} sc->code = opt1_any(sc->code); goto EVAL;
93423 	case OP_IF_S_P_P: if_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93424 	case OP_IF_S_N:   if_not_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93425 	case OP_IF_S_N_N: if_not_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93426 
93427 	case OP_IF_S_P_A: if_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = fx_call(sc, opt2_pair(sc->code)); continue;
93428 
93429 	case OP_IF_A_P:   if_a_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93430 	case OP_IF_A_R:   if_a_p(sc) {sc->value = sc->unspecified; continue;} sc->code = opt1_any(sc->code); goto EVAL;
93431 	case OP_IF_A_P_P: if_a_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93432 	case OP_IF_A_N:   if_not_a_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93433 	case OP_IF_A_N_N: if_not_a_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93434 
93435 	  #define if_is_type_s_p(sc) if (gen_type_match(sc, lookup(sc, opt2_sym(cdr(sc->code))), opt3_byte(cdr(sc->code))))
93436 	  #define if_is_not_type_s_p(sc) if (!gen_type_match(sc, lookup(sc, opt2_sym(cdr(sc->code))), opt3_byte(cdr(sc->code))))
93437 
93438 	case OP_IF_IS_TYPE_S_P:   if_is_type_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93439 	case OP_IF_IS_TYPE_S_R:   if_is_type_s_p(sc) {sc->value = sc->unspecified; continue;} sc->code = opt1_any(sc->code); goto EVAL;
93440 	case OP_IF_IS_TYPE_S_P_P: if_is_type_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93441 	case OP_IF_IS_TYPE_S_N:   if_is_not_type_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93442 	case OP_IF_IS_TYPE_S_N_N: if_is_not_type_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93443 
93444 	case OP_IF_IS_TYPE_S_A_A: if_is_type_s_p(sc) sc->value = fx_call(sc, cddr(sc->code)); else sc->value = fx_call(sc, opt2_pair(sc->code)); continue;
93445 	case OP_IF_IS_TYPE_S_P_A: if_is_type_s_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = fx_call(sc, opt2_pair(sc->code)); continue;
93446 
93447 	  #define if_opsq_p(sc) set_car(sc->t1_1, lookup(sc, opt2_sym(cdr(sc->code)))); if (is_true(sc, fn_proc(cadr(sc->code))(sc, sc->t1_1)))
93448 	  #define if_not_opsq_p(sc) set_car(sc->t1_1, lookup(sc, opt2_sym(cdr(sc->code)))); if (is_false(sc, fn_proc(opt1_pair(cdr(sc->code)))(sc, sc->t1_1))) /* cadadr */
93449 
93450 	case OP_IF_opSq_P:   if_opsq_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93451 	case OP_IF_opSq_R:   if_opsq_p(sc) {sc->value = sc->unspecified; continue;} sc->code = opt1_any(sc->code); goto EVAL;
93452 	case OP_IF_opSq_P_P: if_opsq_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93453 	case OP_IF_opSq_N:   if_not_opsq_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93454 	case OP_IF_opSq_N_N: if_not_opsq_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93455 
93456 	  #define if_and2_p(sc) if ((is_true(sc, fx_call(sc, opt2_pair(cdr(sc->code))))) && (is_true(sc, fx_call(sc, opt3_pair(cdr(sc->code))))))
93457 	  #define if_not_and2_p(sc) if ((is_false(sc, fx_call(sc, opt2_pair(cdr(sc->code))))) || (is_false(sc, fx_call(sc, opt3_pair(cdr(sc->code))))))
93458 
93459 	case OP_IF_AND2_P:   if_and2_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93460 	case OP_IF_AND2_R:   if_and2_p(sc) {sc->value = sc->unspecified; continue;} sc->code = opt1_any(sc->code); goto EVAL;
93461 	case OP_IF_AND2_P_P: if_and2_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93462 	case OP_IF_AND2_N:   if_not_and2_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93463 	case OP_IF_AND2_N_N: if_not_and2_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93464 
93465 	  #define if_or2_p(sc) if ((is_true(sc, fx_call(sc, opt2_pair(cdr(sc->code))))) || (is_true(sc, fx_call(sc, opt3_pair(cdr(sc->code))))))
93466 	  #define if_not_or2_p(sc) if ((is_false(sc, fx_call(sc, opt2_pair(cdr(sc->code))))) && (is_false(sc, fx_call(sc, opt3_pair(cdr(sc->code))))))
93467 
93468 	case OP_IF_OR2_P:   if_or2_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93469 	case OP_IF_OR2_R:   if_or2_p(sc) {sc->value = sc->unspecified; continue;} sc->code = opt1_any(sc->code); goto EVAL;
93470 	case OP_IF_OR2_P_P: if_or2_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93471 	case OP_IF_OR2_N:   if_not_or2_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93472 	case OP_IF_OR2_N_N: if_not_or2_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93473 
93474 	  #define if_and3_p(sc) if ((is_true(sc, fx_call(sc, opt2_pair(cdr(sc->code))))) && \
93475                                        (is_true(sc, fx_call(sc, opt3_pair(cdr(sc->code))))) && (is_true(sc, fx_call(sc, opt1_pair(cdr(sc->code))))))
93476 	  #define if_not_and3_p(sc) if ((is_false(sc, fx_call(sc, opt2_pair(cdr(sc->code))))) || \
93477                                           (is_false(sc, fx_call(sc, opt3_pair(cdr(sc->code))))) || (is_false(sc, fx_call(sc, opt1_pair(cdr(sc->code))))))
93478 
93479 	case OP_IF_AND3_P:   if_and3_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93480 	case OP_IF_AND3_R:   if_and3_p(sc) {sc->value = sc->unspecified; continue;} sc->code = opt1_any(sc->code); goto EVAL;
93481 	case OP_IF_AND3_P_P: if_and3_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93482 	case OP_IF_AND3_N:   if_not_and3_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->value = sc->unspecified; continue;
93483 	case OP_IF_AND3_N_N: if_not_and3_p(sc) {sc->code = opt1_any(sc->code); goto EVAL;} sc->code = opt2_any(sc->code); goto EVAL;
93484 
93485 	    #define if_p_push(op) do {push_stack_no_args(sc, op, opt2_any(cdr(sc->code)));  sc->code = opt3_any(cdr(sc->code));} while (0)
93486 	case OP_IF_P_P:      if_p_push(OP_IF_PP); goto EVAL;
93487 	case OP_IF_P_N:      if_p_push(OP_IF_PR); goto EVAL;
93488 	case OP_IF_P_P_P:    if_p_push(OP_IF_PPP); goto EVAL;
93489 	case OP_IF_P_R:      if_p_push(OP_IF_PR); goto EVAL;
93490 	case OP_IF_P_N_N:    if_p_push(OP_IF_PRR); goto EVAL;
93491 
93492 	    #define if_bp_push(op) do {push_stack_no_args(sc, op, opt2_any(cdr(sc->code)));  sc->code = opt3_pair(cdr(sc->code));} while (0)
93493 	case OP_IF_ANDP_P:   if_bp_push(OP_IF_PP);  goto AND_P;
93494 	case OP_IF_ANDP_R:   if_bp_push(OP_IF_PR);  goto AND_P;
93495 	case OP_IF_ANDP_P_P: if_bp_push(OP_IF_PPP); goto AND_P;
93496 	case OP_IF_ANDP_N:   if_bp_push(OP_IF_PR);  goto AND_P;
93497 	case OP_IF_ANDP_N_N: if_bp_push(OP_IF_PRR); goto AND_P;
93498 
93499 	case OP_IF_ORP_P:    if_bp_push(OP_IF_PP);  goto OR_P;
93500 	case OP_IF_ORP_R:    if_bp_push(OP_IF_PR);  goto OR_P;
93501 	case OP_IF_ORP_P_P:  if_bp_push(OP_IF_PPP); goto OR_P;
93502 	case OP_IF_ORP_N:    if_bp_push(OP_IF_PR);  goto OR_P;
93503 	case OP_IF_ORP_N_N:  if_bp_push(OP_IF_PRR); goto OR_P;
93504 
93505 	case OP_IF_PP:       if (sc->value != sc->F) goto EVAL; sc->value = sc->unspecified; continue;
93506 	case OP_IF_PR:       if (sc->value == sc->F) goto EVAL; sc->value = sc->unspecified; continue;
93507 	case OP_IF_PPP:      sc->code = (sc->value != sc->F) ? car(sc->code) : cadr(sc->code); goto EVAL;
93508 	case OP_IF_PRR:      sc->code = (sc->value == sc->F) ? car(sc->code) : cadr(sc->code); goto EVAL;
93509 
93510 	case OP_COND_FEED:   if (op_cond_feed(sc)) goto EVAL; /* else fall through */
93511 	case OP_COND_FEED_1: if (op_cond_feed_1(sc)) goto EVAL; continue;
93512 
93513 	case OP_WHEN:        check_when(sc);                   goto EVAL;
93514 	case OP_WHEN_S:      if (op_when_s(sc)) continue;      goto EVAL;
93515 	case OP_WHEN_A:      if (op_when_a(sc)) continue;      goto EVAL;
93516         case OP_WHEN_P:      op_when_p(sc);                    goto EVAL;
93517 	case OP_WHEN_AND_2:  if (op_when_and_2(sc)) continue;  goto EVAL;
93518 	case OP_WHEN_AND_3:  if (op_when_and_3(sc)) continue;  goto EVAL;
93519 	case OP_WHEN_AND_AP: if (op_when_and_ap(sc)) continue; goto EVAL;
93520 	case OP_WHEN_PP:     if (op_when_pp(sc)) continue;     goto EVAL;
93521 
93522 	case OP_UNLESS:      check_unless(sc);                 goto EVAL;
93523 	case OP_UNLESS_S:    if (op_unless_s(sc)) continue;    goto EVAL;
93524 	case OP_UNLESS_A:    if (op_unless_a(sc)) continue;    goto EVAL;
93525         case OP_UNLESS_P:    op_unless_p(sc);                  goto EVAL;
93526 	case OP_UNLESS_PP:   if (op_unless_pp(sc)) continue;   goto EVAL;
93527 
93528 	case OP_NAMED_LET_NO_VARS: op_named_let_no_vars(sc);   goto BEGIN;
93529 	case OP_NAMED_LET:	   if (op_named_let(sc))       goto BEGIN; goto EVAL;
93530 	case OP_NAMED_LET_FX:      if (op_named_let_fx(sc))    goto BEGIN; goto EVAL;
93531 
93532 	case OP_LET: 	           if (op_let(sc))             goto BEGIN; goto EVAL;
93533 	case OP_LET_UNCHECKED:	   if (op_let_unchecked(sc))   goto BEGIN; goto EVAL;
93534 	case OP_LET1:	           if (op_let1(sc))            goto BEGIN; goto EVAL;
93535 	case OP_LET_NO_VARS: 	   op_let_no_vars(sc);	       goto BEGIN;
93536 
93537 	case OP_LET_A_A_OLD:       op_let_a_a_old(sc);         continue;
93538 	case OP_LET_A_A_NEW:       op_let_a_a_new(sc);         continue;
93539 	case OP_LET_A_FX_OLD:      op_let_a_fx_old(sc);        continue;
93540 	case OP_LET_A_FX_NEW:      op_let_a_fx_new(sc);        continue;
93541 	case OP_LET_FX_OLD: 	   op_let_fx_old(sc);	       goto BEGIN;
93542 	case OP_LET_FX_NEW: 	   op_let_fx_new(sc);	       goto BEGIN;
93543 	case OP_LET_2A_OLD: 	   op_let_2a_old(sc);	       goto EVAL;
93544 	case OP_LET_2A_NEW: 	   op_let_2a_new(sc);	       goto EVAL;
93545 	case OP_LET_3A_OLD: 	   op_let_3a_old(sc);	       goto EVAL;
93546 	case OP_LET_3A_NEW: 	   op_let_3a_new(sc);	       goto EVAL;
93547 	case OP_LET_ONE_OLD:	   op_let_one_old(sc);	       goto EVAL;
93548 	case OP_LET_ONE_NEW:	   op_let_one_new(sc);	       goto EVAL;
93549 	case OP_LET_ONE_P_OLD: 	   op_let_one_p_old(sc);       goto EVAL;
93550 	case OP_LET_ONE_P_NEW: 	   op_let_one_p_new(sc);       goto EVAL;
93551 
93552 	case OP_LET_A_OLD:         op_let_a_old(sc); sc->code = cdr(sc->code);  goto BEGIN;
93553 	case OP_LET_A_NEW:         op_let_a_new(sc); sc->code = cdr(sc->code);  goto BEGIN;
93554 	case OP_LET_A_OLD_2:       op_let_a_old(sc); push_stack_no_args(sc, OP_EVAL, caddr(sc->code)); sc->code = cadr(sc->code); goto EVAL;
93555 	case OP_LET_A_NEW_2:       op_let_a_new(sc); push_stack_no_args(sc, OP_EVAL, caddr(sc->code)); sc->code = cadr(sc->code); goto EVAL;
93556 	case OP_LET_A_P_OLD:       op_let_a_old(sc); sc->code = cadr(sc->code); goto EVAL;
93557 	case OP_LET_A_P_NEW:       op_let_a_new(sc); sc->code = cadr(sc->code); goto EVAL;
93558 	case OP_LET_ONE_OLD_1:     op_let_one_old_1(sc);   goto BEGIN;
93559 	case OP_LET_ONE_P_OLD_1:   op_let_one_p_old_1(sc); goto EVAL;
93560 	case OP_LET_ONE_NEW_1:	   sc->curlet = make_let_with_slot(sc, sc->curlet, opt2_sym(sc->code), sc->value); goto BEGIN;
93561 	case OP_LET_ONE_P_NEW_1:   sc->curlet = make_let_with_slot(sc, sc->curlet, opt2_sym(sc->code), sc->value); sc->code = car(sc->code); goto EVAL;
93562 
93563 	case OP_LET_opSSq_OLD:    op_let_opssq_old(sc);    goto BEGIN;
93564 	case OP_LET_opSSq_NEW:    op_let_opssq_new(sc);    goto BEGIN;
93565 	case OP_LET_opSSq_E_OLD:  op_let_opssq_e_old(sc);  goto EVAL;
93566 	case OP_LET_opSSq_E_NEW:  op_let_opssq_e_new(sc);  goto EVAL;
93567 	case OP_LET_opaSSq_OLD:   op_let_opassq_old(sc);   goto BEGIN;
93568 	case OP_LET_opaSSq_NEW:   op_let_opassq_new(sc);   goto BEGIN;
93569 	case OP_LET_opaSSq_E_OLD: op_let_opassq_e_old(sc); goto EVAL;
93570 	case OP_LET_opaSSq_E_NEW: op_let_opassq_e_new(sc); goto EVAL;
93571 
93572 	case OP_LET_STAR_FX:      op_let_star_fx(sc);     goto BEGIN;
93573 	case OP_LET_STAR_FX_A:    op_let_star_fx_a(sc);   continue;
93574 
93575 	case OP_NAMED_LET_STAR:   op_named_let_star(sc);  goto EVAL;
93576 	case OP_LET_STAR2:        op_let_star2(sc);       goto EVAL;
93577 	case OP_LET_STAR:         if (check_let_star(sc)) goto EVAL; goto BEGIN;
93578 	case OP_LET_STAR1:        if (op_let_star1(sc))   goto EVAL; goto BEGIN;
93579 
93580 	case OP_LETREC:             check_letrec(sc, true);
93581 	case OP_LETREC_UNCHECKED:   if (op_letrec_unchecked(sc)) goto EVAL; goto BEGIN;
93582 	case OP_LETREC1:            if (op_letrec1(sc)) goto EVAL; goto BEGIN;
93583 
93584 	case OP_LETREC_STAR:           check_letrec(sc, false);
93585 	case OP_LETREC_STAR_UNCHECKED: if (op_letrec_star_unchecked(sc)) goto EVAL; goto BEGIN;
93586 	case OP_LETREC_STAR1:          if (op_letrec_star1(sc)) goto EVAL; goto BEGIN;
93587 
93588 
93589 	case OP_LET_TEMPORARILY: check_let_temporarily(sc);
93590 	case OP_LET_TEMP_UNCHECKED: op_let_temp_unchecked(sc); goto LET_TEMP_INIT1;
93591 
93592 	case OP_LET_TEMP_INIT1:
93593 	  caddr(sc->args) = cons(sc, sc->value, caddr(sc->args));
93594 	LET_TEMP_INIT1:
93595 	  if (op_let_temp_init1(sc)) goto EVAL;
93596 	case OP_LET_TEMP_INIT2:
93597 	  switch (op_let_temp_init2(sc))
93598 	    {
93599 	    case goto_begin: goto BEGIN;
93600 	    case goto_top_no_pop: sc->cur_op = OP_SET_UNCHECKED; goto TOP_NO_POP;
93601 	    default: break;
93602 	    }
93603 
93604 	case OP_LET_TEMP_DONE:  push_stack(sc, OP_GC_PROTECT, sc->args, sc->value); /* fall through */
93605 	case OP_LET_TEMP_DONE1: if (op_let_temp_done1(sc)) continue; goto EVAL;
93606 
93607 	case OP_LET_TEMP_S7:     if(op_let_temp_s7(sc))      goto BEGIN; sc->value = sc->nil; continue;
93608 	case OP_LET_TEMP_FX:     if (op_let_temp_fx(sc))     goto BEGIN; sc->value = sc->nil; continue;
93609 	case OP_LET_TEMP_FX_1:   if (op_let_temp_fx_1(sc))   goto BEGIN; sc->value = sc->nil; continue;
93610 	case OP_LET_TEMP_SETTER: if (op_let_temp_setter(sc)) goto BEGIN; sc->value = sc->nil; continue;
93611 	case OP_LET_TEMP_A_A:    sc->value = fx_let_temp_a_a(sc, sc->code); continue;
93612 
93613 	case OP_LET_TEMP_UNWIND:        op_let_temp_unwind(sc);        continue;
93614 	case OP_LET_TEMP_S7_UNWIND:     op_let_temp_s7_unwind(sc);     continue;
93615 	case OP_LET_TEMP_SETTER_UNWIND: op_let_temp_setter_unwind(sc); continue;
93616 
93617 
93618 	case OP_COND:           check_cond(sc);
93619 	case OP_COND_UNCHECKED: if (op_cond_unchecked(sc)) goto EVAL;
93620 	case OP_COND1:          if (op_cond1(sc)) goto TOP_NO_POP;
93621 
93622 	FEED_TO:
93623 	  if (feed_to(sc)) goto APPLY;
93624 	  goto EVAL;
93625 	case OP_FEED_TO_1:       sc->code = sc->value; goto APPLY;   /* sc->args saved in feed_to via push_stack */
93626 
93627 	case OP_COND_SIMPLE:     if (op_cond_simple(sc)) goto EVAL;
93628 	case OP_COND1_SIMPLE:    if (op_cond1_simple(sc)) goto TOP_NO_POP; goto BEGIN;
93629 	case OP_COND_SIMPLE_O:   if (op_cond_simple_o(sc)) goto EVAL;
93630 	case OP_COND1_SIMPLE_O:  if (op_cond1_simple_o(sc)) continue;  goto EVAL;
93631 
93632 	case OP_COND_FX_FX:      sc->value = fx_cond_fx_fx(sc, sc->code); continue;
93633 	case OP_COND_FX_FP:      if (op_cond_fx_fp(sc)) continue;   goto EVAL;
93634 	case OP_COND_FX_FP_1:    if (op_cond_fx_fp_1(sc)) continue; goto EVAL;
93635 	case OP_COND_FX_FP_O:    if (op_cond_fx_fp_o(sc)) continue; goto EVAL;
93636 	case OP_COND_FX_2E:      if (op_cond_fx_2e(sc)) continue; goto EVAL;
93637 	case OP_COND_FX_3E:      if (op_cond_fx_3e(sc)) continue; goto EVAL;
93638 
93639 
93640 	case OP_AND:
93641 	  if (check_and(sc, sc->code)) continue;
93642 
93643 	case OP_AND_P:
93644 	  sc->code = cdr(sc->code);
93645 	AND_P:                        /* this code (and OR_P below) is ugly, but the pretty version (procedurized) is much slower */
93646 	  if (has_fx(sc->code))       /* all fx_proc's are set via fx_choose which can return nil, but it is not cleared when type is */
93647 	    {                         /*   so, if (fx_proc(sc->code)) here and in OR_P is not safe */
93648 	      sc->value = fx_call(sc, sc->code);
93649 	      if (is_false(sc, sc->value))
93650 		continue;
93651 	      sc->code = cdr(sc->code);
93652 	      if (is_null(sc->code))  /* this order of checks appears to be faster than any of the alternatives */
93653 		continue;
93654 	      goto AND_P;
93655 	    }
93656 	  if (is_not_null(cdr(sc->code)))
93657 	    push_stack_no_args(sc, OP_AND_P1, cdr(sc->code));
93658 	  sc->code = car(sc->code);
93659 	  goto EVAL;
93660 
93661 	case OP_AND_P1:
93662 	  if ((is_false(sc, sc->value)) ||
93663 	      (is_null(sc->code)))
93664 	    continue;
93665 	  goto AND_P;
93666 
93667 	case OP_AND_AP:      if (op_and_ap(sc)) continue; goto EVAL;
93668 	case OP_AND_2:       sc->value = fx_and_2(sc, sc->code); continue;
93669 	case OP_AND_3:       sc->value = fx_and_3(sc, sc->code); continue;
93670 	case OP_AND_N:       sc->value = fx_and_n(sc, sc->code); continue;
93671 	case OP_AND_S_2:     sc->value = fx_and_s_2(sc, sc->code); continue;
93672 	case OP_AND_PAIR_P:  if (op_and_pair_p(sc)) continue; goto EVAL;
93673 	case OP_AND_SAFE_P1: op_and_safe_p1(sc); goto EVAL;
93674 	case OP_AND_SAFE_P2: if (op_and_safe_p2(sc)) continue; goto EVAL;
93675 	case OP_AND_SAFE_P3: if (op_and_safe_p3(sc)) continue; goto EVAL;
93676 	case OP_AND_SAFE_P_REST: if (is_true(sc, sc->value)) sc->value = fx_and_n(sc, sc->code); continue;
93677 
93678 
93679 	case OP_OR:
93680 	  if (check_or(sc, sc->code)) continue;
93681 
93682 	case OP_OR_P:
93683 	  sc->code = cdr(sc->code);
93684 	OR_P:
93685 	  if (has_fx(sc->code))
93686 	    {
93687 	      sc->value = fx_call(sc, sc->code);
93688 	      if (is_true(sc, sc->value))
93689 		continue;
93690 	      sc->code = cdr(sc->code);
93691 	      if (is_null(sc->code))
93692 		continue;
93693 	      goto OR_P;
93694 	    }
93695 	  if (is_not_null(cdr(sc->code)))
93696 	    push_stack_no_args(sc, OP_OR_P1, cdr(sc->code));
93697 	  sc->code = car(sc->code);
93698 	  goto EVAL;
93699 
93700 	case OP_OR_P1:
93701 	  if ((is_true(sc, sc->value)) ||
93702 	      (is_null(sc->code)))
93703 	    continue;
93704 	  goto OR_P;
93705 
93706 	case OP_OR_AP:       if (op_or_ap(sc)) continue; goto EVAL;
93707 	case OP_OR_2:        sc->value = fx_or_2(sc, sc->code); continue;
93708 	case OP_OR_S_2:      sc->value = fx_or_s_2(sc, sc->code); continue;
93709 	case OP_OR_S_TYPE_2: sc->value = fx_or_s_type_2(sc, sc->code); continue;
93710 	case OP_OR_3:        sc->value = fx_or_3(sc, sc->code); continue;
93711 	case OP_OR_N:        sc->value = fx_or_n(sc, sc->code); continue;
93712 
93713 	case OP_EVAL_MACRO:    op_eval_macro(sc);                  goto EVAL;
93714 	case OP_EVAL_MACRO_MV: if (op_eval_macro_mv(sc)) continue; goto EVAL;
93715 	case OP_EXPANSION:     op_finish_expansion(sc);            continue;
93716 
93717 	case OP_DEFINE_BACRO:     case OP_DEFINE_BACRO_STAR:
93718 	case OP_DEFINE_EXPANSION: case OP_DEFINE_EXPANSION_STAR:
93719 	case OP_DEFINE_MACRO:     case OP_DEFINE_MACRO_STAR:
93720 	  if (op_define_macro(sc)) continue;
93721 	  goto APPLY;
93722 
93723 	case OP_MACRO: case OP_BACRO: case OP_MACRO_STAR: case OP_BACRO_STAR:
93724 	  op_macro(sc);
93725 	  continue;
93726 
93727 	case OP_LAMBDA:                op_lambda(sc);                continue;
93728 	case OP_LAMBDA_UNCHECKED:      op_lambda_unchecked(sc);      continue;
93729 
93730 	case OP_LAMBDA_STAR:           op_lambda_star(sc);           continue;
93731 	case OP_LAMBDA_STAR_UNCHECKED: op_lambda_star_unchecked(sc); continue;
93732 
93733 
93734 	case OP_CASE:                             /* car(sc->code) is the selector */
93735 	  /* selector A, key type: E=eq (symbol/char), I=integer, G=any, S=single keys and single bodies */
93736 	  if (check_case(sc)) goto EVAL;          /* else drop into CASE_G_G -- selector is a symbol or constant */
93737 
93738 	case OP_CASE_G_G: if (op_case_g_g(sc)) goto TOP_NO_POP; goto FEED_TO;
93739 	case OP_CASE_A_G_G: sc->value = fx_call(sc, cdr(sc->code));         if (op_case_g_g(sc)) goto TOP_NO_POP; goto FEED_TO;
93740 	case OP_CASE_S_G_G: sc->value = lookup_checked(sc, cadr(sc->code)); if (op_case_g_g(sc)) goto TOP_NO_POP; goto FEED_TO;
93741 
93742 	case OP_CASE_P_G_G: push_stack_no_args_direct(sc, OP_CASE_G_G); sc->code = cadr(sc->code); goto EVAL;
93743 	case OP_CASE_P_E_S: push_stack_no_args_direct(sc, OP_CASE_E_S); sc->code = cadr(sc->code); goto EVAL;
93744 	case OP_CASE_P_S_S: push_stack_no_args_direct(sc, OP_CASE_S_S); sc->code = cadr(sc->code); goto EVAL;
93745 	case OP_CASE_P_G_S: push_stack_no_args_direct(sc, OP_CASE_G_S); sc->code = cadr(sc->code); goto EVAL;
93746 	case OP_CASE_P_E_G: push_stack_no_args_direct(sc, OP_CASE_E_G); sc->code = cadr(sc->code); goto EVAL;
93747 	case OP_CASE_P_S_G: push_stack_no_args_direct(sc, OP_CASE_S_G); sc->code = cadr(sc->code); goto EVAL;
93748 
93749 	case OP_CASE_A_E_S: sc->value = fx_call(sc, cdr(sc->code)); op_case_e_s(sc); goto EVAL;
93750 	case OP_CASE_S_E_S: sc->value = lookup_checked(sc, cadr(sc->code));  /* fall through */
93751 	case OP_CASE_E_S: op_case_e_s(sc); goto EVAL;
93752 
93753 	case OP_CASE_A_S_S: sc->value = fx_call(sc, cdr(sc->code)); op_case_s_s(sc); goto EVAL;
93754 	case OP_CASE_S_S_S: sc->value = lookup_checked(sc, cadr(sc->code)); /* fall through */
93755 	case OP_CASE_S_S: op_case_s_s(sc); goto EVAL;
93756 #if (!WITH_GMP)
93757 	case OP_CASE_P_I_S: push_stack_no_args_direct(sc, OP_CASE_I_S); sc->code = cadr(sc->code); goto EVAL;
93758 	case OP_CASE_A_I_S: sc->value = fx_call(sc, cdr(sc->code)); if (op_case_i_s(sc)) continue; goto EVAL;
93759 	case OP_CASE_S_I_S: sc->value = lookup_checked(sc, cadr(sc->code)); /* fall through */
93760 	case OP_CASE_I_S: if (op_case_i_s(sc)) continue; goto EVAL;
93761 #endif
93762 	case OP_CASE_S_G_S: sc->value = lookup_checked(sc, cadr(sc->code)); op_case_g_s(sc); goto EVAL;
93763 	case OP_CASE_A_G_S: sc->value = fx_call(sc, cdr(sc->code));         /* fall through */
93764 	case OP_CASE_G_S: op_case_g_s(sc); goto EVAL;
93765 
93766 	case OP_CASE_A_E_G: sc->value = fx_call(sc, cdr(sc->code)); if (op_case_e_g_1(sc, sc->value, is_simple(sc->value))) goto TOP_NO_POP; goto FEED_TO;
93767 	case OP_CASE_S_E_G: sc->value = lookup_checked(sc, cadr(sc->code));   /* fall through */
93768 	case OP_CASE_E_G: if (op_case_e_g_1(sc, sc->value, is_simple(sc->value))) goto TOP_NO_POP; goto FEED_TO;
93769 
93770 	case OP_CASE_A_S_G: sc->value = fx_call(sc, cdr(sc->code)); if (op_case_e_g_1(sc, sc->value, is_case_key(sc->value))) goto TOP_NO_POP; goto FEED_TO;
93771 	case OP_CASE_S_S_G: sc->value = lookup_checked(sc, cadr(sc->code));   /* fall through */
93772 	case OP_CASE_S_G: if (op_case_e_g_1(sc, sc->value, is_case_key(sc->value))) goto TOP_NO_POP; goto FEED_TO;
93773 
93774 
93775 	case OP_ERROR_QUIT:
93776 	  if (sc->stack_end <= sc->stack_start)
93777 	    stack_reset(sc);          /* sets stack_end to stack_start, then pushes op_barrier and op_eval_done */
93778 	  return(sc->F);
93779 
93780 	case OP_ERROR_HOOK_QUIT:
93781 	  op_error_hook_quit(sc);
93782 
93783 	case OP_EVAL_DONE:
93784 	  return(sc->F);
93785 
93786 	case OP_SPLICE_VALUES:         /* if splice_in_values hits eval_done, it needs to continue the splice after returning, so we get here */
93787 	  splice_in_values(sc, sc->args);
93788 	  continue;
93789 
93790 	case OP_GC_PROTECT: case OP_BARRIER:
93791 	case OP_CATCH_ALL: case OP_CATCH: case OP_CATCH_1: case OP_CATCH_2:
93792 	  continue;
93793 
93794 	case OP_GET_OUTPUT_STRING:     /* from call-with-output-string and with-output-to-string -- return the port string directly */
93795 	  op_get_output_string(sc);
93796 	  /* fall through */
93797 
93798 	case OP_UNWIND_OUTPUT:          op_unwind_output(sc);                          continue;
93799 	case OP_UNWIND_INPUT:           op_unwind_input(sc);                           continue;
93800 	case OP_DYNAMIC_UNWIND:         dynamic_unwind(sc, sc->code, sc->args);        continue;
93801 	case OP_DYNAMIC_UNWIND_PROFILE: g_profile_out(sc, set_plist_1(sc, sc->args));  continue;
93802 	case OP_PROFILE_IN:	        g_profile_in(sc, set_plist_1(sc, sc->curlet)); continue;
93803 
93804 	case OP_DYNAMIC_WIND: if (op_dynamic_wind(sc) == goto_apply) goto APPLY; continue;
93805 	case OP_DEACTIVATE_GOTO: call_exit_active(sc->args) = false; continue; /* deactivate the exiter */
93806 
93807 
93808 	case OP_WITH_LET_S:         if (op_with_let_s(sc)) goto BEGIN; continue;
93809 	case OP_WITH_LET:           check_with_let(sc);
93810 	case OP_WITH_LET_UNCHECKED: if (op_with_let_unchecked(sc)) goto EVAL;
93811 	case OP_WITH_LET1:          if (sc->value != sc->curlet) activate_let(sc, sc->value); goto BEGIN;
93812 	case OP_WITH_UNLET_S:       sc->value = with_unlet_s(sc); continue;
93813 
93814 	case OP_WITH_BAFFLE:           check_with_baffle(sc);
93815 	case OP_WITH_BAFFLE_UNCHECKED: if (op_with_baffle_unchecked(sc)) continue; goto BEGIN;
93816 
93817 
93818 	case OP_READ_INTERNAL:             op_read_internal(sc); continue;
93819 	case OP_READ_DONE:                 op_read_done(sc);     continue;
93820 	case OP_LOAD_RETURN_IF_EOF:        if (op_load_return_if_eof(sc)) goto EVAL; return(sc->F);
93821 	case OP_LOAD_CLOSE_AND_POP_IF_EOF: if (op_load_close_and_pop_if_eof(sc)) goto EVAL; continue;
93822 
93823 	POP_READ_LIST:
93824 	  if (pop_read_list(sc)) goto READ_NEXT;
93825 
93826 	READ_LIST:
93827 	case OP_READ_LIST:        /* sc->args is sc->nil at first */
93828 	  sc->args = cons(sc, sc->value, sc->args);
93829 
93830 	READ_NEXT:
93831 	case OP_READ_NEXT:       /* this is 75% of the token calls, so expanding it saves lots of time */
93832 	  {
93833 	    int32_t c;
93834 	    s7_pointer pt;
93835 
93836 	    pt = current_input_port(sc);
93837 	    c = port_read_white_space(pt)(sc, pt);
93838 
93839 	  READ_C:
93840 	    switch (c)
93841 	      {
93842 	      case '(':
93843 		c = port_read_white_space(pt)(sc, pt);  /* sc->tok = token(sc) */
93844 		switch (c)
93845 		  {
93846 		  case '(':  sc->tok = TOKEN_LEFT_PAREN;                break;
93847 		  case ')':  sc->value = sc->nil; goto READ_LIST;       /* was tok = TOKEN_RIGHT_PAREN */
93848 		  case '.':  sc->tok = read_dot(sc, pt);                break;
93849 		  case '\'': sc->tok = TOKEN_QUOTE;                     break;
93850 		  case ';':  sc->tok = port_read_semicolon(pt)(sc, pt); break;
93851 		  case '"':  sc->tok = TOKEN_DOUBLE_QUOTE;              break;
93852 		  case '`':  sc->tok = TOKEN_BACK_QUOTE;                break;
93853 		  case ',':  sc->tok = read_comma(sc, pt);              break;
93854 		  case '#':  sc->tok = read_sharp(sc, pt);              break;
93855 		  case '\0': case EOF: sc->tok = TOKEN_EOF;             break;
93856 
93857 		  default: /* read first element of list (ignore callgrind confusion -- this happens a lot) */
93858 		    {
93859 		      sc->strbuf[0] = (unsigned char)c;
93860 		      push_stack_no_let_no_code(sc, OP_READ_LIST, sc->args);
93861 		      check_stack_size(sc);
93862 		      sc->value = port_read_name(pt)(sc, pt);
93863 		      sc->args = list_1(sc, sc->value);
93864 		      pair_set_current_input_location(sc, sc->args);
93865 		      c = port_read_white_space(pt)(sc, pt);
93866 		      goto READ_C;
93867 		    }}
93868 
93869 		if (sc->tok == TOKEN_ATOM)
93870 		  {
93871 		    c = read_atom(sc, pt);
93872 		    goto READ_C;
93873 		  }
93874 
93875 		if (sc->tok == TOKEN_RIGHT_PAREN)
93876 		  {
93877 		    sc->value = sc->nil;
93878 		    goto READ_LIST;
93879 		  }
93880 
93881 		if (sc->tok == TOKEN_DOT)
93882 		  {
93883 		    do {c = inchar(pt);} while ((c != ')') && (c != EOF));
93884 		    read_error(sc, "stray dot after '('?");      /* (car '( . )) */
93885 		  }
93886 
93887 		if (sc->tok == TOKEN_EOF)
93888 		  return(missing_close_paren_error(sc));
93889 
93890 		push_stack_no_let_no_code(sc, OP_READ_LIST, sc->args);
93891 		push_stack_no_let_no_code(sc, OP_READ_LIST, sc->nil);
93892 		check_stack_size(sc);
93893 		sc->value = read_expression(sc);
93894 		if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
93895 		continue;
93896 
93897 	      case ')':
93898 		sc->tok = TOKEN_RIGHT_PAREN;
93899 		break;
93900 
93901 	      case '.':
93902 		sc->tok = read_dot(sc, pt); /* dot or atom */
93903 		break;
93904 
93905 	      case '\'':
93906 		sc->tok = TOKEN_QUOTE;
93907 		push_stack_no_let_no_code(sc, OP_READ_LIST, sc->args);
93908 		sc->value = read_expression(sc);
93909 		continue;
93910 
93911 	      case ';':
93912 		sc->tok = port_read_semicolon(pt)(sc, pt);
93913 		break;
93914 
93915 	      case '"':
93916 		sc->tok = TOKEN_DOUBLE_QUOTE;
93917 		read_double_quote(sc);
93918 		goto READ_LIST;
93919 
93920 	      case '`':
93921 		sc->tok = TOKEN_BACK_QUOTE;
93922 		push_stack_no_let_no_code(sc, OP_READ_LIST, sc->args);
93923 		sc->value = read_expression(sc);
93924 		if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
93925 		continue;
93926 
93927 	      case ',':
93928 		sc->tok = read_comma(sc, pt); /* at_mark or comma */
93929 		push_stack_no_let_no_code(sc, OP_READ_LIST, sc->args);
93930 		sc->value = read_expression(sc);
93931 		continue;
93932 
93933 	      case '#':
93934 		sc->tok = read_sharp(sc, pt);
93935 		break;
93936 
93937 	      case '\0':
93938 	      case EOF:
93939 		return(missing_close_paren_error(sc));
93940 
93941 	      default:
93942 		sc->strbuf[0] = (unsigned char)c;
93943 		sc->value = port_read_name(pt)(sc, pt);
93944 		goto READ_LIST;
93945 	      }}
93946 
93947 	READ_TOK:
93948 	  switch (sc->tok)
93949 	    {
93950 	    case TOKEN_RIGHT_PAREN: 	      /* sc->args can't be null here */
93951 	      sc->value = proper_list_reverse_in_place(sc, sc->args);
93952 	      if ((is_expansion(car(sc->value))) &&
93953 		  (sc->is_expanding))
93954 		switch (op_expansion(sc))
93955 		  {
93956 		  case goto_begin: goto BEGIN;
93957 		  case goto_apply_lambda: goto APPLY_LAMBDA;
93958 		  default: break;
93959 		  }
93960 	      break;
93961 
93962 	    case TOKEN_EOF:          return(missing_close_paren_error(sc));       /* can't happen, I believe */
93963 	    case TOKEN_ATOM:         sc->value = port_read_name(current_input_port(sc))(sc, current_input_port(sc)); goto READ_LIST;
93964 	    case TOKEN_SHARP_CONST:  if (read_sharp_const(sc)) goto READ_TOK; goto READ_LIST;
93965 	    case TOKEN_DOUBLE_QUOTE: read_double_quote(sc); goto READ_LIST;
93966 	    case TOKEN_DOT:          read_dot_and_expression(sc); break;
93967 	    default:                 read_tok_default(sc); break;
93968 	    }
93969 	  if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
93970 	  continue;
93971 
93972 	case OP_READ_DOT:
93973 	  switch (op_read_dot(sc))
93974 	    {
93975 	    case goto_start: continue;
93976 	    case goto_pop_read_list: goto POP_READ_LIST;
93977 	    default: goto READ_TOK;
93978 	    }
93979 
93980 	case OP_READ_QUOTE:        if (op_read_quote(sc)) continue;        goto POP_READ_LIST;
93981 	case OP_READ_QUASIQUOTE:   if (op_read_quasiquote(sc)) continue;   goto POP_READ_LIST;
93982 	case OP_READ_UNQUOTE:      if (op_read_unquote(sc)) continue;      goto POP_READ_LIST;
93983 	case OP_READ_APPLY_VALUES: if (op_read_apply_values(sc)) continue; goto POP_READ_LIST;
93984 	case OP_READ_VECTOR:       if (op_read_vector(sc)) continue;       goto POP_READ_LIST;
93985 	case OP_READ_INT_VECTOR:   if (op_read_int_vector(sc)) continue;   goto POP_READ_LIST;
93986 	case OP_READ_FLOAT_VECTOR: if (op_read_float_vector(sc)) continue; goto POP_READ_LIST;
93987 	case OP_READ_BYTE_VECTOR:  if (op_read_byte_vector(sc)) continue;  goto POP_READ_LIST;
93988 
93989 	case OP_CLEAR_OPTS:
93990 	  break;
93991 
93992 	default:
93993 	  fprintf(stderr, "unknown operator: %" print_pointer " in %s\n", sc->cur_op, display(current_code(sc)));
93994 	  return(sc->F);
93995 	}
93996 
93997       clear_all_optimizations(sc, sc->code);
93998 
93999     UNOPT:
94000       switch (trailers(sc))
94001 	{
94002 	case goto_top_no_pop:    goto TOP_NO_POP;
94003 	case goto_eval_args_top: goto EVAL_ARGS_TOP;
94004 	case goto_eval:          goto EVAL;
94005 	default: break;
94006 	}}
94007   return(sc->F);
94008 }
94009 
94010 
94011 /* -------------------------------- *s7* let -------------------------------- */
94012 
94013 typedef enum {SL_NO_FIELD=0, SL_STACK_TOP, SL_STACK_SIZE, SL_STACKTRACE_DEFAULTS, SL_HEAP_SIZE, SL_FREE_HEAP_SIZE,
94014 	      SL_GC_FREED, SL_GC_PROTECTED_OBJECTS, SL_GC_TOTAL_FREED, SL_GC_INFO, SL_FILE_NAMES, SL_ROOTLET_SIZE, SL_C_TYPES, SL_SAFETY,
94015 	      SL_UNDEFINED_IDENTIFIER_WARNINGS, SL_UNDEFINED_CONSTANT_WARNINGS, SL_GC_STATS, SL_MAX_HEAP_SIZE,
94016 	      SL_MAX_PORT_DATA_SIZE, SL_MAX_STACK_SIZE, SL_CPU_TIME, SL_CATCHES, SL_STACK, SL_MAX_STRING_LENGTH,
94017 	      SL_MAX_FORMAT_LENGTH, SL_MAX_LIST_LENGTH, SL_MAX_VECTOR_LENGTH, SL_MAX_VECTOR_DIMENSIONS,
94018 	      SL_DEFAULT_HASH_TABLE_LENGTH, SL_INITIAL_STRING_PORT_LENGTH, SL_DEFAULT_RATIONALIZE_ERROR,
94019 	      SL_DEFAULT_RANDOM_STATE, SL_EQUIVALENT_FLOAT_EPSILON, SL_HASH_TABLE_FLOAT_EPSILON, SL_PRINT_LENGTH,
94020 	      SL_BIGNUM_PRECISION, SL_MEMORY_USAGE, SL_FLOAT_FORMAT_PRECISION, SL_HISTORY, SL_HISTORY_ENABLED,
94021 	      SL_HISTORY_SIZE, SL_PROFILE, SL_PROFILE_INFO, SL_AUTOLOADING, SL_ACCEPT_ALL_KEYWORD_ARGUMENTS,
94022 	      SL_MOST_POSITIVE_FIXNUM, SL_MOST_NEGATIVE_FIXNUM, SL_OUTPUT_PORT_DATA_SIZE, SL_DEBUG, SL_VERSION,
94023 	      SL_GC_TEMPS_SIZE, SL_GC_RESIZE_HEAP_FRACTION, SL_GC_RESIZE_HEAP_BY_4_FRACTION, SL_OPENLETS, SL_EXPANSIONS,
94024 	      SL_NUM_FIELDS} s7_let_field_t;
94025 
94026 static const char *s7_let_field_names[SL_NUM_FIELDS] =
94027   {"no-field", "stack-top", "stack-size", "stacktrace-defaults", "heap-size", "free-heap-size",
94028    "gc-freed", "gc-protected-objects", "gc-total-freed", "gc-info", "file-names", "rootlet-size", "c-types", "safety",
94029    "undefined-identifier-warnings", "undefined-constant-warnings", "gc-stats", "max-heap-size",
94030    "max-port-data-size", "max-stack-size", "cpu-time", "catches", "stack", "max-string-length",
94031    "max-format-length", "max-list-length", "max-vector-length", "max-vector-dimensions",
94032    "default-hash-table-length", "initial-string-port-length", "default-rationalize-error",
94033    "default-random-state", "equivalent-float-epsilon", "hash-table-float-epsilon", "print-length",
94034    "bignum-precision", "memory-usage", "float-format-precision", "history", "history-enabled",
94035    "history-size", "profile", "profile-info", "autoloading?", "accept-all-keyword-arguments",
94036    "most-positive-fixnum", "most-negative-fixnum", "output-port-data-size", "debug", "version",
94037    "gc-temps-size", "gc-resize-heap-fraction", "gc-resize-heap-by-4-fraction", "openlets", "expansions?"};
94038 
94039 static s7_int s7_let_length(void) {return(SL_NUM_FIELDS - 1);}
94040 
94041 static s7_pointer s7_let_add_field(s7_scheme *sc, const char *name, s7_let_field_t field)
94042 {
94043   s7_pointer sym;
94044   sym = make_symbol(sc, name);
94045   symbol_set_s7_let(sym, field);
94046   return(sym);
94047 }
94048 
94049 static void init_s7_let(s7_scheme *sc)
94050 {
94051   int32_t i;
94052   for (i = SL_STACK_TOP; i < SL_NUM_FIELDS; i++)
94053     s7_let_add_field(sc, s7_let_field_names[i], (s7_let_field_t)i);
94054 }
94055 
94056 /* handling all *s7* fields via fallbacks lets us use direct field accesses in the rest of s7, and avoids
94057  *   using ca 100 cells for the let slots/values.  We would need the fallbacks anyway for 'files et al.
94058  *   Since most of the fields need special setters, it's actually less code this way.  See old/s7-let-s7.c.
94059  */
94060 
94061 #if (!_WIN32) /* (!MS_WINDOWS) */
94062   #include <sys/resource.h>
94063 #endif
94064 
94065 static s7_pointer kmg(s7_scheme *sc, s7_int bytes)
94066 {
94067   block_t *b;
94068   int len = 0;
94069   b = mallocate(sc, 128);
94070   if (bytes < 1000)
94071     len = snprintf((char *)block_data(b), 128, "%" print_s7_int, bytes);
94072   else
94073     {
94074       if (bytes < 1000000)
94075 	len = snprintf((char *)block_data(b), 128, "%.1fk", bytes / 1000.0);
94076       else
94077 	{
94078 	  if (bytes < 1000000000)
94079 	    len = snprintf((char *)block_data(b), 128, "%.1fM", bytes / 1000000.0);
94080 	  else len = snprintf((char *)block_data(b), 128, "%.1fG", bytes / 1000000000.0);
94081 	}}
94082   return(cons(sc, make_integer(sc, bytes), block_to_string(sc, b, len)));
94083 }
94084 
94085 static s7_pointer memory_usage(s7_scheme *sc)
94086 {
94087   s7_int gc_loc, i, k, len, in_use = 0, vlen = 0, flen = 0, ilen = 0, blen = 0, hlen = 0;
94088   s7_pointer mu_let;
94089   gc_list_t *gp;
94090   s7_int ts[NUM_TYPES];
94091 
94092 #if (!_WIN32) /* (!MS_WINDOWS) */
94093   struct rusage info;
94094   struct timeval ut;
94095 #endif
94096 
94097   mu_let = s7_inlet(sc, sc->nil);
94098   gc_loc = s7_gc_protect_1(sc, mu_let);
94099 
94100 #if (!_WIN32) /* (!MS_WINDOWS) */
94101   getrusage(RUSAGE_SELF, &info);
94102   ut = info.ru_utime;
94103   make_slot_1(sc, mu_let, make_symbol(sc, "process-time"), make_real(sc, ut.tv_sec + (floor(ut.tv_usec / 1000.0) / 1000.0)));
94104 #ifdef __APPLE__
94105   make_slot_1(sc, mu_let, make_symbol(sc, "process-resident-size"), kmg(sc, info.ru_maxrss));
94106   /* apple docs say this is in kilobytes, but apparently that is an error */
94107 #else
94108   make_slot_1(sc, mu_let, make_symbol(sc, "process-resident-size"), kmg(sc, info.ru_maxrss * 1024));
94109   /* why does this number sometimes have no relation to RES in top? */
94110 #endif
94111   make_slot_1(sc, mu_let, make_symbol(sc, "IO"), cons(sc, make_integer(sc, info.ru_inblock), make_integer(sc, info.ru_oublock)));
94112 #endif
94113 
94114   make_slot_1(sc, mu_let, make_symbol(sc, "rootlet-size"), make_integer(sc, sc->rootlet_entries));
94115   make_slot_1(sc, mu_let, make_symbol(sc, "heap-size"), cons(sc, make_integer(sc, sc->heap_size), kmg(sc, sc->heap_size * (sizeof(s7_cell) + 2 * sizeof(s7_pointer)))));
94116   make_slot_1(sc, mu_let, make_symbol(sc, "cell-size"), make_integer(sc, sizeof(s7_cell)));
94117   make_slot_1(sc, mu_let, make_symbol(sc, "gc-total-freed"), make_integer(sc, sc->gc_total_freed));
94118   make_slot_1(sc, mu_let, make_symbol(sc, "gc-total-time"), make_real(sc, (double)(sc->gc_total_time) / ticks_per_second()));
94119 
94120   make_slot_1(sc, mu_let, make_symbol(sc, "small_ints"), cons(sc, make_integer(sc, NUM_SMALL_INTS), kmg(sc, NUM_SMALL_INTS * sizeof(s7_cell))));
94121   make_slot_1(sc, mu_let, make_symbol(sc, "permanent-cells"), cons(sc, make_integer(sc, sc->permanent_cells), kmg(sc, sc->permanent_cells * sizeof(s7_cell))));
94122   {
94123     gc_obj_t *g;
94124     for (i = 0, g = sc->permanent_objects; g; i++, g = (gc_obj_t *)(g->nxt));
94125     make_slot_1(sc, mu_let, make_symbol(sc, "permanent_objects"), make_integer(sc, i));
94126     for (i = 0, g = sc->permanent_lets; g; i++, g = (gc_obj_t *)(g->nxt));
94127     make_slot_1(sc, mu_let, make_symbol(sc, "permanent_lets"), make_integer(sc, i));
94128   }
94129 
94130   /* show how many active cells there are of each type (this is where all the memory_usage cpu time goes) */
94131   for (i = 0; i < NUM_TYPES; i++) ts[i] = 0;
94132   for (k = 0; k < sc->heap_size; k++)
94133     ts[unchecked_type(sc->heap[k])]++;
94134   sc->w = sc->nil;
94135   for (i = 0; i < NUM_TYPES; i++)
94136     {
94137       if (i > 0) in_use += ts[i];
94138       if (ts[i] > 50)
94139 	sc->w = cons(sc, cons(sc, make_symbol(sc, (i == 0) ? "free" : type_name_from_type(i, NO_ARTICLE)), make_integer(sc, ts[i])), sc->w);
94140     }
94141   make_slot_1(sc, mu_let, make_symbol(sc, "cells-in-use/free"), cons(sc, make_integer(sc, in_use), make_integer(sc, sc->free_heap_top - sc->free_heap)));
94142   if (is_pair(sc->w))
94143     make_slot_1(sc, mu_let, make_symbol(sc, "types"), proper_list_reverse_in_place(sc, sc->w));
94144   sc->w = sc->nil;
94145   /* same for permanent cells requires traversing saved_pointers and the alloc and big_alloc blocks up to alloc_k, or keeping explicit counts */
94146 
94147   make_slot_1(sc, mu_let, make_symbol(sc, "gc-protected-objects"),
94148 	      cons(sc, make_integer(sc, sc->protected_objects_size - sc->gpofl_loc),
94149 		   make_integer(sc, sc->protected_objects_size)));
94150   make_slot_1(sc, mu_let, make_symbol(sc, "setters"), make_integer(sc, sc->protected_setters_loc));
94151 
94152   /* check the symbol table, counting gensyms etc */
94153   {
94154     s7_int syms = 0, gens = 0, keys = 0, mx_list = 0;
94155     s7_pointer *els;
94156     for (i = 0, els = vector_elements(sc->symbol_table); i < SYMBOL_TABLE_SIZE; i++)
94157       {
94158 	s7_pointer x;
94159 	for (k = 0, x = els[i]; is_not_null(x); x = cdr(x), k++)
94160 	  {
94161 	    syms++;
94162 	    if (is_gensym(car(x))) gens++;
94163 	    if (is_keyword(car(x))) keys++;
94164 	  }
94165 	if (k > mx_list) mx_list = k;
94166       }
94167     make_slot_1(sc, mu_let, make_symbol(sc, "symbol-table"),
94168 		s7_list(sc, 9,
94169 			make_integer(sc, SYMBOL_TABLE_SIZE),
94170 			make_symbol(sc, "max-bin"), make_integer(sc, mx_list),
94171 			make_symbol(sc, "symbols"), cons(sc, make_integer(sc, syms), make_integer(sc, syms - gens - keys)),
94172 			make_symbol(sc, "gensyms"), make_integer(sc, gens),
94173 			make_symbol(sc, "keys"),    make_integer(sc, keys)));
94174   }
94175   make_slot_1(sc, mu_let, make_symbol(sc, "stack"), cons(sc, make_integer(sc, current_stack_top(sc)), make_integer(sc, sc->stack_size)));
94176 
94177   len = sc->autoload_names_top * (sizeof(const char **) + sizeof(s7_int) + sizeof(bool));
94178   for (i = 0; i < sc->autoload_names_loc; i++) len += sc->autoload_names_sizes[i];
94179   make_slot_1(sc, mu_let, make_symbol(sc, "autoload"), make_integer(sc, len));
94180 
94181   make_slot_1(sc, mu_let, make_symbol(sc, "circle_info"), make_integer(sc, sc->circle_info->size * (sizeof(s7_pointer) + sizeof(int32_t) + sizeof(bool))));
94182 
94183   /* check the gc lists (finalizations) */
94184   len = sc->strings->size + sc->vectors->size + sc->input_ports->size + sc->output_ports->size + sc->input_string_ports->size +
94185     sc->continuations->size + sc->c_objects->size + sc->hash_tables->size + sc->gensyms->size + sc->undefineds->size +
94186     sc->lambdas->size + sc->multivectors->size + sc->weak_refs->size + sc->weak_hash_iterators->size + sc->opt1_funcs->size;
94187   {
94188     int loc;
94189     loc = sc->strings->loc + sc->vectors->loc + sc->input_ports->loc + sc->output_ports->loc + sc->input_string_ports->loc +
94190     sc->continuations->loc + sc->c_objects->loc + sc->hash_tables->loc + sc->gensyms->loc + sc->undefineds->loc +
94191     sc->lambdas->loc + sc->multivectors->loc + sc->weak_refs->loc + sc->weak_hash_iterators->loc + sc->opt1_funcs->loc;
94192     make_slot_1(sc, mu_let, make_symbol(sc, "gc-lists"), cons(sc, make_integer(sc, loc), cons(sc, make_integer(sc, len), make_integer(sc, len * sizeof(s7_pointer)))));
94193   }
94194   /* strings */
94195   gp = sc->strings;
94196   for (len = 0, i = 0; i < (int32_t)(gp->loc); i++)
94197     len += string_length(gp->list[i]);
94198   make_slot_1(sc, mu_let, make_symbol(sc, "strings"), cons(sc, make_integer(sc, gp->loc), make_integer(sc, len)));
94199 
94200   /* vectors */
94201   for (k = 0, gp = sc->vectors; k < 2; k++, gp = sc->multivectors)
94202     for (i = 0; i < gp->loc; i++)
94203       {
94204 	s7_pointer v;
94205 	v = gp->list[i];
94206 	if (is_float_vector(v))
94207 	  flen += vector_length(v);
94208 	else
94209 	  {
94210 	    if (is_int_vector(v))
94211 	      ilen += vector_length(v);
94212 	    else
94213 	      {
94214 		if (is_byte_vector(v))
94215 		  blen += vector_length(v);
94216 		else vlen += vector_length(v);
94217 	      }}}
94218   make_slot_1(sc, mu_let, make_symbol(sc, "vectors"),
94219 	      s7_list(sc, 9,
94220 		      make_integer(sc, sc->vectors->loc + sc->multivectors->loc),
94221 		      make_symbol(sc, "vlen"),  make_integer(sc, vlen),
94222 		      make_symbol(sc, "fvlen"), make_integer(sc, flen),
94223 		      make_symbol(sc, "ivlen"), make_integer(sc, ilen),
94224 		      make_symbol(sc, "bvlen"), make_integer(sc, blen)));
94225 
94226   /* hash-tables */
94227   for (i = 0, gp = sc->hash_tables; i < gp->loc; i++)
94228     {
94229       s7_pointer v;
94230       v = gp->list[i];
94231       hlen += ((hash_table_mask(v) + 1) * sizeof(hash_entry_t *));
94232       hlen += (hash_table_entries(v) * sizeof(hash_entry_t));
94233     }
94234   make_slot_1(sc, mu_let, make_symbol(sc, "hash-tables"), cons(sc, make_integer(sc, sc->hash_tables->loc), make_integer(sc, hlen)));
94235 
94236   /* ports */
94237   gp = sc->input_ports;
94238   for (i = 0, len = 0; i < gp->loc; i++)
94239     {
94240       s7_pointer v;
94241       v = gp->list[i];
94242       if (port_data(v)) len += port_data_size(v);
94243     }
94244   gp = sc->input_string_ports;
94245   for (i = 0, len = 0; i < gp->loc; i++)
94246     {
94247       s7_pointer v;
94248       v = gp->list[i];
94249       if (port_data(v)) len += port_data_size(v);
94250     }
94251   make_slot_1(sc, mu_let, make_symbol(sc, "input-ports"), cons(sc, make_integer(sc, sc->input_ports->loc + sc->input_string_ports->loc), make_integer(sc, len)));
94252 
94253   gp = sc->output_ports;
94254   for (i = 0, len = 0; i < gp->loc; i++)
94255     {
94256       s7_pointer v;
94257       v = gp->list[i];
94258       if (port_data(v)) len += port_data_size(v);
94259     }
94260   make_slot_1(sc, mu_let, make_symbol(sc, "output-ports"), cons(sc, make_integer(sc, sc->output_ports->loc), make_integer(sc, len)));
94261 
94262   {
94263     s7_pointer p;
94264     for (i = 0, p = sc->format_ports; p; p = (s7_pointer)port_next(p));
94265     make_slot_1(sc, mu_let, make_symbol(sc, "format-ports"), make_integer(sc, i));
94266   }
94267 
94268   /* continuations (sketchy!) */
94269   gp = sc->continuations;
94270   for (i = 0, len = 0; i < gp->loc; i++)
94271     if (is_continuation(gp->list[i]))
94272       len += continuation_stack_size(gp->list[i]);
94273   if (len > 0)
94274     make_slot_1(sc, mu_let, make_symbol(sc, "continuations"), cons(sc, make_integer(sc, sc->continuations->loc), make_integer(sc, len * sizeof(s7_pointer))));
94275 
94276   /* c-objects */
94277   if (sc->c_objects->loc > 0)
94278     make_slot_1(sc, mu_let, make_symbol(sc, "c-objects"), make_integer(sc, sc->c_objects->loc));
94279 #if WITH_GMP
94280   make_slot_1(sc, mu_let, make_symbol(sc, "bignums"),
94281 	      s7_list(sc, 5, make_integer(sc, sc->big_integers->loc), make_integer(sc, sc->big_ratios->loc),
94282 		      make_integer(sc, sc->big_reals->loc), make_integer(sc, sc->big_complexes->loc),
94283 		      make_integer(sc, sc->big_random_states->loc)));
94284 #endif
94285 
94286   /* free-lists (mallocate) */
94287   {
94288     block_t *b;
94289     for (i = 0, len = 0, sc->w = sc->nil; i < TOP_BLOCK_LIST; i++)
94290       {
94291 	for (b = sc->block_lists[i], k = 0; b; b = block_next(b), k++);
94292 	sc->w = cons(sc, make_integer(sc, k), sc->w);
94293 	len += ((sizeof(block_t) + (1LL << i)) * k);
94294       }
94295     for (b = sc->block_lists[TOP_BLOCK_LIST], k = 0; b; b = block_next(b), k++)
94296       len += (sizeof(block_t) + block_size(b));
94297     sc->w = cons(sc, make_integer(sc, k), sc->w);
94298     make_slot_1(sc, mu_let, make_symbol(sc, "free-lists"),
94299 		list_2(sc, cons(sc, make_symbol(sc, "bytes"), kmg(sc, len)),
94300 		       cons(sc, make_symbol(sc, "bins"), proper_list_reverse_in_place(sc, sc->w))));
94301     sc->w = sc->nil;
94302     make_slot_1(sc, mu_let, make_symbol(sc, "approximate-s7-size"),
94303 		kmg(sc, ((sc->permanent_cells + NUM_SMALL_INTS + sc->heap_size) * sizeof(s7_cell)) +
94304 		    ((2 * sc->heap_size + SYMBOL_TABLE_SIZE + sc->stack_size) * sizeof(s7_pointer)) +
94305 		    len + hlen +
94306 		    (vlen * sizeof(s7_pointer)) + (flen * sizeof(s7_double)) + (ilen * sizeof(s7_int)) + blen));
94307   }
94308 
94309   s7_gc_unprotect_at(sc, gc_loc);
94310   return(mu_let);
94311 }
94312 
94313 static s7_pointer sl_c_types(s7_scheme *sc)
94314 {
94315   s7_pointer res;
94316   int32_t i;
94317   sc->w = sc->nil;
94318   for (i = 0; i < sc->num_c_object_types; i++)                       /*   c-object type (tag) is i */
94319     sc->w = cons(sc, sc->c_object_types[i]->scheme_name, sc->w);
94320   res = proper_list_reverse_in_place(sc, sc->w);                     /*   so car(types) has tag 0 */
94321   sc->w = sc->nil;
94322   return(res);
94323 }
94324 
94325 static s7_pointer sl_file_names(s7_scheme *sc)
94326 {
94327   int32_t i;
94328   s7_pointer p;
94329   sc->w = sc->nil;
94330   for (i = 0; i <= sc->file_names_top; i++)
94331     sc->w = cons(sc, sc->file_names[i], sc->w);
94332   p = proper_list_reverse_in_place(sc, sc->w);
94333   sc->w = sc->nil;
94334   return(p);
94335 }
94336 
94337 static s7_pointer sl_int_fixup(s7_scheme *sc, s7_pointer val)
94338 {
94339 #if WITH_GMP
94340   return(s7_int_to_big_integer(sc, s7_integer_checked(sc, val)));
94341 #else
94342   return(val);
94343 #endif
94344 }
94345 
94346 static s7_pointer sl_history(s7_scheme *sc)
94347 {
94348 #if WITH_HISTORY
94349     return(cull_history(sc, (sc->cur_code == sc->history_sink) ? sc->old_cur_code : sc->cur_code));
94350 #else
94351     return(sc->cur_code);
94352 #endif
94353 }
94354 
94355 static s7_pointer s7_let_field(s7_scheme *sc, s7_pointer sym)
94356 {
94357   switch (symbol_s7_let(sym))
94358     {
94359     case SL_ACCEPT_ALL_KEYWORD_ARGUMENTS:  return(make_boolean(sc, sc->accept_all_keyword_arguments));
94360     case SL_AUTOLOADING:                   return(s7_make_boolean(sc, sc->is_autoloading));
94361     case SL_BIGNUM_PRECISION:              return(make_integer(sc, sc->bignum_precision));
94362     case SL_CATCHES:                       return(active_catches(sc));
94363     case SL_CPU_TIME:                      return(s7_make_real(sc, (double)clock() / (double)CLOCKS_PER_SEC));
94364     case SL_C_TYPES:                       return(sl_c_types(sc));
94365     case SL_DEBUG:                         return(make_integer(sc, sc->debug));
94366     case SL_DEFAULT_HASH_TABLE_LENGTH:     return(make_integer(sc, sc->default_hash_table_length));
94367     case SL_DEFAULT_RANDOM_STATE:          return(sc->default_rng);
94368     case SL_DEFAULT_RATIONALIZE_ERROR:     return(make_real(sc, sc->default_rationalize_error));
94369     case SL_EQUIVALENT_FLOAT_EPSILON:      return(s7_make_real(sc, sc->equivalent_float_epsilon));
94370     case SL_FILE_NAMES:                    return(sl_file_names(sc));
94371     case SL_FLOAT_FORMAT_PRECISION:        return(make_integer(sc, sc->float_format_precision));
94372     case SL_FREE_HEAP_SIZE:                return(make_integer(sc, sc->free_heap_top - sc->free_heap));
94373     case SL_GC_FREED:                      return(make_integer(sc, sc->gc_freed));
94374     case SL_GC_TOTAL_FREED:                return(make_integer(sc, sc->gc_total_freed));
94375     case SL_GC_INFO:                       return(list_3(sc, make_integer(sc, sc->gc_calls), make_integer(sc, sc->gc_total_time), make_integer(sc, ticks_per_second())));
94376     case SL_GC_PROTECTED_OBJECTS:          return(sc->protected_objects);
94377     case SL_GC_STATS:                      return(make_integer(sc, sc->gc_stats));
94378     case SL_GC_TEMPS_SIZE:                 return(make_integer(sc, sc->gc_temps_size));
94379     case SL_GC_RESIZE_HEAP_FRACTION:       return(make_real(sc, sc->gc_resize_heap_fraction));
94380     case SL_GC_RESIZE_HEAP_BY_4_FRACTION:  return(make_real(sc, sc->gc_resize_heap_by_4_fraction));
94381     case SL_HASH_TABLE_FLOAT_EPSILON:      return(s7_make_real(sc, sc->hash_table_float_epsilon));
94382     case SL_HEAP_SIZE:                     return(make_integer(sc, sc->heap_size));
94383     case SL_HISTORY:                       return(sl_history(sc));
94384     case SL_HISTORY_ENABLED:               return(s7_make_boolean(sc, s7_history_enabled(sc)));
94385     case SL_HISTORY_SIZE:                  return(make_integer(sc, sc->history_size));
94386     case SL_INITIAL_STRING_PORT_LENGTH:    return(make_integer(sc, sc->initial_string_port_length));
94387     case SL_MAX_FORMAT_LENGTH:             return(make_integer(sc, sc->max_format_length));
94388     case SL_MAX_HEAP_SIZE:                 return(make_integer(sc, sc->max_heap_size));
94389     case SL_MAX_LIST_LENGTH:               return(make_integer(sc, sc->max_list_length));
94390     case SL_MAX_PORT_DATA_SIZE:            return(make_integer(sc, sc->max_port_data_size));
94391     case SL_MAX_STACK_SIZE:                return(make_integer(sc, sc->max_stack_size));
94392     case SL_MAX_STRING_LENGTH:             return(make_integer(sc, sc->max_string_length));
94393     case SL_MAX_VECTOR_DIMENSIONS:         return(make_integer(sc, sc->max_vector_dimensions));
94394     case SL_MAX_VECTOR_LENGTH:             return(make_integer(sc, sc->max_vector_length));
94395     case SL_MEMORY_USAGE:                  return(memory_usage(sc));
94396     case SL_MOST_NEGATIVE_FIXNUM:          return(sl_int_fixup(sc, leastfix));
94397     case SL_MOST_POSITIVE_FIXNUM:          return(sl_int_fixup(sc, mostfix));
94398     case SL_OPENLETS:                      return(s7_make_boolean(sc, sc->has_openlets));
94399     case SL_EXPANSIONS:                    return(s7_make_boolean(sc, sc->is_expanding));
94400     case SL_OUTPUT_PORT_DATA_SIZE:         return(make_integer(sc, sc->output_port_data_size));
94401     case SL_PRINT_LENGTH:                  return(make_integer(sc, sc->print_length));
94402     case SL_PROFILE:                       return(make_integer(sc, sc->profile));
94403     case SL_PROFILE_INFO:                  return(profile_info_out(sc));
94404     case SL_ROOTLET_SIZE:                  return(make_integer(sc, sc->rootlet_entries));
94405     case SL_SAFETY:                        return(make_integer(sc, sc->safety));
94406     case SL_STACK:                         return(stack_entries(sc, sc->stack, current_stack_top(sc)));
94407     case SL_STACKTRACE_DEFAULTS:           return(sc->stacktrace_defaults);
94408     case SL_STACK_SIZE:                    return(make_integer(sc, sc->stack_size));
94409     case SL_STACK_TOP:                     return(make_integer(sc, (sc->stack_end - sc->stack_start) / 4));
94410     case SL_UNDEFINED_CONSTANT_WARNINGS:   return(s7_make_boolean(sc, sc->undefined_constant_warnings));
94411     case SL_UNDEFINED_IDENTIFIER_WARNINGS: return(s7_make_boolean(sc, sc->undefined_identifier_warnings));
94412     case SL_VERSION:                       return(s7_make_string(sc, "s7 " S7_VERSION ", " S7_DATE));
94413     default:
94414       return(s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, wrap_string(sc, "can't get (*s7* '~S); no such field in *s7*", 43), sym)));
94415     }
94416   return(sc->undefined);
94417 }
94418 
94419 s7_pointer s7_let_field_ref(s7_scheme *sc, s7_pointer sym)
94420 {
94421   if (is_symbol(sym))
94422     {
94423       if (is_keyword(sym))
94424 	sym = keyword_symbol(sym);
94425       if (symbol_s7_let(sym) != SL_NO_FIELD)
94426 	return(s7_let_field(sc, sym));
94427     }
94428   return(sc->undefined);
94429 }
94430 
94431 static s7_pointer g_s7_let_ref_fallback(s7_scheme *sc, s7_pointer args)
94432 {
94433   s7_pointer sym;
94434 
94435   sym = cadr(args);
94436   if (!is_symbol(sym))
94437     return(simple_wrong_type_argument(sc, sc->let_ref_symbol, sym, T_SYMBOL));
94438   if (is_keyword(sym))
94439     sym = keyword_symbol(sym);
94440   return(s7_let_field(sc, sym));
94441 }
94442 
94443 static s7_pointer s7_let_iterate(s7_scheme *sc, s7_pointer iterator)
94444 {
94445   s7_pointer symbol, value, osw;
94446 
94447   iterator_position(iterator)++;
94448   if (iterator_position(iterator) >= SL_NUM_FIELDS)
94449     return(iterator_quit(iterator));
94450 
94451   symbol = make_symbol(sc, s7_let_field_names[iterator_position(iterator)]);
94452   osw = sc->w;  /* protect against s7_let_field list making */
94453   value = s7_let_field(sc, symbol);
94454   sc->w = osw;
94455 
94456   if (iterator_let_cons(iterator))
94457     {
94458       s7_pointer p;
94459       p = iterator_let_cons(iterator);
94460       set_car(p, symbol);
94461       set_cdr(p, value);
94462       return(p);
94463     }
94464   return(cons(sc, symbol, value));
94465 }
94466 
94467 static s7_pointer s7_let_make_iterator(s7_scheme *sc, s7_pointer iter)
94468 {
94469   iterator_position(iter) = SL_NO_FIELD;
94470   iterator_next(iter) = s7_let_iterate;
94471   iterator_let_cons(iter) = NULL;
94472   return(iter);
94473 }
94474 
94475 static s7_pointer sl_real_geq_0(s7_scheme *sc, s7_pointer sym, s7_pointer val)
94476 {
94477   if (!s7_is_real(val))
94478     return(simple_wrong_type_argument(sc, sym, val, T_REAL));
94479   return((s7_real(val) >= 0.0) ? val : simple_out_of_range(sc, sym, val, wrap_string(sc, "should not be negative", 22)));
94480 }
94481 
94482 static s7_pointer sl_integer_gt_0(s7_scheme *sc, s7_pointer sym, s7_pointer val)
94483 {
94484   if (!s7_is_integer(val))
94485     return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
94486   return((s7_integer_checked(sc, val) > 0) ? val : simple_out_of_range(sc, sym, val, wrap_string(sc, "should be positive", 18)));
94487 }
94488 
94489 static s7_pointer sl_integer_geq_0(s7_scheme *sc, s7_pointer sym, s7_pointer val)
94490 {
94491   if (!s7_is_integer(val))
94492     return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
94493   return((s7_integer_checked(sc, val) >= 0) ? val : simple_out_of_range(sc, sym, val, wrap_string(sc, "should not be negative", 22)));
94494 }
94495 
94496 #if WITH_HISTORY
94497 static void sl_set_history_size(s7_scheme *sc, s7_int iv)
94498 {
94499   s7_pointer p1, p2, p3;
94500   if (iv > MAX_HISTORY_SIZE) iv = MAX_HISTORY_SIZE;
94501   if (iv > sc->true_history_size)
94502     {
94503       /* splice in the new cells, reattach the circles */
94504       s7_pointer next1, next2, next3;
94505       next1 = cdr(sc->eval_history1);
94506       next2 = cdr(sc->eval_history2);
94507       next3 = cdr(sc->history_pairs);
94508       set_cdr(sc->eval_history1, permanent_list(sc, iv - sc->true_history_size));
94509       set_cdr(sc->eval_history2, permanent_list(sc, iv - sc->true_history_size));
94510       set_cdr(sc->history_pairs, permanent_list(sc, iv - sc->true_history_size));
94511       for (p3 = cdr(sc->history_pairs); is_pair(cdr(p3)); p3 = cdr(p3)) set_car(p3, permanent_list(sc, 1));
94512       set_car(p3, permanent_list(sc, 1));
94513       set_cdr(p3, next3);
94514       for (p1 = sc->eval_history1, p2 = sc->eval_history2; is_pair(cdr(p1)); p1 = cdr(p1), p2 = cdr(p2));
94515       set_cdr(p1, next1);
94516       set_cdr(p2, next2);
94517       sc->true_history_size = iv;
94518     }
94519   sc->history_size = iv;
94520   /* clear out both buffers to avoid GC confusion */
94521   for (p1 = sc->eval_history1, p2 = sc->eval_history2; ; p2 = cdr(p2))
94522     {
94523       set_car(p1, sc->nil);
94524       set_car(p2, sc->nil);
94525       p1 = cdr(p1);
94526       if (p1 == sc->eval_history1) break;
94527     }
94528 }
94529 #endif
94530 
94531 #if WITH_GMP
94532 static s7_pointer set_bignum_precision(s7_scheme *sc, int32_t precision)
94533 {
94534   mp_prec_t bits;
94535   s7_pointer bpi;
94536   if (precision <= 1)                   /* (set! (*s7* 'bignum-precision) 1) causes mpfr to segfault! (also 0 and -1) */
94537     return(s7_out_of_range_error(sc, "set! (*s7* 'bignum-precision)", 0, wrap_integer2(sc, precision), "has to be greater than 1"));
94538   bits = (mp_prec_t)precision;
94539   mpfr_set_default_prec(bits);
94540   mpc_set_default_precision(bits);
94541   bpi = big_pi(sc);
94542   s7_symbol_set_value(sc, sc->pi_symbol, bpi);
94543   slot_set_value(initial_slot(sc->pi_symbol), bpi); /* if #_pi occurs after precision set, make sure #_pi is still legit (not a free cell) */
94544   return(sc->F);
94545 }
94546 #endif
94547 
94548 static s7_pointer sl_unsettable_error(s7_scheme *sc, s7_pointer sym)
94549 {
94550   return(s7_error(sc, sc->immutable_error_symbol, set_elist_2(sc, wrap_string(sc, "can't set (*s7* '~S)", 20), sym)));
94551 }
94552 
94553 static s7_pointer g_s7_let_set_fallback(s7_scheme *sc, s7_pointer args)
94554 {
94555   s7_pointer sym, val;
94556 
94557   sym = cadr(args);
94558   if (!is_symbol(sym))
94559     return(simple_wrong_type_argument(sc, sc->let_set_symbol, sym, T_SYMBOL));
94560   if (is_keyword(sym))
94561     sym = keyword_symbol(sym);
94562   val = caddr(args);
94563 
94564   switch (symbol_s7_let(sym))
94565     {
94566     case SL_ACCEPT_ALL_KEYWORD_ARGUMENTS:
94567       if (s7_is_boolean(val)) {sc->accept_all_keyword_arguments = s7_boolean(sc, val); return(val);}
94568       return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
94569 
94570     case SL_AUTOLOADING:
94571       if (s7_is_boolean(val)) {sc->is_autoloading = s7_boolean(sc, val); return(val);}
94572       return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
94573 
94574     case SL_BIGNUM_PRECISION:
94575       {
94576 	s7_int iv;
94577 	iv = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val));
94578 	sc->bignum_precision = iv;
94579 #if WITH_GMP
94580 	set_bignum_precision(sc, sc->bignum_precision);
94581 	mpfr_set_prec(sc->mpfr_1, sc->bignum_precision);
94582 	mpfr_set_prec(sc->mpfr_2, sc->bignum_precision);
94583 	mpc_set_prec(sc->mpc_1, sc->bignum_precision);
94584 	mpc_set_prec(sc->mpc_2, sc->bignum_precision);
94585 #endif
94586 	return(val);
94587       }
94588 
94589     case SL_CATCHES:  return(sl_unsettable_error(sc, sym));
94590     case SL_CPU_TIME: return(sl_unsettable_error(sc, sym));
94591     case SL_C_TYPES:  return(sl_unsettable_error(sc, sym));
94592 
94593     case SL_DEBUG:
94594       if (s7_is_integer(val))
94595 	{
94596 	  sc->debug = s7_integer_checked(sc, val);
94597 	  sc->debug_or_profile = ((sc->debug  > 1) || (sc->profile > 0));
94598 	  if ((sc->debug > 0) &&
94599 	      (!is_memq(make_symbol(sc, "debug.scm"), s7_symbol_value(sc, sc->features_symbol))))
94600 	    s7_load(sc, "debug.scm");
94601 	  return(val);
94602 	}
94603       return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
94604 
94605     case SL_DEFAULT_HASH_TABLE_LENGTH:
94606       sc->default_hash_table_length = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val));
94607       return(val);
94608 
94609     case SL_DEFAULT_RANDOM_STATE:
94610       if (is_random_state(val))
94611 	{
94612 #if (!WITH_GMP)
94613 	  random_seed(sc->default_rng) = random_seed(val);
94614 	  random_carry(sc->default_rng) = random_carry(val);
94615 #endif
94616 	  return(val);
94617 	}
94618       return(wrong_type_argument_with_type(sc, sym, 1, val, a_random_state_object_string));
94619 
94620     case SL_DEFAULT_RATIONALIZE_ERROR:
94621       sc->default_rationalize_error = s7_real(sl_real_geq_0(sc, sym, val));
94622       return(val);
94623 
94624     case SL_EQUIVALENT_FLOAT_EPSILON:
94625       sc->equivalent_float_epsilon = s7_real(sl_real_geq_0(sc, sym, val));
94626       return(val);
94627 
94628     case SL_FILE_NAMES:
94629       return(sl_unsettable_error(sc, sym));
94630 
94631     case SL_FLOAT_FORMAT_PRECISION:
94632       {
94633 	s7_int iv; /* float-format-precision should not be huge => hangs in snprintf -- what's a reasonable limit here? */
94634 	iv = s7_integer_checked(sc, sl_integer_geq_0(sc, sym, val));
94635 	sc->float_format_precision = (iv < MAX_FLOAT_FORMAT_PRECISION) ? iv : MAX_FLOAT_FORMAT_PRECISION;
94636 	return(val);
94637       }
94638 
94639     case SL_FREE_HEAP_SIZE:       return(sl_unsettable_error(sc, sym));
94640     case SL_GC_FREED:             return(sl_unsettable_error(sc, sym));
94641     case SL_GC_TOTAL_FREED:       return(sl_unsettable_error(sc, sym));
94642     case SL_GC_PROTECTED_OBJECTS: return(sl_unsettable_error(sc, sym));
94643     case SL_GC_TEMPS_SIZE:                sc->gc_temps_size = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val)); return(val);
94644     case SL_GC_RESIZE_HEAP_FRACTION:      sc->gc_resize_heap_fraction = s7_real(sl_real_geq_0(sc, sym, val)); return(val);
94645     case SL_GC_RESIZE_HEAP_BY_4_FRACTION: sc->gc_resize_heap_by_4_fraction = s7_real(sl_real_geq_0(sc, sym, val)); return(val);
94646 
94647     case SL_GC_STATS:
94648       if (s7_is_boolean(val))
94649 	{
94650 	  sc->gc_stats = ((val == sc->T) ? GC_STATS : 0);
94651 	  return(val);
94652 	}
94653       if (s7_is_integer(val))
94654 	{
94655 	  sc->gc_stats = s7_integer_checked(sc, val);
94656 	  if (sc->gc_stats < 16) /* gc_stats is uint32_t */
94657 	    return(val);
94658 	  sc->gc_stats = 0;
94659 	  return(simple_out_of_range(sc, sym, val, wrap_string(sc, "should be between 0 and 15", 26)));
94660 	}
94661       return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
94662 
94663     case SL_GC_INFO:
94664       if (val == sc->F)
94665 	{
94666 	  sc->gc_total_time = 0;
94667 	  sc->gc_calls = 0;
94668 	  return(sc->F);
94669 	}
94670       return(simple_wrong_type_argument_with_type(sc, sym, val, wrap_string(sc, "#f (to clear gc_calls and gc_total_time)", 40)));
94671 
94672     case SL_HASH_TABLE_FLOAT_EPSILON:
94673       sc->hash_table_float_epsilon = s7_real(sl_real_geq_0(sc, sym, val));
94674       return(val);
94675 
94676     case SL_HEAP_SIZE:
94677       {
94678 	s7_int iv;
94679 	iv = s7_integer_checked(sc, sl_integer_geq_0(sc, sym, val));
94680 	if (iv > sc->heap_size)
94681 	  resize_heap_to(sc, iv);
94682 	return(val);
94683       }
94684 
94685     case SL_HISTORY:               /* (set! (*s7* 'history) val) */
94686       replace_current_code(sc, val);
94687       return(val);
94688 
94689     case SL_HISTORY_ENABLED:       /* (set! (*s7* 'history-enabled) #f|#t) */
94690       if (s7_is_boolean(val))
94691 	return(s7_make_boolean(sc, s7_set_history_enabled(sc, s7_boolean(sc, val))));
94692       return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
94693 
94694     case SL_HISTORY_SIZE:
94695       {
94696 	s7_int iv;
94697 	iv = s7_integer_checked(sc, sl_integer_geq_0(sc, sym, val));
94698 #if WITH_HISTORY
94699 	sl_set_history_size(sc, iv);
94700 #else
94701 	sc->history_size = iv;
94702 #endif
94703 	return(val);
94704       }
94705 
94706     case SL_INITIAL_STRING_PORT_LENGTH: sc->initial_string_port_length = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val)); return(val);
94707     case SL_MAX_FORMAT_LENGTH:          sc->max_format_length = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val));          return(val);
94708     case SL_MAX_HEAP_SIZE:              sc->max_heap_size = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val));              return(val);
94709     case SL_MAX_LIST_LENGTH:            sc->max_list_length = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val));            return(val);
94710     case SL_MAX_PORT_DATA_SIZE:         sc->max_port_data_size = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val));         return(val);
94711 
94712     case SL_MAX_STACK_SIZE:
94713       {
94714 	s7_int iv;
94715 	iv = s7_integer_checked(sc, sl_integer_geq_0(sc, sym, val));
94716 	if (iv < INITIAL_STACK_SIZE)
94717 	  return(simple_out_of_range(sc, sym, val, wrap_string(sc, "should be greater than the initial stack size", 45)));
94718 	sc->max_stack_size = (uint32_t)iv;
94719 	return(val);
94720       }
94721 
94722     case SL_MAX_STRING_LENGTH:     sc->max_string_length = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val));     return(val);
94723     case SL_MAX_VECTOR_DIMENSIONS: sc->max_vector_dimensions = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val)); return(val);
94724     case SL_MAX_VECTOR_LENGTH:     sc->max_vector_length = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val));     return(val);
94725     case SL_MEMORY_USAGE:          return(sl_unsettable_error(sc, sym));
94726     case SL_MOST_NEGATIVE_FIXNUM:  return(sl_unsettable_error(sc, sym));
94727     case SL_MOST_POSITIVE_FIXNUM:  return(sl_unsettable_error(sc, sym));
94728 
94729     case SL_OPENLETS:
94730       if (s7_is_boolean(val)) {sc->has_openlets = s7_boolean(sc, val); return(val);}
94731       return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
94732 
94733     case SL_EXPANSIONS:
94734       if (s7_is_boolean(val)) {sc->is_expanding = s7_boolean(sc, val); return(val);}
94735       return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
94736 
94737     case SL_OUTPUT_PORT_DATA_SIZE: sc->output_port_data_size = s7_integer_checked(sc, sl_integer_gt_0(sc, sym, val)); return(val);
94738     case SL_PRINT_LENGTH:          sc->print_length = s7_integer_checked(sc, sl_integer_geq_0(sc, sym, val));         return(val);
94739 
94740     case SL_PROFILE:
94741       if (s7_is_integer(val))
94742 	{
94743 	  sc->profile = s7_integer_checked(sc, val);
94744 	  sc->debug_or_profile = ((sc->debug  > 1) || (sc->profile > 0));
94745 	  if (sc->profile > 0)
94746 	    {
94747 	      if (!is_memq(make_symbol(sc, "profile.scm"), s7_symbol_value(sc, sc->features_symbol)))
94748 		s7_load(sc, "profile.scm");
94749 	      if (!sc->profile_data)
94750 		make_profile_info(sc);
94751 	      if (!sc->profile_out)
94752 		sc->profile_out = s7_make_function(sc, "profile-out", g_profile_out, 2, 0, false, NULL);
94753 	    }
94754 	  return(val);
94755 	}
94756       return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
94757 
94758     case SL_PROFILE_INFO:
94759       return((val == sc->F) ? clear_profile_info(sc) : simple_wrong_type_argument_with_type(sc, sym, val, wrap_string(sc, "#f (to clear the table)", 23)));
94760 
94761     case SL_ROOTLET_SIZE: return(sl_unsettable_error(sc, sym));
94762 
94763     case SL_SAFETY:
94764       if (s7_is_integer(val))
94765 	{
94766 	  if ((s7_integer_checked(sc, val) > 2) || (s7_integer_checked(sc, val) < -1))
94767 	    return(simple_out_of_range(sc, sym, val, wrap_string(sc, "should be between -1 (no safety) and 2 (max safety)", 51)));
94768 	  sc->safety = s7_integer_checked(sc, val);
94769 	  return(val);
94770 	}
94771       return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
94772 
94773     case SL_STACKTRACE_DEFAULTS:
94774       if (!is_pair(val))
94775 	return(simple_wrong_type_argument(sc, sym, val, T_PAIR));
94776       if (s7_list_length(sc, val) != 5)
94777 	return(simple_wrong_type_argument_with_type(sc, sym, val, wrap_string(sc, "a list with 5 entries", 21)));
94778       if (!is_t_integer(car(val)))
94779 	return(wrong_type_argument_with_type(sc, sym, 1, car(val), wrap_string(sc, "an integer (stack frames)", 25)));
94780       if (!is_t_integer(cadr(val)))
94781 	return(wrong_type_argument_with_type(sc, sym, 2, cadr(val), wrap_string(sc, "an integer (cols-for-data)", 26)));
94782       if (!is_t_integer(caddr(val)))
94783 	return(wrong_type_argument_with_type(sc, sym, 3, caddr(val), wrap_string(sc, "an integer (line length)", 24)));
94784       if (!is_t_integer(cadddr(val)))
94785 	return(wrong_type_argument_with_type(sc, sym, 4, cadddr(val), wrap_string(sc, "an integer (comment position)", 29)));
94786       if (!s7_is_boolean(s7_list_ref(sc, val, 4)))
94787 	return(wrong_type_argument_with_type(sc, sym, 5, s7_list_ref(sc, val, 4), wrap_string(sc, "a boolean (treat-data-as-comment)", 33)));
94788       sc->stacktrace_defaults = copy_proper_list(sc, val);
94789       return(val);
94790 
94791     case SL_STACK:
94792     case SL_STACK_SIZE:
94793     case SL_STACK_TOP:  return(sl_unsettable_error(sc, sym));
94794 
94795     case SL_UNDEFINED_CONSTANT_WARNINGS:
94796       if (s7_is_boolean(val)) {sc->undefined_constant_warnings = s7_boolean(sc, val); return(val);}
94797       return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
94798 
94799     case SL_UNDEFINED_IDENTIFIER_WARNINGS:
94800       if (s7_is_boolean(val)) {sc->undefined_identifier_warnings = s7_boolean(sc, val); return(val);}
94801       return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
94802 
94803     case SL_VERSION:  return(sl_unsettable_error(sc, sym));
94804 
94805     default:
94806       return(s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, wrap_string(sc, "can't set (*s7* '~S); no such field in *s7*", 43), sym)));
94807     }
94808   return(sc->undefined);
94809 }
94810 
94811 s7_pointer s7_let_field_set(s7_scheme *sc, s7_pointer sym, s7_pointer new_value)
94812 {
94813   if (is_symbol(sym))
94814     {
94815       if (is_keyword(sym))
94816 	sym = keyword_symbol(sym);
94817       if (symbol_s7_let(sym) != SL_NO_FIELD)
94818 	return(g_s7_let_set_fallback(sc, set_plist_3(sc, sc->s7_let_symbol, sym, new_value)));
94819     }
94820   return(sc->undefined);
94821 }
94822 
94823 
94824 /* ---------------- gdbinit annotated stacktrace ---------------- */
94825 #if (!MS_WINDOWS)
94826 /* s7bt, s7fullbt: gdb stacktrace decoding */
94827 
94828 static const char *decoded_name(s7_scheme *sc, s7_pointer p)
94829 {
94830   if (p == sc->value) return("value");
94831   if (p == sc->args) return("args");
94832   if (p == sc->code) return("code");
94833   if (p == sc->cur_code) return("cur_code");
94834   if (p == sc->curlet) return("curlet");
94835   if (p == sc->nil) return("()");
94836   if (p == sc->T) return("#t");
94837   if (p == sc->F) return("#f");
94838   if (p == eof_object) return("eof_object");
94839   if (p == sc->undefined) return("undefined");
94840   if (p == sc->unspecified) return("unspecified");
94841   if (p == sc->no_value) return("no_value");
94842   if (p == sc->unused) return("#<unused>");
94843   if (p == sc->symbol_table) return("symbol_table");
94844   if (p == sc->rootlet) return("rootlet");
94845   if (p == sc->s7_let) return("*s7*");
94846   if (p == sc->unlet) return("unlet");
94847   if (p == current_input_port(sc)) return("current-input-port");
94848   if (p == current_output_port(sc)) return("current-output-port");
94849   if (p == sc->error_port) return("error_port");
94850   if (p == sc->owlet) return("owlet");
94851   if (p == sc->standard_input) return("*stdin*");
94852   if (p == sc->standard_output) return("*stdout*");
94853   if (p == sc->standard_error) return("*stderr*");
94854   if (p == sc->else_symbol) return("else_symbol");
94855   return((p == sc->stack) ? "stack" : NULL);
94856 }
94857 
94858 static bool is_decodable(s7_scheme *sc, s7_pointer p)
94859 {
94860   int32_t i;
94861   s7_pointer x;
94862   s7_pointer *tp, *heap_top;
94863 
94864   /* check symbol-table */
94865   for (i = 0; i < SYMBOL_TABLE_SIZE; i++)
94866     for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
94867       {
94868 	s7_pointer sym;
94869 	sym = car(x);
94870 	if ((sym == p) ||
94871 	    ((is_global(sym)) && (is_slot(global_slot(sym))) && (p == global_value(sym))))
94872 	  return(true);
94873       }
94874 
94875   for (i = 0; i < NUM_CHARS; i++) if (p == chars[i]) return(true);
94876   for (i = 0; i < NUM_SMALL_INTS; i++) if (p == small_ints[i]) return(true);
94877 
94878   /* check the heap */
94879   tp = sc->heap;
94880   heap_top = (s7_pointer *)(sc->heap + sc->heap_size);
94881   while (tp < heap_top)
94882     if (p == (*tp++))
94883       return(true);
94884 
94885   return(false);
94886 }
94887 
94888 char *s7_decode_bt(s7_scheme *sc)
94889 {
94890   FILE *fp;
94891   fp = fopen("gdb.txt", "r");
94892   if (fp)
94893     {
94894       int64_t i, size;
94895       size_t bytes;
94896       bool in_quotes = false, old_stop;
94897       uint8_t *bt;
94898       block_t *bt_block;
94899 
94900       old_stop = sc->stop_at_error;
94901       sc->stop_at_error = false;
94902       fseek(fp, 0, SEEK_END);
94903       size = ftell(fp);
94904       rewind(fp);
94905 
94906       bt_block = mallocate(sc, (size + 1) * sizeof(uint8_t));
94907       bt = (uint8_t *)block_data(bt_block);
94908       bytes = fread(bt, sizeof(uint8_t), size, fp);
94909       if (bytes != (size_t)size)
94910 	{
94911 	  fclose(fp);
94912 	  liberate(sc, bt_block);
94913 	  return((char *)" oops ");
94914 	}
94915       bt[size] = '\0';
94916       fclose(fp);
94917 
94918       for (i = 0; i < size; i++)
94919 	{
94920 	  fputc(bt[i], stdout);
94921 	  if ((bt[i] == '"') && ((i == 0) || (bt[i - 1] != '\\')))
94922 	    in_quotes = (!in_quotes);
94923 	  else
94924 	    if ((!in_quotes) && (i < size - 8) &&
94925 		((bt[i] == '=') &&
94926 		 (((bt[i + 1] == '0') && (bt[i + 2] == 'x')) ||
94927 		  ((bt[i + 1] == ' ') && (bt[i + 2] == '0') && (bt[i + 3] == 'x')))))
94928 	      {
94929 		void *vp;
94930 		int32_t vals;
94931 		vals = sscanf((const char *)(bt + i + 1), "%p", &vp);
94932 		if ((vp) && (vals == 1))
94933 		  {
94934 		    int32_t k;
94935 		    for (k = i + ((bt[i + 2] == 'x') ? 3 : 4); (k < size) && (IS_DIGIT(bt[k], 16)); k++);
94936 		    if ((bt[k] != ' ') || (bt[k + 1] != '"'))
94937 		      {
94938 			if (vp == (void *)sc)
94939 			  {
94940 			    if (bt[i + 1] == ' ') fputc(' ', stdout);
94941 			    fprintf(stdout, "%s[s7]%s", BOLD_TEXT, UNBOLD_TEXT);
94942 			    i = k - 1;
94943 			  }
94944 			else
94945 			  {
94946 			    s7_pointer p;
94947 			    const char *dname;
94948 			    p = (s7_pointer)vp;
94949 			    dname = decoded_name(sc, p);
94950 			    if (dname)
94951 			      {
94952 				if (bt[i + 1] == ' ') fputc(' ', stdout);
94953 				fprintf(stdout, "%s[sc->%s]%s", BOLD_TEXT, dname, UNBOLD_TEXT);
94954 			      }
94955 			    if ((dname) || (is_decodable(sc, p)))
94956 			      {
94957 				if (bt[i + 1] == ' ') fputc(' ', stdout);
94958 				i = k - 1;
94959 				if (s7_is_valid(sc, p))
94960 				  {
94961 				    s7_pointer strp;
94962 				    if (dname) fprintf(stdout, " ");
94963 				    strp = object_to_truncated_string(sc, p, 80);
94964 				    fprintf(stdout, "%s%s%s", BOLD_TEXT, string_value(strp), UNBOLD_TEXT);
94965 				    if ((is_pair(p)) &&
94966 					(has_location(p)))
94967 				      {
94968 					uint32_t line, file;
94969 					line = pair_line_number(p);
94970 					file = pair_file_number(p);
94971 					if (line > 0)
94972 					  fprintf(stdout, " %s(%s[%u])%s", BOLD_TEXT, string_value(sc->file_names[file]), line, UNBOLD_TEXT);
94973 				      }}}}}}}}
94974       liberate(sc, bt_block);
94975       sc->stop_at_error = old_stop;
94976     }
94977   return((char *)"");
94978 }
94979 #endif
94980 
94981 
94982 /* -------------------------------- initialization -------------------------------- */
94983 
94984 static void init_fx_function(void)
94985 {
94986   int32_t i;
94987   for (i = 0; i < NUM_OPS; i++)
94988     fx_function[i] = NULL;
94989 
94990   fx_function[HOP_SAFE_C_D] = fx_c_d;
94991   fx_function[HOP_SAFE_C_S] = fx_c_s;
94992   fx_function[HOP_SAFE_C_SC] = fx_c_sc;
94993   fx_function[HOP_SAFE_C_CS] = fx_c_cs;
94994   fx_function[HOP_SAFE_C_CQ] = fx_c_cq;
94995   fx_function[HOP_SAFE_C_FF] = fx_c_ff;
94996   fx_function[HOP_SAFE_C_SS] = fx_c_ss;
94997   fx_function[HOP_SAFE_C_opDq] = fx_c_opdq;
94998   fx_function[HOP_SAFE_C_opSq] = fx_c_opsq;
94999   fx_function[HOP_SAFE_C_opSSq] = fx_c_opssq;
95000   fx_function[HOP_SAFE_C_opSCq] = fx_c_opscq;
95001   fx_function[HOP_SAFE_C_opCSq] = fx_c_opcsq;
95002   fx_function[HOP_SAFE_C_opSq_S] = fx_c_opsq_s;
95003   fx_function[HOP_SAFE_C_opSq_C] = fx_c_opsq_c;
95004   fx_function[HOP_SAFE_C_opSq_CS] = fx_c_opsq_cs;
95005   fx_function[HOP_SAFE_C_S_opSq] = fx_c_s_opsq;
95006   fx_function[HOP_SAFE_C_C_opSq] = fx_c_c_opsq;
95007   fx_function[HOP_SAFE_C_opCSq_C] = fx_c_opcsq_c;
95008   fx_function[HOP_SAFE_C_opCSq_S] = fx_c_opcsq_s;
95009   fx_function[HOP_SAFE_C_S_opCSq] = fx_c_s_opcsq;
95010   fx_function[HOP_SAFE_C_opSSq_C] = fx_c_opssq_c;
95011   fx_function[HOP_SAFE_C_opSCq_C] = fx_c_opscq_c;
95012   fx_function[HOP_SAFE_C_opSSq_S] = fx_c_opssq_s;
95013   fx_function[HOP_SAFE_C_S_opSSq] = fx_c_s_opssq;
95014   fx_function[HOP_SAFE_C_C_opSSq] = fx_c_c_opssq;
95015   fx_function[HOP_SAFE_C_S_opSCq] = fx_c_s_opscq;
95016   fx_function[HOP_SAFE_C_C_opSCq] = fx_c_c_opscq;
95017   fx_function[HOP_SAFE_C_opSq_opSq] = fx_c_opsq_opsq;
95018   fx_function[HOP_SAFE_C_opSq_opSSq] = fx_c_opsq_opssq;
95019   fx_function[HOP_SAFE_C_opSSq_opSq] = fx_c_opssq_opsq;
95020   fx_function[HOP_SAFE_C_opSSq_opSSq] = fx_c_opssq_opssq;
95021   fx_function[HOP_SAFE_C_op_opSqq] = fx_c_op_opsqq;
95022   fx_function[HOP_SAFE_C_op_S_opSqq] = fx_c_op_s_opsqq;
95023   fx_function[HOP_SAFE_C_op_opSq_Sq] = fx_c_op_opsq_sq;
95024   fx_function[HOP_SAFE_C_op_opSSqq_S] = fx_c_op_opssqq_s;
95025 
95026   fx_function[HOP_SAFE_C_SSC] = fx_c_ssc;
95027   fx_function[HOP_SAFE_C_SSS] = fx_c_sss;
95028   fx_function[HOP_SAFE_C_SCS] = fx_c_scs;
95029   fx_function[HOP_SAFE_C_SCC] = fx_c_scc;
95030   fx_function[HOP_SAFE_C_CSS] = fx_c_css;
95031   fx_function[HOP_SAFE_C_CSC] = fx_c_csc;
95032   fx_function[HOP_SAFE_C_CCS] = fx_c_ccs;
95033   fx_function[HOP_SAFE_C_ALL_S] = fx_c_all_s;
95034 
95035   fx_function[HOP_SAFE_C_A] = fx_c_a;
95036   fx_function[HOP_SAFE_C_AA] = fx_c_aa;
95037   fx_function[HOP_SAFE_C_SA] = fx_c_sa;
95038   fx_function[HOP_SAFE_C_AS] = fx_c_as;
95039   fx_function[HOP_SAFE_C_CA] = fx_c_ca;
95040   fx_function[HOP_SAFE_C_AC] = fx_c_ac;
95041   fx_function[HOP_SAFE_C_AAA] = fx_c_aaa;
95042   fx_function[HOP_SAFE_C_CAC] = fx_c_cac;
95043   fx_function[HOP_SAFE_C_CSA] = fx_c_csa;
95044   fx_function[HOP_SAFE_C_SCA] = fx_c_sca;
95045   fx_function[HOP_SAFE_C_SAS] = fx_c_sas;
95046   fx_function[HOP_SAFE_C_SAA] = fx_c_saa;
95047   fx_function[HOP_SAFE_C_SSA] = fx_c_ssa;
95048   fx_function[HOP_SAFE_C_ASS] = fx_c_ass;
95049   fx_function[HOP_SAFE_C_ALL_CA] = fx_c_all_ca;
95050   fx_function[HOP_SAFE_C_INLET_CA] = fx_inlet_ca;
95051   fx_function[HOP_SAFE_C_ALL_A] = fx_c_all_a;
95052   fx_function[HOP_SAFE_C_4A] = fx_c_4a;
95053   fx_function[HOP_SAFE_C_opAq] = fx_c_opaq;
95054   fx_function[HOP_SAFE_C_opAAq] = fx_c_opaaq;
95055   fx_function[HOP_SAFE_C_opAAAq] = fx_c_opaaaq;
95056   fx_function[HOP_SAFE_C_opAq_S] = fx_c_opaq_s;
95057   fx_function[HOP_SAFE_C_S_opAq] = fx_c_s_opaq;
95058   fx_function[HOP_SAFE_C_S_opAAq] = fx_c_s_opaaq;
95059   fx_function[HOP_SAFE_C_S_opAAAq] = fx_c_s_opaaaq;
95060 
95061   fx_function[HOP_SSA_DIRECT] = fx_c_ssa_direct;
95062   fx_function[HOP_HASH_TABLE_INCREMENT] = fx_hash_table_increment;
95063 
95064   fx_function[HOP_SAFE_THUNK_A] = fx_safe_thunk_a;
95065   fx_function[HOP_SAFE_CLOSURE_S_A] = fx_safe_closure_s_a;
95066   fx_function[HOP_SAFE_CLOSURE_A_A] = fx_safe_closure_a_a;
95067   fx_function[HOP_SAFE_CLOSURE_SS_A] = fx_safe_closure_ss_a;
95068   fx_function[HOP_SAFE_CLOSURE_AA_A] = fx_safe_closure_aa_a;
95069   fx_function[HOP_SAFE_CLOSURE_3S_A] = fx_safe_closure_3s_a;
95070   fx_function[HOP_SAFE_CLOSURE_S_TO_S] = fx_safe_closure_s_to_s;
95071   fx_function[HOP_SAFE_CLOSURE_S_TO_SC] = fx_safe_closure_s_to_sc;
95072   fx_function[HOP_SAFE_CLOSURE_A_TO_SC] = fx_safe_closure_a_to_sc;
95073 
95074   fx_function[OP_COND_FX_FX] = fx_cond_fx_fx;
95075   fx_function[OP_IF_A_C_C] = fx_if_a_c_c;
95076   fx_function[OP_IF_A_A] = fx_if_a_a;
95077   fx_function[OP_IF_S_A_A] = fx_if_s_a_a;
95078   fx_function[OP_IF_A_A_A] = fx_if_a_a_a;
95079   fx_function[OP_IF_AND2_S_A] = fx_if_and2_s_a;
95080   fx_function[OP_IF_NOT_A_A] = fx_if_not_a_a;
95081   fx_function[OP_IF_NOT_A_A_A] = fx_if_not_a_a_a;
95082   fx_function[OP_IF_IS_TYPE_S_A_A] = fx_if_is_type_s_a_a;
95083   fx_function[OP_OR_2] = fx_or_2;
95084   fx_function[OP_OR_S_2] = fx_or_s_2;
95085   fx_function[OP_OR_S_TYPE_2] = fx_or_s_type_2;
95086   fx_function[OP_OR_3] = fx_or_3;
95087   fx_function[OP_OR_N] = fx_or_n;
95088   fx_function[OP_AND_2] = fx_and_2;
95089   fx_function[OP_AND_S_2] = fx_and_s_2;
95090   fx_function[OP_AND_3] = fx_and_3;
95091   fx_function[OP_AND_N] = fx_and_n;
95092   fx_function[OP_BEGIN_ALL_A] = fx_begin_all_a;
95093   fx_function[OP_BEGIN_AA] = fx_begin_aa;
95094   fx_function[OP_LET_TEMP_A_A] = fx_let_temp_a_a;
95095   fx_function[OP_IMPLICIT_S7_LET_REF_S] = fx_implicit_s7_let_ref_s;
95096   fx_function[OP_IMPLICIT_S7_LET_SET_SA] = fx_implicit_s7_let_set_sa;
95097 
95098   /* these are ok even if a "z" branch is taken -- in that case the body does not have the is_optimized bit, so is_fxable returns false */
95099   fx_function[OP_TC_AND_A_OR_A_LA] = fx_tc_and_a_or_a_la;
95100   fx_function[OP_TC_OR_A_AND_A_LA] = fx_tc_or_a_and_a_la;
95101   fx_function[OP_TC_OR_A_A_AND_A_A_LA] = fx_tc_or_a_a_and_a_a_la;
95102   fx_function[OP_TC_AND_A_OR_A_LAA] = fx_tc_and_a_or_a_laa;
95103   fx_function[OP_TC_OR_A_AND_A_LAA] = fx_tc_or_a_and_a_laa;
95104   fx_function[OP_TC_AND_A_OR_A_A_LA] = fx_tc_and_a_or_a_a_la;
95105   fx_function[OP_TC_OR_A_AND_A_A_LA] = fx_tc_or_a_and_a_a_la;
95106   fx_function[OP_TC_IF_A_Z_LA] = fx_tc_if_a_z_la;
95107   fx_function[OP_TC_IF_A_LA_Z] = fx_tc_if_a_la_z;
95108   fx_function[OP_TC_COND_A_Z_LA] = fx_tc_cond_a_z_la;
95109   fx_function[OP_TC_COND_A_LA_Z] = fx_tc_cond_a_la_z;
95110   fx_function[OP_TC_IF_A_Z_LAA] = fx_tc_if_a_z_laa;
95111   fx_function[OP_TC_IF_A_LAA_Z] = fx_tc_if_a_laa_z;
95112   fx_function[OP_TC_COND_A_Z_LAA] = fx_tc_cond_a_z_laa;
95113   fx_function[OP_TC_COND_A_LAA_Z] = fx_tc_cond_a_laa_z;
95114   fx_function[OP_TC_IF_A_Z_L3A] = fx_tc_if_a_z_l3a;
95115   fx_function[OP_TC_IF_A_L3A_Z] = fx_tc_if_a_l3a_z;
95116   fx_function[OP_TC_IF_A_Z_IF_A_Z_LA] = fx_tc_if_a_z_if_a_z_la;
95117   fx_function[OP_TC_IF_A_Z_IF_A_LA_Z] = fx_tc_if_a_z_if_a_la_z;
95118   fx_function[OP_TC_COND_A_Z_A_Z_LA] = fx_tc_cond_a_z_a_z_la;
95119   fx_function[OP_TC_COND_A_Z_A_LA_Z] = fx_tc_cond_a_z_a_la_z;
95120   fx_function[OP_TC_AND_A_IF_A_Z_LA] = fx_tc_and_a_if_a_z_la;
95121   fx_function[OP_TC_AND_A_IF_A_LA_Z] = fx_tc_and_a_if_a_la_z;
95122   fx_function[OP_TC_IF_A_Z_IF_A_LAA_Z] = fx_tc_if_a_z_if_a_laa_z;
95123   fx_function[OP_TC_IF_A_Z_IF_A_Z_LAA] = fx_tc_if_a_z_if_a_z_laa;
95124   fx_function[OP_TC_COND_A_Z_A_Z_LAA] = fx_tc_cond_a_z_a_z_laa;
95125   fx_function[OP_TC_COND_A_Z_A_LAA_Z] = fx_tc_cond_a_z_a_laa_z;
95126   fx_function[OP_TC_IF_A_Z_IF_A_L3A_L3A] = fx_tc_if_a_z_if_a_l3a_l3a;
95127   fx_function[OP_TC_CASE_LA] = fx_tc_case_la;
95128   fx_function[OP_TC_OR_A_AND_A_A_L3A] = fx_tc_or_a_and_a_a_l3a;
95129   fx_function[OP_TC_LET_IF_A_Z_LA] = fx_tc_let_if_a_z_la;
95130   fx_function[OP_TC_LET_IF_A_Z_LAA] = fx_tc_let_if_a_z_laa;
95131   fx_function[OP_TC_LET_WHEN_LAA] = fx_tc_let_when_laa;
95132   fx_function[OP_TC_LET_UNLESS_LAA] = fx_tc_let_unless_laa;
95133   fx_function[OP_TC_LET_COND] = fx_tc_let_cond;
95134   fx_function[OP_TC_COND_A_Z_A_LAA_LAA] = fx_tc_cond_a_z_a_laa_laa;
95135 
95136   fx_function[OP_RECUR_IF_A_A_opA_LAq] = fx_recur_if_a_a_opa_laq;
95137   fx_function[OP_RECUR_IF_A_opA_LAq_A] = fx_recur_if_a_opa_laq_a;
95138   fx_function[OP_RECUR_IF_A_A_AND_A_LAA_LAA] = fx_recur_if_a_a_and_a_laa_laa;
95139   fx_function[OP_RECUR_COND_A_A_A_A_opLA_LAq] = fx_recur_cond_a_a_a_a_opla_laq;
95140   fx_function[OP_RECUR_AND_A_OR_A_LAA_LAA] = fx_recur_and_a_or_a_laa_laa;
95141 }
95142 
95143 static void init_opt_functions(s7_scheme *sc)
95144 {
95145 #if (!WITH_PURE_S7)
95146   s7_set_b_7pp_function(sc, global_value(sc->char_ci_lt_symbol), char_ci_lt_b_7pp);
95147   s7_set_b_7pp_function(sc, global_value(sc->char_ci_leq_symbol), char_ci_leq_b_7pp);
95148   s7_set_b_7pp_function(sc, global_value(sc->char_ci_gt_symbol), char_ci_gt_b_7pp);
95149   s7_set_b_7pp_function(sc, global_value(sc->char_ci_geq_symbol), char_ci_geq_b_7pp);
95150   s7_set_b_7pp_function(sc, global_value(sc->char_ci_eq_symbol), char_ci_eq_b_7pp);
95151   s7_set_b_7pp_function(sc, global_value(sc->string_ci_lt_symbol), string_ci_lt_b_7pp);
95152   s7_set_b_7pp_function(sc, global_value(sc->string_ci_leq_symbol), string_ci_leq_b_7pp);
95153   s7_set_b_7pp_function(sc, global_value(sc->string_ci_gt_symbol), string_ci_gt_b_7pp);
95154   s7_set_b_7pp_function(sc, global_value(sc->string_ci_geq_symbol), string_ci_geq_b_7pp);
95155   s7_set_b_7pp_function(sc, global_value(sc->string_ci_eq_symbol), string_ci_eq_b_7pp);
95156 
95157   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_ci_lt_symbol), char_ci_lt_b_unchecked);
95158   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_ci_leq_symbol), char_ci_leq_b_unchecked);
95159   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_ci_gt_symbol), char_ci_gt_b_unchecked);
95160   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_ci_geq_symbol), char_ci_geq_b_unchecked);
95161   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_ci_eq_symbol), char_ci_eq_b_unchecked);
95162   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_ci_lt_symbol), string_ci_lt_b_unchecked);
95163   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_ci_leq_symbol), string_ci_leq_b_unchecked);
95164   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_ci_gt_symbol), string_ci_gt_b_unchecked);
95165   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_ci_geq_symbol), string_ci_geq_b_unchecked);
95166   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_ci_eq_symbol), string_ci_eq_b_unchecked);
95167 
95168   s7_set_p_pp_function(sc, global_value(sc->vector_append_symbol), vector_append_p_pp);
95169   s7_set_p_ppp_function(sc, global_value(sc->vector_append_symbol), vector_append_p_ppp);
95170   s7_set_i_i_function(sc, global_value(sc->integer_length_symbol), integer_length_i_i);
95171   s7_set_i_7p_function(sc, global_value(sc->string_length_symbol), string_length_i_7p);
95172   s7_set_i_7p_function(sc, global_value(sc->vector_length_symbol), vector_length_i_7p);
95173   s7_set_p_p_function(sc, global_value(sc->vector_to_list_symbol), vector_to_list_p_p);
95174   s7_set_p_p_function(sc, global_value(sc->vector_length_symbol), vector_length_p_p);
95175   s7_set_b_7p_function(sc, global_value(sc->is_exact_symbol), is_exact_b_7p);
95176   s7_set_b_7p_function(sc, global_value(sc->is_inexact_symbol), is_inexact_b_7p);
95177 #endif
95178 
95179   s7_set_p_pp_function(sc, global_value(sc->float_vector_ref_symbol), float_vector_ref_p_pp);
95180   s7_set_d_7pi_function(sc, global_value(sc->float_vector_ref_symbol), float_vector_ref_d_7pi);
95181   s7_set_d_7pii_function(sc, global_value(sc->float_vector_ref_symbol), float_vector_ref_d_7pii);
95182   s7_set_d_7pid_function(sc, global_value(sc->float_vector_set_symbol), float_vector_set_d_7pid);
95183   s7_set_d_7piid_function(sc, global_value(sc->float_vector_set_symbol), float_vector_set_d_7piid);
95184 
95185   s7_set_p_pp_function(sc, global_value(sc->int_vector_ref_symbol), int_vector_ref_p_pp);
95186   s7_set_i_7pi_function(sc, global_value(sc->int_vector_ref_symbol), int_vector_ref_i_7pi);
95187   s7_set_i_7pii_function(sc, global_value(sc->int_vector_ref_symbol), int_vector_ref_i_7pii);
95188   s7_set_i_7piii_function(sc, global_value(sc->int_vector_ref_symbol), int_vector_ref_i_7piii);
95189   s7_set_i_7pii_function(sc, global_value(sc->int_vector_set_symbol), int_vector_set_i_7pii);
95190   s7_set_i_7piii_function(sc, global_value(sc->int_vector_set_symbol), int_vector_set_i_7piii);
95191 
95192   s7_set_i_7pi_function(sc, global_value(sc->byte_vector_ref_symbol), byte_vector_ref_i_7pi);
95193   s7_set_i_7pii_function(sc, global_value(sc->byte_vector_ref_symbol), byte_vector_ref_i_7pii);
95194   s7_set_i_7pii_function(sc, global_value(sc->byte_vector_set_symbol), byte_vector_set_i_7pii);
95195   s7_set_i_7piii_function(sc, global_value(sc->byte_vector_set_symbol), byte_vector_set_i_7piii);
95196 
95197   s7_set_p_pp_function(sc, global_value(sc->vector_ref_symbol), vector_ref_p_pp);
95198   s7_set_p_pi_function(sc, global_value(sc->vector_ref_symbol), vector_ref_p_pi);
95199   s7_set_p_pii_function(sc, global_value(sc->vector_ref_symbol), vector_ref_p_pii);
95200   s7_set_p_pip_function(sc, global_value(sc->vector_set_symbol), vector_set_p_pip);
95201   s7_set_p_piip_function(sc, global_value(sc->vector_set_symbol), vector_set_p_piip);
95202   s7_set_p_pi_unchecked_function(sc, global_value(sc->vector_ref_symbol), vector_ref_p_pi_unchecked);
95203   s7_set_p_pip_unchecked_function(sc, global_value(sc->vector_set_symbol), vector_set_p_pip_unchecked);
95204   s7_set_p_ppp_function(sc, global_value(sc->vector_set_symbol), vector_set_p_ppp);
95205   s7_set_p_ppp_function(sc, global_value(sc->int_vector_set_symbol), int_vector_set_p_ppp);
95206 
95207   s7_set_p_pi_function(sc, global_value(sc->list_ref_symbol), list_ref_p_pi);
95208   s7_set_p_pip_function(sc, global_value(sc->list_set_symbol), list_set_p_pip);
95209   s7_set_p_pi_unchecked_function(sc, global_value(sc->list_ref_symbol), list_ref_p_pi_unchecked);
95210   s7_set_p_pip_unchecked_function(sc, global_value(sc->list_set_symbol), list_set_p_pip_unchecked);
95211   s7_set_p_p_function(sc, global_value(sc->cyclic_sequences_symbol), cyclic_sequences_p_p);
95212 
95213   s7_set_p_pp_function(sc, global_value(sc->let_ref_symbol), s7_let_ref);
95214   s7_set_p_ppp_function(sc, global_value(sc->let_set_symbol), s7_let_set);
95215 
95216   s7_set_p_pi_function(sc, global_value(sc->string_ref_symbol), string_ref_p_pi);
95217   s7_set_p_pp_function(sc, global_value(sc->string_ref_symbol), string_ref_p_pp);
95218   s7_set_p_pip_function(sc, global_value(sc->string_set_symbol), string_set_p_pip);
95219   s7_set_p_pi_unchecked_function(sc, global_value(sc->string_ref_symbol), string_ref_p_pi_unchecked);
95220   s7_set_p_pip_unchecked_function(sc, global_value(sc->string_set_symbol), string_set_p_pip_unchecked);
95221 
95222   s7_set_p_pp_function(sc, global_value(sc->hash_table_ref_symbol), hash_table_ref_p_pp);
95223   s7_set_p_ppp_function(sc, global_value(sc->hash_table_set_symbol), hash_table_set_p_ppp);
95224 
95225   s7_set_p_ii_function(sc, global_value(sc->complex_symbol), complex_p_ii);
95226   s7_set_p_dd_function(sc, global_value(sc->complex_symbol), complex_p_dd);
95227 
95228   s7_set_p_i_function(sc, global_value(sc->number_to_string_symbol), number_to_string_p_i);
95229   s7_set_p_p_function(sc, global_value(sc->number_to_string_symbol), number_to_string_p_p);
95230   s7_set_p_pp_function(sc, global_value(sc->number_to_string_symbol), number_to_string_p_pp);
95231   s7_set_p_p_function(sc, global_value(sc->string_to_number_symbol), string_to_number_p_p);
95232   s7_set_p_pp_function(sc, global_value(sc->string_to_number_symbol), string_to_number_p_pp);
95233 
95234   s7_set_p_p_function(sc, global_value(sc->car_symbol), car_p_p);
95235   s7_set_p_pp_function(sc, global_value(sc->set_car_symbol), set_car_p_pp);
95236   s7_set_p_p_function(sc, global_value(sc->cdr_symbol), cdr_p_p);
95237   s7_set_p_pp_function(sc, global_value(sc->set_cdr_symbol), set_cdr_p_pp);
95238   s7_set_p_p_function(sc, global_value(sc->caar_symbol), caar_p_p);
95239   s7_set_p_p_function(sc, global_value(sc->cadr_symbol), cadr_p_p);
95240   s7_set_p_p_function(sc, global_value(sc->cdar_symbol), cdar_p_p);
95241   s7_set_p_p_function(sc, global_value(sc->cddr_symbol), cddr_p_p);
95242   s7_set_p_p_function(sc, global_value(sc->caddr_symbol), caddr_p_p);
95243   s7_set_p_p_function(sc, global_value(sc->caddar_symbol), caddar_p_p);
95244   s7_set_p_p_function(sc, global_value(sc->caadr_symbol), caadr_p_p);
95245   s7_set_p_p_function(sc, global_value(sc->caaddr_symbol), caaddr_p_p);
95246   s7_set_p_p_function(sc, global_value(sc->cadddr_symbol), cadddr_p_p);
95247   s7_set_p_p_function(sc, global_value(sc->cadar_symbol), cadar_p_p);
95248   s7_set_p_p_function(sc, global_value(sc->cadadr_symbol), cadadr_p_p);
95249   s7_set_p_p_function(sc, global_value(sc->cdadr_symbol), cdadr_p_p);
95250 
95251   s7_set_p_p_function(sc, global_value(sc->string_symbol), string_p_p);
95252   s7_set_p_p_function(sc, global_value(sc->string_to_symbol_symbol), string_to_symbol_p_p);
95253   s7_set_p_p_function(sc, global_value(sc->symbol_to_string_symbol), symbol_to_string_p_p);
95254   s7_set_p_p_function(sc, global_value(sc->symbol_symbol), string_to_symbol_p_p);
95255   s7_set_p_pp_function(sc, global_value(sc->symbol_symbol), symbol_p_pp);
95256   s7_set_p_function(sc, global_value(sc->newline_symbol), newline_p);
95257   s7_set_p_p_function(sc, global_value(sc->newline_symbol), newline_p_p);
95258   s7_set_p_p_function(sc, global_value(sc->display_symbol), display_p_p);
95259   s7_set_p_pp_function(sc, global_value(sc->display_symbol), display_p_pp);
95260   s7_set_p_p_function(sc, global_value(sc->write_symbol), write_p_p);
95261   s7_set_p_pp_function(sc, global_value(sc->write_symbol), write_p_pp);
95262   s7_set_p_p_function(sc, global_value(sc->write_char_symbol), write_char_p_p);
95263   s7_set_p_pp_function(sc, global_value(sc->write_char_symbol), write_char_p_pp);
95264   s7_set_p_pp_function(sc, global_value(sc->write_string_symbol), write_string_p_pp);
95265   s7_set_p_pp_function(sc, global_value(sc->read_line_symbol), read_line_p_pp);
95266   s7_set_p_p_function(sc, global_value(sc->read_line_symbol), read_line_p_p);
95267   s7_set_p_pp_function(sc, global_value(sc->inlet_symbol), inlet_p_pp);
95268   s7_set_i_7p_function(sc, global_value(sc->port_line_number_symbol), s7_port_line_number);
95269   s7_set_p_pp_function(sc, global_value(sc->cons_symbol), cons_p_pp);
95270   s7_set_p_function(sc, global_value(sc->open_output_string_symbol), open_output_string_p);
95271   s7_set_p_ppi_function(sc, global_value(sc->char_position_symbol), char_position_p_ppi);
95272   s7_set_p_pp_function(sc, global_value(sc->append_symbol), s7_append);
95273   s7_set_p_pp_function(sc, global_value(sc->string_append_symbol), string_append_p_pp);
95274   s7_set_p_ppp_function(sc, global_value(sc->append_symbol), append_p_ppp);
95275   s7_set_p_function(sc, global_value(sc->values_symbol), values_p);
95276   s7_set_p_p_function(sc, global_value(sc->values_symbol), values_p_p);
95277   s7_set_p_pp_function(sc, global_value(sc->member_symbol), member_p_pp);
95278   s7_set_p_pp_function(sc, global_value(sc->assoc_symbol), assoc_p_pp);
95279 
95280   s7_set_i_i_function(sc, global_value(sc->abs_symbol), abs_i_i);
95281   s7_set_d_d_function(sc, global_value(sc->abs_symbol), abs_d_d);
95282   s7_set_p_p_function(sc, global_value(sc->abs_symbol), abs_p_p);
95283   s7_set_p_p_function(sc, global_value(sc->magnitude_symbol), magnitude_p_p);
95284 
95285   s7_set_p_d_function(sc, global_value(sc->sin_symbol), sin_p_d);
95286   s7_set_p_p_function(sc, global_value(sc->sin_symbol), sin_p_p);
95287   s7_set_p_d_function(sc, global_value(sc->cos_symbol), cos_p_d);
95288   s7_set_p_p_function(sc, global_value(sc->cos_symbol), cos_p_p);
95289   s7_set_p_p_function(sc, global_value(sc->tan_symbol), tan_p_p);
95290   s7_set_p_p_function(sc, global_value(sc->asin_symbol), asin_p_p);
95291 
95292   s7_set_p_d_function(sc, global_value(sc->rationalize_symbol), rationalize_p_d);
95293   s7_set_p_i_function(sc, global_value(sc->rationalize_symbol), rationalize_p_i);
95294   s7_set_i_i_function(sc, global_value(sc->rationalize_symbol), rationalize_i_i);
95295   s7_set_p_p_function(sc, global_value(sc->truncate_symbol), truncate_p_p);
95296   s7_set_p_pp_function(sc, global_value(sc->max_symbol), max_p_pp);
95297   s7_set_p_pp_function(sc, global_value(sc->min_symbol), min_p_pp);
95298   s7_set_p_p_function(sc, global_value(sc->sqrt_symbol), sqrt_p_p);
95299 
95300   s7_set_d_7dd_function(sc, global_value(sc->remainder_symbol), remainder_d_7dd);
95301   s7_set_i_7ii_function(sc, global_value(sc->remainder_symbol), remainder_i_7ii);
95302   s7_set_i_7ii_function(sc, global_value(sc->quotient_symbol), quotient_i_7ii);
95303   s7_set_d_7dd_function(sc, global_value(sc->modulo_symbol), modulo_d_7dd);
95304   s7_set_i_ii_function(sc, global_value(sc->modulo_symbol), modulo_i_ii);
95305   s7_set_p_dd_function(sc, global_value(sc->multiply_symbol), mul_p_dd);
95306   s7_set_p_dd_function(sc, global_value(sc->add_symbol), add_p_dd);
95307   s7_set_p_dd_function(sc, global_value(sc->subtract_symbol), subtract_p_dd);
95308   s7_set_p_ii_function(sc, global_value(sc->subtract_symbol), subtract_p_ii);
95309 
95310   s7_set_p_pp_function(sc, global_value(sc->modulo_symbol), modulo_p_pp);
95311   s7_set_p_pp_function(sc, global_value(sc->remainder_symbol), remainder_p_pp);
95312   s7_set_p_pp_function(sc, global_value(sc->quotient_symbol), quotient_p_pp);
95313   s7_set_p_pp_function(sc, global_value(sc->subtract_symbol), subtract_p_pp);
95314   s7_set_p_pp_function(sc, global_value(sc->add_symbol), add_p_pp);
95315   s7_set_p_ppp_function(sc, global_value(sc->add_symbol), add_p_ppp);
95316   s7_set_p_pp_function(sc, global_value(sc->multiply_symbol), multiply_p_pp);
95317   s7_set_p_ppp_function(sc, global_value(sc->multiply_symbol), multiply_p_ppp);
95318   s7_set_p_pp_function(sc, global_value(sc->divide_symbol), divide_p_pp);
95319   s7_set_p_p_function(sc, global_value(sc->divide_symbol), invert_p_p);
95320   s7_set_p_p_function(sc, global_value(sc->subtract_symbol), negate_p_p);
95321 
95322   s7_set_p_p_function(sc, global_value(sc->random_symbol), random_p_p);
95323   s7_set_d_7d_function(sc, global_value(sc->random_symbol), random_d_7d);
95324   s7_set_i_7i_function(sc, global_value(sc->random_symbol), random_i_7i);
95325 
95326   s7_set_p_d_function(sc, global_value(sc->float_vector_symbol), float_vector_p_d);
95327   s7_set_p_i_function(sc, global_value(sc->int_vector_symbol), int_vector_p_i);
95328   s7_set_i_i_function(sc, global_value(sc->round_symbol), round_i_i);
95329   s7_set_i_i_function(sc, global_value(sc->floor_symbol), floor_i_i);
95330   s7_set_p_p_function(sc, global_value(sc->floor_symbol), floor_p_p);
95331   s7_set_i_i_function(sc, global_value(sc->ceiling_symbol), ceiling_i_i);
95332   s7_set_i_i_function(sc, global_value(sc->truncate_symbol), truncate_i_i);
95333 
95334   s7_set_d_d_function(sc, global_value(sc->tan_symbol), tan_d_d);
95335   s7_set_d_dd_function(sc, global_value(sc->atan_symbol), atan_d_dd);
95336   s7_set_d_d_function(sc, global_value(sc->tanh_symbol), tanh_d_d);
95337   s7_set_p_p_function(sc, global_value(sc->exp_symbol), exp_p_p);
95338 #if (!WITH_GMP)
95339   s7_set_i_7ii_function(sc, global_value(sc->ash_symbol), ash_i_7ii);
95340   s7_set_d_d_function(sc, global_value(sc->sin_symbol), sin_d_d);
95341   s7_set_d_d_function(sc, global_value(sc->cos_symbol), cos_d_d);
95342   s7_set_d_d_function(sc, global_value(sc->sinh_symbol), sinh_d_d);
95343   s7_set_d_d_function(sc, global_value(sc->cosh_symbol), cosh_d_d);
95344   s7_set_d_d_function(sc, global_value(sc->exp_symbol), exp_d_d);
95345   s7_set_i_7d_function(sc, global_value(sc->round_symbol), round_i_7d);
95346   s7_set_i_7d_function(sc, global_value(sc->floor_symbol), floor_i_7d);
95347   s7_set_i_7d_function(sc, global_value(sc->ceiling_symbol), ceiling_i_7d);
95348   s7_set_i_7p_function(sc, global_value(sc->floor_symbol), floor_i_7p);
95349   s7_set_i_7p_function(sc, global_value(sc->ceiling_symbol), ceiling_i_7p);
95350   s7_set_i_7d_function(sc, global_value(sc->truncate_symbol), truncate_i_7d);
95351 #endif
95352 
95353   s7_set_d_d_function(sc, global_value(sc->add_symbol), add_d_d);
95354   s7_set_d_d_function(sc, global_value(sc->subtract_symbol), subtract_d_d);
95355   s7_set_d_d_function(sc, global_value(sc->multiply_symbol), multiply_d_d);
95356   s7_set_d_7d_function(sc, global_value(sc->divide_symbol), divide_d_7d);
95357   s7_set_d_dd_function(sc, global_value(sc->add_symbol), add_d_dd);
95358   s7_set_d_dd_function(sc, global_value(sc->subtract_symbol), subtract_d_dd);
95359   s7_set_d_dd_function(sc, global_value(sc->multiply_symbol), multiply_d_dd);
95360   s7_set_d_7dd_function(sc, global_value(sc->divide_symbol), divide_d_7dd);
95361   s7_set_d_ddd_function(sc, global_value(sc->add_symbol), add_d_ddd);
95362   s7_set_d_ddd_function(sc, global_value(sc->subtract_symbol), subtract_d_ddd);
95363   s7_set_d_ddd_function(sc, global_value(sc->multiply_symbol), multiply_d_ddd);
95364   s7_set_d_dddd_function(sc, global_value(sc->add_symbol), add_d_dddd);
95365   s7_set_d_dddd_function(sc, global_value(sc->subtract_symbol), subtract_d_dddd);
95366   s7_set_d_dddd_function(sc, global_value(sc->multiply_symbol), multiply_d_dddd);
95367   s7_set_p_i_function(sc, global_value(sc->divide_symbol), divide_p_i);
95368   s7_set_p_ii_function(sc, global_value(sc->divide_symbol), divide_p_ii);
95369   s7_set_d_dd_function(sc, global_value(sc->max_symbol), max_d_dd);
95370   s7_set_d_dd_function(sc, global_value(sc->min_symbol), min_d_dd);
95371   s7_set_d_ddd_function(sc, global_value(sc->max_symbol), max_d_ddd);
95372   s7_set_d_ddd_function(sc, global_value(sc->min_symbol), min_d_ddd);
95373   s7_set_d_dddd_function(sc, global_value(sc->max_symbol), max_d_dddd);
95374   s7_set_d_dddd_function(sc, global_value(sc->min_symbol), min_d_dddd);
95375   s7_set_i_ii_function(sc, global_value(sc->max_symbol), max_i_ii);
95376   s7_set_i_ii_function(sc, global_value(sc->min_symbol), min_i_ii);
95377   s7_set_i_iii_function(sc, global_value(sc->max_symbol), max_i_iii);
95378   s7_set_i_iii_function(sc, global_value(sc->min_symbol), min_i_iii);
95379   s7_set_i_i_function(sc, global_value(sc->subtract_symbol), subtract_i_i);
95380   s7_set_i_ii_function(sc, global_value(sc->add_symbol), add_i_ii);
95381   s7_set_i_iii_function(sc, global_value(sc->add_symbol), add_i_iii);
95382   s7_set_i_ii_function(sc, global_value(sc->subtract_symbol), subtract_i_ii);
95383   s7_set_i_iii_function(sc, global_value(sc->subtract_symbol), subtract_i_iii);
95384   s7_set_i_ii_function(sc, global_value(sc->multiply_symbol), multiply_i_ii);
95385   s7_set_i_iii_function(sc, global_value(sc->multiply_symbol), multiply_i_iii);
95386 
95387   s7_set_i_i_function(sc, global_value(sc->lognot_symbol), lognot_i_i);
95388   s7_set_i_ii_function(sc, global_value(sc->logior_symbol), logior_i_ii);
95389   s7_set_i_ii_function(sc, global_value(sc->logxor_symbol), logxor_i_ii);
95390   s7_set_i_ii_function(sc, global_value(sc->logand_symbol), logand_i_ii);
95391   s7_set_i_iii_function(sc, global_value(sc->logior_symbol), logior_i_iii);
95392   s7_set_i_iii_function(sc, global_value(sc->logxor_symbol), logxor_i_iii);
95393   s7_set_i_iii_function(sc, global_value(sc->logand_symbol), logand_i_iii);
95394   s7_set_b_7ii_function(sc, global_value(sc->logbit_symbol), logbit_b_7ii);
95395   s7_set_b_7pp_function(sc, global_value(sc->logbit_symbol), logbit_b_7pp);
95396 
95397   s7_set_i_7p_function(sc, global_value(sc->numerator_symbol), numerator_i_7p);
95398   s7_set_i_7p_function(sc, global_value(sc->denominator_symbol), denominator_i_7p);
95399   s7_set_i_7p_function(sc, global_value(sc->char_to_integer_symbol), char_to_integer_i_7p);
95400   s7_set_i_7p_function(sc, global_value(sc->hash_table_entries_symbol), hash_table_entries_i_7p);
95401   s7_set_i_7p_function(sc, global_value(sc->tree_leaves_symbol), tree_leaves_i_7p);
95402 
95403   s7_set_b_p_function(sc, global_value(sc->is_boolean_symbol), s7_is_boolean);
95404   s7_set_b_p_function(sc, global_value(sc->is_byte_vector_symbol), s7_is_byte_vector);
95405   s7_set_b_p_function(sc, global_value(sc->is_c_object_symbol), s7_is_c_object);
95406   s7_set_b_p_function(sc, global_value(sc->is_char_symbol), s7_is_character);
95407   s7_set_b_p_function(sc, global_value(sc->is_complex_symbol), s7_is_complex);
95408   s7_set_b_p_function(sc, global_value(sc->is_continuation_symbol), s7_is_continuation);
95409   s7_set_b_p_function(sc, global_value(sc->is_c_pointer_symbol), s7_is_c_pointer);
95410   s7_set_b_p_function(sc, global_value(sc->is_dilambda_symbol), s7_is_dilambda);
95411   s7_set_b_p_function(sc, global_value(sc->is_eof_object_symbol), s7_is_eof_object);
95412   s7_set_b_7p_function(sc, global_value(sc->is_even_symbol), is_even_b_7p);
95413   s7_set_b_7p_function(sc, global_value(sc->is_odd_symbol), is_odd_b_7p);
95414   s7_set_b_p_function(sc, global_value(sc->is_float_symbol), is_float_b);
95415   s7_set_b_p_function(sc, global_value(sc->is_float_vector_symbol), s7_is_float_vector);
95416   s7_set_b_p_function(sc, global_value(sc->is_gensym_symbol), s7_is_gensym);
95417   s7_set_b_p_function(sc, global_value(sc->is_hash_table_symbol), s7_is_hash_table);
95418   s7_set_b_7p_function(sc, global_value(sc->is_infinite_symbol), is_infinite_b_7p);
95419   s7_set_b_7p_function(sc, global_value(sc->is_nan_symbol), is_nan_b_7p);
95420   s7_set_b_p_function(sc, global_value(sc->is_input_port_symbol), is_input_port_b);
95421   s7_set_b_p_function(sc, global_value(sc->is_integer_symbol), s7_is_integer);
95422   s7_set_b_p_function(sc, global_value(sc->is_int_vector_symbol), s7_is_int_vector);
95423   s7_set_b_p_function(sc, global_value(sc->is_keyword_symbol), s7_is_keyword);
95424   s7_set_b_p_function(sc, global_value(sc->is_let_symbol), s7_is_let);
95425   s7_set_b_p_function(sc, global_value(sc->is_list_symbol), is_list_b);
95426   s7_set_b_p_function(sc, global_value(sc->is_macro_symbol), is_macro_b);
95427   s7_set_b_p_function(sc, global_value(sc->is_null_symbol), is_null_b);
95428   s7_set_b_p_function(sc, global_value(sc->is_number_symbol), s7_is_number);
95429   s7_set_b_p_function(sc, global_value(sc->is_output_port_symbol), is_output_port_b);
95430   s7_set_b_p_function(sc, global_value(sc->is_pair_symbol), s7_is_pair);
95431   s7_set_b_7p_function(sc, global_value(sc->is_port_closed_symbol), is_port_closed_b_7p);
95432   s7_set_b_p_function(sc, global_value(sc->is_procedure_symbol), s7_is_procedure);
95433   s7_set_b_7p_function(sc, global_value(sc->is_proper_list_symbol), s7_is_proper_list);
95434   s7_set_b_p_function(sc, global_value(sc->is_random_state_symbol), is_random_state_b);
95435   s7_set_b_p_function(sc, global_value(sc->is_rational_symbol), s7_is_rational);
95436   s7_set_b_p_function(sc, global_value(sc->is_real_symbol), s7_is_real);
95437   s7_set_b_p_function(sc, global_value(sc->is_sequence_symbol), is_sequence_b);
95438   s7_set_b_p_function(sc, global_value(sc->is_string_symbol), s7_is_string);
95439   s7_set_b_p_function(sc, global_value(sc->is_symbol_symbol), s7_is_symbol);
95440   s7_set_b_p_function(sc, global_value(sc->is_syntax_symbol), s7_is_syntax);
95441   s7_set_b_p_function(sc, global_value(sc->is_vector_symbol), s7_is_vector);
95442   s7_set_b_7p_function(sc, global_value(sc->is_iterator_symbol), is_iterator_b_7p);
95443 
95444   s7_set_b_7p_function(sc, global_value(sc->is_char_alphabetic_symbol), is_char_alphabetic_b_7p);
95445   s7_set_b_7p_function(sc, global_value(sc->is_char_lower_case_symbol), is_char_lower_case_b_7p);
95446   s7_set_b_7p_function(sc, global_value(sc->is_char_numeric_symbol), is_char_numeric_b_7p);
95447   s7_set_b_7p_function(sc, global_value(sc->is_char_upper_case_symbol), is_char_upper_case_b_7p);
95448   s7_set_b_7p_function(sc, global_value(sc->is_char_whitespace_symbol), is_char_whitespace_b_7p);
95449 
95450   s7_set_b_p_function(sc, global_value(sc->is_openlet_symbol), s7_is_openlet);
95451   s7_set_b_7p_function(sc, global_value(sc->iterator_is_at_end_symbol), iterator_is_at_end_b_7p);
95452   s7_set_b_7p_function(sc, global_value(sc->is_zero_symbol), is_zero_b_7p);
95453   s7_set_b_7p_function(sc, global_value(sc->is_negative_symbol), is_negative_b_7p);
95454   s7_set_b_7p_function(sc, global_value(sc->is_positive_symbol), is_positive_b_7p);
95455   s7_set_b_7p_function(sc, global_value(sc->not_symbol), not_b_7p);
95456   s7_set_b_7p_function(sc, global_value(sc->is_provided_symbol), is_provided_b_7p);
95457   s7_set_b_7p_function(sc, global_value(sc->is_defined_symbol), is_defined_b_7p);
95458   s7_set_b_7pp_function(sc, global_value(sc->is_defined_symbol), is_defined_b_7pp);
95459   s7_set_b_7pp_function(sc, global_value(sc->tree_memq_symbol), s7_tree_memq);
95460   s7_set_b_7pp_function(sc, global_value(sc->tree_set_memq_symbol), tree_set_memq_b_7pp);
95461   s7_set_p_pp_function(sc, global_value(sc->tree_set_memq_symbol), tree_set_memq_p_pp);
95462   s7_set_b_p_function(sc, global_value(sc->is_immutable_symbol), s7_is_immutable);
95463 
95464   s7_set_p_p_function(sc, global_value(sc->is_pair_symbol), is_pair_p_p);
95465   s7_set_p_p_function(sc, global_value(sc->is_constant_symbol), is_constant_p_p);
95466   s7_set_p_p_function(sc, global_value(sc->type_of_symbol), s7_type_of);
95467   /* s7_set_p_p_function(sc, global_value(sc->openlet_symbol), s7_openlet); -- needs error check */
95468   s7_set_p_i_function(sc, global_value(sc->integer_to_char_symbol), integer_to_char_p_i);
95469   s7_set_p_p_function(sc, global_value(sc->integer_to_char_symbol), integer_to_char_p_p);
95470   s7_set_p_p_function(sc, global_value(sc->iterate_symbol), iterate_p_p);
95471   s7_set_p_p_function(sc, global_value(sc->list_symbol), list_p_p);
95472   s7_set_p_pp_function(sc, global_value(sc->list_symbol), list_p_pp);
95473   s7_set_p_pp_function(sc, global_value(sc->list_tail_symbol), list_tail_p_pp);
95474   s7_set_p_pp_function(sc, global_value(sc->assq_symbol), assq_p_pp);
95475   s7_set_p_pp_function(sc, global_value(sc->assv_symbol), assv_p_pp);
95476   s7_set_p_pp_function(sc, global_value(sc->memq_symbol), memq_p_pp);
95477   s7_set_p_pp_function(sc, global_value(sc->memv_symbol), memv_p_pp);
95478   s7_set_p_p_function(sc, global_value(sc->tree_leaves_symbol), tree_leaves_p_p);
95479   s7_set_p_p_function(sc, global_value(sc->length_symbol), s7_length);
95480   s7_set_p_p_function(sc, global_value(sc->pair_line_number_symbol), pair_line_number_p_p);
95481   s7_set_p_p_function(sc, global_value(sc->port_line_number_symbol), port_line_number_p_p);
95482   s7_set_p_p_function(sc, global_value(sc->port_filename_symbol), port_filename_p_p);
95483   s7_set_p_p_function(sc, global_value(sc->c_pointer_info_symbol), c_pointer_info_p_p);
95484   s7_set_p_p_function(sc, global_value(sc->c_pointer_type_symbol), c_pointer_type_p_p);
95485   s7_set_p_p_function(sc, global_value(sc->c_pointer_weak1_symbol), c_pointer_weak1_p_p);
95486   s7_set_p_p_function(sc, global_value(sc->c_pointer_weak2_symbol), c_pointer_weak2_p_p);
95487   s7_set_p_p_function(sc, global_value(sc->is_char_alphabetic_symbol), is_char_alphabetic_p_p);
95488   s7_set_p_p_function(sc, global_value(sc->is_char_whitespace_symbol), is_char_whitespace_p_p);
95489   s7_set_p_p_function(sc, global_value(sc->char_upcase_symbol), char_upcase_p_p);
95490   s7_set_p_p_function(sc, global_value(sc->read_char_symbol), read_char_p_p);
95491   s7_set_p_i_function(sc, global_value(sc->make_string_symbol), make_string_p_i);
95492   s7_set_p_ii_function(sc, global_value(sc->make_int_vector_symbol), make_int_vector_p_ii);
95493   s7_set_p_ii_function(sc, global_value(sc->make_byte_vector_symbol), make_byte_vector_p_ii);
95494   s7_set_p_pp_function(sc, global_value(sc->vector_symbol), vector_p_pp);
95495 
95496 #if WITH_SYSTEM_EXTRAS
95497   s7_set_b_7p_function(sc, global_value(sc->is_directory_symbol), is_directory_b_7p);
95498   s7_set_b_7p_function(sc, global_value(sc->file_exists_symbol), file_exists_b_7p);
95499 #endif
95500 
95501   s7_set_b_i_function(sc, global_value(sc->is_even_symbol), is_even_i);
95502   s7_set_b_i_function(sc, global_value(sc->is_odd_symbol), is_odd_i);
95503   s7_set_b_i_function(sc, global_value(sc->is_zero_symbol), is_zero_i);
95504   s7_set_b_d_function(sc, global_value(sc->is_zero_symbol), is_zero_d);
95505   s7_set_p_p_function(sc, global_value(sc->is_zero_symbol), is_zero_p_p);
95506   s7_set_p_p_function(sc, global_value(sc->is_positive_symbol), is_positive_p_p);
95507   s7_set_p_p_function(sc, global_value(sc->is_negative_symbol), is_negative_p_p);
95508   s7_set_p_p_function(sc, global_value(sc->real_part_symbol), real_part_p_p);
95509   s7_set_p_p_function(sc, global_value(sc->imag_part_symbol), imag_part_p_p);
95510   s7_set_b_i_function(sc, global_value(sc->is_positive_symbol), is_positive_i);
95511   s7_set_b_d_function(sc, global_value(sc->is_positive_symbol), is_positive_d);
95512   s7_set_b_i_function(sc, global_value(sc->is_negative_symbol), is_negative_i);
95513   s7_set_b_d_function(sc, global_value(sc->is_negative_symbol), is_negative_d);
95514 
95515   s7_set_p_pi_function(sc, global_value(sc->lt_symbol), lt_p_pi);
95516   s7_set_b_pi_function(sc, global_value(sc->lt_symbol), lt_b_pi);
95517   s7_set_p_pi_function(sc, global_value(sc->leq_symbol), leq_p_pi);
95518   s7_set_b_pi_function(sc, global_value(sc->leq_symbol), leq_b_pi);
95519   s7_set_p_pi_function(sc, global_value(sc->gt_symbol), gt_p_pi);
95520   s7_set_p_pi_function(sc, global_value(sc->geq_symbol), geq_p_pi);
95521   s7_set_b_pi_function(sc, global_value(sc->gt_symbol), gt_b_pi);
95522   s7_set_b_pi_function(sc, global_value(sc->geq_symbol), geq_b_pi);
95523   /* no ip pd dp! */
95524   s7_set_b_pi_function(sc, global_value(sc->num_eq_symbol), num_eq_b_pi);
95525   s7_set_p_pi_function(sc, global_value(sc->num_eq_symbol), num_eq_p_pi);
95526   s7_set_p_pi_function(sc, global_value(sc->add_symbol), g_add_xi);
95527   s7_set_p_pi_function(sc, global_value(sc->subtract_symbol), g_sub_xi);
95528   s7_set_p_pi_function(sc, global_value(sc->multiply_symbol), g_mul_xi);
95529 
95530   s7_set_p_ii_function(sc, global_value(sc->num_eq_symbol), num_eq_p_ii);
95531   s7_set_p_dd_function(sc, global_value(sc->num_eq_symbol), num_eq_p_dd);
95532   s7_set_p_pp_function(sc, global_value(sc->num_eq_symbol), num_eq_p_pp);
95533   s7_set_b_7pp_function(sc, global_value(sc->num_eq_symbol), num_eq_b_7pp);
95534   s7_set_b_ii_function(sc, global_value(sc->num_eq_symbol), num_eq_b_ii);
95535   s7_set_b_dd_function(sc, global_value(sc->num_eq_symbol), num_eq_b_dd);
95536 
95537   s7_set_p_ii_function(sc, global_value(sc->lt_symbol), lt_p_ii);
95538   s7_set_p_dd_function(sc, global_value(sc->lt_symbol), lt_p_dd);
95539   s7_set_p_pp_function(sc, global_value(sc->lt_symbol), lt_p_pp);
95540   s7_set_b_7pp_function(sc, global_value(sc->lt_symbol), lt_b_7pp);
95541   s7_set_b_ii_function(sc, global_value(sc->lt_symbol), lt_b_ii);
95542   s7_set_b_dd_function(sc, global_value(sc->lt_symbol), lt_b_dd);
95543 
95544   s7_set_b_ii_function(sc, global_value(sc->leq_symbol), leq_b_ii);
95545   s7_set_p_dd_function(sc, global_value(sc->leq_symbol), leq_p_dd);
95546   s7_set_p_ii_function(sc, global_value(sc->leq_symbol), leq_p_ii);
95547   s7_set_b_dd_function(sc, global_value(sc->leq_symbol), leq_b_dd);
95548   s7_set_p_pp_function(sc, global_value(sc->leq_symbol), leq_p_pp);
95549   s7_set_b_7pp_function(sc, global_value(sc->leq_symbol), leq_b_7pp);
95550 
95551   s7_set_b_ii_function(sc, global_value(sc->gt_symbol), gt_b_ii);
95552   s7_set_b_dd_function(sc, global_value(sc->gt_symbol), gt_b_dd);
95553   s7_set_p_dd_function(sc, global_value(sc->gt_symbol), gt_p_dd);
95554   s7_set_p_ii_function(sc, global_value(sc->gt_symbol), gt_p_ii);
95555   s7_set_p_pp_function(sc, global_value(sc->gt_symbol), gt_p_pp);
95556   s7_set_b_7pp_function(sc, global_value(sc->gt_symbol), gt_b_7pp);
95557 
95558   s7_set_b_ii_function(sc, global_value(sc->geq_symbol), geq_b_ii);
95559   s7_set_b_dd_function(sc, global_value(sc->geq_symbol), geq_b_dd);
95560   s7_set_p_ii_function(sc, global_value(sc->geq_symbol), geq_p_ii);
95561   s7_set_p_dd_function(sc, global_value(sc->geq_symbol), geq_p_dd);
95562   s7_set_p_pp_function(sc, global_value(sc->geq_symbol), geq_p_pp);
95563   s7_set_b_7pp_function(sc, global_value(sc->geq_symbol), geq_b_7pp);
95564 
95565   s7_set_b_pp_function(sc, global_value(sc->is_eq_symbol), s7_is_eq);
95566   s7_set_p_pp_function(sc, global_value(sc->is_eq_symbol), is_eq_p_pp);
95567   s7_set_b_7pp_function(sc, global_value(sc->is_eqv_symbol), s7_is_eqv);
95568   s7_set_p_pp_function(sc, global_value(sc->is_eqv_symbol), is_eqv_p_pp);
95569   s7_set_b_7pp_function(sc, global_value(sc->is_equal_symbol), s7_is_equal);
95570   s7_set_b_7pp_function(sc, global_value(sc->is_equivalent_symbol), s7_is_equivalent);
95571   s7_set_p_pp_function(sc, global_value(sc->is_equal_symbol), is_equal_p_pp);
95572   s7_set_p_pp_function(sc, global_value(sc->is_equivalent_symbol), is_equivalent_p_pp);
95573   s7_set_p_pp_function(sc, global_value(sc->char_eq_symbol), char_eq_p_pp);
95574 
95575   s7_set_b_7pp_function(sc, global_value(sc->char_lt_symbol), char_lt_b_7pp);
95576   s7_set_b_7pp_function(sc, global_value(sc->char_leq_symbol), char_leq_b_7pp);
95577   s7_set_b_7pp_function(sc, global_value(sc->char_gt_symbol), char_gt_b_7pp);
95578   s7_set_b_7pp_function(sc, global_value(sc->char_geq_symbol), char_geq_b_7pp);
95579   s7_set_b_7pp_function(sc, global_value(sc->char_eq_symbol), char_eq_b_7pp);
95580   s7_set_b_7pp_function(sc, global_value(sc->string_lt_symbol), string_lt_b_7pp);
95581   s7_set_b_7pp_function(sc, global_value(sc->string_leq_symbol), string_leq_b_7pp);
95582   s7_set_b_7pp_function(sc, global_value(sc->string_gt_symbol), string_gt_b_7pp);
95583   s7_set_b_7pp_function(sc, global_value(sc->string_geq_symbol), string_geq_b_7pp);
95584   s7_set_b_7pp_function(sc, global_value(sc->string_eq_symbol), string_eq_b_7pp);
95585 
95586   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_lt_symbol), char_lt_b_unchecked);
95587   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_leq_symbol), char_leq_b_unchecked);
95588   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_gt_symbol), char_gt_b_unchecked);
95589   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_geq_symbol), char_geq_b_unchecked);
95590   s7_set_b_pp_unchecked_function(sc, global_value(sc->char_eq_symbol), char_eq_b_unchecked);
95591   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_lt_symbol), string_lt_b_unchecked);
95592   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_leq_symbol), string_leq_b_unchecked);
95593   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_gt_symbol), string_gt_b_unchecked);
95594   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_geq_symbol), string_geq_b_unchecked);
95595   s7_set_b_pp_unchecked_function(sc, global_value(sc->string_eq_symbol), string_eq_b_unchecked);
95596 
95597   s7_set_b_7pp_function(sc, global_value(sc->is_aritable_symbol), is_aritable_b_7pp);
95598 }
95599 
95600 static void init_features(s7_scheme *sc)
95601 {
95602   s7_provide(sc, "s7");
95603   s7_provide(sc, "s7-" S7_VERSION);
95604   s7_provide(sc, "ratio");
95605 
95606 #if WITH_PURE_S7
95607   s7_provide(sc, "pure-s7");
95608 #endif
95609 #if WITH_EXTRA_EXPONENT_MARKERS
95610   s7_provide(sc, "dfls-exponents");
95611 #endif
95612 #if HAVE_OVERFLOW_CHECKS
95613   s7_provide(sc, "overflow-checks");
95614 #endif
95615 #if WITH_SYSTEM_EXTRAS
95616   s7_provide(sc, "system-extras");
95617 #endif
95618 #if WITH_IMMUTABLE_UNQUOTE
95619   s7_provide(sc, "immutable-unquote");
95620 #endif
95621 #if S7_DEBUGGING
95622   s7_provide(sc, "debugging");
95623 #endif
95624 #if HAVE_COMPLEX_NUMBERS
95625   s7_provide(sc, "complex-numbers");
95626 #endif
95627 #if WITH_HISTORY
95628   s7_provide(sc, "history");
95629 #endif
95630 #if WITH_C_LOADER
95631   s7_provide(sc, "dlopen");
95632 #endif
95633 #if (!DISABLE_AUTOLOAD)
95634   s7_provide(sc, "autoload");
95635 #endif
95636 #if S7_ALIGNED
95637   s7_provide(sc, "aligned");
95638 #endif
95639 
95640 #ifdef __APPLE__
95641   s7_provide(sc, "osx");
95642 #endif
95643 #ifdef __linux__
95644   s7_provide(sc, "linux");
95645 #endif
95646 #ifdef __OpenBSD__
95647   s7_provide(sc, "openbsd");
95648 #endif
95649 #ifdef __NetBSD__
95650   s7_provide(sc, "netbsd");
95651 #endif
95652 #ifdef __FreeBSD__
95653   s7_provide(sc, "freebsd");
95654 #endif
95655 #if MS_WINDOWS
95656   s7_provide(sc, "windows");
95657 #endif
95658 #ifdef __bfin__
95659   s7_provide(sc, "blackfin");
95660 #endif
95661 #ifdef __ANDROID__
95662   s7_provide(sc, "android");
95663 #endif
95664 #ifdef __CYGWIN__
95665   s7_provide(sc, "cygwin");
95666 #endif
95667 #ifdef __hpux
95668   s7_provide(sc, "hpux");
95669 #endif
95670 #if defined(__sun) && defined(__SVR4)
95671   s7_provide(sc, "solaris");
95672 #endif
95673 #ifdef __MINGW32__
95674   s7_provide(sc, "mingw");
95675 #endif
95676 #if POINTER_32
95677   s7_provide(sc, "32-bit");
95678 #endif
95679 #ifdef __SUNPRO_C
95680   s7_provide(sc, "sunpro_c");
95681 #endif
95682 #if (defined(__clang__))
95683   s7_provide(sc, "clang");
95684 #endif
95685 #if (defined(__GNUC__))
95686   s7_provide(sc, "gcc");
95687 #endif
95688 #ifdef __EMSCRIPTEN__
95689   s7_provide(sc, "emscripten");
95690 #endif
95691 }
95692 
95693 static s7_pointer make_real_wrapper(s7_scheme *sc)
95694 {
95695   s7_pointer p;
95696   p = (s7_pointer)calloc(1, sizeof(s7_cell));
95697   add_saved_pointer(sc, p);
95698   full_type(p) = T_REAL | T_UNHEAP | T_MUTABLE | T_IMMUTABLE;
95699   return(p);
95700 }
95701 
95702 static s7_pointer make_integer_wrapper(s7_scheme *sc)
95703 {
95704   s7_pointer p;
95705   p = (s7_pointer)calloc(1, sizeof(s7_cell));
95706   add_saved_pointer(sc, p);
95707   full_type(p) = T_INTEGER | T_UNHEAP | T_MUTABLE | T_IMMUTABLE; /* mutable to turn off set_has_number_name */
95708   return(p);
95709 }
95710 
95711 static void init_wrappers(s7_scheme *sc)
95712 {
95713   int32_t i;
95714   sc->integer_wrapper1 = make_integer_wrapper(sc);
95715   sc->integer_wrapper2 = make_integer_wrapper(sc);
95716   sc->integer_wrapper3 = make_integer_wrapper(sc);
95717   sc->real_wrapper1 = make_real_wrapper(sc);
95718   sc->real_wrapper2 = make_real_wrapper(sc);
95719   sc->real_wrapper3 = make_real_wrapper(sc);
95720   sc->real_wrapper4 = make_real_wrapper(sc);
95721 
95722   sc->string_wrappers = (s7_pointer *)malloc(NUM_STRING_WRAPPERS * sizeof(s7_pointer));
95723   add_saved_pointer(sc, sc->string_wrappers);
95724   sc->string_wrapper_pos = 0;
95725   for (i = 0; i < NUM_STRING_WRAPPERS; i++)
95726     {
95727       s7_pointer p;
95728       p = (s7_pointer)calloc(1, sizeof(s7_cell));
95729       add_saved_pointer(sc, p);
95730       sc->string_wrappers[i] = p;
95731       full_type(p) = T_STRING | T_IMMUTABLE | T_SAFE_PROCEDURE | T_UNHEAP;
95732       string_block(p) = NULL;
95733       string_value(p) = NULL;
95734       string_length(p) = 0;
95735       string_hash(p) = 0;
95736     }
95737 }
95738 
95739 static s7_pointer syntax(s7_scheme *sc, const char *name, opcode_t op, s7_pointer min_args, s7_pointer max_args, const char *doc)
95740 {
95741   s7_pointer x, syn;
95742   uint64_t hash;
95743   uint32_t loc;
95744 
95745   hash = raw_string_hash((const uint8_t *)name, safe_strlen(name));
95746   loc = hash % SYMBOL_TABLE_SIZE;
95747   x = new_symbol(sc, name, safe_strlen(name), hash, loc);
95748 
95749   syn = alloc_pointer(sc);
95750   set_full_type(syn, T_SYNTAX | T_SYNTACTIC | T_DONT_EVAL_ARGS | T_GLOBAL | T_UNHEAP);
95751   syntax_opcode(syn) = op;
95752   syntax_set_symbol(syn, x);
95753   syntax_min_args(syn) = integer(min_args);
95754   syntax_max_args(syn) = ((max_args == max_arity) ? -1 : integer(max_args));
95755   syntax_documentation(syn) = doc;
95756 
95757   set_global_slot(x, make_permanent_slot(sc, x, syn));
95758   set_initial_slot(x, make_permanent_slot(sc, x, syn));
95759   /* set_local_slot(x, global_slot(x)); */
95760   set_type_bit(x, T_SYMBOL | T_SYNTACTIC | T_GLOBAL | T_UNHEAP);
95761   symbol_set_local_slot_unchecked(x, 0LL, sc->nil);
95762   symbol_clear_ctr(x);
95763   return(x);
95764 }
95765 
95766 static s7_pointer definer_syntax(s7_scheme *sc, const char *name, opcode_t op, s7_pointer min_args, s7_pointer max_args, const char *doc)
95767 {
95768   s7_pointer x;
95769   x = syntax(sc, name, op, min_args, max_args, doc);
95770   set_syntax_is_definer(x);
95771   return(x);
95772 }
95773 
95774 static s7_pointer binder_syntax(s7_scheme *sc, const char *name, opcode_t op, s7_pointer min_args, s7_pointer max_args, const char *doc)
95775 {
95776   s7_pointer x;
95777   x = syntax(sc, name, op, min_args, max_args, doc);
95778   set_syntax_is_binder(x);
95779   return(x);
95780 }
95781 
95782 static s7_pointer copy_args_syntax(s7_scheme *sc, const char *name, opcode_t op, s7_pointer min_args, s7_pointer max_args, const char *doc)
95783 {
95784   s7_pointer x, p;
95785   x = syntax(sc, name, op, min_args, max_args, doc);
95786   p = global_value(x);
95787   full_type(p) |= T_COPY_ARGS;
95788   return(x);
95789 }
95790 
95791 static s7_pointer make_unique(s7_scheme *sc, const char* name, uint64_t typ)
95792 {
95793   s7_pointer p;
95794   p = alloc_pointer(sc);
95795   set_full_type(p, typ | T_IMMUTABLE | T_UNHEAP);
95796   set_optimize_op(p, OP_CON);
95797   if (typ == T_UNDEFINED) /* sc->undefined here to avoid the undefined_constant_warning */
95798     {
95799       undefined_set_name_length(p, safe_strlen(name));
95800       undefined_name(p) = copy_string_with_length(name, undefined_name_length(p));
95801     }
95802   else
95803     {
95804       unique_name_length(p) = safe_strlen(name);
95805       unique_name(p) = copy_string_with_length(name, unique_name_length(p));
95806       add_saved_pointer(sc, (void *)unique_name(p));
95807     }
95808   return(p);
95809 }
95810 
95811 static void init_setters(s7_scheme *sc)
95812 {
95813   sc->vector_set_function = global_value(sc->vector_set_symbol);
95814   set_is_setter(sc->vector_set_symbol);
95815   /* not float-vector-set! here */
95816 
95817   sc->list_set_function = global_value(sc->list_set_symbol);
95818   set_is_setter(sc->list_set_symbol);
95819 
95820   sc->hash_table_set_function = global_value(sc->hash_table_set_symbol);
95821   set_is_setter(sc->hash_table_set_symbol);
95822 
95823   sc->let_set_function = global_value(sc->let_set_symbol);
95824   set_is_setter(sc->let_set_symbol);
95825 
95826   set_is_setter(sc->cons_symbol); /* (this blocks an over-eager do loop optimization -- see do-test-15 in s7test) */
95827 
95828   sc->string_set_function = global_value(sc->string_set_symbol);
95829   set_is_setter(sc->string_set_symbol);
95830 
95831   set_is_setter(sc->byte_vector_set_symbol);
95832   set_is_setter(sc->set_car_symbol);
95833   set_is_setter(sc->set_cdr_symbol);
95834 
95835   set_is_safe_setter(sc->byte_vector_set_symbol);
95836   set_is_safe_setter(sc->int_vector_set_symbol);
95837   set_is_safe_setter(sc->float_vector_set_symbol);
95838   set_is_safe_setter(sc->string_set_symbol);
95839 
95840 #if (WITH_PURE_S7)
95841   /* we need to be able at least to set (current-output-port) to #f */
95842   c_function_set_setter(global_value(sc->current_input_port_symbol),
95843 			s7_make_function(sc, "#<set-*stdin*>", g_set_current_input_port, 1, 0, false, "*stdin* setter"));
95844   c_function_set_setter(global_value(sc->current_output_port_symbol),
95845 			s7_make_function(sc, "#<set-*stdout*>", g_set_current_output_port, 1, 0, false, "*stdout* setter"));
95846 #else
95847   set_is_setter(sc->set_current_input_port_symbol);
95848   set_is_setter(sc->set_current_output_port_symbol);
95849   s7_function_set_setter(sc, "current-input-port",  "set-current-input-port");
95850   s7_function_set_setter(sc, "current-output-port", "set-current-output-port");
95851 #endif
95852 
95853   set_is_setter(sc->set_current_error_port_symbol);
95854   s7_function_set_setter(sc, "current-error-port",  "set-current-error-port");
95855   /* despite the similar names, current-error-port is different from the other two, and a setter is needed
95856    *    in scheme because error and warn send output to it by default.  It is not a "dynamic variable".
95857    */
95858 
95859   s7_function_set_setter(sc, "car",              "set-car!");
95860   s7_function_set_setter(sc, "cdr",              "set-cdr!");
95861   s7_function_set_setter(sc, "hash-table-ref",   "hash-table-set!");
95862   s7_function_set_setter(sc, "vector-ref",       "vector-set!");
95863   s7_function_set_setter(sc, "float-vector-ref", "float-vector-set!");
95864   s7_function_set_setter(sc, "int-vector-ref",   "int-vector-set!");
95865   s7_function_set_setter(sc, "byte-vector-ref",  "byte-vector-set!");
95866   s7_function_set_setter(sc, "list-ref",         "list-set!");
95867   s7_function_set_setter(sc, "let-ref",          "let-set!");
95868   s7_function_set_setter(sc, "string-ref",       "string-set!");
95869   c_function_set_setter(global_value(sc->outlet_symbol),
95870 			s7_make_function(sc, "#<set-outlet>", g_set_outlet, 2, 0, false, "outlet setter"));
95871   c_function_set_setter(global_value(sc->port_line_number_symbol),
95872 			s7_make_function(sc, "#<set-port-line-number>", g_set_port_line_number, 1, 1, false, "port line setter"));
95873   c_function_set_setter(global_value(sc->port_position_symbol),
95874 			s7_make_function(sc, "#<set-port-position>", g_set_port_position, 2, 0, false, "port position setter"));
95875 }
95876 
95877 static void init_syntax(s7_scheme *sc)
95878 {
95879   #define H_quote             "(quote obj) returns obj unevaluated.  'obj is an abbreviation for (quote obj)."
95880   #define H_if                "(if expr true-stuff optional-false-stuff) evaluates expr, then if it is true, evaluates true-stuff; otherwise, \
95881                                       if optional-false-stuff exists, it is evaluated."
95882   #define H_when              "(when expr ...) evaluates expr, and if it is true, evaluates each form in its body, returning the value of the last"
95883   #define H_unless            "(unless expr ...) evaluates expr, and if it is false, evaluates each form in its body, returning the value of the last"
95884   #define H_begin             "(begin ...) evaluates each form in its body, returning the value of the last one"
95885   #define H_set               "(set! variable value) sets the value of variable to value."
95886   #define H_let               "(let ((var val)...) ...) binds each variable to its initial value, then evaluates its body,\
95887                                       returning the value of the last form.  The let variables are local to it, and \
95888                                       are not available for use until all have been initialized."
95889   #define H_let_star          "(let* ((var val)...) ...) binds each variable to its initial value, then evaluates its body, \
95890                                       returning the value of the last form.  The let* variables are local to it, and are available immediately."
95891   #define H_letrec            "(letrec ((var (lambda ...)))...) is like let, but var can refer to itself in its value \
95892                                       (i.e. you can define local recursive functions)"
95893   #define H_letrec_star       "(letrec* ((var val))...) is like letrec, but successive bindings are handled as in let*"
95894   #define H_cond              "(cond (expr clause...)...) is like if..then.  Each expr is evaluated in order, and if one is not #f, \
95895                                       the associated clauses are evaluated, whereupon cond returns."
95896   #define H_and               "(and expr expr ...) evaluates each of its arguments in order, quitting (and returning #f) \
95897                                       as soon as one of them returns #f.  If all are non-#f, it returns the last value."
95898   #define H_or                "(or expr expr ...) evaluates each of its arguments in order, quitting as soon as one of them is not #f.  \
95899                                       If all are #f, or returns #f."
95900   #define H_case              "(case val ((key...) clause...)...) looks for val in the various lists of keys, and if a \
95901                                       match is found (via eqv?), the associated clauses are evaluated, and case returns."
95902   #define H_do                "(do (vars...) (loop control and return value) ...) is a do-loop."
95903   #define H_lambda            "(lambda args ...) returns a function."
95904   #define H_lambda_star       "(lambda* args ...) returns a function; the args list can have default values, \
95905                                       the parameters themselves can be accessed via keywords."
95906   #define H_define            "(define var val) assigns val to the variable (symbol) var.  (define (func args) ...) is \
95907                                       shorthand for (define func (lambda args ...))"
95908   #define H_define_star       "(define* (func args) ...) defines a function with optional/keyword arguments."
95909   #define H_define_constant   "(define-constant var val) defines var to be a constant (it can't be set or bound), with the value val."
95910   #define H_define_macro      "(define-macro (mac args) ...) defines mac to be a macro."
95911   #define H_define_macro_star "(define-macro* (mac args) ...) defines mac to be a macro with optional/keyword arguments."
95912   #define H_macro             "(macro args ...) defines an unnamed macro."
95913   #define H_macro_star        "(macro* args ...) defines an unnamed macro with optional/keyword arguments."
95914   #define H_define_expansion  "(define-expansion (mac args) ...) defines mac to be a read-time macro."
95915   #define H_define_expansion_star "(define-expansion* (mac args) ...) defines mac to be a read-time macro*."
95916   #define H_define_bacro      "(define-bacro (mac args) ...) defines mac to be a bacro."
95917   #define H_define_bacro_star "(define-bacro* (mac args) ...) defines mac to be a bacro with optional/keyword arguments."
95918   #define H_bacro             "(bacro args ...) defines an unnamed bacro."
95919   #define H_bacro_star        "(bacro* args ...) defines an unnamed bacro with optional/keyword arguments."
95920   #define H_with_baffle       "(with-baffle ...) evaluates its body in a context that blocks re-entry via call/cc."
95921   #define H_macroexpand       "(macroexpand macro-call) returns the result of the expansion phase of evaluating the macro call."
95922   #define H_with_let          "(with-let let ...) evaluates its body in the environment let."
95923   #define H_let_temporarily   "(let-temporarily ((var value)...) . body) sets each var to its new value, evals body, then returns each var to its original value."
95924 
95925   sc->quote_symbol =             syntax(sc, "quote",                   OP_QUOTE,             int_one,  int_one,    H_quote);
95926   sc->if_symbol =                syntax(sc, "if",                      OP_IF,                int_two,  int_three,  H_if);
95927   sc->when_symbol =              syntax(sc, "when",                    OP_WHEN,              int_two,  max_arity,  H_when);
95928   sc->unless_symbol =            syntax(sc, "unless",                  OP_UNLESS,            int_two,  max_arity,  H_unless);
95929   sc->begin_symbol =             syntax(sc, "begin",                   OP_BEGIN,             int_zero, max_arity,  H_begin);      /* (begin) is () */
95930   sc->set_symbol =               syntax(sc, "set!",                    OP_SET,               int_two,  int_two,    H_set);
95931   sc->cond_symbol =              copy_args_syntax(sc, "cond",          OP_COND,              int_one,  max_arity,  H_cond);
95932   sc->and_symbol =               copy_args_syntax(sc, "and",           OP_AND,               int_zero, max_arity,  H_and);
95933   sc->or_symbol =                copy_args_syntax(sc, "or",            OP_OR,                int_zero, max_arity,  H_or);
95934   sc->case_symbol =              syntax(sc, "case",                    OP_CASE,              int_two,  max_arity,  H_case);
95935   sc->macroexpand_symbol =       syntax(sc, "macroexpand",             OP_MACROEXPAND,       int_one,  int_one,    H_macroexpand);
95936   sc->let_temporarily_symbol =   syntax(sc, "let-temporarily",         OP_LET_TEMPORARILY,   int_two,  max_arity,  H_let_temporarily);
95937   sc->define_symbol =            definer_syntax(sc, "define",          OP_DEFINE,            int_two,  max_arity,  H_define);
95938   sc->define_star_symbol =       definer_syntax(sc, "define*",         OP_DEFINE_STAR,       int_two,  max_arity,  H_define_star);
95939   sc->define_constant_symbol =   definer_syntax(sc, "define-constant", OP_DEFINE_CONSTANT,   int_two,  max_arity,  H_define_constant);
95940   sc->define_macro_symbol =      definer_syntax(sc, "define-macro",    OP_DEFINE_MACRO,      int_two,  max_arity,  H_define_macro);
95941   sc->define_macro_star_symbol = definer_syntax(sc, "define-macro*",   OP_DEFINE_MACRO_STAR, int_two,  max_arity,  H_define_macro_star);
95942   sc->define_expansion_symbol =  definer_syntax(sc, "define-expansion",OP_DEFINE_EXPANSION,  int_two,  max_arity,  H_define_expansion);
95943   sc->define_expansion_star_symbol = definer_syntax(sc, "define-expansion*",OP_DEFINE_EXPANSION_STAR, int_two, max_arity, H_define_expansion_star);
95944   sc->define_bacro_symbol =      definer_syntax(sc, "define-bacro",    OP_DEFINE_BACRO,      int_two,  max_arity,  H_define_bacro);
95945   sc->define_bacro_star_symbol = definer_syntax(sc, "define-bacro*",   OP_DEFINE_BACRO_STAR, int_two,  max_arity,  H_define_bacro_star);
95946   sc->let_symbol =               binder_syntax(sc, "let",              OP_LET,               int_two,  max_arity,  H_let);
95947   sc->let_star_symbol =          binder_syntax(sc, "let*",             OP_LET_STAR,          int_two,  max_arity,  H_let_star);
95948   sc->letrec_symbol =            binder_syntax(sc, "letrec",           OP_LETREC,            int_two,  max_arity,  H_letrec);
95949   sc->letrec_star_symbol =       binder_syntax(sc, "letrec*",          OP_LETREC_STAR,       int_two,  max_arity,  H_letrec_star);
95950   sc->do_symbol =                binder_syntax(sc, "do",               OP_DO,                int_two,  max_arity,  H_do); /* 2 because body can be null */
95951   sc->lambda_symbol =            binder_syntax(sc, "lambda",           OP_LAMBDA,            int_two,  max_arity,  H_lambda);
95952   sc->lambda_star_symbol =       binder_syntax(sc, "lambda*",          OP_LAMBDA_STAR,       int_two,  max_arity,  H_lambda_star);
95953   sc->macro_symbol =             binder_syntax(sc, "macro",            OP_MACRO,             int_two,  max_arity,  H_macro);
95954   sc->macro_star_symbol =        binder_syntax(sc, "macro*",           OP_MACRO_STAR,        int_two,  max_arity,  H_macro_star);
95955   sc->bacro_symbol =             binder_syntax(sc, "bacro",            OP_BACRO,             int_two,  max_arity,  H_bacro);
95956   sc->bacro_star_symbol =        binder_syntax(sc, "bacro*",           OP_BACRO_STAR,        int_two,  max_arity,  H_bacro_star);
95957   sc->with_let_symbol =          binder_syntax(sc, "with-let",         OP_WITH_LET,          int_one,  max_arity,  H_with_let);
95958   sc->with_baffle_symbol =       binder_syntax(sc, "with-baffle",      OP_WITH_BAFFLE,       int_zero, max_arity,  H_with_baffle); /* (with-baffle) is () */
95959   set_local_slot(sc->with_let_symbol, global_slot(sc->with_let_symbol)); /* for set_locals */
95960   set_immutable(sc->with_let_symbol);
95961   sc->setter_symbol = make_symbol(sc, "setter");
95962 
95963 #if WITH_IMMUTABLE_UNQUOTE
95964   /* this code solves the various unquote redefinition troubles
95965    * if "," -> "(unquote...)" in the reader, (let (, (lambda (x) (+ x 1))) ,,,,'1) -> 5
95966    */
95967   sc->unquote_symbol =              make_symbol(sc, ",");
95968   set_immutable(sc->unquote_symbol);
95969 #else
95970   sc->unquote_symbol =              make_symbol(sc, "unquote");
95971 #endif
95972 
95973   sc->feed_to_symbol =              make_symbol(sc, "=>");
95974   sc->body_symbol =                 make_symbol(sc, "body");
95975   sc->read_error_symbol =           make_symbol(sc, "read-error");
95976   sc->string_read_error_symbol =    make_symbol(sc, "string-read-error");
95977   sc->syntax_error_symbol =         make_symbol(sc, "syntax-error");
95978   sc->unbound_variable_symbol =     make_symbol(sc, "unbound-variable");
95979   sc->wrong_type_arg_symbol =       make_symbol(sc, "wrong-type-arg");
95980   sc->wrong_number_of_args_symbol = make_symbol(sc, "wrong-number-of-args");
95981   sc->format_error_symbol =         make_symbol(sc, "format-error");
95982   sc->autoload_error_symbol =       make_symbol(sc, "autoload-error");
95983   sc->out_of_range_symbol =         make_symbol(sc, "out-of-range");
95984   sc->out_of_memory_symbol =        make_symbol(sc, "out-of-memory");
95985   sc->no_catch_symbol =             make_symbol(sc, "no-catch");
95986   sc->io_error_symbol =             make_symbol(sc, "io-error");
95987   sc->missing_method_symbol =       make_symbol(sc, "missing-method");
95988   sc->invalid_escape_function_symbol = make_symbol(sc, "invalid-escape-function");
95989   sc->immutable_error_symbol =      make_symbol(sc, "immutable-error");
95990   sc->division_by_zero_symbol =     make_symbol(sc, "division-by-zero");
95991   sc->bad_result_symbol =           make_symbol(sc, "bad-result");
95992 
95993   sc->baffled_symbol =              make_symbol(sc, "baffled!");
95994   sc->value_symbol =                make_symbol(sc, "value");
95995   sc->type_symbol =                 make_symbol(sc, "type");
95996   sc->position_symbol =             make_symbol(sc, "position");
95997   sc->file_symbol =                 make_symbol(sc, "file");
95998   sc->line_symbol =                 make_symbol(sc, "line");
95999   sc->function_symbol =             make_symbol(sc, "function");
96000   sc->else_symbol =                 make_symbol(sc, "else");
96001   s7_make_slot(sc, sc->nil, sc->else_symbol, sc->else_symbol);
96002   slot_set_value(initial_slot(sc->else_symbol), sc->T);
96003   /* if we set #_else to 'else, it can pick up a local else value: (let ((else #f)) (cond (#_else 2)...)) */
96004   sc->key_allow_other_keys_symbol = s7_make_keyword(sc, "allow-other-keys");
96005   sc->key_rest_symbol =             s7_make_keyword(sc, "rest");
96006   sc->key_if_symbol =               s7_make_keyword(sc, "if");       /* internal optimizer local-let marker */
96007   sc->key_readable_symbol =         s7_make_keyword(sc, "readable");
96008   sc->key_display_symbol =          s7_make_keyword(sc, "display");
96009   sc->key_write_symbol =            s7_make_keyword(sc, "write");
96010 }
96011 
96012 static void init_rootlet(s7_scheme *sc)
96013 {
96014   s7_pointer sym;
96015   init_syntax(sc);
96016 
96017   sc->owlet = init_owlet(sc);
96018 
96019   sc->wrong_type_arg_info = permanent_list(sc, 6);
96020   set_car(sc->wrong_type_arg_info, s7_make_permanent_string(sc, "~A argument ~D, ~S, is ~A but should be ~A"));
96021 
96022   sc->simple_wrong_type_arg_info = permanent_list(sc, 5);
96023   set_car(sc->simple_wrong_type_arg_info, s7_make_permanent_string(sc, "~A argument, ~S, is ~A but should be ~A"));
96024 
96025   sc->out_of_range_info = permanent_list(sc, 5);
96026   set_car(sc->out_of_range_info, s7_make_permanent_string(sc, "~A argument ~D, ~S, is out of range (~A)"));
96027 
96028   sc->simple_out_of_range_info = permanent_list(sc, 4);
96029   set_car(sc->simple_out_of_range_info, s7_make_permanent_string(sc, "~A argument, ~S, is out of range (~A)"));
96030 
96031   sc->gc_off = false;
96032 
96033   #define defun(Scheme_Name, C_Name, Req, Opt, Rst) \
96034     s7_define_typed_function(sc, Scheme_Name, g_ ## C_Name, Req, Opt, Rst, H_ ## C_Name, Q_ ## C_Name)
96035 
96036   #define unsafe_defun(Scheme_Name, C_Name, Req, Opt, Rst) \
96037     s7_define_unsafe_typed_function(sc, Scheme_Name, g_ ## C_Name, Req, Opt, Rst, H_ ## C_Name, Q_ ## C_Name)
96038 
96039   #define semisafe_defun(Scheme_Name, C_Name, Req, Opt, Rst) \
96040     s7_define_semisafe_typed_function(sc, Scheme_Name, g_ ## C_Name, Req, Opt, Rst, H_ ## C_Name, Q_ ## C_Name)
96041 
96042   #define b_defun(Scheme_Name, C_Name, Opt, SymId, Marker, Simple) \
96043     define_bool_function(sc, Scheme_Name, g_ ## C_Name, Opt, H_ ## C_Name, Q_ ## C_Name, SymId, Marker, Simple, b_ ## C_Name ## _setter)
96044 
96045   /* we need the sc->is_* symbols first for the procedure signature lists */
96046   sc->is_boolean_symbol = make_symbol(sc, "boolean?");
96047   sc->pl_bt = s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->T);
96048 
96049   sc->is_symbol_symbol =          b_defun("symbol?",	      is_symbol,	  0, T_SYMBOL,       mark_symbol_vector, true);
96050   sc->is_syntax_symbol =          b_defun("syntax?",	      is_syntax,	  0, T_SYNTAX,       just_mark_vector,   true);
96051   sc->is_gensym_symbol =          b_defun("gensym?",	      is_gensym,	  0, T_FREE,         mark_symbol_vector, true);
96052   sc->is_keyword_symbol =         b_defun("keyword?",	      is_keyword,	  0, T_FREE,         just_mark_vector,   true);
96053   sc->is_let_symbol =             b_defun("let?",	      is_let,		  0, T_LET,          mark_vector_1,      false);
96054   sc->is_openlet_symbol =         b_defun("openlet?",	      is_openlet,	  0, T_FREE,         mark_vector_1,      false);
96055   sc->is_iterator_symbol =        b_defun("iterator?",	      is_iterator,	  0, T_ITERATOR,     mark_vector_1,      false);
96056   sc->is_macro_symbol =           b_defun("macro?",	      is_macro,		  0, T_FREE,         mark_vector_1,      false);
96057   sc->is_c_pointer_symbol =       b_defun("c-pointer?",	      is_c_pointer,	  1, T_C_POINTER,    mark_vector_1,      false);
96058   sc->is_input_port_symbol =      b_defun("input-port?",      is_input_port,	  0, T_INPUT_PORT,   mark_vector_1,      true);
96059   sc->is_output_port_symbol =     b_defun("output-port?",     is_output_port,	  0, T_OUTPUT_PORT,  mark_simple_vector, true);
96060   sc->is_eof_object_symbol =      b_defun("eof-object?",      is_eof_object,	  0, T_EOF,          just_mark_vector,   true);
96061   sc->is_integer_symbol =         b_defun("integer?",	      is_integer,	  0, (WITH_GMP) ? T_FREE : T_INTEGER, mark_simple_vector, true);
96062   sc->is_byte_symbol =            b_defun("byte?",	      is_byte,		  0, T_FREE,         mark_simple_vector, true);
96063   sc->is_number_symbol =          b_defun("number?",	      is_number,	  0, T_FREE,         mark_simple_vector, true);
96064   sc->is_real_symbol =            b_defun("real?",	      is_real,		  0, T_FREE,         mark_simple_vector, true);
96065   sc->is_float_symbol =           b_defun("float?",           is_float,           0, T_FREE,         mark_simple_vector, true);
96066   sc->is_complex_symbol =         b_defun("complex?",	      is_complex,	  0, T_FREE,         mark_simple_vector, true);
96067   sc->is_rational_symbol =        b_defun("rational?",	      is_rational,	  0, T_FREE,         mark_simple_vector, true);
96068   sc->is_random_state_symbol =    b_defun("random-state?",    is_random_state,	  0, T_RANDOM_STATE, mark_simple_vector, true);
96069   sc->is_char_symbol =            b_defun("char?",	      is_char,		  0, T_CHARACTER,    just_mark_vector,   true);
96070   sc->is_string_symbol =          b_defun("string?",	      is_string,	  0, T_STRING,       mark_simple_vector, true);
96071   sc->is_list_symbol =            b_defun("list?",	      is_list,		  0, T_FREE,         mark_vector_1,      false);
96072   sc->is_pair_symbol =            b_defun("pair?",	      is_pair,		  0, T_PAIR,         mark_vector_1,      false);
96073   sc->is_vector_symbol =          b_defun("vector?",	      is_vector,	  0, T_FREE,         mark_vector_1,      false);
96074   sc->is_float_vector_symbol =    b_defun("float-vector?",    is_float_vector,	  0, T_FLOAT_VECTOR, mark_simple_vector, true);
96075   sc->is_int_vector_symbol =      b_defun("int-vector?",      is_int_vector,	  0, T_INT_VECTOR,   mark_simple_vector, true);
96076   sc->is_byte_vector_symbol =     b_defun("byte-vector?",     is_byte_vector,	  0, T_BYTE_VECTOR,  mark_simple_vector, true);
96077   sc->is_hash_table_symbol =      b_defun("hash-table?",      is_hash_table,      0, T_HASH_TABLE,   mark_vector_1,      false);
96078   sc->is_continuation_symbol =    b_defun("continuation?",    is_continuation,	  0, T_CONTINUATION, mark_vector_1,      false);
96079   sc->is_procedure_symbol =       b_defun("procedure?",	      is_procedure,	  0, T_FREE,         mark_vector_1,      false);
96080   sc->is_dilambda_symbol =        b_defun("dilambda?",	      is_dilambda,	  0, T_FREE,         mark_vector_1,      false);
96081   /* set above */                 b_defun("boolean?",	      is_boolean,	  0, T_BOOLEAN,      just_mark_vector,   true);
96082   sc->is_proper_list_symbol =     b_defun("proper-list?",     is_proper_list,     0, T_FREE,         mark_vector_1,      false);
96083   sc->is_sequence_symbol =        b_defun("sequence?",	      is_sequence,	  0, T_FREE,         mark_vector_1,      false);
96084   sc->is_null_symbol =            b_defun("null?",	      is_null,		  0, T_NIL,          just_mark_vector,   true);
96085   sc->is_undefined_symbol =       b_defun("undefined?",       is_undefined,       0, T_UNDEFINED,    just_mark_vector,   true);
96086   sc->is_unspecified_symbol =     b_defun("unspecified?",     is_unspecified,     0, T_UNSPECIFIED,  just_mark_vector,   true);
96087   sc->is_c_object_symbol =        b_defun("c-object?",	      is_c_object,	  0, T_C_OBJECT,     mark_vector_1,      false);
96088   sc->is_subvector_symbol =       b_defun("subvector?",	      is_subvector,	  0, T_FREE,         mark_vector_1,      false);
96089   sc->is_weak_hash_table_symbol = b_defun("weak-hash-table?", is_weak_hash_table, 0, T_FREE,         mark_vector_1,      false);
96090   sc->is_goto_symbol =            b_defun("goto?",	      is_goto,	          0, T_GOTO,         mark_vector_1,      true);
96091 
96092   /* these are for signatures */
96093   sc->not_symbol = defun("not",	not, 1, 0, false);
96094   sc->is_integer_or_real_at_end_symbol = make_symbol(sc, "integer:real?");
96095   sc->is_integer_or_any_at_end_symbol =  make_symbol(sc, "integer:any?");
96096 
96097   sc->pl_p =   s7_make_signature(sc, 2, sc->T, sc->is_pair_symbol);
96098   sc->pl_tl =  s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->not_symbol), sc->T, sc->is_list_symbol); /* memq and memv signature */
96099   sc->pl_bc =  s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_char_symbol);
96100   sc->pl_bn =  s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_number_symbol);
96101   sc->pl_nn =  s7_make_signature(sc, 2, sc->is_number_symbol, sc->is_number_symbol);
96102   sc->pl_sf =  s7_make_signature(sc, 3, sc->T, sc->is_string_symbol, s7_make_signature(sc, 2, sc->is_procedure_symbol, sc->is_macro_symbol));
96103   sc->pcl_bt = s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->T);
96104   sc->pcl_bc = s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_char_symbol);
96105   sc->pcl_bs = s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_string_symbol);
96106   sc->pcl_i =  s7_make_circular_signature(sc, 0, 1, sc->is_integer_symbol);
96107   sc->pcl_r =  s7_make_circular_signature(sc, 0, 1, sc->is_real_symbol);
96108   sc->pcl_f =  s7_make_circular_signature(sc, 0, 1, sc->is_rational_symbol);
96109   sc->pcl_n =  s7_make_circular_signature(sc, 0, 1, sc->is_number_symbol);
96110   sc->pcl_s =  s7_make_circular_signature(sc, 0, 1, sc->is_string_symbol);
96111   sc->pcl_v =  s7_make_circular_signature(sc, 0, 1, sc->is_vector_symbol);
96112   sc->pcl_c =  s7_make_circular_signature(sc, 0, 1, sc->is_char_symbol);
96113   sc->pcl_e =  s7_make_circular_signature(sc, 0, 1, s7_make_signature(sc, 4, sc->is_let_symbol, sc->is_procedure_symbol, sc->is_macro_symbol, sc->is_c_object_symbol));
96114 
96115   sc->values_symbol = make_symbol(sc, "values");
96116 
96117   sc->is_bignum_symbol =             defun("bignum?",           is_bignum,              1, 0, false);
96118   sc->bignum_symbol =                defun("bignum",            bignum,                 1, 1, false);
96119 
96120   sc->gensym_symbol =                defun("gensym",		gensym,			0, 1, false);
96121   sc->symbol_table_symbol =          defun("symbol-table",	symbol_table,		0, 0, false);
96122   sc->symbol_to_string_symbol =      defun("symbol->string",	symbol_to_string,	1, 0, false);
96123   sc->string_to_symbol_symbol =      defun("string->symbol",	string_to_symbol,	1, 0, false);
96124   sc->symbol_symbol =                defun("symbol",		symbol,			1, 0, true);
96125   sc->symbol_to_value_symbol =       defun("symbol->value",	symbol_to_value,	1, 1, false);
96126   sc->symbol_to_dynamic_value_symbol = defun("symbol->dynamic-value", symbol_to_dynamic_value, 1, 0, false);
96127   sc->immutable_symbol =             defun("immutable!",	immutable,		1, 0, false);
96128   sc->is_immutable_symbol =          defun("immutable?",	is_immutable,		1, 0, false);
96129   sc->is_constant_symbol =           defun("constant?",	        is_constant,		1, 0, false);
96130 
96131   sc->string_to_keyword_symbol =     defun("string->keyword",	string_to_keyword,      1, 0, false);
96132   sc->symbol_to_keyword_symbol =     defun("symbol->keyword",	symbol_to_keyword,	1, 0, false);
96133   sc->keyword_to_symbol_symbol =     defun("keyword->symbol",	keyword_to_symbol,	1, 0, false);
96134 
96135   sc->outlet_symbol =                defun("outlet",		outlet,			1, 0, false);
96136   sc->rootlet_symbol =               defun("rootlet",		rootlet,		0, 0, false);
96137   sc->curlet_symbol =                defun("curlet",		curlet,			0, 0, false);
96138   set_func_is_definer(sc->curlet_symbol);
96139   sc->unlet_symbol =                 defun("unlet",		unlet,			0, 0, false);
96140   set_local_slot(sc->unlet_symbol, global_slot(sc->unlet_symbol)); /* for set_locals */
96141   set_immutable(sc->unlet_symbol);
96142   /* unlet (and with-let) don't actually need to be immutable, but s7.html says they are... */
96143   sc->is_funclet_symbol =            defun("funclet?",          is_funclet,             1, 0, false);
96144   sc->sublet_symbol =                defun("sublet",		sublet,			1, 0, true);
96145   sc->varlet_symbol =                semisafe_defun("varlet",	varlet,			1, 0, true);
96146   set_func_is_definer(sc->varlet_symbol);
96147   sc->cutlet_symbol =                semisafe_defun("cutlet",	cutlet,			1, 0, true);
96148   set_func_is_definer(sc->cutlet_symbol);
96149   sc->inlet_symbol =                 defun("inlet",		inlet,			0, 0, true);
96150   sc->owlet_symbol =                 defun("owlet",		owlet,			0, 0, false);
96151   sc->coverlet_symbol =              defun("coverlet",		coverlet,		1, 0, false);
96152   sc->openlet_symbol =               defun("openlet",		openlet,		1, 0, false);
96153   sc->let_ref_symbol =               defun("let-ref",		let_ref,		2, 0, false);
96154   set_immutable(sc->let_ref_symbol);  /* 16-Sep-19 */
96155   sc->let_set_symbol =               defun("let-set!",		let_set,		3, 0, false);
96156   set_immutable(sc->let_set_symbol);
96157   sc->let_ref_fallback_symbol = make_symbol(sc, "let-ref-fallback");
96158   sc->let_set_fallback_symbol = make_symbol(sc, "let-set-fallback"); /* was let-set!-fallback until 9-Oct-17 */
96159 
96160   sc->make_iterator_symbol =         defun("make-iterator",	make_iterator,		1, 1, false);
96161   sc->iterate_symbol =               defun("iterate",		iterate,		1, 0, false);
96162   sc->iterator_sequence_symbol =     defun("iterator-sequence", iterator_sequence,	1, 0, false);
96163   sc->iterator_is_at_end_symbol =    defun("iterator-at-end?",  iterator_is_at_end,	1, 0, false);
96164 
96165   sc->is_provided_symbol =           defun("provided?",	        is_provided,		1, 0, false);
96166   sc->provide_symbol =               semisafe_defun("provide",	provide,		1, 0, false); /* can add *features* to curlet */
96167   set_func_is_definer(sc->provide_symbol);
96168   sc->is_defined_symbol =            defun("defined?",		is_defined,		1, 2, false);
96169 
96170   sc->c_object_type_symbol =         defun("c-object-type",     c_object_type,		1, 0, false);
96171   sc->c_pointer_symbol =             defun("c-pointer",	        c_pointer,		1, 4, false);
96172   sc->c_pointer_info_symbol =        defun("c-pointer-info",    c_pointer_info,		1, 0, false);
96173   sc->c_pointer_type_symbol =        defun("c-pointer-type",    c_pointer_type,		1, 0, false);
96174   sc->c_pointer_weak1_symbol =       defun("c-pointer-weak1",   c_pointer_weak1,	1, 0, false);
96175   sc->c_pointer_weak2_symbol =       defun("c-pointer-weak2",   c_pointer_weak2,	1, 0, false);
96176   sc->c_pointer_to_list_symbol =     defun("c-pointer->list",   c_pointer_to_list,      1, 0, false);
96177 
96178   sc->port_file_symbol =             defun("port-file",	        port_file,		1, 0, false);
96179   sc->port_position_symbol =         defun("port-position",	port_position,		1, 0, false);
96180   sc->port_line_number_symbol =      defun("port-line-number",  port_line_number,	0, 1, false);
96181   sc->port_filename_symbol =         defun("port-filename",	port_filename,		0, 1, false);
96182   sc->pair_line_number_symbol =      defun("pair-line-number",  pair_line_number,	1, 0, false);
96183   sc->pair_filename_symbol =         defun("pair-filename",     pair_filename,	        1, 0, false);
96184   sc->is_port_closed_symbol =        defun("port-closed?",	is_port_closed,		1, 0, false);
96185 
96186   sc->current_input_port_symbol =    defun("current-input-port",  current_input_port,  0, 0, false);
96187   sc->current_output_port_symbol =   defun("current-output-port", current_output_port, 0, 0, false);
96188   sc->current_error_port_symbol =    defun("current-error-port", current_error_port,    0, 0, false);
96189   sc->set_current_error_port_symbol = defun("set-current-error-port", set_current_error_port, 1, 0, false);
96190 #if (!WITH_PURE_S7)
96191   sc->let_to_list_symbol =           defun("let->list",	         let_to_list,		1, 0, false);
96192   sc->set_current_input_port_symbol = defun("set-current-input-port", set_current_input_port, 1, 0, false);
96193   sc->set_current_output_port_symbol = defun("set-current-output-port", set_current_output_port, 1, 0, false);
96194   sc->is_char_ready_symbol =         defun("char-ready?",	is_char_ready,		0, 1, false); /* the least-used scheme function */
96195 #endif
96196 
96197   sc->close_input_port_symbol =      defun("close-input-port",   close_input_port,	1, 0, false);
96198   sc->close_output_port_symbol =     defun("close-output-port",  close_output_port,	1, 0, false);
96199   sc->flush_output_port_symbol =     defun("flush-output-port",  flush_output_port,	0, 1, false);
96200   sc->open_input_file_symbol =       defun("open-input-file",    open_input_file,	1, 1, false);
96201   sc->open_output_file_symbol =      defun("open-output-file",   open_output_file,	1, 1, false);
96202   sc->open_input_string_symbol =     defun("open-input-string",  open_input_string,	1, 0, false);
96203   sc->open_output_string_symbol =    defun("open-output-string", open_output_string,	0, 0, false);
96204   sc->get_output_string_symbol =     defun("get-output-string",  get_output_string,	1, 1, false);
96205   sc->get_output_string_uncopied =   s7_make_function(sc, "get-output-string", g_get_output_string_uncopied, 1, 1, false, NULL);
96206   sc->open_input_function_symbol =   defun("open-input-function",open_input_function,	1, 0, false);
96207   sc->open_output_function_symbol =  defun("open-output-function",open_output_function,	1, 0, false);
96208 
96209   sc->closed_input_function = s7_make_function(sc, "closed-input-function", g_closed_input_function_port, 2, 0, false, "input-function error"),
96210   sc->closed_output_function = s7_make_function(sc, "closed-output-function", g_closed_output_function_port, 1, 0, false, "output-function error"),
96211 
96212   sc->newline_symbol =               defun("newline",		newline,		0, 1, false);
96213   sc->write_symbol =                 defun("write",		write,			1, 1, false);
96214   sc->display_symbol =               defun("display",		display,		1, 1, false);
96215   sc->read_char_symbol =             defun("read-char",	        read_char,		0, 1, false);
96216   sc->peek_char_symbol =             defun("peek-char",	        peek_char,		0, 1, false);
96217   sc->write_char_symbol =            defun("write-char",	write_char,		1, 1, false);
96218   sc->write_string_symbol =          defun("write-string",	write_string,		1, 3, false);
96219   sc->read_byte_symbol =             defun("read-byte",	        read_byte,		0, 1, false);
96220   sc->write_byte_symbol =            defun("write-byte",	write_byte,		1, 1, false);
96221   sc->read_line_symbol =             defun("read-line",	        read_line,		0, 2, false);
96222   sc->read_string_symbol =           defun("read-string",	read_string,		1, 1, false);
96223   sc->read_symbol =                  semisafe_defun("read",	read,			0, 1, false);
96224   /* read can't be safe because it messes with the stack, expecting to be all by itself in the call sequence
96225    *   (not embedded in OP_SAFE_C_opSq for example) -- that is, it pushes OP_READ_INTERNAL, then returns
96226    *   expecting continue (goto top-of-eval-loop), which would be nonsense if arg=fn|x_proc(read) -> fn|x_proc(arg).
96227    *   a safe procedure leaves its argument list alone, does not push anything on the stack,
96228    *   and leaves sc->code|args unscathed (fx_call assumes that is the case).  The stack part can
96229    *   be hidden: if a c_function calls s7_apply_function (lambda passed as arg as in some clm gens)
96230    *   then is called with args that use fx*, and the lambda func does the same, the two calls
96231    *   can step on each other.
96232    */
96233 
96234   sc->call_with_input_string_symbol = semisafe_defun("call-with-input-string", call_with_input_string, 2, 0, false); /* body unsafe if func=read */
96235   sc->call_with_input_file_symbol =   semisafe_defun("call-with-input-file",   call_with_input_file,   2, 0, false);
96236   sc->with_input_from_string_symbol = semisafe_defun("with-input-from-string", with_input_from_string, 2, 0, false);
96237   sc->with_input_from_file_symbol =   semisafe_defun("with-input-from-file",   with_input_from_file,   2, 0, false);
96238 
96239   sc->call_with_output_string_symbol = semisafe_defun("call-with-output-string", call_with_output_string, 1, 0, false);
96240   sc->call_with_output_file_symbol =   semisafe_defun("call-with-output-file",   call_with_output_file,   2, 0, false);
96241   sc->with_output_to_string_symbol =   semisafe_defun("with-output-to-string",   with_output_to_string,   1, 0, false);
96242   sc->with_output_to_file_symbol =     semisafe_defun("with-output-to-file",     with_output_to_file,     2, 0, false);
96243 
96244 #if WITH_SYSTEM_EXTRAS
96245   sc->is_directory_symbol =          defun("directory?",	is_directory,		1, 0, false);
96246   sc->file_exists_symbol =           defun("file-exists?",	file_exists,		1, 0, false);
96247   sc->delete_file_symbol =           defun("delete-file",	delete_file,		1, 0, false);
96248   sc->getenv_symbol =                defun("getenv",		getenv,			1, 0, false);
96249   sc->system_symbol =                defun("system",		system,			1, 1, false);
96250 #if (!MS_WINDOWS)
96251   sc->directory_to_list_symbol =     defun("directory->list",   directory_to_list,	1, 0, false);
96252   sc->file_mtime_symbol =            defun("file-mtime",	file_mtime,		1, 0, false);
96253 #endif
96254 #endif
96255 
96256   sc->real_part_symbol =             defun("real-part",	        real_part,		1, 0, false);
96257   sc->imag_part_symbol =             defun("imag-part",	        imag_part,		1, 0, false);
96258   sc->numerator_symbol =             defun("numerator",	        numerator,		1, 0, false);
96259   sc->denominator_symbol =           defun("denominator",	denominator,		1, 0, false);
96260   sc->is_even_symbol =               defun("even?",		is_even,		1, 0, false);
96261   sc->is_odd_symbol =                defun("odd?",		is_odd,			1, 0, false);
96262   sc->is_zero_symbol =               defun("zero?",		is_zero,		1, 0, false);
96263   sc->is_positive_symbol =           defun("positive?",	        is_positive,		1, 0, false);
96264   sc->is_negative_symbol =           defun("negative?",	        is_negative,		1, 0, false);
96265   sc->is_infinite_symbol =           defun("infinite?",	        is_infinite,		1, 0, false);
96266   sc->is_nan_symbol =                defun("nan?",		is_nan,			1, 0, false);
96267   sc->complex_symbol =               defun("complex",	        complex,	        2, 0, false);
96268 
96269   sc->add_symbol =                   defun("+",		        add,			0, 0, true); set_all_integer_and_float(sc->add_symbol);
96270   sc->subtract_symbol =              defun("-",		        subtract,		1, 0, true); set_all_integer_and_float(sc->subtract_symbol);
96271   sc->multiply_symbol =              defun("*",		        multiply,		0, 0, true); set_all_integer_and_float(sc->multiply_symbol);
96272   sc->divide_symbol =                defun("/",		        divide,			1, 0, true); set_all_float(sc->divide_symbol);
96273   sc->min_symbol =                   defun("min",		min,			1, 0, true); set_all_integer_and_float(sc->min_symbol);
96274   sc->max_symbol =                   defun("max",		max,			1, 0, true); set_all_integer_and_float(sc->max_symbol);
96275 
96276   sc->quotient_symbol =              defun("quotient",		quotient,		2, 0, false); set_all_integer(sc->quotient_symbol);
96277   sc->remainder_symbol =             defun("remainder",	        remainder,		2, 0, false); set_all_integer(sc->remainder_symbol);
96278   sc->modulo_symbol =                defun("modulo",		modulo,			2, 0, false); set_all_integer(sc->modulo_symbol);
96279   sc->num_eq_symbol =                defun("=",		        num_eq,			2, 0, true);
96280   sc->lt_symbol =                    defun("<",		        less,			2, 0, true);
96281   sc->gt_symbol =                    defun(">",		        greater,		2, 0, true);
96282   sc->leq_symbol =                   defun("<=",		less_or_equal,		2, 0, true);
96283   sc->geq_symbol =                   defun(">=",		greater_or_equal,	2, 0, true);
96284   sc->gcd_symbol =                   defun("gcd",		gcd,			0, 0, true);
96285   sc->lcm_symbol =                   defun("lcm",		lcm,			0, 0, true);
96286   sc->rationalize_symbol =           defun("rationalize",	rationalize,		1, 1, false);
96287   sc->random_symbol =                defun("random",		random,			1, 1, false); set_all_integer_and_float(sc->random_symbol);
96288   sc->random_state_symbol =          defun("random-state",      random_state,	        1, 1, false);
96289   sc->expt_symbol =                  defun("expt",		expt,			2, 0, false);
96290   sc->log_symbol =                   defun("log",		log,			1, 1, false);
96291   sc->ash_symbol =                   defun("ash",		ash,			2, 0, false);
96292   sc->exp_symbol =                   defun("exp",		exp,			1, 0, false); set_all_float(sc->exp_symbol);
96293   sc->abs_symbol =                   defun("abs",		abs,			1, 0, false); set_all_integer_and_float(sc->abs_symbol);
96294   sc->magnitude_symbol =             defun("magnitude",	        magnitude,		1, 0, false); set_all_integer_and_float(sc->magnitude_symbol);
96295   sc->angle_symbol =                 defun("angle",		angle,			1, 0, false);
96296   sc->sin_symbol =                   defun("sin",		sin,			1, 0, false); set_all_float(sc->sin_symbol);
96297   sc->cos_symbol =                   defun("cos",		cos,			1, 0, false); set_all_float(sc->cos_symbol);
96298   sc->tan_symbol =                   defun("tan",		tan,			1, 0, false); set_all_float(sc->tan_symbol);
96299   sc->sinh_symbol =                  defun("sinh",		sinh,			1, 0, false); set_all_float(sc->sinh_symbol);
96300   sc->cosh_symbol =                  defun("cosh",		cosh,			1, 0, false); set_all_float(sc->cosh_symbol);
96301   sc->tanh_symbol =                  defun("tanh",		tanh,			1, 0, false); set_all_float(sc->tanh_symbol);
96302   sc->asin_symbol =                  defun("asin",		asin,			1, 0, false);
96303   sc->acos_symbol =                  defun("acos",		acos,			1, 0, false);
96304   sc->atan_symbol =                  defun("atan",		atan,			1, 1, false);
96305   sc->asinh_symbol =                 defun("asinh",		asinh,			1, 0, false);
96306   sc->acosh_symbol =                 defun("acosh",		acosh,			1, 0, false);
96307   sc->atanh_symbol =                 defun("atanh",		atanh,			1, 0, false);
96308   sc->sqrt_symbol =                  defun("sqrt",		sqrt,			1, 0, false);
96309   sc->floor_symbol =                 defun("floor",		floor,			1, 0, false);
96310   sc->ceiling_symbol =               defun("ceiling",		ceiling,		1, 0, false);
96311   sc->truncate_symbol =              defun("truncate",		truncate,		1, 0, false);
96312   sc->round_symbol =                 defun("round",		round,			1, 0, false);
96313   sc->logand_symbol =                defun("logand",		logand,			0, 0, true);
96314   sc->logior_symbol =                defun("logior",		logior,			0, 0, true);
96315   sc->logxor_symbol =                defun("logxor",		logxor,			0, 0, true);
96316   sc->lognot_symbol =                defun("lognot",		lognot,			1, 0, false);
96317   sc->logbit_symbol =                defun("logbit?",		logbit,			2, 0, false);
96318   sc->integer_decode_float_symbol =  defun("integer-decode-float", integer_decode_float, 1, 0, false);
96319 #if (!WITH_PURE_S7)
96320   sc->integer_length_symbol =        defun("integer-length",	integer_length,		1, 0, false);
96321   sc->inexact_to_exact_symbol =      defun("inexact->exact",	inexact_to_exact,	1, 0, false);
96322   sc->exact_to_inexact_symbol =      defun("exact->inexact",	exact_to_inexact,	1, 0, false);
96323   sc->is_exact_symbol =              defun("exact?",		is_exact,		1, 0, false);
96324   sc->is_inexact_symbol =            defun("inexact?",		is_inexact,		1, 0, false);
96325 #endif
96326   sc->random_state_to_list_symbol =  defun("random-state->list", random_state_to_list,  0, 1, false);
96327   sc->number_to_string_symbol =      defun("number->string",	number_to_string,	1, 1, false);
96328   sc->string_to_number_symbol =      defun("string->number",	string_to_number,	1, 1, false);
96329 
96330   sc->char_upcase_symbol =           defun("char-upcase",	char_upcase,		1, 0, false);
96331   sc->char_downcase_symbol =         defun("char-downcase",	char_downcase,		1, 0, false);
96332   sc->char_to_integer_symbol =       defun("char->integer",	char_to_integer,	1, 0, false);
96333   sc->integer_to_char_symbol =       defun("integer->char",	integer_to_char,	1, 0, false);
96334 
96335   sc->is_char_upper_case_symbol =    defun("char-upper-case?",  is_char_upper_case,	1, 0, false);
96336   sc->is_char_lower_case_symbol =    defun("char-lower-case?",  is_char_lower_case,	1, 0, false);
96337   sc->is_char_alphabetic_symbol =    defun("char-alphabetic?",  is_char_alphabetic,	1, 0, false);
96338   sc->is_char_numeric_symbol =       defun("char-numeric?",	is_char_numeric,	1, 0, false);
96339   sc->is_char_whitespace_symbol =    defun("char-whitespace?",  is_char_whitespace,	1, 0, false);
96340 
96341   sc->char_eq_symbol =               defun("char=?",		chars_are_equal,	2, 0, true);
96342   sc->char_lt_symbol =               defun("char<?",		chars_are_less,		2, 0, true);
96343   sc->char_gt_symbol =               defun("char>?",		chars_are_greater,	2, 0, true);
96344   sc->char_leq_symbol =              defun("char<=?",		chars_are_leq,		2, 0, true);
96345   sc->char_geq_symbol =              defun("char>=?",		chars_are_geq,		2, 0, true);
96346   sc->char_position_symbol =         defun("char-position",	char_position,		2, 1, false);
96347   sc->string_position_symbol =       defun("string-position",	string_position,	2, 1, false);
96348 
96349   sc->make_string_symbol =           defun("make-string",	make_string,		1, 1, false);
96350   sc->string_ref_symbol =            defun("string-ref",	string_ref,		2, 0, false);
96351   sc->string_set_symbol =            defun("string-set!",	string_set,		3, 0, false);
96352 
96353   sc->string_eq_symbol =             defun("string=?",		strings_are_equal,	2, 0, true);
96354   sc->string_lt_symbol =             defun("string<?",		strings_are_less,	2, 0, true);
96355   sc->string_gt_symbol =             defun("string>?",		strings_are_greater,	2, 0, true);
96356   sc->string_leq_symbol =            defun("string<=?",	        strings_are_leq,	2, 0, true);
96357   sc->string_geq_symbol =            defun("string>=?",	        strings_are_geq,	2, 0, true);
96358 
96359 #if (!WITH_PURE_S7)
96360   sc->char_ci_eq_symbol =            defun("char-ci=?",	        chars_are_ci_equal,	2, 0, true);
96361   sc->char_ci_lt_symbol =            defun("char-ci<?",	        chars_are_ci_less,	2, 0, true);
96362   sc->char_ci_gt_symbol =            defun("char-ci>?",	        chars_are_ci_greater,	2, 0, true);
96363   sc->char_ci_leq_symbol =           defun("char-ci<=?",	chars_are_ci_leq,	2, 0, true);
96364   sc->char_ci_geq_symbol =           defun("char-ci>=?",	chars_are_ci_geq,	2, 0, true);
96365   sc->string_ci_eq_symbol =          defun("string-ci=?",	strings_are_ci_equal,	2, 0, true);
96366   sc->string_ci_lt_symbol =          defun("string-ci<?",	strings_are_ci_less,	2, 0, true);
96367   sc->string_ci_gt_symbol =          defun("string-ci>?",	strings_are_ci_greater, 2, 0, true);
96368   sc->string_ci_leq_symbol =         defun("string-ci<=?",	strings_are_ci_leq,	2, 0, true);
96369   sc->string_ci_geq_symbol =         defun("string-ci>=?",	strings_are_ci_geq,	2, 0, true);
96370   sc->string_fill_symbol =           defun("string-fill!",	string_fill,		2, 2, false);
96371   sc->list_to_string_symbol =        defun("list->string",	list_to_string,		1, 0, false);
96372   sc->string_length_symbol =         defun("string-length",	string_length,		1, 0, false);
96373   sc->string_to_list_symbol =        defun("string->list",	string_to_list,		1, 2, false);
96374 #endif
96375   sc->string_copy_symbol =           defun("string-copy",	string_copy,		1, 3, false);
96376 
96377   sc->string_downcase_symbol =       defun("string-downcase",	string_downcase,	1, 0, false);
96378   sc->string_upcase_symbol =         defun("string-upcase",	string_upcase,		1, 0, false);
96379   sc->string_append_symbol =         defun("string-append",	string_append,		0, 0, true);
96380   sc->substring_symbol =             defun("substring",	        substring,		2, 1, false);
96381   sc->string_symbol =                defun("string",		string,			0, 0, true);
96382   sc->object_to_string_symbol =      defun("object->string",	object_to_string,	1, 2, false);
96383   sc->format_symbol =                defun("format",		format,			2, 0, true);
96384   sc->object_to_let_symbol =         defun("object->let",	object_to_let,	        1, 0, false);
96385 
96386   sc->cons_symbol =                  defun("cons",		cons,			2, 0, false);
96387   sc->car_symbol =                   defun("car",		car,			1, 0, false);
96388   sc->cdr_symbol =                   defun("cdr",		cdr,			1, 0, false);
96389   sc->set_car_symbol =               defun("set-car!",		set_car,		2, 0, false);
96390   sc->set_cdr_symbol =               defun("set-cdr!",	        set_cdr,		2, 0, false);
96391   sc->caar_symbol =                  defun("caar",		caar,			1, 0, false);
96392   sc->cadr_symbol =                  defun("cadr",		cadr,			1, 0, false);
96393   sc->cdar_symbol =                  defun("cdar",		cdar,			1, 0, false);
96394   sc->cddr_symbol =                  defun("cddr",		cddr,			1, 0, false);
96395   sc->caaar_symbol =                 defun("caaar",		caaar,			1, 0, false);
96396   sc->caadr_symbol =                 defun("caadr",		caadr,			1, 0, false);
96397   sc->cadar_symbol =                 defun("cadar",		cadar,			1, 0, false);
96398   sc->cdaar_symbol =                 defun("cdaar",		cdaar,			1, 0, false);
96399   sc->caddr_symbol =                 defun("caddr",		caddr,			1, 0, false);
96400   sc->cdddr_symbol =                 defun("cdddr",		cdddr,			1, 0, false);
96401   sc->cdadr_symbol =                 defun("cdadr",		cdadr,			1, 0, false);
96402   sc->cddar_symbol =                 defun("cddar",		cddar,			1, 0, false);
96403   sc->caaaar_symbol =                defun("caaaar",		caaaar,			1, 0, false);
96404   sc->caaadr_symbol =                defun("caaadr",		caaadr,			1, 0, false);
96405   sc->caadar_symbol =                defun("caadar",		caadar,			1, 0, false);
96406   sc->cadaar_symbol =                defun("cadaar",		cadaar,			1, 0, false);
96407   sc->caaddr_symbol =                defun("caaddr",		caaddr,			1, 0, false);
96408   sc->cadddr_symbol =                defun("cadddr",		cadddr,			1, 0, false);
96409   sc->cadadr_symbol =                defun("cadadr",		cadadr,			1, 0, false);
96410   sc->caddar_symbol =                defun("caddar",		caddar,			1, 0, false);
96411   sc->cdaaar_symbol =                defun("cdaaar",		cdaaar,			1, 0, false);
96412   sc->cdaadr_symbol =                defun("cdaadr",		cdaadr,			1, 0, false);
96413   sc->cdadar_symbol =                defun("cdadar",		cdadar,			1, 0, false);
96414   sc->cddaar_symbol =                defun("cddaar",		cddaar,			1, 0, false);
96415   sc->cdaddr_symbol =                defun("cdaddr",		cdaddr,			1, 0, false);
96416   sc->cddddr_symbol =                defun("cddddr",		cddddr,			1, 0, false);
96417   sc->cddadr_symbol =                defun("cddadr",		cddadr,			1, 0, false);
96418   sc->cdddar_symbol =                defun("cdddar",		cdddar,			1, 0, false);
96419 
96420   sc->assq_symbol =                  defun("assq",		assq,			2, 0, false);
96421   sc->assv_symbol =                  defun("assv",		assv,			2, 0, false);
96422   sc->assoc_symbol =                 semisafe_defun("assoc",	assoc,			2, 1, false);
96423   sc->memq_symbol =                  defun("memq",		memq,			2, 0, false);
96424   sc->memv_symbol =                  defun("memv",		memv,			2, 0, false);
96425   sc->member_symbol =                semisafe_defun("member",	member,			2, 1, false);
96426 
96427   sc->list_symbol =                  defun("list",		list,			0, 0, true);
96428   sc->list_ref_symbol =              defun("list-ref",		list_ref,		2, 0, true);
96429   sc->list_set_symbol =              defun("list-set!",	        list_set,		3, 0, true);
96430   sc->list_tail_symbol =             defun("list-tail",	        list_tail,		2, 0, false);
96431   sc->make_list_symbol =             defun("make-list",  	make_list,		1, 1, false);
96432 
96433   sc->length_symbol =                defun("length",		length,			1, 0, false);
96434   sc->copy_symbol =                  defun("copy",		copy,			1, 3, false);
96435   /* set_is_definer(sc->copy_symbol); */ /* (copy (inlet 'a 1) (curlet)), but this check needs to be smarter */
96436   sc->fill_symbol =                  defun("fill!",		fill,			2, 2, false);
96437   sc->reverse_symbol =               defun("reverse",		reverse,		1, 0, false);
96438   sc->reverseb_symbol =              defun("reverse!",		reverse_in_place,	1, 0, false);
96439   sc->sort_symbol =                  unsafe_defun("sort!",      sort, 	                2, 0, false); /* not semisafe! */
96440   sc->append_symbol =                defun("append",		append,			0, 0, true);
96441 
96442 #if (!WITH_PURE_S7)
96443   sc->vector_append_symbol =         defun("vector-append",	vector_append,		0, 0, true);
96444   sc->list_to_vector_symbol =        defun("list->vector",	list_to_vector,		1, 0, false);
96445   sc->vector_fill_symbol =           defun("vector-fill!",	vector_fill,		2, 2, false);
96446   sc->vector_length_symbol =         defun("vector-length",	vector_length,		1, 0, false);
96447   sc->vector_to_list_symbol =        defun("vector->list",	vector_to_list,		1, 2, false);
96448 #else
96449   sc->vector_append_symbol = sc->append_symbol;
96450   sc->vector_fill_symbol = sc->fill_symbol;
96451   sc->string_fill_symbol = sc->fill_symbol;
96452 #endif
96453   sc->vector_ref_symbol =            defun("vector-ref",	vector_ref,		2, 0, true);
96454   sc->vector_set_symbol =            defun("vector-set!",	vector_set,		3, 0, true);
96455   sc->vector_dimensions_symbol =     defun("vector-dimensions", vector_dimensions,	1, 0, false);
96456   sc->make_vector_symbol =           defun("make-vector",	make_vector,		1, 2, false);
96457   sc->vector_symbol =                defun("vector",		vector,			0, 0, true);
96458   set_is_setter(sc->vector_symbol); /* like cons, I guess */
96459 
96460   sc->subvector_symbol =             defun("subvector",         subvector,	        1, 3, false);
96461   sc->subvector_position_symbol =    defun("subvector-position", subvector_position,    1, 0, false);
96462   sc->subvector_vector_symbol =      defun("subvector-vector",  subvector_vector,       1, 0, false);
96463 
96464   sc->float_vector_symbol =          defun("float-vector",	float_vector,		0, 0, true);
96465   sc->make_float_vector_symbol =     defun("make-float-vector", make_float_vector,	1, 1, false);
96466   sc->float_vector_set_symbol =      defun("float-vector-set!", float_vector_set,	3, 0, true);
96467   sc->float_vector_ref_symbol =      defun("float-vector-ref",  float_vector_ref,	2, 0, true);
96468 
96469   sc->int_vector_symbol =            defun("int-vector",	int_vector,		0, 0, true);
96470   sc->make_int_vector_symbol =       defun("make-int-vector",	make_int_vector,	1, 1, false);
96471   sc->int_vector_set_symbol =        defun("int-vector-set!",	int_vector_set,		3, 0, true);
96472   sc->int_vector_ref_symbol =        defun("int-vector-ref",	int_vector_ref,		2, 0, true);
96473 
96474   sc->byte_vector_symbol =           defun("byte-vector",	byte_vector,		0, 0, true);
96475   sc->make_byte_vector_symbol =      defun("make-byte-vector",  make_byte_vector,	1, 1, false);
96476   sc->byte_vector_ref_symbol =       defun("byte-vector-ref",	byte_vector_ref,        2, 0, true);
96477   sc->byte_vector_set_symbol =       defun("byte-vector-set!",	byte_vector_set,	3, 0, true);
96478   sc->string_to_byte_vector_symbol = defun("string->byte-vector", string_to_byte_vector, 1, 0, false);
96479   sc->byte_vector_to_string_symbol = defun("byte-vector->string", byte_vector_to_string, 1, 0, false);
96480 
96481   sc->hash_table_symbol =            defun("hash-table",	hash_table,		0, 0, true);
96482   sc->make_hash_table_symbol =       defun("make-hash-table",	make_hash_table,	0, 3, false);
96483   sc->make_weak_hash_table_symbol =  defun("make-weak-hash-table", make_weak_hash_table,0, 3, false);
96484   sc->weak_hash_table_symbol =       defun("weak-hash-table",   weak_hash_table,        0, 0, true);
96485   sc->hash_table_ref_symbol =        defun("hash-table-ref",	hash_table_ref,		2, 0, true);
96486   sc->hash_table_set_symbol =        defun("hash-table-set!",	hash_table_set,		3, 0, false);
96487   sc->hash_table_entries_symbol =    defun("hash-table-entries", hash_table_entries,	1, 0, false);
96488   sc->hash_code_symbol =             defun("hash-code",         hash_code,              1, 1, false);
96489   sc->dummy_equal_hash_table = make_dummy_hash_table(sc);
96490 
96491   sc->cyclic_sequences_symbol =      defun("cyclic-sequences",  cyclic_sequences,	1, 0, false);
96492   sc->call_cc_symbol =               semisafe_defun("call/cc",	call_cc,		1, 0, false);   /* was unsafe 8-Feb-21 */
96493   sc->call_with_current_continuation_symbol = unsafe_defun("call-with-current-continuation", call_cc, 1, 0, false);
96494   sc->call_with_exit_symbol =        semisafe_defun("call-with-exit", call_with_exit,     1, 0, false); /* was unsafe 8-Feb-21 */
96495 
96496   sc->load_symbol =                  semisafe_defun("load",	load,			1, 1, false);
96497   sc->autoload_symbol =              defun("autoload",	        autoload,		2, 0, false);
96498   sc->eval_symbol =                  semisafe_defun("eval",	eval,			1, 1, false); /* was unsafe 8-Feb-21, can affect stack */
96499   set_func_is_definer(sc->eval_symbol);
96500   sc->eval_string_symbol =           semisafe_defun("eval-string", eval_string,		1, 1, false);
96501   set_func_is_definer(sc->eval_string_symbol);
96502   sc->apply_symbol =                 semisafe_defun("apply",    apply,			1, 0, true); /* was unsafe 8-Feb-21, can jump to OP_APPLY */
96503   {
96504     s7_pointer p;
96505     set_func_is_definer(sc->apply_symbol);
96506     /* yow... (apply (inlet) (f)) in do body where (f) returns '(define...) -- see s7test.scm under apply
96507      *   perhaps better: if closure returns a definer in some way set its name as a definer? even this is not fool-proof
96508      */
96509     p = global_value(sc->apply_symbol);
96510     set_full_type(p, type(p) | T_COPY_ARGS | T_UNHEAP);
96511     /* (let ((x '((1 2) 3 4))) (catch #t (lambda () (apply apply apply x)) (lambda args 'error)) x) should not mess up x! */
96512   }
96513   sc->for_each_symbol =              semisafe_defun("for-each",	for_each,		2, 0, true);
96514   sc->map_symbol =                   semisafe_defun("map",	map,			2, 0, true);
96515   sc->dynamic_wind_symbol =          semisafe_defun("dynamic-wind", dynamic_wind,       3, 0, false);
96516   sc->dynamic_unwind_symbol =        semisafe_defun("dynamic-unwind", dynamic_unwind,   2, 0, false);
96517   sc->catch_symbol =                 semisafe_defun("catch",	catch,			3, 0, false);
96518   sc->throw_symbol =                 unsafe_defun("throw",	throw,			1, 0, true);
96519   sc->error_symbol =                 unsafe_defun("error",	error,			0, 0, true);
96520   /* not safe in catch if macro as error handler, (define-macro (m . args) `(apply ,(car args) ',(cadr args))) (catch #t (lambda () (error abs -1)) m) */
96521   sc->stacktrace_symbol =            defun("stacktrace",	stacktrace,		0, 5, false);
96522 
96523   /* sc->values_symbol = */          unsafe_defun("values",	values,			0, 0, true); /* values_symbol set above for signatures, not semisafe! */
96524   sc->apply_values_symbol =          unsafe_defun("apply-values", apply_values,         0, 1, false);
96525   set_immutable(sc->apply_values_symbol);
96526   sc->list_values_symbol =           defun("list-values",       list_values,            0, 0, true);
96527   set_immutable(sc->list_values_symbol);
96528 
96529   sc->documentation_symbol =         defun("documentation",     documentation,          1, 0, false);
96530   sc->signature_symbol =             defun("signature",         signature,	        1, 0, false);
96531   sc->help_symbol =                  defun("help",		help,			1, 0, false);
96532   sc->procedure_source_symbol =      defun("procedure-source",  procedure_source,	1, 0, false);
96533   sc->funclet_symbol =               defun("funclet",		funclet,		1, 0, false);
96534   sc->_function__symbol =            defun("*function*",        function,	        0, 2, false);
96535   sc->dilambda_symbol =              defun("dilambda",          dilambda,               2, 0, false);
96536   s7_typed_dilambda(sc, "setter", g_setter, 1, 1, g_set_setter, 2, 1, H_setter, Q_setter, NULL);
96537   sc->arity_symbol =                 defun("arity",		arity,			1, 0, false);
96538   sc->is_aritable_symbol =           defun("aritable?",	        is_aritable,		2, 0, false);
96539 
96540   sc->is_eq_symbol =                 defun("eq?",		is_eq,			2, 0, false);
96541   sc->is_eqv_symbol =                defun("eqv?",		is_eqv,			2, 0, false);
96542   sc->is_equal_symbol =              defun("equal?",		is_equal,		2, 0, false);
96543   sc->is_equivalent_symbol =         defun("equivalent?",	is_equivalent,	2, 0, false);
96544   sc->type_of_symbol =               defun("type-of",		type_of,		1, 0, false);
96545 
96546   sc->gc_symbol =                    semisafe_defun("gc",	gc,			0, 1, false);
96547                                      defun("emergency-exit",	emergency_exit,		0, 1, false);
96548   sc->exit_symbol =                  defun("exit",		exit,			0, 1, false);
96549 
96550 #if WITH_GCC
96551   s7_define_function(sc, "abort", g_abort, 0, 0, true, "drop into gdb I hope");
96552 #endif
96553   s7_define_function(sc, "s7-optimize", g_optimize, 1, 0, false, "short-term debugging aid");
96554   sc->c_object_set_function = s7_make_function(sc, "#<c-object-setter>", g_c_object_set, 1, 0, true, "c-object setter");
96555   /* c_function_signature(sc->c_object_set_function) = s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_c_object_symbol, sc->T); */
96556 
96557   set_scope_safe(global_value(sc->call_with_input_string_symbol));
96558   set_scope_safe(global_value(sc->call_with_input_file_symbol));
96559   set_scope_safe(global_value(sc->call_with_output_string_symbol));
96560   set_scope_safe(global_value(sc->call_with_output_file_symbol));
96561   set_scope_safe(global_value(sc->with_input_from_string_symbol));
96562   set_scope_safe(global_value(sc->with_input_from_file_symbol));
96563   set_scope_safe(global_value(sc->with_output_to_string_symbol));
96564   set_scope_safe(global_value(sc->with_output_to_file_symbol));
96565   set_maybe_safe(global_value(sc->assoc_symbol));
96566   set_scope_safe(global_value(sc->assoc_symbol));
96567   set_maybe_safe(global_value(sc->member_symbol));
96568   set_scope_safe(global_value(sc->member_symbol));
96569   set_scope_safe(global_value(sc->sort_symbol));
96570   set_scope_safe(global_value(sc->call_with_exit_symbol));
96571   set_scope_safe(global_value(sc->for_each_symbol));
96572   set_maybe_safe(global_value(sc->for_each_symbol));
96573   set_scope_safe(global_value(sc->map_symbol));
96574   set_maybe_safe(global_value(sc->map_symbol));
96575   set_scope_safe(global_value(sc->dynamic_wind_symbol));
96576   set_scope_safe(global_value(sc->catch_symbol));
96577   set_scope_safe(global_value(sc->throw_symbol));
96578   set_scope_safe(global_value(sc->error_symbol));
96579   set_scope_safe(global_value(sc->apply_values_symbol));
96580 
96581   sc->tree_leaves_symbol =    defun("tree-leaves",   tree_leaves,    1, 0, false);
96582   sc->tree_memq_symbol =      defun("tree-memq",     tree_memq,      2, 0, false);
96583   sc->tree_set_memq_symbol =  defun("tree-set-memq", tree_set_memq,  2, 0, false);
96584   sc->tree_count_symbol =     defun("tree-count",    tree_count,     2, 1, false);
96585   sc->tree_is_cyclic_symbol = defun("tree-cyclic?",  tree_is_cyclic, 1, 0, false);
96586 
96587   sc->quasiquote_symbol = s7_define_macro(sc, "quasiquote", g_quasiquote, 1, 0, false, H_quasiquote);
96588 
96589   sc->profile_in_symbol = unsafe_defun("profile-in", profile_in, 1, 0, false); /* calls dynamic-unwind */
96590   sc->profile_out = NULL;
96591 
96592   /* -------- *features* -------- */
96593   sc->features_symbol = s7_define_variable_with_documentation(sc, "*features*", sc->nil, "list of currently available features ('complex-numbers, etc)");
96594   s7_set_setter(sc, sc->features_symbol, s7_make_function(sc, "#<set-*features*>", g_features_set, 2, 0, false, "*features* setter"));
96595 
96596   /* -------- *load-path* -------- */
96597   sc->load_path_symbol = s7_define_variable_with_documentation(sc, "*load-path*", list_1(sc, s7_make_string(sc, ".")), /* was sc->nil 12-Jul-19 */
96598 			   "*load-path* is a list of directories (strings) that the load function searches if it is passed an incomplete file name");
96599   s7_set_setter(sc, sc->load_path_symbol, s7_make_function(sc, "#<set-*load-path*>", g_load_path_set, 2, 0, false, "*load-path* setter"));
96600 
96601 #ifdef CLOAD_DIR
96602   sc->cload_directory_symbol = s7_define_variable(sc, "*cload-directory*", s7_make_string(sc, (char *)CLOAD_DIR));
96603   s7_add_to_load_path(sc, (const char *)CLOAD_DIR);
96604 #else
96605   sc->cload_directory_symbol = s7_define_variable(sc, "*cload-directory*", make_empty_string(sc, 0, 0));
96606 #endif
96607   s7_set_setter(sc, sc->cload_directory_symbol, s7_make_function(sc, "#<set-*cload-directory*>", g_cload_directory_set, 2, 0, false, "*cload-directory* setter"));
96608 
96609   /* -------- *autoload* --------
96610    * this pretends to be a hash-table or environment, but it's actually a function
96611    */
96612   sc->autoloader_symbol = s7_define_typed_function(sc, "*autoload*", g_autoloader, 1, 0, false, H_autoloader, Q_autoloader);
96613   c_function_set_setter(global_value(sc->autoloader_symbol), global_value(sc->autoload_symbol)); /* (set! (*autoload* x) y) */
96614 
96615   sc->libraries_symbol = s7_define_variable_with_documentation(sc, "*libraries*", sc->nil, "list of currently loaded libraries (libc.scm, etc)");
96616   s7_set_setter(sc, sc->libraries_symbol, s7_make_function(sc, "#<set-*libraries*>", g_libraries_set, 2, 0, false, "*libraries* setter"));
96617 
96618   s7_autoload(sc, make_symbol(sc, "cload.scm"),       s7_make_permanent_string(sc, "cload.scm"));
96619   s7_autoload(sc, make_symbol(sc, "lint.scm"),        s7_make_permanent_string(sc, "lint.scm"));
96620   s7_autoload(sc, make_symbol(sc, "stuff.scm"),       s7_make_permanent_string(sc, "stuff.scm"));
96621   s7_autoload(sc, make_symbol(sc, "mockery.scm"),     s7_make_permanent_string(sc, "mockery.scm"));
96622   s7_autoload(sc, make_symbol(sc, "write.scm"),       s7_make_permanent_string(sc, "write.scm"));
96623   s7_autoload(sc, make_symbol(sc, "reactive.scm"),    s7_make_permanent_string(sc, "reactive.scm"));
96624   s7_autoload(sc, make_symbol(sc, "repl.scm"),        s7_make_permanent_string(sc, "repl.scm"));
96625   s7_autoload(sc, make_symbol(sc, "r7rs.scm"),        s7_make_permanent_string(sc, "r7rs.scm"));
96626   s7_autoload(sc, make_symbol(sc, "profile.scm"),     s7_make_permanent_string(sc, "profile.scm"));
96627   s7_autoload(sc, make_symbol(sc, "debug.scm"),       s7_make_permanent_string(sc, "debug.scm"));
96628   s7_autoload(sc, make_symbol(sc, "case.scm"),        s7_make_permanent_string(sc, "case.scm"));
96629 
96630   s7_autoload(sc, make_symbol(sc, "libc.scm"),        s7_make_permanent_string(sc, "libc.scm"));
96631   s7_autoload(sc, make_symbol(sc, "libm.scm"),        s7_make_permanent_string(sc, "libm.scm"));
96632   s7_autoload(sc, make_symbol(sc, "libdl.scm"),       s7_make_permanent_string(sc, "libdl.scm"));
96633   s7_autoload(sc, make_symbol(sc, "libgsl.scm"),      s7_make_permanent_string(sc, "libgsl.scm"));
96634   s7_autoload(sc, make_symbol(sc, "libgdbm.scm"),     s7_make_permanent_string(sc, "libgdbm.scm"));
96635   s7_autoload(sc, make_symbol(sc, "libutf8proc.scm"), s7_make_permanent_string(sc, "libutf8proc.scm"));
96636 
96637   sc->require_symbol = s7_define_macro(sc, "require", g_require, 1, 0, true, H_require);
96638   sc->stacktrace_defaults = s7_list(sc, 5, int_three, small_int(45), small_int(80), small_int(45), sc->T); /* assume NUM_SMALL_INTS >= NUM_CHARS == 256 */
96639 
96640   /* -------- *#readers* -------- */
96641   sym = s7_define_variable_with_documentation(sc, "*#readers*", sc->nil, "list of current reader macros");
96642   sc->sharp_readers = global_slot(sym);
96643   s7_set_setter(sc, sym, s7_make_function(sc, "#<set-*#readers*>", g_sharp_readers_set, 2, 0, false, "*#readers* setter"));
96644 
96645   sc->local_documentation_symbol = make_symbol(sc, "+documentation+");
96646   sc->local_signature_symbol =     make_symbol(sc, "+signature+");
96647   sc->local_setter_symbol =        make_symbol(sc, "+setter+");
96648   sc->local_iterator_symbol =      make_symbol(sc, "+iterator+");
96649 
96650 #if (!DISABLE_DEPRECATED)
96651   s7_define_variable(sc, "nan.0", real_NaN);
96652   s7_define_variable(sc, "inf.0", real_infinity);
96653 #endif
96654 
96655   init_features(sc);
96656   init_setters(sc);
96657 }
96658 
96659 #if (!MS_WINDOWS)
96660 static pthread_mutex_t init_lock = PTHREAD_MUTEX_INITIALIZER;
96661 #endif
96662 
96663 s7_scheme *s7_init(void)
96664 {
96665   int32_t i;
96666   s7_scheme *sc;
96667   static bool already_inited = false;
96668 
96669 #if (!MS_WINDOWS)
96670   setlocale(LC_NUMERIC, "C"); /* use decimal point in floats */
96671   pthread_mutex_lock(&init_lock);
96672 #endif
96673 
96674   if (!already_inited)
96675     {
96676       init_types();
96677       init_ctables();
96678       init_mark_functions();
96679       init_display_functions();
96680       init_length_functions();
96681       init_equals();
96682       init_hash_maps();
96683       init_pows();
96684       init_int_limits();
96685       init_small_ints();
96686       init_uppers();
96687       init_chars();
96688       init_strings();
96689       init_fx_function();
96690       init_catchers();
96691       already_inited = true;
96692     }
96693 
96694 #if (!MS_WINDOWS)
96695   pthread_mutex_unlock(&init_lock);
96696 #endif
96697   sc = (s7_scheme *)calloc(1, sizeof(s7_scheme)); /* not malloc! */
96698   cur_sc = sc;                                    /* for gdb/debugging */
96699   sc->gc_off = true;                              /* sc->args and so on are not set yet, so a gc during init -> segfault */
96700   sc->gc_stats = 0;
96701 
96702   sc->saved_pointers = (void **)malloc(INITIAL_SAVED_POINTERS_SIZE * sizeof(void *));
96703   sc->saved_pointers_loc = 0;
96704   sc->saved_pointers_size = INITIAL_SAVED_POINTERS_SIZE;
96705 
96706   init_gc_caches(sc);
96707   sc->permanent_cells = 0;
96708   sc->alloc_pointer_k = ALLOC_POINTER_SIZE;
96709   sc->alloc_pointer_cells = NULL;
96710   sc->alloc_big_pointer_k = ALLOC_BIG_POINTER_SIZE;
96711   sc->alloc_big_pointer_cells = NULL;
96712   sc->alloc_function_k = ALLOC_FUNCTION_SIZE;
96713   sc->alloc_function_cells = NULL;
96714   sc->alloc_symbol_k = ALLOC_SYMBOL_SIZE;
96715   sc->alloc_symbol_cells = NULL;
96716   sc->num_to_str_size = -1;
96717   sc->num_to_str = NULL;
96718   init_block_lists(sc);
96719   sc->alloc_string_k = ALLOC_STRING_SIZE;
96720   sc->alloc_string_cells = NULL;
96721   sc->alloc_opt_func_cells = NULL;
96722   sc->alloc_opt_func_k = ALLOC_FUNCTION_SIZE;
96723 
96724   sc->longjmp_ok = false;
96725   sc->setjmp_loc = NO_SET_JUMP;
96726 
96727   sc->max_vector_length = (1LL << 32);
96728   sc->max_string_length = 1073741824; /* 1 << 30 */
96729   sc->max_format_length = 10000;
96730   sc->max_list_length = 1073741824;
96731   sc->max_vector_dimensions = 512;
96732 
96733   sc->strbuf_size = INITIAL_STRBUF_SIZE;
96734   sc->strbuf = (char *)calloc(sc->strbuf_size, 1);
96735   sc->print_width = sc->max_string_length;
96736   sc->short_print = false;
96737   sc->in_with_let = false;
96738   sc->object_out_locked = false;
96739   sc->has_openlets = true;
96740   sc->is_expanding = true;
96741   sc->accept_all_keyword_arguments = false;
96742 
96743   sc->initial_string_port_length = 128;
96744   sc->format_depth = -1;
96745   sc->singletons = (s7_pointer *)calloc(256, sizeof(s7_pointer));
96746   add_saved_pointer(sc, sc->singletons);
96747   sc->read_line_buf = NULL;
96748   sc->read_line_buf_size = 0;
96749   sc->last_error_line = -1;
96750   sc->stop_at_error = true;
96751 
96752   sc->nil =         make_unique(sc, "()",             T_NIL);
96753   sc->unused =      make_unique(sc, "#<unused>",      T_UNUSED);
96754   sc->T =           make_unique(sc, "#t",             T_BOOLEAN);
96755   sc->F =           make_unique(sc, "#f",             T_BOOLEAN);
96756   sc->undefined =   make_unique(sc, "#<undefined>",   T_UNDEFINED);
96757   sc->unspecified = make_unique(sc, "#<unspecified>", T_UNSPECIFIED);
96758   sc->no_value =    make_unique(sc, "#<unspecified>", T_UNSPECIFIED);
96759 
96760   unique_car(sc->nil) = sc->unspecified;
96761   unique_cdr(sc->nil) = sc->unspecified;
96762   /* this is mixing two different s7_cell structs, cons and envr, but luckily envr has two initial s7_pointer fields, equivalent to car and cdr, so
96763    *   let_id which is the same as opt1 is unaffected.  To get the names built-in, I'll append unique_name and unique_name_length fields to the envr struct.
96764    */
96765   let_set_id(sc->nil, -1);
96766   unique_cdr(sc->unspecified) = sc->unspecified;
96767 
96768   sc->temp_cell_2 = permanent_cons(sc, sc->nil, sc->nil, T_PAIR | T_IMMUTABLE);
96769 
96770   sc->t1_1 = permanent_cons(sc, sc->nil, sc->nil,  T_PAIR | T_IMMUTABLE);
96771   sc->t2_2 = permanent_cons(sc, sc->nil, sc->nil,  T_PAIR | T_IMMUTABLE);
96772   sc->t2_1 = permanent_cons(sc, sc->nil, sc->t2_2, T_PAIR | T_IMMUTABLE);
96773   sc->z2_2 = permanent_cons(sc, sc->nil, sc->nil,  T_PAIR | T_IMMUTABLE);
96774   sc->z2_1 = permanent_cons(sc, sc->nil, sc->z2_2, T_PAIR | T_IMMUTABLE);
96775   sc->t3_3 = permanent_cons(sc, sc->nil, sc->nil,  T_PAIR | T_IMMUTABLE);
96776   sc->t3_2 = permanent_cons(sc, sc->nil, sc->t3_3, T_PAIR | T_IMMUTABLE);
96777   sc->t3_1 = permanent_cons(sc, sc->nil, sc->t3_2, T_PAIR | T_IMMUTABLE);
96778   sc->t4_1 = permanent_cons(sc, sc->nil, sc->t3_1, T_PAIR | T_IMMUTABLE);
96779   sc->u1_1 = permanent_cons(sc, sc->nil, sc->nil,  T_PAIR | T_IMMUTABLE);
96780   sc->u2_1 = permanent_cons(sc, sc->nil, sc->u1_1, T_PAIR | T_IMMUTABLE);
96781 
96782   sc->safe_lists[0] = sc->nil;
96783   for (i = 1; i < NUM_SAFE_PRELISTS; i++)
96784     sc->safe_lists[i] = permanent_list(sc, i);
96785   for (i = NUM_SAFE_PRELISTS; i < NUM_SAFE_LISTS; i++)
96786     sc->safe_lists[i] = sc->nil;
96787   sc->current_safe_list = 0;
96788 
96789   sc->input_port_stack_size = INPUT_PORT_STACK_INITIAL_SIZE;
96790   sc->input_port_stack = (s7_pointer *)malloc(sc->input_port_stack_size * sizeof(s7_pointer));
96791   sc->input_port_stack_loc = 0;
96792 
96793   sc->code = sc->nil;
96794 #if WITH_HISTORY
96795   sc->eval_history1 = permanent_list(sc, DEFAULT_HISTORY_SIZE);
96796   sc->eval_history2 = permanent_list(sc, DEFAULT_HISTORY_SIZE);
96797   sc->history_pairs = permanent_list(sc, DEFAULT_HISTORY_SIZE);
96798   sc->history_sink = permanent_list(sc, 1);
96799   cdr(sc->history_sink) = sc->history_sink;
96800   {
96801     s7_pointer p1, p2, p3;
96802     for (p3 = sc->history_pairs; is_pair(cdr(p3)); p3 = cdr(p3)) set_car(p3, permanent_list(sc, 1));
96803     set_car(p3, permanent_list(sc, 1));
96804     set_cdr(p3, sc->history_pairs);
96805     for (p1 = sc->eval_history1, p2 = sc->eval_history2; is_pair(cdr(p1)); p1 = cdr(p1), p2 = cdr(p2));
96806     set_cdr(p1, sc->eval_history1);
96807     set_cdr(p2, sc->eval_history2);
96808     sc->cur_code = sc->eval_history1;
96809     sc->using_history1 = true;
96810     sc->old_cur_code = sc->cur_code;
96811   }
96812 #else
96813   sc->cur_code = sc->F;
96814 #endif
96815   sc->args = sc->nil;
96816   sc->value = sc->nil;
96817   sc->u = sc->nil;
96818   sc->v = sc->nil;
96819   sc->w = sc->nil;
96820   sc->x = sc->nil;
96821   sc->y = sc->nil;
96822   sc->z = sc->nil;
96823 
96824   sc->temp1 = sc->nil;
96825   sc->temp2 = sc->nil;
96826   sc->temp3 = sc->nil;
96827   sc->temp4 = sc->nil;
96828   sc->temp5 = sc->nil;
96829   sc->temp6 = sc->nil;
96830   sc->temp7 = sc->nil;
96831   sc->temp8 = sc->nil;
96832   sc->temp9 = sc->nil;
96833 
96834   sc->rec_p1 = sc->F;
96835   sc->rec_p2 = sc->F;
96836 
96837   sc->begin_hook = NULL;
96838   sc->autoload_table = sc->nil;
96839   sc->autoload_names = NULL;
96840   sc->autoload_names_sizes = NULL;
96841   sc->autoloaded_already = NULL;
96842   sc->autoload_names_loc = 0;
96843 #if DISABLE_AUTOLOAD
96844   sc->is_autoloading = false;
96845 #else
96846   sc->is_autoloading = true;
96847 #endif
96848   sc->rec_stack = NULL;
96849 
96850   sc->heap_size = INITIAL_HEAP_SIZE;
96851   if ((sc->heap_size % 32) != 0)
96852     sc->heap_size = 32 * (int64_t)ceil((double)(sc->heap_size) / 32.0);
96853   sc->heap = (s7_pointer *)malloc(sc->heap_size * sizeof(s7_pointer));
96854   sc->free_heap = (s7_cell **)malloc(sc->heap_size * sizeof(s7_cell *));
96855   sc->free_heap_top = (s7_cell **)(sc->free_heap + INITIAL_HEAP_SIZE);
96856   sc->free_heap_trigger = (s7_cell **)(sc->free_heap + GC_TRIGGER_SIZE);
96857   sc->previous_free_heap_top = sc->free_heap_top;
96858   {
96859     s7_cell *cells;
96860     cells = (s7_cell *)calloc(INITIAL_HEAP_SIZE, sizeof(s7_cell)); /* calloc to make sure type=0 at start? (for gc/valgrind) */
96861     add_saved_pointer(sc, (void *)cells);
96862     for (i = 0; i < INITIAL_HEAP_SIZE; i++)       /* LOOP_4 here is slower! */
96863       {
96864 	sc->heap[i] = &cells[i];
96865  	sc->free_heap[i] = sc->heap[i];
96866 	i++;
96867 	sc->heap[i] = &cells[i];
96868  	sc->free_heap[i] = sc->heap[i];
96869      }
96870     sc->heap_blocks = (heap_block_t *)malloc(sizeof(heap_block_t));
96871     sc->heap_blocks->start = (intptr_t)cells;
96872     sc->heap_blocks->end = (intptr_t)cells + (sc->heap_size * sizeof(s7_cell));
96873     sc->heap_blocks->offset = 0;
96874     sc->heap_blocks->next = NULL;
96875   }
96876   sc->gc_temps_size = GC_TEMPS_SIZE;
96877   sc->gc_resize_heap_fraction = GC_RESIZE_HEAP_FRACTION;
96878   sc->gc_resize_heap_by_4_fraction = GC_RESIZE_HEAP_BY_4_FRACTION;
96879   sc->max_heap_size = (1LL << 62);
96880   sc->gc_calls = 0;
96881   sc->gc_total_time = 0;
96882 
96883   sc->max_port_data_size = (1LL << 62);
96884 #ifndef OUTPUT_PORT_DATA_SIZE
96885   #define OUTPUT_PORT_DATA_SIZE 2048
96886 #endif
96887   sc->output_port_data_size = OUTPUT_PORT_DATA_SIZE;
96888 
96889   /* this has to precede s7_make_* allocations */
96890   sc->protected_setters_size = INITIAL_PROTECTED_OBJECTS_SIZE;
96891   sc->protected_setters_loc = 0;
96892   sc->protected_setters = s7_make_vector(sc, INITIAL_PROTECTED_OBJECTS_SIZE);
96893   sc->protected_setter_symbols = s7_make_vector(sc, INITIAL_PROTECTED_OBJECTS_SIZE);
96894 
96895   sc->protected_objects_size = INITIAL_PROTECTED_OBJECTS_SIZE;
96896   sc->gpofl = (s7_int *)malloc(INITIAL_PROTECTED_OBJECTS_SIZE * sizeof(s7_int));
96897   sc->gpofl_loc = INITIAL_PROTECTED_OBJECTS_SIZE - 1;
96898   sc->protected_objects = s7_make_vector(sc, INITIAL_PROTECTED_OBJECTS_SIZE);
96899   for (i = 0; i < INITIAL_PROTECTED_OBJECTS_SIZE; i++)
96900     {
96901       vector_element(sc->protected_objects, i) = sc->unused;
96902       vector_element(sc->protected_setters, i) = sc->unused;
96903       vector_element(sc->protected_setter_symbols, i) = sc->unused;
96904       sc->gpofl[i] = i;
96905     }
96906 
96907   sc->stack = s7_make_vector(sc, INITIAL_STACK_SIZE); /* this fills it with sc->nil */
96908   sc->stack_start = vector_elements(sc->stack); /* stack type set below */
96909   sc->stack_end = sc->stack_start;
96910   sc->stack_size = INITIAL_STACK_SIZE;
96911   /* sc->stack_resize_trigger = (s7_pointer *)(sc->stack_start + sc->stack_size / 2); */
96912   sc->stack_resize_trigger = (s7_pointer *)(sc->stack_start + (INITIAL_STACK_SIZE - STACK_RESIZE_TRIGGER));
96913   set_full_type(sc->stack, T_STACK);
96914   sc->max_stack_size = (1 << 30);
96915   stack_clear_flags(sc->stack);
96916   initialize_op_stack(sc);
96917 
96918   /* keep the symbol table out of the heap */
96919   sc->symbol_table = (s7_pointer)calloc(1, sizeof(s7_cell));
96920   set_full_type(sc->symbol_table, T_VECTOR | T_UNHEAP);
96921   vector_length(sc->symbol_table) = SYMBOL_TABLE_SIZE;
96922   vector_elements(sc->symbol_table) = (s7_pointer *)malloc(SYMBOL_TABLE_SIZE * sizeof(s7_pointer));
96923   vector_getter(sc->symbol_table) = default_vector_getter;
96924   vector_setter(sc->symbol_table) = default_vector_setter;
96925   s7_vector_fill(sc, sc->symbol_table, sc->nil);
96926   {
96927     opt_info *os;
96928     os = (opt_info *)calloc(OPTS_SIZE, sizeof(opt_info));
96929     add_saved_pointer(sc, os);
96930     for (i = 0; i < OPTS_SIZE; i++)
96931       {
96932 	opt_info *o;
96933 	o = &os[i];
96934 	sc->opts[i] = o;
96935 	opt_set_sc(o, sc);
96936       }}
96937 
96938   for (i = 0; i < NUM_TYPES; i++)
96939     sc->prepackaged_type_names[i] = s7_make_permanent_string(sc, (const char *)type_name_from_type(i, INDEFINITE_ARTICLE));
96940 
96941 #if WITH_MULTITHREAD_CHECKS
96942   sc->lock_count = 0;
96943   {
96944     pthread_mutexattr_t attr;
96945     pthread_mutexattr_init(&attr);
96946     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
96947     pthread_mutex_init(&sc->lock, &attr);
96948   }
96949 #endif
96950 
96951   sc->c_object_types = NULL;
96952   sc->c_object_types_size = 0;
96953   sc->num_c_object_types = 0;
96954   sc->typnam = NULL;
96955   sc->typnam_len = 0;
96956   sc->default_rationalize_error = 1.0e-12;
96957   sc->hash_table_float_epsilon = 1.0e-12;
96958   sc->equivalent_float_epsilon = 1.0e-15;
96959   sc->float_format_precision = WRITE_REAL_PRECISION;
96960   sc->default_hash_table_length = 8;
96961   sc->gensym_counter = 0;
96962   sc->capture_let_counter = 0;
96963   sc->f_class = 0;
96964   sc->add_class = 0;
96965   sc->num_eq_class = 0;
96966   sc->let_number = 0;
96967   sc->format_column = 0;
96968   sc->format_ports = NULL;
96969   sc->file_names = NULL;
96970   sc->file_names_size = 0;
96971   sc->file_names_top = -1;
96972   sc->s7_call_line = 0;
96973   sc->s7_call_file = NULL;
96974   sc->s7_call_name = NULL;
96975   sc->safety = NO_SAFETY;
96976   sc->debug = 0;
96977   sc->profile = 0;
96978   sc->debug_or_profile = false;
96979   sc->profiling_gensyms = false;
96980   sc->profile_data = NULL;
96981   sc->print_length = DEFAULT_PRINT_LENGTH;
96982   sc->history_size = DEFAULT_HISTORY_SIZE;
96983   sc->true_history_size = DEFAULT_HISTORY_SIZE;
96984   sc->baffle_ctr = 0;
96985   sc->syms_tag = 0;
96986   sc->syms_tag2 = 0;
96987   sc->class_name_symbol = make_symbol(sc, "class-name");
96988   sc->name_symbol = make_symbol(sc, "name");
96989   sc->trace_in_symbol = make_symbol(sc, "trace-in");
96990   sc->size_symbol = make_symbol(sc, "size");
96991   sc->mutable_symbol = make_symbol(sc, "mutable?");
96992   sc->circle_info = init_circle_info(sc);
96993   sc->fdats = (format_data_t **)calloc(8, sizeof(format_data_t *));
96994   sc->num_fdats = 8;
96995   sc->plist_1 = permanent_list(sc, 1);
96996   sc->plist_2 = permanent_list(sc, 2);
96997   sc->plist_2_2 = cdr(sc->plist_2);
96998   sc->plist_3 = permanent_list(sc, 3);
96999   sc->qlist_2 = permanent_list(sc, 2);
97000   sc->qlist_3 = permanent_list(sc, 3);
97001   sc->clist_1 = permanent_list(sc, 1);
97002   sc->elist_1 = permanent_list(sc, 1);
97003   sc->elist_2 = permanent_list(sc, 2);
97004   sc->elist_3 = permanent_list(sc, 3);
97005   sc->elist_4 = permanent_list(sc, 4);
97006   sc->elist_5 = permanent_list(sc, 5);
97007   sc->undefined_identifier_warnings = false;
97008   sc->undefined_constant_warnings = false;
97009   sc->wrap_only = make_wrap_only(sc);
97010   sc->unentry = (hash_entry_t *)malloc(sizeof(hash_entry_t));
97011   hash_entry_set_value(sc->unentry, sc->F);
97012   sc->begin_op = OP_BEGIN_NO_HOOK;
97013   /* we used to laboriously set various other fields to null, but the calloc takes care of that */
97014   sc->tree_pointers = NULL;
97015   sc->tree_pointers_size = 0;
97016   sc->tree_pointers_top = 0;
97017 
97018   sc->rootlet = s7_make_vector(sc, INITIAL_ROOTLET_SIZE);
97019   set_full_type(sc->rootlet, T_LET | T_SAFE_PROCEDURE);
97020   sc->rootlet_entries = 0;
97021   for (i = 0; i < INITIAL_ROOTLET_SIZE; i++)
97022     rootlet_element(sc->rootlet, i) = sc->nil;
97023   sc->curlet = sc->nil;
97024   sc->shadow_rootlet = sc->nil;
97025   sc->objstr_max_len = S7_INT64_MAX;
97026 
97027   init_wrappers(sc);
97028   init_standard_ports(sc);
97029   init_rootlet(sc);
97030   init_open_input_function_choices(sc);
97031 
97032   {
97033     s7_pointer p;
97034     new_cell(sc, p, T_RANDOM_STATE); /* s7_set_default_random_state might set sc->default_rng, so this shouldn't be permanent */
97035     sc->default_rng = p;
97036 
97037     sc->bignum_precision = DEFAULT_BIGNUM_PRECISION;
97038 #if WITH_GMP
97039     sc->bigints = NULL;
97040     sc->bigrats = NULL;
97041     sc->bigflts = NULL;
97042     sc->bigcmps = NULL;
97043 
97044     mpfr_set_default_prec((mp_prec_t)DEFAULT_BIGNUM_PRECISION);
97045     mpc_set_default_precision((mp_prec_t)DEFAULT_BIGNUM_PRECISION);
97046 
97047     mpz_inits(sc->mpz_1, sc->mpz_2, sc->mpz_3, sc->mpz_4, NULL);
97048     mpq_inits(sc->mpq_1, sc->mpq_2, sc->mpq_3, NULL);
97049     mpfr_inits2(DEFAULT_BIGNUM_PRECISION, sc->mpfr_1, sc->mpfr_2, sc->mpfr_3, NULL);
97050     mpc_init(sc->mpc_1);
97051     mpc_init(sc->mpc_2);
97052 
97053     mpz_set_ui(sc->mpz_1, (uint64_t)my_clock());
97054     gmp_randinit_default(random_gmp_state(p));
97055     gmp_randseed(random_gmp_state(p), sc->mpz_1);
97056 
97057     sc->pi_symbol = s7_define_constant(sc, "pi", big_pi(sc));
97058     set_initial_slot(sc->pi_symbol, make_permanent_slot(sc, sc->pi_symbol, big_pi(sc))); /* s7_make_slot does not handle this */
97059     s7_provide(sc, "gmp");
97060 #else
97061     random_seed(p) = (uint64_t)my_clock(); /* used to be time(NULL), but that means separate threads can get the same random number sequence */
97062     random_carry(p) = 1675393560;
97063     sc->pi_symbol = s7_define_constant(sc, "pi", real_pi);
97064 #endif
97065   }
97066   for (i = 0; i < 10; i++) sc->singletons[(uint8_t)'0' + i] = small_int(i);
97067   sc->singletons[(uint8_t)'+'] = sc->add_symbol;
97068   sc->singletons[(uint8_t)'-'] = sc->subtract_symbol;
97069   sc->singletons[(uint8_t)'*'] = sc->multiply_symbol;
97070   sc->singletons[(uint8_t)'/'] = sc->divide_symbol;
97071   sc->singletons[(uint8_t)'<'] = sc->lt_symbol;
97072   sc->singletons[(uint8_t)'>'] = sc->gt_symbol;
97073   sc->singletons[(uint8_t)'='] = sc->num_eq_symbol;
97074 
97075   init_choosers(sc);
97076   init_typers(sc);
97077   init_opt_functions(sc);
97078   s7_set_history_enabled(sc, false);
97079 
97080 #if S7_DEBUGGING
97081   init_tc_rec(sc);
97082 #endif
97083 
97084 #if (!WITH_PURE_S7)
97085   s7_define_variable(sc, "make-rectangular", global_value(sc->complex_symbol));
97086   s7_eval_c_string(sc, "(define make-polar                                                                \n\
97087                           (let ((+signature+ '(number? real? real?)))                                     \n\
97088                             (lambda (mag ang)                                                             \n\
97089                               (if (and (real? mag) (real? ang))                                           \n\
97090                                   (complex (* mag (cos ang)) (* mag (sin ang)))                           \n\
97091                                   (error 'wrong-type-arg \"make-polar arguments should be real\")))))");
97092 
97093   s7_eval_c_string(sc, "(define (call-with-values producer consumer) (consumer (producer)))");
97094 
97095   s7_eval_c_string(sc, "(define-macro (multiple-value-bind vars expression . body)                        \n\
97096                           (list (cons 'lambda (cons vars body)) expression))");
97097 
97098   s7_eval_c_string(sc, "(define-macro (cond-expand . clauses)                                             \n\
97099                           (letrec ((traverse (lambda (tree)                                               \n\
97100 		                               (if (pair? tree)                                           \n\
97101 			                           (cons (traverse (car tree))                            \n\
97102 				                         (case (cdr tree) ((())) (else => traverse)))     \n\
97103 			                           (if (memq tree '(and or not else)) tree                \n\
97104 			                               (and (symbol? tree) (provided? tree)))))))         \n\
97105                             (cons 'cond (map (lambda (clause)                                             \n\
97106 		                               (if (pair? clause)                                         \n\
97107                                                    (cons (traverse (car clause))                          \n\
97108 			                                 (case (cdr clause) ((()) '(#f)) (else)))         \n\
97109                                                    (error 'read-error \"cond-expand: bad clause\")))      \n\
97110 		                             clauses))))");
97111 #endif
97112 
97113   s7_eval_c_string(sc, "(define-expansion (reader-cond . clauses)                                         \n\
97114                           (call-with-exit                                                                 \n\
97115                             (lambda (return)                                                              \n\
97116                               (for-each                                                                   \n\
97117                                 (lambda (clause)                                                          \n\
97118 	                          (let ((val (eval (car clause))))                                        \n\
97119                                     (when val                                                             \n\
97120                                       (return (cond ((null? (cdr clause)) val)                            \n\
97121                                                     ((eq? (cadr clause) '=>) ((eval (caddr clause)) val)) \n\
97122                                                     ((null? (cddr clause)) (cadr clause))                 \n\
97123                                                     (else (apply values (map quote (cdr clause)))))))))   \n\
97124                                 clauses)                                                                  \n\
97125                               (values))))"); /* this is not redundant */  /* map above ignores trailing cdr if improper */
97126 
97127   s7_eval_c_string(sc, "(define make-hook                                                                 \n\
97128                           (let ((+signature+ '(procedure?))                                               \n\
97129                                 (+documentation+ \"(make-hook . pars) returns a new hook (a function) that passes the parameters to its function list.\")) \n\
97130                             (lambda hook-args                                                             \n\
97131                               (let ((body ()))                                                            \n\
97132                                 (apply lambda* hook-args                                                  \n\
97133                                   (copy '(let ((result #<unspecified>))                                   \n\
97134                                            (let ((hook (curlet)))                                         \n\
97135                                              (for-each (lambda (hook-function) (hook-function hook)) body)\n\
97136                                              result))                                                     \n\
97137                                         :readable)                                                        \n\
97138                                   ())))))");
97139 
97140   s7_eval_c_string(sc, "(define hook-functions                                                            \n\
97141                           (let ((+signature+ '(#t procedure?))                                            \n\
97142                                 (+documentation+ \"(hook-functions hook) gets or sets the list of functions associated with the hook\")) \n\
97143                             (dilambda                                                                     \n\
97144                               (lambda (hook)                                                              \n\
97145                                 ((funclet hook) 'body))                                                   \n\
97146                               (lambda (hook lst)                                                          \n\
97147                                 (if (do ((p lst (cdr p)))                                                 \n\
97148                                         ((not (and (pair? p)                                              \n\
97149                                                    (procedure? (car p))                                   \n\
97150                                                    (aritable? (car p) 1)))                                \n\
97151                                          (null? p)))                                                      \n\
97152                                     (set! ((funclet hook) 'body) lst)                                     \n\
97153                                     (error 'wrong-type-arg \"hook-functions must be a list of functions, each accepting one argument: ~S\" lst))))))");
97154 
97155   /* -------- *unbound-variable-hook* -------- */
97156   sc->unbound_variable_hook = s7_eval_c_string(sc, "(make-hook 'variable)");
97157   s7_define_constant_with_documentation(sc, "*unbound-variable-hook*", sc->unbound_variable_hook,
97158 					"*unbound-variable-hook* functions are called when an unbound variable is encountered, passed (hook 'variable).");
97159 
97160   /* -------- *missing-close-paren-hook* -------- */
97161   sc->missing_close_paren_hook = s7_eval_c_string(sc, "(make-hook)");
97162   s7_define_constant_with_documentation(sc, "*missing-close-paren-hook*", sc->missing_close_paren_hook,
97163 					"*missing-close-paren-hook* functions are called when the reader thinks a close paren is missing");
97164 
97165   /* -------- *load-hook* -------- */
97166   sc->load_hook = s7_eval_c_string(sc, "(make-hook 'name)");
97167   s7_define_constant_with_documentation(sc, "*load-hook*", sc->load_hook,
97168 					"*load-hook* functions are invoked by load, passing the to-be-loaded filename as (hook 'name)");
97169 
97170   /* -------- *autoload-hook* -------- */
97171   sc->autoload_hook = s7_eval_c_string(sc, "(make-hook 'name 'file)");
97172   s7_define_constant_with_documentation(sc, "*autoload-hook*", sc->autoload_hook,
97173 					"*autoload-hook* functions are invoked by autoload, passing the to-be-autoloaded filename as (hook 'name) and (hook 'file))");
97174 
97175   /* -------- *error-hook* -------- */
97176   sc->error_hook = s7_eval_c_string(sc, "(make-hook 'type 'data)");
97177   s7_define_constant_with_documentation(sc, "*error-hook*", sc->error_hook,
97178 					"*error-hook* functions are called in the error handler, passed (hook 'type) and (hook 'data).");
97179 
97180   /* -------- *read-error-hook* -------- */
97181   sc->read_error_hook = s7_eval_c_string(sc, "(make-hook 'type 'data)");
97182   s7_define_constant_with_documentation(sc, "*read-error-hook*", sc->read_error_hook,
97183 					"*read-error-hook* functions are called by the reader if it is unhappy, passing the current program string as (hook 'data).");
97184 
97185   /* -------- *rootlet-redefinition-hook* -------- */
97186   sc->rootlet_redefinition_hook = s7_eval_c_string(sc, "(make-hook 'name 'value)");
97187   s7_define_constant_with_documentation(sc, "*rootlet-redefinition-hook*", sc->rootlet_redefinition_hook,
97188 					"*rootlet-redefinition-hook* functions are called when a top-level variable's value is changed, (hook 'name 'value).");
97189 
97190   sc->s7_let = s7_inlet(sc, /* have to use s7_inlet here because we're setting let fallbacks */
97191 		 s7_list(sc, 4,
97192 			 sc->let_ref_fallback_symbol, s7_make_function(sc, "s7-let-ref", g_s7_let_ref_fallback, 2, 0, false, "*s7* reader"),
97193 			 sc->let_set_fallback_symbol, s7_make_function(sc, "s7-let-set", g_s7_let_set_fallback, 3, 0, false, "*s7* writer")));
97194   sc->s7_let_symbol = s7_define_constant(sc, "*s7*", s7_openlet(sc, sc->s7_let));
97195   set_immutable(let_slots(sc->s7_let)); /* make the *s7* let-ref|set! fallbacks immutable */
97196   set_immutable(next_slot(let_slots(sc->s7_let)));
97197   set_immutable(sc->s7_let);
97198 
97199   s7_set_history_enabled(sc, true);
97200 
97201 #if S7_DEBUGGING
97202   s7_define_function(sc, "report-missed-calls", g_report_missed_calls, 0, 0, false, NULL);
97203   if (!s7_type_names[0]) {fprintf(stderr, "no type_names\n"); gdb_break();} /* squelch very stupid warnings! */
97204   if (strcmp(op_names[HOP_SAFE_C_PP], "h_safe_c_pp") != 0) fprintf(stderr, "c op_name: %s\n", op_names[HOP_SAFE_C_PP]);
97205   if (strcmp(op_names[OP_SET_WITH_LET_2], "set_with_let_2") != 0) fprintf(stderr, "set op_name: %s\n", op_names[OP_SET_WITH_LET_2]);
97206   if (NUM_OPS != 923) fprintf(stderr, "size: cell: %d, block: %d, max op: %d, opt: %d\n", (int)sizeof(s7_cell), (int)sizeof(block_t), NUM_OPS, (int)sizeof(opt_info));
97207   /* cell size: 48, 120 if debugging, block size: 40, opt: 128 or 280 */
97208 #endif
97209 
97210   init_unlet(sc);
97211   init_s7_let(sc);          /* set up *s7* */
97212   init_signatures(sc);      /* depends on procedure symbols */
97213 
97214   return(sc);
97215 }
97216 
97217 
97218 /* -------------------------------- s7_free -------------------------------- */
97219 
97220 void s7_free(s7_scheme *sc)
97221 {
97222   /* free the memory associated with sc
97223    *   most pointers are in the saved_pointers table, but any that might be realloc'd need to be handled explicitly
97224    * valgrind --leak-check=full --show-reachable=yes --suppressions=/home/bil/cl/free.supp repl s7test.scm
97225    * valgrind --leak-check=full --show-reachable=yes --gen-suppressions=all --error-limit=no --log-file=raw.log repl s7test.scm
97226    */
97227   s7_int i;
97228   gc_list_t *gp;
97229 
97230   g_gc(sc, sc->nil); /* probably not needed (my simple tests work fine if the gc call is omitted) */
97231 
97232   gp = sc->vectors;
97233   for (i = 0; i < gp->loc; i++)
97234     if (block_index(unchecked_vector_block(gp->list[i])) == TOP_BLOCK_LIST)
97235       free(block_data(unchecked_vector_block(gp->list[i])));
97236   free(gp->list);
97237   free(gp);
97238   free(sc->multivectors->list); /* I assume vector_dimension_info won't need 131072 bytes */
97239   free(sc->multivectors);
97240 
97241   gp = sc->strings;
97242   for (i = 0; i < gp->loc; i++)
97243     if (block_index(unchecked_string_block(gp->list[i])) == TOP_BLOCK_LIST)
97244       free(block_data(unchecked_string_block(gp->list[i])));
97245   free(gp->list);
97246   free(gp);
97247 
97248   gp = sc->output_ports;
97249   for (i = 0; i < gp->loc; i++)
97250     {
97251       if ((unchecked_port_data_block(gp->list[i])) &&
97252 	  (block_index(unchecked_port_data_block(gp->list[i])) == TOP_BLOCK_LIST))
97253 	free(block_data(unchecked_port_data_block(gp->list[i])));   /* the file contents, port_block is other stuff */
97254       if ((is_file_port(gp->list[i])) &&
97255 	  (!port_is_closed(gp->list[i])))
97256 	fclose(port_file(gp->list[i]));
97257     }
97258   free(gp->list);
97259   free(gp);
97260 
97261   gp = sc->input_ports;
97262   for (i = 0; i < gp->loc; i++)
97263     if ((unchecked_port_data_block(gp->list[i])) &&
97264 	(block_index(unchecked_port_data_block(gp->list[i])) == TOP_BLOCK_LIST))
97265       free(block_data(unchecked_port_data_block(gp->list[i])));    /* the file contents, port_block is other stuff */
97266   free(gp->list);
97267   free(gp);
97268   free(sc->input_string_ports->list); /* port_data_block is null, port_block is the const char* data, so I assume it is handled elsewhere */
97269   free(sc->input_string_ports);
97270 
97271   gp = sc->hash_tables;
97272   for (i = 0; i < gp->loc; i++)
97273     if (block_index(unchecked_hash_table_block(gp->list[i])) == TOP_BLOCK_LIST)
97274       free(block_data(unchecked_hash_table_block(gp->list[i])));
97275   free(gp->list);
97276   free(gp);
97277 
97278   gp = sc->c_objects;
97279   for (i = 0; i < gp->loc; i++)
97280     {
97281       s7_pointer s1;
97282       s1 = gp->list[i];
97283       if (c_object_gc_free(sc, s1))
97284         (*(c_object_gc_free(sc, s1)))(sc, s1);
97285       else (*(c_object_free(sc, s1)))(c_object_value(s1));
97286     }
97287   free(gp->list);
97288   free(gp);
97289 
97290 #if WITH_GMP
97291   /* free lists */
97292   {bigint *p, *np; for (p = sc->bigints; p; p = np) {mpz_clear(p->n); np = p->nxt; free(p);}}
97293   {bigrat *p, *np; for (p = sc->bigrats; p; p = np) {mpq_clear(p->q); np = p->nxt; free(p);}}
97294   {bigflt *p, *np; for (p = sc->bigflts; p; p = np) {mpfr_clear(p->x); np = p->nxt; free(p);}}
97295   {bigcmp *p, *np; for (p = sc->bigcmps; p; p = np) {mpc_clear(p->z); np = p->nxt; free(p);}}
97296 
97297   /* in-use lists */
97298   gp = sc->big_integers;
97299   for (i = 0; i < gp->loc; i++) {bigint *p; p = big_integer_bgi(gp->list[i]); mpz_clear(p->n); free(p);}
97300   free(gp->list);
97301   free(gp);
97302 
97303   gp = sc->big_ratios;
97304   for (i = 0; i < gp->loc; i++) {bigrat *p; p = big_ratio_bgr(gp->list[i]); mpq_clear(p->q); free(p);}
97305   free(gp->list);
97306   free(gp);
97307 
97308   gp = sc->big_reals;
97309   for (i = 0; i < gp->loc; i++) {bigflt *p; p = big_real_bgf(gp->list[i]); mpfr_clear(p->x); free(p);}
97310   free(gp->list);
97311   free(gp);
97312 
97313   gp = sc->big_complexes;
97314   for (i = 0; i < gp->loc; i++) {bigcmp *p; p = big_complex_bgc(gp->list[i]); mpc_clear(p->z); free(p);}
97315   free(gp->list);
97316   free(gp);
97317 
97318   gp = sc->big_random_states;
97319   for (i = 0; i < gp->loc; i++) gmp_randclear(random_gmp_state(gp->list[i]));
97320   free(gp->list);
97321   free(gp);
97322 
97323   gmp_randclear(random_gmp_state(sc->default_rng));
97324 
97325   /* temps */
97326   if (sc->ratloc) free_rat_locals(sc);
97327   mpz_clears(sc->mpz_1, sc->mpz_2, sc->mpz_3, sc->mpz_4, NULL);
97328   mpq_clears(sc->mpq_1, sc->mpq_2, sc->mpq_3, NULL);
97329   mpfr_clears(sc->mpfr_1, sc->mpfr_2, sc->mpfr_3, NULL);
97330   mpc_clear(sc->mpc_1);
97331   mpc_clear(sc->mpc_2);
97332   /* I claim the leftovers (864 bytes, all from mpfr_cosh) are gmp's fault */
97333 #endif
97334 
97335   free(undefined_name(sc->undefined));
97336   gp = sc->undefineds;
97337   for (i = 0; i < gp->loc; i++)
97338     free(undefined_name(gp->list[i]));
97339   free(gp->list);
97340   free(gp);
97341 
97342   free(sc->gensyms->list);
97343   free(sc->gensyms);
97344   free(sc->continuations->list);
97345   free(sc->continuations);            /* stack is simple vector (handled above) */
97346   free(sc->lambdas->list);
97347   free(sc->lambdas);
97348   free(sc->weak_refs->list);
97349   free(sc->weak_refs);
97350   free(sc->weak_hash_iterators->list);
97351   free(sc->weak_hash_iterators);
97352   free(sc->opt1_funcs);
97353 
97354   free(port_port(sc->standard_output));
97355   free(port_port(sc->standard_error));
97356   free(port_port(sc->standard_input));
97357 
97358   if (sc->autoload_names) free(sc->autoload_names);
97359   if (sc->autoload_names_sizes) free(sc->autoload_names_sizes);
97360   if (sc->autoloaded_already) free(sc->autoloaded_already);
97361 
97362   {
97363     block_t *top;
97364     for (top = sc->block_lists[TOP_BLOCK_LIST]; top; top = block_next(top))
97365       if (block_data(top))
97366 	free(block_data(top));
97367   }
97368 
97369   for (i = 0; i < sc->saved_pointers_loc; i++)
97370     free(sc->saved_pointers[i]);
97371   free(sc->saved_pointers);
97372 
97373   {
97374     gc_obj_t *g, *gnxt;
97375     for (g = sc->permanent_lets; g; g = gnxt)    {gnxt = g->nxt; free(g);}
97376     for (g = sc->permanent_objects; g; g = gnxt) {gnxt = g->nxt; free(g);}
97377   }
97378 
97379   {
97380     heap_block_t *hp, *hpnxt;
97381     for (hp = sc->heap_blocks; hp; hp = hpnxt) {hpnxt = hp->next; free(hp);}
97382   }
97383 
97384   free(sc->heap);
97385   free(sc->free_heap);
97386   free(vector_elements(sc->symbol_table)); /* alloc'd directly, not via block */
97387   free(sc->symbol_table);
97388   free(sc->unlet);
97389   free(sc->setters);
97390   free(sc->op_stack);
97391   if (sc->tree_pointers) free(sc->tree_pointers);
97392   free(sc->num_to_str);
97393   free(sc->gpofl);
97394   if (sc->read_line_buf) free(sc->read_line_buf);
97395   free(sc->strbuf);
97396   free(sc->circle_info->objs);
97397   free(sc->circle_info->refs);
97398   free(sc->circle_info->defined);
97399   free(sc->circle_info);
97400   if (sc->file_names) free(sc->file_names);
97401   free(sc->unentry);
97402   free(sc->input_port_stack);
97403   if (sc->typnam) free(sc->typnam);
97404 
97405   for (i = 0; i < sc->num_fdats; i++)
97406     if (sc->fdats[i])                 /* init val is NULL */
97407       {
97408 	if (sc->fdats[i]->curly_str)
97409 	  free(sc->fdats[i]->curly_str);
97410 	free(sc->fdats[i]);
97411       }
97412   free(sc->fdats);
97413 
97414   if (sc->profile_data)
97415     {
97416       free(sc->profile_data->funcs);
97417       free(sc->profile_data->excl);
97418       free(sc->profile_data->data);
97419       free(sc->profile_data);
97420     }
97421   if (sc->c_object_types)
97422     {
97423       for (i = 0; i < sc->num_c_object_types; i++)
97424 	free(sc->c_object_types[i]);
97425       free(sc->c_object_types);
97426     }
97427   free(sc);
97428 }
97429 
97430 
97431 /* -------------------------------- repl -------------------------------- */
97432 
97433 #ifndef USE_SND
97434   #define USE_SND 0
97435 #endif
97436 #ifndef WITH_MAIN
97437   #define WITH_MAIN 0
97438 #endif
97439 
97440 #if WITH_MAIN && WITH_NOTCURSES
97441   #define S7_MAIN 1
97442   #include "nrepl.c"
97443   /* gcc -o nrepl s7.c -O2 -I. -Wl,-export-dynamic -lm -ldl -DWITH_MAIN -DWITH_NOTCURSES -lnotcurses */
97444 #else
97445 
97446 static void dumb_repl(s7_scheme *sc)
97447 {
97448   while (true)
97449     {
97450       char buffer[512];
97451       fprintf(stdout, "\n> ");
97452       if (!fgets(buffer, 512, stdin)) break;  /* error or ctrl-D */
97453       if (((buffer[0] != '\n') || (strlen(buffer) > 1)))
97454 	{
97455 	  char response[1024];
97456 	  snprintf(response, 1024, "(write %s)", buffer);
97457 	  s7_eval_c_string(sc, response);
97458 	}}
97459   fprintf(stdout, "\n");
97460   if (ferror(stdin))
97461     fprintf(stderr, "read error on stdin\n");
97462 }
97463 
97464 void s7_repl(s7_scheme *sc)
97465 {
97466 #if (!WITH_C_LOADER)
97467   dumb_repl(sc);
97468 #else
97469 
97470   s7_pointer old_e, e, val;
97471   s7_int gc_loc;
97472   /* try to get lib_s7.so from the repl's directory, and set *libc*.
97473    *   otherwise repl.scm will try to load libc.scm which will try to build libc_s7.so locally, but that requires s7.h
97474    */
97475   e = s7_inlet(sc, list_2(sc, s7_make_symbol(sc, "init_func"), s7_make_symbol(sc, "libc_s7_init")));
97476   gc_loc = s7_gc_protect(sc, e);
97477   old_e = s7_set_curlet(sc, e);   /* e is now (curlet) so loaded names from libc will be placed there, not in (rootlet) */
97478 
97479   val = s7_load_with_environment(sc, "libc_s7.so", e);
97480   if (val)
97481     {
97482       s7_pointer libs;
97483       s7_define_variable(sc, "*libc*", e);
97484       libs = global_slot(sc->libraries_symbol);
97485       slot_set_value(libs, cons(sc, cons(sc, make_permanent_string("libc.scm"), e), slot_value(libs)));
97486     }
97487 
97488   s7_set_curlet(sc, old_e);       /* restore incoming (curlet) */
97489   s7_gc_unprotect_at(sc, gc_loc);
97490 
97491   if (!val) /* s7_load_with_environment was unable to find/load libc_s7.so */
97492     dumb_repl(sc);
97493   else
97494     {
97495 #if S7_DEBUGGING
97496       s7_autoload(sc, s7_make_symbol(sc, "compare-calls"), s7_make_string(sc, "compare-calls.scm"));
97497       s7_autoload(sc, s7_make_symbol(sc, "get-overheads"), s7_make_string(sc, "compare-calls.scm"));
97498 #endif
97499       s7_provide(sc, "libc.scm");
97500 #if WITH_NREPL
97501       s7_load(sc, "nrepl.scm");
97502       s7_eval_c_string(sc, "((*nrepl* 'run))");
97503 #else
97504       s7_load(sc, "repl.scm");
97505       s7_eval_c_string(sc, "((*repl* 'run))");
97506 #endif
97507     }
97508 #endif
97509 }
97510 
97511 #if WITH_MAIN && (!USE_SND)
97512 
97513 #if (!MS_WINDOWS) && WITH_C_LOADER
97514 static char *realdir(const char *filename) /* this code courtesy Lassi Kortela 4-Nov-19 */
97515 {
97516   char *path;
97517   char *p;
97518   /* s7_repl wants to load libc_s7.o (for tcsetattr et al), but if it is started in a directory other than the libc_s7.so
97519    *   directory, it fails (it tries to build the library but that requires s7.h and libc.scm).  So here we are trying to
97520    *   guess the libc_s7 directory from the command line program name.  This can't work in general, but it works often
97521    *   enough to be worth the effort.  If S7_LOAD_PATH is set, it is used instead.
97522    */
97523   if (!strchr(filename, '/'))
97524     {
97525       if (!file_probe("libc_s7.so"))
97526 	{
97527 	  fprintf(stderr, "%s needs libc_s7.so (give the explicit pathname)\n", filename); /* env PATH=/home/bil/cl repl */
97528 	  exit(2);
97529 	}
97530       return(NULL); /* we're in the libc_s7.so directory, I hope (local s7 might not match local libc_s7.so) */
97531     }
97532   if (!(path = realpath(filename, NULL)))
97533     {
97534       fprintf(stderr, "%s: %s\n", strerror(errno), filename);
97535       exit(2);
97536     }
97537   if (!(p = strrchr(path, '/')))
97538     {
97539       free(path);
97540       fprintf(stderr, "please provide the full pathname for %s\n", filename);
97541       exit(2);
97542     }
97543   if (p > path) *p = '\0'; else p[1] = 0;
97544   return(path);
97545 }
97546 #endif
97547 
97548 int main(int argc, char **argv)
97549 {
97550   s7_scheme *sc;
97551 
97552   sc = s7_init();
97553   fprintf(stderr, "s7: %s\n", S7_DATE);
97554 
97555   if (argc == 2)
97556     {
97557       fprintf(stderr, "load %s\n", argv[1]);
97558       if (!s7_load(sc, argv[1]))
97559 	{
97560 	  fprintf(stderr, "can't load %s\n", argv[1]);
97561 	  return(2);
97562 	}}
97563   else
97564     {
97565 #if (MS_WINDOWS) || (!WITH_C_LOADER) || ((defined(__linux__)) && (!defined(__GLIBC__))) /* musl? */
97566       dumb_repl(sc);
97567 #else
97568 #ifdef S7_LOAD_PATH
97569       s7_add_to_load_path(sc, S7_LOAD_PATH);
97570 #else
97571       char *dir;
97572       dir = realdir(argv[0]);
97573       if (dir)
97574 	{
97575 	  s7_add_to_load_path(sc, dir);
97576 	  free(dir);
97577 	}
97578 #endif
97579       s7_repl(sc);
97580 #endif
97581     }
97582   return(0);
97583 }
97584 
97585 /* in Linux:  gcc s7.c -o repl -DWITH_MAIN -I. -O2 -g -ldl -lm -Wl,-export-dynamic
97586  * in *BSD:   gcc s7.c -o repl -DWITH_MAIN -I. -O2 -g -lm -Wl,-export-dynamic
97587  * in OSX:    gcc s7.c -o repl -DWITH_MAIN -I. -O2 -g -lm
97588  *   (clang also needs LDFLAGS="-Wl,-export-dynamic" in Linux and "-fPIC")
97589  * (s7.c compile time 17-Jun-20 48 secs)
97590  * musl works, but there is some problem in libgsl.scm with gsl/gsl_blas.h I think
97591  */
97592 #endif
97593 #endif
97594 
97595 /* -----------------------------------------------------
97596  *             gmp (2-11)  20.9   21.0   21.1   21.2
97597  * -----------------------------------------------------
97598  * tpeak       128          115    114    114    113
97599  * tref        739          691    687    687    602
97600  * tauto       786          648    642    647    651
97601  * tshoot     1663          883    872    872    856
97602  * index      1076         1026   1016   1014   1013
97603  * tmock      7690         1177   1165   1166   1147
97604  * s7test     4527         1873   1831   1817   1809
97605  * lt         2117         2123   2110   2112   2101
97606  * tmat       2418         2285   2258   2256   2117
97607  * tcopy      2277         2256   2230   2219   2217
97608  * tform      3319         2281   2273   2266   2288
97609  * tvect      2649         2456   2413   2413   2331
97610  * tread      2610         2440   2421   2412   2403
97611  * trclo      4292         2715   2561   2560   2526
97612  * fbench     2980         2688   2583   2577   2561
97613  * tb         3472         2735   2681   2677   2640
97614  * tmap       3759         2886   2857   2827   2786
97615  * titer      2860         2865   2842   2842   2803
97616  * tsort      3816         3105   3104   3097   2936
97617  * dup        3456         3334   3332   3203   3003
97618  * tmac       3326         3317   3277   3247   3221
97619  * tset       3287         3253   3104   3207   3253
97620  * tio        3763         3816   3752   3738   3692
97621  * teq        4054         4068   4045   4038   3713
97622  * tfft       11.3         4142   4109   4107   4067
97623  * tstr       6755         5281   4863   4765   4543
97624  * tcase      4671         4960   4793   4669   4570
97625  * tclo       4949         4787   4735   4668   4588  4607
97626  * tlet       5762         7775   5640   5585   4632
97627  * tnum       59.4         6348   6013   5998   5860
97628  * trec       7763         5976   5970   5970   5969
97629  * tmisc      6506         7389   6210   6174   6167
97630  * tgc        12.5         11.9   11.1   11.0   10.7  10.4
97631  * tgen       12.3         11.2   11.4   11.3   11.3
97632  * thash      37.4         11.8   11.7   11.7   11.4
97633  * tall       26.9         15.6   15.6   15.6   15.6
97634  * calls      61.1         36.7   37.5   37.2   37.1
97635  * sg         98.6         71.9   72.3   72.2   72.7
97636  * lg        105.4        106.6  105.0  105.1  104.3
97637  * tbig      600.0        177.4  175.8  174.3  172.9  172.5
97638  * -----------------------------------------------------
97639  *
97640  * notcurses 2.1 diffs, use notcurses-core if 2.1.6 -- but this requires notcurses_core_init so nrepl needs to know which is loaded
97641  * check other symbol cases in s7-optimize [is_unchanged_global but also allow cur_val=init_val?  could this be the o_sc problem?]
97642  * g++ in t725, clang?
97643  * maybe case* built-in, but the syntax is not right yet
97644  * opts false, opt_print for return info
97645  * sigjmp_buf for *BSD
97646  */
97647