Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

75086 lines
2.2MB

  1. /* s7, a Scheme interpreter
  2. *
  3. * derived from:
  4. *
  5. * --------------------------------------------------------------------------------
  6. * T I N Y S C H E M E 1 . 3 9
  7. * Dimitrios Souflis (dsouflis@acm.org)
  8. * Based on MiniScheme (original credits follow)
  9. * (MINISCM) coded by Atsushi Moriwaki (11/5/1989)
  10. * (MINISCM) E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
  11. * (MINISCM) This version has been modified by R.C. Secrist.
  12. * (MINISCM)
  13. * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
  14. * (MINISCM)
  15. * (MINISCM) This is a revised and modified version by Akira KIDA.
  16. * (MINISCM) current version is 0.85k4 (15 May 1994)
  17. * --------------------------------------------------------------------------------
  18. *
  19. * apparently tinyScheme is under the BSD license, so I guess s7 is too.
  20. * Here is Snd's verbiage which can apply here:
  21. *
  22. * The authors hereby grant permission to use, copy, modify, distribute,
  23. * and license this software and its documentation for any purpose. No
  24. * written agreement, license, or royalty fee is required. Modifications
  25. * to this software may be copyrighted by their authors and need not
  26. * follow the licensing terms described here.
  27. *
  28. * followed by the usual all-caps shouting about liability.
  29. *
  30. * --------------------------------------------------------------------------------
  31. *
  32. * s7, Bill Schottstaedt, Aug-08, bil@ccrma.stanford.edu
  33. *
  34. * Mike Scholz provided the FreeBSD support (complex trig funcs, etc)
  35. * Rick Taube, Andrew Burnson, Donny Ward, and Greg Santucci provided the MS Visual C++ support
  36. *
  37. * Documentation is in s7.h and s7.html.
  38. * s7test.scm is a regression test.
  39. * glistener.c is a gtk-based listener.
  40. * repl.scm is a vt100-based listener.
  41. * cload.scm and lib*.scm tie in various C libraries.
  42. * lint.scm checks Scheme code for infelicities.
  43. * r7rs.scm implements some of r7rs (small).
  44. * write.scm currrently has pretty-print.
  45. * mockery.scm has the mock-data definitions.
  46. * stuff.scm has some stuff.
  47. *
  48. * s7.c is organized as follows:
  49. *
  50. * structs and type flags
  51. * constants
  52. * GC
  53. * stacks
  54. * symbols and keywords
  55. * environments
  56. * continuations
  57. * numbers
  58. * characters
  59. * strings
  60. * ports
  61. * format
  62. * lists
  63. * vectors
  64. * hash-tables
  65. * c-objects
  66. * functions
  67. * equal?
  68. * generic length, copy, reverse, fill!, append
  69. * error handlers
  70. * sundry leftovers
  71. * multiple-values, quasiquote
  72. * eval
  73. * multiprecision arithmetic
  74. * *s7* environment
  75. * initialization
  76. * repl
  77. *
  78. * naming conventions: s7_* usually are C accessible (s7.h), g_* are scheme accessible (FFI),
  79. * H_* are documentation strings, Q_* are procedure signatures,
  80. * *_1 are auxilliary functions, big_* refer to gmp,
  81. * scheme "?" corresponds to C "is_", scheme "->" to C "_to_".
  82. *
  83. * ---------------- compile time switches ----------------
  84. */
  85. #include "mus-config.h"
  86. /*
  87. * Your config file goes here, or just replace that #include line with the defines you need.
  88. * The compile-time switches involve booleans, complex numbers, and multiprecision arithmetic.
  89. * Currently we assume we have setjmp.h (used by the error handlers).
  90. *
  91. * Complex number support which is problematic in C++, Solaris, and netBSD
  92. * is on the HAVE_COMPLEX_NUMBERS switch. In OSX or Linux, if you're not using C++,
  93. *
  94. * #define HAVE_COMPLEX_NUMBERS 1
  95. * #define HAVE_COMPLEX_TRIG 1
  96. *
  97. * In C++ I use:
  98. *
  99. * #define HAVE_COMPLEX_NUMBERS 1
  100. * #define HAVE_COMPLEX_TRIG 0
  101. *
  102. * In windows, both are 0.
  103. *
  104. * Some systems (FreeBSD) have complex.h, but some random subset of the trig funcs, so
  105. * HAVE_COMPLEX_NUMBERS means we can find
  106. * cimag creal cabs csqrt carg conj
  107. * and HAVE_COMPLEX_TRIG means we have
  108. * cacos cacosh casin casinh catan catanh ccos ccosh cexp clog cpow csin csinh ctan ctanh
  109. *
  110. * When HAVE_COMPLEX_NUMBERS is 0, the complex functions are stubs that simply return their
  111. * argument -- this will be very confusing for the s7 user because, for example, (sqrt -2)
  112. * will return something bogus (it will not signal an error).
  113. *
  114. * so the incoming (non-s7-specific) compile-time switches are
  115. * HAVE_COMPLEX_NUMBERS, HAVE_COMPLEX_TRIG, SIZEOF_VOID_P
  116. * if SIZEOF_VOID_P is not defined, we look for __SIZEOF_POINTER__ instead
  117. * the default is to assume that we're running on a 64-bit machine.
  118. *
  119. * To get multiprecision arithmetic, set WITH_GMP to 1.
  120. * You'll also need libgmp, libmpfr, and libmpc (version 0.8.0 or later)
  121. * In highly numerical contexts, the gmp version of s7 is about 50(!) times slower than the non-gmp version.
  122. *
  123. * and we use these predefined macros: __cplusplus, _MSC_VER, __GNUC__, __clang__, __ANDROID__
  124. *
  125. * if WITH_SYSTEM_EXTRAS is 1 (default is 1 unless _MSC_VER), various OS and file related functions are included.
  126. * in openBSD I think you need to include -ftrampolines in CFLAGS.
  127. * if you want this file to compile into a stand-alone interpreter, define WITH_MAIN
  128. *
  129. * -O3 is sometimes slower, sometimes faster
  130. * -march=native -fomit-frame-pointer -m64 -funroll-loops gains about .1%
  131. * -ffast-math makes a mess of NaNs, and does not appear to be faster
  132. * for timing tests, I use: -O2 -DINITIAL_HEAP_SIZE=1024000 -march=native -fomit-frame-pointer -funroll-loops
  133. */
  134. /* ---------------- initial sizes ---------------- */
  135. #ifndef INITIAL_HEAP_SIZE
  136. #define INITIAL_HEAP_SIZE 128000
  137. /* the heap grows as needed, this is its initial size.
  138. * If the initial heap is small, s7 can run in about 2.5 Mbytes of memory. There are (many) cases where a bigger heap is faster.
  139. * The heap size must be a multiple of 32. Each object takes about 50 bytes.
  140. *
  141. * repl runs in 4Mb (18v) (64bit) if heap is 8192
  142. * 11Mb (25v) if 128k heap
  143. * snd (no gui) 15Mb (151v)
  144. * snd (motif) 12Mb (285v)
  145. * snd (gtk) 32Mb (515v!)
  146. */
  147. #endif
  148. #ifndef SYMBOL_TABLE_SIZE
  149. #define SYMBOL_TABLE_SIZE 13567
  150. /* names are hashed into the symbol table (a vector) and collisions are chained as lists.
  151. */
  152. #endif
  153. #define INITIAL_STACK_SIZE 512
  154. /* the stack grows as needed, each frame takes 4 entries, this is its initial size.
  155. * this needs to be big enough to handle the eval_c_string's at startup (ca 100)
  156. * In s7test.scm, the maximum stack size is ca 440. In snd-test.scm, it's ca 200.
  157. * This number matters only because call/cc copies the stack, which requires filling
  158. * the unused portion of the new stack, which requires memcpy of #<unspecified>'s.
  159. */
  160. #define INITIAL_PROTECTED_OBJECTS_SIZE 16
  161. /* a vector of objects that are (semi-permanently) protected from the GC, grows as needed */
  162. #define GC_TEMPS_SIZE 256
  163. /* the number of recent objects that are temporarily gc-protected; 8 works for s7test and snd-test.
  164. * For the FFI, this sets the lag between a call on s7_cons and the first moment when its result
  165. * might be vulnerable to the GC.
  166. */
  167. /* ---------------- scheme choices ---------------- */
  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, bignum?, bignum-precision
  172. * using gmp with precision=128 is about 50 times slower than using C doubles and long long ints.
  173. */
  174. #endif
  175. #if WITH_GMP
  176. #define DEFAULT_BIGNUM_PRECISION 128
  177. #endif
  178. #ifndef WITH_PURE_S7
  179. #define WITH_PURE_S7 0
  180. #endif
  181. #if WITH_PURE_S7
  182. #define WITH_EXTRA_EXPONENT_MARKERS 0
  183. #define WITH_IMMUTABLE_UNQUOTE 1
  184. /* also omitted: *-ci* functions, char-ready?, cond-expand, multiple-values-bind|set!, call-with-values, defmacro(*)
  185. * and a lot more (inexact/exact, integer-length, etc) -- see s7.html.
  186. */
  187. #endif
  188. #ifndef WITH_EXTRA_EXPONENT_MARKERS
  189. #define WITH_EXTRA_EXPONENT_MARKERS 0
  190. /* if 1, s7 recognizes "d", "f", "l", and "s" as exponent markers, in addition to "e" (also "D", "F", "L", "S") */
  191. #endif
  192. #ifndef WITH_SYSTEM_EXTRAS
  193. #define WITH_SYSTEM_EXTRAS (!_MSC_VER)
  194. /* this adds several functions that access file info, directories, times, etc
  195. * this may be replaced by the cload business below
  196. */
  197. #endif
  198. #ifndef WITH_IMMUTABLE_UNQUOTE
  199. #define WITH_IMMUTABLE_UNQUOTE 0
  200. /* this removes the name "unquote" */
  201. #endif
  202. #ifndef WITH_C_LOADER
  203. #define WITH_C_LOADER WITH_GCC
  204. /* (load file.so [e]) looks for (e 'init_func) and if found, calls it
  205. * as the shared object init function. If WITH_SYSTEM_EXTRAS is 0, the caller
  206. * needs to supply system and delete-file so that cload.scm works.
  207. */
  208. #endif
  209. #ifndef WITH_HISTORY
  210. #define WITH_HISTORY 0
  211. /* this includes a circular buffer of previous evaluations for debugging, ((owlet) 'error-history) and (*s7* 'history-size) */
  212. #endif
  213. #ifndef DEFAULT_HISTORY_SIZE
  214. #define DEFAULT_HISTORY_SIZE 8
  215. /* this is the default length of the eval history buffer */
  216. #endif
  217. #ifndef WITH_PROFILE
  218. #define WITH_PROFILE 0
  219. /* this includes profiling data collection accessible from scheme via the hash-table (*s7* 'profile-info) */
  220. #endif
  221. #define WITH_GCC (defined(__GNUC__) || defined(__clang__))
  222. /* in case mus-config.h forgets these */
  223. #ifdef _MSC_VER
  224. #ifndef HAVE_COMPLEX_NUMBERS
  225. #define HAVE_COMPLEX_NUMBERS 0
  226. #endif
  227. #ifndef HAVE_COMPLEX_TRIG
  228. #define HAVE_COMPLEX_TRIG 0
  229. #endif
  230. #else
  231. #ifndef HAVE_COMPLEX_NUMBERS
  232. #define HAVE_COMPLEX_NUMBERS 1
  233. #endif
  234. #if __cplusplus
  235. #ifndef HAVE_COMPLEX_TRIG
  236. #define HAVE_COMPLEX_TRIG 0
  237. #endif
  238. #else
  239. #ifndef HAVE_COMPLEX_TRIG
  240. #define HAVE_COMPLEX_TRIG 1
  241. #endif
  242. #endif
  243. #endif
  244. /* -------------------------------------------------------------------------------- */
  245. #ifndef DEBUGGING
  246. #define DEBUGGING 0
  247. #endif
  248. #ifndef OP_NAMES
  249. #define OP_NAMES 0
  250. #endif
  251. #define WITH_ADD_PF 0
  252. #ifndef _MSC_VER
  253. #include <unistd.h>
  254. #include <sys/param.h>
  255. #include <strings.h>
  256. #include <errno.h>
  257. #include <locale.h>
  258. #else
  259. /* in Snd these are in mus-config.h */
  260. #ifndef MUS_CONFIG_H_LOADED
  261. #define snprintf _snprintf
  262. #if _MSC_VER > 1200
  263. #define _CRT_SECURE_NO_DEPRECATE 1
  264. #define _CRT_NONSTDC_NO_DEPRECATE 1
  265. #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
  266. #endif
  267. #endif
  268. #include <io.h>
  269. #pragma warning(disable: 4244)
  270. #endif
  271. #include <limits.h>
  272. #include <ctype.h>
  273. #include <string.h>
  274. #include <stdlib.h>
  275. #include <sys/types.h>
  276. #include <time.h>
  277. #include <stdarg.h>
  278. #include <stddef.h>
  279. #if __cplusplus
  280. #include <cmath>
  281. #else
  282. #include <math.h>
  283. #endif
  284. #if HAVE_COMPLEX_NUMBERS
  285. #if __cplusplus
  286. #include <complex>
  287. #else
  288. #include <complex.h>
  289. #ifndef __SUNPRO_C
  290. #if defined(__sun) && defined(__SVR4)
  291. #undef _Complex_I
  292. #define _Complex_I 1.0fi
  293. #endif
  294. #endif
  295. #endif
  296. #ifndef CMPLX
  297. /* c11 addition? */
  298. #define CMPLX(r, i) ((r) + ((i) * _Complex_I))
  299. #endif
  300. #endif
  301. #include <setjmp.h>
  302. #include "s7.h"
  303. enum {NO_JUMP, CALL_WITH_EXIT_JUMP, THROW_JUMP, CATCH_JUMP, ERROR_JUMP, ERROR_QUIT_JUMP};
  304. enum {NO_SET_JUMP, READ_SET_JUMP, LOAD_SET_JUMP, DYNAMIC_WIND_SET_JUMP, S7_CALL_SET_JUMP, EVAL_SET_JUMP};
  305. #ifndef M_PI
  306. #define M_PI 3.1415926535897932384626433832795029L
  307. #endif
  308. #ifndef INFINITY
  309. #define INFINITY (-log(0.0))
  310. /* 1.0 / 0.0 is also used, there is sometimes a function, infinity(), MSC apparently uses HUGE_VALF */
  311. #endif
  312. #ifndef NAN
  313. #define NAN (INFINITY / INFINITY)
  314. #endif
  315. #define BOLD_TEXT "\033[1m"
  316. #define UNBOLD_TEXT "\033[22m"
  317. #define WRITE_REAL_PRECISION 16
  318. static int float_format_precision = WRITE_REAL_PRECISION;
  319. #if ((!__NetBSD__) && ((_MSC_VER) || (!defined(__STC__)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L))))
  320. #define __func__ __FUNCTION__
  321. #endif
  322. #define DISPLAY(Obj) s7_object_to_c_string(sc, Obj)
  323. #define DISPLAY_80(Obj) object_to_truncated_string(sc, Obj, 80)
  324. #if (((defined(SIZEOF_VOID_P)) && (SIZEOF_VOID_P == 4)) || ((defined(__SIZEOF_POINTER__)) && (__SIZEOF_POINTER__ == 4)))
  325. #define opcode_t unsigned int
  326. #define PRINT_NAME_PADDING 8
  327. #define PRINT_NAME_SIZE (20 - PRINT_NAME_PADDING - 2)
  328. #define ptr_int unsigned int
  329. #define INT_FORMAT "%u"
  330. #ifndef WITH_OPTIMIZATION
  331. #define WITH_OPTIMIZATION 0
  332. /* 32-bit optimized case gets inexplicable NaNs in float-vector ops.
  333. * only the rf cases are faulty, so it is possible to set this flag to 1, then make s7_rf_set_function a no-op,
  334. * and comment out the 2 syntax_rp cases.
  335. * In standard scheme code, this flag does not matter much, but it makes CLM run about 3 times as fast.
  336. */
  337. #endif
  338. #else
  339. #define opcode_t unsigned long long int
  340. #define ptr_int unsigned long long int
  341. #define INT_FORMAT "%llu"
  342. #define PRINT_NAME_PADDING 16
  343. #define PRINT_NAME_SIZE (40 - PRINT_NAME_PADDING - 2)
  344. #ifndef WITH_OPTIMIZATION
  345. #define WITH_OPTIMIZATION 1
  346. #endif
  347. #endif
  348. /* types */
  349. #define T_FREE 0
  350. #define T_PAIR 1
  351. #define T_NIL 2
  352. #define T_UNIQUE 3
  353. #define T_UNSPECIFIED 4
  354. #define T_BOOLEAN 5
  355. #define T_CHARACTER 6
  356. #define T_SYMBOL 7
  357. #define T_SYNTAX 8
  358. #define T_INTEGER 9
  359. #define T_RATIO 10
  360. #define T_REAL 11
  361. #define T_COMPLEX 12
  362. #define T_BIG_INTEGER 13 /* these four used only if WITH_GMP -- order matters */
  363. #define T_BIG_RATIO 14
  364. #define T_BIG_REAL 15
  365. #define T_BIG_COMPLEX 16
  366. #define T_STRING 17
  367. #define T_C_OBJECT 18
  368. #define T_VECTOR 19
  369. #define T_INT_VECTOR 20
  370. #define T_FLOAT_VECTOR 21
  371. #define T_CATCH 22
  372. #define T_DYNAMIC_WIND 23
  373. #define T_HASH_TABLE 24
  374. #define T_LET 25
  375. #define T_ITERATOR 26
  376. #define T_STACK 27
  377. #define T_COUNTER 28
  378. #define T_SLOT 29
  379. #define T_C_POINTER 30
  380. #define T_OUTPUT_PORT 31
  381. #define T_INPUT_PORT 32
  382. #define T_BAFFLE 33
  383. #define T_RANDOM_STATE 34
  384. #define T_GOTO 35
  385. #define T_CONTINUATION 36
  386. #define T_CLOSURE 37
  387. #define T_CLOSURE_STAR 38
  388. #define T_C_MACRO 39
  389. #define T_MACRO 40
  390. #define T_MACRO_STAR 41
  391. #define T_BACRO 42
  392. #define T_BACRO_STAR 43
  393. #define T_C_FUNCTION_STAR 44
  394. #define T_C_FUNCTION 45
  395. #define T_C_ANY_ARGS_FUNCTION 46
  396. #define T_C_OPT_ARGS_FUNCTION 47
  397. #define T_C_RST_ARGS_FUNCTION 48
  398. #define NUM_TYPES 49
  399. /* T_STACK, T_SLOT, T_BAFFLE, T_DYNAMIC_WIND, and T_COUNTER are internal
  400. * I tried T_CASE_SELECTOR that turned a case statement into an array, but it was slower!
  401. */
  402. typedef enum {TOKEN_EOF, TOKEN_LEFT_PAREN, TOKEN_RIGHT_PAREN, TOKEN_DOT, TOKEN_ATOM, TOKEN_QUOTE, TOKEN_DOUBLE_QUOTE,
  403. TOKEN_BACK_QUOTE, TOKEN_COMMA, TOKEN_AT_MARK, TOKEN_SHARP_CONST,
  404. TOKEN_VECTOR, TOKEN_BYTE_VECTOR} token_t;
  405. typedef enum {FILE_PORT, STRING_PORT, FUNCTION_PORT} port_type_t;
  406. typedef struct {
  407. bool needs_free;
  408. FILE *file;
  409. char *filename;
  410. int filename_length, gc_loc;
  411. void *next;
  412. s7_pointer (*input_function)(s7_scheme *sc, s7_read_t read_choice, s7_pointer port);
  413. void (*output_function)(s7_scheme *sc, unsigned char c, s7_pointer port);
  414. /* a version of string ports using a pointer to the current location and a pointer to the end
  415. * (rather than an integer for both, indexing from the base string) was not faster.
  416. */
  417. s7_pointer orig_str; /* GC protection for string port string */
  418. int (*read_character)(s7_scheme *sc, s7_pointer port); /* function to read a character */
  419. void (*write_character)(s7_scheme *sc, int c, s7_pointer port); /* function to write a character */
  420. void (*write_string)(s7_scheme *sc, const char *str, int len, s7_pointer port); /* function to write a string of known length */
  421. token_t (*read_semicolon)(s7_scheme *sc, s7_pointer port); /* internal skip-to-semicolon reader */
  422. int (*read_white_space)(s7_scheme *sc, s7_pointer port); /* internal skip white space reader */
  423. s7_pointer (*read_name)(s7_scheme *sc, s7_pointer pt); /* internal get-next-name reader */
  424. s7_pointer (*read_sharp)(s7_scheme *sc, s7_pointer pt); /* internal get-next-sharp-constant reader */
  425. s7_pointer (*read_line)(s7_scheme *sc, s7_pointer pt, bool eol_case, bool copied); /* function to read a string up to \n */
  426. void (*display)(s7_scheme *sc, const char *s, s7_pointer pt);
  427. } port_t;
  428. typedef struct {
  429. const char *name;
  430. int name_length;
  431. unsigned int id;
  432. char *doc;
  433. s7_pointer generic_ff;
  434. s7_pointer signature;
  435. s7_pointer (*chooser)(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr);
  436. s7_pointer *arg_defaults, *arg_names;
  437. s7_pointer call_args;
  438. s7_rp_t rp;
  439. s7_ip_t ip;
  440. s7_pp_t pp, gp;
  441. } c_proc_t;
  442. typedef struct { /* call/cc */
  443. unsigned int stack_size, op_stack_loc, op_stack_size;
  444. int local_key; /* for with-baffle */
  445. } continuation_t;
  446. typedef struct vdims_t {
  447. unsigned int ndims;
  448. bool elements_allocated, dimensions_allocated; /* these are allocated as bytes, not ints, so the struct size is 32 */
  449. s7_int *dims, *offsets;
  450. s7_pointer original;
  451. } vdims_t;
  452. typedef struct {
  453. int type;
  454. unsigned int outer_type;
  455. const char *name;
  456. s7_pointer scheme_name;
  457. char *(*print)(s7_scheme *sc, void *value);
  458. void (*free)(void *value);
  459. bool (*equal)(void *val1, void *val2);
  460. void (*gc_mark)(void *val);
  461. s7_pointer (*ref)(s7_scheme *sc, s7_pointer obj, s7_pointer args);
  462. s7_pointer (*set)(s7_scheme *sc, s7_pointer obj, s7_pointer args);
  463. s7_pointer (*length)(s7_scheme *sc, s7_pointer obj);
  464. s7_pointer (*copy)(s7_scheme *sc, s7_pointer args);
  465. s7_pointer (*reverse)(s7_scheme *sc, s7_pointer obj);
  466. s7_pointer (*fill)(s7_scheme *sc, s7_pointer args);
  467. char *(*print_readably)(s7_scheme *sc, void *value);
  468. s7_pointer (*direct_ref)(s7_scheme *sc, s7_pointer obj, s7_int index);
  469. s7_pointer (*direct_set)(s7_scheme *sc, s7_pointer obj, s7_int index, s7_pointer val);
  470. s7_ip_t ip, set_ip;
  471. s7_rp_t rp, set_rp;
  472. } c_object_t;
  473. typedef struct hash_entry_t {
  474. s7_pointer key, value;
  475. struct hash_entry_t *next;
  476. unsigned int raw_hash;
  477. } hash_entry_t;
  478. typedef unsigned int (*hash_map_t)(s7_scheme *sc, s7_pointer table, s7_pointer key); /* hash-table object->location mapper */
  479. typedef hash_entry_t *(*hash_check_t)(s7_scheme *sc, s7_pointer table, s7_pointer key); /* hash-table object equality function */
  480. static hash_map_t *default_hash_map;
  481. /* cell structure */
  482. typedef struct s7_cell {
  483. union {
  484. unsigned int flag;
  485. unsigned char type_field;
  486. unsigned short sflag;
  487. } tf;
  488. int hloc;
  489. union {
  490. union {
  491. s7_int integer_value;
  492. s7_double real_value;
  493. struct {
  494. char padding[PRINT_NAME_PADDING];
  495. char name[PRINT_NAME_SIZE + 2];
  496. } pval;
  497. struct {
  498. s7_int numerator;
  499. s7_int denominator;
  500. } fraction_value;
  501. struct {
  502. s7_double rl;
  503. s7_double im;
  504. } complex_value;
  505. unsigned long ul_value; /* these two are not used by s7 in any way */
  506. unsigned long long ull_value;
  507. #if WITH_GMP
  508. mpz_t big_integer;
  509. mpq_t big_ratio;
  510. mpfr_t big_real;
  511. mpc_t big_complex;
  512. /* using free_lists here was not faster, and avoiding the extra init/clear too tricky. These make up
  513. * no more than ca. 5% of the gmp computation -- it is totally dominated by stuff like __gmpz_mul,
  514. * so I can't see much point in optimizing the background noise. In a very numerical context,
  515. * gmp slows us down by a factor of 50.
  516. */
  517. #endif
  518. } number;
  519. struct {
  520. port_t *port;
  521. unsigned char *data;
  522. unsigned int size, point; /* these limit the in-core portion of a string-port to 2^31 bytes */
  523. unsigned int line_number, file_number;
  524. bool is_closed;
  525. port_type_t ptype;
  526. } prt;
  527. struct{
  528. unsigned char c, up_c;
  529. int length;
  530. bool alpha_c, digit_c, space_c, upper_c, lower_c;
  531. char c_name[12];
  532. } chr;
  533. void *c_pointer;
  534. int baffle_key;
  535. struct {
  536. s7_int length;
  537. union {
  538. s7_pointer *objects;
  539. s7_int *ints;
  540. s7_double *floats;
  541. } elements;
  542. vdims_t *dim_info;
  543. s7_pointer (*vget)(s7_scheme *sc, s7_pointer vec, s7_int loc);
  544. s7_pointer (*vset)(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val);
  545. } vector;
  546. struct {
  547. s7_int length;
  548. s7_pointer *objects;
  549. vdims_t *dim_info;
  550. int top;
  551. } stk;
  552. struct {
  553. unsigned int mask, entries;
  554. hash_entry_t **elements;
  555. hash_check_t hash_func;
  556. hash_map_t *loc;
  557. s7_pointer dproc;
  558. } hasher;
  559. struct {
  560. s7_pointer obj, cur;
  561. union {
  562. s7_int loc;
  563. s7_pointer lcur;
  564. } lc;
  565. union {
  566. s7_int len;
  567. s7_pointer slow;
  568. hash_entry_t *hcur;
  569. } lw;
  570. s7_pointer (*next)(s7_scheme *sc, s7_pointer iterator);
  571. } iter;
  572. struct {
  573. c_proc_t *c_proc; /* C functions, macros */
  574. s7_function ff;
  575. s7_pointer setter;
  576. unsigned int required_args, optional_args, all_args;
  577. bool rest_arg;
  578. } fnc;
  579. struct { /* pairs */
  580. s7_pointer car, cdr, opt1, opt2, opt3;
  581. } cons;
  582. struct {
  583. s7_pointer sym_car, sym_cdr;
  584. unsigned long long int hash;
  585. const char *fstr;
  586. unsigned int op, line;
  587. } sym_cons;
  588. struct {
  589. s7_pointer args, body, env, setter;
  590. int arity;
  591. } func;
  592. struct {
  593. unsigned int length;
  594. union {
  595. bool needs_free;
  596. int accessor;
  597. } str_ext;
  598. char *svalue;
  599. unsigned long long int hash; /* string hash-index */
  600. s7_pointer initial_slot;
  601. union {
  602. char *documentation;
  603. s7_pointer ksym;
  604. } doc;
  605. } string;
  606. struct { /* symbols */
  607. s7_pointer name, global_slot, local_slot;
  608. long long int id;
  609. unsigned int op, tag;
  610. } sym;
  611. struct { /* syntax */
  612. s7_pointer symbol;
  613. int op;
  614. short min_args, max_args;
  615. s7_rp_t rp;
  616. s7_ip_t ip;
  617. s7_pp_t pp;
  618. } syn;
  619. struct { /* slots (bindings) */
  620. s7_pointer sym, val, nxt, pending_value, expr;
  621. } slt;
  622. struct { /* environments (frames) */
  623. s7_pointer slots, nxt;
  624. long long int id; /* id of rootlet is -1 */
  625. union {
  626. struct {
  627. s7_pointer function; /* __func__ (code) if this is a funclet */
  628. unsigned int line, file; /* __func__ location if it is known */
  629. } efnc;
  630. struct {
  631. s7_pointer dox1, dox2; /* do loop variables */
  632. } dox;
  633. struct { /* (catch #t ...) opts */
  634. s7_pointer result;
  635. unsigned int op_stack_loc, goto_loc;
  636. } ctall;
  637. } edat;
  638. } envr;
  639. struct {
  640. /* these 3 are just place-holders */
  641. s7_pointer unused_slots, unused_nxt;
  642. long long int unused_id;
  643. /* these two fields are for some special case objects like #<unspecified> */
  644. const char *name;
  645. int len;
  646. } unq;
  647. struct { /* counter (internal) */
  648. s7_pointer result, list, env, slots; /* env = counter_let (curlet after map/for-each frame created) */
  649. unsigned long long int cap; /* sc->capture_let_counter for frame reuse */
  650. } ctr;
  651. struct {
  652. #if WITH_GMP
  653. gmp_randstate_t state;
  654. #else
  655. unsigned long long int seed, carry;
  656. #endif
  657. } rng;
  658. struct { /* additional object types (C) */
  659. int type;
  660. void *value; /* the value the caller associates with the object */
  661. s7_pointer e; /* the method list, if any (openlet) */
  662. s7_pointer (*ref)(s7_scheme *sc, s7_pointer obj, s7_int pos);
  663. } c_obj;
  664. struct {
  665. continuation_t *continuation;
  666. s7_pointer stack;
  667. s7_pointer *stack_start, *stack_end, *op_stack;
  668. } cwcc;
  669. struct { /* call-with-exit */
  670. unsigned int goto_loc, op_stack_loc;
  671. bool active;
  672. } rexit;
  673. struct { /* catch */
  674. unsigned int goto_loc, op_stack_loc;
  675. s7_pointer tag;
  676. s7_pointer handler;
  677. } rcatch; /* C++ reserves "catch" I guess */
  678. struct { /* dynamic-wind */
  679. s7_pointer in, out, body;
  680. unsigned int state;
  681. } winder;
  682. } object;
  683. #if DEBUGGING
  684. int current_alloc_line, previous_alloc_line, current_alloc_type, previous_alloc_type, debugger_bits, gc_line, clear_line, alloc_line, uses;
  685. const char *current_alloc_func, *previous_alloc_func, *gc_func, *alloc_func;
  686. #endif
  687. } s7_cell;
  688. typedef struct {
  689. s7_pointer *objs;
  690. int size, top, ref;
  691. bool has_hits;
  692. int *refs;
  693. } shared_info;
  694. typedef struct {
  695. int loc, curly_len, ctr;
  696. char *curly_str;
  697. s7_pointer args, orig_str, curly_arg;
  698. s7_pointer port, strport;
  699. } format_data;
  700. typedef struct gc_obj {
  701. s7_pointer p;
  702. struct gc_obj *nxt;
  703. } gc_obj;
  704. typedef struct xf_t {
  705. s7_pointer *data, *cur, *end;
  706. s7_pointer e;
  707. int size;
  708. gc_obj *gc_list;
  709. struct xf_t *next;
  710. } xf_t;
  711. static s7_pointer *small_ints, *chars;
  712. static s7_pointer real_zero, real_NaN, real_pi, real_one, arity_not_set, max_arity, real_infinity, real_minus_infinity, minus_one, minus_two;
  713. struct s7_scheme {
  714. opcode_t op; /* making this global is much slower! */
  715. s7_pointer value;
  716. s7_pointer args; /* arguments of current function */
  717. s7_pointer code, cur_code; /* current code */
  718. s7_pointer envir; /* curlet */
  719. token_t tok;
  720. s7_pointer stack; /* stack is a vector */
  721. unsigned int stack_size;
  722. s7_pointer *stack_start, *stack_end, *stack_resize_trigger;
  723. s7_pointer *op_stack, *op_stack_now, *op_stack_end;
  724. unsigned int op_stack_size, max_stack_size;
  725. s7_cell **heap, **free_heap, **free_heap_top, **free_heap_trigger, **previous_free_heap_top;
  726. unsigned int heap_size;
  727. int gc_freed;
  728. #if WITH_HISTORY
  729. s7_pointer eval_history1, eval_history2, error_history;
  730. bool using_history1;
  731. #endif
  732. /* "int" or "unsigned int" seems safe here:
  733. * sizeof(s7_cell) = 48 bytes
  734. * so to get more than 2^32 actual objects would require ca 206 GBytes RAM
  735. * vectors might be full of the same object (sc->nil for example), so there
  736. * we need ca 38 GBytes RAM (8 bytes per pointer).
  737. */
  738. gc_obj *permanent_objects;
  739. s7_pointer protected_objects, protected_accessors; /* a vector of gc-protected objects */
  740. unsigned int *gpofl;
  741. unsigned int protected_objects_size, protected_accessors_size, protected_accessors_loc;
  742. int gpofl_loc;
  743. s7_pointer nil; /* empty list */
  744. s7_pointer T; /* #t */
  745. s7_pointer F; /* #f */
  746. s7_pointer eof_object; /* #<eof> */
  747. s7_pointer undefined; /* #<undefined> */
  748. s7_pointer unspecified; /* #<unspecified> */
  749. s7_pointer no_value; /* the (values) value */
  750. s7_pointer else_object; /* else */
  751. s7_pointer gc_nil; /* a marker for an unoccupied slot in sc->protected_objects (and other similar stuff) */
  752. s7_pointer symbol_table; /* symbol table */
  753. s7_pointer rootlet, shadow_rootlet; /* rootlet */
  754. s7_int rootlet_entries;
  755. s7_pointer unlet; /* original bindings of predefined functions */
  756. s7_pointer input_port; /* current-input-port */
  757. s7_pointer input_port_stack; /* input port stack (load and read internally) */
  758. s7_pointer output_port; /* current-output-port */
  759. s7_pointer error_port; /* current-error-port */
  760. s7_pointer owlet; /* owlet */
  761. s7_pointer error_type, error_data, error_code, error_line, error_file; /* owlet slots */
  762. s7_pointer standard_input, standard_output, standard_error;
  763. s7_pointer sharp_readers; /* the binding pair for the global *#readers* list */
  764. s7_pointer load_hook; /* *load-hook* hook object */
  765. s7_pointer unbound_variable_hook; /* *unbound-variable-hook* hook object */
  766. s7_pointer missing_close_paren_hook;
  767. s7_pointer error_hook, read_error_hook; /* *error-hook* hook object, and *read-error-hook* */
  768. s7_pointer direct_str;
  769. bool gc_off; /* gc_off: if true, the GC won't run */
  770. unsigned int gc_stats;
  771. unsigned int gensym_counter, cycle_counter, f_class, add_class, multiply_class, subtract_class, equal_class;
  772. int format_column;
  773. unsigned long long int capture_let_counter;
  774. bool symbol_table_is_locked, short_print;
  775. long long int let_number;
  776. double default_rationalize_error, morally_equal_float_epsilon, hash_table_float_epsilon;
  777. s7_int default_hash_table_length, initial_string_port_length, print_length, history_size, true_history_size;
  778. s7_int max_vector_length, max_string_length, max_list_length, max_vector_dimensions;
  779. s7_pointer stacktrace_defaults;
  780. vdims_t *wrap_only;
  781. char *typnam;
  782. int typnam_len;
  783. char *help_arglist;
  784. int print_width;
  785. s7_pointer *singletons;
  786. #define INITIAL_TMP_STR_SIZE 16
  787. s7_pointer *tmp_strs;
  788. #define INITIAL_FILE_NAMES_SIZE 8
  789. s7_pointer *file_names;
  790. int file_names_size, file_names_top;
  791. #define INITIAL_STRBUF_SIZE 1024
  792. unsigned int strbuf_size;
  793. #define TMPBUF_SIZE 1024
  794. char *strbuf, *tmpbuf;
  795. char *read_line_buf;
  796. unsigned int read_line_buf_size;
  797. s7_pointer v, w, x, y, z; /* evaluator local vars */
  798. s7_pointer temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10;
  799. s7_pointer temp_cell, temp_cell_1, temp_cell_2;
  800. s7_pointer d1, d2, d3, d4;
  801. s7_pointer t1_1, t2_1, t2_2, t3_1, t3_2, t3_3, z2_1, z2_2;
  802. s7_pointer a1_1, a2_1, a2_2, a3_1, a3_2, a3_3, a4_1, a4_2, a4_3, a4_4;
  803. jmp_buf goto_start;
  804. bool longjmp_ok;
  805. int setjmp_loc;
  806. void (*begin_hook)(s7_scheme *sc, bool *val);
  807. int no_values, current_line, s7_call_line, safety;
  808. const char *current_file, *s7_call_file, *s7_call_name;
  809. shared_info *circle_info;
  810. format_data **fdats;
  811. int num_fdats;
  812. s7_pointer elist_1, elist_2, elist_3, elist_4, elist_5, plist_1, plist_2, plist_3;
  813. s7_pointer *strings, *vectors, *input_ports, *output_ports, *continuations, *c_objects, *hash_tables, *gensyms, *setters;
  814. unsigned int strings_size, vectors_size, input_ports_size, output_ports_size, continuations_size, c_objects_size, hash_tables_size, gensyms_size, setters_size;
  815. unsigned int strings_loc, vectors_loc, input_ports_loc, output_ports_loc, continuations_loc, c_objects_loc, hash_tables_loc, gensyms_loc, setters_loc;
  816. unsigned int syms_tag;
  817. int ht_iter_tag, baffle_ctr, bignum_precision;
  818. s7_pointer default_rng;
  819. /* these symbols are primarily for the generic function search */
  820. s7_pointer abs_symbol, acos_symbol, acosh_symbol, add_symbol, angle_symbol, append_symbol, apply_symbol, arity_symbol,
  821. ash_symbol, asin_symbol, asinh_symbol, assoc_symbol, assq_symbol, assv_symbol, atan_symbol, atanh_symbol,
  822. autoload_symbol, autoloader_symbol,
  823. byte_vector_symbol,
  824. c_pointer_symbol, caaaar_symbol, caaadr_symbol, caaar_symbol, caadar_symbol, caaddr_symbol, caadr_symbol,
  825. caar_symbol, cadaar_symbol, cadadr_symbol, cadar_symbol, caddar_symbol, cadddr_symbol, caddr_symbol, cadr_symbol,
  826. call_cc_symbol, call_with_current_continuation_symbol, call_with_exit_symbol, call_with_input_file_symbol,
  827. call_with_input_string_symbol, call_with_output_file_symbol, call_with_output_string_symbol, car_symbol,
  828. catch_symbol, cdaaar_symbol, cdaadr_symbol, cdaar_symbol, cdadar_symbol, cdaddr_symbol, cdadr_symbol, cdar_symbol,
  829. cddaar_symbol, cddadr_symbol, cddar_symbol, cdddar_symbol, cddddr_symbol, cdddr_symbol, cddr_symbol, cdr_symbol,
  830. ceiling_symbol, char_downcase_symbol, char_eq_symbol, char_geq_symbol, char_gt_symbol, char_leq_symbol, char_lt_symbol,
  831. char_position_symbol, char_to_integer_symbol, char_upcase_symbol, cload_directory_symbol, close_input_port_symbol,
  832. close_output_port_symbol, complex_symbol, cons_symbol, copy_symbol, cos_symbol, cosh_symbol, coverlet_symbol,
  833. curlet_symbol, current_error_port_symbol, current_input_port_symbol, current_output_port_symbol, cutlet_symbol,
  834. denominator_symbol, dilambda_symbol, display_symbol, divide_symbol, dynamic_wind_symbol,
  835. eq_symbol, error_symbol, eval_string_symbol, eval_symbol, exact_to_inexact_symbol, exp_symbol, expt_symbol,
  836. features_symbol, fill_symbol, float_vector_ref_symbol, float_vector_set_symbol, float_vector_symbol, floor_symbol,
  837. flush_output_port_symbol, for_each_symbol, format_symbol, funclet_symbol,
  838. gc_symbol, gcd_symbol, gensym_symbol, geq_symbol, get_output_string_symbol, gt_symbol,
  839. hash_table_entries_symbol, hash_table_ref_symbol, hash_table_set_symbol, hash_table_star_symbol, hash_table_symbol,
  840. help_symbol,
  841. imag_part_symbol, inexact_to_exact_symbol, inlet_symbol, int_vector_ref_symbol, int_vector_set_symbol, int_vector_symbol,
  842. integer_decode_float_symbol, integer_to_char_symbol, is_aritable_symbol, is_boolean_symbol, is_byte_vector_symbol,
  843. is_c_object_symbol, is_c_pointer_symbol, is_char_alphabetic_symbol, is_char_lower_case_symbol, is_char_numeric_symbol,
  844. is_char_symbol, is_char_upper_case_symbol, is_char_whitespace_symbol, is_complex_symbol, is_constant_symbol,
  845. is_continuation_symbol, is_defined_symbol, is_dilambda_symbol, is_eof_object_symbol, is_eq_symbol, is_equal_symbol,
  846. is_eqv_symbol, is_even_symbol, is_exact_symbol, is_float_vector_symbol, is_gensym_symbol, is_hash_table_symbol,
  847. is_inexact_symbol, is_infinite_symbol, is_input_port_symbol, is_int_vector_symbol, is_integer_symbol, is_iterator_symbol,
  848. is_keyword_symbol, is_let_symbol, is_list_symbol, is_macro_symbol, is_morally_equal_symbol, is_nan_symbol, is_negative_symbol,
  849. is_null_symbol, is_number_symbol, is_odd_symbol, is_openlet_symbol, is_output_port_symbol, is_pair_symbol,
  850. is_port_closed_symbol, is_positive_symbol, is_procedure_symbol, is_proper_list_symbol, is_provided_symbol,
  851. is_random_state_symbol, is_rational_symbol, is_real_symbol, is_sequence_symbol, is_string_symbol, is_symbol_symbol,
  852. is_vector_symbol, is_zero_symbol, iterate_symbol, iterator_is_at_end_symbol, iterator_sequence_symbol,
  853. is_float_symbol, is_integer_or_real_at_end_symbol, is_integer_or_any_at_end_symbol,
  854. keyword_to_symbol_symbol,
  855. lcm_symbol, length_symbol, leq_symbol, let_ref_fallback_symbol, let_ref_symbol, let_set_fallback_symbol,
  856. let_set_symbol, list_ref_symbol, list_set_symbol, list_symbol, list_tail_symbol, load_path_symbol,
  857. load_symbol, log_symbol, logand_symbol, logbit_symbol, logior_symbol, lognot_symbol, logxor_symbol, lt_symbol,
  858. magnitude_symbol, make_byte_vector_symbol, make_float_vector_symbol, make_hash_table_symbol, make_int_vector_symbol,
  859. make_iterator_symbol, make_keyword_symbol, make_list_symbol, make_shared_vector_symbol, make_string_symbol,
  860. make_vector_symbol, map_symbol, max_symbol, member_symbol, memq_symbol, memv_symbol, min_symbol, modulo_symbol,
  861. multiply_symbol,
  862. newline_symbol, not_symbol, number_to_string_symbol, numerator_symbol,
  863. object_to_string_symbol, object_to_let_symbol, open_input_file_symbol, open_input_string_symbol, open_output_file_symbol,
  864. openlet_symbol, outlet_symbol, owlet_symbol,
  865. pair_filename_symbol, pair_line_number_symbol, peek_char_symbol, pi_symbol, port_filename_symbol, port_line_number_symbol,
  866. procedure_documentation_symbol, procedure_signature_symbol, procedure_source_symbol, provide_symbol,
  867. quotient_symbol,
  868. random_state_symbol, random_state_to_list_symbol, random_symbol, rationalize_symbol, read_byte_symbol,
  869. read_char_symbol, read_line_symbol, read_string_symbol, read_symbol, real_part_symbol, remainder_symbol,
  870. require_symbol, reverse_symbol, reverseb_symbol, rootlet_symbol, round_symbol,
  871. set_car_symbol, set_cdr_symbol, sin_symbol, sinh_symbol, sort_symbol, sqrt_symbol,
  872. stacktrace_symbol, string_append_symbol, string_downcase_symbol, string_eq_symbol, string_fill_symbol,
  873. string_geq_symbol, string_gt_symbol, string_leq_symbol, string_lt_symbol, string_position_symbol, string_ref_symbol,
  874. string_set_symbol, string_symbol, string_to_number_symbol, string_to_symbol_symbol, string_upcase_symbol,
  875. sublet_symbol, substring_symbol, subtract_symbol, symbol_access_symbol, symbol_symbol, symbol_to_dynamic_value_symbol,
  876. symbol_to_keyword_symbol, symbol_to_string_symbol, symbol_to_value_symbol,
  877. tan_symbol, tanh_symbol, throw_symbol, string_to_byte_vector_symbol, truncate_symbol,
  878. unlet_symbol,
  879. values_symbol, varlet_symbol, vector_append_symbol, vector_dimensions_symbol, vector_fill_symbol, vector_ref_symbol,
  880. vector_set_symbol, vector_symbol,
  881. with_input_from_file_symbol, with_input_from_string_symbol, with_output_to_file_symbol, with_output_to_string_symbol,
  882. write_byte_symbol, write_char_symbol, write_string_symbol, write_symbol;
  883. #if (!WITH_PURE_S7)
  884. 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,
  885. let_to_list_symbol, integer_length_symbol, string_ci_leq_symbol, string_ci_lt_symbol, string_ci_eq_symbol,
  886. string_ci_geq_symbol, string_ci_gt_symbol, string_to_list_symbol, vector_to_list_symbol, string_length_symbol,
  887. string_copy_symbol, list_to_string_symbol, list_to_vector_symbol, vector_length_symbol, make_polar_symbol,
  888. make_rectangular_symbol;
  889. #endif
  890. /* s7 env symbols */
  891. s7_pointer stack_top_symbol, symbol_table_is_locked_symbol, heap_size_symbol, gc_freed_symbol, gc_protected_objects_symbol,
  892. free_heap_size_symbol, file_names_symbol, symbol_table_symbol, cpu_time_symbol, c_objects_symbol, float_format_precision_symbol,
  893. stack_size_symbol, rootlet_size_symbol, c_types_symbol, safety_symbol, max_stack_size_symbol, gc_stats_symbol,
  894. strings_symbol, vectors_symbol, input_ports_symbol, output_ports_symbol, continuations_symbol, hash_tables_symbol, gensyms_symbol,
  895. catches_symbol, exits_symbol, stack_symbol, default_rationalize_error_symbol, max_string_length_symbol, default_random_state_symbol,
  896. max_list_length_symbol, max_vector_length_symbol, max_vector_dimensions_symbol, default_hash_table_length_symbol, profile_info_symbol,
  897. hash_table_float_epsilon_symbol, morally_equal_float_epsilon_symbol, initial_string_port_length_symbol, memory_usage_symbol,
  898. undefined_identifier_warnings_symbol, print_length_symbol, bignum_precision_symbol, stacktrace_defaults_symbol, history_size_symbol;
  899. /* syntax symbols et al */
  900. s7_pointer else_symbol, lambda_symbol, lambda_star_symbol, let_symbol, quote_symbol, unquote_symbol, macroexpand_symbol,
  901. define_expansion_symbol, baffle_symbol, with_let_symbol, documentation_symbol, signature_symbol, if_symbol,
  902. when_symbol, unless_symbol, begin_symbol, cond_symbol, case_symbol, and_symbol, or_symbol, do_symbol,
  903. define_symbol, define_star_symbol, define_constant_symbol, with_baffle_symbol, define_macro_symbol,
  904. define_macro_star_symbol, define_bacro_symbol, define_bacro_star_symbol, letrec_symbol, letrec_star_symbol,
  905. let_star_symbol, key_rest_symbol, key_allow_other_keys_symbol, key_readable_symbol, value_symbol, type_symbol,
  906. baffled_symbol, __func___symbol, set_symbol, body_symbol, class_name_symbol, feed_to_symbol, format_error_symbol,
  907. wrong_number_of_args_symbol, read_error_symbol, string_read_error_symbol, syntax_error_symbol, division_by_zero_symbol,
  908. no_catch_symbol, io_error_symbol, invalid_escape_function_symbol, wrong_type_arg_symbol, out_of_range_symbol;
  909. /* optimizer symbols */
  910. s7_pointer and_p2_symbol, and_p_symbol, and_unchecked_symbol, begin_unchecked_symbol, case_simple_symbol, case_simpler_1_symbol,
  911. case_simpler_ss_symbol, case_simpler_symbol, case_simplest_ss_symbol, case_simplest_symbol, case_unchecked_symbol,
  912. cond_all_x_2_symbol, cond_all_x_symbol, cond_s_symbol, cond_simple_symbol, cond_unchecked_symbol, decrement_1_symbol,
  913. define_constant_unchecked_symbol, define_funchecked_symbol, define_star_unchecked_symbol, define_unchecked_symbol,
  914. do_unchecked_symbol, dotimes_p_symbol, dox_symbol, if_a_p_p_symbol, if_a_p_symbol, if_and2_p_p_symbol, if_and2_p_symbol,
  915. if_andp_p_p_symbol, if_andp_p_symbol, if_cc_p_p_symbol, if_cc_p_symbol, if_cs_p_p_symbol, if_cs_p_symbol, if_csc_p_p_symbol,
  916. if_csc_p_symbol, if_csq_p_p_symbol, if_csq_p_symbol, if_css_p_p_symbol, if_css_p_symbol, if_is_pair_p_p_symbol,
  917. if_is_pair_p_symbol, if_is_symbol_p_p_symbol, if_is_symbol_p_symbol, if_not_s_p_p_symbol, if_not_s_p_symbol,
  918. if_opssq_p_p_symbol, if_opssq_p_symbol, if_orp_p_p_symbol, if_orp_p_symbol, if_p_feed_symbol, if_p_p_p_symbol,
  919. if_p_p_symbol, if_s_opcq_p_p_symbol, if_s_opcq_p_symbol, if_s_p_p_symbol, if_s_p_symbol, if_unchecked_symbol,
  920. if_z_p_p_symbol, if_z_p_symbol, increment_1_symbol, increment_sa_symbol, increment_saa_symbol, increment_ss_symbol,
  921. increment_sss_symbol, increment_sz_symbol, lambda_star_unchecked_symbol, lambda_unchecked_symbol, let_all_c_symbol,
  922. let_all_opsq_symbol, let_all_s_symbol, let_all_x_symbol, let_c_symbol, let_no_vars_symbol, let_one_symbol,
  923. let_opcq_symbol, let_opsq_p_symbol, let_opsq_symbol, let_opssq_symbol, let_s_symbol, let_star2_symbol,
  924. let_star_all_x_symbol, let_star_unchecked_symbol, let_unchecked_symbol, let_z_symbol, letrec_star_unchecked_symbol,
  925. letrec_unchecked_symbol, named_let_no_vars_symbol, named_let_star_symbol, named_let_symbol, or_p2_symbol, or_p_symbol,
  926. or_unchecked_symbol, quote_unchecked_symbol, safe_do_symbol, safe_dotimes_symbol, set_cons_symbol, set_let_all_x_symbol,
  927. set_let_s_symbol, set_normal_symbol, set_pair_a_symbol, set_pair_c_p_symbol, set_pair_c_symbol, set_pair_p_symbol,
  928. set_pair_symbol, set_pair_z_symbol, set_pair_za_symbol, set_pws_symbol, set_symbol_a_symbol, set_symbol_c_symbol,
  929. set_symbol_opcq_symbol, set_symbol_opsq_symbol, set_symbol_opssq_symbol, set_symbol_opsssq_symbol, set_symbol_p_symbol,
  930. set_symbol_q_symbol, set_symbol_s_symbol, set_symbol_z_symbol, set_unchecked_symbol, simple_do_a_symbol,
  931. simple_do_e_symbol, simple_do_p_symbol, simple_do_symbol, unless_s_symbol, unless_unchecked_symbol, when_s_symbol,
  932. when_unchecked_symbol, with_baffle_unchecked_symbol, with_let_s_symbol, with_let_unchecked_symbol,
  933. dox_slot_symbol;
  934. #if WITH_GMP
  935. s7_pointer bignum_symbol, is_bignum_symbol;
  936. s7_pointer *bigints, *bigratios, *bigreals, *bignumbers;
  937. int bigints_size, bigratios_size, bigreals_size, bignumbers_size;
  938. int bigints_loc, bigratios_loc, bigreals_loc, bignumbers_loc;
  939. #endif
  940. #if WITH_SYSTEM_EXTRAS
  941. s7_pointer is_directory_symbol, file_exists_symbol, delete_file_symbol, getenv_symbol, system_symbol, directory_to_list_symbol, file_mtime_symbol;
  942. #endif
  943. /* setter and quasiquote functions */
  944. s7_pointer vector_set_function, string_set_function, list_set_function, hash_table_set_function, let_set_function, object_set_function,
  945. qq_list_function, qq_apply_values_function, qq_append_function, multivector_function,
  946. apply_function, vector_function;
  947. s7_pointer wrong_type_arg_info, out_of_range_info, simple_wrong_type_arg_info, simple_out_of_range_info;
  948. s7_pointer too_many_arguments_string, not_enough_arguments_string, division_by_zero_error_string;
  949. s7_pointer *safe_lists, *syn_docs; /* prebuilt evaluator arg lists, syntax doc strings */
  950. s7_pointer autoload_table, libraries, profile_info;
  951. const char ***autoload_names;
  952. int *autoload_names_sizes;
  953. bool **autoloaded_already;
  954. int autoload_names_loc, autoload_names_top;
  955. port_t *port_heap;
  956. int format_depth;
  957. int slash_str_size;
  958. char *slash_str;
  959. xf_t *cur_rf;
  960. xf_t *rf_free_list, *rf_stack;
  961. bool undefined_identifier_warnings;
  962. };
  963. typedef enum {USE_DISPLAY, USE_WRITE, USE_READABLE_WRITE, USE_WRITE_WRONG} use_write_t;
  964. #define NUM_SAFE_LISTS 16
  965. #define INITIAL_AUTOLOAD_NAMES_SIZE 4
  966. static s7_pointer prepackaged_type_names[NUM_TYPES];
  967. static bool t_number_p[NUM_TYPES], t_real_p[NUM_TYPES], t_rational_p[NUM_TYPES];
  968. static bool t_simple_p[NUM_TYPES];
  969. static bool t_big_number_p[NUM_TYPES];
  970. static bool t_structure_p[NUM_TYPES];
  971. static bool t_any_macro_p[NUM_TYPES];
  972. static bool t_any_closure_p[NUM_TYPES];
  973. static bool t_has_closure_let[NUM_TYPES];
  974. static bool t_sequence_p[NUM_TYPES];
  975. static bool t_vector_p[NUM_TYPES];
  976. static bool t_applicable_p[NUM_TYPES];
  977. static void init_types(void)
  978. {
  979. int i;
  980. for (i = 0; i < NUM_TYPES; i++)
  981. {
  982. t_number_p[i] = false;
  983. t_real_p[i] = false;
  984. t_rational_p[i] = false;
  985. t_simple_p[i] = false;
  986. t_structure_p[i] = false;
  987. t_any_macro_p[i] = false;
  988. t_any_closure_p[i] = false;
  989. t_has_closure_let[i] = false;
  990. t_sequence_p[i] = false;
  991. t_vector_p[i] = false;
  992. t_applicable_p[i] = false;
  993. }
  994. t_number_p[T_INTEGER] = true;
  995. t_number_p[T_RATIO] = true;
  996. t_number_p[T_REAL] = true;
  997. t_number_p[T_COMPLEX] = true;
  998. t_rational_p[T_INTEGER] = true;
  999. t_rational_p[T_RATIO] = true;
  1000. t_real_p[T_INTEGER] = true;
  1001. t_real_p[T_RATIO] = true;
  1002. t_real_p[T_REAL] = true;
  1003. t_big_number_p[T_BIG_INTEGER] = true;
  1004. t_big_number_p[T_BIG_RATIO] = true;
  1005. t_big_number_p[T_BIG_REAL] = true;
  1006. t_big_number_p[T_BIG_COMPLEX] = true;
  1007. t_structure_p[T_PAIR] = true;
  1008. t_structure_p[T_VECTOR] = true;
  1009. t_structure_p[T_HASH_TABLE] = true;
  1010. t_structure_p[T_SLOT] = true;
  1011. t_structure_p[T_LET] = true;
  1012. t_structure_p[T_ITERATOR] = true;
  1013. t_sequence_p[T_NIL] = true;
  1014. t_sequence_p[T_PAIR] = true;
  1015. t_sequence_p[T_STRING] = true;
  1016. t_sequence_p[T_VECTOR] = true;
  1017. t_sequence_p[T_INT_VECTOR] = true;
  1018. t_sequence_p[T_FLOAT_VECTOR] = true;
  1019. t_sequence_p[T_HASH_TABLE] = true;
  1020. t_sequence_p[T_LET] = true;
  1021. t_sequence_p[T_C_OBJECT] = true;
  1022. t_vector_p[T_VECTOR] = true;
  1023. t_vector_p[T_INT_VECTOR] = true;
  1024. t_vector_p[T_FLOAT_VECTOR] = true;
  1025. t_applicable_p[T_PAIR] = true;
  1026. t_applicable_p[T_STRING] = true;
  1027. t_applicable_p[T_VECTOR] = true;
  1028. t_applicable_p[T_INT_VECTOR] = true;
  1029. t_applicable_p[T_FLOAT_VECTOR] = true;
  1030. t_applicable_p[T_HASH_TABLE] = true;
  1031. t_applicable_p[T_ITERATOR] = true;
  1032. t_applicable_p[T_LET] = true;
  1033. t_applicable_p[T_C_OBJECT] = true;
  1034. t_applicable_p[T_C_MACRO] = true;
  1035. t_applicable_p[T_MACRO] = true;
  1036. t_applicable_p[T_BACRO] = true;
  1037. t_applicable_p[T_MACRO_STAR] = true;
  1038. t_applicable_p[T_BACRO_STAR] = true;
  1039. t_applicable_p[T_SYNTAX] = true;
  1040. t_applicable_p[T_C_FUNCTION] = true;
  1041. t_applicable_p[T_C_FUNCTION_STAR] = true;
  1042. t_applicable_p[T_C_ANY_ARGS_FUNCTION] = true;
  1043. t_applicable_p[T_C_OPT_ARGS_FUNCTION] = true;
  1044. t_applicable_p[T_C_RST_ARGS_FUNCTION] = true;
  1045. t_applicable_p[T_CLOSURE] = true;
  1046. t_applicable_p[T_CLOSURE_STAR] = true;
  1047. t_applicable_p[T_GOTO] = true;
  1048. t_applicable_p[T_CONTINUATION] = true;
  1049. t_any_macro_p[T_C_MACRO] = true;
  1050. t_any_macro_p[T_MACRO] = true;
  1051. t_any_macro_p[T_BACRO] = true;
  1052. t_any_macro_p[T_MACRO_STAR] = true;
  1053. t_any_macro_p[T_BACRO_STAR] = true;
  1054. t_any_closure_p[T_CLOSURE] = true;
  1055. t_any_closure_p[T_CLOSURE_STAR] = true;
  1056. t_has_closure_let[T_MACRO] = true;
  1057. t_has_closure_let[T_BACRO] = true;
  1058. t_has_closure_let[T_MACRO_STAR] = true;
  1059. t_has_closure_let[T_BACRO_STAR] = true;
  1060. t_has_closure_let[T_CLOSURE] = true;
  1061. t_has_closure_let[T_CLOSURE_STAR] = true;
  1062. t_simple_p[T_NIL] = true;
  1063. t_simple_p[T_UNIQUE] = true;
  1064. t_simple_p[T_BOOLEAN] = true;
  1065. t_simple_p[T_CHARACTER] = true;
  1066. t_simple_p[T_SYMBOL] = true;
  1067. t_simple_p[T_SYNTAX] = true;
  1068. t_simple_p[T_C_MACRO] = true;
  1069. t_simple_p[T_C_FUNCTION] = true;
  1070. t_simple_p[T_C_FUNCTION_STAR] = true;
  1071. t_simple_p[T_C_ANY_ARGS_FUNCTION] = true;
  1072. t_simple_p[T_C_OPT_ARGS_FUNCTION] = true;
  1073. t_simple_p[T_C_RST_ARGS_FUNCTION] = true;
  1074. /* not completely sure about the next ones */
  1075. t_simple_p[T_LET] = true;
  1076. t_simple_p[T_INPUT_PORT] = true;
  1077. t_simple_p[T_OUTPUT_PORT] = true;
  1078. }
  1079. #if WITH_HISTORY
  1080. #define current_code(Sc) car(Sc->cur_code)
  1081. #define set_current_code(Sc, Code) do {Sc->cur_code = cdr(Sc->cur_code); set_car(Sc->cur_code, Code);} while (0)
  1082. #define mark_current_code(Sc) do {int i; s7_pointer p; for (p = Sc->cur_code, i = 0; i < sc->history_size; i++, p = cdr(p)) S7_MARK(car(p));} while (0)
  1083. #else
  1084. #define current_code(Sc) Sc->cur_code
  1085. #define set_current_code(Sc, Code) Sc->cur_code = Code
  1086. #define mark_current_code(Sc) S7_MARK(Sc->cur_code)
  1087. #endif
  1088. #define typeflag(p) ((p)->tf.flag)
  1089. #define typesflag(p) ((p)->tf.sflag)
  1090. static s7_scheme *hidden_sc = NULL;
  1091. #if DEBUGGING
  1092. static const char *check_name(int typ);
  1093. static s7_pointer check_seti(s7_scheme *sc, s7_pointer x, const char *func, int line);
  1094. static s7_pointer check_ref(s7_pointer p, int expected_type, const char *func, int line, const char *func1, const char *func2);
  1095. static s7_pointer check_ref2(s7_pointer p, int expected_type, int other_type, const char *func, int line, const char *func1, const char *func2);
  1096. static s7_pointer check_ref3(s7_pointer p, const char *func, int line);
  1097. static s7_pointer check_ref4(s7_pointer p, const char *func, int line);
  1098. static s7_pointer check_ref5(s7_pointer p, const char *func, int line);
  1099. static s7_pointer check_ref6(s7_pointer p, const char *func, int line);
  1100. static s7_pointer check_ref7(s7_pointer p, const char *func, int line);
  1101. static s7_pointer check_ref8(s7_pointer p, const char *func, int line);
  1102. static s7_pointer check_ref9(s7_pointer p, const char *func, int line);
  1103. static s7_pointer check_ref10(s7_pointer p, const char *func, int line);
  1104. static s7_pointer check_ref11(s7_pointer p, const char *func, int line);
  1105. static s7_pointer check_nref(s7_pointer p, const char *func, int line);
  1106. static void print_gc_info(s7_pointer obj, int line);
  1107. static s7_pointer opt1_1(s7_scheme *sc, s7_pointer p, unsigned int role, const char *func, int line);
  1108. static s7_pointer set_opt1_1(s7_scheme *sc, s7_pointer p, s7_pointer x, unsigned int role, const char *func, int line);
  1109. static s7_pointer opt2_1(s7_scheme *sc, s7_pointer p, unsigned int role, const char *func, int line);
  1110. static void set_opt2_1(s7_scheme *sc, s7_pointer p, s7_pointer x, unsigned int role, const char *func, int line);
  1111. static s7_pointer opt3_1(s7_scheme *sc, s7_pointer p, unsigned int role, const char *func, int line);
  1112. static void set_opt3_1(s7_scheme *sc, s7_pointer p, s7_pointer x, unsigned int role, const char *func, int line);
  1113. static unsigned long long int s_hash_1(s7_scheme *sc, s7_pointer p, const char *func, int line);
  1114. static void set_s_hash_1(s7_scheme *sc, s7_pointer p, unsigned long long int x, const char *func, int line);
  1115. static const char *s_name_1(s7_scheme *sc, s7_pointer p, const char *func, int line);
  1116. static void set_s_name_1(s7_scheme *sc, s7_pointer p, const char *str, const char *func, int line);
  1117. static unsigned int s_line_1(s7_scheme *sc, s7_pointer p, const char *func, int line);
  1118. static void set_s_line_1(s7_scheme *sc, s7_pointer p, unsigned int x, const char *func, int line);
  1119. static unsigned int s_len_1(s7_scheme *sc, s7_pointer p, const char *func, int line);
  1120. static void set_s_len_1(s7_scheme *sc, s7_pointer p, unsigned int x, const char *func, int line);
  1121. static unsigned int s_op_1(s7_scheme *sc, s7_pointer p, const char *func, int line);
  1122. static void set_s_op_1(s7_scheme *sc, s7_pointer p, unsigned int x, const char *func, int line);
  1123. static unsigned int s_syn_op_1(s7_scheme *sc, s7_pointer p, const char *func, int line);
  1124. static void set_s_syn_op_1(s7_scheme *sc, s7_pointer p, unsigned int x, const char *func, int line);
  1125. #define unchecked_type(p) ((p)->tf.type_field)
  1126. #define type(p) ({unsigned char _t_; _t_ = (p)->tf.type_field; if (((_t_ == T_FREE)) || (_t_ >= NUM_TYPES)) print_gc_info(p, __LINE__); _t_;})
  1127. #define set_type(p, f) \
  1128. do { \
  1129. p->previous_alloc_line = p->current_alloc_line; \
  1130. p->previous_alloc_func = p->current_alloc_func; \
  1131. p->previous_alloc_type = p->current_alloc_type; \
  1132. p->current_alloc_line = __LINE__; \
  1133. p->current_alloc_func = __func__; \
  1134. p->current_alloc_type = f; \
  1135. p->uses++; p->clear_line = 0; \
  1136. if ((((f) & 0xff) == T_FREE) || (((f) & 0xff) >= NUM_TYPES)) \
  1137. fprintf(stderr, "%d: set free %p type to %x\n", __LINE__, p, f); \
  1138. else \
  1139. { \
  1140. if (((typeflag(p) & T_IMMUTABLE) != 0) && ((typeflag(p) != (f)))) \
  1141. fprintf(stderr, "%d: set immutable %p type %x to %x\n", __LINE__, p, unchecked_type(p), f); \
  1142. if (((typeflag(p) & T_LINE_NUMBER) != 0) && (((typeflag(p)) & 0xff) == T_PAIR) && (((f) & T_LINE_NUMBER) == 0)) \
  1143. fprintf(stderr, "%d unsets line_number\n", __LINE__); \
  1144. } \
  1145. typeflag(p) = f; \
  1146. } while (0)
  1147. #define clear_type(p) do {p->clear_line = __LINE__; typeflag(p) = T_FREE;} while (0)
  1148. /* these check most s7cell field references (and many type bits) for consistency */
  1149. #define _TI(P) check_ref(P, T_INTEGER, __func__, __LINE__, NULL, NULL)
  1150. #define _TR(P) check_ref(P, T_REAL, __func__, __LINE__, NULL, NULL)
  1151. #define _TF(P) check_ref2(P, T_RATIO, T_INTEGER, __func__, __LINE__, NULL, NULL)
  1152. #define _TZ(P) check_ref(P, T_COMPLEX, __func__, __LINE__, NULL, NULL)
  1153. #define _TBgi(P) check_ref(P, T_BIG_INTEGER, __func__, __LINE__, "sweep", NULL)
  1154. #define _TBgr(P) check_ref(P, T_BIG_REAL, __func__, __LINE__, "sweep", NULL)
  1155. #define _TBgf(P) check_ref(P, T_BIG_RATIO, __func__, __LINE__, "sweep", NULL)
  1156. #define _TBgz(P) check_ref(P, T_BIG_COMPLEX, __func__, __LINE__, "sweep", NULL)
  1157. #define _TChr(P) check_ref(P, T_CHARACTER, __func__, __LINE__, NULL, NULL)
  1158. #define _TCtr(P) check_ref(P, T_COUNTER, __func__, __LINE__, NULL, NULL)
  1159. #define _TPtr(P) check_ref(P, T_C_POINTER, __func__, __LINE__, NULL, NULL)
  1160. #define _TBfl(P) check_ref(P, T_BAFFLE, __func__, __LINE__, NULL, NULL)
  1161. #define _TGot(P) check_ref(P, T_GOTO, __func__, __LINE__, NULL, NULL)
  1162. #define _TStk(P) check_ref(P, T_STACK, __func__, __LINE__, NULL, NULL)
  1163. #define _TPair(P) check_ref(P, T_PAIR, __func__, __LINE__, NULL, NULL)
  1164. #define _TCat(P) check_ref(P, T_CATCH, __func__, __LINE__, NULL, NULL)
  1165. #define _TDyn(P) check_ref(P, T_DYNAMIC_WIND, __func__, __LINE__, NULL, NULL)
  1166. #define _TSlt(P) check_ref(P, T_SLOT, __func__, __LINE__, NULL, NULL)
  1167. #define _TSlp(P) check_ref2(P, T_SLOT, T_PAIR, __func__, __LINE__, NULL, NULL)
  1168. #define _TSln(P) check_ref2(P, T_SLOT, T_NIL, __func__, __LINE__, NULL, NULL)
  1169. #define _TSld(P) check_ref2(P, T_SLOT, T_UNIQUE, __func__, __LINE__, NULL, NULL)
  1170. #define _TSyn(P) check_ref(P, T_SYNTAX, __func__, __LINE__, NULL, NULL)
  1171. #define _TMac(P) check_ref(P, T_C_MACRO, __func__, __LINE__, NULL, NULL)
  1172. #define _TLet(P) check_ref(P, T_LET, __func__, __LINE__, NULL, NULL)
  1173. #define _TLid(P) check_ref2(P, T_LET, T_NIL, __func__, __LINE__, NULL, NULL)
  1174. #define _TRan(P) check_ref(P, T_RANDOM_STATE, __func__, __LINE__, NULL, NULL)
  1175. #define _TLst(P) check_ref2(P, T_PAIR, T_NIL, __func__, __LINE__, "gc", NULL)
  1176. #define _TStr(P) check_ref(P, T_STRING, __func__, __LINE__, "sweep", NULL)
  1177. #define _TObj(P) check_ref(P, T_C_OBJECT, __func__, __LINE__, "free_object", NULL)
  1178. #define _THsh(P) check_ref(P, T_HASH_TABLE, __func__, __LINE__, "sweep", "free_hash_table")
  1179. #define _TItr(P) check_ref(P, T_ITERATOR, __func__, __LINE__, "sweep", NULL)
  1180. #define _TCon(P) check_ref(P, T_CONTINUATION, __func__, __LINE__, "sweep", NULL)
  1181. #define _TFvc(P) check_ref(P, T_FLOAT_VECTOR, __func__, __LINE__, "sweep", NULL)
  1182. #define _TIvc(P) check_ref(P, T_INT_VECTOR, __func__, __LINE__, "sweep", NULL)
  1183. #define _TSym(P) check_ref(P, T_SYMBOL, __func__, __LINE__, "sweep", "remove_gensym_from_symbol_table")
  1184. #define _TPrt(P) check_ref3(P, __func__, __LINE__) /* input|output_port, or free */
  1185. #define _TVec(P) check_ref4(P, __func__, __LINE__) /* any vector or free */
  1186. #define _TClo(P) check_ref5(P, __func__, __LINE__) /* has closure let */
  1187. #define _TFnc(P) check_ref6(P, __func__, __LINE__) /* any c_function|c_macro */
  1188. #define _TNum(P) check_ref7(P, __func__, __LINE__) /* any number (not bignums I think) */
  1189. #define _TSeq(P) check_ref8(P, __func__, __LINE__) /* any sequence or structure */
  1190. #define _TMet(P) check_ref9(P, __func__, __LINE__) /* anything that might contain a method */
  1191. #define _TArg(P) check_ref10(P, __func__, __LINE__) /* closure arg (list, symbol) */
  1192. #define _TApp(P) check_ref11(P, __func__, __LINE__) /* setter (any_procedure or #f) */
  1193. #define _NFre(P) check_nref(P, __func__, __LINE__) /* not free */
  1194. #define _TSet(P) check_seti(sc, P, __func__, __LINE__) /* set of immutable value */
  1195. #else
  1196. #define unchecked_type(p) ((p)->tf.type_field)
  1197. #define type(p) ((p)->tf.type_field)
  1198. #define set_type(p, f) typeflag(p) = f
  1199. #define clear_type(p) typeflag(p) = T_FREE
  1200. #define _TSet(P) P
  1201. #define _TI(P) P
  1202. #define _TR(P) P
  1203. #define _TF(P) P
  1204. #define _TZ(P) P
  1205. #define _TBgi(P) P
  1206. #define _TBgr(P) P
  1207. #define _TBgf(P) P
  1208. #define _TBgz(P) P
  1209. #define _TStr(P) P
  1210. #define _TSyn(P) P
  1211. #define _TChr(P) P
  1212. #define _TObj(P) P
  1213. #define _TCtr(P) P
  1214. #define _THsh(P) P
  1215. #define _TItr(P) P
  1216. #define _TPtr(P) P
  1217. #define _TBfl(P) P
  1218. #define _TGot(P) P
  1219. #define _TCon(P) P
  1220. #define _TStk(P) P
  1221. #define _TPrt(P) P
  1222. #define _TIvc(P) P
  1223. #define _TFvc(P) P
  1224. #define _TVec(P) P
  1225. #define _TPair(P) P
  1226. #define _TRan(P) P
  1227. #define _TDyn(P) P
  1228. #define _TCat(P) P
  1229. #define _TClo(P) P
  1230. #define _TFnc(P) P
  1231. #define _TSlt(P) P
  1232. #define _TSln(P) P
  1233. #define _TSld(P) P
  1234. #define _TSlp(P) P
  1235. #define _TSym(P) P
  1236. #define _TLet(P) P
  1237. #define _TLid(P) P
  1238. #define _TLst(P) P
  1239. #define _TNum(P) P
  1240. #define _TSeq(P) P
  1241. #define _TMet(P) P
  1242. #define _TMac(P) P
  1243. #define _TArg(P) P
  1244. #define _TApp(P) P
  1245. #define _NFre(P) P
  1246. #endif
  1247. #define is_number(P) t_number_p[type(P)]
  1248. #define is_integer(P) (type(P) == T_INTEGER)
  1249. #define is_real(P) t_real_p[type(P)]
  1250. #define is_rational(P) t_rational_p[type(P)]
  1251. #define is_big_number(p) t_big_number_p[type(p)]
  1252. #define is_t_integer(p) (type(p) == T_INTEGER)
  1253. #define is_t_ratio(p) (type(p) == T_RATIO)
  1254. #define is_t_real(p) (type(p) == T_REAL)
  1255. #define is_t_complex(p) (type(p) == T_COMPLEX)
  1256. #define is_t_big_integer(p) (type(p) == T_BIG_INTEGER)
  1257. #define is_t_big_ratio(p) (type(p) == T_BIG_RATIO)
  1258. #define is_t_big_real(p) (type(p) == T_BIG_REAL)
  1259. #define is_t_big_complex(p) (type(p) == T_BIG_COMPLEX)
  1260. #define is_free(p) (type(p) == T_FREE)
  1261. #define is_free_and_clear(p) (typeflag(p) == T_FREE)
  1262. #define is_simple(P) t_simple_p[type(P)]
  1263. #define has_structure(P) t_structure_p[type(P)]
  1264. #define is_any_macro(P) t_any_macro_p[type(P)]
  1265. #define is_any_closure(P) t_any_closure_p[type(P)]
  1266. #define is_procedure_or_macro(P) ((t_any_macro_p[type(P)]) || ((typeflag(P) & T_PROCEDURE) != 0))
  1267. #define is_any_procedure(P) (type(P) >= T_CLOSURE)
  1268. #define has_closure_let(P) t_has_closure_let[type(P)]
  1269. #define is_simple_sequence(P) (t_sequence_p[type(P)])
  1270. #define is_sequence(P) ((t_sequence_p[type(P)]) || (has_methods(P)))
  1271. #define is_applicable(P) (t_applicable_p[type(P)])
  1272. /* this misses #() which actually is not applicable to anything, probably "" also, and inapplicable c-objects like random-state */
  1273. /* the layout of these bits does matter in several cases -- in particular, don't use the second byte for anything
  1274. * that might shadow SYNTACTIC_PAIR and OPTIMIZED_PAIR.
  1275. */
  1276. #define TYPE_BITS 8
  1277. #define T_KEYWORD (1 << (TYPE_BITS + 0))
  1278. #define is_keyword(p) ((typesflag(_NFre(p)) & T_KEYWORD) != 0)
  1279. /* this bit distinguishes a symbol from a symbol that is also a keyword
  1280. * this should be ok in the second byte because keywords are constants in s7 (never syntax)
  1281. */
  1282. #define T_SYNTACTIC (1 << (TYPE_BITS + 1))
  1283. #define is_syntactic(p) ((typesflag(_NFre(p)) & T_SYNTACTIC) != 0)
  1284. #define is_syntactic_symbol(p) ((typesflag(_NFre(p)) & (T_SYNTACTIC | 0xff)) == (T_SYMBOL | T_SYNTACTIC))
  1285. #define SYNTACTIC_TYPE (unsigned short)(T_SYMBOL | T_DONT_EVAL_ARGS | T_SYNTACTIC)
  1286. #define SYNTACTIC_PAIR (unsigned short)(T_PAIR | T_SYNTACTIC)
  1287. /* this marks symbols that represent syntax objects, it should be in the second byte */
  1288. #define set_syntactic_pair(p) typeflag(p) = (SYNTACTIC_PAIR | (typeflag(p) & 0xffff0000))
  1289. #define T_PROCEDURE (1 << (TYPE_BITS + 2))
  1290. #define is_procedure(p) ((typesflag(_NFre(p)) & T_PROCEDURE) != 0)
  1291. /* closure, c_function, applicable object, goto or continuation, should be in second byte */
  1292. #define T_OPTIMIZED (1 << (TYPE_BITS + 3))
  1293. #define set_optimized(p) typesflag(_TPair(p)) |= T_OPTIMIZED
  1294. #define clear_optimized(p) typesflag(_TPair(p)) &= (~T_OPTIMIZED)
  1295. #define OPTIMIZED_PAIR (unsigned short)(T_PAIR | T_OPTIMIZED)
  1296. #define is_optimized(p) (typesflag(p) == OPTIMIZED_PAIR)
  1297. /* this is faster than the bit extraction above and the same speed as xor */
  1298. /* optimizer flag for an expression that has optimization info, it should be in the second byte
  1299. */
  1300. #define T_SAFE_CLOSURE (1 << (TYPE_BITS + 4))
  1301. #define is_safe_closure(p) ((typesflag(_NFre(p)) & T_SAFE_CLOSURE) != 0)
  1302. #define set_safe_closure(p) typesflag(p) |= T_SAFE_CLOSURE
  1303. #define clear_safe_closure(p) typesflag(p) &= (~T_SAFE_CLOSURE)
  1304. /* optimizer flag for a closure body that is completely simple (every expression is safe)
  1305. * set_safe_closure happens only in optimize_lambda, clear only in procedure_source, bits only here
  1306. * this has to be separate from T_SAFE_PROCEDURE, and should be in the second byte.
  1307. * It can be set on either the body (a pair) or the closure itself.
  1308. */
  1309. #define T_DONT_EVAL_ARGS (1 << (TYPE_BITS + 5))
  1310. #define dont_eval_args(p) ((typesflag(_NFre(p)) & T_DONT_EVAL_ARGS) != 0)
  1311. /* this marks things that don't evaluate their arguments */
  1312. #define T_EXPANSION (1 << (TYPE_BITS + 6))
  1313. #define is_expansion(p) ((typesflag(_NFre(p)) & T_EXPANSION) != 0)
  1314. #define clear_expansion(p) typesflag(_TSym(p)) &= (~T_EXPANSION)
  1315. /* this marks the symbol associated with a run-time macro and distinguishes the value from an ordinary macro */
  1316. #define T_MULTIPLE_VALUE (1 << (TYPE_BITS + 7))
  1317. #define is_multiple_value(p) ((typesflag(_NFre(p)) & T_MULTIPLE_VALUE) != 0)
  1318. #define set_multiple_value(p) typesflag(_TPair(p)) |= T_MULTIPLE_VALUE
  1319. #define clear_multiple_value(p) typesflag(_TPair(p)) &= (~T_MULTIPLE_VALUE)
  1320. #define multiple_value(p) p
  1321. /* this bit marks a list (from "values") that is waiting for a
  1322. * chance to be spliced into its caller's argument list. It is normally
  1323. * on only for a very short time.
  1324. */
  1325. #define T_MATCHED T_MULTIPLE_VALUE
  1326. #define is_matched_pair(p) ((typesflag(_TPair(p)) & T_MATCHED) != 0)
  1327. #define set_match_pair(p) typesflag(_TPair(p)) |= T_MATCHED
  1328. #define clear_match_pair(p) typesflag(_TPair(p)) &= (~T_MATCHED)
  1329. #define is_matched_symbol(p) ((typesflag(_TSym(p)) & T_MATCHED) != 0)
  1330. #define set_match_symbol(p) typesflag(_TSym(p)) |= T_MATCHED
  1331. #define clear_match_symbol(p) typesflag(_TSym(p)) &= (~T_MATCHED)
  1332. #define T_GLOBAL (1 << (TYPE_BITS + 8))
  1333. #define is_global(p) ((typeflag(_TSym(p)) & T_GLOBAL) != 0)
  1334. #define set_global(p) typeflag(_TSym(p)) |= T_GLOBAL
  1335. #if 0
  1336. /* to find who is stomping on our symbols: */
  1337. static char *object_to_truncated_string(s7_scheme *sc, s7_pointer p, int len);
  1338. static void set_local_1(s7_scheme *sc, s7_pointer symbol, const char *func, int line)
  1339. {
  1340. if ((is_global(symbol)) || (is_syntactic(symbol)))
  1341. fprintf(stderr, "%s[%d]: %s%s%s in %s\n", func, line, BOLD_TEXT, DISPLAY(symbol), UNBOLD_TEXT, DISPLAY_80(current_code(sc)));
  1342. typeflag(symbol) = (typeflag(symbol) & ~(T_DONT_EVAL_ARGS | T_GLOBAL | T_SYNTACTIC));
  1343. }
  1344. #define set_local(Symbol) set_local_1(sc, Symbol, __func__, __LINE__)
  1345. #else
  1346. #define set_local(p) typeflag(_TSym(p)) &= ~(T_DONT_EVAL_ARGS | T_GLOBAL | T_SYNTACTIC)
  1347. #endif
  1348. /* this marks something defined (bound) at the top-level, and never defined locally */
  1349. #define T_UNSAFE_DO T_GLOBAL
  1350. #define is_unsafe_do(p) ((typeflag(_TPair(p)) & T_UNSAFE_DO) != 0)
  1351. #define set_unsafe_do(p) typeflag(_TPair(p)) |= T_UNSAFE_DO
  1352. #define is_unsafe_sort(p) is_unsafe_do(p)
  1353. #define set_unsafe_sort(p) set_unsafe_do(p)
  1354. /* marks do-loops (and sort functions) that resist optimization */
  1355. #define T_COLLECTED (1 << (TYPE_BITS + 9))
  1356. #define is_collected(p) ((typeflag(_TSeq(p)) & T_COLLECTED) != 0)
  1357. #define set_collected(p) typeflag(_TSeq(p)) |= T_COLLECTED
  1358. /* #define clear_collected(p) typeflag(_TSeq(p)) &= (~T_COLLECTED) */
  1359. /* this is a transient flag used by the printer to catch cycles. It affects only objects that have structure.
  1360. * We can't use a low bit (bit 7 for example), because collect_shared_info inspects the object's type.
  1361. */
  1362. #define T_LINE_NUMBER (1 << (TYPE_BITS + 10))
  1363. #define has_line_number(p) ((typeflag(_TPair(p)) & T_LINE_NUMBER) != 0)
  1364. #define set_has_line_number(p) typeflag(_TPair(p)) |= T_LINE_NUMBER
  1365. /* pair in question has line/file info added during read, or the environment has function placement info
  1366. * this bit should not be in the first byte -- SYNTACTIC_PAIR ignores it.
  1367. */
  1368. #define T_LOADER_PORT T_LINE_NUMBER
  1369. #define is_loader_port(p) ((typeflag(_TPrt(p)) & T_LOADER_PORT) != 0)
  1370. #define set_loader_port(p) typeflag(_TPrt(p)) |= T_LOADER_PORT
  1371. #define clear_loader_port(p) typeflag(_TPrt(p)) &= (~T_LOADER_PORT)
  1372. /* to block random load-time reads from screwing up the load process, this bit marks a port used by the loader */
  1373. #define T_HAS_ACCESSOR T_LINE_NUMBER
  1374. #define symbol_has_accessor(p) ((typeflag(_TSym(p)) & T_HAS_ACCESSOR) != 0)
  1375. #define symbol_set_has_accessor(p) typeflag(_TSym(p)) |= T_HAS_ACCESSOR
  1376. #define slot_has_accessor(p) ((typeflag(_TSlt(p)) & T_HAS_ACCESSOR) != 0)
  1377. #define slot_set_has_accessor(p) typeflag(_TSlt(p)) |= T_HAS_ACCESSOR
  1378. /* marks a slot or symbol that has a setter */
  1379. #define T_WITH_LET_LET T_LINE_NUMBER
  1380. #define is_with_let_let(p) ((typeflag(_TLet(p)) & T_WITH_LET_LET) != 0)
  1381. #define set_with_let_let(p) typeflag(_TLet(p)) |= T_WITH_LET_LET
  1382. /* marks a let that is the argument to with-let */
  1383. #define T_SIMPLE_DEFAULTS T_LINE_NUMBER
  1384. #define has_simple_defaults(p) ((typeflag(_TFnc(p)) & T_SIMPLE_DEFAULTS) != 0)
  1385. #define set_simple_defaults(p) typeflag(_TFnc(p)) |= T_SIMPLE_DEFAULTS
  1386. #define clear_simple_defaults(p) typeflag(_TFnc(p)) &= (~T_SIMPLE_DEFAULTS)
  1387. /* flag c_func_star arg defaults that need GC protection */
  1388. #define T_SHARED (1 << (TYPE_BITS + 11))
  1389. #define is_shared(p) ((typeflag(_TSeq(p)) & T_SHARED) != 0)
  1390. #define set_shared(p) typeflag(_TSeq(p)) |= T_SHARED
  1391. /* #define clear_shared(p) typeflag(_TSeq(p)) &= (~T_SHARED) */
  1392. #define clear_collected_and_shared(p) typeflag(p) &= (~(T_COLLECTED | T_SHARED)) /* this can clear free cells = calloc */
  1393. #define T_OVERLAY (1 << (TYPE_BITS + 12))
  1394. #define set_overlay(p) typeflag(_TPair(p)) |= T_OVERLAY
  1395. #define is_overlaid(p) ((typeflag(_TPair(p)) & T_OVERLAY) != 0)
  1396. /* optimizer flag that marks a cell whose opt_back [ie opt1] points to the previous cell in a list */
  1397. #define T_SAFE_PROCEDURE (1 << (TYPE_BITS + 13))
  1398. #define is_safe_procedure(p) ((typeflag(_NFre(p)) & T_SAFE_PROCEDURE) != 0)
  1399. /* applicable objects that do not return or modify their arg list directly (no :rest arg in particular),
  1400. * and that can't call apply themselves either directly or via s7_call, and that don't mess with the stack.
  1401. */
  1402. #define T_CHECKED (1 << (TYPE_BITS + 14))
  1403. #define set_checked(p) typeflag(_TPair(p)) |= T_CHECKED
  1404. #define is_checked(p) ((typeflag(_TPair(p)) & T_CHECKED) != 0)
  1405. #define clear_checked(p) typeflag(_TPair(p)) &= (~T_CHECKED)
  1406. #define set_checked_slot(p) typeflag(_TSlt(p)) |= T_CHECKED
  1407. #define is_checked_slot(p) ((typeflag(_TSlt(p)) & T_CHECKED) != 0)
  1408. #define is_not_checked_slot(p) ((typeflag(_TSlt(p)) & T_CHECKED) == 0)
  1409. #define T_UNSAFE (1 << (TYPE_BITS + 15))
  1410. #define set_unsafe(p) typeflag(_TPair(p)) |= T_UNSAFE
  1411. #define set_unsafely_optimized(p) typeflag(_TPair(p)) |= (T_UNSAFE | T_OPTIMIZED)
  1412. #define is_unsafe(p) ((typeflag(_TPair(p)) & T_UNSAFE) != 0)
  1413. #define clear_unsafe(p) typeflag(_TPair(p)) &= (~T_UNSAFE)
  1414. #define is_safely_optimized(p) ((typeflag(p) & (T_OPTIMIZED | T_UNSAFE)) == T_OPTIMIZED)
  1415. /* optimizer flag saying "this expression is not completely self-contained. It might involve the stack, etc" */
  1416. #define T_CLEAN_SYMBOL T_UNSAFE
  1417. #define is_clean_symbol(p) ((typeflag(_TSym(p)) & T_CLEAN_SYMBOL) != 0)
  1418. #define set_clean_symbol(p) typeflag(_TSym(p)) |= T_CLEAN_SYMBOL
  1419. /* set if we know the symbol name can be printed without quotes (slashification) */
  1420. #define T_IMMUTABLE (1 << (TYPE_BITS + 16))
  1421. #define is_immutable(p) ((typeflag(_NFre(p)) & T_IMMUTABLE) != 0)
  1422. #define is_immutable_port(p) ((typeflag(_TPrt(p)) & T_IMMUTABLE) != 0)
  1423. #define is_immutable_symbol(p) ((typeflag(_TSym(p)) & T_IMMUTABLE) != 0)
  1424. #define is_immutable_integer(p) ((typeflag(_TI(p)) & T_IMMUTABLE) != 0)
  1425. #define is_immutable_real(p) ((typeflag(_TR(p)) & T_IMMUTABLE) != 0)
  1426. #define set_immutable(p) typeflag(_TSym(p)) |= T_IMMUTABLE
  1427. /* immutable means the value can't be changed via set! or bind -- this is separate from the symbol access stuff
  1428. * this bit can't be in the second byte -- with-let, for example, is immutable, but we use SYNTACTIC_TYPE to
  1429. * recognize syntax in do loop optimizations.
  1430. */
  1431. #define T_SETTER (1 << (TYPE_BITS + 17))
  1432. #define set_setter(p) typeflag(_TSym(p)) |= T_SETTER
  1433. #define is_setter(p) ((typeflag(_TSym(p)) & T_SETTER) != 0)
  1434. /* optimizer flag for a procedure that sets some variable (set-car! for example). */
  1435. #define T_ALLOW_OTHER_KEYS T_SETTER
  1436. #define set_allow_other_keys(p) typeflag(_TPair(p)) |= T_ALLOW_OTHER_KEYS
  1437. #define allows_other_keys(p) ((typeflag(_TPair(p)) & T_ALLOW_OTHER_KEYS) != 0)
  1438. /* marks arglist that allows keyword args other than those in the parameter list; can't allow
  1439. * (define* (f :allow-other-keys)...) because there's only one nil, and besides, it does say "other".
  1440. */
  1441. #define T_MUTABLE (1 << (TYPE_BITS + 18))
  1442. #define is_mutable(p) ((typeflag(_TNum(p)) & T_MUTABLE) != 0)
  1443. /* #define set_mutable(p) typeflag(_TNum(p)) |= T_MUTABLE */
  1444. /* used for mutable numbers */
  1445. #define T_MARK_SEQ T_MUTABLE
  1446. #define is_mark_seq(p) ((typeflag(_TItr(p)) & T_MARK_SEQ) != 0)
  1447. #define set_mark_seq(p) typeflag(_TItr(p)) |= T_MARK_SEQ
  1448. /* used in iterators for GC mark of sequence */
  1449. #define T_BYTE_VECTOR T_MUTABLE
  1450. #define is_byte_vector(p) ((typeflag(_TStr(p)) & T_BYTE_VECTOR) != 0)
  1451. #define set_byte_vector(p) typeflag(_TStr(p)) |= T_BYTE_VECTOR
  1452. /* marks a string that the caller considers a byte_vector */
  1453. #define T_STEPPER T_MUTABLE
  1454. #define is_stepper(p) ((typeflag(_TSlt(p)) & T_STEPPER) != 0)
  1455. #define set_stepper(p) typeflag(_TSlt(p)) |= T_STEPPER
  1456. bool s7_is_stepper(s7_pointer p) {return(is_stepper(p));}
  1457. /* marks a slot that holds a do-loop's step variable (if int, can be numerator=current, denominator=end) */
  1458. #define T_SAFE_STEPPER (1 << (TYPE_BITS + 19))
  1459. #define is_safe_stepper(p) ((typeflag(_TSlp(p)) & T_SAFE_STEPPER) != 0)
  1460. #define set_safe_stepper(p) typeflag(_TSlp(p)) |= T_SAFE_STEPPER
  1461. #define is_unsafe_stepper(p) ((typeflag(_TSlp(p)) & (T_STEPPER | T_SAFE_STEPPER)) == T_STEPPER)
  1462. /* an experiment */
  1463. #define T_PRINT_NAME T_SAFE_STEPPER
  1464. #define has_print_name(p) ((typeflag(_TNum(p)) & T_PRINT_NAME) != 0)
  1465. #define set_has_print_name(p) typeflag(_TNum(p)) |= T_PRINT_NAME
  1466. /* marks numbers that have a saved version of their string representation */
  1467. #define T_POSSIBLY_SAFE T_SAFE_STEPPER
  1468. #define is_possibly_safe(p) ((typeflag(_TFnc(p)) & T_POSSIBLY_SAFE) != 0)
  1469. #define set_is_possibly_safe(p) typeflag(_TFnc(p)) |= T_POSSIBLY_SAFE
  1470. /* marks c_functions that are not always unsafe -- this bit didn't work out as intended */
  1471. #define T_HAS_SET_FALLBACK T_SAFE_STEPPER
  1472. #define T_HAS_REF_FALLBACK T_MUTABLE
  1473. #define has_ref_fallback(p) ((typeflag(_TLid(p)) & T_HAS_REF_FALLBACK) != 0)
  1474. #define has_set_fallback(p) ((typeflag(_TLid(p)) & T_HAS_SET_FALLBACK) != 0)
  1475. #define set_has_ref_fallback(p) typeflag(_TLet(p)) |= T_HAS_REF_FALLBACK
  1476. #define set_has_set_fallback(p) typeflag(_TLet(p)) |= T_HAS_SET_FALLBACK
  1477. #define set_all_methods(p, e) typeflag(_TLet(p)) |= (typeflag(e) & (T_HAS_METHODS | T_HAS_REF_FALLBACK | T_HAS_SET_FALLBACK))
  1478. #define T_COPY_ARGS (1 << (TYPE_BITS + 20))
  1479. #define needs_copied_args(p) ((typeflag(_NFre(p)) & T_COPY_ARGS) != 0)
  1480. /* this marks something that might mess with its argument list, it should not be in the second byte */
  1481. #define T_GENSYM (1 << (TYPE_BITS + 21))
  1482. #define is_gensym(p) ((typeflag(_TSym(p)) & T_GENSYM) != 0)
  1483. /* symbol is from gensym (GC-able etc) */
  1484. #define T_SIMPLE_ARGS T_GENSYM
  1485. #define has_simple_args(p) ((typeflag(_TPair(p)) & T_SIMPLE_ARGS) != 0)
  1486. #define set_simple_args(p) typeflag(_TPair(p)) |= T_SIMPLE_ARGS
  1487. /* are all lambda* default values simple? */
  1488. #define T_LIST_IN_USE T_GENSYM
  1489. #define list_is_in_use(p) ((typeflag(_TPair(p)) & T_LIST_IN_USE) != 0)
  1490. #define set_list_in_use(p) typeflag(_TPair(p)) |= T_LIST_IN_USE
  1491. #define clear_list_in_use(p) typeflag(_TPair(p)) &= (~T_LIST_IN_USE)
  1492. /* these could all be one permanent list, indexed from inside, and this bit is never actually protecting anything across a call */
  1493. #define T_FUNCTION_ENV T_GENSYM
  1494. #define is_function_env(p) ((typeflag(_TLet(p)) & T_FUNCTION_ENV) != 0)
  1495. #define set_function_env(p) typeflag(_TLet(p)) |= T_FUNCTION_ENV
  1496. /* this marks a funclet */
  1497. #define T_DOCUMENTED T_GENSYM
  1498. #define is_documented(p) ((typeflag(_TStr(p)) & T_DOCUMENTED) != 0)
  1499. #define set_documented(p) typeflag(_TStr(p)) |= T_DOCUMENTED
  1500. /* this marks a symbol that has documentation (bit is set on name cell) */
  1501. #define T_HAS_METHODS (1 << (TYPE_BITS + 22))
  1502. #define has_methods(p) ((typeflag(_NFre(p)) & T_HAS_METHODS) != 0)
  1503. #define set_has_methods(p) typeflag(_TMet(p)) |= T_HAS_METHODS
  1504. #define clear_has_methods(p) typeflag(_TMet(p)) &= (~T_HAS_METHODS)
  1505. /* this marks an environment or closure that is "opened" up to generic functions etc
  1506. * don't reuse this bit if possible
  1507. */
  1508. #define T_GC_MARK 0x80000000 /* (1 << (TYPE_BITS + 23)) but that makes gcc unhappy */
  1509. #define is_marked(p) ((typeflag(p) & T_GC_MARK) != 0)
  1510. #define set_mark(p) typeflag(_NFre(p)) |= T_GC_MARK
  1511. #define clear_mark(p) typeflag(p) &= (~T_GC_MARK)
  1512. /* using bit 23 for this makes a big difference in the GC */
  1513. static int not_heap = -1;
  1514. #define heap_location(p) (p)->hloc
  1515. #define not_in_heap(p) ((_NFre(p))->hloc < 0)
  1516. #define unheap(p) (p)->hloc = not_heap--
  1517. #define is_eof(p) (_NFre(p) == sc->eof_object)
  1518. #define is_true(Sc, p) ((_NFre(p)) != Sc->F)
  1519. #define is_false(Sc, p) ((_NFre(p)) == Sc->F)
  1520. #ifdef _MSC_VER
  1521. #define MS_WINDOWS 1
  1522. static s7_pointer make_boolean(s7_scheme *sc, bool val) {if (val) return(sc->T); return(sc->F);}
  1523. #else
  1524. #define MS_WINDOWS 0
  1525. #define make_boolean(sc, Val) ((Val) ? sc->T : sc->F)
  1526. #endif
  1527. #define is_pair(p) (type(p) == T_PAIR)
  1528. #define is_null(p) ((_NFre(p)) == sc->nil)
  1529. #define is_not_null(p) ((_NFre(p)) != sc->nil)
  1530. #if (!DEBUGGING)
  1531. #define opt1(p, r) ((p)->object.cons.opt1)
  1532. #define set_opt1(p, x, r) (p)->object.cons.opt1 = x
  1533. #define opt2(p, r) ((p)->object.cons.opt2)
  1534. #define set_opt2(p, x, r) (p)->object.cons.opt2 = (s7_pointer)(x)
  1535. #define opt3(p, r) ((p)->object.cons.opt3)
  1536. #define set_opt3(p, x, r) do {(p)->object.cons.opt3 = x; typeflag(p) &= ~(T_OPTIMIZED | T_LINE_NUMBER);} while (0)
  1537. #define pair_line(p) (p)->object.sym_cons.line
  1538. #define pair_set_line(p, X) (p)->object.sym_cons.line = X
  1539. #define pair_raw_hash(p) (p)->object.sym_cons.hash
  1540. #define pair_set_raw_hash(p, X) (p)->object.sym_cons.hash = X
  1541. #define pair_raw_len(p) (p)->object.sym_cons.op
  1542. #define pair_set_raw_len(p, X) (p)->object.sym_cons.op = X
  1543. #define pair_raw_name(p) (p)->object.sym_cons.fstr
  1544. #define pair_set_raw_name(p, X) (p)->object.sym_cons.fstr = X
  1545. /* opt1 == raw_hash, opt2 == raw_name, opt3 == line+op|len, but hash/name/len only apply to the symbol table so there's no collision */
  1546. #else
  1547. /* these 3 fields (or 8 counting sym_cons) hold most of the varigated optimizer info, so they are used in many conflicting ways.
  1548. * the bits and funcs here try to track each such use, and report any cross-talk or collisions.
  1549. * all of this machinery vanishes if debugging is turned off.
  1550. */
  1551. #define S_NAME (1 << 26)
  1552. #define S_HASH (1 << 27)
  1553. #define S_OP (1 << 28)
  1554. #define S_LINE (1 << 29)
  1555. #define S_LEN (1 << 30)
  1556. #define S_SYNOP 0x80000000 /* (1 << 31) */
  1557. #define E_SET (1 << 0)
  1558. #define E_FAST (1 << 6) /* fast list in member/assoc circular list check */
  1559. #define E_CFUNC (1 << 7) /* c-function */
  1560. #define E_CLAUSE (1 << 8) /* case clause */
  1561. #define E_BACK (1 << 9) /* back pointer for doubly-linked list */
  1562. #define E_LAMBDA (1 << 10) /* lambda(*) */
  1563. #define E_SYM (1 << 11) /* symbol */
  1564. #define E_PAIR (1 << 12) /* pair */
  1565. #define E_CON (1 << 13) /* constant from eval's point of view */
  1566. #define E_GOTO (1 << 14) /* call-with-exit exit func */
  1567. #define E_VECTOR (1 << 15) /* vector (any kind) */
  1568. #define E_ANY (1 << 16) /* anything -- deliberate unchecked case */
  1569. #define E_SLOT (1 << 17) /* slot */
  1570. #define E_MASK (E_FAST | E_CFUNC | E_CLAUSE | E_BACK | E_LAMBDA | E_SYM | E_PAIR | E_CON | E_GOTO | E_VECTOR | E_ANY | E_SLOT | S_HASH)
  1571. #define opt1_is_set(p) (((p)->debugger_bits & E_SET) != 0)
  1572. #define set_opt1_is_set(p) (p)->debugger_bits |= E_SET
  1573. #define opt1_role_matches(p, Role) (((p)->debugger_bits & E_MASK) == Role)
  1574. #define set_opt1_role(p, Role) (p)->debugger_bits = (Role | ((p)->debugger_bits & ~E_MASK))
  1575. #define opt1(p, Role) opt1_1(hidden_sc, _TPair(p), Role, __func__, __LINE__)
  1576. #define set_opt1(p, x, Role) set_opt1_1(hidden_sc, _TPair(p), x, Role, __func__, __LINE__)
  1577. #define F_SET (1 << 1) /* bit 18 is free */
  1578. #define F_KEY (1 << 19) /* case key */
  1579. #define F_SLOW (1 << 20) /* slow list in member/assoc circular list check */
  1580. #define F_SYM (1 << 21) /* symbol */
  1581. #define F_PAIR (1 << 22) /* pair */
  1582. #define F_CON (1 << 23) /* constant as above */
  1583. #define F_CALL (1 << 24) /* c-func */
  1584. #define F_LAMBDA (1 << 25) /* lambda form */
  1585. #define F_MASK (F_KEY | F_SLOW | F_SYM | F_PAIR | F_CON | F_CALL | F_LAMBDA | S_NAME)
  1586. #define opt2_is_set(p) (((p)->debugger_bits & F_SET) != 0)
  1587. #define set_opt2_is_set(p) (p)->debugger_bits |= F_SET
  1588. #define opt2_role_matches(p, Role) (((p)->debugger_bits & F_MASK) == Role)
  1589. #define set_opt2_role(p, Role) (p)->debugger_bits = (Role | ((p)->debugger_bits & ~F_MASK))
  1590. #define opt2(p, Role) opt2_1(hidden_sc, _TPair(p), Role, __func__, __LINE__)
  1591. #define set_opt2(p, x, Role) set_opt2_1(hidden_sc, _TPair(p), (s7_pointer)x, Role, __func__, __LINE__)
  1592. /* opt3 collides with optimization and line number stuff (T_LINE_NUMBER, T_OPTIMIZED) */
  1593. #define G_SET (1 << 2)
  1594. #define G_ARGLEN (1 << 3) /* arglist length */
  1595. #define G_SYM (1 << 4) /* expression symbol access */
  1596. #define G_AND (1 << 5) /* and second clause */
  1597. #define G_MASK (G_ARGLEN | G_SYM | G_AND | S_OP | S_LINE | S_LEN | S_SYNOP)
  1598. #define opt3_is_set(p) (((p)->debugger_bits & G_SET) != 0)
  1599. #define set_opt3_is_set(p) (p)->debugger_bits |= G_SET
  1600. #define opt3_role_matches(p, Role) (((p)->debugger_bits & G_MASK) == Role)
  1601. #define set_opt3_role(p, Role) (p)->debugger_bits = (Role | ((p)->debugger_bits & ~G_MASK))
  1602. #define opt3(p, Role) opt3_1(hidden_sc, _TPair(p), Role, __func__, __LINE__)
  1603. #define set_opt3(p, x, Role) set_opt3_1(hidden_sc, _TPair(p), x, Role, __func__, __LINE__)
  1604. /* opt1 == s_hash, opt2 == s_fstr, opt3 == s_op|len|line and op==len so they are contradictory (but only op/line|opt3 actually collide)
  1605. * line|len|op: unsigned int set G_SET and S_* if S_LEN -> not op and vice versa
  1606. * another collider: pair_syntax_op|optimize_op below. Both need bits: S_SYNOP?
  1607. */
  1608. #define pair_line(p) s_line_1(sc, _TPair(p), __func__, __LINE__)
  1609. #define pair_set_line(p, X) set_s_line_1(sc, _TPair(p), X, __func__, __LINE__)
  1610. #define pair_raw_hash(p) s_hash_1(sc, _TPair(p), __func__, __LINE__)
  1611. #define pair_set_raw_hash(p, X) set_s_hash_1(sc, _TPair(p), X, __func__, __LINE__)
  1612. #define pair_raw_len(p) s_len_1(sc, _TPair(p), __func__, __LINE__)
  1613. #define pair_set_raw_len(p, X) set_s_len_1(sc, _TPair(p), X, __func__, __LINE__)
  1614. #define pair_raw_name(p) s_name_1(sc, _TPair(p), __func__, __LINE__)
  1615. #define pair_set_raw_name(p, X) set_s_name_1(sc, _TPair(p), X, __func__, __LINE__)
  1616. #endif
  1617. #define opt_fast(P) _TLst(opt1(P, E_FAST))
  1618. #define set_opt_fast(P, X) set_opt1(P, _TPair(X), E_FAST)
  1619. #define opt_back(P) _TPair(opt1(P, E_BACK))
  1620. #define set_opt_back(P) set_opt1(cdr(P), _TPair(P), E_BACK)
  1621. #define has_opt_back(P) (cdr(opt_back(P)) == P )
  1622. #define opt_cfunc(P) opt1(P, E_CFUNC)
  1623. #define set_opt_cfunc(P, X) set_opt1(P, X, E_CFUNC)
  1624. #define opt_lambda_unchecked(P) opt1(P, E_LAMBDA)
  1625. #define opt_lambda(P) _TClo(opt1(P, E_LAMBDA))
  1626. #define set_opt_lambda(P, X) set_opt1(P, X, E_LAMBDA)
  1627. #define opt_goto(P) _TGot(opt1(P, E_GOTO))
  1628. #define set_opt_goto(P, X) set_opt1(P, _TGot(X), E_GOTO)
  1629. #define opt_vector(P) _TVec(opt1(P, E_VECTOR))
  1630. #define set_opt_vector(P, X) set_opt1(P, _TVec(X), E_VECTOR)
  1631. #define opt_clause(P) opt1(P, E_CLAUSE)
  1632. #define set_opt_clause(P, X) set_opt1(P, X, E_CLAUSE)
  1633. #define opt_sym1(P) _TSym(opt1(P, E_SYM))
  1634. #define set_opt_sym1(P, X) set_opt1(P, _TSym(X), E_SYM)
  1635. #define opt_pair1(P) _TLst(opt1(P, E_PAIR))
  1636. #define set_opt_pair1(P, X) set_opt1(P, _TLst(X), E_PAIR)
  1637. #define opt_con1(P) opt1(P, E_CON)
  1638. #define set_opt_con1(P, X) set_opt1(P, X, E_CON)
  1639. #define opt_any1(P) opt1(P, E_ANY)
  1640. #define opt_slot1(P) _TSlt(opt1(P, E_SLOT))
  1641. #define set_opt_slot1(P, X) set_opt1(P, _TSlt(X), E_SLOT)
  1642. #define c_callee(f) ((s7_function)opt2(f, F_CALL))
  1643. #define c_call(f) ((s7_function)opt2(f, F_CALL))
  1644. #define set_c_call(f, X) set_opt2(f, (s7_pointer)X, F_CALL)
  1645. #define opt_key(P) opt2(P, F_KEY)
  1646. #define set_opt_key(P, X) set_opt2(P, X, F_KEY)
  1647. #define opt_slow(P) _TLst(opt2(P, F_SLOW))
  1648. #define set_opt_slow(P, X) set_opt2(P, _TPair(X), F_SLOW)
  1649. #define opt_sym2(P) _TSym(opt2(P, F_SYM))
  1650. #define set_opt_sym2(P, X) set_opt2(P, _TSym(X), F_SYM)
  1651. #define opt_pair2(P) _TLst(opt2(P, F_PAIR))
  1652. #define set_opt_pair2(P, X) set_opt2(P, _TLst(X), F_PAIR)
  1653. #define opt_con2(P) opt2(P, F_CON)
  1654. #define set_opt_con2(P, X) set_opt2(P, X, F_CON)
  1655. #define opt_lambda2(P) _TPair(opt2(P, F_LAMBDA))
  1656. #define set_opt_lambda2(P, X) set_opt2(P, _TPair(X), F_LAMBDA)
  1657. #define arglist_length(P) _TI(opt3(cdr(P), G_ARGLEN))
  1658. #define set_arglist_length(P, X) set_opt3(cdr(P), _TI(X), G_ARGLEN)
  1659. #define opt_sym3(P) _TSym(opt3(P, G_SYM))
  1660. #define set_opt_sym3(P, X) set_opt3(P, _TSym(X), G_SYM)
  1661. #define opt_and_2_test(P) _TPair(opt3(P, G_AND))
  1662. #define set_opt_and_2_test(P, X) set_opt3(P, _TPair(X), G_AND)
  1663. #define car(p) (_TLst(p))->object.cons.car
  1664. #define set_car(p, Val) (_TLst(p))->object.cons.car = _NFre(Val)
  1665. #define cdr(p) (_TLst(p))->object.cons.cdr
  1666. #define set_cdr(p, Val) (_TLst(p))->object.cons.cdr = _NFre(Val)
  1667. #define unchecked_car(p) (_NFre(p))->object.cons.car
  1668. #define unchecked_cdr(p) (_NFre(p))->object.cons.cdr
  1669. #define caar(p) car(car(p))
  1670. #define cadr(p) car(cdr(p))
  1671. #define set_cadr(p, Val) (_TLst(p))->object.cons.cdr->object.cons.car = _NFre(Val)
  1672. #define cdar(p) cdr(car(p))
  1673. #define set_cdar(p, Val) (_TLst(p))->object.cons.car->object.cons.cdr = _NFre(Val)
  1674. #define cddr(p) cdr(cdr(p))
  1675. #define caaar(p) car(car(car(p)))
  1676. #define cadar(p) car(cdr(car(p)))
  1677. #define cdadr(p) cdr(car(cdr(p)))
  1678. #define caddr(p) car(cdr(cdr(p)))
  1679. #define set_caddr(p, Val) (_TLst(p))->object.cons.cdr->object.cons.cdr->object.cons.car = _NFre(Val)
  1680. #define caadr(p) car(car(cdr(p)))
  1681. #define cdaar(p) cdr(car(car(p)))
  1682. #define cdddr(p) cdr(cdr(cdr(p)))
  1683. #define cddar(p) cdr(cdr(car(p)))
  1684. #define caaadr(p) car(car(car(cdr(p))))
  1685. #define caadar(p) car(car(cdr(car(p))))
  1686. #define cadaar(p) car(cdr(car(car(p))))
  1687. #define cadddr(p) car(cdr(cdr(cdr(p))))
  1688. #define caaddr(p) car(car(cdr(cdr(p))))
  1689. #define cddddr(p) cdr(cdr(cdr(cdr(p))))
  1690. #define caddar(p) car(cdr(cdr(car(p))))
  1691. #define cdadar(p) cdr(car(cdr(car(p))))
  1692. #define cdaddr(p) cdr(car(cdr(cdr(p))))
  1693. #define caaaar(p) car(car(car(car(p))))
  1694. #define cadadr(p) car(cdr(car(cdr(p))))
  1695. #define cdaadr(p) cdr(car(car(cdr(p))))
  1696. #define cdaaar(p) cdr(car(car(car(p))))
  1697. #define cdddar(p) cdr(cdr(cdr(car(p))))
  1698. #define cddadr(p) cdr(cdr(car(cdr(p))))
  1699. #define cddaar(p) cdr(cdr(car(car(p))))
  1700. #if WITH_GCC
  1701. /* slightly tricky because cons can be called recursively */
  1702. #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_;})
  1703. #else
  1704. #define cons(Sc, A, B) s7_cons(Sc, A, B)
  1705. #endif
  1706. #define list_1(Sc, A) cons(Sc, A, Sc->nil)
  1707. #define list_2(Sc, A, B) cons_unchecked(Sc, A, cons(Sc, B, Sc->nil))
  1708. #define list_3(Sc, A, B, C) cons_unchecked(Sc, A, cons_unchecked(Sc, B, cons(Sc, C, Sc->nil)))
  1709. #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))))
  1710. #define is_string(p) (type(p) == T_STRING)
  1711. #define string_value(p) (_TStr(p))->object.string.svalue
  1712. #define string_length(p) (_TStr(p))->object.string.length
  1713. #define string_hash(p) (_TStr(p))->object.string.hash
  1714. #define string_needs_free(p) (_TStr(p))->object.string.str_ext.needs_free
  1715. #define string_temp_true_length(p) (_TStr(p))->object.string.str_ext.accessor
  1716. #define tmpbuf_malloc(P, Len) do {if ((Len) < TMPBUF_SIZE) P = sc->tmpbuf; else P = (char *)malloc((Len) * sizeof(char));} while (0)
  1717. #define tmpbuf_calloc(P, Len) do {if ((Len) < TMPBUF_SIZE) {P = sc->tmpbuf; memset((void *)P, 0, Len);} else P = (char *)calloc(Len, sizeof(char));} while (0)
  1718. #define tmpbuf_free(P, Len) do {if ((Len) >= TMPBUF_SIZE) free(P);} while (0)
  1719. #define character(p) (_TChr(p))->object.chr.c
  1720. #define upper_character(p) (_TChr(p))->object.chr.up_c
  1721. #define is_char_alphabetic(p) (_TChr(p))->object.chr.alpha_c
  1722. #define is_char_numeric(p) (_TChr(p))->object.chr.digit_c
  1723. #define is_char_whitespace(p) (_TChr(p))->object.chr.space_c
  1724. #define is_char_uppercase(p) (_TChr(p))->object.chr.upper_c
  1725. #define is_char_lowercase(p) (_TChr(p))->object.chr.lower_c
  1726. #define character_name(p) (_TChr(p))->object.chr.c_name
  1727. #define character_name_length(p) (_TChr(p))->object.chr.length
  1728. #if (!DEBUGGING)
  1729. #define optimize_op(p) (_TPair(p))->object.sym_cons.op
  1730. #define set_optimize_op(P, Op) optimize_op(P) = Op
  1731. #else
  1732. #define optimize_op(p) s_op_1(hidden_sc, _TPair(p), __func__, __LINE__)
  1733. #define set_optimize_op(p, Op) set_s_op_1(hidden_sc, _TPair(p), Op, __func__, __LINE__)
  1734. #endif
  1735. #define optimize_op_match(P, Q) ((is_optimized(P)) && ((optimize_op(P) & 0xfffe) == Q))
  1736. #define op_no_hop(P) (optimize_op(P) & 0xfffe)
  1737. #define clear_hop(P) set_optimize_op(P, op_no_hop(P))
  1738. #define clear_optimize_op(P) set_optimize_op(P, 0)
  1739. #define set_safe_optimize_op(P, Q) do {set_optimized(P); set_optimize_op(P, Q);} while (0)
  1740. #define set_unsafe_optimize_op(P, Q) do {set_unsafely_optimized(P); set_optimize_op(P, Q);} while (0)
  1741. #define is_symbol(p) (type(p) == T_SYMBOL)
  1742. #define symbol_name_cell(p) _TStr((_TSym(p))->object.sym.name)
  1743. #define symbol_set_name_cell(p, S) (_TSym(p))->object.sym.name = _TStr(S)
  1744. #define symbol_name(p) string_value(symbol_name_cell(p))
  1745. #define symbol_name_length(p) string_length(symbol_name_cell(p))
  1746. #define symbol_hmap(p) s7_int_abs(heap_location(p))
  1747. #define symbol_global_accessor_index(p) (symbol_name_cell(p))->object.string.str_ext.accessor
  1748. #define symbol_id(p) (_TSym(p))->object.sym.id
  1749. #define symbol_set_id(p, X) (_TSym(p))->object.sym.id = X
  1750. /* we need 64-bits here, since we don't want this thing to wrap around, and frames are created at a great rate
  1751. * callgrind says this is faster than an unsigned int!
  1752. */
  1753. #define symbol_syntax_op(p) (_TSym(p))->object.sym.op
  1754. #define global_slot(p) (_TSym(p))->object.sym.global_slot
  1755. #define set_global_slot(p, Val) (_TSym(p))->object.sym.global_slot = _TSld(Val)
  1756. #define initial_slot(p) (symbol_name_cell(p))->object.string.initial_slot
  1757. #define set_initial_slot(p, Val) (symbol_name_cell(p))->object.string.initial_slot = _TSld(Val)
  1758. #define local_slot(p) (_TSym(p))->object.sym.local_slot
  1759. #define set_local_slot(p, Val) (_TSym(p))->object.sym.local_slot = _TSln(Val)
  1760. #define keyword_symbol(p) (symbol_name_cell(p))->object.string.doc.ksym
  1761. #define keyword_set_symbol(p, Val) (symbol_name_cell(p))->object.string.doc.ksym = _TSym(Val)
  1762. #define symbol_help(p) (symbol_name_cell(p))->object.string.doc.documentation
  1763. #define symbol_tag(p) (_TSym(p))->object.sym.tag
  1764. #define symbol_set_tag(p, Val) (_TSym(p))->object.sym.tag = Val
  1765. #define symbol_has_help(p) (is_documented(symbol_name_cell(p)))
  1766. #define symbol_set_has_help(p) set_documented(symbol_name_cell(p))
  1767. #define symbol_set_local(Symbol, Id, Slot) do {set_local_slot(Symbol, Slot); symbol_set_id(Symbol, Id);} while (0)
  1768. /* set slot before id in case Slot is an expression that tries to find the current Symbol slot (using its old Id obviously) */
  1769. #define is_slot(p) (type(p) == T_SLOT)
  1770. #define slot_value(p) _NFre((_TSlt(p))->object.slt.val)
  1771. #define slot_set_value(p, Val) (_TSlt(p))->object.slt.val = _NFre(Val)
  1772. #define slot_symbol(p) _TSym((_TSlt(p))->object.slt.sym)
  1773. #define slot_set_symbol(p, Sym) (_TSlt(p))->object.slt.sym = _TSym(Sym)
  1774. #define next_slot(p) (_TSlt(p))->object.slt.nxt
  1775. #define set_next_slot(p, Val) (_TSlt(p))->object.slt.nxt = _TSln(Val)
  1776. #define slot_pending_value(p) (_TSlt(p))->object.slt.pending_value
  1777. #define slot_set_pending_value(p, Val) (_TSlt(p))->object.slt.pending_value = _NFre(Val)
  1778. #define slot_expression(p) (_TSlt(p))->object.slt.expr
  1779. #define slot_set_expression(p, Val) (_TSlt(p))->object.slt.expr = _NFre(Val)
  1780. #define slot_accessor(p) slot_expression(p)
  1781. #define slot_set_accessor(p, Val) slot_expression(p) = _TApp(Val)
  1782. #define is_syntax(p) (type(p) == T_SYNTAX)
  1783. #define syntax_symbol(p) _TSym((_TSyn(p))->object.syn.symbol)
  1784. #define syntax_set_symbol(p, Sym) (_TSyn(p))->object.syn.symbol = _TSym(Sym)
  1785. #define syntax_opcode(p) (_TSyn(p))->object.syn.op
  1786. #define syntax_min_args(p) (_TSyn(p))->object.syn.min_args
  1787. #define syntax_max_args(p) (_TSyn(p))->object.syn.max_args
  1788. #define syntax_documentation(p) sc->syn_docs[syntax_opcode(p)]
  1789. #define syntax_rp(p) (_TSyn(p))->object.syn.rp
  1790. #define syntax_ip(p) (_TSyn(p))->object.syn.ip
  1791. #define syntax_pp(p) (_TSyn(p))->object.syn.pp
  1792. #if (!DEBUGGING)
  1793. #define pair_syntax_op(p) (p)->object.sym_cons.op
  1794. #define pair_set_syntax_op(p, X) (p)->object.sym_cons.op = X
  1795. #else
  1796. #define pair_syntax_op(p) s_syn_op_1(hidden_sc, _TPair(p), __func__, __LINE__)
  1797. #define pair_set_syntax_op(p, Op) set_s_syn_op_1(hidden_sc, _TPair(p), Op, __func__, __LINE__)
  1798. #endif
  1799. #define pair_syntax_symbol(P) car(opt_back(P))
  1800. static void pair_set_syntax_symbol(s7_pointer p, s7_pointer op) {set_car(opt_back(p), op); pair_set_syntax_op(opt_back(p), symbol_syntax_op(op));}
  1801. #define ROOTLET_SIZE 512
  1802. #define let_id(p) (_TLid(p))->object.envr.id
  1803. #define is_let(p) (type(p) == T_LET)
  1804. #define let_slots(p) (_TLet(p))->object.envr.slots
  1805. #define let_set_slots(p, Slot) (_TLet(p))->object.envr.slots = _TSln(Slot)
  1806. #define outlet(p) (_TLet(p))->object.envr.nxt
  1807. #define set_outlet(p, ol) (_TLet(p))->object.envr.nxt = _TLid(ol)
  1808. #define funclet_function(p) _TSym((_TLet(p))->object.envr.edat.efnc.function)
  1809. #define funclet_set_function(p, F) (_TLet(p))->object.envr.edat.efnc.function = _TSym(F)
  1810. #define let_line(p) (_TLet(p))->object.envr.edat.efnc.line
  1811. #define let_set_line(p, L) (_TLet(p))->object.envr.edat.efnc.line = L
  1812. #define let_file(p) (_TLet(p))->object.envr.edat.efnc.file
  1813. #define let_set_file(p, F) (_TLet(p))->object.envr.edat.efnc.file = F
  1814. #define dox_slot1(p) _TSlt((_TLet(p))->object.envr.edat.dox.dox1)
  1815. #define dox_set_slot1(p, S) (_TLet(p))->object.envr.edat.dox.dox1 = _TSlt(S)
  1816. #define dox_slot2(p) _TSlt((_TLet(p))->object.envr.edat.dox.dox2)
  1817. #define dox_set_slot2(p, S) (_TLet(p))->object.envr.edat.dox.dox2 = _TSlt(S)
  1818. #define unique_name(p) (p)->object.unq.name
  1819. #define unique_name_length(p) (p)->object.unq.len
  1820. #define is_unspecified(p) (type(p) == T_UNSPECIFIED)
  1821. #define unique_cdr(p) (p)->object.unq.unused_nxt
  1822. #define vector_length(p) ((p)->object.vector.length)
  1823. #define vector_element(p, i) ((p)->object.vector.elements.objects[i])
  1824. #define vector_elements(p) (p)->object.vector.elements.objects
  1825. #define vector_getter(p) (_TVec(p))->object.vector.vget
  1826. #define vector_setter(p) (_TVec(p))->object.vector.vset
  1827. #define int_vector_element(p, i) ((_TIvc(p))->object.vector.elements.ints[i])
  1828. #define int_vector_elements(p) (_TIvc(p))->object.vector.elements.ints
  1829. #define float_vector_element(p, i) ((_TFvc(p))->object.vector.elements.floats[i])
  1830. #define float_vector_elements(p) (_TFvc(p))->object.vector.elements.floats
  1831. #define is_normal_vector(p) (type(p) == T_VECTOR)
  1832. #define is_int_vector(p) (type(p) == T_INT_VECTOR)
  1833. #define is_float_vector(p) (type(p) == T_FLOAT_VECTOR)
  1834. #define vector_ndims(p) ((_TVec(p))->object.vector.dim_info->ndims)
  1835. #define vector_dimension(p, i) ((_TVec(p))->object.vector.dim_info->dims[i])
  1836. #define vector_dimensions(p) ((_TVec(p))->object.vector.dim_info->dims)
  1837. #define vector_offset(p, i) ((_TVec(p))->object.vector.dim_info->offsets[i])
  1838. #define vector_offsets(p) ((_TVec(p))->object.vector.dim_info->offsets)
  1839. #define vector_dimension_info(p) ((_TVec(p))->object.vector.dim_info)
  1840. #define shared_vector(p) ((_TVec(p))->object.vector.dim_info->original)
  1841. #define vector_rank(p) ((vector_dimension_info(p)) ? vector_ndims(p) : 1)
  1842. #define vector_has_dimensional_info(p) (vector_dimension_info(p))
  1843. #define vector_elements_allocated(p) ((_TVec(p))->object.vector.dim_info->elements_allocated)
  1844. #define vector_dimensions_allocated(p) ((_TVec(p))->object.vector.dim_info->dimensions_allocated)
  1845. #define is_hash_table(p) (type(p) == T_HASH_TABLE)
  1846. #define hash_table_mask(p) (_THsh(p))->object.hasher.mask
  1847. #define hash_table_element(p, i) ((_THsh(p))->object.hasher.elements[i])
  1848. #define hash_table_elements(p) (_THsh(p))->object.hasher.elements
  1849. #define hash_table_entries(p) (_THsh(p))->object.hasher.entries
  1850. #define hash_table_checker(p) (_THsh(p))->object.hasher.hash_func
  1851. #define hash_table_mapper(p) (_THsh(p))->object.hasher.loc
  1852. #define hash_table_checker_locked(p) (hash_table_mapper(p) != default_hash_map)
  1853. #define hash_table_procedures(p) _TLst((_THsh(p))->object.hasher.dproc)
  1854. #define hash_table_set_procedures(p, Lst) (_THsh(p))->object.hasher.dproc = _TLst(Lst)
  1855. #define hash_table_procedures_checker(p) car(hash_table_procedures(p))
  1856. #define hash_table_procedures_mapper(p) cdr(hash_table_procedures(p))
  1857. #define is_iterator(p) (type(p) == T_ITERATOR)
  1858. #define iterator_sequence(p) (_TItr(p))->object.iter.obj
  1859. #define iterator_position(p) (_TItr(p))->object.iter.lc.loc
  1860. #define iterator_length(p) (_TItr(p))->object.iter.lw.len
  1861. #define iterator_slow(p) _TLst((_TItr(p))->object.iter.lw.slow)
  1862. #define iterator_set_slow(p, Val) (_TItr(p))->object.iter.lw.slow = _TLst(Val)
  1863. #define iterator_hash_current(p) (_TItr(p))->object.iter.lw.hcur
  1864. #define iterator_current(p) (_TItr(p))->object.iter.cur
  1865. #define iterator_current_slot(p) _TSln((_TItr(p))->object.iter.lc.lcur)
  1866. #define iterator_set_current_slot(p, Val) (_TItr(p))->object.iter.lc.lcur = _TSln(Val)
  1867. #define iterator_let_cons(p) (_TItr(p))->object.iter.cur
  1868. #define iterator_next(p) (_TItr(p))->object.iter.next
  1869. #define iterator_is_at_end(p) (iterator_next(p) == iterator_finished)
  1870. #define ITERATOR_END eof_object
  1871. #define ITERATOR_END_NAME "#<eof>"
  1872. #define is_input_port(p) (type(p) == T_INPUT_PORT)
  1873. #define is_output_port(p) (type(p) == T_OUTPUT_PORT)
  1874. #define port_port(p) (_TPrt(p))->object.prt.port
  1875. #define port_type(p) (_TPrt(p))->object.prt.ptype
  1876. #define is_string_port(p) (port_type(p) == STRING_PORT)
  1877. #define is_file_port(p) (port_type(p) == FILE_PORT)
  1878. #define is_function_port(p) (port_type(p) == FUNCTION_PORT)
  1879. #define port_line_number(p) (_TPrt(p))->object.prt.line_number
  1880. #define port_file_number(p) (_TPrt(p))->object.prt.file_number
  1881. #define port_filename(p) port_port(p)->filename
  1882. #define port_filename_length(p) port_port(p)->filename_length
  1883. #define port_file(p) port_port(p)->file
  1884. #define port_is_closed(p) (_TPrt(p))->object.prt.is_closed
  1885. #define port_data(p) (_TPrt(p))->object.prt.data
  1886. #define port_data_size(p) (_TPrt(p))->object.prt.size
  1887. #define port_position(p) (_TPrt(p))->object.prt.point
  1888. #define port_needs_free(p) port_port(p)->needs_free
  1889. #define port_output_function(p) port_port(p)->output_function
  1890. #define port_input_function(p) port_port(p)->input_function
  1891. #define port_original_input_string(p) port_port(p)->orig_str
  1892. #define port_read_character(p) port_port(p)->read_character
  1893. #define port_read_line(p) port_port(p)->read_line
  1894. #define port_display(p) port_port(p)->display
  1895. #define port_write_character(p) port_port(p)->write_character
  1896. #define port_write_string(p) port_port(p)->write_string
  1897. #define port_read_semicolon(p) port_port(p)->read_semicolon
  1898. #define port_read_white_space(p) port_port(p)->read_white_space
  1899. #define port_read_name(p) port_port(p)->read_name
  1900. #define port_read_sharp(p) port_port(p)->read_sharp
  1901. #define port_gc_loc(p) port_port(p)->gc_loc
  1902. #define is_c_function(f) (type(f) >= T_C_FUNCTION)
  1903. #define is_c_function_star(f) (type(f) == T_C_FUNCTION_STAR)
  1904. #define is_any_c_function(f) (type(f) >= T_C_FUNCTION_STAR)
  1905. #define c_function_data(f) (_TFnc(f))->object.fnc.c_proc
  1906. #define c_function_call(f) (_TFnc(f))->object.fnc.ff
  1907. #define c_function_required_args(f) (_TFnc(f))->object.fnc.required_args
  1908. #define c_function_optional_args(f) (_TFnc(f))->object.fnc.optional_args
  1909. #define c_function_has_rest_arg(f) (_TFnc(f))->object.fnc.rest_arg
  1910. #define c_function_all_args(f) (_TFnc(f))->object.fnc.all_args
  1911. #define c_function_setter(f) _TApp((_TFnc(f))->object.fnc.setter)
  1912. #define c_function_set_setter(f, Val) (_TFnc(f))->object.fnc.setter = _TApp(Val)
  1913. #define c_function_name(f) c_function_data(f)->name
  1914. #define c_function_name_length(f) c_function_data(f)->name_length
  1915. #define c_function_documentation(f) c_function_data(f)->doc
  1916. #define c_function_signature(f) c_function_data(f)->signature
  1917. #define c_function_class(f) c_function_data(f)->id
  1918. #define c_function_chooser(f) c_function_data(f)->chooser
  1919. #define c_function_base(f) _TApp(c_function_data(f)->generic_ff)
  1920. #define c_function_set_base(f, Val) c_function_data(f)->generic_ff = _TApp(Val)
  1921. #define c_function_arg_defaults(f) c_function_data(f)->arg_defaults
  1922. #define c_function_call_args(f) c_function_data(f)->call_args
  1923. #define c_function_arg_names(f) c_function_data(f)->arg_names
  1924. #define c_function_rp(f) c_function_data(f)->rp
  1925. #define c_function_ip(f) c_function_data(f)->ip
  1926. #define c_function_pp(f) c_function_data(f)->pp
  1927. #define c_function_gp(f) c_function_data(f)->gp
  1928. #define set_c_function(f, X) do {set_opt_cfunc(f, X); set_c_call(f, c_function_call(opt_cfunc(f)));} while (0)
  1929. #define is_c_macro(p) (type(p) == T_C_MACRO)
  1930. #define c_macro_data(f) (_TMac(f))->object.fnc.c_proc
  1931. #define c_macro_call(f) (_TMac(f))->object.fnc.ff
  1932. #define c_macro_name(f) c_macro_data(f)->name
  1933. #define c_macro_name_length(f) c_macro_data(f)->name_length
  1934. #define c_macro_required_args(f) (_TMac(f))->object.fnc.required_args
  1935. #define c_macro_all_args(f) (_TMac(f))->object.fnc.all_args
  1936. #define c_macro_setter(f) _TApp((_TMac(f))->object.fnc.setter)
  1937. #define c_macro_set_setter(f, Val) (_TMac(f))->object.fnc.setter = _TApp(Val)
  1938. #define is_random_state(p) (type(p) == T_RANDOM_STATE)
  1939. #if WITH_GMP
  1940. #define random_gmp_state(p) (_TRan(p))->object.rng.state
  1941. #else
  1942. #define random_seed(p) (_TRan(p))->object.rng.seed
  1943. #define random_carry(p) (_TRan(p))->object.rng.carry
  1944. #endif
  1945. #define continuation_data(p) (_TCon(p))->object.cwcc.continuation
  1946. #define continuation_stack(p) (_TCon(p))->object.cwcc.stack
  1947. #define continuation_set_stack(p, Val) (_TCon(p))->object.cwcc.stack = _TStk(Val)
  1948. #define continuation_stack_end(p) (_TCon(p))->object.cwcc.stack_end
  1949. #define continuation_stack_start(p) (_TCon(p))->object.cwcc.stack_start
  1950. #define continuation_stack_size(p) (_TCon(p))->object.cwcc.continuation->stack_size
  1951. #define continuation_stack_top(p) (continuation_stack_end(p) - continuation_stack_start(p))
  1952. #define continuation_op_stack(p) (_TCon(p))->object.cwcc.op_stack
  1953. #define continuation_op_loc(p) (_TCon(p))->object.cwcc.continuation->op_stack_loc
  1954. #define continuation_op_size(p) (_TCon(p))->object.cwcc.continuation->op_stack_size
  1955. #define continuation_key(p) (_TCon(p))->object.cwcc.continuation->local_key
  1956. #define call_exit_goto_loc(p) (_TGot(p))->object.rexit.goto_loc
  1957. #define call_exit_op_loc(p) (_TGot(p))->object.rexit.op_stack_loc
  1958. #define call_exit_active(p) (_TGot(p))->object.rexit.active
  1959. #define temp_stack_top(p) (_TStk(p))->object.stk.top
  1960. #define s7_stack_top(Sc) ((Sc)->stack_end - (Sc)->stack_start)
  1961. #define is_continuation(p) (type(p) == T_CONTINUATION)
  1962. #define is_goto(p) (type(p) == T_GOTO)
  1963. #define is_macro(p) (type(p) == T_MACRO)
  1964. /* #define is_bacro(p) (type(p) == T_BACRO) */
  1965. #define is_macro_star(p) (type(p) == T_MACRO_STAR)
  1966. #define is_bacro_star(p) (type(p) == T_BACRO_STAR)
  1967. #define is_closure(p) (type(p) == T_CLOSURE)
  1968. #define is_closure_star(p) (type(p) == T_CLOSURE_STAR)
  1969. #define closure_args(p) (_TClo(p))->object.func.args
  1970. #define closure_set_args(p, Val) (_TClo(p))->object.func.args = _TArg(Val)
  1971. #define closure_body(p) (_TPair((_TClo(p))->object.func.body))
  1972. #define closure_set_body(p, Val) (_TClo(p))->object.func.body = _TPair(Val)
  1973. #define closure_let(p) _TLid((_TClo(p))->object.func.env)
  1974. #define closure_set_let(p, L) (_TClo(p))->object.func.env = _TLid(L)
  1975. #define closure_setter(p) _TApp((_TClo(p))->object.func.setter)
  1976. #define closure_set_setter(p, Val) (_TClo(p))->object.func.setter = _TApp(Val)
  1977. #define closure_arity(p) (_TClo(p))->object.func.arity
  1978. #define CLOSURE_ARITY_NOT_SET 0x40000000
  1979. #define MAX_ARITY 0x20000000
  1980. #define closure_arity_unknown(p) (closure_arity(p) == CLOSURE_ARITY_NOT_SET)
  1981. #define is_thunk(Sc, Fnc) ((type(Fnc) >= T_GOTO) && (s7_is_aritable(Sc, Fnc, 0)))
  1982. #define hook_has_functions(p) (is_pair(s7_hook_functions(sc, _TClo(p))))
  1983. #define catch_tag(p) (_TCat(p))->object.rcatch.tag
  1984. #define catch_goto_loc(p) (_TCat(p))->object.rcatch.goto_loc
  1985. #define catch_op_loc(p) (_TCat(p))->object.rcatch.op_stack_loc
  1986. #define catch_handler(p) (_TCat(p))->object.rcatch.handler
  1987. #define catch_all_goto_loc(p) (_TLet(p))->object.envr.edat.ctall.goto_loc
  1988. #define catch_all_set_goto_loc(p, L) (_TLet(p))->object.envr.edat.ctall.goto_loc = L
  1989. #define catch_all_op_loc(p) (_TLet(p))->object.envr.edat.ctall.op_stack_loc
  1990. #define catch_all_set_op_loc(p, L) (_TLet(p))->object.envr.edat.ctall.op_stack_loc = L
  1991. #define catch_all_result(p) _NFre((_TLet(p))->object.envr.edat.ctall.result)
  1992. #define catch_all_set_result(p, R) (_TLet(p))->object.envr.edat.ctall.result = R
  1993. enum {DWIND_INIT, DWIND_BODY, DWIND_FINISH};
  1994. #define dynamic_wind_state(p) (_TDyn(p))->object.winder.state
  1995. #define dynamic_wind_in(p) (_TDyn(p))->object.winder.in
  1996. #define dynamic_wind_out(p) (_TDyn(p))->object.winder.out
  1997. #define dynamic_wind_body(p) (_TDyn(p))->object.winder.body
  1998. #define is_c_object(p) (type(p) == T_C_OBJECT)
  1999. #define c_object_value(p) (_TObj(p))->object.c_obj.value
  2000. #define c_object_type(p) (_TObj(p))->object.c_obj.type
  2001. #define c_object_let(p) _TLid((_TObj(p))->object.c_obj.e)
  2002. #define c_object_set_let(p, L) (_TObj(p))->object.c_obj.e = _TLid(L)
  2003. #define c_object_cref(p) (_TObj(p))->object.c_obj.ref
  2004. static c_object_t **object_types = NULL;
  2005. static int object_types_size = 0;
  2006. static int num_object_types = 0;
  2007. #define c_object_info(p) object_types[c_object_type(_TObj(p))]
  2008. #define c_object_ref(p) c_object_info(p)->ref
  2009. #define c_object_set(p) c_object_info(p)->set
  2010. #define c_object_print(p) c_object_info(p)->print
  2011. #define c_object_print_readably(p) c_object_info(p)->print_readably
  2012. #define c_object_length(p) c_object_info(p)->length
  2013. #define c_object_eql(p) c_object_info(p)->equal
  2014. #define c_object_fill(p) c_object_info(p)->fill
  2015. #define c_object_copy(p) c_object_info(p)->copy
  2016. #define c_object_free(p) c_object_info(p)->free
  2017. #define c_object_mark(p) c_object_info(p)->gc_mark
  2018. #define c_object_reverse(p) c_object_info(p)->reverse
  2019. #define c_object_direct_ref(p) c_object_info(p)->direct_ref
  2020. #define c_object_direct_set(p) c_object_info(p)->direct_set
  2021. #define c_object_ip(p) c_object_info(p)->ip
  2022. #define c_object_rp(p) c_object_info(p)->rp
  2023. #define c_object_set_ip(p) c_object_info(p)->set_ip
  2024. #define c_object_set_rp(p) c_object_info(p)->set_rp
  2025. #define c_object_scheme_name(p) _TStr(c_object_info(p)->scheme_name)
  2026. /* #define c_object_outer_type(p) c_object_info(p)->outer_type */
  2027. #define raw_pointer(p) (_TPtr(p))->object.c_pointer
  2028. #define is_counter(p) (type(p) == T_COUNTER)
  2029. #define counter_result(p) (_TCtr(p))->object.ctr.result
  2030. #define counter_set_result(p, Val) (_TCtr(p))->object.ctr.result = _NFre(Val)
  2031. #define counter_list(p) (_TCtr(p))->object.ctr.list
  2032. #define counter_set_list(p, Val) (_TCtr(p))->object.ctr.list = _NFre(Val)
  2033. #define counter_capture(p) (_TCtr(p))->object.ctr.cap
  2034. #define counter_set_capture(p, Val) (_TCtr(p))->object.ctr.cap = Val
  2035. #define counter_let(p) _TLid((_TCtr(p))->object.ctr.env)
  2036. #define counter_set_let(p, L) (_TCtr(p))->object.ctr.env = _TLid(L)
  2037. #define counter_slots(p) (_TCtr(p))->object.ctr.slots
  2038. #define counter_set_slots(p, Val) (_TCtr(p))->object.ctr.slots = _TSln(Val)
  2039. #define is_baffle(p) (type(p) == T_BAFFLE)
  2040. #define baffle_key(p) (_TBfl(p))->object.baffle_key
  2041. #if __cplusplus && HAVE_COMPLEX_NUMBERS
  2042. using namespace std; /* the code has to work in C as well as C++, so we can't scatter std:: all over the place */
  2043. typedef complex<s7_double> s7_complex;
  2044. static s7_double Real(complex<s7_double> x) {return(real(x));} /* protect the C++ name */
  2045. static s7_double Imag(complex<s7_double> x) {return(imag(x));}
  2046. #endif
  2047. #define integer(p) (_TI(p))->object.number.integer_value
  2048. #define real(p) (_TR(p))->object.number.real_value
  2049. #define set_real(p, x) real(p) = x
  2050. #define numerator(p) (_TF(p))->object.number.fraction_value.numerator
  2051. #define denominator(p) (_TF(p))->object.number.fraction_value.denominator
  2052. #define fraction(p) (((long double)numerator(p)) / ((long double)denominator(p)))
  2053. #define inverted_fraction(p) (((long double)denominator(p)) / ((long double)numerator(p)))
  2054. #define real_part(p) (_TZ(p))->object.number.complex_value.rl
  2055. #define set_real_part(p, x) real_part(p) = x
  2056. #define imag_part(p) (_TZ(p))->object.number.complex_value.im
  2057. #define set_imag_part(p, x) imag_part(p) = x
  2058. #if HAVE_COMPLEX_NUMBERS
  2059. #define as_c_complex(p) CMPLX(real_part(p), imag_part(p))
  2060. #endif
  2061. #if WITH_GMP
  2062. #define big_integer(p) ((_TBgi(p))->object.number.big_integer)
  2063. #define big_ratio(p) ((_TBgf(p))->object.number.big_ratio)
  2064. #define big_real(p) ((_TBgr(p))->object.number.big_real)
  2065. #define big_complex(p) ((_TBgz(p))->object.number.big_complex)
  2066. #endif
  2067. #define NUM_SMALL_INTS 2048
  2068. #define small_int(Val) small_ints[Val]
  2069. #define is_small(n) ((n & ~(NUM_SMALL_INTS - 1)) == 0)
  2070. #define print_name(p) (char *)((_TNum(p))->object.number.pval.name + 1)
  2071. #define print_name_length(p) (_TNum(p))->object.number.pval.name[0]
  2072. static void set_print_name(s7_pointer p, const char *name, int len)
  2073. {
  2074. if ((len < PRINT_NAME_SIZE) &&
  2075. (!is_mutable(p)))
  2076. {
  2077. set_has_print_name(p);
  2078. print_name_length(p) = (unsigned char)(len & 0xff);
  2079. memcpy((void *)print_name(p), (void *)name, len);
  2080. }
  2081. }
  2082. #if WITH_GCC
  2083. #define make_integer(Sc, N) \
  2084. ({ s7_int _N_; _N_ = (N); (is_small(_N_) ? small_int(_N_) : ({ s7_pointer _X_; new_cell(Sc, _X_, T_INTEGER); integer(_X_) = _N_; _X_;}) ); })
  2085. #define make_real(Sc, X) \
  2086. ({ s7_double _N_ = (X); ((_N_ == 0.0) ? real_zero : ({ s7_pointer _X_; new_cell(Sc, _X_, T_REAL); set_real(_X_, _N_); _X_;}) ); })
  2087. /* the x == 0.0 check saves more than it costs */
  2088. #define make_complex(Sc, R, I) \
  2089. ({ s7_double im; im = (I); ((im == 0.0) ? make_real(Sc, R) : ({ s7_pointer _X_; new_cell(Sc, _X_, T_COMPLEX); set_real_part(_X_, R); set_imag_part(_X_, im); _X_;}) ); })
  2090. #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)); })
  2091. #define rational_to_double(Sc, X) ({ s7_pointer _x_; _x_ = (X); ((type(_x_) == T_INTEGER) ? (s7_double)integer(_x_) : fraction(_x_)); })
  2092. #else
  2093. #define make_integer(Sc, N) s7_make_integer(Sc, N)
  2094. #define make_real(Sc, X) s7_make_real(Sc, X)
  2095. #define make_complex(Sc, R, I) s7_make_complex(Sc, R, I)
  2096. #define real_to_double(Sc, X, Caller) s7_number_to_real_with_caller(Sc, X, Caller)
  2097. #define rational_to_double(Sc, X) s7_number_to_real(Sc, X)
  2098. #endif
  2099. #define S7_LLONG_MAX 9223372036854775807LL
  2100. #define S7_LLONG_MIN (-S7_LLONG_MAX - 1LL)
  2101. #define S7_LONG_MAX 2147483647LL
  2102. #define S7_LONG_MIN (-S7_LONG_MAX - 1LL)
  2103. #define S7_SHORT_MAX 32767
  2104. #define S7_SHORT_MIN -32768
  2105. static s7_int s7_int_max = 0, s7_int_min = 0;
  2106. /* 9007199254740991LL is where a truncated double starts to skip integers (expt 2 53) = ca 1e16
  2107. * :(ceiling (+ 1e16 1))
  2108. * 10000000000000000
  2109. * :(> 9007199254740993.0 9007199254740992.0)
  2110. * #f ; in non-gmp 64-bit doubles
  2111. *
  2112. * but we can't fix this except in the gmp case because:
  2113. * :(integer-decode-float (+ (expt 2.0 62) 100))
  2114. * (4503599627370496 10 1)
  2115. * :(integer-decode-float (+ (expt 2.0 62) 500))
  2116. * (4503599627370496 10 1)
  2117. * :(> (+ (expt 2.0 62) 500) (+ (expt 2.0 62) 100))
  2118. * #f ; non-gmp again
  2119. *
  2120. * i.e. the bits are identical. We can't even detect when it has happened, so should
  2121. * we just give an error for any floor (or whatever) of an arg>1e16? (sin has a similar problem)?
  2122. * I think in the non-gmp case I'll throw an error in these cases because the results are
  2123. * bogus:
  2124. * :(floor (+ (expt 2.0 62) 512))
  2125. * 4611686018427387904
  2126. * :(floor (+ (expt 2.0 62) 513))
  2127. * 4611686018427388928
  2128. *
  2129. * another case at the edge: (round 9007199254740992.51) -> 9007199254740992
  2130. *
  2131. * This spells trouble for normal arithmetic in this range. If no gmp,
  2132. * (- (+ (expt 2.0 62) 512) (+ (expt 2.0 62) 513)) = -1024.0 (should be -1.0)
  2133. * but we don't currently give an error in this case -- not sure what the right thing is.
  2134. */
  2135. /* --------------------------------------------------------------------------------
  2136. * local versions of some standard C library functions
  2137. * timing tests involving these are very hard to interpret -- pervasive inconsistency!
  2138. */
  2139. static int safe_strlen(const char *str)
  2140. {
  2141. /* this is safer than strlen, and slightly faster */
  2142. char *tmp = (char *)str;
  2143. if ((!tmp) || (!(*tmp))) return(0);
  2144. while (*tmp++) {};
  2145. return(tmp - str - 1);
  2146. }
  2147. static int safe_strlen5(const char *str)
  2148. {
  2149. /* safe_strlen but we quit counting if len>5 */
  2150. char *tmp = (char *)str;
  2151. char *end;
  2152. if ((!tmp) || (!(*tmp))) return(0);
  2153. end = (char *)(tmp + 6);
  2154. while ((*tmp++) && (tmp < end)) {};
  2155. return(tmp - str - 1);
  2156. }
  2157. static char *copy_string_with_length(const char *str, int len)
  2158. {
  2159. char *newstr;
  2160. newstr = (char *)malloc((len + 1) * sizeof(char));
  2161. if (len != 0)
  2162. memcpy((void *)newstr, (void *)str, len + 1);
  2163. else newstr[0] = 0;
  2164. return(newstr);
  2165. }
  2166. static char *copy_string(const char *str)
  2167. {
  2168. return(copy_string_with_length(str, safe_strlen(str)));
  2169. }
  2170. static bool local_strcmp(const char *s1, const char *s2)
  2171. {
  2172. while (true)
  2173. {
  2174. if (*s1 != *s2++) return(false);
  2175. if (*s1++ == 0) return(true);
  2176. }
  2177. return(true);
  2178. }
  2179. #define strings_are_equal(Str1, Str2) (local_strcmp(Str1, Str2))
  2180. /* this should only be used for internal strings -- scheme strings can have embedded nulls. */
  2181. static bool safe_strcmp(const char *s1, const char *s2)
  2182. {
  2183. if ((!s1) || (!s2)) return(s1 == s2);
  2184. return(local_strcmp(s1, s2));
  2185. }
  2186. static bool local_strncmp(const char *s1, const char *s2, unsigned int n)
  2187. {
  2188. #if defined(__x86_64__) || defined(__i386__) /* unaligned accesses are safe on i386 hardware, sez everyone */
  2189. if (n >= 4)
  2190. {
  2191. int *is1, *is2;
  2192. int n4 = n >> 2;
  2193. is1 = (int *)s1;
  2194. is2 = (int *)s2;
  2195. do {if (*is1++ != *is2++) return(false);} while (--n4 > 0);
  2196. s1 = (const char *)is1;
  2197. s2 = (const char *)is2;
  2198. n &= 3;
  2199. }
  2200. #endif
  2201. while (n > 0)
  2202. {
  2203. if (*s1++ != *s2++) return(false);
  2204. n--;
  2205. }
  2206. return(true);
  2207. }
  2208. #define strings_are_equal_with_length(Str1, Str2, Len) (local_strncmp(Str1, Str2, Len))
  2209. static void memclr(void *s, size_t n)
  2210. {
  2211. unsigned char *s2;
  2212. #if defined(__x86_64__) || defined(__i386__)
  2213. if (n >= 4)
  2214. {
  2215. int *s1 = (int *)s;
  2216. size_t n4 = n >> 2;
  2217. do {*s1++ = 0;} while (--n4 > 0);
  2218. n &= 3;
  2219. s2 = (unsigned char *)s1;
  2220. }
  2221. else s2 = (unsigned char *)s;
  2222. #else
  2223. s2 = (unsigned char *)s;
  2224. #endif
  2225. while (n > 0)
  2226. {
  2227. *s2++ = 0;
  2228. n--;
  2229. }
  2230. }
  2231. /* ---------------- forward decls ---------------- */
  2232. static char *number_to_string_base_10(s7_pointer obj, int width, int precision, char float_choice, int *nlen, use_write_t choice);
  2233. static bool is_proper_list(s7_scheme *sc, s7_pointer lst);
  2234. static s7_pointer iterator_finished(s7_scheme *sc, s7_pointer iterator);
  2235. static bool is_all_x_safe(s7_scheme *sc, s7_pointer p);
  2236. static void annotate_args(s7_scheme *sc, s7_pointer args, s7_pointer e);
  2237. static void annotate_arg(s7_scheme *sc, s7_pointer arg, s7_pointer e);
  2238. static s7_pointer eval(s7_scheme *sc, opcode_t first_op);
  2239. static s7_pointer division_by_zero_error(s7_scheme *sc, s7_pointer caller, s7_pointer arg);
  2240. static s7_pointer file_error(s7_scheme *sc, const char *caller, const char *descr, const char *name);
  2241. static s7_pointer prepackaged_type_name(s7_scheme *sc, s7_pointer x);
  2242. static void s7_warn(s7_scheme *sc, int len, const char *ctrl, ...);
  2243. static s7_pointer safe_reverse_in_place(s7_scheme *sc, s7_pointer list);
  2244. static s7_pointer cons_unchecked(s7_scheme *sc, s7_pointer a, s7_pointer b);
  2245. static s7_pointer permanent_cons(s7_pointer a, s7_pointer b, unsigned int type);
  2246. static s7_pointer permanent_list(s7_scheme *sc, int len);
  2247. static void free_object(s7_pointer a);
  2248. static s7_pointer make_atom(s7_scheme *sc, char *q, int radix, bool want_symbol, bool with_error);
  2249. static s7_pointer apply_error(s7_scheme *sc, s7_pointer obj, s7_pointer args);
  2250. static int remember_file_name(s7_scheme *sc, const char *file);
  2251. static const char *type_name(s7_scheme *sc, s7_pointer arg, int article);
  2252. static s7_pointer make_vector_1(s7_scheme *sc, s7_int len, bool filled, unsigned int typ);
  2253. static s7_pointer make_string_uncopied_with_length(s7_scheme *sc, char *str, int len);
  2254. static s7_pointer make_string_wrapper_with_length(s7_scheme *sc, const char *str, int len);
  2255. static s7_pointer make_string_wrapper(s7_scheme *sc, const char *str);
  2256. static void check_for_substring_temp(s7_scheme *sc, s7_pointer expr);
  2257. static s7_pointer splice_in_values(s7_scheme *sc, s7_pointer args);
  2258. static void pop_input_port(s7_scheme *sc);
  2259. static char *object_to_truncated_string(s7_scheme *sc, s7_pointer p, int len);
  2260. static token_t token(s7_scheme *sc);
  2261. static s7_pointer implicit_index(s7_scheme *sc, s7_pointer obj, s7_pointer indices);
  2262. static bool s7_is_morally_equal(s7_scheme *sc, s7_pointer x, s7_pointer y);
  2263. static void remove_gensym_from_symbol_table(s7_scheme *sc, s7_pointer sym);
  2264. static s7_pointer unbound_variable(s7_scheme *sc, s7_pointer sym);
  2265. static s7_pointer optimize_lambda(s7_scheme *sc, bool unstarred_lambda, s7_pointer func, s7_pointer args, s7_pointer body);
  2266. static bool optimize_expression(s7_scheme *sc, s7_pointer expr, int hop, s7_pointer e);
  2267. static s7_pointer optimize(s7_scheme *sc, s7_pointer code, int hop, s7_pointer e);
  2268. static void free_hash_table(s7_pointer table);
  2269. #if WITH_GMP
  2270. static s7_int big_integer_to_s7_int(mpz_t n);
  2271. #else
  2272. static double next_random(s7_pointer r);
  2273. #endif
  2274. #if DEBUGGING && WITH_GCC
  2275. static s7_pointer find_symbol_unchecked_1(s7_scheme *sc, s7_pointer symbol);
  2276. #define find_symbol_unchecked(Sc, Sym) check_null_sym(Sc, find_symbol_unchecked_1(Sc, Sym), Sym, __LINE__, __func__)
  2277. static s7_pointer check_null_sym(s7_scheme *sc, s7_pointer p, s7_pointer sym, int line, const char *func);
  2278. #define find_symbol_unexamined(Sc, Sym) find_symbol_unchecked_1(Sc, Sym)
  2279. #else
  2280. static s7_pointer find_symbol_unchecked(s7_scheme *sc, s7_pointer symbol);
  2281. #define find_symbol_unexamined(Sc, Sym) find_symbol_unchecked(Sc, Sym)
  2282. #endif
  2283. #if WITH_GCC
  2284. #if DEBUGGING
  2285. #define find_symbol_checked(Sc, Sym) ({s7_pointer _x_; _x_ = find_symbol_unchecked_1(Sc, Sym); ((_x_) ? _x_ : unbound_variable(Sc, Sym));})
  2286. #else
  2287. #define find_symbol_checked(Sc, Sym) ({s7_pointer _x_; _x_ = find_symbol_unchecked(Sc, Sym); ((_x_) ? _x_ : unbound_variable(Sc, Sym));})
  2288. #endif
  2289. #else
  2290. #define find_symbol_checked(Sc, Sym) find_symbol_unchecked(Sc, Sym)
  2291. #endif
  2292. static s7_pointer find_method(s7_scheme *sc, s7_pointer env, s7_pointer symbol);
  2293. static s7_pointer find_let(s7_scheme *sc, s7_pointer obj);
  2294. static bool call_begin_hook(s7_scheme *sc);
  2295. static s7_pointer default_vector_setter(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val);
  2296. static s7_pointer default_vector_getter(s7_scheme *sc, s7_pointer vec, s7_int loc);
  2297. static s7_pointer simple_wrong_type_arg_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg, s7_pointer typnam, s7_pointer descr);
  2298. 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);
  2299. static s7_pointer out_of_range_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg_n, s7_pointer arg, s7_pointer descr);
  2300. static s7_pointer simple_out_of_range_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg, s7_pointer descr);
  2301. /* putting off the type description until s7_error via the sc->gc_nil marker below makes it possible
  2302. * for gcc to speed up the functions that call these as tail-calls. 1-2% overall speedup!
  2303. */
  2304. #define simple_wrong_type_argument(Sc, Caller, Arg, Desired_Type) \
  2305. simple_wrong_type_arg_error_prepackaged(Sc, symbol_name_cell(Caller), Arg, sc->gc_nil, prepackaged_type_names[Desired_Type])
  2306. #define wrong_type_argument(Sc, Caller, Num, Arg, Desired_Type) \
  2307. wrong_type_arg_error_prepackaged(Sc, symbol_name_cell(Caller), make_integer(Sc, Num), Arg, sc->gc_nil, prepackaged_type_names[Desired_Type])
  2308. #define simple_wrong_type_argument_with_type(Sc, Caller, Arg, Type) \
  2309. simple_wrong_type_arg_error_prepackaged(Sc, symbol_name_cell(Caller), Arg, sc->gc_nil, Type)
  2310. #define wrong_type_argument_with_type(Sc, Caller, Num, Arg, Type) \
  2311. wrong_type_arg_error_prepackaged(Sc, symbol_name_cell(Caller), make_integer(Sc, Num), Arg, sc->gc_nil, Type)
  2312. #define simple_out_of_range(Sc, Caller, Arg, Description) \
  2313. simple_out_of_range_error_prepackaged(Sc, symbol_name_cell(Caller), Arg, Description)
  2314. #define out_of_range(Sc, Caller, Arg_Num, Arg, Description) \
  2315. out_of_range_error_prepackaged(Sc, symbol_name_cell(Caller), Arg_Num, Arg, Description)
  2316. static s7_pointer car_a_list_string, cdr_a_list_string, caar_a_list_string, cadr_a_list_string, cdar_a_list_string,
  2317. cddr_a_list_string, caaar_a_list_string, caadr_a_list_string, cadar_a_list_string, caddr_a_list_string,
  2318. cdaar_a_list_string, cdadr_a_list_string, cddar_a_list_string, cdddr_a_list_string, a_list_string,
  2319. an_association_list_string, an_output_port_string, an_input_port_string, an_open_port_string,
  2320. a_normal_real_string, a_rational_string, a_boolean_string, a_number_string, a_let_string,
  2321. a_procedure_string, a_proper_list_string, a_thunk_string, something_applicable_string, a_symbol_string,
  2322. a_non_negative_integer_string, a_format_port_string, an_unsigned_byte_string, a_binding_string,
  2323. a_non_constant_symbol_string, an_eq_func_string, a_sequence_string, its_too_small_string,
  2324. a_normal_procedure_string, its_too_large_string, its_negative_string, result_is_too_large_string,
  2325. its_nan_string, its_infinite_string, too_many_indices_string, a_valid_radix_string, an_input_string_port_string,
  2326. an_input_file_port_string, an_output_string_port_string, an_output_file_port_string, a_random_state_object_string;
  2327. #if (!HAVE_COMPLEX_NUMBERS)
  2328. static s7_pointer no_complex_numbers_string;
  2329. #endif
  2330. /* ---------------- evaluator ops ---------------- */
  2331. enum {OP_NO_OP,
  2332. OP_READ_INTERNAL, OP_EVAL,
  2333. OP_EVAL_ARGS, OP_EVAL_ARGS1, OP_EVAL_ARGS2, OP_EVAL_ARGS3, OP_EVAL_ARGS4, OP_EVAL_ARGS5,
  2334. OP_APPLY, OP_EVAL_MACRO, OP_LAMBDA, OP_QUOTE, OP_MACROEXPAND,
  2335. OP_DEFINE, OP_DEFINE1, OP_BEGIN, OP_BEGIN_UNCHECKED, OP_BEGIN1,
  2336. OP_IF, OP_IF1, OP_WHEN, OP_WHEN1, OP_UNLESS, OP_UNLESS1, OP_SET, OP_SET1, OP_SET2,
  2337. OP_LET, OP_LET1, OP_LET_STAR, OP_LET_STAR1, OP_LET_STAR2,
  2338. OP_LETREC, OP_LETREC1, OP_LETREC_STAR, OP_LETREC_STAR1, OP_COND, OP_COND1, OP_COND1_1, OP_COND_SIMPLE, OP_COND1_SIMPLE,
  2339. OP_AND, OP_AND1, OP_OR, OP_OR1,
  2340. OP_DEFINE_MACRO, OP_DEFINE_MACRO_STAR, OP_DEFINE_EXPANSION,
  2341. OP_CASE, OP_CASE1, OP_READ_LIST, OP_READ_NEXT, OP_READ_DOT, OP_READ_QUOTE,
  2342. OP_READ_QUASIQUOTE, OP_READ_UNQUOTE, OP_READ_APPLY_VALUES,
  2343. OP_READ_VECTOR, OP_READ_BYTE_VECTOR, OP_READ_DONE,
  2344. OP_LOAD_RETURN_IF_EOF, OP_LOAD_CLOSE_AND_POP_IF_EOF, OP_EVAL_DONE,
  2345. OP_CATCH, OP_DYNAMIC_WIND, OP_DEFINE_CONSTANT, OP_DEFINE_CONSTANT1,
  2346. OP_DO, OP_DO_END, OP_DO_END1, OP_DO_STEP, OP_DO_STEP2, OP_DO_INIT,
  2347. OP_DEFINE_STAR, OP_LAMBDA_STAR, OP_LAMBDA_STAR_DEFAULT, OP_ERROR_QUIT, OP_UNWIND_INPUT, OP_UNWIND_OUTPUT,
  2348. OP_ERROR_HOOK_QUIT,
  2349. OP_WITH_LET, OP_WITH_LET1, OP_WITH_LET_UNCHECKED, OP_WITH_LET_S,
  2350. OP_WITH_BAFFLE, OP_WITH_BAFFLE_UNCHECKED, OP_EXPANSION,
  2351. OP_FOR_EACH, OP_FOR_EACH_1, OP_FOR_EACH_2, OP_FOR_EACH_3,
  2352. OP_MAP, OP_MAP_1, OP_MAP_GATHER, OP_MAP_GATHER_1, OP_BARRIER, OP_DEACTIVATE_GOTO,
  2353. OP_DEFINE_BACRO, OP_DEFINE_BACRO_STAR,
  2354. OP_GET_OUTPUT_STRING, OP_GET_OUTPUT_STRING_1,
  2355. OP_SORT, OP_SORT1, OP_SORT2, OP_SORT3, OP_SORT_PAIR_END, OP_SORT_VECTOR_END, OP_SORT_STRING_END,
  2356. OP_EVAL_STRING_1, OP_EVAL_STRING_2,
  2357. OP_MEMBER_IF, OP_ASSOC_IF, OP_MEMBER_IF1, OP_ASSOC_IF1,
  2358. OP_QUOTE_UNCHECKED, OP_LAMBDA_UNCHECKED, OP_LET_UNCHECKED, OP_CASE_UNCHECKED, OP_WHEN_UNCHECKED, OP_UNLESS_UNCHECKED,
  2359. OP_SET_UNCHECKED, OP_SET_SYMBOL_C, OP_SET_SYMBOL_S, OP_SET_SYMBOL_Q, OP_SET_SYMBOL_P, OP_SET_SYMBOL_Z, OP_SET_SYMBOL_A,
  2360. OP_SET_SYMBOL_opSq, OP_SET_SYMBOL_opCq, OP_SET_SYMBOL_opSSq, OP_SET_SYMBOL_opSSSq,
  2361. OP_SET_NORMAL, OP_SET_PAIR, OP_SET_PAIR_Z, OP_SET_PAIR_A, OP_SET_PAIR_P, OP_SET_PAIR_ZA,
  2362. OP_SET_PAIR_P_1, OP_SET_WITH_ACCESSOR, OP_SET_PWS, OP_SET_LET_S, OP_SET_LET_ALL_X,
  2363. OP_SET_PAIR_C, OP_SET_PAIR_C_P, OP_SET_PAIR_C_P_1, OP_SET_SAFE,
  2364. OP_INCREMENT_1, OP_DECREMENT_1, OP_SET_CONS,
  2365. OP_INCREMENT_SS, OP_INCREMENT_SSS, OP_INCREMENT_SZ, OP_INCREMENT_SA, OP_INCREMENT_SAA,
  2366. OP_LET_STAR_UNCHECKED, OP_LETREC_UNCHECKED, OP_LETREC_STAR_UNCHECKED, OP_COND_UNCHECKED,
  2367. OP_LAMBDA_STAR_UNCHECKED, OP_DO_UNCHECKED, OP_DEFINE_UNCHECKED, OP_DEFINE_STAR_UNCHECKED, OP_DEFINE_FUNCHECKED, OP_DEFINE_CONSTANT_UNCHECKED,
  2368. OP_DEFINE_WITH_ACCESSOR, OP_DEFINE_MACRO_WITH_ACCESSOR,
  2369. OP_LET_NO_VARS, OP_NAMED_LET, OP_NAMED_LET_NO_VARS, OP_NAMED_LET_STAR,
  2370. OP_LET_C, OP_LET_S, OP_LET_ALL_C, OP_LET_ALL_S, OP_LET_ALL_X,
  2371. OP_LET_STAR_ALL_X, OP_LET_opCq, OP_LET_opSSq,
  2372. OP_LET_opSq, OP_LET_ALL_opSq, OP_LET_opSq_P, OP_LET_ONE, OP_LET_ONE_1, OP_LET_Z, OP_LET_Z_1,
  2373. OP_CASE_SIMPLE, OP_CASE_SIMPLER, OP_CASE_SIMPLER_1, OP_CASE_SIMPLER_SS, OP_CASE_SIMPLEST, OP_CASE_SIMPLEST_SS,
  2374. OP_IF_UNCHECKED, OP_AND_UNCHECKED, OP_AND_P, OP_AND_P1, OP_AND_P2, OP_OR_UNCHECKED, OP_OR_P, OP_OR_P1, OP_OR_P2,
  2375. OP_IF_P_FEED, OP_IF_P_FEED_1, OP_WHEN_S, OP_UNLESS_S,
  2376. OP_IF_S_P, OP_IF_S_P_P, OP_IF_NOT_S_P, OP_IF_NOT_S_P_P, OP_IF_CC_P, OP_IF_CC_P_P,
  2377. OP_IF_CS_P, OP_IF_CS_P_P, OP_IF_CSQ_P, OP_IF_CSQ_P_P, OP_IF_CSS_P, OP_IF_CSS_P_P,
  2378. OP_IF_CSC_P, OP_IF_CSC_P_P, OP_IF_IS_PAIR_P, OP_IF_IS_PAIR_P_P, OP_IF_opSSq_P, OP_IF_opSSq_P_P, OP_IF_S_opCq_P, OP_IF_S_opCq_P_P,
  2379. OP_IF_IS_SYMBOL_P, OP_IF_IS_SYMBOL_P_P, OP_IF_A_P, OP_IF_A_P_P, OP_IF_AND2_P, OP_IF_AND2_P_P,
  2380. OP_IF_Z_P, OP_IF_Z_P_P, OP_IF_P_P_P, OP_IF_P_P, OP_IF_ANDP_P, OP_IF_ANDP_P_P, OP_IF_ORP_P, OP_IF_ORP_P_P,
  2381. OP_IF_PPP, OP_IF_PP,
  2382. OP_CATCH_1, OP_CATCH_2, OP_CATCH_ALL, OP_COND_ALL_X, OP_COND_ALL_X_2, OP_COND_S,
  2383. OP_SIMPLE_DO, OP_SIMPLE_DO_STEP, OP_SAFE_DOTIMES, OP_SAFE_DOTIMES_STEP, OP_SAFE_DOTIMES_STEP_P, OP_SAFE_DOTIMES_STEP_O, OP_SAFE_DOTIMES_STEP_A,
  2384. OP_SAFE_DO, OP_SAFE_DO_STEP, OP_SIMPLE_DO_P, OP_SIMPLE_DO_STEP_P, OP_DOX, OP_DOX_STEP, OP_DOX_STEP_P,
  2385. OP_DOTIMES_P, OP_DOTIMES_STEP_P, OP_SIMPLE_DO_A, OP_SIMPLE_DO_STEP_A, OP_SIMPLE_DO_E, OP_SIMPLE_DO_STEP_E,
  2386. OP_SAFE_C_P_1, OP_SAFE_C_PP_1, OP_SAFE_C_PP_2, OP_SAFE_C_PP_3, OP_SAFE_C_PP_4, OP_SAFE_C_PP_5, OP_SAFE_C_PP_6,
  2387. OP_EVAL_ARGS_P_2, OP_EVAL_ARGS_P_2_MV, OP_EVAL_ARGS_P_3, OP_EVAL_ARGS_P_4, OP_EVAL_ARGS_P_3_MV, OP_EVAL_ARGS_P_4_MV,
  2388. OP_EVAL_ARGS_SSP_1, OP_EVAL_ARGS_SSP_MV, OP_EVAL_MACRO_MV, OP_MACROEXPAND_1,
  2389. OP_SAFE_C_ZZ_1, OP_SAFE_C_ZZ_2, OP_SAFE_C_ZC_1, OP_SAFE_C_SZ_1, OP_SAFE_C_ZA_1, OP_INCREMENT_SZ_1, OP_SAFE_C_SZ_SZ,
  2390. OP_SAFE_C_ZAA_1, OP_SAFE_C_AZA_1, OP_SAFE_C_AAZ_1, OP_SAFE_C_SSZ_1,
  2391. OP_SAFE_C_ZZA_1, OP_SAFE_C_ZZA_2, OP_SAFE_C_ZAZ_1, OP_SAFE_C_ZAZ_2, OP_SAFE_C_AZZ_1, OP_SAFE_C_AZZ_2,
  2392. OP_SAFE_C_ZZZ_1, OP_SAFE_C_ZZZ_2, OP_SAFE_C_ZZZ_3,
  2393. OP_SAFE_C_opSq_P_1, OP_SAFE_C_opSq_P_MV, OP_C_P_1, OP_C_P_2, OP_C_SP_1, OP_C_SP_2,
  2394. OP_CLOSURE_P_1, OP_CLOSURE_P_2, OP_SAFE_CLOSURE_P_1,
  2395. OP_SET_WITH_LET_1, OP_SET_WITH_LET_2,
  2396. OP_MAX_DEFINED_1};
  2397. #define OP_MAX_DEFINED (OP_MAX_DEFINED_1 + 1)
  2398. typedef enum{E_C_P, E_C_PP, E_C_CP, E_C_SP, E_C_PC, E_C_PS} combine_op_t;
  2399. enum {OP_SAFE_C_C, HOP_SAFE_C_C, OP_SAFE_C_S, HOP_SAFE_C_S,
  2400. OP_SAFE_C_SS, HOP_SAFE_C_SS, OP_SAFE_C_SC, HOP_SAFE_C_SC, OP_SAFE_C_CS, HOP_SAFE_C_CS,
  2401. OP_SAFE_C_Q, HOP_SAFE_C_Q, OP_SAFE_C_SQ, HOP_SAFE_C_SQ, OP_SAFE_C_QS, HOP_SAFE_C_QS, OP_SAFE_C_QQ, HOP_SAFE_C_QQ,
  2402. OP_SAFE_C_CQ, HOP_SAFE_C_CQ, OP_SAFE_C_QC, HOP_SAFE_C_QC,
  2403. 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,
  2404. OP_SAFE_C_SCC, HOP_SAFE_C_SCC, OP_SAFE_C_CSC, HOP_SAFE_C_CSC,
  2405. OP_SAFE_C_ALL_S, HOP_SAFE_C_ALL_S, OP_SAFE_C_ALL_X, HOP_SAFE_C_ALL_X, OP_SAFE_C_SSA, HOP_SAFE_C_SSA, OP_SAFE_C_SAS, HOP_SAFE_C_SAS,
  2406. OP_SAFE_C_CSA, HOP_SAFE_C_CSA, OP_SAFE_C_SCA, HOP_SAFE_C_SCA, OP_SAFE_C_CAS, HOP_SAFE_C_CAS,
  2407. OP_SAFE_C_A, HOP_SAFE_C_A, OP_SAFE_C_AA, HOP_SAFE_C_AA, OP_SAFE_C_AAA, HOP_SAFE_C_AAA, OP_SAFE_C_AAAA, HOP_SAFE_C_AAAA,
  2408. OP_SAFE_C_SQS, HOP_SAFE_C_SQS, OP_SAFE_C_opAq, HOP_SAFE_C_opAq, OP_SAFE_C_opAAq, HOP_SAFE_C_opAAq, OP_SAFE_C_opAAAq, HOP_SAFE_C_opAAAq,
  2409. OP_SAFE_C_S_opAq, HOP_SAFE_C_S_opAq, OP_SAFE_C_S_opAAq, HOP_SAFE_C_S_opAAq, OP_SAFE_C_S_opAAAq, HOP_SAFE_C_S_opAAAq,
  2410. OP_SAFE_C_opCq, HOP_SAFE_C_opCq, OP_SAFE_C_opSq, HOP_SAFE_C_opSq,
  2411. OP_SAFE_C_opSSq, HOP_SAFE_C_opSSq, OP_SAFE_C_opSCq, HOP_SAFE_C_opSCq, OP_SAFE_C_opSQq, HOP_SAFE_C_opSQq,
  2412. OP_SAFE_C_opCSq, HOP_SAFE_C_opCSq, OP_SAFE_C_S_opSq, HOP_SAFE_C_S_opSq,
  2413. OP_SAFE_C_C_opSCq, HOP_SAFE_C_C_opSCq,
  2414. OP_SAFE_C_S_opSCq, HOP_SAFE_C_S_opSCq, OP_SAFE_C_S_opCSq, HOP_SAFE_C_S_opCSq,
  2415. OP_SAFE_C_opSq_S, HOP_SAFE_C_opSq_S, OP_SAFE_C_opSq_C, HOP_SAFE_C_opSq_C,
  2416. 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,
  2417. OP_SAFE_C_C_opCSq, HOP_SAFE_C_C_opCSq, OP_SAFE_C_opCSq_C, HOP_SAFE_C_opCSq_C,
  2418. OP_SAFE_C_S_opCq, HOP_SAFE_C_S_opCq, OP_SAFE_C_opSSq_C, HOP_SAFE_C_opSSq_C, OP_SAFE_C_C_opSSq, HOP_SAFE_C_C_opSSq,
  2419. OP_SAFE_C_C_opCq, HOP_SAFE_C_C_opCq, OP_SAFE_C_opCq_S, HOP_SAFE_C_opCq_S,
  2420. OP_SAFE_C_opCq_opCq, HOP_SAFE_C_opCq_opCq, OP_SAFE_C_opCq_C, HOP_SAFE_C_opCq_C,
  2421. OP_SAFE_C_opSCq_opSCq, HOP_SAFE_C_opSCq_opSCq, OP_SAFE_C_opSSq_opSSq, HOP_SAFE_C_opSSq_opSSq,
  2422. OP_SAFE_C_opSSq_opCq, HOP_SAFE_C_opSSq_opCq, OP_SAFE_C_opSSq_opSq, HOP_SAFE_C_opSSq_opSq, OP_SAFE_C_opSq_opSSq, HOP_SAFE_C_opSq_opSSq,
  2423. OP_SAFE_C_opSSq_S, HOP_SAFE_C_opSSq_S, OP_SAFE_C_opSCq_S, HOP_SAFE_C_opSCq_S, OP_SAFE_C_opCSq_S, HOP_SAFE_C_opCSq_S,
  2424. OP_SAFE_C_opSCq_C, HOP_SAFE_C_opSCq_C, OP_SAFE_C_opCq_opSSq, HOP_SAFE_C_opCq_opSSq,
  2425. OP_SAFE_C_S_op_opSSq_Sq, HOP_SAFE_C_S_op_opSSq_Sq, OP_SAFE_C_S_op_S_opSSqq, HOP_SAFE_C_S_op_S_opSSqq,
  2426. OP_SAFE_C_op_opSSq_q_C, HOP_SAFE_C_op_opSSq_q_C, OP_SAFE_C_op_opSq_q_C, HOP_SAFE_C_op_opSq_q_C,
  2427. OP_SAFE_C_op_opSSq_q_S, HOP_SAFE_C_op_opSSq_q_S, OP_SAFE_C_op_opSq_q_S, HOP_SAFE_C_op_opSq_q_S,
  2428. OP_SAFE_C_S_op_opSSq_opSSqq, HOP_SAFE_C_S_op_opSSq_opSSqq,
  2429. OP_SAFE_C_op_opSq_q, HOP_SAFE_C_op_opSq_q, OP_SAFE_C_C_op_S_opCqq, HOP_SAFE_C_C_op_S_opCqq,
  2430. OP_SAFE_C_op_S_opSq_q, HOP_SAFE_C_op_S_opSq_q,
  2431. OP_SAFE_C_opSq_Q, HOP_SAFE_C_opSq_Q, OP_SAFE_C_opSq_Q_S, HOP_SAFE_C_opSq_Q_S,
  2432. OP_SAFE_C_Z, HOP_SAFE_C_Z, OP_SAFE_C_ZZ, HOP_SAFE_C_ZZ, OP_SAFE_C_SZ, HOP_SAFE_C_SZ, OP_SAFE_C_ZS, HOP_SAFE_C_ZS,
  2433. OP_SAFE_C_CZ, HOP_SAFE_C_CZ, OP_SAFE_C_ZC, HOP_SAFE_C_ZC,
  2434. OP_SAFE_C_opCq_Z, HOP_SAFE_C_opCq_Z, OP_SAFE_C_S_opSZq, HOP_SAFE_C_S_opSZq,
  2435. OP_SAFE_C_AZ, HOP_SAFE_C_AZ, OP_SAFE_C_ZA, HOP_SAFE_C_ZA,
  2436. OP_SAFE_C_ZAA, HOP_SAFE_C_ZAA, OP_SAFE_C_AZA, HOP_SAFE_C_AZA, OP_SAFE_C_AAZ, HOP_SAFE_C_AAZ, OP_SAFE_C_SSZ, HOP_SAFE_C_SSZ,
  2437. OP_SAFE_C_ZZA, HOP_SAFE_C_ZZA, OP_SAFE_C_ZAZ, HOP_SAFE_C_ZAZ, OP_SAFE_C_AZZ, HOP_SAFE_C_AZZ,
  2438. OP_SAFE_C_ZZZ, HOP_SAFE_C_ZZZ,
  2439. OP_THUNK, HOP_THUNK,
  2440. OP_CLOSURE_S, HOP_CLOSURE_S, OP_CLOSURE_C, HOP_CLOSURE_C, OP_CLOSURE_Q, HOP_CLOSURE_Q,
  2441. OP_CLOSURE_SS, HOP_CLOSURE_SS, OP_CLOSURE_SC, HOP_CLOSURE_SC, OP_CLOSURE_CS, HOP_CLOSURE_CS,
  2442. OP_CLOSURE_A, HOP_CLOSURE_A, OP_CLOSURE_AA, HOP_CLOSURE_AA,
  2443. OP_CLOSURE_ALL_X, HOP_CLOSURE_ALL_X, OP_CLOSURE_ALL_S, HOP_CLOSURE_ALL_S,
  2444. OP_GLOSURE_A, HOP_GLOSURE_A, OP_GLOSURE_S, HOP_GLOSURE_S, OP_GLOSURE_P, HOP_GLOSURE_P,
  2445. OP_CLOSURE_STAR_S, HOP_CLOSURE_STAR_S, OP_CLOSURE_STAR_SX, HOP_CLOSURE_STAR_SX,
  2446. OP_CLOSURE_STAR, HOP_CLOSURE_STAR, OP_CLOSURE_STAR_ALL_X, HOP_CLOSURE_STAR_ALL_X,
  2447. OP_SAFE_THUNK, HOP_SAFE_THUNK, OP_SAFE_THUNK_E, HOP_SAFE_THUNK_E, OP_SAFE_THUNK_P, HOP_SAFE_THUNK_P,
  2448. OP_SAFE_CLOSURE_S, HOP_SAFE_CLOSURE_S, OP_SAFE_CLOSURE_C, HOP_SAFE_CLOSURE_C, OP_SAFE_CLOSURE_Q, HOP_SAFE_CLOSURE_Q,
  2449. OP_SAFE_CLOSURE_SS, HOP_SAFE_CLOSURE_SS, OP_SAFE_CLOSURE_SC, HOP_SAFE_CLOSURE_SC, OP_SAFE_CLOSURE_CS, HOP_SAFE_CLOSURE_CS,
  2450. OP_SAFE_CLOSURE_A, HOP_SAFE_CLOSURE_A, OP_SAFE_CLOSURE_SA, HOP_SAFE_CLOSURE_SA, OP_SAFE_CLOSURE_S_P, HOP_SAFE_CLOSURE_S_P,
  2451. OP_SAFE_CLOSURE_SAA, HOP_SAFE_CLOSURE_SAA,
  2452. OP_SAFE_CLOSURE_ALL_X, HOP_SAFE_CLOSURE_ALL_X, OP_SAFE_CLOSURE_AA, HOP_SAFE_CLOSURE_AA,
  2453. OP_SAFE_GLOSURE_A, HOP_SAFE_GLOSURE_A, OP_SAFE_GLOSURE_S, HOP_SAFE_GLOSURE_S, OP_SAFE_GLOSURE_S_E, HOP_SAFE_GLOSURE_S_E,
  2454. OP_SAFE_GLOSURE_P, HOP_SAFE_GLOSURE_P,
  2455. OP_SAFE_CLOSURE_STAR_S, HOP_SAFE_CLOSURE_STAR_S, OP_SAFE_CLOSURE_STAR_SS, HOP_SAFE_CLOSURE_STAR_SS,
  2456. OP_SAFE_CLOSURE_STAR_SC, HOP_SAFE_CLOSURE_STAR_SC, OP_SAFE_CLOSURE_STAR_SA, HOP_SAFE_CLOSURE_STAR_SA, OP_SAFE_CLOSURE_STAR_S0, HOP_SAFE_CLOSURE_STAR_S0,
  2457. OP_SAFE_CLOSURE_STAR, HOP_SAFE_CLOSURE_STAR, OP_SAFE_CLOSURE_STAR_ALL_X, HOP_SAFE_CLOSURE_STAR_ALL_X,
  2458. /* these can't be embedded, and have to be the last thing called */
  2459. OP_APPLY_SS, HOP_APPLY_SS,
  2460. OP_C_ALL_X, HOP_C_ALL_X, OP_CALL_WITH_EXIT, HOP_CALL_WITH_EXIT, OP_C_CATCH, HOP_C_CATCH, OP_C_CATCH_ALL, HOP_C_CATCH_ALL,
  2461. OP_C_S_opSq, HOP_C_S_opSq, OP_C_S_opCq, HOP_C_S_opCq, OP_C_SS, HOP_C_SS,
  2462. OP_C_S, HOP_C_S, OP_READ_S, HOP_READ_S, OP_C_P, HOP_C_P, OP_C_Z, HOP_C_Z, OP_C_SP, HOP_C_SP,
  2463. OP_C_SZ, HOP_C_SZ, OP_C_A, HOP_C_A, OP_C_SCS, HOP_C_SCS,
  2464. OP_GOTO, HOP_GOTO, OP_GOTO_C, HOP_GOTO_C, OP_GOTO_S, HOP_GOTO_S, OP_GOTO_A, HOP_GOTO_A,
  2465. OP_VECTOR_C, HOP_VECTOR_C, OP_VECTOR_S, HOP_VECTOR_S, OP_VECTOR_A, HOP_VECTOR_A, OP_VECTOR_CC, HOP_VECTOR_CC,
  2466. OP_STRING_C, HOP_STRING_C, OP_STRING_S, HOP_STRING_S, OP_STRING_A, HOP_STRING_A,
  2467. OP_C_OBJECT, HOP_C_OBJECT, OP_C_OBJECT_C, HOP_C_OBJECT_C, OP_C_OBJECT_S, HOP_C_OBJECT_S, OP_C_OBJECT_A, HOP_C_OBJECT_A,
  2468. OP_PAIR_C, HOP_PAIR_C, OP_PAIR_S, HOP_PAIR_S, OP_PAIR_A, HOP_PAIR_A,
  2469. OP_HASH_TABLE_C, HOP_HASH_TABLE_C, OP_HASH_TABLE_S, HOP_HASH_TABLE_S, OP_HASH_TABLE_A, HOP_HASH_TABLE_A,
  2470. OP_ENVIRONMENT_S, HOP_ENVIRONMENT_S, OP_ENVIRONMENT_Q, HOP_ENVIRONMENT_Q, OP_ENVIRONMENT_A, HOP_ENVIRONMENT_A, OP_ENVIRONMENT_C, HOP_ENVIRONMENT_C,
  2471. OP_UNKNOWN, HOP_UNKNOWN, OP_UNKNOWN_ALL_S, HOP_UNKNOWN_ALL_S, OP_UNKNOWN_ALL_X, HOP_UNKNOWN_ALL_X,
  2472. OP_UNKNOWN_G, HOP_UNKNOWN_G, OP_UNKNOWN_GG, HOP_UNKNOWN_GG, OP_UNKNOWN_A, HOP_UNKNOWN_A, OP_UNKNOWN_AA, HOP_UNKNOWN_AA,
  2473. OP_SAFE_C_PP, HOP_SAFE_C_PP,
  2474. OP_SAFE_C_opSq_P, HOP_SAFE_C_opSq_P,
  2475. OP_SAFE_C_SP, HOP_SAFE_C_SP, OP_SAFE_C_CP, HOP_SAFE_C_CP, OP_SAFE_C_QP, HOP_SAFE_C_QP, OP_SAFE_C_AP, HOP_SAFE_C_AP,
  2476. OP_SAFE_C_PS, HOP_SAFE_C_PS, OP_SAFE_C_PC, HOP_SAFE_C_PC, OP_SAFE_C_PQ, HOP_SAFE_C_PQ,
  2477. OP_SAFE_C_SSP, HOP_SAFE_C_SSP,
  2478. OPT_MAX_DEFINED
  2479. };
  2480. #if DEBUGGING || OP_NAMES
  2481. static const char *op_names[OP_MAX_DEFINED_1] = {
  2482. "no_op",
  2483. "read_internal", "eval",
  2484. "eval_args", "eval_args1", "eval_args2", "eval_args3", "eval_args4", "eval_args5",
  2485. "apply", "eval_macro", "lambda", "quote", "macroexpand",
  2486. "define", "define1", "begin", "begin_unchecked", "begin1",
  2487. "if", "if1", "when", "when1", "unless", "unless1", "set", "set1", "set2",
  2488. "let", "let1", "let_star", "let_star1", "let_star2",
  2489. "letrec", "letrec1", "letrec_star", "letrec_star1", "cond", "cond1", "cond1_1", "cond_simple", "cond1_simple",
  2490. "and", "and1", "or", "or1",
  2491. "define_macro", "define_macro_star", "define_expansion",
  2492. "case", "case1", "read_list", "read_next", "read_dot", "read_quote",
  2493. "read_quasiquote", "read_unquote", "read_apply_values",
  2494. "read_vector", "read_byte_vector", "read_done",
  2495. "load_return_if_eof", "load_close_and_pop_if_eof", "eval_done",
  2496. "catch", "dynamic_wind", "define_constant", "define_constant1",
  2497. "do", "do_end", "do_end1", "do_step", "do_step2", "do_init",
  2498. "define_star", "lambda_star", "lambda_star_default", "error_quit", "unwind_input", "unwind_output",
  2499. "error_hook_quit",
  2500. "with_let", "with_let1", "with_let_unchecked", "with_let_s",
  2501. "with_baffle", "with_baffle_unchecked", "expansion",
  2502. "for_each", "for_each_1", "for_each_2", "for_each_3",
  2503. "map", "map_1", "map_gather", "map_gather_1", "barrier", "deactivate_goto",
  2504. "define_bacro", "define_bacro_star",
  2505. "get_output_string", "get_output_string_1",
  2506. "sort", "sort1", "sort2", "sort3", "sort_pair_end", "sort_vector_end", "sort_string_end",
  2507. "eval_string_1", "eval_string_2",
  2508. "member_if", "assoc_if", "member_if1", "assoc_if1",
  2509. "quote_unchecked", "lambda_unchecked", "let_unchecked", "case_unchecked", "when_unchecked", "unless_unchecked",
  2510. "set_unchecked", "set_symbol_c", "set_symbol_s", "set_symbol_q", "set_symbol_p", "set_symbol_z", "set_symbol_a",
  2511. "set_symbol_opsq", "set_symbol_opcq", "set_symbol_opssq", "set_symbol_opsssq",
  2512. "set_normal", "set_pair", "set_pair_z", "set_pair_a", "set_pair_p", "set_pair_za",
  2513. "set_pair_p_1", "set_with_accessor", "set_pws", "set_let_s", "set_let_all_x",
  2514. "set_pair_c", "set_pair_c_p", "set_pair_c_p_1", "set_safe",
  2515. "increment_1", "decrement_1", "set_cons",
  2516. "increment_ss", "increment_sss", "increment_sz", "increment_sa", "increment_saa",
  2517. "let_star_unchecked", "letrec_unchecked", "letrec_star_unchecked", "cond_unchecked",
  2518. "lambda_star_unchecked", "do_unchecked", "define_unchecked", "define_star_unchecked", "define_funchecked", "define_constant_unchecked",
  2519. "define_with_accessor", "define_macro_with_accessor",
  2520. "let_no_vars", "named_let", "named_let_no_vars", "named_let_star",
  2521. "let_c", "let_s", "let_all_c", "let_all_s", "let_all_x",
  2522. "let_star_all_x", "let_opcq", "let_opssq",
  2523. "let_opsq", "let_all_opsq", "let_opsq_p", "let_one", "let_one_1", "let_z", "let_z_1",
  2524. "case_simple", "case_simpler", "case_simpler_1", "case_simpler_ss", "case_simplest", "case_simplest_ss",
  2525. "if_unchecked", "and_unchecked", "and_p", "and_p1", "and_p2", "or_unchecked", "or_p", "or_p1", "or_p2",
  2526. "if_p_feed", "if_p_feed_1", "when_s", "unless_s",
  2527. "if_s_p", "if_s_p_p", "if_not_s_p", "if_not_s_p_p", "if_cc_p", "if_cc_p_p",
  2528. "if_cs_p", "if_cs_p_p", "if_csq_p", "if_csq_p_p", "if_css_p", "if_css_p_p",
  2529. "if_csc_p", "if_csc_p_p", "if_is_pair_p", "if_is_pair_p_p", "if_opssq_p", "if_opssq_p_p", "if_s_opcq_p", "if_s_opcq_p_p",
  2530. "if_is_symbol_p", "if_is_symbol_p_p", "if_a_p", "if_a_p_p", "if_and2_p", "if_and2_p_p",
  2531. "if_z_p", "if_z_p_p", "if_p_p_p", "if_p_p", "if_andp_p", "if_andp_p_p", "if_orp_p", "if_orp_p_p",
  2532. "if_ppp", "if_pp",
  2533. "catch_1", "catch_2", "catch_all", "cond_all_x", "cond_all_x_2", "cond_s",
  2534. "simple_do", "simple_do_step", "safe_dotimes", "safe_dotimes_step", "safe_dotimes_step_p", "safe_dotimes_step_o", "safe_dotimes_step_a",
  2535. "safe_do", "safe_do_step", "simple_do_p", "simple_do_step_p", "dox", "dox_step", "dox_step_p",
  2536. "dotimes_p", "dotimes_step_p", "simple_do_a", "simple_do_step_a", "simple_do_e", "simple_do_step_e",
  2537. "safe_c_p_1", "safe_c_pp_1", "safe_c_pp_2", "safe_c_pp_3", "safe_c_pp_4", "safe_c_pp_5", "safe_c_pp_6",
  2538. "eval_args_p_2", "eval_args_p_2_mv", "eval_args_p_3", "eval_args_p_4", "eval_args_p_3_mv", "eval_args_p_4_mv",
  2539. "eval_args_ssp_1", "eval_args_ssp_mv", "eval_macro_mv", "macroexpand_1",
  2540. "safe_c_zz_1", "safe_c_zz_2", "safe_c_zc_1", "safe_c_sz_1", "safe_c_za_1", "increment_sz_1", "safe_c_sz_sz",
  2541. "safe_c_zaa_1", "safe_c_aza_1", "safe_c_aaz_1", "safe_c_ssz_1",
  2542. "safe_c_zza_1", "safe_c_zza_2", "safe_c_zaz_1", "safe_c_zaz_2", "safe_c_azz_1", "safe_c_azz_2",
  2543. "safe_c_zzz_1", "safe_c_zzz_2", "safe_c_zzz_3",
  2544. "safe_c_opsq_p_1", "safe_c_opsq_p_mv", "c_p_1", "c_p_2", "c_sp_1", "c_sp_2",
  2545. "closure_p_1", "closure_p_2", "safe_closure_p_1",
  2546. "set-with-let-1", "set-with-let-2",
  2547. };
  2548. static const char* opt_names[OPT_MAX_DEFINED] =
  2549. {"safe_c_c", "h_safe_c_c", "safe_c_s", "h_safe_c_s",
  2550. "safe_c_ss", "h_safe_c_ss", "safe_c_sc", "h_safe_c_sc", "safe_c_cs", "h_safe_c_cs",
  2551. "safe_c_q", "h_safe_c_q", "safe_c_sq", "h_safe_c_sq", "safe_c_qs", "h_safe_c_qs", "safe_c_qq", "h_safe_c_qq",
  2552. "safe_c_cq", "h_safe_c_cq", "safe_c_qc", "h_safe_c_qc",
  2553. "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",
  2554. "safe_c_scc", "h_safe_c_scc", "safe_c_csc", "h_safe_c_csc",
  2555. "safe_c_all_s", "h_safe_c_all_s", "safe_c_all_x", "h_safe_c_all_x", "safe_c_ssa", "h_safe_c_ssa", "safe_c_sas", "h_safe_c_sas",
  2556. "safe_c_csa", "h_safe_c_csa", "safe_c_sca", "h_safe_c_sca", "safe_c_cas", "h_safe_c_cas",
  2557. "safe_c_a", "h_safe_c_a", "safe_c_aa", "h_safe_c_aa", "safe_c_aaa", "h_safe_c_aaa", "safe_c_aaaa", "h_safe_c_aaaa",
  2558. "safe_c_sqs", "h_safe_c_sqs", "safe_c_opaq", "h_safe_c_opaq", "safe_c_opaaq", "h_safe_c_opaaq", "safe_c_opaaaq", "h_safe_c_opaaaq",
  2559. "safe_c_s_opaq", "h_safe_c_s_opaq", "safe_c_s_opaaq", "h_safe_c_s_opaaq", "safe_c_s_opaaaq", "h_safe_c_s_opaaaq",
  2560. "safe_c_opcq", "h_safe_c_opcq", "safe_c_opsq", "h_safe_c_opsq",
  2561. "safe_c_opssq", "h_safe_c_opssq", "safe_c_opscq", "h_safe_c_opscq", "safe_c_opsqq", "h_safe_c_opsqq",
  2562. "safe_c_opcsq", "h_safe_c_opcsq", "safe_c_s_opsq", "h_safe_c_s_opsq",
  2563. "safe_c_c_opscq", "h_safe_c_c_opscq",
  2564. "safe_c_s_opscq", "h_safe_c_s_opscq", "safe_c_s_opcsq", "h_safe_c_s_opcsq",
  2565. "safe_c_opsq_s", "h_safe_c_opsq_s", "safe_c_opsq_c", "h_safe_c_opsq_c",
  2566. "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",
  2567. "safe_c_c_opcsq", "h_safe_c_c_opcsq", "safe_c_opcsq_c", "h_safe_c_opcsq_c",
  2568. "safe_c_s_opcq", "h_safe_c_s_opcq", "safe_c_opssq_c", "h_safe_c_opssq_c", "safe_c_c_opssq", "h_safe_c_c_opssq",
  2569. "safe_c_c_opcq", "h_safe_c_c_opcq", "safe_c_opcq_s", "h_safe_c_opcq_s",
  2570. "safe_c_opcq_opcq", "h_safe_c_opcq_opcq", "safe_c_opcq_c", "h_safe_c_opcq_c",
  2571. "safe_c_opscq_opscq", "h_safe_c_opscq_opscq", "safe_c_opssq_opssq", "h_safe_c_opssq_opssq",
  2572. "safe_c_opssq_opcq", "h_safe_c_opssq_opcq", "safe_c_opssq_opsq", "h_safe_c_opssq_opsq", "safe_c_opsq_opssq", "h_safe_c_opsq_opssq",
  2573. "safe_c_opssq_s", "h_safe_c_opssq_s", "safe_c_opscq_s", "h_safe_c_opscq_s", "safe_c_opcsq_s", "h_safe_c_opcsq_s",
  2574. "safe_c_opscq_c", "h_safe_c_opscq_c", "safe_c_opcq_opssq", "h_safe_c_opcq_opssq",
  2575. "safe_c_s_op_opssq_sq", "h_safe_c_s_op_opssq_sq", "safe_c_s_op_s_opssqq", "h_safe_c_s_op_s_opssqq",
  2576. "safe_c_op_opssq_q_c", "h_safe_c_op_opssq_q_c", "safe_c_op_opsq_q_c", "h_safe_c_op_opsq_q_c",
  2577. "safe_c_op_opssq_q_s", "h_safe_c_op_opssq_q_s", "safe_c_op_opsq_q_s", "h_safe_c_op_opsq_q_s",
  2578. "safe_c_s_op_opssq_opssqq", "h_safe_c_s_op_opssq_opssqq",
  2579. "safe_c_op_opsq_q", "h_safe_c_op_opsq_q", "safe_c_c_op_s_opcqq", "h_safe_c_c_op_s_opcqq",
  2580. "safe_c_op_s_opsq_q", "h_safe_c_op_s_opsq_q",
  2581. "safe_c_opsq_q", "h_safe_c_opsq_q", "safe_c_opsq_q_s", "h_safe_c_opsq_q_s",
  2582. "safe_c_z", "h_safe_c_z", "safe_c_zz", "h_safe_c_zz", "safe_c_sz", "h_safe_c_sz", "safe_c_zs", "h_safe_c_zs",
  2583. "safe_c_cz", "h_safe_c_cz", "safe_c_zc", "h_safe_c_zc",
  2584. "safe_c_opcq_z", "h_safe_c_opcq_z", "safe_c_s_opszq", "h_safe_c_s_opszq",
  2585. "safe_c_az", "h_safe_c_az", "safe_c_za", "h_safe_c_za",
  2586. "safe_c_zaa", "h_safe_c_zaa", "safe_c_aza", "h_safe_c_aza", "safe_c_aaz", "h_safe_c_aaz", "safe_c_ssz", "h_safe_c_ssz",
  2587. "safe_c_zza", "h_safe_c_zza", "safe_c_zaz", "h_safe_c_zaz", "safe_c_azz", "h_safe_c_azz",
  2588. "safe_c_zzz", "h_safe_c_zzz",
  2589. "thunk", "h_thunk",
  2590. "closure_s", "h_closure_s", "closure_c", "h_closure_c", "closure_q", "h_closure_q",
  2591. "closure_ss", "h_closure_ss", "closure_sc", "h_closure_sc", "closure_cs", "h_closure_cs",
  2592. "closure_a", "h_closure_a", "closure_aa", "h_closure_aa",
  2593. "closure_all_x", "h_closure_all_x", "closure_all_s", "h_closure_all_s",
  2594. "glosure_a", "h_glosure_a", "glosure_s", "h_glosure_s", "glosure_p", "h_glosure_p",
  2595. "closure_star_s", "h_closure_star_s", "closure_star_sx", "h_closure_star_sx",
  2596. "closure_star", "h_closure_star", "closure_star_all_x", "h_closure_star_all_x",
  2597. "safe_thunk", "h_safe_thunk", "safe_thunk_e", "h_safe_thunk_e", "safe_thunk_p", "h_safe_thunk_p",
  2598. "safe_closure_s", "h_safe_closure_s", "safe_closure_c", "h_safe_closure_c", "safe_closure_q", "h_safe_closure_q",
  2599. "safe_closure_ss", "h_safe_closure_ss", "safe_closure_sc", "h_safe_closure_sc", "safe_closure_cs", "h_safe_closure_cs",
  2600. "safe_closure_a", "h_safe_closure_a", "safe_closure_sa", "h_safe_closure_sa", "safe_closure_s_p", "h_safe_closure_s_p",
  2601. "safe_closure_saa", "h_safe_closure_saa",
  2602. "safe_closure_all_x", "h_safe_closure_all_x", "safe_closure_aa", "h_safe_closure_aa",
  2603. "safe_glosure_a", "h_safe_glosure_a", "safe_glosure_s", "h_safe_glosure_s", "safe_glosure_s_e", "h_safe_glosure_s_e",
  2604. "safe_glosure_p", "h_safe_glosure_p",
  2605. "safe_closure_star_s", "h_safe_closure_star_s", "safe_closure_star_ss", "h_safe_closure_star_ss",
  2606. "safe_closure_star_sc", "h_safe_closure_star_sc", "safe_closure_star_sa", "h_safe_closure_star_sa", "safe_closure_star_s0", "h_safe_closure_star_s0",
  2607. "safe_closure_star", "h_safe_closure_star", "safe_closure_star_all_x", "h_safe_closure_star_all_x",
  2608. "apply_ss", "h_apply_ss",
  2609. "c_all_x", "h_c_all_x", "call_with_exit", "h_call_with_exit", "c_catch", "h_c_catch", "c_catch_all", "h_c_catch_all",
  2610. "c_s_opsq", "h_c_s_opsq", "c_s_opcq", "h_c_s_opcq", "c_ss", "h_c_ss",
  2611. "c_s", "h_c_s", "read_s", "h_read_s", "c_p", "h_c_p", "c_z", "h_c_z", "c_sp", "h_c_sp",
  2612. "c_sz", "h_c_sz", "c_a", "h_c_a", "c_scs", "h_c_scs",
  2613. "goto", "h_goto", "goto_c", "h_goto_c", "goto_s", "h_goto_s", "goto_a", "h_goto_a",
  2614. "vector_c", "h_vector_c", "vector_s", "h_vector_s", "vector_a", "h_vector_a", "vector_cc", "h_vector_cc",
  2615. "string_c", "h_string_c", "string_s", "h_string_s", "string_a", "h_string_a",
  2616. "c_object", "h_c_object", "c_object_c", "h_c_object_c", "c_object_s", "h_c_object_s", "c_object_a", "h_c_object_a",
  2617. "pair_c", "h_pair_c", "pair_s", "h_pair_s", "pair_a", "h_pair_a",
  2618. "hash_table_c", "h_hash_table_c", "hash_table_s", "h_hash_table_s", "hash_table_a", "h_hash_table_a",
  2619. "environment_s", "h_environment_s", "environment_q", "h_environment_q", "environment_a", "h_environment_a", "environment_c", "h_environment_c",
  2620. "unknown", "h_unknown", "unknown_all_s", "h_unknown_all_s", "unknown_all_x", "h_unknown_all_x",
  2621. "unknown_g", "h_unknown_g", "unknown_gg", "h_unknown_gg", "unknown_a", "h_unknown_a", "unknown_aa", "h_unknown_aa",
  2622. "safe_c_pp", "h_safe_c_pp",
  2623. "safe_c_opsq_p", "h_safe_c_opsq_p",
  2624. "safe_c_sp", "h_safe_c_sp", "safe_c_cp", "h_safe_c_cp", "safe_c_qp", "h_safe_c_qp", "safe_c_ap", "h_safe_c_ap",
  2625. "safe_c_ps", "h_safe_c_ps", "safe_c_pc", "h_safe_c_pc", "safe_c_pq", "h_safe_c_pq",
  2626. "safe_c_ssp", "h_safe_c_ssp",
  2627. };
  2628. #endif
  2629. #define is_safe_c_op(op) (op < OP_THUNK) /* used only in safe_stepper */
  2630. #define is_unknown_op(op) ((op >= OP_UNKNOWN) && (op < OP_SAFE_C_PP))
  2631. #define is_callable_c_op(op) ((op < OP_THUNK) || (op > OP_UNKNOWN_AA)) /* used only in check_set */
  2632. static bool is_h_optimized(s7_pointer p)
  2633. {
  2634. return((is_optimized(p)) &&
  2635. ((optimize_op(p) & 1) != 0) &&
  2636. (!is_unknown_op(optimize_op(p))));
  2637. }
  2638. #define is_h_safe_c_c(P) ((is_optimized(P)) && (optimize_op(P) == HOP_SAFE_C_C))
  2639. #define is_h_safe_c_s(P) ((is_optimized(P)) && (optimize_op(P) == HOP_SAFE_C_S))
  2640. #define is_safe_c_s(P) ((is_optimized(P)) && (op_no_hop(P) == OP_SAFE_C_S))
  2641. static int position_of(s7_pointer p, s7_pointer args)
  2642. {
  2643. int i;
  2644. for (i = 1; p != args; i++, args = cdr(args));
  2645. return(i);
  2646. }
  2647. s7_pointer s7_method(s7_scheme *sc, s7_pointer obj, s7_pointer method)
  2648. {
  2649. if (has_methods(obj))
  2650. return(find_method(sc, find_let(sc, obj), method));
  2651. return(sc->undefined);
  2652. }
  2653. /* if a method is shadowing a built-in like abs, it should expect the same args as abs and
  2654. * behave the same -- no multiple values etc.
  2655. */
  2656. #define check_method(Sc, Obj, Method, Args) \
  2657. { \
  2658. s7_pointer func; \
  2659. if ((has_methods(Obj)) && ((func = find_method(Sc, find_let(Sc, Obj), Method)) != Sc->undefined)) \
  2660. return(s7_apply_function(Sc, func, Args)); \
  2661. }
  2662. #define check_two_methods(Sc, Obj, Method1, Method2, Args) \
  2663. if (has_methods(Obj)) \
  2664. { \
  2665. s7_pointer func; \
  2666. func = find_method(Sc, find_let(Sc, Obj), Method1); \
  2667. if ((func == Sc->undefined) && (Method1 != Method2) && (Method2)) func = find_method(Sc, find_let(Sc, Obj), Method2); \
  2668. if (func != Sc->undefined) return(s7_apply_function(Sc, func, Args)); \
  2669. }
  2670. static s7_pointer check_values(s7_scheme *sc, s7_pointer obj, s7_pointer args)
  2671. {
  2672. check_method(sc, obj, sc->values_symbol, args);
  2673. return(sc->gc_nil);
  2674. }
  2675. /* unfortunately, in the simplest cases, where a function (like number?) accepts any argument,
  2676. * this costs about a factor of 1.5 in speed (we're doing the normal check like s7_is_number,
  2677. * but then have to check has_methods before returning #f). We can't use the old form until
  2678. * openlet is seen because the prior code might use #_number? which gets the value
  2679. * before the switch. These simple functions normally do not dominate timing info, so I'll
  2680. * go ahead. It's mostly boilerplate:
  2681. */
  2682. #define check_boolean_method(Sc, Checker, Method, Args) \
  2683. { \
  2684. s7_pointer p; \
  2685. p = car(Args); \
  2686. if (Checker(p)) return(Sc->T); \
  2687. check_method(Sc, p, Method, Args); \
  2688. return(Sc->F); \
  2689. }
  2690. #define check_boolean_not_method(Sc, Checker, Method, Args) \
  2691. { \
  2692. s7_pointer p, func; \
  2693. p = find_symbol_checked(Sc, cadar(Args)); \
  2694. if (Checker(p)) return(Sc->F); \
  2695. if ((has_methods(p)) && ((func = find_method(Sc, find_let(Sc, p), Method)) != Sc->undefined) && \
  2696. (s7_apply_function(Sc, func, list_1(Sc, p)) != Sc->F)) \
  2697. return(Sc->F); \
  2698. return(Sc->T); \
  2699. }
  2700. #define method_or_bust(Sc, Obj, Method, Args, Type, Num) \
  2701. { \
  2702. s7_pointer func; \
  2703. if ((has_methods(Obj)) && ((func = find_method(Sc, find_let(Sc, Obj), Method)) != Sc->undefined)) \
  2704. return(s7_apply_function(Sc, func, Args)); \
  2705. if (Num == 0) return(simple_wrong_type_argument(Sc, Method, Obj, Type)); \
  2706. return(wrong_type_argument(Sc, Method, Num, Obj, Type)); \
  2707. }
  2708. #define method_or_bust_with_type(Sc, Obj, Method, Args, Type, Num) \
  2709. { \
  2710. s7_pointer func; \
  2711. if ((has_methods(Obj)) && ((func = find_method(Sc, find_let(Sc, Obj), Method)) != Sc->undefined)) \
  2712. return(s7_apply_function(Sc, func, Args)); \
  2713. if (Num == 0) return(simple_wrong_type_argument_with_type(Sc, Method, Obj, Type)); \
  2714. return(wrong_type_argument_with_type(Sc, Method, Num, Obj, Type)); \
  2715. }
  2716. #define eval_error_any(Sc, ErrType, ErrMsg, Obj) \
  2717. do {static s7_pointer _Err_ = NULL; if (!_Err_) _Err_ = s7_make_permanent_string(ErrMsg); \
  2718. return(s7_error(Sc, ErrType, set_elist_2(Sc, _Err_, Obj)));} while (0)
  2719. #define eval_error(Sc, ErrMsg, Obj) eval_error_any(Sc, Sc->syntax_error_symbol, ErrMsg, Obj)
  2720. #define eval_type_error(Sc, ErrMsg, Obj) eval_error_any(Sc, Sc->wrong_type_arg_symbol, ErrMsg, Obj)
  2721. #define eval_range_error(Sc, ErrMsg, Obj) eval_error_any(Sc, Sc->out_of_range_symbol, ErrMsg, Obj)
  2722. #define eval_error_no_return(Sc, ErrType, ErrMsg, Obj) \
  2723. do {static s7_pointer _Err_ = NULL; \
  2724. if (!_Err_) _Err_ = s7_make_permanent_string(ErrMsg); \
  2725. s7_error(Sc, ErrType, set_elist_2(Sc, _Err_, Obj));} while (0)
  2726. #define eval_error_with_caller(Sc, ErrMsg, Caller, Obj) \
  2727. do {static s7_pointer _Err_ = NULL; \
  2728. if (!_Err_) _Err_ = s7_make_permanent_string(ErrMsg); \
  2729. return(s7_error(Sc, Sc->syntax_error_symbol, set_elist_3(Sc, _Err_, Caller, Obj)));} while (0)
  2730. static s7_pointer set_elist_1(s7_scheme *sc, s7_pointer x1)
  2731. {
  2732. set_car(sc->elist_1, x1);
  2733. return(sc->elist_1);
  2734. }
  2735. static s7_pointer set_elist_2(s7_scheme *sc, s7_pointer x1, s7_pointer x2)
  2736. {
  2737. set_car(sc->elist_2, x1);
  2738. set_cadr(sc->elist_2, x2);
  2739. return(sc->elist_2);
  2740. }
  2741. static s7_pointer set_elist_3(s7_scheme *sc, s7_pointer x1, s7_pointer x2, s7_pointer x3)
  2742. {
  2743. s7_pointer p;
  2744. p = sc->elist_3;
  2745. set_car(p, x1); p = cdr(p);
  2746. set_car(p, x2); p = cdr(p);
  2747. set_car(p, x3);
  2748. return(sc->elist_3);
  2749. }
  2750. static s7_pointer set_elist_4(s7_scheme *sc, s7_pointer x1, s7_pointer x2, s7_pointer x3, s7_pointer x4)
  2751. {
  2752. s7_pointer p;
  2753. p = sc->elist_4;
  2754. set_car(p, x1); p = cdr(p);
  2755. set_car(p, x2); p = cdr(p);
  2756. set_car(p, x3); p = cdr(p);
  2757. set_car(p, x4);
  2758. return(sc->elist_4);
  2759. }
  2760. static s7_pointer set_elist_5(s7_scheme *sc, s7_pointer x1, s7_pointer x2, s7_pointer x3, s7_pointer x4, s7_pointer x5)
  2761. {
  2762. s7_pointer p;
  2763. p = sc->elist_5;
  2764. set_car(p, x1); p = cdr(p);
  2765. set_car(p, x2); p = cdr(p);
  2766. set_car(p, x3); p = cdr(p);
  2767. set_car(p, x4); p = cdr(p);
  2768. set_car(p, x5);
  2769. return(sc->elist_5);
  2770. }
  2771. static s7_pointer set_wlist_3(s7_scheme *sc, s7_pointer lst, s7_pointer x1, s7_pointer x2, s7_pointer x3)
  2772. {
  2773. s7_pointer p;
  2774. p = lst;
  2775. set_car(p, x1); p = cdr(p);
  2776. set_car(p, x2); p = cdr(p);
  2777. set_car(p, x3);
  2778. return(lst);
  2779. }
  2780. static s7_pointer set_wlist_4(s7_scheme *sc, s7_pointer lst, s7_pointer x1, s7_pointer x2, s7_pointer x3, s7_pointer x4)
  2781. {
  2782. s7_pointer p;
  2783. p = lst;
  2784. set_car(p, x1); p = cdr(p);
  2785. set_car(p, x2); p = cdr(p);
  2786. set_car(p, x3); p = cdr(p);
  2787. set_car(p, x4);
  2788. return(lst);
  2789. }
  2790. static s7_pointer set_plist_1(s7_scheme *sc, s7_pointer x1)
  2791. {
  2792. set_car(sc->plist_1, x1);
  2793. return(sc->plist_1);
  2794. }
  2795. static s7_pointer set_plist_2(s7_scheme *sc, s7_pointer x1, s7_pointer x2)
  2796. {
  2797. set_car(sc->plist_2, x1);
  2798. set_cadr(sc->plist_2, x2);
  2799. return(sc->plist_2);
  2800. }
  2801. static s7_pointer set_plist_3(s7_scheme *sc, s7_pointer x1, s7_pointer x2, s7_pointer x3)
  2802. {
  2803. return(set_wlist_3(sc, sc->plist_3, x1, x2, x3));
  2804. }
  2805. /* -------------------------------- constants -------------------------------- */
  2806. s7_pointer s7_f(s7_scheme *sc)
  2807. {
  2808. return(sc->F);
  2809. }
  2810. s7_pointer s7_t(s7_scheme *sc)
  2811. {
  2812. return(sc->T);
  2813. }
  2814. s7_pointer s7_nil(s7_scheme *sc)
  2815. {
  2816. return(sc->nil);
  2817. }
  2818. bool s7_is_null(s7_scheme *sc, s7_pointer p)
  2819. {
  2820. return(is_null(p));
  2821. }
  2822. s7_pointer s7_undefined(s7_scheme *sc)
  2823. {
  2824. return(sc->undefined);
  2825. }
  2826. s7_pointer s7_unspecified(s7_scheme *sc)
  2827. {
  2828. return(sc->unspecified);
  2829. }
  2830. bool s7_is_unspecified(s7_scheme *sc, s7_pointer val)
  2831. {
  2832. return(is_unspecified(val));
  2833. }
  2834. s7_pointer s7_eof_object(s7_scheme *sc) /* returns #<eof> -- not equivalent to "eof-object?" */
  2835. {
  2836. return(sc->eof_object);
  2837. }
  2838. static s7_pointer g_not(s7_scheme *sc, s7_pointer args)
  2839. {
  2840. #define H_not "(not obj) returns #t if obj is #f, otherwise #t: (not ()) -> #f"
  2841. #define Q_not pl_bt
  2842. return(make_boolean(sc, is_false(sc, car(args))));
  2843. }
  2844. bool s7_boolean(s7_scheme *sc, s7_pointer x)
  2845. {
  2846. return(x != sc->F);
  2847. }
  2848. bool s7_is_boolean(s7_pointer x)
  2849. {
  2850. return(type(x) == T_BOOLEAN);
  2851. }
  2852. s7_pointer s7_make_boolean(s7_scheme *sc, bool x)
  2853. {
  2854. return(make_boolean(sc, x));
  2855. }
  2856. static s7_pointer g_is_boolean(s7_scheme *sc, s7_pointer args)
  2857. {
  2858. #define H_is_boolean "(boolean? obj) returns #t if obj is #f or #t: (boolean? ()) -> #f"
  2859. #define Q_is_boolean pl_bt
  2860. check_boolean_method(sc, s7_is_boolean, sc->is_boolean_symbol, args);
  2861. }
  2862. bool s7_is_constant(s7_pointer p)
  2863. {
  2864. /* this means "always evaluates to the same thing", sort of, not "evaluates to itself":
  2865. * (let ((x 'x)) (and (not (constant? x)) (equal? x (eval x))))
  2866. * (and (constant? (list + 1)) (not (equal? (list + 1) (eval (list + 1)))))
  2867. */
  2868. return((type(p) != T_SYMBOL) || (is_immutable_symbol(p)));
  2869. }
  2870. static s7_pointer g_is_constant(s7_scheme *sc, s7_pointer args)
  2871. {
  2872. #define H_is_constant "(constant? obj) returns #t if obj is a constant (unsettable): (constant? pi) -> #t"
  2873. #define Q_is_constant pl_bt
  2874. check_boolean_method(sc, s7_is_constant, sc->is_constant_symbol, args);
  2875. }
  2876. /* -------------------------------- GC -------------------------------- */
  2877. unsigned int s7_gc_protect(s7_scheme *sc, s7_pointer x)
  2878. {
  2879. unsigned int loc;
  2880. if (sc->gpofl_loc < 0)
  2881. {
  2882. unsigned int i, size, new_size;
  2883. size = sc->protected_objects_size;
  2884. new_size = 2 * size;
  2885. vector_elements(sc->protected_objects) = (s7_pointer *)realloc(vector_elements(sc->protected_objects), new_size * sizeof(s7_pointer));
  2886. vector_length(sc->protected_objects) = new_size;
  2887. sc->protected_objects_size = new_size;
  2888. sc->gpofl = (unsigned int *)realloc(sc->gpofl, new_size * sizeof(unsigned int));
  2889. for (i = size; i < new_size; i++)
  2890. {
  2891. vector_element(sc->protected_objects, i) = sc->gc_nil;
  2892. sc->gpofl[++sc->gpofl_loc] = i;
  2893. }
  2894. }
  2895. loc = sc->gpofl[sc->gpofl_loc--];
  2896. #if DEBUGGING
  2897. if ((loc < 0) || (loc >= sc->protected_objects_size))
  2898. fprintf(stderr, "sc->gpofl loc: %u (%d)\n", loc, sc->protected_objects_size);
  2899. if (vector_element(sc->protected_objects, loc) != sc->gc_nil)
  2900. fprintf(stderr, "protected object at %u about to be clobbered? %s\n", loc, DISPLAY(vector_element(sc->protected_objects, loc)));
  2901. #endif
  2902. vector_element(sc->protected_objects, loc) = x;
  2903. return(loc);
  2904. }
  2905. void s7_gc_unprotect(s7_scheme *sc, s7_pointer x)
  2906. {
  2907. unsigned int i;
  2908. for (i = 0; i < sc->protected_objects_size; i++)
  2909. if (vector_element(sc->protected_objects, i) == x)
  2910. {
  2911. vector_element(sc->protected_objects, i) = sc->gc_nil;
  2912. sc->gpofl[++sc->gpofl_loc] = i;
  2913. return;
  2914. }
  2915. }
  2916. void s7_gc_unprotect_at(s7_scheme *sc, unsigned int loc)
  2917. {
  2918. if (loc < sc->protected_objects_size)
  2919. {
  2920. if (vector_element(sc->protected_objects, loc) != sc->gc_nil)
  2921. sc->gpofl[++sc->gpofl_loc] = loc;
  2922. vector_element(sc->protected_objects, loc) = sc->gc_nil;
  2923. }
  2924. }
  2925. s7_pointer s7_gc_protected_at(s7_scheme *sc, unsigned int loc)
  2926. {
  2927. s7_pointer obj;
  2928. obj = sc->unspecified;
  2929. if (loc < sc->protected_objects_size)
  2930. obj = vector_element(sc->protected_objects, loc);
  2931. if (obj == sc->gc_nil)
  2932. return(sc->unspecified);
  2933. return(obj);
  2934. }
  2935. #define gc_protected_at(Sc, Loc) vector_element(Sc->protected_objects, Loc)
  2936. static void (*mark_function[NUM_TYPES])(s7_pointer p);
  2937. #define S7_MARK(Obj) do {s7_pointer _p_; _p_ = Obj; if (!is_marked(_p_)) (*mark_function[unchecked_type(_p_)])(_p_);} while (0)
  2938. static void mark_symbol(s7_pointer p)
  2939. {
  2940. if (is_gensym(p))
  2941. set_mark(p);
  2942. /* don't set the mark bit of a normal symbol! It wrecks the check against SYNTACTIC_TYPE,
  2943. * slowing everything down by a large amount.
  2944. */
  2945. }
  2946. static void mark_noop(s7_pointer p) {}
  2947. /* ports can be alloc'd and freed at a frightening pace, so I think I'll make a special free_list for them. */
  2948. static port_t *alloc_port(s7_scheme *sc)
  2949. {
  2950. if (sc->port_heap)
  2951. {
  2952. port_t *p;
  2953. p = sc->port_heap;
  2954. sc->port_heap = (port_t *)(p->next);
  2955. return(p);
  2956. }
  2957. return((port_t *)calloc(1, sizeof(port_t)));
  2958. }
  2959. static void free_port(s7_scheme *sc, port_t *p)
  2960. {
  2961. p->next = (void *)(sc->port_heap);
  2962. sc->port_heap = p;
  2963. }
  2964. static void close_output_port(s7_scheme *sc, s7_pointer p);
  2965. static void sweep(s7_scheme *sc)
  2966. {
  2967. unsigned int i, j;
  2968. if (sc->strings_loc > 0)
  2969. {
  2970. /* unrolling this loop is not an improvement */
  2971. for (i = 0, j = 0; i < sc->strings_loc; i++)
  2972. {
  2973. s7_pointer s1;
  2974. s1 = sc->strings[i];
  2975. if (is_free_and_clear(s1))
  2976. {
  2977. if (string_needs_free(s1))
  2978. free(string_value(s1));
  2979. }
  2980. else sc->strings[j++] = s1;
  2981. }
  2982. sc->strings_loc = j;
  2983. }
  2984. if (sc->gensyms_loc > 0)
  2985. {
  2986. for (i = 0, j = 0; i < sc->gensyms_loc; i++)
  2987. {
  2988. s7_pointer s1;
  2989. s1 = sc->gensyms[i];
  2990. if (is_free_and_clear(s1))
  2991. {
  2992. remove_gensym_from_symbol_table(sc, s1); /* this uses symbol_name_cell data */
  2993. free(symbol_name(s1));
  2994. if ((is_documented(s1)) &&
  2995. (symbol_help(s1)))
  2996. {
  2997. free(symbol_help(s1));
  2998. symbol_help(s1) = NULL;
  2999. }
  3000. free(symbol_name_cell(s1));
  3001. }
  3002. else sc->gensyms[j++] = s1;
  3003. }
  3004. sc->gensyms_loc = j;
  3005. if (j == 0) mark_function[T_SYMBOL] = mark_noop;
  3006. }
  3007. if (sc->c_objects_loc > 0)
  3008. {
  3009. for (i = 0, j = 0; i < sc->c_objects_loc; i++)
  3010. {
  3011. if (is_free_and_clear(sc->c_objects[i]))
  3012. free_object(sc->c_objects[i]);
  3013. else sc->c_objects[j++] = sc->c_objects[i];
  3014. }
  3015. sc->c_objects_loc = j;
  3016. }
  3017. if (sc->vectors_loc > 0)
  3018. {
  3019. for (i = 0, j = 0; i < sc->vectors_loc; i++)
  3020. {
  3021. if (is_free_and_clear(sc->vectors[i]))
  3022. {
  3023. s7_pointer a;
  3024. a = sc->vectors[i];
  3025. /* a multidimensional empty vector can have dimension info, wrapped vectors always have dimension info */
  3026. if (vector_dimension_info(a))
  3027. {
  3028. if (vector_dimensions_allocated(a))
  3029. {
  3030. free(vector_dimensions(a));
  3031. free(vector_offsets(a));
  3032. }
  3033. if (vector_elements_allocated(a))
  3034. free(vector_elements(a)); /* I think this will work for any vector (int/float too) */
  3035. if (vector_dimension_info(a) != sc->wrap_only)
  3036. free(vector_dimension_info(a));
  3037. }
  3038. else
  3039. {
  3040. if (vector_length(a) != 0)
  3041. free(vector_elements(a));
  3042. }
  3043. }
  3044. else sc->vectors[j++] = sc->vectors[i];
  3045. /* here (in the else branch) if a vector constant in a global function has been removed from the heap,
  3046. * not_in_heap(heap_location(v)), and we'll never see it freed, so if there were a lot of these, they might
  3047. * glom up this loop. Surely not a big deal!?
  3048. */
  3049. }
  3050. sc->vectors_loc = j;
  3051. }
  3052. if (sc->hash_tables_loc > 0)
  3053. {
  3054. for (i = 0, j = 0; i < sc->hash_tables_loc; i++)
  3055. {
  3056. if (is_free_and_clear(sc->hash_tables[i]))
  3057. {
  3058. if (hash_table_mask(sc->hash_tables[i]) > 0)
  3059. free_hash_table(sc->hash_tables[i]);
  3060. }
  3061. else sc->hash_tables[j++] = sc->hash_tables[i];
  3062. }
  3063. sc->hash_tables_loc = j;
  3064. }
  3065. if (sc->input_ports_loc > 0)
  3066. {
  3067. for (i = 0, j = 0; i < sc->input_ports_loc; i++)
  3068. {
  3069. if (is_free_and_clear(sc->input_ports[i]))
  3070. {
  3071. s7_pointer a;
  3072. a = sc->input_ports[i];
  3073. if (port_needs_free(a))
  3074. {
  3075. if (port_data(a))
  3076. {
  3077. free(port_data(a));
  3078. port_data(a) = NULL;
  3079. port_data_size(a) = 0;
  3080. }
  3081. port_needs_free(a) = false;
  3082. }
  3083. if (port_filename(a))
  3084. {
  3085. free(port_filename(a));
  3086. port_filename(a) = NULL;
  3087. }
  3088. free_port(sc, port_port(a));
  3089. }
  3090. else sc->input_ports[j++] = sc->input_ports[i];
  3091. }
  3092. sc->input_ports_loc = j;
  3093. }
  3094. if (sc->output_ports_loc > 0)
  3095. {
  3096. for (i = 0, j = 0; i < sc->output_ports_loc; i++)
  3097. {
  3098. if (is_free_and_clear(sc->output_ports[i]))
  3099. {
  3100. close_output_port(sc, sc->output_ports[i]); /* needed for free filename, etc */
  3101. free_port(sc, port_port(sc->output_ports[i]));
  3102. }
  3103. else sc->output_ports[j++] = sc->output_ports[i];
  3104. }
  3105. sc->output_ports_loc = j;
  3106. }
  3107. if (sc->continuations_loc > 0)
  3108. {
  3109. for (i = 0, j = 0; i < sc->continuations_loc; i++)
  3110. {
  3111. if (is_free_and_clear(sc->continuations[i]))
  3112. {
  3113. s7_pointer c;
  3114. c = sc->continuations[i];
  3115. if (continuation_op_stack(c))
  3116. {
  3117. free(continuation_op_stack(c));
  3118. continuation_op_stack(c) = NULL;
  3119. }
  3120. free(continuation_data(c));
  3121. }
  3122. else sc->continuations[j++] = sc->continuations[i];
  3123. }
  3124. sc->continuations_loc = j;
  3125. }
  3126. #if WITH_GMP
  3127. if (sc->bigints_loc > 0)
  3128. {
  3129. for (i = 0, j = 0; i < sc->bigints_loc; i++)
  3130. {
  3131. s7_pointer s1;
  3132. s1 = sc->bigints[i];
  3133. if (is_free_and_clear(s1))
  3134. mpz_clear(big_integer(s1));
  3135. else sc->bigints[j++] = s1;
  3136. }
  3137. sc->bigints_loc = j;
  3138. }
  3139. if (sc->bigratios_loc > 0)
  3140. {
  3141. for (i = 0, j = 0; i < sc->bigratios_loc; i++)
  3142. {
  3143. s7_pointer s1;
  3144. s1 = sc->bigratios[i];
  3145. if (is_free_and_clear(s1))
  3146. mpq_clear(big_ratio(s1));
  3147. else sc->bigratios[j++] = s1;
  3148. }
  3149. sc->bigratios_loc = j;
  3150. }
  3151. if (sc->bigreals_loc > 0)
  3152. {
  3153. for (i = 0, j = 0; i < sc->bigreals_loc; i++)
  3154. {
  3155. s7_pointer s1;
  3156. s1 = sc->bigreals[i];
  3157. if (is_free_and_clear(s1))
  3158. mpfr_clear(big_real(s1));
  3159. else sc->bigreals[j++] = s1;
  3160. }
  3161. sc->bigreals_loc = j;
  3162. }
  3163. if (sc->bignumbers_loc > 0)
  3164. {
  3165. for (i = 0, j = 0; i < sc->bignumbers_loc; i++)
  3166. {
  3167. s7_pointer s1;
  3168. s1 = sc->bignumbers[i];
  3169. if (is_free_and_clear(s1))
  3170. mpc_clear(big_complex(s1));
  3171. else sc->bignumbers[j++] = s1;
  3172. }
  3173. sc->bignumbers_loc = j;
  3174. }
  3175. #endif
  3176. }
  3177. static void add_string(s7_scheme *sc, s7_pointer p)
  3178. {
  3179. if (sc->strings_loc == sc->strings_size)
  3180. {
  3181. sc->strings_size *= 2;
  3182. sc->strings = (s7_pointer *)realloc(sc->strings, sc->strings_size * sizeof(s7_pointer));
  3183. }
  3184. sc->strings[sc->strings_loc++] = p;
  3185. }
  3186. #define Add_String(Str) if (sc->strings_loc == sc->strings_size) add_string(sc, Str); else sc->strings[sc->strings_loc++] = Str
  3187. static void add_gensym(s7_scheme *sc, s7_pointer p)
  3188. {
  3189. if (sc->gensyms_loc == sc->gensyms_size)
  3190. {
  3191. sc->gensyms_size *= 2;
  3192. sc->gensyms = (s7_pointer *)realloc(sc->gensyms, sc->gensyms_size * sizeof(s7_pointer));
  3193. }
  3194. sc->gensyms[sc->gensyms_loc++] = p;
  3195. mark_function[T_SYMBOL] = mark_symbol;
  3196. }
  3197. static void add_c_object(s7_scheme *sc, s7_pointer p)
  3198. {
  3199. if (sc->c_objects_loc == sc->c_objects_size)
  3200. {
  3201. sc->c_objects_size *= 2;
  3202. sc->c_objects = (s7_pointer *)realloc(sc->c_objects, sc->c_objects_size * sizeof(s7_pointer));
  3203. }
  3204. sc->c_objects[sc->c_objects_loc++] = p;
  3205. }
  3206. static void add_hash_table(s7_scheme *sc, s7_pointer p)
  3207. {
  3208. if (sc->hash_tables_loc == sc->hash_tables_size)
  3209. {
  3210. sc->hash_tables_size *= 2;
  3211. sc->hash_tables = (s7_pointer *)realloc(sc->hash_tables, sc->hash_tables_size * sizeof(s7_pointer));
  3212. }
  3213. sc->hash_tables[sc->hash_tables_loc++] = p;
  3214. }
  3215. static void add_vector(s7_scheme *sc, s7_pointer p)
  3216. {
  3217. if (sc->vectors_loc == sc->vectors_size)
  3218. {
  3219. sc->vectors_size *= 2;
  3220. sc->vectors = (s7_pointer *)realloc(sc->vectors, sc->vectors_size * sizeof(s7_pointer));
  3221. }
  3222. sc->vectors[sc->vectors_loc++] = p;
  3223. }
  3224. #define Add_Vector(Vec) if (sc->vectors_loc == sc->vectors_size) add_vector(sc, Vec); else sc->vectors[sc->vectors_loc++] = Vec
  3225. static void add_input_port(s7_scheme *sc, s7_pointer p)
  3226. {
  3227. if (sc->input_ports_loc == sc->input_ports_size)
  3228. {
  3229. sc->input_ports_size *= 2;
  3230. sc->input_ports = (s7_pointer *)realloc(sc->input_ports, sc->input_ports_size * sizeof(s7_pointer));
  3231. }
  3232. sc->input_ports[sc->input_ports_loc++] = p;
  3233. }
  3234. static void add_output_port(s7_scheme *sc, s7_pointer p)
  3235. {
  3236. if (sc->output_ports_loc == sc->output_ports_size)
  3237. {
  3238. sc->output_ports_size *= 2;
  3239. sc->output_ports = (s7_pointer *)realloc(sc->output_ports, sc->output_ports_size * sizeof(s7_pointer));
  3240. }
  3241. sc->output_ports[sc->output_ports_loc++] = p;
  3242. }
  3243. static void add_continuation(s7_scheme *sc, s7_pointer p)
  3244. {
  3245. if (sc->continuations_loc == sc->continuations_size)
  3246. {
  3247. sc->continuations_size *= 2;
  3248. sc->continuations = (s7_pointer *)realloc(sc->continuations, sc->continuations_size * sizeof(s7_pointer));
  3249. }
  3250. sc->continuations[sc->continuations_loc++] = p;
  3251. }
  3252. #if WITH_GMP
  3253. static void add_bigint(s7_scheme *sc, s7_pointer p)
  3254. {
  3255. if (sc->bigints_loc == sc->bigints_size)
  3256. {
  3257. sc->bigints_size *= 2;
  3258. sc->bigints = (s7_pointer *)realloc(sc->bigints, sc->bigints_size * sizeof(s7_pointer));
  3259. }
  3260. sc->bigints[sc->bigints_loc++] = p;
  3261. }
  3262. static void add_bigratio(s7_scheme *sc, s7_pointer p)
  3263. {
  3264. if (sc->bigratios_loc == sc->bigratios_size)
  3265. {
  3266. sc->bigratios_size *= 2;
  3267. sc->bigratios = (s7_pointer *)realloc(sc->bigratios, sc->bigratios_size * sizeof(s7_pointer));
  3268. }
  3269. sc->bigratios[sc->bigratios_loc++] = p;
  3270. }
  3271. static void add_bigreal(s7_scheme *sc, s7_pointer p)
  3272. {
  3273. if (sc->bigreals_loc == sc->bigreals_size)
  3274. {
  3275. sc->bigreals_size *= 2;
  3276. sc->bigreals = (s7_pointer *)realloc(sc->bigreals, sc->bigreals_size * sizeof(s7_pointer));
  3277. }
  3278. sc->bigreals[sc->bigreals_loc++] = p;
  3279. }
  3280. static void add_bignumber(s7_scheme *sc, s7_pointer p)
  3281. {
  3282. if (sc->bignumbers_loc == sc->bignumbers_size)
  3283. {
  3284. sc->bignumbers_size *= 2;
  3285. sc->bignumbers = (s7_pointer *)realloc(sc->bignumbers, sc->bignumbers_size * sizeof(s7_pointer));
  3286. }
  3287. sc->bignumbers[sc->bignumbers_loc++] = p;
  3288. }
  3289. #endif
  3290. #define INIT_GC_CACHE_SIZE 64
  3291. static void init_gc_caches(s7_scheme *sc)
  3292. {
  3293. sc->strings_size = INIT_GC_CACHE_SIZE * 16;
  3294. sc->strings_loc = 0;
  3295. sc->strings = (s7_pointer *)malloc(sc->strings_size * sizeof(s7_pointer));
  3296. sc->gensyms_size = INIT_GC_CACHE_SIZE;
  3297. sc->gensyms_loc = 0;
  3298. sc->gensyms = (s7_pointer *)malloc(sc->gensyms_size * sizeof(s7_pointer));
  3299. sc->vectors_size = INIT_GC_CACHE_SIZE * 8;
  3300. sc->vectors_loc = 0;
  3301. sc->vectors = (s7_pointer *)malloc(sc->vectors_size * sizeof(s7_pointer));
  3302. sc->hash_tables_size = INIT_GC_CACHE_SIZE;
  3303. sc->hash_tables_loc = 0;
  3304. sc->hash_tables = (s7_pointer *)malloc(sc->hash_tables_size * sizeof(s7_pointer));
  3305. sc->input_ports_size = INIT_GC_CACHE_SIZE;
  3306. sc->input_ports_loc = 0;
  3307. sc->input_ports = (s7_pointer *)malloc(sc->input_ports_size * sizeof(s7_pointer));
  3308. sc->output_ports_size = INIT_GC_CACHE_SIZE;
  3309. sc->output_ports_loc = 0;
  3310. sc->output_ports = (s7_pointer *)malloc(sc->output_ports_size * sizeof(s7_pointer));
  3311. sc->continuations_size = INIT_GC_CACHE_SIZE;
  3312. sc->continuations_loc = 0;
  3313. sc->continuations = (s7_pointer *)malloc(sc->continuations_size * sizeof(s7_pointer));
  3314. sc->c_objects_size = INIT_GC_CACHE_SIZE;
  3315. sc->c_objects_loc = 0;
  3316. sc->c_objects = (s7_pointer *)malloc(sc->c_objects_size * sizeof(s7_pointer));
  3317. #if WITH_GMP
  3318. sc->bigints_size = INIT_GC_CACHE_SIZE;
  3319. sc->bigints_loc = 0;
  3320. sc->bigints = (s7_pointer *)malloc(sc->bigints_size * sizeof(s7_pointer));
  3321. sc->bigratios_size = INIT_GC_CACHE_SIZE;
  3322. sc->bigratios_loc = 0;
  3323. sc->bigratios = (s7_pointer *)malloc(sc->bigratios_size * sizeof(s7_pointer));
  3324. sc->bigreals_size = INIT_GC_CACHE_SIZE;
  3325. sc->bigreals_loc = 0;
  3326. sc->bigreals = (s7_pointer *)malloc(sc->bigreals_size * sizeof(s7_pointer));
  3327. sc->bignumbers_size = INIT_GC_CACHE_SIZE;
  3328. sc->bignumbers_loc = 0;
  3329. sc->bignumbers = (s7_pointer *)malloc(sc->bignumbers_size * sizeof(s7_pointer));
  3330. #endif
  3331. /* slightly unrelated... */
  3332. sc->setters_size = 4;
  3333. sc->setters_loc = 0;
  3334. sc->setters = (s7_pointer *)malloc(sc->c_objects_size * sizeof(s7_pointer));
  3335. }
  3336. static void add_setter(s7_scheme *sc, s7_pointer p, s7_pointer setter)
  3337. {
  3338. /* procedure-setters GC-protected. The c_function_setter field can't be used because the built-in functions
  3339. * are often removed from the heap and never thereafter marked.
  3340. */
  3341. unsigned int i;
  3342. for (i = 0; i < sc->setters_loc; i++)
  3343. {
  3344. s7_pointer x;
  3345. x = sc->setters[i];
  3346. if (car(x) == p)
  3347. {
  3348. set_cdr(x, setter);
  3349. return;
  3350. }
  3351. }
  3352. if (sc->setters_loc == sc->setters_size)
  3353. {
  3354. sc->setters_size *= 2;
  3355. sc->setters = (s7_pointer *)realloc(sc->setters, sc->setters_size * sizeof(s7_pointer));
  3356. }
  3357. sc->setters[sc->setters_loc++] = permanent_cons(p, setter, T_PAIR | T_IMMUTABLE);
  3358. }
  3359. static void mark_vector_1(s7_pointer p, s7_int top)
  3360. {
  3361. s7_pointer *tp, *tend, *tend4;
  3362. set_mark(p);
  3363. tp = (s7_pointer *)(vector_elements(p));
  3364. if (!tp) return;
  3365. tend = (s7_pointer *)(tp + top);
  3366. tend4 = (s7_pointer *)(tend - 4);
  3367. while (tp <= tend4)
  3368. {
  3369. S7_MARK(*tp++);
  3370. S7_MARK(*tp++);
  3371. S7_MARK(*tp++);
  3372. S7_MARK(*tp++);
  3373. }
  3374. while (tp < tend)
  3375. S7_MARK(*tp++);
  3376. }
  3377. static void mark_slot(s7_pointer p)
  3378. {
  3379. set_mark(p);
  3380. S7_MARK(slot_value(p));
  3381. if (slot_has_accessor(p))
  3382. S7_MARK(slot_accessor(p));
  3383. if (is_gensym(slot_symbol(p))) /* (let () (apply define (gensym) (list 32)) (gc) (gc) (curlet)) */
  3384. set_mark(slot_symbol(p));
  3385. }
  3386. static void mark_let(s7_pointer env)
  3387. {
  3388. s7_pointer x;
  3389. for (x = env; is_let(x) && (!is_marked(x)); x = outlet(x))
  3390. {
  3391. s7_pointer y;
  3392. set_mark(x);
  3393. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  3394. if (!is_marked(y)) /* slot value might be the enclosing let */
  3395. mark_slot(y);
  3396. }
  3397. }
  3398. static void just_mark(s7_pointer p)
  3399. {
  3400. set_mark(p);
  3401. }
  3402. static void mark_c_proc_star(s7_pointer p)
  3403. {
  3404. set_mark(p);
  3405. if (!has_simple_defaults(p))
  3406. {
  3407. s7_pointer arg;
  3408. for (arg = c_function_call_args(p); is_pair(arg); arg = cdr(arg))
  3409. S7_MARK(car(arg));
  3410. }
  3411. }
  3412. static void mark_pair(s7_pointer p)
  3413. {
  3414. s7_pointer x;
  3415. set_mark(p);
  3416. S7_MARK(car(p));
  3417. /* if the list is huge, recursion to cdr(p) is problematic when there are strict limits on the stack size
  3418. * so I'll try something else... (This form is faster according to callgrind).
  3419. *
  3420. * in snd-14 or so through 15.3, sc->temp_cell_2|3 were used for trailing args in eval, but that meant
  3421. * the !is_marked check below (which is intended to catch cyclic lists) caused cells to be missed;
  3422. * since sc->args could contain permanently marked cells, if these were passed to g_vector, for example, and
  3423. * make_vector_1 triggered a GC call, we needed to mark both the permanent (always marked) cell and its contents,
  3424. * and continue through the rest of the list. But adding temp_cell_2|3 to sc->permanent_objects was not enough.
  3425. * Now I've already forgotten the rest of the story, and it was just an hour ago! -- the upshot is that temp_cell_2|3
  3426. * are not now used as arg list members.
  3427. */
  3428. for (x = cdr(p); is_pair(x) && (!is_marked(x)); x = cdr(x))
  3429. {
  3430. set_mark(x);
  3431. S7_MARK(car(x));
  3432. }
  3433. S7_MARK(x);
  3434. }
  3435. static void mark_counter(s7_pointer p)
  3436. {
  3437. set_mark(p);
  3438. S7_MARK(counter_result(p));
  3439. S7_MARK(counter_list(p));
  3440. S7_MARK(counter_let(p));
  3441. }
  3442. static void mark_closure(s7_pointer p)
  3443. {
  3444. set_mark(p);
  3445. S7_MARK(closure_args(p));
  3446. S7_MARK(closure_body(p));
  3447. mark_let(closure_let(p));
  3448. S7_MARK(closure_setter(p));
  3449. }
  3450. static void mark_stack_1(s7_pointer p, s7_int top)
  3451. {
  3452. s7_pointer *tp, *tend;
  3453. set_mark(p);
  3454. tp = (s7_pointer *)(vector_elements(p));
  3455. if (!tp) return;
  3456. tend = (s7_pointer *)(tp + top);
  3457. while (tp < tend)
  3458. {
  3459. S7_MARK(*tp++);
  3460. S7_MARK(*tp++);
  3461. S7_MARK(*tp++);
  3462. tp++;
  3463. }
  3464. }
  3465. static void mark_stack(s7_pointer p)
  3466. {
  3467. /* we can have a bare stack awaiting a continuation to hold it if the new_cell for the continuation
  3468. * triggers the GC! But we need a top-of-stack??
  3469. */
  3470. mark_stack_1(p, temp_stack_top(p));
  3471. }
  3472. static void mark_continuation(s7_pointer p)
  3473. {
  3474. unsigned int i;
  3475. set_mark(p);
  3476. mark_stack_1(continuation_stack(p), continuation_stack_top(p));
  3477. for (i = 0; i < continuation_op_loc(p); i++)
  3478. S7_MARK(continuation_op_stack(p)[i]);
  3479. }
  3480. static void mark_vector(s7_pointer p)
  3481. {
  3482. mark_vector_1(p, vector_length(p));
  3483. }
  3484. static void mark_vector_possibly_shared(s7_pointer p)
  3485. {
  3486. /* If a subvector (an inner dimension) of a vector is the only remaining reference
  3487. * to the main vector, we want to make sure the main vector is not GC'd until
  3488. * the subvector is also GC-able. The shared_vector field either points to the
  3489. * parent vector, or it is sc->F, so we need to check for a vector parent if
  3490. * the current is multidimensional (this will include 1-dim slices). We need
  3491. * to keep the parent case separate (i.e. sc->F means the current is the original)
  3492. * so that we only free once (or remove_from_heap once).
  3493. *
  3494. * If we have a shared-vector of a shared-vector, and the middle and original are not otherwise
  3495. * in use, we mark the middle one, but (since it itself is not in use anywhere else)
  3496. * we don't mark the original! So we need to follow the share-vector chain marking every one.
  3497. */
  3498. if ((vector_has_dimensional_info(p)) &&
  3499. (s7_is_vector(shared_vector(p))))
  3500. mark_vector_possibly_shared(shared_vector(p));
  3501. mark_vector_1(p, vector_length(p));
  3502. }
  3503. static void mark_int_or_float_vector(s7_pointer p)
  3504. {
  3505. set_mark(p);
  3506. }
  3507. static void mark_int_or_float_vector_possibly_shared(s7_pointer p)
  3508. {
  3509. if ((vector_has_dimensional_info(p)) &&
  3510. (s7_is_vector(shared_vector(p))))
  3511. mark_int_or_float_vector_possibly_shared(shared_vector(p));
  3512. set_mark(p);
  3513. }
  3514. static void mark_c_object(s7_pointer p)
  3515. {
  3516. set_mark(p);
  3517. (*(c_object_mark(p)))(c_object_value(p));
  3518. }
  3519. static void mark_catch(s7_pointer p)
  3520. {
  3521. set_mark(p);
  3522. S7_MARK(catch_tag(p));
  3523. S7_MARK(catch_handler(p));
  3524. }
  3525. static void mark_dynamic_wind(s7_pointer p)
  3526. {
  3527. set_mark(p);
  3528. S7_MARK(dynamic_wind_in(p));
  3529. S7_MARK(dynamic_wind_out(p));
  3530. S7_MARK(dynamic_wind_body(p));
  3531. }
  3532. static void mark_hash_table(s7_pointer p)
  3533. {
  3534. set_mark(p);
  3535. S7_MARK(hash_table_procedures(p));
  3536. if (hash_table_entries(p) > 0)
  3537. {
  3538. unsigned int i, len;
  3539. hash_entry_t **entries;
  3540. entries = hash_table_elements(p);
  3541. len = hash_table_mask(p) + 1;
  3542. for (i = 0; i < len; i++)
  3543. {
  3544. hash_entry_t *xp;
  3545. for (xp = entries[i++]; xp; xp = xp->next)
  3546. {
  3547. S7_MARK(xp->key);
  3548. S7_MARK(xp->value);
  3549. }
  3550. for (xp = entries[i]; xp; xp = xp->next)
  3551. {
  3552. S7_MARK(xp->key);
  3553. S7_MARK(xp->value);
  3554. }
  3555. }
  3556. }
  3557. }
  3558. static void mark_iterator(s7_pointer p)
  3559. {
  3560. set_mark(p);
  3561. S7_MARK(iterator_sequence(p));
  3562. if (is_mark_seq(p))
  3563. S7_MARK(iterator_current(p));
  3564. }
  3565. static void mark_input_port(s7_pointer p)
  3566. {
  3567. set_mark(p);
  3568. set_mark(port_original_input_string(p));
  3569. }
  3570. static void gf_mark(s7_scheme *sc)
  3571. {
  3572. gc_obj *p;
  3573. if (sc->cur_rf)
  3574. for (p = sc->cur_rf->gc_list; p; p = p->nxt)
  3575. S7_MARK(p->p);
  3576. }
  3577. static void init_mark_functions(void)
  3578. {
  3579. mark_function[T_FREE] = mark_noop;
  3580. mark_function[T_UNIQUE] = mark_noop;
  3581. mark_function[T_UNSPECIFIED] = mark_noop;
  3582. mark_function[T_NIL] = mark_noop;
  3583. mark_function[T_BOOLEAN] = mark_noop;
  3584. mark_function[T_STRING] = just_mark;
  3585. mark_function[T_INTEGER] = just_mark;
  3586. mark_function[T_RATIO] = just_mark;
  3587. mark_function[T_REAL] = just_mark;
  3588. mark_function[T_COMPLEX] = just_mark;
  3589. mark_function[T_BIG_INTEGER] = just_mark;
  3590. mark_function[T_BIG_RATIO] = just_mark;
  3591. mark_function[T_BIG_REAL] = just_mark;
  3592. mark_function[T_BIG_COMPLEX] = just_mark;
  3593. mark_function[T_SYMBOL] = mark_noop; /* this changes to mark_symbol when gensyms are in the heap */
  3594. mark_function[T_PAIR] = mark_pair;
  3595. mark_function[T_CLOSURE] = mark_closure;
  3596. mark_function[T_CLOSURE_STAR] = mark_closure;
  3597. mark_function[T_CONTINUATION] = mark_continuation;
  3598. mark_function[T_CHARACTER] = mark_noop;
  3599. mark_function[T_INPUT_PORT] = mark_input_port;
  3600. mark_function[T_VECTOR] = mark_vector; /* this changes if shared vector created (similarly below) */
  3601. mark_function[T_INT_VECTOR] = mark_int_or_float_vector;
  3602. mark_function[T_FLOAT_VECTOR] = mark_int_or_float_vector;
  3603. mark_function[T_MACRO] = mark_closure;
  3604. mark_function[T_BACRO] = mark_closure;
  3605. mark_function[T_MACRO_STAR] = mark_closure;
  3606. mark_function[T_BACRO_STAR] = mark_closure;
  3607. mark_function[T_C_OBJECT] = mark_c_object;
  3608. mark_function[T_RANDOM_STATE] = just_mark;
  3609. mark_function[T_GOTO] = just_mark;
  3610. mark_function[T_OUTPUT_PORT] = just_mark;
  3611. mark_function[T_CATCH] = mark_catch;
  3612. mark_function[T_DYNAMIC_WIND] = mark_dynamic_wind;
  3613. mark_function[T_HASH_TABLE] = mark_hash_table;
  3614. mark_function[T_ITERATOR] = mark_iterator;
  3615. mark_function[T_SYNTAX] = mark_noop;
  3616. mark_function[T_LET] = mark_let;
  3617. mark_function[T_STACK] = mark_stack;
  3618. mark_function[T_COUNTER] = mark_counter;
  3619. mark_function[T_SLOT] = mark_slot;
  3620. mark_function[T_BAFFLE] = just_mark;
  3621. mark_function[T_C_MACRO] = just_mark;
  3622. mark_function[T_C_POINTER] = just_mark;
  3623. mark_function[T_C_FUNCTION] = just_mark;
  3624. mark_function[T_C_FUNCTION_STAR] = just_mark; /* changes to mark_c_proc_star if defaults involve an expression */
  3625. mark_function[T_C_ANY_ARGS_FUNCTION] = just_mark;
  3626. mark_function[T_C_OPT_ARGS_FUNCTION] = just_mark;
  3627. mark_function[T_C_RST_ARGS_FUNCTION] = just_mark;
  3628. }
  3629. static void mark_op_stack(s7_scheme *sc)
  3630. {
  3631. s7_pointer *p, *tp;
  3632. tp = sc->op_stack_now;
  3633. p = sc->op_stack;
  3634. while (p < tp)
  3635. S7_MARK(*p++);
  3636. }
  3637. static void mark_rootlet(s7_scheme *sc)
  3638. {
  3639. s7_pointer ge;
  3640. s7_pointer *tmp, *top;
  3641. ge = sc->rootlet;
  3642. tmp = vector_elements(ge);
  3643. top = (s7_pointer *)(tmp + sc->rootlet_entries);
  3644. set_mark(ge);
  3645. while (tmp < top)
  3646. S7_MARK(slot_value(*tmp++));
  3647. }
  3648. void s7_mark_object(s7_pointer p)
  3649. {
  3650. S7_MARK(p);
  3651. }
  3652. static void mark_permanent_objects(s7_scheme *sc)
  3653. {
  3654. gc_obj *g;
  3655. for (g = sc->permanent_objects; g; g = (gc_obj *)(g->nxt))
  3656. S7_MARK(g->p);
  3657. }
  3658. static void unmark_permanent_objects(s7_scheme *sc)
  3659. {
  3660. gc_obj *g;
  3661. for (g = sc->permanent_objects; g; g = (gc_obj *)(g->nxt))
  3662. clear_mark(g->p);
  3663. }
  3664. #ifndef _MSC_VER
  3665. #include <time.h>
  3666. #include <sys/time.h>
  3667. static struct timeval start_time;
  3668. static struct timezone z0;
  3669. #endif
  3670. #if DEBUGGING
  3671. static int last_gc_line = 0;
  3672. static const char *last_gc_func = NULL;
  3673. #endif
  3674. #define GC_STATS 1
  3675. #define HEAP_STATS 2
  3676. #define STACK_STATS 4
  3677. #define show_gc_stats(Sc) ((Sc->gc_stats & GC_STATS) != 0)
  3678. #define show_stack_stats(Sc) ((Sc->gc_stats & STACK_STATS) != 0)
  3679. #define show_heap_stats(Sc) ((Sc->gc_stats & HEAP_STATS) != 0)
  3680. static int gc(s7_scheme *sc)
  3681. {
  3682. s7_cell **old_free_heap_top;
  3683. /* mark all live objects (the symbol table is in permanent memory, not the heap) */
  3684. #if DEBUGGING
  3685. #define gc_call(P, Tp) \
  3686. p = (*tp++); \
  3687. if (is_marked(p)) \
  3688. clear_mark(p); \
  3689. else \
  3690. { \
  3691. if (!is_free_and_clear(p)) \
  3692. { \
  3693. p->debugger_bits = 0; p->gc_line = last_gc_line; p->gc_func = last_gc_func; \
  3694. clear_type(p); \
  3695. (*fp++) = p;\
  3696. }}
  3697. #else
  3698. #define gc_call(P, Tp) p = (*tp++); if (is_marked(p)) clear_mark(p); else {if (!is_free_and_clear(p)) {clear_type(p); (*fp++) = p;}}
  3699. #endif
  3700. if (show_gc_stats(sc))
  3701. {
  3702. fprintf(stdout, "gc ");
  3703. #if DEBUGGING
  3704. fprintf(stdout, "%s[%d] ", last_gc_func, last_gc_line);
  3705. #endif
  3706. #ifndef _MSC_VER
  3707. /* this is apparently deprecated in favor of clock_gettime -- what compile-time switch to use here?
  3708. * _POSIX_TIMERS, or perhaps use CLOCK_REALTIME, but clock_gettime requires -lrt -- no thanks.
  3709. */
  3710. gettimeofday(&start_time, &z0);
  3711. #endif
  3712. }
  3713. mark_rootlet(sc);
  3714. S7_MARK(sc->args);
  3715. mark_let(sc->envir);
  3716. slot_set_value(sc->error_data, sc->F);
  3717. /* the other choice here is to explicitly mark slot_value(sc->error_data) as we do eval_history1/2 below.
  3718. * in both cases, the values are permanent lists that do not mark impermanent contents.
  3719. * this will need circular list checks, and can't depend on marked to exit early
  3720. */
  3721. mark_let(sc->owlet);
  3722. #if WITH_HISTORY
  3723. {
  3724. s7_pointer p1, p2;
  3725. for (p1 = sc->eval_history1, p2 = sc->eval_history2; ; p2 = cdr(p2))
  3726. {
  3727. S7_MARK(car(p1));
  3728. S7_MARK(car(p2));
  3729. p1 = cdr(p1);
  3730. if (p1 == sc->eval_history1) break; /* these are circular lists */
  3731. }
  3732. }
  3733. #endif
  3734. S7_MARK(sc->code);
  3735. mark_current_code(sc);
  3736. mark_stack_1(sc->stack, s7_stack_top(sc));
  3737. S7_MARK(sc->v);
  3738. S7_MARK(sc->w);
  3739. S7_MARK(sc->x);
  3740. S7_MARK(sc->y);
  3741. S7_MARK(sc->z);
  3742. S7_MARK(sc->value);
  3743. S7_MARK(sc->temp1);
  3744. S7_MARK(sc->temp2);
  3745. S7_MARK(sc->temp3);
  3746. S7_MARK(sc->temp4);
  3747. S7_MARK(sc->temp5);
  3748. S7_MARK(sc->temp6);
  3749. S7_MARK(sc->temp7);
  3750. S7_MARK(sc->temp8);
  3751. S7_MARK(sc->temp9);
  3752. S7_MARK(sc->temp10);
  3753. gf_mark(sc);
  3754. set_mark(sc->input_port);
  3755. S7_MARK(sc->input_port_stack);
  3756. set_mark(sc->output_port);
  3757. set_mark(sc->error_port);
  3758. S7_MARK(sc->stacktrace_defaults);
  3759. S7_MARK(sc->autoload_table);
  3760. S7_MARK(sc->default_rng);
  3761. mark_pair(sc->temp_cell_1);
  3762. mark_pair(sc->temp_cell_2);
  3763. S7_MARK(car(sc->t1_1));
  3764. S7_MARK(car(sc->t2_1));
  3765. S7_MARK(car(sc->t2_2));
  3766. S7_MARK(car(sc->t3_1));
  3767. S7_MARK(car(sc->t3_2));
  3768. S7_MARK(car(sc->t3_3));
  3769. S7_MARK(car(sc->a4_1));
  3770. S7_MARK(car(sc->a4_2));
  3771. S7_MARK(car(sc->a4_3));
  3772. S7_MARK(car(sc->a4_4));
  3773. S7_MARK(car(sc->plist_1));
  3774. S7_MARK(car(sc->plist_2));
  3775. S7_MARK(cadr(sc->plist_2));
  3776. S7_MARK(car(sc->plist_3));
  3777. S7_MARK(cadr(sc->plist_3));
  3778. S7_MARK(caddr(sc->plist_3));
  3779. {
  3780. unsigned int i;
  3781. s7_pointer p;
  3782. for (i = 1; i < NUM_SAFE_LISTS; i++)
  3783. if (list_is_in_use(sc->safe_lists[i]))
  3784. for (p = sc->safe_lists[i]; is_pair(p); p = cdr(p))
  3785. S7_MARK(car(p));
  3786. for (i = 0; i < sc->setters_loc; i++)
  3787. S7_MARK(cdr(sc->setters[i]));
  3788. }
  3789. {
  3790. int i;
  3791. for (i = 0; i < sc->num_fdats; i++)
  3792. if (sc->fdats[i])
  3793. S7_MARK(sc->fdats[i]->curly_arg);
  3794. }
  3795. S7_MARK(sc->protected_objects);
  3796. S7_MARK(sc->protected_accessors);
  3797. /* now protect recent allocations using the free_heap cells above the current free_heap_top (if any).
  3798. *
  3799. * cells above sc->free_heap_top might be malloc'd garbage (after heap reallocation), so we keep track of
  3800. * where the last actually freed cells were after the previous GC call. We're trying to
  3801. * GC protect the previous GC_TEMPS_SIZE allocated pointers so that the caller doesn't have
  3802. * to gc-protect every temporary cell.
  3803. *
  3804. * There's one remaining possible problem. s7_remove_from_heap frees cells outside
  3805. * the GC and might push free_heap_top beyond its previous_free_heap_top, then
  3806. * an immediate explicit gc call might not see those temp cells.
  3807. */
  3808. {
  3809. s7_pointer *tmps, *tmps_top;
  3810. tmps = sc->free_heap_top;
  3811. tmps_top = tmps + GC_TEMPS_SIZE;
  3812. if (tmps_top > sc->previous_free_heap_top)
  3813. tmps_top = sc->previous_free_heap_top;
  3814. while (tmps < tmps_top)
  3815. S7_MARK(*tmps++);
  3816. }
  3817. mark_op_stack(sc);
  3818. mark_permanent_objects(sc);
  3819. /* free up all unmarked objects */
  3820. old_free_heap_top = sc->free_heap_top;
  3821. {
  3822. s7_pointer *fp, *tp, *heap_top;
  3823. fp = sc->free_heap_top;
  3824. tp = sc->heap;
  3825. heap_top = (s7_pointer *)(sc->heap + sc->heap_size);
  3826. while (tp < heap_top) /* != here or ^ makes no difference */
  3827. {
  3828. s7_pointer p;
  3829. /* from here down is gc_call, but I wanted one case explicit for readability */
  3830. p = (*tp++);
  3831. if (is_marked(p)) /* this order is faster than checking typeflag(p) != T_FREE first */
  3832. clear_mark(p);
  3833. else
  3834. {
  3835. if (!is_free_and_clear(p)) /* if T_FREE, it's an already-free object -- the free_heap is usually not empty when we call the GC */
  3836. {
  3837. #if DEBUGGING
  3838. p->debugger_bits = 0;
  3839. #endif
  3840. clear_type(p); /* (this is needed -- otherwise we try to free some objects twice) */
  3841. (*fp++) = p;
  3842. }
  3843. }
  3844. /* this looks crazy, but it speeds up the entire GC process by 25%!
  3845. * going from 16 to 32 saves .2% so it may not matter.
  3846. */
  3847. gc_call(p, tp);
  3848. gc_call(p, tp);
  3849. gc_call(p, tp);
  3850. gc_call(p, tp);
  3851. gc_call(p, tp);
  3852. gc_call(p, tp);
  3853. gc_call(p, tp);
  3854. gc_call(p, tp);
  3855. gc_call(p, tp);
  3856. gc_call(p, tp);
  3857. gc_call(p, tp);
  3858. gc_call(p, tp);
  3859. gc_call(p, tp);
  3860. gc_call(p, tp);
  3861. gc_call(p, tp);
  3862. gc_call(p, tp);
  3863. gc_call(p, tp);
  3864. gc_call(p, tp);
  3865. gc_call(p, tp);
  3866. gc_call(p, tp);
  3867. gc_call(p, tp);
  3868. gc_call(p, tp);
  3869. gc_call(p, tp);
  3870. gc_call(p, tp);
  3871. gc_call(p, tp);
  3872. gc_call(p, tp);
  3873. gc_call(p, tp);
  3874. gc_call(p, tp);
  3875. gc_call(p, tp);
  3876. gc_call(p, tp);
  3877. gc_call(p, tp);
  3878. }
  3879. sc->free_heap_top = fp;
  3880. sweep(sc);
  3881. }
  3882. unmark_permanent_objects(sc);
  3883. sc->gc_freed = (int)(sc->free_heap_top - old_free_heap_top);
  3884. if (show_gc_stats(sc))
  3885. {
  3886. #ifndef _MSC_VER
  3887. struct timeval t0;
  3888. double secs;
  3889. gettimeofday(&t0, &z0);
  3890. secs = (t0.tv_sec - start_time.tv_sec) + 0.000001 * (t0.tv_usec - start_time.tv_usec);
  3891. #if (PRINT_NAME_PADDING == 8)
  3892. fprintf(stdout, "freed %d/%u (free: %d), time: %f\n", sc->gc_freed, sc->heap_size, sc->free_heap_top - sc->free_heap, secs);
  3893. #else
  3894. fprintf(stdout, "freed %d/%u (free: %ld), time: %f\n", sc->gc_freed, sc->heap_size, sc->free_heap_top - sc->free_heap, secs);
  3895. #endif
  3896. #else
  3897. fprintf(stdout, "freed %d/%u\n", sc->gc_freed, sc->heap_size);
  3898. #endif
  3899. }
  3900. /* if (sc->begin_hook) call_begin_hook(sc); */
  3901. sc->previous_free_heap_top = sc->free_heap_top;
  3902. return(sc->gc_freed); /* needed by cell allocator to decide when to increase heap size */
  3903. }
  3904. void s7_gc_stats(s7_scheme *sc, bool on) {sc->gc_stats = (on) ? GC_STATS : 0;}
  3905. unsigned int s7_heap_size(s7_scheme *sc) {return(sc->heap_size);}
  3906. int s7_gc_freed(s7_scheme *sc) {return(sc->gc_freed);}
  3907. #define GC_TRIGGER_SIZE 64
  3908. /* new_cell has to include the new cell's type. In the free list, it is 0 (T_FREE). If we remove it here,
  3909. * but then hit some error before setting the type, the GC sweep thinks it is a free cell already and
  3910. * does not return it to the free list: a memory leak.
  3911. */
  3912. #if (!DEBUGGING)
  3913. #define new_cell(Sc, Obj, Type) \
  3914. do { \
  3915. if (Sc->free_heap_top <= Sc->free_heap_trigger) try_to_call_gc(Sc); \
  3916. Obj = (*(--(Sc->free_heap_top))); \
  3917. set_type(Obj, Type); \
  3918. } while (0)
  3919. #define new_cell_no_check(Sc, Obj, Type) do {Obj = (*(--(Sc->free_heap_top))); set_type(Obj, Type);} while (0)
  3920. /* since sc->free_heap_trigger is GC_TRIGGER_SIZE above the free heap base, we don't need
  3921. * to check it repeatedly after the first such check.
  3922. */
  3923. #else
  3924. static bool for_any_other_reason(s7_scheme *sc, int line)
  3925. {
  3926. #if 0
  3927. static int ctr = 0;
  3928. if ((sc->default_rng) &&
  3929. (!sc->gc_off) &&
  3930. (ctr > GC_TRIGGER_SIZE))
  3931. {
  3932. s7_double x;
  3933. x = next_random(sc->default_rng);
  3934. if (x > .995)
  3935. {
  3936. ctr = 0;
  3937. return(true);
  3938. }
  3939. }
  3940. ctr++;
  3941. #endif
  3942. return(false);
  3943. }
  3944. #define new_cell(Sc, Obj, Type) \
  3945. do { \
  3946. if ((Sc->free_heap_top <= Sc->free_heap_trigger) || (for_any_other_reason(sc, __LINE__))) {last_gc_line = __LINE__; last_gc_func = __func__; try_to_call_gc(Sc);} \
  3947. Obj = (*(--(Sc->free_heap_top))); \
  3948. Obj->alloc_line = __LINE__; Obj->alloc_func = __func__; \
  3949. set_type(Obj, Type); \
  3950. } while (0)
  3951. #define new_cell_no_check(Sc, Obj, Type) \
  3952. do { \
  3953. Obj = (*(--(Sc->free_heap_top))); \
  3954. Obj->alloc_line = __LINE__; Obj->alloc_func = __func__; \
  3955. set_type(Obj, Type); \
  3956. } while (0)
  3957. #endif
  3958. static void resize_heap(s7_scheme *sc)
  3959. {
  3960. /* alloc more heap */
  3961. unsigned int old_size, old_free, k;
  3962. s7_cell *cells;
  3963. s7_pointer p;
  3964. old_size = sc->heap_size;
  3965. old_free = sc->free_heap_top - sc->free_heap;
  3966. if (sc->heap_size < 512000)
  3967. sc->heap_size *= 2;
  3968. else sc->heap_size += 512000;
  3969. sc->heap = (s7_cell **)realloc(sc->heap, sc->heap_size * sizeof(s7_cell *));
  3970. if (!(sc->heap))
  3971. s7_warn(sc, 256, "heap reallocation failed! tried to get %lu bytes\n", (unsigned long)(sc->heap_size * sizeof(s7_cell *)));
  3972. sc->free_heap = (s7_cell **)realloc(sc->free_heap, sc->heap_size * sizeof(s7_cell *));
  3973. if (!(sc->free_heap))
  3974. s7_warn(sc, 256, "free heap reallocation failed! tried to get %lu bytes\n", (unsigned long)(sc->heap_size * sizeof(s7_cell *)));
  3975. sc->free_heap_trigger = (s7_cell **)(sc->free_heap + GC_TRIGGER_SIZE);
  3976. sc->free_heap_top = sc->free_heap + old_free; /* incremented below, added old_free 21-Aug-12?!? */
  3977. /* optimization suggested by K Matheussen */
  3978. cells = (s7_cell *)calloc(sc->heap_size - old_size, sizeof(s7_cell));
  3979. for (p = cells, k = old_size; k < sc->heap_size;)
  3980. {
  3981. sc->heap[k] = p;
  3982. heap_location(p) = k++;
  3983. (*sc->free_heap_top++) = p++;
  3984. sc->heap[k] = p;
  3985. heap_location(p) = k++;
  3986. (*sc->free_heap_top++) = p++;
  3987. sc->heap[k] = p;
  3988. heap_location(p) = k++;
  3989. (*sc->free_heap_top++) = p++;
  3990. sc->heap[k] = p;
  3991. heap_location(p) = k++;
  3992. (*sc->free_heap_top++) = p++;
  3993. }
  3994. sc->previous_free_heap_top = sc->free_heap_top;
  3995. if (show_heap_stats(sc))
  3996. fprintf(stderr, "heap grows to %u\n", sc->heap_size);
  3997. }
  3998. static void try_to_call_gc(s7_scheme *sc)
  3999. {
  4000. /* called only from new_cell and cons */
  4001. if (sc->gc_off)
  4002. {
  4003. /* we can't just return here! Someone needs a new cell, and once the heap free list is exhausted, segfault */
  4004. resize_heap(sc);
  4005. }
  4006. else
  4007. {
  4008. #if (!DEBUGGING)
  4009. unsigned int freed_heap;
  4010. freed_heap = gc(sc);
  4011. if ((freed_heap < sc->heap_size / 2) &&
  4012. (freed_heap < 1000000)) /* if huge heap */
  4013. resize_heap(sc);
  4014. #else
  4015. gc(sc);
  4016. if ((unsigned int)(sc->free_heap_top - sc->free_heap) < sc->heap_size / 2)
  4017. resize_heap(sc);
  4018. #endif
  4019. }
  4020. }
  4021. /* originally I tried to mark each temporary value until I was done with it, but
  4022. * that way madness lies... By delaying GC of _every_ %$^#%@ pointer, I can dispense
  4023. * with hundreds of individual protections. So the free_heap's last GC_TEMPS_SIZE
  4024. * allocated pointers are protected during the mark sweep.
  4025. */
  4026. static s7_pointer g_gc(s7_scheme *sc, s7_pointer args)
  4027. {
  4028. #define H_gc "(gc (on #t)) runs the garbage collector. If 'on' is supplied, it turns the GC on or off. \
  4029. Evaluation produces a surprising amount of garbage, so don't leave the GC off for very long!"
  4030. #define Q_gc s7_make_signature(sc, 2, sc->T, sc->is_boolean_symbol)
  4031. if (is_not_null(args))
  4032. {
  4033. if (!s7_is_boolean(car(args)))
  4034. method_or_bust(sc, car(args), sc->gc_symbol, args, T_BOOLEAN, 0);
  4035. sc->gc_off = (car(args) == sc->F);
  4036. if (sc->gc_off)
  4037. return(sc->F);
  4038. }
  4039. #if DEBUGGING
  4040. last_gc_line = __LINE__;
  4041. last_gc_func = __func__;
  4042. #endif
  4043. gc(sc);
  4044. return(sc->unspecified);
  4045. }
  4046. s7_pointer s7_gc_on(s7_scheme *sc, bool on)
  4047. {
  4048. sc->gc_off = !on;
  4049. return(s7_make_boolean(sc, on));
  4050. }
  4051. static int permanent_cells = 0;
  4052. #if (!WITH_THREADS)
  4053. static s7_cell *alloc_pointer(void)
  4054. {
  4055. #define ALLOC_SIZE 256
  4056. static unsigned int alloc_k = ALLOC_SIZE;
  4057. static s7_cell *alloc_cells = NULL;
  4058. if (alloc_k == ALLOC_SIZE) /* if either no current block or the block is used up */
  4059. { /* make a new block */
  4060. permanent_cells += ALLOC_SIZE;
  4061. alloc_cells = (s7_cell *)calloc(ALLOC_SIZE, sizeof(s7_cell));
  4062. alloc_k = 0;
  4063. }
  4064. return(&alloc_cells[alloc_k++]);
  4065. }
  4066. #else
  4067. #define alloc_pointer() (s7_cell *)calloc(1, sizeof(s7_cell))
  4068. #endif
  4069. static void add_permanent_object(s7_scheme *sc, s7_pointer obj)
  4070. {
  4071. gc_obj *g;
  4072. g = (gc_obj *)malloc(sizeof(gc_obj));
  4073. g->p = obj;
  4074. g->nxt = sc->permanent_objects;
  4075. sc->permanent_objects = g;
  4076. }
  4077. static void free_cell(s7_scheme *sc, s7_pointer p)
  4078. {
  4079. #if DEBUGGING
  4080. p->debugger_bits = 0;
  4081. #endif
  4082. clear_type(p);
  4083. (*(sc->free_heap_top++)) = p;
  4084. }
  4085. static void s7_remove_from_heap(s7_scheme *sc, s7_pointer x)
  4086. {
  4087. int loc;
  4088. s7_pointer p;
  4089. /* global functions are very rarely redefined, so we can remove the function body from
  4090. * the heap when it is defined. If redefined, we currently lose the memory held by the
  4091. * old definition. (It is not trivial to recover this memory because it is allocated
  4092. * in blocks, not by the pointer, I think, but s7_define is the point to try).
  4093. *
  4094. * There is at least one problem with this: if, for example, a function has
  4095. * a quoted (constant) list, then uses list-set! to change an element of it,
  4096. * then a GC happens, and the new element is GC'd because no one in the heap
  4097. * points to it, then we call the function again, and it tries to access
  4098. * that element.
  4099. *
  4100. * (define (bad-idea)
  4101. * (let ((lst '(1 2 3)))
  4102. * (let ((result (list-ref lst 1)))
  4103. * (list-set! lst 1 (* 2.0 16.6))
  4104. * (gc)
  4105. * result)))
  4106. *
  4107. * put that in a file, load it (to force removal), than call bad-idea a few times.
  4108. * so... if (*s7* 'safety) is not 0, remove-from-heap is disabled.
  4109. */
  4110. loc = heap_location(x);
  4111. if (not_in_heap(x)) return;
  4112. switch (type(x))
  4113. {
  4114. case T_PAIR:
  4115. unheap(x);
  4116. p = alloc_pointer();
  4117. sc->heap[loc] = p;
  4118. (*sc->free_heap_top++) = p;
  4119. heap_location(p) = loc;
  4120. #if 0
  4121. /* this code fixes the problem above, but at some cost (gc + mark_pair up by about 2% in the worst case (snd-test.scm)) */
  4122. if ((car(x) == sc->quote_symbol) &&
  4123. (is_pair(cadr(x))))
  4124. {
  4125. add_permanent_object(sc, cdr(x));
  4126. }
  4127. else
  4128. {
  4129. s7_remove_from_heap(sc, car(x));
  4130. s7_remove_from_heap(sc, cdr(x));
  4131. }
  4132. #else
  4133. s7_remove_from_heap(sc, car(x));
  4134. s7_remove_from_heap(sc, cdr(x));
  4135. #endif
  4136. return;
  4137. case T_HASH_TABLE:
  4138. case T_LET:
  4139. case T_VECTOR:
  4140. /* not int|float_vector or string because none of their elements are GC-able (so unheap below is ok)
  4141. * but hash-table and let seem like they need protection? And let does happen via define-class.
  4142. */
  4143. add_permanent_object(sc, x);
  4144. return;
  4145. case T_SYNTAX:
  4146. return;
  4147. case T_SYMBOL:
  4148. if (is_gensym(x))
  4149. {
  4150. unsigned int i;
  4151. sc->heap[loc] = alloc_pointer();
  4152. free_cell(sc, sc->heap[loc]);
  4153. heap_location(sc->heap[loc]) = loc;
  4154. /* unheap(x); */
  4155. heap_location(x) = -heap_location(x);
  4156. /* if gensym is a hash-table key, then is removed from the heap, we need to be sure the hash-table map to it
  4157. * continues to be valid. symbol_hmap is abs(heap_location), and the possible overlap with other not-in-heap
  4158. * ints is not problematic (they'll just hash to the same location).
  4159. */
  4160. for (i = 0; i < sc->gensyms_loc; i++) /* sc->gensyms reaches size 512 during s7test, but this search is called 3 times and costs nothing */
  4161. if (sc->gensyms[i] == x)
  4162. {
  4163. unsigned int j;
  4164. for (j = i + 1; i < sc->gensyms_loc - 1; i++, j++)
  4165. sc->gensyms[i] = sc->gensyms[j];
  4166. sc->gensyms[i] = NULL;
  4167. sc->gensyms_loc--;
  4168. if (sc->gensyms_loc == 0) mark_function[T_SYMBOL] = mark_noop;
  4169. break;
  4170. }
  4171. }
  4172. return;
  4173. case T_CLOSURE: case T_CLOSURE_STAR:
  4174. case T_MACRO: case T_MACRO_STAR:
  4175. case T_BACRO: case T_BACRO_STAR:
  4176. unheap(x);
  4177. p = alloc_pointer();
  4178. free_cell(sc, p);
  4179. sc->heap[loc] = p;
  4180. heap_location(p) = loc;
  4181. s7_remove_from_heap(sc, closure_args(x));
  4182. s7_remove_from_heap(sc, closure_body(x));
  4183. return;
  4184. default:
  4185. break;
  4186. }
  4187. unheap(x);
  4188. p = alloc_pointer();
  4189. free_cell(sc, p);
  4190. sc->heap[loc] = p;
  4191. heap_location(p) = loc;
  4192. }
  4193. /* -------------------------------- stacks -------------------------------- */
  4194. #define OP_STACK_INITIAL_SIZE 32
  4195. #if DEBUGGING
  4196. #define stop_at_error true
  4197. static void push_op_stack(s7_scheme *sc, s7_pointer op)
  4198. {
  4199. (*sc->op_stack_now++) = _NFre(op);
  4200. if (sc->op_stack_now > (sc->op_stack + sc->op_stack_size))
  4201. {
  4202. fprintf(stderr, "%sop_stack overflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
  4203. if (stop_at_error) abort();
  4204. }
  4205. }
  4206. static s7_pointer pop_op_stack(s7_scheme *sc)
  4207. {
  4208. s7_pointer op;
  4209. op = (*(--(sc->op_stack_now)));
  4210. if (sc->op_stack_now < sc->op_stack)
  4211. {
  4212. fprintf(stderr, "%sop_stack underflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
  4213. if (stop_at_error) abort();
  4214. }
  4215. return(_NFre(op));
  4216. }
  4217. #else
  4218. #define push_op_stack(Sc, Op) (*Sc->op_stack_now++) = Op
  4219. #define pop_op_stack(Sc) (*(--(Sc->op_stack_now)))
  4220. #endif
  4221. static void initialize_op_stack(s7_scheme *sc)
  4222. {
  4223. int i;
  4224. sc->op_stack = (s7_pointer *)malloc(OP_STACK_INITIAL_SIZE * sizeof(s7_pointer));
  4225. sc->op_stack_size = OP_STACK_INITIAL_SIZE;
  4226. sc->op_stack_now = sc->op_stack;
  4227. sc->op_stack_end = (s7_pointer *)(sc->op_stack + sc->op_stack_size);
  4228. for (i = 0; i < OP_STACK_INITIAL_SIZE; i++)
  4229. sc->op_stack[i] = sc->nil;
  4230. }
  4231. static void resize_op_stack(s7_scheme *sc)
  4232. {
  4233. int i, loc, new_size;
  4234. loc = (int)(sc->op_stack_now - sc->op_stack);
  4235. new_size = sc->op_stack_size * 2;
  4236. sc->op_stack = (s7_pointer *)realloc((void *)(sc->op_stack), new_size * sizeof(s7_pointer));
  4237. for (i = sc->op_stack_size; i < new_size; i++)
  4238. sc->op_stack[i] = sc->nil;
  4239. sc->op_stack_size = new_size;
  4240. sc->op_stack_now = (s7_pointer *)(sc->op_stack + loc);
  4241. sc->op_stack_end = (s7_pointer *)(sc->op_stack + sc->op_stack_size);
  4242. }
  4243. #define stack_code(Stack, Loc) vector_element(_TStk(Stack), Loc - 3)
  4244. #define stack_let(Stack, Loc) vector_element(_TStk(Stack), Loc - 2)
  4245. #define stack_args(Stack, Loc) vector_element(_TStk(Stack), Loc - 1)
  4246. #define stack_op(Stack, Loc) ((opcode_t)(vector_element(_TStk(Stack), Loc)))
  4247. #if DEBUGGING
  4248. static void pop_stack(s7_scheme *sc)
  4249. {
  4250. opcode_t cur_op;
  4251. cur_op = sc->op;
  4252. sc->stack_end -= 4;
  4253. if (sc->stack_end < sc->stack_start)
  4254. {
  4255. fprintf(stderr, "%sstack underflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
  4256. if (stop_at_error) abort();
  4257. }
  4258. sc->code = sc->stack_end[0];
  4259. sc->envir = _TLid(sc->stack_end[1]);
  4260. sc->args = sc->stack_end[2];
  4261. sc->op = (opcode_t)(sc->stack_end[3]);
  4262. if (sc->op > OP_MAX_DEFINED)
  4263. {
  4264. fprintf(stderr, "%spop_stack[%d] invalid opcode: " INT_FORMAT "%s\n", BOLD_TEXT, __LINE__, sc->op, UNBOLD_TEXT);
  4265. if (stop_at_error) abort();
  4266. }
  4267. if (unchecked_type(sc->code) == T_FREE)
  4268. {
  4269. fprintf(stderr, "%s%s[%d]: stack code is free, op: %s -> %s%s\n", BOLD_TEXT, __func__, __LINE__, op_names[cur_op], op_names[sc->op], UNBOLD_TEXT);
  4270. if (stop_at_error) abort();
  4271. }
  4272. if (unchecked_type(sc->args) == T_FREE)
  4273. {
  4274. fprintf(stderr, "%s%s[%d]: stack args is free, op: %s -> %s%s\n", BOLD_TEXT, __func__, __LINE__, op_names[cur_op], op_names[sc->op], UNBOLD_TEXT);
  4275. if (stop_at_error) abort();
  4276. }
  4277. }
  4278. static void pop_stack_no_op(s7_scheme *sc)
  4279. {
  4280. opcode_t cur_op;
  4281. cur_op = sc->op;
  4282. sc->stack_end -= 4;
  4283. if (sc->stack_end < sc->stack_start)
  4284. {
  4285. fprintf(stderr, "%sstack underflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
  4286. if (stop_at_error) abort();
  4287. }
  4288. sc->code = sc->stack_end[0];
  4289. sc->envir = _TLid(sc->stack_end[1]);
  4290. sc->args = sc->stack_end[2];
  4291. if (unchecked_type(sc->code) == T_FREE)
  4292. {
  4293. fprintf(stderr, "%s%s[%d]: stack code is free, op: %s -> %s%s\n", BOLD_TEXT, __func__, __LINE__, op_names[cur_op], op_names[sc->op], UNBOLD_TEXT);
  4294. if (stop_at_error) abort();
  4295. }
  4296. if (unchecked_type(sc->args) == T_FREE)
  4297. {
  4298. fprintf(stderr, "%s%s[%d]: stack args is free, op: %s -> %s%s\n", BOLD_TEXT, __func__, __LINE__, op_names[cur_op], op_names[sc->op], UNBOLD_TEXT);
  4299. if (stop_at_error) abort();
  4300. }
  4301. }
  4302. static void push_stack(s7_scheme *sc, opcode_t op, s7_pointer args, s7_pointer code)
  4303. {
  4304. if (sc->stack_end >= sc->stack_start + sc->stack_size)
  4305. {
  4306. fprintf(stderr, "%sstack overflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
  4307. if (stop_at_error) abort();
  4308. }
  4309. if (op > OP_MAX_DEFINED)
  4310. {
  4311. fprintf(stderr, "%spush_stack[%d] invalid opcode: " INT_FORMAT "%s\n", BOLD_TEXT, __LINE__, sc->op, UNBOLD_TEXT);
  4312. if (stop_at_error) abort();
  4313. }
  4314. if (code) sc->stack_end[0] = _NFre(code);
  4315. sc->stack_end[1] = _TLid(sc->envir);
  4316. if (args) sc->stack_end[2] = _NFre(args);
  4317. sc->stack_end[3] = (s7_pointer)op;
  4318. sc->stack_end += 4;
  4319. }
  4320. #define push_stack_no_code(Sc, Op, Args) push_stack(Sc, Op, Args, Sc->gc_nil)
  4321. #define push_stack_no_args(Sc, Op, Code) push_stack(Sc, Op, Sc->gc_nil, Code)
  4322. /* in the non-debugging case, the sc->F's here are not set, so we can (later) pop free cells */
  4323. #else
  4324. /* these macros are faster than the equivalent simple function calls. If the s7_scheme struct is set up to reflect the
  4325. * stack order [code envir args op], we can use memcpy here:
  4326. * #define pop_stack(Sc) do {Sc->stack_end -= 4; memcpy((void *)Sc, (void *)(Sc->stack_end), 4 * sizeof(s7_pointer));} while (0)
  4327. * but it is only slightly faster (.2% at best)!
  4328. */
  4329. #define pop_stack(Sc) \
  4330. do { \
  4331. Sc->stack_end -= 4; \
  4332. Sc->code = Sc->stack_end[0]; \
  4333. Sc->envir = Sc->stack_end[1]; \
  4334. Sc->args = Sc->stack_end[2]; \
  4335. Sc->op = (opcode_t)(Sc->stack_end[3]); \
  4336. } while (0)
  4337. #define pop_stack_no_op(Sc) \
  4338. do { \
  4339. Sc->stack_end -= 4; \
  4340. Sc->code = Sc->stack_end[0]; \
  4341. Sc->envir = Sc->stack_end[1]; \
  4342. Sc->args = Sc->stack_end[2]; \
  4343. } while (0)
  4344. #define push_stack(Sc, Op, Args, Code) \
  4345. do { \
  4346. Sc->stack_end[0] = Code; \
  4347. Sc->stack_end[1] = Sc->envir; \
  4348. Sc->stack_end[2] = Args; \
  4349. Sc->stack_end[3] = (s7_pointer)Op; \
  4350. Sc->stack_end += 4; \
  4351. } while (0)
  4352. #define push_stack_no_code(Sc, Op, Args) \
  4353. do { \
  4354. Sc->stack_end[2] = Args; \
  4355. Sc->stack_end[3] = (s7_pointer)Op; \
  4356. Sc->stack_end += 4; \
  4357. } while (0)
  4358. #define push_stack_no_args(Sc, Op, Code) \
  4359. do { \
  4360. Sc->stack_end[0] = Code; \
  4361. Sc->stack_end[1] = Sc->envir; \
  4362. Sc->stack_end[3] = (s7_pointer)Op; \
  4363. Sc->stack_end += 4; \
  4364. } while (0)
  4365. #endif
  4366. /* since we don't GC mark the stack past the stack_top, push_stack_no_args and friends can cause pop_stack to set
  4367. * sc->code and sc->args to currently free objects.
  4368. */
  4369. #define main_stack_op(Sc) ((opcode_t)(Sc->stack_end[-1]))
  4370. /* #define main_stack_args(Sc) (Sc->stack_end[-2]) */
  4371. /* #define main_stack_let(Sc) (Sc->stack_end[-3]) */
  4372. /* #define main_stack_code(Sc) (Sc->stack_end[-4]) */
  4373. /* #define pop_main_stack(Sc) Sc->stack_end -= 4 */
  4374. /* beware of main_stack_code! If a function has a tail-call, the main_stack_code that form sees
  4375. * if main_stack_op==op-begin1 can change from call to call -- the begin actually refers
  4376. * to the caller, which is dependent on where the current function was called, so we can't hard-wire
  4377. * any optimizations based on that sequence.
  4378. */
  4379. static void stack_reset(s7_scheme *sc)
  4380. {
  4381. sc->stack_end = sc->stack_start;
  4382. push_stack(sc, OP_EVAL_DONE, sc->nil, sc->nil);
  4383. push_stack(sc, OP_BARRIER, sc->nil, sc->nil);
  4384. }
  4385. static void resize_stack(s7_scheme *sc)
  4386. {
  4387. unsigned int i, new_size, loc; /* long long ints?? sc->stack_size also is an unsigned int */
  4388. loc = s7_stack_top(sc);
  4389. new_size = sc->stack_size * 2;
  4390. /* how can we trap infinite recursions? Is a warning in order here?
  4391. * I think I'll add 'max-stack-size
  4392. * size currently reaches 8192 in s7test
  4393. */
  4394. if (new_size > sc->max_stack_size)
  4395. s7_error(sc, s7_make_symbol(sc, "stack-too-big"), set_elist_1(sc, make_string_wrapper(sc, "stack has grown past (*s7* 'max-stack-size)")));
  4396. vector_elements(sc->stack) = (s7_pointer *)realloc(vector_elements(sc->stack), new_size * sizeof(s7_pointer));
  4397. if (vector_elements(sc->stack) == NULL)
  4398. s7_error(sc, s7_make_symbol(sc, "stack-too-big"), set_elist_1(sc, make_string_wrapper(sc, "no room to expand stack?")));
  4399. for (i = sc->stack_size; i < new_size; i++)
  4400. vector_element(sc->stack, i) = sc->nil;
  4401. vector_length(sc->stack) = new_size;
  4402. sc->stack_size = new_size;
  4403. sc->stack_start = vector_elements(sc->stack);
  4404. sc->stack_end = (s7_pointer *)(sc->stack_start + loc);
  4405. sc->stack_resize_trigger = (s7_pointer *)(sc->stack_start + sc->stack_size / 2);
  4406. if (show_stack_stats(sc))
  4407. fprintf(stderr, "stack grows to %u\n", new_size);
  4408. }
  4409. #define check_stack_size(Sc) \
  4410. if (Sc->stack_end >= Sc->stack_resize_trigger) \
  4411. { \
  4412. if ((Sc->begin_hook) && (call_begin_hook(Sc))) return(Sc->F); \
  4413. resize_stack(Sc); \
  4414. }
  4415. /* -------------------------------- symbols -------------------------------- */
  4416. static unsigned long long int raw_string_hash(const unsigned char *key, unsigned int len)
  4417. {
  4418. unsigned long long int x;
  4419. unsigned char *cx = (unsigned char *)&x;
  4420. x = 0;
  4421. if (len <= 8)
  4422. memcpy((void *)cx, (void *)key, len);
  4423. else
  4424. {
  4425. unsigned long long int y;
  4426. unsigned char *cy = (unsigned char *)&y;
  4427. memcpy((void *)cx, (void *)key, 8);
  4428. y = 0;
  4429. len -= 8;
  4430. memcpy((void *)cy, (void *)(key + 8), (len > 8) ? 8 : len);
  4431. x |= y;
  4432. }
  4433. return(x);
  4434. }
  4435. static s7_pointer make_symbol_with_length(s7_scheme *sc, const char *name, unsigned int len);
  4436. static s7_pointer new_symbol(s7_scheme *sc, const char *name, unsigned int len, unsigned long long int hash, unsigned int location)
  4437. {
  4438. s7_pointer x, str, p;
  4439. unsigned char *base, *val;
  4440. if (sc->symbol_table_is_locked)
  4441. return(s7_error(sc, sc->error_symbol, set_elist_1(sc, make_string_wrapper(sc, "can't make symbol: symbol table is locked!"))));
  4442. base = (unsigned char *)malloc(sizeof(s7_cell) * 3 + len + 1);
  4443. x = (s7_pointer)base;
  4444. str = (s7_pointer)(base + sizeof(s7_cell));
  4445. p = (s7_pointer)(base + 2 * sizeof(s7_cell));
  4446. val = (unsigned char *)(base + 3 * sizeof(s7_cell));
  4447. memcpy((void *)val, (void *)name, len);
  4448. val[len] = '\0';
  4449. unheap(str);
  4450. typeflag(str) = T_STRING | T_IMMUTABLE; /* avoid debugging confusion involving set_type (also below) */
  4451. string_length(str) = len;
  4452. string_value(str) = (char *)val;
  4453. string_hash(str) = hash;
  4454. string_needs_free(str) = false;
  4455. unheap(x);
  4456. typeflag(x) = T_SYMBOL;
  4457. symbol_set_name_cell(x, str);
  4458. set_global_slot(x, sc->undefined); /* was sc->nil; */
  4459. set_initial_slot(x, sc->undefined);
  4460. symbol_set_local(x, 0LL, sc->nil);
  4461. symbol_set_tag(x, 0);
  4462. if (symbol_name_length(x) > 1) /* not 0, otherwise : is a keyword */
  4463. {
  4464. if (name[0] == ':')
  4465. {
  4466. typeflag(x) |= (T_IMMUTABLE | T_KEYWORD);
  4467. keyword_set_symbol(x, make_symbol_with_length(sc, (char *)(name + 1), len - 1));
  4468. set_global_slot(x, s7_make_slot(sc, sc->nil, x, x));
  4469. }
  4470. else
  4471. {
  4472. char c;
  4473. c = name[symbol_name_length(x) - 1];
  4474. if (c == ':')
  4475. {
  4476. char *kstr;
  4477. unsigned int klen;
  4478. klen = symbol_name_length(x) - 1;
  4479. /* can't used tmpbuf_* here (or not safely I think) because name is already using tmpbuf */
  4480. kstr = (char *)malloc((klen + 1) * sizeof(char));
  4481. memcpy((void *)kstr, (void *)name, klen);
  4482. kstr[klen] = 0;
  4483. typeflag(x) |= (T_IMMUTABLE | T_KEYWORD);
  4484. keyword_set_symbol(x, make_symbol_with_length(sc, kstr, klen));
  4485. set_global_slot(x, s7_make_slot(sc, sc->nil, x, x));
  4486. free(kstr);
  4487. }
  4488. }
  4489. }
  4490. unheap(p);
  4491. typeflag(p) = T_PAIR | T_IMMUTABLE;
  4492. set_car(p, x);
  4493. set_cdr(p, vector_element(sc->symbol_table, location));
  4494. vector_element(sc->symbol_table, location) = p;
  4495. pair_set_raw_hash(p, hash);
  4496. pair_set_raw_len(p, len);
  4497. pair_set_raw_name(p, string_value(str));
  4498. return(x);
  4499. }
  4500. static s7_pointer make_symbol_with_length(s7_scheme *sc, const char *name, unsigned int len)
  4501. {
  4502. s7_pointer x;
  4503. unsigned long long int hash;
  4504. unsigned int location;
  4505. hash = raw_string_hash((const unsigned char *)name, len);
  4506. location = hash % SYMBOL_TABLE_SIZE;
  4507. if (len <= 8)
  4508. {
  4509. for (x = vector_element(sc->symbol_table, location); is_pair(x); x = cdr(x))
  4510. if ((hash == pair_raw_hash(x)) &&
  4511. (len == pair_raw_len(x)))
  4512. return(car(x));
  4513. }
  4514. else
  4515. {
  4516. for (x = vector_element(sc->symbol_table, location); is_pair(x); x = cdr(x))
  4517. if ((hash == pair_raw_hash(x)) &&
  4518. (len == pair_raw_len(x)) &&
  4519. (strings_are_equal_with_length(name, pair_raw_name(x), len))) /* length here because name might not be null-terminated */
  4520. return(car(x));
  4521. }
  4522. return(new_symbol(sc, name, len, hash, location));
  4523. }
  4524. static s7_pointer make_symbol(s7_scheme *sc, const char *name)
  4525. {
  4526. return(make_symbol_with_length(sc, name, safe_strlen(name)));
  4527. }
  4528. s7_pointer s7_make_symbol(s7_scheme *sc, const char *name)
  4529. {
  4530. if (!name) return(sc->F);
  4531. return(make_symbol_with_length(sc, name, safe_strlen(name)));
  4532. }
  4533. static s7_pointer symbol_table_find_by_name(s7_scheme *sc, const char *name, unsigned long long int hash, unsigned int location)
  4534. {
  4535. s7_pointer x;
  4536. for (x = vector_element(sc->symbol_table, location); is_not_null(x); x = cdr(x))
  4537. if ((hash == pair_raw_hash(x)) &&
  4538. (strings_are_equal(name, pair_raw_name(x))))
  4539. return(car(x));
  4540. return(sc->nil);
  4541. }
  4542. s7_pointer s7_symbol_table_find_name(s7_scheme *sc, const char *name)
  4543. {
  4544. unsigned long long int hash;
  4545. unsigned int location;
  4546. s7_pointer result;
  4547. hash = raw_string_hash((const unsigned char *)name, safe_strlen(name));
  4548. location = hash % SYMBOL_TABLE_SIZE;
  4549. result = symbol_table_find_by_name(sc, name, hash, location);
  4550. if (is_null(result))
  4551. return(NULL);
  4552. return(result);
  4553. }
  4554. #define FILLED true
  4555. #define NOT_FILLED false
  4556. static s7_pointer g_symbol_table(s7_scheme *sc, s7_pointer args)
  4557. {
  4558. #define H_symbol_table "(symbol-table) returns a vector containing the current symbol-table symbols"
  4559. #define Q_symbol_table s7_make_signature(sc, 1, sc->is_vector_symbol)
  4560. s7_pointer lst, x;
  4561. s7_pointer *els;
  4562. int i, j, syms = 0;
  4563. /* this can't be optimized by returning the actual symbol-table (a vector of lists), because
  4564. * gensyms can cause the table's lists and symbols to change at any time. This wreaks havoc
  4565. * on traversals like for-each. So, symbol-table returns a snap-shot of the table contents
  4566. * at the time it is called, and we call gc before making the list. I suppose the next step
  4567. * is to check that we have room, and increase the heap here if necessary!
  4568. *
  4569. * (define (for-each-symbol func num) (for-each (lambda (sym) (if (> num 0) (for-each-symbol func (- num 1)) (func sym))) (symbol-table)))
  4570. * (for-each-symbol (lambda (sym) (gensym) 1))
  4571. */
  4572. for (i = 0; i < vector_length(sc->symbol_table); i++)
  4573. for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
  4574. syms++;
  4575. sc->w = make_vector_1(sc, syms, NOT_FILLED, T_VECTOR);
  4576. els = vector_elements(sc->w);
  4577. for (i = 0, j = 0; i < vector_length(sc->symbol_table); i++)
  4578. for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
  4579. els[j++] = car(x);
  4580. lst = sc->w;
  4581. sc->w = sc->nil;
  4582. return(lst);
  4583. }
  4584. bool s7_for_each_symbol_name(s7_scheme *sc, bool (*symbol_func)(const char *symbol_name, void *data), void *data)
  4585. {
  4586. /* this includes the special constants #<unspecified> and so on for simplicity -- are there any others? */
  4587. int i;
  4588. s7_pointer x;
  4589. for (i = 0; i < vector_length(sc->symbol_table); i++)
  4590. for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
  4591. if (symbol_func(symbol_name(car(x)), data))
  4592. return(true);
  4593. return((symbol_func("#t", data)) ||
  4594. (symbol_func("#f", data)) ||
  4595. (symbol_func("#<unspecified>", data)) ||
  4596. (symbol_func("#<undefined>", data)) ||
  4597. (symbol_func("#<eof>", data)) ||
  4598. (symbol_func("#true", data)) ||
  4599. (symbol_func("#false", data)));
  4600. }
  4601. bool s7_for_each_symbol(s7_scheme *sc, bool (*symbol_func)(const char *symbol_name, s7_pointer value, void *data), void *data)
  4602. {
  4603. int i;
  4604. s7_pointer x;
  4605. for (i = 0; i < vector_length(sc->symbol_table); i++)
  4606. for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
  4607. if (symbol_func(symbol_name(car(x)), cdr(x), data))
  4608. return(true);
  4609. return(false);
  4610. }
  4611. static void remove_gensym_from_symbol_table(s7_scheme *sc, s7_pointer sym)
  4612. {
  4613. /* sym is a free cell at this point (we're called after the GC), but the name_cell is still intact */
  4614. s7_pointer x, name;
  4615. unsigned int location;
  4616. name = symbol_name_cell(sym);
  4617. location = string_hash(name) % SYMBOL_TABLE_SIZE;
  4618. x = vector_element(sc->symbol_table, location);
  4619. if (car(x) == sym)
  4620. {
  4621. vector_element(sc->symbol_table, location) = cdr(x);
  4622. free(x);
  4623. }
  4624. else
  4625. {
  4626. s7_pointer y;
  4627. for (y = x, x = cdr(x); is_pair(x); y = x, x = cdr(x))
  4628. {
  4629. if (car(x) == sym)
  4630. {
  4631. set_cdr(y, cdr(x));
  4632. free(x);
  4633. return;
  4634. }
  4635. }
  4636. #if DEBUGGING
  4637. fprintf(stderr, "could not remove %s?\n", string_value(name));
  4638. #endif
  4639. }
  4640. }
  4641. s7_pointer s7_gensym(s7_scheme *sc, const char *prefix)
  4642. {
  4643. char *name;
  4644. unsigned int len, location;
  4645. unsigned long long int hash;
  4646. s7_pointer x;
  4647. len = safe_strlen(prefix) + 32;
  4648. tmpbuf_malloc(name, len);
  4649. /* there's no point in heroic efforts here to avoid name collisions -- the user can screw up no matter what we do */
  4650. len = snprintf(name, len, "{%s}-%u", prefix, sc->gensym_counter++);
  4651. hash = raw_string_hash((const unsigned char *)name, len);
  4652. location = hash % SYMBOL_TABLE_SIZE;
  4653. x = new_symbol(sc, name, len, hash, location); /* not T_GENSYM -- might be called from outside */
  4654. tmpbuf_free(name, len);
  4655. return(x);
  4656. }
  4657. static bool s7_is_gensym(s7_pointer g) {return((is_symbol(g)) && (is_gensym(g)));}
  4658. static s7_pointer g_is_gensym(s7_scheme *sc, s7_pointer args)
  4659. {
  4660. #define H_is_gensym "(gensym? sym) returns #t if sym is a gensym"
  4661. #define Q_is_gensym pl_bt
  4662. check_boolean_method(sc, s7_is_gensym, sc->is_gensym_symbol, args);
  4663. }
  4664. static char *pos_int_to_str(s7_int num, unsigned int *len, char endc)
  4665. {
  4666. #define INT_TO_STR_SIZE 32
  4667. static char itos[INT_TO_STR_SIZE];
  4668. char *p, *op;
  4669. p = (char *)(itos + INT_TO_STR_SIZE - 1);
  4670. op = p;
  4671. *p-- = '\0';
  4672. if (endc != '\0') *p-- = endc;
  4673. do {*p-- = "0123456789"[num % 10]; num /= 10;} while (num);
  4674. (*len) = op - p; /* this includes the trailing #\null */
  4675. return((char *)(p + 1));
  4676. }
  4677. static s7_pointer g_gensym(s7_scheme *sc, s7_pointer args)
  4678. {
  4679. #define H_gensym "(gensym (prefix \"gensym\")) returns a new, unused symbol"
  4680. #define Q_gensym s7_make_signature(sc, 2, sc->is_gensym_symbol, sc->is_string_symbol)
  4681. const char *prefix;
  4682. char *name, *p;
  4683. unsigned int len, plen, nlen, location;
  4684. unsigned long long int hash;
  4685. s7_pointer x, str, stc;
  4686. /* get symbol name */
  4687. if (is_not_null(args))
  4688. {
  4689. s7_pointer name;
  4690. name = car(args);
  4691. if (!is_string(name))
  4692. method_or_bust(sc, name, sc->gensym_symbol, args, T_STRING, 0);
  4693. prefix = string_value(name);
  4694. }
  4695. else prefix = "gensym";
  4696. plen = safe_strlen(prefix);
  4697. len = plen + 32;
  4698. name = (char *)malloc(len * sizeof(char));
  4699. name[0] = '{';
  4700. if (plen > 0) memcpy((void *)(name + 1), prefix, plen);
  4701. name[plen + 1] = '}';
  4702. name[plen + 2] = '-';
  4703. p = pos_int_to_str(sc->gensym_counter++, &len, '\0');
  4704. memcpy((void *)(name + plen + 3), (void *)p, len);
  4705. nlen = len + plen + 2;
  4706. hash = raw_string_hash((const unsigned char *)name, nlen);
  4707. location = hash % SYMBOL_TABLE_SIZE;
  4708. /* make-string for symbol name */
  4709. str = (s7_cell *)malloc(sizeof(s7_cell)); /* was calloc? */
  4710. unheap(str);
  4711. #if DEBUGGING
  4712. typeflag(str) = 0;
  4713. #endif
  4714. set_type(str, T_STRING | T_IMMUTABLE);
  4715. string_length(str) = nlen;
  4716. string_value(str) = name;
  4717. string_needs_free(str) = false;
  4718. string_hash(str) = hash;
  4719. /* allocate the symbol in the heap so GC'd when inaccessible */
  4720. new_cell(sc, x, T_SYMBOL | T_GENSYM);
  4721. symbol_set_name_cell(x, str);
  4722. set_global_slot(x, sc->undefined);
  4723. set_initial_slot(x, sc->undefined);
  4724. symbol_set_local(x, 0LL, sc->nil);
  4725. /* place new symbol in symbol-table, but using calloc so we can easily free it (remove it from the table) in GC sweep */
  4726. stc = (s7_cell *)malloc(sizeof(s7_cell)); /* was calloc? */
  4727. #if DEBUGGING
  4728. typeflag(stc) = 0;
  4729. #endif
  4730. unheap(stc);
  4731. set_type(stc, T_PAIR | T_IMMUTABLE);
  4732. set_car(stc, x);
  4733. set_cdr(stc, vector_element(sc->symbol_table, location));
  4734. vector_element(sc->symbol_table, location) = stc;
  4735. pair_set_raw_hash(stc, hash);
  4736. pair_set_raw_len(stc, string_length(str));
  4737. pair_set_raw_name(stc, string_value(str));
  4738. add_gensym(sc, x);
  4739. return(x);
  4740. }
  4741. s7_pointer s7_name_to_value(s7_scheme *sc, const char *name)
  4742. {
  4743. return(s7_symbol_value(sc, make_symbol(sc, name)));
  4744. }
  4745. bool s7_is_symbol(s7_pointer p)
  4746. {
  4747. return(is_symbol(p));
  4748. }
  4749. bool s7_is_syntax(s7_pointer p)
  4750. {
  4751. return(is_syntax(p));
  4752. }
  4753. static s7_pointer g_is_symbol(s7_scheme *sc, s7_pointer args)
  4754. {
  4755. #define H_is_symbol "(symbol? obj) returns #t if obj is a symbol"
  4756. #define Q_is_symbol pl_bt
  4757. check_boolean_method(sc, is_symbol, sc->is_symbol_symbol, args);
  4758. }
  4759. const char *s7_symbol_name(s7_pointer p)
  4760. {
  4761. return(symbol_name(p));
  4762. }
  4763. static s7_pointer g_symbol_to_string(s7_scheme *sc, s7_pointer args)
  4764. {
  4765. #define H_symbol_to_string "(symbol->string sym) returns the symbol sym converted to a string"
  4766. #define Q_symbol_to_string s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_symbol_symbol)
  4767. s7_pointer sym;
  4768. sym = car(args);
  4769. if (!is_symbol(sym))
  4770. method_or_bust(sc, sym, sc->symbol_to_string_symbol, args, T_SYMBOL, 0);
  4771. /* s7_make_string uses strlen which stops at an embedded null */
  4772. return(s7_make_string_with_length(sc, symbol_name(sym), symbol_name_length(sym))); /* return a copy */
  4773. }
  4774. static s7_pointer symbol_to_string_uncopied;
  4775. static s7_pointer g_symbol_to_string_uncopied(s7_scheme *sc, s7_pointer args)
  4776. {
  4777. s7_pointer sym;
  4778. sym = car(args);
  4779. if (!is_symbol(sym))
  4780. method_or_bust(sc, sym, sc->symbol_to_string_symbol, args, T_SYMBOL, 0);
  4781. return(symbol_name_cell(sym));
  4782. }
  4783. static s7_pointer g_string_to_symbol_1(s7_scheme *sc, s7_pointer str, s7_pointer caller)
  4784. {
  4785. if (!is_string(str))
  4786. method_or_bust(sc, str, caller, list_1(sc, str), T_STRING, 0);
  4787. if (string_length(str) == 0)
  4788. return(simple_wrong_type_argument_with_type(sc, caller, str, make_string_wrapper(sc, "a non-null string")));
  4789. /* currently if the string has an embedded null, it marks the end of the new symbol name. */
  4790. return(make_symbol_with_length(sc, string_value(str), string_length(str)));
  4791. }
  4792. static s7_pointer g_string_to_symbol(s7_scheme *sc, s7_pointer args)
  4793. {
  4794. #define H_string_to_symbol "(string->symbol str) returns the string str converted to a symbol"
  4795. #define Q_string_to_symbol s7_make_signature(sc, 2, sc->is_symbol_symbol, sc->is_string_symbol)
  4796. return(g_string_to_symbol_1(sc, car(args), sc->string_to_symbol_symbol));
  4797. }
  4798. static s7_pointer g_string_append(s7_scheme *sc, s7_pointer args);
  4799. static s7_pointer g_symbol(s7_scheme *sc, s7_pointer args)
  4800. {
  4801. #define H_symbol "(symbol str ...) returns its string arguments concatenated and converted to a symbol"
  4802. #define Q_symbol s7_make_circular_signature(sc, 1, 2, sc->is_symbol_symbol, sc->is_string_symbol)
  4803. if (is_null(cdr(args)))
  4804. return(g_string_to_symbol_1(sc, car(args), sc->symbol_symbol));
  4805. return(g_string_to_symbol_1(sc, g_string_append(sc, args), sc->symbol_symbol));
  4806. }
  4807. static s7_pointer add_sym_to_list(s7_scheme *sc, s7_pointer sym)
  4808. {
  4809. symbol_set_tag(sym, sc->syms_tag);
  4810. return(sym);
  4811. }
  4812. #define clear_syms_in_list(Sc) Sc->syms_tag++
  4813. /* -------------------------------- environments -------------------------------- */
  4814. #define new_frame(Sc, Old_Env, New_Env) \
  4815. do { \
  4816. s7_pointer _x_; \
  4817. new_cell(Sc, _x_, T_LET); \
  4818. let_id(_x_) = ++sc->let_number; \
  4819. let_set_slots(_x_, Sc->nil); \
  4820. set_outlet(_x_, Old_Env); \
  4821. New_Env = _x_; \
  4822. } while (0)
  4823. static s7_pointer new_frame_in_env(s7_scheme *sc, s7_pointer old_env)
  4824. {
  4825. /* return(cons(sc, sc->nil, old_env)); */
  4826. s7_pointer x;
  4827. new_cell(sc, x, T_LET);
  4828. let_id(x) = ++sc->let_number;
  4829. let_set_slots(x, sc->nil);
  4830. set_outlet(x, old_env);
  4831. return(x);
  4832. }
  4833. static s7_pointer make_simple_let(s7_scheme *sc)
  4834. {
  4835. s7_pointer frame;
  4836. new_cell(sc, frame, T_LET);
  4837. let_id(frame) = sc->let_number + 1;
  4838. let_set_slots(frame, sc->nil);
  4839. set_outlet(frame, sc->envir);
  4840. return(frame);
  4841. }
  4842. /* in all these macros, symbol_set_local should follow slot_set_value so that we can evaluate the
  4843. * slot's value in its old state.
  4844. */
  4845. #define add_slot(Frame, Symbol, Value) \
  4846. do { \
  4847. s7_pointer _slot_, _sym_, _val_; \
  4848. _sym_ = Symbol; _val_ = Value; \
  4849. new_cell_no_check(sc, _slot_, T_SLOT);\
  4850. slot_set_symbol(_slot_, _sym_); \
  4851. slot_set_value(_slot_, _val_); \
  4852. symbol_set_local(_sym_, let_id(Frame), _slot_); \
  4853. set_next_slot(_slot_, let_slots(Frame)); \
  4854. let_set_slots(Frame, _slot_); \
  4855. } while (0)
  4856. #define add_slot_checked(Frame, Symbol, Value) \
  4857. do { \
  4858. s7_pointer _slot_, _sym_, _val_; \
  4859. _sym_ = Symbol; _val_ = Value; \
  4860. new_cell(sc, _slot_, T_SLOT); \
  4861. slot_set_symbol(_slot_, _sym_); \
  4862. slot_set_value(_slot_, _val_); \
  4863. symbol_set_local(_sym_, let_id(Frame), _slot_); \
  4864. set_next_slot(_slot_, let_slots(Frame)); \
  4865. let_set_slots(Frame, _slot_); \
  4866. } while (0)
  4867. /* no set_local here -- presumably done earlier in check_* */
  4868. #define new_frame_with_slot(Sc, Old_Env, New_Env, Symbol, Value) \
  4869. do { \
  4870. s7_pointer _x_, _slot_, _sym_, _val_; \
  4871. _sym_ = Symbol; _val_ = Value; \
  4872. new_cell(Sc, _x_, T_LET); \
  4873. let_id(_x_) = ++sc->let_number; \
  4874. set_outlet(_x_, Old_Env); \
  4875. New_Env = _x_; \
  4876. new_cell_no_check(Sc, _slot_, T_SLOT); \
  4877. slot_set_symbol(_slot_, _sym_); \
  4878. slot_set_value(_slot_, _val_); \
  4879. symbol_set_local(_sym_, sc->let_number, _slot_); \
  4880. set_next_slot(_slot_, sc->nil); \
  4881. let_set_slots(_x_, _slot_); \
  4882. } while (0)
  4883. #define new_frame_with_two_slots(Sc, Old_Env, New_Env, Symbol1, Value1, Symbol2, Value2) \
  4884. do { \
  4885. s7_pointer _x_, _slot_, _sym1_, _val1_, _sym2_, _val2_; \
  4886. _sym1_ = Symbol1; _val1_ = Value1; \
  4887. _sym2_ = Symbol2; _val2_ = Value2; \
  4888. new_cell(Sc, _x_, T_LET); \
  4889. let_id(_x_) = ++sc->let_number; \
  4890. set_outlet(_x_, Old_Env); \
  4891. New_Env = _x_; \
  4892. new_cell_no_check(Sc, _slot_, T_SLOT); \
  4893. slot_set_symbol(_slot_, _sym1_); \
  4894. slot_set_value(_slot_, _val1_); \
  4895. symbol_set_local(_sym1_, sc->let_number, _slot_); \
  4896. let_set_slots(_x_, _slot_); \
  4897. new_cell_no_check(Sc, _x_, T_SLOT); \
  4898. slot_set_symbol(_x_, _sym2_); \
  4899. slot_set_value(_x_, _val2_); \
  4900. symbol_set_local(_sym2_, sc->let_number, _x_); \
  4901. set_next_slot(_x_, sc->nil); \
  4902. set_next_slot(_slot_, _x_); \
  4903. } while (0)
  4904. static s7_pointer old_frame_in_env(s7_scheme *sc, s7_pointer frame, s7_pointer next_frame)
  4905. {
  4906. set_type(frame, T_LET);
  4907. let_set_slots(frame, sc->nil);
  4908. set_outlet(frame, next_frame);
  4909. let_id(frame) = ++sc->let_number;
  4910. return(frame);
  4911. }
  4912. static s7_pointer old_frame_with_slot(s7_scheme *sc, s7_pointer env, s7_pointer val)
  4913. {
  4914. s7_pointer x, sym;
  4915. unsigned long long int id;
  4916. id = ++sc->let_number;
  4917. let_id(env) = id;
  4918. x = let_slots(env);
  4919. slot_set_value(x, val);
  4920. sym = slot_symbol(x);
  4921. symbol_set_local(sym, id, x);
  4922. return(env);
  4923. }
  4924. static s7_pointer old_frame_with_two_slots(s7_scheme *sc, s7_pointer env, s7_pointer val1, s7_pointer val2)
  4925. {
  4926. s7_pointer x, sym;
  4927. unsigned long long int id;
  4928. id = ++sc->let_number;
  4929. let_id(env) = id;
  4930. x = let_slots(env);
  4931. slot_set_value(x, val1);
  4932. sym = slot_symbol(x);
  4933. symbol_set_local(sym, id, x);
  4934. x = next_slot(x);
  4935. slot_set_value(x, val2);
  4936. sym = slot_symbol(x);
  4937. symbol_set_local(sym, id, x);
  4938. return(env);
  4939. }
  4940. static s7_pointer old_frame_with_three_slots(s7_scheme *sc, s7_pointer env, s7_pointer val1, s7_pointer val2, s7_pointer val3)
  4941. {
  4942. s7_pointer x, sym;
  4943. unsigned long long int id;
  4944. id = ++sc->let_number;
  4945. let_id(env) = id;
  4946. x = let_slots(env);
  4947. slot_set_value(x, val1);
  4948. sym = slot_symbol(x);
  4949. symbol_set_local(sym, id, x);
  4950. x = next_slot(x);
  4951. slot_set_value(x, val2);
  4952. sym = slot_symbol(x);
  4953. symbol_set_local(sym, id, x);
  4954. x = next_slot(x);
  4955. slot_set_value(x, val3);
  4956. sym = slot_symbol(x);
  4957. symbol_set_local(sym, id, x);
  4958. return(env);
  4959. }
  4960. static s7_pointer permanent_slot(s7_pointer symbol, s7_pointer value)
  4961. {
  4962. s7_pointer x;
  4963. x = alloc_pointer();
  4964. unheap(x);
  4965. set_type(x, T_SLOT);
  4966. slot_set_symbol(x, symbol);
  4967. slot_set_value(x, value);
  4968. return(x);
  4969. }
  4970. static s7_pointer find_let(s7_scheme *sc, s7_pointer obj)
  4971. {
  4972. if (is_let(obj)) return(obj);
  4973. switch (type(obj))
  4974. {
  4975. case T_LET:
  4976. return(obj);
  4977. case T_MACRO: case T_MACRO_STAR:
  4978. case T_BACRO: case T_BACRO_STAR:
  4979. case T_CLOSURE: case T_CLOSURE_STAR:
  4980. return(closure_let(obj));
  4981. case T_C_OBJECT:
  4982. return(c_object_let(obj));
  4983. }
  4984. return(sc->nil);
  4985. }
  4986. static s7_pointer free_let(s7_scheme *sc, s7_pointer e)
  4987. {
  4988. s7_pointer p;
  4989. #if DEBUGGING
  4990. for (p = let_slots(e); is_slot(p);)
  4991. {
  4992. s7_pointer n;
  4993. n = next_slot(p); /* grab it before we free p, or the type check stuff will complain */
  4994. free_cell(sc, p);
  4995. p = n;
  4996. }
  4997. #else
  4998. for (p = let_slots(e); is_slot(p); p = next_slot(p))
  4999. free_cell(sc, p);
  5000. #endif
  5001. free_cell(sc, e);
  5002. return(sc->nil);
  5003. }
  5004. static s7_pointer find_method(s7_scheme *sc, s7_pointer env, s7_pointer symbol)
  5005. {
  5006. s7_pointer x;
  5007. if (symbol_id(symbol) == 0) /* this means the symbol has never been used locally, so how can it be a method? */
  5008. return(sc->undefined);
  5009. /* I think the symbol_id is in sync with let_id, so the standard search should work */
  5010. if (let_id(env) == symbol_id(symbol))
  5011. return(slot_value(local_slot(symbol)));
  5012. for (x = env; symbol_id(symbol) < let_id(x); x = outlet(x));
  5013. if (let_id(x) == symbol_id(symbol))
  5014. return(slot_value(local_slot(symbol)));
  5015. for (; is_let(x); x = outlet(x))
  5016. {
  5017. s7_pointer y;
  5018. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  5019. if (slot_symbol(y) == symbol)
  5020. return(slot_value(y));
  5021. }
  5022. return(sc->undefined);
  5023. }
  5024. static int let_length(s7_scheme *sc, s7_pointer e)
  5025. {
  5026. /* used by length, applicable_length, and some length optimizations */
  5027. int i;
  5028. s7_pointer p;
  5029. if (e == sc->rootlet)
  5030. return(sc->rootlet_entries);
  5031. if (has_methods(e))
  5032. {
  5033. s7_pointer length_func;
  5034. length_func = find_method(sc, e, sc->length_symbol);
  5035. if (length_func != sc->undefined)
  5036. {
  5037. p = s7_apply_function(sc, length_func, list_1(sc, e));
  5038. if (s7_is_integer(p))
  5039. return((int)s7_integer(p));
  5040. return(-1); /* ?? */
  5041. }
  5042. }
  5043. for (i = 0, p = let_slots(e); is_slot(p); i++, p = next_slot(p));
  5044. return(i);
  5045. }
  5046. static s7_pointer make_slot_1(s7_scheme *sc, s7_pointer env, s7_pointer symbol, s7_pointer value)
  5047. {
  5048. /* env is not rootlet and is a let */
  5049. s7_pointer slot;
  5050. new_cell(sc, slot, T_SLOT);
  5051. slot_set_symbol(slot, symbol);
  5052. slot_set_value(slot, value);
  5053. set_next_slot(slot, let_slots(env));
  5054. let_set_slots(env, slot);
  5055. set_local(symbol);
  5056. /* this is called by varlet so we have to be careful about the resultant let_id
  5057. * check for greater to ensure shadowing stays in effect, and equal to do updates (set! in effect)
  5058. */
  5059. if (let_id(env) >= symbol_id(symbol))
  5060. symbol_set_local(symbol, let_id(env), slot);
  5061. return(slot);
  5062. }
  5063. s7_pointer s7_make_slot(s7_scheme *sc, s7_pointer env, s7_pointer symbol, s7_pointer value)
  5064. {
  5065. if ((!is_let(env)) ||
  5066. (env == sc->rootlet))
  5067. {
  5068. s7_pointer ge, slot;
  5069. if ((sc->safety == 0) && (has_closure_let(value)))
  5070. {
  5071. s7_remove_from_heap(sc, closure_args(value));
  5072. s7_remove_from_heap(sc, closure_body(value));
  5073. }
  5074. /* first look for existing slot -- this is not always checked before calling s7_make_slot */
  5075. if (is_slot(global_slot(symbol)))
  5076. {
  5077. slot = global_slot(symbol);
  5078. slot_set_value(slot, value);
  5079. return(slot);
  5080. }
  5081. ge = sc->rootlet;
  5082. slot = permanent_slot(symbol, value);
  5083. vector_element(ge, sc->rootlet_entries++) = slot;
  5084. if (sc->rootlet_entries >= vector_length(ge))
  5085. {
  5086. int i;
  5087. vector_length(ge) *= 2;
  5088. vector_elements(ge) = (s7_pointer *)realloc(vector_elements(ge), vector_length(ge) * sizeof(s7_pointer));
  5089. for (i = sc->rootlet_entries; i < vector_length(ge); i++)
  5090. vector_element(ge, i) = sc->nil;
  5091. }
  5092. set_global_slot(symbol, slot);
  5093. if (symbol_id(symbol) == 0) /* never defined locally? */
  5094. {
  5095. if (initial_slot(symbol) == sc->undefined)
  5096. set_initial_slot(symbol, permanent_slot(symbol, value));
  5097. set_local_slot(symbol, slot);
  5098. set_global(symbol);
  5099. }
  5100. if (is_gensym(symbol))
  5101. s7_remove_from_heap(sc, symbol);
  5102. return(slot);
  5103. }
  5104. return(make_slot_1(sc, env, symbol, value));
  5105. /* there are about the same number of frames as local variables -- this
  5106. * strikes me as surprising, but it holds up across a lot of code.
  5107. */
  5108. }
  5109. static s7_pointer make_slot(s7_scheme *sc, s7_pointer variable, s7_pointer value)
  5110. {
  5111. /* this is for a do-loop optimization -- an unattached slot */
  5112. s7_pointer y;
  5113. new_cell(sc, y, T_SLOT);
  5114. slot_set_symbol(y, variable);
  5115. if (!is_symbol(variable)) abort();
  5116. slot_set_value(y, value);
  5117. return(y);
  5118. }
  5119. /* -------------------------------- let? -------------------------------- */
  5120. bool s7_is_let(s7_pointer e)
  5121. {
  5122. return(is_let(e));
  5123. }
  5124. static s7_pointer g_is_let(s7_scheme *sc, s7_pointer args)
  5125. {
  5126. #define H_is_let "(let? obj) returns #t if obj is a let (an environment)."
  5127. #define Q_is_let pl_bt
  5128. check_boolean_method(sc, is_let, sc->is_let_symbol, args);
  5129. }
  5130. /* -------------------------------- unlet -------------------------------- */
  5131. #define UNLET_ENTRIES 410 /* 401 if not --disable-deprecated etc */
  5132. static void save_unlet(s7_scheme *sc)
  5133. {
  5134. int i, k = 0;
  5135. s7_pointer x;
  5136. s7_pointer *inits;
  5137. sc->unlet = (s7_pointer)calloc(1, sizeof(s7_cell));
  5138. set_type(sc->unlet, T_VECTOR);
  5139. vector_length(sc->unlet) = UNLET_ENTRIES;
  5140. vector_elements(sc->unlet) = (s7_pointer *)malloc(UNLET_ENTRIES * sizeof(s7_pointer));
  5141. vector_getter(sc->unlet) = default_vector_getter;
  5142. vector_setter(sc->unlet) = default_vector_setter;
  5143. inits = vector_elements(sc->unlet);
  5144. s7_vector_fill(sc, sc->unlet, sc->nil);
  5145. unheap(sc->unlet);
  5146. for (i = 0; i < vector_length(sc->symbol_table); i++)
  5147. for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
  5148. {
  5149. s7_pointer sym;
  5150. sym = car(x);
  5151. if (is_slot(initial_slot(sym)))
  5152. {
  5153. s7_pointer val;
  5154. val = slot_value(initial_slot(sym));
  5155. if ((is_procedure(val)) || (is_syntax(val)))
  5156. inits[k++] = initial_slot(sym);
  5157. /* (let ((begin +)) (with-let (unlet) (begin 1 2))) */
  5158. #if DEBUGGING
  5159. if (k >= UNLET_ENTRIES)
  5160. fprintf(stderr, "unlet overflow\n");
  5161. #endif
  5162. }
  5163. }
  5164. }
  5165. static s7_pointer g_unlet(s7_scheme *sc, s7_pointer args)
  5166. {
  5167. /* add sc->unlet bindings to the current environment */
  5168. #define H_unlet "(unlet) establishes the original bindings of all the predefined functions"
  5169. #define Q_unlet s7_make_signature(sc, 1, sc->is_let_symbol)
  5170. /* slightly confusing:
  5171. * :((unlet) 'abs)
  5172. * #<undefined>
  5173. * :(defined? 'abs (unlet))
  5174. * #t
  5175. * this is because unlet sets up a local environment of unshadowed symbols,
  5176. * and s7_let_ref below only looks at the local env chain (that is, if env is not
  5177. * the global env, then the global env is not searched).
  5178. *
  5179. * Also (define hi 3) #_hi => 3, (set! hi 4), #_hi -> 3 but (with-let (unlet) hi) -> 4!
  5180. */
  5181. int i;
  5182. s7_pointer *inits;
  5183. s7_pointer x;
  5184. sc->w = new_frame_in_env(sc, sc->envir);
  5185. inits = vector_elements(sc->unlet);
  5186. for (i = 0; (i < UNLET_ENTRIES) && (is_slot(inits[i])); i++)
  5187. {
  5188. s7_pointer sym;
  5189. x = slot_value(inits[i]);
  5190. sym = slot_symbol(inits[i]);
  5191. if (is_procedure(x))
  5192. {
  5193. if (((!is_global(sym)) && /* it might be shadowed locally */
  5194. (s7_symbol_local_value(sc, sym, sc->envir) != slot_value(global_slot(sym)))) ||
  5195. (x != slot_value(global_slot(sym)))) /* it's not shadowed, but has been changed globally */
  5196. make_slot_1(sc, sc->w, sym, x);
  5197. }
  5198. else
  5199. {
  5200. if ((is_syntax(x)) &&
  5201. (local_slot(sym) != sc->nil)) /* this can be a freed cell, will be nil if unchanged */
  5202. make_slot_1(sc, sc->w, sym, x);
  5203. }
  5204. }
  5205. /* if (set! + -) then + needs to be overridden, but the local bit isn't set,
  5206. * so we have to check the actual values in the non-local case.
  5207. * (define (f x) (with-let (unlet) (+ x 1)))
  5208. */
  5209. x = sc->w;
  5210. sc->w = sc->nil;
  5211. return(x);
  5212. }
  5213. /* -------------------------------- openlet? -------------------------------- */
  5214. bool s7_is_openlet(s7_pointer e)
  5215. {
  5216. return(has_methods(e));
  5217. }
  5218. static s7_pointer g_is_openlet(s7_scheme *sc, s7_pointer args)
  5219. {
  5220. #define H_is_openlet "(openlet? obj) returns #t is 'obj' has methods."
  5221. #define Q_is_openlet pl_bt
  5222. /* if car(args) is not a let (or possibly have one), should this raise an error? */
  5223. check_method(sc, car(args), sc->is_openlet_symbol, args);
  5224. return(make_boolean(sc, has_methods(car(args))));
  5225. }
  5226. /* -------------------------------- openlet -------------------------------- */
  5227. s7_pointer s7_openlet(s7_scheme *sc, s7_pointer e)
  5228. {
  5229. set_has_methods(e);
  5230. return(e);
  5231. }
  5232. static s7_pointer g_openlet(s7_scheme *sc, s7_pointer args)
  5233. {
  5234. #define H_openlet "(openlet e) tells the built-in generic functions that the environment 'e might have an over-riding method."
  5235. #define Q_openlet pcl_t
  5236. s7_pointer e;
  5237. e = car(args);
  5238. check_method(sc, e, sc->openlet_symbol, args);
  5239. if (((is_let(e)) && (e != sc->rootlet)) ||
  5240. (has_closure_let(e)) ||
  5241. ((is_c_object(e)) && (c_object_let(e) != sc->nil)))
  5242. {
  5243. set_has_methods(e);
  5244. return(e);
  5245. }
  5246. return(simple_wrong_type_argument_with_type(sc, sc->openlet_symbol, e, a_let_string));
  5247. }
  5248. /* -------------------------------- coverlet -------------------------------- */
  5249. static s7_pointer c_coverlet(s7_scheme *sc, s7_pointer e)
  5250. {
  5251. sc->temp3 = e;
  5252. check_method(sc, e, sc->coverlet_symbol, list_1(sc, e));
  5253. if (((is_let(e)) && (e != sc->rootlet)) ||
  5254. (has_closure_let(e)) ||
  5255. ((is_c_object(e)) && (c_object_let(e) != sc->nil)))
  5256. {
  5257. clear_has_methods(e);
  5258. return(e);
  5259. }
  5260. return(simple_wrong_type_argument_with_type(sc, sc->coverlet_symbol, e, a_let_string));
  5261. }
  5262. static s7_pointer g_coverlet(s7_scheme *sc, s7_pointer args)
  5263. {
  5264. #define H_coverlet "(coverlet e) undoes an earlier openlet."
  5265. #define Q_coverlet pcl_t
  5266. return(c_coverlet(sc, car(args)));
  5267. }
  5268. /* -------------------------------- varlet -------------------------------- */
  5269. static void append_let(s7_scheme *sc, s7_pointer new_e, s7_pointer old_e)
  5270. {
  5271. s7_pointer x;
  5272. if (old_e == sc->rootlet)
  5273. return;
  5274. if (new_e != sc->rootlet)
  5275. {
  5276. for (x = let_slots(old_e); is_slot(x); x = next_slot(x))
  5277. 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 */
  5278. }
  5279. else
  5280. {
  5281. for (x = let_slots(old_e); is_slot(x); x = next_slot(x))
  5282. {
  5283. s7_pointer sym, val;
  5284. sym = slot_symbol(x);
  5285. val = slot_value(x);
  5286. if (is_slot(global_slot(sym)))
  5287. slot_set_value(global_slot(sym), val);
  5288. else s7_make_slot(sc, new_e, sym, val);
  5289. }
  5290. }
  5291. }
  5292. static s7_pointer check_c_obj_env(s7_scheme *sc, s7_pointer old_e, s7_pointer caller)
  5293. {
  5294. if (is_c_object(old_e))
  5295. old_e = c_object_let(old_e);
  5296. if (!is_let(old_e))
  5297. return(simple_wrong_type_argument_with_type(sc, caller, old_e, a_let_string));
  5298. return(old_e);
  5299. }
  5300. s7_pointer s7_varlet(s7_scheme *sc, s7_pointer env, s7_pointer symbol, s7_pointer value)
  5301. {
  5302. if (!is_let(env))
  5303. return(wrong_type_argument_with_type(sc, sc->varlet_symbol, 1, env, a_let_string));
  5304. if (!is_symbol(symbol))
  5305. return(wrong_type_argument_with_type(sc, sc->varlet_symbol, 2, symbol, a_symbol_string));
  5306. if (env == sc->rootlet)
  5307. {
  5308. if (is_slot(global_slot(symbol)))
  5309. {
  5310. if (is_syntax(slot_value(global_slot(symbol))))
  5311. return(wrong_type_argument_with_type(sc, sc->varlet_symbol, 2, symbol, make_string_wrapper(sc, "a non-syntactic keyword")));
  5312. slot_set_value(global_slot(symbol), value);
  5313. }
  5314. else s7_make_slot(sc, env, symbol, value);
  5315. }
  5316. else make_slot_1(sc, env, symbol, value);
  5317. return(value);
  5318. }
  5319. static s7_pointer g_varlet(s7_scheme *sc, s7_pointer args)
  5320. {
  5321. #define H_varlet "(varlet env ...) adds its arguments (an environment, a cons: symbol . value, or a pair of arguments, the symbol and its value) \
  5322. to the environment env, and returns the environment."
  5323. #define Q_varlet s7_make_circular_signature(sc, 2, 3, sc->is_let_symbol, sc->is_let_symbol, sc->T)
  5324. /* varlet = with-let + define */
  5325. s7_pointer x, e, sym, val, p;
  5326. e = car(args);
  5327. if (is_null(e))
  5328. e = sc->rootlet;
  5329. else
  5330. {
  5331. check_method(sc, e, sc->varlet_symbol, args);
  5332. if (!is_let(e))
  5333. return(wrong_type_argument_with_type(sc, sc->varlet_symbol, 1, e, a_let_string));
  5334. }
  5335. for (x = cdr(args); is_pair(x); x = cdr(x))
  5336. {
  5337. p = car(x);
  5338. switch (type(p))
  5339. {
  5340. case T_SYMBOL:
  5341. if (is_keyword(p))
  5342. sym = keyword_symbol(p);
  5343. else sym = p;
  5344. if (!is_pair(cdr(x)))
  5345. return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), p, a_binding_string));
  5346. x = cdr(x);
  5347. val = car(x);
  5348. break;
  5349. case T_PAIR:
  5350. sym = car(p);
  5351. if (!is_symbol(sym))
  5352. return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), p, a_symbol_string));
  5353. val = cdr(p);
  5354. break;
  5355. case T_LET:
  5356. append_let(sc, e, check_c_obj_env(sc, p, sc->varlet_symbol));
  5357. continue;
  5358. default:
  5359. return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), p, a_symbol_string));
  5360. }
  5361. if (is_immutable_symbol(sym))
  5362. return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), sym, a_non_constant_symbol_string));
  5363. if (e == sc->rootlet)
  5364. {
  5365. if (is_slot(global_slot(sym)))
  5366. {
  5367. if (is_syntax(slot_value(global_slot(sym))))
  5368. return(wrong_type_argument_with_type(sc, sc->varlet_symbol, position_of(x, args), p, make_string_wrapper(sc, "a non-syntactic keyword")));
  5369. /* without this check we can end up turning our code into gibberish:
  5370. * :(set! quote 1)
  5371. * ;can't set! quote
  5372. * :(varlet (rootlet) '(quote . 1))
  5373. * :quote
  5374. * 1
  5375. * or worse set quote to a function of one arg that tries to quote something -- infinite loop
  5376. */
  5377. slot_set_value(global_slot(sym), val);
  5378. }
  5379. else s7_make_slot(sc, e, sym, val);
  5380. }
  5381. else make_slot_1(sc, e, sym, val);
  5382. /* this used to check for sym already defined, and set its value, but that greatly slows down
  5383. * the most common use (adding a slot), and makes it hard to shadow explicitly. Don't use
  5384. * varlet as a substitute for set!/let-set!.
  5385. */
  5386. }
  5387. return(e);
  5388. }
  5389. /* -------------------------------- cutlet -------------------------------- */
  5390. static s7_pointer g_cutlet(s7_scheme *sc, s7_pointer args)
  5391. {
  5392. #define H_cutlet "(cutlet e symbol ...) removes symbols from the environment e."
  5393. #define Q_cutlet s7_make_circular_signature(sc, 2, 3, sc->is_let_symbol, sc->is_let_symbol, sc->is_symbol_symbol)
  5394. s7_pointer e, syms;
  5395. #define THE_UN_ID ++sc->let_number
  5396. e = car(args);
  5397. if (is_null(e))
  5398. e = sc->rootlet;
  5399. else
  5400. {
  5401. check_method(sc, e, sc->cutlet_symbol, args);
  5402. if (!is_let(e))
  5403. return(wrong_type_argument_with_type(sc, sc->cutlet_symbol, 1, e, a_let_string));
  5404. }
  5405. /* besides removing the slot we have to make sure the symbol_id does not match else
  5406. * let-ref and others will use the old slot! What's the un-id? Perhaps the next one?
  5407. * (let ((b 1)) (let ((b 2)) (cutlet (curlet) 'b)) b)
  5408. */
  5409. for (syms = cdr(args); is_pair(syms); syms = cdr(syms))
  5410. {
  5411. s7_pointer sym, slot;
  5412. sym = car(syms);
  5413. if (!is_symbol(sym))
  5414. return(wrong_type_argument_with_type(sc, sc->cutlet_symbol, position_of(syms, args), sym, a_symbol_string));
  5415. if (is_keyword(sym))
  5416. sym = keyword_symbol(sym);
  5417. if (e == sc->rootlet)
  5418. {
  5419. if (is_slot(global_slot(sym)))
  5420. {
  5421. symbol_set_id(sym, THE_UN_ID);
  5422. slot_set_value(global_slot(sym), sc->undefined);
  5423. }
  5424. }
  5425. else
  5426. {
  5427. slot = let_slots(e);
  5428. if (is_slot(slot))
  5429. {
  5430. if (slot_symbol(slot) == sym)
  5431. {
  5432. let_set_slots(e, next_slot(let_slots(e)));
  5433. symbol_set_id(sym, THE_UN_ID);
  5434. }
  5435. else
  5436. {
  5437. s7_pointer last_slot;
  5438. last_slot = slot;
  5439. for (slot = next_slot(let_slots(e)); is_slot(slot); last_slot = slot, slot = next_slot(slot))
  5440. {
  5441. if (slot_symbol(slot) == sym)
  5442. {
  5443. symbol_set_id(sym, THE_UN_ID);
  5444. set_next_slot(last_slot, next_slot(slot));
  5445. break;
  5446. }
  5447. }
  5448. }
  5449. }
  5450. }
  5451. }
  5452. return(e);
  5453. }
  5454. /* -------------------------------- sublet -------------------------------- */
  5455. static s7_pointer sublet_1(s7_scheme *sc, s7_pointer e, s7_pointer bindings, s7_pointer caller)
  5456. {
  5457. s7_pointer new_e;
  5458. if (e == sc->rootlet)
  5459. new_e = new_frame_in_env(sc, sc->nil);
  5460. else new_e = new_frame_in_env(sc, e);
  5461. set_all_methods(new_e, e);
  5462. if (!is_null(bindings))
  5463. {
  5464. s7_pointer x;
  5465. sc->temp3 = new_e;
  5466. for (x = bindings; is_not_null(x); x = cdr(x))
  5467. {
  5468. s7_pointer p, sym, val;
  5469. p = car(x);
  5470. switch (type(p))
  5471. {
  5472. case T_SYMBOL:
  5473. if (is_keyword(p))
  5474. sym = keyword_symbol(p);
  5475. else sym = p;
  5476. if (!is_pair(cdr(x)))
  5477. return(wrong_type_argument_with_type(sc, caller, position_of(x, bindings), p, a_binding_string));
  5478. x = cdr(x);
  5479. val = car(x);
  5480. break;
  5481. case T_PAIR:
  5482. sym = car(p);
  5483. if (!is_symbol(sym))
  5484. return(wrong_type_argument_with_type(sc, caller, position_of(x, bindings), p, a_symbol_string));
  5485. val = cdr(p);
  5486. break;
  5487. case T_LET:
  5488. append_let(sc, new_e, check_c_obj_env(sc, p, caller));
  5489. continue;
  5490. default:
  5491. return(wrong_type_argument_with_type(sc, caller, position_of(x, bindings), p, a_symbol_string));
  5492. }
  5493. if (is_immutable_symbol(sym))
  5494. return(wrong_type_argument_with_type(sc, caller, position_of(x, bindings), sym, a_non_constant_symbol_string));
  5495. /* here we know new_e is a let and is not rootlet */
  5496. make_slot_1(sc, new_e, sym, val);
  5497. if (sym == sc->let_ref_fallback_symbol)
  5498. set_has_ref_fallback(new_e);
  5499. else
  5500. {
  5501. if (sym == sc->let_set_fallback_symbol)
  5502. set_has_set_fallback(new_e);
  5503. }
  5504. }
  5505. sc->temp3 = sc->nil;
  5506. }
  5507. return(new_e);
  5508. }
  5509. s7_pointer s7_sublet(s7_scheme *sc, s7_pointer e, s7_pointer bindings)
  5510. {
  5511. return(sublet_1(sc, e, bindings, sc->sublet_symbol));
  5512. }
  5513. static s7_pointer g_sublet(s7_scheme *sc, s7_pointer args)
  5514. {
  5515. #define H_sublet "(sublet env ...) adds its \
  5516. arguments (each an environment or a cons: symbol . value) to the environment env, and returns the \
  5517. new environment."
  5518. #define Q_sublet s7_make_circular_signature(sc, 2, 3, sc->is_let_symbol, s7_make_signature(sc, 2, sc->is_let_symbol, sc->is_null_symbol), sc->T)
  5519. s7_pointer e;
  5520. e = car(args);
  5521. if (is_null(e))
  5522. e = sc->rootlet;
  5523. else
  5524. {
  5525. check_method(sc, e, sc->sublet_symbol, args);
  5526. if (!is_let(e))
  5527. return(wrong_type_argument_with_type(sc, sc->sublet_symbol, 1, e, a_let_string));
  5528. }
  5529. return(sublet_1(sc, e, cdr(args), sc->sublet_symbol));
  5530. }
  5531. /* -------------------------------- inlet -------------------------------- */
  5532. s7_pointer s7_inlet(s7_scheme *sc, s7_pointer args)
  5533. {
  5534. #define H_inlet "(inlet ...) adds its \
  5535. arguments, each an environment, a cons: '(symbol . value), or a keyword/value pair, to a new environment, and returns the \
  5536. new environment. (inlet :a 1 :b 2) or (inlet '(a . 1) '(b . 2))"
  5537. #define Q_inlet s7_make_circular_signature(sc, 1, 2, sc->is_let_symbol, sc->T)
  5538. return(sublet_1(sc, sc->rootlet, args, sc->inlet_symbol));
  5539. }
  5540. #define g_inlet s7_inlet
  5541. /* -------------------------------- let->list -------------------------------- */
  5542. s7_pointer s7_let_to_list(s7_scheme *sc, s7_pointer env)
  5543. {
  5544. s7_pointer x;
  5545. sc->temp3 = sc->w;
  5546. sc->w = sc->nil;
  5547. if (env == sc->rootlet)
  5548. {
  5549. unsigned int i, lim2;
  5550. s7_pointer *entries;
  5551. entries = vector_elements(env);
  5552. lim2 = sc->rootlet_entries;
  5553. if (lim2 & 1) lim2--;
  5554. for (i = 0; i < lim2; )
  5555. {
  5556. sc->w = cons_unchecked(sc, cons(sc, slot_symbol(entries[i]), slot_value(entries[i])), sc->w); i++;
  5557. sc->w = cons_unchecked(sc, cons_unchecked(sc, slot_symbol(entries[i]), slot_value(entries[i])), sc->w); i++;
  5558. }
  5559. if (lim2 < sc->rootlet_entries)
  5560. sc->w = cons_unchecked(sc, cons(sc, slot_symbol(entries[i]), slot_value(entries[i])), sc->w);
  5561. }
  5562. else
  5563. {
  5564. s7_pointer iter, func;
  5565. /* need to check make-iterator method before dropping into let->list */
  5566. if ((has_methods(env)) && ((func = find_method(sc, env, sc->make_iterator_symbol)) != sc->undefined))
  5567. iter = s7_apply_function(sc, func, list_1(sc, env));
  5568. else iter = sc->nil;
  5569. if (is_null(iter))
  5570. {
  5571. for (x = let_slots(env); is_slot(x); x = next_slot(x))
  5572. sc->w = cons_unchecked(sc, cons(sc, slot_symbol(x), slot_value(x)), sc->w);
  5573. }
  5574. else
  5575. {
  5576. /* (begin (load "mockery.scm") (let ((lt ((*mock-pair* 'mock-pair) 1 2 3))) (format *stderr* "~{~A ~}" lt))) */
  5577. while (true)
  5578. {
  5579. x = s7_iterate(sc, iter);
  5580. if (iterator_is_at_end(iter)) break;
  5581. sc->w = cons(sc, x, sc->w);
  5582. }
  5583. sc->w = safe_reverse_in_place(sc, sc->w);
  5584. }
  5585. }
  5586. x = sc->w;
  5587. sc->w = sc->temp3;
  5588. sc->temp3 = sc->nil;
  5589. return(x);
  5590. }
  5591. #if (!WITH_PURE_S7)
  5592. static s7_pointer g_let_to_list(s7_scheme *sc, s7_pointer args)
  5593. {
  5594. #define H_let_to_list "(let->list env) returns env's bindings as a list of cons's: '(symbol . value)."
  5595. #define Q_let_to_list s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_let_symbol)
  5596. s7_pointer env;
  5597. env = car(args);
  5598. check_method(sc, env, sc->let_to_list_symbol, args);
  5599. if (!is_let(env))
  5600. {
  5601. if (is_c_object(env))
  5602. env = c_object_let(env);
  5603. if (!is_let(env))
  5604. return(simple_wrong_type_argument_with_type(sc, sc->let_to_list_symbol, env, a_let_string));
  5605. }
  5606. return(s7_let_to_list(sc, env));
  5607. }
  5608. #endif
  5609. /* -------------------------------- let-ref -------------------------------- */
  5610. static s7_pointer let_ref_1(s7_scheme *sc, s7_pointer env, s7_pointer symbol)
  5611. {
  5612. s7_pointer x, y;
  5613. /* (let ((a 1)) ((curlet) 'a))
  5614. * ((rootlet) 'abs)
  5615. */
  5616. if (is_keyword(symbol))
  5617. symbol = keyword_symbol(symbol);
  5618. if (env == sc->rootlet)
  5619. {
  5620. y = global_slot(symbol);
  5621. if (is_slot(y))
  5622. return(slot_value(y));
  5623. return(sc->undefined);
  5624. }
  5625. if (let_id(env) == symbol_id(symbol))
  5626. return(slot_value(local_slot(symbol))); /* this obviously has to follow the global-env check */
  5627. for (x = env; is_let(x); x = outlet(x))
  5628. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  5629. if (slot_symbol(y) == symbol)
  5630. return(slot_value(y));
  5631. /* now for a horrible kludge. If a let is a mock-hash-table (for example), implicit
  5632. * indexing of the hash-table collides with the same thing for the let (field names
  5633. * versus keys), and we can't just try again here because that makes it too easy to
  5634. * get into infinite recursion. So, 'let-ref-fallback...
  5635. */
  5636. if (has_ref_fallback(env))
  5637. check_method(sc, env, sc->let_ref_fallback_symbol, sc->w = list_2(sc, env, symbol));
  5638. /* why did this ignore a global value? Changed 24-May-16 to check rootlet if no methods --
  5639. * apparently I was using #<undefined> here (pre-rootlet-check) to indicate that an
  5640. * open let did not have a particular method (locally). This seems inconsistent now,
  5641. * but it was far worse before. At least (let () ((curlet) 'pi)) is pi!
  5642. */
  5643. if (!has_methods(env))
  5644. {
  5645. y = global_slot(symbol);
  5646. if (is_slot(y))
  5647. return(slot_value(y));
  5648. }
  5649. return(sc->undefined);
  5650. }
  5651. s7_pointer s7_let_ref(s7_scheme *sc, s7_pointer env, s7_pointer symbol)
  5652. {
  5653. if (!is_let(env))
  5654. return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 1, env, a_let_string));
  5655. if (!is_symbol(symbol))
  5656. {
  5657. check_method(sc, env, sc->let_ref_symbol, sc->w = list_2(sc, env, symbol));
  5658. if (has_ref_fallback(env))
  5659. check_method(sc, env, sc->let_ref_fallback_symbol, sc->w = list_2(sc, env, symbol));
  5660. return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 2, symbol, a_symbol_string));
  5661. }
  5662. return(let_ref_1(sc, env, symbol));
  5663. }
  5664. static s7_pointer g_let_ref(s7_scheme *sc, s7_pointer args)
  5665. {
  5666. #define H_let_ref "(let-ref env sym) returns the value of the symbol sym in the environment env"
  5667. #define Q_let_ref s7_make_signature(sc, 3, sc->T, sc->is_let_symbol, sc->is_symbol_symbol)
  5668. s7_pointer e, s;
  5669. e = car(args);
  5670. if (!is_let(e))
  5671. return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 1, e, a_let_string));
  5672. s = cadr(args);
  5673. if (!is_symbol(s))
  5674. {
  5675. check_method(sc, e, sc->let_ref_symbol, args);
  5676. if (has_ref_fallback(e))
  5677. check_method(sc, e, sc->let_ref_fallback_symbol, args);
  5678. return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 2, s, a_symbol_string));
  5679. }
  5680. return(let_ref_1(sc, e, s));
  5681. }
  5682. /* -------------------------------- let-set! -------------------------------- */
  5683. static s7_pointer call_accessor(s7_scheme *sc, s7_pointer slot, s7_pointer old_value)
  5684. {
  5685. s7_pointer func, new_value;
  5686. /* new_value = sc->error_symbol; */
  5687. func = slot_accessor(slot);
  5688. if (is_procedure_or_macro(func))
  5689. {
  5690. if (is_c_function(func))
  5691. {
  5692. set_car(sc->t2_1, slot_symbol(slot));
  5693. set_car(sc->t2_2, old_value);
  5694. new_value = c_function_call(func)(sc, sc->t2_1);
  5695. }
  5696. else
  5697. {
  5698. bool old_off;
  5699. old_off = sc->gc_off;
  5700. sc->gc_off = true;
  5701. new_value = s7_apply_function(sc, func, list_2(sc, slot_symbol(slot), old_value));
  5702. sc->gc_off = old_off;
  5703. }
  5704. }
  5705. else return(old_value);
  5706. if (new_value == sc->error_symbol)
  5707. return(s7_error(sc, sc->error_symbol, set_elist_3(sc, make_string_wrapper(sc, "can't set! ~S to ~S"), slot_symbol(slot), old_value)));
  5708. return(new_value);
  5709. }
  5710. static s7_pointer let_set_1(s7_scheme *sc, s7_pointer env, s7_pointer symbol, s7_pointer value)
  5711. {
  5712. s7_pointer x, y;
  5713. if (is_keyword(symbol))
  5714. symbol = keyword_symbol(symbol);
  5715. if (env == sc->rootlet)
  5716. {
  5717. if (is_immutable_symbol(symbol)) /* (let-set! (rootlet) :rest #f) */
  5718. return(wrong_type_argument_with_type(sc, sc->let_set_symbol, 2, symbol, a_non_constant_symbol_string));
  5719. y = global_slot(symbol);
  5720. if (is_slot(y))
  5721. {
  5722. if (slot_has_accessor(y))
  5723. slot_set_value(y, call_accessor(sc, y, value));
  5724. else slot_set_value(y, value);
  5725. return(slot_value(y));
  5726. }
  5727. return(sc->undefined);
  5728. }
  5729. for (x = env; is_let(x); x = outlet(x))
  5730. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  5731. if (slot_symbol(y) == symbol)
  5732. {
  5733. if (slot_has_accessor(y))
  5734. slot_set_value(y, call_accessor(sc, y, value));
  5735. else slot_set_value(y, value);
  5736. return(slot_value(y));
  5737. }
  5738. if (has_set_fallback(env))
  5739. check_method(sc, env, sc->let_set_fallback_symbol, sc->w = list_3(sc, env, symbol, value));
  5740. if (!has_methods(env))
  5741. {
  5742. y = global_slot(symbol);
  5743. if (is_slot(y))
  5744. {
  5745. if (slot_has_accessor(y))
  5746. slot_set_value(y, call_accessor(sc, y, value));
  5747. else slot_set_value(y, value);
  5748. return(slot_value(y));
  5749. }
  5750. }
  5751. return(sc->undefined);
  5752. }
  5753. s7_pointer s7_let_set(s7_scheme *sc, s7_pointer env, s7_pointer symbol, s7_pointer value)
  5754. {
  5755. if (!is_let(env))
  5756. return(wrong_type_argument_with_type(sc, sc->let_set_symbol, 1, env, a_let_string));
  5757. if (!is_symbol(symbol))
  5758. {
  5759. check_method(sc, env, sc->let_set_symbol, sc->w = list_3(sc, env, symbol, value));
  5760. if (has_set_fallback(env))
  5761. check_method(sc, env, sc->let_set_fallback_symbol, sc->w = list_3(sc, env, symbol, value));
  5762. return(wrong_type_argument_with_type(sc, sc->let_set_symbol, 2, symbol, a_symbol_string));
  5763. }
  5764. return(let_set_1(sc, env, symbol, value));
  5765. }
  5766. static s7_pointer g_let_set(s7_scheme *sc, s7_pointer args)
  5767. {
  5768. /* (let ((a 1)) (set! ((curlet) 'a) 32) a) */
  5769. #define H_let_set "(let-set! env sym val) sets the symbol sym's value in the environment env to val"
  5770. #define Q_let_set s7_make_signature(sc, 4, sc->T, sc->is_let_symbol, sc->is_symbol_symbol, sc->T)
  5771. return(s7_let_set(sc, car(args), cadr(args), caddr(args)));
  5772. }
  5773. static s7_pointer reverse_slots(s7_scheme *sc, s7_pointer list)
  5774. {
  5775. s7_pointer p = list, result, q;
  5776. result = sc->nil;
  5777. while (is_slot(p))
  5778. {
  5779. q = next_slot(p);
  5780. set_next_slot(p, result);
  5781. result = p;
  5782. p = q;
  5783. }
  5784. return(result);
  5785. }
  5786. static s7_pointer let_copy(s7_scheme *sc, s7_pointer env)
  5787. {
  5788. if (is_let(env))
  5789. {
  5790. s7_pointer new_e;
  5791. if (env == sc->rootlet) /* (copy (rootlet)) or (copy (funclet abs)) etc */
  5792. return(sc->rootlet);
  5793. /* we can't make copy handle environments-as-objects specially because the
  5794. * make-object function in define-class uses copy to make a new object!
  5795. * So if it is present, we get it here, and then there's almost surely trouble.
  5796. */
  5797. new_e = new_frame_in_env(sc, outlet(env));
  5798. set_all_methods(new_e, env);
  5799. sc->temp3 = new_e;
  5800. if (is_slot(let_slots(env)))
  5801. {
  5802. s7_int id;
  5803. s7_pointer x, y = NULL;
  5804. id = let_id(new_e);
  5805. for (x = let_slots(env); is_slot(x); x = next_slot(x))
  5806. {
  5807. s7_pointer z;
  5808. new_cell(sc, z, T_SLOT);
  5809. slot_set_symbol(z, slot_symbol(x));
  5810. slot_set_value(z, slot_value(x));
  5811. if (symbol_id(slot_symbol(z)) != id) /* keep shadowing intact */
  5812. symbol_set_local(slot_symbol(x), id, z);
  5813. if (is_slot(let_slots(new_e)))
  5814. set_next_slot(y, z);
  5815. else let_set_slots(new_e, z);
  5816. set_next_slot(z, sc->nil); /* in case GC runs during this loop */
  5817. y = z;
  5818. }
  5819. }
  5820. /* We can't do a (normal) loop here then reverse the slots later because the symbol's local_slot has to
  5821. * match the unshadowed slot, not the last in the list:
  5822. * (let ((e1 (inlet 'a 1 'a 2))) (let ((e2 (copy e1))) (list (equal? e1 e2) (equal? (e1 'a) (e2 'a)))))
  5823. */
  5824. sc->temp3 = sc->nil;
  5825. return(new_e);
  5826. }
  5827. return(sc->nil);
  5828. }
  5829. /* -------------------------------- rootlet -------------------------------- */
  5830. static s7_pointer g_rootlet(s7_scheme *sc, s7_pointer ignore)
  5831. {
  5832. #define H_rootlet "(rootlet) returns the current top-level definitions (symbol bindings)."
  5833. #define Q_rootlet s7_make_signature(sc, 1, sc->is_let_symbol)
  5834. return(sc->rootlet);
  5835. }
  5836. /* as with the symbol-table, this function can lead to disaster -- user could
  5837. * clobber the environment etc. But we want it to be editable and augmentable,
  5838. * so I guess I'll leave it alone. (See curlet|funclet as well).
  5839. */
  5840. s7_pointer s7_rootlet(s7_scheme *sc)
  5841. {
  5842. return(sc->rootlet);
  5843. }
  5844. s7_pointer s7_shadow_rootlet(s7_scheme *sc)
  5845. {
  5846. return(sc->shadow_rootlet);
  5847. }
  5848. s7_pointer s7_set_shadow_rootlet(s7_scheme *sc, s7_pointer let)
  5849. {
  5850. sc->shadow_rootlet = let;
  5851. return(let);
  5852. }
  5853. /* -------------------------------- curlet -------------------------------- */
  5854. static s7_pointer g_curlet(s7_scheme *sc, s7_pointer args)
  5855. {
  5856. #define H_curlet "(curlet) returns the current definitions (symbol bindings)"
  5857. #define Q_curlet s7_make_signature(sc, 1, sc->is_let_symbol)
  5858. sc->capture_let_counter++;
  5859. if (is_let(sc->envir))
  5860. return(sc->envir);
  5861. return(sc->rootlet);
  5862. }
  5863. s7_pointer s7_curlet(s7_scheme *sc)
  5864. {
  5865. sc->capture_let_counter++;
  5866. return(sc->envir);
  5867. }
  5868. s7_pointer s7_set_curlet(s7_scheme *sc, s7_pointer e)
  5869. {
  5870. s7_pointer p, old_e;
  5871. old_e = sc->envir;
  5872. sc->envir = e;
  5873. if ((is_let(e)) && (let_id(e) > 0)) /* might be () [id=-1] or rootlet [id=0] etc */
  5874. {
  5875. let_id(e) = ++sc->let_number;
  5876. for (p = let_slots(e); is_slot(p); p = next_slot(p))
  5877. {
  5878. s7_pointer sym;
  5879. sym = slot_symbol(p);
  5880. if (symbol_id(sym) != sc->let_number)
  5881. symbol_set_local(sym, sc->let_number, p);
  5882. }
  5883. }
  5884. return(old_e);
  5885. }
  5886. /* -------------------------------- outlet -------------------------------- */
  5887. s7_pointer s7_outlet(s7_scheme *sc, s7_pointer e)
  5888. {
  5889. return(outlet(e));
  5890. }
  5891. static s7_pointer g_outlet(s7_scheme *sc, s7_pointer args)
  5892. {
  5893. #define H_outlet "(outlet env) is the environment that contains env."
  5894. #define Q_outlet s7_make_signature(sc, 2, sc->is_let_symbol, sc->is_let_symbol)
  5895. s7_pointer env;
  5896. env = car(args);
  5897. if (!is_let(env))
  5898. method_or_bust_with_type(sc, env, sc->outlet_symbol, args, a_let_string, 0);
  5899. if ((env == sc->rootlet) ||
  5900. (is_null(outlet(env))))
  5901. return(sc->rootlet);
  5902. return(outlet(env));
  5903. }
  5904. static s7_pointer g_set_outlet(s7_scheme *sc, s7_pointer args)
  5905. {
  5906. /* (let ((a 1)) (let ((b 2)) (set! (outlet (curlet)) (rootlet)) ((curlet) 'a))) */
  5907. s7_pointer env, new_outer;
  5908. env = car(args);
  5909. if (!is_let(env))
  5910. return(s7_wrong_type_arg_error(sc, "set! outlet", 1, env, "a let"));
  5911. new_outer = cadr(args);
  5912. if (!is_let(new_outer))
  5913. return(s7_wrong_type_arg_error(sc, "set! outlet", 2, new_outer, "a let"));
  5914. if (new_outer == sc->rootlet)
  5915. new_outer = sc->nil;
  5916. if (env != sc->rootlet)
  5917. set_outlet(env, new_outer);
  5918. return(new_outer);
  5919. }
  5920. static s7_pointer find_symbol(s7_scheme *sc, s7_pointer symbol)
  5921. {
  5922. s7_pointer x;
  5923. if (let_id(sc->envir) == symbol_id(symbol))
  5924. return(local_slot(symbol));
  5925. for (x = sc->envir; symbol_id(symbol) < let_id(x); x = outlet(x));
  5926. if (let_id(x) == symbol_id(symbol))
  5927. return(local_slot(symbol));
  5928. for (; is_let(x); x = outlet(x))
  5929. {
  5930. s7_pointer y;
  5931. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  5932. if (slot_symbol(y) == symbol)
  5933. return(y);
  5934. }
  5935. return(global_slot(symbol));
  5936. }
  5937. #if WITH_GCC && DEBUGGING
  5938. static s7_pointer find_symbol_unchecked_1(s7_scheme *sc, s7_pointer symbol)
  5939. #else
  5940. static s7_pointer find_symbol_unchecked(s7_scheme *sc, s7_pointer symbol) /* find_symbol_checked includes the unbound_variable call */
  5941. #endif
  5942. {
  5943. s7_pointer x;
  5944. /* fprintf(stderr, "let_id: %lld, %s id: %lld\n", let_id(sc->envir), DISPLAY(symbol), symbol_id(symbol)); */
  5945. if (let_id(sc->envir) == symbol_id(symbol))
  5946. return(slot_value(local_slot(symbol)));
  5947. for (x = sc->envir; symbol_id(symbol) < let_id(x); x = outlet(x));
  5948. /* this looks redundant, but every attempt to improve it is much slower! */
  5949. if (let_id(x) == symbol_id(symbol))
  5950. return(slot_value(local_slot(symbol)));
  5951. for (; is_let(x); x = outlet(x))
  5952. {
  5953. s7_pointer y;
  5954. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  5955. if (slot_symbol(y) == symbol)
  5956. return(slot_value(y));
  5957. }
  5958. x = global_slot(symbol);
  5959. if (is_slot(x))
  5960. return(slot_value(x));
  5961. #if WITH_GCC
  5962. return(NULL);
  5963. #else
  5964. return(unbound_variable(sc, symbol));
  5965. #endif
  5966. }
  5967. s7_pointer s7_slot(s7_scheme *sc, s7_pointer symbol)
  5968. {
  5969. return(find_symbol(sc, symbol));
  5970. }
  5971. s7_pointer s7_slot_value(s7_pointer slot)
  5972. {
  5973. return(slot_value(slot));
  5974. }
  5975. s7_pointer s7_slot_set_value(s7_scheme *sc, s7_pointer slot, s7_pointer value)
  5976. {
  5977. slot_set_value(slot, value);
  5978. return(value);
  5979. }
  5980. void s7_slot_set_real_value(s7_scheme *sc, s7_pointer slot, s7_double value)
  5981. {
  5982. set_real(slot_value(slot), value);
  5983. }
  5984. s7_double s7_slot_real_value(s7_scheme *sc, s7_pointer slot, const char *caller)
  5985. {
  5986. return(real_to_double(sc, slot_value(slot), caller));
  5987. }
  5988. s7_int s7_slot_integer_value(s7_pointer slot)
  5989. {
  5990. return(integer(slot_value(slot)));
  5991. }
  5992. static s7_pointer find_local_symbol(s7_scheme *sc, s7_pointer symbol, s7_pointer e)
  5993. {
  5994. if (!is_let(e))
  5995. return(global_slot(symbol));
  5996. if (symbol_id(symbol) != 0)
  5997. {
  5998. s7_pointer y;
  5999. for (y = let_slots(e); is_slot(y); y = next_slot(y))
  6000. if (slot_symbol(y) == symbol)
  6001. return(y);
  6002. }
  6003. return(sc->undefined);
  6004. }
  6005. static s7_pointer s7_local_slot(s7_scheme *sc, s7_pointer symbol)
  6006. {
  6007. s7_pointer y;
  6008. for (y = let_slots(sc->envir); is_slot(y); y = next_slot(y))
  6009. if (slot_symbol(y) == symbol)
  6010. return(y);
  6011. return(NULL);
  6012. }
  6013. s7_pointer s7_symbol_value(s7_scheme *sc, s7_pointer sym)
  6014. {
  6015. s7_pointer x;
  6016. x = find_symbol(sc, sym);
  6017. if (is_slot(x))
  6018. return(slot_value(x));
  6019. return(sc->undefined);
  6020. }
  6021. s7_pointer s7_symbol_local_value(s7_scheme *sc, s7_pointer sym, s7_pointer local_env)
  6022. {
  6023. if (is_let(local_env))
  6024. {
  6025. s7_pointer x;
  6026. for (x = local_env; is_let(x); x = outlet(x))
  6027. {
  6028. s7_pointer y;
  6029. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  6030. if (slot_symbol(y) == sym)
  6031. return(slot_value(y));
  6032. }
  6033. }
  6034. return(s7_symbol_value(sc, sym));
  6035. }
  6036. /* -------------------------------- symbol->value -------------------------------- */
  6037. #define find_global_symbol_checked(Sc, Sym) ((is_global(Sym)) ? slot_value(global_slot(Sym)) : find_symbol_checked(Sc, Sym))
  6038. static s7_pointer g_symbol_to_value(s7_scheme *sc, s7_pointer args)
  6039. {
  6040. #define H_symbol_to_value "(symbol->value sym (env (curlet))) returns the binding of (the value associated with) the \
  6041. symbol sym in the given environment: (let ((x 32)) (symbol->value 'x)) -> 32"
  6042. #define Q_symbol_to_value s7_make_signature(sc, 3, sc->T, sc->is_symbol_symbol, sc->is_let_symbol)
  6043. /* (symbol->value 'x e) => (e 'x)? */
  6044. s7_pointer sym;
  6045. sym = car(args);
  6046. if (!is_symbol(sym))
  6047. method_or_bust(sc, sym, sc->symbol_to_value_symbol, args, T_SYMBOL, 1);
  6048. if (is_not_null(cdr(args)))
  6049. {
  6050. s7_pointer local_env;
  6051. local_env = cadr(args);
  6052. if (local_env == sc->unlet_symbol)
  6053. return((is_slot(initial_slot(sym))) ? slot_value(initial_slot(sym)) : sc->undefined);
  6054. if (!is_let(local_env))
  6055. method_or_bust_with_type(sc, local_env, sc->symbol_to_value_symbol, args, a_let_string, 2);
  6056. if (local_env == sc->rootlet)
  6057. {
  6058. s7_pointer x;
  6059. x = global_slot(sym);
  6060. if (is_slot(x))
  6061. return(slot_value(x));
  6062. return(sc->undefined);
  6063. }
  6064. return(s7_symbol_local_value(sc, sym, local_env));
  6065. }
  6066. if (is_global(sym))
  6067. return(slot_value(global_slot(sym)));
  6068. return(s7_symbol_value(sc, sym));
  6069. }
  6070. s7_pointer s7_symbol_set_value(s7_scheme *sc, s7_pointer sym, s7_pointer val)
  6071. {
  6072. s7_pointer x;
  6073. /* if immutable should this return an error? */
  6074. x = find_symbol(sc, sym);
  6075. if (is_slot(x))
  6076. slot_set_value(x, val);
  6077. return(val);
  6078. }
  6079. /* -------------------------------- symbol->dynamic-value -------------------------------- */
  6080. static s7_pointer find_dynamic_value(s7_scheme *sc, s7_pointer x, s7_pointer sym, long long int *id)
  6081. {
  6082. for (; symbol_id(sym) < let_id(x); x = outlet(x));
  6083. if (let_id(x) == symbol_id(sym))
  6084. {
  6085. (*id) = let_id(x);
  6086. return(slot_value(local_slot(sym)));
  6087. }
  6088. for (; (is_let(x)) && (let_id(x) > (*id)); x = outlet(x))
  6089. {
  6090. s7_pointer y;
  6091. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  6092. if (slot_symbol(y) == sym)
  6093. {
  6094. (*id) = let_id(x);
  6095. return(slot_value(y));
  6096. }
  6097. }
  6098. return(sc->gc_nil);
  6099. }
  6100. static s7_pointer g_symbol_to_dynamic_value(s7_scheme *sc, s7_pointer args)
  6101. {
  6102. #define H_symbol_to_dynamic_value "(symbol->dynamic-value sym) returns the dynamic binding of the symbol sym"
  6103. #define Q_symbol_to_dynamic_value s7_make_signature(sc, 2, sc->T, sc->is_symbol_symbol)
  6104. s7_pointer sym, val;
  6105. long long int top_id;
  6106. int i;
  6107. sym = car(args);
  6108. if (!is_symbol(sym))
  6109. method_or_bust(sc, sym, sc->symbol_to_dynamic_value_symbol, args, T_SYMBOL, 1);
  6110. if (is_global(sym))
  6111. return(slot_value(global_slot(sym)));
  6112. if (let_id(sc->envir) == symbol_id(sym))
  6113. return(slot_value(local_slot(sym)));
  6114. top_id = -1;
  6115. val = find_dynamic_value(sc, sc->envir, sym, &top_id);
  6116. if (top_id == symbol_id(sym))
  6117. return(val);
  6118. for (i = s7_stack_top(sc) - 1; i > 0; i -= 4)
  6119. {
  6120. s7_pointer cur_val;
  6121. cur_val = find_dynamic_value(sc, stack_let(sc->stack, i), sym, &top_id);
  6122. if (cur_val != sc->gc_nil)
  6123. val = cur_val;
  6124. if (top_id == symbol_id(sym))
  6125. return(val);
  6126. }
  6127. if (val == sc->gc_nil)
  6128. return(s7_symbol_value(sc, sym));
  6129. return(val);
  6130. }
  6131. typedef bool (safe_sym_t)(s7_scheme *sc, s7_pointer sym, s7_pointer e);
  6132. static s7_function all_x_eval(s7_scheme *sc, s7_pointer arg, s7_pointer e, safe_sym_t *checker);
  6133. static bool direct_memq(s7_pointer symbol, s7_pointer symbols)
  6134. {
  6135. s7_pointer x;
  6136. for (x = symbols; is_pair(x); x = unchecked_cdr(x))
  6137. {
  6138. if (car(x) == symbol)
  6139. return(true);
  6140. x = cdr(x);
  6141. if (unchecked_car(x) == symbol)
  6142. return(true);
  6143. }
  6144. return(false);
  6145. }
  6146. static bool indirect_memq(s7_pointer symbol, s7_pointer symbols)
  6147. { /* used only below in do_symbol_is_safe */
  6148. s7_pointer x;
  6149. for (x = symbols; is_pair(x); x = cdr(x))
  6150. if (caar(x) == symbol)
  6151. return(true);
  6152. return(false);
  6153. }
  6154. static bool do_symbol_is_safe(s7_scheme *sc, s7_pointer sym, s7_pointer e)
  6155. {
  6156. return((is_slot(global_slot(sym))) ||
  6157. (indirect_memq(sym, e)) ||
  6158. (is_slot(find_symbol(sc, sym))));
  6159. }
  6160. static bool let_symbol_is_safe(s7_scheme *sc, s7_pointer sym, s7_pointer e)
  6161. {
  6162. return((is_slot(global_slot(sym))) || ((!is_with_let_let(e)) && (is_slot(find_symbol(sc, sym)))));
  6163. }
  6164. static bool pair_symbol_is_safe(s7_scheme *sc, s7_pointer sym, s7_pointer e)
  6165. {
  6166. return((is_slot(global_slot(sym))) || (direct_memq(sym, e)));
  6167. }
  6168. /* make macros and closures */
  6169. static s7_pointer make_macro(s7_scheme *sc)
  6170. {
  6171. s7_pointer cx, mac;
  6172. unsigned int typ;
  6173. if (sc->op == OP_DEFINE_MACRO)
  6174. typ = T_MACRO | T_DONT_EVAL_ARGS | T_COPY_ARGS;
  6175. else
  6176. {
  6177. if (sc->op == OP_DEFINE_MACRO_STAR)
  6178. typ = T_MACRO_STAR | T_DONT_EVAL_ARGS | T_COPY_ARGS;
  6179. else
  6180. {
  6181. if (sc->op == OP_DEFINE_BACRO)
  6182. typ = T_BACRO | T_DONT_EVAL_ARGS | T_COPY_ARGS;
  6183. else
  6184. {
  6185. if (sc->op == OP_DEFINE_BACRO_STAR)
  6186. typ = T_BACRO_STAR | T_DONT_EVAL_ARGS | T_COPY_ARGS;
  6187. else
  6188. {
  6189. if ((sc->op == OP_DEFINE_EXPANSION) &&
  6190. (!is_let(sc->envir))) /* local expansions are just normal macros */
  6191. typ = T_MACRO | T_EXPANSION | T_DONT_EVAL_ARGS | T_COPY_ARGS;
  6192. else typ = T_MACRO | T_DONT_EVAL_ARGS | T_COPY_ARGS;
  6193. }
  6194. }
  6195. }
  6196. }
  6197. new_cell_no_check(sc, mac, typ);
  6198. sc->temp6 = mac;
  6199. closure_set_args(mac, cdar(sc->code));
  6200. closure_set_body(mac, cdr(sc->code));
  6201. closure_set_setter(mac, sc->F);
  6202. closure_set_let(mac, sc->envir);
  6203. closure_arity(mac) = CLOSURE_ARITY_NOT_SET;
  6204. sc->capture_let_counter++;
  6205. sc->code = caar(sc->code);
  6206. if ((sc->op == OP_DEFINE_EXPANSION) &&
  6207. (!is_let(sc->envir)))
  6208. set_type(sc->code, T_EXPANSION | T_SYMBOL); /* see comment under READ_TOK */
  6209. /* symbol? macro name has already been checked, find name in environment, and define it */
  6210. cx = find_local_symbol(sc, sc->code, sc->envir);
  6211. if (is_slot(cx))
  6212. slot_set_value(cx, mac);
  6213. else s7_make_slot(sc, sc->envir, sc->code, mac); /* was current but we've checked immutable already */
  6214. optimize(sc, closure_body(mac), 0, sc->nil);
  6215. sc->temp6 = sc->nil;
  6216. return(mac);
  6217. }
  6218. static s7_pointer make_closure(s7_scheme *sc, s7_pointer args, s7_pointer code, int type)
  6219. {
  6220. /* this is called every time a lambda form is evaluated, or during letrec, etc */
  6221. s7_pointer x;
  6222. unsigned int typ;
  6223. if (is_safe_closure(code))
  6224. {
  6225. if (type == T_CLOSURE)
  6226. typ = T_CLOSURE | T_PROCEDURE | T_SAFE_CLOSURE | T_COPY_ARGS;
  6227. else typ = T_CLOSURE_STAR | T_PROCEDURE | T_SAFE_CLOSURE;
  6228. }
  6229. else
  6230. {
  6231. if (type == T_CLOSURE)
  6232. typ = T_CLOSURE | T_PROCEDURE | T_COPY_ARGS;
  6233. else typ = T_CLOSURE_STAR | T_PROCEDURE;
  6234. }
  6235. new_cell(sc, x, typ);
  6236. closure_set_args(x, args);
  6237. closure_set_body(x, code);
  6238. closure_set_setter(x, sc->F);
  6239. if (is_null(args))
  6240. closure_arity(x) = 0;
  6241. else closure_arity(x) = CLOSURE_ARITY_NOT_SET;
  6242. closure_set_let(x, sc->envir);
  6243. sc->capture_let_counter++;
  6244. return(x);
  6245. }
  6246. #define make_closure_with_let(Sc, X, Args, Code, Env) \
  6247. do { \
  6248. unsigned int _T_; \
  6249. if (is_safe_closure(Code)) \
  6250. _T_ = T_CLOSURE | T_PROCEDURE | T_SAFE_CLOSURE | T_COPY_ARGS; \
  6251. else _T_ = T_CLOSURE | T_PROCEDURE | T_COPY_ARGS; \
  6252. new_cell(Sc, X, _T_); \
  6253. closure_set_args(X, Args); \
  6254. closure_set_body(X, Code); \
  6255. closure_set_setter(X, sc->F); \
  6256. if (is_null(Args)) closure_arity(X) = 0; else closure_arity(X) = CLOSURE_ARITY_NOT_SET; \
  6257. closure_set_let(X, Env); \
  6258. sc->capture_let_counter++; \
  6259. } while (0)
  6260. #define make_closure_without_capture(Sc, X, Args, Code, Env) \
  6261. do { \
  6262. unsigned int _T_; \
  6263. if (is_safe_closure(Code)) \
  6264. _T_ = T_CLOSURE | T_PROCEDURE | T_SAFE_CLOSURE | T_COPY_ARGS; \
  6265. else _T_ = T_CLOSURE | T_PROCEDURE | T_COPY_ARGS; \
  6266. new_cell(Sc, X, _T_); \
  6267. closure_set_args(X, Args); \
  6268. closure_set_body(X, Code); \
  6269. closure_set_setter(X, sc->F); \
  6270. if (is_null(Args)) closure_arity(X) = 0; else closure_arity(X) = CLOSURE_ARITY_NOT_SET; \
  6271. closure_set_let(X, Env); \
  6272. } while (0)
  6273. static int closure_length(s7_scheme *sc, s7_pointer e)
  6274. {
  6275. /* we can't use let_length(sc, closure_let(e)) because the closure_let(closure)
  6276. * changes. So the open bit is not always on. Besides, the fallbacks need to be for closures, not environments.
  6277. */
  6278. s7_pointer length_func;
  6279. length_func = find_method(sc, closure_let(e), sc->length_symbol);
  6280. if (length_func != sc->undefined)
  6281. return((int)s7_integer(s7_apply_function(sc, length_func, list_1(sc, e))));
  6282. /* there are cases where this should raise a wrong-type-arg error, but for now... */
  6283. return(-1);
  6284. }
  6285. #define check_closure_for(Sc, Fnc, Sym) \
  6286. if ((has_closure_let(Fnc)) && (is_let(closure_let(Fnc)))) \
  6287. { \
  6288. s7_pointer val; \
  6289. val = find_local_symbol(Sc, Sym, closure_let(Fnc)); \
  6290. if ((!is_slot(val)) && (is_let(outlet(closure_let(Fnc))))) \
  6291. val = find_local_symbol(Sc, Sym, outlet(closure_let(Fnc))); \
  6292. if (is_slot(val)) \
  6293. return(slot_value(val)); \
  6294. }
  6295. static s7_pointer copy_tree(s7_scheme *sc, s7_pointer tree)
  6296. {
  6297. #if WITH_GCC
  6298. #define COPY_TREE(P) ({s7_pointer _p; _p = P; cons_unchecked(sc, (is_pair(car(_p))) ? copy_tree(sc, car(_p)) : car(_p), (is_pair(cdr(_p))) ? copy_tree(sc, cdr(_p)) : cdr(_p));})
  6299. #else
  6300. #define COPY_TREE(P) copy_tree(sc, P)
  6301. #endif
  6302. return(cons_unchecked(sc,
  6303. (is_pair(car(tree))) ? COPY_TREE(car(tree)) : car(tree),
  6304. (is_pair(cdr(tree))) ? COPY_TREE(cdr(tree)) : cdr(tree)));
  6305. }
  6306. static void annotate_expansion(s7_pointer p)
  6307. {
  6308. if ((is_symbol(car(p))) &&
  6309. (is_pair(cdr(p))))
  6310. {
  6311. set_opt_back(p);
  6312. set_overlay(cdr(p));
  6313. }
  6314. else
  6315. {
  6316. if (is_pair(car(p)))
  6317. annotate_expansion(car(p));
  6318. }
  6319. for (p = cdr(p); is_pair(p); p = cdr(p))
  6320. if (is_pair(car(p)))
  6321. annotate_expansion(car(p));
  6322. }
  6323. static s7_pointer copy_body(s7_scheme *sc, s7_pointer p)
  6324. {
  6325. if (8192 >= (sc->free_heap_top - sc->free_heap))
  6326. {
  6327. gc(sc);
  6328. while (8192 >= (sc->free_heap_top - sc->free_heap))
  6329. resize_heap(sc);
  6330. }
  6331. sc->w = copy_tree(sc, p);
  6332. annotate_expansion(sc->w);
  6333. p = sc->w;
  6334. sc->w = sc->nil;
  6335. return(p);
  6336. }
  6337. static s7_pointer copy_closure(s7_scheme *sc, s7_pointer fnc)
  6338. {
  6339. /* copy the source tree annotating (for eventual optimization), return a thing of the same type as fnc */
  6340. s7_pointer x, body;
  6341. body = copy_body(sc, closure_body(fnc));
  6342. new_cell(sc, x, typeflag(fnc));
  6343. closure_set_args(x, closure_args(fnc));
  6344. closure_set_body(x, body);
  6345. closure_set_setter(x, closure_setter(fnc));
  6346. closure_arity(x) = closure_arity(fnc);
  6347. closure_set_let(x, closure_let(fnc));
  6348. return(x);
  6349. }
  6350. /* -------------------------------- defined? -------------------------------- */
  6351. static s7_pointer g_is_defined(s7_scheme *sc, s7_pointer args)
  6352. {
  6353. #define H_is_defined "(defined? obj (env (curlet)) ignore-globals) returns #t if obj has a binding (a value) in the environment env"
  6354. #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)
  6355. s7_pointer sym;
  6356. /* is this correct?
  6357. * (defined? '_x) #f (symbol->value '_x) #<undefined>
  6358. * (define x #<undefined>) (defined? 'x) #t
  6359. */
  6360. sym = car(args);
  6361. if (!is_symbol(sym))
  6362. method_or_bust(sc, sym, sc->is_defined_symbol, args, T_SYMBOL, 1);
  6363. if (is_pair(cdr(args)))
  6364. {
  6365. s7_pointer e, b, x;
  6366. e = cadr(args);
  6367. if (!is_let(e))
  6368. return(wrong_type_argument_with_type(sc, sc->is_defined_symbol, 2, e, a_let_string));
  6369. if (is_pair(cddr(args)))
  6370. {
  6371. b = caddr(args);
  6372. if (!s7_is_boolean(b))
  6373. method_or_bust_with_type(sc, b, sc->is_defined_symbol, args, a_boolean_string, 3);
  6374. }
  6375. else b = sc->F;
  6376. if (e == sc->rootlet)
  6377. return(make_boolean(sc, is_slot(global_slot(sym)))); /* new_symbol and gensym initialize global_slot to #<undefined> */
  6378. x = find_local_symbol(sc, sym, e);
  6379. if (is_slot(x))
  6380. return(sc->T);
  6381. if (b == sc->T)
  6382. return(sc->F);
  6383. /* here we can't fall back on find_symbol:
  6384. * (let ((b 2))
  6385. * (let ((e (curlet)))
  6386. * (let ((a 1))
  6387. * (if (defined? 'a e)
  6388. * (format #t "a: ~A in ~{~A ~}" (symbol->value 'a e) e))))
  6389. * "a: 1 in (b . 2)"
  6390. *
  6391. * but we also can't just return #f:
  6392. * (let ((b 2))
  6393. * (let ((e (curlet)))
  6394. * (let ((a 1))
  6395. * (format #t "~A: ~A" (defined? 'abs e) (eval '(abs -1) e)))))
  6396. * "#f: 1"
  6397. */
  6398. return(make_boolean(sc, is_slot(global_slot(sym))));
  6399. }
  6400. else
  6401. {
  6402. if (is_global(sym))
  6403. return(sc->T);
  6404. }
  6405. return(make_boolean(sc, is_slot(find_symbol(sc, sym))));
  6406. }
  6407. bool s7_is_defined(s7_scheme *sc, const char *name)
  6408. {
  6409. s7_pointer x;
  6410. x = s7_symbol_table_find_name(sc, name);
  6411. if (x)
  6412. {
  6413. x = find_symbol(sc, x);
  6414. return(is_slot(x));
  6415. }
  6416. return(false);
  6417. }
  6418. void s7_define(s7_scheme *sc, s7_pointer envir, s7_pointer symbol, s7_pointer value)
  6419. {
  6420. s7_pointer x;
  6421. if ((envir == sc->nil) ||
  6422. (envir == sc->rootlet))
  6423. envir = sc->shadow_rootlet;
  6424. x = find_local_symbol(sc, symbol, envir);
  6425. if (is_slot(x))
  6426. slot_set_value(x, value);
  6427. else
  6428. {
  6429. s7_make_slot(sc, envir, symbol, value); /* I think this means C code can override "constant" defs */
  6430. if ((envir == sc->shadow_rootlet) &&
  6431. (!is_slot(global_slot(symbol))))
  6432. {
  6433. set_global(symbol); /* is_global => global_slot is usable */
  6434. set_global_slot(symbol, local_slot(symbol));
  6435. }
  6436. }
  6437. }
  6438. s7_pointer s7_define_variable(s7_scheme *sc, const char *name, s7_pointer value)
  6439. {
  6440. s7_pointer sym;
  6441. sym = make_symbol(sc, name);
  6442. s7_define(sc, sc->nil, sym, value);
  6443. return(sym);
  6444. }
  6445. s7_pointer s7_define_variable_with_documentation(s7_scheme *sc, const char *name, s7_pointer value, const char *help)
  6446. {
  6447. s7_pointer sym;
  6448. sym = s7_define_variable(sc, name, value);
  6449. symbol_set_has_help(sym);
  6450. symbol_help(sym) = copy_string(help);
  6451. return(sym);
  6452. }
  6453. s7_pointer s7_define_constant(s7_scheme *sc, const char *name, s7_pointer value)
  6454. {
  6455. s7_pointer sym;
  6456. sym = make_symbol(sc, name);
  6457. s7_define(sc, sc->nil, sym, value);
  6458. set_immutable(sym);
  6459. return(sym);
  6460. }
  6461. /* (define (func a) (let ((cvar (+ a 1))) cvar)) (define-constant cvar 23) (func 1) -> ;can't bind an immutable object: cvar
  6462. * (let ((aaa 1)) (define-constant aaa 32) (set! aaa 3)) -> set!: can't alter immutable object: aaa
  6463. */
  6464. s7_pointer s7_define_constant_with_documentation(s7_scheme *sc, const char *name, s7_pointer value, const char *help)
  6465. {
  6466. s7_pointer sym;
  6467. sym = s7_define_constant(sc, name, value);
  6468. symbol_set_has_help(sym);
  6469. symbol_help(sym) = copy_string(help);
  6470. return(value); /* inconsistent with variable above, but consistent with define_function? */
  6471. }
  6472. char *s7_symbol_documentation(s7_scheme *sc, s7_pointer sym)
  6473. {
  6474. if (is_keyword(sym)) return(NULL);
  6475. if ((is_symbol(sym)) &&
  6476. (symbol_has_help(sym)))
  6477. return(symbol_help(sym));
  6478. return(NULL);
  6479. }
  6480. char *s7_symbol_set_documentation(s7_scheme *sc, s7_pointer sym, const char *new_doc)
  6481. {
  6482. if (is_keyword(sym)) return(NULL);
  6483. if ((is_symbol(sym)) &&
  6484. (symbol_has_help(sym)) &&
  6485. (symbol_help(sym)))
  6486. free(symbol_help(sym));
  6487. symbol_set_has_help(sym);
  6488. symbol_help(sym) = copy_string(new_doc);
  6489. return(symbol_help(sym));
  6490. }
  6491. /* -------------------------------- keyword? -------------------------------- */
  6492. bool s7_is_keyword(s7_pointer obj)
  6493. {
  6494. return(is_keyword(obj));
  6495. }
  6496. static s7_pointer g_is_keyword(s7_scheme *sc, s7_pointer args)
  6497. {
  6498. #define H_is_keyword "(keyword? obj) returns #t if obj is a keyword, (keyword? :rest) -> #t"
  6499. #define Q_is_keyword pl_bt
  6500. check_boolean_method(sc, is_keyword, sc->is_keyword_symbol, args);
  6501. }
  6502. /* -------------------------------- make-keyword -------------------------------- */
  6503. s7_pointer s7_make_keyword(s7_scheme *sc, const char *key)
  6504. {
  6505. s7_pointer sym;
  6506. char *name;
  6507. unsigned int slen;
  6508. slen = safe_strlen(key);
  6509. tmpbuf_malloc(name, slen + 2);
  6510. name[0] = ':'; /* prepend ":" */
  6511. name[1] = '\0';
  6512. memcpy((void *)(name + 1), (void *)key, slen);
  6513. sym = make_symbol_with_length(sc, name, slen + 1); /* keyword slot etc taken care of here (in new_symbol actually) */
  6514. tmpbuf_free(name, slen + 2);
  6515. return(sym);
  6516. }
  6517. static s7_pointer g_make_keyword(s7_scheme *sc, s7_pointer args)
  6518. {
  6519. /* this should be keyword, not make-keyword, but the latter is in use elsewhere, and in s7.h
  6520. * (string->)symbol is s7_make_symbol. string->symbol is redundant.
  6521. * Either use symbol/keyword/gensym, or string->symbol/string->keyword/string->gensym?
  6522. */
  6523. #define H_make_keyword "(make-keyword str) prepends ':' to str and defines that as a keyword"
  6524. #define Q_make_keyword s7_make_signature(sc, 2, sc->is_keyword_symbol, sc->is_string_symbol)
  6525. if (!is_string(car(args)))
  6526. method_or_bust(sc, car(args), sc->make_keyword_symbol, args, T_STRING, 0);
  6527. return(s7_make_keyword(sc, string_value(car(args))));
  6528. }
  6529. static s7_pointer c_make_keyword(s7_scheme *sc, s7_pointer x)
  6530. {
  6531. if (!is_string(x))
  6532. method_or_bust(sc, x, sc->make_keyword_symbol, list_1(sc, x), T_STRING, 0);
  6533. return(s7_make_keyword(sc, string_value(x)));
  6534. }
  6535. /* -------------------------------- keyword->symbol -------------------------------- */
  6536. static s7_pointer g_keyword_to_symbol(s7_scheme *sc, s7_pointer args)
  6537. {
  6538. #define H_keyword_to_symbol "(keyword->symbol key) returns a symbol with the same name as key but no prepended colon"
  6539. #define Q_keyword_to_symbol s7_make_signature(sc, 2, sc->is_symbol_symbol, sc->is_keyword_symbol)
  6540. s7_pointer sym;
  6541. sym = car(args);
  6542. if (!is_keyword(sym))
  6543. method_or_bust_with_type(sc, sym, sc->keyword_to_symbol_symbol, args, make_string_wrapper(sc, "a keyword"), 0);
  6544. return(keyword_symbol(sym));
  6545. }
  6546. static s7_pointer c_keyword_to_symbol(s7_scheme *sc, s7_pointer sym)
  6547. {
  6548. if (!is_keyword(sym))
  6549. method_or_bust_with_type(sc, sym, sc->keyword_to_symbol_symbol, list_1(sc, sym), make_string_wrapper(sc, "a keyword"), 0);
  6550. return(keyword_symbol(sym));
  6551. }
  6552. /* -------------------------------- symbol->keyword -------------------------------- */
  6553. static s7_pointer g_symbol_to_keyword(s7_scheme *sc, s7_pointer args)
  6554. {
  6555. #define H_symbol_to_keyword "(symbol->keyword sym) returns a keyword with the same name as sym, but with a colon prepended"
  6556. #define Q_symbol_to_keyword s7_make_signature(sc, 2, sc->is_keyword_symbol, sc->is_symbol_symbol)
  6557. if (!is_symbol(car(args)))
  6558. method_or_bust(sc, car(args), sc->symbol_to_keyword_symbol, args, T_SYMBOL, 0);
  6559. return(s7_make_keyword(sc, symbol_name(car(args))));
  6560. }
  6561. static s7_pointer c_symbol_to_keyword(s7_scheme *sc, s7_pointer sym)
  6562. {
  6563. if (!is_symbol(sym))
  6564. method_or_bust(sc, sym, sc->symbol_to_keyword_symbol, list_1(sc, sym), T_SYMBOL, 0);
  6565. return(s7_make_keyword(sc, symbol_name(sym)));
  6566. }
  6567. /* ---------------- uninterpreted pointers ---------------- */
  6568. bool s7_is_c_pointer(s7_pointer arg)
  6569. {
  6570. return(type(arg) == T_C_POINTER);
  6571. }
  6572. void *s7_c_pointer(s7_pointer p)
  6573. {
  6574. if ((is_number(p)) &&
  6575. (s7_integer(p) == 0))
  6576. return(NULL); /* special case where the null pointer has been cons'd up by hand */
  6577. if (type(p) != T_C_POINTER)
  6578. return(NULL);
  6579. return(raw_pointer(p));
  6580. }
  6581. s7_pointer s7_make_c_pointer(s7_scheme *sc, void *ptr)
  6582. {
  6583. s7_pointer x;
  6584. new_cell(sc, x, T_C_POINTER);
  6585. raw_pointer(x) = ptr;
  6586. return(x);
  6587. }
  6588. static s7_pointer g_is_c_pointer(s7_scheme *sc, s7_pointer args)
  6589. {
  6590. #define H_is_c_pointer "(c-pointer? obj) returns #t if obj is a C pointer being held in s7."
  6591. #define Q_is_c_pointer pl_bt
  6592. check_boolean_method(sc, s7_is_c_pointer, sc->is_c_pointer_symbol, args);
  6593. }
  6594. static s7_pointer c_c_pointer(s7_scheme *sc, s7_pointer arg)
  6595. {
  6596. ptr_int p;
  6597. if (!s7_is_integer(arg))
  6598. method_or_bust(sc, arg, sc->c_pointer_symbol, list_1(sc, arg), T_INTEGER, 1);
  6599. p = (ptr_int)s7_integer(arg); /* (c-pointer (bignum "1234")) */
  6600. return(s7_make_c_pointer(sc, (void *)p));
  6601. }
  6602. static s7_pointer g_c_pointer(s7_scheme *sc, s7_pointer args)
  6603. {
  6604. #define H_c_pointer "(c-pointer int) returns a c-pointer object."
  6605. #define Q_c_pointer s7_make_signature(sc, 2, sc->is_c_pointer_symbol, sc->is_integer_symbol)
  6606. return(c_c_pointer(sc, car(args)));
  6607. }
  6608. /* --------------------------------- rf (CLM optimizer) ----------------------------------------------- */
  6609. s7_pointer *s7_xf_start(s7_scheme *sc)
  6610. {
  6611. sc->cur_rf->cur = sc->cur_rf->data;
  6612. return(sc->cur_rf->cur);
  6613. }
  6614. static void resize_xf(s7_scheme *sc, xf_t *rc)
  6615. {
  6616. /* if we're saving pointers into this array (for later fill-in), this realloc
  6617. * means earlier (backfill) pointers are not valid, so we have to save the position to be
  6618. * filled, not the pointer to it.
  6619. */
  6620. s7_int loc;
  6621. loc = rc->cur - rc->data;
  6622. #if DEBUGGING
  6623. int i;
  6624. s7_pointer *old;
  6625. old = rc->data;
  6626. rc->data = (s7_pointer *)calloc(rc->size * 2, sizeof(s7_pointer));
  6627. for (i = 0; i < rc->size; i++)
  6628. {
  6629. rc->data[i] = old[i];
  6630. old[i] = NULL;
  6631. }
  6632. #else
  6633. rc->data = (s7_pointer *)realloc(rc->data, rc->size * 2 * sizeof(s7_pointer));
  6634. #endif
  6635. rc->cur = (s7_pointer *)(rc->data + loc);
  6636. rc->size *= 2;
  6637. rc->end = (s7_pointer *)(rc->data + rc->size);
  6638. }
  6639. #define rc_loc(sc) (ptr_int)(sc->cur_rf->cur - sc->cur_rf->data)
  6640. #define rc_go(sc, loc) (s7_pointer *)(sc->cur_rf->data + loc)
  6641. #define xf_init(N) do {rc = sc->cur_rf; if ((rc->cur + N) >= rc->end) resize_xf(sc, rc);} while (0)
  6642. #define xf_store(Val) do {(*(rc->cur)) = Val; rc->cur++;} while (0)
  6643. #define xf_save_loc(Loc) do {Loc = rc->cur - rc->data; rc->cur++;} while (0)
  6644. #define xf_save_loc2(Loc1, Loc2) do {Loc1 = rc->cur - rc->data; Loc2 = Loc1 + 1; rc->cur += 2;} while (0)
  6645. #define xf_save_loc3(Loc1, Loc2, Loc3) do {Loc1 = rc->cur - rc->data; Loc2 = Loc1 + 1; Loc3 = Loc2 + 1; rc->cur += 3;} while (0)
  6646. #define xf_store_at(Loc, Val) rc->data[Loc] = Val
  6647. #define xf_go(loc) rc->cur = (s7_pointer *)(rc->data + loc)
  6648. /* #define xf_loc() (ptr_int)(rc->cur - rc->data) */
  6649. s7_int s7_xf_store(s7_scheme *sc, s7_pointer val)
  6650. {
  6651. s7_pointer *cur;
  6652. xf_t *rc;
  6653. rc = sc->cur_rf;
  6654. if (rc->cur == rc->end)
  6655. resize_xf(sc, rc);
  6656. cur = rc->cur++;
  6657. (*cur) = val;
  6658. return(cur - rc->data);
  6659. }
  6660. void s7_xf_store_at(s7_scheme *sc, s7_int index, s7_pointer val)
  6661. {
  6662. sc->cur_rf->data[index] = val;
  6663. }
  6664. void *s7_xf_new(s7_scheme *sc, s7_pointer e)
  6665. {
  6666. xf_t *result;
  6667. if (sc->rf_free_list)
  6668. {
  6669. result = sc->rf_free_list;
  6670. sc->rf_free_list = sc->rf_free_list->next;
  6671. }
  6672. else
  6673. {
  6674. result = (xf_t *)malloc(sizeof(xf_t));
  6675. result->size = 8;
  6676. result->data = (s7_pointer *)calloc(result->size, sizeof(s7_pointer));
  6677. result->end = (s7_pointer *)(result->data + result->size);
  6678. }
  6679. if (sc->cur_rf)
  6680. {
  6681. sc->cur_rf->next = sc->rf_stack;
  6682. sc->rf_stack = sc->cur_rf;
  6683. }
  6684. sc->cur_rf = result;
  6685. result->cur = result->data;
  6686. result->e = e; /* set only here? */
  6687. result->gc_list = NULL;
  6688. return((void *)result);
  6689. }
  6690. static void s7_xf_clear(s7_scheme *sc)
  6691. {
  6692. while (sc->cur_rf) {s7_xf_free(sc);}
  6693. }
  6694. bool s7_xf_is_stepper(s7_scheme *sc, s7_pointer sym)
  6695. {
  6696. s7_pointer e, p;
  6697. e = sc->cur_rf->e;
  6698. if (!e) return(false);
  6699. for (p = let_slots(e); is_slot(p); p = next_slot(p))
  6700. if (slot_symbol(p) == sym)
  6701. return(true);
  6702. return(false);
  6703. }
  6704. static void xf_clear_list(s7_scheme *sc, xf_t *r)
  6705. {
  6706. gc_obj *p, *op;
  6707. for (p = r->gc_list; p; p = op)
  6708. {
  6709. op = p->nxt;
  6710. free(p);
  6711. }
  6712. r->gc_list = NULL;
  6713. }
  6714. void *s7_xf_detach(s7_scheme *sc)
  6715. {
  6716. xf_t *r;
  6717. r = sc->cur_rf;
  6718. sc->cur_rf = sc->rf_stack;
  6719. if (sc->rf_stack)
  6720. sc->rf_stack = sc->rf_stack->next;
  6721. return((void *)r);
  6722. }
  6723. void s7_xf_attach(s7_scheme *sc, void *ur)
  6724. {
  6725. xf_t *r = (xf_t *)ur;
  6726. r->next = sc->rf_free_list;
  6727. sc->rf_free_list = r;
  6728. xf_clear_list(sc, r);
  6729. }
  6730. s7_pointer *s7_xf_top(s7_scheme *sc, void *ur)
  6731. {
  6732. xf_t *r = (xf_t *)ur;
  6733. return(r->data);
  6734. }
  6735. static s7_pointer xf_push(s7_scheme *sc, s7_pointer obj)
  6736. {
  6737. gc_obj *p;
  6738. p = (gc_obj *)malloc(sizeof(gc_obj));
  6739. p->nxt = sc->cur_rf->gc_list;
  6740. sc->cur_rf->gc_list = p;
  6741. p->p = obj;
  6742. return(obj);
  6743. }
  6744. #if WITH_ADD_PF
  6745. static s7_pointer xf_pop(s7_scheme *sc)
  6746. {
  6747. if ((sc->cur_rf) &&
  6748. (sc->cur_rf->gc_list))
  6749. {
  6750. s7_pointer p;
  6751. gc_obj *g;
  6752. g = sc->cur_rf->gc_list;
  6753. p = g->p;
  6754. sc->cur_rf->gc_list = g->nxt;
  6755. free(g);
  6756. return(p);
  6757. }
  6758. return(NULL);
  6759. }
  6760. #endif
  6761. void s7_xf_free(s7_scheme *sc)
  6762. {
  6763. sc->cur_rf->next = sc->rf_free_list;
  6764. sc->rf_free_list = sc->cur_rf;
  6765. xf_clear_list(sc, sc->cur_rf);
  6766. sc->cur_rf = sc->rf_stack;
  6767. if (sc->rf_stack)
  6768. sc->rf_stack = sc->rf_stack->next;
  6769. }
  6770. static s7_if_t implicit_int_vector_ref(s7_scheme *sc, s7_pointer expr);
  6771. static s7_rf_t implicit_float_vector_ref(s7_scheme *sc, s7_pointer expr);
  6772. static s7_pf_t implicit_pf_sequence_ref(s7_scheme *sc, s7_pointer expr);
  6773. static s7_pf_t implicit_gf_sequence_ref(s7_scheme *sc, s7_pointer expr);
  6774. #if WITH_OPTIMIZATION
  6775. static s7_pf_t implicit_pf_sequence_set(s7_scheme *sc, s7_pointer v, s7_pointer ind, s7_pointer val);
  6776. static s7_pf_t implicit_gf_sequence_set(s7_scheme *sc, s7_pointer v, s7_pointer ind, s7_pointer val);
  6777. #endif
  6778. /* set cases are via set_if/set_rf -- but set_gp|pf would need to be restricted to non-symbol settees */
  6779. /* need to make sure sequence is not a step var, also set cases */
  6780. static s7_rp_t rf_function(s7_pointer f)
  6781. {
  6782. switch (type(f))
  6783. {
  6784. 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:
  6785. return(c_function_rp(f));
  6786. case T_FLOAT_VECTOR:
  6787. return(implicit_float_vector_ref);
  6788. case T_C_OBJECT:
  6789. return(c_object_rp(f));
  6790. case T_SYNTAX:
  6791. return(syntax_rp(f));
  6792. }
  6793. return(NULL);
  6794. }
  6795. static s7_ip_t if_function(s7_pointer f)
  6796. {
  6797. switch (type(f))
  6798. {
  6799. 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:
  6800. return(c_function_ip(f));
  6801. case T_INT_VECTOR:
  6802. return(implicit_int_vector_ref);
  6803. case T_C_OBJECT:
  6804. return(c_object_ip(f));
  6805. case T_SYNTAX:
  6806. return(syntax_ip(f));
  6807. }
  6808. return(NULL);
  6809. }
  6810. static s7_pp_t pf_function(s7_pointer f)
  6811. {
  6812. switch (type(f))
  6813. {
  6814. 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:
  6815. return(c_function_pp(f));
  6816. case T_PAIR: case T_STRING: case T_VECTOR: case T_HASH_TABLE: case T_LET:
  6817. return(implicit_pf_sequence_ref);
  6818. case T_SYNTAX:
  6819. return(syntax_pp(f));
  6820. }
  6821. return(NULL);
  6822. }
  6823. static s7_pp_t gf_function(s7_pointer f)
  6824. {
  6825. switch (type(f))
  6826. {
  6827. 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:
  6828. return(c_function_gp(f));
  6829. case T_PAIR: case T_STRING: case T_VECTOR: case T_HASH_TABLE: case T_LET: case T_C_OBJECT: case T_INT_VECTOR: case T_FLOAT_VECTOR:
  6830. return(implicit_gf_sequence_ref);
  6831. }
  6832. return(NULL);
  6833. }
  6834. s7_rp_t s7_rf_function(s7_scheme *sc, s7_pointer func) {return(rf_function(func));}
  6835. s7_ip_t s7_if_function(s7_scheme *sc, s7_pointer func) {return(if_function(func));}
  6836. s7_pp_t s7_pf_function(s7_scheme *sc, s7_pointer func) {return(pf_function(func));}
  6837. s7_pp_t s7_gf_function(s7_scheme *sc, s7_pointer func) {return(gf_function(func));}
  6838. void s7_rf_set_function(s7_pointer f, s7_rp_t rp)
  6839. {
  6840. #if WITH_OPTIMIZATION
  6841. if (!is_c_function(f)) return;
  6842. c_function_rp(f) = rp;
  6843. #else
  6844. return;
  6845. #endif
  6846. }
  6847. void s7_if_set_function(s7_pointer f, s7_ip_t ip)
  6848. {
  6849. #if WITH_OPTIMIZATION
  6850. if (!is_c_function(f)) return;
  6851. c_function_ip(f) = ip;
  6852. #else
  6853. return;
  6854. #endif
  6855. }
  6856. void s7_pf_set_function(s7_pointer f, s7_pp_t pp)
  6857. {
  6858. #if WITH_OPTIMIZATION
  6859. if (!is_c_function(f)) return;
  6860. c_function_pp(f) = pp;
  6861. #else
  6862. return;
  6863. #endif
  6864. }
  6865. void s7_gf_set_function(s7_pointer f, s7_pp_t gp)
  6866. {
  6867. #if WITH_OPTIMIZATION
  6868. if (!is_c_function(f)) return;
  6869. c_function_gp(f) = gp;
  6870. #else
  6871. return;
  6872. #endif
  6873. }
  6874. static s7_rp_t pair_to_rp(s7_scheme *sc, s7_pointer expr)
  6875. {
  6876. s7_pointer val_sym, val;
  6877. val_sym = car(expr);
  6878. if (!s7_is_symbol(val_sym)) return(NULL);
  6879. if (s7_local_slot(sc, val_sym)) return(NULL);
  6880. val = s7_symbol_value(sc, val_sym);
  6881. return(s7_rf_function(sc, val));
  6882. }
  6883. static s7_ip_t pair_to_ip(s7_scheme *sc, s7_pointer expr)
  6884. {
  6885. s7_pointer val_sym, val;
  6886. val_sym = car(expr);
  6887. if (!s7_is_symbol(val_sym)) return(NULL);
  6888. if (s7_local_slot(sc, val_sym)) return(NULL);
  6889. val = s7_symbol_value(sc, val_sym);
  6890. return(s7_if_function(sc, val));
  6891. }
  6892. static s7_pp_t pair_to_pp(s7_scheme *sc, s7_pointer expr)
  6893. {
  6894. s7_pointer val_sym, val;
  6895. val_sym = car(expr);
  6896. if (!s7_is_symbol(val_sym)) return(NULL);
  6897. if (s7_local_slot(sc, val_sym)) return(NULL);
  6898. val = s7_symbol_value(sc, val_sym);
  6899. return(s7_pf_function(sc, val));
  6900. }
  6901. static s7_pp_t pair_to_gp(s7_scheme *sc, s7_pointer expr)
  6902. {
  6903. s7_pointer val_sym, val;
  6904. val_sym = car(expr);
  6905. if (!s7_is_symbol(val_sym)) return(NULL);
  6906. if (s7_local_slot(sc, val_sym)) return(NULL);
  6907. val = s7_symbol_value(sc, val_sym);
  6908. return(s7_gf_function(sc, val));
  6909. }
  6910. static s7_pf_t xf_opt(s7_scheme *sc, s7_pointer lp)
  6911. {
  6912. s7_int loc;
  6913. s7_pointer f;
  6914. s7_rp_t rp;
  6915. s7_ip_t xp;
  6916. s7_pp_t pp;
  6917. xf_t *rc;
  6918. f = find_symbol(sc, car(lp));
  6919. if (!is_slot(f)) return(NULL);
  6920. f = slot_value(f);
  6921. xf_init(3);
  6922. xf_save_loc(loc);
  6923. xp = if_function(f);
  6924. if (xp)
  6925. {
  6926. s7_if_t xf;
  6927. xf = xp(sc, lp);
  6928. if (xf)
  6929. {
  6930. xf_store_at(loc, (s7_pointer)xf);
  6931. return((s7_pf_t)xf);
  6932. }
  6933. xf_go(loc + 1);
  6934. }
  6935. rp = rf_function(f);
  6936. if (rp)
  6937. {
  6938. s7_rf_t rf;
  6939. rf = rp(sc, lp);
  6940. if (rf)
  6941. {
  6942. xf_store_at(loc, (s7_pointer)rf);
  6943. return((s7_pf_t)rf);
  6944. }
  6945. xf_go(loc + 1);
  6946. }
  6947. pp = pf_function(f);
  6948. if (pp)
  6949. {
  6950. s7_pf_t pf;
  6951. pf = pp(sc, lp);
  6952. if (pf)
  6953. {
  6954. xf_store_at(loc, (s7_pointer)pf);
  6955. return(pf);
  6956. }
  6957. xf_go(loc + 1);
  6958. }
  6959. pp = gf_function(f);
  6960. if (pp)
  6961. {
  6962. s7_pf_t pf;
  6963. pf = pp(sc, lp);
  6964. if (pf)
  6965. {
  6966. xf_store_at(loc, (s7_pointer)pf);
  6967. return(pf);
  6968. }
  6969. }
  6970. return(NULL);
  6971. }
  6972. #if 0
  6973. static s7_pointer if_to_pf(s7_scheme *sc, s7_pointer **p)
  6974. {
  6975. s7_if_t xf;
  6976. s7_int x;
  6977. xf = (s7_if_t)(**p); (*p)++;
  6978. x = xf(sc, p);
  6979. return(make_integer(sc, x));
  6980. }
  6981. static s7_pointer rf_to_pf(s7_scheme *sc, s7_pointer **p)
  6982. {
  6983. s7_rf_t rf;
  6984. s7_double x;
  6985. rf = (s7_rf_t)(**p); (*p)++;
  6986. x = rf(sc, p);
  6987. return(make_real(sc, x));
  6988. }
  6989. static s7_pf_t pf_opt(s7_scheme *sc, s7_pointer lp)
  6990. {
  6991. s7_int loc, loc1;
  6992. s7_pointer f;
  6993. s7_rp_t rp;
  6994. s7_ip_t xp;
  6995. s7_pp_t pp;
  6996. xf_t *rc;
  6997. f = find_symbol(sc, car(lp));
  6998. if (!is_slot(f)) return(NULL);
  6999. f = slot_value(f);
  7000. xf_init(3);
  7001. xf_save_loc(loc);
  7002. xp = if_function(f);
  7003. if (xp)
  7004. {
  7005. s7_if_t xf;
  7006. xf_save_loc(loc1);
  7007. xf = xp(sc, lp);
  7008. if (xf)
  7009. {
  7010. xf_store_at(loc, (s7_pointer)if_to_pf);
  7011. xf_store_at(loc1, (s7_pointer)xf);
  7012. return((s7_pf_t)if_to_pf);
  7013. }
  7014. xf_go(loc + 1);
  7015. }
  7016. rp = rf_function(f);
  7017. if (rp)
  7018. {
  7019. s7_rf_t rf;
  7020. xf_save_loc(loc1);
  7021. rf = rp(sc, lp);
  7022. if (rf)
  7023. {
  7024. xf_store_at(loc, (s7_pointer)rf_to_pf);
  7025. xf_store_at(loc1, (s7_pointer)rf);
  7026. return((s7_pf_t)rf_to_pf);
  7027. }
  7028. xf_go(loc + 1);
  7029. }
  7030. pp = pf_function(f);
  7031. if (pp)
  7032. {
  7033. s7_pf_t pf;
  7034. pf = pp(sc, lp);
  7035. if (pf)
  7036. {
  7037. xf_store_at(loc, (s7_pointer)pf);
  7038. return(pf);
  7039. }
  7040. }
  7041. return(NULL);
  7042. }
  7043. #endif
  7044. static s7_double rf_c(s7_scheme *sc, s7_pointer **p)
  7045. {
  7046. s7_double x;
  7047. x = s7_number_to_real(sc, **p); (*p)++;
  7048. return(x);
  7049. }
  7050. static s7_double rf_s(s7_scheme *sc, s7_pointer **p)
  7051. {
  7052. s7_double x;
  7053. x = s7_number_to_real(sc, slot_value(**p)); (*p)++;
  7054. return(x);
  7055. }
  7056. static bool arg_to_rf(s7_scheme *sc, s7_pointer a1, s7_int in_loc)
  7057. {
  7058. s7_int loc;
  7059. xf_t *rc;
  7060. xf_init(2);
  7061. if (in_loc == -1)
  7062. xf_save_loc(loc);
  7063. else loc = in_loc;
  7064. if (is_pair(a1))
  7065. {
  7066. s7_rp_t rp;
  7067. s7_rf_t rf;
  7068. rp = pair_to_rp(sc, a1);
  7069. if (!rp) return(false);
  7070. rf = rp(sc, a1);
  7071. if (!rf) return(false);
  7072. xf_store_at(loc, (s7_pointer)rf);
  7073. return(true);
  7074. }
  7075. if (is_symbol(a1))
  7076. {
  7077. s7_pointer slot;
  7078. slot = s7_slot(sc, a1);
  7079. if ((is_slot(slot)) &&
  7080. (is_real(slot_value(slot))))
  7081. {
  7082. xf_store(slot);
  7083. xf_store_at(loc, (s7_pointer)rf_s);
  7084. return(true);
  7085. }
  7086. return(false);
  7087. }
  7088. if (is_real(a1))
  7089. {
  7090. xf_store(a1);
  7091. xf_store_at(loc, (s7_pointer)rf_c);
  7092. return(true);
  7093. }
  7094. return(false);
  7095. }
  7096. bool s7_arg_to_rf(s7_scheme *sc, s7_pointer a1)
  7097. {
  7098. return(arg_to_rf(sc, a1, -1));
  7099. }
  7100. static s7_int if_c(s7_scheme *sc, s7_pointer **p)
  7101. {
  7102. s7_pointer i;
  7103. i = **p; (*p)++;
  7104. return(integer(i));
  7105. }
  7106. static s7_int if_s(s7_scheme *sc, s7_pointer **p)
  7107. {
  7108. s7_pointer x;
  7109. x = slot_value(**p); (*p)++;
  7110. if (!is_integer(x)) s7_wrong_type_arg_error(sc, "", 0, x, "an integer");
  7111. return(integer(x));
  7112. }
  7113. static bool arg_to_if(s7_scheme *sc, s7_pointer a1, s7_int in_loc)
  7114. {
  7115. s7_int loc;
  7116. xf_t *rc;
  7117. xf_init(2);
  7118. if (in_loc == -1)
  7119. xf_save_loc(loc);
  7120. else loc = in_loc;
  7121. if (is_pair(a1))
  7122. {
  7123. s7_ip_t ip;
  7124. s7_if_t xf;
  7125. ip = pair_to_ip(sc, a1);
  7126. if (!ip) return(false);
  7127. xf = ip(sc, a1);
  7128. if (!xf) return(false);
  7129. xf_store_at(loc, (s7_pointer)xf);
  7130. return(true);
  7131. }
  7132. if (is_symbol(a1))
  7133. {
  7134. s7_pointer slot;
  7135. slot = s7_slot(sc, a1);
  7136. if ((is_slot(slot)) &&
  7137. (is_integer(slot_value(slot))))
  7138. {
  7139. xf_store(slot);
  7140. xf_store_at(loc, (s7_pointer)if_s);
  7141. return(true);
  7142. }
  7143. return(false);
  7144. }
  7145. if (is_integer(a1))
  7146. {
  7147. xf_store(a1);
  7148. xf_store_at(loc, (s7_pointer)if_c);
  7149. return(true);
  7150. }
  7151. return(false);
  7152. }
  7153. bool s7_arg_to_if(s7_scheme *sc, s7_pointer a1)
  7154. {
  7155. return(arg_to_if(sc, a1, -1));
  7156. }
  7157. static s7_pointer pf_c(s7_scheme *sc, s7_pointer **p)
  7158. {
  7159. s7_pointer x;
  7160. x = **p; (*p)++;
  7161. return(x);
  7162. }
  7163. static s7_pointer pf_s(s7_scheme *sc, s7_pointer **p)
  7164. {
  7165. s7_pointer x;
  7166. x = slot_value(**p); (*p)++;
  7167. return(x);
  7168. }
  7169. static bool arg_to_pf(s7_scheme *sc, s7_pointer a1, s7_int in_loc)
  7170. {
  7171. s7_int loc;
  7172. xf_t *rc;
  7173. xf_init(2);
  7174. if (in_loc == -1)
  7175. xf_save_loc(loc);
  7176. else loc = in_loc;
  7177. if (is_pair(a1))
  7178. {
  7179. s7_pp_t pp;
  7180. s7_pf_t pf;
  7181. pp = pair_to_pp(sc, a1);
  7182. if (!pp) return(false);
  7183. pf = pp(sc, a1);
  7184. if (!pf) return(false);
  7185. xf_store_at(loc, (s7_pointer)pf);
  7186. return(true);
  7187. }
  7188. if (is_symbol(a1))
  7189. {
  7190. s7_pointer slot;
  7191. slot = s7_slot(sc, a1);
  7192. if (is_slot(slot))
  7193. {
  7194. xf_store(slot);
  7195. xf_store_at(loc, (s7_pointer)pf_s);
  7196. return(true);
  7197. }
  7198. return(false);
  7199. }
  7200. xf_store(a1);
  7201. xf_store_at(loc, (s7_pointer)pf_c);
  7202. return(true);
  7203. }
  7204. bool s7_arg_to_pf(s7_scheme *sc, s7_pointer a1)
  7205. {
  7206. return(arg_to_pf(sc, a1, -1));
  7207. }
  7208. static bool arg_to_gf(s7_scheme *sc, s7_pointer a1, s7_int in_loc)
  7209. {
  7210. if (is_pair(a1))
  7211. {
  7212. s7_pp_t gp;
  7213. gp = pair_to_gp(sc, a1);
  7214. if (gp)
  7215. {
  7216. xf_t *rc;
  7217. s7_pf_t gf;
  7218. s7_int loc;
  7219. xf_init(1);
  7220. if (in_loc == -1)
  7221. xf_save_loc(loc);
  7222. else loc = in_loc;
  7223. gf = gp(sc, a1);
  7224. if (gf)
  7225. {
  7226. xf_store_at(loc, (s7_pointer)gf);
  7227. return(true);
  7228. }
  7229. }
  7230. }
  7231. return(false);
  7232. }
  7233. bool s7_arg_to_gf(s7_scheme *sc, s7_pointer a1)
  7234. {
  7235. return(arg_to_gf(sc, a1, -1));
  7236. }
  7237. static s7_rf_t pair_to_rf(s7_scheme *sc, s7_pointer a1, s7_rf_t x)
  7238. {
  7239. if (s7_arg_to_rf(sc, a1))
  7240. return(x);
  7241. return(NULL);
  7242. }
  7243. static s7_rf_t pair_to_rf_via_if(s7_scheme *sc, s7_pointer a1, s7_rf_t x)
  7244. {
  7245. if (s7_arg_to_if(sc, a1))
  7246. return(x);
  7247. return(NULL);
  7248. }
  7249. s7_rf_t s7_rf_1(s7_scheme *sc, s7_pointer expr, s7_rf_t r, s7_rf_t s, s7_rf_t x)
  7250. {
  7251. s7_pointer a1;
  7252. xf_t *rc;
  7253. if ((is_null(cdr(expr))) || (!is_null(cddr(expr)))) return(NULL);
  7254. a1 = cadr(expr);
  7255. xf_init(1);
  7256. if (is_real(a1))
  7257. {
  7258. xf_store(a1);
  7259. return(r);
  7260. }
  7261. if (is_symbol(a1))
  7262. {
  7263. a1 = s7_slot(sc, a1);
  7264. if ((!is_slot(a1)) || (is_t_complex(slot_value(a1)))) return(NULL);
  7265. xf_store(a1);
  7266. return(s);
  7267. }
  7268. if (is_pair(a1))
  7269. return(pair_to_rf(sc, a1, x));
  7270. return(NULL);
  7271. }
  7272. s7_rf_t s7_rf_2(s7_scheme *sc, s7_pointer expr, s7_rf_t rr, s7_rf_t sr, s7_rf_t xr, s7_rf_t rs, s7_rf_t ss, s7_rf_t xs, s7_rf_t rx, s7_rf_t sx, s7_rf_t xx)
  7273. {
  7274. s7_pointer a1, a2;
  7275. xf_t *rc;
  7276. if ((is_null(cdr(expr))) || (!is_null(cdddr(expr)))) return(NULL);
  7277. a1 = cadr(expr);
  7278. a2 = caddr(expr);
  7279. xf_init(2);
  7280. if (is_real(a1))
  7281. {
  7282. xf_store(a1);
  7283. if (is_real(a2))
  7284. {
  7285. xf_store(a2);
  7286. return(rr);
  7287. }
  7288. if (is_symbol(a2))
  7289. {
  7290. a2 = s7_slot(sc, a2);
  7291. if ((!is_slot(a2)) || (is_t_complex(slot_value(a2)))) return(NULL);
  7292. xf_store(a2);
  7293. return(rs);
  7294. }
  7295. if (is_pair(a2))
  7296. return(pair_to_rf(sc, a2, rx));
  7297. return(NULL);
  7298. }
  7299. if (is_symbol(a1))
  7300. {
  7301. a1 = s7_slot(sc, a1);
  7302. if ((!is_slot(a1)) || (is_t_complex(slot_value(a1)))) return(NULL);
  7303. xf_store(a1);
  7304. if (is_real(a2))
  7305. {
  7306. xf_store(a2);
  7307. return(sr);
  7308. }
  7309. if (is_symbol(a2))
  7310. {
  7311. a2 = s7_slot(sc, a2);
  7312. if ((!is_slot(a2)) || (is_t_complex(slot_value(a2)))) return(NULL);
  7313. xf_store(a2);
  7314. return(ss);
  7315. }
  7316. if (is_pair(a2))
  7317. return(pair_to_rf(sc, a2, sx));
  7318. return(NULL);
  7319. }
  7320. if (is_pair(a1))
  7321. {
  7322. s7_int loc;
  7323. s7_rp_t rp;
  7324. s7_rf_t rf;
  7325. xf_save_loc(loc);
  7326. rp = pair_to_rp(sc, a1);
  7327. if (!rp) return(NULL);
  7328. rf = rp(sc, a1);
  7329. if (!rf) return(NULL);
  7330. xf_store_at(loc, (s7_pointer)rf);
  7331. if (is_real(a2))
  7332. {
  7333. xf_store(a2);
  7334. return(xr);
  7335. }
  7336. if (is_symbol(a2))
  7337. {
  7338. a2 = s7_slot(sc, a2);
  7339. if ((!is_slot(a2)) || (is_t_complex(slot_value(a2)))) return(NULL);
  7340. xf_store(a2);
  7341. return(xs);
  7342. }
  7343. if (is_pair(a2))
  7344. return(pair_to_rf(sc, a2, xx));
  7345. return(NULL);
  7346. }
  7347. return(NULL);
  7348. }
  7349. #if (!WITH_GMP)
  7350. typedef struct {s7_rf_t none, r, s, p, rs, rp, ss, sp, pp, rss, rsp, rpp, sss, ssp, spp, ppp;} rf_ops;
  7351. static rf_ops *add_r_ops, *multiply_r_ops;
  7352. static s7_rf_t com_rf_2(s7_scheme *sc, s7_pointer expr, rf_ops *a)
  7353. {
  7354. /* expr len is assumed to be 3 (2 args) */
  7355. s7_pointer a1, a2, p1 = NULL, p2 = NULL, s1 = NULL, s2 = NULL, c1 = NULL, c2 = NULL;
  7356. xf_t *rc;
  7357. a1 = cadr(expr);
  7358. if (is_pair(a1)) p1 = a1; else {if (is_symbol(a1)) s1 = a1; else {if (is_real(a1)) c1 = a1; else return(NULL);}}
  7359. a2 = caddr(expr);
  7360. if (is_pair(a2)) p2 = a2; else {if (is_symbol(a2)) s2 = a2; else {if (is_real(a2)) c2 = a2; else return(NULL);}}
  7361. xf_init(2);
  7362. if (!c1) {c1 = c2; c2 = NULL;}
  7363. if (c2)
  7364. {
  7365. if ((is_t_real(c1)) || (is_t_real(c2)))
  7366. {
  7367. s7_pointer x;
  7368. s7_double x1, x2;
  7369. x1 = real_to_double(sc, c1, (a == add_r_ops) ? "+" : "*");
  7370. x2 = real_to_double(sc, c2, (a == add_r_ops) ? "+" : "*");
  7371. if (a == add_r_ops)
  7372. x = make_real(sc, x1 + x2);
  7373. else x = make_real(sc, x1 * x2);
  7374. if (!is_immutable_real(x))
  7375. xf_push(sc, x);
  7376. xf_store(x);
  7377. return(a->r);
  7378. }
  7379. return(NULL);
  7380. }
  7381. if (!s1) {s1 = s2; s2 = NULL;}
  7382. if (!p1) {p1 = p2; p2 = NULL;}
  7383. if (s1)
  7384. {
  7385. bool s1_real;
  7386. s1 = s7_slot(sc, s1);
  7387. if ((!is_slot(s1)) || (is_unsafe_stepper(s1)) || (is_t_complex(slot_value(s1)))) return(NULL);
  7388. s1_real = (is_t_real(slot_value(s1)));
  7389. xf_store(s1);
  7390. if (s2)
  7391. {
  7392. s2 = s7_slot(sc, s2);
  7393. if ((!is_slot(s2)) || (is_unsafe_stepper(s2)) || (is_t_complex(slot_value(s2)))) return(NULL);
  7394. if ((s1_real) || /* TODO: look at step etc */
  7395. (is_t_real(slot_value(s2))))
  7396. {
  7397. xf_store(s2);
  7398. return(a->ss);
  7399. }
  7400. return(NULL);
  7401. }
  7402. if (c1)
  7403. {
  7404. if ((s1_real) || (is_t_real(c1)))
  7405. {
  7406. xf_store(c1);
  7407. return(a->rs);
  7408. }
  7409. return(NULL);
  7410. }
  7411. if (s7_arg_to_rf(sc, p1))
  7412. return(a->sp);
  7413. return(NULL);
  7414. }
  7415. /* must be p1 here, c1 or p2 */
  7416. if (c1)
  7417. {
  7418. xf_store(c1);
  7419. if (s7_arg_to_rf(sc, p1))
  7420. return(a->rp);
  7421. return(NULL);
  7422. }
  7423. if ((s7_arg_to_rf(sc, p1)) &&
  7424. (s7_arg_to_rf(sc, p2)))
  7425. return(a->pp);
  7426. return(NULL);
  7427. }
  7428. static s7_rf_t com_rf_3(s7_scheme *sc, s7_pointer expr, rf_ops *a)
  7429. {
  7430. /* expr len is assumed to be 4 (3 args) */
  7431. s7_pointer a1, a2, a3, p1 = NULL, p2 = NULL, p3 = NULL, s1 = NULL, s2 = NULL, s3 = NULL, c1 = NULL, c2 = NULL, c3 = NULL;
  7432. bool s1_real = false;
  7433. xf_t *rc;
  7434. a1 = cadr(expr);
  7435. if (is_pair(a1)) p1 = a1; else {if (is_symbol(a1)) s1 = a1; else {if (is_real(a1)) c1 = a1; else return(NULL);}}
  7436. a2 = caddr(expr);
  7437. if (is_pair(a2)) p2 = a2; else {if (is_symbol(a2)) s2 = a2; else {if (is_real(a2)) c2 = a2; else return(NULL);}}
  7438. a3 = cadddr(expr);
  7439. if (is_pair(a3)) p3 = a3; else {if (is_symbol(a3)) s3 = a3; else {if (is_real(a3)) c3 = a3; else return(NULL);}}
  7440. if (!s2) {s2 = s3; s3 = NULL;}
  7441. if (!s1) {s1 = s2; s2 = s3; s3 = NULL;}
  7442. xf_init(3);
  7443. if (s1)
  7444. {
  7445. s1 = s7_slot(sc, s1);
  7446. if ((!is_slot(s1)) || (is_unsafe_stepper(s1)) || (is_t_complex(slot_value(s1)))) return(NULL);
  7447. s1_real = (is_t_real(slot_value(s1)));
  7448. xf_store(s1);
  7449. }
  7450. if (!p2) {p2 = p3; p3 = NULL;}
  7451. if (!p1) {p1 = p2; p2 = p3; p3 = NULL;}
  7452. if (!c2) {c2 = c3; c3 = NULL;}
  7453. if (!c1) {c1 = c2; c2 = c3; c3 = NULL;}
  7454. if (c2)
  7455. {
  7456. if ((is_t_real(c1)) || (is_t_real(c2)) || ((c3) && (is_t_real(c3))))
  7457. {
  7458. s7_pointer x;
  7459. s7_double x1, x2, x3;
  7460. x1 = real_to_double(sc, c1, (a == add_r_ops) ? "+" : "*");
  7461. x2 = real_to_double(sc, c2, (a == add_r_ops) ? "+" : "*");
  7462. if (c3) x3 = real_to_double(sc, c3, (a == add_r_ops) ? "+" : "*"); else x3 = ((a == add_r_ops) ? 0.0 : 1.0);
  7463. if (a == add_r_ops)
  7464. x = make_real(sc, x1 + x2 + x3);
  7465. else x = make_real(sc, x1 * x2 * x3);
  7466. if (!is_immutable_real(x))
  7467. xf_push(sc, x);
  7468. xf_store(x);
  7469. if (c3) return(a->r);
  7470. if (s1) return(a->rs);
  7471. if (s7_arg_to_rf(sc, p1))
  7472. return(a->rp);
  7473. }
  7474. return(NULL);
  7475. }
  7476. if (s1)
  7477. {
  7478. if (s2)
  7479. {
  7480. bool s2_real;
  7481. s2 = s7_slot(sc, s2);
  7482. if ((!is_slot(s2)) || (is_unsafe_stepper(s2)) || (is_t_complex(slot_value(s2)))) return(NULL);
  7483. s2_real = (is_t_real(slot_value(s2)));
  7484. xf_store(s2);
  7485. if (s3)
  7486. {
  7487. s3 = s7_slot(sc, s3);
  7488. if ((!is_slot(s3)) || (is_unsafe_stepper(s3)) || (is_t_complex(slot_value(s3)))) return(NULL);
  7489. if ((s1_real) || (s2_real) || (is_t_real(slot_value(s3))))
  7490. {
  7491. xf_store(s3);
  7492. return(a->sss);
  7493. }
  7494. return(NULL);
  7495. }
  7496. if (c1)
  7497. {
  7498. if ((s1_real) || (s2_real) || (is_t_real(c1)))
  7499. {
  7500. xf_store(c1);
  7501. return(a->rss);
  7502. }
  7503. return(NULL);
  7504. }
  7505. if (s7_arg_to_rf(sc, p1))
  7506. return(a->ssp);
  7507. return(NULL);
  7508. }
  7509. if (c1)
  7510. {
  7511. xf_store(c1);
  7512. if (s7_arg_to_rf(sc, p1))
  7513. return(a->rsp);
  7514. return(NULL);
  7515. }
  7516. if ((s7_arg_to_rf(sc, p1)) &&
  7517. (s7_arg_to_rf(sc, p2)))
  7518. return(a->spp);
  7519. return(NULL);
  7520. }
  7521. if (c1)
  7522. {
  7523. xf_store(c1);
  7524. if ((s7_arg_to_rf(sc, p1)) &&
  7525. (s7_arg_to_rf(sc, p2)))
  7526. return(a->rpp);
  7527. return(NULL);
  7528. }
  7529. if ((s7_arg_to_rf(sc, p1)) &&
  7530. (s7_arg_to_rf(sc, p2)) &&
  7531. (s7_arg_to_rf(sc, p3)))
  7532. return(a->ppp);
  7533. return(NULL);
  7534. }
  7535. typedef struct {s7_if_t none, r, s, p, rs, rp, ss, sp, pp, rss, rsp, rpp, sss, ssp, spp, ppp;} if_ops;
  7536. static if_ops *add_i_ops, *multiply_i_ops;
  7537. static s7_if_t com_if_2(s7_scheme *sc, s7_pointer expr, if_ops *a)
  7538. {
  7539. /* expr len is assumed to be 3 (2 args) */
  7540. s7_pointer a1, a2, p1 = NULL, p2 = NULL, s1 = NULL, s2 = NULL, c1 = NULL, c2 = NULL;
  7541. xf_t *rc;
  7542. a1 = cadr(expr);
  7543. if (is_pair(a1)) p1 = a1; else {if (is_symbol(a1)) s1 = a1; else {if (is_real(a1)) c1 = a1; else return(NULL);}}
  7544. a2 = caddr(expr);
  7545. if (is_pair(a2)) p2 = a2; else {if (is_symbol(a2)) s2 = a2; else {if (is_real(a2)) c2 = a2; else return(NULL);}}
  7546. xf_init(2);
  7547. if (!c1) {c1 = c2; c2 = NULL;}
  7548. if ((c1) && (!is_t_integer(c1))) return(NULL);
  7549. if (c2)
  7550. {
  7551. s7_pointer x;
  7552. if (!(is_t_integer(c2))) return(NULL);
  7553. if (a == add_i_ops)
  7554. x = make_integer(sc, integer(c1) + integer(c2));
  7555. else x = make_integer(sc, integer(c1) * integer(c2));
  7556. if (!is_immutable_integer(x))
  7557. xf_push(sc, x);
  7558. xf_store(x);
  7559. return(a->r);
  7560. }
  7561. if (!s1) {s1 = s2; s2 = NULL;}
  7562. if (!p1) {p1 = p2; p2 = NULL;}
  7563. if (s1)
  7564. {
  7565. s1 = s7_slot(sc, s1);
  7566. if ((!is_slot(s1)) || (is_unsafe_stepper(s1)) || (!is_t_integer(slot_value(s1)))) return(NULL);
  7567. xf_store(s1);
  7568. if (s2)
  7569. {
  7570. s2 = s7_slot(sc, s2);
  7571. if ((!is_slot(s2)) || (is_unsafe_stepper(s2)) || (!is_t_integer(slot_value(s2)))) return(NULL);
  7572. xf_store(s2);
  7573. return(a->ss);
  7574. }
  7575. if (c1)
  7576. {
  7577. xf_store(c1);
  7578. return(a->rs);
  7579. }
  7580. if (s7_arg_to_if(sc, p1))
  7581. return(a->sp);
  7582. return(NULL);
  7583. }
  7584. /* must be p1 here, c1 or p2 */
  7585. if (c1)
  7586. {
  7587. xf_store(c1);
  7588. if (s7_arg_to_if(sc, p1))
  7589. return(a->rp);
  7590. return(NULL);
  7591. }
  7592. if ((s7_arg_to_if(sc, p1)) &&
  7593. (s7_arg_to_if(sc, p2)))
  7594. return(a->pp);
  7595. return(NULL);
  7596. }
  7597. static s7_if_t com_if_3(s7_scheme *sc, s7_pointer expr, if_ops *a)
  7598. {
  7599. /* expr len is assumed to be 4 (3 args) */
  7600. s7_pointer a1, a2, a3, p1 = NULL, p2 = NULL, p3 = NULL, s1 = NULL, s2 = NULL, s3 = NULL, c1 = NULL, c2 = NULL, c3 = NULL;
  7601. xf_t *rc;
  7602. a1 = cadr(expr);
  7603. if (is_pair(a1)) p1 = a1; else {if (is_symbol(a1)) s1 = a1; else {if (is_real(a1)) c1 = a1; else return(NULL);}}
  7604. a2 = caddr(expr);
  7605. if (is_pair(a2)) p2 = a2; else {if (is_symbol(a2)) s2 = a2; else {if (is_real(a2)) c2 = a2; else return(NULL);}}
  7606. a3 = cadddr(expr);
  7607. if (is_pair(a3)) p3 = a3; else {if (is_symbol(a3)) s3 = a3; else {if (is_real(a3)) c3 = a3; else return(NULL);}}
  7608. xf_init(3);
  7609. if (!s2) {s2 = s3; s3 = NULL;}
  7610. if (!s1) {s1 = s2; s2 = s3; s3 = NULL;}
  7611. if (s1)
  7612. {
  7613. s1 = s7_slot(sc, s1);
  7614. if ((!is_slot(s1)) || (is_unsafe_stepper(s1)) || (!is_t_integer(slot_value(s1)))) return(NULL);
  7615. xf_store(s1);
  7616. }
  7617. if (!p2) {p2 = p3; p3 = NULL;}
  7618. if (!p1) {p1 = p2; p2 = p3; p3 = NULL;}
  7619. if (!c2) {c2 = c3; c3 = NULL;}
  7620. if (!c1) {c1 = c2; c2 = c3; c3 = NULL;}
  7621. if (c1)
  7622. {
  7623. if (!is_t_integer(c1)) return(NULL);
  7624. if (c2)
  7625. {
  7626. s7_pointer x;
  7627. if (!is_t_integer(c2)) return(NULL);
  7628. if ((c3) && (!is_t_integer(c3))) return(NULL);
  7629. if (a == add_i_ops)
  7630. x = make_integer(sc, integer(c1) + integer(c2) + ((c3) ? integer(c3) : 0));
  7631. else x = make_integer(sc, integer(c1) * integer(c2) * ((c3) ? integer(c3) : 1));
  7632. if (!is_immutable_integer(x))
  7633. xf_push(sc, x);
  7634. xf_store(x);
  7635. if (c3) return(a->r);
  7636. if (s1) return(a->rs);
  7637. if (s7_arg_to_if(sc, p1))
  7638. return(a->rp);
  7639. }
  7640. return(NULL);
  7641. }
  7642. if (s1)
  7643. {
  7644. if (s2)
  7645. {
  7646. s2 = s7_slot(sc, s2);
  7647. if ((!is_slot(s2)) || (is_unsafe_stepper(s2)) || (!is_t_integer(slot_value(s2)))) return(NULL);
  7648. xf_store(s2);
  7649. if (s3)
  7650. {
  7651. s3 = s7_slot(sc, s3);
  7652. if ((!is_slot(s3)) || (is_unsafe_stepper(s3)) || (!is_t_integer(slot_value(s3)))) return(NULL);
  7653. xf_store(s3);
  7654. return(a->sss);
  7655. }
  7656. if (c1)
  7657. {
  7658. xf_store(c1);
  7659. return(a->rss);
  7660. }
  7661. if (s7_arg_to_if(sc, p1))
  7662. return(a->ssp);
  7663. return(NULL);
  7664. }
  7665. if (c1)
  7666. {
  7667. xf_store(c1);
  7668. if (s7_arg_to_if(sc, p1))
  7669. return(a->rsp);
  7670. return(NULL);
  7671. }
  7672. if ((s7_arg_to_if(sc, p1)) &&
  7673. (s7_arg_to_if(sc, p2)))
  7674. return(a->spp);
  7675. return(NULL);
  7676. }
  7677. if (c1)
  7678. {
  7679. xf_store(c1);
  7680. if ((s7_arg_to_if(sc, p1)) &&
  7681. (s7_arg_to_if(sc, p2)))
  7682. return(a->rpp);
  7683. return(NULL);
  7684. }
  7685. if ((s7_arg_to_if(sc, p1)) &&
  7686. (s7_arg_to_if(sc, p2)) &&
  7687. (s7_arg_to_if(sc, p3)))
  7688. return(a->ppp);
  7689. return(NULL);
  7690. }
  7691. #endif
  7692. #if WITH_OPTIMIZATION
  7693. static s7_double set_rf_sr(s7_scheme *sc, s7_pointer **p)
  7694. {
  7695. s7_pointer s1, c1;
  7696. s7_double x;
  7697. s1 = (**p); (*p)++;
  7698. c1 = (**p); (*p)++;
  7699. x = real(c1);
  7700. slot_set_value(s1, make_real(sc, x));
  7701. return(x);
  7702. }
  7703. #if 0
  7704. static s7_double set_rf_ss(s7_scheme *sc, s7_pointer **p)
  7705. {
  7706. s7_pointer s1, s2;
  7707. s7_double x;
  7708. s1 = (**p); (*p)++;
  7709. s2 = (**p); (*p)++;
  7710. x = real_to_double(sc, slot_value(s2), "set!");
  7711. slot_set_value(s1, make_real(sc, x));
  7712. return(x);
  7713. }
  7714. #endif
  7715. static s7_double set_rf_sx(s7_scheme *sc, s7_pointer **p)
  7716. {
  7717. s7_pointer s1;
  7718. s7_double x;
  7719. s7_rf_t r1;
  7720. s1 = (**p); (*p)++;
  7721. r1 = (s7_rf_t)(**p); (*p)++;
  7722. x = r1(sc, p);
  7723. slot_set_value(s1, make_real(sc, x));
  7724. return(x);
  7725. }
  7726. static s7_int set_if_sx(s7_scheme *sc, s7_pointer **p)
  7727. {
  7728. s7_pointer s1;
  7729. s7_int x;
  7730. s7_if_t i1;
  7731. s1 = (**p); (*p)++;
  7732. i1 = (s7_if_t)(**p); (*p)++;
  7733. x = i1(sc, p);
  7734. slot_set_value(s1, make_integer(sc, x));
  7735. return(x);
  7736. }
  7737. static s7_rf_t float_vector_set_rf_expanded(s7_scheme *sc, s7_pointer fv, s7_pointer ind_sym, s7_pointer val_expr);
  7738. static s7_if_t int_vector_set_if_expanded(s7_scheme *sc, s7_pointer iv, s7_pointer ind_sym, s7_pointer val_expr);
  7739. static s7_rf_t set_rf(s7_scheme *sc, s7_pointer expr)
  7740. {
  7741. s7_pointer slot, a1;
  7742. xf_t *rc;
  7743. if (is_pair(cdddr(expr))) return(NULL);
  7744. a1 = cadr(expr);
  7745. if (!is_symbol(a1)) /* look for implicit index case */
  7746. {
  7747. s7_pointer fv;
  7748. if ((!is_pair(a1)) || (!is_symbol(car(a1))) || (!is_null(cddr(a1)))) return(NULL);
  7749. fv = s7_symbol_value(sc, car(a1));
  7750. if (is_float_vector(fv))
  7751. return(float_vector_set_rf_expanded(sc, fv, cadr(a1), caddr(expr)));
  7752. if ((is_c_object(fv)) &&
  7753. (c_object_set_rp(fv)))
  7754. return(c_object_set_rp(fv)(sc, expr));
  7755. return(NULL);
  7756. }
  7757. /* if sym has real value and new val is real, we're ok */
  7758. slot = s7_slot(sc, a1);
  7759. if (!is_slot(slot)) return(NULL);
  7760. xf_init(2);
  7761. if (is_t_real(slot_value(slot)))
  7762. {
  7763. s7_pointer a2;
  7764. xf_store(slot);
  7765. a2 = caddr(expr);
  7766. if (is_t_real(a2))
  7767. {
  7768. xf_store(a2);
  7769. return(set_rf_sr);
  7770. }
  7771. #if 0
  7772. if (is_symbol(a2))
  7773. {
  7774. s7_pointer a2_slot;
  7775. a2_slot = s7_slot(sc, a2);
  7776. if (!is_slot(a2_slot)) return(NULL);
  7777. if (type(slot_value(a2_slot)) != T_REAL) return(NULL);
  7778. xf_store(a2_slot);
  7779. return(set_rf_ss);
  7780. }
  7781. #endif
  7782. if (is_pair(a2))
  7783. {
  7784. s7_rp_t rp;
  7785. s7_rf_t rf;
  7786. s7_int loc;
  7787. xf_save_loc(loc);
  7788. rp = pair_to_rp(sc, a2);
  7789. if (!rp) return(NULL);
  7790. rf = rp(sc, a2);
  7791. if (!rf) return(NULL);
  7792. xf_store_at(loc, (s7_pointer)rf);
  7793. return(set_rf_sx);
  7794. }
  7795. }
  7796. return(NULL);
  7797. }
  7798. static s7_if_t set_if(s7_scheme *sc, s7_pointer expr)
  7799. {
  7800. s7_pointer slot, a1;
  7801. if (is_pair(cdddr(expr))) return(NULL);
  7802. a1 = cadr(expr);
  7803. if (!is_symbol(a1)) /* look for implicit index case */
  7804. {
  7805. s7_pointer fv;
  7806. if ((!is_pair(a1)) || (!is_symbol(car(a1))) || (!is_null(cddr(a1)))) return(NULL);
  7807. fv = s7_symbol_value(sc, car(a1));
  7808. if (is_int_vector(fv))
  7809. return(int_vector_set_if_expanded(sc, fv, cadr(a1), caddr(expr)));
  7810. if ((is_c_object(fv)) &&
  7811. (c_object_set_ip(fv)))
  7812. return(c_object_set_ip(fv)(sc, expr));
  7813. return(NULL);
  7814. }
  7815. if (!is_symbol(a1)) return(NULL);
  7816. slot = s7_slot(sc, a1);
  7817. if (!is_slot(slot)) return(NULL);
  7818. if (is_t_integer(slot_value(slot)))
  7819. {
  7820. s7_pointer a2;
  7821. xf_t *rc;
  7822. xf_init(1);
  7823. xf_store(slot);
  7824. a2 = caddr(expr);
  7825. if ((is_pair(a2)) &&
  7826. (s7_arg_to_if(sc, a2)))
  7827. return(set_if_sx);
  7828. }
  7829. return(NULL);
  7830. }
  7831. static s7_pf_t set_pf(s7_scheme *sc, s7_pointer expr)
  7832. {
  7833. s7_pointer a1;
  7834. if (is_pair(cdddr(expr))) return(NULL);
  7835. a1 = cadr(expr);
  7836. if (is_pair(a1)) /* look for implicit index case */
  7837. {
  7838. s7_pointer v;
  7839. if ((!is_symbol(car(a1))) || (!is_pair(cdr(a1))) || (!is_null(cddr(a1)))) return(NULL);
  7840. v = s7_slot(sc, car(a1));
  7841. if (!is_slot(v)) return(NULL);
  7842. switch (type(slot_value(v)))
  7843. {
  7844. case T_PAIR: case T_STRING: case T_VECTOR: case T_HASH_TABLE: case T_LET:
  7845. return(implicit_pf_sequence_set(sc, v, cadr(a1), caddr(expr)));
  7846. case T_INT_VECTOR: case T_FLOAT_VECTOR:
  7847. return(implicit_gf_sequence_set(sc, v, cadr(a1), caddr(expr)));
  7848. }
  7849. }
  7850. return(NULL);
  7851. }
  7852. #endif
  7853. typedef s7_pointer (*p0_pf_t)(s7_scheme *sc);
  7854. static s7_pointer p0_pf_1(s7_scheme *sc, s7_pointer **p, p0_pf_t fnc)
  7855. {
  7856. return(fnc(sc));
  7857. }
  7858. static s7_pf_t pf_0(s7_scheme *sc, s7_pointer expr, s7_pf_t fnc)
  7859. {
  7860. if (!is_null(cdr(expr))) return(NULL);
  7861. return(fnc);
  7862. }
  7863. #define PF_0(CName, Pfnc) \
  7864. static s7_pointer CName ## _pf_0(s7_scheme *sc, s7_pointer **rp) {return(p0_pf_1(sc, rp, Pfnc));} \
  7865. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(pf_0(sc, expr, CName ## _pf_0));}
  7866. PF_0(curlet, s7_curlet)
  7867. PF_0(rootlet, s7_rootlet)
  7868. PF_0(current_input_port, s7_current_input_port)
  7869. PF_0(current_output_port, s7_current_output_port)
  7870. PF_0(current_error_port, s7_current_error_port)
  7871. static s7_pointer c_unlet(s7_scheme *sc) {return(g_unlet(sc, sc->nil));}
  7872. PF_0(unlet, c_unlet)
  7873. static s7_pointer c_gc(s7_scheme *sc) {return(g_gc(sc, sc->nil));}
  7874. PF_0(gc, c_gc)
  7875. /* -------- PF_TO_PF -------- */
  7876. typedef s7_pointer (*pf_pf_t)(s7_scheme *sc, s7_pointer x);
  7877. static s7_pointer pf_pf_1(s7_scheme *sc, s7_pointer **p, pf_pf_t fnc)
  7878. {
  7879. s7_pf_t f;
  7880. s7_pointer x;
  7881. f = (s7_pf_t)(**p); (*p)++;
  7882. x = f(sc, p);
  7883. return(fnc(sc, x));
  7884. }
  7885. static s7_pointer pf_pf_s(s7_scheme *sc, s7_pointer **p, pf_pf_t fnc)
  7886. {
  7887. s7_pointer x;
  7888. (*p)++; x = slot_value(**p); (*p)++;
  7889. return(fnc(sc, x));
  7890. }
  7891. static s7_pf_t pf_1(s7_scheme *sc, s7_pointer expr, s7_pf_t f1, s7_pf_t f2)
  7892. {
  7893. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))))
  7894. {
  7895. ptr_int loc;
  7896. s7_pointer a1;
  7897. a1 = cadr(expr);
  7898. loc = rc_loc(sc);
  7899. if (s7_arg_to_pf(sc, a1)) return((is_symbol(a1)) ? f2 : f1);
  7900. sc->cur_rf->cur = rc_go(sc, loc);
  7901. if (s7_arg_to_gf(sc, a1)) return((is_symbol(a1)) ? f2 : f1);
  7902. }
  7903. return(NULL);
  7904. }
  7905. #define PF_TO_PF(CName, Pfnc) \
  7906. static s7_pointer CName ## _pf_p(s7_scheme *sc, s7_pointer **rp) {return(pf_pf_1(sc, rp, Pfnc));} \
  7907. static s7_pointer CName ## _pf_s(s7_scheme *sc, s7_pointer **rp) {return(pf_pf_s(sc, rp, Pfnc));} \
  7908. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(pf_1(sc, expr, CName ## _pf_p, CName ## _pf_s));}
  7909. static s7_pointer c_symbol_to_value(s7_scheme *sc, s7_pointer x) {return(g_symbol_to_value(sc, set_plist_1(sc, x)));}
  7910. PF_TO_PF(symbol_to_value, c_symbol_to_value)
  7911. static s7_pointer c_symbol_to_string(s7_scheme *sc, s7_pointer p) {return(g_symbol_to_string(sc, set_plist_1(sc, p)));}
  7912. PF_TO_PF(symbol_to_string, c_symbol_to_string)
  7913. static s7_pointer c_gensym(s7_scheme *sc, s7_pointer p) {return(g_gensym(sc, set_plist_1(sc, p)));}
  7914. PF_TO_PF(gensym, c_gensym)
  7915. static s7_pointer c_not(s7_scheme *sc, s7_pointer x) {return((x == sc->F) ? sc->T : sc->F);}
  7916. PF_TO_PF(not, c_not)
  7917. PF_TO_PF(outlet, s7_outlet)
  7918. PF_TO_PF(openlet, s7_openlet)
  7919. PF_TO_PF(funclet, s7_funclet)
  7920. PF_TO_PF(coverlet, c_coverlet)
  7921. #define bool_with_method(Name, Checker, Method) \
  7922. static s7_pointer c_ ## Name (s7_scheme *sc, s7_pointer p) \
  7923. { \
  7924. s7_pointer func; \
  7925. if (Checker(p)) return(sc->T); \
  7926. if ((has_methods(p)) && \
  7927. ((func = find_method(sc, find_let(sc, p), Method)) != sc->undefined)) \
  7928. return(s7_apply_function(sc, func, list_1(sc, p))); \
  7929. return(sc->F); \
  7930. } \
  7931. PF_TO_PF(Name, c_ ## Name)
  7932. bool_with_method(is_char, s7_is_character, sc->is_char_symbol)
  7933. bool_with_method(is_boolean, s7_is_boolean, sc->is_boolean_symbol)
  7934. bool_with_method(is_byte_vector, is_byte_vector, sc->is_byte_vector_symbol)
  7935. bool_with_method(is_complex, is_number, sc->is_complex_symbol)
  7936. bool_with_method(is_constant, s7_is_constant, sc->is_constant_symbol)
  7937. bool_with_method(is_continuation, is_continuation, sc->is_continuation_symbol)
  7938. bool_with_method(is_c_pointer, s7_is_c_pointer, sc->is_c_pointer_symbol)
  7939. bool_with_method(is_dilambda, s7_is_dilambda, sc->is_dilambda_symbol)
  7940. bool_with_method(is_eof_object, is_eof, sc->is_eof_object_symbol)
  7941. bool_with_method(is_float_vector, is_float_vector, sc->is_float_vector_symbol)
  7942. bool_with_method(is_gensym, is_gensym, sc->is_gensym_symbol)
  7943. bool_with_method(is_hash_table, is_hash_table, sc->is_hash_table_symbol)
  7944. bool_with_method(is_input_port, is_input_port, sc->is_input_port_symbol)
  7945. bool_with_method(is_integer, is_integer, sc->is_integer_symbol)
  7946. bool_with_method(is_int_vector, is_int_vector, sc->is_int_vector_symbol)
  7947. bool_with_method(is_iterator, is_iterator, sc->is_iterator_symbol)
  7948. bool_with_method(is_keyword, is_keyword, sc->is_keyword_symbol)
  7949. bool_with_method(is_let, is_let, sc->is_let_symbol)
  7950. bool_with_method(is_macro, is_macro, sc->is_macro_symbol)
  7951. bool_with_method(is_null, is_null, sc->is_null_symbol)
  7952. bool_with_method(is_number, is_number, sc->is_number_symbol)
  7953. bool_with_method(is_openlet, s7_is_openlet, sc->is_openlet_symbol)
  7954. bool_with_method(is_output_port, is_output_port, sc->is_output_port_symbol)
  7955. bool_with_method(is_pair, is_pair, sc->is_pair_symbol)
  7956. bool_with_method(is_procedure, is_procedure, sc->is_procedure_symbol)
  7957. bool_with_method(is_rational, is_rational, sc->is_rational_symbol)
  7958. bool_with_method(is_real, is_real, sc->is_real_symbol)
  7959. bool_with_method(is_string, is_string, sc->is_string_symbol)
  7960. bool_with_method(is_symbol, is_symbol, sc->is_symbol_symbol)
  7961. bool_with_method(is_vector, s7_is_vector, sc->is_vector_symbol)
  7962. #define opt_is_list(p) s7_is_list(sc, p)
  7963. bool_with_method(is_list, opt_is_list, sc->is_list_symbol)
  7964. bool_with_method(iterator_is_at_end, iterator_is_at_end, sc->iterator_is_at_end_symbol)
  7965. bool_with_method(is_random_state, is_random_state, sc->is_random_state_symbol)
  7966. PF_TO_PF(make_keyword, c_make_keyword)
  7967. PF_TO_PF(keyword_to_symbol, c_keyword_to_symbol)
  7968. PF_TO_PF(symbol_to_keyword, c_symbol_to_keyword)
  7969. static s7_pointer c_symbol(s7_scheme *sc, s7_pointer x) {return(g_string_to_symbol_1(sc, x, sc->symbol_symbol));}
  7970. PF_TO_PF(symbol, c_symbol)
  7971. #if 0
  7972. static s7_pointer symbol_pf_p(s7_scheme *sc, s7_pointer **p)
  7973. {
  7974. s7_pf_t f;
  7975. s7_pointer x;
  7976. f = (s7_pf_t)(**p); (*p)++;
  7977. x = f(sc, p);
  7978. return(g_string_to_symbol_1(sc, x, sc->symbol_symbol));
  7979. }
  7980. #endif
  7981. /* an experiment -- we need a temp pointer per func? */
  7982. static s7_pointer string_to_symbol_pf_p(s7_scheme *sc, s7_pointer **p)
  7983. {
  7984. s7_pf_t f;
  7985. s7_pointer x;
  7986. f = (s7_pf_t)(**p); (*p)++;
  7987. x = f(sc, p);
  7988. return(g_string_to_symbol_1(sc, x, sc->string_to_symbol_symbol));
  7989. }
  7990. static s7_pointer number_to_string_pf_p(s7_scheme *sc, s7_pointer **p);
  7991. static s7_pointer number_to_string_pf_s(s7_scheme *sc, s7_pointer **p);
  7992. static s7_pointer number_to_string_pf_temp(s7_scheme *sc, s7_pointer **p);
  7993. static s7_pointer number_to_string_pf_s_temp(s7_scheme *sc, s7_pointer **p);
  7994. static s7_pf_t string_to_symbol_pf(s7_scheme *sc, s7_pointer expr)
  7995. {
  7996. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))))
  7997. {
  7998. ptr_int loc;
  7999. loc = rc_loc(sc);
  8000. if (s7_arg_to_pf(sc, cadr(expr)))
  8001. return(string_to_symbol_pf_p);
  8002. sc->cur_rf->cur = rc_go(sc, loc);
  8003. if (s7_arg_to_gf(sc, cadr(expr)))
  8004. {
  8005. if (sc->cur_rf->data[loc] == (s7_pointer)number_to_string_pf_p)
  8006. sc->cur_rf->data[loc] = (s7_pointer)number_to_string_pf_temp;
  8007. if (sc->cur_rf->data[loc] == (s7_pointer)number_to_string_pf_s)
  8008. sc->cur_rf->data[loc] = (s7_pointer)number_to_string_pf_s_temp;
  8009. return(string_to_symbol_pf_p);
  8010. }
  8011. }
  8012. return(NULL);
  8013. }
  8014. #if (!WITH_PURE_S7)
  8015. PF_TO_PF(let_to_list, s7_let_to_list)
  8016. #endif
  8017. /* -------- PF2_TO_PF -------- */
  8018. typedef s7_pointer (*pf2_pf_t)(s7_scheme *sc, s7_pointer x, s7_pointer y);
  8019. static s7_pointer pf2_pf_1(s7_scheme *sc, s7_pointer **p, pf2_pf_t fnc)
  8020. {
  8021. s7_pf_t f;
  8022. s7_pointer x, y;
  8023. f = (s7_pf_t)(**p); (*p)++;
  8024. x = f(sc, p);
  8025. f = (s7_pf_t)(**p); (*p)++;
  8026. y = f(sc, p);
  8027. return(fnc(sc, x, y));
  8028. }
  8029. static s7_pointer pf2_pf_sp(s7_scheme *sc, s7_pointer **p, pf2_pf_t fnc)
  8030. {
  8031. s7_pf_t f;
  8032. s7_pointer x, y;
  8033. x = slot_value(**p); (*p)++;
  8034. f = (s7_pf_t)(**p); (*p)++;
  8035. y = f(sc, p);
  8036. return(fnc(sc, x, y));
  8037. }
  8038. static s7_pointer pf2_pf_ss(s7_scheme *sc, s7_pointer **p, pf2_pf_t fnc)
  8039. {
  8040. s7_pointer x, y;
  8041. x = slot_value(**p); (*p)++;
  8042. y = slot_value(**p); (*p)++;
  8043. return(fnc(sc, x, y));
  8044. }
  8045. static s7_pointer pf2_pf_sc(s7_scheme *sc, s7_pointer **p, pf2_pf_t fnc)
  8046. {
  8047. s7_pointer x, y;
  8048. x = slot_value(**p); (*p)++;
  8049. y = (**p); (*p)++;
  8050. return(fnc(sc, x, y));
  8051. }
  8052. static s7_pointer pf2_pf_pc(s7_scheme *sc, s7_pointer **p, pf2_pf_t fnc)
  8053. {
  8054. s7_pf_t f;
  8055. s7_pointer x, y;
  8056. f = (s7_pf_t)(**p); (*p)++;
  8057. x = f(sc, p);
  8058. y = (**p); (*p)++;
  8059. return(fnc(sc, x, y));
  8060. }
  8061. static s7_pf_t pf_2(s7_scheme *sc, s7_pointer expr, s7_pf_t fpp, s7_pf_t fsp, s7_pf_t fss, s7_pf_t fsc, s7_pf_t fpc)
  8062. {
  8063. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_null(cdddr(expr))))
  8064. {
  8065. s7_pointer a1, a2;
  8066. xf_t *rc;
  8067. xf_init(2);
  8068. a1 = cadr(expr);
  8069. a2 = caddr(expr);
  8070. if (is_symbol(a1))
  8071. {
  8072. a1 = s7_slot(sc, a1);
  8073. if (!is_slot(a1)) return(NULL);
  8074. xf_store(a1);
  8075. if (is_symbol(a2))
  8076. {
  8077. a2 = s7_slot(sc, a2);
  8078. if (!is_slot(a2)) return(NULL);
  8079. xf_store(a2);
  8080. return(fss);
  8081. }
  8082. if (is_pair(a2))
  8083. {
  8084. if (!s7_arg_to_pf(sc, a2)) return(NULL);
  8085. return(fsp);
  8086. }
  8087. xf_store(a2);
  8088. return(fsc);
  8089. }
  8090. if (s7_arg_to_pf(sc, a1))
  8091. {
  8092. if ((!is_pair(a2)) && (!is_symbol(a2)))
  8093. {
  8094. xf_store(a2);
  8095. return(fpc);
  8096. }
  8097. if (s7_arg_to_pf(sc, a2))
  8098. return(fpp);
  8099. }
  8100. }
  8101. return(NULL);
  8102. }
  8103. #define PF2_TO_PF(CName, Pfnc) \
  8104. static s7_pointer CName ## _pf_p2(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_1(sc, rp, Pfnc));} \
  8105. static s7_pointer CName ## _pf_p2_sp(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_sp(sc, rp, Pfnc));} \
  8106. static s7_pointer CName ## _pf_p2_ss(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_ss(sc, rp, Pfnc));} \
  8107. static s7_pointer CName ## _pf_p2_sc(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_sc(sc, rp, Pfnc));} \
  8108. static s7_pointer CName ## _pf_p2_pc(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_pc(sc, rp, Pfnc));} \
  8109. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) \
  8110. { \
  8111. return(pf_2(sc, expr, CName ## _pf_p2, CName ## _pf_p2_sp, CName ## _pf_p2_ss, CName ## _pf_p2_sc, CName ## _pf_p2_pc));\
  8112. }
  8113. static s7_pf_t pf_2_x(s7_scheme *sc, s7_pointer expr, bool (*checker)(s7_scheme *sc, s7_pointer obj),
  8114. s7_pf_t fpp, s7_pf_t fpp_x, s7_pf_t fsp, s7_pf_t fss, s7_pf_t fsc, s7_pf_t fpc, s7_pf_t fpc_x)
  8115. {
  8116. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_null(cdddr(expr))))
  8117. {
  8118. s7_pointer a1, a2;
  8119. xf_t *rc;
  8120. xf_init(2);
  8121. a1 = cadr(expr);
  8122. a2 = caddr(expr);
  8123. if (is_symbol(a1))
  8124. {
  8125. a1 = s7_slot(sc, a1);
  8126. if (!is_slot(a1)) return(NULL);
  8127. xf_store(a1);
  8128. if (is_symbol(a2))
  8129. {
  8130. a2 = s7_slot(sc, a2);
  8131. if (!is_slot(a2)) return(NULL);
  8132. xf_store(a2);
  8133. return(fss);
  8134. }
  8135. if (is_pair(a2))
  8136. {
  8137. if (!s7_arg_to_pf(sc, a2)) return(NULL);
  8138. return(fsp);
  8139. }
  8140. xf_store(a2);
  8141. return(fsc);
  8142. }
  8143. if (s7_arg_to_pf(sc, a1))
  8144. {
  8145. if ((!is_pair(a2)) && (!is_symbol(a2)))
  8146. {
  8147. xf_store(a2);
  8148. if ((checker(sc, a1)) && (checker(sc, a2)))
  8149. return(fpc_x);
  8150. return(fpc);
  8151. }
  8152. if (s7_arg_to_pf(sc, a2))
  8153. {
  8154. if ((checker(sc, a1)) && (checker(sc, a2)))
  8155. return(fpp_x);
  8156. return(fpp);
  8157. }
  8158. }
  8159. }
  8160. return(NULL);
  8161. }
  8162. #define PF2_TO_PF_X(CName, Checker, Pfnc1, Pfnc2) \
  8163. static s7_pointer CName ## _pf_p2_pp(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_1(sc, rp, Pfnc1));} \
  8164. static s7_pointer CName ## _pf_p2_ppx(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_1(sc, rp, Pfnc2));} \
  8165. static s7_pointer CName ## _pf_p2_pc(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_pc(sc, rp, Pfnc1));} \
  8166. static s7_pointer CName ## _pf_p2_pcx(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_pc(sc, rp, Pfnc2));} \
  8167. static s7_pointer CName ## _pf_p2_sp(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_sp(sc, rp, Pfnc1));} \
  8168. static s7_pointer CName ## _pf_p2_ss(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_ss(sc, rp, Pfnc1));} \
  8169. static s7_pointer CName ## _pf_p2_sc(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_sc(sc, rp, Pfnc1));} \
  8170. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) \
  8171. {\
  8172. return(pf_2_x(sc, expr, Checker, \
  8173. CName ## _pf_p2_pp, CName ## _pf_p2_ppx, \
  8174. CName ## _pf_p2_sp, CName ## _pf_p2_ss, CName ## _pf_p2_sc, \
  8175. CName ## _pf_p2_pc, CName ## _pf_p2_pcx)); \
  8176. }
  8177. static s7_pointer c_is_eq(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(make_boolean(sc, x == y));}
  8178. PF2_TO_PF(is_eq, c_is_eq)
  8179. static s7_pointer c_is_eqv(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(make_boolean(sc, s7_is_eqv(x, y)));}
  8180. PF2_TO_PF(is_eqv, c_is_eqv)
  8181. static s7_pointer c_is_equal(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(make_boolean(sc, s7_is_equal(sc, x, y)));}
  8182. PF2_TO_PF(is_equal, c_is_equal)
  8183. static s7_pointer c_is_morally_equal(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(make_boolean(sc, s7_is_morally_equal(sc, x, y)));}
  8184. PF2_TO_PF(is_morally_equal, c_is_morally_equal)
  8185. PF2_TO_PF(let_ref, s7_let_ref)
  8186. static s7_pointer c_cutlet(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_cutlet(sc, set_plist_2(sc, x, y)));}
  8187. PF2_TO_PF(cutlet, c_cutlet)
  8188. static s7_pointer c_inlet(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(s7_inlet(sc, set_plist_2(sc, x, y)));}
  8189. PF2_TO_PF(inlet, c_inlet)
  8190. /* -------- PF3_TO_PF -------- */
  8191. typedef s7_pointer (*pf3_pf_t)(s7_scheme *sc, s7_pointer x, s7_pointer y, s7_pointer z);
  8192. static s7_pointer pf3_pf_1(s7_scheme *sc, s7_pointer **p, pf3_pf_t fnc)
  8193. {
  8194. s7_pf_t f;
  8195. s7_pointer x, y, z;
  8196. f = (s7_pf_t)(**p); (*p)++;
  8197. x = f(sc, p);
  8198. f = (s7_pf_t)(**p); (*p)++;
  8199. y = f(sc, p);
  8200. f = (s7_pf_t)(**p); (*p)++;
  8201. z = f(sc, p);
  8202. return(fnc(sc, x, y, z));
  8203. }
  8204. static s7_pointer pf3_pf_s(s7_scheme *sc, s7_pointer **p, pf3_pf_t fnc)
  8205. {
  8206. s7_pf_t f;
  8207. s7_pointer x, y, z;
  8208. x = slot_value(**p); (*p)++;
  8209. f = (s7_pf_t)(**p); (*p)++;
  8210. y = f(sc, p);
  8211. f = (s7_pf_t)(**p); (*p)++;
  8212. z = f(sc, p);
  8213. return(fnc(sc, x, y, z));
  8214. }
  8215. static s7_pf_t pf_3(s7_scheme *sc, s7_pointer expr, s7_pf_t fp, s7_pf_t fs)
  8216. {
  8217. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_pair(cdddr(expr))) && (is_null(cddddr(expr))))
  8218. {
  8219. s7_pointer a1;
  8220. a1 = cadr(expr);
  8221. if (is_symbol(a1))
  8222. {
  8223. s7_pointer slot;
  8224. slot = s7_slot(sc, a1);
  8225. if (!is_slot(slot)) return(NULL);
  8226. s7_xf_store(sc, slot);
  8227. }
  8228. else
  8229. {
  8230. if (!s7_arg_to_pf(sc, a1)) return(NULL);
  8231. }
  8232. if ((s7_arg_to_pf(sc, caddr(expr))) &&
  8233. (s7_arg_to_pf(sc, cadddr(expr))))
  8234. return((is_symbol(a1)) ? fs : fp);
  8235. }
  8236. return(NULL);
  8237. }
  8238. #define PF3_TO_PF(CName, Pfnc) \
  8239. static s7_pointer CName ## _pf_p3(s7_scheme *sc, s7_pointer **rp) {return(pf3_pf_1(sc, rp, Pfnc));} \
  8240. static s7_pointer CName ## _pf_p3_s(s7_scheme *sc, s7_pointer **rp) {return(pf3_pf_s(sc, rp, Pfnc));} \
  8241. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(pf_3(sc, expr, CName ## _pf_p3, CName ## _pf_p3_s));}
  8242. PF3_TO_PF(let_set, s7_let_set)
  8243. PF3_TO_PF(varlet, s7_varlet)
  8244. PF_TO_PF(c_pointer, c_c_pointer)
  8245. /* -------- PIF_TO_PF -------- */
  8246. typedef s7_pointer (*pif_pf_t)(s7_scheme *sc, s7_pointer x, s7_int y);
  8247. static s7_pointer pif_pf_1(s7_scheme *sc, s7_pointer **p, pif_pf_t fnc)
  8248. {
  8249. s7_pf_t pf;
  8250. s7_if_t xf;
  8251. s7_pointer x;
  8252. s7_int y;
  8253. pf = (s7_pf_t)(**p); (*p)++;
  8254. x = pf(sc, p);
  8255. xf = (s7_if_t)(**p); (*p)++;
  8256. y = xf(sc, p);
  8257. return(fnc(sc, x, y));
  8258. }
  8259. static s7_pointer pif_pf_s(s7_scheme *sc, s7_pointer **p, pif_pf_t fnc)
  8260. {
  8261. s7_if_t xf;
  8262. s7_pointer x;
  8263. s7_int y;
  8264. x = slot_value(**p); (*p)++;
  8265. xf = (s7_if_t)(**p); (*p)++;
  8266. y = xf(sc, p);
  8267. return(fnc(sc, x, y));
  8268. }
  8269. static s7_pointer pif_pf_pp(s7_scheme *sc, s7_pointer **p, pif_pf_t fnc)
  8270. {
  8271. s7_pf_t pf;
  8272. s7_pointer x, y;
  8273. pf = (s7_pf_t)(**p); (*p)++;
  8274. x = pf(sc, p);
  8275. pf = (s7_pf_t)(**p); (*p)++;
  8276. y = pf(sc, p);
  8277. if (!is_integer(y))
  8278. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "~A should be an integer"), y)));
  8279. return(fnc(sc, x, integer(y)));
  8280. }
  8281. static s7_pointer pif_pf_sp(s7_scheme *sc, s7_pointer **p, pif_pf_t fnc)
  8282. {
  8283. s7_pf_t pf;
  8284. s7_pointer x, y;
  8285. x = slot_value(**p); (*p)++;
  8286. pf = (s7_pf_t)(**p); (*p)++;
  8287. y = pf(sc, p);
  8288. if (!is_integer(y))
  8289. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "~A should be an integer"), y)));
  8290. return(fnc(sc, x, integer(y)));
  8291. }
  8292. static s7_pf_t pif_1(s7_scheme *sc, s7_pointer expr, s7_pf_t fpi, s7_pf_t fsi, s7_pf_t fpp, s7_pf_t fsp)
  8293. {
  8294. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_null(cdddr(expr))))
  8295. {
  8296. s7_pointer a1, a2;
  8297. ptr_int loc;
  8298. a1 = cadr(expr);
  8299. a2 = caddr(expr);
  8300. if (is_symbol(a1))
  8301. {
  8302. s7_pointer slot;
  8303. slot = s7_slot(sc, a1);
  8304. if (!is_slot(slot)) return(NULL);
  8305. s7_xf_store(sc, slot);
  8306. }
  8307. else
  8308. {
  8309. if (!s7_arg_to_pf(sc, a1))
  8310. return(NULL);
  8311. }
  8312. loc = rc_loc(sc);
  8313. if (s7_arg_to_if(sc, a2))
  8314. return((is_symbol(a1)) ? fsi : fpi);
  8315. sc->cur_rf->cur = rc_go(sc, loc);
  8316. if (s7_arg_to_pf(sc, a2))
  8317. return((is_symbol(a1)) ? fsp : fpp);
  8318. }
  8319. return(NULL);
  8320. }
  8321. #define PIF_TO_PF(CName, Pfnc) \
  8322. static s7_pointer CName ## _pf_pi(s7_scheme *sc, s7_pointer **rp) {return(pif_pf_1(sc, rp, Pfnc));} \
  8323. static s7_pointer CName ## _pf_si(s7_scheme *sc, s7_pointer **rp) {return(pif_pf_s(sc, rp, Pfnc));} \
  8324. static s7_pointer CName ## _pf_pp(s7_scheme *sc, s7_pointer **rp) {return(pif_pf_pp(sc, rp, Pfnc));} \
  8325. static s7_pointer CName ## _pf_sp(s7_scheme *sc, s7_pointer **rp) {return(pif_pf_sp(sc, rp, Pfnc));} \
  8326. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(pif_1(sc, expr, CName ## _pf_pi, CName ## _pf_si, CName ## _pf_pp, CName ## _pf_sp));}
  8327. /* -------- PPIF_TO_PF -------- */
  8328. typedef s7_pointer (*ppif_pf_t)(s7_scheme *sc, s7_pointer x, s7_pointer y, s7_int z);
  8329. static s7_pointer ppif_pf_1(s7_scheme *sc, s7_pointer **p, ppif_pf_t fnc) /* other case is pf2_pf_1, type pf2_pf_t */
  8330. {
  8331. s7_pf_t pf;
  8332. s7_if_t xf;
  8333. s7_pointer x, y;
  8334. s7_int z;
  8335. pf = (s7_pf_t)(**p); (*p)++;
  8336. x = pf(sc, p);
  8337. pf = (s7_pf_t)(**p); (*p)++;
  8338. y = pf(sc, p);
  8339. xf = (s7_if_t)(**p); (*p)++;
  8340. z = xf(sc, p);
  8341. return(fnc(sc, x, y, z));
  8342. }
  8343. static s7_pf_t ppif_1(s7_scheme *sc, s7_pointer expr, s7_pf_t f1, s7_pf_t f2)
  8344. {
  8345. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))))
  8346. {
  8347. ptr_int loc;
  8348. if (!s7_arg_to_pf(sc, cadr(expr))) return(NULL);
  8349. loc = rc_loc(sc);
  8350. if (!s7_arg_to_pf(sc, caddr(expr)))
  8351. {
  8352. sc->cur_rf->cur = rc_go(sc, loc);
  8353. if (!s7_arg_to_gf(sc, caddr(expr))) return(NULL);
  8354. }
  8355. if (is_null(cdddr(expr))) return(f1);
  8356. if (!is_null(cddddr(expr))) return(NULL);
  8357. if (s7_arg_to_if(sc, cadddr(expr))) return(f2);
  8358. }
  8359. return(NULL);
  8360. }
  8361. #define PPIF_TO_PF(CName, Pfnc1, Pfnc2) \
  8362. static s7_pointer CName ## _pf_pp(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_1(sc, rp, Pfnc1));} \
  8363. static s7_pointer CName ## _pf_ppi(s7_scheme *sc, s7_pointer **rp) {return(ppif_pf_1(sc, rp, Pfnc2));} \
  8364. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(ppif_1(sc, expr, CName ## _pf_pp, CName ## _pf_ppi));}
  8365. /* -------- PIPF_TO_PF -------- */
  8366. typedef s7_pointer (*pipf_pf_t)(s7_scheme *sc, s7_pointer x, s7_int y, s7_pointer z);
  8367. static s7_pointer pipf_pf_slot(s7_scheme *sc, s7_pointer **p, pipf_pf_t fnc)
  8368. {
  8369. s7_pf_t pf;
  8370. s7_pointer x, z;
  8371. s7_int y;
  8372. x = (s7_pointer)(**p); (*p)++;
  8373. y = s7_integer(slot_value(**p)); (*p)++;
  8374. pf = (s7_pf_t)(**p); (*p)++;
  8375. z = pf(sc, p);
  8376. return(fnc(sc, x, y, z));
  8377. }
  8378. static s7_pointer pipf_pf_s(s7_scheme *sc, s7_pointer **p, pipf_pf_t fnc)
  8379. {
  8380. s7_pf_t pf;
  8381. s7_if_t xf;
  8382. s7_pointer x, z;
  8383. s7_int y;
  8384. x = (s7_pointer)(**p); (*p)++;
  8385. xf = (s7_if_t)(**p); (*p)++;
  8386. y = xf(sc, p);
  8387. pf = (s7_pf_t)(**p); (*p)++;
  8388. z = pf(sc, p);
  8389. return(fnc(sc, x, y, z));
  8390. }
  8391. static s7_pointer pipf_pf_seq(s7_scheme *sc, s7_pointer **p, pipf_pf_t fnc) /* used in implicit_sequence_set */
  8392. {
  8393. s7_pf_t pf;
  8394. s7_if_t xf;
  8395. s7_pointer x, z;
  8396. s7_int y;
  8397. x = slot_value(**p); (*p)++;
  8398. xf = (s7_if_t)(**p); (*p)++;
  8399. y = xf(sc, p);
  8400. pf = (s7_pf_t)(**p); (*p)++;
  8401. z = pf(sc, p);
  8402. return(fnc(sc, x, y, z));
  8403. }
  8404. static s7_pointer pipf_pf_a(s7_scheme *sc, s7_pointer **p, pipf_pf_t fnc)
  8405. {
  8406. s7_pf_t pf;
  8407. s7_if_t xf;
  8408. s7_pointer x, z;
  8409. s7_int y;
  8410. pf = (s7_pf_t)(**p); (*p)++;
  8411. x = pf(sc, p);
  8412. xf = (s7_if_t)(**p); (*p)++;
  8413. y = xf(sc, p);
  8414. pf = (s7_pf_t)(**p); (*p)++;
  8415. z = pf(sc, p);
  8416. return(fnc(sc, x, y, z));
  8417. }
  8418. enum {TEST_NO_S, TEST_SS, TEST_SI, TEST_SQ}; /* si = sym ind, ss = sym sym for first two */
  8419. typedef int (*pf_i_t)(s7_scheme *sc, s7_pointer x);
  8420. static s7_pf_t pipf_1(s7_scheme *sc, s7_pointer expr, s7_pf_t f1, s7_pf_t f2, s7_pf_t f3, pf_i_t tester)
  8421. {
  8422. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_pair(cdddr(expr))) && (is_null(cddddr(expr))))
  8423. {
  8424. int choice;
  8425. choice = tester(sc, expr);
  8426. if ((choice == TEST_SS) || (choice == TEST_SI) ||
  8427. ((choice == TEST_NO_S) &&
  8428. (s7_arg_to_pf(sc, cadr(expr))) &&
  8429. (s7_arg_to_if(sc, caddr(expr)))))
  8430. {
  8431. ptr_int loc;
  8432. loc = rc_loc(sc);
  8433. if (s7_arg_to_pf(sc, cadddr(expr)))
  8434. return((choice == TEST_SS) ? f1 : ((choice == TEST_SI) ? f2 : f3));
  8435. sc->cur_rf->cur = rc_go(sc, loc);
  8436. if (s7_arg_to_gf(sc, cadddr(expr)))
  8437. return((choice == TEST_SS) ? f1 : ((choice == TEST_SI) ? f2 : f3));
  8438. }
  8439. }
  8440. return(NULL);
  8441. }
  8442. #define PIPF_TO_PF(CName, F1, F2, Tester) \
  8443. static s7_pointer CName ## _pf_slot(s7_scheme *sc, s7_pointer **rp) {return(pipf_pf_slot(sc, rp, F1));} \
  8444. static s7_pointer CName ## _pf_s(s7_scheme *sc, s7_pointer **rp) {return(pipf_pf_s(sc, rp, F1));} \
  8445. static s7_pointer CName ## _pf_seq(s7_scheme *sc, s7_pointer **rp) {return(pipf_pf_seq(sc, rp, F1));} \
  8446. static s7_pointer CName ## _pf_a(s7_scheme *sc, s7_pointer **rp) {return(pipf_pf_a(sc, rp, F2));} \
  8447. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(pipf_1(sc, expr, CName ## _pf_slot, CName ## _pf_s, CName ## _pf_a, Tester));}
  8448. /* -------- IF_TO_IF -------- */
  8449. typedef s7_int (*if_if_t)(s7_scheme *sc, s7_int x);
  8450. static s7_int if_if_1(s7_scheme *sc, s7_pointer **p, if_if_t fnc)
  8451. {
  8452. s7_if_t f;
  8453. s7_int x;
  8454. f = (s7_if_t)(**p); (*p)++;
  8455. x = f(sc, p);
  8456. return(fnc(sc, x));
  8457. }
  8458. static s7_if_t if_1(s7_scheme *sc, s7_pointer expr, s7_if_t f)
  8459. {
  8460. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))) && (s7_arg_to_if(sc, cadr(expr))))
  8461. return(f);
  8462. return(NULL);
  8463. }
  8464. #define IF_TO_IF(CName, Ifnc) \
  8465. static s7_int CName ## _if_i(s7_scheme *sc, s7_pointer **rp) {return(if_if_1(sc, rp, Ifnc));} \
  8466. static s7_if_t CName ## _if(s7_scheme *sc, s7_pointer expr) {return(if_1(sc, expr, CName ## _if_i));}
  8467. #if (!WITH_GMP)
  8468. /* -------- IF2_TO_IF -------- */
  8469. typedef s7_int (*if2_if_t)(s7_scheme *sc, s7_int x, s7_int y);
  8470. static s7_int if2_if_1(s7_scheme *sc, s7_pointer **p, if2_if_t fnc)
  8471. {
  8472. s7_if_t f;
  8473. s7_int x, y;
  8474. f = (s7_if_t)(**p); (*p)++;
  8475. x = f(sc, p);
  8476. f = (s7_if_t)(**p); (*p)++;
  8477. y = f(sc, p);
  8478. return(fnc(sc, x, y));
  8479. }
  8480. static s7_if_t if_2(s7_scheme *sc, s7_pointer expr, s7_if_t f)
  8481. {
  8482. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_null(cdddr(expr))) &&
  8483. (s7_arg_to_if(sc, cadr(expr))) &&
  8484. (s7_arg_to_if(sc, caddr(expr))))
  8485. return(f);
  8486. return(NULL);
  8487. }
  8488. #define IF2_TO_IF(CName, Ifnc) \
  8489. static s7_int CName ## _if_i2(s7_scheme *sc, s7_pointer **rp) {return(if2_if_1(sc, rp, Ifnc));} \
  8490. static s7_if_t CName ## _if(s7_scheme *sc, s7_pointer expr) {return(if_2(sc, expr, CName ## _if_i2));}
  8491. /* -------- IF_3_TO_IF -------- */
  8492. typedef s7_int (*if3_if_t)(s7_scheme *sc, s7_int x, s7_int y, s7_int z);
  8493. static s7_int if3_if_1(s7_scheme *sc, s7_pointer **p, if3_if_t fnc)
  8494. {
  8495. s7_if_t f;
  8496. s7_int x, y, z;
  8497. f = (s7_if_t)(**p); (*p)++;
  8498. x = f(sc, p);
  8499. f = (s7_if_t)(**p); (*p)++;
  8500. y = f(sc, p);
  8501. f = (s7_if_t)(**p); (*p)++;
  8502. z = f(sc, p);
  8503. return(fnc(sc, x, y, z));
  8504. }
  8505. static s7_if_t if_3(s7_scheme *sc, s7_pointer expr, s7_if_t f1, s7_if_t f2, s7_if_t f3)
  8506. {
  8507. if (!is_pair(cdr(expr))) return(NULL);
  8508. if (!s7_arg_to_if(sc, cadr(expr))) return(NULL);
  8509. if (is_null(cddr(expr))) return(f1);
  8510. if (!s7_arg_to_if(sc, caddr(expr))) return(NULL);
  8511. if (is_null(cdddr(expr))) return(f2);
  8512. if (!s7_arg_to_if(sc, cadddr(expr))) return(NULL);
  8513. if (is_null(cddddr(expr))) return(f3);
  8514. return(NULL);
  8515. }
  8516. #define IF_3_TO_IF(CName, Ifnc1, Ifnc2, Ifnc3) \
  8517. static s7_int CName ## _if_i1(s7_scheme *sc, s7_pointer **rp) {return(if_if_1(sc, rp, Ifnc1));} \
  8518. static s7_int CName ## _if_i2(s7_scheme *sc, s7_pointer **rp) {return(if2_if_1(sc, rp, Ifnc2));} \
  8519. static s7_int CName ## _if_i3(s7_scheme *sc, s7_pointer **rp) {return(if3_if_1(sc, rp, Ifnc3));} \
  8520. static s7_if_t CName ## _if(s7_scheme *sc, s7_pointer expr) {return(if_3(sc, expr, CName ## _if_i1, CName ## _if_i2, CName ## _if_i3));}
  8521. #endif /* gmp */
  8522. /* -------- IF_TO_PF -------- */
  8523. typedef s7_pointer (*if_pf_t)(s7_scheme *sc, s7_int x);
  8524. static s7_pointer if_p_1(s7_scheme *sc, s7_pointer **p, if_pf_t fnc)
  8525. {
  8526. s7_if_t f;
  8527. s7_int x;
  8528. f = (s7_if_t)(**p); (*p)++;
  8529. x = f(sc, p);
  8530. return(fnc(sc, x));
  8531. }
  8532. static s7_pf_t if_pf_1(s7_scheme *sc, s7_pointer expr, s7_pf_t f)
  8533. {
  8534. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))) && (s7_arg_to_if(sc, cadr(expr))))
  8535. return(f);
  8536. return(NULL);
  8537. }
  8538. #define IF_TO_PF(CName, Ifnc) \
  8539. static s7_pointer CName ## _pf_i(s7_scheme *sc, s7_pointer **rp) {return(if_p_1(sc, rp, Ifnc));} \
  8540. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(if_pf_1(sc, expr, CName ## _pf_i));}
  8541. /* -------- PF_TO_IF -------- */
  8542. typedef s7_int (*pf_if_t)(s7_scheme *sc, s7_pointer x);
  8543. static s7_int pf_i_1(s7_scheme *sc, s7_pointer **p, pf_if_t fnc)
  8544. {
  8545. s7_pf_t f;
  8546. s7_pointer x;
  8547. f = (s7_pf_t)(**p); (*p)++;
  8548. x = f(sc, p);
  8549. return(fnc(sc, x));
  8550. }
  8551. static s7_if_t pf_if_1(s7_scheme *sc, s7_pointer expr, s7_if_t f)
  8552. {
  8553. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))) && (s7_arg_to_pf(sc, cadr(expr))))
  8554. return(f);
  8555. return(NULL);
  8556. }
  8557. #define PF_TO_IF(CName, Pfnc) \
  8558. static s7_int CName ## _if_p(s7_scheme *sc, s7_pointer **rp) {return(pf_i_1(sc, rp, Pfnc));} \
  8559. static s7_if_t CName ## _if(s7_scheme *sc, s7_pointer expr) {return(pf_if_1(sc, expr, CName ## _if_p));}
  8560. /* -------- PF_TO_RF -------- */
  8561. typedef s7_double (*pf_rf_t)(s7_scheme *sc, s7_pointer x);
  8562. static s7_double pf_r_1(s7_scheme *sc, s7_pointer **p, pf_rf_t fnc)
  8563. {
  8564. s7_pf_t f;
  8565. s7_pointer x;
  8566. f = (s7_pf_t)(**p); (*p)++;
  8567. x = f(sc, p);
  8568. return(fnc(sc, x));
  8569. }
  8570. static s7_rf_t pf_rf_1(s7_scheme *sc, s7_pointer expr, s7_rf_t f)
  8571. {
  8572. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))) && (s7_arg_to_rf(sc, cadr(expr))))
  8573. return(f);
  8574. return(NULL);
  8575. }
  8576. #define PF_TO_RF(CName, Pfnc) \
  8577. static s7_double CName ## _rf_p(s7_scheme *sc, s7_pointer **rp) {return(pf_r_1(sc, rp, Pfnc));} \
  8578. static s7_rf_t CName ## _rf(s7_scheme *sc, s7_pointer expr) {return(pf_rf_1(sc, expr, CName ## _rf_p));}
  8579. #if (!WITH_GMP)
  8580. /* -------- RF_TO_IF -------- */
  8581. typedef s7_int (*rf_if_t)(s7_scheme *sc, s7_double x);
  8582. static s7_int rf_i_1(s7_scheme *sc, s7_pointer **p, rf_if_t fnc)
  8583. {
  8584. s7_rf_t f;
  8585. s7_double x;
  8586. f = (s7_rf_t)(**p); (*p)++;
  8587. x = f(sc, p);
  8588. return(fnc(sc, x));
  8589. }
  8590. static s7_if_t rf_if_1(s7_scheme *sc, s7_pointer expr, s7_if_t f)
  8591. {
  8592. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))) && (s7_arg_to_rf(sc, cadr(expr))))
  8593. return(f);
  8594. return(NULL);
  8595. }
  8596. #define RF_TO_IF(CName, Rfnc) \
  8597. static s7_int CName ## _if_r(s7_scheme *sc, s7_pointer **rp) {return(rf_i_1(sc, rp, Rfnc));} \
  8598. static s7_if_t CName ## _if(s7_scheme *sc, s7_pointer expr) {return(rf_if_1(sc, expr, CName ## _if_r));}
  8599. #endif /* gmp */
  8600. /* -------- RF_TO_PF -------- */
  8601. typedef s7_pointer (*rf_pf_t)(s7_scheme *sc, s7_double x);
  8602. static s7_pointer rf_p_1(s7_scheme *sc, s7_pointer **p, rf_pf_t fnc)
  8603. {
  8604. s7_rf_t f;
  8605. s7_double x;
  8606. f = (s7_rf_t)(**p); (*p)++;
  8607. x = f(sc, p);
  8608. return(fnc(sc, x));
  8609. }
  8610. #if (!WITH_GMP)
  8611. static s7_pf_t rf_pf_1(s7_scheme *sc, s7_pointer expr, s7_pf_t f)
  8612. {
  8613. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))) && (s7_arg_to_rf(sc, cadr(expr))))
  8614. return(f);
  8615. return(NULL);
  8616. }
  8617. #define RF_TO_PF(CName, Pfnc) \
  8618. static s7_pointer CName ## _pf_r(s7_scheme *sc, s7_pointer **rp) {return(rf_p_1(sc, rp, Pfnc));} \
  8619. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(rf_pf_1(sc, expr, CName ## _pf_r));}
  8620. /* -------- RF_TO_RF -------- */
  8621. typedef s7_double (*rf_rf_t)(s7_scheme *sc, s7_double x);
  8622. static s7_double rf_rf_1(s7_scheme *sc, s7_pointer **p, rf_rf_t fnc)
  8623. {
  8624. s7_rf_t f;
  8625. s7_double x;
  8626. f = (s7_rf_t)(**p); (*p)++;
  8627. x = f(sc, p);
  8628. return(fnc(sc, x));
  8629. }
  8630. static s7_rf_t rf_1(s7_scheme *sc, s7_pointer expr, s7_rf_t f)
  8631. {
  8632. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))) && (s7_arg_to_rf(sc, cadr(expr))))
  8633. return(f);
  8634. return(NULL);
  8635. }
  8636. #define RF_TO_RF(CName, Rfnc) \
  8637. static s7_double CName ## _rf_r(s7_scheme *sc, s7_pointer **rp) {return(rf_rf_1(sc, rp, Rfnc));} \
  8638. static s7_rf_t CName ## _rf(s7_scheme *sc, s7_pointer expr) {return(rf_1(sc, expr, CName ## _rf_r));}
  8639. #define DIRECT_RF_TO_RF(CName) \
  8640. static s7_double CName ## _rf_r(s7_scheme *sc, s7_pointer **p) {s7_rf_t f; s7_double x; f = (s7_rf_t)(**p); (*p)++; x = f(sc, p); return(CName(x));} \
  8641. static s7_rf_t CName ## _rf(s7_scheme *sc, s7_pointer expr) {if (s7_arg_to_rf(sc, s7_cadr(expr))) return(CName ## _rf_r); return(NULL);}
  8642. /* -------- RF2_TO_RF -------- */
  8643. typedef s7_double (*rf2_rf_t)(s7_scheme *sc, s7_double x, s7_double y);
  8644. static s7_double rf2_rf_1(s7_scheme *sc, s7_pointer **p, rf2_rf_t fnc)
  8645. {
  8646. s7_rf_t f;
  8647. s7_double x, y;
  8648. f = (s7_rf_t)(**p); (*p)++;
  8649. x = f(sc, p);
  8650. f = (s7_rf_t)(**p); (*p)++;
  8651. y = f(sc, p);
  8652. return(fnc(sc, x, y));
  8653. }
  8654. static s7_rf_t rf_2(s7_scheme *sc, s7_pointer expr, s7_rf_t f)
  8655. {
  8656. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))) &&
  8657. (s7_arg_to_rf(sc, cadr(expr))) &&
  8658. (s7_arg_to_rf(sc, caddr(expr))))
  8659. return(f);
  8660. return(NULL);
  8661. }
  8662. #define RF2_TO_RF(CName, Rfnc) \
  8663. static s7_double CName ## _rf_r2(s7_scheme *sc, s7_pointer **rp) {return(rf2_rf_1(sc, rp, Rfnc));} \
  8664. static s7_rf_t CName ## _rf(s7_scheme *sc, s7_pointer expr) {return(rf_2(sc, expr, CName ## _rf_r2));}
  8665. /* -------- RF_3_TO_RF -------- */
  8666. typedef s7_double (*rf3_rf_t)(s7_scheme *sc, s7_double x, s7_double y, s7_double z);
  8667. static s7_double rf3_rf_1(s7_scheme *sc, s7_pointer **p, rf3_rf_t fnc)
  8668. {
  8669. s7_rf_t f;
  8670. s7_double x, y, z;
  8671. f = (s7_rf_t)(**p); (*p)++;
  8672. x = f(sc, p);
  8673. f = (s7_rf_t)(**p); (*p)++;
  8674. y = f(sc, p);
  8675. f = (s7_rf_t)(**p); (*p)++;
  8676. z = f(sc, p);
  8677. return(fnc(sc, x, y, z));
  8678. }
  8679. static s7_rf_t rf_3(s7_scheme *sc, s7_pointer expr, s7_rf_t f1, s7_rf_t f2, s7_rf_t f3)
  8680. {
  8681. if (!is_pair(cdr(expr))) return(NULL);
  8682. if (!s7_arg_to_rf(sc, cadr(expr))) return(NULL);
  8683. if (is_null(cddr(expr))) return(f1);
  8684. if (!s7_arg_to_rf(sc, caddr(expr))) return(NULL);
  8685. if (is_null(cdddr(expr))) return(f2);
  8686. if (!s7_arg_to_rf(sc, cadddr(expr))) return(NULL);
  8687. if (is_null(cddddr(expr))) return(f3);
  8688. return(NULL);
  8689. }
  8690. #define RF_3_TO_RF(CName, Rfnc1, Rfnc2, Rfnc3) \
  8691. static s7_double CName ## _rf_r1(s7_scheme *sc, s7_pointer **rp) {return(rf_rf_1(sc, rp, Rfnc1));} \
  8692. static s7_double CName ## _rf_r2(s7_scheme *sc, s7_pointer **rp) {return(rf2_rf_1(sc, rp, Rfnc2));} \
  8693. static s7_double CName ## _rf_r3(s7_scheme *sc, s7_pointer **rp) {return(rf3_rf_1(sc, rp, Rfnc3));} \
  8694. static s7_rf_t CName ## _rf(s7_scheme *sc, s7_pointer expr) {return(rf_3(sc, expr, CName ## _rf_r1, CName ## _rf_r2, CName ## _rf_r3));}
  8695. /* -------- R_P_F_TO_PF -------- */
  8696. static s7_pf_t rpf_pf_1(s7_scheme *sc, s7_pointer expr, s7_pf_t fnc1, s7_pf_t fnc2, s7_pf_t fnc3)
  8697. {
  8698. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))))
  8699. {
  8700. ptr_int loc;
  8701. loc = rc_loc(sc);
  8702. if (s7_arg_to_rf(sc, cadr(expr))) return(fnc1);
  8703. sc->cur_rf->cur = rc_go(sc, loc);
  8704. if (s7_arg_to_pf(sc, cadr(expr))) return(fnc2);
  8705. sc->cur_rf->cur = rc_go(sc, loc);
  8706. if (s7_arg_to_gf(sc, cadr(expr))) return(fnc3);
  8707. }
  8708. return(NULL);
  8709. }
  8710. #define R_P_F_TO_PF(CName, PFnc1, PFnc2, PFnc3) \
  8711. static s7_pointer CName ## _pf_r(s7_scheme *sc, s7_pointer **rp) {return(rf_p_1(sc, rp, PFnc1));} \
  8712. static s7_pointer CName ## _pf_p(s7_scheme *sc, s7_pointer **rp) {return(pf_pf_1(sc, rp, PFnc2));} \
  8713. static s7_pointer CName ## _pf_g(s7_scheme *sc, s7_pointer **rp) {return(pf_pf_1(sc, rp, PFnc3));} \
  8714. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(rpf_pf_1(sc, expr, CName ## _pf_r, CName ## _pf_p, CName ## _pf_g));}
  8715. #endif /* gmp */
  8716. /* -------- XF_TO_PF -------- */
  8717. static s7_pf_t xf_pf_1(s7_scheme *sc, s7_pointer expr, s7_pf_t f1, s7_pf_t f2, s7_pf_t f3)
  8718. {
  8719. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))))
  8720. {
  8721. ptr_int loc;
  8722. loc = rc_loc(sc);
  8723. if (s7_arg_to_if(sc, cadr(expr))) return(f1);
  8724. sc->cur_rf->cur = rc_go(sc, loc);
  8725. if (s7_arg_to_rf(sc, cadr(expr))) return(f2);
  8726. sc->cur_rf->cur = rc_go(sc, loc);
  8727. if (s7_arg_to_pf(sc, cadr(expr))) return(f3);
  8728. }
  8729. return(NULL);
  8730. }
  8731. #define XF_TO_PF(CName, PFnc1, PFnc2, PFnc3) \
  8732. static s7_pointer CName ## _pf_i(s7_scheme *sc, s7_pointer **rp) {return(if_p_1(sc, rp, PFnc1));} \
  8733. static s7_pointer CName ## _pf_r(s7_scheme *sc, s7_pointer **rp) {return(rf_p_1(sc, rp, PFnc2));} \
  8734. static s7_pointer CName ## _pf_p(s7_scheme *sc, s7_pointer **rp) {return(pf_pf_1(sc, rp, PFnc3));} \
  8735. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) {return(xf_pf_1(sc, expr, CName ## _pf_i, CName ## _pf_r, CName ## _pf_p));}
  8736. /* -------- XF2_TO_PF -------- */
  8737. typedef s7_pointer (*if2_pf_t)(s7_scheme *sc, s7_int x, s7_int y);
  8738. typedef s7_pointer (*rf2_pf_t)(s7_scheme *sc, s7_double x, s7_double y);
  8739. static s7_pointer if2_pf_1(s7_scheme *sc, s7_pointer **p, if2_pf_t fnc)
  8740. {
  8741. s7_if_t f;
  8742. s7_int x, y;
  8743. f = (s7_if_t)(**p); (*p)++; x = f(sc, p);
  8744. f = (s7_if_t)(**p); (*p)++; y = f(sc, p);
  8745. return(fnc(sc, x, y));
  8746. }
  8747. static s7_pointer rf2_pf_1(s7_scheme *sc, s7_pointer **p, rf2_pf_t fnc)
  8748. {
  8749. s7_rf_t f;
  8750. s7_double x, y;
  8751. f = (s7_rf_t)(**p); (*p)++; x = f(sc, p);
  8752. f = (s7_rf_t)(**p); (*p)++; y = f(sc, p);
  8753. return(fnc(sc, x, y));
  8754. }
  8755. static s7_pointer rf2_pf_sc(s7_scheme *sc, s7_pointer **p, rf2_pf_t fnc)
  8756. {
  8757. s7_pointer xp, yp;
  8758. (*p)++;
  8759. xp = slot_value(**p); (*p) += 2;
  8760. yp = (**p); (*p)++;
  8761. if ((is_t_real(xp)) && (is_t_real(yp)))
  8762. return(fnc(sc, real(xp), real(yp)));
  8763. return(fnc(sc, s7_number_to_real(sc, xp), s7_number_to_real(sc, yp)));
  8764. }
  8765. static s7_pf_t xf2_pf_1(s7_scheme *sc, s7_pointer expr, s7_pf_t f1, s7_pf_t f2, s7_pf_t f3, s7_pf_t f4, s7_pf_t f5)
  8766. {
  8767. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_null(cdddr(expr))))
  8768. {
  8769. ptr_int loc;
  8770. s7_pointer a1, a2;
  8771. a1 = cadr(expr);
  8772. a2 = caddr(expr);
  8773. if ((is_symbol(a1)) && (is_symbol(a2)))
  8774. {
  8775. a1 = s7_slot(sc, a1);
  8776. if (!is_slot(a1)) return(NULL);
  8777. s7_xf_store(sc, a1);
  8778. a2 = s7_slot(sc, a2);
  8779. if (!is_slot(a2)) return(NULL);
  8780. s7_xf_store(sc, a2);
  8781. return(f5);
  8782. }
  8783. loc = rc_loc(sc);
  8784. if ((s7_arg_to_if(sc, a1)) && (s7_arg_to_if(sc, a2))) return(f1);
  8785. sc->cur_rf->cur = rc_go(sc, loc);
  8786. if ((s7_arg_to_rf(sc, a1)) && (s7_arg_to_rf(sc, a2))) return(((is_symbol(a1)) && (is_real(a2))) ? f3 : f2);
  8787. sc->cur_rf->cur = rc_go(sc, loc);
  8788. if ((s7_arg_to_pf(sc, a1)) && (s7_arg_to_pf(sc, a2))) return(f4);
  8789. }
  8790. return(NULL);
  8791. }
  8792. #define XF2_TO_PF(CName, PFnc1, PFnc2, PFnc3) \
  8793. static s7_pointer CName ## _pf_i2(s7_scheme *sc, s7_pointer **rp) {return(if2_pf_1(sc, rp, PFnc1));} \
  8794. static s7_pointer CName ## _pf_r2(s7_scheme *sc, s7_pointer **rp) {return(rf2_pf_1(sc, rp, PFnc2));} \
  8795. static s7_pointer CName ## _pf_r2_sc(s7_scheme *sc, s7_pointer **rp) {return(rf2_pf_sc(sc, rp, PFnc2));} \
  8796. static s7_pointer CName ## _pf_p2(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_1(sc, rp, PFnc3));} \
  8797. static s7_pointer CName ## _pf_ss(s7_scheme *sc, s7_pointer **rp) {return(pf2_pf_ss(sc, rp, PFnc3));} \
  8798. static s7_pf_t CName ## _pf(s7_scheme *sc, s7_pointer expr) \
  8799. {\
  8800. return(xf2_pf_1(sc, expr, CName ## _pf_i2, CName ## _pf_r2, CName ## _pf_r2_sc, CName ## _pf_p2, CName ## _pf_ss)); \
  8801. }
  8802. #if WITH_OPTIMIZATION
  8803. static s7_pointer if_pf_xx(s7_scheme *sc, s7_pointer **p)
  8804. {
  8805. s7_pf_t test, t;
  8806. s7_pointer val;
  8807. ptr_int e1;
  8808. test = (s7_pf_t)(**p); (*p)++;
  8809. t = (s7_pf_t)(**p); (*p)++;
  8810. e1 = (ptr_int)(**p); (*p)++;
  8811. val = test(sc, p);
  8812. if (val != sc->F)
  8813. val = t(sc, p);
  8814. else val = sc->unspecified;
  8815. (*p) = rc_go(sc, e1);
  8816. return(val);
  8817. }
  8818. static s7_pointer if_pf_not_xx(s7_scheme *sc, s7_pointer **p)
  8819. {
  8820. s7_pf_t test, t;
  8821. s7_pointer val;
  8822. ptr_int e1;
  8823. test = (s7_pf_t)(**p); (*p)++;
  8824. t = (s7_pf_t)(**p); (*p)++;
  8825. e1 = (ptr_int)(**p); (*p)++;
  8826. val = test(sc, p);
  8827. if (val == sc->F)
  8828. val = t(sc, p);
  8829. else val = sc->unspecified;
  8830. (*p) = rc_go(sc, e1);
  8831. return(val);
  8832. }
  8833. #if (!WITH_GMP)
  8834. static s7_pointer equal_p2(s7_scheme *sc, s7_pointer **p);
  8835. #endif
  8836. static s7_pointer c_equal_2(s7_scheme *sc, s7_pointer x, s7_pointer y);
  8837. static s7_pointer if_pf_not_equal_2(s7_scheme *sc, s7_pointer **p)
  8838. {
  8839. s7_pf_t t, eq2;
  8840. s7_pointer val, x, y;
  8841. ptr_int e1;
  8842. (*p)++;
  8843. t = (s7_pf_t)(**p); (*p)++;
  8844. e1 = (ptr_int)(**p); (*p)++;
  8845. eq2 = (s7_pf_t)(**p); (*p)++;
  8846. x = eq2(sc, p);
  8847. eq2 = (s7_pf_t)(**p); (*p)++;
  8848. y = eq2(sc, p);
  8849. if (c_equal_2(sc, x, y) == sc->F)
  8850. val = t(sc, p);
  8851. else val = sc->unspecified;
  8852. (*p) = rc_go(sc, e1);
  8853. return(val);
  8854. }
  8855. static s7_pointer if_pf_xxx(s7_scheme *sc, s7_pointer **p)
  8856. {
  8857. s7_pointer x;
  8858. s7_pf_t r1, r2;
  8859. s7_pf_t pf;
  8860. s7_pointer val;
  8861. ptr_int e1, e2;
  8862. pf = (s7_pf_t)(**p); (*p)++;
  8863. r1 = (s7_pf_t)(**p); (*p)++;
  8864. e1 = (ptr_int)(**p); (*p)++;
  8865. r2 = (s7_pf_t)(**p); (*p)++;
  8866. e2 = (ptr_int)(**p); (*p)++;
  8867. val = pf(sc, p);
  8868. if (val != sc->F)
  8869. {
  8870. x = r1(sc, p);
  8871. (*p) = rc_go(sc, e2);
  8872. }
  8873. else
  8874. {
  8875. (*p) = rc_go(sc, e1);
  8876. x = r2(sc, p);
  8877. }
  8878. return(x);
  8879. }
  8880. static s7_pf_t if_pf(s7_scheme *sc, s7_pointer expr)
  8881. {
  8882. s7_pointer test, t, f = NULL;
  8883. s7_int test_loc, t_loc, f_loc = 0, e1_loc, e2_loc = 0;
  8884. bool not_case = false;
  8885. ptr_int loc;
  8886. xf_t *rc;
  8887. if ((is_null(cdr(expr))) || (is_null(cddr(expr)))) return(NULL);
  8888. test = cadr(expr);
  8889. if ((is_pair(test)) && (car(test) == sc->not_symbol))
  8890. {
  8891. not_case = true;
  8892. test = cadr(test);
  8893. }
  8894. t = caddr(expr);
  8895. xf_init(5);
  8896. xf_save_loc3(test_loc, t_loc, e1_loc);
  8897. if (is_pair(cdddr(expr)))
  8898. {
  8899. f = cadddr(expr);
  8900. xf_save_loc2(f_loc, e2_loc);
  8901. }
  8902. if (!arg_to_pf(sc, test, test_loc)) return(NULL);
  8903. loc = rc_loc(sc);
  8904. if (!arg_to_pf(sc, t, t_loc))
  8905. {
  8906. sc->cur_rf->cur = rc_go(sc, loc);
  8907. if (!arg_to_if(sc, t, t_loc)) return(NULL);
  8908. }
  8909. xf_store_at(e1_loc, (s7_pointer)rc_loc(sc));
  8910. if (f)
  8911. {
  8912. if (!arg_to_pf(sc, f, f_loc)) return(NULL);
  8913. xf_store_at(e2_loc, (s7_pointer)rc_loc(sc));
  8914. }
  8915. if (!f)
  8916. {
  8917. if (not_case)
  8918. {
  8919. #if (!WITH_GMP)
  8920. if ((s7_pointer)equal_p2 == sc->cur_rf->data[test_loc])
  8921. return(if_pf_not_equal_2);
  8922. #endif
  8923. return(if_pf_not_xx);
  8924. }
  8925. return(if_pf_xx);
  8926. }
  8927. return(if_pf_xxx);
  8928. }
  8929. static s7_double if_rf_xxx(s7_scheme *sc, s7_pointer **p)
  8930. {
  8931. s7_double x;
  8932. s7_rf_t r1, r2;
  8933. s7_pf_t pf;
  8934. s7_pointer val;
  8935. ptr_int e1, e2;
  8936. pf = (s7_pf_t)(**p); (*p)++;
  8937. r1 = (s7_rf_t)(**p); (*p)++;
  8938. r2 = (s7_rf_t)(**p); (*p)++;
  8939. e1 = (ptr_int)(**p); (*p)++;
  8940. e2 = (ptr_int)(**p); (*p)++;
  8941. val = pf(sc, p);
  8942. if (val != sc->F)
  8943. {
  8944. x = r1(sc, p);
  8945. (*p) = rc_go(sc, e2);
  8946. }
  8947. else
  8948. {
  8949. (*p) = rc_go(sc, e1);
  8950. x = r2(sc, p);
  8951. }
  8952. return(x);
  8953. }
  8954. static s7_rf_t if_rf(s7_scheme *sc, s7_pointer expr)
  8955. {
  8956. s7_pointer test, t, f;
  8957. s7_int test_loc, t_loc, f_loc = 0, e1_loc = 0, e2_loc;
  8958. xf_t *rc;
  8959. if ((is_null(cdr(expr))) || (is_null(cddr(expr))) || (is_null(cdddr(expr)))) return(NULL);
  8960. test = cadr(expr);
  8961. t = caddr(expr);
  8962. f = cadddr(expr);
  8963. xf_init(5);
  8964. xf_save_loc3(test_loc, t_loc, f_loc);
  8965. xf_save_loc2(e1_loc, e2_loc);
  8966. if (!arg_to_pf(sc, test, test_loc)) return(NULL);
  8967. if (!arg_to_rf(sc, t, t_loc)) return(NULL);
  8968. xf_store_at(e1_loc, (s7_pointer)rc_loc(sc));
  8969. if (!arg_to_rf(sc, f, f_loc)) return(NULL);
  8970. xf_store_at(e2_loc, (s7_pointer)rc_loc(sc));
  8971. return(if_rf_xxx);
  8972. }
  8973. static s7_pointer quote_pf_s(s7_scheme *sc, s7_pointer **p)
  8974. {
  8975. s7_pointer s;
  8976. s = **p; (*p)++;
  8977. return(s);
  8978. }
  8979. static s7_pf_t quote_pf(s7_scheme *sc, s7_pointer expr)
  8980. {
  8981. if (is_symbol(cadr(expr)))
  8982. {
  8983. xf_t *rc;
  8984. xf_init(1);
  8985. xf_store(cadr(expr));
  8986. return(quote_pf_s);
  8987. }
  8988. return(NULL);
  8989. }
  8990. static s7_pointer or_pf_xx(s7_scheme *sc, s7_pointer **p)
  8991. {
  8992. s7_pf_t pf1, pf2;
  8993. ptr_int e1;
  8994. s7_pointer val;
  8995. pf1 = (s7_pf_t)(**p); (*p)++;
  8996. pf2 = (s7_pf_t)(**p); (*p)++;
  8997. e1 = (ptr_int)(**p); (*p)++;
  8998. val = pf1(sc, p);
  8999. if (val != sc->F)
  9000. {
  9001. (*p) = rc_go(sc, e1);
  9002. return(val);
  9003. }
  9004. return(pf2(sc, p));
  9005. }
  9006. static s7_pf_t or_pf(s7_scheme *sc, s7_pointer expr)
  9007. {
  9008. int len;
  9009. len = s7_list_length(sc, expr);
  9010. if (len == 3)
  9011. {
  9012. int loc1, loc2, eloc;
  9013. xf_t *rc;
  9014. xf_init(3);
  9015. xf_save_loc3(loc1, loc2, eloc);
  9016. if (!arg_to_pf(sc, cadr(expr), loc1)) return(NULL);
  9017. if (!arg_to_pf(sc, caddr(expr), loc2)) return(NULL);
  9018. xf_store_at(eloc, (s7_pointer)rc_loc(sc));
  9019. return(or_pf_xx);
  9020. }
  9021. return(NULL);
  9022. }
  9023. static s7_pointer and_pf_xx(s7_scheme *sc, s7_pointer **p)
  9024. {
  9025. s7_pf_t pf1, pf2;
  9026. ptr_int e1;
  9027. pf1 = (s7_pf_t)(**p); (*p)++;
  9028. pf2 = (s7_pf_t)(**p); (*p)++;
  9029. e1 = (ptr_int)(**p); (*p)++;
  9030. if (pf1(sc, p) == sc->F)
  9031. {
  9032. (*p) = rc_go(sc, e1);
  9033. return(sc->F);
  9034. }
  9035. return(pf2(sc, p));
  9036. }
  9037. static s7_pf_t and_pf(s7_scheme *sc, s7_pointer expr)
  9038. {
  9039. int len;
  9040. len = s7_list_length(sc, expr);
  9041. if (len == 3)
  9042. {
  9043. s7_int loc1, loc2, eloc;
  9044. xf_t *rc;
  9045. xf_init(3);
  9046. xf_save_loc3(loc1, loc2, eloc);
  9047. if (!arg_to_pf(sc, cadr(expr), loc1)) return(NULL);
  9048. if (!arg_to_pf(sc, caddr(expr), loc2)) return(NULL);
  9049. xf_store_at(eloc, (s7_pointer)rc_loc(sc));
  9050. return(and_pf_xx);
  9051. }
  9052. return(NULL);
  9053. }
  9054. #endif
  9055. /* -------------------------------- continuations and gotos -------------------------------- */
  9056. static s7_pointer g_is_continuation(s7_scheme *sc, s7_pointer args)
  9057. {
  9058. #define H_is_continuation "(continuation? obj) returns #t if obj is a continuation"
  9059. #define Q_is_continuation pl_bt
  9060. check_boolean_method(sc, is_continuation, sc->is_continuation_symbol, args);
  9061. /* is this the right thing? It returns #f for call-with-exit ("goto") because
  9062. * that form of continuation can't continue (via a jump back to its context).
  9063. * how to recognize the call-with-exit function? "goto" is an internal name.
  9064. */
  9065. }
  9066. static s7_pointer protected_list_copy(s7_scheme *sc, s7_pointer a)
  9067. {
  9068. s7_pointer slow, fast, p;
  9069. sc->w = cons(sc, car(a), sc->nil);
  9070. p = sc->w;
  9071. slow = fast = cdr(a);
  9072. while (true)
  9073. {
  9074. if (!is_pair(fast))
  9075. {
  9076. if (is_null(fast))
  9077. return(sc->w);
  9078. set_cdr(p, fast);
  9079. return(sc->w);
  9080. }
  9081. set_cdr(p, cons(sc, car(fast), sc->nil));
  9082. p = cdr(p);
  9083. fast = cdr(fast);
  9084. if (!is_pair(fast))
  9085. {
  9086. if (is_null(fast))
  9087. return(sc->w);
  9088. set_cdr(p, fast);
  9089. return(sc->w);
  9090. }
  9091. /* if unrolled further, it's a lot slower? */
  9092. set_cdr(p, cons(sc, car(fast), sc->nil));
  9093. p = cdr(p);
  9094. fast = cdr(fast);
  9095. slow = cdr(slow);
  9096. if (fast == slow)
  9097. {
  9098. /* try to preserve the original cyclic structure */
  9099. s7_pointer p1, f1, p2, f2;
  9100. set_match_pair(a);
  9101. for (p1 = sc->w, f1 = a; !(is_matched_pair(cdr(f1))); f1 = cdr(f1), p1 = cdr(p1))
  9102. set_match_pair(f1);
  9103. for (p2 = sc->w, f2 = a; cdr(f1) != f2; f2 = cdr(f2), p2 = cdr(p2))
  9104. clear_match_pair(f2);
  9105. for (f1 = f2; is_pair(f1); f1 = cdr(f1), f2 = cdr(f2))
  9106. {
  9107. clear_match_pair(f1);
  9108. f1 = cdr(f1);
  9109. clear_match_pair(f1);
  9110. if (f1 == f2) break;
  9111. }
  9112. if (is_null(p1))
  9113. set_cdr(p2, p2);
  9114. else set_cdr(p1, p2);
  9115. return(sc->w);
  9116. }
  9117. }
  9118. return(sc->w);
  9119. }
  9120. static s7_pointer copy_counter(s7_scheme *sc, s7_pointer obj)
  9121. {
  9122. s7_pointer nobj;
  9123. new_cell(sc, nobj, T_COUNTER);
  9124. counter_set_result(nobj, counter_result(obj));
  9125. counter_set_list(nobj, counter_list(obj));
  9126. counter_set_capture(nobj, counter_capture(obj));
  9127. counter_set_let(nobj, counter_let(obj));
  9128. counter_set_slots(nobj, counter_slots(obj));
  9129. return(nobj);
  9130. }
  9131. static s7_pointer copy_stack(s7_scheme *sc, s7_pointer old_v, int top)
  9132. {
  9133. #define CC_INITIAL_STACK_SIZE 256 /* 128 is too small here */
  9134. int i, len;
  9135. s7_pointer new_v;
  9136. s7_pointer *nv, *ov;
  9137. /* stacks can grow temporarily, so sc->stack_size grows, but we don't normally need all that
  9138. * leftover space here, so choose the original stack size if it's smaller.
  9139. */
  9140. len = vector_length(old_v);
  9141. if (len > CC_INITIAL_STACK_SIZE)
  9142. {
  9143. if (top < CC_INITIAL_STACK_SIZE / 4)
  9144. len = CC_INITIAL_STACK_SIZE;
  9145. }
  9146. else
  9147. {
  9148. if (len < CC_INITIAL_STACK_SIZE)
  9149. len = CC_INITIAL_STACK_SIZE;
  9150. }
  9151. if ((int)(sc->free_heap_top - sc->free_heap) < (int)(sc->heap_size / 4)) gc(sc);
  9152. /* this gc call is needed if there are lots of call/cc's -- by pure bad luck
  9153. * we can end up hitting the end of the gc free list time after time while
  9154. * in successive copy_stack's below, causing s7 to core up until it runs out of memory.
  9155. */
  9156. new_v = make_vector_1(sc, len, NOT_FILLED, T_VECTOR);
  9157. set_type(new_v, T_STACK);
  9158. temp_stack_top(new_v) = top;
  9159. nv = vector_elements(new_v);
  9160. ov = vector_elements(old_v);
  9161. if (len > 0)
  9162. memcpy((void *)nv, (void *)ov, len * sizeof(s7_pointer));
  9163. s7_gc_on(sc, false);
  9164. for (i = 2; i < top; i += 4)
  9165. {
  9166. s7_pointer p;
  9167. p = ov[i]; /* args */
  9168. if (is_pair(p)) /* args need not be a list (it can be a port or #f, etc) */
  9169. nv[i] = protected_list_copy(sc, p); /* args (copy is needed -- see s7test.scm) */
  9170. /* lst can be dotted or circular here. The circular list only happens in a case like:
  9171. * (dynamic-wind (lambda () (eq? (let ((lst (cons 1 2))) (set-cdr! lst lst) lst) (call/cc (lambda (k) k)))) (lambda () #f) (lambda () #f))
  9172. */
  9173. else
  9174. {
  9175. if (is_counter(p)) /* these can only occur in this context */
  9176. nv[i] = copy_counter(sc, p);
  9177. }
  9178. }
  9179. s7_gc_on(sc, true);
  9180. return(new_v);
  9181. }
  9182. static s7_pointer make_goto(s7_scheme *sc)
  9183. {
  9184. s7_pointer x;
  9185. new_cell(sc, x, T_GOTO | T_PROCEDURE);
  9186. call_exit_goto_loc(x) = s7_stack_top(sc);
  9187. call_exit_op_loc(x) = (int)(sc->op_stack_now - sc->op_stack);
  9188. call_exit_active(x) = true;
  9189. return(x);
  9190. }
  9191. static s7_pointer *copy_op_stack(s7_scheme *sc)
  9192. {
  9193. int len;
  9194. s7_pointer *ops;
  9195. ops = (s7_pointer *)malloc(sc->op_stack_size * sizeof(s7_pointer));
  9196. len = (int)(sc->op_stack_now - sc->op_stack);
  9197. if (len > 0)
  9198. memcpy((void *)ops, (void *)(sc->op_stack), len * sizeof(s7_pointer));
  9199. return(ops);
  9200. }
  9201. /* (with-baffle . body) calls body guaranteeing that there can be no jumps into the
  9202. * middle of it from outside -- no outer evaluation of a continuation can jump across this
  9203. * barrier: The flip-side of call-with-exit.
  9204. * It sets a T_BAFFLE var in a new env, that has a unique key. Call/cc then always
  9205. * checks the env chain for any such variable, saving the localmost. Apply of a continuation
  9206. * looks for such a saved variable, if none, go ahead, else check the current env (before the
  9207. * jump) for that variable. If none, error, else go ahead. This is different from a delimited
  9208. * continuation which simply delimits the extent of the continuation (why not use lambda?) -- we want to block it
  9209. * from coming at us from some unknown place.
  9210. */
  9211. static s7_pointer make_baffle(s7_scheme *sc)
  9212. {
  9213. s7_pointer x;
  9214. new_cell(sc, x, T_BAFFLE);
  9215. baffle_key(x) = sc->baffle_ctr++;
  9216. return(x);
  9217. }
  9218. static bool find_baffle(s7_scheme *sc, int key)
  9219. {
  9220. /* search backwards through sc->envir for sc->baffle_symbol with key as value
  9221. */
  9222. s7_pointer x, y;
  9223. for (x = sc->envir; is_let(x); x = outlet(x))
  9224. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  9225. if ((slot_symbol(y) == sc->baffle_symbol) &&
  9226. (baffle_key(slot_value(y)) == key))
  9227. return(true);
  9228. if ((is_slot(global_slot(sc->baffle_symbol))) &&
  9229. (is_baffle(slot_value(global_slot(sc->baffle_symbol)))))
  9230. return(baffle_key(slot_value(global_slot(sc->baffle_symbol))) == key);
  9231. return(false);
  9232. }
  9233. static int find_any_baffle(s7_scheme *sc)
  9234. {
  9235. /* search backwards through sc->envir for any sc->baffle_symbol
  9236. */
  9237. if (sc->baffle_ctr > 0)
  9238. {
  9239. s7_pointer x, y;
  9240. for (x = sc->envir; is_let(x); x = outlet(x))
  9241. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  9242. if (slot_symbol(y) == sc->baffle_symbol)
  9243. return(baffle_key(slot_value(y)));
  9244. if ((is_slot(global_slot(sc->baffle_symbol))) &&
  9245. (is_baffle(slot_value(global_slot(sc->baffle_symbol)))))
  9246. return(baffle_key(slot_value(global_slot(sc->baffle_symbol))));
  9247. }
  9248. return(-1);
  9249. }
  9250. s7_pointer s7_make_continuation(s7_scheme *sc)
  9251. {
  9252. s7_pointer x, stack;
  9253. int loc;
  9254. loc = s7_stack_top(sc);
  9255. stack = copy_stack(sc, sc->stack, loc);
  9256. sc->temp8 = stack;
  9257. new_cell(sc, x, T_CONTINUATION | T_PROCEDURE);
  9258. continuation_data(x) = (continuation_t *)malloc(sizeof(continuation_t));
  9259. continuation_set_stack(x, stack);
  9260. continuation_stack_size(x) = vector_length(continuation_stack(x)); /* copy_stack can return a smaller stack than the current one */
  9261. continuation_stack_start(x) = vector_elements(continuation_stack(x));
  9262. continuation_stack_end(x) = (s7_pointer *)(continuation_stack_start(x) + loc);
  9263. continuation_op_stack(x) = copy_op_stack(sc); /* no heap allocation here */
  9264. continuation_op_loc(x) = (int)(sc->op_stack_now - sc->op_stack);
  9265. continuation_op_size(x) = sc->op_stack_size;
  9266. continuation_key(x) = find_any_baffle(sc);
  9267. add_continuation(sc, x);
  9268. return(x);
  9269. }
  9270. static bool check_for_dynamic_winds(s7_scheme *sc, s7_pointer c)
  9271. {
  9272. int i, s_base = 0, c_base = -1;
  9273. opcode_t op;
  9274. for (i = s7_stack_top(sc) - 1; i > 0; i -= 4)
  9275. {
  9276. op = stack_op(sc->stack, i);
  9277. switch (op)
  9278. {
  9279. case OP_DYNAMIC_WIND:
  9280. {
  9281. s7_pointer x;
  9282. int j;
  9283. x = stack_code(sc->stack, i);
  9284. for (j = 3; j < continuation_stack_top(c); j += 4)
  9285. if ((stack_op(continuation_stack(c), j) == OP_DYNAMIC_WIND) &&
  9286. (x == stack_code(continuation_stack(c), j)))
  9287. {
  9288. s_base = i;
  9289. c_base = j;
  9290. break;
  9291. }
  9292. if (s_base != 0)
  9293. break;
  9294. if (dynamic_wind_state(x) == DWIND_BODY)
  9295. {
  9296. dynamic_wind_state(x) = DWIND_FINISH;
  9297. if (dynamic_wind_out(x) != sc->F)
  9298. {
  9299. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  9300. sc->args = sc->nil;
  9301. sc->code = dynamic_wind_out(x);
  9302. eval(sc, OP_APPLY);
  9303. }
  9304. }
  9305. }
  9306. break;
  9307. case OP_BARRIER:
  9308. if (i > continuation_stack_top(c)) /* otherwise it's some unproblematic outer eval-string? */
  9309. return(false); /* but what if we've already evaluated a dynamic-wind closer? */
  9310. break;
  9311. case OP_DEACTIVATE_GOTO: /* here we're jumping out of an unrelated call-with-exit block */
  9312. if (i > continuation_stack_top(c))
  9313. call_exit_active(stack_args(sc->stack, i)) = false;
  9314. break;
  9315. default:
  9316. break;
  9317. }
  9318. }
  9319. for (i = c_base + 4; i < continuation_stack_top(c); i += 4)
  9320. {
  9321. op = stack_op(continuation_stack(c), i);
  9322. if (op == OP_DYNAMIC_WIND)
  9323. {
  9324. s7_pointer x;
  9325. x = stack_code(continuation_stack(c), i);
  9326. if (dynamic_wind_in(x) != sc->F)
  9327. {
  9328. /* this can cause an infinite loop if the call/cc is trying to jump back into
  9329. * a dynamic-wind init function -- it's even possible to trick with-baffle!
  9330. * I can't find any fool-proof way to catch this problem.
  9331. */
  9332. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  9333. sc->args = sc->nil;
  9334. sc->code = dynamic_wind_in(x);
  9335. eval(sc, OP_APPLY);
  9336. }
  9337. dynamic_wind_state(x) = DWIND_BODY;
  9338. }
  9339. else
  9340. {
  9341. if (op == OP_DEACTIVATE_GOTO)
  9342. call_exit_active(stack_args(continuation_stack(c), i)) = true;
  9343. }
  9344. }
  9345. return(true);
  9346. }
  9347. static bool call_with_current_continuation(s7_scheme *sc)
  9348. {
  9349. s7_pointer c;
  9350. c = sc->code;
  9351. /* check for (baffle ...) blocking the current attempt to continue */
  9352. if ((continuation_key(c) >= 0) &&
  9353. (!(find_baffle(sc, continuation_key(c))))) /* should this raise an error? */
  9354. return(false);
  9355. if (!check_for_dynamic_winds(sc, c)) /* if OP_BARRIER on stack deeper than continuation top(?), but can this happen? (it doesn't in s7test) */
  9356. return(true);
  9357. /* we push_stack sc->code before calling an embedded eval above, so sc->code should still be c here, etc
  9358. */
  9359. sc->stack = copy_stack(sc, continuation_stack(c), continuation_stack_top(c));
  9360. sc->stack_size = continuation_stack_size(c);
  9361. sc->stack_start = vector_elements(sc->stack);
  9362. sc->stack_end = (s7_pointer *)(sc->stack_start + continuation_stack_top(c));
  9363. sc->stack_resize_trigger = (s7_pointer *)(sc->stack_start + sc->stack_size / 2);
  9364. {
  9365. int i, top;
  9366. top = continuation_op_loc(c);
  9367. sc->op_stack_now = (s7_pointer *)(sc->op_stack + top);
  9368. sc->op_stack_size = continuation_op_size(c);
  9369. sc->op_stack_end = (s7_pointer *)(sc->op_stack + sc->op_stack_size);
  9370. for (i = 0; i < top; i++)
  9371. sc->op_stack[i] = continuation_op_stack(c)[i];
  9372. }
  9373. if (is_null(sc->args))
  9374. sc->value = sc->nil;
  9375. else
  9376. {
  9377. if (is_null(cdr(sc->args)))
  9378. sc->value = car(sc->args);
  9379. else sc->value = splice_in_values(sc, sc->args);
  9380. }
  9381. return(true);
  9382. }
  9383. static void call_with_exit(s7_scheme *sc)
  9384. {
  9385. int i, new_stack_top, quit = 0;
  9386. if (!call_exit_active(sc->code))
  9387. {
  9388. static s7_pointer call_with_exit_error = NULL;
  9389. if (!call_with_exit_error)
  9390. call_with_exit_error = s7_make_permanent_string("call-with-exit escape procedure called outside its block");
  9391. s7_error(sc, sc->invalid_escape_function_symbol, set_elist_1(sc, call_with_exit_error));
  9392. }
  9393. call_exit_active(sc->code) = false;
  9394. new_stack_top = call_exit_goto_loc(sc->code);
  9395. sc->op_stack_now = (s7_pointer *)(sc->op_stack + call_exit_op_loc(sc->code));
  9396. /* look for dynamic-wind in the stack section that we are jumping out of */
  9397. for (i = s7_stack_top(sc) - 1; i > new_stack_top; i -= 4)
  9398. {
  9399. opcode_t op;
  9400. op = stack_op(sc->stack, i);
  9401. switch (op)
  9402. {
  9403. case OP_DYNAMIC_WIND:
  9404. {
  9405. s7_pointer lx;
  9406. lx = stack_code(sc->stack, i);
  9407. if (dynamic_wind_state(lx) == DWIND_BODY)
  9408. {
  9409. dynamic_wind_state(lx) = DWIND_FINISH;
  9410. if (dynamic_wind_out(lx) != sc->F)
  9411. {
  9412. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  9413. sc->args = sc->nil;
  9414. sc->code = dynamic_wind_out(lx);
  9415. eval(sc, OP_APPLY);
  9416. }
  9417. }
  9418. }
  9419. break;
  9420. case OP_EVAL_STRING_2:
  9421. s7_close_input_port(sc, sc->input_port);
  9422. pop_input_port(sc);
  9423. break;
  9424. case OP_BARRIER: /* oops -- we almost certainly went too far */
  9425. return;
  9426. case OP_DEACTIVATE_GOTO: /* here we're jumping into an unrelated call-with-exit block */
  9427. call_exit_active(stack_args(sc->stack, i)) = false;
  9428. break;
  9429. /* call/cc does not close files, but I think call-with-exit should */
  9430. case OP_GET_OUTPUT_STRING_1:
  9431. case OP_UNWIND_OUTPUT:
  9432. {
  9433. s7_pointer x;
  9434. x = stack_code(sc->stack, i); /* "code" = port that we opened */
  9435. s7_close_output_port(sc, x);
  9436. x = stack_args(sc->stack, i); /* "args" = port that we shadowed, if not #f */
  9437. if (x != sc->F)
  9438. sc->output_port = x;
  9439. }
  9440. break;
  9441. case OP_UNWIND_INPUT:
  9442. s7_close_input_port(sc, stack_code(sc->stack, i)); /* "code" = port that we opened */
  9443. sc->input_port = stack_args(sc->stack, i); /* "args" = port that we shadowed */
  9444. break;
  9445. case OP_EVAL_DONE: /* goto called in a method -- put off the inner eval return(s) until we clean up the stack */
  9446. quit++;
  9447. break;
  9448. default:
  9449. break;
  9450. }
  9451. }
  9452. sc->stack_end = (s7_pointer *)(sc->stack_start + new_stack_top);
  9453. /* the return value should have an implicit values call, just as in call/cc */
  9454. if (is_null(sc->args))
  9455. sc->value = sc->nil;
  9456. else
  9457. {
  9458. if (is_null(cdr(sc->args)))
  9459. sc->value = car(sc->args);
  9460. else sc->value = splice_in_values(sc, sc->args);
  9461. }
  9462. if (quit > 0)
  9463. {
  9464. if (sc->longjmp_ok)
  9465. {
  9466. pop_stack(sc);
  9467. longjmp(sc->goto_start, CALL_WITH_EXIT_JUMP);
  9468. }
  9469. for (i = 0; i < quit; i++)
  9470. push_stack(sc, OP_EVAL_DONE, sc->nil, sc->nil);
  9471. }
  9472. }
  9473. static s7_pointer g_call_cc(s7_scheme *sc, s7_pointer args)
  9474. {
  9475. #define H_call_cc "(call-with-current-continuation func) is always a mistake!"
  9476. #define Q_call_cc s7_make_signature(sc, 2, sc->values_symbol, sc->is_procedure_symbol)
  9477. /* I think the intent is that sc->values_symbol as the proc-sig return type indicates multiple values are possible (otherwise use #t). */
  9478. s7_pointer p;
  9479. p = car(args); /* this is the procedure passed to call/cc */
  9480. if (!is_procedure(p)) /* this includes continuations */
  9481. {
  9482. check_two_methods(sc, p, sc->call_cc_symbol, sc->call_with_current_continuation_symbol, args);
  9483. return(simple_wrong_type_argument_with_type(sc, sc->call_cc_symbol, p, a_procedure_string));
  9484. }
  9485. if (!s7_is_aritable(sc, p, 1))
  9486. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "call/cc procedure, ~A, should take one argument"), p)));
  9487. sc->w = s7_make_continuation(sc);
  9488. push_stack(sc, OP_APPLY, list_1(sc, sc->w), p);
  9489. sc->w = sc->nil;
  9490. return(sc->nil);
  9491. }
  9492. /* we can't naively optimize call/cc to call-with-exit if the continuation is only
  9493. * used as a function in the call/cc body because it might (for example) be wrapped
  9494. * in a lambda form that is being exported. See b-func in s7test for an example.
  9495. */
  9496. static s7_pointer g_call_with_exit(s7_scheme *sc, s7_pointer args)
  9497. {
  9498. #define H_call_with_exit "(call-with-exit func) is call/cc without the ability to jump back into a previous computation."
  9499. #define Q_call_with_exit s7_make_signature(sc, 2, sc->values_symbol, sc->is_procedure_symbol)
  9500. s7_pointer p, x;
  9501. /* (call-with-exit (lambda (return) ...)) */
  9502. p = car(args);
  9503. if (!is_procedure(p)) /* this includes continuations */
  9504. method_or_bust_with_type(sc, p, sc->call_with_exit_symbol, args, a_procedure_string, 0);
  9505. x = make_goto(sc);
  9506. push_stack(sc, OP_DEACTIVATE_GOTO, x, p); /* this means call-with-exit is not tail-recursive */
  9507. push_stack(sc, OP_APPLY, cons_unchecked(sc, x, sc->nil), p);
  9508. /* if the lambda body calls the argument as a function,
  9509. * it is applied to its arguments, apply notices that it is a goto, and...
  9510. *
  9511. * (conceptually...) sc->stack_top = call_exit_goto_loc(sc->code);
  9512. * s_pop(sc, (is_not_null(sc->args)) ? car(sc->args) : sc->nil);
  9513. *
  9514. * which jumps to the point of the goto returning car(args).
  9515. *
  9516. * There is one gotcha: we can't jump back in from outside, so if the caller saves the goto
  9517. * and tries to invoke it outside the call-with-exit block, we have to
  9518. * make sure it triggers an error. So, if the escape is called, it then
  9519. * deactivates itself. Otherwise the block returns, we pop to OP_DEACTIVATE_GOTO,
  9520. * and it finds the goto in sc->args.
  9521. * Even worse:
  9522. *
  9523. (let ((cc #f))
  9524. (call-with-exit
  9525. (lambda (c3)
  9526. (call/cc (lambda (ret) (set! cc ret)))
  9527. (c3)))
  9528. (cc))
  9529. *
  9530. * where we jump back into a call-with-exit body via call/cc, the goto has to be
  9531. * re-established.
  9532. *
  9533. * I think call-with-exit could be based on catch, but it's a simpler notion,
  9534. * and certainly at the source level it is easier to read.
  9535. */
  9536. return(sc->nil);
  9537. }
  9538. /* -------------------------------- numbers -------------------------------- */
  9539. #if WITH_GMP
  9540. static char *big_number_to_string_with_radix(s7_pointer p, int radix, int width, int *nlen, use_write_t use_write);
  9541. static bool big_numbers_are_eqv(s7_pointer a, s7_pointer b);
  9542. static s7_pointer string_to_either_integer(s7_scheme *sc, const char *str, int radix);
  9543. static s7_pointer string_to_either_ratio(s7_scheme *sc, const char *nstr, const char *dstr, int radix);
  9544. static s7_pointer string_to_either_real(s7_scheme *sc, const char *str, int radix);
  9545. static s7_pointer string_to_either_complex(s7_scheme *sc, char *q, char *slash1, char *ex1, bool has_dec_point1,
  9546. char *plus, char *slash2, char *ex2, bool has_dec_point2, int radix, int has_plus_or_minus);
  9547. static s7_pointer big_add(s7_scheme *sc, s7_pointer args);
  9548. static s7_pointer big_subtract(s7_scheme *sc, s7_pointer args);
  9549. static s7_pointer big_multiply(s7_scheme *sc, s7_pointer args);
  9550. static s7_pointer big_divide(s7_scheme *sc, s7_pointer args);
  9551. static s7_pointer big_random(s7_scheme *sc, s7_pointer args);
  9552. static s7_pointer s7_int_to_big_integer(s7_scheme *sc, s7_int val);
  9553. static s7_pointer s7_ratio_to_big_ratio(s7_scheme *sc, s7_int num, s7_int den);
  9554. static s7_pointer s7_number_to_big_real(s7_scheme *sc, s7_pointer p);
  9555. static s7_pointer promote_number(s7_scheme *sc, int type, s7_pointer x);
  9556. static s7_pointer big_equal(s7_scheme *sc, s7_pointer args);
  9557. static s7_pointer big_negate(s7_scheme *sc, s7_pointer args);
  9558. static s7_pointer big_invert(s7_scheme *sc, s7_pointer args);
  9559. #if (!WITH_PURE_S7)
  9560. static s7_pointer big_inexact_to_exact(s7_scheme *sc, s7_pointer args);
  9561. static s7_pointer big_exact_to_inexact(s7_scheme *sc, s7_pointer args);
  9562. #endif
  9563. static s7_pointer mpz_to_big_integer(s7_scheme *sc, mpz_t val);
  9564. static s7_pointer mpq_to_big_ratio(s7_scheme *sc, mpq_t val);
  9565. static s7_pointer mpfr_to_big_real(s7_scheme *sc, mpfr_t val);
  9566. static s7_pointer mpc_to_big_complex(s7_scheme *sc, mpc_t val);
  9567. #endif
  9568. #define HAVE_OVERFLOW_CHECKS ((defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
  9569. (defined(__GNUC__) && __GNUC__ >= 5))
  9570. #if (defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4)))
  9571. #define subtract_overflow(A, B, C) __builtin_ssubll_overflow(A, B, C)
  9572. #define add_overflow(A, B, C) __builtin_saddll_overflow(A, B, C)
  9573. #define multiply_overflow(A, B, C) __builtin_smulll_overflow(A, B, C)
  9574. #define int_subtract_overflow(A, B, C) __builtin_ssub_overflow(A, B, C)
  9575. #define int_add_overflow(A, B, C) __builtin_sadd_overflow(A, B, C)
  9576. #define int_multiply_overflow(A, B, C) __builtin_smul_overflow(A, B, C)
  9577. #else
  9578. #if (defined(__GNUC__) && __GNUC__ >= 5)
  9579. #define subtract_overflow(A, B, C) __builtin_sub_overflow(A, B, C)
  9580. #define add_overflow(A, B, C) __builtin_add_overflow(A, B, C)
  9581. #define multiply_overflow(A, B, C) __builtin_mul_overflow(A, B, C)
  9582. #define int_subtract_overflow(A, B, C) __builtin_sub_overflow(A, B, C)
  9583. #define int_add_overflow(A, B, C) __builtin_add_overflow(A, B, C)
  9584. #define int_multiply_overflow(A, B, C) __builtin_mul_overflow(A, B, C)
  9585. #endif
  9586. #endif
  9587. #define s7_int_abs(x) ((x) >= 0 ? (x) : -(x))
  9588. /* can't use abs even in gcc -- it doesn't work with long long ints! */
  9589. #if (!__NetBSD__)
  9590. #define s7_fabsl(X) fabsl(X)
  9591. #else
  9592. static double s7_fabsl(long double x) {if (x < 0.0) return(-x); return(x);}
  9593. #endif
  9594. static bool is_NaN(s7_double x) {return(x != x);}
  9595. /* callgrind says this is faster than isnan, I think (very confusing data...) */
  9596. #if defined(__sun) && defined(__SVR4)
  9597. static bool is_inf(s7_double x) {return((x == x) && (is_NaN(x - x)));} /* there's no isinf in Solaris */
  9598. #else
  9599. #if (!MS_WINDOWS)
  9600. #if __cplusplus
  9601. #define is_inf(x) std::isinf(x)
  9602. #else
  9603. #define is_inf(x) isinf(x)
  9604. #endif
  9605. #else
  9606. static bool is_inf(s7_double x) {return((x == x) && (is_NaN(x - x)));} /* Another possibility: (x * 0) != 0 */
  9607. /* in MS C, we need to provide inverse hyperbolic trig funcs and cbrt */
  9608. static double asinh(double x) {return(log(x + sqrt(1.0 + x * x)));}
  9609. static double acosh(double x) {return(log(x + sqrt(x * x - 1.0)));}
  9610. /* perhaps less prone to numerical troubles (untested): 2.0 * log(sqrt(0.5 * (x + 1.0)) + sqrt(0.5 * (x - 1.0))) */
  9611. static double atanh(double x) {return(log((1.0 + x) / (1.0 - x)) / 2.0);}
  9612. static double cbrt(double x) {if (x >= 0.0) return(pow(x, 1.0 / 3.0)); return(-pow(-x, 1.0 / 3.0));}
  9613. #endif /* windows */
  9614. #endif /* sun */
  9615. /* for g_log, we also need round. this version is from stackoverflow, see also round_per_R5RS below */
  9616. double s7_round(double number) {return((number < 0.0) ? ceil(number - 0.5) : floor(number + 0.5));}
  9617. #if HAVE_COMPLEX_NUMBERS
  9618. #if __cplusplus
  9619. #define _Complex_I (complex<s7_double>(0.0, 1.0))
  9620. #define creal(x) Real(x)
  9621. #define cimag(x) Imag(x)
  9622. #define carg(x) arg(x)
  9623. #define cabs(x) abs(x)
  9624. #define csqrt(x) sqrt(x)
  9625. #define cpow(x, y) pow(x, y)
  9626. #define clog(x) log(x)
  9627. #define cexp(x) exp(x)
  9628. #define csin(x) sin(x)
  9629. #define ccos(x) cos(x)
  9630. #define csinh(x) sinh(x)
  9631. #define ccosh(x) cosh(x)
  9632. #else
  9633. typedef double complex s7_complex;
  9634. #endif
  9635. #if (!HAVE_COMPLEX_TRIG)
  9636. #if (__cplusplus)
  9637. static s7_complex ctan(s7_complex z) {return(csin(z) / ccos(z));}
  9638. static s7_complex ctanh(s7_complex z) {return(csinh(z) / ccosh(z));}
  9639. static s7_complex casin(s7_complex z) {return(-_Complex_I * clog(_Complex_I * z + csqrt(1.0 - z * z)));}
  9640. static s7_complex cacos(s7_complex z) {return(-_Complex_I * clog(z + _Complex_I * csqrt(1.0 - z * z)));}
  9641. static s7_complex catan(s7_complex z) {return(_Complex_I * clog((_Complex_I + z) / (_Complex_I - z)) / 2.0);}
  9642. static s7_complex casinh(s7_complex z) {return(clog(z + csqrt(1.0 + z * z)));}
  9643. static s7_complex cacosh(s7_complex z) {return(clog(z + csqrt(z * z - 1.0)));}
  9644. static s7_complex catanh(s7_complex z) {return(clog((1.0 + z) / (1.0 - z)) / 2.0);}
  9645. #else
  9646. /* still not in FreeBSD! */
  9647. static s7_complex clog(s7_complex z) {return(log(fabs(cabs(z))) + carg(z) * _Complex_I);}
  9648. static s7_complex cpow(s7_complex x, s7_complex y)
  9649. {
  9650. s7_double r = cabs(x);
  9651. s7_double theta = carg(x);
  9652. s7_double yre = creal(y);
  9653. s7_double yim = cimag(y);
  9654. s7_double nr = exp(yre * log(r) - yim * theta);
  9655. s7_double ntheta = yre * theta + yim * log(r);
  9656. return(nr * cos(ntheta) + (nr * sin(ntheta)) * _Complex_I); /* make-polar */
  9657. }
  9658. #if (!defined(__FreeBSD__)) || (__FreeBSD__ < 9) /* untested -- this orignally looked at __FreeBSD_version which apparently no longer exists */
  9659. static s7_complex cexp(s7_complex z) {return(exp(creal(z)) * cos(cimag(z)) + (exp(creal(z)) * sin(cimag(z))) * _Complex_I);}
  9660. #endif
  9661. #if (!defined(__FreeBSD__)) || (__FreeBSD__ < 10)
  9662. static s7_complex csin(s7_complex z) {return(sin(creal(z)) * cosh(cimag(z)) + (cos(creal(z)) * sinh(cimag(z))) * _Complex_I);}
  9663. static s7_complex ccos(s7_complex z) {return(cos(creal(z)) * cosh(cimag(z)) + (-sin(creal(z)) * sinh(cimag(z))) * _Complex_I);}
  9664. static s7_complex csinh(s7_complex z) {return(sinh(creal(z)) * cos(cimag(z)) + (cosh(creal(z)) * sin(cimag(z))) * _Complex_I);}
  9665. static s7_complex ccosh(s7_complex z) {return(cosh(creal(z)) * cos(cimag(z)) + (sinh(creal(z)) * sin(cimag(z))) * _Complex_I);}
  9666. static s7_complex ctan(s7_complex z) {return(csin(z) / ccos(z));}
  9667. static s7_complex ctanh(s7_complex z) {return(csinh(z) / ccosh(z));}
  9668. static s7_complex casin(s7_complex z) {return(-_Complex_I * clog(_Complex_I * z + csqrt(1.0 - z * z)));}
  9669. static s7_complex cacos(s7_complex z) {return(-_Complex_I * clog(z + _Complex_I * csqrt(1.0 - z * z)));}
  9670. static s7_complex catan(s7_complex z) {return(_Complex_I * clog((_Complex_I + z) / (_Complex_I - z)) / 2.0);}
  9671. static s7_complex catanh(s7_complex z) {return(clog((1.0 + z) / (1.0 - z)) / 2.0);}
  9672. static s7_complex casinh(s7_complex z) {return(clog(z + csqrt(1.0 + z * z)));}
  9673. static s7_complex cacosh(s7_complex z) {return(clog(z + csqrt(z * z - 1.0)));}
  9674. /* perhaps less prone to numerical troubles (untested): 2.0 * clog(csqrt(0.5 * (z + 1.0)) + csqrt(0.5 * (z - 1.0))) */
  9675. #endif /* not FreeBSD 10 */
  9676. #endif /* not c++ */
  9677. #endif /* not HAVE_COMPLEX_TRIG */
  9678. #else /* not HAVE_COMPLEX_NUMBERS */
  9679. typedef double s7_complex;
  9680. #define _Complex_I 1
  9681. #define creal(x) x
  9682. #define cimag(x) x
  9683. #define csin(x) sin(x)
  9684. #define casin(x) x
  9685. #define ccos(x) cos(x)
  9686. #define cacos(x) x
  9687. #define ctan(x) x
  9688. #define catan(x) x
  9689. #define csinh(x) x
  9690. #define casinh(x) x
  9691. #define ccosh(x) x
  9692. #define cacosh(x) x
  9693. #define ctanh(x) x
  9694. #define catanh(x) x
  9695. #define cexp(x) exp(x)
  9696. #define cpow(x, y) pow(x, y)
  9697. #define clog(x) log(x)
  9698. #define csqrt(x) sqrt(x)
  9699. #define conj(x) x
  9700. #endif
  9701. #ifdef __OpenBSD__
  9702. /* openbsd's builtin versions of these functions are not usable */
  9703. static s7_complex catanh_1(s7_complex z) {return(clog((1.0 + z) / (1.0 - z)) / 2.0);}
  9704. static s7_complex casinh_1(s7_complex z) {return(clog(z + csqrt(1.0 + z * z)));}
  9705. static s7_complex cacosh_1(s7_complex z) {return(clog(z + csqrt(z * z - 1.0)));}
  9706. #endif
  9707. #ifdef __NetBSD__
  9708. static s7_complex catanh_1(s7_complex z) {return(clog((1.0 + z) / (1.0 - z)) / 2.0);}
  9709. static s7_complex casinh_1(s7_complex z) {return(clog(z + csqrt(1.0 + z * z)));}
  9710. #endif
  9711. bool s7_is_number(s7_pointer p)
  9712. {
  9713. #if WITH_GMP
  9714. return((is_number(p)) || (is_big_number(p)));
  9715. #else
  9716. return(is_number(p));
  9717. #endif
  9718. }
  9719. bool s7_is_integer(s7_pointer p)
  9720. {
  9721. #if WITH_GMP
  9722. return((is_t_integer(p)) ||
  9723. (is_t_big_integer(p)));
  9724. #else
  9725. return(is_integer(p));
  9726. #endif
  9727. }
  9728. bool s7_is_real(s7_pointer p)
  9729. {
  9730. #if WITH_GMP
  9731. return((is_real(p)) ||
  9732. (is_t_big_integer(p)) ||
  9733. (is_t_big_ratio(p)) ||
  9734. (is_t_big_real(p)));
  9735. #else
  9736. return(is_real(p)); /* in GSL, a NaN or inf is not a real, or perhaps better, finite = not (nan or inf) */
  9737. #endif
  9738. }
  9739. bool s7_is_rational(s7_pointer p)
  9740. {
  9741. #if WITH_GMP
  9742. return((is_rational(p)) ||
  9743. (is_t_big_integer(p)) ||
  9744. (is_t_big_ratio(p)));
  9745. #else
  9746. return(is_rational(p));
  9747. #endif
  9748. }
  9749. bool s7_is_ratio(s7_pointer p)
  9750. {
  9751. #if WITH_GMP
  9752. return((is_t_ratio(p)) ||
  9753. (is_t_big_ratio(p)));
  9754. #else
  9755. return(is_t_ratio(p));
  9756. #endif
  9757. }
  9758. bool s7_is_complex(s7_pointer p)
  9759. {
  9760. #if WITH_GMP
  9761. return((is_number(p)) || (is_big_number(p)));
  9762. #else
  9763. return(is_number(p));
  9764. #endif
  9765. }
  9766. static s7_int c_gcd(s7_int u, s7_int v)
  9767. {
  9768. s7_int a, b;
  9769. if ((u == s7_int_min) || (v == s7_int_min))
  9770. {
  9771. /* can't take abs of these (below) so do it by hand */
  9772. s7_int divisor = 1;
  9773. if (u == v) return(u);
  9774. while (((u & 1) == 0) && ((v & 1) == 0))
  9775. {
  9776. u /= 2;
  9777. v /= 2;
  9778. divisor *= 2;
  9779. }
  9780. return(divisor);
  9781. }
  9782. a = s7_int_abs(u);
  9783. b = s7_int_abs(v);
  9784. while (b != 0)
  9785. {
  9786. s7_int temp;
  9787. temp = a % b;
  9788. a = b;
  9789. b = temp;
  9790. }
  9791. if (a < 0)
  9792. return(-a);
  9793. return(a);
  9794. }
  9795. static bool c_rationalize(s7_double ux, s7_double error, s7_int *numer, s7_int *denom)
  9796. {
  9797. /*
  9798. (define* (rat ux (err 0.0000001))
  9799. ;; translated from CL code in Canny, Donald, Ressler, "A Rational Rotation Method for Robust Geometric Algorithms"
  9800. (let ((x0 (- ux error))
  9801. (x1 (+ ux error)))
  9802. (let ((i (ceiling x0))
  9803. (i0 (floor x0))
  9804. (i1 (ceiling x1))
  9805. (r 0))
  9806. (if (>= x1 i)
  9807. i
  9808. (do ((p0 i0 (+ p1 (* r p0)))
  9809. (q0 1 (+ q1 (* r q0)))
  9810. (p1 i1 p0)
  9811. (q1 1 q0)
  9812. (e0 (- i1 x0) e1p)
  9813. (e1 (- x0 i0) (- e0p (* r e1p)))
  9814. (e0p (- i1 x1) e1)
  9815. (e1p (- x1 i0) (- e0 (* r e1))))
  9816. ((<= x0 (/ p0 q0) x1)
  9817. (/ p0 q0))
  9818. (set! r (min (floor (/ e0 e1))
  9819. (ceiling (/ e0p e1p)))))))))
  9820. */
  9821. double x0, x1;
  9822. s7_int i, i0, i1, p0, q0, p1, q1;
  9823. double e0, e1, e0p, e1p;
  9824. int tries = 0;
  9825. /* don't use s7_double here; if it is "long double", the loop below will hang */
  9826. /* #e1e19 is a killer -- it's bigger than most-positive-fixnum, but if we ceil(ux) below
  9827. * it turns into most-negative-fixnum. 1e19 is trouble in many places.
  9828. */
  9829. if ((ux > s7_int_max) || (ux < s7_int_min))
  9830. {
  9831. /* can't return false here because that confuses some of the callers!
  9832. */
  9833. if (ux > s7_int_min) (*numer) = s7_int_max; else (*numer) = s7_int_min;
  9834. (*denom) = 1;
  9835. return(true);
  9836. }
  9837. if (error < 0.0) error = -error;
  9838. x0 = ux - error;
  9839. x1 = ux + error;
  9840. i = (s7_int)ceil(x0);
  9841. if (error >= 1.0) /* aw good grief! */
  9842. {
  9843. if (x0 < 0)
  9844. {
  9845. if (x1 < 0)
  9846. (*numer) = (s7_int)floor(x1);
  9847. else (*numer) = 0;
  9848. }
  9849. else (*numer) = i;
  9850. (*denom) = 1;
  9851. return(true);
  9852. }
  9853. if (x1 >= i)
  9854. {
  9855. if (i >= 0)
  9856. (*numer) = i;
  9857. else (*numer) = (s7_int)floor(x1);
  9858. (*denom) = 1;
  9859. return(true);
  9860. }
  9861. i0 = (s7_int)floor(x0);
  9862. i1 = (s7_int)ceil(x1);
  9863. p0 = i0;
  9864. q0 = 1;
  9865. p1 = i1;
  9866. q1 = 1;
  9867. e0 = i1 - x0;
  9868. e1 = x0 - i0;
  9869. e0p = i1 - x1;
  9870. e1p = x1 - i0;
  9871. while (true)
  9872. {
  9873. s7_int old_p1, old_q1;
  9874. double old_e0, old_e1, old_e0p, val, r, r1;
  9875. val = (double)p0 / (double)q0;
  9876. if (((x0 <= val) && (val <= x1)) ||
  9877. (e1 == 0) ||
  9878. (e1p == 0) ||
  9879. (tries > 100))
  9880. {
  9881. (*numer) = p0;
  9882. (*denom) = q0;
  9883. return(true);
  9884. }
  9885. tries++;
  9886. r = (s7_int)floor(e0 / e1);
  9887. r1 = (s7_int)ceil(e0p / e1p);
  9888. if (r1 < r) r = r1;
  9889. /* do handles all step vars in parallel */
  9890. old_p1 = p1;
  9891. p1 = p0;
  9892. old_q1 = q1;
  9893. q1 = q0;
  9894. old_e0 = e0;
  9895. e0 = e1p;
  9896. old_e0p = e0p;
  9897. e0p = e1;
  9898. old_e1 = e1;
  9899. p0 = old_p1 + r * p0;
  9900. q0 = old_q1 + r * q0;
  9901. e1 = old_e0p - r * e1p;
  9902. /* if the error is set too low, we can get e1 = 0 here: (rationalize (/ pi) 1e-17) */
  9903. e1p = old_e0 - r * old_e1;
  9904. }
  9905. return(false);
  9906. }
  9907. s7_pointer s7_rationalize(s7_scheme *sc, s7_double x, s7_double error)
  9908. {
  9909. s7_int numer = 0, denom = 1;
  9910. if (c_rationalize(x, error, &numer, &denom))
  9911. return(s7_make_ratio(sc, numer, denom));
  9912. return(make_real(sc, x));
  9913. }
  9914. static s7_int number_to_numerator(s7_pointer n)
  9915. {
  9916. if (is_t_ratio(n))
  9917. return(numerator(n));
  9918. return(integer(n));
  9919. }
  9920. static s7_int number_to_denominator(s7_pointer n)
  9921. {
  9922. if (is_t_ratio(n))
  9923. return(denominator(n));
  9924. return(1);
  9925. }
  9926. s7_pointer s7_make_integer(s7_scheme *sc, s7_int n)
  9927. {
  9928. s7_pointer x;
  9929. if (is_small(n)) /* ((n >= 0) && (n < NUM_SMALL_INTS)) is slower */
  9930. return(small_int(n));
  9931. new_cell(sc, x, T_INTEGER);
  9932. integer(x) = n;
  9933. return(x);
  9934. }
  9935. static s7_pointer make_mutable_integer(s7_scheme *sc, s7_int n)
  9936. {
  9937. s7_pointer x;
  9938. new_cell(sc, x, T_INTEGER | T_MUTABLE);
  9939. integer(x) = n;
  9940. return(x);
  9941. }
  9942. static s7_pointer make_permanent_integer_unchecked(s7_int i)
  9943. {
  9944. s7_pointer p;
  9945. p = (s7_pointer)calloc(1, sizeof(s7_cell));
  9946. typeflag(p) = T_IMMUTABLE | T_INTEGER;
  9947. unheap(p);
  9948. integer(p) = i;
  9949. return(p);
  9950. }
  9951. static s7_pointer make_permanent_integer(s7_int i)
  9952. {
  9953. if (is_small(i)) return(small_int(i));
  9954. if (i == MAX_ARITY) return(max_arity);
  9955. if (i == CLOSURE_ARITY_NOT_SET) return(arity_not_set);
  9956. if (i == -1) return(minus_one);
  9957. if (i == -2) return(minus_two);
  9958. /* a few -3 */
  9959. return(make_permanent_integer_unchecked(i));
  9960. }
  9961. s7_pointer s7_make_real(s7_scheme *sc, s7_double n)
  9962. {
  9963. s7_pointer x;
  9964. /* in snd-test this is called about 40000000 times, primarily test 8/18/22 */
  9965. if (n == 0.0)
  9966. return(real_zero);
  9967. new_cell(sc, x, T_REAL);
  9968. set_real(x, n);
  9969. return(x);
  9970. }
  9971. s7_pointer s7_make_mutable_real(s7_scheme *sc, s7_double n)
  9972. {
  9973. s7_pointer x;
  9974. new_cell(sc, x, T_REAL | T_MUTABLE);
  9975. set_real(x, n);
  9976. return(x);
  9977. }
  9978. static s7_pointer make_permanent_real(s7_double n)
  9979. {
  9980. s7_pointer x;
  9981. int nlen = 0;
  9982. char *str;
  9983. x = (s7_pointer)calloc(1, sizeof(s7_cell));
  9984. set_type(x, T_IMMUTABLE | T_REAL);
  9985. unheap(x);
  9986. set_real(x, n);
  9987. str = number_to_string_base_10(x, 0, float_format_precision, 'g', &nlen, USE_WRITE);
  9988. set_print_name(x, str, nlen);
  9989. return(x);
  9990. }
  9991. s7_pointer s7_make_complex(s7_scheme *sc, s7_double a, s7_double b)
  9992. {
  9993. s7_pointer x;
  9994. if (b == 0.0)
  9995. {
  9996. new_cell(sc, x, T_REAL);
  9997. set_real(x, a);
  9998. }
  9999. else
  10000. {
  10001. new_cell(sc, x, T_COMPLEX);
  10002. set_real_part(x, a);
  10003. set_imag_part(x, b);
  10004. }
  10005. return(x);
  10006. }
  10007. s7_pointer s7_make_ratio(s7_scheme *sc, s7_int a, s7_int b)
  10008. {
  10009. s7_pointer x;
  10010. s7_int divisor;
  10011. if (b == 0)
  10012. return(division_by_zero_error(sc, make_string_wrapper(sc, "make-ratio"), set_elist_2(sc, make_integer(sc, a), small_int(0))));
  10013. if (a == 0)
  10014. return(small_int(0));
  10015. if (b == 1)
  10016. return(make_integer(sc, a));
  10017. #if (!WITH_GMP)
  10018. if (b == s7_int_min)
  10019. {
  10020. if (a == b)
  10021. return(small_int(1));
  10022. /* we've got a problem... This should not trigger an error during reading -- we might have the
  10023. * ratio on a switch with-bignums or whatever, so its mere occurrence is just an annoyance.
  10024. * We'll try to do something...
  10025. */
  10026. if (a & 1)
  10027. {
  10028. if (a == 1)
  10029. return(real_NaN);
  10030. /* not an error here? we can't get this in the ratio reader, I think, because the denominator is negative */
  10031. b = b + 1;
  10032. /* so (/ -1 most-negative-fixnum) -> 1/9223372036854775807 -- not ideal, but ... */
  10033. }
  10034. else
  10035. {
  10036. a /= 2;
  10037. b /= 2;
  10038. }
  10039. }
  10040. #endif
  10041. if (b < 0)
  10042. {
  10043. a = -a;
  10044. b = -b;
  10045. }
  10046. divisor = c_gcd(a, b);
  10047. if (divisor != 1)
  10048. {
  10049. a /= divisor;
  10050. b /= divisor;
  10051. }
  10052. if (b == 1)
  10053. return(make_integer(sc, a));
  10054. new_cell(sc, x, T_RATIO);
  10055. numerator(x) = a;
  10056. denominator(x) = b;
  10057. return(x);
  10058. }
  10059. /* in fc19 as a guest running in virtualbox on OSX, the line a /= divisor can abort with an arithmetic exception (SIGFPE)
  10060. * if leastfix/mostfix -- apparently this is a bug in virtualbox.
  10061. */
  10062. #define WITH_OVERFLOW_ERROR true
  10063. #define WITHOUT_OVERFLOW_ERROR false
  10064. #if (!WITH_PURE_S7)
  10065. static s7_pointer exact_to_inexact(s7_scheme *sc, s7_pointer x)
  10066. {
  10067. /* this is tricky because a big int can mess up when turned into a double:
  10068. * (truncate (exact->inexact most-positive-fixnum)) -> -9223372036854775808
  10069. */
  10070. switch (type(x))
  10071. {
  10072. case T_INTEGER: return(make_real(sc, (s7_double)(integer(x))));
  10073. case T_RATIO: return(make_real(sc, (s7_double)(fraction(x))));
  10074. case T_REAL:
  10075. case T_COMPLEX: return(x); /* apparently (exact->inexact 1+i) is not an error */
  10076. default:
  10077. method_or_bust_with_type(sc, x, sc->exact_to_inexact_symbol, list_1(sc, x), a_number_string, 0);
  10078. }
  10079. }
  10080. static s7_pointer inexact_to_exact(s7_scheme *sc, s7_pointer x, bool with_error)
  10081. {
  10082. switch (type(x))
  10083. {
  10084. case T_INTEGER:
  10085. case T_RATIO:
  10086. return(x);
  10087. case T_REAL:
  10088. {
  10089. s7_int numer = 0, denom = 1;
  10090. s7_double val;
  10091. val = s7_real(x);
  10092. if ((is_inf(val)) || (is_NaN(val)))
  10093. {
  10094. if (with_error)
  10095. return(simple_wrong_type_argument_with_type(sc, sc->inexact_to_exact_symbol, x, a_normal_real_string));
  10096. return(sc->nil);
  10097. }
  10098. if ((val > s7_int_max) ||
  10099. (val < s7_int_min))
  10100. {
  10101. if (with_error)
  10102. return(simple_out_of_range(sc, sc->inexact_to_exact_symbol, x, its_too_large_string));
  10103. return(sc->nil);
  10104. }
  10105. if (c_rationalize(val, sc->default_rationalize_error, &numer, &denom))
  10106. return(s7_make_ratio(sc, numer, denom));
  10107. }
  10108. default:
  10109. if (with_error)
  10110. method_or_bust(sc, x, sc->inexact_to_exact_symbol, list_1(sc, x), T_REAL, 0);
  10111. return(sc->nil);
  10112. }
  10113. return(x);
  10114. }
  10115. #endif
  10116. s7_double s7_number_to_real_with_caller(s7_scheme *sc, s7_pointer x, const char *caller)
  10117. {
  10118. if (is_t_real(x))
  10119. return(real(x));
  10120. /* this is nearly always the case in current usage, so by avoiding the "switch" we can go twice as fast */
  10121. switch (type(x))
  10122. {
  10123. case T_INTEGER: return((s7_double)integer(x));
  10124. case T_RATIO: return((s7_double)numerator(x) / (s7_double)denominator(x));
  10125. case T_REAL: return(real(x));
  10126. #if WITH_GMP
  10127. case T_BIG_INTEGER: return((s7_double)big_integer_to_s7_int(big_integer(x)));
  10128. case T_BIG_RATIO: return((s7_double)((long double)big_integer_to_s7_int(mpq_numref(big_ratio(x))) /
  10129. (long double)big_integer_to_s7_int(mpq_denref(big_ratio(x)))));
  10130. case T_BIG_REAL: return((s7_double)mpfr_get_d(big_real(x), GMP_RNDN));
  10131. #endif
  10132. }
  10133. s7_wrong_type_arg_error(sc, caller, 0, x, "a real number");
  10134. return(0.0);
  10135. }
  10136. s7_double s7_number_to_real(s7_scheme *sc, s7_pointer x)
  10137. {
  10138. return(s7_number_to_real_with_caller(sc, x, "s7_number_to_real"));
  10139. }
  10140. s7_int s7_number_to_integer_with_caller(s7_scheme *sc, s7_pointer x, const char *caller) /* currently unused */
  10141. {
  10142. if (type(x) != T_INTEGER)
  10143. s7_wrong_type_arg_error(sc, caller, 0, x, "an integer");
  10144. return(integer(x));
  10145. }
  10146. s7_int s7_number_to_integer(s7_scheme *sc, s7_pointer x) /* currently unused */
  10147. {
  10148. return(s7_number_to_integer_with_caller(sc, x, "s7_number_to_integer"));
  10149. }
  10150. s7_int s7_numerator(s7_pointer x)
  10151. {
  10152. switch (type(x))
  10153. {
  10154. case T_INTEGER: return(integer(x));
  10155. case T_RATIO: return(numerator(x));
  10156. #if WITH_GMP
  10157. case T_BIG_INTEGER: return(big_integer_to_s7_int(big_integer(x)));
  10158. case T_BIG_RATIO: return(big_integer_to_s7_int(mpq_numref(big_ratio(x))));
  10159. #endif
  10160. }
  10161. return(0);
  10162. }
  10163. s7_int s7_denominator(s7_pointer x)
  10164. {
  10165. switch (type(x))
  10166. {
  10167. case T_RATIO: return(denominator(x));
  10168. #if WITH_GMP
  10169. case T_BIG_RATIO: return(big_integer_to_s7_int(mpq_denref(big_ratio(x))));
  10170. #endif
  10171. }
  10172. return(1);
  10173. }
  10174. s7_int s7_integer(s7_pointer p)
  10175. {
  10176. #if WITH_GMP
  10177. if (is_t_big_integer(p))
  10178. return(big_integer_to_s7_int(big_integer(p)));
  10179. #endif
  10180. return(integer(p));
  10181. }
  10182. s7_double s7_real(s7_pointer p)
  10183. {
  10184. #if WITH_GMP
  10185. if (is_t_big_real(p))
  10186. return((s7_double)mpfr_get_d(big_real(p), GMP_RNDN));
  10187. #endif
  10188. return(real(p));
  10189. }
  10190. #if (!WITH_GMP)
  10191. static s7_complex s7_to_c_complex(s7_pointer p)
  10192. {
  10193. #if HAVE_COMPLEX_NUMBERS
  10194. return(CMPLX(s7_real_part(p), s7_imag_part(p)));
  10195. #else
  10196. return(0.0);
  10197. #endif
  10198. }
  10199. static s7_pointer s7_from_c_complex(s7_scheme *sc, s7_complex z)
  10200. {
  10201. return(s7_make_complex(sc, creal(z), cimag(z)));
  10202. }
  10203. #endif
  10204. #if ((!WITH_PURE_S7) || (!HAVE_OVERFLOW_CHECKS))
  10205. static int integer_length(s7_int a)
  10206. {
  10207. static const int bits[256] =
  10208. {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,
  10209. 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,
  10210. 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,
  10211. 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,
  10212. 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,
  10213. 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,
  10214. 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,
  10215. 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};
  10216. #define I_8 256LL
  10217. #define I_16 65536LL
  10218. #define I_24 16777216LL
  10219. #define I_32 4294967296LL
  10220. #define I_40 1099511627776LL
  10221. #define I_48 281474976710656LL
  10222. #define I_56 72057594037927936LL
  10223. /* a might be most-negative-fixnum! in Clisp: (integer-length -9223372036854775808) -> 63
  10224. */
  10225. if (a < 0)
  10226. {
  10227. if (a == s7_int_min) return(63);
  10228. a = -a;
  10229. }
  10230. if (a < I_8) return(bits[a]);
  10231. if (a < I_16) return(8 + bits[a >> 8]);
  10232. if (a < I_24) return(16 + bits[a >> 16]);
  10233. if (a < I_32) return(24 + bits[a >> 24]);
  10234. if (a < I_40) return(32 + bits[a >> 32]);
  10235. if (a < I_48) return(40 + bits[a >> 40]);
  10236. if (a < I_56) return(48 + bits[a >> 48]);
  10237. return(56 + bits[a >> 56]);
  10238. }
  10239. #endif
  10240. static int s7_int32_max = 0, s7_int32_min = 0, s7_int_bits = 0, s7_int_digits = 0; /* initialized later */
  10241. static int s7_int_digits_by_radix[17];
  10242. #if (!WITH_GMP)
  10243. static s7_pointer s7_negate(s7_scheme *sc, s7_pointer p) /* can't use "negate" because it confuses C++! */
  10244. {
  10245. switch (type(p))
  10246. {
  10247. case T_INTEGER: return(make_integer(sc, -integer(p)));
  10248. case T_RATIO: return(s7_make_ratio(sc, -numerator(p), denominator(p)));
  10249. case T_REAL: return(make_real(sc, -real(p)));
  10250. default: return(s7_make_complex(sc, -real_part(p), -imag_part(p)));
  10251. }
  10252. }
  10253. #endif
  10254. static s7_pointer s7_invert(s7_scheme *sc, s7_pointer p) /* s7_ to be consistent... */
  10255. {
  10256. switch (type(p))
  10257. {
  10258. case T_INTEGER:
  10259. return(s7_make_ratio(sc, 1, integer(p))); /* a already checked, not 0 */
  10260. case T_RATIO:
  10261. return(s7_make_ratio(sc, denominator(p), numerator(p)));
  10262. case T_REAL:
  10263. return(make_real(sc, 1.0 / real(p)));
  10264. case T_COMPLEX:
  10265. {
  10266. s7_double r2, i2, den;
  10267. r2 = real_part(p);
  10268. i2 = imag_part(p);
  10269. den = (r2 * r2 + i2 * i2);
  10270. return(s7_make_complex(sc, r2 / den, -i2 / den));
  10271. }
  10272. default:
  10273. return(wrong_type_argument_with_type(sc, sc->divide_symbol, 1, p, a_number_string));
  10274. }
  10275. }
  10276. static s7_pointer subtract_ratios(s7_scheme *sc, s7_pointer x, s7_pointer y)
  10277. {
  10278. s7_int d1, d2, n1, n2;
  10279. d1 = number_to_denominator(x);
  10280. n1 = number_to_numerator(x);
  10281. d2 = number_to_denominator(y);
  10282. n2 = number_to_numerator(y);
  10283. if (d1 == d2) /* the easy case -- if overflow here, it matches the int case */
  10284. return(s7_make_ratio(sc, n1 - n2, d1));
  10285. #if (!WITH_GMP)
  10286. #if HAVE_OVERFLOW_CHECKS
  10287. {
  10288. s7_int n1d2, n2d1, d1d2, dn;
  10289. if ((multiply_overflow(d1, d2, &d1d2)) ||
  10290. (multiply_overflow(n1, d2, &n1d2)) ||
  10291. (multiply_overflow(n2, d1, &n2d1)) ||
  10292. (subtract_overflow(n1d2, n2d1, &dn)))
  10293. return(make_real(sc, ((long double)n1 / (long double)d1) - ((long double)n2 / (long double)d2)));
  10294. return(s7_make_ratio(sc, dn, d1d2));
  10295. }
  10296. #else
  10297. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  10298. (n1 > s7_int32_max) || (n2 > s7_int32_max) ||
  10299. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  10300. {
  10301. int d1bits, d2bits;
  10302. d1bits = integer_length(d1);
  10303. d2bits = integer_length(d2);
  10304. if (((d1bits + d2bits) > s7_int_bits) ||
  10305. ((d1bits + integer_length(n2)) > (s7_int_bits - 1)) ||
  10306. ((d2bits + integer_length(n1)) > (s7_int_bits - 1)))
  10307. return(make_real(sc, ((long double)n1 / (long double)d1) - ((long double)n2 / (long double)d2)));
  10308. return(s7_make_ratio(sc, n1 * d2 - n2 * d1, d1 * d2));
  10309. }
  10310. #endif
  10311. #endif
  10312. return(s7_make_ratio(sc, n1 * d2 - n2 * d1, d1 * d2));
  10313. }
  10314. static bool s7_is_negative(s7_pointer obj)
  10315. {
  10316. switch (type(obj))
  10317. {
  10318. case T_INTEGER: return(integer(obj) < 0);
  10319. case T_RATIO: return(numerator(obj) < 0);
  10320. #if WITH_GMP
  10321. case T_BIG_INTEGER: return(mpz_cmp_ui(big_integer(obj), 0) < 0);
  10322. case T_BIG_RATIO: return(mpq_cmp_ui(big_ratio(obj), 0, 1) < 0);
  10323. case T_BIG_REAL: return(mpfr_cmp_ui(big_real(obj), 0) < 0);
  10324. #endif
  10325. default: return(real(obj) < 0);
  10326. }
  10327. }
  10328. static bool s7_is_positive(s7_pointer x)
  10329. {
  10330. switch (type(x))
  10331. {
  10332. case T_INTEGER: return(integer(x) > 0);
  10333. case T_RATIO: return(numerator(x) > 0);
  10334. #if WITH_GMP
  10335. case T_BIG_INTEGER: return(mpz_cmp_ui(big_integer(x), 0) > 0);
  10336. case T_BIG_RATIO: return(mpq_cmp_ui(big_ratio(x), 0, 1) > 0);
  10337. case T_BIG_REAL: return(mpfr_cmp_ui(big_real(x), 0) > 0);
  10338. #endif
  10339. default: return(real(x) > 0.0);
  10340. }
  10341. }
  10342. static bool s7_is_zero(s7_pointer x)
  10343. {
  10344. switch (type(x))
  10345. {
  10346. case T_INTEGER: return(integer(x) == 0);
  10347. case T_REAL: return(real(x) == 0.0);
  10348. #if WITH_GMP
  10349. case T_BIG_INTEGER: return(mpz_cmp_ui(big_integer(x), 0) == 0);
  10350. case T_BIG_REAL: return(mpfr_zero_p(big_real(x)));
  10351. #endif
  10352. default: return(false); /* ratios and complex numbers here are already collapsed into integers and reals */
  10353. }
  10354. }
  10355. static bool s7_is_one(s7_pointer x)
  10356. {
  10357. return(((is_integer(x)) && (integer(x) == 1)) ||
  10358. ((is_t_real(x)) && (real(x) == 1.0)));
  10359. }
  10360. /* optimize exponents */
  10361. #define MAX_POW 32
  10362. static double pepow[17][MAX_POW], mepow[17][MAX_POW];
  10363. static void init_pows(void)
  10364. {
  10365. int i, j;
  10366. for (i = 2; i < 17; i++) /* radix between 2 and 16 */
  10367. for (j = 0; j < MAX_POW; j++) /* saved exponent between 0 and +/- MAX_POW */
  10368. {
  10369. pepow[i][j] = pow((double)i, (double)j);
  10370. mepow[i][j] = pow((double)i, (double)(-j));
  10371. }
  10372. }
  10373. static double ipow(int x, int y)
  10374. {
  10375. if ((y < MAX_POW) && (y > (-MAX_POW)))
  10376. {
  10377. if (y >= 0)
  10378. return(pepow[x][y]);
  10379. return(mepow[x][-y]);
  10380. }
  10381. return(pow((double)x, (double)y));
  10382. }
  10383. static int s7_int_to_string(char *p, s7_int n, int radix, int width)
  10384. {
  10385. static const char dignum[] = "0123456789abcdef";
  10386. int i, len, start, end;
  10387. bool sign;
  10388. s7_int pown;
  10389. if ((radix < 2) || (radix > 16))
  10390. return(0);
  10391. if (n == s7_int_min) /* can't negate this, so do it by hand */
  10392. {
  10393. static const char *mnfs[17] = {"","",
  10394. "-1000000000000000000000000000000000000000000000000000000000000000", "-2021110011022210012102010021220101220222",
  10395. "-20000000000000000000000000000000", "-1104332401304422434310311213", "-1540241003031030222122212",
  10396. "-22341010611245052052301", "-1000000000000000000000", "-67404283172107811828", "-9223372036854775808",
  10397. "-1728002635214590698", "-41a792678515120368", "-10b269549075433c38", "-4340724c6c71dc7a8", "-160e2ad3246366808", "-8000000000000000"};
  10398. len = safe_strlen(mnfs[radix]);
  10399. if (width > len)
  10400. {
  10401. start = width - len - 1;
  10402. memset((void *)p, (int)' ', start);
  10403. }
  10404. else start = 0;
  10405. for (i = 0; i < len; i++)
  10406. p[start + i] = mnfs[radix][i];
  10407. p[len + start] = '\0';
  10408. return(len + start);
  10409. }
  10410. sign = (n < 0);
  10411. if (sign) n = -n;
  10412. /* the previous version that counted up to n, rather than dividing down below n, as here,
  10413. * could be confused by large ints on 64 bit machines
  10414. */
  10415. pown = n;
  10416. for (i = 1; i < 100; i++)
  10417. {
  10418. if (pown < radix)
  10419. break;
  10420. pown /= (s7_int)radix;
  10421. }
  10422. len = i - 1;
  10423. if (sign) len++;
  10424. end = 0;
  10425. if (width > len) /* (format #f "~10B" 123) */
  10426. {
  10427. start = width - len - 1;
  10428. end += start;
  10429. memset((void *)p, (int)' ', start);
  10430. }
  10431. else
  10432. {
  10433. start = 0;
  10434. end = 0;
  10435. }
  10436. if (sign)
  10437. {
  10438. p[start] = '-';
  10439. end++;
  10440. }
  10441. for (i = start + len; i >= end; i--)
  10442. {
  10443. p[i] = dignum[n % radix];
  10444. n /= radix;
  10445. }
  10446. p[len + start + 1] = '\0';
  10447. return(len + start + 1);
  10448. }
  10449. static char *integer_to_string_base_10_no_width(s7_pointer obj, int *nlen) /* do not free the returned string */
  10450. {
  10451. long long int num;
  10452. char *p, *op;
  10453. bool sign;
  10454. static char int_to_str[INT_TO_STR_SIZE];
  10455. if (has_print_name(obj))
  10456. {
  10457. (*nlen) = print_name_length(obj);
  10458. return((char *)print_name(obj));
  10459. }
  10460. /* (*nlen) = snprintf(int_to_str, INT_TO_STR_SIZE, "%lld", (long long int)integer(obj));
  10461. * but that is very slow -- the following code is 6 times faster
  10462. */
  10463. num = (long long int)integer(obj);
  10464. if (num == s7_int_min)
  10465. {
  10466. (*nlen) = 20;
  10467. return((char *)"-9223372036854775808");
  10468. }
  10469. p = (char *)(int_to_str + INT_TO_STR_SIZE - 1);
  10470. op = p;
  10471. *p-- = '\0';
  10472. sign = (num < 0);
  10473. if (sign) num = -num; /* we need a positive index below */
  10474. do {*p-- = "0123456789"[num % 10]; num /= 10;} while (num);
  10475. if (sign)
  10476. {
  10477. *p = '-';
  10478. (*nlen) = op - p;
  10479. return(p);
  10480. }
  10481. (*nlen) = op - p - 1;
  10482. return(++p);
  10483. }
  10484. #define BASE_10 10
  10485. static int num_to_str_size = -1;
  10486. static char *num_to_str = NULL;
  10487. static const char *float_format_g = NULL;
  10488. static char *floatify(char *str, int *nlen)
  10489. {
  10490. if ((strchr(str, 'e') == NULL) &&
  10491. (strchr(str, '.') == NULL))
  10492. {
  10493. /* this assumes there is room in str for 2 more chars */
  10494. int len;
  10495. len = *nlen;
  10496. str[len]='.';
  10497. str[len + 1]='0';
  10498. str[len + 2]='\0';
  10499. (*nlen) = len + 2;
  10500. }
  10501. return(str);
  10502. }
  10503. static char *number_to_string_base_10(s7_pointer obj, int width, int precision, char float_choice, int *nlen, use_write_t choice) /* don't free result */
  10504. {
  10505. /* the rest of s7 assumes nlen is set to the correct length
  10506. * a tricky case: (format #f "~f" 1e308) -- tries to print 308 digits! so 256 as default len is too small.
  10507. * but then even worse: (format #f "~F" 1e308+1e308i)!
  10508. */
  10509. int len;
  10510. len = 1024;
  10511. if (width > len) len = 2 * width;
  10512. if (len > num_to_str_size)
  10513. {
  10514. if (!num_to_str)
  10515. num_to_str = (char *)malloc(len * sizeof(char));
  10516. else num_to_str = (char *)realloc(num_to_str, len * sizeof(char));
  10517. num_to_str_size = len;
  10518. }
  10519. /* bignums can't happen here */
  10520. switch (type(obj))
  10521. {
  10522. case T_INTEGER:
  10523. if (width == 0)
  10524. return(integer_to_string_base_10_no_width(obj, nlen));
  10525. (*nlen) = snprintf(num_to_str, num_to_str_size, "%*lld", width, (long long int)integer(obj));
  10526. break;
  10527. case T_RATIO:
  10528. len = snprintf(num_to_str, num_to_str_size, "%lld/%lld", (long long int)numerator(obj), (long long int)denominator(obj));
  10529. if (width > len)
  10530. {
  10531. int spaces;
  10532. if (width >= num_to_str_size)
  10533. {
  10534. num_to_str_size = width + 1;
  10535. num_to_str = (char *)realloc(num_to_str, num_to_str_size * sizeof(char));
  10536. }
  10537. spaces = width - len;
  10538. num_to_str[width] = '\0';
  10539. memmove((void *)(num_to_str + spaces), (void *)num_to_str, len);
  10540. memset((void *)num_to_str, (int)' ', spaces);
  10541. (*nlen) = width;
  10542. }
  10543. else (*nlen) = len;
  10544. break;
  10545. case T_REAL:
  10546. {
  10547. const char *frmt;
  10548. if (sizeof(double) >= sizeof(s7_double))
  10549. frmt = (float_choice == 'g') ? "%*.*g" : ((float_choice == 'f') ? "%*.*f" : "%*.*e");
  10550. else frmt = (float_choice == 'g') ? "%*.*Lg" : ((float_choice == 'f') ? "%*.*Lf" : "%*.*Le");
  10551. len = snprintf(num_to_str, num_to_str_size - 4, frmt, width, precision, s7_real(obj)); /* -4 for floatify */
  10552. (*nlen) = len;
  10553. floatify(num_to_str, nlen);
  10554. }
  10555. break;
  10556. default:
  10557. {
  10558. if ((choice == USE_READABLE_WRITE) &&
  10559. ((is_NaN(real_part(obj))) || (is_NaN(imag_part(obj))) || ((is_inf(real_part(obj))) || (is_inf(imag_part(obj))))))
  10560. {
  10561. char rbuf[128], ibuf[128];
  10562. char *rp, *ip;
  10563. if (is_NaN(real_part(obj)))
  10564. rp = (char *)"nan.0";
  10565. else
  10566. {
  10567. if (is_inf(real_part(obj)))
  10568. {
  10569. if (real_part(obj) < 0.0)
  10570. rp = (char *)"-inf.0";
  10571. else rp = (char *)"inf.0";
  10572. }
  10573. else
  10574. {
  10575. snprintf(rbuf, 128, float_format_g, precision, real_part(obj));
  10576. rp = rbuf;
  10577. }
  10578. }
  10579. if (is_NaN(imag_part(obj)))
  10580. ip = (char *)"nan.0";
  10581. else
  10582. {
  10583. if (is_inf(imag_part(obj)))
  10584. {
  10585. if (imag_part(obj) < 0.0)
  10586. ip = (char *)"-inf.0";
  10587. else ip = (char *)"inf.0";
  10588. }
  10589. else
  10590. {
  10591. snprintf(ibuf, 128, float_format_g, precision, imag_part(obj));
  10592. ip = ibuf;
  10593. }
  10594. }
  10595. len = snprintf(num_to_str, num_to_str_size, "(complex %s %s)", rp, ip);
  10596. }
  10597. else
  10598. {
  10599. const char *frmt;
  10600. if (sizeof(double) >= sizeof(s7_double))
  10601. {
  10602. if (imag_part(obj) >= 0.0)
  10603. frmt = (float_choice == 'g') ? "%.*g+%.*gi" : ((float_choice == 'f') ? "%.*f+%.*fi" : "%.*e+%.*ei");
  10604. else frmt = (float_choice == 'g') ? "%.*g%.*gi" : ((float_choice == 'f') ? "%.*f%.*fi" :"%.*e%.*ei"); /* minus sign comes with the imag_part */
  10605. }
  10606. else
  10607. {
  10608. if (imag_part(obj) >= 0.0)
  10609. frmt = (float_choice == 'g') ? "%.*Lg+%.*Lgi" : ((float_choice == 'f') ? "%.*Lf+%.*Lfi" : "%.*Le+%.*Lei");
  10610. else frmt = (float_choice == 'g') ? "%.*Lg%.*Lgi" : ((float_choice == 'f') ? "%.*Lf%.*Lfi" : "%.*Le%.*Lei");
  10611. }
  10612. len = snprintf(num_to_str, num_to_str_size, frmt, precision, real_part(obj), precision, imag_part(obj));
  10613. }
  10614. if (width > len) /* (format #f "~20g" 1+i) */
  10615. {
  10616. int spaces;
  10617. if (width >= num_to_str_size)
  10618. {
  10619. num_to_str_size = width + 1;
  10620. num_to_str = (char *)realloc(num_to_str, num_to_str_size * sizeof(char));
  10621. }
  10622. spaces = width - len;
  10623. num_to_str[width] = '\0';
  10624. memmove((void *)(num_to_str + spaces), (void *)num_to_str, len);
  10625. memset((void *)num_to_str, (int)' ', spaces);
  10626. (*nlen) = width;
  10627. }
  10628. else (*nlen) = len;
  10629. }
  10630. break;
  10631. }
  10632. return(num_to_str);
  10633. }
  10634. static char *number_to_string_with_radix(s7_scheme *sc, s7_pointer obj, int radix, int width, int precision, char float_choice, int *nlen)
  10635. {
  10636. /* the rest of s7 assumes nlen is set to the correct length */
  10637. char *p;
  10638. int len, str_len;
  10639. #if WITH_GMP
  10640. if (s7_is_bignum(obj))
  10641. return(big_number_to_string_with_radix(obj, radix, width, nlen, USE_WRITE));
  10642. /* this ignores precision because it's way too hard to get the mpfr string to look like
  10643. * C's output -- we either have to call mpfr_get_str twice (the first time just to
  10644. * find out what the exponent is and how long the string actually is), or we have
  10645. * to do messy string manipulations. So (format #f "",3F" pi) ignores the "3" and
  10646. * prints the full string.
  10647. */
  10648. #endif
  10649. if (radix == 10)
  10650. {
  10651. p = number_to_string_base_10(obj, width, precision, float_choice, nlen, USE_WRITE);
  10652. return(copy_string_with_length(p, *nlen));
  10653. }
  10654. switch (type(obj))
  10655. {
  10656. case T_INTEGER:
  10657. p = (char *)malloc((128 + width) * sizeof(char));
  10658. *nlen = s7_int_to_string(p, s7_integer(obj), radix, width);
  10659. return(p);
  10660. case T_RATIO:
  10661. {
  10662. char n[128], d[128];
  10663. s7_int_to_string(n, numerator(obj), radix, 0);
  10664. s7_int_to_string(d, denominator(obj), radix, 0);
  10665. p = (char *)malloc(256 * sizeof(char));
  10666. len = snprintf(p, 256, "%s/%s", n, d);
  10667. str_len = 256;
  10668. }
  10669. break;
  10670. case T_REAL:
  10671. {
  10672. int i;
  10673. s7_int int_part;
  10674. s7_double x, frac_part, min_frac, base;
  10675. bool sign = false;
  10676. char n[128], d[256];
  10677. x = s7_real(obj);
  10678. if (is_NaN(x))
  10679. return(copy_string_with_length("nan.0", *nlen = 5));
  10680. if (is_inf(x))
  10681. {
  10682. if (x < 0.0)
  10683. return(copy_string_with_length("-inf.0", *nlen = 6));
  10684. return(copy_string_with_length("inf.0", *nlen = 5));
  10685. }
  10686. if (x < 0.0)
  10687. {
  10688. sign = true;
  10689. x = -x;
  10690. }
  10691. 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) */
  10692. {
  10693. int ep;
  10694. char *p1;
  10695. s7_pointer r;
  10696. len = 0;
  10697. ep = (int)floor(log(x) / log((double)radix));
  10698. r = make_real(sc, x / pow((double)radix, (double)ep)); /* divide it down to one digit, then the fractional part */
  10699. p1 = number_to_string_with_radix(sc, r, radix, width, precision, float_choice, &len);
  10700. p = (char *)malloc((len + 8) * sizeof(char));
  10701. (*nlen) = snprintf(p, len + 8, "%s%se%d", (sign) ? "-" : "", p1, ep);
  10702. free(p1);
  10703. return(p);
  10704. }
  10705. int_part = (s7_int)floor(x);
  10706. frac_part = x - int_part;
  10707. s7_int_to_string(n, int_part, radix, 0);
  10708. min_frac = (s7_double)ipow(radix, -precision);
  10709. /* doesn't this assume precision < 128/256 and that we can fit in 256 digits (1e308)? */
  10710. for (i = 0, base = radix; (i < precision) && (frac_part > min_frac); i++, base *= radix)
  10711. {
  10712. s7_int ipart;
  10713. ipart = (s7_int)(frac_part * base);
  10714. if (ipart >= radix) /* rounding confusion */
  10715. ipart = radix - 1;
  10716. frac_part -= (ipart / base);
  10717. if (ipart < 10)
  10718. d[i] = (char)('0' + ipart);
  10719. else d[i] = (char)('a' + ipart - 10);
  10720. }
  10721. if (i == 0)
  10722. d[i++] = '0';
  10723. d[i] = '\0';
  10724. p = (char *)malloc(256 * sizeof(char));
  10725. len = snprintf(p, 256, "%s%s.%s", (sign) ? "-" : "", n, d);
  10726. str_len = 256;
  10727. }
  10728. break;
  10729. default:
  10730. {
  10731. char *n, *d;
  10732. p = (char *)malloc(512 * sizeof(char));
  10733. n = number_to_string_with_radix(sc, make_real(sc, real_part(obj)), radix, 0, precision, float_choice, &len);
  10734. d = number_to_string_with_radix(sc, make_real(sc, imag_part(obj)), radix, 0, precision, float_choice, &len);
  10735. len = snprintf(p, 512, "%s%s%si", n, (imag_part(obj) < 0.0) ? "" : "+", d);
  10736. str_len = 512;
  10737. free(n);
  10738. free(d);
  10739. }
  10740. break;
  10741. }
  10742. if (width > len)
  10743. {
  10744. int spaces;
  10745. if (width >= str_len)
  10746. {
  10747. str_len = width + 1;
  10748. p = (char *)realloc(p, str_len * sizeof(char));
  10749. }
  10750. spaces = width - len;
  10751. p[width] = '\0';
  10752. memmove((void *)(p + spaces), (void *)p, len);
  10753. memset((void *)p, (int)' ', spaces);
  10754. (*nlen) = width;
  10755. }
  10756. else (*nlen) = len;
  10757. return(p);
  10758. }
  10759. char *s7_number_to_string(s7_scheme *sc, s7_pointer obj, int radix)
  10760. {
  10761. int nlen = 0;
  10762. return(number_to_string_with_radix(sc, obj, radix, 0, 20, 'g', &nlen));
  10763. /* (log top 10) so we get all the digits in base 10 (??) */
  10764. }
  10765. static void prepare_temporary_string(s7_scheme *sc, int len, int which)
  10766. {
  10767. s7_pointer p;
  10768. p = sc->tmp_strs[which];
  10769. if (len > string_temp_true_length(p))
  10770. {
  10771. string_value(p) = (char *)realloc(string_value(p), len * sizeof(char));
  10772. string_temp_true_length(p) = len;
  10773. }
  10774. }
  10775. static s7_pointer g_number_to_string_1(s7_scheme *sc, s7_pointer args, bool temporary)
  10776. {
  10777. #define H_number_to_string "(number->string num (radix 10)) converts the number num into a string."
  10778. #define Q_number_to_string s7_make_signature(sc, 3, sc->is_string_symbol, sc->is_number_symbol, sc->is_integer_symbol)
  10779. s7_int radix = 10;
  10780. int size, nlen = 0;
  10781. char *res;
  10782. s7_pointer x;
  10783. x = car(args);
  10784. if (!s7_is_number(x))
  10785. method_or_bust_with_type(sc, x, sc->number_to_string_symbol, args, a_number_string, 1);
  10786. if (is_pair(cdr(args)))
  10787. {
  10788. s7_pointer y;
  10789. y = cadr(args);
  10790. if (s7_is_integer(y))
  10791. radix = s7_integer(y);
  10792. else method_or_bust(sc, y, sc->number_to_string_symbol, args, T_INTEGER, 2);
  10793. if ((radix < 2) || (radix > 16))
  10794. return(out_of_range(sc, sc->number_to_string_symbol, small_int(2), y, a_valid_radix_string));
  10795. }
  10796. #if WITH_GMP
  10797. if (s7_is_bignum(x))
  10798. {
  10799. res = big_number_to_string_with_radix(x, radix, 0, &nlen, USE_WRITE);
  10800. return(make_string_uncopied_with_length(sc, res, nlen));
  10801. }
  10802. #endif
  10803. size = float_format_precision;
  10804. if (!is_rational(x))
  10805. {
  10806. /* if size = 20, (number->string .1) gives "0.10000000000000000555", but if it's less than 20,
  10807. * large numbers (or very small numbers) mess up the less significant digits.
  10808. */
  10809. if (radix == 10)
  10810. {
  10811. if (is_real(x))
  10812. {
  10813. s7_double val;
  10814. val = fabs(s7_real(x));
  10815. if ((val > (s7_int32_max / 4)) || (val < 1.0e-6))
  10816. size += 4;
  10817. }
  10818. else
  10819. {
  10820. s7_double rl;
  10821. rl = fabs(s7_real_part(x));
  10822. if ((rl > (s7_int32_max / 4)) || (rl < 1.0e-6))
  10823. {
  10824. s7_double im;
  10825. im = fabs(s7_imag_part(x));
  10826. if ((im > (s7_int32_max / 4)) || (im < 1.0e-6))
  10827. size += 4;
  10828. }
  10829. }
  10830. }
  10831. }
  10832. if (radix != 10)
  10833. {
  10834. res = number_to_string_with_radix(sc, x, radix, 0, size, 'g', &nlen);
  10835. return(make_string_uncopied_with_length(sc, res, nlen));
  10836. }
  10837. res = number_to_string_base_10(x, 0, size, 'g', &nlen, USE_WRITE);
  10838. if (temporary)
  10839. {
  10840. s7_pointer p;
  10841. prepare_temporary_string(sc, nlen + 1, 1);
  10842. p = sc->tmp_strs[1];
  10843. string_length(p) = nlen;
  10844. memcpy((void *)(string_value(p)), (void *)res, nlen);
  10845. string_value(p)[nlen] = 0;
  10846. return(p);
  10847. }
  10848. return(s7_make_string_with_length(sc, res, nlen));
  10849. }
  10850. static s7_pointer g_number_to_string(s7_scheme *sc, s7_pointer args)
  10851. {
  10852. return(g_number_to_string_1(sc, args, false));
  10853. }
  10854. static s7_pointer number_to_string_temp;
  10855. static s7_pointer g_number_to_string_temp(s7_scheme *sc, s7_pointer args)
  10856. {
  10857. return(g_number_to_string_1(sc, args, true));
  10858. }
  10859. static s7_pointer number_to_string_pf_temp(s7_scheme *sc, s7_pointer **p)
  10860. {
  10861. s7_pf_t f;
  10862. s7_pointer x;
  10863. f = (s7_pf_t)(**p); (*p)++;
  10864. x = f(sc, p);
  10865. return(g_number_to_string_1(sc, set_plist_1(sc, x), true));
  10866. }
  10867. static s7_pointer number_to_string_pf_s_temp(s7_scheme *sc, s7_pointer **p)
  10868. {
  10869. s7_pointer x;
  10870. (*p)++; x = slot_value(**p); (*p)++;
  10871. return(g_number_to_string_1(sc, set_plist_1(sc, x), true));
  10872. }
  10873. static s7_pointer c_number_to_string(s7_scheme *sc, s7_pointer n) {return(g_number_to_string_1(sc, set_plist_1(sc, n), false));}
  10874. PF_TO_PF(number_to_string, c_number_to_string)
  10875. #define CTABLE_SIZE 256
  10876. static bool *exponent_table, *slashify_table, *char_ok_in_a_name, *white_space, *number_table, *symbol_slashify_table;
  10877. static int *digits;
  10878. static void init_ctables(void)
  10879. {
  10880. int i;
  10881. exponent_table = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
  10882. slashify_table = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
  10883. symbol_slashify_table = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
  10884. char_ok_in_a_name = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
  10885. white_space = (bool *)calloc(CTABLE_SIZE + 1, sizeof(bool));
  10886. white_space++; /* leave white_space[-1] false for white_space[EOF] */
  10887. number_table = (bool *)calloc(CTABLE_SIZE, sizeof(bool));
  10888. for (i = 1; i < CTABLE_SIZE; i++)
  10889. char_ok_in_a_name[i] = true;
  10890. char_ok_in_a_name[0] = false;
  10891. char_ok_in_a_name[(unsigned char)'('] = false; /* idiotic cast is for C++'s benefit */
  10892. char_ok_in_a_name[(unsigned char)')'] = false;
  10893. char_ok_in_a_name[(unsigned char)';'] = false;
  10894. char_ok_in_a_name[(unsigned char)'\t'] = false;
  10895. char_ok_in_a_name[(unsigned char)'\n'] = false;
  10896. char_ok_in_a_name[(unsigned char)'\r'] = false;
  10897. char_ok_in_a_name[(unsigned char)' '] = false;
  10898. char_ok_in_a_name[(unsigned char)'"'] = false;
  10899. /* what about stuff like vertical tab? or comma? */
  10900. for (i = 0; i < CTABLE_SIZE; i++)
  10901. white_space[i] = false;
  10902. white_space[(unsigned char)'\t'] = true;
  10903. white_space[(unsigned char)'\n'] = true;
  10904. white_space[(unsigned char)'\r'] = true;
  10905. white_space[(unsigned char)'\f'] = true;
  10906. white_space[(unsigned char)'\v'] = true;
  10907. white_space[(unsigned char)' '] = true;
  10908. white_space[(unsigned char)'\205'] = true; /* 133 */
  10909. white_space[(unsigned char)'\240'] = true; /* 160 */
  10910. /* surely only 'e' is needed... */
  10911. exponent_table[(unsigned char)'e'] = true; exponent_table[(unsigned char)'E'] = true;
  10912. exponent_table[(unsigned char)'@'] = true;
  10913. #if WITH_EXTRA_EXPONENT_MARKERS
  10914. exponent_table[(unsigned char)'s'] = true; exponent_table[(unsigned char)'S'] = true;
  10915. exponent_table[(unsigned char)'f'] = true; exponent_table[(unsigned char)'F'] = true;
  10916. exponent_table[(unsigned char)'d'] = true; exponent_table[(unsigned char)'D'] = true;
  10917. exponent_table[(unsigned char)'l'] = true; exponent_table[(unsigned char)'L'] = true;
  10918. #endif
  10919. for (i = 0; i < 32; i++)
  10920. slashify_table[i] = true;
  10921. for (i = 127; i < 160; i++)
  10922. slashify_table[i] = true;
  10923. slashify_table[(unsigned char)'\\'] = true;
  10924. slashify_table[(unsigned char)'"'] = true;
  10925. slashify_table[(unsigned char)'\n'] = false;
  10926. for (i = 0; i < CTABLE_SIZE; i++)
  10927. symbol_slashify_table[i] = ((slashify_table[i]) || (!char_ok_in_a_name[i]));
  10928. digits = (int *)calloc(CTABLE_SIZE, sizeof(int));
  10929. for (i = 0; i < CTABLE_SIZE; i++)
  10930. digits[i] = 256;
  10931. digits[(unsigned char)'0'] = 0; digits[(unsigned char)'1'] = 1; digits[(unsigned char)'2'] = 2; digits[(unsigned char)'3'] = 3; digits[(unsigned char)'4'] = 4;
  10932. digits[(unsigned char)'5'] = 5; digits[(unsigned char)'6'] = 6; digits[(unsigned char)'7'] = 7; digits[(unsigned char)'8'] = 8; digits[(unsigned char)'9'] = 9;
  10933. digits[(unsigned char)'a'] = 10; digits[(unsigned char)'A'] = 10;
  10934. digits[(unsigned char)'b'] = 11; digits[(unsigned char)'B'] = 11;
  10935. digits[(unsigned char)'c'] = 12; digits[(unsigned char)'C'] = 12;
  10936. digits[(unsigned char)'d'] = 13; digits[(unsigned char)'D'] = 13;
  10937. digits[(unsigned char)'e'] = 14; digits[(unsigned char)'E'] = 14;
  10938. digits[(unsigned char)'f'] = 15; digits[(unsigned char)'F'] = 15;
  10939. for (i = 0; i < CTABLE_SIZE; i++)
  10940. number_table[i] = false;
  10941. number_table[(unsigned char)'0'] = true;
  10942. number_table[(unsigned char)'1'] = true;
  10943. number_table[(unsigned char)'2'] = true;
  10944. number_table[(unsigned char)'3'] = true;
  10945. number_table[(unsigned char)'4'] = true;
  10946. number_table[(unsigned char)'5'] = true;
  10947. number_table[(unsigned char)'6'] = true;
  10948. number_table[(unsigned char)'7'] = true;
  10949. number_table[(unsigned char)'8'] = true;
  10950. number_table[(unsigned char)'9'] = true;
  10951. number_table[(unsigned char)'.'] = true;
  10952. number_table[(unsigned char)'+'] = true;
  10953. number_table[(unsigned char)'-'] = true;
  10954. number_table[(unsigned char)'#'] = true;
  10955. }
  10956. #define is_white_space(C) white_space[C]
  10957. /* this is much faster than C's isspace, and does not depend on the current locale.
  10958. * if c == EOF (-1), it indexes into the empty (0) slot we preallocated below white_space
  10959. */
  10960. static s7_pointer check_sharp_readers(s7_scheme *sc, const char *name)
  10961. {
  10962. s7_pointer reader, value, args;
  10963. bool need_loader_port;
  10964. value = sc->F;
  10965. args = sc->F;
  10966. /* *#reader* is assumed to be an alist of (char . proc)
  10967. * where each proc takes one argument, the string from just beyond the "#" to the next delimiter.
  10968. * The procedure can call read-char to read ahead in the current-input-port.
  10969. * If it returns anything other than #f, that is the value of the sharp expression.
  10970. * Since #f means "nothing found", it is tricky to handle #F:
  10971. * (cons #\F (lambda (str) (and (string=? str "F") (list 'not #t))))
  10972. * This search happens after #|, #t, and #f (and #nD for multivectors?). #! has a fallback.
  10973. */
  10974. need_loader_port = is_loader_port(sc->input_port);
  10975. if (need_loader_port)
  10976. clear_loader_port(sc->input_port);
  10977. /* normally read* can't read from sc->input_port if it is in use by the loader,
  10978. * but here we are deliberately making that possible.
  10979. */
  10980. for (reader = slot_value(sc->sharp_readers); is_not_null(reader); reader = cdr(reader))
  10981. {
  10982. if (name[0] == s7_character(caar(reader)))
  10983. {
  10984. if (args == sc->F)
  10985. args = list_1(sc, s7_make_string(sc, name));
  10986. /* args is GC protected by s7_apply_function?? (placed on the stack) */
  10987. value = s7_apply_function(sc, cdar(reader), args); /* this is much less error-safe than s7_call */
  10988. if (value != sc->F)
  10989. break;
  10990. }
  10991. }
  10992. if (need_loader_port)
  10993. set_loader_port(sc->input_port);
  10994. return(value);
  10995. }
  10996. static s7_pointer g_sharp_readers_set(s7_scheme *sc, s7_pointer args)
  10997. {
  10998. /* new value must be either () or a proper list of conses (char . func) */
  10999. if (is_null(cadr(args))) return(cadr(args));
  11000. if (is_pair(cadr(args)))
  11001. {
  11002. s7_pointer x;
  11003. for (x = cadr(args); is_pair(x); x = cdr(x))
  11004. {
  11005. if ((!is_pair(car(x))) ||
  11006. (!s7_is_character(caar(x))) ||
  11007. (!s7_is_procedure(cdar(x))))
  11008. return(sc->error_symbol);
  11009. }
  11010. if (is_null(x))
  11011. return(cadr(args));
  11012. }
  11013. return(sc->error_symbol);
  11014. }
  11015. static bool is_abnormal(s7_pointer x)
  11016. {
  11017. switch (type(x))
  11018. {
  11019. case T_INTEGER:
  11020. case T_RATIO:
  11021. return(false);
  11022. case T_REAL:
  11023. return(is_inf(real(x)) ||
  11024. is_NaN(real(x)));
  11025. case T_COMPLEX:
  11026. return(((is_inf(s7_real_part(x))) ||
  11027. (is_inf(s7_imag_part(x))) ||
  11028. (is_NaN(s7_real_part(x))) ||
  11029. (is_NaN(s7_imag_part(x)))));
  11030. #if WITH_GMP
  11031. case T_BIG_INTEGER:
  11032. case T_BIG_RATIO:
  11033. return(false);
  11034. case T_BIG_REAL:
  11035. return((is_inf(s7_real_part(x))) ||
  11036. (is_NaN(s7_real_part(x))));
  11037. case T_BIG_COMPLEX:
  11038. return((is_inf(s7_real_part(x))) ||
  11039. (is_inf(s7_imag_part(x))) ||
  11040. (is_NaN(s7_real_part(x))) ||
  11041. (is_NaN(s7_imag_part(x))));
  11042. #endif
  11043. default:
  11044. return(true);
  11045. }
  11046. }
  11047. static s7_pointer unknown_sharp_constant(s7_scheme *sc, char *name)
  11048. {
  11049. /* check *read-error-hook* */
  11050. if (hook_has_functions(sc->read_error_hook))
  11051. {
  11052. s7_pointer result;
  11053. result = s7_call(sc, sc->read_error_hook, list_2(sc, sc->T, make_string_wrapper(sc, name)));
  11054. if (result != sc->unspecified)
  11055. return(result);
  11056. }
  11057. return(sc->nil);
  11058. }
  11059. #define NESTED_SHARP false
  11060. #define UNNESTED_SHARP true
  11061. #define SYMBOL_OK true
  11062. #define NO_SYMBOLS false
  11063. static s7_pointer make_sharp_constant(s7_scheme *sc, char *name, bool at_top, int radix, bool with_error)
  11064. {
  11065. /* name is the stuff after the '#', return sc->nil if not a recognized #... entity */
  11066. int len;
  11067. s7_pointer x;
  11068. if ((name[0] == 't') &&
  11069. ((name[1] == '\0') || (strings_are_equal(name, "true"))))
  11070. return(sc->T);
  11071. if ((name[0] == 'f') &&
  11072. ((name[1] == '\0') || (strings_are_equal(name, "false"))))
  11073. return(sc->F);
  11074. if (is_not_null(slot_value(sc->sharp_readers)))
  11075. {
  11076. x = check_sharp_readers(sc, name);
  11077. if (x != sc->F)
  11078. return(x);
  11079. }
  11080. len = safe_strlen5(name); /* just count up to 5 */
  11081. if (len < 2)
  11082. return(unknown_sharp_constant(sc, name));
  11083. switch (name[0])
  11084. {
  11085. /* -------- #< ... > -------- */
  11086. case '<':
  11087. if (strings_are_equal(name, "<unspecified>"))
  11088. return(sc->unspecified);
  11089. if (strings_are_equal(name, "<undefined>"))
  11090. return(sc->undefined);
  11091. if (strings_are_equal(name, "<eof>"))
  11092. return(sc->eof_object);
  11093. return(unknown_sharp_constant(sc, name));
  11094. /* -------- #o #d #x #b -------- */
  11095. case 'o': /* #o (octal) */
  11096. case 'd': /* #d (decimal) */
  11097. case 'x': /* #x (hex) */
  11098. case 'b': /* #b (binary) */
  11099. {
  11100. int num_at = 1;
  11101. #if (!WITH_PURE_S7)
  11102. bool to_inexact = false, to_exact = false;
  11103. if (name[1] == '#')
  11104. {
  11105. if (!at_top)
  11106. return(unknown_sharp_constant(sc, name));
  11107. if ((len > 2) && ((name[2] == 'e') || (name[2] == 'i'))) /* r6rs includes caps here */
  11108. {
  11109. if ((len > 3) && (name[3] == '#'))
  11110. return(unknown_sharp_constant(sc, name));
  11111. to_inexact = (name[2] == 'i');
  11112. to_exact = (name[2] == 'e');
  11113. num_at = 3;
  11114. }
  11115. else return(unknown_sharp_constant(sc, name));
  11116. }
  11117. #endif
  11118. /* the #b or whatever overrides any radix passed in earlier */
  11119. x = make_atom(sc, (char *)(name + num_at), (name[0] == 'o') ? 8 : ((name[0] == 'x') ? 16 : ((name[0] == 'b') ? 2 : 10)), NO_SYMBOLS, with_error);
  11120. /* #x#i1 apparently makes sense, so #x1.0 should also be accepted.
  11121. * here we can get #b#e0/0 or #b#e+1/0 etc.
  11122. * surely if #e1+i is an error (or #f), and #e#x1+i is an error,
  11123. * #x#e1+i should also be an error, but #e1+0i is not an error I guess since there actually isn't any imaginary part
  11124. */
  11125. if (is_abnormal(x))
  11126. return(unknown_sharp_constant(sc, name));
  11127. #if (!WITH_PURE_S7)
  11128. if ((!to_exact) && (!to_inexact))
  11129. return(x);
  11130. if ((s7_imag_part(x) != 0.0) && (to_exact)) /* #x#e1+i */
  11131. return(unknown_sharp_constant(sc, name));
  11132. #if WITH_GMP
  11133. if (s7_is_bignum(x))
  11134. {
  11135. if (to_exact)
  11136. return(big_inexact_to_exact(sc, set_plist_1(sc, x)));
  11137. return(big_exact_to_inexact(sc, set_plist_1(sc, x)));
  11138. }
  11139. #endif
  11140. if (to_exact)
  11141. return(inexact_to_exact(sc, x, with_error));
  11142. return(exact_to_inexact(sc, x));
  11143. #else
  11144. return(x);
  11145. #endif
  11146. }
  11147. break;
  11148. #if (!WITH_PURE_S7)
  11149. /* -------- #i -------- */
  11150. case 'i': /* #i<num> = ->inexact (see token for table of choices here) */
  11151. if (name[1] == '#')
  11152. {
  11153. /* there are special cases here: "#e0/0" or "#e#b0/0" -- all infs are complex:
  11154. * #i1/0=nan.0 but #i1/0+i=inf+1i so e->i is a no-op but i->e is not
  11155. *
  11156. * even trickier: a *#reader* like #t<num> could be used as #e#t13.25 so make_sharp_constant
  11157. * needs to be willing to call the readers even when not at_top (i.e. when NESTED_SHARP).
  11158. */
  11159. if ((name[2] == 'e') || /* #i#e1 -- assume these aren't redefinable? */
  11160. (name[2] == 'i'))
  11161. return(unknown_sharp_constant(sc, name));
  11162. x = make_sharp_constant(sc, (char *)(name + 2), NESTED_SHARP, radix, with_error);
  11163. if (s7_is_number(x))
  11164. {
  11165. if (is_abnormal(x))
  11166. return(unknown_sharp_constant(sc, name));
  11167. #if WITH_GMP
  11168. if (s7_is_bignum(x)) /* (string->number "#b#e-11e+111") */
  11169. return(big_exact_to_inexact(sc, set_plist_1(sc, x)));
  11170. #endif
  11171. return(exact_to_inexact(sc, x));
  11172. }
  11173. return(unknown_sharp_constant(sc, name));
  11174. }
  11175. x = make_atom(sc, (char *)(name + 1), radix, NO_SYMBOLS, with_error);
  11176. if (!s7_is_number(x)) /* not is_abnormal(x) -- #i0/0 -> nan etc */
  11177. return(unknown_sharp_constant(sc, name));
  11178. #if WITH_GMP
  11179. if (s7_is_bignum(x))
  11180. return(big_exact_to_inexact(sc, set_plist_1(sc, x)));
  11181. #endif
  11182. return(exact_to_inexact(sc, x));
  11183. /* -------- #e -------- */
  11184. case 'e': /* #e<num> = ->exact */
  11185. if (name[1] == '#')
  11186. {
  11187. if ((name[2] == 'e') || /* #e#e1 */
  11188. (name[2] == 'i'))
  11189. return(unknown_sharp_constant(sc, name));
  11190. x = make_sharp_constant(sc, (char *)(name + 2), NESTED_SHARP, radix, with_error);
  11191. if (s7_is_number(x))
  11192. {
  11193. if (is_abnormal(x)) /* (string->number "#e#b0/0") */
  11194. return(unknown_sharp_constant(sc, name));
  11195. if (!s7_is_real(x)) /* (string->number "#e#b1+i") */
  11196. return(unknown_sharp_constant(sc, name));
  11197. #if WITH_GMP
  11198. return(big_inexact_to_exact(sc, set_plist_1(sc, x)));
  11199. #endif
  11200. return(inexact_to_exact(sc, x, with_error));
  11201. }
  11202. return(unknown_sharp_constant(sc, name));
  11203. }
  11204. x = make_atom(sc, (char *)(name + 1), radix, NO_SYMBOLS, with_error);
  11205. #if WITH_GMP
  11206. /* #e1e310 is a simple case */
  11207. if (s7_is_bignum(x))
  11208. return(big_inexact_to_exact(sc, set_plist_1(sc, x)));
  11209. #endif
  11210. if (is_abnormal(x)) /* (string->number "#e0/0") */
  11211. return(unknown_sharp_constant(sc, name));
  11212. if (!s7_is_real(x)) /* (string->number "#e1+i") */
  11213. return(unknown_sharp_constant(sc, name));
  11214. #if WITH_GMP
  11215. /* there are non-big floats that are greater than most-positive-fixnum:
  11216. * :(> .1e20 most-positive-fixnum) -> #t
  11217. * :(bignum? .1e20) -> #f
  11218. * so we have to check that, not just is it a bignum.
  11219. */
  11220. return(big_inexact_to_exact(sc, set_plist_1(sc, x)));
  11221. #endif
  11222. return(inexact_to_exact(sc, x, with_error));
  11223. #endif /* !WITH_PURE_S7 */
  11224. /* -------- #_... -------- */
  11225. case '_':
  11226. {
  11227. s7_pointer sym;
  11228. sym = make_symbol(sc, (char *)(name + 1));
  11229. if (is_slot(initial_slot(sym)))
  11230. return(slot_value(initial_slot(sym)));
  11231. return(s7_error(sc, sc->syntax_error_symbol, set_elist_2(sc, make_string_wrapper(sc, "#~A is undefined"), make_string_wrapper(sc, name))));
  11232. /* return(sc->undefined); */
  11233. }
  11234. /* -------- #\... -------- */
  11235. case '\\':
  11236. if (name[2] == 0) /* the most common case: #\a */
  11237. return(chars[(unsigned char)(name[1])]);
  11238. /* not unsigned int here! (unsigned int)255 (as a char) returns -1!! */
  11239. switch (name[1])
  11240. {
  11241. case 'n':
  11242. if ((strings_are_equal(name + 1, "null")) ||
  11243. (strings_are_equal(name + 1, "nul")))
  11244. return(chars[0]);
  11245. if (strings_are_equal(name + 1, "newline"))
  11246. return(chars[(unsigned char)'\n']);
  11247. break;
  11248. case 's':
  11249. if (strings_are_equal(name + 1, "space"))
  11250. return(chars[(unsigned char)' ']);
  11251. break;
  11252. case 'r':
  11253. if (strings_are_equal(name + 1, "return"))
  11254. return(chars[(unsigned char)'\r']);
  11255. break;
  11256. case 'l':
  11257. if (strings_are_equal(name + 1, "linefeed"))
  11258. return(chars[(unsigned char)'\n']);
  11259. break;
  11260. case 't':
  11261. if (strings_are_equal(name + 1, "tab"))
  11262. return(chars[(unsigned char)'\t']);
  11263. break;
  11264. case 'a':
  11265. /* the next 4 are for r7rs */
  11266. if (strings_are_equal(name + 1, "alarm"))
  11267. return(chars[7]);
  11268. break;
  11269. case 'b':
  11270. if (strings_are_equal(name + 1, "backspace"))
  11271. return(chars[8]);
  11272. break;
  11273. case 'e':
  11274. if (strings_are_equal(name + 1, "escape"))
  11275. return(chars[0x1b]);
  11276. break;
  11277. case 'd':
  11278. if (strings_are_equal(name + 1, "delete"))
  11279. return(chars[0x7f]);
  11280. break;
  11281. case 'x':
  11282. /* #\x is just x, but apparently #\x<num> is int->char? #\x65 -> #\e -- Guile doesn't have this
  11283. *
  11284. * r7rs has 2/3/4-byte "characters" of the form #\xcebb but this is not compatible with
  11285. * make-string, string-length, and so on. We'd either have to have 2-byte chars
  11286. * so (string-length (make-string 3 #\xcebb)) = 3, or accept 6 here for number of chars.
  11287. * Then substring and string-set! and so on have to use utf8 encoding throughout or
  11288. * risk changing the string length unexpectedly.
  11289. */
  11290. {
  11291. /* sscanf here misses errors like #\x1.4, but make_atom misses #\x6/3,
  11292. * #\x#b0, #\x#e0.0, #\x-0, #\x#e0e100 etc, so we have to do it at
  11293. * an even lower level.
  11294. * another problem: #\xbdca2cbec overflows so lval is -593310740 -> segfault unless caught
  11295. */
  11296. bool happy = true;
  11297. char *tmp;
  11298. int lval = 0;
  11299. tmp = (char *)(name + 2);
  11300. while ((*tmp) && (happy) && (lval >= 0))
  11301. {
  11302. int dig;
  11303. dig = digits[(int)(*tmp++)];
  11304. if (dig < 16)
  11305. lval = dig + (lval * 16);
  11306. else happy = false;
  11307. }
  11308. if ((happy) &&
  11309. (lval < 256) &&
  11310. (lval >= 0))
  11311. return(chars[lval]);
  11312. }
  11313. break;
  11314. }
  11315. }
  11316. return(unknown_sharp_constant(sc, name));
  11317. }
  11318. static s7_int string_to_integer(const char *str, int radix, bool *overflow)
  11319. {
  11320. bool negative = false;
  11321. s7_int lval = 0;
  11322. int dig;
  11323. char *tmp = (char *)str;
  11324. char *tmp1;
  11325. if (str[0] == '+')
  11326. tmp++;
  11327. else
  11328. {
  11329. if (str[0] == '-')
  11330. {
  11331. negative = true;
  11332. tmp++;
  11333. }
  11334. }
  11335. while (*tmp == '0') {tmp++;};
  11336. tmp1 = tmp;
  11337. if (radix == 10)
  11338. {
  11339. while (true)
  11340. {
  11341. dig = digits[(unsigned char)(*tmp++)];
  11342. if (dig > 9) break;
  11343. #if HAVE_OVERFLOW_CHECKS
  11344. if (multiply_overflow(lval, (s7_int)10, &lval)) break;
  11345. if (add_overflow(lval, (s7_int)dig, &lval)) break;
  11346. #else
  11347. lval = dig + (lval * 10);
  11348. dig = digits[(unsigned char)(*tmp++)];
  11349. if (dig > 9) break;
  11350. lval = dig + (lval * 10);
  11351. #endif
  11352. }
  11353. }
  11354. else
  11355. {
  11356. while (true)
  11357. {
  11358. dig = digits[(unsigned char)(*tmp++)];
  11359. if (dig >= radix) break;
  11360. #if HAVE_OVERFLOW_CHECKS
  11361. if (multiply_overflow(lval, (s7_int)radix, &lval)) break;
  11362. if (add_overflow(lval, (s7_int)dig, &lval)) break;
  11363. #else
  11364. lval = dig + (lval * radix);
  11365. dig = digits[(unsigned char)(*tmp++)];
  11366. if (dig >= radix) break;
  11367. lval = dig + (lval * radix);
  11368. #endif
  11369. }
  11370. }
  11371. #if WITH_GMP
  11372. (*overflow) = ((lval > s7_int32_max) ||
  11373. ((tmp - tmp1) > s7_int_digits_by_radix[radix]));
  11374. /* this tells the string->number readers to create a bignum. We need to be very
  11375. * conservative here to catch contexts such as (/ 1/524288 19073486328125)
  11376. */
  11377. #else
  11378. if ((tmp - tmp1 - 2) > s7_int_digits_by_radix[radix])
  11379. {
  11380. /* I can't decide what to do with these non-gmp overflows. Perhaps NAN in all cases?
  11381. * overflow: 9223372036854775810 -> -9223372036854775806 -- this is not caught currently
  11382. */
  11383. (*overflow) = true;
  11384. if (negative)
  11385. return(s7_int_min); /* or INFINITY? */
  11386. return(s7_int_max); /* 0/100000000000000000000000000000000000000000000000000000000000000000000 */
  11387. }
  11388. #endif
  11389. if (negative)
  11390. return(-lval);
  11391. return(lval);
  11392. }
  11393. /* 9223372036854775807 9223372036854775807
  11394. * -9223372036854775808 -9223372036854775808
  11395. * 0000000000000000000000000001.0 1.0
  11396. * 1.0000000000000000000000000000 1.0
  11397. * 1000000000000000000000000000.0e-40 1.0e-12
  11398. * 0.0000000000000000000000000001e40 1.0e12
  11399. * 1.0e00000000000000000001 10.0
  11400. */
  11401. static s7_double string_to_double_with_radix(const char *ur_str, int radix, bool *overflow)
  11402. {
  11403. /* strtod follows LANG which is not what we want (only "." is decimal point in Scheme).
  11404. * To overcome LANG in strtod would require screwing around with setlocale which never works.
  11405. * So we use our own code -- according to valgrind, this function is much faster than strtod.
  11406. *
  11407. * comma as decimal point causes ambiguities: `(+ ,1 2) etc
  11408. */
  11409. int i, sign = 1, frac_len, int_len, dig, max_len, exponent = 0;
  11410. long long int int_part = 0, frac_part = 0;
  11411. char *str;
  11412. char *ipart, *fpart;
  11413. s7_double dval = 0.0;
  11414. /* 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?
  11415. * but 1e+1, for example disambiguates it -- kind of messy! -- the scheme spec says "e" can only occur in base 10.
  11416. * mpfr says "e" as exponent only in bases <= 10 -- else use '@' which works in any base. This can only cause confusion
  11417. * in scheme, unfortunately, due to the idiotic scheme polar notation. But we accept "s" and "l" as exponent markers
  11418. * so, perhaps for radix > 10, the exponent, if any, has to use one of S s L l? Not "l"! And "s" originally meant "short".
  11419. *
  11420. * '@' can now be used as the exponent marker (26-Mar-12).
  11421. * 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
  11422. */
  11423. max_len = s7_int_digits_by_radix[radix];
  11424. str = (char *)ur_str;
  11425. if (*str == '+')
  11426. str++;
  11427. else
  11428. {
  11429. if (*str == '-')
  11430. {
  11431. str++;
  11432. sign = -1;
  11433. }
  11434. }
  11435. while (*str == '0') {str++;};
  11436. ipart = str;
  11437. while (digits[(int)(*str)] < radix) str++;
  11438. int_len = str - ipart;
  11439. if (*str == '.') str++;
  11440. fpart = str;
  11441. while (digits[(int)(*str)] < radix) str++;
  11442. frac_len = str - fpart;
  11443. if ((*str) && (exponent_table[(unsigned char)(*str)]))
  11444. {
  11445. int exp_negative = false;
  11446. str++;
  11447. if (*str == '+')
  11448. str++;
  11449. else
  11450. {
  11451. if (*str == '-')
  11452. {
  11453. str++;
  11454. exp_negative = true;
  11455. }
  11456. }
  11457. while ((dig = digits[(int)(*str++)]) < 10) /* exponent itself is always base 10 */
  11458. {
  11459. #if HAVE_OVERFLOW_CHECKS
  11460. if ((int_multiply_overflow(exponent, 10, &exponent)) ||
  11461. (int_add_overflow(exponent, dig, &exponent)))
  11462. {
  11463. exponent = 1000000; /* see below */
  11464. break;
  11465. }
  11466. #else
  11467. exponent = dig + (exponent * 10);
  11468. #endif
  11469. }
  11470. #if (!defined(__GNUC__)) || (__GNUC__ < 5)
  11471. if (exponent < 0) /* we overflowed, so make sure we notice it below (need to check for 0.0e... first) (Brian Damgaard) */
  11472. exponent = 1000000; /* see below for examples -- this number needs to be very big but not too big for add */
  11473. #endif
  11474. if (exp_negative)
  11475. exponent = -exponent;
  11476. /* 2e12341234123123123123213123123123 -> 0.0
  11477. * but exp len is not the decider: 2e00000000000000000000000000000000000000001 -> 20.0
  11478. * first zero: 2e123412341231231231231
  11479. * then: 2e12341234123123123123123123 -> inf
  11480. * then: 2e123412341231231231231231231231231231 -> 0.0
  11481. * 2e-123412341231231231231 -> inf
  11482. * but: 0e123412341231231231231231231231231231
  11483. */
  11484. }
  11485. #if WITH_GMP
  11486. /* 9007199254740995.0 */
  11487. if (int_len + frac_len >= max_len)
  11488. {
  11489. (*overflow) = true;
  11490. return(0.0);
  11491. }
  11492. #endif
  11493. str = ipart;
  11494. if ((int_len + exponent) > max_len)
  11495. {
  11496. /* 12341234.56789e12 12341234567889999872.0 1.234123456789e+19
  11497. * -1234567890123456789.0 -1234567890123456768.0 -1.2345678901235e+18
  11498. * 12345678901234567890.0 12345678901234567168.0 1.2345678901235e+19
  11499. * 123.456e30 123456000000000012741097792995328.0 1.23456e+32
  11500. * 12345678901234567890.0e12 12345678901234569054409354903552.0 1.2345678901235e+31
  11501. * 1.234567890123456789012e30 1234567890123456849145940148224.0 1.2345678901235e+30
  11502. * 1e20 100000000000000000000.0 1e+20
  11503. * 1234567890123456789.0 1234567890123456768.0 1.2345678901235e+18
  11504. * 123.456e16 1234560000000000000.0 1.23456e+18
  11505. * 98765432101234567890987654321.0e-5 987654321012345728401408.0 9.8765432101235e+23
  11506. * 98765432101234567890987654321.0e-10 9876543210123456512.0 9.8765432101235e+18
  11507. * 0.00000000000000001234e20 1234.0
  11508. * 0.000000000000000000000000001234e30 1234.0
  11509. * 0.0000000000000000000000000000000000001234e40 1234.0
  11510. * 0.000000000012345678909876543210e15 12345.678909877
  11511. * 0e1000 0.0
  11512. */
  11513. for (i = 0; i < max_len; i++)
  11514. {
  11515. dig = digits[(int)(*str++)];
  11516. if (dig < radix)
  11517. int_part = dig + (int_part * radix);
  11518. else break;
  11519. }
  11520. /* if the exponent is huge, check for 0 int_part and frac_part before complaining (0e1000 or 0.0e1000)
  11521. */
  11522. if ((int_part == 0) &&
  11523. (exponent > max_len))
  11524. {
  11525. /* if frac_part is also 0, return 0.0 */
  11526. if (frac_len == 0)
  11527. return(0.0);
  11528. str = fpart;
  11529. while ((dig = digits[(int)(*str++)]) < radix)
  11530. frac_part = dig + (frac_part * radix);
  11531. if (frac_part == 0)
  11532. return(0.0);
  11533. #if WITH_GMP
  11534. (*overflow) = true;
  11535. #endif
  11536. }
  11537. #if WITH_GMP
  11538. (*overflow) = ((int_part > 0) || (exponent > 20)); /* .1e310 is a tricky case */
  11539. #endif
  11540. if (int_part != 0) /* 0.<310 zeros here>1e310 for example --
  11541. * pow (via ipow) thinks it has to be too big, returns Nan,
  11542. * then Nan * 0 -> Nan and the NaN propagates
  11543. */
  11544. {
  11545. if (int_len <= max_len)
  11546. dval = int_part * ipow(radix, exponent);
  11547. else dval = int_part * ipow(radix, exponent + int_len - max_len);
  11548. }
  11549. else dval = 0.0;
  11550. /* shift by exponent, but if int_len > max_len then we assumed (see below) int_len - max_len 0's on the left */
  11551. /* using int_to_int or table lookups here instead of pow did not make any difference in speed */
  11552. if (int_len < max_len)
  11553. {
  11554. int k, flen;
  11555. str = fpart;
  11556. for (k = 0; (frac_len > 0) && (k < exponent); k += max_len)
  11557. {
  11558. if (frac_len > max_len) flen = max_len; else flen = frac_len;
  11559. frac_len -= max_len;
  11560. frac_part = 0;
  11561. for (i = 0; i < flen; i++)
  11562. frac_part = digits[(int)(*str++)] + (frac_part * radix);
  11563. if (frac_part != 0) /* same pow->NaN problem as above can occur here */
  11564. dval += frac_part * ipow(radix, exponent - flen - k);
  11565. }
  11566. }
  11567. else
  11568. {
  11569. /* some of the fraction is in the integer part before the negative exponent shifts it over */
  11570. if (int_len > max_len)
  11571. {
  11572. int ilen;
  11573. /* str should be at the last digit we read */
  11574. ilen = int_len - max_len; /* we read these above */
  11575. if (ilen > max_len)
  11576. ilen = max_len;
  11577. for (i = 0; i < ilen; i++)
  11578. frac_part = digits[(int)(*str++)] + (frac_part * radix);
  11579. dval += frac_part * ipow(radix, exponent - ilen);
  11580. }
  11581. }
  11582. return(sign * dval);
  11583. }
  11584. /* int_len + exponent <= max_len */
  11585. if (int_len <= max_len)
  11586. {
  11587. int int_exponent;
  11588. /* a better algorithm (since the inaccuracies are in the radix^exponent portion):
  11589. * strip off leading zeros and possible sign,
  11590. * strip off digits beyond max_len, then remove any trailing zeros.
  11591. * (maybe fiddle with the lowest order digit here for rounding, but I doubt it matters)
  11592. * read digits until end of number or max_len reached, ignoring the decimal point
  11593. * get exponent and use it and decimal point location to position the current result integer
  11594. * this always combines the same integer and the same exponent no matter how the number is expressed.
  11595. */
  11596. int_exponent = exponent;
  11597. if (int_len > 0)
  11598. {
  11599. char *iend;
  11600. iend = (char *)(str + int_len - 1);
  11601. while ((*iend == '0') && (iend != str)) {iend--; int_exponent++;}
  11602. while (str <= iend)
  11603. int_part = digits[(int)(*str++)] + (int_part * radix);
  11604. }
  11605. if (int_exponent != 0)
  11606. dval = int_part * ipow(radix, int_exponent);
  11607. else dval = (s7_double)int_part;
  11608. }
  11609. else
  11610. {
  11611. int len, flen;
  11612. long long int frpart = 0;
  11613. /* 98765432101234567890987654321.0e-20 987654321.012346
  11614. * 98765432101234567890987654321.0e-29 0.98765432101235
  11615. * 98765432101234567890987654321.0e-30 0.098765432101235
  11616. * 98765432101234567890987654321.0e-28 9.8765432101235
  11617. */
  11618. len = int_len + exponent;
  11619. for (i = 0; i < len; i++)
  11620. int_part = digits[(int)(*str++)] + (int_part * radix);
  11621. flen = -exponent;
  11622. if (flen > max_len)
  11623. flen = max_len;
  11624. for (i = 0; i < flen; i++)
  11625. frpart = digits[(int)(*str++)] + (frpart * radix);
  11626. if (len <= 0)
  11627. dval = int_part + frpart * ipow(radix, len - flen);
  11628. else dval = int_part + frpart * ipow(radix, -flen);
  11629. }
  11630. if (frac_len > 0)
  11631. {
  11632. str = fpart;
  11633. if (frac_len <= max_len)
  11634. {
  11635. /* splitting out base 10 case saves very little here */
  11636. /* this ignores trailing zeros, so that 0.3 equals 0.300 */
  11637. char *fend;
  11638. fend = (char *)(str + frac_len - 1);
  11639. while ((*fend == '0') && (fend != str)) {fend--; frac_len--;} /* (= .6 0.6000) */
  11640. while (str <= fend)
  11641. frac_part = digits[(int)(*str++)] + (frac_part * radix);
  11642. dval += frac_part * ipow(radix, exponent - frac_len);
  11643. /* fprintf(stderr, "frac: %lld, exp: (%d %d) %.20f, val: %.20f\n", frac_part, exponent, frac_len, ipow(radix, exponent - frac_len), dval);
  11644. * 0.6: frac: 6, exp: 0.10000000000000000555, val: 0.60000000000000008882
  11645. * 0.60: frac: 60, exp: 0.01000000000000000021, val: 0.59999999999999997780
  11646. * 0.6000: frac: 6000, exp: 0.00010000000000000000, val: 0.59999999999999997780
  11647. * :(= 0.6 0.60)
  11648. * #f
  11649. * :(= #i3/5 0.6)
  11650. * #f
  11651. * so (string->number (number->string num)) == num only if both num's are the same text (or you get lucky)
  11652. * :(= 0.6 6e-1) ; but not 60e-2
  11653. * #t
  11654. *
  11655. * to fix the 0.60 case, we need to ignore trailing post-dot zeros.
  11656. */
  11657. }
  11658. else
  11659. {
  11660. if (exponent <= 0)
  11661. {
  11662. for (i = 0; i < max_len; i++)
  11663. frac_part = digits[(int)(*str++)] + (frac_part * radix);
  11664. dval += frac_part * ipow(radix, exponent - max_len);
  11665. }
  11666. else
  11667. {
  11668. /* 1.0123456789876543210e1 10.12345678987654373771
  11669. * 1.0123456789876543210e10 10123456789.87654304504394531250
  11670. * 0.000000010000000000000000e10 100.0
  11671. * 0.000000010000000000000000000000000000000000000e10 100.0
  11672. * 0.000000012222222222222222222222222222222222222e10 122.22222222222222
  11673. * 0.000000012222222222222222222222222222222222222e17 1222222222.222222
  11674. */
  11675. int_part = 0;
  11676. for (i = 0; i < exponent; i++)
  11677. int_part = digits[(int)(*str++)] + (int_part * radix);
  11678. frac_len -= exponent;
  11679. if (frac_len > max_len)
  11680. frac_len = max_len;
  11681. for (i = 0; i < frac_len; i++)
  11682. frac_part = digits[(int)(*str++)] + (frac_part * radix);
  11683. dval += int_part + frac_part * ipow(radix, -frac_len);
  11684. }
  11685. }
  11686. }
  11687. #if WITH_GMP
  11688. if ((int_part == 0) &&
  11689. (frac_part == 0))
  11690. return(0.0);
  11691. (*overflow) = ((frac_len - exponent) > max_len);
  11692. #endif
  11693. return(sign * dval);
  11694. }
  11695. static s7_pointer make_atom(s7_scheme *sc, char *q, int radix, bool want_symbol, bool with_error)
  11696. {
  11697. /* make symbol or number from string */
  11698. #define IS_DIGIT(Chr, Rad) (digits[(unsigned char)Chr] < Rad)
  11699. char c, *p;
  11700. bool has_dec_point1 = false;
  11701. p = q;
  11702. c = *p++;
  11703. /* a number starts with + - . or digit, but so does 1+ for example */
  11704. switch (c)
  11705. {
  11706. case '#':
  11707. return(make_sharp_constant(sc, p, UNNESTED_SHARP, radix, with_error)); /* make_sharp_constant expects the '#' to be removed */
  11708. case '+':
  11709. case '-':
  11710. c = *p++;
  11711. if (c == '.')
  11712. {
  11713. has_dec_point1 = true;
  11714. c = *p++;
  11715. }
  11716. if ((!c) || (!IS_DIGIT(c, radix)))
  11717. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11718. break;
  11719. case '.':
  11720. has_dec_point1 = true;
  11721. c = *p++;
  11722. if ((!c) || (!IS_DIGIT(c, radix)))
  11723. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11724. break;
  11725. case '0': /* these two are always digits */
  11726. case '1':
  11727. break;
  11728. default:
  11729. if (!IS_DIGIT(c, radix))
  11730. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11731. break;
  11732. }
  11733. /* now it's possibly a number -- the first character(s) could be part of a number in the current radix */
  11734. {
  11735. char *slash1 = NULL, *slash2 = NULL, *plus = NULL, *ex1 = NULL, *ex2 = NULL;
  11736. bool has_i = false, has_dec_point2 = false;
  11737. int has_plus_or_minus = 0, current_radix;
  11738. #if (!WITH_GMP)
  11739. bool overflow = false;
  11740. #endif
  11741. current_radix = radix; /* current_radix is 10 for the exponent portions, but radix for all the rest */
  11742. for ( ; (c = *p) != 0; ++p)
  11743. {
  11744. /* what about embedded null? (string->number (string #\1 (integer->char 0) #\0))
  11745. * currently we stop and return 1, but Guile returns #f
  11746. */
  11747. if (!IS_DIGIT(c, current_radix)) /* moving this inside the switch statement was much slower */
  11748. {
  11749. current_radix = radix;
  11750. switch (c)
  11751. {
  11752. /* -------- decimal point -------- */
  11753. case '.':
  11754. if ((!IS_DIGIT(p[1], current_radix)) &&
  11755. (!IS_DIGIT(p[-1], current_radix)))
  11756. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11757. if (has_plus_or_minus == 0)
  11758. {
  11759. if ((has_dec_point1) || (slash1))
  11760. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11761. has_dec_point1 = true;
  11762. }
  11763. else
  11764. {
  11765. if ((has_dec_point2) || (slash2))
  11766. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11767. has_dec_point2 = true;
  11768. }
  11769. continue;
  11770. /* -------- exponent marker -------- */
  11771. #if WITH_EXTRA_EXPONENT_MARKERS
  11772. /* 1st 3d-perspective 0.0f 128.0f 3d 1s -- in 2 million lines of public scheme code, not one actual use! */
  11773. case 's': case 'S':
  11774. case 'd': case 'D':
  11775. case 'f': case 'F':
  11776. case 'l': case 'L':
  11777. #endif
  11778. case 'e': case 'E':
  11779. if (current_radix > 10)
  11780. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11781. /* see note above */
  11782. /* fall through -- if '@' used, radices>10 are ok */
  11783. case '@':
  11784. current_radix = 10;
  11785. if (((ex1) ||
  11786. (slash1)) &&
  11787. (has_plus_or_minus == 0)) /* ee */
  11788. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11789. if (((ex2) ||
  11790. (slash2)) &&
  11791. (has_plus_or_minus != 0)) /* 1+1.0ee */
  11792. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11793. if ((!IS_DIGIT(p[-1], radix)) && /* was current_radix but that's always 10! */
  11794. (p[-1] != '.'))
  11795. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11796. if (has_plus_or_minus == 0)
  11797. {
  11798. ex1 = p;
  11799. has_dec_point1 = true; /* decimal point illegal from now on */
  11800. }
  11801. else
  11802. {
  11803. ex2 = p;
  11804. has_dec_point2 = true;
  11805. }
  11806. p++;
  11807. if ((*p == '-') || (*p == '+')) p++;
  11808. if (IS_DIGIT(*p, current_radix))
  11809. continue;
  11810. break;
  11811. /* -------- internal + or - -------- */
  11812. case '+':
  11813. case '-':
  11814. if (has_plus_or_minus != 0) /* already have the separator */
  11815. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11816. if (c == '+') has_plus_or_minus = 1; else has_plus_or_minus = -1;
  11817. plus = (char *)(p + 1);
  11818. continue;
  11819. /* ratio marker */
  11820. case '/':
  11821. if ((has_plus_or_minus == 0) &&
  11822. ((ex1) ||
  11823. (slash1) ||
  11824. (has_dec_point1)))
  11825. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11826. if ((has_plus_or_minus != 0) &&
  11827. ((ex2) ||
  11828. (slash2) ||
  11829. (has_dec_point2)))
  11830. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11831. if (has_plus_or_minus == 0)
  11832. slash1 = (char *)(p + 1);
  11833. else slash2 = (char *)(p + 1);
  11834. if ((!IS_DIGIT(p[1], current_radix)) ||
  11835. (!IS_DIGIT(p[-1], current_radix)))
  11836. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11837. continue;
  11838. /* -------- i for the imaginary part -------- */
  11839. case 'i':
  11840. if ((has_plus_or_minus != 0) &&
  11841. (!has_i))
  11842. {
  11843. has_i = true;
  11844. continue;
  11845. }
  11846. break;
  11847. default:
  11848. break;
  11849. }
  11850. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11851. }
  11852. }
  11853. if ((has_plus_or_minus != 0) && /* that is, we have an internal + or - */
  11854. (!has_i)) /* but no i for the imaginary part */
  11855. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11856. if (has_i)
  11857. {
  11858. #if (!WITH_GMP)
  11859. s7_double rl = 0.0, im = 0.0;
  11860. #else
  11861. char e1 = 0, e2 = 0;
  11862. #endif
  11863. s7_pointer result;
  11864. int len;
  11865. char ql1, pl1;
  11866. len = safe_strlen(q);
  11867. if (q[len - 1] != 'i')
  11868. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11869. /* save original string */
  11870. ql1 = q[len - 1];
  11871. pl1 = (*(plus - 1));
  11872. #if WITH_GMP
  11873. if (ex1) {e1 = *ex1; (*ex1) = '@';} /* for mpfr */
  11874. if (ex2) {e2 = *ex2; (*ex2) = '@';}
  11875. #endif
  11876. /* look for cases like 1+i */
  11877. if ((q[len - 2] == '+') || (q[len - 2] == '-'))
  11878. q[len - 1] = '1';
  11879. else q[len - 1] = '\0'; /* remove 'i' */
  11880. (*((char *)(plus - 1))) = '\0';
  11881. /* there is a slight inconsistency here:
  11882. 1/0 -> nan.0
  11883. 1/0+0i -> inf.0 (0/1+0i is 0.0)
  11884. #i1/0+0i -> inf.0
  11885. 0/0 -> nan.0
  11886. 0/0+0i -> -nan.0
  11887. */
  11888. #if (!WITH_GMP)
  11889. if ((has_dec_point1) ||
  11890. (ex1))
  11891. {
  11892. /* (string->number "1100.1+0.11i" 2) -- need to split into 2 honest reals before passing to non-base-10 str->dbl */
  11893. rl = string_to_double_with_radix(q, radix, &overflow);
  11894. }
  11895. else
  11896. {
  11897. if (slash1)
  11898. {
  11899. /* here the overflow could be innocuous if it's in the denominator and the numerator is 0
  11900. * 0/100000000000000000000000000000000000000-0i
  11901. */
  11902. s7_int num, den;
  11903. num = string_to_integer(q, radix, &overflow);
  11904. den = string_to_integer(slash1, radix, &overflow);
  11905. if (den == 0)
  11906. rl = NAN;
  11907. else
  11908. {
  11909. if (num == 0)
  11910. {
  11911. rl = 0.0;
  11912. overflow = false;
  11913. }
  11914. else rl = (s7_double)num / (s7_double)den;
  11915. }
  11916. }
  11917. else rl = (s7_double)string_to_integer(q, radix, &overflow);
  11918. if (overflow) return(real_NaN);
  11919. }
  11920. if (rl == -0.0) rl = 0.0;
  11921. if ((has_dec_point2) ||
  11922. (ex2))
  11923. im = string_to_double_with_radix(plus, radix, &overflow);
  11924. else
  11925. {
  11926. if (slash2)
  11927. {
  11928. /* same as above: 0-0/100000000000000000000000000000000000000i
  11929. */
  11930. s7_int num, den;
  11931. num = string_to_integer(plus, radix, &overflow);
  11932. den = string_to_integer(slash2, radix, &overflow);
  11933. if (den == 0)
  11934. im = NAN;
  11935. else
  11936. {
  11937. if (num == 0)
  11938. {
  11939. im = 0.0;
  11940. overflow = false;
  11941. }
  11942. else im = (s7_double)num / (s7_double)den;
  11943. }
  11944. }
  11945. else im = (s7_double)string_to_integer(plus, radix, &overflow);
  11946. if (overflow) return(real_NaN);
  11947. }
  11948. if ((has_plus_or_minus == -1) &&
  11949. (im != 0.0))
  11950. im = -im;
  11951. result = s7_make_complex(sc, rl, im);
  11952. #else
  11953. result = string_to_either_complex(sc, q, slash1, ex1, has_dec_point1, plus, slash2, ex2, has_dec_point2, radix, has_plus_or_minus);
  11954. #endif
  11955. /* restore original string */
  11956. q[len - 1] = ql1;
  11957. (*((char *)(plus - 1))) = pl1;
  11958. #if WITH_GMP
  11959. if (ex1) (*ex1) = e1;
  11960. if (ex2) (*ex2) = e2;
  11961. #endif
  11962. return(result);
  11963. }
  11964. /* not complex */
  11965. if ((has_dec_point1) ||
  11966. (ex1))
  11967. {
  11968. s7_pointer result;
  11969. if (slash1) /* not complex, so slash and "." is not a number */
  11970. return((want_symbol) ? make_symbol(sc, q) : sc->F);
  11971. #if (!WITH_GMP)
  11972. result = make_real(sc, string_to_double_with_radix(q, radix, &overflow));
  11973. #else
  11974. {
  11975. char old_e = 0;
  11976. if (ex1)
  11977. {
  11978. old_e = (*ex1);
  11979. (*ex1) = '@';
  11980. }
  11981. result = string_to_either_real(sc, q, radix);
  11982. if (ex1)
  11983. (*ex1) = old_e;
  11984. }
  11985. #endif
  11986. return(result);
  11987. }
  11988. /* not real */
  11989. if (slash1)
  11990. #if (!WITH_GMP)
  11991. {
  11992. s7_int n, d;
  11993. n = string_to_integer(q, radix, &overflow);
  11994. d = string_to_integer(slash1, radix, &overflow);
  11995. if ((n == 0) && (d != 0)) /* 0/100000000000000000000000000000000000000 */
  11996. return(small_int(0));
  11997. if ((d == 0) || (overflow))
  11998. return(real_NaN);
  11999. /* it would be neat to return 1 from 10000000000000000000000000000/10000000000000000000000000000
  12000. * but q is the entire number ('/' included) and slash1 is the stuff after the '/', and every
  12001. * big number comes through here, so there's no clean and safe way to check that q == slash1.
  12002. */
  12003. return(s7_make_ratio(sc, n, d));
  12004. }
  12005. #else
  12006. return(string_to_either_ratio(sc, q, slash1, radix));
  12007. #endif
  12008. /* integer */
  12009. #if (!WITH_GMP)
  12010. {
  12011. s7_int x;
  12012. x = string_to_integer(q, radix, &overflow);
  12013. if (overflow)
  12014. return((q[0] == '-') ? real_minus_infinity : real_infinity);
  12015. return(make_integer(sc, x));
  12016. }
  12017. #else
  12018. return(string_to_either_integer(sc, q, radix));
  12019. #endif
  12020. }
  12021. }
  12022. static s7_pointer s7_string_to_number(s7_scheme *sc, char *str, int radix)
  12023. {
  12024. s7_pointer x;
  12025. x = make_atom(sc, str, radix, NO_SYMBOLS, WITHOUT_OVERFLOW_ERROR);
  12026. if (s7_is_number(x)) /* only needed because str might start with '#' and not be a number (#t for example) */
  12027. return(x);
  12028. return(sc->F);
  12029. }
  12030. static s7_pointer g_string_to_number_1(s7_scheme *sc, s7_pointer args, s7_pointer caller)
  12031. {
  12032. #define H_string_to_number "(string->number str (radix 10)) converts str into a number. \
  12033. If str does not represent a number, string->number returns #f. If 'str' has an embedded radix, \
  12034. the 'radix' it is ignored: (string->number \"#x11\" 2) -> 17 not 3."
  12035. #define Q_string_to_number s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->is_number_symbol, sc->is_boolean_symbol), sc->is_string_symbol, sc->is_integer_symbol)
  12036. s7_int radix = 0;
  12037. char *str;
  12038. if (!is_string(car(args)))
  12039. method_or_bust(sc, car(args), caller, args, T_STRING, 1);
  12040. if (is_pair(cdr(args)))
  12041. {
  12042. s7_pointer rad, p;
  12043. rad = cadr(args);
  12044. if (!s7_is_integer(rad))
  12045. {
  12046. if (!s7_is_integer(p = check_values(sc, rad, cdr(args))))
  12047. method_or_bust(sc, rad, caller, args, T_INTEGER, 2);
  12048. rad = p;
  12049. }
  12050. radix = s7_integer(rad);
  12051. if ((radix < 2) || /* what about negative int as base (Knuth), reals such as phi, and some complex like -1+i */
  12052. (radix > 16)) /* the only problem here is printing the number; perhaps put each digit in "()" in base 10: (123)(0)(34) */
  12053. return(out_of_range(sc, caller, small_int(2), rad, a_valid_radix_string));
  12054. }
  12055. else radix = 10;
  12056. str = (char *)string_value(car(args));
  12057. if ((!str) || (!(*str)))
  12058. return(sc->F);
  12059. switch (str[0])
  12060. {
  12061. case 'n':
  12062. if (safe_strcmp(str, "nan.0"))
  12063. return(real_NaN);
  12064. break;
  12065. case 'i':
  12066. if (safe_strcmp(str, "inf.0"))
  12067. return(real_infinity);
  12068. break;
  12069. case '-':
  12070. if ((str[1] == 'i') && (safe_strcmp((const char *)(str + 1), "inf.0")))
  12071. return(real_minus_infinity);
  12072. break;
  12073. case '+':
  12074. if ((str[1] == 'i') && (safe_strcmp((const char *)(str + 1), "inf.0")))
  12075. return(real_infinity);
  12076. break;
  12077. }
  12078. return(s7_string_to_number(sc, str, radix));
  12079. }
  12080. static s7_pointer g_string_to_number(s7_scheme *sc, s7_pointer args)
  12081. {
  12082. return(g_string_to_number_1(sc, args, sc->string_to_number_symbol));
  12083. }
  12084. static s7_pointer c_string_to_number(s7_scheme *sc, s7_pointer n)
  12085. {
  12086. return(g_string_to_number_1(sc, set_plist_1(sc, n), sc->string_to_number_symbol));
  12087. }
  12088. PF_TO_PF(string_to_number, c_string_to_number)
  12089. static bool numbers_are_eqv(s7_pointer a, s7_pointer b)
  12090. {
  12091. if (type(a) != type(b)) /* (eqv? 1 1.0) -> #f! */
  12092. return(false);
  12093. switch (type(a))
  12094. {
  12095. case T_INTEGER:
  12096. return((integer(a) == integer(b)));
  12097. case T_RATIO:
  12098. return((numerator(a) == numerator(b)) &&
  12099. (denominator(a) == denominator(b)));
  12100. case T_REAL:
  12101. if (is_NaN(real(a)))
  12102. return(false);
  12103. return(real(a) == real(b));
  12104. case T_COMPLEX:
  12105. if ((is_NaN(real_part(a))) ||
  12106. (is_NaN(imag_part(a))))
  12107. return(false);
  12108. return((real_part(a) == real_part(b)) &&
  12109. (imag_part(a) == imag_part(b)));
  12110. default:
  12111. #if WITH_GMP
  12112. if ((is_big_number(a)) || (is_big_number(b))) /* this can happen if (member bignum ...) -> memv */
  12113. return(big_numbers_are_eqv(a, b));
  12114. #endif
  12115. break;
  12116. }
  12117. return(false);
  12118. }
  12119. static bool is_rational_via_method(s7_scheme *sc, s7_pointer p)
  12120. {
  12121. if (s7_is_rational(p))
  12122. return(true);
  12123. if (has_methods(p))
  12124. {
  12125. s7_pointer f;
  12126. f = find_method(sc, find_let(sc, p), sc->is_rational_symbol);
  12127. if (f != sc->undefined)
  12128. return(is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil))));
  12129. }
  12130. return(false);
  12131. }
  12132. /* -------------------------------- abs -------------------------------- */
  12133. #if (!WITH_GMP)
  12134. static s7_pointer g_abs(s7_scheme *sc, s7_pointer args)
  12135. {
  12136. #define H_abs "(abs x) returns the absolute value of the real number x"
  12137. #define Q_abs s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_real_symbol)
  12138. s7_pointer x;
  12139. x = car(args);
  12140. switch (type(x))
  12141. {
  12142. case T_INTEGER:
  12143. if (integer(x) < 0)
  12144. {
  12145. if (integer(x) == s7_int_min)
  12146. return(make_integer(sc, s7_int_max));
  12147. return(make_integer(sc, -integer(x)));
  12148. }
  12149. return(x);
  12150. case T_RATIO:
  12151. if (numerator(x) < 0)
  12152. {
  12153. if (numerator(x) == s7_int_min)
  12154. return(s7_make_ratio(sc, s7_int_max, denominator(x)));
  12155. return(s7_make_ratio(sc, -numerator(x), denominator(x)));
  12156. }
  12157. return(x);
  12158. case T_REAL:
  12159. if (is_NaN(real(x))) /* (abs -nan.0) -> nan.0, not -nan.0 */
  12160. return(real_NaN);
  12161. if (real(x) < 0.0)
  12162. return(make_real(sc, -real(x)));
  12163. return(x);
  12164. default:
  12165. method_or_bust(sc, x, sc->abs_symbol, args, T_REAL, 0);
  12166. }
  12167. }
  12168. static s7_int c_abs_i(s7_scheme *sc, s7_int arg) {return((arg < 0) ? (-arg) : arg);}
  12169. IF_TO_IF(abs, c_abs_i)
  12170. static s7_double c_abs_r(s7_scheme *sc, s7_double arg) {return((arg < 0.0) ? (-arg) : arg);}
  12171. DIRECT_RF_TO_RF(fabs)
  12172. /* -------------------------------- magnitude -------------------------------- */
  12173. static double my_hypot(double x, double y)
  12174. {
  12175. /* according to callgrind, this is much faster than libc's hypot */
  12176. if (x == 0.0) return(fabs(y));
  12177. if (y == 0.0) return(fabs(x));
  12178. if (x == y) return(1.414213562373095 * fabs(x));
  12179. if ((is_NaN(x)) || (is_NaN(y))) return(NAN);
  12180. return(sqrt(x * x + y * y));
  12181. }
  12182. static s7_pointer g_magnitude(s7_scheme *sc, s7_pointer args)
  12183. {
  12184. #define H_magnitude "(magnitude z) returns the magnitude of z"
  12185. #define Q_magnitude s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
  12186. s7_pointer x;
  12187. x = car(args);
  12188. switch (type(x))
  12189. {
  12190. case T_INTEGER:
  12191. if (integer(x) == s7_int_min)
  12192. return(make_integer(sc, s7_int_max));
  12193. /* (magnitude -9223372036854775808) -> -9223372036854775808
  12194. * same thing happens in abs, lcm and gcd: (gcd -9223372036854775808) -> -9223372036854775808
  12195. */
  12196. if (integer(x) < 0)
  12197. return(make_integer(sc, -integer(x)));
  12198. return(x);
  12199. case T_RATIO:
  12200. if (numerator(x) < 0)
  12201. return(s7_make_ratio(sc, -numerator(x), denominator(x)));
  12202. return(x);
  12203. case T_REAL:
  12204. if (is_NaN(real(x))) /* (magnitude -nan.0) -> nan.0, not -nan.0 */
  12205. return(real_NaN);
  12206. if (real(x) < 0.0)
  12207. return(make_real(sc, -real(x)));
  12208. return(x);
  12209. case T_COMPLEX:
  12210. return(make_real(sc, my_hypot(imag_part(x), real_part(x))));
  12211. default:
  12212. method_or_bust_with_type(sc, x, sc->magnitude_symbol, args, a_number_string, 0);
  12213. }
  12214. }
  12215. IF_TO_IF(magnitude, c_abs_i)
  12216. RF_TO_RF(magnitude, c_abs_r)
  12217. /* -------------------------------- rationalize -------------------------------- */
  12218. static s7_pointer g_rationalize(s7_scheme *sc, s7_pointer args)
  12219. {
  12220. #define H_rationalize "(rationalize x err) returns the ratio with lowest denominator within err of x"
  12221. #define Q_rationalize s7_make_signature(sc, 3, sc->is_rational_symbol, sc->is_real_symbol, sc->is_real_symbol)
  12222. s7_double err;
  12223. s7_pointer x;
  12224. x = car(args);
  12225. if (!s7_is_real(x))
  12226. method_or_bust(sc, x, sc->rationalize_symbol, args, T_REAL, 1);
  12227. if (is_not_null(cdr(args)))
  12228. {
  12229. s7_pointer ex;
  12230. ex = cadr(args);
  12231. if (!s7_is_real(ex))
  12232. method_or_bust(sc, ex, sc->rationalize_symbol, args, T_REAL, 2);
  12233. err = real_to_double(sc, ex, "rationalize");
  12234. if (is_NaN(err))
  12235. return(out_of_range(sc, sc->rationalize_symbol, small_int(2), cadr(args), its_nan_string));
  12236. if (err < 0.0) err = -err;
  12237. }
  12238. else err = sc->default_rationalize_error;
  12239. switch (type(x))
  12240. {
  12241. case T_INTEGER:
  12242. {
  12243. s7_int a, b, pa;
  12244. if (err < 1.0) return(x);
  12245. a = s7_integer(x);
  12246. if (a < 0) pa = -a; else pa = a;
  12247. if (err >= pa) return(small_int(0));
  12248. b = (s7_int)err;
  12249. pa -= b;
  12250. if (a < 0)
  12251. return(make_integer(sc, -pa));
  12252. return(make_integer(sc, pa));
  12253. }
  12254. case T_RATIO:
  12255. if (err == 0.0)
  12256. return(x);
  12257. case T_REAL:
  12258. {
  12259. s7_double rat;
  12260. s7_int numer = 0, denom = 1;
  12261. rat = real_to_double(sc, x, "rationalize");
  12262. if ((is_NaN(rat)) || (is_inf(rat)))
  12263. return(wrong_type_argument_with_type(sc, sc->rationalize_symbol, 1, x, a_normal_real_string));
  12264. if (err >= fabs(rat))
  12265. return(small_int(0));
  12266. if ((rat > 9.2233720368548e+18) || (rat < -9.2233720368548e+18))
  12267. return(out_of_range(sc, sc->rationalize_symbol, small_int(1), x, its_too_large_string));
  12268. if ((fabs(rat) + fabs(err)) < 1.0e-18)
  12269. err = 1.0e-18;
  12270. /* (/ 1.0 most-positive-fixnum) is 1.0842021e-19, so if we let err be less than that,
  12271. * (rationalize 1e-19 1e-20) hangs, but this only affects the initial ceiling, I believe.
  12272. */
  12273. if (fabs(rat) < fabs(err))
  12274. return(small_int(0));
  12275. if (c_rationalize(rat, err, &numer, &denom))
  12276. return(s7_make_ratio(sc, numer, denom));
  12277. return(sc->F);
  12278. }
  12279. }
  12280. return(sc->F); /* make compiler happy */
  12281. }
  12282. static s7_pointer c_rats(s7_scheme *sc, s7_pointer x) {return(g_rationalize(sc, set_plist_1(sc, x)));}
  12283. PF_TO_PF(rationalize, c_rats)
  12284. /* -------------------------------- angle -------------------------------- */
  12285. static s7_pointer g_angle(s7_scheme *sc, s7_pointer args)
  12286. {
  12287. #define H_angle "(angle z) returns the angle of z"
  12288. #define Q_angle s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
  12289. s7_pointer x;
  12290. /* (angle inf+infi) -> 0.78539816339745 ?
  12291. * I think this should be -pi < ang <= pi
  12292. */
  12293. x = car(args);
  12294. switch (type(x))
  12295. {
  12296. case T_INTEGER:
  12297. if (integer(x) < 0)
  12298. return(real_pi);
  12299. return(small_int(0));
  12300. case T_RATIO:
  12301. if (numerator(x) < 0)
  12302. return(real_pi);
  12303. return(small_int(0));
  12304. case T_REAL:
  12305. if (is_NaN(real(x))) return(x);
  12306. if (real(x) < 0.0)
  12307. return(real_pi);
  12308. return(real_zero);
  12309. case T_COMPLEX:
  12310. return(make_real(sc, atan2(imag_part(x), real_part(x))));
  12311. default:
  12312. method_or_bust_with_type(sc, x, sc->angle_symbol, args, a_number_string, 0);
  12313. }
  12314. }
  12315. /* -------------------------------- make-polar -------------------------------- */
  12316. #if (!WITH_PURE_S7)
  12317. static s7_pointer g_make_polar(s7_scheme *sc, s7_pointer args)
  12318. {
  12319. s7_pointer x, y;
  12320. s7_double ang, mag;
  12321. #define H_make_polar "(make-polar mag ang) returns a complex number with magnitude mag and angle ang"
  12322. #define Q_make_polar s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_real_symbol, sc->is_real_symbol)
  12323. x = car(args);
  12324. y = cadr(args);
  12325. switch (type(x))
  12326. {
  12327. case T_INTEGER:
  12328. switch (type(y))
  12329. {
  12330. case T_INTEGER:
  12331. if (integer(x) == 0) return(x); /* (make-polar 0 1) -> 0 */
  12332. if (integer(y) == 0) return(x); /* (make-polar 1 0) -> 1 */
  12333. mag = (s7_double)integer(x);
  12334. ang = (s7_double)integer(y);
  12335. break;
  12336. case T_RATIO:
  12337. if (integer(x) == 0) return(x);
  12338. mag = (s7_double)integer(x);
  12339. ang = (s7_double)fraction(y);
  12340. break;
  12341. case T_REAL:
  12342. ang = real(y);
  12343. if (ang == 0.0) return(x);
  12344. if (is_NaN(ang)) return(y);
  12345. if (is_inf(ang)) return(real_NaN);
  12346. if ((ang == M_PI) || (ang == -M_PI)) return(make_integer(sc, -integer(x)));
  12347. mag = (s7_double)integer(x);
  12348. break;
  12349. default:
  12350. method_or_bust(sc, y, sc->make_polar_symbol, args, T_REAL, 2);
  12351. }
  12352. break;
  12353. case T_RATIO:
  12354. switch (type(y))
  12355. {
  12356. case T_INTEGER:
  12357. if (integer(y) == 0) return(x);
  12358. mag = (s7_double)fraction(x);
  12359. ang = (s7_double)integer(y);
  12360. break;
  12361. case T_RATIO:
  12362. mag = (s7_double)fraction(x);
  12363. ang = (s7_double)fraction(y);
  12364. break;
  12365. case T_REAL:
  12366. ang = real(y);
  12367. if (ang == 0.0) return(x);
  12368. if (is_NaN(ang)) return(y);
  12369. if (is_inf(ang)) return(real_NaN);
  12370. if ((ang == M_PI) || (ang == -M_PI)) return(s7_make_ratio(sc, -numerator(x), denominator(x)));
  12371. mag = (s7_double)fraction(x);
  12372. break;
  12373. default:
  12374. method_or_bust(sc, y, sc->make_polar_symbol, args, T_REAL, 2);
  12375. }
  12376. break;
  12377. case T_REAL:
  12378. mag = real(x);
  12379. switch (type(y))
  12380. {
  12381. case T_INTEGER:
  12382. if (is_NaN(mag)) return(x);
  12383. if (integer(y) == 0) return(x);
  12384. ang = (s7_double)integer(y);
  12385. break;
  12386. case T_RATIO:
  12387. if (is_NaN(mag)) return(x);
  12388. ang = (s7_double)fraction(y);
  12389. break;
  12390. case T_REAL:
  12391. if (is_NaN(mag)) return(x);
  12392. ang = real(y);
  12393. if (ang == 0.0) return(x);
  12394. if (is_NaN(ang)) return(y);
  12395. if (is_inf(ang)) return(real_NaN);
  12396. break;
  12397. default:
  12398. method_or_bust(sc, y, sc->make_polar_symbol, args, T_REAL, 2);
  12399. }
  12400. break;
  12401. default:
  12402. method_or_bust(sc, x, sc->make_polar_symbol, args, T_REAL, 1);
  12403. }
  12404. return(s7_make_complex(sc, mag * cos(ang), mag * sin(ang)));
  12405. /* since sin is inaccurate for large arguments, so is make-polar:
  12406. * (make-polar 1.0 1e40) -> -0.76267273202438+0.64678458842683i, not 8.218988919070239214448025364432557517335E-1-5.696334009536363273080341815735687231337E-1i
  12407. */
  12408. }
  12409. static s7_pointer c_make_polar_2(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_make_polar(sc, set_plist_2(sc, x, y)));}
  12410. PF2_TO_PF(make_polar, c_make_polar_2)
  12411. #endif
  12412. /* -------------------------------- complex -------------------------------- */
  12413. static s7_pointer g_complex(s7_scheme *sc, s7_pointer args)
  12414. {
  12415. s7_pointer x, y;
  12416. #define H_complex "(complex x1 x2) returns a complex number with real-part x1 and imaginary-part x2"
  12417. #define Q_complex s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_real_symbol, sc->is_real_symbol)
  12418. x = car(args);
  12419. y = cadr(args);
  12420. switch (type(y))
  12421. {
  12422. case T_INTEGER:
  12423. switch (type(x))
  12424. {
  12425. case T_INTEGER:
  12426. if (integer(y) == 0) return(x);
  12427. return(s7_make_complex(sc, (s7_double)integer(x), (s7_double)integer(y)));
  12428. case T_RATIO:
  12429. if (integer(y) == 0) return(x);
  12430. return(s7_make_complex(sc, (s7_double)fraction(x), (s7_double)integer(y)));
  12431. case T_REAL:
  12432. if (integer(y) == 0) return(x);
  12433. return(s7_make_complex(sc, real(x), (s7_double)integer(y)));
  12434. default:
  12435. method_or_bust(sc, x, sc->complex_symbol, args, T_REAL, 1);
  12436. }
  12437. case T_RATIO:
  12438. switch (type(x))
  12439. {
  12440. case T_INTEGER: return(s7_make_complex(sc, (s7_double)integer(x), (s7_double)fraction(y)));
  12441. case T_RATIO: return(s7_make_complex(sc, (s7_double)fraction(x), (s7_double)fraction(y)));
  12442. case T_REAL: return(s7_make_complex(sc, real(x), (s7_double)fraction(y)));
  12443. default:
  12444. method_or_bust(sc, x, sc->complex_symbol, args, T_REAL, 1);
  12445. }
  12446. case T_REAL:
  12447. switch (type(x))
  12448. {
  12449. case T_INTEGER:
  12450. if (real(y) == 0.0) return(x);
  12451. return(s7_make_complex(sc, (s7_double)integer(x), real(y)));
  12452. case T_RATIO:
  12453. if (real(y) == 0.0) return(x);
  12454. return(s7_make_complex(sc, (s7_double)fraction(x), real(y)));
  12455. case T_REAL:
  12456. if (real(y) == 0.0) return(x);
  12457. return(s7_make_complex(sc, real(x), real(y)));
  12458. default:
  12459. method_or_bust(sc, x, sc->complex_symbol, args, T_REAL, 1);
  12460. }
  12461. default:
  12462. method_or_bust(sc, (is_let(x)) ? x : y, sc->complex_symbol, args, T_REAL, 2);
  12463. }
  12464. }
  12465. static s7_pointer c_make_complex_2(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_complex(sc, set_plist_2(sc, x, y)));}
  12466. PF2_TO_PF(make_complex, c_make_complex_2)
  12467. /* -------------------------------- exp -------------------------------- */
  12468. static s7_pointer g_exp(s7_scheme *sc, s7_pointer args)
  12469. {
  12470. #define H_exp "(exp z) returns e^z, (exp 1) is 2.718281828459"
  12471. #define Q_exp pcl_n
  12472. s7_pointer x;
  12473. x = car(args);
  12474. switch (type(x))
  12475. {
  12476. case T_INTEGER:
  12477. if (integer(x) == 0) return(small_int(1)); /* (exp 0) -> 1 */
  12478. return(make_real(sc, exp((s7_double)(integer(x)))));
  12479. case T_RATIO:
  12480. return(make_real(sc, exp((s7_double)fraction(x))));
  12481. case T_REAL:
  12482. return(make_real(sc, exp(real(x))));
  12483. case T_COMPLEX:
  12484. #if HAVE_COMPLEX_NUMBERS
  12485. return(s7_from_c_complex(sc, cexp(as_c_complex(x))));
  12486. /* this is inaccurate for large arguments:
  12487. * (exp 0+1e20i) -> -0.66491178990701-0.74692189125949i, not 7.639704044417283004001468027378811228331E-1-6.45251285265780844205811711312523007406E-1i
  12488. */
  12489. #else
  12490. return(out_of_range(sc, sc->exp_symbol, small_int(1), x, no_complex_numbers_string));
  12491. #endif
  12492. default:
  12493. method_or_bust_with_type(sc, x, sc->exp_symbol, args, a_number_string, 0);
  12494. }
  12495. }
  12496. DIRECT_RF_TO_RF(exp)
  12497. /* -------------------------------- log -------------------------------- */
  12498. #if __cplusplus
  12499. #define LOG_2 1.4426950408889634074
  12500. #else
  12501. #define LOG_2 1.4426950408889634073599246810018921L /* (/ (log 2.0)) */
  12502. #endif
  12503. static s7_pointer g_log(s7_scheme *sc, s7_pointer args)
  12504. {
  12505. #define H_log "(log z1 (z2 e)) returns log(z1) / log(z2) where z2 (the base) defaults to e: (log 8 2) = 3"
  12506. #define Q_log pcl_n
  12507. s7_pointer x;
  12508. x = car(args);
  12509. if (!s7_is_number(x))
  12510. method_or_bust_with_type(sc, x, sc->log_symbol, args, a_number_string, 1);
  12511. if (is_pair(cdr(args)))
  12512. {
  12513. s7_pointer y;
  12514. y = cadr(args);
  12515. if (!(s7_is_number(y)))
  12516. method_or_bust_with_type(sc, y, sc->log_symbol, args, a_number_string, 2);
  12517. if (y == small_int(2))
  12518. {
  12519. /* (define (2^n? x) (and (not (zero? x)) (zero? (logand x (- x 1))))) */
  12520. if (is_integer(x))
  12521. {
  12522. s7_int ix;
  12523. ix = s7_integer(x);
  12524. if (ix > 0)
  12525. {
  12526. s7_double fx;
  12527. #if (__ANDROID__) || (MS_WINDOWS) || ((__GNUC__) && ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ <= 4))))
  12528. /* just a guess -- log2 gets a warning in gcc 4.3.2, but not in 4.4.4 */
  12529. fx = log((double)ix) / log(2.0);
  12530. #else
  12531. fx = log2((double)ix);
  12532. #endif
  12533. /* (s7_int)fx rounds (log 8 2) to 2 in FreeBSD! */
  12534. #if ((__GNUC__) && ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 4))))
  12535. return(make_real(sc, fx));
  12536. #else
  12537. if ((ix & (ix - 1)) == 0)
  12538. return(make_integer(sc, (s7_int)s7_round(fx)));
  12539. return(make_real(sc, fx));
  12540. #endif
  12541. }
  12542. }
  12543. if ((s7_is_real(x)) &&
  12544. (s7_is_positive(x)))
  12545. return(make_real(sc, log(real_to_double(sc, x, "log")) * LOG_2));
  12546. return(s7_from_c_complex(sc, clog(s7_to_c_complex(x)) * LOG_2));
  12547. }
  12548. if ((x == small_int(1)) && (y == small_int(1))) /* (log 1 1) -> 0 (this is NaN in the bignum case) */
  12549. return(small_int(0));
  12550. /* (log 1 0) must be 0 since everyone says (expt 0 0) is 1 */
  12551. if (s7_is_zero(y))
  12552. {
  12553. if ((y == small_int(0)) &&
  12554. (x == small_int(1)))
  12555. return(y);
  12556. return(out_of_range(sc, sc->log_symbol, small_int(2), y, make_string_wrapper(sc, "can't be 0")));
  12557. }
  12558. if (s7_is_one(y)) /* this used to raise an error, but the bignum case is simpler if we return inf */
  12559. {
  12560. if (s7_is_one(x)) /* but (log 1.0 1.0) -> 0.0 */
  12561. return(real_zero);
  12562. return(real_infinity); /* currently (log 1/0 1) is inf? */
  12563. }
  12564. if ((s7_is_real(x)) &&
  12565. (s7_is_real(y)) &&
  12566. (s7_is_positive(x)) &&
  12567. (s7_is_positive(y)))
  12568. {
  12569. if ((s7_is_rational(x)) &&
  12570. (s7_is_rational(y)))
  12571. {
  12572. s7_double res;
  12573. s7_int ires;
  12574. res = log(rational_to_double(sc, x)) / log(rational_to_double(sc, y));
  12575. ires = (s7_int)res;
  12576. if (res - ires == 0.0)
  12577. return(make_integer(sc, ires)); /* (log 8 2) -> 3 or (log 1/8 2) -> -3 */
  12578. return(make_real(sc, res)); /* perhaps use rationalize here? (log 2 8) -> 1/3 */
  12579. }
  12580. return(make_real(sc, log(real_to_double(sc, x, "log")) / log(real_to_double(sc, y, "log"))));
  12581. }
  12582. return(s7_from_c_complex(sc, clog(s7_to_c_complex(x)) / clog(s7_to_c_complex(y))));
  12583. }
  12584. if (s7_is_real(x))
  12585. {
  12586. if (s7_is_positive(x))
  12587. return(make_real(sc, log(real_to_double(sc, x, "log"))));
  12588. return(s7_make_complex(sc, log(-real_to_double(sc, x, "log")), M_PI));
  12589. }
  12590. return(s7_from_c_complex(sc, clog(s7_to_c_complex(x))));
  12591. }
  12592. /* -------------------------------- sin -------------------------------- */
  12593. static s7_pointer g_sin(s7_scheme *sc, s7_pointer args)
  12594. {
  12595. #define H_sin "(sin z) returns sin(z)"
  12596. #define Q_sin pcl_n
  12597. s7_pointer x;
  12598. x = car(args);
  12599. switch (type(x))
  12600. {
  12601. case T_REAL:
  12602. return(make_real(sc, sin(real(x))));
  12603. case T_INTEGER:
  12604. if (integer(x) == 0) return(small_int(0)); /* (sin 0) -> 0 */
  12605. return(make_real(sc, sin((s7_double)integer(x))));
  12606. case T_RATIO:
  12607. return(make_real(sc, sin((s7_double)(fraction(x)))));
  12608. case T_COMPLEX:
  12609. #if HAVE_COMPLEX_NUMBERS
  12610. return(s7_from_c_complex(sc, csin(as_c_complex(x))));
  12611. #else
  12612. return(out_of_range(sc, sc->sin_symbol, small_int(1), x, no_complex_numbers_string));
  12613. #endif
  12614. default:
  12615. method_or_bust_with_type(sc, x, sc->sin_symbol, args, a_number_string, 0);
  12616. }
  12617. /* sin is totally inaccurate over about 1e18. There's a way to get true results,
  12618. * but it involves fancy "range reduction" techniques.
  12619. * This means that lots of things are inaccurate:
  12620. * (sin (remainder 1e22 (* 2 pi)))
  12621. * -0.57876806033477
  12622. * but it should be -8.522008497671888065747423101326159661908E-1
  12623. * ---
  12624. * (remainder 1e22 (* 2 pi)) -> 1.0057952155665e+22 !!
  12625. * it should be 5.263007914620499494429139986095833592117E0
  12626. */
  12627. }
  12628. DIRECT_RF_TO_RF(sin)
  12629. /* -------------------------------- cos -------------------------------- */
  12630. static s7_pointer g_cos(s7_scheme *sc, s7_pointer args)
  12631. {
  12632. #define H_cos "(cos z) returns cos(z)"
  12633. #define Q_cos pcl_n
  12634. s7_pointer x;
  12635. x = car(args);
  12636. switch (type(x))
  12637. {
  12638. case T_REAL:
  12639. return(make_real(sc, cos(real(x))));
  12640. case T_INTEGER:
  12641. if (integer(x) == 0) return(small_int(1)); /* (cos 0) -> 1 */
  12642. return(make_real(sc, cos((s7_double)integer(x))));
  12643. case T_RATIO:
  12644. return(make_real(sc, cos((s7_double)(fraction(x)))));
  12645. case T_COMPLEX:
  12646. #if HAVE_COMPLEX_NUMBERS
  12647. return(s7_from_c_complex(sc, ccos(as_c_complex(x))));
  12648. #else
  12649. return(out_of_range(sc, sc->cos_symbol, small_int(1), x, no_complex_numbers_string));
  12650. #endif
  12651. default:
  12652. method_or_bust_with_type(sc, x, sc->cos_symbol, args, a_number_string, 0);
  12653. }
  12654. }
  12655. DIRECT_RF_TO_RF(cos)
  12656. /* -------------------------------- tan -------------------------------- */
  12657. static s7_pointer g_tan(s7_scheme *sc, s7_pointer args)
  12658. {
  12659. #define H_tan "(tan z) returns tan(z)"
  12660. #define Q_tan pcl_n
  12661. s7_pointer x;
  12662. x = car(args);
  12663. switch (type(x))
  12664. {
  12665. case T_REAL:
  12666. return(make_real(sc, tan(real(x))));
  12667. case T_INTEGER:
  12668. if (integer(x) == 0) return(small_int(0)); /* (tan 0) -> 0 */
  12669. return(make_real(sc, tan((s7_double)(integer(x)))));
  12670. case T_RATIO:
  12671. return(make_real(sc, tan((s7_double)(fraction(x)))));
  12672. case T_COMPLEX:
  12673. #if HAVE_COMPLEX_NUMBERS
  12674. if (imag_part(x) > 350.0)
  12675. return(s7_make_complex(sc, 0.0, 1.0));
  12676. if (imag_part(x) < -350.0)
  12677. return(s7_make_complex(sc, 0.0, -1.0));
  12678. return(s7_from_c_complex(sc, ctan(as_c_complex(x))));
  12679. #else
  12680. return(out_of_range(sc, sc->tan_symbol, small_int(1), x, no_complex_numbers_string));
  12681. #endif
  12682. default:
  12683. method_or_bust_with_type(sc, x, sc->tan_symbol, args, a_number_string, 0);
  12684. }
  12685. }
  12686. DIRECT_RF_TO_RF(tan)
  12687. /* -------------------------------- asin -------------------------------- */
  12688. static s7_pointer c_asin(s7_scheme *sc, s7_double x)
  12689. {
  12690. s7_double absx, recip;
  12691. s7_complex result;
  12692. absx = fabs(x);
  12693. if (absx <= 1.0)
  12694. return(make_real(sc, asin(x)));
  12695. /* otherwise use maxima code: */
  12696. recip = 1.0 / absx;
  12697. result = (M_PI / 2.0) - (_Complex_I * clog(absx * (1.0 + (sqrt(1.0 + recip) * csqrt(1.0 - recip)))));
  12698. if (x < 0.0)
  12699. return(s7_from_c_complex(sc, -result));
  12700. return(s7_from_c_complex(sc, result));
  12701. }
  12702. static s7_pointer g_asin_1(s7_scheme *sc, s7_pointer n)
  12703. {
  12704. switch (type(n))
  12705. {
  12706. case T_INTEGER:
  12707. if (integer(n) == 0) return(small_int(0)); /* (asin 0) -> 0 */
  12708. /* in netBSD, (asin 2) returns 0.25383842987008+0.25383842987008i according to Peter Bex */
  12709. return(c_asin(sc, (s7_double)integer(n)));
  12710. case T_RATIO:
  12711. return(c_asin(sc, (s7_double)numerator(n) / (s7_double)denominator(n)));
  12712. case T_REAL:
  12713. return(c_asin(sc, real(n)));
  12714. case T_COMPLEX:
  12715. #if HAVE_COMPLEX_NUMBERS
  12716. /* if either real or imag part is very large, use explicit formula, not casin */
  12717. /* this code taken from sbcl's src/code/irrat.lisp */
  12718. /* break is around x+70000000i */
  12719. if ((fabs(real_part(n)) > 1.0e7) ||
  12720. (fabs(imag_part(n)) > 1.0e7))
  12721. {
  12722. s7_complex sq1mz, sq1pz, z;
  12723. z = as_c_complex(n);
  12724. sq1mz = csqrt(1.0 - z);
  12725. sq1pz = csqrt(1.0 + z);
  12726. return(s7_make_complex(sc, atan(real_part(n) / creal(sq1mz * sq1pz)), asinh(cimag(sq1pz * conj(sq1mz)))));
  12727. }
  12728. return(s7_from_c_complex(sc, casin(as_c_complex(n))));
  12729. #else
  12730. return(out_of_range(sc, sc->asin_symbol, small_int(1), n, no_complex_numbers_string));
  12731. #endif
  12732. default:
  12733. method_or_bust_with_type(sc, n, sc->asin_symbol, list_1(sc, n), a_number_string, 0);
  12734. }
  12735. }
  12736. static s7_pointer g_asin(s7_scheme *sc, s7_pointer args)
  12737. {
  12738. #define H_asin "(asin z) returns asin(z); (sin (asin x)) = x"
  12739. #define Q_asin pcl_n
  12740. return(g_asin_1(sc, car(args)));
  12741. }
  12742. R_P_F_TO_PF(asin, c_asin, g_asin_1, g_asin_1)
  12743. /* g_asin_1 is safe for the gf case because it won't trigger the GC before it is done with its argument */
  12744. /* -------------------------------- acos -------------------------------- */
  12745. static s7_pointer c_acos(s7_scheme *sc, s7_double x)
  12746. {
  12747. s7_double absx, recip;
  12748. s7_complex result;
  12749. absx = fabs(x);
  12750. if (absx <= 1.0)
  12751. return(make_real(sc, acos(x)));
  12752. /* else follow maxima again: */
  12753. recip = 1.0 / absx;
  12754. if (x > 0.0)
  12755. result = _Complex_I * clog(absx * (1.0 + (sqrt(1.0 + recip) * csqrt(1.0 - recip))));
  12756. else result = M_PI - _Complex_I * clog(absx * (1.0 + (sqrt(1.0 + recip) * csqrt(1.0 - recip))));
  12757. return(s7_from_c_complex(sc, result));
  12758. }
  12759. static s7_pointer g_acos_1(s7_scheme *sc, s7_pointer n)
  12760. {
  12761. switch (type(n))
  12762. {
  12763. case T_INTEGER:
  12764. if (integer(n) == 1) return(small_int(0));
  12765. return(c_acos(sc, (s7_double)integer(n)));
  12766. case T_RATIO:
  12767. return(c_acos(sc, (s7_double)numerator(n) / (s7_double)denominator(n)));
  12768. case T_REAL:
  12769. return(c_acos(sc, real(n)));
  12770. case T_COMPLEX:
  12771. #if HAVE_COMPLEX_NUMBERS
  12772. /* if either real or imag part is very large, use explicit formula, not cacos */
  12773. /* this code taken from sbcl's src/code/irrat.lisp */
  12774. if ((fabs(real_part(n)) > 1.0e7) ||
  12775. (fabs(imag_part(n)) > 1.0e7))
  12776. {
  12777. s7_complex sq1mz, sq1pz, z;
  12778. z = as_c_complex(n);
  12779. sq1mz = csqrt(1.0 - z);
  12780. sq1pz = csqrt(1.0 + z);
  12781. return(s7_make_complex(sc, 2.0 * atan(creal(sq1mz) / creal(sq1pz)), asinh(cimag(sq1mz * conj(sq1pz)))));
  12782. }
  12783. return(s7_from_c_complex(sc, cacos(s7_to_c_complex(n))));
  12784. #else
  12785. return(out_of_range(sc, sc->acos_symbol, small_int(1), n, no_complex_numbers_string));
  12786. #endif
  12787. default:
  12788. method_or_bust_with_type(sc, n, sc->acos_symbol, list_1(sc, n), a_number_string, 0);
  12789. }
  12790. }
  12791. static s7_pointer g_acos(s7_scheme *sc, s7_pointer args)
  12792. {
  12793. #define H_acos "(acos z) returns acos(z); (cos (acos 1)) = 1"
  12794. #define Q_acos pcl_n
  12795. return(g_acos_1(sc, car(args)));
  12796. }
  12797. R_P_F_TO_PF(acos, c_acos, g_acos_1, g_acos_1)
  12798. /* -------------------------------- atan -------------------------------- */
  12799. static s7_double c_atan(s7_scheme *sc, s7_double x, s7_double y)
  12800. {
  12801. return(atan2(x, y));
  12802. }
  12803. static s7_pointer g_atan(s7_scheme *sc, s7_pointer args)
  12804. {
  12805. #define H_atan "(atan z) returns atan(z), (atan y x) returns atan(y/x)"
  12806. #define Q_atan s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_number_symbol, sc->is_real_symbol)
  12807. /* actually if there are two args, both should be real, but how to express that in the signature? */
  12808. s7_pointer x, y;
  12809. s7_double x1, x2;
  12810. /* currently (atan inf.0 inf.0) -> 0.78539816339745, and (atan inf.0 -inf.0) -> 2.3561944901923 (etc) */
  12811. x = car(args);
  12812. if (!is_pair(cdr(args)))
  12813. {
  12814. switch (type(x))
  12815. {
  12816. case T_INTEGER:
  12817. if (integer(x) == 0) return(small_int(0)); /* (atan 0) -> 0 */
  12818. case T_RATIO:
  12819. case T_REAL:
  12820. return(make_real(sc, atan(real_to_double(sc, x, "atan"))));
  12821. case T_COMPLEX:
  12822. #if HAVE_COMPLEX_NUMBERS
  12823. return(s7_from_c_complex(sc, catan(as_c_complex(x))));
  12824. #else
  12825. return(out_of_range(sc, sc->atan_symbol, small_int(1), x, no_complex_numbers_string));
  12826. #endif
  12827. default:
  12828. method_or_bust_with_type(sc, x, sc->atan_symbol, args, a_number_string, 0);
  12829. }
  12830. }
  12831. if (!s7_is_real(x))
  12832. method_or_bust(sc, x, sc->atan_symbol, args, T_REAL, 1);
  12833. y = cadr(args);
  12834. if (!s7_is_real(y))
  12835. method_or_bust(sc, y, sc->atan_symbol, args, T_REAL, 2);
  12836. x1 = real_to_double(sc, x, "atan");
  12837. x2 = real_to_double(sc, y, "atan");
  12838. return(make_real(sc, atan2(x1, x2)));
  12839. }
  12840. RF2_TO_RF(atan, c_atan)
  12841. /* -------------------------------- sinh -------------------------------- */
  12842. static s7_pointer g_sinh(s7_scheme *sc, s7_pointer args)
  12843. {
  12844. #define H_sinh "(sinh z) returns sinh(z)"
  12845. #define Q_sinh pcl_n
  12846. s7_pointer x;
  12847. x = car(args);
  12848. switch (type(x))
  12849. {
  12850. case T_INTEGER:
  12851. if (integer(x) == 0) return(small_int(0)); /* (sinh 0) -> 0 */
  12852. case T_REAL:
  12853. case T_RATIO:
  12854. return(make_real(sc, sinh(real_to_double(sc, x, "sinh"))));
  12855. case T_COMPLEX:
  12856. #if HAVE_COMPLEX_NUMBERS
  12857. return(s7_from_c_complex(sc, csinh(as_c_complex(x))));
  12858. #else
  12859. return(out_of_range(sc, sc->sinh_symbol, small_int(1), x, no_complex_numbers_string));
  12860. #endif
  12861. default:
  12862. method_or_bust_with_type(sc, x, sc->sinh_symbol, args, a_number_string, 0);
  12863. }
  12864. }
  12865. DIRECT_RF_TO_RF(sinh)
  12866. /* -------------------------------- cosh -------------------------------- */
  12867. static s7_pointer g_cosh(s7_scheme *sc, s7_pointer args)
  12868. {
  12869. #define H_cosh "(cosh z) returns cosh(z)"
  12870. #define Q_cosh pcl_n
  12871. s7_pointer x;
  12872. x = car(args);
  12873. switch (type(x))
  12874. {
  12875. case T_INTEGER:
  12876. if (integer(x) == 0) return(small_int(1)); /* (cosh 0) -> 1 */
  12877. case T_REAL:
  12878. case T_RATIO:
  12879. /* this is not completely correct when optimization kicks in.
  12880. * :(define (hi) (do ((i 0 (+ i 1))) ((= i 1)) (display (cosh i))))
  12881. * hi
  12882. * :(hi)
  12883. * 1.0()
  12884. * :(cosh 0)
  12885. * 1
  12886. */
  12887. return(make_real(sc, cosh(real_to_double(sc, x, "cosh"))));
  12888. case T_COMPLEX:
  12889. #if HAVE_COMPLEX_NUMBERS
  12890. return(s7_from_c_complex(sc, ccosh(as_c_complex(x))));
  12891. #else
  12892. return(out_of_range(sc, sc->cosh_symbol, small_int(1), x, no_complex_numbers_string));
  12893. #endif
  12894. default:
  12895. method_or_bust_with_type(sc, x, sc->cosh_symbol, args, a_number_string, 0);
  12896. }
  12897. }
  12898. DIRECT_RF_TO_RF(cosh)
  12899. /* -------------------------------- tanh -------------------------------- */
  12900. static s7_pointer g_tanh(s7_scheme *sc, s7_pointer args)
  12901. {
  12902. #define H_tanh "(tanh z) returns tanh(z)"
  12903. #define Q_tanh pcl_n
  12904. s7_pointer x;
  12905. x = car(args);
  12906. switch (type(x))
  12907. {
  12908. case T_INTEGER:
  12909. if (integer(x) == 0) return(small_int(0)); /* (tanh 0) -> 0 */
  12910. case T_REAL:
  12911. case T_RATIO:
  12912. return(make_real(sc, tanh(real_to_double(sc, x, "tanh"))));
  12913. case T_COMPLEX:
  12914. #if HAVE_COMPLEX_NUMBERS
  12915. if (real_part(x) > 350.0)
  12916. return(real_one); /* closer than 0.0 which is what ctanh is about to return! */
  12917. if (real_part(x) < -350.0)
  12918. return(make_real(sc, -1.0)); /* closer than ctanh's -0.0 */
  12919. return(s7_from_c_complex(sc, ctanh(as_c_complex(x))));
  12920. #else
  12921. return(out_of_range(sc, sc->tanh_symbol, small_int(1), x, no_complex_numbers_string));
  12922. #endif
  12923. default:
  12924. method_or_bust_with_type(sc, x, sc->tanh_symbol, args, a_number_string, 0);
  12925. }
  12926. }
  12927. DIRECT_RF_TO_RF(tanh)
  12928. /* -------------------------------- asinh -------------------------------- */
  12929. static s7_pointer c_asinh_1(s7_scheme *sc, s7_pointer x)
  12930. {
  12931. switch (type(x))
  12932. {
  12933. case T_INTEGER:
  12934. if (integer(x) == 0) return(small_int(0));
  12935. return(make_real(sc, asinh((s7_double)integer(x))));
  12936. case T_RATIO:
  12937. return(make_real(sc, asinh((s7_double)numerator(x) / (s7_double)denominator(x))));
  12938. case T_REAL:
  12939. return(make_real(sc, asinh(real(x))));
  12940. case T_COMPLEX:
  12941. #if HAVE_COMPLEX_NUMBERS
  12942. #if (defined(__OpenBSD__)) || (defined(__NetBSD__))
  12943. return(s7_from_c_complex(sc, casinh_1(as_c_complex(x))));
  12944. #else
  12945. return(s7_from_c_complex(sc, casinh(as_c_complex(x))));
  12946. #endif
  12947. #else
  12948. return(out_of_range(sc, sc->asinh_symbol, small_int(1), x, no_complex_numbers_string));
  12949. #endif
  12950. default:
  12951. method_or_bust_with_type(sc, x, sc->asinh_symbol, list_1(sc, x), a_number_string, 0);
  12952. }
  12953. }
  12954. static s7_pointer g_asinh(s7_scheme *sc, s7_pointer args)
  12955. {
  12956. #define H_asinh "(asinh z) returns asinh(z)"
  12957. #define Q_asinh pcl_n
  12958. return(c_asinh_1(sc, car(args)));
  12959. }
  12960. static s7_pointer c_asinh(s7_scheme *sc, s7_double x)
  12961. {
  12962. return(make_real(sc, asinh(x)));
  12963. }
  12964. R_P_F_TO_PF(asinh, c_asinh, c_asinh_1, c_asinh_1)
  12965. /* -------------------------------- acosh -------------------------------- */
  12966. static s7_pointer c_acosh_1(s7_scheme *sc, s7_pointer x)
  12967. {
  12968. switch (type(x))
  12969. {
  12970. case T_INTEGER:
  12971. if (integer(x) == 1) return(small_int(0));
  12972. case T_REAL:
  12973. case T_RATIO:
  12974. {
  12975. double x1;
  12976. x1 = real_to_double(sc, x, "acosh");
  12977. if (x1 >= 1.0)
  12978. return(make_real(sc, acosh(x1)));
  12979. }
  12980. case T_COMPLEX:
  12981. #if HAVE_COMPLEX_NUMBERS
  12982. #ifdef __OpenBSD__
  12983. return(s7_from_c_complex(sc, cacosh_1(s7_to_c_complex(x))));
  12984. #else
  12985. return(s7_from_c_complex(sc, cacosh(s7_to_c_complex(x)))); /* not as_c_complex because x might not be complex */
  12986. #endif
  12987. #else
  12988. /* since we can fall through to this branch, we need a better error message than "must be a number, not 0.0" */
  12989. return(out_of_range(sc, sc->acosh_symbol, small_int(1), x, no_complex_numbers_string));
  12990. #endif
  12991. default:
  12992. method_or_bust_with_type(sc, x, sc->acosh_symbol, list_1(sc, x), a_number_string, 0);
  12993. }
  12994. }
  12995. static s7_pointer g_acosh(s7_scheme *sc, s7_pointer args)
  12996. {
  12997. #define H_acosh "(acosh z) returns acosh(z)"
  12998. #define Q_acosh pcl_n
  12999. return(c_acosh_1(sc, car(args)));
  13000. }
  13001. static s7_pointer c_acosh(s7_scheme *sc, s7_double x)
  13002. {
  13003. if (x >= 1.0)
  13004. return(make_real(sc, acosh(x)));
  13005. return(c_acosh_1(sc, set_plist_1(sc, make_real(sc, x))));
  13006. }
  13007. R_P_F_TO_PF(acosh, c_acosh, c_acosh_1, c_acosh_1)
  13008. /* -------------------------------- atanh -------------------------------- */
  13009. static s7_pointer c_atanh_1(s7_scheme *sc, s7_pointer x)
  13010. {
  13011. switch (type(x))
  13012. {
  13013. case T_INTEGER:
  13014. if (integer(x) == 0) return(small_int(0)); /* (atanh 0) -> 0 */
  13015. case T_REAL:
  13016. case T_RATIO:
  13017. {
  13018. double x1;
  13019. x1 = real_to_double(sc, x, "atanh");
  13020. if (fabs(x1) < 1.0)
  13021. return(make_real(sc, atanh(x1)));
  13022. }
  13023. /* if we can't distinguish x from 1.0 even with long doubles, we'll get inf.0:
  13024. * (atanh 9223372036854775/9223372036854776) -> 18.714973875119
  13025. * (atanh 92233720368547758/92233720368547757) -> inf.0
  13026. */
  13027. case T_COMPLEX:
  13028. #if HAVE_COMPLEX_NUMBERS
  13029. #if (defined(__OpenBSD__)) || (defined(__NetBSD__))
  13030. return(s7_from_c_complex(sc, catanh_1(s7_to_c_complex(x))));
  13031. #else
  13032. return(s7_from_c_complex(sc, catanh(s7_to_c_complex(x))));
  13033. #endif
  13034. #else
  13035. return(out_of_range(sc, sc->atanh_symbol, small_int(1), x, no_complex_numbers_string));
  13036. #endif
  13037. default:
  13038. method_or_bust_with_type(sc, x, sc->atanh_symbol, list_1(sc, x), a_number_string, 0);
  13039. }
  13040. }
  13041. static s7_pointer g_atanh(s7_scheme *sc, s7_pointer args)
  13042. {
  13043. #define H_atanh "(atanh z) returns atanh(z)"
  13044. #define Q_atanh pcl_n
  13045. return(c_atanh_1(sc, car(args)));
  13046. }
  13047. static s7_pointer c_atanh(s7_scheme *sc, s7_double x)
  13048. {
  13049. if (fabs(x) < 1.0)
  13050. return(make_real(sc, atanh(x)));
  13051. return(c_atanh_1(sc, set_plist_1(sc, make_real(sc, x))));
  13052. }
  13053. R_P_F_TO_PF(atanh, c_atanh, c_atanh_1, c_atanh_1)
  13054. /* -------------------------------- sqrt -------------------------------- */
  13055. static s7_pointer g_sqrt(s7_scheme *sc, s7_pointer args)
  13056. {
  13057. #define H_sqrt "(sqrt z) returns the square root of z"
  13058. #define Q_sqrt pcl_n
  13059. s7_pointer n;
  13060. s7_double sqx;
  13061. n = car(args);
  13062. switch (type(n))
  13063. {
  13064. case T_INTEGER:
  13065. if (integer(n) >= 0)
  13066. {
  13067. s7_int ix;
  13068. sqx = sqrt((s7_double)integer(n));
  13069. ix = (s7_int)sqx;
  13070. if ((ix * ix) == integer(n))
  13071. return(make_integer(sc, ix));
  13072. return(make_real(sc, sqx));
  13073. /* Mark Weaver notes that
  13074. * (zero? (- (sqrt 9007199136250226) 94906265.0)) -> #t
  13075. * but (* 94906265 94906265) -> 9007199136250225 -- oops
  13076. * at least we return a real here, not an incorrect integer and
  13077. * (sqrt 9007199136250225) -> 94906265
  13078. */
  13079. }
  13080. sqx = (s7_double)integer(n); /* we're trying to protect against (sqrt -9223372036854775808) where we can't negate the integer argument */
  13081. return(s7_make_complex(sc, 0.0, sqrt((s7_double)(-sqx))));
  13082. case T_RATIO:
  13083. sqx = (s7_double)fraction(n);
  13084. if (sqx > 0.0) /* else it's complex, so it can't be a ratio */
  13085. {
  13086. s7_int nm = 0, dn = 1;
  13087. if (c_rationalize(sqx, 1.0e-16, &nm, &dn)) /* 1e-16 so that (sqrt 1/1099511627776) returns 1/1048576 */
  13088. {
  13089. #if HAVE_OVERFLOW_CHECKS
  13090. s7_int nm2, dn2;
  13091. if ((multiply_overflow(nm, nm, &nm2)) ||
  13092. (multiply_overflow(dn, dn, &dn2)))
  13093. return(make_real(sc, sqrt(sqx)));
  13094. if ((nm2 == numerator(n)) &&
  13095. (dn2 == denominator(n)))
  13096. return(s7_make_ratio(sc, nm, dn));
  13097. #else
  13098. if ((nm * nm == numerator(n)) &&
  13099. (dn * dn == denominator(n)))
  13100. return(s7_make_ratio(sc, nm, dn));
  13101. #endif
  13102. }
  13103. return(make_real(sc, sqrt(sqx)));
  13104. }
  13105. return(s7_make_complex(sc, 0.0, sqrt(-sqx)));
  13106. case T_REAL:
  13107. if (is_NaN(real(n)))
  13108. return(real_NaN);
  13109. if (real(n) >= 0.0)
  13110. return(make_real(sc, sqrt(real(n))));
  13111. return(s7_make_complex(sc, 0.0, sqrt(-real(n))));
  13112. case T_COMPLEX:
  13113. /* (* inf.0 (sqrt -1)) -> -nan+infi, but (sqrt -inf.0) -> 0+infi */
  13114. #if HAVE_COMPLEX_NUMBERS
  13115. return(s7_from_c_complex(sc, csqrt(as_c_complex(n))));
  13116. #else
  13117. return(out_of_range(sc, sc->sqrt_symbol, small_int(1), n, no_complex_numbers_string));
  13118. #endif
  13119. default:
  13120. method_or_bust_with_type(sc, n, sc->sqrt_symbol, args, a_number_string, 0);
  13121. }
  13122. }
  13123. /* -------------------------------- expt -------------------------------- */
  13124. static s7_int int_to_int(s7_int x, s7_int n)
  13125. {
  13126. /* from GSL */
  13127. s7_int value = 1;
  13128. do {
  13129. if (n & 1) value *= x;
  13130. n >>= 1;
  13131. #if HAVE_OVERFLOW_CHECKS
  13132. if (multiply_overflow(x, x, &x))
  13133. break;
  13134. #else
  13135. x *= x;
  13136. #endif
  13137. } while (n);
  13138. return(value);
  13139. }
  13140. static const long long int nth_roots[63] = {
  13141. S7_LLONG_MAX, S7_LLONG_MAX, 3037000499LL, 2097151, 55108, 6208, 1448, 511, 234, 127, 78, 52, 38, 28, 22,
  13142. 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,
  13143. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
  13144. static const long int_nth_roots[31] = {
  13145. S7_LONG_MAX, S7_LONG_MAX, 46340, 1290, 215, 73, 35, 21, 14, 10, 8, 7, 5, 5, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
  13146. static bool int_pow_ok(s7_int x, s7_int y)
  13147. {
  13148. if (s7_int_bits > 31)
  13149. return((y < 63) &&
  13150. (nth_roots[y] >= s7_int_abs(x)));
  13151. return((y < 31) &&
  13152. (int_nth_roots[y] >= s7_int_abs(x)));
  13153. }
  13154. static s7_pointer g_expt(s7_scheme *sc, s7_pointer args)
  13155. {
  13156. #define H_expt "(expt z1 z2) returns z1^z2"
  13157. #define Q_expt pcl_n
  13158. s7_pointer n, pw;
  13159. n = car(args);
  13160. if (!s7_is_number(n))
  13161. method_or_bust_with_type(sc, n, sc->expt_symbol, args, a_number_string, 1);
  13162. pw = cadr(args);
  13163. if (!s7_is_number(pw))
  13164. method_or_bust_with_type(sc, pw, sc->expt_symbol, args, a_number_string, 2);
  13165. /* this provides more than 2 args to expt:
  13166. * if (is_not_null(cddr(args)))
  13167. * return(g_expt(sc, list_2(sc, car(args), g_expt(sc, cdr(args)))));
  13168. *
  13169. * but it's unusual in scheme to process args in reverse order, and the
  13170. * syntax by itself is ambiguous (does (expt 2 2 3) = 256 or 64?)
  13171. */
  13172. if (s7_is_zero(n))
  13173. {
  13174. if (s7_is_zero(pw))
  13175. {
  13176. if ((s7_is_integer(n)) && (s7_is_integer(pw))) /* (expt 0 0) -> 1 */
  13177. return(small_int(1));
  13178. return(real_zero); /* (expt 0.0 0) -> 0.0 */
  13179. }
  13180. if (s7_is_real(pw))
  13181. {
  13182. if (s7_is_negative(pw)) /* (expt 0 -1) */
  13183. return(division_by_zero_error(sc, sc->expt_symbol, args));
  13184. /* (Clisp gives divide-by-zero error here, Guile returns inf.0) */
  13185. if ((!s7_is_rational(pw)) && /* (expt 0 most-positive-fixnum) */
  13186. (is_NaN(s7_real(pw)))) /* (expt 0 +nan.0) */
  13187. return(pw);
  13188. }
  13189. else
  13190. { /* (expt 0 a+bi) */
  13191. if (real_part(pw) < 0.0) /* (expt 0 -1+i) */
  13192. return(division_by_zero_error(sc, sc->expt_symbol, args));
  13193. if ((is_NaN(real_part(pw))) || /* (expt 0 0+1/0i) */
  13194. (is_NaN(imag_part(pw))))
  13195. return(real_NaN);
  13196. }
  13197. if ((s7_is_integer(n)) && (s7_is_integer(pw))) /* pw != 0, (expt 0 2312) */
  13198. return(small_int(0));
  13199. return(real_zero); /* (expt 0.0 123123) */
  13200. }
  13201. if (s7_is_one(pw))
  13202. {
  13203. if (s7_is_integer(pw))
  13204. return(n);
  13205. if (is_rational(n))
  13206. return(make_real(sc, rational_to_double(sc, n)));
  13207. return(n);
  13208. }
  13209. if (is_t_integer(pw))
  13210. {
  13211. s7_int y;
  13212. y = integer(pw);
  13213. if (y == 0)
  13214. {
  13215. if (is_rational(n)) /* (expt 3 0) */
  13216. return(small_int(1));
  13217. if ((is_NaN(s7_real_part(n))) || /* (expt 1/0 0) -> NaN */
  13218. (is_NaN(s7_imag_part(n)))) /* (expt (complex 0 1/0) 0) -> NaN */
  13219. return(n);
  13220. return(real_one); /* (expt 3.0 0) */
  13221. }
  13222. switch (type(n))
  13223. {
  13224. case T_INTEGER:
  13225. {
  13226. s7_int x;
  13227. x = s7_integer(n);
  13228. if (x == 1) /* (expt 1 y) */
  13229. return(n);
  13230. if (x == -1)
  13231. {
  13232. if (y == s7_int_min) /* (expt -1 most-negative-fixnum) */
  13233. return(small_int(1));
  13234. if (s7_int_abs(y) & 1) /* (expt -1 odd-int) */
  13235. return(n);
  13236. return(small_int(1)); /* (expt -1 even-int) */
  13237. }
  13238. if (y == s7_int_min) /* (expt x most-negative-fixnum) */
  13239. return(small_int(0));
  13240. if (x == s7_int_min) /* (expt most-negative-fixnum y) */
  13241. return(make_real(sc, pow((double)x, (double)y)));
  13242. if (int_pow_ok(x, s7_int_abs(y)))
  13243. {
  13244. if (y > 0)
  13245. return(make_integer(sc, int_to_int(x, y)));
  13246. return(s7_make_ratio(sc, 1, int_to_int(x, -y)));
  13247. }
  13248. }
  13249. break;
  13250. case T_RATIO:
  13251. {
  13252. s7_int nm, dn;
  13253. nm = numerator(n);
  13254. dn = denominator(n);
  13255. if (y == s7_int_min)
  13256. {
  13257. if (s7_int_abs(nm) > dn)
  13258. return(small_int(0)); /* (expt 4/3 most-negative-fixnum) -> 0? */
  13259. return(real_infinity); /* (expt 3/4 most-negative-fixnum) -> inf? */
  13260. }
  13261. if ((int_pow_ok(nm, s7_int_abs(y))) &&
  13262. (int_pow_ok(dn, s7_int_abs(y))))
  13263. {
  13264. if (y > 0)
  13265. return(s7_make_ratio(sc, int_to_int(nm, y), int_to_int(dn, y)));
  13266. return(s7_make_ratio(sc, int_to_int(dn, -y), int_to_int(nm, -y)));
  13267. }
  13268. }
  13269. break;
  13270. /* occasionally int^rat can be int but it happens so infrequently it's probably not worth checking
  13271. * one possibly easy case: (expt 1 1/2) -> 1 (-1?) etc
  13272. */
  13273. case T_REAL:
  13274. /* (expt -1.0 most-positive-fixnum) should be -1.0
  13275. * (expt -1.0 (+ (expt 2 53) 1)) -> -1.0
  13276. * (expt -1.0 (- 1 (expt 2 54))) -> -1.0
  13277. */
  13278. if (real(n) == -1.0)
  13279. {
  13280. if (y == s7_int_min)
  13281. return(real_one);
  13282. if (s7_int_abs(y) & 1)
  13283. return(n);
  13284. return(real_one);
  13285. }
  13286. break;
  13287. case T_COMPLEX:
  13288. #if HAVE_COMPLEX_NUMBERS
  13289. if ((s7_real_part(n) == 0.0) &&
  13290. ((s7_imag_part(n) == 1.0) ||
  13291. (s7_imag_part(n) == -1.0)))
  13292. {
  13293. bool yp, np;
  13294. yp = (y > 0);
  13295. np = (s7_imag_part(n) > 0.0);
  13296. switch (s7_int_abs(y) % 4)
  13297. {
  13298. case 0: return(real_one);
  13299. case 1: return(s7_make_complex(sc, 0.0, (yp == np) ? 1.0 : -1.0));
  13300. case 2: return(make_real(sc, -1.0));
  13301. case 3: return(s7_make_complex(sc, 0.0, (yp == np) ? -1.0 : 1.0));
  13302. }
  13303. }
  13304. #else
  13305. return(out_of_range(sc, sc->expt_symbol, small_int(2), n, no_complex_numbers_string));
  13306. #endif
  13307. break;
  13308. }
  13309. }
  13310. if ((s7_is_real(n)) &&
  13311. (s7_is_real(pw)))
  13312. {
  13313. s7_double x, y;
  13314. if ((is_t_ratio(pw)) &&
  13315. (numerator(pw) == 1))
  13316. {
  13317. if (denominator(pw) == 2)
  13318. return(g_sqrt(sc, args));
  13319. if (denominator(pw) == 3)
  13320. return(make_real(sc, cbrt(real_to_double(sc, n, "expt")))); /* (expt 27 1/3) should be 3, not 3.0... */
  13321. /* but: (expt 512/729 1/3) -> 0.88888888888889
  13322. */
  13323. /* and 4 -> sqrt(sqrt...) etc? */
  13324. }
  13325. x = real_to_double(sc, n, "expt");
  13326. y = real_to_double(sc, pw, "expt");
  13327. if (is_NaN(x)) return(n);
  13328. if (is_NaN(y)) return(pw);
  13329. if (y == 0.0) return(real_one);
  13330. if (x > 0.0)
  13331. return(make_real(sc, pow(x, y)));
  13332. /* tricky cases abound here: (expt -1 1/9223372036854775807)
  13333. */
  13334. }
  13335. /* (expt 0+i 1e+16) = 0.98156860153485-0.19111012657867i ?
  13336. * (expt 0+i 1+1/0i) = 0.0 ??
  13337. */
  13338. return(s7_from_c_complex(sc, cpow(s7_to_c_complex(n), s7_to_c_complex(pw))));
  13339. }
  13340. #if (!WITH_GMP)
  13341. static s7_pointer c_expt_i(s7_scheme *sc, s7_int x, s7_int y)
  13342. {
  13343. if (y == 0) return(small_int(1));
  13344. if (y == 1) return(make_integer(sc, x));
  13345. return(g_expt(sc, set_plist_2(sc, make_integer(sc, x), make_integer(sc, y))));
  13346. }
  13347. static s7_pointer c_expt_r(s7_scheme *sc, s7_double x, s7_double y)
  13348. {
  13349. if (y > 0.0)
  13350. return(make_real(sc, pow(x, y)));
  13351. return(g_expt(sc, set_plist_2(sc, make_real(sc, x), make_real(sc, y))));
  13352. }
  13353. static s7_pointer c_expt_2(s7_scheme *sc, s7_pointer x, s7_pointer y)
  13354. {
  13355. return(g_expt(sc, set_plist_2(sc, x, y)));
  13356. }
  13357. XF2_TO_PF(expt, c_expt_i, c_expt_r, c_expt_2)
  13358. #endif
  13359. /* -------------------------------- lcm -------------------------------- */
  13360. static s7_pointer g_lcm(s7_scheme *sc, s7_pointer args)
  13361. {
  13362. #define H_lcm "(lcm ...) returns the least common multiple of its rational arguments"
  13363. #define Q_lcm pcl_f
  13364. s7_int n = 1, d = 0;
  13365. s7_pointer p;
  13366. if (!is_pair(args))
  13367. return(small_int(1));
  13368. if (!is_pair(cdr(args)))
  13369. {
  13370. if (!is_rational(car(args)))
  13371. method_or_bust_with_type(sc, car(args), sc->lcm_symbol, args, a_rational_string, 1);
  13372. return(g_abs(sc, args));
  13373. }
  13374. for (p = args; is_pair(p); p = cdr(p))
  13375. {
  13376. s7_pointer x;
  13377. s7_int b;
  13378. x = car(p);
  13379. switch (type(x))
  13380. {
  13381. case T_INTEGER:
  13382. if (integer(x) == 0)
  13383. n = 0;
  13384. else
  13385. {
  13386. b = integer(x);
  13387. if (b < 0) b = -b;
  13388. n = (n / c_gcd(n, b)) * b;
  13389. }
  13390. if (d != 0) d = 1;
  13391. break;
  13392. case T_RATIO:
  13393. b = numerator(x);
  13394. if (b < 0) b = -b;
  13395. n = (n / c_gcd(n, b)) * b;
  13396. if (d == 0)
  13397. {
  13398. if (p == args)
  13399. d = s7_denominator(x);
  13400. else d = 1;
  13401. }
  13402. else d = c_gcd(d, s7_denominator(x));
  13403. break;
  13404. default:
  13405. method_or_bust_with_type(sc, x, sc->lcm_symbol, cons(sc, (d <= 1) ? make_integer(sc, n) : s7_make_ratio(sc, n, d), p), a_rational_string, position_of(p, args));
  13406. }
  13407. if (n < 0) return(simple_out_of_range(sc, sc->lcm_symbol, args, result_is_too_large_string));
  13408. if (n == 0)
  13409. {
  13410. for (p = cdr(p); is_pair(p); p = cdr(p))
  13411. if (!is_rational_via_method(sc, car(p)))
  13412. return(wrong_type_argument_with_type(sc, sc->lcm_symbol, position_of(p, args), x, a_rational_string));
  13413. return(small_int(0));
  13414. }
  13415. }
  13416. if (d <= 1)
  13417. return(make_integer(sc, n));
  13418. return(s7_make_ratio(sc, n, d));
  13419. }
  13420. static s7_int c_lcm(s7_scheme *sc, s7_int a, s7_int b)
  13421. {
  13422. if ((a == 0) || (b == 0)) return(0);
  13423. if (a < 0) a = -a;
  13424. if (b < 0) b = -b;
  13425. return((a / c_gcd(a, b)) * b);
  13426. }
  13427. IF2_TO_IF(lcm, c_lcm)
  13428. /* -------------------------------- gcd -------------------------------- */
  13429. static s7_pointer g_gcd(s7_scheme *sc, s7_pointer args)
  13430. {
  13431. #define H_gcd "(gcd ...) returns the greatest common divisor of its rational arguments"
  13432. #define Q_gcd pcl_f
  13433. s7_int n = 0, d = 1;
  13434. s7_pointer p;
  13435. if (!is_pair(args))
  13436. return(small_int(0));
  13437. if (!is_pair(cdr(args)))
  13438. {
  13439. if (!is_rational(car(args)))
  13440. method_or_bust_with_type(sc, car(args), sc->gcd_symbol, args, a_rational_string, 1);
  13441. return(g_abs(sc, args));
  13442. }
  13443. for (p = args; is_pair(p); p = cdr(p))
  13444. {
  13445. s7_pointer x;
  13446. s7_int b;
  13447. x = car(p);
  13448. switch (type(x))
  13449. {
  13450. case T_INTEGER:
  13451. n = c_gcd(n, integer(x));
  13452. break;
  13453. case T_RATIO:
  13454. n = c_gcd(n, s7_numerator(x));
  13455. b = s7_denominator(x);
  13456. if (b < 0) b = -b;
  13457. d = (d / c_gcd(d, b)) * b;
  13458. if (d < 0) return(simple_out_of_range(sc, sc->gcd_symbol, args, result_is_too_large_string));
  13459. break;
  13460. default:
  13461. method_or_bust_with_type(sc, x, sc->gcd_symbol, cons(sc, (d <= 1) ? make_integer(sc, n) : s7_make_ratio(sc, n, d), p), a_rational_string, position_of(p, args));
  13462. }
  13463. if (n < 0) return(simple_out_of_range(sc, sc->gcd_symbol, args, result_is_too_large_string));
  13464. }
  13465. if (d <= 1)
  13466. return(make_integer(sc, n));
  13467. return(s7_make_ratio(sc, n, d));
  13468. }
  13469. static s7_int c_gcd_1(s7_scheme *sc, s7_int a, s7_int b) {return(c_gcd(a, b));}
  13470. IF2_TO_IF(gcd, c_gcd_1)
  13471. static s7_pointer s7_truncate(s7_scheme *sc, s7_pointer caller, s7_double xf) /* can't use "truncate" -- it's in unistd.h */
  13472. {
  13473. if ((xf > s7_int_max) ||
  13474. (xf < s7_int_min))
  13475. return(simple_out_of_range(sc, caller, make_real(sc, xf), its_too_large_string));
  13476. if (xf > 0.0)
  13477. return(make_integer(sc, (s7_int)floor(xf)));
  13478. return(make_integer(sc, (s7_int)ceil(xf)));
  13479. }
  13480. static s7_int c_quo_int(s7_scheme *sc, s7_int x, s7_int y)
  13481. {
  13482. if (y == 0)
  13483. division_by_zero_error(sc, sc->quotient_symbol, set_elist_2(sc, make_integer(sc, x), make_integer(sc, y)));
  13484. if ((y == -1) && (x == s7_int_min)) /* (quotient most-negative-fixnum -1) */
  13485. simple_out_of_range(sc, sc->quotient_symbol, set_elist_2(sc, make_integer(sc, x), make_integer(sc, y)), its_too_large_string);
  13486. return(x / y);
  13487. }
  13488. static s7_double c_quo_dbl(s7_scheme *sc, s7_double x, s7_double y)
  13489. {
  13490. s7_double xf;
  13491. if (y == 0.0)
  13492. division_by_zero_error(sc, sc->quotient_symbol, set_elist_2(sc, make_real(sc, x), make_real(sc, y)));
  13493. if ((is_inf(y)) || (is_NaN(y)))
  13494. wrong_type_argument_with_type(sc, sc->quotient_symbol, 2, make_real(sc, y), a_normal_real_string);
  13495. xf = x / y;
  13496. if ((xf > s7_int_max) ||
  13497. (xf < s7_int_min))
  13498. simple_out_of_range(sc, sc->quotient_symbol, make_real(sc, xf), its_too_large_string);
  13499. if (xf > 0.0)
  13500. return(floor(xf));
  13501. return(ceil(xf));
  13502. }
  13503. static s7_pointer g_quotient(s7_scheme *sc, s7_pointer args)
  13504. {
  13505. #define H_quotient "(quotient x1 x2) returns the integer quotient of x1 and x2; (quotient 4 3) = 1"
  13506. #define Q_quotient pcl_r
  13507. /* (define (quo x1 x2) (truncate (/ x1 x2))) ; slib
  13508. */
  13509. s7_pointer x, y;
  13510. s7_int d1, d2, n1, n2;
  13511. x = car(args);
  13512. y = cadr(args);
  13513. switch (type(x))
  13514. {
  13515. case T_INTEGER:
  13516. switch (type(y))
  13517. {
  13518. case T_INTEGER:
  13519. return(make_integer(sc, c_quo_int(sc, integer(x), integer(y))));
  13520. case T_RATIO:
  13521. n1 = integer(x);
  13522. d1 = 1;
  13523. n2 = numerator(y);
  13524. d2 = denominator(y);
  13525. goto RATIO_QUO_RATIO;
  13526. case T_REAL:
  13527. if (real(y) == 0.0)
  13528. return(division_by_zero_error(sc, sc->quotient_symbol, args));
  13529. if ((is_inf(real(y))) || (is_NaN(real(y))))
  13530. return(wrong_type_argument_with_type(sc, sc->quotient_symbol, 2, y, a_normal_real_string));
  13531. return(s7_truncate(sc, sc->quotient_symbol, (s7_double)integer(x) / real(y)));
  13532. default:
  13533. method_or_bust(sc, y, sc->quotient_symbol, args, T_REAL, 2);
  13534. }
  13535. case T_RATIO:
  13536. switch (type(y))
  13537. {
  13538. case T_INTEGER:
  13539. if (integer(y) == 0)
  13540. return(division_by_zero_error(sc, sc->quotient_symbol, args));
  13541. n1 = numerator(x);
  13542. d1 = denominator(x);
  13543. n2 = integer(y);
  13544. d2 = 1;
  13545. goto RATIO_QUO_RATIO;
  13546. /* this can lose:
  13547. * (quotient 1 2305843009213693952/4611686018427387903) -> 2, not 1
  13548. * (quotient 21053343141/6701487259 3587785776203/1142027682075) -> 1, not 0
  13549. */
  13550. case T_RATIO:
  13551. n1 = numerator(x);
  13552. d1 = denominator(x);
  13553. n2 = numerator(y);
  13554. d2 = denominator(y);
  13555. RATIO_QUO_RATIO:
  13556. if (d1 == d2)
  13557. return(make_integer(sc, n1 / n2)); /* (quotient 3/9223372036854775807 1/9223372036854775807) */
  13558. if (n1 == n2)
  13559. return(make_integer(sc, d2 / d1)); /* (quotient 9223372036854775807/2 9223372036854775807/8) */
  13560. #if HAVE_OVERFLOW_CHECKS
  13561. {
  13562. s7_int n1d2, n2d1;
  13563. if ((multiply_overflow(n1, d2, &n1d2)) ||
  13564. (multiply_overflow(n2, d1, &n2d1)))
  13565. return(s7_truncate(sc, sc->quotient_symbol, ((long double)n1 / (long double)n2) * ((long double)d2 / (long double)d1)));
  13566. return(make_integer(sc, n1d2 / n2d1));
  13567. }
  13568. #else
  13569. if ((integer_length(n1) + integer_length(d2) >= s7_int_bits) ||
  13570. (integer_length(n2) + integer_length(d1) >= s7_int_bits))
  13571. return(s7_truncate(sc, sc->quotient_symbol, ((long double)n1 / (long double)n2) * ((long double)d2 / (long double)d1)));
  13572. return(make_integer(sc, (n1 * d2) / (n2 * d1)));
  13573. #endif
  13574. case T_REAL:
  13575. if (real(y) == 0.0)
  13576. return(division_by_zero_error(sc, sc->quotient_symbol, args));
  13577. if ((is_inf(real(y))) || (is_NaN(real(y))))
  13578. return(wrong_type_argument_with_type(sc, sc->quotient_symbol, 2, y, a_normal_real_string));
  13579. return(s7_truncate(sc, sc->quotient_symbol, (s7_double)fraction(x) / real(y)));
  13580. default:
  13581. method_or_bust(sc, y, sc->quotient_symbol, args, T_REAL, 2);
  13582. }
  13583. case T_REAL:
  13584. if ((is_inf(real(x))) || (is_NaN(real(x))))
  13585. return(wrong_type_argument_with_type(sc, sc->quotient_symbol, 1, x, a_normal_real_string));
  13586. /* if infs allowed we need to return infs/nans, else:
  13587. * (quotient inf.0 1e-309) -> -9223372036854775808
  13588. * (quotient inf.0 inf.0) -> -9223372036854775808
  13589. */
  13590. switch (type(y))
  13591. {
  13592. case T_INTEGER:
  13593. if (integer(y) == 0)
  13594. return(division_by_zero_error(sc, sc->quotient_symbol, args));
  13595. return(s7_truncate(sc, sc->quotient_symbol, real(x) / (s7_double)integer(y)));
  13596. case T_RATIO:
  13597. return(s7_truncate(sc, sc->quotient_symbol, real(x) / (s7_double)fraction(y)));
  13598. case T_REAL:
  13599. return(make_real(sc, c_quo_dbl(sc, real(x), real(y))));
  13600. default:
  13601. method_or_bust(sc, y, sc->quotient_symbol, args, T_REAL, 2);
  13602. }
  13603. default:
  13604. method_or_bust(sc, x, sc->quotient_symbol, args, T_REAL, 2);
  13605. }
  13606. }
  13607. IF2_TO_IF(quotient, c_quo_int)
  13608. RF2_TO_RF(quotient, c_quo_dbl)
  13609. static s7_int c_rem_int(s7_scheme *sc, s7_int x, s7_int y)
  13610. {
  13611. if (y == 0)
  13612. division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, make_integer(sc, x), make_integer(sc, y)));
  13613. if ((y == 1) || (y == -1)) /* (remainder most-negative-fixnum -1) will segfault with arithmetic exception */
  13614. return(0);
  13615. return(x % y);
  13616. }
  13617. static s7_double c_rem_dbl(s7_scheme *sc, s7_double x, s7_double y)
  13618. {
  13619. s7_int quo;
  13620. s7_double pre_quo;
  13621. if (y == 0.0)
  13622. division_by_zero_error(sc, sc->remainder_symbol, set_elist_2(sc, make_real(sc, x), make_real(sc, y)));
  13623. if ((is_inf(y)) || (is_NaN(y)))
  13624. wrong_type_argument_with_type(sc, sc->remainder_symbol, 2, set_elist_1(sc, make_real(sc, y)), a_normal_real_string);
  13625. pre_quo = x / y;
  13626. if ((pre_quo > s7_int_max) || (pre_quo < s7_int_min))
  13627. simple_out_of_range(sc, sc->remainder_symbol, set_elist_2(sc, make_real(sc, x), make_real(sc, y)), its_too_large_string);
  13628. if (pre_quo > 0.0)
  13629. quo = (s7_int)floor(pre_quo);
  13630. else quo = (s7_int)ceil(pre_quo);
  13631. return(x - (y * quo));
  13632. }
  13633. static s7_pointer g_remainder(s7_scheme *sc, s7_pointer args)
  13634. {
  13635. #define H_remainder "(remainder x1 x2) returns the remainder of x1/x2; (remainder 10 3) = 1"
  13636. #define Q_remainder pcl_r
  13637. /* (define (rem x1 x2) (- x1 (* x2 (quo x1 x2)))) ; slib, if x2 is an integer (- x1 (truncate x1 x2)), fractional part: (remainder x 1) */
  13638. s7_pointer x, y;
  13639. s7_int quo, d1, d2, n1, n2;
  13640. s7_double pre_quo;
  13641. x = car(args);
  13642. y = cadr(args);
  13643. switch (type(x))
  13644. {
  13645. case T_INTEGER:
  13646. switch (type(y))
  13647. {
  13648. case T_INTEGER:
  13649. return(make_integer(sc, c_rem_int(sc, integer(x), integer(y))));
  13650. case T_RATIO:
  13651. n1 = integer(x);
  13652. d1 = 1;
  13653. n2 = numerator(y);
  13654. d2 = denominator(y);
  13655. goto RATIO_REM_RATIO;
  13656. case T_REAL:
  13657. if (real(y) == 0.0)
  13658. return(division_by_zero_error(sc, sc->remainder_symbol, args));
  13659. if ((is_inf(real(y))) || (is_NaN(real(y))))
  13660. return(wrong_type_argument_with_type(sc, sc->remainder_symbol, 2, y, a_normal_real_string));
  13661. pre_quo = (s7_double)integer(x) / real(y);
  13662. if ((pre_quo > s7_int_max) || (pre_quo < s7_int_min))
  13663. return(simple_out_of_range(sc, sc->remainder_symbol, args, its_too_large_string));
  13664. if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
  13665. return(make_real(sc, integer(x) - real(y) * quo));
  13666. default:
  13667. method_or_bust(sc, y, sc->remainder_symbol, args, T_REAL, 2);
  13668. }
  13669. case T_RATIO:
  13670. switch (type(y))
  13671. {
  13672. case T_INTEGER:
  13673. n2 = integer(y);
  13674. if (n2 == 0)
  13675. return(division_by_zero_error(sc, sc->remainder_symbol, args));
  13676. n1 = numerator(x);
  13677. d1 = denominator(x);
  13678. d2 = 1;
  13679. goto RATIO_REM_RATIO;
  13680. case T_RATIO:
  13681. n1 = numerator(x);
  13682. d1 = denominator(x);
  13683. n2 = numerator(y);
  13684. d2 = denominator(y);
  13685. RATIO_REM_RATIO:
  13686. if (d1 == d2)
  13687. quo = (s7_int)(n1 / n2);
  13688. else
  13689. {
  13690. if (n1 == n2)
  13691. quo = (s7_int)(d2 / d1);
  13692. else
  13693. {
  13694. #if HAVE_OVERFLOW_CHECKS
  13695. s7_int n1d2, n2d1;
  13696. if ((multiply_overflow(n1, d2, &n1d2)) ||
  13697. (multiply_overflow(n2, d1, &n2d1)))
  13698. {
  13699. pre_quo = ((long double)n1 / (long double)n2) * ((long double)d2 / (long double)d1);
  13700. if ((pre_quo > s7_int_max) || (pre_quo < s7_int_min))
  13701. return(simple_out_of_range(sc, sc->remainder_symbol, args, its_too_large_string));
  13702. if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
  13703. }
  13704. else quo = n1d2 / n2d1;
  13705. #else
  13706. if ((integer_length(n1) + integer_length(d2) >= s7_int_bits) ||
  13707. (integer_length(n2) + integer_length(d1) >= s7_int_bits))
  13708. {
  13709. pre_quo = ((long double)n1 / (long double)n2) * ((long double)d2 / (long double)d1);
  13710. if ((pre_quo > s7_int_max) || (pre_quo < s7_int_min))
  13711. return(simple_out_of_range(sc, sc->remainder_symbol, args, its_too_large_string));
  13712. if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
  13713. }
  13714. else quo = (n1 * d2) / (n2 * d1);
  13715. #endif
  13716. }
  13717. }
  13718. if (quo == 0)
  13719. return(x);
  13720. #if HAVE_OVERFLOW_CHECKS
  13721. {
  13722. s7_int dn, nq;
  13723. if (!multiply_overflow(n2, quo, &nq))
  13724. {
  13725. if ((d1 == d2) &&
  13726. (!subtract_overflow(n1, nq, &dn)))
  13727. return(s7_make_ratio(sc, dn, d1));
  13728. if ((!multiply_overflow(n1, d2, &dn)) &&
  13729. (!multiply_overflow(nq, d1, &nq)) &&
  13730. (!subtract_overflow(dn, nq, &nq)) &&
  13731. (!multiply_overflow(d1, d2, &d1)))
  13732. return(s7_make_ratio(sc, nq, d1));
  13733. }
  13734. }
  13735. #else
  13736. if ((d1 == d2) &&
  13737. ((integer_length(n2) + integer_length(quo)) < s7_int_bits))
  13738. return(s7_make_ratio(sc, n1 - n2 * quo, d1));
  13739. if ((integer_length(n1) + integer_length(d2) < s7_int_bits) &&
  13740. (integer_length(d1) + integer_length(d2) < s7_int_bits) &&
  13741. (integer_length(n2) + integer_length(d1) + integer_length(quo) < s7_int_bits))
  13742. return(s7_make_ratio(sc, n1 * d2 - n2 * d1 * quo, d1 * d2));
  13743. #endif
  13744. return(simple_out_of_range(sc, sc->remainder_symbol, args, make_string_wrapper(sc, "intermediate (a/b) is too large")));
  13745. case T_REAL:
  13746. {
  13747. s7_double frac;
  13748. if (real(y) == 0.0)
  13749. return(division_by_zero_error(sc, sc->remainder_symbol, args));
  13750. if ((is_inf(real(y))) || (is_NaN(real(y))))
  13751. return(wrong_type_argument_with_type(sc, sc->remainder_symbol, 2, y, a_normal_real_string));
  13752. frac = (s7_double)fraction(x);
  13753. pre_quo = frac / real(y);
  13754. if ((pre_quo > s7_int_max) || (pre_quo < s7_int_min))
  13755. return(simple_out_of_range(sc, sc->remainder_symbol, args, its_too_large_string));
  13756. if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
  13757. return(make_real(sc, frac - real(y) * quo));
  13758. }
  13759. default:
  13760. method_or_bust(sc, y, sc->remainder_symbol, args, T_REAL, 2);
  13761. }
  13762. case T_REAL:
  13763. if ((is_inf(real(x))) || (is_NaN(real(x))))
  13764. return(wrong_type_argument_with_type(sc, sc->remainder_symbol, 1, x, a_normal_real_string));
  13765. switch (type(y))
  13766. {
  13767. case T_INTEGER:
  13768. if (integer(y) == 0)
  13769. return(division_by_zero_error(sc, sc->remainder_symbol, args));
  13770. pre_quo = real(x) / (s7_double)integer(y);
  13771. if ((pre_quo > s7_int_max) || (pre_quo < s7_int_min))
  13772. return(simple_out_of_range(sc, sc->remainder_symbol, args, its_too_large_string));
  13773. if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
  13774. return(make_real(sc, real(x) - integer(y) * quo));
  13775. /* but... (remainder 1e+18 9223372036854775807) -> 1e+18 */
  13776. case T_RATIO:
  13777. {
  13778. /* bad cases here start around 1e16: (remainder 1e15 3/13) -> 0.0 with loss of digits earlier
  13779. * would long double help?
  13780. */
  13781. s7_double frac;
  13782. frac = (s7_double)fraction(y);
  13783. pre_quo = real(x) / frac;
  13784. if ((pre_quo > s7_int_max) || (pre_quo < s7_int_min))
  13785. return(simple_out_of_range(sc, sc->remainder_symbol, args, its_too_large_string));
  13786. if (pre_quo > 0.0) quo = (s7_int)floor(pre_quo); else quo = (s7_int)ceil(pre_quo);
  13787. return(make_real(sc, real(x) - frac * quo));
  13788. }
  13789. case T_REAL:
  13790. return(make_real(sc, c_rem_dbl(sc, real(x), real(y))));
  13791. /* see under sin -- this calculation is completely bogus if "a" is large
  13792. * (quotient 1e22 (* 2 pi)) -> -9223372036854775808 -- should this return arithmetic-overflow?
  13793. * but it should be 1591549430918953357688,
  13794. * (remainder 1e22 (* 2 pi)) -> 1.0057952155665e+22
  13795. * -- the "remainder" is greater than the original argument!
  13796. * Clisp gives 0.0 here, as does sbcl
  13797. * currently s7 throws an error (out-of-range).
  13798. */
  13799. default:
  13800. method_or_bust(sc, y, sc->remainder_symbol, args, T_REAL, 2);
  13801. }
  13802. default:
  13803. method_or_bust(sc, x, sc->remainder_symbol, args, T_REAL, 1);
  13804. }
  13805. }
  13806. IF2_TO_IF(remainder, c_rem_int)
  13807. RF2_TO_RF(remainder, c_rem_dbl)
  13808. /* -------------------------------- floor -------------------------------- */
  13809. #define REAL_TO_INT_LIMIT 9.2233727815085e+18
  13810. /* unfortunately, this limit is only a max in a sense: (ceiling 9223372036854770.9) => 9223372036854770
  13811. * see s7test for more examples
  13812. */
  13813. static s7_pointer g_floor(s7_scheme *sc, s7_pointer args)
  13814. {
  13815. #define H_floor "(floor x) returns the integer closest to x toward -inf"
  13816. #define Q_floor s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
  13817. s7_pointer x;
  13818. x = car(args);
  13819. switch (type(x))
  13820. {
  13821. case T_INTEGER:
  13822. return(x);
  13823. case T_RATIO:
  13824. {
  13825. s7_int val;
  13826. val = numerator(x) / denominator(x);
  13827. /* C "/" truncates? -- C spec says "truncation toward 0" */
  13828. /* we're avoiding "floor" here because the int->double conversion introduces inaccuracies for big numbers */
  13829. if (numerator(x) < 0) /* not "val" because it might be truncated to 0 */
  13830. return(make_integer(sc, val - 1));
  13831. return(make_integer(sc, val));
  13832. }
  13833. case T_REAL:
  13834. {
  13835. s7_double z;
  13836. z = real(x);
  13837. if (is_NaN(z))
  13838. return(simple_out_of_range(sc, sc->floor_symbol, x, its_nan_string));
  13839. if (fabs(z) > REAL_TO_INT_LIMIT)
  13840. return(simple_out_of_range(sc, sc->floor_symbol, x, its_too_large_string));
  13841. return(make_integer(sc, (s7_int)floor(z)));
  13842. /* floor here rounds down, whereas a straight int<=real coercion apparently rounds towards 0 */
  13843. }
  13844. case T_COMPLEX:
  13845. default:
  13846. method_or_bust(sc, x, sc->floor_symbol, args, T_REAL, 0);
  13847. }
  13848. }
  13849. static s7_int c_floor(s7_scheme *sc, s7_double x) {return((s7_int)floor(x));}
  13850. RF_TO_IF(floor, c_floor)
  13851. /* -------------------------------- ceiling -------------------------------- */
  13852. static s7_pointer g_ceiling(s7_scheme *sc, s7_pointer args)
  13853. {
  13854. #define H_ceiling "(ceiling x) returns the integer closest to x toward inf"
  13855. #define Q_ceiling s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
  13856. s7_pointer x;
  13857. x = car(args);
  13858. switch (type(x))
  13859. {
  13860. case T_INTEGER:
  13861. return(x);
  13862. case T_RATIO:
  13863. {
  13864. s7_int val;
  13865. val = numerator(x) / denominator(x);
  13866. if (numerator(x) < 0)
  13867. return(make_integer(sc, val));
  13868. return(make_integer(sc, val + 1));
  13869. }
  13870. case T_REAL:
  13871. {
  13872. s7_double z;
  13873. z = real(x);
  13874. if (is_NaN(z))
  13875. return(simple_out_of_range(sc, sc->ceiling_symbol, x, its_nan_string));
  13876. if ((is_inf(z)) ||
  13877. (z > REAL_TO_INT_LIMIT) ||
  13878. (z < -REAL_TO_INT_LIMIT))
  13879. return(simple_out_of_range(sc, sc->ceiling_symbol, x, its_too_large_string));
  13880. return(make_integer(sc, (s7_int)ceil(real(x))));
  13881. }
  13882. case T_COMPLEX:
  13883. default:
  13884. method_or_bust(sc, x, sc->ceiling_symbol, args, T_REAL, 0);
  13885. }
  13886. }
  13887. static s7_int c_ceiling(s7_scheme *sc, s7_double x) {return((s7_int)ceil(x));}
  13888. RF_TO_IF(ceiling, c_ceiling)
  13889. /* -------------------------------- truncate -------------------------------- */
  13890. static s7_pointer g_truncate(s7_scheme *sc, s7_pointer args)
  13891. {
  13892. #define H_truncate "(truncate x) returns the integer closest to x toward 0"
  13893. #define Q_truncate s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
  13894. s7_pointer x;
  13895. x = car(args);
  13896. switch (type(x))
  13897. {
  13898. case T_INTEGER:
  13899. return(x);
  13900. case T_RATIO:
  13901. return(make_integer(sc, (s7_int)(numerator(x) / denominator(x)))); /* C "/" already truncates */
  13902. case T_REAL:
  13903. {
  13904. s7_double z;
  13905. z = real(x);
  13906. if (is_NaN(z))
  13907. return(simple_out_of_range(sc, sc->truncate_symbol, x, its_nan_string));
  13908. if (is_inf(z))
  13909. return(simple_out_of_range(sc, sc->truncate_symbol, x, its_infinite_string));
  13910. return(s7_truncate(sc, sc->truncate_symbol, real(x)));
  13911. }
  13912. case T_COMPLEX:
  13913. default:
  13914. method_or_bust(sc, x, sc->truncate_symbol, args, T_REAL, 0);
  13915. }
  13916. }
  13917. static s7_int c_trunc(s7_scheme *sc, s7_double x)
  13918. {
  13919. if ((x > s7_int_max) || (x < s7_int_min))
  13920. simple_out_of_range(sc, sc->truncate_symbol, make_real(sc, x), its_too_large_string);
  13921. if (x > 0.0)
  13922. return((s7_int)floor(x));
  13923. return((s7_int)ceil(x));
  13924. }
  13925. RF_TO_IF(truncate, c_trunc)
  13926. /* -------------------------------- round -------------------------------- */
  13927. static s7_double round_per_R5RS(s7_double x)
  13928. {
  13929. s7_double fl, ce, dfl, dce;
  13930. fl = floor(x);
  13931. ce = ceil(x);
  13932. dfl = x - fl;
  13933. dce = ce - x;
  13934. if (dfl > dce) return(ce);
  13935. if (dfl < dce) return(fl);
  13936. if (fmod(fl, 2.0) == 0.0) return(fl);
  13937. return(ce);
  13938. }
  13939. static s7_pointer g_round(s7_scheme *sc, s7_pointer args)
  13940. {
  13941. #define H_round "(round x) returns the integer closest to x"
  13942. #define Q_round s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
  13943. s7_pointer x;
  13944. x = car(args);
  13945. switch (type(x))
  13946. {
  13947. case T_INTEGER:
  13948. return(x);
  13949. case T_RATIO:
  13950. {
  13951. s7_int truncated, remains;
  13952. long double frac;
  13953. truncated = numerator(x) / denominator(x);
  13954. remains = numerator(x) % denominator(x);
  13955. frac = s7_fabsl((long double)remains / (long double)denominator(x));
  13956. if ((frac > 0.5) ||
  13957. ((frac == 0.5) &&
  13958. (truncated % 2 != 0)))
  13959. {
  13960. if (numerator(x) < 0)
  13961. return(make_integer(sc, truncated - 1));
  13962. return(make_integer(sc, truncated + 1));
  13963. }
  13964. return(make_integer(sc, truncated));
  13965. }
  13966. case T_REAL:
  13967. {
  13968. s7_double z;
  13969. z = real(x);
  13970. if (is_NaN(z))
  13971. return(simple_out_of_range(sc, sc->round_symbol, x, its_nan_string));
  13972. if ((is_inf(z)) ||
  13973. (z > REAL_TO_INT_LIMIT) ||
  13974. (z < -REAL_TO_INT_LIMIT))
  13975. return(simple_out_of_range(sc, sc->round_symbol, x, its_too_large_string));
  13976. return(make_integer(sc, (s7_int)round_per_R5RS(z)));
  13977. }
  13978. case T_COMPLEX:
  13979. default:
  13980. method_or_bust(sc, x, sc->round_symbol, args, T_REAL, 0);
  13981. }
  13982. }
  13983. static s7_int c_round(s7_scheme *sc, s7_double x) {return((s7_int)round_per_R5RS(x));}
  13984. RF_TO_IF(round, c_round)
  13985. static s7_int c_mod(s7_scheme *sc, s7_int x, s7_int y)
  13986. {
  13987. s7_int z;
  13988. /* if (y == 0) return(x); */ /* else arithmetic exception, but we're checking for this elsewhere */
  13989. z = x % y;
  13990. if (((y < 0) && (z > 0)) ||
  13991. ((y > 0) && (z < 0)))
  13992. return(z + y);
  13993. return(z);
  13994. }
  13995. static s7_pointer g_modulo(s7_scheme *sc, s7_pointer args)
  13996. {
  13997. #define H_modulo "(modulo x1 x2) returns x1 mod x2; (modulo 4 3) = 1. The arguments can be real numbers."
  13998. #define Q_modulo pcl_r
  13999. /* (define (mod x1 x2) (- x1 (* x2 (floor (/ x1 x2))))) from slib
  14000. * (mod x 0) = x according to "Concrete Mathematics"
  14001. */
  14002. s7_pointer x, y;
  14003. s7_double a, b;
  14004. s7_int n1, n2, d1, d2;
  14005. x = car(args);
  14006. y = cadr(args);
  14007. switch (type(x))
  14008. {
  14009. case T_INTEGER:
  14010. switch (type(y))
  14011. {
  14012. case T_INTEGER:
  14013. if (integer(y) == 0)
  14014. return(x);
  14015. if ((integer(y) == 1) || (integer(y) == -1))
  14016. return(small_int(0));
  14017. /* (modulo most-negative-fixnum -1) will segfault with arithmetic exception */
  14018. return(make_integer(sc, c_mod(sc, integer(x), integer(y))));
  14019. case T_RATIO:
  14020. n1 = integer(x);
  14021. d1 = 1;
  14022. n2 = numerator(y);
  14023. d2 = denominator(y);
  14024. goto RATIO_MOD_RATIO;
  14025. case T_REAL:
  14026. b = real(y);
  14027. if (b == 0.0) return(x);
  14028. if (is_NaN(b)) return(y);
  14029. if (is_inf(b)) return(real_NaN);
  14030. a = (s7_double)integer(x);
  14031. return(make_real(sc, a - b * (s7_int)floor(a / b)));
  14032. default:
  14033. method_or_bust(sc, y, sc->modulo_symbol, args, T_REAL, 2);
  14034. }
  14035. case T_RATIO:
  14036. switch (type(y))
  14037. {
  14038. case T_INTEGER:
  14039. if (integer(y) == 0) return(x);
  14040. n1 = numerator(x);
  14041. d1 = denominator(x);
  14042. n2 = integer(y);
  14043. if ((n2 > 0) && (n1 > 0) && (n2 > n1)) return(x);
  14044. if ((n2 < 0) && (n1 < 0) && (n2 < n1)) return(x);
  14045. if (n2 == s7_int_min)
  14046. return(simple_out_of_range(sc, sc->modulo_symbol, y, make_string_wrapper(sc, "intermediate (a/b) is too large")));
  14047. /* the problem here is that (modulo 3/2 most-negative-fixnum)
  14048. * will segfault with signal SIGFPE, Arithmetic exception, so try to trap it.
  14049. */
  14050. d2 = 1;
  14051. goto RATIO_MOD_RATIO;
  14052. case T_RATIO:
  14053. n1 = numerator(x);
  14054. d1 = denominator(x);
  14055. n2 = numerator(y); /* can't be 0 */
  14056. d2 = denominator(y);
  14057. if (d1 == d2)
  14058. return(s7_make_ratio(sc, c_mod(sc, n1, n2), d1));
  14059. RATIO_MOD_RATIO:
  14060. if ((n1 == n2) &&
  14061. (d1 > d2))
  14062. return(x); /* signs match so this should be ok */
  14063. #if HAVE_OVERFLOW_CHECKS
  14064. {
  14065. s7_int n2d1, n1d2, d1d2, fl;
  14066. if (!multiply_overflow(n2, d1, &n2d1))
  14067. {
  14068. if (n2d1 == 1)
  14069. return(small_int(0));
  14070. if (!multiply_overflow(n1, d2, &n1d2))
  14071. {
  14072. /* can't use "floor" here (int->float ruins everything) */
  14073. fl = (s7_int)(n1d2 / n2d1);
  14074. if (((n1 < 0) && (n2 > 0)) ||
  14075. ((n1 > 0) && (n2 < 0)))
  14076. fl -= 1;
  14077. if (fl == 0)
  14078. return(x);
  14079. if ((!multiply_overflow(d1, d2, &d1d2)) &&
  14080. (!multiply_overflow(fl, n2d1, &fl)) &&
  14081. (!subtract_overflow(n1d2, fl, &fl)))
  14082. return(s7_make_ratio(sc, fl, d1d2));
  14083. }
  14084. }
  14085. }
  14086. #else
  14087. if ((integer_length(n1) + integer_length(d2) < s7_int_bits) &&
  14088. (integer_length(n2) + integer_length(d1) < s7_int_bits) &&
  14089. (integer_length(d1) + integer_length(d2) < s7_int_bits))
  14090. {
  14091. s7_int n1d2, n2d1, fl;
  14092. n1d2 = n1 * d2;
  14093. n2d1 = n2 * d1;
  14094. if (n2d1 == 1)
  14095. return(small_int(0));
  14096. /* can't use "floor" here (int->float ruins everything) */
  14097. fl = (s7_int)(n1d2 / n2d1);
  14098. if (((n1 < 0) && (n2 > 0)) ||
  14099. ((n1 > 0) && (n2 < 0)))
  14100. fl -= 1;
  14101. if (fl == 0)
  14102. return(x);
  14103. if (integer_length(n2d1) + integer_length(fl) < s7_int_bits)
  14104. return(s7_make_ratio(sc, n1d2 - (n2d1 * fl), d1 * d2));
  14105. }
  14106. #endif
  14107. /* there are cases here we might want to catch:
  14108. * (modulo 9223372036 1/9223372036) -> error, not 0?
  14109. * (modulo 1 1/9223372036854775807) -> error, not 0?
  14110. */
  14111. return(simple_out_of_range(sc, sc->modulo_symbol, x, make_string_wrapper(sc, "intermediate (a/b) is too large")));
  14112. case T_REAL:
  14113. b = real(y);
  14114. if (b == 0.0) return(x);
  14115. if (is_NaN(b)) return(y);
  14116. if (is_inf(b)) return(real_NaN);
  14117. a = fraction(x);
  14118. return(make_real(sc, a - b * (s7_int)floor(a / b)));
  14119. default:
  14120. method_or_bust(sc, y, sc->modulo_symbol, args, T_REAL, 2);
  14121. }
  14122. case T_REAL:
  14123. a = real(x);
  14124. switch (type(y))
  14125. {
  14126. case T_INTEGER:
  14127. if (is_NaN(a)) return(x);
  14128. if (is_inf(a)) return(real_NaN);
  14129. if (integer(y) == 0) return(x);
  14130. b = (s7_double)integer(y);
  14131. return(make_real(sc, a - b * (s7_int)floor(a / b)));
  14132. case T_RATIO:
  14133. if (is_NaN(a)) return(x);
  14134. if (is_inf(a)) return(real_NaN);
  14135. b = fraction(y);
  14136. return(make_real(sc, a - b * (s7_int)floor(a / b)));
  14137. case T_REAL:
  14138. if (is_NaN(a)) return(x);
  14139. if (is_inf(a)) return(real_NaN);
  14140. b = real(y);
  14141. if (b == 0.0) return(x);
  14142. if (is_NaN(b)) return(y);
  14143. if (is_inf(b)) return(real_NaN);
  14144. return(make_real(sc, a - b * (s7_int)floor(a / b)));
  14145. default:
  14146. method_or_bust(sc, y, sc->modulo_symbol, args, T_REAL, 2);
  14147. }
  14148. default:
  14149. method_or_bust(sc, x, sc->modulo_symbol, args, T_REAL, 1);
  14150. }
  14151. }
  14152. IF2_TO_IF(modulo, c_mod)
  14153. static s7_double c_mod_r(s7_scheme *sc, s7_double x, s7_double y) {return(x - y * (s7_int)floor(x / y));}
  14154. RF2_TO_RF(modulo, c_mod_r)
  14155. static s7_pointer mod_si;
  14156. static s7_pointer g_mod_si(s7_scheme *sc, s7_pointer args)
  14157. {
  14158. s7_pointer x;
  14159. s7_int y;
  14160. x = find_symbol_checked(sc, car(args));
  14161. y = integer(cadr(args));
  14162. if (is_integer(x))
  14163. {
  14164. s7_int z;
  14165. /* here we know y is positive */
  14166. z = integer(x) % y;
  14167. if (z < 0)
  14168. return(make_integer(sc, z + y));
  14169. return(make_integer(sc, z));
  14170. }
  14171. if (is_t_real(x))
  14172. {
  14173. s7_double a, b;
  14174. a = real(x);
  14175. if (is_NaN(a)) return(x);
  14176. if (is_inf(a)) return(real_NaN);
  14177. b = (s7_double)y;
  14178. return(make_real(sc, a - b * (s7_int)floor(a / b)));
  14179. }
  14180. if (s7_is_ratio(x))
  14181. return(g_modulo(sc, set_plist_2(sc, x, cadr(args))));
  14182. method_or_bust(sc, x, sc->modulo_symbol, list_2(sc, x, cadr(args)), T_REAL, 1);
  14183. }
  14184. static s7_pointer g_is_zero(s7_scheme *sc, s7_pointer args);
  14185. static s7_pointer mod_si_is_zero;
  14186. static s7_pointer g_mod_si_is_zero(s7_scheme *sc, s7_pointer args)
  14187. {
  14188. s7_pointer x;
  14189. s7_int y;
  14190. /* car is (modulo symbol integer), cadr is 0 or not present (if zero?) */
  14191. x = find_symbol_checked(sc, cadar(args));
  14192. y = integer(caddar(args));
  14193. if (is_integer(x))
  14194. return(make_boolean(sc, (integer(x) % y) == 0));
  14195. if (is_t_real(x))
  14196. return(make_boolean(sc, (fmod(real(x), (s7_double)y) == 0.0)));
  14197. if (s7_is_ratio(x))
  14198. return(sc->F);
  14199. {
  14200. s7_pointer func;
  14201. if ((func = find_method(sc, find_let(sc, x), sc->modulo_symbol)) != sc->undefined)
  14202. return(g_is_zero(sc, set_plist_1(sc, s7_apply_function(sc, func, list_2(sc, x, caddar(args))))));
  14203. }
  14204. return(wrong_type_argument(sc, sc->modulo_symbol, 1, x, T_REAL));
  14205. }
  14206. #endif
  14207. /* !WITH_GMP */
  14208. static int reduce_fraction(s7_scheme *sc, s7_int *numer, s7_int *denom)
  14209. {
  14210. /* we're assuming in several places that we have a normal s7 rational after returning,
  14211. * so the denominator needs to be positive.
  14212. */
  14213. s7_int divisor;
  14214. if (*numer == 0)
  14215. {
  14216. *denom = 1;
  14217. return(T_INTEGER);
  14218. }
  14219. if (*denom < 0)
  14220. {
  14221. if (*denom == *numer)
  14222. {
  14223. *denom = 1;
  14224. *numer = 1;
  14225. return(T_INTEGER);
  14226. }
  14227. if (*denom == s7_int_min)
  14228. {
  14229. if (*numer & 1)
  14230. return(T_RATIO);
  14231. *denom /= 2;
  14232. *numer /= 2;
  14233. }
  14234. else
  14235. {
  14236. if (*numer == s7_int_min)
  14237. {
  14238. if (*denom & 1)
  14239. return(T_RATIO);
  14240. *denom /= 2;
  14241. *numer /= 2;
  14242. }
  14243. }
  14244. *denom = -*denom;
  14245. *numer = -*numer;
  14246. }
  14247. divisor = c_gcd(*numer, *denom);
  14248. if (divisor != 1)
  14249. {
  14250. *numer /= divisor;
  14251. *denom /= divisor;
  14252. }
  14253. if (*denom == 1)
  14254. return(T_INTEGER);
  14255. return(T_RATIO);
  14256. }
  14257. /* ---------------------------------------- add ---------------------------------------- */
  14258. static s7_pointer g_add(s7_scheme *sc, s7_pointer args)
  14259. {
  14260. #define H_add "(+ ...) adds its arguments"
  14261. #define Q_add pcl_n
  14262. s7_pointer x, p;
  14263. s7_int num_a, den_a, dn;
  14264. s7_double rl_a, im_a;
  14265. #if (!WITH_GMP)
  14266. if (is_null(args))
  14267. return(small_int(0));
  14268. #endif
  14269. x = car(args);
  14270. p = cdr(args);
  14271. if (is_null(p))
  14272. {
  14273. if (!is_number(x))
  14274. method_or_bust_with_type(sc, x, sc->add_symbol, args, a_number_string, 0);
  14275. return(x);
  14276. }
  14277. switch (type(x))
  14278. {
  14279. case T_INTEGER:
  14280. num_a = integer(x);
  14281. ADD_INTEGERS:
  14282. #if WITH_GMP
  14283. if ((num_a > s7_int32_max) ||
  14284. (num_a < s7_int32_min))
  14285. return(big_add(sc, cons(sc, s7_int_to_big_integer(sc, num_a), p)));
  14286. #endif
  14287. x = car(p);
  14288. p = cdr(p);
  14289. switch (type(x))
  14290. {
  14291. case T_INTEGER:
  14292. #if HAVE_OVERFLOW_CHECKS
  14293. if (add_overflow(num_a, integer(x), &den_a))
  14294. {
  14295. rl_a = (s7_double)num_a + (s7_double)integer(x);
  14296. if (is_null(p)) return(make_real(sc, rl_a));
  14297. goto ADD_REALS;
  14298. }
  14299. #else
  14300. den_a = num_a + integer(x);
  14301. if (den_a < 0)
  14302. {
  14303. if ((num_a > 0) && (integer(x) > 0))
  14304. {
  14305. rl_a = (s7_double)num_a + (s7_double)integer(x);
  14306. if (is_null(p)) return(make_real(sc, rl_a));
  14307. goto ADD_REALS;
  14308. }
  14309. }
  14310. else
  14311. {
  14312. if ((num_a < 0) && (integer(x) < 0))
  14313. {
  14314. rl_a = (s7_double)num_a + (s7_double)integer(x);
  14315. if (is_null(p)) return(make_real(sc, rl_a));
  14316. /* this is not ideal! piano.scm has its own noise generator that wants integer
  14317. * arithmetic to overflow as an integer. Perhaps 'safety==0 would not check
  14318. * anywhere?
  14319. */
  14320. goto ADD_REALS;
  14321. }
  14322. }
  14323. #endif
  14324. if (is_null(p)) return(make_integer(sc, den_a));
  14325. num_a = den_a;
  14326. /* (+ 4611686018427387904 4611686018427387904) -> -9223372036854775808
  14327. * (+ most-positive-fixnum most-positive-fixnum) -> -2
  14328. * (+ most-negative-fixnum most-negative-fixnum) -> 0
  14329. * can't check result - arg: (- 0 most-negative-fixnum) -> most-negative-fixnum
  14330. */
  14331. goto ADD_INTEGERS;
  14332. case T_RATIO:
  14333. den_a = denominator(x);
  14334. #if HAVE_OVERFLOW_CHECKS
  14335. if ((multiply_overflow(den_a, num_a, &dn)) ||
  14336. (add_overflow(dn, numerator(x), &dn)))
  14337. #else
  14338. if ((integer_length(num_a) + integer_length(den_a) + integer_length(numerator(x))) < s7_int_bits)
  14339. dn = numerator(x) + (num_a * den_a);
  14340. else
  14341. #endif
  14342. {
  14343. if (is_null(p))
  14344. {
  14345. if (num_a == 0) /* (+ 0 1/9223372036854775807) */
  14346. return(x);
  14347. return(make_real(sc, num_a + fraction(x)));
  14348. }
  14349. rl_a = (s7_double)num_a + fraction(x);
  14350. goto ADD_REALS;
  14351. }
  14352. if (is_null(p)) return(s7_make_ratio(sc, dn, den_a));
  14353. num_a = dn;
  14354. /* overflow examples:
  14355. * (+ 100000 1/142857142857140) -> -832205957599110323/28571428571428
  14356. * (+ 4611686018427387904 3/4) -> 3/4
  14357. * see s7test for more
  14358. */
  14359. goto ADD_RATIOS;
  14360. case T_REAL:
  14361. if (is_null(p)) return(make_real(sc, num_a + real(x)));
  14362. rl_a = (s7_double)num_a + real(x);
  14363. goto ADD_REALS;
  14364. case T_COMPLEX:
  14365. if (is_null(p)) return(s7_make_complex(sc, num_a + real_part(x), imag_part(x)));
  14366. rl_a = (s7_double)num_a + real_part(x);
  14367. im_a = imag_part(x);
  14368. goto ADD_COMPLEX;
  14369. default:
  14370. method_or_bust_with_type(sc, x, sc->add_symbol, cons(sc, s7_make_integer(sc, num_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  14371. }
  14372. break;
  14373. case T_RATIO:
  14374. num_a = numerator(x);
  14375. den_a = denominator(x);
  14376. ADD_RATIOS:
  14377. #if WITH_GMP
  14378. if ((num_a > s7_int32_max) ||
  14379. (den_a > s7_int32_max) ||
  14380. (num_a < s7_int32_min))
  14381. return(big_add(sc, cons(sc, s7_ratio_to_big_ratio(sc, num_a, den_a), p)));
  14382. #endif
  14383. x = car(p);
  14384. p = cdr(p);
  14385. switch (type(x))
  14386. {
  14387. case T_INTEGER:
  14388. #if HAVE_OVERFLOW_CHECKS
  14389. if ((multiply_overflow(den_a, integer(x), &dn)) ||
  14390. (add_overflow(dn, num_a, &dn)))
  14391. #else
  14392. if ((integer_length(integer(x)) + integer_length(den_a) + integer_length(num_a)) < s7_int_bits)
  14393. dn = num_a + (integer(x) * den_a);
  14394. else
  14395. #endif
  14396. {
  14397. /* (+ 3/4 4611686018427387904) -> 3/4
  14398. * (+ 1/17179869184 1073741824) -> 1/17179869184
  14399. * (+ 1/8589934592 1073741824) -> -9223372036854775807/8589934592
  14400. */
  14401. if (is_null(p))
  14402. return(make_real(sc, (s7_double)integer(x) + ((long double)num_a / (long double)den_a)));
  14403. rl_a = (s7_double)integer(x) + ((long double)num_a / (long double)den_a);
  14404. goto ADD_REALS;
  14405. }
  14406. if (is_null(p)) return(s7_make_ratio(sc, dn, den_a));
  14407. num_a = dn;
  14408. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  14409. goto ADD_INTEGERS;
  14410. goto ADD_RATIOS;
  14411. case T_RATIO:
  14412. {
  14413. s7_int d1, d2, n1, n2;
  14414. d1 = den_a;
  14415. n1 = num_a;
  14416. d2 = denominator(x);
  14417. n2 = numerator(x);
  14418. if (d1 == d2) /* the easy case -- if overflow here, it matches the int case */
  14419. {
  14420. if (is_null(p))
  14421. return(s7_make_ratio(sc, n1 + n2, d1));
  14422. num_a += n2; /* d1 can't be zero */
  14423. }
  14424. else
  14425. {
  14426. #if (!WITH_GMP)
  14427. #if HAVE_OVERFLOW_CHECKS
  14428. s7_int n1d2, n2d1;
  14429. if ((multiply_overflow(d1, d2, &den_a)) ||
  14430. (multiply_overflow(n1, d2, &n1d2)) ||
  14431. (multiply_overflow(n2, d1, &n2d1)) ||
  14432. (add_overflow(n1d2, n2d1, &num_a)))
  14433. {
  14434. if (is_null(p))
  14435. return(make_real(sc, ((long double)n1 / (long double)d1) + ((long double)n2 / (long double)d2)));
  14436. rl_a = ((long double)n1 / (long double)d1) + ((long double)n2 / (long double)d2);
  14437. goto ADD_REALS;
  14438. }
  14439. #else
  14440. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  14441. (n1 > s7_int32_max) || (n2 > s7_int32_max) ||
  14442. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  14443. {
  14444. int d1bits, d2bits;
  14445. d1bits = integer_length(d1);
  14446. d2bits = integer_length(d2);
  14447. if (((d1bits + d2bits) > s7_int_bits) ||
  14448. ((d1bits + integer_length(n2)) > (s7_int_bits - 1)) ||
  14449. ((d2bits + integer_length(n1)) > (s7_int_bits - 1)))
  14450. {
  14451. if (is_null(p))
  14452. return(make_real(sc, ((long double)n1 / (long double)d1) + ((long double)n2 / (long double)d2)));
  14453. rl_a = ((long double)n1 / (long double)d1) + ((long double)n2 / (long double)d2);
  14454. /* this can lose:
  14455. * (+ 1 1/9223372036854775807 -1) -> 0.0 not 1/9223372036854775807
  14456. */
  14457. goto ADD_REALS;
  14458. }
  14459. }
  14460. num_a = n1 * d2 + n2 * d1;
  14461. den_a = d1 * d2;
  14462. #endif
  14463. #else
  14464. num_a = n1 * d2 + n2 * d1;
  14465. den_a = d1 * d2;
  14466. #endif
  14467. if (is_null(p))
  14468. return(s7_make_ratio(sc, num_a, den_a));
  14469. }
  14470. /* (+ 1/100 99/100 (- most-positive-fixnum 2)) should not be converted to real
  14471. */
  14472. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  14473. goto ADD_INTEGERS;
  14474. goto ADD_RATIOS;
  14475. }
  14476. case T_REAL:
  14477. if (is_null(p)) return(make_real(sc, ((long double)num_a / (long double)den_a) + real(x)));
  14478. rl_a = ((long double)num_a / (long double)den_a) + real(x);
  14479. goto ADD_REALS;
  14480. case T_COMPLEX:
  14481. if (is_null(p)) return(s7_make_complex(sc, ((long double)num_a / (long double)den_a) + real_part(x), imag_part(x)));
  14482. rl_a = ((long double)num_a / (long double)den_a) + real_part(x);
  14483. im_a = imag_part(x);
  14484. goto ADD_COMPLEX;
  14485. default:
  14486. method_or_bust_with_type(sc, x, sc->add_symbol, cons(sc, s7_make_ratio(sc, num_a, den_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  14487. }
  14488. break;
  14489. case T_REAL:
  14490. rl_a = real(x);
  14491. ADD_REALS:
  14492. x = car(p);
  14493. p = cdr(p);
  14494. switch (type(x))
  14495. {
  14496. case T_INTEGER:
  14497. if (is_null(p)) return(make_real(sc, rl_a + integer(x)));
  14498. rl_a += (s7_double)integer(x);
  14499. goto ADD_REALS;
  14500. case T_RATIO:
  14501. if (is_null(p)) return(make_real(sc, rl_a + fraction(x)));
  14502. rl_a += (s7_double)fraction(x);
  14503. goto ADD_REALS;
  14504. case T_REAL:
  14505. if (is_null(p)) return(make_real(sc, rl_a + real(x)));
  14506. rl_a += real(x);
  14507. goto ADD_REALS;
  14508. case T_COMPLEX:
  14509. if (is_null(p)) return(s7_make_complex(sc, rl_a + real_part(x), imag_part(x)));
  14510. rl_a += real_part(x);
  14511. im_a = imag_part(x);
  14512. goto ADD_COMPLEX;
  14513. default:
  14514. method_or_bust_with_type(sc, x, sc->add_symbol, cons(sc, make_real(sc, rl_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  14515. }
  14516. break;
  14517. case T_COMPLEX:
  14518. rl_a = real_part(x);
  14519. im_a = imag_part(x);
  14520. ADD_COMPLEX:
  14521. x = car(p);
  14522. p = cdr(p);
  14523. switch (type(x))
  14524. {
  14525. case T_INTEGER:
  14526. if (is_null(p)) return(s7_make_complex(sc, rl_a + integer(x), im_a));
  14527. rl_a += (s7_double)integer(x);
  14528. goto ADD_COMPLEX;
  14529. case T_RATIO:
  14530. if (is_null(p)) return(s7_make_complex(sc, rl_a + fraction(x), im_a));
  14531. rl_a += (s7_double)fraction(x);
  14532. goto ADD_COMPLEX;
  14533. case T_REAL:
  14534. if (is_null(p)) return(s7_make_complex(sc, rl_a + real(x), im_a));
  14535. rl_a += real(x);
  14536. goto ADD_COMPLEX;
  14537. case T_COMPLEX:
  14538. if (is_null(p)) return(s7_make_complex(sc, rl_a + real_part(x), im_a + imag_part(x)));
  14539. rl_a += real_part(x);
  14540. im_a += imag_part(x);
  14541. if (im_a == 0.0)
  14542. goto ADD_REALS;
  14543. goto ADD_COMPLEX;
  14544. default:
  14545. method_or_bust_with_type(sc, x, sc->add_symbol, cons(sc, s7_make_complex(sc, rl_a, im_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  14546. }
  14547. break;
  14548. default:
  14549. method_or_bust_with_type(sc, x, sc->add_symbol, args, a_number_string, 1);
  14550. }
  14551. }
  14552. static s7_pointer add_2, add_1s, add_s1, add_cs1, add_si, add_sf, add_fs;
  14553. static s7_pointer add_ratios(s7_scheme *sc, s7_pointer x, s7_pointer y)
  14554. {
  14555. s7_int d1, d2, n1, n2;
  14556. d1 = number_to_denominator(x);
  14557. n1 = number_to_numerator(x);
  14558. d2 = number_to_denominator(y);
  14559. n2 = number_to_numerator(y);
  14560. if (d1 == d2) /* the easy case -- if overflow here, it matches the int case */
  14561. return(s7_make_ratio(sc, n1 + n2, d1));
  14562. #if HAVE_OVERFLOW_CHECKS
  14563. {
  14564. s7_int n1d2, n2d1, d1d2, dn;
  14565. if ((multiply_overflow(d1, d2, &d1d2)) ||
  14566. (multiply_overflow(n1, d2, &n1d2)) ||
  14567. (multiply_overflow(n2, d1, &n2d1)) ||
  14568. (add_overflow(n1d2, n2d1, &dn)))
  14569. return(make_real(sc, ((long double)n1 / (long double)d1) + ((long double)n2 / (long double)d2)));
  14570. return(s7_make_ratio(sc, dn, d1d2));
  14571. }
  14572. #else
  14573. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  14574. (n1 > s7_int32_max) || (n2 > s7_int32_max) ||
  14575. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  14576. {
  14577. int d1bits, d2bits;
  14578. d1bits = integer_length(d1);
  14579. d2bits = integer_length(d2);
  14580. if (((d1bits + d2bits) > s7_int_bits) ||
  14581. ((d1bits + integer_length(n2)) > (s7_int_bits - 1)) ||
  14582. ((d2bits + integer_length(n1)) > (s7_int_bits - 1)))
  14583. return(make_real(sc, ((long double)n1 / (long double)d1) + ((long double)n2 / (long double)d2)));
  14584. }
  14585. return(s7_make_ratio(sc, n1 * d2 + n2 * d1, d1 * d2));
  14586. #endif
  14587. }
  14588. static s7_pointer g_add_2(s7_scheme *sc, s7_pointer args)
  14589. {
  14590. s7_pointer x, y;
  14591. x = car(args);
  14592. y = cadr(args);
  14593. if (type(x) == type(y))
  14594. {
  14595. if (is_t_real(x))
  14596. return(make_real(sc, real(x) + real(y)));
  14597. else
  14598. {
  14599. switch (type(x))
  14600. {
  14601. #if HAVE_OVERFLOW_CHECKS
  14602. case T_INTEGER:
  14603. {
  14604. s7_int val;
  14605. if (add_overflow(integer(x), integer(y), &val))
  14606. return(make_real(sc, (double)integer(x) + (double)integer(y)));
  14607. return(make_integer(sc, val));
  14608. }
  14609. #else
  14610. case T_INTEGER: return(make_integer(sc, integer(x) + integer(y)));
  14611. #endif
  14612. case T_RATIO: return(add_ratios(sc, x, y));
  14613. case T_REAL: return(make_real(sc, real(x) + real(y)));
  14614. case T_COMPLEX: return(make_complex(sc, real_part(x) + real_part(y), imag_part(x) + imag_part(y)));
  14615. default:
  14616. if (!is_number(x))
  14617. method_or_bust_with_type(sc, x, sc->add_symbol, args, a_number_string, 1);
  14618. method_or_bust_with_type(sc, y, sc->add_symbol, args, a_number_string, 2);
  14619. }
  14620. }
  14621. }
  14622. switch (type(x))
  14623. {
  14624. case T_INTEGER:
  14625. switch (type(y))
  14626. {
  14627. case T_INTEGER: return(make_integer(sc, integer(x) + integer(y)));
  14628. case T_RATIO: return(add_ratios(sc, x, y));
  14629. case T_REAL: return(make_real(sc, integer(x) + real(y)));
  14630. case T_COMPLEX: return(make_complex(sc, integer(x) + real_part(y), imag_part(y)));
  14631. default:
  14632. method_or_bust_with_type(sc, y, sc->add_symbol, args, a_number_string, 2);
  14633. }
  14634. case T_RATIO:
  14635. switch (type(y))
  14636. {
  14637. case T_INTEGER:
  14638. case T_RATIO: return(add_ratios(sc, x, y));
  14639. case T_REAL: return(make_real(sc, fraction(x) + real(y)));
  14640. case T_COMPLEX: return(s7_make_complex(sc, fraction(x) + real_part(y), imag_part(y)));
  14641. default:
  14642. method_or_bust_with_type(sc, y, sc->add_symbol, args, a_number_string, 2);
  14643. }
  14644. case T_REAL:
  14645. switch (type(y))
  14646. {
  14647. case T_INTEGER: return(make_real(sc, real(x) + integer(y)));
  14648. case T_RATIO: return(make_real(sc, real(x) + fraction(y)));
  14649. case T_REAL: return(make_real(sc, real(x) + real(y)));
  14650. case T_COMPLEX: return(make_complex(sc, real(x) + real_part(y), imag_part(y)));
  14651. default:
  14652. method_or_bust_with_type(sc, y, sc->add_symbol, args, a_number_string, 2);
  14653. }
  14654. case T_COMPLEX:
  14655. switch (type(y))
  14656. {
  14657. case T_INTEGER: return(s7_make_complex(sc, real_part(x) + integer(y), imag_part(x)));
  14658. case T_RATIO: return(s7_make_complex(sc, real_part(x) + fraction(y), imag_part(x)));
  14659. case T_REAL: return(s7_make_complex(sc, real_part(x) + real(y), imag_part(x)));
  14660. case T_COMPLEX: return(make_complex(sc, real_part(x) + real_part(y), imag_part(x) + imag_part(y)));
  14661. default:
  14662. method_or_bust_with_type(sc, y, sc->add_symbol, args, a_number_string, 2);
  14663. }
  14664. default:
  14665. method_or_bust_with_type(sc, x, sc->add_symbol, args, a_number_string, 1);
  14666. }
  14667. return(x);
  14668. }
  14669. static s7_pointer g_add_s1_1(s7_scheme *sc, s7_pointer x, s7_pointer args)
  14670. {
  14671. switch (type(x))
  14672. {
  14673. #if HAVE_OVERFLOW_CHECKS
  14674. case T_INTEGER:
  14675. {
  14676. s7_int val;
  14677. if (add_overflow(integer(x), 1, &val))
  14678. return(make_real(sc, (double)integer(x) + 1.0));
  14679. return(make_integer(sc, val));
  14680. }
  14681. #else
  14682. case T_INTEGER: return(make_integer(sc, integer(x) + 1));
  14683. #endif
  14684. case T_RATIO: return(add_ratios(sc, x, small_int(1)));
  14685. case T_REAL: return(make_real(sc, real(x) + 1.0));
  14686. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) + 1.0, imag_part(x)));
  14687. default:
  14688. method_or_bust_with_type(sc, x, sc->add_symbol, cons(sc, x, cdr(args)), a_number_string, 1);
  14689. }
  14690. return(x);
  14691. }
  14692. static s7_pointer g_add_s1(s7_scheme *sc, s7_pointer args)
  14693. {
  14694. s7_pointer x;
  14695. x = car(args);
  14696. if (is_t_integer(x))
  14697. return(make_integer(sc, integer(x) + 1));
  14698. return(g_add_s1_1(sc, x, args));
  14699. }
  14700. static s7_pointer c_add_s1(s7_scheme *sc, s7_pointer x)
  14701. {
  14702. if (is_t_integer(x))
  14703. return(make_integer(sc, integer(x) + 1));
  14704. return(g_add_s1_1(sc, x, set_plist_1(sc, x)));
  14705. }
  14706. static s7_pointer g_add_cs1(s7_scheme *sc, s7_pointer args)
  14707. {
  14708. s7_pointer x;
  14709. x = find_symbol_checked(sc, car(args));
  14710. if (is_integer(x))
  14711. return(make_integer(sc, integer(x) + 1));
  14712. return(g_add_s1_1(sc, x, args));
  14713. }
  14714. static s7_pointer g_add_1s(s7_scheme *sc, s7_pointer args)
  14715. {
  14716. s7_pointer x;
  14717. x = cadr(args);
  14718. if (is_integer(x))
  14719. return(make_integer(sc, integer(x) + 1));
  14720. switch (type(x))
  14721. {
  14722. case T_INTEGER: return(make_integer(sc, integer(x) + 1));
  14723. case T_RATIO: return(add_ratios(sc, x, small_int(1)));
  14724. case T_REAL: return(make_real(sc, real(x) + 1.0));
  14725. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) + 1.0, imag_part(x)));
  14726. default:
  14727. method_or_bust_with_type(sc, x, sc->add_symbol, args, a_number_string, 2);
  14728. }
  14729. return(x);
  14730. }
  14731. static s7_pointer g_add_si(s7_scheme *sc, s7_pointer args)
  14732. {
  14733. s7_pointer x;
  14734. s7_int n;
  14735. x = find_symbol_checked(sc, car(args));
  14736. n = integer(cadr(args));
  14737. if (is_integer(x))
  14738. #if HAVE_OVERFLOW_CHECKS
  14739. {
  14740. s7_int val;
  14741. if (add_overflow(integer(x), n, &val))
  14742. return(make_real(sc, (double)integer(x) + (double)n));
  14743. return(make_integer(sc, val));
  14744. }
  14745. #else
  14746. return(make_integer(sc, integer(x) + n));
  14747. #endif
  14748. switch (type(x))
  14749. {
  14750. case T_INTEGER: return(make_integer(sc, integer(x) + n));
  14751. case T_RATIO: return(add_ratios(sc, x, cadr(args)));
  14752. case T_REAL: return(make_real(sc, real(x) + n));
  14753. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) + n, imag_part(x)));
  14754. default:
  14755. method_or_bust_with_type(sc, x, sc->add_symbol, list_2(sc, x, cadr(args)), a_number_string, 1);
  14756. }
  14757. return(x);
  14758. }
  14759. static s7_pointer g_add_sf(s7_scheme *sc, s7_pointer args)
  14760. {
  14761. s7_pointer x;
  14762. s7_double n;
  14763. x = find_symbol_checked(sc, car(args));
  14764. n = real(cadr(args));
  14765. switch (type(x))
  14766. {
  14767. case T_INTEGER: return(make_real(sc, integer(x) + n));
  14768. case T_RATIO: return(make_real(sc, fraction(x) + n));
  14769. case T_REAL: return(make_real(sc, real(x) + n));
  14770. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) + n, imag_part(x)));
  14771. default:
  14772. method_or_bust_with_type(sc, x, sc->add_symbol, list_2(sc, x, cadr(args)), a_number_string, 1);
  14773. }
  14774. return(x);
  14775. }
  14776. static s7_pointer g_add_fs(s7_scheme *sc, s7_pointer args)
  14777. {
  14778. s7_pointer x;
  14779. s7_double n;
  14780. x = find_symbol_checked(sc, cadr(args));
  14781. n = real(car(args));
  14782. switch (type(x))
  14783. {
  14784. case T_INTEGER: return(make_real(sc, integer(x) + n));
  14785. case T_RATIO: return(make_real(sc, fraction(x) + n));
  14786. case T_REAL: return(make_real(sc, real(x) + n));
  14787. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) + n, imag_part(x)));
  14788. default:
  14789. method_or_bust_with_type(sc, x, sc->add_symbol, list_2(sc, x, car(args)), a_number_string, 2);
  14790. }
  14791. return(x);
  14792. }
  14793. static s7_pointer add_f_sf;
  14794. static s7_pointer g_add_f_sf(s7_scheme *sc, s7_pointer args)
  14795. {
  14796. /* (+ x (* s y)) */
  14797. s7_pointer vargs, s;
  14798. s7_double x, y;
  14799. x = real(car(args));
  14800. vargs = cdadr(args);
  14801. s = find_symbol_checked(sc, car(vargs));
  14802. y = real(cadr(vargs));
  14803. if (is_t_real(s))
  14804. return(make_real(sc, x + (real(s) * y)));
  14805. switch (type(s))
  14806. {
  14807. case T_INTEGER: return(make_real(sc, x + (integer(s) * y)));
  14808. case T_RATIO: return(make_real(sc, x + (fraction(s) * y)));
  14809. case T_REAL: return(make_real(sc, x + real(s) * y));
  14810. case T_COMPLEX: return(s7_make_complex(sc, x + (real_part(s) * y), imag_part(s) * y));
  14811. default:
  14812. {
  14813. s7_pointer func;
  14814. if ((func = find_method(sc, find_let(sc, s), sc->multiply_symbol)) != sc->undefined)
  14815. return(g_add_2(sc, set_plist_2(sc, car(args), s7_apply_function(sc, func, list_2(sc, s, cadr(vargs))))));
  14816. return(wrong_type_argument_with_type(sc, sc->multiply_symbol, 1, s, a_number_string));
  14817. }
  14818. }
  14819. return(s);
  14820. }
  14821. static s7_pointer add_ss_1ss_1(s7_scheme *sc, s7_pointer s1, s7_pointer s2, s7_pointer s3)
  14822. {
  14823. s7_double r1, r2, r3, loc, i1, i2, i3, is1;
  14824. if ((is_t_real(s1)) &&
  14825. (is_t_real(s2)) &&
  14826. (is_t_real(s3)))
  14827. return(make_real(sc, (real(s1) * real(s2)) + ((1.0 - real(s1)) * real(s3))));
  14828. if ((is_real(s1)) &&
  14829. (is_real(s2)) &&
  14830. (is_real(s3)))
  14831. {
  14832. r1 = real_to_double(sc, s1, "*");
  14833. r2 = real_to_double(sc, s2, "*");
  14834. r3 = real_to_double(sc, s3, "*");
  14835. return(make_real(sc, (r1 * r2) + ((1.0 - r1) * r3)));
  14836. }
  14837. r1 = s7_real_part(s1);
  14838. loc = 1.0 - r1;
  14839. r2 = s7_real_part(s2);
  14840. r3 = s7_real_part(s3);
  14841. i1 = s7_imag_part(s1);
  14842. is1 = -i1;
  14843. i2 = s7_imag_part(s2);
  14844. i3 = s7_imag_part(s3);
  14845. return(s7_make_complex(sc,
  14846. (r1 * r2 - i1 * i2) + (loc * r3 - is1 * i3),
  14847. (r1 * i2 + r2 * i1) + (loc * i3 + r3 * is1)));
  14848. /* (let ()
  14849. * (define (hi a b c) (+ (* a b) (* (- 1.0 a) c)))
  14850. * (define (hi1 a b c) (+ (* b a) (* c (- 1 a))))
  14851. * (define (ho a b c) (list (hi a b c) (hi1 a b c)))
  14852. * (ho 1.4 2.5+i 3.1))
  14853. */
  14854. }
  14855. static s7_pointer add_ss_1ss;
  14856. static s7_pointer g_add_ss_1ss(s7_scheme *sc, s7_pointer args)
  14857. {
  14858. /* (+ (* s1 s2) (* (- 1.0 s1) s3)) */
  14859. s7_pointer s1, s2, s3;
  14860. s1 = find_symbol_checked(sc, cadr(car(args)));
  14861. s2 = find_symbol_checked(sc, opt_sym1(args)); /* caddr(car(args))) */
  14862. s3 = find_symbol_checked(sc, opt_sym2(args)); /* caddr(cadr(args))) */
  14863. return(add_ss_1ss_1(sc, s1, s2, s3));
  14864. }
  14865. #if (!WITH_GMP)
  14866. static s7_double add_rf_xx(s7_scheme *sc, s7_pointer **p)
  14867. {
  14868. s7_rf_t r1, r2;
  14869. s7_double x, y;
  14870. r1 = (s7_rf_t)(**p); (*p)++;
  14871. x = r1(sc, p);
  14872. r2 = (s7_rf_t)(**p); (*p)++;
  14873. y = r2(sc, p);
  14874. return(x + y);
  14875. }
  14876. static s7_double add_rf_rx(s7_scheme *sc, s7_pointer **p)
  14877. {
  14878. s7_pointer s1;
  14879. s7_rf_t r1;
  14880. s1 = **p; (*p)++;
  14881. r1 = (s7_rf_t)(**p); (*p)++;
  14882. return(r1(sc, p) + real_to_double(sc, s1, "+"));
  14883. }
  14884. static s7_double add_rf_sx(s7_scheme *sc, s7_pointer **p)
  14885. {
  14886. s7_pointer s1;
  14887. s7_rf_t r1;
  14888. s1 = slot_value(**p); (*p)++;
  14889. r1 = (s7_rf_t)(**p); (*p)++;
  14890. return(r1(sc, p) + real_to_double(sc, s1, "+"));
  14891. }
  14892. static s7_double add_rf_ss(s7_scheme *sc, s7_pointer **p)
  14893. {
  14894. s7_pointer s1, s2;
  14895. s7_double x1;
  14896. s1 = slot_value(**p); (*p)++;
  14897. x1 = real_to_double(sc, s1, "+");
  14898. s2 = slot_value(**p); (*p)++;
  14899. return(x1 + real_to_double(sc, s2, "+"));
  14900. }
  14901. static s7_double add_rf_rs(s7_scheme *sc, s7_pointer **p)
  14902. {
  14903. s7_pointer c1, s1;
  14904. s7_double x1;
  14905. s1 = slot_value(**p); (*p)++;
  14906. c1 = **p; (*p)++;
  14907. x1 = real_to_double(sc, c1, "+");
  14908. return(x1 + real_to_double(sc, s1, "+"));
  14909. }
  14910. static s7_double add_rf_xxx(s7_scheme *sc, s7_pointer **p)
  14911. {
  14912. s7_rf_t r1, r2, r3;
  14913. s7_double x, y, z;
  14914. r1 = (s7_rf_t)(**p); (*p)++;
  14915. x = r1(sc, p);
  14916. r2 = (s7_rf_t)(**p); (*p)++;
  14917. y = r2(sc, p);
  14918. r3 = (s7_rf_t)(**p); (*p)++;
  14919. z = r3(sc, p);
  14920. return(x + y + z);
  14921. }
  14922. static s7_double add_rf_rxx(s7_scheme *sc, s7_pointer **p)
  14923. {
  14924. s7_pointer c1;
  14925. s7_rf_t r1, r2;
  14926. s7_double x, y;
  14927. c1 = **p; (*p)++;
  14928. r1 = (s7_rf_t)(**p); (*p)++;
  14929. x = r1(sc, p);
  14930. r2 = (s7_rf_t)(**p); (*p)++;
  14931. y = r2(sc, p);
  14932. return(x + y + real_to_double(sc, c1, "+"));
  14933. }
  14934. static s7_double add_rf_sxx(s7_scheme *sc, s7_pointer **p)
  14935. {
  14936. s7_pointer s1;
  14937. s7_rf_t r1, r2;
  14938. s7_double x, y;
  14939. s1 = slot_value(**p); (*p)++;
  14940. r1 = (s7_rf_t)(**p); (*p)++;
  14941. x = r1(sc, p);
  14942. r2 = (s7_rf_t)(**p); (*p)++;
  14943. y = r2(sc, p);
  14944. return(x + y + real_to_double(sc, s1, "+"));
  14945. }
  14946. static s7_double add_rf_rsx(s7_scheme *sc, s7_pointer **p)
  14947. {
  14948. s7_pointer c1, s1;
  14949. s7_rf_t r1;
  14950. s7_double x, x1, x2;
  14951. s1 = slot_value(**p); (*p)++;
  14952. x2 = real_to_double(sc, s1, "+");
  14953. c1 = **p; (*p)++;
  14954. x1 = real_to_double(sc, c1, "+");
  14955. r1 = (s7_rf_t)(**p); (*p)++;
  14956. x = r1(sc, p);
  14957. return(x + x1 + x2);
  14958. }
  14959. static s7_double add_rf_ssx(s7_scheme *sc, s7_pointer **p)
  14960. {
  14961. s7_pointer s1, s2;
  14962. s7_rf_t r1;
  14963. s7_double x, x1;
  14964. s1 = slot_value(**p); (*p)++;
  14965. x1 = real_to_double(sc, s1, "+");
  14966. s2 = slot_value(**p); (*p)++;
  14967. r1 = (s7_rf_t)(**p); (*p)++;
  14968. x = r1(sc, p);
  14969. return(x + x1 + real_to_double(sc, s2, "+"));
  14970. }
  14971. static s7_double add_rf_sss(s7_scheme *sc, s7_pointer **p)
  14972. {
  14973. s7_pointer s1, s2, s3;
  14974. s7_double x1, x2;
  14975. s1 = slot_value(**p); (*p)++;
  14976. x1 = real_to_double(sc, s1, "+");
  14977. s2 = slot_value(**p); (*p)++;
  14978. x2 = real_to_double(sc, s2, "+");
  14979. s3 = slot_value(**p); (*p)++;
  14980. return(x1 + x2 + real_to_double(sc, s3, "+"));
  14981. }
  14982. static s7_double add_rf_rss(s7_scheme *sc, s7_pointer **p)
  14983. {
  14984. s7_pointer c1, s1, s2;
  14985. s7_double x1, x2;
  14986. s1 = slot_value(**p); (*p)++;
  14987. x1 = real_to_double(sc, s1, "+");
  14988. s2 = slot_value(**p); (*p)++;
  14989. x2 = real_to_double(sc, s2, "+");
  14990. c1 = **p; (*p)++;
  14991. return(real_to_double(sc, c1, "+") + x1 + x2);
  14992. }
  14993. static s7_rf_t add_rf_1(s7_scheme *sc, s7_pointer expr, int len)
  14994. {
  14995. if (len == 3)
  14996. return(com_rf_2(sc, expr, add_r_ops));
  14997. if (len == 4)
  14998. return(com_rf_3(sc, expr, add_r_ops));
  14999. if (len > 4)
  15000. {
  15001. s7_rf_t rf;
  15002. ptr_int loc;
  15003. int first_len;
  15004. xf_t *rc;
  15005. first_len = (int)(len / 2);
  15006. xf_init(2);
  15007. xf_save_loc(loc);
  15008. rf = add_rf_1(sc, expr, first_len + 1);
  15009. if (rf)
  15010. {
  15011. int i;
  15012. s7_pointer p;
  15013. xf_store_at(loc, (s7_pointer)rf);
  15014. xf_save_loc(loc);
  15015. for (i = 0, p = expr; i < first_len; i++, p = cdr(p));
  15016. rf = add_rf_1(sc, p, len - first_len);
  15017. if (rf)
  15018. {
  15019. xf_store_at(loc, (s7_pointer)rf);
  15020. return(add_rf_xx);
  15021. }
  15022. else return(NULL);
  15023. }
  15024. else return(NULL);
  15025. }
  15026. return(NULL);
  15027. }
  15028. static s7_rf_t add_rf(s7_scheme *sc, s7_pointer expr)
  15029. {
  15030. return(add_rf_1(sc, expr, s7_list_length(sc, expr)));
  15031. }
  15032. static s7_int add_if_xx(s7_scheme *sc, s7_pointer **p)
  15033. {
  15034. s7_if_t r1, r2;
  15035. s7_int x, y;
  15036. r1 = (s7_if_t)(**p); (*p)++;
  15037. x = r1(sc, p);
  15038. r2 = (s7_if_t)(**p); (*p)++;
  15039. y = r2(sc, p);
  15040. return(x + y);
  15041. }
  15042. static s7_int add_if_rx(s7_scheme *sc, s7_pointer **p)
  15043. {
  15044. s7_pointer s1;
  15045. s7_if_t r1;
  15046. s1 = **p; (*p)++;
  15047. r1 = (s7_if_t)(**p); (*p)++;
  15048. return(r1(sc, p) + integer(s1));
  15049. }
  15050. static s7_int add_if_sx(s7_scheme *sc, s7_pointer **p)
  15051. {
  15052. s7_pointer s1;
  15053. s7_if_t r1;
  15054. s1 = slot_value(**p); (*p)++;
  15055. r1 = (s7_if_t)(**p); (*p)++;
  15056. return(r1(sc, p) + integer(s1));
  15057. }
  15058. static s7_int add_if_ss(s7_scheme *sc, s7_pointer **p)
  15059. {
  15060. s7_pointer s1, s2;
  15061. s1 = slot_value(**p); (*p)++;
  15062. s2 = slot_value(**p); (*p)++;
  15063. return(integer(s1) + integer(s2));
  15064. }
  15065. static s7_int add_if_rs(s7_scheme *sc, s7_pointer **p)
  15066. {
  15067. s7_pointer c1, s1;
  15068. s1 = slot_value(**p); (*p)++;
  15069. c1 = **p; (*p)++;
  15070. return(integer(c1) + integer(s1));
  15071. }
  15072. static s7_int add_if_xxx(s7_scheme *sc, s7_pointer **p)
  15073. {
  15074. s7_if_t r1, r2, r3;
  15075. s7_int x, y, z;
  15076. r1 = (s7_if_t)(**p); (*p)++;
  15077. x = r1(sc, p);
  15078. r2 = (s7_if_t)(**p); (*p)++;
  15079. y = r2(sc, p);
  15080. r3 = (s7_if_t)(**p); (*p)++;
  15081. z = r3(sc, p);
  15082. return(x + y + z);
  15083. }
  15084. static s7_int add_if_rxx(s7_scheme *sc, s7_pointer **p)
  15085. {
  15086. s7_pointer c1;
  15087. s7_if_t r1, r2;
  15088. s7_int x, y;
  15089. c1 = **p; (*p)++;
  15090. r1 = (s7_if_t)(**p); (*p)++;
  15091. x = r1(sc, p);
  15092. r2 = (s7_if_t)(**p); (*p)++;
  15093. y = r2(sc, p);
  15094. return(x + y + integer(c1));
  15095. }
  15096. static s7_int add_if_sxx(s7_scheme *sc, s7_pointer **p)
  15097. {
  15098. s7_pointer s1;
  15099. s7_if_t r1, r2;
  15100. s7_int x, y;
  15101. s1 = slot_value(**p); (*p)++;
  15102. r1 = (s7_if_t)(**p); (*p)++;
  15103. x = r1(sc, p);
  15104. r2 = (s7_if_t)(**p); (*p)++;
  15105. y = r2(sc, p);
  15106. return(x + y + integer(s1));
  15107. }
  15108. static s7_int add_if_rsx(s7_scheme *sc, s7_pointer **p)
  15109. {
  15110. s7_pointer c1, s1;
  15111. s7_if_t r1;
  15112. s7_int x;
  15113. s1 = slot_value(**p); (*p)++;
  15114. c1 = **p; (*p)++;
  15115. r1 = (s7_if_t)(**p); (*p)++;
  15116. x = r1(sc, p);
  15117. return(x + integer(c1) + integer(s1));
  15118. }
  15119. static s7_int add_if_ssx(s7_scheme *sc, s7_pointer **p)
  15120. {
  15121. s7_pointer s1, s2;
  15122. s7_if_t r1;
  15123. s7_int x;
  15124. s1 = slot_value(**p); (*p)++;
  15125. s2 = slot_value(**p); (*p)++;
  15126. r1 = (s7_if_t)(**p); (*p)++;
  15127. x = r1(sc, p);
  15128. return(x + integer(s1) + integer(s2));
  15129. }
  15130. static s7_int add_if_sss(s7_scheme *sc, s7_pointer **p)
  15131. {
  15132. s7_pointer s1, s2, s3;
  15133. s1 = slot_value(**p); (*p)++;
  15134. s2 = slot_value(**p); (*p)++;
  15135. s3 = slot_value(**p); (*p)++;
  15136. return(integer(s1) + integer(s2) + integer(s3));
  15137. }
  15138. static s7_int add_if_rss(s7_scheme *sc, s7_pointer **p)
  15139. {
  15140. s7_pointer c1, s1, s2;
  15141. s1 = slot_value(**p); (*p)++;
  15142. s2 = slot_value(**p); (*p)++;
  15143. c1 = **p; (*p)++;
  15144. return(integer(c1) + integer(s1) + integer(s2));
  15145. }
  15146. static s7_if_t add_if_1(s7_scheme *sc, s7_pointer expr, int len)
  15147. {
  15148. if (len == 3)
  15149. return(com_if_2(sc, expr, add_i_ops));
  15150. if (len == 4)
  15151. return(com_if_3(sc, expr, add_i_ops));
  15152. if (len > 4)
  15153. {
  15154. s7_if_t xf;
  15155. ptr_int loc;
  15156. int first_len;
  15157. xf_t *rc;
  15158. xf_init(2);
  15159. xf_save_loc(loc);
  15160. first_len = (int)(len / 2);
  15161. xf = add_if_1(sc, expr, first_len + 1);
  15162. if (xf)
  15163. {
  15164. int i;
  15165. s7_pointer p;
  15166. xf_store_at(loc, (s7_pointer)xf);
  15167. xf_save_loc(loc);
  15168. for (i = 0, p = expr; i < first_len; i++, p = cdr(p));
  15169. xf = add_if_1(sc, p, len - first_len);
  15170. if (xf)
  15171. {
  15172. xf_store_at(loc, (s7_pointer)xf);
  15173. return(add_if_xx);
  15174. }
  15175. else return(NULL);
  15176. }
  15177. else return(NULL);
  15178. }
  15179. return(NULL);
  15180. }
  15181. static s7_if_t add_if(s7_scheme *sc, s7_pointer expr)
  15182. {
  15183. return(add_if_1(sc, expr, s7_list_length(sc, expr)));
  15184. }
  15185. static void init_add_ops(void)
  15186. {
  15187. add_r_ops = (rf_ops *)calloc(1, sizeof(rf_ops));
  15188. add_r_ops->r = rf_c;
  15189. add_r_ops->s = rf_s;
  15190. add_r_ops->rs = add_rf_rs;
  15191. add_r_ops->rp = add_rf_rx;
  15192. add_r_ops->sp = add_rf_sx;
  15193. add_r_ops->ss = add_rf_ss;
  15194. add_r_ops->pp = add_rf_xx;
  15195. add_r_ops->rss = add_rf_rss;
  15196. add_r_ops->rsp = add_rf_rsx;
  15197. add_r_ops->rpp = add_rf_rxx;
  15198. add_r_ops->sss = add_rf_sss;
  15199. add_r_ops->ssp = add_rf_ssx;
  15200. add_r_ops->spp = add_rf_sxx;
  15201. add_r_ops->ppp = add_rf_xxx;
  15202. add_i_ops = (if_ops *)calloc(1, sizeof(if_ops));
  15203. add_i_ops->r = if_c;
  15204. add_i_ops->s = if_s;
  15205. add_i_ops->rs = add_if_rs;
  15206. add_i_ops->rp = add_if_rx;
  15207. add_i_ops->sp = add_if_sx;
  15208. add_i_ops->ss = add_if_ss;
  15209. add_i_ops->pp = add_if_xx;
  15210. add_i_ops->rss = add_if_rss;
  15211. add_i_ops->rsp = add_if_rsx;
  15212. add_i_ops->rpp = add_if_rxx;
  15213. add_i_ops->sss = add_if_sss;
  15214. add_i_ops->ssp = add_if_ssx;
  15215. add_i_ops->spp = add_if_sxx;
  15216. add_i_ops->ppp = add_if_xxx;
  15217. }
  15218. #if WITH_ADD_PF
  15219. static s7_pointer c_add_pf2(s7_scheme *sc, s7_pointer **p)
  15220. {
  15221. s7_pf_t pf;
  15222. s7_pointer x, y;
  15223. pf = (s7_pf_t)(**p); (*p)++;
  15224. x = pf(sc, p);
  15225. xf_push(sc, x);
  15226. pf = (s7_pf_t)(**p); (*p)++;
  15227. y = pf(sc, p);
  15228. x = g_add_2(sc, set_plist_2(sc, x, y));
  15229. xf_pop(sc);
  15230. return(x);
  15231. }
  15232. static s7_pf_t add_pf(s7_scheme *sc, s7_pointer expr)
  15233. {
  15234. int len;
  15235. len = s7_list_length(sc, expr);
  15236. if (len == 3)
  15237. {
  15238. if ((s7_arg_to_pf(sc, cadr(expr))) &&
  15239. (s7_arg_to_pf(sc, caddr(expr))))
  15240. return(c_add_pf2);
  15241. }
  15242. return(NULL);
  15243. }
  15244. #endif
  15245. #endif
  15246. /* ---------------------------------------- subtract ---------------------------------------- */
  15247. static s7_pointer g_subtract(s7_scheme *sc, s7_pointer args)
  15248. {
  15249. #define H_subtract "(- x1 ...) subtracts its trailing arguments from the first, or negates the first if only one it is given"
  15250. #define Q_subtract pcl_n
  15251. s7_pointer x, p;
  15252. s7_int num_a, den_a;
  15253. s7_double rl_a, im_a;
  15254. x = car(args);
  15255. p = cdr(args);
  15256. #if (!WITH_GMP)
  15257. if (is_null(p))
  15258. {
  15259. if (!is_number(x))
  15260. method_or_bust_with_type(sc, x, sc->subtract_symbol, args, a_number_string, 0);
  15261. return(s7_negate(sc, x));
  15262. }
  15263. #endif
  15264. switch (type(x))
  15265. {
  15266. case T_INTEGER:
  15267. num_a = integer(x);
  15268. SUBTRACT_INTEGERS:
  15269. #if WITH_GMP
  15270. if ((num_a > s7_int32_max) ||
  15271. (num_a < s7_int32_min))
  15272. return(big_subtract(sc, cons(sc, s7_int_to_big_integer(sc, num_a), p)));
  15273. #endif
  15274. x = car(p);
  15275. p = cdr(p);
  15276. switch (type(x))
  15277. {
  15278. case T_INTEGER:
  15279. #if HAVE_OVERFLOW_CHECKS
  15280. if (subtract_overflow(num_a, integer(x), &den_a))
  15281. {
  15282. rl_a = (s7_double)num_a - (s7_double)integer(x);
  15283. if (is_null(p)) return(make_real(sc, rl_a));
  15284. goto SUBTRACT_REALS;
  15285. }
  15286. #else
  15287. den_a = num_a - integer(x);
  15288. if (den_a < 0)
  15289. {
  15290. if ((num_a > 0) && (integer(x) < 0))
  15291. {
  15292. rl_a = (s7_double)num_a - (s7_double)integer(x);
  15293. if (is_null(p)) return(make_real(sc, rl_a));
  15294. goto SUBTRACT_REALS;
  15295. }
  15296. /* (- most-positive-fixnum most-negative-fixnum) -> -1 (1.8446744073709551615E19)
  15297. */
  15298. }
  15299. else
  15300. {
  15301. if ((num_a < 0) && (integer(x) > 0))
  15302. {
  15303. rl_a = (s7_double)num_a - (s7_double)integer(x);
  15304. if (is_null(p)) return(make_real(sc, rl_a));
  15305. goto SUBTRACT_REALS;
  15306. }
  15307. /* (- most-negative-fixnum most-positive-fixnum) -> 1 (-1.8446744073709551615E19)
  15308. */
  15309. }
  15310. #endif
  15311. if (is_null(p)) return(make_integer(sc, den_a));
  15312. num_a = den_a;
  15313. goto SUBTRACT_INTEGERS;
  15314. case T_RATIO:
  15315. {
  15316. s7_int dn;
  15317. den_a = denominator(x);
  15318. #if HAVE_OVERFLOW_CHECKS
  15319. if ((multiply_overflow(num_a, den_a, &dn)) ||
  15320. (subtract_overflow(dn, numerator(x), &dn)))
  15321. {
  15322. if (is_null(p)) return(make_real(sc, num_a - fraction(x)));
  15323. rl_a = (s7_double)num_a - fraction(x);
  15324. goto SUBTRACT_REALS;
  15325. }
  15326. #else
  15327. if ((integer_length(num_a) + integer_length(den_a) + integer_length(numerator(x))) > s7_int_bits)
  15328. {
  15329. if (is_null(p)) return(make_real(sc, num_a - fraction(x)));
  15330. rl_a = (s7_double)num_a - fraction(x);
  15331. goto SUBTRACT_REALS;
  15332. }
  15333. dn = (num_a * den_a) - numerator(x);
  15334. #endif
  15335. if (is_null(p)) return(s7_make_ratio(sc, dn, den_a));
  15336. num_a = dn;
  15337. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  15338. goto SUBTRACT_INTEGERS;
  15339. goto SUBTRACT_RATIOS;
  15340. }
  15341. case T_REAL:
  15342. if (is_null(p)) return(make_real(sc, num_a - real(x)));
  15343. rl_a = (s7_double)num_a - real(x);
  15344. goto SUBTRACT_REALS;
  15345. case T_COMPLEX:
  15346. if (is_null(p)) return(s7_make_complex(sc, num_a - real_part(x), -imag_part(x)));
  15347. rl_a = (s7_double)num_a - real_part(x);
  15348. im_a = -imag_part(x);
  15349. goto SUBTRACT_COMPLEX;
  15350. default:
  15351. method_or_bust_with_type(sc, x, sc->subtract_symbol, cons(sc, s7_make_integer(sc, num_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  15352. }
  15353. break;
  15354. case T_RATIO:
  15355. num_a = numerator(x);
  15356. den_a = denominator(x);
  15357. SUBTRACT_RATIOS:
  15358. #if WITH_GMP
  15359. if ((num_a > s7_int32_max) ||
  15360. (den_a > s7_int32_max) ||
  15361. (num_a < s7_int32_min))
  15362. return(big_subtract(sc, cons(sc, s7_ratio_to_big_ratio(sc, num_a, den_a), p)));
  15363. #endif
  15364. x = car(p);
  15365. p = cdr(p);
  15366. switch (type(x))
  15367. {
  15368. case T_INTEGER:
  15369. #if HAVE_OVERFLOW_CHECKS
  15370. {
  15371. s7_int di;
  15372. if ((multiply_overflow(den_a, integer(x), &di)) ||
  15373. (subtract_overflow(num_a, di, &di)))
  15374. {
  15375. if (is_null(p)) return(make_real(sc, ((long double)num_a / (long double)den_a) - integer(x)));
  15376. rl_a = ((long double)num_a / (long double)den_a) - integer(x);
  15377. goto SUBTRACT_REALS;
  15378. }
  15379. if (is_null(p)) return(s7_make_ratio(sc, di, den_a));
  15380. num_a = di;
  15381. }
  15382. #else
  15383. if ((integer_length(integer(x)) + integer_length(num_a) + integer_length(den_a)) > s7_int_bits)
  15384. {
  15385. if (is_null(p)) return(make_real(sc, ((long double)num_a / (long double)den_a) - integer(x)));
  15386. rl_a = ((long double)num_a / (long double)den_a) - integer(x);
  15387. goto SUBTRACT_REALS;
  15388. }
  15389. if (is_null(p)) return(s7_make_ratio(sc, num_a - (den_a * integer(x)), den_a));
  15390. num_a -= (den_a * integer(x));
  15391. #endif
  15392. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  15393. goto SUBTRACT_INTEGERS;
  15394. goto SUBTRACT_RATIOS;
  15395. case T_RATIO:
  15396. {
  15397. s7_int d1, d2, n1, n2;
  15398. d1 = den_a;
  15399. n1 = num_a;
  15400. d2 = denominator(x);
  15401. n2 = numerator(x);
  15402. if (d1 == d2) /* the easy case -- if overflow here, it matches the int case */
  15403. {
  15404. if (is_null(p))
  15405. return(s7_make_ratio(sc, n1 - n2, d1));
  15406. num_a -= n2; /* d1 can't be zero */
  15407. }
  15408. else
  15409. {
  15410. #if (!WITH_GMP)
  15411. #if HAVE_OVERFLOW_CHECKS
  15412. s7_int n1d2, n2d1;
  15413. if ((multiply_overflow(d1, d2, &den_a)) ||
  15414. (multiply_overflow(n1, d2, &n1d2)) ||
  15415. (multiply_overflow(n2, d1, &n2d1)) ||
  15416. (subtract_overflow(n1d2, n2d1, &num_a)))
  15417. {
  15418. if (is_null(p))
  15419. return(make_real(sc, ((long double)n1 / (long double)d1) - ((long double)n2 / (long double)d2)));
  15420. rl_a = ((long double)n1 / (long double)d1) - ((long double)n2 / (long double)d2);
  15421. goto SUBTRACT_REALS;
  15422. }
  15423. #else
  15424. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  15425. (n1 > s7_int32_max) || (n2 > s7_int32_max) ||
  15426. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  15427. {
  15428. int d1bits, d2bits;
  15429. d1bits = integer_length(d1);
  15430. d2bits = integer_length(d2);
  15431. if (((d1bits + d2bits) > s7_int_bits) ||
  15432. ((d1bits + integer_length(n2)) > (s7_int_bits - 1)) ||
  15433. ((d2bits + integer_length(n1)) > (s7_int_bits - 1)))
  15434. {
  15435. if (is_null(p))
  15436. return(make_real(sc, ((long double)n1 / (long double)d1) - ((long double)n2 / (long double)d2)));
  15437. rl_a = ((long double)n1 / (long double)d1) - ((long double)n2 / (long double)d2);
  15438. goto SUBTRACT_REALS;
  15439. }
  15440. }
  15441. num_a = n1 * d2 - n2 * d1;
  15442. den_a = d1 * d2;
  15443. #endif
  15444. #else
  15445. num_a = n1 * d2 - n2 * d1;
  15446. den_a = d1 * d2;
  15447. #endif
  15448. if (is_null(p))
  15449. return(s7_make_ratio(sc, num_a, den_a));
  15450. }
  15451. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  15452. goto SUBTRACT_INTEGERS;
  15453. goto SUBTRACT_RATIOS;
  15454. }
  15455. case T_REAL:
  15456. if (is_null(p)) return(make_real(sc, ((long double)num_a / (long double)den_a) - real(x)));
  15457. rl_a = ((long double)num_a / (long double)den_a) - real(x);
  15458. goto SUBTRACT_REALS;
  15459. case T_COMPLEX:
  15460. if (is_null(p)) return(s7_make_complex(sc, ((long double)num_a / (long double)den_a) - real_part(x), -imag_part(x)));
  15461. rl_a = ((long double)num_a / (long double)den_a) - real_part(x);
  15462. im_a = -imag_part(x);
  15463. goto SUBTRACT_COMPLEX;
  15464. default:
  15465. method_or_bust_with_type(sc, x, sc->subtract_symbol, cons(sc, s7_make_ratio(sc, num_a, den_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  15466. }
  15467. break;
  15468. case T_REAL:
  15469. rl_a = real(x);
  15470. SUBTRACT_REALS:
  15471. x = car(p);
  15472. p = cdr(p);
  15473. switch (type(x))
  15474. {
  15475. case T_INTEGER:
  15476. if (is_null(p)) return(make_real(sc, rl_a - integer(x)));
  15477. rl_a -= (s7_double)integer(x);
  15478. goto SUBTRACT_REALS;
  15479. case T_RATIO:
  15480. if (is_null(p)) return(make_real(sc, rl_a - fraction(x)));
  15481. rl_a -= (s7_double)fraction(x);
  15482. goto SUBTRACT_REALS;
  15483. case T_REAL:
  15484. if (is_null(p)) return(make_real(sc, rl_a - real(x)));
  15485. rl_a -= real(x);
  15486. goto SUBTRACT_REALS;
  15487. case T_COMPLEX:
  15488. if (is_null(p)) return(s7_make_complex(sc, rl_a - real_part(x), -imag_part(x)));
  15489. rl_a -= real_part(x);
  15490. im_a = -imag_part(x);
  15491. goto SUBTRACT_COMPLEX;
  15492. default:
  15493. method_or_bust_with_type(sc, x, sc->subtract_symbol, cons(sc, make_real(sc, rl_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  15494. }
  15495. break;
  15496. case T_COMPLEX:
  15497. rl_a = real_part(x);
  15498. im_a = imag_part(x);
  15499. SUBTRACT_COMPLEX:
  15500. x = car(p);
  15501. p = cdr(p);
  15502. switch (type(x))
  15503. {
  15504. case T_INTEGER:
  15505. if (is_null(p)) return(s7_make_complex(sc, rl_a - integer(x), im_a));
  15506. rl_a -= (s7_double)integer(x);
  15507. goto SUBTRACT_COMPLEX;
  15508. case T_RATIO:
  15509. if (is_null(p)) return(s7_make_complex(sc, rl_a - fraction(x), im_a));
  15510. rl_a -= (s7_double)fraction(x);
  15511. goto SUBTRACT_COMPLEX;
  15512. case T_REAL:
  15513. if (is_null(p)) return(s7_make_complex(sc, rl_a - real(x), im_a));
  15514. rl_a -= real(x);
  15515. goto SUBTRACT_COMPLEX;
  15516. case T_COMPLEX:
  15517. if (is_null(p)) return(s7_make_complex(sc, rl_a - real_part(x), im_a - imag_part(x)));
  15518. rl_a -= real_part(x);
  15519. im_a -= imag_part(x);
  15520. if (im_a == 0.0)
  15521. goto SUBTRACT_REALS;
  15522. goto SUBTRACT_COMPLEX;
  15523. default:
  15524. method_or_bust_with_type(sc, x, sc->subtract_symbol, cons(sc, s7_make_complex(sc, rl_a, im_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  15525. }
  15526. break;
  15527. default:
  15528. method_or_bust_with_type(sc, x, sc->subtract_symbol, args, a_number_string, 1);
  15529. }
  15530. }
  15531. static s7_pointer subtract_1, subtract_s1, subtract_cs1, subtract_2, subtract_csn;
  15532. static s7_pointer g_subtract_1(s7_scheme *sc, s7_pointer args)
  15533. {
  15534. s7_pointer p;
  15535. p = car(args);
  15536. switch (type(p))
  15537. {
  15538. case T_INTEGER:
  15539. if (integer(p) == s7_int_min)
  15540. #if WITH_GMP
  15541. return(big_negate(sc, set_plist_1(sc, promote_number(sc, T_BIG_INTEGER, p))));
  15542. #else
  15543. return(make_integer(sc, s7_int_max));
  15544. #endif
  15545. return(make_integer(sc, -integer(p)));
  15546. case T_RATIO:
  15547. return(s7_make_ratio(sc, -numerator(p), denominator(p)));
  15548. case T_REAL:
  15549. return(make_real(sc, -real(p)));
  15550. case T_COMPLEX:
  15551. return(s7_make_complex(sc, -real_part(p), -imag_part(p)));
  15552. default:
  15553. method_or_bust_with_type(sc, p, sc->subtract_symbol, args, a_number_string, 1);
  15554. }
  15555. }
  15556. static s7_pointer g_subtract_2(s7_scheme *sc, s7_pointer args)
  15557. {
  15558. s7_pointer x, y;
  15559. x = car(args);
  15560. y = cadr(args);
  15561. if (type(x) == type(y))
  15562. {
  15563. if (is_t_real(x))
  15564. return(make_real(sc, real(x) - real(y)));
  15565. else
  15566. {
  15567. switch (type(x))
  15568. {
  15569. #if HAVE_OVERFLOW_CHECKS
  15570. case T_INTEGER:
  15571. {
  15572. s7_int val;
  15573. if (subtract_overflow(integer(x), integer(y), &val))
  15574. return(make_real(sc, (double)integer(x) - (double)integer(y)));
  15575. return(make_integer(sc, val));
  15576. }
  15577. #else
  15578. case T_INTEGER: return(make_integer(sc, integer(x) - integer(y)));
  15579. #endif
  15580. case T_RATIO: return(g_subtract(sc, args));
  15581. case T_REAL: return(make_real(sc, real(x) - real(y)));
  15582. case T_COMPLEX: return(make_complex(sc, real_part(x) - real_part(y), imag_part(x) - imag_part(y)));
  15583. default:
  15584. if (!is_number(x))
  15585. method_or_bust_with_type(sc, x, sc->subtract_symbol, args, a_number_string, 1);
  15586. method_or_bust_with_type(sc, y, sc->subtract_symbol, args, a_number_string, 2);
  15587. }
  15588. }
  15589. }
  15590. switch (type(x))
  15591. {
  15592. case T_INTEGER:
  15593. switch (type(y))
  15594. {
  15595. case T_INTEGER: return(make_integer(sc, integer(x) - integer(y)));
  15596. case T_RATIO: return(g_subtract(sc, args));
  15597. case T_REAL: return(make_real(sc, integer(x) - real(y)));
  15598. case T_COMPLEX: return(make_complex(sc, integer(x) - real_part(y), -imag_part(y)));
  15599. default:
  15600. method_or_bust_with_type(sc, y, sc->subtract_symbol, args, a_number_string, 2);
  15601. }
  15602. case T_RATIO:
  15603. switch (type(y))
  15604. {
  15605. case T_INTEGER:
  15606. case T_RATIO: return(g_subtract(sc, args));
  15607. case T_REAL: return(make_real(sc, fraction(x) - real(y)));
  15608. case T_COMPLEX: return(s7_make_complex(sc, fraction(x) - real_part(y), -imag_part(y)));
  15609. default:
  15610. method_or_bust_with_type(sc, y, sc->subtract_symbol, args, a_number_string, 2);
  15611. }
  15612. case T_REAL:
  15613. switch (type(y))
  15614. {
  15615. case T_INTEGER: return(make_real(sc, real(x) - integer(y)));
  15616. case T_RATIO: return(make_real(sc, real(x) - fraction(y)));
  15617. case T_REAL: return(make_real(sc, real(x) - real(y)));
  15618. case T_COMPLEX: return(make_complex(sc, real(x) - real_part(y), -imag_part(y)));
  15619. default:
  15620. method_or_bust_with_type(sc, y, sc->subtract_symbol, args, a_number_string, 2);
  15621. }
  15622. case T_COMPLEX:
  15623. switch (type(y))
  15624. {
  15625. case T_INTEGER: return(s7_make_complex(sc, real_part(x) - integer(y), imag_part(x)));
  15626. case T_RATIO: return(s7_make_complex(sc, real_part(x) - fraction(y), imag_part(x)));
  15627. case T_REAL: return(s7_make_complex(sc, real_part(x) - real(y), imag_part(x)));
  15628. case T_COMPLEX: return(make_complex(sc, real_part(x) - real_part(y), imag_part(x) - imag_part(y)));
  15629. default:
  15630. method_or_bust_with_type(sc, y, sc->subtract_symbol, args, a_number_string, 2);
  15631. }
  15632. default:
  15633. method_or_bust_with_type(sc, x, sc->subtract_symbol, args, a_number_string, 1);
  15634. }
  15635. return(x);
  15636. }
  15637. static s7_pointer g_subtract_cs1(s7_scheme *sc, s7_pointer args)
  15638. {
  15639. s7_pointer x;
  15640. x = find_symbol_checked(sc, car(args));
  15641. if (is_integer(x))
  15642. return(make_integer(sc, integer(x) - 1));
  15643. switch (type(x))
  15644. {
  15645. #if HAVE_OVERFLOW_CHECKS
  15646. case T_INTEGER:
  15647. {
  15648. s7_int val;
  15649. if (subtract_overflow(integer(x), 1, &val))
  15650. return(make_real(sc, (double)integer(x) - 1.0));
  15651. return(make_integer(sc, val));
  15652. }
  15653. #else
  15654. case T_INTEGER: return(make_integer(sc, integer(x) - 1));
  15655. #endif
  15656. case T_RATIO: return(subtract_ratios(sc, x, small_int(1)));
  15657. case T_REAL: return(make_real(sc, real(x) - 1.0));
  15658. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) - 1.0, imag_part(x)));
  15659. default:
  15660. method_or_bust_with_type(sc, x, sc->subtract_symbol, list_2(sc, x, small_int(1)), a_number_string, 1);
  15661. }
  15662. return(x);
  15663. }
  15664. static s7_pointer g_subtract_s1(s7_scheme *sc, s7_pointer args)
  15665. {
  15666. s7_pointer x;
  15667. x = car(args);
  15668. /* this one seems to hit reals as often as integers */
  15669. switch (type(x))
  15670. {
  15671. #if HAVE_OVERFLOW_CHECKS
  15672. case T_INTEGER:
  15673. {
  15674. s7_int val;
  15675. if (subtract_overflow(integer(x), 1, &val))
  15676. return(make_real(sc, (double)integer(x) - 1.0));
  15677. return(make_integer(sc, val));
  15678. }
  15679. #else
  15680. case T_INTEGER: return(make_integer(sc, integer(x) - 1));
  15681. #endif
  15682. case T_RATIO: return(subtract_ratios(sc, x, small_int(1)));
  15683. case T_REAL: return(make_real(sc, real(x) - 1.0));
  15684. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) - 1.0, imag_part(x)));
  15685. default:
  15686. method_or_bust_with_type(sc, x, sc->subtract_symbol, args, a_number_string, 1);
  15687. }
  15688. return(x);
  15689. }
  15690. static s7_pointer g_subtract_csn(s7_scheme *sc, s7_pointer args)
  15691. {
  15692. s7_pointer x;
  15693. s7_int n;
  15694. x = find_symbol_checked(sc, car(args));
  15695. n = s7_integer(cadr(args));
  15696. if (is_integer(x))
  15697. return(make_integer(sc, integer(x) - n));
  15698. switch (type(x))
  15699. {
  15700. #if HAVE_OVERFLOW_CHECKS
  15701. case T_INTEGER:
  15702. {
  15703. s7_int val;
  15704. if (subtract_overflow(integer(x), n, &val))
  15705. return(make_real(sc, (double)integer(x) - (double)n));
  15706. return(make_integer(sc, val));
  15707. }
  15708. #else
  15709. case T_INTEGER: return(make_integer(sc, integer(x) - n));
  15710. #endif
  15711. case T_RATIO: return(subtract_ratios(sc, x, cadr(args)));
  15712. case T_REAL: return(make_real(sc, real(x) - n));
  15713. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) - n, imag_part(x)));
  15714. default:
  15715. method_or_bust_with_type(sc, x, sc->subtract_symbol, list_2(sc, x, cadr(args)), a_number_string, 1);
  15716. }
  15717. return(x);
  15718. }
  15719. static s7_pointer subtract_sf;
  15720. static s7_pointer g_subtract_sf(s7_scheme *sc, s7_pointer args)
  15721. {
  15722. s7_pointer x;
  15723. s7_double n;
  15724. x = find_symbol_checked(sc, car(args));
  15725. n = real(cadr(args));
  15726. switch (type(x))
  15727. {
  15728. case T_INTEGER: return(make_real(sc, integer(x) - n));
  15729. case T_RATIO: return(make_real(sc, fraction(x) - n));
  15730. case T_REAL: return(make_real(sc, real(x) - n));
  15731. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) - n, imag_part(x)));
  15732. default:
  15733. method_or_bust_with_type(sc, x, sc->subtract_symbol, list_2(sc, x, cadr(args)), a_number_string, 1);
  15734. }
  15735. return(x);
  15736. }
  15737. static s7_pointer subtract_2f;
  15738. static s7_pointer g_subtract_2f(s7_scheme *sc, s7_pointer args)
  15739. {
  15740. s7_pointer x;
  15741. s7_double n;
  15742. x = car(args);
  15743. n = real(cadr(args));
  15744. switch (type(x))
  15745. {
  15746. case T_INTEGER: return(make_real(sc, integer(x) - n));
  15747. case T_RATIO: return(make_real(sc, fraction(x) - n));
  15748. case T_REAL: return(make_real(sc, real(x) - n));
  15749. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) - n, imag_part(x)));
  15750. default:
  15751. method_or_bust_with_type(sc, x, sc->subtract_symbol, args, a_number_string, 1);
  15752. }
  15753. return(x);
  15754. }
  15755. static s7_pointer subtract_fs;
  15756. static s7_pointer g_subtract_fs(s7_scheme *sc, s7_pointer args)
  15757. {
  15758. s7_pointer x;
  15759. s7_double n;
  15760. x = find_symbol_checked(sc, cadr(args));
  15761. n = real(car(args));
  15762. switch (type(x))
  15763. {
  15764. case T_INTEGER: return(make_real(sc, n - integer(x)));
  15765. case T_RATIO: return(make_real(sc, n - fraction(x)));
  15766. case T_REAL: return(make_real(sc, n - real(x)));
  15767. case T_COMPLEX: return(s7_make_complex(sc, n - real_part(x), -imag_part(x)));
  15768. default:
  15769. method_or_bust_with_type(sc, x, sc->subtract_symbol, list_2(sc, car(args), x), a_number_string, 2);
  15770. }
  15771. return(x);
  15772. }
  15773. static s7_pointer subtract_f_sqr;
  15774. static s7_pointer g_subtract_f_sqr(s7_scheme *sc, s7_pointer args)
  15775. {
  15776. s7_pointer x;
  15777. s7_double y;
  15778. y = real(car(args));
  15779. x = find_symbol_checked(sc, cadr(cadr(args)));
  15780. if (is_t_real(x))
  15781. return(make_real(sc, y - (real(x) * real(x))));
  15782. switch (type(x))
  15783. {
  15784. case T_INTEGER: return(make_real(sc, y - (integer(x) * integer(x))));
  15785. case T_RATIO: return(make_real(sc, y - (fraction(x) * fraction(x))));
  15786. case T_REAL: return(make_real(sc, y - (real(x) * real(x))));
  15787. case T_COMPLEX: return(s7_make_complex(sc, y - real_part(x) * real_part(x) + imag_part(x) * imag_part(x), 2.0 * real_part(x) * imag_part(x)));
  15788. default:
  15789. /* complicated -- look for * method, if any get (* x x), then go to g_subtract_2 with that and the original y
  15790. * can't use check_method here because it returns from the caller.
  15791. */
  15792. {
  15793. s7_pointer func;
  15794. if ((func = find_method(sc, find_let(sc, x), sc->multiply_symbol)) != sc->undefined)
  15795. return(g_subtract_2(sc, set_plist_2(sc, car(args), s7_apply_function(sc, func, list_2(sc, x, x)))));
  15796. return(wrong_type_argument_with_type(sc, sc->multiply_symbol, 1, x, a_number_string));
  15797. }
  15798. }
  15799. return(x);
  15800. }
  15801. #if (!WITH_GMP)
  15802. /* (define (hi) (- (random 100) 50)) (define (ho) (- (random 1.0) 0.5)) */
  15803. static s7_pointer sub_random_ic, sub_random_rc;
  15804. static s7_pointer g_sub_random_ic(s7_scheme *sc, s7_pointer args)
  15805. {
  15806. return(make_integer(sc, ((s7_int)(integer(cadar(args)) * next_random(sc->default_rng))) - integer(cadr(args))));
  15807. }
  15808. static s7_pointer g_sub_random_rc(s7_scheme *sc, s7_pointer args)
  15809. {
  15810. return(make_real(sc, real(cadar(args)) * next_random(sc->default_rng) - real(cadr(args))));
  15811. }
  15812. static s7_int negate_if_c(s7_scheme *sc, s7_pointer **p) {s7_pointer x; x = (**p); (*p)++; return(-integer(x));}
  15813. static s7_int negate_if_s(s7_scheme *sc, s7_pointer **p) {s7_pointer x; x = slot_value(**p); (*p)++; return(-integer(x));}
  15814. static s7_int negate_if_p(s7_scheme *sc, s7_pointer **p) {s7_if_t f; f = (s7_if_t)(**p); (*p)++; return(f(sc, p));}
  15815. static s7_int sub_if_cc(s7_scheme *sc, s7_pointer **p) {s7_pointer x, y; x = (**p); (*p)++; y = (**p); (*p)++; return(integer(x) - integer(y));}
  15816. static s7_int sub_if_cs(s7_scheme *sc, s7_pointer **p) {s7_pointer x, y; x = (**p); (*p)++; y = slot_value(**p); (*p)++; return(integer(x) - integer(y));}
  15817. static s7_int sub_if_ss(s7_scheme *sc, s7_pointer **p) {s7_pointer x, y; x = slot_value(**p); (*p)++; y = slot_value(**p); (*p)++; return(integer(x) - integer(y));}
  15818. static s7_int sub_if_sc(s7_scheme *sc, s7_pointer **p) {s7_pointer x, y; x = slot_value(**p); (*p)++; y = (**p); (*p)++; return(integer(x) - integer(y));}
  15819. static s7_int sub_if_cp(s7_scheme *sc, s7_pointer **p)
  15820. {
  15821. s7_if_t xf;
  15822. s7_pointer x;
  15823. x = (**p); (*p)++;
  15824. xf = (s7_if_t)(**p); (*p)++;
  15825. return(integer(x) - xf(sc, p));
  15826. }
  15827. static s7_int sub_if_pc(s7_scheme *sc, s7_pointer **p)
  15828. {
  15829. s7_if_t xf;
  15830. s7_int x;
  15831. s7_pointer y;
  15832. xf = (s7_if_t)(**p); (*p)++; x = xf(sc,p);
  15833. y = (**p); (*p)++;
  15834. return(x - integer(y));
  15835. }
  15836. static s7_int sub_if_sp(s7_scheme *sc, s7_pointer **p)
  15837. {
  15838. s7_if_t xf;
  15839. s7_pointer x;
  15840. x = slot_value(**p); (*p)++;
  15841. xf = (s7_if_t)(**p); (*p)++;
  15842. return(integer(x) - xf(sc, p));
  15843. }
  15844. static s7_int sub_if_ps(s7_scheme *sc, s7_pointer **p)
  15845. {
  15846. s7_if_t xf;
  15847. s7_int x;
  15848. s7_pointer y;
  15849. xf = (s7_if_t)(**p); (*p)++; x = xf(sc,p);
  15850. y = slot_value(**p); (*p)++;
  15851. return(x - integer(y));
  15852. }
  15853. static s7_int sub_if_pp(s7_scheme *sc, s7_pointer **p)
  15854. {
  15855. s7_if_t xf;
  15856. s7_int x, y;
  15857. xf = (s7_if_t)(**p); (*p)++; x = xf(sc,p);
  15858. xf = (s7_if_t)(**p); (*p)++; y = xf(sc,p);
  15859. return(x - y);
  15860. }
  15861. static s7_if_t subtract_if(s7_scheme *sc, s7_pointer expr)
  15862. {
  15863. s7_pointer a1, a2, slot;
  15864. xf_t *rc;
  15865. if (!is_pair(cdr(expr))) return(NULL);
  15866. xf_init(2);
  15867. a1 = cadr(expr);
  15868. if (is_null(cddr(expr)))
  15869. {
  15870. if (is_t_integer(a1))
  15871. {
  15872. xf_store(a1);
  15873. return(negate_if_c);
  15874. }
  15875. if (is_symbol(a1))
  15876. {
  15877. s7_pointer s1;
  15878. s1 = s7_slot(sc, a1);
  15879. if ((!is_slot(s1)) || (is_unsafe_stepper(s1)) || (!is_t_integer(slot_value(s1)))) return(NULL);
  15880. xf_store(s1);
  15881. return(negate_if_s);
  15882. }
  15883. if ((is_pair(a1)) &&
  15884. (s7_arg_to_if(sc, a1)))
  15885. return(negate_if_p);
  15886. return(NULL);
  15887. }
  15888. a2 = caddr(expr);
  15889. if (is_null(cdddr(expr)))
  15890. {
  15891. if (is_t_integer(a1))
  15892. {
  15893. xf_store(a1);
  15894. if (is_t_integer(a2))
  15895. {
  15896. xf_store(a2);
  15897. return(sub_if_cc);
  15898. }
  15899. if (is_symbol(a2))
  15900. {
  15901. slot = s7_slot(sc, a2);
  15902. if ((!slot) || (!is_t_integer(slot_value(slot))) || (is_unsafe_stepper(slot))) return(NULL);
  15903. xf_store(slot);
  15904. return(sub_if_cs);
  15905. }
  15906. if ((is_pair(a2)) &&
  15907. (s7_arg_to_if(sc, a2)))
  15908. return(sub_if_cp);
  15909. return(NULL);
  15910. }
  15911. if (is_symbol(a1))
  15912. {
  15913. slot = s7_slot(sc, a1);
  15914. if ((!slot) || (!is_t_integer(slot_value(slot))) || (is_unsafe_stepper(slot))) return(NULL);
  15915. xf_store(slot);
  15916. if (is_t_integer(a2))
  15917. {
  15918. xf_store(a2);
  15919. return(sub_if_sc);
  15920. }
  15921. if (is_symbol(a2))
  15922. {
  15923. slot = s7_slot(sc, a2);
  15924. if ((!slot) || (!is_t_integer(slot_value(slot))) || (is_unsafe_stepper(slot))) return(NULL);
  15925. xf_store(slot);
  15926. return(sub_if_ss);
  15927. }
  15928. if ((is_pair(a2)) &&
  15929. (s7_arg_to_if(sc, a2)))
  15930. return(sub_if_sp);
  15931. return(NULL);
  15932. }
  15933. if (is_pair(a1) &&
  15934. (s7_arg_to_if(sc, a1)))
  15935. {
  15936. if (is_t_integer(a2))
  15937. {
  15938. xf_store(a2);
  15939. return(sub_if_pc);
  15940. }
  15941. if (is_symbol(a2))
  15942. {
  15943. slot = s7_slot(sc, a2);
  15944. if ((!slot) || (!is_t_integer(slot_value(slot))) || (is_unsafe_stepper(slot))) return(NULL);
  15945. xf_store(slot);
  15946. return(sub_if_ps);
  15947. }
  15948. if ((is_pair(a2)) &&
  15949. (s7_arg_to_if(sc, a2)))
  15950. return(sub_if_pp);
  15951. }
  15952. return(NULL);
  15953. }
  15954. {
  15955. s7_if_t xf, res;
  15956. ptr_int loc;
  15957. if (is_t_integer(a1))
  15958. {
  15959. xf_store(a1);
  15960. res = sub_if_cp;
  15961. }
  15962. else
  15963. {
  15964. if (is_symbol(a1))
  15965. {
  15966. slot = s7_slot(sc, a1);
  15967. if ((!slot) || (!is_t_integer(slot_value(slot))) || (is_unsafe_stepper(slot))) return(NULL);
  15968. xf_store(slot);
  15969. res = sub_if_sp;
  15970. }
  15971. else
  15972. {
  15973. if ((!is_pair(a1)) || (!s7_arg_to_if(sc, a1))) return(NULL);
  15974. res = sub_if_pp;
  15975. }
  15976. }
  15977. xf_save_loc(loc);
  15978. xf = add_if(sc, cdr(expr));
  15979. if (xf)
  15980. {
  15981. xf_store_at(loc, (s7_pointer)xf);
  15982. return(res);
  15983. }
  15984. }
  15985. return(NULL);
  15986. }
  15987. static s7_double negate_rf_c(s7_scheme *sc, s7_pointer **p) {s7_pointer x; x = (**p); (*p)++; return(-(real_to_double(sc, x, "-")));}
  15988. static s7_double negate_rf_s(s7_scheme *sc, s7_pointer **p) {s7_pointer x; x = slot_value(**p); (*p)++; return(-(real_to_double(sc, x, "-")));}
  15989. static s7_double negate_rf_p(s7_scheme *sc, s7_pointer **p) {s7_rf_t f; f = (s7_rf_t)(**p); (*p)++; return(f(sc, p));}
  15990. static s7_double sub_rf_cc(s7_scheme *sc, s7_pointer **p)
  15991. {
  15992. s7_pointer x, y;
  15993. x = (**p); (*p)++;
  15994. y = (**p); (*p)++;
  15995. return(real(x) - real_to_double(sc, y, "-"));
  15996. }
  15997. static s7_double sub_rf_cs(s7_scheme *sc, s7_pointer **p)
  15998. {
  15999. s7_pointer x, y;
  16000. x = (**p); (*p)++;
  16001. y = slot_value(**p); (*p)++;
  16002. return(real(x) - real_to_double(sc, y, "-"));
  16003. }
  16004. static s7_double sub_rf_ss(s7_scheme *sc, s7_pointer **p)
  16005. {
  16006. s7_pointer x, y;
  16007. s7_double x1;
  16008. x = slot_value(**p); (*p)++;
  16009. y = slot_value(**p); (*p)++;
  16010. x1 = real_to_double(sc, x, "-");
  16011. return(x1 - real_to_double(sc, y, "-"));
  16012. }
  16013. static s7_double sub_rf_sc(s7_scheme *sc, s7_pointer **p)
  16014. {
  16015. s7_pointer x, y;
  16016. x = slot_value(**p); (*p)++;
  16017. y = (**p); (*p)++;
  16018. return(real_to_double(sc, x, "-") - real(y));
  16019. }
  16020. static s7_double sub_rf_cp(s7_scheme *sc, s7_pointer **p)
  16021. {
  16022. s7_rf_t rf;
  16023. s7_pointer x;
  16024. x = (**p); (*p)++;
  16025. rf = (s7_rf_t)(**p); (*p)++;
  16026. return(real_to_double(sc, x, "-") - rf(sc, p));
  16027. }
  16028. static s7_double sub_rf_pc(s7_scheme *sc, s7_pointer **p)
  16029. {
  16030. s7_rf_t rf;
  16031. s7_double x;
  16032. s7_pointer y;
  16033. rf = (s7_rf_t)(**p); (*p)++; x = rf(sc,p);
  16034. y = (**p); (*p)++;
  16035. return(x - real_to_double(sc, y, "-"));
  16036. }
  16037. static s7_double sub_rf_sp(s7_scheme *sc, s7_pointer **p)
  16038. {
  16039. s7_rf_t rf;
  16040. s7_pointer x;
  16041. x = slot_value(**p); (*p)++;
  16042. rf = (s7_rf_t)(**p); (*p)++;
  16043. return(real_to_double(sc, x, "-") - rf(sc, p));
  16044. }
  16045. static s7_double sub_rf_ps(s7_scheme *sc, s7_pointer **p)
  16046. {
  16047. s7_rf_t rf;
  16048. s7_double x;
  16049. s7_pointer y;
  16050. rf = (s7_rf_t)(**p); (*p)++; x = rf(sc,p);
  16051. y = slot_value(**p); (*p)++;
  16052. return(x - real_to_double(sc, y, "-"));
  16053. }
  16054. static s7_double sub_rf_pp(s7_scheme *sc, s7_pointer **p)
  16055. {
  16056. s7_rf_t rf;
  16057. s7_double x, y;
  16058. rf = (s7_rf_t)(**p); (*p)++; x = rf(sc,p);
  16059. rf = (s7_rf_t)(**p); (*p)++; y = rf(sc,p);
  16060. return(x - y);
  16061. }
  16062. static s7_rf_t subtract_rf(s7_scheme *sc, s7_pointer expr)
  16063. {
  16064. s7_pointer a1, a2, slot1, slot2;
  16065. xf_t *rc;
  16066. if (!is_pair(cdr(expr))) return(NULL);
  16067. xf_init(2);
  16068. a1 = cadr(expr);
  16069. if (is_null(cddr(expr)))
  16070. {
  16071. if (is_t_real(a1))
  16072. {
  16073. xf_store(a1);
  16074. return(negate_rf_c);
  16075. }
  16076. if (is_symbol(a1))
  16077. {
  16078. slot1 = s7_slot(sc, a1);
  16079. if ((!is_slot(slot1)) || (is_unsafe_stepper(slot1)) || (!(is_real(slot_value(slot1))))) return(NULL);
  16080. xf_store(slot1);
  16081. return(negate_rf_s);
  16082. }
  16083. if ((is_pair(a1)) &&
  16084. (s7_arg_to_if(sc, a1)))
  16085. return(negate_rf_p);
  16086. return(NULL);
  16087. }
  16088. a2 = caddr(expr);
  16089. if (is_null(cdddr(expr)))
  16090. {
  16091. if (is_t_real(a1))
  16092. {
  16093. xf_store(a1);
  16094. if (is_real(a2))
  16095. {
  16096. xf_store(a2);
  16097. return(sub_rf_cc);
  16098. }
  16099. if (is_symbol(a2))
  16100. {
  16101. slot2 = s7_slot(sc, a2);
  16102. if ((!slot2) || (!is_real(slot_value(slot2))) || (is_unsafe_stepper(slot2))) return(NULL);
  16103. xf_store(slot2);
  16104. return(sub_rf_cs);
  16105. }
  16106. if ((is_pair(a2)) &&
  16107. (s7_arg_to_if(sc, a2)))
  16108. return(sub_rf_cp);
  16109. return(NULL);
  16110. }
  16111. if (is_symbol(a1))
  16112. {
  16113. slot1 = s7_slot(sc, a1);
  16114. if ((!slot1) || (!is_real(slot_value(slot1))) || (is_unsafe_stepper(slot1))) return(NULL);
  16115. xf_store(slot1);
  16116. if (is_t_real(a2))
  16117. {
  16118. xf_store(a2);
  16119. return(sub_rf_sc);
  16120. }
  16121. if (is_symbol(a2))
  16122. {
  16123. slot2 = s7_slot(sc, a2);
  16124. if ((!slot2) || (!is_real(slot_value(slot2))) || (is_unsafe_stepper(slot2))) return(NULL);
  16125. if ((!is_t_real(slot_value(slot1))) && (!is_t_real(slot_value(slot2)))) return(NULL);
  16126. xf_store(slot2);
  16127. return(sub_rf_ss);
  16128. }
  16129. if ((is_pair(a2)) &&
  16130. (s7_arg_to_rf(sc, a2)))
  16131. return(sub_rf_sp);
  16132. return(NULL);
  16133. }
  16134. if (is_pair(a1) &&
  16135. (s7_arg_to_rf(sc, a1)))
  16136. {
  16137. if (is_real(a2))
  16138. {
  16139. xf_store(a2);
  16140. return(sub_rf_pc);
  16141. }
  16142. if (is_symbol(a2))
  16143. {
  16144. slot2 = s7_slot(sc, a2);
  16145. if ((!slot2) || (!is_real(slot_value(slot2))) || (is_unsafe_stepper(slot2))) return(NULL);
  16146. xf_store(slot2);
  16147. return(sub_rf_ps);
  16148. }
  16149. if ((is_pair(a2)) &&
  16150. (s7_arg_to_rf(sc, a2)))
  16151. return(sub_rf_pp);
  16152. }
  16153. return(NULL);
  16154. }
  16155. {
  16156. s7_rf_t rf, res;
  16157. ptr_int loc;
  16158. if (is_real(a1))
  16159. {
  16160. xf_store(a1);
  16161. res = sub_rf_cp;
  16162. }
  16163. else
  16164. {
  16165. if (is_symbol(a1))
  16166. {
  16167. slot1 = s7_slot(sc, a1);
  16168. if ((!slot1) || (!is_t_integer(slot_value(slot1))) || (is_unsafe_stepper(slot1))) return(NULL);
  16169. xf_store(slot1);
  16170. res = sub_rf_sp;
  16171. }
  16172. else
  16173. {
  16174. if ((!is_pair(a1)) || (!s7_arg_to_rf(sc, a1))) return(NULL);
  16175. res = sub_rf_pp;
  16176. }
  16177. }
  16178. xf_save_loc(loc);
  16179. rf = add_rf(sc, cdr(expr));
  16180. if (rf)
  16181. {
  16182. xf_store_at(loc, (s7_pointer)rf);
  16183. return(res);
  16184. }
  16185. }
  16186. return(NULL);
  16187. }
  16188. #if WITH_ADD_PF
  16189. static s7_pointer c_subtract_pf2(s7_scheme *sc, s7_pointer **p)
  16190. {
  16191. s7_pf_t pf;
  16192. s7_pointer x, y;
  16193. pf = (s7_pf_t)(**p); (*p)++;
  16194. x = pf(sc, p);
  16195. xf_push(sc, x);
  16196. pf = (s7_pf_t)(**p); (*p)++;
  16197. y = pf(sc, p);
  16198. x = g_subtract_2(sc, set_plist_2(sc, x, y));
  16199. xf_pop(sc);
  16200. return(x);
  16201. }
  16202. static s7_pf_t subtract_pf(s7_scheme *sc, s7_pointer expr)
  16203. {
  16204. int len;
  16205. len = s7_list_length(sc, expr);
  16206. if (len == 3)
  16207. {
  16208. if ((s7_arg_to_pf(sc, cadr(expr))) &&
  16209. (s7_arg_to_pf(sc, caddr(expr))))
  16210. return(c_subtract_pf2);
  16211. }
  16212. return(NULL);
  16213. }
  16214. #endif
  16215. #endif
  16216. /* ---------------------------------------- multiply ---------------------------------------- */
  16217. static s7_pointer g_multiply(s7_scheme *sc, s7_pointer args)
  16218. {
  16219. #define H_multiply "(* ...) multiplies its arguments"
  16220. #define Q_multiply pcl_n
  16221. s7_pointer x, p;
  16222. s7_int num_a, den_a;
  16223. s7_double rl_a, im_a;
  16224. #if (!WITH_GMP)
  16225. if (is_null(args))
  16226. return(small_int(1));
  16227. #endif
  16228. x = car(args);
  16229. p = cdr(args);
  16230. if (is_null(p))
  16231. {
  16232. if (!is_number(x))
  16233. method_or_bust_with_type(sc, x, sc->multiply_symbol, args, a_number_string, 0);
  16234. return(x);
  16235. }
  16236. switch (type(x))
  16237. {
  16238. case T_INTEGER:
  16239. num_a = integer(x);
  16240. MULTIPLY_INTEGERS:
  16241. #if WITH_GMP
  16242. if ((num_a > s7_int32_max) ||
  16243. (num_a < s7_int32_min))
  16244. return(big_multiply(sc, cons(sc, s7_int_to_big_integer(sc, num_a), p)));
  16245. #endif
  16246. x = car(p);
  16247. p = cdr(p);
  16248. switch (type(x))
  16249. {
  16250. case T_INTEGER:
  16251. #if WITH_GMP
  16252. if ((integer(x) > s7_int32_max) ||
  16253. (integer(x) < s7_int32_min))
  16254. return(big_multiply(sc, cons(sc, s7_int_to_big_integer(sc, num_a), cons(sc, x, p))));
  16255. #endif
  16256. #if HAVE_OVERFLOW_CHECKS
  16257. {
  16258. s7_int dn;
  16259. if (multiply_overflow(num_a, integer(x), &dn))
  16260. {
  16261. if (is_null(p)) return(make_real(sc, (s7_double)num_a * (s7_double)integer(x)));
  16262. rl_a = (s7_double)num_a * (s7_double)integer(x);
  16263. goto MULTIPLY_REALS;
  16264. }
  16265. num_a = dn;
  16266. }
  16267. #else
  16268. /* perhaps put all the math-safety stuff on the 'safety switch?
  16269. * (* 256 17179869184 4194304) -> 0 which is annoying
  16270. * (* 134217728 137438953472) -> 0
  16271. */
  16272. if ((integer_length(num_a) + integer_length(integer(x))) >= s7_int_bits)
  16273. {
  16274. if (is_null(p)) return(make_real(sc, (s7_double)num_a * (s7_double)integer(x)));
  16275. rl_a = (s7_double)num_a * (s7_double)integer(x);
  16276. goto MULTIPLY_REALS;
  16277. }
  16278. num_a *= integer(x);
  16279. #endif
  16280. if (is_null(p)) return(make_integer(sc, num_a));
  16281. goto MULTIPLY_INTEGERS;
  16282. case T_RATIO:
  16283. #if HAVE_OVERFLOW_CHECKS
  16284. {
  16285. s7_int dn;
  16286. if (multiply_overflow(numerator(x), num_a, &dn))
  16287. {
  16288. if (is_null(p))
  16289. return(make_real(sc, (s7_double)num_a * fraction(x)));
  16290. rl_a = (s7_double)num_a * fraction(x);
  16291. goto MULTIPLY_REALS;
  16292. }
  16293. num_a = dn;
  16294. }
  16295. #else
  16296. if ((integer_length(num_a) + integer_length(numerator(x))) >= s7_int_bits)
  16297. {
  16298. if (is_null(p))
  16299. return(make_real(sc, (s7_double)num_a * fraction(x)));
  16300. rl_a = (s7_double)num_a * fraction(x);
  16301. goto MULTIPLY_REALS;
  16302. }
  16303. num_a *= numerator(x);
  16304. #endif
  16305. den_a = denominator(x);
  16306. if (is_null(p)) return(s7_make_ratio(sc, num_a, den_a));
  16307. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  16308. goto MULTIPLY_INTEGERS;
  16309. goto MULTIPLY_RATIOS;
  16310. case T_REAL:
  16311. if (is_null(p)) return(make_real(sc, num_a * real(x)));
  16312. rl_a = num_a * real(x);
  16313. goto MULTIPLY_REALS;
  16314. case T_COMPLEX:
  16315. if (is_null(p)) return(s7_make_complex(sc, num_a * real_part(x), num_a * imag_part(x)));
  16316. rl_a = num_a * real_part(x);
  16317. im_a = num_a * imag_part(x);
  16318. goto MULTIPLY_COMPLEX;
  16319. default:
  16320. method_or_bust_with_type(sc, x, sc->multiply_symbol, cons(sc, s7_make_integer(sc, num_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  16321. }
  16322. break;
  16323. case T_RATIO:
  16324. num_a = numerator(x);
  16325. den_a = denominator(x);
  16326. MULTIPLY_RATIOS:
  16327. #if WITH_GMP
  16328. if ((num_a > s7_int32_max) ||
  16329. (den_a > s7_int32_max) ||
  16330. (num_a < s7_int32_min))
  16331. return(big_multiply(sc, cons(sc, s7_ratio_to_big_ratio(sc, num_a, den_a), p)));
  16332. #endif
  16333. x = car(p);
  16334. p = cdr(p);
  16335. switch (type(x))
  16336. {
  16337. case T_INTEGER:
  16338. /* as in +, this can overflow:
  16339. * (* 8 -9223372036854775807 8) -> 64
  16340. * (* 3/4 -9223372036854775807 8) -> 6
  16341. * (* 8 -9223372036854775808 8) -> 0
  16342. * (* -1 9223372036854775806 8) -> 16
  16343. * (* -9223372036854775808 8 1e+308) -> 0.0
  16344. */
  16345. #if HAVE_OVERFLOW_CHECKS
  16346. {
  16347. s7_int dn;
  16348. if (multiply_overflow(integer(x), num_a, &dn))
  16349. {
  16350. if (is_null(p))
  16351. return(make_real(sc, ((s7_double)integer(x) / (s7_double)den_a) * (s7_double)num_a));
  16352. rl_a = ((s7_double)integer(x) / (s7_double)den_a) * (s7_double)num_a;
  16353. goto MULTIPLY_REALS;
  16354. }
  16355. num_a = dn;
  16356. }
  16357. #else
  16358. if ((integer_length(num_a) + integer_length(integer(x))) >= s7_int_bits)
  16359. {
  16360. if (is_null(p))
  16361. return(make_real(sc, ((s7_double)integer(x) / (s7_double)den_a) * (s7_double)num_a));
  16362. rl_a = ((s7_double)integer(x) / (s7_double)den_a) * (s7_double)num_a;
  16363. goto MULTIPLY_REALS;
  16364. }
  16365. num_a *= integer(x);
  16366. #endif
  16367. if (is_null(p)) return(s7_make_ratio(sc, num_a, den_a));
  16368. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  16369. goto MULTIPLY_INTEGERS;
  16370. goto MULTIPLY_RATIOS;
  16371. case T_RATIO:
  16372. {
  16373. #if (!WITH_GMP)
  16374. s7_int d1, n1;
  16375. #endif
  16376. s7_int d2, n2;
  16377. d2 = denominator(x);
  16378. n2 = numerator(x);
  16379. #if (!WITH_GMP)
  16380. d1 = den_a;
  16381. n1 = num_a;
  16382. #if HAVE_OVERFLOW_CHECKS
  16383. if ((multiply_overflow(n1, n2, &num_a)) ||
  16384. (multiply_overflow(d1, d2, &den_a)))
  16385. {
  16386. if (is_null(p))
  16387. return(make_real(sc, ((long double)n1 / (long double)d1) * ((long double)n2 / (long double)d2)));
  16388. rl_a = ((long double)n1 / (long double)d1) * ((long double)n2 / (long double)d2);
  16389. goto MULTIPLY_REALS;
  16390. }
  16391. #else
  16392. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  16393. (n1 > s7_int32_max) || (n2 > s7_int32_max) || /* (* 1/524288 1/19073486328125) for example */
  16394. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  16395. {
  16396. if ((integer_length(d1) + integer_length(d2) > s7_int_bits) ||
  16397. (integer_length(n1) + integer_length(n2) > s7_int_bits))
  16398. {
  16399. if (is_null(p))
  16400. return(make_real(sc, ((long double)n1 / (long double)d1) * ((long double)n2 / (long double)d2)));
  16401. rl_a = ((long double)n1 / (long double)d1) * ((long double)n2 / (long double)d2);
  16402. goto MULTIPLY_REALS;
  16403. }
  16404. }
  16405. num_a *= n2;
  16406. den_a *= d2;
  16407. #endif
  16408. #else
  16409. num_a *= n2;
  16410. den_a *= d2;
  16411. #endif
  16412. if (is_null(p)) return(s7_make_ratio(sc, num_a, den_a));
  16413. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  16414. goto MULTIPLY_INTEGERS;
  16415. goto MULTIPLY_RATIOS;
  16416. }
  16417. case T_REAL:
  16418. if (is_null(p)) return(make_real(sc, ((long double)num_a / (long double)den_a) * real(x)));
  16419. rl_a = ((long double)num_a / (long double)den_a) * real(x);
  16420. goto MULTIPLY_REALS;
  16421. case T_COMPLEX:
  16422. {
  16423. s7_double frac;
  16424. frac = ((long double)num_a / (long double)den_a);
  16425. if (is_null(p)) return(s7_make_complex(sc, frac * real_part(x), frac * imag_part(x)));
  16426. rl_a = frac * real_part(x);
  16427. im_a = frac * imag_part(x);
  16428. goto MULTIPLY_COMPLEX;
  16429. }
  16430. default:
  16431. method_or_bust_with_type(sc, x, sc->multiply_symbol, cons(sc, s7_make_ratio(sc, num_a, den_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  16432. }
  16433. break;
  16434. case T_REAL:
  16435. rl_a = real(x);
  16436. MULTIPLY_REALS:
  16437. x = car(p);
  16438. p = cdr(p);
  16439. switch (type(x))
  16440. {
  16441. case T_INTEGER:
  16442. if (is_null(p)) return(make_real(sc, rl_a * integer(x)));
  16443. rl_a *= integer(x);
  16444. goto MULTIPLY_REALS;
  16445. case T_RATIO:
  16446. if (is_null(p)) return(make_real(sc, rl_a * fraction(x)));
  16447. rl_a *= (s7_double)fraction(x);
  16448. goto MULTIPLY_REALS;
  16449. case T_REAL:
  16450. if (is_null(p)) return(make_real(sc, rl_a * real(x)));
  16451. rl_a *= real(x);
  16452. goto MULTIPLY_REALS;
  16453. case T_COMPLEX:
  16454. if (is_null(p)) return(s7_make_complex(sc, rl_a * real_part(x), rl_a * imag_part(x)));
  16455. im_a = rl_a * imag_part(x);
  16456. rl_a *= real_part(x);
  16457. goto MULTIPLY_COMPLEX;
  16458. default:
  16459. method_or_bust_with_type(sc, x, sc->multiply_symbol, cons(sc, make_real(sc, rl_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  16460. }
  16461. break;
  16462. case T_COMPLEX:
  16463. rl_a = real_part(x);
  16464. im_a = imag_part(x);
  16465. MULTIPLY_COMPLEX:
  16466. x = car(p);
  16467. p = cdr(p);
  16468. switch (type(x))
  16469. {
  16470. case T_INTEGER:
  16471. if (is_null(p)) return(s7_make_complex(sc, rl_a * integer(x), im_a * integer(x)));
  16472. rl_a *= integer(x);
  16473. im_a *= integer(x);
  16474. goto MULTIPLY_COMPLEX;
  16475. case T_RATIO:
  16476. {
  16477. s7_double frac;
  16478. frac = fraction(x);
  16479. if (is_null(p)) return(s7_make_complex(sc, rl_a * frac, im_a * frac));
  16480. rl_a *= frac;
  16481. im_a *= frac;
  16482. goto MULTIPLY_COMPLEX;
  16483. }
  16484. case T_REAL:
  16485. if (is_null(p)) return(s7_make_complex(sc, rl_a * real(x), im_a * real(x)));
  16486. rl_a *= real(x);
  16487. im_a *= real(x);
  16488. goto MULTIPLY_COMPLEX;
  16489. case T_COMPLEX:
  16490. {
  16491. s7_double r1, r2, i1, i2;
  16492. r1 = rl_a;
  16493. i1 = im_a;
  16494. r2 = real_part(x);
  16495. i2 = imag_part(x);
  16496. if (is_null(p))
  16497. return(s7_make_complex(sc, r1 * r2 - i1 * i2, r1 * i2 + r2 * i1));
  16498. rl_a = r1 * r2 - i1 * i2;
  16499. im_a = r1 * i2 + r2 * i1;
  16500. if (im_a == 0.0)
  16501. goto MULTIPLY_REALS;
  16502. goto MULTIPLY_COMPLEX;
  16503. }
  16504. default:
  16505. method_or_bust_with_type(sc, x, sc->multiply_symbol, cons(sc, s7_make_complex(sc, rl_a, im_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  16506. }
  16507. break;
  16508. default:
  16509. method_or_bust_with_type(sc, x, sc->multiply_symbol, args, a_number_string, 1);
  16510. }
  16511. }
  16512. #if (!WITH_GMP)
  16513. static s7_pointer multiply_2, multiply_fs, multiply_sf, multiply_is, multiply_si;
  16514. static s7_pointer g_multiply_2(s7_scheme *sc, s7_pointer args)
  16515. {
  16516. s7_pointer x, y;
  16517. x = car(args);
  16518. y = cadr(args);
  16519. if (type(x) == type(y))
  16520. {
  16521. if (is_t_real(x))
  16522. return(make_real(sc, real(x) * real(y)));
  16523. else
  16524. {
  16525. switch (type(x))
  16526. {
  16527. #if HAVE_OVERFLOW_CHECKS
  16528. case T_INTEGER:
  16529. {
  16530. s7_int n;
  16531. if (multiply_overflow(integer(x), integer(y), &n))
  16532. return(make_real(sc, ((s7_double)integer(x)) * ((s7_double)integer(y))));
  16533. return(make_integer(sc, n));
  16534. }
  16535. #else
  16536. case T_INTEGER: return(make_integer(sc, integer(x) * integer(y)));
  16537. #endif
  16538. case T_RATIO: return(g_multiply(sc, args));
  16539. case T_REAL: return(make_real(sc, real(x) * real(y)));
  16540. case T_COMPLEX:
  16541. {
  16542. s7_double r1, r2, i1, i2;
  16543. r1 = real_part(x);
  16544. r2 = real_part(y);
  16545. i1 = imag_part(x);
  16546. i2 = imag_part(y);
  16547. return(s7_make_complex(sc, r1 * r2 - i1 * i2, r1 * i2 + r2 * i1));
  16548. }
  16549. default:
  16550. if (!is_number(x))
  16551. method_or_bust_with_type(sc, x, sc->multiply_symbol, args, a_number_string, 1);
  16552. method_or_bust_with_type(sc, y, sc->multiply_symbol, args, a_number_string, 2);
  16553. }
  16554. }
  16555. }
  16556. switch (type(x))
  16557. {
  16558. case T_INTEGER:
  16559. switch (type(y))
  16560. {
  16561. case T_INTEGER: return(make_integer(sc, integer(x) * integer(y)));
  16562. case T_RATIO: return(g_multiply(sc, args));
  16563. case T_REAL: return(make_real(sc, integer(x) * real(y)));
  16564. case T_COMPLEX: return(s7_make_complex(sc, integer(x) * real_part(y), integer(x) * imag_part(y)));
  16565. default:
  16566. method_or_bust_with_type(sc, y, sc->multiply_symbol, args, a_number_string, 2);
  16567. }
  16568. case T_RATIO:
  16569. switch (type(y))
  16570. {
  16571. case T_INTEGER:
  16572. case T_RATIO: return(g_multiply(sc, args));
  16573. case T_REAL: return(make_real(sc, fraction(x) * real(y)));
  16574. case T_COMPLEX:
  16575. {
  16576. s7_double frac;
  16577. frac = fraction(x);
  16578. return(s7_make_complex(sc, frac * real_part(y), frac * imag_part(y)));
  16579. }
  16580. default:
  16581. method_or_bust_with_type(sc, y, sc->multiply_symbol, args, a_number_string, 2);
  16582. }
  16583. case T_REAL:
  16584. switch (type(y))
  16585. {
  16586. case T_INTEGER: return(make_real(sc, real(x) * integer(y)));
  16587. case T_RATIO: return(make_real(sc, real(x) * fraction(y)));
  16588. case T_REAL: return(make_real(sc, real(x) * real(y)));
  16589. case T_COMPLEX: return(s7_make_complex(sc, real(x) * real_part(y), real(x) * imag_part(y)));
  16590. default:
  16591. method_or_bust_with_type(sc, y, sc->multiply_symbol, args, a_number_string, 2);
  16592. }
  16593. case T_COMPLEX:
  16594. switch (type(y))
  16595. {
  16596. case T_INTEGER: return(s7_make_complex(sc, real_part(x) * integer(y), imag_part(x) * integer(y)));
  16597. case T_RATIO:
  16598. {
  16599. s7_double frac;
  16600. frac = fraction(y);
  16601. return(s7_make_complex(sc, real_part(x) * frac, imag_part(x) * frac));
  16602. }
  16603. case T_REAL: return(s7_make_complex(sc, real_part(x) * real(y), imag_part(x) * real(y)));
  16604. case T_COMPLEX:
  16605. {
  16606. s7_double r1, r2, i1, i2;
  16607. r1 = real_part(x);
  16608. r2 = real_part(y);
  16609. i1 = imag_part(x);
  16610. i2 = imag_part(y);
  16611. return(s7_make_complex(sc, r1 * r2 - i1 * i2, r1 * i2 + r2 * i1));
  16612. }
  16613. default:
  16614. method_or_bust_with_type(sc, y, sc->multiply_symbol, args, a_number_string, 2);
  16615. }
  16616. default:
  16617. method_or_bust_with_type(sc, x, sc->multiply_symbol, args, a_number_string, 1);
  16618. }
  16619. return(x);
  16620. }
  16621. /* all of these mess up if overflows occur
  16622. * (let () (define (f x) (* x 9223372036854775806)) (f -63)) -> -9223372036854775682, but (* -63 9223372036854775806) -> -5.810724383218509e+20
  16623. * how to catch this? (affects * - +)
  16624. */
  16625. static s7_pointer g_multiply_si(s7_scheme *sc, s7_pointer args)
  16626. {
  16627. s7_pointer x;
  16628. s7_int n;
  16629. x = find_symbol_checked(sc, car(args));
  16630. n = integer(cadr(args));
  16631. switch (type(x))
  16632. {
  16633. #if HAVE_OVERFLOW_CHECKS
  16634. case T_INTEGER:
  16635. {
  16636. s7_int val;
  16637. if (multiply_overflow(integer(x), n, &val))
  16638. return(make_real(sc, (double)integer(x) * (double)n));
  16639. return(make_integer(sc, val));
  16640. }
  16641. case T_RATIO:
  16642. {
  16643. s7_int val;
  16644. if (multiply_overflow(numerator(x), n, &val))
  16645. return(make_real(sc, fraction(x) * (double)n));
  16646. return(s7_make_ratio(sc, val, denominator(x)));
  16647. }
  16648. #else
  16649. case T_INTEGER: return(make_integer(sc, integer(x) * n));
  16650. case T_RATIO: return(s7_make_ratio(sc, numerator(x) * n, denominator(x)));
  16651. #endif
  16652. case T_REAL: return(make_real(sc, real(x) * n));
  16653. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) * n, imag_part(x) * n));
  16654. default:
  16655. method_or_bust_with_type(sc, x, sc->multiply_symbol, list_2(sc, x, cadr(args)), a_number_string, 1);
  16656. }
  16657. return(x);
  16658. }
  16659. static s7_pointer g_multiply_is(s7_scheme *sc, s7_pointer args)
  16660. {
  16661. s7_pointer x;
  16662. s7_int n;
  16663. x = find_symbol_checked(sc, cadr(args));
  16664. n = integer(car(args));
  16665. switch (type(x))
  16666. {
  16667. #if HAVE_OVERFLOW_CHECKS
  16668. case T_INTEGER:
  16669. {
  16670. s7_int val;
  16671. if (multiply_overflow(integer(x), n, &val))
  16672. return(make_real(sc, (double)integer(x) * (double)n));
  16673. return(make_integer(sc, val));
  16674. }
  16675. case T_RATIO:
  16676. {
  16677. s7_int val;
  16678. if (multiply_overflow(numerator(x), n, &val))
  16679. return(make_real(sc, fraction(x) * (double)n));
  16680. return(s7_make_ratio(sc, val, denominator(x)));
  16681. }
  16682. #else
  16683. case T_INTEGER: return(make_integer(sc, integer(x) * n));
  16684. case T_RATIO: return(s7_make_ratio(sc, numerator(x) * n, denominator(x)));
  16685. #endif
  16686. case T_REAL: return(make_real(sc, real(x) * n));
  16687. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) * n, imag_part(x) * n));
  16688. default:
  16689. method_or_bust_with_type(sc, x, sc->multiply_symbol, list_2(sc, car(args), x), a_number_string, 2);
  16690. }
  16691. return(x);
  16692. }
  16693. static s7_pointer g_multiply_fs(s7_scheme *sc, s7_pointer args)
  16694. {
  16695. s7_pointer x;
  16696. s7_double scl;
  16697. scl = real(car(args));
  16698. x = find_symbol_checked(sc, cadr(args));
  16699. switch (type(x))
  16700. {
  16701. case T_INTEGER: return(make_real(sc, integer(x) * scl));
  16702. case T_RATIO: return(make_real(sc, numerator(x) * scl / denominator(x)));
  16703. case T_REAL: return(make_real(sc, real(x) * scl));
  16704. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) * scl, imag_part(x) * scl));
  16705. default:
  16706. method_or_bust_with_type(sc, x, sc->multiply_symbol, list_2(sc, car(args), x), a_number_string, 1);
  16707. }
  16708. return(x);
  16709. }
  16710. static s7_pointer g_multiply_sf(s7_scheme *sc, s7_pointer args)
  16711. {
  16712. s7_pointer x;
  16713. s7_double scl;
  16714. scl = real(cadr(args));
  16715. x = find_symbol_checked(sc, car(args));
  16716. switch (type(x))
  16717. {
  16718. case T_INTEGER: return(make_real(sc, integer(x) * scl));
  16719. case T_RATIO: return(make_real(sc, numerator(x) * scl / denominator(x)));
  16720. case T_REAL: return(make_real(sc, real(x) * scl));
  16721. case T_COMPLEX: return(s7_make_complex(sc, real_part(x) * scl, imag_part(x) * scl));
  16722. default:
  16723. method_or_bust_with_type(sc, x, sc->multiply_symbol, list_2(sc, x, cadr(args)), a_number_string, 2);
  16724. }
  16725. return(x);
  16726. }
  16727. static s7_pointer sqr_ss;
  16728. static s7_pointer g_sqr_ss(s7_scheme *sc, s7_pointer args)
  16729. {
  16730. s7_pointer x;
  16731. x = find_symbol_checked(sc, car(args));
  16732. switch (type(x))
  16733. {
  16734. #if HAVE_OVERFLOW_CHECKS
  16735. case T_INTEGER:
  16736. {
  16737. s7_int val;
  16738. if (multiply_overflow(integer(x), integer(x), &val))
  16739. return(make_real(sc, (double)integer(x) * (double)integer(x)));
  16740. return(make_integer(sc, val));
  16741. }
  16742. case T_RATIO:
  16743. {
  16744. s7_int num, den;
  16745. if ((multiply_overflow(numerator(x), numerator(x), &num)) ||
  16746. (multiply_overflow(denominator(x), denominator(x), &den)))
  16747. return(make_real(sc, fraction(x) * fraction(x)));
  16748. return(s7_make_ratio(sc, num, den));
  16749. }
  16750. #else
  16751. case T_INTEGER: return(s7_make_integer(sc, integer(x) * integer(x)));
  16752. case T_RATIO: return(s7_make_ratio(sc, numerator(x) * numerator(x), denominator(x) * denominator(x)));
  16753. #endif
  16754. case T_REAL: return(make_real(sc, real(x) * real(x)));
  16755. 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)));
  16756. default:
  16757. method_or_bust_with_type(sc, x, sc->multiply_symbol, list_2(sc, x, x), a_number_string, 1);
  16758. }
  16759. return(x);
  16760. }
  16761. static s7_pointer mul_1ss;
  16762. static s7_pointer g_mul_1ss(s7_scheme *sc, s7_pointer args)
  16763. {
  16764. /* (* (- 1.0 x) y) */
  16765. s7_pointer x, y;
  16766. x = find_symbol_checked(sc, caddr(car(args)));
  16767. y = find_symbol_checked(sc, cadr(args));
  16768. if ((is_t_real(x)) &&
  16769. (is_t_real(y)))
  16770. return(make_real(sc, real(y) * (1.0 - real(x))));
  16771. if ((is_real(x)) &&
  16772. (is_real(y)))
  16773. {
  16774. s7_double x1;
  16775. x1 = real_to_double(sc, y, "*");
  16776. return(make_real(sc, x1 * (1.0 - real_to_double(sc, x, "*"))));
  16777. }
  16778. else
  16779. {
  16780. s7_double r1, r2, i1, i2;
  16781. if (!is_number(x))
  16782. {
  16783. s7_pointer func;
  16784. if ((func = find_method(sc, find_let(sc, x), sc->subtract_symbol)) != sc->undefined)
  16785. return(g_multiply_2(sc, set_plist_2(sc, s7_apply_function(sc, func, list_2(sc, real_one, x)), y)));
  16786. return(wrong_type_argument_with_type(sc, sc->subtract_symbol, 2, x, a_number_string));
  16787. }
  16788. if (!is_number(y))
  16789. {
  16790. s7_pointer func;
  16791. if ((func = find_method(sc, find_let(sc, y), sc->multiply_symbol)) != sc->undefined)
  16792. return(s7_apply_function(sc, func, list_2(sc, g_subtract(sc, list_2(sc, real_one, x)), y)));
  16793. return(wrong_type_argument_with_type(sc, sc->multiply_symbol, 2, y, a_number_string));
  16794. }
  16795. r1 = 1.0 - s7_real_part(x);
  16796. r2 = s7_real_part(y);
  16797. i1 = -s7_imag_part(x);
  16798. i2 = s7_imag_part(y);
  16799. return(s7_make_complex(sc, r1 * r2 - i1 * i2, r1 * i2 + r2 * i1));
  16800. }
  16801. }
  16802. static s7_pointer multiply_cs_cos;
  16803. static s7_pointer g_multiply_cs_cos(s7_scheme *sc, s7_pointer args)
  16804. {
  16805. /* ([*] -2.0 r (cos x)) */
  16806. s7_pointer r, x;
  16807. r = find_symbol_checked(sc, cadr(args));
  16808. x = find_symbol_checked(sc, cadr(caddr(args)));
  16809. if ((is_t_real(r)) &&
  16810. (is_t_real(x)))
  16811. return(make_real(sc, real(car(args)) * real(r) * cos(real(x))));
  16812. if ((is_real(r)) &&
  16813. (is_real(x)))
  16814. return(make_real(sc, real(car(args)) * real_to_double(sc, r, "*") * cos(real_to_double(sc, x, "*"))));
  16815. return(g_multiply(sc, set_plist_3(sc, car(args), r, g_cos(sc, set_plist_1(sc, x)))));
  16816. }
  16817. static s7_pointer mul_s_sin_s, mul_s_cos_s;
  16818. static s7_pointer g_mul_s_sin_s(s7_scheme *sc, s7_pointer args)
  16819. {
  16820. /* (* s (sin s)) */
  16821. s7_pointer x, y;
  16822. x = find_symbol_checked(sc, car(args));
  16823. y = find_symbol_checked(sc, cadadr(args));
  16824. if ((is_real(x)) && (is_real(y)))
  16825. return(make_real(sc, real_to_double(sc, x, "*") * sin(real_to_double(sc, y, "sin"))));
  16826. return(g_multiply(sc, set_plist_2(sc, x, g_sin(sc, set_plist_1(sc, y)))));
  16827. }
  16828. static s7_pointer g_mul_s_cos_s(s7_scheme *sc, s7_pointer args)
  16829. {
  16830. /* (* s (cos s)) */
  16831. s7_pointer x, y;
  16832. x = find_symbol_checked(sc, car(args));
  16833. y = find_symbol_checked(sc, cadadr(args));
  16834. if ((is_real(x)) && (is_real(y)))
  16835. return(make_real(sc, real_to_double(sc, x, "*") * cos(real_to_double(sc, y, "cos"))));
  16836. return(g_multiply(sc, set_plist_2(sc, x, g_cos(sc, set_plist_1(sc, y)))));
  16837. }
  16838. static s7_double multiply_rf_xx(s7_scheme *sc, s7_pointer **p)
  16839. {
  16840. s7_rf_t r1, r2;
  16841. s7_double x, y;
  16842. r1 = (s7_rf_t)(**p); (*p)++;
  16843. x = r1(sc, p);
  16844. r2 = (s7_rf_t)(**p); (*p)++;
  16845. y = r2(sc, p);
  16846. return(x * y);
  16847. }
  16848. static s7_double multiply_rf_rx(s7_scheme *sc, s7_pointer **p)
  16849. {
  16850. s7_pointer c1;
  16851. s7_rf_t r1;
  16852. s7_double x;
  16853. c1 = **p; (*p)++;
  16854. r1 = (s7_rf_t)(**p); (*p)++;
  16855. x = r1(sc, p);
  16856. return(x * real_to_double(sc, c1, "*"));
  16857. }
  16858. static s7_double multiply_rf_sx(s7_scheme *sc, s7_pointer **p)
  16859. {
  16860. s7_pointer s1;
  16861. s7_rf_t r1;
  16862. s7_double x;
  16863. s1 = slot_value(**p); (*p)++;
  16864. r1 = (s7_rf_t)(**p); (*p)++;
  16865. x = r1(sc, p);
  16866. return(x * real_to_double(sc, s1, "*"));
  16867. }
  16868. static s7_double multiply_rf_ss(s7_scheme *sc, s7_pointer **p)
  16869. {
  16870. s7_pointer s1, s2;
  16871. s7_double x1;
  16872. s1 = slot_value(**p); (*p)++;
  16873. x1 = real_to_double(sc, s1, "*");
  16874. s2 = slot_value(**p); (*p)++;
  16875. return(x1 * real_to_double(sc, s2, "*"));
  16876. }
  16877. static s7_double multiply_rf_rs(s7_scheme *sc, s7_pointer **p)
  16878. {
  16879. s7_pointer c1, s1;
  16880. s7_double x1;
  16881. s1 = slot_value(**p); (*p)++;
  16882. c1 = **p; (*p)++;
  16883. x1 = real_to_double(sc, c1, "*");
  16884. return(x1 * real_to_double(sc, s1, "*"));
  16885. }
  16886. static s7_double multiply_rf_xxx(s7_scheme *sc, s7_pointer **p)
  16887. {
  16888. s7_rf_t r1, r2, r3;
  16889. s7_double x, y, z;
  16890. r1 = (s7_rf_t)(**p); (*p)++;
  16891. x = r1(sc, p);
  16892. r2 = (s7_rf_t)(**p); (*p)++;
  16893. y = r2(sc, p);
  16894. r3 = (s7_rf_t)(**p); (*p)++;
  16895. z = r3(sc, p);
  16896. return(x * y * z);
  16897. }
  16898. static s7_double multiply_rf_rxx(s7_scheme *sc, s7_pointer **p)
  16899. {
  16900. s7_pointer c1;
  16901. s7_rf_t r1, r2;
  16902. s7_double x, y;
  16903. c1 = **p; (*p)++;
  16904. r1 = (s7_rf_t)(**p); (*p)++;
  16905. x = r1(sc, p);
  16906. r2 = (s7_rf_t)(**p); (*p)++;
  16907. y = r2(sc, p);
  16908. return(x * y * real_to_double(sc, c1, "*"));
  16909. }
  16910. static s7_double multiply_rf_sxx(s7_scheme *sc, s7_pointer **p)
  16911. {
  16912. s7_pointer s1;
  16913. s7_rf_t r1, r2;
  16914. s7_double x, y;
  16915. s1 = slot_value(**p); (*p)++;
  16916. r1 = (s7_rf_t)(**p); (*p)++;
  16917. x = r1(sc, p);
  16918. r2 = (s7_rf_t)(**p); (*p)++;
  16919. y = r2(sc, p);
  16920. return(x * y * real_to_double(sc, s1, "*"));
  16921. }
  16922. static s7_double multiply_rf_rsx(s7_scheme *sc, s7_pointer **p)
  16923. {
  16924. s7_pointer c1, s1;
  16925. s7_rf_t r1;
  16926. s7_double x, x1;
  16927. s1 = slot_value(**p); (*p)++;
  16928. c1 = **p; (*p)++;
  16929. x1 = real_to_double(sc, c1, "*");
  16930. r1 = (s7_rf_t)(**p); (*p)++;
  16931. x = r1(sc, p);
  16932. return(x * x1 * real_to_double(sc, s1, "*"));
  16933. }
  16934. static s7_double multiply_rf_ssx(s7_scheme *sc, s7_pointer **p)
  16935. {
  16936. s7_pointer s1, s2;
  16937. s7_rf_t r1;
  16938. s7_double x, x1;
  16939. s1 = slot_value(**p); (*p)++;
  16940. x1 = real_to_double(sc, s1, "*");
  16941. s2 = slot_value(**p); (*p)++;
  16942. r1 = (s7_rf_t)(**p); (*p)++;
  16943. x = r1(sc, p);
  16944. return(x * x1 * real_to_double(sc, s2, "*"));
  16945. }
  16946. static s7_double multiply_rf_sss(s7_scheme *sc, s7_pointer **p)
  16947. {
  16948. s7_pointer s1, s2, s3;
  16949. s7_double x1, x2, x3;
  16950. s1 = slot_value(**p); (*p)++;
  16951. x1 = real_to_double(sc, s1, "*");
  16952. s2 = slot_value(**p); (*p)++;
  16953. x2 = real_to_double(sc, s2, "*");
  16954. s3 = slot_value(**p); (*p)++;
  16955. x3 = real_to_double(sc, s3, "*");
  16956. return(x1 * x2 * x3);
  16957. }
  16958. static s7_double multiply_rf_rss(s7_scheme *sc, s7_pointer **p)
  16959. {
  16960. s7_pointer c1, s1, s2;
  16961. s7_double x1, x2, x3;
  16962. s1 = slot_value(**p); (*p)++;
  16963. x1 = real_to_double(sc, s1, "*");
  16964. s2 = slot_value(**p); (*p)++;
  16965. x2 = real_to_double(sc, s2, "*");
  16966. c1 = **p; (*p)++;
  16967. x3 = real_to_double(sc, c1, "*");
  16968. return(x1 * x2 * x3);
  16969. }
  16970. static s7_rf_t multiply_rf_1(s7_scheme *sc, s7_pointer expr, int len)
  16971. {
  16972. if (len == 3)
  16973. return(com_rf_2(sc, expr, multiply_r_ops));
  16974. if (len == 4)
  16975. return(com_rf_3(sc, expr, multiply_r_ops));
  16976. if (len > 4)
  16977. {
  16978. s7_rf_t rf;
  16979. ptr_int loc;
  16980. xf_t *rc;
  16981. int first_len;
  16982. xf_init(2);
  16983. first_len = (int)(len / 2);
  16984. xf_save_loc(loc);
  16985. rf = multiply_rf_1(sc, expr, first_len + 1);
  16986. if (rf)
  16987. {
  16988. int i;
  16989. s7_pointer p;
  16990. xf_store_at(loc, (s7_pointer)rf);
  16991. xf_save_loc(loc);
  16992. for (i = 0, p = expr; i < first_len; i++, p = cdr(p));
  16993. rf = multiply_rf_1(sc, p, len - first_len);
  16994. if (rf)
  16995. {
  16996. xf_store_at(loc, (s7_pointer)rf);
  16997. return(multiply_rf_xx);
  16998. }
  16999. else return(NULL);
  17000. }
  17001. else return(NULL);
  17002. }
  17003. return(NULL);
  17004. }
  17005. static s7_rf_t multiply_rf(s7_scheme *sc, s7_pointer expr)
  17006. {
  17007. return(multiply_rf_1(sc, expr, s7_list_length(sc, expr)));
  17008. }
  17009. static s7_int multiply_if_xx(s7_scheme *sc, s7_pointer **p)
  17010. {
  17011. s7_if_t r1, r2;
  17012. s7_int x, y;
  17013. r1 = (s7_if_t)(**p); (*p)++;
  17014. x = r1(sc, p);
  17015. r2 = (s7_if_t)(**p); (*p)++;
  17016. y = r2(sc, p);
  17017. return(x * y);
  17018. }
  17019. static s7_int multiply_if_rx(s7_scheme *sc, s7_pointer **p)
  17020. {
  17021. s7_pointer c1;
  17022. s7_if_t r1;
  17023. s7_int x;
  17024. c1 = **p; (*p)++;
  17025. r1 = (s7_if_t)(**p); (*p)++;
  17026. x = r1(sc, p);
  17027. return(x * integer(c1));
  17028. }
  17029. static s7_int multiply_if_sx(s7_scheme *sc, s7_pointer **p)
  17030. {
  17031. s7_pointer s1;
  17032. s7_if_t r1;
  17033. s7_int x;
  17034. s1 = slot_value(**p); (*p)++;
  17035. r1 = (s7_if_t)(**p); (*p)++;
  17036. x = r1(sc, p);
  17037. return(x * integer(s1));
  17038. }
  17039. static s7_int multiply_if_ss(s7_scheme *sc, s7_pointer **p)
  17040. {
  17041. s7_pointer s1, s2;
  17042. s1 = slot_value(**p); (*p)++;
  17043. s2 = slot_value(**p); (*p)++;
  17044. return(integer(s1) * integer(s2));
  17045. }
  17046. static s7_int multiply_if_rs(s7_scheme *sc, s7_pointer **p)
  17047. {
  17048. s7_pointer c1, s1;
  17049. s1 = slot_value(**p); (*p)++;
  17050. c1 = **p; (*p)++;
  17051. return(integer(c1) * integer(s1));
  17052. }
  17053. static s7_int multiply_if_xxx(s7_scheme *sc, s7_pointer **p)
  17054. {
  17055. s7_if_t r1, r2, r3;
  17056. s7_int x, y, z;
  17057. r1 = (s7_if_t)(**p); (*p)++;
  17058. x = r1(sc, p);
  17059. r2 = (s7_if_t)(**p); (*p)++;
  17060. y = r2(sc, p);
  17061. r3 = (s7_if_t)(**p); (*p)++;
  17062. z = r3(sc, p);
  17063. return(x * y * z);
  17064. }
  17065. static s7_int multiply_if_rxx(s7_scheme *sc, s7_pointer **p)
  17066. {
  17067. s7_pointer c1;
  17068. s7_if_t r1, r2;
  17069. s7_int x, y;
  17070. c1 = **p; (*p)++;
  17071. r1 = (s7_if_t)(**p); (*p)++;
  17072. x = r1(sc, p);
  17073. r2 = (s7_if_t)(**p); (*p)++;
  17074. y = r2(sc, p);
  17075. return(x * y * integer(c1));
  17076. }
  17077. static s7_int multiply_if_sxx(s7_scheme *sc, s7_pointer **p)
  17078. {
  17079. s7_pointer s1;
  17080. s7_if_t r1, r2;
  17081. s7_int x, y;
  17082. s1 = slot_value(**p); (*p)++;
  17083. r1 = (s7_if_t)(**p); (*p)++;
  17084. x = r1(sc, p);
  17085. r2 = (s7_if_t)(**p); (*p)++;
  17086. y = r2(sc, p);
  17087. return(x * y * integer(s1));
  17088. }
  17089. static s7_int multiply_if_rsx(s7_scheme *sc, s7_pointer **p)
  17090. {
  17091. s7_pointer c1, s1;
  17092. s7_if_t r1;
  17093. s7_int x;
  17094. s1 = slot_value(**p); (*p)++;
  17095. c1 = **p; (*p)++;
  17096. r1 = (s7_if_t)(**p); (*p)++;
  17097. x = r1(sc, p);
  17098. return(x * integer(c1) * integer(s1));
  17099. }
  17100. static s7_int multiply_if_ssx(s7_scheme *sc, s7_pointer **p)
  17101. {
  17102. s7_pointer s1, s2;
  17103. s7_if_t r1;
  17104. s7_int x;
  17105. s1 = slot_value(**p); (*p)++;
  17106. s2 = slot_value(**p); (*p)++;
  17107. r1 = (s7_if_t)(**p); (*p)++;
  17108. x = r1(sc, p);
  17109. return(x * integer(s1) * integer(s2));
  17110. }
  17111. static s7_int multiply_if_sss(s7_scheme *sc, s7_pointer **p)
  17112. {
  17113. s7_pointer s1, s2, s3;
  17114. s1 = slot_value(**p); (*p)++;
  17115. s2 = slot_value(**p); (*p)++;
  17116. s3 = slot_value(**p); (*p)++;
  17117. return(integer(s1) * integer(s2) * integer(s3));
  17118. }
  17119. static s7_int multiply_if_rss(s7_scheme *sc, s7_pointer **p)
  17120. {
  17121. s7_pointer c1, s1, s2;
  17122. s1 = slot_value(**p); (*p)++;
  17123. s2 = slot_value(**p); (*p)++;
  17124. c1 = **p; (*p)++;
  17125. return(integer(c1) * integer(s1) * integer(s2));
  17126. }
  17127. static s7_if_t multiply_if_1(s7_scheme *sc, s7_pointer expr, int len)
  17128. {
  17129. if (len == 3)
  17130. return(com_if_2(sc, expr, multiply_i_ops));
  17131. if (len == 4)
  17132. return(com_if_3(sc, expr, multiply_i_ops));
  17133. if (len > 4)
  17134. {
  17135. s7_if_t xf;
  17136. xf_t *rc;
  17137. ptr_int loc;
  17138. int first_len;
  17139. xf_init(2);
  17140. first_len = (int)(len / 2);
  17141. xf_save_loc(loc);
  17142. xf = multiply_if_1(sc, expr, first_len + 1);
  17143. if (xf)
  17144. {
  17145. int i;
  17146. s7_pointer p;
  17147. xf_store_at(loc, (s7_pointer)xf);
  17148. xf_save_loc(loc);
  17149. for (i = 0, p = expr; i < first_len; i++, p = cdr(p));
  17150. xf = multiply_if_1(sc, p, len - first_len);
  17151. if (xf)
  17152. {
  17153. xf_store_at(loc, (s7_pointer)xf);
  17154. return(multiply_if_xx);
  17155. }
  17156. else return(NULL);
  17157. }
  17158. else return(NULL);
  17159. }
  17160. return(NULL);
  17161. }
  17162. static s7_if_t multiply_if(s7_scheme *sc, s7_pointer expr)
  17163. {
  17164. return(multiply_if_1(sc, expr, s7_list_length(sc, expr)));
  17165. }
  17166. static void init_multiply_ops(void)
  17167. {
  17168. multiply_r_ops = (rf_ops *)calloc(1, sizeof(rf_ops));
  17169. multiply_r_ops->r = rf_c;
  17170. multiply_r_ops->s = rf_s;
  17171. multiply_r_ops->rs = multiply_rf_rs;
  17172. multiply_r_ops->rp = multiply_rf_rx;
  17173. multiply_r_ops->sp = multiply_rf_sx;
  17174. multiply_r_ops->ss = multiply_rf_ss;
  17175. multiply_r_ops->pp = multiply_rf_xx;
  17176. multiply_r_ops->rss = multiply_rf_rss;
  17177. multiply_r_ops->rsp = multiply_rf_rsx;
  17178. multiply_r_ops->rpp = multiply_rf_rxx;
  17179. multiply_r_ops->sss = multiply_rf_sss;
  17180. multiply_r_ops->ssp = multiply_rf_ssx;
  17181. multiply_r_ops->spp = multiply_rf_sxx;
  17182. multiply_r_ops->ppp = multiply_rf_xxx;
  17183. multiply_i_ops = (if_ops *)calloc(1, sizeof(if_ops));
  17184. multiply_i_ops->r = if_c;
  17185. multiply_i_ops->s = if_s;
  17186. multiply_i_ops->rs = multiply_if_rs;
  17187. multiply_i_ops->rp = multiply_if_rx;
  17188. multiply_i_ops->sp = multiply_if_sx;
  17189. multiply_i_ops->ss = multiply_if_ss;
  17190. multiply_i_ops->pp = multiply_if_xx;
  17191. multiply_i_ops->rss = multiply_if_rss;
  17192. multiply_i_ops->rsp = multiply_if_rsx;
  17193. multiply_i_ops->rpp = multiply_if_rxx;
  17194. multiply_i_ops->sss = multiply_if_sss;
  17195. multiply_i_ops->ssp = multiply_if_ssx;
  17196. multiply_i_ops->spp = multiply_if_sxx;
  17197. multiply_i_ops->ppp = multiply_if_xxx;
  17198. }
  17199. #if WITH_ADD_PF
  17200. static s7_pointer c_mul_pf2(s7_scheme *sc, s7_pointer **p)
  17201. {
  17202. s7_pf_t pf;
  17203. s7_pointer x, y;
  17204. pf = (s7_pf_t)(**p); (*p)++;
  17205. x = pf(sc, p);
  17206. xf_push(sc, x);
  17207. pf = (s7_pf_t)(**p); (*p)++;
  17208. y = pf(sc, p);
  17209. x = g_multiply_2(sc, set_plist_2(sc, x, y));
  17210. xf_pop(sc);
  17211. return(x);
  17212. }
  17213. static s7_pf_t multiply_pf(s7_scheme *sc, s7_pointer expr)
  17214. {
  17215. int len;
  17216. len = s7_list_length(sc, expr);
  17217. if (len == 3)
  17218. {
  17219. if ((s7_arg_to_pf(sc, cadr(expr))) &&
  17220. (s7_arg_to_pf(sc, caddr(expr))))
  17221. return(c_mul_pf2);
  17222. }
  17223. return(NULL);
  17224. }
  17225. #endif
  17226. #endif /* with-gmp */
  17227. /* ---------------------------------------- divide ---------------------------------------- */
  17228. static bool is_number_via_method(s7_scheme *sc, s7_pointer p)
  17229. {
  17230. if (s7_is_number(p))
  17231. return(true);
  17232. if (has_methods(p))
  17233. {
  17234. s7_pointer f;
  17235. f = find_method(sc, find_let(sc, p), sc->is_number_symbol);
  17236. if (f != sc->undefined)
  17237. return(is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil))));
  17238. }
  17239. return(false);
  17240. }
  17241. static s7_pointer g_divide(s7_scheme *sc, s7_pointer args)
  17242. {
  17243. #define H_divide "(/ x1 ...) divides its first argument by the rest, or inverts the first if there is only one argument"
  17244. #define Q_divide pcl_n
  17245. s7_pointer x, p;
  17246. s7_int num_a, den_a;
  17247. s7_double rl_a, im_a;
  17248. x = car(args);
  17249. p = cdr(args);
  17250. if (is_null(p))
  17251. {
  17252. if (!is_number(x))
  17253. method_or_bust_with_type(sc, x, sc->divide_symbol, args, a_number_string, 0);
  17254. if (s7_is_zero(x))
  17255. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17256. return(s7_invert(sc, x));
  17257. }
  17258. switch (type(x))
  17259. {
  17260. case T_INTEGER:
  17261. num_a = integer(x);
  17262. if (num_a == 0)
  17263. {
  17264. bool return_nan = false, return_real_zero = false;
  17265. for (; is_pair(p); p = cdr(p))
  17266. {
  17267. s7_pointer n;
  17268. n = car(p);
  17269. if (!s7_is_number(n))
  17270. {
  17271. n = check_values(sc, n, p);
  17272. if (!s7_is_number(n))
  17273. return(wrong_type_argument_with_type(sc, sc->divide_symbol, position_of(p, args), n, a_number_string));
  17274. }
  17275. if (s7_is_zero(n))
  17276. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17277. if (type(n) > T_RATIO)
  17278. {
  17279. return_real_zero = true;
  17280. if (is_NaN(s7_real_part(n)))
  17281. return_nan = true;
  17282. }
  17283. }
  17284. if (return_nan)
  17285. return(real_NaN);
  17286. if (return_real_zero)
  17287. return(real_zero);
  17288. return(small_int(0));
  17289. }
  17290. DIVIDE_INTEGERS:
  17291. #if WITH_GMP
  17292. if ((num_a > s7_int32_max) ||
  17293. (num_a < s7_int32_min))
  17294. return(big_divide(sc, cons(sc, s7_int_to_big_integer(sc, num_a), p)));
  17295. #endif
  17296. x = car(p);
  17297. p = cdr(p);
  17298. switch (type(x))
  17299. {
  17300. case T_INTEGER:
  17301. if (integer(x) == 0)
  17302. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17303. /* to be consistent, I suppose we should search first for NaNs in the divisor list.
  17304. * (* 0 0/0) is NaN, so (/ 1 0 0/0) should equal (/ 1 0/0) = NaN. But the whole
  17305. * thing is ridiculous.
  17306. */
  17307. if (is_null(p))
  17308. return(s7_make_ratio(sc, num_a, integer(x)));
  17309. den_a = integer(x);
  17310. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  17311. goto DIVIDE_INTEGERS;
  17312. goto DIVIDE_RATIOS;
  17313. case T_RATIO:
  17314. den_a = denominator(x);
  17315. #if HAVE_OVERFLOW_CHECKS
  17316. {
  17317. s7_int dn;
  17318. if (multiply_overflow(num_a, den_a, &dn))
  17319. {
  17320. if (is_null(p)) return(make_real(sc, num_a * inverted_fraction(x)));
  17321. rl_a = (s7_double)num_a * inverted_fraction(x);
  17322. goto DIVIDE_REALS;
  17323. }
  17324. num_a = dn;
  17325. }
  17326. #else
  17327. if ((integer_length(num_a) + integer_length(den_a)) > s7_int_bits)
  17328. {
  17329. if (is_null(p)) return(make_real(sc, num_a * inverted_fraction(x)));
  17330. rl_a = (s7_double)num_a * inverted_fraction(x);
  17331. goto DIVIDE_REALS;
  17332. }
  17333. num_a *= den_a;
  17334. #endif
  17335. den_a = numerator(x);
  17336. if (is_null(p)) return(s7_make_ratio(sc, num_a, den_a));
  17337. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  17338. goto DIVIDE_INTEGERS;
  17339. goto DIVIDE_RATIOS;
  17340. case T_REAL:
  17341. rl_a = (s7_double)num_a;
  17342. if (real(x) == 0.0)
  17343. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17344. if (is_null(p)) return(make_real(sc, rl_a / real(x)));
  17345. rl_a /= real(x);
  17346. goto DIVIDE_REALS;
  17347. case T_COMPLEX:
  17348. {
  17349. s7_double i2, r2, den;
  17350. rl_a = (s7_double)num_a;
  17351. r2 = real_part(x);
  17352. i2 = imag_part(x);
  17353. den = 1.0 / (r2 * r2 + i2 * i2);
  17354. /* we could avoid the squaring (see Knuth II p613 16)
  17355. * not a big deal: (/ 1.0e308+1.0e308i 2.0e308+2.0e308i) => nan
  17356. * (gmp case is ok here)
  17357. */
  17358. if (is_null(p))
  17359. return(s7_make_complex(sc, rl_a * r2 * den, -(rl_a * i2 * den)));
  17360. im_a = -rl_a * i2 * den;
  17361. rl_a *= r2 * den;
  17362. goto DIVIDE_COMPLEX;
  17363. }
  17364. default:
  17365. method_or_bust_with_type(sc, x, sc->divide_symbol, cons(sc, s7_make_integer(sc, num_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  17366. }
  17367. break;
  17368. case T_RATIO:
  17369. num_a = numerator(x);
  17370. den_a = denominator(x);
  17371. DIVIDE_RATIOS:
  17372. #if WITH_GMP
  17373. if ((num_a > s7_int32_max) ||
  17374. (den_a > s7_int32_max) ||
  17375. (num_a < s7_int32_min))
  17376. return(big_divide(sc, cons(sc, s7_ratio_to_big_ratio(sc, num_a, den_a), p)));
  17377. #endif
  17378. x = car(p);
  17379. p = cdr(p);
  17380. switch (type(x))
  17381. {
  17382. case T_INTEGER:
  17383. if (integer(x) == 0)
  17384. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17385. #if HAVE_OVERFLOW_CHECKS
  17386. {
  17387. s7_int dn;
  17388. if (multiply_overflow(den_a, integer(x), &dn))
  17389. {
  17390. if (is_null(p)) return(make_real(sc, (long double)num_a / ((long double)den_a * (s7_double)integer(x))));
  17391. rl_a = (long double)num_a / ((long double)den_a * (s7_double)integer(x));
  17392. goto DIVIDE_REALS;
  17393. }
  17394. den_a = dn;
  17395. }
  17396. #else
  17397. if ((integer_length(integer(x)) + integer_length(den_a)) > s7_int_bits)
  17398. {
  17399. if (is_null(p)) return(make_real(sc, (long double)num_a / ((long double)den_a * (s7_double)integer(x))));
  17400. rl_a = (long double)num_a / ((long double)den_a * (s7_double)integer(x));
  17401. goto DIVIDE_REALS;
  17402. }
  17403. den_a *= integer(x);
  17404. #endif
  17405. if (is_null(p)) return(s7_make_ratio(sc, num_a, den_a));
  17406. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  17407. goto DIVIDE_INTEGERS;
  17408. goto DIVIDE_RATIOS;
  17409. case T_RATIO:
  17410. {
  17411. s7_int d1, d2, n1, n2;
  17412. d1 = den_a;
  17413. n1 = num_a;
  17414. d2 = denominator(x);
  17415. n2 = numerator(x);
  17416. if (d1 == d2)
  17417. {
  17418. if (is_null(p))
  17419. return(s7_make_ratio(sc, n1, n2));
  17420. den_a = n2;
  17421. }
  17422. else
  17423. {
  17424. #if (!WITH_GMP)
  17425. #if HAVE_OVERFLOW_CHECKS
  17426. if ((multiply_overflow(n1, d2, &n1)) ||
  17427. (multiply_overflow(n2, d1, &d1)))
  17428. {
  17429. s7_double r1, r2;
  17430. r1 = ((long double)num_a / (long double)den_a);
  17431. r2 = inverted_fraction(x);
  17432. if (is_null(p)) return(make_real(sc, r1 * r2));
  17433. rl_a = r1 * r2;
  17434. goto DIVIDE_REALS;
  17435. }
  17436. num_a = n1;
  17437. den_a = d1;
  17438. #else
  17439. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  17440. (n1 > s7_int32_max) || (n2 > s7_int32_max) ||
  17441. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  17442. {
  17443. if ((integer_length(d1) + integer_length(n2) > s7_int_bits) ||
  17444. (integer_length(d2) + integer_length(n1) > s7_int_bits))
  17445. {
  17446. s7_double r1, r2;
  17447. r1 = ((long double)num_a / (long double)den_a);
  17448. r2 = inverted_fraction(x);
  17449. if (is_null(p)) return(make_real(sc, r1 * r2));
  17450. rl_a = r1 * r2;
  17451. goto DIVIDE_REALS;
  17452. }
  17453. }
  17454. num_a *= d2;
  17455. den_a *= n2;
  17456. #endif
  17457. #else
  17458. num_a *= d2;
  17459. den_a *= n2;
  17460. #endif
  17461. if (is_null(p))
  17462. return(s7_make_ratio(sc, num_a, den_a));
  17463. }
  17464. if (reduce_fraction(sc, &num_a, &den_a) == T_INTEGER)
  17465. goto DIVIDE_INTEGERS;
  17466. goto DIVIDE_RATIOS;
  17467. }
  17468. case T_REAL:
  17469. {
  17470. s7_double r1;
  17471. if (real(x) == 0.0)
  17472. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17473. r1 = ((long double)num_a / (long double)den_a);
  17474. if (is_null(p)) return(make_real(sc, r1 / real(x)));
  17475. rl_a = r1 / real(x);
  17476. goto DIVIDE_REALS;
  17477. }
  17478. case T_COMPLEX:
  17479. {
  17480. s7_double den, i2, r2;
  17481. rl_a = ((long double)num_a / (long double)den_a);
  17482. r2 = real_part(x);
  17483. i2 = imag_part(x);
  17484. den = 1.0 / (r2 * r2 + i2 * i2);
  17485. if (is_null(p))
  17486. return(s7_make_complex(sc, rl_a * r2 * den, -rl_a * i2 * den));
  17487. im_a = -rl_a * i2 * den;
  17488. rl_a *= r2 * den;
  17489. goto DIVIDE_COMPLEX;
  17490. }
  17491. default:
  17492. method_or_bust_with_type(sc, x, sc->divide_symbol, cons(sc, s7_make_ratio(sc, num_a, den_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  17493. }
  17494. break;
  17495. case T_REAL:
  17496. rl_a = real(x);
  17497. if (rl_a == 0)
  17498. {
  17499. bool return_nan = false;
  17500. for (; is_pair(p); p = cdr(p))
  17501. {
  17502. s7_pointer n;
  17503. n = car(p);
  17504. if (!s7_is_number(n))
  17505. {
  17506. n = check_values(sc, n, p);
  17507. if (!s7_is_number(n))
  17508. return(wrong_type_argument_with_type(sc, sc->divide_symbol, position_of(p, args), n, a_number_string));
  17509. }
  17510. if (s7_is_zero(n))
  17511. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17512. if ((is_t_real(n)) &&
  17513. (is_NaN(real(n))))
  17514. return_nan = true;
  17515. }
  17516. if (return_nan)
  17517. return(real_NaN);
  17518. return(real_zero);
  17519. }
  17520. DIVIDE_REALS:
  17521. x = car(p);
  17522. p = cdr(p);
  17523. switch (type(x))
  17524. {
  17525. case T_INTEGER:
  17526. if (integer(x) == 0)
  17527. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17528. if (is_null(p)) return(make_real(sc, rl_a / integer(x)));
  17529. rl_a /= (s7_double)integer(x);
  17530. goto DIVIDE_REALS;
  17531. case T_RATIO:
  17532. if (is_null(p)) return(make_real(sc, rl_a * inverted_fraction(x)));
  17533. rl_a *= (s7_double)inverted_fraction(x);
  17534. goto DIVIDE_REALS;
  17535. case T_REAL:
  17536. if (real(x) == 0.0)
  17537. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17538. if (is_null(p)) return(make_real(sc, rl_a / real(x)));
  17539. rl_a /= real(x);
  17540. goto DIVIDE_REALS;
  17541. case T_COMPLEX:
  17542. {
  17543. s7_double den, r2, i2;
  17544. r2 = real_part(x);
  17545. i2 = imag_part(x);
  17546. den = 1.0 / (r2 * r2 + i2 * i2);
  17547. if (is_null(p))
  17548. return(s7_make_complex(sc, rl_a * r2 * den, -rl_a * i2 * den));
  17549. im_a = -rl_a * i2 * den;
  17550. rl_a *= r2 * den;
  17551. goto DIVIDE_COMPLEX;
  17552. }
  17553. default:
  17554. method_or_bust_with_type(sc, x, sc->divide_symbol, cons(sc, make_real(sc, rl_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  17555. }
  17556. break;
  17557. case T_COMPLEX:
  17558. rl_a = real_part(x);
  17559. im_a = imag_part(x);
  17560. DIVIDE_COMPLEX:
  17561. x = car(p);
  17562. p = cdr(p);
  17563. switch (type(x))
  17564. {
  17565. case T_INTEGER:
  17566. {
  17567. s7_double r1;
  17568. if (integer(x) == 0)
  17569. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17570. r1 = 1.0 / (s7_double)integer(x);
  17571. if (is_null(p)) return(s7_make_complex(sc, rl_a * r1, im_a * r1));
  17572. rl_a *= r1;
  17573. im_a *= r1;
  17574. goto DIVIDE_COMPLEX;
  17575. }
  17576. case T_RATIO:
  17577. {
  17578. s7_double frac;
  17579. frac = inverted_fraction(x);
  17580. if (is_null(p)) return(s7_make_complex(sc, rl_a * frac, im_a * frac));
  17581. rl_a *= frac;
  17582. im_a *= frac;
  17583. goto DIVIDE_COMPLEX;
  17584. }
  17585. case T_REAL:
  17586. {
  17587. s7_double r1;
  17588. if (real(x) == 0.0)
  17589. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17590. r1 = 1.0 / real(x);
  17591. if (is_null(p)) return(s7_make_complex(sc, rl_a * r1, im_a * r1));
  17592. rl_a *= r1;
  17593. im_a *= r1;
  17594. goto DIVIDE_COMPLEX;
  17595. }
  17596. case T_COMPLEX:
  17597. {
  17598. s7_double r1, r2, i1, i2, den;
  17599. r1 = rl_a;
  17600. i1 = im_a;
  17601. r2 = real_part(x);
  17602. i2 = imag_part(x);
  17603. den = 1.0 / (r2 * r2 + i2 * i2);
  17604. if (is_null(p))
  17605. return(s7_make_complex(sc, (r1 * r2 + i1 * i2) * den, (r2 * i1 - r1 * i2) * den));
  17606. rl_a = (r1 * r2 + i1 * i2) * den;
  17607. im_a = (r2 * i1 - r1 * i2) * den;
  17608. goto DIVIDE_COMPLEX;
  17609. }
  17610. default:
  17611. method_or_bust_with_type(sc, x, sc->divide_symbol, cons(sc, s7_make_complex(sc, rl_a, im_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  17612. }
  17613. break;
  17614. default:
  17615. method_or_bust_with_type(sc, x, sc->divide_symbol, args, a_number_string, 1);
  17616. }
  17617. }
  17618. #if (!WITH_GMP)
  17619. static s7_pointer invert_1;
  17620. static s7_pointer g_invert_1(s7_scheme *sc, s7_pointer args)
  17621. {
  17622. s7_pointer p;
  17623. p = car(args);
  17624. switch (type(p))
  17625. {
  17626. case T_INTEGER:
  17627. if (integer(p) != 0)
  17628. return(s7_make_ratio(sc, 1, integer(p))); /* a already checked, not 0 */
  17629. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17630. case T_RATIO:
  17631. return(s7_make_ratio(sc, denominator(p), numerator(p)));
  17632. case T_REAL:
  17633. if (real(p) != 0.0)
  17634. return(make_real(sc, 1.0 / real(p)));
  17635. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17636. case T_COMPLEX:
  17637. {
  17638. s7_double r2, i2, den;
  17639. r2 = real_part(p);
  17640. i2 = imag_part(p);
  17641. den = (r2 * r2 + i2 * i2);
  17642. return(s7_make_complex(sc, r2 / den, -i2 / den));
  17643. }
  17644. default:
  17645. method_or_bust_with_type(sc, p, sc->divide_symbol, args, a_number_string, 1);
  17646. }
  17647. }
  17648. static s7_pointer divide_1r;
  17649. static s7_pointer g_divide_1r(s7_scheme *sc, s7_pointer args)
  17650. {
  17651. if (s7_is_real(cadr(args)))
  17652. {
  17653. s7_double rl;
  17654. rl = real_to_double(sc, cadr(args), "/");
  17655. if (rl == 0.0)
  17656. return(division_by_zero_error(sc, sc->divide_symbol, args));
  17657. return(make_real(sc, 1.0 / rl));
  17658. }
  17659. return(g_divide(sc, args));
  17660. }
  17661. static s7_double c_dbl_invert(s7_scheme *sc, s7_double x)
  17662. {
  17663. if (x == 0.0) division_by_zero_error(sc, sc->divide_symbol, set_elist_1(sc, real_zero));
  17664. return(1.0 / x);
  17665. }
  17666. static s7_double c_dbl_divide_2(s7_scheme *sc, s7_double x, s7_double y)
  17667. {
  17668. if (y == 0.0) division_by_zero_error(sc, sc->divide_symbol, set_elist_2(sc, make_real(sc, x), real_zero));
  17669. return(x / y);
  17670. }
  17671. static s7_double c_dbl_divide_3(s7_scheme *sc, s7_double x, s7_double y, s7_double z)
  17672. {
  17673. s7_double d;
  17674. d = y * z;
  17675. if (d == 0.0) division_by_zero_error(sc, sc->divide_symbol, set_elist_3(sc, make_real(sc, x), make_real(sc, y), make_real(sc, z)));
  17676. return(x / d);
  17677. }
  17678. RF_3_TO_RF(divide, c_dbl_invert, c_dbl_divide_2, c_dbl_divide_3)
  17679. #endif
  17680. /* ---------------------------------------- max/min ---------------------------------------- */
  17681. static bool is_real_via_method_1(s7_scheme *sc, s7_pointer p)
  17682. {
  17683. s7_pointer f;
  17684. f = find_method(sc, find_let(sc, p), sc->is_real_symbol);
  17685. if (f != sc->undefined)
  17686. return(is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil))));
  17687. return(false);
  17688. }
  17689. #define is_real_via_method(sc, p) ((s7_is_real(p)) || ((has_methods(p)) && (is_real_via_method_1(sc, p))))
  17690. static s7_pointer g_max(s7_scheme *sc, s7_pointer args)
  17691. {
  17692. #define H_max "(max ...) returns the maximum of its arguments"
  17693. #define Q_max pcl_r
  17694. s7_pointer x, y, p;
  17695. s7_int num_a, num_b, den_a, den_b;
  17696. x = car(args);
  17697. p = cdr(args);
  17698. switch (type(x))
  17699. {
  17700. case T_INTEGER:
  17701. MAX_INTEGERS:
  17702. if (is_null(p)) return(x);
  17703. y = car(p);
  17704. p = cdr(p);
  17705. /* fprintf(stderr, "%d: %s %s\n", __LINE__, DISPLAY(x), DISPLAY(y)); */
  17706. switch (type(y))
  17707. {
  17708. case T_INTEGER:
  17709. if (integer(x) < integer(y)) x = y;
  17710. goto MAX_INTEGERS;
  17711. case T_RATIO:
  17712. num_a = integer(x);
  17713. den_a = 1;
  17714. num_b = numerator(y);
  17715. den_b = denominator(y);
  17716. goto RATIO_MAX_RATIO;
  17717. case T_REAL:
  17718. if (is_NaN(real(y)))
  17719. {
  17720. for (; is_not_null(p); p = cdr(p))
  17721. if (!is_real_via_method(sc, car(p)))
  17722. return(wrong_type_argument(sc, sc->max_symbol, position_of(p, args), car(p), T_REAL));
  17723. return(y);
  17724. }
  17725. if (integer(x) < real(y))
  17726. {
  17727. x = y;
  17728. goto MAX_REALS;
  17729. }
  17730. goto MAX_INTEGERS;
  17731. default:
  17732. method_or_bust(sc, y, sc->max_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  17733. }
  17734. case T_RATIO:
  17735. MAX_RATIOS:
  17736. if (is_null(p)) return(x);
  17737. y = car(p);
  17738. p = cdr(p);
  17739. /* fprintf(stderr, "%d: %s %s\n", __LINE__, DISPLAY(x), DISPLAY(y)); */
  17740. switch (type(y))
  17741. {
  17742. case T_INTEGER:
  17743. num_a = numerator(x);
  17744. den_a = denominator(x);
  17745. num_b = integer(y);
  17746. den_b = 1;
  17747. goto RATIO_MAX_RATIO;
  17748. case T_RATIO:
  17749. num_a = numerator(x);
  17750. den_a = denominator(x);
  17751. num_b = numerator(y);
  17752. den_b = denominator(y);
  17753. RATIO_MAX_RATIO:
  17754. /* there are tricky cases here where long ints outrun doubles:
  17755. * (max 92233720368547758/9223372036854775807 92233720368547757/9223372036854775807)
  17756. * which should be 92233720368547758/9223372036854775807) but first the fraction gets reduced
  17757. * to 13176245766935394/1317624576693539401, so we fall into the double comparison, and
  17758. * there we should be comparing
  17759. * 9.999999999999999992410584792601468961145E-3 and
  17760. * 9.999999999999999883990367544051025548645E-3
  17761. * but if using doubles we get
  17762. * 0.010000000000000000208166817117 and
  17763. * 0.010000000000000000208166817117
  17764. * that is, we can't distinguish these two fractions once they're coerced to doubles.
  17765. *
  17766. * Even long doubles fail in innocuous-looking cases:
  17767. * (min 21053343141/6701487259 3587785776203/1142027682075) -> 3587785776203/1142027682075
  17768. * (max 21053343141/6701487259 3587785776203/1142027682075) -> 3587785776203/1142027682075
  17769. *
  17770. * Another consequence: outside gmp, we can't handle cases like
  17771. * (max 9223372036854776/9223372036854775807 #i9223372036854775/9223372036854775000)
  17772. * (max #i9223372036854776/9223372036854775807 9223372036854775/9223372036854775000)
  17773. * I guess if the user is using "inexact" numbers (#i...), he accepts their inexactness.
  17774. */
  17775. if ((num_a < 0) && (num_b >= 0)) /* x < 0, y >= 0 -> y */
  17776. x = y;
  17777. else
  17778. {
  17779. if ((num_a < 0) || (num_b >= 0))
  17780. {
  17781. if (den_a == den_b)
  17782. {
  17783. if (num_a < num_b)
  17784. x = y;
  17785. }
  17786. else
  17787. {
  17788. if (num_a == num_b)
  17789. {
  17790. if (((num_a >= 0) &&
  17791. (den_a > den_b)) ||
  17792. ((num_a < 0) &&
  17793. (den_a < den_b)))
  17794. x = y;
  17795. }
  17796. else
  17797. {
  17798. s7_int vala, valb;
  17799. vala = num_a / den_a;
  17800. valb = num_b / den_b;
  17801. /* fprintf(stderr, "val: %lld %lld %d %d\n", vala, valb, -1/2, 0); */
  17802. if (!((vala > valb) ||
  17803. ((vala == valb) && (is_t_integer(y)))))
  17804. {
  17805. if ((valb > vala) ||
  17806. ((vala == valb) && (is_t_integer(x))) ||
  17807. /* sigh -- both are ratios and the int parts are equal */
  17808. (((long double)(num_a % den_a) / (long double)den_a) <= ((long double)(num_b % den_b) / (long double)den_b)))
  17809. x = y;
  17810. }
  17811. }
  17812. }
  17813. }
  17814. }
  17815. if (is_t_ratio(x))
  17816. goto MAX_RATIOS;
  17817. goto MAX_INTEGERS;
  17818. case T_REAL:
  17819. /* (max 3/4 nan.0) should probably return NaN */
  17820. if (is_NaN(real(y)))
  17821. {
  17822. for (; is_not_null(p); p = cdr(p))
  17823. if (!is_real_via_method(sc, car(p)))
  17824. return(wrong_type_argument(sc, sc->max_symbol, position_of(p, args), car(p), T_REAL));
  17825. return(y);
  17826. }
  17827. if (fraction(x) < real(y))
  17828. {
  17829. x = y;
  17830. goto MAX_REALS;
  17831. }
  17832. goto MAX_RATIOS;
  17833. default:
  17834. method_or_bust(sc, y, sc->max_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  17835. }
  17836. case T_REAL:
  17837. if (is_NaN(real(x)))
  17838. {
  17839. for (; is_not_null(p); p = cdr(p))
  17840. if (!is_real_via_method(sc, car(p)))
  17841. return(wrong_type_argument(sc, sc->max_symbol, position_of(p, args), car(p), T_REAL));
  17842. return(x);
  17843. }
  17844. MAX_REALS:
  17845. if (is_null(p)) return(x);
  17846. y = car(p);
  17847. p = cdr(p);
  17848. switch (type(y))
  17849. {
  17850. case T_INTEGER:
  17851. if (real(x) < integer(y))
  17852. {
  17853. x = y;
  17854. goto MAX_INTEGERS;
  17855. }
  17856. goto MAX_REALS;
  17857. case T_RATIO:
  17858. if (real(x) < fraction(y))
  17859. {
  17860. x = y;
  17861. goto MAX_RATIOS;
  17862. }
  17863. goto MAX_REALS;
  17864. case T_REAL:
  17865. if (is_NaN(real(y)))
  17866. {
  17867. for (; is_not_null(p); p = cdr(p))
  17868. if (!is_real_via_method(sc, car(p)))
  17869. return(wrong_type_argument(sc, sc->max_symbol, position_of(p, args), car(p), T_REAL));
  17870. return(y);
  17871. }
  17872. if (real(x) < real(y)) x = y;
  17873. goto MAX_REALS;
  17874. default:
  17875. method_or_bust(sc, y, sc->max_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  17876. }
  17877. default:
  17878. method_or_bust(sc, x, sc->max_symbol, cons(sc, x, p), T_REAL, 1);
  17879. }
  17880. }
  17881. #if (!WITH_GMP)
  17882. static s7_pointer max_f2;
  17883. static s7_pointer g_max_f2(s7_scheme *sc, s7_pointer args)
  17884. {
  17885. s7_pointer x, y;
  17886. x = car(args);
  17887. y = cadr(args);
  17888. if (is_t_real(y))
  17889. return((real(x) >= real(y)) ? x : y);
  17890. if (is_real(y))
  17891. return((real(x) >= real_to_double(sc, y, "max")) ? x : y);
  17892. method_or_bust(sc, y, sc->max_symbol, args, T_REAL, 2);
  17893. }
  17894. #endif
  17895. static s7_pointer g_min(s7_scheme *sc, s7_pointer args)
  17896. {
  17897. #define H_min "(min ...) returns the minimum of its arguments"
  17898. #define Q_min pcl_r
  17899. s7_pointer x, y, p;
  17900. s7_int num_a, num_b, den_a, den_b;
  17901. x = car(args);
  17902. p = cdr(args);
  17903. switch (type(x))
  17904. {
  17905. case T_INTEGER:
  17906. MIN_INTEGERS:
  17907. if (is_null(p)) return(x);
  17908. y = car(p);
  17909. p = cdr(p);
  17910. switch (type(y))
  17911. {
  17912. case T_INTEGER:
  17913. if (integer(x) > integer(y)) x = y;
  17914. goto MIN_INTEGERS;
  17915. case T_RATIO:
  17916. num_a = integer(x);
  17917. den_a = 1;
  17918. num_b = numerator(y);
  17919. den_b = denominator(y);
  17920. goto RATIO_MIN_RATIO;
  17921. case T_REAL:
  17922. if (is_NaN(real(y)))
  17923. {
  17924. for (; is_not_null(p); p = cdr(p))
  17925. if (!is_real_via_method(sc, car(p)))
  17926. return(wrong_type_argument(sc, sc->min_symbol, position_of(p, args), car(p), T_REAL));
  17927. return(y);
  17928. }
  17929. if (integer(x) > real(y))
  17930. {
  17931. x = y;
  17932. goto MIN_REALS;
  17933. }
  17934. goto MIN_INTEGERS;
  17935. default:
  17936. method_or_bust(sc, y, sc->min_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  17937. }
  17938. case T_RATIO:
  17939. MIN_RATIOS:
  17940. if (is_null(p)) return(x);
  17941. y = car(p);
  17942. p = cdr(p);
  17943. switch (type(y))
  17944. {
  17945. case T_INTEGER:
  17946. num_a = numerator(x);
  17947. den_a = denominator(x);
  17948. num_b = integer(y);
  17949. den_b = 1;
  17950. goto RATIO_MIN_RATIO;
  17951. case T_RATIO:
  17952. num_a = numerator(x);
  17953. den_a = denominator(x);
  17954. num_b = numerator(y);
  17955. den_b = denominator(y);
  17956. RATIO_MIN_RATIO:
  17957. if ((num_a >= 0) && (num_b < 0))
  17958. x = y;
  17959. else
  17960. {
  17961. if ((num_a >= 0) || (num_b < 0))
  17962. {
  17963. if (den_a == den_b)
  17964. {
  17965. if (num_a > num_b)
  17966. x = y;
  17967. }
  17968. else
  17969. {
  17970. if (num_a == num_b)
  17971. {
  17972. if (((num_a >= 0) &&
  17973. (den_a < den_b)) ||
  17974. ((num_a < 0) &&
  17975. (den_a > den_b)))
  17976. x = y;
  17977. }
  17978. else
  17979. {
  17980. s7_int vala, valb;
  17981. vala = num_a / den_a;
  17982. valb = num_b / den_b;
  17983. if (!((vala < valb) ||
  17984. ((vala == valb) && (is_t_integer(x)))))
  17985. {
  17986. if ((valb < vala) ||
  17987. ((vala == valb) && (is_t_integer(y))) ||
  17988. (((long double)(num_a % den_a) / (long double)den_a) >= ((long double)(num_b % den_b) / (long double)den_b)))
  17989. x = y;
  17990. }
  17991. }
  17992. }
  17993. }
  17994. }
  17995. if (is_t_ratio(x))
  17996. goto MIN_RATIOS;
  17997. goto MIN_INTEGERS;
  17998. case T_REAL:
  17999. /* (min 3/4 nan.0) should probably return NaN */
  18000. if (is_NaN(real(y)))
  18001. {
  18002. for (; is_not_null(p); p = cdr(p))
  18003. if (!is_real_via_method(sc, car(p)))
  18004. return(wrong_type_argument(sc, sc->min_symbol, position_of(p, args), car(p), T_REAL));
  18005. return(y);
  18006. }
  18007. if (fraction(x) > real(y))
  18008. {
  18009. x = y;
  18010. goto MIN_REALS;
  18011. }
  18012. goto MIN_RATIOS;
  18013. default:
  18014. method_or_bust(sc, y, sc->min_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18015. }
  18016. case T_REAL:
  18017. if (is_NaN(real(x)))
  18018. {
  18019. for (; is_not_null(p); p = cdr(p))
  18020. if (!is_real_via_method(sc, car(p)))
  18021. return(wrong_type_argument(sc, sc->min_symbol, position_of(p, args), car(p), T_REAL));
  18022. return(x);
  18023. }
  18024. MIN_REALS:
  18025. if (is_null(p)) return(x);
  18026. y = car(p);
  18027. p = cdr(p);
  18028. switch (type(y))
  18029. {
  18030. case T_INTEGER:
  18031. if (real(x) > integer(y))
  18032. {
  18033. x = y;
  18034. goto MIN_INTEGERS;
  18035. }
  18036. goto MIN_REALS;
  18037. case T_RATIO:
  18038. if (real(x) > fraction(y))
  18039. {
  18040. x = y;
  18041. goto MIN_RATIOS;
  18042. }
  18043. goto MIN_REALS;
  18044. case T_REAL:
  18045. if (is_NaN(real(y)))
  18046. {
  18047. for (; is_not_null(p); p = cdr(p))
  18048. if (!is_real_via_method(sc, car(p)))
  18049. return(wrong_type_argument(sc, sc->min_symbol, position_of(p, args), car(p), T_REAL));
  18050. return(y);
  18051. }
  18052. if (real(x) > real(y)) x = y;
  18053. goto MIN_REALS;
  18054. default:
  18055. method_or_bust(sc, y, sc->min_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18056. }
  18057. default:
  18058. method_or_bust(sc, x, sc->min_symbol, cons(sc, x, p), T_REAL, 1);
  18059. }
  18060. }
  18061. #if (!WITH_GMP)
  18062. static s7_pointer min_f2;
  18063. static s7_pointer g_min_f2(s7_scheme *sc, s7_pointer args)
  18064. {
  18065. s7_pointer x, y;
  18066. x = car(args);
  18067. y = cadr(args);
  18068. if (is_t_real(y))
  18069. return((real(x) <= real(y)) ? x : y);
  18070. if (is_real(y))
  18071. return((real(x) <= real_to_double(sc, y, "min")) ? x : y);
  18072. method_or_bust(sc, y, sc->min_symbol, args, T_REAL, 2);
  18073. }
  18074. static s7_int c_max_i1(s7_scheme *sc, s7_int x) {return(x);}
  18075. static s7_int c_max_i2(s7_scheme *sc, s7_int x, s7_int y) {return((x >= y) ? x : y);}
  18076. static s7_int c_max_i3(s7_scheme *sc, s7_int x, s7_int y, s7_int z) {return(((x >= y) ? ((x >= z) ? x : z) : ((y >= z) ? y : z)));}
  18077. IF_3_TO_IF(max, c_max_i1, c_max_i2, c_max_i3)
  18078. static s7_int c_min_i1(s7_scheme *sc, s7_int x) {return(x);}
  18079. static s7_int c_min_i2(s7_scheme *sc, s7_int x, s7_int y) {return((x <= y) ? x : y);}
  18080. static s7_int c_min_i3(s7_scheme *sc, s7_int x, s7_int y, s7_int z) {return(((x <= y) ? ((x <= z) ? x : z) : ((y <= z) ? y : z)));}
  18081. IF_3_TO_IF(min, c_min_i1, c_min_i2, c_min_i3)
  18082. static s7_double c_max_r1(s7_scheme *sc, s7_double x) {return(x);}
  18083. static s7_double c_max_r2(s7_scheme *sc, s7_double x, s7_double y) {return((x >= y) ? x : y);}
  18084. static s7_double c_max_r3(s7_scheme *sc, s7_double x, s7_double y, s7_double z) {return(((x >= y) ? ((x >= z) ? x : z) : ((y >= z) ? y : z)));}
  18085. RF_3_TO_RF(max, c_max_r1, c_max_r2, c_max_r3)
  18086. static s7_double c_min_r1(s7_scheme *sc, s7_double x) {return(x);}
  18087. static s7_double c_min_r2(s7_scheme *sc, s7_double x, s7_double y) {return((x <= y) ? x : y);}
  18088. static s7_double c_min_r3(s7_scheme *sc, s7_double x, s7_double y, s7_double z) {return(((x <= y) ? ((x <= z) ? x : z) : ((y <= z) ? y : z)));}
  18089. RF_3_TO_RF(min, c_min_r1, c_min_r2, c_min_r3)
  18090. #endif
  18091. /* ---------------------------------------- = > < >= <= ---------------------------------------- */
  18092. static s7_pointer g_equal(s7_scheme *sc, s7_pointer args)
  18093. {
  18094. #define H_equal "(= z1 ...) returns #t if all its arguments are equal"
  18095. #define Q_equal s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_number_symbol)
  18096. s7_pointer x, p;
  18097. s7_int num_a, den_a;
  18098. s7_double rl_a, im_a;
  18099. x = car(args);
  18100. p = cdr(args);
  18101. switch (type(x))
  18102. {
  18103. case T_INTEGER:
  18104. num_a = integer(x);
  18105. while (true)
  18106. {
  18107. x = car(p);
  18108. p = cdr(p);
  18109. switch (type(x))
  18110. {
  18111. case T_INTEGER:
  18112. if (num_a != integer(x)) goto NOT_EQUAL;
  18113. break;
  18114. case T_RATIO:
  18115. case T_COMPLEX:
  18116. goto NOT_EQUAL;
  18117. case T_REAL:
  18118. if (num_a != real(x)) goto NOT_EQUAL;
  18119. break;
  18120. default:
  18121. method_or_bust_with_type(sc, x, sc->eq_symbol, cons(sc, make_integer(sc, num_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  18122. }
  18123. if (is_null(p))
  18124. return(sc->T);
  18125. }
  18126. case T_RATIO:
  18127. num_a = numerator(x);
  18128. den_a = denominator(x);
  18129. rl_a = 0.0;
  18130. while (true)
  18131. {
  18132. x = car(p);
  18133. p = cdr(p);
  18134. switch (type(x))
  18135. {
  18136. case T_INTEGER:
  18137. case T_COMPLEX:
  18138. goto NOT_EQUAL;
  18139. case T_RATIO:
  18140. if ((num_a != numerator(x)) || (den_a != denominator(x))) goto NOT_EQUAL; /* hidden cast here */
  18141. break;
  18142. case T_REAL:
  18143. if (rl_a == 0.0)
  18144. rl_a = ((long double)num_a) / ((long double)den_a);
  18145. if (rl_a != real(x)) goto NOT_EQUAL;
  18146. break;
  18147. default:
  18148. method_or_bust_with_type(sc, x, sc->eq_symbol, cons(sc, s7_make_ratio(sc, num_a, den_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  18149. }
  18150. if (is_null(p))
  18151. return(sc->T);
  18152. }
  18153. case T_REAL:
  18154. rl_a = real(x);
  18155. while (true)
  18156. {
  18157. x = car(p);
  18158. p = cdr(p);
  18159. switch (type(x))
  18160. {
  18161. case T_INTEGER:
  18162. if (rl_a != integer(x)) goto NOT_EQUAL;
  18163. break;
  18164. case T_RATIO:
  18165. if (rl_a != (double)fraction(x)) goto NOT_EQUAL;
  18166. /* the cast to double is needed because rl_a is s7_double and we want (= ratio real) to be the same as (= real ratio):
  18167. * (= 1.0 9223372036854775807/9223372036854775806)
  18168. * (= 9223372036854775807/9223372036854775806 1.0)
  18169. */
  18170. break;
  18171. case T_REAL:
  18172. if (rl_a != real(x)) goto NOT_EQUAL;
  18173. break;
  18174. case T_COMPLEX:
  18175. goto NOT_EQUAL;
  18176. default:
  18177. method_or_bust_with_type(sc, x, sc->eq_symbol, cons(sc, make_real(sc, rl_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  18178. }
  18179. if (is_null(p))
  18180. return(sc->T);
  18181. }
  18182. case T_COMPLEX:
  18183. rl_a = real_part(x);
  18184. im_a = imag_part(x);
  18185. while (true)
  18186. {
  18187. x = car(p);
  18188. p = cdr(p);
  18189. switch (type(x))
  18190. {
  18191. case T_INTEGER:
  18192. case T_RATIO:
  18193. case T_REAL:
  18194. goto NOT_EQUAL;
  18195. break;
  18196. case T_COMPLEX:
  18197. if ((rl_a != real_part(x)) || (im_a != imag_part(x)))
  18198. goto NOT_EQUAL;
  18199. break;
  18200. default:
  18201. method_or_bust_with_type(sc, x, sc->eq_symbol, cons(sc, s7_make_complex(sc, rl_a, im_a), cons(sc, x, p)), a_number_string, position_of(p, args) - 1);
  18202. }
  18203. if (is_null(p))
  18204. return(sc->T);
  18205. }
  18206. default:
  18207. method_or_bust_with_type(sc, x, sc->eq_symbol, args, a_number_string, 1);
  18208. }
  18209. NOT_EQUAL:
  18210. for (; is_pair(p); p = cdr(p))
  18211. if (!is_number_via_method(sc, car(p)))
  18212. return(wrong_type_argument_with_type(sc, sc->eq_symbol, position_of(p, args), car(p), a_number_string));
  18213. return(sc->F);
  18214. }
  18215. static s7_pointer equal_s_ic, equal_2;
  18216. static s7_pointer g_equal_s_ic(s7_scheme *sc, s7_pointer args)
  18217. {
  18218. s7_int y;
  18219. s7_pointer val;
  18220. val = find_symbol_checked(sc, car(args));
  18221. y = s7_integer(cadr(args));
  18222. if (is_integer(val))
  18223. return(make_boolean(sc, integer(val) == y));
  18224. switch (type(val))
  18225. {
  18226. case T_INTEGER: return(make_boolean(sc, integer(val) == y));
  18227. case T_RATIO: return(sc->F);
  18228. case T_REAL: return(make_boolean(sc, real(val) == y));
  18229. case T_COMPLEX: return(sc->F);
  18230. default:
  18231. method_or_bust_with_type(sc, val, sc->eq_symbol, list_2(sc, val, cadr(args)), a_number_string, 1);
  18232. }
  18233. return(sc->T);
  18234. }
  18235. static s7_int object_length_to_int(s7_scheme *sc, s7_pointer obj);
  18236. #if (!WITH_GMP)
  18237. static s7_pointer equal_length_ic;
  18238. static s7_pointer g_equal_length_ic(s7_scheme *sc, s7_pointer args)
  18239. {
  18240. /* avoid make_integer (and telescope opts), we get here with car=length expr, cadr=int */
  18241. s7_int ilen;
  18242. s7_pointer val;
  18243. val = find_symbol_checked(sc, cadar(args));
  18244. ilen = s7_integer(cadr(args));
  18245. switch (type(val))
  18246. {
  18247. case T_PAIR: return(make_boolean(sc, s7_list_length(sc, val) == ilen));
  18248. case T_NIL: return(make_boolean(sc, ilen == 0));
  18249. case T_STRING: return(make_boolean(sc, string_length(val) == ilen));
  18250. case T_HASH_TABLE: return(make_boolean(sc, (hash_table_mask(val) + 1) == ilen));
  18251. case T_ITERATOR: return(make_boolean(sc, iterator_length(val) == ilen));
  18252. case T_C_OBJECT: return(make_boolean(sc, object_length_to_int(sc, val) == ilen));
  18253. case T_LET: return(make_boolean(sc, let_length(sc, val) == ilen));
  18254. case T_INT_VECTOR:
  18255. case T_FLOAT_VECTOR:
  18256. case T_VECTOR: return(make_boolean(sc, vector_length(val) == ilen));
  18257. case T_CLOSURE:
  18258. case T_CLOSURE_STAR: if (has_methods(val)) return(make_boolean(sc, closure_length(sc, val) == ilen));
  18259. default: return(simple_wrong_type_argument_with_type(sc, sc->length_symbol, val, a_sequence_string));
  18260. /* here we already lost because we checked for the length above */
  18261. }
  18262. return(sc->F);
  18263. }
  18264. #endif
  18265. static s7_pointer c_equal_2_1(s7_scheme *sc, s7_pointer x, s7_pointer y)
  18266. {
  18267. switch (type(x))
  18268. {
  18269. case T_INTEGER:
  18270. switch (type(y))
  18271. {
  18272. case T_INTEGER: return(make_boolean(sc, integer(x) == integer(y)));
  18273. case T_RATIO: return(sc->F);
  18274. case T_REAL: return(make_boolean(sc, integer(x) == real(y)));
  18275. case T_COMPLEX: return(sc->F);
  18276. default:
  18277. method_or_bust_with_type(sc, y, sc->eq_symbol, list_2(sc, x, y), a_number_string, 2);
  18278. }
  18279. break;
  18280. case T_RATIO:
  18281. switch (type(y))
  18282. {
  18283. case T_INTEGER: return(sc->F);
  18284. case T_RATIO: return(make_boolean(sc, (numerator(x) == numerator(y)) && (denominator(x) == denominator(y))));
  18285. case T_REAL: return(make_boolean(sc, fraction(x) == real(y))); /* this could avoid the divide via numerator == denominator * x */
  18286. case T_COMPLEX: return(sc->F);
  18287. default:
  18288. method_or_bust_with_type(sc, y, sc->eq_symbol, list_2(sc, x, y), a_number_string, 2);
  18289. }
  18290. break;
  18291. case T_REAL:
  18292. switch (type(y))
  18293. {
  18294. case T_INTEGER: return(make_boolean(sc, real(x) == integer(y)));
  18295. case T_RATIO: return(make_boolean(sc, real(x) == fraction(y)));
  18296. case T_REAL: return(make_boolean(sc, real(x) == real(y)));
  18297. case T_COMPLEX: return(sc->F);
  18298. default:
  18299. method_or_bust_with_type(sc, y, sc->eq_symbol, list_2(sc, x, y), a_number_string, 2);
  18300. }
  18301. break;
  18302. case T_COMPLEX:
  18303. switch (type(y))
  18304. {
  18305. case T_INTEGER:
  18306. case T_RATIO:
  18307. case T_REAL:
  18308. return(sc->F);
  18309. #if (!MS_WINDOWS)
  18310. case T_COMPLEX:
  18311. return(make_boolean(sc, (real_part(x) == real_part(y)) && (imag_part(x) == imag_part(y))));
  18312. #else
  18313. case T_COMPLEX:
  18314. if ((real_part(x) == real_part(y)) && (imag_part(x) == imag_part(y))) return(sc->T); else return(sc->F);
  18315. #endif
  18316. default:
  18317. method_or_bust_with_type(sc, y, sc->eq_symbol, list_2(sc, x, y), a_number_string, 2);
  18318. }
  18319. break;
  18320. default:
  18321. method_or_bust_with_type(sc, x, sc->eq_symbol, list_2(sc, x, y), a_number_string, 1);
  18322. }
  18323. return(sc->F);
  18324. }
  18325. static s7_pointer c_equal_2(s7_scheme *sc, s7_pointer x, s7_pointer y)
  18326. {
  18327. #if (!MS_WINDOWS)
  18328. if (type(x) == type(y))
  18329. {
  18330. if (is_integer(x))
  18331. return(make_boolean(sc, integer(x) == integer(y)));
  18332. switch (type(x))
  18333. {
  18334. case T_INTEGER: return(make_boolean(sc, integer(x) == integer(y)));
  18335. case T_RATIO: return(make_boolean(sc, (numerator(x) == numerator(y)) && (denominator(x) == denominator(y))));
  18336. case T_REAL: return(make_boolean(sc, real(x) == real(y)));
  18337. case T_COMPLEX: return(make_boolean(sc, (real_part(x) == real_part(y)) && (imag_part(x) == imag_part(y))));
  18338. }
  18339. }
  18340. #endif
  18341. return(c_equal_2_1(sc, x, y));
  18342. }
  18343. static s7_pointer g_equal_2(s7_scheme *sc, s7_pointer args)
  18344. {
  18345. s7_pointer x, y;
  18346. x = car(args);
  18347. y = cadr(args);
  18348. #if (!MS_WINDOWS)
  18349. if (type(x) == type(y))
  18350. {
  18351. if (is_integer(x))
  18352. return(make_boolean(sc, integer(x) == integer(y)));
  18353. switch (type(x))
  18354. {
  18355. case T_INTEGER: return(make_boolean(sc, integer(x) == integer(y)));
  18356. case T_RATIO: return(make_boolean(sc, (numerator(x) == numerator(y)) && (denominator(x) == denominator(y))));
  18357. case T_REAL: return(make_boolean(sc, real(x) == real(y)));
  18358. case T_COMPLEX: return(make_boolean(sc, (real_part(x) == real_part(y)) && (imag_part(x) == imag_part(y))));
  18359. }
  18360. }
  18361. #endif
  18362. return(c_equal_2_1(sc, x, y));
  18363. }
  18364. #if (!WITH_GMP)
  18365. static s7_pointer equal_i2(s7_scheme *sc, s7_pointer **p)
  18366. {
  18367. s7_if_t f;
  18368. s7_int x, y;
  18369. f = (s7_if_t)(**p); (*p)++; x = f(sc, p);
  18370. f = (s7_if_t)(**p); (*p)++; y = f(sc, p);
  18371. return(make_boolean(sc, x == y));
  18372. }
  18373. static s7_pointer equal_i2_ic(s7_scheme *sc, s7_pointer **p)
  18374. {
  18375. s7_pointer x, y;
  18376. (*p)++;
  18377. x = slot_value(**p); (*p) += 2;
  18378. y = (**p); (*p)++;
  18379. if (!is_integer(x))
  18380. return(c_equal_2_1(sc, x, y));
  18381. return(make_boolean(sc, integer(x) == integer(y)));
  18382. }
  18383. static s7_pointer equal_i2_ii(s7_scheme *sc, s7_pointer **p)
  18384. {
  18385. s7_pointer x, y;
  18386. (*p)++;
  18387. x = slot_value(**p); (*p) += 2;
  18388. y = slot_value(**p); (*p)++;
  18389. if (!is_integer(x))
  18390. return(c_equal_2_1(sc, x, y));
  18391. return(make_boolean(sc, integer(x) == integer(y)));
  18392. }
  18393. static s7_pointer equal_r2(s7_scheme *sc, s7_pointer **p)
  18394. {
  18395. s7_rf_t f;
  18396. s7_double x, y;
  18397. f = (s7_rf_t)(**p); (*p)++; x = f(sc, p);
  18398. f = (s7_rf_t)(**p); (*p)++; y = f(sc, p);
  18399. return(make_boolean(sc, x == y));
  18400. }
  18401. static s7_pointer equal_p2(s7_scheme *sc, s7_pointer **p)
  18402. {
  18403. s7_pf_t f;
  18404. s7_pointer x, y;
  18405. f = (s7_pf_t)(**p); (*p)++; x = f(sc, p);
  18406. f = (s7_pf_t)(**p); (*p)++; y = f(sc, p);
  18407. return(c_equal_2(sc, x, y));
  18408. }
  18409. static s7_pf_t equal_pf(s7_scheme *sc, s7_pointer expr)
  18410. {
  18411. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_null(cdddr(expr))))
  18412. {
  18413. ptr_int loc;
  18414. s7_pointer a1, a2;
  18415. a1 = cadr(expr);
  18416. a2 = caddr(expr);
  18417. loc = rc_loc(sc);
  18418. if ((s7_arg_to_if(sc, cadr(expr))) && (s7_arg_to_if(sc, caddr(expr))))
  18419. {
  18420. if (is_symbol(a1))
  18421. {
  18422. if (is_integer(a2)) return(equal_i2_ic);
  18423. if (is_symbol(a2)) return(equal_i2_ii);
  18424. }
  18425. return(equal_i2);
  18426. }
  18427. sc->cur_rf->cur = rc_go(sc, loc);
  18428. if ((s7_arg_to_rf(sc, cadr(expr))) && (s7_arg_to_rf(sc, caddr(expr)))) return(equal_r2);
  18429. sc->cur_rf->cur = rc_go(sc, loc);
  18430. if ((s7_arg_to_pf(sc, cadr(expr))) && (s7_arg_to_pf(sc, caddr(expr)))) return(equal_p2);
  18431. }
  18432. return(NULL);
  18433. }
  18434. static s7_pointer g_less(s7_scheme *sc, s7_pointer args)
  18435. {
  18436. #define H_less "(< x1 ...) returns #t if its arguments are in increasing order"
  18437. #define Q_less s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  18438. s7_pointer x, y, p;
  18439. x = car(args);
  18440. p = cdr(args);
  18441. switch (type(x))
  18442. {
  18443. case T_INTEGER:
  18444. INTEGER_LESS:
  18445. y = car(p);
  18446. p = cdr(p);
  18447. switch (type(y))
  18448. {
  18449. case T_INTEGER:
  18450. if (integer(x) >= integer(y)) goto NOT_LESS;
  18451. if (is_null(p)) return(sc->T);
  18452. x = y;
  18453. goto INTEGER_LESS;
  18454. case T_RATIO:
  18455. /* no gmp here, but this can overflow: (< 9223372036 1/9223372036), but conversion to real is also problematic
  18456. */
  18457. if ((integer(x) >= 0) && (numerator(y) < 0)) goto NOT_LESS; /* (< 1 -1/2), ratio numerator can't be 0 */
  18458. if ((integer(x) <= 0) && (numerator(y) > 0)) /* (< 0 1/2) */
  18459. {
  18460. if (is_null(p)) return(sc->T);
  18461. x = y;
  18462. goto RATIO_LESS;
  18463. }
  18464. if ((integer(x) < s7_int32_max) &&
  18465. (integer(x) > s7_int32_min) &&
  18466. (denominator(y) < s7_int32_max))
  18467. {
  18468. if ((integer(x) * denominator(y)) >= numerator(y)) goto NOT_LESS;
  18469. }
  18470. else
  18471. {
  18472. if (integer(x) >= fraction(y)) goto NOT_LESS;
  18473. }
  18474. if (is_null(p)) return(sc->T);
  18475. x = y;
  18476. goto RATIO_LESS;
  18477. case T_REAL:
  18478. if (is_NaN(real(y))) goto NOT_LESS;
  18479. if (integer(x) >= real(y)) goto NOT_LESS;
  18480. if (is_null(p)) return(sc->T);
  18481. x = y;
  18482. goto REAL_LESS;
  18483. default:
  18484. method_or_bust(sc, y, sc->lt_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18485. }
  18486. case T_RATIO:
  18487. RATIO_LESS:
  18488. y = car(p);
  18489. p = cdr(p);
  18490. switch (type(y))
  18491. {
  18492. case T_INTEGER:
  18493. if ((numerator(x) > 0) && (integer(y) <= 0)) goto NOT_LESS;
  18494. if ((numerator(x) < 0) && (integer(y) >= 0))
  18495. {
  18496. if (is_null(p)) return(sc->T);
  18497. x = y;
  18498. goto INTEGER_LESS;
  18499. }
  18500. if ((integer(y) < s7_int32_max) &&
  18501. (integer(y) > s7_int32_min) &&
  18502. (denominator(x) < s7_int32_max))
  18503. {
  18504. if (numerator(x) >= (integer(y) * denominator(x))) goto NOT_LESS;
  18505. }
  18506. else
  18507. {
  18508. if (fraction(x) >= integer(y)) goto NOT_LESS;
  18509. }
  18510. if (is_null(p)) return(sc->T);
  18511. x = y;
  18512. goto INTEGER_LESS;
  18513. case T_RATIO:
  18514. /* conversion to real and >= is not safe here (see comment under g_greater) */
  18515. {
  18516. s7_int d1, d2, n1, n2;
  18517. d1 = denominator(x);
  18518. n1 = numerator(x);
  18519. d2 = denominator(y);
  18520. n2 = numerator(y);
  18521. if (d1 == d2)
  18522. {
  18523. if (n1 >= n2) goto NOT_LESS;
  18524. }
  18525. else
  18526. {
  18527. #if HAVE_OVERFLOW_CHECKS
  18528. if ((multiply_overflow(n1, d2, &n1)) ||
  18529. (multiply_overflow(n2, d1, &n2)))
  18530. {
  18531. if (fraction(x) >= fraction(y)) goto NOT_LESS;
  18532. }
  18533. else
  18534. {
  18535. if (n1 >= n2) goto NOT_LESS;
  18536. }
  18537. #else
  18538. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  18539. (n1 > s7_int32_max) || (n2 > s7_int32_max) ||
  18540. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  18541. {
  18542. int d1bits, d2bits;
  18543. d1bits = integer_length(d1);
  18544. d2bits = integer_length(d2);
  18545. if (((d1bits + d2bits) > s7_int_bits) ||
  18546. ((d1bits + integer_length(n2)) > (s7_int_bits - 1)) ||
  18547. ((d2bits + integer_length(n1)) > (s7_int_bits - 1)))
  18548. {
  18549. if (fraction(x) >= fraction(y)) goto NOT_LESS;
  18550. /* (< 21053343141/6701487259 3587785776203/1142027682075) -> #f because even long doubles aren't enough here
  18551. * (= 21053343141/6701487259 3587785776203/1142027682075) is #f because it checks the actual ints and
  18552. * (> 21053343141/6701487259 3587785776203/1142027682075) is #f just like the < case.
  18553. * similarly
  18554. * (min 21053343141/6701487259 3587785776203/1142027682075) -> 3587785776203/1142027682075
  18555. * (max 21053343141/6701487259 3587785776203/1142027682075) -> 3587785776203/1142027682075
  18556. *
  18557. * if we print the long double results as integers, both are -3958705157555305931
  18558. * so there's not a lot I can do in the non-gmp case.
  18559. */
  18560. }
  18561. else
  18562. {
  18563. if ((n1 * d2) >= (n2 * d1)) goto NOT_LESS;
  18564. }
  18565. }
  18566. else
  18567. {
  18568. if ((n1 * d2) >= (n2 * d1)) goto NOT_LESS;
  18569. }
  18570. #endif
  18571. }
  18572. }
  18573. if (is_null(p)) return(sc->T);
  18574. x = y;
  18575. goto RATIO_LESS;
  18576. case T_REAL:
  18577. if (is_NaN(real(y))) goto NOT_LESS;
  18578. if (fraction(x) >= real(y)) goto NOT_LESS;
  18579. if (is_null(p)) return(sc->T);
  18580. x = y;
  18581. goto REAL_LESS;
  18582. default:
  18583. method_or_bust(sc, y, sc->lt_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18584. }
  18585. case T_REAL:
  18586. if (is_NaN(real(x))) goto NOT_LESS;
  18587. REAL_LESS:
  18588. y = car(p);
  18589. p = cdr(p);
  18590. switch (type(y))
  18591. {
  18592. case T_INTEGER:
  18593. if (real(x) >= integer(y)) goto NOT_LESS;
  18594. if (is_null(p)) return(sc->T);
  18595. x = y;
  18596. goto INTEGER_LESS;
  18597. case T_RATIO:
  18598. if (real(x) >= fraction(y)) goto NOT_LESS;
  18599. if (is_null(p)) return(sc->T);
  18600. x = y;
  18601. goto RATIO_LESS;
  18602. case T_REAL:
  18603. if (is_NaN(real(y))) goto NOT_LESS;
  18604. if (real(x) >= real(y)) goto NOT_LESS;
  18605. if (is_null(p)) return(sc->T);
  18606. x = y;
  18607. goto REAL_LESS;
  18608. default:
  18609. method_or_bust(sc, y, sc->lt_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18610. }
  18611. default:
  18612. method_or_bust(sc, x, sc->lt_symbol, args, T_REAL, 1);
  18613. }
  18614. NOT_LESS:
  18615. for (; is_pair(p); p = cdr(p))
  18616. if (!is_real_via_method(sc, car(p)))
  18617. return(wrong_type_argument(sc, sc->lt_symbol, position_of(p, args), car(p), T_REAL));
  18618. return(sc->F);
  18619. }
  18620. static s7_pointer g_less_or_equal(s7_scheme *sc, s7_pointer args)
  18621. {
  18622. #define H_less_or_equal "(<= x1 ...) returns #t if its arguments are in increasing order"
  18623. #define Q_less_or_equal s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  18624. s7_pointer x, y, p;
  18625. x = car(args);
  18626. p = cdr(args);
  18627. switch (type(x))
  18628. {
  18629. case T_INTEGER:
  18630. INTEGER_LEQ:
  18631. y = car(p);
  18632. p = cdr(p);
  18633. switch (type(y))
  18634. {
  18635. case T_INTEGER:
  18636. if (integer(x) > integer(y)) goto NOT_LEQ;
  18637. if (is_null(p)) return(sc->T);
  18638. x = y;
  18639. goto INTEGER_LEQ;
  18640. case T_RATIO:
  18641. /* no gmp here, but this can overflow: (< 9223372036 1/9223372036), but conversion to real is also problematic
  18642. */
  18643. if ((integer(x) >= 0) && (numerator(y) < 0)) goto NOT_LEQ; /* (< 1 -1/2), ratio numerator can't be 0 */
  18644. if ((integer(x) <= 0) && (numerator(y) > 0)) /* (< 0 1/2) */
  18645. {
  18646. if (is_null(p)) return(sc->T);
  18647. x = y;
  18648. goto RATIO_LEQ;
  18649. }
  18650. if ((integer(x) < s7_int32_max) &&
  18651. (integer(x) > s7_int32_min) &&
  18652. (denominator(y) < s7_int32_max))
  18653. {
  18654. if ((integer(x) * denominator(y)) > numerator(y)) goto NOT_LEQ;
  18655. }
  18656. else
  18657. {
  18658. if (integer(x) > fraction(y)) goto NOT_LEQ;
  18659. }
  18660. if (is_null(p)) return(sc->T);
  18661. x = y;
  18662. goto RATIO_LEQ;
  18663. case T_REAL:
  18664. if (is_NaN(real(y))) goto NOT_LEQ;
  18665. if (integer(x) > real(y)) goto NOT_LEQ;
  18666. if (is_null(p)) return(sc->T);
  18667. x = y;
  18668. goto REAL_LEQ;
  18669. default:
  18670. method_or_bust(sc, y, sc->leq_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18671. }
  18672. case T_RATIO:
  18673. RATIO_LEQ:
  18674. y = car(p);
  18675. p = cdr(p);
  18676. switch (type(y))
  18677. {
  18678. case T_INTEGER:
  18679. if ((numerator(x) > 0) && (integer(y) <= 0)) goto NOT_LEQ;
  18680. if ((numerator(x) < 0) && (integer(y) >= 0))
  18681. {
  18682. if (is_null(p)) return(sc->T);
  18683. x = y;
  18684. goto INTEGER_LEQ;
  18685. }
  18686. if ((integer(y) < s7_int32_max) &&
  18687. (integer(y) > s7_int32_min) &&
  18688. (denominator(x) < s7_int32_max))
  18689. {
  18690. if (numerator(x) > (integer(y) * denominator(x))) goto NOT_LEQ;
  18691. }
  18692. else
  18693. {
  18694. if (fraction(x) > integer(y)) goto NOT_LEQ;
  18695. }
  18696. if (is_null(p)) return(sc->T);
  18697. x = y;
  18698. goto INTEGER_LEQ;
  18699. case T_RATIO:
  18700. {
  18701. s7_int d1, d2, n1, n2;
  18702. d1 = denominator(x);
  18703. n1 = numerator(x);
  18704. d2 = denominator(y);
  18705. n2 = numerator(y);
  18706. if (d1 == d2)
  18707. {
  18708. if (n1 > n2) goto NOT_LEQ;
  18709. }
  18710. else
  18711. {
  18712. #if HAVE_OVERFLOW_CHECKS
  18713. if ((multiply_overflow(n1, d2, &n1)) ||
  18714. (multiply_overflow(n2, d1, &n2)))
  18715. {
  18716. if (fraction(x) > fraction(y)) goto NOT_LEQ;
  18717. }
  18718. else
  18719. {
  18720. if (n1 > n2) goto NOT_LEQ;
  18721. }
  18722. #else
  18723. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  18724. (n1 > s7_int32_max) || (n2 > s7_int32_max) ||
  18725. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  18726. {
  18727. int d1bits, d2bits;
  18728. d1bits = integer_length(d1);
  18729. d2bits = integer_length(d2);
  18730. if (((d1bits + d2bits) > s7_int_bits) ||
  18731. ((d1bits + integer_length(n2)) > (s7_int_bits - 1)) ||
  18732. ((d2bits + integer_length(n1)) > (s7_int_bits - 1)))
  18733. {
  18734. if (fraction(x) > fraction(y)) goto NOT_LEQ;
  18735. }
  18736. else
  18737. {
  18738. if ((n1 * d2) > (n2 * d1)) goto NOT_LEQ;
  18739. }
  18740. }
  18741. else
  18742. {
  18743. if ((n1 * d2) > (n2 * d1)) goto NOT_LEQ;
  18744. }
  18745. #endif
  18746. }
  18747. }
  18748. if (is_null(p)) return(sc->T);
  18749. x = y;
  18750. goto RATIO_LEQ;
  18751. case T_REAL:
  18752. if (is_NaN(real(y))) goto NOT_LEQ;
  18753. if (fraction(x) > real(y)) goto NOT_LEQ;
  18754. if (is_null(p)) return(sc->T);
  18755. x = y;
  18756. goto REAL_LEQ;
  18757. default:
  18758. method_or_bust(sc, y, sc->leq_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18759. }
  18760. case T_REAL:
  18761. if (is_NaN(real(x))) goto NOT_LEQ;
  18762. REAL_LEQ:
  18763. y = car(p);
  18764. p = cdr(p);
  18765. switch (type(y))
  18766. {
  18767. case T_INTEGER:
  18768. if (real(x) > integer(y)) goto NOT_LEQ;
  18769. if (is_null(p)) return(sc->T);
  18770. x = y;
  18771. goto INTEGER_LEQ;
  18772. case T_RATIO:
  18773. if (real(x) > fraction(y)) goto NOT_LEQ;
  18774. if (is_null(p)) return(sc->T);
  18775. x = y;
  18776. goto RATIO_LEQ;
  18777. case T_REAL:
  18778. if (is_NaN(real(y))) goto NOT_LEQ;
  18779. if (real(x) > real(y)) goto NOT_LEQ;
  18780. if (is_null(p)) return(sc->T);
  18781. x = y;
  18782. goto REAL_LEQ;
  18783. default:
  18784. method_or_bust(sc, y, sc->leq_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18785. }
  18786. default:
  18787. method_or_bust(sc, x, sc->leq_symbol, args, T_REAL, 1);
  18788. }
  18789. NOT_LEQ:
  18790. for (; is_pair(p); p = cdr(p))
  18791. if (!is_real_via_method(sc, car(p)))
  18792. return(wrong_type_argument(sc, sc->leq_symbol, position_of(p, args), car(p), T_REAL));
  18793. return(sc->F);
  18794. }
  18795. static s7_pointer g_greater(s7_scheme *sc, s7_pointer args)
  18796. {
  18797. #define H_greater "(> x1 ...) returns #t if its arguments are in decreasing order"
  18798. #define Q_greater s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  18799. s7_pointer x, y, p;
  18800. x = car(args);
  18801. p = cdr(args);
  18802. switch (type(x))
  18803. {
  18804. case T_INTEGER:
  18805. INTEGER_GREATER:
  18806. y = car(p);
  18807. p = cdr(p);
  18808. switch (type(y))
  18809. {
  18810. case T_INTEGER:
  18811. if (integer(x) <= integer(y)) goto NOT_GREATER;
  18812. if (is_null(p)) return(sc->T);
  18813. x = y;
  18814. goto INTEGER_GREATER;
  18815. case T_RATIO:
  18816. /* no gmp here, but this can overflow: (< 9223372036 1/9223372036), but conversion to real is also problematic
  18817. */
  18818. if ((integer(x) <= 0) && (numerator(y) > 0)) goto NOT_GREATER;
  18819. if ((integer(x) >= 0) && (numerator(y) < 0))
  18820. {
  18821. if (is_null(p)) return(sc->T);
  18822. x = y;
  18823. goto RATIO_GREATER;
  18824. }
  18825. if ((integer(x) < s7_int32_max) &&
  18826. (integer(x) > s7_int32_min) &&
  18827. (denominator(y) < s7_int32_max))
  18828. {
  18829. if ((integer(x) * denominator(y)) <= numerator(y)) goto NOT_GREATER;
  18830. }
  18831. else
  18832. {
  18833. if (integer(x) <= fraction(y)) goto NOT_GREATER;
  18834. }
  18835. if (is_null(p)) return(sc->T);
  18836. x = y;
  18837. goto RATIO_GREATER;
  18838. case T_REAL:
  18839. if (is_NaN(real(y))) goto NOT_GREATER;
  18840. if (integer(x) <= real(y)) goto NOT_GREATER;
  18841. if (is_null(p)) return(sc->T);
  18842. x = y;
  18843. goto REAL_GREATER;
  18844. default:
  18845. method_or_bust(sc, y, sc->gt_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18846. }
  18847. case T_RATIO:
  18848. RATIO_GREATER:
  18849. y = car(p);
  18850. p = cdr(p);
  18851. switch (type(y))
  18852. {
  18853. case T_INTEGER:
  18854. if ((numerator(x) < 0) && (integer(y) >= 0)) goto NOT_GREATER;
  18855. if ((numerator(x) > 0) && (integer(y) <= 0))
  18856. {
  18857. if (is_null(p)) return(sc->T);
  18858. x = y;
  18859. goto INTEGER_GREATER;
  18860. }
  18861. if ((integer(y) < s7_int32_max) &&
  18862. (integer(y) > s7_int32_min) &&
  18863. (denominator(x) < s7_int32_max))
  18864. {
  18865. if (numerator(x) <= (integer(y) * denominator(x))) goto NOT_GREATER;
  18866. }
  18867. else
  18868. {
  18869. if (fraction(x) <= integer(y)) goto NOT_GREATER;
  18870. }
  18871. if (is_null(p)) return(sc->T);
  18872. x = y;
  18873. goto INTEGER_GREATER;
  18874. case T_RATIO:
  18875. {
  18876. s7_int d1, d2, n1, n2;
  18877. d1 = denominator(x);
  18878. n1 = numerator(x);
  18879. d2 = denominator(y);
  18880. n2 = numerator(y);
  18881. if (d1 == d2)
  18882. {
  18883. if (n1 <= n2) goto NOT_GREATER;
  18884. }
  18885. else
  18886. {
  18887. #if HAVE_OVERFLOW_CHECKS
  18888. if ((multiply_overflow(n1, d2, &n1)) ||
  18889. (multiply_overflow(n2, d1, &n2)))
  18890. {
  18891. if (fraction(x) <= fraction(y)) goto NOT_GREATER;
  18892. }
  18893. else
  18894. {
  18895. if (n1 <= n2) goto NOT_GREATER;
  18896. }
  18897. #else
  18898. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  18899. (n1 > s7_int32_max) || (n2 > s7_int32_max) ||
  18900. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  18901. {
  18902. int d1bits, d2bits;
  18903. d1bits = integer_length(d1);
  18904. d2bits = integer_length(d2);
  18905. if (((d1bits + d2bits) > s7_int_bits) ||
  18906. ((d1bits + integer_length(n2)) > (s7_int_bits - 1)) ||
  18907. ((d2bits + integer_length(n1)) > (s7_int_bits - 1)))
  18908. {
  18909. if (fraction(x) <= fraction(y)) goto NOT_GREATER;
  18910. /* (< 21053343141/6701487259 3587785776203/1142027682075) -> #f because even long doubles aren't enough here
  18911. * (= 21053343141/6701487259 3587785776203/1142027682075) is #f because it checks the actual ints and
  18912. * (> 21053343141/6701487259 3587785776203/1142027682075) is #f just like the < case.
  18913. * similarly
  18914. * (min 21053343141/6701487259 3587785776203/1142027682075) -> 3587785776203/1142027682075
  18915. * (max 21053343141/6701487259 3587785776203/1142027682075) -> 3587785776203/1142027682075
  18916. *
  18917. * if we print the long double results as integers, both are -3958705157555305931
  18918. * so there's not a lot I can do in the non-gmp case.
  18919. */
  18920. }
  18921. else
  18922. {
  18923. if ((n1 * d2) <= (n2 * d1)) goto NOT_GREATER;
  18924. }
  18925. }
  18926. else
  18927. {
  18928. if ((n1 * d2) <= (n2 * d1)) goto NOT_GREATER;
  18929. }
  18930. #endif
  18931. }
  18932. }
  18933. if (is_null(p)) return(sc->T);
  18934. x = y;
  18935. goto RATIO_GREATER;
  18936. case T_REAL:
  18937. if (is_NaN(real(y))) goto NOT_GREATER;
  18938. if (fraction(x) <= real(y)) goto NOT_GREATER;
  18939. if (is_null(p)) return(sc->T);
  18940. x = y;
  18941. goto REAL_GREATER;
  18942. default:
  18943. method_or_bust(sc, y, sc->gt_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18944. }
  18945. case T_REAL:
  18946. if (is_NaN(real(x))) goto NOT_GREATER;
  18947. REAL_GREATER:
  18948. y = car(p);
  18949. p = cdr(p);
  18950. switch (type(y))
  18951. {
  18952. case T_INTEGER:
  18953. if (real(x) <= integer(y)) goto NOT_GREATER;
  18954. if (is_null(p)) return(sc->T);
  18955. x = y;
  18956. goto INTEGER_GREATER;
  18957. case T_RATIO:
  18958. if (real(x) <= fraction(y)) goto NOT_GREATER;
  18959. if (is_null(p)) return(sc->T);
  18960. x = y;
  18961. goto RATIO_GREATER;
  18962. case T_REAL:
  18963. if (is_NaN(real(y))) goto NOT_GREATER;
  18964. if (real(x) <= real(y)) goto NOT_GREATER;
  18965. if (is_null(p)) return(sc->T);
  18966. x = y;
  18967. goto REAL_GREATER;
  18968. default:
  18969. method_or_bust(sc, y, sc->gt_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  18970. }
  18971. default:
  18972. method_or_bust(sc, x, sc->gt_symbol, args, T_REAL, 1);
  18973. }
  18974. NOT_GREATER:
  18975. for (; is_pair(p); p = cdr(p))
  18976. if (!is_real_via_method(sc, car(p)))
  18977. return(wrong_type_argument(sc, sc->gt_symbol, position_of(p, args), car(p), T_REAL));
  18978. return(sc->F);
  18979. }
  18980. static s7_pointer g_greater_or_equal(s7_scheme *sc, s7_pointer args)
  18981. {
  18982. #define H_greater_or_equal "(>= x1 ...) returns #t if its arguments are in decreasing order"
  18983. #define Q_greater_or_equal s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  18984. /* (>= 1+i 1+i) is an error which seems unfortunate */
  18985. s7_pointer x, y, p;
  18986. x = car(args);
  18987. p = cdr(args);
  18988. switch (type(x))
  18989. {
  18990. case T_INTEGER:
  18991. INTEGER_GEQ:
  18992. y = car(p);
  18993. p = cdr(p);
  18994. switch (type(y))
  18995. {
  18996. case T_INTEGER:
  18997. if (integer(x) < integer(y)) goto NOT_GEQ;
  18998. if (is_null(p)) return(sc->T);
  18999. x = y;
  19000. goto INTEGER_GEQ;
  19001. case T_RATIO:
  19002. /* no gmp here, but this can overflow: (< 9223372036 1/9223372036), but conversion to real is also problematic
  19003. */
  19004. if ((integer(x) <= 0) && (numerator(y) > 0)) goto NOT_GEQ;
  19005. if ((integer(x) >= 0) && (numerator(y) < 0))
  19006. {
  19007. if (is_null(p)) return(sc->T);
  19008. x = y;
  19009. goto RATIO_GEQ;
  19010. }
  19011. if ((integer(x) < s7_int32_max) &&
  19012. (integer(x) > s7_int32_min) &&
  19013. (denominator(y) < s7_int32_max))
  19014. {
  19015. if ((integer(x) * denominator(y)) < numerator(y)) goto NOT_GEQ;
  19016. }
  19017. else
  19018. {
  19019. if (integer(x) < fraction(y)) goto NOT_GEQ;
  19020. }
  19021. if (is_null(p)) return(sc->T);
  19022. x = y;
  19023. goto RATIO_GEQ;
  19024. case T_REAL:
  19025. if (is_NaN(real(y))) goto NOT_GEQ;
  19026. if (integer(x) < real(y)) goto NOT_GEQ;
  19027. if (is_null(p)) return(sc->T);
  19028. x = y;
  19029. goto REAL_GEQ;
  19030. default:
  19031. method_or_bust(sc, y, sc->geq_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  19032. }
  19033. case T_RATIO:
  19034. RATIO_GEQ:
  19035. y = car(p);
  19036. p = cdr(p);
  19037. switch (type(y))
  19038. {
  19039. case T_INTEGER:
  19040. if ((numerator(x) < 0) && (integer(y) >= 0)) goto NOT_GEQ;
  19041. if ((numerator(x) > 0) && (integer(y) <= 0))
  19042. {
  19043. if (is_null(p)) return(sc->T);
  19044. x = y;
  19045. goto INTEGER_GEQ;
  19046. }
  19047. if ((integer(y) < s7_int32_max) &&
  19048. (integer(y) > s7_int32_min) &&
  19049. (denominator(x) < s7_int32_max))
  19050. {
  19051. if (numerator(x) < (integer(y) * denominator(x))) goto NOT_GEQ;
  19052. }
  19053. else
  19054. {
  19055. if (fraction(x) < integer(y)) goto NOT_GEQ;
  19056. }
  19057. if (is_null(p)) return(sc->T);
  19058. x = y;
  19059. goto INTEGER_GEQ;
  19060. case T_RATIO:
  19061. {
  19062. s7_int d1, d2, n1, n2;
  19063. d1 = denominator(x);
  19064. n1 = numerator(x);
  19065. d2 = denominator(y);
  19066. n2 = numerator(y);
  19067. if (d1 == d2)
  19068. {
  19069. if (n1 < n2) goto NOT_GEQ;
  19070. }
  19071. else
  19072. {
  19073. #if HAVE_OVERFLOW_CHECKS
  19074. if ((multiply_overflow(n1, d2, &n1)) ||
  19075. (multiply_overflow(n2, d1, &n2)))
  19076. {
  19077. if (fraction(x) < fraction(y)) goto NOT_GEQ;
  19078. }
  19079. else
  19080. {
  19081. if (n1 < n2) goto NOT_GEQ;
  19082. }
  19083. #else
  19084. if ((d1 > s7_int32_max) || (d2 > s7_int32_max) || /* before counting bits, check that overflow is possible */
  19085. (n1 > s7_int32_max) || (n2 > s7_int32_max) ||
  19086. (n1 < s7_int32_min) || (n2 < s7_int32_min))
  19087. {
  19088. int d1bits, d2bits;
  19089. d1bits = integer_length(d1);
  19090. d2bits = integer_length(d2);
  19091. if (((d1bits + d2bits) > s7_int_bits) ||
  19092. ((d1bits + integer_length(n2)) > (s7_int_bits - 1)) ||
  19093. ((d2bits + integer_length(n1)) > (s7_int_bits - 1)))
  19094. {
  19095. if (fraction(x) < fraction(y)) goto NOT_GEQ;
  19096. }
  19097. else
  19098. {
  19099. if ((n1 * d2) < (n2 * d1)) goto NOT_GEQ;
  19100. }
  19101. }
  19102. else
  19103. {
  19104. if ((n1 * d2) < (n2 * d1)) goto NOT_GEQ;
  19105. }
  19106. #endif
  19107. }
  19108. }
  19109. if (is_null(p)) return(sc->T);
  19110. x = y;
  19111. goto RATIO_GEQ;
  19112. case T_REAL:
  19113. if (is_NaN(real(y))) goto NOT_GEQ;
  19114. if (fraction(x) < real(y)) goto NOT_GEQ;
  19115. if (is_null(p)) return(sc->T);
  19116. x = y;
  19117. goto REAL_GEQ;
  19118. default:
  19119. method_or_bust(sc, y, sc->geq_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  19120. }
  19121. case T_REAL:
  19122. if (is_NaN(real(x))) goto NOT_GEQ;
  19123. REAL_GEQ:
  19124. y = car(p);
  19125. p = cdr(p);
  19126. switch (type(y))
  19127. {
  19128. case T_INTEGER:
  19129. if (real(x) < integer(y)) goto NOT_GEQ;
  19130. if (is_null(p)) return(sc->T);
  19131. x = y;
  19132. goto INTEGER_GEQ;
  19133. case T_RATIO:
  19134. if (real(x) < fraction(y)) goto NOT_GEQ;
  19135. if (is_null(p)) return(sc->T);
  19136. x = y;
  19137. goto RATIO_GEQ;
  19138. case T_REAL:
  19139. if (is_NaN(real(y))) goto NOT_GEQ;
  19140. if (real(x) < real(y)) goto NOT_GEQ;
  19141. if (is_null(p)) return(sc->T);
  19142. x = y;
  19143. goto REAL_GEQ;
  19144. default:
  19145. method_or_bust(sc, y, sc->geq_symbol, cons(sc, x, cons(sc, y, p)), T_REAL, position_of(p, args) - 1);
  19146. }
  19147. default:
  19148. method_or_bust(sc, x, sc->geq_symbol, args, T_REAL, 1);
  19149. }
  19150. NOT_GEQ:
  19151. for (; is_pair(p); p = cdr(p))
  19152. if (!is_real_via_method(sc, car(p)))
  19153. return(wrong_type_argument(sc, sc->geq_symbol, position_of(p, args), car(p), T_REAL));
  19154. return(sc->F);
  19155. }
  19156. static s7_pointer less_s_ic, less_s0;
  19157. static s7_pointer g_less_s0(s7_scheme *sc, s7_pointer args)
  19158. {
  19159. s7_pointer x;
  19160. x = car(args);
  19161. if (is_integer(x))
  19162. return(make_boolean(sc, integer(x) < 0));
  19163. if (is_real(x))
  19164. return(make_boolean(sc, s7_is_negative(x)));
  19165. method_or_bust(sc, x, sc->lt_symbol, args, T_REAL, 1);
  19166. }
  19167. static s7_pointer g_less_s_ic(s7_scheme *sc, s7_pointer args)
  19168. {
  19169. s7_int y;
  19170. s7_pointer x;
  19171. x = car(args);
  19172. y = integer(cadr(args));
  19173. if (is_integer(x))
  19174. return(make_boolean(sc, integer(x) < y));
  19175. switch (type(x))
  19176. {
  19177. case T_INTEGER:
  19178. return(make_boolean(sc, integer(x) < y));
  19179. case T_RATIO:
  19180. if ((y >= 0) && (numerator(x) < 0))
  19181. return(sc->T);
  19182. if ((y <= 0) && (numerator(x) > 0))
  19183. return(sc->F);
  19184. if (denominator(x) < s7_int32_max)
  19185. return(make_boolean(sc, (numerator(x) < (y * denominator(x)))));
  19186. return(make_boolean(sc, fraction(x) < y));
  19187. case T_REAL:
  19188. return(make_boolean(sc, real(x) < y));
  19189. case T_COMPLEX:
  19190. default:
  19191. method_or_bust(sc, x, sc->lt_symbol, args, T_REAL, 1);
  19192. }
  19193. return(sc->T);
  19194. }
  19195. static s7_pointer less_length_ic;
  19196. static s7_pointer g_less_length_ic(s7_scheme *sc, s7_pointer args)
  19197. {
  19198. s7_int ilen;
  19199. s7_pointer val;
  19200. val = find_symbol_checked(sc, cadar(args));
  19201. ilen = s7_integer(cadr(args));
  19202. switch (type(val))
  19203. {
  19204. case T_PAIR: return(make_boolean(sc, s7_list_length(sc, val) < ilen));
  19205. case T_NIL: return(make_boolean(sc, ilen > 0));
  19206. case T_STRING: return(make_boolean(sc, string_length(val) < ilen));
  19207. case T_HASH_TABLE: return(make_boolean(sc, hash_table_mask(val) < ilen)); /* was <=? -- changed 15-Dec-15 */
  19208. case T_ITERATOR: return(make_boolean(sc, iterator_length(val) < ilen));
  19209. case T_C_OBJECT: return(make_boolean(sc, object_length_to_int(sc, val) < ilen));
  19210. case T_LET: return(make_boolean(sc, let_length(sc, val) < ilen)); /* this works because let_length handles the length method itself! */
  19211. case T_INT_VECTOR:
  19212. case T_FLOAT_VECTOR:
  19213. case T_VECTOR: return(make_boolean(sc, vector_length(val) < ilen));
  19214. case T_CLOSURE:
  19215. case T_CLOSURE_STAR: if (has_methods(val)) return(make_boolean(sc, closure_length(sc, val) < ilen));
  19216. default: return(simple_wrong_type_argument_with_type(sc, sc->length_symbol, val, a_sequence_string)); /* no check method here because we checked above */
  19217. }
  19218. return(sc->F);
  19219. }
  19220. static s7_pointer c_less_2_1(s7_scheme *sc, s7_pointer x, s7_pointer y)
  19221. {
  19222. switch (type(x))
  19223. {
  19224. case T_INTEGER:
  19225. switch (type(y))
  19226. {
  19227. case T_INTEGER:
  19228. return(make_boolean(sc, integer(x) < integer(y)));
  19229. case T_RATIO:
  19230. return(g_less(sc, list_2(sc, x, y)));
  19231. case T_REAL:
  19232. if (is_NaN(real(y))) return(sc->F);
  19233. return(make_boolean(sc, integer(x) < real(y)));
  19234. default:
  19235. method_or_bust(sc, y, sc->lt_symbol, list_2(sc, x, y), T_REAL, 2);
  19236. }
  19237. break;
  19238. case T_RATIO:
  19239. return(g_less(sc, list_2(sc, x, y)));
  19240. case T_REAL:
  19241. switch (type(y))
  19242. {
  19243. case T_INTEGER:
  19244. if (is_NaN(real(x))) return(sc->F);
  19245. return(make_boolean(sc, real(x) < integer(y)));
  19246. case T_RATIO:
  19247. if (is_NaN(real(x))) return(sc->F);
  19248. return(make_boolean(sc, real(x) < fraction(y)));
  19249. case T_REAL:
  19250. if (is_NaN(real(x))) return(sc->F);
  19251. if (is_NaN(real(y))) return(sc->F);
  19252. return(make_boolean(sc, real(x) < real(y)));
  19253. default:
  19254. method_or_bust(sc, y, sc->lt_symbol, list_2(sc, x, y), T_REAL, 2);
  19255. }
  19256. break;
  19257. default:
  19258. method_or_bust(sc, x, sc->lt_symbol, list_2(sc, x, y), T_REAL, 1);
  19259. }
  19260. return(sc->T);
  19261. }
  19262. static s7_pointer c_less_2(s7_scheme *sc, s7_pointer x, s7_pointer y)
  19263. {
  19264. #if (!MS_WINDOWS)
  19265. if (type(x) == type(y))
  19266. {
  19267. switch (type(x))
  19268. {
  19269. case T_INTEGER: return(make_boolean(sc, integer(x) < integer(y)));
  19270. case T_RATIO: return(make_boolean(sc, fraction(x) < fraction(y)));
  19271. case T_REAL: return(make_boolean(sc, real(x) < real(y)));
  19272. }
  19273. }
  19274. #endif
  19275. return(c_less_2_1(sc, x, y));
  19276. }
  19277. static s7_pointer less_2;
  19278. static s7_pointer g_less_2(s7_scheme *sc, s7_pointer args)
  19279. {
  19280. s7_pointer x, y;
  19281. x = car(args);
  19282. y = cadr(args);
  19283. #if (!MS_WINDOWS)
  19284. if (type(x) == type(y))
  19285. {
  19286. switch (type(x))
  19287. {
  19288. case T_INTEGER: return(make_boolean(sc, integer(x) < integer(y)));
  19289. case T_RATIO: return(make_boolean(sc, fraction(x) < fraction(y)));
  19290. case T_REAL: return(make_boolean(sc, real(x) < real(y)));
  19291. }
  19292. }
  19293. #endif
  19294. return(c_less_2_1(sc, x, y));
  19295. }
  19296. static s7_pointer c_less_i(s7_scheme *sc, s7_int x, s7_int y) {return(make_boolean(sc, x < y));}
  19297. static s7_pointer c_less_r(s7_scheme *sc, s7_double x, s7_double y) {return(make_boolean(sc, x < y));}
  19298. XF2_TO_PF(less, c_less_i, c_less_r, c_less_2)
  19299. static s7_pointer leq_s_ic;
  19300. static s7_pointer g_leq_s_ic(s7_scheme *sc, s7_pointer args)
  19301. {
  19302. s7_int y;
  19303. s7_pointer x;
  19304. x = car(args);
  19305. y = s7_integer(cadr(args));
  19306. switch (type(x))
  19307. {
  19308. case T_INTEGER:
  19309. return(make_boolean(sc, integer(x) <= y));
  19310. case T_RATIO:
  19311. if ((y >= 0) && (numerator(x) <= 0))
  19312. return(sc->T);
  19313. if ((y <= 0) && (numerator(x) > 0))
  19314. return(sc->F);
  19315. if (denominator(x) < s7_int32_max)
  19316. return(make_boolean(sc, (numerator(x) <= (y * denominator(x)))));
  19317. return(make_boolean(sc, fraction(x) <= y));
  19318. case T_REAL:
  19319. return(make_boolean(sc, real(x) <= y));
  19320. default:
  19321. method_or_bust(sc, x, sc->leq_symbol, args, T_REAL, 1);
  19322. }
  19323. return(sc->T);
  19324. }
  19325. static s7_pointer c_leq_2_1(s7_scheme *sc, s7_pointer x, s7_pointer y)
  19326. {
  19327. switch (type(x))
  19328. {
  19329. case T_INTEGER:
  19330. switch (type(y))
  19331. {
  19332. case T_INTEGER:
  19333. return(make_boolean(sc, integer(x) <= integer(y)));
  19334. case T_RATIO:
  19335. return(g_less_or_equal(sc, list_2(sc, x, y)));
  19336. case T_REAL:
  19337. if (is_NaN(real(y))) return(sc->F);
  19338. return(make_boolean(sc, integer(x) <= real(y)));
  19339. default:
  19340. method_or_bust(sc, y, sc->leq_symbol, list_2(sc, x, y), T_REAL, 2);
  19341. }
  19342. break;
  19343. case T_RATIO:
  19344. return(g_less_or_equal(sc, list_2(sc, x, y)));
  19345. case T_REAL:
  19346. switch (type(y))
  19347. {
  19348. case T_INTEGER:
  19349. if (is_NaN(real(x))) return(sc->F);
  19350. return(make_boolean(sc, real(x) <= integer(y)));
  19351. case T_RATIO:
  19352. if (is_NaN(real(x))) return(sc->F);
  19353. return(make_boolean(sc, real(x) <= fraction(y)));
  19354. case T_REAL:
  19355. if (is_NaN(real(x))) return(sc->F);
  19356. if (is_NaN(real(y))) return(sc->F);
  19357. return(make_boolean(sc, real(x) <= real(y)));
  19358. default:
  19359. method_or_bust(sc, y, sc->leq_symbol, list_2(sc, x, y), T_REAL, 2);
  19360. }
  19361. break;
  19362. default:
  19363. method_or_bust(sc, x, sc->leq_symbol, list_2(sc, x, y), T_REAL, 1);
  19364. }
  19365. return(sc->T);
  19366. }
  19367. static s7_pointer c_leq_2(s7_scheme *sc, s7_pointer x, s7_pointer y)
  19368. {
  19369. #if (!MS_WINDOWS)
  19370. if (type(x) == type(y))
  19371. {
  19372. switch (type(x))
  19373. {
  19374. case T_INTEGER: return(make_boolean(sc, integer(x) <= integer(y)));
  19375. case T_RATIO: return(make_boolean(sc, fraction(x) <= fraction(y)));
  19376. case T_REAL: return(make_boolean(sc, real(x) <= real(y)));
  19377. }
  19378. }
  19379. #endif
  19380. return(c_leq_2_1(sc, x, y));
  19381. }
  19382. static s7_pointer leq_2;
  19383. static s7_pointer g_leq_2(s7_scheme *sc, s7_pointer args)
  19384. {
  19385. s7_pointer x, y;
  19386. x = car(args);
  19387. y = cadr(args);
  19388. #if (!MS_WINDOWS)
  19389. if (type(x) == type(y))
  19390. {
  19391. switch (type(x))
  19392. {
  19393. case T_INTEGER: return(make_boolean(sc, integer(x) <= integer(y)));
  19394. case T_RATIO: return(make_boolean(sc, fraction(x) <= fraction(y)));
  19395. case T_REAL: return(make_boolean(sc, real(x) <= real(y)));
  19396. }
  19397. }
  19398. #endif
  19399. return(c_leq_2_1(sc, x, y));
  19400. }
  19401. static s7_pointer c_leq_i(s7_scheme *sc, s7_int x, s7_int y) {return(make_boolean(sc, x <= y));}
  19402. static s7_pointer c_leq_r(s7_scheme *sc, s7_double x, s7_double y) {return(make_boolean(sc, x <= y));}
  19403. XF2_TO_PF(leq, c_leq_i, c_leq_r, c_leq_2)
  19404. static s7_pointer greater_s_ic, greater_s_fc;
  19405. static s7_pointer g_greater_s_ic(s7_scheme *sc, s7_pointer args)
  19406. {
  19407. s7_int y;
  19408. s7_pointer x;
  19409. x = car(args);
  19410. y = integer(cadr(args));
  19411. switch (type(x))
  19412. {
  19413. case T_INTEGER:
  19414. return(make_boolean(sc, integer(x) > y));
  19415. case T_RATIO:
  19416. if (denominator(x) < s7_int32_max) /* y has already been checked for range */
  19417. return(make_boolean(sc, (numerator(x) > (y * denominator(x)))));
  19418. return(make_boolean(sc, fraction(x) > y));
  19419. case T_REAL:
  19420. return(make_boolean(sc, real(x) > y));
  19421. default:
  19422. method_or_bust_with_type(sc, x, sc->gt_symbol, args, a_number_string, 1);
  19423. }
  19424. return(sc->T);
  19425. }
  19426. static s7_pointer g_greater_s_fc(s7_scheme *sc, s7_pointer args)
  19427. {
  19428. s7_double y;
  19429. s7_pointer x;
  19430. x = car(args);
  19431. y = real(cadr(args));
  19432. if (is_t_real(x))
  19433. return(make_boolean(sc, real(x) > y));
  19434. switch (type(x))
  19435. {
  19436. case T_INTEGER:
  19437. return(make_boolean(sc, integer(x) > y));
  19438. case T_RATIO:
  19439. /* (> 9223372036854775807/9223372036854775806 1.0) */
  19440. if (denominator(x) < s7_int32_max) /* y range check was handled in greater_chooser */
  19441. return(make_boolean(sc, (numerator(x) > (y * denominator(x)))));
  19442. return(make_boolean(sc, fraction(x) > y));
  19443. case T_REAL:
  19444. return(make_boolean(sc, real(x) > y));
  19445. default:
  19446. method_or_bust_with_type(sc, x, sc->gt_symbol, args, a_number_string, 1);
  19447. }
  19448. return(sc->T);
  19449. }
  19450. static s7_pointer c_greater_2_1(s7_scheme *sc, s7_pointer x, s7_pointer y)
  19451. {
  19452. switch (type(x))
  19453. {
  19454. case T_INTEGER:
  19455. switch (type(y))
  19456. {
  19457. case T_INTEGER:
  19458. return(make_boolean(sc, integer(x) > integer(y)));
  19459. case T_RATIO:
  19460. return(g_greater(sc, list_2(sc, x, y)));
  19461. case T_REAL:
  19462. if (is_NaN(real(y))) return(sc->F);
  19463. return(make_boolean(sc, integer(x) > real(y)));
  19464. default:
  19465. method_or_bust(sc, y, sc->gt_symbol, list_2(sc, x, y), T_REAL, 2);
  19466. }
  19467. break;
  19468. case T_RATIO:
  19469. return(g_greater(sc, list_2(sc, x, y)));
  19470. case T_REAL:
  19471. switch (type(y))
  19472. {
  19473. case T_INTEGER:
  19474. if (is_NaN(real(x))) return(sc->F);
  19475. return(make_boolean(sc, real(x) > integer(y)));
  19476. case T_RATIO:
  19477. if (is_NaN(real(x))) return(sc->F);
  19478. return(make_boolean(sc, real(x) > fraction(y)));
  19479. case T_REAL:
  19480. if (is_NaN(real(x))) return(sc->F);
  19481. if (is_NaN(real(y))) return(sc->F);
  19482. return(make_boolean(sc, real(x) > real(y)));
  19483. default:
  19484. method_or_bust(sc, y, sc->gt_symbol, list_2(sc, x, y), T_REAL, 2);
  19485. }
  19486. break;
  19487. default:
  19488. method_or_bust(sc, x, sc->gt_symbol, list_2(sc, x, y), T_REAL, 1);
  19489. }
  19490. return(sc->T);
  19491. }
  19492. static s7_pointer c_greater_2(s7_scheme *sc, s7_pointer x, s7_pointer y)
  19493. {
  19494. #if (!MS_WINDOWS)
  19495. if (type(x) == type(y))
  19496. {
  19497. switch (type(x))
  19498. {
  19499. case T_INTEGER: return(make_boolean(sc, integer(x) > integer(y)));
  19500. case T_RATIO: return(make_boolean(sc, fraction(x) > fraction(y)));
  19501. case T_REAL: return(make_boolean(sc, real(x) > real(y)));
  19502. }
  19503. }
  19504. #endif
  19505. return(c_greater_2_1(sc, x, y));
  19506. }
  19507. static s7_pointer greater_2;
  19508. static s7_pointer g_greater_2(s7_scheme *sc, s7_pointer args)
  19509. {
  19510. s7_pointer x, y;
  19511. x = car(args);
  19512. y = cadr(args);
  19513. #if (!MS_WINDOWS)
  19514. if (type(x) == type(y))
  19515. {
  19516. switch (type(x))
  19517. {
  19518. case T_INTEGER: return(make_boolean(sc, integer(x) > integer(y)));
  19519. case T_RATIO: return(make_boolean(sc, fraction(x) > fraction(y)));
  19520. case T_REAL: return(make_boolean(sc, real(x) > real(y)));
  19521. }
  19522. }
  19523. #endif
  19524. return(c_greater_2_1(sc, x, y));
  19525. }
  19526. static s7_pointer c_gt_i(s7_scheme *sc, s7_int x, s7_int y) {return(make_boolean(sc, x > y));}
  19527. static s7_pointer c_gt_r(s7_scheme *sc, s7_double x, s7_double y) {return(make_boolean(sc, x > y));}
  19528. XF2_TO_PF(gt, c_gt_i, c_gt_r, c_greater_2)
  19529. static s7_pointer greater_2_f;
  19530. static s7_pointer g_greater_2_f(s7_scheme *sc, s7_pointer args)
  19531. {
  19532. return(make_boolean(sc, real(car(args)) > real(cadr(args))));
  19533. }
  19534. static s7_pointer c_geq_2_1(s7_scheme *sc, s7_pointer x, s7_pointer y)
  19535. {
  19536. switch (type(x))
  19537. {
  19538. case T_INTEGER:
  19539. switch (type(y))
  19540. {
  19541. case T_INTEGER:
  19542. return(make_boolean(sc, integer(x) >= integer(y)));
  19543. case T_RATIO:
  19544. return(g_greater_or_equal(sc, list_2(sc, x, y)));
  19545. case T_REAL:
  19546. if (is_NaN(real(y))) return(sc->F);
  19547. return(make_boolean(sc, integer(x) >= real(y)));
  19548. default:
  19549. method_or_bust(sc, y, sc->geq_symbol, list_2(sc, x, y), T_REAL, 2);
  19550. }
  19551. break;
  19552. case T_RATIO:
  19553. return(g_greater_or_equal(sc, list_2(sc, x, y)));
  19554. case T_REAL:
  19555. switch (type(y))
  19556. {
  19557. case T_INTEGER:
  19558. if (is_NaN(real(x))) return(sc->F);
  19559. return(make_boolean(sc, real(x) >= integer(y)));
  19560. case T_RATIO:
  19561. if (is_NaN(real(x))) return(sc->F);
  19562. return(make_boolean(sc, real(x) >= fraction(y)));
  19563. case T_REAL:
  19564. if (is_NaN(real(x))) return(sc->F);
  19565. if (is_NaN(real(y))) return(sc->F);
  19566. return(make_boolean(sc, real(x) >= real(y)));
  19567. default:
  19568. method_or_bust(sc, y, sc->geq_symbol, list_2(sc, x, y), T_REAL, 2);
  19569. }
  19570. break;
  19571. default:
  19572. method_or_bust(sc, x, sc->geq_symbol, list_2(sc, x, y), T_REAL, 1);
  19573. }
  19574. return(sc->T);
  19575. }
  19576. static s7_pointer c_geq_2(s7_scheme *sc, s7_pointer x, s7_pointer y)
  19577. {
  19578. #if (!MS_WINDOWS)
  19579. if (type(x) == type(y))
  19580. {
  19581. switch (type(x))
  19582. {
  19583. case T_INTEGER: return(make_boolean(sc, integer(x) >= integer(y)));
  19584. case T_RATIO: return(make_boolean(sc, fraction(x) >= fraction(y)));
  19585. case T_REAL: return(make_boolean(sc, real(x) >= real(y)));
  19586. }
  19587. }
  19588. #endif
  19589. return(c_geq_2_1(sc, x, y));
  19590. }
  19591. #endif
  19592. static s7_pointer geq_2 = NULL;
  19593. #if (!WITH_GMP)
  19594. static s7_pointer g_geq_2(s7_scheme *sc, s7_pointer args)
  19595. {
  19596. s7_pointer x, y;
  19597. x = car(args);
  19598. y = cadr(args);
  19599. #if (!MS_WINDOWS)
  19600. if (type(x) == type(y))
  19601. {
  19602. if (is_integer(x))
  19603. return(make_boolean(sc, integer(x) >= integer(y)));
  19604. switch (type(x))
  19605. {
  19606. case T_INTEGER: return(make_boolean(sc, integer(x) >= integer(y)));
  19607. case T_RATIO: return(make_boolean(sc, fraction(x) >= fraction(y)));
  19608. case T_REAL: return(make_boolean(sc, real(x) >= real(y)));
  19609. }
  19610. }
  19611. #endif
  19612. return(c_geq_2_1(sc, x, y));
  19613. }
  19614. static s7_pointer c_geq_i(s7_scheme *sc, s7_int x, s7_int y) {return(make_boolean(sc, x >= y));}
  19615. static s7_pointer c_geq_r(s7_scheme *sc, s7_double x, s7_double y) {return(make_boolean(sc, x >= y));}
  19616. XF2_TO_PF(geq, c_geq_i, c_geq_r, c_geq_2)
  19617. static s7_pointer geq_s_fc;
  19618. static s7_pointer g_geq_s_fc(s7_scheme *sc, s7_pointer args)
  19619. {
  19620. s7_double y;
  19621. s7_pointer x;
  19622. x = car(args);
  19623. y = real(cadr(args));
  19624. if (is_t_real(x))
  19625. return(make_boolean(sc, real(x) >= y));
  19626. return(g_geq_2(sc, args));
  19627. }
  19628. static s7_pointer geq_length_ic;
  19629. static s7_pointer g_geq_length_ic(s7_scheme *sc, s7_pointer args)
  19630. {
  19631. return(make_boolean(sc, is_false(sc, g_less_length_ic(sc, args))));
  19632. }
  19633. static s7_pointer geq_s_ic;
  19634. static s7_pointer g_geq_s_ic(s7_scheme *sc, s7_pointer args)
  19635. {
  19636. s7_int y;
  19637. s7_pointer x;
  19638. x = car(args);
  19639. y = s7_integer(cadr(args));
  19640. switch (type(x))
  19641. {
  19642. case T_INTEGER:
  19643. return(make_boolean(sc, integer(x) >= y));
  19644. case T_RATIO:
  19645. if ((y >= 0) && (numerator(x) < 0))
  19646. return(sc->F);
  19647. if ((y <= 0) && (numerator(x) >= 0))
  19648. return(sc->T);
  19649. if ((y < s7_int32_max) &&
  19650. (y > s7_int32_min) &&
  19651. (denominator(x) < s7_int32_max))
  19652. return(make_boolean(sc, (numerator(x) >= (y * denominator(x)))));
  19653. return(make_boolean(sc, fraction(x) >= y));
  19654. case T_REAL:
  19655. return(make_boolean(sc, real(x) >= y));
  19656. default:
  19657. method_or_bust(sc, x, sc->geq_symbol, args, T_REAL, 1);
  19658. }
  19659. return(sc->T);
  19660. }
  19661. #endif
  19662. /* end (!WITH_GMP) */
  19663. /* ---------------------------------------- real-part imag-part ---------------------------------------- */
  19664. s7_double s7_real_part(s7_pointer x)
  19665. {
  19666. switch(type(x))
  19667. {
  19668. case T_INTEGER: return((s7_double)integer(x));
  19669. case T_RATIO: return(fraction(x));
  19670. case T_REAL: return(real(x));
  19671. case T_COMPLEX: return(real_part(x));
  19672. #if WITH_GMP
  19673. case T_BIG_INTEGER: return((s7_double)big_integer_to_s7_int(big_integer(x)));
  19674. case T_BIG_RATIO: return((s7_double)((long double)big_integer_to_s7_int(mpq_numref(big_ratio(x))) / (long double)big_integer_to_s7_int(mpq_denref(big_ratio(x)))));
  19675. case T_BIG_REAL: return((s7_double)mpfr_get_d(big_real(x), GMP_RNDN));
  19676. case T_BIG_COMPLEX: return((s7_double)mpfr_get_d(mpc_realref(big_complex(x)), GMP_RNDN));
  19677. #endif
  19678. }
  19679. return(0.0);
  19680. }
  19681. s7_double s7_imag_part(s7_pointer x)
  19682. {
  19683. switch (type(x))
  19684. {
  19685. case T_COMPLEX: return(imag_part(x));
  19686. #if WITH_GMP
  19687. case T_BIG_COMPLEX: return((s7_double)mpfr_get_d(mpc_imagref(big_complex(x)), GMP_RNDN));
  19688. #endif
  19689. }
  19690. return(0.0);
  19691. }
  19692. static s7_pointer g_real_part(s7_scheme *sc, s7_pointer args)
  19693. {
  19694. #define H_real_part "(real-part num) returns the real part of num"
  19695. #define Q_real_part s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
  19696. s7_pointer p;
  19697. p = car(args);
  19698. switch (type(p))
  19699. {
  19700. case T_INTEGER:
  19701. case T_RATIO:
  19702. case T_REAL:
  19703. return(p);
  19704. case T_COMPLEX:
  19705. return(make_real(sc, real_part(p)));
  19706. #if WITH_GMP
  19707. case T_BIG_INTEGER:
  19708. case T_BIG_RATIO:
  19709. case T_BIG_REAL:
  19710. return(p);
  19711. case T_BIG_COMPLEX:
  19712. {
  19713. s7_pointer x;
  19714. new_cell(sc, x, T_BIG_REAL);
  19715. add_bigreal(sc, x);
  19716. mpfr_init(big_real(x));
  19717. mpc_real(big_real(x), big_complex(p), GMP_RNDN);
  19718. return(x);
  19719. }
  19720. #endif
  19721. default:
  19722. method_or_bust_with_type(sc, p, sc->real_part_symbol, args, a_number_string, 0);
  19723. }
  19724. }
  19725. #if (!WITH_GMP)
  19726. static s7_double c_real_part(s7_scheme *sc, s7_pointer x) {return(real(g_real_part(sc, set_plist_1(sc, x))));}
  19727. PF_TO_RF(real_part, c_real_part)
  19728. #endif
  19729. static s7_pointer g_imag_part(s7_scheme *sc, s7_pointer args)
  19730. {
  19731. #define H_imag_part "(imag-part num) returns the imaginary part of num"
  19732. #define Q_imag_part s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
  19733. s7_pointer p;
  19734. /* currently (imag-part nan.0) -> 0.0 ? it's true but maybe confusing */
  19735. p = car(args);
  19736. switch (type(p))
  19737. {
  19738. case T_INTEGER:
  19739. case T_RATIO:
  19740. return(small_int(0));
  19741. case T_REAL:
  19742. return(real_zero);
  19743. case T_COMPLEX:
  19744. return(make_real(sc, imag_part(p)));
  19745. #if WITH_GMP
  19746. case T_BIG_INTEGER:
  19747. case T_BIG_RATIO:
  19748. return(small_int(0));
  19749. case T_BIG_REAL:
  19750. return(real_zero);
  19751. case T_BIG_COMPLEX:
  19752. {
  19753. s7_pointer x;
  19754. new_cell(sc, x, T_BIG_REAL);
  19755. add_bigreal(sc, x);
  19756. mpfr_init(big_real(x));
  19757. mpc_imag(big_real(x), big_complex(p), GMP_RNDN);
  19758. return(x);
  19759. }
  19760. #endif
  19761. default:
  19762. method_or_bust_with_type(sc, p, sc->imag_part_symbol, args, a_number_string, 0);
  19763. }
  19764. }
  19765. #if (!WITH_GMP)
  19766. static s7_double c_imag_part(s7_scheme *sc, s7_pointer x) {return(real(g_imag_part(sc, set_plist_1(sc, x))));}
  19767. PF_TO_RF(imag_part, c_imag_part)
  19768. #endif
  19769. /* ---------------------------------------- numerator denominator ---------------------------------------- */
  19770. static s7_pointer g_numerator(s7_scheme *sc, s7_pointer args)
  19771. {
  19772. #define H_numerator "(numerator rat) returns the numerator of the rational number rat"
  19773. #define Q_numerator s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_rational_symbol)
  19774. s7_pointer x;
  19775. x = car(args);
  19776. switch (type(x))
  19777. {
  19778. case T_RATIO: return(make_integer(sc, numerator(x)));
  19779. case T_INTEGER: return(x);
  19780. #if WITH_GMP
  19781. case T_BIG_INTEGER: return(x);
  19782. case T_BIG_RATIO: return(mpz_to_big_integer(sc, mpq_numref(big_ratio(x))));
  19783. #endif
  19784. default: method_or_bust_with_type(sc, x, sc->numerator_symbol, args, a_rational_string, 0);
  19785. }
  19786. }
  19787. #if (!WITH_GMP)
  19788. static s7_int c_numerator(s7_scheme *sc, s7_pointer x) {return(s7_numerator(x));}
  19789. PF_TO_IF(numerator, c_numerator)
  19790. #endif
  19791. static s7_pointer g_denominator(s7_scheme *sc, s7_pointer args)
  19792. {
  19793. #define H_denominator "(denominator rat) returns the denominator of the rational number rat"
  19794. #define Q_denominator s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_rational_symbol)
  19795. s7_pointer x;
  19796. x = car(args);
  19797. switch (type(x))
  19798. {
  19799. case T_RATIO: return(make_integer(sc, denominator(x)));
  19800. case T_INTEGER: return(small_int(1));
  19801. #if WITH_GMP
  19802. case T_BIG_INTEGER: return(small_int(1));
  19803. case T_BIG_RATIO: return(mpz_to_big_integer(sc, mpq_denref(big_ratio(x))));
  19804. #endif
  19805. default: method_or_bust_with_type(sc, x, sc->denominator_symbol, args, a_rational_string, 0);
  19806. }
  19807. }
  19808. #if (!WITH_GMP)
  19809. static s7_int c_denominator(s7_scheme *sc, s7_pointer x) {return(s7_denominator(x));}
  19810. PF_TO_IF(denominator, c_denominator)
  19811. #endif
  19812. /* ---------------------------------------- nan? infinite? ---------------------------------------- */
  19813. static s7_pointer g_is_nan(s7_scheme *sc, s7_pointer args)
  19814. {
  19815. #define H_is_nan "(nan? obj) returns #t if obj is a NaN"
  19816. #define Q_is_nan pl_bn
  19817. s7_pointer x;
  19818. x = car(args);
  19819. switch (type(x))
  19820. {
  19821. case T_INTEGER:
  19822. case T_RATIO:
  19823. return(sc->F);
  19824. case T_REAL:
  19825. return(make_boolean(sc, is_NaN(real(x))));
  19826. case T_COMPLEX:
  19827. return(make_boolean(sc, (is_NaN(real_part(x))) || (is_NaN(imag_part(x)))));
  19828. #if WITH_GMP
  19829. case T_BIG_INTEGER:
  19830. case T_BIG_RATIO:
  19831. return(sc->F);
  19832. case T_BIG_REAL:
  19833. return(make_boolean(sc, is_NaN(s7_real_part(x))));
  19834. case T_BIG_COMPLEX:
  19835. return(make_boolean(sc, (is_NaN(s7_real_part(x))) || (is_NaN(s7_imag_part(x)))));
  19836. #endif
  19837. default:
  19838. method_or_bust_with_type(sc, x, sc->is_nan_symbol, list_1(sc, x), a_number_string, 0);
  19839. }
  19840. }
  19841. #if (!WITH_GMP)
  19842. static s7_pointer c_is_nan(s7_scheme *sc, s7_double x) {return((is_NaN(x)) ? sc->T : sc->F);}
  19843. RF_TO_PF(is_nan, c_is_nan)
  19844. #endif
  19845. static s7_pointer g_is_infinite(s7_scheme *sc, s7_pointer args)
  19846. {
  19847. #define H_is_infinite "(infinite? obj) returns #t if obj is an infinite real"
  19848. #define Q_is_infinite pl_bn
  19849. s7_pointer x;
  19850. x = car(args);
  19851. switch (type(x))
  19852. {
  19853. case T_INTEGER:
  19854. case T_RATIO:
  19855. return(sc->F);
  19856. case T_REAL:
  19857. return(make_boolean(sc, is_inf(real(x))));
  19858. case T_COMPLEX:
  19859. return(make_boolean(sc, (is_inf(real_part(x))) || (is_inf(imag_part(x)))));
  19860. #if WITH_GMP
  19861. case T_BIG_INTEGER:
  19862. case T_BIG_RATIO:
  19863. return(sc->F);
  19864. case T_BIG_REAL:
  19865. return(make_boolean(sc, mpfr_inf_p(big_real(x)) != 0));
  19866. case T_BIG_COMPLEX:
  19867. return(make_boolean(sc,
  19868. (mpfr_inf_p(big_real(g_real_part(sc, list_1(sc, x)))) != 0) ||
  19869. (mpfr_inf_p(big_real(g_imag_part(sc, list_1(sc, x)))) != 0)));
  19870. #endif
  19871. default:
  19872. method_or_bust_with_type(sc, x, sc->is_infinite_symbol, list_1(sc, x), a_number_string, 0);
  19873. }
  19874. }
  19875. #if (!WITH_GMP)
  19876. static s7_pointer c_is_infinite(s7_scheme *sc, s7_double x) {return((is_inf(x)) ? sc->T : sc->F);}
  19877. RF_TO_PF(is_infinite, c_is_infinite)
  19878. #endif
  19879. /* ---------------------------------------- number? complex? integer? rational? real? ---------------------------------------- */
  19880. static s7_pointer g_is_number(s7_scheme *sc, s7_pointer args)
  19881. {
  19882. #define H_is_number "(number? obj) returns #t if obj is a number"
  19883. #define Q_is_number pl_bt
  19884. check_boolean_method(sc, s7_is_number, sc->is_number_symbol, args); /* we need the s7_* versions here for the GMP case */
  19885. }
  19886. static s7_pointer g_is_integer(s7_scheme *sc, s7_pointer args)
  19887. {
  19888. #define H_is_integer "(integer? obj) returns #t if obj is an integer"
  19889. #define Q_is_integer pl_bt
  19890. check_boolean_method(sc, s7_is_integer, sc->is_integer_symbol, args);
  19891. }
  19892. static s7_pointer g_is_real(s7_scheme *sc, s7_pointer args)
  19893. {
  19894. #define H_is_real "(real? obj) returns #t if obj is a real number"
  19895. #define Q_is_real pl_bt
  19896. check_boolean_method(sc, s7_is_real, sc->is_real_symbol, args);
  19897. }
  19898. static s7_pointer g_is_complex(s7_scheme *sc, s7_pointer args)
  19899. {
  19900. #define H_is_complex "(complex? obj) returns #t if obj is a number"
  19901. #define Q_is_complex pl_bt
  19902. check_boolean_method(sc, s7_is_number, sc->is_complex_symbol, args);
  19903. }
  19904. static s7_pointer g_is_rational(s7_scheme *sc, s7_pointer args)
  19905. {
  19906. #define H_is_rational "(rational? obj) returns #t if obj is a rational number (either an integer or a ratio)"
  19907. #define Q_is_rational pl_bt
  19908. check_boolean_method(sc, s7_is_rational, sc->is_rational_symbol, args);
  19909. /* in the non-gmp case, (rational? 455702434782048082459/86885567283849955830) -> #f, not #t
  19910. * and similarly for exact? etc.
  19911. */
  19912. }
  19913. /* ---------------------------------------- even? odd?---------------------------------------- */
  19914. static s7_pointer g_is_even(s7_scheme *sc, s7_pointer args)
  19915. {
  19916. #define H_is_even "(even? int) returns #t if the integer int is even"
  19917. #define Q_is_even s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_integer_symbol)
  19918. s7_pointer p;
  19919. p = car(args);
  19920. switch (type(p))
  19921. {
  19922. case T_INTEGER: return(make_boolean(sc, ((integer(p) & 1) == 0)));
  19923. #if WITH_GMP
  19924. case T_BIG_INTEGER: return(make_boolean(sc, mpz_even_p(big_integer(p))));
  19925. #endif
  19926. default: method_or_bust(sc, p, sc->is_even_symbol, list_1(sc, p), T_INTEGER, 0);
  19927. }
  19928. }
  19929. #if (!WITH_GMP)
  19930. static s7_pointer c_is_even(s7_scheme *sc, s7_int arg) {return(((arg & 1) == 0) ? sc->T : sc->F);}
  19931. IF_TO_PF(is_even, c_is_even)
  19932. #endif
  19933. static s7_pointer g_is_odd(s7_scheme *sc, s7_pointer args)
  19934. {
  19935. #define H_is_odd "(odd? int) returns #t if the integer int is odd"
  19936. #define Q_is_odd s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_integer_symbol)
  19937. s7_pointer p;
  19938. p = car(args);
  19939. switch (type(p))
  19940. {
  19941. case T_INTEGER: return(make_boolean(sc, ((integer(p) & 1) == 1)));
  19942. #if WITH_GMP
  19943. case T_BIG_INTEGER: return(make_boolean(sc, mpz_odd_p(big_integer(p))));
  19944. #endif
  19945. default: method_or_bust(sc, p, sc->is_odd_symbol, list_1(sc, p), T_INTEGER, 0);
  19946. }
  19947. }
  19948. #if (!WITH_GMP)
  19949. static s7_pointer c_is_odd(s7_scheme *sc, s7_int arg) {return(((arg & 1) == 0) ? sc->F : sc->T);}
  19950. IF_TO_PF(is_odd, c_is_odd)
  19951. #endif
  19952. /* ---------------------------------------- zero? ---------------------------------------- */
  19953. static s7_pointer c_is_zero(s7_scheme *sc, s7_pointer x)
  19954. {
  19955. switch (type(x))
  19956. {
  19957. case T_INTEGER: return(make_boolean(sc, integer(x) == 0));
  19958. case T_REAL: return(make_boolean(sc, real(x) == 0.0));
  19959. case T_RATIO:
  19960. case T_COMPLEX: return(sc->F); /* ratios and complex numbers are already collapsed into integers and reals */
  19961. #if WITH_GMP
  19962. case T_BIG_INTEGER: return(make_boolean(sc, mpz_cmp_ui(big_integer(x), 0) == 0));
  19963. case T_BIG_REAL: return(make_boolean(sc, mpfr_zero_p(big_real(x))));
  19964. case T_BIG_RATIO:
  19965. case T_BIG_COMPLEX: return(sc->F);
  19966. #endif
  19967. default:
  19968. method_or_bust_with_type(sc, x, sc->is_zero_symbol, list_1(sc, x), a_number_string, 0);
  19969. }
  19970. }
  19971. static s7_pointer g_is_zero(s7_scheme *sc, s7_pointer args)
  19972. {
  19973. #define H_is_zero "(zero? num) returns #t if the number num is zero"
  19974. #define Q_is_zero pl_bn
  19975. return(c_is_zero(sc, car(args)));
  19976. }
  19977. static s7_pointer c_is_zero_i(s7_scheme *sc, s7_int x) {return(make_boolean(sc, x == 0));}
  19978. static s7_pointer c_is_zero_r(s7_scheme *sc, s7_double x) {return(make_boolean(sc, x == 0.0));}
  19979. XF_TO_PF(is_zero, c_is_zero_i, c_is_zero_r, c_is_zero)
  19980. /* -------------------------------- positive? -------------------------------- */
  19981. static s7_pointer c_is_positive(s7_scheme *sc, s7_pointer x)
  19982. {
  19983. switch (type(x))
  19984. {
  19985. case T_INTEGER: return(make_boolean(sc, integer(x) > 0));
  19986. case T_RATIO: return(make_boolean(sc, numerator(x) > 0));
  19987. case T_REAL: return(make_boolean(sc, real(x) > 0.0));
  19988. #if WITH_GMP
  19989. case T_BIG_INTEGER: return(make_boolean(sc, (mpz_cmp_ui(big_integer(x), 0) > 0)));
  19990. case T_BIG_RATIO: return(make_boolean(sc, (mpq_cmp_ui(big_ratio(x), 0, 1) > 0)));
  19991. case T_BIG_REAL: return(make_boolean(sc, (mpfr_cmp_ui(big_real(x), 0) > 0)));
  19992. #endif
  19993. default:
  19994. method_or_bust(sc, x, sc->is_positive_symbol, list_1(sc, x), T_REAL, 0);
  19995. }
  19996. }
  19997. static s7_pointer g_is_positive(s7_scheme *sc, s7_pointer args)
  19998. {
  19999. #define H_is_positive "(positive? num) returns #t if the real number num is positive (greater than 0)"
  20000. #define Q_is_positive s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  20001. return(c_is_positive(sc, car(args)));
  20002. }
  20003. static s7_pointer c_is_positive_i(s7_scheme *sc, s7_int x) {return(make_boolean(sc, x > 0));}
  20004. static s7_pointer c_is_positive_r(s7_scheme *sc, s7_double x) {return(make_boolean(sc, x > 0.0));}
  20005. XF_TO_PF(is_positive, c_is_positive_i, c_is_positive_r, c_is_positive)
  20006. /* -------------------------------- negative? -------------------------------- */
  20007. static s7_pointer c_is_negative(s7_scheme *sc, s7_pointer x)
  20008. {
  20009. switch (type(x))
  20010. {
  20011. case T_INTEGER: return(make_boolean(sc, integer(x) < 0));
  20012. case T_RATIO: return(make_boolean(sc, numerator(x) < 0));
  20013. case T_REAL: return(make_boolean(sc, real(x) < 0.0));
  20014. #if WITH_GMP
  20015. case T_BIG_INTEGER: return(make_boolean(sc, (mpz_cmp_ui(big_integer(x), 0) < 0)));
  20016. case T_BIG_RATIO: return(make_boolean(sc, (mpq_cmp_ui(big_ratio(x), 0, 1) < 0)));
  20017. case T_BIG_REAL: return(make_boolean(sc, (mpfr_cmp_ui(big_real(x), 0) < 0)));
  20018. #endif
  20019. default:
  20020. method_or_bust(sc, x, sc->is_negative_symbol, list_1(sc, x), T_REAL, 0);
  20021. }
  20022. }
  20023. static s7_pointer g_is_negative(s7_scheme *sc, s7_pointer args)
  20024. {
  20025. #define H_is_negative "(negative? num) returns #t if the real number num is negative (less than 0)"
  20026. #define Q_is_negative s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  20027. return(c_is_negative(sc, car(args)));
  20028. }
  20029. static s7_pointer c_is_negative_i(s7_scheme *sc, s7_int x) {return(make_boolean(sc, x < 0));}
  20030. static s7_pointer c_is_negative_r(s7_scheme *sc, s7_double x) {return(make_boolean(sc, x < 0.0));}
  20031. XF_TO_PF(is_negative, c_is_negative_i, c_is_negative_r, c_is_negative)
  20032. bool s7_is_ulong(s7_pointer arg)
  20033. {
  20034. return(is_integer(arg));
  20035. }
  20036. unsigned long s7_ulong(s7_pointer p)
  20037. {
  20038. return((_NFre(p))->object.number.ul_value);
  20039. }
  20040. s7_pointer s7_make_ulong(s7_scheme *sc, unsigned long n)
  20041. {
  20042. s7_pointer x;
  20043. new_cell(sc, x, T_INTEGER);
  20044. x->object.number.ul_value = n;
  20045. return(x);
  20046. }
  20047. bool s7_is_ulong_long(s7_pointer arg)
  20048. {
  20049. return(is_integer(arg));
  20050. }
  20051. unsigned long long s7_ulong_long(s7_pointer p)
  20052. {
  20053. return((_NFre(p))->object.number.ull_value);
  20054. }
  20055. s7_pointer s7_make_ulong_long(s7_scheme *sc, unsigned long long n)
  20056. {
  20057. s7_pointer x;
  20058. new_cell(sc, x, T_INTEGER);
  20059. x->object.number.ull_value = n;
  20060. return(x);
  20061. }
  20062. #if (!WITH_PURE_S7)
  20063. #if (!WITH_GMP)
  20064. /* ---------------------------------------- exact<->inexact exact? inexact? ---------------------------------------- */
  20065. static s7_pointer g_exact_to_inexact(s7_scheme *sc, s7_pointer args)
  20066. {
  20067. #define H_exact_to_inexact "(exact->inexact num) converts num to an inexact number; (exact->inexact 3/2) = 1.5"
  20068. #define Q_exact_to_inexact pcl_r
  20069. return(exact_to_inexact(sc, car(args)));
  20070. }
  20071. static s7_pointer g_inexact_to_exact(s7_scheme *sc, s7_pointer args)
  20072. {
  20073. #define H_inexact_to_exact "(inexact->exact num) converts num to an exact number; (inexact->exact 1.5) = 3/2"
  20074. #define Q_inexact_to_exact s7_make_signature(sc, 2, sc->is_rational_symbol, sc->is_real_symbol)
  20075. return(inexact_to_exact(sc, car(args), WITH_OVERFLOW_ERROR));
  20076. }
  20077. #endif
  20078. /* (!WITH_GMP) */
  20079. static s7_pointer g_is_exact(s7_scheme *sc, s7_pointer args)
  20080. {
  20081. #define H_is_exact "(exact? num) returns #t if num is exact (an integer or a ratio)"
  20082. #define Q_is_exact pl_bn
  20083. s7_pointer x;
  20084. x = car(args);
  20085. switch (type(x))
  20086. {
  20087. case T_INTEGER:
  20088. case T_RATIO: return(sc->T);
  20089. case T_REAL:
  20090. case T_COMPLEX: return(sc->F);
  20091. #if WITH_GMP
  20092. case T_BIG_INTEGER:
  20093. case T_BIG_RATIO: return(sc->T);
  20094. case T_BIG_REAL:
  20095. case T_BIG_COMPLEX: return(sc->F);
  20096. #endif
  20097. default:
  20098. method_or_bust_with_type(sc, x, sc->is_exact_symbol, args, a_number_string, 0);
  20099. }
  20100. }
  20101. static s7_pointer g_is_inexact(s7_scheme *sc, s7_pointer args)
  20102. {
  20103. #define H_is_inexact "(inexact? num) returns #t if num is inexact (neither an integer nor a ratio)"
  20104. #define Q_is_inexact pl_bn
  20105. s7_pointer x;
  20106. x = car(args);
  20107. switch (type(x))
  20108. {
  20109. case T_INTEGER:
  20110. case T_RATIO: return(sc->F);
  20111. case T_REAL:
  20112. case T_COMPLEX: return(sc->T);
  20113. #if WITH_GMP
  20114. case T_BIG_INTEGER:
  20115. case T_BIG_RATIO: return(sc->F);
  20116. case T_BIG_REAL:
  20117. case T_BIG_COMPLEX: return(sc->T);
  20118. #endif
  20119. default:
  20120. method_or_bust_with_type(sc, x, sc->is_inexact_symbol, args, a_number_string, 0);
  20121. }
  20122. }
  20123. /* ---------------------------------------- integer-length, integer-decode-float ---------------------------------------- */
  20124. static s7_pointer g_integer_length(s7_scheme *sc, s7_pointer args)
  20125. {
  20126. #define H_integer_length "(integer-length arg) returns the number of bits required to represent the integer 'arg': (ceiling (log (abs arg) 2))"
  20127. #define Q_integer_length pcl_i
  20128. s7_int x;
  20129. s7_pointer p;
  20130. p = car(args);
  20131. if (!s7_is_integer(p))
  20132. method_or_bust(sc, p, sc->integer_length_symbol, args, T_INTEGER, 0);
  20133. x = s7_integer(p);
  20134. if (x < 0)
  20135. return(make_integer(sc, integer_length(-(x + 1))));
  20136. return(make_integer(sc, integer_length(x)));
  20137. }
  20138. #if (!WITH_GMP)
  20139. static s7_int c_integer_length(s7_scheme *sc, s7_int arg) {return((arg < 0) ? integer_length(-(arg + 1)) : integer_length(arg));}
  20140. IF_TO_IF(integer_length, c_integer_length)
  20141. #endif
  20142. #endif /* !pure s7 */
  20143. static s7_pointer g_integer_decode_float(s7_scheme *sc, s7_pointer args)
  20144. {
  20145. #define H_integer_decode_float "(integer-decode-float x) returns a list containing the significand, exponent, and \
  20146. sign of 'x' (1 = positive, -1 = negative). (integer-decode-float 0.0): (0 0 1)"
  20147. #define Q_integer_decode_float s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_float_symbol)
  20148. /* no matter what s7_double is, integer-decode-float acts as if x is a C double */
  20149. typedef struct decode_float_t {
  20150. union {
  20151. long long int ix;
  20152. double fx;
  20153. } value;
  20154. } decode_float_t;
  20155. decode_float_t num;
  20156. s7_pointer x;
  20157. x = car(args);
  20158. switch (type(x))
  20159. {
  20160. case T_REAL:
  20161. num.value.fx = (double)real(x);
  20162. break;
  20163. #if WITH_GMP
  20164. case T_BIG_REAL:
  20165. num.value.fx = (double)real_to_double(sc, x, "integer-decode-float");
  20166. break;
  20167. #endif
  20168. default:
  20169. method_or_bust_with_type(sc, x, sc->integer_decode_float_symbol, args, make_string_wrapper(sc, "a non-rational real"), 0);
  20170. }
  20171. if (num.value.fx == 0.0)
  20172. return(list_3(sc, small_int(0), small_int(0), small_int(1)));
  20173. return(list_3(sc,
  20174. make_integer(sc, (s7_int)((num.value.ix & 0xfffffffffffffLL) | 0x10000000000000LL)),
  20175. make_integer(sc, (s7_int)(((num.value.ix & 0x7fffffffffffffffLL) >> 52) - 1023 - 52)),
  20176. make_integer(sc, ((num.value.ix & 0x8000000000000000LL) != 0) ? -1 : 1)));
  20177. }
  20178. /* -------------------------------- logior -------------------------------- */
  20179. static s7_pointer g_logior(s7_scheme *sc, s7_pointer args)
  20180. {
  20181. #define H_logior "(logior int ...) returns the bitwise OR of its integer arguments (the bits that are on in any of the arguments)"
  20182. #define Q_logior pcl_i
  20183. s7_int result = 0;
  20184. s7_pointer x;
  20185. for (x = args; is_not_null(x); x = cdr(x))
  20186. {
  20187. if (!s7_is_integer(car(x)))
  20188. method_or_bust(sc, car(x), sc->logior_symbol, cons(sc, make_integer(sc, result), x), T_INTEGER, position_of(x, args));
  20189. result |= s7_integer(car(x));
  20190. }
  20191. return(make_integer(sc, result));
  20192. }
  20193. #if (!WITH_GMP)
  20194. static s7_int c_logior(s7_scheme *sc, s7_int x, s7_int y) {return(x | y);}
  20195. IF2_TO_IF(logior, c_logior)
  20196. #endif
  20197. /* -------------------------------- logxor -------------------------------- */
  20198. static s7_pointer g_logxor(s7_scheme *sc, s7_pointer args)
  20199. {
  20200. #define H_logxor "(logxor int ...) returns the bitwise XOR of its integer arguments (the bits that are on in an odd number of the arguments)"
  20201. #define Q_logxor pcl_i
  20202. s7_int result = 0;
  20203. s7_pointer x;
  20204. for (x = args; is_not_null(x); x = cdr(x))
  20205. {
  20206. if (!s7_is_integer(car(x)))
  20207. method_or_bust(sc, car(x), sc->logxor_symbol, cons(sc, make_integer(sc, result), x), T_INTEGER, position_of(x, args));
  20208. result ^= s7_integer(car(x));
  20209. }
  20210. return(make_integer(sc, result));
  20211. }
  20212. #if (!WITH_GMP)
  20213. static s7_int c_logxor(s7_scheme *sc, s7_int x, s7_int y) {return(x ^ y);}
  20214. IF2_TO_IF(logxor, c_logxor)
  20215. #endif
  20216. /* -------------------------------- logand -------------------------------- */
  20217. static s7_pointer g_logand(s7_scheme *sc, s7_pointer args)
  20218. {
  20219. #define H_logand "(logand int ...) returns the bitwise AND of its integer arguments (the bits that are on in every argument)"
  20220. #define Q_logand pcl_i
  20221. s7_int result = -1;
  20222. s7_pointer x;
  20223. for (x = args; is_not_null(x); x = cdr(x))
  20224. {
  20225. if (!s7_is_integer(car(x)))
  20226. method_or_bust(sc, car(x), sc->logand_symbol, cons(sc, make_integer(sc, result), x), T_INTEGER, position_of(x, args));
  20227. result &= s7_integer(car(x));
  20228. }
  20229. return(make_integer(sc, result));
  20230. }
  20231. #if (!WITH_GMP)
  20232. static s7_int c_logand(s7_scheme *sc, s7_int x, s7_int y) {return(x & y);}
  20233. IF2_TO_IF(logand, c_logand)
  20234. #endif
  20235. /* -------------------------------- lognot -------------------------------- */
  20236. static s7_pointer g_lognot(s7_scheme *sc, s7_pointer args)
  20237. {
  20238. #define H_lognot "(lognot num) returns the bitwise negation (the complement, the bits that are not on) in num: (lognot 0) -> -1"
  20239. #define Q_lognot pcl_i
  20240. if (!s7_is_integer(car(args)))
  20241. method_or_bust(sc, car(args), sc->lognot_symbol, args, T_INTEGER, 0);
  20242. return(make_integer(sc, ~s7_integer(car(args))));
  20243. }
  20244. #if (!WITH_GMP)
  20245. static s7_int c_lognot(s7_scheme *sc, s7_int arg) {return(~arg);}
  20246. IF_TO_IF(lognot, c_lognot)
  20247. #endif
  20248. /* -------------------------------- logbit? -------------------------------- */
  20249. /* logbit? CL is (logbitp index int) using 2^index, but that order strikes me as backwards
  20250. * at least gmp got the arg order right!
  20251. */
  20252. static s7_pointer g_logbit(s7_scheme *sc, s7_pointer args)
  20253. {
  20254. #define H_logbit "(logbit? int index) returns #t if the index-th bit is on in int, otherwise #f. The argument \
  20255. 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))))."
  20256. #define Q_logbit s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_integer_symbol)
  20257. s7_pointer x, y;
  20258. s7_int index; /* index in gmp is mp_bitcnt which is an unsigned long int */
  20259. x = car(args);
  20260. y = cadr(args);
  20261. if (!s7_is_integer(x))
  20262. method_or_bust(sc, x, sc->logbit_symbol, args, T_INTEGER, 1);
  20263. if (!s7_is_integer(y))
  20264. method_or_bust(sc, y, sc->logbit_symbol, args, T_INTEGER, 2);
  20265. index = s7_integer(y);
  20266. if (index < 0)
  20267. return(out_of_range(sc, sc->logbit_symbol, small_int(2), y, its_negative_string));
  20268. #if WITH_GMP
  20269. if (is_t_big_integer(x))
  20270. return(make_boolean(sc, (mpz_tstbit(big_integer(x), index) != 0)));
  20271. #endif
  20272. if (index >= s7_int_bits) /* not sure about the >: (logbit? -1 64) ?? */
  20273. return(make_boolean(sc, integer(x) < 0));
  20274. /* :(zero? (logand most-positive-fixnum (ash 1 63)))
  20275. * -> ash argument 2, 63, is out of range (shift is too large)
  20276. * so logbit? has a wider range than the logand/ash shuffle above.
  20277. */
  20278. /* all these long long ints are necessary, else C turns it into an int, gets confused about signs etc */
  20279. return(make_boolean(sc, ((((long long int)(1LL << (long long int)index)) & (long long int)integer(x)) != 0)));
  20280. }
  20281. /* -------------------------------- ash -------------------------------- */
  20282. static s7_int c_ash(s7_scheme *sc, s7_int arg1, s7_int arg2)
  20283. {
  20284. if (arg1 == 0) return(0);
  20285. if (arg2 >= s7_int_bits)
  20286. out_of_range(sc, sc->ash_symbol, small_int(2), make_integer(sc, arg2), its_too_large_string);
  20287. if (arg2 < -s7_int_bits)
  20288. {
  20289. if (arg1 < 0) /* (ash -31 -100) */
  20290. return(-1);
  20291. return(0);
  20292. }
  20293. /* I can't see any point in protecting this: (ash 9223372036854775807 1) -> -2, but anyone using ash must know something about bits */
  20294. if (arg2 >= 0)
  20295. {
  20296. if (arg1 < 0)
  20297. {
  20298. unsigned long long int z;
  20299. z = (unsigned long long int)arg1;
  20300. return((s7_int)(z << arg2));
  20301. }
  20302. return(arg1 << arg2);
  20303. }
  20304. return(arg1 >> -arg2);
  20305. }
  20306. static s7_pointer g_ash(s7_scheme *sc, s7_pointer args)
  20307. {
  20308. #define H_ash "(ash i1 i2) returns i1 shifted right or left i2 times, i1 << i2, (ash 1 3) -> 8, (ash 8 -3) -> 1"
  20309. #define Q_ash pcl_i
  20310. s7_pointer x, y;
  20311. x = car(args);
  20312. if (!s7_is_integer(x))
  20313. method_or_bust(sc, x, sc->ash_symbol, args, T_INTEGER, 1);
  20314. y = cadr(args);
  20315. if (!s7_is_integer(y))
  20316. method_or_bust(sc, y, sc->ash_symbol, args, T_INTEGER, 2);
  20317. return(make_integer(sc, c_ash(sc, s7_integer(x), s7_integer(y))));
  20318. }
  20319. #if (!WITH_GMP)
  20320. IF2_TO_IF(ash, c_ash)
  20321. #endif
  20322. /* ---------------------------------------- random ---------------------------------------- */
  20323. /* random numbers. The simple version used in clm.c is probably adequate,
  20324. * but here I'll use Marsaglia's MWC algorithm.
  20325. * (random num) -> a number (0..num), if num == 0 return 0, use global default state
  20326. * (random num state) -> same but use this state
  20327. * (random-state seed) -> make a new state
  20328. * to save the current seed, use copy
  20329. * to save it across load, random-state->list and list->random-state.
  20330. * random-state? returns #t if its arg is one of these guys
  20331. */
  20332. #if (!WITH_GMP)
  20333. s7_pointer s7_random_state(s7_scheme *sc, s7_pointer args)
  20334. {
  20335. #define H_random_state "(random-state seed (carry plausible-default)) returns a new random number state initialized with 'seed'. \
  20336. Pass this as the second argument to 'random' to get a repeatable random number sequence:\n\
  20337. (let ((seed (random-state 1234))) (random 1.0 seed))"
  20338. #define Q_random_state s7_make_circular_signature(sc, 1, 2, sc->is_random_state_symbol, sc->is_integer_symbol)
  20339. s7_pointer r1, r2, p;
  20340. s7_int i1, i2;
  20341. r1 = car(args);
  20342. if (!s7_is_integer(r1))
  20343. method_or_bust(sc, r1, sc->random_state_symbol, args, T_INTEGER, 1);
  20344. i1 = s7_integer(r1);
  20345. if (i1 < 0)
  20346. return(out_of_range(sc, sc->random_state_symbol, small_int(1), r1, its_negative_string));
  20347. if (is_null(cdr(args)))
  20348. {
  20349. new_cell(sc, p, T_RANDOM_STATE);
  20350. random_seed(p) = (unsigned long long int)i1;
  20351. random_carry(p) = 1675393560; /* should this be dependent on the seed? */
  20352. return(p);
  20353. }
  20354. r2 = cadr(args);
  20355. if (!s7_is_integer(r2))
  20356. method_or_bust(sc, r2, sc->random_state_symbol, args, T_INTEGER, 2);
  20357. i2 = s7_integer(r2);
  20358. if (i2 < 0)
  20359. return(out_of_range(sc, sc->random_state_symbol, small_int(2), r2, its_negative_string));
  20360. new_cell(sc, p, T_RANDOM_STATE);
  20361. random_seed(p) = (unsigned long long int)i1;
  20362. random_carry(p) = (unsigned long long int)i2;
  20363. return(p);
  20364. }
  20365. #define g_random_state s7_random_state
  20366. static s7_pointer c_random_state(s7_scheme *sc, s7_pointer x) {return(s7_random_state(sc, set_plist_1(sc, x)));}
  20367. PF_TO_PF(random_state, c_random_state)
  20368. #endif
  20369. static s7_pointer rng_copy(s7_scheme *sc, s7_pointer args)
  20370. {
  20371. #if WITH_GMP
  20372. return(sc->F); /* I can't find a way to copy a gmp random generator */
  20373. #else
  20374. s7_pointer obj;
  20375. obj = car(args);
  20376. if (is_random_state(obj))
  20377. {
  20378. s7_pointer new_r;
  20379. new_cell(sc, new_r, T_RANDOM_STATE);
  20380. random_seed(new_r) = random_seed(obj);
  20381. random_carry(new_r) = random_carry(obj);
  20382. return(new_r);
  20383. }
  20384. return(sc->F);
  20385. #endif
  20386. }
  20387. static s7_pointer g_is_random_state(s7_scheme *sc, s7_pointer args)
  20388. {
  20389. #define H_is_random_state "(random-state? obj) returns #t if obj is a random-state object (from random-state)."
  20390. #define Q_is_random_state pl_bt
  20391. check_boolean_method(sc, is_random_state, sc->is_random_state_symbol, args);
  20392. }
  20393. s7_pointer s7_random_state_to_list(s7_scheme *sc, s7_pointer args)
  20394. {
  20395. #define H_random_state_to_list "(random-state->list r) returns the random state object as a list.\
  20396. You can later apply random-state to this list to continue a random number sequence from any point."
  20397. #define Q_random_state_to_list s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_random_state_symbol)
  20398. #if WITH_GMP
  20399. if ((is_pair(args)) &&
  20400. (!is_random_state(car(args))))
  20401. method_or_bust_with_type(sc, car(args), sc->random_state_to_list_symbol, args, a_random_state_object_string, 1);
  20402. return(sc->nil);
  20403. #else
  20404. s7_pointer r;
  20405. if (is_null(args))
  20406. r = sc->default_rng;
  20407. else
  20408. {
  20409. r = car(args);
  20410. if (!is_random_state(r))
  20411. method_or_bust_with_type(sc, r, sc->random_state_to_list_symbol, args, a_random_state_object_string, 1);
  20412. }
  20413. return(list_2(sc, make_integer(sc, random_seed(r)), make_integer(sc, random_carry(r))));
  20414. #endif
  20415. }
  20416. #define g_random_state_to_list s7_random_state_to_list
  20417. s7_pointer c_random_state_to_list(s7_scheme *sc, s7_pointer x) {return(s7_random_state_to_list(sc, set_plist_1(sc, x)));}
  20418. PF_TO_PF(random_state_to_list, c_random_state_to_list)
  20419. void s7_set_default_random_state(s7_scheme *sc, s7_int seed, s7_int carry)
  20420. {
  20421. #if (!WITH_GMP)
  20422. s7_pointer p;
  20423. new_cell(sc, p, T_RANDOM_STATE);
  20424. random_seed(p) = (unsigned long long int)seed;
  20425. random_carry(p) = (unsigned long long int)carry;
  20426. sc->default_rng = p;
  20427. #endif
  20428. }
  20429. #if (!WITH_GMP)
  20430. /* -------------------------------- random -------------------------------- */
  20431. static double next_random(s7_pointer r)
  20432. {
  20433. /* The multiply-with-carry generator for 32-bit integers:
  20434. * x(n)=a*x(n-1) + carry mod 2^32
  20435. * Choose multiplier a from this list:
  20436. * 1791398085 1929682203 1683268614 1965537969 1675393560
  20437. * 1967773755 1517746329 1447497129 1655692410 1606218150
  20438. * 2051013963 1075433238 1557985959 1781943330 1893513180
  20439. * 1631296680 2131995753 2083801278 1873196400 1554115554
  20440. * ( or any 'a' for which both a*2^32-1 and a*2^31-1 are prime)
  20441. */
  20442. double result;
  20443. unsigned long long int temp;
  20444. #define RAN_MULT 2131995753UL
  20445. temp = random_seed(r) * RAN_MULT + random_carry(r);
  20446. random_seed(r) = (temp & 0xffffffffUL);
  20447. random_carry(r) = (temp >> 32);
  20448. result = (double)((unsigned int)(random_seed(r))) / 4294967295.5;
  20449. /* divisor was 2^32-1 = 4294967295.0, but somehow this can round up once in a billion tries?
  20450. * do we want the double just less than 2^32?
  20451. */
  20452. /* (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)) */
  20453. return(result);
  20454. }
  20455. s7_double s7_random(s7_scheme *sc, s7_pointer state)
  20456. {
  20457. if (!state)
  20458. return(next_random(sc->default_rng));
  20459. return(next_random(state));
  20460. }
  20461. static s7_pointer g_random(s7_scheme *sc, s7_pointer args)
  20462. {
  20463. #define H_random "(random num (state #f)) returns a random number between 0 and num (0 if num=0)."
  20464. #define Q_random s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_number_symbol, sc->is_random_state_symbol)
  20465. s7_pointer r, num;
  20466. num = car(args);
  20467. if (!s7_is_number(num))
  20468. method_or_bust_with_type(sc, num, sc->random_symbol, args, a_number_string, 1);
  20469. if (is_not_null(cdr(args)))
  20470. {
  20471. r = cadr(args);
  20472. if (!is_random_state(r))
  20473. method_or_bust_with_type(sc, r, sc->random_symbol, args, a_random_state_object_string, 2);
  20474. }
  20475. else r = sc->default_rng;
  20476. switch (type(num))
  20477. {
  20478. case T_INTEGER:
  20479. return(make_integer(sc, (s7_int)(integer(num) * next_random(r))));
  20480. case T_RATIO:
  20481. {
  20482. s7_double x, error;
  20483. s7_int numer = 0, denom = 1;
  20484. /* the error here needs to take the size of the fraction into account. Otherwise, if
  20485. * error is (say) 1e-6 and the fraction is (say) 9000000/9223372036854775807,
  20486. * c_rationalize will always return 0. But even that isn't foolproof:
  20487. * (random 1/562949953421312) -> 1/376367230475000
  20488. */
  20489. x = fraction(num);
  20490. if ((x < 1.0e-10) && (x > -1.0e-10))
  20491. {
  20492. /* 1e-12 is not tight enough:
  20493. * (random 1/2251799813685248) -> 1/2250240579436280
  20494. * (random -1/4503599627370496) -> -1/4492889778435526
  20495. * (random 1/140737488355328) -> 1/140730223985746
  20496. * (random -1/35184372088832) -> -1/35183145492420
  20497. * (random -1/70368744177664) -> -1/70366866392738
  20498. * (random 1/4398046511104) -> 1/4398033095756
  20499. * (random 1/137438953472) -> 1/137438941127
  20500. */
  20501. if (numerator(num) < -10)
  20502. numer = -(s7_int)(floor(-numerator(num) * next_random(r)));
  20503. else
  20504. {
  20505. if (numerator(num) > 10)
  20506. numer = (s7_int)floor(numerator(num) * next_random(r));
  20507. else
  20508. {
  20509. long long int diff;
  20510. numer = numerator(num);
  20511. diff = s7_int_max - denominator(num);
  20512. if (diff < 100)
  20513. return(s7_make_ratio(sc, numer, denominator(num)));
  20514. denom = denominator(num) + (s7_int)floor(diff * next_random(r));
  20515. return(s7_make_ratio(sc, numer, denom));
  20516. }
  20517. }
  20518. return(s7_make_ratio(sc, numer, denominator(num)));
  20519. }
  20520. if ((x < 1e-6) && (x > -1e-6))
  20521. error = 1e-18;
  20522. else error = 1e-12;
  20523. c_rationalize(x * next_random(r), error, &numer, &denom);
  20524. return(s7_make_ratio(sc, numer, denom));
  20525. }
  20526. case T_REAL:
  20527. return(make_real(sc, real(num) * next_random(r)));
  20528. case T_COMPLEX:
  20529. return(s7_make_complex(sc, real_part(num) * next_random(r), imag_part(num) * next_random(r)));
  20530. }
  20531. return(sc->F);
  20532. }
  20533. static s7_int c_random_i(s7_scheme *sc, s7_int arg) {return((s7_int)(arg * next_random(sc->default_rng)));} /* not round! */
  20534. IF_TO_IF(random, c_random_i)
  20535. static s7_double c_random_r(s7_scheme *sc, s7_double arg) {return(arg * next_random(sc->default_rng));}
  20536. RF_TO_RF(random, c_random_r)
  20537. static s7_pointer random_ic, random_rc, random_i;
  20538. static s7_pointer g_random_ic(s7_scheme *sc, s7_pointer args)
  20539. {
  20540. return(make_integer(sc, (s7_int)(integer(car(args)) * next_random(sc->default_rng))));
  20541. }
  20542. static s7_pointer g_random_i(s7_scheme *sc, s7_pointer args)
  20543. {
  20544. return(make_integer(sc, (s7_int)(integer(slot_value(global_slot(car(args)))) * next_random(sc->default_rng))));
  20545. }
  20546. static s7_pointer g_random_rc(s7_scheme *sc, s7_pointer args)
  20547. {
  20548. return(make_real(sc, real(car(args)) * next_random(sc->default_rng)));
  20549. }
  20550. static s7_pointer random_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  20551. {
  20552. if (args == 1)
  20553. {
  20554. s7_pointer arg1;
  20555. arg1 = cadr(expr);
  20556. if (s7_is_integer(arg1))
  20557. {
  20558. set_optimize_op(expr, HOP_SAFE_C_C);
  20559. return(random_ic);
  20560. }
  20561. if ((is_real(arg1)) &&
  20562. (!is_rational(arg1)))
  20563. {
  20564. set_optimize_op(expr, HOP_SAFE_C_C);
  20565. return(random_rc);
  20566. }
  20567. if ((is_symbol(arg1)) &&
  20568. (is_immutable_symbol(arg1)) &&
  20569. (is_global(arg1)) &&
  20570. (is_integer(slot_value(global_slot(arg1)))))
  20571. {
  20572. set_optimize_op(expr, HOP_SAFE_C_C);
  20573. return(random_i);
  20574. }
  20575. }
  20576. return(f);
  20577. }
  20578. #endif /* gmp */
  20579. /* -------------------------------- characters -------------------------------- */
  20580. #define NUM_CHARS 256
  20581. static s7_pointer g_char_to_integer(s7_scheme *sc, s7_pointer args)
  20582. {
  20583. #define H_char_to_integer "(char->integer c) converts the character c to an integer"
  20584. #define Q_char_to_integer s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_char_symbol)
  20585. if (!s7_is_character(car(args)))
  20586. method_or_bust(sc, car(args), sc->char_to_integer_symbol, args, T_CHARACTER, 0);
  20587. return(small_int(character(car(args))));
  20588. }
  20589. #define int_method_or_bust(Sc, Obj, Method, Args, Type, Num) \
  20590. { \
  20591. s7_pointer func; \
  20592. if ((has_methods(Obj)) && ((func = find_method(Sc, find_let(Sc, Obj), Method)) != Sc->undefined)) \
  20593. return(integer(s7_apply_function(Sc, func, Args))); \
  20594. if (Num == 0) simple_wrong_type_argument(Sc, Method, Obj, Type); \
  20595. wrong_type_argument(Sc, Method, Num, Obj, Type); \
  20596. }
  20597. static s7_int c_char_to_integer(s7_scheme *sc, s7_pointer p)
  20598. {
  20599. if (!s7_is_character(p))
  20600. int_method_or_bust(sc, p, sc->char_to_integer_symbol, set_plist_1(sc, p), T_CHARACTER, 0);
  20601. return(character(p));
  20602. }
  20603. PF_TO_IF(char_to_integer, c_char_to_integer)
  20604. static s7_pointer c_int_to_char(s7_scheme *sc, s7_int ind)
  20605. {
  20606. if ((ind < 0) || (ind >= NUM_CHARS))
  20607. return(simple_wrong_type_argument_with_type(sc, sc->integer_to_char_symbol, make_integer(sc, ind),
  20608. make_string_wrapper(sc, "an integer that can represent a character")));
  20609. return(s7_make_character(sc, (unsigned char)ind));
  20610. }
  20611. static s7_pointer c_integer_to_char(s7_scheme *sc, s7_pointer x)
  20612. {
  20613. s7_int ind;
  20614. if (!s7_is_integer(x))
  20615. method_or_bust(sc, x, sc->integer_to_char_symbol, list_1(sc, x), T_INTEGER, 0);
  20616. ind = s7_integer(x);
  20617. if ((ind < 0) || (ind >= NUM_CHARS))
  20618. return(simple_wrong_type_argument_with_type(sc, sc->integer_to_char_symbol, x, make_string_wrapper(sc, "an integer that can represent a character")));
  20619. return(s7_make_character(sc, (unsigned char)ind));
  20620. }
  20621. static s7_pointer g_integer_to_char(s7_scheme *sc, s7_pointer args)
  20622. {
  20623. #define H_integer_to_char "(integer->char i) converts the non-negative integer i to a character"
  20624. #define Q_integer_to_char s7_make_signature(sc, 2, sc->is_char_symbol, sc->is_integer_symbol)
  20625. return(c_integer_to_char(sc, car(args)));
  20626. }
  20627. IF_TO_PF(integer_to_char, c_int_to_char)
  20628. static unsigned char uppers[256], lowers[256];
  20629. static void init_uppers(void)
  20630. {
  20631. int i;
  20632. for (i = 0; i < 256; i++)
  20633. {
  20634. uppers[i] = (unsigned char)toupper(i);
  20635. lowers[i] = (unsigned char)tolower(i);
  20636. }
  20637. }
  20638. static s7_pointer c_char_upcase(s7_scheme *sc, s7_pointer arg)
  20639. {
  20640. if (!s7_is_character(arg))
  20641. method_or_bust(sc, arg, sc->char_upcase_symbol, set_plist_1(sc, arg), T_CHARACTER, 0);
  20642. return(s7_make_character(sc, upper_character(arg)));
  20643. }
  20644. static s7_pointer g_char_upcase(s7_scheme *sc, s7_pointer args)
  20645. {
  20646. #define H_char_upcase "(char-upcase c) converts the character c to upper case"
  20647. #define Q_char_upcase pcl_c
  20648. if (!s7_is_character(car(args)))
  20649. method_or_bust(sc, car(args), sc->char_upcase_symbol, args, T_CHARACTER, 0);
  20650. return(s7_make_character(sc, upper_character(car(args))));
  20651. }
  20652. PF_TO_PF(char_upcase, c_char_upcase)
  20653. static s7_pointer c_char_downcase(s7_scheme *sc, s7_pointer arg)
  20654. {
  20655. if (!s7_is_character(arg))
  20656. method_or_bust(sc, arg, sc->char_downcase_symbol, set_plist_1(sc, arg), T_CHARACTER, 0);
  20657. return(s7_make_character(sc, lowers[(int)character(arg)]));
  20658. }
  20659. static s7_pointer g_char_downcase(s7_scheme *sc, s7_pointer args)
  20660. {
  20661. #define H_char_downcase "(char-downcase c) converts the character c to lower case"
  20662. #define Q_char_downcase pcl_c
  20663. if (!s7_is_character(car(args)))
  20664. method_or_bust(sc, car(args), sc->char_downcase_symbol, args, T_CHARACTER, 0);
  20665. return(s7_make_character(sc, lowers[character(car(args))]));
  20666. }
  20667. PF_TO_PF(char_downcase, c_char_downcase)
  20668. static s7_pointer c_is_char_alphabetic(s7_scheme *sc, s7_pointer arg)
  20669. {
  20670. if (!s7_is_character(arg))
  20671. method_or_bust(sc, arg, sc->is_char_alphabetic_symbol, set_plist_1(sc, arg), T_CHARACTER, 0);
  20672. return(make_boolean(sc, is_char_alphabetic(arg)));
  20673. }
  20674. static s7_pointer g_is_char_alphabetic(s7_scheme *sc, s7_pointer args)
  20675. {
  20676. #define H_is_char_alphabetic "(char-alphabetic? c) returns #t if the character c is alphabetic"
  20677. #define Q_is_char_alphabetic pl_bc
  20678. if (!s7_is_character(car(args)))
  20679. method_or_bust(sc, car(args), sc->is_char_alphabetic_symbol, args, T_CHARACTER, 0);
  20680. return(make_boolean(sc, is_char_alphabetic(car(args))));
  20681. /* isalpha returns #t for (integer->char 226) and others in that range */
  20682. }
  20683. PF_TO_PF(is_char_alphabetic, c_is_char_alphabetic)
  20684. static s7_pointer c_is_char_numeric(s7_scheme *sc, s7_pointer arg)
  20685. {
  20686. if (!s7_is_character(arg))
  20687. method_or_bust(sc, arg, sc->is_char_numeric_symbol, set_plist_1(sc, arg), T_CHARACTER, 0);
  20688. return(make_boolean(sc, is_char_numeric(arg)));
  20689. }
  20690. static s7_pointer g_is_char_numeric(s7_scheme *sc, s7_pointer args)
  20691. {
  20692. #define H_is_char_numeric "(char-numeric? c) returns #t if the character c is a digit"
  20693. #define Q_is_char_numeric pl_bc
  20694. return(c_is_char_numeric(sc, car(args)));
  20695. }
  20696. PF_TO_PF(is_char_numeric, c_is_char_numeric)
  20697. static s7_pointer c_is_char_whitespace(s7_scheme *sc, s7_pointer arg)
  20698. {
  20699. if (!s7_is_character(arg))
  20700. method_or_bust(sc, arg, sc->is_char_whitespace_symbol, set_plist_1(sc, arg), T_CHARACTER, 0);
  20701. return(make_boolean(sc, is_char_whitespace(arg)));
  20702. }
  20703. static s7_pointer g_is_char_whitespace(s7_scheme *sc, s7_pointer args)
  20704. {
  20705. #define H_is_char_whitespace "(char-whitespace? c) returns #t if the character c is non-printing character"
  20706. #define Q_is_char_whitespace pl_bc
  20707. return(c_is_char_whitespace(sc, car(args)));
  20708. }
  20709. PF_TO_PF(is_char_whitespace, c_is_char_whitespace)
  20710. static s7_pointer c_is_char_upper_case(s7_scheme *sc, s7_pointer arg)
  20711. {
  20712. if (!s7_is_character(arg))
  20713. method_or_bust(sc, arg, sc->is_char_upper_case_symbol, set_plist_1(sc, arg), T_CHARACTER, 0);
  20714. return(make_boolean(sc, is_char_uppercase(arg)));
  20715. }
  20716. static s7_pointer g_is_char_upper_case(s7_scheme *sc, s7_pointer args)
  20717. {
  20718. #define H_is_char_upper_case "(char-upper-case? c) returns #t if the character c is in upper case"
  20719. #define Q_is_char_upper_case pl_bc
  20720. return(c_is_char_upper_case(sc, car(args)));
  20721. }
  20722. PF_TO_PF(is_char_upper_case, c_is_char_upper_case)
  20723. static s7_pointer c_is_char_lower_case(s7_scheme *sc, s7_pointer arg)
  20724. {
  20725. if (!s7_is_character(arg))
  20726. method_or_bust(sc, arg, sc->is_char_lower_case_symbol, set_plist_1(sc, arg), T_CHARACTER, 0);
  20727. return(make_boolean(sc, is_char_lowercase(arg)));
  20728. }
  20729. static s7_pointer g_is_char_lower_case(s7_scheme *sc, s7_pointer args)
  20730. {
  20731. #define H_is_char_lower_case "(char-lower-case? c) returns #t if the character c is in lower case"
  20732. #define Q_is_char_lower_case pl_bc
  20733. return(c_is_char_lower_case(sc, car(args)));
  20734. }
  20735. PF_TO_PF(is_char_lower_case, c_is_char_lower_case)
  20736. static s7_pointer g_is_char(s7_scheme *sc, s7_pointer args)
  20737. {
  20738. #define H_is_char "(char? obj) returns #t if obj is a character"
  20739. #define Q_is_char pl_bt
  20740. check_boolean_method(sc, s7_is_character, sc->is_char_symbol, args);
  20741. }
  20742. s7_pointer s7_make_character(s7_scheme *sc, unsigned int c)
  20743. {
  20744. return(chars[c]);
  20745. }
  20746. bool s7_is_character(s7_pointer p)
  20747. {
  20748. return(type(p) == T_CHARACTER);
  20749. }
  20750. char s7_character(s7_pointer p)
  20751. {
  20752. return(character(p));
  20753. }
  20754. static int charcmp(unsigned char c1, unsigned char c2)
  20755. {
  20756. return((c1 == c2) ? 0 : (c1 < c2) ? -1 : 1);
  20757. /* not tolower here -- the single case is apparently supposed to be upper case
  20758. * this matters in a case like (char-ci<? #\_ #\e) which Guile and Gauche say is #f
  20759. * although (char<? #\_ #\e) is #t -- the spec does not say how to interpret this!
  20760. */
  20761. }
  20762. static bool is_character_via_method(s7_scheme *sc, s7_pointer p)
  20763. {
  20764. if (s7_is_character(p))
  20765. return(true);
  20766. if (has_methods(p))
  20767. {
  20768. s7_pointer f;
  20769. f = find_method(sc, find_let(sc, p), sc->is_char_symbol);
  20770. if (f != sc->undefined)
  20771. return(is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil))));
  20772. }
  20773. return(false);
  20774. }
  20775. static s7_pointer g_char_cmp(s7_scheme *sc, s7_pointer args, int val, s7_pointer sym)
  20776. {
  20777. s7_pointer x, y;
  20778. y = car(args);
  20779. if (!s7_is_character(y))
  20780. method_or_bust(sc, y, sym, args, T_CHARACTER, 1);
  20781. for (x = cdr(args); is_pair(x); x = cdr(x))
  20782. {
  20783. if (!s7_is_character(car(x)))
  20784. method_or_bust(sc, car(x), sym, cons(sc, y, x), T_CHARACTER, position_of(x, args));
  20785. if (charcmp(character(y), character(car(x))) != val)
  20786. {
  20787. for (y = cdr(x); is_pair(y); y = cdr(y))
  20788. if (!is_character_via_method(sc, car(y)))
  20789. return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_CHARACTER));
  20790. return(sc->F);
  20791. }
  20792. y = car(x);
  20793. }
  20794. return(sc->T);
  20795. }
  20796. static s7_pointer g_char_cmp_not(s7_scheme *sc, s7_pointer args, int val, s7_pointer sym)
  20797. {
  20798. s7_pointer x, y;
  20799. y = car(args);
  20800. if (!s7_is_character(y))
  20801. method_or_bust(sc, y, sym, args, T_CHARACTER, 1);
  20802. for (x = cdr(args); is_pair(x); x = cdr(x))
  20803. {
  20804. if (!s7_is_character(car(x)))
  20805. method_or_bust(sc, car(x), sym, cons(sc, y, x), T_CHARACTER, position_of(x, args));
  20806. if (charcmp(character(y), character(car(x))) == val)
  20807. {
  20808. for (y = cdr(x); is_pair(y); y = cdr(y))
  20809. if (!is_character_via_method(sc, car(y)))
  20810. return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_CHARACTER));
  20811. return(sc->F);
  20812. }
  20813. y = car(x);
  20814. }
  20815. return(sc->T);
  20816. }
  20817. static s7_pointer g_chars_are_equal(s7_scheme *sc, s7_pointer args)
  20818. {
  20819. #define H_chars_are_equal "(char=? char ...) returns #t if all the character arguments are equal"
  20820. #define Q_chars_are_equal pcl_bc
  20821. s7_pointer x, y;
  20822. y = car(args);
  20823. if (!s7_is_character(y))
  20824. method_or_bust(sc, y, sc->char_eq_symbol, args, T_CHARACTER, 1);
  20825. for (x = cdr(args); is_pair(x); x = cdr(x))
  20826. {
  20827. if (!s7_is_character(car(x)))
  20828. method_or_bust(sc, car(x), sc->char_eq_symbol, cons(sc, y, x), T_CHARACTER, position_of(x, args));
  20829. if (car(x) != y)
  20830. {
  20831. for (y = cdr(x); is_pair(y); y = cdr(y))
  20832. if (!is_character_via_method(sc, car(y)))
  20833. return(wrong_type_argument(sc, sc->char_eq_symbol, position_of(y, args), car(y), T_CHARACTER));
  20834. return(sc->F);
  20835. }
  20836. }
  20837. return(sc->T);
  20838. }
  20839. static s7_pointer g_chars_are_less(s7_scheme *sc, s7_pointer args)
  20840. {
  20841. #define H_chars_are_less "(char<? char ...) returns #t if all the character arguments are increasing"
  20842. #define Q_chars_are_less pcl_bc
  20843. return(g_char_cmp(sc, args, -1, sc->char_lt_symbol));
  20844. }
  20845. static s7_pointer g_chars_are_greater(s7_scheme *sc, s7_pointer args)
  20846. {
  20847. #define H_chars_are_greater "(char>? char ...) returns #t if all the character arguments are decreasing"
  20848. #define Q_chars_are_greater pcl_bc
  20849. return(g_char_cmp(sc, args, 1, sc->char_gt_symbol));
  20850. }
  20851. static s7_pointer g_chars_are_geq(s7_scheme *sc, s7_pointer args)
  20852. {
  20853. #define H_chars_are_geq "(char>=? char ...) returns #t if all the character arguments are equal or decreasing"
  20854. #define Q_chars_are_geq pcl_bc
  20855. return(g_char_cmp_not(sc, args, -1, sc->char_geq_symbol));
  20856. }
  20857. static s7_pointer g_chars_are_leq(s7_scheme *sc, s7_pointer args)
  20858. {
  20859. #define H_chars_are_leq "(char<=? char ...) returns #t if all the character arguments are equal or increasing"
  20860. #define Q_chars_are_leq pcl_bc
  20861. return(g_char_cmp_not(sc, args, 1, sc->char_leq_symbol));
  20862. }
  20863. static s7_pointer simple_char_eq;
  20864. static s7_pointer g_simple_char_eq(s7_scheme *sc, s7_pointer args)
  20865. {
  20866. return(make_boolean(sc, character(car(args)) == character(cadr(args))));
  20867. }
  20868. static s7_pointer c_char_eq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  20869. {
  20870. if (!s7_is_character(x))
  20871. method_or_bust(sc, x, sc->char_eq_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  20872. if (!s7_is_character(y))
  20873. method_or_bust(sc, y, sc->char_eq_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  20874. return(make_boolean(sc, x == y));
  20875. }
  20876. static s7_pointer s7_procedure_signature(s7_scheme *sc, s7_pointer x);
  20877. static bool char_check(s7_scheme *sc, s7_pointer obj)
  20878. {
  20879. if (s7_is_character(obj)) return(true);
  20880. if ((is_pair(obj)) && (is_symbol(car(obj))))
  20881. {
  20882. s7_pointer sig;
  20883. sig = s7_procedure_signature(sc, s7_symbol_value(sc, car(obj)));
  20884. return((sig) && (is_pair(sig)) && (car(sig) == sc->is_char_symbol));
  20885. }
  20886. return(false);
  20887. }
  20888. PF2_TO_PF_X(char_eq, char_check, c_char_eq, c_is_eq)
  20889. static s7_pointer char_equal_s_ic, char_equal_2;
  20890. static s7_pointer g_char_equal_s_ic(s7_scheme *sc, s7_pointer args)
  20891. {
  20892. s7_pointer c;
  20893. c = find_symbol_checked(sc, car(args));
  20894. if (c == cadr(args))
  20895. return(sc->T);
  20896. if (s7_is_character(c))
  20897. return(sc->F);
  20898. method_or_bust(sc, c, sc->char_eq_symbol, list_2(sc, c, cadr(args)), T_CHARACTER, 1);
  20899. }
  20900. static s7_pointer g_char_equal_2(s7_scheme *sc, s7_pointer args)
  20901. {
  20902. if (!s7_is_character(car(args)))
  20903. method_or_bust(sc, car(args), sc->char_eq_symbol, args, T_CHARACTER, 1);
  20904. if (car(args) == cadr(args))
  20905. return(sc->T);
  20906. if (!s7_is_character(cadr(args)))
  20907. method_or_bust(sc, cadr(args), sc->char_eq_symbol, args, T_CHARACTER, 2);
  20908. return(sc->F);
  20909. }
  20910. static s7_pointer char_less_s_ic, char_less_2;
  20911. static s7_pointer g_char_less_s_ic(s7_scheme *sc, s7_pointer args)
  20912. {
  20913. if (!s7_is_character(car(args)))
  20914. method_or_bust(sc, car(args), sc->char_lt_symbol, args, T_CHARACTER, 1);
  20915. return(make_boolean(sc, character(car(args)) < character(cadr(args))));
  20916. }
  20917. static s7_pointer g_char_less_2(s7_scheme *sc, s7_pointer args)
  20918. {
  20919. if (!s7_is_character(car(args)))
  20920. method_or_bust(sc, car(args), sc->char_lt_symbol, args, T_CHARACTER, 1);
  20921. if (!s7_is_character(cadr(args)))
  20922. method_or_bust(sc, cadr(args), sc->char_lt_symbol, args, T_CHARACTER, 2);
  20923. return(make_boolean(sc, character(car(args)) < character(cadr(args))));
  20924. }
  20925. static s7_pointer c_char_lt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  20926. {
  20927. if (!s7_is_character(x))
  20928. method_or_bust(sc, x, sc->char_lt_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  20929. if (!s7_is_character(y))
  20930. method_or_bust(sc, y, sc->char_lt_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  20931. return(make_boolean(sc, character(x) < character(y)));
  20932. }
  20933. static s7_pointer c_clt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  20934. {
  20935. return(make_boolean(sc, character(x) < character(y)));
  20936. }
  20937. PF2_TO_PF_X(char_lt, char_check, c_char_lt, c_clt)
  20938. static s7_pointer char_greater_s_ic, char_greater_2;
  20939. static s7_pointer g_char_greater_s_ic(s7_scheme *sc, s7_pointer args)
  20940. {
  20941. if (!s7_is_character(car(args)))
  20942. method_or_bust(sc, car(args), sc->char_gt_symbol, args, T_CHARACTER, 1);
  20943. return(make_boolean(sc, character(car(args)) > character(cadr(args))));
  20944. }
  20945. static s7_pointer g_char_greater_2(s7_scheme *sc, s7_pointer args)
  20946. {
  20947. if (!s7_is_character(car(args)))
  20948. method_or_bust(sc, car(args), sc->char_gt_symbol, args, T_CHARACTER, 1);
  20949. if (!s7_is_character(cadr(args)))
  20950. method_or_bust(sc, cadr(args), sc->char_gt_symbol, args, T_CHARACTER, 2);
  20951. return(make_boolean(sc, character(car(args)) > character(cadr(args))));
  20952. }
  20953. static s7_pointer c_char_gt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  20954. {
  20955. if (!s7_is_character(x))
  20956. method_or_bust(sc, x, sc->char_gt_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  20957. if (!s7_is_character(y))
  20958. method_or_bust(sc, y, sc->char_gt_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  20959. return(make_boolean(sc, character(x) > character(y)));
  20960. }
  20961. static s7_pointer c_cgt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  20962. {
  20963. return(make_boolean(sc, character(x) > character(y)));
  20964. }
  20965. PF2_TO_PF_X(char_gt, char_check, c_char_gt, c_cgt)
  20966. static s7_pointer c_char_geq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  20967. {
  20968. if (!s7_is_character(x))
  20969. method_or_bust(sc, x, sc->char_geq_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  20970. if (!s7_is_character(y))
  20971. method_or_bust(sc, y, sc->char_geq_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  20972. return(make_boolean(sc, character(x) >= character(y)));
  20973. }
  20974. PF2_TO_PF(char_geq, c_char_geq)
  20975. static s7_pointer c_char_leq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  20976. {
  20977. if (!s7_is_character(x))
  20978. method_or_bust(sc, x, sc->char_leq_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  20979. if (!s7_is_character(y))
  20980. method_or_bust(sc, y, sc->char_leq_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  20981. return(make_boolean(sc, character(x) <= character(y)));
  20982. }
  20983. PF2_TO_PF(char_leq, c_char_leq)
  20984. #if (!WITH_PURE_S7)
  20985. static s7_pointer g_char_cmp_ci(s7_scheme *sc, s7_pointer args, int val, s7_pointer sym)
  20986. {
  20987. s7_pointer x, y;
  20988. y = car(args);
  20989. if (!s7_is_character(y))
  20990. method_or_bust(sc, y, sym, args, T_CHARACTER, 1);
  20991. for (x = cdr(args); is_pair(x); x = cdr(x))
  20992. {
  20993. if (!s7_is_character(car(x)))
  20994. method_or_bust(sc, car(x), sym, cons(sc, y, x), T_CHARACTER, position_of(x, args));
  20995. if (charcmp(upper_character(y), upper_character(car(x))) != val)
  20996. {
  20997. for (y = cdr(x); is_pair(y); y = cdr(y))
  20998. if (!is_character_via_method(sc, car(y)))
  20999. return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_CHARACTER));
  21000. return(sc->F);
  21001. }
  21002. y = car(x);
  21003. }
  21004. return(sc->T);
  21005. }
  21006. static s7_pointer g_char_cmp_ci_not(s7_scheme *sc, s7_pointer args, int val, s7_pointer sym)
  21007. {
  21008. s7_pointer x, y;
  21009. y = car(args);
  21010. if (!s7_is_character(y))
  21011. method_or_bust(sc, y, sym, args, T_CHARACTER, 1);
  21012. for (x = cdr(args); is_pair(x); x = cdr(x))
  21013. {
  21014. if (!s7_is_character(car(x)))
  21015. method_or_bust(sc, car(x), sym, cons(sc, y, x), T_CHARACTER, position_of(x, args));
  21016. if (charcmp(upper_character(y), upper_character(car(x))) == val)
  21017. {
  21018. for (y = cdr(x); is_pair(y); y = cdr(y))
  21019. if (!is_character_via_method(sc, car(y)))
  21020. return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_CHARACTER));
  21021. return(sc->F);
  21022. }
  21023. y = car(x);
  21024. }
  21025. return(sc->T);
  21026. }
  21027. static s7_pointer g_chars_are_ci_equal(s7_scheme *sc, s7_pointer args)
  21028. {
  21029. #define H_chars_are_ci_equal "(char-ci=? char ...) returns #t if all the character arguments are equal, ignoring case"
  21030. #define Q_chars_are_ci_equal pcl_bc
  21031. return(g_char_cmp_ci(sc, args, 0, sc->char_ci_eq_symbol));
  21032. }
  21033. static s7_pointer c_char_ci_eq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21034. {
  21035. if (!s7_is_character(x))
  21036. method_or_bust(sc, x, sc->char_ci_eq_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  21037. if (!s7_is_character(y))
  21038. method_or_bust(sc, y, sc->char_ci_eq_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  21039. return(make_boolean(sc, upper_character(x) == upper_character(y)));
  21040. }
  21041. PF2_TO_PF(char_ci_eq, c_char_ci_eq)
  21042. static s7_pointer g_chars_are_ci_less(s7_scheme *sc, s7_pointer args)
  21043. {
  21044. #define H_chars_are_ci_less "(char-ci<? char ...) returns #t if all the character arguments are increasing, ignoring case"
  21045. #define Q_chars_are_ci_less pcl_bc
  21046. return(g_char_cmp_ci(sc, args, -1, sc->char_ci_lt_symbol));
  21047. }
  21048. static s7_pointer c_char_ci_lt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21049. {
  21050. if (!s7_is_character(x))
  21051. method_or_bust(sc, x, sc->char_ci_lt_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  21052. if (!s7_is_character(y))
  21053. method_or_bust(sc, y, sc->char_ci_lt_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  21054. return(make_boolean(sc, upper_character(x) < upper_character(y)));
  21055. }
  21056. PF2_TO_PF(char_ci_lt, c_char_ci_lt)
  21057. static s7_pointer g_chars_are_ci_greater(s7_scheme *sc, s7_pointer args)
  21058. {
  21059. #define H_chars_are_ci_greater "(char-ci>? char ...) returns #t if all the character arguments are decreasing, ignoring case"
  21060. #define Q_chars_are_ci_greater pcl_bc
  21061. return(g_char_cmp_ci(sc, args, 1, sc->char_ci_gt_symbol));
  21062. }
  21063. static s7_pointer c_char_ci_gt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21064. {
  21065. if (!s7_is_character(x))
  21066. method_or_bust(sc, x, sc->char_ci_gt_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  21067. if (!s7_is_character(y))
  21068. method_or_bust(sc, y, sc->char_ci_gt_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  21069. return(make_boolean(sc, upper_character(x) > upper_character(y)));
  21070. }
  21071. PF2_TO_PF(char_ci_gt, c_char_ci_gt)
  21072. static s7_pointer g_chars_are_ci_geq(s7_scheme *sc, s7_pointer args)
  21073. {
  21074. #define H_chars_are_ci_geq "(char-ci>=? char ...) returns #t if all the character arguments are equal or decreasing, ignoring case"
  21075. #define Q_chars_are_ci_geq pcl_bc
  21076. return(g_char_cmp_ci_not(sc, args, -1, sc->char_ci_geq_symbol));
  21077. }
  21078. static s7_pointer c_char_ci_geq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21079. {
  21080. if (!s7_is_character(x))
  21081. method_or_bust(sc, x, sc->char_ci_geq_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  21082. if (!s7_is_character(y))
  21083. method_or_bust(sc, y, sc->char_ci_geq_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  21084. return(make_boolean(sc, upper_character(x) >= upper_character(y)));
  21085. }
  21086. PF2_TO_PF(char_ci_geq, c_char_ci_geq)
  21087. static s7_pointer g_chars_are_ci_leq(s7_scheme *sc, s7_pointer args)
  21088. {
  21089. #define H_chars_are_ci_leq "(char-ci<=? char ...) returns #t if all the character arguments are equal or increasing, ignoring case"
  21090. #define Q_chars_are_ci_leq pcl_bc
  21091. return(g_char_cmp_ci_not(sc, args, 1, sc->char_ci_leq_symbol));
  21092. }
  21093. static s7_pointer c_char_ci_leq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21094. {
  21095. if (!s7_is_character(x))
  21096. method_or_bust(sc, x, sc->char_ci_leq_symbol, list_2(sc, x, y), T_CHARACTER, 1);
  21097. if (!s7_is_character(y))
  21098. method_or_bust(sc, y, sc->char_ci_leq_symbol, list_2(sc, x, y), T_CHARACTER, 2);
  21099. return(make_boolean(sc, upper_character(x) <= upper_character(y)));
  21100. }
  21101. PF2_TO_PF(char_ci_leq, c_char_ci_leq)
  21102. #endif /* not pure s7 */
  21103. static s7_pointer g_char_position(s7_scheme *sc, s7_pointer args)
  21104. {
  21105. #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"
  21106. #define Q_char_position s7_make_signature(sc, 4, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_boolean_symbol), s7_make_signature(sc, 2, sc->is_char_symbol, sc->is_string_symbol), sc->is_string_symbol, sc->is_integer_symbol)
  21107. const char *porig, *p, *pset;
  21108. s7_int start, pos, len; /* not "int" because start arg might be most-negative-fixnum */
  21109. s7_pointer arg1, arg2;
  21110. arg1 = car(args);
  21111. if ((!s7_is_character(arg1)) &&
  21112. (!is_string(arg1)))
  21113. method_or_bust(sc, arg1, sc->char_position_symbol, args, T_CHARACTER, 1);
  21114. arg2 = cadr(args);
  21115. if (!is_string(arg2))
  21116. method_or_bust(sc, arg2, sc->char_position_symbol, args, T_STRING, 2);
  21117. porig = string_value(arg2);
  21118. len = string_length(arg2);
  21119. if (is_pair(cddr(args)))
  21120. {
  21121. s7_pointer arg3;
  21122. arg3 = caddr(args);
  21123. if (!s7_is_integer(arg3))
  21124. {
  21125. s7_pointer p;
  21126. if (!s7_is_integer(p = check_values(sc, arg3, cddr(args))))
  21127. method_or_bust(sc, arg3, sc->char_position_symbol, args, T_INTEGER, 3);
  21128. arg3 = p;
  21129. }
  21130. start = s7_integer(arg3);
  21131. if (start < 0)
  21132. return(wrong_type_argument_with_type(sc, sc->char_position_symbol, 3, arg3, a_non_negative_integer_string));
  21133. }
  21134. else start = 0;
  21135. if (start >= len) return(sc->F);
  21136. if (s7_is_character(arg1))
  21137. {
  21138. char c;
  21139. c = character(arg1);
  21140. p = strchr((const char *)(porig + start), (int)c); /* use strchrnul in Gnu C to catch embedded null case */
  21141. if (p)
  21142. return(make_integer(sc, p - porig));
  21143. return(sc->F);
  21144. }
  21145. if (string_length(arg1) == 0)
  21146. return(sc->F);
  21147. pset = string_value(arg1);
  21148. pos = strcspn((const char *)(porig + start), (const char *)pset);
  21149. if ((pos + start) < len)
  21150. return(make_integer(sc, pos + start));
  21151. /* but if the string has an embedded null, we can get erroneous results here --
  21152. * perhaps check for null at pos+start? What about a searched-for string that
  21153. * also has embedded nulls?
  21154. *
  21155. * The embedded nulls are for byte-vector usages, where presumably you're not talking
  21156. * about chars and strings, so I think I'll ignore these cases. In unicode, you'd
  21157. * want to use unicode-aware searchers, so that also is irrelevant.
  21158. */
  21159. return(sc->F);
  21160. }
  21161. static s7_pointer c_char_position_ppi(s7_scheme *sc, s7_pointer x, s7_pointer y, s7_int z) {return(g_char_position(sc, set_plist_3(sc, x, y, make_integer(sc, z))));}
  21162. static s7_pointer c_char_position_pp(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_char_position(sc, set_plist_2(sc, x, y)));}
  21163. PPIF_TO_PF(char_position, c_char_position_pp, c_char_position_ppi)
  21164. static s7_pointer char_position_csi;
  21165. static s7_pointer g_char_position_csi(s7_scheme *sc, s7_pointer args)
  21166. {
  21167. /* assume char arg1, no end */
  21168. const char *porig, *p;
  21169. char c;
  21170. s7_pointer arg2;
  21171. s7_int start, len;
  21172. c = character(car(args));
  21173. arg2 = cadr(args);
  21174. if (!is_string(arg2))
  21175. return(g_char_position(sc, args));
  21176. len = string_length(arg2); /* can't return #f here if len==0 -- need start error check first */
  21177. porig = string_value(arg2);
  21178. if (is_pair(cddr(args)))
  21179. {
  21180. s7_pointer arg3;
  21181. arg3 = caddr(args);
  21182. if (!s7_is_integer(arg3))
  21183. return(g_char_position(sc, args));
  21184. start = s7_integer(arg3);
  21185. if (start < 0)
  21186. return(wrong_type_argument_with_type(sc, sc->char_position_symbol, 3, arg3, a_non_negative_integer_string));
  21187. if (start >= len) return(sc->F);
  21188. }
  21189. else start = 0;
  21190. if (len == 0) return(sc->F);
  21191. p = strchr((const char *)(porig + start), (int)c);
  21192. if (p)
  21193. return(make_integer(sc, p - porig));
  21194. return(sc->F);
  21195. }
  21196. static s7_pointer g_string_position(s7_scheme *sc, s7_pointer args)
  21197. {
  21198. #define H_string_position "(string-position str1 str2 (start 0)) returns the starting position of str1 in str2 or #f"
  21199. #define Q_string_position s7_make_signature(sc, 4, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_boolean_symbol), sc->is_string_symbol, sc->is_string_symbol, sc->is_integer_symbol)
  21200. const char *s1, *s2, *p2;
  21201. s7_int start = 0;
  21202. s7_pointer s1p, s2p;
  21203. s1p = car(args);
  21204. if (!is_string(s1p))
  21205. method_or_bust(sc, s1p, sc->string_position_symbol, args, T_STRING, 1);
  21206. s2p = cadr(args);
  21207. if (!is_string(s2p))
  21208. method_or_bust(sc, s2p, sc->string_position_symbol, args, T_STRING, 2);
  21209. if (is_pair(cddr(args)))
  21210. {
  21211. s7_pointer arg3;
  21212. arg3 = caddr(args);
  21213. if (!s7_is_integer(arg3))
  21214. {
  21215. s7_pointer p;
  21216. if (!s7_is_integer(p = check_values(sc, arg3, cddr(args))))
  21217. method_or_bust(sc, arg3, sc->string_position_symbol, args, T_INTEGER, 3);
  21218. arg3 = p;
  21219. }
  21220. start = s7_integer(arg3);
  21221. if (start < 0)
  21222. return(wrong_type_argument_with_type(sc, sc->string_position_symbol, 3, arg3, a_non_negative_integer_string));
  21223. }
  21224. if (string_length(s1p) == 0)
  21225. return(sc->F);
  21226. s1 = string_value(s1p);
  21227. s2 = string_value(s2p);
  21228. if (start >= string_length(s2p))
  21229. return(sc->F);
  21230. p2 = strstr((const char *)(s2 + start), s1);
  21231. if (!p2) return(sc->F);
  21232. return(make_integer(sc, p2 - s2));
  21233. }
  21234. static s7_pointer c_string_position_ppi(s7_scheme *sc, s7_pointer x, s7_pointer y, s7_int z) {return(g_string_position(sc, set_plist_3(sc, x, y, make_integer(sc, z))));}
  21235. static s7_pointer c_string_position_pp(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_string_position(sc, set_plist_2(sc, x, y)));}
  21236. PPIF_TO_PF(string_position, c_string_position_pp, c_string_position_ppi)
  21237. /* -------------------------------- strings -------------------------------- */
  21238. s7_pointer s7_make_string_with_length(s7_scheme *sc, const char *str, int len)
  21239. {
  21240. s7_pointer x;
  21241. new_cell(sc, x, T_STRING | T_SAFE_PROCEDURE);
  21242. string_value(x) = (char *)malloc((len + 1) * sizeof(char));
  21243. if (len != 0) /* memcpy can segfault if string_value(x) is NULL */
  21244. memcpy((void *)string_value(x), (void *)str, len);
  21245. string_value(x)[len] = 0;
  21246. string_length(x) = len;
  21247. string_hash(x) = 0;
  21248. string_needs_free(x) = true;
  21249. Add_String(x);
  21250. return(x);
  21251. }
  21252. static s7_pointer make_string_uncopied_with_length(s7_scheme *sc, char *str, int len)
  21253. {
  21254. s7_pointer x;
  21255. new_cell(sc, x, T_STRING | T_SAFE_PROCEDURE);
  21256. string_value(x) = str;
  21257. string_length(x) = len;
  21258. string_hash(x) = 0;
  21259. string_needs_free(x) = true;
  21260. add_string(sc, x);
  21261. return(x);
  21262. }
  21263. static s7_pointer make_string_wrapper_with_length(s7_scheme *sc, const char *str, int len)
  21264. {
  21265. s7_pointer x;
  21266. new_cell(sc, x, T_STRING | T_IMMUTABLE | T_SAFE_PROCEDURE);
  21267. string_value(x) = (char *)str;
  21268. string_length(x) = len;
  21269. string_hash(x) = 0;
  21270. string_needs_free(x) = false;
  21271. return(x);
  21272. }
  21273. static s7_pointer make_string_wrapper(s7_scheme *sc, const char *str)
  21274. {
  21275. return(make_string_wrapper_with_length(sc, str, safe_strlen(str)));
  21276. }
  21277. static s7_pointer make_empty_string(s7_scheme *sc, int len, char fill)
  21278. {
  21279. s7_pointer x;
  21280. new_cell(sc, x, T_STRING);
  21281. string_value(x) = (char *)malloc((len + 1) * sizeof(char));
  21282. if (fill != 0)
  21283. memset((void *)(string_value(x)), fill, len);
  21284. string_value(x)[len] = 0;
  21285. string_hash(x) = 0;
  21286. string_length(x) = len;
  21287. string_needs_free(x) = true;
  21288. add_string(sc, x);
  21289. return(x);
  21290. }
  21291. s7_pointer s7_make_string(s7_scheme *sc, const char *str)
  21292. {
  21293. if (str)
  21294. return(s7_make_string_with_length(sc, str, safe_strlen(str)));
  21295. return(make_empty_string(sc, 0, 0));
  21296. }
  21297. static char *make_permanent_string(const char *str)
  21298. {
  21299. char *x;
  21300. int len;
  21301. len = safe_strlen(str);
  21302. x = (char *)malloc((len + 1) * sizeof(char));
  21303. memcpy((void *)x, (void *)str, len);
  21304. x[len] = 0;
  21305. return(x);
  21306. }
  21307. s7_pointer s7_make_permanent_string(const char *str)
  21308. {
  21309. /* for the symbol table which is never GC'd */
  21310. s7_pointer x;
  21311. x = alloc_pointer();
  21312. unheap(x);
  21313. set_type(x, T_STRING | T_IMMUTABLE);
  21314. if (str)
  21315. {
  21316. unsigned int len;
  21317. len = safe_strlen(str);
  21318. string_length(x) = len;
  21319. string_value(x) = (char *)malloc((len + 1) * sizeof(char));
  21320. memcpy((void *)string_value(x), (void *)str, len);
  21321. string_value(x)[len] = 0;
  21322. }
  21323. else
  21324. {
  21325. string_value(x) = NULL;
  21326. string_length(x) = 0;
  21327. }
  21328. string_hash(x) = 0;
  21329. string_needs_free(x) = false;
  21330. return(x);
  21331. }
  21332. static s7_pointer make_temporary_string(s7_scheme *sc, const char *str, int len)
  21333. {
  21334. s7_pointer p;
  21335. p = sc->tmp_strs[0];
  21336. prepare_temporary_string(sc, len + 1, 0);
  21337. string_length(p) = len;
  21338. if (len > 0)
  21339. memmove((void *)(string_value(p)), (void *)str, len); /* not memcpy because str might be a temp string (i.e. sc->tmp_str_chars -> itself) */
  21340. string_value(p)[len] = 0;
  21341. return(p);
  21342. }
  21343. bool s7_is_string(s7_pointer p)
  21344. {
  21345. return(is_string(p));
  21346. }
  21347. const char *s7_string(s7_pointer p)
  21348. {
  21349. return(string_value(p));
  21350. }
  21351. static s7_pointer g_is_string(s7_scheme *sc, s7_pointer args)
  21352. {
  21353. #define H_is_string "(string? obj) returns #t if obj is a string"
  21354. #define Q_is_string pl_bt
  21355. check_boolean_method(sc, is_string, sc->is_string_symbol, args);
  21356. }
  21357. /* -------------------------------- make-string -------------------------------- */
  21358. static s7_pointer g_make_string(s7_scheme *sc, s7_pointer args)
  21359. {
  21360. #define H_make_string "(make-string len (val #\\space)) makes a string of length len filled with the character val (default: space)"
  21361. #define Q_make_string s7_make_signature(sc, 3, sc->is_string_symbol, sc->is_integer_symbol, sc->is_char_symbol)
  21362. s7_pointer n;
  21363. s7_int len;
  21364. char fill = ' ';
  21365. n = car(args);
  21366. if (!s7_is_integer(n))
  21367. {
  21368. check_two_methods(sc, n, sc->make_string_symbol, sc->make_byte_vector_symbol, args);
  21369. return(wrong_type_argument(sc, sc->make_string_symbol, 1, n, T_INTEGER));
  21370. }
  21371. len = s7_integer(n);
  21372. if ((len < 0) || (len > sc->max_string_length))
  21373. return(out_of_range(sc, sc->make_string_symbol, small_int(1), n, (len < 0) ? its_negative_string : its_too_large_string));
  21374. if (is_not_null(cdr(args)))
  21375. {
  21376. if (!s7_is_character(cadr(args)))
  21377. method_or_bust(sc, cadr(args), sc->make_string_symbol, args, T_CHARACTER, 2);
  21378. fill = s7_character(cadr(args));
  21379. }
  21380. n = make_empty_string(sc, (int)len, fill);
  21381. if (fill == '\0')
  21382. memset((void *)string_value(n), 0, (int)len);
  21383. return(n);
  21384. }
  21385. static s7_pointer c_make_string(s7_scheme *sc, s7_int len) {return(make_empty_string(sc, (int)len, ' '));}
  21386. IF_TO_PF(make_string, c_make_string)
  21387. #if (!WITH_PURE_S7)
  21388. static s7_pointer g_string_length(s7_scheme *sc, s7_pointer args)
  21389. {
  21390. #define H_string_length "(string-length str) returns the length of the string str"
  21391. #define Q_string_length s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_string_symbol)
  21392. s7_pointer p;
  21393. p = car(args);
  21394. if (!is_string(p))
  21395. method_or_bust(sc, p, sc->string_length_symbol, args, T_STRING, 0);
  21396. return(make_integer(sc, string_length(p)));
  21397. }
  21398. static s7_int c_string_length(s7_scheme *sc, s7_pointer p)
  21399. {
  21400. if (!is_string(p))
  21401. int_method_or_bust(sc, p, sc->string_length_symbol, set_plist_1(sc, p), T_STRING, 0);
  21402. return(string_length(p));
  21403. }
  21404. PF_TO_IF(string_length, c_string_length)
  21405. #endif
  21406. /* -------------------------------- string-up|downcase -------------------------------- */
  21407. static s7_pointer c_string_downcase(s7_scheme *sc, s7_pointer p)
  21408. {
  21409. s7_pointer newstr;
  21410. int i, len;
  21411. unsigned char *nstr, *ostr;
  21412. sc->temp3 = p;
  21413. if (!is_string(p))
  21414. method_or_bust(sc, p, sc->string_downcase_symbol, list_1(sc, p), T_STRING, 0);
  21415. len = string_length(p);
  21416. newstr = make_empty_string(sc, len, 0);
  21417. ostr = (unsigned char *)string_value(p);
  21418. nstr = (unsigned char *)string_value(newstr);
  21419. for (i = 0; i < len; i++)
  21420. nstr[i] = lowers[(int)ostr[i]];
  21421. return(newstr);
  21422. }
  21423. static s7_pointer g_string_downcase(s7_scheme *sc, s7_pointer args)
  21424. {
  21425. #define H_string_downcase "(string-downcase str) returns the lower case version of str."
  21426. #define Q_string_downcase pcl_s
  21427. return(c_string_downcase(sc, car(args)));
  21428. }
  21429. PF_TO_PF(string_downcase, c_string_downcase)
  21430. static s7_pointer c_string_upcase(s7_scheme *sc, s7_pointer p)
  21431. {
  21432. s7_pointer newstr;
  21433. int i, len;
  21434. unsigned char *nstr, *ostr;
  21435. sc->temp3 = p;
  21436. if (!is_string(p))
  21437. method_or_bust(sc, p, sc->string_upcase_symbol, list_1(sc, p), T_STRING, 0);
  21438. len = string_length(p);
  21439. newstr = make_empty_string(sc, len, 0);
  21440. ostr = (unsigned char *)string_value(p);
  21441. nstr = (unsigned char *)string_value(newstr);
  21442. for (i = 0; i < len; i++)
  21443. nstr[i] = uppers[(int)ostr[i]];
  21444. return(newstr);
  21445. }
  21446. static s7_pointer g_string_upcase(s7_scheme *sc, s7_pointer args)
  21447. {
  21448. #define H_string_upcase "(string-upcase str) returns the upper case version of str."
  21449. #define Q_string_upcase pcl_s
  21450. return(c_string_upcase(sc, car(args)));
  21451. }
  21452. PF_TO_PF(string_upcase, c_string_upcase)
  21453. unsigned int s7_string_length(s7_pointer str)
  21454. {
  21455. return(string_length(str));
  21456. }
  21457. /* -------------------------------- string-ref -------------------------------- */
  21458. static s7_pointer string_ref_1(s7_scheme *sc, s7_pointer strng, s7_pointer index)
  21459. {
  21460. char *str;
  21461. s7_int ind;
  21462. if (!s7_is_integer(index))
  21463. {
  21464. s7_pointer p;
  21465. if (!s7_is_integer(p = check_values(sc, index, cons(sc, index, sc->nil))))
  21466. method_or_bust(sc, index, sc->string_ref_symbol, list_2(sc, strng, index), T_INTEGER, 2);
  21467. index = p;
  21468. }
  21469. ind = s7_integer(index);
  21470. if (ind < 0)
  21471. return(wrong_type_argument_with_type(sc, sc->string_ref_symbol, 2, index, a_non_negative_integer_string));
  21472. if (ind >= string_length(strng))
  21473. return(out_of_range(sc, sc->string_ref_symbol, small_int(2), index, its_too_large_string));
  21474. str = string_value(strng);
  21475. return(s7_make_character(sc, ((unsigned char *)str)[ind]));
  21476. }
  21477. static s7_pointer g_string_ref(s7_scheme *sc, s7_pointer args)
  21478. {
  21479. s7_pointer strng, index, p;
  21480. char *str;
  21481. s7_int ind;
  21482. #define H_string_ref "(string-ref str index) returns the character at the index-th element of the string str"
  21483. #define Q_string_ref s7_make_signature(sc, 3, sc->is_char_symbol, sc->is_string_symbol, sc->is_integer_symbol)
  21484. strng = car(args);
  21485. if (!is_string(strng))
  21486. method_or_bust(sc, strng, sc->string_ref_symbol, args, T_STRING, 1);
  21487. index = cadr(args);
  21488. if (!s7_is_integer(index))
  21489. {
  21490. if (!s7_is_integer(p = check_values(sc, index, cdr(args))))
  21491. method_or_bust(sc, index, sc->string_ref_symbol, args, T_INTEGER, 2);
  21492. index = p;
  21493. }
  21494. ind = s7_integer(index);
  21495. if (ind < 0)
  21496. return(wrong_type_argument_with_type(sc, sc->string_ref_symbol, 2, index, a_non_negative_integer_string));
  21497. if (ind >= string_length(strng))
  21498. return(out_of_range(sc, sc->string_ref_symbol, small_int(2), index, its_too_large_string));
  21499. str = string_value(strng);
  21500. return(s7_make_character(sc, ((unsigned char *)str)[ind]));
  21501. }
  21502. static s7_pointer c_string_ref(s7_scheme *sc, s7_pointer str, s7_int ind)
  21503. {
  21504. if (!is_string(str))
  21505. method_or_bust(sc, str, sc->string_ref_symbol, list_2(sc, str, make_integer(sc, ind)), T_STRING, 1);
  21506. if (ind < 0)
  21507. return(wrong_type_argument_with_type(sc, sc->string_ref_symbol, 2, make_integer(sc, ind), a_non_negative_integer_string));
  21508. if (ind >= string_length(str))
  21509. return(out_of_range(sc, sc->string_ref_symbol, small_int(2), make_integer(sc, ind), its_too_large_string));
  21510. return(s7_make_character(sc, ((unsigned char *)string_value(str))[ind]));
  21511. }
  21512. PIF_TO_PF(string_ref, c_string_ref)
  21513. /* -------------------------------- string-set! -------------------------------- */
  21514. static s7_pointer g_string_set(s7_scheme *sc, s7_pointer args)
  21515. {
  21516. #define H_string_set "(string-set! str index chr) sets the index-th element of the string str to the character chr"
  21517. #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)
  21518. s7_pointer x, c, index;
  21519. char *str;
  21520. s7_int ind;
  21521. x = car(args);
  21522. if (!is_string(x))
  21523. method_or_bust(sc, x, sc->string_set_symbol, args, T_STRING, 1);
  21524. index = cadr(args);
  21525. if (!s7_is_integer(index))
  21526. {
  21527. s7_pointer p;
  21528. if (!s7_is_integer(p = check_values(sc, index, cdr(args))))
  21529. method_or_bust(sc, index, sc->string_set_symbol, args, T_INTEGER, 2);
  21530. index = p;
  21531. }
  21532. ind = s7_integer(index);
  21533. if (ind < 0)
  21534. return(wrong_type_argument_with_type(sc, sc->string_set_symbol, 2, index, a_non_negative_integer_string));
  21535. if (ind >= string_length(x))
  21536. return(out_of_range(sc, sc->string_set_symbol, small_int(2), index, its_too_large_string));
  21537. str = string_value(_TSet(x));
  21538. c = caddr(args);
  21539. if (!s7_is_character(c))
  21540. {
  21541. if ((is_byte_vector(x)) &&
  21542. (s7_is_integer(c)))
  21543. {
  21544. s7_int ic; /* not int here! */
  21545. ic = s7_integer(c);
  21546. if ((ic < 0) || (ic > 255))
  21547. return(wrong_type_argument_with_type(sc, sc->string_set_symbol, 3, c, an_unsigned_byte_string));
  21548. str[ind] = (char)ic;
  21549. return(c);
  21550. }
  21551. method_or_bust(sc, c, sc->string_set_symbol, list_3(sc, x, index, c), T_CHARACTER, 3);
  21552. }
  21553. str[ind] = (char)s7_character(c);
  21554. return(c);
  21555. }
  21556. static int c_string_tester(s7_scheme *sc, s7_pointer expr)
  21557. {
  21558. s7_pointer a1;
  21559. a1 = cadr(expr);
  21560. if (is_symbol(a1))
  21561. {
  21562. s7_pointer table;
  21563. table = s7_slot(sc, a1);
  21564. if ((is_slot(table)) &&
  21565. ((is_immutable_symbol(a1)) || (!is_stepper(table))) &&
  21566. (is_string(slot_value(table))))
  21567. {
  21568. s7_pointer a2;
  21569. s7_xf_store(sc, slot_value(table));
  21570. a2 = caddr(expr);
  21571. if (is_symbol(a2))
  21572. {
  21573. s7_pointer slot;
  21574. slot = s7_slot(sc, a2);
  21575. if ((is_slot(slot)) &&
  21576. (is_integer(slot_value(slot))))
  21577. {
  21578. s7_xf_store(sc, slot);
  21579. return(TEST_SS);
  21580. }
  21581. }
  21582. else
  21583. {
  21584. if (s7_arg_to_if(sc, a1))
  21585. return(TEST_SI);
  21586. }
  21587. return(TEST_SQ);
  21588. }
  21589. }
  21590. return(TEST_NO_S);
  21591. }
  21592. static s7_pointer c_string_set_s(s7_scheme *sc, s7_pointer vec, s7_int index, s7_pointer val)
  21593. {
  21594. if (!s7_is_character(val))
  21595. method_or_bust(sc, val, sc->string_set_symbol, list_3(sc, vec, make_integer(sc, index), val), T_CHARACTER, 3);
  21596. if ((index < 0) ||
  21597. (index >= string_length(vec)))
  21598. return(out_of_range(sc, sc->string_set_symbol, small_int(2), make_integer(sc, index), (index < 0) ? its_negative_string : its_too_large_string));
  21599. string_value(vec)[index] = (char)character(val);
  21600. return(val);
  21601. }
  21602. static s7_pointer c_string_set(s7_scheme *sc, s7_pointer vec, s7_int index, s7_pointer val)
  21603. {
  21604. if (!s7_is_string(vec))
  21605. method_or_bust(sc, vec, sc->string_set_symbol, set_plist_3(sc, vec, make_integer(sc, index), val), T_STRING, 1);
  21606. return(c_string_set_s(sc, vec, index, val));
  21607. }
  21608. PIPF_TO_PF(string_set, c_string_set_s, c_string_set, c_string_tester)
  21609. /* -------------------------------- string-append -------------------------------- */
  21610. static s7_pointer g_string_append_1(s7_scheme *sc, s7_pointer args, bool use_temp)
  21611. {
  21612. int len = 0;
  21613. s7_pointer x, newstr;
  21614. char *pos;
  21615. if (is_null(args))
  21616. return(s7_make_string_with_length(sc, "", 0));
  21617. /* get length for new string */
  21618. for (x = args; is_not_null(x); x = cdr(x))
  21619. {
  21620. s7_pointer p;
  21621. p = car(x);
  21622. if (!is_string(p))
  21623. {
  21624. /* look for string-append and if found, cobble up a plausible intermediate call */
  21625. if (has_methods(p))
  21626. {
  21627. s7_pointer func;
  21628. func = find_method(sc, find_let(sc, p), sc->string_append_symbol);
  21629. if (func != sc->undefined)
  21630. {
  21631. s7_pointer y;
  21632. if (len == 0)
  21633. return(s7_apply_function(sc, func, args));
  21634. newstr = make_empty_string(sc, len, 0);
  21635. for (pos = string_value(newstr), y = args; y != x; pos += string_length(car(y)), y = cdr(y))
  21636. memcpy(pos, string_value(car(y)), string_length(car(y)));
  21637. return(s7_apply_function(sc, func, cons(sc, newstr, x)));
  21638. }
  21639. }
  21640. return(wrong_type_argument(sc, sc->string_append_symbol, position_of(x, args), p, T_STRING));
  21641. }
  21642. len += string_length(p);
  21643. }
  21644. if (use_temp)
  21645. {
  21646. newstr = sc->tmp_strs[0];
  21647. prepare_temporary_string(sc, len + 1, 0);
  21648. string_length(newstr) = len;
  21649. string_value(newstr)[len] = 0;
  21650. }
  21651. else
  21652. {
  21653. /* store the contents of the argument strings into the new string */
  21654. newstr = make_empty_string(sc, len, 0);
  21655. }
  21656. for (pos = string_value(newstr), x = args; is_not_null(x); pos += string_length(car(x)), x = cdr(x))
  21657. memcpy(pos, string_value(car(x)), string_length(car(x)));
  21658. if (is_byte_vector(car(args)))
  21659. set_byte_vector(newstr);
  21660. return(newstr);
  21661. }
  21662. static s7_pointer g_string_append(s7_scheme *sc, s7_pointer args)
  21663. {
  21664. #define H_string_append "(string-append str1 ...) appends all its string arguments into one string"
  21665. #define Q_string_append pcl_s
  21666. return(g_string_append_1(sc, args, false));
  21667. }
  21668. static s7_pointer string_append_to_temp;
  21669. static s7_pointer g_string_append_to_temp(s7_scheme *sc, s7_pointer args)
  21670. {
  21671. return(g_string_append_1(sc, args, true));
  21672. }
  21673. #if (!WITH_PURE_S7)
  21674. static s7_pointer g_string_copy(s7_scheme *sc, s7_pointer args)
  21675. {
  21676. #define H_string_copy "(string-copy str) returns a copy of its string argument"
  21677. #define Q_string_copy s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_string_symbol)
  21678. s7_pointer p;
  21679. p = car(args);
  21680. if (!is_string(p))
  21681. method_or_bust(sc, p, sc->string_copy_symbol, args, T_STRING, 1);
  21682. return(s7_make_string_with_length(sc, string_value(p), string_length(p)));
  21683. }
  21684. #endif
  21685. /* -------------------------------- substring -------------------------------- */
  21686. static s7_pointer start_and_end(s7_scheme *sc, s7_pointer caller, s7_pointer fallback,
  21687. s7_pointer start_and_end_args, s7_pointer args, int position, s7_int *start, s7_int *end)
  21688. {
  21689. /* we assume that *start=0 and *end=length, that end is "exclusive"
  21690. * return true if the start/end points are not changed.
  21691. */
  21692. s7_pointer pstart, pend, p;
  21693. s7_int index;
  21694. #if DEBUGGING
  21695. if (is_null(start_and_end_args))
  21696. {
  21697. fprintf(stderr, "start_and_end args is null\n");
  21698. return(sc->gc_nil);
  21699. }
  21700. #endif
  21701. pstart = car(start_and_end_args);
  21702. if (!s7_is_integer(pstart))
  21703. {
  21704. if (!s7_is_integer(p = check_values(sc, pstart, start_and_end_args)))
  21705. {
  21706. check_two_methods(sc, pstart, caller, fallback, args);
  21707. return(wrong_type_argument(sc, caller, position, pstart, T_INTEGER));
  21708. }
  21709. else pstart = p;
  21710. }
  21711. index = s7_integer(pstart);
  21712. if ((index < 0) ||
  21713. (index > *end)) /* *end == length here */
  21714. return(out_of_range(sc, caller, small_int(position), pstart, (index < 0) ? its_negative_string : its_too_large_string));
  21715. *start = index;
  21716. if (is_null(cdr(start_and_end_args)))
  21717. return(sc->gc_nil);
  21718. pend = cadr(start_and_end_args);
  21719. if (!s7_is_integer(pend))
  21720. {
  21721. if (!s7_is_integer(p = check_values(sc, pend, cdr(start_and_end_args))))
  21722. {
  21723. check_two_methods(sc, pend, caller, fallback,
  21724. (position == 2) ? list_3(sc, car(args), pstart, pend) : list_4(sc, car(args), cadr(args), pstart, pend));
  21725. return(wrong_type_argument(sc, caller, position + 1, pend, T_INTEGER));
  21726. }
  21727. else pend = p;
  21728. }
  21729. index = s7_integer(pend);
  21730. if ((index < *start) ||
  21731. (index > *end))
  21732. return(out_of_range(sc, caller, small_int(position + 1), pend, (index < *start) ? its_too_small_string : its_too_large_string));
  21733. *end = index;
  21734. return(sc->gc_nil);
  21735. }
  21736. static s7_pointer g_substring(s7_scheme *sc, s7_pointer args)
  21737. {
  21738. #define H_substring "(substring str start (end (length str))) returns the portion of the string str between start and \
  21739. end: (substring \"01234\" 1 2) -> \"1\""
  21740. #define Q_substring s7_make_circular_signature(sc, 2, 3, sc->is_string_symbol, sc->is_string_symbol, sc->is_integer_symbol)
  21741. s7_pointer x, str;
  21742. s7_int start = 0, end;
  21743. int len;
  21744. char *s;
  21745. str = car(args);
  21746. if (!is_string(str))
  21747. method_or_bust(sc, str, sc->substring_symbol, args, T_STRING, 1);
  21748. end = string_length(str);
  21749. if (!is_null(cdr(args)))
  21750. {
  21751. x = start_and_end(sc, sc->substring_symbol, NULL, cdr(args), args, 2, &start, &end);
  21752. if (x != sc->gc_nil) return(x);
  21753. }
  21754. s = string_value(str);
  21755. len = (int)(end - start);
  21756. x = s7_make_string_with_length(sc, (char *)(s + start), len);
  21757. string_value(x)[len] = 0;
  21758. return(x);
  21759. }
  21760. static s7_pointer substring_to_temp;
  21761. static s7_pointer g_substring_to_temp(s7_scheme *sc, s7_pointer args)
  21762. {
  21763. s7_pointer str;
  21764. s7_int start = 0, end;
  21765. str = car(args);
  21766. if (!is_string(str))
  21767. method_or_bust(sc, str, sc->substring_symbol, args, T_STRING, 1);
  21768. end = string_length(str);
  21769. if (!is_null(cdr(args)))
  21770. {
  21771. s7_pointer x;
  21772. x = start_and_end(sc, sc->substring_symbol, NULL, cdr(args), args, 2, &start, &end);
  21773. if (x != sc->gc_nil) return(x);
  21774. }
  21775. return(make_temporary_string(sc, (const char *)(string_value(str) + start), (int)(end - start)));
  21776. }
  21777. /* -------------------------------- object->string -------------------------------- */
  21778. static use_write_t write_choice(s7_scheme *sc, s7_pointer arg)
  21779. {
  21780. if (arg == sc->F) return(USE_DISPLAY);
  21781. if (arg == sc->T) return(USE_WRITE);
  21782. if (arg == sc->key_readable_symbol) return(USE_READABLE_WRITE);
  21783. return(USE_WRITE_WRONG);
  21784. }
  21785. #define DONT_USE_DISPLAY(Choice) ((Choice == USE_DISPLAY) ? USE_WRITE : Choice)
  21786. static char *s7_object_to_c_string_1(s7_scheme *sc, s7_pointer obj, use_write_t use_write, int *nlen);
  21787. static s7_pointer g_object_to_string(s7_scheme *sc, s7_pointer args)
  21788. {
  21789. #define H_object_to_string "(object->string obj (write #t)) returns a string representation of obj."
  21790. #define Q_object_to_string s7_make_signature(sc, 3, sc->is_string_symbol, sc->T, s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_keyword_symbol))
  21791. use_write_t choice;
  21792. char *str;
  21793. s7_pointer obj;
  21794. int len = 0;
  21795. if (is_not_null(cdr(args)))
  21796. {
  21797. choice = write_choice(sc, cadr(args));
  21798. if (choice == USE_WRITE_WRONG)
  21799. method_or_bust(sc, cadr(args), sc->object_to_string_symbol, args, T_BOOLEAN, 2);
  21800. }
  21801. else choice = USE_WRITE;
  21802. /* can't use s7_object_to_string here anymore because it assumes use_write arg is a boolean */
  21803. obj = car(args);
  21804. check_method(sc, obj, sc->object_to_string_symbol, args);
  21805. str = s7_object_to_c_string_1(sc, obj, choice, &len);
  21806. if (str)
  21807. return(make_string_uncopied_with_length(sc, str, len));
  21808. return(s7_make_string_with_length(sc, "", 0));
  21809. }
  21810. static s7_pointer c_object_to_string(s7_scheme *sc, s7_pointer x) {return(g_object_to_string(sc, set_plist_1(sc, x)));}
  21811. PF_TO_PF(object_to_string, c_object_to_string)
  21812. /* -------------------------------- string comparisons -------------------------------- */
  21813. static int scheme_strcmp(s7_pointer s1, s7_pointer s2)
  21814. {
  21815. /* tricky here because str[i] must be treated as unsigned
  21816. * (string<? (string (integer->char #xf0)) (string (integer->char #x70)))
  21817. * also null or lack thereof does not say anything about the string end
  21818. * so we have to go by its length.
  21819. */
  21820. int i, len, len1, len2;
  21821. char *str1, *str2;
  21822. len1 = string_length(s1);
  21823. len2 = string_length(s2);
  21824. if (len1 > len2)
  21825. len = len2;
  21826. else len = len1;
  21827. str1 = string_value(s1);
  21828. str2 = string_value(s2);
  21829. for (i = 0; i < len; i++)
  21830. if ((unsigned char)(str1[i]) < (unsigned char )(str2[i]))
  21831. return(-1);
  21832. else
  21833. {
  21834. if ((unsigned char)(str1[i]) > (unsigned char)(str2[i]))
  21835. return(1);
  21836. }
  21837. if (len1 < len2)
  21838. return(-1);
  21839. if (len1 > len2)
  21840. return(1);
  21841. return(0);
  21842. }
  21843. static bool is_string_via_method(s7_scheme *sc, s7_pointer p)
  21844. {
  21845. if (s7_is_string(p))
  21846. return(true);
  21847. if (has_methods(p))
  21848. {
  21849. s7_pointer f;
  21850. f = find_method(sc, find_let(sc, p), sc->is_string_symbol);
  21851. if (f != sc->undefined)
  21852. return(is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil))));
  21853. }
  21854. return(false);
  21855. }
  21856. static s7_pointer g_string_cmp(s7_scheme *sc, s7_pointer args, int val, s7_pointer sym)
  21857. {
  21858. s7_pointer x, y;
  21859. y = car(args);
  21860. if (!is_string(y))
  21861. method_or_bust(sc, y, sym, args, T_STRING, 1);
  21862. for (x = cdr(args); is_not_null(x); x = cdr(x))
  21863. {
  21864. if (!is_string(car(x)))
  21865. method_or_bust(sc, car(x), sym, cons(sc, y, x), T_STRING, position_of(x, args));
  21866. if (scheme_strcmp(y, car(x)) != val)
  21867. {
  21868. for (y = cdr(x); is_pair(y); y = cdr(y))
  21869. if (!is_string_via_method(sc, car(y)))
  21870. return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_STRING));
  21871. return(sc->F);
  21872. }
  21873. y = car(x);
  21874. }
  21875. return(sc->T);
  21876. }
  21877. static s7_pointer g_string_cmp_not(s7_scheme *sc, s7_pointer args, int val, s7_pointer sym)
  21878. {
  21879. s7_pointer x, y;
  21880. y = car(args);
  21881. if (!is_string(y))
  21882. method_or_bust(sc, y, sym, args, T_STRING, 1);
  21883. for (x = cdr(args); is_not_null(x); x = cdr(x))
  21884. {
  21885. if (!is_string(car(x)))
  21886. method_or_bust(sc, car(x), sym, cons(sc, y, x), T_STRING, position_of(x, args));
  21887. if (scheme_strcmp(y, car(x)) == val)
  21888. {
  21889. for (y = cdr(x); is_pair(y); y = cdr(y))
  21890. if (!is_string_via_method(sc, car(y)))
  21891. return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_STRING));
  21892. return(sc->F);
  21893. }
  21894. y = car(x);
  21895. }
  21896. return(sc->T);
  21897. }
  21898. static bool scheme_strings_are_equal(s7_pointer x, s7_pointer y)
  21899. {
  21900. return((string_length(x) == string_length(y)) &&
  21901. (strings_are_equal_with_length(string_value(x), string_value(y), string_length(x))));
  21902. }
  21903. static s7_pointer g_strings_are_equal(s7_scheme *sc, s7_pointer args)
  21904. {
  21905. #define H_strings_are_equal "(string=? str ...) returns #t if all the string arguments are equal"
  21906. #define Q_strings_are_equal pcl_bs
  21907. /* C-based check stops at null, but we can have embedded nulls.
  21908. * (let ((s1 "1234") (s2 "1245")) (string-set! s1 1 #\null) (string-set! s2 1 #\null) (string=? s1 s2))
  21909. */
  21910. s7_pointer x, y;
  21911. bool happy = true;
  21912. y = car(args);
  21913. if (!is_string(y))
  21914. method_or_bust(sc, y, sc->string_eq_symbol, args, T_STRING, 1);
  21915. for (x = cdr(args); is_pair(x); x = cdr(x))
  21916. {
  21917. s7_pointer p;
  21918. p = car(x);
  21919. if (y != p)
  21920. {
  21921. if (!is_string(p))
  21922. method_or_bust(sc, p, sc->string_eq_symbol, cons(sc, y, x), T_STRING, position_of(x, args));
  21923. if (happy)
  21924. happy = scheme_strings_are_equal(p, y);
  21925. }
  21926. }
  21927. if (!happy)
  21928. return(sc->F);
  21929. return(sc->T);
  21930. }
  21931. static s7_pointer c_string_eq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21932. {
  21933. if (!is_string(x))
  21934. method_or_bust(sc, x, sc->string_eq_symbol, list_2(sc, x, y), T_STRING, 1);
  21935. if (!is_string(y))
  21936. method_or_bust(sc, y, sc->string_eq_symbol, list_2(sc, x, y), T_STRING, 2);
  21937. return(make_boolean(sc, ((string_length(x) == string_length(y)) &&
  21938. (strings_are_equal_with_length(string_value(x), string_value(y), string_length(x))))));
  21939. }
  21940. PF2_TO_PF(string_eq, c_string_eq)
  21941. static s7_pointer g_strings_are_less(s7_scheme *sc, s7_pointer args)
  21942. {
  21943. #define H_strings_are_less "(string<? str ...) returns #t if all the string arguments are increasing"
  21944. #define Q_strings_are_less pcl_bs
  21945. return(g_string_cmp(sc, args, -1, sc->string_lt_symbol));
  21946. }
  21947. static s7_pointer c_string_lt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21948. {
  21949. if (!is_string(x))
  21950. method_or_bust(sc, x, sc->string_lt_symbol, list_2(sc, x, y), T_STRING, 1);
  21951. if (!is_string(y))
  21952. method_or_bust(sc, y, sc->string_lt_symbol, list_2(sc, x, y), T_STRING, 2);
  21953. return(make_boolean(sc, scheme_strcmp(x, y) == -1));
  21954. }
  21955. PF2_TO_PF(string_lt, c_string_lt)
  21956. static s7_pointer g_strings_are_greater(s7_scheme *sc, s7_pointer args)
  21957. {
  21958. #define H_strings_are_greater "(string>? str ...) returns #t if all the string arguments are decreasing"
  21959. #define Q_strings_are_greater pcl_bs
  21960. return(g_string_cmp(sc, args, 1, sc->string_gt_symbol));
  21961. }
  21962. static s7_pointer c_string_gt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21963. {
  21964. if (!is_string(x))
  21965. method_or_bust(sc, x, sc->string_gt_symbol, list_2(sc, x, y), T_STRING, 1);
  21966. if (!is_string(y))
  21967. method_or_bust(sc, y, sc->string_gt_symbol, list_2(sc, x, y), T_STRING, 2);
  21968. return(make_boolean(sc, scheme_strcmp(x, y) == 1));
  21969. }
  21970. PF2_TO_PF(string_gt, c_string_gt)
  21971. static s7_pointer g_strings_are_geq(s7_scheme *sc, s7_pointer args)
  21972. {
  21973. #define H_strings_are_geq "(string>=? str ...) returns #t if all the string arguments are equal or decreasing"
  21974. #define Q_strings_are_geq pcl_bs
  21975. return(g_string_cmp_not(sc, args, -1, sc->string_geq_symbol));
  21976. }
  21977. static s7_pointer c_string_geq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21978. {
  21979. if (!is_string(x))
  21980. method_or_bust(sc, x, sc->string_geq_symbol, list_2(sc, x, y), T_STRING, 1);
  21981. if (!is_string(y))
  21982. method_or_bust(sc, y, sc->string_geq_symbol, list_2(sc, x, y), T_STRING, 2);
  21983. return(make_boolean(sc, scheme_strcmp(x, y) != -1));
  21984. }
  21985. PF2_TO_PF(string_geq, c_string_geq)
  21986. static s7_pointer g_strings_are_leq(s7_scheme *sc, s7_pointer args)
  21987. {
  21988. #define H_strings_are_leq "(string<=? str ...) returns #t if all the string arguments are equal or increasing"
  21989. #define Q_strings_are_leq pcl_bs
  21990. return(g_string_cmp_not(sc, args, 1, sc->string_leq_symbol));
  21991. }
  21992. static s7_pointer c_string_leq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  21993. {
  21994. if (!is_string(x))
  21995. method_or_bust(sc, x, sc->string_leq_symbol, list_2(sc, x, y), T_STRING, 1);
  21996. if (!is_string(y))
  21997. method_or_bust(sc, y, sc->string_leq_symbol, list_2(sc, x, y), T_STRING, 2);
  21998. return(make_boolean(sc, scheme_strcmp(x, y) != 1));
  21999. }
  22000. PF2_TO_PF(string_leq, c_string_leq)
  22001. static s7_pointer string_equal_s_ic, string_equal_2;
  22002. static s7_pointer g_string_equal_s_ic(s7_scheme *sc, s7_pointer args)
  22003. {
  22004. if (!is_string(car(args)))
  22005. method_or_bust(sc, car(args), sc->string_eq_symbol, args, T_STRING, 1);
  22006. return(make_boolean(sc, scheme_strings_are_equal(car(args), cadr(args))));
  22007. }
  22008. static s7_pointer g_string_equal_2(s7_scheme *sc, s7_pointer args)
  22009. {
  22010. if (!is_string(car(args)))
  22011. method_or_bust(sc, car(args), sc->string_eq_symbol, args, T_STRING, 1);
  22012. if (!is_string(cadr(args)))
  22013. method_or_bust(sc, cadr(args), sc->string_eq_symbol, args, T_STRING, 2);
  22014. return(make_boolean(sc, scheme_strings_are_equal(car(args), cadr(args))));
  22015. }
  22016. static s7_pointer string_less_2;
  22017. static s7_pointer g_string_less_2(s7_scheme *sc, s7_pointer args)
  22018. {
  22019. if (!is_string(car(args)))
  22020. method_or_bust(sc, car(args), sc->string_lt_symbol, args, T_STRING, 1);
  22021. if (!is_string(cadr(args)))
  22022. method_or_bust(sc, cadr(args), sc->string_lt_symbol, args, T_STRING, 2);
  22023. return(make_boolean(sc, scheme_strcmp(car(args), cadr(args)) == -1));
  22024. }
  22025. static s7_pointer string_greater_2;
  22026. static s7_pointer g_string_greater_2(s7_scheme *sc, s7_pointer args)
  22027. {
  22028. if (!is_string(car(args)))
  22029. method_or_bust(sc, car(args), sc->string_gt_symbol, args, T_STRING, 1);
  22030. if (!is_string(cadr(args)))
  22031. method_or_bust(sc, cadr(args), sc->string_gt_symbol, args, T_STRING, 2);
  22032. return(make_boolean(sc, scheme_strcmp(car(args), cadr(args)) == 1));
  22033. }
  22034. #if (!WITH_PURE_S7)
  22035. static int scheme_strcasecmp(s7_pointer s1, s7_pointer s2)
  22036. {
  22037. /* same as scheme_strcmp -- watch out for unwanted sign! and lack of trailing null (length sets string end).
  22038. */
  22039. int i, len, len1, len2;
  22040. unsigned char *str1, *str2;
  22041. len1 = string_length(s1);
  22042. len2 = string_length(s2);
  22043. if (len1 > len2)
  22044. len = len2;
  22045. else len = len1;
  22046. str1 = (unsigned char *)string_value(s1);
  22047. str2 = (unsigned char *)string_value(s2);
  22048. for (i = 0; i < len; i++)
  22049. if (uppers[(int)str1[i]] < uppers[(int)str2[i]])
  22050. return(-1);
  22051. else
  22052. {
  22053. if (uppers[(int)str1[i]] > uppers[(int)str2[i]])
  22054. return(1);
  22055. }
  22056. if (len1 < len2)
  22057. return(-1);
  22058. if (len1 > len2)
  22059. return(1);
  22060. return(0);
  22061. }
  22062. static bool scheme_strequal_ci(s7_pointer s1, s7_pointer s2)
  22063. {
  22064. /* same as scheme_strcmp -- watch out for unwanted sign! */
  22065. int i, len, len2;
  22066. unsigned char *str1, *str2;
  22067. len = string_length(s1);
  22068. len2 = string_length(s2);
  22069. if (len != len2)
  22070. return(false);
  22071. str1 = (unsigned char *)string_value(s1);
  22072. str2 = (unsigned char *)string_value(s2);
  22073. for (i = 0; i < len; i++)
  22074. if (uppers[(int)str1[i]] != uppers[(int)str2[i]])
  22075. return(false);
  22076. return(true);
  22077. }
  22078. static s7_pointer g_string_ci_cmp(s7_scheme *sc, s7_pointer args, int val, s7_pointer sym)
  22079. {
  22080. s7_pointer x, y;
  22081. y = car(args);
  22082. if (!is_string(y))
  22083. method_or_bust(sc, y, sym, args, T_STRING, 1);
  22084. for (x = cdr(args); is_not_null(x); x = cdr(x))
  22085. {
  22086. if (!is_string(car(x)))
  22087. method_or_bust(sc, car(x), sym, cons(sc, y, x), T_STRING, position_of(x, args));
  22088. if (val == 0)
  22089. {
  22090. if (!scheme_strequal_ci(y, car(x)))
  22091. {
  22092. for (y = cdr(x); is_pair(y); y = cdr(y))
  22093. if (!is_string_via_method(sc, car(y)))
  22094. return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_STRING));
  22095. return(sc->F);
  22096. }
  22097. }
  22098. else
  22099. {
  22100. if (scheme_strcasecmp(y, car(x)) != val)
  22101. {
  22102. for (y = cdr(x); is_pair(y); y = cdr(y))
  22103. if (!is_string_via_method(sc, car(y)))
  22104. return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_STRING));
  22105. return(sc->F);
  22106. }
  22107. }
  22108. y = car(x);
  22109. }
  22110. return(sc->T);
  22111. }
  22112. static s7_pointer g_string_ci_cmp_not(s7_scheme *sc, s7_pointer args, int val, s7_pointer sym)
  22113. {
  22114. s7_pointer x, y;
  22115. y = car(args);
  22116. if (!is_string(y))
  22117. method_or_bust(sc, y, sym, args, T_STRING, 1);
  22118. for (x = cdr(args); is_not_null(x); x = cdr(x))
  22119. {
  22120. if (!is_string(car(x)))
  22121. method_or_bust(sc, car(x), sym, cons(sc, y, x), T_STRING, position_of(x, args));
  22122. if (scheme_strcasecmp(y, car(x)) == val)
  22123. {
  22124. for (y = cdr(x); is_pair(y); y = cdr(y))
  22125. if (!is_string_via_method(sc, car(y)))
  22126. return(wrong_type_argument(sc, sym, position_of(y, args), car(y), T_STRING));
  22127. return(sc->F);
  22128. }
  22129. y = car(x);
  22130. }
  22131. return(sc->T);
  22132. }
  22133. static s7_pointer g_strings_are_ci_equal(s7_scheme *sc, s7_pointer args)
  22134. {
  22135. #define H_strings_are_ci_equal "(string-ci=? str ...) returns #t if all the string arguments are equal, ignoring case"
  22136. #define Q_strings_are_ci_equal pcl_bs
  22137. return(g_string_ci_cmp(sc, args, 0, sc->string_ci_eq_symbol));
  22138. }
  22139. static s7_pointer c_string_ci_eq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  22140. {
  22141. if (!is_string(x))
  22142. method_or_bust(sc, x, sc->string_ci_eq_symbol, list_2(sc, x, y), T_STRING, 1);
  22143. if (!is_string(y))
  22144. method_or_bust(sc, y, sc->string_ci_eq_symbol, list_2(sc, x, y), T_STRING, 2);
  22145. return(make_boolean(sc, scheme_strcasecmp(x, y) == 0));
  22146. }
  22147. PF2_TO_PF(string_ci_eq, c_string_ci_eq)
  22148. static s7_pointer g_strings_are_ci_less(s7_scheme *sc, s7_pointer args)
  22149. {
  22150. #define H_strings_are_ci_less "(string-ci<? str ...) returns #t if all the string arguments are increasing, ignoring case"
  22151. #define Q_strings_are_ci_less pcl_bs
  22152. return(g_string_ci_cmp(sc, args, -1, sc->string_ci_lt_symbol));
  22153. }
  22154. static s7_pointer c_string_ci_lt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  22155. {
  22156. if (!is_string(x))
  22157. method_or_bust(sc, x, sc->string_ci_lt_symbol, list_2(sc, x, y), T_STRING, 1);
  22158. if (!is_string(y))
  22159. method_or_bust(sc, y, sc->string_ci_lt_symbol, list_2(sc, x, y), T_STRING, 2);
  22160. return(make_boolean(sc, scheme_strcasecmp(x, y) == -1));
  22161. }
  22162. PF2_TO_PF(string_ci_lt, c_string_ci_lt)
  22163. static s7_pointer g_strings_are_ci_greater(s7_scheme *sc, s7_pointer args)
  22164. {
  22165. #define H_strings_are_ci_greater "(string-ci>? str ...) returns #t if all the string arguments are decreasing, ignoring case"
  22166. #define Q_strings_are_ci_greater pcl_bs
  22167. return(g_string_ci_cmp(sc, args, 1, sc->string_ci_gt_symbol));
  22168. }
  22169. static s7_pointer c_string_ci_gt(s7_scheme *sc, s7_pointer x, s7_pointer y)
  22170. {
  22171. if (!is_string(x))
  22172. method_or_bust(sc, x, sc->string_ci_gt_symbol, list_2(sc, x, y), T_STRING, 1);
  22173. if (!is_string(y))
  22174. method_or_bust(sc, y, sc->string_ci_gt_symbol, list_2(sc, x, y), T_STRING, 2);
  22175. return(make_boolean(sc, scheme_strcasecmp(x, y) == 1));
  22176. }
  22177. PF2_TO_PF(string_ci_gt, c_string_ci_gt)
  22178. static s7_pointer g_strings_are_ci_geq(s7_scheme *sc, s7_pointer args)
  22179. {
  22180. #define H_strings_are_ci_geq "(string-ci>=? str ...) returns #t if all the string arguments are equal or decreasing, ignoring case"
  22181. #define Q_strings_are_ci_geq pcl_bs
  22182. return(g_string_ci_cmp_not(sc, args, -1, sc->string_ci_geq_symbol));
  22183. }
  22184. static s7_pointer c_string_ci_geq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  22185. {
  22186. if (!is_string(x))
  22187. method_or_bust(sc, x, sc->string_ci_geq_symbol, list_2(sc, x, y), T_STRING, 1);
  22188. if (!is_string(y))
  22189. method_or_bust(sc, y, sc->string_ci_geq_symbol, list_2(sc, x, y), T_STRING, 2);
  22190. return(make_boolean(sc, scheme_strcasecmp(x, y) != -1));
  22191. }
  22192. PF2_TO_PF(string_ci_geq, c_string_ci_geq)
  22193. static s7_pointer g_strings_are_ci_leq(s7_scheme *sc, s7_pointer args)
  22194. {
  22195. #define H_strings_are_ci_leq "(string-ci<=? str ...) returns #t if all the string arguments are equal or increasing, ignoring case"
  22196. #define Q_strings_are_ci_leq pcl_bs
  22197. return(g_string_ci_cmp_not(sc, args, 1, sc->string_ci_leq_symbol));
  22198. }
  22199. static s7_pointer c_string_ci_leq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  22200. {
  22201. if (!is_string(x))
  22202. method_or_bust(sc, x, sc->string_ci_leq_symbol, list_2(sc, x, y), T_STRING, 1);
  22203. if (!is_string(y))
  22204. method_or_bust(sc, y, sc->string_ci_leq_symbol, list_2(sc, x, y), T_STRING, 2);
  22205. return(make_boolean(sc, scheme_strcasecmp(x, y) != 1));
  22206. }
  22207. PF2_TO_PF(string_ci_leq, c_string_ci_leq)
  22208. #endif /* pure s7 */
  22209. static s7_pointer g_string_fill(s7_scheme *sc, s7_pointer args)
  22210. {
  22211. #define H_string_fill "(string-fill! str chr start end) fills the string str with the character chr"
  22212. #define Q_string_fill s7_make_circular_signature(sc, 3, 4, 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)
  22213. s7_pointer x, chr;
  22214. s7_int start = 0, end, byte = 0;
  22215. x = car(args);
  22216. if (!is_string(x))
  22217. method_or_bust(sc, x, sc->string_fill_symbol, args, T_STRING, 1); /* not two methods here */
  22218. chr = cadr(args);
  22219. if (!is_byte_vector(x))
  22220. {
  22221. if (!s7_is_character(chr))
  22222. {
  22223. check_two_methods(sc, chr, sc->string_fill_symbol, sc->fill_symbol, args);
  22224. return(wrong_type_argument(sc, sc->string_fill_symbol, 2, chr, T_CHARACTER));
  22225. }
  22226. }
  22227. else
  22228. {
  22229. if (!is_integer(chr))
  22230. {
  22231. check_two_methods(sc, chr, sc->string_fill_symbol, sc->fill_symbol, args);
  22232. return(wrong_type_argument(sc, sc->fill_symbol, 2, chr, T_INTEGER));
  22233. }
  22234. byte = integer(chr);
  22235. if ((byte < 0) || (byte > 255))
  22236. return(simple_wrong_type_argument_with_type(sc, sc->string_fill_symbol, chr, an_unsigned_byte_string));
  22237. }
  22238. end = string_length(x);
  22239. if (!is_null(cddr(args)))
  22240. {
  22241. s7_pointer p;
  22242. p = start_and_end(sc, sc->string_fill_symbol, sc->fill_symbol, cddr(args), args, 3, &start, &end);
  22243. if (p != sc->gc_nil) return(p);
  22244. if (start == end) return(chr);
  22245. }
  22246. if (end == 0) return(chr);
  22247. if (!is_byte_vector(x))
  22248. memset((void *)(string_value(x) + start), (int)character(chr), end - start);
  22249. else memset((void *)(string_value(x) + start), (int)byte, end - start);
  22250. return(chr);
  22251. }
  22252. #if (!WITH_PURE_S7)
  22253. static s7_pointer c_string_fill(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_string_fill(sc, set_plist_2(sc, x, y)));}
  22254. PF2_TO_PF(string_fill, c_string_fill)
  22255. #endif
  22256. static s7_pointer g_string_1(s7_scheme *sc, s7_pointer args, s7_pointer sym)
  22257. {
  22258. int i, len;
  22259. s7_pointer x, newstr;
  22260. char *str;
  22261. /* get length for new string and check arg types */
  22262. for (len = 0, x = args; is_not_null(x); len++, x = cdr(x))
  22263. {
  22264. s7_pointer p;
  22265. p = car(x);
  22266. if (!s7_is_character(p))
  22267. {
  22268. if (has_methods(p))
  22269. {
  22270. s7_pointer func;
  22271. func = find_method(sc, find_let(sc, p), sym);
  22272. if (func != sc->undefined)
  22273. {
  22274. s7_pointer y;
  22275. if (len == 0)
  22276. return(s7_apply_function(sc, func, args));
  22277. newstr = make_empty_string(sc, len, 0);
  22278. str = string_value(newstr);
  22279. for (i = 0, y = args; y != x; i++, y = cdr(y))
  22280. str[i] = character(car(y));
  22281. return(g_string_append(sc, set_plist_2(sc, newstr, s7_apply_function(sc, func, x))));
  22282. }
  22283. }
  22284. return(wrong_type_argument(sc, sym, len + 1, car(x), T_CHARACTER));
  22285. }
  22286. }
  22287. newstr = make_empty_string(sc, len, 0);
  22288. str = string_value(newstr);
  22289. for (i = 0, x = args; is_not_null(x); i++, x = cdr(x))
  22290. str[i] = character(car(x));
  22291. return(newstr);
  22292. }
  22293. static s7_pointer g_string(s7_scheme *sc, s7_pointer args)
  22294. {
  22295. #define H_string "(string chr...) appends all its character arguments into one string"
  22296. #define Q_string s7_make_circular_signature(sc, 1, 2, sc->is_string_symbol, sc->is_char_symbol)
  22297. if (is_null(args)) /* (string) but not (string ()) */
  22298. return(s7_make_string_with_length(sc, "", 0));
  22299. return(g_string_1(sc, args, sc->string_symbol));
  22300. }
  22301. #if (!WITH_PURE_S7)
  22302. static s7_pointer g_list_to_string(s7_scheme *sc, s7_pointer args)
  22303. {
  22304. #define H_list_to_string "(list->string lst) appends all the list's characters into one string; (apply string lst)"
  22305. #define Q_list_to_string s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_proper_list_symbol)
  22306. if (is_null(car(args)))
  22307. return(s7_make_string_with_length(sc, "", 0));
  22308. if (!is_proper_list(sc, car(args)))
  22309. method_or_bust_with_type(sc, car(args), sc->list_to_string_symbol, args, make_string_wrapper(sc, "a (proper, non-circular) list of characters"), 0);
  22310. return(g_string_1(sc, car(args), sc->list_to_string_symbol));
  22311. }
  22312. #endif
  22313. static s7_pointer s7_string_to_list(s7_scheme *sc, const char *str, int len)
  22314. {
  22315. int i;
  22316. s7_pointer result;
  22317. if (len == 0)
  22318. return(sc->nil);
  22319. if (len >= (sc->free_heap_top - sc->free_heap))
  22320. {
  22321. gc(sc);
  22322. while (len >= (sc->free_heap_top - sc->free_heap))
  22323. resize_heap(sc);
  22324. }
  22325. sc->v = sc->nil;
  22326. for (i = len - 1; i >= 0; i--)
  22327. sc->v = cons_unchecked(sc, s7_make_character(sc, ((unsigned char)str[i])), sc->v);
  22328. result = sc->v;
  22329. sc->v = sc->nil;
  22330. return(result);
  22331. }
  22332. #if (!WITH_PURE_S7)
  22333. static s7_pointer g_string_to_list(s7_scheme *sc, s7_pointer args)
  22334. {
  22335. #define H_string_to_list "(string->list str start end) returns the elements of the string str in a list; (map values str)"
  22336. #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)
  22337. s7_int i, start = 0, end;
  22338. s7_pointer p, str;
  22339. str = car(args);
  22340. if (!is_string(str))
  22341. method_or_bust(sc, str, sc->string_to_list_symbol, args, T_STRING, 0);
  22342. end = string_length(str);
  22343. if (!is_null(cdr(args)))
  22344. {
  22345. p = start_and_end(sc, sc->string_to_list_symbol, NULL, cdr(args), args, 2, &start, &end);
  22346. if (p != sc->gc_nil) return(p);
  22347. if (start == end) return(sc->nil);
  22348. }
  22349. else
  22350. {
  22351. if (end == 0) return(sc->nil);
  22352. }
  22353. if ((start == 0) && (end == string_length(str)))
  22354. return(s7_string_to_list(sc, string_value(str), string_length(str)));
  22355. sc->w = sc->nil;
  22356. for (i = end - 1; i >= start; i--)
  22357. sc->w = cons(sc, s7_make_character(sc, ((unsigned char)string_value(str)[i])), sc->w);
  22358. p = sc->w;
  22359. sc->w = sc->nil;
  22360. return(p);
  22361. }
  22362. static s7_pointer c_string_to_list(s7_scheme *sc, s7_pointer x) {return(g_string_to_list(sc, set_plist_1(sc, x)));}
  22363. PF_TO_PF(string_to_list, c_string_to_list)
  22364. #endif
  22365. /* -------------------------------- byte_vectors --------------------------------
  22366. *
  22367. * these are just strings with the T_BYTE_VECTOR bit set.
  22368. */
  22369. static bool s7_is_byte_vector(s7_pointer b) {return((is_string(b)) && (is_byte_vector(b)));}
  22370. static s7_pointer g_is_byte_vector(s7_scheme *sc, s7_pointer args)
  22371. {
  22372. #define H_is_byte_vector "(byte-vector? obj) returns #t if obj is a byte-vector"
  22373. #define Q_is_byte_vector pl_bt
  22374. check_boolean_method(sc, s7_is_byte_vector, sc->is_byte_vector_symbol, args);
  22375. }
  22376. static s7_pointer g_string_to_byte_vector(s7_scheme *sc, s7_pointer args)
  22377. {
  22378. #define H_string_to_byte_vector "(string->byte-vector obj) turns a string into a byte-vector."
  22379. #define Q_string_to_byte_vector s7_make_signature(sc, 2, sc->is_byte_vector_symbol, sc->is_string_symbol)
  22380. s7_pointer str;
  22381. str = car(args);
  22382. if (is_integer(str))
  22383. str = s7_make_string_with_length(sc, (const char *)(&(integer(str))), sizeof(s7_int));
  22384. else
  22385. {
  22386. if (!is_string(str))
  22387. method_or_bust(sc, str, sc->string_to_byte_vector_symbol, set_plist_1(sc, str), T_STRING, 1);
  22388. }
  22389. set_byte_vector(str);
  22390. return(str);
  22391. }
  22392. static s7_pointer c_string_to_byte_vector(s7_scheme *sc, s7_pointer str) {return(g_string_to_byte_vector(sc, set_plist_1(sc, str)));}
  22393. PF_TO_PF(string_to_byte_vector, c_string_to_byte_vector)
  22394. static s7_pointer g_make_byte_vector(s7_scheme *sc, s7_pointer args)
  22395. {
  22396. #define H_make_byte_vector "(make-byte-vector len (byte 0)) makes a byte-vector of length len filled with byte."
  22397. #define Q_make_byte_vector s7_make_circular_signature(sc, 1, 2, sc->is_byte_vector_symbol, sc->is_integer_symbol)
  22398. s7_pointer str;
  22399. if (is_null(cdr(args)))
  22400. {
  22401. str = g_make_string(sc, args);
  22402. if (is_string(str))
  22403. memclr((void *)(string_value(str)), string_length(str));
  22404. }
  22405. else
  22406. {
  22407. s7_pointer len, byte;
  22408. s7_int b;
  22409. len = car(args);
  22410. if (!is_integer(len))
  22411. method_or_bust(sc, len, sc->make_byte_vector_symbol, args, T_INTEGER, 1);
  22412. byte = cadr(args);
  22413. if (!s7_is_integer(byte))
  22414. method_or_bust(sc, byte, sc->make_byte_vector_symbol, args, T_INTEGER, 2);
  22415. b = s7_integer(byte);
  22416. if ((b < 0) || (b > 255))
  22417. return(simple_wrong_type_argument_with_type(sc, sc->make_byte_vector_symbol, byte, an_unsigned_byte_string));
  22418. str = g_make_string(sc, set_plist_2(sc, len, chars[b]));
  22419. }
  22420. set_byte_vector(str);
  22421. return(str);
  22422. }
  22423. static s7_pointer g_byte_vector(s7_scheme *sc, s7_pointer args)
  22424. {
  22425. #define H_byte_vector "(byte-vector ...) returns a byte-vector whose elements are the arguments"
  22426. #define Q_byte_vector s7_make_circular_signature(sc, 1, 2, sc->is_byte_vector_symbol, sc->is_integer_symbol)
  22427. s7_int i, len;
  22428. s7_pointer vec, x;
  22429. char *str;
  22430. len = s7_list_length(sc, args);
  22431. vec = make_empty_string(sc, len, 0);
  22432. str = string_value(vec);
  22433. for (i = 0, x = args; is_pair(x); i++, x = cdr(x))
  22434. {
  22435. s7_pointer byte;
  22436. s7_int b;
  22437. byte = car(x);
  22438. if (!s7_is_integer(byte))
  22439. {
  22440. if (has_methods(byte))
  22441. {
  22442. s7_pointer func;
  22443. func = find_method(sc, find_let(sc, byte), sc->byte_vector_symbol);
  22444. if (func != sc->undefined)
  22445. {
  22446. if (i == 0)
  22447. return(s7_apply_function(sc, func, args));
  22448. string_length(vec) = i;
  22449. vec = g_string_append(sc, set_plist_2(sc, vec, s7_apply_function(sc, func, x)));
  22450. set_byte_vector(vec);
  22451. return(vec);
  22452. }
  22453. }
  22454. return(wrong_type_argument(sc, sc->byte_vector_symbol, i + 1, byte, T_INTEGER));
  22455. }
  22456. b = s7_integer(byte);
  22457. if ((b < 0) || (b > 255))
  22458. return(simple_wrong_type_argument_with_type(sc, sc->byte_vector_symbol, byte, an_unsigned_byte_string));
  22459. str[i] = (unsigned char)b;
  22460. }
  22461. set_byte_vector(vec);
  22462. return(vec);
  22463. }
  22464. static s7_pointer byte_vector_to_list(s7_scheme *sc, const char *str, int len)
  22465. {
  22466. int i;
  22467. s7_pointer p;
  22468. if (len == 0) return(sc->nil);
  22469. sc->w = sc->nil;
  22470. for (i = len - 1; i >= 0; i--)
  22471. sc->w = cons(sc, small_int((unsigned int)((unsigned char)(str[i]))), sc->w); /* extra cast is not redundant! */
  22472. p = sc->w;
  22473. sc->w = sc->nil;
  22474. return(p);
  22475. }
  22476. /* -------------------------------- ports --------------------------------
  22477. *
  22478. * originally nil served as stdin and friends, but that made it impossible to catch an error
  22479. * like (read-line (current-output-port)) when the latter was stdout. So we now have
  22480. * the built-in constant ports *stdin*, *stdout*, and *stderr*. Some way is needed to
  22481. * refer to these directly so that (read-line *stdin*) for example can insist on reading
  22482. * from the terminal, or whatever stdin is.
  22483. */
  22484. static s7_pointer g_is_port_closed(s7_scheme *sc, s7_pointer args)
  22485. {
  22486. #define H_is_port_closed "(port-closed? p) returns #t if the port p is closed."
  22487. #define Q_is_port_closed pl_bt
  22488. s7_pointer x;
  22489. x = car(args);
  22490. if ((is_input_port(x)) || (is_output_port(x)))
  22491. return(make_boolean(sc, port_is_closed(x)));
  22492. method_or_bust_with_type(sc, x, sc->is_port_closed_symbol, args, make_string_wrapper(sc, "a port"), 0);
  22493. }
  22494. static s7_pointer c_port_line_number(s7_scheme *sc, s7_pointer x)
  22495. {
  22496. if ((!(is_input_port(x))) ||
  22497. (port_is_closed(x)))
  22498. method_or_bust_with_type(sc, x, sc->port_line_number_symbol, list_1(sc, x), an_input_port_string, 0);
  22499. return(make_integer(sc, port_line_number(x)));
  22500. }
  22501. static s7_pointer g_port_line_number(s7_scheme *sc, s7_pointer args)
  22502. {
  22503. #define H_port_line_number "(port-line-number input-file-port) returns the current read line number of port"
  22504. #define Q_port_line_number s7_make_signature(sc, 2, sc->is_integer_symbol, s7_make_signature(sc, 2, sc->is_input_port_symbol, sc->is_null_symbol))
  22505. if ((is_null(args)) || (is_null(car(args))))
  22506. return(c_port_line_number(sc, sc->input_port));
  22507. return(c_port_line_number(sc, car(args)));
  22508. }
  22509. PF_TO_PF(port_line_number, c_port_line_number)
  22510. int s7_port_line_number(s7_pointer p)
  22511. {
  22512. if (is_input_port(p))
  22513. return(port_line_number(p));
  22514. return(0);
  22515. }
  22516. static s7_pointer g_set_port_line_number(s7_scheme *sc, s7_pointer args)
  22517. {
  22518. s7_pointer p, line;
  22519. if ((is_null(car(args))) ||
  22520. ((is_null(cdr(args))) && (is_integer(car(args)))))
  22521. p = sc->input_port;
  22522. else
  22523. {
  22524. p = car(args);
  22525. if (!(is_input_port(p)))
  22526. return(s7_wrong_type_arg_error(sc, "set! port-line-number", 1, p, "an input port"));
  22527. }
  22528. line = (is_null(cdr(args)) ? car(args) : cadr(args));
  22529. if (!is_integer(line))
  22530. return(s7_wrong_type_arg_error(sc, "set! port-line-number", 2, line, "an integer"));
  22531. port_line_number(p) = integer(line);
  22532. return(line);
  22533. }
  22534. const char *s7_port_filename(s7_pointer x)
  22535. {
  22536. if (((is_input_port(x)) ||
  22537. (is_output_port(x))) &&
  22538. (!port_is_closed(x)))
  22539. return(port_filename(x));
  22540. return(NULL);
  22541. }
  22542. static s7_pointer c_port_filename(s7_scheme *sc, s7_pointer x)
  22543. {
  22544. if (((is_input_port(x)) ||
  22545. (is_output_port(x))) &&
  22546. (!port_is_closed(x)))
  22547. {
  22548. if (port_filename(x))
  22549. return(make_string_wrapper_with_length(sc, port_filename(x), port_filename_length(x)));
  22550. return(s7_make_string_with_length(sc, "", 0));
  22551. /* otherwise (eval-string (port-filename)) and (string->symbol (port-filename)) segfault */
  22552. }
  22553. method_or_bust_with_type(sc, x, sc->port_filename_symbol, list_1(sc, x), an_open_port_string, 0);
  22554. }
  22555. static s7_pointer g_port_filename(s7_scheme *sc, s7_pointer args)
  22556. {
  22557. #define H_port_filename "(port-filename file-port) returns the filename associated with port"
  22558. #define Q_port_filename s7_make_signature(sc, 2, sc->is_string_symbol, sc->T)
  22559. if (is_null(args))
  22560. return(c_port_filename(sc, sc->input_port));
  22561. return(c_port_filename(sc, car(args)));
  22562. }
  22563. PF_TO_PF(port_filename, c_port_filename)
  22564. bool s7_is_input_port(s7_scheme *sc, s7_pointer p)
  22565. {
  22566. return(is_input_port(p));
  22567. }
  22568. static s7_pointer g_is_input_port(s7_scheme *sc, s7_pointer args)
  22569. {
  22570. #define H_is_input_port "(input-port? p) returns #t if p is an input port"
  22571. #define Q_is_input_port pl_bt
  22572. check_boolean_method(sc, is_input_port, sc->is_input_port_symbol, args);
  22573. }
  22574. bool s7_is_output_port(s7_scheme *sc, s7_pointer p)
  22575. {
  22576. return(is_output_port(p));
  22577. }
  22578. static s7_pointer g_is_output_port(s7_scheme *sc, s7_pointer args)
  22579. {
  22580. #define H_is_output_port "(output-port? p) returns #t if p is an output port"
  22581. #define Q_is_output_port pl_bt
  22582. check_boolean_method(sc, is_output_port, sc->is_output_port_symbol, args);
  22583. }
  22584. s7_pointer s7_current_input_port(s7_scheme *sc)
  22585. {
  22586. return(sc->input_port);
  22587. }
  22588. static s7_pointer g_current_input_port(s7_scheme *sc, s7_pointer args)
  22589. {
  22590. #define H_current_input_port "(current-input-port) returns the current input port"
  22591. #define Q_current_input_port s7_make_signature(sc, 1, sc->is_input_port_symbol)
  22592. return(sc->input_port);
  22593. }
  22594. #if (!WITH_PURE_S7)
  22595. static s7_pointer g_set_current_input_port(s7_scheme *sc, s7_pointer args)
  22596. {
  22597. #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"
  22598. #define Q_set_current_input_port s7_make_signature(sc, 2, sc->is_input_port_symbol, sc->is_input_port_symbol)
  22599. s7_pointer old_port, port;
  22600. old_port = sc->input_port;
  22601. port = car(args);
  22602. if ((is_input_port(port)) &&
  22603. (!port_is_closed(port)))
  22604. sc->input_port = port;
  22605. else
  22606. {
  22607. check_method(sc, port, s7_make_symbol(sc, "set-current-input-port"), args);
  22608. return(s7_wrong_type_arg_error(sc, "set-current-input-port", 0, port, "an open input port"));
  22609. }
  22610. return(old_port);
  22611. }
  22612. #endif
  22613. s7_pointer s7_set_current_input_port(s7_scheme *sc, s7_pointer port)
  22614. {
  22615. s7_pointer old_port;
  22616. old_port = sc->input_port;
  22617. sc->input_port = port;
  22618. return(old_port);
  22619. }
  22620. s7_pointer s7_current_output_port(s7_scheme *sc)
  22621. {
  22622. return(sc->output_port);
  22623. }
  22624. s7_pointer s7_set_current_output_port(s7_scheme *sc, s7_pointer port)
  22625. {
  22626. s7_pointer old_port;
  22627. old_port = sc->output_port;
  22628. sc->output_port = port;
  22629. return(old_port);
  22630. }
  22631. static s7_pointer g_current_output_port(s7_scheme *sc, s7_pointer args)
  22632. {
  22633. #define H_current_output_port "(current-output-port) returns the current output port"
  22634. #define Q_current_output_port s7_make_signature(sc, 1, sc->is_output_port_symbol)
  22635. return(sc->output_port);
  22636. }
  22637. #if (!WITH_PURE_S7)
  22638. static s7_pointer g_set_current_output_port(s7_scheme *sc, s7_pointer args)
  22639. {
  22640. #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"
  22641. #define Q_set_current_output_port s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->is_output_port_symbol)
  22642. s7_pointer old_port, port;
  22643. old_port = sc->output_port;
  22644. port = car(args);
  22645. if (((is_output_port(port)) &&
  22646. (!port_is_closed(port))) ||
  22647. (port == sc->F))
  22648. sc->output_port = port;
  22649. else
  22650. {
  22651. check_method(sc, port, s7_make_symbol(sc, "set-current-output-port"), args);
  22652. return(s7_wrong_type_arg_error(sc, "set-current-output-port", 0, port, "an open output port"));
  22653. }
  22654. return(old_port);
  22655. }
  22656. #endif
  22657. s7_pointer s7_current_error_port(s7_scheme *sc)
  22658. {
  22659. return(sc->error_port);
  22660. }
  22661. s7_pointer s7_set_current_error_port(s7_scheme *sc, s7_pointer port)
  22662. {
  22663. s7_pointer old_port;
  22664. old_port = sc->error_port;
  22665. sc->error_port = port;
  22666. return(old_port);
  22667. }
  22668. static s7_pointer g_current_error_port(s7_scheme *sc, s7_pointer args)
  22669. {
  22670. #define H_current_error_port "(current-error-port) returns the current error port"
  22671. #define Q_current_error_port s7_make_signature(sc, 1, sc->is_output_port_symbol)
  22672. return(sc->error_port);
  22673. }
  22674. static s7_pointer g_set_current_error_port(s7_scheme *sc, s7_pointer args)
  22675. {
  22676. #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"
  22677. #define Q_set_current_error_port s7_make_signature(sc, 2, sc->is_output_port_symbol, sc->is_output_port_symbol)
  22678. s7_pointer old_port, port;
  22679. old_port = sc->error_port;
  22680. port = car(args);
  22681. if (((is_output_port(port)) &&
  22682. (!port_is_closed(port))) ||
  22683. (port == sc->F))
  22684. sc->error_port = port;
  22685. else
  22686. {
  22687. check_method(sc, port, s7_make_symbol(sc, "set-current-error-port"), args);
  22688. return(s7_wrong_type_arg_error(sc, "set-current-error-port", 0, port, "an open output port"));
  22689. }
  22690. return(old_port);
  22691. }
  22692. #if (!WITH_PURE_S7)
  22693. static s7_pointer g_is_char_ready(s7_scheme *sc, s7_pointer args)
  22694. {
  22695. #define H_is_char_ready "(char-ready? (port (current-input-port))) returns #t if a character is ready for input on the given port"
  22696. #define Q_is_char_ready s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_input_port_symbol)
  22697. if (is_not_null(args))
  22698. {
  22699. s7_pointer pt = car(args);
  22700. if (!is_input_port(pt))
  22701. method_or_bust_with_type(sc, pt, sc->is_char_ready_symbol, args, an_input_port_string, 0);
  22702. if (port_is_closed(pt))
  22703. return(simple_wrong_type_argument_with_type(sc, sc->is_char_ready_symbol, pt, an_open_port_string));
  22704. if (is_function_port(pt))
  22705. return((*(port_input_function(pt)))(sc, S7_IS_CHAR_READY, pt));
  22706. return(make_boolean(sc, is_string_port(pt)));
  22707. }
  22708. return(make_boolean(sc, (is_input_port(sc->input_port)) && (is_string_port(sc->input_port))));
  22709. }
  22710. #endif
  22711. static s7_pointer g_is_eof_object(s7_scheme *sc, s7_pointer args)
  22712. {
  22713. #define H_is_eof_object "(eof-object? val) returns #t if val is the end-of-file object"
  22714. #define Q_is_eof_object pl_bt
  22715. check_boolean_method(sc, is_eof, sc->is_eof_object_symbol, args);
  22716. }
  22717. static int closed_port_read_char(s7_scheme *sc, s7_pointer port);
  22718. static s7_pointer closed_port_read_line(s7_scheme *sc, s7_pointer port, bool with_eol, bool copied);
  22719. static void closed_port_write_char(s7_scheme *sc, int c, s7_pointer port);
  22720. static void closed_port_write_string(s7_scheme *sc, const char *str, int len, s7_pointer port);
  22721. static void closed_port_display(s7_scheme *sc, const char *s, s7_pointer port);
  22722. void s7_close_input_port(s7_scheme *sc, s7_pointer p)
  22723. {
  22724. #if DEBUGGING
  22725. if (!is_input_port(p))
  22726. fprintf(stderr, "s7_close_input_port: %s\n", DISPLAY(p));
  22727. #endif
  22728. if ((is_immutable_port(p)) ||
  22729. ((is_input_port(p)) && (port_is_closed(p))))
  22730. return;
  22731. if (port_filename(p))
  22732. {
  22733. free(port_filename(p));
  22734. port_filename(p) = NULL;
  22735. }
  22736. if (is_file_port(p))
  22737. {
  22738. if (port_file(p))
  22739. {
  22740. fclose(port_file(p));
  22741. port_file(p) = NULL;
  22742. }
  22743. }
  22744. else
  22745. {
  22746. if ((is_string_port(p)) &&
  22747. (port_gc_loc(p) != -1))
  22748. s7_gc_unprotect_at(sc, port_gc_loc(p));
  22749. }
  22750. if (port_needs_free(p))
  22751. {
  22752. if (port_data(p))
  22753. {
  22754. free(port_data(p));
  22755. port_data(p) = NULL;
  22756. port_data_size(p) = 0;
  22757. }
  22758. port_needs_free(p) = false;
  22759. }
  22760. port_read_character(p) = closed_port_read_char;
  22761. port_read_line(p) = closed_port_read_line;
  22762. port_write_character(p) = closed_port_write_char;
  22763. port_write_string(p) = closed_port_write_string;
  22764. port_display(p) = closed_port_display;
  22765. port_is_closed(p) = true;
  22766. }
  22767. static s7_pointer c_close_input_port(s7_scheme *sc, s7_pointer pt)
  22768. {
  22769. if (!is_input_port(pt))
  22770. method_or_bust_with_type(sc, pt, sc->close_input_port_symbol, set_plist_1(sc, pt), an_input_port_string, 0);
  22771. if (!is_immutable_port(pt))
  22772. s7_close_input_port(sc, pt);
  22773. return(sc->unspecified);
  22774. }
  22775. static s7_pointer g_close_input_port(s7_scheme *sc, s7_pointer args)
  22776. {
  22777. #define H_close_input_port "(close-input-port port) closes the port"
  22778. #define Q_close_input_port s7_make_signature(sc, 2, sc->T, sc->is_input_port_symbol)
  22779. return(c_close_input_port(sc, car(args)));
  22780. }
  22781. PF_TO_PF(close_input_port, c_close_input_port)
  22782. void s7_flush_output_port(s7_scheme *sc, s7_pointer p)
  22783. {
  22784. if ((!is_output_port(p)) ||
  22785. (!is_file_port(p)) ||
  22786. (port_is_closed(p)) ||
  22787. (p == sc->F))
  22788. return;
  22789. if (port_file(p))
  22790. {
  22791. if (port_position(p) > 0)
  22792. {
  22793. if (fwrite((void *)(port_data(p)), 1, port_position(p), port_file(p)) != port_position(p))
  22794. s7_warn(sc, 64, "fwrite trouble in flush-output-port\n");
  22795. port_position(p) = 0;
  22796. }
  22797. fflush(port_file(p));
  22798. }
  22799. }
  22800. static s7_pointer g_flush_output_port(s7_scheme *sc, s7_pointer args)
  22801. {
  22802. #define H_flush_output_port "(flush-output-port port) flushes the port"
  22803. #define Q_flush_output_port s7_make_signature(sc, 2, sc->T, sc->is_output_port_symbol)
  22804. s7_pointer pt;
  22805. if (is_null(args))
  22806. pt = sc->output_port;
  22807. else pt = car(args);
  22808. if (!is_output_port(pt))
  22809. {
  22810. if (pt == sc->F) return(pt);
  22811. method_or_bust_with_type(sc, pt, sc->flush_output_port_symbol, args, an_output_port_string, 0);
  22812. }
  22813. s7_flush_output_port(sc, pt);
  22814. return(pt);
  22815. }
  22816. static s7_pointer c_flush_output_port(s7_scheme *sc) {return(g_flush_output_port(sc, sc->nil));}
  22817. PF_0(flush_output_port, c_flush_output_port)
  22818. static void close_output_port(s7_scheme *sc, s7_pointer p)
  22819. {
  22820. if (is_file_port(p))
  22821. {
  22822. if (port_filename(p)) /* only a file (output) port has a filename */
  22823. {
  22824. free(port_filename(p));
  22825. port_filename(p) = NULL;
  22826. port_filename_length(p) = 0;
  22827. }
  22828. if (port_file(p))
  22829. {
  22830. if (port_position(p) > 0)
  22831. {
  22832. if (fwrite((void *)(port_data(p)), 1, port_position(p), port_file(p)) != port_position(p))
  22833. s7_warn(sc, 64, "fwrite trouble in close-output-port\n");
  22834. port_position(p) = 0;
  22835. }
  22836. free(port_data(p));
  22837. fflush(port_file(p));
  22838. fclose(port_file(p));
  22839. port_file(p) = NULL;
  22840. }
  22841. }
  22842. else
  22843. {
  22844. if ((is_string_port(p)) &&
  22845. (port_data(p)))
  22846. {
  22847. free(port_data(p));
  22848. port_data(p) = NULL;
  22849. port_data_size(p) = 0;
  22850. port_needs_free(p) = false;
  22851. }
  22852. }
  22853. port_read_character(p) = closed_port_read_char;
  22854. port_read_line(p) = closed_port_read_line;
  22855. port_write_character(p) = closed_port_write_char;
  22856. port_write_string(p) = closed_port_write_string;
  22857. port_display(p) = closed_port_display;
  22858. port_is_closed(p) = true;
  22859. }
  22860. void s7_close_output_port(s7_scheme *sc, s7_pointer p)
  22861. {
  22862. if ((is_immutable_port(p)) ||
  22863. ((is_output_port(p)) && (port_is_closed(p))) ||
  22864. (p == sc->F))
  22865. return;
  22866. close_output_port(sc, p);
  22867. }
  22868. static s7_pointer c_close_output_port(s7_scheme *sc, s7_pointer pt)
  22869. {
  22870. if (!is_output_port(pt))
  22871. {
  22872. if (pt == sc->F) return(sc->unspecified);
  22873. method_or_bust_with_type(sc, pt, sc->close_output_port_symbol, set_plist_1(sc, pt), an_output_port_string, 0);
  22874. }
  22875. if (!(is_immutable_port(pt)))
  22876. s7_close_output_port(sc, pt);
  22877. return(sc->unspecified);
  22878. }
  22879. static s7_pointer g_close_output_port(s7_scheme *sc, s7_pointer args)
  22880. {
  22881. #define H_close_output_port "(close-output-port port) closes the port"
  22882. #define Q_close_output_port s7_make_signature(sc, 2, sc->T, sc->is_output_port_symbol)
  22883. return(c_close_output_port(sc, car(args)));
  22884. }
  22885. PF_TO_PF(close_output_port, c_close_output_port)
  22886. /* -------- read character functions -------- */
  22887. static int file_read_char(s7_scheme *sc, s7_pointer port)
  22888. {
  22889. return(fgetc(port_file(port)));
  22890. }
  22891. static int function_read_char(s7_scheme *sc, s7_pointer port)
  22892. {
  22893. return(character((*(port_input_function(port)))(sc, S7_READ_CHAR, port)));
  22894. }
  22895. static int string_read_char(s7_scheme *sc, s7_pointer port)
  22896. {
  22897. if (port_data_size(port) <= port_position(port)) /* port_string_length is 0 if no port string */
  22898. return(EOF);
  22899. return((unsigned char)port_data(port)[port_position(port)++]);
  22900. }
  22901. static int output_read_char(s7_scheme *sc, s7_pointer port)
  22902. {
  22903. simple_wrong_type_argument_with_type(sc, sc->read_char_symbol, port, an_input_port_string);
  22904. return(0);
  22905. }
  22906. static int closed_port_read_char(s7_scheme *sc, s7_pointer port)
  22907. {
  22908. simple_wrong_type_argument_with_type(sc, sc->read_char_symbol, port, an_open_port_string);
  22909. return(0);
  22910. }
  22911. /* -------- read line functions -------- */
  22912. static s7_pointer output_read_line(s7_scheme *sc, s7_pointer port, bool with_eol, bool copied)
  22913. {
  22914. return(simple_wrong_type_argument_with_type(sc, sc->read_line_symbol, port, an_input_port_string));
  22915. }
  22916. static s7_pointer closed_port_read_line(s7_scheme *sc, s7_pointer port, bool with_eol, bool copied)
  22917. {
  22918. return(simple_wrong_type_argument_with_type(sc, sc->read_line_symbol, port, an_open_port_string));
  22919. }
  22920. static s7_pointer function_read_line(s7_scheme *sc, s7_pointer port, bool with_eol, bool copied)
  22921. {
  22922. return((*(port_input_function(port)))(sc, S7_READ_LINE, port));
  22923. }
  22924. static s7_pointer stdin_read_line(s7_scheme *sc, s7_pointer port, bool with_eol, bool copied)
  22925. {
  22926. if (sc->read_line_buf == NULL)
  22927. {
  22928. sc->read_line_buf_size = 1024;
  22929. sc->read_line_buf = (char *)malloc(sc->read_line_buf_size * sizeof(char));
  22930. }
  22931. if (fgets(sc->read_line_buf, sc->read_line_buf_size, stdin) != NULL)
  22932. return(s7_make_string(sc, sc->read_line_buf)); /* fgets adds the trailing '\0' */
  22933. return(s7_make_string_with_length(sc, NULL, 0));
  22934. }
  22935. static s7_pointer file_read_line(s7_scheme *sc, s7_pointer port, bool with_eol, bool copied)
  22936. {
  22937. char *buf;
  22938. int read_size, previous_size = 0;
  22939. if (sc->read_line_buf == NULL)
  22940. {
  22941. sc->read_line_buf_size = 1024;
  22942. sc->read_line_buf = (char *)malloc(sc->read_line_buf_size * sizeof(char));
  22943. }
  22944. buf = sc->read_line_buf;
  22945. read_size = sc->read_line_buf_size;
  22946. while (true)
  22947. {
  22948. char *p, *rtn;
  22949. size_t len;
  22950. p = fgets(buf, read_size, port_file(port));
  22951. if (!p)
  22952. return(sc->eof_object);
  22953. rtn = strchr(buf, (int)'\n');
  22954. if (rtn)
  22955. {
  22956. port_line_number(port)++;
  22957. return(s7_make_string_with_length(sc, sc->read_line_buf, (with_eol) ? (previous_size + rtn - p + 1) : (previous_size + rtn - p)));
  22958. }
  22959. /* if no newline, then either at eof or need bigger buffer */
  22960. len = strlen(sc->read_line_buf);
  22961. if ((len + 1) < sc->read_line_buf_size)
  22962. return(s7_make_string_with_length(sc, sc->read_line_buf, len));
  22963. previous_size = sc->read_line_buf_size;
  22964. sc->read_line_buf_size *= 2;
  22965. sc->read_line_buf = (char *)realloc(sc->read_line_buf, sc->read_line_buf_size * sizeof(char));
  22966. read_size = previous_size;
  22967. previous_size -= 1;
  22968. buf = (char *)(sc->read_line_buf + previous_size);
  22969. }
  22970. return(sc->eof_object);
  22971. }
  22972. static s7_pointer string_read_line(s7_scheme *sc, s7_pointer port, bool with_eol, bool copied)
  22973. {
  22974. unsigned int i, port_start;
  22975. unsigned char *port_str, *cur, *start;
  22976. port_start = port_position(port);
  22977. port_str = port_data(port);
  22978. start = (unsigned char *)(port_str + port_start);
  22979. cur = (unsigned char *)strchr((const char *)start, (int)'\n'); /* this can run off the end making valgrind unhappy, but I think it's innocuous */
  22980. if (cur)
  22981. {
  22982. port_line_number(port)++;
  22983. i = cur - port_str;
  22984. port_position(port) = i + 1;
  22985. if (copied)
  22986. return(s7_make_string_with_length(sc, (const char *)start, ((with_eol) ? i + 1 : i) - port_start));
  22987. return(make_string_wrapper_with_length(sc, (char *)start, ((with_eol) ? i + 1 : i) - port_start));
  22988. }
  22989. i = port_data_size(port);
  22990. port_position(port) = i;
  22991. if (i <= port_start) /* the < part can happen -- if not caught we try to create a string of length -1 -> segfault */
  22992. return(sc->eof_object);
  22993. if (copied)
  22994. return(s7_make_string_with_length(sc, (const char *)start, i - port_start));
  22995. return(make_string_wrapper_with_length(sc, (char *)start, i - port_start));
  22996. }
  22997. /* -------- write character functions -------- */
  22998. static void resize_port_data(s7_pointer pt, int new_size)
  22999. {
  23000. int loc;
  23001. loc = port_data_size(pt);
  23002. port_data_size(pt) = new_size;
  23003. port_data(pt) = (unsigned char *)realloc(port_data(pt), new_size * sizeof(unsigned char));
  23004. memclr((void *)(port_data(pt) + loc), new_size - loc);
  23005. }
  23006. static void string_write_char(s7_scheme *sc, int c, s7_pointer pt)
  23007. {
  23008. if (port_position(pt) >= port_data_size(pt))
  23009. resize_port_data(pt, port_data_size(pt) * 2);
  23010. port_data(pt)[port_position(pt)++] = c;
  23011. }
  23012. static void stdout_write_char(s7_scheme *sc, int c, s7_pointer port)
  23013. {
  23014. fputc(c, stdout);
  23015. }
  23016. static void stderr_write_char(s7_scheme *sc, int c, s7_pointer port)
  23017. {
  23018. fputc(c, stderr);
  23019. }
  23020. static void function_write_char(s7_scheme *sc, int c, s7_pointer port)
  23021. {
  23022. (*(port_output_function(port)))(sc, c, port);
  23023. }
  23024. #define PORT_DATA_SIZE 256
  23025. static void file_write_char(s7_scheme *sc, int c, s7_pointer port)
  23026. {
  23027. if (port_position(port) == PORT_DATA_SIZE)
  23028. {
  23029. if (fwrite((void *)(port_data(port)), 1, PORT_DATA_SIZE, port_file(port)) != PORT_DATA_SIZE)
  23030. s7_warn(sc, 64, "fwrite trouble during write-char\n");
  23031. port_position(port) = 0;
  23032. }
  23033. port_data(port)[port_position(port)++] = (unsigned char)c;
  23034. }
  23035. static void input_write_char(s7_scheme *sc, int c, s7_pointer port)
  23036. {
  23037. simple_wrong_type_argument_with_type(sc, sc->write_char_symbol, port, an_output_port_string);
  23038. }
  23039. static void closed_port_write_char(s7_scheme *sc, int c, s7_pointer port)
  23040. {
  23041. simple_wrong_type_argument_with_type(sc, sc->write_char_symbol, port, an_open_port_string);
  23042. }
  23043. /* -------- write string functions -------- */
  23044. static void input_write_string(s7_scheme *sc, const char *str, int len, s7_pointer port)
  23045. {
  23046. simple_wrong_type_argument_with_type(sc, sc->write_symbol, port, an_output_port_string);
  23047. }
  23048. static void closed_port_write_string(s7_scheme *sc, const char *str, int len, s7_pointer port)
  23049. {
  23050. simple_wrong_type_argument_with_type(sc, sc->write_symbol, port, an_open_port_string);
  23051. }
  23052. static void input_display(s7_scheme *sc, const char *s, s7_pointer port)
  23053. {
  23054. simple_wrong_type_argument_with_type(sc, sc->write_symbol, port, an_output_port_string);
  23055. }
  23056. static void closed_port_display(s7_scheme *sc, const char *s, s7_pointer port)
  23057. {
  23058. simple_wrong_type_argument_with_type(sc, sc->write_symbol, port, an_open_port_string);
  23059. }
  23060. static void stdout_write_string(s7_scheme *sc, const char *str, int len, s7_pointer port)
  23061. {
  23062. if (str[len] == '\0')
  23063. fputs(str, stdout);
  23064. else
  23065. {
  23066. int i;
  23067. for (i = 0; i < len; i++)
  23068. fputc(str[i], stdout);
  23069. }
  23070. }
  23071. static void stderr_write_string(s7_scheme *sc, const char *str, int len, s7_pointer port)
  23072. {
  23073. if (str[len] == '\0')
  23074. fputs(str, stderr);
  23075. else
  23076. {
  23077. int i;
  23078. for (i = 0; i < len; i++)
  23079. fputc(str[i], stderr);
  23080. }
  23081. }
  23082. static void string_write_string(s7_scheme *sc, const char *str, int len, s7_pointer pt)
  23083. {
  23084. int new_len; /* len is known to be non-zero */
  23085. new_len = port_position(pt) + len;
  23086. if (new_len >= (int)port_data_size(pt))
  23087. resize_port_data(pt, new_len * 2);
  23088. memcpy((void *)(port_data(pt) + port_position(pt)), (void *)str, len);
  23089. /* memcpy is much faster than the equivalent while loop */
  23090. port_position(pt) = new_len;
  23091. }
  23092. static s7_pointer write_string_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  23093. {
  23094. check_for_substring_temp(sc, expr);
  23095. return(f);
  23096. }
  23097. static void file_display(s7_scheme *sc, const char *s, s7_pointer port)
  23098. {
  23099. if (s)
  23100. {
  23101. if (port_position(port) > 0)
  23102. {
  23103. if (fwrite((void *)(port_data(port)), 1, port_position(port), port_file(port)) != port_position(port))
  23104. s7_warn(sc, 64, "fwrite trouble in display\n");
  23105. port_position(port) = 0;
  23106. }
  23107. if (fputs(s, port_file(port)) == EOF)
  23108. s7_warn(sc, 64, "write to %s: %s\n", port_filename(port), strerror(errno));
  23109. }
  23110. }
  23111. static void file_write_string(s7_scheme *sc, const char *str, int len, s7_pointer pt)
  23112. {
  23113. int new_len;
  23114. new_len = port_position(pt) + len;
  23115. if (new_len >= PORT_DATA_SIZE)
  23116. {
  23117. if (port_position(pt) > 0)
  23118. {
  23119. if (fwrite((void *)(port_data(pt)), 1, port_position(pt), port_file(pt)) != port_position(pt))
  23120. s7_warn(sc, 64, "fwrite trouble in write-string\n");
  23121. port_position(pt) = 0;
  23122. }
  23123. if (fwrite((void *)str, 1, len, port_file(pt)) != (size_t)len)
  23124. s7_warn(sc, 64, "fwrite trouble in write-string\n");
  23125. }
  23126. else
  23127. {
  23128. memcpy((void *)(port_data(pt) + port_position(pt)), (void *)str, len);
  23129. port_position(pt) = new_len;
  23130. }
  23131. }
  23132. static void string_display(s7_scheme *sc, const char *s, s7_pointer port)
  23133. {
  23134. if (s)
  23135. string_write_string(sc, s, safe_strlen(s), port);
  23136. }
  23137. static void function_display(s7_scheme *sc, const char *s, s7_pointer port)
  23138. {
  23139. if (s)
  23140. {
  23141. for (; *s; s++)
  23142. (*(port_output_function(port)))(sc, *s, port);
  23143. }
  23144. }
  23145. static void function_write_string(s7_scheme *sc, const char *str, int len, s7_pointer pt)
  23146. {
  23147. int i;
  23148. for (i = 0; i < len; i++)
  23149. (*(port_output_function(pt)))(sc, str[i], pt);
  23150. }
  23151. static void stdout_display(s7_scheme *sc, const char *s, s7_pointer port)
  23152. {
  23153. if (s) fputs(s, stdout);
  23154. }
  23155. static void stderr_display(s7_scheme *sc, const char *s, s7_pointer port)
  23156. {
  23157. if (s) fputs(s, stderr);
  23158. }
  23159. static s7_pointer g_write_string(s7_scheme *sc, s7_pointer args)
  23160. {
  23161. #define H_write_string "(write-string str port start end) writes str to port."
  23162. #define Q_write_string s7_make_circular_signature(sc, 3, 4, sc->is_string_symbol, sc->is_string_symbol, sc->is_output_port_symbol, sc->is_integer_symbol)
  23163. s7_pointer str, port;
  23164. s7_int start = 0, end;
  23165. str = car(args);
  23166. if (!is_string(str))
  23167. method_or_bust(sc, str, sc->write_string_symbol, args, T_STRING, 1);
  23168. end = string_length(str);
  23169. if (!is_null(cdr(args)))
  23170. {
  23171. s7_pointer inds;
  23172. port = cadr(args);
  23173. inds = cddr(args);
  23174. if (!is_null(inds))
  23175. {
  23176. s7_pointer p;
  23177. p = start_and_end(sc, sc->write_string_symbol, NULL, inds, args, 3, &start, &end);
  23178. if (p != sc->gc_nil) return(p);
  23179. }
  23180. }
  23181. else port = sc->output_port;
  23182. if (!is_output_port(port))
  23183. {
  23184. if (port == sc->F)
  23185. {
  23186. s7_pointer x;
  23187. int len;
  23188. if ((start == 0) && (end == string_length(str)))
  23189. return(str);
  23190. len = (int)(end - start);
  23191. x = s7_make_string_with_length(sc, (char *)(string_value(str) + start), len);
  23192. string_value(x)[len] = 0;
  23193. return(x);
  23194. }
  23195. method_or_bust_with_type(sc, port, sc->write_string_symbol, args, an_output_port_string, 2);
  23196. }
  23197. if (start == 0)
  23198. port_write_string(port)(sc, string_value(str), end, port);
  23199. else port_write_string(port)(sc, (char *)(string_value(str) + start), (end - start), port);
  23200. return(str);
  23201. }
  23202. static s7_pointer c_write_string(s7_scheme *sc, s7_pointer x) {return(g_write_string(sc, set_plist_1(sc, x)));}
  23203. PF_TO_PF(write_string, c_write_string)
  23204. /* -------- skip to newline readers -------- */
  23205. static token_t file_read_semicolon(s7_scheme *sc, s7_pointer pt)
  23206. {
  23207. int c;
  23208. do (c = fgetc(port_file(pt))); while ((c != '\n') && (c != EOF));
  23209. port_line_number(pt)++;
  23210. if (c == EOF)
  23211. return(TOKEN_EOF);
  23212. return(token(sc));
  23213. }
  23214. static token_t string_read_semicolon(s7_scheme *sc, s7_pointer pt)
  23215. {
  23216. const char *orig_str, *str;
  23217. str = (const char *)(port_data(pt) + port_position(pt));
  23218. orig_str = strchr(str, (int)'\n');
  23219. if (!orig_str)
  23220. {
  23221. port_position(pt) = port_data_size(pt);
  23222. return(TOKEN_EOF);
  23223. }
  23224. port_position(pt) += (orig_str - str + 1); /* + 1 because strchr leaves orig_str pointing at the newline */
  23225. port_line_number(pt)++;
  23226. return(token(sc));
  23227. }
  23228. /* -------- white space readers -------- */
  23229. static int file_read_white_space(s7_scheme *sc, s7_pointer port)
  23230. {
  23231. int c;
  23232. while (is_white_space(c = fgetc(port_file(port))))
  23233. if (c == '\n')
  23234. port_line_number(port)++;
  23235. return(c);
  23236. }
  23237. static int terminated_string_read_white_space(s7_scheme *sc, s7_pointer pt)
  23238. {
  23239. const unsigned char *str;
  23240. unsigned char c;
  23241. /* here we know we have null termination and white_space[#\null] is false.
  23242. */
  23243. str = (const unsigned char *)(port_data(pt) + port_position(pt));
  23244. while (white_space[c = *str++]) /* (let ((ÿa 1)) ÿa) -- 255 is not -1 = EOF */
  23245. if (c == '\n')
  23246. port_line_number(pt)++;
  23247. if (c)
  23248. port_position(pt) = str - port_data(pt);
  23249. else port_position(pt) = port_data_size(pt);
  23250. return((int)c);
  23251. }
  23252. /* name (alphanumeric token) readers */
  23253. static void resize_strbuf(s7_scheme *sc, unsigned int needed_size)
  23254. {
  23255. unsigned int i, old_size;
  23256. old_size = sc->strbuf_size;
  23257. while (sc->strbuf_size <= needed_size) sc->strbuf_size *= 2;
  23258. sc->strbuf = (char *)realloc(sc->strbuf, sc->strbuf_size * sizeof(char));
  23259. for (i = old_size; i < sc->strbuf_size; i++) sc->strbuf[i] = '\0';
  23260. }
  23261. static s7_pointer file_read_name_or_sharp(s7_scheme *sc, s7_pointer pt, bool atom_case)
  23262. {
  23263. int c;
  23264. unsigned int i = 1;
  23265. /* sc->strbuf[0] has the first char of the string we're reading */
  23266. do {
  23267. c = fgetc(port_file(pt)); /* might return EOF */
  23268. if (c == '\n')
  23269. port_line_number(pt)++;
  23270. sc->strbuf[i++] = c;
  23271. if (i >= sc->strbuf_size)
  23272. resize_strbuf(sc, i);
  23273. } while ((c != EOF) && (char_ok_in_a_name[c]));
  23274. if ((i == 2) &&
  23275. (sc->strbuf[0] == '\\'))
  23276. sc->strbuf[2] = '\0';
  23277. else
  23278. {
  23279. if (c != EOF)
  23280. {
  23281. if (c == '\n')
  23282. port_line_number(pt)--;
  23283. ungetc(c, port_file(pt));
  23284. }
  23285. sc->strbuf[i - 1] = '\0';
  23286. }
  23287. if (atom_case)
  23288. return(make_atom(sc, sc->strbuf, BASE_10, SYMBOL_OK, WITH_OVERFLOW_ERROR));
  23289. return(make_sharp_constant(sc, sc->strbuf, UNNESTED_SHARP, BASE_10, WITH_OVERFLOW_ERROR));
  23290. }
  23291. static s7_pointer file_read_name(s7_scheme *sc, s7_pointer pt)
  23292. {
  23293. return(file_read_name_or_sharp(sc, pt, true));
  23294. }
  23295. static s7_pointer file_read_sharp(s7_scheme *sc, s7_pointer pt)
  23296. {
  23297. return(file_read_name_or_sharp(sc, pt, false));
  23298. }
  23299. static s7_pointer string_read_name_no_free(s7_scheme *sc, s7_pointer pt)
  23300. {
  23301. /* sc->strbuf[0] has the first char of the string we're reading */
  23302. unsigned int k;
  23303. char *str, *orig_str;
  23304. str = (char *)(port_data(pt) + port_position(pt));
  23305. if (!char_ok_in_a_name[(unsigned char)*str])
  23306. {
  23307. s7_pointer result;
  23308. result = sc->singletons[(unsigned char)(sc->strbuf[0])];
  23309. if (!result)
  23310. {
  23311. sc->strbuf[1] = '\0';
  23312. result = make_symbol_with_length(sc, sc->strbuf, 1);
  23313. sc->singletons[(unsigned char)(sc->strbuf[0])] = result;
  23314. }
  23315. return(result);
  23316. }
  23317. orig_str = (char *)(str - 1);
  23318. str++;
  23319. while (char_ok_in_a_name[(unsigned char)(*str)]) {str++;}
  23320. k = str - orig_str;
  23321. if (*str != 0)
  23322. port_position(pt) += (k - 1);
  23323. else port_position(pt) = port_data_size(pt);
  23324. /* this is equivalent to:
  23325. * str = strpbrk(str, "(); \"\t\r\n");
  23326. * if (!str)
  23327. * {
  23328. * k = strlen(orig_str);
  23329. * str = (char *)(orig_str + k);
  23330. * }
  23331. * else k = str - orig_str;
  23332. * but slightly faster.
  23333. */
  23334. if (!number_table[(unsigned char)(*orig_str)])
  23335. return(make_symbol_with_length(sc, orig_str, k));
  23336. /* eval_c_string string is a constant so we can't set and unset the token's end char */
  23337. if ((k + 1) >= sc->strbuf_size)
  23338. resize_strbuf(sc, k + 1);
  23339. memcpy((void *)(sc->strbuf), (void *)orig_str, k);
  23340. sc->strbuf[k] = '\0';
  23341. return(make_atom(sc, sc->strbuf, BASE_10, SYMBOL_OK, WITH_OVERFLOW_ERROR));
  23342. }
  23343. static s7_pointer string_read_sharp(s7_scheme *sc, s7_pointer pt)
  23344. {
  23345. /* sc->strbuf[0] has the first char of the string we're reading.
  23346. * since a *#readers* function might want to get further input, we can't mess with the input even when it is otherwise safe
  23347. */
  23348. unsigned int k;
  23349. char *orig_str, *str;
  23350. str = (char *)(port_data(pt) + port_position(pt));
  23351. if (!char_ok_in_a_name[(unsigned char)*str])
  23352. {
  23353. if (sc->strbuf[0] == 'f')
  23354. return(sc->F);
  23355. if (sc->strbuf[0] == 't')
  23356. return(sc->T);
  23357. if (sc->strbuf[0] == '\\')
  23358. {
  23359. /* must be from #\( and friends -- a character that happens to be not ok-in-a-name */
  23360. sc->strbuf[1] = str[0];
  23361. sc->strbuf[2] = '\0';
  23362. port_position(pt)++;
  23363. }
  23364. else sc->strbuf[1] = '\0';
  23365. return(make_sharp_constant(sc, sc->strbuf, UNNESTED_SHARP, BASE_10, WITH_OVERFLOW_ERROR));
  23366. }
  23367. orig_str = (char *)(str - 1);
  23368. str++;
  23369. while (char_ok_in_a_name[(unsigned char)(*str)]) {str++;}
  23370. k = str - orig_str;
  23371. if (*str != 0)
  23372. port_position(pt) += (k - 1);
  23373. else port_position(pt) += k;
  23374. if ((k + 1) >= sc->strbuf_size)
  23375. resize_strbuf(sc, k + 1);
  23376. memcpy((void *)(sc->strbuf), (void *)orig_str, k);
  23377. sc->strbuf[k] = '\0';
  23378. return(make_sharp_constant(sc, sc->strbuf, UNNESTED_SHARP, BASE_10, WITH_OVERFLOW_ERROR));
  23379. }
  23380. static s7_pointer string_read_name(s7_scheme *sc, s7_pointer pt)
  23381. {
  23382. /* port_string was allocated (and read from a file) so we can mess with it directly */
  23383. s7_pointer result;
  23384. unsigned int k;
  23385. char *orig_str, *str;
  23386. char endc;
  23387. str = (char *)(port_data(pt) + port_position(pt));
  23388. if (!char_ok_in_a_name[(unsigned char)*str])
  23389. {
  23390. s7_pointer result;
  23391. result = sc->singletons[(unsigned char)(sc->strbuf[0])];
  23392. if (!result)
  23393. {
  23394. sc->strbuf[1] = '\0';
  23395. result = make_symbol_with_length(sc, sc->strbuf, 1);
  23396. sc->singletons[(unsigned char)(sc->strbuf[0])] = result;
  23397. }
  23398. return(result);
  23399. }
  23400. orig_str = (char *)(str - 1);
  23401. str++;
  23402. while (char_ok_in_a_name[(unsigned char)(*str)]) {str++;}
  23403. k = str - orig_str;
  23404. if (*str != 0)
  23405. port_position(pt) += (k - 1);
  23406. else port_position(pt) = port_data_size(pt);
  23407. if (!number_table[(unsigned char)(*orig_str)])
  23408. return(make_symbol_with_length(sc, orig_str, k));
  23409. endc = (*str);
  23410. (*str) = '\0';
  23411. result = make_atom(sc, orig_str, BASE_10, SYMBOL_OK, WITH_OVERFLOW_ERROR);
  23412. (*str) = endc;
  23413. return(result);
  23414. }
  23415. static s7_pointer read_file(s7_scheme *sc, FILE *fp, const char *name, long max_size, const char *caller)
  23416. {
  23417. s7_pointer port;
  23418. #ifndef _MSC_VER
  23419. long size;
  23420. #endif
  23421. int port_loc;
  23422. new_cell(sc, port, T_INPUT_PORT);
  23423. port_loc = s7_gc_protect(sc, port);
  23424. port_port(port) = alloc_port(sc);
  23425. port_is_closed(port) = false;
  23426. port_original_input_string(port) = sc->nil;
  23427. port_write_character(port) = input_write_char;
  23428. port_write_string(port) = input_write_string;
  23429. /* if we're constantly opening files, and each open saves the file name in permanent
  23430. * memory, we gradually core-up.
  23431. */
  23432. port_filename_length(port) = safe_strlen(name);
  23433. port_filename(port) = copy_string_with_length(name, port_filename_length(port));
  23434. port_line_number(port) = 1; /* first line is numbered 1 */
  23435. add_input_port(sc, port);
  23436. #ifndef _MSC_VER
  23437. /* this doesn't work in MS C */
  23438. fseek(fp, 0, SEEK_END);
  23439. size = ftell(fp);
  23440. rewind(fp);
  23441. /* pseudo files (under /proc for example) have size=0, but we can read them, so don't assume a 0 length file is empty
  23442. */
  23443. if ((size > 0) && /* if (size != 0) we get (open-input-file "/dev/tty") -> (open "/dev/tty") read 0 bytes of an expected -1? */
  23444. ((max_size < 0) || (size < max_size)))
  23445. {
  23446. size_t bytes;
  23447. unsigned char *content;
  23448. content = (unsigned char *)malloc((size + 2) * sizeof(unsigned char));
  23449. bytes = fread(content, sizeof(unsigned char), size, fp);
  23450. if (bytes != (size_t)size)
  23451. {
  23452. char tmp[256];
  23453. int len;
  23454. len = snprintf(tmp, 256, "(%s \"%s\") read %ld bytes of an expected %ld?", caller, name, (long)bytes, size);
  23455. port_write_string(sc->output_port)(sc, tmp, len, sc->output_port);
  23456. size = bytes;
  23457. }
  23458. content[size] = '\0';
  23459. content[size + 1] = '\0';
  23460. fclose(fp);
  23461. port_type(port) = STRING_PORT;
  23462. port_data(port) = content;
  23463. port_data_size(port) = size;
  23464. port_position(port) = 0;
  23465. port_needs_free(port) = true;
  23466. port_gc_loc(port) = -1;
  23467. port_read_character(port) = string_read_char;
  23468. port_read_line(port) = string_read_line;
  23469. port_display(port) = input_display;
  23470. port_read_semicolon(port) = string_read_semicolon;
  23471. port_read_white_space(port) = terminated_string_read_white_space;
  23472. port_read_name(port) = string_read_name;
  23473. port_read_sharp(port) = string_read_sharp;
  23474. }
  23475. else
  23476. {
  23477. port_file(port) = fp;
  23478. port_type(port) = FILE_PORT;
  23479. port_needs_free(port) = false;
  23480. port_read_character(port) = file_read_char;
  23481. port_read_line(port) = file_read_line;
  23482. port_display(port) = input_display;
  23483. port_read_semicolon(port) = file_read_semicolon;
  23484. port_read_white_space(port) = file_read_white_space;
  23485. port_read_name(port) = file_read_name;
  23486. port_read_sharp(port) = file_read_sharp; /* was string_read_sharp?? */
  23487. }
  23488. #else
  23489. /* _stat64 is no better than the fseek/ftell route, and
  23490. * GetFileSizeEx and friends requires Windows.h which makes hash of everything else.
  23491. * fread until done takes too long on big files, so use a file port
  23492. */
  23493. port_file(port) = fp;
  23494. port_type(port) = FILE_PORT;
  23495. port_needs_free(port) = false;
  23496. port_read_character(port) = file_read_char;
  23497. port_read_line(port) = file_read_line;
  23498. port_display(port) = input_display;
  23499. port_read_semicolon(port) = file_read_semicolon;
  23500. port_read_white_space(port) = file_read_white_space;
  23501. port_read_name(port) = file_read_name;
  23502. port_read_sharp(port) = file_read_sharp;
  23503. #endif
  23504. s7_gc_unprotect_at(sc, port_loc);
  23505. return(port);
  23506. }
  23507. static s7_pointer make_input_file(s7_scheme *sc, const char *name, FILE *fp)
  23508. {
  23509. #define MAX_SIZE_FOR_STRING_PORT 5000000
  23510. return(read_file(sc, fp, name, MAX_SIZE_FOR_STRING_PORT, "open"));
  23511. }
  23512. #if (!MS_WINDOWS)
  23513. #include <sys/stat.h>
  23514. #endif
  23515. static bool is_directory(const char *filename)
  23516. {
  23517. #if (!MS_WINDOWS)
  23518. #ifdef S_ISDIR
  23519. struct stat statbuf;
  23520. return((stat(filename, &statbuf) >= 0) &&
  23521. (S_ISDIR(statbuf.st_mode)));
  23522. #endif
  23523. #endif
  23524. return(false);
  23525. }
  23526. static s7_pointer open_input_file_1(s7_scheme *sc, const char *name, const char *mode, const char *caller)
  23527. {
  23528. FILE *fp;
  23529. /* see if we can open this file before allocating a port */
  23530. if (is_directory(name))
  23531. return(file_error(sc, caller, "is a directory", name));
  23532. errno = 0;
  23533. fp = fopen(name, mode);
  23534. if (!fp)
  23535. {
  23536. #if (!MS_WINDOWS)
  23537. if (errno == EINVAL)
  23538. return(file_error(sc, caller, "invalid mode", mode));
  23539. #if WITH_GCC
  23540. /* catch one special case, "~/..." */
  23541. if ((name[0] == '~') &&
  23542. (name[1] == '/'))
  23543. {
  23544. char *home;
  23545. home = getenv("HOME");
  23546. if (home)
  23547. {
  23548. char *filename;
  23549. int len;
  23550. len = safe_strlen(name) + safe_strlen(home) + 1;
  23551. tmpbuf_malloc(filename, len);
  23552. snprintf(filename, len, "%s%s", home, (char *)(name + 1));
  23553. fp = fopen(filename, "r");
  23554. tmpbuf_free(filename, len);
  23555. if (fp)
  23556. return(make_input_file(sc, name, fp));
  23557. }
  23558. }
  23559. #endif
  23560. #endif
  23561. return(file_error(sc, caller, strerror(errno), name));
  23562. }
  23563. return(make_input_file(sc, name, fp));
  23564. }
  23565. s7_pointer s7_open_input_file(s7_scheme *sc, const char *name, const char *mode)
  23566. {
  23567. return(open_input_file_1(sc, name, mode, "open-input-file"));
  23568. }
  23569. static s7_pointer g_open_input_file(s7_scheme *sc, s7_pointer args)
  23570. {
  23571. #define H_open_input_file "(open-input-file filename (mode \"r\")) opens filename for reading"
  23572. #define Q_open_input_file s7_make_signature(sc, 3, sc->is_input_port_symbol, sc->is_string_symbol, sc->is_string_symbol)
  23573. s7_pointer name = car(args);
  23574. if (!is_string(name))
  23575. method_or_bust(sc, name, sc->open_input_file_symbol, args, T_STRING, 1);
  23576. /* what if the file name is a byte-vector? currently we accept it */
  23577. if (is_pair(cdr(args)))
  23578. {
  23579. s7_pointer mode;
  23580. mode = cadr(args);
  23581. if (!is_string(mode))
  23582. method_or_bust_with_type(sc, mode, sc->open_input_file_symbol, args, make_string_wrapper(sc, "a string (a mode such as \"r\")"), 2);
  23583. /* since scheme allows embedded nulls, dumb stuff is accepted here: (open-input-file file "a\x00b") -- should this be an error? */
  23584. return(open_input_file_1(sc, string_value(name), string_value(mode), "open-input-file"));
  23585. }
  23586. return(open_input_file_1(sc, string_value(name), "r", "open-input-file"));
  23587. }
  23588. static void make_standard_ports(s7_scheme *sc)
  23589. {
  23590. s7_pointer x;
  23591. /* standard output */
  23592. x = alloc_pointer();
  23593. unheap(x);
  23594. set_type(x, T_OUTPUT_PORT | T_IMMUTABLE);
  23595. port_port(x) = (port_t *)calloc(1, sizeof(port_t));
  23596. port_type(x) = FILE_PORT;
  23597. port_data(x) = NULL;
  23598. port_is_closed(x) = false;
  23599. port_filename_length(x) = 8;
  23600. port_filename(x) = copy_string_with_length("*stdout*", 8);
  23601. port_file_number(x) = remember_file_name(sc, port_filename(x)); /* these numbers need to be correct for the evaluator (__FUNC__ data) */
  23602. port_line_number(x) = 0;
  23603. port_file(x) = stdout;
  23604. port_needs_free(x) = false;
  23605. port_read_character(x) = output_read_char;
  23606. port_read_line(x) = output_read_line;
  23607. port_display(x) = stdout_display;
  23608. port_write_character(x) = stdout_write_char;
  23609. port_write_string(x) = stdout_write_string;
  23610. sc->standard_output = x;
  23611. /* standard error */
  23612. x = alloc_pointer();
  23613. unheap(x);
  23614. set_type(x, T_OUTPUT_PORT | T_IMMUTABLE);
  23615. port_port(x) = (port_t *)calloc(1, sizeof(port_t));
  23616. port_type(x) = FILE_PORT;
  23617. port_data(x) = NULL;
  23618. port_is_closed(x) = false;
  23619. port_filename_length(x) = 8;
  23620. port_filename(x) = copy_string_with_length("*stderr*", 8);
  23621. port_file_number(x) = remember_file_name(sc, port_filename(x));
  23622. port_line_number(x) = 0;
  23623. port_file(x) = stderr;
  23624. port_needs_free(x) = false;
  23625. port_read_character(x) = output_read_char;
  23626. port_read_line(x) = output_read_line;
  23627. port_display(x) = stderr_display;
  23628. port_write_character(x) = stderr_write_char;
  23629. port_write_string(x) = stderr_write_string;
  23630. sc->standard_error = x;
  23631. /* standard input */
  23632. x = alloc_pointer();
  23633. unheap(x);
  23634. set_type(x, T_INPUT_PORT | T_IMMUTABLE);
  23635. port_port(x) = (port_t *)calloc(1, sizeof(port_t));
  23636. port_type(x) = FILE_PORT;
  23637. port_is_closed(x) = false;
  23638. port_original_input_string(x) = sc->nil;
  23639. port_filename_length(x) = 7;
  23640. port_filename(x) = copy_string_with_length("*stdin*", 7);
  23641. port_file_number(x) = remember_file_name(sc, port_filename(x));
  23642. port_line_number(x) = 0;
  23643. port_file(x) = stdin;
  23644. port_needs_free(x) = false;
  23645. port_read_character(x) = file_read_char;
  23646. port_read_line(x) = stdin_read_line;
  23647. port_display(x) = input_display;
  23648. port_read_semicolon(x) = file_read_semicolon;
  23649. port_read_white_space(x) = file_read_white_space;
  23650. port_read_name(x) = file_read_name;
  23651. port_read_sharp(x) = file_read_sharp;
  23652. port_write_character(x) = input_write_char;
  23653. port_write_string(x) = input_write_string;
  23654. sc->standard_input = x;
  23655. s7_define_constant(sc, "*stdin*", sc->standard_input);
  23656. s7_define_constant(sc, "*stdout*", sc->standard_output);
  23657. s7_define_constant(sc, "*stderr*", sc->standard_error);
  23658. sc->input_port = sc->standard_input;
  23659. sc->output_port = sc->standard_output;
  23660. sc->error_port = sc->standard_error;
  23661. sc->current_file = NULL;
  23662. sc->current_line = -1;
  23663. }
  23664. s7_pointer s7_open_output_file(s7_scheme *sc, const char *name, const char *mode)
  23665. {
  23666. FILE *fp;
  23667. s7_pointer x;
  23668. /* see if we can open this file before allocating a port */
  23669. errno = 0;
  23670. fp = fopen(name, mode);
  23671. if (!fp)
  23672. {
  23673. #if (!MS_WINDOWS)
  23674. if (errno == EINVAL)
  23675. return(file_error(sc, "open-output-file", "invalid mode", mode));
  23676. #endif
  23677. return(file_error(sc, "open-output-file", strerror(errno), name));
  23678. }
  23679. new_cell(sc, x, T_OUTPUT_PORT);
  23680. port_port(x) = alloc_port(sc);
  23681. port_type(x) = FILE_PORT;
  23682. port_is_closed(x) = false;
  23683. port_filename_length(x) = safe_strlen(name);
  23684. port_filename(x) = copy_string_with_length(name, port_filename_length(x));
  23685. port_line_number(x) = 1;
  23686. port_file(x) = fp;
  23687. port_needs_free(x) = false;
  23688. port_read_character(x) = output_read_char;
  23689. port_read_line(x) = output_read_line;
  23690. port_display(x) = file_display;
  23691. port_write_character(x) = file_write_char;
  23692. port_write_string(x) = file_write_string;
  23693. port_position(x) = 0;
  23694. port_data_size(x) = PORT_DATA_SIZE;
  23695. port_data(x) = (unsigned char *)malloc(PORT_DATA_SIZE); /* was +8? */
  23696. add_output_port(sc, x);
  23697. return(x);
  23698. }
  23699. static s7_pointer g_open_output_file(s7_scheme *sc, s7_pointer args)
  23700. {
  23701. #define H_open_output_file "(open-output-file filename (mode \"w\")) opens filename for writing"
  23702. #define Q_open_output_file s7_make_signature(sc, 3, sc->is_output_port_symbol, sc->is_string_symbol, sc->is_string_symbol)
  23703. s7_pointer name = car(args);
  23704. if (!is_string(name))
  23705. method_or_bust(sc, name, sc->open_output_file_symbol, args, T_STRING, 1);
  23706. if (is_pair(cdr(args)))
  23707. {
  23708. if (!is_string(cadr(args)))
  23709. method_or_bust_with_type(sc, cadr(args), sc->open_output_file_symbol, args, make_string_wrapper(sc, "a string (a mode such as \"w\")"), 2);
  23710. return(s7_open_output_file(sc, string_value(name), string_value(cadr(args))));
  23711. }
  23712. return(s7_open_output_file(sc, string_value(name), "w"));
  23713. }
  23714. static s7_pointer open_input_string(s7_scheme *sc, const char *input_string, int len)
  23715. {
  23716. s7_pointer x;
  23717. new_cell(sc, x, T_INPUT_PORT);
  23718. port_port(x) = alloc_port(sc);
  23719. port_type(x) = STRING_PORT;
  23720. port_is_closed(x) = false;
  23721. port_original_input_string(x) = sc->nil;
  23722. port_data(x) = (unsigned char *)input_string;
  23723. port_data_size(x) = len;
  23724. port_position(x) = 0;
  23725. port_filename_length(x) = 0;
  23726. port_filename(x) = NULL;
  23727. port_file_number(x) = 0; /* unsigned int */
  23728. port_line_number(x) = 0;
  23729. port_needs_free(x) = false;
  23730. port_gc_loc(x) = -1;
  23731. port_read_character(x) = string_read_char;
  23732. port_read_line(x) = string_read_line;
  23733. port_display(x) = input_display;
  23734. port_read_semicolon(x) = string_read_semicolon;
  23735. #if DEBUGGING
  23736. if (input_string[len] != '\0')
  23737. fprintf(stderr, "read_white_space string is not terminated: %s", input_string);
  23738. #endif
  23739. port_read_white_space(x) = terminated_string_read_white_space;
  23740. port_read_name(x) = string_read_name_no_free;
  23741. port_read_sharp(x) = string_read_sharp;
  23742. port_write_character(x) = input_write_char;
  23743. port_write_string(x) = input_write_string;
  23744. add_input_port(sc, x);
  23745. return(x);
  23746. }
  23747. static s7_pointer open_and_protect_input_string(s7_scheme *sc, s7_pointer str)
  23748. {
  23749. s7_pointer p;
  23750. p = open_input_string(sc, string_value(str), string_length(str));
  23751. port_gc_loc(p) = s7_gc_protect(sc, str);
  23752. return(p);
  23753. }
  23754. s7_pointer s7_open_input_string(s7_scheme *sc, const char *input_string)
  23755. {
  23756. return(open_input_string(sc, input_string, safe_strlen(input_string)));
  23757. }
  23758. static s7_pointer g_open_input_string(s7_scheme *sc, s7_pointer args)
  23759. {
  23760. #define H_open_input_string "(open-input-string str) opens an input port reading str"
  23761. #define Q_open_input_string s7_make_signature(sc, 2, sc->is_input_port_symbol, sc->is_string_symbol)
  23762. s7_pointer input_string, port;
  23763. input_string = car(args);
  23764. if (!is_string(input_string))
  23765. method_or_bust(sc, input_string, sc->open_input_string_symbol, args, T_STRING, 0);
  23766. port = open_and_protect_input_string(sc, input_string);
  23767. return(port);
  23768. }
  23769. #define FORMAT_PORT_LENGTH 128
  23770. /* the large majority (> 99% in my tests) of the output strings have less than 128 chars when the port is finally closed
  23771. * 256 is slightly slower (the calloc time below dominates the realloc time in string_write_string)
  23772. * 64 is much slower (realloc dominates)
  23773. */
  23774. static s7_pointer open_output_string(s7_scheme *sc, int len)
  23775. {
  23776. s7_pointer x;
  23777. new_cell(sc, x, T_OUTPUT_PORT);
  23778. port_port(x) = alloc_port(sc);
  23779. port_type(x) = STRING_PORT;
  23780. port_is_closed(x) = false;
  23781. port_data_size(x) = len;
  23782. port_data(x) = (unsigned char *)malloc(len * sizeof(unsigned char)); /* was +8? */
  23783. port_data(x)[0] = '\0'; /* in case s7_get_output_string before any output */
  23784. port_position(x) = 0;
  23785. port_needs_free(x) = true;
  23786. port_read_character(x) = output_read_char;
  23787. port_read_line(x) = output_read_line;
  23788. port_display(x) = string_display;
  23789. port_write_character(x) = string_write_char;
  23790. port_write_string(x) = string_write_string;
  23791. add_output_port(sc, x);
  23792. return(x);
  23793. }
  23794. s7_pointer s7_open_output_string(s7_scheme *sc)
  23795. {
  23796. return(open_output_string(sc, sc->initial_string_port_length));
  23797. }
  23798. static s7_pointer g_open_output_string(s7_scheme *sc, s7_pointer args)
  23799. {
  23800. #define H_open_output_string "(open-output-string) opens an output string port"
  23801. #define Q_open_output_string s7_make_signature(sc, 1, sc->is_output_port_symbol)
  23802. return(s7_open_output_string(sc));
  23803. }
  23804. const char *s7_get_output_string(s7_scheme *sc, s7_pointer p)
  23805. {
  23806. port_data(p)[port_position(p)] = '\0';
  23807. return((const char *)port_data(p));
  23808. }
  23809. static s7_pointer g_get_output_string(s7_scheme *sc, s7_pointer args)
  23810. {
  23811. #define H_get_output_string "(get-output-string port clear-port) returns the output accumulated in port. \
  23812. If the optional 'clear-port' is #t, the current string is flushed."
  23813. #define Q_get_output_string s7_make_signature(sc, 3, sc->is_string_symbol, sc->is_output_port_symbol, sc->is_boolean_symbol)
  23814. s7_pointer p, result;
  23815. bool clear_port = false;
  23816. if (is_pair(cdr(args)))
  23817. {
  23818. p = cadr(args);
  23819. if (!s7_is_boolean(p))
  23820. return(wrong_type_argument(sc, sc->get_output_string_symbol, 2, p, T_BOOLEAN));
  23821. clear_port = (p == sc->T);
  23822. }
  23823. p = car(args);
  23824. if ((!is_output_port(p)) ||
  23825. (!is_string_port(p)))
  23826. {
  23827. if (p == sc->F) return(make_empty_string(sc, 0, 0));
  23828. method_or_bust_with_type(sc, p, sc->get_output_string_symbol, args, make_string_wrapper(sc, "an output string port"), 0);
  23829. }
  23830. if (port_is_closed(p))
  23831. return(simple_wrong_type_argument_with_type(sc, sc->get_output_string_symbol, p, make_string_wrapper(sc, "an active (open) string port")));
  23832. result = s7_make_string_with_length(sc, (const char *)port_data(p), port_position(p));
  23833. if (clear_port)
  23834. {
  23835. port_position(p) = 0;
  23836. port_data(p)[0] = '\0';
  23837. }
  23838. return(result);
  23839. }
  23840. s7_pointer s7_open_input_function(s7_scheme *sc, s7_pointer (*function)(s7_scheme *sc, s7_read_t read_choice, s7_pointer port))
  23841. {
  23842. s7_pointer x;
  23843. new_cell(sc, x, T_INPUT_PORT);
  23844. port_port(x) = alloc_port(sc);
  23845. port_type(x) = FUNCTION_PORT;
  23846. port_is_closed(x) = false;
  23847. port_original_input_string(x) = sc->nil;
  23848. port_needs_free(x) = false;
  23849. port_input_function(x) = function;
  23850. port_read_character(x) = function_read_char;
  23851. port_read_line(x) = function_read_line;
  23852. port_display(x) = input_display;
  23853. port_write_character(x) = input_write_char;
  23854. port_write_string(x) = input_write_string;
  23855. add_input_port(sc, x);
  23856. return(x);
  23857. }
  23858. s7_pointer s7_open_output_function(s7_scheme *sc, void (*function)(s7_scheme *sc, unsigned char c, s7_pointer port))
  23859. {
  23860. s7_pointer x;
  23861. new_cell(sc, x, T_OUTPUT_PORT);
  23862. port_port(x) = alloc_port(sc);
  23863. port_type(x) = FUNCTION_PORT;
  23864. port_data(x) = NULL;
  23865. port_is_closed(x) = false;
  23866. port_needs_free(x) = false;
  23867. port_output_function(x) = function;
  23868. port_read_character(x) = output_read_char;
  23869. port_read_line(x) = output_read_line;
  23870. port_display(x) = function_display;
  23871. port_write_character(x) = function_write_char;
  23872. port_write_string(x) = function_write_string;
  23873. add_output_port(sc, x);
  23874. return(x);
  23875. }
  23876. static void push_input_port(s7_scheme *sc, s7_pointer new_port)
  23877. {
  23878. sc->temp6 = sc->input_port;
  23879. sc->input_port = new_port;
  23880. sc->input_port_stack = cons(sc, sc->temp6, sc->input_port_stack);
  23881. sc->temp6 = sc->nil;
  23882. }
  23883. static void pop_input_port(s7_scheme *sc)
  23884. {
  23885. if (is_pair(sc->input_port_stack))
  23886. {
  23887. s7_pointer nxt;
  23888. sc->input_port = car(sc->input_port_stack);
  23889. nxt = cdr(sc->input_port_stack);
  23890. /* is this safe? */
  23891. free_cell(sc, sc->input_port_stack);
  23892. sc->input_port_stack = nxt;
  23893. }
  23894. else sc->input_port = sc->standard_input;
  23895. }
  23896. static int inchar(s7_pointer pt)
  23897. {
  23898. int c;
  23899. if (is_file_port(pt))
  23900. c = fgetc(port_file(pt)); /* not unsigned char! -- could be EOF */
  23901. else
  23902. {
  23903. if (port_data_size(pt) <= port_position(pt))
  23904. return(EOF);
  23905. c = (unsigned char)port_data(pt)[port_position(pt)++];
  23906. }
  23907. if (c == '\n')
  23908. port_line_number(pt)++;
  23909. return(c);
  23910. }
  23911. static void backchar(char c, s7_pointer pt)
  23912. {
  23913. if (c == '\n')
  23914. port_line_number(pt)--;
  23915. if (is_file_port(pt))
  23916. ungetc(c, port_file(pt));
  23917. else
  23918. {
  23919. if (port_position(pt) > 0)
  23920. port_position(pt)--;
  23921. }
  23922. }
  23923. int s7_read_char(s7_scheme *sc, s7_pointer port)
  23924. {
  23925. /* needs to be int return value so EOF=-1, but not 255 */
  23926. return(port_read_character(port)(sc, port));
  23927. }
  23928. int s7_peek_char(s7_scheme *sc, s7_pointer port)
  23929. {
  23930. int c; /* needs to be an int so EOF=-1, but not 255 */
  23931. c = port_read_character(port)(sc, port);
  23932. if (c != EOF)
  23933. backchar(c, port);
  23934. return(c);
  23935. }
  23936. void s7_write_char(s7_scheme *sc, int c, s7_pointer pt)
  23937. {
  23938. if (pt != sc->F)
  23939. port_write_character(pt)(sc, c, pt);
  23940. }
  23941. static s7_pointer input_port_if_not_loading(s7_scheme *sc)
  23942. {
  23943. s7_pointer port;
  23944. port = sc->input_port;
  23945. if (is_loader_port(port)) /* this flag is turned off by the reader macros, so we aren't in that context */
  23946. {
  23947. int c;
  23948. c = port_read_white_space(port)(sc, port);
  23949. if (c > 0) /* we can get either EOF or NULL at the end */
  23950. {
  23951. backchar(c, port);
  23952. return(NULL);
  23953. }
  23954. return(sc->standard_input);
  23955. }
  23956. return(port);
  23957. }
  23958. static s7_pointer g_read_char(s7_scheme *sc, s7_pointer args)
  23959. {
  23960. #define H_read_char "(read-char (port (current-input-port))) returns the next character in the input port"
  23961. #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)
  23962. s7_pointer port;
  23963. if (is_not_null(args))
  23964. port = car(args);
  23965. else
  23966. {
  23967. port = input_port_if_not_loading(sc);
  23968. if (!port) return(sc->eof_object);
  23969. }
  23970. if (!is_input_port(port))
  23971. method_or_bust_with_type(sc, port, sc->read_char_symbol, args, an_input_port_string, 0);
  23972. return(chars[port_read_character(port)(sc, port)]);
  23973. }
  23974. static s7_pointer read_char_0, read_char_1;
  23975. static s7_pointer g_read_char_0(s7_scheme *sc, s7_pointer args)
  23976. {
  23977. s7_pointer port;
  23978. port = input_port_if_not_loading(sc);
  23979. if (port)
  23980. return(chars[port_read_character(port)(sc, port)]);
  23981. return(sc->eof_object);
  23982. }
  23983. static s7_pointer g_read_char_1(s7_scheme *sc, s7_pointer args)
  23984. {
  23985. s7_pointer port;
  23986. port = car(args);
  23987. if (!is_input_port(port))
  23988. method_or_bust_with_type(sc, port, sc->read_char_symbol, args, an_input_port_string, 0);
  23989. return(chars[port_read_character(port)(sc, port)]);
  23990. }
  23991. static s7_pointer c_read_char(s7_scheme *sc)
  23992. {
  23993. int c;
  23994. s7_pointer port;
  23995. port = input_port_if_not_loading(sc);
  23996. if (!port) return(sc->eof_object);
  23997. c = port_read_character(port)(sc, port);
  23998. if (c == EOF)
  23999. return(sc->eof_object);
  24000. return(chars[c]);
  24001. }
  24002. PF_0(read_char, c_read_char)
  24003. static s7_pointer read_char_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  24004. {
  24005. if (args == 0)
  24006. return(read_char_0);
  24007. if (args == 1)
  24008. return(read_char_1);
  24009. return(f);
  24010. }
  24011. static s7_pointer g_write_char(s7_scheme *sc, s7_pointer args)
  24012. {
  24013. #define H_write_char "(write-char char (port (current-output-port))) writes char to the output port"
  24014. #define Q_write_char s7_make_signature(sc, 3, sc->is_char_symbol, sc->is_char_symbol, sc->is_output_port_symbol)
  24015. s7_pointer port, chr;
  24016. chr = car(args);
  24017. if (!s7_is_character(chr))
  24018. method_or_bust(sc, chr, sc->write_char_symbol, args, T_CHARACTER, 1);
  24019. if (is_pair(cdr(args)))
  24020. port = cadr(args);
  24021. else port = sc->output_port;
  24022. if (port == sc->F) return(chr);
  24023. if (!is_output_port(port))
  24024. method_or_bust_with_type(sc, port, sc->write_char_symbol, args, an_output_port_string, 2);
  24025. port_write_character(port)(sc, s7_character(chr), port);
  24026. return(chr);
  24027. }
  24028. static s7_pointer c_write_char(s7_scheme *sc, s7_pointer chr)
  24029. {
  24030. if (!s7_is_character(chr))
  24031. method_or_bust(sc, chr, sc->write_char_symbol, set_plist_1(sc, chr), T_CHARACTER, 1);
  24032. if (sc->output_port == sc->F) return(chr);
  24033. port_write_character(sc->output_port)(sc, s7_character(chr), sc->output_port);
  24034. return(chr);
  24035. }
  24036. static s7_pointer write_char_1;
  24037. static s7_pointer g_write_char_1(s7_scheme *sc, s7_pointer args) {return(c_write_char(sc, car(args)));}
  24038. PF_TO_PF(write_char, c_write_char)
  24039. static s7_pointer write_char_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  24040. {
  24041. if (args == 1)
  24042. return(write_char_1);
  24043. return(f);
  24044. }
  24045. /* (with-output-to-string (lambda () (write-char #\space))) -> " "
  24046. * (with-output-to-string (lambda () (write #\space))) -> "#\\space"
  24047. * (with-output-to-string (lambda () (display #\space))) -> " "
  24048. * is this correct? It's what Guile does. write-char is actually display-char.
  24049. */
  24050. static s7_pointer g_peek_char(s7_scheme *sc, s7_pointer args)
  24051. {
  24052. #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"
  24053. #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)
  24054. s7_pointer port;
  24055. if (is_not_null(args))
  24056. port = car(args);
  24057. else port = sc->input_port;
  24058. if (!is_input_port(port))
  24059. method_or_bust_with_type(sc, port, sc->peek_char_symbol, args, an_input_port_string, 0);
  24060. if (port_is_closed(port))
  24061. return(simple_wrong_type_argument_with_type(sc, sc->peek_char_symbol, port, an_open_port_string));
  24062. if (is_function_port(port))
  24063. return((*(port_input_function(port)))(sc, S7_PEEK_CHAR, port));
  24064. return(chars[s7_peek_char(sc, port)]);
  24065. }
  24066. static s7_pointer c_peek_char(s7_scheme *sc) {return(chars[s7_peek_char(sc, sc->input_port)]);}
  24067. PF_0(peek_char, c_peek_char)
  24068. static s7_pointer g_read_byte(s7_scheme *sc, s7_pointer args)
  24069. {
  24070. #define H_read_byte "(read-byte (port (current-input-port))): reads a byte from the input port"
  24071. #define Q_read_byte s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_eof_object_symbol), sc->is_input_port_symbol)
  24072. s7_pointer port;
  24073. int c;
  24074. if (is_not_null(args))
  24075. port = car(args);
  24076. else
  24077. {
  24078. port = input_port_if_not_loading(sc);
  24079. if (!port) return(sc->eof_object);
  24080. }
  24081. if (!is_input_port(port))
  24082. method_or_bust_with_type(sc, port, sc->read_byte_symbol, args, an_input_port_string, 0);
  24083. c = port_read_character(port)(sc, port);
  24084. if (c == EOF)
  24085. return(sc->eof_object);
  24086. return(small_int(c));
  24087. }
  24088. static s7_pointer c_read_byte(s7_scheme *sc)
  24089. {
  24090. int c;
  24091. s7_pointer port;
  24092. port = input_port_if_not_loading(sc);
  24093. if (!port) return(sc->eof_object);
  24094. c = port_read_character(port)(sc, port);
  24095. if (c == EOF)
  24096. return(sc->eof_object);
  24097. return(small_int(c));
  24098. }
  24099. PF_0(read_byte, c_read_byte)
  24100. static s7_pointer g_write_byte(s7_scheme *sc, s7_pointer args)
  24101. {
  24102. #define H_write_byte "(write-byte byte (port (current-output-port))): writes byte to the output port"
  24103. #define Q_write_byte s7_make_signature(sc, 3, sc->is_integer_symbol, sc->is_integer_symbol, sc->is_output_port_symbol)
  24104. s7_pointer port, b;
  24105. s7_int val;
  24106. b = car(args);
  24107. if (!s7_is_integer(b))
  24108. method_or_bust(sc, car(args), sc->write_byte_symbol, args, T_INTEGER, 1);
  24109. val = s7_integer(b);
  24110. if ((val < 0) || (val > 255)) /* need to check this before port==#f, else (write-byte most-positive-fixnum #f) is not an error */
  24111. return(wrong_type_argument_with_type(sc, sc->write_byte_symbol, 1, b, an_unsigned_byte_string));
  24112. if (is_pair(cdr(args)))
  24113. port = cadr(args);
  24114. else port = sc->output_port;
  24115. if (!is_output_port(port))
  24116. {
  24117. if (port == sc->F) return(car(args));
  24118. method_or_bust_with_type(sc, port, sc->write_byte_symbol, args, an_output_port_string, 0);
  24119. }
  24120. s7_write_char(sc, (int)(s7_integer(b)), port);
  24121. return(b);
  24122. }
  24123. static s7_int c_write_byte(s7_scheme *sc, s7_int x)
  24124. {
  24125. if ((x < 0) || (x > 255))
  24126. wrong_type_argument_with_type(sc, sc->write_byte_symbol, 1, make_integer(sc, x), an_unsigned_byte_string);
  24127. s7_write_char(sc, (int)x, sc->output_port);
  24128. return(x);
  24129. }
  24130. IF_TO_IF(write_byte, c_write_byte)
  24131. static s7_pointer g_read_line(s7_scheme *sc, s7_pointer args)
  24132. {
  24133. #define H_read_line "(read-line port (with-eol #f)) returns the next line from port, or #<eof>.\
  24134. If 'with-eol' is not #f, read-line includes the trailing end-of-line character."
  24135. #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)
  24136. s7_pointer port;
  24137. bool with_eol = false;
  24138. if (is_not_null(args))
  24139. {
  24140. port = car(args);
  24141. if (!is_input_port(port))
  24142. method_or_bust_with_type(sc, port, sc->read_line_symbol, args, an_input_port_string, 1);
  24143. if (is_not_null(cdr(args)))
  24144. with_eol = (cadr(args) != sc->F);
  24145. }
  24146. else
  24147. {
  24148. port = input_port_if_not_loading(sc);
  24149. if (!port) return(sc->eof_object);
  24150. }
  24151. return(port_read_line(port)(sc, port, with_eol, true));
  24152. }
  24153. static s7_pointer c_read_line(s7_scheme *sc) {return(g_read_line(sc, sc->nil));}
  24154. PF_0(read_line, c_read_line)
  24155. static s7_pointer read_line_uncopied;
  24156. static s7_pointer g_read_line_uncopied(s7_scheme *sc, s7_pointer args)
  24157. {
  24158. s7_pointer port;
  24159. bool with_eol = false;
  24160. port = car(args);
  24161. if (!is_input_port(port))
  24162. return(g_read_line(sc, args));
  24163. if (is_not_null(cdr(args)))
  24164. with_eol = (cadr(args) != sc->F);
  24165. return(port_read_line(port)(sc, port, with_eol, false));
  24166. }
  24167. static s7_pointer c_read_string(s7_scheme *sc, s7_int chars, s7_pointer port)
  24168. {
  24169. s7_pointer s;
  24170. s7_int i;
  24171. unsigned char *str;
  24172. if (chars < 0)
  24173. return(wrong_type_argument_with_type(sc, sc->read_string_symbol, 1, make_integer(sc, chars), a_non_negative_integer_string));
  24174. if (chars > sc->max_string_length)
  24175. return(out_of_range(sc, sc->read_string_symbol, small_int(1), make_integer(sc, chars), its_too_large_string));
  24176. if (!port) return(sc->eof_object);
  24177. if (!is_input_port(port))
  24178. method_or_bust_with_type(sc, port, sc->read_string_symbol, list_2(sc, make_integer(sc, chars), port), an_input_port_string, 2);
  24179. if (chars == 0)
  24180. return(make_empty_string(sc, 0, 0));
  24181. s = make_empty_string(sc, chars, 0);
  24182. str = (unsigned char *)string_value(s);
  24183. for (i = 0; i < chars; i++)
  24184. {
  24185. int c;
  24186. c = port_read_character(port)(sc, port);
  24187. if (c == EOF)
  24188. {
  24189. if (i == 0)
  24190. return(sc->eof_object);
  24191. string_length(s) = i;
  24192. return(s);
  24193. }
  24194. str[i] = (unsigned char)c;
  24195. }
  24196. return(s);
  24197. }
  24198. static s7_pointer g_read_string(s7_scheme *sc, s7_pointer args)
  24199. {
  24200. #define H_read_string "(read-string k port) reads k characters from port into a new string and returns it."
  24201. #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)
  24202. s7_pointer k, port;
  24203. k = car(args);
  24204. if (!s7_is_integer(k))
  24205. method_or_bust(sc, k, sc->read_string_symbol, args, T_INTEGER, 1);
  24206. if (!is_null(cdr(args)))
  24207. port = cadr(args);
  24208. else port = input_port_if_not_loading(sc); /* port checked (for NULL) in c_read_string */
  24209. return(c_read_string(sc, s7_integer(k), port));
  24210. }
  24211. static s7_pointer c_read_string_1(s7_scheme *sc, s7_int chars) {return(c_read_string(sc, chars, input_port_if_not_loading(sc)));}
  24212. IF_TO_PF(read_string, c_read_string_1)
  24213. #define declare_jump_info() bool old_longjmp; int old_jump_loc, jump_loc; jmp_buf old_goto_start
  24214. #define store_jump_info(Sc) \
  24215. do { \
  24216. old_longjmp = Sc->longjmp_ok; \
  24217. old_jump_loc = Sc->setjmp_loc; \
  24218. memcpy((void *)old_goto_start, (void *)(Sc->goto_start), sizeof(jmp_buf));\
  24219. } while (0)
  24220. #define restore_jump_info(Sc) \
  24221. do { \
  24222. Sc->longjmp_ok = old_longjmp; \
  24223. Sc->setjmp_loc = old_jump_loc; \
  24224. memcpy((void *)(Sc->goto_start), (void *)old_goto_start, sizeof(jmp_buf));\
  24225. if ((jump_loc == ERROR_JUMP) &&\
  24226. (sc->longjmp_ok))\
  24227. longjmp(sc->goto_start, ERROR_JUMP);\
  24228. } while (0)
  24229. #define set_jump_info(Sc, Tag) \
  24230. do { \
  24231. sc->longjmp_ok = true; \
  24232. sc->setjmp_loc = Tag; \
  24233. jump_loc = setjmp(sc->goto_start); \
  24234. } while (0)
  24235. s7_pointer s7_read(s7_scheme *sc, s7_pointer port)
  24236. {
  24237. if (is_input_port(port))
  24238. {
  24239. s7_pointer old_envir;
  24240. declare_jump_info();
  24241. old_envir = sc->envir;
  24242. sc->envir = sc->nil;
  24243. push_input_port(sc, port);
  24244. store_jump_info(sc);
  24245. set_jump_info(sc, READ_SET_JUMP);
  24246. if (jump_loc != NO_JUMP)
  24247. {
  24248. if (jump_loc != ERROR_JUMP)
  24249. eval(sc, sc->op);
  24250. }
  24251. else
  24252. {
  24253. push_stack(sc, OP_BARRIER, port, sc->nil);
  24254. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  24255. eval(sc, OP_READ_INTERNAL);
  24256. if (sc->tok == TOKEN_EOF)
  24257. sc->value = sc->eof_object;
  24258. if ((sc->op == OP_EVAL_DONE) &&
  24259. (stack_op(sc->stack, s7_stack_top(sc) - 1) == OP_BARRIER))
  24260. pop_stack(sc);
  24261. }
  24262. pop_input_port(sc);
  24263. sc->envir = old_envir;
  24264. restore_jump_info(sc);
  24265. return(sc->value);
  24266. }
  24267. return(simple_wrong_type_argument_with_type(sc, sc->read_symbol, port, an_input_port_string));
  24268. }
  24269. static s7_pointer g_read(s7_scheme *sc, s7_pointer args)
  24270. {
  24271. /* would it be useful to add an environment arg here? (just set sc->envir at the end?)
  24272. * except for expansions, nothing is evaluated at read time, unless...
  24273. * say we set up a dot reader:
  24274. * (set! *#readers* (cons (cons #\. (lambda (str) (if (string=? str ".") (eval (read)) #f))) *#readers*))
  24275. * then
  24276. * (call-with-input-string "(+ 1 #.(+ 1 hiho))" (lambda (p) (read p)))
  24277. * evaluates hiho in the rootlet, but how to pass the env to the inner eval or read?
  24278. * (eval, eval-string and load already have an env arg)
  24279. */
  24280. #define H_read "(read (port (current-input-port))) returns the next object in the input port, or #<eof> at the end"
  24281. #define Q_read s7_make_signature(sc, 2, sc->T, sc->is_input_port_symbol)
  24282. s7_pointer port;
  24283. if (is_not_null(args))
  24284. port = car(args);
  24285. else
  24286. {
  24287. port = input_port_if_not_loading(sc);
  24288. if (!port) return(sc->eof_object);
  24289. }
  24290. if (!is_input_port(port))
  24291. method_or_bust_with_type(sc, port, sc->read_symbol, args, an_input_port_string, 0);
  24292. if (is_function_port(port))
  24293. return((*(port_input_function(port)))(sc, S7_READ, port));
  24294. if ((is_string_port(port)) &&
  24295. (port_data_size(port) <= port_position(port)))
  24296. return(sc->eof_object);
  24297. push_input_port(sc, port);
  24298. push_stack(sc, OP_READ_DONE, sc->nil, sc->nil); /* this stops the internal read process so we only get one form */
  24299. push_stack(sc, OP_READ_INTERNAL, sc->nil, sc->nil);
  24300. return(port);
  24301. }
  24302. static s7_pointer c_read(s7_scheme *sc) {return(g_read(sc, sc->nil));}
  24303. PF_0(read, c_read)
  24304. /* -------------------------------- load -------------------------------- */
  24305. static FILE *search_load_path(s7_scheme *sc, const char *name)
  24306. {
  24307. int i, len;
  24308. s7_pointer lst;
  24309. lst = s7_load_path(sc);
  24310. len = s7_list_length(sc, lst);
  24311. for (i = 0; i < len; i++)
  24312. {
  24313. const char *new_dir;
  24314. new_dir = string_value(s7_list_ref(sc, lst, i));
  24315. if (new_dir)
  24316. {
  24317. FILE *fp;
  24318. snprintf(sc->tmpbuf, TMPBUF_SIZE, "%s/%s", new_dir, name);
  24319. fp = fopen(sc->tmpbuf, "r");
  24320. if (fp) return(fp);
  24321. }
  24322. }
  24323. return(NULL);
  24324. }
  24325. s7_pointer s7_load_with_environment(s7_scheme *sc, const char *filename, s7_pointer e)
  24326. {
  24327. s7_pointer port;
  24328. FILE *fp;
  24329. char *new_filename = NULL;
  24330. declare_jump_info();
  24331. fp = fopen(filename, "r");
  24332. if (!fp)
  24333. {
  24334. fp = search_load_path(sc, filename);
  24335. if (fp)
  24336. new_filename = copy_string(sc->tmpbuf); /* (require libc.scm) for example needs the directory for cload in some cases */
  24337. }
  24338. if (!fp)
  24339. return(file_error(sc, "load", "can't open", filename));
  24340. if (hook_has_functions(sc->load_hook))
  24341. s7_call(sc, sc->load_hook, list_1(sc, sc->temp4 = s7_make_string(sc, filename)));
  24342. port = read_file(sc, fp, (new_filename) ? (const char *)new_filename : filename, -1, "load"); /* -1 means always read its contents into a local string */
  24343. port_file_number(port) = remember_file_name(sc, filename);
  24344. if (new_filename) free(new_filename);
  24345. set_loader_port(port);
  24346. push_input_port(sc, port);
  24347. /* it's possible to call this recursively (s7_load is Xen_load_file which can be invoked via s7_call)
  24348. * but in that case, we actually want it to behave like g_load and continue the evaluation upon completion
  24349. */
  24350. sc->envir = e;
  24351. push_stack(sc, OP_LOAD_RETURN_IF_EOF, port, sc->code);
  24352. store_jump_info(sc);
  24353. set_jump_info(sc, LOAD_SET_JUMP);
  24354. if (jump_loc != NO_JUMP)
  24355. {
  24356. if (jump_loc != ERROR_JUMP)
  24357. eval(sc, sc->op);
  24358. }
  24359. else eval(sc, OP_READ_INTERNAL);
  24360. pop_input_port(sc);
  24361. if (is_input_port(port))
  24362. s7_close_input_port(sc, port);
  24363. restore_jump_info(sc);
  24364. if (is_multiple_value(sc->value))
  24365. sc->value = splice_in_values(sc, multiple_value(sc->value));
  24366. return(sc->value);
  24367. }
  24368. s7_pointer s7_load(s7_scheme *sc, const char *filename)
  24369. {
  24370. return(s7_load_with_environment(sc, filename, sc->nil));
  24371. }
  24372. #if WITH_C_LOADER
  24373. #include <dlfcn.h>
  24374. static char *full_filename(const char *filename)
  24375. {
  24376. int len;
  24377. char *pwd, *rtn;
  24378. pwd = getcwd(NULL, 0); /* docs say this means it will return a new string of the right size */
  24379. len = safe_strlen(pwd) + safe_strlen(filename) + 8;
  24380. rtn = (char *)malloc(len * sizeof(char));
  24381. if (pwd)
  24382. {
  24383. snprintf(rtn, len, "%s/%s", pwd, filename);
  24384. free(pwd);
  24385. }
  24386. else snprintf(rtn, len, "%s", filename);
  24387. return(rtn);
  24388. }
  24389. #endif
  24390. static s7_pointer g_load(s7_scheme *sc, s7_pointer args)
  24391. {
  24392. #define H_load "(load file (env (rootlet))) loads the scheme file 'file'. The 'env' argument \
  24393. defaults to the rootlet. To load into the current environment instead, pass (curlet)."
  24394. #define Q_load s7_make_signature(sc, 3, sc->values_symbol, sc->is_string_symbol, sc->is_let_symbol)
  24395. FILE *fp = NULL;
  24396. s7_pointer name, port;
  24397. const char *fname;
  24398. name = car(args);
  24399. if (!is_string(name))
  24400. method_or_bust(sc, name, sc->load_symbol, args, T_STRING, 1);
  24401. if (is_not_null(cdr(args)))
  24402. {
  24403. s7_pointer e;
  24404. e = cadr(args);
  24405. if (!is_let(e))
  24406. return(wrong_type_argument_with_type(sc, sc->load_symbol, 2, e, a_let_string));
  24407. if (e == sc->rootlet)
  24408. sc->envir = sc->nil;
  24409. else sc->envir = e;
  24410. }
  24411. else sc->envir = sc->nil;
  24412. fname = string_value(name);
  24413. if ((!fname) || (!(*fname))) /* fopen("", "r") returns a file pointer?? */
  24414. return(s7_error(sc, sc->out_of_range_symbol, set_elist_2(sc, make_string_wrapper(sc, "load's first argument, ~S, should be a filename"), name)));
  24415. if (is_directory(fname))
  24416. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "load argument, ~S, is a directory"), name)));
  24417. #if WITH_C_LOADER
  24418. /* if fname ends in .so, try loading it as a c shared object
  24419. * (load "/home/bil/cl/m_j0.so" (inlet (cons 'init_func 'init_m_j0)))
  24420. */
  24421. {
  24422. int fname_len;
  24423. fname_len = safe_strlen(fname);
  24424. if ((fname_len > 3) &&
  24425. (is_pair(cdr(args))) &&
  24426. (local_strcmp((const char *)(fname + (fname_len - 3)), ".so")))
  24427. {
  24428. s7_pointer init;
  24429. init = let_ref_1(sc, sc->envir, s7_make_symbol(sc, "init_func"));
  24430. if (is_symbol(init))
  24431. {
  24432. void *library;
  24433. char *pwd_name = NULL;
  24434. if (fname[0] != '/')
  24435. pwd_name = full_filename(fname); /* this is necessary, at least in Linux -- we can't blithely dlopen whatever is passed to us */
  24436. library = dlopen((pwd_name) ? pwd_name : fname, RTLD_NOW);
  24437. if (library)
  24438. {
  24439. const char *init_name = NULL;
  24440. void *init_func;
  24441. init_name = symbol_name(init);
  24442. init_func = dlsym(library, init_name);
  24443. if (init_func)
  24444. {
  24445. typedef void *(*dl_func)(s7_scheme *sc);
  24446. ((dl_func)init_func)(sc);
  24447. if (pwd_name) free(pwd_name);
  24448. return(sc->T);
  24449. }
  24450. else
  24451. {
  24452. s7_warn(sc, 512, "loaded %s, but can't find %s (%s)?\n", fname, init_name, dlerror());
  24453. dlclose(library);
  24454. }
  24455. }
  24456. else s7_warn(sc, 512, "load %s failed: %s\n", (pwd_name) ? pwd_name : fname, dlerror());
  24457. if (pwd_name) free(pwd_name);
  24458. }
  24459. else s7_warn(sc, 512, "can't load %s: no init function\n", fname);
  24460. return(sc->F);
  24461. }
  24462. }
  24463. #endif
  24464. fp = fopen(fname, "r");
  24465. #if WITH_GCC
  24466. if (!fp)
  24467. {
  24468. /* catch one special case, "~/..." since it causes 99.9% of the "can't load ..." errors */
  24469. if ((fname[0] == '~') &&
  24470. (fname[1] == '/'))
  24471. {
  24472. char *home;
  24473. home = getenv("HOME");
  24474. if (home)
  24475. {
  24476. char *filename;
  24477. int len;
  24478. len = safe_strlen(fname) + safe_strlen(home) + 1;
  24479. tmpbuf_malloc(filename, len);
  24480. snprintf(filename, len, "%s%s", home, (char *)(fname + 1));
  24481. fp = fopen(filename, "r");
  24482. tmpbuf_free(filename, len);
  24483. }
  24484. }
  24485. }
  24486. #endif
  24487. if (!fp)
  24488. {
  24489. fp = search_load_path(sc, fname);
  24490. if (!fp)
  24491. return(file_error(sc, "load", "can't open", fname));
  24492. }
  24493. port = read_file(sc, fp, fname, -1, "load");
  24494. port_file_number(port) = remember_file_name(sc, fname);
  24495. set_loader_port(port);
  24496. push_input_port(sc, port);
  24497. push_stack(sc, OP_LOAD_CLOSE_AND_POP_IF_EOF, sc->nil, sc->nil); /* was pushing args and code, but I don't think they're used later */
  24498. push_stack(sc, OP_READ_INTERNAL, sc->nil, sc->nil);
  24499. /* now we've opened and moved to the file to be loaded, and set up the stack to return
  24500. * to where we were. Call *load-hook* if it is a procedure.
  24501. */
  24502. if (hook_has_functions(sc->load_hook))
  24503. s7_apply_function(sc, sc->load_hook, list_1(sc, sc->temp4 = s7_make_string(sc, fname)));
  24504. return(sc->unspecified);
  24505. }
  24506. s7_pointer s7_load_path(s7_scheme *sc)
  24507. {
  24508. return(s7_symbol_value(sc, sc->load_path_symbol));
  24509. }
  24510. s7_pointer s7_add_to_load_path(s7_scheme *sc, const char *dir)
  24511. {
  24512. s7_symbol_set_value(sc,
  24513. sc->load_path_symbol,
  24514. cons(sc,
  24515. s7_make_string(sc, dir),
  24516. s7_symbol_value(sc, sc->load_path_symbol)));
  24517. return(s7_symbol_value(sc, sc->load_path_symbol));
  24518. }
  24519. static s7_pointer g_load_path_set(s7_scheme *sc, s7_pointer args)
  24520. {
  24521. /* new value must be either () or a proper list of strings */
  24522. if (is_null(cadr(args))) return(cadr(args));
  24523. if (is_pair(cadr(args)))
  24524. {
  24525. s7_pointer x;
  24526. for (x = cadr(args); is_pair(x); x = cdr(x))
  24527. if (!is_string(car(x)))
  24528. return(sc->error_symbol);
  24529. if (is_null(x))
  24530. return(cadr(args));
  24531. }
  24532. return(sc->error_symbol);
  24533. }
  24534. static s7_pointer g_cload_directory_set(s7_scheme *sc, s7_pointer args)
  24535. {
  24536. s7_pointer cl_dir;
  24537. cl_dir = cadr(args);
  24538. if (!is_string(cl_dir))
  24539. return(sc->error_symbol);
  24540. s7_symbol_set_value(sc, sc->cload_directory_symbol, cl_dir);
  24541. if (safe_strlen(string_value(cl_dir)) > 0)
  24542. s7_add_to_load_path(sc, (const char *)(string_value(cl_dir)));
  24543. return(cl_dir);
  24544. }
  24545. /* ---------------- autoload ---------------- */
  24546. void s7_autoload_set_names(s7_scheme *sc, const char **names, int size)
  24547. {
  24548. /* the idea here is that by sticking to string constants we can handle 90% of the work at compile-time,
  24549. * with less start-up memory. Then eventually we'll add C libraries a la xg (gtk) as environments
  24550. * and every name in that library will come as an import once dlopen has picked up the library.
  24551. * So, hopefully, we can pre-declare as many names as we want from as many libraries as we want,
  24552. * without a bloated mess of a run-time image. And new libraries are easy to accommodate --
  24553. * add the names to be auto-exported to this list with the name of the scheme file that cloads
  24554. * the library and exports the given name. So, we'll need a separate such file for each library?
  24555. *
  24556. * the environment variable could use the library base name in *: *libm* or *libgtk*
  24557. * (*libm* 'j0)
  24558. * why not just predeclare these libraries? The caller could import what he wants via require.
  24559. * So the autoloader need only know which libraries, but this doesn't fit the current use of gtk in xg
  24560. * In fact, we only need to see *libm* -> libm.so etc, but we still need the arg/return types of each function, etc
  24561. * And libgtk is enormous -- seems too bad to tie-in everything via the FFI when we need less than 1% of it.
  24562. * Perhaps each module as an environment within the main one: ((*libgtk* *gtkwidget*) 'gtk_widget_new)?
  24563. * But that requires inside knowlege of the library, and changes without notice.
  24564. *
  24565. * Also we need to decide how to handle name collisions (by order of autoload lib setup)
  24566. * And (lastly?) how to handle different library versions?
  24567. *
  24568. *
  24569. * so autoload known libs here in s7 so we're indepentdent of snd
  24570. * (currently these are included in make-index.scm[line 575] -> snd-xref.c)
  24571. * for each module, include an env in the lib env (*libgtk* 'gtkwidget.h) or whatever that has the names in that header
  24572. * 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)
  24573. * for versions, include wrapper macro at end of each c-define choice
  24574. * in the xg case, there's no savings in delaying the defines
  24575. *
  24576. */
  24577. if (sc->autoload_names == NULL)
  24578. {
  24579. sc->autoload_names = (const char ***)calloc(INITIAL_AUTOLOAD_NAMES_SIZE, sizeof(const char **));
  24580. sc->autoload_names_sizes = (int *)calloc(INITIAL_AUTOLOAD_NAMES_SIZE, sizeof(int));
  24581. sc->autoloaded_already = (bool **)calloc(INITIAL_AUTOLOAD_NAMES_SIZE, sizeof(bool *));
  24582. sc->autoload_names_top = INITIAL_AUTOLOAD_NAMES_SIZE;
  24583. sc->autoload_names_loc = 0;
  24584. }
  24585. else
  24586. {
  24587. if (sc->autoload_names_loc >= sc->autoload_names_top)
  24588. {
  24589. int i;
  24590. sc->autoload_names_top *= 2;
  24591. sc->autoload_names = (const char ***)realloc(sc->autoload_names, sc->autoload_names_top * sizeof(const char **));
  24592. sc->autoload_names_sizes = (int *)realloc(sc->autoload_names_sizes, sc->autoload_names_top * sizeof(int));
  24593. sc->autoloaded_already = (bool **)realloc(sc->autoloaded_already, sc->autoload_names_top * sizeof(bool *));
  24594. for (i = sc->autoload_names_loc; i < sc->autoload_names_top; i++)
  24595. {
  24596. sc->autoload_names[i] = NULL;
  24597. sc->autoload_names_sizes[i] = 0;
  24598. sc->autoloaded_already[i] = NULL;
  24599. }
  24600. }
  24601. }
  24602. sc->autoload_names[sc->autoload_names_loc] = names;
  24603. sc->autoload_names_sizes[sc->autoload_names_loc] = size;
  24604. sc->autoloaded_already[sc->autoload_names_loc] = (bool *)calloc(size, sizeof(bool));
  24605. sc->autoload_names_loc++;
  24606. }
  24607. static const char *find_autoload_name(s7_scheme *sc, s7_pointer symbol, bool *already_loaded, bool loading)
  24608. {
  24609. int l = 0, pos = -1, lib, libs;
  24610. const char *name, *this_name;
  24611. name = symbol_name(symbol);
  24612. libs = sc->autoload_names_loc;
  24613. for (lib = 0; lib < libs; lib++)
  24614. {
  24615. const char **names;
  24616. int u;
  24617. u = sc->autoload_names_sizes[lib] - 1;
  24618. names = sc->autoload_names[lib];
  24619. while (true)
  24620. {
  24621. int comp;
  24622. if (u < l) break;
  24623. pos = (l + u) / 2;
  24624. this_name = names[pos * 2];
  24625. comp = strcmp(this_name, name);
  24626. if (comp == 0)
  24627. {
  24628. *already_loaded = sc->autoloaded_already[lib][pos];
  24629. if (loading) sc->autoloaded_already[lib][pos] = true;
  24630. return(names[pos * 2 + 1]); /* file name given func name */
  24631. }
  24632. if (comp < 0)
  24633. l = pos + 1;
  24634. else u = pos - 1;
  24635. }
  24636. }
  24637. return(NULL);
  24638. }
  24639. s7_pointer s7_autoload(s7_scheme *sc, s7_pointer symbol, s7_pointer file_or_function)
  24640. {
  24641. /* add '(symbol . file) to s7's autoload table */
  24642. if (is_null(sc->autoload_table))
  24643. sc->autoload_table = s7_make_hash_table(sc, sc->default_hash_table_length);
  24644. s7_hash_table_set(sc, sc->autoload_table, symbol, file_or_function);
  24645. return(file_or_function);
  24646. }
  24647. static s7_pointer g_autoload(s7_scheme *sc, s7_pointer args)
  24648. {
  24649. #define H_autoload "(autoload symbol file-or-function) adds the symbol to its table of autoloadable symbols. \
  24650. If that symbol is encountered as an unbound variable, s7 either loads the file (following *load-path*), or calls \
  24651. the function. The function takes one argument, the calling environment. Presumably the symbol is defined \
  24652. in the file, or by the function."
  24653. #define Q_autoload s7_make_signature(sc, 3, sc->T, sc->is_symbol_symbol, sc->T)
  24654. s7_pointer sym, value;
  24655. sym = car(args);
  24656. if (is_string(sym))
  24657. {
  24658. if (string_length(sym) == 0) /* (autoload "" ...) */
  24659. return(s7_wrong_type_arg_error(sc, "autoload", 1, sym, "a symbol-name or a symbol"));
  24660. sym = make_symbol_with_length(sc, string_value(sym), string_length(sym));
  24661. }
  24662. if (!is_symbol(sym))
  24663. {
  24664. check_method(sc, sym, sc->autoload_symbol, args);
  24665. return(s7_wrong_type_arg_error(sc, "autoload", 1, sym, "a string (symbol-name) or a symbol"));
  24666. }
  24667. if (is_keyword(sym))
  24668. return(s7_wrong_type_arg_error(sc, "autoload", 1, sym, "a normal symbol (a keyword is never unbound)"));
  24669. value = cadr(args);
  24670. if (is_string(value))
  24671. return(s7_autoload(sc, sym, value));
  24672. if (((is_closure(value)) || (is_closure_star(value))) &&
  24673. (s7_is_aritable(sc, value, 1)))
  24674. return(s7_autoload(sc, sym, value));
  24675. check_method(sc, value, sc->autoload_symbol, args);
  24676. return(s7_wrong_type_arg_error(sc, "autoload", 2, value, "a string (file-name) or a thunk"));
  24677. }
  24678. static s7_pointer g_autoloader(s7_scheme *sc, s7_pointer args)
  24679. {
  24680. #define H_autoloader "(*autoload* sym) returns the autoload info for the symbol sym, or #f."
  24681. #define Q_autoloader s7_make_signature(sc, 2, sc->T, sc->is_symbol_symbol)
  24682. s7_pointer sym;
  24683. sym = car(args);
  24684. if (!is_symbol(sym))
  24685. {
  24686. check_method(sc, sym, sc->autoloader_symbol, args);
  24687. return(s7_wrong_type_arg_error(sc, "*autoload*", 1, sym, "a symbol"));
  24688. }
  24689. if (sc->autoload_names)
  24690. {
  24691. const char *file;
  24692. bool loaded = false;
  24693. file = find_autoload_name(sc, sym, &loaded, false);
  24694. if (file)
  24695. return(s7_make_string(sc, file));
  24696. }
  24697. if (is_hash_table(sc->autoload_table))
  24698. return(s7_hash_table_ref(sc, sc->autoload_table, sym));
  24699. return(sc->F);
  24700. }
  24701. static s7_pointer g_require(s7_scheme *sc, s7_pointer args)
  24702. {
  24703. #define H_require "(require . symbols) loads each file associated with each symbol if it has not been loaded already.\
  24704. The symbols refer to the argument to \"provide\"."
  24705. #define Q_require s7_make_circular_signature(sc, 1, 2, sc->T, sc->is_symbol_symbol)
  24706. s7_pointer p;
  24707. sc->temp5 = cons(sc, args, sc->temp5);
  24708. for (p = args; is_pair(p); p = cdr(p))
  24709. {
  24710. s7_pointer sym;
  24711. if (is_symbol(car(p)))
  24712. sym = car(p);
  24713. else
  24714. {
  24715. if ((is_pair(car(p))) &&
  24716. (caar(p) == sc->quote_symbol) &&
  24717. (is_symbol(cadar(p))))
  24718. sym = cadar(p);
  24719. else return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "require: ~S is not a symbol"), car(p))));
  24720. }
  24721. if (!is_slot(find_symbol(sc, sym)))
  24722. {
  24723. s7_pointer f;
  24724. f = g_autoloader(sc, list_1(sc, sym));
  24725. if (is_string(f))
  24726. s7_load_with_environment(sc, string_value(f), sc->envir);
  24727. else
  24728. {
  24729. sc->temp5 = sc->nil;
  24730. return(s7_error(sc, make_symbol(sc, "autoload-error"),
  24731. set_elist_2(sc, make_string_wrapper(sc, "require: no autoload info for ~S"), sym)));
  24732. }
  24733. }
  24734. }
  24735. sc->temp5 = cdr(sc->temp5); /* in-coming value */
  24736. return(sc->T);
  24737. }
  24738. /* -------------------------------- eval-string -------------------------------- */
  24739. s7_pointer s7_eval_c_string_with_environment(s7_scheme *sc, const char *str, s7_pointer e)
  24740. {
  24741. s7_pointer code, port;
  24742. port = s7_open_input_string(sc, str);
  24743. code = s7_read(sc, port);
  24744. s7_close_input_port(sc, port);
  24745. return(s7_eval(sc, _NFre(code), e));
  24746. }
  24747. s7_pointer s7_eval_c_string(s7_scheme *sc, const char *str)
  24748. {
  24749. return(s7_eval_c_string_with_environment(sc, str, sc->nil));
  24750. }
  24751. static s7_pointer g_eval_string(s7_scheme *sc, s7_pointer args)
  24752. {
  24753. #define H_eval_string "(eval-string str (env (curlet))) returns the result of evaluating the string str as Scheme code"
  24754. #define Q_eval_string s7_make_signature(sc, 3, sc->values_symbol, sc->is_string_symbol, sc->is_let_symbol)
  24755. s7_pointer port, str;
  24756. str = car(args);
  24757. if (!is_string(str))
  24758. method_or_bust(sc, str, sc->eval_string_symbol, args, T_STRING, 1);
  24759. if (is_not_null(cdr(args)))
  24760. {
  24761. s7_pointer e;
  24762. e = cadr(args);
  24763. if (!is_let(e))
  24764. return(wrong_type_argument_with_type(sc, sc->eval_string_symbol, 2, e, a_let_string));
  24765. if (e == sc->rootlet)
  24766. sc->envir = sc->nil;
  24767. else sc->envir = e;
  24768. }
  24769. port = open_and_protect_input_string(sc, str);
  24770. push_input_port(sc, port);
  24771. sc->temp3 = sc->args;
  24772. push_stack(sc, OP_EVAL_STRING_1, args, sc->code);
  24773. push_stack(sc, OP_READ_INTERNAL, sc->nil, sc->nil);
  24774. return(sc->F);
  24775. }
  24776. static s7_pointer eval_string_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  24777. {
  24778. check_for_substring_temp(sc, expr);
  24779. return(f);
  24780. }
  24781. static s7_pointer call_with_input(s7_scheme *sc, s7_pointer port, s7_pointer args)
  24782. {
  24783. s7_pointer p;
  24784. p = cadr(args);
  24785. port_original_input_string(port) = car(args);
  24786. push_stack(sc, OP_UNWIND_INPUT, sc->input_port, port);
  24787. push_stack(sc, OP_APPLY, list_1(sc, port), p);
  24788. return(sc->F);
  24789. }
  24790. /* -------------------------------- call-with-input-string -------------------------------- */
  24791. static s7_pointer g_call_with_input_string(s7_scheme *sc, s7_pointer args)
  24792. {
  24793. s7_pointer str, proc;
  24794. #define H_call_with_input_string "(call-with-input-string str proc) opens a string port for str and applies proc to it"
  24795. #define Q_call_with_input_string pl_sf
  24796. /* (call-with-input-string "44" (lambda (p) (+ 1 (read p)))) -> 45 */
  24797. str = car(args);
  24798. if (!is_string(str))
  24799. method_or_bust(sc, str, sc->call_with_input_string_symbol, args, T_STRING, 1);
  24800. proc = cadr(args);
  24801. if (is_let(proc))
  24802. check_method(sc, proc, sc->call_with_input_string_symbol, args);
  24803. if (!s7_is_aritable(sc, proc, 1))
  24804. return(wrong_type_argument_with_type(sc, sc->call_with_input_string_symbol, 2, proc,
  24805. make_string_wrapper(sc, "a procedure of one argument (the port)")));
  24806. if ((is_continuation(proc)) || (is_goto(proc)))
  24807. return(wrong_type_argument_with_type(sc, sc->call_with_input_string_symbol, 2, proc, a_normal_procedure_string));
  24808. return(call_with_input(sc, open_and_protect_input_string(sc, str), args));
  24809. }
  24810. static s7_pointer c_call_with_input_string(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_call_with_input_string(sc, set_plist_2(sc, x, y)));}
  24811. PF2_TO_PF(call_with_input_string, c_call_with_input_string)
  24812. /* -------------------------------- call-with-input-file -------------------------------- */
  24813. static s7_pointer g_call_with_input_file(s7_scheme *sc, s7_pointer args)
  24814. {
  24815. #define H_call_with_input_file "(call-with-input-file filename proc) opens filename and calls proc with the input port as its argument"
  24816. #define Q_call_with_input_file pl_sf
  24817. s7_pointer str, proc;
  24818. str = car(args);
  24819. if (!is_string(str))
  24820. method_or_bust(sc, str, sc->call_with_input_file_symbol, args, T_STRING, 1);
  24821. proc = cadr(args);
  24822. if (!s7_is_aritable(sc, proc, 1))
  24823. return(wrong_type_argument_with_type(sc, sc->call_with_input_file_symbol, 2, proc,
  24824. make_string_wrapper(sc, "a procedure of one argument (the port)")));
  24825. if ((is_continuation(proc)) || (is_goto(proc)))
  24826. return(wrong_type_argument_with_type(sc, sc->call_with_input_file_symbol, 2, proc, a_normal_procedure_string));
  24827. return(call_with_input(sc, open_input_file_1(sc, string_value(str), "r", "call-with-input-file"), args));
  24828. }
  24829. static s7_pointer c_call_with_input_file(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_call_with_input_file(sc, set_plist_2(sc, x, y)));}
  24830. PF2_TO_PF(call_with_input_file, c_call_with_input_file)
  24831. static s7_pointer with_input(s7_scheme *sc, s7_pointer port, s7_pointer args)
  24832. {
  24833. s7_pointer old_input_port, p;
  24834. old_input_port = sc->input_port;
  24835. sc->input_port = port;
  24836. port_original_input_string(port) = car(args);
  24837. push_stack(sc, OP_UNWIND_INPUT, old_input_port, port);
  24838. p = cadr(args);
  24839. push_stack(sc, OP_APPLY, sc->nil, p);
  24840. return(sc->F);
  24841. }
  24842. /* -------------------------------- with-input-from-string -------------------------------- */
  24843. static s7_pointer g_with_input_from_string(s7_scheme *sc, s7_pointer args)
  24844. {
  24845. #define H_with_input_from_string "(with-input-from-string str thunk) opens str as the temporary current-input-port and calls thunk"
  24846. #define Q_with_input_from_string pl_sf
  24847. s7_pointer str;
  24848. str = car(args);
  24849. if (!is_string(str))
  24850. method_or_bust(sc, str, sc->with_input_from_string_symbol, args, T_STRING, 1);
  24851. if (!is_thunk(sc, cadr(args)))
  24852. method_or_bust_with_type(sc, cadr(args), sc->with_input_from_string_symbol, args, a_thunk_string, 2);
  24853. /* since the arguments are evaluated before we get here, we can get some confusing situations:
  24854. * (with-input-from-string "#x2.1" (read))
  24855. * (read) -> whatever it can get from the current input port!
  24856. * ";with-input-from-string argument 2, #<eof>, is untyped but should be a thunk"
  24857. */
  24858. return(with_input(sc, open_and_protect_input_string(sc, str), args));
  24859. }
  24860. static s7_pointer c_with_input_from_string(s7_scheme *sc, s7_pointer x) {return(g_with_input_from_string(sc, set_plist_1(sc, x)));}
  24861. PF_TO_PF(with_input_from_string, c_with_input_from_string)
  24862. /* -------------------------------- with-input-from-file -------------------------------- */
  24863. static s7_pointer g_with_input_from_file(s7_scheme *sc, s7_pointer args)
  24864. {
  24865. #define H_with_input_from_file "(with-input-from-file filename thunk) opens filename as the temporary current-input-port and calls thunk"
  24866. #define Q_with_input_from_file pl_sf
  24867. if (!is_string(car(args)))
  24868. method_or_bust(sc, car(args), sc->with_input_from_file_symbol, args, T_STRING, 1);
  24869. if (!is_thunk(sc, cadr(args)))
  24870. method_or_bust_with_type(sc, cadr(args), sc->with_input_from_file_symbol, args, a_thunk_string, 2);
  24871. return(with_input(sc, open_input_file_1(sc, string_value(car(args)), "r", "with-input-from-file"), args));
  24872. }
  24873. static s7_pointer c_with_input_from_file(s7_scheme *sc, s7_pointer x) {return(g_with_input_from_file(sc, set_plist_1(sc, x)));}
  24874. PF_TO_PF(with_input_from_file, c_with_input_from_file)
  24875. /* -------------------------------- iterators -------------------------------- */
  24876. static s7_pointer g_is_iterator(s7_scheme *sc, s7_pointer args)
  24877. {
  24878. #define H_is_iterator "(iterator? obj) returns #t if obj is an iterator."
  24879. #define Q_is_iterator pl_bt
  24880. s7_pointer x;
  24881. x = car(args);
  24882. if (is_iterator(x)) return(sc->T);
  24883. check_closure_for(sc, x, sc->is_iterator_symbol);
  24884. check_boolean_method(sc, is_iterator, sc->is_iterator_symbol, args);
  24885. return(sc->F);
  24886. }
  24887. static s7_pointer iterator_copy(s7_scheme *sc, s7_pointer p)
  24888. {
  24889. /* fields are obj cur [loc|lcur] [len|slow|hcur] next */
  24890. s7_pointer iter;
  24891. new_cell(sc, iter, T_ITERATOR | T_SAFE_PROCEDURE);
  24892. iterator_sequence(iter) = iterator_sequence(p); /* obj */
  24893. iterator_position(iter) = iterator_position(p); /* loc|lcur (loc is s7_int) */
  24894. iterator_length(iter) = iterator_length(p); /* len|slow|hcur (len is s7_int) */
  24895. iterator_current(iter) = iterator_current(p); /* cur */
  24896. iterator_next(iter) = iterator_next(p); /* next */
  24897. return(iter);
  24898. }
  24899. static s7_pointer iterator_finished(s7_scheme *sc, s7_pointer iterator)
  24900. {
  24901. return(sc->ITERATOR_END);
  24902. }
  24903. static s7_pointer let_iterate(s7_scheme *sc, s7_pointer iterator)
  24904. {
  24905. s7_pointer slot;
  24906. slot = iterator_current_slot(iterator);
  24907. if (is_slot(slot))
  24908. {
  24909. iterator_set_current_slot(iterator, next_slot(slot));
  24910. if (iterator_let_cons(iterator))
  24911. {
  24912. s7_pointer p;
  24913. p = iterator_let_cons(iterator);
  24914. set_car(p, slot_symbol(slot));
  24915. set_cdr(p, slot_value(slot));
  24916. return(p);
  24917. }
  24918. return(cons(sc, slot_symbol(slot), slot_value(slot)));
  24919. }
  24920. iterator_next(iterator) = iterator_finished;
  24921. return(sc->ITERATOR_END);
  24922. }
  24923. static s7_pointer rootlet_iterate(s7_scheme *sc, s7_pointer iterator)
  24924. {
  24925. s7_pointer slot;
  24926. slot = iterator_current(iterator);
  24927. if (is_slot(slot))
  24928. {
  24929. if (iterator_position(iterator) < sc->rootlet_entries)
  24930. {
  24931. iterator_position(iterator)++;
  24932. iterator_current(iterator) = vector_element(sc->rootlet, iterator_position(iterator));
  24933. }
  24934. else iterator_current(iterator) = sc->nil;
  24935. return(cons(sc, slot_symbol(slot), slot_value(slot)));
  24936. }
  24937. iterator_next(iterator) = iterator_finished;
  24938. return(sc->ITERATOR_END);
  24939. }
  24940. static s7_pointer hash_table_iterate(s7_scheme *sc, s7_pointer iterator)
  24941. {
  24942. s7_pointer table;
  24943. int loc, len;
  24944. hash_entry_t **elements;
  24945. hash_entry_t *lst;
  24946. lst = iterator_hash_current(iterator);
  24947. if (lst)
  24948. {
  24949. iterator_hash_current(iterator) = lst->next;
  24950. if (iterator_current(iterator))
  24951. {
  24952. s7_pointer p;
  24953. p = iterator_current(iterator);
  24954. set_car(p, lst->key);
  24955. set_cdr(p, lst->value);
  24956. return(p);
  24957. }
  24958. return(cons(sc, lst->key, lst->value));
  24959. }
  24960. table = iterator_sequence(iterator); /* using iterator_length and hash_table_entries here was slightly slower */
  24961. len = hash_table_mask(table) + 1;
  24962. elements = hash_table_elements(table);
  24963. for (loc = iterator_position(iterator) + 1; loc < len; loc++)
  24964. {
  24965. hash_entry_t *x;
  24966. x = elements[loc];
  24967. if (x)
  24968. {
  24969. iterator_position(iterator) = loc;
  24970. iterator_hash_current(iterator) = x->next;
  24971. if (iterator_current(iterator))
  24972. {
  24973. s7_pointer p;
  24974. p = iterator_current(iterator);
  24975. set_car(p, x->key);
  24976. set_cdr(p, x->value);
  24977. return(p);
  24978. }
  24979. return(cons(sc, x->key, x->value));
  24980. }
  24981. }
  24982. iterator_next(iterator) = iterator_finished;
  24983. return(sc->ITERATOR_END);
  24984. }
  24985. static s7_pointer string_iterate(s7_scheme *sc, s7_pointer obj)
  24986. {
  24987. if (iterator_position(obj) < iterator_length(obj))
  24988. return(s7_make_character(sc, (unsigned char)(string_value(iterator_sequence(obj))[iterator_position(obj)++])));
  24989. iterator_next(obj) = iterator_finished;
  24990. return(sc->ITERATOR_END);
  24991. }
  24992. static s7_pointer byte_vector_iterate(s7_scheme *sc, s7_pointer obj)
  24993. {
  24994. if (iterator_position(obj) < iterator_length(obj))
  24995. return(small_int((unsigned char)(string_value(iterator_sequence(obj))[iterator_position(obj)++])));
  24996. iterator_next(obj) = iterator_finished;
  24997. return(sc->ITERATOR_END);
  24998. }
  24999. static s7_pointer float_vector_iterate(s7_scheme *sc, s7_pointer obj)
  25000. {
  25001. if (iterator_position(obj) < iterator_length(obj))
  25002. return(make_real(sc, float_vector_element(iterator_sequence(obj), iterator_position(obj)++)));
  25003. iterator_next(obj) = iterator_finished;
  25004. return(sc->ITERATOR_END);
  25005. }
  25006. static s7_pointer int_vector_iterate(s7_scheme *sc, s7_pointer obj)
  25007. {
  25008. if (iterator_position(obj) < iterator_length(obj))
  25009. return(make_integer(sc, int_vector_element(iterator_sequence(obj), iterator_position(obj)++)));
  25010. iterator_next(obj) = iterator_finished;
  25011. return(sc->ITERATOR_END);
  25012. }
  25013. static s7_pointer vector_iterate(s7_scheme *sc, s7_pointer obj)
  25014. {
  25015. if (iterator_position(obj) < iterator_length(obj))
  25016. return(vector_element(iterator_sequence(obj), iterator_position(obj)++));
  25017. iterator_next(obj) = iterator_finished;
  25018. return(sc->ITERATOR_END);
  25019. }
  25020. static s7_pointer closure_iterate(s7_scheme *sc, s7_pointer obj)
  25021. {
  25022. s7_pointer result;
  25023. result = s7_apply_function(sc, iterator_sequence(obj), sc->nil);
  25024. if (result == sc->ITERATOR_END)
  25025. iterator_next(obj) = iterator_finished;
  25026. return(result);
  25027. }
  25028. static s7_pointer c_object_direct_iterate(s7_scheme *sc, s7_pointer obj)
  25029. {
  25030. if (iterator_position(obj) < iterator_length(obj))
  25031. {
  25032. s7_pointer result, p;
  25033. p = iterator_sequence(obj);
  25034. result = c_object_cref(p)(sc, p, iterator_position(obj));
  25035. iterator_position(obj)++;
  25036. if (result == sc->ITERATOR_END)
  25037. iterator_next(obj) = iterator_finished;
  25038. return(result);
  25039. }
  25040. iterator_next(obj) = iterator_finished;
  25041. return(sc->ITERATOR_END);
  25042. }
  25043. static s7_pointer c_object_iterate(s7_scheme *sc, s7_pointer obj)
  25044. {
  25045. if (iterator_position(obj) < iterator_length(obj))
  25046. {
  25047. s7_pointer result, p, cur;
  25048. p = iterator_sequence(obj);
  25049. cur = iterator_current(obj);
  25050. set_car(sc->z2_1, sc->x);
  25051. set_car(sc->z2_2, sc->z); /* is this necessary? */
  25052. set_car(cur, make_integer(sc, iterator_position(obj)));
  25053. result = (*(c_object_ref(p)))(sc, p, cur);
  25054. sc->x = car(sc->z2_1);
  25055. sc->z = car(sc->z2_2);
  25056. iterator_position(obj)++;
  25057. if (result == sc->ITERATOR_END)
  25058. iterator_next(obj) = iterator_finished;
  25059. return(result);
  25060. }
  25061. iterator_next(obj) = iterator_finished;
  25062. return(sc->ITERATOR_END);
  25063. }
  25064. static s7_pointer pair_iterate_1(s7_scheme *sc, s7_pointer obj);
  25065. static s7_pointer pair_iterate(s7_scheme *sc, s7_pointer obj)
  25066. {
  25067. if (is_pair(iterator_current(obj)))
  25068. {
  25069. s7_pointer result;
  25070. result = car(iterator_current(obj));
  25071. iterator_current(obj) = cdr(iterator_current(obj));
  25072. if (iterator_current(obj) == iterator_slow(obj))
  25073. {
  25074. iterator_next(obj) = iterator_finished;
  25075. return(result);
  25076. }
  25077. iterator_next(obj) = pair_iterate_1;
  25078. return(result);
  25079. }
  25080. iterator_next(obj) = iterator_finished;
  25081. return(sc->ITERATOR_END);
  25082. }
  25083. static s7_pointer pair_iterate_1(s7_scheme *sc, s7_pointer obj)
  25084. {
  25085. if (is_pair(iterator_current(obj)))
  25086. {
  25087. s7_pointer result;
  25088. result = car(iterator_current(obj));
  25089. iterator_current(obj) = cdr(iterator_current(obj));
  25090. if (iterator_current(obj) == iterator_slow(obj))
  25091. {
  25092. iterator_next(obj) = iterator_finished;
  25093. return(result);
  25094. }
  25095. iterator_set_slow(obj, cdr(iterator_slow(obj)));
  25096. iterator_next(obj) = pair_iterate;
  25097. return(result);
  25098. }
  25099. iterator_next(obj) = iterator_finished;
  25100. return(sc->ITERATOR_END);
  25101. }
  25102. static s7_pointer iterator_method(s7_scheme *sc, s7_pointer e)
  25103. {
  25104. s7_pointer func;
  25105. if ((has_methods(e)) &&
  25106. ((func = find_method(sc, find_let(sc, e), sc->make_iterator_symbol)) != sc->undefined))
  25107. {
  25108. s7_pointer it;
  25109. it = s7_apply_function(sc, func, list_1(sc, e));
  25110. if (!is_iterator(it))
  25111. return(s7_error(sc, sc->error_symbol, set_elist_2(sc, make_string_wrapper(sc, "make-iterator method must return an interator: ~S"), it)));
  25112. return(it);
  25113. }
  25114. return(NULL);
  25115. }
  25116. s7_pointer s7_make_iterator(s7_scheme *sc, s7_pointer e)
  25117. {
  25118. s7_pointer iter;
  25119. new_cell(sc, iter, T_ITERATOR | T_SAFE_PROCEDURE);
  25120. iterator_sequence(iter) = e;
  25121. iterator_position(iter) = 0;
  25122. switch (type(e))
  25123. {
  25124. case T_LET:
  25125. if (e == sc->rootlet)
  25126. {
  25127. iterator_current(iter) = vector_element(e, 0); /* unfortunately tricky -- let_iterate uses different fields */
  25128. iterator_next(iter) = rootlet_iterate;
  25129. }
  25130. else
  25131. {
  25132. s7_pointer f;
  25133. sc->temp6 = iter;
  25134. f = iterator_method(sc, e);
  25135. sc->temp6 = sc->nil;
  25136. if (f) {free_cell(sc, iter); return(f);}
  25137. iterator_set_current_slot(iter, let_slots(e));
  25138. iterator_next(iter) = let_iterate;
  25139. iterator_let_cons(iter) = NULL;
  25140. }
  25141. break;
  25142. case T_HASH_TABLE:
  25143. iterator_hash_current(iter) = NULL;
  25144. iterator_current(iter) = NULL;
  25145. iterator_position(iter) = -1;
  25146. iterator_next(iter) = hash_table_iterate;
  25147. break;
  25148. case T_STRING:
  25149. iterator_length(iter) = string_length(e);
  25150. if (is_byte_vector(e))
  25151. iterator_next(iter) = byte_vector_iterate;
  25152. else iterator_next(iter) = string_iterate;
  25153. break;
  25154. case T_VECTOR:
  25155. iterator_length(iter) = vector_length(e);
  25156. iterator_next(iter) = vector_iterate;
  25157. break;
  25158. case T_INT_VECTOR:
  25159. iterator_length(iter) = vector_length(e);
  25160. iterator_next(iter) = int_vector_iterate;
  25161. break;
  25162. case T_FLOAT_VECTOR:
  25163. iterator_length(iter) = vector_length(e);
  25164. iterator_next(iter) = float_vector_iterate;
  25165. break;
  25166. case T_PAIR:
  25167. iterator_current(iter) = e;
  25168. iterator_next(iter) = pair_iterate;
  25169. iterator_set_slow(iter, e);
  25170. break;
  25171. case T_MACRO: case T_MACRO_STAR:
  25172. case T_BACRO: case T_BACRO_STAR:
  25173. case T_CLOSURE: case T_CLOSURE_STAR:
  25174. {
  25175. s7_pointer p;
  25176. p = cons(sc, e, sc->nil);
  25177. if (g_is_iterator(sc, p) != sc->F)
  25178. {
  25179. set_car(p, small_int(0));
  25180. iterator_current(iter) = p;
  25181. set_mark_seq(iter);
  25182. iterator_next(iter) = closure_iterate;
  25183. if (has_methods(e))
  25184. iterator_length(iter) = closure_length(sc, e);
  25185. else iterator_length(iter) = s7_int_max;
  25186. }
  25187. else
  25188. {
  25189. free_cell(sc, iter);
  25190. return(simple_wrong_type_argument_with_type(sc, sc->make_iterator_symbol, e, make_string_wrapper(sc, "a closure/macro with an 'iterator local that is not #f")));
  25191. }
  25192. }
  25193. break;
  25194. case T_C_OBJECT:
  25195. iterator_length(iter) = object_length_to_int(sc, e);
  25196. if (c_object_direct_ref(e))
  25197. {
  25198. iterator_next(iter) = c_object_direct_iterate;
  25199. c_object_cref(e) = c_object_direct_ref(e);
  25200. }
  25201. else
  25202. {
  25203. s7_pointer f;
  25204. sc->temp6 = iter;
  25205. f = iterator_method(sc, e);
  25206. sc->temp6 = sc->nil;
  25207. if (f) {free_cell(sc, iter); return(f);}
  25208. iterator_current(iter) = cons(sc, small_int(0), sc->nil);
  25209. set_mark_seq(iter);
  25210. iterator_next(iter) = c_object_iterate;
  25211. }
  25212. break;
  25213. default:
  25214. return(simple_wrong_type_argument_with_type(sc, sc->make_iterator_symbol, e, a_sequence_string));
  25215. }
  25216. return(iter);
  25217. }
  25218. static s7_pointer g_make_iterator(s7_scheme *sc, s7_pointer args)
  25219. {
  25220. #define H_make_iterator "(make-iterator sequence) returns an iterator object that \
  25221. returns the next value in the sequence each time it is called. When it reaches the end, it returns " ITERATOR_END_NAME "."
  25222. #define Q_make_iterator s7_make_signature(sc, 3, sc->is_iterator_symbol, sc->is_sequence_symbol, sc->is_pair_symbol)
  25223. s7_pointer seq;
  25224. seq = car(args);
  25225. if (is_pair(cdr(args)))
  25226. {
  25227. if (is_pair(cadr(args)))
  25228. {
  25229. if (is_hash_table(seq))
  25230. {
  25231. s7_pointer iter;
  25232. iter = s7_make_iterator(sc, seq);
  25233. iterator_current(iter) = cadr(args);
  25234. set_mark_seq(iter);
  25235. return(iter);
  25236. }
  25237. if ((is_let(seq)) && (seq != sc->rootlet))
  25238. {
  25239. s7_pointer iter;
  25240. iter = s7_make_iterator(sc, seq);
  25241. iterator_let_cons(iter) = cadr(args);
  25242. set_mark_seq(iter);
  25243. return(iter);
  25244. }
  25245. }
  25246. else return(simple_wrong_type_argument(sc, sc->make_iterator_symbol, cadr(args), T_PAIR));
  25247. }
  25248. return(s7_make_iterator(sc, seq));
  25249. }
  25250. PF_TO_PF(make_iterator, s7_make_iterator)
  25251. static s7_pointer c_iterate(s7_scheme *sc, s7_pointer iter)
  25252. {
  25253. if (!is_iterator(iter))
  25254. method_or_bust(sc, iter, sc->iterate_symbol, list_1(sc, iter), T_ITERATOR, 0);
  25255. return((iterator_next(iter))(sc, iter));
  25256. }
  25257. static s7_pointer g_iterate(s7_scheme *sc, s7_pointer args)
  25258. {
  25259. #define H_iterate "(iterate obj) returns the next element from the iterator obj, or " ITERATOR_END_NAME "."
  25260. #define Q_iterate s7_make_signature(sc, 2, sc->T, sc->is_iterator_symbol)
  25261. s7_pointer iter;
  25262. iter = car(args);
  25263. if (!is_iterator(iter))
  25264. method_or_bust(sc, iter, sc->iterate_symbol, args, T_ITERATOR, 0);
  25265. return((iterator_next(iter))(sc, iter));
  25266. }
  25267. static s7_pointer iterate_pf_p(s7_scheme *sc, s7_pointer **p)
  25268. {
  25269. s7_pf_t f;
  25270. s7_pointer x;
  25271. f = (s7_pf_t)(**p); (*p)++;
  25272. x = f(sc, p);
  25273. return(c_iterate(sc, x));
  25274. }
  25275. static s7_pointer iterate_pf_s(s7_scheme *sc, s7_pointer **p)
  25276. {
  25277. pf_pf_t f;
  25278. s7_pointer x;
  25279. x = (s7_pointer)(**p); (*p)++;
  25280. f = (pf_pf_t)(**p); (*p)++;
  25281. return(f(sc, x));
  25282. }
  25283. static s7_pf_t iterate_gf(s7_scheme *sc, s7_pointer expr)
  25284. {
  25285. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))))
  25286. {
  25287. s7_pointer a1, obj;
  25288. a1 = cadr(expr);
  25289. if ((is_symbol(a1)) &&
  25290. (!s7_xf_is_stepper(sc, a1)) &&
  25291. (is_iterator(obj = s7_symbol_value(sc, a1))))
  25292. {
  25293. s7_xf_store(sc, obj);
  25294. s7_xf_store(sc, (s7_pointer)iterator_next(obj));
  25295. return(iterate_pf_s);
  25296. }
  25297. if (s7_arg_to_pf(sc, a1))
  25298. return(iterate_pf_p);
  25299. }
  25300. return(NULL);
  25301. }
  25302. static s7_pf_t iterate_pf(s7_scheme *sc, s7_pointer expr)
  25303. {
  25304. if ((is_pair(cdr(expr))) && (is_null(cddr(expr))))
  25305. {
  25306. s7_pointer a1, obj;
  25307. a1 = cadr(expr);
  25308. if ((is_symbol(a1)) &&
  25309. (!s7_xf_is_stepper(sc, a1)) &&
  25310. (is_iterator(obj = s7_symbol_value(sc, a1))))
  25311. {
  25312. s7_pointer seq;
  25313. seq = iterator_sequence(obj);
  25314. if ((type(seq) == T_VECTOR) || (is_string(seq)) || (is_pair(seq)))
  25315. {
  25316. s7_xf_store(sc, obj);
  25317. s7_xf_store(sc, (s7_pointer)iterator_next(obj));
  25318. return(iterate_pf_s);
  25319. }
  25320. }
  25321. }
  25322. return(NULL);
  25323. }
  25324. s7_pointer s7_iterate(s7_scheme *sc, s7_pointer obj)
  25325. {
  25326. return((iterator_next(obj))(sc, obj));
  25327. }
  25328. bool s7_is_iterator(s7_pointer obj)
  25329. {
  25330. return(is_iterator(obj));
  25331. }
  25332. bool s7_iterator_is_at_end(s7_pointer obj)
  25333. {
  25334. return(iterator_is_at_end(obj));
  25335. }
  25336. static s7_pointer g_iterator_sequence(s7_scheme *sc, s7_pointer args)
  25337. {
  25338. #define H_iterator_sequence "(iterator-sequence iterator) returns the sequence that iterator is traversing."
  25339. #define Q_iterator_sequence s7_make_signature(sc, 2, sc->is_sequence_symbol, sc->is_iterator_symbol)
  25340. s7_pointer iter;
  25341. iter = car(args);
  25342. if (!is_iterator(iter))
  25343. return(simple_wrong_type_argument(sc, sc->iterator_sequence_symbol, iter, T_ITERATOR));
  25344. return(iterator_sequence(iter));
  25345. }
  25346. static s7_pointer c_iterator_sequence(s7_scheme *sc, s7_pointer iter)
  25347. {
  25348. if (!is_iterator(iter))
  25349. return(simple_wrong_type_argument(sc, sc->iterator_sequence_symbol, iter, T_ITERATOR));
  25350. return(iterator_sequence(iter));
  25351. }
  25352. PF_TO_PF(iterator_sequence, c_iterator_sequence)
  25353. static s7_pointer g_iterator_is_at_end(s7_scheme *sc, s7_pointer args)
  25354. {
  25355. #define H_iterator_is_at_end "(iterator-at-end? iter) returns #t if the iterator has reached the end of its sequence."
  25356. #define Q_iterator_is_at_end s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_iterator_symbol)
  25357. s7_pointer iter;
  25358. iter = car(args);
  25359. if (!is_iterator(iter))
  25360. return(simple_wrong_type_argument(sc, sc->iterator_is_at_end_symbol, iter, T_ITERATOR));
  25361. return(make_boolean(sc, iterator_is_at_end(iter)));
  25362. }
  25363. /* -------------------------------------------------------------------------------- */
  25364. #define INITIAL_SHARED_INFO_SIZE 8
  25365. static int shared_ref(shared_info *ci, s7_pointer p)
  25366. {
  25367. /* from print after collecting refs, not called by equality check */
  25368. int i;
  25369. s7_pointer *objs;
  25370. if (!is_collected(p)) return(0);
  25371. objs = ci->objs;
  25372. for (i = 0; i < ci->top; i++)
  25373. if (objs[i] == p)
  25374. {
  25375. int val;
  25376. val = ci->refs[i];
  25377. if (val > 0)
  25378. ci->refs[i] = -ci->refs[i];
  25379. return(val);
  25380. }
  25381. return(0);
  25382. }
  25383. static int peek_shared_ref(shared_info *ci, s7_pointer p)
  25384. {
  25385. /* returns 0 if not found, otherwise the ref value for p */
  25386. int i;
  25387. s7_pointer *objs;
  25388. objs = ci->objs;
  25389. if (!is_collected(p)) return(0);
  25390. for (i = 0; i < ci->top; i++)
  25391. if (objs[i] == p) return(ci->refs[i]);
  25392. return(0);
  25393. }
  25394. static void enlarge_shared_info(shared_info *ci)
  25395. {
  25396. int i;
  25397. ci->size *= 2;
  25398. ci->objs = (s7_pointer *)realloc(ci->objs, ci->size * sizeof(s7_pointer));
  25399. ci->refs = (int *)realloc(ci->refs, ci->size * sizeof(int));
  25400. for (i = ci->top; i < ci->size; i++)
  25401. {
  25402. ci->refs[i] = 0;
  25403. ci->objs[i] = NULL;
  25404. }
  25405. }
  25406. static void add_equal_ref(shared_info *ci, s7_pointer x, s7_pointer y)
  25407. {
  25408. /* assume neither x nor y is in the table, and that they should share a ref value,
  25409. * called only in equality check, not printer.
  25410. */
  25411. if ((ci->top + 2) >= ci->size)
  25412. enlarge_shared_info(ci);
  25413. set_collected(x);
  25414. set_collected(y);
  25415. ci->ref++;
  25416. ci->objs[ci->top] = x;
  25417. ci->refs[ci->top++] = ci->ref;
  25418. ci->objs[ci->top] = y;
  25419. ci->refs[ci->top++] = ci->ref;
  25420. }
  25421. static void add_shared_ref(shared_info *ci, s7_pointer x, int ref_x)
  25422. {
  25423. /* called only in equality check, not printer */
  25424. if (ci->top == ci->size)
  25425. enlarge_shared_info(ci);
  25426. set_collected(x);
  25427. ci->objs[ci->top] = x;
  25428. ci->refs[ci->top++] = ref_x;
  25429. }
  25430. static shared_info *collect_shared_info(s7_scheme *sc, shared_info *ci, s7_pointer top, bool stop_at_print_length, bool *cyclic);
  25431. static hash_entry_t *hash_equal(s7_scheme *sc, s7_pointer table, s7_pointer key);
  25432. static void collect_vector_info(s7_scheme *sc, shared_info *ci, s7_pointer top, bool stop_at_print_length, bool *cyclic)
  25433. {
  25434. s7_int i, plen;
  25435. if (stop_at_print_length)
  25436. {
  25437. plen = sc->print_length;
  25438. if (plen > vector_length(top))
  25439. plen = vector_length(top);
  25440. }
  25441. else plen = vector_length(top);
  25442. for (i = 0; i < plen; i++)
  25443. if (has_structure(vector_element(top, i)))
  25444. collect_shared_info(sc, ci, vector_element(top, i), stop_at_print_length, cyclic);
  25445. }
  25446. static shared_info *collect_shared_info(s7_scheme *sc, shared_info *ci, s7_pointer top, bool stop_at_print_length, bool *cyclic)
  25447. {
  25448. /* look for top in current list.
  25449. *
  25450. * As we collect objects (guaranteed to have structure) we set the collected bit. If we ever
  25451. * encounter an object with that bit on, we've seen it before so we have a possible cycle.
  25452. * Once the collection pass is done, we run through our list, and clear all these bits.
  25453. */
  25454. if (is_shared(top))
  25455. return(ci);
  25456. if (is_collected(top))
  25457. {
  25458. s7_pointer *p, *objs_end;
  25459. int i;
  25460. *cyclic = true;
  25461. objs_end = (s7_pointer *)(ci->objs + ci->top);
  25462. for (p = ci->objs; p < objs_end; p++)
  25463. if ((*p) == top)
  25464. {
  25465. i = (int)(p - ci->objs);
  25466. if (ci->refs[i] == 0)
  25467. {
  25468. ci->has_hits = true;
  25469. ci->refs[i] = ++ci->ref; /* if found, set the ref number */
  25470. }
  25471. break;
  25472. }
  25473. }
  25474. else
  25475. {
  25476. /* top not seen before -- add it to the list */
  25477. bool top_cyclic = false;
  25478. set_collected(top);
  25479. if (ci->top == ci->size)
  25480. enlarge_shared_info(ci);
  25481. ci->objs[ci->top++] = top;
  25482. /* now search the rest of this structure */
  25483. switch (type(top))
  25484. {
  25485. case T_PAIR:
  25486. if (has_structure(car(top)))
  25487. collect_shared_info(sc, ci, car(top), stop_at_print_length, &top_cyclic);
  25488. if (has_structure(cdr(top)))
  25489. collect_shared_info(sc, ci, cdr(top), stop_at_print_length, &top_cyclic);
  25490. break;
  25491. case T_VECTOR:
  25492. collect_vector_info(sc, ci, top, stop_at_print_length, &top_cyclic);
  25493. break;
  25494. case T_ITERATOR:
  25495. collect_shared_info(sc, ci, iterator_sequence(top), stop_at_print_length, &top_cyclic);
  25496. break;
  25497. case T_HASH_TABLE:
  25498. if (hash_table_entries(top) > 0)
  25499. {
  25500. unsigned int i, len;
  25501. hash_entry_t **entries;
  25502. bool keys_safe;
  25503. keys_safe = ((hash_table_checker(top) != hash_equal) &&
  25504. (!hash_table_checker_locked(top)));
  25505. entries = hash_table_elements(top);
  25506. len = hash_table_mask(top) + 1;
  25507. for (i = 0; i < len; i++)
  25508. {
  25509. hash_entry_t *p;
  25510. for (p = entries[i]; p; p = p->next)
  25511. {
  25512. if ((!keys_safe) &&
  25513. (has_structure(p->key)))
  25514. collect_shared_info(sc, ci, p->key, stop_at_print_length, &top_cyclic);
  25515. if (has_structure(p->value))
  25516. collect_shared_info(sc, ci, p->value, stop_at_print_length, &top_cyclic);
  25517. }
  25518. }
  25519. }
  25520. break;
  25521. case T_SLOT:
  25522. if (has_structure(slot_value(top)))
  25523. collect_shared_info(sc, ci, slot_value(top), stop_at_print_length, &top_cyclic);
  25524. break;
  25525. case T_LET:
  25526. if (top == sc->rootlet)
  25527. collect_vector_info(sc, ci, top, stop_at_print_length, &top_cyclic);
  25528. else
  25529. {
  25530. s7_pointer p;
  25531. for (p = let_slots(top); is_slot(p); p = next_slot(p))
  25532. if (has_structure(slot_value(p)))
  25533. collect_shared_info(sc, ci, slot_value(p), stop_at_print_length, &top_cyclic);
  25534. }
  25535. break;
  25536. }
  25537. if (!top_cyclic)
  25538. set_shared(top);
  25539. else *cyclic = true;
  25540. }
  25541. return(ci);
  25542. }
  25543. static shared_info *new_shared_info(s7_scheme *sc)
  25544. {
  25545. shared_info *ci;
  25546. if (sc->circle_info == NULL)
  25547. {
  25548. ci = (shared_info *)calloc(1, sizeof(shared_info));
  25549. ci->size = INITIAL_SHARED_INFO_SIZE;
  25550. ci->objs = (s7_pointer *)malloc(ci->size * sizeof(s7_pointer));
  25551. ci->refs = (int *)calloc(ci->size, sizeof(int)); /* finder expects 0 = unseen previously */
  25552. sc->circle_info = ci;
  25553. }
  25554. else
  25555. {
  25556. int i;
  25557. ci = sc->circle_info;
  25558. memclr((void *)(ci->refs), ci->top * sizeof(int));
  25559. for (i = 0; i < ci->top; i++)
  25560. clear_collected_and_shared(ci->objs[i]);
  25561. }
  25562. ci->top = 0;
  25563. ci->ref = 0;
  25564. ci->has_hits = false;
  25565. return(ci);
  25566. }
  25567. static shared_info *make_shared_info(s7_scheme *sc, s7_pointer top, bool stop_at_print_length)
  25568. {
  25569. /* for the printer */
  25570. shared_info *ci;
  25571. int i, refs;
  25572. s7_pointer *ci_objs;
  25573. int *ci_refs;
  25574. bool no_problem = true, cyclic = false;
  25575. /* check for simple cases first */
  25576. if (is_pair(top))
  25577. {
  25578. if (s7_list_length(sc, top) != 0) /* it is not circular at the top level (following cdr), so we can check each car(x) */
  25579. {
  25580. s7_pointer x;
  25581. for (x = top; is_pair(x); x = cdr(x))
  25582. if (has_structure(car(x)))
  25583. {
  25584. /* it can help a little in some cases to scan vectors here (and slots):
  25585. * if no element has structure, it's ok (maybe also hash_table_entries == 0)
  25586. */
  25587. no_problem = false;
  25588. break;
  25589. }
  25590. if ((no_problem) &&
  25591. (!is_null(x)) &&
  25592. (has_structure(x)))
  25593. no_problem = false;
  25594. if (no_problem)
  25595. return(NULL);
  25596. }
  25597. }
  25598. else
  25599. {
  25600. if (s7_is_vector(top))
  25601. {
  25602. if (type(top) != T_VECTOR)
  25603. return(NULL);
  25604. for (i = 0; i < vector_length(top); i++)
  25605. if (has_structure(vector_element(top, i)))
  25606. {
  25607. no_problem = false;
  25608. break;
  25609. }
  25610. if (no_problem)
  25611. return(NULL);
  25612. }
  25613. }
  25614. ci = new_shared_info(sc);
  25615. /* collect all pointers associated with top */
  25616. collect_shared_info(sc, ci, top, stop_at_print_length, &cyclic);
  25617. for (i = 0; i < ci->top; i++)
  25618. {
  25619. s7_pointer p;
  25620. p = ci->objs[i];
  25621. clear_collected_and_shared(p);
  25622. }
  25623. if (!cyclic)
  25624. return(NULL);
  25625. if (!(ci->has_hits))
  25626. return(NULL);
  25627. ci_objs = ci->objs;
  25628. ci_refs = ci->refs;
  25629. /* find if any were referenced twice (once for just being there, so twice=shared)
  25630. * we know there's at least one such reference because has_hits is true.
  25631. */
  25632. for (i = 0, refs = 0; i < ci->top; i++)
  25633. if (ci_refs[i] > 0)
  25634. {
  25635. set_collected(ci_objs[i]);
  25636. if (i == refs)
  25637. refs++;
  25638. else
  25639. {
  25640. ci_objs[refs] = ci_objs[i];
  25641. ci_refs[refs++] = ci_refs[i];
  25642. ci_refs[i] = 0;
  25643. ci_objs[i] = NULL;
  25644. }
  25645. }
  25646. ci->top = refs;
  25647. return(ci);
  25648. }
  25649. /* -------------------------------- cyclic-sequences -------------------------------- */
  25650. static s7_pointer cyclic_sequences(s7_scheme *sc, s7_pointer obj, bool return_list)
  25651. {
  25652. if (has_structure(obj))
  25653. {
  25654. shared_info *ci;
  25655. ci = make_shared_info(sc, obj, false); /* false=don't stop at print length (vectors etc) */
  25656. if (ci)
  25657. {
  25658. if (return_list)
  25659. {
  25660. int i;
  25661. s7_pointer lst;
  25662. sc->w = sc->nil;
  25663. for (i = 0; i < ci->top; i++)
  25664. sc->w = cons(sc, ci->objs[i], sc->w);
  25665. lst = sc->w;
  25666. sc->w = sc->nil;
  25667. return(lst);
  25668. }
  25669. else return(sc->T);
  25670. }
  25671. }
  25672. return(sc->nil);
  25673. }
  25674. static s7_pointer g_cyclic_sequences(s7_scheme *sc, s7_pointer args)
  25675. {
  25676. #define H_cyclic_sequences "(cyclic-sequences obj) returns a list of elements that are cyclic."
  25677. #define Q_cyclic_sequences s7_make_signature(sc, 2, sc->is_proper_list_symbol, sc->T)
  25678. return(cyclic_sequences(sc, car(args), true));
  25679. }
  25680. static int circular_list_entries(s7_pointer lst)
  25681. {
  25682. int i;
  25683. s7_pointer x;
  25684. for (i = 1, x = cdr(lst); ; i++, x = cdr(x))
  25685. {
  25686. int j;
  25687. s7_pointer y;
  25688. for (y = lst, j = 0; j < i; y = cdr(y), j++)
  25689. if (x == y)
  25690. return(i);
  25691. }
  25692. }
  25693. static void object_to_port_with_circle_check(s7_scheme *sc, s7_pointer vr, s7_pointer port, use_write_t use_write, shared_info *ci);
  25694. static void object_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info *ci);
  25695. static s7_pointer object_out(s7_scheme *sc, s7_pointer obj, s7_pointer strport, use_write_t choice);
  25696. static char *multivector_indices_to_string(s7_scheme *sc, s7_int index, s7_pointer vect, char *str, int cur_dim)
  25697. {
  25698. s7_int size, ind;
  25699. char buf[64];
  25700. size = vector_dimension(vect, cur_dim);
  25701. ind = index % size;
  25702. if (cur_dim > 0)
  25703. multivector_indices_to_string(sc, (index - ind) / size, vect, str, cur_dim - 1);
  25704. snprintf(buf, 64, " %lld", ind);
  25705. #ifdef __OpenBSD__
  25706. strlcat(str, buf, 128); /* 128=length of str */
  25707. #else
  25708. strcat(str, buf);
  25709. #endif
  25710. return(str);
  25711. }
  25712. static int multivector_to_port(s7_scheme *sc, s7_pointer vec, s7_pointer port,
  25713. int out_len, int flat_ref, int dimension, int dimensions, bool *last,
  25714. use_write_t use_write, shared_info *ci)
  25715. {
  25716. int i;
  25717. if (use_write != USE_READABLE_WRITE)
  25718. {
  25719. if (*last)
  25720. port_write_string(port)(sc, " (", 2, port);
  25721. else port_write_character(port)(sc, '(', port);
  25722. (*last) = false;
  25723. }
  25724. for (i = 0; i < vector_dimension(vec, dimension); i++)
  25725. {
  25726. if (dimension == (dimensions - 1))
  25727. {
  25728. if (flat_ref < out_len)
  25729. {
  25730. if (use_write == USE_READABLE_WRITE)
  25731. {
  25732. int plen;
  25733. char buf[128];
  25734. char *indices;
  25735. /* need to translate flat_ref into a set of indices
  25736. */
  25737. tmpbuf_calloc(indices, 128);
  25738. plen = snprintf(buf, 128, "(set! ({v}%s) ", multivector_indices_to_string(sc, flat_ref, vec, indices, dimension));
  25739. port_write_string(port)(sc, buf, plen, port);
  25740. tmpbuf_free(indices, 128);
  25741. }
  25742. object_to_port_with_circle_check(sc, vector_element(vec, flat_ref), port, DONT_USE_DISPLAY(use_write), ci);
  25743. if (use_write == USE_READABLE_WRITE)
  25744. port_write_string(port)(sc, ") ", 2, port);
  25745. flat_ref++;
  25746. }
  25747. else
  25748. {
  25749. port_write_string(port)(sc, "...)", 4, port);
  25750. return(flat_ref);
  25751. }
  25752. if ((use_write != USE_READABLE_WRITE) &&
  25753. (i < (vector_dimension(vec, dimension) - 1)))
  25754. port_write_character(port)(sc, ' ', port);
  25755. }
  25756. else
  25757. {
  25758. if (flat_ref < out_len)
  25759. flat_ref = multivector_to_port(sc, vec, port, out_len, flat_ref, dimension + 1, dimensions, last, DONT_USE_DISPLAY(use_write), ci);
  25760. else
  25761. {
  25762. port_write_string(port)(sc, "...)", 4, port);
  25763. return(flat_ref);
  25764. }
  25765. }
  25766. }
  25767. if (use_write != USE_READABLE_WRITE)
  25768. port_write_character(port)(sc, ')', port);
  25769. (*last) = true;
  25770. return(flat_ref);
  25771. }
  25772. static void vector_to_port(s7_scheme *sc, s7_pointer vect, s7_pointer port, use_write_t use_write, shared_info *ci)
  25773. {
  25774. s7_int i, len;
  25775. int plen;
  25776. bool too_long = false;
  25777. char buf[128];
  25778. len = vector_length(vect);
  25779. if (len == 0)
  25780. {
  25781. if (vector_rank(vect) > 1)
  25782. {
  25783. plen = snprintf(buf, 32, "#%uD()", vector_ndims(vect));
  25784. port_write_string(port)(sc, buf, plen, port);
  25785. }
  25786. else port_write_string(port)(sc, "#()", 3, port);
  25787. return;
  25788. }
  25789. if (use_write != USE_READABLE_WRITE)
  25790. {
  25791. plen = sc->print_length;
  25792. if (plen <= 0)
  25793. {
  25794. if (vector_rank(vect) > 1)
  25795. {
  25796. plen = snprintf(buf, 32, "#%uD(...)", vector_ndims(vect));
  25797. port_write_string(port)(sc, buf, plen, port);
  25798. }
  25799. else port_write_string(port)(sc, "#(...)", 6, port);
  25800. return;
  25801. }
  25802. if (len > plen)
  25803. {
  25804. too_long = true;
  25805. len = plen;
  25806. }
  25807. }
  25808. if (use_write == USE_READABLE_WRITE)
  25809. {
  25810. if ((ci) &&
  25811. (peek_shared_ref(ci, vect) != 0))
  25812. {
  25813. port_write_string(port)(sc, "(let (({v} (make-vector ", 24, port);
  25814. if (vector_rank(vect) > 1)
  25815. {
  25816. unsigned int dim;
  25817. port_write_string(port)(sc, "'(", 2, port);
  25818. for (dim = 0; dim < vector_ndims(vect); dim++)
  25819. {
  25820. plen = snprintf(buf, 128, "%lld ", vector_dimension(vect, dim));
  25821. port_write_string(port)(sc, buf, plen, port);
  25822. }
  25823. port_write_string(port)(sc, ")))) ", 5, port);
  25824. }
  25825. else
  25826. {
  25827. plen = snprintf(buf, 128, "%lld))) ", vector_length(vect));
  25828. port_write_string(port)(sc, buf, plen, port);
  25829. }
  25830. if (shared_ref(ci, vect) < 0)
  25831. {
  25832. plen = snprintf(buf, 128, "(set! {%d} {v}) ", -shared_ref(ci, vect));
  25833. port_write_string(port)(sc, buf, plen, port);
  25834. }
  25835. if (vector_rank(vect) > 1)
  25836. {
  25837. bool last = false;
  25838. multivector_to_port(sc, vect, port, len, 0, 0, vector_ndims(vect), &last, use_write, ci);
  25839. }
  25840. else
  25841. {
  25842. for (i = 0; i < len; i++)
  25843. {
  25844. port_write_string(port)(sc, "(set! ({v} ", 11, port);
  25845. plen = snprintf(buf, 128, "%lld) ", i);
  25846. port_write_string(port)(sc, buf, plen, port);
  25847. object_to_port_with_circle_check(sc, vector_element(vect, i), port, use_write, ci);
  25848. port_write_string(port)(sc, ") ", 2, port);
  25849. }
  25850. }
  25851. port_write_string(port)(sc, "{v})", 4, port);
  25852. }
  25853. else /* simple readable case */
  25854. {
  25855. if (vector_rank(vect) > 1)
  25856. port_write_string(port)(sc, "(make-shared-vector (vector", 27, port);
  25857. else port_write_string(port)(sc, "(vector", 7, port);
  25858. for (i = 0; i < len; i++)
  25859. {
  25860. port_write_character(port)(sc, ' ', port);
  25861. object_to_port_with_circle_check(sc, vector_element(vect, i), port, use_write, ci);
  25862. }
  25863. port_write_character(port)(sc, ')', port);
  25864. if (vector_rank(vect) > 1)
  25865. {
  25866. unsigned int dim;
  25867. port_write_string(port)(sc, " '(", 3, port);
  25868. for (dim = 0; dim < vector_ndims(vect) - 1; dim++)
  25869. {
  25870. plen = snprintf(buf, 128, "%lld ", vector_dimension(vect, dim));
  25871. port_write_string(port)(sc, buf, plen, port);
  25872. }
  25873. plen = snprintf(buf, 128, "%lld", vector_dimension(vect, dim));
  25874. port_write_string(port)(sc, buf, plen, port);
  25875. port_write_string(port)(sc, "))", 2, port);
  25876. }
  25877. }
  25878. }
  25879. else
  25880. {
  25881. if (vector_rank(vect) > 1)
  25882. {
  25883. bool last = false;
  25884. if (vector_ndims(vect) > 1)
  25885. {
  25886. plen = snprintf(buf, 32, "#%uD", vector_ndims(vect));
  25887. port_write_string(port)(sc, buf, plen, port);
  25888. }
  25889. else port_write_character(port)(sc, '#', port);
  25890. multivector_to_port(sc, vect, port, len, 0, 0, vector_ndims(vect), &last, use_write, ci);
  25891. }
  25892. else
  25893. {
  25894. port_write_string(port)(sc, "#(", 2, port);
  25895. for (i = 0; i < len - 1; i++)
  25896. {
  25897. object_to_port_with_circle_check(sc, vector_element(vect, i), port, DONT_USE_DISPLAY(use_write), ci);
  25898. port_write_character(port)(sc, ' ', port);
  25899. }
  25900. object_to_port_with_circle_check(sc, vector_element(vect, i), port, DONT_USE_DISPLAY(use_write), ci);
  25901. if (too_long)
  25902. port_write_string(port)(sc, " ...)", 5, port);
  25903. else port_write_character(port)(sc, ')', port);
  25904. }
  25905. }
  25906. }
  25907. static bool string_needs_slashification(const char *str, int len)
  25908. {
  25909. /* we have to go by len (str len) not *s==0 because s7 strings can have embedded nulls */
  25910. unsigned char *p, *pend;
  25911. pend = (unsigned char *)(str + len);
  25912. for (p = (unsigned char *)str; p < pend; p++)
  25913. if (slashify_table[*p])
  25914. return(true);
  25915. return(false);
  25916. }
  25917. #define IN_QUOTES true
  25918. #define NOT_IN_QUOTES false
  25919. static char *slashify_string(s7_scheme *sc, const char *p, int len, bool quoted, int *nlen) /* do not free result */
  25920. {
  25921. int j = 0, cur_size, size;
  25922. char *s;
  25923. unsigned char *pcur, *pend;
  25924. pend = (unsigned char *)(p + len);
  25925. size = len + 256;
  25926. if (size > sc->slash_str_size)
  25927. {
  25928. if (sc->slash_str) free(sc->slash_str);
  25929. sc->slash_str_size = size;
  25930. sc->slash_str = (char *)malloc(size);
  25931. }
  25932. else size = sc->slash_str_size;
  25933. cur_size = size - 2;
  25934. /* memset((void *)sc->slash_str, 0, size); */
  25935. s = sc->slash_str;
  25936. if (quoted) s[j++] = '"';
  25937. /* what about the trailing nulls? Guile writes them out (as does s7 currently)
  25938. * but that is not ideal. I'd like to use ~S for error messages, so that
  25939. * strings are clearly identified via the double-quotes, but this way of
  25940. * writing them is ugly:
  25941. *
  25942. * :(let ((str (make-string 8 #\null))) (set! (str 0) #\a) str)
  25943. * "a\x00\x00\x00\x00\x00\x00\x00"
  25944. *
  25945. * but it would be misleading to omit them because:
  25946. *
  25947. * :(let ((str (make-string 8 #\null))) (set! (str 0) #\a) (string-append str "bc"))
  25948. * "a\x00\x00\x00\x00\x00\x00\x00bc"
  25949. */
  25950. for (pcur = (unsigned char *)p; pcur < pend; pcur++)
  25951. {
  25952. if (slashify_table[*pcur])
  25953. {
  25954. s[j++] = '\\';
  25955. switch (*pcur)
  25956. {
  25957. case '"':
  25958. s[j++] = '"';
  25959. break;
  25960. case '\\':
  25961. s[j++] = '\\';
  25962. break;
  25963. default: /* this is the "\x01" stuff */
  25964. {
  25965. unsigned int n;
  25966. static char dignum[] = "0123456789abcdef";
  25967. s[j++] = 'x';
  25968. n = (unsigned int)(*pcur);
  25969. if (n < 16)
  25970. s[j++] = '0';
  25971. else s[j++] = dignum[(n / 16) % 16];
  25972. s[j++] = dignum[n % 16];
  25973. }
  25974. break;
  25975. }
  25976. }
  25977. else s[j++] = *pcur;
  25978. if (j >= cur_size) /* even with 256 extra, we can overflow (for example, inordinately many tabs in ALSA output) */
  25979. {
  25980. /* int k; */
  25981. size *= 2;
  25982. sc->slash_str = (char *)realloc(sc->slash_str, size * sizeof(char));
  25983. sc->slash_str_size = size;
  25984. cur_size = size - 2;
  25985. s = sc->slash_str;
  25986. /* for (k = j; k < size; k++) s[k] = 0; */
  25987. }
  25988. }
  25989. if (quoted) s[j++] = '"';
  25990. s[j] = '\0';
  25991. (*nlen) = j;
  25992. return(s);
  25993. }
  25994. static void output_port_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write)
  25995. {
  25996. if ((obj == sc->standard_output) ||
  25997. (obj == sc->standard_error))
  25998. port_write_string(port)(sc, port_filename(obj), port_filename_length(obj), port);
  25999. else
  26000. {
  26001. int nlen;
  26002. if (use_write == USE_READABLE_WRITE)
  26003. {
  26004. if (port_is_closed(obj))
  26005. port_write_string(port)(sc, "(let ((p (open-output-string))) (close-output-port p) p)", 56, port);
  26006. else
  26007. {
  26008. char *str;
  26009. if (is_string_port(obj))
  26010. {
  26011. port_write_string(port)(sc, "(let ((p (open-output-string)))", 31, port);
  26012. if (port_position(obj) > 0)
  26013. {
  26014. port_write_string(port)(sc, " (display ", 10, port);
  26015. str = slashify_string(sc, (const char *)port_data(obj), port_position(obj), IN_QUOTES, &nlen);
  26016. port_write_string(port)(sc, str, nlen, port);
  26017. port_write_string(port)(sc, " p)", 3, port);
  26018. }
  26019. port_write_string(port)(sc, " p)", 3, port);
  26020. }
  26021. else
  26022. {
  26023. str = (char *)malloc(256 * sizeof(char));
  26024. nlen = snprintf(str, 256, "(open-output-file \"%s\" \"a\")", port_filename(obj));
  26025. port_write_string(port)(sc, str, nlen, port);
  26026. free(str);
  26027. }
  26028. }
  26029. }
  26030. else
  26031. {
  26032. if (is_string_port(obj))
  26033. port_write_string(port)(sc, "<output-string-port", 19, port);
  26034. else
  26035. {
  26036. if (is_file_port(obj))
  26037. port_write_string(port)(sc, "<output-file-port", 17, port);
  26038. else port_write_string(port)(sc, "<output-function-port", 21, port);
  26039. }
  26040. if (port_is_closed(obj))
  26041. port_write_string(port)(sc, " (closed)>", 10, port);
  26042. else port_write_character(port)(sc, '>', port);
  26043. }
  26044. }
  26045. }
  26046. static void input_port_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write)
  26047. {
  26048. if (obj == sc->standard_input)
  26049. port_write_string(port)(sc, port_filename(obj), port_filename_length(obj), port);
  26050. else
  26051. {
  26052. int nlen = 0;
  26053. if (use_write == USE_READABLE_WRITE)
  26054. {
  26055. if (port_is_closed(obj))
  26056. port_write_string(port)(sc, "(call-with-input-string \"\" (lambda (p) p))", 42, port);
  26057. else
  26058. {
  26059. if (is_function_port(obj))
  26060. port_write_string(port)(sc, "#<function input port>", 22, port);
  26061. else
  26062. {
  26063. char *str;
  26064. if (is_file_port(obj))
  26065. {
  26066. str = (char *)malloc(256 * sizeof(char));
  26067. nlen = snprintf(str, 256, "(open-input-file \"%s\")", port_filename(obj));
  26068. port_write_string(port)(sc, str, nlen, port);
  26069. free(str);
  26070. }
  26071. else
  26072. {
  26073. /* if the string is large, slashify_string is a problem. Usually this is actually
  26074. * a file port where the contents were read in one (up to 5MB) gulp, so the
  26075. * readable version could be: open file, read-char to the current port_position.
  26076. * s7_port_filename(port) has the char* name if any.
  26077. */
  26078. int data_len;
  26079. data_len = port_data_size(obj) - port_position(obj);
  26080. if (data_len > 100)
  26081. {
  26082. const char *filename;
  26083. filename = (const char *)s7_port_filename(obj);
  26084. if (filename)
  26085. {
  26086. #define DO_STR_LEN 1024
  26087. char *do_str;
  26088. int len;
  26089. do_str = (char *)malloc(DO_STR_LEN * sizeof(char));
  26090. if (port_position(obj) > 0)
  26091. {
  26092. len = snprintf(do_str, DO_STR_LEN, "(let ((port (open-input-file \"%s\")))", filename);
  26093. port_write_string(port)(sc, do_str, len, port);
  26094. len = snprintf(do_str, DO_STR_LEN, " (do ((i 0 (+ i 1)) (c (read-char port) (read-char port))) ((= i %u) port)))",
  26095. port_position(obj) - 1);
  26096. }
  26097. else len = snprintf(do_str, DO_STR_LEN, "(open-input-file \"%s\")", filename);
  26098. port_write_string(port)(sc, do_str, len, port);
  26099. free(do_str);
  26100. return;
  26101. }
  26102. }
  26103. port_write_string(port)(sc, "(open-input-string ", 19, port);
  26104. /* not port_write_string here because there might be embedded double-quotes */
  26105. str = slashify_string(sc, (const char *)(port_data(obj) + port_position(obj)), port_data_size(obj) - port_position(obj), IN_QUOTES, &nlen);
  26106. port_write_string(port)(sc, str, nlen, port);
  26107. port_write_character(port)(sc, ')', port);
  26108. }
  26109. }
  26110. }
  26111. }
  26112. else
  26113. {
  26114. if (is_string_port(obj))
  26115. port_write_string(port)(sc, "<input-string-port", 18, port);
  26116. else
  26117. {
  26118. if (is_file_port(obj))
  26119. port_write_string(port)(sc, "<input-file-port", 16, port);
  26120. else port_write_string(port)(sc, "<input-function-port", 20, port);
  26121. }
  26122. if (port_is_closed(obj))
  26123. port_write_string(port)(sc, " (closed)>", 10, port);
  26124. else port_write_character(port)(sc, '>', port);
  26125. }
  26126. }
  26127. }
  26128. static bool symbol_needs_slashification(s7_pointer obj)
  26129. {
  26130. unsigned char *p, *pend;
  26131. const char *str;
  26132. int len;
  26133. str = symbol_name(obj);
  26134. if (str[0] == '#')
  26135. return(true);
  26136. len = symbol_name_length(obj);
  26137. pend = (unsigned char *)(str + len);
  26138. for (p = (unsigned char *)str; p < pend; p++)
  26139. if (symbol_slashify_table[*p])
  26140. return(true);
  26141. set_clean_symbol(obj);
  26142. return(false);
  26143. }
  26144. static void symbol_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write)
  26145. {
  26146. /* I think this is the only place we print a symbol's name
  26147. * but in the readable case, what about (symbol "1;3")? it actually seems ok!
  26148. */
  26149. if ((!is_clean_symbol(obj)) &&
  26150. (symbol_needs_slashification(obj)))
  26151. {
  26152. int nlen = 0;
  26153. char *str, *symstr;
  26154. str = slashify_string(sc, symbol_name(obj), symbol_name_length(obj), NOT_IN_QUOTES, &nlen);
  26155. nlen += 16;
  26156. tmpbuf_malloc(symstr, nlen);
  26157. nlen = snprintf(symstr, nlen, "(symbol \"%s\")", str);
  26158. port_write_string(port)(sc, symstr, nlen, port);
  26159. tmpbuf_free(symstr, nlen);
  26160. }
  26161. else
  26162. {
  26163. if ((use_write == USE_READABLE_WRITE) &&
  26164. (!is_keyword(obj)))
  26165. port_write_character(port)(sc, '\'', port);
  26166. if (is_string_port(port))
  26167. {
  26168. int new_len;
  26169. new_len = port_position(port) + symbol_name_length(obj);
  26170. if (new_len >= (int)port_data_size(port))
  26171. resize_port_data(port, new_len * 2);
  26172. memcpy((void *)(port_data(port) + port_position(port)), (void *)symbol_name(obj), symbol_name_length(obj));
  26173. port_position(port) = new_len;
  26174. }
  26175. else port_write_string(port)(sc, symbol_name(obj), symbol_name_length(obj), port);
  26176. }
  26177. }
  26178. static void string_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write)
  26179. {
  26180. if (string_length(obj) > 0)
  26181. {
  26182. /* this used to check for length > 1<<24 -- is that still necessary?
  26183. * since string_length is a scheme length, not C, this write can embed nulls from C's point of view
  26184. */
  26185. if (use_write == USE_DISPLAY)
  26186. port_write_string(port)(sc, string_value(obj), string_length(obj), port);
  26187. else
  26188. {
  26189. if (!string_needs_slashification(string_value(obj), string_length(obj)))
  26190. {
  26191. port_write_character(port)(sc, '"', port);
  26192. port_write_string(port)(sc, string_value(obj), string_length(obj), port);
  26193. port_write_character(port)(sc, '"', port);
  26194. }
  26195. else
  26196. {
  26197. char *str;
  26198. int nlen = 0;
  26199. str = slashify_string(sc, string_value(obj), string_length(obj), IN_QUOTES, &nlen);
  26200. port_write_string(port)(sc, str, nlen, port);
  26201. }
  26202. }
  26203. }
  26204. else
  26205. {
  26206. if (use_write != USE_DISPLAY)
  26207. port_write_string(port)(sc, "\"\"", 2, port);
  26208. }
  26209. }
  26210. static void byte_vector_to_port(s7_scheme *sc, s7_pointer vect, s7_pointer port, use_write_t use_write)
  26211. {
  26212. s7_int i, len;
  26213. int plen;
  26214. bool too_long = false;
  26215. len = string_length(vect);
  26216. if (use_write == USE_READABLE_WRITE)
  26217. plen = len;
  26218. else plen = sc->print_length;
  26219. if (len == 0)
  26220. port_write_string(port)(sc, "#u8()", 5, port);
  26221. else
  26222. {
  26223. if (plen <= 0)
  26224. port_write_string(port)(sc, "#u8(...)", 8, port);
  26225. else
  26226. {
  26227. unsigned int nlen;
  26228. char *p;
  26229. if (len > plen)
  26230. {
  26231. too_long = true;
  26232. len = plen;
  26233. }
  26234. port_write_string(port)(sc, "#u8(", 4, port);
  26235. for (i = 0; i < len - 1; i++)
  26236. {
  26237. p = pos_int_to_str((int)((unsigned char)string_value(vect)[i]), &nlen, ' ');
  26238. port_write_string(port)(sc, p, nlen - 1, port);
  26239. }
  26240. p = pos_int_to_str((int)((unsigned char)string_value(vect)[i]), &nlen, (too_long) ? '\0' : ')');
  26241. port_write_string(port)(sc, p, nlen - 1, port);
  26242. if (too_long)
  26243. port_write_string(port)(sc, " ...)", 5, port);
  26244. }
  26245. }
  26246. }
  26247. static void int_or_float_vector_to_port(s7_scheme *sc, s7_pointer vect, s7_pointer port, use_write_t use_write)
  26248. {
  26249. s7_int i, len;
  26250. int plen;
  26251. bool too_long = false;
  26252. len = vector_length(vect);
  26253. if (use_write == USE_READABLE_WRITE)
  26254. plen = len;
  26255. else plen = sc->print_length;
  26256. if (len == 0)
  26257. port_write_string(port)(sc, "#()", 3, port);
  26258. else
  26259. {
  26260. if (plen <= 0)
  26261. port_write_string(port)(sc, "#(...)", 6, port);
  26262. else
  26263. {
  26264. char buf[128];
  26265. if (len > plen)
  26266. {
  26267. too_long = true;
  26268. len = plen;
  26269. }
  26270. if (is_int_vector(vect))
  26271. {
  26272. if (vector_rank(vect) > 1)
  26273. port_write_string(port)(sc, "(make-shared-vector (int-vector", 31, port);
  26274. else port_write_string(port)(sc, "(int-vector", 11, port);
  26275. if (!is_string_port(port))
  26276. {
  26277. for (i = 0; i < len; i++)
  26278. {
  26279. plen = snprintf(buf, 128, " %lld", int_vector_element(vect, i));
  26280. port_write_string(port)(sc, buf, plen, port);
  26281. }
  26282. }
  26283. else
  26284. {
  26285. /* an experiment */
  26286. int new_len, next_len;
  26287. unsigned char *dbuf;
  26288. new_len = port_position(port);
  26289. next_len = port_data_size(port) - 128;
  26290. dbuf = port_data(port);
  26291. for (i = 0; i < len; i++)
  26292. {
  26293. if (new_len >= next_len)
  26294. {
  26295. resize_port_data(port, port_data_size(port) * 2);
  26296. next_len = port_data_size(port) - 128;
  26297. dbuf = port_data(port);
  26298. }
  26299. plen = snprintf((char *)(dbuf + new_len), 128, " %lld", int_vector_element(vect, i));
  26300. new_len += plen;
  26301. }
  26302. port_position(port) = new_len;
  26303. }
  26304. }
  26305. else
  26306. {
  26307. if (vector_rank(vect) > 1)
  26308. port_write_string(port)(sc, "(make-shared-vector (float-vector", 33, port);
  26309. else port_write_string(port)(sc, "(float-vector", 13, port);
  26310. for (i = 0; i < len; i++)
  26311. {
  26312. port_write_character(port)(sc, ' ', port);
  26313. plen = snprintf(buf, 124, float_format_g, float_format_precision, float_vector_element(vect, i)); /* 124 so floatify has room */
  26314. floatify(buf, &plen);
  26315. port_write_string(port)(sc, buf, plen, port);
  26316. }
  26317. }
  26318. if (too_long)
  26319. port_write_string(port)(sc, " ...)", 5, port);
  26320. else port_write_character(port)(sc, ')', port);
  26321. if (vector_rank(vect) > 1)
  26322. {
  26323. unsigned int dim;
  26324. port_write_string(port)(sc, " '(", 3, port);
  26325. for (dim = 0; dim < vector_ndims(vect) - 1; dim++)
  26326. {
  26327. plen = snprintf(buf, 128, "%lld ", vector_dimension(vect, dim));
  26328. port_write_string(port)(sc, buf, plen, port);
  26329. }
  26330. plen = snprintf(buf, 128, "%lld", vector_dimension(vect, dim));
  26331. port_write_string(port)(sc, buf, plen, port);
  26332. port_write_string(port)(sc, "))", 2, port);
  26333. }
  26334. }
  26335. }
  26336. }
  26337. static void list_to_port(s7_scheme *sc, s7_pointer lst, s7_pointer port, use_write_t use_write, shared_info *ci)
  26338. {
  26339. /* we need list_to_starboard... */
  26340. s7_pointer x;
  26341. int i, len, true_len;
  26342. true_len = s7_list_length(sc, lst);
  26343. if (true_len < 0) /* a dotted list -- handle cars, then final cdr */
  26344. len = (-true_len + 1);
  26345. else
  26346. {
  26347. if (true_len == 0) /* either () or a circular list */
  26348. {
  26349. if (is_not_null(lst))
  26350. len = circular_list_entries(lst);
  26351. else
  26352. {
  26353. port_write_string(port)(sc, "()", 2, port);
  26354. return;
  26355. }
  26356. }
  26357. else len = true_len;
  26358. }
  26359. if (((car(lst) == sc->quote_symbol) ||
  26360. (car(lst) == sc->quote_unchecked_symbol)) && /* this can happen (see lint.scm) */
  26361. (true_len == 2))
  26362. {
  26363. /* len == 1 is important, otherwise (list 'quote 1 2) -> '1 2 which looks weird
  26364. * or (object->string (apply . `''1)) -> "'quote 1"
  26365. * so (quote x) = 'x but (quote x y z) should be left alone (if evaluated, it's an error)
  26366. */
  26367. port_write_character(port)(sc, '\'', port);
  26368. object_to_port_with_circle_check(sc, cadr(lst), port, USE_WRITE, ci);
  26369. return;
  26370. }
  26371. else port_write_character(port)(sc, '(', port);
  26372. if (is_multiple_value(lst))
  26373. port_write_string(port)(sc, "values ", 7, port);
  26374. if (use_write == USE_READABLE_WRITE)
  26375. {
  26376. if (ci)
  26377. {
  26378. int plen;
  26379. char buf[128];
  26380. port_write_string(port)(sc, "let (({lst} (make-list ", 23, port);
  26381. plen = snprintf(buf, 128, "%d))) ", len);
  26382. port_write_string(port)(sc, buf, plen, port);
  26383. if ((shared_ref(ci, lst) < 0))
  26384. {
  26385. plen = snprintf(buf, 128, "(set! {%d} {lst}) ", -shared_ref(ci, lst));
  26386. port_write_string(port)(sc, buf, plen, port);
  26387. }
  26388. port_write_string(port)(sc, "(let (({x} {lst})) ", 19, port);
  26389. for (i = 0, x = lst; (i < len) && (is_pair(x)); i++, x = cdr(x))
  26390. {
  26391. port_write_string(port)(sc, "(set-car! {x} ", 14, port);
  26392. object_to_port_with_circle_check(sc, car(x), port, use_write, ci);
  26393. port_write_string(port)(sc, ") ", 2, port);
  26394. if (i < len - 1)
  26395. port_write_string(port)(sc, "(set! {x} (cdr {x})) ", 21, port);
  26396. }
  26397. if (!is_null(x))
  26398. {
  26399. port_write_string(port)(sc, "(set-cdr! {x} ", 14, port);
  26400. object_to_port_with_circle_check(sc, x, port, use_write, ci);
  26401. port_write_string(port)(sc, ") ", 2, port);
  26402. }
  26403. port_write_string(port)(sc, ") {lst})", 8, port);
  26404. }
  26405. else
  26406. {
  26407. /* the easier cases: no circles or shared refs to patch up */
  26408. if (true_len > 0)
  26409. {
  26410. port_write_string(port)(sc, "list", 4, port);
  26411. for (x = lst; is_pair(x); x = cdr(x))
  26412. {
  26413. port_write_character(port)(sc, ' ', port);
  26414. object_to_port_with_circle_check(sc, car(x), port, use_write, ci);
  26415. }
  26416. port_write_character(port)(sc, ')', port);
  26417. }
  26418. else
  26419. {
  26420. port_write_string(port)(sc, "cons ", 5, port);
  26421. object_to_port_with_circle_check(sc, car(lst), port, use_write, ci);
  26422. for (x = cdr(lst); is_pair(x); x = cdr(x))
  26423. {
  26424. port_write_character(port)(sc, ' ', port);
  26425. port_write_string(port)(sc, "(cons ", 6, port);
  26426. object_to_port_with_circle_check(sc, car(x), port, use_write, ci);
  26427. }
  26428. port_write_character(port)(sc, ' ', port);
  26429. object_to_port_with_circle_check(sc, x, port, use_write, ci);
  26430. for (i = 1; i < len; i++)
  26431. port_write_character(port)(sc, ')', port);
  26432. }
  26433. }
  26434. }
  26435. else
  26436. {
  26437. if (ci)
  26438. {
  26439. for (x = lst, i = 0; (is_pair(x)) && (i < len) && ((!ci) || (i == 0) || (peek_shared_ref(ci, x) == 0)); i++, x = cdr(x))
  26440. {
  26441. object_to_port_with_circle_check(sc, car(x), port, DONT_USE_DISPLAY(use_write), ci);
  26442. if (i < (len - 1))
  26443. port_write_character(port)(sc, ' ', port);
  26444. }
  26445. if (is_not_null(x))
  26446. {
  26447. if ((true_len == 0) &&
  26448. (i == len))
  26449. port_write_string(port)(sc, " . ", 3, port);
  26450. else port_write_string(port)(sc, ". ", 2, port);
  26451. object_to_port_with_circle_check(sc, x, port, DONT_USE_DISPLAY(use_write), ci);
  26452. }
  26453. port_write_character(port)(sc, ')', port);
  26454. }
  26455. else
  26456. {
  26457. for (x = lst, i = 0; (is_pair(x)) && (i < len); i++, x = cdr(x))
  26458. {
  26459. object_to_port(sc, car(x), port, DONT_USE_DISPLAY(use_write), ci);
  26460. if (i < (len - 1))
  26461. port_write_character(port)(sc, ' ', port);
  26462. }
  26463. if (is_not_null(x))
  26464. {
  26465. port_write_string(port)(sc, ". ", 2, port);
  26466. object_to_port(sc, x, port, DONT_USE_DISPLAY(use_write), ci);
  26467. }
  26468. port_write_character(port)(sc, ')', port);
  26469. }
  26470. }
  26471. }
  26472. static void hash_table_to_port(s7_scheme *sc, s7_pointer hash, s7_pointer port, use_write_t use_write, shared_info *ci)
  26473. {
  26474. int i, len, gc_iter;
  26475. bool too_long = false;
  26476. s7_pointer iterator, p;
  26477. /* if hash is a member of ci, just print its number
  26478. * (let ((ht (hash-table '(a . 1)))) (hash-table-set! ht 'b ht))
  26479. *
  26480. * since equal? does not care about the hash-table lengths, we can ignore that complication in the :readable case
  26481. */
  26482. len = hash_table_entries(hash);
  26483. if (len == 0)
  26484. {
  26485. port_write_string(port)(sc, "(hash-table)", 12, port);
  26486. return;
  26487. }
  26488. if (use_write != USE_READABLE_WRITE)
  26489. {
  26490. s7_int plen;
  26491. plen = sc->print_length;
  26492. if (plen <= 0)
  26493. {
  26494. port_write_string(port)(sc, "(hash-table ...)", 16, port);
  26495. return;
  26496. }
  26497. if (len > plen)
  26498. {
  26499. too_long = true;
  26500. len = plen;
  26501. }
  26502. }
  26503. iterator = s7_make_iterator(sc, hash);
  26504. gc_iter = s7_gc_protect(sc, iterator);
  26505. p = cons(sc, sc->F, sc->F);
  26506. iterator_current(iterator) = p;
  26507. set_mark_seq(iterator);
  26508. if ((use_write == USE_READABLE_WRITE) &&
  26509. (ci) &&
  26510. (peek_shared_ref(ci, hash) != 0))
  26511. {
  26512. port_write_string(port)(sc, "(let (({ht} (make-hash-table)))", 31, port);
  26513. if (shared_ref(ci, hash) < 0)
  26514. {
  26515. int plen;
  26516. char buf[64];
  26517. plen = snprintf(buf, 64, "(set! {%d} {ht}) ", -shared_ref(ci, hash));
  26518. port_write_string(port)(sc, buf, plen, port);
  26519. }
  26520. for (i = 0; i < len; i++)
  26521. {
  26522. s7_pointer key_val, key, val;
  26523. key_val = hash_table_iterate(sc, iterator);
  26524. key = car(key_val);
  26525. val = cdr(key_val);
  26526. port_write_string(port)(sc, " (set! ({ht} ", 13, port);
  26527. if (key == hash)
  26528. port_write_string(port)(sc, "{ht}", 4, port);
  26529. else object_to_port_with_circle_check(sc, key, port, USE_READABLE_WRITE, ci);
  26530. port_write_string(port)(sc, ") ", 2, port);
  26531. if (val == hash)
  26532. port_write_string(port)(sc, "{ht}", 4, port);
  26533. else object_to_port_with_circle_check(sc, val, port, USE_READABLE_WRITE, ci);
  26534. port_write_character(port)(sc, ')', port);
  26535. }
  26536. port_write_string(port)(sc, " {ht})", 6, port);
  26537. }
  26538. else
  26539. {
  26540. port_write_string(port)(sc, "(hash-table", 11, port);
  26541. for (i = 0; i < len; i++)
  26542. {
  26543. s7_pointer key_val;
  26544. if (use_write == USE_READABLE_WRITE)
  26545. port_write_character(port)(sc, ' ', port);
  26546. else port_write_string(port)(sc, " '", 2, port);
  26547. key_val = hash_table_iterate(sc, iterator);
  26548. object_to_port_with_circle_check(sc, key_val, port, DONT_USE_DISPLAY(use_write), ci);
  26549. }
  26550. if (too_long)
  26551. port_write_string(port)(sc, " ...)", 5, port);
  26552. else port_write_character(port)(sc, ')', port);
  26553. }
  26554. s7_gc_unprotect_at(sc, gc_iter);
  26555. }
  26556. static int slot_to_port_1(s7_scheme *sc, s7_pointer x, s7_pointer port, use_write_t use_write, shared_info *ci, int n)
  26557. {
  26558. if (is_slot(x))
  26559. {
  26560. n = slot_to_port_1(sc, next_slot(x), port, use_write, ci, n);
  26561. if (n <= sc->print_length)
  26562. {
  26563. port_write_character(port)(sc, ' ', port);
  26564. object_to_port_with_circle_check(sc, x, port, use_write, ci);
  26565. }
  26566. if (n == (sc->print_length + 1))
  26567. port_write_string(port)(sc, " ...", 4, port);
  26568. }
  26569. return(n + 1);
  26570. }
  26571. static void let_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info *ci)
  26572. {
  26573. /* if outer env points to (say) method list, the object needs to specialize object->string itself */
  26574. if (has_methods(obj))
  26575. {
  26576. s7_pointer print_func;
  26577. print_func = find_method(sc, obj, sc->object_to_string_symbol);
  26578. if (print_func != sc->undefined)
  26579. {
  26580. s7_pointer p;
  26581. /* what needs to be protected here? for one, the function might not return a string! */
  26582. clear_has_methods(obj);
  26583. if (use_write == USE_WRITE)
  26584. p = s7_apply_function(sc, print_func, list_1(sc, obj));
  26585. else p = s7_apply_function(sc, print_func, list_2(sc, obj, (use_write == USE_DISPLAY) ? sc->F : sc->key_readable_symbol));
  26586. set_has_methods(obj);
  26587. if ((is_string(p)) &&
  26588. (string_length(p) > 0))
  26589. port_write_string(port)(sc, string_value(p), string_length(p), port);
  26590. return;
  26591. }
  26592. }
  26593. if (obj == sc->rootlet)
  26594. port_write_string(port)(sc, "(rootlet)", 9, port);
  26595. else
  26596. {
  26597. if (sc->short_print)
  26598. port_write_string(port)(sc, "#<let>", 6, port);
  26599. else
  26600. {
  26601. /* circles can happen here:
  26602. * (let () (let ((b (curlet))) (curlet)))
  26603. * #<let 'b #<let>>
  26604. * or (let ((b #f)) (set! b (curlet)) (curlet))
  26605. * #1=#<let 'b #1#>
  26606. */
  26607. if ((use_write == USE_READABLE_WRITE) &&
  26608. (ci) &&
  26609. (peek_shared_ref(ci, obj) != 0))
  26610. {
  26611. s7_pointer x;
  26612. port_write_string(port)(sc, "(let (({e} (inlet))) ", 21, port);
  26613. if ((ci) &&
  26614. (shared_ref(ci, obj) < 0))
  26615. {
  26616. int plen;
  26617. char buf[64];
  26618. plen = snprintf(buf, 64, "(set! {%d} {e}) ", -shared_ref(ci, obj));
  26619. port_write_string(port)(sc, buf, plen, port);
  26620. }
  26621. port_write_string(port)(sc, "(apply varlet {e} (reverse (list ", 33, port);
  26622. for (x = let_slots(obj); is_slot(x); x = next_slot(x))
  26623. {
  26624. port_write_string(port)(sc, "(cons ", 6, port);
  26625. symbol_to_port(sc, slot_symbol(x), port, use_write);
  26626. port_write_character(port)(sc, ' ', port);
  26627. object_to_port_with_circle_check(sc, slot_value(x), port, use_write, ci);
  26628. port_write_character(port)(sc, ')', port);
  26629. }
  26630. port_write_string(port)(sc, "))) {e})", 8, port);
  26631. }
  26632. else
  26633. {
  26634. port_write_string(port)(sc, "(inlet", 6, port);
  26635. slot_to_port_1(sc, let_slots(obj), port, use_write, ci, 0);
  26636. port_write_character(port)(sc, ')', port);
  26637. }
  26638. }
  26639. }
  26640. }
  26641. static void write_macro_readably(s7_scheme *sc, s7_pointer obj, s7_pointer port)
  26642. {
  26643. s7_pointer arglist, body, expr;
  26644. body = closure_body(obj);
  26645. arglist = closure_args(obj);
  26646. port_write_string(port)(sc, "(define-", 8, port);
  26647. port_write_string(port)(sc, ((is_macro(obj)) || (is_macro_star(obj))) ? "macro" : "bacro", 5, port);
  26648. if ((is_macro_star(obj)) || (is_bacro_star(obj)))
  26649. port_write_character(port)(sc, '*', port);
  26650. port_write_string(port)(sc, " (_m_", 5, port);
  26651. if (is_symbol(arglist))
  26652. {
  26653. port_write_string(port)(sc, " . ", 3, port);
  26654. port_write_string(port)(sc, symbol_name(arglist), symbol_name_length(arglist), port);
  26655. }
  26656. else
  26657. {
  26658. if (is_pair(arglist))
  26659. {
  26660. for (expr = arglist; is_pair(expr); expr = cdr(expr))
  26661. {
  26662. port_write_character(port)(sc, ' ', port);
  26663. object_to_port(sc, car(expr), port, USE_WRITE, NULL);
  26664. }
  26665. if (!is_null(expr))
  26666. {
  26667. port_write_string(port)(sc, " . ", 3, port);
  26668. object_to_port(sc, expr, port, USE_WRITE, NULL);
  26669. }
  26670. }
  26671. }
  26672. port_write_string(port)(sc, ") ", 2, port);
  26673. for (expr = body; is_pair(expr); expr = cdr(expr))
  26674. object_to_port(sc, car(expr), port, USE_WRITE, NULL);
  26675. port_write_character(port)(sc, ')', port);
  26676. }
  26677. static s7_pointer match_symbol(s7_scheme *sc, s7_pointer symbol, s7_pointer e)
  26678. {
  26679. s7_pointer y, le;
  26680. for (le = e; is_let(le) && (le != sc->rootlet); le = outlet(le))
  26681. for (y = let_slots(le); is_slot(y); y = next_slot(y))
  26682. if (slot_symbol(y) == symbol)
  26683. return(y);
  26684. return(NULL);
  26685. }
  26686. static bool slot_memq(s7_pointer symbol, s7_pointer symbols)
  26687. {
  26688. s7_pointer x;
  26689. for (x = symbols; is_pair(x); x = cdr(x))
  26690. if (slot_symbol(car(x)) == symbol)
  26691. return(true);
  26692. return(false);
  26693. }
  26694. static bool arg_memq(s7_pointer symbol, s7_pointer args)
  26695. {
  26696. s7_pointer x;
  26697. for (x = args; is_pair(x); x = cdr(x))
  26698. if ((car(x) == symbol) ||
  26699. ((is_pair(car(x))) &&
  26700. (caar(x) == symbol)))
  26701. return(true);
  26702. return(false);
  26703. }
  26704. static void collect_locals(s7_scheme *sc, s7_pointer body, s7_pointer e, s7_pointer args, int gc_loc)
  26705. {
  26706. if (is_pair(body))
  26707. {
  26708. collect_locals(sc, car(body), e, args, gc_loc);
  26709. collect_locals(sc, cdr(body), e, args, gc_loc);
  26710. }
  26711. else
  26712. {
  26713. if ((is_symbol(body)) &&
  26714. (!arg_memq(body, args)) &&
  26715. (!slot_memq(body, gc_protected_at(sc, gc_loc))))
  26716. {
  26717. s7_pointer slot;
  26718. slot = match_symbol(sc, body, e);
  26719. if (slot)
  26720. gc_protected_at(sc, gc_loc) = cons(sc, slot, gc_protected_at(sc, gc_loc));
  26721. }
  26722. }
  26723. }
  26724. static s7_pointer find_closure(s7_scheme *sc, s7_pointer closure, s7_pointer cur_env)
  26725. {
  26726. s7_pointer e, y;
  26727. for (e = cur_env; is_let(e); e = outlet(e))
  26728. {
  26729. if ((is_function_env(e)) &&
  26730. (is_global(funclet_function(e))) && /* (define (f1) (lambda () 1)) shouldn't say the returned closure is named f1 */
  26731. (slot_value(global_slot(funclet_function(e))) == closure))
  26732. return(funclet_function(e));
  26733. for (y = let_slots(e); is_slot(y); y = next_slot(y))
  26734. if (slot_value(y) == closure)
  26735. return(slot_symbol(y));
  26736. }
  26737. return(sc->nil);
  26738. }
  26739. static void write_closure_name(s7_scheme *sc, s7_pointer closure, s7_pointer port)
  26740. {
  26741. s7_pointer x;
  26742. x = find_closure(sc, closure, closure_let(closure));
  26743. /* this can be confusing! In some cases, the function is in its environment, and in other very similar-looking cases it isn't:
  26744. * (let ((a (lambda () 1))) a)
  26745. * #<lambda ()>
  26746. * (letrec ((a (lambda () 1))) a)
  26747. * a
  26748. * (let () (define (a) 1) a)
  26749. * a
  26750. */
  26751. if (is_symbol(x)) /* after find_closure */
  26752. {
  26753. port_write_string(port)(sc, symbol_name(x), symbol_name_length(x), port);
  26754. return;
  26755. }
  26756. /* names like #<closure> and #<macro> are useless -- try to be a bit more informative */
  26757. switch (type(closure))
  26758. {
  26759. case T_CLOSURE:
  26760. port_write_string(port)(sc, "#<lambda ", 9, port);
  26761. break;
  26762. case T_CLOSURE_STAR:
  26763. port_write_string(port)(sc, "#<lambda* ", 10, port);
  26764. break;
  26765. case T_MACRO:
  26766. if (is_expansion(closure))
  26767. port_write_string(port)(sc, "#<expansion ", 12, port);
  26768. else port_write_string(port)(sc, "#<macro ", 8, port);
  26769. break;
  26770. case T_MACRO_STAR:
  26771. port_write_string(port)(sc, "#<macro* ", 9, port);
  26772. break;
  26773. case T_BACRO:
  26774. port_write_string(port)(sc, "#<bacro ", 8, port);
  26775. break;
  26776. case T_BACRO_STAR:
  26777. port_write_string(port)(sc, "#<bacro* ", 9, port);
  26778. break;
  26779. }
  26780. if (is_null(closure_args(closure)))
  26781. port_write_string(port)(sc, "()>", 3, port);
  26782. else
  26783. {
  26784. s7_pointer args;
  26785. args = closure_args(closure);
  26786. if (is_symbol(args))
  26787. {
  26788. port_write_string(port)(sc, symbol_name(args), symbol_name_length(args), port);
  26789. port_write_character(port)(sc, '>', port); /* (lambda a a) -> #<lambda a> */
  26790. }
  26791. else
  26792. {
  26793. port_write_character(port)(sc, '(', port);
  26794. x = car(args);
  26795. if (is_pair(x)) x = car(x);
  26796. port_write_string(port)(sc, symbol_name(x), symbol_name_length(x), port);
  26797. if (!is_null(cdr(args)))
  26798. {
  26799. s7_pointer y;
  26800. port_write_character(port)(sc, ' ', port);
  26801. if (is_pair(cdr(args)))
  26802. {
  26803. y = cadr(args);
  26804. if (is_pair(y))
  26805. y = car(y);
  26806. else
  26807. {
  26808. if (y == sc->key_rest_symbol)
  26809. {
  26810. port_write_string(port)(sc, ":rest ", 6, port);
  26811. args = cdr(args);
  26812. y = cadr(args);
  26813. if (is_pair(y)) y = car(y);
  26814. }
  26815. }
  26816. }
  26817. else
  26818. {
  26819. port_write_string(port)(sc, ". ", 2, port);
  26820. y = cdr(args);
  26821. }
  26822. port_write_string(port)(sc, symbol_name(y), symbol_name_length(y), port);
  26823. if ((is_pair(cdr(args))) &&
  26824. (!is_null(cddr(args))))
  26825. port_write_string(port)(sc, " ...", 4, port);
  26826. }
  26827. port_write_string(port)(sc, ")>", 2, port);
  26828. }
  26829. }
  26830. }
  26831. static s7_pointer closure_name(s7_scheme *sc, s7_pointer closure)
  26832. {
  26833. /* this is used by the error handlers to get the current function name
  26834. */
  26835. s7_pointer x;
  26836. x = find_closure(sc, closure, sc->envir);
  26837. if (is_symbol(x))
  26838. return(x);
  26839. if (is_pair(current_code(sc)))
  26840. return(current_code(sc));
  26841. return(closure); /* desperation -- the parameter list (caar here) will cause endless confusion in OP_APPLY errors! */
  26842. }
  26843. static void write_closure_readably_1(s7_scheme *sc, s7_pointer obj, s7_pointer arglist, s7_pointer body, s7_pointer port)
  26844. {
  26845. s7_int old_print_length;
  26846. s7_pointer p;
  26847. if (type(obj) == T_CLOSURE_STAR)
  26848. port_write_string(port)(sc, "(lambda* ", 9, port);
  26849. else port_write_string(port)(sc, "(lambda ", 8, port);
  26850. if ((is_pair(arglist)) &&
  26851. (allows_other_keys(arglist)))
  26852. {
  26853. sc->temp9 = s7_append(sc, arglist, cons(sc, sc->key_allow_other_keys_symbol, sc->nil));
  26854. object_out(sc, sc->temp9, port, USE_WRITE);
  26855. sc->temp9 = sc->nil;
  26856. }
  26857. else object_out(sc, arglist, port, USE_WRITE); /* here we just want the straight output (a b) not (list 'a 'b) */
  26858. old_print_length = sc->print_length;
  26859. sc->print_length = 1048576;
  26860. for (p = body; is_pair(p); p = cdr(p))
  26861. {
  26862. port_write_character(port)(sc, ' ', port);
  26863. object_out(sc, car(p), port, USE_WRITE);
  26864. }
  26865. port_write_character(port)(sc, ')', port);
  26866. sc->print_length = old_print_length;
  26867. }
  26868. static void write_closure_readably(s7_scheme *sc, s7_pointer obj, s7_pointer port)
  26869. {
  26870. s7_pointer body, arglist, pe, local_slots, setter = NULL;
  26871. int gc_loc;
  26872. body = closure_body(obj);
  26873. arglist = closure_args(obj);
  26874. pe = closure_let(obj); /* perhaps check for documentation? */
  26875. gc_loc = s7_gc_protect(sc, sc->nil);
  26876. collect_locals(sc, body, pe, arglist, gc_loc); /* collect locals used only here */
  26877. if (s7_is_dilambda(obj))
  26878. {
  26879. setter = closure_setter(obj);
  26880. if ((!(has_closure_let(setter))) ||
  26881. (closure_let(setter) != pe))
  26882. setter = NULL;
  26883. }
  26884. if (setter)
  26885. collect_locals(sc, closure_body(setter), pe, closure_args(setter), gc_loc);
  26886. local_slots = _TLst(gc_protected_at(sc, gc_loc)); /* possibly a list of slots */
  26887. if (!is_null(local_slots))
  26888. {
  26889. s7_pointer x;
  26890. port_write_string(port)(sc, "(let (", 6, port);
  26891. for (x = local_slots; is_pair(x); x = cdr(x))
  26892. {
  26893. s7_pointer slot;
  26894. slot = car(x);
  26895. port_write_character(port)(sc, '(', port);
  26896. port_write_string(port)(sc, symbol_name(slot_symbol(slot)), symbol_name_length(slot_symbol(slot)), port);
  26897. port_write_character(port)(sc, ' ', port);
  26898. object_out(sc, slot_value(slot), port, USE_WRITE);
  26899. if (is_null(cdr(x)))
  26900. port_write_character(port)(sc, ')', port);
  26901. else port_write_string(port)(sc, ") ", 2, port);
  26902. }
  26903. port_write_string(port)(sc, ") ", 2, port);
  26904. }
  26905. if (setter)
  26906. port_write_string(port)(sc, "(dilambda ", 10, port);
  26907. write_closure_readably_1(sc, obj, arglist, body, port);
  26908. if (setter)
  26909. {
  26910. port_write_character(port)(sc, ' ', port);
  26911. write_closure_readably_1(sc, setter, closure_args(setter), closure_body(setter), port);
  26912. port_write_character(port)(sc, ')', port);
  26913. }
  26914. if (!is_null(local_slots))
  26915. port_write_character(port)(sc, ')', port);
  26916. s7_gc_unprotect_at(sc, gc_loc);
  26917. }
  26918. #if TRAP_SEGFAULT
  26919. #include <signal.h>
  26920. static sigjmp_buf senv; /* global here is not a problem -- it is used only to protect s7_is_valid */
  26921. static volatile sig_atomic_t can_jump = 0;
  26922. static void segv(int ignored) {if (can_jump) siglongjmp(senv, 1);}
  26923. #endif
  26924. bool s7_is_valid(s7_scheme *sc, s7_pointer arg)
  26925. {
  26926. bool result = false;
  26927. if (!arg) return(false);
  26928. #if TRAP_SEGFAULT
  26929. if (sigsetjmp(senv, 1) == 0)
  26930. {
  26931. void (*old_segv)(int sig);
  26932. can_jump = 1;
  26933. old_segv = signal(SIGSEGV, segv);
  26934. #endif
  26935. result = ((!is_free(arg)) &&
  26936. (type(arg) < NUM_TYPES) &&
  26937. (arg->hloc >= not_heap) &&
  26938. ((arg->hloc < 0) ||
  26939. ((arg->hloc < (int)sc->heap_size) && (sc->heap[arg->hloc] == arg))));
  26940. #if TRAP_SEGFAULT
  26941. signal(SIGSEGV, old_segv);
  26942. }
  26943. else result = false;
  26944. can_jump = 0;
  26945. #endif
  26946. return(result);
  26947. }
  26948. enum {NO_ARTICLE, INDEFINITE_ARTICLE};
  26949. static char *describe_type_bits(s7_scheme *sc, s7_pointer obj)
  26950. {
  26951. unsigned int full_typ;
  26952. unsigned char typ;
  26953. char *buf;
  26954. buf = (char *)malloc(512 * sizeof(char));
  26955. typ = unchecked_type(obj);
  26956. full_typ = typeflag(obj);
  26957. /* if debugging all of these bits are being watched, so we need some ugly subterfuges */
  26958. snprintf(buf, 512, "type: %d (%s), flags: #x%x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
  26959. typ,
  26960. type_name(sc, obj, NO_ARTICLE),
  26961. full_typ,
  26962. ((full_typ & T_PROCEDURE) != 0) ? " procedure" : "",
  26963. ((full_typ & T_GC_MARK) != 0) ? " gc-marked" : "",
  26964. ((full_typ & T_IMMUTABLE) != 0) ? " immutable" : "",
  26965. ((full_typ & T_EXPANSION) != 0) ? " expansion" : "",
  26966. ((full_typ & T_MULTIPLE_VALUE) != 0) ? " values or matched" : "",
  26967. ((full_typ & T_KEYWORD) != 0) ? " keyword" : "",
  26968. ((full_typ & T_DONT_EVAL_ARGS) != 0) ? " dont-eval-args" : "",
  26969. ((full_typ & T_SYNTACTIC) != 0) ? " syntactic" : "",
  26970. ((full_typ & T_OVERLAY) != 0) ? " overlay" : "",
  26971. ((full_typ & T_CHECKED) != 0) ? " checked" : "",
  26972. ((full_typ & T_UNSAFE) != 0) ? ((is_symbol(obj)) ? " clean" : " unsafe") : "",
  26973. ((full_typ & T_OPTIMIZED) != 0) ? " optimized" : "",
  26974. ((full_typ & T_SAFE_CLOSURE) != 0) ? " safe-closure" : "",
  26975. ((full_typ & T_SAFE_PROCEDURE) != 0) ? " safe-procedure" : "",
  26976. ((full_typ & T_SETTER) != 0) ? " setter" : "",
  26977. ((full_typ & T_COPY_ARGS) != 0) ? " copy-args" : "",
  26978. ((full_typ & T_COLLECTED) != 0) ? " collected" : "",
  26979. ((full_typ & T_SHARED) != 0) ? " shared" : "",
  26980. ((full_typ & T_HAS_METHODS) != 0) ? " has-methods" : "",
  26981. ((full_typ & T_GLOBAL) != 0) ? ((is_pair(obj)) ? " unsafe-do" : " global") : "",
  26982. ((full_typ & T_SAFE_STEPPER) != 0) ? ((is_let(obj)) ? " let-set!-fallback" : ((is_slot(obj)) ? " safe-stepper" : " print-name")) : "",
  26983. ((full_typ & T_LINE_NUMBER) != 0) ?
  26984. ((is_pair(obj)) ? " line number" : ((is_input_port(obj)) ? " loader-port" : ((is_let(obj)) ? " with-let" : " has accessor"))) : "",
  26985. ((full_typ & T_MUTABLE) != 0) ?
  26986. ((is_string(obj)) ? " byte-vector" : ((is_let(obj)) ? " let-ref-fallback" :
  26987. ((is_iterator(obj)) ? " mark-seq" : ((is_slot(obj)) ? " stepper" : " mutable")))) : "",
  26988. ((full_typ & T_GENSYM) != 0) ?
  26989. ((is_let(obj)) ? " function-env" : ((is_unspecified(obj)) ? " no-value" : ((is_pair(obj)) ? " list-in-use" :
  26990. ((is_closure_star(obj)) ? " simple-args" : ((is_string(obj)) ? " documented" : " gensym"))))) : "");
  26991. return(buf);
  26992. }
  26993. #if DEBUGGING
  26994. static const char *check_name(int typ)
  26995. {
  26996. if ((typ >= 0) && (typ < NUM_TYPES))
  26997. {
  26998. s7_pointer p;
  26999. p = prepackaged_type_names[typ];
  27000. if (is_string(p)) return(string_value(p));
  27001. switch (typ)
  27002. {
  27003. case T_C_OBJECT: return("a c-object");
  27004. case T_INPUT_PORT: return("an input port");
  27005. case T_OUTPUT_PORT: return("an output port");
  27006. }
  27007. }
  27008. return("unknown type!");
  27009. }
  27010. static s7_pointer check_seti(s7_scheme *sc, s7_pointer x, const char *func, int line)
  27011. {
  27012. if (is_immutable(x))
  27013. {
  27014. fprintf(stderr, "%s%s[%d]: set! immutable %s: %s%s\n", BOLD_TEXT, func, line, type_name(sc, x, NO_ARTICLE), DISPLAY(x), UNBOLD_TEXT);
  27015. if (stop_at_error) abort();
  27016. }
  27017. return(x);
  27018. }
  27019. static s7_pointer check_ref(s7_pointer p, int expected_type, const char *func, int line, const char *func1, const char *func2)
  27020. {
  27021. int typ;
  27022. typ = unchecked_type(p);
  27023. if (typ != expected_type)
  27024. {
  27025. if ((!func1) || (typ != T_FREE))
  27026. {
  27027. fprintf(stderr, "%s%s[%d]: not %s, but %s (%d)%s\n", BOLD_TEXT, func, line, check_name(expected_type), check_name(typ), typ, UNBOLD_TEXT);
  27028. if (stop_at_error) abort();
  27029. }
  27030. else
  27031. {
  27032. if ((strcmp(func, func1) != 0) &&
  27033. ((!func2) || (strcmp(func, func2) != 0)))
  27034. {
  27035. fprintf(stderr, "%s%s[%d]: free cell, not %s%s\n", BOLD_TEXT, func, line, check_name(expected_type), UNBOLD_TEXT);
  27036. if (stop_at_error) abort();
  27037. }
  27038. }
  27039. }
  27040. return(p);
  27041. }
  27042. static s7_pointer check_ref2(s7_pointer p, int expected_type, int other_type, const char *func, int line, const char *func1, const char *func2)
  27043. {
  27044. int typ;
  27045. typ = unchecked_type(p);
  27046. if ((typ != expected_type) && (typ != other_type))
  27047. return(check_ref(p, expected_type, func, line, func1, func2));
  27048. return(p);
  27049. }
  27050. static s7_pointer check_ref3(s7_pointer p, const char *func, int line)
  27051. {
  27052. int typ;
  27053. typ = unchecked_type(p);
  27054. if ((typ != T_INPUT_PORT) && (typ != T_OUTPUT_PORT) && (typ != T_FREE))
  27055. {
  27056. fprintf(stderr, "%s%s[%d]: not a port, but %s (%d)%s\n", BOLD_TEXT, func, line, check_name(typ), typ, UNBOLD_TEXT);
  27057. if (stop_at_error) abort();
  27058. }
  27059. return(p);
  27060. }
  27061. static s7_pointer check_ref4(s7_pointer p, const char *func, int line)
  27062. {
  27063. int typ;
  27064. typ = unchecked_type(p);
  27065. if ((typ != T_VECTOR) && (typ != T_FLOAT_VECTOR) && (typ != T_INT_VECTOR) && (typ != T_FREE))
  27066. {
  27067. fprintf(stderr, "%s%s[%d]: not a vector, but %s (%d)%s\n", BOLD_TEXT, func, line, check_name(typ), typ, UNBOLD_TEXT);
  27068. if (stop_at_error) abort();
  27069. }
  27070. return(p);
  27071. }
  27072. static s7_pointer check_ref5(s7_pointer p, const char *func, int line)
  27073. {
  27074. int typ;
  27075. typ = unchecked_type(p);
  27076. if (!t_has_closure_let[typ])
  27077. {
  27078. fprintf(stderr, "%s%s[%d]: not a closure, but %s (%d)%s\n", BOLD_TEXT, func, line, check_name(typ), typ, UNBOLD_TEXT);
  27079. if (stop_at_error) abort();
  27080. }
  27081. return(p);
  27082. }
  27083. static s7_pointer check_ref6(s7_pointer p, const char *func, int line)
  27084. {
  27085. int typ;
  27086. typ = unchecked_type(p);
  27087. if ((typ < T_C_FUNCTION_STAR) && (typ != T_C_MACRO))
  27088. {
  27089. fprintf(stderr, "%s%s[%d]: not a c function, but %s (%d)%s\n", BOLD_TEXT, func, line, check_name(typ), typ, UNBOLD_TEXT);
  27090. if (stop_at_error) abort();
  27091. }
  27092. return(p);
  27093. }
  27094. static s7_pointer check_ref7(s7_pointer p, const char *func, int line)
  27095. {
  27096. if ((!func) || (strcmp(func, "decribe_type_bits") != 0))
  27097. {
  27098. int typ;
  27099. typ = unchecked_type(p);
  27100. if ((typ < T_INTEGER) || (typ > T_COMPLEX))
  27101. {
  27102. fprintf(stderr, "%s%s[%d]: not a number, but %s (%d)%s\n", BOLD_TEXT, func, line, check_name(typ), typ, UNBOLD_TEXT);
  27103. if (stop_at_error) abort();
  27104. }
  27105. }
  27106. return(p);
  27107. }
  27108. static s7_pointer check_ref8(s7_pointer p, const char *func, int line)
  27109. {
  27110. int typ;
  27111. typ = unchecked_type(p);
  27112. if ((!t_sequence_p[typ]) && (!t_structure_p[typ]) && (!is_any_closure(p))) /* closure calling itself an iterator?? */
  27113. {
  27114. fprintf(stderr, "%s%s[%d]: not a sequence or structure, but %s (%d)%s\n", BOLD_TEXT, func, line, check_name(typ), typ, UNBOLD_TEXT);
  27115. if (stop_at_error) abort();
  27116. }
  27117. return(p);
  27118. }
  27119. static s7_pointer check_ref9(s7_pointer p, const char *func, int line)
  27120. {
  27121. int typ;
  27122. typ = unchecked_type(p);
  27123. if ((typ != T_LET) && (typ != T_C_OBJECT) && (!is_any_closure(p)) && (!is_any_macro(p)))
  27124. {
  27125. fprintf(stderr, "%s%s[%d]: not a possible method holder, but %s (%d)%s\n", BOLD_TEXT, func, line, check_name(typ), typ, UNBOLD_TEXT);
  27126. if (stop_at_error) abort();
  27127. }
  27128. return(p);
  27129. }
  27130. static s7_pointer check_ref10(s7_pointer p, const char *func, int line)
  27131. {
  27132. int typ;
  27133. typ = unchecked_type(p);
  27134. if ((typ != T_PAIR) && (typ != T_NIL) && (typ != T_SYMBOL))
  27135. {
  27136. fprintf(stderr, "%s%s[%d]: arglist is %s (%d)%s?\n", BOLD_TEXT, func, line, check_name(typ), typ, UNBOLD_TEXT);
  27137. if (stop_at_error) abort();
  27138. }
  27139. return(p);
  27140. }
  27141. static s7_pointer check_ref11(s7_pointer p, const char *func, int line)
  27142. {
  27143. int typ;
  27144. typ = unchecked_type(p);
  27145. if ((typ < T_CLOSURE) && (typ != T_BOOLEAN)) /* actually #t is an error here */
  27146. {
  27147. fprintf(stderr, "%s%s[%d]: setter is %s (%d)%s?\n", BOLD_TEXT, func, line, check_name(typ), typ, UNBOLD_TEXT);
  27148. if (stop_at_error) abort();
  27149. }
  27150. return(p);
  27151. }
  27152. static s7_pointer check_nref(s7_pointer p, const char *func, int line)
  27153. {
  27154. int typ;
  27155. typ = unchecked_type(p);
  27156. if (typ == T_FREE)
  27157. {
  27158. fprintf(stderr, "%s%s[%d]: attempt to use cleared type%s\n", BOLD_TEXT, func, line, UNBOLD_TEXT);
  27159. if (stop_at_error) abort();
  27160. }
  27161. if ((typ < 0) || (typ >= NUM_TYPES))
  27162. {
  27163. fprintf(stderr, "%s%s[%d]: attempt to use messed up cell (type: %d)%s\n", BOLD_TEXT, func, line, typ, UNBOLD_TEXT);
  27164. if (stop_at_error) abort();
  27165. }
  27166. return(p);
  27167. }
  27168. static void print_gc_info(s7_pointer obj, int line)
  27169. {
  27170. fprintf(stderr, "%s%p is free (line %d), current: %s[%d], previous: %s[%d], gc call: %s[%d], clear: %d, alloc: %s[%d]%s\n",
  27171. BOLD_TEXT,
  27172. obj, line,
  27173. obj->current_alloc_func, obj->current_alloc_line,
  27174. obj->previous_alloc_func, obj->previous_alloc_line,
  27175. obj->gc_func, obj->gc_line, obj->clear_line, obj->alloc_func, obj->alloc_line,
  27176. UNBOLD_TEXT);
  27177. abort();
  27178. }
  27179. static void show_opt1_bits(s7_scheme *sc, s7_pointer p, const char *func, int line)
  27180. {
  27181. fprintf(stderr, "%sopt1 %s[%d]: %p->%p %x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", BOLD_TEXT, func, line, p, p->object.cons.opt1, p->debugger_bits,
  27182. ((p->debugger_bits & E_SET) != 0) ? " e-set" : "",
  27183. ((p->debugger_bits & E_FAST) != 0) ? " fast" : "",
  27184. ((p->debugger_bits & E_CFUNC) != 0) ? " cfunc" : "",
  27185. ((p->debugger_bits & E_CLAUSE) != 0) ? " clause" : "",
  27186. ((p->debugger_bits & E_BACK) != 0) ? " back" : "",
  27187. ((p->debugger_bits & E_LAMBDA) != 0) ? " lambda" : "",
  27188. ((p->debugger_bits & E_SYM) != 0) ? " sym" : "",
  27189. ((p->debugger_bits & E_PAIR) != 0) ? " pair" : "",
  27190. ((p->debugger_bits & E_CON) != 0) ? " con" : "",
  27191. ((p->debugger_bits & E_GOTO) != 0) ? " goto" : "",
  27192. ((p->debugger_bits & E_VECTOR) != 0) ? " vector" : "",
  27193. ((p->debugger_bits & E_ANY) != 0) ? " any" : "",
  27194. ((p->debugger_bits & E_SLOT) != 0) ? " slot" : "",
  27195. ((p->debugger_bits & S_HASH) != 0) ? " raw-hash" : "",
  27196. UNBOLD_TEXT);
  27197. }
  27198. static s7_pointer opt1_1(s7_scheme *sc, s7_pointer p, unsigned int role, const char *func, int line)
  27199. {
  27200. if ((!opt1_is_set(p)) ||
  27201. ((!opt1_role_matches(p, role)) &&
  27202. (role != E_ANY)))
  27203. {
  27204. show_opt1_bits(sc, p, func, line);
  27205. if (stop_at_error) abort();
  27206. }
  27207. return(p->object.cons.opt1);
  27208. }
  27209. static s7_pointer set_opt1_1(s7_scheme *sc, s7_pointer p, s7_pointer x, unsigned int role, const char *func, int line)
  27210. {
  27211. p->object.cons.opt1 = x;
  27212. set_opt1_role(p, role);
  27213. set_opt1_is_set(p);
  27214. return(x);
  27215. }
  27216. static unsigned long long int s_hash_1(s7_scheme *sc, s7_pointer p, const char *func, int line)
  27217. {
  27218. if ((!opt1_is_set(p)) ||
  27219. (!opt1_role_matches(p, S_HASH)))
  27220. {
  27221. show_opt1_bits(sc, p, func, line);
  27222. if (stop_at_error) abort();
  27223. }
  27224. return(p->object.sym_cons.hash);
  27225. }
  27226. static void set_s_hash_1(s7_scheme *sc, s7_pointer p, unsigned long long int x, const char *func, int line)
  27227. {
  27228. p->object.sym_cons.hash = x;
  27229. set_opt1_role(p, S_HASH);
  27230. set_opt1_is_set(p);
  27231. }
  27232. static void show_opt2_bits(s7_scheme *sc, s7_pointer p, const char *func, int line, unsigned int role)
  27233. {
  27234. fprintf(stderr, "%s%s[%d]: opt2: %p->%p is %x%s%s%s%s%s%s%s%s%s but expects %x%s%s%s%s%s%s%s%s%s%s\n",
  27235. BOLD_TEXT, func, line, p, p->object.cons.opt2,
  27236. p->debugger_bits,
  27237. ((p->debugger_bits & F_SET) != 0) ? " f-set" : "",
  27238. ((p->debugger_bits & F_KEY) != 0) ? " key" : "",
  27239. ((p->debugger_bits & F_SLOW) != 0) ? " slow" : "",
  27240. ((p->debugger_bits & F_SYM) != 0) ? " sym" : "",
  27241. ((p->debugger_bits & F_PAIR) != 0) ? " pair" : "",
  27242. ((p->debugger_bits & F_CON) != 0) ? " con" : "",
  27243. ((p->debugger_bits & F_CALL) != 0) ? " call" : "",
  27244. ((p->debugger_bits & F_LAMBDA) != 0) ? " lambda" : "",
  27245. ((p->debugger_bits & S_NAME) != 0) ? " raw-name" : "",
  27246. role,
  27247. ((role & F_SET) != 0) ? " f-set" : "",
  27248. ((role & F_KEY) != 0) ? " key" : "",
  27249. ((role & F_SLOW) != 0) ? " slow" : "",
  27250. ((role & F_SYM) != 0) ? " sym" : "",
  27251. ((role & F_PAIR) != 0) ? " pair" : "",
  27252. ((role & F_CON) != 0) ? " con" : "",
  27253. ((role & F_CALL) != 0) ? " call" : "",
  27254. ((role & F_LAMBDA) != 0) ? " lambda" : "",
  27255. ((role & S_NAME) != 0) ? " raw-name" : "",
  27256. UNBOLD_TEXT);
  27257. }
  27258. static s7_pointer opt2_1(s7_scheme *sc, s7_pointer p, unsigned int role, const char *func, int line)
  27259. {
  27260. if ((!opt2_is_set(p)) ||
  27261. (!opt2_role_matches(p, role)))
  27262. {
  27263. show_opt2_bits(sc, p, func, line, role);
  27264. fprintf(stderr, "p: %s\n", DISPLAY(p));
  27265. if (stop_at_error) abort();
  27266. }
  27267. return(p->object.cons.opt2);
  27268. }
  27269. static void set_opt2_1(s7_scheme *sc, s7_pointer p, s7_pointer x, unsigned int role, const char *func, int line)
  27270. {
  27271. p->object.cons.opt2 = x;
  27272. set_opt2_role(p, role);
  27273. set_opt2_is_set(p);
  27274. }
  27275. static const char *s_name_1(s7_scheme *sc, s7_pointer p, const char *func, int line)
  27276. {
  27277. if ((!opt2_is_set(p)) ||
  27278. (!opt2_role_matches(p, S_NAME)))
  27279. {
  27280. show_opt2_bits(sc, p, func, line, (unsigned int)S_NAME);
  27281. if (stop_at_error) abort();
  27282. }
  27283. return(p->object.sym_cons.fstr);
  27284. }
  27285. static void set_s_name_1(s7_scheme *sc, s7_pointer p, const char *str, const char *func, int line)
  27286. {
  27287. p->object.sym_cons.fstr = str;
  27288. set_opt2_role(p, S_NAME);
  27289. set_opt2_is_set(p);
  27290. }
  27291. static void show_opt3_bits(s7_scheme *sc, s7_pointer p, const char *func, int line)
  27292. {
  27293. fprintf(stderr, "%s%s[%d]: opt3: %x%s%s%s%s%s%s%s%s%s\n", BOLD_TEXT, func, line,
  27294. p->debugger_bits,
  27295. ((p->debugger_bits & G_SET) != 0) ? " g-set" : "",
  27296. ((p->debugger_bits & G_ARGLEN) != 0) ? " arglen" : "",
  27297. ((p->debugger_bits & G_SYM) != 0) ? " sym" : "",
  27298. ((p->debugger_bits & G_AND) != 0) ? " and" : "",
  27299. ((p->debugger_bits & S_LINE) != 0) ? " line" : "",
  27300. ((p->debugger_bits & S_LEN) != 0) ? " len" : "",
  27301. ((p->debugger_bits & S_OP) != 0) ? " op" : "",
  27302. ((p->debugger_bits & S_SYNOP) != 0) ? " syn-op" : "",
  27303. UNBOLD_TEXT);
  27304. }
  27305. static s7_pointer opt3_1(s7_scheme *sc, s7_pointer p, unsigned int role, const char *func, int line)
  27306. {
  27307. if ((!opt3_is_set(p)) ||
  27308. (!opt3_role_matches(p, role)))
  27309. {
  27310. show_opt3_bits(sc, p, func, line);
  27311. if (stop_at_error) abort();
  27312. }
  27313. return(p->object.cons.opt3);
  27314. }
  27315. static void set_opt3_1(s7_scheme *sc, s7_pointer p, s7_pointer x, unsigned int role, const char *func, int line)
  27316. {
  27317. typeflag(p) &= ~(T_OPTIMIZED | T_LINE_NUMBER);
  27318. p->object.cons.opt3 = x;
  27319. set_opt3_is_set(p);
  27320. set_opt3_role(p, role);
  27321. }
  27322. /* S_LINE */
  27323. static unsigned int s_line_1(s7_scheme *sc, s7_pointer p, const char *func, int line)
  27324. {
  27325. if ((!opt3_is_set(p)) ||
  27326. ((p->debugger_bits & S_LINE) == 0) ||
  27327. (!has_line_number(p)))
  27328. {
  27329. show_opt3_bits(sc, p, func, line);
  27330. if (stop_at_error) abort();
  27331. }
  27332. return(p->object.sym_cons.line);
  27333. }
  27334. static void set_s_line_1(s7_scheme *sc, s7_pointer p, unsigned int x, const char *func, int line)
  27335. {
  27336. p->object.sym_cons.line = x;
  27337. (p)->debugger_bits = (S_LINE | (p->debugger_bits & ~S_LEN)); /* turn on line, cancel len */
  27338. set_opt3_is_set(p);
  27339. }
  27340. /* S_LEN (collides with S_LINE) */
  27341. static unsigned int s_len_1(s7_scheme *sc, s7_pointer p, const char *func, int line)
  27342. {
  27343. if ((!opt3_is_set(p)) ||
  27344. ((p->debugger_bits & S_LEN) == 0) ||
  27345. (has_line_number(p)))
  27346. {
  27347. show_opt3_bits(sc, p, func, line);
  27348. if (stop_at_error) abort();
  27349. }
  27350. return(p->object.sym_cons.line);
  27351. }
  27352. static void set_s_len_1(s7_scheme *sc, s7_pointer p, unsigned int x, const char *func, int line)
  27353. {
  27354. typeflag(p) &= ~(T_LINE_NUMBER);
  27355. p->object.sym_cons.line = x;
  27356. (p)->debugger_bits = (S_LEN | (p->debugger_bits & ~(S_LINE)));
  27357. set_opt3_is_set(p);
  27358. }
  27359. /* S_OP */
  27360. static unsigned int s_op_1(s7_scheme *sc, s7_pointer p, const char *func, int line)
  27361. {
  27362. if ((!opt3_is_set(p)) ||
  27363. ((p->debugger_bits & S_OP) == 0))
  27364. {
  27365. show_opt3_bits(sc, p, func, line);
  27366. if (stop_at_error) abort();
  27367. }
  27368. return(p->object.sym_cons.op);
  27369. }
  27370. static void set_s_op_1(s7_scheme *sc, s7_pointer p, unsigned int x, const char *func, int line)
  27371. {
  27372. p->object.sym_cons.op = x;
  27373. (p)->debugger_bits = (S_OP | (p->debugger_bits & ~(S_SYNOP)));
  27374. set_opt3_is_set(p);
  27375. }
  27376. /* S_SYNOP (collides with S_OP) */
  27377. static unsigned int s_syn_op_1(s7_scheme *sc, s7_pointer p, const char *func, int line)
  27378. {
  27379. if ((!opt3_is_set(p)) ||
  27380. ((p->debugger_bits & S_SYNOP) == 0))
  27381. {
  27382. show_opt3_bits(sc, p, func, line);
  27383. if (stop_at_error) abort();
  27384. }
  27385. return(p->object.sym_cons.op);
  27386. }
  27387. static void set_s_syn_op_1(s7_scheme *sc, s7_pointer p, unsigned int x, const char *func, int line)
  27388. {
  27389. p->object.sym_cons.op = x;
  27390. (p)->debugger_bits = (S_SYNOP | (p->debugger_bits & ~(S_OP)));
  27391. set_opt3_is_set(p);
  27392. }
  27393. static void print_debugging_state(s7_scheme *sc, s7_pointer obj, s7_pointer port)
  27394. {
  27395. /* show current state, current allocated state, and previous allocated state.
  27396. */
  27397. char *current_bits, *allocated_bits, *previous_bits, *str;
  27398. int save_typeflag, len, nlen;
  27399. const char *excl_name;
  27400. if (is_free(obj))
  27401. excl_name = "free cell!";
  27402. else excl_name = "unknown object!";
  27403. current_bits = describe_type_bits(sc, obj);
  27404. save_typeflag = typeflag(obj);
  27405. typeflag(obj) = obj->current_alloc_type;
  27406. allocated_bits = describe_type_bits(sc, obj);
  27407. typeflag(obj) = obj->previous_alloc_type;
  27408. previous_bits = describe_type_bits(sc, obj);
  27409. typeflag(obj) = save_typeflag;
  27410. len = safe_strlen(excl_name) +
  27411. safe_strlen(current_bits) + safe_strlen(allocated_bits) + safe_strlen(previous_bits) +
  27412. safe_strlen(obj->previous_alloc_func) + safe_strlen(obj->current_alloc_func) + 512;
  27413. tmpbuf_malloc(str, len);
  27414. nlen = snprintf(str, len,
  27415. "\n<%s %s,\n current: %s[%d] %s,\n previous: %s[%d] %s\n hloc: %d (%d uses), free: %s[%d], clear: %d, alloc: %s[%d]>",
  27416. excl_name, current_bits,
  27417. obj->current_alloc_func, obj->current_alloc_line, allocated_bits,
  27418. obj->previous_alloc_func, obj->previous_alloc_line, previous_bits,
  27419. heap_location(obj), obj->uses,
  27420. obj->gc_func, obj->gc_line, obj->clear_line, obj->alloc_func, obj->alloc_line);
  27421. free(current_bits);
  27422. free(allocated_bits);
  27423. free(previous_bits);
  27424. if (is_null(port))
  27425. fprintf(stderr, "%p: %s\n", obj, str);
  27426. else port_write_string(port)(sc, str, nlen, port);
  27427. tmpbuf_free(str, len);
  27428. }
  27429. static s7_pointer check_null_sym(s7_scheme *sc, s7_pointer p, s7_pointer sym, int line, const char *func)
  27430. {
  27431. if (!p)
  27432. {
  27433. fprintf(stderr, "%s%s[%d]: %s unbound%s\n", BOLD_TEXT, func, line, symbol_name(sym), UNBOLD_TEXT);
  27434. if (stop_at_error) abort();
  27435. }
  27436. return(p);
  27437. }
  27438. #endif
  27439. static void iterator_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info *ci)
  27440. {
  27441. if (use_write == USE_READABLE_WRITE)
  27442. {
  27443. if (iterator_is_at_end(obj))
  27444. port_write_string(port)(sc, "(make-iterator #())", 19, port);
  27445. else
  27446. {
  27447. s7_pointer seq;
  27448. seq = iterator_sequence(obj);
  27449. if ((is_string(seq)) && (!is_byte_vector(seq)))
  27450. {
  27451. port_write_string(port)(sc, "(make-iterator \"", 16, port);
  27452. port_write_string(port)(sc, (char *)(string_value(seq) + iterator_position(obj)), string_length(seq) - iterator_position(obj), port);
  27453. port_write_string(port)(sc, "\")", 2, port);
  27454. }
  27455. else
  27456. {
  27457. if (iterator_position(obj) > 0)
  27458. port_write_string(port)(sc, "(let ((iter (make-iterator ", 27, port);
  27459. else port_write_string(port)(sc, "(make-iterator ", 15, port);
  27460. object_to_port_with_circle_check(sc, iterator_sequence(obj), port, use_write, ci);
  27461. if (iterator_position(obj) > 0)
  27462. {
  27463. int nlen;
  27464. char *str;
  27465. str = (char *)malloc(128 * sizeof(char));
  27466. nlen = snprintf(str, 128, "))) (do ((i 0 (+ i 1))) ((= i %lld) iter) (iterate iter)))", iterator_position(obj));
  27467. port_write_string(port)(sc, str, nlen, port);
  27468. free(str);
  27469. }
  27470. else port_write_character(port)(sc, ')', port);
  27471. }
  27472. }
  27473. }
  27474. else
  27475. {
  27476. const char *str;
  27477. str = type_name(sc, iterator_sequence(obj), NO_ARTICLE);
  27478. port_write_string(port)(sc, "#<iterator: ", 12, port);
  27479. port_write_string(port)(sc, str, safe_strlen(str), port);
  27480. port_write_character(port)(sc, '>', port);
  27481. }
  27482. }
  27483. static void baffle_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port)
  27484. {
  27485. int nlen;
  27486. char buf[64];
  27487. nlen = snprintf(buf, 64, "#<baffle: %d>", baffle_key(obj));
  27488. port_write_string(port)(sc, buf, nlen, port);
  27489. }
  27490. static void c_pointer_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write)
  27491. {
  27492. int nlen;
  27493. char buf[64];
  27494. if (use_write == USE_READABLE_WRITE)
  27495. nlen = snprintf(buf, 64, "(c-pointer " INT_FORMAT ")", (ptr_int)raw_pointer(obj));
  27496. else nlen = snprintf(buf, 64, "#<c_pointer %p>", raw_pointer(obj));
  27497. port_write_string(port)(sc, buf, nlen, port);
  27498. }
  27499. static void rng_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write)
  27500. {
  27501. int nlen;
  27502. char buf[128];
  27503. #if WITH_GMP
  27504. if (use_write == USE_READABLE_WRITE)
  27505. nlen = snprintf(buf, 128, "#<unprint-readable object>");
  27506. else nlen = snprintf(buf, 128, "#<rng %p>", obj);
  27507. #else
  27508. if (use_write == USE_READABLE_WRITE)
  27509. nlen = snprintf(buf, 128, "(random-state %llu %llu)", random_seed(obj), random_carry(obj));
  27510. else nlen = snprintf(buf, 128, "#<rng %llu %llu>", random_seed(obj), random_carry(obj));
  27511. #endif
  27512. port_write_string(port)(sc, buf, nlen, port);
  27513. }
  27514. static void object_to_port(s7_scheme *sc, s7_pointer obj, s7_pointer port, use_write_t use_write, shared_info *ci)
  27515. {
  27516. int nlen;
  27517. char *str;
  27518. switch (type(obj))
  27519. {
  27520. case T_FLOAT_VECTOR:
  27521. case T_INT_VECTOR:
  27522. int_or_float_vector_to_port(sc, obj, port, use_write);
  27523. break;
  27524. case T_VECTOR:
  27525. vector_to_port(sc, obj, port, use_write, ci);
  27526. break;
  27527. case T_PAIR:
  27528. list_to_port(sc, obj, port, use_write, ci);
  27529. break;
  27530. case T_HASH_TABLE:
  27531. hash_table_to_port(sc, obj, port, use_write, ci);
  27532. break;
  27533. case T_ITERATOR:
  27534. iterator_to_port(sc, obj, port, use_write, ci);
  27535. break;
  27536. case T_LET:
  27537. let_to_port(sc, obj, port, use_write, ci);
  27538. break;
  27539. case T_UNIQUE:
  27540. /* if file has #<eof> it causes read to return #<eof> -> end of read! what is readable version? */
  27541. if ((use_write == USE_READABLE_WRITE) &&
  27542. (obj == sc->eof_object))
  27543. port_write_string(port)(sc, "(begin #<eof>)", 14, port);
  27544. else port_write_string(port)(sc, unique_name(obj), unique_name_length(obj), port);
  27545. break;
  27546. case T_BOOLEAN:
  27547. case T_NIL:
  27548. case T_UNSPECIFIED:
  27549. port_write_string(port)(sc, unique_name(obj), unique_name_length(obj), port);
  27550. break;
  27551. case T_INPUT_PORT:
  27552. input_port_to_port(sc, obj, port, use_write);
  27553. break;
  27554. case T_OUTPUT_PORT:
  27555. output_port_to_port(sc, obj, port, use_write);
  27556. break;
  27557. case T_COUNTER:
  27558. port_write_string(port)(sc, "#<counter>", 10, port);
  27559. break;
  27560. case T_BAFFLE:
  27561. baffle_to_port(sc, obj, port);
  27562. break;
  27563. case T_INTEGER:
  27564. if (has_print_name(obj))
  27565. port_write_string(port)(sc, print_name(obj), print_name_length(obj), port);
  27566. else
  27567. {
  27568. nlen = 0;
  27569. str = integer_to_string_base_10_no_width(obj, &nlen);
  27570. if (nlen > 0)
  27571. {
  27572. set_print_name(obj, str, nlen);
  27573. port_write_string(port)(sc, str, nlen, port);
  27574. }
  27575. else port_display(port)(sc, str, port);
  27576. }
  27577. break;
  27578. case T_REAL:
  27579. case T_RATIO:
  27580. case T_COMPLEX:
  27581. if (has_print_name(obj))
  27582. port_write_string(port)(sc, print_name(obj), print_name_length(obj), port);
  27583. else
  27584. {
  27585. nlen = 0;
  27586. str = number_to_string_base_10(obj, 0, float_format_precision, 'g', &nlen, use_write); /* was 14 */
  27587. set_print_name(obj, str, nlen);
  27588. port_write_string(port)(sc, str, nlen, port);
  27589. }
  27590. break;
  27591. #if WITH_GMP
  27592. case T_BIG_INTEGER:
  27593. case T_BIG_RATIO:
  27594. case T_BIG_REAL:
  27595. case T_BIG_COMPLEX:
  27596. nlen = 0;
  27597. str = big_number_to_string_with_radix(obj, BASE_10, 0, &nlen, use_write);
  27598. port_write_string(port)(sc, str, nlen, port);
  27599. free(str);
  27600. break;
  27601. #endif
  27602. case T_SYMBOL:
  27603. symbol_to_port(sc, obj, port, use_write);
  27604. break;
  27605. case T_SYNTAX:
  27606. port_display(port)(sc, symbol_name(syntax_symbol(obj)), port);
  27607. break;
  27608. case T_STRING:
  27609. if (is_byte_vector(obj))
  27610. byte_vector_to_port(sc, obj, port, use_write);
  27611. else string_to_port(sc, obj, port, use_write);
  27612. break;
  27613. case T_CHARACTER:
  27614. if (use_write == USE_DISPLAY)
  27615. port_write_character(port)(sc, character(obj), port);
  27616. else port_write_string(port)(sc, character_name(obj), character_name_length(obj), port);
  27617. break;
  27618. case T_CLOSURE:
  27619. case T_CLOSURE_STAR:
  27620. if (has_methods(obj))
  27621. {
  27622. /* look for object->string method else fallback on ordinary case.
  27623. * can't use recursion on closure_let here because then the fallback name is #<let>.
  27624. */
  27625. s7_pointer print_func;
  27626. print_func = find_method(sc, closure_let(obj), sc->object_to_string_symbol);
  27627. if (print_func != sc->undefined)
  27628. {
  27629. s7_pointer p;
  27630. p = s7_apply_function(sc, print_func, list_1(sc, obj));
  27631. if (string_length(p) > 0)
  27632. port_write_string(port)(sc, string_value(p), string_length(p), port);
  27633. break;
  27634. }
  27635. }
  27636. if (use_write == USE_READABLE_WRITE)
  27637. write_closure_readably(sc, obj, port);
  27638. else write_closure_name(sc, obj, port);
  27639. break;
  27640. case T_MACRO:
  27641. case T_MACRO_STAR:
  27642. case T_BACRO:
  27643. case T_BACRO_STAR:
  27644. if (use_write == USE_READABLE_WRITE)
  27645. write_macro_readably(sc, obj, port);
  27646. else write_closure_name(sc, obj, port);
  27647. break;
  27648. case T_C_OPT_ARGS_FUNCTION:
  27649. case T_C_RST_ARGS_FUNCTION:
  27650. case T_C_ANY_ARGS_FUNCTION:
  27651. case T_C_FUNCTION:
  27652. case T_C_FUNCTION_STAR:
  27653. port_write_string(port)(sc, c_function_name(obj), c_function_name_length(obj), port);
  27654. break;
  27655. case T_C_MACRO:
  27656. port_write_string(port)(sc, c_macro_name(obj), c_macro_name_length(obj), port);
  27657. break;
  27658. case T_C_POINTER:
  27659. c_pointer_to_port(sc, obj, port, use_write);
  27660. break;
  27661. case T_RANDOM_STATE:
  27662. rng_to_port(sc, obj, port, use_write);
  27663. break;
  27664. case T_CONTINUATION:
  27665. if (use_write == USE_READABLE_WRITE)
  27666. port_write_string(port)(sc, "continuation", 12, port);
  27667. else port_write_string(port)(sc, "#<continuation>", 15, port);
  27668. break;
  27669. case T_GOTO:
  27670. if (use_write == USE_READABLE_WRITE)
  27671. port_write_string(port)(sc, "goto", 4, port);
  27672. else port_write_string(port)(sc, "#<goto>", 7, port);
  27673. break;
  27674. case T_CATCH:
  27675. port_write_string(port)(sc, "#<catch>", 8, port);
  27676. break;
  27677. case T_DYNAMIC_WIND:
  27678. /* this can happen because (*s7* 'stack) can involve dynamic-wind markers */
  27679. port_write_string(port)(sc, "#<dynamic-wind>", 15, port);
  27680. break;
  27681. case T_C_OBJECT:
  27682. if (use_write == USE_READABLE_WRITE)
  27683. str = ((*(c_object_print_readably(obj)))(sc, c_object_value(obj)));
  27684. else str = ((*(c_object_print(obj)))(sc, c_object_value(obj)));
  27685. port_display(port)(sc, str, port);
  27686. free(str);
  27687. break;
  27688. case T_SLOT:
  27689. if (use_write != USE_READABLE_WRITE)
  27690. port_write_character(port)(sc, '\'', port);
  27691. symbol_to_port(sc, slot_symbol(obj), port, use_write);
  27692. port_write_character(port)(sc, ' ', port);
  27693. object_to_port_with_circle_check(sc, slot_value(obj), port, use_write, ci);
  27694. break;
  27695. default:
  27696. #if DEBUGGING
  27697. print_debugging_state(sc, obj, port);
  27698. #else
  27699. {
  27700. char *str, *tmp;
  27701. int len;
  27702. tmp = describe_type_bits(sc, obj);
  27703. len = 32 + safe_strlen(tmp);
  27704. tmpbuf_malloc(str, len);
  27705. if (is_free(obj))
  27706. nlen = snprintf(str, len, "<free cell! %s>", tmp);
  27707. else nlen = snprintf(str, len, "<unknown object! %s>", tmp);
  27708. free(tmp);
  27709. port_write_string(port)(sc, str, nlen, port);
  27710. tmpbuf_free(str, len);
  27711. }
  27712. #endif
  27713. break;
  27714. }
  27715. }
  27716. static void object_to_port_with_circle_check(s7_scheme *sc, s7_pointer vr, s7_pointer port, use_write_t use_write, shared_info *ci)
  27717. {
  27718. if ((ci) &&
  27719. (has_structure(vr)))
  27720. {
  27721. int ref;
  27722. ref = shared_ref(ci, vr);
  27723. if (ref != 0)
  27724. {
  27725. char buf[32];
  27726. int nlen;
  27727. char *p;
  27728. unsigned int len;
  27729. if (ref > 0)
  27730. {
  27731. if (use_write == USE_READABLE_WRITE)
  27732. {
  27733. nlen = snprintf(buf, 32, "(set! {%d} ", ref);
  27734. port_write_string(port)(sc, buf, nlen, port);
  27735. object_to_port(sc, vr, port, USE_READABLE_WRITE, ci);
  27736. port_write_character(port)(sc, ')', port);
  27737. }
  27738. else
  27739. {
  27740. p = pos_int_to_str((s7_int)ref, &len, '=');
  27741. *--p = '#';
  27742. port_write_string(port)(sc, p, len, port);
  27743. object_to_port(sc, vr, port, DONT_USE_DISPLAY(use_write), ci);
  27744. }
  27745. }
  27746. else
  27747. {
  27748. if (use_write == USE_READABLE_WRITE)
  27749. {
  27750. nlen = snprintf(buf, 32, "{%d}", -ref);
  27751. port_write_string(port)(sc, buf, nlen, port);
  27752. }
  27753. else
  27754. {
  27755. p = pos_int_to_str((s7_int)(-ref), &len, '#');
  27756. *--p = '#';
  27757. port_write_string(port)(sc, p, len, port);
  27758. }
  27759. }
  27760. return;
  27761. }
  27762. }
  27763. object_to_port(sc, vr, port, use_write, ci);
  27764. }
  27765. static void setup_shared_reads(s7_scheme *sc, s7_pointer port, shared_info *ci)
  27766. {
  27767. int i;
  27768. char buf[64];
  27769. port_write_string(port)(sc, "(let (", 6, port);
  27770. for (i = 1; i <= ci->top; i++)
  27771. {
  27772. int len;
  27773. len = snprintf(buf, 64, "({%d} #f)", i);
  27774. port_write_string(port)(sc, buf, len, port);
  27775. }
  27776. port_write_string(port)(sc, ") ", 2, port);
  27777. }
  27778. static void finish_shared_reads(s7_scheme *sc, s7_pointer port, shared_info *ci)
  27779. {
  27780. port_write_character(port)(sc, ')', port);
  27781. }
  27782. static s7_pointer object_out(s7_scheme *sc, s7_pointer obj, s7_pointer strport, use_write_t choice)
  27783. {
  27784. if ((has_structure(obj)) &&
  27785. (obj != sc->rootlet))
  27786. {
  27787. shared_info *ci;
  27788. ci = make_shared_info(sc, obj, choice != USE_READABLE_WRITE);
  27789. if (ci)
  27790. {
  27791. if (choice == USE_READABLE_WRITE)
  27792. {
  27793. setup_shared_reads(sc, strport, ci);
  27794. object_to_port_with_circle_check(sc, obj, strport, choice, ci);
  27795. finish_shared_reads(sc, strport, ci);
  27796. }
  27797. else object_to_port_with_circle_check(sc, obj, strport, choice, ci);
  27798. return(obj);
  27799. }
  27800. }
  27801. object_to_port(sc, obj, strport, choice, NULL);
  27802. return(obj);
  27803. }
  27804. static s7_pointer format_ports = NULL;
  27805. static s7_pointer open_format_port(s7_scheme *sc)
  27806. {
  27807. s7_pointer x;
  27808. int len;
  27809. if (format_ports)
  27810. {
  27811. x = format_ports;
  27812. format_ports = (s7_pointer)(port_port(x)->next);
  27813. port_position(x) = 0;
  27814. port_data(x)[0] = '\0';
  27815. return(x);
  27816. }
  27817. len = FORMAT_PORT_LENGTH;
  27818. x = alloc_pointer();
  27819. set_type(x, T_OUTPUT_PORT);
  27820. port_port(x) = (port_t *)calloc(1, sizeof(port_t));
  27821. port_type(x) = STRING_PORT;
  27822. port_is_closed(x) = false;
  27823. port_data_size(x) = len;
  27824. port_data(x) = (unsigned char *)malloc(len * sizeof(unsigned char)); /* was +8 */
  27825. port_data(x)[0] = '\0';
  27826. port_position(x) = 0;
  27827. port_needs_free(x) = false;
  27828. port_read_character(x) = output_read_char;
  27829. port_read_line(x) = output_read_line;
  27830. port_display(x) = string_display;
  27831. port_write_character(x) = string_write_char;
  27832. port_write_string(x) = string_write_string;
  27833. return(x);
  27834. }
  27835. static void close_format_port(s7_scheme *sc, s7_pointer port)
  27836. {
  27837. port_port(port)->next = (void *)format_ports;
  27838. format_ports = port;
  27839. }
  27840. static char *s7_object_to_c_string_1(s7_scheme *sc, s7_pointer obj, use_write_t use_write, int *nlen)
  27841. {
  27842. char *str;
  27843. s7_pointer strport;
  27844. strport = open_format_port(sc);
  27845. object_out(sc, obj, strport, use_write);
  27846. if (nlen) (*nlen) = port_position(strport);
  27847. str = (char *)malloc((port_position(strport) + 1) * sizeof(char));
  27848. memcpy((void *)str, (void *)port_data(strport), port_position(strport));
  27849. str[port_position(strport)] = '\0';
  27850. close_format_port(sc, strport);
  27851. return(str);
  27852. }
  27853. char *s7_object_to_c_string(s7_scheme *sc, s7_pointer obj)
  27854. {
  27855. return(s7_object_to_c_string_1(sc, obj, USE_WRITE, NULL));
  27856. }
  27857. s7_pointer s7_object_to_string(s7_scheme *sc, s7_pointer obj, bool use_write) /* unavoidable backwards compatibility rigidity here */
  27858. {
  27859. char *str;
  27860. int len = 0;
  27861. str = s7_object_to_c_string_1(sc, obj, (use_write) ? USE_WRITE : USE_DISPLAY, &len);
  27862. if (str)
  27863. return(make_string_uncopied_with_length(sc, str, len));
  27864. return(s7_make_string_with_length(sc, "", 0));
  27865. }
  27866. /* -------------------------------- newline -------------------------------- */
  27867. void s7_newline(s7_scheme *sc, s7_pointer port)
  27868. {
  27869. s7_write_char(sc, '\n', port);
  27870. }
  27871. static s7_pointer g_newline(s7_scheme *sc, s7_pointer args)
  27872. {
  27873. #define H_newline "(newline (port (current-output-port))) writes a carriage return to the port"
  27874. #define Q_newline s7_make_signature(sc, 2, sc->T, sc->is_output_port_symbol)
  27875. s7_pointer port;
  27876. if (is_not_null(args))
  27877. port = car(args);
  27878. else port = sc->output_port;
  27879. if (!is_output_port(port))
  27880. {
  27881. if (port == sc->F) return(sc->unspecified);
  27882. method_or_bust_with_type(sc, port, sc->newline_symbol, args, an_output_port_string, 0);
  27883. }
  27884. s7_newline(sc, port);
  27885. return(sc->unspecified);
  27886. }
  27887. static s7_pointer c_newline(s7_scheme *sc) {s7_newline(sc, sc->output_port); return(sc->unspecified);}
  27888. PF_0(newline, c_newline)
  27889. /* -------------------------------- write -------------------------------- */
  27890. void s7_write(s7_scheme *sc, s7_pointer obj, s7_pointer port)
  27891. {
  27892. if (port != sc->F)
  27893. {
  27894. if (port_is_closed(port))
  27895. s7_wrong_type_arg_error(sc, "write", 2, port, "an open output port");
  27896. object_out(sc, obj, port, USE_WRITE);
  27897. }
  27898. }
  27899. static s7_pointer g_write(s7_scheme *sc, s7_pointer args)
  27900. {
  27901. #define H_write "(write obj (port (current-output-port))) writes (object->string obj) to the output port"
  27902. #define Q_write s7_make_signature(sc, 3, sc->T, sc->T, sc->is_output_port_symbol)
  27903. s7_pointer port;
  27904. if (is_pair(cdr(args)))
  27905. port = cadr(args);
  27906. else port = sc->output_port;
  27907. if (!is_output_port(port))
  27908. {
  27909. if (port == sc->F) return(car(args));
  27910. method_or_bust_with_type(sc, port, sc->write_symbol, args, an_output_port_string, 2);
  27911. }
  27912. if (port_is_closed(port))
  27913. return(s7_wrong_type_arg_error(sc, "write", 2, port, "an open output port"));
  27914. return(object_out(sc, car(args), port, USE_WRITE));
  27915. }
  27916. static s7_pointer c_write_i(s7_scheme *sc, s7_int x) {return(g_write(sc, set_plist_1(sc, make_integer(sc, x))));}
  27917. static s7_pointer c_write_r(s7_scheme *sc, s7_double x) {return(g_write(sc, set_plist_1(sc, make_real(sc, x))));}
  27918. static s7_pointer c_write_p(s7_scheme *sc, s7_pointer x) {return(g_write(sc, set_plist_1(sc, x)));}
  27919. XF_TO_PF(write, c_write_i, c_write_r, c_write_p)
  27920. /* -------------------------------- display -------------------------------- */
  27921. void s7_display(s7_scheme *sc, s7_pointer obj, s7_pointer port)
  27922. {
  27923. if (port != sc->F)
  27924. {
  27925. if (port_is_closed(port))
  27926. s7_wrong_type_arg_error(sc, "display", 2, port, "an open output port");
  27927. object_out(sc, obj, port, USE_DISPLAY);
  27928. }
  27929. }
  27930. static s7_pointer g_display(s7_scheme *sc, s7_pointer args)
  27931. {
  27932. #define H_display "(display obj (port (current-output-port))) prints obj"
  27933. #define Q_display s7_make_signature(sc, 3, sc->T, sc->T, sc->is_output_port_symbol)
  27934. s7_pointer port;
  27935. if (is_pair(cdr(args)))
  27936. port = cadr(args);
  27937. else port = sc->output_port;
  27938. if (!is_output_port(port))
  27939. {
  27940. if (port == sc->F) return(car(args));
  27941. method_or_bust_with_type(sc, port, sc->display_symbol, args, an_output_port_string, 2);
  27942. }
  27943. if (port_is_closed(port))
  27944. return(s7_wrong_type_arg_error(sc, "display", 2, port, "an open output port"));
  27945. return(object_out(sc, car(args), port, USE_DISPLAY));
  27946. }
  27947. static s7_pointer c_display(s7_scheme *sc, s7_pointer x) {return(g_display(sc, set_plist_1(sc, x)));}
  27948. PF_TO_PF(display, c_display)
  27949. /* -------------------------------- call-with-output-string -------------------------------- */
  27950. static s7_pointer g_call_with_output_string(s7_scheme *sc, s7_pointer args)
  27951. {
  27952. #define H_call_with_output_string "(call-with-output-string proc) opens a string port applies proc to it, then returns the collected output"
  27953. #define Q_call_with_output_string s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_procedure_symbol)
  27954. s7_pointer port, proc;
  27955. proc = car(args);
  27956. if (is_let(proc))
  27957. check_method(sc, proc, sc->call_with_output_string_symbol, args);
  27958. if (!s7_is_aritable(sc, proc, 1))
  27959. method_or_bust_with_type(sc, proc, sc->call_with_output_string_symbol, args, make_string_wrapper(sc, "a procedure of one argument (the port)"), 1);
  27960. if ((is_continuation(proc)) || (is_goto(proc)))
  27961. return(wrong_type_argument_with_type(sc, sc->call_with_output_string_symbol, 1, proc, a_normal_procedure_string));
  27962. port = s7_open_output_string(sc);
  27963. push_stack(sc, OP_GET_OUTPUT_STRING_1, sc->F, port);
  27964. push_stack(sc, OP_APPLY, list_1(sc, port), proc);
  27965. return(sc->F);
  27966. }
  27967. static s7_pointer c_call_with_output_string(s7_scheme *sc, s7_pointer x) {return(g_call_with_output_string(sc, set_plist_1(sc, x)));}
  27968. PF_TO_PF(call_with_output_string, c_call_with_output_string)
  27969. /* -------------------------------- call-with-output-file -------------------------------- */
  27970. static s7_pointer g_call_with_output_file(s7_scheme *sc, s7_pointer args)
  27971. {
  27972. #define H_call_with_output_file "(call-with-output-file filename proc) opens filename and calls proc with the output port as its argument"
  27973. #define Q_call_with_output_file pl_sf
  27974. s7_pointer port, file, proc;
  27975. file = car(args);
  27976. if (!is_string(file))
  27977. method_or_bust(sc, file, sc->call_with_output_file_symbol, args, T_STRING, 1);
  27978. proc = cadr(args);
  27979. if (!s7_is_aritable(sc, proc, 1))
  27980. method_or_bust_with_type(sc, proc, sc->call_with_output_file_symbol, args, make_string_wrapper(sc, "a procedure of one argument (the port)"), 2);
  27981. if ((is_continuation(proc)) || is_goto(proc))
  27982. return(wrong_type_argument_with_type(sc, sc->call_with_output_file_symbol, 2, proc, a_normal_procedure_string));
  27983. port = s7_open_output_file(sc, string_value(file), "w");
  27984. push_stack(sc, OP_UNWIND_OUTPUT, sc->F, port);
  27985. push_stack(sc, OP_APPLY, list_1(sc, port), proc);
  27986. return(sc->F);
  27987. }
  27988. static s7_pointer c_call_with_output_file(s7_scheme *sc, s7_pointer x) {return(g_call_with_output_file(sc, set_plist_1(sc, x)));}
  27989. PF_TO_PF(call_with_output_file, c_call_with_output_file)
  27990. /* -------------------------------- with-output-to-string -------------------------------- */
  27991. static s7_pointer g_with_output_to_string(s7_scheme *sc, s7_pointer args)
  27992. {
  27993. #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"
  27994. #define Q_with_output_to_string s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_procedure_symbol)
  27995. s7_pointer old_output_port, p;
  27996. p = car(args);
  27997. if (!is_thunk(sc, p))
  27998. method_or_bust_with_type(sc, p, sc->with_output_to_string_symbol, args, a_thunk_string, 1);
  27999. old_output_port = sc->output_port;
  28000. sc->output_port = s7_open_output_string(sc);
  28001. push_stack(sc, OP_GET_OUTPUT_STRING_1, old_output_port, sc->output_port);
  28002. push_stack(sc, OP_APPLY, sc->nil, p);
  28003. return(sc->F);
  28004. }
  28005. static s7_pointer c_with_output_to_string(s7_scheme *sc, s7_pointer x) {return(g_with_output_to_string(sc, set_plist_1(sc, x)));}
  28006. PF_TO_PF(with_output_to_string, c_with_output_to_string)
  28007. /* (let () (define-macro (mac) (write "123")) (with-output-to-string mac))
  28008. * (string-ref (with-output-to-string (lambda () (write "1234") (values (get-output-string) 1))))
  28009. */
  28010. /* -------------------------------- with-output-to-file -------------------------------- */
  28011. static s7_pointer g_with_output_to_file(s7_scheme *sc, s7_pointer args)
  28012. {
  28013. #define H_with_output_to_file "(with-output-to-file filename thunk) opens filename as the temporary current-output-port and calls thunk"
  28014. #define Q_with_output_to_file pl_sf
  28015. s7_pointer old_output_port, file, proc;
  28016. file = car(args);
  28017. if (!is_string(file))
  28018. method_or_bust(sc, file, sc->with_output_to_file_symbol, args, T_STRING, 1);
  28019. proc = cadr(args);
  28020. if (!is_thunk(sc, proc))
  28021. method_or_bust_with_type(sc, proc, sc->with_output_to_file_symbol, args, a_thunk_string, 2);
  28022. old_output_port = sc->output_port;
  28023. sc->output_port = s7_open_output_file(sc, string_value(file), "w");
  28024. push_stack(sc, OP_UNWIND_OUTPUT, old_output_port, sc->output_port);
  28025. push_stack(sc, OP_APPLY, sc->nil, proc);
  28026. return(sc->F);
  28027. }
  28028. static s7_pointer c_with_output_to_file(s7_scheme *sc, s7_pointer x) {return(g_with_output_to_file(sc, set_plist_1(sc, x)));}
  28029. PF_TO_PF(with_output_to_file, c_with_output_to_file)
  28030. /* -------------------------------- format -------------------------------- */
  28031. static s7_pointer format_error_1(s7_scheme *sc, s7_pointer msg, const char *str, s7_pointer args, format_data *fdat)
  28032. {
  28033. s7_pointer x = NULL, ctrl_str;
  28034. static s7_pointer format_string_1 = NULL, format_string_2, format_string_3, format_string_4;
  28035. if (!format_string_1)
  28036. {
  28037. format_string_1 = s7_make_permanent_string("format: ~S ~{~S~^ ~}: ~A");
  28038. format_string_2 = s7_make_permanent_string("format: ~S: ~A");
  28039. format_string_3 = s7_make_permanent_string("format: ~S ~{~S~^ ~}~&~NT^: ~A");
  28040. format_string_4 = s7_make_permanent_string("format: ~S~&~NT^: ~A");
  28041. }
  28042. if (fdat->orig_str)
  28043. ctrl_str = fdat->orig_str;
  28044. else ctrl_str = make_string_wrapper(sc, str);
  28045. if (fdat->loc == 0)
  28046. {
  28047. if (is_pair(args))
  28048. x = set_elist_4(sc, format_string_1, ctrl_str, args, msg);
  28049. else x = set_elist_3(sc, format_string_2, ctrl_str, msg);
  28050. }
  28051. else
  28052. {
  28053. if (is_pair(args))
  28054. x = set_elist_5(sc, format_string_3, ctrl_str, args, make_integer(sc, fdat->loc + 20), msg);
  28055. else x = set_elist_4(sc, format_string_4, ctrl_str, make_integer(sc, fdat->loc + 20), msg);
  28056. }
  28057. if (fdat->port)
  28058. {
  28059. close_format_port(sc, fdat->port);
  28060. fdat->port = NULL;
  28061. }
  28062. return(s7_error(sc, sc->format_error_symbol, x));
  28063. }
  28064. #define format_error(Sc, Msg, Str, Args, Fdat) \
  28065. do {static s7_pointer _Err_ = NULL; if (!_Err_) _Err_ = s7_make_permanent_string(Msg); return(format_error_1(Sc, _Err_, Str, Args, Fdat));} while (0)
  28066. #define just_format_error(Sc, Msg, Str, Args, Fdat) \
  28067. do {static s7_pointer _Err_ = NULL; if (!_Err_) _Err_ = s7_make_permanent_string(Msg); format_error_1(Sc, _Err_, Str, Args, Fdat);} while (0)
  28068. static void format_append_char(s7_scheme *sc, format_data *fdat, char c, s7_pointer port)
  28069. {
  28070. port_write_character(port)(sc, c, port);
  28071. sc->format_column++;
  28072. /* if c is #\null, is this the right thing to do?
  28073. * We used to return "1 2 3 4" because ~C was first turned into a string (empty in this case)
  28074. * (format #f "1 2~C3 4" #\null)
  28075. * "1 2"
  28076. * Clisp does this:
  28077. * (format nil "1 2~C3 4" (int-char 0))
  28078. * "1 23 4"
  28079. * whereas sbcl says int-char is undefined, and
  28080. * Guile returns "1 2\x003 4"
  28081. */
  28082. }
  28083. static void format_append_newline(s7_scheme *sc, format_data *fdat, s7_pointer port)
  28084. {
  28085. port_write_character(port)(sc, '\n', port);
  28086. sc->format_column = 0;
  28087. }
  28088. static void format_append_string(s7_scheme *sc, format_data *fdat, const char *str, int len, s7_pointer port)
  28089. {
  28090. port_write_string(port)(sc, str, len, port);
  28091. fdat->loc += len;
  28092. sc->format_column += len;
  28093. }
  28094. static void format_append_chars(s7_scheme *sc, format_data *fdat, char pad, int chars, s7_pointer port)
  28095. {
  28096. int j;
  28097. if (chars > 0)
  28098. {
  28099. if (chars < TMPBUF_SIZE)
  28100. {
  28101. for (j = 0; j < chars; j++)
  28102. sc->tmpbuf[j] = pad;
  28103. sc->tmpbuf[chars] = '\0';
  28104. format_append_string(sc, fdat, sc->tmpbuf, chars, port);
  28105. }
  28106. else
  28107. {
  28108. for (j = 0; j < chars; j++)
  28109. format_append_char(sc, fdat, pad, port);
  28110. }
  28111. }
  28112. }
  28113. static int format_read_integer(s7_scheme *sc, int *cur_i, int str_len, const char *str, s7_pointer args, format_data *fdat)
  28114. {
  28115. /* we know that str[*cur_i] is a digit */
  28116. int i, lval = 0;
  28117. for (i = *cur_i; i < str_len - 1; i++)
  28118. {
  28119. int dig;
  28120. dig = digits[(unsigned char)str[i]];
  28121. if (dig < 10)
  28122. {
  28123. #if HAVE_OVERFLOW_CHECKS
  28124. if ((int_multiply_overflow(lval, 10, &lval)) ||
  28125. (int_add_overflow(lval, dig, &lval)))
  28126. break;
  28127. #else
  28128. lval = dig + (lval * 10);
  28129. #endif
  28130. }
  28131. else break;
  28132. }
  28133. if (i >= str_len)
  28134. just_format_error(sc, "numeric argument, but no directive!", str, args, fdat);
  28135. *cur_i = i;
  28136. return(lval);
  28137. }
  28138. static void format_number(s7_scheme *sc, format_data *fdat, int radix, int width, int precision, char float_choice, char pad, s7_pointer port)
  28139. {
  28140. char *tmp;
  28141. int nlen = 0;
  28142. if (width < 0) width = 0;
  28143. /* precision choice depends on float_choice if it's -1 */
  28144. if (precision < 0)
  28145. {
  28146. if ((float_choice == 'e') ||
  28147. (float_choice == 'f') ||
  28148. (float_choice == 'g'))
  28149. precision = 6;
  28150. else
  28151. {
  28152. /* in the "int" cases, precision depends on the arg type */
  28153. switch (type(car(fdat->args)))
  28154. {
  28155. case T_INTEGER:
  28156. case T_RATIO:
  28157. precision = 0;
  28158. break;
  28159. default:
  28160. precision = 6;
  28161. break;
  28162. }
  28163. }
  28164. }
  28165. /* should (format #f "~F" 1/3) return "1/3"?? in CL it's "0.33333334" */
  28166. tmp = number_to_string_with_radix(sc, car(fdat->args), radix, width, precision, float_choice, &nlen);
  28167. if (pad != ' ')
  28168. {
  28169. char *padtmp;
  28170. padtmp = tmp;
  28171. while (*padtmp == ' ') (*(padtmp++)) = pad;
  28172. }
  28173. format_append_string(sc, fdat, tmp, nlen, port);
  28174. free(tmp);
  28175. fdat->args = cdr(fdat->args);
  28176. fdat->ctr++;
  28177. }
  28178. static int format_nesting(const char *str, char opener, char closer, int start, int end) /* start=i, end=str_len-1 */
  28179. {
  28180. int k, nesting = 1;
  28181. for (k = start + 2; k < end; k++)
  28182. if (str[k] == '~')
  28183. {
  28184. if (str[k + 1] == closer)
  28185. {
  28186. nesting--;
  28187. if (nesting == 0)
  28188. return(k - start - 1);
  28189. }
  28190. else
  28191. {
  28192. if (str[k + 1] == opener)
  28193. nesting++;
  28194. }
  28195. }
  28196. return(-1);
  28197. }
  28198. static bool format_method(s7_scheme *sc, const char *str, format_data *fdat, s7_pointer port)
  28199. {
  28200. s7_pointer obj, func;
  28201. obj = car(fdat->args);
  28202. if ((has_methods(obj)) &&
  28203. ((func = find_method(sc, find_let(sc, obj), sc->format_symbol)) != sc->undefined))
  28204. {
  28205. s7_pointer ctrl_str;
  28206. if (fdat->orig_str)
  28207. ctrl_str = fdat->orig_str;
  28208. else ctrl_str = make_string_wrapper(sc, str);
  28209. obj = s7_apply_function(sc, func, cons(sc, ctrl_str, fdat->args));
  28210. if (is_string(obj))
  28211. {
  28212. format_append_string(sc, fdat, string_value(obj), string_length(obj), port);
  28213. fdat->args = cdr(fdat->args);
  28214. fdat->ctr++;
  28215. return(true);
  28216. }
  28217. }
  28218. return(false);
  28219. }
  28220. #define MAX_FORMAT_NUMERIC_ARG 10000
  28221. static int format_n_arg(s7_scheme *sc, const char *str, int str_len, format_data *fdat, s7_pointer args)
  28222. {
  28223. int n;
  28224. if (is_null(fdat->args)) /* (format #f "~nT") */
  28225. just_format_error(sc, "~~N: missing argument", str, args, fdat);
  28226. if (!s7_is_integer(car(fdat->args)))
  28227. just_format_error(sc, "~~N: integer argument required", str, args, fdat);
  28228. n = (int)s7_integer(car(fdat->args));
  28229. if (n < 0)
  28230. just_format_error(sc, "~~N value is negative?", str, args, fdat);
  28231. else
  28232. {
  28233. if (n > MAX_FORMAT_NUMERIC_ARG)
  28234. just_format_error(sc, "~~N value is too big", str, args, fdat);
  28235. }
  28236. fdat->args = cdr(fdat->args); /* I don't think fdat->ctr should be incremented here -- it's for *vector-print-length* etc */
  28237. return(n);
  28238. }
  28239. static int format_numeric_arg(s7_scheme *sc, const char *str, int str_len, format_data *fdat, s7_pointer args, int *i)
  28240. {
  28241. int width;
  28242. width = format_read_integer(sc, i, str_len, str, args, fdat);
  28243. if (width < 0)
  28244. just_format_error(sc, "width value is negative?", str, fdat->args, fdat);
  28245. else
  28246. {
  28247. if (width > MAX_FORMAT_NUMERIC_ARG)
  28248. just_format_error(sc, "width value is too big", str, fdat->args, fdat);
  28249. }
  28250. return(width);
  28251. }
  28252. #if WITH_GMP
  28253. static bool s7_is_one_or_big_one(s7_pointer p);
  28254. #else
  28255. #define s7_is_one_or_big_one(Num) s7_is_one(Num)
  28256. #endif
  28257. static s7_pointer object_to_list(s7_scheme *sc, s7_pointer obj);
  28258. static s7_pointer format_to_port_1(s7_scheme *sc, s7_pointer port, const char *str, s7_pointer args,
  28259. s7_pointer *next_arg, bool with_result, bool columnized, int len, s7_pointer orig_str)
  28260. {
  28261. int i, str_len;
  28262. format_data *fdat;
  28263. s7_pointer deferred_port;
  28264. if ((!with_result) &&
  28265. (port == sc->F))
  28266. return(sc->F);
  28267. if (len <= 0)
  28268. {
  28269. str_len = safe_strlen(str);
  28270. if (str_len == 0)
  28271. {
  28272. if (is_not_null(args))
  28273. {
  28274. static s7_pointer null_err = NULL;
  28275. if (!null_err)
  28276. null_err = s7_make_permanent_string("format control string is null, but there are arguments: ~S");
  28277. return(s7_error(sc, sc->format_error_symbol, set_elist_2(sc, null_err, args)));
  28278. }
  28279. if (with_result)
  28280. return(make_string_wrapper_with_length(sc, "", 0));
  28281. return(sc->F);
  28282. }
  28283. }
  28284. else str_len = len;
  28285. sc->format_depth++;
  28286. if (sc->format_depth >= sc->num_fdats)
  28287. {
  28288. int k, new_num_fdats;
  28289. new_num_fdats = sc->format_depth * 2;
  28290. sc->fdats = (format_data **)realloc(sc->fdats, sizeof(format_data *) * new_num_fdats);
  28291. for (k = sc->num_fdats; k < new_num_fdats; k++) sc->fdats[k] = NULL;
  28292. sc->num_fdats = new_num_fdats;
  28293. }
  28294. fdat = sc->fdats[sc->format_depth];
  28295. if (!fdat)
  28296. {
  28297. fdat = (format_data *)malloc(sizeof(format_data));
  28298. sc->fdats[sc->format_depth] = fdat;
  28299. fdat->curly_len = 0;
  28300. fdat->curly_str = NULL;
  28301. fdat->ctr = 0;
  28302. }
  28303. else
  28304. {
  28305. if (fdat->port)
  28306. close_format_port(sc, fdat->port);
  28307. if (fdat->strport)
  28308. close_format_port(sc, fdat->strport);
  28309. }
  28310. fdat->port = NULL;
  28311. fdat->strport = NULL;
  28312. fdat->loc = 0;
  28313. fdat->args = args;
  28314. fdat->orig_str = orig_str;
  28315. fdat->curly_arg = sc->nil;
  28316. /* choose whether to write to a temporary string port, or simply use the in-coming port
  28317. * if with_result, returned string is wanted.
  28318. * if port is sc->F, no non-string result is wanted.
  28319. * if port is not boolean, it better be a port.
  28320. * if we are about to goto START in eval, and main_stack_op(Sc) == OP_BEGIN1, no return string is wanted -- yow, this is not true
  28321. */
  28322. if (with_result)
  28323. {
  28324. deferred_port = port;
  28325. port = open_format_port(sc);
  28326. fdat->port = port;
  28327. }
  28328. else deferred_port = sc->F;
  28329. for (i = 0; i < str_len - 1; i++)
  28330. {
  28331. if ((unsigned char)(str[i]) == (unsigned char)'~') /* what does MS C want? */
  28332. {
  28333. use_write_t use_write;
  28334. switch (str[i + 1])
  28335. {
  28336. case '%': /* -------- newline -------- */
  28337. /* sbcl apparently accepts numeric args here (including 0) */
  28338. if ((port_data(port)) &&
  28339. (port_position(port) < port_data_size(port)))
  28340. {
  28341. port_data(port)[port_position(port)++] = '\n';
  28342. /* which is actually a bad idea, but as a desperate stopgap, I simply padded
  28343. * the string port string with 8 chars that are not in the length.
  28344. */
  28345. sc->format_column = 0;
  28346. }
  28347. else format_append_newline(sc, fdat, port);
  28348. i++;
  28349. break;
  28350. case '&': /* -------- conditional newline -------- */
  28351. /* this only works if all output goes through format -- display/write for example do not update format_column */
  28352. if (sc->format_column > 0)
  28353. format_append_newline(sc, fdat, port);
  28354. i++;
  28355. break;
  28356. case '~': /* -------- tilde -------- */
  28357. format_append_char(sc, fdat, '~', port);
  28358. i++;
  28359. break;
  28360. case '\n': /* -------- trim white-space -------- */
  28361. for (i = i + 2; i <str_len - 1; i++)
  28362. if (!(white_space[(unsigned char)(str[i])]))
  28363. {
  28364. i--;
  28365. break;
  28366. }
  28367. break;
  28368. case '*': /* -------- ignore arg -------- */
  28369. i++;
  28370. if (is_null(fdat->args)) /* (format #f "~*~A") */
  28371. format_error(sc, "can't skip argument!", str, args, fdat);
  28372. fdat->args = cdr(fdat->args);
  28373. break;
  28374. case '|': /* -------- exit if args nil or ctr > (*s7* 'print-length) -------- */
  28375. if ((is_pair(fdat->args)) &&
  28376. (fdat->ctr >= sc->print_length))
  28377. {
  28378. format_append_string(sc, fdat, " ...", 4, port);
  28379. fdat->args = sc->nil;
  28380. }
  28381. /* fall through */
  28382. case '^': /* -------- exit -------- */
  28383. if (is_null(fdat->args))
  28384. {
  28385. i = str_len;
  28386. goto ALL_DONE;
  28387. }
  28388. i++;
  28389. break;
  28390. case '@': /* -------- plural, 'y' or 'ies' -------- */
  28391. i += 2;
  28392. if ((str[i] != 'P') && (str[i] != 'p'))
  28393. format_error(sc, "unknown '@' directive", str, args, fdat);
  28394. if (!s7_is_real(car(fdat->args))) /* CL accepts non numbers here */
  28395. format_error(sc, "'@P' directive argument is not a real number", str, args, fdat);
  28396. if (!s7_is_one_or_big_one(car(fdat->args)))
  28397. format_append_string(sc, fdat, "ies", 3, port);
  28398. else format_append_char(sc, fdat, 'y', port);
  28399. fdat->args = cdr(fdat->args);
  28400. break;
  28401. case 'P': case 'p': /* -------- plural in 's' -------- */
  28402. if (!s7_is_real(car(fdat->args)))
  28403. format_error(sc, "'P' directive argument is not a real number", str, args, fdat);
  28404. if (!s7_is_one_or_big_one(car(fdat->args)))
  28405. format_append_char(sc, fdat, 's', port);
  28406. i++;
  28407. fdat->args = cdr(fdat->args);
  28408. break;
  28409. case '{': /* -------- iteration -------- */
  28410. {
  28411. int curly_len;
  28412. if (is_null(fdat->args))
  28413. format_error(sc, "missing argument", str, args, fdat);
  28414. curly_len = format_nesting(str, '{', '}', i, str_len - 1);
  28415. if (curly_len == -1)
  28416. format_error(sc, "'{' directive, but no matching '}'", str, args, fdat);
  28417. if (curly_len == 1)
  28418. format_error(sc, "~{~}' doesn't consume any arguments!", str, args, fdat);
  28419. /* 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
  28420. * (cons 1 2) is applicable: ((cons 1 2) 0) -> 1
  28421. * also there can be applicable objects that won't work in the map context (arg not integer etc)
  28422. */
  28423. if (is_not_null(car(fdat->args))) /* (format #f "~{~A ~}" ()) -> "" */
  28424. {
  28425. s7_pointer curly_arg;
  28426. curly_arg = object_to_list(sc, car(fdat->args)); /* if a pair, this simply returns the original */
  28427. if (is_not_null(curly_arg)) /* (format #f "~{~A ~}" #()) -> "" */
  28428. {
  28429. char *curly_str = NULL; /* this is the local (nested) format control string */
  28430. s7_pointer orig_arg;
  28431. if (!is_proper_list(sc, curly_arg))
  28432. format_error(sc, "'{' directive argument should be a proper list or something we can turn into a list", str, args, fdat);
  28433. fdat->curly_arg = curly_arg;
  28434. if (curly_arg != car(fdat->args))
  28435. orig_arg = curly_arg;
  28436. else orig_arg = sc->nil;
  28437. if (curly_len > fdat->curly_len)
  28438. {
  28439. if (fdat->curly_str) free (fdat->curly_str);
  28440. fdat->curly_len = curly_len;
  28441. fdat->curly_str = (char *)malloc(curly_len * sizeof(char));
  28442. }
  28443. curly_str = fdat->curly_str;
  28444. memcpy((void *)curly_str, (void *)(str + i + 2), curly_len - 1);
  28445. curly_str[curly_len - 1] = '\0';
  28446. if ((sc->format_depth < sc->num_fdats - 1) &&
  28447. (sc->fdats[sc->format_depth + 1]))
  28448. sc->fdats[sc->format_depth + 1]->ctr = 0;
  28449. /* it's not easy to use an iterator here instead of a list (so object->list isn't needed above),
  28450. * because the curly brackets may enclose multiple arguments -- we would need to use
  28451. * iterators throughout this function.
  28452. */
  28453. while (is_not_null(curly_arg))
  28454. {
  28455. s7_pointer new_arg = sc->nil;
  28456. format_to_port_1(sc, port, curly_str, curly_arg, &new_arg, false, columnized, curly_len - 1, NULL);
  28457. if (curly_arg == new_arg)
  28458. {
  28459. fdat->curly_arg = sc->nil;
  28460. format_error(sc, "'{...}' doesn't consume any arguments!", str, args, fdat);
  28461. }
  28462. curly_arg = new_arg;
  28463. }
  28464. fdat->curly_arg = sc->nil;
  28465. while (is_pair(orig_arg))
  28466. {
  28467. s7_pointer p;
  28468. p = orig_arg;
  28469. orig_arg = cdr(orig_arg);
  28470. 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 */
  28471. }
  28472. }
  28473. }
  28474. i += (curly_len + 2); /* jump past the ending '}' too */
  28475. fdat->args = cdr(fdat->args);
  28476. fdat->ctr++;
  28477. }
  28478. break;
  28479. case '}':
  28480. format_error(sc, "unmatched '}'", str, args, fdat);
  28481. case 'W': case 'w':
  28482. use_write = USE_READABLE_WRITE;
  28483. goto OBJSTR;
  28484. case 'S': case 's':
  28485. use_write = USE_WRITE;
  28486. goto OBJSTR;
  28487. case 'A': case 'a':
  28488. use_write = USE_DISPLAY;
  28489. OBJSTR:
  28490. /* object->string */
  28491. {
  28492. s7_pointer obj, strport;
  28493. if (is_null(fdat->args))
  28494. format_error(sc, "missing argument", str, args, fdat);
  28495. i++;
  28496. obj = car(fdat->args);
  28497. /* for the column check, we need to know the length of the object->string output */
  28498. if (columnized)
  28499. {
  28500. strport = open_format_port(sc);
  28501. fdat->strport = strport;
  28502. }
  28503. else strport = port;
  28504. object_out(sc, obj, strport, use_write);
  28505. if (columnized)
  28506. {
  28507. if (port_position(strport) >= port_data_size(strport))
  28508. resize_port_data(strport, port_data_size(strport) * 2);
  28509. port_data(strport)[port_position(strport)] = '\0';
  28510. if (port_position(strport) > 0)
  28511. format_append_string(sc, fdat, (const char *)port_data(strport), port_position(strport), port);
  28512. close_format_port(sc, strport);
  28513. fdat->strport = NULL;
  28514. }
  28515. fdat->args = cdr(fdat->args);
  28516. fdat->ctr++;
  28517. }
  28518. break;
  28519. /* -------- numeric args -------- */
  28520. case '0': case '1': case '2': case '3': case '4': case '5':
  28521. case '6': case '7': case '8': case '9': case ',':
  28522. case 'N': case 'n':
  28523. case 'B': case 'b':
  28524. case 'D': case 'd':
  28525. case 'E': case 'e':
  28526. case 'F': case 'f':
  28527. case 'G': case 'g':
  28528. case 'O': case 'o':
  28529. case 'X': case 'x':
  28530. case 'T': case 't':
  28531. case 'C': case 'c':
  28532. {
  28533. int width = -1, precision = -1;
  28534. char pad = ' ';
  28535. i++; /* str[i] == '~' */
  28536. if (isdigit((int)(str[i])))
  28537. width = format_numeric_arg(sc, str, str_len, fdat, args, &i);
  28538. else
  28539. {
  28540. if ((str[i] == 'N') || (str[i] == 'n'))
  28541. {
  28542. i++;
  28543. width = format_n_arg(sc, str, str_len, fdat, args);
  28544. }
  28545. }
  28546. if (str[i] == ',')
  28547. {
  28548. i++; /* is (format #f "~12,12D" 1) an error? The precision has no use here. */
  28549. if (isdigit((int)(str[i])))
  28550. precision = format_numeric_arg(sc, str, str_len, fdat, args, &i);
  28551. else
  28552. {
  28553. if ((str[i] == 'N') || (str[i] == 'n'))
  28554. {
  28555. i++;
  28556. precision = format_n_arg(sc, str, str_len, fdat, args);
  28557. }
  28558. else
  28559. {
  28560. if (str[i] == '\'') /* (format #f "~12,'xD" 1) -> "xxxxxxxxxxx1" */
  28561. {
  28562. pad = str[i + 1];
  28563. i += 2;
  28564. if (i >= str_len) /* (format #f "~,'") */
  28565. format_error(sc, "incomplete numeric argument", str, args, fdat);
  28566. }
  28567. /* is (let ((str "~12,'xD")) (set! (str 5) #\null) (format #f str 1)) an error? */
  28568. }
  28569. }
  28570. }
  28571. switch (str[i])
  28572. {
  28573. /* -------- pad to column --------
  28574. * are columns numbered from 1 or 0? there seems to be disagreement about this directive
  28575. * does "space over to" mean including?
  28576. */
  28577. case 'T': case 't':
  28578. if (width == -1) width = 0;
  28579. if (precision == -1) precision = 0;
  28580. if ((width > 0) || (precision > 0)) /* (format #f "a~8Tb") */
  28581. {
  28582. /* (length (substring (format #f "~%~10T.") 1)) == (length (format #f "~10T."))
  28583. * (length (substring (format #f "~%-~10T.~%") 1)) == (length (format #f "-~10T.~%"))
  28584. */
  28585. if (precision > 0)
  28586. {
  28587. int mult;
  28588. mult = (int)(ceil((s7_double)(sc->format_column + 1 - width) / (s7_double)precision)); /* CLtL2 ("least positive int") */
  28589. if (mult < 1) mult = 1;
  28590. width += (precision * mult);
  28591. }
  28592. format_append_chars(sc, fdat, pad, width - sc->format_column - 1, port);
  28593. }
  28594. break;
  28595. case 'C': case 'c':
  28596. {
  28597. s7_pointer obj;
  28598. if (is_null(fdat->args))
  28599. format_error(sc, "~~C: missing argument", str, args, fdat);
  28600. /* the "~~" here and below protects against "~C" being treated as a directive */
  28601. /* i++; */
  28602. obj = car(fdat->args);
  28603. if (!s7_is_character(obj))
  28604. {
  28605. if (!format_method(sc, str, fdat, port))
  28606. format_error(sc, "'C' directive requires a character argument", str, args, fdat);
  28607. }
  28608. else
  28609. {
  28610. /* here use_write is false, so we just add the char, not its name */
  28611. if (width == -1)
  28612. format_append_char(sc, fdat, character(obj), port);
  28613. else format_append_chars(sc, fdat, character(obj), width, port);
  28614. fdat->args = cdr(fdat->args);
  28615. fdat->ctr++;
  28616. }
  28617. }
  28618. break;
  28619. /* -------- numbers -------- */
  28620. case 'F': case 'f':
  28621. if (is_null(fdat->args))
  28622. format_error(sc, "~~F: missing argument", str, args, fdat);
  28623. if (!(s7_is_number(car(fdat->args))))
  28624. {
  28625. if (!format_method(sc, str, fdat, port))
  28626. format_error(sc, "~~F: numeric argument required", str, args, fdat);
  28627. }
  28628. else format_number(sc, fdat, 10, width, precision, 'f', pad, port);
  28629. break;
  28630. case 'G': case 'g':
  28631. if (is_null(fdat->args))
  28632. format_error(sc, "~~G: missing argument", str, args, fdat);
  28633. if (!(s7_is_number(car(fdat->args))))
  28634. {
  28635. if (!format_method(sc, str, fdat, port))
  28636. format_error(sc, "~~G: numeric argument required", str, args, fdat);
  28637. }
  28638. else format_number(sc, fdat, 10, width, precision, 'g', pad, port);
  28639. break;
  28640. case 'E': case 'e':
  28641. if (is_null(fdat->args))
  28642. format_error(sc, "~~E: missing argument", str, args, fdat);
  28643. if (!(s7_is_number(car(fdat->args))))
  28644. {
  28645. if (!format_method(sc, str, fdat, port))
  28646. format_error(sc, "~~E: numeric argument required", str, args, fdat);
  28647. }
  28648. else format_number(sc, fdat, 10, width, precision, 'e', pad, port);
  28649. break;
  28650. /* how to handle non-integer arguments in the next 4 cases? clisp just returns
  28651. * the argument: (format nil "~X" 1.25) -> "1.25" which is perverse (ClTl2 p 581:
  28652. * "if arg is not an integer, it is printed in ~A format and decimal base")!!
  28653. * I think I'll use the type of the number to choose the output format.
  28654. */
  28655. case 'D': case 'd':
  28656. if (is_null(fdat->args))
  28657. format_error(sc, "~~D: missing argument", str, args, fdat);
  28658. if (!(s7_is_number(car(fdat->args))))
  28659. {
  28660. /* (let () (require mockery.scm) (format #f "~D" ((*mock-number* 'mock-number) 123)))
  28661. * port here is a string-port, str has the width/precision data if the caller wants it,
  28662. * args is the current arg. But format_number handles fdat->args and so on, so
  28663. * I think I'll pass the format method the current control string (str), the
  28664. * current object (car(fdat->args)), and the arglist (args), and assume it will
  28665. * return a (scheme) string.
  28666. */
  28667. if (!format_method(sc, str, fdat, port))
  28668. format_error(sc, "~~D: numeric argument required", str, args, fdat);
  28669. }
  28670. else format_number(sc, fdat, 10, width, precision, 'd', pad, port);
  28671. break;
  28672. case 'O': case 'o':
  28673. if (is_null(fdat->args))
  28674. format_error(sc, "~~O: missing argument", str, args, fdat);
  28675. if (!(s7_is_number(car(fdat->args))))
  28676. {
  28677. if (!format_method(sc, str, fdat, port))
  28678. format_error(sc, "~~O: numeric argument required", str, args, fdat);
  28679. }
  28680. else format_number(sc, fdat, 8, width, precision, 'o', pad, port);
  28681. break;
  28682. case 'X': case 'x':
  28683. if (is_null(fdat->args))
  28684. format_error(sc, "~~X: missing argument", str, args, fdat);
  28685. if (!(s7_is_number(car(fdat->args))))
  28686. {
  28687. if (!format_method(sc, str, fdat, port))
  28688. format_error(sc, "~~X: numeric argument required", str, args, fdat);
  28689. }
  28690. else format_number(sc, fdat, 16, width, precision, 'x', pad, port);
  28691. break;
  28692. case 'B': case 'b':
  28693. if (is_null(fdat->args))
  28694. format_error(sc, "~~B: missing argument", str, args, fdat);
  28695. if (!(s7_is_number(car(fdat->args))))
  28696. {
  28697. if (!format_method(sc, str, fdat, port))
  28698. format_error(sc, "~~B: numeric argument required", str, args, fdat);
  28699. }
  28700. else format_number(sc, fdat, 2, width, precision, 'b', pad, port);
  28701. break;
  28702. default:
  28703. if (width > 0)
  28704. format_error(sc, "unused numeric argument", str, args, fdat);
  28705. format_error(sc, "unimplemented format directive", str, args, fdat);
  28706. }
  28707. }
  28708. break;
  28709. default:
  28710. format_error(sc, "unimplemented format directive", str, args, fdat);
  28711. }
  28712. }
  28713. else /* str[i] is not #\~ */
  28714. {
  28715. int j, new_len;
  28716. const char *p;
  28717. p = (char *)strchr((const char *)(str + i + 1), (int)'~');
  28718. if (!p)
  28719. j = str_len;
  28720. else j = (int)(p - str);
  28721. new_len = j - i;
  28722. if ((port_data(port)) &&
  28723. ((port_position(port) + new_len) < port_data_size(port)))
  28724. {
  28725. memcpy((void *)(port_data(port) + port_position(port)), (void *)(str + i), new_len);
  28726. port_position(port) += new_len;
  28727. }
  28728. else port_write_string(port)(sc, (char *)(str + i), new_len, port);
  28729. fdat->loc += new_len;
  28730. sc->format_column += new_len;
  28731. i = j - 1;
  28732. }
  28733. }
  28734. ALL_DONE:
  28735. if (next_arg)
  28736. (*next_arg) = fdat->args;
  28737. else
  28738. {
  28739. if (is_not_null(fdat->args))
  28740. format_error(sc, "too many arguments", str, args, fdat);
  28741. }
  28742. if (i < str_len)
  28743. {
  28744. if (str[i] == '~')
  28745. format_error(sc, "control string ends in tilde", str, args, fdat);
  28746. format_append_char(sc, fdat, str[i], port);
  28747. }
  28748. sc->format_depth--;
  28749. if (with_result)
  28750. {
  28751. s7_pointer result;
  28752. if ((is_output_port(deferred_port)) &&
  28753. (port_position(port) > 0))
  28754. {
  28755. port_data(port)[port_position(port)] = '\0';
  28756. port_write_string(deferred_port)(sc, (const char *)port_data(port), port_position(port), deferred_port);
  28757. }
  28758. result = s7_make_string_with_length(sc, (char *)port_data(port), port_position(port));
  28759. close_format_port(sc, port);
  28760. fdat->port = NULL;
  28761. return(result);
  28762. }
  28763. return(sc->F);
  28764. }
  28765. static bool is_columnizing(const char *str)
  28766. {
  28767. /* look for ~t ~,<int>T ~<int>,<int>t */
  28768. char *p;
  28769. for (p = (char *)str; (*p);)
  28770. if (*p++ == '~') /* this is faster than strchr */
  28771. {
  28772. char c;
  28773. c = *p++;
  28774. if ((c == 't') || (c == 'T')) return(true);
  28775. if (!c) return(false);
  28776. if ((c == ',') || ((c >= '0') && (c <= '9')) || (c == 'n') || (c == 'N'))
  28777. {
  28778. while (((c >= '0') && (c <= '9')) || (c == 'n') || (c == 'N')) c = *p++;
  28779. if ((c == 't') || (c == 'T')) return(true);
  28780. if (!c) return(false); /* ~,1 for example */
  28781. if (c == ',')
  28782. {
  28783. c = *p++;
  28784. while (((c >= '0') && (c <= '9')) || (c == 'n') || (c == 'N')) c = *p++;
  28785. if ((c == 't') || (c == 'T')) return(true);
  28786. if (!c) return(false);
  28787. }
  28788. }
  28789. }
  28790. return(false);
  28791. }
  28792. static s7_pointer format_to_port(s7_scheme *sc, s7_pointer port, const char *str, s7_pointer args, s7_pointer *next_arg, bool with_result, int len)
  28793. {
  28794. return(format_to_port_1(sc, port, str, args, next_arg, with_result, true /* is_columnizing(str) */, len, NULL));
  28795. /* is_columnizing on every call is much slower than ignoring the issue */
  28796. }
  28797. static s7_pointer g_format_1(s7_scheme *sc, s7_pointer args)
  28798. {
  28799. s7_pointer pt, str;
  28800. sc->format_column = 0;
  28801. pt = car(args);
  28802. if (is_string(pt))
  28803. return(format_to_port_1(sc, sc->F, string_value(pt), cdr(args), NULL, true, true, string_length(pt), pt));
  28804. if (is_null(pt)) pt = sc->output_port; /* () -> (current-output-port) */
  28805. if (!((s7_is_boolean(pt)) || /* #f or #t */
  28806. ((is_output_port(pt)) && /* (current-output-port) or call-with-open-file arg, etc */
  28807. (!port_is_closed(pt)))))
  28808. method_or_bust_with_type(sc, pt, sc->format_symbol, args, an_output_port_string, 1);
  28809. str = cadr(args);
  28810. if (!is_string(str))
  28811. method_or_bust(sc, str, sc->format_symbol, args, T_STRING, 2);
  28812. return(format_to_port_1(sc, (pt == sc->T) ? sc->output_port : pt,
  28813. string_value(str), cddr(args), NULL, !is_output_port(pt), true, string_length(str), str));
  28814. }
  28815. static s7_pointer g_format(s7_scheme *sc, s7_pointer args)
  28816. {
  28817. #define H_format "(format out str . args) substitutes args into str sending the result to out. Most of \
  28818. s7's format directives are taken from CL: ~% = newline, ~& = newline if the preceding output character was \
  28819. no a newline, ~~ = ~, ~<newline> trims white space, ~* skips an argument, ~^ exits {} iteration if the arg list is exhausted, \
  28820. ~nT spaces over to column n, ~A prints a representation of any object, ~S is the same, but puts strings in double quotes, \
  28821. ~C prints a character, numbers are handled by ~F, ~E, ~G, ~B, ~O, ~D, and ~X with preceding numbers giving \
  28822. spacing (and spacing character) and precision. ~{ starts an embedded format directive which is ended by ~}: \n\
  28823. \n\
  28824. >(format #f \"dashed: ~{~A~^-~}\" '(1 2 3))\n\
  28825. \"dashed: 1-2-3\"\n\
  28826. \n\
  28827. ~P inserts \"s\" if the current it is not 1 or 1.0 (use ~@P for \"ies\" or \"y\").\n\
  28828. ~B is number->string in base 2, ~O in base 8, ~D base 10, ~X base 16,\n\
  28829. ~E: (format #f \"~E\" 100.1) -&gt; \"1.001000e+02\" (%e in C)\n\
  28830. ~F: (format #f \"~F\" 100.1) -&gt; \"100.100000\" (%f in C)\n\
  28831. ~G: (format #f \"~G\" 100.1) -&gt; \"100.1\" (%g in C)\n\
  28832. \n\
  28833. If the 'out' it is not an output port, the resultant string is returned. If it \
  28834. is #t, the string is also sent to the current-output-port."
  28835. #define Q_format s7_make_circular_signature(sc, 1, 2, s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_boolean_symbol), sc->T)
  28836. return(g_format_1(sc, args));
  28837. }
  28838. const char *s7_format(s7_scheme *sc, s7_pointer args)
  28839. {
  28840. s7_pointer result;
  28841. result = g_format_1(sc, args);
  28842. if (is_string(result))
  28843. return(string_value(result));
  28844. return(NULL);
  28845. }
  28846. /* -------------------------------- system extras -------------------------------- */
  28847. #if WITH_SYSTEM_EXTRAS
  28848. #include <fcntl.h>
  28849. static s7_pointer g_is_directory(s7_scheme *sc, s7_pointer args)
  28850. {
  28851. #define H_is_directory "(directory? str) returns #t if str is the name of a directory"
  28852. #define Q_is_directory s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_string_symbol)
  28853. s7_pointer name;
  28854. name = car(args);
  28855. if (!is_string(name))
  28856. method_or_bust(sc, name, sc->is_directory_symbol, args, T_STRING, 0);
  28857. return(s7_make_boolean(sc, is_directory(string_value(name))));
  28858. }
  28859. static bool file_probe(const char *arg)
  28860. {
  28861. #if (!MS_WINDOWS)
  28862. return(access(arg, F_OK) == 0);
  28863. #else
  28864. int fd;
  28865. fd = open(arg, O_RDONLY, 0);
  28866. if (fd == -1) return(false);
  28867. close(fd);
  28868. return(true);
  28869. #endif
  28870. }
  28871. static s7_pointer g_file_exists(s7_scheme *sc, s7_pointer args)
  28872. {
  28873. #define H_file_exists "(file-exists? filename) returns #t if the file exists"
  28874. #define Q_file_exists s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_string_symbol)
  28875. s7_pointer name;
  28876. name = car(args);
  28877. if (!is_string(name))
  28878. method_or_bust(sc, name, sc->file_exists_symbol, args, T_STRING, 0);
  28879. return(s7_make_boolean(sc, file_probe(string_value(name))));
  28880. }
  28881. static s7_pointer g_delete_file(s7_scheme *sc, s7_pointer args)
  28882. {
  28883. #define H_delete_file "(delete-file filename) deletes the file filename."
  28884. #define Q_delete_file s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_string_symbol)
  28885. s7_pointer name;
  28886. name = car(args);
  28887. if (!is_string(name))
  28888. method_or_bust(sc, name, sc->delete_file_symbol, args, T_STRING, 0);
  28889. return(make_integer(sc, unlink(string_value(name))));
  28890. }
  28891. static s7_pointer g_getenv(s7_scheme *sc, s7_pointer args)
  28892. {
  28893. #define H_getenv "(getenv var) returns the value of an environment variable."
  28894. #define Q_getenv pcl_s
  28895. s7_pointer name;
  28896. name = car(args);
  28897. if (!is_string(name))
  28898. method_or_bust(sc, name, sc->getenv_symbol, args, T_STRING, 0);
  28899. return(s7_make_string(sc, getenv(string_value(name))));
  28900. }
  28901. static s7_pointer g_system(s7_scheme *sc, s7_pointer args)
  28902. {
  28903. #define H_system "(system command) executes the command. If the optional second it is #t, \
  28904. system captures the output as a string and returns it."
  28905. #define Q_system s7_make_signature(sc, 3, sc->T, sc->is_string_symbol, sc->is_boolean_symbol)
  28906. s7_pointer name;
  28907. name = car(args);
  28908. if (!is_string(name))
  28909. method_or_bust(sc, name, sc->system_symbol, args, T_STRING, 0);
  28910. if ((is_pair(cdr(args))) &&
  28911. (cadr(args) == sc->T))
  28912. {
  28913. #define BUF_SIZE 256
  28914. char buf[BUF_SIZE];
  28915. char *str = NULL;
  28916. int cur_len = 0, full_len = 0;
  28917. FILE *fd;
  28918. s7_pointer res;
  28919. fd = popen(string_value(name), "r");
  28920. while (fgets(buf, BUF_SIZE, fd))
  28921. {
  28922. int buf_len;
  28923. buf_len = safe_strlen(buf);
  28924. if (cur_len + buf_len >= full_len)
  28925. {
  28926. full_len += BUF_SIZE * 2;
  28927. if (str)
  28928. str = (char *)realloc(str, full_len * sizeof(char));
  28929. else str = (char *)malloc(full_len * sizeof(char));
  28930. }
  28931. memcpy((void *)(str + cur_len), (void *)buf, buf_len);
  28932. cur_len += buf_len;
  28933. }
  28934. pclose(fd);
  28935. res = s7_make_string_with_length(sc, str, cur_len);
  28936. if (str) free(str);
  28937. return(res);
  28938. }
  28939. return(make_integer(sc, system(string_value(name))));
  28940. }
  28941. #ifndef _MSC_VER
  28942. #include <dirent.h>
  28943. static s7_pointer c_directory_to_list(s7_scheme *sc, s7_pointer name)
  28944. {
  28945. DIR *dpos;
  28946. s7_pointer result;
  28947. if (!is_string(name))
  28948. method_or_bust(sc, name, sc->directory_to_list_symbol, list_1(sc, name), T_STRING, 0);
  28949. sc->w = sc->nil;
  28950. if ((dpos = opendir(string_value(name))) != NULL)
  28951. {
  28952. struct dirent *dirp;
  28953. while ((dirp = readdir(dpos)) != NULL)
  28954. sc->w = cons(sc, s7_make_string(sc, dirp->d_name), sc->w);
  28955. closedir(dpos);
  28956. }
  28957. result = sc->w;
  28958. sc->w = sc->nil;
  28959. return(result);
  28960. }
  28961. static s7_pointer g_directory_to_list(s7_scheme *sc, s7_pointer args)
  28962. {
  28963. #define H_directory_to_list "(directory->list directory) returns the contents of the directory as a list of strings (filenames)."
  28964. #define Q_directory_to_list s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_string_symbol)
  28965. return(c_directory_to_list(sc, car(args)));
  28966. }
  28967. PF_TO_PF(directory_to_list, c_directory_to_list)
  28968. static s7_pointer g_file_mtime(s7_scheme *sc, s7_pointer args)
  28969. {
  28970. #define H_file_mtime "(file-mtime file): return the write date of file"
  28971. #define Q_file_mtime s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_string_symbol)
  28972. struct stat statbuf;
  28973. int err;
  28974. s7_pointer name;
  28975. name = car(args);
  28976. if (!is_string(name))
  28977. method_or_bust(sc, name, sc->file_mtime_symbol, args, T_STRING, 0);
  28978. err = stat(string_value(name), &statbuf);
  28979. if (err < 0)
  28980. return(file_error(sc, "file-mtime", strerror(errno), string_value(name)));
  28981. return(s7_make_integer(sc, (s7_int)(statbuf.st_mtime)));
  28982. }
  28983. #endif
  28984. #endif
  28985. /* -------------------------------- lists -------------------------------- */
  28986. s7_pointer s7_cons(s7_scheme *sc, s7_pointer a, s7_pointer b)
  28987. {
  28988. s7_pointer x;
  28989. new_cell(sc, x, T_PAIR | T_SAFE_PROCEDURE);
  28990. set_car(x, a);
  28991. set_cdr(x, b);
  28992. return(x);
  28993. }
  28994. static s7_pointer cons_unchecked(s7_scheme *sc, s7_pointer a, s7_pointer b)
  28995. {
  28996. /* apparently slightly faster as a function? */
  28997. s7_pointer x;
  28998. new_cell_no_check(sc, x, T_PAIR | T_SAFE_PROCEDURE);
  28999. set_car(x, a);
  29000. set_cdr(x, b);
  29001. return(x);
  29002. }
  29003. static s7_pointer permanent_cons(s7_pointer a, s7_pointer b, unsigned int type)
  29004. {
  29005. /* for the symbol table which is never GC'd (and its contents aren't marked) */
  29006. s7_pointer x;
  29007. x = alloc_pointer();
  29008. set_type(x, type);
  29009. unheap(x);
  29010. set_car(x, a);
  29011. set_cdr(x, b);
  29012. return(x);
  29013. }
  29014. static s7_pointer permanent_list(s7_scheme *sc, int len)
  29015. {
  29016. int j;
  29017. s7_pointer p;
  29018. p = sc->nil;
  29019. for (j = 0; j < len; j++)
  29020. p = permanent_cons(sc->nil, p, T_PAIR | T_IMMUTABLE);
  29021. return(p);
  29022. }
  29023. #if DEBUGGING
  29024. static int sigs = 0, sig_pairs = 0;
  29025. #endif
  29026. static void check_sig_entry(s7_scheme *sc, s7_pointer p, s7_pointer res, bool circle)
  29027. {
  29028. if ((!is_symbol(car(p))) &&
  29029. (!s7_is_boolean(car(p))) &&
  29030. (!is_pair(car(p))))
  29031. {
  29032. s7_pointer np;
  29033. int i;
  29034. for (np = res, i = 0; np != p; np = cdr(np), i++);
  29035. fprintf(stderr, "s7_make_%ssignature got an invalid entry at position %d: (", (circle) ? "circular_" : "", i);
  29036. for (np = res; np != p; np = cdr(np))
  29037. fprintf(stderr, "%s ", DISPLAY(car(np)));
  29038. fprintf(stderr, "...");
  29039. set_car(p, sc->nil);
  29040. }
  29041. }
  29042. s7_pointer s7_make_signature(s7_scheme *sc, int len, ...)
  29043. {
  29044. va_list ap;
  29045. s7_pointer p, res;
  29046. #if DEBUGGING
  29047. sigs++;
  29048. sig_pairs += len;
  29049. #endif
  29050. res = permanent_list(sc, len);
  29051. va_start(ap, len);
  29052. for (p = res; is_pair(p); p = cdr(p))
  29053. {
  29054. set_car(p, va_arg(ap, s7_pointer));
  29055. check_sig_entry(sc, p, res, false);
  29056. }
  29057. va_end(ap);
  29058. return((s7_pointer)res);
  29059. }
  29060. s7_pointer s7_make_circular_signature(s7_scheme *sc, int cycle_point, int len, ...)
  29061. {
  29062. va_list ap;
  29063. int i;
  29064. s7_pointer p, res, back = NULL, end = NULL;
  29065. #if DEBUGGING
  29066. sigs++;
  29067. sig_pairs += len;
  29068. #endif
  29069. res = permanent_list(sc, len);
  29070. va_start(ap, len);
  29071. for (p = res, i = 0; is_pair(p); p = cdr(p), i++)
  29072. {
  29073. set_car(p, va_arg(ap, s7_pointer));
  29074. check_sig_entry(sc, p, res, true);
  29075. if (i == cycle_point) back = p;
  29076. if (i == (len - 1)) end = p;
  29077. }
  29078. va_end(ap);
  29079. if (end) set_cdr(end, back);
  29080. if (i < len)
  29081. fprintf(stderr, "s7_make_circular_signature got too few entries: %s\n", DISPLAY(res));
  29082. return((s7_pointer)res);
  29083. }
  29084. bool s7_is_pair(s7_pointer p)
  29085. {
  29086. return(is_pair(p));
  29087. }
  29088. s7_pointer s7_car(s7_pointer p) {return(car(p));}
  29089. s7_pointer s7_cdr(s7_pointer p) {return(cdr(p));}
  29090. s7_pointer s7_cadr(s7_pointer p) {return(cadr(p));}
  29091. s7_pointer s7_cddr(s7_pointer p) {return(cddr(p));}
  29092. s7_pointer s7_cdar(s7_pointer p) {return(cdar(p));}
  29093. s7_pointer s7_caar(s7_pointer p) {return(caar(p));}
  29094. s7_pointer s7_caadr(s7_pointer p) {return(caadr(p));}
  29095. s7_pointer s7_caddr(s7_pointer p) {return(caddr(p));}
  29096. s7_pointer s7_cadar(s7_pointer p) {return(cadar(p));}
  29097. s7_pointer s7_caaar(s7_pointer p) {return(caaar(p));}
  29098. s7_pointer s7_cdadr(s7_pointer p) {return(cdadr(p));}
  29099. s7_pointer s7_cdddr(s7_pointer p) {return(cdddr(p));}
  29100. s7_pointer s7_cddar(s7_pointer p) {return(cddar(p));}
  29101. s7_pointer s7_cdaar(s7_pointer p) {return(cdaar(p));}
  29102. s7_pointer s7_caaadr(s7_pointer p) {return(caaadr(p));}
  29103. s7_pointer s7_caaddr(s7_pointer p) {return(caaddr(p));}
  29104. s7_pointer s7_caadar(s7_pointer p) {return(caadar(p));}
  29105. s7_pointer s7_caaaar(s7_pointer p) {return(caaaar(p));}
  29106. s7_pointer s7_cadadr(s7_pointer p) {return(cadadr(p));}
  29107. s7_pointer s7_cadddr(s7_pointer p) {return(cadddr(p));}
  29108. s7_pointer s7_caddar(s7_pointer p) {return(caddar(p));}
  29109. s7_pointer s7_cadaar(s7_pointer p) {return(cadaar(p));}
  29110. s7_pointer s7_cdaadr(s7_pointer p) {return(cdaadr(p));}
  29111. s7_pointer s7_cdaddr(s7_pointer p) {return(cdaddr(p));}
  29112. s7_pointer s7_cdadar(s7_pointer p) {return(cdadar(p));}
  29113. s7_pointer s7_cdaaar(s7_pointer p) {return(cdaaar(p));}
  29114. s7_pointer s7_cddadr(s7_pointer p) {return(cddadr(p));}
  29115. s7_pointer s7_cddddr(s7_pointer p) {return(cddddr(p));}
  29116. s7_pointer s7_cdddar(s7_pointer p) {return(cdddar(p));}
  29117. s7_pointer s7_cddaar(s7_pointer p) {return(cddaar(p));}
  29118. s7_pointer s7_set_car(s7_pointer p, s7_pointer q)
  29119. {
  29120. set_car(p, q);
  29121. return(p);
  29122. }
  29123. s7_pointer s7_set_cdr(s7_pointer p, s7_pointer q)
  29124. {
  29125. set_cdr(p, q);
  29126. return(p);
  29127. }
  29128. /* -------------------------------------------------------------------------------- */
  29129. s7_pointer s7_apply_1(s7_scheme *sc, s7_pointer args, s7_pointer (*f1)(s7_pointer a1))
  29130. {
  29131. /* not currently used */
  29132. return(f1(car(args)));
  29133. }
  29134. s7_pointer s7_apply_2(s7_scheme *sc, s7_pointer args, s7_pointer (*f2)(s7_pointer a1, s7_pointer a2))
  29135. {
  29136. return(f2(car(args), cadr(args)));
  29137. }
  29138. s7_pointer s7_apply_3(s7_scheme *sc, s7_pointer args, s7_pointer (*f3)(s7_pointer a1, s7_pointer a2, s7_pointer a3))
  29139. {
  29140. s7_pointer a1;
  29141. a1 = car(args); args = cdr(args);
  29142. return(f3(a1, car(args), cadr(args)));
  29143. }
  29144. 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))
  29145. {
  29146. s7_pointer a1, a2;
  29147. a1 = car(args); a2 = cadr(args); args = cddr(args);
  29148. return(f4(a1, a2, car(args), cadr(args)));
  29149. }
  29150. 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))
  29151. {
  29152. s7_pointer a1, a2, a3, a4;
  29153. a1 = car(args); a2 = cadr(args); args = cddr(args);
  29154. a3 = car(args); a4 = cadr(args); args = cddr(args);
  29155. return(f5(a1, a2, a3, a4, car(args)));
  29156. }
  29157. 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))
  29158. {
  29159. s7_pointer a1, a2, a3, a4;
  29160. a1 = car(args); a2 = cadr(args); args = cddr(args);
  29161. a3 = car(args); a4 = cadr(args); args = cddr(args);
  29162. return(f6(a1, a2, a3, a4, car(args), cadr(args)));
  29163. }
  29164. s7_pointer s7_apply_7(s7_scheme *sc, s7_pointer args,
  29165. s7_pointer (*f7)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4, s7_pointer a5, s7_pointer a6, s7_pointer a7))
  29166. {
  29167. s7_pointer a1, a2, a3, a4, a5, a6;
  29168. a1 = car(args); a2 = cadr(args); args = cddr(args);
  29169. a3 = car(args); a4 = cadr(args); args = cddr(args);
  29170. a5 = car(args); a6 = cadr(args); args = cddr(args);
  29171. return(f7(a1, a2, a3, a4, a5, a6, car(args)));
  29172. }
  29173. s7_pointer s7_apply_8(s7_scheme *sc, s7_pointer args,
  29174. 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))
  29175. {
  29176. s7_pointer a1, a2, a3, a4, a5, a6;
  29177. a1 = car(args); a2 = cadr(args); args = cddr(args);
  29178. a3 = car(args); a4 = cadr(args); args = cddr(args);
  29179. a5 = car(args); a6 = cadr(args); args = cddr(args);
  29180. return(f8(a1, a2, a3, a4, a5, a6, car(args), cadr(args)));
  29181. }
  29182. 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,
  29183. s7_pointer a5, s7_pointer a6, s7_pointer a7, s7_pointer a8, s7_pointer a9))
  29184. {
  29185. s7_pointer a1, a2, a3, a4, a5, a6;
  29186. a1 = car(args); a2 = cadr(args); args = cddr(args);
  29187. a3 = car(args); a4 = cadr(args); args = cddr(args);
  29188. a5 = car(args); a6 = cadr(args); args = cddr(args);
  29189. return(f9(a1, a2, a3, a4, a5, a6, car(args), cadr(args), caddr(args)));
  29190. }
  29191. s7_pointer s7_apply_n_1(s7_scheme *sc, s7_pointer args, s7_pointer (*f1)(s7_pointer a1))
  29192. {
  29193. if (is_pair(args))
  29194. return(f1(car(args)));
  29195. return(f1(sc->undefined));
  29196. }
  29197. s7_pointer s7_apply_n_2(s7_scheme *sc, s7_pointer args, s7_pointer (*f2)(s7_pointer a1, s7_pointer a2))
  29198. {
  29199. if (is_pair(args))
  29200. {
  29201. if (is_pair(cdr(args)))
  29202. return(f2(car(args), cadr(args)));
  29203. return(f2(car(args), sc->undefined));
  29204. }
  29205. return(f2(sc->undefined, sc->undefined));
  29206. }
  29207. s7_pointer s7_apply_n_3(s7_scheme *sc, s7_pointer args, s7_pointer (*f3)(s7_pointer a1, s7_pointer a2, s7_pointer a3))
  29208. {
  29209. if (is_pair(args))
  29210. {
  29211. s7_pointer a1;
  29212. a1 = car(args); args = cdr(args);
  29213. if (is_pair(args))
  29214. {
  29215. s7_pointer a2;
  29216. a2 = car(args);
  29217. if (is_pair(cdr(args)))
  29218. return(f3(a1, a2, cadr(args)));
  29219. return(f3(a1, a2, sc->undefined));
  29220. }
  29221. return(f3(a1, sc->undefined, sc->undefined));
  29222. }
  29223. return(f3(sc->undefined, sc->undefined, sc->undefined));
  29224. }
  29225. 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))
  29226. {
  29227. if (is_pair(args))
  29228. {
  29229. s7_pointer a1;
  29230. a1 = car(args); args = cdr(args);
  29231. if (is_pair(args))
  29232. {
  29233. s7_pointer a2;
  29234. a2 = car(args); args = cdr(args);
  29235. if (is_pair(args))
  29236. {
  29237. s7_pointer a3;
  29238. a3 = car(args);
  29239. if (is_pair(cdr(args)))
  29240. return(f4(a1, a2, a3, cadr(args)));
  29241. return(f4(a1, a2, a3, sc->undefined));
  29242. }
  29243. return(f4(a1, a2, sc->undefined, sc->undefined));
  29244. }
  29245. return(f4(a1, sc->undefined, sc->undefined, sc->undefined));
  29246. }
  29247. return(f4(sc->undefined, sc->undefined, sc->undefined, sc->undefined));
  29248. }
  29249. s7_pointer s7_apply_n_5(s7_scheme *sc, s7_pointer args,
  29250. s7_pointer (*f5)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4, s7_pointer a5))
  29251. {
  29252. if (is_pair(args))
  29253. {
  29254. s7_pointer a1;
  29255. a1 = car(args); args = cdr(args);
  29256. if (is_pair(args))
  29257. {
  29258. s7_pointer a2;
  29259. a2 = car(args); args = cdr(args);
  29260. if (is_pair(args))
  29261. {
  29262. s7_pointer a3;
  29263. a3 = car(args); args = cdr(args);
  29264. if (is_pair(args))
  29265. {
  29266. s7_pointer a4;
  29267. a4 = car(args);
  29268. if (is_pair(cdr(args)))
  29269. return(f5(a1, a2, a3, a4, cadr(args)));
  29270. return(f5(a1, a2, a3, a4, sc->undefined));
  29271. }
  29272. return(f5(a1, a2, a3, sc->undefined, sc->undefined));
  29273. }
  29274. return(f5(a1, a2, sc->undefined, sc->undefined, sc->undefined));
  29275. }
  29276. return(f5(a1, sc->undefined, sc->undefined, sc->undefined, sc->undefined));
  29277. }
  29278. return(f5(sc->undefined, sc->undefined, sc->undefined, sc->undefined, sc->undefined));
  29279. }
  29280. s7_pointer s7_apply_n_6(s7_scheme *sc, s7_pointer args,
  29281. s7_pointer (*f6)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4, s7_pointer a5, s7_pointer a6))
  29282. {
  29283. s7_pointer a1, a2, a3, a4, a5, a6;
  29284. a1 = sc->undefined; a2 = sc->undefined; a3 = sc->undefined; a4 = sc->undefined; a5 = sc->undefined; a6 = sc->undefined;
  29285. if (is_pair(args))
  29286. {
  29287. a1 = car(args); args = cdr(args);
  29288. if (is_pair(args))
  29289. {
  29290. a2 = car(args); args = cdr(args);
  29291. if (is_pair(args))
  29292. {
  29293. a3 = car(args); args = cdr(args);
  29294. if (is_pair(args))
  29295. {
  29296. a4 = car(args); args = cdr(args);
  29297. if (is_pair(args))
  29298. {
  29299. a5 = car(args);
  29300. if (is_pair(cdr(args))) a6 = cadr(args);
  29301. }}}}}
  29302. return(f6(a1, a2, a3, a4, a5, a6));
  29303. }
  29304. s7_pointer s7_apply_n_7(s7_scheme *sc, s7_pointer args,
  29305. s7_pointer (*f7)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4,
  29306. s7_pointer a5, s7_pointer a6, s7_pointer a7))
  29307. {
  29308. s7_pointer a1, a2, a3, a4, a5, a6, a7;
  29309. a1 = sc->undefined; a2 = sc->undefined; a3 = sc->undefined; a4 = sc->undefined; a5 = sc->undefined;
  29310. a6 = sc->undefined, a7 = sc->undefined;
  29311. if (is_pair(args))
  29312. {
  29313. a1 = car(args); args = cdr(args);
  29314. if (is_pair(args))
  29315. {
  29316. a2 = car(args); args = cdr(args);
  29317. if (is_pair(args))
  29318. {
  29319. a3 = car(args); args = cdr(args);
  29320. if (is_pair(args))
  29321. {
  29322. a4 = car(args); args = cdr(args);
  29323. if (is_pair(args))
  29324. {
  29325. a5 = car(args); args = cdr(args);
  29326. if (is_pair(args))
  29327. {
  29328. a6 = car(args);
  29329. if (is_pair(cdr(args))) a7 = cadr(args);
  29330. }}}}}}
  29331. return(f7(a1, a2, a3, a4, a5, a6, a7));
  29332. }
  29333. s7_pointer s7_apply_n_8(s7_scheme *sc, s7_pointer args,
  29334. s7_pointer (*f8)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4,
  29335. s7_pointer a5, s7_pointer a6, s7_pointer a7, s7_pointer a8))
  29336. {
  29337. s7_pointer a1, a2, a3, a4, a5, a6, a7, a8;
  29338. a1 = sc->undefined; a2 = sc->undefined; a3 = sc->undefined; a4 = sc->undefined; a5 = sc->undefined;
  29339. a6 = sc->undefined, a7 = sc->undefined; a8 = sc->undefined;
  29340. if (is_pair(args))
  29341. {
  29342. a1 = car(args); args = cdr(args);
  29343. if (is_pair(args))
  29344. {
  29345. a2 = car(args); args = cdr(args);
  29346. if (is_pair(args))
  29347. {
  29348. a3 = car(args); args = cdr(args);
  29349. if (is_pair(args))
  29350. {
  29351. a4 = car(args); args = cdr(args);
  29352. if (is_pair(args))
  29353. {
  29354. a5 = car(args); args = cdr(args);
  29355. if (is_pair(args))
  29356. {
  29357. a6 = car(args); args = cdr(args);
  29358. if (is_pair(args))
  29359. {
  29360. a7 = car(args);
  29361. if (is_pair(cdr(args))) a8 = cadr(args);
  29362. }}}}}}}
  29363. return(f8(a1, a2, a3, a4, a5, a6, a7, a8));
  29364. }
  29365. s7_pointer s7_apply_n_9(s7_scheme *sc, s7_pointer args,
  29366. s7_pointer (*f9)(s7_pointer a1, s7_pointer a2, s7_pointer a3, s7_pointer a4,
  29367. s7_pointer a5, s7_pointer a6, s7_pointer a7, s7_pointer a8,
  29368. s7_pointer a9))
  29369. {
  29370. s7_pointer a1, a2, a3, a4, a5, a6, a7, a8, a9;
  29371. a1 = sc->undefined; a2 = sc->undefined; a3 = sc->undefined; a4 = sc->undefined; a5 = sc->undefined;
  29372. a6 = sc->undefined, a7 = sc->undefined; a8 = sc->undefined; a9 = sc->undefined;
  29373. if (is_pair(args))
  29374. {
  29375. a1 = car(args); args = cdr(args);
  29376. if (is_pair(args))
  29377. {
  29378. a2 = car(args); args = cdr(args);
  29379. if (is_pair(args))
  29380. {
  29381. a3 = car(args); args = cdr(args);
  29382. if (is_pair(args))
  29383. {
  29384. a4 = car(args); args = cdr(args);
  29385. if (is_pair(args))
  29386. {
  29387. a5 = car(args); args = cdr(args);
  29388. if (is_pair(args))
  29389. {
  29390. a6 = car(args); args = cdr(args);
  29391. if (is_pair(args))
  29392. {
  29393. a7 = car(args); args = cdr(args);
  29394. if (is_pair(args))
  29395. {
  29396. a8 = car(args);
  29397. if (is_pair(cdr(args))) a9 = cadr(args);
  29398. }}}}}}}}
  29399. return(f9(a1, a2, a3, a4, a5, a6, a7, a8, a9));
  29400. }
  29401. /* -------------------------------------------------------------------------------- */
  29402. s7_pointer s7_list_ref(s7_scheme *sc, s7_pointer lst, int num)
  29403. {
  29404. int i;
  29405. s7_pointer x;
  29406. for (x = lst, i = 0; (i < num) && (is_pair(x)); i++, x = cdr(x)) {}
  29407. if ((i == num) && (is_pair(x)))
  29408. return(car(x));
  29409. return(sc->nil);
  29410. }
  29411. s7_pointer s7_list_set(s7_scheme *sc, s7_pointer lst, int num, s7_pointer val)
  29412. {
  29413. int i;
  29414. s7_pointer x;
  29415. for (x = lst, i = 0; (i < num) && (is_pair(x)); i++, x = cdr(x)) {}
  29416. if ((i == num) &&
  29417. (is_pair(x)))
  29418. set_car(x, _NFre(val));
  29419. return(val);
  29420. }
  29421. s7_pointer s7_member(s7_scheme *sc, s7_pointer sym, s7_pointer lst)
  29422. {
  29423. s7_pointer x;
  29424. for (x = lst; is_pair(x); x = cdr(x))
  29425. if (s7_is_equal(sc, sym, car(x)))
  29426. return(x);
  29427. return(sc->F);
  29428. }
  29429. static bool symbol_is_in_arg_list(s7_pointer sym, s7_pointer lst)
  29430. {
  29431. s7_pointer x;
  29432. for (x = lst; is_pair(x); x = cdr(x))
  29433. if ((sym == car(x)) ||
  29434. ((is_pair(car(x))) &&
  29435. (sym == caar(x))))
  29436. return(true);
  29437. return(sym == x);
  29438. }
  29439. s7_pointer s7_assoc(s7_scheme *sc, s7_pointer sym, s7_pointer lst)
  29440. {
  29441. s7_pointer x, y;
  29442. if (!is_pair(lst))
  29443. return(sc->F);
  29444. x = lst;
  29445. y = lst;
  29446. while (true)
  29447. {
  29448. if ((is_pair(car(x))) && (s7_is_equal(sc, sym, caar(x)))) return(car(x));
  29449. x = cdr(x);
  29450. if (!is_pair(x)) return(sc->F);
  29451. if ((is_pair(car(x))) && (s7_is_equal(sc, sym, caar(x)))) return(car(x));
  29452. x = cdr(x);
  29453. if (!is_pair(x)) return(sc->F);
  29454. y = cdr(y);
  29455. if (x == y) return(sc->F);
  29456. }
  29457. return(sc->F);
  29458. }
  29459. s7_pointer s7_reverse(s7_scheme *sc, s7_pointer a)
  29460. {
  29461. /* reverse list -- produce new list (other code assumes this function does not return the original!) */
  29462. s7_pointer x, p;
  29463. if (is_null(a)) return(a);
  29464. if (!is_pair(cdr(a)))
  29465. {
  29466. if (is_not_null(cdr(a)))
  29467. return(cons(sc, cdr(a), car(a)));
  29468. return(cons(sc, car(a), sc->nil)); /* don't return 'a' itself */
  29469. }
  29470. sc->w = list_1(sc, car(a));
  29471. for (x = cdr(a), p = a; is_pair(x); x = cdr(x), p = cdr(p))
  29472. {
  29473. sc->w = cons(sc, car(x), sc->w);
  29474. if (is_pair(cdr(x)))
  29475. {
  29476. x = cdr(x);
  29477. sc->w = cons(sc, car(x), sc->w);
  29478. }
  29479. if (x == p) /* this can take awhile to notice there's a cycle, but what does the caller expect? */
  29480. break;
  29481. }
  29482. if (is_not_null(x))
  29483. p = cons(sc, x, sc->w); /* ?? this means that (reverse '(1 2 . 3)) returns '(3 2 1) -- we used to return () here */
  29484. else p = sc->w;
  29485. sc->w = sc->nil;
  29486. return(p);
  29487. }
  29488. /* s7_reverse sometimes tacks extra nodes on the end of a reversed circular list (it detects the cycle too late)
  29489. * (let ((lst (list 0))) (set! (cdr lst) lst) (reverse lst)) -> (#1=(0 . #1#) 0 0 0)
  29490. */
  29491. static s7_pointer reverse_in_place(s7_scheme *sc, s7_pointer term, s7_pointer list)
  29492. {
  29493. s7_pointer p = list, result = term, q;
  29494. while (is_not_null(p))
  29495. {
  29496. q = cdr(p);
  29497. if ((!is_pair(q)) &&
  29498. (is_not_null(q)))
  29499. return(sc->nil); /* improper list? */
  29500. set_cdr(p, result);
  29501. result = p;
  29502. p = q;
  29503. }
  29504. return(result);
  29505. }
  29506. static s7_pointer reverse_in_place_unchecked(s7_scheme *sc, s7_pointer term, s7_pointer list)
  29507. {
  29508. s7_pointer p = list, result = term, q;
  29509. while (is_not_null(p))
  29510. {
  29511. q = cdr(p);
  29512. set_cdr(p, result);
  29513. result = p;
  29514. p = q;
  29515. if (is_null(p)) break;
  29516. q = cdr(p);
  29517. set_cdr(p, result);
  29518. result = p;
  29519. p = q;
  29520. }
  29521. return(result);
  29522. }
  29523. static s7_pointer safe_reverse_in_place(s7_scheme *sc, s7_pointer list) /* "safe" here means we guarantee this list is unproblematic */
  29524. {
  29525. s7_pointer p = list, result, q;
  29526. result = sc->nil;
  29527. while (is_not_null(p))
  29528. {
  29529. q = cdr(p);
  29530. /* also if (is_null(list)) || (is_null(cdr(list))) return(list) */
  29531. set_cdr(p, result);
  29532. result = p;
  29533. p = q;
  29534. /* unroll the loop for speed */
  29535. if (is_null(p)) break;
  29536. q = cdr(p);
  29537. set_cdr(p, result);
  29538. result = p;
  29539. p = q;
  29540. if (is_null(p)) break;
  29541. q = cdr(p);
  29542. set_cdr(p, result);
  29543. result = p;
  29544. p = q;
  29545. if (is_null(p)) break;
  29546. q = cdr(p);
  29547. set_cdr(p, result);
  29548. result = p;
  29549. p = q;
  29550. }
  29551. return(result);
  29552. }
  29553. /* is this correct? (let ((x (list 1 2))) (eq? x (append () x))) -> #t
  29554. */
  29555. s7_pointer s7_append(s7_scheme *sc, s7_pointer a, s7_pointer b)
  29556. {
  29557. s7_pointer p, tp, np;
  29558. if (is_null(a)) return(b);
  29559. tp = cons(sc, car(a), sc->nil);
  29560. sc->y = tp;
  29561. for (p = cdr(a), np = tp; is_pair(p); p = cdr(p), np = cdr(np))
  29562. set_cdr(np, cons(sc, car(p), sc->nil));
  29563. set_cdr(np, b);
  29564. sc->y = sc->nil;
  29565. return(tp);
  29566. }
  29567. static s7_pointer copy_list(s7_scheme *sc, s7_pointer lst)
  29568. {
  29569. s7_pointer p, tp, np;
  29570. if (!is_pair(lst)) return(sc->nil);
  29571. tp = cons(sc, car(lst), sc->nil);
  29572. sc->y = tp;
  29573. for (p = cdr(lst), np = tp; is_pair(p); p = cdr(p), np = cdr(np))
  29574. set_cdr(np, cons(sc, car(p), sc->nil));
  29575. sc->y = sc->nil;
  29576. return(tp);
  29577. }
  29578. static s7_pointer copy_list_with_arglist_error(s7_scheme *sc, s7_pointer lst)
  29579. {
  29580. s7_pointer p, tp, np;
  29581. if (is_null(lst)) return(sc->nil);
  29582. if (!is_pair(lst))
  29583. s7_error(sc, sc->syntax_error_symbol, set_elist_2(sc, make_string_wrapper(sc, "stray dot?: ~S"), lst));
  29584. tp = cons(sc, car(lst), sc->nil);
  29585. sc->y = tp;
  29586. for (p = cdr(lst), np = tp; is_pair(p); p = cdr(p), np = cdr(np))
  29587. set_cdr(np, cons(sc, car(p), sc->nil));
  29588. sc->y = sc->nil;
  29589. if (!is_null(p))
  29590. s7_error(sc, sc->syntax_error_symbol, set_elist_2(sc, make_string_wrapper(sc, "improper list of arguments: ~S"), lst));
  29591. return(tp);
  29592. }
  29593. static s7_pointer revappend(s7_scheme *sc, s7_pointer a, s7_pointer b)
  29594. {
  29595. /* (map (lambda (x) (if (odd? x) (apply values '(1 2 3)) (values))) (list 1 2 3 4))
  29596. * is a bad case -- we have to copy the incoming list.
  29597. */
  29598. s7_pointer p = b, q;
  29599. if (is_not_null(a))
  29600. {
  29601. a = copy_list(sc, a);
  29602. while (is_not_null(a))
  29603. {
  29604. q = cdr(a);
  29605. set_cdr(a, p);
  29606. p = a;
  29607. a = q;
  29608. }
  29609. }
  29610. return(p);
  29611. }
  29612. static int safe_list_length(s7_scheme *sc, s7_pointer a)
  29613. {
  29614. /* assume that "a" is a proper list */
  29615. int i = 0;
  29616. s7_pointer b;
  29617. for (b = a; is_pair(b); i++, b = cdr(b)) {};
  29618. return(i);
  29619. }
  29620. int s7_list_length(s7_scheme *sc, s7_pointer a)
  29621. {
  29622. /* returns -len if list is dotted, 0 if it's (directly) circular */
  29623. int i;
  29624. s7_pointer slow, fast;
  29625. slow = fast = a;
  29626. for (i = 0; ; i += 2)
  29627. {
  29628. if (!is_pair(fast))
  29629. {
  29630. if (is_null(fast))
  29631. return(i);
  29632. return(-i);
  29633. }
  29634. fast = cdr(fast);
  29635. if (!is_pair(fast))
  29636. {
  29637. if (is_null(fast))
  29638. return(i + 1);
  29639. return(-i - 1);
  29640. }
  29641. /* if unrolled further, it's a lot slower? */
  29642. fast = cdr(fast);
  29643. slow = cdr(slow);
  29644. if (fast == slow)
  29645. return(0);
  29646. }
  29647. return(0);
  29648. }
  29649. /* -------------------------------- null? pair? -------------------------------- */
  29650. static s7_pointer g_is_null(s7_scheme *sc, s7_pointer args)
  29651. {
  29652. #define H_is_null "(null? obj) returns #t if obj is the empty list"
  29653. #define Q_is_null pl_bt
  29654. check_boolean_method(sc, is_null, sc->is_null_symbol, args);
  29655. /* as a generic this could be: has_structure and length == 0 */
  29656. }
  29657. static s7_pointer g_is_pair(s7_scheme *sc, s7_pointer args)
  29658. {
  29659. #define H_is_pair "(pair? obj) returns #t if obj is a pair (a non-empty list)"
  29660. #define Q_is_pair pl_bt
  29661. check_boolean_method(sc, is_pair, sc->is_pair_symbol, args);
  29662. }
  29663. /* -------------------------------- list? proper-list? -------------------------------- */
  29664. bool s7_is_list(s7_scheme *sc, s7_pointer p)
  29665. {
  29666. return((is_pair(p)) ||
  29667. (is_null(p)));
  29668. }
  29669. static bool is_proper_list(s7_scheme *sc, s7_pointer lst)
  29670. {
  29671. /* #t if () or undotted/non-circular pair */
  29672. s7_pointer slow, fast;
  29673. fast = lst;
  29674. slow = lst;
  29675. while (true)
  29676. {
  29677. if (!is_pair(fast))
  29678. return(is_null(fast)); /* else it's an improper list */
  29679. fast = cdr(fast);
  29680. if (!is_pair(fast)) return(is_null(fast));
  29681. fast = cdr(fast);
  29682. if (!is_pair(fast)) return(is_null(fast));
  29683. fast = cdr(fast);
  29684. slow = cdr(slow);
  29685. if (fast == slow) return(false);
  29686. }
  29687. return(true);
  29688. }
  29689. static s7_pointer g_is_list(s7_scheme *sc, s7_pointer args)
  29690. {
  29691. #define H_is_list "(list? obj) returns #t if obj is a pair or null"
  29692. #define Q_is_list pl_bt
  29693. #define is_a_list(p) s7_is_list(sc, p)
  29694. check_boolean_method(sc, is_a_list, sc->is_list_symbol, args);
  29695. }
  29696. /* -------------------------------- make-list -------------------------------- */
  29697. static s7_pointer make_list(s7_scheme *sc, int len, s7_pointer init)
  29698. {
  29699. switch (len)
  29700. {
  29701. case 0: return(sc->nil);
  29702. case 1: return(cons(sc, init, sc->nil));
  29703. case 2: return(cons_unchecked(sc, init, cons(sc, init, sc->nil)));
  29704. case 3: return(cons_unchecked(sc, init, cons_unchecked(sc, init, cons(sc, init, sc->nil))));
  29705. case 4: return(cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init, cons(sc, init, sc->nil)))));
  29706. case 5: return(cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init,
  29707. cons_unchecked(sc, init, cons(sc, init, sc->nil))))));
  29708. case 6: return(cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init,
  29709. cons_unchecked(sc, init, cons_unchecked(sc, init, cons(sc, init, sc->nil)))))));
  29710. case 7: return(cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init,
  29711. cons_unchecked(sc, init, cons_unchecked(sc, init, cons_unchecked(sc, init, cons(sc, init, sc->nil))))))));
  29712. default:
  29713. {
  29714. s7_pointer result;
  29715. int i;
  29716. if (len >= (sc->free_heap_top - sc->free_heap))
  29717. {
  29718. gc(sc);
  29719. while (len >= (sc->free_heap_top - sc->free_heap))
  29720. resize_heap(sc);
  29721. }
  29722. sc->v = sc->nil;
  29723. for (i = 0; i < len; i++)
  29724. sc->v = cons_unchecked(sc, init, sc->v);
  29725. result = sc->v;
  29726. sc->v = sc->nil;
  29727. return(result);
  29728. }
  29729. }
  29730. return(sc->nil); /* never happens, I hope */
  29731. }
  29732. static s7_pointer g_make_list(s7_scheme *sc, s7_pointer args)
  29733. {
  29734. #define H_make_list "(make-list length (initial-element #f)) returns a list of 'length' elements whose value is 'initial-element'."
  29735. #define Q_make_list s7_make_signature(sc, 3, sc->is_proper_list_symbol, sc->is_integer_symbol, sc->T)
  29736. s7_pointer init;
  29737. s7_int len;
  29738. if (!s7_is_integer(car(args)))
  29739. method_or_bust(sc, car(args), sc->make_list_symbol, args, T_INTEGER, 1);
  29740. len = s7_integer(car(args)); /* needs to be s7_int here so that (make-list most-negative-fixnum) is handled correctly */
  29741. if (len < 0)
  29742. return(out_of_range(sc, sc->make_list_symbol, small_int(1), car(args), its_negative_string));
  29743. if (len == 0) return(sc->nil); /* what about (make-list 0 123)? */
  29744. if (len > sc->max_list_length)
  29745. return(out_of_range(sc, sc->make_list_symbol, small_int(1), car(args), its_too_large_string));
  29746. if (is_pair(cdr(args)))
  29747. init = cadr(args);
  29748. else init = sc->F;
  29749. return(make_list(sc, (int)len, init));
  29750. }
  29751. static s7_pointer c_make_list(s7_scheme *sc, s7_int len) {return(make_list(sc, (int)len, sc->F));}
  29752. IF_TO_PF(make_list, c_make_list)
  29753. /* -------------------------------- list-ref -------------------------------- */
  29754. static s7_pointer list_ref_ic;
  29755. static s7_pointer g_list_ref_ic(s7_scheme *sc, s7_pointer args)
  29756. {
  29757. s7_int i, index;
  29758. s7_pointer lst, p;
  29759. lst = car(args);
  29760. if (!is_pair(lst))
  29761. method_or_bust(sc, lst, sc->list_ref_symbol, args, T_PAIR, 1);
  29762. index = s7_integer(cadr(args));
  29763. for (i = 0, p = lst; (i < index) && is_pair(p); i++, p = cdr(p)) {}
  29764. if (!is_pair(p))
  29765. {
  29766. if (is_null(p))
  29767. return(out_of_range(sc, sc->list_ref_symbol, small_int(2), cadr(args), its_too_large_string));
  29768. return(wrong_type_argument_with_type(sc, sc->list_ref_symbol, 1, lst, a_proper_list_string));
  29769. }
  29770. return(car(p));
  29771. }
  29772. static s7_pointer list_ref_1(s7_scheme *sc, s7_pointer lst, s7_pointer ind)
  29773. {
  29774. s7_int i, index;
  29775. s7_pointer p;
  29776. if (!s7_is_integer(ind))
  29777. {
  29778. if (!s7_is_integer(p = check_values(sc, ind, cons(sc, ind, sc->nil))))
  29779. method_or_bust(sc, ind, sc->list_ref_symbol, list_2(sc, lst, ind), T_INTEGER, 2);
  29780. ind = p;
  29781. }
  29782. index = s7_integer(ind);
  29783. if ((index < 0) || (index > sc->max_list_length))
  29784. return(out_of_range(sc, sc->list_ref_symbol, small_int(2), ind, (index < 0) ? its_negative_string : its_too_large_string));
  29785. for (i = 0, p = lst; (i < index) && is_pair(p); i++, p = cdr(p)) {}
  29786. if (!is_pair(p))
  29787. {
  29788. if (is_null(p))
  29789. return(out_of_range(sc, sc->list_ref_symbol, small_int(2), ind, its_too_large_string));
  29790. return(wrong_type_argument_with_type(sc, sc->list_ref_symbol, 1, lst, a_proper_list_string));
  29791. }
  29792. return(car(p));
  29793. }
  29794. static s7_pointer g_list_ref(s7_scheme *sc, s7_pointer args)
  29795. {
  29796. #define H_list_ref "(list-ref lst i ...) returns the i-th element (0-based) of the list"
  29797. #define Q_list_ref s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_pair_symbol, sc->is_integer_symbol)
  29798. /* (let ((L '((1 2 3) (4 5 6)))) (list-ref L 1 2))
  29799. (define (lref L . args)
  29800. (if (null? (cdr args))
  29801. (list-ref L (car args))
  29802. (apply lref (list-ref L (car args)) (cdr args))))
  29803. */
  29804. s7_pointer lst, inds;
  29805. lst = car(args);
  29806. if (!is_pair(lst))
  29807. method_or_bust(sc, lst, sc->list_ref_symbol, args, T_PAIR, 1);
  29808. inds = cdr(args);
  29809. while (true)
  29810. {
  29811. lst = list_ref_1(sc, lst, car(inds));
  29812. if (is_null(cdr(inds)))
  29813. return(lst);
  29814. inds = cdr(inds);
  29815. if (!is_pair(lst)) /* trying to avoid a cons here at the cost of one extra type check */
  29816. return(implicit_index(sc, lst, inds));
  29817. }
  29818. }
  29819. static s7_pointer c_list_ref(s7_scheme *sc, s7_pointer x, s7_int index)
  29820. {
  29821. int i;
  29822. s7_pointer p;
  29823. if (!s7_is_pair(x))
  29824. method_or_bust(sc, x, sc->list_ref_symbol, list_2(sc, x, make_integer(sc, index)), T_PAIR, 1);
  29825. if (index < 0)
  29826. return(out_of_range(sc, sc->list_ref_symbol, small_int(2), make_integer(sc, index), its_negative_string));
  29827. for (i = 0, p = x; (i < index) && is_pair(p); i++, p = cdr(p)) {}
  29828. if (!is_pair(p))
  29829. {
  29830. if (is_null(p))
  29831. return(out_of_range(sc, sc->list_ref_symbol, small_int(2), make_integer(sc, index), its_too_large_string));
  29832. return(wrong_type_argument_with_type(sc, sc->list_ref_symbol, 1, x, a_proper_list_string));
  29833. }
  29834. return(car(p));
  29835. }
  29836. PIF_TO_PF(list_ref, c_list_ref)
  29837. /* -------------------------------- list-set! -------------------------------- */
  29838. static s7_pointer g_list_set_1(s7_scheme *sc, s7_pointer lst, s7_pointer args, int arg_num)
  29839. {
  29840. #define H_list_set "(list-set! lst i ... val) sets the i-th element (0-based) of the list to val"
  29841. #define Q_list_set s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_pair_symbol, sc->T)
  29842. int i;
  29843. s7_int index;
  29844. s7_pointer p, ind;
  29845. /* (let ((L '((1 2 3) (4 5 6)))) (list-set! L 1 2 32) L) */
  29846. if (!is_pair(lst))
  29847. method_or_bust(sc, lst, sc->list_set_symbol, cons(sc, lst, args), T_PAIR, 1);
  29848. ind = car(args);
  29849. if (!s7_is_integer(ind))
  29850. {
  29851. if (!s7_is_integer(p = check_values(sc, ind, args)))
  29852. method_or_bust(sc, ind, sc->list_set_symbol, cons(sc, lst, args), T_INTEGER, arg_num);
  29853. ind = p;
  29854. }
  29855. index = s7_integer(ind);
  29856. if ((index < 0) || (index > sc->max_list_length))
  29857. return(out_of_range(sc, sc->list_set_symbol, small_int(arg_num), ind, (index < 0) ? its_negative_string : its_too_large_string));
  29858. for (i = 0, p = _TSet(lst); (i < index) && is_pair(p); i++, p = cdr(p)) {}
  29859. if (!is_pair(p))
  29860. {
  29861. if (is_null(p))
  29862. return(out_of_range(sc, sc->list_set_symbol, small_int(arg_num), ind, its_too_large_string));
  29863. return(wrong_type_argument_with_type(sc, sc->list_set_symbol, 1, lst, a_proper_list_string));
  29864. }
  29865. if (is_null(cddr(args)))
  29866. set_car(p, cadr(args));
  29867. else return(g_list_set_1(sc, car(p), cdr(args), arg_num + 1));
  29868. return(cadr(args));
  29869. }
  29870. static s7_pointer g_list_set(s7_scheme *sc, s7_pointer args)
  29871. {
  29872. return(g_list_set_1(sc, car(args), cdr(args), 2));
  29873. }
  29874. static int c_list_tester(s7_scheme *sc, s7_pointer expr)
  29875. {
  29876. s7_pointer a1;
  29877. a1 = cadr(expr);
  29878. if (is_symbol(a1))
  29879. {
  29880. s7_pointer table;
  29881. table = s7_slot(sc, a1);
  29882. if ((is_slot(table)) &&
  29883. ((is_immutable_symbol(a1)) || (!is_stepper(table))) &&
  29884. (is_pair(slot_value(table))))
  29885. {
  29886. s7_xf_store(sc, slot_value(table));
  29887. a1 = caddr(expr);
  29888. if (is_symbol(a1))
  29889. {
  29890. s7_pointer slot;
  29891. slot = s7_slot(sc, a1);
  29892. if ((is_slot(slot)) &&
  29893. (is_integer(slot_value(slot))))
  29894. {
  29895. s7_xf_store(sc, slot);
  29896. return(TEST_SS);
  29897. }
  29898. }
  29899. else
  29900. {
  29901. if (s7_arg_to_if(sc, a1))
  29902. return(TEST_SI);
  29903. }
  29904. return(TEST_SQ);
  29905. }
  29906. }
  29907. return(TEST_NO_S);
  29908. }
  29909. static s7_pointer c_list_set_s(s7_scheme *sc, s7_pointer lst, s7_int index, s7_pointer val)
  29910. {
  29911. s7_int i;
  29912. s7_pointer p;
  29913. if ((index < 0) || (index > sc->max_list_length))
  29914. return(out_of_range(sc, sc->list_set_symbol, small_int(2), make_integer(sc, index), (index < 0) ? its_negative_string : its_too_large_string));
  29915. for (i = 0, p = lst; (i < index) && is_pair(p); i++, p = cdr(p)) {}
  29916. if (!is_pair(p))
  29917. {
  29918. if (is_null(p))
  29919. return(out_of_range(sc, sc->list_set_symbol, small_int(2), make_integer(sc, index), its_too_large_string));
  29920. return(wrong_type_argument_with_type(sc, sc->list_set_symbol, 1, lst, a_proper_list_string));
  29921. }
  29922. set_car(p, val);
  29923. return(val);
  29924. }
  29925. static s7_pointer c_list_set(s7_scheme *sc, s7_pointer vec, s7_int index, s7_pointer val)
  29926. {
  29927. if (!s7_is_pair(vec))
  29928. method_or_bust(sc, vec, sc->list_set_symbol, set_plist_3(sc, vec, make_integer(sc, index), val), T_PAIR, 1);
  29929. return(c_list_set_s(sc, vec, index, val));
  29930. }
  29931. PIPF_TO_PF(list_set, c_list_set_s, c_list_set, c_list_tester)
  29932. static s7_pointer list_set_ic;
  29933. static s7_pointer g_list_set_ic(s7_scheme *sc, s7_pointer args)
  29934. {
  29935. s7_pointer lst;
  29936. lst = car(args);
  29937. if (!is_pair(lst))
  29938. method_or_bust(sc, lst, sc->list_set_symbol, args, T_PAIR, 1);
  29939. return(c_list_set_s(sc, lst, s7_integer(cadr(args)), caddr(args)));
  29940. }
  29941. /* -------------------------------- list-tail -------------------------------- */
  29942. static s7_pointer c_list_tail(s7_scheme *sc, s7_pointer lst, s7_int index)
  29943. {
  29944. s7_int i;
  29945. s7_pointer p;
  29946. if (!s7_is_list(sc, lst))
  29947. method_or_bust_with_type(sc, lst, sc->list_tail_symbol, list_2(sc, lst, make_integer(sc, index)), a_list_string, 1);
  29948. if ((index < 0) || (index > sc->max_list_length))
  29949. return(out_of_range(sc, sc->list_tail_symbol, small_int(2), make_integer(sc, index), (index < 0) ? its_negative_string : its_too_large_string));
  29950. for (i = 0, p = lst; (i < index) && (is_pair(p)); i++, p = cdr(p)) {}
  29951. if (i < index)
  29952. return(out_of_range(sc, sc->list_tail_symbol, small_int(2), make_integer(sc, index), its_too_large_string));
  29953. return(p);
  29954. }
  29955. static s7_pointer g_list_tail(s7_scheme *sc, s7_pointer args)
  29956. {
  29957. #define H_list_tail "(list-tail lst i) returns the list from the i-th element on"
  29958. #define Q_list_tail s7_make_signature(sc, 3, sc->is_list_symbol, sc->is_pair_symbol, sc->is_integer_symbol)
  29959. s7_pointer p;
  29960. p = cadr(args);
  29961. if (!s7_is_integer(p))
  29962. {
  29963. s7_pointer p1;
  29964. if (!s7_is_integer(p1 = check_values(sc, p, cdr(args))))
  29965. method_or_bust(sc, p, sc->list_tail_symbol, args, T_INTEGER, 2);
  29966. p = p1;
  29967. }
  29968. return(c_list_tail(sc, car(args), s7_integer(p)));
  29969. }
  29970. PIF_TO_PF(list_tail, c_list_tail)
  29971. /* -------------------------------- cons -------------------------------- */
  29972. static s7_pointer g_cons(s7_scheme *sc, s7_pointer args)
  29973. {
  29974. /* n-ary cons could be the equivalent of CL's list*? */
  29975. /* it would be neater to have a single cons cell able to contain (directly) any number of elements */
  29976. /* (set! (cadr (cons 1 2 3)) 4) -> (1 4 . 3) */
  29977. #define H_cons "(cons a b) returns a pair containing a and b"
  29978. #define Q_cons s7_make_signature(sc, 3, sc->is_pair_symbol, sc->T, sc->T)
  29979. /* set_cdr(args, cadr(args));
  29980. * this is not safe -- it changes a variable's value directly:
  29981. * (let ((lst (list 1 2))) (list (apply cons lst) lst)) -> '((1 . 2) (1 . 2))
  29982. */
  29983. s7_pointer x;
  29984. new_cell(sc, x, T_PAIR | T_SAFE_PROCEDURE);
  29985. set_car(x, car(args));
  29986. set_cdr(x, cadr(args));
  29987. return(x);
  29988. }
  29989. PF2_TO_PF(cons, s7_cons)
  29990. static void init_car_a_list(void)
  29991. {
  29992. car_a_list_string = s7_make_permanent_string("a list whose car is also a list");
  29993. cdr_a_list_string = s7_make_permanent_string("a list whose cdr is also a list");
  29994. caar_a_list_string = s7_make_permanent_string("a list whose caar is also a list");
  29995. cadr_a_list_string = s7_make_permanent_string("a list whose cadr is also a list");
  29996. cdar_a_list_string = s7_make_permanent_string("a list whose cdar is also a list");
  29997. cddr_a_list_string = s7_make_permanent_string("a list whose cddr is also a list");
  29998. caaar_a_list_string = s7_make_permanent_string("a list whose caaar is also a list");
  29999. caadr_a_list_string = s7_make_permanent_string("a list whose caadr is also a list");
  30000. cadar_a_list_string = s7_make_permanent_string("a list whose cadar is also a list");
  30001. caddr_a_list_string = s7_make_permanent_string("a list whose caddr is also a list");
  30002. cdaar_a_list_string = s7_make_permanent_string("a list whose cdaar is also a list");
  30003. cdadr_a_list_string = s7_make_permanent_string("a list whose cdadr is also a list");
  30004. cddar_a_list_string = s7_make_permanent_string("a list whose cddar is also a list");
  30005. cdddr_a_list_string = s7_make_permanent_string("a list whose cdddr is also a list");
  30006. a_list_string = s7_make_permanent_string("a list");
  30007. an_eq_func_string = s7_make_permanent_string("a procedure that can take 2 arguments");
  30008. an_association_list_string = s7_make_permanent_string("an association list");
  30009. a_normal_real_string = s7_make_permanent_string("a normal real");
  30010. a_rational_string = s7_make_permanent_string("an integer or a ratio");
  30011. a_number_string = s7_make_permanent_string("a number");
  30012. a_procedure_string = s7_make_permanent_string("a procedure");
  30013. a_normal_procedure_string = s7_make_permanent_string("a normal procedure (not a continuation)");
  30014. a_let_string = s7_make_permanent_string("a let (environment)");
  30015. a_proper_list_string = s7_make_permanent_string("a proper list");
  30016. a_boolean_string = s7_make_permanent_string("a boolean");
  30017. an_input_port_string = s7_make_permanent_string("an input port");
  30018. an_open_port_string = s7_make_permanent_string("an open port");
  30019. an_output_port_string = s7_make_permanent_string("an output port");
  30020. an_input_string_port_string = s7_make_permanent_string("an input string port");
  30021. an_input_file_port_string = s7_make_permanent_string("an input file port");
  30022. an_output_string_port_string = s7_make_permanent_string("an output string port");
  30023. an_output_file_port_string = s7_make_permanent_string("an output file port");
  30024. a_thunk_string = s7_make_permanent_string("a thunk");
  30025. a_symbol_string = s7_make_permanent_string("a symbol");
  30026. a_non_negative_integer_string = s7_make_permanent_string("a non-negative integer");
  30027. an_unsigned_byte_string = s7_make_permanent_string("an unsigned byte");
  30028. something_applicable_string = s7_make_permanent_string("a procedure or something applicable");
  30029. a_random_state_object_string = s7_make_permanent_string("a random-state object");
  30030. a_format_port_string = s7_make_permanent_string("#f, #t, or an open output port");
  30031. a_binding_string = s7_make_permanent_string("a pair whose car is a symbol: '(symbol . value)");
  30032. a_non_constant_symbol_string = s7_make_permanent_string("a non-constant symbol");
  30033. a_sequence_string = s7_make_permanent_string("a sequence");
  30034. a_valid_radix_string = s7_make_permanent_string("should be between 2 and 16");
  30035. result_is_too_large_string = s7_make_permanent_string("result is too large");
  30036. its_too_large_string = s7_make_permanent_string("it is too large");
  30037. its_too_small_string = s7_make_permanent_string("it is less than the start position");
  30038. its_negative_string = s7_make_permanent_string("it is negative");
  30039. its_nan_string = s7_make_permanent_string("NaN usually indicates a numerical error");
  30040. its_infinite_string = s7_make_permanent_string("it is infinite");
  30041. too_many_indices_string = s7_make_permanent_string("too many indices");
  30042. #if (!HAVE_COMPLEX_NUMBERS)
  30043. no_complex_numbers_string = s7_make_permanent_string("this version of s7 does not support complex numbers");
  30044. #endif
  30045. }
  30046. /* -------- car -------- */
  30047. static s7_pointer g_car_1(s7_scheme *sc, s7_pointer lst)
  30048. {
  30049. if (!is_pair(lst))
  30050. method_or_bust(sc, lst, sc->car_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30051. return(car(lst));
  30052. }
  30053. static s7_pointer g_car(s7_scheme *sc, s7_pointer args)
  30054. {
  30055. #define H_car "(car pair) returns the first element of the pair"
  30056. #define Q_car pl_p
  30057. s7_pointer lst;
  30058. lst = car(args);
  30059. if (!is_pair(lst))
  30060. method_or_bust(sc, lst, sc->car_symbol, args, T_PAIR, 0);
  30061. return(car(lst));
  30062. }
  30063. PF_TO_PF(car, g_car_1)
  30064. static s7_pointer g_set_car(s7_scheme *sc, s7_pointer args)
  30065. {
  30066. #define H_set_car "(set-car! pair val) sets the pair's first element to val"
  30067. #define Q_set_car s7_make_signature(sc, 3, sc->T, sc->is_pair_symbol, sc->T)
  30068. s7_pointer p;
  30069. p = car(args);
  30070. if (!is_pair(p))
  30071. method_or_bust(sc, p, sc->set_car_symbol, args, T_PAIR, 1);
  30072. set_car(p, cadr(args));
  30073. return(car(p));
  30074. }
  30075. static s7_pointer c_set_car(s7_scheme *sc, s7_pointer x, s7_pointer y)
  30076. {
  30077. if (!is_pair(x))
  30078. method_or_bust(sc, x, sc->set_car_symbol, set_plist_2(sc, x, y), T_PAIR, 1);
  30079. set_car(x, y);
  30080. return(y);
  30081. }
  30082. PF2_TO_PF(set_car, c_set_car)
  30083. /* -------- cdr -------- */
  30084. static s7_pointer g_cdr_1(s7_scheme *sc, s7_pointer lst)
  30085. {
  30086. if (!is_pair(lst))
  30087. method_or_bust(sc, lst, sc->cdr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30088. return(cdr(lst));
  30089. }
  30090. static s7_pointer g_cdr(s7_scheme *sc, s7_pointer args)
  30091. {
  30092. #define H_cdr "(cdr pair) returns the second element of the pair"
  30093. #define Q_cdr pl_p
  30094. s7_pointer lst;
  30095. lst = car(args);
  30096. if (!is_pair(lst))
  30097. method_or_bust(sc, lst, sc->cdr_symbol, args, T_PAIR, 0);
  30098. return(cdr(lst));
  30099. }
  30100. PF_TO_PF(cdr, g_cdr_1)
  30101. static s7_pointer g_set_cdr(s7_scheme *sc, s7_pointer args)
  30102. {
  30103. #define H_set_cdr "(set-cdr! pair val) sets the pair's second element to val"
  30104. #define Q_set_cdr s7_make_signature(sc, 3, sc->T, sc->is_pair_symbol, sc->T)
  30105. s7_pointer p;
  30106. p = car(args);
  30107. if (!is_pair(p))
  30108. method_or_bust(sc, p, sc->set_cdr_symbol, args, T_PAIR, 1);
  30109. set_cdr(p, cadr(args));
  30110. return(cdr(p));
  30111. }
  30112. static s7_pointer c_set_cdr(s7_scheme *sc, s7_pointer x, s7_pointer y)
  30113. {
  30114. if (!is_pair(x))
  30115. method_or_bust(sc, x, sc->set_cdr_symbol, set_plist_2(sc, x, y), T_PAIR, 1);
  30116. set_cdr(x, y);
  30117. return(y);
  30118. }
  30119. PF2_TO_PF(set_cdr, c_set_cdr)
  30120. /* -------- caar --------*/
  30121. static s7_pointer g_caar_1(s7_scheme *sc, s7_pointer lst)
  30122. {
  30123. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30124. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caar_symbol, lst, car_a_list_string));
  30125. /* it makes no difference in timing to move lst here or below (i.e. lst=car(lst) then return(car(lst)) and so on) */
  30126. return(caar(lst));
  30127. }
  30128. static s7_pointer g_caar(s7_scheme *sc, s7_pointer args)
  30129. {
  30130. #define H_caar "(caar lst) returns (car (car lst)): (caar '((1 2))) -> 1"
  30131. #define Q_caar pl_p
  30132. s7_pointer lst;
  30133. lst = car(args);
  30134. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caar_symbol, args, T_PAIR, 0);
  30135. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caar_symbol, lst, car_a_list_string));
  30136. /* it makes no difference in timing to move lst here or below (i.e. lst=car(lst) then return(car(lst)) and so on) */
  30137. return(caar(lst));
  30138. }
  30139. PF_TO_PF(caar, g_caar_1)
  30140. /* -------- cadr --------*/
  30141. static s7_pointer g_cadr_1(s7_scheme *sc, s7_pointer lst)
  30142. {
  30143. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cadr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30144. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadr_symbol, lst, cdr_a_list_string));
  30145. return(cadr(lst));
  30146. }
  30147. static s7_pointer g_cadr(s7_scheme *sc, s7_pointer args)
  30148. {
  30149. #define H_cadr "(cadr lst) returns (car (cdr lst)): (cadr '(1 2 3)) -> 2"
  30150. #define Q_cadr pl_p
  30151. s7_pointer lst;
  30152. lst = car(args);
  30153. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cadr_symbol, args, T_PAIR, 0);
  30154. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadr_symbol, lst, cdr_a_list_string));
  30155. return(cadr(lst));
  30156. }
  30157. PF_TO_PF(cadr, g_cadr_1)
  30158. /* -------- cdar -------- */
  30159. static s7_pointer g_cdar_1(s7_scheme *sc, s7_pointer lst)
  30160. {
  30161. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30162. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdar_symbol, lst, car_a_list_string));
  30163. return(cdar(lst));
  30164. }
  30165. static s7_pointer g_cdar(s7_scheme *sc, s7_pointer args)
  30166. {
  30167. #define H_cdar "(cdar lst) returns (cdr (car lst)): (cdar '((1 2 3))) -> '(2 3)"
  30168. #define Q_cdar pl_p
  30169. s7_pointer lst;
  30170. lst = car(args);
  30171. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdar_symbol, args, T_PAIR, 0);
  30172. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdar_symbol, lst, car_a_list_string));
  30173. return(cdar(lst));
  30174. }
  30175. PF_TO_PF(cdar, g_cdar_1)
  30176. /* -------- cddr -------- */
  30177. static s7_pointer g_cddr_1(s7_scheme *sc, s7_pointer lst)
  30178. {
  30179. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cddr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30180. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddr_symbol, lst, cdr_a_list_string));
  30181. return(cddr(lst));
  30182. }
  30183. static s7_pointer g_cddr(s7_scheme *sc, s7_pointer args)
  30184. {
  30185. #define H_cddr "(cddr lst) returns (cdr (cdr lst)): (cddr '(1 2 3 4)) -> '(3 4)"
  30186. #define Q_cddr pl_p
  30187. s7_pointer lst;
  30188. lst = car(args);
  30189. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cddr_symbol, args, T_PAIR, 0);
  30190. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddr_symbol, lst, cdr_a_list_string));
  30191. return(cddr(lst));
  30192. }
  30193. PF_TO_PF(cddr, g_cddr_1)
  30194. /* -------- caaar -------- */
  30195. static s7_pointer g_caaar_1(s7_scheme *sc, s7_pointer lst)
  30196. {
  30197. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caaar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30198. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaar_symbol, lst, car_a_list_string));
  30199. if (!is_pair(car(car(lst)))) return(simple_wrong_type_argument_with_type(sc, sc->caaar_symbol, lst, caar_a_list_string));
  30200. return(caaar(lst));
  30201. }
  30202. static s7_pointer g_caaar(s7_scheme *sc, s7_pointer args)
  30203. {
  30204. #define H_caaar "(caaar lst) returns (car (car (car lst))): (caaar '(((1 2)))) -> 1"
  30205. #define Q_caaar pl_p
  30206. return(g_caaar_1(sc, car(args)));
  30207. }
  30208. PF_TO_PF(caaar, g_caaar_1)
  30209. /* -------- caadr -------- */
  30210. static s7_pointer g_caadr_1(s7_scheme *sc, s7_pointer lst)
  30211. {
  30212. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caadr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30213. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caadr_symbol, lst, cdr_a_list_string));
  30214. if (!is_pair(car(cdr(lst)))) return(simple_wrong_type_argument_with_type(sc, sc->caadr_symbol, lst, cadr_a_list_string));
  30215. return(caadr(lst));
  30216. }
  30217. static s7_pointer g_caadr(s7_scheme *sc, s7_pointer args)
  30218. {
  30219. #define H_caadr "(caadr lst) returns (car (car (cdr lst))): (caadr '(1 (2 3))) -> 2"
  30220. #define Q_caadr pl_p
  30221. return(g_caadr_1(sc, car(args)));
  30222. }
  30223. PF_TO_PF(caadr, g_caadr_1)
  30224. /* -------- cadar -------- */
  30225. static s7_pointer g_cadar_1(s7_scheme *sc, s7_pointer lst)
  30226. {
  30227. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cadar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30228. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadar_symbol, lst, car_a_list_string));
  30229. if (!is_pair(cdr(car(lst)))) return(simple_wrong_type_argument_with_type(sc, sc->cadar_symbol, lst, cdar_a_list_string));
  30230. return(cadar(lst));
  30231. }
  30232. static s7_pointer g_cadar(s7_scheme *sc, s7_pointer args)
  30233. {
  30234. #define H_cadar "(cadar lst) returns (car (cdr (car lst))): (cadar '((1 2 3))) -> 2"
  30235. #define Q_cadar pl_p
  30236. return(g_cadar_1(sc, car(args)));
  30237. }
  30238. PF_TO_PF(cadar, g_cadar_1)
  30239. /* -------- cdaar -------- */
  30240. static s7_pointer g_cdaar_1(s7_scheme *sc, s7_pointer lst)
  30241. {
  30242. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdaar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30243. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaar_symbol, lst, car_a_list_string));
  30244. if (!is_pair(car(car(lst)))) return(simple_wrong_type_argument_with_type(sc, sc->cdaar_symbol, lst, caar_a_list_string));
  30245. return(cdaar(lst));
  30246. }
  30247. static s7_pointer g_cdaar(s7_scheme *sc, s7_pointer args)
  30248. {
  30249. #define H_cdaar "(cdaar lst) returns (cdr (car (car lst))): (cdaar '(((1 2 3)))) -> '(2 3)"
  30250. #define Q_cdaar pl_p
  30251. return(g_cdaar_1(sc, car(args)));
  30252. }
  30253. PF_TO_PF(cdaar, g_cdaar_1)
  30254. /* -------- caddr -------- */
  30255. static s7_pointer g_caddr_1(s7_scheme *sc, s7_pointer lst)
  30256. {
  30257. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caddr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30258. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caddr_symbol, lst, cdr_a_list_string));
  30259. if (!is_pair(cdr(cdr(lst)))) return(simple_wrong_type_argument_with_type(sc, sc->caddr_symbol, lst, cddr_a_list_string));
  30260. return(caddr(lst));
  30261. }
  30262. static s7_pointer g_caddr(s7_scheme *sc, s7_pointer args)
  30263. {
  30264. #define H_caddr "(caddr lst) returns (car (cdr (cdr lst))): (caddr '(1 2 3 4)) -> 3"
  30265. #define Q_caddr pl_p
  30266. return(g_caddr_1(sc, car(args)));
  30267. }
  30268. PF_TO_PF(caddr, g_caddr_1)
  30269. /* -------- cdddr -------- */
  30270. static s7_pointer g_cdddr_1(s7_scheme *sc, s7_pointer lst)
  30271. {
  30272. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdddr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30273. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdddr_symbol, lst, cdr_a_list_string));
  30274. if (!is_pair(cdr(cdr(lst)))) return(simple_wrong_type_argument_with_type(sc, sc->cdddr_symbol, lst, cddr_a_list_string));
  30275. return(cdddr(lst));
  30276. }
  30277. static s7_pointer g_cdddr(s7_scheme *sc, s7_pointer args)
  30278. {
  30279. #define H_cdddr "(cdddr lst) returns (cdr (cdr (cdr lst))): (cdddr '(1 2 3 4)) -> '(4)"
  30280. #define Q_cdddr pl_p
  30281. return(g_cdddr_1(sc, car(args)));
  30282. }
  30283. PF_TO_PF(cdddr, g_cdddr_1)
  30284. /* -------- cdadr -------- */
  30285. static s7_pointer g_cdadr_1(s7_scheme *sc, s7_pointer lst)
  30286. {
  30287. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdadr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30288. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdadr_symbol, lst, cdr_a_list_string));
  30289. if (!is_pair(car(cdr(lst)))) return(simple_wrong_type_argument_with_type(sc, sc->cdadr_symbol, lst, cadr_a_list_string));
  30290. return(cdadr(lst));
  30291. }
  30292. static s7_pointer g_cdadr(s7_scheme *sc, s7_pointer args)
  30293. {
  30294. #define H_cdadr "(cdadr lst) returns (cdr (car (cdr lst))): (cdadr '(1 (2 3 4))) -> '(3 4)"
  30295. #define Q_cdadr pl_p
  30296. return(g_cdadr_1(sc, car(args)));
  30297. }
  30298. PF_TO_PF(cdadr, g_cdadr_1)
  30299. /* -------- cddar -------- */
  30300. static s7_pointer g_cddar_1(s7_scheme *sc, s7_pointer lst)
  30301. {
  30302. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cddar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30303. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddar_symbol, lst, car_a_list_string));
  30304. if (!is_pair(cdr(car(lst)))) return(simple_wrong_type_argument_with_type(sc, sc->cddar_symbol, lst, cdar_a_list_string));
  30305. return(cddar(lst));
  30306. }
  30307. static s7_pointer g_cddar(s7_scheme *sc, s7_pointer args)
  30308. {
  30309. #define H_cddar "(cddar lst) returns (cdr (cdr (car lst))): (cddar '((1 2 3 4))) -> '(3 4)"
  30310. #define Q_cddar pl_p
  30311. return(g_cddar_1(sc, car(args)));
  30312. }
  30313. PF_TO_PF(cddar, g_cddar_1)
  30314. /* -------- caaaar -------- */
  30315. static s7_pointer g_caaaar_1(s7_scheme *sc, s7_pointer lst)
  30316. {
  30317. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caaaar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30318. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaaar_symbol, lst, car_a_list_string));
  30319. if (!is_pair(caar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaaar_symbol, lst, caar_a_list_string));
  30320. if (!is_pair(caaar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaaar_symbol, lst, caaar_a_list_string));
  30321. return(caaaar(lst));
  30322. }
  30323. static s7_pointer g_caaaar(s7_scheme *sc, s7_pointer args)
  30324. {
  30325. #define H_caaaar "(caaaar lst) returns (car (car (car (car lst)))): (caaaar '((((1 2))))) -> 1"
  30326. #define Q_caaaar pl_p
  30327. return(g_caaaar_1(sc, car(args)));
  30328. }
  30329. PF_TO_PF(caaaar, g_caaaar_1)
  30330. /* -------- caaadr -------- */
  30331. static s7_pointer g_caaadr_1(s7_scheme *sc, s7_pointer lst)
  30332. {
  30333. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caaadr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30334. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaadr_symbol, lst, cdr_a_list_string));
  30335. if (!is_pair(cadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaadr_symbol, lst, cadr_a_list_string));
  30336. if (!is_pair(caadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaadr_symbol, lst, caadr_a_list_string));
  30337. return(caaadr(lst));
  30338. }
  30339. static s7_pointer g_caaadr(s7_scheme *sc, s7_pointer args)
  30340. {
  30341. #define H_caaadr "(caaadr lst) returns (car (car (car (cdr lst)))): (caaadr '(1 ((2 3)))) -> 2"
  30342. #define Q_caaadr pl_p
  30343. return(g_caaadr_1(sc, car(args)));
  30344. }
  30345. PF_TO_PF(caaadr, g_caaadr_1)
  30346. /* -------- caadar -------- */
  30347. static s7_pointer g_caadar_1(s7_scheme *sc, s7_pointer lst)
  30348. {
  30349. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caadar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30350. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caadar_symbol, lst, car_a_list_string));
  30351. if (!is_pair(cdar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caadar_symbol, lst, cdar_a_list_string));
  30352. if (!is_pair(cadar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caadar_symbol, lst, cadar_a_list_string));
  30353. return(caadar(lst));
  30354. }
  30355. static s7_pointer g_caadar(s7_scheme *sc, s7_pointer args)
  30356. {
  30357. #define H_caadar "(caadar lst) returns (car (car (cdr (car lst)))): (caadar '((1 (2 3)))) -> 2"
  30358. #define Q_caadar pl_p
  30359. return(g_caadar_1(sc, car(args)));
  30360. }
  30361. PF_TO_PF(caadar, g_caadar_1)
  30362. /* -------- cadaar -------- */
  30363. static s7_pointer g_cadaar_1(s7_scheme *sc, s7_pointer lst)
  30364. {
  30365. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cadaar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30366. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadaar_symbol, lst, car_a_list_string));
  30367. if (!is_pair(caar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadaar_symbol, lst, caar_a_list_string));
  30368. if (!is_pair(cdaar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadaar_symbol, lst, cdaar_a_list_string));
  30369. return(cadaar(lst));
  30370. }
  30371. static s7_pointer g_cadaar(s7_scheme *sc, s7_pointer args)
  30372. {
  30373. #define H_cadaar "(cadaar lst) returns (car (cdr (car (car lst)))): (cadaar '(((1 2 3)))) -> 2"
  30374. #define Q_cadaar pl_p
  30375. return(g_cadaar_1(sc, car(args)));
  30376. }
  30377. PF_TO_PF(cadaar, g_cadaar_1)
  30378. /* -------- caaddr -------- */
  30379. static s7_pointer g_caaddr_1(s7_scheme *sc, s7_pointer lst)
  30380. {
  30381. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caaddr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30382. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaddr_symbol, lst, cdr_a_list_string));
  30383. if (!is_pair(cddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaddr_symbol, lst, cddr_a_list_string));
  30384. if (!is_pair(caddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caaddr_symbol, lst, caddr_a_list_string));
  30385. return(caaddr(lst));
  30386. }
  30387. static s7_pointer g_caaddr(s7_scheme *sc, s7_pointer args)
  30388. {
  30389. #define H_caaddr "(caaddr lst) returns (car (car (cdr (cdr lst)))): (caaddr '(1 2 (3 4))) -> 3"
  30390. #define Q_caaddr pl_p
  30391. return(g_caaddr_1(sc, car(args)));
  30392. }
  30393. PF_TO_PF(caaddr, g_caaddr_1)
  30394. /* -------- cadddr -------- */
  30395. static s7_pointer g_cadddr_1(s7_scheme *sc, s7_pointer lst)
  30396. {
  30397. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cadddr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30398. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadddr_symbol, lst, cdr_a_list_string));
  30399. if (!is_pair(cddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadddr_symbol, lst, cddr_a_list_string));
  30400. if (!is_pair(cdddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadddr_symbol, lst, cdddr_a_list_string));
  30401. return(cadddr(lst));
  30402. }
  30403. static s7_pointer g_cadddr(s7_scheme *sc, s7_pointer args)
  30404. {
  30405. #define H_cadddr "(cadddr lst) returns (car (cdr (cdr (cdr lst)))): (cadddr '(1 2 3 4 5)) -> 4"
  30406. #define Q_cadddr pl_p
  30407. return(g_cadddr_1(sc, car(args)));
  30408. }
  30409. PF_TO_PF(cadddr, g_cadddr_1)
  30410. /* -------- cadadr -------- */
  30411. static s7_pointer g_cadadr_1(s7_scheme *sc, s7_pointer lst)
  30412. {
  30413. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cadadr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30414. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadadr_symbol, lst, cdr_a_list_string));
  30415. if (!is_pair(cadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadadr_symbol, lst, cadr_a_list_string));
  30416. if (!is_pair(cdadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cadadr_symbol, lst, cdadr_a_list_string));
  30417. return(cadadr(lst));
  30418. }
  30419. static s7_pointer g_cadadr(s7_scheme *sc, s7_pointer args)
  30420. {
  30421. #define H_cadadr "(cadadr lst) returns (car (cdr (car (cdr lst)))): (cadadr '(1 (2 3 4))) -> 3"
  30422. #define Q_cadadr pl_p
  30423. return(g_cadadr_1(sc, car(args)));
  30424. }
  30425. PF_TO_PF(cadadr, g_cadadr_1)
  30426. /* -------- caddar -------- */
  30427. static s7_pointer g_caddar_1(s7_scheme *sc, s7_pointer lst)
  30428. {
  30429. if (!is_pair(lst)) method_or_bust(sc, lst, sc->caddar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30430. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caddar_symbol, lst, car_a_list_string));
  30431. if (!is_pair(cdar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caddar_symbol, lst, cdar_a_list_string));
  30432. if (!is_pair(cddar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->caddar_symbol, lst, cddar_a_list_string));
  30433. return(caddar(lst));
  30434. }
  30435. static s7_pointer g_caddar(s7_scheme *sc, s7_pointer args)
  30436. {
  30437. #define H_caddar "(caddar lst) returns (car (cdr (cdr (car lst)))): (caddar '((1 2 3 4))) -> 3"
  30438. #define Q_caddar pl_p
  30439. return(g_caddar_1(sc, car(args)));
  30440. }
  30441. PF_TO_PF(caddar, g_caddar_1)
  30442. /* -------- cdaaar -------- */
  30443. static s7_pointer g_cdaaar_1(s7_scheme *sc, s7_pointer lst)
  30444. {
  30445. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdaaar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30446. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaaar_symbol, lst, car_a_list_string));
  30447. if (!is_pair(caar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaaar_symbol, lst, caar_a_list_string));
  30448. if (!is_pair(caaar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaaar_symbol, lst, caaar_a_list_string));
  30449. return(cdaaar(lst));
  30450. }
  30451. static s7_pointer g_cdaaar(s7_scheme *sc, s7_pointer args)
  30452. {
  30453. #define H_cdaaar "(cdaaar lst) returns (cdr (car (car (car lst)))): (cdaaar '((((1 2 3))))) -> '(2 3)"
  30454. #define Q_cdaaar pl_p
  30455. return(g_cdaaar_1(sc, car(args)));
  30456. }
  30457. PF_TO_PF(cdaaar, g_cdaaar_1)
  30458. /* -------- cdaadr -------- */
  30459. static s7_pointer g_cdaadr_1(s7_scheme *sc, s7_pointer lst)
  30460. {
  30461. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdaadr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30462. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaadr_symbol, lst, cdr_a_list_string));
  30463. if (!is_pair(cadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaadr_symbol, lst, cadr_a_list_string));
  30464. if (!is_pair(caadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaadr_symbol, lst, caadr_a_list_string));
  30465. return(cdaadr(lst));
  30466. }
  30467. static s7_pointer g_cdaadr(s7_scheme *sc, s7_pointer args)
  30468. {
  30469. #define H_cdaadr "(cdaadr lst) returns (cdr (car (car (cdr lst)))): (cdaadr '(1 ((2 3 4)))) -> '(3 4)"
  30470. #define Q_cdaadr pl_p
  30471. return(g_cdaadr_1(sc, car(args)));
  30472. }
  30473. PF_TO_PF(cdaadr, g_cdaadr_1)
  30474. /* -------- cdadar -------- */
  30475. static s7_pointer g_cdadar_1(s7_scheme *sc, s7_pointer lst)
  30476. {
  30477. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdadar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30478. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdadar_symbol, lst, car_a_list_string));
  30479. if (!is_pair(cdar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdadar_symbol, lst, cdar_a_list_string));
  30480. if (!is_pair(cadar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdadar_symbol, lst, cadar_a_list_string));
  30481. return(cdadar(lst));
  30482. }
  30483. static s7_pointer g_cdadar(s7_scheme *sc, s7_pointer args)
  30484. {
  30485. #define H_cdadar "(cdadar lst) returns (cdr (car (cdr (car lst)))): (cdadar '((1 (2 3 4)))) -> '(3 4)"
  30486. #define Q_cdadar pl_p
  30487. return(g_cdadar_1(sc, car(args)));
  30488. }
  30489. PF_TO_PF(cdadar, g_cdadar_1)
  30490. /* -------- cddaar -------- */
  30491. static s7_pointer g_cddaar_1(s7_scheme *sc, s7_pointer lst)
  30492. {
  30493. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cddaar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30494. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddaar_symbol, lst, car_a_list_string));
  30495. if (!is_pair(caar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddaar_symbol, lst, caar_a_list_string));
  30496. if (!is_pair(cdaar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddaar_symbol, lst, cdaar_a_list_string));
  30497. return(cddaar(lst));
  30498. }
  30499. static s7_pointer g_cddaar(s7_scheme *sc, s7_pointer args)
  30500. {
  30501. #define H_cddaar "(cddaar lst) returns (cdr (cdr (car (car lst)))): (cddaar '(((1 2 3 4)))) -> '(3 4)"
  30502. #define Q_cddaar pl_p
  30503. return(g_cddaar_1(sc, car(args)));
  30504. }
  30505. PF_TO_PF(cddaar, g_cddaar_1)
  30506. /* -------- cdaddr -------- */
  30507. static s7_pointer g_cdaddr_1(s7_scheme *sc, s7_pointer lst)
  30508. {
  30509. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdaddr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30510. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaddr_symbol, lst, cdr_a_list_string));
  30511. if (!is_pair(cddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaddr_symbol, lst, cddr_a_list_string));
  30512. if (!is_pair(caddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdaddr_symbol, lst, caddr_a_list_string));
  30513. return(cdaddr(lst));
  30514. }
  30515. static s7_pointer g_cdaddr(s7_scheme *sc, s7_pointer args)
  30516. {
  30517. #define H_cdaddr "(cdaddr lst) returns (cdr (car (cdr (cdr lst)))): (cdaddr '(1 2 (3 4 5))) -> '(4 5)"
  30518. #define Q_cdaddr pl_p
  30519. return(g_cdaddr_1(sc, car(args)));
  30520. }
  30521. PF_TO_PF(cdaddr, g_cdaddr_1)
  30522. /* -------- cddddr -------- */
  30523. static s7_pointer g_cddddr_1(s7_scheme *sc, s7_pointer lst)
  30524. {
  30525. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cddddr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30526. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddddr_symbol, lst, cdr_a_list_string));
  30527. if (!is_pair(cddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddddr_symbol, lst, cddr_a_list_string));
  30528. if (!is_pair(cdddr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddddr_symbol, lst, cdddr_a_list_string));
  30529. return(cddddr(lst));
  30530. }
  30531. static s7_pointer g_cddddr(s7_scheme *sc, s7_pointer args)
  30532. {
  30533. #define H_cddddr "(cddddr lst) returns (cdr (cdr (cdr (cdr lst)))): (cddddr '(1 2 3 4 5)) -> '(5)"
  30534. #define Q_cddddr pl_p
  30535. return(g_cddddr_1(sc, car(args)));
  30536. }
  30537. PF_TO_PF(cddddr, g_cddddr_1)
  30538. /* -------- cddadr -------- */
  30539. static s7_pointer g_cddadr_1(s7_scheme *sc, s7_pointer lst)
  30540. {
  30541. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cddadr_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30542. if (!is_pair(cdr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddadr_symbol, lst, cdr_a_list_string));
  30543. if (!is_pair(cadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddadr_symbol, lst, cadr_a_list_string));
  30544. if (!is_pair(cdadr(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cddadr_symbol, lst, cdadr_a_list_string));
  30545. return(cddadr(lst));
  30546. }
  30547. static s7_pointer g_cddadr(s7_scheme *sc, s7_pointer args)
  30548. {
  30549. #define H_cddadr "(cddadr lst) returns (cdr (cdr (car (cdr lst)))): (cddadr '(1 (2 3 4 5))) -> '(4 5)"
  30550. #define Q_cddadr pl_p
  30551. return(g_cddadr_1(sc, car(args)));
  30552. }
  30553. PF_TO_PF(cddadr, g_cddadr_1)
  30554. /* -------- cdddar -------- */
  30555. static s7_pointer g_cdddar_1(s7_scheme *sc, s7_pointer lst)
  30556. {
  30557. if (!is_pair(lst)) method_or_bust(sc, lst, sc->cdddar_symbol, set_plist_1(sc, lst), T_PAIR, 0);
  30558. if (!is_pair(car(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdddar_symbol, lst, car_a_list_string));
  30559. if (!is_pair(cdar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdddar_symbol, lst, cdar_a_list_string));
  30560. if (!is_pair(cddar(lst))) return(simple_wrong_type_argument_with_type(sc, sc->cdddar_symbol, lst, cddar_a_list_string));
  30561. return(cdddar(lst));
  30562. }
  30563. static s7_pointer g_cdddar(s7_scheme *sc, s7_pointer args)
  30564. {
  30565. #define H_cdddar "(cdddar lst) returns (cdr (cdr (cdr (car lst)))): (cdddar '((1 2 3 4 5))) -> '(4 5)"
  30566. #define Q_cdddar pl_p
  30567. return(g_cdddar_1(sc, car(args)));
  30568. }
  30569. PF_TO_PF(cdddar, g_cdddar_1)
  30570. s7_pointer s7_assq(s7_scheme *sc, s7_pointer obj, s7_pointer x)
  30571. {
  30572. s7_pointer y;
  30573. y = x;
  30574. while (true)
  30575. {
  30576. /* we can blithely take the car of anything, since we're not treating it as an object,
  30577. * then if we get a bogus match, the following check that caar made sense ought to catch it.
  30578. *
  30579. * if car(#<unspecified>) = #<unspecified> (initialization time), then cdr(nil)->unspec
  30580. * and subsequent caar(unspc)->unspec so we could forgo half the is_pair checks below.
  30581. * This breaks if "x" is a dotted list -- the last cdr is not nil, so we lose.
  30582. */
  30583. if ((obj == unchecked_car(car(x))) && (is_pair(car(x)))) return(car(x));
  30584. x = cdr(x);
  30585. if (!is_pair(x)) return(sc->F);
  30586. if ((obj == unchecked_car(car(x))) && (is_pair(car(x)))) return(car(x));
  30587. x = cdr(x);
  30588. if (!is_pair(x)) return(sc->F);
  30589. if ((obj == unchecked_car(car(x))) && (is_pair(car(x)))) return(car(x));
  30590. x = cdr(x);
  30591. if (!is_pair(x)) return(sc->F);
  30592. if ((obj == unchecked_car(car(x))) && (is_pair(car(x)))) return(car(x));
  30593. x = cdr(x);
  30594. if (!is_pair(x)) return(sc->F);
  30595. if ((obj == unchecked_car(car(x))) && (is_pair(car(x)))) return(car(x));
  30596. x = cdr(x);
  30597. if (!is_pair(x)) return(sc->F);
  30598. if ((obj == unchecked_car(car(x))) && (is_pair(car(x)))) return(car(x));
  30599. x = cdr(x);
  30600. if (!is_pair(x)) return(sc->F);
  30601. y = cdr(y);
  30602. if (x == y) return(sc->F);
  30603. }
  30604. return(sc->F); /* not reached */
  30605. }
  30606. static s7_pointer c_assq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  30607. {
  30608. if (!is_pair(y))
  30609. {
  30610. if (is_null(y)) return(sc->F);
  30611. method_or_bust_with_type(sc, y, sc->assq_symbol, list_2(sc, x, y), an_association_list_string, 2);
  30612. }
  30613. /* we don't check for (pair? (car x)) here (or in assv) so we get some inconsistency with assoc:
  30614. * (assq #f '(#f 2 . 3)) -> #f
  30615. * (assoc #f '(#f 2 . 3)) -> 'error
  30616. */
  30617. return(s7_assq(sc, x, y));
  30618. }
  30619. static s7_pointer g_assq(s7_scheme *sc, s7_pointer args)
  30620. {
  30621. #define H_assq "(assq obj alist) returns the key-value pair associated (via eq?) with the key obj in the association list alist"
  30622. #define Q_assq s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_boolean_symbol), sc->T, sc->is_list_symbol)
  30623. return(c_assq(sc, car(args), cadr(args)));
  30624. }
  30625. PF2_TO_PF(assq, c_assq)
  30626. static s7_pointer c_assv(s7_scheme *sc, s7_pointer x, s7_pointer y)
  30627. {
  30628. s7_pointer z;
  30629. if (!is_pair(y))
  30630. {
  30631. if (is_null(y)) return(sc->F);
  30632. method_or_bust_with_type(sc, y, sc->assv_symbol, list_2(sc, x, y), an_association_list_string, 2);
  30633. }
  30634. if (is_simple(x))
  30635. return(s7_assq(sc, x, y));
  30636. z = y;
  30637. while (true)
  30638. {
  30639. /* here we can't play the assq == game because s7_is_eqv thinks it's getting a legit s7 object */
  30640. if ((is_pair(car(y))) && (s7_is_eqv(x, caar(y)))) return(car(y));
  30641. y = cdr(y);
  30642. if (!is_pair(y)) return(sc->F);
  30643. if ((is_pair(car(y))) && (s7_is_eqv(x, caar(y)))) return(car(y));
  30644. y = cdr(y);
  30645. if (!is_pair(y)) return(sc->F);
  30646. z = cdr(z);
  30647. if (z == y) return(sc->F);
  30648. }
  30649. return(sc->F); /* not reached */
  30650. }
  30651. static s7_pointer g_assv(s7_scheme *sc, s7_pointer args) /* g_assv is called by g_assoc below */
  30652. {
  30653. #define H_assv "(assv obj alist) returns the key-value pair associated (via eqv?) with the key obj in the association list alist"
  30654. #define Q_assv Q_assq
  30655. return(c_assv(sc, car(args), cadr(args)));
  30656. }
  30657. PF2_TO_PF(assv, c_assv)
  30658. static s7_pointer all_x_c_ss(s7_scheme *sc, s7_pointer arg);
  30659. static s7_pointer all_x_c_uu(s7_scheme *sc, s7_pointer arg);
  30660. static s7_pointer g_is_eq(s7_scheme *sc, s7_pointer args);
  30661. static s7_pointer g_is_eqv(s7_scheme *sc, s7_pointer args);
  30662. static s7_pointer g_assoc(s7_scheme *sc, s7_pointer args)
  30663. {
  30664. #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.\
  30665. If 'func' is a function of 2 arguments, it is used for the comparison instead of 'equal?"
  30666. #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)
  30667. s7_pointer x, y, obj, eq_func = NULL;
  30668. x = cadr(args);
  30669. if (!is_null(x))
  30670. {
  30671. if (!is_pair(x))
  30672. method_or_bust_with_type(sc, x, sc->assoc_symbol, args, an_association_list_string, 2);
  30673. if ((is_pair(x)) && (!is_pair(car(x))))
  30674. 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 */
  30675. }
  30676. if (is_not_null(cddr(args)))
  30677. {
  30678. /* check third arg before second (trailing arg error check) */
  30679. eq_func = caddr(args);
  30680. if (type(eq_func) < T_GOTO)
  30681. method_or_bust_with_type(sc, eq_func, sc->assoc_symbol, args, a_procedure_string, 0);
  30682. if (!s7_is_aritable(sc, eq_func, 2))
  30683. return(wrong_type_argument_with_type(sc, sc->assoc_symbol, 3, eq_func, an_eq_func_string));
  30684. }
  30685. if (is_null(x)) return(sc->F);
  30686. if (eq_func)
  30687. {
  30688. /* now maybe there's a simple case */
  30689. if (s7_list_length(sc, x) > 0)
  30690. {
  30691. if ((is_safe_procedure(eq_func)) &&
  30692. (is_c_function(eq_func)))
  30693. {
  30694. s7_function func;
  30695. func = c_function_call(eq_func);
  30696. if (func == g_is_eq) return(s7_assq(sc, car(args), x));
  30697. if (func == g_is_eqv) return(g_assv(sc, args));
  30698. set_car(sc->t2_1, car(args));
  30699. for (; is_pair(x); x = cdr(x))
  30700. {
  30701. if (is_pair(car(x)))
  30702. {
  30703. set_car(sc->t2_2, caar(x));
  30704. if (is_true(sc, func(sc, sc->t2_1)))
  30705. return(car(x));
  30706. /* I wonder if the assoc equality function should get the cons, not just caar?
  30707. */
  30708. }
  30709. else return(wrong_type_argument_with_type(sc, sc->assoc_symbol, 2, cadr(args), an_association_list_string));
  30710. }
  30711. return(sc->F);
  30712. }
  30713. /* lg auto? */
  30714. if ((is_closure(eq_func)) &&
  30715. (is_pair(closure_args(eq_func))) &&
  30716. (is_pair(cdr(closure_args(eq_func))))) /* not dotted arg list */
  30717. {
  30718. s7_pointer body;
  30719. body = closure_body(eq_func);
  30720. if ((is_optimized(car(body))) &&
  30721. (is_null(cdr(body))) &&
  30722. (is_all_x_safe(sc, car(body))))
  30723. {
  30724. s7_function func;
  30725. s7_pointer b;
  30726. new_frame_with_two_slots(sc, sc->envir, sc->envir, car(closure_args(eq_func)), car(args), cadr(closure_args(eq_func)), sc->F);
  30727. func = all_x_eval(sc, car(body), sc->envir, let_symbol_is_safe); /* safe since local */
  30728. b = next_slot(let_slots(sc->envir));
  30729. for (; is_pair(x); x = cdr(x))
  30730. {
  30731. slot_set_value(b, caar(x));
  30732. if (is_true(sc, func(sc, car(body))))
  30733. return(car(x));
  30734. }
  30735. return(sc->F);
  30736. }
  30737. }
  30738. }
  30739. /* sc->value = sc->F; */
  30740. y = cons(sc, args, sc->nil);
  30741. set_opt_fast(y, x);
  30742. set_opt_slow(y, x);
  30743. push_stack(sc, OP_ASSOC_IF, y, eq_func);
  30744. push_stack(sc, OP_APPLY, list_2(sc, car(args), caar(x)), eq_func);
  30745. return(sc->unspecified);
  30746. }
  30747. x = cadr(args);
  30748. obj = car(args);
  30749. if (is_simple(obj))
  30750. return(s7_assq(sc, obj, x));
  30751. y = x;
  30752. if (is_string(obj))
  30753. {
  30754. s7_pointer val;
  30755. while (true)
  30756. {
  30757. if (is_pair(car(x)))
  30758. {
  30759. val = caar(x);
  30760. if ((val == obj) ||
  30761. ((is_string(val)) &&
  30762. (scheme_strings_are_equal(obj, val))))
  30763. return(car(x));
  30764. }
  30765. x = cdr(x);
  30766. if (!is_pair(x)) return(sc->F);
  30767. if (is_pair(car(x)))
  30768. {
  30769. val = caar(x);
  30770. if ((val == obj) ||
  30771. ((is_string(val)) &&
  30772. (scheme_strings_are_equal(obj, val))))
  30773. return(car(x));
  30774. }
  30775. x = cdr(x);
  30776. if (!is_pair(x)) return(sc->F);
  30777. y = cdr(y);
  30778. if (x == y) return(sc->F);
  30779. }
  30780. return(sc->F);
  30781. }
  30782. while (true)
  30783. {
  30784. if ((is_pair(car(x))) && (s7_is_equal(sc, obj, caar(x)))) return(car(x));
  30785. x = cdr(x);
  30786. if (!is_pair(x)) return(sc->F);
  30787. if ((is_pair(car(x))) && (s7_is_equal(sc, obj, caar(x)))) return(car(x));
  30788. x = cdr(x);
  30789. if (!is_pair(x)) return(sc->F);
  30790. y = cdr(y);
  30791. if (x == y) return(sc->F);
  30792. }
  30793. return(sc->F); /* not reached */
  30794. }
  30795. static s7_pointer c_assoc(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_assoc(sc, set_plist_2(sc, x, y)));}
  30796. PF2_TO_PF(assoc, c_assoc)
  30797. /* ---------------- member, memv, memq ---------------- */
  30798. s7_pointer s7_memq(s7_scheme *sc, s7_pointer obj, s7_pointer x)
  30799. {
  30800. s7_pointer y;
  30801. y = x;
  30802. while (true)
  30803. {
  30804. if (obj == car(x)) return(x);
  30805. x = cdr(x);
  30806. if (!is_pair(x)) return(sc->F);
  30807. if (obj == car(x)) return(x);
  30808. x = cdr(x);
  30809. if (!is_pair(x)) return(sc->F);
  30810. if (obj == car(x)) return(x);
  30811. x = cdr(x);
  30812. if (!is_pair(x)) return(sc->F);
  30813. if (obj == car(x)) return(x);
  30814. x = cdr(x);
  30815. if (!is_pair(x)) return(sc->F);
  30816. y = cdr(y);
  30817. if (x == y) return(sc->F);
  30818. }
  30819. return(sc->F);
  30820. }
  30821. static s7_pointer c_memq(s7_scheme *sc, s7_pointer x, s7_pointer y)
  30822. {
  30823. if (!is_pair(y))
  30824. {
  30825. if (is_null(y)) return(sc->F);
  30826. method_or_bust_with_type(sc, y, sc->memq_symbol, list_2(sc, x, y), a_list_string, 2);
  30827. }
  30828. return(s7_memq(sc, x, y));
  30829. }
  30830. static s7_pointer g_memq(s7_scheme *sc, s7_pointer args)
  30831. {
  30832. #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?"
  30833. #define Q_memq pl_tl
  30834. return(c_memq(sc, car(args), cadr(args)));
  30835. }
  30836. PF2_TO_PF(memq, c_memq)
  30837. /* I think (memq 'c '(a b . c)) should return #f because otherwise
  30838. * (memq () ...) would return the () at the end.
  30839. */
  30840. /* if memq's list is a quoted list, it won't be changing, so we can tell ahead of time that it is
  30841. * a proper list, and what its length is.
  30842. */
  30843. static s7_pointer memq_3, memq_4, memq_any;
  30844. static s7_pointer g_memq_3(s7_scheme *sc, s7_pointer args)
  30845. {
  30846. s7_pointer x, obj;
  30847. x = cadr(args);
  30848. obj = car(args);
  30849. while (true)
  30850. {
  30851. if (obj == car(x)) return(x);
  30852. x = cdr(x);
  30853. if (obj == car(x)) return(x);
  30854. x = cdr(x);
  30855. if (obj == car(x)) return(x);
  30856. x = cdr(x);
  30857. if (!is_pair(x)) return(sc->F);
  30858. }
  30859. return(sc->F);
  30860. }
  30861. static s7_pointer g_memq_4(s7_scheme *sc, s7_pointer args)
  30862. {
  30863. s7_pointer x, obj;
  30864. x = cadr(args);
  30865. obj = car(args);
  30866. while (true)
  30867. {
  30868. if (obj == car(x)) return(x);
  30869. x = cdr(x);
  30870. if (obj == car(x)) return(x);
  30871. x = cdr(x);
  30872. if (obj == car(x)) return(x);
  30873. x = cdr(x);
  30874. if (obj == car(x)) return(x);
  30875. x = cdr(x);
  30876. if (!is_pair(x)) return(sc->F);
  30877. }
  30878. return(sc->F);
  30879. }
  30880. static s7_pointer g_memq_any(s7_scheme *sc, s7_pointer args)
  30881. {
  30882. /* no circular list check needed in this case */
  30883. s7_pointer x, obj;
  30884. x = cadr(args);
  30885. obj = car(args);
  30886. while (true)
  30887. {
  30888. if (obj == car(x)) return(x);
  30889. x = cdr(x);
  30890. if (!is_pair(x)) return(sc->F); /* every other pair check could be omitted */
  30891. if (obj == car(x)) return(x);
  30892. x = cdr(x);
  30893. if (!is_pair(x)) return(sc->F);
  30894. if (obj == car(x)) return(x);
  30895. x = cdr(x);
  30896. if (!is_pair(x)) return(sc->F);
  30897. if (obj == car(x)) return(x);
  30898. x = cdr(x);
  30899. if (!is_pair(x)) return(sc->F);
  30900. }
  30901. return(sc->F);
  30902. }
  30903. static s7_pointer memq_car;
  30904. static s7_pointer g_memq_car(s7_scheme *sc, s7_pointer args)
  30905. {
  30906. s7_pointer x, obj;
  30907. obj = find_symbol_checked(sc, cadar(args));
  30908. if (!is_pair(obj))
  30909. {
  30910. s7_pointer func;
  30911. if ((has_methods(obj)) &&
  30912. ((func = find_method(sc, find_let(sc, obj), sc->car_symbol)) != sc->undefined))
  30913. obj = s7_apply_function(sc, func, list_1(sc, obj));
  30914. if (!is_pair(obj))
  30915. return(simple_wrong_type_argument(sc, sc->car_symbol, obj, T_PAIR));
  30916. }
  30917. obj = car(obj);
  30918. x = cadr(cadr(args));
  30919. while (true)
  30920. {
  30921. if (obj == car(x)) return(x);
  30922. x = cdr(x);
  30923. if (!is_pair(x)) return(sc->F);
  30924. if (obj == car(x)) return(x);
  30925. x = cdr(x);
  30926. if (!is_pair(x)) return(sc->F);
  30927. }
  30928. return(sc->F);
  30929. }
  30930. static s7_pointer memq_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  30931. {
  30932. if ((is_pair(caddr(expr))) &&
  30933. (car(caddr(expr)) == sc->quote_symbol) &&
  30934. (is_pair(cadr(caddr(expr)))))
  30935. {
  30936. int len;
  30937. if ((is_h_safe_c_s(cadr(expr))) &&
  30938. (c_callee(cadr(expr)) == g_car))
  30939. {
  30940. set_optimize_op(expr, HOP_SAFE_C_C);
  30941. return(memq_car);
  30942. }
  30943. len = s7_list_length(sc, cadr(caddr(expr)));
  30944. if (len > 0)
  30945. {
  30946. if ((len % 4) == 0)
  30947. return(memq_4);
  30948. if ((len % 3) == 0)
  30949. return(memq_3);
  30950. return(memq_any);
  30951. }
  30952. }
  30953. return(f);
  30954. }
  30955. static s7_pointer memv_number(s7_scheme *sc, s7_pointer obj, s7_pointer x)
  30956. {
  30957. s7_pointer y;
  30958. y = x;
  30959. while (true)
  30960. {
  30961. if ((s7_is_number(car(x))) && (numbers_are_eqv(obj, car(x)))) return(x);
  30962. x = cdr(x);
  30963. if (!is_pair(x)) return(sc->F);
  30964. if ((s7_is_number(car(x))) && (numbers_are_eqv(obj, car(x)))) return(x);
  30965. x = cdr(x);
  30966. if (!is_pair(x)) return(sc->F);
  30967. if ((s7_is_number(car(x))) && (numbers_are_eqv(obj, car(x)))) return(x);
  30968. x = cdr(x);
  30969. if (!is_pair(x)) return(sc->F);
  30970. if ((s7_is_number(car(x))) && (numbers_are_eqv(obj, car(x)))) return(x);
  30971. x = cdr(x);
  30972. if (!is_pair(x)) return(sc->F);
  30973. y = cdr(y);
  30974. if (x == y) return(sc->F);
  30975. }
  30976. return(sc->F);
  30977. }
  30978. static s7_pointer c_memv(s7_scheme *sc, s7_pointer x, s7_pointer y)
  30979. {
  30980. s7_pointer z;
  30981. if (!is_pair(y))
  30982. {
  30983. if (is_null(y)) return(sc->F);
  30984. method_or_bust_with_type(sc, y, sc->memv_symbol, list_2(sc, x, y), a_list_string, 2);
  30985. }
  30986. if (is_simple(x)) return(s7_memq(sc, x, y));
  30987. if (s7_is_number(x)) return(memv_number(sc, x, y));
  30988. z = y;
  30989. while (true)
  30990. {
  30991. if (s7_is_eqv(x, car(y))) return(y);
  30992. y = cdr(y);
  30993. if (!is_pair(y)) return(sc->F);
  30994. if (s7_is_eqv(x, car(y))) return(y);
  30995. y = cdr(y);
  30996. if (!is_pair(y)) return(sc->F);
  30997. z = cdr(z);
  30998. if (z == y) return(sc->F);
  30999. }
  31000. return(sc->F); /* not reached */
  31001. }
  31002. static s7_pointer g_memv(s7_scheme *sc, s7_pointer args)
  31003. {
  31004. #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?"
  31005. #define Q_memv pl_tl
  31006. return(c_memv(sc, car(args), cadr(args)));
  31007. }
  31008. PF2_TO_PF(memv, c_memv)
  31009. static s7_pointer member(s7_scheme *sc, s7_pointer obj, s7_pointer x)
  31010. {
  31011. s7_pointer y;
  31012. y = x;
  31013. if (is_string(obj))
  31014. {
  31015. while (true)
  31016. {
  31017. if ((obj == car(x)) ||
  31018. ((is_string(car(x))) &&
  31019. (scheme_strings_are_equal(obj, car(x)))))
  31020. return(x);
  31021. x = cdr(x);
  31022. if (!is_pair(x)) return(sc->F);
  31023. if ((obj == car(x)) ||
  31024. ((is_string(car(x))) &&
  31025. (scheme_strings_are_equal(obj, car(x)))))
  31026. return(x);
  31027. x = cdr(x);
  31028. if (!is_pair(x)) return(sc->F);
  31029. y = cdr(y);
  31030. if (x == y) return(sc->F);
  31031. }
  31032. return(sc->F);
  31033. }
  31034. while (true)
  31035. {
  31036. if (s7_is_equal(sc, obj, car(x))) return(x);
  31037. x = cdr(x);
  31038. if (!is_pair(x)) return(sc->F);
  31039. if (s7_is_equal(sc, obj, car(x))) return(x);
  31040. x = cdr(x);
  31041. if (!is_pair(x)) return(sc->F);
  31042. if (s7_is_equal(sc, obj, car(x))) return(x);
  31043. x = cdr(x);
  31044. if (!is_pair(x)) return(sc->F);
  31045. if (s7_is_equal(sc, obj, car(x))) return(x);
  31046. x = cdr(x);
  31047. if (!is_pair(x)) return(sc->F);
  31048. y = cdr(y);
  31049. if (x == y) return(sc->F);
  31050. }
  31051. return(sc->F); /* not reached */
  31052. }
  31053. static s7_pointer g_member(s7_scheme *sc, s7_pointer args)
  31054. {
  31055. #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. \
  31056. member uses equal? If 'func' is a function of 2 arguments, it is used for the comparison instead of 'equal?"
  31057. #define Q_member 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)
  31058. /* this could be extended to accept sequences:
  31059. * (member #\a "123123abnfc" char=?) -> "abnfc"
  31060. * (member "abc" "123abc321" string=?) -> "abc321" but there's the string length complication
  31061. * (member 1 #(0 1 2) =) -> #(1 2) etc but what would it do for a hash-table?
  31062. * the third arg can be weird: (member #f (list #t) cons) -> (#t) -- cons returns '(#f . #t) which is true, so we get '(#t)
  31063. * should this be an error: (member '(1 2 3) () '(1 . 2)) -- the third arg is bogus, but the second is nil
  31064. *
  31065. * here as in assoc, sort, and make-hash-table we accept macros, but I can't think of a good reason to do so.
  31066. */
  31067. s7_pointer x, y, obj, eq_func = NULL;
  31068. x = cadr(args);
  31069. if ((!is_pair(x)) && (!is_null(x)))
  31070. method_or_bust_with_type(sc, x, sc->member_symbol, args, a_list_string, 2);
  31071. if (is_not_null(cddr(args)))
  31072. {
  31073. /* check third arg before second (trailing arg error check) */
  31074. eq_func = caddr(args);
  31075. if (type(eq_func) < T_GOTO)
  31076. method_or_bust_with_type(sc, eq_func, sc->member_symbol, args, a_procedure_string, 3);
  31077. if (!s7_is_aritable(sc, eq_func, 2))
  31078. return(wrong_type_argument_with_type(sc, sc->member_symbol, 3, eq_func, an_eq_func_string));
  31079. }
  31080. if (is_null(x)) return(sc->F);
  31081. if (eq_func)
  31082. {
  31083. /* now maybe there's a simple case */
  31084. if (s7_list_length(sc, x) > 0)
  31085. {
  31086. if ((is_safe_procedure(eq_func)) &&
  31087. (is_c_function(eq_func)))
  31088. {
  31089. s7_function func;
  31090. func = c_function_call(eq_func);
  31091. if (func == g_is_eq) return(s7_memq(sc, car(args), x));
  31092. if (func == g_is_eqv) return(g_memv(sc, args));
  31093. set_car(sc->t2_1, car(args));
  31094. for (; is_pair(x); x = cdr(x))
  31095. {
  31096. set_car(sc->t2_2, car(x));
  31097. if (is_true(sc, func(sc, sc->t2_1)))
  31098. return(x);
  31099. }
  31100. return(sc->F);
  31101. }
  31102. if ((is_closure(eq_func)) &&
  31103. (is_pair(closure_args(eq_func))) &&
  31104. (is_pair(cdr(closure_args(eq_func))))) /* not dotted arg list */
  31105. {
  31106. s7_pointer body;
  31107. body = closure_body(eq_func);
  31108. if ((is_optimized(car(body))) &&
  31109. (is_null(cdr(body))) &&
  31110. (is_all_x_safe(sc, car(body))))
  31111. {
  31112. s7_function func;
  31113. func = all_x_eval(sc, car(body), closure_args(eq_func), pair_symbol_is_safe);
  31114. /* tmap, lg falls through*/
  31115. if (((func == all_x_c_ss) || (func == all_x_c_uu)) &&
  31116. (cadar(body) == car(closure_args(eq_func))) &&
  31117. (caddar(body) == cadr(closure_args(eq_func))))
  31118. {
  31119. set_car(sc->t2_1, car(args));
  31120. func = c_callee(car(body));
  31121. for (; is_pair(x); x = cdr(x))
  31122. {
  31123. set_car(sc->t2_2, car(x));
  31124. if (is_true(sc, func(sc, sc->t2_1)))
  31125. return(x);
  31126. }
  31127. }
  31128. else
  31129. {
  31130. s7_pointer b;
  31131. new_frame_with_two_slots(sc, sc->envir, sc->envir, car(closure_args(eq_func)), car(args), cadr(closure_args(eq_func)), sc->F);
  31132. b = next_slot(let_slots(sc->envir));
  31133. for (; is_pair(x); x = cdr(x))
  31134. {
  31135. slot_set_value(b, car(x));
  31136. if (is_true(sc, func(sc, car(body))))
  31137. return(x);
  31138. }
  31139. }
  31140. return(sc->F);
  31141. }
  31142. }
  31143. }
  31144. y = cons(sc, args, sc->nil); /* this could probably be handled with a counter cell (cdr here is unused) */
  31145. set_opt_fast(y, x);
  31146. set_opt_slow(y, x);
  31147. push_stack(sc, OP_MEMBER_IF, y, eq_func);
  31148. set_car(sc->t2_1, car(args));
  31149. set_car(sc->t2_2, car(x));
  31150. push_stack(sc, OP_APPLY, sc->t2_1, eq_func);
  31151. return(sc->unspecified);
  31152. }
  31153. obj = car(args);
  31154. if (is_simple(obj))
  31155. return(s7_memq(sc, obj, x));
  31156. /* the only things that aren't simply == here are c_object, string, number, vector, hash-table, pair, and c_pointer
  31157. * but all the other cases are unlikely.
  31158. */
  31159. if (s7_is_number(obj))
  31160. return(memv_number(sc, obj, x));
  31161. return(member(sc, obj, x));
  31162. }
  31163. static s7_pointer c_member(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_member(sc, set_plist_2(sc, x, y)));}
  31164. PF2_TO_PF(member, c_member)
  31165. static s7_pointer member_sq;
  31166. static s7_pointer g_member_sq(s7_scheme *sc, s7_pointer args)
  31167. {
  31168. s7_pointer obj, lst;
  31169. lst = cadr(cadr(args));
  31170. obj = find_symbol_checked(sc, car(args));
  31171. if (is_simple(obj))
  31172. return(s7_memq(sc, obj, lst));
  31173. if (s7_is_number(obj))
  31174. return(memv_number(sc, obj, lst));
  31175. return(member(sc, obj, lst));
  31176. }
  31177. static s7_pointer member_num_s;
  31178. static s7_pointer g_member_num_s(s7_scheme *sc, s7_pointer args)
  31179. {
  31180. s7_pointer lst;
  31181. lst = find_symbol_checked(sc, cadr(args));
  31182. if (!is_pair(lst))
  31183. {
  31184. if (is_null(lst)) return(sc->F);
  31185. method_or_bust_with_type(sc, lst, sc->member_symbol, list_2(sc, car(args), lst), a_list_string, 2);
  31186. }
  31187. return(memv_number(sc, car(args), lst));
  31188. }
  31189. static s7_pointer member_ss;
  31190. static s7_pointer g_member_ss(s7_scheme *sc, s7_pointer args)
  31191. {
  31192. s7_pointer obj, x;
  31193. obj = find_symbol_checked(sc, car(args));
  31194. x = find_symbol_checked(sc, cadr(args));
  31195. if (!is_pair(x))
  31196. {
  31197. if (is_null(x)) return(sc->F);
  31198. method_or_bust_with_type(sc, x, sc->member_symbol, list_2(sc, obj, x), a_list_string, 2);
  31199. }
  31200. if (is_simple(obj))
  31201. return(s7_memq(sc, obj, x));
  31202. if (s7_is_number(obj))
  31203. return(memv_number(sc, obj, x));
  31204. return(member(sc, obj, x));
  31205. }
  31206. static s7_pointer member_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  31207. {
  31208. if (args == 2)
  31209. {
  31210. if (is_symbol(caddr(expr)))
  31211. {
  31212. if (s7_is_number(cadr(expr)))
  31213. {
  31214. set_optimize_op(expr, HOP_SAFE_C_C);
  31215. return(member_num_s); /* (member 4 lst) */
  31216. }
  31217. if (is_symbol(cadr(expr)))
  31218. {
  31219. set_optimize_op(expr, HOP_SAFE_C_C);
  31220. return(member_ss); /* (member obj lst) */
  31221. }
  31222. }
  31223. else
  31224. {
  31225. if ((is_symbol(cadr(expr))) &&
  31226. (is_pair(caddr(expr))) &&
  31227. (car(caddr(expr)) == sc->quote_symbol) &&
  31228. (is_pair(cadr(caddr(expr)))))
  31229. {
  31230. set_optimize_op(expr, HOP_SAFE_C_C);
  31231. return(member_sq); /* (member q '(quote lambda case)) */
  31232. }
  31233. }
  31234. }
  31235. if ((args == 3) &&
  31236. (is_symbol(cadddr(expr))) &&
  31237. (cadddr(expr) == sc->is_eq_symbol))
  31238. return(memq_chooser(sc, f, 2, expr));
  31239. return(f);
  31240. }
  31241. static bool is_memq(s7_pointer sym, s7_pointer lst)
  31242. {
  31243. s7_pointer x;
  31244. for (x = lst; is_pair(x); x = cdr(x))
  31245. if (sym == car(x))
  31246. return(true);
  31247. return(false);
  31248. }
  31249. static s7_pointer c_is_provided(s7_scheme *sc, s7_pointer sym)
  31250. {
  31251. s7_pointer topf, x;
  31252. if (!is_symbol(sym))
  31253. method_or_bust(sc, sym, sc->is_provided_symbol, list_1(sc, sym), T_SYMBOL, 0);
  31254. /* here the *features* list is spread out (or can be anyway) along the curlet chain,
  31255. * so we need to travel back all the way to the top level checking each *features* list in turn.
  31256. * Since *features* grows via cons (newest first), we can stop the scan if we hit the shared
  31257. * top-level at least.
  31258. */
  31259. topf = slot_value(global_slot(sc->features_symbol));
  31260. if (is_memq(sym, topf))
  31261. return(sc->T);
  31262. if (is_global(sc->features_symbol))
  31263. return(sc->F);
  31264. for (x = sc->envir; symbol_id(sc->features_symbol) < let_id(x); x = outlet(x));
  31265. for (; is_let(x); x = outlet(x))
  31266. {
  31267. s7_pointer y;
  31268. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  31269. if (slot_symbol(y) == sc->features_symbol)
  31270. {
  31271. if ((slot_value(y) != topf) &&
  31272. (is_memq(sym, slot_value(y))))
  31273. return(sc->T);
  31274. }
  31275. }
  31276. return(sc->F);
  31277. }
  31278. static s7_pointer g_is_provided(s7_scheme *sc, s7_pointer args)
  31279. {
  31280. #define H_is_provided "(provided? symbol) returns #t if symbol is a member of the *features* list"
  31281. #define Q_is_provided s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_symbol_symbol)
  31282. return(c_is_provided(sc, car(args)));
  31283. }
  31284. bool s7_is_provided(s7_scheme *sc, const char *feature)
  31285. {
  31286. return(is_memq(s7_make_symbol(sc, feature), s7_symbol_value(sc, sc->features_symbol))); /* this goes from local outward */
  31287. }
  31288. PF_TO_PF(is_provided, c_is_provided)
  31289. static s7_pointer c_provide(s7_scheme *sc, s7_pointer sym)
  31290. {
  31291. /* this has to be relative to the curlet: (load file env)
  31292. * the things loaded are only present in env, and go away with it, so should not be in the global *features* list
  31293. */
  31294. s7_pointer p, lst;
  31295. if (!is_symbol(sym))
  31296. method_or_bust(sc, sym, sc->provide_symbol, list_1(sc, sym), T_SYMBOL, 0);
  31297. p = find_local_symbol(sc, sc->features_symbol, sc->envir); /* if sc->envir is nil, this returns the global slot, else local slot */
  31298. lst = slot_value(find_symbol(sc, sc->features_symbol)); /* in either case, we want the current *features* list */
  31299. if (p == sc->undefined)
  31300. make_slot_1(sc, sc->envir, sc->features_symbol, cons(sc, sym, lst));
  31301. else
  31302. {
  31303. if (!is_memq(sym, lst))
  31304. slot_set_value(p, cons(sc, sym, lst));
  31305. }
  31306. if (!is_slot(find_symbol(sc, sym))) /* *features* name might be the same as an existing function */
  31307. s7_define(sc, sc->envir, sym, sym);
  31308. return(sym);
  31309. }
  31310. static s7_pointer g_provide(s7_scheme *sc, s7_pointer args)
  31311. {
  31312. #define H_provide "(provide symbol) adds symbol to the *features* list"
  31313. #define Q_provide s7_make_signature(sc, 2, sc->is_symbol_symbol, sc->is_symbol_symbol)
  31314. return(c_provide(sc, car(args)));
  31315. }
  31316. void s7_provide(s7_scheme *sc, const char *feature)
  31317. {
  31318. c_provide(sc, s7_make_symbol(sc, feature));
  31319. }
  31320. PF_TO_PF(provide, c_provide)
  31321. static s7_pointer g_features_set(s7_scheme *sc, s7_pointer args)
  31322. {
  31323. /* symbol_access for set/let of *features* which can only be changed via provide */
  31324. if (s7_is_list(sc, cadr(args)))
  31325. return(cadr(args));
  31326. return(sc->error_symbol);
  31327. }
  31328. static s7_pointer g_list(s7_scheme *sc, s7_pointer args)
  31329. {
  31330. #define H_list "(list ...) returns its arguments in a list"
  31331. #define Q_list s7_make_circular_signature(sc, 1, 2, sc->is_proper_list_symbol, sc->T)
  31332. return(copy_list(sc, args));
  31333. }
  31334. static s7_pointer c_list_1(s7_scheme *sc, s7_pointer x) {return(cons(sc, x, sc->nil));}
  31335. PF_TO_PF(list, c_list_1)
  31336. static s7_pointer list_0, list_1, list_2;
  31337. static s7_pointer g_list_0(s7_scheme *sc, s7_pointer args)
  31338. {
  31339. return(sc->nil);
  31340. }
  31341. static s7_pointer g_list_1(s7_scheme *sc, s7_pointer args)
  31342. {
  31343. return(cons(sc, car(args), sc->nil));
  31344. }
  31345. static s7_pointer g_list_2(s7_scheme *sc, s7_pointer args)
  31346. {
  31347. return(cons_unchecked(sc, car(args), cons(sc, cadr(args), sc->nil)));
  31348. }
  31349. static s7_pointer list_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  31350. {
  31351. switch (args)
  31352. {
  31353. case 0: return(list_0);
  31354. case 1: return(list_1);
  31355. case 2: return(list_2);
  31356. }
  31357. return(f);
  31358. }
  31359. s7_pointer s7_list(s7_scheme *sc, int num_values, ...)
  31360. {
  31361. int i;
  31362. va_list ap;
  31363. s7_pointer p;
  31364. if (num_values == 0)
  31365. return(sc->nil);
  31366. sc->w = sc->nil;
  31367. va_start(ap, num_values);
  31368. for (i = 0; i < num_values; i++)
  31369. sc->w = cons(sc, va_arg(ap, s7_pointer), sc->w);
  31370. va_end(ap);
  31371. p = sc->w;
  31372. sc->w = sc->nil;
  31373. return(safe_reverse_in_place(sc, p));
  31374. }
  31375. static s7_int sequence_length(s7_scheme *sc, s7_pointer lst);
  31376. static s7_pointer g_list_append(s7_scheme *sc, s7_pointer args)
  31377. {
  31378. s7_pointer y, tp, np = NULL, pp;
  31379. /* we know here that args is a pair and cdr(args) is a pair */
  31380. tp = sc->nil;
  31381. for (y = args; is_pair(y); y = cdr(y)) /* arglist so not dotted */
  31382. {
  31383. s7_pointer p;
  31384. p = car(y);
  31385. check_method(sc, p, sc->append_symbol, (is_null(tp)) ? args : cons(sc, tp, y));
  31386. if (is_null(cdr(y)))
  31387. {
  31388. if (is_null(tp))
  31389. return(p);
  31390. if ((s7_is_list(sc, p)) ||
  31391. (!is_sequence(p)))
  31392. set_cdr(np, p);
  31393. else
  31394. {
  31395. s7_int len;
  31396. len = sequence_length(sc, p);
  31397. if (len > 0)
  31398. set_cdr(np, s7_copy(sc, set_plist_2(sc, p, make_list(sc, len, sc->F))));
  31399. else
  31400. {
  31401. if (len < 0)
  31402. set_cdr(np, p);
  31403. }
  31404. }
  31405. sc->y = sc->nil;
  31406. return(tp);
  31407. }
  31408. if (!is_sequence(p))
  31409. return(wrong_type_argument_with_type(sc, sc->append_symbol, position_of(y, args), p, a_sequence_string));
  31410. if (!is_null(p))
  31411. {
  31412. if (is_pair(p))
  31413. {
  31414. if (!is_proper_list(sc, p))
  31415. {
  31416. sc->y = sc->nil;
  31417. return(wrong_type_argument_with_type(sc, sc->append_symbol, position_of(y, args), p, a_proper_list_string));
  31418. }
  31419. /* is this error correct?
  31420. * (append '(3) '(1 . 2)) -> '(3 1 . 2) ; (old) guile also returns this
  31421. * but (append '(1 . 2) '(3)) -> this error
  31422. */
  31423. if (is_null(tp))
  31424. {
  31425. tp = cons(sc, car(p), sc->nil);
  31426. np = tp;
  31427. sc->y = tp; /* GC protect? */
  31428. pp = cdr(p);
  31429. }
  31430. else pp = p;
  31431. for (; is_pair(pp); pp = cdr(pp), np = cdr(np))
  31432. set_cdr(np, cons(sc, car(pp), sc->nil));
  31433. }
  31434. else
  31435. {
  31436. s7_int len;
  31437. len = sequence_length(sc, p);
  31438. if (len > 0)
  31439. {
  31440. if (is_null(tp))
  31441. {
  31442. tp = s7_copy(sc, set_plist_2(sc, p, make_list(sc, len, sc->F)));
  31443. np = tp;
  31444. sc->y = tp;
  31445. }
  31446. else set_cdr(np, s7_copy(sc, set_plist_2(sc, p, make_list(sc, len, sc->F))));
  31447. for (; is_pair(cdr(np)); np = cdr(np));
  31448. }
  31449. else
  31450. {
  31451. if (len < 0)
  31452. return(wrong_type_argument_with_type(sc, sc->append_symbol, position_of(y, args), p, a_sequence_string));
  31453. }
  31454. }
  31455. }
  31456. }
  31457. return(tp);
  31458. }
  31459. static s7_pointer append_in_place(s7_scheme *sc, s7_pointer a, s7_pointer b)
  31460. {
  31461. /* tack b onto the end of a without copying either -- 'a' is changed! */
  31462. s7_pointer p;
  31463. if (is_null(a))
  31464. return(b);
  31465. p = a;
  31466. while (is_not_null(cdr(p))) p = cdr(p);
  31467. set_cdr(p, b);
  31468. return(a);
  31469. }
  31470. /* -------------------------------- vectors -------------------------------- */
  31471. bool s7_is_vector(s7_pointer p)
  31472. {
  31473. return(t_vector_p[type(p)]);
  31474. }
  31475. bool s7_is_float_vector(s7_pointer p)
  31476. {
  31477. return(type(p) == T_FLOAT_VECTOR);
  31478. }
  31479. bool s7_is_int_vector(s7_pointer p)
  31480. {
  31481. return(type(p) == T_INT_VECTOR);
  31482. }
  31483. static s7_pointer default_vector_setter(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val)
  31484. {
  31485. vector_element(vec, loc) = val;
  31486. return(val);
  31487. }
  31488. static s7_pointer default_vector_getter(s7_scheme *sc, s7_pointer vec, s7_int loc)
  31489. {
  31490. return(vector_element(vec, loc));
  31491. }
  31492. static s7_pointer int_vector_setter(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val)
  31493. {
  31494. if (!s7_is_integer(val))
  31495. s7_wrong_type_arg_error(sc, "int_vector_set!", 3, val, "an integer");
  31496. int_vector_element(vec, loc) = s7_integer(val);
  31497. return(val);
  31498. }
  31499. static s7_pointer int_vector_getter(s7_scheme *sc, s7_pointer vec, s7_int loc)
  31500. {
  31501. return(make_integer(sc, int_vector_element(vec, loc)));
  31502. }
  31503. static s7_pointer float_vector_setter(s7_scheme *sc, s7_pointer vec, s7_int loc, s7_pointer val)
  31504. {
  31505. float_vector_element(vec, loc) = real_to_double(sc, val, "float-vector-set!");
  31506. return(val);
  31507. }
  31508. static s7_pointer float_vector_getter(s7_scheme *sc, s7_pointer vec, s7_int loc)
  31509. {
  31510. return(make_real(sc, float_vector_element(vec, loc)));
  31511. }
  31512. static s7_pointer make_vector_1(s7_scheme *sc, s7_int len, bool filled, unsigned int typ)
  31513. {
  31514. s7_pointer x;
  31515. if (len < 0)
  31516. return(wrong_type_argument_with_type(sc, sc->make_vector_symbol, 1, make_integer(sc, len), a_non_negative_integer_string));
  31517. if (len > sc->max_vector_length)
  31518. return(out_of_range(sc, sc->make_vector_symbol, small_int(1), make_integer(sc, len), its_too_large_string));
  31519. /* this has to follow the error checks! (else garbage in free_heap temps portion confuses GC when "vector" is finalized) */
  31520. new_cell(sc, x, typ | T_SAFE_PROCEDURE); /* (v 0) as vector-ref is safe */
  31521. vector_length(x) = 0;
  31522. vector_elements(x) = NULL;
  31523. vector_dimension_info(x) = NULL;
  31524. if (len > 0)
  31525. {
  31526. vector_length(x) = len;
  31527. if (typ == T_VECTOR)
  31528. {
  31529. vector_elements(x) = (s7_pointer *)malloc(len * sizeof(s7_pointer));
  31530. if (!vector_elements(x))
  31531. return(s7_error(sc, make_symbol(sc, "out-of-memory"), set_elist_1(sc, make_string_wrapper(sc, "make-vector allocation failed!"))));
  31532. vector_getter(x) = default_vector_getter;
  31533. vector_setter(x) = default_vector_setter;
  31534. if (filled) s7_vector_fill(sc, x, sc->nil); /* make_hash_table assumes nil as the default value */
  31535. }
  31536. else
  31537. {
  31538. if (typ == T_FLOAT_VECTOR)
  31539. {
  31540. if (filled)
  31541. float_vector_elements(x) = (s7_double *)calloc(len, sizeof(s7_double));
  31542. else float_vector_elements(x) = (s7_double *)malloc(len * sizeof(s7_double));
  31543. if (!float_vector_elements(x))
  31544. return(s7_error(sc, make_symbol(sc, "out-of-memory"), set_elist_1(sc, make_string_wrapper(sc, "make-float-vector allocation failed!"))));
  31545. vector_getter(x) = float_vector_getter;
  31546. vector_setter(x) = float_vector_setter;
  31547. }
  31548. else
  31549. {
  31550. if (filled)
  31551. int_vector_elements(x) = (s7_int *)calloc(len, sizeof(s7_int));
  31552. else int_vector_elements(x) = (s7_int *)malloc(len * sizeof(s7_int));
  31553. if (!int_vector_elements(x))
  31554. return(s7_error(sc, make_symbol(sc, "out-of-memory"), set_elist_1(sc, make_string_wrapper(sc, "make-int-vector allocation failed!"))));
  31555. vector_getter(x) = int_vector_getter;
  31556. vector_setter(x) = int_vector_setter;
  31557. }
  31558. }
  31559. }
  31560. Add_Vector(x);
  31561. return(x);
  31562. }
  31563. s7_pointer s7_make_vector(s7_scheme *sc, s7_int len)
  31564. {
  31565. return(make_vector_1(sc, len, FILLED, T_VECTOR));
  31566. }
  31567. static vdims_t *make_wrap_only(s7_scheme *sc)
  31568. {
  31569. vdims_t *v;
  31570. v = (vdims_t *)malloc(sizeof(vdims_t));
  31571. v->original = sc->F;
  31572. v->elements_allocated = false;
  31573. v->ndims = 1;
  31574. v->dimensions_allocated = false;
  31575. v->dims = NULL;
  31576. v->offsets = NULL;
  31577. return(v);
  31578. }
  31579. #define make_vdims(Sc, Alloc, Dims, Info) ((((Dims) == 1) && (!(Alloc))) ? sc->wrap_only : make_vdims_1(Sc, Alloc, Dims, Info))
  31580. static vdims_t *make_vdims_1(s7_scheme *sc, bool elements_allocated, int dims, s7_int *dim_info)
  31581. {
  31582. vdims_t *v;
  31583. v = (vdims_t *)malloc(sizeof(vdims_t));
  31584. v->original = sc->F;
  31585. v->elements_allocated = elements_allocated;
  31586. v->ndims = dims;
  31587. if (dims > 1)
  31588. {
  31589. int i;
  31590. s7_int offset = 1;
  31591. v->dimensions_allocated = true;
  31592. v->dims = (s7_int *)malloc(v->ndims * sizeof(s7_int));
  31593. v->offsets = (s7_int *)malloc(v->ndims * sizeof(s7_int));
  31594. for (i = 0; i < dims; i++)
  31595. v->dims[i] = dim_info[i];
  31596. for (i = v->ndims - 1; i >= 0; i--)
  31597. {
  31598. v->offsets[i] = offset;
  31599. offset *= v->dims[i];
  31600. }
  31601. }
  31602. else
  31603. {
  31604. v->dimensions_allocated = false;
  31605. v->dims = NULL;
  31606. v->offsets = NULL;
  31607. }
  31608. return(v);
  31609. }
  31610. s7_pointer s7_make_int_vector(s7_scheme *sc, s7_int len, int dims, s7_int *dim_info)
  31611. {
  31612. s7_pointer p;
  31613. p = make_vector_1(sc, len, FILLED, T_INT_VECTOR);
  31614. if (dim_info)
  31615. vector_dimension_info(p) = make_vdims(sc, true, dims, dim_info);
  31616. return(p);
  31617. }
  31618. s7_pointer s7_make_float_vector(s7_scheme *sc, s7_int len, int dims, s7_int *dim_info)
  31619. {
  31620. s7_pointer p;
  31621. p = make_vector_1(sc, len, FILLED, T_FLOAT_VECTOR);
  31622. if (dim_info)
  31623. vector_dimension_info(p) = make_vdims(sc, true, dims, dim_info);
  31624. return(p);
  31625. }
  31626. s7_pointer s7_make_float_vector_wrapper(s7_scheme *sc, s7_int len, s7_double *data, int dims, s7_int *dim_info, bool free_data)
  31627. {
  31628. /* this wraps up a C-allocated/freed double array as an s7 vector.
  31629. */
  31630. s7_pointer x;
  31631. new_cell(sc, x, T_FLOAT_VECTOR | T_SAFE_PROCEDURE);
  31632. float_vector_elements(x) = data;
  31633. vector_getter(x) = float_vector_getter;
  31634. vector_setter(x) = float_vector_setter;
  31635. vector_length(x) = len;
  31636. if (!dim_info)
  31637. {
  31638. if (!free_data) /* here we need the dim info to tell the GC to leave the data alone */
  31639. {
  31640. s7_int di[1];
  31641. di[0] = len;
  31642. vector_dimension_info(x) = make_vdims(sc, free_data, 1, di);
  31643. }
  31644. else vector_dimension_info(x) = NULL;
  31645. }
  31646. else vector_dimension_info(x) = make_vdims(sc, free_data, dims, dim_info);
  31647. Add_Vector(x);
  31648. return(x);
  31649. }
  31650. s7_int s7_vector_length(s7_pointer vec)
  31651. {
  31652. return(vector_length(vec));
  31653. }
  31654. s7_int s7_print_length(s7_scheme *sc) {return(sc->print_length);}
  31655. s7_int s7_set_print_length(s7_scheme *sc, s7_int new_len)
  31656. {
  31657. s7_int old_len;
  31658. old_len = sc->print_length;
  31659. sc->print_length = new_len;
  31660. return(old_len);
  31661. }
  31662. #if (!WITH_GMP)
  31663. void s7_vector_fill(s7_scheme *sc, s7_pointer vec, s7_pointer obj)
  31664. #else
  31665. static void vector_fill(s7_scheme *sc, s7_pointer vec, s7_pointer obj)
  31666. #endif
  31667. {
  31668. s7_int len, i, left;
  31669. len = vector_length(vec);
  31670. if (len == 0) return;
  31671. left = len - 8;
  31672. i = 0;
  31673. switch (type(vec))
  31674. {
  31675. case T_FLOAT_VECTOR:
  31676. if (!s7_is_real(obj))
  31677. s7_wrong_type_arg_error(sc, "(float) vector-fill!", 2, obj, "a real");
  31678. else
  31679. {
  31680. s7_double x;
  31681. x = real_to_double(sc, obj, "vector-fill!");
  31682. if (x == 0.0)
  31683. memclr((void *)float_vector_elements(vec), len * sizeof(s7_double));
  31684. else
  31685. {
  31686. s7_double *orig;
  31687. orig = float_vector_elements(vec);
  31688. while (i <= left)
  31689. {
  31690. orig[i++] = x;
  31691. orig[i++] = x;
  31692. orig[i++] = x;
  31693. orig[i++] = x;
  31694. orig[i++] = x;
  31695. orig[i++] = x;
  31696. orig[i++] = x;
  31697. orig[i++] = x;
  31698. }
  31699. for (; i < len; i++)
  31700. orig[i] = x;
  31701. }
  31702. }
  31703. break;
  31704. case T_INT_VECTOR:
  31705. if (!s7_is_integer(obj)) /* possibly a bignum */
  31706. s7_wrong_type_arg_error(sc, "(int) vector-fill!", 2, obj, "an integer");
  31707. else
  31708. {
  31709. s7_int k;
  31710. k = s7_integer(obj);
  31711. if (k == 0)
  31712. memclr((void *)int_vector_elements(vec), len * sizeof(s7_int));
  31713. else
  31714. {
  31715. s7_int* orig;
  31716. orig = int_vector_elements(vec);
  31717. while (i <= left)
  31718. {
  31719. orig[i++] = k;
  31720. orig[i++] = k;
  31721. orig[i++] = k;
  31722. orig[i++] = k;
  31723. orig[i++] = k;
  31724. orig[i++] = k;
  31725. orig[i++] = k;
  31726. orig[i++] = k;
  31727. }
  31728. for (; i < len; i++)
  31729. orig[i] = k;
  31730. }
  31731. }
  31732. break;
  31733. default:
  31734. {
  31735. s7_pointer *orig;
  31736. orig = vector_elements(vec);
  31737. while (i <= left)
  31738. {
  31739. orig[i++] = obj;
  31740. orig[i++] = obj;
  31741. orig[i++] = obj;
  31742. orig[i++] = obj;
  31743. orig[i++] = obj;
  31744. orig[i++] = obj;
  31745. orig[i++] = obj;
  31746. orig[i++] = obj;
  31747. }
  31748. for (; i < len; i++)
  31749. orig[i] = obj;
  31750. }
  31751. }
  31752. }
  31753. static s7_pointer g_vector_fill(s7_scheme *sc, s7_pointer args)
  31754. {
  31755. #define H_vector_fill "(vector-fill! v val start end) sets all elements of the vector v between start and end to val"
  31756. #define Q_vector_fill s7_make_circular_signature(sc, 3, 4, sc->T, sc->is_vector_symbol, sc->T, sc->is_integer_symbol)
  31757. s7_pointer x, fill;
  31758. s7_int start = 0, end;
  31759. x = car(args);
  31760. if (!s7_is_vector(x))
  31761. {
  31762. check_method(sc, x, sc->vector_fill_symbol, args);
  31763. /* not two_methods (and fill!) here else we get stuff like:
  31764. * (let ((e (openlet (inlet 'fill! (lambda (obj val) (string-fill! (obj 'value) val)) 'value "01234")))) (vector-fill! e #\a) (e 'value)) -> "aaaaa"
  31765. */
  31766. return(wrong_type_argument(sc, sc->vector_fill_symbol, 1, x, T_VECTOR));
  31767. }
  31768. fill = cadr(args);
  31769. if (is_float_vector(x))
  31770. {
  31771. if (!s7_is_real(fill)) /* possibly a bignum */
  31772. {
  31773. check_two_methods(sc, fill, sc->vector_fill_symbol, sc->fill_symbol, args);
  31774. s7_wrong_type_arg_error(sc, "(float) vector-fill!", 2, fill, "a real");
  31775. }
  31776. }
  31777. else
  31778. {
  31779. if (is_int_vector(x))
  31780. {
  31781. if (!s7_is_integer(fill))
  31782. {
  31783. check_two_methods(sc, fill, sc->vector_fill_symbol, sc->fill_symbol, args);
  31784. s7_wrong_type_arg_error(sc, "(int) vector-fill!", 2, fill, "an integer");
  31785. }
  31786. }
  31787. }
  31788. end = vector_length(x);
  31789. if (!is_null(cddr(args)))
  31790. {
  31791. s7_pointer p;
  31792. p = start_and_end(sc, sc->vector_fill_symbol, sc->fill_symbol, cddr(args), args, 3, &start, &end);
  31793. if (p != sc->gc_nil) return(p);
  31794. if (start == end) return(fill);
  31795. }
  31796. if (end == 0) return(fill);
  31797. if ((start == 0) && (end == vector_length(x)))
  31798. s7_vector_fill(sc, x, fill);
  31799. else
  31800. {
  31801. s7_int i;
  31802. if (is_normal_vector(x))
  31803. {
  31804. for (i = start; i < end; i++)
  31805. vector_element(x, i) = fill;
  31806. }
  31807. else
  31808. {
  31809. if (is_int_vector(x))
  31810. {
  31811. s7_int k;
  31812. k = s7_integer(fill);
  31813. if (k == 0)
  31814. memclr((void *)(int_vector_elements(x) + start), (end - start) * sizeof(s7_int));
  31815. else
  31816. {
  31817. for (i = start; i < end; i++)
  31818. int_vector_element(x, i) = k;
  31819. }
  31820. }
  31821. else
  31822. {
  31823. if (is_float_vector(x))
  31824. {
  31825. s7_double y;
  31826. y = real_to_double(sc, fill, "vector-fill!");
  31827. if (y == 0.0)
  31828. memclr((void *)(float_vector_elements(x) + start), (end - start) * sizeof(s7_double));
  31829. else
  31830. {
  31831. s7_double *orig;
  31832. s7_int left;
  31833. orig = float_vector_elements(x);
  31834. left = end - 8;
  31835. i = start;
  31836. while (i <= left)
  31837. {
  31838. orig[i++] = y;
  31839. orig[i++] = y;
  31840. orig[i++] = y;
  31841. orig[i++] = y;
  31842. orig[i++] = y;
  31843. orig[i++] = y;
  31844. orig[i++] = y;
  31845. orig[i++] = y;
  31846. }
  31847. for (; i < end; i++)
  31848. orig[i] = y;
  31849. }
  31850. }
  31851. }
  31852. }
  31853. }
  31854. return(fill);
  31855. }
  31856. #if (!WITH_PURE_S7)
  31857. static s7_pointer c_vector_fill(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_vector_fill(sc, set_plist_2(sc, x, y)));}
  31858. PF2_TO_PF(vector_fill, c_vector_fill)
  31859. #endif
  31860. s7_pointer s7_vector_ref(s7_scheme *sc, s7_pointer vec, s7_int index)
  31861. {
  31862. if (index >= vector_length(vec))
  31863. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), make_integer(sc, index), its_too_large_string));
  31864. return(vector_getter(vec)(sc, vec, index));
  31865. }
  31866. s7_pointer s7_vector_set(s7_scheme *sc, s7_pointer vec, s7_int index, s7_pointer a)
  31867. {
  31868. if (index >= vector_length(vec))
  31869. return(out_of_range(sc, sc->vector_set_symbol, small_int(2), make_integer(sc, index), its_too_large_string));
  31870. vector_setter(vec)(sc, vec, index, _NFre(a));
  31871. return(a);
  31872. }
  31873. s7_pointer *s7_vector_elements(s7_pointer vec)
  31874. {
  31875. return(vector_elements(vec));
  31876. }
  31877. s7_int *s7_int_vector_elements(s7_pointer vec)
  31878. {
  31879. return(int_vector_elements(vec));
  31880. }
  31881. s7_double *s7_float_vector_elements(s7_pointer vec)
  31882. {
  31883. return(float_vector_elements(vec));
  31884. }
  31885. s7_int *s7_vector_dimensions(s7_pointer vec)
  31886. {
  31887. s7_int *dims;
  31888. if (vector_dimension_info(vec))
  31889. return(vector_dimensions(vec));
  31890. dims = (s7_int *)malloc(sizeof(s7_int));
  31891. dims[0] = vector_length(vec);
  31892. return(dims);
  31893. }
  31894. s7_int *s7_vector_offsets(s7_pointer vec)
  31895. {
  31896. s7_int *offs;
  31897. if (vector_dimension_info(vec))
  31898. return(vector_offsets(vec));
  31899. offs = (s7_int *)malloc(sizeof(s7_int));
  31900. offs[0] = 1;
  31901. return(offs);
  31902. }
  31903. #if (!WITH_PURE_S7)
  31904. static s7_pointer vector_append(s7_scheme *sc, s7_pointer args, int typ);
  31905. static s7_pointer g_vector_append(s7_scheme *sc, s7_pointer args)
  31906. {
  31907. /* returns a one-dimensional vector. To handle multidimensional vectors, we'd need to
  31908. * ensure all the dimensional data matches (rank, size of each dimension except the last etc),
  31909. * which is too much trouble.
  31910. */
  31911. #define H_vector_append "(vector-append . vectors) returns a new (1-dimensional) vector containing the elements of its vector arguments."
  31912. #define Q_vector_append pcl_v
  31913. s7_pointer p;
  31914. int i;
  31915. if (is_null(args))
  31916. return(make_vector_1(sc, 0, NOT_FILLED, T_VECTOR));
  31917. for (i = 0, p = args; is_pair(p); p = cdr(p), i++)
  31918. {
  31919. s7_pointer x;
  31920. x = car(p);
  31921. if (!s7_is_vector(x))
  31922. {
  31923. if (has_methods(x))
  31924. {
  31925. s7_pointer func;
  31926. func = find_method(sc, find_let(sc, x), sc->vector_append_symbol);
  31927. if (func != sc->undefined)
  31928. {
  31929. int k;
  31930. s7_pointer v, y;
  31931. if (i == 0)
  31932. return(s7_apply_function(sc, func, args));
  31933. /* we have to copy the arglist here */
  31934. sc->temp9 = make_list(sc, i, sc->F);
  31935. for (k = 0, y = args, v = sc->temp9; k < i; k++, y = cdr(y), v = cdr(v))
  31936. set_car(v, car(y));
  31937. v = g_vector_append(sc, sc->temp9);
  31938. y = s7_apply_function(sc, func, cons(sc, v, p));
  31939. sc->temp9 = sc->nil;
  31940. return(y);
  31941. }
  31942. }
  31943. return(wrong_type_argument(sc, sc->vector_append_symbol, i, x, T_VECTOR));
  31944. }
  31945. }
  31946. return(vector_append(sc, args, type(car(args))));
  31947. }
  31948. #endif
  31949. s7_pointer s7_vector_ref_n(s7_scheme *sc, s7_pointer vector, int indices, ...)
  31950. {
  31951. /* from s7.html */
  31952. int ndims;
  31953. ndims = s7_vector_rank(vector);
  31954. if (ndims == indices)
  31955. {
  31956. va_list ap;
  31957. s7_int index = 0;
  31958. va_start(ap, indices);
  31959. if (ndims == 1)
  31960. {
  31961. index = va_arg(ap, s7_int);
  31962. va_end(ap);
  31963. return(s7_vector_ref(sc, vector, index));
  31964. }
  31965. else
  31966. {
  31967. int i;
  31968. s7_int *offsets, *dimensions;
  31969. dimensions = s7_vector_dimensions(vector);
  31970. offsets = s7_vector_offsets(vector);
  31971. for (i = 0; i < indices; i++)
  31972. {
  31973. int ind;
  31974. ind = va_arg(ap, int);
  31975. if ((ind < 0) ||
  31976. (ind >= dimensions[i]))
  31977. {
  31978. va_end(ap);
  31979. return(out_of_range(sc, sc->vector_ref_symbol, small_int(i), make_integer(sc, ind), (ind < 0) ? its_negative_string : its_too_large_string));
  31980. }
  31981. index += (ind * offsets[i]);
  31982. }
  31983. va_end(ap);
  31984. return(vector_getter(vector)(sc, vector, index));
  31985. }
  31986. }
  31987. return(s7_wrong_number_of_args_error(sc, "s7_vector_ref_n: wrong number of indices: ~A", s7_make_integer(sc, indices)));
  31988. }
  31989. s7_pointer s7_vector_set_n(s7_scheme *sc, s7_pointer vector, s7_pointer value, int indices, ...)
  31990. {
  31991. int ndims;
  31992. ndims = s7_vector_rank(vector);
  31993. if (ndims == indices)
  31994. {
  31995. va_list ap;
  31996. s7_int index = 0;
  31997. va_start(ap, indices);
  31998. if (ndims == 1)
  31999. {
  32000. index = va_arg(ap, s7_int);
  32001. va_end(ap);
  32002. s7_vector_set(sc, vector, index, value);
  32003. return(value);
  32004. }
  32005. else
  32006. {
  32007. int i;
  32008. s7_int *offsets, *dimensions;
  32009. dimensions = s7_vector_dimensions(vector);
  32010. offsets = s7_vector_offsets(vector);
  32011. for (i = 0; i < indices; i++)
  32012. {
  32013. int ind;
  32014. ind = va_arg(ap, int);
  32015. if ((ind < 0) ||
  32016. (ind >= dimensions[i]))
  32017. {
  32018. va_end(ap);
  32019. return(s7_out_of_range_error(sc, "s7_vector_set_n", i, s7_make_integer(sc, ind), "should be a valid index"));
  32020. }
  32021. index += (ind * offsets[i]);
  32022. }
  32023. va_end(ap);
  32024. vector_setter(vector)(sc, vector, index, value);
  32025. return(value);
  32026. }
  32027. }
  32028. return(s7_wrong_number_of_args_error(sc, "s7_vector_set_n: wrong number of indices: ~A", s7_make_integer(sc, indices)));
  32029. }
  32030. s7_pointer s7_vector_to_list(s7_scheme *sc, s7_pointer vect)
  32031. {
  32032. s7_int i, len;
  32033. s7_pointer result;
  32034. len = vector_length(vect);
  32035. if (len == 0)
  32036. return(sc->nil);
  32037. if (len >= (sc->free_heap_top - sc->free_heap))
  32038. {
  32039. gc(sc);
  32040. while (len >= (sc->free_heap_top - sc->free_heap))
  32041. resize_heap(sc);
  32042. }
  32043. sc->v = sc->nil;
  32044. for (i = len - 1; i >= 0; i--)
  32045. sc->v = cons_unchecked(sc, vector_getter(vect)(sc, vect, i), sc->v);
  32046. result = sc->v;
  32047. sc->v = sc->nil;
  32048. return(result);
  32049. }
  32050. #if (!WITH_PURE_S7)
  32051. static s7_pointer c_vector_to_list(s7_scheme *sc, s7_pointer vec)
  32052. {
  32053. sc->temp3 = vec;
  32054. if (!s7_is_vector(vec))
  32055. method_or_bust(sc, vec, sc->vector_to_list_symbol, list_1(sc, vec), T_VECTOR, 0);
  32056. return(s7_vector_to_list(sc, vec));
  32057. }
  32058. static s7_pointer g_vector_to_list(s7_scheme *sc, s7_pointer args)
  32059. {
  32060. s7_int i, start = 0, end;
  32061. s7_pointer p, vec;
  32062. #define H_vector_to_list "(vector->list v start end) returns the elements of the vector v as a list; (map values v)"
  32063. #define Q_vector_to_list s7_make_circular_signature(sc, 2, 3, sc->is_proper_list_symbol, sc->is_vector_symbol, sc->is_integer_symbol)
  32064. vec = car(args);
  32065. if (!s7_is_vector(vec))
  32066. method_or_bust(sc, vec, sc->vector_to_list_symbol, args, T_VECTOR, 0);
  32067. end = vector_length(vec);
  32068. if (!is_null(cdr(args)))
  32069. {
  32070. p = start_and_end(sc, sc->vector_to_list_symbol, NULL, cdr(args), args, 2, &start, &end);
  32071. if (p != sc->gc_nil) return(p);
  32072. if (start == end) return(sc->nil);
  32073. }
  32074. if ((start == 0) && (end == vector_length(vec)))
  32075. return(s7_vector_to_list(sc, vec));
  32076. sc->w = sc->nil;
  32077. for (i = end - 1; i >= start; i--)
  32078. sc->w = cons(sc, vector_getter(vec)(sc, vec, i), sc->w);
  32079. p = sc->w;
  32080. sc->w = sc->nil;
  32081. return(p);
  32082. }
  32083. PF_TO_PF(vector_to_list, c_vector_to_list)
  32084. #endif
  32085. s7_pointer s7_make_and_fill_vector(s7_scheme *sc, s7_int len, s7_pointer fill)
  32086. {
  32087. s7_pointer vect;
  32088. vect = make_vector_1(sc, len, NOT_FILLED, T_VECTOR);
  32089. s7_vector_fill(sc, vect, fill);
  32090. return(vect);
  32091. }
  32092. static s7_pointer g_vector(s7_scheme *sc, s7_pointer args)
  32093. {
  32094. #define H_vector "(vector ...) returns a vector whose elements are the arguments"
  32095. #define Q_vector s7_make_circular_signature(sc, 1, 2, sc->is_vector_symbol, sc->T)
  32096. s7_int len;
  32097. s7_pointer vec;
  32098. len = s7_list_length(sc, args);
  32099. vec = make_vector_1(sc, len, NOT_FILLED, T_VECTOR);
  32100. if (len > 0)
  32101. {
  32102. s7_int i;
  32103. s7_pointer x;
  32104. for (x = args, i = 0; is_pair(x); x = cdr(x), i++)
  32105. vector_element(vec, i) = car(x);
  32106. }
  32107. return(vec);
  32108. }
  32109. static s7_pointer c_vector_1(s7_scheme *sc, s7_pointer x) {return(g_vector(sc, set_plist_1(sc, x)));}
  32110. PF_TO_PF(vector, c_vector_1)
  32111. static s7_pointer g_is_float_vector(s7_scheme *sc, s7_pointer args)
  32112. {
  32113. #define H_is_float_vector "(float-vector? obj) returns #t if obj is an homogeneous float vector"
  32114. #define Q_is_float_vector pl_bt
  32115. check_boolean_method(sc, s7_is_float_vector, sc->is_float_vector_symbol, args);
  32116. }
  32117. static s7_pointer g_float_vector(s7_scheme *sc, s7_pointer args)
  32118. {
  32119. #define H_float_vector "(float-vector ...) returns an homogeneous float vector whose elements are the arguments"
  32120. #define Q_float_vector s7_make_circular_signature(sc, 1, 2, sc->is_float_vector_symbol, sc->is_real_symbol)
  32121. s7_int len;
  32122. s7_pointer vec;
  32123. len = s7_list_length(sc, args);
  32124. vec = make_vector_1(sc, len, NOT_FILLED, T_FLOAT_VECTOR); /* dangerous: assumes real_to_double won't trigger GC even if bignums */
  32125. if (len > 0)
  32126. {
  32127. s7_int i;
  32128. s7_pointer x;
  32129. for (x = args, i = 0; is_pair(x); x = cdr(x), i++)
  32130. {
  32131. if (s7_is_real(car(x))) /* bignum is ok here */
  32132. float_vector_element(vec, i) = real_to_double(sc, car(x), "float-vector");
  32133. else return(simple_wrong_type_argument(sc, sc->float_vector_symbol, car(x), T_REAL));
  32134. }
  32135. }
  32136. return(vec);
  32137. }
  32138. static s7_pointer c_float_vector_1(s7_scheme *sc, s7_pointer x) {return(g_float_vector(sc, set_plist_1(sc, x)));}
  32139. PF_TO_PF(float_vector, c_float_vector_1)
  32140. static s7_pointer g_is_int_vector(s7_scheme *sc, s7_pointer args)
  32141. {
  32142. #define H_is_int_vector "(int-vector? obj) returns #t if obj is an homogeneous int vector"
  32143. #define Q_is_int_vector pl_bt
  32144. check_boolean_method(sc, is_int_vector, sc->is_int_vector_symbol, args);
  32145. }
  32146. static s7_pointer g_int_vector(s7_scheme *sc, s7_pointer args)
  32147. {
  32148. #define H_int_vector "(int-vector ...) returns an homogeneous int vector whose elements are the arguments"
  32149. #define Q_int_vector s7_make_circular_signature(sc, 1, 2, sc->is_int_vector_symbol, sc->is_integer_symbol)
  32150. s7_int len;
  32151. s7_pointer vec;
  32152. len = s7_list_length(sc, args);
  32153. vec = make_vector_1(sc, len, NOT_FILLED, T_INT_VECTOR);
  32154. if (len > 0)
  32155. {
  32156. s7_int i;
  32157. s7_pointer x;
  32158. for (x = args, i = 0; is_pair(x); x = cdr(x), i++)
  32159. {
  32160. if (is_integer(car(x)))
  32161. int_vector_element(vec, i) = integer(car(x));
  32162. else return(simple_wrong_type_argument(sc, sc->int_vector_symbol, car(x), T_INTEGER));
  32163. }
  32164. }
  32165. return(vec);
  32166. }
  32167. static s7_pointer c_int_vector_1(s7_scheme *sc, s7_pointer x) {return(g_int_vector(sc, set_plist_1(sc, x)));}
  32168. PF_TO_PF(int_vector, c_int_vector_1)
  32169. #if (!WITH_PURE_S7)
  32170. static s7_pointer c_list_to_vector(s7_scheme *sc, s7_pointer p)
  32171. {
  32172. sc->temp3 = p;
  32173. if (is_null(p))
  32174. return(s7_make_vector(sc, 0));
  32175. if (!is_proper_list(sc, p))
  32176. method_or_bust_with_type(sc, p, sc->list_to_vector_symbol, list_1(sc, p), a_proper_list_string, 0);
  32177. return(g_vector(sc, p));
  32178. }
  32179. static s7_pointer g_list_to_vector(s7_scheme *sc, s7_pointer args)
  32180. {
  32181. #define H_list_to_vector "(list->vector lst) returns a vector containing the elements of lst; (apply vector lst)"
  32182. #define Q_list_to_vector s7_make_signature(sc, 2, sc->is_vector_symbol, sc->is_proper_list_symbol)
  32183. return(c_list_to_vector(sc, car(args)));
  32184. }
  32185. PF_TO_PF(list_to_vector, c_list_to_vector)
  32186. static s7_pointer g_vector_length(s7_scheme *sc, s7_pointer args)
  32187. {
  32188. s7_pointer vec;
  32189. #define H_vector_length "(vector-length v) returns the length of vector v"
  32190. #define Q_vector_length s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_vector_symbol)
  32191. vec = car(args);
  32192. if (!s7_is_vector(vec))
  32193. method_or_bust(sc, vec, sc->vector_length_symbol, args, T_VECTOR, 0);
  32194. return(make_integer(sc, vector_length(vec)));
  32195. }
  32196. static s7_int c_vector_length(s7_scheme *sc, s7_pointer vec)
  32197. {
  32198. if (!s7_is_vector(vec))
  32199. int_method_or_bust(sc, vec, sc->vector_length_symbol, set_plist_1(sc, vec), T_VECTOR, 0);
  32200. return(vector_length(vec));
  32201. }
  32202. PF_TO_IF(vector_length, c_vector_length)
  32203. #endif
  32204. static s7_pointer make_shared_vector(s7_scheme *sc, s7_pointer vect, int skip_dims, s7_int index)
  32205. {
  32206. s7_pointer x;
  32207. vdims_t *v;
  32208. /* (let ((v #2d((1 2) (3 4)))) (v 1))
  32209. * (let ((v (make-vector '(2 3 4) 0))) (v 1 2))
  32210. * (let ((v #3d(((0 1 2 3) (4 5 6 7) (8 9 10 11)) ((12 13 14 15) (16 17 18 19) (20 21 22 23))))) (v 0 1))
  32211. */
  32212. new_cell(sc, x, typeflag(vect) | T_SAFE_PROCEDURE);
  32213. vector_length(x) = 0;
  32214. vector_elements(x) = NULL;
  32215. vector_getter(x) = vector_getter(vect);
  32216. vector_setter(x) = vector_setter(vect);
  32217. v = (vdims_t *)malloc(sizeof(vdims_t));
  32218. v->ndims = vector_ndims(vect) - skip_dims;
  32219. v->dims = (s7_int *)(vector_dimensions(vect) + skip_dims);
  32220. v->offsets = (s7_int *)(vector_offsets(vect) + skip_dims);
  32221. v->original = vect; /* shared_vector */
  32222. if (type(vect) == T_VECTOR)
  32223. mark_function[T_VECTOR] = mark_vector_possibly_shared;
  32224. else mark_function[type(vect)] = mark_int_or_float_vector_possibly_shared;
  32225. v->elements_allocated = false;
  32226. v->dimensions_allocated = false;
  32227. vector_dimension_info(x) = v;
  32228. if (skip_dims > 0)
  32229. vector_length(x) = vector_offset(vect, skip_dims - 1);
  32230. else vector_length(x) = vector_length(vect);
  32231. if (is_int_vector(vect))
  32232. int_vector_elements(x) = (s7_int *)(int_vector_elements(vect) + index);
  32233. else
  32234. {
  32235. if (is_float_vector(vect))
  32236. float_vector_elements(x) = (s7_double *)(float_vector_elements(vect) + index);
  32237. else vector_elements(x) = (s7_pointer *)(vector_elements(vect) + index);
  32238. }
  32239. add_vector(sc, x);
  32240. return(x);
  32241. }
  32242. static s7_pointer g_make_shared_vector(s7_scheme *sc, s7_pointer args)
  32243. {
  32244. #define H_make_shared_vector "(make-shared-vector original-vector new-dimensions (offset 0)) returns \
  32245. a vector that points to the same elements as the original-vector but with different dimensional info."
  32246. #define Q_make_shared_vector s7_make_signature(sc, 4, sc->is_vector_symbol, sc->is_vector_symbol, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_integer_symbol), sc->is_integer_symbol)
  32247. /* (let ((v1 #2d((1 2 3) (4 5 6)))) (let ((v2 (make-shared-vector v1 '(6)))) v2)) -> #(1 2 3 4 5 6)
  32248. * (let ((v1 #(1 2 3 4 5 6))) (let ((v2 (make-shared-vector v1 '(3 2)))) v2)) -> #2D((1 2) (3 4) (5 6))
  32249. * this is most useful in generic functions -- they can still use (v n) as the accessor.
  32250. */
  32251. s7_pointer orig, dims, y, x;
  32252. vdims_t *v;
  32253. int i;
  32254. s7_int new_len = 1, orig_len, offset = 0;
  32255. orig = car(args);
  32256. if (!s7_is_vector(orig))
  32257. method_or_bust(sc, orig, sc->make_shared_vector_symbol, args, T_VECTOR, 1);
  32258. orig_len = vector_length(orig);
  32259. if (!is_null(cddr(args)))
  32260. {
  32261. s7_pointer off;
  32262. off = caddr(args);
  32263. if (s7_is_integer(off))
  32264. {
  32265. offset = s7_integer(off);
  32266. if ((offset < 0) ||
  32267. (offset >= orig_len)) /* we need this if, for example, offset == 9223372036854775807 */
  32268. return(out_of_range(sc, sc->make_shared_vector_symbol, small_int(3), off, (offset < 0) ? its_negative_string : its_too_large_string));
  32269. }
  32270. else method_or_bust(sc, off, sc->make_shared_vector_symbol, args, T_INTEGER, 3);
  32271. }
  32272. dims = cadr(args);
  32273. if (is_integer(dims))
  32274. {
  32275. if ((s7_integer(dims) < 0) ||
  32276. (s7_integer(dims) >= orig_len))
  32277. return(out_of_range(sc, sc->make_shared_vector_symbol, small_int(2), dims, (s7_integer(dims) < 0) ? its_negative_string : its_too_large_string));
  32278. dims = list_1(sc, dims);
  32279. }
  32280. else
  32281. {
  32282. if ((is_null(dims)) ||
  32283. (!is_proper_list(sc, dims)))
  32284. method_or_bust(sc, dims, sc->make_shared_vector_symbol, args, T_PAIR, 2);
  32285. for (y = dims; is_pair(y); y = cdr(y))
  32286. if ((!s7_is_integer(car(y))) || /* (make-shared-vector v '((1 2) (3 4))) */
  32287. (s7_integer(car(y)) > orig_len) ||
  32288. (s7_integer(car(y)) < 0))
  32289. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_1(sc, make_string_wrapper(sc, "a list of integers that fits the original vector"))));
  32290. }
  32291. v = (vdims_t *)malloc(sizeof(vdims_t));
  32292. v->ndims = safe_list_length(sc, dims);
  32293. v->dims = (s7_int *)malloc(v->ndims * sizeof(s7_int));
  32294. v->offsets = (s7_int *)malloc(v->ndims * sizeof(s7_int));
  32295. v->dimensions_allocated = true;
  32296. v->elements_allocated = false;
  32297. v->original = orig; /* shared_vector */
  32298. if (type(orig) == T_VECTOR)
  32299. mark_function[T_VECTOR] = mark_vector_possibly_shared;
  32300. else mark_function[type(orig)] = mark_int_or_float_vector_possibly_shared;
  32301. for (i = 0, y = dims; is_pair(y); i++, y = cdr(y))
  32302. v->dims[i] = s7_integer(car(y));
  32303. for (i = v->ndims - 1; i >= 0; i--)
  32304. {
  32305. v->offsets[i] = new_len;
  32306. new_len *= v->dims[i];
  32307. }
  32308. if ((new_len < 0) || ((new_len + offset) > vector_length(orig)))
  32309. {
  32310. free(v->dims);
  32311. free(v->offsets);
  32312. free(v);
  32313. return(out_of_range(sc, sc->make_shared_vector_symbol, small_int(2), dims, make_string_wrapper(sc, "a shared vector has to fit in the original vector")));
  32314. }
  32315. new_cell(sc, x, typeflag(orig) | T_SAFE_PROCEDURE);
  32316. vector_dimension_info(x) = v;
  32317. vector_length(x) = new_len; /* might be less than original length */
  32318. vector_getter(x) = vector_getter(orig);
  32319. vector_setter(x) = vector_setter(orig);
  32320. if (is_int_vector(orig))
  32321. int_vector_elements(x) = (s7_int *)(int_vector_elements(orig) + offset);
  32322. else
  32323. {
  32324. if (is_float_vector(orig))
  32325. float_vector_elements(x) = (s7_double *)(float_vector_elements(orig) + offset);
  32326. else vector_elements(x) = (s7_pointer *)(vector_elements(orig) + offset);
  32327. }
  32328. add_vector(sc, x);
  32329. return(x);
  32330. }
  32331. static s7_pointer c_make_shared_vector_ppi(s7_scheme *sc, s7_pointer x, s7_pointer y, s7_int z)
  32332. {
  32333. return(g_make_shared_vector(sc, set_plist_3(sc, x, y, make_integer(sc, z))));
  32334. }
  32335. static s7_pointer c_make_shared_vector_pp(s7_scheme *sc, s7_pointer x, s7_pointer y)
  32336. {
  32337. return(g_make_shared_vector(sc, set_plist_2(sc, x, y)));
  32338. }
  32339. PPIF_TO_PF(make_shared_vector, c_make_shared_vector_pp, c_make_shared_vector_ppi)
  32340. static s7_pointer make_vector_wrapper(s7_scheme *sc, s7_int size, s7_pointer *elements)
  32341. {
  32342. s7_pointer x;
  32343. new_cell(sc, x, T_VECTOR | T_SAFE_PROCEDURE);
  32344. vector_length(x) = size;
  32345. vector_elements(x) = elements;
  32346. vector_getter(x) = default_vector_getter;
  32347. vector_setter(x) = default_vector_setter;
  32348. vector_dimension_info(x) = NULL;
  32349. /* don't add_vector -- no need for sweep to see this */
  32350. return(x);
  32351. }
  32352. static s7_pointer make_subvector(s7_scheme *sc, s7_pointer v)
  32353. {
  32354. s7_pointer x;
  32355. new_cell(sc, x, type(v));
  32356. vector_length(x) = vector_length(v);
  32357. if (is_normal_vector(v))
  32358. vector_elements(x) = vector_elements(v);
  32359. else
  32360. {
  32361. if (is_float_vector(v))
  32362. float_vector_elements(x) = float_vector_elements(v);
  32363. else int_vector_elements(x) = int_vector_elements(v);
  32364. }
  32365. vector_getter(x) = vector_getter(v);
  32366. vector_setter(x) = vector_setter(v);
  32367. vector_dimension_info(x) = NULL;
  32368. return(x);
  32369. }
  32370. static s7_pointer vector_ref_1(s7_scheme *sc, s7_pointer vect, s7_pointer indices)
  32371. {
  32372. s7_int index = 0;
  32373. if (vector_length(vect) == 0)
  32374. return(out_of_range(sc, sc->vector_ref_symbol, small_int(1), vect, its_too_large_string));
  32375. if (vector_rank(vect) > 1)
  32376. {
  32377. unsigned int i;
  32378. s7_pointer x;
  32379. for (x = indices, i = 0; (is_not_null(x)) && (i < vector_ndims(vect)); x = cdr(x), i++)
  32380. {
  32381. s7_int n;
  32382. s7_pointer p, p1;
  32383. p = car(x);
  32384. if (!s7_is_integer(p))
  32385. {
  32386. if (!s7_is_integer(p1 = check_values(sc, p, x)))
  32387. method_or_bust(sc, p, sc->vector_ref_symbol, cons(sc, vect, indices), T_INTEGER, i + 2);
  32388. p = p1;
  32389. }
  32390. n = s7_integer(p);
  32391. if ((n < 0) ||
  32392. (n >= vector_dimension(vect, i)))
  32393. return(out_of_range(sc, sc->vector_ref_symbol, make_integer(sc, i + 2), p, (n < 0) ? its_negative_string : its_too_large_string));
  32394. index += n * vector_offset(vect, i);
  32395. }
  32396. if (is_not_null(x))
  32397. {
  32398. if (type(vect) != T_VECTOR)
  32399. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), indices, too_many_indices_string));
  32400. return(implicit_index(sc, vector_element(vect, index), x));
  32401. }
  32402. /* if not enough indices, return a shared vector covering whatever is left */
  32403. if (i < vector_ndims(vect))
  32404. return(make_shared_vector(sc, vect, i, index));
  32405. }
  32406. else
  32407. {
  32408. s7_pointer p, p1;
  32409. /* (let ((hi (make-vector 3 0.0)) (sum 0.0)) (do ((i 0 (+ i 1))) ((= i 3)) (set! sum (+ sum (hi i)))) sum) */
  32410. p = car(indices);
  32411. if (!s7_is_integer(p))
  32412. {
  32413. if (!s7_is_integer(p1 = check_values(sc, p, indices)))
  32414. method_or_bust(sc, p, sc->vector_ref_symbol, cons(sc, vect, indices), T_INTEGER, 2);
  32415. p = p1;
  32416. }
  32417. index = s7_integer(p);
  32418. if ((index < 0) ||
  32419. (index >= vector_length(vect)))
  32420. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), p, (index < 0) ? its_negative_string : its_too_large_string));
  32421. if (is_not_null(cdr(indices))) /* (let ((L #(#(1 2 3) #(4 5 6)))) (vector-ref L 1 2)) */
  32422. {
  32423. if (type(vect) != T_VECTOR)
  32424. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), indices, too_many_indices_string));
  32425. return(implicit_index(sc, vector_element(vect, index), cdr(indices)));
  32426. }
  32427. }
  32428. return((vector_getter(vect))(sc, vect, index));
  32429. }
  32430. static s7_pointer g_vector_ref(s7_scheme *sc, s7_pointer args)
  32431. {
  32432. #define H_vector_ref "(vector-ref v ... i) returns the i-th element of vector v."
  32433. #define Q_vector_ref s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_vector_symbol, sc->is_integer_symbol)
  32434. s7_pointer vec;
  32435. vec = car(args);
  32436. if (!s7_is_vector(vec))
  32437. method_or_bust(sc, vec, sc->vector_ref_symbol, args, T_VECTOR, 1);
  32438. return(vector_ref_1(sc, vec, cdr(args)));
  32439. }
  32440. static s7_pointer g_vector_ref_ic_n(s7_scheme *sc, s7_pointer args, s7_int index)
  32441. {
  32442. s7_pointer vec;
  32443. vec = find_symbol_checked(sc, car(args));
  32444. if (!s7_is_vector(vec))
  32445. method_or_bust(sc, vec, sc->vector_ref_symbol, list_2(sc, vec, cadr(args)), T_VECTOR, 1);
  32446. if (index >= vector_length(vec))
  32447. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), cadr(args), its_too_large_string));
  32448. if (vector_rank(vec) > 1)
  32449. {
  32450. if (index >= vector_dimension(vec, 0))
  32451. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), cadr(args), its_too_large_string));
  32452. return(make_shared_vector(sc, vec, 1, index * vector_offset(vec, 0)));
  32453. }
  32454. return(vector_getter(vec)(sc,vec, index));
  32455. }
  32456. /* (vector-ref fv i) -> allocates real, so it's not a pf case */
  32457. static s7_pointer vector_ref_pf_slot(s7_scheme *sc, s7_pointer **p)
  32458. {
  32459. s7_pointer x, y;
  32460. x = (**p); (*p)++;
  32461. y = slot_value(**p); (*p)++;
  32462. return(vector_elements(x)[s7_integer(y)]);
  32463. }
  32464. static s7_pointer vector_ref_pf_s(s7_scheme *sc, s7_pointer **p)
  32465. {
  32466. s7_if_t xf;
  32467. s7_pointer x;
  32468. s7_int y;
  32469. x = (**p); (*p)++;
  32470. xf = (s7_if_t)(**p); (*p)++;
  32471. y = xf(sc, p);
  32472. return(vector_elements(x)[y]);
  32473. }
  32474. static s7_pointer vector_ref_pf_i(s7_scheme *sc, s7_pointer **p)
  32475. {
  32476. s7_if_t xf;
  32477. s7_pointer x;
  32478. s7_int y;
  32479. x = slot_value(**p); (*p)++;
  32480. xf = (s7_if_t)(**p); (*p)++;
  32481. y = xf(sc, p);
  32482. return(vector_elements(x)[y]);
  32483. }
  32484. static int c_vector_tester(s7_scheme *sc, s7_pointer expr)
  32485. {
  32486. s7_pointer a1;
  32487. a1 = cadr(expr);
  32488. if (is_symbol(a1))
  32489. {
  32490. s7_pointer table;
  32491. table = s7_slot(sc, a1);
  32492. if ((is_slot(table)) && ((is_immutable_symbol(a1)) || (!is_stepper(table))))
  32493. {
  32494. table = slot_value(table);
  32495. if ((type(table) == T_VECTOR) && (vector_rank(table) == 1))
  32496. {
  32497. s7_pointer a2;
  32498. s7_xf_store(sc, table);
  32499. a2 = caddr(expr);
  32500. if (is_symbol(a2))
  32501. {
  32502. s7_pointer slot;
  32503. slot = s7_slot(sc, a2);
  32504. if ((is_slot(slot)) &&
  32505. (is_integer(slot_value(slot))))
  32506. {
  32507. s7_xf_store(sc, slot);
  32508. return(TEST_SS);
  32509. }
  32510. }
  32511. else
  32512. {
  32513. if (s7_arg_to_if(sc, a2))
  32514. return(TEST_SI);
  32515. }
  32516. return(TEST_SQ);
  32517. }
  32518. }
  32519. }
  32520. return(TEST_NO_S);
  32521. }
  32522. static s7_pf_t vector_ref_pf(s7_scheme *sc, s7_pointer expr)
  32523. {
  32524. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_null(cdddr(expr))))
  32525. {
  32526. int choice;
  32527. choice = (c_vector_tester(sc, expr));
  32528. if (choice == TEST_SS)
  32529. return(vector_ref_pf_slot);
  32530. if (choice == TEST_SI)
  32531. return(vector_ref_pf_s);
  32532. }
  32533. return(NULL);
  32534. }
  32535. static s7_pointer vector_ref_ic;
  32536. static s7_pointer g_vector_ref_ic(s7_scheme *sc, s7_pointer args) {return(g_vector_ref_ic_n(sc, args, s7_integer(cadr(args))));}
  32537. static s7_pointer vector_ref_ic_0;
  32538. static s7_pointer g_vector_ref_ic_0(s7_scheme *sc, s7_pointer args) {return(g_vector_ref_ic_n(sc, args, 0));}
  32539. static s7_pointer vector_ref_ic_1;
  32540. static s7_pointer g_vector_ref_ic_1(s7_scheme *sc, s7_pointer args) {return(g_vector_ref_ic_n(sc, args, 1));}
  32541. static s7_pointer vector_ref_ic_2;
  32542. static s7_pointer g_vector_ref_ic_2(s7_scheme *sc, s7_pointer args) {return(g_vector_ref_ic_n(sc, args, 2));}
  32543. static s7_pointer vector_ref_ic_3;
  32544. static s7_pointer g_vector_ref_ic_3(s7_scheme *sc, s7_pointer args) {return(g_vector_ref_ic_n(sc, args, 3));}
  32545. static s7_pointer vector_ref_gs;
  32546. static s7_pointer g_vector_ref_gs(s7_scheme *sc, s7_pointer args)
  32547. {
  32548. /* global vector ref: (vector-ref global_vector i) */
  32549. s7_pointer x, vec;
  32550. s7_int index;
  32551. vec = find_global_symbol_checked(sc, car(args));
  32552. x = find_symbol_checked(sc, cadr(args));
  32553. if (!s7_is_vector(vec))
  32554. method_or_bust(sc, vec, sc->vector_ref_symbol, list_2(sc, vec, x), T_VECTOR, 1);
  32555. if (!s7_is_integer(x))
  32556. method_or_bust(sc, x, sc->vector_ref_symbol, list_2(sc, vec, x), T_INTEGER, 2);
  32557. index = s7_integer(x);
  32558. if ((index < 0) ||
  32559. (index >= vector_length(vec)))
  32560. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), cadr(args), (index < 0) ? its_negative_string : its_too_large_string));
  32561. if (vector_rank(vec) > 1)
  32562. {
  32563. if (index >= vector_dimension(vec, 0))
  32564. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), cadr(args), its_too_large_string));
  32565. return(make_shared_vector(sc, vec, 1, index * vector_offset(vec, 0)));
  32566. }
  32567. return(vector_getter(vec)(sc, vec, index));
  32568. }
  32569. static s7_pointer vector_ref_add1;
  32570. static s7_pointer g_vector_ref_add1(s7_scheme *sc, s7_pointer args)
  32571. {
  32572. /* (vector-ref v (+ s 1)) I think */
  32573. s7_pointer vec, x;
  32574. s7_int index;
  32575. vec = find_symbol_checked(sc, car(args));
  32576. x = find_symbol_checked(sc, cadr(cadr(args)));
  32577. if (!s7_is_integer(x))
  32578. method_or_bust(sc, x, sc->vector_ref_symbol, list_2(sc, vec, x), T_INTEGER, 2);
  32579. index = s7_integer(x) + 1;
  32580. if (!s7_is_vector(vec))
  32581. method_or_bust(sc, vec, sc->vector_ref_symbol, list_2(sc, vec, s7_make_integer(sc, index)), T_VECTOR, 1);
  32582. if ((index < 0) ||
  32583. (index >= vector_length(vec)))
  32584. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), cadr(args), (index < 0) ? its_negative_string : its_too_large_string));
  32585. if (vector_rank(vec) > 1)
  32586. {
  32587. if (index >= vector_dimension(vec, 0))
  32588. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), cadr(args), its_too_large_string));
  32589. return(make_shared_vector(sc, vec, 1, index * vector_offset(vec, 0)));
  32590. }
  32591. return(vector_getter(vec)(sc, vec, index));
  32592. }
  32593. static s7_pointer vector_ref_2, constant_vector_ref_gs;
  32594. static s7_pointer g_constant_vector_ref_gs(s7_scheme *sc, s7_pointer args)
  32595. {
  32596. s7_pointer x, vec;
  32597. s7_int index;
  32598. vec = opt_vector(args);
  32599. x = find_symbol_checked(sc, cadr(args));
  32600. if (!s7_is_integer(x))
  32601. return(g_vector_ref_gs(sc, args));
  32602. index = s7_integer(x);
  32603. if ((index < 0) ||
  32604. (index >= vector_length(vec)))
  32605. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), cadr(args), (index < 0) ? its_negative_string : its_too_large_string));
  32606. return(vector_element(vec, index));
  32607. }
  32608. static s7_pointer g_vector_ref_2(s7_scheme *sc, s7_pointer args)
  32609. {
  32610. s7_pointer vec, ind;
  32611. s7_int index;
  32612. vec = car(args);
  32613. if (!s7_is_vector(vec))
  32614. method_or_bust(sc, vec, sc->vector_ref_symbol, args, T_VECTOR, 1); /* should be ok because we go to g_vector_ref below */
  32615. if (vector_rank(vec) > 1)
  32616. return(g_vector_ref(sc, args));
  32617. ind = cadr(args);
  32618. if (!s7_is_integer(ind))
  32619. method_or_bust(sc, ind, sc->vector_ref_symbol, args, T_INTEGER, 2);
  32620. index = s7_integer(ind);
  32621. if ((index < 0) || (index >= vector_length(vec)))
  32622. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), ind, (index < 0) ? its_negative_string : its_too_large_string));
  32623. return(vector_getter(vec)(sc, vec, index));
  32624. }
  32625. static s7_pointer g_vector_set(s7_scheme *sc, s7_pointer args)
  32626. {
  32627. #define H_vector_set "(vector-set! v i ... value) sets the i-th element of vector v to value."
  32628. #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)
  32629. s7_pointer vec, val;
  32630. s7_int index;
  32631. vec = car(args);
  32632. if (!s7_is_vector(vec))
  32633. method_or_bust(sc, vec, sc->vector_set_symbol, args, T_VECTOR, 1);
  32634. if (vector_length(_TSet(vec)) == 0)
  32635. return(out_of_range(sc, sc->vector_set_symbol, small_int(1), vec, its_too_large_string));
  32636. if (vector_rank(vec) > 1)
  32637. {
  32638. unsigned int i;
  32639. s7_pointer x;
  32640. index = 0;
  32641. for (x = cdr(args), i = 0; (is_not_null(cdr(x))) && (i < vector_ndims(vec)); x = cdr(x), i++)
  32642. {
  32643. s7_int n;
  32644. s7_pointer p, p1;
  32645. p = car(x);
  32646. if (!s7_is_integer(p))
  32647. {
  32648. if (!s7_is_integer(p1 = check_values(sc, p, x)))
  32649. method_or_bust(sc, p, sc->vector_set_symbol, args, T_INTEGER, i + 2);
  32650. p = p1;
  32651. }
  32652. n = s7_integer(p);
  32653. if ((n < 0) ||
  32654. (n >= vector_dimension(vec, i)))
  32655. return(out_of_range(sc, sc->vector_set_symbol, make_integer(sc, i + 2), p, (n < 0) ? its_negative_string : its_too_large_string));
  32656. index += n * vector_offset(vec, i);
  32657. }
  32658. if (is_not_null(cdr(x)))
  32659. return(s7_wrong_number_of_args_error(sc, "too many args for vector-set!: ~S", args));
  32660. if (i != vector_ndims(vec))
  32661. return(s7_wrong_number_of_args_error(sc, "not enough args for vector-set!: ~S", args));
  32662. val = car(x);
  32663. }
  32664. else
  32665. {
  32666. s7_pointer p, p1;
  32667. p = cadr(args);
  32668. if (!s7_is_integer(p))
  32669. {
  32670. if (!s7_is_integer(p1 = check_values(sc, p, cdr(args))))
  32671. method_or_bust(sc, p, sc->vector_set_symbol, args, T_INTEGER, 2);
  32672. p = p1;
  32673. }
  32674. index = s7_integer(p);
  32675. if ((index < 0) ||
  32676. (index >= vector_length(vec)))
  32677. return(out_of_range(sc, sc->vector_set_symbol, small_int(2), p, (index < 0) ? its_negative_string : its_too_large_string));
  32678. if (is_not_null(cdddr(args)))
  32679. {
  32680. set_car(sc->temp_cell_2, vector_getter(vec)(sc, vec, index));
  32681. set_cdr(sc->temp_cell_2, cddr(args));
  32682. return(g_vector_set(sc, sc->temp_cell_2));
  32683. }
  32684. val = caddr(args);
  32685. }
  32686. vector_setter(vec)(sc, vec, index, val);
  32687. return(val);
  32688. }
  32689. static s7_pointer vector_set_ic;
  32690. static s7_pointer g_vector_set_ic(s7_scheme *sc, s7_pointer args)
  32691. {
  32692. /* (vector-set! vec 0 x) */
  32693. s7_pointer vec, val;
  32694. s7_int index;
  32695. vec = find_symbol_checked(sc, car(args));
  32696. if (!s7_is_vector(vec))
  32697. method_or_bust(sc, vec, sc->vector_set_symbol, list_3(sc, vec, cadr(args), find_symbol_checked(sc, caddr(args))), T_VECTOR, 1);
  32698. /* the list_3 happens only if we find the method */
  32699. if (vector_rank(vec) > 1)
  32700. return(g_vector_set(sc, set_plist_3(sc, vec, cadr(args), find_symbol_checked(sc, caddr(args)))));
  32701. index = s7_integer(cadr(args));
  32702. if (index >= vector_length(vec))
  32703. return(out_of_range(sc, sc->vector_set_symbol, small_int(2), cadr(args), its_too_large_string));
  32704. val = find_symbol_checked(sc, caddr(args));
  32705. vector_setter(vec)(sc, vec, index, val);
  32706. return(val);
  32707. }
  32708. static s7_pointer vector_set_vref;
  32709. static s7_pointer g_vector_set_vref(s7_scheme *sc, s7_pointer args)
  32710. {
  32711. /* (vector-set! vec i (vector-ref vec j)) -- checked that the vector is the same */
  32712. s7_pointer vec, val1, val2;
  32713. s7_int index1, index2;
  32714. vec = find_symbol_checked(sc, car(args));
  32715. val1 = find_symbol_checked(sc, cadr(args));
  32716. val2 = find_symbol_checked(sc, caddr(caddr(args)));
  32717. if ((!s7_is_vector(vec)) ||
  32718. (vector_rank(vec) > 1) ||
  32719. (!s7_is_integer(val1)) ||
  32720. (!s7_is_integer(val2)))
  32721. return(g_vector_set(sc, set_plist_3(sc, vec, val1, g_vector_ref(sc, set_plist_2(sc, vec, val2)))));
  32722. index1 = s7_integer(val1);
  32723. if (index1 >= vector_length(vec))
  32724. return(out_of_range(sc, sc->vector_set_symbol, small_int(2), val1, its_too_large_string));
  32725. index2 = s7_integer(val2);
  32726. if (index2 >= vector_length(vec))
  32727. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), val2, its_too_large_string));
  32728. vector_setter(vec)(sc, vec, index1, val1 = vector_getter(vec)(sc, vec, index2));
  32729. return(val1);
  32730. }
  32731. static s7_pointer vector_set_vector_ref;
  32732. static s7_pointer g_vector_set_vector_ref(s7_scheme *sc, s7_pointer args)
  32733. {
  32734. /* (vector-set! data i|j (+|- (vector-ref data i) tc)) */
  32735. s7_pointer vec, val, val2, tc, arg3;
  32736. s7_int index1, index2;
  32737. vec = find_symbol_checked(sc, car(args));
  32738. val = find_symbol_checked(sc, cadr(args));
  32739. arg3 = caddr(args);
  32740. tc = find_symbol_checked(sc, caddr(arg3));
  32741. val2 = caddr(cadr(arg3));
  32742. if ((!s7_is_vector(vec)) ||
  32743. (vector_rank(vec) > 1) ||
  32744. (!s7_is_integer(val)))
  32745. return(g_vector_set(sc, set_plist_3(sc, vec, val, c_call(arg3)(sc, list_2(sc, g_vector_ref(sc, set_plist_2(sc, vec, find_symbol_checked(sc, val2))), tc)))));
  32746. index1 = s7_integer(val);
  32747. if (index1 >= vector_length(vec))
  32748. return(out_of_range(sc, sc->vector_set_symbol, small_int(2), val, its_too_large_string));
  32749. if (val2 != cadr(args))
  32750. {
  32751. val2 = find_symbol_checked(sc, val2);
  32752. if (!s7_is_integer(val2))
  32753. {
  32754. s7_pointer p;
  32755. if (!s7_is_integer(p = check_values(sc, val2, list_1(sc, val2))))
  32756. return(wrong_type_argument(sc, sc->vector_ref_symbol, 2, val2, T_INTEGER));
  32757. else val2 = p;
  32758. }
  32759. index2 = s7_integer(val2);
  32760. if (index2 >= vector_length(vec))
  32761. return(out_of_range(sc, sc->vector_ref_symbol, small_int(2), val, its_too_large_string));
  32762. }
  32763. else index2 = index1;
  32764. set_car(sc->z2_1, vector_getter(vec)(sc, vec, index2));
  32765. set_car(sc->z2_2, tc);
  32766. vector_setter(vec)(sc, vec, index1, tc = c_call(arg3)(sc, sc->z2_1));
  32767. return(tc);
  32768. }
  32769. static s7_pointer c_vector_set_3(s7_scheme *sc, s7_pointer vec, s7_int index, s7_pointer val)
  32770. {
  32771. /* (vector-set! vec ind val) where are all predigested */
  32772. if (!s7_is_vector(vec))
  32773. method_or_bust(sc, vec, sc->vector_set_symbol, list_3(sc, vec, make_integer(sc, index), val), T_VECTOR, 1);
  32774. if (vector_rank(vec) > 1)
  32775. return(g_vector_set(sc, list_3(sc, vec, make_integer(sc, index), val)));
  32776. if ((index < 0) ||
  32777. (index >= vector_length(vec)))
  32778. return(out_of_range(sc, sc->vector_set_symbol, small_int(2), make_integer(sc, index), (index < 0) ? its_negative_string : its_too_large_string));
  32779. vector_setter(vec)(sc, vec, index, val);
  32780. return(val);
  32781. }
  32782. static s7_pointer c_vector_set_s(s7_scheme *sc, s7_pointer vec, s7_int index, s7_pointer val)
  32783. {
  32784. /* (vector-set! vec ind val) where are all predigested, vector is prechecked */
  32785. if ((index < 0) ||
  32786. (index >= vector_length(vec)))
  32787. return(out_of_range(sc, sc->vector_set_symbol, small_int(2), make_integer(sc, index), (index < 0) ? its_negative_string : its_too_large_string));
  32788. vector_elements(vec)[index] = val;
  32789. return(val);
  32790. }
  32791. static s7_pointer vector_set_3;
  32792. static s7_pointer g_vector_set_3(s7_scheme *sc, s7_pointer args)
  32793. {
  32794. s7_pointer ind;
  32795. ind = cadr(args);
  32796. if (!s7_is_integer(ind))
  32797. {
  32798. s7_pointer p;
  32799. if (!s7_is_integer(p = check_values(sc, ind, cdr(args))))
  32800. return(wrong_type_argument(sc, sc->vector_set_symbol, 2, ind, T_INTEGER));
  32801. else ind = p;
  32802. }
  32803. return(c_vector_set_3(sc, car(args), s7_integer(ind), caddr(args)));
  32804. }
  32805. PIPF_TO_PF(vector_set, c_vector_set_s, c_vector_set_3, c_vector_tester)
  32806. static s7_pointer g_make_vector(s7_scheme *sc, s7_pointer args)
  32807. {
  32808. #define H_make_vector "(make-vector len (value #<unspecified>)) returns a vector of len elements initialized to value. \
  32809. To create a multidimensional vector, put the dimension bounds in a list (this is to avoid ambiguities such as \
  32810. (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) \
  32811. returns a 2 dimensional vector of 6 total elements, all initialized to 1.0."
  32812. #define Q_make_vector s7_make_signature(sc, 3, sc->is_vector_symbol, s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_pair_symbol), sc->T)
  32813. s7_int len;
  32814. s7_pointer x, fill, vec;
  32815. int result_type = T_VECTOR;
  32816. fill = sc->unspecified;
  32817. x = car(args);
  32818. if (s7_is_integer(x))
  32819. {
  32820. len = s7_integer(x);
  32821. if (len < 0)
  32822. return(wrong_type_argument_with_type(sc, sc->make_vector_symbol, 1, x, a_non_negative_integer_string));
  32823. }
  32824. else
  32825. {
  32826. if (!(is_pair(x)))
  32827. method_or_bust_with_type(sc, x, sc->make_vector_symbol, args, make_string_wrapper(sc, "an integer or a list of integers"), 1);
  32828. if (!s7_is_integer(car(x)))
  32829. return(wrong_type_argument_with_type(sc, sc->make_vector_symbol, 1, car(x),
  32830. make_string_wrapper(sc, "each dimension should be an integer")));
  32831. if (is_null(cdr(x)))
  32832. len = s7_integer(car(x));
  32833. else
  32834. {
  32835. int dims;
  32836. s7_pointer y;
  32837. dims = s7_list_length(sc, x);
  32838. if (dims <= 0) /* 0 if circular, negative if dotted */
  32839. return(wrong_type_argument_with_type(sc, sc->make_vector_symbol, 1, x, a_proper_list_string));
  32840. if (dims > sc->max_vector_dimensions)
  32841. return(out_of_range(sc, sc->make_vector_symbol, small_int(1), x, its_too_large_string));
  32842. for (len = 1, y = x; is_not_null(y); y = cdr(y))
  32843. {
  32844. if (!s7_is_integer(car(y)))
  32845. return(wrong_type_argument(sc, sc->make_vector_symbol, position_of(y, x), car(y), T_INTEGER));
  32846. len *= s7_integer(car(y));
  32847. if (len < 0)
  32848. return(wrong_type_argument_with_type(sc, sc->make_vector_symbol, position_of(y, x), car(y), a_non_negative_integer_string));
  32849. }
  32850. }
  32851. }
  32852. if (is_not_null(cdr(args)))
  32853. {
  32854. fill = cadr(args);
  32855. if (is_not_null(cddr(args)))
  32856. {
  32857. if (caddr(args) == sc->T)
  32858. {
  32859. /* here bignums can cause confusion, so use is_integer not s7_is_integer etc */
  32860. if (is_integer(fill))
  32861. result_type = T_INT_VECTOR;
  32862. else
  32863. {
  32864. if (s7_is_real(fill)) /* might be gmp with big_real by accident (? see above) */
  32865. result_type = T_FLOAT_VECTOR;
  32866. else method_or_bust_with_type(sc, fill, sc->make_vector_symbol, args, make_string_wrapper(sc, "an integer or a real since 'homogeneous' is #t"), 2);
  32867. }
  32868. }
  32869. else
  32870. {
  32871. if (caddr(args) != sc->F)
  32872. method_or_bust_with_type(sc, caddr(args), sc->make_vector_symbol, args, a_boolean_string, 3);
  32873. }
  32874. }
  32875. }
  32876. vec = make_vector_1(sc, len, NOT_FILLED, result_type);
  32877. if (len > 0) s7_vector_fill(sc, vec, fill);
  32878. if ((is_pair(x)) &&
  32879. (is_pair(cdr(x))))
  32880. {
  32881. int i;
  32882. s7_int offset = 1;
  32883. s7_pointer y;
  32884. vdims_t *v;
  32885. v = (vdims_t *)malloc(sizeof(vdims_t));
  32886. v->ndims = safe_list_length(sc, x);
  32887. v->dims = (s7_int *)malloc(v->ndims * sizeof(s7_int));
  32888. v->offsets = (s7_int *)malloc(v->ndims * sizeof(s7_int));
  32889. v->original = sc->F;
  32890. v->dimensions_allocated = true;
  32891. v->elements_allocated = (len > 0);
  32892. for (i = 0, y = x; is_not_null(y); i++, y = cdr(y))
  32893. v->dims[i] = s7_integer(car(y));
  32894. for (i = v->ndims - 1; i >= 0; i--)
  32895. {
  32896. v->offsets[i] = offset;
  32897. offset *= v->dims[i];
  32898. }
  32899. vector_dimension_info(vec) = v;
  32900. }
  32901. return(vec);
  32902. }
  32903. IF_TO_PF(make_vector, s7_make_vector)
  32904. static s7_pointer g_make_float_vector(s7_scheme *sc, s7_pointer args)
  32905. {
  32906. #define H_make_float_vector "(make-float-vector len (init 0.0)) returns a float-vector."
  32907. #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)
  32908. s7_int len;
  32909. s7_pointer x, p;
  32910. s7_double *arr;
  32911. p = car(args);
  32912. if ((is_pair(cdr(args))) ||
  32913. (!is_integer(p)))
  32914. {
  32915. s7_pointer init;
  32916. if (is_pair(cdr(args)))
  32917. {
  32918. init = cadr(args);
  32919. if (!s7_is_real(init))
  32920. method_or_bust(sc, init, sc->make_float_vector_symbol, args, T_REAL, 2);
  32921. #if WITH_GMP
  32922. if (s7_is_bignum(init))
  32923. return(g_make_vector(sc, set_plist_3(sc, p, make_real(sc, real_to_double(sc, init, "make-float-vector")), sc->T)));
  32924. #endif
  32925. if (is_rational(init))
  32926. return(g_make_vector(sc, set_plist_3(sc, p, make_real(sc, rational_to_double(sc, init)), sc->T)));
  32927. }
  32928. else init = real_zero;
  32929. return(g_make_vector(sc, set_plist_3(sc, p, init, sc->T)));
  32930. }
  32931. len = s7_integer(p);
  32932. if (len < 0)
  32933. return(wrong_type_argument_with_type(sc, sc->make_float_vector_symbol, 1, p, a_non_negative_integer_string));
  32934. if (len > sc->max_vector_length)
  32935. return(out_of_range(sc, sc->make_float_vector_symbol, small_int(1), p, its_too_large_string));
  32936. if (len > 0)
  32937. arr = (s7_double *)calloc(len, sizeof(s7_double));
  32938. else arr = NULL;
  32939. new_cell(sc, x, T_FLOAT_VECTOR | T_SAFE_PROCEDURE);
  32940. vector_length(x) = len;
  32941. float_vector_elements(x) = arr;
  32942. vector_dimension_info(x) = NULL;
  32943. vector_getter(x) = float_vector_getter;
  32944. vector_setter(x) = float_vector_setter;
  32945. add_vector(sc, x);
  32946. return(x);
  32947. }
  32948. static s7_pointer c_make_float_vector(s7_scheme *sc, s7_int len) {return(s7_make_float_vector(sc, len, 1, NULL));}
  32949. IF_TO_PF(make_float_vector, c_make_float_vector)
  32950. static s7_pointer g_make_int_vector(s7_scheme *sc, s7_pointer args)
  32951. {
  32952. #define H_make_int_vector "(make-int-vector len (init 0.0)) returns an int-vector."
  32953. #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)
  32954. s7_int len;
  32955. s7_pointer x, p;
  32956. s7_int *arr;
  32957. p = car(args);
  32958. if ((is_pair(cdr(args))) ||
  32959. (!is_integer(p)))
  32960. {
  32961. s7_pointer init;
  32962. if (is_pair(cdr(args)))
  32963. {
  32964. init = cadr(args);
  32965. if (!is_integer(init))
  32966. method_or_bust(sc, init, sc->make_int_vector_symbol, args, T_INTEGER, 2);
  32967. }
  32968. else init = small_int(0);
  32969. return(g_make_vector(sc, set_plist_3(sc, p, init, sc->T)));
  32970. }
  32971. len = s7_integer(p);
  32972. if (len < 0)
  32973. return(wrong_type_argument_with_type(sc, sc->make_int_vector_symbol, 1, p, a_non_negative_integer_string));
  32974. if (len > sc->max_vector_length)
  32975. return(out_of_range(sc, sc->make_int_vector_symbol, small_int(1), p, its_too_large_string));
  32976. if (len > 0)
  32977. arr = (s7_int *)calloc(len, sizeof(s7_int));
  32978. else arr = NULL;
  32979. new_cell(sc, x, T_INT_VECTOR | T_SAFE_PROCEDURE);
  32980. vector_length(x) = len;
  32981. int_vector_elements(x) = arr;
  32982. vector_dimension_info(x) = NULL;
  32983. vector_getter(x) = int_vector_getter;
  32984. vector_setter(x) = int_vector_setter;
  32985. add_vector(sc, x);
  32986. return(x);
  32987. }
  32988. static s7_pointer c_make_int_vector(s7_scheme *sc, s7_int len) {return(s7_make_int_vector(sc, len, 1, NULL));}
  32989. IF_TO_PF(make_int_vector, c_make_int_vector)
  32990. static s7_pointer g_is_vector(s7_scheme *sc, s7_pointer args)
  32991. {
  32992. #define H_is_vector "(vector? obj) returns #t if obj is a vector"
  32993. #define Q_is_vector pl_bt
  32994. check_boolean_method(sc, s7_is_vector, sc->is_vector_symbol, args);
  32995. }
  32996. int s7_vector_rank(s7_pointer vect)
  32997. {
  32998. return(vector_rank(vect));
  32999. }
  33000. static s7_pointer g_vector_dimensions(s7_scheme *sc, s7_pointer args)
  33001. {
  33002. #define H_vector_dimensions "(vector-dimensions vect) returns a list of vect's dimensions. In srfi-63 terms:\n\
  33003. (define array-dimensions vector-dimensions)\n\
  33004. (define (array-rank v) (length (vector-dimensions v)))"
  33005. #define Q_vector_dimensions s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_vector_symbol)
  33006. s7_pointer x;
  33007. x = car(args);
  33008. if (!s7_is_vector(x))
  33009. method_or_bust(sc, x, sc->vector_dimensions_symbol, args, T_VECTOR, 0);
  33010. if (vector_rank(x) > 1)
  33011. {
  33012. int i;
  33013. sc->w = sc->nil;
  33014. for (i = vector_ndims(x) - 1; i >= 0; i--)
  33015. sc->w = cons(sc, make_integer(sc, vector_dimension(x, i)), sc->w);
  33016. x = sc->w;
  33017. sc->w = sc->nil;
  33018. return(x);
  33019. }
  33020. return(list_1(sc, make_integer(sc, vector_length(x))));
  33021. }
  33022. static s7_pointer c_vector_dimensions(s7_scheme *sc, s7_pointer x) {return(g_vector_dimensions(sc, set_plist_1(sc, x)));}
  33023. PF_TO_PF(vector_dimensions, c_vector_dimensions)
  33024. #define MULTIVECTOR_TOO_MANY_ELEMENTS -1
  33025. #define MULTIVECTOR_NOT_ENOUGH_ELEMENTS -2
  33026. static int traverse_vector_data(s7_scheme *sc, s7_pointer vec, int flat_ref, int dimension, int dimensions, int *sizes, s7_pointer lst)
  33027. {
  33028. /* we're filling vec, we're currently looking for element (flat-wise) flat_ref,
  33029. * we're at ref in dimension of dimensions, where sizes gives the bounds, and lst is our data
  33030. * #3D(((1 2 3) (4 5 6)) ((7 8 9) (10 11 12)))
  33031. */
  33032. int i;
  33033. s7_pointer x;
  33034. for (i = 0, x = lst; i < sizes[dimension]; i++, x = cdr(x))
  33035. {
  33036. if (!is_pair(x))
  33037. return(MULTIVECTOR_NOT_ENOUGH_ELEMENTS);
  33038. if (dimension == (dimensions - 1))
  33039. vector_setter(vec)(sc, vec, flat_ref++, car(x));
  33040. else
  33041. {
  33042. flat_ref = traverse_vector_data(sc, vec, flat_ref, dimension + 1, dimensions, sizes, car(x));
  33043. if (flat_ref < 0) return(flat_ref);
  33044. }
  33045. }
  33046. if (is_not_null(x))
  33047. return(MULTIVECTOR_TOO_MANY_ELEMENTS);
  33048. return(flat_ref);
  33049. }
  33050. static s7_pointer s7_multivector_error(s7_scheme *sc, const char *message, s7_pointer data)
  33051. {
  33052. return(s7_error(sc, sc->read_error_symbol,
  33053. set_elist_3(sc, make_string_wrapper(sc, "reading constant vector, ~A: ~A"), make_string_wrapper(sc, message), data)));
  33054. }
  33055. static s7_pointer g_multivector(s7_scheme *sc, s7_int dims, s7_pointer data)
  33056. {
  33057. /* get the dimension bounds from data, make the new vector, fill it from data
  33058. *
  33059. * dims needs to be s7_int so we can at least give correct error messages.
  33060. * also should we let an empty vector have any number of dimensions? currently ndims is an int.
  33061. */
  33062. s7_pointer vec, x;
  33063. int i, vec_loc, err;
  33064. int *sizes;
  33065. /* (#2d((1 2 3) (4 5 6)) 0 0) -> 1
  33066. * (#2d((1 2 3) (4 5 6)) 0 1) -> 2
  33067. * (#2d((1 2 3) (4 5 6)) 1 1) -> 5
  33068. * (#3D(((1 2) (3 4)) ((5 6) (7 8))) 0 0 0) -> 1
  33069. * (#3D(((1 2) (3 4)) ((5 6) (7 8))) 1 1 0) -> 7
  33070. * #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
  33071. *
  33072. * but a special case: #nD() is an n-dimensional empty vector
  33073. */
  33074. if (dims <= 0) /* #0d(...) #2147483649D() [if dims is int this is negative] */
  33075. return(s7_out_of_range_error(sc, "#nD(...) dimensions", 1, make_integer(sc, dims), "must be 1 or more"));
  33076. if (dims > sc->max_vector_dimensions)
  33077. return(s7_out_of_range_error(sc, "#nD(...) dimensions", 1, make_integer(sc, dims), "must be < 512")); /* sc->max_vector_dimensions=512 currently */
  33078. sc->w = sc->nil;
  33079. if (is_null(data)) /* dims are already 0 (calloc above) */
  33080. return(g_make_vector(sc, set_plist_1(sc, make_list(sc, dims, small_int(0)))));
  33081. sizes = (int *)calloc(dims, sizeof(int));
  33082. for (x = data, i = 0; i < dims; i++)
  33083. {
  33084. sizes[i] = safe_list_length(sc, x);
  33085. sc->w = cons(sc, make_integer(sc, sizes[i]), sc->w);
  33086. x = car(x);
  33087. if ((i < (dims - 1)) &&
  33088. (!is_pair(x)))
  33089. {
  33090. free(sizes);
  33091. return(s7_multivector_error(sc, "we need a list that fully specifies the vector's elements", data));
  33092. }
  33093. }
  33094. vec = g_make_vector(sc, set_plist_1(sc, sc->w = safe_reverse_in_place(sc, sc->w)));
  33095. vec_loc = s7_gc_protect(sc, vec);
  33096. sc->w = sc->nil;
  33097. /* now fill the vector checking that all the lists match */
  33098. err = traverse_vector_data(sc, vec, 0, 0, dims, sizes, data);
  33099. free(sizes);
  33100. s7_gc_unprotect_at(sc, vec_loc);
  33101. if (err < 0)
  33102. return(s7_multivector_error(sc, (err == MULTIVECTOR_TOO_MANY_ELEMENTS) ? "found too many elements" : "not enough elements found", data));
  33103. return(vec);
  33104. }
  33105. s7_pointer s7_vector_copy(s7_scheme *sc, s7_pointer old_vect)
  33106. {
  33107. s7_int len;
  33108. s7_pointer new_vect;
  33109. len = vector_length(old_vect);
  33110. if (is_float_vector(old_vect))
  33111. {
  33112. if (vector_rank(old_vect) > 1)
  33113. new_vect = g_make_vector(sc, set_plist_3(sc, g_vector_dimensions(sc, set_plist_1(sc, old_vect)), real_zero, sc->T));
  33114. else new_vect = make_vector_1(sc, len, NOT_FILLED, T_FLOAT_VECTOR);
  33115. if (len > 0)
  33116. memcpy((void *)(float_vector_elements(new_vect)), (void *)(float_vector_elements(old_vect)), len * sizeof(s7_double));
  33117. }
  33118. else
  33119. {
  33120. if (is_int_vector(old_vect))
  33121. {
  33122. if (vector_rank(old_vect) > 1)
  33123. new_vect = g_make_vector(sc, set_plist_3(sc, g_vector_dimensions(sc, set_plist_1(sc, old_vect)), small_int(0), sc->T));
  33124. else new_vect = make_vector_1(sc, len, NOT_FILLED, T_INT_VECTOR);
  33125. if (len > 0)
  33126. memcpy((void *)(int_vector_elements(new_vect)), (void *)(int_vector_elements(old_vect)), len * sizeof(s7_int));
  33127. }
  33128. else
  33129. {
  33130. if (vector_rank(old_vect) > 1)
  33131. new_vect = g_make_vector(sc, set_plist_1(sc, g_vector_dimensions(sc, list_1(sc, old_vect))));
  33132. else new_vect = make_vector_1(sc, len, NOT_FILLED, T_VECTOR);
  33133. /* here and in vector-fill! we have a problem with bignums -- should new bignums be allocated? (copy_list also) */
  33134. if (len > 0)
  33135. memcpy((void *)(vector_elements(new_vect)), (void *)(vector_elements(old_vect)), len * sizeof(s7_pointer));
  33136. }
  33137. }
  33138. return(new_vect);
  33139. }
  33140. static s7_pointer univect_ref(s7_scheme *sc, s7_pointer args, bool flt)
  33141. {
  33142. s7_pointer v, caller;
  33143. s7_int ind;
  33144. int typ;
  33145. caller = (flt) ? sc->float_vector_ref_symbol : sc->int_vector_ref_symbol;
  33146. typ = (flt) ? T_FLOAT_VECTOR : T_INT_VECTOR;
  33147. v = car(args);
  33148. if (type(v) != typ)
  33149. method_or_bust(sc, v, caller, args, typ, 1);
  33150. if (vector_rank(v) == 1)
  33151. {
  33152. s7_pointer index;
  33153. index = cadr(args);
  33154. if (!s7_is_integer(index))
  33155. {
  33156. s7_pointer p;
  33157. if (!s7_is_integer(p = check_values(sc, index, cdr(args))))
  33158. return(wrong_type_argument(sc, caller, 2, index, T_INTEGER));
  33159. else index = p;
  33160. }
  33161. ind = s7_integer(index);
  33162. if ((ind < 0) || (ind >= vector_length(v)))
  33163. return(simple_out_of_range(sc, caller, index, (ind < 0) ? its_negative_string : its_too_large_string));
  33164. if (!is_null(cddr(args)))
  33165. return(out_of_range(sc, caller, small_int(2), cdr(args), too_many_indices_string));
  33166. }
  33167. else
  33168. {
  33169. unsigned int i;
  33170. s7_pointer x;
  33171. ind = 0;
  33172. for (x = cdr(args), i = 0; (is_not_null(x)) && (i < vector_ndims(v)); x = cdr(x), i++)
  33173. {
  33174. s7_int n;
  33175. if (!s7_is_integer(car(x)))
  33176. {
  33177. s7_pointer p;
  33178. if (!s7_is_integer(p = check_values(sc, car(x), x)))
  33179. return(wrong_type_argument(sc, caller, i + 2, car(x), T_INTEGER));
  33180. n = s7_integer(p);
  33181. }
  33182. else n = s7_integer(car(x));
  33183. if ((n < 0) ||
  33184. (n >= vector_dimension(v, i)))
  33185. return(out_of_range(sc, caller, make_integer(sc, i + 2), car(x), (n < 0) ? its_negative_string : its_too_large_string));
  33186. ind += n * vector_offset(v, i);
  33187. }
  33188. if (is_not_null(x))
  33189. return(out_of_range(sc, caller, small_int(2), cdr(args), too_many_indices_string));
  33190. /* if not enough indices, return a shared vector covering whatever is left */
  33191. if (i < vector_ndims(v))
  33192. return(make_shared_vector(sc, v, i, ind));
  33193. }
  33194. if (flt)
  33195. return(make_real(sc, float_vector_element(v, ind)));
  33196. return(make_integer(sc, int_vector_element(v, ind)));
  33197. }
  33198. static s7_pointer univect_set(s7_scheme *sc, s7_pointer args, bool flt)
  33199. {
  33200. s7_pointer vec, val, caller;
  33201. s7_int index;
  33202. int typ;
  33203. caller = (flt) ? sc->float_vector_set_symbol : sc->int_vector_set_symbol;
  33204. typ = (flt) ? T_FLOAT_VECTOR : T_INT_VECTOR;
  33205. vec = car(args);
  33206. if (type(vec) != typ)
  33207. method_or_bust(sc, vec, caller, args, typ, 1);
  33208. if (vector_rank(vec) > 1)
  33209. {
  33210. unsigned int i;
  33211. s7_pointer x;
  33212. index = 0;
  33213. for (x = cdr(args), i = 0; (is_not_null(cdr(x))) && (i < vector_ndims(vec)); x = cdr(x), i++)
  33214. {
  33215. s7_int n;
  33216. if (!s7_is_integer(car(x)))
  33217. {
  33218. s7_pointer p;
  33219. if (!s7_is_integer(p = check_values(sc, car(x), x)))
  33220. method_or_bust(sc, car(x), caller, args, T_INTEGER, i + 2);
  33221. n = s7_integer(p);
  33222. }
  33223. else n = s7_integer(car(x));
  33224. if ((n < 0) ||
  33225. (n >= vector_dimension(vec, i)))
  33226. return(out_of_range(sc, caller, make_integer(sc, i + 2), car(x), (n < 0) ? its_negative_string : its_too_large_string));
  33227. index += n * vector_offset(vec, i);
  33228. }
  33229. if (is_not_null(cdr(x)))
  33230. return(s7_wrong_number_of_args_error(sc, "too many args: ~S", args));
  33231. if (i != vector_ndims(vec))
  33232. return(s7_wrong_number_of_args_error(sc, "not enough args: ~S", args));
  33233. val = car(x);
  33234. }
  33235. else
  33236. {
  33237. if (!s7_is_integer(cadr(args)))
  33238. {
  33239. s7_pointer p;
  33240. if (!s7_is_integer(p = check_values(sc, cadr(args), cdr(args))))
  33241. method_or_bust(sc, cadr(args), caller, args, T_INTEGER, 2);
  33242. index = s7_integer(p);
  33243. }
  33244. else index = s7_integer(cadr(args));
  33245. if ((index < 0) ||
  33246. (index >= vector_length(vec)))
  33247. return(out_of_range(sc, caller, small_int(2), cadr(args), (index < 0) ? its_negative_string : its_too_large_string));
  33248. if (is_not_null(cdddr(args)))
  33249. return(s7_wrong_number_of_args_error(sc, "too many args: ~S", args));
  33250. val = caddr(args);
  33251. }
  33252. if (flt)
  33253. {
  33254. if (!s7_is_real(val))
  33255. method_or_bust(sc, val, caller, args, T_REAL, 3);
  33256. float_vector_element(vec, index) = real_to_double(sc, val, "float-vector-set!");
  33257. /* currently this accepts a complex value and assigns real_part(val) to the float-vector -- maybe an error instead? */
  33258. }
  33259. else
  33260. {
  33261. if (!s7_is_integer(val))
  33262. method_or_bust(sc, val, caller, args, T_INTEGER, 3);
  33263. int_vector_element(vec, index) = s7_integer(val);
  33264. }
  33265. return(val);
  33266. }
  33267. static s7_pointer g_float_vector_ref(s7_scheme *sc, s7_pointer args)
  33268. {
  33269. #define H_float_vector_ref "(float-vector-ref v ...) returns an element of the float-vector v."
  33270. #define Q_float_vector_ref s7_make_circular_signature(sc, 2, 3, sc->is_float_symbol, sc->is_float_vector_symbol, sc->is_integer_symbol)
  33271. return(univect_ref(sc, args, true));
  33272. }
  33273. static s7_pointer g_float_vector_set(s7_scheme *sc, s7_pointer args)
  33274. {
  33275. #define H_float_vector_set "(float-vector-set! v i ... value) sets the i-th element of the float-vector v to value."
  33276. #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)
  33277. return(univect_set(sc, args, true));
  33278. }
  33279. static s7_pointer g_int_vector_ref(s7_scheme *sc, s7_pointer args)
  33280. {
  33281. #define H_int_vector_ref "(int-vector-ref v ...) returns an element of the int-vector v."
  33282. #define Q_int_vector_ref s7_make_circular_signature(sc, 2, 3, sc->is_integer_symbol, sc->is_int_vector_symbol, sc->is_integer_symbol)
  33283. return(univect_ref(sc, args, false));
  33284. }
  33285. static s7_pointer g_int_vector_set(s7_scheme *sc, s7_pointer args)
  33286. {
  33287. #define H_int_vector_set "(int-vector-set! v i ... value) sets the i-th element of the int-vector v to value."
  33288. #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)
  33289. return(univect_set(sc, args, false));
  33290. }
  33291. /* int-vector-ref|set optimizers */
  33292. static s7_int int_vector_ref_if_a(s7_scheme *sc, s7_pointer **p)
  33293. {
  33294. s7_if_t xf;
  33295. s7_pointer x;
  33296. s7_int y;
  33297. x = (**p); (*p)++;
  33298. if (!is_int_vector(x))
  33299. wrong_type_argument(sc, sc->int_vector_ref_symbol, 1, x, T_INT_VECTOR);
  33300. xf = (s7_if_t)(**p); (*p)++;
  33301. y = xf(sc, p);
  33302. if ((y < 0) || (y >= vector_length(x)))
  33303. out_of_range(sc, sc->int_vector_ref_symbol, small_int(2), make_integer(sc, y), (y < 0) ? its_negative_string : its_too_large_string);
  33304. return(int_vector_elements(x)[y]);
  33305. }
  33306. static s7_if_t int_vector_ref_if_expanded(s7_scheme *sc, s7_pointer iv, s7_pointer ind_expr)
  33307. {
  33308. s7_xf_store(sc, iv);
  33309. if (s7_arg_to_if(sc, ind_expr))
  33310. return(int_vector_ref_if_a);
  33311. return(NULL);
  33312. }
  33313. static s7_if_t int_vector_ref_if(s7_scheme *sc, s7_pointer expr)
  33314. {
  33315. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_null(cdddr(expr))))
  33316. {
  33317. s7_pointer iv;
  33318. iv = cadr(expr);
  33319. if (!is_symbol(iv)) return(NULL);
  33320. iv = s7_slot(sc, iv);
  33321. if (!is_slot(iv)) return(NULL);
  33322. if (!is_int_vector(slot_value(iv))) return(NULL);
  33323. return(int_vector_ref_if_expanded(sc, slot_value(iv), caddr(expr)));
  33324. }
  33325. return(NULL);
  33326. }
  33327. static s7_if_t implicit_int_vector_ref(s7_scheme *sc, s7_pointer expr)
  33328. {
  33329. if ((is_null(cdr(expr))) || (!is_null(cddr(expr)))) return(NULL);
  33330. return(int_vector_ref_if_expanded(sc, s7_symbol_value(sc, car(expr)), cadr(expr)));
  33331. }
  33332. static s7_int int_vector_set_if_a(s7_scheme *sc, s7_pointer **p)
  33333. {
  33334. s7_if_t xf;
  33335. s7_pointer x;
  33336. s7_int y, z;
  33337. x = (**p); (*p)++;
  33338. if (!is_int_vector(x))
  33339. wrong_type_argument(sc, sc->int_vector_set_symbol, 1, x, T_INT_VECTOR);
  33340. xf = (s7_if_t)(**p); (*p)++;
  33341. y = xf(sc, p);
  33342. if ((y < 0) || (y >= vector_length(x)))
  33343. out_of_range(sc, sc->int_vector_set_symbol, small_int(2), make_integer(sc, y), (y < 0) ? its_negative_string : its_too_large_string);
  33344. xf = (s7_if_t)(**p); (*p)++;
  33345. z = xf(sc, p);
  33346. int_vector_elements(x)[y] = z;
  33347. return(z);
  33348. }
  33349. static s7_if_t int_vector_set_if_expanded(s7_scheme *sc, s7_pointer iv, s7_pointer ind_sym, s7_pointer val_expr)
  33350. {
  33351. s7_xf_store(sc, iv);
  33352. if ((s7_arg_to_if(sc, ind_sym)) &&
  33353. (s7_arg_to_if(sc, val_expr)))
  33354. return(int_vector_set_if_a);
  33355. return(NULL);
  33356. }
  33357. static s7_if_t int_vector_set_if(s7_scheme *sc, s7_pointer expr)
  33358. {
  33359. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_pair(cdddr(expr))) && (is_null(cddddr(expr))))
  33360. {
  33361. s7_pointer iv;
  33362. iv = cadr(expr);
  33363. if (!is_symbol(iv)) return(NULL);
  33364. iv = s7_slot(sc, iv);
  33365. if (!is_slot(iv)) return(NULL);
  33366. if (!is_int_vector(slot_value(iv))) return(NULL);
  33367. return(int_vector_set_if_expanded(sc, slot_value(iv), caddr(expr), cadddr(expr)));
  33368. }
  33369. return(NULL);
  33370. }
  33371. /* float-vector-ref|set optimizers */
  33372. static s7_double fv_set_rf_checked(s7_scheme *sc, s7_pointer **p)
  33373. {
  33374. s7_pointer fv, ind;
  33375. s7_double val;
  33376. s7_int index;
  33377. s7_rf_t rf;
  33378. fv = **p; (*p)++;
  33379. ind = slot_value(**p); (*p)++;
  33380. if (!is_integer(ind))
  33381. wrong_type_argument(sc, sc->float_vector_set_symbol, 2, ind, T_INTEGER);
  33382. index = integer(ind);
  33383. if ((index < 0) || (index >= vector_length(fv)))
  33384. out_of_range(sc, sc->float_vector_set_symbol, small_int(2), ind, (index < 0) ? its_negative_string : its_too_large_string);
  33385. rf = (s7_rf_t)(**p); (*p)++;
  33386. val = rf(sc, p);
  33387. float_vector_element(fv, index) = val;
  33388. return(val);
  33389. }
  33390. static s7_double fv_set_rf_r(s7_scheme *sc, s7_pointer **p)
  33391. {
  33392. s7_pointer fv, ind, x;
  33393. s7_double val;
  33394. s7_int index;
  33395. fv = **p; (*p)++;
  33396. ind = slot_value(**p); (*p)++;
  33397. if (!is_integer(ind))
  33398. wrong_type_argument(sc, sc->float_vector_set_symbol, 2, ind, T_INTEGER);
  33399. index = integer(ind);
  33400. if ((index < 0) || (index >= vector_length(fv)))
  33401. out_of_range(sc, sc->float_vector_set_symbol, small_int(2), ind, (index < 0) ? its_negative_string : its_too_large_string);
  33402. x = **p; (*p)++;
  33403. val = real_to_double(sc, x, "float-vector-set!");
  33404. float_vector_element(fv, index) = val;
  33405. return(val);
  33406. }
  33407. static s7_double fv_set_rf_s(s7_scheme *sc, s7_pointer **p)
  33408. {
  33409. s7_pointer fv, ind, x;
  33410. s7_double val;
  33411. s7_int index;
  33412. fv = **p; (*p)++;
  33413. ind = slot_value(**p); (*p)++;
  33414. if (!is_integer(ind))
  33415. wrong_type_argument(sc, sc->float_vector_set_symbol, 2, ind, T_INTEGER);
  33416. index = integer(ind);
  33417. if ((index < 0) || (index >= vector_length(fv)))
  33418. out_of_range(sc, sc->float_vector_set_symbol, small_int(2), ind, (index < 0) ? its_negative_string : its_too_large_string);
  33419. x = slot_value(**p); (*p)++;
  33420. val = real_to_double(sc, x, "float-vector-set!");
  33421. float_vector_element(fv, index) = val;
  33422. return(val);
  33423. }
  33424. static s7_double fv_set_rf_six(s7_scheme *sc, s7_pointer **p)
  33425. {
  33426. s7_pointer fv, ind;
  33427. s7_double val;
  33428. s7_int index;
  33429. s7_rf_t rf;
  33430. fv = **p; (*p)++;
  33431. ind = **p; (*p)++;
  33432. index = integer(ind);
  33433. rf = (s7_rf_t)(**p); (*p)++;
  33434. val = rf(sc, p);
  33435. float_vector_element(fv, index) = val;
  33436. return(val);
  33437. }
  33438. static s7_double fv_set_rf_if(s7_scheme *sc, s7_pointer **p)
  33439. {
  33440. s7_pointer fv;
  33441. s7_double val;
  33442. s7_int index;
  33443. s7_rf_t rf;
  33444. s7_if_t xf;
  33445. fv = **p; (*p)++;
  33446. xf = (s7_if_t)(**p); (*p)++;
  33447. index = xf(sc, p);
  33448. if ((index < 0) || (index >= vector_length(fv)))
  33449. out_of_range(sc, sc->float_vector_set_symbol, small_int(2), make_integer(sc, index), (index < 0) ? its_negative_string : its_too_large_string);
  33450. rf = (s7_rf_t)(**p); (*p)++;
  33451. val = rf(sc, p);
  33452. float_vector_element(fv, index) = val;
  33453. return(val);
  33454. }
  33455. static s7_rf_t float_vector_set_rf_expanded(s7_scheme *sc, s7_pointer fv, s7_pointer ind_sym, s7_pointer val_expr)
  33456. {
  33457. xf_t *rc;
  33458. xf_init(3);
  33459. xf_store(fv);
  33460. if (is_symbol(ind_sym))
  33461. {
  33462. s7_pointer ind, ind_slot;
  33463. ind_slot = s7_slot(sc, ind_sym);
  33464. if (!is_slot(ind_slot)) return(NULL);
  33465. ind = slot_value(ind_slot);
  33466. if (!is_integer(ind)) return(NULL);
  33467. if (numerator(ind) < 0) return(NULL);
  33468. xf_store(ind_slot);
  33469. if (is_real(val_expr))
  33470. {
  33471. xf_store(val_expr);
  33472. return(fv_set_rf_r);
  33473. }
  33474. if (is_symbol(val_expr))
  33475. {
  33476. s7_pointer slot, val;
  33477. slot = s7_slot(sc, val_expr);
  33478. if (!is_slot(slot)) return(NULL);
  33479. val = slot_value(slot);
  33480. if (!is_real(val)) return(NULL);
  33481. xf_store(slot);
  33482. return(fv_set_rf_s);
  33483. }
  33484. if (!is_pair(val_expr)) return(NULL);
  33485. return(pair_to_rf(sc, val_expr, fv_set_rf_checked));
  33486. }
  33487. if (is_pair(ind_sym))
  33488. {
  33489. s7_ip_t ip;
  33490. s7_if_t xf;
  33491. s7_int loc;
  33492. if (!is_pair(val_expr)) return(NULL);
  33493. xf_save_loc(loc);
  33494. ip = pair_to_ip(sc, ind_sym);
  33495. if (!ip) return(NULL);
  33496. xf = ip(sc, ind_sym);
  33497. if (!xf) return(NULL);
  33498. xf_store_at(loc, (s7_pointer)xf);
  33499. return(pair_to_rf(sc, val_expr, fv_set_rf_if));
  33500. }
  33501. if ((is_integer(ind_sym)) &&
  33502. (is_pair(val_expr)))
  33503. {
  33504. s7_int index;
  33505. index = integer(ind_sym);
  33506. if ((index < 0) || (index >= vector_length(fv))) return(NULL);
  33507. xf_store(ind_sym);
  33508. return(pair_to_rf(sc, val_expr, fv_set_rf_six));
  33509. }
  33510. return(NULL);
  33511. }
  33512. static s7_rf_t float_vector_set_rf(s7_scheme *sc, s7_pointer expr)
  33513. {
  33514. s7_pointer fv;
  33515. fv = cadr(expr);
  33516. if (!is_symbol(fv)) return(NULL);
  33517. fv = s7_slot(sc, fv);
  33518. if (!is_slot(fv)) return(NULL);
  33519. if (!is_float_vector(slot_value(fv))) return(NULL);
  33520. return(float_vector_set_rf_expanded(sc, slot_value(fv), caddr(expr), cadddr(expr)));
  33521. }
  33522. static s7_double fv_ref_rf_ss(s7_scheme *sc, s7_pointer **p)
  33523. {
  33524. s7_pointer s1, s2;
  33525. s7_int ind;
  33526. s1 = slot_value(**p); (*p)++;
  33527. s2 = slot_value(**p); (*p)++;
  33528. ind = s7_integer(s2);
  33529. if ((ind < 0) || (ind >= vector_length(s1)))
  33530. out_of_range(sc, sc->float_vector_ref_symbol, small_int(2), s2, (ind < 0) ? its_negative_string : its_too_large_string);
  33531. return(float_vector_elements(s1)[ind]);
  33532. }
  33533. static s7_double fv_ref_rf_si(s7_scheme *sc, s7_pointer **p)
  33534. {
  33535. s7_pointer s1, s2;
  33536. s7_int ind;
  33537. s1 = slot_value(**p); (*p)++;
  33538. s2 = (**p); (*p)++;
  33539. ind = s7_integer(s2);
  33540. if ((ind < 0) || (ind >= vector_length(s1)))
  33541. out_of_range(sc, sc->float_vector_ref_symbol, small_int(2), s2, (ind < 0) ? its_negative_string : its_too_large_string);
  33542. return(float_vector_elements(s1)[ind]);
  33543. }
  33544. static s7_double fv_ref_rf_sx(s7_scheme *sc, s7_pointer **p)
  33545. {
  33546. s7_pointer s1;
  33547. s7_if_t i1;
  33548. s7_int ind;
  33549. s1 = slot_value(**p); (*p)++;
  33550. i1 = (s7_if_t)(**p); (*p)++;
  33551. ind = i1(sc, p);
  33552. if ((ind < 0) || (ind >= vector_length(s1)))
  33553. out_of_range(sc, sc->float_vector_ref_symbol, small_int(2), make_integer(sc, ind), (ind < 0) ? its_negative_string : its_too_large_string);
  33554. return(float_vector_elements(s1)[ind]);
  33555. }
  33556. static s7_double fv_ref_rf_pf(s7_scheme *sc, s7_pointer **p)
  33557. {
  33558. s7_pointer s1;
  33559. s7_pf_t fv;
  33560. s7_if_t i1;
  33561. s7_int ind;
  33562. fv = (s7_pf_t)(**p); (*p)++;
  33563. s1 = fv(sc, p);
  33564. if (!is_float_vector(s1))
  33565. wrong_type_argument(sc, sc->float_vector_ref_symbol, 1, s1, T_FLOAT_VECTOR);
  33566. i1 = (s7_if_t)(**p); (*p)++;
  33567. ind = i1(sc, p);
  33568. if ((ind < 0) || (ind >= vector_length(s1)))
  33569. out_of_range(sc, sc->float_vector_ref_symbol, small_int(2), make_integer(sc, ind), (ind < 0) ? its_negative_string : its_too_large_string);
  33570. return(float_vector_elements(s1)[ind]);
  33571. }
  33572. static s7_rf_t float_vector_ref_rf_expanded(s7_scheme *sc, s7_pointer a1, s7_pointer a2)
  33573. {
  33574. if ((is_symbol(a1)) &&
  33575. (is_float_vector(s7_symbol_value(sc, a1))))
  33576. {
  33577. xf_t *rc;
  33578. xf_init(2);
  33579. xf_store(s7_slot(sc, a1));
  33580. if (is_integer(a2))
  33581. {
  33582. xf_store(a2);
  33583. return(fv_ref_rf_si);
  33584. }
  33585. if (is_symbol(a2))
  33586. {
  33587. a2 = s7_slot(sc, a2);
  33588. if ((!is_slot(a2)) || (is_t_complex(slot_value(a2)))) return(NULL);
  33589. xf_store(a2);
  33590. return(fv_ref_rf_ss);
  33591. }
  33592. if (is_pair(a2))
  33593. return(pair_to_rf_via_if(sc, a2, fv_ref_rf_sx));
  33594. }
  33595. if ((is_pair(a1)) &&
  33596. (s7_arg_to_pf(sc, a1)) &&
  33597. (s7_arg_to_if(sc, a2)))
  33598. return(fv_ref_rf_pf);
  33599. return(NULL);
  33600. }
  33601. static s7_rf_t float_vector_ref_rf(s7_scheme *sc, s7_pointer expr)
  33602. {
  33603. if ((is_null(cdr(expr))) || (is_null(cddr(expr))) || (!is_null(cdddr(expr)))) return(NULL);
  33604. return(float_vector_ref_rf_expanded(sc, cadr(expr), caddr(expr)));
  33605. }
  33606. static s7_rf_t implicit_float_vector_ref(s7_scheme *sc, s7_pointer expr)
  33607. {
  33608. if ((is_null(cdr(expr))) || (!is_null(cddr(expr)))) return(NULL);
  33609. return(float_vector_ref_rf_expanded(sc, car(expr), cadr(expr)));
  33610. }
  33611. static s7_pointer hash_table_ref_pf_i(s7_scheme *sc, s7_pointer **p);
  33612. static s7_pointer hash_table_set_pf_sxx(s7_scheme *sc, s7_pointer **p);
  33613. static s7_pf_t implicit_pf_sequence_ref(s7_scheme *sc, s7_pointer expr)
  33614. {
  33615. s7_pointer seq, ind;
  33616. if ((is_null(cdr(expr))) || (!is_null(cddr(expr)))) return(NULL);
  33617. seq = car(expr);
  33618. ind = cadr(expr);
  33619. if (!is_symbol(seq)) return(NULL);
  33620. seq = s7_slot(sc, seq);
  33621. if (!is_slot(seq)) return(NULL);
  33622. s7_xf_store(sc, seq);
  33623. switch (type(slot_value(seq)))
  33624. {
  33625. case T_STRING:
  33626. if (s7_arg_to_if(sc, ind))
  33627. return(string_ref_pf_si);
  33628. break;
  33629. case T_PAIR:
  33630. if (s7_arg_to_if(sc, ind))
  33631. return(list_ref_pf_si);
  33632. break;
  33633. case T_VECTOR:
  33634. if (s7_arg_to_if(sc, ind))
  33635. return(vector_ref_pf_i); /* TODO: these vref funcs don't check bounds */
  33636. break;
  33637. case T_HASH_TABLE:
  33638. if (s7_arg_to_pf(sc, ind))
  33639. return(hash_table_ref_pf_i);
  33640. break;
  33641. case T_LET:
  33642. if (s7_arg_to_pf(sc, ind))
  33643. return(let_ref_pf_p2_sp);
  33644. break;
  33645. }
  33646. return(NULL);
  33647. }
  33648. static s7_pf_t implicit_gf_sequence_ref(s7_scheme *sc, s7_pointer expr)
  33649. {
  33650. /* only difference from pf case: int|float-vectors return s7_pointer values */
  33651. return(implicit_pf_sequence_ref(sc, expr));
  33652. }
  33653. #if WITH_OPTIMIZATION
  33654. static s7_pf_t implicit_pf_sequence_set(s7_scheme *sc, s7_pointer seq, s7_pointer ind, s7_pointer val)
  33655. {
  33656. /* seq is the slot */
  33657. s7_xf_store(sc, seq);
  33658. switch (type(slot_value(seq)))
  33659. {
  33660. case T_STRING:
  33661. if ((s7_arg_to_if(sc, ind)) &&
  33662. (s7_arg_to_pf(sc, val)))
  33663. return(string_set_pf_seq);
  33664. break;
  33665. case T_PAIR:
  33666. if ((s7_arg_to_if(sc, ind)) &&
  33667. (s7_arg_to_pf(sc, val)))
  33668. return(list_set_pf_seq);
  33669. break;
  33670. case T_VECTOR:
  33671. if ((s7_arg_to_if(sc, ind)) &&
  33672. (s7_arg_to_pf(sc, val)))
  33673. return(vector_set_pf_seq);
  33674. break;
  33675. case T_HASH_TABLE:
  33676. if ((s7_arg_to_pf(sc, ind)) &&
  33677. (s7_arg_to_pf(sc, val)))
  33678. return(hash_table_set_pf_sxx);
  33679. break;
  33680. case T_LET:
  33681. if ((s7_arg_to_pf(sc, ind)) &&
  33682. (s7_arg_to_pf(sc, val)))
  33683. return(let_set_pf_p3_s);
  33684. break;
  33685. }
  33686. return(NULL);
  33687. }
  33688. static s7_pf_t implicit_gf_sequence_set(s7_scheme *sc, s7_pointer v, s7_pointer ind, s7_pointer val)
  33689. {
  33690. return(implicit_pf_sequence_set(sc, v, ind, val));
  33691. }
  33692. #endif
  33693. /* -------------------------------------------------------------------------------- */
  33694. static bool c_function_is_ok(s7_scheme *sc, s7_pointer x)
  33695. {
  33696. /* macro version of this (below) is much slower! */
  33697. s7_pointer p;
  33698. p = car(x);
  33699. if (is_global(p)) p = slot_value(global_slot(p)); else p = find_symbol_unchecked(sc, p);
  33700. /* this is nearly always global and p == opt_cfunc(x)
  33701. * p can be null if we evaluate some code, optimizing it, then eval it again in a context
  33702. * where the incoming p was undefined(!) -- explicit use of eval and so on.
  33703. * I guess ideally eval would ignore optimization info -- copy :readable or something.
  33704. */
  33705. return((p == opt_any1(x)) ||
  33706. ((is_any_c_function(p)) && /* (opt_cfunc(x)) && */
  33707. (c_function_class(p) == c_function_class(opt_cfunc(x)))));
  33708. }
  33709. static bool arglist_has_rest(s7_scheme *sc, s7_pointer args)
  33710. {
  33711. s7_pointer p;
  33712. for (p = args; is_pair(p); p = cdr(p))
  33713. if (car(p) == sc->key_rest_symbol)
  33714. return(true);
  33715. return(false);
  33716. }
  33717. static bool arglist_has_keyword(s7_pointer args)
  33718. {
  33719. s7_pointer p;
  33720. for (p = args; is_pair(p); p = cdr(p))
  33721. if (is_keyword(car(p)))
  33722. return(true);
  33723. return(false);
  33724. }
  33725. /* -------- sort! -------- */
  33726. #if (!WITH_GMP)
  33727. static int dbl_less(const void *f1, const void *f2)
  33728. {
  33729. if ((*((s7_double *)f1)) < (*((s7_double *)f2))) return(-1);
  33730. if ((*((s7_double *)f1)) > (*((s7_double *)f2))) return(1);
  33731. return(0);
  33732. }
  33733. static int int_less(const void *f1, const void *f2)
  33734. {
  33735. if ((*((s7_int *)f1)) < (*((s7_int *)f2))) return(-1);
  33736. if ((*((s7_int *)f1)) > (*((s7_int *)f2))) return(1);
  33737. return(0);
  33738. }
  33739. static int dbl_greater(const void *f1, const void *f2) {return(-dbl_less(f1, f2));}
  33740. static int int_greater(const void *f1, const void *f2) {return(-int_less(f1, f2));}
  33741. static int byte_less(const void *f1, const void *f2)
  33742. {
  33743. if ((*((unsigned char *)f1)) < (*((unsigned char *)f2))) return(-1);
  33744. if ((*((unsigned char *)f1)) > (*((unsigned char *)f2))) return(1);
  33745. return(0);
  33746. }
  33747. static int byte_greater(const void *f1, const void *f2) {return(-byte_less(f1, f2));}
  33748. static int dbl_less_2(const void *f1, const void *f2)
  33749. {
  33750. s7_pointer p1, p2;
  33751. p1 = (*((s7_pointer *)f1));
  33752. p2 = (*((s7_pointer *)f2));
  33753. if (real(p1) < real(p2)) return(-1);
  33754. if (real(p1) > real(p2)) return(1);
  33755. return(0);
  33756. }
  33757. static int int_less_2(const void *f1, const void *f2)
  33758. {
  33759. s7_pointer p1, p2;
  33760. p1 = (*((s7_pointer *)f1));
  33761. p2 = (*((s7_pointer *)f2));
  33762. if (integer(p1) < integer(p2)) return(-1);
  33763. if (integer(p1) > integer(p2)) return(1);
  33764. return(0);
  33765. }
  33766. static int dbl_greater_2(const void *f1, const void *f2) {return(-dbl_less_2(f1, f2));}
  33767. static int int_greater_2(const void *f1, const void *f2) {return(-int_less_2(f1, f2));}
  33768. #endif
  33769. static s7_scheme *compare_sc;
  33770. static s7_function compare_func;
  33771. static s7_pointer compare_args, compare_begin, compare_v1, compare_v2;
  33772. static opcode_t compare_op;
  33773. static s7_pf_t compare_pf;
  33774. static int vector_compare(const void *v1, const void *v2)
  33775. {
  33776. set_car(compare_args, (*(s7_pointer *)v1));
  33777. set_cadr(compare_args, (*(s7_pointer *)v2));
  33778. return(((*(compare_func))(compare_sc, compare_args) != compare_sc->F) ? -1 : 1);
  33779. }
  33780. static int pf_compare(const void *v1, const void *v2)
  33781. {
  33782. s7_pointer *top;
  33783. s7_pointer **rp;
  33784. slot_set_value(compare_v1, (*(s7_pointer *)v1));
  33785. slot_set_value(compare_v2, (*(s7_pointer *)v2));
  33786. top = compare_sc->cur_rf->data;
  33787. rp = &top; (*rp)++;
  33788. if (is_true(compare_sc, compare_pf(compare_sc, rp)))
  33789. return(-1);
  33790. return(1);
  33791. }
  33792. static int closure_compare(const void *v1, const void *v2)
  33793. {
  33794. slot_set_value(compare_v1, (*(s7_pointer *)v1));
  33795. slot_set_value(compare_v2, (*(s7_pointer *)v2));
  33796. push_stack(compare_sc, OP_EVAL_DONE, compare_sc->args, compare_sc->code);
  33797. compare_sc->code = compare_args; /* this should be ok because we checked in advance that it is a safe closure (no sort! for example) */
  33798. eval(compare_sc, compare_op);
  33799. return((compare_sc->value != compare_sc->F) ? -1 : 1);
  33800. }
  33801. static int closure_compare_begin(const void *v1, const void *v2)
  33802. {
  33803. slot_set_value(compare_v1, (*(s7_pointer *)v1));
  33804. slot_set_value(compare_v2, (*(s7_pointer *)v2));
  33805. push_stack(compare_sc, OP_EVAL_DONE, compare_sc->args, compare_sc->code);
  33806. push_stack_no_args(compare_sc, OP_BEGIN1, compare_begin);
  33807. compare_sc->code = compare_args;
  33808. eval(compare_sc, compare_op);
  33809. return((compare_sc->value != compare_sc->F) ? -1 : 1);
  33810. }
  33811. static s7_pointer g_sort(s7_scheme *sc, s7_pointer args)
  33812. {
  33813. #define H_sort "(sort! sequence less?) sorts a sequence using the function 'less?' to compare elements."
  33814. #define Q_sort s7_make_signature(sc, 3, sc->T, sc->is_sequence_symbol, sc->is_procedure_symbol)
  33815. s7_pointer data, lessp, lx;
  33816. s7_int len = 0, n, k;
  33817. int (*sort_func)(const void *v1, const void *v2);
  33818. s7_pointer *elements;
  33819. int gc_loc = -1;
  33820. /* both the intermediate vector (if any) and the current args pointer need GC protection,
  33821. * but it is a real bother to unprotect args at every return statement, so I'll use temp3
  33822. */
  33823. sc->temp3 = args; /* this is needed! */
  33824. data = car(args);
  33825. if (is_null(data))
  33826. {
  33827. /* (apply sort! () #f) should be an error I think */
  33828. lessp = cadr(args);
  33829. if (type(lessp) < T_GOTO)
  33830. method_or_bust_with_type(sc, lessp, sc->sort_symbol, args, a_procedure_string, 2);
  33831. if (!s7_is_aritable(sc, lessp, 2))
  33832. return(wrong_type_argument_with_type(sc, sc->sort_symbol, 2, lessp, an_eq_func_string));
  33833. return(sc->nil);
  33834. }
  33835. lessp = cadr(args);
  33836. if (type(lessp) < T_GOTO)
  33837. method_or_bust_with_type(sc, lessp, sc->sort_symbol, args, a_procedure_string, 2);
  33838. if (!s7_is_aritable(sc, lessp, 2))
  33839. return(wrong_type_argument_with_type(sc, sc->sort_symbol, 2, lessp, an_eq_func_string));
  33840. if ((is_continuation(lessp)) || is_goto(lessp))
  33841. return(wrong_type_argument_with_type(sc, sc->sort_symbol, 2, lessp, a_normal_procedure_string));
  33842. sort_func = vector_compare;
  33843. compare_func = NULL;
  33844. compare_args = sc->t2_1;
  33845. compare_sc = sc;
  33846. if ((is_safe_procedure(lessp)) && /* (sort! a <) */
  33847. (is_c_function(lessp)))
  33848. {
  33849. s7_pointer sig;
  33850. sig = c_function_signature(lessp);
  33851. if ((sig) &&
  33852. (is_pair(sig)) &&
  33853. (car(sig) != sc->is_boolean_symbol))
  33854. return(wrong_type_argument_with_type(sc, sc->sort_symbol, 2, lessp, make_string_wrapper(sc, "sort! function should return a boolean")));
  33855. compare_func = c_function_call(lessp);
  33856. }
  33857. else
  33858. {
  33859. if (is_closure(lessp))
  33860. {
  33861. s7_pointer expr, largs;
  33862. expr = car(closure_body(lessp));
  33863. largs = closure_args(lessp);
  33864. if ((is_null(cdr(closure_body(lessp)))) &&
  33865. (is_optimized(expr)))
  33866. {
  33867. /* since (sort seq (lambda (a b) ...)) can't return a "safe closure" (the hop bit is off in
  33868. * optimize in this case, for some arcane reason), the optimized expression won't be hop_safe,
  33869. * but that is irrelevant at this point -- if c_function_is_ok, we're good to go.
  33870. */
  33871. if ((is_pair(largs)) &&
  33872. (!arglist_has_rest(sc, largs)) &&
  33873. (((optimize_op(expr) & 1) != 0) ||
  33874. (c_function_is_ok(sc, expr))))
  33875. {
  33876. int orig_data;
  33877. orig_data = optimize_op(expr);
  33878. set_optimize_op(expr, optimize_op(expr) | 1);
  33879. if ((optimize_op(expr) == HOP_SAFE_C_SS) &&
  33880. (car(largs) == cadr(expr)) &&
  33881. (cadr(largs) == caddr(expr)))
  33882. {
  33883. lessp = find_symbol_unchecked(sc, car(expr));
  33884. compare_func = c_function_call(lessp);
  33885. }
  33886. else
  33887. {
  33888. if (!is_unsafe_sort(expr))
  33889. {
  33890. new_frame_with_two_slots(sc, closure_let(lessp), sc->envir, car(largs), sc->F, cadr(largs), sc->F);
  33891. set_stepper(let_slots(sc->envir));
  33892. set_stepper(next_slot(let_slots(sc->envir)));
  33893. s7_xf_new(sc, sc->envir);
  33894. compare_pf = xf_opt(sc, expr);
  33895. if (compare_pf)
  33896. {
  33897. sort_func = pf_compare;
  33898. compare_func = g_sort; /* whatever...(just a flag) */
  33899. compare_v1 = let_slots(sc->envir);
  33900. compare_v2 = next_slot(let_slots(sc->envir));
  33901. }
  33902. else
  33903. {
  33904. set_unsafe_sort(expr);
  33905. s7_xf_free(sc);
  33906. }
  33907. }
  33908. }
  33909. set_optimize_op(expr, orig_data);
  33910. }
  33911. }
  33912. if ((!compare_func) &&
  33913. (is_pair(largs)) && /* closure args not a symbol, etc */
  33914. (is_safe_closure(lessp))) /* no embedded sort! or call/cc, etc */
  33915. {
  33916. new_frame_with_two_slots(sc, closure_let(lessp), sc->envir, car(largs), sc->F, cadr(largs), sc->F);
  33917. compare_func = (s7_function)lessp; /* not used -- just a flag */
  33918. compare_args = car(closure_body(lessp));
  33919. compare_begin = cdr(closure_body(lessp));
  33920. if (is_null(compare_begin))
  33921. sort_func = closure_compare;
  33922. else sort_func = closure_compare_begin;
  33923. if (typesflag(compare_args) == SYNTACTIC_PAIR)
  33924. {
  33925. compare_op = (opcode_t)pair_syntax_op(compare_args);
  33926. compare_args = cdr(compare_args);
  33927. }
  33928. else compare_op = OP_EVAL;
  33929. compare_v1 = let_slots(sc->envir);
  33930. compare_v2 = next_slot(let_slots(sc->envir));
  33931. }
  33932. }
  33933. }
  33934. #if (!WITH_GMP)
  33935. if (compare_func == g_less)
  33936. compare_func = g_less_2;
  33937. else
  33938. {
  33939. if (compare_func == g_greater)
  33940. compare_func = g_greater_2;
  33941. }
  33942. #endif
  33943. switch (type(data))
  33944. {
  33945. case T_PAIR:
  33946. len = s7_list_length(sc, data); /* 0 here == infinite */
  33947. if (len <= 0)
  33948. {
  33949. if (sort_func == pf_compare) s7_xf_free(sc);
  33950. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "sort! argument 1 should be a proper list: ~S"), data)));
  33951. }
  33952. if (len < 2)
  33953. {
  33954. if (sort_func == pf_compare) s7_xf_free(sc);
  33955. return(data);
  33956. }
  33957. if (compare_func)
  33958. {
  33959. int i;
  33960. s7_pointer vec, p;
  33961. vec = g_vector(sc, data);
  33962. gc_loc = s7_gc_protect(sc, vec);
  33963. elements = s7_vector_elements(vec);
  33964. sc->v = vec;
  33965. qsort((void *)elements, len, sizeof(s7_pointer), sort_func);
  33966. for (p = data, i = 0; i < len; i++, p = cdr(p))
  33967. set_car(p, elements[i]);
  33968. s7_gc_unprotect_at(sc, gc_loc);
  33969. if (sort_func == pf_compare) s7_xf_free(sc);
  33970. return(data);
  33971. }
  33972. push_stack(sc, OP_SORT_PAIR_END, cons(sc, data, lessp), sc->code); /* save and gc protect the original list and func */
  33973. set_car(args, g_vector(sc, data));
  33974. break;
  33975. case T_STRING:
  33976. {
  33977. /* byte-vectors here also, so this isn't completely silly */
  33978. int i;
  33979. s7_pointer vec;
  33980. unsigned char *chrs;
  33981. len = string_length(data);
  33982. if (len < 2)
  33983. {
  33984. if (sort_func == pf_compare) s7_xf_free(sc);
  33985. return(data);
  33986. }
  33987. #if (!WITH_GMP)
  33988. if (is_c_function(lessp))
  33989. {
  33990. if (((!is_byte_vector(data)) && (compare_func == g_chars_are_less)) ||
  33991. ((is_byte_vector(data)) && (compare_func == g_less_2)))
  33992. {
  33993. qsort((void *)vector_elements(data), len, sizeof(unsigned char), byte_less);
  33994. return(data);
  33995. }
  33996. if (((!is_byte_vector(data)) && (compare_func == g_chars_are_greater)) ||
  33997. ((is_byte_vector(data)) && (compare_func == g_greater_2)))
  33998. {
  33999. qsort((void *)vector_elements(data), len, sizeof(unsigned char), byte_greater);
  34000. return(data);
  34001. }
  34002. }
  34003. #endif
  34004. vec = make_vector_1(sc, len, NOT_FILLED, T_VECTOR);
  34005. gc_loc = s7_gc_protect(sc, vec);
  34006. elements = s7_vector_elements(vec);
  34007. chrs = (unsigned char *)string_value(data);
  34008. if (is_byte_vector(data))
  34009. {
  34010. for (i = 0; i < len; i++)
  34011. elements[i] = small_int(chrs[i]);
  34012. }
  34013. else
  34014. {
  34015. for (i = 0; i < len; i++)
  34016. elements[i] = chars[chrs[i]];
  34017. }
  34018. if (compare_func)
  34019. {
  34020. sc->v = vec;
  34021. qsort((void *)elements, len, sizeof(s7_pointer), sort_func);
  34022. if (is_byte_vector(data))
  34023. {
  34024. for (i = 0; i < len; i++)
  34025. chrs[i] = (char)integer(elements[i]);
  34026. }
  34027. else
  34028. {
  34029. for (i = 0; i < len; i++)
  34030. chrs[i] = character(elements[i]);
  34031. }
  34032. s7_gc_unprotect_at(sc, gc_loc);
  34033. if (sort_func == pf_compare) s7_xf_free(sc);
  34034. return(data);
  34035. }
  34036. push_stack(sc, OP_SORT_STRING_END, cons(sc, data, lessp), sc->code);
  34037. set_car(args, vec);
  34038. s7_gc_unprotect_at(sc, gc_loc);
  34039. }
  34040. break;
  34041. case T_INT_VECTOR:
  34042. case T_FLOAT_VECTOR:
  34043. {
  34044. int i;
  34045. s7_pointer vec;
  34046. len = vector_length(data);
  34047. if (len < 2)
  34048. {
  34049. if (sort_func == pf_compare) s7_xf_free(sc);
  34050. return(data);
  34051. }
  34052. #if (!WITH_GMP)
  34053. if (is_c_function(lessp))
  34054. {
  34055. if (compare_func == g_less_2)
  34056. {
  34057. if (type(data) == T_FLOAT_VECTOR)
  34058. qsort((void *)vector_elements(data), len, sizeof(s7_double), dbl_less);
  34059. else qsort((void *)vector_elements(data), len, sizeof(s7_int), int_less);
  34060. return(data);
  34061. }
  34062. if (compare_func == g_greater_2)
  34063. {
  34064. if (type(data) == T_FLOAT_VECTOR)
  34065. qsort((void *)vector_elements(data), len, sizeof(s7_double), dbl_greater);
  34066. else qsort((void *)vector_elements(data), len, sizeof(s7_int), int_greater);
  34067. return(data);
  34068. }
  34069. }
  34070. #endif
  34071. /* currently we have to make the ordinary vector here even if not compare_func
  34072. * because the sorter uses vector_element to access sort args (see SORT_DATA in eval).
  34073. * This is probably better than passing down getter/setter (fewer allocations).
  34074. * get/set macro in eval is SORT_DATA(k) then s7_vector_to_list if pair at start (sort_*_end)
  34075. */
  34076. vec = make_vector_1(sc, len, FILLED, T_VECTOR);
  34077. /* we need this vector prefilled because vector_getter below makes reals/int, causing possible GC
  34078. * at any time during that loop, and the GC mark process expects the vector to have an s7_pointer
  34079. * at every element.
  34080. */
  34081. gc_loc = s7_gc_protect(sc, vec);
  34082. elements = s7_vector_elements(vec);
  34083. for (i = 0; i < len; i++)
  34084. elements[i] = vector_getter(data)(sc, data, i);
  34085. if (compare_func)
  34086. {
  34087. sc->v = vec;
  34088. qsort((void *)elements, len, sizeof(s7_pointer), sort_func);
  34089. for (i = 0; i < len; i++)
  34090. vector_setter(data)(sc, data, i, elements[i]);
  34091. s7_gc_unprotect_at(sc, gc_loc);
  34092. if (sort_func == pf_compare) s7_xf_free(sc);
  34093. return(data);
  34094. }
  34095. push_stack(sc, OP_SORT_VECTOR_END, cons(sc, data, lessp), sc->code); /* save and gc protect the original homogeneous vector and func */
  34096. set_car(args, vec);
  34097. s7_gc_unprotect_at(sc, gc_loc);
  34098. }
  34099. break;
  34100. case T_VECTOR:
  34101. len = vector_length(data);
  34102. if (len < 2)
  34103. {
  34104. if (sort_func == pf_compare) s7_xf_free(sc);
  34105. return(data);
  34106. }
  34107. if (compare_func)
  34108. {
  34109. /* here if, for example, compare_func == string<?, we could precheck for strings,
  34110. * then qsort without the type checks. Also common is (lambda (a b) (f (car a) (car b))).
  34111. */
  34112. #if (!WITH_GMP)
  34113. if ((compare_func == g_less_2) || (compare_func == g_greater_2))
  34114. {
  34115. int i, typ;
  34116. s7_pointer *els;
  34117. els = s7_vector_elements(data);
  34118. typ = type(els[0]);
  34119. if ((typ == T_INTEGER) || (typ == T_REAL))
  34120. for (i = 1; i < len; i++)
  34121. if (type(els[i]) != typ)
  34122. {
  34123. typ = T_FREE;
  34124. break;
  34125. }
  34126. if (typ == T_INTEGER)
  34127. {
  34128. qsort((void *)els, len, sizeof(s7_pointer), ((compare_func == g_less_2) ? int_less_2 : int_greater_2));
  34129. return(data);
  34130. }
  34131. if (typ == T_REAL)
  34132. {
  34133. qsort((void *)els, len, sizeof(s7_pointer), ((compare_func == g_less_2) ? dbl_less_2 : dbl_greater_2));
  34134. return(data);
  34135. }
  34136. }
  34137. #endif
  34138. qsort((void *)s7_vector_elements(data), len, sizeof(s7_pointer), sort_func);
  34139. if (sort_func == pf_compare) s7_xf_free(sc);
  34140. return(data);
  34141. }
  34142. break;
  34143. default:
  34144. method_or_bust_with_type(sc, data, sc->sort_symbol, args, a_sequence_string, 1);
  34145. }
  34146. if (sort_func == pf_compare) s7_xf_free(sc);
  34147. n = len - 1;
  34148. k = ((int)(n / 2)) + 1;
  34149. lx = s7_make_vector(sc, (sc->safety == 0) ? 4 : 6);
  34150. gc_loc = s7_gc_protect(sc, lx);
  34151. sc->v = lx;
  34152. vector_element(lx, 0) = make_mutable_integer(sc, n);
  34153. vector_element(lx, 1) = make_mutable_integer(sc, k);
  34154. vector_element(lx, 2) = make_mutable_integer(sc, 0);
  34155. vector_element(lx, 3) = make_mutable_integer(sc, 0);
  34156. if (sc->safety != 0)
  34157. {
  34158. vector_element(lx, 4) = make_mutable_integer(sc, 0);
  34159. vector_element(lx, 5) = make_integer(sc, n * n);
  34160. }
  34161. push_stack(sc, OP_SORT, args, lx);
  34162. s7_gc_unprotect_at(sc, gc_loc);
  34163. return(sc->F);
  34164. /* if the comparison function waffles, sort! can hang: (sort! '(1 2 3) (lambda (a b) (= a b)))
  34165. * set 'safety to 1 to add a check for this loop, but the "safe" procedures are direct, so unchecked.
  34166. */
  34167. }
  34168. static s7_pointer c_sort_p(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(g_sort(sc, set_plist_2(sc, x, y)));}
  34169. PF2_TO_PF(sort, c_sort_p)
  34170. /* these are for the eval sort -- sort a vector, then if necessary put that data into the original sequence */
  34171. static s7_pointer vector_into_list(s7_pointer vect, s7_pointer lst)
  34172. {
  34173. s7_pointer p;
  34174. s7_pointer *elements;
  34175. int i, len;
  34176. elements = s7_vector_elements(vect);
  34177. len = vector_length(vect);
  34178. for (i = 0, p = lst; i < len; i++, p = cdr(p))
  34179. set_car(p, elements[i]);
  34180. return(lst);
  34181. }
  34182. static s7_pointer vector_into_fi_vector(s7_pointer source, s7_pointer dest)
  34183. {
  34184. s7_pointer *elements;
  34185. int i, len;
  34186. elements = s7_vector_elements(source);
  34187. len = vector_length(source);
  34188. if (is_float_vector(dest))
  34189. {
  34190. s7_double *flts;
  34191. flts = float_vector_elements(dest);
  34192. for (i = 0; i < len; i++)
  34193. flts[i] = real(elements[i]);
  34194. }
  34195. else
  34196. {
  34197. s7_int *ints;
  34198. ints = int_vector_elements(dest);
  34199. for (i = 0; i < len; i++)
  34200. ints[i] = integer(elements[i]);
  34201. }
  34202. return(dest);
  34203. }
  34204. static s7_pointer vector_into_string(s7_pointer vect, s7_pointer dest)
  34205. {
  34206. s7_pointer *elements;
  34207. int i, len;
  34208. unsigned char *str;
  34209. elements = s7_vector_elements(vect);
  34210. len = vector_length(vect);
  34211. str = (unsigned char *)string_value(dest);
  34212. if (is_byte_vector(dest))
  34213. {
  34214. for (i = 0; i < len; i++)
  34215. str[i] = (unsigned char)integer(elements[i]);
  34216. }
  34217. else
  34218. {
  34219. for (i = 0; i < len; i++)
  34220. str[i] = character(elements[i]);
  34221. }
  34222. return(dest);
  34223. }
  34224. /* -------- hash tables -------- */
  34225. static hash_entry_t *hash_free_list = NULL;
  34226. static void free_hash_table(s7_pointer table)
  34227. {
  34228. hash_entry_t **entries;
  34229. entries = hash_table_elements(table);
  34230. if (hash_table_entries(table) > 0)
  34231. {
  34232. unsigned int i, len;
  34233. len = hash_table_mask(table) + 1;
  34234. for (i = 0; i < len; i++)
  34235. {
  34236. hash_entry_t *p, *n;
  34237. for (p = entries[i++]; p; p = n)
  34238. {
  34239. n = p->next;
  34240. p->next = hash_free_list;
  34241. hash_free_list = p;
  34242. }
  34243. for (p = entries[i]; p; p = n)
  34244. {
  34245. n = p->next;
  34246. p->next = hash_free_list;
  34247. hash_free_list = p;
  34248. }
  34249. }
  34250. }
  34251. free(entries);
  34252. }
  34253. static hash_entry_t *make_hash_entry(s7_pointer key, s7_pointer value, unsigned int raw_hash)
  34254. {
  34255. hash_entry_t *p;
  34256. if (hash_free_list)
  34257. {
  34258. p = hash_free_list;
  34259. hash_free_list = p->next;
  34260. }
  34261. else p = (hash_entry_t *)malloc(sizeof(hash_entry_t));
  34262. p->key = key;
  34263. p->value = value;
  34264. p->raw_hash = raw_hash;
  34265. return(p);
  34266. }
  34267. /* -------------------------------- hash-table? -------------------------------- */
  34268. bool s7_is_hash_table(s7_pointer p)
  34269. {
  34270. return(is_hash_table(p));
  34271. }
  34272. static s7_pointer g_is_hash_table(s7_scheme *sc, s7_pointer args)
  34273. {
  34274. #define H_is_hash_table "(hash-table? obj) returns #t if obj is a hash-table"
  34275. #define Q_is_hash_table pl_bt
  34276. check_boolean_method(sc, is_hash_table, sc->is_hash_table_symbol, args);
  34277. }
  34278. /* -------------------------------- hash-table-entries -------------------------------- */
  34279. static s7_pointer g_hash_table_entries(s7_scheme *sc, s7_pointer args)
  34280. {
  34281. #define H_hash_table_entries "(hash-table-entries obj) returns the number of entries in the hash-table obj"
  34282. #define Q_hash_table_entries s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_hash_table_symbol)
  34283. if (!is_hash_table(car(args)))
  34284. method_or_bust(sc, car(args), sc->hash_table_entries_symbol, args, T_HASH_TABLE, 0);
  34285. return(make_integer(sc, hash_table_entries(car(args))));
  34286. }
  34287. static s7_int c_hash_table_entries(s7_scheme *sc, s7_pointer p)
  34288. {
  34289. if (!is_hash_table(p))
  34290. int_method_or_bust(sc, p, sc->hash_table_entries_symbol, set_plist_1(sc, p), T_HASH_TABLE, 0);
  34291. return(hash_table_entries(p));
  34292. }
  34293. PF_TO_IF(hash_table_entries, c_hash_table_entries)
  34294. /* ---------------- mappers ---------------- */
  34295. static unsigned int hash_float_location(s7_double x)
  34296. {
  34297. int loc;
  34298. #if defined(__clang__)
  34299. if ((is_inf(x)) || (is_NaN(x))) return(0);
  34300. #endif
  34301. x = fabs(x);
  34302. if (x < 100.0)
  34303. loc = 1000.0 * x; /* this means hash_table_float_epsilon only works if it is less than about .001 */
  34304. else loc = x;
  34305. if (loc < 0)
  34306. return(0);
  34307. return(loc);
  34308. }
  34309. /* built in hash loc tables for eq? eqv? equal? morally-equal? = string=? string-ci=? char=? char-ci=? (default=equal?) */
  34310. #define hash_loc(Sc, Table, Key) (*(hash_table_mapper(Table)[type(Key)]))(Sc, Table, Key)
  34311. static hash_map_t *eq_hash_map, *eqv_hash_map, *string_eq_hash_map, *number_eq_hash_map, *char_eq_hash_map, *closure_hash_map;
  34312. static hash_map_t *morally_equal_hash_map, *c_function_hash_map;
  34313. #if (!WITH_PURE_S7)
  34314. static hash_map_t *string_ci_eq_hash_map, *char_ci_eq_hash_map;
  34315. #endif
  34316. static unsigned int hash_map_nil(s7_scheme *sc, s7_pointer table, s7_pointer key) {return(type(key));}
  34317. static unsigned int hash_map_int(s7_scheme *sc, s7_pointer table, s7_pointer key) {return((unsigned int)(s7_int_abs(integer(key))));}
  34318. static unsigned int hash_map_char(s7_scheme *sc, s7_pointer table, s7_pointer key) {return(character(key));}
  34319. static unsigned int hash_map_ratio(s7_scheme *sc, s7_pointer table, s7_pointer key) {return((unsigned int)denominator(key));} /* overflow possible as elsewhere */
  34320. static unsigned int hash_map_complex(s7_scheme *sc, s7_pointer table, s7_pointer key) {return(hash_float_location(real_part(key)));}
  34321. static unsigned int hash_map_symbol(s7_scheme *sc, s7_pointer table, s7_pointer key) {return(symbol_hmap(key));}
  34322. static unsigned int hash_map_syntax(s7_scheme *sc, s7_pointer table, s7_pointer key) {return(symbol_hmap(syntax_symbol(key)));}
  34323. #if WITH_GMP
  34324. static unsigned int hash_map_big_int(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34325. {
  34326. return((unsigned int)(big_integer_to_s7_int(big_integer(key))));
  34327. }
  34328. static unsigned int hash_map_big_ratio(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34329. {
  34330. return((unsigned int)(big_integer_to_s7_int(mpq_denref(big_ratio(key)))));
  34331. }
  34332. static unsigned int hash_map_big_real(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34333. {
  34334. return((unsigned int)mpfr_get_d(big_real(key), GMP_RNDN));
  34335. }
  34336. static unsigned int hash_map_big_complex(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34337. {
  34338. return((unsigned int)mpfr_get_d(mpc_realref(big_complex(key)), GMP_RNDN));
  34339. }
  34340. #endif
  34341. static unsigned int hash_map_string(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34342. {
  34343. if (string_hash(key) == 0)
  34344. string_hash(key) = raw_string_hash((const unsigned char *)string_value(key), string_length(key));
  34345. return(string_hash(key));
  34346. }
  34347. #if (!WITH_PURE_S7)
  34348. static unsigned int hash_map_ci_char(s7_scheme *sc, s7_pointer table, s7_pointer key) {return(upper_character(key));}
  34349. static unsigned int hash_map_ci_string(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34350. {
  34351. int len;
  34352. len = string_length(key);
  34353. if (len == 0) return(0);
  34354. return(len + (uppers[(int)(string_value(key)[0])] << 4));
  34355. }
  34356. #endif
  34357. static unsigned int hash_map_real(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34358. {
  34359. return(hash_float_location(real(key)));
  34360. /* currently 1e300 goes to most-negative-fixnum! -> 0 after logand size, I hope
  34361. *
  34362. * we need round, not floor for the location calculation in the real/complex cases else
  34363. * 1-eps doesn't match 1.0, but 1+eps does. And what if round(val) is too big for int?
  34364. * lrint is complex and requires special compiler flags to get any speed (-fno-math-errno).
  34365. * all we need is (int)(val+0.5) -- all the other stuff is pointless in this context
  34366. */
  34367. }
  34368. static unsigned int hash_map_real_eq(s7_scheme *sc, s7_pointer table, s7_pointer x)
  34369. {
  34370. if (real(x) < 0.0)
  34371. return((unsigned int)(s7_round(-real(x))));
  34372. return((unsigned int)s7_round(real(x)));
  34373. }
  34374. static unsigned int hash_map_ratio_eq(s7_scheme *sc, s7_pointer table, s7_pointer y)
  34375. {
  34376. s7_double x;
  34377. x = fraction(y);
  34378. if (x < 0.0)
  34379. return((unsigned int)s7_round(-x));
  34380. return((unsigned int)s7_round(x));
  34381. }
  34382. static unsigned int hash_map_hash_table(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34383. {
  34384. /* hash-tables are equal if key/values match independent of table size and entry order.
  34385. * if not using morally-equal?, hash_table_checker|mapper must also be the same.
  34386. * Keys are supposed to be constant while keys, so a hash-table shouldn't be a key of itself.
  34387. */
  34388. return(hash_table_entries(key));
  34389. }
  34390. static unsigned int hash_map_int_vector(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34391. {
  34392. if (vector_length(key) == 0)
  34393. return(0);
  34394. if (vector_length(key) == 1)
  34395. return((unsigned int)(s7_int_abs(int_vector_element(key, 0))));
  34396. return((unsigned int)(vector_length(key) + s7_int_abs(int_vector_element(key, 0)) + s7_int_abs(int_vector_element(key, 1))));
  34397. }
  34398. static unsigned int hash_map_float_vector(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34399. {
  34400. if (vector_length(key) == 0)
  34401. return(0);
  34402. if (vector_length(key) == 1)
  34403. return(hash_float_location(float_vector_element(key, 0)));
  34404. return((unsigned int)(vector_length(key) + hash_float_location(float_vector_element(key, 0)) + hash_float_location(float_vector_element(key, 1))));
  34405. }
  34406. static unsigned int hash_map_vector(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34407. {
  34408. if ((vector_length(key) == 0) ||
  34409. (is_sequence(vector_element(key, 0))))
  34410. return(vector_length(key));
  34411. if ((vector_length(key) == 1) ||
  34412. (is_sequence(vector_element(key, 1))))
  34413. return(hash_loc(sc, table, vector_element(key, 0)));
  34414. return(vector_length(key) + hash_loc(sc, table, vector_element(key, 0)) + hash_loc(sc, table, vector_element(key, 1)));
  34415. }
  34416. static unsigned int hash_map_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34417. {
  34418. int x;
  34419. x = heap_location(key);
  34420. if (x < 0) return(-x);
  34421. return(x);
  34422. }
  34423. static unsigned int hash_map_closure(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34424. {
  34425. s7_pointer f, old_e, args, body;
  34426. f = hash_table_procedures_mapper(table);
  34427. old_e = sc->envir;
  34428. args = closure_args(f);
  34429. body = closure_body(f);
  34430. new_frame_with_slot(sc, closure_let(f), sc->envir, (is_symbol(car(args))) ? car(args) : caar(args), key);
  34431. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  34432. if (is_pair(cdr(body)))
  34433. push_stack_no_args(sc, OP_BEGIN1, cdr(body));
  34434. sc->code = car(body);
  34435. eval(sc, OP_EVAL);
  34436. sc->envir = old_e;
  34437. return(integer(sc->value));
  34438. }
  34439. static unsigned int hash_map_c_function(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34440. {
  34441. s7_function f;
  34442. f = c_function_call(hash_table_procedures_mapper(table));
  34443. set_car(sc->t1_1, key);
  34444. return(integer(f(sc, sc->t1_1)));
  34445. }
  34446. static unsigned int hash_map_let(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34447. {
  34448. /* lets are equal if same symbol/value pairs, independent of order, taking into account shadowing
  34449. * (length (inlet 'a 1 'a 2)) = 2
  34450. * but this counts as just one entry from equal?'s point of view, so if more than one entry, we have a problem.
  34451. * (equal? (inlet 'a 1) (inlet 'a 3 'a 2 'a 1)) = #t
  34452. * also currently equal? follows outlet, but that is ridiculous here, so in this case hash equal?
  34453. * is not the same as equal? Surely anyone using lets as keys wants eq?
  34454. */
  34455. s7_pointer slot;
  34456. int slots;
  34457. if ((key == sc->rootlet) ||
  34458. (!is_slot(let_slots(key))))
  34459. return(0);
  34460. slot = let_slots(key);
  34461. if (!is_slot(next_slot(slot)))
  34462. {
  34463. if (is_sequence(slot_value(slot))) /* avoid loop if cycles */
  34464. return(symbol_hmap(slot_symbol(slot)));
  34465. return(symbol_hmap(slot_symbol(slot)) + hash_loc(sc, table, slot_value(slot)));
  34466. }
  34467. slots = 0;
  34468. for (; is_slot(slot); slot = next_slot(slot))
  34469. if (!is_matched_symbol(slot_symbol(slot)))
  34470. {
  34471. set_match_symbol(slot_symbol(slot));
  34472. slots++;
  34473. }
  34474. for (slot = let_slots(key); is_slot(slot); slot = next_slot(slot))
  34475. clear_match_symbol(slot_symbol(slot));
  34476. if (slots == 1)
  34477. {
  34478. slot = let_slots(key);
  34479. if (is_sequence(slot_value(slot))) /* avoid loop if cycles */
  34480. return(symbol_hmap(slot_symbol(slot)));
  34481. return(symbol_hmap(slot_symbol(slot)) + hash_loc(sc, table, slot_value(slot)));
  34482. }
  34483. return(slots);
  34484. }
  34485. static unsigned int hash_map_pair(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34486. {
  34487. /* len+loc(car) is not horrible, but it means (for example) every list '(set! ...) is hashed to the same location,
  34488. * so at least we need to take cadr into account if possible. Better would combine the list_length(max 5 == safe_strlen5?) call
  34489. * with stats like symbols/pairs/constants at top level, then use those to spread it out over all the locs.
  34490. */
  34491. s7_pointer p1;
  34492. unsigned int loc = 0;
  34493. if (!is_sequence(car(key)))
  34494. loc = hash_loc(sc, table, car(key)) + 1;
  34495. else
  34496. {
  34497. if ((is_pair(car(key))) &&
  34498. (!is_sequence(caar(key))))
  34499. loc = hash_loc(sc, table, caar(key)) + 1;
  34500. }
  34501. p1 = cdr(key);
  34502. if (is_pair(p1))
  34503. {
  34504. if (!is_sequence(car(p1)))
  34505. loc += hash_loc(sc, table, car(p1)) + 1;
  34506. else
  34507. {
  34508. if ((is_pair(car(p1))) &&
  34509. (!is_sequence(caar(p1))))
  34510. loc += hash_loc(sc, table, caar(p1)) + 1;
  34511. }
  34512. }
  34513. return(loc);
  34514. }
  34515. /* ---------------- checkers ---------------- */
  34516. static hash_entry_t *hash_empty(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34517. {
  34518. return(NULL);
  34519. }
  34520. static hash_entry_t *hash_int(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34521. {
  34522. if (is_integer(key))
  34523. {
  34524. s7_int keyval;
  34525. hash_entry_t *x;
  34526. unsigned int loc, hash_len;
  34527. hash_len = hash_table_mask(table);
  34528. keyval = integer(key);
  34529. if (keyval < 0)
  34530. loc = (unsigned int)((-keyval) & hash_len);
  34531. else loc = (unsigned int)(keyval & hash_len);
  34532. /* I think this assumes hash_map_int is using s7_int_abs (and high order bits are ignored) */
  34533. for (x = hash_table_element(table, loc); x; x = x->next)
  34534. if (integer(x->key) == keyval)
  34535. return(x);
  34536. }
  34537. return(NULL);
  34538. }
  34539. static hash_entry_t *hash_string(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34540. {
  34541. if (is_string(key))
  34542. {
  34543. hash_entry_t *x;
  34544. unsigned int hash_len, key_len;
  34545. unsigned long long int hash;
  34546. const char *key_str;
  34547. key_len = string_length(key);
  34548. key_str = string_value(key);
  34549. hash_len = hash_table_mask(table);
  34550. if (string_hash(key) == 0)
  34551. string_hash(key) = raw_string_hash((const unsigned char *)string_value(key), string_length(key));
  34552. hash = string_hash(key);
  34553. if (key_len <= 8)
  34554. {
  34555. for (x = hash_table_element(table, hash & hash_len); x; x = x->next)
  34556. if ((hash == string_hash(x->key)) &&
  34557. (key_len == string_length(x->key)))
  34558. return(x);
  34559. }
  34560. else
  34561. {
  34562. for (x = hash_table_element(table, hash & hash_len); x; x = x->next)
  34563. if ((hash == string_hash(x->key)) &&
  34564. (key_len == string_length(x->key)) && /* these are scheme strings, so we can't assume 0=end of string */
  34565. (strings_are_equal_with_length(key_str, string_value(x->key), key_len)))
  34566. return(x);
  34567. }
  34568. }
  34569. return(NULL);
  34570. }
  34571. #if (!WITH_PURE_S7)
  34572. static hash_entry_t *hash_ci_string(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34573. {
  34574. if (is_string(key))
  34575. {
  34576. hash_entry_t *x;
  34577. unsigned int hash, hash_len;
  34578. hash_len = hash_table_mask(table);
  34579. hash = hash_map_ci_string(sc, table, key);
  34580. for (x = hash_table_element(table, hash & hash_len); x; x = x->next)
  34581. if (scheme_strequal_ci(key, x->key))
  34582. return(x);
  34583. }
  34584. return(NULL);
  34585. }
  34586. static hash_entry_t *hash_ci_char(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34587. {
  34588. if (s7_is_character(key))
  34589. {
  34590. hash_entry_t *x;
  34591. unsigned int hash_len, loc;
  34592. hash_len = hash_table_mask(table);
  34593. loc = hash_loc(sc, table, key) & hash_len;
  34594. for (x = hash_table_element(table, loc); x; x = x->next)
  34595. if (upper_character(key) == upper_character(x->key))
  34596. return(x);
  34597. }
  34598. return(NULL);
  34599. }
  34600. #endif
  34601. static hash_entry_t *hash_float_1(s7_scheme *sc, s7_pointer table, unsigned int loc, s7_double keyval)
  34602. {
  34603. hash_entry_t *x;
  34604. bool look_for_nan;
  34605. look_for_nan = is_NaN(keyval);
  34606. for (x = hash_table_element(table, loc); x; x = x->next)
  34607. {
  34608. if (is_t_real(x->key)) /* we're possibly called from hash_equal, so keys might not be T_REAL */
  34609. {
  34610. s7_double val;
  34611. val = real(x->key);
  34612. if (look_for_nan)
  34613. {
  34614. if (is_NaN(val))
  34615. return(x);
  34616. }
  34617. else
  34618. {
  34619. if ((val == keyval) || /* inf case */
  34620. (fabs(val - keyval) < sc->hash_table_float_epsilon))
  34621. return(x);
  34622. }
  34623. }
  34624. }
  34625. return(NULL);
  34626. }
  34627. static hash_entry_t *hash_float(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34628. {
  34629. /* give the equality check some room. also inf == inf and nan == nan
  34630. */
  34631. if (type(key) == T_REAL)
  34632. {
  34633. s7_double keyval;
  34634. unsigned int hash_len, loc;
  34635. hash_len = hash_table_mask(table);
  34636. keyval = real(key);
  34637. loc = hash_float_location(keyval) & hash_len;
  34638. return(hash_float_1(sc, table, loc, keyval));
  34639. }
  34640. return(NULL);
  34641. }
  34642. static hash_entry_t *hash_complex_1(s7_scheme *sc, s7_pointer table, unsigned int loc, s7_pointer key)
  34643. {
  34644. hash_entry_t *x;
  34645. for (x = hash_table_element(table, loc); x; x = x->next)
  34646. if ((is_t_complex(x->key)) &&
  34647. (s7_is_morally_equal(sc, x->key, key)))
  34648. return(x);
  34649. return(NULL);
  34650. }
  34651. static hash_entry_t *hash_equal_real(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34652. {
  34653. return(hash_float_1(sc, table, hash_loc(sc, table, key) & hash_table_mask(table), real(key)));
  34654. }
  34655. static hash_entry_t *hash_equal_complex(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34656. {
  34657. return(hash_complex_1(sc, table, hash_loc(sc, table, key) & hash_table_mask(table), key));
  34658. }
  34659. static hash_entry_t *hash_equal_syntax(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34660. {
  34661. hash_entry_t *x;
  34662. unsigned int loc;
  34663. loc = hash_loc(sc, table, key) & hash_table_mask(table);
  34664. for (x = hash_table_element(table, loc); x; x = x->next)
  34665. if ((is_syntax(x->key)) &&
  34666. (syntax_symbol(x->key) == syntax_symbol(key))) /* the opcodes might differ, but the symbols should not */
  34667. return(x);
  34668. return(NULL);
  34669. }
  34670. static hash_entry_t *hash_equal_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34671. {
  34672. hash_entry_t *x;
  34673. unsigned int loc;
  34674. loc = hash_loc(sc, table, key) & hash_table_mask(table);
  34675. for (x = hash_table_element(table, loc); x; x = x->next)
  34676. if (x->key == key)
  34677. return(x);
  34678. return(NULL);
  34679. }
  34680. static hash_entry_t *hash_equal_any(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34681. {
  34682. hash_entry_t *x;
  34683. unsigned int loc;
  34684. loc = hash_loc(sc, table, key) & hash_table_mask(table);
  34685. /* we can get into an infinite loop here, but it requires 2 hash tables that are members of each other
  34686. * and key is one of them, so I changed the equality check above to use eq? -- not sure this is right.
  34687. */
  34688. /* hope for an easy case... */
  34689. for (x = hash_table_element(table, loc); x; x = x->next)
  34690. if (x->key == key)
  34691. return(x);
  34692. for (x = hash_table_element(table, loc); x; x = x->next)
  34693. if (s7_is_equal(sc, x->key, key))
  34694. return(x);
  34695. return(NULL);
  34696. }
  34697. static hash_entry_t *(*default_hash_checks[NUM_TYPES])(s7_scheme *sc, s7_pointer table, s7_pointer key);
  34698. static hash_entry_t *(*equal_hash_checks[NUM_TYPES])(s7_scheme *sc, s7_pointer table, s7_pointer key);
  34699. static hash_entry_t *(*morally_equal_hash_checks[NUM_TYPES])(s7_scheme *sc, s7_pointer table, s7_pointer key);
  34700. static hash_entry_t *hash_equal(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34701. {
  34702. return((*(equal_hash_checks[type(key)]))(sc, table, key));
  34703. }
  34704. static hash_entry_t *hash_morally_equal(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34705. {
  34706. hash_entry_t *x;
  34707. unsigned int loc;
  34708. loc = hash_loc(sc, table, key) & hash_table_mask(table);
  34709. for (x = hash_table_element(table, loc); x; x = x->next)
  34710. if (x->key == key)
  34711. return(x);
  34712. for (x = hash_table_element(table, loc); x; x = x->next)
  34713. if (s7_is_morally_equal(sc, x->key, key))
  34714. return(x);
  34715. return(NULL);
  34716. }
  34717. static hash_entry_t *hash_c_function(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34718. {
  34719. hash_entry_t *x;
  34720. unsigned int hash_len, loc;
  34721. s7_function f;
  34722. f = c_function_call(hash_table_procedures_checker(table));
  34723. hash_len = hash_table_mask(table);
  34724. loc = hash_loc(sc, table, key) & hash_len;
  34725. set_car(sc->t2_1, key);
  34726. for (x = hash_table_element(table, loc); x; x = x->next)
  34727. {
  34728. set_car(sc->t2_2, x->key);
  34729. if (is_true(sc, f(sc, sc->t2_1)))
  34730. return(x);
  34731. }
  34732. return(NULL);
  34733. }
  34734. static hash_entry_t *hash_eq(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34735. {
  34736. /* explicit eq? as hash equality func or (for example) symbols as keys */
  34737. hash_entry_t *x;
  34738. unsigned int hash_len, loc;
  34739. hash_len = hash_table_mask(table);
  34740. loc = hash_loc(sc, table, key) & hash_len;
  34741. for (x = hash_table_element(table, loc); x; x = x->next)
  34742. if (key == x->key)
  34743. return(x);
  34744. return(NULL);
  34745. }
  34746. static hash_entry_t *hash_eqv(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34747. {
  34748. hash_entry_t *x;
  34749. unsigned int hash_len, loc;
  34750. hash_len = hash_table_mask(table);
  34751. loc = hash_loc(sc, table, key) & hash_len;
  34752. for (x = hash_table_element(table, loc); x; x = x->next)
  34753. if (s7_is_eqv(key, x->key))
  34754. return(x);
  34755. return(NULL);
  34756. }
  34757. static hash_entry_t *hash_number(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34758. {
  34759. if (is_number(key))
  34760. {
  34761. hash_entry_t *x;
  34762. unsigned int hash_len, loc;
  34763. hash_len = hash_table_mask(table);
  34764. loc = hash_loc(sc, table, key) & hash_len;
  34765. #if (!WITH_GMP)
  34766. for (x = hash_table_element(table, loc); x; x = x->next)
  34767. if ((is_number(x->key)) &&
  34768. (is_true(sc, c_equal_2_1(sc, key, x->key))))
  34769. return(x);
  34770. #else
  34771. for (x = hash_table_element(table, loc); x; x = x->next)
  34772. if ((is_number(x->key)) &&
  34773. (is_true(sc, big_equal(sc, set_plist_2(sc, key, x->key)))))
  34774. return(x);
  34775. #endif
  34776. }
  34777. return(NULL);
  34778. }
  34779. static hash_entry_t *hash_symbol(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34780. {
  34781. if (is_symbol(key))
  34782. {
  34783. hash_entry_t *x;
  34784. for (x = hash_table_element(table, symbol_hmap(key) & hash_table_mask(table)); x; x = x->next)
  34785. if (key == x->key)
  34786. return(x);
  34787. }
  34788. return(NULL);
  34789. }
  34790. static hash_entry_t *hash_char(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34791. {
  34792. if (s7_is_character(key))
  34793. return(hash_eq(sc, table, key));
  34794. return(NULL);
  34795. }
  34796. static hash_entry_t *hash_closure(s7_scheme *sc, s7_pointer table, s7_pointer key)
  34797. {
  34798. hash_entry_t *x;
  34799. unsigned int hash_len, loc;
  34800. s7_pointer f, args, body, old_e;
  34801. f = hash_table_procedures_checker(table);
  34802. hash_len = hash_table_mask(table);
  34803. loc = hash_loc(sc, table, key) & hash_len;
  34804. old_e = sc->envir;
  34805. args = closure_args(f); /* in lambda* case, car/cadr(args) can be lists */
  34806. body = closure_body(f);
  34807. new_frame_with_two_slots(sc, closure_let(f), sc->envir,
  34808. (is_symbol(car(args))) ? car(args) : caar(args), key,
  34809. (is_symbol(cadr(args))) ? cadr(args) : caadr(args), sc->F);
  34810. for (x = hash_table_element(table, loc); x; x = x->next)
  34811. {
  34812. slot_set_value(next_slot(let_slots(sc->envir)), x->key);
  34813. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  34814. if (is_pair(cdr(body)))
  34815. push_stack_no_args(sc, OP_BEGIN1, cdr(body));
  34816. sc->code = car(body);
  34817. eval(sc, OP_EVAL);
  34818. if (is_true(sc, sc->value))
  34819. {
  34820. sc->envir = old_e;
  34821. return(x);
  34822. }
  34823. }
  34824. sc->envir = old_e;
  34825. return(NULL);
  34826. }
  34827. static s7_pointer remove_from_hash_table(s7_scheme *sc, s7_pointer table, s7_pointer key, hash_entry_t *p)
  34828. {
  34829. hash_entry_t *x;
  34830. unsigned int hash_len, loc;
  34831. hash_len = hash_table_mask(table);
  34832. #if DEBUGGING
  34833. if (p->raw_hash != hash_loc(sc, table, key))
  34834. fprintf(stderr, "%s[%d]: %s raw: %u, loc: %u\n", __func__, __LINE__, DISPLAY(key), p->raw_hash, hash_loc(sc, table, key));
  34835. #endif
  34836. loc = p->raw_hash & hash_len;
  34837. x = hash_table_element(table, loc);
  34838. if (x == p)
  34839. hash_table_element(table, loc) = x->next;
  34840. else
  34841. {
  34842. hash_entry_t *y;
  34843. for (y = x, x = x->next; x; y = x, x = x->next)
  34844. if (x == p)
  34845. {
  34846. y->next = x->next;
  34847. break;
  34848. }
  34849. }
  34850. hash_table_entries(table)--;
  34851. if ((hash_table_entries(table) == 0) &&
  34852. (!hash_table_checker_locked(table)))
  34853. hash_table_checker(table) = hash_empty;
  34854. x->next = hash_free_list;
  34855. hash_free_list = x;
  34856. return(sc->F);
  34857. }
  34858. /* -------------------------------- make-hash-table -------------------------------- */
  34859. s7_pointer s7_make_hash_table(s7_scheme *sc, s7_int size)
  34860. {
  34861. s7_pointer table;
  34862. hash_entry_t **els;
  34863. /* size is rounded up to the next power of 2 */
  34864. if ((size == 0) || /* already 2^n ? */
  34865. ((size & (size - 1)) != 0))
  34866. {
  34867. if ((size & (size + 1)) != 0) /* already 2^n - 1 ? */
  34868. {
  34869. size--;
  34870. size |= (size >> 1);
  34871. size |= (size >> 2);
  34872. size |= (size >> 4);
  34873. size |= (size >> 8);
  34874. size |= (size >> 16);
  34875. if (s7_int_bits > 31) /* this is either 31 or 63 */
  34876. size |= (size >> 32);
  34877. }
  34878. size++;
  34879. }
  34880. els = (hash_entry_t **)calloc(size, sizeof(hash_entry_t *));
  34881. if (!els) return(s7_error(sc, make_symbol(sc, "out-of-memory"), set_elist_1(sc, make_string_wrapper(sc, "make-hash-table allocation failed!"))));
  34882. new_cell(sc, table, T_HASH_TABLE | T_SAFE_PROCEDURE);
  34883. hash_table_mask(table) = size - 1;
  34884. hash_table_elements(table) = els;
  34885. hash_table_checker(table) = hash_empty;
  34886. hash_table_mapper(table) = default_hash_map;
  34887. hash_table_entries(table) = 0;
  34888. hash_table_set_procedures(table, sc->nil);
  34889. add_hash_table(sc, table);
  34890. return(table);
  34891. }
  34892. static s7_pointer g_is_equal(s7_scheme *sc, s7_pointer args);
  34893. static s7_pointer g_is_morally_equal(s7_scheme *sc, s7_pointer args);
  34894. static s7_pointer g_make_hash_table(s7_scheme *sc, s7_pointer args)
  34895. {
  34896. #define H_make_hash_table "(make-hash-table (size 511) eq-func) returns a new hash table"
  34897. #define Q_make_hash_table s7_make_signature(sc, 3, sc->is_hash_table_symbol, sc->is_integer_symbol, s7_make_signature(sc, 2, sc->is_procedure_symbol, sc->is_pair_symbol))
  34898. s7_int size;
  34899. size = sc->default_hash_table_length;
  34900. if (is_not_null(args))
  34901. {
  34902. s7_pointer p;
  34903. p = car(args);
  34904. if (!s7_is_integer(p))
  34905. {
  34906. s7_pointer p1;
  34907. if (!s7_is_integer(p1 = check_values(sc, p, args)))
  34908. method_or_bust(sc, p, sc->make_hash_table_symbol, args, T_INTEGER, 1);
  34909. p = p1;
  34910. }
  34911. size = s7_integer(p);
  34912. if (size <= 0) /* we need s7_int here to catch (make-hash-table most-negative-fixnum) etc */
  34913. return(simple_out_of_range(sc, sc->make_hash_table_symbol, p, make_string_wrapper(sc, "should be a positive integer")));
  34914. if (size > sc->max_vector_length)
  34915. return(simple_out_of_range(sc, sc->make_hash_table_symbol, p, its_too_large_string));
  34916. if (is_not_null(cdr(args)))
  34917. {
  34918. s7_pointer ht, proc;
  34919. proc = cadr(args);
  34920. if (is_c_function(proc))
  34921. {
  34922. if (!s7_is_aritable(sc, proc, 2))
  34923. return(wrong_type_argument_with_type(sc, sc->make_hash_table_symbol, 3, proc, an_eq_func_string));
  34924. ht = s7_make_hash_table(sc, size);
  34925. if (c_function_call(proc) == g_is_equal)
  34926. return(ht);
  34927. if (c_function_call(proc) == g_is_eq)
  34928. {
  34929. hash_table_checker(ht) = hash_eq;
  34930. hash_table_mapper(ht) = eq_hash_map;
  34931. }
  34932. else
  34933. {
  34934. if (c_function_call(proc) == g_strings_are_equal)
  34935. {
  34936. hash_table_checker(ht) = hash_string;
  34937. hash_table_mapper(ht) = string_eq_hash_map;
  34938. }
  34939. else
  34940. {
  34941. #if (!WITH_PURE_S7)
  34942. if (c_function_call(proc) == g_strings_are_ci_equal)
  34943. {
  34944. hash_table_checker(ht) = hash_ci_string;
  34945. hash_table_mapper(ht) = string_ci_eq_hash_map;
  34946. }
  34947. else
  34948. {
  34949. if (c_function_call(proc) == g_chars_are_ci_equal)
  34950. {
  34951. hash_table_checker(ht) = hash_ci_char;
  34952. hash_table_mapper(ht) = char_ci_eq_hash_map;
  34953. }
  34954. else
  34955. {
  34956. #endif
  34957. if (c_function_call(proc) == g_chars_are_equal)
  34958. {
  34959. hash_table_checker(ht) = hash_char;
  34960. hash_table_mapper(ht) = char_eq_hash_map;
  34961. }
  34962. else
  34963. {
  34964. #if (!WITH_GMP)
  34965. if (c_function_call(proc) == g_equal)
  34966. #else
  34967. if ((c_function_call(proc) == g_equal) ||
  34968. (c_function_call(proc) == big_equal))
  34969. #endif
  34970. {
  34971. hash_table_checker(ht) = hash_number;
  34972. hash_table_mapper(ht) = number_eq_hash_map;
  34973. }
  34974. else
  34975. {
  34976. if (c_function_call(proc) == g_is_eqv)
  34977. {
  34978. hash_table_checker(ht) = hash_eqv;
  34979. hash_table_mapper(ht) = eqv_hash_map;
  34980. }
  34981. else
  34982. {
  34983. if (c_function_call(proc) == g_is_morally_equal)
  34984. {
  34985. hash_table_checker(ht) = hash_morally_equal;
  34986. hash_table_mapper(ht) = morally_equal_hash_map;
  34987. }
  34988. else return(wrong_type_argument_with_type(sc, sc->make_hash_table_symbol, 3, proc,
  34989. make_string_wrapper(sc, "a hash function")));
  34990. }}}}}
  34991. #if (!WITH_PURE_S7)
  34992. }}
  34993. #endif
  34994. return(ht);
  34995. }
  34996. /* proc not c_function */
  34997. else
  34998. {
  34999. if (is_pair(proc))
  35000. {
  35001. s7_pointer checker, mapper;
  35002. checker = car(proc);
  35003. mapper = cdr(proc);
  35004. if (((is_any_c_function(checker)) || (is_any_closure(checker))) &&
  35005. ((is_any_c_function(mapper)) || (is_any_closure(mapper))) &&
  35006. (s7_is_aritable(sc, checker, 2)) &&
  35007. (s7_is_aritable(sc, mapper, 1)))
  35008. {
  35009. s7_pointer sig;
  35010. ht = s7_make_hash_table(sc, size);
  35011. if (is_any_c_function(checker))
  35012. {
  35013. sig = c_function_signature(checker);
  35014. if ((sig) &&
  35015. (is_pair(sig)) &&
  35016. (car(sig) != sc->is_boolean_symbol))
  35017. return(wrong_type_argument_with_type(sc, sc->make_hash_table_symbol, 3, proc,
  35018. make_string_wrapper(sc, "equality function should return a boolean")));
  35019. hash_table_checker(ht) = hash_c_function;
  35020. }
  35021. else hash_table_checker(ht) = hash_closure;
  35022. if (is_any_c_function(mapper))
  35023. {
  35024. sig = c_function_signature(mapper);
  35025. if ((sig) &&
  35026. (is_pair(sig)) &&
  35027. (car(sig) != sc->is_integer_symbol))
  35028. return(wrong_type_argument_with_type(sc, sc->make_hash_table_symbol, 3, proc,
  35029. make_string_wrapper(sc, "mapping function should return an integer")));
  35030. hash_table_mapper(ht) = c_function_hash_map;
  35031. }
  35032. else hash_table_mapper(ht) = closure_hash_map;
  35033. hash_table_set_procedures(ht, proc);
  35034. return(ht);
  35035. }
  35036. }
  35037. return(wrong_type_argument_with_type(sc, sc->make_hash_table_symbol, 3, proc,
  35038. make_string_wrapper(sc, "a cons of two functions")));
  35039. }
  35040. }
  35041. }
  35042. return(s7_make_hash_table(sc, size));
  35043. }
  35044. void init_hash_maps(void)
  35045. {
  35046. int i;
  35047. default_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35048. eq_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35049. eqv_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35050. string_eq_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35051. number_eq_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35052. char_eq_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35053. #if (!WITH_PURE_S7)
  35054. string_ci_eq_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35055. char_ci_eq_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35056. #endif
  35057. closure_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35058. c_function_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35059. morally_equal_hash_map = (hash_map_t *)malloc(NUM_TYPES * sizeof(hash_map_t));
  35060. for (i = 0; i < NUM_TYPES; i++)
  35061. {
  35062. default_hash_map[i] = hash_map_nil;
  35063. string_eq_hash_map[i] = hash_map_nil;
  35064. char_eq_hash_map[i] = hash_map_nil;
  35065. #if (!WITH_PURE_S7)
  35066. string_ci_eq_hash_map[i] = hash_map_nil;
  35067. char_ci_eq_hash_map[i] = hash_map_nil;
  35068. #endif
  35069. number_eq_hash_map[i] = hash_map_nil;
  35070. closure_hash_map[i] = hash_map_closure;
  35071. c_function_hash_map[i] = hash_map_c_function;
  35072. eq_hash_map[i] = hash_map_eq;
  35073. eqv_hash_map[i] = hash_map_eq;
  35074. equal_hash_checks[i] = hash_equal_any;
  35075. morally_equal_hash_checks[i] = hash_equal_any;
  35076. default_hash_checks[i] = hash_equal;
  35077. }
  35078. default_hash_map[T_INTEGER] = hash_map_int;
  35079. default_hash_map[T_RATIO] = hash_map_ratio;
  35080. default_hash_map[T_REAL] = hash_map_real;
  35081. default_hash_map[T_COMPLEX] = hash_map_complex;
  35082. default_hash_map[T_CHARACTER] = hash_map_char;
  35083. default_hash_map[T_SYMBOL] = hash_map_symbol;
  35084. default_hash_map[T_SYNTAX] = hash_map_syntax;
  35085. default_hash_map[T_STRING] = hash_map_string;
  35086. default_hash_map[T_HASH_TABLE] = hash_map_hash_table;
  35087. default_hash_map[T_VECTOR] = hash_map_vector;
  35088. default_hash_map[T_INT_VECTOR] = hash_map_int_vector;
  35089. default_hash_map[T_FLOAT_VECTOR] = hash_map_float_vector;
  35090. default_hash_map[T_LET] = hash_map_let;
  35091. default_hash_map[T_PAIR] = hash_map_pair;
  35092. #if WITH_GMP
  35093. default_hash_map[T_BIG_INTEGER] = hash_map_big_int;
  35094. default_hash_map[T_BIG_RATIO] = hash_map_big_ratio;
  35095. default_hash_map[T_BIG_REAL] = hash_map_big_real;
  35096. default_hash_map[T_BIG_COMPLEX] = hash_map_big_complex;
  35097. #endif
  35098. for (i = 0; i < NUM_TYPES; i++) morally_equal_hash_map[i] = default_hash_map[i];
  35099. string_eq_hash_map[T_STRING] = hash_map_string;
  35100. char_eq_hash_map[T_CHARACTER] = hash_map_char;
  35101. #if (!WITH_PURE_S7)
  35102. string_ci_eq_hash_map[T_STRING] = hash_map_ci_string;
  35103. char_ci_eq_hash_map[T_CHARACTER] = hash_map_ci_char;
  35104. #endif
  35105. number_eq_hash_map[T_INTEGER] = hash_map_int;
  35106. number_eq_hash_map[T_RATIO] = hash_map_ratio_eq;
  35107. number_eq_hash_map[T_REAL] = hash_map_real_eq;
  35108. number_eq_hash_map[T_COMPLEX] = hash_map_complex;
  35109. #if (WITH_GMP)
  35110. number_eq_hash_map[T_BIG_INTEGER] = hash_map_big_int;
  35111. number_eq_hash_map[T_BIG_RATIO] = hash_map_big_ratio;
  35112. number_eq_hash_map[T_BIG_REAL] = hash_map_big_real;
  35113. number_eq_hash_map[T_BIG_COMPLEX] = hash_map_big_complex;
  35114. #endif
  35115. eqv_hash_map[T_INTEGER] = hash_map_int;
  35116. eqv_hash_map[T_RATIO] = hash_map_ratio_eq;
  35117. eqv_hash_map[T_REAL] = hash_map_real_eq;
  35118. eqv_hash_map[T_COMPLEX] = hash_map_complex;
  35119. morally_equal_hash_map[T_INTEGER] = hash_map_int;
  35120. morally_equal_hash_map[T_RATIO] = hash_map_ratio_eq;
  35121. morally_equal_hash_map[T_REAL] = hash_map_real_eq;
  35122. morally_equal_hash_map[T_COMPLEX] = hash_map_complex;
  35123. equal_hash_checks[T_REAL] = hash_equal_real;
  35124. equal_hash_checks[T_COMPLEX] = hash_equal_complex;
  35125. equal_hash_checks[T_SYNTAX] = hash_equal_syntax;
  35126. equal_hash_checks[T_SYMBOL] = hash_equal_eq;
  35127. equal_hash_checks[T_CHARACTER] = hash_equal_eq;
  35128. default_hash_checks[T_STRING] = hash_string;
  35129. default_hash_checks[T_INTEGER] = hash_int;
  35130. default_hash_checks[T_REAL] = hash_float;
  35131. default_hash_checks[T_SYMBOL] = hash_symbol;
  35132. default_hash_checks[T_CHARACTER] = hash_char;
  35133. }
  35134. static unsigned int resize_hash_table(s7_scheme *sc, s7_pointer table)
  35135. {
  35136. /* resize the table */
  35137. unsigned int hash_len, loc;
  35138. int i, old_size, new_size;
  35139. hash_entry_t **new_els, **old_els;
  35140. old_size = hash_table_mask(table) + 1;
  35141. new_size = old_size * 4;
  35142. hash_len = new_size - 1;
  35143. new_els = (hash_entry_t **)calloc(new_size, sizeof(hash_entry_t *));
  35144. old_els = hash_table_elements(table);
  35145. for (i = 0; i < old_size; i++)
  35146. {
  35147. hash_entry_t *x, *n;
  35148. for (x = old_els[i]; x; x = n)
  35149. {
  35150. n = x->next;
  35151. loc = x->raw_hash & hash_len;
  35152. x->next = new_els[loc];
  35153. new_els[loc] = x;
  35154. }
  35155. }
  35156. hash_table_elements(table) = new_els;
  35157. free(old_els);
  35158. hash_table_mask(table) = new_size - 1;
  35159. return(hash_len);
  35160. }
  35161. /* -------------------------------- hash-table-ref -------------------------------- */
  35162. s7_pointer s7_hash_table_ref(s7_scheme *sc, s7_pointer table, s7_pointer key)
  35163. {
  35164. hash_entry_t *x;
  35165. x = (*hash_table_checker(table))(sc, table, key);
  35166. if (x) return(x->value);
  35167. return(sc->F);
  35168. }
  35169. static s7_pointer g_hash_table_ref(s7_scheme *sc, s7_pointer args)
  35170. {
  35171. #define H_hash_table_ref "(hash-table-ref table key) returns the value associated with key in the hash table"
  35172. #define Q_hash_table_ref s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_hash_table_symbol, sc->T)
  35173. s7_pointer table;
  35174. table = car(args);
  35175. if (!is_hash_table(table))
  35176. method_or_bust(sc, table, sc->hash_table_ref_symbol, args, T_HASH_TABLE, 1);
  35177. /*
  35178. (define (href H . args)
  35179. (if (null? (cdr args))
  35180. (hash-table-ref H (car args))
  35181. (apply href (hash-table-ref H (car args)) (cdr args))))
  35182. */
  35183. if (is_null(cddr(args)))
  35184. return(s7_hash_table_ref(sc, table, cadr(args)));
  35185. return(implicit_index(sc, s7_hash_table_ref(sc, table, cadr(args)), cddr(args)));
  35186. }
  35187. static s7_pointer hash_table_ref_2;
  35188. static s7_pointer g_hash_table_ref_2(s7_scheme *sc, s7_pointer args)
  35189. {
  35190. s7_pointer table;
  35191. hash_entry_t *x;
  35192. table = car(args);
  35193. if (!is_hash_table(table))
  35194. method_or_bust(sc, table, sc->hash_table_ref_symbol, args, T_HASH_TABLE, 1);
  35195. x = (*hash_table_checker(table))(sc, table, cadr(args));
  35196. if (x) return(x->value);
  35197. return(sc->F);
  35198. }
  35199. static s7_pointer hash_table_ref_ss;
  35200. static s7_pointer g_hash_table_ref_ss(s7_scheme *sc, s7_pointer args)
  35201. {
  35202. s7_pointer table;
  35203. hash_entry_t *x;
  35204. table = find_symbol_checked(sc, car(args));
  35205. if (!is_hash_table(table))
  35206. method_or_bust(sc, table, sc->hash_table_ref_symbol, list_2(sc, table, find_symbol_checked(sc, cadr(args))), T_HASH_TABLE, 1);
  35207. x = (*hash_table_checker(table))(sc, table, find_symbol_checked(sc, cadr(args)));
  35208. if (x) return(x->value);
  35209. return(sc->F);
  35210. }
  35211. static s7_pointer hash_table_ref_car;
  35212. static s7_pointer g_hash_table_ref_car(s7_scheme *sc, s7_pointer args)
  35213. {
  35214. s7_pointer y, table;
  35215. hash_entry_t *x;
  35216. table = find_symbol_checked(sc, car(args));
  35217. if (!is_hash_table(table))
  35218. method_or_bust(sc, table, sc->hash_table_ref_symbol, list_2(sc, table, car(find_symbol_checked(sc, cadadr(args)))), T_HASH_TABLE, 1);
  35219. y = find_symbol_checked(sc, cadadr(args));
  35220. if (!is_pair(y))
  35221. return(simple_wrong_type_argument(sc, sc->car_symbol, y, T_PAIR));
  35222. x = (*hash_table_checker(table))(sc, table, car(y));
  35223. if (x) return(x->value);
  35224. return(sc->F);
  35225. }
  35226. static s7_pointer hash_table_ref_pf_a(s7_scheme *sc, s7_pointer **p)
  35227. {
  35228. s7_pf_t f;
  35229. s7_pointer x, y;
  35230. f = (s7_pf_t)(**p); (*p)++;
  35231. x = f(sc, p);
  35232. f = (s7_pf_t)(**p); (*p)++;
  35233. y = f(sc, p);
  35234. return(s7_hash_table_ref(sc, x, y));
  35235. }
  35236. static s7_pointer hash_table_ref_pf_i(s7_scheme *sc, s7_pointer **p) /* i=implicit I think */
  35237. {
  35238. s7_pf_t f;
  35239. s7_pointer x, y;
  35240. x = slot_value(**p); (*p)++;
  35241. f = (s7_pf_t)(**p); (*p)++;
  35242. y = f(sc, p);
  35243. return(s7_hash_table_ref(sc, x, y));
  35244. }
  35245. static s7_pointer hash_table_ref_pf_s(s7_scheme *sc, s7_pointer **p)
  35246. {
  35247. s7_pf_t f;
  35248. s7_pointer x, y;
  35249. hash_entry_t *h;
  35250. x = (**p); (*p)++;
  35251. f = (s7_pf_t)(**p); (*p)++;
  35252. y = f(sc, p);
  35253. h = (*hash_table_checker(x))(sc, x, y);
  35254. if (h) return(h->value);
  35255. return(sc->F);
  35256. }
  35257. static s7_pointer hash_table_ref_pf_ps(s7_scheme *sc, s7_pointer **p)
  35258. {
  35259. s7_pointer x, y;
  35260. x = (**p); (*p) += 2;
  35261. y = slot_value(**p); (*p)++;
  35262. return(s7_hash_table_ref(sc, x, y));
  35263. }
  35264. static s7_pointer hash_table_ref_pf_r(s7_scheme *sc, s7_pointer **p)
  35265. {
  35266. s7_rf_t f;
  35267. s7_pointer x;
  35268. s7_double y;
  35269. int hash_len;
  35270. hash_entry_t *h;
  35271. x = (**p); (*p)++;
  35272. f = (s7_rf_t)(**p); (*p)++;
  35273. y = f(sc, p);
  35274. hash_len = hash_table_mask(x);
  35275. h = hash_float_1(sc, x, hash_float_location(y) & hash_len, y);
  35276. if (h) return(h->value);
  35277. return(sc->F);
  35278. }
  35279. static s7_pf_t hash_table_ref_pf(s7_scheme *sc, s7_pointer expr)
  35280. {
  35281. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_null(cdddr(expr))))
  35282. {
  35283. s7_pointer a1;
  35284. a1 = cadr(expr);
  35285. if (is_symbol(a1))
  35286. {
  35287. s7_pointer table;
  35288. table = s7_slot(sc, a1);
  35289. if ((is_slot(table)) && (!is_stepper(table)) && (is_hash_table(slot_value(table))))
  35290. {
  35291. ptr_int loc;
  35292. s7_pointer a2;
  35293. a2 = caddr(expr);
  35294. s7_xf_store(sc, slot_value(table));
  35295. loc = rc_loc(sc);
  35296. if (s7_arg_to_pf(sc, a2))
  35297. return((is_symbol(a2)) ? hash_table_ref_pf_ps : hash_table_ref_pf_s);
  35298. sc->cur_rf->cur = rc_go(sc, loc);
  35299. if (s7_arg_to_gf(sc, a2))
  35300. return((is_symbol(a2)) ? hash_table_ref_pf_ps : hash_table_ref_pf_s);
  35301. sc->cur_rf->cur = rc_go(sc, loc);
  35302. if (s7_arg_to_rf(sc, a2))
  35303. return(hash_table_ref_pf_r);
  35304. return(NULL);
  35305. }
  35306. }
  35307. if ((s7_arg_to_pf(sc, cadr(expr))) &&
  35308. (s7_arg_to_pf(sc, caddr(expr))))
  35309. return(hash_table_ref_pf_a);
  35310. }
  35311. return(NULL);
  35312. }
  35313. /* -------------------------------- hash-table-set! -------------------------------- */
  35314. static void hash_table_set_function(s7_pointer table, int typ)
  35315. {
  35316. if ((hash_table_checker(table) != hash_equal) &&
  35317. (hash_table_checker(table) != default_hash_checks[typ]))
  35318. {
  35319. if (hash_table_checker(table) == hash_empty)
  35320. hash_table_checker(table) = default_hash_checks[typ];
  35321. else hash_table_checker(table) = hash_equal;
  35322. }
  35323. }
  35324. s7_pointer s7_hash_table_set(s7_scheme *sc, s7_pointer table, s7_pointer key, s7_pointer value)
  35325. {
  35326. hash_entry_t *x;
  35327. x = (*hash_table_checker(table))(sc, table, key);
  35328. if (x)
  35329. {
  35330. if (value == sc->F)
  35331. return(remove_from_hash_table(sc, table, key, x));
  35332. x->value = _NFre(value);
  35333. }
  35334. else
  35335. {
  35336. unsigned int hash_len, raw_hash, loc;
  35337. hash_entry_t *p;
  35338. if (value == sc->F) return(sc->F);
  35339. if (!hash_table_checker_locked(table))
  35340. hash_table_set_function(table, type(key));
  35341. hash_len = hash_table_mask(table);
  35342. if (hash_table_entries(table) > hash_len)
  35343. hash_len = resize_hash_table(sc, table);
  35344. raw_hash = hash_loc(sc, table, key);
  35345. if (!hash_free_list)
  35346. {
  35347. int i;
  35348. hash_free_list = (hash_entry_t *)malloc(16 * sizeof(hash_entry_t));
  35349. for (p = hash_free_list, i = 0; i < 15; i++) {p->next = p + 1; p++;}
  35350. p->next = NULL;
  35351. }
  35352. p = hash_free_list;
  35353. hash_free_list = p->next;
  35354. p->key = key;
  35355. p->value = _NFre(value);
  35356. p->raw_hash = raw_hash;
  35357. loc = raw_hash & hash_len;
  35358. p->next = hash_table_element(table, loc);
  35359. hash_table_element(table, loc) = p;
  35360. hash_table_entries(table)++;
  35361. }
  35362. return(value);
  35363. }
  35364. static s7_pointer hash_table_set_pf_sxs(s7_scheme *sc, s7_pointer **p)
  35365. {
  35366. s7_pointer key, table, value;
  35367. s7_pf_t pf;
  35368. table = slot_value(**p); (*p)++;
  35369. pf = (s7_pf_t)(**p); (*p)++;
  35370. key = pf(sc, p);
  35371. value = slot_value(**p); (*p)++;
  35372. return(s7_hash_table_set(sc, table, key, value));
  35373. }
  35374. static s7_pointer hash_table_set_pf_sxx(s7_scheme *sc, s7_pointer **p)
  35375. {
  35376. s7_pointer key, table, value;
  35377. s7_pf_t pf;
  35378. table = slot_value(**p); (*p)++;
  35379. pf = (s7_pf_t)(**p); (*p)++;
  35380. key = pf(sc, p);
  35381. pf = (s7_pf_t)(**p); (*p)++;
  35382. value = pf(sc, p);
  35383. return(s7_hash_table_set(sc, table, key, value));
  35384. }
  35385. static s7_pointer hash_table_set_pf_sss(s7_scheme *sc, s7_pointer **p)
  35386. {
  35387. s7_pointer key, table, value;
  35388. table = slot_value(**p); (*p)++;
  35389. key = slot_value(**p); (*p)++;
  35390. value = slot_value(**p); (*p)++;
  35391. return(s7_hash_table_set(sc, table, key, value));
  35392. }
  35393. static s7_pointer hash_table_set_pf_ssx(s7_scheme *sc, s7_pointer **p)
  35394. {
  35395. s7_pf_t pf;
  35396. s7_pointer key, table, value;
  35397. table = slot_value(**p); (*p)++;
  35398. key = slot_value(**p); (*p)++;
  35399. pf = (s7_pf_t)(**p); (*p)++;
  35400. value = pf(sc, p);
  35401. return(s7_hash_table_set(sc, table, key, value));
  35402. }
  35403. static s7_pf_t hash_table_set_pf(s7_scheme *sc, s7_pointer expr)
  35404. {
  35405. if ((is_pair(cdr(expr))) && (is_pair(cddr(expr))) && (is_pair(cdddr(expr))) && (is_null(cddddr(expr))))
  35406. {
  35407. s7_pointer a1, a2, a3;
  35408. a1 = cadr(expr);
  35409. a2 = caddr(expr);
  35410. a3 = cadddr(expr);
  35411. if (is_symbol(a1))
  35412. {
  35413. xf_t *rc;
  35414. a1 = s7_slot(sc, a1);
  35415. if ((!is_slot(a1)) || (!is_hash_table(slot_value(a1))) || (is_stepper(a1))) return(NULL);
  35416. xf_init(3);
  35417. xf_store(a1);
  35418. if (is_symbol(a2))
  35419. {
  35420. a2 = s7_slot(sc, a2);
  35421. if (!is_slot(a2)) return(NULL);
  35422. xf_store(a2);
  35423. }
  35424. else
  35425. {
  35426. ptr_int loc;
  35427. loc = rc_loc(sc);
  35428. if (!s7_arg_to_pf(sc, a2))
  35429. {
  35430. sc->cur_rf->cur = rc_go(sc, loc);
  35431. if (!s7_arg_to_gf(sc, a2)) return(NULL);
  35432. }
  35433. }
  35434. if (is_symbol(a3))
  35435. {
  35436. a3 = s7_slot(sc, a3);
  35437. if (!is_slot(a3)) return(NULL);
  35438. xf_store(a3);
  35439. return((is_slot(a2)) ? hash_table_set_pf_sss : hash_table_set_pf_sxs);
  35440. }
  35441. else
  35442. {
  35443. ptr_int loc;
  35444. loc = rc_loc(sc);
  35445. if (!s7_arg_to_pf(sc, a3))
  35446. {
  35447. sc->cur_rf->cur = rc_go(sc, loc);
  35448. if (!s7_arg_to_gf(sc, a3)) return(NULL);
  35449. }
  35450. return((is_slot(a2)) ? hash_table_set_pf_ssx : hash_table_set_pf_sxx);
  35451. }
  35452. }
  35453. }
  35454. return(NULL);
  35455. }
  35456. static s7_pointer g_hash_table_set(s7_scheme *sc, s7_pointer args)
  35457. {
  35458. #define H_hash_table_set "(hash-table-set! table key value) sets the value associated with key in the hash table to value"
  35459. #define Q_hash_table_set s7_make_signature(sc, 4, sc->T, sc->is_hash_table_symbol, sc->T, sc->T)
  35460. s7_pointer table;
  35461. table = car(args);
  35462. if (!is_hash_table(table))
  35463. method_or_bust(sc, table, sc->hash_table_set_symbol, args,T_HASH_TABLE, 1);
  35464. return(s7_hash_table_set(sc, table, cadr(args), caddr(args)));
  35465. }
  35466. /* -------------------------------- hash-table -------------------------------- */
  35467. static s7_pointer g_hash_table(s7_scheme *sc, s7_pointer args)
  35468. {
  35469. #define H_hash_table "(hash-table ...) returns a hash-table containing the cons's passed as its arguments. \
  35470. That is, (hash-table '(\"hi\" . 3) (\"ho\" . 32)) returns a new hash-table with the two key/value pairs preinstalled."
  35471. #define Q_hash_table s7_make_circular_signature(sc, 1, 2, sc->is_hash_table_symbol, sc->is_list_symbol)
  35472. int len;
  35473. s7_pointer x, ht;
  35474. /* this accepts repeated keys: (hash-table '(a . 1) '(a . 1)) */
  35475. for (len = 0, x = args; is_pair(x); x = cdr(x), len++)
  35476. if ((!is_pair(car(x))) &&
  35477. (!is_null(car(x))))
  35478. return(wrong_type_argument(sc, sc->hash_table_symbol, position_of(x, args), car(x), T_PAIR));
  35479. ht = s7_make_hash_table(sc, (len > sc->default_hash_table_length) ? len : sc->default_hash_table_length);
  35480. if (len > 0)
  35481. {
  35482. int ht_loc;
  35483. ht_loc = s7_gc_protect(sc, ht); /* hash_table_set can cons, so we need to protect this */
  35484. for (x = args; is_pair(x); x = cdr(x))
  35485. if (is_pair(car(x)))
  35486. s7_hash_table_set(sc, ht, caar(x), cdar(x));
  35487. s7_gc_unprotect_at(sc, ht_loc);
  35488. }
  35489. return(ht);
  35490. }
  35491. /* -------------------------------- hash-table* -------------------------------- */
  35492. static s7_pointer g_hash_table_star(s7_scheme *sc, s7_pointer args)
  35493. {
  35494. #define H_hash_table_star "(hash-table* ...) returns a hash-table containing the symbol/value pairs passed as its arguments. \
  35495. That is, (hash-table* 'a 1 'b 2) returns a new hash-table with the two key/value pairs preinstalled."
  35496. #define Q_hash_table_star s7_make_circular_signature(sc, 1, 2, sc->is_hash_table_symbol, sc->T)
  35497. int len;
  35498. s7_pointer ht;
  35499. len = safe_list_length(sc, args);
  35500. if (len & 1)
  35501. return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_2(sc, make_string_wrapper(sc, "hash-table* got an odd number of arguments: ~S"), args)));
  35502. len /= 2;
  35503. ht = s7_make_hash_table(sc, (len > sc->default_hash_table_length) ? len : sc->default_hash_table_length);
  35504. if (len > 0)
  35505. {
  35506. int ht_loc;
  35507. s7_pointer x, y;
  35508. ht_loc = s7_gc_protect(sc, ht); /* hash_table_set can cons, so we need to protect this */
  35509. for (x = args, y = cdr(args); is_pair(y); x = cddr(x), y = cddr(y))
  35510. s7_hash_table_set(sc, ht, car(x), car(y));
  35511. s7_gc_unprotect_at(sc, ht_loc);
  35512. }
  35513. return(ht);
  35514. }
  35515. static s7_pointer hash_table_copy(s7_scheme *sc, s7_pointer old_hash, s7_pointer new_hash, unsigned int start, unsigned int end)
  35516. {
  35517. unsigned int i, old_len, new_len, count = 0;
  35518. hash_entry_t **old_lists, **new_lists;
  35519. hash_entry_t *x, *p;
  35520. old_len = hash_table_mask(old_hash) + 1;
  35521. new_len = hash_table_mask(new_hash);
  35522. old_lists = hash_table_elements(old_hash);
  35523. new_lists = hash_table_elements(new_hash);
  35524. if (hash_table_entries(new_hash) == 0)
  35525. {
  35526. hash_table_checker(new_hash) = hash_table_checker(old_hash);
  35527. for (i = 0; i < old_len; i++)
  35528. for (x = old_lists[i]; x; x = x->next)
  35529. {
  35530. if (count >= end)
  35531. {
  35532. hash_table_entries(new_hash) = end - start;
  35533. return(new_hash);
  35534. }
  35535. if (count >= start)
  35536. {
  35537. unsigned int loc;
  35538. loc = x->raw_hash & new_len;
  35539. p = make_hash_entry(x->key, x->value, x->raw_hash);
  35540. p->next = new_lists[loc];
  35541. new_lists[loc] = p;
  35542. }
  35543. count++;
  35544. }
  35545. hash_table_entries(new_hash) = count - start;
  35546. return(new_hash);
  35547. }
  35548. /* this can't be optimized much because we have to look for key matches */
  35549. for (i = 0; i < old_len; i++)
  35550. for (x = old_lists[i]; x; x = x->next)
  35551. {
  35552. if (count >= end)
  35553. return(new_hash);
  35554. if (count >= start)
  35555. {
  35556. hash_entry_t *y;
  35557. y = (*hash_table_checker(new_hash))(sc, new_hash, x->key);
  35558. if (y)
  35559. y->value = x->value;
  35560. else
  35561. {
  35562. unsigned int loc;
  35563. loc = x->raw_hash & new_len;
  35564. p = make_hash_entry(x->key, x->value, x->raw_hash);
  35565. p->next = new_lists[loc];
  35566. new_lists[loc] = p;
  35567. hash_table_entries(new_hash)++;
  35568. if (!hash_table_checker_locked(new_hash))
  35569. hash_table_set_function(new_hash, type(x->key));
  35570. }
  35571. }
  35572. count++;
  35573. }
  35574. return(new_hash);
  35575. }
  35576. s7_pointer hash_table_fill(s7_scheme *sc, s7_pointer args)
  35577. {
  35578. s7_pointer val, table;
  35579. table = car(args);
  35580. val = cadr(args);
  35581. if (hash_table_entries(table) > 0)
  35582. {
  35583. int len;
  35584. hash_entry_t **entries;
  35585. entries = hash_table_elements(table);
  35586. len = hash_table_mask(table) + 1;
  35587. /* hash-table-ref returns #f if it can't find a key, so val == #f here means empty the table */
  35588. if (val == sc->F)
  35589. {
  35590. hash_entry_t **hp, **hn;
  35591. hash_entry_t *p;
  35592. hp = entries;
  35593. hn = (hash_entry_t **)(hp + len);
  35594. for (; hp < hn; hp++)
  35595. {
  35596. if (*hp)
  35597. {
  35598. p = *hp;
  35599. while (p->next) p = p->next;
  35600. p->next = hash_free_list;
  35601. hash_free_list = *hp;
  35602. }
  35603. hp++;
  35604. if (*hp)
  35605. {
  35606. p = *hp;
  35607. while (p->next) p = p->next;
  35608. p->next = hash_free_list;
  35609. hash_free_list = *hp;
  35610. }
  35611. }
  35612. memset(entries, 0, len * sizeof(hash_entry_t *));
  35613. if (!hash_table_checker_locked(table))
  35614. hash_table_checker(table) = hash_empty;
  35615. hash_table_entries(table) = 0;
  35616. }
  35617. else
  35618. {
  35619. int i;
  35620. hash_entry_t *x;
  35621. for (i = 0; i < len; i++)
  35622. for (x = entries[i]; x; x = x->next)
  35623. x->value = val;
  35624. /* keys haven't changed, so no need to mess with hash_table_checker */
  35625. }
  35626. }
  35627. return(val);
  35628. }
  35629. static s7_pointer hash_table_reverse(s7_scheme *sc, s7_pointer old_hash)
  35630. {
  35631. int i, len;
  35632. s7_pointer new_hash;
  35633. hash_entry_t **old_lists;
  35634. int gc_loc;
  35635. len = hash_table_mask(old_hash) + 1;
  35636. new_hash = s7_make_hash_table(sc, len);
  35637. gc_loc = s7_gc_protect(sc, new_hash);
  35638. /* I don't think the original hash functions can make any sense in general, so ignore them */
  35639. old_lists = hash_table_elements(old_hash);
  35640. for (i = 0; i < len; i++)
  35641. {
  35642. hash_entry_t *x;
  35643. for (x = old_lists[i]; x; x = x->next)
  35644. s7_hash_table_set(sc, new_hash, x->value, x->key);
  35645. }
  35646. s7_gc_unprotect_at(sc, gc_loc);
  35647. return(new_hash);
  35648. }
  35649. /* -------------------------------- functions -------------------------------- */
  35650. bool s7_is_function(s7_pointer p)
  35651. {
  35652. return(is_c_function(p));
  35653. }
  35654. static s7_pointer fallback_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  35655. {
  35656. return(f);
  35657. }
  35658. static void s7_function_set_class(s7_pointer f, s7_pointer base_f)
  35659. {
  35660. c_function_class(f) = c_function_class(base_f);
  35661. c_function_set_base(f, base_f);
  35662. }
  35663. static int c_functions = 0;
  35664. s7_pointer s7_make_function(s7_scheme *sc, const char *name, s7_function f, int required_args, int optional_args, bool rest_arg, const char *doc)
  35665. {
  35666. c_proc_t *ptr;
  35667. unsigned int ftype = T_C_FUNCTION;
  35668. s7_pointer x;
  35669. x = alloc_pointer();
  35670. unheap(x);
  35671. ptr = (c_proc_t *)malloc(sizeof(c_proc_t));
  35672. c_functions++;
  35673. if (required_args == 0)
  35674. {
  35675. if (rest_arg)
  35676. ftype = T_C_ANY_ARGS_FUNCTION;
  35677. else
  35678. {
  35679. if (optional_args != 0)
  35680. ftype = T_C_OPT_ARGS_FUNCTION;
  35681. /* a thunk needs to check for no args passed */
  35682. }
  35683. }
  35684. else
  35685. {
  35686. if (rest_arg)
  35687. ftype = T_C_RST_ARGS_FUNCTION;
  35688. }
  35689. set_type(x, ftype | T_PROCEDURE);
  35690. c_function_data(x) = ptr;
  35691. c_function_call(x) = f;
  35692. /* f is _TApp but needs cast */
  35693. c_function_set_base(x, x);
  35694. c_function_set_setter(x, sc->F);
  35695. c_function_name(x) = name; /* (procedure-name proc) => (format #f "~A" proc) */
  35696. c_function_name_length(x) = safe_strlen(name);
  35697. if (doc)
  35698. c_function_documentation(x) = make_permanent_string(doc);
  35699. else c_function_documentation(x) = NULL;
  35700. c_function_signature(x) = sc->F;
  35701. c_function_required_args(x) = required_args;
  35702. c_function_optional_args(x) = optional_args;
  35703. c_function_has_rest_arg(x) = rest_arg;
  35704. if (rest_arg)
  35705. c_function_all_args(x) = MAX_ARITY;
  35706. else c_function_all_args(x) = required_args + optional_args;
  35707. c_function_class(x) = ++sc->f_class;
  35708. c_function_chooser(x) = fallback_chooser;
  35709. c_function_rp(x) = NULL;
  35710. c_function_ip(x) = NULL;
  35711. c_function_pp(x) = NULL;
  35712. c_function_gp(x) = NULL;
  35713. return(x);
  35714. }
  35715. s7_pointer s7_make_safe_function(s7_scheme *sc, const char *name, s7_function f,
  35716. int required_args, int optional_args, bool rest_arg, const char *doc)
  35717. {
  35718. s7_pointer p;
  35719. p = s7_make_function(sc, name, f, required_args, optional_args, rest_arg, doc);
  35720. typeflag(p) |= T_SAFE_PROCEDURE; /* not set_type(p, type(p) ...) because that accidentally clears the T_PROCEDURE bit */
  35721. return(p);
  35722. }
  35723. s7_pointer s7_make_typed_function(s7_scheme *sc, const char *name, s7_function f,
  35724. int required_args, int optional_args, bool rest_arg, const char *doc, s7_pointer signature)
  35725. {
  35726. s7_pointer func;
  35727. func = s7_make_function(sc, name, f, required_args, optional_args, rest_arg, doc);
  35728. typeflag(func) |= T_SAFE_PROCEDURE;
  35729. if (signature) c_function_signature(func) = signature;
  35730. return(func);
  35731. }
  35732. bool s7_is_procedure(s7_pointer x)
  35733. {
  35734. return(is_procedure(x)); /* this returns "is applicable" so it is true for applicable c_objects, macros, etc */
  35735. }
  35736. static s7_pointer g_is_procedure(s7_scheme *sc, s7_pointer args)
  35737. {
  35738. #define H_is_procedure "(procedure? obj) returns #t if obj is a procedure"
  35739. #define Q_is_procedure pl_bt
  35740. s7_pointer x;
  35741. int typ;
  35742. x = car(args);
  35743. if ((!is_procedure(x)) || (is_c_object(x)))
  35744. {
  35745. check_method(sc, x, sc->is_procedure_symbol, args);
  35746. return(sc->F);
  35747. }
  35748. typ = type(x);
  35749. /* make_object sets the T_PROCEDURE bit if the object has an apply function,
  35750. * but we currently return (procedure? "hi") -> #f, so we can't simply use
  35751. * is_procedure.
  35752. *
  35753. * Unfortunately much C code depends on s7_is_procedure treating applicable
  35754. * objects and macros as procedures. We can use arity = applicable?
  35755. */
  35756. return(make_boolean(sc,
  35757. (typ == T_CLOSURE) ||
  35758. (typ == T_CLOSURE_STAR) ||
  35759. (typ >= T_C_FUNCTION_STAR) ||
  35760. (typ == T_GOTO) ||
  35761. (typ == T_CONTINUATION)));
  35762. }
  35763. static void s7_function_set_setter(s7_scheme *sc, const char *getter, const char *setter)
  35764. {
  35765. /* this is internal, used only with c_function setters, so we don't need to worry about the GC mark choice
  35766. */
  35767. c_function_set_setter(s7_name_to_value(sc, getter), s7_name_to_value(sc, setter));
  35768. }
  35769. s7_pointer s7_closure_body(s7_scheme *sc, s7_pointer p)
  35770. {
  35771. if (has_closure_let(p))
  35772. return(closure_body(p));
  35773. return(sc->nil);
  35774. }
  35775. s7_pointer s7_closure_let(s7_scheme *sc, s7_pointer p)
  35776. {
  35777. if (has_closure_let(p))
  35778. return(closure_let(p));
  35779. return(sc->nil);
  35780. }
  35781. s7_pointer s7_closure_args(s7_scheme *sc, s7_pointer p)
  35782. {
  35783. if (has_closure_let(p))
  35784. return(closure_args(p));
  35785. return(sc->nil);
  35786. }
  35787. static s7_pointer c_procedure_source(s7_scheme *sc, s7_pointer p)
  35788. {
  35789. /* make it look like a scheme-level lambda */
  35790. if (is_symbol(p))
  35791. {
  35792. p = s7_symbol_value(sc, p);
  35793. if (p == sc->undefined)
  35794. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "procedure-source arg, '~S, is unbound"), p)));
  35795. }
  35796. if ((is_c_function(p)) || (is_c_macro(p)))
  35797. return(sc->nil);
  35798. check_method(sc, p, sc->procedure_source_symbol, list_1(sc, p));
  35799. if (has_closure_let(p))
  35800. {
  35801. s7_pointer body;
  35802. body = closure_body(p);
  35803. if (is_safe_closure(body))
  35804. clear_safe_closure(body);
  35805. return(append_in_place(sc, list_2(sc, ((is_closure_star(p)) ||
  35806. (is_macro_star(p)) ||
  35807. (is_bacro_star(p))) ? sc->lambda_star_symbol : sc->lambda_symbol,
  35808. closure_args(p)), body));
  35809. }
  35810. if (!is_procedure(p))
  35811. return(simple_wrong_type_argument_with_type(sc, sc->procedure_source_symbol, p, make_string_wrapper(sc, "a procedure or a macro")));
  35812. return(sc->nil);
  35813. }
  35814. static s7_pointer g_procedure_source(s7_scheme *sc, s7_pointer args)
  35815. {
  35816. #define H_procedure_source "(procedure-source func) tries to return the definition of func"
  35817. #define Q_procedure_source s7_make_signature(sc, 2, sc->is_list_symbol, sc->is_procedure_symbol)
  35818. return(c_procedure_source(sc, car(args)));
  35819. }
  35820. PF_TO_PF(procedure_source, c_procedure_source)
  35821. s7_pointer s7_funclet(s7_scheme *sc, s7_pointer p)
  35822. {
  35823. if (has_closure_let(p))
  35824. return(closure_let(p));
  35825. return(sc->rootlet);
  35826. }
  35827. static s7_pointer g_funclet(s7_scheme *sc, s7_pointer args)
  35828. {
  35829. s7_pointer p, e;
  35830. #define H_funclet "(funclet func) tries to return an object's environment"
  35831. #define Q_funclet s7_make_signature(sc, 2, sc->is_let_symbol, sc->is_procedure_symbol)
  35832. /* this procedure gives direct access to a function's closure -- see s7test.scm
  35833. * for some wild examples. At least it provides a not-too-kludgey way for several functions
  35834. * to share a closure.
  35835. */
  35836. p = car(args);
  35837. if (is_symbol(p))
  35838. {
  35839. p = s7_symbol_value(sc, p);
  35840. if (p == sc->undefined)
  35841. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "funclet arg, '~S, is unbound"), car(args)))); /* not p here */
  35842. }
  35843. check_method(sc, p, sc->funclet_symbol, args);
  35844. if (!is_procedure_or_macro(p))
  35845. return(simple_wrong_type_argument_with_type(sc, sc->funclet_symbol, p, make_string_wrapper(sc, "a procedure or a macro")));
  35846. e = find_let(sc, p);
  35847. if ((is_null(e)) &&
  35848. (!is_c_object(p)))
  35849. return(sc->rootlet);
  35850. return(e);
  35851. }
  35852. s7_pointer s7_define_function(s7_scheme *sc, const char *name, s7_function fnc,
  35853. int required_args, int optional_args, bool rest_arg, const char *doc)
  35854. {
  35855. s7_pointer func, sym;
  35856. func = s7_make_function(sc, name, fnc, required_args, optional_args, rest_arg, doc);
  35857. sym = make_symbol(sc, name);
  35858. s7_define(sc, sc->nil, sym, func);
  35859. return(sym);
  35860. }
  35861. s7_pointer s7_define_safe_function(s7_scheme *sc, const char *name, s7_function fnc,
  35862. int required_args, int optional_args, bool rest_arg, const char *doc)
  35863. {
  35864. /* returns (string->symbol name), not the c_proc_t func */
  35865. s7_pointer func, sym;
  35866. func = s7_make_safe_function(sc, name, fnc, required_args, optional_args, rest_arg, doc);
  35867. sym = make_symbol(sc, name);
  35868. s7_define(sc, sc->nil, sym, func);
  35869. return(sym);
  35870. }
  35871. s7_pointer s7_define_typed_function(s7_scheme *sc, const char *name, s7_function fnc,
  35872. int required_args, int optional_args, bool rest_arg,
  35873. const char *doc, s7_pointer signature)
  35874. {
  35875. /* returns (string->symbol name), not the c_proc_t func */
  35876. s7_pointer func, sym;
  35877. func = s7_make_typed_function(sc, name, fnc, required_args, optional_args, rest_arg, doc, signature);
  35878. sym = make_symbol(sc, name);
  35879. s7_define(sc, sc->nil, sym, func);
  35880. return(sym);
  35881. }
  35882. s7_pointer s7_define_unsafe_typed_function(s7_scheme *sc, const char *name, s7_function fnc,
  35883. int required_args, int optional_args, bool rest_arg,
  35884. const char *doc, s7_pointer signature)
  35885. {
  35886. /* returns (string->symbol name), not the c_proc_t func */
  35887. s7_pointer func, sym;
  35888. func = s7_make_function(sc, name, fnc, required_args, optional_args, rest_arg, doc);
  35889. if (signature) c_function_signature(func) = signature;
  35890. sym = make_symbol(sc, name);
  35891. s7_define(sc, sc->nil, sym, func);
  35892. return(sym);
  35893. }
  35894. s7_pointer s7_define_macro(s7_scheme *sc, const char *name, s7_function fnc,
  35895. int required_args, int optional_args, bool rest_arg, const char *doc)
  35896. {
  35897. s7_pointer func, sym;
  35898. func = s7_make_function(sc, name, fnc, required_args, optional_args, rest_arg, doc);
  35899. set_type(func, T_C_MACRO | T_DONT_EVAL_ARGS); /* this used to include T_PROCEDURE */
  35900. sym = make_symbol(sc, name);
  35901. s7_define(sc, sc->nil, sym, func);
  35902. return(sym);
  35903. }
  35904. bool s7_is_macro(s7_scheme *sc, s7_pointer x)
  35905. {
  35906. return(is_any_macro(x));
  35907. }
  35908. static s7_pointer g_is_macro(s7_scheme *sc, s7_pointer args)
  35909. {
  35910. #define H_is_macro "(macro? arg) returns #t if 'arg' is a macro or a bacro"
  35911. #define Q_is_macro pl_bt
  35912. check_boolean_method(sc, is_any_macro, sc->is_macro_symbol, args);
  35913. }
  35914. static void define_function_star_1(s7_scheme *sc, const char *name, s7_function fnc, const char *arglist, const char *doc, bool safe)
  35915. {
  35916. s7_pointer func, sym, local_args, p;
  35917. char *internal_arglist;
  35918. int i, len, n_args, gc_loc;
  35919. s7_pointer *names, *defaults;
  35920. len = safe_strlen(arglist) + 8;
  35921. tmpbuf_malloc(internal_arglist, len);
  35922. snprintf(internal_arglist, len, "'(%s)", arglist);
  35923. local_args = s7_eval_c_string(sc, internal_arglist);
  35924. gc_loc = s7_gc_protect(sc, local_args);
  35925. tmpbuf_free(internal_arglist, len);
  35926. n_args = safe_list_length(sc, local_args); /* currently rest arg not supported, and we don't notice :allow-other-keys etc */
  35927. func = s7_make_function(sc, name, fnc, 0, n_args, false, doc);
  35928. if (safe)
  35929. set_type(func, T_C_FUNCTION_STAR | T_PROCEDURE | T_SAFE_PROCEDURE);
  35930. else set_type(func, T_C_FUNCTION_STAR | T_PROCEDURE);
  35931. c_function_call_args(func) = make_list(sc, n_args, sc->F);
  35932. s7_remove_from_heap(sc, c_function_call_args(func));
  35933. sym = make_symbol(sc, name);
  35934. s7_define(sc, sc->nil, sym, func);
  35935. names = (s7_pointer *)malloc(n_args * sizeof(s7_pointer));
  35936. c_function_arg_names(func) = names;
  35937. defaults = (s7_pointer *)malloc(n_args * sizeof(s7_pointer));
  35938. c_function_arg_defaults(func) = defaults;
  35939. set_simple_defaults(func);
  35940. for (p = local_args, i = 0; i < n_args; p = cdr(p), i++)
  35941. {
  35942. s7_pointer arg;
  35943. arg = car(p);
  35944. if (is_pair(arg))
  35945. {
  35946. names[i] = s7_make_keyword(sc, symbol_name(car(arg)));
  35947. defaults[i] = cadr(arg);
  35948. s7_remove_from_heap(sc, cadr(arg));
  35949. if ((is_symbol(defaults[i])) ||
  35950. (is_pair(defaults[i])))
  35951. {
  35952. clear_simple_defaults(func);
  35953. mark_function[T_C_FUNCTION_STAR] = mark_c_proc_star;
  35954. }
  35955. }
  35956. else
  35957. {
  35958. names[i] = s7_make_keyword(sc, symbol_name(arg));
  35959. defaults[i] = sc->F;
  35960. }
  35961. }
  35962. s7_gc_unprotect_at(sc, gc_loc);
  35963. }
  35964. void s7_define_function_star(s7_scheme *sc, const char *name, s7_function fnc, const char *arglist, const char *doc)
  35965. {
  35966. define_function_star_1(sc, name, fnc, arglist, doc, false);
  35967. }
  35968. void s7_define_safe_function_star(s7_scheme *sc, const char *name, s7_function fnc, const char *arglist, const char *doc)
  35969. {
  35970. define_function_star_1(sc, name, fnc, arglist, doc, true);
  35971. }
  35972. static s7_pointer set_c_function_call_args(s7_scheme *sc)
  35973. {
  35974. int i, j, n_args;
  35975. s7_pointer arg, par, call_args, func;
  35976. s7_pointer *df;
  35977. func = sc->code;
  35978. n_args = c_function_all_args(func);
  35979. call_args = c_function_call_args(func);
  35980. df = c_function_arg_defaults(func);
  35981. for (i = 0, par = call_args; is_pair(par); i++, par = cdr(par))
  35982. {
  35983. clear_checked(par);
  35984. set_car(par, df[i]);
  35985. }
  35986. df = c_function_arg_names(func);
  35987. for (i = 0, arg = sc->args, par = call_args; (i < n_args) && (is_pair(arg)); i++, arg = cdr(arg), par = cdr(par))
  35988. {
  35989. if (!is_keyword(car(arg)))
  35990. {
  35991. if (is_checked(par))
  35992. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, make_string_wrapper(sc, "parameter set twice, ~S in ~S"), car(par), sc->args)));
  35993. set_checked(par);
  35994. set_car(par, car(arg));
  35995. }
  35996. else
  35997. {
  35998. s7_pointer p;
  35999. for (j = 0, p = call_args; j < n_args; j++, p = cdr(p))
  36000. if (df[j] == car(arg))
  36001. break;
  36002. if (j == n_args)
  36003. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "~A: not a parameter name?"), car(arg))));
  36004. if (is_checked(p))
  36005. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_3(sc, make_string_wrapper(sc, "parameter set twice, ~S in ~S"), car(p), sc->args)));
  36006. set_checked(p);
  36007. arg = cdr(arg);
  36008. set_car(p, car(arg));
  36009. }
  36010. }
  36011. if (!is_null(arg))
  36012. return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->too_many_arguments_string, func, sc->args)));
  36013. if (!has_simple_defaults(func))
  36014. for (i = 0, par = call_args; i < n_args; i++, par = cdr(par))
  36015. if (!is_checked(par))
  36016. {
  36017. if (is_symbol(car(par)))
  36018. set_car(par, find_symbol_checked(sc, car(par)));
  36019. else
  36020. {
  36021. if (is_pair(car(par)))
  36022. set_car(par, s7_eval(sc, car(par), sc->nil));
  36023. }
  36024. }
  36025. return(call_args);
  36026. }
  36027. /* -------------------------------- procedure-documentation -------------------------------- */
  36028. static s7_pointer get_doc(s7_scheme *sc, s7_pointer x)
  36029. {
  36030. check_closure_for(sc, x, sc->documentation_symbol);
  36031. return(NULL);
  36032. }
  36033. const char *s7_procedure_documentation(s7_scheme *sc, s7_pointer x)
  36034. {
  36035. s7_pointer val;
  36036. if (is_symbol(x))
  36037. {
  36038. if ((symbol_has_help(x)) &&
  36039. (is_global(x)))
  36040. return(symbol_help(x));
  36041. x = s7_symbol_value(sc, x); /* this is needed by Snd */
  36042. }
  36043. if ((is_any_c_function(x)) ||
  36044. (is_c_macro(x)))
  36045. return((char *)c_function_documentation(x));
  36046. val = get_doc(sc, x);
  36047. if ((val) && (is_string(val)))
  36048. return(string_value(val));
  36049. return(NULL);
  36050. }
  36051. static s7_pointer c_procedure_documentation(s7_scheme *sc, s7_pointer p)
  36052. {
  36053. if (is_symbol(p))
  36054. {
  36055. if ((symbol_has_help(p)) &&
  36056. (is_global(p)))
  36057. return(s7_make_string(sc, symbol_help(p)));
  36058. p = s7_symbol_value(sc, p);
  36059. }
  36060. check_method(sc, p, sc->procedure_documentation_symbol, list_1(sc, p));
  36061. if ((!is_procedure(p)) &&
  36062. (!s7_is_macro(sc, p)))
  36063. return(simple_wrong_type_argument_with_type(sc, sc->procedure_documentation_symbol, p, a_procedure_string));
  36064. return(s7_make_string(sc, s7_procedure_documentation(sc, p)));
  36065. }
  36066. static s7_pointer g_procedure_documentation(s7_scheme *sc, s7_pointer args)
  36067. {
  36068. #define H_procedure_documentation "(procedure-documentation func) returns func's documentation string"
  36069. #define Q_procedure_documentation s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_procedure_symbol)
  36070. return(c_procedure_documentation(sc, car(args)));
  36071. }
  36072. PF_TO_PF(procedure_documentation, c_procedure_documentation)
  36073. /* -------------------------------- help -------------------------------- */
  36074. const char *s7_help(s7_scheme *sc, s7_pointer obj)
  36075. {
  36076. if (is_syntax(obj))
  36077. return(string_value(syntax_documentation(obj)));
  36078. if (is_symbol(obj))
  36079. {
  36080. /* here look for name */
  36081. if (s7_symbol_documentation(sc, obj))
  36082. return(s7_symbol_documentation(sc, obj));
  36083. obj = s7_symbol_value(sc, obj);
  36084. }
  36085. if (is_procedure_or_macro(obj))
  36086. return(s7_procedure_documentation(sc, obj));
  36087. /* if is string, apropos? (can scan symbol table) */
  36088. return(NULL);
  36089. }
  36090. static s7_pointer g_help(s7_scheme *sc, s7_pointer args)
  36091. {
  36092. #define H_help "(help obj) returns obj's documentation"
  36093. #define Q_help s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_boolean_symbol), sc->T)
  36094. const char *doc;
  36095. check_method(sc, car(args), sc->help_symbol, args);
  36096. doc = s7_help(sc, car(args));
  36097. if (!doc)
  36098. return(sc->F);
  36099. return(s7_make_string(sc, doc));
  36100. }
  36101. static s7_pointer c_help(s7_scheme *sc, s7_pointer x) {return(g_help(sc, set_plist_1(sc, x)));}
  36102. PF_TO_PF(help, c_help)
  36103. /* -------------------------------- procedure-signature -------------------------------- */
  36104. static s7_pointer get_signature(s7_scheme *sc, s7_pointer x)
  36105. {
  36106. check_closure_for(sc, x, sc->signature_symbol);
  36107. return(sc->F);
  36108. }
  36109. static s7_pointer s7_procedure_signature(s7_scheme *sc, s7_pointer x)
  36110. {
  36111. if ((is_any_c_function(x)) ||
  36112. (is_c_macro(x)))
  36113. return((s7_pointer)c_function_signature(x));
  36114. return(get_signature(sc, x));
  36115. }
  36116. static s7_pointer c_procedure_signature(s7_scheme *sc, s7_pointer p)
  36117. {
  36118. if (is_symbol(p))
  36119. {
  36120. p = s7_symbol_value(sc, p);
  36121. if (p == sc->undefined)
  36122. return(sc->F);
  36123. }
  36124. check_method(sc, p, sc->procedure_signature_symbol, list_1(sc, p));
  36125. if (!is_procedure(p))
  36126. return(sc->F);
  36127. return(s7_procedure_signature(sc, p));
  36128. }
  36129. static s7_pointer g_procedure_signature(s7_scheme *sc, s7_pointer args)
  36130. {
  36131. #define H_procedure_signature "(procedure-signature func) returns func's signature"
  36132. #define Q_procedure_signature s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_boolean_symbol), sc->T)
  36133. return(c_procedure_signature(sc, car(args)));
  36134. }
  36135. PF_TO_PF(procedure_signature, c_procedure_signature)
  36136. /* -------------------------------- new types (c_objects) -------------------------------- */
  36137. static void fallback_free(void *value) {}
  36138. static void fallback_mark(void *value) {}
  36139. static char *fallback_print(s7_scheme *sc, void *val)
  36140. {
  36141. return(copy_string("#<unprintable object>"));
  36142. }
  36143. static char *fallback_print_readably(s7_scheme *sc, void *val)
  36144. {
  36145. return(copy_string("#<unprint-readable object>"));
  36146. }
  36147. static bool fallback_equal(void *val1, void *val2)
  36148. {
  36149. return(val1 == val2);
  36150. }
  36151. static s7_pointer fallback_ref(s7_scheme *sc, s7_pointer obj, s7_pointer args)
  36152. {
  36153. return(apply_error(sc, obj, args));
  36154. }
  36155. static s7_pointer fallback_set(s7_scheme *sc, s7_pointer obj, s7_pointer args)
  36156. {
  36157. eval_error(sc, "attempt to set ~S?", obj);
  36158. }
  36159. static s7_pointer fallback_length(s7_scheme *sc, s7_pointer obj)
  36160. {
  36161. return(sc->F);
  36162. }
  36163. bool s7_is_object(s7_pointer p)
  36164. {
  36165. return(is_c_object(p));
  36166. }
  36167. static s7_pointer g_is_c_object(s7_scheme *sc, s7_pointer args)
  36168. {
  36169. #define H_is_c_object "(c-object? obj) returns the object's type tag if obj is a C object, otherwise #f"
  36170. #define Q_is_c_object pl_bt
  36171. s7_pointer p;
  36172. p = car(args);
  36173. if (is_c_object(p))
  36174. return(make_integer(sc, c_object_type(p))); /* this is the object_types table index = tag */
  36175. check_method(sc, p, sc->is_c_object_symbol, args);
  36176. return(sc->F);
  36177. /* <1> (*s7* 'c-types)
  36178. ("<random-number-generator>")
  36179. <2> (c-object? (random-state 123))
  36180. 0
  36181. */
  36182. }
  36183. static s7_pointer g_internal_object_set(s7_scheme *sc, s7_pointer args)
  36184. {
  36185. return((*(c_object_set(car(args))))(sc, car(args), cdr(args)));
  36186. }
  36187. int s7_new_type(const char *name,
  36188. char *(*print)(s7_scheme *sc, void *value),
  36189. void (*gc_free)(void *value),
  36190. bool (*equal)(void *val1, void *val2),
  36191. void (*gc_mark)(void *val),
  36192. s7_pointer (*ref)(s7_scheme *sc, s7_pointer obj, s7_pointer args),
  36193. s7_pointer (*set)(s7_scheme *sc, s7_pointer obj, s7_pointer args))
  36194. {
  36195. int tag;
  36196. tag = num_object_types++;
  36197. if (tag >= object_types_size)
  36198. {
  36199. if (object_types_size == 0)
  36200. {
  36201. object_types_size = 8;
  36202. object_types = (c_object_t **)calloc(object_types_size, sizeof(c_object_t *));
  36203. }
  36204. else
  36205. {
  36206. object_types_size = tag + 8;
  36207. object_types = (c_object_t **)realloc((void *)object_types, object_types_size * sizeof(c_object_t *));
  36208. }
  36209. }
  36210. object_types[tag] = (c_object_t *)calloc(1, sizeof(c_object_t));
  36211. object_types[tag]->type = tag;
  36212. object_types[tag]->name = copy_string(name);
  36213. object_types[tag]->scheme_name = s7_make_permanent_string(name);
  36214. object_types[tag]->free = (gc_free) ? gc_free : fallback_free;
  36215. object_types[tag]->print = (print) ? print : fallback_print;
  36216. object_types[tag]->equal = (equal) ? equal : fallback_equal;
  36217. object_types[tag]->gc_mark = (gc_mark) ? gc_mark : fallback_mark;
  36218. object_types[tag]->ref = (ref) ? ref : fallback_ref;
  36219. object_types[tag]->set = (set) ? set : fallback_set;
  36220. if (object_types[tag]->ref != fallback_ref)
  36221. object_types[tag]->outer_type = (T_C_OBJECT | T_PROCEDURE | T_SAFE_PROCEDURE);
  36222. else object_types[tag]->outer_type = T_C_OBJECT;
  36223. object_types[tag]->length = fallback_length;
  36224. object_types[tag]->copy = NULL;
  36225. object_types[tag]->reverse = NULL;
  36226. object_types[tag]->fill = NULL;
  36227. object_types[tag]->print_readably = fallback_print_readably;
  36228. object_types[tag]->ip = NULL;
  36229. object_types[tag]->rp = NULL;
  36230. object_types[tag]->set_ip = NULL;
  36231. object_types[tag]->set_rp = NULL;
  36232. return(tag);
  36233. }
  36234. int s7_new_type_x(s7_scheme *sc,
  36235. const char *name,
  36236. char *(*print)(s7_scheme *sc, void *value),
  36237. void (*free)(void *value),
  36238. bool (*equal)(void *val1, void *val2),
  36239. void (*gc_mark)(void *val),
  36240. s7_pointer (*apply)(s7_scheme *sc, s7_pointer obj, s7_pointer args),
  36241. s7_pointer (*set)(s7_scheme *sc, s7_pointer obj, s7_pointer args),
  36242. s7_pointer (*length)(s7_scheme *sc, s7_pointer obj),
  36243. s7_pointer (*copy)(s7_scheme *sc, s7_pointer args),
  36244. s7_pointer (*reverse)(s7_scheme *sc, s7_pointer args),
  36245. s7_pointer (*fill)(s7_scheme *sc, s7_pointer args))
  36246. {
  36247. int tag;
  36248. tag = s7_new_type(name, print, free, equal, gc_mark, apply, set);
  36249. if (length)
  36250. object_types[tag]->length = length;
  36251. else object_types[tag]->length = fallback_length;
  36252. object_types[tag]->copy = copy;
  36253. object_types[tag]->reverse = reverse;
  36254. object_types[tag]->fill = fill;
  36255. return(tag);
  36256. }
  36257. static void free_object(s7_pointer a)
  36258. {
  36259. (*(c_object_free(a)))(c_object_value(a));
  36260. }
  36261. static bool objects_are_equal(s7_scheme *sc, s7_pointer a, s7_pointer b)
  36262. {
  36263. return((c_object_type(a) == c_object_type(b)) &&
  36264. ((*(c_object_eql(a)))(c_object_value(a), c_object_value(b))));
  36265. }
  36266. void *s7_object_value(s7_pointer obj)
  36267. {
  36268. return(c_object_value(obj));
  36269. }
  36270. void *s7_object_value_checked(s7_pointer obj, int type)
  36271. {
  36272. if ((is_c_object(obj)) &&
  36273. (c_object_type(obj) == type))
  36274. return(c_object_value(obj));
  36275. return(NULL);
  36276. }
  36277. void s7_set_object_print_readably(int type, char *(*printer)(s7_scheme *sc, void *val))
  36278. {
  36279. object_types[type]->print_readably = printer;
  36280. }
  36281. int s7_object_type(s7_pointer obj)
  36282. {
  36283. if (is_c_object(obj))
  36284. return(c_object_type(obj));
  36285. return(-1);
  36286. }
  36287. s7_pointer s7_make_object(s7_scheme *sc, int type, void *value)
  36288. {
  36289. s7_pointer x;
  36290. new_cell(sc, x, object_types[type]->outer_type);
  36291. /* c_object_info(x) = &(object_types[type]); */
  36292. /* that won't work because object_types can move when it is realloc'd and the old stuff is freed by realloc
  36293. * and since we're checking (for example) ref_2 existence as not null, we can't use a table of c_object_t's!
  36294. */
  36295. c_object_type(x) = type;
  36296. c_object_value(x) = value;
  36297. c_object_set_let(x, sc->nil);
  36298. add_c_object(sc, x);
  36299. return(x);
  36300. }
  36301. s7_pointer s7_object_let(s7_pointer obj)
  36302. {
  36303. return(c_object_let(obj));
  36304. }
  36305. s7_pointer s7_object_set_let(s7_pointer obj, s7_pointer e)
  36306. {
  36307. c_object_set_let(obj, e);
  36308. return(e);
  36309. }
  36310. void s7_object_type_set_xf(int tag, s7_ip_t ip, s7_ip_t set_ip, s7_rp_t rp, s7_rp_t set_rp)
  36311. {
  36312. object_types[tag]->ip = ip;
  36313. object_types[tag]->rp = rp;
  36314. object_types[tag]->set_ip = set_ip;
  36315. object_types[tag]->set_rp = set_rp;
  36316. }
  36317. void s7_object_type_set_direct(int tag,
  36318. s7_pointer (*dref)(s7_scheme *sc, s7_pointer obj, s7_int index),
  36319. s7_pointer (*dset)(s7_scheme *sc, s7_pointer obj, s7_int index, s7_pointer val))
  36320. {
  36321. object_types[tag]->direct_ref = dref;
  36322. object_types[tag]->direct_set = dset;
  36323. }
  36324. static s7_pointer object_length(s7_scheme *sc, s7_pointer obj)
  36325. {
  36326. if (c_object_length(obj))
  36327. return((*(c_object_length(obj)))(sc, obj));
  36328. eval_error(sc, "attempt to get length of ~S?", obj);
  36329. }
  36330. static s7_int object_length_to_int(s7_scheme *sc, s7_pointer obj)
  36331. {
  36332. if (c_object_length(obj))
  36333. {
  36334. s7_pointer res;
  36335. res = (*(c_object_length(obj)))(sc, obj);
  36336. if (s7_is_integer(res))
  36337. return(s7_integer(res));
  36338. }
  36339. return(-1);
  36340. }
  36341. static s7_pointer object_copy(s7_scheme *sc, s7_pointer args)
  36342. {
  36343. s7_pointer obj;
  36344. obj = car(args);
  36345. check_method(sc, obj, sc->copy_symbol, args);
  36346. if (c_object_copy(obj))
  36347. return((*(c_object_copy(obj)))(sc, args));
  36348. eval_error(sc, "attempt to copy ~S?", obj);
  36349. }
  36350. /* -------- dilambda -------- */
  36351. s7_pointer s7_dilambda(s7_scheme *sc,
  36352. const char *name,
  36353. s7_pointer (*getter)(s7_scheme *sc, s7_pointer args),
  36354. int get_req_args, int get_opt_args,
  36355. s7_pointer (*setter)(s7_scheme *sc, s7_pointer args),
  36356. int set_req_args, int set_opt_args,
  36357. const char *documentation)
  36358. {
  36359. s7_pointer get_func, set_func;
  36360. char *internal_set_name;
  36361. int len;
  36362. len = 16 + safe_strlen(name);
  36363. internal_set_name = (char *)malloc(len * sizeof(char));
  36364. snprintf(internal_set_name, len, "[set-%s]", name);
  36365. get_func = s7_make_safe_function(sc, name, getter, get_req_args, get_opt_args, false, documentation);
  36366. s7_define(sc, sc->nil, make_symbol(sc, name), get_func);
  36367. set_func = s7_make_function(sc, internal_set_name, setter, set_req_args, set_opt_args, false, documentation);
  36368. c_function_set_setter(get_func, set_func);
  36369. return(get_func);
  36370. }
  36371. s7_pointer s7_typed_dilambda(s7_scheme *sc,
  36372. const char *name,
  36373. s7_pointer (*getter)(s7_scheme *sc, s7_pointer args),
  36374. int get_req_args, int get_opt_args,
  36375. s7_pointer (*setter)(s7_scheme *sc, s7_pointer args),
  36376. int set_req_args, int set_opt_args,
  36377. const char *documentation,
  36378. s7_pointer get_sig, s7_pointer set_sig)
  36379. {
  36380. s7_pointer get_func, set_func;
  36381. get_func = s7_dilambda(sc, name, getter, get_req_args, get_opt_args, setter, set_req_args, set_opt_args, documentation);
  36382. set_func = c_function_setter(get_func);
  36383. if (get_sig) c_function_signature(get_func) = get_sig;
  36384. if (set_sig) c_function_signature(set_func) = set_sig;
  36385. return(get_func);
  36386. }
  36387. bool s7_is_dilambda(s7_pointer obj)
  36388. {
  36389. return(((is_c_function(obj)) &&
  36390. (is_c_function(c_function_setter(obj)))) ||
  36391. ((is_any_closure(obj)) &&
  36392. (is_procedure(closure_setter(obj)))));
  36393. }
  36394. static s7_pointer g_is_dilambda(s7_scheme *sc, s7_pointer args)
  36395. {
  36396. #define H_is_dilambda "(dilambda? obj) returns #t if obj is a procedure with setter."
  36397. #define Q_is_dilambda pl_bt
  36398. check_boolean_method(sc, s7_is_dilambda, sc->is_dilambda_symbol, args);
  36399. }
  36400. static s7_pointer c_set_setter(s7_scheme *sc, s7_pointer p, s7_pointer setter)
  36401. {
  36402. switch (type(p))
  36403. {
  36404. case T_MACRO: case T_MACRO_STAR:
  36405. case T_BACRO: case T_BACRO_STAR:
  36406. case T_CLOSURE: case T_CLOSURE_STAR:
  36407. closure_set_setter(p, setter);
  36408. break;
  36409. case T_C_FUNCTION:
  36410. case T_C_ANY_ARGS_FUNCTION:
  36411. case T_C_OPT_ARGS_FUNCTION:
  36412. case T_C_RST_ARGS_FUNCTION:
  36413. c_function_set_setter(p, setter);
  36414. if (is_any_closure(setter))
  36415. add_setter(sc, p, setter);
  36416. break;
  36417. case T_C_FUNCTION_STAR:
  36418. c_function_set_setter(p, setter);
  36419. if (is_any_closure(setter))
  36420. add_setter(sc, p, setter);
  36421. break;
  36422. case T_C_MACRO:
  36423. if (is_any_closure(setter))
  36424. add_setter(sc, p, setter);
  36425. c_macro_set_setter(p, setter);
  36426. break;
  36427. }
  36428. return(setter);
  36429. }
  36430. static s7_pointer g_dilambda(s7_scheme *sc, s7_pointer args)
  36431. {
  36432. #define H_dilambda "(dilambda getter setter) sets getter's procedure-setter to be setter."
  36433. #define Q_dilambda s7_make_signature(sc, 3, sc->is_procedure_symbol, sc->is_procedure_symbol, sc->is_procedure_symbol)
  36434. s7_pointer getter, setter;
  36435. getter = car(args);
  36436. if (!is_any_procedure(getter))
  36437. return(wrong_type_argument_with_type(sc, sc->dilambda_symbol, 1, getter, make_string_wrapper(sc, "a procedure or macro")));
  36438. setter = cadr(args);
  36439. if (!is_any_procedure(setter))
  36440. return(wrong_type_argument_with_type(sc, sc->dilambda_symbol, 2, setter, make_string_wrapper(sc, "a procedure or macro")));
  36441. c_set_setter(sc, getter, setter);
  36442. return(getter);
  36443. }
  36444. s7_pointer s7_procedure_setter(s7_scheme *sc, s7_pointer obj)
  36445. {
  36446. if (is_c_function(obj))
  36447. return(c_function_setter(obj));
  36448. return(closure_setter(obj));
  36449. }
  36450. static s7_pointer g_procedure_setter(s7_scheme *sc, s7_pointer args)
  36451. {
  36452. #define H_procedure_setter "(procedure-setter obj) returns the setter associated with obj, or #f"
  36453. #define Q_procedure_setter s7_make_signature(sc, 2, sc->T, sc->is_procedure_symbol)
  36454. s7_pointer p;
  36455. p = car(args);
  36456. switch (type(p))
  36457. {
  36458. case T_MACRO: case T_MACRO_STAR:
  36459. case T_BACRO: case T_BACRO_STAR:
  36460. case T_CLOSURE: case T_CLOSURE_STAR:
  36461. return(closure_setter(p));
  36462. case T_C_FUNCTION:
  36463. case T_C_FUNCTION_STAR:
  36464. case T_C_ANY_ARGS_FUNCTION:
  36465. case T_C_OPT_ARGS_FUNCTION:
  36466. case T_C_RST_ARGS_FUNCTION:
  36467. return(c_function_setter(p));
  36468. case T_C_MACRO:
  36469. return(c_macro_setter(p));
  36470. case T_GOTO:
  36471. case T_CONTINUATION:
  36472. return(sc->F);
  36473. case T_LET:
  36474. case T_C_OBJECT:
  36475. check_method(sc, p, s7_make_symbol(sc, "procedure-setter"), args);
  36476. break;
  36477. case T_ITERATOR:
  36478. if (is_any_closure(iterator_sequence(p)))
  36479. return(closure_setter(iterator_sequence(p)));
  36480. return(sc->F);
  36481. }
  36482. return(s7_wrong_type_arg_error(sc, "procedure-setter", 0, p, "a procedure or a reasonable facsimile thereof"));
  36483. }
  36484. static s7_pointer g_procedure_set_setter(s7_scheme *sc, s7_pointer args)
  36485. {
  36486. s7_pointer p, setter;
  36487. p = car(args);
  36488. if (!is_any_procedure(p))
  36489. return(s7_wrong_type_arg_error(sc, "set! procedure-setter procedure", 1, p, "a procedure"));
  36490. setter = cadr(args);
  36491. if ((setter != sc->F) &&
  36492. (!is_any_procedure(setter)))
  36493. return(s7_wrong_type_arg_error(sc, "set! procedure-setter setter", 2, setter, "a procedure or #f"));
  36494. /* should we check that p != setter?
  36495. * :(set! (procedure-setter <) <)
  36496. * <
  36497. * :(set! (< 3 2) 3)
  36498. * #f
  36499. * :(set! (< 1) 2)
  36500. * #t
  36501. * can this make sense?
  36502. */
  36503. return(c_set_setter(sc, p, setter));
  36504. }
  36505. void s7_define_function_with_setter(s7_scheme *sc, const char *name, s7_function get_fnc, s7_function set_fnc, int req_args, int opt_args, const char *doc)
  36506. {
  36507. s7_dilambda(sc, name, get_fnc, req_args, opt_args, set_fnc, req_args + 1, opt_args, doc);
  36508. }
  36509. /* -------------------------------- arity -------------------------------- */
  36510. static s7_pointer closure_arity_to_cons(s7_scheme *sc, s7_pointer x, s7_pointer x_args)
  36511. {
  36512. /* x_args is unprocessed -- it is exactly the list as used in the closure[*] definition
  36513. */
  36514. int len;
  36515. if (is_symbol(x_args)) /* any number of args is ok */
  36516. return(s7_cons(sc, small_int(0), max_arity));
  36517. if (closure_arity_unknown(x))
  36518. closure_arity(x) = s7_list_length(sc, x_args);
  36519. len = closure_arity(x);
  36520. if (len < 0) /* dotted list => rest arg, (length '(a b . c)) is -2 */
  36521. return(s7_cons(sc, s7_make_integer(sc, -len), max_arity));
  36522. return(s7_cons(sc, s7_make_integer(sc, len), s7_make_integer(sc, len)));
  36523. }
  36524. static void closure_star_arity_1(s7_scheme *sc, s7_pointer x, s7_pointer args)
  36525. {
  36526. if (closure_arity_unknown(x))
  36527. {
  36528. if (is_null(args))
  36529. closure_arity(x) = 0;
  36530. else
  36531. {
  36532. if (allows_other_keys(args))
  36533. closure_arity(x) = -1;
  36534. else
  36535. {
  36536. s7_pointer p;
  36537. int i;
  36538. for (i = 0, p = args; is_pair(p); p = cdr(p))
  36539. {
  36540. s7_pointer arg;
  36541. arg = car(p);
  36542. if (arg == sc->key_rest_symbol)
  36543. break;
  36544. i++;
  36545. }
  36546. if (is_null(p))
  36547. closure_arity(x) = i;
  36548. else closure_arity(x) = -1; /* see below */
  36549. }
  36550. }
  36551. }
  36552. }
  36553. static s7_pointer closure_star_arity_to_cons(s7_scheme *sc, s7_pointer x, s7_pointer x_args)
  36554. {
  36555. if (is_symbol(x_args))
  36556. return(s7_cons(sc, small_int(0), max_arity));
  36557. closure_star_arity_1(sc, x, x_args);
  36558. if (closure_arity(x) == -1)
  36559. return(s7_cons(sc, small_int(0), max_arity));
  36560. return(s7_cons(sc, small_int(0), s7_make_integer(sc, closure_arity(x))));
  36561. }
  36562. static int closure_arity_to_int(s7_scheme *sc, s7_pointer x)
  36563. {
  36564. /* not lambda* here */
  36565. if (closure_arity_unknown(x))
  36566. {
  36567. int i;
  36568. s7_pointer b;
  36569. for (i = 0, b = closure_args(x); is_pair(b); i++, b = cdr(b)) {};
  36570. if (is_null(b))
  36571. closure_arity(x) = i;
  36572. else
  36573. {
  36574. if (i == 0)
  36575. return(-1);
  36576. closure_arity(x) = -i;
  36577. }
  36578. }
  36579. return(closure_arity(x));
  36580. }
  36581. static int closure_star_arity_to_int(s7_scheme *sc, s7_pointer x)
  36582. {
  36583. /* not lambda here */
  36584. closure_star_arity_1(sc, x, closure_args(x));
  36585. return(closure_arity(x));
  36586. }
  36587. s7_pointer s7_arity(s7_scheme *sc, s7_pointer x)
  36588. {
  36589. switch (type(x))
  36590. {
  36591. case T_C_OPT_ARGS_FUNCTION:
  36592. case T_C_RST_ARGS_FUNCTION:
  36593. case T_C_FUNCTION:
  36594. return(s7_cons(sc, s7_make_integer(sc, c_function_required_args(x)), s7_make_integer(sc, c_function_all_args(x))));
  36595. case T_C_ANY_ARGS_FUNCTION:
  36596. case T_C_FUNCTION_STAR:
  36597. return(s7_cons(sc, small_int(0), s7_make_integer(sc, c_function_all_args(x)))); /* should this be *2? */
  36598. case T_MACRO:
  36599. case T_BACRO:
  36600. case T_CLOSURE:
  36601. return(closure_arity_to_cons(sc, x, closure_args(x)));
  36602. case T_MACRO_STAR:
  36603. case T_BACRO_STAR:
  36604. case T_CLOSURE_STAR:
  36605. return(closure_star_arity_to_cons(sc, x, closure_args(x)));
  36606. case T_C_MACRO:
  36607. return(s7_cons(sc, s7_make_integer(sc, c_macro_required_args(x)), s7_make_integer(sc, c_macro_all_args(x))));
  36608. case T_GOTO:
  36609. case T_CONTINUATION:
  36610. return(s7_cons(sc, small_int(0), max_arity));
  36611. case T_STRING:
  36612. if (string_length(x) == 0)
  36613. return(sc->F);
  36614. case T_LET:
  36615. /* check_method(sc, x, sc->arity_symbol, args); */
  36616. return(s7_cons(sc, small_int(1), small_int(1)));
  36617. case T_C_OBJECT:
  36618. /* check_method(sc, x, sc->arity_symbol, args); */
  36619. if (is_procedure(x))
  36620. return(s7_cons(sc, small_int(0), max_arity));
  36621. return(sc->F);
  36622. case T_INT_VECTOR:
  36623. case T_FLOAT_VECTOR:
  36624. case T_VECTOR:
  36625. if (vector_length(x) == 0)
  36626. return(sc->F);
  36627. case T_PAIR:
  36628. case T_HASH_TABLE:
  36629. return(s7_cons(sc, small_int(1), max_arity));
  36630. case T_ITERATOR:
  36631. return(s7_cons(sc, small_int(0), small_int(0)));
  36632. case T_SYNTAX:
  36633. return(s7_cons(sc, small_int(syntax_min_args(x)), (syntax_max_args(x) == -1) ? max_arity : small_int(syntax_max_args(x))));
  36634. }
  36635. return(sc->F);
  36636. }
  36637. static s7_pointer g_arity(s7_scheme *sc, s7_pointer args)
  36638. {
  36639. #define H_arity "(arity obj) the min and max acceptable args for obj if it is applicable, otherwise #f."
  36640. #define Q_arity pcl_t
  36641. /* check_method(sc, p, sc->arity_symbol, args); */
  36642. return(s7_arity(sc, car(args)));
  36643. }
  36644. PF_TO_PF(arity, s7_arity)
  36645. static bool closure_is_aritable(s7_scheme *sc, s7_pointer x, s7_pointer x_args, int args)
  36646. {
  36647. /* x_args is unprocessed -- it is exactly the list as used in the closure definition
  36648. */
  36649. int len;
  36650. if (args == 0)
  36651. return(!is_pair(x_args));
  36652. if (is_symbol(x_args)) /* any number of args is ok */
  36653. return(true);
  36654. len = closure_arity(x);
  36655. if (len == CLOSURE_ARITY_NOT_SET)
  36656. {
  36657. len = s7_list_length(sc, x_args);
  36658. closure_arity(x) = len;
  36659. }
  36660. if (len < 0) /* dotted list => rest arg, (length '(a b . c)) is -2 */
  36661. return((-len) <= args); /* so we have enough to take care of the required args */
  36662. return(args == len); /* in a normal lambda list, there are no other possibilities */
  36663. }
  36664. static bool closure_star_is_aritable(s7_scheme *sc, s7_pointer x, s7_pointer x_args, int args)
  36665. {
  36666. if (is_symbol(x_args))
  36667. return(true);
  36668. closure_star_arity_1(sc, x, x_args);
  36669. return((closure_arity(x) == -1) ||
  36670. (args <= closure_arity(x)));
  36671. }
  36672. bool s7_is_aritable(s7_scheme *sc, s7_pointer x, int args)
  36673. {
  36674. switch (type(x))
  36675. {
  36676. case T_C_OPT_ARGS_FUNCTION:
  36677. case T_C_RST_ARGS_FUNCTION:
  36678. case T_C_FUNCTION:
  36679. return(((int)c_function_required_args(x) <= args) &&
  36680. ((int)c_function_all_args(x) >= args));
  36681. case T_C_ANY_ARGS_FUNCTION:
  36682. case T_C_FUNCTION_STAR:
  36683. return((int)c_function_all_args(x) >= args);
  36684. case T_MACRO:
  36685. case T_BACRO:
  36686. case T_CLOSURE:
  36687. return(closure_is_aritable(sc, x, closure_args(x), args));
  36688. case T_MACRO_STAR:
  36689. case T_BACRO_STAR:
  36690. case T_CLOSURE_STAR:
  36691. return(closure_star_is_aritable(sc, x, closure_args(x), args));
  36692. case T_C_MACRO:
  36693. return(((int)c_macro_required_args(x) <= args) &&
  36694. ((int)c_macro_all_args(x) >= args));
  36695. case T_GOTO:
  36696. case T_CONTINUATION:
  36697. return(true);
  36698. case T_STRING:
  36699. return((args == 1) &&
  36700. (string_length(x) > 0)); /* ("" 0) -> error */
  36701. case T_C_OBJECT:
  36702. /* check_method(sc, x, sc->is_aritable_symbol, list_2(sc, x, s7_make_integer(sc, args))); -- see below */
  36703. return(is_procedure(x)); /* i.e. is_applicable */
  36704. case T_INT_VECTOR:
  36705. case T_FLOAT_VECTOR:
  36706. case T_VECTOR:
  36707. return((args > 0) &&
  36708. (vector_length(x) > 0) && /* (#() 0) -> error */
  36709. ((unsigned int)args <= vector_rank(x)));
  36710. case T_LET:
  36711. /* check_method(sc, x, sc->is_aritable_symbol, list_2(sc, x, s7_make_integer(sc, args))); */
  36712. /* this slows us down a lot */
  36713. case T_HASH_TABLE:
  36714. case T_PAIR:
  36715. return(args == 1);
  36716. case T_ITERATOR:
  36717. return(args == 0);
  36718. case T_SYNTAX:
  36719. return((args >= syntax_min_args(x)) && ((args <= syntax_max_args(x)) || (syntax_max_args(x) == -1)));
  36720. }
  36721. return(false);
  36722. }
  36723. static s7_pointer g_is_aritable(s7_scheme *sc, s7_pointer args)
  36724. {
  36725. #define H_is_aritable "(aritable? obj num-args) returns #t if 'obj can be applied to 'num-args arguments."
  36726. #define Q_is_aritable s7_make_signature(sc, 3, sc->is_boolean_symbol, sc->T, sc->is_integer_symbol)
  36727. s7_pointer n;
  36728. s7_int num;
  36729. n = cadr(args);
  36730. if (!s7_is_integer(n)) /* remember gmp case! */
  36731. method_or_bust(sc, n, sc->is_aritable_symbol, args, T_INTEGER, 2);
  36732. num = s7_integer(n);
  36733. if (num < 0)
  36734. return(out_of_range(sc, sc->is_aritable_symbol, small_int(2), n, its_negative_string));
  36735. if (num > MAX_ARITY) num = MAX_ARITY;
  36736. return(make_boolean(sc, s7_is_aritable(sc, car(args), (int)num)));
  36737. }
  36738. static s7_pointer c_is_aritable(s7_scheme *sc, s7_pointer x, s7_int y) {return(make_boolean(sc, s7_is_aritable(sc, x, y)));}
  36739. PIF_TO_PF(is_aritable, c_is_aritable)
  36740. static s7_pointer is_aritable_ic;
  36741. static s7_pointer g_is_aritable_ic(s7_scheme *sc, s7_pointer args)
  36742. {
  36743. return(make_boolean(sc, s7_is_aritable(sc, car(args), (int)integer(cadr(args)))));
  36744. }
  36745. static s7_pointer is_aritable_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  36746. {
  36747. if (args == 2)
  36748. {
  36749. s7_pointer arg2;
  36750. arg2 = caddr(expr);
  36751. if ((s7_is_integer(arg2)) &&
  36752. (s7_integer(arg2) < MAX_ARITY) &&
  36753. (s7_integer(arg2) >= 0))
  36754. return(is_aritable_ic);
  36755. }
  36756. return(f);
  36757. }
  36758. /* -------- sequence? -------- */
  36759. static s7_pointer g_is_sequence(s7_scheme *sc, s7_pointer args)
  36760. {
  36761. #define H_is_sequence "(sequence? obj) returns #t if obj is a sequence (vector, string, pair, etc)"
  36762. #define Q_is_sequence pl_bt
  36763. check_boolean_method(sc, is_simple_sequence, sc->is_sequence_symbol, args);
  36764. }
  36765. /* -------------------------------- symbol-access ------------------------------------------------ */
  36766. static unsigned int protect_accessor(s7_scheme *sc, s7_pointer acc)
  36767. {
  36768. unsigned int loc;
  36769. if (sc->protected_accessors_size == sc->protected_accessors_loc)
  36770. {
  36771. int i, new_size, size;
  36772. size = sc->protected_accessors_size;
  36773. new_size = 2 * size;
  36774. vector_elements(sc->protected_accessors) = (s7_pointer *)realloc(vector_elements(sc->protected_accessors), new_size * sizeof(s7_pointer));
  36775. vector_length(sc->protected_accessors) = new_size;
  36776. for (i = size; i < new_size; i++)
  36777. vector_element(sc->protected_accessors, i) = sc->gc_nil;
  36778. sc->protected_accessors_size = new_size;
  36779. }
  36780. loc = sc->protected_accessors_loc++;
  36781. vector_element(sc->protected_accessors, loc) = acc;
  36782. return(loc);
  36783. }
  36784. s7_pointer s7_symbol_access(s7_scheme *sc, s7_pointer sym)
  36785. {
  36786. /* these refer to the rootlet */
  36787. if ((is_slot(global_slot(sym))) &&
  36788. (slot_has_accessor(global_slot(sym))))
  36789. /* return(s7_gc_protected_at(sc, symbol_global_accessor_index(sym))); */ /* 26-Feb-16 */
  36790. return(vector_element(sc->protected_accessors, symbol_global_accessor_index(sym)));
  36791. return(sc->F);
  36792. }
  36793. s7_pointer s7_symbol_set_access(s7_scheme *sc, s7_pointer symbol, s7_pointer func)
  36794. {
  36795. if (slot_has_accessor(global_slot(symbol)))
  36796. {
  36797. unsigned int index;
  36798. index = symbol_global_accessor_index(symbol);
  36799. if (is_immutable(vector_element(sc->protected_accessors, index)))
  36800. return(func);
  36801. vector_element(sc->protected_accessors, index) = func;
  36802. }
  36803. else
  36804. {
  36805. if (func != sc->F)
  36806. {
  36807. slot_set_has_accessor(global_slot(symbol));
  36808. symbol_set_has_accessor(symbol);
  36809. symbol_global_accessor_index(symbol) = protect_accessor(sc, func);
  36810. }
  36811. }
  36812. slot_set_accessor(global_slot(symbol), func);
  36813. return(func);
  36814. }
  36815. /* (let () (define xxx 23) (define (hix) (set! xxx 24)) (hix) (set! (symbol-access 'xxx) (lambda (sym val) (format *stderr* "val: ~A~%" val) val)) (hix))
  36816. * so set symbol-access before use!
  36817. */
  36818. static s7_pointer g_symbol_access(s7_scheme *sc, s7_pointer args)
  36819. {
  36820. #define H_symbol_access "(symbol-access sym (env (curlet))) is the function called when the symbol is set!."
  36821. #define Q_symbol_access s7_make_signature(sc, 3, sc->T, sc->is_symbol_symbol, sc->is_let_symbol)
  36822. s7_pointer sym, p, e;
  36823. sym = car(args);
  36824. if (!is_symbol(sym))
  36825. method_or_bust(sc, sym, sc->symbol_access_symbol, args, T_SYMBOL, 0);
  36826. if (is_keyword(sym))
  36827. return(sc->F);
  36828. if (is_pair(cdr(args)))
  36829. {
  36830. e = cadr(args);
  36831. if (!is_let(e))
  36832. return(wrong_type_argument(sc, sc->symbol_access_symbol, 2, e, T_LET));
  36833. }
  36834. else e = sc->envir;
  36835. if ((e == sc->rootlet) ||
  36836. (e == sc->nil))
  36837. return(s7_symbol_access(sc, sym));
  36838. if (is_null(cdr(args)))
  36839. p = find_symbol(sc, sym);
  36840. else p = find_local_symbol(sc, sym, e);
  36841. if ((is_slot(p)) &&
  36842. (slot_has_accessor(p)))
  36843. return(slot_accessor(p));
  36844. return(sc->F);
  36845. }
  36846. static s7_pointer g_symbol_set_access(s7_scheme *sc, s7_pointer args)
  36847. {
  36848. s7_pointer sym, func, e, p;
  36849. /* perhaps: check func */
  36850. sym = car(args);
  36851. if (!is_symbol(sym)) /* no check method because no method name? */
  36852. return(s7_wrong_type_arg_error(sc, "set! symbol-access", 1, sym, "a symbol"));
  36853. if (is_keyword(sym))
  36854. return(s7_wrong_type_arg_error(sc, "set! symbol-access", 1, sym, "a normal symbol (a keyword can't be set)"));
  36855. /* (set! (symbol-access sym) f) or (set! (symbol-access sym env) f) */
  36856. if (is_pair(cddr(args)))
  36857. {
  36858. e = cadr(args);
  36859. if (!is_let(e))
  36860. return(s7_wrong_type_arg_error(sc, "set! symbol-access", 2, e, "a let"));
  36861. func = caddr(args);
  36862. }
  36863. else
  36864. {
  36865. e = sc->envir;
  36866. func = cadr(args);
  36867. }
  36868. if ((!is_procedure_or_macro(func)) &&
  36869. (func != sc->F))
  36870. return(s7_wrong_type_arg_error(sc, "set! symbol-access", 3, func, "a function or #f"));
  36871. if ((e == sc->rootlet) ||
  36872. (e == sc->nil))
  36873. {
  36874. if (!is_slot(global_slot(sym)))
  36875. return(sc->F);
  36876. return(s7_symbol_set_access(sc, sym, func));
  36877. }
  36878. if (is_null(cddr(args)))
  36879. p = find_symbol(sc, sym);
  36880. else p = find_local_symbol(sc, sym, e);
  36881. if (is_slot(p))
  36882. {
  36883. slot_set_accessor(p, func);
  36884. if (func != sc->F)
  36885. {
  36886. slot_set_has_accessor(p);
  36887. symbol_set_has_accessor(sym);
  36888. }
  36889. return(func);
  36890. }
  36891. return(sc->F);
  36892. }
  36893. static s7_pointer bind_accessed_symbol(s7_scheme *sc, opcode_t op, s7_pointer symbol, s7_pointer new_value)
  36894. {
  36895. /* this refers to (define (sym ...)) and friends -- define cases
  36896. * see call_accessor for the set! cases
  36897. */
  36898. s7_pointer func;
  36899. func = g_symbol_access(sc, set_plist_2(sc, symbol, sc->envir));
  36900. if (is_procedure_or_macro(func))
  36901. {
  36902. if (is_c_function(func))
  36903. {
  36904. s7_pointer old_value;
  36905. old_value = new_value;
  36906. set_car(sc->t2_1, symbol);
  36907. set_car(sc->t2_2, new_value);
  36908. new_value = c_function_call(func)(sc, sc->t2_1);
  36909. if (new_value == sc->error_symbol)
  36910. return(s7_error(sc, sc->error_symbol, set_elist_3(sc, make_string_wrapper(sc, "can't bind ~S to ~S"), symbol, old_value)));
  36911. }
  36912. else
  36913. {
  36914. sc->args = list_2(sc, symbol, new_value);
  36915. push_stack(sc, op, sc->args, sc->code);
  36916. sc->code = func;
  36917. return(sc->no_value); /* this means the accessor in set! needs to goto APPLY to get the new value */
  36918. }
  36919. }
  36920. return(new_value);
  36921. }
  36922. /* -------------------------------- hooks -------------------------------- */
  36923. s7_pointer s7_hook_functions(s7_scheme *sc, s7_pointer hook)
  36924. {
  36925. return(s7_symbol_local_value(sc, sc->body_symbol, closure_let(hook)));
  36926. }
  36927. s7_pointer s7_hook_set_functions(s7_scheme *sc, s7_pointer hook, s7_pointer functions)
  36928. {
  36929. if (s7_is_list(sc, functions))
  36930. s7_let_set(sc, closure_let(hook), sc->body_symbol, functions);
  36931. return(functions);
  36932. }
  36933. /* -------------------------------- eq etc -------------------------------- */
  36934. bool s7_is_eq(s7_pointer obj1, s7_pointer obj2)
  36935. {
  36936. return(obj1 == obj2); /* so floats and NaNs might be eq? but not eqv? */
  36937. }
  36938. static s7_pointer g_is_eq(s7_scheme *sc, s7_pointer args)
  36939. {
  36940. #define H_is_eq "(eq? obj1 obj2) returns #t if obj1 is eq to (the same object as) obj2"
  36941. #define Q_is_eq pcl_bt
  36942. return(make_boolean(sc, ((car(args) == cadr(args)) ||
  36943. ((is_unspecified(car(args))) && (is_unspecified(cadr(args)))))));
  36944. /* (eq? (apply apply apply values '(())) #<unspecified>) should return #t
  36945. */
  36946. }
  36947. bool s7_is_eqv(s7_pointer a, s7_pointer b)
  36948. {
  36949. if ((a == b) && (!is_number(a)))
  36950. return(true);
  36951. #if WITH_GMP
  36952. if ((is_big_number(a)) || (is_big_number(b)))
  36953. return(big_numbers_are_eqv(a, b));
  36954. #endif
  36955. if (type(a) != type(b))
  36956. return(false);
  36957. if (is_string(a))
  36958. return(string_value(a) == string_value(b));
  36959. if (s7_is_number(a))
  36960. return(numbers_are_eqv(a, b));
  36961. if (is_unspecified(a)) /* types are the same so we know b is also unspecified */
  36962. return(true);
  36963. return(false);
  36964. }
  36965. static s7_pointer g_is_eqv(s7_scheme *sc, s7_pointer args)
  36966. {
  36967. #define H_is_eqv "(eqv? obj1 obj2) returns #t if obj1 is equivalent to obj2"
  36968. #define Q_is_eqv pcl_bt
  36969. return(make_boolean(sc, s7_is_eqv(car(args), cadr(args))));
  36970. }
  36971. static bool floats_are_morally_equal(s7_scheme *sc, s7_double x, s7_double y)
  36972. {
  36973. if (x == y) return(true);
  36974. if ((is_NaN(x)) || (is_NaN(y)))
  36975. return((is_NaN(x)) && (is_NaN(y)));
  36976. return(fabs(x - y) <= sc->morally_equal_float_epsilon);
  36977. }
  36978. static bool eq_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  36979. {
  36980. return(x == y);
  36981. }
  36982. static bool symbol_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  36983. {
  36984. if (x == y) return(true);
  36985. if (!is_symbol(y)) return(false); /* (morally-equal? ''(1) '(1)) */
  36986. if (!morally) return(false);
  36987. return((is_slot(global_slot(x))) && /* the optimizer can replace the original symbol with its own */
  36988. (is_syntax(slot_value(global_slot(x)))) &&
  36989. (is_slot(global_slot(y))) &&
  36990. (is_syntax(slot_value(global_slot(y)))) &&
  36991. (syntax_symbol(slot_value(global_slot(x))) == syntax_symbol(slot_value(global_slot(y)))));
  36992. }
  36993. static bool unspecified_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  36994. {
  36995. return(is_unspecified(y));
  36996. }
  36997. static bool c_pointer_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  36998. {
  36999. return((s7_is_c_pointer(y)) && (raw_pointer(x) == raw_pointer(y)));
  37000. }
  37001. static bool string_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37002. {
  37003. return((is_string(y)) && (scheme_strings_are_equal(x, y)));
  37004. }
  37005. static bool syntax_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37006. {
  37007. return((is_syntax(y)) && (syntax_symbol(x) == syntax_symbol(y)));
  37008. }
  37009. static bool c_object_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37010. {
  37011. return((is_c_object(y)) && (objects_are_equal(sc, x, y)));
  37012. }
  37013. static bool port_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37014. {
  37015. if (x == y) return(true);
  37016. if ((!morally) || (type(x) != type(y)) || (port_type(x) != port_type(y))) return(false);
  37017. if ((port_is_closed(x)) && (port_is_closed(y))) return(true);
  37018. return((is_string_port(x)) &&
  37019. (port_position(x) == port_position(y)) &&
  37020. (port_data_size(x) == port_data_size(y)) &&
  37021. (local_strncmp((const char *)port_data(x), (const char *)port_data(y), (is_input_port(x)) ? port_data_size(x) : port_position(x))));
  37022. }
  37023. static int equal_ref(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci)
  37024. {
  37025. /* here we know x and y are pointers to the same type of structure */
  37026. int ref_x, ref_y;
  37027. ref_x = peek_shared_ref(ci, x);
  37028. ref_y = peek_shared_ref(ci, y);
  37029. if ((ref_x != 0) && (ref_y != 0))
  37030. return((ref_x == ref_y) ? 1 : 0);
  37031. /* try to harmonize the new guy -- there can be more than one structure equal to the current one */
  37032. if (ref_x != 0)
  37033. add_shared_ref(ci, y, ref_x);
  37034. else
  37035. {
  37036. if (ref_y != 0)
  37037. add_shared_ref(ci, x, ref_y);
  37038. else add_equal_ref(ci, x, y);
  37039. }
  37040. return(-1);
  37041. }
  37042. static bool s7_is_equal_1(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally);
  37043. static bool hash_table_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37044. {
  37045. hash_entry_t **lists;
  37046. int i, len;
  37047. shared_info *nci = ci;
  37048. if (x == y)
  37049. return(true);
  37050. if (!is_hash_table(y))
  37051. {
  37052. if ((morally) && (has_methods(y)))
  37053. {
  37054. s7_pointer equal_func;
  37055. equal_func = find_method(sc, find_let(sc, y), sc->is_morally_equal_symbol);
  37056. if (equal_func != sc->undefined)
  37057. return(s7_boolean(sc, s7_apply_function(sc, equal_func, list_2(sc, y, x))));
  37058. }
  37059. return(false);
  37060. }
  37061. if (ci)
  37062. {
  37063. i = equal_ref(sc, x, y, ci);
  37064. if (i == 0) return(false);
  37065. if (i == 1) return(true);
  37066. }
  37067. if (hash_table_entries(x) != hash_table_entries(y))
  37068. return(false);
  37069. if (hash_table_entries(x) == 0)
  37070. return(true);
  37071. if ((!morally) &&
  37072. ((hash_table_checker_locked(x)) || (hash_table_checker_locked(y))))
  37073. {
  37074. if (hash_table_checker(x) != hash_table_checker(y))
  37075. return(false);
  37076. if (hash_table_mapper(x) != hash_table_mapper(y))
  37077. return(false);
  37078. }
  37079. len = hash_table_mask(x) + 1;
  37080. lists = hash_table_elements(x);
  37081. if (!nci) nci = new_shared_info(sc);
  37082. for (i = 0; i < len; i++)
  37083. {
  37084. hash_entry_t *p;
  37085. for (p = lists[i]; p; p = p->next)
  37086. {
  37087. hash_entry_t *y_val;
  37088. y_val = (*hash_table_checker(y))(sc, y, p->key);
  37089. if ((!y_val) ||
  37090. (!s7_is_equal_1(sc, p->value, y_val->value, nci, morally)))
  37091. return(false);
  37092. }
  37093. }
  37094. /* if we get here, every key/value in x has a corresponding key/value in y, and the number of entries match,
  37095. * so surely the tables are equal??
  37096. */
  37097. return(true);
  37098. }
  37099. static bool slots_match(s7_scheme *sc, s7_pointer px, s7_pointer y, bool morally, shared_info *nci)
  37100. {
  37101. s7_pointer ey, py;
  37102. for (ey = y; (is_let(ey)) && (ey != sc->rootlet); ey = outlet(ey))
  37103. for (py = let_slots(ey); is_slot(py); py = next_slot(py))
  37104. if (slot_symbol(px) == slot_symbol(py)) /* we know something will match */
  37105. return(s7_is_equal_1(sc, slot_value(px), slot_value(py), nci, morally));
  37106. return(false);
  37107. }
  37108. static bool let_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37109. {
  37110. /* x == y if all unshadowed vars match, leaving aside the rootlet, so that for any local variable,
  37111. * we get the same value in either x or y.
  37112. */
  37113. s7_pointer ex, ey, px, py;
  37114. shared_info *nci = ci;
  37115. int x_len, y_len;
  37116. if (x == y)
  37117. return(true);
  37118. if (morally)
  37119. {
  37120. s7_pointer equal_func;
  37121. if (has_methods(x))
  37122. {
  37123. equal_func = find_method(sc, find_let(sc, x), sc->is_morally_equal_symbol);
  37124. if (equal_func != sc->undefined)
  37125. return(s7_boolean(sc, s7_apply_function(sc, equal_func, list_2(sc, x, y))));
  37126. }
  37127. if (has_methods(y))
  37128. {
  37129. equal_func = find_method(sc, find_let(sc, y), sc->is_morally_equal_symbol);
  37130. if (equal_func != sc->undefined)
  37131. return(s7_boolean(sc, s7_apply_function(sc, equal_func, list_2(sc, y, x))));
  37132. }
  37133. }
  37134. if (!is_let(y))
  37135. return(false);
  37136. if ((x == sc->rootlet) || (y == sc->rootlet))
  37137. return(false);
  37138. if (ci)
  37139. {
  37140. int i;
  37141. i = equal_ref(sc, x, y, ci);
  37142. if (i == 0) return(false);
  37143. if (i == 1) return(true);
  37144. }
  37145. clear_syms_in_list(sc);
  37146. for (x_len = 0, ex = x; (is_let(ex)) && (ex != sc->rootlet); ex = outlet(ex))
  37147. for (px = let_slots(ex); is_slot(px); px = next_slot(px))
  37148. if (symbol_tag(slot_symbol(px)) != sc->syms_tag)
  37149. {
  37150. add_sym_to_list(sc, slot_symbol(px));
  37151. x_len++;
  37152. }
  37153. for (ey = y; (is_let(ey)) && (ey != sc->rootlet); ey = outlet(ey))
  37154. for (py = let_slots(ey); is_slot(py); py = next_slot(py))
  37155. if (symbol_tag(slot_symbol(py)) != sc->syms_tag) /* symbol in y, not in x */
  37156. return(false);
  37157. for (y_len = 0, ey = y; (is_let(ey)) && (ey != sc->rootlet); ey = outlet(ey))
  37158. for (py = let_slots(ey); is_slot(py); py = next_slot(py))
  37159. if (symbol_tag(slot_symbol(py)) != 0)
  37160. {
  37161. y_len ++;
  37162. symbol_set_tag(slot_symbol(py), 0);
  37163. }
  37164. if (x_len != y_len) /* symbol in x, not in y */
  37165. return(false);
  37166. if (!nci) nci = new_shared_info(sc);
  37167. for (ex = x; (is_let(ex)) && (ex != sc->rootlet); ex = outlet(ex))
  37168. for (px = let_slots(ex); is_slot(px); px = next_slot(px))
  37169. if (symbol_tag(slot_symbol(px)) == 0) /* unshadowed */
  37170. {
  37171. symbol_set_tag(slot_symbol(px), sc->syms_tag); /* values don't match */
  37172. if (!slots_match(sc, px, y, morally, nci))
  37173. return(false);
  37174. }
  37175. return(true);
  37176. }
  37177. static bool closure_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37178. {
  37179. if (x == y)
  37180. return(true);
  37181. if (type(x) != type(y))
  37182. return(false);
  37183. if ((has_methods(x)) &&
  37184. (has_methods(y)))
  37185. {
  37186. s7_pointer equal_func;
  37187. equal_func = find_method(sc, closure_let(x), (morally) ? sc->is_morally_equal_symbol : sc->is_equal_symbol);
  37188. if (equal_func != sc->undefined)
  37189. return(s7_boolean(sc, s7_apply_function(sc, equal_func, list_2(sc, x, y))));
  37190. }
  37191. /* not sure about this -- we can't simply check let_equal(closure_let(x), closure_let(y))
  37192. * because locally defined constant functions on the second pass find the outer let.
  37193. */
  37194. return((morally) &&
  37195. (s7_is_equal_1(sc, closure_args(x), closure_args(y), ci, morally)) &&
  37196. (s7_is_equal_1(sc, closure_body(x), closure_body(y), ci, morally)));
  37197. }
  37198. static bool pair_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37199. {
  37200. int i;
  37201. s7_pointer px, py;
  37202. shared_info *nci = ci;
  37203. if (x == y)
  37204. return(true);
  37205. if (!is_pair(y))
  37206. {
  37207. if ((morally) && (has_methods(y)))
  37208. {
  37209. s7_pointer equal_func;
  37210. equal_func = find_method(sc, find_let(sc, y), sc->is_morally_equal_symbol);
  37211. if (equal_func != sc->undefined)
  37212. return(s7_boolean(sc, s7_apply_function(sc, equal_func, list_2(sc, y, x))));
  37213. }
  37214. return(false);
  37215. }
  37216. if (ci)
  37217. {
  37218. i = equal_ref(sc, x, y, ci);
  37219. if (i == 0) return(false);
  37220. if (i == 1) return(true);
  37221. }
  37222. else nci = new_shared_info(sc);
  37223. if (!s7_is_equal_1(sc, car(x), car(y), nci, morally)) return(false);
  37224. for (px = cdr(x), py = cdr(y); (is_pair(px)) && (is_pair(py)); px = cdr(px), py = cdr(py))
  37225. {
  37226. if (!s7_is_equal_1(sc, car(px), car(py), nci, morally)) return(false);
  37227. i = equal_ref(sc, px, py, nci);
  37228. if (i == 0) return(false);
  37229. if (i == 1) return(true);
  37230. }
  37231. return(s7_is_equal_1(sc, px, py, nci, morally));
  37232. }
  37233. static bool vector_rank_match(s7_scheme *sc, s7_pointer x, s7_pointer y)
  37234. {
  37235. int x_dims, y_dims;
  37236. if (vector_has_dimensional_info(x))
  37237. x_dims = vector_ndims(x);
  37238. else x_dims = 1;
  37239. if (vector_has_dimensional_info(y))
  37240. y_dims = vector_ndims(y);
  37241. else y_dims = 1;
  37242. if (x_dims != y_dims)
  37243. return(false);
  37244. if (x_dims > 1)
  37245. {
  37246. int j;
  37247. for (j = 0; j < x_dims; j++)
  37248. if (vector_dimension(x, j) != vector_dimension(y, j))
  37249. return(false);
  37250. }
  37251. return(true);
  37252. }
  37253. static bool vector_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37254. {
  37255. s7_int i, len;
  37256. shared_info *nci = ci;
  37257. if (x == y)
  37258. return(true);
  37259. if (!s7_is_vector(y))
  37260. {
  37261. if ((morally) && (has_methods(y)))
  37262. {
  37263. s7_pointer equal_func;
  37264. equal_func = find_method(sc, find_let(sc, y), sc->is_morally_equal_symbol);
  37265. if (equal_func != sc->undefined)
  37266. return(s7_boolean(sc, s7_apply_function(sc, equal_func, list_2(sc, y, x))));
  37267. }
  37268. return(false);
  37269. }
  37270. len = vector_length(x);
  37271. if (len != vector_length(y)) return(false);
  37272. if (len == 0)
  37273. {
  37274. if (morally) return(true);
  37275. if (!vector_rank_match(sc, x, y))
  37276. return(false);
  37277. return(true);
  37278. }
  37279. if (!vector_rank_match(sc, x, y))
  37280. return(false);
  37281. if (type(x) != type(y))
  37282. {
  37283. if (!morally) return(false);
  37284. /* (morally-equal? (make-int-vector 3 0) (make-vector 3 0)) -> #t
  37285. * (morally-equal? (make-float-vector 3 1.0) (vector 1 1 1)) -> #t
  37286. */
  37287. for (i = 0; i < len; i++)
  37288. if (!s7_is_equal_1(sc, vector_getter(x)(sc, x, i), vector_getter(y)(sc, y, i), NULL, true)) /* this could be greatly optimized */
  37289. return(false);
  37290. return(true);
  37291. }
  37292. if (is_float_vector(x))
  37293. {
  37294. if (!morally)
  37295. {
  37296. for (i = 0; i < len; i++)
  37297. {
  37298. s7_double z;
  37299. z = float_vector_element(x, i);
  37300. if ((is_NaN(z)) ||
  37301. (z != float_vector_element(y, i)))
  37302. return(false);
  37303. }
  37304. return(true);
  37305. }
  37306. else
  37307. {
  37308. s7_double *arr1, *arr2;
  37309. s7_double fudge;
  37310. arr1 = float_vector_elements(x);
  37311. arr2 = float_vector_elements(y);
  37312. fudge = sc->morally_equal_float_epsilon;
  37313. if (fudge == 0.0)
  37314. {
  37315. for (i = 0; i < len; i++)
  37316. if ((arr1[i] != arr2[i]) &&
  37317. ((!is_NaN(arr1[i])) || (!is_NaN(arr2[i]))))
  37318. return(false);
  37319. }
  37320. else
  37321. {
  37322. for (i = 0; i < len; i++)
  37323. {
  37324. s7_double diff;
  37325. diff = fabs(arr1[i] - arr2[i]);
  37326. if (diff > fudge) return(false);
  37327. if ((is_NaN(diff)) &&
  37328. ((!is_NaN(arr1[i])) || (!is_NaN(arr2[i]))))
  37329. return(false);
  37330. }
  37331. }
  37332. return(true);
  37333. }
  37334. }
  37335. if (is_int_vector(x))
  37336. {
  37337. for (i = 0; i < len; i++)
  37338. if (int_vector_element(x, i) != int_vector_element(y, i))
  37339. return(false);
  37340. return(true);
  37341. }
  37342. if (ci)
  37343. {
  37344. i = equal_ref(sc, x, y, ci);
  37345. if (i == 0) return(false);
  37346. if (i == 1) return(true);
  37347. }
  37348. else nci = new_shared_info(sc);
  37349. for (i = 0; i < len; i++)
  37350. if (!(s7_is_equal_1(sc, vector_element(x, i), vector_element(y, i), nci, morally)))
  37351. return(false);
  37352. return(true);
  37353. }
  37354. static bool iterator_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37355. {
  37356. if (x == y) return(true);
  37357. if (!is_iterator(y)) return(false);
  37358. switch (type(iterator_sequence(x)))
  37359. {
  37360. case T_STRING:
  37361. return((is_string(iterator_sequence(y))) &&
  37362. (iterator_position(x) == iterator_position(y)) &&
  37363. (string_equal(sc, iterator_sequence(x), iterator_sequence(y), ci, morally)));
  37364. case T_VECTOR:
  37365. case T_INT_VECTOR:
  37366. case T_FLOAT_VECTOR:
  37367. return((s7_is_vector(iterator_sequence(y))) &&
  37368. (iterator_position(x) == iterator_position(y)) &&
  37369. (vector_equal(sc, iterator_sequence(x), iterator_sequence(y), ci, morally)));
  37370. case T_PAIR:
  37371. return((iterator_sequence(x) == iterator_sequence(y)) &&
  37372. (iterator_next(x) == iterator_next(y)) && /* even if seqs are equal, one might be at end */
  37373. (iterator_current(x) == iterator_current(y))); /* current pointer into the sequence */
  37374. case T_HASH_TABLE:
  37375. return((iterator_sequence(x) == iterator_sequence(y)) &&
  37376. (iterator_next(x) == iterator_next(y)) &&
  37377. (iterator_current(x) == iterator_current(y)) &&
  37378. (iterator_hash_current(x) == iterator_hash_current(y)) &&
  37379. (iterator_position(x) == iterator_position(y)));
  37380. default:
  37381. break;
  37382. }
  37383. return(false);
  37384. }
  37385. static bool bignum_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37386. {
  37387. if (!s7_is_number(y)) return(false);
  37388. #if WITH_GMP
  37389. if (!morally)
  37390. return(big_numbers_are_eqv(x, y));
  37391. return(big_equal(sc, set_plist_2(sc, x, y)) != sc->F);
  37392. #else
  37393. return(false);
  37394. #endif
  37395. }
  37396. static bool integer_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37397. {
  37398. #if WITH_GMP
  37399. if (is_big_number(y))
  37400. {
  37401. if (!morally)
  37402. return(big_numbers_are_eqv(x, y));
  37403. return(big_equal(sc, set_plist_2(sc, x, y)) != sc->F);
  37404. }
  37405. #endif
  37406. if (is_integer(y))
  37407. return(integer(x) == integer(y));
  37408. if ((!morally) || (!is_number(y)))
  37409. return(false);
  37410. if (is_t_real(y))
  37411. return((!is_NaN(real(y))) &&
  37412. (fabs(integer(x) - real(y)) <= sc->morally_equal_float_epsilon));
  37413. if (is_t_ratio(y))
  37414. return(s7_fabsl(integer(x) - fraction(y)) <= sc->morally_equal_float_epsilon);
  37415. return((!is_NaN(real_part(y))) &&
  37416. (!is_NaN(imag_part(y))) &&
  37417. (fabs(integer(x) - real_part(y)) <= sc->morally_equal_float_epsilon) &&
  37418. (fabs(imag_part(y)) <= sc->morally_equal_float_epsilon));
  37419. }
  37420. /* apparently ratio_equal is predefined in g++ -- name collision on mac */
  37421. static bool fraction_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37422. {
  37423. #if WITH_GMP
  37424. if (is_big_number(y))
  37425. {
  37426. if (!morally)
  37427. return(big_numbers_are_eqv(x, y));
  37428. return(big_equal(sc, set_plist_2(sc, x, y)) != sc->F);
  37429. }
  37430. #endif
  37431. if (!morally)
  37432. return((s7_is_ratio(y)) &&
  37433. (numerator(x) == numerator(y)) &&
  37434. (denominator(x) == denominator(y)));
  37435. if (is_t_ratio(y))
  37436. return(s7_fabsl(fraction(x) - fraction(y)) <= sc->morally_equal_float_epsilon);
  37437. if (is_t_real(y))
  37438. return(floats_are_morally_equal(sc, fraction(x), real(y)));
  37439. if (is_integer(y))
  37440. return(s7_fabsl(fraction(x) - integer(y)) <= sc->morally_equal_float_epsilon);
  37441. if (is_t_complex(y))
  37442. return((!is_NaN(real_part(y))) &&
  37443. (!is_NaN(imag_part(y))) &&
  37444. (s7_fabsl(fraction(x) - real_part(y)) <= sc->morally_equal_float_epsilon) &&
  37445. (fabs(imag_part(y)) <= sc->morally_equal_float_epsilon));
  37446. return(false);
  37447. }
  37448. static bool real_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37449. {
  37450. #if WITH_GMP
  37451. if (is_big_number(y))
  37452. {
  37453. if (!morally)
  37454. return(big_numbers_are_eqv(x, y));
  37455. return(big_equal(sc, set_plist_2(sc, x, y)) != sc->F);
  37456. }
  37457. #endif
  37458. if (!morally)
  37459. return((is_t_real(y)) &&
  37460. (real(x) == real(y)));
  37461. if (!is_number(y)) return(false);
  37462. if (is_t_real(y))
  37463. return(floats_are_morally_equal(sc, real(x), real(y)));
  37464. if (is_integer(y))
  37465. return((!is_NaN(real(x))) &&
  37466. (fabs(real(x) - integer(y)) <= sc->morally_equal_float_epsilon));
  37467. if (is_t_ratio(y))
  37468. return(floats_are_morally_equal(sc, real(x), fraction(y)));
  37469. if (is_NaN(real(x)))
  37470. return((is_NaN(real_part(y))) &&
  37471. (fabs(imag_part(y)) <= sc->morally_equal_float_epsilon));
  37472. return((!is_NaN(real(x))) &&
  37473. (!is_NaN(real_part(y))) &&
  37474. (!is_NaN(imag_part(y))) &&
  37475. ((real(x) == real_part(y)) ||
  37476. (fabs(real(x) - real_part(y)) <= sc->morally_equal_float_epsilon)) &&
  37477. (fabs(imag_part(y)) <= sc->morally_equal_float_epsilon));
  37478. }
  37479. static bool complex_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37480. {
  37481. #if WITH_GMP
  37482. if (is_big_number(y))
  37483. {
  37484. if (!morally)
  37485. return(big_numbers_are_eqv(x, y));
  37486. return(big_equal(sc, set_plist_2(sc, x, y)) != sc->F);
  37487. }
  37488. #endif
  37489. if (!morally)
  37490. return((is_t_complex(y)) &&
  37491. (!is_NaN(real_part(x))) &&
  37492. (!is_NaN(imag_part(x))) &&
  37493. (real_part(x) == real_part(y)) &&
  37494. (imag_part(x) == imag_part(y)));
  37495. if (!is_number(y)) return(false);
  37496. if (is_integer(y))
  37497. return((!is_NaN(real_part(x))) &&
  37498. (!is_NaN(imag_part(x))) &&
  37499. (fabs(real_part(x) - integer(y)) <= sc->morally_equal_float_epsilon) &&
  37500. (fabs(imag_part(x)) <= sc->morally_equal_float_epsilon));
  37501. if (s7_is_ratio(y))
  37502. return((!is_NaN(real_part(x))) &&
  37503. (!is_NaN(imag_part(x))) &&
  37504. (s7_fabsl(real_part(x) - fraction(y)) <= sc->morally_equal_float_epsilon) &&
  37505. (fabs(imag_part(x)) <= sc->morally_equal_float_epsilon));
  37506. if (is_real(y))
  37507. {
  37508. if (is_NaN(imag_part(x)))
  37509. return(false);
  37510. if (is_NaN(real(y)))
  37511. return((is_NaN(real_part(x))) &&
  37512. (fabs(imag_part(x)) <= sc->morally_equal_float_epsilon));
  37513. return(((real_part(x) == real(y)) ||
  37514. (fabs(real_part(x) - real(y)) <= sc->morally_equal_float_epsilon)) &&
  37515. (fabs(imag_part(x)) <= sc->morally_equal_float_epsilon));
  37516. }
  37517. /* should (morally-equal? nan.0 (complex nan.0 nan.0)) be #t (it's #f above)? */
  37518. if (is_NaN(real_part(x)))
  37519. return((is_NaN(real_part(y))) &&
  37520. (((is_NaN(imag_part(x))) && (is_NaN(imag_part(y)))) ||
  37521. (imag_part(x) == imag_part(y)) ||
  37522. (fabs(imag_part(x) - imag_part(y)) <= sc->morally_equal_float_epsilon)));
  37523. if (is_NaN(imag_part(x)))
  37524. return((is_NaN(imag_part(y))) &&
  37525. ((real_part(x) == real_part(y)) ||
  37526. (fabs(real_part(x) - real_part(y)) <= sc->morally_equal_float_epsilon)));
  37527. if ((is_NaN(real_part(y))) ||
  37528. (is_NaN(imag_part(y))))
  37529. return(false);
  37530. return(((real_part(x) == real_part(y)) ||
  37531. (fabs(real_part(x) - real_part(y)) <= sc->morally_equal_float_epsilon)) &&
  37532. ((imag_part(x) == imag_part(y)) ||
  37533. (fabs(imag_part(x) - imag_part(y)) <= sc->morally_equal_float_epsilon)));
  37534. }
  37535. static bool rng_equal(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37536. {
  37537. #if WITH_GMP
  37538. return(x == y);
  37539. #else
  37540. return((x == y) ||
  37541. ((is_random_state(y)) &&
  37542. (random_seed(x) == random_seed(y)) &&
  37543. (random_carry(x) == random_carry(y))));
  37544. #endif
  37545. }
  37546. static bool (*equals[NUM_TYPES])(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally);
  37547. static void init_equals(void)
  37548. {
  37549. int i;
  37550. for (i = 0; i < NUM_TYPES; i++) equals[i] = eq_equal;
  37551. equals[T_SYMBOL] = symbol_equal;
  37552. equals[T_C_POINTER] = c_pointer_equal;
  37553. equals[T_UNSPECIFIED] = unspecified_equal;
  37554. equals[T_STRING] = string_equal;
  37555. equals[T_SYNTAX] = syntax_equal;
  37556. equals[T_C_OBJECT] = c_object_equal;
  37557. equals[T_RANDOM_STATE] = rng_equal;
  37558. equals[T_ITERATOR] = iterator_equal;
  37559. equals[T_INPUT_PORT] = port_equal;
  37560. equals[T_OUTPUT_PORT] = port_equal;
  37561. equals[T_MACRO] = closure_equal;
  37562. equals[T_MACRO_STAR] = closure_equal;
  37563. equals[T_BACRO] = closure_equal;
  37564. equals[T_BACRO_STAR] = closure_equal;
  37565. equals[T_CLOSURE] = closure_equal;
  37566. equals[T_CLOSURE_STAR] = closure_equal;
  37567. equals[T_HASH_TABLE] = hash_table_equal;
  37568. equals[T_LET] = let_equal;
  37569. equals[T_PAIR] = pair_equal;
  37570. equals[T_VECTOR] = vector_equal;
  37571. equals[T_INT_VECTOR] = vector_equal;
  37572. equals[T_FLOAT_VECTOR] = vector_equal;
  37573. equals[T_INTEGER] = integer_equal;
  37574. equals[T_RATIO] = fraction_equal;
  37575. equals[T_REAL] = real_equal;
  37576. equals[T_COMPLEX] = complex_equal;
  37577. equals[T_BIG_INTEGER] = bignum_equal;
  37578. equals[T_BIG_RATIO] = bignum_equal;
  37579. equals[T_BIG_REAL] = bignum_equal;
  37580. equals[T_BIG_COMPLEX] = bignum_equal;
  37581. }
  37582. static bool s7_is_equal_1(s7_scheme *sc, s7_pointer x, s7_pointer y, shared_info *ci, bool morally)
  37583. {
  37584. return((*(equals[type(x)]))(sc, x, y, ci, morally));
  37585. }
  37586. bool s7_is_equal(s7_scheme *sc, s7_pointer x, s7_pointer y)
  37587. {
  37588. return(s7_is_equal_1(sc, x, y, NULL, false));
  37589. }
  37590. bool s7_is_morally_equal(s7_scheme *sc, s7_pointer x, s7_pointer y)
  37591. {
  37592. return(s7_is_equal_1(sc, x, y, NULL, true));
  37593. }
  37594. static s7_pointer g_is_equal(s7_scheme *sc, s7_pointer args)
  37595. {
  37596. #define H_is_equal "(equal? obj1 obj2) returns #t if obj1 is equal to obj2"
  37597. #define Q_is_equal pcl_bt
  37598. return(make_boolean(sc, s7_is_equal(sc, car(args), cadr(args))));
  37599. }
  37600. static s7_pointer g_is_morally_equal(s7_scheme *sc, s7_pointer args)
  37601. {
  37602. #define H_is_morally_equal "(morally-equal? obj1 obj2) returns #t if obj1 is close enough to obj2."
  37603. #define Q_is_morally_equal pcl_bt
  37604. return(make_boolean(sc, s7_is_morally_equal(sc, car(args), cadr(args))));
  37605. }
  37606. /* ---------------------------------------- length, copy, fill ---------------------------------------- */
  37607. static s7_pointer s7_length(s7_scheme *sc, s7_pointer lst)
  37608. {
  37609. switch (type(lst))
  37610. {
  37611. case T_PAIR:
  37612. {
  37613. int len;
  37614. len = s7_list_length(sc, lst);
  37615. /* len < 0 -> dotted and (abs len) is length not counting the final cdr
  37616. * len == 0, circular so length is infinite
  37617. */
  37618. if (len == 0)
  37619. return(real_infinity);
  37620. return(make_integer(sc, len));
  37621. }
  37622. case T_NIL:
  37623. return(small_int(0));
  37624. case T_INT_VECTOR:
  37625. case T_FLOAT_VECTOR:
  37626. case T_VECTOR:
  37627. return(make_integer(sc, vector_length(lst)));
  37628. case T_STRING:
  37629. return(make_integer(sc, string_length(lst)));
  37630. case T_ITERATOR:
  37631. return(make_integer(sc, iterator_length(lst))); /* in several cases, this is incorrect */
  37632. case T_HASH_TABLE:
  37633. return(make_integer(sc, hash_table_mask(lst) + 1));
  37634. case T_C_OBJECT:
  37635. check_method(sc, lst, sc->length_symbol, list_1(sc, lst));
  37636. return(object_length(sc, lst));
  37637. case T_LET:
  37638. check_method(sc, lst, sc->length_symbol, list_1(sc, lst));
  37639. return(make_integer(sc, let_length(sc, lst)));
  37640. case T_CLOSURE:
  37641. case T_CLOSURE_STAR:
  37642. if (has_methods(lst))
  37643. return(make_integer(sc, closure_length(sc, lst)));
  37644. return(sc->F);
  37645. case T_INPUT_PORT:
  37646. if (is_string_port(lst))
  37647. return(make_integer(sc, port_data_size(lst)));
  37648. return(sc->F);
  37649. default:
  37650. return(sc->F);
  37651. }
  37652. return(sc->F);
  37653. }
  37654. static s7_pointer g_length(s7_scheme *sc, s7_pointer args)
  37655. {
  37656. #define H_length "(length obj) returns the length of obj, which can be a list, vector, string, or hash-table. \
  37657. The length of a dotted list does not include the final cdr, and is returned as a negative number. A circular \
  37658. list has infinite length. Length of anything else returns #f."
  37659. #define Q_length s7_make_signature(sc, 2, s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_boolean_symbol), sc->T)
  37660. return(s7_length(sc, car(args)));
  37661. }
  37662. /* what about (length file)? input port, read_file gets the file length, so perhaps save it
  37663. * but we're actually looking at the port, so its length is what remains to be read? (if input port)
  37664. */
  37665. PF_TO_PF(length, s7_length)
  37666. /* -------------------------------- copy -------------------------------- */
  37667. static s7_pointer copy_to_string_error = NULL, copy_to_byte_vector_error = NULL;
  37668. static void set_string_error_source(s7_scheme *sc, s7_pointer source)
  37669. {
  37670. if (!copy_to_string_error)
  37671. copy_to_string_error = s7_make_permanent_string("copy ~A to string, ~S is not a character");
  37672. if (!copy_to_byte_vector_error)
  37673. copy_to_byte_vector_error = s7_make_permanent_string("copy ~A to byte-vector, ~S is not a byte");
  37674. set_cadr(sc->elist_3, prepackaged_type_name(sc, source));
  37675. }
  37676. static s7_pointer string_setter(s7_scheme *sc, s7_pointer str, s7_int loc, s7_pointer val)
  37677. {
  37678. if (s7_is_character(val))
  37679. {
  37680. string_value(str)[loc] = s7_character(val);
  37681. return(val);
  37682. }
  37683. /* (copy #(3) "123"): wrong type arg because not a char, but it's very confusing to report
  37684. * error: copy argument 3, 3, is an integer but should be a character
  37685. * perhaps better, copy #(3) to string, 3 is not a character
  37686. */
  37687. #if DEBUGGING
  37688. if (!copy_to_string_error) {fprintf(stderr, "string_error not set\n"); abort();}
  37689. #endif
  37690. set_car(sc->elist_3, copy_to_string_error);
  37691. set_caddr(sc->elist_3, val);
  37692. return(s7_error(sc, sc->wrong_type_arg_symbol, sc->elist_3));
  37693. }
  37694. static s7_pointer byte_vector_setter(s7_scheme *sc, s7_pointer str, s7_int loc, s7_pointer val)
  37695. {
  37696. if (s7_is_integer(val))
  37697. {
  37698. s7_int byte;
  37699. byte = s7_integer(val);
  37700. if ((byte >= 0) && (byte < 256))
  37701. string_value(str)[loc] = (unsigned char)byte;
  37702. else return(simple_wrong_type_argument_with_type(sc, sc->copy_symbol, val, an_unsigned_byte_string));
  37703. return(val);
  37704. }
  37705. #if DEBUGGING
  37706. if (!copy_to_byte_vector_error) {fprintf(stderr, "byte_vector_error not set\n"); abort();}
  37707. #endif
  37708. set_car(sc->elist_3, copy_to_byte_vector_error);
  37709. set_caddr(sc->elist_3, val);
  37710. return(s7_error(sc, sc->wrong_type_arg_symbol, sc->elist_3));
  37711. }
  37712. static s7_pointer string_getter(s7_scheme *sc, s7_pointer str, s7_int loc)
  37713. {
  37714. return(s7_make_character(sc, (unsigned char)(string_value(str)[loc]))); /* cast needed else (copy (string (integer->char 255))...) is trouble */
  37715. }
  37716. static s7_pointer byte_vector_getter(s7_scheme *sc, s7_pointer str, s7_int loc)
  37717. {
  37718. return(make_integer(sc, (unsigned char)(string_value(str)[loc])));
  37719. }
  37720. static s7_pointer c_object_setter(s7_scheme *sc, s7_pointer obj, s7_int loc, s7_pointer val)
  37721. {
  37722. set_car(sc->t2_1, make_integer(sc, loc));
  37723. set_car(sc->t2_2, val);
  37724. return((*(c_object_set(obj)))(sc, obj, sc->t2_1));
  37725. }
  37726. static s7_pointer c_object_getter(s7_scheme *sc, s7_pointer obj, s7_int loc)
  37727. {
  37728. set_car(sc->t1_1, make_integer(sc, loc));
  37729. return((*(c_object_ref(obj)))(sc, obj, sc->t1_1));
  37730. }
  37731. static s7_pointer let_setter(s7_scheme *sc, s7_pointer e, s7_int loc, s7_pointer val)
  37732. {
  37733. /* loc is irrelevant here
  37734. * val has to be of the form (cons symbol value)
  37735. * if symbol is already in e, its value is changed, otherwise a new slot is added to e
  37736. */
  37737. static s7_pointer ls_err = NULL;
  37738. s7_pointer sym;
  37739. if (!is_pair(val))
  37740. {
  37741. if (!ls_err) ls_err = s7_make_permanent_string("(cons symbol value)");
  37742. return(wrong_type_argument_with_type(sc, sc->copy_symbol, 3, e, ls_err));
  37743. }
  37744. sym = car(val);
  37745. if (!is_symbol(sym))
  37746. {
  37747. if (!ls_err) ls_err = s7_make_permanent_string("(cons symbol value)");
  37748. return(wrong_type_argument_with_type(sc, sc->copy_symbol, 3, e, ls_err));
  37749. }
  37750. if ((symbol_id(sym) < let_id(e)) ||
  37751. (s7_let_set(sc, e, sym, cdr(val)) != cdr(val)))
  37752. make_slot_1(sc, e, sym, cdr(val));
  37753. return(val);
  37754. }
  37755. static s7_pointer hash_table_setter(s7_scheme *sc, s7_pointer e, s7_int loc, s7_pointer val)
  37756. {
  37757. /* loc is irrelevant here
  37758. * val has to be of the form (cons key value)
  37759. * if key is already in e, its value is changed, otherwise a new slot is added to e
  37760. */
  37761. if (!is_pair(val))
  37762. return(wrong_type_argument_with_type(sc, sc->copy_symbol, 1, e, a_list_string));
  37763. return(s7_hash_table_set(sc, e, car(val), cdr(val)));
  37764. }
  37765. s7_pointer s7_copy(s7_scheme *sc, s7_pointer args)
  37766. {
  37767. #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."
  37768. /* #define Q_copy s7_make_circular_signature(sc, 3, 4, sc->T, sc->is_sequence_symbol, sc->is_sequence_symbol, sc->is_integer_symbol) */
  37769. /* this is not right when c-object types are handled in lint -- a generator or Snd object need not consider itself a sequence,
  37770. * but it can provide a copy method. So, I think I'll just use #t
  37771. */
  37772. #define Q_copy s7_make_circular_signature(sc, 3, 4, sc->T, sc->T, sc->T, sc->is_integer_symbol)
  37773. s7_pointer source, dest;
  37774. s7_int i, j, dest_len, start, end, source_len;
  37775. s7_pointer (*set)(s7_scheme *sc, s7_pointer obj, s7_int loc, s7_pointer val) = NULL;
  37776. s7_pointer (*get)(s7_scheme *sc, s7_pointer obj, s7_int loc) = NULL;
  37777. bool have_indices;
  37778. source = car(args);
  37779. if (is_null(cdr(args))) /* (copy obj) */
  37780. {
  37781. switch (type(source))
  37782. {
  37783. case T_STRING:
  37784. {
  37785. s7_pointer ns;
  37786. ns = s7_make_string_with_length(sc, string_value(source), string_length(source));
  37787. if (is_byte_vector(source))
  37788. set_byte_vector(ns);
  37789. return(ns);
  37790. }
  37791. case T_C_OBJECT:
  37792. return(object_copy(sc, args));
  37793. case T_RANDOM_STATE:
  37794. return(rng_copy(sc, args));
  37795. case T_HASH_TABLE: /* this has to copy nearly everything */
  37796. {
  37797. int gc_loc;
  37798. s7_pointer new_hash;
  37799. new_hash = s7_make_hash_table(sc, hash_table_mask(source) + 1);
  37800. gc_loc = s7_gc_protect(sc, new_hash);
  37801. hash_table_checker(new_hash) = hash_table_checker(source);
  37802. hash_table_mapper(new_hash) = hash_table_mapper(source);
  37803. hash_table_set_procedures(new_hash, hash_table_procedures(source));
  37804. hash_table_copy(sc, source, new_hash, 0, hash_table_entries(source));
  37805. s7_gc_unprotect_at(sc, gc_loc);
  37806. return(new_hash);
  37807. }
  37808. case T_ITERATOR:
  37809. return(iterator_copy(sc, source));
  37810. case T_LET:
  37811. check_method(sc, source, sc->copy_symbol, args);
  37812. return(let_copy(sc, source)); /* this copies only the local env and points to outer envs */
  37813. case T_CLOSURE: case T_CLOSURE_STAR:
  37814. case T_MACRO: case T_MACRO_STAR:
  37815. case T_BACRO: case T_BACRO_STAR:
  37816. check_method(sc, source, sc->copy_symbol, args);
  37817. return(copy_closure(sc, source));
  37818. case T_INT_VECTOR:
  37819. case T_FLOAT_VECTOR:
  37820. case T_VECTOR:
  37821. return(s7_vector_copy(sc, source)); /* "shallow" copy */
  37822. case T_PAIR: /* top level only, as in the other cases, last arg checks for circles */
  37823. return(protected_list_copy(sc, source));
  37824. case T_INTEGER:
  37825. new_cell(sc, dest, T_INTEGER);
  37826. integer(dest) = integer(source);
  37827. return(dest);
  37828. case T_RATIO:
  37829. new_cell(sc, dest, T_RATIO);
  37830. numerator(dest) = numerator(source);
  37831. denominator(dest) = denominator(source);
  37832. return(dest);
  37833. case T_REAL:
  37834. new_cell(sc, dest, T_REAL);
  37835. set_real(dest, real(source));
  37836. return(dest);
  37837. case T_COMPLEX:
  37838. new_cell(sc, dest, T_COMPLEX);
  37839. set_real_part(dest, real_part(source));
  37840. set_imag_part(dest, imag_part(source));
  37841. return(dest);
  37842. #if WITH_GMP
  37843. case T_BIG_INTEGER: return(mpz_to_big_integer(sc, big_integer(source)));
  37844. case T_BIG_RATIO: return(mpq_to_big_ratio(sc, big_ratio(source)));
  37845. case T_BIG_REAL: return(mpfr_to_big_real(sc, big_real(source)));
  37846. case T_BIG_COMPLEX: return(mpc_to_big_complex(sc, big_complex(source)));
  37847. #endif
  37848. case T_C_POINTER:
  37849. return(s7_make_c_pointer(sc, s7_c_pointer(source)));
  37850. }
  37851. return(source);
  37852. }
  37853. have_indices = (is_pair(cddr(args)));
  37854. dest = cadr(args);
  37855. if ((source == dest) && (!have_indices))
  37856. return(dest);
  37857. switch (type(source))
  37858. {
  37859. case T_PAIR:
  37860. if (dest == sc->key_readable_symbol) /* a kludge, but I can't think of anything less stupid */
  37861. return(copy_body(sc, source));
  37862. end = s7_list_length(sc, source);
  37863. if (end == 0)
  37864. end = circular_list_entries(source);
  37865. else
  37866. {
  37867. if (end < 0) end = -end;
  37868. }
  37869. break;
  37870. case T_INT_VECTOR:
  37871. case T_FLOAT_VECTOR:
  37872. case T_VECTOR:
  37873. get = vector_getter(source);
  37874. end = vector_length(source);
  37875. break;
  37876. case T_STRING:
  37877. if (is_byte_vector(source))
  37878. get = byte_vector_getter;
  37879. else get = string_getter;
  37880. end = string_length(source);
  37881. break;
  37882. case T_HASH_TABLE:
  37883. end = hash_table_entries(source);
  37884. break;
  37885. case T_C_OBJECT:
  37886. check_method(sc, source, sc->copy_symbol, args);
  37887. {
  37888. s7_pointer x;
  37889. x = object_copy(sc, args);
  37890. if (x == dest)
  37891. return(dest);
  37892. /* if object_copy can't handle args for some reason, it should return #f (not dest), and we'll soldier on... */
  37893. }
  37894. get = c_object_direct_ref(source);
  37895. if (!get) get = c_object_getter;
  37896. end = object_length_to_int(sc, source);
  37897. break;
  37898. case T_LET:
  37899. check_method(sc, source, sc->copy_symbol, args);
  37900. if (source == sc->rootlet)
  37901. return(wrong_type_argument_with_type(sc, sc->copy_symbol, 1, source, make_string_wrapper(sc, "a sequence other than the rootlet")));
  37902. end = let_length(sc, source);
  37903. break;
  37904. case T_NIL:
  37905. end = 0;
  37906. if (is_sequence(dest))
  37907. break;
  37908. default:
  37909. return(wrong_type_argument_with_type(sc, sc->copy_symbol, 1, source, a_sequence_string));
  37910. /* copy doesn't have to duplicate fill!, so (copy 1 #(...)) need not be supported */
  37911. }
  37912. start = 0;
  37913. if (have_indices)
  37914. {
  37915. s7_pointer p;
  37916. p = start_and_end(sc, sc->copy_symbol, NULL, cddr(args), args, 3, &start, &end);
  37917. if (p != sc->gc_nil) return(p);
  37918. }
  37919. if ((start == 0) && (source == dest))
  37920. return(dest);
  37921. source_len = end - start;
  37922. switch (type(dest))
  37923. {
  37924. case T_PAIR:
  37925. dest_len = s7_list_length(sc, dest);
  37926. if (dest_len == 0)
  37927. dest_len = circular_list_entries(dest);
  37928. else
  37929. {
  37930. if (dest_len < 0)
  37931. dest_len = -dest_len;
  37932. }
  37933. break;
  37934. case T_INT_VECTOR:
  37935. case T_FLOAT_VECTOR:
  37936. case T_VECTOR:
  37937. set = vector_setter(dest);
  37938. dest_len = vector_length(dest);
  37939. break;
  37940. case T_STRING:
  37941. if (is_byte_vector(dest))
  37942. set = byte_vector_setter;
  37943. else set = string_setter;
  37944. dest_len = string_length(dest);
  37945. break;
  37946. case T_HASH_TABLE:
  37947. set = hash_table_setter;
  37948. dest_len = source_len;
  37949. break;
  37950. case T_C_OBJECT:
  37951. set = c_object_direct_set(dest);
  37952. if (!set) set = c_object_setter;
  37953. dest_len = object_length_to_int(sc, dest);
  37954. break;
  37955. case T_LET:
  37956. if (dest == sc->rootlet)
  37957. return(wrong_type_argument_with_type(sc, sc->copy_symbol, 2, dest, make_string_wrapper(sc, "a sequence other than the rootlet")));
  37958. set = let_setter;
  37959. dest_len = source_len; /* grows via set, so dest_len isn't relevant */
  37960. break;
  37961. case T_NIL:
  37962. return(sc->nil);
  37963. default:
  37964. return(wrong_type_argument_with_type(sc, sc->copy_symbol, 2, dest, a_sequence_string));
  37965. }
  37966. if ((source_len == 0) || (dest_len == 0))
  37967. return(dest);
  37968. /* end is source_len if not set explicitly */
  37969. if (dest_len < source_len)
  37970. {
  37971. end = dest_len + start;
  37972. source_len = dest_len;
  37973. }
  37974. if ((source != dest) &&
  37975. (type(source) == type(dest)))
  37976. {
  37977. switch (type(source))
  37978. {
  37979. case T_PAIR:
  37980. {
  37981. s7_pointer ps, pd;
  37982. ps = source;
  37983. for (i = 0; i < start; i++)
  37984. ps = cdr(ps);
  37985. for (pd = dest; (i < end) && is_pair(ps) && is_pair(pd); i++, ps = cdr(ps), pd = cdr(pd))
  37986. set_car(pd, car(ps));
  37987. return(dest);
  37988. }
  37989. case T_VECTOR:
  37990. memcpy((void *)(vector_elements(dest)), (void *)((vector_elements(source)) + start), source_len * sizeof(s7_pointer));
  37991. return(dest);
  37992. case T_INT_VECTOR:
  37993. memcpy((void *)(int_vector_elements(dest)), (void *)((int_vector_elements(source)) + start), source_len * sizeof(s7_int));
  37994. return(dest);
  37995. case T_FLOAT_VECTOR:
  37996. memcpy((void *)(float_vector_elements(dest)), (void *)((float_vector_elements(source)) + start), source_len * sizeof(s7_double));
  37997. return(dest);
  37998. case T_STRING: /* this is 4 cases (string/byte-vector) */
  37999. memcpy((void *)string_value(dest), (void *)((string_value(source)) + start), source_len * sizeof(char));
  38000. return(dest);
  38001. case T_C_OBJECT:
  38002. {
  38003. s7_pointer mi, mj;
  38004. int gc_loc1, gc_loc2;
  38005. s7_pointer (*ref)(s7_scheme *sc, s7_pointer obj, s7_pointer args);
  38006. s7_pointer (*set)(s7_scheme *sc, s7_pointer obj, s7_pointer args);
  38007. mi = make_mutable_integer(sc, start);
  38008. mj = make_mutable_integer(sc, end);
  38009. gc_loc1 = s7_gc_protect(sc, mi);
  38010. gc_loc2 = s7_gc_protect(sc, mj);
  38011. ref = c_object_ref(source);
  38012. set = c_object_set(dest);
  38013. for (i = start, j = 0; i < end; i++, j++)
  38014. {
  38015. integer(mi) = i;
  38016. integer(mj) = j;
  38017. set_car(sc->t1_1, mi);
  38018. set_car(sc->t2_2, ref(sc, source, sc->t1_1));
  38019. set_car(sc->t2_1, mj);
  38020. set(sc, dest, sc->t2_1);
  38021. }
  38022. s7_gc_unprotect_at(sc, gc_loc1);
  38023. s7_gc_unprotect_at(sc, gc_loc2);
  38024. return(dest);
  38025. }
  38026. case T_LET:
  38027. break;
  38028. case T_HASH_TABLE:
  38029. {
  38030. s7_pointer p;
  38031. p = hash_table_copy(sc, source, dest, start, end);
  38032. if ((hash_table_checker(source) != hash_table_checker(dest)) &&
  38033. (!hash_table_checker_locked(dest)))
  38034. {
  38035. if (hash_table_checker(dest) == hash_empty)
  38036. hash_table_checker(dest) = hash_table_checker(source);
  38037. else hash_table_checker(dest) = hash_equal;
  38038. }
  38039. return(p);
  38040. }
  38041. break;
  38042. default:
  38043. return(dest);
  38044. }
  38045. }
  38046. switch (type(source))
  38047. {
  38048. case T_PAIR:
  38049. {
  38050. s7_pointer p;
  38051. p = source;
  38052. if (start > 0)
  38053. for (i = 0; i < start; i++)
  38054. p = cdr(p);
  38055. /* dest won't be a pair here -- the pair->pair case was caught above */
  38056. if (is_string(dest)) set_string_error_source(sc, source);
  38057. for (i = start, j = 0; i < end; i++, j++, p = cdr(p))
  38058. set(sc, dest, j, car(p));
  38059. return(dest);
  38060. }
  38061. case T_LET:
  38062. /* implicit index can give n-way reality check (ht growth by new entries)
  38063. * if shadowed entries are they unshadowed by reversal?
  38064. */
  38065. {
  38066. /* source and dest can't be rootlet (checked above) */
  38067. s7_pointer slot;
  38068. slot = let_slots(source);
  38069. for (i = 0; i < start; i++) slot = next_slot(slot);
  38070. if (is_pair(dest))
  38071. {
  38072. s7_pointer p;
  38073. for (i = start, p = dest; i < end; i++, p = cdr(p), slot = next_slot(slot))
  38074. set_car(p, cons(sc, slot_symbol(slot), slot_value(slot)));
  38075. }
  38076. else
  38077. {
  38078. if (is_let(dest))
  38079. {
  38080. for (i = start; i < end; i++, slot = next_slot(slot))
  38081. make_slot_1(sc, dest, slot_symbol(slot), slot_value(slot));
  38082. }
  38083. else
  38084. {
  38085. if (is_hash_table(dest))
  38086. {
  38087. for (i = start; i < end; i++, slot = next_slot(slot))
  38088. s7_hash_table_set(sc, dest, slot_symbol(slot), slot_value(slot));
  38089. }
  38090. else
  38091. {
  38092. for (i = start, j = 0; i < end; i++, j++, slot = next_slot(slot))
  38093. set(sc, dest, j, cons(sc, slot_symbol(slot), slot_value(slot)));
  38094. }
  38095. }
  38096. }
  38097. return(dest);
  38098. }
  38099. case T_HASH_TABLE:
  38100. {
  38101. int loc, skip;
  38102. hash_entry_t **elements;
  38103. hash_entry_t *x = NULL;
  38104. elements = hash_table_elements(source);
  38105. loc = -1;
  38106. skip = start;
  38107. while (skip > 0)
  38108. {
  38109. while (!x) x = elements[++loc];
  38110. skip--;
  38111. x = x->next;
  38112. }
  38113. if (is_pair(dest))
  38114. {
  38115. s7_pointer p;
  38116. for (i = start, p = dest; i < end; i++, p = cdr(p))
  38117. {
  38118. while (!x) x = elements[++loc];
  38119. set_car(p, cons(sc, x->key, x->value));
  38120. x = x->next;
  38121. }
  38122. }
  38123. else
  38124. {
  38125. if (is_let(dest))
  38126. {
  38127. for (i = start; i < end; i++)
  38128. {
  38129. while (!x) x = elements[++loc];
  38130. make_slot_1(sc, dest, x->key, x->value);
  38131. x = x->next;
  38132. }
  38133. }
  38134. else
  38135. {
  38136. for (i = start, j = 0; i < end; i++, j++)
  38137. {
  38138. while (!x) x = elements[++loc];
  38139. set(sc, dest, j, cons(sc, x->key, x->value));
  38140. x = x->next;
  38141. }
  38142. }
  38143. }
  38144. return(dest);
  38145. }
  38146. case T_FLOAT_VECTOR:
  38147. if (is_int_vector(dest))
  38148. {
  38149. for (i = start, j = 0; i < end; i++, j++)
  38150. int_vector_element(dest, j) = (s7_int)(float_vector_element(source, i));
  38151. return(dest);
  38152. }
  38153. break;
  38154. case T_INT_VECTOR:
  38155. if (is_float_vector(dest))
  38156. {
  38157. for (i = start, j = 0; i < end; i++, j++)
  38158. float_vector_element(dest, j) = (s7_double)(int_vector_element(source, i));
  38159. return(dest);
  38160. }
  38161. if (is_string(dest)) /* includes byte-vector, as below */
  38162. {
  38163. for (i = start, j = 0; i < end; i++, j++)
  38164. string_value(dest)[j] = (unsigned char)int_vector_element(source, i);
  38165. return(dest);
  38166. }
  38167. break;
  38168. case T_STRING:
  38169. if (is_normal_vector(dest))
  38170. {
  38171. if (is_byte_vector(source))
  38172. {
  38173. for (i = start, j = 0; i < end; i++, j++)
  38174. vector_element(dest, j) = make_integer(sc, (s7_int)((unsigned char)string_value(source)[i]));
  38175. }
  38176. else
  38177. {
  38178. for (i = start, j = 0; i < end; i++, j++)
  38179. vector_element(dest, j) = s7_make_character(sc, (unsigned char)string_value(source)[i]);
  38180. }
  38181. return(dest);
  38182. }
  38183. if (is_int_vector(dest))
  38184. {
  38185. for (i = start, j = 0; i < end; i++, j++)
  38186. int_vector_element(dest, j) = (s7_int)((unsigned char)(string_value(source)[i]));
  38187. return(dest);
  38188. }
  38189. if (is_float_vector(dest))
  38190. {
  38191. for (i = start, j = 0; i < end; i++, j++)
  38192. float_vector_element(dest, j) = (s7_double)((unsigned char)(string_value(source)[i]));
  38193. return(dest);
  38194. }
  38195. }
  38196. if (is_pair(dest))
  38197. {
  38198. s7_pointer p;
  38199. for (i = start, p = dest; i < end; i++, p = cdr(p))
  38200. set_car(p, get(sc, source, i));
  38201. }
  38202. else
  38203. {
  38204. /* if source == dest here, we're moving data backwards, so this is safe in either case */
  38205. if (is_string(dest)) set_string_error_source(sc, source);
  38206. for (i = start, j = 0; i < end; i++, j++)
  38207. set(sc, dest, j, get(sc, source, i));
  38208. }
  38209. /* some choices probably should raise an error, but don't:
  38210. * (copy (make-hash-table) "1") ; nothing to copy (empty hash table), so no error
  38211. */
  38212. return(dest);
  38213. }
  38214. #define g_copy s7_copy
  38215. static s7_pointer c_copy(s7_scheme *sc, s7_pointer x) {return(s7_copy(sc, set_plist_1(sc, x)));}
  38216. PF_TO_PF(copy, c_copy)
  38217. /* -------------------------------- reverse -------------------------------- */
  38218. static s7_pointer g_reverse(s7_scheme *sc, s7_pointer args)
  38219. {
  38220. #define H_reverse "(reverse lst) returns a list with the elements of lst in reverse order. reverse \
  38221. also accepts a string or vector argument."
  38222. #define Q_reverse s7_make_signature(sc, 2, sc->is_sequence_symbol, sc->is_sequence_symbol)
  38223. s7_pointer p, np;
  38224. p = car(args);
  38225. sc->temp3 = p;
  38226. np = sc->nil;
  38227. switch (type(p))
  38228. {
  38229. case T_NIL:
  38230. return(sc->nil);
  38231. case T_PAIR:
  38232. return(s7_reverse(sc, p));
  38233. case T_STRING:
  38234. {
  38235. char *source, *dest, *end;
  38236. int len;
  38237. len = string_length(p);
  38238. source = string_value(p);
  38239. end = (char *)(source + len);
  38240. dest = (char *)malloc((len + 1) * sizeof(char));
  38241. dest[len] = 0;
  38242. np = make_string_uncopied_with_length(sc, dest, len);
  38243. dest += len;
  38244. while (source < end) *(--dest) = *source++;
  38245. if (is_byte_vector(p))
  38246. set_byte_vector(np);
  38247. }
  38248. break;
  38249. case T_INT_VECTOR:
  38250. {
  38251. s7_int *source, *dest, *end;
  38252. s7_int len;
  38253. len = vector_length(p);
  38254. if (vector_rank(p) > 1)
  38255. np = g_make_vector(sc, set_plist_3(sc, g_vector_dimensions(sc, set_plist_1(sc, p)), small_int(0), sc->T));
  38256. else np = make_vector_1(sc, len, NOT_FILLED, T_INT_VECTOR);
  38257. source = int_vector_elements(p);
  38258. end = (s7_int *)(source + len);
  38259. dest = (s7_int *)(int_vector_elements(np) + len);
  38260. while (source < end) *(--dest) = *source++;
  38261. }
  38262. break;
  38263. case T_FLOAT_VECTOR:
  38264. {
  38265. s7_double *source, *dest, *end;
  38266. s7_int len;
  38267. len = vector_length(p);
  38268. if (vector_rank(p) > 1)
  38269. np = g_make_vector(sc, set_plist_3(sc, g_vector_dimensions(sc, set_plist_1(sc, p)), real_zero, sc->T));
  38270. else np = make_vector_1(sc, len, NOT_FILLED, T_FLOAT_VECTOR);
  38271. source = float_vector_elements(p);
  38272. end = (s7_double *)(source + len);
  38273. dest = (s7_double *)(float_vector_elements(np) + len);
  38274. while (source < end) *(--dest) = *source++;
  38275. }
  38276. break;
  38277. case T_VECTOR:
  38278. {
  38279. s7_pointer *source, *dest, *end;
  38280. s7_int len;
  38281. len = vector_length(p);
  38282. if (vector_rank(p) > 1)
  38283. np = g_make_vector(sc, set_plist_1(sc, g_vector_dimensions(sc, list_1(sc, p))));
  38284. else np = make_vector_1(sc, len, NOT_FILLED, T_VECTOR);
  38285. source = vector_elements(p);
  38286. end = (s7_pointer *)(source + len);
  38287. dest = (s7_pointer *)(vector_elements(np) + len);
  38288. while (source < end) *(--dest) = *source++;
  38289. }
  38290. break;
  38291. case T_HASH_TABLE:
  38292. return(hash_table_reverse(sc, p));
  38293. case T_C_OBJECT:
  38294. check_method(sc, p, sc->reverse_symbol, args);
  38295. if (c_object_reverse(p))
  38296. return((*(c_object_reverse(p)))(sc, args));
  38297. eval_error(sc, "attempt to reverse ~S?", p);
  38298. default:
  38299. method_or_bust_with_type(sc, p, sc->reverse_symbol, args, a_sequence_string, 0);
  38300. }
  38301. return(np);
  38302. }
  38303. static s7_pointer c_reverse(s7_scheme *sc, s7_pointer x) {return(g_reverse(sc, set_plist_1(sc, x)));}
  38304. PF_TO_PF(reverse, c_reverse)
  38305. static s7_pointer c_reverse_in_place(s7_scheme *sc, s7_pointer p)
  38306. {
  38307. switch (type(p))
  38308. {
  38309. case T_NIL:
  38310. return(sc->nil);
  38311. case T_PAIR:
  38312. {
  38313. s7_pointer np;
  38314. np = reverse_in_place(sc, sc->nil, p);
  38315. if (is_null(np))
  38316. return(simple_wrong_type_argument_with_type(sc, sc->reverseb_symbol, p, a_proper_list_string));
  38317. return(np);
  38318. }
  38319. break;
  38320. /* (reverse! p) is supposed to change p directly and lisp programmers expect reverse! to be fast
  38321. * so in a sense this is different from the other cases: it assumes (set! p (reverse! p))
  38322. * To make (reverse! p) direct:
  38323. * for (l = p, r = cdr(p); is_pair(r); l = r, r = cdr(r)) opt1(r) = l;
  38324. * if (!is_null(r)) return(simple_wrong_type_argument_with_type(sc, sc->reverseb_symbol, p, a_proper_list_string));
  38325. * 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);}
  38326. */
  38327. case T_STRING:
  38328. {
  38329. int len;
  38330. char *s1, *s2;
  38331. len = string_length(p);
  38332. if (len < 2) return(p);
  38333. s1 = string_value(p);
  38334. s2 = (char *)(s1 + len - 1);
  38335. while (s1 < s2) {char c; c = *s1; *s1++ = *s2; *s2-- = c;}
  38336. }
  38337. break;
  38338. case T_INT_VECTOR:
  38339. {
  38340. s7_int len;
  38341. s7_int *s1, *s2;
  38342. len = vector_length(p);
  38343. if (len < 2) return(p);
  38344. s1 = int_vector_elements(p);
  38345. s2 = (s7_int *)(s1 + len - 1);
  38346. while (s1 < s2) {s7_int c; c = *s1; *s1++ = *s2; *s2-- = c;}
  38347. }
  38348. break;
  38349. case T_FLOAT_VECTOR:
  38350. {
  38351. s7_int len;
  38352. s7_double *s1, *s2;
  38353. len = vector_length(p);
  38354. if (len < 2) return(p);
  38355. s1 = float_vector_elements(p);
  38356. s2 = (s7_double *)(s1 + len - 1);
  38357. while (s1 < s2) {s7_double c; c = *s1; *s1++ = *s2; *s2-- = c;}
  38358. }
  38359. break;
  38360. case T_VECTOR:
  38361. {
  38362. s7_int len;
  38363. s7_pointer *s1, *s2;
  38364. len = vector_length(p);
  38365. if (len < 2) return(p);
  38366. s1 = vector_elements(p);
  38367. s2 = (s7_pointer *)(s1 + len - 1);
  38368. while (s1 < s2) {s7_pointer c; c = *s1; *s1++ = *s2; *s2-- = c;}
  38369. }
  38370. break;
  38371. default:
  38372. if ((is_simple_sequence(p)) &&
  38373. (!has_methods(p)))
  38374. return(simple_wrong_type_argument_with_type(sc, sc->reverseb_symbol, p, make_string_wrapper(sc, "a vector, string, or list")));
  38375. method_or_bust_with_type(sc, p, sc->reverseb_symbol, list_1(sc, p), a_sequence_string, 0);
  38376. }
  38377. return(p);
  38378. }
  38379. static s7_pointer g_reverse_in_place(s7_scheme *sc, s7_pointer args)
  38380. {
  38381. #define H_reverse_in_place "(reverse! lst) reverses lst in place"
  38382. #define Q_reverse_in_place s7_make_signature(sc, 2, sc->is_sequence_symbol, sc->is_sequence_symbol)
  38383. return(c_reverse_in_place(sc, car(args)));
  38384. }
  38385. PF_TO_PF(reverse_in_place, c_reverse_in_place)
  38386. /* -------------------------------- fill! -------------------------------- */
  38387. static s7_pointer list_fill(s7_scheme *sc, s7_pointer args)
  38388. {
  38389. /* ambiguous ("tree-fill"?) but if it's like vector-fill, we just stomp on the top level */
  38390. s7_pointer x, y, obj, val;
  38391. s7_int i, start = 0, end, len;
  38392. obj = car(args);
  38393. len = s7_list_length(sc, obj);
  38394. end = len;
  38395. if (end < 0) end = -end; else {if (end == 0) end = 123123123;}
  38396. val = cadr(args);
  38397. if (!is_null(cddr(args)))
  38398. {
  38399. s7_pointer p;
  38400. p = start_and_end(sc, sc->fill_symbol, sc->fill_symbol, cddr(args), args, 3, &start, &end);
  38401. if (p != sc->gc_nil) return(p);
  38402. if (start == end) return(val);
  38403. }
  38404. if (len > 0)
  38405. {
  38406. s7_int i;
  38407. s7_pointer p;
  38408. if (end < len) len = end;
  38409. for (i = 0, p = obj; i < start; p = cdr(p), i++);
  38410. for (; i < len; p = cdr(p), i++) set_car(p, val);
  38411. return(val);
  38412. }
  38413. for (x = obj, y = obj, i = 0; ;i++)
  38414. {
  38415. if ((end > 0) && (i >= end))
  38416. return(val);
  38417. if (i >= start) set_car(x, val);
  38418. if (!is_pair(cdr(x)))
  38419. {
  38420. if (!is_null(cdr(x)))
  38421. set_cdr(x, val);
  38422. return(val);
  38423. }
  38424. x = cdr(x);
  38425. if ((i & 1) != 0) y = cdr(y);
  38426. if (x == y) return(val);
  38427. }
  38428. return(val);
  38429. }
  38430. s7_pointer s7_fill(s7_scheme *sc, s7_pointer args)
  38431. {
  38432. #define H_fill "(fill! obj val (start 0) end) fills obj with val"
  38433. #define Q_fill s7_make_circular_signature(sc, 3, 4, sc->T, sc->is_sequence_symbol, sc->T, sc->is_integer_symbol)
  38434. s7_pointer p;
  38435. p = car(args);
  38436. switch (type(p))
  38437. {
  38438. case T_STRING:
  38439. return(g_string_fill(sc, args)); /* redundant type check here and below */
  38440. case T_INT_VECTOR:
  38441. case T_FLOAT_VECTOR:
  38442. case T_VECTOR:
  38443. return(g_vector_fill(sc, args));
  38444. case T_PAIR:
  38445. return(list_fill(sc, args));
  38446. case T_NIL:
  38447. return(cadr(args)); /* this parallels the empty vector case */
  38448. case T_HASH_TABLE:
  38449. return(hash_table_fill(sc, args));
  38450. case T_C_OBJECT:
  38451. check_method(sc, p, sc->fill_symbol, args);
  38452. if (c_object_fill(p))
  38453. return((*(c_object_fill(p)))(sc, args));
  38454. eval_error(sc, "attempt to fill ~S?", p);
  38455. default:
  38456. check_method(sc, p, sc->fill_symbol, args);
  38457. }
  38458. return(wrong_type_argument_with_type(sc, sc->fill_symbol, 1, p, a_sequence_string)); /* (fill! 1 0) */
  38459. }
  38460. #define g_fill s7_fill
  38461. /* perhaps (fill iterator obj) could fill the underlying sequence (if any) -- not let/closure
  38462. * similarly for length, reverse etc
  38463. */
  38464. static s7_pointer c_fill(s7_scheme *sc, s7_pointer x, s7_pointer y) {return(s7_fill(sc, set_plist_2(sc, x, y)));}
  38465. PF2_TO_PF(fill, c_fill)
  38466. /* -------------------------------- append -------------------------------- */
  38467. static s7_int sequence_length(s7_scheme *sc, s7_pointer lst)
  38468. {
  38469. switch (type(lst))
  38470. {
  38471. case T_PAIR:
  38472. {
  38473. int len;
  38474. len = s7_list_length(sc, lst);
  38475. if (len == 0) return(-1);
  38476. return(len);
  38477. }
  38478. case T_NIL: return(0);
  38479. case T_INT_VECTOR:
  38480. case T_FLOAT_VECTOR:
  38481. case T_VECTOR: return(vector_length(lst));
  38482. case T_STRING: return(string_length(lst));
  38483. case T_HASH_TABLE: return(hash_table_entries(lst));
  38484. case T_LET: return(let_length(sc, lst));
  38485. case T_C_OBJECT:
  38486. {
  38487. s7_pointer x;
  38488. x = object_length(sc, lst);
  38489. if (s7_is_integer(x))
  38490. return(s7_integer(x));
  38491. }
  38492. }
  38493. return(-1);
  38494. }
  38495. static s7_int total_sequence_length(s7_scheme *sc, s7_pointer args, s7_pointer caller, int typ)
  38496. {
  38497. s7_pointer p;
  38498. int i;
  38499. s7_int len = 0;
  38500. for (i = 1, p = args; is_pair(p); p = cdr(p), i++)
  38501. {
  38502. s7_pointer seq;
  38503. s7_int n;
  38504. seq = car(p);
  38505. n = sequence_length(sc, seq);
  38506. if ((n > 0) &&
  38507. (typ != T_FREE) &&
  38508. ((type(seq) == T_HASH_TABLE) || /* can't append hash-tables (no obvious meaning to the operation) */
  38509. ((type(seq) == T_LET) && /* similarly for lets, unless this is a mock-string or something similar */
  38510. ((!has_methods(seq)) || (find_method(sc, seq, sc->append_symbol) == sc->undefined)))))
  38511. {
  38512. wrong_type_argument(sc, sc->append_symbol, i, seq, typ);
  38513. return(0);
  38514. }
  38515. if (n < 0)
  38516. {
  38517. wrong_type_argument_with_type(sc, sc->append_symbol, i, seq, (is_pair(seq)) ? a_proper_list_string : a_sequence_string);
  38518. return(0);
  38519. }
  38520. len += n;
  38521. }
  38522. return(len);
  38523. }
  38524. static s7_pointer vector_append(s7_scheme *sc, s7_pointer args, int typ)
  38525. {
  38526. s7_pointer new_vec;
  38527. s7_int len;
  38528. len = total_sequence_length(sc, args, sc->vector_append_symbol, (typ == T_VECTOR) ? T_FREE : ((typ == T_FLOAT_VECTOR) ? T_REAL : T_INTEGER));
  38529. 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 */
  38530. if (len > 0)
  38531. {
  38532. s7_pointer p, sv;
  38533. int i;
  38534. sc->temp9 = new_vec; /* s7_copy below can call s7_error so s7_gc_protect here is tricky -- use a preset position perhaps? */
  38535. sv = make_subvector(sc, new_vec);
  38536. sc->temp10 = sv;
  38537. for (i = 0, p = args; is_pair(p); p = cdr(p))
  38538. {
  38539. s7_int n;
  38540. s7_pointer x;
  38541. x = car(p);
  38542. n = sequence_length(sc, x);
  38543. if (n > 0)
  38544. {
  38545. vector_length(sv) = n;
  38546. s7_copy(sc, set_plist_2(sc, x, sv));
  38547. vector_length(sv) = 0; /* so GC doesn't march off the end */
  38548. i += n;
  38549. if (typ == T_VECTOR)
  38550. vector_elements(sv) = (s7_pointer *)(vector_elements(new_vec) + i);
  38551. else
  38552. {
  38553. if (typ == T_FLOAT_VECTOR)
  38554. float_vector_elements(sv) = (s7_double *)(float_vector_elements(new_vec) + i);
  38555. else int_vector_elements(sv) = (s7_int *)(int_vector_elements(new_vec) + i);
  38556. }
  38557. }
  38558. }
  38559. set_plist_2(sc, sc->nil, sc->nil);
  38560. sc->temp9 = sc->nil;
  38561. sc->temp10 = sc->nil;
  38562. vector_length(sv) = 0;
  38563. }
  38564. return(new_vec);
  38565. }
  38566. static s7_pointer string_append(s7_scheme *sc, s7_pointer args)
  38567. {
  38568. s7_pointer new_str;
  38569. s7_int len;
  38570. len = total_sequence_length(sc, args, sc->string_append_symbol, (is_byte_vector(car(args))) ? T_INTEGER : T_CHARACTER);
  38571. new_str = make_empty_string(sc, len, 0);
  38572. if (is_byte_vector(car(args)))
  38573. set_byte_vector(new_str);
  38574. if (len > 0)
  38575. {
  38576. s7_pointer p, sv;
  38577. int i;
  38578. sc->temp9 = new_str;
  38579. sv = make_string_wrapper_with_length(sc, (const char *)string_value(new_str), len);
  38580. if (is_byte_vector(new_str))
  38581. set_byte_vector(sv);
  38582. sc->temp10 = sv;
  38583. for (i = 0, p = args; is_pair(p); p = cdr(p))
  38584. {
  38585. s7_pointer x;
  38586. s7_int n;
  38587. x = car(p);
  38588. n = sequence_length(sc, x);
  38589. if (n > 0)
  38590. {
  38591. string_length(sv) = n;
  38592. s7_copy(sc, set_plist_2(sc, x, sv));
  38593. i += n;
  38594. string_value(sv) = (char *)(string_value(new_str) + i);
  38595. }
  38596. }
  38597. set_plist_2(sc, sc->nil, sc->nil);
  38598. sc->temp9 = sc->nil;
  38599. sc->temp10 = sc->nil;
  38600. string_length(sv) = 0;
  38601. }
  38602. return(new_str);
  38603. }
  38604. static s7_pointer hash_table_append(s7_scheme *sc, s7_pointer args)
  38605. {
  38606. s7_pointer new_hash, p;
  38607. new_hash = s7_make_hash_table(sc, sc->default_hash_table_length);
  38608. for (p = args; is_pair(p); p = cdr(p))
  38609. s7_copy(sc, set_plist_2(sc, car(p), new_hash));
  38610. set_plist_2(sc, sc->nil, sc->nil);
  38611. return(new_hash);
  38612. }
  38613. static s7_pointer let_append(s7_scheme *sc, s7_pointer args)
  38614. {
  38615. s7_pointer new_let, p, e;
  38616. e = car(args);
  38617. check_method(sc, e, sc->append_symbol, args);
  38618. new_let = new_frame_in_env(sc, sc->nil);
  38619. for (p = args; is_pair(p); p = cdr(p))
  38620. s7_copy(sc, set_plist_2(sc, car(p), new_let));
  38621. set_plist_2(sc, sc->nil, sc->nil);
  38622. return(new_let);
  38623. }
  38624. static s7_pointer g_append(s7_scheme *sc, s7_pointer args)
  38625. {
  38626. #define H_append "(append ...) returns its argument sequences appended into one sequence"
  38627. #define Q_append s7_make_circular_signature(sc, 0, 1, sc->T)
  38628. s7_pointer a1;
  38629. if (is_null(args)) return(sc->nil); /* (append) -> () */
  38630. a1 = car(args); /* first arg determines result type unless all args but last are empty (sigh) */
  38631. if (is_null(cdr(args))) return(a1); /* (append <anything>) -> <anything> */
  38632. switch (type(a1))
  38633. {
  38634. case T_NIL:
  38635. case T_PAIR:
  38636. return(g_list_append(sc, args)); /* only list case accepts any trailing arg because dotted lists are special */
  38637. case T_VECTOR:
  38638. case T_INT_VECTOR:
  38639. case T_FLOAT_VECTOR:
  38640. return(vector_append(sc, args, type(a1)));
  38641. case T_STRING:
  38642. return(string_append(sc, args));
  38643. case T_HASH_TABLE:
  38644. return(hash_table_append(sc, args));
  38645. case T_LET:
  38646. return(let_append(sc, args));
  38647. default:
  38648. check_method(sc, a1, sc->append_symbol, args);
  38649. }
  38650. return(wrong_type_argument_with_type(sc, sc->append_symbol, 1, a1, a_sequence_string)); /* (append 1 0) */
  38651. }
  38652. static s7_pointer object_to_list(s7_scheme *sc, s7_pointer obj)
  38653. {
  38654. /* used only in format_to_port_1 and (map values ...) */
  38655. switch (type(obj))
  38656. {
  38657. case T_INT_VECTOR:
  38658. case T_FLOAT_VECTOR:
  38659. case T_VECTOR:
  38660. return(s7_vector_to_list(sc, obj));
  38661. case T_STRING:
  38662. if (is_byte_vector(obj))
  38663. return(byte_vector_to_list(sc, string_value(obj), string_length(obj)));
  38664. return(s7_string_to_list(sc, string_value(obj), string_length(obj)));
  38665. case T_HASH_TABLE:
  38666. if (hash_table_entries(obj) > 0)
  38667. {
  38668. s7_pointer x, iterator;
  38669. iterator = s7_make_iterator(sc, obj);
  38670. sc->temp8 = iterator;
  38671. sc->w = sc->nil;
  38672. while (true)
  38673. {
  38674. x = s7_iterate(sc, iterator);
  38675. if (iterator_is_at_end(iterator)) break;
  38676. sc->w = cons(sc, x, sc->w);
  38677. }
  38678. x = sc->w;
  38679. sc->w = sc->nil;
  38680. sc->temp8 = sc->nil;
  38681. return(x);
  38682. }
  38683. return(sc->nil);
  38684. case T_LET:
  38685. #if (!WITH_PURE_S7)
  38686. check_method(sc, obj, sc->let_to_list_symbol, list_1(sc, obj));
  38687. #endif
  38688. return(s7_let_to_list(sc, obj));
  38689. case T_ITERATOR:
  38690. {
  38691. s7_pointer result, p = NULL;
  38692. int results = 0;
  38693. result = sc->nil;
  38694. while (true)
  38695. {
  38696. s7_pointer val;
  38697. val = s7_iterate(sc, obj);
  38698. if ((val == sc->ITERATOR_END) &&
  38699. (iterator_is_at_end(obj)))
  38700. {
  38701. sc->temp8 = sc->nil;
  38702. return(result);
  38703. }
  38704. if (sc->safety > 0)
  38705. {
  38706. results++;
  38707. if (results > 10000)
  38708. {
  38709. fprintf(stderr, "iterator in object->list is creating a very long list!\n");
  38710. results = S7_LONG_MIN;
  38711. }
  38712. }
  38713. if (val != sc->no_value)
  38714. {
  38715. if (is_null(result))
  38716. {
  38717. if (is_multiple_value(val))
  38718. {
  38719. result = multiple_value(val);
  38720. clear_multiple_value(val);
  38721. for (p = result; is_pair(cdr(p)); p = cdr(p));
  38722. }
  38723. else
  38724. {
  38725. result = cons(sc, val, sc->nil);
  38726. p = result;
  38727. }
  38728. sc->temp8 = result;
  38729. }
  38730. else
  38731. {
  38732. if (is_multiple_value(val))
  38733. {
  38734. set_cdr(p, multiple_value(val));
  38735. clear_multiple_value(val);
  38736. for (; is_pair(cdr(p)); p = cdr(p));
  38737. }
  38738. else
  38739. {
  38740. set_cdr(p, cons(sc, val, sc->nil));
  38741. p = cdr(p);
  38742. }
  38743. }
  38744. }
  38745. }
  38746. }
  38747. case T_C_OBJECT:
  38748. {
  38749. long int i, len; /* the "long" matters on 64-bit machines */
  38750. s7_pointer x, z, result;
  38751. int gc_z = -1;
  38752. x = object_length(sc, obj);
  38753. if (s7_is_integer(x))
  38754. len = s7_integer(x);
  38755. else return(sc->F);
  38756. if (len < 0)
  38757. return(sc->F);
  38758. if (len == 0)
  38759. return(sc->nil);
  38760. result = make_list(sc, len, sc->nil);
  38761. sc->temp8 = result;
  38762. z = list_1(sc, sc->F);
  38763. gc_z = s7_gc_protect(sc, z);
  38764. set_car(sc->z2_1, sc->x);
  38765. set_car(sc->z2_2, sc->z);
  38766. for (i = 0, x = result; i < len; i++, x = cdr(x))
  38767. {
  38768. set_car(z, make_integer(sc, i));
  38769. set_car(x, (*(c_object_ref(obj)))(sc, obj, z));
  38770. }
  38771. sc->x = car(sc->z2_1);
  38772. sc->z = car(sc->z2_2);
  38773. s7_gc_unprotect_at(sc, gc_z);
  38774. sc->temp8 = sc->nil;
  38775. return(result);
  38776. }
  38777. }
  38778. return(obj);
  38779. }
  38780. /* -------------------------------- object->let -------------------------------- */
  38781. static bool is_decodable(s7_scheme *sc, s7_pointer p);
  38782. static s7_pointer stack_entries(s7_scheme *sc, s7_pointer stack, int top);
  38783. static s7_pointer g_object_to_let(s7_scheme *sc, s7_pointer args)
  38784. {
  38785. #define H_object_to_let "(object->let obj) returns a let (namespace) describing obj."
  38786. #define Q_object_to_let s7_make_signature(sc, 2, sc->is_let_symbol, sc->T)
  38787. s7_pointer obj;
  38788. obj = car(args);
  38789. switch (type(obj))
  38790. {
  38791. case T_NIL:
  38792. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_null_symbol)));
  38793. case T_UNSPECIFIED:
  38794. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, obj)));
  38795. case T_SYNTAX:
  38796. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, s7_make_symbol(sc, "syntax?"))));
  38797. case T_UNIQUE:
  38798. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, (is_eof(obj)) ? sc->is_eof_object_symbol : obj)));
  38799. case T_BOOLEAN:
  38800. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_boolean_symbol)));
  38801. case T_SYMBOL:
  38802. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, (is_keyword(obj)) ? sc->is_keyword_symbol : sc->is_symbol_symbol)));
  38803. case T_CHARACTER:
  38804. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_char_symbol)));
  38805. case T_INTEGER:
  38806. case T_BIG_INTEGER:
  38807. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_integer_symbol)));
  38808. case T_RATIO:
  38809. case T_BIG_RATIO:
  38810. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_rational_symbol)));
  38811. case T_REAL:
  38812. case T_BIG_REAL:
  38813. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_real_symbol)));
  38814. case T_COMPLEX:
  38815. case T_BIG_COMPLEX:
  38816. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_complex_symbol)));
  38817. case T_STRING:
  38818. return(s7_inlet(sc, s7_list(sc, 6, sc->value_symbol, obj,
  38819. sc->type_symbol, (is_byte_vector(obj)) ? sc->is_byte_vector_symbol : sc->is_string_symbol,
  38820. sc->length_symbol, s7_length(sc, obj))));
  38821. case T_PAIR:
  38822. return(s7_inlet(sc, s7_list(sc, 6, sc->value_symbol, obj,
  38823. sc->type_symbol, sc->is_pair_symbol,
  38824. sc->length_symbol, s7_length(sc, obj))));
  38825. case T_RANDOM_STATE:
  38826. #if WITH_GMP
  38827. return(s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_random_state_symbol)));
  38828. #else
  38829. return(s7_inlet(sc, s7_list(sc, 8, sc->value_symbol, obj,
  38830. sc->type_symbol, sc->is_random_state_symbol,
  38831. s7_make_symbol(sc, "seed"), s7_make_integer(sc, random_seed(obj)),
  38832. s7_make_symbol(sc, "carry"), s7_make_integer(sc, random_carry(obj)))));
  38833. #endif
  38834. case T_GOTO:
  38835. return(s7_inlet(sc, s7_list(sc, 6, sc->value_symbol, obj,
  38836. sc->type_symbol, s7_make_symbol(sc, "goto?"),
  38837. s7_make_symbol(sc, "active"), s7_make_boolean(sc, call_exit_active(obj)))));
  38838. case T_INT_VECTOR:
  38839. case T_FLOAT_VECTOR:
  38840. case T_VECTOR:
  38841. return(s7_inlet(sc, s7_list(sc, 10, sc->value_symbol, obj,
  38842. sc->type_symbol,
  38843. (is_int_vector(obj)) ? sc->is_int_vector_symbol : ((is_float_vector(obj)) ? sc->is_float_vector_symbol : sc->is_vector_symbol),
  38844. sc->length_symbol, s7_length(sc, obj),
  38845. s7_make_symbol(sc, "dimensions"), g_vector_dimensions(sc, list_1(sc, obj)),
  38846. s7_make_symbol(sc, "shared"),
  38847. ((vector_has_dimensional_info(obj)) && (is_normal_vector(shared_vector(obj)))) ? shared_vector(obj) : sc->F)));
  38848. case T_C_POINTER:
  38849. return(s7_inlet(sc, s7_list(sc, 6, sc->value_symbol, obj,
  38850. sc->type_symbol, sc->is_c_pointer_symbol,
  38851. s7_make_symbol(sc, "s7-value"),
  38852. ((is_decodable(sc, (s7_pointer)raw_pointer(obj))) &&
  38853. (!is_free(obj))) ? g_object_to_let(sc, cons(sc, (s7_pointer)raw_pointer(obj), sc->nil)) : sc->F)));
  38854. case T_CONTINUATION:
  38855. {
  38856. s7_pointer let;
  38857. int gc_loc;
  38858. let = s7_inlet(sc, s7_list(sc, 4, sc->value_symbol, obj, sc->type_symbol, sc->is_continuation_symbol));
  38859. gc_loc = s7_gc_protect(sc, let);
  38860. s7_varlet(sc, let, s7_make_symbol(sc, "stack"), stack_entries(sc, continuation_stack(obj), continuation_stack_top(obj)));
  38861. s7_gc_unprotect_at(sc, gc_loc);
  38862. return(let);
  38863. }
  38864. case T_ITERATOR:
  38865. {
  38866. s7_pointer let, seq;
  38867. seq = iterator_sequence(obj);
  38868. let = s7_inlet(sc, s7_list(sc, 8, sc->value_symbol, obj,
  38869. sc->type_symbol, sc->is_iterator_symbol,
  38870. s7_make_symbol(sc, "at-end"), s7_make_boolean(sc, iterator_is_at_end(obj)),
  38871. s7_make_symbol(sc, "sequence"), iterator_sequence(obj)));
  38872. if (is_pair(seq))
  38873. s7_varlet(sc, let, sc->length_symbol, s7_length(sc, seq));
  38874. else
  38875. {
  38876. if (is_hash_table(seq))
  38877. s7_varlet(sc, let, sc->length_symbol, s7_make_integer(sc, hash_table_entries(seq)));
  38878. else s7_varlet(sc, let, sc->length_symbol, s7_length(sc, obj));
  38879. }
  38880. if ((is_string(seq)) ||
  38881. (is_normal_vector(seq)) ||
  38882. (is_int_vector(seq)) ||
  38883. (is_float_vector(seq)) ||
  38884. (seq == sc->rootlet) ||
  38885. (is_c_object(seq)) ||
  38886. (is_hash_table(seq)))
  38887. s7_varlet(sc, let, s7_make_symbol(sc, "position"), s7_make_integer(sc, iterator_position(obj)));
  38888. else
  38889. {
  38890. if (is_pair(seq))
  38891. s7_varlet(sc, let, s7_make_symbol(sc, "position"), iterator_current(obj));
  38892. }
  38893. return(let);
  38894. }
  38895. case T_HASH_TABLE:
  38896. {
  38897. s7_pointer let;
  38898. let = s7_inlet(sc, s7_list(sc, 10, sc->value_symbol, obj,
  38899. sc->type_symbol, sc->is_hash_table_symbol,
  38900. sc->length_symbol, s7_length(sc, obj),
  38901. s7_make_symbol(sc, "entries"), s7_make_integer(sc, hash_table_entries(obj)),
  38902. s7_make_symbol(sc, "locked"), s7_make_boolean(sc, hash_table_checker_locked(obj))));
  38903. if ((hash_table_checker(obj) == hash_eq) ||
  38904. (hash_table_checker(obj) == hash_c_function) ||
  38905. (hash_table_checker(obj) == hash_closure) ||
  38906. (hash_table_checker(obj) == hash_equal_eq) ||
  38907. (hash_table_checker(obj) == hash_equal_syntax) ||
  38908. (hash_table_checker(obj) == hash_symbol))
  38909. s7_varlet(sc, let, s7_make_symbol(sc, "function"), sc->is_eq_symbol);
  38910. else
  38911. {
  38912. if (hash_table_checker(obj) == hash_eqv)
  38913. s7_varlet(sc, let, s7_make_symbol(sc, "function"), sc->is_eqv_symbol);
  38914. else
  38915. {
  38916. if ((hash_table_checker(obj) == hash_equal) ||
  38917. (hash_table_checker(obj) == hash_empty))
  38918. s7_varlet(sc, let, s7_make_symbol(sc, "function"), sc->is_equal_symbol);
  38919. else
  38920. {
  38921. if (hash_table_checker(obj) == hash_morally_equal)
  38922. s7_varlet(sc, let, s7_make_symbol(sc, "function"), sc->is_morally_equal_symbol);
  38923. else
  38924. {
  38925. if ((hash_table_checker(obj) == hash_number) ||
  38926. (hash_table_checker(obj) == hash_int) ||
  38927. (hash_table_checker(obj) == hash_float) ||
  38928. (hash_table_checker(obj) == hash_equal_real) ||
  38929. (hash_table_checker(obj) == hash_equal_complex))
  38930. s7_varlet(sc, let, s7_make_symbol(sc, "function"), sc->eq_symbol);
  38931. else
  38932. {
  38933. if (hash_table_checker(obj) == hash_string)
  38934. s7_varlet(sc, let, s7_make_symbol(sc, "function"), sc->string_eq_symbol);
  38935. else
  38936. {
  38937. if (hash_table_checker(obj) == hash_char)
  38938. s7_varlet(sc, let, s7_make_symbol(sc, "function"), sc->char_eq_symbol);
  38939. #if (!WITH_PURE_S7)
  38940. else
  38941. {
  38942. if (hash_table_checker(obj) == hash_ci_char)
  38943. s7_varlet(sc, let, s7_make_symbol(sc, "function"), sc->char_ci_eq_symbol);
  38944. else
  38945. {
  38946. if (hash_table_checker(obj) == hash_ci_string)
  38947. s7_varlet(sc, let, s7_make_symbol(sc, "function"), sc->string_ci_eq_symbol);
  38948. }}
  38949. #endif
  38950. }}}}}}
  38951. return(let);
  38952. }
  38953. case T_LET:
  38954. {
  38955. s7_pointer let;
  38956. let = s7_inlet(sc, s7_list(sc, 10, sc->value_symbol, obj,
  38957. sc->type_symbol, sc->is_let_symbol,
  38958. sc->length_symbol, s7_length(sc, obj),
  38959. s7_make_symbol(sc, "open"), s7_make_boolean(sc, has_methods(obj)),
  38960. sc->outlet_symbol, (obj == sc->rootlet) ? sc->nil : outlet(obj)));
  38961. if (obj == sc->rootlet)
  38962. s7_varlet(sc, let, s7_make_symbol(sc, "alias"), sc->rootlet_symbol);
  38963. else
  38964. {
  38965. if (obj == sc->owlet)
  38966. s7_varlet(sc, let, s7_make_symbol(sc, "alias"), sc->owlet_symbol);
  38967. else
  38968. {
  38969. if (is_function_env(obj))
  38970. {
  38971. s7_varlet(sc, let, s7_make_symbol(sc, "function"), funclet_function(obj));
  38972. if ((let_file(obj) > 0) &&
  38973. (let_file(obj) < (s7_int)sc->file_names_top) &&
  38974. (let_line(obj) > 0))
  38975. {
  38976. s7_varlet(sc, let, s7_make_symbol(sc, "file"), sc->file_names[let_file(obj)]);
  38977. s7_varlet(sc, let, s7_make_symbol(sc, "line"), make_integer(sc, let_line(obj)));
  38978. }
  38979. }
  38980. }
  38981. }
  38982. if (has_methods(obj))
  38983. {
  38984. s7_pointer func;
  38985. func = find_method(sc, obj, sc->object_to_let_symbol);
  38986. if (func != sc->undefined)
  38987. {
  38988. int gc_loc;
  38989. gc_loc = s7_gc_protect(sc, let);
  38990. s7_apply_function(sc, func, list_2(sc, obj, let));
  38991. s7_gc_unprotect_at(sc, gc_loc);
  38992. }
  38993. }
  38994. return(let);
  38995. }
  38996. case T_C_OBJECT:
  38997. {
  38998. s7_pointer let, clet;
  38999. clet = c_object_let(obj);
  39000. let = s7_inlet(sc, s7_list(sc, 12, sc->value_symbol, obj,
  39001. sc->type_symbol, sc->is_c_object_symbol,
  39002. sc->length_symbol, s7_length(sc, obj),
  39003. s7_make_symbol(sc, "c-type"), s7_make_integer(sc, c_object_type(obj)),
  39004. sc->let_symbol, clet,
  39005. s7_make_symbol(sc, "class"), c_object_scheme_name(obj)));
  39006. if ((is_let(clet)) &&
  39007. ((has_methods(clet)) || (has_methods(obj))))
  39008. {
  39009. s7_pointer func;
  39010. func = find_method(sc, clet, sc->object_to_let_symbol);
  39011. if (func != sc->undefined)
  39012. {
  39013. int gc_loc;
  39014. gc_loc = s7_gc_protect(sc, let);
  39015. s7_apply_function(sc, func, list_2(sc, obj, let));
  39016. s7_gc_unprotect_at(sc, gc_loc);
  39017. }
  39018. }
  39019. return(let);
  39020. }
  39021. case T_INPUT_PORT:
  39022. case T_OUTPUT_PORT:
  39023. {
  39024. s7_pointer let;
  39025. int gc_loc;
  39026. let = s7_inlet(sc, s7_list(sc, 8, sc->value_symbol, obj,
  39027. sc->type_symbol, (is_input_port(obj)) ? sc->is_input_port_symbol : sc->is_output_port_symbol,
  39028. s7_make_symbol(sc, "port-type"),
  39029. (is_string_port(obj)) ? sc->string_symbol :
  39030. ((is_file_port(obj)) ? s7_make_symbol(sc, "file") : s7_make_symbol(sc, "function")),
  39031. s7_make_symbol(sc, "closed"), s7_make_boolean(sc, port_is_closed(obj))));
  39032. gc_loc = s7_gc_protect(sc, let);
  39033. if (is_file_port(obj))
  39034. {
  39035. s7_varlet(sc, let, s7_make_symbol(sc, "file"), g_port_filename(sc, list_1(sc, obj)));
  39036. if (is_input_port(obj))
  39037. s7_varlet(sc, let, s7_make_symbol(sc, "line"), g_port_line_number(sc, list_1(sc, obj)));
  39038. }
  39039. if (port_data_size(obj) > 0)
  39040. {
  39041. s7_varlet(sc, let, sc->length_symbol, s7_make_integer(sc, port_data_size(obj)));
  39042. s7_varlet(sc, let, s7_make_symbol(sc, "position"), s7_make_integer(sc, port_position(obj)));
  39043. /* I think port_data need not be null-terminated, but s7_make_string assumes it is:
  39044. * both valgrind and lib*san complain about the uninitialized data during strlen.
  39045. */
  39046. s7_varlet(sc, let, s7_make_symbol(sc, "data"), s7_make_string_with_length(sc, (const char *)port_data(obj), port_data_size(obj)));
  39047. }
  39048. s7_gc_unprotect_at(sc, gc_loc);
  39049. return(let);
  39050. }
  39051. case T_CLOSURE:
  39052. case T_CLOSURE_STAR:
  39053. case T_MACRO:
  39054. case T_MACRO_STAR:
  39055. case T_BACRO:
  39056. case T_BACRO_STAR:
  39057. {
  39058. s7_pointer let, sig;
  39059. const char* doc;
  39060. int gc_loc;
  39061. let = s7_inlet(sc, s7_list(sc, 6, sc->value_symbol, obj,
  39062. sc->type_symbol, (is_procedure(obj)) ? sc->is_procedure_symbol : sc->is_macro_symbol,
  39063. s7_make_symbol(sc, "arity"), s7_arity(sc, obj)));
  39064. gc_loc = s7_gc_protect(sc, let);
  39065. sig = s7_procedure_signature(sc, obj);
  39066. if (is_pair(sig))
  39067. s7_varlet(sc, let, sc->signature_symbol, sig);
  39068. doc = s7_procedure_documentation(sc, obj);
  39069. if (doc)
  39070. s7_varlet(sc, let, sc->documentation_symbol, s7_make_string(sc, doc));
  39071. if (is_let(closure_let(obj)))
  39072. {
  39073. s7_pointer flet;
  39074. flet = closure_let(obj);
  39075. if ((let_file(flet) > 0) &&
  39076. (let_file(flet) < (s7_int)sc->file_names_top) &&
  39077. (let_line(flet) > 0))
  39078. {
  39079. s7_varlet(sc, let, s7_make_symbol(sc, "file"), sc->file_names[let_file(flet)]);
  39080. s7_varlet(sc, let, s7_make_symbol(sc, "line"), make_integer(sc, let_line(flet)));
  39081. }
  39082. }
  39083. if (closure_setter(obj) != sc->F)
  39084. s7_varlet(sc, let, s7_make_symbol(sc, "setter"), closure_setter(obj));
  39085. s7_varlet(sc, let, s7_make_symbol(sc, "source"),
  39086. append_in_place(sc, list_2(sc, (is_closure_star(obj)) ? sc->lambda_star_symbol : sc->lambda_symbol,
  39087. closure_args(obj)),
  39088. closure_body(obj)));
  39089. s7_gc_unprotect_at(sc, gc_loc);
  39090. return(let);
  39091. }
  39092. case T_C_MACRO:
  39093. case T_C_FUNCTION_STAR:
  39094. case T_C_FUNCTION:
  39095. case T_C_ANY_ARGS_FUNCTION:
  39096. case T_C_OPT_ARGS_FUNCTION:
  39097. case T_C_RST_ARGS_FUNCTION:
  39098. {
  39099. s7_pointer let, sig;
  39100. const char* doc;
  39101. let = s7_inlet(sc, s7_list(sc, 6, sc->value_symbol, obj,
  39102. sc->type_symbol, (is_procedure(obj)) ? sc->is_procedure_symbol : sc->is_macro_symbol,
  39103. s7_make_symbol(sc, "arity"), s7_arity(sc, obj)));
  39104. sig = s7_procedure_signature(sc, obj);
  39105. if (is_pair(sig))
  39106. s7_varlet(sc, let, sc->signature_symbol, sig);
  39107. doc = s7_procedure_documentation(sc, obj);
  39108. if (doc)
  39109. s7_varlet(sc, let, sc->documentation_symbol, s7_make_string(sc, doc));
  39110. if (c_function_setter(obj) != sc->F)
  39111. s7_varlet(sc, let, s7_make_symbol(sc, "setter"), c_function_setter(obj));
  39112. return(let);
  39113. }
  39114. default:
  39115. #if DEBUGGING
  39116. fprintf(stderr, "object->let: %s, type: %d\n", DISPLAY(obj), type(obj));
  39117. #endif
  39118. return(sc->F);
  39119. }
  39120. return(sc->F);
  39121. }
  39122. /* ---------------- stacktrace ---------------- */
  39123. static s7_pointer stacktrace_find_caller(s7_scheme *sc, s7_pointer e)
  39124. {
  39125. if ((is_let(e)) && (e != sc->rootlet))
  39126. {
  39127. if (is_function_env(e))
  39128. return(funclet_function(e));
  39129. return(stacktrace_find_caller(sc, outlet(e)));
  39130. }
  39131. return(sc->F);
  39132. }
  39133. static bool stacktrace_find_let(s7_scheme *sc, int loc, s7_pointer e)
  39134. {
  39135. return((loc > 0) &&
  39136. ((stack_let(sc->stack, loc) == e) ||
  39137. (stacktrace_find_let(sc, loc - 4, e))));
  39138. }
  39139. static int stacktrace_find_error_hook_quit(s7_scheme *sc)
  39140. {
  39141. int i;
  39142. for (i = s7_stack_top(sc) - 1; i >= 3; i -= 4)
  39143. if (stack_op(sc->stack, i) == OP_ERROR_HOOK_QUIT)
  39144. return(i);
  39145. return(-1);
  39146. }
  39147. static bool stacktrace_in_error_handler(s7_scheme *sc, int loc)
  39148. {
  39149. return((outlet(sc->owlet) == sc->envir) ||
  39150. (stacktrace_find_let(sc, loc * 4, outlet(sc->owlet))) ||
  39151. (stacktrace_find_error_hook_quit(sc) > 0));
  39152. }
  39153. static bool stacktrace_error_hook_function(s7_scheme *sc, s7_pointer sym)
  39154. {
  39155. if (is_symbol(sym))
  39156. {
  39157. s7_pointer f;
  39158. f = s7_symbol_value(sc, sym);
  39159. return((is_procedure(f)) &&
  39160. (is_procedure(sc->error_hook)) &&
  39161. (hook_has_functions(sc->error_hook)) &&
  39162. (direct_memq(f, s7_hook_functions(sc, sc->error_hook))));
  39163. }
  39164. return(false);
  39165. }
  39166. static char *stacktrace_walker(s7_scheme *sc, s7_pointer code, s7_pointer e,
  39167. char *notes, int gc_syms,
  39168. int code_cols, int total_cols, int notes_start_col,
  39169. bool as_comment)
  39170. {
  39171. s7_pointer syms;
  39172. syms = gc_protected_at(sc, gc_syms);
  39173. if (is_symbol(code))
  39174. {
  39175. if ((!direct_memq(code, syms)) &&
  39176. (!is_slot(global_slot(code))))
  39177. {
  39178. s7_pointer val;
  39179. syms = cons(sc, code, syms);
  39180. gc_protected_at(sc, gc_syms) = syms;
  39181. val = s7_symbol_local_value(sc, code, e);
  39182. if ((val) && (val != sc->undefined) &&
  39183. (!is_any_macro(val)))
  39184. {
  39185. int typ;
  39186. typ = type(val);
  39187. if (typ < T_GOTO)
  39188. {
  39189. char *objstr, *str;
  39190. const char *spaces;
  39191. int objlen, new_note_len, notes_max, cur_line_len = 0, spaces_len;
  39192. bool new_notes_line = false, old_short_print;
  39193. s7_int old_len;
  39194. spaces = " ";
  39195. spaces_len = strlen(spaces);
  39196. if (notes_start_col < 0) notes_start_col = 50;
  39197. notes_max = total_cols - notes_start_col;
  39198. old_short_print = sc->short_print;
  39199. sc->short_print = true;
  39200. old_len = sc->print_length;
  39201. if (sc->print_length > 4) sc->print_length = 4;
  39202. objstr = s7_object_to_c_string(sc, val);
  39203. objlen = safe_strlen(objstr);
  39204. if (objlen > notes_max)
  39205. {
  39206. objstr[notes_max - 4] = '.';
  39207. objstr[notes_max - 3] = '.';
  39208. objstr[notes_max - 2] = '.';
  39209. objstr[notes_max - 1] = '\0';
  39210. objlen = notes_max;
  39211. }
  39212. sc->short_print = old_short_print;
  39213. sc->print_length = old_len;
  39214. new_note_len = symbol_name_length(code) + 3 + objlen;
  39215. /* we want to append this much info to the notes, but does it need a new line?
  39216. */
  39217. if (notes_start_col < code_cols)
  39218. new_notes_line = true;
  39219. else
  39220. {
  39221. if (notes)
  39222. {
  39223. char *last_newline;
  39224. last_newline = strrchr(notes, (int)'\n'); /* returns ptr to end if none = nil if not found? */
  39225. if (last_newline)
  39226. cur_line_len = strlen(notes) - strlen(last_newline);
  39227. else cur_line_len = strlen(notes);
  39228. new_notes_line = ((cur_line_len + new_note_len) > notes_max);
  39229. }
  39230. }
  39231. if (new_notes_line)
  39232. {
  39233. new_note_len += (4 + notes_start_col + ((notes) ? strlen(notes) : 0));
  39234. str = (char *)malloc(new_note_len * sizeof(char));
  39235. snprintf(str, new_note_len, "%s\n%s%s%s%s: %s",
  39236. (notes) ? notes : "",
  39237. (as_comment) ? "; " : "",
  39238. (spaces_len >= notes_start_col) ? (char *)(spaces + spaces_len - notes_start_col) : "",
  39239. (as_comment) ? "" : " ; ",
  39240. symbol_name(code),
  39241. objstr);
  39242. }
  39243. else
  39244. {
  39245. new_note_len += ((notes) ? strlen(notes) : 0) + 4;
  39246. str = (char *)malloc(new_note_len * sizeof(char));
  39247. snprintf(str, new_note_len, "%s%s%s: %s",
  39248. (notes) ? notes : "",
  39249. (notes) ? ", " : " ; ",
  39250. symbol_name(code),
  39251. objstr);
  39252. }
  39253. free(objstr);
  39254. if (notes) free(notes);
  39255. return(str);
  39256. }
  39257. }
  39258. }
  39259. return(notes);
  39260. }
  39261. if (is_pair(code))
  39262. {
  39263. notes = stacktrace_walker(sc, car(code), e, notes, gc_syms, code_cols, total_cols, notes_start_col, as_comment);
  39264. return(stacktrace_walker(sc, cdr(code), e, notes, gc_syms, code_cols, total_cols, notes_start_col, as_comment));
  39265. }
  39266. return(notes);
  39267. }
  39268. static char *stacktrace_add_func(s7_scheme *sc, s7_pointer f, s7_pointer code, char *errstr, char *notes, int code_max, bool as_comment)
  39269. {
  39270. int newlen, errlen;
  39271. char *newstr, *str;
  39272. errlen = strlen(errstr);
  39273. if ((is_symbol(f)) &&
  39274. (f != car(code)))
  39275. {
  39276. newlen = symbol_name_length(f) + errlen + 10;
  39277. newstr = (char *)malloc(newlen * sizeof(char));
  39278. errlen = snprintf(newstr, newlen, "%s: %s", symbol_name(f), errstr);
  39279. }
  39280. else
  39281. {
  39282. newlen = errlen + 8;
  39283. newstr = (char *)malloc(newlen * sizeof(char));
  39284. if ((errlen > 2) && (errstr[2] == '('))
  39285. errlen = snprintf(newstr, newlen, " %s", errstr);
  39286. else errlen = snprintf(newstr, newlen, "%s", errstr);
  39287. }
  39288. newlen = code_max + 8 + ((notes) ? strlen(notes) : 0);
  39289. str = (char *)malloc(newlen * sizeof(char));
  39290. if (errlen >= code_max)
  39291. {
  39292. newstr[code_max - 4] = '.';
  39293. newstr[code_max - 3] = '.';
  39294. newstr[code_max - 2] = '.';
  39295. newstr[code_max - 1] = '\0';
  39296. snprintf(str, newlen, "%s%s%s\n", (as_comment) ? "; " : "", newstr, (notes) ? notes : "");
  39297. }
  39298. else
  39299. {
  39300. /* send out newstr, pad with spaces to code_max, then notes */
  39301. int len;
  39302. len = snprintf(str, newlen, "%s%s", (as_comment) ? "; " : "", newstr);
  39303. if (notes)
  39304. {
  39305. int i;
  39306. for (i = len; i < code_max - 1; i++)
  39307. str[i] = ' ';
  39308. str[i] = '\0';
  39309. #ifdef __OpenBSD__
  39310. strlcat(str, notes, newlen);
  39311. strlcat(str, "\n", newlen);
  39312. #else
  39313. strcat(str, notes);
  39314. strcat(str, "\n");
  39315. #endif
  39316. }
  39317. }
  39318. free(newstr);
  39319. return(str);
  39320. }
  39321. static char *stacktrace_1(s7_scheme *sc, int frames_max, int code_cols, int total_cols, int notes_start_col, bool as_comment)
  39322. {
  39323. char *str;
  39324. int loc, top, frames = 0, gc_syms;
  39325. gc_syms = s7_gc_protect(sc, sc->nil);
  39326. str = NULL;
  39327. top = (sc->stack_end - sc->stack_start) / 4; /* (*s7* 'stack_top), not s7_stack_top! */
  39328. if (stacktrace_in_error_handler(sc, top))
  39329. {
  39330. s7_pointer err_code;
  39331. err_code = slot_value(sc->error_code);
  39332. if (is_pair(err_code))
  39333. {
  39334. char *errstr, *notes = NULL;
  39335. s7_pointer cur_env, f;
  39336. errstr = s7_object_to_c_string(sc, err_code);
  39337. cur_env = outlet(sc->owlet);
  39338. f = stacktrace_find_caller(sc, cur_env); /* this is a symbol */
  39339. if ((is_let(cur_env)) &&
  39340. (cur_env != sc->rootlet))
  39341. notes = stacktrace_walker(sc, err_code, cur_env, NULL, gc_syms, code_cols, total_cols, notes_start_col, as_comment);
  39342. str = stacktrace_add_func(sc, f, err_code, errstr, notes, code_cols, as_comment);
  39343. free(errstr);
  39344. }
  39345. /* now if OP_ERROR_HOOK_QUIT is in the stack, jump past it!
  39346. */
  39347. loc = stacktrace_find_error_hook_quit(sc);
  39348. if (loc > 0) top = (loc + 1) / 4;
  39349. }
  39350. for (loc = top - 1; loc > 0; loc--)
  39351. {
  39352. s7_pointer code;
  39353. int true_loc;
  39354. true_loc = (int)(loc + 1) * 4 - 1;
  39355. code = stack_code(sc->stack, true_loc); /* can code be free here? [hit this once, could not repeat it] */
  39356. if (is_pair(code))
  39357. {
  39358. char *codestr;
  39359. codestr = s7_object_to_c_string(sc, code);
  39360. if (codestr)
  39361. {
  39362. if ((!local_strcmp(codestr, "(result)")) &&
  39363. (!local_strcmp(codestr, "(#f)")) &&
  39364. (strstr(codestr, "(stacktrace)") == NULL) &&
  39365. (strstr(codestr, "(stacktrace ") == NULL))
  39366. {
  39367. s7_pointer e, f;
  39368. e = stack_let(sc->stack, true_loc);
  39369. f = stacktrace_find_caller(sc, e);
  39370. if (!stacktrace_error_hook_function(sc, f))
  39371. {
  39372. char *notes = NULL, *newstr;
  39373. int newlen;
  39374. frames++;
  39375. if (frames > frames_max)
  39376. {
  39377. free(codestr);
  39378. s7_gc_unprotect_at(sc, gc_syms);
  39379. return(str);
  39380. }
  39381. if ((is_let(e)) && (e != sc->rootlet))
  39382. notes = stacktrace_walker(sc, code, e, NULL, gc_syms, code_cols, total_cols, notes_start_col, as_comment);
  39383. newstr = stacktrace_add_func(sc, f, code, codestr, notes, code_cols, as_comment);
  39384. free(codestr);
  39385. if (notes) free(notes);
  39386. newlen = strlen(newstr) + 1 + ((str) ? strlen(str) : 0);
  39387. codestr = (char *)malloc(newlen * sizeof(char));
  39388. snprintf(codestr, newlen, "%s%s", (str) ? str : "", newstr);
  39389. if (str) free(str);
  39390. free(newstr);
  39391. str = codestr;
  39392. codestr = NULL;
  39393. }
  39394. else free(codestr);
  39395. }
  39396. else free(codestr);
  39397. }
  39398. }
  39399. }
  39400. s7_gc_unprotect_at(sc, gc_syms);
  39401. return(str);
  39402. }
  39403. s7_pointer s7_stacktrace(s7_scheme *sc)
  39404. {
  39405. char *str;
  39406. str = stacktrace_1(sc, 30, 45, 80, 45, false);
  39407. return(make_string_uncopied_with_length(sc, str, safe_strlen(str)));
  39408. }
  39409. static s7_pointer g_stacktrace(s7_scheme *sc, s7_pointer args)
  39410. {
  39411. #define H_stacktrace "(stacktrace (max-frames 30) (code-cols 50) (total-cols 80) (note-col 50) as-comment) returns \
  39412. a stacktrace as a string. Each line has two portions, the code being evaluated and a note giving \
  39413. the value of local variables in that code. The first argument sets how many lines are displayed. \
  39414. The next three arguments set the length and layout of those lines. 'as-comment' if #t causes each \
  39415. line to be preceded by a semicolon."
  39416. #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)
  39417. s7_int max_frames = 30, code_cols = 50, total_cols = 80, notes_start_col = 50;
  39418. bool as_comment = false;
  39419. char *str;
  39420. if (!is_null(args))
  39421. {
  39422. if (s7_is_integer(car(args)))
  39423. {
  39424. max_frames = s7_integer(car(args));
  39425. if ((max_frames <= 0) || (max_frames > s7_int32_max))
  39426. max_frames = 30;
  39427. args = cdr(args);
  39428. if (!is_null(args))
  39429. {
  39430. if (s7_is_integer(car(args)))
  39431. {
  39432. code_cols = s7_integer(car(args));
  39433. if ((code_cols <= 8) || (code_cols > s7_int32_max))
  39434. code_cols = 50;
  39435. args = cdr(args);
  39436. if (!is_null(args))
  39437. {
  39438. if (s7_is_integer(car(args)))
  39439. {
  39440. total_cols = s7_integer(car(args));
  39441. if ((total_cols <= code_cols) || (total_cols > s7_int32_max))
  39442. total_cols = 80;
  39443. args = cdr(args);
  39444. if (!is_null(args))
  39445. {
  39446. if (s7_is_integer(car(args)))
  39447. {
  39448. notes_start_col = s7_integer(car(args));
  39449. if ((notes_start_col <= 0) || (notes_start_col > s7_int32_max))
  39450. notes_start_col = 50;
  39451. args = cdr(args);
  39452. if (!is_null(args))
  39453. {
  39454. if (s7_is_boolean(car(args)))
  39455. as_comment = s7_boolean(sc, car(args));
  39456. else return(wrong_type_argument(sc, sc->stacktrace_symbol, 5, car(args), T_BOOLEAN));
  39457. }
  39458. }
  39459. else return(wrong_type_argument(sc, sc->stacktrace_symbol, 4, car(args), T_INTEGER));
  39460. }
  39461. }
  39462. else return(wrong_type_argument(sc, sc->stacktrace_symbol, 3, car(args), T_INTEGER));
  39463. }
  39464. }
  39465. else return(wrong_type_argument(sc, sc->stacktrace_symbol, 2, car(args), T_INTEGER));
  39466. }
  39467. }
  39468. else method_or_bust(sc, car(args), sc->stacktrace_symbol, args, T_INTEGER, 1);
  39469. }
  39470. str = stacktrace_1(sc, (int)max_frames, (int)code_cols, (int)total_cols, (int)notes_start_col, as_comment);
  39471. return(make_string_uncopied_with_length(sc, str, safe_strlen(str)));
  39472. }
  39473. /* -------- error handlers -------- */
  39474. static const char *make_type_name(s7_scheme *sc, const char *name, int article)
  39475. {
  39476. int i, slen, len;
  39477. slen = safe_strlen(name);
  39478. len = slen + 8;
  39479. if (len > sc->typnam_len)
  39480. {
  39481. if (sc->typnam) free(sc->typnam);
  39482. sc->typnam = (char *)malloc(len * sizeof(char));
  39483. sc->typnam_len = len;
  39484. }
  39485. if (article == INDEFINITE_ARTICLE)
  39486. {
  39487. i = 1;
  39488. sc->typnam[0] = 'a';
  39489. if ((name[0] == 'a') || (name[0] == 'e') || (name[0] == 'i') || (name[0] == 'o') || (name[0] == 'u'))
  39490. sc->typnam[i++] = 'n';
  39491. sc->typnam[i++] = ' ';
  39492. }
  39493. else i = 0;
  39494. memcpy((void *)(sc->typnam + i), (void *)name, slen);
  39495. sc->typnam[i + slen] = '\0';
  39496. return(sc->typnam);
  39497. }
  39498. static const char *type_name_from_type(s7_scheme *sc, int typ, int article)
  39499. {
  39500. static const char *frees[2] = {"free cell", "a free cell"};
  39501. static const char *nils[2] = {"nil", "nil"};
  39502. static const char *uniques[2] = {"untyped", "untyped"};
  39503. static const char *booleans[2] = {"boolean", "boolean"};
  39504. static const char *strings[2] = {"string", "a string"};
  39505. static const char *symbols[2] = {"symbol", "a symbol"};
  39506. static const char *syntaxes[2] = {"syntax", "syntactic"};
  39507. static const char *pairs[2] = {"pair", "a pair"};
  39508. static const char *gotos[2] = {"goto", "a goto (from call-with-exit)"};
  39509. static const char *continuations[2] = {"continuation", "a continuation"};
  39510. static const char *c_functions[2] = {"c-function", "a c-function"};
  39511. static const char *macros[2] = {"macro", "a macro"};
  39512. static const char *c_macros[2] = {"c-macro", "a c-macro"};
  39513. static const char *bacros[2] = {"bacro", "a bacro"};
  39514. static const char *vectors[2] = {"vector", "a vector"};
  39515. static const char *int_vectors[2] = {"int-vector", "an int-vector"};
  39516. static const char *float_vectors[2] = {"float-vector", "a float-vector"};
  39517. static const char *c_pointers[2] = {"C pointer", "a raw C pointer"};
  39518. static const char *counters[2] = {"internal counter", "an internal counter"};
  39519. static const char *baffles[2] = {"baffle", "a baffle"};
  39520. static const char *slots[2] = {"slot", "a slot (variable binding)"};
  39521. static const char *characters[2] = {"character", "a character"};
  39522. static const char *catches[2] = {"catch", "a catch"};
  39523. static const char *dynamic_winds[2] = {"dynamic-wind", "a dynamic-wind"};
  39524. static const char *hash_tables[2] = {"hash-table", "a hash-table"};
  39525. static const char *iterators[2] = {"iterator", "an iterator"};
  39526. static const char *environments[2] = {"environment", "an environment"};
  39527. static const char *integers[2] = {"integer", "an integer"};
  39528. static const char *big_integers[2] = {"big integer", "a big integer"};
  39529. static const char *ratios[2] = {"ratio", "a ratio"};
  39530. static const char *big_ratios[2] = {"big ratio", "a big ratio"};
  39531. static const char *reals[2] = {"real", "a real"};
  39532. static const char *big_reals[2] = {"big real", "a big real"};
  39533. static const char *complexes[2] = {"complex number", "a complex number"};
  39534. static const char *big_complexes[2] = {"big complex number", "a big complex number"};
  39535. static const char *functions[2] = {"function", "a function"};
  39536. static const char *function_stars[2] = {"function*", "a function*"};
  39537. static const char *rngs[2] = {"random-state", "a random-state"};
  39538. switch (typ)
  39539. {
  39540. case T_FREE: return(frees[article]);
  39541. case T_NIL: return(nils[article]);
  39542. case T_UNIQUE: return(uniques[article]);
  39543. case T_UNSPECIFIED: return(uniques[article]);
  39544. case T_BOOLEAN: return(booleans[article]);
  39545. case T_STRING: return(strings[article]);
  39546. case T_SYMBOL: return(symbols[article]);
  39547. case T_SYNTAX: return(syntaxes[article]);
  39548. case T_PAIR: return(pairs[article]);
  39549. case T_GOTO: return(gotos[article]);
  39550. case T_CONTINUATION: return(continuations[article]);
  39551. case T_C_OPT_ARGS_FUNCTION:
  39552. case T_C_RST_ARGS_FUNCTION:
  39553. case T_C_ANY_ARGS_FUNCTION:
  39554. case T_C_FUNCTION_STAR:
  39555. case T_C_FUNCTION: return(c_functions[article]);
  39556. case T_CLOSURE: return(functions[article]);
  39557. case T_CLOSURE_STAR: return(function_stars[article]);
  39558. case T_C_MACRO: return(c_macros[article]);
  39559. case T_C_POINTER: return(c_pointers[article]);
  39560. case T_CHARACTER: return(characters[article]);
  39561. case T_VECTOR: return(vectors[article]);
  39562. case T_INT_VECTOR: return(int_vectors[article]);
  39563. case T_FLOAT_VECTOR: return(float_vectors[article]);
  39564. case T_MACRO_STAR:
  39565. case T_MACRO: return(macros[article]);
  39566. case T_BACRO_STAR:
  39567. case T_BACRO: return(bacros[article]);
  39568. case T_CATCH: return(catches[article]); /* are these 2 possible? */
  39569. case T_DYNAMIC_WIND: return(dynamic_winds[article]);
  39570. case T_HASH_TABLE: return(hash_tables[article]);
  39571. case T_ITERATOR: return(iterators[article]);
  39572. case T_LET: return(environments[article]);
  39573. case T_COUNTER: return(counters[article]);
  39574. case T_BAFFLE: return(baffles[article]);
  39575. case T_RANDOM_STATE: return(rngs[article]);
  39576. case T_SLOT: return(slots[article]);
  39577. case T_INTEGER: return(integers[article]);
  39578. case T_RATIO: return(ratios[article]);
  39579. case T_REAL: return(reals[article]);
  39580. case T_COMPLEX: return(complexes[article]);
  39581. case T_BIG_INTEGER: return(big_integers[article]);
  39582. case T_BIG_RATIO: return(big_ratios[article]);
  39583. case T_BIG_REAL: return(big_reals[article]);
  39584. case T_BIG_COMPLEX: return(big_complexes[article]);
  39585. }
  39586. return(NULL);
  39587. }
  39588. static const char *type_name(s7_scheme *sc, s7_pointer arg, int article)
  39589. {
  39590. switch (unchecked_type(arg))
  39591. {
  39592. case T_C_OBJECT:
  39593. return(make_type_name(sc, object_types[c_object_type(arg)]->name, article));
  39594. case T_INPUT_PORT:
  39595. return(make_type_name(sc, (is_file_port(arg)) ? "input file port" : ((is_string_port(arg)) ? "input string port" : "input port"), article));
  39596. case T_OUTPUT_PORT:
  39597. return(make_type_name(sc, (is_file_port(arg)) ? "output file port" : ((is_string_port(arg)) ? "output string port" : "output port"), article));
  39598. case T_LET:
  39599. if (has_methods(arg))
  39600. {
  39601. s7_pointer class_name;
  39602. class_name = find_method(sc, arg, sc->class_name_symbol);
  39603. if (is_symbol(class_name))
  39604. return(make_type_name(sc, symbol_name(class_name), article));
  39605. }
  39606. default:
  39607. {
  39608. const char *str;
  39609. str = type_name_from_type(sc, unchecked_type(arg), article);
  39610. if (str) return(str);
  39611. }
  39612. }
  39613. return("messed up object");
  39614. }
  39615. static s7_pointer prepackaged_type_name(s7_scheme *sc, s7_pointer x)
  39616. {
  39617. s7_pointer p;
  39618. if (has_methods(x))
  39619. {
  39620. p = find_method(sc, find_let(sc, x), sc->class_name_symbol);
  39621. if (is_symbol(p))
  39622. return(symbol_name_cell(p));
  39623. }
  39624. p = prepackaged_type_names[type(x)];
  39625. if (is_string(p)) return(p);
  39626. switch (type(x))
  39627. {
  39628. case T_C_OBJECT: return(c_object_scheme_name(x));
  39629. 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));
  39630. 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));
  39631. }
  39632. return(make_string_wrapper(sc, "unknown type!"));
  39633. }
  39634. static s7_pointer type_name_string(s7_scheme *sc, s7_pointer arg)
  39635. {
  39636. if (type(arg) < NUM_TYPES)
  39637. {
  39638. s7_pointer p;
  39639. p = prepackaged_type_names[type(arg)]; /* these use INDEFINITE_ARTICLE */
  39640. if (is_string(p)) return(p);
  39641. }
  39642. return(make_string_wrapper(sc, type_name(sc, arg, INDEFINITE_ARTICLE)));
  39643. }
  39644. 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)
  39645. {
  39646. s7_pointer p;
  39647. p = cdr(sc->wrong_type_arg_info); /* info list is '(format_string caller arg_n arg type_name descr) */
  39648. set_car(p, caller); p = cdr(p);
  39649. set_car(p, arg_n); p = cdr(p);
  39650. set_car(p, arg); p = cdr(p);
  39651. set_car(p, (typnam == sc->gc_nil) ? prepackaged_type_name(sc, arg) : typnam);
  39652. p = cdr(p);
  39653. set_car(p, descr);
  39654. return(s7_error(sc, sc->wrong_type_arg_symbol, sc->wrong_type_arg_info));
  39655. }
  39656. static s7_pointer simple_wrong_type_arg_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg, s7_pointer typnam, s7_pointer descr)
  39657. {
  39658. set_wlist_4(sc, cdr(sc->simple_wrong_type_arg_info), caller, arg, (typnam == sc->gc_nil) ? prepackaged_type_name(sc, arg) : typnam, descr);
  39659. return(s7_error(sc, sc->wrong_type_arg_symbol, sc->simple_wrong_type_arg_info));
  39660. }
  39661. s7_pointer s7_wrong_type_arg_error(s7_scheme *sc, const char *caller, int arg_n, s7_pointer arg, const char *descr)
  39662. {
  39663. /* info list is '(format_string caller arg_n arg type_name descr) */
  39664. if (arg_n < 0) arg_n = 0;
  39665. if (arg_n > 0)
  39666. return(wrong_type_arg_error_prepackaged(sc, make_string_wrapper(sc, caller),
  39667. make_integer(sc, arg_n), arg, type_name_string(sc, arg),
  39668. make_string_wrapper(sc, descr)));
  39669. return(simple_wrong_type_arg_error_prepackaged(sc, make_string_wrapper(sc, caller),
  39670. arg, type_name_string(sc, arg),
  39671. make_string_wrapper(sc, descr)));
  39672. }
  39673. static s7_pointer out_of_range_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg_n, s7_pointer arg, s7_pointer descr)
  39674. {
  39675. /* info list is '(format_string caller arg_n arg descr) */
  39676. set_wlist_4(sc, cdr(sc->out_of_range_info), caller, arg_n, arg, descr);
  39677. return(s7_error(sc, sc->out_of_range_symbol, sc->out_of_range_info));
  39678. }
  39679. static s7_pointer simple_out_of_range_error_prepackaged(s7_scheme *sc, s7_pointer caller, s7_pointer arg, s7_pointer descr)
  39680. {
  39681. set_wlist_3(sc, cdr(sc->simple_out_of_range_info), caller, arg, descr);
  39682. return(s7_error(sc, sc->out_of_range_symbol, sc->simple_out_of_range_info));
  39683. }
  39684. s7_pointer s7_out_of_range_error(s7_scheme *sc, const char *caller, int arg_n, s7_pointer arg, const char *descr)
  39685. {
  39686. /* info list is '(format_string caller arg_n arg descr) */
  39687. if (arg_n < 0) arg_n = 0;
  39688. if (arg_n > 0)
  39689. return(out_of_range_error_prepackaged(sc, make_string_wrapper(sc, caller), make_integer(sc, arg_n), arg, make_string_wrapper(sc, descr)));
  39690. return(simple_out_of_range_error_prepackaged(sc, make_string_wrapper(sc, caller), arg, make_string_wrapper(sc, descr)));
  39691. }
  39692. s7_pointer s7_wrong_number_of_args_error(s7_scheme *sc, const char *caller, s7_pointer args)
  39693. {
  39694. return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_2(sc, make_string_wrapper(sc, caller), args))); /* "caller" includes the format directives */
  39695. }
  39696. static s7_pointer division_by_zero_error(s7_scheme *sc, s7_pointer caller, s7_pointer arg)
  39697. {
  39698. return(s7_error(sc, sc->division_by_zero_symbol, set_elist_3(sc, sc->division_by_zero_error_string, caller, arg)));
  39699. }
  39700. static s7_pointer file_error(s7_scheme *sc, const char *caller, const char *descr, const char *name)
  39701. {
  39702. return(s7_error(sc, sc->io_error_symbol,
  39703. set_elist_4(sc, make_string_wrapper(sc, "~A: ~A ~S"),
  39704. make_string_wrapper(sc, caller),
  39705. make_string_wrapper(sc, descr),
  39706. make_string_wrapper(sc, name))));
  39707. }
  39708. static s7_pointer closure_or_f(s7_scheme *sc, s7_pointer p)
  39709. {
  39710. s7_pointer body;
  39711. if (!is_closure(p)) return(p);
  39712. body = closure_body(p);
  39713. if (is_pair(cdr(body))) return(p);
  39714. if (!is_pair(car(body))) return(sc->F);
  39715. if (caar(body) == sc->quote_symbol) return(sc->F);
  39716. return(p);
  39717. }
  39718. static s7_pointer g_dynamic_wind(s7_scheme *sc, s7_pointer args)
  39719. {
  39720. #define H_dynamic_wind "(dynamic-wind init body finish) calls init, then body, then finish, \
  39721. each a function of no arguments, guaranteeing that finish is called even if body is exited"
  39722. #define Q_dynamic_wind s7_make_circular_signature(sc, 1, 2, sc->values_symbol, sc->is_procedure_symbol)
  39723. s7_pointer p;
  39724. if (!is_thunk(sc, car(args)))
  39725. method_or_bust_with_type(sc, car(args), sc->dynamic_wind_symbol, args, a_thunk_string, 1);
  39726. if (!is_thunk(sc, cadr(args)))
  39727. method_or_bust_with_type(sc, cadr(args), sc->dynamic_wind_symbol, args, a_thunk_string, 2);
  39728. if (!is_thunk(sc, caddr(args)))
  39729. method_or_bust_with_type(sc, caddr(args), sc->dynamic_wind_symbol, args, a_thunk_string, 3);
  39730. /* this won't work:
  39731. (let ((final (lambda (a b c) (list a b c))))
  39732. (dynamic-wind
  39733. (lambda () #f)
  39734. (lambda () (set! final (lambda () (display "in final"))))
  39735. final))
  39736. * but why not? 'final' is a thunk by the time it is evaluated.
  39737. * catch (the error handler) is similar.
  39738. *
  39739. * It can't work here because we set up the dynamic_wind_out slot below and
  39740. * even if the thunk check was removed, we'd still be trying to apply the original function.
  39741. */
  39742. new_cell(sc, p, T_DYNAMIC_WIND); /* don't mark car/cdr, don't copy */
  39743. dynamic_wind_in(p) = closure_or_f(sc, car(args));
  39744. dynamic_wind_body(p) = cadr(args);
  39745. dynamic_wind_out(p) = closure_or_f(sc, caddr(args));
  39746. /* since we don't care about the in and out results, and they are thunks, if the body is not a pair,
  39747. * or is a quoted thing, we just ignore that function.
  39748. */
  39749. push_stack(sc, OP_DYNAMIC_WIND, sc->nil, p); /* args will be the saved result, code = s7_dynwind_t obj */
  39750. if (dynamic_wind_in(p) != sc->F)
  39751. {
  39752. dynamic_wind_state(p) = DWIND_INIT;
  39753. push_stack(sc, OP_APPLY, sc->nil, dynamic_wind_in(p));
  39754. }
  39755. else
  39756. {
  39757. dynamic_wind_state(p) = DWIND_BODY;
  39758. push_stack(sc, OP_APPLY, sc->nil, dynamic_wind_body(p));
  39759. }
  39760. return(sc->F);
  39761. }
  39762. s7_pointer s7_dynamic_wind(s7_scheme *sc, s7_pointer init, s7_pointer body, s7_pointer finish)
  39763. {
  39764. /* this is essentially s7_call with a dynamic-wind wrapper around "body" */
  39765. s7_pointer p;
  39766. declare_jump_info();
  39767. sc->temp1 = ((init == sc->F) ? finish : init);
  39768. sc->temp2 = body;
  39769. store_jump_info(sc);
  39770. set_jump_info(sc, DYNAMIC_WIND_SET_JUMP);
  39771. if (jump_loc != NO_JUMP)
  39772. {
  39773. if (jump_loc != ERROR_JUMP)
  39774. eval(sc, sc->op);
  39775. }
  39776. else
  39777. {
  39778. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  39779. sc->args = sc->nil;
  39780. new_cell(sc, p, T_DYNAMIC_WIND);
  39781. dynamic_wind_in(p) = _NFre(init);
  39782. dynamic_wind_body(p) = _NFre(body);
  39783. dynamic_wind_out(p) = _NFre(finish);
  39784. push_stack(sc, OP_DYNAMIC_WIND, sc->nil, p);
  39785. if (init != sc->F)
  39786. {
  39787. dynamic_wind_state(p) = DWIND_INIT;
  39788. sc->code = init;
  39789. }
  39790. else
  39791. {
  39792. dynamic_wind_state(p) = DWIND_BODY;
  39793. sc->code = body;
  39794. }
  39795. eval(sc, OP_APPLY);
  39796. }
  39797. restore_jump_info(sc);
  39798. if (is_multiple_value(sc->value))
  39799. sc->value = splice_in_values(sc, multiple_value(sc->value));
  39800. return(sc->value);
  39801. }
  39802. static s7_pointer g_catch(s7_scheme *sc, s7_pointer args)
  39803. {
  39804. #define H_catch "(catch tag thunk handler) evaluates thunk; if an error occurs that matches the tag (#t matches all), the handler is called"
  39805. #define Q_catch s7_make_circular_signature(sc, 2, 3, sc->values_symbol, sc->T, sc->is_procedure_symbol)
  39806. s7_pointer p, proc, err;
  39807. /* Guile sets up the catch before looking for arg errors:
  39808. * (catch #t log (lambda args "hiho")) -> "hiho"
  39809. * which is consistent in that (catch #t (lambda () (log))...) should probably be the same as (catch #t log ...)
  39810. */
  39811. proc = cadr(args);
  39812. err = caddr(args);
  39813. /* if (is_let(err)) check_method(sc, err, sc->catch_symbol, args); */ /* causes exit from s7! */
  39814. new_cell(sc, p, T_CATCH);
  39815. catch_tag(p) = car(args);
  39816. catch_goto_loc(p) = s7_stack_top(sc);
  39817. catch_op_loc(p) = (int)(sc->op_stack_now - sc->op_stack);
  39818. catch_handler(p) = err;
  39819. if (is_any_macro(err))
  39820. push_stack(sc, OP_CATCH_2, args, p);
  39821. else push_stack(sc, OP_CATCH, args, p); /* args ignored but maybe safer for GC? */
  39822. /* not sure about these error checks -- they can be omitted */
  39823. if (!is_thunk(sc, proc))
  39824. return(wrong_type_argument_with_type(sc, sc->catch_symbol, 2, proc, a_thunk_string));
  39825. if (!is_applicable(err))
  39826. return(wrong_type_argument_with_type(sc, sc->catch_symbol, 3, err, something_applicable_string));
  39827. /* should we check here for (aritable? err 2)? -- right now:
  39828. * (catch #t (lambda () 1) "hiho") -> 1
  39829. * currently this is checked only if the error handler is called
  39830. */
  39831. if (is_closure(proc)) /* not also lambda* here because we need to handle the arg defaults */
  39832. {
  39833. sc->code = closure_body(proc);
  39834. new_frame(sc, closure_let(proc), sc->envir);
  39835. push_stack(sc, OP_BEGIN_UNCHECKED, sc->args, sc->code);
  39836. }
  39837. else push_stack(sc, OP_APPLY, sc->nil, proc);
  39838. return(sc->F);
  39839. }
  39840. /* s7_catch(sc, tag, body, error): return(g_catch(sc, list(sc, 3, tag, body, error))) */
  39841. /* error reporting info -- save filename and line number */
  39842. #define remember_location(Line, File) (((File) << 20) | (Line))
  39843. #define remembered_line_number(Line) ((Line) & 0xfffff)
  39844. #define remembered_file_name(Line) ((((Line) >> 20) <= sc->file_names_top) ? sc->file_names[Line >> 20] : sc->F)
  39845. /* this gives room for 4000 files each of 1000000 lines */
  39846. static int remember_file_name(s7_scheme *sc, const char *file)
  39847. {
  39848. int i;
  39849. for (i = 0; i <= sc->file_names_top; i++)
  39850. if (safe_strcmp(file, string_value(sc->file_names[i])))
  39851. return(i);
  39852. sc->file_names_top++;
  39853. if (sc->file_names_top >= sc->file_names_size)
  39854. {
  39855. int old_size = 0;
  39856. if (sc->file_names_size == 0)
  39857. {
  39858. sc->file_names_size = INITIAL_FILE_NAMES_SIZE;
  39859. sc->file_names = (s7_pointer *)calloc(sc->file_names_size, sizeof(s7_pointer));
  39860. }
  39861. else
  39862. {
  39863. old_size = sc->file_names_size;
  39864. sc->file_names_size *= 2;
  39865. sc->file_names = (s7_pointer *)realloc(sc->file_names, sc->file_names_size * sizeof(s7_pointer));
  39866. }
  39867. for (i = old_size; i < sc->file_names_size; i++)
  39868. sc->file_names[i] = sc->F;
  39869. }
  39870. sc->file_names[sc->file_names_top] = s7_make_permanent_string(file);
  39871. return(sc->file_names_top);
  39872. }
  39873. static s7_pointer init_owlet(s7_scheme *sc)
  39874. {
  39875. s7_pointer e;
  39876. e = new_frame_in_env(sc, sc->rootlet);
  39877. sc->temp3 = e;
  39878. sc->error_type = make_slot_1(sc, e, make_symbol(sc, "error-type"), sc->F); /* the error type or tag ('division-by-zero) */
  39879. sc->error_data = make_slot_1(sc, e, make_symbol(sc, "error-data"), sc->F); /* the message or information passed by the error function */
  39880. sc->error_code = make_slot_1(sc, e, make_symbol(sc, "error-code"), sc->F); /* the code that s7 thinks triggered the error */
  39881. sc->error_line = make_slot_1(sc, e, make_symbol(sc, "error-line"), sc->F); /* the line number of that code */
  39882. sc->error_file = make_slot_1(sc, e, make_symbol(sc, "error-file"), sc->F); /* the file name of that code */
  39883. #if WITH_HISTORY
  39884. sc->error_history = make_slot_1(sc, e, make_symbol(sc, "error-history"), sc->F); /* buffer of previous evaluations */
  39885. #endif
  39886. return(e);
  39887. }
  39888. static s7_pointer g_owlet(s7_scheme *sc, s7_pointer args)
  39889. {
  39890. #if WITH_HISTORY
  39891. #define H_owlet "(owlet) returns the environment at the point of the last error. \
  39892. It has the additional local variables: error-type, error-data, error-code, error-line, error-file, and error-history."
  39893. #else
  39894. #define H_owlet "(owlet) returns the environment at the point of the last error. \
  39895. It has the additional local variables: error-type, error-data, error-code, error-line, and error-file."
  39896. #endif
  39897. #define Q_owlet s7_make_signature(sc, 1, sc->is_let_symbol)
  39898. /* if owlet is not copied, (define e (owlet)), e changes as owlet does!
  39899. */
  39900. s7_pointer e, x;
  39901. int gc_loc;
  39902. e = let_copy(sc, sc->owlet);
  39903. gc_loc = s7_gc_protect(sc, e);
  39904. /* also make sure the pairs are copied: should be error-data, error-code, and possibly error-history */
  39905. for (x = let_slots(e); is_slot(x); x = next_slot(x))
  39906. if (is_pair(slot_value(x)))
  39907. slot_set_value(x, protected_list_copy(sc, slot_value(x)));
  39908. s7_gc_unprotect_at(sc, gc_loc);
  39909. return(e);
  39910. }
  39911. static s7_pointer c_owlet(s7_scheme *sc) {return(g_owlet(sc, sc->nil));}
  39912. PF_0(owlet, c_owlet)
  39913. static s7_pointer active_catches(s7_scheme *sc)
  39914. {
  39915. int i;
  39916. s7_pointer x, lst;
  39917. lst = sc->nil;
  39918. for (i = s7_stack_top(sc) - 1; i >= 3; i -= 4)
  39919. switch (stack_op(sc->stack, i))
  39920. {
  39921. case OP_CATCH_ALL:
  39922. lst = cons(sc, sc->T, lst);
  39923. break;
  39924. case OP_CATCH_2:
  39925. case OP_CATCH_1:
  39926. case OP_CATCH:
  39927. x = stack_code(sc->stack, i);
  39928. lst = cons(sc, catch_tag(x), lst);
  39929. break;
  39930. }
  39931. return(reverse_in_place_unchecked(sc, sc->nil, lst));
  39932. }
  39933. static s7_pointer active_exits(s7_scheme *sc)
  39934. {
  39935. /* (call-with-exit (lambda (exiter) (*s7* 'exits))) */
  39936. int i;
  39937. s7_pointer lst;
  39938. lst = sc->nil;
  39939. for (i = s7_stack_top(sc) - 1; i >= 3; i -= 4)
  39940. if (stack_op(sc->stack, i) == OP_DEACTIVATE_GOTO)
  39941. {
  39942. s7_pointer func, jump;
  39943. func = stack_code(sc->stack, i); /* presumably this has the goto name */
  39944. jump = stack_args(sc->stack, i); /* call this to jump */
  39945. if (is_any_closure(func))
  39946. lst = cons(sc, cons(sc, car(closure_args(func)), jump), lst);
  39947. else
  39948. {
  39949. if ((is_pair(func)) && (car(func) == sc->call_with_exit_symbol))
  39950. lst = cons(sc, cons(sc, car(cadr(cadr(func))), jump), lst); /* (call-with-exit (lambda (three) ...)) */
  39951. else lst = cons(sc, cons(sc, sc->unspecified, jump), lst);
  39952. }
  39953. sc->w = lst;
  39954. }
  39955. return(reverse_in_place_unchecked(sc, sc->nil, lst));
  39956. }
  39957. static s7_pointer stack_entries(s7_scheme *sc, s7_pointer stack, int top)
  39958. {
  39959. int i;
  39960. s7_pointer lst;
  39961. lst = sc->nil;
  39962. for (i = top - 1; i >= 3; i -= 4)
  39963. {
  39964. s7_pointer func, args, e;
  39965. opcode_t op;
  39966. func = stack_code(stack, i);
  39967. args = stack_args(stack, i);
  39968. e = stack_let(stack, i);
  39969. op = stack_op(stack, i);
  39970. if ((s7_is_valid(sc, func)) &&
  39971. (s7_is_valid(sc, args)) &&
  39972. (s7_is_valid(sc, e)) &&
  39973. (op < OP_MAX_DEFINED))
  39974. {
  39975. #if DEBUGGING
  39976. if (op < OP_MAX_DEFINED_1)
  39977. lst = cons(sc, list_4(sc, func, args, e, make_string_wrapper(sc, op_names[op])), lst);
  39978. else lst = cons(sc, list_4(sc, func, args, e, make_integer(sc, op)), lst);
  39979. #else
  39980. lst = cons(sc, list_4(sc, func, args, e, make_integer(sc, op)), lst);
  39981. #endif
  39982. sc->w = lst;
  39983. }
  39984. }
  39985. return(reverse_in_place_unchecked(sc, sc->nil, lst));
  39986. }
  39987. /* catch handlers */
  39988. typedef bool (*catch_function)(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook);
  39989. static catch_function catchers[OP_MAX_DEFINED + 1];
  39990. static bool catch_all_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  39991. {
  39992. s7_pointer catcher;
  39993. catcher = stack_let(sc->stack, i);
  39994. sc->op_stack_now = (s7_pointer *)(sc->op_stack + catch_all_op_loc(catcher));
  39995. sc->stack_end = (s7_pointer *)(sc->stack_start + catch_all_goto_loc(catcher));
  39996. pop_stack(sc);
  39997. sc->value = catch_all_result(catcher);
  39998. return(true);
  39999. }
  40000. static bool catch_2_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40001. {
  40002. /* this is the macro-error-handler case from g_catch
  40003. * (let () (define-macro (m . args) (apply (car args) (cadr args))) (catch #t (lambda () (error abs -1)) m))
  40004. */
  40005. s7_pointer x;
  40006. x = stack_code(sc->stack, i);
  40007. if ((catch_tag(x) == sc->T) ||
  40008. (catch_tag(x) == type) ||
  40009. (type == sc->T))
  40010. {
  40011. int loc;
  40012. loc = catch_goto_loc(x);
  40013. sc->op_stack_now = (s7_pointer *)(sc->op_stack + catch_op_loc(x));
  40014. sc->stack_end = (s7_pointer *)(sc->stack_start + loc);
  40015. sc->code = catch_handler(x);
  40016. set_car(sc->t2_1, type);
  40017. set_car(sc->t2_2, info);
  40018. sc->args = sc->t2_1; /* copied in op_apply? */
  40019. sc->op = OP_APPLY;
  40020. return(true);
  40021. }
  40022. return(false);
  40023. }
  40024. static bool catch_1_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40025. {
  40026. s7_pointer x;
  40027. x = stack_code(sc->stack, i);
  40028. if ((catch_tag(x) == sc->T) ||
  40029. (catch_tag(x) == type) ||
  40030. (type == sc->T))
  40031. {
  40032. unsigned int loc;
  40033. opcode_t op;
  40034. s7_pointer catcher, error_func, body;
  40035. op = stack_op(sc->stack, i);
  40036. sc->temp4 = stack_let(sc->stack, i); /* GC protect this, since we're moving the stack top below */
  40037. catcher = x;
  40038. loc = catch_goto_loc(catcher);
  40039. sc->op_stack_now = (s7_pointer *)(sc->op_stack + catch_op_loc(catcher));
  40040. sc->stack_end = (s7_pointer *)(sc->stack_start + loc);
  40041. error_func = catch_handler(catcher);
  40042. /* very often the error handler just returns either a constant ('error or #f), or
  40043. * the args passed to it, so there's no need to laboriously make a closure,
  40044. * and apply it -- just set sc->value to the closure body (or the args) and
  40045. * return.
  40046. *
  40047. * so first examine closure_body(error_func)
  40048. * if it is a constant, or quoted symbol, return that,
  40049. * if it is the args symbol, return (list type info)
  40050. */
  40051. /* if OP_CATCH_1, we deferred making the error handler until it is actually needed */
  40052. if (op == OP_CATCH_1)
  40053. body = cdr(error_func);
  40054. else
  40055. {
  40056. if (is_closure(error_func))
  40057. body = closure_body(error_func);
  40058. else body = NULL;
  40059. }
  40060. if ((body) && (is_null(cdr(body))))
  40061. {
  40062. s7_pointer y = NULL;
  40063. body = car(body);
  40064. if (is_pair(body))
  40065. {
  40066. if (car(body) == sc->quote_symbol)
  40067. y = cadr(body);
  40068. else
  40069. {
  40070. if ((car(body) == sc->car_symbol) &&
  40071. (is_pair(error_func)) &&
  40072. (cadr(body) == car(error_func)))
  40073. y = type;
  40074. }
  40075. }
  40076. else
  40077. {
  40078. if (is_symbol(body))
  40079. {
  40080. if ((is_pair(error_func)) &&
  40081. (body == car(error_func)))
  40082. y = list_2(sc, type, info);
  40083. }
  40084. else y = body;
  40085. }
  40086. if (y)
  40087. {
  40088. if (loc > 4)
  40089. pop_stack(sc);
  40090. /* we're at OP_CATCH, normally we want to pop that away, but (handwaving...) if we're coming
  40091. * from s7_eval (indirectly perhaps through s7_eval_c_string), we might push the OP_EVAL_DONE
  40092. * to end that call, but it's pushed at the precatch stack end (far beyond the catch loc).
  40093. * If we catch an error, catch unwinds to its starting point, and the pop_stack above
  40094. * puts us at the bottom of the stack (i.e. stack_end == stack_start), OP_EVAL_DONE.
  40095. * Now we return true, ending up back in eval, because the error handler jumped out of eval,
  40096. * back to wherever we were in eval when we hit the error. eval jumps back to the start
  40097. * of its loop, and pops the stack to see what to do next! So the (loc > 4) at least
  40098. * protects against stack underflow, but ideally we'd know we came from OP_CATCH+s7_eval.
  40099. * We can't do anything fancy here because we have to unwind the C stack as well as s7's stack.
  40100. * s7_eval doesn't know anything about the catches on the stack. We can't look back for
  40101. * OP_EVAL_DONE -- segfault in OP_BEGIN. Hmmmm. Perhaps catch should not unwind until the
  40102. * end? But we want the error handler to run as a part of the calling expression, and
  40103. * in any case the OP_EVAL_DONE is not useful (it marks the end of the no-error case).
  40104. */
  40105. sc->value = y;
  40106. sc->temp4 = sc->nil;
  40107. return(true);
  40108. }
  40109. }
  40110. if (op == OP_CATCH_1)
  40111. {
  40112. s7_pointer y = NULL;
  40113. make_closure_without_capture(sc, y, car(error_func), cdr(error_func), sc->temp4);
  40114. sc->code = y;
  40115. }
  40116. else sc->code = error_func;
  40117. sc->temp4 = sc->nil;
  40118. /* if user (i.e. yers truly!) copies/pastes the preceding lambda () into the
  40119. * error handler portion of the catch, he gets the inexplicable message:
  40120. * ;(): too many arguments: (a1 ())
  40121. * when this apply tries to call the handler. So, we need a special case
  40122. * error check here!
  40123. */
  40124. if (!s7_is_aritable(sc, sc->code, 2))
  40125. {
  40126. s7_wrong_number_of_args_error(sc, "catch error handler should accept 2 args: ~S", sc->code);
  40127. return(false);
  40128. }
  40129. /* since make_closure_with_let sets needs_copied_args and we're going to OP_APPLY,
  40130. * we don't need a new list here.
  40131. */
  40132. set_car(sc->t2_1, type);
  40133. set_car(sc->t2_2, info);
  40134. sc->args = sc->t2_1;
  40135. sc->op = OP_APPLY;
  40136. /* explicit eval needed if s7_call called into scheme where a caught error occurred (ex6 in exs7.c)
  40137. * but putting it here (via eval(sc, OP_APPLY)) means the C stack is not cleared correctly in non-s7-call cases,
  40138. * so defer it until s7_call
  40139. */
  40140. return(true);
  40141. }
  40142. return(false);
  40143. }
  40144. static bool catch_dw_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40145. {
  40146. s7_pointer x;
  40147. x = stack_code(sc->stack, i);
  40148. if (dynamic_wind_state(x) == DWIND_BODY)
  40149. {
  40150. dynamic_wind_state(x) = DWIND_FINISH; /* make sure an uncaught error in the exit thunk doesn't cause us to loop */
  40151. if (dynamic_wind_out(x) != sc->F)
  40152. {
  40153. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  40154. sc->code = dynamic_wind_out(x);
  40155. sc->args = sc->nil;
  40156. eval(sc, OP_APPLY); /* I guess this means no call/cc out of the exit thunk in an error-catching context */
  40157. }
  40158. }
  40159. return(false);
  40160. }
  40161. static bool catch_out_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40162. {
  40163. s7_pointer x;
  40164. x = stack_code(sc->stack, i); /* "code" = port that we opened */
  40165. s7_close_output_port(sc, x);
  40166. x = stack_args(sc->stack, i); /* "args" = port that we shadowed, if not #f */
  40167. if (x != sc->F)
  40168. sc->output_port = x;
  40169. return(false);
  40170. }
  40171. static bool catch_in_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40172. {
  40173. s7_close_input_port(sc, stack_code(sc->stack, i)); /* "code" = port that we opened */
  40174. sc->input_port = stack_args(sc->stack, i); /* "args" = port that we shadowed */
  40175. return(false);
  40176. }
  40177. static bool catch_read_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40178. {
  40179. pop_input_port(sc);
  40180. return(false);
  40181. }
  40182. static bool catch_eval_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40183. {
  40184. s7_close_input_port(sc, sc->input_port);
  40185. pop_input_port(sc);
  40186. return(false);
  40187. }
  40188. static bool catch_barrier_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40189. {
  40190. if (is_input_port(stack_args(sc->stack, i))) /* (eval-string "'(1 .)") */
  40191. {
  40192. if (sc->input_port == stack_args(sc->stack, i))
  40193. pop_input_port(sc);
  40194. s7_close_input_port(sc, stack_args(sc->stack, i));
  40195. }
  40196. return(false);
  40197. }
  40198. static bool catch_hook_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40199. {
  40200. sc->error_hook = stack_code(sc->stack, i);
  40201. /* apparently there was an error during *error-hook* evaluation, but Rick wants the hook re-established anyway */
  40202. (*reset_hook) = true;
  40203. /* avoid infinite loop -- don't try to (re-)evaluate (buggy) *error-hook*! */
  40204. return(false);
  40205. }
  40206. static bool catch_goto_function(s7_scheme *sc, int i, s7_pointer type, s7_pointer info, bool *reset_hook)
  40207. {
  40208. call_exit_active(stack_args(sc->stack, i)) = false;
  40209. return(false);
  40210. }
  40211. static void init_catchers(void)
  40212. {
  40213. int i;
  40214. for (i = 0; i <= OP_MAX_DEFINED; i++) catchers[i] = NULL;
  40215. catchers[OP_CATCH_ALL] = catch_all_function;
  40216. catchers[OP_CATCH_2] = catch_2_function;
  40217. catchers[OP_CATCH_1] = catch_1_function;
  40218. catchers[OP_CATCH] = catch_1_function;
  40219. catchers[OP_DYNAMIC_WIND] = catch_dw_function;
  40220. catchers[OP_GET_OUTPUT_STRING_1] = catch_out_function;
  40221. catchers[OP_UNWIND_OUTPUT] = catch_out_function;
  40222. catchers[OP_UNWIND_INPUT] = catch_in_function;
  40223. catchers[OP_READ_DONE] = catch_read_function; /* perhaps an error during (read) */
  40224. catchers[OP_EVAL_STRING_1] = catch_eval_function; /* perhaps an error happened before we could push the OP_EVAL_STRING_2 */
  40225. catchers[OP_EVAL_STRING_2] = catch_eval_function;
  40226. catchers[OP_BARRIER] = catch_barrier_function;
  40227. catchers[OP_DEACTIVATE_GOTO] = catch_goto_function;
  40228. catchers[OP_ERROR_HOOK_QUIT] = catch_hook_function;
  40229. }
  40230. static s7_pointer g_throw(s7_scheme *sc, s7_pointer args)
  40231. {
  40232. #define H_throw "(throw tag . info) is like (error ...) but it does not affect the owlet. \
  40233. It looks for an existing catch with a matching tag, and jumps to it if found. Otherwise it raises an error."
  40234. #define Q_throw pcl_t
  40235. bool ignored_flag = false;
  40236. int i;
  40237. s7_pointer type, info;
  40238. type = car(args);
  40239. info = cdr(args);
  40240. /* look for a catcher */
  40241. for (i = s7_stack_top(sc) - 1; i >= 3; i -= 4)
  40242. {
  40243. catch_function catcher;
  40244. catcher = catchers[stack_op(sc->stack, i)];
  40245. if ((catcher) &&
  40246. (catcher(sc, i, type, info, &ignored_flag)))
  40247. {
  40248. if (sc->longjmp_ok) longjmp(sc->goto_start, THROW_JUMP);
  40249. return(sc->value);
  40250. }
  40251. }
  40252. if (is_let(car(args))) check_method(sc, car(args), sc->throw_symbol, args);
  40253. return(s7_error(sc, make_symbol(sc, "uncaught-throw"),
  40254. set_elist_3(sc, make_string_wrapper(sc, "no catch found for (throw ~W~{~^ ~S~~})"), type, info)));
  40255. }
  40256. static void s7_warn(s7_scheme *sc, int len, const char *ctrl, ...)
  40257. {
  40258. va_list ap;
  40259. char *str;
  40260. str = (char *)malloc(len * sizeof(char));
  40261. va_start(ap, ctrl);
  40262. len = vsnprintf(str, len, ctrl, ap);
  40263. va_end(ap);
  40264. if (port_is_closed(sc->error_port))
  40265. sc->error_port = sc->standard_error;
  40266. s7_display(sc, make_string_uncopied_with_length(sc, str, len), sc->error_port);
  40267. }
  40268. s7_pointer s7_error(s7_scheme *sc, s7_pointer type, s7_pointer info)
  40269. {
  40270. static int last_line = -1;
  40271. bool reset_error_hook = false;
  40272. s7_pointer cur_code;
  40273. /* type is a symbol normally, and info is compatible with format: (apply format #f info) --
  40274. * car(info) is the control string, cdr(info) its args
  40275. * type/range errors have cadr(info)=caller, caddr(info)=offending arg number
  40276. * null info can mean symbol table is locked so make-symbol uses s7_error to get out
  40277. *
  40278. * set up (owlet), look for a catch that matches 'type', if found
  40279. * call its error-handler, else if *error-hook* is bound, call it,
  40280. * else send out the error info ourselves.
  40281. */
  40282. sc->no_values = 0;
  40283. sc->format_depth = -1;
  40284. sc->gc_off = false; /* this is in case we were triggered from the sort function -- clumsy! */
  40285. s7_xf_clear(sc);
  40286. slot_set_value(sc->error_type, type);
  40287. slot_set_value(sc->error_data, info);
  40288. #if DEBUGGING
  40289. if (!is_let(sc->owlet))
  40290. fprintf(stderr, "owlet clobbered!\n");
  40291. #endif
  40292. if ((unchecked_type(sc->envir) != T_LET) &&
  40293. (sc->envir != sc->nil))
  40294. sc->envir = sc->nil; /* in reader, the envir frame is mostly ignored so it can be (and usually is) garbage */
  40295. set_outlet(sc->owlet, sc->envir);
  40296. cur_code = current_code(sc);
  40297. slot_set_value(sc->error_code, cur_code);
  40298. #if WITH_HISTORY
  40299. slot_set_value(sc->error_history, sc->cur_code);
  40300. if (sc->using_history1)
  40301. sc->cur_code = sc->eval_history2;
  40302. else sc->cur_code = sc->eval_history1;
  40303. sc->using_history1 = (!sc->using_history1);
  40304. #endif
  40305. if ((is_pair(cur_code)) && /* can be () if unexpected close paren read error */
  40306. (has_line_number(cur_code)))
  40307. {
  40308. int line;
  40309. line = (int)pair_line(cur_code); /* cast to int (from unsigned int) for last_line */
  40310. if (line != last_line)
  40311. {
  40312. last_line = line;
  40313. if (line > 0)
  40314. {
  40315. slot_set_value(sc->error_line, make_integer(sc, remembered_line_number(line)));
  40316. slot_set_value(sc->error_file, remembered_file_name(line));
  40317. }
  40318. else
  40319. {
  40320. slot_set_value(sc->error_line, sc->F);
  40321. slot_set_value(sc->error_file, sc->F);
  40322. }
  40323. }
  40324. }
  40325. else
  40326. {
  40327. slot_set_value(sc->error_line, sc->F);
  40328. slot_set_value(sc->error_file, sc->F);
  40329. }
  40330. { /* look for a catcher */
  40331. int i;
  40332. /* top is 1 past actual top, top - 1 is op, if op = OP_CATCH, top - 4 is the cell containing the catch struct */
  40333. for (i = s7_stack_top(sc) - 1; i >= 3; i -= 4)
  40334. {
  40335. catch_function catcher;
  40336. catcher = catchers[stack_op(sc->stack, i)];
  40337. /* fprintf(stderr, "catching %s %s\n", DISPLAY(type), DISPLAY(info)); */
  40338. if ((catcher) &&
  40339. (catcher(sc, i, type, info, &reset_error_hook)))
  40340. {
  40341. if (sc->longjmp_ok) longjmp(sc->goto_start, CATCH_JUMP);
  40342. /* all the rest of the code expects s7_error to jump, not return,
  40343. * so presumably if we get here, we're in trouble -- try to send out an error message
  40344. */
  40345. /* return(type); */
  40346. /* fprintf(stderr, "falling through now\n"); */
  40347. }
  40348. }
  40349. }
  40350. /* error not caught */
  40351. /* (set! *error-hook* (list (lambda (hook) (apply format #t (hook 'args))))) */
  40352. if ((!reset_error_hook) &&
  40353. (is_procedure(sc->error_hook)) &&
  40354. (hook_has_functions(sc->error_hook)))
  40355. {
  40356. s7_pointer error_hook_func;
  40357. /* (set! (hook-functions *error-hook*) (list (lambda (h) (format *stderr* "got error ~A~%" (h 'args))))) */
  40358. error_hook_func = sc->error_hook;
  40359. sc->error_hook = sc->F;
  40360. /* if the *error-hook* functions trigger an error, we had better not have *error-hook* still set! */
  40361. push_stack(sc, OP_ERROR_HOOK_QUIT, sc->nil, error_hook_func); /* restore *error-hook* upon successful (or any!) evaluation */
  40362. sc->args = list_2(sc, type, info);
  40363. sc->code = error_hook_func;
  40364. /* if we drop into the longjmp below, the hook functions are not called!
  40365. * OP_ERROR_HOOK_QUIT performs the longjmp, so it should be safe to go to eval.
  40366. */
  40367. eval(sc, OP_APPLY);
  40368. }
  40369. else
  40370. {
  40371. if (port_is_closed(sc->error_port))
  40372. sc->error_port = sc->standard_error;
  40373. /* if info is not a list, send object->string to current error port,
  40374. * else assume car(info) is a format control string, and cdr(info) are its args
  40375. *
  40376. * if at all possible, get some indication of where we are!
  40377. */
  40378. if ((!s7_is_list(sc, info)) ||
  40379. (!is_string(car(info))))
  40380. format_to_port(sc, sc->error_port, "\n;~S ~S", set_plist_2(sc, type, info), NULL, false, 7);
  40381. else
  40382. {
  40383. int len = 0;
  40384. bool use_format = false;
  40385. /* it's possible that the error string is just a string -- not intended for format */
  40386. if (type != sc->format_error_symbol) /* avoid an infinite loop of format errors */
  40387. {
  40388. int i;
  40389. const char *carstr;
  40390. carstr = string_value(car(info));
  40391. len = string_length(car(info));
  40392. for (i = 0; i < len; i++)
  40393. if (carstr[i] == '~')
  40394. {
  40395. use_format = true;
  40396. break;
  40397. }
  40398. }
  40399. if (use_format)
  40400. {
  40401. char *errstr;
  40402. int str_len;
  40403. len += 8;
  40404. tmpbuf_malloc(errstr, len);
  40405. str_len = snprintf(errstr, len, "\n;%s", string_value(car(info)));
  40406. format_to_port(sc, sc->error_port, errstr, cdr(info), NULL, false, str_len);
  40407. tmpbuf_free(errstr, len);
  40408. }
  40409. else format_to_port(sc, sc->error_port, "\n;~S ~S", set_plist_2(sc, type, info), NULL, false, 7);
  40410. }
  40411. /* now display location at end */
  40412. if ((is_input_port(sc->input_port)) &&
  40413. (port_file(sc->input_port) != stdin) &&
  40414. (!port_is_closed(sc->input_port)))
  40415. {
  40416. const char *filename = NULL;
  40417. int line;
  40418. filename = port_filename(sc->input_port);
  40419. line = port_line_number(sc->input_port);
  40420. if (filename)
  40421. format_to_port(sc, sc->error_port, "\n; ~A[~D]", set_plist_2(sc, make_string_wrapper(sc, filename), make_integer(sc, line)), NULL, false, 10);
  40422. else
  40423. {
  40424. if ((line > 0) &&
  40425. (slot_value(sc->error_line) != sc->F))
  40426. format_to_port(sc, sc->error_port, "\n; line ~D", set_plist_1(sc, make_integer(sc, line)), NULL, false, 11);
  40427. else
  40428. {
  40429. if (is_pair(sc->input_port_stack))
  40430. {
  40431. s7_pointer p;
  40432. p = car(sc->input_port_stack);
  40433. if ((is_input_port(p)) &&
  40434. (port_file(p) != stdin) &&
  40435. (!port_is_closed(p)))
  40436. {
  40437. filename = port_filename(p);
  40438. line = port_line_number(p);
  40439. if (filename)
  40440. format_to_port(sc, sc->error_port, "\n; ~A[~D]",
  40441. set_plist_2(sc, make_string_wrapper(sc, filename), make_integer(sc, line)), NULL, false, 10);
  40442. }
  40443. }
  40444. }
  40445. }
  40446. }
  40447. else
  40448. {
  40449. const char *call_name;
  40450. call_name = sc->s7_call_name;
  40451. /* sc->s7_call_name = NULL; */
  40452. if (call_name)
  40453. {
  40454. sc->s7_call_name = NULL;
  40455. if ((sc->s7_call_file != NULL) &&
  40456. (sc->s7_call_line >= 0))
  40457. {
  40458. format_to_port(sc, sc->error_port, "\n; ~A ~A[~D]",
  40459. set_plist_3(sc,
  40460. make_string_wrapper(sc, call_name),
  40461. make_string_wrapper(sc, sc->s7_call_file),
  40462. make_integer(sc, sc->s7_call_line)),
  40463. NULL, false, 13);
  40464. }
  40465. }
  40466. }
  40467. s7_newline(sc, sc->error_port);
  40468. if (is_string(slot_value(sc->error_file)))
  40469. {
  40470. format_to_port(sc, sc->error_port, "; ~S, line ~D",
  40471. set_plist_2(sc, slot_value(sc->error_file), slot_value(sc->error_line)),
  40472. NULL, false, 16);
  40473. s7_newline(sc, sc->error_port);
  40474. }
  40475. /* look for __func__ in the error environment etc */
  40476. if (sc->error_port != sc->F)
  40477. {
  40478. char *errstr;
  40479. errstr = stacktrace_1(sc,
  40480. s7_integer(car(sc->stacktrace_defaults)),
  40481. s7_integer(cadr(sc->stacktrace_defaults)),
  40482. s7_integer(caddr(sc->stacktrace_defaults)),
  40483. s7_integer(cadddr(sc->stacktrace_defaults)),
  40484. s7_boolean(sc, s7_list_ref(sc, sc->stacktrace_defaults, 4)));
  40485. if (errstr)
  40486. {
  40487. port_write_string(sc->error_port)(sc, ";\n", 2, sc->error_port);
  40488. port_write_string(sc->error_port)(sc, errstr, strlen(errstr), sc->error_port);
  40489. free(errstr);
  40490. port_write_character(sc->error_port)(sc, '\n', sc->error_port);
  40491. }
  40492. }
  40493. else
  40494. {
  40495. if (is_pair(slot_value(sc->error_code)))
  40496. {
  40497. format_to_port(sc, sc->error_port, "; ~S", set_plist_1(sc, slot_value(sc->error_code)), NULL, false, 7);
  40498. s7_newline(sc, sc->error_port);
  40499. }
  40500. }
  40501. /* if (is_continuation(type))
  40502. * go into repl here with access to continuation? Or expect *error-handler* to deal with it?
  40503. */
  40504. sc->value = type;
  40505. /* stack_reset(sc); */
  40506. sc->op = OP_ERROR_QUIT;
  40507. }
  40508. if (sc->longjmp_ok) longjmp(sc->goto_start, ERROR_JUMP);
  40509. return(type);
  40510. }
  40511. static s7_pointer apply_error(s7_scheme *sc, s7_pointer obj, s7_pointer args)
  40512. {
  40513. /* the operator type is needed here else the error message is confusing:
  40514. * (apply '+ (list 1 2))) -> ;attempt to apply + to (1 2)?
  40515. */
  40516. static s7_pointer errstr = NULL;
  40517. if (is_null(obj))
  40518. return(s7_error(sc, sc->syntax_error_symbol, set_elist_2(sc, make_string_wrapper_with_length(sc, "attempt to apply nil to ~S?", 27), args)));
  40519. if (!errstr)
  40520. errstr = s7_make_permanent_string("attempt to apply ~A ~S to ~S?");
  40521. return(s7_error(sc, sc->syntax_error_symbol, set_elist_4(sc, errstr, type_name_string(sc, obj), obj, args)));
  40522. }
  40523. static s7_pointer read_error_1(s7_scheme *sc, const char *errmsg, bool string_error)
  40524. {
  40525. /* reader errors happen before the evaluator gets involved, so forms such as:
  40526. * (catch #t (lambda () (car '( . ))) (lambda arg 'error))
  40527. * do not catch the error if we simply signal an error when we encounter it.
  40528. */
  40529. char *msg;
  40530. int len;
  40531. s7_pointer pt;
  40532. /* fprintf(stderr, "read error: %s\n", errmsg); */
  40533. pt = sc->input_port;
  40534. if (!string_error)
  40535. {
  40536. /* make an heroic effort to find where we slid off the tracks */
  40537. if (is_string_port(sc->input_port))
  40538. {
  40539. #define QUOTE_SIZE 40
  40540. unsigned int i, j, start = 0, end, slen;
  40541. char *recent_input = NULL;
  40542. /* we can run off the end in cases like (eval-string "(. . ,.)") or (eval-string " (@ . ,.)") */
  40543. if (port_position(pt) >= port_data_size(pt))
  40544. port_position(pt) = port_data_size(pt) - 1;
  40545. /* start at current position and look back a few chars */
  40546. for (i = port_position(pt), j = 0; (i > 0) && (j < QUOTE_SIZE); i--, j++)
  40547. if ((port_data(pt)[i] == '\0') ||
  40548. (port_data(pt)[i] == '\n') ||
  40549. (port_data(pt)[i] == '\r'))
  40550. break;
  40551. start = i;
  40552. /* start at current position and look ahead a few chars */
  40553. for (i = port_position(pt), j = 0; (i < port_data_size(pt)) && (j < QUOTE_SIZE); i++, j++)
  40554. if ((port_data(pt)[i] == '\0') ||
  40555. (port_data(pt)[i] == '\n') ||
  40556. (port_data(pt)[i] == '\r'))
  40557. break;
  40558. end = i;
  40559. slen = end - start;
  40560. /* hopefully this is more or less the current line where the read error happened */
  40561. if (slen > 0)
  40562. {
  40563. recent_input = (char *)calloc((slen + 9), sizeof(char));
  40564. for (i = 0; i < (slen + 8); i++) recent_input[i] = '.';
  40565. recent_input[3] = ' ';
  40566. recent_input[slen + 4] = ' ';
  40567. for (i = 0; i < slen; i++) recent_input[i + 4] = port_data(pt)[start + i];
  40568. }
  40569. if ((port_line_number(pt) > 0) &&
  40570. (port_filename(pt)))
  40571. {
  40572. len = safe_strlen(recent_input) + safe_strlen(errmsg) + port_filename_length(pt) + safe_strlen(sc->current_file) + 64;
  40573. msg = (char *)malloc(len * sizeof(char));
  40574. len = snprintf(msg, len, "%s: %s %s[%u], last top-level form at: %s[%d]",
  40575. errmsg, (recent_input) ? recent_input : "", port_filename(pt), port_line_number(pt),
  40576. sc->current_file, sc->current_line);
  40577. }
  40578. else
  40579. {
  40580. len = safe_strlen(recent_input) + safe_strlen(errmsg) + safe_strlen(sc->current_file) + 64;
  40581. msg = (char *)malloc(len * sizeof(char));
  40582. if ((sc->current_file) &&
  40583. (sc->current_line >= 0))
  40584. len = snprintf(msg, len, "%s: %s, last top-level form at %s[%d]",
  40585. errmsg, (recent_input) ? recent_input : "",
  40586. sc->current_file, sc->current_line);
  40587. else len = snprintf(msg, len, "%s: %s", errmsg, (recent_input) ? recent_input : "");
  40588. }
  40589. if (recent_input) free(recent_input);
  40590. return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_uncopied_with_length(sc, msg, len))));
  40591. }
  40592. }
  40593. if ((port_line_number(pt) > 0) &&
  40594. (port_filename(pt)))
  40595. {
  40596. len = safe_strlen(errmsg) + port_filename_length(pt) + safe_strlen(sc->current_file) + 128;
  40597. msg = (char *)malloc(len * sizeof(char));
  40598. if (string_error)
  40599. len = snprintf(msg, len, "%s %s[%u],\n; possible culprit: \"%s...\"\n; last top-level form at %s[%d]",
  40600. errmsg, port_filename(pt), port_line_number(pt),
  40601. sc->strbuf, sc->current_file, sc->current_line);
  40602. else len = snprintf(msg, len, "%s %s[%u], last top-level form at %s[%d]",
  40603. errmsg, port_filename(pt), port_line_number(pt),
  40604. sc->current_file, sc->current_line);
  40605. return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_uncopied_with_length(sc, msg, len))));
  40606. }
  40607. return(s7_error(sc, (string_error) ? sc->string_read_error_symbol : sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, (char *)errmsg))));
  40608. }
  40609. static s7_pointer read_error(s7_scheme *sc, const char *errmsg)
  40610. {
  40611. return(read_error_1(sc, errmsg, false));
  40612. }
  40613. static s7_pointer string_read_error(s7_scheme *sc, const char *errmsg)
  40614. {
  40615. return(read_error_1(sc, errmsg, true));
  40616. }
  40617. static s7_pointer g_error(s7_scheme *sc, s7_pointer args)
  40618. {
  40619. #define H_error "(error type ...) signals an error. The 'type' can be used with catch to trap \
  40620. particular errors. If the error is not caught, s7 treats the second argument as a format control string, \
  40621. and applies it to the rest of the arguments."
  40622. #define Q_error pcl_t
  40623. if (is_not_null(args))
  40624. {
  40625. if (is_string(car(args))) /* CL-style error? -- use tag = 'no-catch */
  40626. {
  40627. s7_error(sc, sc->no_catch_symbol, args); /* this can have trailing args (implicit format) */
  40628. return(sc->unspecified);
  40629. }
  40630. return(s7_error(sc, car(args), cdr(args)));
  40631. }
  40632. return(s7_error(sc, sc->nil, sc->nil));
  40633. }
  40634. static char *truncate_string(char *form, int len, use_write_t use_write, int *form_len)
  40635. {
  40636. unsigned char *f;
  40637. f = (unsigned char *)form;
  40638. if (use_write != USE_DISPLAY)
  40639. {
  40640. /* I guess we need to protect the outer double quotes in this case */
  40641. int i;
  40642. for (i = len - 5; i >= (len / 2); i--)
  40643. if (is_white_space((int)f[i]))
  40644. {
  40645. form[i] = '.';
  40646. form[i + 1] = '.';
  40647. form[i + 2] = '.';
  40648. form[i + 3] = '"';
  40649. form[i + 4] = '\0';
  40650. (*form_len) = i + 4;
  40651. return(form);
  40652. }
  40653. i = len - 5;
  40654. if (i > 0)
  40655. {
  40656. form[i] = '.';
  40657. form[i + 1] = '.';
  40658. form[i + 2] = '.';
  40659. form[i + 3] = '"';
  40660. form[i + 4] = '\0';
  40661. }
  40662. else
  40663. {
  40664. if (len >= 2)
  40665. {
  40666. form[len - 1] = '"';
  40667. form[len] = '\0';
  40668. }
  40669. }
  40670. }
  40671. else
  40672. {
  40673. int i;
  40674. for (i = len - 4; i >= (len / 2); i--)
  40675. if (is_white_space((int)f[i]))
  40676. {
  40677. form[i] = '.';
  40678. form[i + 1] = '.';
  40679. form[i + 2] = '.';
  40680. form[i + 3] = '\0';
  40681. (*form_len) = i + 3;
  40682. return(form);
  40683. }
  40684. i = len - 4;
  40685. if (i >= 0)
  40686. {
  40687. form[i] = '.';
  40688. form[i + 1] = '.';
  40689. form[i + 2] = '.';
  40690. form[i + 3] = '\0';
  40691. }
  40692. else form[len] = '\0';
  40693. }
  40694. return(form);
  40695. }
  40696. static char *object_to_truncated_string(s7_scheme *sc, s7_pointer p, int len)
  40697. {
  40698. char *s;
  40699. int s_len;
  40700. s = s7_object_to_c_string(sc, p);
  40701. s_len = safe_strlen(s);
  40702. if (s_len > len)
  40703. return(truncate_string(s, len, USE_DISPLAY, &s_len));
  40704. return(s);
  40705. }
  40706. static s7_pointer tree_descend(s7_scheme *sc, s7_pointer p, unsigned int line)
  40707. {
  40708. s7_pointer tp;
  40709. if (!is_pair(p)) return(NULL);
  40710. if (has_line_number(p))
  40711. {
  40712. unsigned int x;
  40713. x = (unsigned int)remembered_line_number(pair_line(p));
  40714. if (x > 0)
  40715. {
  40716. if (line == 0) /* first line number we encounter will be the current reader location (i.e. the end of the form) */
  40717. line = x;
  40718. else
  40719. {
  40720. if (x < line)
  40721. return(p);
  40722. }
  40723. }
  40724. }
  40725. tp = tree_descend(sc, car(p), line);
  40726. if (tp) return(tp);
  40727. return(tree_descend(sc, cdr(p), line));
  40728. }
  40729. static char *current_input_string(s7_scheme *sc, s7_pointer pt)
  40730. {
  40731. /* try to show the current input */
  40732. if ((is_input_port(pt)) &&
  40733. (!port_is_closed(pt)) &&
  40734. (port_data(pt)) &&
  40735. (port_position(pt) > 0))
  40736. {
  40737. const unsigned char *str;
  40738. char *msg;
  40739. int i, j, start;
  40740. start = (int)port_position(pt) - 40;
  40741. if (start < 0) start = 0;
  40742. msg = (char *)malloc(64 * sizeof(char));
  40743. str = (const unsigned char *)port_data(pt);
  40744. for (i = start, j = 0; i < (int)port_position(pt); i++, j++)
  40745. msg[j] = str[i];
  40746. msg[j] = '\0';
  40747. return(msg);
  40748. }
  40749. return(NULL);
  40750. }
  40751. static s7_pointer missing_close_paren_error(s7_scheme *sc)
  40752. {
  40753. int len;
  40754. char *msg, *syntax_msg = NULL;
  40755. s7_pointer pt;
  40756. if ((unchecked_type(sc->envir) != T_LET) &&
  40757. (sc->envir != sc->nil))
  40758. sc->envir = sc->nil;
  40759. pt = sc->input_port;
  40760. /* check *missing-close-paren-hook* */
  40761. if (hook_has_functions(sc->missing_close_paren_hook))
  40762. {
  40763. s7_pointer result;
  40764. if ((port_line_number(pt) > 0) &&
  40765. (port_filename(pt)))
  40766. {
  40767. slot_set_value(sc->error_line, make_integer(sc, port_line_number(pt)));
  40768. slot_set_value(sc->error_file, make_string_wrapper(sc, port_filename(pt)));
  40769. }
  40770. result = s7_call(sc, sc->missing_close_paren_hook, sc->nil);
  40771. if (result != sc->unspecified)
  40772. return(g_throw(sc, list_1(sc, result)));
  40773. }
  40774. if (is_pair(sc->args))
  40775. {
  40776. s7_pointer p;
  40777. p = tree_descend(sc, sc->args, 0);
  40778. if ((p) && (is_pair(p)) &&
  40779. (has_line_number(p)))
  40780. {
  40781. int msg_len, form_len;
  40782. char *form;
  40783. form = object_to_truncated_string(sc, p, 40);
  40784. form_len = safe_strlen(form);
  40785. msg_len = form_len + 128;
  40786. syntax_msg = (char *)malloc(msg_len * sizeof(char));
  40787. snprintf(syntax_msg, msg_len, "; current form awaiting a close paren starts around line %u: %s", remembered_line_number(pair_line(p)), form);
  40788. free(form);
  40789. }
  40790. }
  40791. if ((port_line_number(pt) > 0) &&
  40792. (port_filename(pt)))
  40793. {
  40794. len = port_filename_length(pt) + safe_strlen(sc->current_file) + safe_strlen(syntax_msg) + 128;
  40795. msg = (char *)malloc(len * sizeof(char));
  40796. if (syntax_msg)
  40797. {
  40798. len = snprintf(msg, len, "missing close paren, %s[%u], last top-level form at %s[%d]\n%s",
  40799. port_filename(pt), port_line_number(pt),
  40800. sc->current_file, sc->current_line, syntax_msg);
  40801. free(syntax_msg);
  40802. }
  40803. else len = snprintf(msg, len, "missing close paren, %s[%u], last top-level form at %s[%d]",
  40804. port_filename(pt), port_line_number(pt),
  40805. sc->current_file, sc->current_line);
  40806. return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_uncopied_with_length(sc, msg, len))));
  40807. }
  40808. if (syntax_msg)
  40809. {
  40810. len = safe_strlen(syntax_msg) + 128;
  40811. msg = (char *)malloc(len * sizeof(char));
  40812. len = snprintf(msg, len, "missing close paren\n%s\n", syntax_msg);
  40813. free(syntax_msg);
  40814. return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_uncopied_with_length(sc, msg, len))));
  40815. }
  40816. {
  40817. char *str;
  40818. msg = (char *)malloc(128 * sizeof(char));
  40819. str = current_input_string(sc, pt);
  40820. len = snprintf(msg, 128, "missing close paren: %s", str);
  40821. free(str);
  40822. return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_uncopied_with_length(sc, msg, len))));
  40823. }
  40824. return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "missing close paren"))));
  40825. }
  40826. static void improper_arglist_error(s7_scheme *sc)
  40827. {
  40828. /* sc->code is the last (dotted) arg, sc->args is the arglist reversed not including sc->code
  40829. * the original was `(,@(reverse args) . ,code) essentially
  40830. */
  40831. if (sc->args == sc->nil) /* (abs . 1) */
  40832. s7_error(sc, sc->syntax_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "function call is a dotted list?")));
  40833. else s7_error(sc, sc->syntax_error_symbol,
  40834. set_elist_2(sc, make_string_wrapper(sc, "improper list of arguments: ~S"),
  40835. append_in_place(sc, sc->args = safe_reverse_in_place(sc, sc->args), sc->code)));
  40836. }
  40837. /* -------------------------------- leftovers -------------------------------- */
  40838. void (*s7_begin_hook(s7_scheme *sc))(s7_scheme *sc, bool *val)
  40839. {
  40840. return(sc->begin_hook);
  40841. }
  40842. void s7_set_begin_hook(s7_scheme *sc, void (*hook)(s7_scheme *sc, bool *val))
  40843. {
  40844. sc->begin_hook = hook;
  40845. }
  40846. static bool call_begin_hook(s7_scheme *sc)
  40847. {
  40848. bool result = false;
  40849. /* originally begin_hook was bool (*hook)(s7_scheme *sc): the value was returned directly,
  40850. * rather than going through a *bool arg (&result below). That works in gcc (Linux/OSX),
  40851. * but does not work in MS Visual C++. In the latter, the compiler apparently completely
  40852. * eliminates any local, returning (for example) a thread-relative stack-allocated value
  40853. * directly, but then by the time we get here, that variable has vanished, and we get
  40854. * garbage. We had to thwart the optimization by adding if ((flag) && (!flag)) fprintf(...);
  40855. * So, in the new form (26-Jun-13), the value is passed directly into an s7 variable
  40856. * that I hope can't be optimized out of existence.
  40857. */
  40858. opcode_t op;
  40859. op = sc->op;
  40860. push_stack(sc, OP_BARRIER, sc->args, sc->code);
  40861. sc->begin_hook(sc, &result);
  40862. if (result)
  40863. {
  40864. /* set (owlet) in case we were interrupted and need to see why something was hung */
  40865. slot_set_value(sc->error_type, sc->F);
  40866. slot_set_value(sc->error_data, sc->value); /* was sc->F but we now clobber this below */
  40867. slot_set_value(sc->error_code, current_code(sc));
  40868. slot_set_value(sc->error_line, sc->F);
  40869. slot_set_value(sc->error_file, sc->F);
  40870. #if WITH_HISTORY
  40871. slot_set_value(sc->error_history, sc->F);
  40872. #endif
  40873. set_outlet(sc->owlet, sc->envir);
  40874. sc->value = s7_make_symbol(sc, "begin-hook-interrupt");
  40875. /* otherwise the evaluator returns whatever random thing is in sc->value (normally #<closure>)
  40876. * which makes debugging unnecessarily difficult.
  40877. */
  40878. s7_quit(sc); /* don't call gc here -- perhaps at restart somehow? */
  40879. return(true);
  40880. }
  40881. pop_stack_no_op(sc);
  40882. sc->op = op; /* for better error handling. otherwise we get "barrier" as the offending function name in eval_error */
  40883. return(false);
  40884. }
  40885. static s7_pointer apply_list_star(s7_scheme *sc, s7_pointer d)
  40886. {
  40887. s7_pointer p, q;
  40888. /* we check this ahead of time: if (is_null(cdr(d))) return(car(d)); */
  40889. p = cons(sc, car(d), cdr(d));
  40890. q = p;
  40891. while (is_not_null(cdr(cdr(p))))
  40892. {
  40893. d = cdr(d);
  40894. set_cdr(p, cons(sc, car(d), cdr(d)));
  40895. if (is_not_null(cdr(d)))
  40896. p = cdr(p);
  40897. }
  40898. set_cdr(p, car(cdr(p)));
  40899. return(q);
  40900. }
  40901. static s7_pointer apply_list_error(s7_scheme *sc, s7_pointer lst)
  40902. {
  40903. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "apply's last argument should be a proper list: ~S"), lst)));
  40904. }
  40905. static s7_pointer g_apply(s7_scheme *sc, s7_pointer args)
  40906. {
  40907. #define H_apply "(apply func ...) applies func to the rest of the arguments"
  40908. #define Q_apply s7_make_circular_signature(sc, 2, 3, sc->values_symbol, sc->is_procedure_symbol, sc->T)
  40909. /* can apply always be replaced with apply values?
  40910. * (apply + '(1 2 3)) is the same as (+ (apply values '(1 2 3)))
  40911. * not if apply* in disguise, I think:
  40912. * (apply + 1 2 ()) -> 3
  40913. * (apply + 1 2 (apply values ())) -> error
  40914. */
  40915. sc->code = car(args);
  40916. if (is_null(cdr(args)))
  40917. sc->args = sc->nil;
  40918. else
  40919. {
  40920. if (is_safe_procedure(sc->code))
  40921. {
  40922. s7_pointer p, q;
  40923. for (q = args, p = cdr(args); is_not_null(cdr(p)); q = p, p = cdr(p));
  40924. /* the last arg is supposed to be a list, it will be spliced onto the end of the previous arg list (if any) below */
  40925. if (!is_proper_list(sc, car(p))) /* (apply + #f) etc */
  40926. return(apply_list_error(sc, args));
  40927. set_cdr(q, car(p));
  40928. /* this would work: if (is_c_function(sc->code)) return(c_function_call(sc->code)(sc, cdr(args)));
  40929. * but it omits the arg number check
  40930. */
  40931. push_stack(sc, OP_APPLY, cdr(args), sc->code);
  40932. return(sc->nil);
  40933. }
  40934. else
  40935. {
  40936. /* here we have to copy the arg list */
  40937. if (is_null(cddr(args)))
  40938. sc->args = cadr(args);
  40939. else sc->args = apply_list_star(sc, cdr(args));
  40940. if (!is_proper_list(sc, sc->args)) /* (apply + #f) etc */
  40941. return(apply_list_error(sc, args));
  40942. }
  40943. }
  40944. push_stack(sc, OP_APPLY, sc->args, sc->code);
  40945. return(sc->nil);
  40946. }
  40947. s7_pointer s7_apply_function(s7_scheme *sc, s7_pointer fnc, s7_pointer args)
  40948. {
  40949. #if DEBUGGING
  40950. {
  40951. s7_pointer p;
  40952. int argnum;
  40953. _NFre(fnc);
  40954. for (argnum = 0, p = _NFre(args); is_pair(p); argnum++, p = _NFre(cdr(p)))
  40955. _NFre(car(p));
  40956. }
  40957. #endif
  40958. if (is_c_function(fnc))
  40959. return(c_function_call(fnc)(sc, args));
  40960. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  40961. sc->args = args;
  40962. sc->code = fnc;
  40963. eval(sc, OP_APPLY);
  40964. /* we're limited in choices here -- the caller might be (say) car(sc->t1_1) = c_call(...) where the c_call
  40965. * happens to fallback on a method -- we can't just push OP_APPLY and drop back into the evaluator normally.
  40966. */
  40967. return(sc->value);
  40968. }
  40969. s7_pointer s7_eval(s7_scheme *sc, s7_pointer code, s7_pointer e)
  40970. {
  40971. declare_jump_info();
  40972. #if DEBUGGING
  40973. _NFre(code);
  40974. #endif
  40975. store_jump_info(sc);
  40976. set_jump_info(sc, EVAL_SET_JUMP);
  40977. if (jump_loc != NO_JUMP)
  40978. {
  40979. if (jump_loc != ERROR_JUMP)
  40980. eval(sc, sc->op);
  40981. }
  40982. else
  40983. {
  40984. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code);
  40985. sc->code = code;
  40986. if ((e != sc->rootlet) &&
  40987. (is_let(e)))
  40988. sc->envir = e;
  40989. else sc->envir = sc->nil;
  40990. eval(sc, OP_EVAL);
  40991. }
  40992. restore_jump_info(sc);
  40993. if (is_multiple_value(sc->value))
  40994. sc->value = splice_in_values(sc, multiple_value(sc->value));
  40995. return(sc->value);
  40996. }
  40997. static s7_pointer g_eval(s7_scheme *sc, s7_pointer args)
  40998. {
  40999. #define H_eval "(eval code (env (curlet))) evaluates code in the environment env. 'env' \
  41000. defaults to the curlet; to evaluate something in the top-level environment instead, \
  41001. pass (rootlet):\n\
  41002. \n\
  41003. (define x 32) \n\
  41004. (let ((x 3))\n\
  41005. (eval 'x (rootlet)))\n\
  41006. \n\
  41007. returns 32"
  41008. #define Q_eval s7_make_signature(sc, 3, sc->values_symbol, sc->T, sc->is_let_symbol)
  41009. if (is_not_null(cdr(args)))
  41010. {
  41011. s7_pointer e;
  41012. e = cadr(args);
  41013. if (!is_let(e))
  41014. return(wrong_type_argument_with_type(sc, sc->eval_symbol, 2, e, a_let_string));
  41015. if (e == sc->rootlet)
  41016. sc->envir = sc->nil;
  41017. else sc->envir = e;
  41018. }
  41019. sc->code = car(args);
  41020. if (s7_stack_top(sc) < 12)
  41021. push_stack(sc, OP_BARRIER, sc->nil, sc->nil);
  41022. push_stack(sc, OP_EVAL, sc->args, sc->code);
  41023. return(sc->nil);
  41024. }
  41025. s7_pointer s7_call(s7_scheme *sc, s7_pointer func, s7_pointer args)
  41026. {
  41027. /* fprintf(stderr, "%s %s\n", DISPLAY(func), DISPLAY(args)); */
  41028. declare_jump_info();
  41029. if (is_c_function(func))
  41030. return(c_function_call(func)(sc, _NFre(args))); /* no check for wrong-number-of-args -- is that reasonable? */
  41031. sc->temp1 = _NFre(func); /* this is feeble GC protection */
  41032. sc->temp2 = _NFre(args);
  41033. store_jump_info(sc);
  41034. set_jump_info(sc, S7_CALL_SET_JUMP);
  41035. if (jump_loc != NO_JUMP)
  41036. {
  41037. if (jump_loc != ERROR_JUMP)
  41038. eval(sc, sc->op);
  41039. if ((jump_loc == CATCH_JUMP) && /* we're returning (back to eval) from an error in catch */
  41040. (sc->stack_end == sc->stack_start))
  41041. push_stack(sc, OP_ERROR_QUIT, sc->nil, sc->nil);
  41042. }
  41043. else
  41044. {
  41045. #if DEBUGGING
  41046. {
  41047. s7_pointer p;
  41048. int argnum;
  41049. /* incoming args may be non-s7 cells -- check now before they reach the GC */
  41050. for (argnum = 0, p = _NFre(args); is_pair(p); argnum++, p = _NFre(cdr(p)))
  41051. _NFre(car(p));
  41052. }
  41053. #endif
  41054. push_stack(sc, OP_EVAL_DONE, sc->args, sc->code); /* this saves the current evaluation and will eventually finish this (possibly) nested call */
  41055. sc->args = args;
  41056. sc->code = func;
  41057. /* besides a closure, "func" can also be an object (T_C_OBJECT) -- in Snd, a generator for example */
  41058. eval(sc, OP_APPLY);
  41059. }
  41060. restore_jump_info(sc);
  41061. return(sc->value);
  41062. }
  41063. s7_pointer s7_call_with_location(s7_scheme *sc, s7_pointer func, s7_pointer args, const char *caller, const char *file, int line)
  41064. {
  41065. s7_pointer result;
  41066. if (caller)
  41067. {
  41068. sc->s7_call_name = caller;
  41069. sc->s7_call_file = file;
  41070. sc->s7_call_line = line;
  41071. }
  41072. result = s7_call(sc, func, args);
  41073. if (caller)
  41074. {
  41075. sc->s7_call_name = NULL;
  41076. sc->s7_call_file = NULL;
  41077. sc->s7_call_line = -1;
  41078. }
  41079. return(result);
  41080. }
  41081. static s7_pointer implicit_index(s7_scheme *sc, s7_pointer obj, s7_pointer indices)
  41082. {
  41083. /* (let ((lst '("12" "34"))) (lst 0 1)) -> #\2
  41084. * (let ((lst (list #(1 2) #(3 4)))) (lst 0 1)) -> 2
  41085. *
  41086. * this can get tricky:
  41087. * ((list (lambda (a) (+ a 1)) (lambda (b) (* b 2))) 1 2) -> 4
  41088. * but what if func takes rest/optional args, etc?
  41089. * ((list (lambda args (car args))) 0 "hi" 0)
  41090. * should this return #\h or "hi"??
  41091. * currently it is "hi" which is consistent with
  41092. * ((lambda args (car args)) "hi" 0)
  41093. * but...
  41094. * ((lambda (arg) arg) "hi" 0)
  41095. * is currently an error (too many arguments)
  41096. * it should be (((lambda (arg) arg) "hi") 0) -> #\h
  41097. *
  41098. * this applies to non-homogeneous cases, so float|int-vectors don't get here
  41099. */
  41100. switch (type(obj))
  41101. {
  41102. case T_VECTOR: /* (#(#(1 2) #(3 4)) 1 1) -> 4 */
  41103. return(vector_ref_1(sc, obj, indices));
  41104. case T_STRING: /* (#("12" "34") 0 1) -> #\2 */
  41105. if (is_null(cdr(indices)))
  41106. {
  41107. if (is_byte_vector(obj)) /* ((vector (byte-vector 1)) 0 0) */
  41108. return(small_int((unsigned int)(character(string_ref_1(sc, obj, car(indices))))));
  41109. return(string_ref_1(sc, obj, car(indices)));
  41110. }
  41111. return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->too_many_arguments_string, obj, indices)));
  41112. case T_PAIR: /* (#((1 2) (3 4)) 1 0) -> 3, (#((1 (2 3))) 0 1 0) -> 2 */
  41113. obj = list_ref_1(sc, obj, car(indices));
  41114. if (is_pair(cdr(indices)))
  41115. return(implicit_index(sc, obj, cdr(indices)));
  41116. return(obj);
  41117. case T_HASH_TABLE: /* ((vector (hash-table '(a . 1) '(b . 2))) 0 'a) -> 1 */
  41118. obj = s7_hash_table_ref(sc, obj, car(indices));
  41119. if (is_pair(cdr(indices)))
  41120. return(implicit_index(sc, obj, cdr(indices)));
  41121. return(obj);
  41122. case T_C_OBJECT:
  41123. return((*(c_object_ref(obj)))(sc, obj, indices));
  41124. case T_LET:
  41125. obj = s7_let_ref(sc, obj, car(indices));
  41126. if (is_pair(cdr(indices)))
  41127. return(implicit_index(sc, obj, cdr(indices)));
  41128. return(obj);
  41129. default: /* (#(a b c) 0 1) -> error, but ((list (lambda (x) x)) 0 "hi") -> "hi" */
  41130. return(g_apply(sc, list_2(sc, obj, indices)));
  41131. }
  41132. }
  41133. /* -------------------------------- s7-version -------------------------------- */
  41134. static s7_pointer g_s7_version(s7_scheme *sc, s7_pointer args)
  41135. {
  41136. #define H_s7_version "(s7-version) returns some string describing the current s7"
  41137. #define Q_s7_version pcl_s
  41138. return(s7_make_string(sc, "s7 " S7_VERSION ", " S7_DATE));
  41139. }
  41140. void s7_quit(s7_scheme *sc)
  41141. {
  41142. sc->longjmp_ok = false;
  41143. pop_input_port(sc);
  41144. stack_reset(sc);
  41145. push_stack(sc, OP_EVAL_DONE, sc->nil, sc->nil);
  41146. }
  41147. /* -------------------------------- exit -------------------------------- */
  41148. static s7_pointer g_emergency_exit(s7_scheme *sc, s7_pointer args)
  41149. {
  41150. #define H_emergency_exit "(emergency-exit obj) exits s7 immediately"
  41151. #define Q_emergency_exit pcl_t
  41152. s7_pointer obj;
  41153. #ifndef EXIT_SUCCESS
  41154. #define EXIT_SUCCESS 0
  41155. #define EXIT_FAILURE 1
  41156. #endif
  41157. if (is_null(args))
  41158. _exit(EXIT_SUCCESS); /* r7rs spec says use _exit here */
  41159. obj = car(args);
  41160. if (obj == sc->F)
  41161. _exit(EXIT_FAILURE);
  41162. if ((obj == sc->T) || (!s7_is_integer(obj)))
  41163. _exit(EXIT_SUCCESS);
  41164. _exit((int)s7_integer(obj));
  41165. return(sc->F);
  41166. }
  41167. static s7_pointer g_exit(s7_scheme *sc, s7_pointer args)
  41168. {
  41169. #define H_exit "(exit obj) exits s7"
  41170. #define Q_exit pcl_t
  41171. s7_quit(sc);
  41172. return(g_emergency_exit(sc, args));
  41173. }
  41174. #if DEBUGGING
  41175. static s7_pointer g_abort(s7_scheme *sc, s7_pointer args) {abort();}
  41176. #endif
  41177. static s7_function all_x_function[OPT_MAX_DEFINED];
  41178. #define is_all_x_op(Op) (all_x_function[Op] != NULL)
  41179. static bool is_all_x_safe(s7_scheme *sc, s7_pointer p)
  41180. {
  41181. return((!is_pair(p)) ||
  41182. ((car(p) == sc->quote_symbol) && (is_pair(cdr(p)))) || /* (if #t (quote . -1)) */
  41183. ((is_optimized(p)) && (is_all_x_op(optimize_op(p)))));
  41184. }
  41185. static int all_x_count(s7_pointer x)
  41186. {
  41187. int count = 0;
  41188. s7_pointer p;
  41189. for (p = cdr(x); is_pair(p); p = cdr(p))
  41190. if ((is_optimized(car(p))) &&
  41191. (is_all_x_op(optimize_op(car(p)))))
  41192. count++;
  41193. return(count);
  41194. }
  41195. /* arg here is the full expression */
  41196. static s7_pointer all_x_else(s7_scheme *sc, s7_pointer arg) {return(sc->T);} /* used in cond_all_x */
  41197. static s7_pointer all_x_c(s7_scheme *sc, s7_pointer arg) {return(arg);}
  41198. static s7_pointer all_x_q(s7_scheme *sc, s7_pointer arg) {return(cadr(arg));}
  41199. static s7_pointer all_x_s(s7_scheme *sc, s7_pointer arg) {return(find_symbol_checked(sc, arg));}
  41200. static s7_pointer all_x_u(s7_scheme *sc, s7_pointer arg) {return(find_symbol_unchecked(sc, arg));}
  41201. static s7_pointer all_x_k(s7_scheme *sc, s7_pointer arg) {return(arg);}
  41202. static s7_pointer all_x_c_c(s7_scheme *sc, s7_pointer arg) {return(c_call(arg)(sc, cdr(arg)));}
  41203. static s7_pointer all_x_c_add1(s7_scheme *sc, s7_pointer arg)
  41204. {
  41205. s7_pointer x;
  41206. x = find_symbol_unchecked(sc, cadr(arg));
  41207. if (is_integer(x))
  41208. return(make_integer(sc, integer(x) + 1));
  41209. return(g_add_s1_1(sc, x, arg));
  41210. }
  41211. static s7_pointer all_x_c_addi(s7_scheme *sc, s7_pointer arg)
  41212. {
  41213. s7_pointer x;
  41214. x = find_symbol_unchecked(sc, cadr(arg));
  41215. if (is_integer(x))
  41216. return(make_integer(sc, integer(x) + integer(caddr(arg))));
  41217. return(g_add_2(sc, set_plist_2(sc, x, caddr(arg))));
  41218. }
  41219. static s7_pointer all_x_c_char_eq(s7_scheme *sc, s7_pointer arg)
  41220. {
  41221. s7_pointer c;
  41222. c = find_symbol_unchecked(sc, cadr(arg));
  41223. if (c == caddr(arg))
  41224. return(sc->T);
  41225. if (s7_is_character(c))
  41226. return(sc->F);
  41227. method_or_bust(sc, c, sc->char_eq_symbol, set_plist_2(sc, c, caddr(arg)), T_CHARACTER, 1);
  41228. }
  41229. static s7_pointer all_x_c_q(s7_scheme *sc, s7_pointer arg)
  41230. {
  41231. set_car(sc->t1_1, cadr(cadr(arg)));
  41232. return(c_call(arg)(sc, sc->t1_1));
  41233. }
  41234. static s7_pointer all_x_c_s(s7_scheme *sc, s7_pointer arg)
  41235. {
  41236. set_car(sc->t1_1, find_symbol_checked(sc, cadr(arg)));
  41237. return(c_call(arg)(sc, sc->t1_1));
  41238. }
  41239. static s7_pointer all_x_c_u(s7_scheme *sc, s7_pointer arg)
  41240. {
  41241. set_car(sc->t1_1, find_symbol_unchecked(sc, cadr(arg)));
  41242. return(c_call(arg)(sc, sc->t1_1));
  41243. }
  41244. static s7_pointer all_x_cdr_s(s7_scheme *sc, s7_pointer arg)
  41245. {
  41246. s7_pointer val;
  41247. val = find_symbol_checked(sc, cadr(arg));
  41248. return((is_pair(val)) ? cdr(val) : g_cdr(sc, set_plist_1(sc, val)));
  41249. }
  41250. static s7_pointer all_x_cdr_u(s7_scheme *sc, s7_pointer arg)
  41251. {
  41252. s7_pointer val;
  41253. val = find_symbol_unchecked(sc, cadr(arg));
  41254. return((is_pair(val)) ? cdr(val) : g_cdr(sc, set_plist_1(sc, val)));
  41255. }
  41256. static s7_pointer all_x_car_s(s7_scheme *sc, s7_pointer arg)
  41257. {
  41258. s7_pointer val;
  41259. val = find_symbol_checked(sc, cadr(arg));
  41260. return((is_pair(val)) ? car(val) : g_car(sc, set_plist_1(sc, val)));
  41261. }
  41262. static s7_pointer all_x_null_s(s7_scheme *sc, s7_pointer arg)
  41263. {
  41264. return(make_boolean(sc, is_null(find_symbol_checked(sc, cadr(arg)))));
  41265. }
  41266. static s7_pointer all_x_c_sc(s7_scheme *sc, s7_pointer arg)
  41267. {
  41268. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg)));
  41269. set_car(sc->t2_2, caddr(arg));
  41270. return(c_call(arg)(sc, sc->t2_1));
  41271. }
  41272. static s7_pointer all_x_c_uc(s7_scheme *sc, s7_pointer arg)
  41273. {
  41274. set_car(sc->t2_1, find_symbol_unchecked(sc, cadr(arg)));
  41275. set_car(sc->t2_2, caddr(arg));
  41276. return(c_call(arg)(sc, sc->t2_1));
  41277. }
  41278. static s7_pointer all_x_c_cs(s7_scheme *sc, s7_pointer arg)
  41279. {
  41280. set_car(sc->t2_2, find_symbol_checked(sc, caddr(arg)));
  41281. set_car(sc->t2_1, cadr(arg));
  41282. return(c_call(arg)(sc, sc->t2_1));
  41283. }
  41284. static s7_pointer all_x_c_ss(s7_scheme *sc, s7_pointer arg)
  41285. {
  41286. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg)));
  41287. set_car(sc->t2_2, find_symbol_checked(sc, caddr(arg)));
  41288. return(c_call(arg)(sc, sc->t2_1));
  41289. }
  41290. static s7_pointer all_x_c_uu(s7_scheme *sc, s7_pointer arg)
  41291. {
  41292. set_car(sc->t2_1, find_symbol_unchecked(sc, cadr(arg)));
  41293. set_car(sc->t2_2, find_symbol_unchecked(sc, caddr(arg)));
  41294. return(c_call(arg)(sc, sc->t2_1));
  41295. }
  41296. static s7_pointer all_x_c_sss(s7_scheme *sc, s7_pointer arg)
  41297. {
  41298. set_car(sc->t3_1, find_symbol_checked(sc, cadr(arg)));
  41299. set_car(sc->t3_2, find_symbol_checked(sc, caddr(arg)));
  41300. set_car(sc->t3_3, find_symbol_checked(sc, cadddr(arg)));
  41301. return(c_call(arg)(sc, sc->t3_1));
  41302. }
  41303. static s7_pointer all_x_c_uuu(s7_scheme *sc, s7_pointer arg)
  41304. {
  41305. set_car(sc->t3_1, find_symbol_unchecked(sc, cadr(arg)));
  41306. set_car(sc->t3_2, find_symbol_unchecked(sc, caddr(arg)));
  41307. set_car(sc->t3_3, find_symbol_unchecked(sc, cadddr(arg)));
  41308. return(c_call(arg)(sc, sc->t3_1));
  41309. }
  41310. static s7_pointer all_x_c_scs(s7_scheme *sc, s7_pointer arg)
  41311. {
  41312. set_car(sc->t3_1, find_symbol_checked(sc, cadr(arg)));
  41313. set_car(sc->t3_3, find_symbol_checked(sc, cadddr(arg)));
  41314. set_car(sc->t3_2, caddr(arg));
  41315. return(c_call(arg)(sc, sc->t3_1));
  41316. }
  41317. static s7_pointer all_x_c_css(s7_scheme *sc, s7_pointer arg)
  41318. {
  41319. set_car(sc->t3_2, find_symbol_checked(sc, caddr(arg)));
  41320. set_car(sc->t3_3, find_symbol_checked(sc, cadddr(arg)));
  41321. set_car(sc->t3_1, cadr(arg));
  41322. return(c_call(arg)(sc, sc->t3_1));
  41323. }
  41324. static s7_pointer all_x_c_csc(s7_scheme *sc, s7_pointer arg)
  41325. {
  41326. set_car(sc->t3_2, find_symbol_checked(sc, caddr(arg)));
  41327. set_car(sc->t3_1, cadr(arg));
  41328. set_car(sc->t3_3, cadddr(arg));
  41329. return(c_call(arg)(sc, sc->t3_1));
  41330. }
  41331. static s7_pointer all_x_c_ssc(s7_scheme *sc, s7_pointer arg)
  41332. {
  41333. set_car(sc->t3_1, find_symbol_checked(sc, cadr(arg)));
  41334. set_car(sc->t3_2, find_symbol_checked(sc, caddr(arg)));
  41335. set_car(sc->t3_3, cadddr(arg));
  41336. return(c_call(arg)(sc, sc->t3_1));
  41337. }
  41338. static s7_pointer all_x_c_sq(s7_scheme *sc, s7_pointer arg)
  41339. {
  41340. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg)));
  41341. set_car(sc->t2_2, cadr(caddr(arg)));
  41342. return(c_call(arg)(sc, sc->t2_1));
  41343. }
  41344. static s7_pointer all_x_c_opcq(s7_scheme *sc, s7_pointer arg)
  41345. {
  41346. s7_pointer largs;
  41347. largs = cadr(arg);
  41348. set_car(sc->t1_1, c_call(largs)(sc, cdr(largs)));
  41349. return(c_call(arg)(sc, sc->t1_1));
  41350. }
  41351. static s7_pointer all_x_c_s_opcq(s7_scheme *sc, s7_pointer arg)
  41352. {
  41353. s7_pointer largs;
  41354. largs = caddr(arg);
  41355. set_car(sc->t2_2, c_call(largs)(sc, cdr(largs)));
  41356. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg)));
  41357. return(c_call(arg)(sc, sc->t2_1));
  41358. }
  41359. static s7_pointer all_x_c_c_opcq(s7_scheme *sc, s7_pointer arg)
  41360. {
  41361. s7_pointer largs;
  41362. largs = caddr(arg);
  41363. set_car(sc->t2_2, c_call(largs)(sc, cdr(largs)));
  41364. set_car(sc->t2_1, cadr(arg));
  41365. return(c_call(arg)(sc, sc->t2_1));
  41366. }
  41367. static s7_pointer all_x_c_opcq_s(s7_scheme *sc, s7_pointer arg)
  41368. {
  41369. s7_pointer largs;
  41370. largs = cadr(arg);
  41371. set_car(sc->t2_1, c_call(largs)(sc, cdr(largs)));
  41372. set_car(sc->t2_2, find_symbol_checked(sc, caddr(arg)));
  41373. return(c_call(arg)(sc, sc->t2_1));
  41374. }
  41375. static s7_pointer all_x_c_opcq_c(s7_scheme *sc, s7_pointer arg)
  41376. {
  41377. s7_pointer largs;
  41378. largs = cadr(arg);
  41379. set_car(sc->t2_1, c_call(largs)(sc, cdr(largs)));
  41380. set_car(sc->t2_2, caddr(arg));
  41381. return(c_call(arg)(sc, sc->t2_1));
  41382. }
  41383. static s7_pointer all_x_c_opcq_opcq(s7_scheme *sc, s7_pointer arg)
  41384. {
  41385. s7_pointer largs;
  41386. largs = cadr(arg);
  41387. set_car(sc->t2_1, c_call(largs)(sc, cdr(largs)));
  41388. largs = caddr(arg);
  41389. set_car(sc->t2_2, c_call(largs)(sc, cdr(largs)));
  41390. return(c_call(arg)(sc, sc->t2_1));
  41391. }
  41392. static s7_pointer all_x_c_opsq(s7_scheme *sc, s7_pointer arg)
  41393. {
  41394. s7_pointer largs;
  41395. largs = cadr(arg);
  41396. set_car(sc->t1_1, find_symbol_checked(sc, cadr(largs)));
  41397. set_car(sc->t1_1, c_call(largs)(sc, sc->t1_1));
  41398. return(c_call(arg)(sc, sc->t1_1));
  41399. }
  41400. static s7_pointer all_x_c_not_opsq(s7_scheme *sc, s7_pointer arg)
  41401. {
  41402. s7_pointer largs;
  41403. largs = cadr(arg);
  41404. set_car(sc->t1_1, find_symbol_checked(sc, cadr(largs)));
  41405. if (c_call(largs)(sc, sc->t1_1) == sc->F)
  41406. return(sc->T);
  41407. return(sc->F);
  41408. }
  41409. static s7_pointer all_x_c_opuq(s7_scheme *sc, s7_pointer arg)
  41410. {
  41411. s7_pointer largs;
  41412. largs = cadr(arg);
  41413. set_car(sc->t1_1, find_symbol_unchecked(sc, cadr(largs)));
  41414. set_car(sc->t1_1, c_call(largs)(sc, sc->t1_1));
  41415. return(c_call(arg)(sc, sc->t1_1));
  41416. }
  41417. static s7_pointer all_x_c_not_opuq(s7_scheme *sc, s7_pointer arg)
  41418. {
  41419. s7_pointer largs;
  41420. largs = cadr(arg);
  41421. set_car(sc->t1_1, find_symbol_unchecked(sc, cadr(largs)));
  41422. if (c_call(largs)(sc, sc->t1_1) == sc->F)
  41423. return(sc->T);
  41424. return(sc->F);
  41425. }
  41426. static s7_pointer all_x_c_opssq(s7_scheme *sc, s7_pointer arg)
  41427. {
  41428. s7_pointer largs;
  41429. largs = cadr(arg);
  41430. set_car(sc->t2_1, find_symbol_checked(sc, cadr(largs)));
  41431. set_car(sc->t2_2, find_symbol_checked(sc, caddr(largs)));
  41432. set_car(sc->t1_1, c_call(largs)(sc, sc->t2_1));
  41433. return(c_call(arg)(sc, sc->t1_1));
  41434. }
  41435. static s7_pointer all_x_c_opuuq(s7_scheme *sc, s7_pointer arg)
  41436. {
  41437. s7_pointer largs;
  41438. largs = cadr(arg);
  41439. set_car(sc->t2_1, find_symbol_unchecked(sc, cadr(largs)));
  41440. set_car(sc->t2_2, find_symbol_unchecked(sc, caddr(largs)));
  41441. set_car(sc->t1_1, c_call(largs)(sc, sc->t2_1));
  41442. return(c_call(arg)(sc, sc->t1_1));
  41443. }
  41444. static s7_pointer all_x_c_opscq(s7_scheme *sc, s7_pointer arg)
  41445. {
  41446. s7_pointer largs;
  41447. largs = cadr(arg);
  41448. set_car(sc->t2_1, find_symbol_checked(sc, cadr(largs)));
  41449. set_car(sc->t2_2, caddr(largs));
  41450. set_car(sc->t1_1, c_call(largs)(sc, sc->t2_1));
  41451. return(c_call(arg)(sc, sc->t1_1));
  41452. }
  41453. static s7_pointer all_x_c_opsqq(s7_scheme *sc, s7_pointer arg)
  41454. {
  41455. s7_pointer largs;
  41456. largs = cadr(arg);
  41457. set_car(sc->t2_1, find_symbol_checked(sc, cadr(largs)));
  41458. set_car(sc->t2_2, cadr(caddr(largs)));
  41459. set_car(sc->t1_1, c_call(largs)(sc, sc->t2_1));
  41460. return(c_call(arg)(sc, sc->t1_1));
  41461. }
  41462. static s7_pointer all_x_c_opssq_s(s7_scheme *sc, s7_pointer arg)
  41463. {
  41464. s7_pointer largs;
  41465. largs = cadr(arg);
  41466. set_car(sc->t2_1, find_symbol_checked(sc, cadr(largs)));
  41467. set_car(sc->t2_2, find_symbol_checked(sc, caddr(largs)));
  41468. set_car(sc->t2_1, c_call(largs)(sc, sc->t2_1));
  41469. set_car(sc->t2_2, find_symbol_checked(sc, caddr(arg)));
  41470. return(c_call(arg)(sc, sc->t2_1));
  41471. }
  41472. static s7_pointer all_x_c_opuuq_u(s7_scheme *sc, s7_pointer arg)
  41473. {
  41474. s7_pointer largs;
  41475. largs = cadr(arg);
  41476. set_car(sc->t2_1, find_symbol_unchecked(sc, cadr(largs)));
  41477. set_car(sc->t2_2, find_symbol_unchecked(sc, caddr(largs)));
  41478. set_car(sc->t2_1, c_call(largs)(sc, sc->t2_1));
  41479. set_car(sc->t2_2, find_symbol_unchecked(sc, caddr(arg)));
  41480. return(c_call(arg)(sc, sc->t2_1));
  41481. }
  41482. static s7_pointer all_x_c_opssq_c(s7_scheme *sc, s7_pointer arg)
  41483. {
  41484. s7_pointer largs;
  41485. largs = cadr(arg);
  41486. set_car(sc->t2_1, find_symbol_checked(sc, cadr(largs)));
  41487. set_car(sc->t2_2, find_symbol_checked(sc, caddr(largs)));
  41488. set_car(sc->t2_1, c_call(largs)(sc, sc->t2_1));
  41489. set_car(sc->t2_2, caddr(arg));
  41490. return(c_call(arg)(sc, sc->t2_1));
  41491. }
  41492. static s7_pointer all_x_c_opsq_s(s7_scheme *sc, s7_pointer arg)
  41493. {
  41494. s7_pointer largs;
  41495. largs = cadr(arg);
  41496. set_car(sc->t1_1, find_symbol_checked(sc, cadr(largs)));
  41497. set_car(sc->t2_1, c_call(largs)(sc, sc->t1_1));
  41498. set_car(sc->t2_2, find_symbol_checked(sc, caddr(arg)));
  41499. return(c_call(arg)(sc, sc->t2_1));
  41500. }
  41501. static s7_pointer all_x_c_opuq_u(s7_scheme *sc, s7_pointer arg)
  41502. {
  41503. s7_pointer largs;
  41504. largs = cadr(arg);
  41505. set_car(sc->t1_1, find_symbol_unchecked(sc, cadr(largs)));
  41506. set_car(sc->t2_1, c_call(largs)(sc, sc->t1_1));
  41507. set_car(sc->t2_2, find_symbol_unchecked(sc, caddr(arg)));
  41508. return(c_call(arg)(sc, sc->t2_1));
  41509. }
  41510. static s7_pointer all_x_c_opsq_c(s7_scheme *sc, s7_pointer arg)
  41511. {
  41512. s7_pointer largs;
  41513. largs = cadr(arg);
  41514. set_car(sc->t1_1, find_symbol_checked(sc, cadr(largs)));
  41515. set_car(sc->t2_1, c_call(largs)(sc, sc->t1_1));
  41516. set_car(sc->t2_2, caddr(arg));
  41517. return(c_call(arg)(sc, sc->t2_1));
  41518. }
  41519. static s7_pointer all_x_c_s_opssq(s7_scheme *sc, s7_pointer arg)
  41520. {
  41521. s7_pointer largs;
  41522. largs = caddr(arg);
  41523. set_car(sc->t2_1, find_symbol_checked(sc, cadr(largs)));
  41524. set_car(sc->t2_2, find_symbol_checked(sc, caddr(largs)));
  41525. set_car(sc->t2_2, c_call(largs)(sc, sc->t2_1));
  41526. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg)));
  41527. return(c_call(arg)(sc, sc->t2_1));
  41528. }
  41529. static s7_pointer all_x_c_u_opuuq(s7_scheme *sc, s7_pointer arg)
  41530. {
  41531. s7_pointer largs;
  41532. largs = caddr(arg);
  41533. set_car(sc->t2_1, find_symbol_unchecked(sc, cadr(largs)));
  41534. set_car(sc->t2_2, find_symbol_unchecked(sc, caddr(largs)));
  41535. set_car(sc->t2_2, c_call(largs)(sc, sc->t2_1));
  41536. set_car(sc->t2_1, find_symbol_unchecked(sc, cadr(arg)));
  41537. return(c_call(arg)(sc, sc->t2_1));
  41538. }
  41539. static s7_pointer all_x_c_s_opsq(s7_scheme *sc, s7_pointer arg)
  41540. {
  41541. s7_pointer largs;
  41542. largs = caddr(arg);
  41543. set_car(sc->t1_1, find_symbol_checked(sc, cadr(largs)));
  41544. set_car(sc->t2_2, c_call(largs)(sc, sc->t1_1));
  41545. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg)));
  41546. return(c_call(arg)(sc, sc->t2_1));
  41547. }
  41548. static s7_pointer all_x_c_u_opuq(s7_scheme *sc, s7_pointer arg)
  41549. {
  41550. s7_pointer largs;
  41551. largs = caddr(arg);
  41552. set_car(sc->t1_1, find_symbol_unchecked(sc, cadr(largs)));
  41553. set_car(sc->t2_2, c_call(largs)(sc, sc->t1_1));
  41554. set_car(sc->t2_1, find_symbol_unchecked(sc, cadr(arg)));
  41555. return(c_call(arg)(sc, sc->t2_1));
  41556. }
  41557. static s7_pointer all_x_c_c_opsq(s7_scheme *sc, s7_pointer arg)
  41558. {
  41559. s7_pointer largs;
  41560. largs = caddr(arg);
  41561. set_car(sc->t1_1, find_symbol_checked(sc, cadr(largs)));
  41562. set_car(sc->t2_2, c_call(largs)(sc, sc->t1_1));
  41563. set_car(sc->t2_1, cadr(arg));
  41564. return(c_call(arg)(sc, sc->t2_1));
  41565. }
  41566. static s7_pointer all_x_c_opsq_opsq(s7_scheme *sc, s7_pointer arg)
  41567. {
  41568. s7_pointer largs;
  41569. largs = cdr(arg);
  41570. set_car(sc->t1_1, find_symbol_checked(sc, cadr(car(largs))));
  41571. sc->temp3 = c_call(car(largs))(sc, sc->t1_1);
  41572. largs = cadr(largs);
  41573. set_car(sc->t1_1, find_symbol_checked(sc, cadr(largs)));
  41574. set_car(sc->t2_2, c_call(largs)(sc, sc->t1_1));
  41575. set_car(sc->t2_1, sc->temp3);
  41576. sc->temp3 = sc->nil;
  41577. return(c_call(arg)(sc, sc->t2_1));
  41578. }
  41579. static s7_pointer all_x_c_opuq_opuq(s7_scheme *sc, s7_pointer arg)
  41580. {
  41581. s7_pointer largs;
  41582. largs = cdr(arg);
  41583. set_car(sc->t1_1, find_symbol_unchecked(sc, cadr(car(largs))));
  41584. sc->temp3 = c_call(car(largs))(sc, sc->t1_1);
  41585. largs = cadr(largs);
  41586. set_car(sc->t1_1, find_symbol_unchecked(sc, cadr(largs)));
  41587. set_car(sc->t2_2, c_call(largs)(sc, sc->t1_1));
  41588. set_car(sc->t2_1, sc->temp3);
  41589. sc->temp3 = sc->nil;
  41590. return(c_call(arg)(sc, sc->t2_1));
  41591. }
  41592. static s7_pointer all_x_c_opssq_opssq(s7_scheme *sc, s7_pointer arg)
  41593. {
  41594. s7_pointer largs;
  41595. largs = cdr(arg);
  41596. set_car(sc->t2_1, find_symbol_checked(sc, cadr(car(largs))));
  41597. set_car(sc->t2_2, find_symbol_checked(sc, caddr(car(largs))));
  41598. sc->temp3 = c_call(car(largs))(sc, sc->t2_1);
  41599. largs = cadr(largs);
  41600. set_car(sc->t2_1, find_symbol_checked(sc, cadr(largs)));
  41601. set_car(sc->t2_2, find_symbol_checked(sc, caddr(largs)));
  41602. set_car(sc->t2_2, c_call(largs)(sc, sc->t2_1));
  41603. set_car(sc->t2_1, sc->temp3);
  41604. sc->temp3 = sc->nil;
  41605. return(c_call(arg)(sc, sc->t2_1));
  41606. }
  41607. static s7_pointer all_x_c_opuuq_opuuq(s7_scheme *sc, s7_pointer arg)
  41608. {
  41609. s7_pointer largs;
  41610. largs = cdr(arg);
  41611. set_car(sc->t2_1, find_symbol_unchecked(sc, cadr(car(largs))));
  41612. set_car(sc->t2_2, find_symbol_unchecked(sc, caddr(car(largs))));
  41613. sc->temp3 = c_call(car(largs))(sc, sc->t2_1);
  41614. largs = cadr(largs);
  41615. set_car(sc->t2_1, find_symbol_unchecked(sc, cadr(largs)));
  41616. set_car(sc->t2_2, find_symbol_unchecked(sc, caddr(largs)));
  41617. set_car(sc->t2_2, c_call(largs)(sc, sc->t2_1));
  41618. set_car(sc->t2_1, sc->temp3);
  41619. sc->temp3 = sc->nil;
  41620. return(c_call(arg)(sc, sc->t2_1));
  41621. }
  41622. static s7_pointer all_x_c_op_opssq_q_c(s7_scheme *sc, s7_pointer code)
  41623. {
  41624. s7_pointer arg;
  41625. arg = cadr(cadr(code));
  41626. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg)));
  41627. set_car(sc->t2_2, find_symbol_checked(sc, caddr(arg)));
  41628. set_car(sc->t1_1, c_call(arg)(sc, sc->t2_1));
  41629. set_car(sc->t2_1, c_call(cadr(code))(sc, sc->t1_1));
  41630. set_car(sc->t2_2, caddr(code));
  41631. return(c_call(code)(sc, sc->t2_1));
  41632. }
  41633. static s7_pointer all_x_c_a(s7_scheme *sc, s7_pointer arg)
  41634. {
  41635. set_car(sc->t1_1, c_call(cdr(arg))(sc, cadr(arg)));
  41636. return(c_call(arg)(sc, sc->t1_1));
  41637. }
  41638. static s7_pointer all_x_c_ssa(s7_scheme *sc, s7_pointer arg)
  41639. {
  41640. sc->temp3 = c_call(cdddr(arg))(sc, cadddr(arg));
  41641. set_car(sc->t3_1, find_symbol_checked(sc, cadr(arg)));
  41642. set_car(sc->t3_2, find_symbol_checked(sc, caddr(arg)));
  41643. set_car(sc->t3_3, sc->temp3);
  41644. sc->temp3 = sc->nil;
  41645. return(c_call(arg)(sc, sc->t3_1));
  41646. }
  41647. static s7_pointer all_x_c_sas(s7_scheme *sc, s7_pointer arg)
  41648. {
  41649. sc->temp3 = c_call(cddr(arg))(sc, caddr(arg));
  41650. set_car(sc->t3_1, find_symbol_checked(sc, cadr(arg)));
  41651. set_car(sc->t3_3, find_symbol_checked(sc, cadddr(arg)));
  41652. set_car(sc->t3_2, sc->temp3);
  41653. sc->temp3 = sc->nil;
  41654. return(c_call(arg)(sc, sc->t3_1));
  41655. }
  41656. static s7_pointer all_x_c_sca(s7_scheme *sc, s7_pointer arg)
  41657. {
  41658. sc->temp3 = c_call(cdddr(arg))(sc, cadddr(arg));
  41659. set_car(sc->t3_1, find_symbol_checked(sc, cadr(arg)));
  41660. set_car(sc->t3_2, caddr(arg));
  41661. set_car(sc->t3_3, sc->temp3);
  41662. sc->temp3 = sc->nil;
  41663. return(c_call(arg)(sc, sc->t3_1));
  41664. }
  41665. static s7_pointer all_x_c_csa(s7_scheme *sc, s7_pointer arg)
  41666. {
  41667. sc->temp3 = c_call(cdddr(arg))(sc, cadddr(arg));
  41668. set_car(sc->t3_1, cadr(arg));
  41669. set_car(sc->t3_2, find_symbol_checked(sc, caddr(arg)));
  41670. set_car(sc->t3_3, sc->temp3);
  41671. sc->temp3 = sc->nil;
  41672. return(c_call(arg)(sc, sc->t3_1));
  41673. }
  41674. static s7_pointer all_x_c_cas(s7_scheme *sc, s7_pointer arg)
  41675. {
  41676. sc->temp3 = c_call(cddr(arg))(sc, caddr(arg));
  41677. set_car(sc->t3_1, cadr(arg));
  41678. set_car(sc->t3_3, find_symbol_checked(sc, cadddr(arg)));
  41679. set_car(sc->t3_2, sc->temp3);
  41680. sc->temp3 = sc->nil;
  41681. return(c_call(arg)(sc, sc->t3_1));
  41682. }
  41683. static void all_x_function_init(void)
  41684. {
  41685. int i;
  41686. for (i = 0; i < OPT_MAX_DEFINED; i++)
  41687. all_x_function[i] = NULL;
  41688. all_x_function[HOP_SAFE_C_C] = all_x_c_c;
  41689. all_x_function[HOP_SAFE_C_Q] = all_x_c_q;
  41690. all_x_function[HOP_SAFE_C_A] = all_x_c_a;
  41691. all_x_function[HOP_SAFE_C_S] = all_x_c_s;
  41692. all_x_function[HOP_SAFE_C_opCq] = all_x_c_opcq;
  41693. all_x_function[HOP_SAFE_C_opSq] = all_x_c_opsq;
  41694. all_x_function[HOP_SAFE_C_opSSq] = all_x_c_opssq;
  41695. all_x_function[HOP_SAFE_C_opSCq] = all_x_c_opscq;
  41696. all_x_function[HOP_SAFE_C_opSQq] = all_x_c_opsqq;
  41697. all_x_function[HOP_SAFE_C_SC] = all_x_c_sc;
  41698. all_x_function[HOP_SAFE_C_CS] = all_x_c_cs;
  41699. all_x_function[HOP_SAFE_C_SQ] = all_x_c_sq;
  41700. all_x_function[HOP_SAFE_C_SS] = all_x_c_ss;
  41701. all_x_function[HOP_SAFE_C_opSq_S] = all_x_c_opsq_s;
  41702. all_x_function[HOP_SAFE_C_opSq_C] = all_x_c_opsq_c;
  41703. all_x_function[HOP_SAFE_C_S_opSq] = all_x_c_s_opsq;
  41704. all_x_function[HOP_SAFE_C_S_opCq] = all_x_c_s_opcq;
  41705. all_x_function[HOP_SAFE_C_opCq_S] = all_x_c_opcq_s;
  41706. all_x_function[HOP_SAFE_C_opCq_C] = all_x_c_opcq_c;
  41707. all_x_function[HOP_SAFE_C_C_opSq] = all_x_c_c_opsq;
  41708. all_x_function[HOP_SAFE_C_C_opCq] = all_x_c_c_opcq;
  41709. all_x_function[HOP_SAFE_C_opSSq_C] = all_x_c_opssq_c;
  41710. all_x_function[HOP_SAFE_C_opSSq_S] = all_x_c_opssq_s;
  41711. all_x_function[HOP_SAFE_C_S_opSSq] = all_x_c_s_opssq;
  41712. all_x_function[HOP_SAFE_C_opSq_opSq] = all_x_c_opsq_opsq;
  41713. all_x_function[HOP_SAFE_C_opCq_opCq] = all_x_c_opcq_opcq;
  41714. all_x_function[HOP_SAFE_C_opSSq_opSSq] = all_x_c_opssq_opssq;
  41715. all_x_function[HOP_SAFE_C_op_opSSq_q_C] = all_x_c_op_opssq_q_c;
  41716. all_x_function[HOP_SAFE_C_CSA] = all_x_c_csa;
  41717. all_x_function[HOP_SAFE_C_CAS] = all_x_c_cas;
  41718. all_x_function[HOP_SAFE_C_SCA] = all_x_c_sca;
  41719. all_x_function[HOP_SAFE_C_SAS] = all_x_c_sas;
  41720. all_x_function[HOP_SAFE_C_SSA] = all_x_c_ssa;
  41721. all_x_function[HOP_SAFE_C_SSC] = all_x_c_ssc;
  41722. all_x_function[HOP_SAFE_C_SSS] = all_x_c_sss;
  41723. all_x_function[HOP_SAFE_C_SCS] = all_x_c_scs;
  41724. all_x_function[HOP_SAFE_C_CSS] = all_x_c_css;
  41725. all_x_function[HOP_SAFE_C_CSC] = all_x_c_csc;
  41726. }
  41727. static s7_function all_x_eval(s7_scheme *sc, s7_pointer arg, s7_pointer e, safe_sym_t *checker)
  41728. {
  41729. /* fprintf(stderr, "all_x_eval: %s %s\n", DISPLAY(arg), DISPLAY(e)); */
  41730. if (is_pair(arg))
  41731. {
  41732. if (is_optimized(arg))
  41733. {
  41734. switch (optimize_op(arg))
  41735. {
  41736. case HOP_SAFE_C_C:
  41737. if ((c_call(arg) == g_add_cs1) &&
  41738. (checker(sc, cadr(arg), e)))
  41739. return(all_x_c_add1);
  41740. if ((c_call(arg) == g_add_si) &&
  41741. (checker(sc, cadr(arg), e)))
  41742. return(all_x_c_addi);
  41743. if ((c_call(arg) == g_char_equal_s_ic) &&
  41744. (checker(sc, cadr(arg), e)))
  41745. return(all_x_c_char_eq);
  41746. return(all_x_c_c);
  41747. case HOP_SAFE_C_S:
  41748. if (car(arg) == sc->cdr_symbol)
  41749. {
  41750. if (checker(sc, cadr(arg), e))
  41751. return(all_x_cdr_u);
  41752. return(all_x_cdr_s);
  41753. }
  41754. if (car(arg) == sc->car_symbol) return(all_x_car_s);
  41755. if (car(arg) == sc->is_null_symbol) return(all_x_null_s);
  41756. if (checker(sc, cadr(arg), e)) /* all we want here is assurance it's not going to be unbound */
  41757. return(all_x_c_u);
  41758. return(all_x_c_s);
  41759. case HOP_SAFE_C_SS:
  41760. if ((checker(sc, cadr(arg), e)) &&
  41761. (checker(sc, caddr(arg), e)))
  41762. return(all_x_c_uu);
  41763. return(all_x_c_ss);
  41764. case HOP_SAFE_C_SSS:
  41765. if ((checker(sc, cadr(arg), e)) &&
  41766. (checker(sc, caddr(arg), e)) &&
  41767. (checker(sc, cadddr(arg), e)))
  41768. return(all_x_c_uuu);
  41769. return(all_x_c_sss);
  41770. case HOP_SAFE_C_SC:
  41771. if (checker(sc, cadr(arg), e))
  41772. return(all_x_c_uc);
  41773. return(all_x_c_sc);
  41774. case HOP_SAFE_C_opSq:
  41775. if (checker(sc, cadr(cadr(arg)), e))
  41776. {
  41777. if (car(arg) == sc->not_symbol)
  41778. return(all_x_c_not_opuq);
  41779. return(all_x_c_opuq);
  41780. }
  41781. if (car(arg) == sc->not_symbol)
  41782. return(all_x_c_not_opsq);
  41783. return(all_x_c_opsq);
  41784. case HOP_SAFE_C_opSq_opSq:
  41785. if ((checker(sc, cadr(cadr(arg)), e)) &&
  41786. (checker(sc, cadr(caddr(arg)), e)))
  41787. return(all_x_c_opuq_opuq);
  41788. return(all_x_c_opsq_opsq);
  41789. case HOP_SAFE_C_opSSq_opSSq:
  41790. if ((checker(sc, cadr(cadr(arg)), e)) &&
  41791. (checker(sc, caddr(cadr(arg)), e)) &&
  41792. (checker(sc, cadr(caddr(arg)), e)) &&
  41793. (checker(sc, caddr(caddr(arg)), e)))
  41794. return(all_x_c_opuuq_opuuq);
  41795. return(all_x_c_opssq_opssq);
  41796. case HOP_SAFE_C_opSSq:
  41797. if ((checker(sc, cadr(cadr(arg)), e)) &&
  41798. (checker(sc, caddr(cadr(arg)), e)))
  41799. return(all_x_c_opuuq);
  41800. return(all_x_c_opssq);
  41801. case HOP_SAFE_C_opSSq_S:
  41802. if ((checker(sc, cadr(cadr(arg)), e)) &&
  41803. (checker(sc, caddr(cadr(arg)), e)) &&
  41804. (checker(sc, caddr(arg), e)))
  41805. return(all_x_c_opuuq_u);
  41806. return(all_x_c_opssq_s);
  41807. case HOP_SAFE_C_S_opSq:
  41808. if ((checker(sc, cadr(arg), e)) &&
  41809. (checker(sc, cadr(caddr(arg)), e)))
  41810. return(all_x_c_u_opuq);
  41811. return(all_x_c_s_opsq);
  41812. case HOP_SAFE_C_S_opSSq:
  41813. if ((checker(sc, cadr(arg), e)) &&
  41814. (checker(sc, cadr(caddr(arg)), e)) &&
  41815. (checker(sc, caddr(caddr(arg)), e)))
  41816. return(all_x_c_u_opuuq);
  41817. return(all_x_c_s_opssq);
  41818. case HOP_SAFE_C_opSq_S:
  41819. if ((checker(sc, cadr(cadr(arg)), e)) &&
  41820. (checker(sc, caddr(arg), e)))
  41821. return(all_x_c_opuq_u);
  41822. return(all_x_c_opsq_s);
  41823. default:
  41824. /* if (!all_x_function[optimize_op(arg)]) fprintf(stderr, "%s: %s\n", opt_names[optimize_op(arg)], DISPLAY(arg)); */
  41825. return(all_x_function[optimize_op(arg)]);
  41826. }
  41827. }
  41828. if (car(arg) == sc->quote_symbol)
  41829. return(all_x_q);
  41830. return(NULL);
  41831. }
  41832. if (is_symbol(arg))
  41833. {
  41834. if (is_keyword(arg))
  41835. return(all_x_k);
  41836. if (checker(sc, arg, e))
  41837. return(all_x_u);
  41838. return(all_x_s);
  41839. }
  41840. return(all_x_c);
  41841. }
  41842. static s7_function cond_all_x_eval(s7_scheme *sc, s7_pointer arg, s7_pointer e)
  41843. {
  41844. if (arg == sc->else_object)
  41845. return(all_x_else);
  41846. return(all_x_eval(sc, arg, e, let_symbol_is_safe));
  41847. }
  41848. /* ---------------------------------------- for-each ---------------------------------------- */
  41849. static s7_pointer make_counter(s7_scheme *sc, s7_pointer iter)
  41850. {
  41851. s7_pointer x;
  41852. new_cell(sc, x, T_COUNTER);
  41853. counter_set_result(x, sc->nil);
  41854. counter_set_list(x, iter); /* iterator -- here it's always either an iterator or a pair */
  41855. counter_set_capture(x, 0); /* will be capture_let_counter */
  41856. counter_set_let(x, sc->nil); /* will be the saved env */
  41857. counter_set_slots(x, sc->nil); /* local env slots before body is evalled */
  41858. return(x);
  41859. }
  41860. static s7_pointer g_for_each(s7_scheme *sc, s7_pointer args)
  41861. {
  41862. #define H_for_each "(for-each proc object . objects) applies proc to each element of the objects traversed in parallel. \
  41863. Each object can be a list, string, vector, hash-table, or any other sequence."
  41864. #define Q_for_each s7_make_circular_signature(sc, 2, 3, sc->T, sc->is_procedure_symbol, sc->is_sequence_symbol)
  41865. s7_pointer p, f;
  41866. int len;
  41867. bool got_nil = false;
  41868. /* fprintf(stderr, "for-each: %s\n", DISPLAY(args)); */
  41869. /* try the normal case first */
  41870. f = car(args); /* the function */
  41871. p = cadr(args);
  41872. if ((is_null(cddr(args))) &&
  41873. (is_pair(p)) &&
  41874. (is_closure(f)) && /* not lambda* that might get confused about arg names */
  41875. (closure_arity_to_int(sc, f) == 1) && /* not a rest arg: not is_pair: (lambda (x . args) arg) */
  41876. (!is_immutable_symbol(car(closure_args(f)))))
  41877. {
  41878. s7_pointer c;
  41879. c = make_counter(sc, p);
  41880. counter_set_result(c, p);
  41881. push_stack(sc, OP_FOR_EACH_2, c, f);
  41882. return(sc->unspecified);
  41883. }
  41884. if (!is_applicable(f))
  41885. method_or_bust_with_type(sc, f, sc->for_each_symbol, args, something_applicable_string, 1);
  41886. for (len = 0, p = cdr(args); is_not_null(p); p = cdr(p), len++)
  41887. {
  41888. if ((!is_sequence(car(p))) && (!is_iterator(car(p))))
  41889. return(simple_wrong_type_argument_with_type(sc, sc->for_each_symbol, car(p), a_sequence_string));
  41890. if (is_null(car(p)))
  41891. got_nil = true;
  41892. }
  41893. if (!s7_is_aritable(sc, f, len))
  41894. {
  41895. static s7_pointer for_each_args_error = NULL;
  41896. if (!for_each_args_error)
  41897. for_each_args_error = s7_make_permanent_string("for-each ~A: ~A args?");
  41898. return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, for_each_args_error, f, small_int(len))));
  41899. }
  41900. if (got_nil) return(sc->unspecified);
  41901. sc->temp3 = args;
  41902. sc->z = sc->nil; /* don't use sc->args here -- it needs GC protection until we get the iterators */
  41903. for (p = cdr(args); is_not_null(p); p = cdr(p))
  41904. {
  41905. s7_pointer iter;
  41906. iter = car(p);
  41907. if (!is_iterator(car(p)))
  41908. iter = s7_make_iterator(sc, iter);
  41909. sc->z = cons(sc, iter, sc->z);
  41910. }
  41911. sc->temp3 = sc->nil;
  41912. sc->x = make_list(sc, len, sc->nil);
  41913. sc->z = safe_reverse_in_place(sc, sc->z);
  41914. sc->z = cons(sc, sc->z, sc->x);
  41915. /* if function is safe c func, do the for-each locally */
  41916. if ((is_safe_procedure(f)) &&
  41917. (is_c_function(f)))
  41918. {
  41919. s7_function func;
  41920. s7_pointer iters;
  41921. func = c_function_call(f);
  41922. push_stack(sc, OP_NO_OP, sc->args, sc->z); /* temporary GC protection */
  41923. if (len == 1)
  41924. {
  41925. s7_pointer x, y;
  41926. x = caar(sc->z);
  41927. y = cdr(sc->z);
  41928. sc->z = sc->nil;
  41929. while (true)
  41930. {
  41931. set_car(y, s7_iterate(sc, x));
  41932. if (iterator_is_at_end(x))
  41933. {
  41934. pop_stack(sc);
  41935. return(sc->unspecified);
  41936. }
  41937. func(sc, y);
  41938. }
  41939. }
  41940. iters = sc->z;
  41941. sc->z = sc->nil;
  41942. while (true)
  41943. {
  41944. s7_pointer x, y;
  41945. for (x = car(iters), y = cdr(iters); is_pair(x); x = cdr(x), y = cdr(y))
  41946. {
  41947. set_car(y, s7_iterate(sc, car(x)));
  41948. if (iterator_is_at_end(car(x)))
  41949. {
  41950. pop_stack(sc);
  41951. return(sc->unspecified);
  41952. }
  41953. }
  41954. func(sc, cdr(iters));
  41955. }
  41956. }
  41957. /* if closure call is straightforward, use OP_FOR_EACH_1 */
  41958. if ((len == 1) &&
  41959. (is_closure(f)) && /* not lambda* that might get confused about arg names */
  41960. (closure_arity_to_int(sc, f) == 1) && /* not a rest arg: not is_pair: (lambda (x . args) arg) */
  41961. (!is_immutable_symbol(car(closure_args(f)))))
  41962. {
  41963. s7_pointer body, expr;
  41964. body = closure_body(f);
  41965. expr = car(body);
  41966. if ((is_null(cdr(body))) &&
  41967. (is_optimized(expr)) &&
  41968. (is_all_x_op(optimize_op(expr))))
  41969. {
  41970. s7_function func;
  41971. s7_pointer slot, iter;
  41972. iter = caar(sc->z);
  41973. sc->z = sc->nil;
  41974. push_stack(sc, OP_NO_OP, iter, f);
  41975. sc->envir = new_frame_in_env(sc, sc->envir);
  41976. slot = make_slot_1(sc, sc->envir, car(closure_args(f)), sc->F);
  41977. func = all_x_eval(sc, expr, sc->envir, let_symbol_is_safe);
  41978. if (func == all_x_c_c)
  41979. {
  41980. func = c_callee(expr);
  41981. expr = cdr(expr);
  41982. }
  41983. while (true)
  41984. {
  41985. slot_set_value(slot, s7_iterate(sc, iter));
  41986. if (iterator_is_at_end(iter))
  41987. {
  41988. pop_stack(sc);
  41989. return(sc->unspecified);
  41990. }
  41991. func(sc, expr);
  41992. }
  41993. }
  41994. push_stack(sc, OP_FOR_EACH_1, make_counter(sc, caar(sc->z)), f);
  41995. sc->z = sc->nil;
  41996. return(sc->unspecified);
  41997. }
  41998. push_stack(sc, OP_FOR_EACH, sc->z, f);
  41999. sc->z = sc->nil;
  42000. return(sc->unspecified);
  42001. }
  42002. /* ---------------------------------------- map ---------------------------------------- */
  42003. static s7_pointer g_map(s7_scheme *sc, s7_pointer args)
  42004. {
  42005. #define H_map "(map proc object . objects) applies proc to a list made up of the next element of each of its arguments, returning \
  42006. a list of the results. Its arguments can be lists, vectors, strings, hash-tables, or any applicable objects."
  42007. #define Q_map s7_make_circular_signature(sc, 2, 3, sc->is_list_symbol, sc->is_procedure_symbol, sc->is_sequence_symbol)
  42008. s7_pointer p, f;
  42009. int len;
  42010. bool got_nil = false;
  42011. f = car(args); /* the function */
  42012. if (!is_applicable(f))
  42013. method_or_bust_with_type(sc, f, sc->map_symbol, args, something_applicable_string, 1);
  42014. for (len = 0, p = cdr(args); is_not_null(p); p = cdr(p), len++)
  42015. {
  42016. if ((!is_sequence(car(p))) && (!is_iterator(car(p))))
  42017. return(simple_wrong_type_argument_with_type(sc, sc->map_symbol, car(p), a_sequence_string));
  42018. if (is_null(car(p)))
  42019. got_nil = true;
  42020. }
  42021. if ((!is_pair(f)) &&
  42022. (!s7_is_aritable(sc, f, len)))
  42023. {
  42024. static s7_pointer map_args_error = NULL;
  42025. if (!map_args_error)
  42026. map_args_error = s7_make_permanent_string("map ~A: ~A args?");
  42027. return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, map_args_error, f, small_int(len))));
  42028. }
  42029. if (got_nil) return(sc->nil);
  42030. if ((f == slot_value(global_slot(sc->values_symbol))) &&
  42031. (is_null(cddr(args))) &&
  42032. (!has_methods(cadr(args))))
  42033. {
  42034. p = object_to_list(sc, cadr(args));
  42035. if (p != cadr(args))
  42036. return(p);
  42037. }
  42038. sc->temp3 = args;
  42039. sc->z = sc->nil; /* don't use sc->args here -- it needs GC protection until we get the iterators */
  42040. for (p = cdr(args); is_not_null(p); p = cdr(p))
  42041. {
  42042. s7_pointer iter;
  42043. iter = car(p);
  42044. if (!is_iterator(car(p)))
  42045. iter = s7_make_iterator(sc, iter);
  42046. sc->z = cons(sc, iter, sc->z);
  42047. }
  42048. sc->z = safe_reverse_in_place(sc, sc->z);
  42049. sc->temp3 = sc->nil;
  42050. /* if function is safe c func, do the map locally */
  42051. if ((is_safe_procedure(f)) &&
  42052. (is_c_function(f)))
  42053. {
  42054. s7_function func;
  42055. s7_pointer val, val1, old_args, iter_list;
  42056. val1 = cons(sc, sc->z, make_list(sc, len, sc->nil));
  42057. iter_list = sc->z;
  42058. old_args = sc->args;
  42059. func = c_function_call(f);
  42060. push_stack(sc, OP_NO_OP, val1, val = cons(sc, sc->nil, sc->code)); /* temporary GC protection: need to protect val1, iter_list, val */
  42061. sc->z = sc->nil;
  42062. while (true)
  42063. {
  42064. s7_pointer x, y, z;
  42065. for (x = iter_list, y = cdr(val1); is_pair(x); x = cdr(x), y = cdr(y))
  42066. {
  42067. set_car(y, s7_iterate(sc, car(x)));
  42068. if (iterator_is_at_end(car(x)))
  42069. {
  42070. pop_stack(sc);
  42071. sc->args = old_args;
  42072. return(safe_reverse_in_place(sc, car(val)));
  42073. }
  42074. }
  42075. z = func(sc, cdr(val1)); /* can this contain multiple-values? */
  42076. if (z != sc->no_value)
  42077. set_car(val, cons(sc, z, car(val)));
  42078. /* to mimic map values handling elsewhere:
  42079. * ((lambda args (format *stderr* "~A~%" (map values args))) (values)): ()
  42080. * ((lambda args (format *stderr* "~A~%" (map values args))) (values #<unspecified>)): #<unspecified> etc
  42081. */
  42082. }
  42083. }
  42084. /* if closure call is straightforward, use OP_MAP_1 */
  42085. if ((len == 1) &&
  42086. (is_closure(f)) && /* not lambda* that might get confused about arg names */
  42087. (closure_arity_to_int(sc, f) == 1) && /* not a rest arg: not is_pair: (lambda (x . args) arg) */
  42088. (!is_immutable_symbol(car(closure_args(f)))))
  42089. {
  42090. s7_pointer body, expr;
  42091. body = closure_body(f);
  42092. expr = car(body);
  42093. if ((is_null(cdr(body))) &&
  42094. (is_optimized(expr)) &&
  42095. (is_all_x_op(optimize_op(expr))))
  42096. {
  42097. s7_function func;
  42098. s7_pointer slot, iter, val, z;
  42099. iter = car(sc->z);
  42100. push_stack(sc, OP_NO_OP, sc->args, val = cons(sc, sc->nil, cons(sc, f, iter))); /* second cons is GC protection */
  42101. sc->envir = new_frame_in_env(sc, sc->envir);
  42102. slot = make_slot_1(sc, sc->envir, car(closure_args(f)), sc->F);
  42103. func = all_x_eval(sc, expr, sc->envir, let_symbol_is_safe);
  42104. sc->z = sc->nil;
  42105. if (func == all_x_c_c)
  42106. {
  42107. func = c_callee(expr);
  42108. expr = cdr(expr);
  42109. }
  42110. while (true)
  42111. {
  42112. slot_set_value(slot, s7_iterate(sc, iter));
  42113. if (iterator_is_at_end(iter))
  42114. {
  42115. pop_stack(sc);
  42116. return(safe_reverse_in_place(sc, car(val)));
  42117. }
  42118. z = func(sc, expr);
  42119. if (z != sc->no_value)
  42120. set_car(val, cons(sc, z, car(val)));
  42121. }
  42122. }
  42123. push_stack(sc, OP_MAP_1, make_counter(sc, car(sc->z)), f);
  42124. sc->z = sc->nil;
  42125. return(sc->nil);
  42126. }
  42127. push_stack(sc, OP_MAP, make_counter(sc, sc->z), f);
  42128. sc->z = sc->nil;
  42129. return(sc->nil);
  42130. }
  42131. /* -------------------------------- multiple-values -------------------------------- */
  42132. static s7_pointer splice_in_values(s7_scheme *sc, s7_pointer args)
  42133. {
  42134. int top;
  42135. s7_pointer x;
  42136. top = s7_stack_top(sc) - 1; /* stack_end - stack_start: if this is negative, we're in big trouble */
  42137. switch (stack_op(sc->stack, top))
  42138. {
  42139. /* the normal case -- splice values into caller's args */
  42140. case OP_EVAL_ARGS1:
  42141. case OP_EVAL_ARGS2:
  42142. case OP_EVAL_ARGS3:
  42143. case OP_EVAL_ARGS4:
  42144. /* code = args yet to eval in order, args = evalled args reversed
  42145. *
  42146. * it's not safe to simply reverse args and tack the current stacked args onto its (new) end,
  42147. * setting stacked args to cdr of reversed-args and returning car because the list (args)
  42148. * can be some variable's value in a macro expansion via ,@ and reversing it in place
  42149. * (all this to avoid consing), clobbers the variable's value.
  42150. */
  42151. for (x = args; is_not_null(cdr(x)); x = cdr(x))
  42152. stack_args(sc->stack, top) = cons(sc, car(x), stack_args(sc->stack, top));
  42153. return(car(x));
  42154. /* in the next set, the main evaluator branches blithely assume no multiple-values,
  42155. * and if it happens anyway, we vector to a different branch here
  42156. */
  42157. case OP_SAFE_C_opSq_P_1:
  42158. vector_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_opSq_P_MV;
  42159. return(args);
  42160. case OP_SAFE_C_SSZ_1:
  42161. case OP_EVAL_ARGS_SSP_1:
  42162. vector_element(sc->stack, top) = (s7_pointer)OP_EVAL_ARGS_SSP_MV;
  42163. return(args);
  42164. case OP_SAFE_C_SZ_1:
  42165. case OP_EVAL_ARGS_P_2:
  42166. vector_element(sc->stack, top) = (s7_pointer)OP_EVAL_ARGS_P_2_MV;
  42167. return(args);
  42168. case OP_EVAL_ARGS_P_3:
  42169. vector_element(sc->stack, top) = (s7_pointer)OP_EVAL_ARGS_P_3_MV;
  42170. return(args);
  42171. case OP_SAFE_C_ZC_1:
  42172. case OP_EVAL_ARGS_P_4:
  42173. vector_element(sc->stack, top) = (s7_pointer)OP_EVAL_ARGS_P_4_MV;
  42174. return(args);
  42175. case OP_C_P_1:
  42176. vector_element(sc->stack, top) = (s7_pointer)OP_C_P_2;
  42177. return(args);
  42178. case OP_SAFE_CLOSURE_P_1:
  42179. case OP_CLOSURE_P_1:
  42180. vector_element(sc->stack, top) = (s7_pointer)OP_CLOSURE_P_2;
  42181. return(args);
  42182. case OP_C_SP_1:
  42183. vector_element(sc->stack, top) = (s7_pointer)OP_C_SP_2;
  42184. return(args);
  42185. case OP_SAFE_C_PP_1:
  42186. vector_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_PP_3;
  42187. return(args);
  42188. case OP_SAFE_C_PP_2:
  42189. vector_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_PP_4;
  42190. return(args);
  42191. case OP_SAFE_C_PP_5:
  42192. vector_element(sc->stack, top) = (s7_pointer)OP_SAFE_C_PP_6;
  42193. return(args);
  42194. case OP_EVAL_ARGS5:
  42195. /* code = previous arg saved, args = ante-previous args reversed
  42196. * we'll take value->code->args and reverse in args5
  42197. * if one value, return it, else
  42198. * put code onto args, splice as above until there are 2 left
  42199. * set code to first and value to last
  42200. */
  42201. if (is_null(args))
  42202. return(sc->unspecified);
  42203. if (is_null(cdr(args)))
  42204. return(car(args));
  42205. stack_args(sc->stack, top) = cons(sc, stack_code(sc->stack, top), stack_args(sc->stack, top));
  42206. for (x = args; is_not_null(cddr(x)); x = cdr(x))
  42207. stack_args(sc->stack, top) = cons(sc, car(x), stack_args(sc->stack, top));
  42208. stack_code(sc->stack, top) = car(x);
  42209. return(cadr(x));
  42210. /* look for errors here rather than glomming up the set! and let code */
  42211. case OP_SET_SAFE:
  42212. case OP_SET1: /* (set! var (values 1 2 3)) */
  42213. set_multiple_value(args);
  42214. eval_error(sc, "can't set! some variable to ~S", args);
  42215. case OP_SET_PAIR_P_1:
  42216. case OP_SET_PAIR_C_P_1:
  42217. set_multiple_value(args);
  42218. eval_error(sc, "too many values to set! ~S", args);
  42219. case OP_LET1: /* (let ((var (values 1 2 3))) ...) */
  42220. case OP_LET_ONE_1:
  42221. case OP_LET_Z_1:
  42222. set_multiple_value(args);
  42223. eval_error_with_caller(sc, "~A: can't bind some variable to ~S", sc->let_symbol, args);
  42224. /* "some variable" is ugly, but the actual name is tricky to find at this point --
  42225. * it's in main_stack_args, but finding the right one is a mess. It's isn't sc->code.
  42226. */
  42227. case OP_LET_STAR1:
  42228. set_multiple_value(args);
  42229. eval_error_with_caller(sc, "~A: can't bind some variable to ~S", sc->let_star_symbol, args);
  42230. case OP_LETREC1:
  42231. case OP_LETREC_STAR1:
  42232. set_multiple_value(args);
  42233. eval_error_with_caller(sc, "~A: can't bind some variable to ~S", (sc->op == OP_LETREC1) ? sc->letrec_symbol : sc->letrec_star_symbol, args);
  42234. /* handle 'and' and 'or' specially */
  42235. case OP_AND1:
  42236. for (x = args; is_not_null(cdr(x)); x = cdr(x))
  42237. if (car(x) == sc->F)
  42238. return(sc->F);
  42239. return(car(x));
  42240. case OP_OR1:
  42241. for (x = args; is_not_null(cdr(x)); x = cdr(x))
  42242. if (car(x) != sc->F)
  42243. return(car(x));
  42244. return(car(x));
  42245. case OP_BARRIER:
  42246. pop_stack(sc);
  42247. return(splice_in_values(sc, args));
  42248. case OP_BEGIN1:
  42249. /* here we have a values call with nothing to splice into. So flush it...
  42250. * otherwise the multiple-values bit gets set in some innocent list and never unset:
  42251. * :(let ((x '((1 2)))) (eval `(apply apply values x)) x)
  42252. * ((values 1 2))
  42253. * other cases: (+ 1 (begin (values 5 6) (values 2 3)) 4) -> 10 -- the (5 6) is dropped
  42254. * (let () (values 1 2 3) 4) but (+ (let () (values 1 2))) -> 3
  42255. */
  42256. return(args);
  42257. case OP_CATCH:
  42258. case OP_CATCH_1:
  42259. case OP_CATCH_2:
  42260. /* (+ (catch #t (lambda () (values 3 4)) (lambda args args))) */
  42261. pop_stack(sc);
  42262. return(splice_in_values(sc, args));
  42263. case OP_EXPANSION:
  42264. /* we get here if a reader-macro (define-expansion) returned multiple values.
  42265. * these need to be read in order into the current reader lists (we'll assume OP_READ_LIST is next in the stack.
  42266. * and that it will be expecting the next arg entry in sc->value).
  42267. */
  42268. pop_stack(sc);
  42269. top -= 4;
  42270. for (x = args; is_not_null(cdr(x)); x = cdr(x))
  42271. stack_args(sc->stack, top) = cons(sc, car(x), stack_args(sc->stack, top));
  42272. return(car(x)); /* sc->value from OP_READ_LIST point of view */
  42273. default:
  42274. break;
  42275. }
  42276. /* let it meander back up the call chain until someone knows where to splice it */
  42277. set_multiple_value(args);
  42278. return(args);
  42279. }
  42280. s7_pointer s7_values(s7_scheme *sc, s7_pointer args)
  42281. {
  42282. #define H_values "(values obj ...) splices its arguments into whatever list holds it (its 'continuation')"
  42283. #define Q_values s7_make_circular_signature(sc, 1, 2, sc->values_symbol, sc->T)
  42284. if (is_null(args)) /* ((lambda () (let ((x 1)) (set! x (boolean? (values)))))) */
  42285. return(sc->no_value);
  42286. /* this was sc->nil until 16-Jun-10,
  42287. * nil is consistent with the implied values call in call/cc (if no args, the continuation function returns ())
  42288. * hmmm...
  42289. * Guile complains ("too few values returned to continuation") in the call/cc case, and
  42290. * (equal? (if #f #f) (* (values))) complains "Zero values returned to single-valued continuation"
  42291. * so perhaps call/cc should also return #<unspecified> -- I don't know what is best.
  42292. *
  42293. * a note in the scheme bboard:
  42294. * This would work in s7:
  42295. * (define (print-concat . args)
  42296. * (if (or (null? args) ; (print-concat)
  42297. * (eq? (car args) (values))) ; (print-concat arg1 ...)
  42298. * (newline)
  42299. * (begin
  42300. * (display (car args))
  42301. * (print-concat (apply values (cdr args))))))
  42302. * but it's a bit ugly. I think (values) should be the same as
  42303. * (apply values ()). It's currently #<unspecified>, mainly for
  42304. * historical reasons (a lot of the code s7 is used with
  42305. * assumes that behavior). If (values) simply vanished,
  42306. * then code like (abs -1 (values)) is not an error.
  42307. */
  42308. if (is_null(cdr(args)))
  42309. return(car(args));
  42310. return(splice_in_values(sc, args));
  42311. }
  42312. #define g_values s7_values
  42313. /* -------------------------------- quasiquote -------------------------------- */
  42314. static s7_pointer g_qq_list(s7_scheme *sc, s7_pointer args)
  42315. {
  42316. #define H_qq_list "({list} ...) returns its arguments in a list (internal to quasiquote)"
  42317. #define Q_qq_list s7_make_circular_signature(sc, 1, 2, sc->is_list_symbol, sc->T)
  42318. s7_pointer x, y, px;
  42319. if (sc->no_values == 0)
  42320. return(args);
  42321. for (x = args; is_pair(x); x = cdr(x))
  42322. if (car(x) == sc->no_value)
  42323. break;
  42324. if (is_null(x))
  42325. return(args);
  42326. /* this is not maximally efficient, but it's not important:
  42327. * we've hit the rare special case where ({apply_values} ())) needs to be ignored
  42328. * in the splicing process (i.e. the arglist acts as if the thing never happened)
  42329. * ({list} ({apply_values} ())) -> (), also ({list} ({apply_values})) -> ()
  42330. */
  42331. px = sc->nil;
  42332. for (x = args, y = args; is_pair(y); y = cdr(y))
  42333. if (car(y) != sc->no_value)
  42334. {
  42335. set_car(x, car(y));
  42336. px = x;
  42337. x = cdr(x);
  42338. }
  42339. if ((is_not_null(y)) &&
  42340. (y != sc->no_value))
  42341. set_cdr(x, cdr(y));
  42342. else
  42343. {
  42344. sc->no_values--;
  42345. if (is_null(px))
  42346. return(sc->nil);
  42347. set_cdr(px, sc->nil);
  42348. }
  42349. return(args);
  42350. }
  42351. static s7_pointer g_apply_values(s7_scheme *sc, s7_pointer args)
  42352. {
  42353. #define H_apply_values "({apply_values} var) applies values to var. This is an internal function."
  42354. #define Q_apply_values pcl_t
  42355. s7_pointer x;
  42356. if (is_null(args))
  42357. {
  42358. sc->no_values++;
  42359. return(sc->no_value);
  42360. }
  42361. if (is_null(cdr(args)))
  42362. x = car(args);
  42363. else x = apply_list_star(sc, args);
  42364. if (!is_proper_list(sc, x))
  42365. return(apply_list_error(sc, args));
  42366. if (is_null(x))
  42367. {
  42368. sc->no_values++;
  42369. return(sc->no_value);
  42370. }
  42371. return(g_values(sc, x));
  42372. }
  42373. /* (apply values ...) replaces (unquote_splicing ...)
  42374. *
  42375. * (define-macro (hi a) `(+ 1 ,a) == (list '+ 1 a)
  42376. * (define-macro (hi a) ``(+ 1 ,,a) == (list list '+ 1 (list quote a)))
  42377. *
  42378. * (define-macro (hi a) `(+ 1 ,@a) == (list '+ 1 (apply values a))
  42379. * (define-macro (hi a) ``(+ 1 ,,@a) == (list list '+ 1 (apply values a))
  42380. *
  42381. * this is not the same as CL's quasiquote; for example:
  42382. * [1]> (let ((a 1) (b 2)) `(,a ,@b))
  42383. * (1 . 2)
  42384. * in s7 this is an error.
  42385. *
  42386. * also in CL the target of ,@ can apparently be a circular list
  42387. */
  42388. static bool is_simple_code(s7_scheme *sc, s7_pointer form)
  42389. {
  42390. s7_pointer tmp;
  42391. for (tmp = form; is_pair(tmp); tmp = cdr(tmp))
  42392. if (is_pair(car(tmp)))
  42393. {
  42394. if ((tmp == car(tmp)) || /* try to protect against #1=(#1) -- do we actually need cyclic_sequences here? */
  42395. (!is_simple_code(sc, car(tmp))))
  42396. return(false);
  42397. }
  42398. else
  42399. {
  42400. if ((car(tmp) == sc->unquote_symbol) ||
  42401. ((is_null(car(tmp))) && (is_null(cdr(tmp)))))
  42402. return(false);
  42403. }
  42404. return(is_null(tmp));
  42405. }
  42406. static s7_pointer g_quasiquote_1(s7_scheme *sc, s7_pointer form)
  42407. {
  42408. #define H_quasiquote "(quasiquote arg) is the same as `arg. If arg is a list, it can contain \
  42409. comma (\"unquote\") and comma-atsign (\"apply values\") to pre-evaluate portions of the list. \
  42410. unquoted expressions are evaluated and plugged into the list, apply-values evaluates the expression \
  42411. and splices the resultant list into the outer list. `(1 ,(+ 1 1) ,@(list 3 4)) -> (1 2 3 4)."
  42412. #define Q_quasiquote pcl_t
  42413. if (!is_pair(form))
  42414. {
  42415. if ((is_symbol(form)) &&
  42416. (!is_keyword(form)))
  42417. return(list_2(sc, sc->quote_symbol, form));
  42418. /* things that evaluate to themselves don't need to be quoted. */
  42419. return(form);
  42420. }
  42421. if (car(form) == sc->unquote_symbol)
  42422. {
  42423. if (is_not_null(cddr(form)))
  42424. eval_error(sc, "unquote: too many arguments, ~S", form);
  42425. return(cadr(form));
  42426. }
  42427. /* it's a list, so return the list with each element handled as above.
  42428. * we try to support dotted lists which makes the code much messier.
  42429. */
  42430. /* if no element of the list is a list or unquote, just return the original quoted */
  42431. if (is_simple_code(sc, form))
  42432. return(list_2(sc, sc->quote_symbol, form));
  42433. {
  42434. int len, i, loc;
  42435. s7_pointer orig, bq, old_scw;
  42436. bool dotted = false;
  42437. len = s7_list_length(sc, form);
  42438. if (len == 0)
  42439. {
  42440. /* a circular form, apparently */
  42441. return(list_2(sc, sc->quote_symbol, form));
  42442. }
  42443. if (len < 0)
  42444. {
  42445. len = -len;
  42446. dotted = true;
  42447. }
  42448. old_scw = sc->w;
  42449. loc = s7_gc_protect(sc, old_scw);
  42450. sc->w = sc->nil;
  42451. for (i = 0; i <= len; i++)
  42452. sc->w = cons(sc, sc->nil, sc->w);
  42453. set_car(sc->w, sc->qq_list_function);
  42454. if (!dotted)
  42455. {
  42456. for (orig = form, bq = cdr(sc->w), i = 0; i < len; i++, orig = cdr(orig), bq = cdr(bq))
  42457. {
  42458. if ((is_pair(cdr(orig))) && /* this was is_pair(orig) which seems to be always the case */
  42459. (cadr(orig) == sc->unquote_symbol))
  42460. {
  42461. /* `(1 . ,(+ 1 1)) -> '(1 unquote (+ 1 1)) -> '(1 . 2)
  42462. * `(1 . ,@'((2 3))) -> (1 unquote ({apply_values} '((2 3)))) -> ({append} ({list} 1) ({apply_values} '((2 3)))) -> '(1 2 3)
  42463. * this used to be `(1 . ,@('(2 3))).
  42464. * This now becomes (1 unquote ({apply_values} ('(2 3)))) -> ({append} ({list} 1) ({apply_values} ('(2 3)))) -> error
  42465. * `(1 . (,@'(2 3))) works in both cases, and `(1 . (,(+ 1 1)))
  42466. */
  42467. set_car(bq, g_quasiquote_1(sc, car(orig)));
  42468. set_cdr(bq, sc->nil);
  42469. sc->w = list_3(sc, sc->qq_append_function, sc->w, caddr(orig));
  42470. break;
  42471. }
  42472. else set_car(bq, g_quasiquote_1(sc, car(orig)));
  42473. }
  42474. }
  42475. else
  42476. {
  42477. /* `(1 2 . 3) */
  42478. len--;
  42479. for (orig = form, bq = cdr(sc->w), i = 0; i < len; i++, orig = cdr(orig), bq = cdr(bq))
  42480. set_car(bq, g_quasiquote_1(sc, car(orig)));
  42481. set_car(bq, g_quasiquote_1(sc, car(orig)));
  42482. sc->w = list_3(sc, sc->qq_append_function, sc->w, g_quasiquote_1(sc, cdr(orig)));
  42483. /* quasiquote might quote a symbol in cdr(orig), so it's not completely pointless */
  42484. }
  42485. bq = sc->w;
  42486. sc->w = old_scw;
  42487. s7_gc_unprotect_at(sc, loc);
  42488. return(bq);
  42489. }
  42490. }
  42491. static s7_pointer g_quasiquote(s7_scheme *sc, s7_pointer args)
  42492. {
  42493. /* this is for explicit quasiquote support, not the backquote stuff in macros */
  42494. return(g_quasiquote_1(sc, car(args)));
  42495. }
  42496. /* ---------------- reader funcs for eval ---------------- */
  42497. static void back_up_stack(s7_scheme *sc)
  42498. {
  42499. opcode_t top_op;
  42500. top_op = stack_op(sc->stack, s7_stack_top(sc) - 1);
  42501. if (top_op == OP_READ_DOT)
  42502. {
  42503. pop_stack(sc);
  42504. top_op = stack_op(sc->stack, s7_stack_top(sc) - 1);
  42505. }
  42506. if ((top_op == OP_READ_VECTOR) ||
  42507. (top_op == OP_READ_BYTE_VECTOR))
  42508. {
  42509. pop_stack(sc);
  42510. top_op = stack_op(sc->stack, s7_stack_top(sc) - 1);
  42511. }
  42512. if (top_op == OP_READ_QUOTE)
  42513. pop_stack(sc);
  42514. }
  42515. static token_t read_sharp(s7_scheme *sc, s7_pointer pt)
  42516. {
  42517. int c;
  42518. /* inchar can return EOF, so it can't be used directly as an index into the digits array */
  42519. c = inchar(pt);
  42520. switch (c)
  42521. {
  42522. case EOF:
  42523. s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "unexpected '#' at end of input")));
  42524. break;
  42525. case '(':
  42526. sc->w = small_int(1);
  42527. return(TOKEN_VECTOR);
  42528. case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
  42529. {
  42530. /* here we can get an overflow: #1231231231231232131D()
  42531. * and we can't shrug it off:
  42532. * :#2147483649123D()
  42533. * ;#nD(...) dimensions argument 1, -2147483647, is out of range (must be 1 or more)
  42534. * but
  42535. * :#2147483649123D()
  42536. * creates a vector with 512 dimensions!
  42537. * ndims in the vector struct is an unsigned int, so we'll complain if it goes over short max for now
  42538. */
  42539. s7_int dims;
  42540. int d, loc = 0;
  42541. sc->strbuf[loc++] = c;
  42542. dims = digits[c];
  42543. while (true)
  42544. {
  42545. s7_int dig;
  42546. d = inchar(pt);
  42547. if (d == EOF)
  42548. s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "unexpected end of input while reading #n...")));
  42549. dig = digits[d];
  42550. if (dig >= 10) break;
  42551. dims = dig + (dims * 10);
  42552. if ((dims <= 0) ||
  42553. (dims > S7_SHORT_MAX))
  42554. s7_error(sc, sc->read_error_symbol, set_elist_2(sc, make_string_wrapper(sc, "overflow while reading #nD: ~A"), make_integer(sc, dims)));
  42555. sc->strbuf[loc++] = d;
  42556. }
  42557. sc->strbuf[loc++] = d;
  42558. if ((d == 'D') || (d == 'd'))
  42559. {
  42560. d = inchar(pt);
  42561. if (d == EOF)
  42562. s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "unexpected end of input while reading #nD...")));
  42563. sc->strbuf[loc++] = d;
  42564. if (d == '(')
  42565. {
  42566. sc->w = make_integer(sc, dims);
  42567. return(TOKEN_VECTOR);
  42568. }
  42569. }
  42570. /* try to back out */
  42571. for (d = loc - 1; d > 0; d--)
  42572. backchar(sc->strbuf[d], pt);
  42573. }
  42574. break;
  42575. case 'u':
  42576. {
  42577. int d;
  42578. d = inchar(pt);
  42579. if (d == EOF)
  42580. s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "unexpected end of input while reading #u...")));
  42581. if (d == '8')
  42582. {
  42583. d = inchar(pt);
  42584. if (d == EOF)
  42585. s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "unexpected end of input while reading #u8...")));
  42586. if (d == '(')
  42587. return(TOKEN_BYTE_VECTOR);
  42588. backchar(d, pt);
  42589. backchar('8', pt);
  42590. }
  42591. else backchar(d, pt);
  42592. }
  42593. break;
  42594. case ':': /* turn #: into : -- this is for compatibility with Guile, sigh.
  42595. * I just noticed that Rick is using this -- I'll just leave it alone.
  42596. * but that means : readers need to handle this case specially.
  42597. * I don't think #! is special anymore -- maybe remove that code?
  42598. */
  42599. sc->strbuf[0] = ':';
  42600. return(TOKEN_ATOM);
  42601. /* block comments in #! ... !# */
  42602. /* this is needed when an input file is treated as a script:
  42603. #!/home/bil/cl/snd
  42604. !#
  42605. (format #t "a test~%")
  42606. (exit)
  42607. * but very often the closing !# is omitted which is too bad
  42608. */
  42609. case '!':
  42610. {
  42611. char last_char;
  42612. s7_pointer reader;
  42613. /* make it possible to override #! handling */
  42614. for (reader = slot_value(sc->sharp_readers); is_pair(reader); reader = cdr(reader))
  42615. if (s7_character(caar(reader)) == '!')
  42616. {
  42617. sc->strbuf[0] = c;
  42618. return(TOKEN_SHARP_CONST); /* next stage notices any errors */
  42619. }
  42620. /* not #! as block comment (for Guile I guess) */
  42621. last_char = ' ';
  42622. while ((c = inchar(pt)) != EOF)
  42623. {
  42624. if ((c == '#') &&
  42625. (last_char == '!'))
  42626. break;
  42627. last_char = c;
  42628. }
  42629. if (c == EOF)
  42630. s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "unexpected end of input while reading #!")));
  42631. return(token(sc));
  42632. }
  42633. /* block comments in #| ... |#
  42634. * since we ignore everything until the |#, internal semicolon comments are ignored,
  42635. * meaning that ;|# is as effective as |#
  42636. */
  42637. case '|':
  42638. {
  42639. if (is_file_port(pt))
  42640. {
  42641. char last_char;
  42642. last_char = ' ';
  42643. while (true)
  42644. {
  42645. c = fgetc(port_file(pt));
  42646. if (c == EOF)
  42647. s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "unexpected end of input while reading #|")));
  42648. if ((c == '#') &&
  42649. (last_char == '|'))
  42650. break;
  42651. last_char = c;
  42652. if (c == '\n')
  42653. port_line_number(pt)++;
  42654. }
  42655. return(token(sc));
  42656. }
  42657. else
  42658. {
  42659. const char *str, *orig_str, *p, *pend;
  42660. orig_str = (const char *)(port_data(pt) + port_position(pt));
  42661. pend = (const char *)(port_data(pt) + port_data_size(pt));
  42662. str = orig_str;
  42663. while (true)
  42664. {
  42665. p = strchr(str, (int)'|');
  42666. if ((!p) || (p >= pend))
  42667. {
  42668. port_position(pt) = port_data_size(pt);
  42669. s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "unexpected end of input while reading #|")));
  42670. }
  42671. if (p[1] == '#')
  42672. break;
  42673. str = (const char *)(p + 1);
  42674. }
  42675. port_position(pt) += (p - orig_str + 2);
  42676. /* now count newline inside the comment */
  42677. str = (const char *)orig_str;
  42678. pend = p;
  42679. while (true)
  42680. {
  42681. p = strchr(str, (int)'\n');
  42682. if ((p) && (p < pend))
  42683. {
  42684. port_line_number(pt)++;
  42685. str = (char *)(p + 1);
  42686. }
  42687. else break;
  42688. }
  42689. return(token(sc));
  42690. }
  42691. }
  42692. }
  42693. sc->strbuf[0] = c;
  42694. return(TOKEN_SHARP_CONST); /* next stage notices any errors */
  42695. }
  42696. static token_t read_comma(s7_scheme *sc, s7_pointer pt)
  42697. {
  42698. int c;
  42699. /* here we probably should check for symbol names that start with "@":
  42700. :(define-macro (hi @foo) `(+ ,@foo 1))
  42701. hi
  42702. :(hi 2)
  42703. ;foo: unbound variable
  42704. but
  42705. :(define-macro (hi .foo) `(+ ,.foo 1))
  42706. hi
  42707. :(hi 2)
  42708. 3
  42709. and ambiguous:
  42710. :(define-macro (hi @foo . foo) `(list ,@foo))
  42711. what about , @foo -- is the space significant? We accept ,@ foo.
  42712. */
  42713. if ((c = inchar(pt)) == '@')
  42714. return(TOKEN_AT_MARK);
  42715. if (c == EOF)
  42716. {
  42717. sc->strbuf[0] = ','; /* was '@' which doesn't make any sense */
  42718. return(TOKEN_COMMA); /* was TOKEN_ATOM, which also doesn't seem sensible */
  42719. }
  42720. backchar(c, pt);
  42721. return(TOKEN_COMMA);
  42722. }
  42723. static token_t read_dot(s7_scheme *sc, s7_pointer pt)
  42724. {
  42725. int c;
  42726. c = inchar(pt);
  42727. if (c != EOF)
  42728. {
  42729. backchar(c, pt);
  42730. if ((!char_ok_in_a_name[c]) && (c != 0))
  42731. return(TOKEN_DOT);
  42732. }
  42733. else
  42734. {
  42735. sc->strbuf[0] = '.';
  42736. return(TOKEN_DOT);
  42737. }
  42738. sc->strbuf[0] = '.';
  42739. return(TOKEN_ATOM); /* i.e. something that can start with a dot like a number */
  42740. }
  42741. static token_t token(s7_scheme *sc)
  42742. {
  42743. int c;
  42744. c = port_read_white_space(sc->input_port)(sc, sc->input_port);
  42745. switch (c)
  42746. {
  42747. case '(': return(TOKEN_LEFT_PAREN);
  42748. case ')': return(TOKEN_RIGHT_PAREN);
  42749. case '.': return(read_dot(sc, sc->input_port));
  42750. case '\'': return(TOKEN_QUOTE);
  42751. case ';': return(port_read_semicolon(sc->input_port)(sc, sc->input_port));
  42752. case '"': return(TOKEN_DOUBLE_QUOTE);
  42753. case '`': return(TOKEN_BACK_QUOTE);
  42754. case ',': return(read_comma(sc, sc->input_port));
  42755. case '#': return(read_sharp(sc, sc->input_port));
  42756. case '\0':
  42757. case EOF: return(TOKEN_EOF);
  42758. default:
  42759. sc->strbuf[0] = c; /* every TOKEN_ATOM return goes to port_read_name, so we save a backchar/inchar shuffle by starting the read here */
  42760. return(TOKEN_ATOM);
  42761. }
  42762. }
  42763. #define NOT_AN_X_CHAR -1
  42764. static int read_x_char(s7_pointer pt)
  42765. {
  42766. /* possible "\xnn" char (write creates these things, so we have to read them)
  42767. * but we could have crazy input like "\x -- with no trailing double quote
  42768. */
  42769. int d1, c;
  42770. c = inchar(pt);
  42771. if (c == EOF)
  42772. return(NOT_AN_X_CHAR);
  42773. d1 = digits[c];
  42774. if (d1 < 16)
  42775. {
  42776. int d2;
  42777. c = inchar(pt);
  42778. if (c == EOF)
  42779. return(NOT_AN_X_CHAR);
  42780. d2 = digits[c];
  42781. if (d2 < 16)
  42782. return(16 * d1 + d2); /* following char can be anything, including a number -- we ignore it */
  42783. /* apparently one digit is also ok */
  42784. backchar(c, pt);
  42785. return(d1);
  42786. }
  42787. return(NOT_AN_X_CHAR);
  42788. }
  42789. static s7_pointer unknown_string_constant(s7_scheme *sc, int c)
  42790. {
  42791. /* check *read-error-hook* */
  42792. if (hook_has_functions(sc->read_error_hook))
  42793. {
  42794. s7_pointer result;
  42795. result = s7_call(sc, sc->read_error_hook, list_2(sc, sc->F, s7_make_character(sc, (unsigned char)c)));
  42796. if (s7_is_character(result))
  42797. return(result);
  42798. }
  42799. return(sc->T);
  42800. }
  42801. static s7_pointer read_string_constant(s7_scheme *sc, s7_pointer pt)
  42802. {
  42803. /* sc->F => error
  42804. * no check needed here for bad input port and so on
  42805. */
  42806. unsigned int i = 0;
  42807. if (is_string_port(pt))
  42808. {
  42809. /* try the most common case first */
  42810. char *s, *start, *end;
  42811. start = (char *)(port_data(pt) + port_position(pt));
  42812. if (*start == '"')
  42813. {
  42814. port_position(pt)++;
  42815. return(make_empty_string(sc, 0, 0));
  42816. }
  42817. end = (char *)(port_data(pt) + port_data_size(pt));
  42818. s = strpbrk(start, "\"\n\\");
  42819. if ((!s) || (s >= end)) /* can this read a huge string constant from a file? */
  42820. {
  42821. if (start == end)
  42822. sc->strbuf[0] = '\0';
  42823. else memcpy((void *)(sc->strbuf), (void *)start, (end - start > 8) ? 8 : (end - start));
  42824. sc->strbuf[8] = '\0';
  42825. return(sc->F);
  42826. }
  42827. if (*s == '"')
  42828. {
  42829. int len;
  42830. len = s - start;
  42831. port_position(pt) += (len + 1);
  42832. return(s7_make_string_with_length(sc, start, len));
  42833. }
  42834. for (; s < end; s++)
  42835. {
  42836. if (*s == '"') /* switch here no faster */
  42837. {
  42838. int len;
  42839. len = s - start;
  42840. port_position(pt) += (len + 1);
  42841. return(s7_make_string_with_length(sc, start, len));
  42842. }
  42843. else
  42844. {
  42845. if (*s == '\\')
  42846. {
  42847. /* all kinds of special cases here (resultant string is not the current string), so drop to loop below (setting "i") */
  42848. unsigned int len;
  42849. len = (unsigned int)(s - start);
  42850. if (len > 0)
  42851. {
  42852. if (len >= sc->strbuf_size)
  42853. resize_strbuf(sc, len);
  42854. /* for (i = 0; i < len; i++) sc->strbuf[i] = port_data(pt)[port_position(pt)++]; */
  42855. memcpy((void *)(sc->strbuf), (void *)(port_data(pt) + port_position(pt)), len);
  42856. port_position(pt) += len;
  42857. }
  42858. i = len;
  42859. break;
  42860. }
  42861. else
  42862. {
  42863. if (*s == '\n')
  42864. port_line_number(pt)++;
  42865. }
  42866. }
  42867. }
  42868. }
  42869. while (true)
  42870. {
  42871. /* splitting this check out and duplicating the loop was slower?!? */
  42872. int c;
  42873. c = port_read_character(pt)(sc, pt);
  42874. switch (c)
  42875. {
  42876. case '\n':
  42877. port_line_number(pt)++;
  42878. sc->strbuf[i++] = c;
  42879. break;
  42880. case EOF:
  42881. sc->strbuf[(i > 8) ? 8 : i] = '\0';
  42882. return(sc->F);
  42883. case '"':
  42884. return(s7_make_string_with_length(sc, sc->strbuf, i));
  42885. case '\\':
  42886. c = inchar(pt);
  42887. if (c == EOF)
  42888. {
  42889. sc->strbuf[(i > 8) ? 8 : i] = '\0';
  42890. return(sc->F);
  42891. }
  42892. if ((c == '\\') || (c == '"') || (c == '|'))
  42893. sc->strbuf[i++] = c;
  42894. else
  42895. {
  42896. if (c == 'n')
  42897. sc->strbuf[i++] = '\n';
  42898. else
  42899. {
  42900. if (c == 't') /* this is for compatibility with other Schemes */
  42901. sc->strbuf[i++] = '\t';
  42902. else
  42903. {
  42904. if (c == 'x')
  42905. {
  42906. c = read_x_char(pt);
  42907. if (c == NOT_AN_X_CHAR)
  42908. {
  42909. s7_pointer result;
  42910. result = unknown_string_constant(sc, c);
  42911. if (s7_is_character(result))
  42912. sc->strbuf[i++] = character(result);
  42913. else return(result);
  42914. }
  42915. sc->strbuf[i++] = (unsigned char)c;
  42916. }
  42917. else
  42918. {
  42919. /* if (!is_white_space(c)) */ /* changed 8-Apr-12 */
  42920. if ((c != '\n') && (c != '\r'))
  42921. {
  42922. s7_pointer result;
  42923. result = unknown_string_constant(sc, c);
  42924. if (s7_is_character(result))
  42925. sc->strbuf[i++] = character(result);
  42926. else return(result);
  42927. }
  42928. /* #f here would give confusing error message "end of input", so return #t=bad backslash.
  42929. * this is not optimal. It's easy to forget that backslash needs to be backslashed.
  42930. *
  42931. * the white_space business half-implements Scheme's \<newline>...<eol>... or \<space>...<eol>...
  42932. * feature -- the characters after \ are flushed if they're all white space and include a newline.
  42933. * (string->number "1\ 2") is 12?? Too bizarre.
  42934. */
  42935. }
  42936. }
  42937. }
  42938. }
  42939. break;
  42940. default:
  42941. sc->strbuf[i++] = c;
  42942. break;
  42943. }
  42944. if (i >= sc->strbuf_size)
  42945. resize_strbuf(sc, i);
  42946. }
  42947. }
  42948. static s7_pointer read_expression(s7_scheme *sc)
  42949. {
  42950. while (true)
  42951. {
  42952. int c;
  42953. switch (sc->tok)
  42954. {
  42955. case TOKEN_EOF:
  42956. return(sc->eof_object);
  42957. case TOKEN_BYTE_VECTOR:
  42958. push_stack_no_code(sc, OP_READ_BYTE_VECTOR, sc->nil);
  42959. sc->tok = TOKEN_LEFT_PAREN;
  42960. break;
  42961. case TOKEN_VECTOR: /* already read #( -- TOKEN_VECTOR is triggered by #( */
  42962. push_stack_no_code(sc, OP_READ_VECTOR, sc->w); /* sc->w is the dimensions */
  42963. /* fall through */
  42964. case TOKEN_LEFT_PAREN:
  42965. sc->tok = token(sc);
  42966. if (sc->tok == TOKEN_RIGHT_PAREN)
  42967. return(sc->nil);
  42968. if (sc->tok == TOKEN_DOT)
  42969. {
  42970. back_up_stack(sc);
  42971. do {c = inchar(sc->input_port);} while ((c != ')') && (c != EOF));
  42972. return(read_error(sc, "stray dot after '('?")); /* (car '( . )) */
  42973. }
  42974. if (sc->tok == TOKEN_EOF)
  42975. return(missing_close_paren_error(sc));
  42976. push_stack_no_code(sc, OP_READ_LIST, sc->nil);
  42977. /* here we need to clear args, but code is ignored */
  42978. check_stack_size(sc);
  42979. break;
  42980. case TOKEN_QUOTE:
  42981. push_stack_no_code(sc, OP_READ_QUOTE, sc->nil);
  42982. sc->tok = token(sc);
  42983. break;
  42984. case TOKEN_BACK_QUOTE:
  42985. sc->tok = token(sc);
  42986. push_stack_no_code(sc, OP_READ_QUASIQUOTE, sc->nil);
  42987. break;
  42988. case TOKEN_COMMA:
  42989. push_stack_no_code(sc, OP_READ_UNQUOTE, sc->nil);
  42990. sc->tok = token(sc);
  42991. switch (sc->tok)
  42992. {
  42993. case TOKEN_EOF:
  42994. pop_stack(sc);
  42995. return(read_error(sc, "stray comma at the end of the input?"));
  42996. case TOKEN_RIGHT_PAREN:
  42997. pop_stack(sc);
  42998. {
  42999. char *str;
  43000. str = current_input_string(sc, sc->input_port);
  43001. if (str)
  43002. {
  43003. char *msg;
  43004. int len;
  43005. msg = (char *)malloc(128 * sizeof(char));
  43006. len = snprintf(msg, 128, "at \"...%s...\", stray comma before ')'?", str);
  43007. free (str);
  43008. return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_uncopied_with_length(sc, msg, len))));
  43009. }
  43010. return(read_error(sc, "stray comma before ')'?")); /* '("a" "b",) */
  43011. }
  43012. default:
  43013. break;
  43014. }
  43015. break;
  43016. case TOKEN_AT_MARK:
  43017. push_stack_no_code(sc, OP_READ_APPLY_VALUES, sc->nil);
  43018. sc->tok = token(sc);
  43019. break;
  43020. case TOKEN_ATOM:
  43021. return(port_read_name(sc->input_port)(sc, sc->input_port));
  43022. /* If reading list (from lparen), this will finally get us to op_read_list */
  43023. case TOKEN_DOUBLE_QUOTE:
  43024. sc->value = read_string_constant(sc, sc->input_port);
  43025. if (sc->value == sc->F) /* can happen if input code ends in the middle of a string */
  43026. return(string_read_error(sc, "end of input encountered while in a string"));
  43027. if (sc->value == sc->T)
  43028. return(read_error(sc, "unknown backslash usage -- perhaps you meant two backslashes?"));
  43029. return(sc->value);
  43030. case TOKEN_SHARP_CONST:
  43031. sc->value = port_read_sharp(sc->input_port)(sc, sc->input_port);
  43032. /* here we need the following character and form
  43033. * strbuf[0] == '#', false above = # case, not an atom
  43034. */
  43035. if (is_null(sc->value))
  43036. {
  43037. return(read_error(sc, "undefined # expression"));
  43038. /* a read error here seems draconian -- this unknown constant doesn't otherwise get in our way
  43039. * but how to alert the caller to the problem without stopping the read?
  43040. */
  43041. }
  43042. return(sc->value);
  43043. case TOKEN_DOT: /* (catch #t (lambda () (+ 1 . . )) (lambda args 'hiho)) */
  43044. back_up_stack(sc);
  43045. do {c = inchar(sc->input_port);} while ((c != ')') && (c != EOF));
  43046. return(read_error(sc, "stray dot in list?")); /* (+ 1 . . ) */
  43047. case TOKEN_RIGHT_PAREN: /* (catch #t (lambda () '(1 2 . )) (lambda args 'hiho)) */
  43048. back_up_stack(sc);
  43049. return(read_error(sc, "unexpected close paren")); /* (+ 1 2)) or (+ 1 . ) */
  43050. }
  43051. }
  43052. /* we never get here */
  43053. return(sc->nil);
  43054. }
  43055. /* ---------------- *unbound-variable-hook* ---------------- */
  43056. static s7_pointer loaded_library(s7_scheme *sc, const char *file)
  43057. {
  43058. s7_pointer p;
  43059. for (p = slot_value(sc->libraries); is_pair(p); p = cdr(p))
  43060. if (local_strcmp(file, string_value(caar(p))))
  43061. return(cdar(p));
  43062. return(sc->nil);
  43063. }
  43064. static s7_pointer find_closure_let(s7_scheme *sc, s7_pointer cur_env)
  43065. {
  43066. s7_pointer e;
  43067. for (e = cur_env; is_let(e); e = outlet(e))
  43068. if (is_function_env(e))
  43069. return(e);
  43070. return(sc->nil);
  43071. }
  43072. static s7_pointer unbound_variable(s7_scheme *sc, s7_pointer sym)
  43073. {
  43074. /* this always occurs in a context where we're trying to find anything, so I'll move a couple of those checks here
  43075. */
  43076. if (has_ref_fallback(sc->envir)) /* an experiment -- see s7test (with-let *db* (+ int (length str))) */
  43077. check_method(sc, sc->envir, sc->let_ref_fallback_symbol, sc->w = list_2(sc, sc->envir, sym));
  43078. /* but if the thing we want to hit this fallback happens to exist at a higher level, oops... */
  43079. if (sym == sc->unquote_symbol)
  43080. eval_error(sc, "unquote (',') occurred outside quasiquote: ~S", current_code(sc));
  43081. if (sym == sc->__func___symbol) /* __func__ is a sort of symbol macro */
  43082. {
  43083. s7_pointer env;
  43084. env = find_closure_let(sc, sc->envir);
  43085. if (is_let(env))
  43086. {
  43087. /* for C-defined things like hooks and dilambda, let_file and let_line are 0 */
  43088. if ((let_file(env) > 0) &&
  43089. (let_file(env) < (s7_int)sc->file_names_top) && /* let_file(env) might be > int */
  43090. (let_line(env) > 0))
  43091. return(list_3(sc, funclet_function(env), sc->file_names[let_file(env)], make_integer(sc, let_line(env))));
  43092. return(funclet_function(env));
  43093. }
  43094. return(sc->undefined);
  43095. }
  43096. if (safe_strcmp(symbol_name(sym), "|#"))
  43097. return(read_error(sc, "unmatched |#"));
  43098. /* check *autoload*, autoload_names, then *unbound-variable-hook*
  43099. */
  43100. if ((sc->autoload_names) ||
  43101. (is_hash_table(sc->autoload_table)) ||
  43102. (hook_has_functions(sc->unbound_variable_hook)))
  43103. {
  43104. s7_pointer result, cur_code, value, code, args, cur_env, x, z;
  43105. /* sc->args and sc->code are pushed on the stack by s7_call, then
  43106. * restored by eval, so they are normally protected, but sc->value and current_code(sc) are
  43107. * not protected (yet). We need current_code(sc) so that the possible eventual error
  43108. * call can tell where the error occurred, and we need sc->value because it might
  43109. * be awaiting addition to sc->args in e.g. OP_EVAL_ARGS5, and then be clobbered
  43110. * by the hook function. (+ 1 asdf) will end up evaluating (+ asdf asdf) if sc->value
  43111. * is not protected. We also need to save/restore sc->envir in case s7_load is called.
  43112. */
  43113. args = sc->args;
  43114. code = sc->code;
  43115. value = sc->value;
  43116. cur_code = current_code(sc);
  43117. cur_env = sc->envir;
  43118. result = sc->undefined;
  43119. x = sc->x;
  43120. z = sc->z;
  43121. sc->temp7 = cons(sc, code, cons(sc, args, cons(sc, value, cons(sc, cur_code, cons(sc, x, cons(sc, z, sc->nil)))))); /* not s7_list (debugger checks) */
  43122. if (!is_pair(cur_code))
  43123. {
  43124. /* isolated typo perhaps -- no pair to hold the position info, so make one.
  43125. * current_code(sc) is GC-protected, so this should be safe.
  43126. */
  43127. cur_code = cons(sc, sym, sc->nil); /* the error will say "(sym)" which is not too misleading */
  43128. pair_set_line(cur_code, remember_location(port_line_number(sc->input_port), port_file_number(sc->input_port)));
  43129. set_has_line_number(cur_code);
  43130. }
  43131. #if (!DISABLE_AUTOLOAD)
  43132. /* check sc->autoload_names */
  43133. if (sc->autoload_names)
  43134. {
  43135. const char *file;
  43136. bool loaded = false;
  43137. file = find_autoload_name(sc, sym, &loaded, true);
  43138. if ((file) && (!loaded))
  43139. {
  43140. s7_pointer e;
  43141. /* if we've already loaded this file, we can get the library (e) from a table [(file lib) ...]
  43142. * here it was possible to get caught in a loop:
  43143. * change file, reload, unbound var seen, check autoload, it says "load file"... (where file does not get added to *libraries*)
  43144. * so the "loaded" arg tries to catch such cases
  43145. */
  43146. e = loaded_library(sc, file);
  43147. if (!is_let(e))
  43148. e = s7_load(sc, file);
  43149. result = s7_symbol_value(sc, sym); /* calls find_symbol, does not trigger unbound_variable search */
  43150. if ((result == sc->undefined) &&
  43151. (is_let(e)))
  43152. {
  43153. result = s7_let_ref(sc, e, sym);
  43154. /* I think to be consistent we should add '(sym . result) to the global env */
  43155. if (result != sc->undefined)
  43156. s7_define(sc, sc->nil, sym, result);
  43157. }
  43158. }
  43159. }
  43160. #endif
  43161. if (result == sc->undefined)
  43162. {
  43163. #if (!DISABLE_AUTOLOAD)
  43164. /* check the *autoload* hash table */
  43165. if (is_hash_table(sc->autoload_table))
  43166. {
  43167. s7_pointer val;
  43168. /* it was possible to get in a loop here: missing paren in x.scm, checks last symbol, sees
  43169. * autoload sym -> x.scm, loads x.scm, missing paren...
  43170. */
  43171. val = s7_hash_table_ref(sc, sc->autoload_table, sym);
  43172. if (is_string(val)) /* val should be a filename. *load-path* is searched if necessary. */
  43173. s7_load(sc, string_value(val));
  43174. else
  43175. {
  43176. if (is_closure(val)) /* val should be a function of one argument, the current (calling) environment */
  43177. s7_call(sc, val, s7_cons(sc, sc->envir, sc->nil));
  43178. }
  43179. result = s7_symbol_value(sc, sym); /* calls find_symbol, does not trigger unbound_variable search */
  43180. }
  43181. #endif
  43182. /* check *unbound-variable-hook* */
  43183. if ((result == sc->undefined) &&
  43184. (hook_has_functions(sc->unbound_variable_hook)))
  43185. {
  43186. /* (let () (set! (hook-functions *unbound-variable-hook*) (list (lambda (v) _asdf_))) _asdf_) */
  43187. s7_pointer old_hook;
  43188. old_hook = sc->unbound_variable_hook;
  43189. set_car(sc->z2_1, old_hook);
  43190. sc->unbound_variable_hook = sc->error_hook; /* avoid the infinite loop mentioned above */
  43191. result = s7_call(sc, old_hook, list_1(sc, sym)); /* not s7_apply_function */
  43192. sc->unbound_variable_hook = old_hook;
  43193. }
  43194. }
  43195. sc->value = _NFre(value);
  43196. set_current_code(sc, cur_code);
  43197. sc->args = args;
  43198. sc->code = code;
  43199. sc->envir = cur_env;
  43200. sc->x = x;
  43201. sc->z = z;
  43202. sc->temp7 = sc->nil;
  43203. if ((result != sc->undefined) &&
  43204. (result != sc->unspecified))
  43205. return(result);
  43206. }
  43207. eval_error(sc, "~A: unbound variable", sym);
  43208. }
  43209. static s7_pointer assign_syntax(s7_scheme *sc, const char *name, opcode_t op, s7_pointer min_args, s7_pointer max_args, const char *doc)
  43210. {
  43211. s7_pointer x, syn;
  43212. unsigned long long int hash;
  43213. unsigned int loc;
  43214. hash = raw_string_hash((const unsigned char *)name, safe_strlen(name));
  43215. loc = hash % SYMBOL_TABLE_SIZE;
  43216. x = new_symbol(sc, name, safe_strlen(name), hash, loc);
  43217. syn = alloc_pointer();
  43218. unheap(syn);
  43219. set_type(syn, T_SYNTAX | T_SYNTACTIC | T_DONT_EVAL_ARGS);
  43220. syntax_opcode(syn) = op;
  43221. syntax_set_symbol(syn, x);
  43222. syntax_min_args(syn) = integer(min_args);
  43223. syntax_max_args(syn) = ((max_args == max_arity) ? -1 : integer(max_args));
  43224. syntax_documentation(syn) = s7_make_permanent_string(doc);
  43225. syntax_rp(syn) = NULL;
  43226. syntax_ip(syn) = NULL;
  43227. syntax_pp(syn) = NULL;
  43228. set_global_slot(x, permanent_slot(x, syn));
  43229. set_initial_slot(x, permanent_slot(x, syn));
  43230. typeflag(x) = SYNTACTIC_TYPE;
  43231. symbol_set_local(x, 0LL, sc->nil);
  43232. symbol_syntax_op(x) = op;
  43233. return(x);
  43234. }
  43235. static s7_pointer assign_internal_syntax(s7_scheme *sc, const char *name, opcode_t op)
  43236. {
  43237. s7_pointer x, str, syn;
  43238. s7_pointer symbol, old_syn;
  43239. symbol = s7_make_symbol(sc, name);
  43240. old_syn = slot_value(global_slot(symbol));
  43241. str = s7_make_permanent_string(name);
  43242. x = alloc_pointer();
  43243. unheap(x);
  43244. set_type(x, T_SYMBOL);
  43245. symbol_set_name_cell(x, str);
  43246. symbol_set_local(x, 0LL, sc->nil);
  43247. symbol_syntax_op(x) = op;
  43248. syn = alloc_pointer();
  43249. heap_location(syn) = heap_location(old_syn);
  43250. set_type(syn, T_SYNTAX | T_SYNTACTIC | T_DONT_EVAL_ARGS);
  43251. syntax_opcode(syn) = op;
  43252. syntax_set_symbol(syn, symbol);
  43253. syntax_min_args(syn) = syntax_min_args(old_syn);
  43254. syntax_max_args(syn) = syntax_max_args(old_syn);
  43255. syntax_documentation(syn) = syntax_documentation(old_syn);
  43256. syntax_rp(syn) = syntax_rp(old_syn);
  43257. syntax_ip(syn) = syntax_ip(old_syn);
  43258. syntax_pp(syn) = syntax_pp(old_syn);
  43259. set_global_slot(x, permanent_slot(x, syn));
  43260. set_initial_slot(x, permanent_slot(x, syn));
  43261. typeflag(x) = SYNTACTIC_TYPE;
  43262. return(x);
  43263. }
  43264. static s7_int c_pair_line_number(s7_scheme *sc, s7_pointer p)
  43265. {
  43266. if (!is_pair(p))
  43267. int_method_or_bust(sc, p, sc->pair_line_number_symbol, set_plist_1(sc, p), T_PAIR, 0);
  43268. if (has_line_number(p))
  43269. {
  43270. unsigned int x;
  43271. x = pair_line(p);
  43272. return(remembered_line_number(x));
  43273. }
  43274. return(0);
  43275. }
  43276. static s7_pointer g_pair_line_number(s7_scheme *sc, s7_pointer args)
  43277. {
  43278. #define H_pair_line_number "(pair-line-number pair) returns the line number at which it read 'pair'"
  43279. #define Q_pair_line_number s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_pair_symbol)
  43280. return(make_integer(sc, c_pair_line_number(sc, car(args))));
  43281. }
  43282. PF_TO_IF(pair_line_number, c_pair_line_number)
  43283. static s7_pointer g_pair_filename(s7_scheme *sc, s7_pointer args)
  43284. {
  43285. #define H_pair_filename "(pair-filename pair) returns the name of the file containing 'pair'"
  43286. #define Q_pair_filename s7_make_signature(sc, 2, sc->is_string_symbol, sc->is_pair_symbol)
  43287. s7_pointer p;
  43288. p = car(args);
  43289. if (!is_pair(p))
  43290. {
  43291. check_method(sc, p, sc->pair_filename_symbol, args);
  43292. return(simple_wrong_type_argument(sc, sc->pair_filename_symbol, p, T_PAIR));
  43293. }
  43294. if (has_line_number(p))
  43295. {
  43296. int x;
  43297. x = pair_line(p);
  43298. return(remembered_file_name(x));
  43299. }
  43300. return(sc->F);
  43301. }
  43302. static s7_pointer lambda_star_argument_set_value(s7_scheme *sc, s7_pointer sym, s7_pointer val)
  43303. {
  43304. s7_pointer x;
  43305. for (x = let_slots(sc->envir) /* presumably the arglist */; is_slot(x); x = next_slot(x))
  43306. if (slot_symbol(x) == sym)
  43307. {
  43308. /* x is our binding (symbol . value) */
  43309. if (is_not_checked_slot(x))
  43310. set_checked_slot(x); /* this is a special use of this bit, I think */
  43311. else return(s7_error(sc, sc->wrong_type_arg_symbol,
  43312. set_elist_4(sc, make_string_wrapper(sc, "~A: parameter set twice, ~S in ~S"), closure_name(sc, sc->code), sym, sc->args)));
  43313. slot_set_value(x, val);
  43314. return(val);
  43315. }
  43316. return(sc->no_value);
  43317. }
  43318. static s7_pointer lambda_star_set_args(s7_scheme *sc)
  43319. {
  43320. /* sc->code is a closure: ((args body) envir)
  43321. * (define* (hi a (b 1)) (+ a b))
  43322. * (procedure-source hi) -> (lambda* (a (b 1)) (+ a b))
  43323. *
  43324. * so rather than spinning through the args binding names to values in the
  43325. * procedure's new environment (as in the usual closure case above),
  43326. * we scan the current args, and match against the
  43327. * template in the car of the closure, binding as we go.
  43328. *
  43329. * for each actual arg, if it's not a keyword that matches a member of the
  43330. * template, bind it to its current (place-wise) arg, else bind it to
  43331. * that arg. If it's :rest bind the next arg to the trailing args at this point.
  43332. * All args can be accessed by their name as a keyword.
  43333. *
  43334. * all args are optional, any arg with no default value defaults to #f.
  43335. * but the rest arg should default to ().
  43336. * I later decided to add two warnings: if a parameter is set twice and if
  43337. * an unknown keyword is seen in a keyword position and there is no rest arg.
  43338. */
  43339. bool allow_other_keys;
  43340. s7_pointer lx, cx, zx;
  43341. /* get the current args, re-setting args that have explicit values */
  43342. cx = closure_args(sc->code);
  43343. allow_other_keys = ((is_pair(cx)) && (allows_other_keys(cx)));
  43344. lx = sc->args;
  43345. zx = sc->nil;
  43346. while ((is_pair(cx)) &&
  43347. (is_pair(lx)))
  43348. {
  43349. if (car(cx) == sc->key_rest_symbol) /* the rest arg */
  43350. {
  43351. /* next arg is bound to trailing args from this point as a list */
  43352. zx = sc->key_rest_symbol;
  43353. cx = cdr(cx);
  43354. lambda_star_argument_set_value(sc, car(cx), lx); /* default arg not allowed here (see check_lambda_star_args) */
  43355. lx = cdr(lx);
  43356. cx = cdr(cx);
  43357. }
  43358. else
  43359. {
  43360. /* mock-symbols introduce an ambiguity here; if the object's value is a keyword, is that
  43361. * intended to be used as an argument name or value?
  43362. */
  43363. s7_pointer car_lx;
  43364. car_lx = car(lx);
  43365. if (has_methods(car_lx))
  43366. car_lx = check_values(sc, car_lx, lx);
  43367. if ((is_pair(cdr(lx))) &&
  43368. (is_keyword(car_lx)))
  43369. {
  43370. /* char *name; */ /* found a keyword, check the lambda args via the corresponding symbol */
  43371. s7_pointer sym;
  43372. sym = keyword_symbol(car_lx);
  43373. if (lambda_star_argument_set_value(sc, sym, car(cdr(lx))) == sc->no_value)
  43374. {
  43375. /* if default value is a key, go ahead and use this value.
  43376. * (define* (f (a :b)) a) (f :c)
  43377. * this has become much trickier than I anticipated...
  43378. */
  43379. if (allow_other_keys)
  43380. {
  43381. /* in CL: (defun hi (&key (a 1) &allow-other-keys) a) (hi :b :a :a 3) -> 3
  43382. * in s7: (define* (hi (a 1) :allow-other-keys) a) (hi :b :a :a 3) -> 3
  43383. */
  43384. lx = cddr(lx);
  43385. continue;
  43386. }
  43387. else
  43388. {
  43389. if ((is_pair(car(cx))) &&
  43390. (is_keyword(cadar(cx))))
  43391. {
  43392. /* cx is the closure args list, not the copy of it in the curlet */
  43393. s7_pointer x;
  43394. x = find_symbol(sc, caar(cx));
  43395. if (is_slot(x))
  43396. {
  43397. if (is_not_checked_slot(x))
  43398. {
  43399. set_checked_slot(x);
  43400. slot_set_value(x, car(lx));
  43401. }
  43402. else
  43403. {
  43404. /* this case is not caught yet: ((lambda* (a b :allow-other-keys ) a) :b 1 :c :a :a ) */
  43405. return(s7_error(sc, sc->wrong_type_arg_symbol,
  43406. set_elist_4(sc, make_string_wrapper(sc, "~A: parameter set twice, ~S in ~S"),
  43407. closure_name(sc, sc->code), lx, sc->args)));
  43408. }
  43409. }
  43410. else
  43411. {
  43412. return(s7_error(sc, sc->wrong_type_arg_symbol,
  43413. set_elist_4(sc, make_string_wrapper(sc, "~A: unknown key: ~S in ~S"),
  43414. closure_name(sc, sc->code), lx, sc->args)));
  43415. }
  43416. /* (define* (f a (b :c)) b) (f :b 1 :d) */
  43417. }
  43418. else
  43419. {
  43420. return(s7_error(sc, sc->wrong_type_arg_symbol,
  43421. set_elist_4(sc, make_string_wrapper(sc, "~A: unknown key: ~S in ~S"),
  43422. closure_name(sc, sc->code), lx, sc->args)));
  43423. }
  43424. }
  43425. }
  43426. lx = cdr(lx);
  43427. if (is_pair(lx)) lx = cdr(lx);
  43428. }
  43429. else /* not a key/value pair */
  43430. {
  43431. /* this is always a positional (i.e. direct) change, but the closure_args are in the
  43432. * definition order whereas currently the environment slots are in reverse order.
  43433. */
  43434. if (is_pair(car(cx)))
  43435. lambda_star_argument_set_value(sc, caar(cx), car(lx));
  43436. else lambda_star_argument_set_value(sc, car(cx), car(lx));
  43437. lx = cdr(lx);
  43438. }
  43439. cx = cdr(cx);
  43440. }
  43441. }
  43442. /* (let () (define* (hi (a 1) :allow-other-keys) a) (hi :a 2 32)) */
  43443. /* (let () (define* (f (a :b)) a) (list (f) (f 1) (f :c) (f :a :c) (f :a 1) (f))) */
  43444. /* check for trailing args with no :rest arg */
  43445. if (is_not_null(lx))
  43446. {
  43447. if ((is_not_null(cx)) ||
  43448. (zx == sc->key_rest_symbol))
  43449. {
  43450. if (is_symbol(cx))
  43451. make_slot_1(sc, sc->envir, cx, lx);
  43452. }
  43453. else
  43454. {
  43455. if (!allow_other_keys) /* ((lambda* (a) a) :a 1 2) */
  43456. return(s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->too_many_arguments_string, closure_name(sc, sc->code), sc->args)));
  43457. else
  43458. {
  43459. /* check trailing args for repeated keys or keys with no values or values with no keys */
  43460. while (is_pair(lx))
  43461. {
  43462. if ((!is_keyword(car(lx))) || /* ((lambda* (a :allow-other-keys) a) :a 1 :b 2 3) */
  43463. (!is_pair(cdr(lx)))) /* ((lambda* (a :allow-other-keys) a) :a 1 :b) */
  43464. return(s7_error(sc, sc->wrong_type_arg_symbol,
  43465. set_elist_3(sc, make_string_wrapper(sc, "~A: not a key/value pair: ~S"), closure_name(sc, sc->code), lx)));
  43466. /* errors not caught?
  43467. * ((lambda* (a :allow-other-keys) a) :a 1 :a 2)
  43468. * ((lambda* (:allow-other-keys ) #f) :b :a :a :b)
  43469. */
  43470. lx = cddr(lx);
  43471. }
  43472. }
  43473. }
  43474. }
  43475. return(sc->nil);
  43476. }
  43477. static s7_pointer is_pair_car, is_pair_cdr, is_pair_cadr;
  43478. static s7_pointer g_is_pair_car(s7_scheme *sc, s7_pointer args)
  43479. {
  43480. s7_pointer val;
  43481. val = find_symbol_checked(sc, cadar(args));
  43482. if (!is_pair(val)) /* (define (tst) (let ((a 123)) (pair? (car a)))) */
  43483. return(g_is_pair(sc, list_1(sc, g_car(sc, set_plist_1(sc, val)))));
  43484. return(make_boolean(sc, is_pair(car(val))));
  43485. }
  43486. static s7_pointer g_is_pair_cdr(s7_scheme *sc, s7_pointer args)
  43487. {
  43488. s7_pointer val;
  43489. val = find_symbol_checked(sc, cadar(args));
  43490. if (!is_pair(val))
  43491. return(g_is_pair(sc, list_1(sc, g_cdr(sc, set_plist_1(sc, val)))));
  43492. return(make_boolean(sc, is_pair(cdr(val))));
  43493. }
  43494. static s7_pointer g_is_pair_cadr(s7_scheme *sc, s7_pointer args)
  43495. {
  43496. s7_pointer val;
  43497. val = find_symbol_checked(sc, cadar(args));
  43498. if (!is_pair(val))
  43499. return(g_is_pair(sc, list_1(sc, g_cadr(sc, set_plist_1(sc, val)))));
  43500. return(make_boolean(sc, is_pair(cadr(val))));
  43501. }
  43502. static s7_pointer is_pair_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43503. {
  43504. if ((is_optimized(cadr(expr))) &&
  43505. (optimize_op(cadr(expr)) == HOP_SAFE_C_S))
  43506. {
  43507. s7_function g;
  43508. g = c_callee(cadr(expr));
  43509. if (g == g_car)
  43510. {
  43511. set_optimize_op(expr, HOP_SAFE_C_C);
  43512. return(is_pair_car);
  43513. }
  43514. if (g == g_cdr)
  43515. {
  43516. set_optimize_op(expr, HOP_SAFE_C_C);
  43517. return(is_pair_cdr);
  43518. }
  43519. if (g == g_cadr)
  43520. {
  43521. set_optimize_op(expr, HOP_SAFE_C_C);
  43522. return(is_pair_cadr);
  43523. }
  43524. }
  43525. return(f);
  43526. }
  43527. static s7_pointer is_null_cdr;
  43528. static s7_pointer g_is_null_cdr(s7_scheme *sc, s7_pointer args)
  43529. {
  43530. s7_pointer val;
  43531. val = find_symbol_checked(sc, cadar(args));
  43532. if (!is_pair(val))
  43533. return(g_is_null(sc, list_1(sc, g_cdr(sc, set_plist_1(sc, val)))));
  43534. return(make_boolean(sc, is_null(cdr(val))));
  43535. }
  43536. static s7_pointer is_null_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43537. {
  43538. if (is_h_safe_c_s(cadr(expr)))
  43539. {
  43540. s7_function g;
  43541. g = c_callee(cadr(expr));
  43542. if (g == g_cdr)
  43543. {
  43544. set_optimize_op(expr, HOP_SAFE_C_C);
  43545. return(is_null_cdr);
  43546. }
  43547. }
  43548. return(f);
  43549. }
  43550. static s7_pointer format_allg, format_allg_no_column, format_just_newline;
  43551. static s7_pointer g_format_allg(s7_scheme *sc, s7_pointer args)
  43552. {
  43553. return(g_format_1(sc, args));
  43554. }
  43555. static s7_pointer g_format_just_newline(s7_scheme *sc, s7_pointer args)
  43556. {
  43557. s7_pointer pt, str;
  43558. pt = car(args);
  43559. str = cadr(args);
  43560. if (pt == sc->F)
  43561. return(s7_make_string_with_length(sc, string_value(str), string_length(str)));
  43562. if (pt == sc->T)
  43563. {
  43564. if (sc->output_port != sc->F)
  43565. port_write_string(sc->output_port)(sc, string_value(str), string_length(str), sc->output_port);
  43566. return(s7_make_string_with_length(sc, string_value(str), string_length(str)));
  43567. }
  43568. if ((!is_output_port(pt)) ||
  43569. (port_is_closed(pt)))
  43570. method_or_bust_with_type(sc, pt, sc->format_symbol, args, a_format_port_string, 1);
  43571. port_write_string(pt)(sc, string_value(str), string_length(str), pt);
  43572. return(sc->F);
  43573. }
  43574. static s7_pointer g_format_allg_no_column(s7_scheme *sc, s7_pointer args)
  43575. {
  43576. s7_pointer pt, str;
  43577. pt = car(args);
  43578. if (is_null(pt)) pt = sc->output_port;
  43579. if (!((s7_is_boolean(pt)) ||
  43580. ((is_output_port(pt)) && /* (current-output-port) or call-with-open-file arg, etc */
  43581. (!port_is_closed(pt)))))
  43582. method_or_bust_with_type(sc, pt, sc->format_symbol, args, a_format_port_string, 1);
  43583. str = cadr(args);
  43584. sc->format_column = 0;
  43585. return(format_to_port_1(sc, (pt == sc->T) ? sc->output_port : pt,
  43586. string_value(str), cddr(args), NULL,
  43587. !is_output_port(pt), /* i.e. is boolean port so we're returning a string */
  43588. false, /* we checked in advance that it is not columnized */
  43589. string_length(str),
  43590. str));
  43591. }
  43592. static s7_pointer format_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43593. {
  43594. s7_pointer port, str_arg;
  43595. port = cadr(expr);
  43596. str_arg = caddr(expr);
  43597. if ((args > 1) &&
  43598. (!is_string(port)) &&
  43599. (is_string(str_arg)))
  43600. {
  43601. if (args == 2)
  43602. {
  43603. int len;
  43604. char *orig;
  43605. const char *p;
  43606. orig = string_value(str_arg);
  43607. p = strchr((const char *)orig, (int)'~');
  43608. if (!p)
  43609. {
  43610. if (s7_is_boolean(port))
  43611. set_optimize_op(expr, HOP_SAFE_C_C);
  43612. return(format_just_newline); /* "just_newline" actually just outputs the control string -- see fixup below */
  43613. }
  43614. len = string_length(str_arg);
  43615. if ((len > 1) &&
  43616. (orig[len - 1] == '%') &&
  43617. ((p - orig) == len - 2))
  43618. {
  43619. orig[len - 2] = '\n';
  43620. orig[len - 1] = '\0';
  43621. string_length(str_arg) = len - 1;
  43622. if (s7_is_boolean(port))
  43623. set_optimize_op(expr, HOP_SAFE_C_C);
  43624. return(format_just_newline);
  43625. }
  43626. }
  43627. /* this used to worry about optimized expr and particular cases -- why? I can't find a broken case */
  43628. if (!is_columnizing(string_value(str_arg)))
  43629. return(format_allg_no_column);
  43630. return(format_allg);
  43631. }
  43632. return(f);
  43633. }
  43634. static s7_pointer is_eq_car, is_eq_car_q, is_eq_caar_q;
  43635. static s7_pointer g_is_eq_car(s7_scheme *sc, s7_pointer args)
  43636. {
  43637. s7_pointer lst, val;
  43638. lst = find_symbol_checked(sc, cadar(args));
  43639. val = find_symbol_checked(sc, cadr(args));
  43640. if (!is_pair(lst))
  43641. return(g_is_eq(sc, set_plist_2(sc, g_car(sc, list_1(sc, lst)), val)));
  43642. return(make_boolean(sc, car(lst) == val));
  43643. }
  43644. static s7_pointer g_is_eq_car_q(s7_scheme *sc, s7_pointer args)
  43645. {
  43646. s7_pointer lst;
  43647. lst = find_symbol_checked(sc, cadar(args));
  43648. if (!is_pair(lst))
  43649. return(g_is_eq(sc, set_plist_2(sc, g_car(sc, set_plist_1(sc, lst)), cadr(cadr(args)))));
  43650. return(make_boolean(sc, car(lst) == cadr(cadr(args))));
  43651. }
  43652. static s7_pointer g_is_eq_caar_q(s7_scheme *sc, s7_pointer args)
  43653. {
  43654. /* (eq? (caar x) 'y), but x is not guaranteed to be list(list) */
  43655. s7_pointer lst;
  43656. lst = find_symbol_checked(sc, cadar(args));
  43657. if ((!is_pair(lst)) || (!is_pair(car(lst))))
  43658. return(g_is_eq(sc, set_plist_2(sc, g_caar(sc, set_plist_1(sc, lst)), cadr(cadr(args)))));
  43659. return(make_boolean(sc, caar(lst) == cadr(cadr(args))));
  43660. }
  43661. static s7_pointer is_eq_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43662. {
  43663. if (is_h_safe_c_s(cadr(expr)))
  43664. {
  43665. if ((is_symbol(caddr(expr))) &&
  43666. (c_callee(cadr(expr)) == g_car))
  43667. {
  43668. set_optimize_op(expr, HOP_SAFE_C_C);
  43669. return(is_eq_car);
  43670. }
  43671. if ((is_pair(caddr(expr))) &&
  43672. (caaddr(expr) == sc->quote_symbol))
  43673. {
  43674. if (c_callee(cadr(expr)) == g_car)
  43675. {
  43676. set_optimize_op(expr, HOP_SAFE_C_C);
  43677. return(is_eq_car_q);
  43678. }
  43679. if (c_callee(cadr(expr)) == g_caar)
  43680. {
  43681. set_optimize_op(expr, HOP_SAFE_C_C);
  43682. return(is_eq_caar_q);
  43683. }
  43684. }
  43685. }
  43686. return(f);
  43687. }
  43688. /* also not-chooser for all the ? procs, ss case for not equal? etc
  43689. */
  43690. static s7_pointer not_is_pair, not_is_symbol, not_is_null, not_is_list, not_is_number;
  43691. static s7_pointer not_is_char, not_is_string, not_is_zero, not_is_eq_sq, not_is_eq_ss;
  43692. static s7_pointer g_not_is_pair(s7_scheme *sc, s7_pointer args) {check_boolean_not_method(sc, is_pair, sc->is_pair_symbol, args);}
  43693. static s7_pointer g_not_is_null(s7_scheme *sc, s7_pointer args) {check_boolean_not_method(sc, is_null, sc->is_null_symbol, args);}
  43694. static s7_pointer g_not_is_symbol(s7_scheme *sc, s7_pointer args) {check_boolean_not_method(sc, is_symbol, sc->is_symbol_symbol, args);}
  43695. static s7_pointer g_not_is_number(s7_scheme *sc, s7_pointer args) {check_boolean_not_method(sc, s7_is_number, sc->is_number_symbol, args);}
  43696. static s7_pointer g_not_is_char(s7_scheme *sc, s7_pointer args) {check_boolean_not_method(sc, s7_is_character, sc->is_char_symbol, args);}
  43697. static s7_pointer g_not_is_string(s7_scheme *sc, s7_pointer args) {check_boolean_not_method(sc, is_string, sc->is_string_symbol, args);}
  43698. static s7_pointer g_not_is_zero(s7_scheme *sc, s7_pointer args) {check_boolean_not_method(sc, s7_is_zero, sc->is_zero_symbol, args);}
  43699. static s7_pointer g_not_is_list(s7_scheme *sc, s7_pointer args) {check_boolean_not_method(sc, opt_is_list, sc->is_list_symbol, args);}
  43700. /* eq? does not check for methods */
  43701. static s7_pointer g_not_is_eq_sq(s7_scheme *sc, s7_pointer args)
  43702. {
  43703. return(make_boolean(sc, find_symbol_checked(sc, cadr(car(args))) != cadr(caddr(car(args)))));
  43704. }
  43705. static s7_pointer g_not_is_eq_ss(s7_scheme *sc, s7_pointer args)
  43706. {
  43707. return(make_boolean(sc, find_symbol_checked(sc, cadr(car(args))) != find_symbol_checked(sc, caddr(car(args)))));
  43708. }
  43709. /* here the method finder is in either car or cdr */
  43710. static s7_pointer not_is_pair_car;
  43711. static s7_pointer g_not_is_pair_car(s7_scheme *sc, s7_pointer args)
  43712. {
  43713. s7_pointer val;
  43714. val = find_symbol_checked(sc, cadr(cadar(args)));
  43715. if (!is_pair(val))
  43716. return(g_not(sc, list_1(sc, g_is_pair(sc, list_1(sc, g_car(sc, set_plist_1(sc, val)))))));
  43717. return(make_boolean(sc, !is_pair(car(val))));
  43718. }
  43719. static s7_pointer not_c_c;
  43720. static s7_pointer g_not_c_c(s7_scheme *sc, s7_pointer args)
  43721. {
  43722. /* args: ( (null? l) ) */
  43723. return(make_boolean(sc, is_false(sc, c_call(car(args))(sc, cdar(args)))));
  43724. }
  43725. static s7_pointer not_chooser(s7_scheme *sc, s7_pointer g, int args, s7_pointer expr)
  43726. {
  43727. if (is_optimized(cadr(expr))) /* cadr(expr) might be a symbol, for example; is_optimized includes is_pair */
  43728. {
  43729. if (optimize_op(cadr(expr)) == HOP_SAFE_C_S)
  43730. {
  43731. s7_function f;
  43732. f = c_callee(cadr(expr));
  43733. if (f == g_is_pair)
  43734. {
  43735. set_optimize_op(expr, HOP_SAFE_C_C);
  43736. return(not_is_pair);
  43737. }
  43738. if (f == g_is_null)
  43739. {
  43740. set_optimize_op(expr, HOP_SAFE_C_C);
  43741. return(not_is_null);
  43742. }
  43743. if (f == g_is_symbol)
  43744. {
  43745. set_optimize_op(expr, HOP_SAFE_C_C);
  43746. return(not_is_symbol);
  43747. }
  43748. if (f == g_is_list)
  43749. {
  43750. set_optimize_op(expr, HOP_SAFE_C_C);
  43751. return(not_is_list);
  43752. }
  43753. /* g_is_number is c_function_call(slot_value(global_slot(sc->is_number_symbol)))
  43754. * so if this is changed (via openlet??) the latter is perhaps better??
  43755. * but user might have (#_number? e), so we can't change later and catch this.
  43756. */
  43757. if ((f == g_is_number) || (f == g_is_complex))
  43758. {
  43759. set_optimize_op(expr, HOP_SAFE_C_C);
  43760. return(not_is_number);
  43761. }
  43762. if (f == g_is_zero)
  43763. {
  43764. set_optimize_op(expr, HOP_SAFE_C_C);
  43765. return(not_is_zero);
  43766. }
  43767. if (f == g_is_char)
  43768. {
  43769. set_optimize_op(expr, HOP_SAFE_C_C);
  43770. return(not_is_char);
  43771. }
  43772. if (f == g_is_string)
  43773. {
  43774. set_optimize_op(expr, HOP_SAFE_C_C);
  43775. return(not_is_string);
  43776. }
  43777. }
  43778. if ((optimize_op(cadr(expr)) == HOP_SAFE_C_SQ) &&
  43779. (c_callee(cadr(expr)) == g_is_eq))
  43780. {
  43781. set_optimize_op(expr, HOP_SAFE_C_C);
  43782. return(not_is_eq_sq);
  43783. }
  43784. if (optimize_op(cadr(expr)) == HOP_SAFE_C_SS)
  43785. {
  43786. if (c_callee(cadr(expr)) == g_is_eq)
  43787. {
  43788. set_optimize_op(expr, HOP_SAFE_C_C);
  43789. return(not_is_eq_ss);
  43790. }
  43791. }
  43792. if (optimize_op(cadr(expr)) == HOP_SAFE_C_C)
  43793. {
  43794. set_optimize_op(expr, HOP_SAFE_C_C);
  43795. if (c_callee(cadr(expr)) == g_is_pair_car)
  43796. return(not_is_pair_car);
  43797. return(not_c_c);
  43798. }
  43799. }
  43800. return(g);
  43801. }
  43802. static s7_pointer vector_ref_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43803. {
  43804. if (args == 2)
  43805. {
  43806. s7_pointer arg1, arg2;
  43807. arg1 = cadr(expr);
  43808. arg2 = caddr(expr);
  43809. if (is_symbol(arg1))
  43810. {
  43811. if ((s7_is_integer(arg2)) &&
  43812. (s7_integer(arg2) >= 0))
  43813. {
  43814. set_optimize_op(expr, HOP_SAFE_C_C);
  43815. switch (s7_integer(arg2)) /* (might be big int) */
  43816. {
  43817. case 0: return(vector_ref_ic_0);
  43818. case 1: return(vector_ref_ic_1);
  43819. case 2: return(vector_ref_ic_2);
  43820. case 3: return(vector_ref_ic_3);
  43821. default: return(vector_ref_ic);
  43822. }
  43823. }
  43824. if (is_global(arg1))
  43825. {
  43826. if (is_symbol(arg2))
  43827. {
  43828. set_optimize_op(expr, HOP_SAFE_C_C);
  43829. if (is_immutable_symbol(arg1))
  43830. {
  43831. s7_pointer vect;
  43832. vect = slot_value(global_slot(arg1));
  43833. if ((is_normal_vector(vect)) &&
  43834. (vector_rank(vect) == 1))
  43835. {
  43836. set_opt_vector(cdr(expr), vect);
  43837. return(constant_vector_ref_gs);
  43838. }
  43839. }
  43840. return(vector_ref_gs);
  43841. }
  43842. }
  43843. if ((is_pair(arg2)) &&
  43844. (is_safely_optimized(arg2)) &&
  43845. (c_callee(arg2) == g_add_cs1))
  43846. {
  43847. set_optimize_op(expr, HOP_SAFE_C_C);
  43848. return(vector_ref_add1);
  43849. }
  43850. }
  43851. /* vector_ref_sub1 was not worth the code, and few other easily optimized expressions happen here */
  43852. return(vector_ref_2);
  43853. }
  43854. return(f);
  43855. }
  43856. static s7_pointer vector_set_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43857. {
  43858. if (args == 3)
  43859. {
  43860. s7_pointer arg1, arg2, arg3;
  43861. arg1 = cadr(expr);
  43862. arg2 = caddr(expr);
  43863. arg3 = cadddr(expr);
  43864. if (is_symbol(arg1))
  43865. {
  43866. if ((s7_is_integer(arg2)) &&
  43867. (s7_integer(arg2) >= 0) &&
  43868. (is_symbol(arg3)))
  43869. {
  43870. set_optimize_op(expr, HOP_SAFE_C_C);
  43871. return(vector_set_ic);
  43872. }
  43873. if (is_symbol(arg2))
  43874. {
  43875. if ((is_pair(arg3)) &&
  43876. (is_safely_optimized(arg3)))
  43877. {
  43878. if ((c_callee(arg3) == g_vector_ref_2) &&
  43879. (arg1 == cadr(arg3)) &&
  43880. (is_symbol(caddr(arg3))))
  43881. {
  43882. set_optimize_op(expr, HOP_SAFE_C_C);
  43883. return(vector_set_vref);
  43884. }
  43885. if (((c_callee(arg3) == g_add_2) || (c_callee(arg3) == g_subtract_2)) &&
  43886. (is_symbol(caddr(arg3))) &&
  43887. (is_optimized(cadr(arg3))) &&
  43888. (c_callee(cadr(arg3)) == g_vector_ref_2) &&
  43889. (cadr(cadr(arg3)) == arg1))
  43890. {
  43891. set_optimize_op(expr, HOP_SAFE_C_C);
  43892. return(vector_set_vector_ref);
  43893. }
  43894. }
  43895. }
  43896. }
  43897. return(vector_set_3);
  43898. }
  43899. return(f);
  43900. }
  43901. static s7_pointer list_set_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43902. {
  43903. if ((args == 3) &&
  43904. (s7_is_integer(caddr(expr))) &&
  43905. (s7_integer(caddr(expr)) >= 0) &&
  43906. (s7_integer(caddr(expr)) < sc->max_list_length))
  43907. return(list_set_ic);
  43908. return(f);
  43909. }
  43910. static s7_pointer list_ref_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43911. {
  43912. if ((args == 2) &&
  43913. (s7_is_integer(caddr(expr))) &&
  43914. (s7_integer(caddr(expr)) >= 0) &&
  43915. (s7_integer(caddr(expr)) < sc->max_list_length))
  43916. return(list_ref_ic);
  43917. return(f);
  43918. }
  43919. static s7_pointer hash_table_ref_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43920. {
  43921. if (args == 2)
  43922. {
  43923. if ((is_symbol(cadr(expr))) &&
  43924. (is_symbol(caddr(expr))))
  43925. {
  43926. set_optimize_op(expr, HOP_SAFE_C_C);
  43927. return(hash_table_ref_ss);
  43928. }
  43929. if ((is_symbol(cadr(expr))) &&
  43930. (is_h_safe_c_s(caddr(expr))) &&
  43931. (c_callee(caddr(expr)) == g_car))
  43932. {
  43933. set_optimize_op(expr, HOP_SAFE_C_C);
  43934. return(hash_table_ref_car);
  43935. }
  43936. return(hash_table_ref_2);
  43937. }
  43938. return(f);
  43939. }
  43940. #if (!WITH_GMP)
  43941. static s7_pointer modulo_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43942. {
  43943. if ((args == 2) &&
  43944. (is_symbol(cadr(expr))) &&
  43945. (is_integer(caddr(expr))) &&
  43946. (integer(caddr(expr)) > 1))
  43947. {
  43948. set_optimize_op(expr, HOP_SAFE_C_C);
  43949. return(mod_si);
  43950. }
  43951. return(f);
  43952. }
  43953. #endif
  43954. static s7_pointer add_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  43955. {
  43956. /* (+ s f) (+ (* s s) s) (+ s s) (+ s (* s s))
  43957. */
  43958. #if (!WITH_GMP)
  43959. if (args == 2)
  43960. {
  43961. s7_pointer arg1, arg2;
  43962. arg1 = cadr(expr);
  43963. arg2 = caddr(expr);
  43964. if (arg1 == small_int(1))
  43965. return(add_1s);
  43966. if (arg2 == small_int(1))
  43967. {
  43968. if (is_symbol(arg1))
  43969. {
  43970. set_optimize_op(expr, HOP_SAFE_C_C);
  43971. return(add_cs1);
  43972. }
  43973. return(add_s1);
  43974. }
  43975. #if HAVE_OVERFLOW_CHECKS
  43976. if (s7_is_integer(arg2))
  43977. #else
  43978. if ((s7_is_integer(arg2)) &&
  43979. (integer_length(integer(arg2)) < 31))
  43980. #endif
  43981. {
  43982. if (is_symbol(arg1))
  43983. {
  43984. set_optimize_op(expr, HOP_SAFE_C_C);
  43985. return(add_si);
  43986. }
  43987. }
  43988. if ((is_t_real(arg2)) &&
  43989. (is_symbol(arg1)))
  43990. {
  43991. set_optimize_op(expr, HOP_SAFE_C_C);
  43992. return(add_sf);
  43993. }
  43994. if (is_t_real(arg1))
  43995. {
  43996. if (is_symbol(arg2))
  43997. {
  43998. set_optimize_op(expr, HOP_SAFE_C_C);
  43999. return(add_fs);
  44000. }
  44001. if ((is_h_safe_c_c(arg2)) &&
  44002. (c_callee(arg2) == g_multiply_sf))
  44003. {
  44004. set_optimize_op(expr, HOP_SAFE_C_C);
  44005. return(add_f_sf);
  44006. }
  44007. }
  44008. if ((is_optimized(arg1)) &&
  44009. (is_optimized(arg2)))
  44010. {
  44011. if ((optimize_op(arg1) == HOP_SAFE_C_SS) &&
  44012. (optimize_op(arg2) == HOP_SAFE_C_C) &&
  44013. (c_callee(arg1) == g_multiply_2) &&
  44014. (c_callee(arg2) == g_mul_1ss) &&
  44015. (cadr(arg1) == caddr(cadr(arg2))))
  44016. {
  44017. set_optimize_op(expr, HOP_SAFE_C_C);
  44018. set_opt_sym1(cdr(expr), caddr(arg1));
  44019. set_opt_sym2(cdr(expr), caddr(arg2));
  44020. return(add_ss_1ss);
  44021. }
  44022. }
  44023. return(add_2);
  44024. }
  44025. #endif
  44026. return(f);
  44027. }
  44028. static s7_pointer multiply_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44029. {
  44030. #if (!WITH_GMP)
  44031. if (args == 2)
  44032. {
  44033. s7_pointer arg1, arg2;
  44034. arg1 = cadr(expr);
  44035. arg2 = caddr(expr);
  44036. if (is_symbol(arg1))
  44037. {
  44038. #if HAVE_OVERFLOW_CHECKS
  44039. if (s7_is_integer(arg2))
  44040. #else
  44041. if ((s7_is_integer(arg2)) &&
  44042. (integer_length(integer(arg2)) < 31))
  44043. #endif
  44044. {
  44045. set_optimize_op(expr, HOP_SAFE_C_C);
  44046. return(multiply_si);
  44047. }
  44048. if (arg1 == arg2)
  44049. {
  44050. set_optimize_op(expr, HOP_SAFE_C_C);
  44051. return(sqr_ss);
  44052. }
  44053. if (is_t_real(arg2))
  44054. {
  44055. set_optimize_op(expr, HOP_SAFE_C_C);
  44056. return(multiply_sf);
  44057. }
  44058. }
  44059. if (is_symbol(arg2))
  44060. {
  44061. #if HAVE_OVERFLOW_CHECKS
  44062. if (s7_is_integer(arg1))
  44063. #else
  44064. if ((s7_is_integer(arg1)) &&
  44065. (integer_length(integer(arg1)) < 31))
  44066. #endif
  44067. {
  44068. set_optimize_op(expr, HOP_SAFE_C_C);
  44069. return(multiply_is);
  44070. }
  44071. if (is_t_real(arg1))
  44072. {
  44073. set_optimize_op(expr, HOP_SAFE_C_C);
  44074. return(multiply_fs);
  44075. }
  44076. }
  44077. if ((is_pair(arg1)) &&
  44078. (is_symbol(arg2)) &&
  44079. (car(arg1) == sc->subtract_symbol) &&
  44080. (is_t_real(cadr(arg1))) &&
  44081. (real(cadr(arg1)) == 1.0) &&
  44082. (is_symbol(caddr(arg1))) &&
  44083. (is_null(cdddr(arg1))))
  44084. {
  44085. set_optimize_op(expr, HOP_SAFE_C_C);
  44086. return(mul_1ss);
  44087. }
  44088. if ((is_symbol(arg1)) &&
  44089. (is_optimized(arg2)) &&
  44090. ((car(arg2) == sc->sin_symbol) || (car(arg2) == sc->cos_symbol)) &&
  44091. (is_symbol(cadr(arg2))))
  44092. {
  44093. set_optimize_op(expr, HOP_SAFE_C_C);
  44094. clear_unsafe(expr);
  44095. if (car(arg2) == sc->sin_symbol)
  44096. return(mul_s_sin_s);
  44097. return(mul_s_cos_s);
  44098. }
  44099. return(multiply_2);
  44100. }
  44101. if (args == 3)
  44102. {
  44103. s7_pointer arg1, arg2, arg3;
  44104. arg1 = cadr(expr);
  44105. arg2 = caddr(expr);
  44106. arg3 = cadddr(expr);
  44107. if ((is_t_real(arg1)) &&
  44108. (is_symbol(arg2)) &&
  44109. (is_pair(arg3)) &&
  44110. (car(arg3) == sc->cos_symbol) &&
  44111. (is_symbol(cadr(arg3))))
  44112. {
  44113. set_optimize_op(expr, HOP_SAFE_C_C);
  44114. return(multiply_cs_cos);
  44115. }
  44116. }
  44117. #endif
  44118. return(f);
  44119. }
  44120. static s7_pointer subtract_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44121. {
  44122. #if (!WITH_GMP)
  44123. if (args == 1)
  44124. return(subtract_1);
  44125. if (args == 2)
  44126. {
  44127. s7_pointer arg1, arg2;
  44128. arg1 = cadr(expr);
  44129. arg2 = caddr(expr);
  44130. if (arg2 == small_int(1))
  44131. {
  44132. if (is_symbol(arg1))
  44133. {
  44134. set_optimize_op(expr, HOP_SAFE_C_C);
  44135. return(subtract_cs1);
  44136. }
  44137. return(subtract_s1);
  44138. }
  44139. if (is_t_real(arg2))
  44140. {
  44141. if (is_symbol(arg1))
  44142. {
  44143. set_optimize_op(expr, HOP_SAFE_C_C);
  44144. return(subtract_sf);
  44145. }
  44146. if ((is_pair(arg1)) &&
  44147. (is_safely_optimized(arg1)))
  44148. {
  44149. if (c_callee(arg1) == g_random_rc)
  44150. {
  44151. set_optimize_op(expr, HOP_SAFE_C_C);
  44152. return(sub_random_rc);
  44153. }
  44154. }
  44155. }
  44156. if (is_t_real(arg1))
  44157. {
  44158. if (is_symbol(arg2))
  44159. {
  44160. set_optimize_op(expr, HOP_SAFE_C_C);
  44161. return(subtract_fs);
  44162. }
  44163. if ((is_h_safe_c_c(arg2)) &&
  44164. (c_callee(arg2) == g_sqr_ss))
  44165. {
  44166. set_optimize_op(expr, HOP_SAFE_C_C);
  44167. return(subtract_f_sqr);
  44168. }
  44169. }
  44170. if (s7_is_integer(arg2))
  44171. {
  44172. if (is_symbol(arg1))
  44173. {
  44174. set_optimize_op(expr, HOP_SAFE_C_C);
  44175. return(subtract_csn);
  44176. }
  44177. if ((is_safely_optimized(arg1)) &&
  44178. (c_callee(arg1) == g_random_ic))
  44179. {
  44180. set_optimize_op(expr, HOP_SAFE_C_C);
  44181. return(sub_random_ic);
  44182. }
  44183. }
  44184. if (is_t_real(arg2))
  44185. return(subtract_2f);
  44186. return(subtract_2);
  44187. }
  44188. #endif
  44189. return(f);
  44190. }
  44191. static s7_pointer divide_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44192. {
  44193. #if (!WITH_GMP)
  44194. if (args == 1)
  44195. return(invert_1);
  44196. if (args == 2)
  44197. {
  44198. s7_pointer arg1;
  44199. arg1 = cadr(expr);
  44200. if ((is_t_real(arg1)) &&
  44201. (real(arg1) == 1.0))
  44202. return(divide_1r);
  44203. }
  44204. #endif
  44205. return(f);
  44206. }
  44207. #if (!WITH_GMP)
  44208. static s7_pointer max_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44209. {
  44210. if ((args == 2) &&
  44211. (is_t_real(cadr(expr))) &&
  44212. (!is_NaN(real(cadr(expr)))))
  44213. return(max_f2);
  44214. return(f);
  44215. }
  44216. static s7_pointer min_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44217. {
  44218. if ((args == 2) &&
  44219. (is_t_real(cadr(expr))) &&
  44220. (!is_NaN(real(cadr(expr)))))
  44221. return(min_f2);
  44222. return(f);
  44223. }
  44224. static s7_pointer is_zero_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44225. {
  44226. if ((args == 1) &&
  44227. (is_safely_optimized(cadr(expr))) &&
  44228. (optimize_op(cadr(expr)) == HOP_SAFE_C_C) &&
  44229. (c_callee(cadr(expr)) == g_mod_si))
  44230. {
  44231. set_optimize_op(expr, HOP_SAFE_C_C);
  44232. return(mod_si_is_zero);
  44233. }
  44234. return(f);
  44235. }
  44236. static s7_pointer equal_chooser(s7_scheme *sc, s7_pointer ur_f, int args, s7_pointer expr)
  44237. {
  44238. if (args == 2)
  44239. {
  44240. s7_pointer arg1, arg2;
  44241. arg1 = cadr(expr);
  44242. arg2 = caddr(expr);
  44243. if (s7_is_integer(arg2))
  44244. {
  44245. if (is_safely_optimized(arg1))
  44246. {
  44247. s7_function f;
  44248. f = c_callee(arg1);
  44249. if (f == g_length)
  44250. {
  44251. if (optimize_op(arg1) == HOP_SAFE_C_S)
  44252. {
  44253. set_optimize_op(expr, HOP_SAFE_C_C);
  44254. return(equal_length_ic);
  44255. }
  44256. }
  44257. if ((f == g_mod_si) &&
  44258. (integer(arg2) == 0))
  44259. {
  44260. set_optimize_op(expr, HOP_SAFE_C_C);
  44261. return(mod_si_is_zero);
  44262. }
  44263. }
  44264. if (is_symbol(arg1))
  44265. {
  44266. set_optimize_op(expr, HOP_SAFE_C_C);
  44267. return(equal_s_ic);
  44268. }
  44269. }
  44270. return(equal_2);
  44271. }
  44272. return(ur_f);
  44273. }
  44274. static s7_pointer less_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44275. {
  44276. if (args == 2)
  44277. {
  44278. s7_pointer arg2;
  44279. arg2 = caddr(expr);
  44280. if (is_integer(arg2))
  44281. {
  44282. if (is_h_safe_c_s(cadr(expr)))
  44283. {
  44284. s7_function f;
  44285. f = c_callee(cadr(expr));
  44286. if (f == g_length)
  44287. {
  44288. set_optimize_op(expr, HOP_SAFE_C_C);
  44289. return(less_length_ic);
  44290. }
  44291. }
  44292. if (integer(arg2) == 0)
  44293. return(less_s0);
  44294. if ((integer(arg2) < s7_int32_max) &&
  44295. (integer(arg2) > s7_int32_min))
  44296. return(less_s_ic);
  44297. }
  44298. return(less_2);
  44299. }
  44300. return(f);
  44301. }
  44302. static s7_pointer leq_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44303. {
  44304. if (args == 2)
  44305. {
  44306. s7_pointer arg2;
  44307. arg2 = caddr(expr);
  44308. if ((is_integer(arg2)) &&
  44309. (integer(arg2) < s7_int32_max) &&
  44310. (integer(arg2) > s7_int32_min))
  44311. return(leq_s_ic);
  44312. return(leq_2);
  44313. }
  44314. return(f);
  44315. }
  44316. static s7_pointer greater_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44317. {
  44318. if (args == 2)
  44319. {
  44320. s7_pointer arg2;
  44321. arg2 = caddr(expr);
  44322. if ((is_integer(arg2)) &&
  44323. (integer(arg2) < s7_int32_max) &&
  44324. (integer(arg2) > s7_int32_min))
  44325. return(greater_s_ic);
  44326. if ((is_t_real(arg2)) &&
  44327. (real(arg2) < s7_int32_max) &&
  44328. (real(arg2) > s7_int32_min))
  44329. return(greater_s_fc);
  44330. return(greater_2);
  44331. }
  44332. return(f);
  44333. }
  44334. static s7_pointer geq_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44335. {
  44336. if (args == 2)
  44337. {
  44338. s7_pointer arg2;
  44339. arg2 = caddr(expr);
  44340. if (is_integer(arg2))
  44341. {
  44342. if (is_h_safe_c_s(cadr(expr)))
  44343. {
  44344. s7_function f;
  44345. f = c_callee(cadr(expr));
  44346. if (f == g_length)
  44347. {
  44348. set_optimize_op(expr, HOP_SAFE_C_C);
  44349. return(geq_length_ic);
  44350. }
  44351. }
  44352. if ((integer(arg2) < s7_int32_max) &&
  44353. (integer(arg2) > s7_int32_min))
  44354. return(geq_s_ic);
  44355. }
  44356. if ((is_t_real(arg2)) &&
  44357. (real(arg2) < s7_int32_max) &&
  44358. (real(arg2) > s7_int32_min))
  44359. return(geq_s_fc);
  44360. return(geq_2);
  44361. }
  44362. return(f);
  44363. }
  44364. #endif
  44365. /* end (!WITH_GMP) */
  44366. static bool returns_char(s7_scheme *sc, s7_pointer arg)
  44367. {
  44368. /* also if arg is immutable symbol + value is char */
  44369. if (s7_is_character(arg)) return(true);
  44370. if ((is_h_optimized(arg)) &&
  44371. (is_c_function(opt_cfunc(arg))))
  44372. {
  44373. s7_pointer sig;
  44374. sig = c_function_signature(opt_cfunc(arg));
  44375. return((sig) &&
  44376. (is_pair(sig)) &&
  44377. (car(sig) == sc->is_char_symbol));
  44378. }
  44379. return(false);
  44380. }
  44381. static s7_pointer char_equal_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44382. {
  44383. if (args == 2)
  44384. {
  44385. s7_pointer arg1, arg2;
  44386. arg1 = cadr(expr);
  44387. arg2 = caddr(expr);
  44388. if ((returns_char(sc, arg1)) && (returns_char(sc, arg2)))
  44389. return(simple_char_eq);
  44390. if ((is_symbol(arg1)) &&
  44391. (s7_is_character(arg2)))
  44392. {
  44393. set_optimize_op(expr, HOP_SAFE_C_C);
  44394. return(char_equal_s_ic);
  44395. }
  44396. return(char_equal_2);
  44397. }
  44398. return(f);
  44399. }
  44400. static s7_pointer char_less_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44401. {
  44402. if (args == 2)
  44403. {
  44404. if (s7_is_character(caddr(expr)))
  44405. return(char_less_s_ic);
  44406. return(char_less_2);
  44407. }
  44408. return(f);
  44409. }
  44410. static s7_pointer char_greater_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44411. {
  44412. if (args == 2)
  44413. {
  44414. if (s7_is_character(caddr(expr)))
  44415. return(char_greater_s_ic);
  44416. return(char_greater_2);
  44417. }
  44418. return(f);
  44419. }
  44420. static void check_for_substring_temp(s7_scheme *sc, s7_pointer expr)
  44421. {
  44422. s7_pointer p, np = NULL, ap = NULL, sp = NULL, arg;
  44423. int pairs = 0;
  44424. /* a bit tricky -- accept temp only if there's just one inner expression and it calls substring */
  44425. for (p = cdr(expr); is_pair(p); p = cdr(p))
  44426. {
  44427. arg = car(p);
  44428. if (is_pair(arg))
  44429. {
  44430. pairs++;
  44431. if ((is_symbol(car(arg))) &&
  44432. (is_safely_optimized(arg)))
  44433. {
  44434. if (c_callee(arg) == g_substring)
  44435. np = arg;
  44436. else
  44437. {
  44438. if (c_callee(arg) == g_number_to_string)
  44439. sp = arg;
  44440. else
  44441. {
  44442. if (c_callee(arg) == g_string_append)
  44443. ap = arg;
  44444. else
  44445. {
  44446. if (c_callee(arg) == g_symbol_to_string)
  44447. set_c_function(arg, symbol_to_string_uncopied);
  44448. else
  44449. {
  44450. if ((c_callee(arg) == g_read_line) &&
  44451. (is_pair(cdr(arg))))
  44452. set_c_function(arg, read_line_uncopied);
  44453. }}}}}}}
  44454. if (pairs == 1)
  44455. {
  44456. if (np)
  44457. set_c_function(np, substring_to_temp);
  44458. else
  44459. {
  44460. if (sp)
  44461. set_c_function(sp, number_to_string_temp);
  44462. else
  44463. {
  44464. if (ap)
  44465. {
  44466. for (p = ap; is_pair(p); p = cdr(p))
  44467. {
  44468. /* make sure there are no embedded uses of the temp string */
  44469. arg = car(p);
  44470. if ((is_pair(arg)) &&
  44471. (is_safely_optimized(arg)))
  44472. {
  44473. if (c_callee(arg) == g_substring_to_temp)
  44474. set_c_function(arg, slot_value(global_slot(sc->substring_symbol)));
  44475. else
  44476. {
  44477. if (c_callee(arg) == g_string_append_to_temp)
  44478. set_c_function(arg, slot_value(global_slot(sc->string_append_symbol)));
  44479. }
  44480. }
  44481. }
  44482. set_c_function(ap, string_append_to_temp);
  44483. }
  44484. }
  44485. }
  44486. }
  44487. }
  44488. static s7_pointer char_position_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44489. {
  44490. if (((args == 2) || (args == 3)) &&
  44491. (s7_is_character(cadr(expr))))
  44492. return(char_position_csi);
  44493. return(f);
  44494. }
  44495. static s7_pointer string_equal_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44496. {
  44497. check_for_substring_temp(sc, expr);
  44498. if (args == 2)
  44499. {
  44500. if (is_string(caddr(expr)))
  44501. return(string_equal_s_ic);
  44502. return(string_equal_2);
  44503. }
  44504. return(f);
  44505. }
  44506. static s7_pointer string_less_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44507. {
  44508. check_for_substring_temp(sc, expr);
  44509. if (args == 2)
  44510. return(string_less_2);
  44511. return(f);
  44512. }
  44513. static s7_pointer string_greater_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44514. {
  44515. check_for_substring_temp(sc, expr);
  44516. if (args == 2)
  44517. return(string_greater_2);
  44518. return(f);
  44519. }
  44520. static s7_pointer string_to_symbol_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44521. {
  44522. check_for_substring_temp(sc, expr);
  44523. return(f);
  44524. }
  44525. static s7_pointer string_ref_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44526. {
  44527. check_for_substring_temp(sc, expr);
  44528. return(f);
  44529. }
  44530. static s7_pointer string_set_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44531. {
  44532. return(f);
  44533. }
  44534. static s7_pointer string_append_chooser(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr)
  44535. {
  44536. check_for_substring_temp(sc, expr);
  44537. return(f);
  44538. }
  44539. static s7_pointer or_direct;
  44540. static s7_pointer g_or_direct(s7_scheme *sc, s7_pointer args)
  44541. {
  44542. s7_pointer p;
  44543. for (p = args; is_pair(p); p = cdr(p))
  44544. {
  44545. s7_pointer x;
  44546. x = car(p);
  44547. if (is_symbol(x))
  44548. x = find_symbol_checked(sc, x);
  44549. if (is_true(sc, x))
  44550. return(x);
  44551. }
  44552. return(sc->F);
  44553. }
  44554. static s7_pointer and_direct;
  44555. static s7_pointer g_and_direct(s7_scheme *sc, s7_pointer args)
  44556. {
  44557. s7_pointer p, x;
  44558. x = sc->T;
  44559. for (p = args; is_pair(p); p = cdr(p))
  44560. {
  44561. x = car(p);
  44562. if (is_symbol(x))
  44563. x = find_symbol_checked(sc, x);
  44564. if (is_false(sc, x))
  44565. return(x);
  44566. }
  44567. return(x);
  44568. }
  44569. static s7_pointer if_direct;
  44570. static s7_pointer g_if_direct(s7_scheme *sc, s7_pointer args)
  44571. {
  44572. s7_pointer p;
  44573. p = car(args);
  44574. if (is_symbol(p))
  44575. p = find_symbol_checked(sc, p);
  44576. if (is_true(sc, p))
  44577. p = cadr(args);
  44578. else
  44579. {
  44580. if (!is_null(cddr(args)))
  44581. p = caddr(args);
  44582. else return(sc->unspecified);
  44583. }
  44584. if (is_symbol(p))
  44585. return(find_symbol_checked(sc, p));
  44586. return(p);
  44587. }
  44588. static s7_pointer or_all_x, or_all_x_2, or_all_x_2s;
  44589. static s7_pointer g_or_all_x(s7_scheme *sc, s7_pointer args)
  44590. {
  44591. s7_pointer p;
  44592. for (p = args; is_pair(p); p = cdr(p))
  44593. {
  44594. s7_pointer x;
  44595. x = c_call(p)(sc, car(p));
  44596. if (is_true(sc, x))
  44597. return(x);
  44598. }
  44599. return(sc->F);
  44600. }
  44601. static s7_pointer g_or_all_x_2(s7_scheme *sc, s7_pointer args)
  44602. {
  44603. s7_pointer p;
  44604. p = c_call(args)(sc, car(args));
  44605. if (p != sc->F) return(p);
  44606. p = cdr(args);
  44607. return(c_call(p)(sc, car(p)));
  44608. }
  44609. static s7_pointer g_or_all_x_2s(s7_scheme *sc, s7_pointer args)
  44610. {
  44611. s7_pointer p;
  44612. p = car(args);
  44613. set_car(sc->t1_1, find_symbol_unchecked(sc, cadr(p)));
  44614. p = c_call(p)(sc, sc->t1_1);
  44615. if (p != sc->F) return(p);
  44616. p = cadr(args);
  44617. set_car(sc->t1_1, find_symbol_unchecked(sc, cadr(p)));
  44618. return(c_call(p)(sc, sc->t1_1));
  44619. }
  44620. static s7_pointer and_all_x, and_all_x_2;
  44621. static s7_pointer g_and_all_x(s7_scheme *sc, s7_pointer args)
  44622. {
  44623. s7_pointer p, x = sc->T;
  44624. for (p = args; is_pair(p); p = cdr(p))
  44625. {
  44626. x = c_call(p)(sc, car(p));
  44627. if (is_false(sc, x))
  44628. return(x);
  44629. }
  44630. return(x);
  44631. }
  44632. static s7_pointer g_and_all_x_2(s7_scheme *sc, s7_pointer args)
  44633. {
  44634. s7_pointer p;
  44635. p = c_call(args)(sc, car(args));
  44636. if (p == sc->F) return(p);
  44637. p = cdr(args);
  44638. return(c_call(p)(sc, car(p)));
  44639. }
  44640. static s7_pointer if_all_x1;
  44641. static s7_pointer g_if_all_x1(s7_scheme *sc, s7_pointer args)
  44642. {
  44643. s7_pointer p;
  44644. if (is_true(sc, c_call(args)(sc, car(args))))
  44645. p = cdr(args);
  44646. else return(sc->unspecified);
  44647. return(c_call(p)(sc, car(p)));
  44648. }
  44649. static s7_pointer if_all_x2;
  44650. static s7_pointer g_if_all_x2(s7_scheme *sc, s7_pointer args)
  44651. {
  44652. s7_pointer p;
  44653. if (is_true(sc, c_call(args)(sc, car(args))))
  44654. p = cdr(args);
  44655. else p = cddr(args);
  44656. return(c_call(p)(sc, car(p)));
  44657. }
  44658. static s7_pointer if_all_not_x1;
  44659. static s7_pointer g_if_all_not_x1(s7_scheme *sc, s7_pointer args)
  44660. {
  44661. s7_pointer p;
  44662. if (is_false(sc, c_call(args)(sc, cadar(args))))
  44663. p = cdr(args);
  44664. else return(sc->unspecified);
  44665. return(c_call(p)(sc, car(p)));
  44666. }
  44667. static s7_pointer if_all_not_x2;
  44668. static s7_pointer g_if_all_not_x2(s7_scheme *sc, s7_pointer args)
  44669. {
  44670. s7_pointer p;
  44671. if (is_false(sc, c_call(args)(sc, cadar(args))))
  44672. p = cdr(args);
  44673. else p = cddr(args);
  44674. return(c_call(p)(sc, car(p)));
  44675. }
  44676. static s7_pointer if_all_x_qq;
  44677. static s7_pointer g_if_all_x_qq(s7_scheme *sc, s7_pointer args)
  44678. {
  44679. if (is_true(sc, c_call(args)(sc, car(args))))
  44680. return(cadr(cadr(args)));
  44681. return(cadr(caddr(args)));
  44682. }
  44683. static s7_pointer if_all_x_qa;
  44684. static s7_pointer g_if_all_x_qa(s7_scheme *sc, s7_pointer args)
  44685. {
  44686. if (is_true(sc, c_call(args)(sc, car(args))))
  44687. return(cadr(cadr(args)));
  44688. return(c_call(cddr(args))(sc, caddr(args)));
  44689. }
  44690. static s7_pointer or_s_direct;
  44691. static s7_pointer g_or_s_direct(s7_scheme *sc, s7_pointer args)
  44692. {
  44693. s7_pointer p;
  44694. set_car(sc->t1_1, find_symbol_checked(sc, cadar(args)));
  44695. for (p = args; is_pair(p); p = cdr(p))
  44696. {
  44697. s7_pointer x;
  44698. x = c_call(car(p))(sc, sc->t1_1);
  44699. if (is_true(sc, x))
  44700. return(x);
  44701. }
  44702. return(sc->F);
  44703. }
  44704. static s7_pointer and_s_direct;
  44705. static s7_pointer g_and_s_direct(s7_scheme *sc, s7_pointer args)
  44706. {
  44707. s7_pointer p, x = sc->T;
  44708. set_car(sc->t1_1, find_symbol_checked(sc, cadar(args)));
  44709. for (p = args; is_pair(p); p = cdr(p))
  44710. {
  44711. x = c_call(car(p))(sc, sc->t1_1);
  44712. if (is_false(sc, x))
  44713. return(x);
  44714. }
  44715. return(x);
  44716. }
  44717. static s7_pointer if_s_direct;
  44718. static s7_pointer g_if_s_direct(s7_scheme *sc, s7_pointer args)
  44719. {
  44720. s7_pointer p;
  44721. set_car(sc->t1_1, find_symbol_checked(sc, cadar(args)));
  44722. if (is_true(sc, c_call(car(args))(sc, sc->t1_1)))
  44723. p = cdr(args);
  44724. else
  44725. {
  44726. p = cddr(args);
  44727. if (is_null(p))
  44728. return(sc->unspecified);
  44729. }
  44730. return(c_call(car(p))(sc, sc->t1_1));
  44731. }
  44732. static s7_pointer make_function_with_class(s7_scheme *sc, s7_pointer cls, const char *name, s7_function f,
  44733. int required_args, int optional_args, bool rest_arg, const char *doc)
  44734. {
  44735. s7_pointer uf;
  44736. /* the "safe_function" business here doesn't matter -- this is after the optimizer decides what is safe */
  44737. uf = s7_make_safe_function(sc, name, f, required_args, optional_args, rest_arg, doc);
  44738. s7_function_set_class(uf, cls);
  44739. return(uf);
  44740. }
  44741. static s7_pointer set_function_chooser(s7_scheme *sc, s7_pointer sym, s7_pointer (*chooser)(s7_scheme *sc, s7_pointer f, int args, s7_pointer expr))
  44742. {
  44743. s7_pointer f;
  44744. f = slot_value(global_slot(sym));
  44745. #ifndef WITHOUT_CHOOSERS
  44746. c_function_chooser(f) = chooser;
  44747. #endif
  44748. return(f);
  44749. }
  44750. static void init_choosers(s7_scheme *sc)
  44751. {
  44752. s7_pointer f;
  44753. #if (!WITH_GMP)
  44754. s7_if_set_function(slot_value(global_slot(sc->modulo_symbol)), modulo_if);
  44755. s7_rf_set_function(slot_value(global_slot(sc->modulo_symbol)), modulo_rf);
  44756. s7_rf_set_function(slot_value(global_slot(sc->remainder_symbol)), remainder_rf);
  44757. s7_if_set_function(slot_value(global_slot(sc->remainder_symbol)), remainder_if);
  44758. s7_rf_set_function(slot_value(global_slot(sc->quotient_symbol)), quotient_rf);
  44759. s7_if_set_function(slot_value(global_slot(sc->quotient_symbol)), quotient_if);
  44760. s7_if_set_function(slot_value(global_slot(sc->numerator_symbol)), numerator_if);
  44761. s7_if_set_function(slot_value(global_slot(sc->denominator_symbol)), denominator_if);
  44762. s7_rf_set_function(slot_value(global_slot(sc->real_part_symbol)), real_part_rf);
  44763. s7_rf_set_function(slot_value(global_slot(sc->imag_part_symbol)), imag_part_rf);
  44764. s7_gf_set_function(slot_value(global_slot(sc->rationalize_symbol)), rationalize_pf);
  44765. s7_if_set_function(slot_value(global_slot(sc->ceiling_symbol)), ceiling_if);
  44766. s7_if_set_function(slot_value(global_slot(sc->truncate_symbol)), truncate_if);
  44767. s7_if_set_function(slot_value(global_slot(sc->round_symbol)), round_if);
  44768. s7_if_set_function(slot_value(global_slot(sc->floor_symbol)), floor_if);
  44769. s7_if_set_function(slot_value(global_slot(sc->logior_symbol)), logior_if);
  44770. s7_if_set_function(slot_value(global_slot(sc->logand_symbol)), logand_if);
  44771. s7_if_set_function(slot_value(global_slot(sc->logxor_symbol)), logxor_if);
  44772. s7_if_set_function(slot_value(global_slot(sc->lognot_symbol)), lognot_if);
  44773. s7_if_set_function(slot_value(global_slot(sc->ash_symbol)), ash_if);
  44774. s7_if_set_function(slot_value(global_slot(sc->gcd_symbol)), gcd_if);
  44775. s7_if_set_function(slot_value(global_slot(sc->lcm_symbol)), lcm_if);
  44776. s7_rf_set_function(slot_value(global_slot(sc->max_symbol)), max_rf);
  44777. s7_if_set_function(slot_value(global_slot(sc->max_symbol)), max_if);
  44778. s7_rf_set_function(slot_value(global_slot(sc->min_symbol)), min_rf);
  44779. s7_if_set_function(slot_value(global_slot(sc->min_symbol)), min_if);
  44780. s7_rf_set_function(slot_value(global_slot(sc->divide_symbol)), divide_rf);
  44781. s7_if_set_function(slot_value(global_slot(sc->multiply_symbol)), multiply_if);
  44782. s7_rf_set_function(slot_value(global_slot(sc->multiply_symbol)), multiply_rf);
  44783. s7_rf_set_function(slot_value(global_slot(sc->add_symbol)), add_rf);
  44784. s7_if_set_function(slot_value(global_slot(sc->add_symbol)), add_if);
  44785. s7_rf_set_function(slot_value(global_slot(sc->subtract_symbol)), subtract_rf);
  44786. s7_if_set_function(slot_value(global_slot(sc->subtract_symbol)), subtract_if);
  44787. #if WITH_ADD_PF
  44788. s7_gf_set_function(slot_value(global_slot(sc->multiply_symbol)), multiply_pf);
  44789. s7_gf_set_function(slot_value(global_slot(sc->add_symbol)), add_pf);
  44790. s7_gf_set_function(slot_value(global_slot(sc->subtract_symbol)), subtract_pf);
  44791. #endif
  44792. s7_rf_set_function(slot_value(global_slot(sc->sin_symbol)), sin_rf);
  44793. s7_rf_set_function(slot_value(global_slot(sc->cos_symbol)), cos_rf);
  44794. s7_rf_set_function(slot_value(global_slot(sc->tan_symbol)), tan_rf);
  44795. s7_rf_set_function(slot_value(global_slot(sc->sinh_symbol)), sinh_rf);
  44796. s7_rf_set_function(slot_value(global_slot(sc->cosh_symbol)), cosh_rf);
  44797. s7_rf_set_function(slot_value(global_slot(sc->tanh_symbol)), tanh_rf);
  44798. s7_rf_set_function(slot_value(global_slot(sc->atan_symbol)), atan_rf);
  44799. s7_rf_set_function(slot_value(global_slot(sc->exp_symbol)), exp_rf);
  44800. s7_gf_set_function(slot_value(global_slot(sc->asin_symbol)), asin_pf);
  44801. s7_gf_set_function(slot_value(global_slot(sc->acos_symbol)), acos_pf);
  44802. s7_gf_set_function(slot_value(global_slot(sc->asinh_symbol)), asinh_pf);
  44803. s7_gf_set_function(slot_value(global_slot(sc->acosh_symbol)), acosh_pf);
  44804. s7_gf_set_function(slot_value(global_slot(sc->atanh_symbol)), atanh_pf);
  44805. s7_rf_set_function(slot_value(global_slot(sc->random_symbol)), random_rf);
  44806. s7_if_set_function(slot_value(global_slot(sc->random_symbol)), random_if);
  44807. s7_gf_set_function(slot_value(global_slot(sc->expt_symbol)), expt_pf);
  44808. s7_gf_set_function(slot_value(global_slot(sc->number_to_string_symbol)), number_to_string_pf);
  44809. s7_gf_set_function(slot_value(global_slot(sc->string_to_number_symbol)), string_to_number_pf);
  44810. s7_rf_set_function(slot_value(global_slot(sc->abs_symbol)), fabs_rf);
  44811. s7_if_set_function(slot_value(global_slot(sc->abs_symbol)), abs_if);
  44812. #if (!WITH_PURE_S7)
  44813. s7_gf_set_function(slot_value(global_slot(sc->make_rectangular_symbol)), make_complex_pf);
  44814. s7_gf_set_function(slot_value(global_slot(sc->make_polar_symbol)), make_polar_pf);
  44815. #endif
  44816. s7_rf_set_function(slot_value(global_slot(sc->magnitude_symbol)), magnitude_rf);
  44817. s7_if_set_function(slot_value(global_slot(sc->magnitude_symbol)), magnitude_if);
  44818. s7_gf_set_function(slot_value(global_slot(sc->complex_symbol)), make_complex_pf); /* actually complex */
  44819. s7_pf_set_function(slot_value(global_slot(sc->eq_symbol)), equal_pf);
  44820. s7_pf_set_function(slot_value(global_slot(sc->lt_symbol)), less_pf);
  44821. s7_pf_set_function(slot_value(global_slot(sc->leq_symbol)), leq_pf);
  44822. s7_pf_set_function(slot_value(global_slot(sc->geq_symbol)), geq_pf);
  44823. s7_pf_set_function(slot_value(global_slot(sc->gt_symbol)), gt_pf);
  44824. #endif /* !gmp */
  44825. s7_if_set_function(slot_value(global_slot(sc->pair_line_number_symbol)), pair_line_number_if);
  44826. s7_if_set_function(slot_value(global_slot(sc->hash_table_entries_symbol)), hash_table_entries_if);
  44827. #if (!WITH_PURE_S7)
  44828. #if (!WITH_GMP)
  44829. s7_if_set_function(slot_value(global_slot(sc->integer_length_symbol)), integer_length_if);
  44830. #endif
  44831. s7_if_set_function(slot_value(global_slot(sc->vector_length_symbol)), vector_length_if);
  44832. s7_if_set_function(slot_value(global_slot(sc->string_length_symbol)), string_length_if);
  44833. s7_pf_set_function(slot_value(global_slot(sc->string_fill_symbol)), string_fill_pf);
  44834. s7_pf_set_function(slot_value(global_slot(sc->vector_fill_symbol)), vector_fill_pf);
  44835. #endif
  44836. s7_pf_set_function(slot_value(global_slot(sc->length_symbol)), length_pf);
  44837. s7_pf_set_function(slot_value(global_slot(sc->fill_symbol)), fill_pf);
  44838. s7_gf_set_function(slot_value(global_slot(sc->copy_symbol)), copy_pf);
  44839. s7_gf_set_function(slot_value(global_slot(sc->reverse_symbol)), reverse_pf);
  44840. s7_pf_set_function(slot_value(global_slot(sc->not_symbol)), not_pf);
  44841. s7_if_set_function(slot_value(global_slot(sc->char_to_integer_symbol)), char_to_integer_if);
  44842. s7_pf_set_function(slot_value(global_slot(sc->char_eq_symbol)), char_eq_pf);
  44843. s7_pf_set_function(slot_value(global_slot(sc->char_gt_symbol)), char_gt_pf);
  44844. s7_pf_set_function(slot_value(global_slot(sc->char_geq_symbol)), char_geq_pf);
  44845. s7_pf_set_function(slot_value(global_slot(sc->char_lt_symbol)), char_lt_pf);
  44846. s7_pf_set_function(slot_value(global_slot(sc->char_leq_symbol)), char_leq_pf);
  44847. s7_pf_set_function(slot_value(global_slot(sc->string_eq_symbol)), string_eq_pf);
  44848. s7_pf_set_function(slot_value(global_slot(sc->string_lt_symbol)), string_lt_pf);
  44849. s7_pf_set_function(slot_value(global_slot(sc->string_leq_symbol)), string_leq_pf);
  44850. s7_pf_set_function(slot_value(global_slot(sc->string_gt_symbol)), string_gt_pf);
  44851. s7_pf_set_function(slot_value(global_slot(sc->string_geq_symbol)), string_geq_pf);
  44852. s7_gf_set_function(slot_value(global_slot(sc->string_upcase_symbol)), string_upcase_pf);
  44853. s7_gf_set_function(slot_value(global_slot(sc->string_downcase_symbol)), string_downcase_pf);
  44854. s7_gf_set_function(slot_value(global_slot(sc->char_position_symbol)), char_position_pf);
  44855. s7_gf_set_function(slot_value(global_slot(sc->string_position_symbol)), string_position_pf);
  44856. #if (!WITH_PURE_S7)
  44857. s7_pf_set_function(slot_value(global_slot(sc->char_ci_eq_symbol)), char_ci_eq_pf);
  44858. s7_pf_set_function(slot_value(global_slot(sc->char_ci_gt_symbol)), char_ci_gt_pf);
  44859. s7_pf_set_function(slot_value(global_slot(sc->char_ci_geq_symbol)), char_ci_geq_pf);
  44860. s7_pf_set_function(slot_value(global_slot(sc->char_ci_lt_symbol)), char_ci_lt_pf);
  44861. s7_pf_set_function(slot_value(global_slot(sc->char_ci_leq_symbol)), char_ci_leq_pf);
  44862. s7_pf_set_function(slot_value(global_slot(sc->string_ci_eq_symbol)), string_ci_eq_pf);
  44863. s7_pf_set_function(slot_value(global_slot(sc->string_ci_lt_symbol)), string_ci_lt_pf);
  44864. s7_pf_set_function(slot_value(global_slot(sc->string_ci_leq_symbol)), string_ci_leq_pf);
  44865. s7_pf_set_function(slot_value(global_slot(sc->string_ci_gt_symbol)), string_ci_gt_pf);
  44866. s7_pf_set_function(slot_value(global_slot(sc->string_ci_geq_symbol)), string_ci_geq_pf);
  44867. #endif
  44868. #if (!WITH_GMP)
  44869. s7_pf_set_function(slot_value(global_slot(sc->is_even_symbol)), is_even_pf);
  44870. s7_pf_set_function(slot_value(global_slot(sc->is_odd_symbol)), is_odd_pf);
  44871. s7_pf_set_function(slot_value(global_slot(sc->is_nan_symbol)), is_nan_pf);
  44872. s7_pf_set_function(slot_value(global_slot(sc->is_infinite_symbol)), is_infinite_pf);
  44873. #endif
  44874. s7_pf_set_function(slot_value(global_slot(sc->is_zero_symbol)), is_zero_pf);
  44875. s7_pf_set_function(slot_value(global_slot(sc->is_positive_symbol)), is_positive_pf);
  44876. s7_pf_set_function(slot_value(global_slot(sc->is_negative_symbol)), is_negative_pf);
  44877. s7_pf_set_function(slot_value(global_slot(sc->hash_table_ref_symbol)), hash_table_ref_pf);
  44878. s7_pf_set_function(slot_value(global_slot(sc->hash_table_set_symbol)), hash_table_set_pf);
  44879. s7_pf_set_function(slot_value(global_slot(sc->vector_ref_symbol)), vector_ref_pf);
  44880. s7_pf_set_function(slot_value(global_slot(sc->vector_set_symbol)), vector_set_pf);
  44881. s7_pf_set_function(slot_value(global_slot(sc->string_ref_symbol)), string_ref_pf);
  44882. s7_pf_set_function(slot_value(global_slot(sc->string_set_symbol)), string_set_pf);
  44883. s7_pf_set_function(slot_value(global_slot(sc->list_ref_symbol)), list_ref_pf);
  44884. s7_pf_set_function(slot_value(global_slot(sc->list_set_symbol)), list_set_pf);
  44885. s7_pf_set_function(slot_value(global_slot(sc->let_ref_symbol)), let_ref_pf);
  44886. s7_pf_set_function(slot_value(global_slot(sc->let_set_symbol)), let_set_pf);
  44887. s7_pf_set_function(slot_value(global_slot(sc->string_to_byte_vector_symbol)), string_to_byte_vector_pf);
  44888. s7_rf_set_function(slot_value(global_slot(sc->float_vector_ref_symbol)), float_vector_ref_rf);
  44889. s7_rf_set_function(slot_value(global_slot(sc->float_vector_set_symbol)), float_vector_set_rf);
  44890. s7_if_set_function(slot_value(global_slot(sc->int_vector_ref_symbol)), int_vector_ref_if);
  44891. s7_if_set_function(slot_value(global_slot(sc->int_vector_set_symbol)), int_vector_set_if);
  44892. s7_pf_set_function(slot_value(global_slot(sc->caaaar_symbol)), caaaar_pf);
  44893. s7_pf_set_function(slot_value(global_slot(sc->caaadr_symbol)), caaadr_pf);
  44894. s7_pf_set_function(slot_value(global_slot(sc->caaar_symbol)), caaar_pf);
  44895. s7_pf_set_function(slot_value(global_slot(sc->caadar_symbol)), caadar_pf);
  44896. s7_pf_set_function(slot_value(global_slot(sc->caaddr_symbol)), caaddr_pf);
  44897. s7_pf_set_function(slot_value(global_slot(sc->caadr_symbol)), caadr_pf);
  44898. s7_pf_set_function(slot_value(global_slot(sc->caar_symbol)), caar_pf);
  44899. s7_pf_set_function(slot_value(global_slot(sc->cadaar_symbol)), cadaar_pf);
  44900. s7_pf_set_function(slot_value(global_slot(sc->cadadr_symbol)), cadadr_pf);
  44901. s7_pf_set_function(slot_value(global_slot(sc->cadar_symbol)), cadar_pf);
  44902. s7_pf_set_function(slot_value(global_slot(sc->caddar_symbol)), caddar_pf);
  44903. s7_pf_set_function(slot_value(global_slot(sc->cadddr_symbol)), cadddr_pf);
  44904. s7_pf_set_function(slot_value(global_slot(sc->caddr_symbol)), caddr_pf);
  44905. s7_pf_set_function(slot_value(global_slot(sc->cadr_symbol)), cadr_pf);
  44906. s7_pf_set_function(slot_value(global_slot(sc->car_symbol)), car_pf);
  44907. s7_pf_set_function(slot_value(global_slot(sc->cdaaar_symbol)), cdaaar_pf);
  44908. s7_pf_set_function(slot_value(global_slot(sc->cdaadr_symbol)), cdaadr_pf);
  44909. s7_pf_set_function(slot_value(global_slot(sc->cdaar_symbol)), cdaar_pf);
  44910. s7_pf_set_function(slot_value(global_slot(sc->cdadar_symbol)), cdadar_pf);
  44911. s7_pf_set_function(slot_value(global_slot(sc->cdaddr_symbol)), cdaddr_pf);
  44912. s7_pf_set_function(slot_value(global_slot(sc->cdadr_symbol)), cdadr_pf);
  44913. s7_pf_set_function(slot_value(global_slot(sc->cdar_symbol)), cdar_pf);
  44914. s7_pf_set_function(slot_value(global_slot(sc->cddaar_symbol)), cddaar_pf);
  44915. s7_pf_set_function(slot_value(global_slot(sc->cddadr_symbol)), cddadr_pf);
  44916. s7_pf_set_function(slot_value(global_slot(sc->cddar_symbol)), cddar_pf);
  44917. s7_pf_set_function(slot_value(global_slot(sc->cdddar_symbol)), cdddar_pf);
  44918. s7_pf_set_function(slot_value(global_slot(sc->cddddr_symbol)), cddddr_pf);
  44919. s7_pf_set_function(slot_value(global_slot(sc->cdddr_symbol)), cdddr_pf);
  44920. s7_pf_set_function(slot_value(global_slot(sc->cddr_symbol)), cddr_pf);
  44921. s7_pf_set_function(slot_value(global_slot(sc->cdr_symbol)), cdr_pf);
  44922. s7_pf_set_function(slot_value(global_slot(sc->set_car_symbol)), set_car_pf);
  44923. s7_pf_set_function(slot_value(global_slot(sc->set_cdr_symbol)), set_cdr_pf);
  44924. s7_pf_set_function(slot_value(global_slot(sc->list_tail_symbol)), list_tail_pf);
  44925. s7_pf_set_function(slot_value(global_slot(sc->assoc_symbol)), assoc_pf);
  44926. s7_pf_set_function(slot_value(global_slot(sc->member_symbol)), member_pf);
  44927. s7_gf_set_function(slot_value(global_slot(sc->cons_symbol)), cons_pf);
  44928. s7_gf_set_function(slot_value(global_slot(sc->list_symbol)), list_pf);
  44929. s7_gf_set_function(slot_value(global_slot(sc->int_vector_symbol)), int_vector_pf);
  44930. s7_gf_set_function(slot_value(global_slot(sc->float_vector_symbol)), float_vector_pf);
  44931. s7_gf_set_function(slot_value(global_slot(sc->vector_symbol)), vector_pf);
  44932. s7_gf_set_function(slot_value(global_slot(sc->c_pointer_symbol)), c_pointer_pf);
  44933. s7_gf_set_function(slot_value(global_slot(sc->vector_dimensions_symbol)), vector_dimensions_pf);
  44934. s7_gf_set_function(slot_value(global_slot(sc->make_shared_vector_symbol)), make_shared_vector_pf);
  44935. s7_gf_set_function(slot_value(global_slot(sc->make_vector_symbol)), make_vector_pf);
  44936. s7_gf_set_function(slot_value(global_slot(sc->make_float_vector_symbol)), make_float_vector_pf);
  44937. s7_gf_set_function(slot_value(global_slot(sc->make_int_vector_symbol)), make_int_vector_pf);
  44938. s7_gf_set_function(slot_value(global_slot(sc->make_list_symbol)), make_list_pf);
  44939. s7_gf_set_function(slot_value(global_slot(sc->make_string_symbol)), make_string_pf);
  44940. s7_pf_set_function(slot_value(global_slot(sc->memq_symbol)), memq_pf);
  44941. s7_pf_set_function(slot_value(global_slot(sc->memv_symbol)), memv_pf);
  44942. s7_pf_set_function(slot_value(global_slot(sc->assq_symbol)), assq_pf);
  44943. s7_pf_set_function(slot_value(global_slot(sc->assv_symbol)), assv_pf);
  44944. #if (!WITH_PURE_S7)
  44945. s7_gf_set_function(slot_value(global_slot(sc->list_to_vector_symbol)), list_to_vector_pf);
  44946. s7_gf_set_function(slot_value(global_slot(sc->vector_to_list_symbol)), vector_to_list_pf);
  44947. s7_gf_set_function(slot_value(global_slot(sc->string_to_list_symbol)), string_to_list_pf);
  44948. s7_gf_set_function(slot_value(global_slot(sc->let_to_list_symbol)), let_to_list_pf);
  44949. #endif
  44950. s7_gf_set_function(slot_value(global_slot(sc->random_state_to_list_symbol)), random_state_to_list_pf);
  44951. s7_pf_set_function(slot_value(global_slot(sc->is_aritable_symbol)), is_aritable_pf);
  44952. s7_pf_set_function(slot_value(global_slot(sc->is_boolean_symbol)), is_boolean_pf);
  44953. s7_pf_set_function(slot_value(global_slot(sc->is_byte_vector_symbol)), is_byte_vector_pf);
  44954. s7_pf_set_function(slot_value(global_slot(sc->is_char_symbol)), is_char_pf);
  44955. s7_pf_set_function(slot_value(global_slot(sc->is_complex_symbol)), is_complex_pf);
  44956. s7_pf_set_function(slot_value(global_slot(sc->is_constant_symbol)), is_constant_pf);
  44957. s7_pf_set_function(slot_value(global_slot(sc->is_continuation_symbol)), is_continuation_pf);
  44958. s7_pf_set_function(slot_value(global_slot(sc->is_c_pointer_symbol)), is_c_pointer_pf);
  44959. s7_pf_set_function(slot_value(global_slot(sc->is_dilambda_symbol)), is_dilambda_pf);
  44960. s7_pf_set_function(slot_value(global_slot(sc->is_eof_object_symbol)), is_eof_object_pf);
  44961. s7_pf_set_function(slot_value(global_slot(sc->is_float_vector_symbol)), is_float_vector_pf);
  44962. s7_pf_set_function(slot_value(global_slot(sc->is_gensym_symbol)), is_gensym_pf);
  44963. s7_pf_set_function(slot_value(global_slot(sc->is_hash_table_symbol)), is_hash_table_pf);
  44964. s7_pf_set_function(slot_value(global_slot(sc->is_input_port_symbol)), is_input_port_pf);
  44965. s7_pf_set_function(slot_value(global_slot(sc->is_integer_symbol)), is_integer_pf);
  44966. s7_pf_set_function(slot_value(global_slot(sc->is_int_vector_symbol)), is_int_vector_pf);
  44967. s7_pf_set_function(slot_value(global_slot(sc->is_keyword_symbol)), is_keyword_pf);
  44968. s7_pf_set_function(slot_value(global_slot(sc->is_let_symbol)), is_let_pf);
  44969. s7_pf_set_function(slot_value(global_slot(sc->is_list_symbol)), is_list_pf);
  44970. s7_pf_set_function(slot_value(global_slot(sc->is_macro_symbol)), is_macro_pf);
  44971. s7_pf_set_function(slot_value(global_slot(sc->is_null_symbol)), is_null_pf);
  44972. s7_pf_set_function(slot_value(global_slot(sc->is_number_symbol)), is_number_pf);
  44973. s7_pf_set_function(slot_value(global_slot(sc->is_output_port_symbol)), is_output_port_pf);
  44974. s7_pf_set_function(slot_value(global_slot(sc->is_pair_symbol)), is_pair_pf);
  44975. s7_pf_set_function(slot_value(global_slot(sc->is_procedure_symbol)), is_procedure_pf);
  44976. s7_pf_set_function(slot_value(global_slot(sc->is_provided_symbol)), is_provided_pf);
  44977. s7_pf_set_function(slot_value(global_slot(sc->is_random_state_symbol)), is_random_state_pf);
  44978. s7_pf_set_function(slot_value(global_slot(sc->is_rational_symbol)), is_rational_pf);
  44979. s7_pf_set_function(slot_value(global_slot(sc->is_real_symbol)), is_real_pf);
  44980. s7_pf_set_function(slot_value(global_slot(sc->is_string_symbol)), is_string_pf);
  44981. s7_pf_set_function(slot_value(global_slot(sc->is_symbol_symbol)), is_symbol_pf);
  44982. s7_pf_set_function(slot_value(global_slot(sc->is_vector_symbol)), is_vector_pf);
  44983. s7_pf_set_function(slot_value(global_slot(sc->is_iterator_symbol)), is_iterator_pf);
  44984. s7_pf_set_function(slot_value(global_slot(sc->iterator_is_at_end_symbol)), iterator_is_at_end_pf);
  44985. s7_pf_set_function(slot_value(global_slot(sc->iterator_sequence_symbol)), iterator_sequence_pf);
  44986. s7_pf_set_function(slot_value(global_slot(sc->iterate_symbol)), iterate_pf);
  44987. s7_gf_set_function(slot_value(global_slot(sc->iterate_symbol)), iterate_gf);
  44988. s7_gf_set_function(slot_value(global_slot(sc->make_iterator_symbol)), make_iterator_pf);
  44989. #if (!WITH_GMP)
  44990. s7_gf_set_function(slot_value(global_slot(sc->random_state_symbol)), random_state_pf);
  44991. #endif
  44992. s7_pf_set_function(slot_value(global_slot(sc->reverseb_symbol)), reverse_in_place_pf);
  44993. s7_gf_set_function(slot_value(global_slot(sc->sort_symbol)), sort_pf);
  44994. s7_pf_set_function(slot_value(global_slot(sc->provide_symbol)), provide_pf);
  44995. s7_pf_set_function(slot_value(global_slot(sc->symbol_symbol)), symbol_pf);
  44996. s7_pf_set_function(slot_value(global_slot(sc->string_to_symbol_symbol)), string_to_symbol_pf);
  44997. s7_gf_set_function(slot_value(global_slot(sc->symbol_to_string_symbol)), symbol_to_string_pf);
  44998. s7_pf_set_function(slot_value(global_slot(sc->make_keyword_symbol)), make_keyword_pf);
  44999. s7_pf_set_function(slot_value(global_slot(sc->keyword_to_symbol_symbol)), keyword_to_symbol_pf);
  45000. s7_pf_set_function(slot_value(global_slot(sc->symbol_to_keyword_symbol)), symbol_to_keyword_pf);
  45001. s7_pf_set_function(slot_value(global_slot(sc->symbol_to_value_symbol)), symbol_to_value_pf);
  45002. s7_gf_set_function(slot_value(global_slot(sc->gensym_symbol)), gensym_pf);
  45003. s7_gf_set_function(slot_value(global_slot(sc->arity_symbol)), arity_pf);
  45004. s7_pf_set_function(slot_value(global_slot(sc->is_openlet_symbol)), is_openlet_pf);
  45005. s7_pf_set_function(slot_value(global_slot(sc->curlet_symbol)), curlet_pf);
  45006. s7_pf_set_function(slot_value(global_slot(sc->owlet_symbol)), owlet_pf);
  45007. s7_pf_set_function(slot_value(global_slot(sc->rootlet_symbol)), rootlet_pf);
  45008. s7_pf_set_function(slot_value(global_slot(sc->outlet_symbol)), outlet_pf);
  45009. s7_pf_set_function(slot_value(global_slot(sc->openlet_symbol)), openlet_pf);
  45010. s7_pf_set_function(slot_value(global_slot(sc->coverlet_symbol)), coverlet_pf);
  45011. s7_pf_set_function(slot_value(global_slot(sc->funclet_symbol)), funclet_pf);
  45012. s7_pf_set_function(slot_value(global_slot(sc->cutlet_symbol)), cutlet_pf);
  45013. s7_pf_set_function(slot_value(global_slot(sc->varlet_symbol)), varlet_pf);
  45014. s7_pf_set_function(slot_value(global_slot(sc->unlet_symbol)), unlet_pf);
  45015. s7_gf_set_function(slot_value(global_slot(sc->inlet_symbol)), inlet_pf);
  45016. s7_pf_set_function(slot_value(global_slot(sc->gc_symbol)), gc_pf);
  45017. s7_gf_set_function(slot_value(global_slot(sc->help_symbol)), help_pf);
  45018. s7_gf_set_function(slot_value(global_slot(sc->procedure_source_symbol)), procedure_source_pf);
  45019. s7_gf_set_function(slot_value(global_slot(sc->procedure_documentation_symbol)), procedure_documentation_pf);
  45020. s7_gf_set_function(slot_value(global_slot(sc->procedure_signature_symbol)), procedure_signature_pf);
  45021. s7_pf_set_function(slot_value(global_slot(sc->is_char_alphabetic_symbol)), is_char_alphabetic_pf);
  45022. s7_pf_set_function(slot_value(global_slot(sc->is_char_lower_case_symbol)), is_char_lower_case_pf);
  45023. s7_pf_set_function(slot_value(global_slot(sc->is_char_numeric_symbol)), is_char_numeric_pf);
  45024. s7_pf_set_function(slot_value(global_slot(sc->is_char_upper_case_symbol)), is_char_upper_case_pf);
  45025. s7_pf_set_function(slot_value(global_slot(sc->is_char_whitespace_symbol)), is_char_whitespace_pf);
  45026. s7_pf_set_function(slot_value(global_slot(sc->char_upcase_symbol)), char_upcase_pf);
  45027. s7_pf_set_function(slot_value(global_slot(sc->char_downcase_symbol)), char_downcase_pf);
  45028. s7_pf_set_function(slot_value(global_slot(sc->integer_to_char_symbol)), integer_to_char_pf);
  45029. s7_pf_set_function(slot_value(global_slot(sc->current_input_port_symbol)), current_input_port_pf);
  45030. s7_pf_set_function(slot_value(global_slot(sc->current_output_port_symbol)), current_output_port_pf);
  45031. s7_pf_set_function(slot_value(global_slot(sc->current_error_port_symbol)), current_error_port_pf);
  45032. s7_pf_set_function(slot_value(global_slot(sc->close_input_port_symbol)), close_input_port_pf);
  45033. s7_pf_set_function(slot_value(global_slot(sc->close_output_port_symbol)), close_output_port_pf);
  45034. s7_pf_set_function(slot_value(global_slot(sc->flush_output_port_symbol)), flush_output_port_pf);
  45035. s7_gf_set_function(slot_value(global_slot(sc->port_filename_symbol)), port_filename_pf);
  45036. s7_gf_set_function(slot_value(global_slot(sc->port_line_number_symbol)), port_line_number_pf);
  45037. s7_pf_set_function(slot_value(global_slot(sc->with_input_from_file_symbol)), with_input_from_file_pf);
  45038. s7_pf_set_function(slot_value(global_slot(sc->with_input_from_string_symbol)), with_input_from_string_pf);
  45039. s7_gf_set_function(slot_value(global_slot(sc->with_output_to_string_symbol)), with_output_to_string_pf);
  45040. s7_pf_set_function(slot_value(global_slot(sc->with_output_to_file_symbol)), with_output_to_file_pf);
  45041. s7_gf_set_function(slot_value(global_slot(sc->call_with_output_string_symbol)), call_with_output_string_pf);
  45042. s7_pf_set_function(slot_value(global_slot(sc->call_with_output_file_symbol)), call_with_output_file_pf);
  45043. s7_pf_set_function(slot_value(global_slot(sc->call_with_input_string_symbol)), call_with_input_string_pf);
  45044. s7_pf_set_function(slot_value(global_slot(sc->call_with_input_file_symbol)), call_with_input_file_pf);
  45045. #if WITH_SYSTEM_EXTRAS
  45046. s7_gf_set_function(slot_value(global_slot(sc->directory_to_list_symbol)), directory_to_list_pf);
  45047. #endif
  45048. s7_if_set_function(slot_value(global_slot(sc->write_byte_symbol)), write_byte_if);
  45049. s7_pf_set_function(slot_value(global_slot(sc->write_char_symbol)), write_char_pf);
  45050. s7_pf_set_function(slot_value(global_slot(sc->read_byte_symbol)), read_byte_pf);
  45051. s7_pf_set_function(slot_value(global_slot(sc->read_char_symbol)), read_char_pf);
  45052. s7_pf_set_function(slot_value(global_slot(sc->peek_char_symbol)), peek_char_pf);
  45053. s7_pf_set_function(slot_value(global_slot(sc->newline_symbol)), newline_pf);
  45054. s7_pf_set_function(slot_value(global_slot(sc->write_symbol)), write_pf);
  45055. s7_pf_set_function(slot_value(global_slot(sc->write_string_symbol)), write_string_pf);
  45056. s7_gf_set_function(slot_value(global_slot(sc->read_string_symbol)), read_string_pf);
  45057. s7_pf_set_function(slot_value(global_slot(sc->display_symbol)), display_pf);
  45058. s7_gf_set_function(slot_value(global_slot(sc->read_symbol)), read_pf);
  45059. s7_gf_set_function(slot_value(global_slot(sc->read_line_symbol)), read_line_pf);
  45060. s7_gf_set_function(slot_value(global_slot(sc->object_to_string_symbol)), object_to_string_pf);
  45061. s7_pf_set_function(slot_value(global_slot(sc->is_eq_symbol)), is_eq_pf);
  45062. s7_pf_set_function(slot_value(global_slot(sc->is_eqv_symbol)), is_eqv_pf);
  45063. s7_pf_set_function(slot_value(global_slot(sc->is_equal_symbol)), is_equal_pf);
  45064. s7_pf_set_function(slot_value(global_slot(sc->is_morally_equal_symbol)), is_morally_equal_pf);
  45065. /* + */
  45066. f = set_function_chooser(sc, sc->add_symbol, add_chooser);
  45067. sc->add_class = c_function_class(f);
  45068. add_2 = make_function_with_class(sc, f, "+", g_add_2, 2, 0, false, "+ opt");
  45069. add_1s = make_function_with_class(sc, f, "+", g_add_1s, 2, 0, false, "+ opt");
  45070. add_s1 = make_function_with_class(sc, f, "+", g_add_s1, 2, 0, false, "+ opt");
  45071. add_cs1 = make_function_with_class(sc, f, "+", g_add_cs1, 2, 0, false, "+ opt");
  45072. add_si = make_function_with_class(sc, f, "+", g_add_si, 2, 0, false, "+ opt");
  45073. add_sf = make_function_with_class(sc, f, "+", g_add_sf, 2, 0, false, "+ opt");
  45074. add_fs = make_function_with_class(sc, f, "+", g_add_fs, 2, 0, false, "+ opt");
  45075. add_ss_1ss = make_function_with_class(sc, f, "+", g_add_ss_1ss, 2, 0, false, "+ opt");
  45076. add_f_sf = make_function_with_class(sc, f, "+", g_add_f_sf, 2, 0, false, "+ opt");
  45077. /* - */
  45078. f = set_function_chooser(sc, sc->subtract_symbol, subtract_chooser);
  45079. sc->subtract_class = c_function_class(f);
  45080. subtract_1 = make_function_with_class(sc, f, "-", g_subtract_1, 1, 0, false, "- opt");
  45081. subtract_2 = make_function_with_class(sc, f, "-", g_subtract_2, 2, 0, false, "- opt");
  45082. subtract_s1 = make_function_with_class(sc, f, "-", g_subtract_s1, 2, 0, false, "- opt");
  45083. subtract_cs1 = make_function_with_class(sc, f, "-", g_subtract_cs1, 2, 0, false, "- opt");
  45084. subtract_csn = make_function_with_class(sc, f, "-", g_subtract_csn, 2, 0, false, "- opt");
  45085. subtract_sf = make_function_with_class(sc, f, "-", g_subtract_sf, 2, 0, false, "- opt");
  45086. subtract_2f = make_function_with_class(sc, f, "-", g_subtract_2f, 2, 0, false, "- opt");
  45087. subtract_fs = make_function_with_class(sc, f, "-", g_subtract_fs, 2, 0, false, "- opt");
  45088. subtract_f_sqr = make_function_with_class(sc, f, "-", g_subtract_f_sqr, 2, 0, false, "- opt");
  45089. #if (!WITH_GMP)
  45090. sub_random_ic = make_function_with_class(sc, f, "random", g_sub_random_ic, 2, 0, false, "- opt");
  45091. sub_random_rc = make_function_with_class(sc, f, "random", g_sub_random_rc, 2, 0, false, "- opt");
  45092. #endif
  45093. /* * */
  45094. f = set_function_chooser(sc, sc->multiply_symbol, multiply_chooser);
  45095. sc->multiply_class = c_function_class(f);
  45096. #if (!WITH_GMP)
  45097. multiply_2 = make_function_with_class(sc, f, "*", g_multiply_2, 2, 0, false, "* opt");
  45098. multiply_is = make_function_with_class(sc, f, "*", g_multiply_is, 2, 0, false, "* opt");
  45099. multiply_si = make_function_with_class(sc, f, "*", g_multiply_si, 2, 0, false, "* opt");
  45100. multiply_fs = make_function_with_class(sc, f, "*", g_multiply_fs, 2, 0, false, "* opt");
  45101. multiply_sf = make_function_with_class(sc, f, "*", g_multiply_sf, 2, 0, false, "* opt");
  45102. sqr_ss = make_function_with_class(sc, f, "*", g_sqr_ss, 2, 0, false, "* opt");
  45103. mul_1ss = make_function_with_class(sc, f, "*", g_mul_1ss, 2, 0, false, "* opt");
  45104. multiply_cs_cos = make_function_with_class(sc, f, "*", g_multiply_cs_cos, 3, 0, false, "* opt");
  45105. mul_s_sin_s = make_function_with_class(sc, f, "*", g_mul_s_sin_s, 2, 0, false, "* opt");
  45106. mul_s_cos_s = make_function_with_class(sc, f, "*", g_mul_s_cos_s, 2, 0, false, "* opt");
  45107. #endif
  45108. /* / */
  45109. f = set_function_chooser(sc, sc->divide_symbol, divide_chooser);
  45110. #if (!WITH_GMP)
  45111. invert_1 = make_function_with_class(sc, f, "/", g_invert_1, 1, 0, false, "/ opt");
  45112. divide_1r = make_function_with_class(sc, f, "/", g_divide_1r, 2, 0, false, "/ opt");
  45113. /* modulo */
  45114. f = set_function_chooser(sc, sc->modulo_symbol, modulo_chooser);
  45115. mod_si = make_function_with_class(sc, f, "modulo", g_mod_si, 2, 0, false, "modulo opt");
  45116. /* max */
  45117. f = set_function_chooser(sc, sc->max_symbol, max_chooser);
  45118. max_f2 = make_function_with_class(sc, f, "max", g_max_f2, 2, 0, false, "max opt");
  45119. /* min */
  45120. f = set_function_chooser(sc, sc->min_symbol, min_chooser);
  45121. min_f2 = make_function_with_class(sc, f, "min", g_min_f2, 2, 0, false, "min opt");
  45122. /* zero? */
  45123. set_function_chooser(sc, sc->is_zero_symbol, is_zero_chooser);
  45124. /* = */
  45125. f = set_function_chooser(sc, sc->eq_symbol, equal_chooser);
  45126. sc->equal_class = c_function_class(f);
  45127. equal_s_ic = make_function_with_class(sc, f, "=", g_equal_s_ic, 2, 0, false, "= opt");
  45128. equal_length_ic = make_function_with_class(sc, f, "=", g_equal_length_ic, 2, 0, false, "= opt");
  45129. equal_2 = make_function_with_class(sc, f, "=", g_equal_2, 2, 0, false, "= opt");
  45130. mod_si_is_zero = make_function_with_class(sc, f, "=", g_mod_si_is_zero, 2, 0, false, "= opt");
  45131. /* < */
  45132. f = set_function_chooser(sc, sc->lt_symbol, less_chooser);
  45133. less_s_ic = make_function_with_class(sc, f, "<", g_less_s_ic, 2, 0, false, "< opt");
  45134. less_s0 = make_function_with_class(sc, f, "<", g_less_s0, 2, 0, false, "< opt");
  45135. less_2 = make_function_with_class(sc, f, "<", g_less_2, 2, 0, false, "< opt");
  45136. less_length_ic = make_function_with_class(sc, f, "<", g_less_length_ic, 2, 0, false, "< opt");
  45137. /* > */
  45138. f = set_function_chooser(sc, sc->gt_symbol, greater_chooser);
  45139. greater_s_ic = make_function_with_class(sc, f, ">", g_greater_s_ic, 2, 0, false, "> opt");
  45140. greater_s_fc = make_function_with_class(sc, f, ">", g_greater_s_fc, 2, 0, false, "> opt");
  45141. greater_2 = make_function_with_class(sc, f, ">", g_greater_2, 2, 0, false, "> opt");
  45142. greater_2_f = make_function_with_class(sc, f, ">", g_greater_2_f, 2, 0, false, "> opt");
  45143. /* <= */
  45144. f = set_function_chooser(sc, sc->leq_symbol, leq_chooser);
  45145. leq_s_ic = make_function_with_class(sc, f, "<=", g_leq_s_ic, 2, 0, false, "<= opt");
  45146. leq_2 = make_function_with_class(sc, f, "<=", g_leq_2, 2, 0, false, "<= opt");
  45147. /* >= */
  45148. f = set_function_chooser(sc, sc->geq_symbol, geq_chooser);
  45149. geq_s_ic = make_function_with_class(sc, f, ">=", g_geq_s_ic, 2, 0, false, ">= opt");
  45150. geq_s_fc = make_function_with_class(sc, f, ">=", g_geq_s_fc, 2, 0, false, ">= opt");
  45151. geq_2 = make_function_with_class(sc, f, ">=", g_geq_2, 2, 0, false, ">= opt");
  45152. geq_length_ic = make_function_with_class(sc, f, ">=", g_geq_length_ic, 2, 0, false, ">= opt");
  45153. /* random */
  45154. f = set_function_chooser(sc, sc->random_symbol, random_chooser);
  45155. random_i = make_function_with_class(sc, f, "random", g_random_i, 1, 0, false, "random opt");
  45156. random_ic = make_function_with_class(sc, f, "random", g_random_ic, 1, 0, false, "random opt");
  45157. random_rc = make_function_with_class(sc, f, "random", g_random_rc, 1, 0, false, "random opt");
  45158. #endif
  45159. /* list */
  45160. f = set_function_chooser(sc, sc->list_symbol, list_chooser);
  45161. list_0 = make_function_with_class(sc, f, "list", g_list_0, 0, 0, false, "list opt");
  45162. list_1 = make_function_with_class(sc, f, "list", g_list_1, 1, 0, false, "list opt");
  45163. list_2 = make_function_with_class(sc, f, "list", g_list_2, 2, 0, false, "list opt");
  45164. /* aritable? */
  45165. f = set_function_chooser(sc, sc->is_aritable_symbol, is_aritable_chooser);
  45166. is_aritable_ic = make_function_with_class(sc, f, "aritable?", g_is_aritable_ic, 2, 0, false, "aritable? opt");
  45167. /* char=? */
  45168. f = set_function_chooser(sc, sc->char_eq_symbol, char_equal_chooser);
  45169. simple_char_eq = make_function_with_class(sc, f, "char=?", g_simple_char_eq, 2, 0, false, "char=? opt");
  45170. char_equal_s_ic = make_function_with_class(sc, f, "char=?", g_char_equal_s_ic, 2, 0, false, "char=? opt");
  45171. char_equal_2 = make_function_with_class(sc, f, "char=?", g_char_equal_2, 2, 0, false, "char=? opt");
  45172. /* char>? */
  45173. f = set_function_chooser(sc, sc->char_gt_symbol, char_greater_chooser);
  45174. char_greater_s_ic = make_function_with_class(sc, f, "char>?", g_char_greater_s_ic, 2, 0, false, "char>? opt");
  45175. char_greater_2 = make_function_with_class(sc, f, "char>?", g_char_greater_2, 2, 0, false, "char>? opt");
  45176. /* char<? */
  45177. f = set_function_chooser(sc, sc->char_lt_symbol, char_less_chooser);
  45178. char_less_s_ic = make_function_with_class(sc, f, "char<?", g_char_less_s_ic, 2, 0, false, "char<? opt");
  45179. char_less_2 = make_function_with_class(sc, f, "char<?", g_char_less_2, 2, 0, false, "char<? opt");
  45180. /* char-position */
  45181. f = set_function_chooser(sc, sc->char_position_symbol, char_position_chooser);
  45182. char_position_csi = make_function_with_class(sc, f, "char-position", g_char_position_csi, 2, 1, false, "char-position opt");
  45183. /* string->symbol */
  45184. set_function_chooser(sc, sc->string_to_symbol_symbol, string_to_symbol_chooser);
  45185. /* string=? */
  45186. f = set_function_chooser(sc, sc->string_eq_symbol, string_equal_chooser);
  45187. string_equal_s_ic = make_function_with_class(sc, f, "string=?", g_string_equal_s_ic, 2, 0, false, "string=? opt");
  45188. string_equal_2 = make_function_with_class(sc, f, "string=?", g_string_equal_2, 2, 0, false, "string=? opt");
  45189. /* substring */
  45190. substring_to_temp = s7_make_function(sc, "substring", g_substring_to_temp, 2, 1, false, "substring opt");
  45191. s7_function_set_class(substring_to_temp, slot_value(global_slot(sc->substring_symbol)));
  45192. /* number->string */
  45193. number_to_string_temp = s7_make_function(sc, "number->string", g_number_to_string_temp, 1, 1, false, "number->string opt");
  45194. s7_function_set_class(number_to_string_temp, slot_value(global_slot(sc->number_to_string_symbol)));
  45195. /* string>? */
  45196. f = set_function_chooser(sc, sc->string_gt_symbol, string_greater_chooser);
  45197. string_greater_2 = make_function_with_class(sc, f, "string>?", g_string_greater_2, 2, 0, false, "string>? opt");
  45198. /* string<? */
  45199. f = set_function_chooser(sc, sc->string_lt_symbol, string_less_chooser);
  45200. string_less_2 = make_function_with_class(sc, f, "string<?", g_string_less_2, 2, 0, false, "string<? opt");
  45201. /* string-ref */
  45202. set_function_chooser(sc, sc->string_ref_symbol, string_ref_chooser);
  45203. /* string-set! */
  45204. set_function_chooser(sc, sc->string_set_symbol, string_set_chooser);
  45205. /* string-append */
  45206. f = set_function_chooser(sc, sc->string_append_symbol, string_append_chooser);
  45207. string_append_to_temp = make_function_with_class(sc, f, "string-append", g_string_append_to_temp, 0, 0, true, "string-append opt");
  45208. /* symbol->string */
  45209. f = slot_value(global_slot(sc->symbol_to_string_symbol));
  45210. symbol_to_string_uncopied = s7_make_function(sc, "symbol->string", g_symbol_to_string_uncopied, 1, 0, false, "symbol->string opt");
  45211. s7_function_set_class(symbol_to_string_uncopied, f);
  45212. /* vector-ref */
  45213. f = set_function_chooser(sc, sc->vector_ref_symbol, vector_ref_chooser);
  45214. vector_ref_ic = make_function_with_class(sc, f, "vector-ref", g_vector_ref_ic, 2, 0, false, "vector-ref opt");
  45215. vector_ref_ic_0 = make_function_with_class(sc, f, "vector-ref", g_vector_ref_ic_0, 1, 0, false, "vector-ref opt");
  45216. vector_ref_ic_1 = make_function_with_class(sc, f, "vector-ref", g_vector_ref_ic_1, 1, 0, false, "vector-ref opt");
  45217. vector_ref_ic_2 = make_function_with_class(sc, f, "vector-ref", g_vector_ref_ic_2, 1, 0, false, "vector-ref opt");
  45218. vector_ref_ic_3 = make_function_with_class(sc, f, "vector-ref", g_vector_ref_ic_3, 1, 0, false, "vector-ref opt");
  45219. vector_ref_add1 = make_function_with_class(sc, f, "vector-ref", g_vector_ref_add1, 2, 0, false, "vector-ref opt");
  45220. vector_ref_2 = make_function_with_class(sc, f, "vector-ref", g_vector_ref_2, 2, 0, false, "vector-ref opt");
  45221. vector_ref_gs = make_function_with_class(sc, f, "vector-ref", g_vector_ref_gs, 2, 0, false, "vector-ref opt");
  45222. constant_vector_ref_gs = make_function_with_class(sc, f, "vector-ref", g_constant_vector_ref_gs, 2, 0, false, "vector-ref opt");
  45223. /* vector-set! */
  45224. f = set_function_chooser(sc, sc->vector_set_symbol, vector_set_chooser);
  45225. vector_set_ic = make_function_with_class(sc, f, "vector-set!", g_vector_set_ic, 3, 0, false, "vector-set! opt");
  45226. vector_set_vref = make_function_with_class(sc, f, "vector-set!", g_vector_set_vref, 3, 0, false, "vector-set! opt");
  45227. vector_set_vector_ref = make_function_with_class(sc, f, "vector-set!", g_vector_set_vector_ref, 3, 0, false, "vector-set! opt");
  45228. vector_set_3 = make_function_with_class(sc, f, "vector-set!", g_vector_set_3, 3, 0, false, "vector-set! opt");
  45229. /* list-ref */
  45230. f = set_function_chooser(sc, sc->list_ref_symbol, list_ref_chooser);
  45231. list_ref_ic = make_function_with_class(sc, f, "list-ref", g_list_ref_ic, 2, 0, false, "list-ref opt");
  45232. /* list-set! */
  45233. f = set_function_chooser(sc, sc->list_set_symbol, list_set_chooser);
  45234. list_set_ic = make_function_with_class(sc, f, "list-set!", g_list_set_ic, 3, 0, false, "list-set! opt");
  45235. /* hash-table-ref */
  45236. f = set_function_chooser(sc, sc->hash_table_ref_symbol, hash_table_ref_chooser);
  45237. hash_table_ref_2 = make_function_with_class(sc, f, "hash-table-ref", g_hash_table_ref_2, 2, 0, false, "hash-table-ref opt");
  45238. hash_table_ref_ss = make_function_with_class(sc, f, "hash-table-ref", g_hash_table_ref_ss, 2, 0, false, "hash-table-ref opt");
  45239. hash_table_ref_car = make_function_with_class(sc, f, "hash-table-ref", g_hash_table_ref_car, 2, 0, false, "hash-table-ref opt");
  45240. /* format */
  45241. f = set_function_chooser(sc, sc->format_symbol, format_chooser);
  45242. format_allg = make_function_with_class(sc, f, "format", g_format_allg, 1, 0, true, "format opt");
  45243. format_allg_no_column = make_function_with_class(sc, f, "format", g_format_allg_no_column, 1, 0, true, "format opt");
  45244. format_just_newline = make_function_with_class(sc, f, "format", g_format_just_newline, 2, 0, false, "format opt");
  45245. /* not */
  45246. f = set_function_chooser(sc, sc->not_symbol, not_chooser);
  45247. not_is_pair = make_function_with_class(sc, f, "not", g_not_is_pair, 1, 0, false, "not opt");
  45248. not_is_null = make_function_with_class(sc, f, "not", g_not_is_null, 1, 0, false, "not opt");
  45249. not_is_list = make_function_with_class(sc, f, "not", g_not_is_list, 1, 0, false, "not opt");
  45250. not_is_symbol = make_function_with_class(sc, f, "not", g_not_is_symbol, 1, 0, false, "not opt");
  45251. not_is_number = make_function_with_class(sc, f, "not", g_not_is_number, 1, 0, false, "not opt");
  45252. not_is_zero = make_function_with_class(sc, f, "not", g_not_is_zero, 1, 0, false, "not opt");
  45253. not_is_string = make_function_with_class(sc, f, "not", g_not_is_string, 1, 0, false, "not opt");
  45254. not_is_char = make_function_with_class(sc, f, "not", g_not_is_char, 1, 0, false, "not opt");
  45255. not_is_eq_ss = make_function_with_class(sc, f, "not", g_not_is_eq_ss, 1, 0, false, "not opt");
  45256. not_is_eq_sq = make_function_with_class(sc, f, "not", g_not_is_eq_sq, 1, 0, false, "not opt");
  45257. not_is_pair_car = make_function_with_class(sc, f, "not", g_not_is_pair_car, 1, 0, false, "not opt");
  45258. not_c_c = make_function_with_class(sc, f, "not", g_not_c_c, 1, 0, false, "not opt");
  45259. /* pair? */
  45260. f = set_function_chooser(sc, sc->is_pair_symbol, is_pair_chooser);
  45261. is_pair_car = make_function_with_class(sc, f, "pair?", g_is_pair_car, 1, 0, false, "pair? opt");
  45262. is_pair_cdr = make_function_with_class(sc, f, "pair?", g_is_pair_cdr, 1, 0, false, "pair? opt");
  45263. is_pair_cadr = make_function_with_class(sc, f, "pair?", g_is_pair_cadr, 1, 0, false, "pair? opt");
  45264. /* null? */
  45265. f = set_function_chooser(sc, sc->is_null_symbol, is_null_chooser);
  45266. is_null_cdr = make_function_with_class(sc, f, "null?", g_is_null_cdr, 1, 0, false, "null? opt");
  45267. /* eq? */
  45268. f = set_function_chooser(sc, sc->is_eq_symbol, is_eq_chooser);
  45269. is_eq_car = make_function_with_class(sc, f, "eq?", g_is_eq_car, 2, 0, false, "eq? opt");
  45270. is_eq_car_q = make_function_with_class(sc, f, "eq?", g_is_eq_car_q, 2, 0, false, "eq? opt");
  45271. is_eq_caar_q = make_function_with_class(sc, f, "eq?", g_is_eq_caar_q, 2, 0, false, "eq? opt");
  45272. /* member */
  45273. f = set_function_chooser(sc, sc->member_symbol, member_chooser);
  45274. member_ss = make_function_with_class(sc, f, "member", g_member_ss, 2, 0, false, "member opt");
  45275. member_sq = make_function_with_class(sc, f, "member", g_member_sq, 2, 0, false, "member opt");
  45276. member_num_s = make_function_with_class(sc, f, "member", g_member_num_s, 2, 0, false, "member opt");
  45277. /* memq */
  45278. f = set_function_chooser(sc, sc->memq_symbol, memq_chooser);
  45279. /* is pure-s7, use member here */
  45280. memq_3 = make_function_with_class(sc, f, "memq", g_memq_3, 2, 0, false, "memq opt");
  45281. memq_4 = make_function_with_class(sc, f, "memq", g_memq_4, 2, 0, false, "memq opt");
  45282. memq_any = make_function_with_class(sc, f, "memq", g_memq_any, 2, 0, false, "memq opt");
  45283. memq_car = make_function_with_class(sc, f, "memq", g_memq_car, 2, 0, false, "memq opt");
  45284. /* read-char */
  45285. f = set_function_chooser(sc, sc->read_char_symbol, read_char_chooser);
  45286. read_char_0 = make_function_with_class(sc, f, "read-char", g_read_char_0, 0, 0, false, "read-char opt");
  45287. read_char_1 = make_function_with_class(sc, f, "read-char", g_read_char_1, 1, 0, false, "read-char opt");
  45288. /* write-char */
  45289. f = set_function_chooser(sc, sc->write_char_symbol, write_char_chooser);
  45290. write_char_1 = make_function_with_class(sc, f, "write-char", g_write_char_1, 1, 0, false, "write-char opt");
  45291. /* read-line */
  45292. read_line_uncopied = s7_make_function(sc, "read-line", g_read_line_uncopied, 1, 1, false, "read-line opt");
  45293. s7_function_set_class(read_line_uncopied, slot_value(global_slot(sc->read_line_symbol)));
  45294. /* write-string */
  45295. set_function_chooser(sc, sc->write_string_symbol, write_string_chooser);
  45296. /* eval-string */
  45297. set_function_chooser(sc, sc->eval_string_symbol, eval_string_chooser);
  45298. /* or and if simple cases */
  45299. or_direct = s7_make_function(sc, "or", g_or_direct, 0, 0, true, "or opt");
  45300. and_direct = s7_make_function(sc, "and", g_and_direct, 0, 0, true, "and opt");
  45301. if_direct = s7_make_function(sc, "if", g_if_direct, 2, 1, false, "if opt");
  45302. or_all_x = s7_make_function(sc, "or", g_or_all_x, 0, 0, true, "or opt");
  45303. or_all_x_2 = s7_make_function(sc, "or", g_or_all_x_2, 2, 0, false, "or opt");
  45304. or_all_x_2s = s7_make_function(sc, "or", g_or_all_x_2s, 2, 0, false, "or opt");
  45305. and_all_x = s7_make_function(sc, "and", g_and_all_x, 0, 0, true, "and opt");
  45306. and_all_x_2 = s7_make_function(sc, "and", g_and_all_x_2, 2, 0, false, "and opt");
  45307. if_all_x1 = s7_make_function(sc, "if", g_if_all_x1, 2, 0, false, "if opt");
  45308. if_all_x2 = s7_make_function(sc, "if", g_if_all_x2, 3, 0, false, "if opt");
  45309. if_all_not_x1 = s7_make_function(sc, "if", g_if_all_not_x1, 2, 0, false, "if opt");
  45310. if_all_not_x2 = s7_make_function(sc, "if", g_if_all_not_x2, 3, 0, false, "if opt");
  45311. if_all_x_qq = s7_make_function(sc, "if", g_if_all_x_qq, 3, 0, false, "if opt");
  45312. if_all_x_qa = s7_make_function(sc, "if", g_if_all_x_qa, 3, 0, false, "if opt");
  45313. or_s_direct = s7_make_function(sc, "or", g_or_s_direct, 0, 0, true, "or opt");
  45314. and_s_direct = s7_make_function(sc, "and", g_and_s_direct, 0, 0, true, "and opt");
  45315. if_s_direct = s7_make_function(sc, "if", g_if_s_direct, 2, 1, false, "if opt");
  45316. }
  45317. static s7_pointer collect_collisions(s7_scheme *sc, s7_pointer lst, s7_pointer e)
  45318. {
  45319. /* collect local variable names from let/do (pre-error-check) */
  45320. s7_pointer p;
  45321. sc->w = e;
  45322. for (p = lst; is_pair(p); p = cdr(p))
  45323. if ((is_pair(car(p))) &&
  45324. (is_symbol(caar(p))))
  45325. sc->w = cons(sc, add_sym_to_list(sc, caar(p)), sc->w);
  45326. return(sc->w);
  45327. }
  45328. static s7_pointer collect_collisions_star(s7_scheme *sc, s7_pointer lst, s7_pointer e)
  45329. {
  45330. /* collect local variable names from lambda arglists (pre-error-check) */
  45331. s7_pointer p;
  45332. sc->w = e;
  45333. for (p = lst; is_pair(p); p = cdr(p))
  45334. {
  45335. s7_pointer car_p;
  45336. car_p = car(p);
  45337. if (is_pair(car_p))
  45338. car_p = car(car_p);
  45339. if ((is_symbol(car_p)) &&
  45340. (!is_keyword(car_p)))
  45341. sc->w = cons(sc, add_sym_to_list(sc, car_p), sc->w);
  45342. }
  45343. return(sc->w);
  45344. }
  45345. #define choose_c_function(Sc, Expr, Func, Args) set_c_function(Expr, c_function_chooser(Func)(Sc, Func, Args, Expr))
  45346. static bool optimize_thunk(s7_scheme *sc, s7_pointer expr, s7_pointer func, int hop)
  45347. {
  45348. /* fprintf(stderr, "expr: %s, hop: %d\n", DISPLAY(expr), hop); */
  45349. if (is_immutable_symbol(car(expr)))
  45350. hop = 1;
  45351. if (is_closure(func))
  45352. {
  45353. if (is_null(closure_args(func))) /* no rest arg funny business */
  45354. {
  45355. if (is_safe_closure(func))
  45356. {
  45357. s7_pointer body;
  45358. body = closure_body(func);
  45359. set_unsafe_optimize_op(expr, hop + OP_SAFE_THUNK);
  45360. if (is_null(cdr(body)))
  45361. {
  45362. if (is_optimized(car(body)))
  45363. set_unsafe_optimize_op(expr, hop + OP_SAFE_THUNK_E);
  45364. else
  45365. {
  45366. if ((is_pair(car(body))) &&
  45367. (is_syntactic(caar(body))))
  45368. {
  45369. set_optimize_op(expr, hop + OP_SAFE_THUNK_P);
  45370. if (typesflag(car(body)) != SYNTACTIC_PAIR)
  45371. {
  45372. pair_set_syntax_op(car(body), symbol_syntax_op(caar(body)));
  45373. set_syntactic_pair(car(body));
  45374. }
  45375. }
  45376. }
  45377. }
  45378. }
  45379. else set_unsafe_optimize_op(expr, hop + OP_THUNK);
  45380. set_opt_lambda(expr, func);
  45381. }
  45382. return(false); /* false because currently the C_PP stuff assumes safe procedure calls */
  45383. }
  45384. if (is_c_function(func))
  45385. {
  45386. if (c_function_required_args(func) != 0)
  45387. return(false);
  45388. if ((is_safe_procedure(func)) ||
  45389. (c_function_call(func) == g_list) || /* (list) is safe */
  45390. (c_function_call(func) == g_values)) /* (values) is safe */
  45391. {
  45392. set_safe_optimize_op(expr, hop + OP_SAFE_C_C);
  45393. choose_c_function(sc, expr, func, 0);
  45394. return(true);
  45395. }
  45396. return(false);
  45397. }
  45398. if (is_closure_star(func))
  45399. {
  45400. if ((is_proper_list(sc, closure_args(func))) &&
  45401. (has_simple_args(closure_body(func))))
  45402. {
  45403. set_unsafe_optimize_op(expr, hop + ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_STAR : OP_CLOSURE_STAR));
  45404. set_opt_lambda(expr, func);
  45405. }
  45406. }
  45407. return(false);
  45408. }
  45409. static int combine_ops(s7_scheme *sc, combine_op_t op1, s7_pointer e1, s7_pointer e2)
  45410. {
  45411. int op2;
  45412. op2 = op_no_hop(e2);
  45413. /* e_c_pp case (1) is slightly different from the others: e2 is not a part of e1
  45414. */
  45415. switch (op1)
  45416. {
  45417. case E_C_P:
  45418. switch (op2)
  45419. {
  45420. case OP_SAFE_C_C: return(OP_SAFE_C_opCq); /* this includes the multi-arg C_C cases */
  45421. case OP_SAFE_C_S: return(OP_SAFE_C_opSq);
  45422. case OP_SAFE_C_SS: return(OP_SAFE_C_opSSq);
  45423. case OP_SAFE_C_SQ: return(OP_SAFE_C_opSQq);
  45424. case OP_SAFE_C_SC: return(OP_SAFE_C_opSCq);
  45425. case OP_SAFE_C_CS: return(OP_SAFE_C_opCSq);
  45426. case OP_SAFE_C_opSq: return(OP_SAFE_C_op_opSq_q);
  45427. case OP_SAFE_C_S_opSq: return(OP_SAFE_C_op_S_opSq_q);
  45428. case OP_SAFE_C_A: return(OP_SAFE_C_opAq);
  45429. case OP_SAFE_C_AA: return(OP_SAFE_C_opAAq);
  45430. case OP_SAFE_C_AAA: return(OP_SAFE_C_opAAAq);
  45431. }
  45432. return(OP_SAFE_C_Z); /* this splits out to A in optimize_func_one_arg */
  45433. case E_C_SP:
  45434. switch (op2)
  45435. {
  45436. case OP_SAFE_C_S:
  45437. set_opt_sym1(cdr(e1), cadr(e2));
  45438. return(OP_SAFE_C_S_opSq);
  45439. case OP_SAFE_C_C:
  45440. set_opt_pair1(cdr(e1), cdr(e2));
  45441. return(OP_SAFE_C_S_opCq);
  45442. case OP_SAFE_C_SC:
  45443. set_opt_sym1(cdr(e1), cadr(e2));
  45444. set_opt_con2(cdr(e1), caddr(e2));
  45445. return(OP_SAFE_C_S_opSCq);
  45446. case OP_SAFE_C_CS:
  45447. /* (* a (- 1 b)), e1 is the full expr, e2 is (- 1 b) */
  45448. set_opt_con1(cdr(e1), cadr(e2));
  45449. set_opt_sym2(cdr(e1), caddr(e2));
  45450. return(OP_SAFE_C_S_opCSq);
  45451. case OP_SAFE_C_SS:
  45452. /* (* a (- b c)) */
  45453. set_opt_sym1(cdr(e1), cadr(e2));
  45454. set_opt_sym2(cdr(e1), caddr(e2));
  45455. return(OP_SAFE_C_S_opSSq);
  45456. case OP_SAFE_C_opSSq_S:
  45457. return(OP_SAFE_C_S_op_opSSq_Sq);
  45458. case OP_SAFE_C_S_opSSq:
  45459. return(OP_SAFE_C_S_op_S_opSSqq);
  45460. case OP_SAFE_C_opSSq_opSSq:
  45461. return(OP_SAFE_C_S_op_opSSq_opSSqq);
  45462. case OP_SAFE_C_SZ:
  45463. return(OP_SAFE_C_S_opSZq);
  45464. case OP_SAFE_C_A:
  45465. return(OP_SAFE_C_S_opAq);
  45466. case OP_SAFE_C_AA:
  45467. return(OP_SAFE_C_S_opAAq);
  45468. case OP_SAFE_C_CSA:
  45469. case OP_SAFE_C_CAS:
  45470. case OP_SAFE_C_SCA:
  45471. case OP_SAFE_C_SAS:
  45472. case OP_SAFE_C_SSA:
  45473. case OP_SAFE_C_AAA:
  45474. return(OP_SAFE_C_S_opAAAq);
  45475. }
  45476. /* fprintf(stderr, "%s: %s\n", opt_names[op2], DISPLAY(e1)); */
  45477. return(OP_SAFE_C_SZ);
  45478. case E_C_PS:
  45479. switch (op2)
  45480. {
  45481. case OP_SAFE_C_C: return(OP_SAFE_C_opCq_S);
  45482. case OP_SAFE_C_S: return(OP_SAFE_C_opSq_S);
  45483. case OP_SAFE_C_CS: return(OP_SAFE_C_opCSq_S);
  45484. case OP_SAFE_C_SC: return(OP_SAFE_C_opSCq_S);
  45485. case OP_SAFE_C_SS: return(OP_SAFE_C_opSSq_S);
  45486. case OP_SAFE_C_opSq: return(OP_SAFE_C_op_opSq_q_S);
  45487. case OP_SAFE_C_opSSq: return(OP_SAFE_C_op_opSSq_q_S);
  45488. }
  45489. return(OP_SAFE_C_ZS);
  45490. case E_C_PC:
  45491. switch (op2)
  45492. {
  45493. case OP_SAFE_C_C: return(OP_SAFE_C_opCq_C);
  45494. case OP_SAFE_C_S: return(OP_SAFE_C_opSq_C);
  45495. case OP_SAFE_C_CS: return(OP_SAFE_C_opCSq_C);
  45496. case OP_SAFE_C_SS: return(OP_SAFE_C_opSSq_C);
  45497. case OP_SAFE_C_SC: return(OP_SAFE_C_opSCq_C);
  45498. case OP_SAFE_C_opSq: return(OP_SAFE_C_op_opSq_q_C);
  45499. case OP_SAFE_C_opSSq: return(OP_SAFE_C_op_opSSq_q_C);
  45500. }
  45501. return(OP_SAFE_C_ZC);
  45502. case E_C_CP:
  45503. switch (op2)
  45504. {
  45505. case OP_SAFE_C_C:
  45506. set_opt_pair1(cdr(e1), cdr(e2));
  45507. return(OP_SAFE_C_C_opCq);
  45508. case OP_SAFE_C_S:
  45509. set_opt_sym1(cdr(e1), cadr(e2));
  45510. return(OP_SAFE_C_C_opSq);
  45511. case OP_SAFE_C_CS:
  45512. set_opt_con1(cdr(e1), cadr(e2));
  45513. set_opt_sym2(cdr(e1), caddr(e2));
  45514. return(OP_SAFE_C_C_opCSq);
  45515. case OP_SAFE_C_SC:
  45516. set_opt_sym1(cdr(e1), cadr(e2));
  45517. set_opt_con2(cdr(e1), caddr(e2));
  45518. return(OP_SAFE_C_C_opSCq);
  45519. case OP_SAFE_C_SS:
  45520. set_opt_sym1(cdr(e1), cadr(e2));
  45521. set_opt_sym2(cdr(e1), caddr(e2));
  45522. return(OP_SAFE_C_C_opSSq);
  45523. case OP_SAFE_C_S_opCq:
  45524. return(OP_SAFE_C_C_op_S_opCqq);
  45525. }
  45526. return(OP_SAFE_C_CZ);
  45527. case E_C_PP:
  45528. switch (op2)
  45529. {
  45530. case OP_SAFE_C_S:
  45531. if (optimize_op_match(e1, OP_SAFE_C_S))
  45532. return(OP_SAFE_C_opSq_opSq);
  45533. if (optimize_op_match(e1, OP_SAFE_C_SS))
  45534. return(OP_SAFE_C_opSSq_opSq);
  45535. break;
  45536. case OP_SAFE_C_C:
  45537. if (optimize_op_match(e1, OP_SAFE_C_C))
  45538. return(OP_SAFE_C_opCq_opCq);
  45539. if (optimize_op_match(e1, OP_SAFE_C_SS))
  45540. return(OP_SAFE_C_opSSq_opCq);
  45541. break;
  45542. case OP_SAFE_C_SC:
  45543. if (optimize_op_match(e1, OP_SAFE_C_SC))
  45544. return(OP_SAFE_C_opSCq_opSCq);
  45545. break;
  45546. case OP_SAFE_C_SS:
  45547. if (optimize_op_match(e1, OP_SAFE_C_C))
  45548. return(OP_SAFE_C_opCq_opSSq);
  45549. if (optimize_op_match(e1, OP_SAFE_C_SS))
  45550. return(OP_SAFE_C_opSSq_opSSq);
  45551. if (optimize_op_match(e1, OP_SAFE_C_S))
  45552. return(OP_SAFE_C_opSq_opSSq);
  45553. break;
  45554. }
  45555. return(OP_SAFE_C_ZZ);
  45556. default:
  45557. break;
  45558. }
  45559. return(OP_NO_OP);
  45560. }
  45561. static void annotate_args(s7_scheme *sc, s7_pointer args, s7_pointer e)
  45562. {
  45563. s7_pointer p;
  45564. for (p = args; is_pair(p); p = cdr(p))
  45565. set_c_call(p, all_x_eval(sc, car(p), e, (s7_is_list(sc, e)) ? pair_symbol_is_safe : let_symbol_is_safe));
  45566. }
  45567. static void annotate_arg(s7_scheme *sc, s7_pointer arg, s7_pointer e)
  45568. {
  45569. /* if sc->envir is sc->nil, we're at the top-level, but the global_slot check should suffice for that */
  45570. set_c_call(arg, all_x_eval(sc, car(arg), e, (s7_is_list(sc, e)) ? pair_symbol_is_safe : let_symbol_is_safe));
  45571. }
  45572. static void opt_generator(s7_scheme *sc, s7_pointer func, s7_pointer expr, int hop)
  45573. {
  45574. /* this is an optimization aimed at generators. So we might as well go all out... */
  45575. if (is_global(car(expr))) /* not a function argument for example */
  45576. {
  45577. s7_pointer body;
  45578. body = closure_body(func);
  45579. if ((s7_list_length(sc, body) == 2) &&
  45580. (caar(body) == sc->let_set_symbol) &&
  45581. (is_optimized(car(body))) &&
  45582. (optimize_op(car(body)) == HOP_SAFE_C_SQS) &&
  45583. (caadr(body) == sc->with_let_symbol) &&
  45584. (is_symbol(cadr(cadr(body)))))
  45585. {
  45586. s7_pointer args;
  45587. args = closure_args(func);
  45588. if ((cadr(cadr(body)) == car(args)) &&
  45589. (is_pair(cdr(args))) &&
  45590. (is_pair(cadr(args))) &&
  45591. (cadddr(car(body)) == caadr(closure_args(func))))
  45592. {
  45593. if (is_global(car(expr))) hop = 1; /* it's my party... */
  45594. set_optimize_op(expr, hop + OP_SAFE_CLOSURE_STAR_S0);
  45595. set_opt_sym1(cdr(expr), cadr(caddar(body)));
  45596. set_opt_pair2(cdr(expr), cddadr(body));
  45597. }
  45598. }
  45599. }
  45600. }
  45601. static bool is_lambda(s7_scheme *sc, s7_pointer sym)
  45602. {
  45603. return((sym == sc->lambda_symbol) && (symbol_id(sym) == 0));
  45604. /* symbol_id==0 means it has never been rebound (T_GLOBAL might not be set for initial stuff) */
  45605. }
  45606. static bool optimize_func_one_arg(s7_scheme *sc, s7_pointer expr, s7_pointer func, int hop, int pairs, int symbols, int quotes, int bad_pairs, s7_pointer e)
  45607. {
  45608. s7_pointer arg1;
  45609. /* very often, expr is already optimized */
  45610. arg1 = cadr(expr);
  45611. if ((pairs == 0) &&
  45612. (is_immutable_symbol(car(expr))))
  45613. hop = 1;
  45614. if (((is_c_function(func)) &&
  45615. (c_function_required_args(func) <= 1) &&
  45616. (c_function_all_args(func) >= 1)) ||
  45617. ((is_c_function_star(func)) &&
  45618. (c_function_all_args(func) == 1))) /* surely no need to check key here? */
  45619. {
  45620. bool func_is_safe;
  45621. func_is_safe = is_safe_procedure(func);
  45622. if (pairs == 0)
  45623. {
  45624. if (func_is_safe) /* safe c function */
  45625. {
  45626. set_safe_optimize_op(expr, hop + ((symbols == 0) ? OP_SAFE_C_C : OP_SAFE_C_S));
  45627. /* we can't simply check is_global here to forego symbol value lookup later because we aren't
  45628. * tracking local vars, so the global bit may be on right now, but won't be when
  45629. * this code is evaluated. But memq(sym, e) would catch such cases.
  45630. * I think it has already been checked for func, so we only need to look for arg1.
  45631. * But global symbols are rare, and I don't see a huge savings in the lookup time --
  45632. * in callgrind it's about 7/lookup in both cases.
  45633. */
  45634. choose_c_function(sc, expr, func, 1);
  45635. return(true);
  45636. }
  45637. else /* c function is not safe */
  45638. {
  45639. set_unsafely_optimized(expr);
  45640. if (symbols == 0)
  45641. {
  45642. set_optimize_op(expr, hop + OP_C_A);
  45643. annotate_arg(sc, cdr(expr), e);
  45644. set_arglist_length(expr, small_int(1));
  45645. }
  45646. else
  45647. {
  45648. if (c_function_call(func) == g_read)
  45649. set_optimize_op(expr, hop + OP_READ_S);
  45650. else set_optimize_op(expr, hop + OP_C_S);
  45651. }
  45652. choose_c_function(sc, expr, func, 1);
  45653. return(false);
  45654. }
  45655. }
  45656. else /* pairs == 1 */
  45657. {
  45658. if (bad_pairs == 0)
  45659. {
  45660. if (func_is_safe)
  45661. {
  45662. int op;
  45663. op = combine_ops(sc, E_C_P, expr, arg1);
  45664. set_safe_optimize_op(expr, hop + op);
  45665. /* fallback is Z */
  45666. if (!hop)
  45667. {
  45668. clear_hop(arg1);
  45669. }
  45670. else
  45671. {
  45672. if ((op == OP_SAFE_C_Z) &&
  45673. (is_all_x_op(optimize_op(arg1))))
  45674. {
  45675. /* this is confusing! this is much faster than safe_c_z, but
  45676. * the parallel let_z|a case seems to claim that z is faster.
  45677. */
  45678. set_optimize_op(expr, hop + OP_SAFE_C_A);
  45679. annotate_arg(sc, cdr(expr), e);
  45680. }
  45681. }
  45682. choose_c_function(sc, expr, func, 1);
  45683. return(true);
  45684. }
  45685. if (is_all_x_op(optimize_op(arg1)))
  45686. {
  45687. set_unsafe_optimize_op(expr, hop + OP_C_A);
  45688. annotate_arg(sc, cdr(expr), e);
  45689. set_arglist_length(expr, small_int(1));
  45690. choose_c_function(sc, expr, func, 1);
  45691. return(false);
  45692. }
  45693. }
  45694. else /* bad_pairs == 1 */
  45695. {
  45696. if (quotes == 1)
  45697. {
  45698. if (func_is_safe)
  45699. {
  45700. set_safe_optimize_op(expr, hop + OP_SAFE_C_Q);
  45701. choose_c_function(sc, expr, func, 1);
  45702. return(true);
  45703. }
  45704. set_unsafe_optimize_op(expr, hop + OP_C_A);
  45705. annotate_arg(sc, cdr(expr), e);
  45706. set_arglist_length(expr, small_int(1));
  45707. choose_c_function(sc, expr, func, 1);
  45708. return(false);
  45709. }
  45710. else /* quotes == 0 */
  45711. {
  45712. if (!func_is_safe)
  45713. {
  45714. s7_pointer lambda_expr;
  45715. lambda_expr = arg1;
  45716. if ((is_pair(lambda_expr)) &&
  45717. (is_lambda(sc, car(lambda_expr))) && /* check for stuff like (define (f) (eval (lambda 2))) */
  45718. (is_pair(cdr(lambda_expr))) &&
  45719. (is_pair(cddr(lambda_expr))))
  45720. {
  45721. if ((c_function_call(func) == g_call_with_exit) &&
  45722. (is_pair(cadr(lambda_expr))) &&
  45723. (is_null(cdadr(lambda_expr))))
  45724. {
  45725. set_unsafe_optimize_op(expr, hop + OP_CALL_WITH_EXIT);
  45726. choose_c_function(sc, expr, func, 1);
  45727. set_opt_pair2(expr, cdr(lambda_expr));
  45728. return(false);
  45729. }
  45730. }
  45731. }
  45732. set_unsafe_optimize_op(expr, hop + ((is_h_optimized(arg1)) ? OP_C_Z : OP_C_P));
  45733. choose_c_function(sc, expr, func, 1);
  45734. return(false);
  45735. }
  45736. }
  45737. }
  45738. if (!func_is_safe)
  45739. {
  45740. set_unsafe_optimize_op(expr, hop + ((is_h_optimized(arg1)) ? OP_C_Z : OP_C_P));
  45741. choose_c_function(sc, expr, func, 1);
  45742. return(false);
  45743. }
  45744. return(is_optimized(expr));
  45745. }
  45746. if (is_closure(func))
  45747. {
  45748. bool safe_case, global_case;
  45749. s7_pointer body;
  45750. if (closure_arity_to_int(sc, func) != 1)
  45751. return(false);
  45752. /* this is checking for dotted arglists: boolean=? for example. To optimize these calls, we need op_closure cases that
  45753. * bind the dotted name to the remaining args as a list. This does not happen enough to be worth the trouble.
  45754. */
  45755. safe_case = is_safe_closure(func);
  45756. global_case = is_global(car(expr));
  45757. body = closure_body(func);
  45758. if (pairs == 0)
  45759. {
  45760. if (is_symbol(arg1))
  45761. {
  45762. if (safe_case)
  45763. {
  45764. set_optimize_op(expr, hop + ((global_case) ? OP_SAFE_GLOSURE_S : OP_SAFE_CLOSURE_S));
  45765. if (is_null(cdr(body)))
  45766. {
  45767. if ((global_case) &&
  45768. (is_optimized(car(body))))
  45769. set_optimize_op(expr, hop + OP_SAFE_GLOSURE_S_E);
  45770. else
  45771. {
  45772. if ((is_pair(car(body))) &&
  45773. (is_syntactic(caar(body))))
  45774. {
  45775. set_optimize_op(expr, hop + OP_SAFE_CLOSURE_S_P);
  45776. if (typesflag(car(body)) != SYNTACTIC_PAIR)
  45777. {
  45778. pair_set_syntax_op(car(body), symbol_syntax_op(caar(body)));
  45779. set_syntactic_pair(car(body));
  45780. }
  45781. }
  45782. }
  45783. }
  45784. }
  45785. else set_optimize_op(expr, hop + ((global_case) ? OP_GLOSURE_S : OP_CLOSURE_S));
  45786. set_opt_sym2(expr, arg1);
  45787. }
  45788. else
  45789. {
  45790. set_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_C : OP_CLOSURE_C));
  45791. set_opt_con2(expr, arg1);
  45792. }
  45793. set_opt_lambda(expr, func);
  45794. set_unsafely_optimized(expr);
  45795. return(false);
  45796. }
  45797. else /* pairs == 1 */
  45798. {
  45799. if (bad_pairs == 0)
  45800. {
  45801. if ((is_optimized(arg1)) &&
  45802. (is_all_x_op(optimize_op(arg1))))
  45803. {
  45804. set_unsafely_optimized(expr);
  45805. annotate_arg(sc, cdr(expr), e);
  45806. set_arglist_length(expr, small_int(1));
  45807. if (safe_case)
  45808. set_optimize_op(expr, hop + ((global_case) ? OP_SAFE_GLOSURE_A : OP_SAFE_CLOSURE_A));
  45809. else set_optimize_op(expr, hop + ((global_case) ? OP_GLOSURE_A : OP_CLOSURE_A));
  45810. set_opt_lambda(expr, func);
  45811. return(false);
  45812. }
  45813. }
  45814. else /* bad_pairs == 1 */
  45815. {
  45816. if (quotes == 1)
  45817. {
  45818. set_unsafe_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_Q : OP_CLOSURE_Q));
  45819. set_opt_lambda(expr, func);
  45820. return(false);
  45821. }
  45822. }
  45823. if ((quotes == 0) &&
  45824. (global_case))
  45825. {
  45826. set_unsafe_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_GLOSURE_P : OP_GLOSURE_P));
  45827. set_opt_lambda(expr, func);
  45828. return(false);
  45829. }
  45830. }
  45831. if (pairs == (quotes + all_x_count(expr)))
  45832. {
  45833. set_unsafe_optimize_op(expr, hop + ((safe_case ? OP_SAFE_CLOSURE_A : OP_CLOSURE_A)));
  45834. annotate_arg(sc, cdr(expr), e);
  45835. set_opt_lambda(expr, func);
  45836. set_arglist_length(expr, small_int(1));
  45837. return(false);
  45838. }
  45839. return(is_optimized(expr));
  45840. }
  45841. if (is_closure_star(func))
  45842. {
  45843. bool safe_case;
  45844. if ((!has_simple_args(closure_body(func))) ||
  45845. (is_null(closure_args(func))))
  45846. return(false);
  45847. safe_case = is_safe_closure(func);
  45848. if ((pairs == 0) &&
  45849. (symbols == 1))
  45850. {
  45851. set_unsafely_optimized(expr);
  45852. if (safe_case)
  45853. {
  45854. set_optimize_op(expr, hop + OP_SAFE_CLOSURE_STAR_S);
  45855. if (closure_star_arity_to_int(sc, func) == 2)
  45856. {
  45857. s7_pointer defarg2;
  45858. defarg2 = cadr(closure_args(func));
  45859. if ((is_pair(defarg2)) &&
  45860. (s7_is_zero(cadr(defarg2))))
  45861. opt_generator(sc, func, expr, hop);
  45862. }
  45863. }
  45864. else set_optimize_op(expr, hop + OP_CLOSURE_STAR_S);
  45865. set_opt_lambda(expr, func);
  45866. set_opt_sym2(expr, arg1);
  45867. return(false);
  45868. }
  45869. if ((!arglist_has_rest(sc, closure_args(func))) &&
  45870. (pairs == (quotes + all_x_count(expr))))
  45871. {
  45872. set_unsafe_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_STAR_ALL_X : OP_CLOSURE_STAR_ALL_X));
  45873. annotate_arg(sc, cdr(expr), e);
  45874. set_opt_lambda(expr, func);
  45875. set_arglist_length(expr, small_int(1));
  45876. return(false);
  45877. }
  45878. return(is_optimized(expr));
  45879. }
  45880. if ((pairs == 0) &&
  45881. (s7_is_vector(func)))
  45882. {
  45883. set_safe_optimize_op(expr, hop + ((symbols == 1) ? OP_VECTOR_S : OP_VECTOR_C));
  45884. set_opt_vector(expr, func);
  45885. return(true);
  45886. }
  45887. /* unknown_* is set later */
  45888. return(is_optimized(expr));
  45889. }
  45890. static bool rdirect_memq(s7_scheme *sc, s7_pointer symbol, s7_pointer symbols)
  45891. {
  45892. s7_pointer x;
  45893. for (x = symbols; is_pair(x); x = cdr(x))
  45894. {
  45895. if (car(x) == symbol)
  45896. return(true);
  45897. x = cdr(x);
  45898. if (car(x) == symbol) /* car(nil)=unspec, cdr(unspec)=unspec! This only works for lists known to be undotted and non-circular */
  45899. return(true);
  45900. }
  45901. return(false);
  45902. }
  45903. static s7_pointer find_uncomplicated_symbol(s7_scheme *sc, s7_pointer symbol, s7_pointer e)
  45904. {
  45905. s7_pointer x;
  45906. long long int id;
  45907. if ((symbol_tag(symbol) == sc->syms_tag) &&
  45908. (rdirect_memq(sc, symbol, e))) /* it's probably a local variable reference */
  45909. return(sc->nil);
  45910. if (is_global(symbol))
  45911. return(global_slot(symbol));
  45912. id = symbol_id(symbol);
  45913. for (x = sc->envir; id < let_id(x); x = outlet(x));
  45914. for (; is_let(x); x = outlet(x))
  45915. {
  45916. s7_pointer y;
  45917. if (let_id(x) == id)
  45918. return(local_slot(symbol));
  45919. for (y = let_slots(x); is_slot(y); y = next_slot(y))
  45920. if (slot_symbol(y) == symbol)
  45921. return(y);
  45922. }
  45923. return(global_slot(symbol)); /* it's no longer global perhaps (local definition now inaccessible) */
  45924. }
  45925. static bool unsafe_is_safe(s7_scheme *sc, s7_pointer func, s7_pointer arg1, s7_pointer arg2, s7_pointer arg3, s7_pointer e)
  45926. {
  45927. s7_pointer f = NULL; /* arg3 if member|assoc */
  45928. if (!arg3) return(true);
  45929. f = arg3;
  45930. if (!is_symbol(f)) return(false);
  45931. f = find_uncomplicated_symbol(sc, f, e); /* form_is_safe -- how to catch local c-funcs here? */
  45932. if (is_slot(f))
  45933. {
  45934. f = slot_value(f);
  45935. return((is_c_function(f)) &&
  45936. (is_safe_procedure(f)));
  45937. }
  45938. return(false);
  45939. }
  45940. static bool optimize_func_two_args(s7_scheme *sc, s7_pointer expr, s7_pointer func, int hop, int pairs, int symbols, int quotes, int bad_pairs, s7_pointer e)
  45941. {
  45942. s7_pointer arg1, arg2;
  45943. arg1 = cadr(expr);
  45944. arg2 = caddr(expr);
  45945. if ((pairs == 0) &&
  45946. (is_immutable_symbol(car(expr))))
  45947. hop = 1;
  45948. if ((is_c_function(func) &&
  45949. (c_function_required_args(func) <= 2) &&
  45950. (c_function_all_args(func) >= 2)) ||
  45951. ((is_c_function_star(func)) &&
  45952. (c_function_all_args(func) == 2) &&
  45953. (!is_keyword(arg1))))
  45954. {
  45955. /* this is a mess */
  45956. bool func_is_safe;
  45957. func_is_safe = is_safe_procedure(func);
  45958. if (pairs == 0)
  45959. {
  45960. if ((func_is_safe) ||
  45961. ((is_possibly_safe(func)) &&
  45962. (unsafe_is_safe(sc, func, arg1, arg2, NULL, e))))
  45963. {
  45964. /* another case here: set-car! and set-cdr! are safe if symbols==1 and arg1 is the symbol (i.e. arg2 is a constant) */
  45965. if (symbols == 0)
  45966. set_optimize_op(expr, hop + OP_SAFE_C_C);
  45967. else
  45968. {
  45969. if (symbols == 2)
  45970. set_optimize_op(expr, hop + OP_SAFE_C_SS); /* these two symbols are almost never the same, (sqrt (+ (* x x) (* y y))) */
  45971. else set_optimize_op(expr, hop + ((is_symbol(arg1)) ? OP_SAFE_C_SC : OP_SAFE_C_CS));
  45972. }
  45973. set_optimized(expr);
  45974. choose_c_function(sc, expr, func, 2);
  45975. return(true);
  45976. }
  45977. set_unsafely_optimized(expr);
  45978. if (symbols == 2)
  45979. {
  45980. if (c_function_call(func) == g_apply)
  45981. {
  45982. set_optimize_op(expr, hop + OP_APPLY_SS);
  45983. set_opt_cfunc(expr, func);
  45984. set_opt_sym2(expr, arg2);
  45985. }
  45986. else
  45987. {
  45988. set_optimize_op(expr, hop + OP_C_SS);
  45989. choose_c_function(sc, expr, func, 2);
  45990. }
  45991. }
  45992. else
  45993. {
  45994. set_optimize_op(expr, hop + OP_C_ALL_X);
  45995. annotate_args(sc, cdr(expr), e);
  45996. set_arglist_length(expr, small_int(2));
  45997. choose_c_function(sc, expr, func, 2);
  45998. if (is_safe_procedure(opt_cfunc(expr)))
  45999. {
  46000. clear_unsafe(expr);
  46001. set_optimized(expr);
  46002. /* symbols can be 0..2 here, no pairs */
  46003. if (symbols == 1)
  46004. {
  46005. if (is_symbol(arg1))
  46006. set_optimize_op(expr, hop + OP_SAFE_C_SC);
  46007. else set_optimize_op(expr, hop + OP_SAFE_C_CS);
  46008. }
  46009. else
  46010. {
  46011. if (symbols == 2)
  46012. set_optimize_op(expr, hop + OP_SAFE_C_SS);
  46013. else set_optimize_op(expr, hop + OP_SAFE_C_C);
  46014. }
  46015. return(true);
  46016. }
  46017. }
  46018. return(false);
  46019. }
  46020. /* pairs != 0 */
  46021. if ((bad_pairs == 0) &&
  46022. (pairs == 2))
  46023. {
  46024. if ((func_is_safe) ||
  46025. ((is_possibly_safe(func)) &&
  46026. (unsafe_is_safe(sc, func, arg1, arg2, NULL, e))))
  46027. {
  46028. int op;
  46029. op = combine_ops(sc, E_C_PP, arg1, arg2);
  46030. set_safe_optimize_op(expr, hop + op);
  46031. /* fallback here is ZZ */
  46032. if (!hop)
  46033. {
  46034. clear_hop(arg1);
  46035. clear_hop(arg2);
  46036. }
  46037. else
  46038. {
  46039. if (op == OP_SAFE_C_ZZ)
  46040. {
  46041. if (is_all_x_safe(sc, arg1))
  46042. {
  46043. if (is_all_x_safe(sc, arg2))
  46044. {
  46045. set_optimize_op(expr, hop + OP_SAFE_C_AA);
  46046. annotate_args(sc, cdr(expr), e);
  46047. set_arglist_length(expr, small_int(2));
  46048. }
  46049. else
  46050. {
  46051. if (optimize_op(arg1) == HOP_SAFE_C_C)
  46052. set_optimize_op(expr, hop + OP_SAFE_C_opCq_Z);
  46053. else
  46054. {
  46055. set_optimize_op(expr, hop + OP_SAFE_C_AZ);
  46056. annotate_arg(sc, cdr(expr), e);
  46057. set_arglist_length(expr, small_int(2));
  46058. }
  46059. }
  46060. }
  46061. else
  46062. {
  46063. if (is_all_x_safe(sc, arg2))
  46064. {
  46065. set_optimize_op(expr, hop + OP_SAFE_C_ZA);
  46066. annotate_arg(sc, cddr(expr), e);
  46067. set_arglist_length(expr, small_int(2));
  46068. }
  46069. }
  46070. }
  46071. }
  46072. choose_c_function(sc, expr, func, 2); /* this might change the op to safe_c_c, so it has to be last */
  46073. return(true);
  46074. }
  46075. }
  46076. if ((bad_pairs == 0) &&
  46077. (pairs == 1))
  46078. {
  46079. if ((func_is_safe) ||
  46080. ((is_possibly_safe(func)) &&
  46081. (unsafe_is_safe(sc, func, arg1, arg2, NULL, e))))
  46082. {
  46083. combine_op_t orig_op;
  46084. int op;
  46085. if (is_pair(arg1))
  46086. {
  46087. if (is_symbol(arg2))
  46088. orig_op = E_C_PS;
  46089. else orig_op = E_C_PC;
  46090. op = combine_ops(sc, orig_op, expr, arg1);
  46091. if (!hop) clear_hop(arg1);
  46092. }
  46093. else
  46094. {
  46095. if (is_symbol(arg1))
  46096. orig_op = E_C_SP;
  46097. else orig_op = E_C_CP;
  46098. op = combine_ops(sc, orig_op, expr, arg2);
  46099. if (!hop) clear_hop(arg2);
  46100. }
  46101. set_safe_optimize_op(expr, hop + op);
  46102. choose_c_function(sc, expr, func, 2);
  46103. return(true);
  46104. }
  46105. if (symbols == 1)
  46106. {
  46107. if (is_symbol(arg1))
  46108. {
  46109. if (is_safe_c_s(arg2))
  46110. {
  46111. set_unsafe_optimize_op(expr, hop + OP_C_S_opSq);
  46112. set_opt_sym1(cdr(expr), cadr(arg2));
  46113. choose_c_function(sc, expr, func, 2);
  46114. return(false);
  46115. }
  46116. if (optimize_op_match(arg2, OP_SAFE_C_C))
  46117. {
  46118. set_unsafe_optimize_op(expr, hop + OP_C_S_opCq);
  46119. set_opt_pair1(cdr(expr), cdr(arg2));
  46120. choose_c_function(sc, expr, func, 2);
  46121. return(false);
  46122. }
  46123. }
  46124. }
  46125. }
  46126. if ((bad_pairs == 1) && (quotes == 1))
  46127. {
  46128. if ((func_is_safe) ||
  46129. ((is_possibly_safe(func)) &&
  46130. (unsafe_is_safe(sc, func, arg1, arg2, NULL, e))))
  46131. {
  46132. if (symbols == 1)
  46133. {
  46134. set_optimized(expr);
  46135. if (is_symbol(arg1))
  46136. set_optimize_op(expr, hop + OP_SAFE_C_SQ);
  46137. else set_optimize_op(expr, hop + OP_SAFE_C_QS);
  46138. choose_c_function(sc, expr, func, 2);
  46139. return(true);
  46140. }
  46141. else
  46142. {
  46143. if (pairs == 1)
  46144. {
  46145. /* Q must be 1, symbols = 0, pairs = 1 (the quote), so this must be CQ or QC?
  46146. */
  46147. set_optimized(expr);
  46148. if (is_pair(arg1))
  46149. set_optimize_op(expr, hop + OP_SAFE_C_QC);
  46150. else set_optimize_op(expr, hop + OP_SAFE_C_CQ);
  46151. choose_c_function(sc, expr, func, 2);
  46152. return(true);
  46153. }
  46154. }
  46155. }
  46156. else
  46157. {
  46158. if (pairs == 1)
  46159. {
  46160. set_unsafe_optimize_op(expr, hop + OP_C_ALL_X);
  46161. annotate_args(sc, cdr(expr), e);
  46162. set_arglist_length(expr, small_int(2));
  46163. choose_c_function(sc, expr, func, 2);
  46164. return(false);
  46165. }
  46166. }
  46167. }
  46168. if (quotes == 2)
  46169. {
  46170. if ((func_is_safe) ||
  46171. ((is_possibly_safe(func)) &&
  46172. (unsafe_is_safe(sc, func, arg1, arg2, NULL, e))))
  46173. {
  46174. set_safe_optimize_op(expr, hop + OP_SAFE_C_QQ);
  46175. choose_c_function(sc, expr, func, 2);
  46176. return(true);
  46177. }
  46178. set_unsafe_optimize_op(expr, hop + OP_C_ALL_X);
  46179. annotate_args(sc, cdr(expr), e);
  46180. set_arglist_length(expr, small_int(2));
  46181. choose_c_function(sc, expr, func, 2);
  46182. return(false);
  46183. }
  46184. if ((pairs == 1) &&
  46185. (quotes == 0) &&
  46186. ((func_is_safe) ||
  46187. ((is_possibly_safe(func)) &&
  46188. (unsafe_is_safe(sc, func, arg1, arg2, NULL, e)))))
  46189. {
  46190. if (symbols == 1)
  46191. {
  46192. set_optimized(expr);
  46193. if (is_symbol(arg1))
  46194. {
  46195. if ((bad_pairs == 0) || (is_h_optimized(arg2))) /* bad_pair && h_optimized happens a lot */
  46196. {
  46197. set_optimize_op(expr, hop + OP_SAFE_C_SZ);
  46198. choose_c_function(sc, expr, func, 2);
  46199. /* if hop is on, is it the case that opt1 is unused? where besides c_function_is_ok is it referenced?
  46200. * some like add_ss_1ss use opt1(cdr(...)) which is safe here I think because cadr is a symbol
  46201. * it's used in the choosers to detect e.g. temp funcs
  46202. */
  46203. return(true);
  46204. }
  46205. set_unsafe(expr);
  46206. set_optimize_op(expr, hop + OP_SAFE_C_SP);
  46207. choose_c_function(sc, expr, func, 2);
  46208. return(false);
  46209. }
  46210. /* arg2 is a symbol */
  46211. if ((bad_pairs == 0) || (is_h_optimized(arg1)))
  46212. {
  46213. set_optimize_op(expr, hop + OP_SAFE_C_ZS);
  46214. choose_c_function(sc, expr, func, 2);
  46215. return(true);
  46216. }
  46217. /* unknowns get here: (* amp (amps 0))
  46218. * also list: (make-polywave pitch (list 1 0.93 2 0.07))
  46219. * and (* vol (granulate gen))
  46220. */
  46221. set_unsafe(expr);
  46222. set_optimize_op(expr, hop + OP_SAFE_C_PS);
  46223. choose_c_function(sc, expr, func, 2);
  46224. return(false);
  46225. }
  46226. if (symbols == 0)
  46227. {
  46228. set_optimized(expr);
  46229. if (is_pair(arg1))
  46230. {
  46231. if ((bad_pairs == 0) || (is_h_optimized(arg2)))
  46232. {
  46233. set_optimize_op(expr, hop + OP_SAFE_C_ZC);
  46234. choose_c_function(sc, expr, func, 2);
  46235. return(true);
  46236. }
  46237. else
  46238. {
  46239. set_unsafe(expr);
  46240. set_optimize_op(expr, hop + OP_SAFE_C_PC);
  46241. choose_c_function(sc, expr, func, 2);
  46242. return(false);
  46243. }
  46244. }
  46245. else
  46246. {
  46247. if ((bad_pairs == 0) || (is_h_optimized(arg1)))
  46248. {
  46249. set_optimize_op(expr, hop + OP_SAFE_C_CZ);
  46250. choose_c_function(sc, expr, func, 2);
  46251. return(true);
  46252. }
  46253. else
  46254. {
  46255. set_unsafe(expr);
  46256. set_optimize_op(expr, hop + OP_SAFE_C_CP);
  46257. choose_c_function(sc, expr, func, 2);
  46258. return(false);
  46259. }
  46260. }
  46261. }
  46262. }
  46263. if ((pairs == 2) &&
  46264. ((func_is_safe) ||
  46265. ((is_possibly_safe(func)) &&
  46266. (unsafe_is_safe(sc, func, arg1, arg2, NULL, e)))))
  46267. {
  46268. if ((bad_pairs == 1) &&
  46269. (is_safe_c_s(arg1)))
  46270. {
  46271. /* unsafe func here won't work unless we check that later and make the new arg list (for {list} etc)
  46272. * (and it has to be the last pair else the unknown_g stuff can mess up)
  46273. */
  46274. if (car(arg2) == sc->quote_symbol)
  46275. {
  46276. set_safe_optimize_op(expr, hop + OP_SAFE_C_opSq_Q);
  46277. choose_c_function(sc, expr, func, 2);
  46278. return(true);
  46279. }
  46280. set_unsafe_optimize_op(expr, hop + OP_SAFE_C_opSq_P);
  46281. choose_c_function(sc, expr, func, 2);
  46282. return(false);
  46283. }
  46284. else
  46285. {
  46286. if (quotes == 0)
  46287. {
  46288. set_unsafely_optimized(expr);
  46289. if (is_all_x_safe(sc, arg1))
  46290. {
  46291. set_optimize_op(expr, hop + ((is_h_optimized(arg2)) ? OP_SAFE_C_AZ : OP_SAFE_C_AP));
  46292. annotate_arg(sc, cdr(expr), e);
  46293. }
  46294. else set_optimize_op(expr, hop + OP_SAFE_C_PP);
  46295. choose_c_function(sc, expr, func, 2);
  46296. return(false);
  46297. }
  46298. else
  46299. {
  46300. if (quotes == 1)
  46301. {
  46302. if (car(arg1) == sc->quote_symbol)
  46303. set_optimize_op(expr, hop + OP_SAFE_C_QP);
  46304. else set_optimize_op(expr, hop + OP_SAFE_C_PQ);
  46305. set_unsafely_optimized(expr);
  46306. choose_c_function(sc, expr, func, 2);
  46307. return(false);
  46308. }
  46309. }
  46310. }
  46311. }
  46312. if (func_is_safe)
  46313. {
  46314. if (pairs == (quotes + all_x_count(expr)))
  46315. {
  46316. set_safe_optimize_op(expr, hop + OP_SAFE_C_AA);
  46317. annotate_args(sc, cdr(expr), e);
  46318. set_arglist_length(expr, small_int(2));
  46319. choose_c_function(sc, expr, func, 2);
  46320. return(true);
  46321. }
  46322. }
  46323. if ((pairs == 1) &&
  46324. (symbols == 1) &&
  46325. (quotes == 0) &&
  46326. (!func_is_safe) &&
  46327. (is_symbol(arg1)))
  46328. {
  46329. set_unsafe_optimize_op(expr, hop + ((is_h_optimized(arg2)) ? OP_C_SZ : OP_C_SP));
  46330. choose_c_function(sc, expr, func, 2);
  46331. return(false);
  46332. }
  46333. return(is_optimized(expr));
  46334. }
  46335. if (is_closure(func))
  46336. {
  46337. if (closure_arity_to_int(sc, func) != 2)
  46338. return(false);
  46339. if ((pairs == 0) &&
  46340. (symbols >= 1))
  46341. {
  46342. set_unsafely_optimized(expr);
  46343. if (symbols == 2)
  46344. {
  46345. set_optimize_op(expr, hop + ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_SS : OP_CLOSURE_SS));
  46346. set_opt_sym2(expr, arg2);
  46347. }
  46348. else
  46349. {
  46350. if (is_symbol(arg1))
  46351. {
  46352. set_optimize_op(expr, hop + ((is_safe_closure(func) ? OP_SAFE_CLOSURE_SC : OP_CLOSURE_SC)));
  46353. set_opt_con2(expr, arg2);
  46354. }
  46355. else
  46356. {
  46357. set_optimize_op(expr, hop + ((is_safe_closure(func) ? OP_SAFE_CLOSURE_CS : OP_CLOSURE_CS)));
  46358. set_opt_sym2(expr, arg2);
  46359. }
  46360. }
  46361. set_opt_lambda(expr, func);
  46362. return(false);
  46363. }
  46364. if ((!arglist_has_rest(sc, closure_args(func))) &&
  46365. (pairs == (quotes + all_x_count(expr))))
  46366. {
  46367. set_unsafely_optimized(expr);
  46368. if (is_safe_closure(func))
  46369. {
  46370. if (is_symbol(arg1))
  46371. set_optimize_op(expr, hop + OP_SAFE_CLOSURE_SA);
  46372. else set_optimize_op(expr, hop + OP_SAFE_CLOSURE_AA);
  46373. }
  46374. else set_optimize_op(expr, hop + OP_CLOSURE_AA);
  46375. annotate_args(sc, cdr(expr), e);
  46376. set_opt_lambda(expr, func);
  46377. set_arglist_length(expr, small_int(2));
  46378. return(false);
  46379. }
  46380. return(is_optimized(expr));
  46381. }
  46382. if (is_closure_star(func))
  46383. {
  46384. if (((!has_simple_args(closure_body(func))) ||
  46385. (closure_star_arity_to_int(sc, func) < 2) ||
  46386. (arglist_has_keyword(cdr(expr)))))
  46387. return(false);
  46388. if ((pairs == 0) &&
  46389. (symbols >= 1) &&
  46390. (is_symbol(arg1)))
  46391. {
  46392. set_unsafely_optimized(expr);
  46393. if (symbols == 2)
  46394. {
  46395. set_optimize_op(expr, hop + ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_STAR_SS : OP_CLOSURE_STAR_SX));
  46396. set_opt_sym2(expr, arg2);
  46397. }
  46398. else
  46399. {
  46400. if (is_safe_closure(func))
  46401. {
  46402. set_optimize_op(expr, hop + OP_SAFE_CLOSURE_STAR_SC);
  46403. set_opt_con2(expr, arg2);
  46404. if (arg2 == real_zero)
  46405. opt_generator(sc, func, expr, hop);
  46406. }
  46407. else set_optimize_op(expr, hop + OP_CLOSURE_STAR_SX);
  46408. }
  46409. set_opt_lambda(expr, func);
  46410. return(false);
  46411. }
  46412. if ((!arglist_has_rest(sc, closure_args(func))) &&
  46413. (pairs == (quotes + all_x_count(expr))))
  46414. {
  46415. set_unsafely_optimized(expr);
  46416. if (is_safe_closure(func))
  46417. {
  46418. if ((is_symbol(arg1)) &&
  46419. (closure_star_arity_to_int(sc, func) == 2))
  46420. set_optimize_op(expr, hop + OP_SAFE_CLOSURE_STAR_SA);
  46421. else set_optimize_op(expr, hop + OP_SAFE_CLOSURE_STAR_ALL_X);
  46422. }
  46423. else set_optimize_op(expr, hop + OP_CLOSURE_STAR_ALL_X);
  46424. annotate_args(sc, cdr(expr), e);
  46425. set_opt_lambda(expr, func);
  46426. set_arglist_length(expr, small_int(2));
  46427. return(false);
  46428. }
  46429. }
  46430. return(is_optimized(expr));
  46431. }
  46432. static bool optimize_func_three_args(s7_scheme *sc, s7_pointer expr, s7_pointer func, int hop, int pairs, int symbols, int quotes, int bad_pairs, s7_pointer e)
  46433. {
  46434. s7_pointer arg1, arg2, arg3;
  46435. arg1 = cadr(expr);
  46436. arg2 = caddr(expr);
  46437. arg3 = cadddr(expr);
  46438. if ((pairs == 0) &&
  46439. (is_immutable_symbol(car(expr))))
  46440. hop = 1;
  46441. if ((is_c_function(func) &&
  46442. (c_function_required_args(func) <= 3) &&
  46443. (c_function_all_args(func) >= 3)) ||
  46444. ((is_c_function_star(func)) &&
  46445. (c_function_all_args(func) == 3) &&
  46446. (!is_keyword(arg1)) &&
  46447. (!is_keyword(arg2))))
  46448. {
  46449. if ((is_safe_procedure(func)) ||
  46450. ((is_possibly_safe(func)) &&
  46451. (unsafe_is_safe(sc, func, arg1, arg2, arg3, e))))
  46452. {
  46453. if (pairs == 0)
  46454. {
  46455. set_optimized(expr);
  46456. if (symbols == 0)
  46457. set_optimize_op(expr, hop + OP_SAFE_C_C);
  46458. else
  46459. {
  46460. if (symbols == 3)
  46461. {
  46462. set_optimize_op(expr, hop + OP_SAFE_C_SSS);
  46463. set_opt_sym1(cdr(expr), arg2);
  46464. set_opt_sym2(cdr(expr), arg3);
  46465. }
  46466. else
  46467. {
  46468. if (symbols == 2)
  46469. {
  46470. if (!is_symbol(arg1))
  46471. {
  46472. set_optimize_op(expr, hop + OP_SAFE_C_CSS);
  46473. set_opt_sym1(cdr(expr), arg2);
  46474. set_opt_sym2(cdr(expr), arg3);
  46475. }
  46476. else
  46477. {
  46478. if (!is_symbol(arg3))
  46479. {
  46480. set_opt_con2(cdr(expr), arg3);
  46481. if (is_keyword(arg2))
  46482. {
  46483. set_opt_con1(cdr(expr), arg2);
  46484. set_optimize_op(expr, hop + OP_SAFE_C_SCC);
  46485. }
  46486. else
  46487. {
  46488. set_opt_sym1(cdr(expr), arg2);
  46489. set_optimize_op(expr, hop + OP_SAFE_C_SSC);
  46490. }
  46491. }
  46492. else
  46493. {
  46494. set_opt_con1(cdr(expr), arg2);
  46495. set_opt_sym2(cdr(expr), arg3);
  46496. set_optimize_op(expr, hop + OP_SAFE_C_SCS);
  46497. }
  46498. }
  46499. }
  46500. else
  46501. {
  46502. if (is_symbol(arg1))
  46503. {
  46504. set_opt_con1(cdr(expr), arg2);
  46505. set_opt_con2(cdr(expr), arg3);
  46506. set_optimize_op(expr, hop + OP_SAFE_C_SCC);
  46507. }
  46508. else
  46509. {
  46510. if (is_symbol(arg2))
  46511. {
  46512. set_opt_sym1(cdr(expr), arg2);
  46513. set_opt_con2(cdr(expr), arg3);
  46514. set_optimize_op(expr, hop + OP_SAFE_C_CSC);
  46515. }
  46516. else
  46517. {
  46518. set_optimize_op(expr, hop + OP_SAFE_C_AAA); /* fallback on all_x_c and s here -- a kludge */
  46519. annotate_args(sc, cdr(expr), e);
  46520. set_arglist_length(expr, small_int(3));
  46521. }
  46522. }
  46523. }
  46524. }
  46525. }
  46526. choose_c_function(sc, expr, func, 3);
  46527. return(true);
  46528. }
  46529. /* pairs != 0 */
  46530. if (pairs == quotes + all_x_count(expr))
  46531. {
  46532. set_optimized(expr);
  46533. if (quotes == 1)
  46534. {
  46535. if ((symbols == 2) &&
  46536. (is_symbol(arg1)) &&
  46537. (is_symbol(arg3)))
  46538. {
  46539. set_opt_con1(cdr(expr), cadr(arg2));
  46540. set_opt_sym2(cdr(expr), arg3);
  46541. set_optimize_op(expr, hop + OP_SAFE_C_SQS);
  46542. choose_c_function(sc, expr, func, 3);
  46543. return(true);
  46544. }
  46545. if ((symbols == 1) &&
  46546. (is_symbol(arg3)) &&
  46547. (is_pair(arg2)) &&
  46548. (car(arg2) == sc->quote_symbol) &&
  46549. (is_safe_c_s(arg1)))
  46550. {
  46551. set_safe_optimize_op(expr, hop + OP_SAFE_C_opSq_Q_S);
  46552. choose_c_function(sc, expr, func, 3);
  46553. return(true);
  46554. }
  46555. }
  46556. annotate_args(sc, cdr(expr), e);
  46557. set_arglist_length(expr, small_int(3));
  46558. set_optimize_op(expr, hop + OP_SAFE_C_AAA);
  46559. if (pairs == 1)
  46560. {
  46561. if (symbols == 1)
  46562. {
  46563. if (is_pair(arg3))
  46564. {
  46565. if (is_symbol(arg2))
  46566. set_optimize_op(expr, hop + OP_SAFE_C_CSA);
  46567. else set_optimize_op(expr, hop + OP_SAFE_C_SCA);
  46568. }
  46569. else
  46570. {
  46571. if ((is_pair(arg2)) &&
  46572. (is_symbol(arg3)))
  46573. set_optimize_op(expr, hop + OP_SAFE_C_CAS);
  46574. }
  46575. }
  46576. else
  46577. {
  46578. if ((symbols == 2) && (is_symbol(arg1)))
  46579. set_optimize_op(expr, hop + ((is_symbol(arg2)) ? OP_SAFE_C_SSA : OP_SAFE_C_SAS));
  46580. }
  46581. }
  46582. choose_c_function(sc, expr, func, 3);
  46583. return(true);
  46584. }
  46585. if (bad_pairs == 0)
  46586. {
  46587. if ((symbols == 2) &&
  46588. (is_symbol(arg1)) &&
  46589. (is_symbol(arg2)))
  46590. {
  46591. set_optimize_op(expr, hop + OP_SAFE_C_SSZ);
  46592. }
  46593. else
  46594. {
  46595. /* use either X or Z in all 8 choices */
  46596. if ((!is_pair(arg1)) ||
  46597. (is_all_x_op(optimize_op(arg1))))
  46598. {
  46599. annotate_arg(sc, cdr(expr), e);
  46600. if ((!is_pair(arg2)) ||
  46601. (is_all_x_op(optimize_op(arg2))))
  46602. {
  46603. set_optimize_op(expr, hop + OP_SAFE_C_AAZ); /* here last can't be A because we checked for that above */
  46604. annotate_arg(sc, cddr(expr), e);
  46605. }
  46606. else
  46607. {
  46608. if ((!is_pair(arg3)) ||
  46609. (is_all_x_op(optimize_op(arg3))))
  46610. {
  46611. set_optimize_op(expr, hop + OP_SAFE_C_AZA);
  46612. annotate_arg(sc, cdddr(expr), e);
  46613. }
  46614. else set_optimize_op(expr, hop + OP_SAFE_C_AZZ);
  46615. }
  46616. }
  46617. else
  46618. {
  46619. if ((!is_pair(arg2)) ||
  46620. (is_all_x_op(optimize_op(arg2))))
  46621. {
  46622. annotate_arg(sc, cddr(expr), e);
  46623. if ((!is_pair(arg3)) ||
  46624. (is_all_x_op(optimize_op(arg3))))
  46625. {
  46626. set_optimize_op(expr, hop + OP_SAFE_C_ZAA);
  46627. annotate_arg(sc, cdddr(expr), e);
  46628. }
  46629. else set_optimize_op(expr, hop + OP_SAFE_C_ZAZ);
  46630. }
  46631. else
  46632. {
  46633. if ((!is_pair(arg3)) ||
  46634. (is_all_x_op(optimize_op(arg3))))
  46635. {
  46636. set_optimize_op(expr, hop + OP_SAFE_C_ZZA);
  46637. annotate_arg(sc, cdddr(expr), e);
  46638. }
  46639. else set_optimize_op(expr, hop + OP_SAFE_C_ZZZ);
  46640. }
  46641. }
  46642. }
  46643. set_optimized(expr);
  46644. choose_c_function(sc, expr, func, 3);
  46645. set_arglist_length(expr, small_int(3));
  46646. return(true);
  46647. }
  46648. /* aap is not better than ssp, sap also saves very little */
  46649. if ((pairs == 1) &&
  46650. (bad_pairs == 1) &&
  46651. (symbols == 2) &&
  46652. (is_pair(arg3)))
  46653. {
  46654. set_unsafe_optimize_op(expr, hop + ((is_h_optimized(arg3)) ? OP_SAFE_C_SSZ : OP_SAFE_C_SSP));
  46655. choose_c_function(sc, expr, func, 3);
  46656. return(false);
  46657. }
  46658. }
  46659. else /* func is not safe */
  46660. {
  46661. if (pairs == quotes + all_x_count(expr))
  46662. {
  46663. set_optimized(expr);
  46664. if ((symbols == 2) &&
  46665. (pairs == 0) &&
  46666. (is_symbol(arg1)) &&
  46667. (is_symbol(arg3)))
  46668. set_optimize_op(expr, hop + OP_C_SCS);
  46669. else
  46670. {
  46671. annotate_args(sc, cdr(expr), e);
  46672. set_arglist_length(expr, small_int(3));
  46673. set_optimize_op(expr, hop + OP_C_ALL_X);
  46674. }
  46675. choose_c_function(sc, expr, func, 3);
  46676. if (optimize_op(expr) != HOP_SAFE_C_C) /* did chooser fix it up? */
  46677. {
  46678. set_unsafe(expr);
  46679. return(false);
  46680. }
  46681. return(true);
  46682. }
  46683. /* (define (hi) (catch #t (lambda () 1) (lambda args 2)))
  46684. * first arg list must be (), second a symbol
  46685. */
  46686. if (c_function_call(func) == g_catch)
  46687. {
  46688. if (((bad_pairs == 2) && (!is_pair(arg1))) ||
  46689. ((bad_pairs == 3) && (car(arg1) == sc->quote_symbol)))
  46690. {
  46691. s7_pointer body_lambda, error_lambda;
  46692. body_lambda = arg2;
  46693. error_lambda = arg3;
  46694. if ((is_pair(body_lambda)) &&
  46695. (is_lambda(sc, car(body_lambda))) &&
  46696. (is_pair(error_lambda)) &&
  46697. (is_lambda(sc, car(error_lambda))) &&
  46698. (is_null(cadr(body_lambda))) &&
  46699. (is_not_null(cddr(body_lambda))) &&
  46700. (is_symbol(cadr(error_lambda))) &&
  46701. (!is_immutable_symbol(cadr(error_lambda))) &&
  46702. (is_not_null(cddr(error_lambda))))
  46703. {
  46704. s7_pointer error_result;
  46705. error_result = caddr(error_lambda);
  46706. set_unsafely_optimized(expr);
  46707. if ((arg1 == sc->T) &&
  46708. (is_null(cdddr(error_lambda))) &&
  46709. (!is_symbol(error_result)) &&
  46710. ((!is_pair(error_result)) || (car(error_result) == sc->quote_symbol)))
  46711. {
  46712. set_optimize_op(expr, hop + OP_C_CATCH_ALL);
  46713. set_c_function(expr, func);
  46714. if (is_pair(error_result))
  46715. set_opt_con2(expr, cadr(error_result));
  46716. else set_opt_con2(expr, error_result);
  46717. set_opt_pair1(cdr(expr), cddr(body_lambda));
  46718. }
  46719. else
  46720. {
  46721. set_optimize_op(expr, hop + OP_C_CATCH);
  46722. choose_c_function(sc, expr, func, 3);
  46723. }
  46724. return(false);
  46725. }
  46726. }
  46727. }
  46728. }
  46729. return(is_optimized(expr));
  46730. }
  46731. /* not c func */
  46732. if (is_closure(func))
  46733. {
  46734. if (closure_arity_to_int(sc, func) != 3)
  46735. return(false);
  46736. if ((symbols == 3) &&
  46737. (!is_safe_closure(func)))
  46738. {
  46739. set_unsafely_optimized(expr);
  46740. set_opt_lambda(expr, func);
  46741. set_arglist_length(expr, small_int(3));
  46742. set_optimize_op(expr, hop + OP_CLOSURE_ALL_S);
  46743. return(false);
  46744. }
  46745. if (pairs == quotes + all_x_count(expr))
  46746. {
  46747. if (is_safe_closure(func))
  46748. {
  46749. if (is_symbol(arg1))
  46750. set_optimize_op(expr, hop + OP_SAFE_CLOSURE_SAA);
  46751. else set_optimize_op(expr, hop + OP_SAFE_CLOSURE_ALL_X);
  46752. }
  46753. else set_optimize_op(expr, hop + OP_CLOSURE_ALL_X);
  46754. set_unsafely_optimized(expr);
  46755. annotate_args(sc, cdr(expr), e);
  46756. set_opt_lambda(expr, func);
  46757. set_arglist_length(expr, small_int(3));
  46758. return(false);
  46759. }
  46760. }
  46761. if (is_closure_star(func))
  46762. {
  46763. if ((!has_simple_args(closure_body(func))) ||
  46764. (closure_star_arity_to_int(sc, func) < 3) ||
  46765. (arglist_has_keyword(cdr(expr))) ||
  46766. (arglist_has_rest(sc, closure_args(func)))) /* is this redundant? */
  46767. return(false);
  46768. if (pairs == quotes + all_x_count(expr))
  46769. {
  46770. set_unsafe_optimize_op(expr, hop + ((is_safe_closure(func) ? OP_SAFE_CLOSURE_STAR_ALL_X : OP_CLOSURE_STAR_ALL_X)));
  46771. annotate_args(sc, cdr(expr), e);
  46772. set_opt_lambda(expr, func);
  46773. set_arglist_length(expr, small_int(3));
  46774. return(false);
  46775. }
  46776. }
  46777. if (bad_pairs > quotes) return(false);
  46778. return(is_optimized(expr));
  46779. }
  46780. static bool optimize_func_many_args(s7_scheme *sc, s7_pointer expr, s7_pointer func, int hop, int args, int pairs, int symbols, int quotes, int bad_pairs, s7_pointer e)
  46781. {
  46782. bool func_is_closure;
  46783. if (bad_pairs > quotes) return(false);
  46784. if ((pairs == 0) &&
  46785. (is_immutable_symbol(car(expr))))
  46786. hop = 1;
  46787. if ((is_c_function(func)) &&
  46788. (c_function_required_args(func) <= (unsigned int)args) &&
  46789. (c_function_all_args(func) >= (unsigned int)args))
  46790. {
  46791. if (is_safe_procedure(func))
  46792. {
  46793. if (pairs == 0)
  46794. {
  46795. if (symbols == 0)
  46796. {
  46797. set_safe_optimize_op(expr, hop + OP_SAFE_C_C);
  46798. choose_c_function(sc, expr, func, args);
  46799. return(true);
  46800. }
  46801. if ((symbols == args) &&
  46802. (args < GC_TRIGGER_SIZE))
  46803. {
  46804. set_safe_optimize_op(expr, hop + OP_SAFE_C_ALL_S);
  46805. set_arglist_length(expr, make_permanent_integer(args));
  46806. choose_c_function(sc, expr, func, args);
  46807. return(true);
  46808. }
  46809. }
  46810. if ((args < GC_TRIGGER_SIZE) &&
  46811. (pairs == (quotes + all_x_count(expr))))
  46812. {
  46813. set_optimized(expr);
  46814. if (args == 4)
  46815. set_optimize_op(expr, hop + OP_SAFE_C_AAAA);
  46816. else set_optimize_op(expr, hop + OP_SAFE_C_ALL_X);
  46817. annotate_args(sc, cdr(expr), e);
  46818. set_arglist_length(expr, make_permanent_integer(args));
  46819. choose_c_function(sc, expr, func, args);
  46820. return(true);
  46821. }
  46822. }
  46823. else /* c_func is not safe */
  46824. {
  46825. if ((args < GC_TRIGGER_SIZE) &&
  46826. (pairs == (quotes + all_x_count(expr))))
  46827. {
  46828. set_unsafe_optimize_op(expr, hop + OP_C_ALL_X);
  46829. annotate_args(sc, cdr(expr), e);
  46830. set_arglist_length(expr, make_permanent_integer(args));
  46831. choose_c_function(sc, expr, func, args);
  46832. return(false);
  46833. }
  46834. }
  46835. return(is_optimized(expr));
  46836. }
  46837. func_is_closure = is_closure(func);
  46838. if (func_is_closure)
  46839. {
  46840. if (closure_arity_to_int(sc, func) != args)
  46841. return(false);
  46842. if ((pairs == 0) &&
  46843. ((symbols == args) || (symbols == 0)) &&
  46844. (args < GC_TRIGGER_SIZE))
  46845. {
  46846. bool safe_case;
  46847. safe_case = is_safe_closure(func);
  46848. set_unsafe_optimize_op(expr, hop + ((safe_case) ? OP_SAFE_CLOSURE_ALL_X : OP_CLOSURE_ALL_X));
  46849. annotate_args(sc, cdr(expr), e);
  46850. set_arglist_length(expr, make_permanent_integer(args));
  46851. set_opt_lambda(expr, func);
  46852. if ((!safe_case) &&
  46853. (symbols == args))
  46854. set_optimize_op(expr, hop + OP_CLOSURE_ALL_S);
  46855. return(false);
  46856. }
  46857. }
  46858. if ((is_closure_star(func)) &&
  46859. ((!has_simple_args(closure_body(func))) ||
  46860. (closure_star_arity_to_int(sc, func) < args) ||
  46861. (arglist_has_keyword(cdr(expr)))))
  46862. return(false);
  46863. if (args < GC_TRIGGER_SIZE)
  46864. {
  46865. if (((func_is_closure) ||
  46866. (is_closure_star(func))) &&
  46867. (!arglist_has_rest(sc, closure_args(func))) &&
  46868. (pairs == (quotes + all_x_count(expr))))
  46869. {
  46870. set_unsafely_optimized(expr);
  46871. if (func_is_closure)
  46872. set_optimize_op(expr, hop + ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_ALL_X : OP_CLOSURE_ALL_X));
  46873. else set_optimize_op(expr, hop + ((is_safe_closure(func)) ? OP_SAFE_CLOSURE_STAR_ALL_X : OP_CLOSURE_STAR_ALL_X));
  46874. annotate_args(sc, cdr(expr), e);
  46875. set_arglist_length(expr, make_permanent_integer(args));
  46876. set_opt_lambda(expr, func);
  46877. return(false);
  46878. }
  46879. }
  46880. return(is_optimized(expr));
  46881. }
  46882. static bool optimize_syntax(s7_scheme *sc, s7_pointer expr, s7_pointer func, int hop, s7_pointer e)
  46883. {
  46884. opcode_t op;
  46885. s7_pointer p, orig_e, body;
  46886. if (!is_pair(cdr(expr))) /* cddr(expr) might be null if, for example, (begin (let ...)) */
  46887. return(false);
  46888. op = (opcode_t)syntax_opcode(func);
  46889. sc->w = e;
  46890. orig_e = e;
  46891. body = cdr(expr);
  46892. switch (op)
  46893. {
  46894. case OP_QUOTE:
  46895. case OP_MACROEXPAND:
  46896. return(false);
  46897. case OP_LET:
  46898. case OP_LET_STAR:
  46899. if (is_symbol(cadr(expr)))
  46900. {
  46901. e = collect_collisions(sc, caddr(expr), cons(sc, add_sym_to_list(sc, cadr(expr)), e));
  46902. body = cdddr(expr);
  46903. }
  46904. else
  46905. {
  46906. e = collect_collisions(sc, cadr(expr), e);
  46907. body = cddr(expr);
  46908. }
  46909. break;
  46910. case OP_LETREC:
  46911. case OP_LETREC_STAR:
  46912. e = collect_collisions(sc, cadr(expr), e);
  46913. body = cddr(expr);
  46914. break;
  46915. case OP_DEFINE_MACRO:
  46916. case OP_DEFINE_MACRO_STAR:
  46917. case OP_DEFINE_BACRO:
  46918. case OP_DEFINE_BACRO_STAR:
  46919. case OP_DEFINE_CONSTANT:
  46920. case OP_DEFINE_EXPANSION:
  46921. case OP_DEFINE:
  46922. case OP_DEFINE_STAR:
  46923. if (is_pair(cadr(expr)))
  46924. {
  46925. s7_pointer name_args;
  46926. name_args = cadr(expr);
  46927. if (is_symbol(car(name_args)))
  46928. e = cons(sc, add_sym_to_list(sc, car(name_args)), e);
  46929. if (is_symbol(cdr(name_args)))
  46930. e = cons(sc, add_sym_to_list(sc, cdr(name_args)), e);
  46931. else e = collect_collisions_star(sc, cdr(name_args), e);
  46932. /* fprintf(stderr, "%s -> e: %s\n", DISPLAY(expr), DISPLAY(e)); */
  46933. }
  46934. body = cddr(expr);
  46935. break;
  46936. case OP_LAMBDA:
  46937. case OP_LAMBDA_STAR:
  46938. if (is_symbol(cadr(expr))) /* (lambda args ...) */
  46939. e = cons(sc, add_sym_to_list(sc, cadr(expr)), e);
  46940. else e = collect_collisions_star(sc, cadr(expr), e);
  46941. body = cddr(expr);
  46942. break;
  46943. case OP_SET:
  46944. if (is_symbol(cadr(expr)))
  46945. e = cons(sc, add_sym_to_list(sc, cadr(expr)), e);
  46946. body = sc->nil;
  46947. break;
  46948. case OP_DO:
  46949. e = collect_collisions(sc, cadr(expr), e);
  46950. body = cddr(expr);
  46951. break;
  46952. case OP_WITH_LET:
  46953. if (sc->safety != 0)
  46954. hop = 0;
  46955. orig_e = sc->nil;
  46956. e = sc->nil;
  46957. /* we can't trust anything here, so hop ought to be off. For example,
  46958. * (define (hi)
  46959. * (let ((e (sublet (curlet)
  46960. * (cons 'abs (lambda (a) (- a 1))))))
  46961. * (with-let e (abs -1))))
  46962. * returns 1 if hop is 1, but -2 outside the function body.
  46963. */
  46964. break;
  46965. default:
  46966. break;
  46967. }
  46968. if (is_pair(e)) sc->w = e;
  46969. /* fprintf(stderr, "%s -> e: %s\n", DISPLAY(expr), DISPLAY(e)); */
  46970. for (p = cdr(expr); is_pair(p); p = cdr(p))
  46971. {
  46972. if (p == body) orig_e = e;
  46973. if ((is_pair(car(p))) && (!is_checked(car(p)))) /* ((typeflag & (0xff | T_CHECKED)) == T_PAIR) is not faster */
  46974. optimize_expression(sc, car(p), hop, orig_e);
  46975. }
  46976. if ((hop == 1) &&
  46977. (symbol_id(car(expr)) == 0))
  46978. {
  46979. if ((op == OP_IF) || (op == OP_OR) || (op == OP_AND))
  46980. {
  46981. bool happy = true;
  46982. for (p = cdr(expr); (happy) && (is_pair(p)); p = cdr(p))
  46983. happy = is_all_x_safe(sc, car(p));
  46984. if ((happy) &&
  46985. (is_null(p))) /* catch the syntax error later: (or #f . 2) etc */
  46986. {
  46987. int args, symbols = 0, pairs = 0, rest = 0;
  46988. s7_pointer sym = NULL;
  46989. bool c_s_is_ok = true;
  46990. for (args = 0, p = cdr(expr); is_pair(p); p = cdr(p), args++)
  46991. {
  46992. if (is_symbol(car(p)))
  46993. symbols++;
  46994. else
  46995. {
  46996. if (!is_pair(car(p)))
  46997. rest++;
  46998. else
  46999. {
  47000. pairs++;
  47001. if ((c_s_is_ok) &&
  47002. ((!is_h_safe_c_s(car(p))) ||
  47003. ((sym) && (sym != cadar(p)))))
  47004. c_s_is_ok = false;
  47005. else sym = cadar(p);
  47006. }
  47007. }
  47008. }
  47009. if ((op == OP_IF) &&
  47010. ((args < 2) || (args > 3))) /* syntax error */
  47011. return(false);
  47012. set_safe_optimize_op(expr, hop + OP_SAFE_C_C);
  47013. if (pairs == 0)
  47014. {
  47015. if (op == OP_OR)
  47016. set_c_function(expr, or_direct);
  47017. else
  47018. {
  47019. if (op == OP_AND)
  47020. set_c_function(expr, and_direct);
  47021. else set_c_function(expr, if_direct);
  47022. }
  47023. return(true);
  47024. }
  47025. if ((pairs == args) &&
  47026. (c_s_is_ok))
  47027. {
  47028. if (op == OP_OR)
  47029. set_c_function(expr, or_s_direct);
  47030. else
  47031. {
  47032. if (op == OP_AND)
  47033. set_c_function(expr, and_s_direct);
  47034. else set_c_function(expr, if_s_direct);
  47035. }
  47036. return(true);
  47037. }
  47038. for (p = cdr(expr); is_pair(p); p = cdr(p))
  47039. set_c_call(p, all_x_eval(sc, car(p), e, pair_symbol_is_safe));
  47040. if (op == OP_OR)
  47041. {
  47042. if (s7_list_length(sc, cdr(expr)) == 2)
  47043. {
  47044. set_c_function(expr, or_all_x_2);
  47045. if ((c_call(cdr(expr)) == all_x_c_u) &&
  47046. (c_call(cddr(expr)) == all_x_c_u))
  47047. set_c_function(expr, or_all_x_2s);
  47048. }
  47049. else set_c_function(expr, or_all_x);
  47050. }
  47051. else
  47052. {
  47053. if (op == OP_AND)
  47054. {
  47055. if (s7_list_length(sc, cdr(expr)) == 2)
  47056. set_c_function(expr, and_all_x_2);
  47057. else set_c_function(expr, and_all_x);
  47058. }
  47059. else
  47060. {
  47061. s7_pointer test, b1, b2;
  47062. test = cdr(expr);
  47063. b1 = cdr(test);
  47064. b2 = cdr(b1);
  47065. if ((c_call(b1) == all_x_q) &&
  47066. (is_pair(b2)))
  47067. {
  47068. if (c_call(b2) == all_x_q)
  47069. set_c_function(expr, if_all_x_qq);
  47070. else set_c_function(expr, if_all_x_qa);
  47071. }
  47072. else
  47073. {
  47074. if ((is_pair(car(test))) &&
  47075. (caar(test) == sc->not_symbol))
  47076. {
  47077. set_c_call(test, all_x_eval(sc, cadar(test), e, pair_symbol_is_safe));
  47078. if (is_null(b2))
  47079. set_c_function(expr, if_all_not_x1);
  47080. else set_c_function(expr, if_all_not_x2);
  47081. }
  47082. else
  47083. {
  47084. if (is_null(b2))
  47085. set_c_function(expr, if_all_x1);
  47086. else set_c_function(expr, if_all_x2);
  47087. }
  47088. }
  47089. }
  47090. }
  47091. return(true);
  47092. }
  47093. /* else we could check other if cases here (test is often all_x_safe)
  47094. */
  47095. }
  47096. }
  47097. return(false);
  47098. }
  47099. static bool optimize_expression(s7_scheme *sc, s7_pointer expr, int hop, s7_pointer e)
  47100. {
  47101. s7_pointer car_expr;
  47102. /* fprintf(stderr, "opt %d %s %s\n", hop, DISPLAY(expr), DISPLAY(e)); */
  47103. /* if (is_checked(expr)) return(true); */
  47104. set_checked(expr);
  47105. car_expr = car(expr);
  47106. if (is_symbol(car_expr))
  47107. {
  47108. s7_pointer func;
  47109. if (is_syntactic(car_expr))
  47110. return(optimize_syntax(sc, expr, _TSyn(slot_value(global_slot(car_expr))), hop, e));
  47111. if (car_expr == sc->quote_symbol)
  47112. return(false);
  47113. func = find_uncomplicated_symbol(sc, car_expr, e);
  47114. if (is_slot(func))
  47115. {
  47116. func = slot_value(func);
  47117. if (is_syntax(func)) /* 12-8-16 was is_syntactic, but that is only appropriate above -- here we have the value */
  47118. return(optimize_syntax(sc, expr, func, hop, e));
  47119. /* we miss implicit indexing here because at this time, the data are not set */
  47120. if ((is_procedure(func)) ||
  47121. (is_c_function(func)) ||
  47122. (is_safe_procedure(func))) /* built-in applicable objects like vectors */
  47123. {
  47124. int pairs = 0, symbols = 0, args = 0, bad_pairs = 0, quotes = 0, orig_hop;
  47125. s7_pointer p;
  47126. orig_hop = hop;
  47127. if ((is_any_closure(func)) || /* can't depend on opt1 here because it might not be global, or might be redefined locally */
  47128. ((!is_global(car_expr)) &&
  47129. ((!is_slot(global_slot(car_expr))) ||
  47130. (slot_value(global_slot(car_expr)) != func))))
  47131. {
  47132. /* (let () (define (f2 a) (+ a 1)) (define (f1 a) (f2 a)) (define (f2 a) (- a)) (f1 12))
  47133. * (let () (define (f2 a) (+ a 1)) (define (f1 a) (f2 a)) (define (f2 a) (- a 1)) (f1 12))
  47134. * and similar define* cases
  47135. */
  47136. hop = 0;
  47137. /* this is very tricky! See s7test for some cases. Basically, we need to protect a recursive call
  47138. * of the current function being optimized from being confused with some previous definition
  47139. * of the same name. But method lists have global names so the global bit is off even though the
  47140. * thing is actually a safe global. But no closure can be considered safe in the hop sense --
  47141. * even a global function might be redefined at any time, and previous uses of it in other functions
  47142. * need to reflect its new value.
  47143. * So, closures are always checked, but built-in functions are used as if never redefined until that redefinition.
  47144. * costs: index 6/1380, t502: 2/12900, bench: 43/4134, snd-test: 22/37200
  47145. * Syntax handling is already impure in s7, so the special handling of built-in functions doesn't
  47146. * offend me much. Consider each a sort of reader macro until someone redefines it -- previous
  47147. * uses may not be affected because they might have been optimized away -- the result depends on the
  47148. * current optimizer.
  47149. * Another case (from K Matheussen):
  47150. * (define (call-func func arg1 arg2) (define (call) (func arg1 arg2)) (call)) (call-func + 1 2.5) (call-func - 5 2)
  47151. * when we get here originally "func" is +, hop=1, but just checking for !is_global(car_expr) is
  47152. * not good enough -- if we load mockery.scm, nothing is global!
  47153. */
  47154. }
  47155. /* but if we make a recursive call on a func, we've obviously already looked up that function, and
  47156. * if it has not been shadowed, then we don't need to check it -- so the hop bit should be on
  47157. * for that one case.
  47158. */
  47159. for (p = cdr(expr); is_pair(p); p = cdr(p), args++) /* check the args (the calling expression) */
  47160. {
  47161. s7_pointer car_p;
  47162. car_p = car(p);
  47163. if (is_symbol(car_p))
  47164. symbols++;
  47165. else
  47166. {
  47167. if (is_pair(car_p))
  47168. {
  47169. pairs++;
  47170. if (!is_checked(car_p))
  47171. {
  47172. if (!optimize_expression(sc, car_p, orig_hop, e))
  47173. {
  47174. bad_pairs++;
  47175. if ((car(car_p) == sc->quote_symbol) &&
  47176. (is_pair(cdr(car_p))) &&
  47177. (is_null(cddr(car_p))))
  47178. quotes++;
  47179. }
  47180. }
  47181. else
  47182. {
  47183. if ((!is_optimized(car_p)) ||
  47184. (is_unsafe(car_p)))
  47185. {
  47186. bad_pairs++;
  47187. if ((car(car_p) == sc->quote_symbol) &&
  47188. (is_pair(cdr(car_p))) &&
  47189. (is_null(cddr(car_p))))
  47190. quotes++;
  47191. }
  47192. }
  47193. }
  47194. }
  47195. }
  47196. if (is_null(p)) /* if not null, dotted list of args? */
  47197. {
  47198. switch (args)
  47199. {
  47200. case 0: return(optimize_thunk(sc, expr, func, hop));
  47201. case 1: return(optimize_func_one_arg(sc, expr, func, hop, pairs, symbols, quotes, bad_pairs, e));
  47202. case 2: return(optimize_func_two_args(sc, expr, func, hop, pairs, symbols, quotes, bad_pairs, e));
  47203. case 3: return(optimize_func_three_args(sc, expr, func, hop, pairs, symbols, quotes, bad_pairs, e));
  47204. default: return(optimize_func_many_args(sc, expr, func, hop, args, pairs, symbols, quotes, bad_pairs, e));
  47205. }
  47206. }
  47207. return(false);
  47208. }
  47209. }
  47210. else
  47211. {
  47212. if ((sc->undefined_identifier_warnings) &&
  47213. (func == sc->undefined) && /* car_expr is not in e or global */
  47214. (symbol_tag(car_expr) == 0)) /* and we haven't looked it up earlier */
  47215. {
  47216. s7_pointer p;
  47217. p = sc->input_port;
  47218. if ((is_input_port(p)) &&
  47219. (port_file(p) != stdin) &&
  47220. (!port_is_closed(p)) &&
  47221. (port_filename(p)))
  47222. s7_warn(sc, 1024, "%s might be undefined (%s %u)\n", DISPLAY(car_expr), port_filename(p), port_line_number(p));
  47223. else s7_warn(sc, 1024, "; %s might be undefined\n", DISPLAY(car_expr));
  47224. symbol_set_tag(car_expr, 1); /* one warning is enough */
  47225. }
  47226. /* we need local definitions and func args in e? also check is_symbol case below
  47227. */
  47228. }
  47229. /* car_expr is a symbol but it's not a known procedure or a "safe" case = vector etc */
  47230. {
  47231. /* else maybe it's something like a let variable binding: (sqrtfreq (sqrt frequency)) */
  47232. s7_pointer p;
  47233. int len = 0, pairs = 0, symbols = 0, quotes = 0;
  47234. for (p = cdr(expr); is_pair(p); p = cdr(p), len++)
  47235. {
  47236. s7_pointer car_p;
  47237. car_p = car(p);
  47238. if (is_pair(car_p))
  47239. {
  47240. pairs++;
  47241. if ((hop != 0) && (car(car_p) == sc->quote_symbol))
  47242. quotes++;
  47243. if (!is_checked(car_p))
  47244. optimize_expression(sc, car_p, hop, e);
  47245. }
  47246. else
  47247. {
  47248. if (is_symbol(car_p))
  47249. symbols++;
  47250. }
  47251. }
  47252. if ((is_null(p)) && /* (+ 1 . 2) */
  47253. (!is_optimized(expr)))
  47254. {
  47255. /* len=0 case is almost entirely arglists */
  47256. set_opt_con1(expr, sc->gc_nil);
  47257. if (pairs == 0)
  47258. {
  47259. if (len == 0)
  47260. {
  47261. /* hoping to catch object application here, as in readers in Snd */
  47262. set_unsafe_optimize_op(expr, OP_UNKNOWN);
  47263. return(false);
  47264. }
  47265. if (len == 1)
  47266. {
  47267. if (car_expr != sc->quote_symbol) /* !! quote can be redefined locally, unsetting the T_SYNTACTIC flag -- can this happen elsewhere? */
  47268. {
  47269. set_unsafe_optimize_op(expr, OP_UNKNOWN_G);
  47270. /* hooboy -- we get here in let bindings...
  47271. * to save access to the caller, we'd need to pass it as an arg to optimize_expression
  47272. */
  47273. }
  47274. return(false);
  47275. }
  47276. if (len == 2)
  47277. {
  47278. set_unsafely_optimized(expr);
  47279. if (symbols == 2)
  47280. set_optimize_op(expr, OP_UNKNOWN_GG);
  47281. else
  47282. {
  47283. if (symbols == 0)
  47284. set_optimize_op(expr, OP_UNKNOWN_GG);
  47285. else
  47286. {
  47287. if (is_symbol(cadr(expr)))
  47288. set_optimize_op(expr, OP_UNKNOWN_GG);
  47289. else set_optimize_op(expr, OP_UNKNOWN_GG);
  47290. }
  47291. }
  47292. return(false);
  47293. }
  47294. if ((len >= 3) &&
  47295. (len == symbols))
  47296. {
  47297. set_unsafe_optimize_op(expr, OP_UNKNOWN_ALL_S);
  47298. set_arglist_length(expr, make_permanent_integer(len));
  47299. return(false);
  47300. }
  47301. }
  47302. else /* pairs != 0 */
  47303. {
  47304. s7_pointer arg1;
  47305. arg1 = cadr(expr);
  47306. if (pairs == 1)
  47307. {
  47308. if (len == 1)
  47309. {
  47310. if (quotes == 1)
  47311. {
  47312. set_unsafe_optimize_op(expr, OP_UNKNOWN_A);
  47313. return(false);
  47314. }
  47315. if (is_all_x_safe(sc, arg1))
  47316. {
  47317. set_arglist_length(expr, small_int(1));
  47318. set_unsafe_optimize_op(expr, OP_UNKNOWN_A);
  47319. return(false);
  47320. }
  47321. }
  47322. else
  47323. {
  47324. if (len == 2)
  47325. {
  47326. if ((is_all_x_safe(sc, arg1)) &&
  47327. (is_all_x_safe(sc, caddr(expr))))
  47328. {
  47329. set_arglist_length(expr, small_int(2));
  47330. set_unsafe_optimize_op(expr, OP_UNKNOWN_AA);
  47331. return(false);
  47332. }
  47333. }
  47334. }
  47335. }
  47336. if ((len == 2) &&
  47337. (is_all_x_safe(sc, arg1)) &&
  47338. (is_all_x_safe(sc, caddr(expr))))
  47339. {
  47340. set_arglist_length(expr, small_int(2));
  47341. set_unsafe_optimize_op(expr, OP_UNKNOWN_AA);
  47342. return(false);
  47343. }
  47344. if ((pairs == (quotes + all_x_count(expr))) &&
  47345. (len < GC_TRIGGER_SIZE))
  47346. {
  47347. set_unsafe_optimize_op(expr, (len == 1) ? OP_UNKNOWN_A : OP_UNKNOWN_ALL_X);
  47348. set_arglist_length(expr, make_permanent_integer(len));
  47349. return(false);
  47350. }
  47351. }
  47352. }
  47353. }
  47354. }
  47355. else
  47356. {
  47357. /* car(expr) is not a symbol, but there might be interesting stuff here */
  47358. /* (define (hi a) (case 1 ((1) (if (> a 2) a 2)))) */
  47359. s7_pointer p;
  47360. for (p = expr; is_pair(p); p = cdr(p))
  47361. {
  47362. if ((is_pair(car(p))) && (!is_checked(car(p))))
  47363. optimize_expression(sc, car(p), hop, e);
  47364. }
  47365. }
  47366. return(false);
  47367. }
  47368. static s7_pointer optimize(s7_scheme *sc, s7_pointer code, int hop, s7_pointer e)
  47369. {
  47370. s7_pointer x;
  47371. if (sc->safety > 1) return(NULL);
  47372. /* fprintf(stderr, "optimize %s %d %s\n", DISPLAY_80(code), hop, DISPLAY(e)); */
  47373. for (x = code; (is_pair(x)) && (!is_checked(x)); x = cdr(x))
  47374. {
  47375. set_checked(x);
  47376. if ((is_pair(car(x))) && (!is_checked(car(x))))
  47377. optimize_expression(sc, car(x), hop, e);
  47378. }
  47379. if ((!is_null(x)) &&
  47380. (!is_pair(x)))
  47381. eval_error(sc, "stray dot in function body: ~S", code);
  47382. return(NULL);
  47383. }
  47384. #if WITH_GCC
  47385. #define indirect_c_function_is_ok(Sc, X) ({s7_pointer _X_; _X_ = X; (((optimize_op(_X_) & 0x1) != 0) || (c_function_is_ok(Sc, _X_)));})
  47386. #define indirect_cq_function_is_ok(Sc, X) ({s7_pointer _X_; _X_ = X; ((!is_optimized(_X_)) || ((optimize_op(_X_) & 0x1) != 0) || (c_function_is_ok(Sc, _X_)));})
  47387. #else
  47388. #define indirect_c_function_is_ok(Sc, X) (((optimize_op(X) & 0x1) != 0) || (c_function_is_ok(Sc, X)))
  47389. #define indirect_cq_function_is_ok(Sc, X) ((!is_optimized(X)) || ((optimize_op(X) & 0x1) != 0) || (c_function_is_ok(Sc, X)))
  47390. #endif
  47391. static bool body_is_safe(s7_scheme *sc, s7_pointer func, s7_pointer body, bool at_end);
  47392. static bool form_is_safe(s7_scheme *sc, s7_pointer func, s7_pointer x, bool at_end)
  47393. {
  47394. /* called only from body_is_safe and itself */
  47395. s7_pointer expr;
  47396. sc->cycle_counter++;
  47397. if ((!is_proper_list(sc, x)) ||
  47398. (sc->cycle_counter > 5000))
  47399. return(false);
  47400. expr = car(x);
  47401. if (is_syntactic_symbol(expr))
  47402. {
  47403. switch (symbol_syntax_op(expr))
  47404. {
  47405. case OP_OR:
  47406. case OP_AND:
  47407. case OP_BEGIN:
  47408. case OP_WITH_BAFFLE:
  47409. if (!body_is_safe(sc, func, cdr(x), at_end))
  47410. return(false);
  47411. break;
  47412. case OP_MACROEXPAND:
  47413. return(false);
  47414. case OP_QUOTE:
  47415. break;
  47416. /* in the name binders, we first have to check that "func" actually is the same thing as the caller's func */
  47417. case OP_LET:
  47418. case OP_LET_STAR:
  47419. if (is_symbol(cadr(x)))
  47420. return(false);
  47421. case OP_LETREC:
  47422. case OP_LETREC_STAR:
  47423. if (is_pair(cadr(x)))
  47424. {
  47425. s7_pointer vars;
  47426. for (vars = cadr(x); is_pair(vars); vars = cdr(vars))
  47427. {
  47428. s7_pointer let_var;
  47429. let_var = car(vars);
  47430. if ((!is_pair(let_var)) ||
  47431. (!is_pair(cdr(let_var))))
  47432. return(false);
  47433. if (car(let_var) == func)
  47434. return(false); /* it's shadowed */
  47435. if ((is_pair(cadr(let_var))) &&
  47436. (!form_is_safe(sc, func, cadr(let_var), false)))
  47437. return(false);
  47438. }
  47439. }
  47440. if (!body_is_safe(sc, func, cddr(x), at_end))
  47441. return(false);
  47442. break;
  47443. case OP_IF:
  47444. if (!is_pair(cdr(x))) return(false); /* (if) ! */
  47445. if (!((!is_pair(cadr(x))) || (form_is_safe(sc, func, cadr(x), false)))) return(false);
  47446. if (!((!is_pair(caddr(x))) || (form_is_safe(sc, func, caddr(x), at_end)))) return(false);
  47447. if (!((!is_pair(cdddr(x))) || (!is_pair(cadddr(x))) || (form_is_safe(sc, func, cadddr(x), at_end)))) return(false);
  47448. break;
  47449. case OP_WHEN:
  47450. case OP_UNLESS:
  47451. if (!is_pair(cdr(x))) return(false); /* (when) */
  47452. if (!((!is_pair(cadr(x))) || (form_is_safe(sc, func, cadr(x), false)))) return(false);
  47453. if (!body_is_safe(sc, func, cddr(x), at_end)) return(false);
  47454. break;
  47455. case OP_COND:
  47456. {
  47457. s7_pointer p;
  47458. for (p = cdr(x); is_pair(p); p = cdr(p))
  47459. {
  47460. s7_pointer ex;
  47461. ex = car(p);
  47462. if (is_pair(ex)) /* ?? */
  47463. {
  47464. if ((is_pair(car(ex))) && (!form_is_safe(sc, func, car(ex), false)))
  47465. return(false);
  47466. if ((is_pair(cdr(ex))) && (!body_is_safe(sc, func, cdr(ex), at_end)))
  47467. return(false);
  47468. }
  47469. }
  47470. if (is_not_null(p))
  47471. return(false);
  47472. }
  47473. break;
  47474. case OP_CASE:
  47475. {
  47476. s7_pointer p;
  47477. if ((is_pair(cadr(x))) && (!form_is_safe(sc, func, cadr(x), false))) return(false);
  47478. for (p = cddr(x); is_pair(p); p = cdr(p))
  47479. if ((is_pair(car(p))) && (!body_is_safe(sc, func, cdar(p), at_end)))
  47480. return(false);
  47481. }
  47482. break;
  47483. case OP_DO:
  47484. /* (do (...) (...) ...) */
  47485. if (!is_pair(cddr(x)))
  47486. return(false);
  47487. if (!body_is_safe(sc, func, cdddr(x), false))
  47488. return(false);
  47489. if (is_pair(cadr(x)))
  47490. {
  47491. s7_pointer vars;
  47492. for (vars = cadr(x); is_pair(vars); vars = cdr(vars))
  47493. {
  47494. s7_pointer do_var;
  47495. do_var = car(vars);
  47496. if (!is_pair(do_var))
  47497. return(false);
  47498. if ((car(do_var) == func) ||
  47499. (!is_pair(cdr(do_var)))) /* (do ((a . 1) (b . 2)) ...) */
  47500. return(false);
  47501. if ((is_pair(cadr(do_var))) &&
  47502. (!form_is_safe(sc, func, cadr(do_var), false)))
  47503. return(false);
  47504. if ((is_pair(cddr(do_var))) &&
  47505. (is_pair(caddr(do_var))) &&
  47506. (!form_is_safe(sc, func, caddr(do_var), false)))
  47507. return(false);
  47508. }
  47509. }
  47510. if ((is_pair(caddr(x))) &&
  47511. (!body_is_safe(sc, func, caddr(x), at_end)))
  47512. return(false);
  47513. break;
  47514. case OP_SET:
  47515. /* if we set func, we have to make sure we abandon the tail call scan:
  47516. * (let () (define (hi a) (let ((v (vector 1 2 3))) (set! hi v) (hi a))) (hi 1))
  47517. */
  47518. if (!is_pair(cdr(x))) return(false); /* (set!) ! */
  47519. if (cadr(x) == func)
  47520. return(false);
  47521. /* car(x) is set!, cadr(x) is settee or obj, caddr(x) is val */
  47522. if (is_symbol(caddr(x)))
  47523. return(false); /* ?? because it might be a local function that has captured local state? */
  47524. if (((!is_pair(caddr(x))) || (form_is_safe(sc, func, caddr(x), false))) &&
  47525. ((is_symbol(cadr(x))) ||
  47526. ((is_pair(cadr(x))) && (form_is_safe(sc, func, cadr(x), false)))))
  47527. return(true);
  47528. return(false);
  47529. case OP_WITH_LET:
  47530. if (is_pair(cadr(x)))
  47531. return(false);
  47532. if (!body_is_safe(sc, sc->F, cddr(x), at_end))
  47533. return(false);
  47534. break;
  47535. /* op_define and friends are not safe: (define (a) (define b 3)...) tries to put b in the current env,
  47536. * but in a safe func, that's a constant. See s7test L 1865 for an example.
  47537. */
  47538. default:
  47539. /* try to catch weird cases like:
  47540. * (let () (define (hi1 a) (define (hi1 b) (+ b 1)) (hi1 a)) (hi1 1))
  47541. * (let () (define (hi1 a) (define (ho1 b) b) (define (hi1 b) (+ b 1)) (hi1 a)) (hi1 1))
  47542. */
  47543. return(false);
  47544. }
  47545. }
  47546. else /* car(x) is not syntactic ?? */
  47547. {
  47548. if ((!is_optimized(x)) ||
  47549. (is_unsafe(x)))
  47550. {
  47551. if (expr == func) /* try to catch tail call */
  47552. {
  47553. s7_pointer p;
  47554. for (p = cdr(x); is_pair(p); p = cdr(p))
  47555. if ((is_pair(car(p))) &&
  47556. (((!is_optimized(car(p))) && (caar(p) != sc->quote_symbol)) ||
  47557. (is_unsafe(car(p))) ||
  47558. (caar(p) == func))) /* func called as arg, so not tail call */
  47559. return(false);
  47560. if ((at_end) && (is_null(p))) /* tail call, so safe */
  47561. return(true);
  47562. return(false);
  47563. }
  47564. if (is_symbol(expr))
  47565. {
  47566. if (is_global(expr))
  47567. {
  47568. s7_pointer f;
  47569. f = find_symbol_checked(sc, expr);
  47570. if (((is_c_function(f)) &&
  47571. ((is_safe_procedure(f)) ||
  47572. ((is_possibly_safe(f)) &&
  47573. (is_pair(cdr(x))) &&
  47574. (is_pair(cddr(x))) &&
  47575. (unsafe_is_safe(sc, f, cadr(x), caddr(x), (is_pair(cdddr(x))) ? cadddr(x) : NULL, sc->nil))))) ||
  47576. ((is_closure(f)) &&
  47577. (is_safe_closure(f))))
  47578. {
  47579. s7_pointer p;
  47580. for (p = cdr(x); is_pair(p); p = cdr(p))
  47581. if ((is_pair(car(p))) &&
  47582. ((!is_optimized(car(p))) ||
  47583. (is_unsafe(car(p)))))
  47584. {
  47585. if ((caar(p) != func) ||
  47586. (!is_null(cdr(p))))
  47587. return(false);
  47588. }
  47589. if (!is_null(p))
  47590. return(false);
  47591. }
  47592. }
  47593. else
  47594. {
  47595. s7_pointer f;
  47596. f = find_symbol(sc, expr);
  47597. if (is_slot(f))
  47598. {
  47599. if ((is_syntax(slot_value(f))) || (is_any_macro(slot_value(f))))
  47600. return(false);
  47601. if ((is_closure(slot_value(f))) &&
  47602. (is_safe_closure(slot_value(f))))
  47603. {
  47604. s7_pointer p;
  47605. /* the calling function is safe, but what about its arguments? */
  47606. for (p = cdr(x); is_pair(p); p = cdr(p))
  47607. if ((is_pair(car(p))) &&
  47608. (caar(p) == func)) /* this would be a recursive call on func that is not in tail-call position */
  47609. return(false);
  47610. return(true);
  47611. }
  47612. }
  47613. }
  47614. }
  47615. return(false);
  47616. }
  47617. }
  47618. return(true);
  47619. }
  47620. static bool body_is_safe(s7_scheme *sc, s7_pointer func, s7_pointer body, bool at_end)
  47621. {
  47622. /* called in optimize_lambda and above */
  47623. s7_pointer p;
  47624. for (p = body; is_pair(p); p = cdr(p))
  47625. if ((is_pair(car(p))) &&
  47626. (!form_is_safe(sc, func, car(p), (at_end) && (is_null(cdr(p))))))
  47627. return(false);
  47628. return(is_null(p));
  47629. }
  47630. /* ---------------------------------------- error checks ---------------------------------------- */
  47631. #define goto_START 0
  47632. #define goto_BEGIN1 1
  47633. #define fall_through 2
  47634. #define goto_DO_END_CLAUSES 3
  47635. #define goto_SAFE_DO_END_CLAUSES 4
  47636. #define goto_OPT_EVAL 5
  47637. #define goto_START_WITHOUT_POP_STACK 6
  47638. #define goto_EVAL 7
  47639. #define goto_APPLY 8
  47640. #define goto_EVAL_ARGS 9
  47641. #define goto_DO_UNCHECKED 10
  47642. static s7_pointer check_lambda_args(s7_scheme *sc, s7_pointer args, int *arity)
  47643. {
  47644. s7_pointer x;
  47645. int i;
  47646. if ((!is_pair(args)) && (!is_null(args)))
  47647. {
  47648. if (s7_is_constant(args)) /* (lambda :a ...) */
  47649. eval_error(sc, "lambda parameter '~S is a constant", args); /* not ~A here, (lambda #\null do) for example */
  47650. /* we currently accept (lambda i i . i) (lambda quote i) (lambda : : . #()) (lambda : 1 . "")
  47651. * at this level, but when the lambda form is evaluated, it will trigger an error.
  47652. */
  47653. if (is_symbol(args))
  47654. set_local(args);
  47655. if (arity) (*arity) = -1;
  47656. return(sc->F);
  47657. }
  47658. for (i = 0, x = args; is_pair(x); i++, x = cdr(x))
  47659. {
  47660. s7_pointer car_x;
  47661. car_x = car(x);
  47662. if (s7_is_constant(car_x)) /* (lambda (pi) pi), constant here means not a symbol */
  47663. {
  47664. if (is_pair(car_x)) /* (lambda ((:hi . "hi") . "hi") 1) */
  47665. eval_error(sc, "lambda parameter '~S is a pair (perhaps you want define* or lambda*?)", car_x);
  47666. eval_error(sc, "lambda parameter '~S is a constant", car_x);
  47667. }
  47668. if (symbol_is_in_arg_list(car_x, cdr(x))) /* (lambda (a a) ...) or (lambda (a . a) ...) */
  47669. eval_error(sc, "lambda parameter '~S is used twice in the parameter list", car_x);
  47670. set_local(car_x);
  47671. }
  47672. if (is_not_null(x))
  47673. {
  47674. if (s7_is_constant(x)) /* (lambda (a . 0.0) a) or (lambda (a . :b) a) */
  47675. eval_error(sc, "lambda :rest parameter '~S is a constant", x);
  47676. i = -i - 1;
  47677. }
  47678. if (arity) (*arity) = i;
  47679. return(sc->F);
  47680. }
  47681. static s7_pointer check_lambda_star_args(s7_scheme *sc, s7_pointer args, int *arity)
  47682. {
  47683. s7_pointer top, v, w;
  47684. int i;
  47685. if (!s7_is_list(sc, args))
  47686. {
  47687. if (s7_is_constant(args)) /* (lambda* :a ...) */
  47688. eval_error(sc, "lambda* parameter '~S is a constant", args);
  47689. if (is_symbol(args))
  47690. set_local(args);
  47691. if (arity) (*arity) = -1;
  47692. return(args);
  47693. }
  47694. top = args;
  47695. v = args;
  47696. for (i = 0, w = args; is_pair(w); i++, v = w, w = cdr(w))
  47697. {
  47698. s7_pointer car_w;
  47699. car_w = car(w);
  47700. if (is_pair(car_w))
  47701. {
  47702. if (s7_is_constant(car(car_w))) /* (lambda* ((:a 1)) ...) */
  47703. eval_error(sc, "lambda* parameter '~A is a constant", car(car_w));
  47704. if (symbol_is_in_arg_list(caar(w), cdr(w))) /* (lambda* ((a 1) a) ...) */
  47705. eval_error(sc, "lambda* parameter '~A is used twice in the argument list", car(car_w));
  47706. if (!is_pair(cdr(car_w))) /* (lambda* ((a . 0.0)) a) */
  47707. {
  47708. if (is_null(cdr(car_w))) /* (lambda* ((a)) ...) */
  47709. eval_error(sc, "lambda* parameter default value missing? '~A", car_w);
  47710. eval_error(sc, "lambda* parameter is a dotted pair? '~A", car_w);
  47711. }
  47712. else
  47713. {
  47714. if ((is_pair(cadr(car_w))) && /* (lambda* ((a (quote . -1))) ...) */
  47715. (s7_list_length(sc, cadr(car_w)) < 0))
  47716. eval_error(sc, "lambda* parameter default value is improper? ~A", car_w);
  47717. }
  47718. if (is_not_null(cddr(car_w))) /* (lambda* ((a 0.0 'hi)) a) */
  47719. eval_error(sc, "lambda* parameter has multiple default values? '~A", car_w);
  47720. set_local(car(car_w));
  47721. }
  47722. else
  47723. {
  47724. if (car_w != sc->key_rest_symbol)
  47725. {
  47726. if (s7_is_constant(car_w))
  47727. {
  47728. if (car_w == sc->key_allow_other_keys_symbol)
  47729. {
  47730. if (is_not_null(cdr(w))) /* (lambda* (:allow-other-keys x) x) */
  47731. eval_error(sc, ":allow-other-keys should be the last parameter: ~A", args);
  47732. if (w == top)
  47733. eval_error(sc, ":allow-other-keys can't be the only parameter: ~A", args);
  47734. set_allow_other_keys(top);
  47735. set_cdr(v, sc->nil);
  47736. }
  47737. else /* (lambda* (pi) ...) */
  47738. eval_error(sc, "lambda* parameter '~A is a constant", car_w);
  47739. }
  47740. if (symbol_is_in_arg_list(car_w, cdr(w))) /* (lambda* (a a) ...) or (lambda* (a . a) ...) */
  47741. eval_error(sc, "lambda* parameter '~A is used twice in the argument list", car_w);
  47742. if (!is_keyword(car_w)) set_local(car_w);
  47743. }
  47744. else
  47745. {
  47746. if (!is_pair(cdr(w))) /* (lambda* (:rest) ...) */
  47747. eval_error(sc, "lambda* :rest parameter missing? ~A", w);
  47748. if (!is_symbol(cadr(w))) /* (lambda* (:rest (a 1)) ...) */
  47749. {
  47750. if (!is_pair(cadr(w))) /* (lambda* (:rest 1) ...) */
  47751. eval_error(sc, "lambda* :rest parameter is not a symbol? ~A", w);
  47752. eval_error(sc, "lambda* :rest parameter can't have a default value. ~A", w);
  47753. }
  47754. else
  47755. {
  47756. if (is_immutable_symbol(cadr(w)))
  47757. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "can't bind an immutable object: ~S"), w)));
  47758. }
  47759. set_local(cadr(w));
  47760. }
  47761. }
  47762. }
  47763. if (is_not_null(w))
  47764. {
  47765. if (s7_is_constant(w)) /* (lambda* (a . 0.0) a) or (lambda* (a . :b) a) */
  47766. eval_error(sc, "lambda* :rest parameter '~A is a constant", w);
  47767. if (is_symbol(w))
  47768. set_local(w);
  47769. i = -1;
  47770. }
  47771. if (arity) (*arity) = i;
  47772. return(top);
  47773. }
  47774. static void check_lambda(s7_scheme *sc)
  47775. {
  47776. /* code is a lambda form minus the "lambda": ((a b) (+ a b)) */
  47777. /* this includes unevaluated symbols (direct symbol table refs) in macro arg list */
  47778. s7_pointer code, body;
  47779. code = sc->code;
  47780. if (!is_pair(code)) /* (lambda) or (lambda . 1) */
  47781. eval_error_no_return(sc, sc->syntax_error_symbol, "lambda: no args? ~A", current_code(sc));
  47782. body = cdr(code);
  47783. if (!is_pair(body)) /* (lambda #f) */
  47784. eval_error_no_return(sc, sc->syntax_error_symbol, "lambda: no body? ~A", code);
  47785. /* in many cases, this is a no-op -- we already checked at define */
  47786. check_lambda_args(sc, car(code), NULL);
  47787. clear_syms_in_list(sc);
  47788. /* look for (define f (let (...) (lambda ...))) and treat as equivalent to (define (f ...)...)
  47789. * one problem the hop=0 fixes is that safe closures assume the old frame exists, so we need to check for define below
  47790. * I wonder about apply define...
  47791. */
  47792. if ((sc->safety == 0) &&
  47793. ((main_stack_op(sc) == OP_DEFINE1) ||
  47794. (((sc->stack_end - sc->stack_start) > 4) &&
  47795. (((opcode_t)(sc->stack_end[-5])) == OP_DEFINE1) && /* surely if define is ok, so is define dilambda? 16-Apr-16 */
  47796. (sc->op_stack_now > sc->op_stack) &&
  47797. ((*(sc->op_stack_now - 1)) == (s7_pointer)slot_value(global_slot(sc->dilambda_symbol))))))
  47798. optimize_lambda(sc, true, sc->gc_nil, car(code), body); /* why was lambda the func? */
  47799. else optimize(sc, body, 0, sc->nil);
  47800. if ((is_overlaid(code)) &&
  47801. (has_opt_back(code)))
  47802. pair_set_syntax_symbol(code, sc->lambda_unchecked_symbol);
  47803. }
  47804. static void check_lambda_star(s7_scheme *sc)
  47805. {
  47806. if ((!is_pair(sc->code)) ||
  47807. (!is_pair(cdr(sc->code)))) /* (lambda*) or (lambda* #f) */
  47808. eval_error_no_return(sc, sc->syntax_error_symbol, "lambda*: no args or no body? ~A", sc->code);
  47809. set_car(sc->code, check_lambda_star_args(sc, car(sc->code), NULL));
  47810. clear_syms_in_list(sc);
  47811. if ((sc->safety != 0) ||
  47812. (main_stack_op(sc) != OP_DEFINE1))
  47813. optimize(sc, cdr(sc->code), 0, sc->nil);
  47814. else optimize_lambda(sc, false, sc->gc_nil, car(sc->code), cdr(sc->code));
  47815. if ((is_overlaid(sc->code)) &&
  47816. (has_opt_back(sc->code)))
  47817. pair_set_syntax_symbol(sc->code, sc->lambda_star_unchecked_symbol);
  47818. }
  47819. static s7_pointer check_when(s7_scheme *sc)
  47820. {
  47821. if (!is_pair(sc->code)) /* (when) or (when . 1) */
  47822. eval_error(sc, "when has no expression or body: ~A", sc->code);
  47823. if (!is_pair(cdr(sc->code))) /* (when 1) or (when 1 . 1) */
  47824. eval_error(sc, "when has no body?: ~A", sc->code);
  47825. if ((is_overlaid(sc->code)) &&
  47826. (has_opt_back(sc->code)))
  47827. {
  47828. pair_set_syntax_symbol(sc->code, sc->when_unchecked_symbol);
  47829. if (is_symbol(car(sc->code)))
  47830. pair_set_syntax_symbol(sc->code, sc->when_s_symbol);
  47831. }
  47832. return(sc->code);
  47833. }
  47834. static s7_pointer check_unless(s7_scheme *sc)
  47835. {
  47836. if (!is_pair(sc->code)) /* (unless) or (unless . 1) */
  47837. eval_error(sc, "unless has no expression or body: ~A", sc->code);
  47838. if (!is_pair(cdr(sc->code))) /* (unless 1) or (unless 1 . 1) */
  47839. eval_error(sc, "unless has no body?: ~A", sc->code);
  47840. if ((is_overlaid(sc->code)) &&
  47841. (has_opt_back(sc->code)))
  47842. {
  47843. pair_set_syntax_symbol(sc->code, sc->unless_unchecked_symbol);
  47844. if (is_symbol(car(sc->code)))
  47845. pair_set_syntax_symbol(sc->code, sc->unless_s_symbol);
  47846. }
  47847. return(sc->code);
  47848. }
  47849. static s7_pointer check_case(s7_scheme *sc)
  47850. {
  47851. bool keys_simple = true, have_else = false, has_feed_to = false, keys_single = true, bodies_simple = true, bodies_simplest = true;
  47852. s7_pointer x;
  47853. if (!is_pair(sc->code)) /* (case) or (case . 1) */
  47854. eval_error(sc, "case has no selector: ~A", sc->code);
  47855. if (!is_pair(cdr(sc->code))) /* (case 1) or (case 1 . 1) */
  47856. eval_error(sc, "case has no clauses?: ~A", sc->code);
  47857. if (!is_pair(cadr(sc->code))) /* (case 1 1) */
  47858. eval_error(sc, "case clause is not a list? ~A", sc->code);
  47859. for (x = cdr(sc->code); is_not_null(x); x = cdr(x))
  47860. {
  47861. s7_pointer y;
  47862. if ((!is_pair(x)) || /* (case 1 ((2) 1) . 1) */
  47863. (!is_pair(car(x))))
  47864. eval_error(sc, "case clause ~A messed up", x);
  47865. if (!is_pair(cdar(x))) /* (case 1 ((1))) */
  47866. eval_error(sc, "case clause result missing: ~A", car(x));
  47867. if ((bodies_simple) && (!is_null(cddar(x))))
  47868. {
  47869. bodies_simple = false;
  47870. bodies_simplest = false;
  47871. }
  47872. if (bodies_simplest)
  47873. {
  47874. if ((is_pair(cadar(x))) &&
  47875. (caadar(x) != sc->quote_symbol))
  47876. {
  47877. if (is_pair(caar(x)))
  47878. bodies_simplest = false;
  47879. else
  47880. {
  47881. if ((caar(x) != sc->else_object) && (caar(x) != sc->else_symbol) &&
  47882. ((!is_symbol(caar(x))) ||
  47883. (s7_symbol_value(sc, caar(x)) != sc->else_object)))
  47884. bodies_simplest = false;
  47885. }
  47886. }
  47887. }
  47888. y = caar(x);
  47889. if (!is_pair(y))
  47890. {
  47891. if ((y != sc->else_object) && (y != sc->else_symbol) && /* (case 1 (2 1)) */
  47892. ((!is_symbol(y)) ||
  47893. (s7_symbol_value(sc, y) != sc->else_object))) /* "proper list" below because: (case 1 (() 2) ... */
  47894. eval_error(sc, "case clause key list ~A is not a proper list or 'else'", y);
  47895. if (is_not_null(cdr(x))) /* (case 1 (else 1) ((2) 1)) */
  47896. eval_error(sc, "case 'else' clause, ~A, is not the last clause", x);
  47897. have_else = true;
  47898. }
  47899. else
  47900. {
  47901. /* what about (case 1 ((1) #t) ((1) #f)) [this is ok by guile]
  47902. * (case 1 ((1) #t) ())
  47903. * (case 1 ((2 2 2) 1)): guile says #<unspecified>
  47904. * but we do support: (let ((otherwise else)) (case 0 ((1) 2) (otherwise 3))) -> 3!
  47905. * is that consistent?
  47906. * (let ((else #f)) (case 0 ((1) 2) (else 3))) -> 3
  47907. * (case 0 ((1) 2) (else (let ((else 3)) else))) -> 3
  47908. * the selector (sc->value) is evaluated, but the search key is not
  47909. * (case '2 ((2) 3) (else 1)) -> 3
  47910. * (case '2 (('2) 3) (else 1)) -> 1
  47911. * another approach: make else a value, not a symbol, like #<unspecified>, evaluates to itself
  47912. * or set it to be immutable, but I guess I'll say "use #_else" for now.
  47913. */
  47914. if (!is_simple(car(y)))
  47915. keys_simple = false;
  47916. if (!is_null(cdr(y)))
  47917. keys_single = false;
  47918. for (y = cdr(y); is_not_null(y); y = cdr(y))
  47919. {
  47920. if (!is_pair(y)) /* (case () ((1 . 2) . hi) . hi) */
  47921. eval_error(sc, "case key list is improper? ~A", x);
  47922. if (!is_simple(car(y)))
  47923. keys_simple = false;
  47924. }
  47925. }
  47926. y = car(x);
  47927. if ((cadr(y) == sc->feed_to_symbol) &&
  47928. (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
  47929. {
  47930. has_feed_to = true;
  47931. if (!is_pair(cddr(y))) /* (case 1 (else =>)) */
  47932. eval_error(sc, "case: '=>' target missing? ~A", y);
  47933. if (is_pair(cdddr(y))) /* (case 1 (else => + - *)) */
  47934. eval_error(sc, "case: '=>' has too many targets: ~A", y);
  47935. }
  47936. }
  47937. if ((is_overlaid(sc->code)) &&
  47938. (has_opt_back(sc->code)))
  47939. {
  47940. for (x = cdr(sc->code); is_not_null(x); x = cdr(x))
  47941. {
  47942. set_opt_key(x, caar(x));
  47943. if (is_pair(opt_key(x))) set_opt_clause(x, cadar(x));
  47944. }
  47945. pair_set_syntax_symbol(sc->code, sc->case_unchecked_symbol);
  47946. if ((!has_feed_to) &&
  47947. (keys_simple))
  47948. {
  47949. if (have_else) /* don't combine ifs ! */
  47950. {
  47951. if (is_symbol(car(sc->code)))
  47952. pair_set_syntax_symbol(sc->code, sc->case_simple_symbol);
  47953. }
  47954. else
  47955. {
  47956. if (keys_single)
  47957. {
  47958. if ((bodies_simple) &&
  47959. (is_symbol(car(sc->code))))
  47960. pair_set_syntax_symbol(sc->code, sc->case_simplest_symbol);
  47961. else
  47962. {
  47963. if ((is_optimized(car(sc->code))) &&
  47964. (optimize_op(car(sc->code)) == HOP_SAFE_C_SS))
  47965. pair_set_syntax_symbol(sc->code, sc->case_simplest_ss_symbol);
  47966. }
  47967. for (x = cdr(sc->code); is_not_null(x); x = cdr(x))
  47968. set_opt_key(x, caaar(x));
  47969. }
  47970. else
  47971. {
  47972. if (bodies_simple)
  47973. {
  47974. if (is_symbol(car(sc->code)))
  47975. pair_set_syntax_symbol(sc->code, sc->case_simpler_1_symbol);
  47976. else
  47977. {
  47978. if ((is_optimized(car(sc->code))) &&
  47979. (optimize_op(car(sc->code)) == HOP_SAFE_C_SS))
  47980. pair_set_syntax_symbol(sc->code, sc->case_simpler_ss_symbol);
  47981. }
  47982. }
  47983. else
  47984. {
  47985. if (is_symbol(car(sc->code)))
  47986. pair_set_syntax_symbol(sc->code, sc->case_simpler_symbol);
  47987. }
  47988. }
  47989. }
  47990. }
  47991. }
  47992. return(sc->code);
  47993. }
  47994. static s7_pointer check_let_one_var(s7_scheme *sc, s7_pointer start)
  47995. {
  47996. s7_pointer binding;
  47997. pair_set_syntax_symbol(sc->code, sc->let_one_symbol);
  47998. binding = car(start);
  47999. if (is_pair(cadr(binding)))
  48000. {
  48001. if (is_h_optimized(cadr(binding)))
  48002. {
  48003. if (is_null(cddr(sc->code))) /* one statement body */
  48004. {
  48005. set_opt_sym2(cdr(sc->code), car(binding));
  48006. set_opt_pair2(sc->code, cadr(binding));
  48007. pair_set_syntax_symbol(sc->code, sc->let_z_symbol);
  48008. if ((is_h_safe_c_s(cadr(binding))) &&
  48009. (is_pair(cadr(sc->code)))) /* one body expr is a pair */
  48010. {
  48011. pair_set_syntax_symbol(sc->code, sc->let_opsq_p_symbol);
  48012. set_opt_sym2(sc->code, cadr(cadr(binding)));
  48013. if ((!is_optimized(cadr(sc->code))) &&
  48014. (is_syntactic_symbol(caadr(sc->code))))
  48015. {
  48016. /* the is_optimized check here and in other parallel cases protects against cases like:
  48017. * (define (hi) (let ((e #f)) (let ((val (not e))) (if (boolean? val) val e)))) (hi)
  48018. * where the "(if...)" part is optimized as safe_c_s before we get here. If we simply
  48019. * pair_set_syntax_op(cadr(sc->code)) as below, the optimization bit is on, but the
  48020. * apparent optimize_op (op) is now safe_c_qq! So eval ejects it and it is handled by the
  48021. * explicit ("trailers") code.
  48022. */
  48023. pair_set_syntax_op(cadr(sc->code), symbol_syntax_op(caadr(sc->code)));
  48024. }
  48025. return(sc->code);
  48026. }
  48027. }
  48028. if (is_h_safe_c_s(cadr(binding)))
  48029. {
  48030. pair_set_syntax_symbol(sc->code, sc->let_opsq_symbol);
  48031. set_opt_sym2(sc->code, cadr(cadr(binding)));
  48032. return(sc->code);
  48033. }
  48034. /* opt1 here is opt_back */
  48035. set_opt_pair2(sc->code, cadr(binding));
  48036. if (optimize_op(cadr(binding)) == HOP_SAFE_C_SS)
  48037. {
  48038. pair_set_syntax_symbol(sc->code, sc->let_opssq_symbol);
  48039. set_opt_sym3(sc->code, caddr(cadr(binding)));
  48040. }
  48041. else
  48042. {
  48043. if (optimize_op(cadr(binding)) == HOP_SAFE_C_C)
  48044. {
  48045. set_opt_sym3(sc->code, car(binding));
  48046. pair_set_syntax_symbol(sc->code, sc->let_opcq_symbol);
  48047. }
  48048. /* let_all_x here is slightly slower than fallback let_z */
  48049. }
  48050. }
  48051. }
  48052. else
  48053. {
  48054. s7_pointer p;
  48055. p = cadaar(sc->code); /* sc->code is of the form '(((x y))...) */
  48056. set_opt_sym3(sc->code, caaar(sc->code));
  48057. if (is_symbol(p))
  48058. {
  48059. set_opt_sym2(sc->code, p);
  48060. pair_set_syntax_symbol(sc->code, sc->let_s_symbol);
  48061. }
  48062. else
  48063. {
  48064. set_opt_con2(sc->code, p);
  48065. pair_set_syntax_symbol(sc->code, sc->let_c_symbol);
  48066. }
  48067. }
  48068. return(sc->code);
  48069. }
  48070. static s7_pointer check_let(s7_scheme *sc)
  48071. {
  48072. s7_pointer x, start;
  48073. bool named_let;
  48074. int vars;
  48075. if (!is_pair(sc->code)) /* (let . 1) */
  48076. {
  48077. if (is_null(sc->code)) /* (let) */
  48078. eval_error(sc, "let has no variables or body: ~A", sc->code);
  48079. eval_error(sc, "let form is an improper list? ~A", sc->code);
  48080. }
  48081. if (!is_pair(cdr(sc->code))) /* (let () ) */
  48082. eval_error(sc, "let has no body: ~A", sc->code);
  48083. if ((!s7_is_list(sc, car(sc->code))) && /* (let 1 ...) */
  48084. (!is_symbol(car(sc->code))))
  48085. eval_error(sc, "let variable list is messed up or missing: ~A", sc->code);
  48086. /* we accept these (other schemes complain, but I can't see why -- a no-op is the user's business!):
  48087. * (let () (define (hi) (+ 1 2)))
  48088. * (let () (begin (define x 3)))
  48089. * (let () 3 (begin (define x 3)))
  48090. * (let () (define x 3))
  48091. * (let () (if #t (define (x) 3)))
  48092. *
  48093. * similar cases:
  48094. * (case 0 ((0) (define (x) 3) (x)))
  48095. * (cond (0 (define (x) 3) (x)))
  48096. * (and (define (x) x) 1)
  48097. * (begin (define (x y) y) (x (define (x y) y)))
  48098. * (if (define (x) 1) 2 3)
  48099. * (do () ((define (x) 1) (define (y) 2)))
  48100. *
  48101. * but we can get some humorous results:
  48102. * (let ((x (lambda () 3))) (if (define (x) 4) (x) 0)) -> 4
  48103. */
  48104. named_let = (is_symbol(car(sc->code)));
  48105. if (named_let)
  48106. {
  48107. if (!s7_is_list(sc, cadr(sc->code))) /* (let hi #t) */
  48108. eval_error(sc, "let variable list is messed up: ~A", sc->code);
  48109. if (is_null(cddr(sc->code))) /* (let hi () ) */
  48110. eval_error(sc, "named let has no body: ~A", sc->code);
  48111. if (is_immutable_symbol(car(sc->code)))
  48112. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "can't bind an immutable object: ~S"), sc->code)));
  48113. set_local(car(sc->code));
  48114. start = cadr(sc->code);
  48115. }
  48116. else start = car(sc->code);
  48117. clear_syms_in_list(sc);
  48118. for (vars = 0, x = start; is_pair(x); vars++, x = cdr(x))
  48119. {
  48120. s7_pointer y, carx;
  48121. carx = car(x);
  48122. if ((!is_pair(carx)) || (is_null(cdr(carx)))) /* (let ((x)) ...) or (let ((x 1) . (y 2)) ...) */
  48123. eval_error(sc, "let variable declaration, but no value?: ~A", x);
  48124. if (!(is_pair(cdr(carx)))) /* (let ((x . 1))...) */
  48125. eval_error(sc, "let variable declaration is not a proper list?: ~A", x);
  48126. if (is_not_null(cddr(carx))) /* (let ((x 1 2 3)) ...) */
  48127. eval_error(sc, "let variable declaration has more than one value?: ~A", x);
  48128. /* currently if the extra value involves a read error, we get a kind of panicky-looking message:
  48129. * (let ((x . 2 . 3)) x)
  48130. * ;let variable declaration has more than one value?: (x error error "stray dot?: ... ((x . 2 . 3)) x) ..")
  48131. */
  48132. y = car(carx);
  48133. if (!(is_symbol(y)))
  48134. eval_error(sc, "bad variable ~S in let", carx);
  48135. if (is_immutable_symbol(y))
  48136. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "can't bind an immutable object: ~S"), x)));
  48137. /* check for name collisions -- not sure this is required by Scheme */
  48138. if (symbol_tag(y) == sc->syms_tag)
  48139. eval_error(sc, "duplicate identifier in let: ~A", y);
  48140. add_sym_to_list(sc, y);
  48141. set_local(y);
  48142. }
  48143. /* we accept (let ((:hi 1)) :hi)
  48144. * (let ('1) quote) [guile accepts this]
  48145. */
  48146. if (is_not_null(x)) /* (let* ((a 1) . b) a) */
  48147. eval_error(sc, "let var list improper?: ~A", sc->code);
  48148. if ((is_overlaid(sc->code)) &&
  48149. (has_opt_back(sc->code)))
  48150. {
  48151. if (named_let)
  48152. {
  48153. s7_pointer ex;
  48154. if (is_null(start))
  48155. pair_set_syntax_symbol(sc->code, sc->named_let_no_vars_symbol);
  48156. else pair_set_syntax_symbol(sc->code, sc->named_let_symbol);
  48157. /* this is (let name ...) so the initial values need to be removed from the closure arg list */
  48158. sc->args = sc->nil; /* sc->args is set to nil in named_let below */
  48159. for (ex = start; is_pair(ex); ex = cdr(ex))
  48160. sc->args = cons(sc, caar(ex), sc->args);
  48161. optimize_lambda(sc, true, car(sc->code), sc->args = safe_reverse_in_place(sc, sc->args), cddr(sc->code));
  48162. /* apparently these guys are almost never safe */
  48163. return(sc->code);
  48164. }
  48165. if (is_null(start))
  48166. pair_set_syntax_symbol(sc->code, sc->let_no_vars_symbol);
  48167. else
  48168. {
  48169. pair_set_syntax_symbol(sc->code, sc->let_unchecked_symbol);
  48170. if (is_null(cdr(start))) /* one binding */
  48171. check_let_one_var(sc, start);
  48172. else
  48173. {
  48174. if (vars < GC_TRIGGER_SIZE)
  48175. {
  48176. s7_pointer p, op;
  48177. op = sc->nil;
  48178. for (p = start; is_pair(p); p = cdr(p))
  48179. {
  48180. s7_pointer x;
  48181. x = car(p);
  48182. if (is_pair(cadr(x)))
  48183. {
  48184. if (car(cadr(x)) == sc->quote_symbol)
  48185. op = sc->let_all_x_symbol;
  48186. else
  48187. {
  48188. if (is_h_safe_c_s(cadr(x)))
  48189. {
  48190. if ((op == sc->nil) || (op == sc->let_all_opsq_symbol))
  48191. op = sc->let_all_opsq_symbol;
  48192. else op = sc->let_all_x_symbol;
  48193. }
  48194. else
  48195. {
  48196. if (is_all_x_safe(sc, cadr(x)))
  48197. op = sc->let_all_x_symbol;
  48198. else
  48199. {
  48200. op = sc->let_unchecked_symbol;
  48201. break;
  48202. }
  48203. }
  48204. }
  48205. }
  48206. else
  48207. {
  48208. if (is_symbol(cadr(x)))
  48209. {
  48210. if ((op == sc->nil) || (op == sc->let_all_s_symbol))
  48211. op = sc->let_all_s_symbol;
  48212. else op = sc->let_all_x_symbol;
  48213. }
  48214. else
  48215. {
  48216. if ((op == sc->nil) || (op == sc->let_all_c_symbol))
  48217. op = sc->let_all_c_symbol;
  48218. else op = sc->let_all_x_symbol;
  48219. }
  48220. }
  48221. }
  48222. pair_set_syntax_symbol(sc->code, op);
  48223. }
  48224. else pair_set_syntax_symbol(sc->code, sc->let_unchecked_symbol);
  48225. }
  48226. }
  48227. if (pair_syntax_symbol(sc->code) == sc->let_all_x_symbol)
  48228. {
  48229. s7_pointer p;
  48230. for (p = start; is_pair(p); p = cdr(p))
  48231. set_c_call(cdar(p), all_x_eval(sc, cadar(p), sc->envir, let_symbol_is_safe));
  48232. }
  48233. }
  48234. return(sc->code);
  48235. }
  48236. static s7_pointer check_let_star(s7_scheme *sc)
  48237. {
  48238. s7_pointer y;
  48239. bool named_let;
  48240. if (!is_pair(sc->code)) /* (let* . 1) */
  48241. eval_error(sc, "let* variable list is messed up: ~A", sc->code);
  48242. if (!is_pair(cdr(sc->code))) /* (let*) */
  48243. eval_error(sc, "let* variable list is messed up: ~A", sc->code);
  48244. named_let = (is_symbol(car(sc->code)));
  48245. if (named_let)
  48246. {
  48247. if (!s7_is_list(sc, cadr(sc->code))) /* (let* hi #t) */
  48248. eval_error(sc, "let* variable list is messed up: ~A", sc->code);
  48249. if (is_null(cddr(sc->code))) /* (let* hi () ) */
  48250. eval_error(sc, "named let* has no body: ~A", sc->code);
  48251. if (is_immutable_symbol(car(sc->code)))
  48252. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "can't bind an immutable object: ~S"), sc->code)));
  48253. set_local(car(sc->code));
  48254. if ((!is_null(cadr(sc->code))) &&
  48255. ((!is_pair(cadr(sc->code))) || /* (let* hi x ... ) */
  48256. (!is_pair(caadr(sc->code))) || /* (let* hi (x) ...) */
  48257. (!is_pair(cdaadr(sc->code))))) /* (let* hi ((x . 1)) ...) */
  48258. eval_error(sc, "named let* variable declaration value is missing: ~A", sc->code);
  48259. }
  48260. else
  48261. {
  48262. if ((!is_null(car(sc->code))) &&
  48263. ((!is_pair(car(sc->code))) || /* (let* x ... ) */
  48264. (!is_pair(caar(sc->code))) || /* (let* (x) ...) */
  48265. (!is_pair(cdaar(sc->code))))) /* (let* ((x . 1)) ...) */
  48266. eval_error(sc, "let* variable declaration value is missing: ~A", sc->code);
  48267. }
  48268. for (y = ((named_let) ? cadr(sc->code) : car(sc->code)); is_pair(y); y = cdr(y))
  48269. {
  48270. s7_pointer x, z;
  48271. x = car(y);
  48272. if (!(is_symbol(car(x)))) /* (let* ((3 1)) 1) */
  48273. eval_error(sc, "bad variable ~S in let*", x);
  48274. z = car(x);
  48275. if (is_immutable_symbol(z))
  48276. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "can't bind an immutable object: ~S"), x)));
  48277. if (!is_pair(x)) /* (let* ((x)) ...) */
  48278. eval_error(sc, "let* variable declaration, but no value?: ~A", x);
  48279. if (!(is_pair(cdr(x)))) /* (let* ((x . 1))...) */
  48280. eval_error(sc, "let* variable declaration is not a proper list?: ~A", x);
  48281. if (is_not_null(cddr(x))) /* (let* ((x 1 2 3)) ...) */
  48282. eval_error(sc, "let* variable declaration has more than one value?: ~A", x);
  48283. x = cdr(y);
  48284. if (is_pair(x))
  48285. {
  48286. if (!is_pair(car(x))) /* (let* ((x -1) 2) 3) */
  48287. eval_error(sc, "let* variable/binding is ~S?", car(x));
  48288. if (!is_pair(cdar(x))) /* (let* ((a 1) (b . 2)) ...) */
  48289. eval_error(sc, "let* variable list is messed up? ~A", x);
  48290. }
  48291. else
  48292. {
  48293. if (is_not_null(x)) /* (let* ((a 1) . b) a) */
  48294. eval_error(sc, "let* var list improper?: ~A", x);
  48295. }
  48296. /* currently (let* ((a 1) (a (+ a 1))) a) is 2, not an error! */
  48297. set_local(z);
  48298. }
  48299. if ((is_overlaid(sc->code)) &&
  48300. (has_opt_back(sc->code)))
  48301. {
  48302. if (named_let)
  48303. {
  48304. if (is_null(cadr(sc->code)))
  48305. pair_set_syntax_symbol(sc->code, sc->named_let_no_vars_symbol);
  48306. else
  48307. {
  48308. pair_set_syntax_symbol(sc->code, sc->named_let_star_symbol);
  48309. set_opt_con2(sc->code, cadr(car(cadr(sc->code))));
  48310. }
  48311. return(sc->code);
  48312. }
  48313. pair_set_syntax_symbol(sc->code, sc->let_star_unchecked_symbol);
  48314. if (is_null(car(sc->code)))
  48315. pair_set_syntax_symbol(sc->code, sc->let_no_vars_symbol); /* (let* () ...) */
  48316. else
  48317. {
  48318. if (is_null(cdar(sc->code)))
  48319. check_let_one_var(sc, car(sc->code)); /* (let* ((var...))...) -> (let ((var...))...) */
  48320. else /* more than one entry */
  48321. {
  48322. s7_pointer p, op;
  48323. op = sc->let_star_all_x_symbol;
  48324. set_opt_con2(sc->code, cadaar(sc->code));
  48325. for (p = car(sc->code); is_pair(p); p = cdr(p))
  48326. {
  48327. s7_pointer x;
  48328. x = car(p);
  48329. if (is_pair(cadr(x)))
  48330. {
  48331. if ((!is_all_x_safe(sc, cadr(x))) &&
  48332. (car(cadr(x)) != sc->quote_symbol))
  48333. {
  48334. op = sc->let_star2_symbol;
  48335. break;
  48336. }
  48337. }
  48338. }
  48339. pair_set_syntax_symbol(sc->code, op);
  48340. }
  48341. }
  48342. if ((pair_syntax_symbol(sc->code) == sc->let_all_x_symbol) ||
  48343. (pair_syntax_symbol(sc->code) == sc->let_star_all_x_symbol))
  48344. {
  48345. s7_pointer p;
  48346. for (p = car(sc->code); is_pair(p); p = cdr(p))
  48347. set_c_call(cdar(p), all_x_eval(sc, cadar(p), sc->envir, let_symbol_is_safe));
  48348. }
  48349. }
  48350. return(sc->code);
  48351. }
  48352. static s7_pointer check_letrec(s7_scheme *sc, bool letrec)
  48353. {
  48354. s7_pointer x, caller;
  48355. caller = (letrec) ? sc->letrec_symbol : sc->letrec_star_symbol;
  48356. if ((!is_pair(sc->code)) || /* (letrec . 1) */
  48357. (!is_pair(cdr(sc->code))) || /* (letrec) */
  48358. (!s7_is_list(sc, car(sc->code)))) /* (letrec 1 ...) */
  48359. eval_error_with_caller(sc, "~A: variable list is messed up: ~A", caller, sc->code);
  48360. clear_syms_in_list(sc);
  48361. for (x = car(sc->code); is_not_null(x); x = cdr(x))
  48362. {
  48363. s7_pointer y, carx;
  48364. if (!is_pair(x)) /* (letrec ((a 1) . 2) ...) */
  48365. eval_error_with_caller(sc, "~A: improper list of variables? ~A", caller, sc->code);
  48366. carx = car(x);
  48367. if ((!is_pair(carx)) || /* (letrec (1 2) #t) */
  48368. (!(is_symbol(car(carx)))))
  48369. eval_error_with_caller(sc, "~A: bad variable ~S", caller, carx);
  48370. y = car(carx);
  48371. if (is_immutable_symbol(y))
  48372. return(s7_error(sc, sc->wrong_type_arg_symbol, set_elist_2(sc, make_string_wrapper(sc, "can't bind an immutable object: ~S"), x)));
  48373. if (!is_pair(cdr(carx))) /* (letrec ((x . 1))...) */
  48374. {
  48375. if (is_null(cdr(carx))) /* (letrec ((x)) x) -- perhaps this is legal? */
  48376. eval_error_with_caller(sc, "~A: variable declaration has no value?: ~A", caller, carx);
  48377. eval_error_with_caller(sc, "~A: variable declaration is not a proper list?: ~A", caller, carx);
  48378. }
  48379. if (is_not_null(cddr(carx))) /* (letrec ((x 1 2 3)) ...) */
  48380. eval_error_with_caller(sc, "~A: variable declaration has more than one value?: ~A", caller, carx);
  48381. /* check for name collisions -- this is needed in letrec* else which of the two legit values
  48382. * does our "rec" refer to, so to speak.
  48383. */
  48384. if (symbol_tag(y) == sc->syms_tag)
  48385. eval_error_with_caller(sc, "~A: duplicate identifier: ~A", caller, y);
  48386. add_sym_to_list(sc, y);
  48387. set_local(y);
  48388. }
  48389. if ((is_overlaid(sc->code)) &&
  48390. (has_opt_back(sc->code)))
  48391. pair_set_syntax_symbol(sc->code, (letrec) ? sc->letrec_unchecked_symbol : sc->letrec_star_unchecked_symbol);
  48392. return(sc->code);
  48393. }
  48394. static s7_pointer check_quote(s7_scheme *sc)
  48395. {
  48396. if (!is_pair(sc->code)) /* (quote . -1) */
  48397. {
  48398. if (is_null(sc->code))
  48399. eval_error(sc, "quote: not enough arguments: ~A", sc->code);
  48400. eval_error(sc, "quote: stray dot?: ~A", sc->code);
  48401. }
  48402. if (is_not_null(cdr(sc->code))) /* (quote . (1 2)) or (quote 1 1) */
  48403. eval_error(sc, "quote: too many arguments ~A", sc->code);
  48404. #if 0
  48405. if ((is_overlaid(sc->code)) &&
  48406. (has_opt_back(sc->code)))
  48407. {
  48408. pair_set_syntax_symbol(sc->code, sc->quote_unchecked_symbol);
  48409. }
  48410. #endif
  48411. return(sc->code);
  48412. }
  48413. static s7_pointer check_and(s7_scheme *sc)
  48414. {
  48415. s7_pointer p;
  48416. bool all_pairs;
  48417. if (is_null(sc->code))
  48418. return(sc->code);
  48419. all_pairs = is_pair(sc->code);
  48420. for (p = sc->code; is_pair(p); p = cdr(p))
  48421. {
  48422. if (!is_pair(car(p)))
  48423. all_pairs = false;
  48424. }
  48425. if (is_not_null(p)) /* (and . 1) (and #t . 1) */
  48426. eval_error(sc, "and: stray dot?: ~A", sc->code);
  48427. if ((is_overlaid(sc->code)) &&
  48428. (has_opt_back(sc->code)))
  48429. {
  48430. if (all_pairs)
  48431. {
  48432. for (p = sc->code; is_pair(p); p = cdr(p))
  48433. set_c_call(p, all_x_eval(sc, car(p), sc->envir, let_symbol_is_safe)); /* c_callee can be nil! */
  48434. if ((c_callee(sc->code)) &&
  48435. (is_pair(cdr(sc->code))) &&
  48436. (is_null(cddr(sc->code))))
  48437. pair_set_syntax_symbol(sc->code, sc->and_p2_symbol);
  48438. else pair_set_syntax_symbol(sc->code, sc->and_p_symbol);
  48439. }
  48440. else pair_set_syntax_symbol(sc->code, sc->and_unchecked_symbol);
  48441. }
  48442. return(sc->code);
  48443. }
  48444. static s7_pointer check_or(s7_scheme *sc)
  48445. {
  48446. s7_pointer p;
  48447. bool all_pairs;
  48448. if (is_null(sc->code))
  48449. return(sc->code);
  48450. all_pairs = is_pair(sc->code);
  48451. for (p = sc->code; is_pair(p); p = cdr(p))
  48452. {
  48453. if (!is_pair(car(p)))
  48454. all_pairs = false;
  48455. }
  48456. if (is_not_null(p))
  48457. eval_error(sc, "or: stray dot?: ~A", sc->code);
  48458. if ((is_overlaid(sc->code)) &&
  48459. (has_opt_back(sc->code)))
  48460. {
  48461. if (all_pairs)
  48462. {
  48463. s7_pointer ep;
  48464. for (ep = sc->code; is_pair(ep); ep = cdr(ep))
  48465. set_c_call(ep, all_x_eval(sc, car(ep), sc->envir, let_symbol_is_safe));
  48466. if ((c_callee(sc->code)) &&
  48467. (is_pair(cdr(sc->code))) &&
  48468. (is_null(cddr(sc->code))))
  48469. pair_set_syntax_symbol(sc->code, sc->or_p2_symbol);
  48470. else pair_set_syntax_symbol(sc->code, sc->or_p_symbol);
  48471. }
  48472. else pair_set_syntax_symbol(sc->code, sc->or_unchecked_symbol);
  48473. }
  48474. return(sc->code);
  48475. }
  48476. static s7_pointer check_if(s7_scheme *sc)
  48477. {
  48478. s7_pointer cdr_code;
  48479. if (!is_pair(sc->code)) /* (if) or (if . 1) */
  48480. eval_error(sc, "(if): if needs at least 2 expressions: ~A", sc->code);
  48481. cdr_code = cdr(sc->code);
  48482. if (!is_pair(cdr_code)) /* (if 1) */
  48483. eval_error(sc, "(if ~A): if needs another clause", car(sc->code));
  48484. if (is_pair(cdr(cdr_code)))
  48485. {
  48486. if (is_not_null(cddr(cdr_code))) /* (if 1 2 3 4) */
  48487. eval_error(sc, "too many clauses for if: ~A", sc->code);
  48488. }
  48489. else
  48490. {
  48491. if (is_not_null(cdr(cdr_code))) /* (if 1 2 . 3) */
  48492. eval_error(sc, "if: ~A has improper list?", sc->code);
  48493. }
  48494. if ((is_overlaid(sc->code)) &&
  48495. (has_opt_back(sc->code)))
  48496. {
  48497. s7_pointer test;
  48498. bool one_branch;
  48499. pair_set_syntax_symbol(sc->code, sc->if_unchecked_symbol);
  48500. one_branch = (is_null(cdr(cdr_code)));
  48501. test = car(sc->code);
  48502. if (is_pair(test))
  48503. {
  48504. if (is_h_optimized(test))
  48505. {
  48506. if (optimize_op(test) == HOP_SAFE_C_C)
  48507. {
  48508. if (c_callee(test) == g_and_all_x_2)
  48509. {
  48510. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_and2_p_symbol : sc->if_and2_p_p_symbol);
  48511. set_opt_and_2_test(sc->code, cddr(test));
  48512. }
  48513. else pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_cc_p_symbol : sc->if_cc_p_p_symbol);
  48514. set_opt_pair2(sc->code, cdr(test));
  48515. }
  48516. else
  48517. {
  48518. if (is_h_safe_c_s(test))
  48519. {
  48520. /* these miss methods? */
  48521. if (car(test) == sc->is_pair_symbol)
  48522. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_is_pair_p_symbol : sc->if_is_pair_p_p_symbol);
  48523. else
  48524. {
  48525. if (car(test) == sc->is_symbol_symbol)
  48526. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_is_symbol_p_symbol : sc->if_is_symbol_p_p_symbol);
  48527. else
  48528. {
  48529. if (car(test) == sc->not_symbol)
  48530. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_not_s_p_symbol : sc->if_not_s_p_p_symbol);
  48531. else pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_cs_p_symbol : sc->if_cs_p_p_symbol);
  48532. }
  48533. }
  48534. set_opt_sym2(sc->code, cadr(test));
  48535. }
  48536. else
  48537. {
  48538. if (optimize_op(test) == HOP_SAFE_C_SQ)
  48539. {
  48540. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_csq_p_symbol : sc->if_csq_p_p_symbol);
  48541. set_opt_con2(sc->code, cadr(caddr(test)));
  48542. set_opt_sym3(sc->code, cadr(test));
  48543. }
  48544. else
  48545. {
  48546. if (optimize_op(test) == HOP_SAFE_C_SS)
  48547. {
  48548. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_css_p_symbol : sc->if_css_p_p_symbol);
  48549. set_opt_sym2(sc->code, caddr(test));
  48550. set_opt_sym3(sc->code, cadr(test));
  48551. }
  48552. else
  48553. {
  48554. if (optimize_op(test) == HOP_SAFE_C_SC)
  48555. {
  48556. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_csc_p_symbol : sc->if_csc_p_p_symbol);
  48557. set_opt_con2(sc->code, caddr(test));
  48558. set_opt_sym3(sc->code, cadr(test));
  48559. }
  48560. else
  48561. {
  48562. if (optimize_op(test) == HOP_SAFE_C_S_opCq)
  48563. {
  48564. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_s_opcq_p_symbol : sc->if_s_opcq_p_p_symbol);
  48565. set_opt_pair2(sc->code, caddr(test));
  48566. set_opt_sym3(sc->code, cadr(test));
  48567. }
  48568. else
  48569. {
  48570. if (optimize_op(test) == HOP_SAFE_C_opSSq)
  48571. {
  48572. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_opssq_p_symbol : sc->if_opssq_p_p_symbol);
  48573. set_opt_pair2(sc->code, cadar(sc->code));
  48574. set_opt_sym3(sc->code, caddr(opt_pair2(sc->code)));
  48575. }
  48576. else
  48577. {
  48578. if (is_all_x_safe(sc, test))
  48579. {
  48580. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_a_p_symbol : sc->if_a_p_p_symbol);
  48581. set_c_call(sc->code, all_x_eval(sc, test, sc->envir, let_symbol_is_safe));
  48582. /* fprintf(stderr, "%s\n", DISPLAY(sc->code)); */
  48583. }
  48584. else
  48585. {
  48586. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_z_p_symbol : sc->if_z_p_p_symbol);
  48587. set_opt_con2(sc->code, cadr(sc->code));
  48588. }
  48589. }
  48590. }
  48591. }
  48592. }
  48593. }
  48594. }
  48595. }
  48596. }
  48597. else
  48598. {
  48599. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_p_p_symbol : sc->if_p_p_p_symbol);
  48600. if (is_syntactic_symbol(car(test)))
  48601. {
  48602. pair_set_syntax_op(test, symbol_syntax_op(car(test)));
  48603. if ((symbol_syntax_op(car(test)) == OP_AND) ||
  48604. (symbol_syntax_op(car(test)) == OP_OR))
  48605. {
  48606. opcode_t new_op;
  48607. s7_pointer old_code;
  48608. old_code = sc->code;
  48609. sc->code = cdr(test);
  48610. if (symbol_syntax_op(car(test)) == OP_AND) check_and(sc); else check_or(sc);
  48611. new_op = symbol_syntax_op(car(test));
  48612. sc->code = old_code;
  48613. if ((new_op == OP_AND_P) || (new_op == OP_AND_P2))
  48614. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_andp_p_symbol : sc->if_andp_p_p_symbol);
  48615. else
  48616. {
  48617. if ((new_op == OP_OR_P) || (new_op == OP_OR_P2))
  48618. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_orp_p_symbol : sc->if_orp_p_p_symbol);
  48619. }
  48620. }
  48621. }
  48622. }
  48623. }
  48624. else /* test is symbol or constant, but constant here is nutty */
  48625. {
  48626. if (is_symbol(test))
  48627. pair_set_syntax_symbol(sc->code, (one_branch) ? sc->if_s_p_symbol : sc->if_s_p_p_symbol);
  48628. }
  48629. }
  48630. return(sc->code);
  48631. }
  48632. static s7_pointer optimize_lambda(s7_scheme *sc, bool unstarred_lambda, s7_pointer func, s7_pointer args, s7_pointer body)
  48633. {
  48634. int len;
  48635. /* fprintf(stderr, "opt %s %s\n", DISPLAY(args), DISPLAY(body)); */
  48636. len = s7_list_length(sc, body);
  48637. if (len < 0) /* (define (hi) 1 . 2) */
  48638. eval_error_with_caller(sc, "~A: function body messed up, ~A", (unstarred_lambda) ? sc->lambda_symbol : sc->lambda_star_symbol, sc->code);
  48639. if (len > 0) /* i.e. not circular */
  48640. {
  48641. s7_pointer lst;
  48642. clear_syms_in_list(sc);
  48643. if (is_symbol(func))
  48644. lst = list_1(sc, add_sym_to_list(sc, func));
  48645. else lst = sc->nil;
  48646. optimize(sc, body, 1, collect_collisions_star(sc, args, lst));
  48647. /* if the body is safe, we can optimize the calling sequence */
  48648. if ((is_proper_list(sc, args)) &&
  48649. (!arglist_has_rest(sc, args)))
  48650. {
  48651. if (!unstarred_lambda)
  48652. {
  48653. s7_pointer p;
  48654. bool happy = true;
  48655. /* check default vals -- if none is an expression or symbol, set simple args */
  48656. for (p = args; is_pair(p); p = cdr(p))
  48657. {
  48658. s7_pointer arg;
  48659. arg = car(p);
  48660. if ((is_pair(arg)) && /* has default value */
  48661. ((is_symbol(cadr(arg))) || /* if default value might involve eval in any way, it isn't simple */
  48662. ((is_pair(cadr(arg))) && /* pair as default only ok if it is (quote ...) */
  48663. (car(cadr(arg)) != sc->quote_symbol))))
  48664. {
  48665. happy = false;
  48666. break;
  48667. }
  48668. }
  48669. if (happy)
  48670. set_simple_args(body);
  48671. }
  48672. sc->cycle_counter = 0;
  48673. if (((unstarred_lambda) || (has_simple_args(body))) &&
  48674. (body_is_safe(sc, func, body, true)))
  48675. {
  48676. /* there is one problem with closure* here -- we can't trust anything that has fancy (non-constant) default argument values. */
  48677. set_safe_closure(body);
  48678. /* this bit is set on the function itself in make_closure and friends */
  48679. }
  48680. }
  48681. }
  48682. return(NULL);
  48683. }
  48684. static s7_pointer check_define(s7_scheme *sc)
  48685. {
  48686. s7_pointer func, caller;
  48687. bool starred;
  48688. int arity = CLOSURE_ARITY_NOT_SET;
  48689. starred = (sc->op == OP_DEFINE_STAR);
  48690. if (starred)
  48691. {
  48692. caller = sc->define_star_symbol;
  48693. sc->op = OP_DEFINE_STAR_UNCHECKED;
  48694. }
  48695. else
  48696. {
  48697. if (sc->op == OP_DEFINE)
  48698. caller = sc->define_symbol;
  48699. else caller = sc->define_constant_symbol;
  48700. }
  48701. if (!is_pair(sc->code))
  48702. eval_error_with_caller(sc, "~A: nothing to define? ~A", caller, sc->code); /* (define) */
  48703. if (!is_pair(cdr(sc->code)))
  48704. {
  48705. if (is_null(cdr(sc->code)))
  48706. eval_error_with_caller(sc, "~A: no value? ~A", caller, sc->code); /* (define var) */
  48707. eval_error_with_caller(sc, "~A: bad form? ~A", caller, sc->code); /* (define var . 1) */
  48708. }
  48709. if (!is_pair(car(sc->code)))
  48710. {
  48711. if (is_not_null(cddr(sc->code))) /* (define var 1 . 2) */
  48712. eval_error_with_caller(sc, "~A: more than 1 value? ~A", caller, sc->code); /* (define var 1 2) */
  48713. if (starred)
  48714. eval_error(sc, "define* is restricted to functions: (define* ~{~S~^ ~})", sc->code);
  48715. func = car(sc->code);
  48716. if (!is_symbol(func)) /* (define 3 a) */
  48717. eval_error_with_caller(sc, "~A: define a non-symbol? ~S", caller, func);
  48718. if (is_keyword(func)) /* (define :hi 1) */
  48719. eval_error_with_caller(sc, "~A ~A: keywords are constants", caller, func);
  48720. if (is_syntactic(func)) /* (define and a) */
  48721. {
  48722. if (sc->safety > 0)
  48723. s7_warn(sc, 128, "%s: syntactic keywords tend to behave badly if redefined", DISPLAY(func));
  48724. set_local(func);
  48725. }
  48726. if ((is_pair(cadr(sc->code))) && /* look for (define sym (lambda ...)) and treat it like (define (sym ...)...) */
  48727. ((caadr(sc->code) == sc->lambda_symbol) ||
  48728. (caadr(sc->code) == sc->lambda_star_symbol)) &&
  48729. (symbol_id(caadr(sc->code)) == 0))
  48730. /* not is_global here because that bit might not be set for initial symbols (why not? -- redef as method etc) */
  48731. optimize_lambda(sc, caadr(sc->code) == sc->lambda_symbol, func, cadr(cadr(sc->code)), cddr(cadr(sc->code)));
  48732. }
  48733. else
  48734. {
  48735. func = caar(sc->code);
  48736. if (!is_symbol(func)) /* (define (3 a) a) */
  48737. eval_error_with_caller(sc, "~A: define a non-symbol? ~S", caller, func);
  48738. if (is_syntactic(func)) /* (define (and a) a) */
  48739. {
  48740. if (sc->safety > 0)
  48741. s7_warn(sc, 128, "%s: syntactic keywords tend to behave badly if redefined", DISPLAY(func));
  48742. set_local(func);
  48743. }
  48744. if (starred)
  48745. set_cdar(sc->code, check_lambda_star_args(sc, cdar(sc->code), &arity));
  48746. else check_lambda_args(sc, cdar(sc->code), &arity);
  48747. optimize_lambda(sc, !starred, func, cdar(sc->code), cdr(sc->code));
  48748. }
  48749. if ((is_overlaid(sc->code)) &&
  48750. (has_opt_back(sc->code)))
  48751. {
  48752. if (sc->op == OP_DEFINE)
  48753. {
  48754. if ((is_pair(car(sc->code))) &&
  48755. (!symbol_has_accessor(func)) &&
  48756. (!is_immutable_symbol(func)))
  48757. pair_set_syntax_symbol(sc->code, sc->define_funchecked_symbol);
  48758. else pair_set_syntax_symbol(sc->code, sc->define_unchecked_symbol);
  48759. }
  48760. else
  48761. {
  48762. if (starred)
  48763. pair_set_syntax_symbol(sc->code, sc->define_star_unchecked_symbol);
  48764. else pair_set_syntax_symbol(sc->code, sc->define_constant_unchecked_symbol);
  48765. }
  48766. }
  48767. return(sc->code);
  48768. }
  48769. static int define_unchecked_ex(s7_scheme *sc)
  48770. {
  48771. if (sc->op == OP_DEFINE_STAR_UNCHECKED)
  48772. {
  48773. s7_pointer x;
  48774. unsigned int typ;
  48775. if (is_safe_closure(cdr(sc->code)))
  48776. typ = T_CLOSURE_STAR | T_PROCEDURE | T_SAFE_CLOSURE;
  48777. else typ = T_CLOSURE_STAR | T_PROCEDURE;
  48778. new_cell(sc, x, typ);
  48779. closure_set_args(x, cdar(sc->code));
  48780. closure_set_body(x, cdr(sc->code));
  48781. closure_set_let(x, sc->envir);
  48782. closure_arity(x) = CLOSURE_ARITY_NOT_SET;
  48783. closure_set_setter(x, sc->F);
  48784. sc->capture_let_counter++;
  48785. sc->value = x;
  48786. sc->code = caar(sc->code);
  48787. return(fall_through);
  48788. }
  48789. if (!is_pair(car(sc->code)))
  48790. {
  48791. s7_pointer x;
  48792. x = car(sc->code);
  48793. sc->code = cadr(sc->code);
  48794. if (is_pair(sc->code))
  48795. {
  48796. push_stack(sc, OP_DEFINE1, sc->nil, x);
  48797. return(goto_EVAL);
  48798. }
  48799. if (is_symbol(sc->code))
  48800. sc->value = find_global_symbol_checked(sc, sc->code);
  48801. else sc->value = sc->code;
  48802. sc->code = x;
  48803. }
  48804. else
  48805. {
  48806. s7_pointer x;
  48807. /* a closure. If we called this same code earlier (a local define), the only thing
  48808. * that is new here is the environment -- we can't blithely save the closure object
  48809. * in opt2 somewhere, and pick it up the next time around (since call/cc might take
  48810. * us back to the previous case). We also can't re-use opt2(sc->code) because opt2
  48811. * is not cleared in the gc.
  48812. */
  48813. make_closure_with_let(sc, x, cdar(sc->code), cdr(sc->code), sc->envir);
  48814. sc->value = _NFre(x);
  48815. sc->code = caar(sc->code);
  48816. }
  48817. return(fall_through);
  48818. }
  48819. static void define_funchecked(s7_scheme *sc)
  48820. {
  48821. s7_pointer new_func, new_env, code;
  48822. code = sc->code;
  48823. sc->value = caar(code);
  48824. new_cell(sc, new_func, T_CLOSURE | T_PROCEDURE | T_COPY_ARGS);
  48825. closure_set_args(new_func, cdar(code));
  48826. closure_set_body(new_func, cdr(code));
  48827. closure_set_setter(new_func, sc->F);
  48828. closure_arity(new_func) = CLOSURE_ARITY_NOT_SET;
  48829. sc->capture_let_counter++;
  48830. if (is_safe_closure(cdr(code)))
  48831. {
  48832. s7_pointer arg;
  48833. set_safe_closure(new_func);
  48834. new_cell_no_check(sc, new_env, T_LET | T_FUNCTION_ENV);
  48835. let_id(new_env) = ++sc->let_number;
  48836. let_set_slots(new_env, sc->nil);
  48837. set_outlet(new_env, sc->envir);
  48838. closure_set_let(new_func, new_env);
  48839. funclet_set_function(new_env, sc->value);
  48840. for (arg = closure_args(new_func); is_pair(arg); arg = cdr(arg))
  48841. make_slot_1(sc, new_env, car(arg), sc->nil);
  48842. let_set_slots(new_env, reverse_slots(sc, let_slots(new_env)));
  48843. }
  48844. else closure_set_let(new_func, sc->envir);
  48845. /* unsafe closures created by other functions do not support __func__ */
  48846. add_slot(sc->envir, sc->value, new_func);
  48847. set_local(sc->value);
  48848. sc->value = new_func;
  48849. }
  48850. static int lambda_star_default(s7_scheme *sc)
  48851. {
  48852. while (true)
  48853. {
  48854. s7_pointer z;
  48855. z = sc->args;
  48856. if (is_slot(z))
  48857. {
  48858. if (slot_value(z) == sc->undefined)
  48859. {
  48860. if (is_closure_star(sc->code))
  48861. {
  48862. s7_pointer val;
  48863. val = slot_expression(z);
  48864. if (is_symbol(val))
  48865. {
  48866. slot_set_value(z, find_symbol_checked(sc, val));
  48867. if (slot_value(z) == sc->undefined)
  48868. {
  48869. /* the current environment here contains the function parameters which
  48870. * defaulted to #<undefined> earlier in apply_lambda_star,
  48871. * so (define (f f) (define* (f (f f)) f) (f)) (f 0) looks for the
  48872. * default f, finds itself currently undefined, and raises an error!
  48873. * So, before claiming it is unbound, we need to check outlet as well.
  48874. * But in the case above, the inner define* shadows the caller's
  48875. * parameter before checking the default arg values, so the default f
  48876. * refers to the define* -- I'm not sure this is a bug. It means
  48877. * that (define* (f (a f)) a) returns f: (equal? f (f)) -> #t, so
  48878. * any outer f needs an extra let and endless outlets:
  48879. * (let ((f 3)) (let () (define* (f (a ((outlet (outlet (outlet (curlet)))) 'f))) a) (f))) -> 3
  48880. * We want the shadowing once the define* is done, so the current mess is simplest.
  48881. */
  48882. slot_set_value(z, s7_symbol_local_value(sc, val, outlet(sc->envir)));
  48883. if (slot_value(z) == sc->undefined)
  48884. eval_error_no_return(sc, sc->syntax_error_symbol, "lambda* defaults: ~A is unbound", slot_symbol(z));
  48885. /* but #f is default if no expr, so there's some inconsistency here */
  48886. }
  48887. }
  48888. else
  48889. {
  48890. if (is_pair(val))
  48891. {
  48892. if (car(val) == sc->quote_symbol)
  48893. {
  48894. if ((!is_pair(cdr(val))) || /* (lambda* ((a (quote))) a) or (lambda* ((a (quote 1 1))) a) etc */
  48895. (is_pair(cddr(val))))
  48896. eval_error_no_return(sc, sc->syntax_error_symbol, "lambda* default: ~A is messed up", val);
  48897. slot_set_value(z, cadr(val));
  48898. }
  48899. else
  48900. {
  48901. push_stack(sc, OP_LAMBDA_STAR_DEFAULT, sc->args, sc->code);
  48902. sc->code = val;
  48903. return(goto_EVAL);
  48904. }
  48905. }
  48906. else slot_set_value(z, val);
  48907. }
  48908. }
  48909. else slot_set_value(z, slot_expression(z));
  48910. }
  48911. sc->args = slot_pending_value(z);
  48912. }
  48913. else break;
  48914. }
  48915. return(fall_through);
  48916. }
  48917. #if 0
  48918. static void unsafe_closure_2(s7_scheme *sc, s7_pointer arg1, s7_pointer arg2)
  48919. {
  48920. s7_pointer code, args;
  48921. if (sc->stack_end >= sc->stack_resize_trigger) resize_stack(sc); /* not check_stack_size because it tries to return sc->F */
  48922. code = opt_lambda(sc->code);
  48923. args = closure_args(code);
  48924. new_frame_with_two_slots(sc, closure_let(code), sc->envir, car(args), arg1, cadr(args), arg2);
  48925. sc->code = closure_body(code);
  48926. }
  48927. #else
  48928. #define unsafe_closure_2(Sc, Arg1, Arg2) \
  48929. { \
  48930. s7_pointer Code, Args, A1, A2; A1 = Arg1; A2 = Arg2; \
  48931. if (Sc->stack_end >= Sc->stack_resize_trigger) resize_stack(Sc); \
  48932. Code = opt_lambda(Sc->code); \
  48933. Args = closure_args(Code); \
  48934. new_frame_with_two_slots(Sc, closure_let(Code), Sc->envir, car(Args), A1, cadr(Args), A2); \
  48935. Sc->code = closure_body(Code); \
  48936. }
  48937. #endif
  48938. static void unsafe_closure_star(s7_scheme *sc)
  48939. {
  48940. s7_pointer x, z, e;
  48941. unsigned long long int id;
  48942. new_frame(sc, closure_let(sc->code), sc->envir);
  48943. e = sc->envir;
  48944. id = let_id(e);
  48945. for (x = closure_args(sc->code), z = sc->args; is_pair(x); x = cdr(x))
  48946. {
  48947. s7_pointer sym, args, val;
  48948. if (is_pair(car(x)))
  48949. sym = caar(x);
  48950. else sym = car(x);
  48951. val = car(z);
  48952. args = cdr(z);
  48953. set_type(z, T_SLOT);
  48954. slot_set_symbol(z, sym);
  48955. symbol_set_local(sym, id, z);
  48956. slot_set_value(z, val);
  48957. set_next_slot(z, let_slots(e));
  48958. let_set_slots(e, z);
  48959. z = args;
  48960. }
  48961. sc->code = closure_body(sc->code);
  48962. }
  48963. static void fill_closure_star(s7_scheme *sc, s7_pointer p)
  48964. {
  48965. for (; is_pair(p); p = cdr(p))
  48966. {
  48967. s7_pointer defval;
  48968. if (is_pair(car(p)))
  48969. {
  48970. defval = cadar(p);
  48971. if (is_pair(defval))
  48972. sc->args = cons(sc, cadr(defval), sc->args);
  48973. else sc->args = cons(sc, defval, sc->args);
  48974. }
  48975. else sc->args = cons(sc, sc->F, sc->args);
  48976. }
  48977. sc->args = safe_reverse_in_place(sc, sc->args);
  48978. sc->code = opt_lambda(sc->code);
  48979. }
  48980. static void fill_safe_closure_star(s7_scheme *sc, s7_pointer x, s7_pointer p)
  48981. {
  48982. for (; is_pair(p); p = cdr(p), x = next_slot(x))
  48983. {
  48984. s7_pointer defval;
  48985. if (is_pair(car(p)))
  48986. {
  48987. defval = cadar(p);
  48988. if (is_pair(defval))
  48989. slot_set_value(x, cadr(defval));
  48990. else slot_set_value(x, defval);
  48991. }
  48992. else slot_set_value(x, sc->F);
  48993. symbol_set_local(slot_symbol(x), let_id(sc->envir), x);
  48994. }
  48995. sc->code = closure_body(opt_lambda(sc->code));
  48996. }
  48997. static s7_pointer check_define_macro(s7_scheme *sc, opcode_t op)
  48998. {
  48999. s7_pointer x, y, caller;
  49000. caller = sc->define_macro_symbol;
  49001. switch (op)
  49002. {
  49003. case OP_DEFINE_MACRO: caller = sc->define_macro_symbol; break;
  49004. case OP_DEFINE_MACRO_STAR: caller = sc->define_macro_star_symbol; break;
  49005. case OP_DEFINE_BACRO: caller = sc->define_bacro_symbol; break;
  49006. case OP_DEFINE_BACRO_STAR: caller = sc->define_bacro_star_symbol; break;
  49007. case OP_DEFINE_EXPANSION: caller = sc->define_expansion_symbol; break;
  49008. }
  49009. if (!is_pair(sc->code)) /* (define-macro . 1) */
  49010. eval_error_with_caller(sc, "~A name missing (stray dot?): ~A", caller, sc->code);
  49011. if (!is_pair(car(sc->code))) /* (define-macro a ...) */
  49012. return(wrong_type_argument_with_type(sc, caller, 1, car(sc->code), make_string_wrapper(sc, "a list: (name ...)")));
  49013. /* not car(opt_back(sc->code)) to get the caller (e.g. 'define-bacro) because opt_back might not be set: (apply define-macro '(1)) */
  49014. x = caar(sc->code);
  49015. if (!is_symbol(x))
  49016. eval_error_with_caller(sc, "~A: ~S is not a symbol?", caller, x);
  49017. if (dont_eval_args(x)) /* (define-macro (quote a) quote) */
  49018. {
  49019. if (sc->safety > 0)
  49020. s7_warn(sc, 128, "%s: syntactic keywords tend to behave badly if redefined", DISPLAY(x));
  49021. set_local(x);
  49022. }
  49023. if (is_immutable_symbol(x))
  49024. eval_error_with_caller(sc, "~A: ~S is immutable", caller, x);
  49025. if (!is_pair(cdr(sc->code))) /* (define-macro (...)) */
  49026. eval_error_with_caller(sc, "~A ~A, but no body?", caller, x);
  49027. y = cdar(sc->code); /* the arglist */
  49028. if ((!s7_is_list(sc, y)) &&
  49029. (!is_symbol(y)))
  49030. return(s7_error(sc, sc->syntax_error_symbol, /* (define-macro (mac . 1) ...) */
  49031. set_elist_3(sc, make_string_wrapper(sc, "macro ~A argument list is ~S?"), x, y)));
  49032. for ( ; is_pair(y); y = cdr(y))
  49033. if ((!is_symbol(car(y))) &&
  49034. ((sc->op == OP_DEFINE_MACRO) || (sc->op == OP_DEFINE_BACRO) || (sc->op == OP_DEFINE_EXPANSION)))
  49035. return(s7_error(sc, sc->syntax_error_symbol, /* (define-macro (mac 1) ...) */
  49036. set_elist_3(sc, make_string_wrapper(sc, "define-macro ~A argument name is not a symbol: ~S"), x, y)));
  49037. if ((sc->op == OP_DEFINE_MACRO_STAR) || (sc->op == OP_DEFINE_BACRO_STAR))
  49038. set_cdar(sc->code, check_lambda_star_args(sc, cdar(sc->code), NULL));
  49039. else check_lambda_args(sc, cdar(sc->code), NULL);
  49040. return(sc->code);
  49041. }
  49042. static int expansion_ex(s7_scheme *sc)
  49043. {
  49044. int loc;
  49045. s7_pointer caller;
  49046. /* read-time macro expansion:
  49047. * (define-macro (hi a) (format #t "hi...") `(+ ,a 1))
  49048. * (define (ho b) (+ 1 (hi b)))
  49049. * here sc->value is: (ho b), (hi b), (+ 1 (hi b)), (define (ho b) (+ 1 (hi b)))
  49050. * but... first we can't tell for sure at this point that "hi" really is a macro
  49051. * (letrec ((hi ... (hi...))) will be confused about the second hi,
  49052. * or (call/cc (lambda (hi) (hi 1))) etc.
  49053. * second, figuring out that we're quoted is not easy -- we have to march all the
  49054. * way to the bottom of the stack looking for op_read_quote or op_read_vector
  49055. * #(((hi)) 2) or '(((hi)))
  49056. * or op_read_list with args not equal (quote) or (macroexapand)
  49057. * '(hi 3) or (macroexpand (hi 3) or (quote (hi 3))
  49058. * and those are only the problems I noticed!
  49059. *
  49060. * The hardest of these problems involve shadowing, so Rick asked for "define-expansion"
  49061. * which is like define-macro, but the programmer guarantees that the macro
  49062. * name will not be shadowed.
  49063. *
  49064. * to make expansion recognition fast here, define-expansion sets the T_EXPANSION
  49065. * bit in the symbol as well as the value:
  49066. * set_type(sc->code, T_EXPANSION | T_SYMBOL)
  49067. * but this can lead to confusion because the expansion name is now globally identified as an expansion.
  49068. * (let () (define-expansion (ex1 a) `(+ ,a 1)) (display (ex1 3)))
  49069. * (define (ex1 b) (* b 2)) (display (ex1 3))
  49070. * since this happens at the top level, the first line is evaluated, ex1 becomes an expansion.
  49071. * but the reader has no idea about lets and whatnot, so in the second line, ex1 is still an expansion
  49072. * to the reader, so it sees (define (+ b 1) ...) -- error! To support tail-calls, there's no
  49073. * way in eval to see the let close, so we can't clear the expansion flag when the let is done.
  49074. * But we don't want define-expansion to mimic define-constant (via T_IMMUTABLE) because programs
  49075. * like lint need to cancel reader-cond (for example). So, we allow an expansion to be redefined,
  49076. * and check here that the expander symbol still refers to an expansion.
  49077. *
  49078. * but in (define (ex1 b) b), the reader doesn't know we're in a define call (or it would be
  49079. * a bother to notice), so to redefine an expansion, first (set! ex1 #f) or (define ex1 #f),
  49080. * then (define (ex1 b) b).
  49081. *
  49082. * This is a mess! Maybe we should insist that expansions are always global.
  49083. *
  49084. * run-time expansion and splicing into the code as in CL won't work in s7 because macros
  49085. * are first-class objects. For example (define (f m) (m 1)), call it with a macro, say `(+ ,arg 1),
  49086. * and in CL-style, you'd now have the body (+ ,arg 1) or maybe even 2, now call f with a function,
  49087. * or some other macro -- oops!
  49088. */
  49089. loc = s7_stack_top(sc) - 1;
  49090. if (is_pair(stack_args(sc->stack, loc)))
  49091. caller = car(stack_args(sc->stack, loc)); /* this can be garbage */
  49092. else caller = sc->F;
  49093. if ((loc >= 3) &&
  49094. (stack_op(sc->stack, loc) != OP_READ_QUOTE) && /* '(hi 1) for example */
  49095. (stack_op(sc->stack, loc) != OP_READ_VECTOR) && /* #(reader-cond) for example */
  49096. (caller != sc->quote_symbol) && /* (quote (hi 1)) */
  49097. (caller != sc->macroexpand_symbol) && /* (macroexpand (hi 1)) */
  49098. (caller != sc->define_expansion_symbol)) /* (define-expansion ...) being reloaded/redefined */
  49099. {
  49100. s7_pointer symbol, slot;
  49101. /* we're playing fast and loose with sc->envir in the reader, so here we need a disaster check */
  49102. #if DEBUGGING
  49103. if (unchecked_type(sc->envir) != T_LET) sc->envir = sc->nil;
  49104. #else
  49105. if (!is_let(sc->envir)) sc->envir = sc->nil;
  49106. #endif
  49107. symbol = car(sc->value);
  49108. if ((symbol_id(symbol) == 0) ||
  49109. (sc->envir == sc->nil))
  49110. slot = global_slot(symbol);
  49111. else slot = find_symbol(sc, symbol);
  49112. if (is_slot(slot))
  49113. sc->code = slot_value(slot);
  49114. else sc->code = sc->undefined;
  49115. if (!is_expansion(sc->code))
  49116. clear_expansion(symbol);
  49117. else
  49118. {
  49119. sc->args = copy_list(sc, cdr(sc->value));
  49120. return(goto_APPLY);
  49121. }
  49122. }
  49123. return(fall_through);
  49124. }
  49125. static s7_pointer check_with_let(s7_scheme *sc)
  49126. {
  49127. if (!is_pair(sc->code)) /* (with-let . "hi") */
  49128. eval_error(sc, "with-let takes an environment argument: ~A", sc->code);
  49129. if (!is_pair(cdr(sc->code))) /* (with-let e) -> an error? */
  49130. eval_error(sc, "with-let body is messed up: ~A", sc->code);
  49131. if ((!is_pair(cddr(sc->code))) &&
  49132. (!is_null(cddr(sc->code))))
  49133. eval_error(sc, "with-let body has stray dot? ~A", sc->code);
  49134. if ((is_overlaid(sc->code)) &&
  49135. (has_opt_back(sc->code)))
  49136. {
  49137. pair_set_syntax_symbol(sc->code, sc->with_let_unchecked_symbol);
  49138. if ((is_symbol(car(sc->code))) &&
  49139. (is_pair(cadr(sc->code))))
  49140. pair_set_syntax_symbol(sc->code, sc->with_let_s_symbol);
  49141. }
  49142. return(sc->code);
  49143. }
  49144. static s7_pointer check_cond(s7_scheme *sc)
  49145. {
  49146. bool has_feed_to = false;
  49147. s7_pointer x;
  49148. if (!is_pair(sc->code)) /* (cond) or (cond . 1) */
  49149. eval_error(sc, "cond, but no body: ~A", sc->code);
  49150. for (x = sc->code; is_pair(x); x = cdr(x))
  49151. {
  49152. if (!is_pair(car(x))) /* (cond 1) or (cond (#t 1) 3) */
  49153. eval_error(sc, "every clause in cond must be a list: ~A", car(x));
  49154. else
  49155. {
  49156. s7_pointer y;
  49157. y = car(x);
  49158. if ((!is_pair(cdr(y))) && (!is_null(cdr(y)))) /* (cond (1 . 2)) */
  49159. eval_error(sc, "cond: stray dot? ~A", sc->code);
  49160. if ((cadr(y) == sc->feed_to_symbol) &&
  49161. (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
  49162. {
  49163. has_feed_to = true;
  49164. if (!is_pair(cddr(y))) /* (cond (#t =>)) or (cond (#t => . 1)) */
  49165. eval_error(sc, "cond: '=>' target missing? ~A", x);
  49166. if (is_pair(cdddr(y))) /* (cond (1 => + abs)) */
  49167. eval_error(sc, "cond: '=>' has too many targets: ~A", x);
  49168. }
  49169. /* currently we accept:
  49170. * (cond (1 2) (=> . =>)) and all variants thereof, e.g. (cond (1 2) (=> 1 . 2) (1 2)) or
  49171. * (cond (1) (=>)) but Guile accepts this?
  49172. * (cond (1) (1 =>))
  49173. * amusing (correct) case: (cond (1 => "hi")) -> #\i
  49174. */
  49175. }
  49176. }
  49177. if (is_not_null(x)) /* (cond ((1 2)) . 1) */
  49178. eval_error(sc, "cond: stray dot? ~A", sc->code);
  49179. if ((is_overlaid(sc->code)) &&
  49180. (has_opt_back(sc->code)))
  49181. {
  49182. if (has_feed_to)
  49183. {
  49184. pair_set_syntax_symbol(sc->code, sc->cond_unchecked_symbol);
  49185. if (is_null(cdr(sc->code)))
  49186. {
  49187. s7_pointer expr, f;
  49188. expr = car(sc->code);
  49189. f = caddr(expr);
  49190. if ((is_pair(f)) &&
  49191. (car(f) == sc->lambda_symbol) &&
  49192. (is_null(cdr(cddr(f)))))
  49193. {
  49194. s7_pointer arg;
  49195. arg = cadr(f);
  49196. if ((is_pair(arg)) &&
  49197. (is_null(cdr(arg))) &&
  49198. (is_symbol(car(arg))))
  49199. {
  49200. /* (define (hi) (cond (#t => (lambda (s) s)))) */
  49201. set_opt_lambda2(sc->code, caddar(sc->code)); /* (lambda ...) above */
  49202. pair_set_syntax_symbol(sc->code, sc->if_p_feed_symbol);
  49203. }
  49204. }
  49205. }
  49206. }
  49207. else
  49208. {
  49209. s7_pointer p, sym = NULL;
  49210. bool xopt = true, c_s_is_ok = true;
  49211. pair_set_syntax_symbol(sc->code, sc->cond_simple_symbol);
  49212. for (p = sc->code; xopt && (is_pair(p)); p = cdr(p))
  49213. {
  49214. xopt = is_all_x_safe(sc, caar(p));
  49215. if ((c_s_is_ok) &&
  49216. (caar(p) != sc->T) &&
  49217. (caar(p) != sc->else_object))
  49218. {
  49219. if ((!is_pair(caar(p))) ||
  49220. (!is_h_safe_c_s(caar(p))) ||
  49221. ((sym) && (sym != cadaar(p))))
  49222. c_s_is_ok = false;
  49223. else sym = cadaar(p);
  49224. }
  49225. }
  49226. if (c_s_is_ok)
  49227. pair_set_syntax_symbol(sc->code, sc->cond_s_symbol);
  49228. else
  49229. {
  49230. if (xopt)
  49231. {
  49232. int i;
  49233. pair_set_syntax_symbol(sc->code, sc->cond_all_x_symbol);
  49234. for (i = 0, p = sc->code; is_pair(p); i++, p = cdr(p))
  49235. set_c_call(car(p), cond_all_x_eval(sc, caar(p), (is_null(sc->envir)) ? sc->rootlet : sc->envir)); /* handle 'else' specially here */
  49236. if (i == 2)
  49237. pair_set_syntax_symbol(sc->code, sc->cond_all_x_2_symbol);
  49238. }
  49239. }
  49240. }
  49241. }
  49242. return(sc->code);
  49243. }
  49244. static s7_pointer check_set(s7_scheme *sc)
  49245. {
  49246. if (!is_pair(sc->code))
  49247. {
  49248. if (is_null(sc->code)) /* (set!) */
  49249. eval_error(sc, "set!: not enough arguments: ~A", sc->code);
  49250. eval_error(sc, "set!: stray dot? ~A", sc->code); /* (set! . 1) */
  49251. }
  49252. if (!is_pair(cdr(sc->code)))
  49253. {
  49254. if (is_null(cdr(sc->code))) /* (set! var) */
  49255. eval_error(sc, "set!: not enough arguments: ~A", sc->code);
  49256. eval_error(sc, "set!: stray dot? ~A", sc->code); /* (set! var . 1) */
  49257. }
  49258. if (is_not_null(cddr(sc->code))) /* (set! var 1 2) */
  49259. eval_error(sc, "~A: too many arguments to set!", sc->code);
  49260. /* cadr (the value) has not yet been evaluated */
  49261. if (is_immutable(car(sc->code))) /* (set! pi 3) */
  49262. eval_error(sc, "set!: can't alter immutable object: ~S", car(sc->code));
  49263. if (is_pair(car(sc->code)))
  49264. {
  49265. if (is_pair(caar(sc->code)))
  49266. {
  49267. if (!s7_is_list(sc, cdar(sc->code))) /* (set! ('(1 2) . 0) 1) */
  49268. eval_error(sc, "improper list of args to set!: ~A", sc->code);
  49269. }
  49270. if (!is_proper_list(sc, car(sc->code))) /* (set! ("hi" . 1) #\a) or (set! (#(1 2) . 1) 0) */
  49271. eval_error(sc, "set! target is an improper list: (set! ~A ...)", car(sc->code));
  49272. }
  49273. else
  49274. {
  49275. if (!is_symbol(car(sc->code))) /* (set! 12345 1) */
  49276. eval_error(sc, "set! can't change ~S", car(sc->code));
  49277. }
  49278. if ((is_overlaid(sc->code)) &&
  49279. (has_opt_back(sc->code)))
  49280. {
  49281. if (is_pair(car(sc->code)))
  49282. {
  49283. /* here we have (set! (...) ...) */
  49284. s7_pointer inner, value;
  49285. inner = car(sc->code);
  49286. value = cadr(sc->code);
  49287. pair_set_syntax_symbol(sc->code, sc->set_unchecked_symbol);
  49288. if (is_symbol(car(inner)))
  49289. {
  49290. if ((is_null(cdr(inner))) &&
  49291. (!is_pair(value)) &&
  49292. (is_global(car(inner))) &&
  49293. (is_c_function(slot_value(global_slot(car(inner))))) &&
  49294. (c_function_required_args(slot_value(global_slot(car(inner)))) == 0))
  49295. pair_set_syntax_symbol(sc->code, sc->set_pws_symbol);
  49296. else
  49297. {
  49298. if ((is_pair(cdr(inner))) &&
  49299. (!is_pair(cddr(inner)))) /* we check cddr(sc->code) above */
  49300. {
  49301. if (!is_pair(cadr(inner)))
  49302. {
  49303. /* (set! (f s) ...) */
  49304. if (!is_pair(value))
  49305. pair_set_syntax_symbol(sc->code, sc->set_pair_symbol);
  49306. else
  49307. {
  49308. pair_set_syntax_symbol(sc->code, sc->set_pair_p_symbol);
  49309. /* splice_in_values protects us here from values */
  49310. if (is_h_optimized(value)) /* this excludes h_unknown_g etc */
  49311. {
  49312. pair_set_syntax_symbol(sc->code, sc->set_pair_z_symbol);
  49313. if (is_all_x_safe(sc, value))
  49314. {
  49315. s7_pointer obj;
  49316. annotate_arg(sc, cdr(sc->code), sc->envir);
  49317. pair_set_syntax_symbol(sc->code, sc->set_pair_za_symbol);
  49318. obj = find_symbol_checked(sc, car(inner));
  49319. if ((is_c_function(obj)) &&
  49320. (is_c_function(c_function_setter(obj))))
  49321. {
  49322. pair_set_syntax_symbol(sc->code, sc->set_pair_a_symbol);
  49323. }
  49324. }
  49325. }
  49326. }
  49327. }
  49328. else
  49329. {
  49330. if ((car(cadr(inner)) == sc->quote_symbol) &&
  49331. (is_symbol(car(inner))) &&
  49332. ((is_symbol(value)) || (is_all_x_safe(sc, value))))
  49333. {
  49334. if (is_symbol(value))
  49335. pair_set_syntax_symbol(sc->code, sc->set_let_s_symbol);
  49336. else
  49337. {
  49338. pair_set_syntax_symbol(sc->code, sc->set_let_all_x_symbol);
  49339. set_c_call(cdr(sc->code), all_x_eval(sc, value, sc->envir, let_symbol_is_safe));
  49340. }
  49341. }
  49342. else
  49343. {
  49344. if (is_h_safe_c_c(cadr(inner)))
  49345. {
  49346. if (!is_pair(value))
  49347. pair_set_syntax_symbol(sc->code, sc->set_pair_c_symbol);
  49348. else
  49349. {
  49350. /* splice_in_values protects us here from values */
  49351. pair_set_syntax_symbol(sc->code, sc->set_pair_c_p_symbol);
  49352. }
  49353. }
  49354. }
  49355. }
  49356. }
  49357. }
  49358. }
  49359. }
  49360. else pair_set_syntax_symbol(sc->code, sc->set_normal_symbol);
  49361. if (is_symbol(car(sc->code)))
  49362. {
  49363. s7_pointer settee, value;
  49364. settee = car(sc->code);
  49365. value = cadr(sc->code);
  49366. if ((!symbol_has_accessor(settee)) &&
  49367. (!is_syntactic(settee)))
  49368. {
  49369. if (is_symbol(value))
  49370. pair_set_syntax_symbol(sc->code, sc->set_symbol_s_symbol);
  49371. else
  49372. {
  49373. if (!is_pair(value))
  49374. pair_set_syntax_symbol(sc->code, sc->set_symbol_c_symbol);
  49375. else
  49376. {
  49377. if (car(value) == sc->quote_symbol)
  49378. pair_set_syntax_symbol(sc->code, sc->set_symbol_q_symbol);
  49379. else
  49380. {
  49381. /* if cadr(cadr) == car, or cdr(cadr) not null and cadr(cadr) == car, and cddr(cadr) == null,
  49382. * it's (set! <var> (<op> <var> val)) or (<op> val <var>) or (<op> <var>)
  49383. * in the set code, we get the slot as usual, then in case 1 above,
  49384. * car(sc->t2_1) = slot_value(slot), car(sc->t2_2) = increment, call <op>, set slot_value(slot)
  49385. *
  49386. * this can be done in all combined cases where a symbol is repeated (do in particular)
  49387. */
  49388. /* (define (hi) (let ((x 1)) (set! x (+ x 1))))
  49389. * but the value might be values:
  49390. * (let () (define (hi) (let ((x 0)) (set! x (values 1 2)) x)) (catch #t hi (lambda a a)) (hi))
  49391. * which is caught in splice_in_values
  49392. */
  49393. pair_set_syntax_symbol(sc->code, sc->set_symbol_p_symbol);
  49394. if (is_h_safe_c_s(value))
  49395. {
  49396. pair_set_syntax_symbol(sc->code, sc->set_symbol_opsq_symbol);
  49397. set_opt_sym2(sc->code, cadr(value));
  49398. }
  49399. else
  49400. {
  49401. if (is_h_optimized(value))
  49402. {
  49403. pair_set_syntax_symbol(sc->code, sc->set_symbol_z_symbol);
  49404. if (optimize_op(value) == HOP_SAFE_C_C)
  49405. {
  49406. pair_set_syntax_symbol(sc->code, sc->set_symbol_opcq_symbol);
  49407. /* opt1 here points back? */
  49408. set_opt_pair2(sc->code, cdr(value));
  49409. }
  49410. else
  49411. {
  49412. /* most of these special cases probably don't matter */
  49413. if (optimize_op(value) == HOP_SAFE_C_SS)
  49414. {
  49415. if (settee == cadr(value))
  49416. pair_set_syntax_symbol(sc->code, sc->increment_ss_symbol);
  49417. else pair_set_syntax_symbol(sc->code, sc->set_symbol_opssq_symbol);
  49418. set_opt_pair2(sc->code, cdr(value));
  49419. }
  49420. else
  49421. {
  49422. if (optimize_op(value) == HOP_SAFE_C_SSS)
  49423. {
  49424. if ((settee == cadr(value)) &&
  49425. (car(value) == sc->add_symbol))
  49426. pair_set_syntax_symbol(sc->code, sc->increment_sss_symbol);
  49427. else pair_set_syntax_symbol(sc->code, sc->set_symbol_opsssq_symbol);
  49428. set_opt_pair2(sc->code, cdr(value));
  49429. }
  49430. else
  49431. {
  49432. if (is_all_x_safe(sc, value)) /* value = cadr(sc->code) */
  49433. {
  49434. pair_set_syntax_symbol(sc->code, sc->set_symbol_a_symbol);
  49435. annotate_arg(sc, cdr(sc->code), sc->envir);
  49436. }
  49437. if (is_callable_c_op(optimize_op(value)))
  49438. {
  49439. if ((settee == cadr(value)) &&
  49440. (!is_null(cddr(value))))
  49441. {
  49442. if (is_null(cdddr(value)))
  49443. {
  49444. if (is_all_x_safe(sc, caddr(value)))
  49445. {
  49446. /* this appears to give a slight savings over the SZ case */
  49447. pair_set_syntax_symbol(sc->code, sc->increment_sa_symbol);
  49448. annotate_arg(sc, cddr(value), sc->envir); /* this sets c_callee(arg) */
  49449. set_opt_pair2(sc->code, cddr(value));
  49450. }
  49451. else
  49452. {
  49453. if (is_optimized(caddr(value)))
  49454. {
  49455. pair_set_syntax_symbol(sc->code, sc->increment_sz_symbol);
  49456. set_opt_pair2(sc->code, caddr(value));
  49457. }
  49458. }
  49459. }
  49460. else
  49461. {
  49462. if ((is_null(cddddr(value))) &&
  49463. (is_all_x_safe(sc, caddr(value))) &&
  49464. (is_all_x_safe(sc, cadddr(value))))
  49465. {
  49466. pair_set_syntax_symbol(sc->code, sc->increment_saa_symbol);
  49467. annotate_arg(sc, cddr(value), sc->envir);
  49468. annotate_arg(sc, cdddr(value), sc->envir);
  49469. set_opt_pair2(sc->code, cddr(value));
  49470. }
  49471. }
  49472. }
  49473. }
  49474. }
  49475. }
  49476. }
  49477. }
  49478. }
  49479. if ((is_h_optimized(value)) &&
  49480. (!is_unsafe(value)) &&
  49481. (is_not_null(cdr(value)))) /* (set! x (y)) */
  49482. {
  49483. if (is_not_null(cddr(value)))
  49484. {
  49485. if ((caddr(value) == small_int(1)) &&
  49486. (cadr(value) == settee))
  49487. {
  49488. if ((opt_cfunc(value) == add_s1) ||
  49489. (opt_cfunc(value) == add_cs1))
  49490. pair_set_syntax_symbol(sc->code, sc->increment_1_symbol);
  49491. else
  49492. {
  49493. if ((opt_cfunc(value) == subtract_s1) ||
  49494. (opt_cfunc(value) == subtract_cs1))
  49495. pair_set_syntax_symbol(sc->code, sc->decrement_1_symbol);
  49496. }
  49497. }
  49498. else
  49499. {
  49500. if ((cadr(value) == small_int(1)) &&
  49501. (caddr(value) == settee) &&
  49502. (opt_cfunc(value) == add_1s))
  49503. pair_set_syntax_symbol(sc->code, sc->increment_1_symbol);
  49504. else
  49505. {
  49506. if ((settee == caddr(value)) &&
  49507. (is_symbol(cadr(value))) &&
  49508. (caadr(sc->code) == sc->cons_symbol))
  49509. {
  49510. pair_set_syntax_symbol(sc->code, sc->set_cons_symbol);
  49511. set_opt_sym2(sc->code, cadr(value));
  49512. }
  49513. }
  49514. }
  49515. }
  49516. }
  49517. }
  49518. }
  49519. }
  49520. }
  49521. }
  49522. }
  49523. return(sc->code);
  49524. }
  49525. static bool set_pair_p_3(s7_scheme *sc, s7_pointer obj, s7_pointer arg, s7_pointer value)
  49526. {
  49527. /* fprintf(stderr, "%s: %s %s\n", __func__, DISPLAY(arg), DISPLAY(value)); */
  49528. if (is_slot(obj))
  49529. obj = slot_value(obj);
  49530. else eval_error(sc, "no generalized set for ~A", caar(sc->code));
  49531. switch (type(obj))
  49532. {
  49533. case T_C_OBJECT:
  49534. set_car(sc->t2_1, arg);
  49535. set_car(sc->t2_2, value);
  49536. sc->value = (*(c_object_set(obj)))(sc, obj, sc->t2_1);
  49537. break;
  49538. /* some of these are wasteful -- we know the object type! (list hash-table) */
  49539. case T_INT_VECTOR:
  49540. case T_FLOAT_VECTOR:
  49541. case T_VECTOR:
  49542. #if WITH_GMP
  49543. set_car(sc->t3_1, obj);
  49544. set_car(sc->t3_2, arg);
  49545. set_car(sc->t3_3, value);
  49546. sc->value = g_vector_set(sc, sc->t3_1);
  49547. #else
  49548. if (vector_rank(obj) > 1)
  49549. {
  49550. set_car(sc->t3_1, obj);
  49551. set_car(sc->t3_2, arg);
  49552. set_car(sc->t3_3, value);
  49553. sc->value = g_vector_set(sc, sc->t3_1);
  49554. }
  49555. else
  49556. {
  49557. s7_int index;
  49558. if (!is_integer(arg))
  49559. eval_type_error(sc, "vector-set!: index must be an integer: ~S", sc->code);
  49560. index = integer(arg);
  49561. if (index < 0)
  49562. eval_range_error(sc, "vector-set!: index must not be negative: ~S", sc->code);
  49563. if (index >= vector_length(obj))
  49564. eval_range_error(sc, "vector-set!: index must be less than vector length: ~S", sc->code);
  49565. vector_setter(obj)(sc, obj, index, value);
  49566. sc->value = _NFre(value);
  49567. }
  49568. #endif
  49569. break;
  49570. case T_STRING:
  49571. #if WITH_GMP
  49572. set_car(sc->t3_1, obj);
  49573. set_car(sc->t3_2, arg);
  49574. set_car(sc->t3_3, value);
  49575. sc->value = g_string_set(sc, sc->t3_1);
  49576. #else
  49577. {
  49578. s7_int index;
  49579. if (!is_integer(arg))
  49580. eval_type_error(sc, "string-set!: index must be an integer: ~S", sc->code);
  49581. index = integer(arg);
  49582. if (index < 0)
  49583. eval_range_error(sc, "string-set!: index must not be negative: ~S", sc->code);
  49584. if (index >= string_length(obj))
  49585. eval_range_error(sc, "string-set!: index must be less than string length: ~S", sc->code);
  49586. if (s7_is_character(value))
  49587. {
  49588. string_value(obj)[index] = (char)s7_character(value);
  49589. sc->value = _NFre(value);
  49590. }
  49591. else
  49592. {
  49593. if ((is_byte_vector(obj)) &&
  49594. (s7_is_integer(value)))
  49595. {
  49596. int ic;
  49597. ic = s7_integer(value);
  49598. if ((ic < 0) || (ic > 255))
  49599. eval_type_error(sc, "string-set!: value must be a character: ~S", sc->code);
  49600. string_value(obj)[index] = (char)ic;
  49601. sc->value = _NFre(value);
  49602. }
  49603. else eval_type_error(sc, "string-set!: value must be a character: ~S", sc->code);
  49604. }
  49605. }
  49606. #endif
  49607. break;
  49608. case T_PAIR:
  49609. set_car(sc->t3_1, obj);
  49610. set_car(sc->t3_2, arg);
  49611. set_car(sc->t3_3, value);
  49612. sc->value = g_list_set(sc, sc->t3_1);
  49613. break;
  49614. case T_HASH_TABLE:
  49615. sc->value = s7_hash_table_set(sc, obj, arg, value);
  49616. break;
  49617. case T_LET:
  49618. sc->value = s7_let_set(sc, obj, arg, value);
  49619. break;
  49620. case T_C_OPT_ARGS_FUNCTION:
  49621. case T_C_RST_ARGS_FUNCTION:
  49622. case T_C_ANY_ARGS_FUNCTION: /* (let ((lst (list 1 2))) (set! (list-ref lst 1) 2) lst) */
  49623. case T_C_FUNCTION:
  49624. case T_C_FUNCTION_STAR:
  49625. /* obj here is a c_function, but its setter could be a closure and vice versa below */
  49626. if (is_procedure_or_macro(c_function_setter(obj)))
  49627. {
  49628. if (is_c_function(c_function_setter(obj)))
  49629. {
  49630. set_car(sc->t2_1, arg);
  49631. set_car(sc->t2_2, value);
  49632. sc->value = c_function_call(c_function_setter(obj))(sc, sc->t2_1);
  49633. }
  49634. else
  49635. {
  49636. sc->code = c_function_setter(obj);
  49637. if (needs_copied_args(sc->code))
  49638. sc->args = list_2(sc, arg, value);
  49639. else sc->args = set_plist_2(sc, arg, value);
  49640. return(true); /* goto APPLY; */
  49641. }
  49642. }
  49643. else eval_error(sc, "no generalized set for ~A", obj);
  49644. break;
  49645. case T_MACRO: case T_MACRO_STAR:
  49646. case T_BACRO: case T_BACRO_STAR:
  49647. case T_CLOSURE: case T_CLOSURE_STAR:
  49648. if (is_procedure_or_macro(closure_setter(obj)))
  49649. {
  49650. if (is_c_function(closure_setter(obj)))
  49651. {
  49652. set_car(sc->t2_1, arg);
  49653. set_car(sc->t2_2, value);
  49654. sc->value = c_function_call(closure_setter(obj))(sc, sc->t2_1);
  49655. }
  49656. else
  49657. {
  49658. sc->code = closure_setter(obj);
  49659. if (needs_copied_args(sc->code))
  49660. sc->args = list_2(sc, arg, value);
  49661. else sc->args = set_plist_2(sc, arg, value);
  49662. return(true); /* goto APPLY; */
  49663. }
  49664. }
  49665. else eval_error(sc, "no generalized set for ~A", obj);
  49666. break;
  49667. default: /* (set! (1 2) 3) */
  49668. eval_error(sc, "no generalized set for ~A", obj);
  49669. }
  49670. return(false);
  49671. }
  49672. static bool safe_stepper(s7_scheme *sc, s7_pointer expr, s7_pointer vars)
  49673. {
  49674. /* for now, just look for stepper as last element of any list
  49675. * any embedded set is handled by do-is-safe, so we don't need to descend into the depths
  49676. */
  49677. s7_pointer p;
  49678. if (direct_memq(cadr(expr), vars))
  49679. return(false);
  49680. for (p = cdr(expr); is_pair(cdr(p)); p = cdr(p));
  49681. if (is_pair(p))
  49682. {
  49683. if ((is_optimized(p)) &&
  49684. ((optimize_op(p) & 1) != 0) &&
  49685. (is_safe_c_op(optimize_op(p))))
  49686. return(true);
  49687. if (direct_memq(car(p), vars))
  49688. return(false);
  49689. }
  49690. else
  49691. {
  49692. if (direct_memq(p, vars))
  49693. return(false);
  49694. }
  49695. return(true);
  49696. }
  49697. static int set_pair_ex(s7_scheme *sc)
  49698. {
  49699. s7_pointer caar_code, cx;
  49700. caar_code = caar(sc->code);
  49701. if (is_pair(caar_code))
  49702. {
  49703. push_stack(sc, OP_SET2, cdar(sc->code), cdr(sc->code));
  49704. sc->code = caar_code;
  49705. return(goto_EVAL);
  49706. }
  49707. if (is_symbol(caar_code))
  49708. {
  49709. /* this was cx = s7_symbol_value(sc, caar_code) but the function call overhead is noticeable */
  49710. cx = find_symbol(sc, caar_code);
  49711. if (is_slot(cx))
  49712. cx = slot_value(cx);
  49713. else eval_error_no_return(sc, sc->syntax_error_symbol, "no generalized set for ~A", caar_code);
  49714. }
  49715. else cx = caar_code;
  49716. /* code here is the accessor and the value without the "set!": ((window-width) 800) */
  49717. /* (set! (hi 0) (* 2 3)) -> ((hi 0) (* 2 3)) */
  49718. /* for these kinds of objects, some Schemes restrict set!
  49719. * (list-set! '(1 2 3) 1 32) is accepted but does it make sense?
  49720. * (set-car! '(1 . 2) 32)
  49721. * (string-set! "hiho" 1 #\z)
  49722. * (vector-set! #(1 2 3) 1 32)
  49723. * (let ((x (lambda () "hiho"))) (string-set! (x) 1 #\a))
  49724. * (let ((x (lambda () #(1 2 3)))) (vector-set! (x) 1 32))
  49725. * (let ((str "hiho")) (string-set! str 1 #\x) str)
  49726. * (let ((v #(1 2 3))) (vector-set! v 1 32) v)
  49727. * (let ((x (lambda () "hiho"))) (string-set! (x) 1 #\x) (x))
  49728. *
  49729. * It seems weird that we can reach into both the function body, and its closure:
  49730. * (let ((xx (let ((x '(1 2 3))) (lambda () x)))) (list-set! (xx) 1 32) (xx)) -> '(1 32 3)
  49731. *
  49732. * (let* ((x '(1 2)) (y (list x)) (z (car y))) (list-set! z 1 32) (list x y z))
  49733. * ((1 32) ((1 32)) (1 32))
  49734. *
  49735. * (string-set! (symbol->string 'symbol->string) 1 #\X) -> error currently also in Guile "string is read-only"
  49736. * (setf (elt (symbol-name 'xyz) 1) #\X) -> error in CL "read-only string"
  49737. */
  49738. /* for gmp case, indices need to be decoded via s7_integer, not just integer */
  49739. switch (type(cx))
  49740. {
  49741. case T_C_OBJECT:
  49742. {
  49743. s7_pointer settee, index, val;
  49744. if (is_null(cdr(sc->code)))
  49745. s7_wrong_number_of_args_error(sc, "no value for object-set!: ~S", sc->code);
  49746. if (!is_null(cddr(sc->code)))
  49747. s7_wrong_number_of_args_error(sc, "too many values for object-set!: ~S", sc->code);
  49748. settee = car(sc->code);
  49749. if ((is_null(cdr(settee))) ||
  49750. (!is_null(cddr(settee))))
  49751. {
  49752. /* no-index or multi-index case -- use slow version.
  49753. * TODO: ambiguity here -- is (set! (obj a b) v) actually (set! ((obj a) b) v)?
  49754. * perhaps look at setter? c-object-set takes 1 arg -- is this a bug?
  49755. */
  49756. push_op_stack(sc, sc->object_set_function);
  49757. if (is_null(cdr(settee)))
  49758. {
  49759. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cddr(sc->code));
  49760. sc->code = cadr(sc->code);
  49761. }
  49762. else
  49763. {
  49764. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), s7_append(sc, cddr(settee), cdr(sc->code)));
  49765. sc->code = cadr(settee);
  49766. }
  49767. return(goto_EVAL);
  49768. }
  49769. index = cadr(settee);
  49770. if (!is_pair(index))
  49771. {
  49772. if (is_symbol(index))
  49773. index = find_symbol_checked(sc, index);
  49774. val = cadr(sc->code);
  49775. if (!is_pair(val))
  49776. {
  49777. if (is_symbol(val))
  49778. val = find_symbol_checked(sc, val);
  49779. set_car(sc->t2_1, index);
  49780. set_car(sc->t2_2, val);
  49781. sc->value = (*(c_object_set(cx)))(sc, cx, sc->t2_1);
  49782. return(goto_START);
  49783. }
  49784. push_op_stack(sc, sc->object_set_function);
  49785. sc->args = list_2(sc, index, cx);
  49786. sc->code = cdr(sc->code);
  49787. return(goto_EVAL_ARGS);
  49788. }
  49789. else
  49790. {
  49791. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
  49792. push_op_stack(sc, sc->object_set_function);
  49793. sc->code = cadr(settee);
  49794. }
  49795. return(goto_EVAL);
  49796. }
  49797. break;
  49798. case T_INT_VECTOR:
  49799. case T_FLOAT_VECTOR:
  49800. case T_VECTOR:
  49801. {
  49802. /* cx is the vector, sc->code is expr without the set! */
  49803. /* args have not been evaluated! */
  49804. s7_pointer settee, index, val;
  49805. if (is_null(cdr(sc->code)))
  49806. s7_wrong_number_of_args_error(sc, "no value for vector-set!: ~S", sc->code);
  49807. if (!is_null(cddr(sc->code)))
  49808. s7_wrong_number_of_args_error(sc, "too many values for vector-set!: ~S", sc->code);
  49809. settee = car(sc->code);
  49810. if (is_null(cdr(settee)))
  49811. s7_wrong_number_of_args_error(sc, "no index for vector-set!: ~S", sc->code);
  49812. if ((!is_null(cddr(settee))) &&
  49813. (type(cx) == T_VECTOR))
  49814. {
  49815. push_stack(sc, OP_SET2, cddr(settee), cdr(sc->code));
  49816. sc->code = list_2(sc, car(settee), cadr(settee));
  49817. return(goto_EVAL);
  49818. }
  49819. if ((!is_null(cddr(settee))) ||
  49820. (vector_rank(cx) > 1))
  49821. {
  49822. /* multi-index case -- use slow version */
  49823. push_op_stack(sc, sc->vector_set_function);
  49824. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), s7_append(sc, cddr(settee), cdr(sc->code)));
  49825. sc->code = cadr(settee);
  49826. return(goto_EVAL);
  49827. }
  49828. index = cadr(settee);
  49829. if (!is_pair(index))
  49830. {
  49831. s7_int ind;
  49832. if (is_symbol(index))
  49833. index = find_symbol_checked(sc, index);
  49834. if (!s7_is_integer(index))
  49835. eval_error_no_return(sc, sc->wrong_type_arg_symbol, "vector-set!: index must be an integer: ~S", sc->code);
  49836. ind = s7_integer(index);
  49837. if ((ind < 0) ||
  49838. (ind >= vector_length(cx)))
  49839. out_of_range(sc, sc->vector_set_symbol, small_int(2), index, (ind < 0) ? its_negative_string : its_too_large_string);
  49840. val = cadr(sc->code);
  49841. if (!is_pair(val))
  49842. {
  49843. if (is_symbol(val))
  49844. val = find_symbol_checked(sc, val);
  49845. vector_setter(cx)(sc, cx, ind, val);
  49846. sc->value = _NFre(val);
  49847. return(goto_START);
  49848. }
  49849. push_op_stack(sc, sc->vector_set_function);
  49850. sc->args = list_2(sc, index, cx);
  49851. sc->code = cdr(sc->code);
  49852. return(goto_EVAL_ARGS);
  49853. }
  49854. else
  49855. {
  49856. /* here the index calc might be trivial -- (+ i 1) or (- j 1) but this branch hardly ever happens
  49857. */
  49858. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
  49859. push_op_stack(sc, sc->vector_set_function);
  49860. sc->code = cadr(settee);
  49861. }
  49862. }
  49863. break;
  49864. case T_STRING:
  49865. {
  49866. /* sc->code = cons(sc, sc->string_set_function, s7_append(sc, car(sc->code), cdr(sc->code)));
  49867. *
  49868. * here only one index makes sense, and it is required, so
  49869. * (set! ("str") #\a), (set! ("str" . 1) #\a) and (set! ("str" 1 2) #\a)
  49870. * are all errors (but see below!).
  49871. */
  49872. s7_pointer settee, index, val;
  49873. if (is_null(cdr(sc->code)))
  49874. s7_wrong_number_of_args_error(sc, "no value for string-set!: ~S", sc->code);
  49875. if (!is_null(cddr(sc->code)))
  49876. s7_wrong_number_of_args_error(sc, "too many values for string-set!: ~S", sc->code);
  49877. settee = car(sc->code);
  49878. if (is_null(cdr(settee))) /* there's an index: (set! (str i) #\a), code is ((str 0) #\1) */
  49879. s7_wrong_number_of_args_error(sc, "no index for string-set!: ~S", sc->code);
  49880. if (!is_null(cddr(settee)))
  49881. s7_wrong_number_of_args_error(sc, "too many indices for string-set!: ~S", sc->code);
  49882. /* if there's one index (the standard case), and it is not a pair, and there's one value (also standard)
  49883. * and it is not a pair, let's optimize this thing!
  49884. * cx is what we're setting, cadar is the index, cadr is the new value
  49885. */
  49886. index = cadr(settee);
  49887. if (!is_pair(index))
  49888. {
  49889. s7_int ind;
  49890. if (is_symbol(index))
  49891. index = find_symbol_checked(sc, index);
  49892. if (!s7_is_integer(index))
  49893. eval_error_no_return(sc, sc->wrong_type_arg_symbol, "string-set!: index must be an integer: ~S", sc->code);
  49894. ind = s7_integer(index);
  49895. if ((ind < 0) ||
  49896. (ind >= string_length(cx)))
  49897. out_of_range(sc, sc->string_set_symbol, small_int(2), index, (ind < 0) ? its_negative_string : its_too_large_string);
  49898. val = cadr(sc->code);
  49899. if (!is_pair(val))
  49900. {
  49901. if (is_symbol(val))
  49902. val = find_symbol_checked(sc, val);
  49903. if (s7_is_character(val))
  49904. {
  49905. string_value(cx)[ind] = character(val);
  49906. sc->value = val;
  49907. return(goto_START);
  49908. }
  49909. else
  49910. {
  49911. if ((is_byte_vector(cx)) &&
  49912. (s7_is_integer(val)))
  49913. {
  49914. int ic;
  49915. ic = s7_integer(val);
  49916. if ((ic < 0) || (ic > 255))
  49917. eval_error_no_return(sc, sc->wrong_type_arg_symbol, "string-set!: value must be a character: ~S", sc->code);
  49918. string_value(cx)[ind] = (char)ic;
  49919. sc->value = val;
  49920. return(goto_START);
  49921. }
  49922. }
  49923. eval_error_no_return(sc, sc->wrong_type_arg_symbol, "string-set!: value must be a character: ~S", sc->code);
  49924. }
  49925. push_op_stack(sc, sc->string_set_function);
  49926. sc->args = list_2(sc, index, cx);
  49927. sc->code = cdr(sc->code);
  49928. return(goto_EVAL_ARGS);
  49929. }
  49930. else
  49931. {
  49932. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
  49933. push_op_stack(sc, sc->string_set_function);
  49934. sc->code = cadar(sc->code);
  49935. }
  49936. }
  49937. break;
  49938. case T_PAIR:
  49939. /* code: ((lst 1) 32) from (let ((lst (list 1 2 3))) (set! (lst 1) 32)) */
  49940. {
  49941. s7_pointer settee, index, val;
  49942. if (is_null(cdr(sc->code)))
  49943. s7_wrong_number_of_args_error(sc, "no value for list-set!: ~S", sc->code);
  49944. if (!is_null(cddr(sc->code)))
  49945. s7_wrong_number_of_args_error(sc, "too many values for list-set!: ~S", sc->code);
  49946. settee = car(sc->code);
  49947. if (is_null(cdr(settee)))
  49948. s7_wrong_number_of_args_error(sc, "no index for list-set!: ~S", sc->code);
  49949. if (!is_null(cddr(settee)))
  49950. {
  49951. /* split (set! (a b c...) v) into (set! ((a b) c ...) v), eval (a b), return
  49952. * (let ((L (list (list 1 2)))) (set! (L 0 0) 3) L)
  49953. */
  49954. push_stack(sc, OP_SET2, cddr(settee), cdr(sc->code));
  49955. sc->code = list_2(sc, car(settee), cadr(settee));
  49956. return(goto_EVAL);
  49957. }
  49958. index = cadr(settee);
  49959. val = cadr(sc->code);
  49960. if ((is_pair(index)) ||
  49961. (is_pair(val)))
  49962. {
  49963. push_op_stack(sc, sc->list_set_function);
  49964. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), s7_append(sc, cddr(settee), cdr(sc->code)));
  49965. sc->code = index;
  49966. return(goto_EVAL);
  49967. }
  49968. if (is_symbol(index))
  49969. index = find_symbol_checked(sc, index);
  49970. if (is_symbol(val))
  49971. val = find_symbol_checked(sc, val);
  49972. set_car(sc->t2_1, index);
  49973. set_car(sc->t2_2, val);
  49974. sc->value = g_list_set_1(sc, cx, sc->t2_1, 2);
  49975. return(goto_START);
  49976. }
  49977. break;
  49978. case T_HASH_TABLE:
  49979. {
  49980. s7_pointer settee, key;
  49981. if (is_null(cdr(sc->code)))
  49982. s7_wrong_number_of_args_error(sc, "no value for hash-table-set!: ~S", sc->code);
  49983. if (!is_null(cddr(sc->code)))
  49984. s7_wrong_number_of_args_error(sc, "too many values for hash-table-set!: ~S", sc->code);
  49985. settee = car(sc->code);
  49986. if (is_null(cdr(settee)))
  49987. s7_wrong_number_of_args_error(sc, "no key for hash-table-set!: ~S", sc->code);
  49988. if (!is_null(cddr(settee)))
  49989. {
  49990. push_stack(sc, OP_SET2, cddr(settee), cdr(sc->code));
  49991. sc->code = list_2(sc, car(settee), cadr(settee));
  49992. return(goto_EVAL);
  49993. }
  49994. key = cadr(settee);
  49995. if (!is_pair(key))
  49996. {
  49997. s7_pointer val;
  49998. if (is_symbol(key))
  49999. key = find_symbol_checked(sc, key);
  50000. val = cadr(sc->code);
  50001. if (!is_pair(val))
  50002. {
  50003. if (is_symbol(val))
  50004. val = find_symbol_checked(sc, val);
  50005. sc->value = s7_hash_table_set(sc, cx, key, val);
  50006. return(goto_START);
  50007. }
  50008. push_op_stack(sc, sc->hash_table_set_function);
  50009. sc->args = list_2(sc, key, cx);
  50010. sc->code = cdr(sc->code);
  50011. return(goto_EVAL_ARGS);
  50012. }
  50013. else
  50014. {
  50015. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
  50016. push_op_stack(sc, sc->hash_table_set_function);
  50017. sc->code = cadar(sc->code);
  50018. }
  50019. }
  50020. break;
  50021. case T_LET:
  50022. /* sc->code = cons(sc, sc->let_set_function, s7_append(sc, car(sc->code), cdr(sc->code))); */
  50023. {
  50024. s7_pointer settee, key;
  50025. /* code: ((gen 'input) input) from (set! (gen 'input) input)
  50026. */
  50027. if (is_null(cdr(sc->code)))
  50028. s7_wrong_number_of_args_error(sc, "no value for let-set!: ~S", sc->code);
  50029. if (!is_null(cddr(sc->code)))
  50030. s7_wrong_number_of_args_error(sc, "too many values for let-set!: ~S", sc->code);
  50031. settee = car(sc->code);
  50032. if (is_null(cdr(settee)))
  50033. s7_wrong_number_of_args_error(sc, "no identifier for let-set!: ~S", sc->code);
  50034. if (!is_null(cddr(settee)))
  50035. {
  50036. push_stack(sc, OP_SET2, cddr(settee), cdr(sc->code));
  50037. sc->code = list_2(sc, car(settee), cadr(settee));
  50038. return(goto_EVAL);
  50039. }
  50040. key = cadr(settee);
  50041. if ((is_pair(key)) &&
  50042. (car(key) == sc->quote_symbol))
  50043. {
  50044. s7_pointer val;
  50045. key = cadr(key);
  50046. val = cadr(sc->code);
  50047. if (!is_pair(val))
  50048. {
  50049. if (is_symbol(val))
  50050. val = find_symbol_checked(sc, val);
  50051. sc->value = s7_let_set(sc, cx, key, val);
  50052. return(goto_START);
  50053. }
  50054. push_op_stack(sc, sc->let_set_function);
  50055. sc->args = list_2(sc, key, cx);
  50056. sc->code = cdr(sc->code);
  50057. return(goto_EVAL_ARGS);
  50058. }
  50059. else
  50060. {
  50061. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, cx), cdr(sc->code));
  50062. push_op_stack(sc, sc->let_set_function);
  50063. sc->code = cadar(sc->code);
  50064. }
  50065. }
  50066. break;
  50067. case T_C_MACRO:
  50068. case T_C_OPT_ARGS_FUNCTION:
  50069. case T_C_RST_ARGS_FUNCTION:
  50070. case T_C_ANY_ARGS_FUNCTION: /* (let ((lst (list 1 2))) (set! (list-ref lst 0) 2) lst) */
  50071. case T_C_FUNCTION:
  50072. case T_C_FUNCTION_STAR:
  50073. /* perhaps it has a setter */
  50074. if (is_procedure(c_function_setter(cx)))
  50075. {
  50076. /* sc->code = cons(sc, c_function_setter(cx), s7_append(sc, cdar(sc->code), cdr(sc->code))); */
  50077. if (is_pair(cdar(sc->code)))
  50078. {
  50079. if ((is_symbol(cadr(sc->code))) &&
  50080. (is_symbol(cadar(sc->code))))
  50081. {
  50082. if (is_null(cddar(sc->code)))
  50083. {
  50084. set_car(sc->t2_1, find_symbol_checked(sc, cadar(sc->code)));
  50085. set_car(sc->t2_2, find_symbol_checked(sc, cadr(sc->code)));
  50086. sc->args = sc->t2_1;
  50087. sc->code = c_function_setter(cx);
  50088. return(goto_APPLY); /* check arg num etc */
  50089. }
  50090. if ((is_symbol(caddar(sc->code))) &&
  50091. (is_null(cdddar(sc->code))))
  50092. {
  50093. set_car(sc->t3_1, find_symbol_checked(sc, cadar(sc->code)));
  50094. set_car(sc->t3_2, find_symbol_checked(sc, caddar(sc->code)));
  50095. set_car(sc->t3_3, find_symbol_checked(sc, cadr(sc->code)));
  50096. sc->args = sc->t3_1;
  50097. sc->code = c_function_setter(cx);
  50098. return(goto_APPLY); /* check arg num etc */
  50099. }
  50100. }
  50101. push_op_stack(sc, c_function_setter(cx));
  50102. push_stack(sc, OP_EVAL_ARGS1, sc->nil, s7_append(sc, cddar(sc->code), cdr(sc->code)));
  50103. sc->code = cadar(sc->code);
  50104. }
  50105. else
  50106. {
  50107. if ((is_null(cddr(sc->code))) &&
  50108. (!is_pair(cadr(sc->code))))
  50109. {
  50110. if (is_symbol(cadr(sc->code)))
  50111. set_car(sc->t1_1, find_symbol_checked(sc, cadr(sc->code)));
  50112. else set_car(sc->t1_1, cadr(sc->code));
  50113. sc->args = sc->t1_1;
  50114. sc->code = c_function_setter(cx);
  50115. return(goto_APPLY); /* check arg num etc */
  50116. }
  50117. push_op_stack(sc, c_function_setter(cx));
  50118. push_stack(sc, OP_EVAL_ARGS1, sc->nil, cddr(sc->code));
  50119. sc->code = cadr(sc->code);
  50120. }
  50121. }
  50122. else
  50123. {
  50124. if (is_any_macro(c_function_setter(cx)))
  50125. {
  50126. if (is_null(cdar(sc->code)))
  50127. sc->args = copy_list(sc, cdr(sc->code));
  50128. else sc->args = s7_append(sc, cdar(sc->code), copy_list(sc, cdr(sc->code)));
  50129. /* append copies except for its last arg, but for macros, we have to copy everything, hence the extra copy_list */
  50130. sc->code = c_function_setter(cx);
  50131. return(goto_APPLY);
  50132. }
  50133. else eval_error_no_return(sc, sc->syntax_error_symbol, "no generalized set for ~A", caar_code);
  50134. }
  50135. break;
  50136. case T_MACRO: case T_MACRO_STAR:
  50137. case T_BACRO: case T_BACRO_STAR:
  50138. case T_CLOSURE: case T_CLOSURE_STAR:
  50139. {
  50140. s7_pointer setter;
  50141. setter = closure_setter(cx);
  50142. if (is_procedure(setter)) /* appears to be caar_code */
  50143. {
  50144. /* (set! (o g) ...), here cx = o, sc->code = ((o g) ...) */
  50145. push_op_stack(sc, setter);
  50146. if (is_null(cdar(sc->code)))
  50147. {
  50148. push_stack(sc, OP_EVAL_ARGS1, sc->nil, cddr(sc->code));
  50149. sc->code = cadr(sc->code);
  50150. }
  50151. else
  50152. {
  50153. if (is_null(cddar(sc->code)))
  50154. push_stack(sc, OP_EVAL_ARGS1, sc->nil, cdr(sc->code));
  50155. else push_stack(sc, OP_EVAL_ARGS1, sc->nil, s7_append(sc, cddar(sc->code), cdr(sc->code)));
  50156. sc->code = cadar(sc->code);
  50157. }
  50158. }
  50159. else
  50160. {
  50161. if (is_any_macro(setter))
  50162. {
  50163. if (is_null(cdar(sc->code)))
  50164. sc->args = copy_list(sc, cdr(sc->code));
  50165. else sc->args = s7_append(sc, cdar(sc->code), copy_list(sc, cdr(sc->code)));
  50166. sc->code = setter;
  50167. return(goto_APPLY);
  50168. }
  50169. else eval_error_no_return(sc, sc->syntax_error_symbol, "no generalized set for ~A", caar_code);
  50170. }
  50171. }
  50172. break;
  50173. case T_ITERATOR: /* not sure this makes sense */
  50174. {
  50175. s7_pointer setter;
  50176. setter = iterator_sequence(cx);
  50177. if ((is_any_closure(setter)) || (is_any_macro(setter)))
  50178. setter = closure_setter(iterator_sequence(cx));
  50179. else setter = sc->F;
  50180. if (is_procedure(setter))
  50181. {
  50182. push_op_stack(sc, setter);
  50183. push_stack(sc, OP_EVAL_ARGS1, sc->nil, sc->nil);
  50184. sc->code = cadr(sc->code); /* the (as yet unevaluated) value, incoming code was ((obj) val) */
  50185. }
  50186. else
  50187. {
  50188. if (is_any_macro(setter))
  50189. {
  50190. sc->args = list_1(sc, cadr(sc->code));
  50191. sc->code = setter;
  50192. return(goto_APPLY);
  50193. }
  50194. else eval_error_no_return(sc, sc->syntax_error_symbol, "no generalized set for ~A", caar_code);
  50195. }
  50196. }
  50197. break;
  50198. case T_SYNTAX:
  50199. if (cx == slot_value(global_slot(sc->with_let_symbol)))
  50200. {
  50201. /* (set! (with-let a b) x), cx = with-let, sc->code = ((with-let a b) x)
  50202. * a and x are in the current env, b is in a, we need to evaluate a and x, then
  50203. * call (with-let a-value (set! b x-value))
  50204. */
  50205. sc->args = cdar(sc->code);
  50206. sc->code = cadr(sc->code);
  50207. push_stack(sc, OP_SET_WITH_LET_1, sc->args, sc->code);
  50208. return(goto_EVAL);
  50209. }
  50210. /* else fall through */
  50211. default: /* (set! (1 2) 3) */
  50212. eval_error_no_return(sc, sc->syntax_error_symbol, "no generalized set for ~A", caar_code);
  50213. }
  50214. return(goto_EVAL);
  50215. }
  50216. static void activate_let(s7_scheme *sc)
  50217. {
  50218. s7_pointer e;
  50219. e = sc->value;
  50220. if (!is_let(e)) /* (with-let . "hi") */
  50221. eval_error_no_return(sc, sc->wrong_type_arg_symbol, "with-let takes an environment argument: ~A", e);
  50222. if (e == sc->rootlet)
  50223. sc->envir = sc->nil; /* (with-let (rootlet) ...) */
  50224. else
  50225. {
  50226. s7_pointer p;
  50227. set_with_let_let(e);
  50228. let_id(e) = ++sc->let_number;
  50229. sc->envir = e;
  50230. for (p = let_slots(e); is_slot(p); p = next_slot(p))
  50231. {
  50232. s7_pointer sym;
  50233. sym = slot_symbol(p);
  50234. if (symbol_id(sym) != sc->let_number)
  50235. symbol_set_local(sym, sc->let_number, p);
  50236. }
  50237. }
  50238. }
  50239. static bool tree_match(s7_scheme *sc, s7_pointer tree)
  50240. {
  50241. if (is_symbol(tree))
  50242. return(is_matched_symbol(tree));
  50243. if (is_pair(tree))
  50244. return((tree_match(sc, car(tree))) || (tree_match(sc, cdr(tree))));
  50245. return(false);
  50246. }
  50247. static bool do_is_safe(s7_scheme *sc, s7_pointer body, s7_pointer steppers, s7_pointer var_list, bool *has_set)
  50248. {
  50249. /* here any (unsafe?) closure or jumping-op (call/cc) or shadowed variable is trouble */
  50250. s7_pointer p;
  50251. for (p = body; is_pair(p); p = cdr(p))
  50252. {
  50253. s7_pointer expr;
  50254. expr = car(p);
  50255. if (is_pair(expr))
  50256. {
  50257. s7_pointer x;
  50258. x = car(expr);
  50259. if (is_symbol(x))
  50260. {
  50261. if (is_syntactic(x))
  50262. {
  50263. opcode_t op;
  50264. s7_pointer func, vars;
  50265. func = slot_value(global_slot(x));
  50266. op = (opcode_t)syntax_opcode(func);
  50267. switch (op)
  50268. {
  50269. case OP_MACROEXPAND:
  50270. return(false);
  50271. case OP_QUOTE:
  50272. break;
  50273. case OP_LET:
  50274. case OP_LET_STAR:
  50275. if (is_symbol(cadr(expr)))
  50276. return(false);
  50277. case OP_LETREC:
  50278. case OP_LETREC_STAR:
  50279. case OP_DO:
  50280. for (vars = cadr(expr); is_pair(vars); vars = cdr(vars))
  50281. {
  50282. s7_pointer var;
  50283. var = caar(vars);
  50284. if ((direct_memq(var, var_list)) ||
  50285. (direct_memq(var, steppers)))
  50286. return(false);
  50287. var_list = cons(sc, var, var_list);
  50288. sc->x = var_list;
  50289. if ((is_pair(cdar(vars))) &&
  50290. (!do_is_safe(sc, cdar(vars), steppers, var_list, has_set)))
  50291. {
  50292. sc->x = sc->nil;
  50293. return(false);
  50294. }
  50295. sc->x = sc->nil;
  50296. }
  50297. if (op == OP_DO)
  50298. {
  50299. /* set_unsafe_do(cdr(expr)); */
  50300. if (!do_is_safe(sc, (op == OP_DO) ? cdddr(expr) : cddr(expr), steppers, var_list, has_set))
  50301. return(false);
  50302. }
  50303. else
  50304. {
  50305. if (!do_is_safe(sc, cddr(expr), steppers, var_list, has_set))
  50306. return(false);
  50307. }
  50308. break;
  50309. case OP_SET:
  50310. {
  50311. s7_pointer settee;
  50312. settee = cadr(expr);
  50313. if (!is_symbol(settee)) /* (set! (...) ...) which is tricky due to setter functions/macros */
  50314. {
  50315. s7_pointer setv;
  50316. if ((!is_pair(settee)) ||
  50317. (!is_symbol(car(settee))))
  50318. return(false);
  50319. setv = find_symbol_unexamined(sc, car(settee));
  50320. if (!((setv) &&
  50321. ((is_sequence(setv)) ||
  50322. ((is_c_function(setv)) &&
  50323. (is_safe_procedure(c_function_setter(setv)))))))
  50324. return(false);
  50325. (*has_set) = true;
  50326. }
  50327. else
  50328. {
  50329. if ((is_pair(cadr(sc->code))) &&
  50330. (is_pair(caadr(sc->code))))
  50331. {
  50332. bool res;
  50333. set_match_symbol(settee);
  50334. res = tree_match(sc, caadr(sc->code)); /* (set! end ...) in some fashion */
  50335. clear_match_symbol(settee);
  50336. if (res) return(false);
  50337. }
  50338. if (!direct_memq(cadr(expr), var_list)) /* is some non-local variable being set? */
  50339. (*has_set) = true;
  50340. }
  50341. if (!do_is_safe(sc, cddr(expr), steppers, var_list, has_set))
  50342. return(false);
  50343. if (!safe_stepper(sc, expr, steppers)) /* is step var's value used as the stored value by set!? */
  50344. return(false);
  50345. }
  50346. break;
  50347. case OP_IF:
  50348. case OP_WHEN:
  50349. case OP_UNLESS:
  50350. case OP_COND:
  50351. case OP_CASE:
  50352. case OP_AND:
  50353. case OP_OR:
  50354. case OP_BEGIN:
  50355. if (!do_is_safe(sc, cdr(expr), steppers, var_list, has_set))
  50356. return(false);
  50357. break;
  50358. case OP_WITH_LET:
  50359. return(true);
  50360. default:
  50361. return(false);
  50362. }
  50363. }
  50364. else
  50365. {
  50366. if ((!is_optimized(expr)) ||
  50367. (is_unsafe(expr)) ||
  50368. (!do_is_safe(sc, cdr(expr), steppers, var_list, has_set)))
  50369. /* this is unreasonably retrictive because optimize_expression returns "unsafe"
  50370. * even when everything is safe -- it's merely saying it could not find a
  50371. * special optimization case for the expression.
  50372. */
  50373. return(false);
  50374. else
  50375. {
  50376. if (is_setter(x)) /* "setter" includes stuff like cons and vector -- x is a symbol */
  50377. {
  50378. /* (hash-table-set! ht i 0) -- caddr is being saved, so this is not safe
  50379. * similarly (vector-set! v 0 i) etc
  50380. */
  50381. if (!direct_memq(cadr(expr), var_list)) /* non-local is being changed */
  50382. {
  50383. if ((direct_memq(cadr(expr), steppers)) || /* stepper is being set? */
  50384. (!is_pair(cddr(expr))) ||
  50385. (!is_pair(cdddr(expr))) ||
  50386. (is_pair(cddddr(expr))) ||
  50387. ((x == sc->hash_table_set_symbol) &&
  50388. (is_symbol(caddr(expr))) &&
  50389. (direct_memq(caddr(expr), steppers))) ||
  50390. ((is_symbol(cadddr(expr))) &&
  50391. (direct_memq(cadddr(expr), steppers))) ||
  50392. (is_pair(cadddr(expr))))
  50393. (*has_set) = true;
  50394. }
  50395. if (!do_is_safe(sc, cddr(expr), steppers, var_list, has_set))
  50396. return(false);
  50397. if (!safe_stepper(sc, expr, steppers))
  50398. return(false);
  50399. }
  50400. }
  50401. }
  50402. }
  50403. else
  50404. {
  50405. return(false);
  50406. /* car(expr) ("x") is not a symbol: ((mus-data loc) chan) for example
  50407. * but that's actually safe since it's just in effect vector-ref
  50408. * there are several examples in dlocsig: ((group-speakers group) i) etc
  50409. */
  50410. }
  50411. }
  50412. }
  50413. return(true);
  50414. }
  50415. static bool preserves_type(s7_scheme *sc, unsigned int x)
  50416. {
  50417. return((x == sc->add_class) ||
  50418. (x == sc->subtract_class) ||
  50419. (x == sc->multiply_class));
  50420. }
  50421. static s7_pointer check_do(s7_scheme *sc)
  50422. {
  50423. s7_pointer x;
  50424. /* fprintf(stderr, "check_do: %s\n", DISPLAY(sc->code)); */
  50425. if ((!is_pair(sc->code)) || /* (do . 1) */
  50426. ((!is_pair(car(sc->code))) && /* (do 123) */
  50427. (is_not_null(car(sc->code))))) /* (do () ...) is ok */
  50428. eval_error(sc, "do: var list is not a list: ~S", sc->code);
  50429. if (!is_pair(cdr(sc->code))) /* (do () . 1) */
  50430. eval_error(sc, "do body is messed up: ~A", sc->code);
  50431. if ((!is_pair(cadr(sc->code))) && /* (do ((i 0)) 123) */
  50432. (is_not_null(cadr(sc->code)))) /* no end-test? */
  50433. eval_error(sc, "do: end-test and end-value list is not a list: ~A", sc->code);
  50434. if (is_pair(car(sc->code)))
  50435. {
  50436. for (x = car(sc->code); is_pair(x); x = cdr(x))
  50437. {
  50438. if (!(is_pair(car(x)))) /* (do (4) (= 3)) */
  50439. eval_error(sc, "do: variable name missing? ~A", sc->code);
  50440. if (!is_symbol(caar(x))) /* (do ((3 2)) ()) */
  50441. eval_error(sc, "do step variable: ~S is not a symbol?", x);
  50442. if (is_immutable_symbol(caar(x))) /* (do ((pi 3 (+ pi 1))) ((= pi 4)) pi) */
  50443. eval_error(sc, "do step variable: ~S is immutable", x);
  50444. if (is_pair(cdar(x)))
  50445. {
  50446. if ((!is_pair(cddar(x))) &&
  50447. (is_not_null(cddar(x)))) /* (do ((i 0 . 1)) ...) */
  50448. eval_error(sc, "do: step variable info is an improper list?: ~A", sc->code);
  50449. if ((is_pair(cddar(x))) &&
  50450. (is_not_null(cdr(cddar(x))))) /* (do ((i 0 1 (+ i 1))) ...) */
  50451. eval_error(sc, "do: step variable info has extra stuff after the increment: ~A", sc->code);
  50452. }
  50453. else eval_error(sc, "do: step variable has no initial value: ~A", x);
  50454. set_local(caar(x));
  50455. /* (do ((i)) ...) */
  50456. }
  50457. if (is_not_null(x)) /* (do ((i 0 i) . 1) ((= i 1))) */
  50458. eval_error(sc, "do: list of variables is improper: ~A", sc->code);
  50459. }
  50460. if (is_pair(cadr(sc->code)))
  50461. {
  50462. for (x = cadr(sc->code); is_pair(x); x = cdr(x));
  50463. if (is_not_null(x))
  50464. eval_error(sc, "stray dot in do end section? ~A", sc->code);
  50465. }
  50466. for (x = cddr(sc->code); is_pair(x); x = cdr(x));
  50467. if (is_not_null(x))
  50468. eval_error(sc, "stray dot in do body? ~A", sc->code);
  50469. if ((is_overlaid(sc->code)) &&
  50470. (has_opt_back(sc->code)))
  50471. {
  50472. s7_pointer vars, end, body;
  50473. bool one_line;
  50474. vars = car(sc->code);
  50475. end = cadr(sc->code);
  50476. body = cddr(sc->code);
  50477. one_line = ((safe_list_length(sc, body) == 1) && (is_pair(car(body))));
  50478. pair_set_syntax_symbol(sc->code, sc->do_unchecked_symbol);
  50479. /* (define (hi) (do ((i 0 (+ i 1))) ((= i 3)) (display i)) (newline)) */
  50480. /* (define (hi) (do ((i 1.5 (+ i 1))) ((= i 2.5)) (display i) (newline)))
  50481. * in OP_SAFE_DOTIMES, for example, if init value is not an integer, it goes to OP_SIMPLE_DO
  50482. * remaining optimizable cases: we can step by 1 and use = for end, and yet simple_do(_p) calls the functions
  50483. * geq happens as often as =, and -1 as step
  50484. * also cdr as step to is_null as end
  50485. * also what about no do-var cases? (do () ...)
  50486. *
  50487. * also do body is optimized expr: vector_set_3 via hop_safe_c_sss for example or (vset v i (vref w i))
  50488. */
  50489. if ((is_pair(end)) && (is_pair(car(end))) &&
  50490. (is_pair(vars)) && (is_null(cdr(vars))) &&
  50491. (is_pair(body)))
  50492. {
  50493. /* loop has one step variable, and normal-looking end test
  50494. */
  50495. vars = car(vars);
  50496. if ((safe_list_length(sc, vars) == 3) &&
  50497. ((!is_pair(cadr(vars))) ||
  50498. (is_h_safe_c_c(cadr(vars)))))
  50499. {
  50500. s7_pointer step_expr;
  50501. step_expr = caddr(vars);
  50502. if ((is_optimized(step_expr)) &&
  50503. (((optimize_op(step_expr) == HOP_SAFE_C_SC) && (car(vars) == cadr(step_expr))) ||
  50504. ((optimize_op(step_expr) == HOP_SAFE_C_C) && (car(vars) == cadr(step_expr)) &&
  50505. ((opt_cfunc(step_expr) == add_cs1) || (opt_cfunc(step_expr) == subtract_cs1))) ||
  50506. ((optimize_op(step_expr) == HOP_SAFE_C_CS) && (car(vars) == caddr(step_expr)))))
  50507. {
  50508. /* step var is (var const|symbol (op var const)|(op const var))
  50509. */
  50510. end = car(end);
  50511. if ((is_optimized(end)) &&
  50512. (car(vars) == cadr(end)) &&
  50513. (cadr(end) != caddr(end)) &&
  50514. ((opt_any1(end) == equal_s_ic) ||
  50515. (optimize_op(end) == HOP_SAFE_C_SS) ||
  50516. (optimize_op(end) == HOP_SAFE_C_SC)))
  50517. {
  50518. /* end var is (op var const|symbol) using same var as step
  50519. * so at least we can use SIMPLE_DO
  50520. */
  50521. bool has_set = false;
  50522. if (opt_cfunc(step_expr) == add_cs1)
  50523. {
  50524. set_c_function(step_expr, add_s1);
  50525. set_optimize_op(step_expr, HOP_SAFE_C_SC);
  50526. }
  50527. if (opt_cfunc(step_expr) == subtract_cs1)
  50528. {
  50529. set_c_function(step_expr, subtract_s1);
  50530. set_optimize_op(step_expr, HOP_SAFE_C_SC);
  50531. }
  50532. if (opt_cfunc(end) == equal_s_ic)
  50533. {
  50534. set_c_function(end, equal_2);
  50535. set_optimize_op(end, HOP_SAFE_C_SC);
  50536. }
  50537. if ((opt_cfunc(step_expr) == add_s1) &&
  50538. (opt_cfunc(end) == equal_2) &&
  50539. (s7_is_integer(caddr(step_expr))) &&
  50540. (s7_integer(caddr(step_expr)) == 1))
  50541. {
  50542. pair_set_syntax_symbol(sc->code, sc->simple_do_a_symbol);
  50543. if ((one_line) &&
  50544. (is_optimized(car(body))))
  50545. pair_set_syntax_symbol(sc->code, sc->simple_do_e_symbol);
  50546. }
  50547. else pair_set_syntax_symbol(sc->code, sc->simple_do_symbol);
  50548. if ((one_line) &&
  50549. ((!is_optimized(car(body))) || (op_no_hop(car(body)) != OP_SAFE_C_C)) &&
  50550. (is_syntactic_symbol(caar(body))))
  50551. {
  50552. pair_set_syntax_op(car(body), symbol_syntax_op(caar(body)));
  50553. pair_set_syntax_symbol(sc->code, sc->simple_do_p_symbol);
  50554. set_opt_pair2(sc->code, caddr(caar(sc->code)));
  50555. if ((s7_is_integer(caddr(step_expr))) &&
  50556. (s7_integer(caddr(step_expr)) == 1) &&
  50557. (c_function_class(opt_cfunc(step_expr)) == sc->add_class) &&
  50558. /* we check above that (car(vars) == cadr(step_expr))
  50559. * and that (car(vars) == cadr(end))
  50560. */
  50561. ((c_function_class(opt_cfunc(end)) == sc->equal_class) ||
  50562. (opt_cfunc(end) == geq_2)))
  50563. pair_set_syntax_symbol(sc->code, sc->dotimes_p_symbol);
  50564. }
  50565. if (do_is_safe(sc, body, sc->w = list_1(sc, car(vars)), sc->nil, &has_set))
  50566. {
  50567. /* now look for the very common dotimes case
  50568. */
  50569. if ((((s7_is_integer(caddr(step_expr))) &&
  50570. (s7_integer(caddr(step_expr)) == 1)) ||
  50571. ((s7_is_integer(cadr(step_expr))) &&
  50572. (s7_integer(cadr(step_expr)) == 1))) &&
  50573. (c_function_class(opt_cfunc(step_expr)) == sc->add_class) &&
  50574. ((c_function_class(opt_cfunc(end)) == sc->equal_class) ||
  50575. (opt_cfunc(end) == geq_2))
  50576. )
  50577. {
  50578. /* we're stepping by +1 and going to =
  50579. * the final integer check has to wait until run time (symbol value dependent)
  50580. */
  50581. pair_set_syntax_symbol(sc->code, sc->safe_do_symbol);
  50582. if ((!has_set) &&
  50583. (c_function_class(opt_cfunc(end)) == sc->equal_class))
  50584. pair_set_syntax_symbol(sc->code, sc->safe_dotimes_symbol);
  50585. }
  50586. }
  50587. return(sc->nil);
  50588. }
  50589. }
  50590. }
  50591. }
  50592. /* we get here if there is more than one local var or anything "non-simple" about the rest
  50593. */
  50594. /* (define (hi) (do ((i 0 (+ i 1))) ((= i 3)) (display i)) (newline))
  50595. * (define (hi) (do ((i 0 (+ i 1)) (j 1 (+ j 1))) ((= i 3)) (display j))(newline))
  50596. */
  50597. vars = car(sc->code);
  50598. end = cadr(sc->code);
  50599. /* check end expression first */
  50600. if ((is_pair(car(end))) &&
  50601. (caar(end) != sc->quote_symbol) &&
  50602. (is_optimized(car(end))) &&
  50603. (is_all_x_safe(sc, car(end))))
  50604. set_c_call(cdr(sc->code), all_x_eval(sc, car(end), sc->envir, let_symbol_is_safe));
  50605. else return(sc->code);
  50606. /* vars can be nil (no steppers) */
  50607. if (is_pair(vars))
  50608. {
  50609. s7_pointer p;
  50610. for (p = vars; is_pair(p); p = cdr(p))
  50611. {
  50612. s7_pointer var;
  50613. var = car(p);
  50614. if ((!is_all_x_safe(sc, cadr(var))) ||
  50615. ((is_pair(cddr(var))) &&
  50616. (!is_all_x_safe(sc, caddr(var)))))
  50617. {
  50618. s7_pointer q;
  50619. for (q = vars; q != p; q = cdr(q))
  50620. clear_match_symbol(caar(q));
  50621. return(sc->code);
  50622. }
  50623. set_match_symbol(car(var));
  50624. }
  50625. /* we want to use the pending_value slot for other purposes, so make sure
  50626. * the current val is not referred to in any trailing step exprs. The inits
  50627. * are ok because at init-time, the new frame is not connected.
  50628. * another tricky case: current var might be used in previous step expr(!)
  50629. */
  50630. for (p = vars; is_pair(p); p = cdr(p))
  50631. {
  50632. s7_pointer var, val;
  50633. var = car(p);
  50634. val = cddr(var);
  50635. if (is_pair(val))
  50636. {
  50637. var = car(var);
  50638. clear_match_symbol(var); /* ignore current var */
  50639. if (tree_match(sc, car(val)))
  50640. {
  50641. s7_pointer q;
  50642. for (q = vars; is_pair(q); q = cdr(q))
  50643. clear_match_symbol(caar(q));
  50644. return(sc->code);
  50645. }
  50646. set_match_symbol(var);
  50647. }
  50648. }
  50649. for (p = vars; is_pair(p); p = cdr(p))
  50650. clear_match_symbol(caar(p));
  50651. }
  50652. /* end and steps look ok! */
  50653. pair_set_syntax_symbol(sc->code, sc->dox_symbol);
  50654. set_opt_pair2(sc->code, car(end)); /* end expr */
  50655. /* each step expr is safe so not an explicit set!
  50656. * the symbol_is_safe check in all_x_eval needs to see the do envir, not the caller's
  50657. * but that means the is_all_x_safe check above also needs to use the local env?
  50658. */
  50659. if (is_pair(vars))
  50660. {
  50661. s7_pointer p;
  50662. for (p = vars; is_pair(p); p = cdr(p))
  50663. {
  50664. s7_pointer var;
  50665. var = car(p);
  50666. if (is_pair(cdr(var)))
  50667. set_c_call(cdr(var), all_x_eval(sc, cadr(var), sc->envir, let_symbol_is_safe)); /* init val */
  50668. if (is_pair(cddr(var)))
  50669. {
  50670. s7_pointer step_expr;
  50671. step_expr = caddr(var);
  50672. set_c_call(cddr(var), all_x_eval(sc, step_expr, vars, do_symbol_is_safe)); /* sets opt2(cddr(var)), not opt1 */
  50673. if ((is_pair(step_expr)) &&
  50674. (car(step_expr) != sc->quote_symbol) && /* opt_cfunc(==opt1) might not be set in this case (sigh) */
  50675. (preserves_type(sc, c_function_class(opt_cfunc(step_expr)))))
  50676. set_safe_stepper(cddr(var));
  50677. }
  50678. }
  50679. }
  50680. /* there are only a couple of cases in snd-test where a multi-statement do body is completely all-x-able */
  50681. return(sc->nil);
  50682. }
  50683. return(sc->code);
  50684. }
  50685. static bool dox_pf_ok(s7_scheme *sc, s7_pointer code, s7_pointer scc, s7_function endf, bool all_pairs)
  50686. {
  50687. s7_pointer p, endp;
  50688. int body_len, i;
  50689. s7_pf_t pf;
  50690. endp = caadr(scc);
  50691. body_len = s7_list_length(sc, code);
  50692. s7_xf_new(sc, sc->envir);
  50693. for (i = 0, p = code; is_pair(p); i++, p = cdr(p))
  50694. if ((!is_symbol(caar(p))) ||
  50695. (!xf_opt(sc, car(p))))
  50696. break;
  50697. if ((is_null(p)) &&
  50698. (pf = xf_opt(sc, endp)))
  50699. {
  50700. s7_pointer slots;
  50701. s7_pointer *top;
  50702. slots = let_slots(sc->envir);
  50703. top = sc->cur_rf->data;
  50704. if ((all_pairs) && (body_len == 1))
  50705. {
  50706. s7_rf_t rf;
  50707. rf = (s7_rf_t)(*top);
  50708. top++;
  50709. while (true)
  50710. {
  50711. s7_pointer slot;
  50712. s7_pointer *temp;
  50713. s7_pointer **rp;
  50714. temp = top;
  50715. rp = &temp;
  50716. rf(sc, rp);
  50717. for (slot = slots; is_slot(slot); slot = next_slot(slot))
  50718. if (is_pair(slot_expression(slot)))
  50719. slot_set_pending_value(slot, c_call(slot_expression(slot))(sc, car(slot_expression(slot))));
  50720. for (slot = slots; is_slot(slot); slot = next_slot(slot))
  50721. if (is_pair(slot_expression(slot)))
  50722. slot_set_value(slot, slot_pending_value(slot));
  50723. (*rp)++;
  50724. if (is_true(sc, pf(sc, rp)))
  50725. {
  50726. s7_xf_free(sc);
  50727. sc->code = cdadr(scc);
  50728. return(true);
  50729. }
  50730. }
  50731. }
  50732. else
  50733. {
  50734. while (true)
  50735. {
  50736. s7_pointer slot;
  50737. s7_pointer *temp;
  50738. s7_pointer **rp;
  50739. temp = top;
  50740. rp = &temp;
  50741. for (i = 0; i < body_len; i++)
  50742. {
  50743. s7_rf_t rf;
  50744. rf = (s7_rf_t)(**rp); (*rp)++;
  50745. rf(sc, rp);
  50746. }
  50747. for (slot = slots; is_slot(slot); slot = next_slot(slot))
  50748. if (is_pair(slot_expression(slot)))
  50749. slot_set_pending_value(slot, c_call(slot_expression(slot))(sc, car(slot_expression(slot))));
  50750. for (slot = slots; is_slot(slot); slot = next_slot(slot))
  50751. if (is_pair(slot_expression(slot)))
  50752. slot_set_value(slot, slot_pending_value(slot));
  50753. (*rp)++;
  50754. if (is_true(sc, pf(sc, rp)))
  50755. {
  50756. s7_xf_free(sc);
  50757. sc->code = cdadr(scc);
  50758. return(true);
  50759. }
  50760. }
  50761. }
  50762. }
  50763. s7_xf_free(sc);
  50764. return(false);
  50765. }
  50766. static int dox_ex(s7_scheme *sc)
  50767. {
  50768. /* any number of steppers using dox exprs, end also dox, body and end result arbitrary.
  50769. * since all these exprs are local, we don't need to jump until the body
  50770. */
  50771. long long int id;
  50772. s7_pointer frame, vars, slot, code;
  50773. s7_function endf;
  50774. int gc_loc;
  50775. bool all_pairs = true;
  50776. new_frame(sc, sc->envir, frame); /* new frame is not tied into the symbol lookup process yet */
  50777. gc_loc = s7_gc_protect(sc, frame); /* maybe use temp3 here? can c_call below jump out? */
  50778. for (vars = car(sc->code); is_pair(vars); vars = cdr(vars))
  50779. {
  50780. s7_pointer expr, val;
  50781. expr = cadar(vars);
  50782. if (is_pair(expr))
  50783. {
  50784. if (car(expr) == sc->quote_symbol)
  50785. val = cadr(expr);
  50786. else val = c_call(cdar(vars))(sc, expr);
  50787. }
  50788. else
  50789. {
  50790. if (is_symbol(expr))
  50791. val = find_symbol_checked(sc, expr);
  50792. else val = expr;
  50793. }
  50794. new_cell_no_check(sc, slot, T_SLOT);
  50795. slot_set_symbol(slot, caar(vars));
  50796. slot_set_value(slot, val);
  50797. set_stepper(slot);
  50798. slot_set_expression(slot, cddar(vars));
  50799. if (is_pair(slot_expression(slot)))
  50800. {
  50801. if (is_safe_stepper(slot_expression(slot)))
  50802. {
  50803. s7_pointer step_expr;
  50804. step_expr = car(slot_expression(slot));
  50805. if ((is_pair(cddr(step_expr))) &&
  50806. (type(val) == type(caddr(step_expr))))
  50807. set_safe_stepper(slot);
  50808. }
  50809. }
  50810. else all_pairs = false;
  50811. set_next_slot(slot, let_slots(frame));
  50812. let_set_slots(frame, slot);
  50813. }
  50814. sc->envir = frame;
  50815. s7_gc_unprotect_at(sc, gc_loc);
  50816. id = let_id(frame);
  50817. for (slot = let_slots(frame); is_slot(slot); slot = next_slot(slot))
  50818. symbol_set_local(slot_symbol(slot), id, slot);
  50819. if (is_true(sc, c_call(cdr(sc->code))(sc, opt_pair2(sc->code))))
  50820. {
  50821. /* if no end result exprs, we return nil, but others probably #<unspecified>
  50822. * (let ((x (do ((i 0 (+ i 1))) (#t)))) x) -> ()
  50823. */
  50824. sc->code = cdadr(sc->code);
  50825. return(goto_DO_END_CLAUSES);
  50826. }
  50827. code = cddr(sc->code);
  50828. endf = c_callee(cdr(sc->code));
  50829. if (is_null(code)) /* no body? */
  50830. {
  50831. s7_pointer endp, slots, scc;
  50832. scc = sc->code;
  50833. endp = opt_pair2(sc->code);
  50834. if (endf == all_x_c_c)
  50835. {
  50836. endf = c_callee(endp);
  50837. endp = cdr(endp);
  50838. }
  50839. slots = let_slots(sc->envir);
  50840. if (!is_slot(slots))
  50841. {
  50842. while (!is_true(sc, endf(sc, endp)));
  50843. sc->code = cdadr(scc);
  50844. return(goto_DO_END_CLAUSES);
  50845. }
  50846. if ((is_null(next_slot(slots))) && (is_pair(slot_expression(slots))))
  50847. {
  50848. s7_function f;
  50849. s7_pointer a;
  50850. f = c_callee(slot_expression(slots));
  50851. a = car(slot_expression(slots));
  50852. if (f == all_x_c_c)
  50853. {
  50854. f = c_callee(a);
  50855. a = cdr(a);
  50856. }
  50857. while (true) /* thash titer */
  50858. {
  50859. slot_set_value(slots, f(sc, a));
  50860. if (is_true(sc, endf(sc, endp)))
  50861. {
  50862. sc->code = cdadr(scc);
  50863. return(goto_DO_END_CLAUSES);
  50864. }
  50865. }
  50866. }
  50867. else
  50868. {
  50869. while (true)
  50870. {
  50871. s7_pointer slt;
  50872. for (slt = slots; is_slot(slt); slt = next_slot(slt))
  50873. if (is_pair(slot_expression(slt)))
  50874. slot_set_value(slt, c_call(slot_expression(slt))(sc, car(slot_expression(slt))));
  50875. if (is_true(sc, endf(sc, endp)))
  50876. {
  50877. sc->code = cdadr(scc);
  50878. return(goto_DO_END_CLAUSES);
  50879. }
  50880. }
  50881. }
  50882. }
  50883. if ((!is_unsafe_do(sc->code)) &&
  50884. (dox_pf_ok(sc, code, sc->code, endf, all_pairs)))
  50885. return(goto_DO_END_CLAUSES);
  50886. /* fprintf(stderr, "dox: %s\n", DISPLAY(code)); */
  50887. set_unsafe_do(sc->code);
  50888. if ((is_null(cdr(code))) && /* one expr */
  50889. (is_pair(car(code))))
  50890. {
  50891. code = car(code);
  50892. if ((typesflag(code) == SYNTACTIC_PAIR) ||
  50893. (typesflag(car(code)) == SYNTACTIC_TYPE))
  50894. {
  50895. push_stack_no_args(sc, OP_DOX_STEP_P, sc->code);
  50896. if (typesflag(code) == SYNTACTIC_PAIR)
  50897. sc->op = (opcode_t)pair_syntax_op(code);
  50898. else
  50899. {
  50900. sc->op = (opcode_t)symbol_syntax_op(car(code));
  50901. pair_set_syntax_op(code, sc->op);
  50902. set_syntactic_pair(code);
  50903. }
  50904. sc->code = cdr(code);
  50905. return(goto_START_WITHOUT_POP_STACK);
  50906. }
  50907. }
  50908. return(fall_through);
  50909. }
  50910. static int simple_do_ex(s7_scheme *sc, s7_pointer code)
  50911. {
  50912. s7_pointer body, step_expr, step_var, ctr, end;
  50913. s7_function stepf, endf;
  50914. s7_pf_t rf;
  50915. /* fprintf(stderr, "%s: %s\n", __func__, DISPLAY(sc->code)); */
  50916. body = car(opt_pair2(code));
  50917. if (!is_symbol(car(body)))
  50918. return(fall_through);
  50919. step_expr = caddr(caar(code));
  50920. stepf = c_callee(step_expr);
  50921. endf = c_callee(caadr(code));
  50922. ctr = dox_slot1(sc->envir);
  50923. end = dox_slot2(sc->envir);
  50924. step_var = caddr(step_expr);
  50925. #if (!WITH_GMP)
  50926. set_stepper(ctr);
  50927. if (((stepf == g_subtract_s1) && (endf == g_less_s0)) ||
  50928. ((stepf == g_add_s1) && (endf == g_equal_2))) /* add_s1 means (+ sym 1) */
  50929. set_safe_stepper(ctr);
  50930. #endif
  50931. s7_xf_new(sc, sc->envir);
  50932. rf = xf_opt(sc, body);
  50933. if (rf)
  50934. {
  50935. s7_pointer *top;
  50936. /* fprintf(stderr, "ex: %s\n", DISPLAY(code)); */
  50937. top = sc->cur_rf->data;
  50938. top++;
  50939. #if (!WITH_GMP)
  50940. if ((stepf == g_add_s1) && (endf == g_equal_2))
  50941. {
  50942. while (true)
  50943. {
  50944. s7_pointer *temp;
  50945. temp = top;
  50946. rf(sc, &temp);
  50947. slot_set_value(ctr, c_add_s1(sc, slot_value(ctr)));
  50948. if (is_true(sc, c_equal_2(sc, slot_value(ctr), slot_value(end))))
  50949. {
  50950. s7_xf_free(sc);
  50951. sc->code = cdr(cadr(code));
  50952. return(goto_DO_END_CLAUSES);
  50953. }
  50954. }
  50955. }
  50956. #endif
  50957. while (true)
  50958. {
  50959. s7_pointer *temp;
  50960. temp = top;
  50961. rf(sc, &temp);
  50962. set_car(sc->t2_1, slot_value(ctr));
  50963. set_car(sc->t2_2, step_var);
  50964. slot_set_value(ctr, stepf(sc, sc->t2_1));
  50965. set_car(sc->t2_1, slot_value(ctr));
  50966. set_car(sc->t2_2, slot_value(end));
  50967. if (is_true(sc, endf(sc, sc->t2_1)))
  50968. {
  50969. s7_xf_free(sc);
  50970. sc->code = cdr(cadr(code));
  50971. return(goto_DO_END_CLAUSES);
  50972. }
  50973. }
  50974. }
  50975. s7_xf_free(sc);
  50976. return(fall_through);
  50977. }
  50978. static bool pf_ok(s7_scheme *sc, s7_pointer code, s7_pointer scc, bool safe_step)
  50979. {
  50980. s7_pointer p;
  50981. int body_len, i;
  50982. if (safe_step)
  50983. set_safe_stepper(sc->args);
  50984. else set_safe_stepper(dox_slot1(sc->envir));
  50985. body_len = s7_list_length(sc, code);
  50986. s7_xf_new(sc, sc->envir);
  50987. for (i = 0, p = code; is_pair(p); i++, p = cdr(p))
  50988. if (!xf_opt(sc, car(p)))
  50989. break;
  50990. if (is_null(p))
  50991. {
  50992. s7_pointer stepper;
  50993. s7_pointer *top;
  50994. s7_int end;
  50995. stepper = slot_value(sc->args);
  50996. end = denominator(stepper);
  50997. top = sc->cur_rf->data;
  50998. if (safe_step)
  50999. {
  51000. if (body_len == 1)
  51001. {
  51002. s7_int end4;
  51003. s7_rf_t rf;
  51004. rf = (s7_rf_t)(*top);
  51005. top++;
  51006. end4 = end - 4;
  51007. for (; numerator(stepper) < end4; numerator(stepper)++)
  51008. {
  51009. s7_pointer *rp;
  51010. rp = top;
  51011. rf(sc, &rp);
  51012. numerator(stepper)++;
  51013. rp = top;
  51014. rf(sc, &rp);
  51015. numerator(stepper)++;
  51016. rp = top;
  51017. rf(sc, &rp);
  51018. numerator(stepper)++;
  51019. rp = top;
  51020. rf(sc, &rp);
  51021. }
  51022. for (; numerator(stepper) < end; numerator(stepper)++)
  51023. {
  51024. s7_pointer *rp;
  51025. rp = top;
  51026. rf(sc, &rp);
  51027. }
  51028. }
  51029. else
  51030. {
  51031. for (; numerator(stepper) < end; numerator(stepper)++)
  51032. {
  51033. s7_pointer *temp;
  51034. s7_pointer **rp;
  51035. temp = top;
  51036. rp = &temp;
  51037. for (i = 0; i < body_len; i++)
  51038. {
  51039. s7_rf_t rf;
  51040. rf = (s7_rf_t)(**rp); (*rp)++;
  51041. rf(sc, rp);
  51042. }
  51043. }
  51044. }
  51045. }
  51046. else
  51047. {
  51048. /* can't re-use the stepper value directly */
  51049. s7_pointer step_slot, end_slot;
  51050. s7_int step;
  51051. step_slot = dox_slot1(sc->envir);
  51052. end_slot = dox_slot2(sc->envir);
  51053. if (body_len == 1)
  51054. {
  51055. s7_rf_t rf;
  51056. rf = (s7_rf_t)(*top);
  51057. top++;
  51058. while (true)
  51059. {
  51060. s7_pointer *rp;
  51061. rp = top;
  51062. rf(sc, &rp);
  51063. step = s7_integer(slot_value(step_slot)) + 1;
  51064. slot_set_value(step_slot, make_integer(sc, step));
  51065. if (step == s7_integer(slot_value(end_slot))) break;
  51066. }
  51067. }
  51068. else
  51069. {
  51070. while (true)
  51071. {
  51072. s7_pointer *temp;
  51073. s7_pointer **rp;
  51074. temp = top;
  51075. rp = &temp;
  51076. for (i = 0; i < body_len; i++)
  51077. {
  51078. s7_rf_t rf;
  51079. rf = (s7_rf_t)(**rp); (*rp)++;
  51080. rf(sc, rp);
  51081. }
  51082. step = s7_integer(slot_value(step_slot)) + 1;
  51083. slot_set_value(step_slot, make_integer(sc, step));
  51084. if (step == s7_integer(slot_value(end_slot))) break;
  51085. }
  51086. }
  51087. }
  51088. s7_xf_free(sc);
  51089. sc->code = cdadr(scc);
  51090. return(true);
  51091. }
  51092. s7_xf_free(sc);
  51093. return(false);
  51094. }
  51095. static int let_pf_ok(s7_scheme *sc, s7_pointer step_slot, s7_pointer scc, bool safe_case)
  51096. {
  51097. s7_pointer let_body, p = NULL, let_vars, let_code;
  51098. bool let_star;
  51099. int body_len;
  51100. s7_rf_t varf = NULL;
  51101. s7_pointer old_e, stepper;
  51102. int var_len;
  51103. /* fprintf(stderr, "%lld %lld %s %d\n", numerator(step_slot), denominator(step_slot), DISPLAY(scc), safe_case); */
  51104. let_code = caddr(scc);
  51105. let_body = cddr(let_code);
  51106. body_len = s7_list_length(sc, let_body);
  51107. let_star = (symbol_syntax_op(car(let_code)) == OP_LET_STAR);
  51108. let_vars = cadr(let_code);
  51109. set_safe_stepper(step_slot);
  51110. stepper = slot_value(step_slot);
  51111. old_e = sc->envir;
  51112. sc->envir = new_frame_in_env(sc, sc->envir);
  51113. s7_xf_new(sc, old_e);
  51114. for (var_len = 0, p = let_vars; (is_pair(p)) && (is_pair(cadar(p))); var_len++, p = cdr(p))
  51115. {
  51116. s7_int var_loc;
  51117. s7_pointer expr, fcar, car_ex;
  51118. s7_rp_t varp;
  51119. var_loc = s7_xf_store(sc, NULL);
  51120. expr = cadar(p);
  51121. car_ex = car(expr);
  51122. /* fcar = find_symbol_checked(sc, car(expr)); */
  51123. if (!is_symbol(car_ex)) break;
  51124. fcar = find_symbol(sc, car_ex);
  51125. if (!is_slot(fcar)) break;
  51126. fcar = slot_value(fcar);
  51127. varp = rf_function(fcar);
  51128. if (!varp) break;
  51129. varf = varp(sc, expr);
  51130. if (!varf) break;
  51131. s7_xf_store_at(sc, var_loc, (s7_pointer)varf);
  51132. if (let_star)
  51133. make_slot_1(sc, sc->envir, caar(p), s7_make_mutable_real(sc, 1.5));
  51134. }
  51135. if (is_null(p))
  51136. {
  51137. int i;
  51138. s7_pf_t bodyf = NULL;
  51139. if (!let_star)
  51140. for (p = let_vars; is_pair(p); p = cdr(p))
  51141. make_slot_1(sc, sc->envir, caar(p), s7_make_mutable_real(sc, 1.5));
  51142. for (i = 0, p = let_body; is_pair(p); i++, p = cdr(p))
  51143. {
  51144. bodyf = xf_opt(sc, car(p));
  51145. if (!bodyf) break;
  51146. }
  51147. if (is_null(p))
  51148. {
  51149. s7_pointer *top;
  51150. s7_int end;
  51151. if (safe_case)
  51152. {
  51153. end = denominator(stepper);
  51154. top = sc->cur_rf->data;
  51155. if ((var_len == 1) && (body_len == 1)) /* very common special case */
  51156. {
  51157. s7_pointer rl;
  51158. s7_int end3;
  51159. s7_pointer **rp;
  51160. s7_pointer *temp;
  51161. end3 = end - 3;
  51162. rl = slot_value(let_slots(sc->envir));
  51163. top++;
  51164. for (; numerator(stepper) < end3; numerator(stepper)++)
  51165. {
  51166. temp = top;
  51167. rp = &temp;
  51168. set_real(rl, varf(sc, rp));
  51169. (*rp)++;
  51170. bodyf(sc, rp);
  51171. numerator(stepper)++;
  51172. temp = top;
  51173. rp = &temp;
  51174. set_real(rl, varf(sc, rp));
  51175. (*rp)++;
  51176. bodyf(sc, rp);
  51177. numerator(stepper)++;
  51178. temp = top;
  51179. rp = &temp;
  51180. set_real(rl, varf(sc, rp));
  51181. (*rp)++;
  51182. bodyf(sc, rp);
  51183. }
  51184. for (; numerator(stepper) < end; numerator(stepper)++)
  51185. {
  51186. temp = top;
  51187. rp = &temp;
  51188. set_real(rl, varf(sc, rp));
  51189. (*rp)++;
  51190. bodyf(sc, rp);
  51191. }
  51192. }
  51193. else
  51194. {
  51195. let_set_slots(sc->envir, reverse_slots(sc, let_slots(sc->envir)));
  51196. for (; numerator(stepper) < end; numerator(stepper)++)
  51197. {
  51198. s7_pointer **rp;
  51199. s7_pointer *temp;
  51200. temp = top;
  51201. rp = &temp;
  51202. for (p = let_slots(sc->envir); is_slot(p); p = next_slot(p))
  51203. {
  51204. s7_rf_t r1;
  51205. r1 = (s7_rf_t)(**rp); (*rp)++;
  51206. set_real(slot_value(p), r1(sc, rp));
  51207. }
  51208. for (i = 0; i < body_len; i++)
  51209. {
  51210. s7_pf_t pf;
  51211. pf = (s7_pf_t)(**rp); (*rp)++;
  51212. pf(sc, rp);
  51213. }
  51214. }
  51215. }
  51216. }
  51217. else
  51218. {
  51219. end = denominator(stepper);
  51220. top = sc->cur_rf->data;
  51221. if ((var_len == 1) && (body_len == 1)) /* very common special case */
  51222. {
  51223. s7_pointer rl;
  51224. s7_int k;
  51225. rl = slot_value(let_slots(sc->envir));
  51226. top++;
  51227. for (k = numerator(stepper); k < end; k++)
  51228. {
  51229. s7_pointer **rp;
  51230. s7_pointer *temp;
  51231. slot_set_value(step_slot, make_integer(sc, k));
  51232. temp = top;
  51233. rp = &temp;
  51234. set_real(rl, varf(sc, rp));
  51235. (*rp)++;
  51236. bodyf(sc, rp);
  51237. }
  51238. }
  51239. else
  51240. {
  51241. s7_int k;
  51242. let_set_slots(sc->envir, reverse_slots(sc, let_slots(sc->envir)));
  51243. for (k = numerator(stepper); k < end; k++)
  51244. {
  51245. s7_pointer **rp;
  51246. s7_pointer *temp;
  51247. slot_set_value(step_slot, make_integer(sc, k));
  51248. temp = top;
  51249. rp = &temp;
  51250. for (p = let_slots(sc->envir); is_slot(p); p = next_slot(p))
  51251. {
  51252. s7_rf_t r1;
  51253. r1 = (s7_rf_t)(**rp); (*rp)++;
  51254. set_real(slot_value(p), r1(sc, rp));
  51255. }
  51256. for (i = 0; i < body_len; i++)
  51257. {
  51258. s7_pf_t pf;
  51259. pf = (s7_pf_t)(**rp); (*rp)++;
  51260. pf(sc, rp);
  51261. }
  51262. }
  51263. }
  51264. }
  51265. s7_xf_free(sc);
  51266. sc->code = cdr(cadr(scc));
  51267. return(goto_SAFE_DO_END_CLAUSES);
  51268. }
  51269. }
  51270. sc->envir = old_e;
  51271. s7_xf_free(sc);
  51272. return(fall_through);
  51273. }
  51274. static int safe_dotimes_ex(s7_scheme *sc)
  51275. {
  51276. s7_pointer init_val;
  51277. /* fprintf(stderr, "%s: %s\n", __func__, DISPLAY(sc->code)); */
  51278. init_val = cadr(caar(sc->code));
  51279. if (is_symbol(init_val))
  51280. init_val = find_symbol_checked(sc, init_val);
  51281. else
  51282. {
  51283. if (is_pair(init_val))
  51284. init_val = c_call(init_val)(sc, cdr(init_val));
  51285. }
  51286. if (s7_is_integer(init_val))
  51287. {
  51288. s7_pointer end_expr, end_val, code;
  51289. code = sc->code;
  51290. end_expr = caadr(code);
  51291. end_val = caddr(end_expr);
  51292. if (is_symbol(end_val))
  51293. end_val = find_symbol_checked(sc, end_val);
  51294. if (s7_is_integer(end_val))
  51295. {
  51296. sc->code = cddr(code);
  51297. sc->envir = new_frame_in_env(sc, sc->envir);
  51298. sc->args = make_slot_1(sc, sc->envir, caaar(code), make_mutable_integer(sc, s7_integer(init_val)));
  51299. denominator(slot_value(sc->args)) = s7_integer(end_val);
  51300. set_stepper(sc->args);
  51301. /* (define (hi) (do ((i 1 (+ 1 i))) ((= i 1) i))) -- we need the frame even if the loop is not evaluated */
  51302. if ((is_null(sc->code)) ||
  51303. ((!is_pair(car(sc->code))) &&
  51304. (is_null(cdr(sc->code)))))
  51305. {
  51306. numerator(slot_value(sc->args)) = s7_integer(end_val);
  51307. sc->code = cdr(cadr(code));
  51308. return(goto_SAFE_DO_END_CLAUSES);
  51309. }
  51310. if (s7_integer(init_val) == s7_integer(end_val))
  51311. {
  51312. sc->code = cdr(cadr(code));
  51313. return(goto_SAFE_DO_END_CLAUSES);
  51314. }
  51315. if ((is_null(cdr(sc->code))) &&
  51316. (is_pair(car(sc->code))))
  51317. {
  51318. sc->code = car(sc->code);
  51319. set_opt_pair2(code, sc->code); /* is_pair above */
  51320. if ((typesflag(sc->code) == SYNTACTIC_PAIR) ||
  51321. (typesflag(car(sc->code)) == SYNTACTIC_TYPE))
  51322. {
  51323. if (!is_unsafe_do(code))
  51324. {
  51325. if ((symbol_syntax_op(car(sc->code)) == OP_LET) ||
  51326. (symbol_syntax_op(car(sc->code)) == OP_LET_STAR))
  51327. {
  51328. if (let_pf_ok(sc, sc->args, code, true) == goto_SAFE_DO_END_CLAUSES)
  51329. return(goto_SAFE_DO_END_CLAUSES);
  51330. }
  51331. else
  51332. {
  51333. if (pf_ok(sc, cddr(code), code, true))
  51334. return(goto_SAFE_DO_END_CLAUSES);
  51335. }
  51336. set_unsafe_do(code);
  51337. }
  51338. push_stack(sc, OP_SAFE_DOTIMES_STEP_P, sc->args, code);
  51339. if (typesflag(sc->code) == SYNTACTIC_PAIR)
  51340. sc->op = (opcode_t)pair_syntax_op(sc->code);
  51341. else
  51342. {
  51343. sc->op = (opcode_t)symbol_syntax_op(car(sc->code));
  51344. pair_set_syntax_op(sc->code, sc->op);
  51345. set_syntactic_pair(sc->code);
  51346. }
  51347. sc->code = cdr(sc->code);
  51348. return(goto_START_WITHOUT_POP_STACK);
  51349. }
  51350. else /* car not syntactic? */
  51351. {
  51352. if ((!is_unsafe_do(code)) &&
  51353. (pf_ok(sc, cddr(code), code, true)))
  51354. return(goto_SAFE_DO_END_CLAUSES);
  51355. set_unsafe_do(code);
  51356. #if DEBUGGING
  51357. if (!is_optimized(sc->code)) fprintf(stderr, "%s[%d]: not opt: %s\n", __func__, __LINE__, DISPLAY(sc->code));
  51358. #endif
  51359. if (is_optimized(sc->code)) /* think this is not needed -- can we get here otherwise? */
  51360. {
  51361. push_stack(sc, OP_SAFE_DOTIMES_STEP_O, sc->args, code);
  51362. return(goto_OPT_EVAL);
  51363. }
  51364. }
  51365. /* impossible? but make sure in any case we're set up for begin */
  51366. sc->code = cddr(code);
  51367. }
  51368. /* multi-line body */
  51369. if ((!is_unsafe_do(code)) &&
  51370. (pf_ok(sc, sc->code, code, true)))
  51371. return(goto_SAFE_DO_END_CLAUSES);
  51372. set_unsafe_do(code);
  51373. set_opt_pair2(code, sc->code);
  51374. push_stack(sc, OP_SAFE_DOTIMES_STEP, sc->args, code);
  51375. return(goto_BEGIN1);
  51376. }
  51377. }
  51378. return(fall_through);
  51379. }
  51380. static int safe_do_ex(s7_scheme *sc)
  51381. {
  51382. /* body is safe, step = +1, end is =, but stepper and end might be set (or at least indirectly exported) in the body:
  51383. * (let ((lst ())) (do ((i 0 (+ i 1))) ((= i 10)) (let ((j (min i 100))) (set! lst (cons j lst)))) lst)
  51384. * however, we're very restrictive about this in check_do and do_is_safe; even this is considered trouble:
  51385. * (let ((x 0)) (do ((i i (+ i 1))) ((= i 7)) (set! x (+ x i))) x)
  51386. * but end might not be an integer -- need to catch this earlier.
  51387. */
  51388. s7_pointer end, init_val, end_val, code;
  51389. /* fprintf(stderr, "%s: %s\n", __func__, DISPLAY(sc->code)); */
  51390. code = sc->code;
  51391. init_val = cadaar(code);
  51392. if (is_symbol(init_val))
  51393. init_val = find_symbol_checked(sc, init_val);
  51394. else
  51395. {
  51396. if (is_pair(init_val))
  51397. init_val = c_call(init_val)(sc, cdr(init_val));
  51398. }
  51399. end = caddr(car(cadr(code)));
  51400. if (is_symbol(end))
  51401. end_val = find_symbol_checked(sc, end);
  51402. else end_val = end;
  51403. if ((!s7_is_integer(init_val)) || (!s7_is_integer(end_val)))
  51404. {
  51405. pair_set_syntax_symbol(sc->code, sc->do_unchecked_symbol);
  51406. return(goto_DO_UNCHECKED);
  51407. }
  51408. /* (let ((sum 0)) (define (hi) (do ((i 10 (+ i 1))) ((= i 10) i) (set! sum (+ sum i)))) (hi)) */
  51409. sc->envir = new_frame_in_env(sc, sc->envir);
  51410. dox_set_slot1(sc->envir, make_slot_1(sc, sc->envir, caaar(code), init_val)); /* define the step var -- might be needed in the end clauses */
  51411. if ((s7_integer(init_val) == s7_integer(end_val)) ||
  51412. ((s7_integer(init_val) > s7_integer(end_val)) &&
  51413. (opt_cfunc(car(cadr(code))) == geq_2)))
  51414. {
  51415. sc->code = cdr(cadr(code));
  51416. return(goto_SAFE_DO_END_CLAUSES);
  51417. }
  51418. if (is_symbol(end))
  51419. sc->args = find_symbol(sc, end);
  51420. else sc->args = make_slot(sc, sc->dox_slot_symbol, end); /* here and elsewhere sc->args is used for GC protection */
  51421. dox_set_slot2(sc->envir, sc->args);
  51422. if ((!is_unsafe_do(sc->code)) &&
  51423. ((!is_optimized(caadr(code))) ||
  51424. (opt_cfunc(caadr(code)) != geq_2)))
  51425. {
  51426. set_stepper(dox_slot1(sc->envir));
  51427. if (pf_ok(sc, cddr(sc->code), sc->code, false))
  51428. return(goto_SAFE_DO_END_CLAUSES);
  51429. set_unsafe_do(sc->code);
  51430. }
  51431. sc->code = cddr(code);
  51432. if (is_unsafe_do(sc->code)) /* we've seen this loop before and it's not optimizable */
  51433. {
  51434. set_opt_pair2(code, sc->code);
  51435. push_stack(sc, OP_SAFE_DO_STEP, sc->args, code);
  51436. return(goto_BEGIN1);
  51437. }
  51438. set_unsafe_do(sc->code);
  51439. set_opt_pair2(code, sc->code);
  51440. push_stack(sc, OP_SAFE_DO_STEP, sc->args, code);
  51441. return(goto_BEGIN1);
  51442. }
  51443. static int dotimes_p_ex(s7_scheme *sc)
  51444. {
  51445. s7_pointer init, end, code, init_val, end_val;
  51446. /* (do ... (set! args ...)) -- one line, syntactic */
  51447. /* if (!is_unsafe_do(sc->code)) fprintf(stderr, "%s: %s\n", __func__, DISPLAY(sc->code)); */
  51448. code = sc->code;
  51449. init = cadaar(code);
  51450. if (is_symbol(init))
  51451. init_val = find_symbol_checked(sc, init);
  51452. else
  51453. {
  51454. if (is_pair(init))
  51455. init_val = c_call(init)(sc, cdr(init));
  51456. else init_val = init;
  51457. }
  51458. sc->value = init_val;
  51459. set_opt_pair2(code, caadr(code));
  51460. end = caddr(opt_pair2(code));
  51461. if (is_symbol(end))
  51462. sc->args = find_symbol(sc, end);
  51463. else sc->args = make_slot(sc, sc->dox_slot_symbol, end);
  51464. end_val = slot_value(sc->args);
  51465. if ((!s7_is_integer(init_val)) || (!s7_is_integer(end_val)))
  51466. {
  51467. pair_set_syntax_symbol(sc->code, sc->do_unchecked_symbol);
  51468. return(goto_DO_UNCHECKED);
  51469. }
  51470. sc->envir = new_frame_in_env(sc, sc->envir);
  51471. dox_set_slot1(sc->envir, make_slot_1(sc, sc->envir, caaar(code), init_val));
  51472. dox_set_slot2(sc->envir, sc->args);
  51473. set_car(sc->t2_1, slot_value(dox_slot1(sc->envir)));
  51474. set_car(sc->t2_2, slot_value(dox_slot2(sc->envir)));
  51475. if (is_true(sc, c_call(caadr(code))(sc, sc->t2_1)))
  51476. {
  51477. sc->code = cdadr(code);
  51478. return(goto_DO_END_CLAUSES);
  51479. }
  51480. if ((!is_unsafe_do(code)) &&
  51481. (opt_cfunc(caadr(code)) != geq_2))
  51482. {
  51483. s7_pointer old_args, old_init, body;
  51484. body = caddr(code);
  51485. old_args = sc->args;
  51486. old_init = slot_value(dox_slot1(sc->envir));
  51487. sc->args = dox_slot1(sc->envir);
  51488. slot_set_value(sc->args, make_mutable_integer(sc, integer(slot_value(dox_slot1(sc->envir)))));
  51489. denominator(slot_value(sc->args)) = integer(slot_value(dox_slot2(sc->envir)));
  51490. set_stepper(sc->args);
  51491. if (((typesflag(body) == SYNTACTIC_PAIR) ||
  51492. (typesflag(car(body)) == SYNTACTIC_TYPE)) &&
  51493. ((symbol_syntax_op(car(body)) == OP_LET) ||
  51494. (symbol_syntax_op(car(body)) == OP_LET_STAR)))
  51495. {
  51496. if (let_pf_ok(sc, sc->args, code, false) == goto_SAFE_DO_END_CLAUSES)
  51497. return(goto_DO_END_CLAUSES);
  51498. }
  51499. else
  51500. {
  51501. if (pf_ok(sc, cddr(code), code, false))
  51502. return(goto_DO_END_CLAUSES);
  51503. }
  51504. slot_set_value(sc->args, old_init);
  51505. sc->args = old_args;
  51506. set_unsafe_do(code);
  51507. }
  51508. push_stack(sc, OP_DOTIMES_STEP_P, sc->args, code);
  51509. sc->code = caddr(code);
  51510. return(goto_EVAL);
  51511. }
  51512. static int do_init_ex(s7_scheme *sc)
  51513. {
  51514. s7_pointer x, y, z;
  51515. while (true)
  51516. {
  51517. sc->args = cons(sc, sc->value, sc->args); /* code will be last element (first after reverse) */
  51518. if (is_pair(sc->code))
  51519. {
  51520. /* here sc->code is a list like: ((i 0 (+ i 1)) ...) so cadar gets the init value. */
  51521. s7_pointer init;
  51522. init = cadar(sc->code);
  51523. if (is_pair(init))
  51524. {
  51525. push_stack(sc, OP_DO_INIT, sc->args, cdr(sc->code));
  51526. sc->code = init;
  51527. return(goto_EVAL);
  51528. }
  51529. if (is_symbol(init))
  51530. sc->value = find_symbol_checked(sc, init);
  51531. else sc->value = init;
  51532. sc->code = cdr(sc->code);
  51533. }
  51534. else break;
  51535. }
  51536. /* all the initial values are now in the args list */
  51537. sc->args = safe_reverse_in_place(sc, sc->args);
  51538. sc->code = car(sc->args); /* saved at the start */
  51539. z = sc->args;
  51540. sc->args = cdr(sc->args); /* init values */
  51541. /* sc->envir = new_frame_in_env(sc, sc->envir); */
  51542. /* sc->args was cons'd above, so it should be safe to reuse it as the new frame */
  51543. sc->envir = old_frame_in_env(sc, z, sc->envir);
  51544. /* run through sc->code and sc->args adding '( caar(car(code)) . car(args) ) to sc->envir,
  51545. * also reuse the value cells as the new frame slots.
  51546. */
  51547. sc->value = sc->nil;
  51548. y = sc->args;
  51549. for (x = car(sc->code); is_not_null(y); x = cdr(x))
  51550. {
  51551. s7_pointer sym, args, val;
  51552. sym = caar(x);
  51553. val = car(y);
  51554. args = cdr(y);
  51555. set_type(y, T_SLOT);
  51556. slot_set_symbol(y, sym);
  51557. slot_set_value(y, val);
  51558. set_next_slot(y, let_slots(sc->envir));
  51559. let_set_slots(sc->envir, y);
  51560. symbol_set_local(sym, let_id(sc->envir), y);
  51561. if (is_not_null(cddar(x))) /* else no incr expr, so ignore it henceforth */
  51562. {
  51563. s7_pointer p;
  51564. p = cons(sc, caddar(x), val);
  51565. set_opt_slot1(p, y);
  51566. /* val is just a place-holder -- this is where we store the new value */
  51567. sc->value = cons_unchecked(sc, p, sc->value);
  51568. }
  51569. y = args;
  51570. }
  51571. sc->args = cons(sc, sc->value = safe_reverse_in_place(sc, sc->value), cadr(sc->code));
  51572. sc->code = cddr(sc->code);
  51573. /* here args is a list of 2 or 3 lists, first is (list (list (var . binding) incr-expr init-value) ...), second is end-expr, third can be result expr
  51574. * so for (do ((i 0 (+ i 1))) ((= i 3) (+ i 1)) ...) args is ((((i . 0) (+ i 1) 0 #f)) (= i 3) (+ i 1))
  51575. */
  51576. return(fall_through);
  51577. }
  51578. #if (!WITH_GCC)
  51579. #define closure_is_ok(Sc, Code, Type, Args) (find_symbol_unchecked(Sc, car(Code)) == opt_lambda_unchecked(Code))
  51580. #define closure_star_is_ok(Sc, Code, Type, Args) (find_symbol_unchecked(Sc, car(Code)) == opt_lambda_unchecked(Code))
  51581. #else
  51582. /* it is almost never the case that we already have the value and can see it in the current environment directly,
  51583. * but once found, the value usually matches the current (opt_lambda(code))
  51584. *
  51585. * (_val_) is needed below because car(code) might be undefined (with-let can cause this confusion),
  51586. * and find_symbol_unchecked returns NULL in that case.
  51587. */
  51588. #if 1
  51589. /* unlike the c_function_is_ok case, the macro form here is faster?? callgrind and time agree on this.
  51590. * opt_lambda(_code_) here can (legitimately) be a free cell or almost anything.
  51591. */
  51592. #define closure_is_ok(Sc, Code, Type, Args) \
  51593. ({ s7_pointer _code_, _val_; _code_ = Code; _val_ = find_symbol_unexamined(Sc, car(_code_)); \
  51594. ((_val_ == opt_any1(_code_)) || \
  51595. ((_val_) && (typesflag(_val_) == (unsigned short)Type) && \
  51596. ((closure_arity(_val_) == Args) || (closure_arity_to_int(Sc, _val_) == Args)) && \
  51597. (set_opt_lambda(_code_, _val_)))); })
  51598. #else
  51599. static bool closure_is_ok(s7_scheme *sc, s7_pointer code, unsigned short type, int args)
  51600. {
  51601. s7_pointer f;
  51602. f = find_symbol_unexamined(sc, car(code));
  51603. return ((f == opt_lambda_unchecked(code)) ||
  51604. ((f) &&
  51605. (typesflag(f) == type) &&
  51606. ((closure_arity(f) == args) || (closure_arity_to_int(sc, f) == args)) &&
  51607. (set_opt_lambda(code, f))));
  51608. }
  51609. #endif
  51610. #define closure_star_is_ok(Sc, Code, Type, Args) \
  51611. ({ s7_pointer _val_; _val_ = find_symbol_unexamined(Sc, car(Code)); \
  51612. ((_val_ == opt_any1(Code)) || \
  51613. ((_val_) && (typesflag(_val_) == (unsigned short)Type) && \
  51614. ((closure_arity(_val_) >= Args) || (closure_star_arity_to_int(Sc, _val_) >= Args)) && \
  51615. (set_opt_lambda(Code, _val_)))); })
  51616. #endif
  51617. #define MATCH_UNSAFE_CLOSURE (T_CLOSURE | T_PROCEDURE)
  51618. #define MATCH_SAFE_CLOSURE (T_CLOSURE | T_PROCEDURE | T_SAFE_CLOSURE)
  51619. #define MATCH_UNSAFE_CLOSURE_STAR (T_CLOSURE_STAR | T_PROCEDURE)
  51620. #define MATCH_SAFE_CLOSURE_STAR (T_CLOSURE_STAR | T_PROCEDURE | T_SAFE_CLOSURE)
  51621. /* since T_HAS_METHODS is on if there might be methods, this can protect us from that case */
  51622. /* unknown ops */
  51623. static int fixup_unknown_op(s7_scheme *sc, s7_pointer code, s7_pointer func, int op)
  51624. {
  51625. /* sc arg used if debugging */
  51626. set_optimize_op(code, op);
  51627. set_opt_lambda(code, func); /* opt_lambda works here because it is the only checked case, but ideally we'd split out all the cases via switch (op) */
  51628. return(goto_OPT_EVAL);
  51629. }
  51630. static int unknown_ex(s7_scheme *sc, s7_pointer f)
  51631. {
  51632. s7_pointer code;
  51633. code = sc->code;
  51634. switch (type(f))
  51635. {
  51636. case T_C_OBJECT:
  51637. if (s7_is_aritable(sc, f, 0))
  51638. return(fixup_unknown_op(sc, code, f, OP_C_OBJECT));
  51639. break;
  51640. case T_GOTO:
  51641. return(fixup_unknown_op(sc, code, f, OP_GOTO));
  51642. case T_CLOSURE:
  51643. if ((!has_methods(f)) &&
  51644. (is_null(closure_args(f))))
  51645. {
  51646. int hop;
  51647. hop = (is_immutable_symbol(car(code))) ? 1 : 0;
  51648. if (is_safe_closure(f))
  51649. {
  51650. s7_pointer body;
  51651. body = closure_body(f);
  51652. set_optimize_op(code, hop + OP_SAFE_THUNK);
  51653. if (is_null(cdr(body)))
  51654. {
  51655. if (is_optimized(car(body)))
  51656. set_optimize_op(code, hop + OP_SAFE_THUNK_E);
  51657. else
  51658. {
  51659. if ((is_pair(car(body))) &&
  51660. (is_syntactic_symbol(caar(body))))
  51661. {
  51662. set_optimize_op(code, hop + OP_SAFE_THUNK_P);
  51663. if (typesflag(car(body)) != SYNTACTIC_PAIR)
  51664. {
  51665. pair_set_syntax_op(car(body), symbol_syntax_op(caar(body)));
  51666. set_syntactic_pair(car(body));
  51667. }
  51668. }
  51669. }
  51670. }
  51671. set_opt_lambda(code, f);
  51672. return(goto_OPT_EVAL);
  51673. }
  51674. return(fixup_unknown_op(sc, code, f, hop + OP_THUNK));
  51675. }
  51676. /* we can't ignore the recheck here (i.e. set the hop bit) because the closure, even if a global can be set later:
  51677. * (begin (define *x* #f) (define (test) (display (*x*))) (define (setx n) (set! *x* (lambda () n))) (setx 1) (test) (setx 2) (test))
  51678. * this is a case where the name matters (we need a pristine global), so it's easily missed.
  51679. */
  51680. break;
  51681. case T_CLOSURE_STAR:
  51682. if ((!has_methods(f)) &&
  51683. (has_simple_args(closure_body(f))))
  51684. return(fixup_unknown_op(sc, code, f, ((is_immutable_symbol(car(code))) ? 1 : 0) + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_STAR : OP_CLOSURE_STAR)));
  51685. break;
  51686. default:
  51687. break;
  51688. }
  51689. return(fall_through);
  51690. }
  51691. static int unknown_g_ex(s7_scheme *sc, s7_pointer f)
  51692. {
  51693. s7_pointer code;
  51694. bool sym_case;
  51695. int hop;
  51696. code = sc->code;
  51697. hop = (is_immutable_symbol(car(code))) ? 1 : 0;
  51698. sym_case = is_symbol(cadr(code));
  51699. switch (type(f))
  51700. {
  51701. case T_C_FUNCTION: case T_C_FUNCTION_STAR: case T_C_ANY_ARGS_FUNCTION: case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION:
  51702. if (s7_is_aritable(sc, f, 1))
  51703. {
  51704. if (sym_case)
  51705. {
  51706. set_optimize_op(code, hop + ((is_safe_procedure(f)) ? OP_SAFE_C_S : OP_C_S));
  51707. set_c_function(code, f);
  51708. return(goto_OPT_EVAL);
  51709. }
  51710. else
  51711. {
  51712. if (is_safe_procedure(f))
  51713. {
  51714. set_optimize_op(code, hop + OP_SAFE_C_C);
  51715. set_c_function(code, f);
  51716. return(goto_OPT_EVAL);
  51717. }
  51718. }
  51719. }
  51720. break;
  51721. case T_CLOSURE:
  51722. if ((!has_methods(f)) &&
  51723. (closure_arity_to_int(sc, f) == 1))
  51724. {
  51725. if (sym_case)
  51726. {
  51727. set_opt_sym2(code, cadr(code));
  51728. if (is_safe_closure(f))
  51729. {
  51730. s7_pointer body;
  51731. set_optimize_op(code, hop + ((is_global(car(code))) ? OP_SAFE_GLOSURE_S : OP_SAFE_CLOSURE_S));
  51732. body = closure_body(f);
  51733. if (is_null(cdr(body)))
  51734. {
  51735. if ((is_optimized(car(body))) &&
  51736. (is_global(car(code))))
  51737. set_optimize_op(code, hop + OP_SAFE_GLOSURE_S_E);
  51738. else
  51739. {
  51740. if ((is_pair(car(body))) &&
  51741. (is_syntactic_symbol(caar(body))))
  51742. {
  51743. set_optimize_op(code, hop + OP_SAFE_CLOSURE_S_P);
  51744. if (typesflag(car(body)) != SYNTACTIC_PAIR)
  51745. {
  51746. pair_set_syntax_op(car(body), symbol_syntax_op(caar(body)));
  51747. set_syntactic_pair(car(body));
  51748. }
  51749. }
  51750. }
  51751. }
  51752. }
  51753. else set_optimize_op(code, hop + ((is_global(car(code))) ? OP_GLOSURE_S : OP_CLOSURE_S));
  51754. }
  51755. else
  51756. {
  51757. set_optimize_op(code, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_C : OP_CLOSURE_C));
  51758. set_opt_con2(code, cadr(code));
  51759. }
  51760. set_opt_lambda(code, f);
  51761. return(goto_OPT_EVAL);
  51762. }
  51763. break;
  51764. case T_CLOSURE_STAR:
  51765. if ((sym_case) &&
  51766. (!has_methods(f)) &&
  51767. (has_simple_args(closure_body(f))) &&
  51768. (!is_null(closure_args(f))))
  51769. {
  51770. set_opt_sym2(code, cadr(code));
  51771. return(fixup_unknown_op(sc, code, f, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_STAR_S : OP_CLOSURE_STAR_S)));
  51772. }
  51773. break;
  51774. case T_INT_VECTOR:
  51775. case T_FLOAT_VECTOR:
  51776. case T_VECTOR:
  51777. if ((sym_case) ||
  51778. (is_integer(cadr(code)))) /* (v 4/3) */
  51779. return(fixup_unknown_op(sc, code, f, (sym_case) ? OP_VECTOR_S : OP_VECTOR_C));
  51780. break;
  51781. case T_STRING:
  51782. return(fixup_unknown_op(sc, code, f, (sym_case) ? OP_STRING_S : OP_STRING_C));
  51783. case T_PAIR:
  51784. return(fixup_unknown_op(sc, code, f, (sym_case) ? OP_PAIR_S : OP_PAIR_C));
  51785. case T_C_OBJECT:
  51786. if (s7_is_aritable(sc, f, 1))
  51787. return(fixup_unknown_op(sc, code, f, (sym_case) ? OP_C_OBJECT_S : OP_C_OBJECT_C));
  51788. break;
  51789. case T_LET:
  51790. return(fixup_unknown_op(sc, code, f, (sym_case) ? OP_ENVIRONMENT_S : OP_ENVIRONMENT_C));
  51791. case T_HASH_TABLE:
  51792. return(fixup_unknown_op(sc, code, f, (sym_case) ? OP_HASH_TABLE_S : OP_HASH_TABLE_C));
  51793. case T_GOTO:
  51794. return(fixup_unknown_op(sc, code, f, (sym_case) ? OP_GOTO_S : OP_GOTO_C));
  51795. default:
  51796. break;
  51797. }
  51798. return(fall_through);
  51799. }
  51800. static int unknown_gg_ex(s7_scheme *sc, s7_pointer f)
  51801. {
  51802. if (s7_is_aritable(sc, f, 2))
  51803. {
  51804. bool s1, s2;
  51805. int hop;
  51806. s7_pointer code;
  51807. code = sc->code;
  51808. hop = (is_immutable_symbol(car(code))) ? 1 : 0;
  51809. s1 = is_symbol(cadr(code));
  51810. s2 = is_symbol(caddr(code));
  51811. switch (type(f))
  51812. {
  51813. case T_CLOSURE:
  51814. if (has_methods(f)) break;
  51815. if (closure_arity_to_int(sc, f) == 2)
  51816. {
  51817. if (s1)
  51818. {
  51819. if (is_safe_closure(f))
  51820. set_optimize_op(code, hop + ((s2) ? OP_SAFE_CLOSURE_SS : OP_SAFE_CLOSURE_SC));
  51821. else set_optimize_op(code, hop + ((s2) ? OP_CLOSURE_SS : OP_CLOSURE_SC));
  51822. }
  51823. else
  51824. {
  51825. if (!s2) break;
  51826. set_optimize_op(code, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_CS : OP_CLOSURE_CS));
  51827. }
  51828. if (s2) set_opt_sym2(code, caddr(code)); else set_opt_con2(code, caddr(code));
  51829. set_opt_lambda(code, f);
  51830. return(goto_OPT_EVAL);
  51831. }
  51832. break;
  51833. case T_CLOSURE_STAR: /* the closure* opts assume args are not keywords, but we can check that! */
  51834. if ((s1) &&
  51835. (!has_methods(f)))
  51836. {
  51837. if (s2)
  51838. {
  51839. if ((!is_keyword(cadr(code))) &&
  51840. (!is_keyword(caddr(code))) &&
  51841. (has_simple_args(closure_body(f))) &&
  51842. (closure_star_arity_to_int(sc, f) >= 2))
  51843. {
  51844. set_opt_sym2(code, caddr(code));
  51845. return(fixup_unknown_op(sc, code, f, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_STAR_SS : OP_CLOSURE_STAR_SX)));
  51846. }
  51847. }
  51848. else
  51849. {
  51850. set_opt_con2(code, caddr(code));
  51851. if ((!is_keyword(cadr(code))) &&
  51852. (has_simple_args(closure_body(f))) &&
  51853. (closure_star_arity_to_int(sc, f) >= 2))
  51854. return(fixup_unknown_op(sc, code, f, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_STAR_SC : OP_CLOSURE_STAR_SX)));
  51855. }
  51856. }
  51857. break;
  51858. case T_C_FUNCTION: case T_C_FUNCTION_STAR: case T_C_ANY_ARGS_FUNCTION: case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION:
  51859. if (is_safe_procedure(f))
  51860. {
  51861. if (s1)
  51862. set_optimize_op(code, hop + ((s2) ? OP_SAFE_C_SS : OP_SAFE_C_SC));
  51863. else set_optimize_op(code, hop + ((s2) ? OP_SAFE_C_CS : OP_SAFE_C_C));
  51864. }
  51865. else
  51866. {
  51867. set_optimize_op(code, hop + OP_C_ALL_X);
  51868. annotate_args(sc, cdr(code), sc->envir);
  51869. }
  51870. set_arglist_length(code, small_int(2));
  51871. set_c_function(code, f);
  51872. return(goto_OPT_EVAL);
  51873. case T_INT_VECTOR:
  51874. case T_FLOAT_VECTOR:
  51875. case T_VECTOR:
  51876. if ((is_integer(cadr(code))) && /* !s1 obviously) */
  51877. (s7_integer(cadr(code)) >= 0) &&
  51878. (is_integer(caddr(code))) &&
  51879. (s7_integer(caddr(code)) >= 0))
  51880. return(fixup_unknown_op(sc, code, f, OP_VECTOR_CC));
  51881. break;
  51882. default:
  51883. break;
  51884. }
  51885. }
  51886. return(fall_through);
  51887. }
  51888. static int unknown_all_s_ex(s7_scheme *sc, s7_pointer f)
  51889. {
  51890. s7_pointer code;
  51891. int num_args;
  51892. code = sc->code;
  51893. num_args = integer(arglist_length(code));
  51894. if (s7_is_aritable(sc, f, num_args))
  51895. {
  51896. int hop;
  51897. hop = (is_immutable_symbol(car(code))) ? 1 : 0;
  51898. switch (type(f))
  51899. {
  51900. case T_CLOSURE:
  51901. if ((!has_methods(f)) &&
  51902. (closure_arity_to_int(sc, f) == num_args))
  51903. {
  51904. annotate_args(sc, cdr(code), sc->envir);
  51905. return(fixup_unknown_op(sc, code, f, hop + ((is_safe_closure(f)) ? OP_SAFE_CLOSURE_ALL_X : OP_CLOSURE_ALL_S)));
  51906. }
  51907. break;
  51908. case T_C_FUNCTION: case T_C_FUNCTION_STAR: case T_C_ANY_ARGS_FUNCTION: case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION:
  51909. if (is_safe_procedure(f))
  51910. set_optimize_op(code, hop + OP_SAFE_C_ALL_S);
  51911. else
  51912. {
  51913. set_optimize_op(code, hop + OP_C_ALL_X);
  51914. annotate_args(sc, cdr(code), sc->envir);
  51915. }
  51916. set_c_function(code, f);
  51917. return(goto_OPT_EVAL);
  51918. default:
  51919. break;
  51920. }
  51921. }
  51922. return(fall_through);
  51923. }
  51924. static int unknown_a_ex(s7_scheme *sc, s7_pointer f)
  51925. {
  51926. if (s7_is_aritable(sc, f, 1))
  51927. {
  51928. s7_pointer code;
  51929. code = sc->code;
  51930. set_arglist_length(code, small_int(1));
  51931. annotate_args(sc, cdr(code), sc->envir);
  51932. switch (type(f))
  51933. {
  51934. case T_INT_VECTOR:
  51935. case T_FLOAT_VECTOR:
  51936. case T_VECTOR:
  51937. return(fixup_unknown_op(sc, code, f, OP_VECTOR_A));
  51938. case T_C_FUNCTION: case T_C_FUNCTION_STAR: case T_C_ANY_ARGS_FUNCTION: case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION:
  51939. if ((is_safe_procedure(f)) &&
  51940. (is_optimized(cadr(code))))
  51941. {
  51942. int op;
  51943. op = combine_ops(sc, E_C_P, code, cadr(code));
  51944. set_optimize_op(code, op);
  51945. if ((op == OP_SAFE_C_Z) &&
  51946. (is_all_x_op(optimize_op(cadr(code)))))
  51947. set_optimize_op(code, OP_SAFE_C_A);
  51948. set_c_function(code, f);
  51949. return(goto_OPT_EVAL);
  51950. }
  51951. if ((is_pair(cadr(code))) &&
  51952. (caadr(code) == sc->quote_symbol))
  51953. set_optimize_op(code, (is_safe_procedure(f)) ? OP_SAFE_C_Q : OP_C_A);
  51954. else set_optimize_op(code, (is_safe_procedure(f)) ? OP_SAFE_C_A : OP_C_A);
  51955. set_c_function(code, f);
  51956. return(goto_OPT_EVAL);
  51957. case T_CLOSURE:
  51958. if ((!has_methods(f)) &&
  51959. (closure_arity_to_int(sc, f) == 1))
  51960. {
  51961. if ((is_pair(cadr(code))) &&
  51962. (caadr(code) == sc->quote_symbol))
  51963. return(fixup_unknown_op(sc, code, f, (is_safe_closure(f)) ? OP_SAFE_CLOSURE_Q : OP_CLOSURE_Q));
  51964. if (is_safe_closure(f))
  51965. set_optimize_op(code, (is_global(car(code))) ? OP_SAFE_GLOSURE_A : OP_SAFE_CLOSURE_A);
  51966. else set_optimize_op(code, (is_global(car(code))) ? OP_GLOSURE_A : OP_CLOSURE_A);
  51967. set_opt_lambda(code, f);
  51968. return(goto_OPT_EVAL);
  51969. }
  51970. break;
  51971. case T_CLOSURE_STAR:
  51972. if ((!has_methods(f)) &&
  51973. (has_simple_args(closure_body(f))) &&
  51974. (closure_star_arity_to_int(sc, f) >= 1) &&
  51975. (!arglist_has_keyword(cdr(code))))
  51976. return(fixup_unknown_op(sc, code, f, (is_safe_closure(f)) ? OP_SAFE_CLOSURE_STAR_ALL_X : OP_CLOSURE_STAR_ALL_X));
  51977. break;
  51978. case T_STRING:
  51979. return(fixup_unknown_op(sc, code, f, OP_STRING_A));
  51980. case T_PAIR:
  51981. return(fixup_unknown_op(sc, code, f, OP_PAIR_A));
  51982. case T_C_OBJECT:
  51983. return(fixup_unknown_op(sc, code, f, OP_C_OBJECT_A));
  51984. case T_LET:
  51985. return(fixup_unknown_op(sc, code, f, ((is_pair(cadr(code))) && (caadr(code) == sc->quote_symbol)) ? OP_ENVIRONMENT_Q : OP_ENVIRONMENT_A));
  51986. case T_HASH_TABLE:
  51987. return(fixup_unknown_op(sc, code, f, OP_HASH_TABLE_A));
  51988. case T_GOTO:
  51989. return(fixup_unknown_op(sc, code, f, OP_GOTO_A));
  51990. default:
  51991. break;
  51992. }
  51993. }
  51994. return(fall_through);
  51995. }
  51996. static int unknown_aa_ex(s7_scheme *sc, s7_pointer f)
  51997. {
  51998. if (s7_is_aritable(sc, f, 2))
  51999. {
  52000. s7_pointer code;
  52001. code = sc->code;
  52002. set_arglist_length(code, small_int(2));
  52003. annotate_args(sc, cdr(code), sc->envir);
  52004. switch (type(f))
  52005. {
  52006. case T_CLOSURE:
  52007. if ((!has_methods(f)) &&
  52008. (closure_arity_to_int(sc, f) == 2))
  52009. {
  52010. set_optimize_op(code, (is_safe_closure(f)) ? OP_SAFE_CLOSURE_AA : OP_CLOSURE_AA);
  52011. set_opt_lambda(code, f);
  52012. return(goto_OPT_EVAL);
  52013. }
  52014. break;
  52015. case T_CLOSURE_STAR:
  52016. if ((!has_methods(f)) &&
  52017. (has_simple_args(closure_body(f))) &&
  52018. (closure_star_arity_to_int(sc, f) >= 2) &&
  52019. (!arglist_has_keyword(cdr(code))))
  52020. return(fixup_unknown_op(sc, code, f, (is_safe_closure(f)) ? OP_SAFE_CLOSURE_STAR_ALL_X : OP_CLOSURE_STAR_ALL_X));
  52021. break;
  52022. case T_C_FUNCTION: case T_C_FUNCTION_STAR: case T_C_ANY_ARGS_FUNCTION: case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION:
  52023. set_optimize_op(code, (is_safe_procedure(f)) ? OP_SAFE_C_AA : OP_C_ALL_X);
  52024. set_c_function(code, f);
  52025. return(goto_OPT_EVAL);
  52026. default:
  52027. break;
  52028. }
  52029. }
  52030. return(fall_through);
  52031. }
  52032. static int unknown_all_x_ex(s7_scheme *sc, s7_pointer f)
  52033. {
  52034. s7_pointer code;
  52035. int num_args;
  52036. code = sc->code;
  52037. num_args = integer(arglist_length(code));
  52038. if (s7_is_aritable(sc, f, num_args))
  52039. {
  52040. switch (type(f))
  52041. {
  52042. case T_CLOSURE:
  52043. if ((!has_methods(f)) &&
  52044. (closure_arity_to_int(sc, f) == num_args))
  52045. {
  52046. annotate_args(sc, cdr(code), sc->envir);
  52047. if (is_safe_closure(f))
  52048. {
  52049. if ((is_symbol(cadr(code))) &&
  52050. (num_args == 3))
  52051. set_optimize_op(code, OP_SAFE_CLOSURE_SAA);
  52052. else set_optimize_op(code, OP_SAFE_CLOSURE_ALL_X);
  52053. }
  52054. else set_optimize_op(code, OP_CLOSURE_ALL_X);
  52055. set_opt_lambda(code, f);
  52056. return(goto_OPT_EVAL);
  52057. }
  52058. break;
  52059. case T_CLOSURE_STAR:
  52060. if ((!has_methods(f)) &&
  52061. (has_simple_args(closure_body(f))) &&
  52062. (closure_star_arity_to_int(sc, f) >= num_args) &&
  52063. (!arglist_has_keyword(cdr(code))))
  52064. {
  52065. annotate_args(sc, cdr(code), sc->envir);
  52066. return(fixup_unknown_op(sc, code, f, (is_safe_closure(f)) ? OP_SAFE_CLOSURE_STAR_ALL_X : OP_CLOSURE_STAR_ALL_X));
  52067. }
  52068. break;
  52069. case T_C_FUNCTION: case T_C_FUNCTION_STAR: case T_C_ANY_ARGS_FUNCTION: case T_C_OPT_ARGS_FUNCTION: case T_C_RST_ARGS_FUNCTION:
  52070. set_optimize_op(code, (is_safe_procedure(f)) ? OP_SAFE_C_ALL_X : OP_C_ALL_X);
  52071. annotate_args(sc, cdr(code), sc->envir);
  52072. set_c_function(code, f);
  52073. return(goto_OPT_EVAL);
  52074. default:
  52075. break;
  52076. }
  52077. }
  52078. return(fall_through);
  52079. }
  52080. static void unwind_output_ex(s7_scheme *sc)
  52081. {
  52082. bool is_file;
  52083. is_file = is_file_port(sc->code);
  52084. if ((is_output_port(sc->code)) &&
  52085. (!port_is_closed(sc->code)))
  52086. s7_close_output_port(sc, sc->code); /* may call fflush */
  52087. if ((is_output_port(sc->args)) &&
  52088. (!port_is_closed(sc->args)))
  52089. sc->output_port = sc->args;
  52090. if ((is_file) &&
  52091. (is_multiple_value(sc->value)))
  52092. sc->value = splice_in_values(sc, multiple_value(sc->value));
  52093. }
  52094. static void unwind_input_ex(s7_scheme *sc)
  52095. {
  52096. if ((is_input_port(sc->code)) &&
  52097. (!port_is_closed(sc->code)))
  52098. s7_close_input_port(sc, sc->code);
  52099. if ((is_input_port(sc->args)) &&
  52100. (!port_is_closed(sc->args)))
  52101. sc->input_port = sc->args;
  52102. if (is_multiple_value(sc->value))
  52103. sc->value = splice_in_values(sc, multiple_value(sc->value));
  52104. }
  52105. static int dynamic_wind_ex(s7_scheme *sc)
  52106. {
  52107. if (dynamic_wind_state(sc->code) == DWIND_INIT)
  52108. {
  52109. dynamic_wind_state(sc->code) = DWIND_BODY;
  52110. push_stack(sc, OP_DYNAMIC_WIND, sc->nil, sc->code);
  52111. sc->code = dynamic_wind_body(sc->code);
  52112. sc->args = sc->nil;
  52113. return(goto_APPLY);
  52114. }
  52115. else
  52116. {
  52117. if (dynamic_wind_state(sc->code) == DWIND_BODY)
  52118. {
  52119. dynamic_wind_state(sc->code) = DWIND_FINISH;
  52120. if (dynamic_wind_out(sc->code) != sc->F)
  52121. {
  52122. push_stack(sc, OP_DYNAMIC_WIND, sc->value, sc->code);
  52123. sc->code = dynamic_wind_out(sc->code);
  52124. sc->args = sc->nil;
  52125. return(goto_APPLY);
  52126. }
  52127. else
  52128. {
  52129. if (is_multiple_value(sc->value))
  52130. sc->value = splice_in_values(sc, multiple_value(sc->value));
  52131. return(goto_START);
  52132. }
  52133. }
  52134. if (is_multiple_value(sc->args)) /* (+ 1 (dynamic-wind (lambda () #f) (lambda () (values 2 3 4)) (lambda () #f)) 5) */
  52135. sc->value = splice_in_values(sc, multiple_value(sc->args));
  52136. else sc->value = sc->args; /* value saved above */
  52137. }
  52138. return(goto_START);
  52139. }
  52140. static int read_s_ex(s7_scheme *sc)
  52141. {
  52142. /* another lint opt */
  52143. s7_pointer port, code;
  52144. code = sc->code;
  52145. port = find_symbol_checked(sc, cadr(code));
  52146. if (!is_input_port(port)) /* was also not stdin */
  52147. {
  52148. sc->value = g_read(sc, list_1(sc, port));
  52149. return(goto_START);
  52150. }
  52151. /* I guess this port_is_closed check is needed because we're going down a level below */
  52152. if (port_is_closed(port))
  52153. simple_wrong_type_argument_with_type(sc, sc->read_symbol, port, an_open_port_string);
  52154. if (is_function_port(port))
  52155. sc->value = (*(port_input_function(port)))(sc, S7_READ, port);
  52156. else
  52157. {
  52158. if ((is_string_port(port)) &&
  52159. (port_data_size(port) <= port_position(port)))
  52160. sc->value = sc->eof_object;
  52161. else
  52162. {
  52163. push_input_port(sc, port);
  52164. push_stack(sc, OP_READ_DONE, sc->nil, sc->nil); /* this stops the internal read process so we only get one form */
  52165. sc->tok = token(sc);
  52166. switch (sc->tok)
  52167. {
  52168. case TOKEN_EOF:
  52169. return(goto_START);
  52170. case TOKEN_RIGHT_PAREN:
  52171. read_error(sc, "unexpected close paren");
  52172. case TOKEN_COMMA:
  52173. read_error(sc, "unexpected comma");
  52174. default:
  52175. sc->value = read_expression(sc);
  52176. sc->current_line = port_line_number(sc->input_port); /* this info is used to track down missing close parens */
  52177. sc->current_file = port_filename(sc->input_port);
  52178. }
  52179. }
  52180. }
  52181. /* equally read-done and read-list here */
  52182. return(goto_START);
  52183. }
  52184. static void eval_string_1_ex(s7_scheme *sc)
  52185. {
  52186. if ((sc->tok != TOKEN_EOF) &&
  52187. (port_position(sc->input_port) < port_data_size(sc->input_port))) /* ran past end somehow? */
  52188. {
  52189. unsigned char c;
  52190. while (white_space[c = port_data(sc->input_port)[port_position(sc->input_port)++]])
  52191. if (c == '\n')
  52192. port_line_number(sc->input_port)++;
  52193. if (c != 0)
  52194. {
  52195. backchar(c, sc->input_port);
  52196. push_stack(sc, OP_EVAL_STRING_1, sc->nil, sc->value);
  52197. push_stack(sc, OP_READ_INTERNAL, sc->nil, sc->nil);
  52198. }
  52199. else push_stack(sc, OP_EVAL_STRING_2, sc->nil, sc->nil);
  52200. }
  52201. else push_stack(sc, OP_EVAL_STRING_2, sc->nil, sc->nil);
  52202. sc->code = sc->value;
  52203. }
  52204. static int string_c_ex(s7_scheme *sc)
  52205. {
  52206. s7_int index;
  52207. s7_pointer s, code;
  52208. code = sc->code;
  52209. s = find_symbol_checked(sc, car(code));
  52210. if ((!is_string(s)) ||
  52211. (!is_integer(cadr(code))))
  52212. return(fall_through);
  52213. index = s7_integer(cadr(code));
  52214. if ((index < string_length(s)) &&
  52215. (index >= 0))
  52216. {
  52217. if (is_byte_vector(s))
  52218. sc->value = small_int((unsigned char)string_value(s)[index]);
  52219. else sc->value = s7_make_character(sc, ((unsigned char *)string_value(s))[index]);
  52220. return(goto_START);
  52221. }
  52222. sc->value = string_ref_1(sc, s, cadr(code));
  52223. return(goto_START);
  52224. }
  52225. static int string_a_ex(s7_scheme *sc)
  52226. {
  52227. s7_int index;
  52228. s7_pointer s, x, code;
  52229. code = sc->code;
  52230. s = find_symbol_checked(sc, car(code));
  52231. x = c_call(cdr(code))(sc, cadr(code));
  52232. if ((!is_string(s)) ||
  52233. (!s7_is_integer(x)))
  52234. return(fall_through);
  52235. index = s7_integer(x);
  52236. if ((index < string_length(s)) &&
  52237. (index >= 0))
  52238. {
  52239. if (is_byte_vector(s))
  52240. sc->value = small_int((unsigned char)string_value(s)[index]);
  52241. else sc->value = s7_make_character(sc, ((unsigned char *)string_value(s))[index]);
  52242. return(goto_START);
  52243. }
  52244. sc->value = string_ref_1(sc, s, x);
  52245. return(goto_START);
  52246. }
  52247. static int string_s_ex(s7_scheme *sc)
  52248. {
  52249. s7_int index;
  52250. s7_pointer s, ind, code;
  52251. code = sc->code;
  52252. s = find_symbol_checked(sc, car(code));
  52253. ind = find_symbol_checked(sc, cadr(code));
  52254. if ((!is_string(s)) ||
  52255. (!s7_is_integer(ind)))
  52256. return(fall_through);
  52257. index = s7_integer(ind);
  52258. if ((index < string_length(s)) &&
  52259. (index >= 0))
  52260. {
  52261. if (is_byte_vector(s))
  52262. sc->value = small_int((unsigned char)string_value(s)[index]);
  52263. else sc->value = s7_make_character(sc, ((unsigned char *)string_value(s))[index]);
  52264. return(goto_START);
  52265. }
  52266. sc->value = string_ref_1(sc, s, ind);
  52267. return(goto_START);
  52268. }
  52269. static int vector_c_ex(s7_scheme *sc)
  52270. {
  52271. /* this is the implicit indexing case (vector-ref is a normal safe op)
  52272. * (define (hi) (let ((v (vector 1 2 3))) (v 0)))
  52273. * this starts as unknown_g in optimize_expression -> vector_c
  52274. * but it still reports itself as unsafe, so there are higher levels possible
  52275. */
  52276. s7_pointer v, code;
  52277. code = sc->code;
  52278. v = find_symbol_checked(sc, car(code));
  52279. if ((!s7_is_vector(v)) ||
  52280. (!s7_is_integer(cadr(code)))) /* (v 4/3) */
  52281. return(fall_through);
  52282. if (vector_rank(v) == 1)
  52283. {
  52284. s7_int index;
  52285. index = s7_integer(cadr(code));
  52286. if ((index < vector_length(v)) &&
  52287. (index >= 0))
  52288. {
  52289. sc->value = vector_getter(v)(sc, v, index);
  52290. return(goto_START);
  52291. }
  52292. }
  52293. sc->value = vector_ref_1(sc, v, cdr(code));
  52294. return(goto_START);
  52295. }
  52296. static int vector_cc_ex(s7_scheme *sc)
  52297. {
  52298. s7_pointer v, code;
  52299. code = sc->code;
  52300. v = find_symbol_checked(sc, car(code));
  52301. if (!s7_is_vector(v)) /* we've checked that the args are non-negative ints */
  52302. return(fall_through);
  52303. if (vector_rank(v) == 2)
  52304. {
  52305. s7_int index;
  52306. index = s7_integer(cadr(code)) * vector_offset(v, 0) + s7_integer(caddr(code));
  52307. if (index < vector_length(v))
  52308. {
  52309. sc->value = vector_getter(v)(sc, v, index);
  52310. return(goto_START);
  52311. }
  52312. }
  52313. sc->value = vector_ref_1(sc, v, cdr(code));
  52314. return(goto_START);
  52315. }
  52316. static int vector_s_ex(s7_scheme *sc)
  52317. {
  52318. s7_pointer v, ind, code;
  52319. code = sc->code;
  52320. v = find_symbol_checked(sc, car(code));
  52321. ind = find_symbol_checked(sc, cadr(code));
  52322. if ((!s7_is_vector(v)) ||
  52323. (!s7_is_integer(ind)))
  52324. return(fall_through);
  52325. if (vector_rank(v) == 1)
  52326. {
  52327. s7_int index;
  52328. index = s7_integer(ind);
  52329. if ((index < vector_length(v)) &&
  52330. (index >= 0))
  52331. {
  52332. sc->value = vector_getter(v)(sc, v, index);
  52333. return(goto_START);
  52334. }
  52335. }
  52336. sc->value = vector_ref_1(sc, v, cons(sc, ind, sc->nil));
  52337. return(goto_START);
  52338. }
  52339. static int vector_a_ex(s7_scheme *sc)
  52340. {
  52341. s7_pointer v, x, code;
  52342. code = sc->code;
  52343. v = find_symbol_checked(sc, car(code));
  52344. if (!s7_is_vector(v))
  52345. return(fall_through);
  52346. x = c_call(cdr(code))(sc, cadr(code));
  52347. if (s7_is_integer(x))
  52348. {
  52349. if (vector_rank(v) == 1)
  52350. {
  52351. s7_int index;
  52352. index = s7_integer(x);
  52353. if ((index < vector_length(v)) &&
  52354. (index >= 0))
  52355. {
  52356. sc->value = vector_getter(v)(sc, v, index);
  52357. return(goto_START);
  52358. }
  52359. }
  52360. }
  52361. sc->value = vector_ref_1(sc, v, cons(sc, x, sc->nil));
  52362. return(goto_START);
  52363. }
  52364. static void increment_1_ex(s7_scheme *sc)
  52365. {
  52366. /* ([set!] ctr (+ ctr 1)) */
  52367. s7_pointer val, y;
  52368. y = find_symbol(sc, car(sc->code));
  52369. if (!is_slot(y))
  52370. eval_error_no_return(sc, sc->wrong_type_arg_symbol, "set! ~A: unbound variable", car(sc->code));
  52371. val = slot_value(y);
  52372. switch (type(val))
  52373. {
  52374. case T_INTEGER:
  52375. sc->value = make_integer(sc, integer(val) + 1); /* this can't be optimized to treat y's value as a mutable integer */
  52376. break;
  52377. case T_RATIO:
  52378. new_cell(sc, sc->value, T_RATIO);
  52379. numerator(sc->value) = numerator(val) + denominator(val);
  52380. denominator(sc->value) = denominator(val);
  52381. break;
  52382. case T_REAL:
  52383. sc->value = make_real(sc, real(val) + 1.0);
  52384. break;
  52385. case T_COMPLEX:
  52386. new_cell(sc, sc->value, T_COMPLEX);
  52387. set_real_part(sc->value, real_part(val) + 1.0);
  52388. set_imag_part(sc->value, imag_part(val));
  52389. break;
  52390. default:
  52391. sc->value = g_add(sc, set_plist_2(sc, val, small_int(1)));
  52392. break;
  52393. }
  52394. slot_set_value(y, sc->value);
  52395. }
  52396. static void decrement_1_ex(s7_scheme *sc)
  52397. {
  52398. /* ([set!] ctr (- ctr 1)) */
  52399. s7_pointer val, y;
  52400. y = find_symbol(sc, car(sc->code));
  52401. if (!is_slot(y))
  52402. eval_error_no_return(sc, sc->wrong_type_arg_symbol, "set! ~A: unbound variable", car(sc->code));
  52403. val = slot_value(y);
  52404. switch (type(val))
  52405. {
  52406. case T_INTEGER:
  52407. sc->value = make_integer(sc, integer(val) - 1);
  52408. break;
  52409. case T_RATIO:
  52410. new_cell(sc, sc->value, T_RATIO);
  52411. numerator(sc->value) = numerator(val) - denominator(val);
  52412. denominator(sc->value) = denominator(val);
  52413. break;
  52414. case T_REAL:
  52415. sc->value = make_real(sc, real(val) - 1.0);
  52416. break;
  52417. case T_COMPLEX:
  52418. new_cell(sc, sc->value, T_COMPLEX);
  52419. set_real_part(sc->value, real_part(val) - 1.0);
  52420. set_imag_part(sc->value, imag_part(val));
  52421. break;
  52422. default:
  52423. sc->value = g_subtract(sc, set_plist_2(sc, val, small_int(1)));
  52424. break;
  52425. }
  52426. slot_set_value(y, sc->value);
  52427. }
  52428. static void set_pws_ex(s7_scheme *sc)
  52429. {
  52430. /* ([set!] (save-dir) "/home/bil/zap/snd") */
  52431. s7_pointer obj;
  52432. obj = caar(sc->code);
  52433. if (is_symbol(obj))
  52434. {
  52435. obj = find_symbol(sc, obj);
  52436. if (is_slot(obj))
  52437. obj = slot_value(obj);
  52438. else eval_error_no_return(sc, sc->syntax_error_symbol, "no generalized set for ~A", caar(sc->code));
  52439. }
  52440. if ((is_c_function(obj)) &&
  52441. (is_procedure(c_function_setter(obj))))
  52442. {
  52443. s7_pointer value;
  52444. value = cadr(sc->code);
  52445. if (is_symbol(value))
  52446. value = find_symbol_checked(sc, value);
  52447. set_car(sc->t1_1, value);
  52448. sc->value = c_function_call(c_function_setter(obj))(sc, sc->t1_1);
  52449. }
  52450. else eval_error_no_return(sc, sc->syntax_error_symbol, "no generalized set for ~A", obj);
  52451. }
  52452. /* -------------------------------- apply functions -------------------------------- */
  52453. static void apply_c_function(s7_scheme *sc) /* -------- C-based function -------- */
  52454. {
  52455. unsigned int len;
  52456. len = safe_list_length(sc, sc->args);
  52457. if (len < c_function_required_args(sc->code))
  52458. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->not_enough_arguments_string, sc->code, sc->args));
  52459. if (c_function_all_args(sc->code) < len)
  52460. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->too_many_arguments_string, sc->code, sc->args));
  52461. sc->value = c_function_call(sc->code)(sc, sc->args);
  52462. }
  52463. static void apply_c_opt_args_function(s7_scheme *sc) /* -------- C-based function that has n optional arguments -------- */
  52464. {
  52465. unsigned int len;
  52466. len = safe_list_length(sc, sc->args);
  52467. if (c_function_all_args(sc->code) < len)
  52468. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->too_many_arguments_string, sc->code, sc->args));
  52469. sc->value = c_function_call(sc->code)(sc, sc->args);
  52470. }
  52471. static void apply_c_rst_args_function(s7_scheme *sc) /* -------- C-based function that has n required args, then any others -------- */
  52472. {
  52473. unsigned int len;
  52474. len = safe_list_length(sc, sc->args);
  52475. if (len < c_function_required_args(sc->code))
  52476. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->not_enough_arguments_string, sc->code, sc->args));
  52477. sc->value = c_function_call(sc->code)(sc, sc->args);
  52478. /* sc->code here need not match sc->code before the function call (map for example) */
  52479. }
  52480. static void apply_c_any_args_function(s7_scheme *sc) /* -------- C-based function that can take any number of arguments -------- */
  52481. {
  52482. sc->value = c_function_call(sc->code)(sc, sc->args);
  52483. }
  52484. static void apply_c_function_star(s7_scheme *sc) /* -------- C-based function with defaults (lambda*) -------- */
  52485. {
  52486. sc->value = c_function_call(sc->code)(sc, set_c_function_call_args(sc));
  52487. }
  52488. static void apply_c_macro(s7_scheme *sc) /* -------- C-based macro -------- */
  52489. {
  52490. int len;
  52491. len = s7_list_length(sc, sc->args);
  52492. if (len < (int)c_macro_required_args(sc->code))
  52493. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->not_enough_arguments_string, sc->code, sc->args));
  52494. if ((int)c_macro_all_args(sc->code) < len)
  52495. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->too_many_arguments_string, sc->code, sc->args));
  52496. sc->code = c_macro_call(sc->code)(sc, sc->args);
  52497. if (is_multiple_value(sc->code)) /* can this happen? s7_values splices before returning, and `(values ...) is handled later */
  52498. {
  52499. push_stack(sc, OP_EVAL_MACRO_MV, sc->nil, cdr(sc->code));
  52500. sc->code = car(sc->code);
  52501. }
  52502. }
  52503. static void apply_syntax(s7_scheme *sc) /* -------- syntactic keyword as applicable object -------- */
  52504. { /* current reader-cond macro uses this via (map quote ...) */
  52505. int len; /* ((apply lambda '((x) (+ x 1))) 4) */
  52506. if (is_pair(sc->args))
  52507. {
  52508. len = s7_list_length(sc, sc->args);
  52509. if (len == 0) eval_error_no_return(sc, sc->syntax_error_symbol, "attempt to evaluate a circular list: ~A", sc->args);
  52510. }
  52511. else len = 0;
  52512. if (len < syntax_min_args(sc->code))
  52513. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->not_enough_arguments_string, sc->code, sc->args));
  52514. if ((syntax_max_args(sc->code) < len) &&
  52515. (syntax_max_args(sc->code) != -1))
  52516. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->too_many_arguments_string, sc->code, sc->args));
  52517. sc->op = (opcode_t)syntax_opcode(sc->code); /* (apply begin '((define x 3) (+ x 2))) */
  52518. /* I used to have elaborate checks here for embedded circular lists, but now i think that is the caller's problem */
  52519. sc->code = sc->args;
  52520. }
  52521. static void apply_vector(s7_scheme *sc) /* -------- vector as applicable object -------- */
  52522. {
  52523. /* sc->code is the vector, sc->args is the list of indices */
  52524. if (is_null(sc->args)) /* (#2d((1 2) (3 4))) */
  52525. s7_wrong_number_of_args_error(sc, "not enough args for vector-ref: ~A", sc->args);
  52526. if ((is_null(cdr(sc->args))) &&
  52527. (s7_is_integer(car(sc->args))) &&
  52528. (vector_rank(sc->code) == 1))
  52529. {
  52530. s7_int index;
  52531. index = s7_integer(car(sc->args));
  52532. if ((index >= 0) &&
  52533. (index < vector_length(sc->code)))
  52534. sc->value = vector_getter(sc->code)(sc, sc->code, index);
  52535. else out_of_range(sc, sc->vector_ref_symbol, small_int(2), car(sc->args), (index < 0) ? its_negative_string : its_too_large_string);
  52536. }
  52537. else sc->value = vector_ref_1(sc, sc->code, sc->args);
  52538. }
  52539. static void apply_string(s7_scheme *sc) /* -------- string as applicable object -------- */
  52540. {
  52541. if (is_null(cdr(sc->args)))
  52542. {
  52543. if (s7_is_integer(car(sc->args)))
  52544. {
  52545. s7_int index; /* not int: ("abs" most-negative-fixnum) */
  52546. index = s7_integer(car(sc->args));
  52547. if ((index >= 0) &&
  52548. (index < string_length(sc->code)))
  52549. {
  52550. if (is_byte_vector(sc->code))
  52551. sc->value = small_int((unsigned char)(string_value(sc->code))[index]);
  52552. else sc->value = s7_make_character(sc, ((unsigned char *)string_value(sc->code))[index]);
  52553. return;
  52554. }
  52555. }
  52556. sc->value = string_ref_1(sc, sc->code, car(sc->args));
  52557. return;
  52558. }
  52559. s7_error(sc, sc->wrong_number_of_args_symbol,
  52560. set_elist_3(sc, (is_null(sc->args)) ? sc->not_enough_arguments_string : sc->too_many_arguments_string, sc->code, sc->args));
  52561. }
  52562. static int apply_pair(s7_scheme *sc) /* -------- list as applicable object -------- */
  52563. {
  52564. if (is_multiple_value(sc->code)) /* ((values 1 2 3) 0) */
  52565. {
  52566. /* car of values can be anything, so conjure up a new expression, and apply again */
  52567. sc->x = multiple_value(sc->code); /* ((values + 1 2) 3) */
  52568. sc->code = car(sc->x);
  52569. sc->args = s7_append(sc, cdr(sc->x), sc->args);
  52570. sc->x = sc->nil;
  52571. return(goto_APPLY);
  52572. }
  52573. if (is_null(sc->args))
  52574. s7_wrong_number_of_args_error(sc, "not enough args for list-ref (via list as applicable object): ~A", sc->args);
  52575. sc->value = list_ref_1(sc, sc->code, car(sc->args)); /* (L 1) */
  52576. if (!is_null(cdr(sc->args)))
  52577. sc->value = implicit_index(sc, sc->value, cdr(sc->args)); /* (L 1 2) */
  52578. return(goto_START);
  52579. }
  52580. static void apply_hash_table(s7_scheme *sc) /* -------- hash-table as applicable object -------- */
  52581. {
  52582. if (is_null(sc->args))
  52583. s7_wrong_number_of_args_error(sc, "not enough args for hash-table-ref (via hash table as applicable object): ~A", sc->args);
  52584. sc->value = s7_hash_table_ref(sc, sc->code, car(sc->args));
  52585. if (!is_null(cdr(sc->args)))
  52586. sc->value = implicit_index(sc, sc->value, cdr(sc->args));
  52587. }
  52588. static void apply_let(s7_scheme *sc) /* -------- environment as applicable object -------- */
  52589. {
  52590. if (is_null(sc->args))
  52591. sc->value = s7_let_ref(sc, sc->code, sc->F); /* why #f and not ()? both are ok in s7test */
  52592. else sc->value = s7_let_ref(sc, sc->code, car(sc->args));
  52593. if (is_pair(cdr(sc->args)))
  52594. sc->value = implicit_index(sc, sc->value, cdr(sc->args));
  52595. /* (let ((v #(1 2 3))) (let ((e (curlet))) ((e 'v) 1))) -> 2
  52596. * so (let ((v #(1 2 3))) (let ((e (curlet))) (e 'v 1))) -> 2
  52597. */
  52598. }
  52599. static void apply_iterator(s7_scheme *sc) /* -------- iterator as applicable object -------- */
  52600. {
  52601. if (!is_null(sc->args))
  52602. s7_wrong_number_of_args_error(sc, "too many args for iterator: ~A", sc->args);
  52603. sc->value = s7_iterate(sc, sc->code);
  52604. }
  52605. static void apply_lambda(s7_scheme *sc) /* -------- normal function (lambda), or macro -------- */
  52606. { /* load up the current args into the ((args) (lambda)) layout [via the current environment] */
  52607. /* not often safe closure here, and very confusing if so to get identity macro args handled correctly */
  52608. s7_pointer x, z, e;
  52609. unsigned long long int id;
  52610. e = sc->envir;
  52611. id = let_id(e);
  52612. for (x = closure_args(sc->code), z = sc->args; is_pair(x); x = cdr(x))
  52613. {
  52614. s7_pointer sym, args, val;
  52615. /* reuse the value cells as the new frame slots */
  52616. if (is_null(z))
  52617. {
  52618. s7_pointer name, ccode;
  52619. name = closure_name(sc, sc->code);
  52620. ccode = current_code(sc);
  52621. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->not_enough_arguments_string, (name == ccode) ? sc->code : name, ccode));
  52622. }
  52623. /* now that args are being reused as slots, the error message can't use sc->args,
  52624. * so fallback on current_code(sc) in this section.
  52625. * But that can be #f, and closure_name can be confusing in this context, so we need a better error message!
  52626. */
  52627. sym = car(x);
  52628. val = _NFre(car(z));
  52629. args = cdr(z);
  52630. set_type(z, T_SLOT);
  52631. slot_set_symbol(z, sym);
  52632. symbol_set_local(sym, id, z);
  52633. slot_set_value(z, val);
  52634. set_next_slot(z, let_slots(e));
  52635. let_set_slots(e, z);
  52636. z = args;
  52637. }
  52638. if (is_null(x))
  52639. {
  52640. if (is_not_null(z))
  52641. {
  52642. s7_pointer name, ccode;
  52643. name = closure_name(sc, sc->code);
  52644. ccode = current_code(sc);
  52645. s7_error(sc, sc->wrong_number_of_args_symbol, set_elist_3(sc, sc->too_many_arguments_string, (name == ccode) ? sc->code : name, ccode));
  52646. }
  52647. }
  52648. else
  52649. {
  52650. sc->temp6 = z; /* the rest arg */
  52651. make_slot_1(sc, sc->envir, x, z);
  52652. sc->temp6 = sc->nil;
  52653. }
  52654. sc->code = closure_body(sc->code);
  52655. }
  52656. static int apply_lambda_star(s7_scheme *sc) /* -------- define* (lambda*) -------- */
  52657. {
  52658. /* to check for and fixup unset args from defaults, we need to traverse the slots in left-to-right order
  52659. * but they are stored backwards in the environment, so use pending_value as a back-pointer.
  52660. * We have to build the environment before calling lambda_star_set_args because keywords can
  52661. * cause any arg to be set at any point in the arg list.
  52662. *
  52663. * the frame-making step below could be precalculated, but where to store it?
  52664. */
  52665. s7_pointer z, top, nxt;
  52666. top = NULL;
  52667. nxt = NULL;
  52668. for (z = closure_args(sc->code); is_pair(z); z = cdr(z))
  52669. {
  52670. s7_pointer car_z;
  52671. car_z = car(z);
  52672. if (is_pair(car_z)) /* arg has a default value of some sort */
  52673. {
  52674. s7_pointer val;
  52675. val = cadr(car_z);
  52676. if ((!is_pair(val)) &&
  52677. (!is_symbol(val)))
  52678. make_slot_1(sc, sc->envir, car(car_z), val);
  52679. else
  52680. {
  52681. s7_pointer y;
  52682. add_slot(sc->envir, car(car_z), sc->undefined);
  52683. y = let_slots(sc->envir);
  52684. slot_set_expression(y, cadr(car_z));
  52685. slot_set_pending_value(y, sc->nil);
  52686. if (!top)
  52687. {
  52688. top = y;
  52689. nxt = top;
  52690. }
  52691. else
  52692. {
  52693. slot_set_pending_value(nxt, y);
  52694. nxt = y;
  52695. }
  52696. }
  52697. }
  52698. else
  52699. {
  52700. if (!is_keyword(car_z))
  52701. make_slot_1(sc, sc->envir, car_z, sc->F);
  52702. else
  52703. {
  52704. if (car_z == sc->key_rest_symbol)
  52705. {
  52706. make_slot_1(sc, sc->envir, cadr(z), sc->nil);
  52707. z = cdr(z);
  52708. }
  52709. }
  52710. }
  52711. }
  52712. if (is_symbol(z))
  52713. make_slot_1(sc, sc->envir, z, sc->nil);
  52714. lambda_star_set_args(sc); /* load up current arg vals */
  52715. if (top)
  52716. {
  52717. /* get default values, which may involve evaluation */
  52718. push_stack(sc, OP_LAMBDA_STAR_DEFAULT, sc->args, sc->code); /* op is just a placeholder (don't use OP_BARRIER here) */
  52719. sc->args = top;
  52720. if (lambda_star_default(sc) == goto_EVAL) return(goto_EVAL);
  52721. pop_stack_no_op(sc); /* get original args and code back */
  52722. }
  52723. sc->code = closure_body(sc->code);
  52724. return(goto_BEGIN1);
  52725. }
  52726. static void apply_continuation(s7_scheme *sc) /* -------- continuation ("call/cc") -------- */
  52727. {
  52728. if (!call_with_current_continuation(sc))
  52729. {
  52730. static s7_pointer cc_err = NULL;
  52731. if (!cc_err) cc_err = s7_make_permanent_string("continuation can't jump into with-baffle");
  52732. s7_error(sc, sc->baffled_symbol, set_elist_1(sc, cc_err));
  52733. }
  52734. }
  52735. static void apply_c_object(s7_scheme *sc) /* -------- applicable (new-type) object -------- */
  52736. {
  52737. sc->value = (*(c_object_ref(sc->code)))(sc, sc->code, sc->args);
  52738. }
  52739. /* -------------------------------------------------------------------------------- */
  52740. static int define1_ex(s7_scheme *sc)
  52741. {
  52742. /* sc->code is the symbol being defined, sc->value is its value
  52743. * if sc->value is a closure, car is of the form ((args...) body...)
  52744. * so the doc string if any is (cadr (car value))
  52745. * and the arg list gives the number of optional args up to the dot
  52746. */
  52747. /* it's not possible to expand and replace macros at this point without evaluating
  52748. * the body. Just as examples, say we have a macro "mac",
  52749. * (define (hi) (call/cc (lambda (mac) (mac 1))))
  52750. * (define (hi) (quote (mac 1))) or macroexpand etc
  52751. * (define (hi mac) (mac 1)) assuming mac here is a function passed as an arg,
  52752. * etc...
  52753. */
  52754. /* the immutable constant check needs to wait until we have the actual new value because
  52755. * we want to ignore the rebinding (not raise an error) if it is the existing value.
  52756. * This happens when we reload a file that calls define-constant.
  52757. */
  52758. if (is_immutable(sc->code)) /* (define pi 3) or (define (pi a) a) */
  52759. {
  52760. s7_pointer x;
  52761. if (!is_symbol(sc->code)) /* (define "pi" 3) ? */
  52762. eval_error_no_return(sc, sc->syntax_error_symbol, "define: ~S is immutable", sc->code);
  52763. x = global_slot(sc->code);
  52764. if ((!is_slot(x)) ||
  52765. (type(sc->value) != unchecked_type(slot_value(x))) ||
  52766. (!s7_is_morally_equal(sc, sc->value, slot_value(x)))) /* if value is unchanged, just ignore this (re)definition */
  52767. eval_error_no_return(sc, sc->syntax_error_symbol, "define: ~S is immutable", sc->code); /* can't use s7_is_equal because value might be NaN, etc */
  52768. }
  52769. if (symbol_has_accessor(sc->code))
  52770. {
  52771. s7_pointer x;
  52772. x = find_symbol(sc, sc->code);
  52773. if ((is_slot(x)) &&
  52774. (slot_has_accessor(x)))
  52775. {
  52776. sc->value = bind_accessed_symbol(sc, OP_DEFINE_WITH_ACCESSOR, sc->code, sc->value);
  52777. if (sc->value == sc->no_value)
  52778. return(goto_APPLY);
  52779. /* if all goes well, OP_DEFINE_WITH_ACCESSOR will jump to DEFINE2 */
  52780. }
  52781. }
  52782. return(fall_through);
  52783. }
  52784. static void define2_ex(s7_scheme *sc)
  52785. {
  52786. if ((is_any_closure(sc->value)) &&
  52787. ((!(is_let(closure_let(sc->value)))) ||
  52788. (!(is_function_env(closure_let(sc->value)))))) /* otherwise it's (define f2 f1) or something similar */
  52789. {
  52790. s7_pointer new_func, new_env;
  52791. new_func = sc->value;
  52792. new_cell_no_check(sc, new_env, T_LET | T_FUNCTION_ENV);
  52793. let_id(new_env) = ++sc->let_number;
  52794. set_outlet(new_env, closure_let(new_func));
  52795. closure_set_let(new_func, new_env);
  52796. let_set_slots(new_env, sc->nil);
  52797. funclet_set_function(new_env, sc->code);
  52798. if (/* (!is_let(sc->envir)) && */
  52799. (port_filename(sc->input_port)) &&
  52800. (port_file(sc->input_port) != stdin))
  52801. {
  52802. /* unbound_variable will be called if __func__ is encountered, and will return this info as if __func__ had some meaning */
  52803. let_set_file(new_env, port_file_number(sc->input_port));
  52804. let_set_line(new_env, port_line_number(sc->input_port));
  52805. }
  52806. else
  52807. {
  52808. let_set_file(new_env, 0);
  52809. let_set_line(new_env, 0);
  52810. }
  52811. /* this should happen only if the closure* default values do not refer in any way to
  52812. * the enclosing environment (else we can accidentally shadow something that happens
  52813. * to share an argument name that is being used as a default value -- kinda dumb!).
  52814. * I think I'll check this before setting the safe_closure bit.
  52815. */
  52816. if (is_safe_closure(new_func))
  52817. {
  52818. int i;
  52819. s7_pointer arg;
  52820. for (i = 0, arg = closure_args(new_func); is_pair(arg); i++, arg = cdr(arg))
  52821. {
  52822. if (is_pair(car(arg)))
  52823. make_slot_1(sc, new_env, caar(arg), sc->nil);
  52824. else make_slot_1(sc, new_env, car(arg), sc->nil);
  52825. }
  52826. let_set_slots(new_env, reverse_slots(sc, let_slots(new_env)));
  52827. }
  52828. /* add the newly defined thing to the current environment */
  52829. if (is_let(sc->envir))
  52830. {
  52831. add_slot(sc->envir, sc->code, new_func);
  52832. set_local(sc->code);
  52833. /* so funchecked is always local already -- perhaps reset below? */
  52834. }
  52835. else s7_make_slot(sc, sc->envir, sc->code, new_func);
  52836. sc->value = new_func; /* 25-Jul-14 so define returns the value not the name */
  52837. }
  52838. else
  52839. {
  52840. s7_pointer lx;
  52841. /* add the newly defined thing to the current environment */
  52842. lx = find_local_symbol(sc, sc->code, sc->envir);
  52843. if (is_slot(lx))
  52844. slot_set_value(lx, sc->value);
  52845. else s7_make_slot(sc, sc->envir, sc->code, sc->value);
  52846. }
  52847. }
  52848. /* ---------------------------------------- */
  52849. static void clear_all_optimizations(s7_scheme *sc, s7_pointer p)
  52850. {
  52851. /* I believe that we would not have been optimized to begin with if the tree were circular,
  52852. * and this tree is supposed to be a function call + args -- a circular list here is a bug.
  52853. */
  52854. if (is_pair(p))
  52855. {
  52856. if ((is_optimized(p)) &&
  52857. ((optimize_op(p) & 1) == 0)) /* protect possibly shared code? Elsewhere we assume these aren't changed */
  52858. {
  52859. clear_optimized(p);
  52860. clear_optimize_op(p);
  52861. /* these apparently make no difference */
  52862. set_opt_con1(p, sc->nil);
  52863. set_opt_con2(p, sc->nil);
  52864. }
  52865. clear_all_optimizations(sc, cdr(p));
  52866. clear_all_optimizations(sc, car(p));
  52867. }
  52868. }
  52869. static bool a_is_ok(s7_scheme *sc, s7_pointer p)
  52870. {
  52871. /* "A" here need not be a function call or "p" a pair (all_x_c etc) */
  52872. if (is_pair(p))
  52873. {
  52874. if ((is_optimized(p)) &&
  52875. (!c_function_is_ok(sc, p)))
  52876. return(false);
  52877. if (car(p) != sc->quote_symbol)
  52878. return((a_is_ok(sc, car(p))) &&
  52879. (a_is_ok(sc, cdr(p))));
  52880. }
  52881. return(true);
  52882. }
  52883. #define c_function_is_ok_cadr(Sc, P) ((c_function_is_ok(Sc, P)) && (c_function_is_ok(Sc, cadr(P))))
  52884. #define c_function_is_ok_caddr(Sc, P) ((c_function_is_ok(Sc, P)) && (c_function_is_ok(Sc, caddr(P))))
  52885. #define c_function_is_ok_cadr_caddr(Sc, P) ((c_function_is_ok(Sc, P)) && (c_function_is_ok(Sc, cadr(P))) && (c_function_is_ok(Sc, caddr(P))))
  52886. #define a_is_ok_cadr(Sc, P) ((c_function_is_ok(Sc, P)) && (a_is_ok(Sc, cadr(P))))
  52887. #define a_is_ok_caddr(Sc, P) ((c_function_is_ok(Sc, P)) && (a_is_ok(Sc, caddr(P))))
  52888. #define a_is_ok_cadddr(Sc, P) ((c_function_is_ok(Sc, P)) && (a_is_ok(Sc, cadddr(P))))
  52889. #if WITH_PROFILE
  52890. static void profile(s7_scheme *sc, s7_pointer expr)
  52891. {
  52892. if (is_null(sc->profile_info))
  52893. {
  52894. sc->profile_info = s7_make_hash_table(sc, 65536);
  52895. s7_gc_protect(sc, sc->profile_info);
  52896. }
  52897. if ((is_pair(expr)) &&
  52898. (has_line_number(expr)))
  52899. {
  52900. s7_pointer val, key;
  52901. key = s7_make_integer(sc, pair_line(expr));
  52902. val = s7_hash_table_ref(sc, sc->profile_info, key);
  52903. if (val == sc->F)
  52904. s7_hash_table_set(sc, sc->profile_info, key, cons(sc, make_mutable_integer(sc, 1), expr));
  52905. else integer(car(val))++;
  52906. }
  52907. }
  52908. #endif
  52909. /* -------------------------------- eval -------------------------------- */
  52910. #if WITH_GCC
  52911. #undef new_cell
  52912. #if (!DEBUGGING)
  52913. #define new_cell(Sc, Obj, Type) \
  52914. do { \
  52915. if (Sc->free_heap_top <= Sc->free_heap_trigger) {try_to_call_gc(Sc); if ((Sc->begin_hook) && (call_begin_hook(Sc))) return(Sc->F);} \
  52916. Obj = (*(--(Sc->free_heap_top))); \
  52917. set_type(Obj, Type); \
  52918. } while (0)
  52919. #else
  52920. #define new_cell(Sc, Obj, Type) \
  52921. do { \
  52922. if ((Sc->free_heap_top <= Sc->free_heap_trigger) || (for_any_other_reason(sc, __LINE__))) {last_gc_line = __LINE__; last_gc_func = __func__; try_to_call_gc(Sc); if ((Sc->begin_hook) && (call_begin_hook(Sc))) return(Sc->F);} \
  52923. Obj = (*(--(Sc->free_heap_top))); \
  52924. Obj->alloc_line = __LINE__; Obj->alloc_func = __func__; \
  52925. set_type(Obj, Type); \
  52926. } while (0)
  52927. #endif
  52928. #endif
  52929. #if WITH_GMP
  52930. #define global_add big_add
  52931. #else
  52932. #define global_add g_add
  52933. #endif
  52934. static s7_pointer check_for_cyclic_code(s7_scheme *sc, s7_pointer code)
  52935. {
  52936. if (cyclic_sequences(sc, code, false) == sc->T)
  52937. eval_error(sc, "attempt to evaluate a circular list: ~A", code);
  52938. resize_stack(sc);
  52939. return(sc->F);
  52940. }
  52941. static s7_pointer eval(s7_scheme *sc, opcode_t first_op)
  52942. {
  52943. sc->op = first_op;
  52944. /* this procedure can be entered recursively (via s7_call for example), so it's no place for a setjmp
  52945. * I don't think the recursion can hurt our continuations because s7_call is coming from hooks and
  52946. * callbacks that are implicit in our stack.
  52947. */
  52948. goto START_WITHOUT_POP_STACK;
  52949. /* this ugly two-step is faster than other ways of writing this code */
  52950. while (true)
  52951. {
  52952. START:
  52953. pop_stack(sc);
  52954. /* syntax_opcode can be optimize_op, the field can be set at read time, we could
  52955. * probably combine the optimized and normal case statements, jump here if eval (eval_pair, opt_eval),
  52956. * and thereby save the is_syntactic and is_pair check in op_eval, op_begin would explicitly jump back here, no op_eval,
  52957. * current trailers would be outside? and where would eval args go? Huge change, might save 1% if lucky.
  52958. * see end of file -- I think this is too pessimistic and given rearrangement of the s7_cell layout,
  52959. * can be done without an increase in size.
  52960. *
  52961. * about half the cases don't care about args or op, but it's not simple to distribute the sc->args
  52962. * setting throughout this switch statement. Lots of branches fall through to the next and there
  52963. * are many internal goto's to branches, so the code becomes a mess. sc->op is even worse because
  52964. * we use it in several cases for error information or choice of next op, etc.
  52965. */
  52966. START_WITHOUT_POP_STACK:
  52967. /* fprintf(stderr, "%s (%d)\n", op_names[sc->op], (int)(sc->op)); */
  52968. switch (sc->op)
  52969. {
  52970. case OP_NO_OP:
  52971. break;
  52972. case OP_READ_INTERNAL:
  52973. /* if we're loading a file, and in the file we evaluate something like:
  52974. * (let ()
  52975. * (set-current-input-port (open-input-file "tmp2.r5rs"))
  52976. * (close-input-port (current-input-port)))
  52977. * ... (with no reset of input port to its original value)
  52978. * the load process tries to read the loaded string, but the sc->input_port is now closed,
  52979. * and the original is inaccessible! So we get a segfault in token. We don't want to put
  52980. * a port_is_closed check there because token only rarely is in this danger. I think this
  52981. * is the only place where we can be about to call token, and someone has screwed up our port.
  52982. *
  52983. * We can't call read_error here because it assumes the input string is ok!
  52984. */
  52985. if (port_is_closed(sc->input_port))
  52986. return(s7_error(sc, sc->read_error_symbol, set_elist_1(sc, make_string_wrapper(sc, "our input port got clobbered!"))));
  52987. sc->tok = token(sc);
  52988. switch (sc->tok)
  52989. {
  52990. case TOKEN_EOF:
  52991. {
  52992. /* (eval-string "'a ; b") gets here with 'a -> a, so we need to squelch the pending eval.
  52993. * another approach would read-ahead in eval_string_1_ex, but this seems less messy.
  52994. */
  52995. int top;
  52996. top = s7_stack_top(sc) - 1;
  52997. if (stack_op(sc->stack, top) == OP_EVAL_STRING_1)
  52998. vector_element(sc->stack, top) = (s7_pointer)OP_EVAL_STRING_2;
  52999. }
  53000. break;
  53001. case TOKEN_RIGHT_PAREN:
  53002. read_error(sc, "unexpected close paren");
  53003. case TOKEN_COMMA:
  53004. read_error(sc, "unexpected comma");
  53005. default:
  53006. sc->value = read_expression(sc);
  53007. sc->current_line = port_line_number(sc->input_port); /* this info is used to track down missing close parens */
  53008. sc->current_file = port_filename(sc->input_port);
  53009. break;
  53010. }
  53011. break;
  53012. /* (read p) from scheme
  53013. * "p" becomes current input port for eval's duration, then pops back before returning value into calling expr
  53014. */
  53015. case OP_READ_DONE:
  53016. pop_input_port(sc);
  53017. if (sc->tok == TOKEN_EOF)
  53018. sc->value = sc->eof_object;
  53019. sc->current_file = NULL; /* this is for error handling */
  53020. break;
  53021. /* load("file"); from C (g_load) -- assume caller will clean up
  53022. * read and evaluate exprs until EOF that matches (stack reflects nesting)
  53023. */
  53024. case OP_LOAD_RETURN_IF_EOF: /* loop here until eof (via push stack below) */
  53025. if (sc->tok != TOKEN_EOF)
  53026. {
  53027. push_stack(sc, OP_LOAD_RETURN_IF_EOF, sc->nil, sc->nil);
  53028. push_stack(sc, OP_READ_INTERNAL, sc->nil, sc->nil);
  53029. sc->code = sc->value;
  53030. goto EVAL; /* we read an expression, now evaluate it, and return to read the next */
  53031. }
  53032. sc->current_file = NULL;
  53033. return(sc->F);
  53034. /* (load "file") in scheme
  53035. * read and evaluate all exprs, then upon EOF, close current and pop input port stack
  53036. */
  53037. case OP_LOAD_CLOSE_AND_POP_IF_EOF:
  53038. if (sc->tok != TOKEN_EOF)
  53039. {
  53040. push_stack(sc, OP_LOAD_CLOSE_AND_POP_IF_EOF, sc->nil, sc->nil); /* was push args, code */
  53041. if ((!is_string_port(sc->input_port)) ||
  53042. (port_position(sc->input_port) < port_data_size(sc->input_port)))
  53043. {
  53044. push_stack(sc, OP_READ_INTERNAL, sc->nil, sc->nil);
  53045. }
  53046. else sc->tok = TOKEN_EOF;
  53047. sc->code = sc->value;
  53048. goto EVAL; /* we read an expression, now evaluate it, and return to read the next */
  53049. }
  53050. s7_close_input_port(sc, sc->input_port);
  53051. pop_input_port(sc);
  53052. sc->current_file = NULL;
  53053. if (is_multiple_value(sc->value)) /* (load "file") where "file" is (values 1 2 3) */
  53054. sc->value = splice_in_values(sc, multiple_value(sc->value));
  53055. break;
  53056. case OP_EVAL_STRING_2:
  53057. s7_close_input_port(sc, sc->input_port);
  53058. pop_input_port(sc);
  53059. if (is_multiple_value(sc->value))
  53060. sc->value = splice_in_values(sc, multiple_value(sc->value));
  53061. break;
  53062. case OP_EVAL_STRING_1:
  53063. eval_string_1_ex(sc);
  53064. goto EVAL;
  53065. /* -------------------- sort! (heapsort, done directly so that call/cc in the sort function will work correctly) -------------------- */
  53066. #define SORT_N integer(vector_element(sc->code, 0))
  53067. #define SORT_K integer(vector_element(sc->code, 1))
  53068. #define SORT_J integer(vector_element(sc->code, 2))
  53069. #define SORT_K1 integer(vector_element(sc->code, 3))
  53070. #define SORT_CALLS integer(vector_element(sc->code, 4))
  53071. #define SORT_STOP integer(vector_element(sc->code, 5))
  53072. #define SORT_DATA(K) vector_element(car(sc->args), K)
  53073. #define SORT_LESSP cadr(sc->args)
  53074. HEAPSORT:
  53075. {
  53076. s7_int n, j, k;
  53077. s7_pointer lx;
  53078. n = SORT_N;
  53079. k = SORT_K1;
  53080. if ((n == k) || (k > ((s7_int)(n / 2)))) /* k == n == 0 is the first case */
  53081. goto START;
  53082. if (sc->safety != 0)
  53083. {
  53084. SORT_CALLS++;
  53085. if (SORT_CALLS > SORT_STOP)
  53086. eval_range_error(sc, "sort! is caught in an infinite loop, comparison: ~S", SORT_LESSP);
  53087. }
  53088. j = 2 * k;
  53089. SORT_J = j;
  53090. if (j < n)
  53091. {
  53092. push_stack(sc, OP_SORT1, sc->args, sc->code);
  53093. lx = SORT_LESSP; /* cadr of sc->args */
  53094. if (needs_copied_args(lx))
  53095. sc->args = list_2(sc, SORT_DATA(j), SORT_DATA(j + 1));
  53096. else
  53097. {
  53098. set_car(sc->t2_1, SORT_DATA(j));
  53099. set_car(sc->t2_2, SORT_DATA(j + 1));
  53100. sc->args = sc->t2_1;
  53101. }
  53102. sc->code = lx;
  53103. goto APPLY;
  53104. }
  53105. else sc->value = sc->F;
  53106. }
  53107. case OP_SORT1:
  53108. {
  53109. s7_int j, k;
  53110. s7_pointer lx;
  53111. k = SORT_K1;
  53112. j = SORT_J;
  53113. if (is_true(sc, sc->value))
  53114. {
  53115. j = j + 1;
  53116. SORT_J = j;
  53117. }
  53118. push_stack(sc, OP_SORT2, sc->args, sc->code);
  53119. lx = SORT_LESSP;
  53120. if (needs_copied_args(lx))
  53121. sc->args = list_2(sc, SORT_DATA(k), SORT_DATA(j));
  53122. else
  53123. {
  53124. set_car(sc->t2_1, SORT_DATA(k));
  53125. set_car(sc->t2_2, SORT_DATA(j));
  53126. sc->args = sc->t2_1;
  53127. }
  53128. sc->code = lx;
  53129. goto APPLY;
  53130. }
  53131. case OP_SORT2:
  53132. {
  53133. s7_int j, k;
  53134. k = SORT_K1;
  53135. j = SORT_J;
  53136. if (is_true(sc, sc->value))
  53137. {
  53138. s7_pointer lx;
  53139. lx = SORT_DATA(j);
  53140. SORT_DATA(j) = SORT_DATA(k);
  53141. SORT_DATA(k) = lx;
  53142. }
  53143. else goto START;
  53144. SORT_K1 = SORT_J;
  53145. goto HEAPSORT;
  53146. }
  53147. case OP_SORT:
  53148. /* coming in sc->args is sort args (data less?), sc->code = '(n k 0)
  53149. * here we call the inner loop until k <= 0 [the local k! -- this is tricky because scheme passes args by value]
  53150. */
  53151. {
  53152. s7_int k;
  53153. k = SORT_K;
  53154. if (k > 0)
  53155. {
  53156. SORT_K = k - 1;
  53157. SORT_K1 = k - 1;
  53158. push_stack(sc, OP_SORT, sc->args, sc->code);
  53159. goto HEAPSORT;
  53160. }
  53161. /* else fall through */
  53162. }
  53163. case OP_SORT3:
  53164. {
  53165. s7_int n;
  53166. s7_pointer lx;
  53167. n = SORT_N;
  53168. if (n <= 0)
  53169. {
  53170. sc->value = car(sc->args);
  53171. goto START;
  53172. }
  53173. lx = SORT_DATA(0);
  53174. SORT_DATA(0) = SORT_DATA(n);
  53175. SORT_DATA(n) = lx;
  53176. SORT_N = n - 1;
  53177. SORT_K1 = 0;
  53178. push_stack(sc, OP_SORT3, sc->args, sc->code);
  53179. goto HEAPSORT;
  53180. }
  53181. case OP_SORT_PAIR_END: /* sc->value is the sort vector which needs to be copied into the original list */
  53182. sc->value = vector_into_list(sc->value, car(sc->args));
  53183. break;
  53184. case OP_SORT_VECTOR_END: /* sc->value is the sort (s7_pointer) vector which needs to be copied into the original (double/int) vector */
  53185. sc->value = vector_into_fi_vector(sc->value, car(sc->args));
  53186. break;
  53187. case OP_SORT_STRING_END:
  53188. sc->value = vector_into_string(sc->value, car(sc->args));
  53189. break;
  53190. /* batcher networks:
  53191. * ((0 2) (0 1) (1 2))
  53192. * ((0 2) (1 3) (0 1) (2 3) (1 2))
  53193. * etc -- see batcher in s7test.scm (from Doug Hoyte)
  53194. * but since it has to be done here by hand, it turns into too much code, 3 is:
  53195. * < l0 l2 ?
  53196. * no goto L1
  53197. * < l0 l1 ?
  53198. * no return 1 0 2
  53199. * < l1 l2?
  53200. * yes return 0 1 2 (direct)
  53201. * no return 0 2 1
  53202. * L1:
  53203. * < l0 l1 ?
  53204. * yes return 2 0 1
  53205. * < l1 l2 ?
  53206. * yes return 1 2 0
  53207. * no return 2 1 0
  53208. * since each "<" op above goes to OP_APPLY, we have ca 5 labels, and ca 25-50 lines
  53209. */
  53210. /* -------------------------------- MAP -------------------------------- */
  53211. case OP_MAP_GATHER_1:
  53212. if (sc->value != sc->no_value)
  53213. {
  53214. if (is_multiple_value(sc->value))
  53215. counter_set_result(sc->args, revappend(sc, multiple_value(sc->value), counter_result(sc->args)));
  53216. else counter_set_result(sc->args, cons(sc, sc->value, counter_result(sc->args)));
  53217. }
  53218. case OP_MAP_1:
  53219. {
  53220. s7_pointer x, args, code, p;
  53221. code = sc->code;
  53222. args = sc->args;
  53223. p = counter_list(args);
  53224. x = s7_iterate(sc, p);
  53225. if (iterator_is_at_end(p))
  53226. {
  53227. sc->value = safe_reverse_in_place(sc, counter_result(args));
  53228. goto START;
  53229. }
  53230. push_stack(sc, OP_MAP_GATHER_1, args, code);
  53231. if (counter_capture(args) != sc->capture_let_counter)
  53232. {
  53233. new_frame_with_slot(sc, closure_let(code), sc->envir, car(closure_args(code)), x);
  53234. counter_set_let(args, sc->envir);
  53235. counter_set_slots(args, let_slots(sc->envir));
  53236. counter_set_capture(args, sc->capture_let_counter);
  53237. }
  53238. else
  53239. {
  53240. /* the counter_slots field saves the original local let slot(s) representing the function
  53241. * argument. If the function has internal defines, they get added to the front of the
  53242. * slots list, but old_frame_with_slot (maybe stupidly) assumes only the one original
  53243. * slot exists when it updates its symbol_id from the (possibly changed) let_id. So,
  53244. * a subsequent reference to the parameter name causes "unbound variable", or a segfault
  53245. * if the check has been optimized away. I think each function call should start with
  53246. * the original let slots, so counter_slots saves that pointer, and resets it here.
  53247. */
  53248. let_set_slots(counter_let(args), counter_slots(args));
  53249. sc->envir = old_frame_with_slot(sc, counter_let(args), x);
  53250. }
  53251. sc->code = closure_body(code);
  53252. goto BEGIN1;
  53253. }
  53254. case OP_MAP_GATHER:
  53255. if (sc->value != sc->no_value) /* (map (lambda (x) (values)) (list 1)) */
  53256. {
  53257. if (is_multiple_value(sc->value)) /* (map (lambda (x) (if (odd? x) (values x (* x 20)) (values))) (list 1 2 3 4)) */
  53258. counter_set_result(sc->args, revappend(sc, multiple_value(sc->value), counter_result(sc->args)));
  53259. /* not append_in_place here because sc->value has the multiple-values bit set */
  53260. else counter_set_result(sc->args, cons(sc, sc->value, counter_result(sc->args)));
  53261. }
  53262. case OP_MAP:
  53263. {
  53264. s7_pointer y, iterators;
  53265. iterators = counter_list(sc->args);
  53266. sc->x = sc->nil; /* can't use preset args list here (as in for-each): (map list '(a b c)) */
  53267. for (y = iterators; is_pair(y); y = cdr(y))
  53268. {
  53269. s7_pointer x;
  53270. x = s7_iterate(sc, car(y));
  53271. if (iterator_is_at_end(car(y)))
  53272. {
  53273. sc->value = safe_reverse_in_place(sc, counter_result(sc->args));
  53274. /* here and below it is not safe to pre-release sc->args (the counter) */
  53275. goto START;
  53276. }
  53277. sc->x = cons(sc, x, sc->x);
  53278. }
  53279. sc->x = safe_reverse_in_place(sc, sc->x);
  53280. push_stack(sc, OP_MAP_GATHER, sc->args, sc->code);
  53281. sc->args = sc->x;
  53282. sc->x = sc->nil;
  53283. if (needs_copied_args(sc->code))
  53284. sc->args = copy_list(sc, sc->args);
  53285. goto APPLY;
  53286. }
  53287. /* -------------------------------- FOR-EACH -------------------------------- */
  53288. case OP_FOR_EACH:
  53289. {
  53290. s7_pointer x, y, iterators, saved_args;
  53291. iterators = car(sc->args);
  53292. saved_args = cdr(sc->args);
  53293. for (x = saved_args, y = iterators; is_pair(x); x = cdr(x), y = cdr(y))
  53294. {
  53295. set_car(x, s7_iterate(sc, car(y)));
  53296. if (iterator_is_at_end(car(y)))
  53297. {
  53298. sc->value = sc->unspecified;
  53299. goto START;
  53300. }
  53301. }
  53302. push_stack(sc, OP_FOR_EACH, sc->args, sc->code);
  53303. sc->args = saved_args;
  53304. if (needs_copied_args(sc->code))
  53305. sc->args = copy_list(sc, sc->args);
  53306. goto APPLY;
  53307. }
  53308. /* for-each et al remake the local frame, but that's only needed if the local env is exported,
  53309. * and that can only happen through make-closure in various guises and curlet.
  53310. * owlet captures, but it would require a deliberate error to use it in this context.
  53311. * c_objects call object_set_let but that requires a prior curlet or sublet. So we have
  53312. * sc->capture_let_counter that is incremented every time an environment is captured, then
  53313. * here we save that ctr, call body, on rerun check ctr, if it has not changed we are safe and can reuse frame.
  53314. */
  53315. case OP_FOR_EACH_1:
  53316. {
  53317. s7_pointer code, counter, p, arg;
  53318. counter = sc->args;
  53319. p = counter_list(counter);
  53320. arg = s7_iterate(sc, p);
  53321. if (iterator_is_at_end(p))
  53322. {
  53323. sc->value = sc->unspecified;
  53324. goto START;
  53325. }
  53326. code = sc->code;
  53327. if (counter_capture(counter) != sc->capture_let_counter)
  53328. {
  53329. new_frame_with_slot(sc, closure_let(code), sc->envir, car(closure_args(code)), arg);
  53330. counter_set_let(counter, sc->envir);
  53331. counter_set_slots(counter, let_slots(sc->envir));
  53332. counter_set_capture(counter, sc->capture_let_counter);
  53333. }
  53334. else
  53335. {
  53336. let_set_slots(counter_let(counter), counter_slots(counter));
  53337. sc->envir = old_frame_with_slot(sc, counter_let(counter), arg);
  53338. }
  53339. push_stack(sc, OP_FOR_EACH_1, counter, code);
  53340. sc->code = closure_body(code);
  53341. goto BEGIN1;
  53342. }
  53343. case OP_FOR_EACH_3:
  53344. case OP_FOR_EACH_2:
  53345. {
  53346. s7_pointer code, c, lst, arg;
  53347. c = sc->args; /* the counter */
  53348. lst = counter_list(c);
  53349. if (!is_pair(lst)) /* '(1 2 . 3) as arg? -- counter_list can be anything here */
  53350. {
  53351. sc->value = sc->unspecified;
  53352. goto START;
  53353. }
  53354. code = sc->code;
  53355. arg = car(lst);
  53356. counter_set_list(c, cdr(lst));
  53357. if (sc->op == OP_FOR_EACH_3)
  53358. {
  53359. counter_set_result(c, cdr(counter_result(c)));
  53360. if (counter_result(c) == counter_list(c))
  53361. {
  53362. sc->value = sc->unspecified;
  53363. goto START;
  53364. }
  53365. push_stack(sc, OP_FOR_EACH_2, c, code);
  53366. }
  53367. else push_stack(sc, OP_FOR_EACH_3, c, code);
  53368. if (counter_capture(c) != sc->capture_let_counter)
  53369. {
  53370. new_frame_with_slot(sc, closure_let(code), sc->envir, car(closure_args(code)), arg);
  53371. counter_set_let(c, sc->envir);
  53372. counter_set_slots(c, let_slots(sc->envir));
  53373. counter_set_capture(c, sc->capture_let_counter);
  53374. }
  53375. else
  53376. {
  53377. let_set_slots(counter_let(c), counter_slots(c));
  53378. sc->envir = old_frame_with_slot(sc, counter_let(c), arg);
  53379. }
  53380. sc->code = closure_body(code);
  53381. goto BEGIN1;
  53382. }
  53383. /* -------------------------------- MEMBER -------------------------------- */
  53384. case OP_MEMBER_IF:
  53385. case OP_MEMBER_IF1:
  53386. /* code=func, args = (list original args) with opt_fast->position in cadr (the list), value = result of comparison
  53387. */
  53388. if (sc->value != sc->F) /* previous comparison was not #f -- return list */
  53389. {
  53390. sc->value = opt_fast(sc->args);
  53391. goto START;
  53392. }
  53393. if (!is_pair(cdr(opt_fast(sc->args)))) /* no more args -- return #f */
  53394. {
  53395. sc->value = sc->F;
  53396. goto START;
  53397. }
  53398. set_opt_fast(sc->args, cdr(opt_fast(sc->args))); /* cdr down arg list */
  53399. if (sc->op == OP_MEMBER_IF1)
  53400. {
  53401. /* circular list check */
  53402. if (opt_fast(sc->args) == opt_slow(sc->args))
  53403. {
  53404. sc->value = sc->F;
  53405. goto START;
  53406. }
  53407. set_opt_slow(sc->args, cdr(opt_slow(sc->args))); /* cdr down the slow list (check for circular list) */
  53408. push_stack(sc, OP_MEMBER_IF, sc->args, sc->code);
  53409. }
  53410. else push_stack(sc, OP_MEMBER_IF1, sc->args, sc->code);
  53411. if (needs_copied_args(sc->code))
  53412. sc->args = list_2(sc, caar(sc->args), car(opt_fast(sc->args)));
  53413. else sc->args = set_plist_2(sc, caar(sc->args), car(opt_fast(sc->args)));
  53414. goto APPLY;
  53415. /* -------------------------------- ASSOC -------------------------------- */
  53416. case OP_ASSOC_IF:
  53417. case OP_ASSOC_IF1:
  53418. /* code=func, args=(list args) with f/opt_fast=list, value=result of comparison
  53419. * (assoc 3 '((1 . a) (2 . b) (3 . c) (4 . d)) =)
  53420. */
  53421. if (sc->value != sc->F) /* previous comparison was not #f -- return (car list) */
  53422. {
  53423. sc->value = car(opt_fast(sc->args));
  53424. goto START;
  53425. }
  53426. if (!is_pair(cdr(opt_fast(sc->args)))) /* (assoc 3 '((1 . 2) . 3) =) or nil */
  53427. {
  53428. sc->value = sc->F;
  53429. goto START;
  53430. }
  53431. set_opt_fast(sc->args, cdr(opt_fast(sc->args))); /* cdr down arg list */
  53432. if (sc->op == OP_ASSOC_IF1)
  53433. {
  53434. /* circular list check */
  53435. if (opt_fast(sc->args) == opt_slow(sc->args))
  53436. {
  53437. sc->value = sc->F;
  53438. goto START;
  53439. }
  53440. set_opt_slow(sc->args, cdr(opt_slow(sc->args))); /* cdr down the slow list */
  53441. push_stack(sc, OP_ASSOC_IF, sc->args, sc->code);
  53442. }
  53443. else push_stack(sc, OP_ASSOC_IF1, sc->args, sc->code);
  53444. if (!is_pair(car(opt_fast(sc->args)))) /* (assoc 1 '((2 . 2) 3) =) -- we access caaadr below */
  53445. eval_type_error(sc, "assoc: second arg is not an alist: ~S", sc->args);
  53446. /* not sure about this -- we could simply skip the entry both here and in g_assoc
  53447. * (assoc 1 '((2 . 2) 3)) -> #f
  53448. * (assoc 1 '((2 . 2) 3) =) -> error currently
  53449. */
  53450. if (needs_copied_args(sc->code))
  53451. sc->args = list_2(sc, caar(sc->args), caar(opt_fast(sc->args)));
  53452. else sc->args = set_plist_2(sc, caar(sc->args), caar(opt_fast(sc->args)));
  53453. goto APPLY;
  53454. /* -------------------------------- DO -------------------------------- */
  53455. SAFE_DOTIMES:
  53456. case OP_SAFE_DOTIMES:
  53457. {
  53458. int choice;
  53459. choice = safe_dotimes_ex(sc);
  53460. if (choice == goto_SAFE_DO_END_CLAUSES) goto SAFE_DO_END_CLAUSES;
  53461. if (choice == goto_BEGIN1) goto BEGIN1;
  53462. if (choice == goto_OPT_EVAL) goto OPT_EVAL;
  53463. if (choice == goto_START_WITHOUT_POP_STACK) goto START_WITHOUT_POP_STACK;
  53464. pair_set_syntax_symbol(sc->code, sc->simple_do_symbol);
  53465. goto SIMPLE_DO;
  53466. }
  53467. case OP_SAFE_DOTIMES_STEP_P:
  53468. {
  53469. s7_pointer arg;
  53470. arg = slot_value(sc->args);
  53471. numerator(arg)++;
  53472. if (numerator(arg) == denominator(arg))
  53473. {
  53474. sc->code = cdr(cadr(sc->code));
  53475. goto DO_END_CLAUSES;
  53476. }
  53477. push_stack(sc, OP_SAFE_DOTIMES_STEP_P, sc->args, sc->code);
  53478. sc->code = opt_pair2(sc->code);
  53479. sc->op = (opcode_t)pair_syntax_op(sc->code);
  53480. sc->code = cdr(sc->code);
  53481. goto START_WITHOUT_POP_STACK;
  53482. }
  53483. case OP_SAFE_DOTIMES_STEP_O:
  53484. {
  53485. s7_pointer arg;
  53486. arg = slot_value(sc->args);
  53487. numerator(arg)++;
  53488. if (numerator(arg) == denominator(arg))
  53489. {
  53490. sc->code = cdr(cadr(sc->code));
  53491. goto DO_END_CLAUSES;
  53492. }
  53493. push_stack(sc, OP_SAFE_DOTIMES_STEP_O, sc->args, sc->code);
  53494. sc->code = opt_pair2(sc->code);
  53495. goto OPT_EVAL;
  53496. }
  53497. case OP_SAFE_DOTIMES_STEP_A:
  53498. {
  53499. s7_pointer arg;
  53500. /* no calls?? */
  53501. arg = slot_value(sc->args);
  53502. set_car(sc->t2_1, arg);
  53503. set_car(sc->t2_2, sc->value);
  53504. c_call(opt_pair2(sc->code))(sc, sc->t2_1);
  53505. numerator(arg)++;
  53506. if (numerator(arg) == denominator(arg))
  53507. {
  53508. sc->code = cdr(cadr(sc->code));
  53509. goto DO_END_CLAUSES;
  53510. }
  53511. push_stack(sc, OP_SAFE_DOTIMES_STEP_A, sc->args, sc->code);
  53512. sc->code = caddr(opt_pair2(sc->code));
  53513. goto OPT_EVAL;
  53514. }
  53515. case OP_SAFE_DOTIMES_STEP:
  53516. {
  53517. s7_pointer arg;
  53518. arg = slot_value(sc->args);
  53519. numerator(arg)++;
  53520. if (numerator(arg) == denominator(arg))
  53521. {
  53522. sc->code = cdr(cadr(sc->code));
  53523. goto DO_END_CLAUSES;
  53524. }
  53525. push_stack(sc, OP_SAFE_DOTIMES_STEP, sc->args, sc->code);
  53526. arg = opt_pair2(sc->code);
  53527. /* here we know the body has more than one form */
  53528. push_stack_no_args(sc, OP_BEGIN1, cdr(arg));
  53529. sc->code = car(arg);
  53530. goto EVAL;
  53531. }
  53532. SAFE_DO:
  53533. case OP_SAFE_DO:
  53534. {
  53535. int choice;
  53536. choice = safe_do_ex(sc);
  53537. if (choice == goto_SAFE_DO_END_CLAUSES) goto SAFE_DO_END_CLAUSES;
  53538. if (choice == goto_EVAL) goto EVAL;
  53539. if (choice == goto_DO_UNCHECKED) goto DO_UNCHECKED;
  53540. goto BEGIN1;
  53541. }
  53542. case OP_SAFE_DO_STEP:
  53543. {
  53544. s7_int step, end;
  53545. s7_pointer args, code, slot;
  53546. args = sc->envir;
  53547. code = sc->code;
  53548. slot = dox_slot1(args);
  53549. step = s7_integer(slot_value(slot)) + 1;
  53550. slot_set_value(slot, make_integer(sc, step));
  53551. end = s7_integer(slot_value(dox_slot2(args)));
  53552. if ((step == end) ||
  53553. ((step > end) &&
  53554. (opt_cfunc(caadr(code)) == geq_2)))
  53555. {
  53556. sc->code = cdadr(code);
  53557. goto DO_END_CLAUSES;
  53558. }
  53559. push_stack(sc, OP_SAFE_DO_STEP, sc->args, code);
  53560. sc->code = opt_pair2(code);
  53561. goto BEGIN1;
  53562. }
  53563. SIMPLE_DO_P:
  53564. case OP_SIMPLE_DO_P:
  53565. sc->op = OP_SIMPLE_DO_P;
  53566. goto SIMPLE_DO;
  53567. SIMPLE_DO_E:
  53568. case OP_SIMPLE_DO_E:
  53569. sc->op = OP_SIMPLE_DO_E;
  53570. goto SIMPLE_DO;
  53571. SIMPLE_DO_A:
  53572. case OP_SIMPLE_DO_A:
  53573. sc->op = OP_SIMPLE_DO_A;
  53574. SIMPLE_DO:
  53575. case OP_SIMPLE_DO:
  53576. {
  53577. /* body might not be safe in this case, but the step and end exprs are easy
  53578. * "not safe" merely means we hit something that the optimizer can't specialize like (+ (* (abs (- ...))))
  53579. */
  53580. s7_pointer init, end, code;
  53581. code = sc->code;
  53582. sc->envir = new_frame_in_env(sc, sc->envir);
  53583. init = cadaar(code);
  53584. if (is_symbol(init))
  53585. sc->value = find_symbol_checked(sc, init);
  53586. else
  53587. {
  53588. if (is_pair(init))
  53589. sc->value = c_call(init)(sc, cdr(init));
  53590. else sc->value = init;
  53591. }
  53592. dox_set_slot1(sc->envir, make_slot_1(sc, sc->envir, caaar(code), sc->value));
  53593. end = caddr(caadr(code));
  53594. if (is_symbol(end))
  53595. sc->args = find_symbol(sc, end);
  53596. else
  53597. {
  53598. s7_pointer slot;
  53599. new_cell_no_check(sc, slot, T_SLOT);
  53600. slot_set_symbol(slot, sc->dox_slot_symbol);
  53601. slot_set_value(slot, end);
  53602. sc->args = slot;
  53603. }
  53604. dox_set_slot2(sc->envir, sc->args);
  53605. set_car(sc->t2_1, slot_value(dox_slot1(sc->envir)));
  53606. set_car(sc->t2_2, slot_value(dox_slot2(sc->envir)));
  53607. if (is_true(sc, c_call(caadr(code))(sc, sc->t2_1)))
  53608. {
  53609. sc->code = cdadr(code);
  53610. goto DO_END_CLAUSES;
  53611. }
  53612. if (sc->op == OP_SIMPLE_DO_P)
  53613. {
  53614. push_stack(sc, OP_SIMPLE_DO_STEP_P, sc->args, code);
  53615. sc->code = caddr(code);
  53616. goto EVAL;
  53617. }
  53618. set_opt_pair2(code, cddr(code));
  53619. if ((is_null(cdr(opt_pair2(code)))) &&
  53620. (is_pair(car(opt_pair2(code)))) &&
  53621. (is_symbol(cadr(caddr(caar(code)))))) /* caar=(i 0 (+ i 1)), caddr=(+ i 1), so this is apparently checking that the stepf is reasonable? */
  53622. {
  53623. int choice;
  53624. choice = simple_do_ex(sc, code);
  53625. if (choice == goto_START) goto START;
  53626. if (choice == goto_BEGIN1) goto BEGIN1;
  53627. if (choice == goto_DO_END_CLAUSES) goto DO_END_CLAUSES;
  53628. }
  53629. if (sc->op == OP_SIMPLE_DO_E)
  53630. push_stack(sc, OP_SIMPLE_DO_STEP_E, sc->args, code);
  53631. else
  53632. {
  53633. if (sc->op == OP_SIMPLE_DO_A)
  53634. push_stack(sc, OP_SIMPLE_DO_STEP_A, sc->args, code);
  53635. else push_stack(sc, OP_SIMPLE_DO_STEP, sc->args, code);
  53636. }
  53637. sc->code = opt_pair2(code);
  53638. goto BEGIN1;
  53639. }
  53640. case OP_SIMPLE_DO_STEP_P:
  53641. case OP_SIMPLE_DO_STEP:
  53642. {
  53643. s7_pointer step, ctr, end, code;
  53644. ctr = dox_slot1(sc->envir);
  53645. end = dox_slot2(sc->envir);
  53646. code = sc->code;
  53647. step = caddr(caar(code));
  53648. if (is_symbol(cadr(step)))
  53649. {
  53650. set_car(sc->t2_1, slot_value(ctr));
  53651. set_car(sc->t2_2, caddr(step));
  53652. }
  53653. else
  53654. {
  53655. set_car(sc->t2_2, slot_value(ctr));
  53656. set_car(sc->t2_1, cadr(step));
  53657. }
  53658. slot_set_value(ctr, c_call(step)(sc, sc->t2_1));
  53659. set_car(sc->t2_1, slot_value(ctr));
  53660. set_car(sc->t2_2, slot_value(end));
  53661. if (is_true(sc, c_call(caadr(code))(sc, sc->t2_1)))
  53662. {
  53663. sc->code = cdr(cadr(code));
  53664. goto DO_END_CLAUSES;
  53665. }
  53666. push_stack(sc, sc->op, sc->args, code);
  53667. if (sc->op == OP_SIMPLE_DO_STEP_P)
  53668. {
  53669. code = caddr(code);
  53670. set_current_code(sc, code);
  53671. sc->op = (opcode_t)pair_syntax_op(code);
  53672. sc->code = cdr(code);
  53673. goto START_WITHOUT_POP_STACK;
  53674. }
  53675. sc->code = opt_pair2(code);
  53676. goto BEGIN1;
  53677. }
  53678. case OP_SIMPLE_DO_STEP_E:
  53679. case OP_SIMPLE_DO_STEP_A:
  53680. {
  53681. /* (((i 0 (+ i 1))) ((= i 1000)) (set! mx (max mx (abs (f1 signal)))) (set! signal 0.0))
  53682. * (((i 0 (+ i 1))) ((= i 20)) (outa i (sine-env e)))
  53683. * we checked in check_do that the step expr is s+1
  53684. */
  53685. s7_pointer val, ctr, end, code;
  53686. s7_int index;
  53687. code = sc->code;
  53688. ctr = dox_slot1(sc->envir);
  53689. val = slot_value(ctr);
  53690. end = slot_value(dox_slot2(sc->envir));
  53691. if (is_integer(val))
  53692. {
  53693. slot_set_value(ctr, make_integer(sc, index = integer(val) + 1));
  53694. if (is_integer(end))
  53695. {
  53696. if (index == integer(end))
  53697. {
  53698. sc->code = cdr(cadr(code));
  53699. goto DO_END_CLAUSES;
  53700. }
  53701. }
  53702. else
  53703. {
  53704. set_car(sc->t2_1, slot_value(ctr));
  53705. set_car(sc->t2_2, end);
  53706. if (is_true(sc, g_equal_2(sc, sc->t2_1)))
  53707. {
  53708. sc->code = cdr(cadr(code));
  53709. goto DO_END_CLAUSES;
  53710. }
  53711. }
  53712. }
  53713. else
  53714. {
  53715. set_car(sc->t1_1, val); /* add_s1 ignores cadr(args) */
  53716. slot_set_value(ctr, g_add_s1(sc, sc->t1_1));
  53717. set_car(sc->t2_1, slot_value(ctr));
  53718. set_car(sc->t2_2, end);
  53719. if (is_true(sc, g_equal_2(sc, sc->t2_1)))
  53720. {
  53721. sc->code = cdr(cadr(code));
  53722. goto DO_END_CLAUSES;
  53723. }
  53724. }
  53725. push_stack(sc, sc->op, sc->args, code);
  53726. if (sc->op == OP_SIMPLE_DO_STEP_E)
  53727. {
  53728. sc->code = car(opt_pair2(code));
  53729. goto OPT_EVAL;
  53730. }
  53731. sc->code = opt_pair2(code);
  53732. goto BEGIN1;
  53733. }
  53734. DOTIMES_P:
  53735. case OP_DOTIMES_P:
  53736. {
  53737. int choice;
  53738. choice = dotimes_p_ex(sc);
  53739. if (choice == goto_DO_END_CLAUSES) goto DO_END_CLAUSES;
  53740. if (choice == goto_DO_UNCHECKED) goto DO_UNCHECKED;
  53741. goto EVAL;
  53742. }
  53743. case OP_DOTIMES_STEP_P:
  53744. {
  53745. s7_pointer ctr, now, end, code, end_test;
  53746. code = sc->code;
  53747. ctr = dox_slot1(sc->envir);
  53748. now = slot_value(ctr);
  53749. end = slot_value(dox_slot2(sc->envir));
  53750. end_test = opt_pair2(code);
  53751. if (is_integer(now))
  53752. {
  53753. slot_set_value(ctr, make_integer(sc, integer(now) + 1));
  53754. now = slot_value(ctr);
  53755. if (is_integer(end))
  53756. {
  53757. if ((integer(now) == integer(end)) ||
  53758. ((integer(now) > integer(end)) &&
  53759. (opt_cfunc(end_test) == geq_2)))
  53760. {
  53761. sc->code = cdadr(code);
  53762. goto DO_END_CLAUSES;
  53763. }
  53764. }
  53765. else
  53766. {
  53767. set_car(sc->t2_1, now);
  53768. set_car(sc->t2_2, end);
  53769. if (is_true(sc, c_call(end_test)(sc, sc->t2_1)))
  53770. {
  53771. sc->code = cdadr(code);
  53772. goto DO_END_CLAUSES;
  53773. }
  53774. }
  53775. }
  53776. else
  53777. {
  53778. set_car(sc->t1_1, now);
  53779. slot_set_value(ctr, g_add_s1(sc, sc->t1_1));
  53780. /* (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)) */
  53781. set_car(sc->t2_1, slot_value(ctr));
  53782. set_car(sc->t2_2, end);
  53783. if (is_true(sc, c_call(end_test)(sc, sc->t2_1)))
  53784. {
  53785. sc->code = cdadr(code);
  53786. goto DO_END_CLAUSES;
  53787. }
  53788. }
  53789. push_stack(sc, OP_DOTIMES_STEP_P, sc->args, code);
  53790. code = caddr(code);
  53791. set_current_code(sc, code);
  53792. sc->op = (opcode_t)pair_syntax_op(code);
  53793. sc->code = cdr(code);
  53794. goto START_WITHOUT_POP_STACK;
  53795. }
  53796. DOX:
  53797. case OP_DOX:
  53798. {
  53799. int choice;
  53800. choice = dox_ex(sc);
  53801. if (choice == goto_DO_END_CLAUSES) goto DO_END_CLAUSES;
  53802. if (choice == goto_START) goto START;
  53803. if (choice == goto_BEGIN1) goto BEGIN1;
  53804. if (choice == goto_START_WITHOUT_POP_STACK) goto START_WITHOUT_POP_STACK;
  53805. push_stack_no_args(sc, OP_DOX_STEP, sc->code);
  53806. sc->code = cddr(sc->code);
  53807. goto BEGIN1;
  53808. }
  53809. case OP_DOX_STEP:
  53810. {
  53811. s7_pointer slot;
  53812. for (slot = let_slots(sc->envir); is_slot(slot); slot = next_slot(slot))
  53813. if (is_pair(slot_expression(slot)))
  53814. slot_set_value(slot, c_call(slot_expression(slot))(sc, car(slot_expression(slot))));
  53815. if (is_true(sc, c_call(cdr(sc->code))(sc, opt_pair2(sc->code))))
  53816. {
  53817. sc->code = cdadr(sc->code);
  53818. goto DO_END_CLAUSES;
  53819. }
  53820. push_stack_no_args(sc, OP_DOX_STEP, sc->code);
  53821. sc->code = cddr(sc->code);
  53822. goto BEGIN1;
  53823. }
  53824. case OP_DOX_STEP_P:
  53825. {
  53826. s7_pointer slot;
  53827. for (slot = let_slots(sc->envir); is_slot(slot); slot = next_slot(slot))
  53828. if (is_pair(slot_expression(slot)))
  53829. slot_set_value(slot, c_call(slot_expression(slot))(sc, car(slot_expression(slot))));
  53830. if (is_true(sc, c_call(cdr(sc->code))(sc, opt_pair2(sc->code))))
  53831. {
  53832. sc->code = cdadr(sc->code);
  53833. goto DO_END_CLAUSES;
  53834. }
  53835. push_stack_no_args(sc, OP_DOX_STEP_P, sc->code);
  53836. sc->code = caddr(sc->code);
  53837. sc->op = (opcode_t)pair_syntax_op(sc->code);
  53838. sc->code = cdr(sc->code);
  53839. goto START_WITHOUT_POP_STACK;
  53840. }
  53841. /* we could use slot_pending_value, slot_expression, not this extra list, but the list seems simpler. */
  53842. #define DO_VAR_SLOT(P) opt_slot1(P)
  53843. #define DO_VAR_NEW_VALUE(P) cdr(P)
  53844. #define DO_VAR_SET_NEW_VALUE(P, Val) set_cdar(P, Val)
  53845. #define DO_VAR_STEP_EXPR(P) car(P)
  53846. DO_STEP:
  53847. case OP_DO_STEP:
  53848. /* increment all vars, return to endtest
  53849. * these are also updated in parallel at the end, so we gather all the incremented values first
  53850. *
  53851. * here we know car(sc->args) is not null, args is the list of steppable vars,
  53852. * any unstepped vars in the do var section are not in this list, so
  53853. * (do ((i 0 (+ i 1)) (j 2)) ...)
  53854. * arrives here with sc->args:
  53855. * '(((+ i 1) . 0))
  53856. */
  53857. push_stack(sc, OP_DO_END, sc->args, sc->code);
  53858. sc->args = car(sc->args); /* the var data lists */
  53859. sc->code = sc->args; /* save the top of the list */
  53860. DO_STEP1:
  53861. /* on each iteration, each arg incr expr is evaluated and the value placed in caddr while we cdr down args
  53862. * finally args is nil...
  53863. */
  53864. if (is_null(sc->args))
  53865. {
  53866. s7_pointer x;
  53867. for (x = sc->code; is_not_null(x); x = cdr(x))
  53868. slot_set_value(DO_VAR_SLOT(car(x)), DO_VAR_NEW_VALUE(car(x)));
  53869. /* some schemes rebind here, rather than reset, but that is expensive,
  53870. * and only matters once in a blue moon (closure over enclosed lambda referring to a do var)
  53871. * and the caller can easily mimic the correct behavior in that case by adding a let or using a named let,
  53872. * making the rebinding explicit.
  53873. *
  53874. * Hmmm... I'll leave this alone, but there are other less cut-and-dried cases:
  53875. * (let ((j (lambda () 0))
  53876. * (k 0))
  53877. * (do ((i (j) (j))
  53878. * (j (lambda () 1) (lambda () (+ i 1)))) ; bind here hits different "i" than set!
  53879. * ((= i 3) k)
  53880. * (set! k (+ k i))))
  53881. * is it 6 or 3?
  53882. *
  53883. * if we had a way to tell that there were no lambdas in the do expression, would that
  53884. * guarantee that set was ok? Here's a bad case:
  53885. * (let ((f #f))
  53886. * (do ((i 0 (+ i 1)))
  53887. * ((= i 3))
  53888. * (let () ; so that the define is ok
  53889. * (define (x) i)
  53890. * (if (= i 1) (set! f x))))
  53891. * (f))
  53892. * s7 says 3, guile says 1.
  53893. *
  53894. * I wonder if what they're actually talking about is a kind of shared value problem. If we
  53895. * set the value directly (not the cdr(binding) but, for example, integer(cdr(binding))), then
  53896. * every previous reference gets changed as a side-effect. In the current code, we're "binding"
  53897. * the value in the sense that on each step, a new value is assigned to the step variable.
  53898. * In the "direct" case, (let ((v #(0 0 0))) (do ((i 0 (+ i 1))) ((= i 3) v) (set! (v i) i))
  53899. * would return #(3 3 3).
  53900. *
  53901. * if sc->capture_let_counter changes, would it be sufficient to simply make a new slot?
  53902. * I think not; the closure retains the current env chain, not the slots, so we need a new env.
  53903. */
  53904. sc->value = sc->nil;
  53905. pop_stack_no_op(sc);
  53906. goto DO_END;
  53907. }
  53908. push_stack(sc, OP_DO_STEP2, sc->args, sc->code);
  53909. /* here sc->args is a list like (((i . 0) (+ i 1) 0) ...)
  53910. * so sc->code becomes (+ i 1) in this case
  53911. */
  53912. sc->code = DO_VAR_STEP_EXPR(car(sc->args));
  53913. goto EVAL;
  53914. case OP_DO_STEP2:
  53915. DO_VAR_SET_NEW_VALUE(sc->args, sc->value); /* save current value */
  53916. sc->args = cdr(sc->args); /* go to next step var */
  53917. goto DO_STEP1;
  53918. case OP_DO: /* sc->code is the stuff after "do" */
  53919. if (is_null(check_do(sc)))
  53920. {
  53921. s7_pointer op;
  53922. op = car(opt_back(sc->code));
  53923. if (op == sc->dox_symbol) goto DOX;
  53924. if (op == sc->safe_dotimes_symbol) goto SAFE_DOTIMES;
  53925. if (op == sc->dotimes_p_symbol) goto DOTIMES_P;
  53926. if (op == sc->safe_do_symbol) goto SAFE_DO;
  53927. if (op == sc->simple_do_a_symbol) goto SIMPLE_DO_A;
  53928. if (op == sc->simple_do_e_symbol) goto SIMPLE_DO_E;
  53929. if (op == sc->simple_do_symbol) goto SIMPLE_DO;
  53930. goto SIMPLE_DO_P;
  53931. }
  53932. DO_UNCHECKED:
  53933. case OP_DO_UNCHECKED:
  53934. if (is_null(car(sc->code))) /* (do () ...) -- (let ((i 0)) (do () ((= i 1)) (set! i 1))) */
  53935. {
  53936. sc->envir = new_frame_in_env(sc, sc->envir);
  53937. sc->args = cons_unchecked(sc, sc->nil, cadr(sc->code));
  53938. sc->code = cddr(sc->code);
  53939. goto DO_END;
  53940. }
  53941. /* eval each init value, then set up the new frame (like let, not let*) */
  53942. sc->args = sc->nil; /* the evaluated var-data */
  53943. sc->value = sc->code; /* protect it */
  53944. sc->code = car(sc->code); /* the vars */
  53945. case OP_DO_INIT:
  53946. if (do_init_ex(sc) == goto_EVAL)
  53947. goto EVAL;
  53948. /* fall through */
  53949. DO_END:
  53950. case OP_DO_END:
  53951. /* here vars have been init'd or incr'd
  53952. * args = (list var-data end-expr return-expr-if-any)
  53953. * if (do ((i 0 (+ i 1))) ((= i 3) 10)), args: (vars (= i 3) 10)
  53954. * if (do ((i 0 (+ i 1))) ((= i 3))), args: (vars (= i 3)) and result expr is () == (begin)
  53955. * if (do ((i 0 (+ i 1))) (#t 10 12)), args: (vars #t 10 12), result: ([begin] 10 12) -> 12
  53956. * if (call-with-exit (lambda (r) (do () () (r)))), args: '(())
  53957. * code = body
  53958. */
  53959. if (is_not_null(cdr(sc->args)))
  53960. {
  53961. push_stack(sc, OP_DO_END1, sc->args, sc->code);
  53962. sc->code = cadr(sc->args); /* evaluate the end expr */
  53963. goto EVAL;
  53964. }
  53965. else
  53966. {
  53967. /* (do ((...)) () ...) -- no endtest */
  53968. if (is_pair(sc->code))
  53969. {
  53970. if (is_null(car(sc->args)))
  53971. push_stack(sc, OP_DO_END, sc->args, sc->code);
  53972. else push_stack(sc, OP_DO_STEP, sc->args, sc->code);
  53973. goto BEGIN1;
  53974. }
  53975. else
  53976. {
  53977. /* no body? */
  53978. if (is_null(car(sc->args)))
  53979. goto DO_END;
  53980. goto DO_STEP;
  53981. }
  53982. }
  53983. case OP_DO_END1:
  53984. /* sc->value is the result of end-test evaluation */
  53985. if (is_true(sc, sc->value))
  53986. {
  53987. /* we're done -- deal with result exprs
  53988. * if there isn't an end test, there also isn't a result (they're in the same list)
  53989. */
  53990. sc->code = cddr(sc->args); /* result expr (a list -- implicit begin) */
  53991. free_cell(sc, sc->args);
  53992. sc->args = sc->nil;
  53993. if (is_null(sc->code))
  53994. {
  53995. sc->value = sc->nil;
  53996. goto START;
  53997. }
  53998. }
  53999. else
  54000. {
  54001. /* evaluate the body and step vars, etc */
  54002. if (is_null(car(sc->args)))
  54003. push_stack(sc, OP_DO_END, sc->args, sc->code);
  54004. else push_stack(sc, OP_DO_STEP, sc->args, sc->code);
  54005. /* sc->code is ready to go */
  54006. }
  54007. goto BEGIN1;
  54008. SAFE_DO_END_CLAUSES:
  54009. if (is_null(sc->code))
  54010. {
  54011. /* sc->args = sc->nil; */
  54012. sc->envir = free_let(sc, sc->envir);
  54013. sc->value = sc->nil;
  54014. goto START;
  54015. }
  54016. goto DO_END_CODE;
  54017. DO_END_CLAUSES:
  54018. if (is_null(sc->code))
  54019. {
  54020. sc->value = sc->nil;
  54021. goto START;
  54022. }
  54023. DO_END_CODE:
  54024. if (is_pair(cdr(sc->code)))
  54025. {
  54026. push_stack_no_args(sc, OP_BEGIN1, cdr(sc->code));
  54027. sc->code = car(sc->code);
  54028. goto EVAL;
  54029. }
  54030. sc->code = car(sc->code);
  54031. if (is_pair(sc->code))
  54032. goto EVAL;
  54033. if (is_symbol(sc->code))
  54034. sc->value = find_symbol_checked(sc, sc->code);
  54035. else sc->value = sc->code;
  54036. goto START;
  54037. /* -------------------------------- BEGIN -------------------------------- */
  54038. case OP_BEGIN:
  54039. if (!is_proper_list(sc, sc->code)) /* proper list includes nil, I think */
  54040. eval_error(sc, "unexpected dot? ~A", sc->code);
  54041. if ((!is_null(sc->code)) && /* so check for it here */
  54042. (!is_null(cdr(sc->code))) &&
  54043. (is_overlaid(sc->code)) &&
  54044. (has_opt_back(sc->code)))
  54045. pair_set_syntax_symbol(sc->code, sc->begin_unchecked_symbol);
  54046. case OP_BEGIN_UNCHECKED:
  54047. /* if ((sc->begin_hook) && (call_begin_hook(sc))) return(sc->F); */
  54048. if (is_null(sc->code)) /* (begin) -> () */
  54049. {
  54050. sc->value = sc->nil;
  54051. goto START;
  54052. }
  54053. case OP_BEGIN1:
  54054. if ((sc->begin_hook) && (call_begin_hook(sc))) return(sc->F);
  54055. BEGIN1:
  54056. #if DEBUGGING
  54057. if (!s7_is_list(sc, sc->code)) abort();
  54058. #endif
  54059. if (is_pair(cdr(sc->code))) /* sc->code can be nil here, but cdr(nil)->#<unspecified> */
  54060. push_stack_no_args(sc, OP_BEGIN1, cdr(sc->code));
  54061. sc->code = car(sc->code);
  54062. /* goto EVAL; */
  54063. EVAL:
  54064. case OP_EVAL:
  54065. /* main part of evaluation
  54066. * at this point, it's sc->code we care about; sc->args is not relevant.
  54067. */
  54068. /* fprintf(stderr, " eval: %s %d %d\n", DISPLAY_80(sc->code), (typesflag(sc->code) == SYNTACTIC_PAIR), (is_optimized(sc->code))); */
  54069. if (typesflag(sc->code) == SYNTACTIC_PAIR) /* xor is not faster here */
  54070. {
  54071. #if WITH_PROFILE
  54072. profile(sc, sc->code);
  54073. #endif
  54074. set_current_code(sc, sc->code); /* in case an error occurs, this helps tell us where we are */
  54075. sc->op = (opcode_t)pair_syntax_op(sc->code);
  54076. sc->code = cdr(sc->code);
  54077. goto START_WITHOUT_POP_STACK; /* it is only slightly faster to use labels as values (computed gotos) here */
  54078. }
  54079. if (is_optimized(sc->code))
  54080. {
  54081. s7_pointer code;
  54082. /* fprintf(stderr, " %s\n", opt_names[optimize_op(sc->code)]); */
  54083. OPT_EVAL:
  54084. #if WITH_PROFILE
  54085. profile(sc, sc->code);
  54086. #endif
  54087. code = sc->code;
  54088. set_current_code(sc, code);
  54089. switch (optimize_op(code))
  54090. {
  54091. /* -------------------------------------------------------------------------------- */
  54092. case OP_SAFE_C_C:
  54093. if (!c_function_is_ok(sc, code)) break;
  54094. case HOP_SAFE_C_C:
  54095. sc->value = c_call(code)(sc, cdr(code)); /* this includes all safe calls where all args are constants */
  54096. goto START;
  54097. case OP_SAFE_C_Q:
  54098. if (!c_function_is_ok(sc, code)) break;
  54099. case HOP_SAFE_C_Q:
  54100. set_car(sc->t1_1, cadr(cadr(code)));
  54101. sc->value = c_call(code)(sc, sc->t1_1);
  54102. goto START;
  54103. case OP_SAFE_C_S:
  54104. if (!c_function_is_ok(sc, code)) break;
  54105. case HOP_SAFE_C_S:
  54106. set_car(sc->t1_1, find_symbol_checked(sc, cadr(code)));
  54107. sc->value = c_call(code)(sc, sc->t1_1);
  54108. goto START;
  54109. case OP_SAFE_C_SS:
  54110. if (!c_function_is_ok(sc, code)) break;
  54111. case HOP_SAFE_C_SS:
  54112. {
  54113. s7_pointer val, args;
  54114. args = cdr(code);
  54115. val = find_symbol_checked(sc, car(args));
  54116. set_car(sc->t2_2, find_symbol_checked(sc, cadr(args)));
  54117. set_car(sc->t2_1, val);
  54118. sc->value = c_call(code)(sc, sc->t2_1);
  54119. goto START;
  54120. }
  54121. case OP_SAFE_C_ALL_S:
  54122. if (!c_function_is_ok(sc, code)) break;
  54123. case HOP_SAFE_C_ALL_S:
  54124. {
  54125. int num_args;
  54126. s7_pointer args, p;
  54127. num_args = integer(arglist_length(code));
  54128. if ((num_args != 0) &&
  54129. (num_args < NUM_SAFE_LISTS) &&
  54130. (!list_is_in_use(sc->safe_lists[num_args])))
  54131. {
  54132. sc->args = sc->safe_lists[num_args];
  54133. set_list_in_use(sc->args);
  54134. }
  54135. else sc->args = make_list(sc, num_args, sc->nil);
  54136. for (args = cdr(code), p = sc->args; is_pair(args); args = cdr(args), p = cdr(p))
  54137. set_car(p, find_symbol_checked(sc, car(args)));
  54138. clear_list_in_use(sc->args);
  54139. sc->value = c_call(code)(sc, sc->args);
  54140. goto START;
  54141. }
  54142. case OP_SAFE_C_SC:
  54143. if (!c_function_is_ok(sc, code)) break;
  54144. case HOP_SAFE_C_SC:
  54145. {
  54146. s7_pointer args;
  54147. args = cdr(code);
  54148. set_car(sc->t2_1, find_symbol_checked(sc, car(args)));
  54149. set_car(sc->t2_2, cadr(args));
  54150. sc->value = c_call(code)(sc, sc->t2_1);
  54151. goto START;
  54152. }
  54153. case OP_SAFE_C_CS:
  54154. if (!c_function_is_ok(sc, code)) break;
  54155. case HOP_SAFE_C_CS:
  54156. {
  54157. s7_pointer args;
  54158. args = cdr(code);
  54159. set_car(sc->t2_2, find_symbol_checked(sc, cadr(args)));
  54160. set_car(sc->t2_1, car(args));
  54161. sc->value = c_call(code)(sc, sc->t2_1);
  54162. goto START;
  54163. }
  54164. case OP_SAFE_C_SQ:
  54165. if (!c_function_is_ok(sc, code)) break;
  54166. case HOP_SAFE_C_SQ:
  54167. {
  54168. s7_pointer args;
  54169. args = cdr(code);
  54170. set_car(sc->t2_1, find_symbol_checked(sc, car(args)));
  54171. set_car(sc->t2_2, cadr(cadr(args)));
  54172. sc->value = c_call(code)(sc, sc->t2_1);
  54173. goto START;
  54174. }
  54175. case OP_SAFE_C_QS:
  54176. if (!c_function_is_ok(sc, code)) break;
  54177. case HOP_SAFE_C_QS:
  54178. {
  54179. s7_pointer args;
  54180. args = cdr(code);
  54181. set_car(sc->t2_2, find_symbol_checked(sc, cadr(args)));
  54182. set_car(sc->t2_1, cadr(car(args)));
  54183. sc->value = c_call(code)(sc, sc->t2_1);
  54184. goto START;
  54185. }
  54186. case OP_SAFE_C_QQ:
  54187. if (!c_function_is_ok(sc, code)) break;
  54188. case HOP_SAFE_C_QQ:
  54189. {
  54190. s7_pointer args;
  54191. args = cdr(code);
  54192. set_car(sc->t2_1, cadr(car(args)));
  54193. set_car(sc->t2_2, cadr(cadr(args)));
  54194. sc->value = c_call(code)(sc, sc->t2_1);
  54195. goto START;
  54196. }
  54197. case OP_SAFE_C_CQ:
  54198. if (!c_function_is_ok(sc, code)) break;
  54199. case HOP_SAFE_C_CQ:
  54200. {
  54201. s7_pointer args;
  54202. args = cdr(code);
  54203. set_car(sc->t2_1, car(args));
  54204. set_car(sc->t2_2, cadr(cadr(args)));
  54205. sc->value = c_call(code)(sc, sc->t2_1);
  54206. goto START;
  54207. }
  54208. case OP_SAFE_C_QC:
  54209. if (!c_function_is_ok(sc, code)) break;
  54210. case HOP_SAFE_C_QC:
  54211. {
  54212. s7_pointer args;
  54213. args = cdr(code);
  54214. set_car(sc->t2_1, cadr(car(args)));
  54215. set_car(sc->t2_2, cadr(args));
  54216. sc->value = c_call(code)(sc, sc->t2_1);
  54217. goto START;
  54218. }
  54219. case OP_SAFE_C_Z:
  54220. if (!c_function_is_ok(sc, code)) break;
  54221. /* I think a_is_ok of cadr here and below is redundant -- they'll be checked when Z is
  54222. * because we cleared the hop bit after combine_ops.
  54223. */
  54224. case HOP_SAFE_C_Z:
  54225. check_stack_size(sc);
  54226. push_stack(sc, OP_SAFE_C_P_1, sc->nil, code);
  54227. sc->code = cadr(code);
  54228. goto OPT_EVAL;
  54229. case OP_SAFE_C_CZ:
  54230. if (!c_function_is_ok(sc, code)) break;
  54231. case HOP_SAFE_C_CZ:
  54232. check_stack_size(sc);
  54233. /* it's possible in a case like this to overflow the stack -- s7test has a deeply
  54234. * nested expression involving (+ c (+ c (+ ... ))) all opt'd as safe_c_cz -- if we're close
  54235. * to the stack end at the start, it runs off the end. Normally the stack increase in
  54236. * the reader protects us, but a call/cc can replace the original stack with a much smaller one.
  54237. * How to minimize the cost of this check?
  54238. */
  54239. push_stack(sc, OP_SAFE_C_SZ_1, cadr(code), code);
  54240. sc->code = caddr(code);
  54241. goto OPT_EVAL;
  54242. case OP_SAFE_C_ZC:
  54243. if (!c_function_is_ok(sc, code)) break;
  54244. case HOP_SAFE_C_ZC:
  54245. check_stack_size(sc);
  54246. push_stack(sc, OP_SAFE_C_ZC_1, caddr(code), code); /* need ZC_1 here in case multiple values encountered */
  54247. sc->code = cadr(code);
  54248. goto OPT_EVAL;
  54249. case OP_SAFE_C_SZ:
  54250. if (!c_function_is_ok(sc, code)) break;
  54251. case HOP_SAFE_C_SZ:
  54252. check_stack_size(sc);
  54253. push_stack(sc, OP_SAFE_C_SZ_1, find_symbol_checked(sc, cadr(code)), code);
  54254. sc->code = caddr(code); /* splitting out the all_x cases here and elsewhere saves nothing */
  54255. goto OPT_EVAL;
  54256. case OP_SAFE_C_ZS:
  54257. if (!c_function_is_ok(sc, code)) break;
  54258. case HOP_SAFE_C_ZS:
  54259. check_stack_size(sc);
  54260. push_stack(sc, OP_EVAL_ARGS_P_3, sc->nil, code);
  54261. sc->code = cadr(code);
  54262. goto OPT_EVAL;
  54263. case OP_SAFE_C_opAq:
  54264. if (!a_is_ok_cadr(sc, code)) break;
  54265. case HOP_SAFE_C_opAq:
  54266. {
  54267. s7_pointer arg;
  54268. arg = cadr(code);
  54269. set_car(sc->a1_1, c_call(cdr(arg))(sc, cadr(arg)));
  54270. set_car(sc->t1_1, c_call(arg)(sc, sc->a1_1));
  54271. sc->value = c_call(code)(sc, sc->t1_1);
  54272. goto START;
  54273. }
  54274. case OP_SAFE_C_opAAq:
  54275. if (!a_is_ok_cadr(sc, code)) break;
  54276. case HOP_SAFE_C_opAAq:
  54277. {
  54278. s7_pointer arg;
  54279. arg = cadr(code);
  54280. set_car(sc->a2_1, c_call(cdr(arg))(sc, cadr(arg)));
  54281. set_car(sc->a2_2, c_call(cddr(arg))(sc, caddr(arg)));
  54282. set_car(sc->t1_1, c_call(arg)(sc, sc->a2_1));
  54283. sc->value = c_call(code)(sc, sc->t1_1);
  54284. goto START;
  54285. }
  54286. case OP_SAFE_C_opAAAq:
  54287. if (!a_is_ok_cadr(sc, code)) break;
  54288. case HOP_SAFE_C_opAAAq:
  54289. {
  54290. s7_pointer arg;
  54291. arg = cadr(code);
  54292. set_car(sc->a3_1, c_call(cdr(arg))(sc, cadr(arg)));
  54293. set_car(sc->a3_2, c_call(cddr(arg))(sc, caddr(arg)));
  54294. set_car(sc->a3_3, c_call(cdddr(arg))(sc, cadddr(arg)));
  54295. set_car(sc->t1_1, c_call(arg)(sc, sc->a3_1));
  54296. sc->value = c_call(code)(sc, sc->t1_1);
  54297. goto START;
  54298. }
  54299. case OP_SAFE_C_S_opAq:
  54300. if (!a_is_ok_caddr(sc, code)) break;
  54301. case HOP_SAFE_C_S_opAq:
  54302. {
  54303. s7_pointer arg;
  54304. arg = caddr(code);
  54305. set_car(sc->a1_1, c_call(cdr(arg))(sc, cadr(arg)));
  54306. set_car(sc->t2_2, c_call(arg)(sc, sc->a1_1));
  54307. set_car(sc->t2_1, find_symbol_checked(sc, cadr(code)));
  54308. sc->value = c_call(code)(sc, sc->t2_1);
  54309. goto START;
  54310. }
  54311. case OP_SAFE_C_S_opAAq:
  54312. if (!a_is_ok_caddr(sc, code)) break;
  54313. case HOP_SAFE_C_S_opAAq:
  54314. {
  54315. s7_pointer arg;
  54316. arg = caddr(code);
  54317. set_car(sc->a2_1, c_call(cdr(arg))(sc, cadr(arg)));
  54318. set_car(sc->a2_2, c_call(cddr(arg))(sc, caddr(arg)));
  54319. set_car(sc->t2_2, c_call(arg)(sc, sc->a2_1));
  54320. set_car(sc->t2_1, find_symbol_checked(sc, cadr(code)));
  54321. sc->value = c_call(code)(sc, sc->t2_1);
  54322. goto START;
  54323. }
  54324. case OP_SAFE_C_S_opAAAq:
  54325. if (!a_is_ok_caddr(sc, code)) break;
  54326. case HOP_SAFE_C_S_opAAAq:
  54327. {
  54328. s7_pointer arg, p;
  54329. p = caddr(code);
  54330. arg = cdr(p);
  54331. set_car(sc->a3_1, c_call(arg)(sc, car(arg)));
  54332. arg = cdr(arg);
  54333. set_car(sc->a3_2, c_call(arg)(sc, car(arg)));
  54334. arg = cdr(arg);
  54335. set_car(sc->a3_3, c_call(arg)(sc, car(arg)));
  54336. set_car(sc->t2_2, c_call(p)(sc, sc->a3_1));
  54337. set_car(sc->t2_1, find_symbol_checked(sc, cadr(code)));
  54338. sc->value = c_call(code)(sc, sc->t2_1);
  54339. goto START;
  54340. }
  54341. case OP_SAFE_C_S_opSZq:
  54342. if (!a_is_ok_caddr(sc, code)) break;
  54343. case HOP_SAFE_C_S_opSZq:
  54344. push_stack(sc, OP_SAFE_C_SZ_SZ, find_symbol_checked(sc, cadr(caddr(code))), code);
  54345. sc->code = caddr(caddr(code));
  54346. goto OPT_EVAL;
  54347. case OP_SAFE_C_AZ:
  54348. if (!a_is_ok(sc, code)) break;
  54349. case HOP_SAFE_C_AZ:
  54350. push_stack(sc, OP_SAFE_C_SZ_1, c_call(cdr(code))(sc, cadr(code)), code);
  54351. sc->code = caddr(code);
  54352. goto OPT_EVAL;
  54353. /* s: h_safe_c_s_op_s_opssqq: 204308 */
  54354. case OP_SAFE_C_ZA:
  54355. if (!a_is_ok(sc, code)) break;
  54356. case HOP_SAFE_C_ZA:
  54357. /* here we can't use ZS order because we sometimes assume left->right arg evaluation (binary-io.scm for example) */
  54358. push_stack(sc, OP_SAFE_C_ZA_1, sc->nil, code);
  54359. sc->code = cadr(code);
  54360. goto OPT_EVAL;
  54361. case OP_SAFE_C_ZZ:
  54362. if (!c_function_is_ok(sc, code)) break;
  54363. case HOP_SAFE_C_ZZ:
  54364. /* most of the component Z's here are very complex:
  54365. * 264600: (+ (* even-amp (oscil (vector-ref evens k) (+ even-freq val))) (* odd-amp...
  54366. */
  54367. push_stack(sc, OP_SAFE_C_ZZ_1, sc->nil, code);
  54368. sc->code = cadr(code);
  54369. goto OPT_EVAL;
  54370. case OP_SAFE_C_opCq_Z:
  54371. if (!a_is_ok(sc, code)) break;
  54372. case HOP_SAFE_C_opCq_Z:
  54373. push_stack(sc, OP_SAFE_C_ZZ_2, c_call(cadr(code))(sc, cdr(cadr(code))), code);
  54374. sc->code = caddr(code);
  54375. goto OPT_EVAL;
  54376. case OP_SAFE_C_ZAA:
  54377. if (!a_is_ok(sc, code)) break;
  54378. case HOP_SAFE_C_ZAA:
  54379. push_stack(sc, OP_SAFE_C_ZAA_1, sc->nil, code);
  54380. sc->code = cadr(code);
  54381. goto OPT_EVAL;
  54382. case OP_SAFE_C_AZA:
  54383. if (!a_is_ok(sc, code)) break;
  54384. case HOP_SAFE_C_AZA:
  54385. push_stack(sc, OP_SAFE_C_AZA_1, c_call(cdr(code))(sc, cadr(code)), code);
  54386. sc->code = caddr(code);
  54387. goto OPT_EVAL;
  54388. case OP_SAFE_C_SSZ:
  54389. if (!c_function_is_ok(sc, code)) break;
  54390. case HOP_SAFE_C_SSZ:
  54391. push_stack(sc, OP_SAFE_C_SSZ_1, find_symbol_checked(sc, cadr(code)), code);
  54392. sc->code = cadddr(code);
  54393. goto OPT_EVAL;
  54394. case OP_SAFE_C_AAZ:
  54395. if (!a_is_ok(sc, code)) break;
  54396. case HOP_SAFE_C_AAZ:
  54397. push_op_stack(sc, c_call(cdr(code))(sc, cadr(code)));
  54398. push_stack(sc, OP_SAFE_C_AAZ_1, c_call(cddr(code))(sc, caddr(code)), code);
  54399. sc->code = cadddr(code);
  54400. goto OPT_EVAL;
  54401. case OP_SAFE_C_ZZA:
  54402. if (!a_is_ok(sc, code)) break;
  54403. case HOP_SAFE_C_ZZA:
  54404. push_stack(sc, OP_SAFE_C_ZZA_1, sc->nil, code);
  54405. sc->code = cadr(code);
  54406. goto OPT_EVAL;
  54407. case OP_SAFE_C_ZAZ:
  54408. if (!a_is_ok(sc, code)) break;
  54409. case HOP_SAFE_C_ZAZ:
  54410. push_stack(sc, OP_SAFE_C_ZAZ_1, sc->nil, code);
  54411. sc->code = cadr(code);
  54412. goto OPT_EVAL;
  54413. case OP_SAFE_C_AZZ:
  54414. if (!a_is_ok(sc, code)) break;
  54415. case HOP_SAFE_C_AZZ:
  54416. push_stack(sc, OP_SAFE_C_AZZ_1, c_call(cdr(code))(sc, cadr(code)), code);
  54417. sc->code = caddr(code);
  54418. goto OPT_EVAL;
  54419. case OP_SAFE_C_ZZZ:
  54420. if (!c_function_is_ok(sc, code)) break;
  54421. case HOP_SAFE_C_ZZZ:
  54422. push_stack(sc, OP_SAFE_C_ZZZ_1, sc->nil, code);
  54423. sc->code = cadr(code);
  54424. goto OPT_EVAL;
  54425. case OP_SAFE_C_A:
  54426. if (!a_is_ok_cadr(sc, code)) break;
  54427. case HOP_SAFE_C_A:
  54428. set_car(sc->a1_1, c_call(cdr(code))(sc, cadr(code)));
  54429. sc->value = c_call(code)(sc, sc->a1_1);
  54430. goto START;
  54431. case OP_SAFE_C_AA:
  54432. if (!a_is_ok(sc, code)) break;
  54433. case HOP_SAFE_C_AA:
  54434. set_car(sc->a2_1, c_call(cdr(code))(sc, cadr(code)));
  54435. set_car(sc->a2_2, c_call(cddr(code))(sc, caddr(code)));
  54436. sc->value = c_call(code)(sc, sc->a2_1);
  54437. goto START;
  54438. case OP_SAFE_C_AAA:
  54439. if (!a_is_ok(sc, code)) break;
  54440. case HOP_SAFE_C_AAA:
  54441. {
  54442. s7_pointer arg;
  54443. arg = cdr(code);
  54444. set_car(sc->a3_1, c_call(arg)(sc, car(arg)));
  54445. arg = cdr(arg);
  54446. set_car(sc->a3_2, c_call(arg)(sc, car(arg)));
  54447. arg = cdr(arg);
  54448. set_car(sc->a3_3, c_call(arg)(sc, car(arg)));
  54449. sc->value = c_call(code)(sc, sc->a3_1);
  54450. goto START;
  54451. }
  54452. case OP_SAFE_C_SSA:
  54453. if (!a_is_ok_cadddr(sc, code)) break;
  54454. case HOP_SAFE_C_SSA:
  54455. {
  54456. s7_pointer arg;
  54457. arg = cdr(code);
  54458. set_car(sc->a3_1, find_symbol_checked(sc, car(arg)));
  54459. arg = cdr(arg);
  54460. set_car(sc->a3_2, find_symbol_checked(sc, car(arg)));
  54461. arg = cdr(arg);
  54462. set_car(sc->a3_3, c_call(arg)(sc, car(arg)));
  54463. sc->value = c_call(code)(sc, sc->a3_1);
  54464. goto START;
  54465. }
  54466. case OP_SAFE_C_SAS:
  54467. if (!a_is_ok_caddr(sc, code)) break;
  54468. case HOP_SAFE_C_SAS:
  54469. {
  54470. s7_pointer arg;
  54471. arg = cdr(code);
  54472. set_car(sc->a3_1, find_symbol_checked(sc, car(arg)));
  54473. arg = cdr(arg);
  54474. set_car(sc->a3_2, c_call(arg)(sc, car(arg)));
  54475. arg = cdr(arg);
  54476. set_car(sc->a3_3, find_symbol_checked(sc, car(arg)));
  54477. sc->value = c_call(code)(sc, sc->a3_1);
  54478. goto START;
  54479. }
  54480. case OP_SAFE_C_CSA:
  54481. if (!a_is_ok_cadddr(sc, code)) break;
  54482. case HOP_SAFE_C_CSA:
  54483. {
  54484. s7_pointer arg;
  54485. arg = cdr(code);
  54486. set_car(sc->a3_1, car(arg));
  54487. arg = cdr(arg);
  54488. set_car(sc->a3_2, find_symbol_checked(sc, car(arg)));
  54489. arg = cdr(arg);
  54490. set_car(sc->a3_3, c_call(arg)(sc, car(arg)));
  54491. sc->value = c_call(code)(sc, sc->a3_1);
  54492. goto START;
  54493. }
  54494. case OP_SAFE_C_SCA:
  54495. if (!a_is_ok_cadddr(sc, code)) break;
  54496. case HOP_SAFE_C_SCA:
  54497. {
  54498. s7_pointer arg;
  54499. arg = cdr(code);
  54500. set_car(sc->a3_1, find_symbol_checked(sc, car(arg)));
  54501. arg = cdr(arg);
  54502. set_car(sc->a3_2, car(arg));
  54503. arg = cdr(arg);
  54504. set_car(sc->a3_3, c_call(arg)(sc, car(arg)));
  54505. sc->value = c_call(code)(sc, sc->a3_1);
  54506. goto START;
  54507. }
  54508. case OP_SAFE_C_CAS:
  54509. if (!a_is_ok_caddr(sc, code)) break;
  54510. case HOP_SAFE_C_CAS:
  54511. {
  54512. s7_pointer arg;
  54513. arg = cdr(code);
  54514. set_car(sc->a3_1, car(arg));
  54515. arg = cdr(arg);
  54516. set_car(sc->a3_2, c_call(arg)(sc, car(arg)));
  54517. set_car(sc->a3_3, find_symbol_checked(sc, cadr(arg)));
  54518. sc->value = c_call(code)(sc, sc->a3_1);
  54519. goto START;
  54520. }
  54521. case OP_SAFE_C_AAAA:
  54522. if (!a_is_ok(sc, code)) break;
  54523. case HOP_SAFE_C_AAAA:
  54524. {
  54525. s7_pointer arg;
  54526. arg = cdr(code);
  54527. set_car(sc->a4_1, c_call(arg)(sc, car(arg)));
  54528. arg = cdr(arg);
  54529. set_car(sc->a4_2, c_call(arg)(sc, car(arg)));
  54530. arg = cdr(arg);
  54531. set_car(sc->a4_3, c_call(arg)(sc, car(arg)));
  54532. arg = cdr(arg);
  54533. set_car(sc->a4_4, c_call(arg)(sc, car(arg)));
  54534. sc->value = c_call(code)(sc, sc->a4_1);
  54535. goto START;
  54536. }
  54537. case OP_SAFE_C_ALL_X:
  54538. if (!a_is_ok(sc, code)) break;
  54539. case HOP_SAFE_C_ALL_X:
  54540. {
  54541. int num_args;
  54542. s7_pointer args, p;
  54543. num_args = integer(arglist_length(code));
  54544. if ((num_args != 0) &&
  54545. (num_args < NUM_SAFE_LISTS) &&
  54546. (!list_is_in_use(sc->safe_lists[num_args])))
  54547. {
  54548. sc->args = sc->safe_lists[num_args];
  54549. set_list_in_use(sc->args);
  54550. }
  54551. else sc->args = make_list(sc, num_args, sc->nil);
  54552. for (args = cdr(code), p = sc->args; is_pair(args); args = cdr(args), p = cdr(p))
  54553. set_car(p, c_call(args)(sc, car(args)));
  54554. clear_list_in_use(sc->args);
  54555. sc->value = c_call(code)(sc, sc->args);
  54556. /* we can't release a temp here:
  54557. * (define (hi) (vector 14800 14020 (oscil os) (* 1/3 14800) 14800 (* 1/2 14800))) (hi) where os returns non-zero:
  54558. * #(14800 14020 <output-string-port> 14800/3 14800 7400)
  54559. */
  54560. goto START;
  54561. }
  54562. case OP_SAFE_C_SQS:
  54563. if (!c_function_is_ok(sc, code)) break;
  54564. case HOP_SAFE_C_SQS:
  54565. {
  54566. /* (let-set! gen 'fm fm); many of these are handled in safe_closure_star_s0 */
  54567. s7_pointer val1, args;
  54568. args = cdr(code);
  54569. val1 = find_symbol_checked(sc, car(args));
  54570. set_car(sc->t3_3, find_symbol_checked(sc, opt_sym2(args)));
  54571. set_car(sc->t3_2, opt_con1(args));
  54572. set_car(sc->t3_1, val1);
  54573. sc->value = c_call(code)(sc, sc->t3_1);
  54574. goto START;
  54575. }
  54576. case OP_SAFE_C_SCS:
  54577. if (!c_function_is_ok(sc, code)) break;
  54578. case HOP_SAFE_C_SCS:
  54579. {
  54580. /* (define (hi) (let ((x 32) (lst '(0 1))) (list-set! lst 0 x) x)) */
  54581. s7_pointer val1, args;
  54582. args = cdr(code);
  54583. val1 = find_symbol_checked(sc, car(args));
  54584. set_car(sc->t3_3, find_symbol_checked(sc, opt_sym2(args)));
  54585. set_car(sc->t3_2, opt_con1(args));
  54586. set_car(sc->t3_1, val1);
  54587. sc->value = c_call(code)(sc, sc->t3_1);
  54588. goto START;
  54589. }
  54590. case OP_SAFE_C_SSC:
  54591. if (!c_function_is_ok(sc, code)) break;
  54592. case HOP_SAFE_C_SSC:
  54593. {
  54594. /* (define (hi) (let ((v #(0 1 2)) (i 0)) (vector-set! v i 1) v)) */
  54595. s7_pointer val1, args;
  54596. args = cdr(code);
  54597. val1 = find_symbol_checked(sc, car(args));
  54598. set_car(sc->t3_2, find_symbol_checked(sc, opt_sym1(args)));
  54599. set_car(sc->t3_3, opt_con2(args));
  54600. set_car(sc->t3_1, val1);
  54601. sc->value = c_call(code)(sc, sc->t3_1);
  54602. goto START;
  54603. }
  54604. case OP_SAFE_C_SCC:
  54605. if (!c_function_is_ok(sc, code)) break;
  54606. case HOP_SAFE_C_SCC:
  54607. {
  54608. /* (make-env E :length 100) */
  54609. s7_pointer args;
  54610. args = cdr(code);
  54611. set_car(sc->t3_1, find_symbol_checked(sc, car(args)));
  54612. set_car(sc->t3_2, opt_con1(args));
  54613. set_car(sc->t3_3, opt_con2(args));
  54614. sc->value = c_call(code)(sc, sc->t3_1);
  54615. goto START;
  54616. }
  54617. case OP_SAFE_C_CSC:
  54618. if (!c_function_is_ok(sc, code)) break;
  54619. case HOP_SAFE_C_CSC:
  54620. {
  54621. s7_pointer args;
  54622. args = cdr(code);
  54623. set_car(sc->t3_2, find_symbol_checked(sc, opt_sym1(args)));
  54624. set_car(sc->t3_1, car(args));
  54625. set_car(sc->t3_3, opt_con2(args));
  54626. sc->value = c_call(code)(sc, sc->t3_1);
  54627. goto START;
  54628. }
  54629. case OP_SAFE_C_CSS:
  54630. if (!c_function_is_ok(sc, code)) break;
  54631. case HOP_SAFE_C_CSS:
  54632. {
  54633. s7_pointer val1, args;
  54634. args = cdr(code);
  54635. val1 = find_symbol_checked(sc, opt_sym2(args));
  54636. set_car(sc->t3_2, find_symbol_checked(sc, opt_sym1(args)));
  54637. set_car(sc->t3_3, val1);
  54638. set_car(sc->t3_1, car(args));
  54639. sc->value = c_call(code)(sc, sc->t3_1);
  54640. goto START;
  54641. }
  54642. case OP_SAFE_C_SSS:
  54643. if (!c_function_is_ok(sc, code)) break;
  54644. case HOP_SAFE_C_SSS:
  54645. {
  54646. s7_pointer val1, val2, args;
  54647. args = cdr(code);
  54648. val1 = find_symbol_checked(sc, car(args));
  54649. val2 = find_symbol_checked(sc, opt_sym1(args));
  54650. set_car(sc->t3_3, find_symbol_checked(sc, opt_sym2(args)));
  54651. set_car(sc->t3_1, val1);
  54652. set_car(sc->t3_2, val2);
  54653. sc->value = c_call(code)(sc, sc->t3_1);
  54654. goto START;
  54655. }
  54656. case OP_SAFE_C_opCq:
  54657. if (!c_function_is_ok_cadr(sc, code)) break;
  54658. case HOP_SAFE_C_opCq:
  54659. set_car(sc->t1_1, c_call(car(cdr(code)))(sc, cdar(cdr(code)))); /* OP_SAFE_C_C can involve any number of ops */
  54660. sc->value = c_call(code)(sc, sc->t1_1);
  54661. goto START;
  54662. case OP_SAFE_C_opSq:
  54663. if (!c_function_is_ok_cadr(sc, code)) break;
  54664. case HOP_SAFE_C_opSq:
  54665. {
  54666. s7_pointer args;
  54667. args = cadr(code);
  54668. set_car(sc->t1_1, find_symbol_checked(sc, cadr(args)));
  54669. set_car(sc->t1_1, c_call(args)(sc, sc->t1_1));
  54670. sc->value = c_call(code)(sc, sc->t1_1);
  54671. goto START;
  54672. }
  54673. case OP_SAFE_C_op_opSq_q:
  54674. if ((!c_function_is_ok(sc, code)) || (!c_function_is_ok(sc, cadr(code))) || (!c_function_is_ok(sc, cadr(cadr(code))))) break;
  54675. case HOP_SAFE_C_op_opSq_q:
  54676. {
  54677. s7_pointer outer, args;
  54678. outer = cadr(code);
  54679. args = cadr(outer);
  54680. set_car(sc->t1_1, find_symbol_checked(sc, cadr(args)));
  54681. set_car(sc->t1_1, c_call(args)(sc, sc->t1_1));
  54682. set_car(sc->t1_1, c_call(outer)(sc, sc->t1_1));
  54683. sc->value = c_call(code)(sc, sc->t1_1);
  54684. goto START;
  54685. }
  54686. case OP_SAFE_C_op_S_opSq_q:
  54687. if ((!c_function_is_ok(sc, code)) || (!c_function_is_ok(sc, cadr(code))) || (!c_function_is_ok(sc, caddr(cadr(code))))) break;
  54688. case HOP_SAFE_C_op_S_opSq_q:
  54689. {
  54690. /* (exp (* r (cos x))) */
  54691. s7_pointer outer, args;
  54692. outer = cadr(code);
  54693. args = caddr(outer);
  54694. set_car(sc->t1_1, find_symbol_checked(sc, cadr(args)));
  54695. set_car(sc->t2_2, c_call(args)(sc, sc->t1_1));
  54696. set_car(sc->t2_1, find_symbol_checked(sc, cadr(outer)));
  54697. set_car(sc->t1_1, c_call(outer)(sc, sc->t2_1));
  54698. sc->value = c_call(code)(sc, sc->t1_1);
  54699. goto START;
  54700. }
  54701. case OP_SAFE_C_PS:
  54702. if (!c_function_is_ok(sc, code)) break;
  54703. case HOP_SAFE_C_PS:
  54704. push_stack(sc, OP_EVAL_ARGS_P_3, sc->nil, code); /* gotta wait in this case */
  54705. sc->code = cadr(code);
  54706. goto EVAL;
  54707. case OP_SAFE_C_PC:
  54708. if (!c_function_is_ok(sc, code)) break;
  54709. case HOP_SAFE_C_PC:
  54710. push_stack(sc, OP_EVAL_ARGS_P_4, caddr(code), code);
  54711. sc->code = cadr(code);
  54712. goto EVAL;
  54713. case OP_SAFE_C_PQ:
  54714. if (!c_function_is_ok(sc, code)) break;
  54715. case HOP_SAFE_C_PQ:
  54716. push_stack(sc, OP_EVAL_ARGS_P_4, cadr(caddr(code)), code); /* was P_5, but that's the same as P_4 */
  54717. sc->code = cadr(code);
  54718. goto EVAL;
  54719. case OP_SAFE_C_SP:
  54720. if (!c_function_is_ok(sc, code)) break;
  54721. case HOP_SAFE_C_SP:
  54722. push_stack(sc, OP_EVAL_ARGS_P_2, find_symbol_checked(sc, cadr(code)), code);
  54723. sc->code = caddr(code);
  54724. goto EVAL;
  54725. case OP_SAFE_C_AP:
  54726. if ((!c_function_is_ok(sc, code)) || (!a_is_ok(sc, cadr(code)))) break;
  54727. case HOP_SAFE_C_AP:
  54728. push_stack(sc, OP_EVAL_ARGS_P_2, c_call(cdr(code))(sc, cadr(code)), code);
  54729. sc->code = caddr(code);
  54730. goto EVAL;
  54731. case OP_SAFE_C_CP:
  54732. if (!c_function_is_ok(sc, code)) break;
  54733. case HOP_SAFE_C_CP:
  54734. push_stack(sc, OP_EVAL_ARGS_P_2, cadr(code), code);
  54735. sc->code = caddr(code);
  54736. goto EVAL;
  54737. case OP_SAFE_C_QP:
  54738. if (!c_function_is_ok(sc, code)) break;
  54739. case HOP_SAFE_C_QP:
  54740. push_stack(sc, OP_EVAL_ARGS_P_2, cadr(cadr(code)), code);
  54741. sc->code = caddr(code);
  54742. goto EVAL;
  54743. case OP_SAFE_C_PP:
  54744. if (!c_function_is_ok(sc, code)) break;
  54745. case HOP_SAFE_C_PP:
  54746. push_stack(sc, OP_SAFE_C_PP_1, sc->nil, code);
  54747. sc->code = cadr(code);
  54748. goto EVAL;
  54749. case OP_SAFE_C_SSP:
  54750. if (!c_function_is_ok(sc, code)) break;
  54751. case HOP_SAFE_C_SSP:
  54752. push_stack(sc, OP_EVAL_ARGS_SSP_1, sc->nil, code);
  54753. sc->code = cadddr(code);
  54754. goto EVAL;
  54755. case OP_SAFE_C_opSSq:
  54756. if (!c_function_is_ok_cadr(sc, code)) break;
  54757. case HOP_SAFE_C_opSSq:
  54758. {
  54759. s7_pointer args, val1;
  54760. args = cadr(code);
  54761. val1 = find_symbol_checked(sc, cadr(args));
  54762. set_car(sc->t2_2, find_symbol_checked(sc, caddr(args)));
  54763. set_car(sc->t2_1, val1);
  54764. set_car(sc->t1_1, c_call(args)(sc, sc->t2_1));
  54765. sc->value = c_call(code)(sc, sc->t1_1);
  54766. goto START;
  54767. }
  54768. case OP_SAFE_C_opSCq:
  54769. if (!c_function_is_ok_cadr(sc, code)) break;
  54770. case HOP_SAFE_C_opSCq:
  54771. {
  54772. s7_pointer args;
  54773. args = cadr(code);
  54774. set_car(sc->t2_1, find_symbol_checked(sc, cadr(args)));
  54775. set_car(sc->t2_2, caddr(args));
  54776. set_car(sc->t1_1, c_call(args)(sc, sc->t2_1));
  54777. sc->value = c_call(code)(sc, sc->t1_1);
  54778. goto START;
  54779. }
  54780. case OP_SAFE_C_opCSq:
  54781. if (!c_function_is_ok_cadr(sc, code)) break;
  54782. case HOP_SAFE_C_opCSq:
  54783. {
  54784. s7_pointer args;
  54785. args = cadr(code);
  54786. set_car(sc->t2_2, find_symbol_checked(sc, caddr(args)));
  54787. set_car(sc->t2_1, cadr(args));
  54788. set_car(sc->t1_1, c_call(args)(sc, sc->t2_1));
  54789. sc->value = c_call(code)(sc, sc->t1_1);
  54790. goto START;
  54791. }
  54792. case OP_SAFE_C_opSQq:
  54793. if (!c_function_is_ok_cadr(sc, code)) break;
  54794. case HOP_SAFE_C_opSQq:
  54795. {
  54796. s7_pointer args;
  54797. args = cadr(code);
  54798. set_car(sc->t2_1, find_symbol_checked(sc, cadr(args)));
  54799. set_car(sc->t2_2, cadr(caddr(args)));
  54800. set_car(sc->t1_1, c_call(args)(sc, sc->t2_1));
  54801. sc->value = c_call(code)(sc, sc->t1_1);
  54802. goto START;
  54803. }
  54804. case OP_SAFE_C_S_opSq:
  54805. if (!c_function_is_ok_caddr(sc, code)) break;
  54806. case HOP_SAFE_C_S_opSq:
  54807. {
  54808. s7_pointer args, val;
  54809. args = cdr(code);
  54810. val = find_symbol_checked(sc, car(args));
  54811. set_car(sc->t1_1, find_symbol_checked(sc, opt_sym1(args)));
  54812. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t1_1));
  54813. set_car(sc->t2_1, val);
  54814. sc->value = c_call(code)(sc, sc->t2_1);
  54815. goto START;
  54816. }
  54817. case OP_SAFE_C_S_opCq:
  54818. if (!c_function_is_ok_caddr(sc, code))break;
  54819. case HOP_SAFE_C_S_opCq:
  54820. {
  54821. s7_pointer args, val;
  54822. args = cdr(code);
  54823. val = find_symbol_checked(sc, car(args));
  54824. set_car(sc->t2_2, c_call(cadr(args))(sc, opt_pair1(args))); /* any number of constants here */
  54825. set_car(sc->t2_1, val);
  54826. sc->value = c_call(code)(sc, sc->t2_1);
  54827. goto START;
  54828. }
  54829. case OP_SAFE_C_C_opSq:
  54830. if (!c_function_is_ok_caddr(sc, code)) break;
  54831. case HOP_SAFE_C_C_opSq:
  54832. {
  54833. s7_pointer args;
  54834. args = cdr(code);
  54835. set_car(sc->t1_1, find_symbol_checked(sc, opt_sym1(args)));
  54836. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t1_1));
  54837. set_car(sc->t2_1, car(args));
  54838. sc->value = c_call(code)(sc, sc->t2_1);
  54839. goto START;
  54840. }
  54841. case OP_SAFE_C_C_opCq:
  54842. if (!c_function_is_ok_caddr(sc, code)) break;
  54843. case HOP_SAFE_C_C_opCq:
  54844. {
  54845. s7_pointer args;
  54846. args = cdr(code);
  54847. set_car(sc->t2_2, c_call(cadr(args))(sc, opt_pair1(args))); /* any # of args */
  54848. set_car(sc->t2_1, car(args));
  54849. sc->value = c_call(code)(sc, sc->t2_1);
  54850. goto START;
  54851. }
  54852. case OP_SAFE_C_C_opCSq:
  54853. if (!c_function_is_ok_caddr(sc, code)) break;
  54854. case HOP_SAFE_C_C_opCSq:
  54855. {
  54856. s7_pointer args;
  54857. args = cdr(code);
  54858. set_car(sc->t2_2, find_symbol_checked(sc, opt_sym2(args)));
  54859. set_car(sc->t2_1, opt_con1(args));
  54860. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t2_1));
  54861. set_car(sc->t2_1, car(args));
  54862. sc->value = c_call(code)(sc, sc->t2_1);
  54863. goto START;
  54864. }
  54865. case OP_SAFE_C_C_opSSq:
  54866. if (!c_function_is_ok_caddr(sc, code)) break;
  54867. case HOP_SAFE_C_C_opSSq:
  54868. {
  54869. s7_pointer args, val;
  54870. args = cdr(code);
  54871. val = find_symbol_checked(sc, opt_sym1(args));
  54872. set_car(sc->t2_2, find_symbol_checked(sc, opt_sym2(args)));
  54873. set_car(sc->t2_1, val);
  54874. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t2_1));
  54875. set_car(sc->t2_1, car(args));
  54876. sc->value = c_call(code)(sc, sc->t2_1);
  54877. goto START;
  54878. }
  54879. case OP_SAFE_C_opCSq_C:
  54880. if (!c_function_is_ok_cadr(sc, code)) break;
  54881. case HOP_SAFE_C_opCSq_C:
  54882. {
  54883. s7_pointer args;
  54884. args = cdr(code);
  54885. set_car(sc->t2_2, find_symbol_checked(sc, caddr(car(args))));
  54886. set_car(sc->t2_1, cadr(car(args)));
  54887. set_car(sc->t2_1, c_call(car(args))(sc, sc->t2_1));
  54888. set_car(sc->t2_2, cadr(args));
  54889. sc->value = c_call(code)(sc, sc->t2_1);
  54890. goto START;
  54891. }
  54892. case OP_SAFE_C_opSSq_C:
  54893. if (!c_function_is_ok_cadr(sc, code)) break;
  54894. case HOP_SAFE_C_opSSq_C:
  54895. {
  54896. s7_pointer args, val;
  54897. args = cdr(code);
  54898. val = find_symbol_checked(sc, cadr(car(args)));
  54899. set_car(sc->t2_2, find_symbol_checked(sc, caddr(car(args))));
  54900. set_car(sc->t2_1, val);
  54901. set_car(sc->t2_1, c_call(car(args))(sc, sc->t2_1));
  54902. set_car(sc->t2_2, cadr(args));
  54903. sc->value = c_call(code)(sc, sc->t2_1);
  54904. goto START;
  54905. }
  54906. case OP_SAFE_C_opSSq_S:
  54907. if (!c_function_is_ok_cadr(sc, code)) break;
  54908. case HOP_SAFE_C_opSSq_S:
  54909. {
  54910. s7_pointer args, val, val1;
  54911. args = cdr(code);
  54912. val = find_symbol_checked(sc, cadr(car(args)));
  54913. val1 = find_symbol_checked(sc, cadr(args));
  54914. set_car(sc->t2_2, find_symbol_checked(sc, caddr(car(args))));
  54915. set_car(sc->t2_1, val);
  54916. set_car(sc->t2_1, c_call(car(args))(sc, sc->t2_1));
  54917. set_car(sc->t2_2, val1);
  54918. sc->value = c_call(code)(sc, sc->t2_1);
  54919. goto START;
  54920. }
  54921. case OP_SAFE_C_op_opSSq_q_C:
  54922. if ((!c_function_is_ok(sc, code)) || (!c_function_is_ok(sc, cadr(code))) || (!c_function_is_ok(sc, cadr(cadr(code))))) break;
  54923. case HOP_SAFE_C_op_opSSq_q_C:
  54924. {
  54925. /* code: (> (magnitude (- old new)) 0.001) */
  54926. s7_pointer arg;
  54927. arg = cadr(cadr(code));
  54928. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg)));
  54929. set_car(sc->t2_2, find_symbol_checked(sc, caddr(arg)));
  54930. set_car(sc->t1_1, c_call(arg)(sc, sc->t2_1));
  54931. set_car(sc->t2_1, c_call(cadr(code))(sc, sc->t1_1));
  54932. set_car(sc->t2_2, caddr(code));
  54933. sc->value = c_call(code)(sc, sc->t2_1);
  54934. goto START;
  54935. }
  54936. case OP_SAFE_C_op_opSSq_q_S:
  54937. if ((!c_function_is_ok(sc, code)) || (!c_function_is_ok(sc, cadr(code))) || (!c_function_is_ok(sc, cadr(cadr(code))))) break;
  54938. case HOP_SAFE_C_op_opSSq_q_S:
  54939. {
  54940. /* code: (> (magnitude (- old new)) s) */
  54941. s7_pointer arg;
  54942. arg = cadr(cadr(code));
  54943. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg)));
  54944. set_car(sc->t2_2, find_symbol_checked(sc, caddr(arg)));
  54945. set_car(sc->t1_1, c_call(arg)(sc, sc->t2_1));
  54946. set_car(sc->t2_1, c_call(cadr(code))(sc, sc->t1_1));
  54947. set_car(sc->t2_2, find_symbol_checked(sc, caddr(code)));
  54948. sc->value = c_call(code)(sc, sc->t2_1);
  54949. goto START;
  54950. }
  54951. case OP_SAFE_C_op_opSq_q_C:
  54952. if ((!c_function_is_ok(sc, code)) || (!c_function_is_ok(sc, cadr(code))) || (!c_function_is_ok(sc, cadr(cadr(code))))) break;
  54953. case HOP_SAFE_C_op_opSq_q_C:
  54954. {
  54955. s7_pointer arg;
  54956. arg = cadr(cadr(code));
  54957. set_car(sc->t1_1, find_symbol_checked(sc, cadr(arg)));
  54958. set_car(sc->t1_1, c_call(arg)(sc, sc->t1_1));
  54959. set_car(sc->t2_1, c_call(cadr(code))(sc, sc->t1_1));
  54960. set_car(sc->t2_2, caddr(code));
  54961. sc->value = c_call(code)(sc, sc->t2_1);
  54962. goto START;
  54963. }
  54964. case OP_SAFE_C_op_opSq_q_S:
  54965. if ((!c_function_is_ok(sc, code)) || (!c_function_is_ok(sc, cadr(code))) || (!c_function_is_ok(sc, cadr(cadr(code))))) break;
  54966. case HOP_SAFE_C_op_opSq_q_S:
  54967. {
  54968. s7_pointer arg;
  54969. arg = cadr(cadr(code));
  54970. set_car(sc->t1_1, find_symbol_checked(sc, cadr(arg)));
  54971. set_car(sc->t1_1, c_call(arg)(sc, sc->t1_1));
  54972. set_car(sc->t2_1, c_call(cadr(code))(sc, sc->t1_1));
  54973. set_car(sc->t2_2, find_symbol_checked(sc, caddr(code)));
  54974. sc->value = c_call(code)(sc, sc->t2_1);
  54975. goto START;
  54976. }
  54977. case OP_SAFE_C_S_op_opSSq_Sq:
  54978. if ((!c_function_is_ok(sc, code)) || (!c_function_is_ok(sc, caddr(code))) || (!c_function_is_ok(sc, cadr(caddr(code))))) break;
  54979. case HOP_SAFE_C_S_op_opSSq_Sq:
  54980. {
  54981. /* (let () (define (hi a b c d) (+ a (* (- b c) d))) (define (ho) (hi 1 2 3 4)) (ho))
  54982. * or actually... (oscil fmosc1 (+ (* fm1-rat vib) fuzz))
  54983. * and that is then packaged as opCq...: (* (env indf1) (oscil fmosc1 (+ (* fm1-rat vib) fuzz)))
  54984. * and that is then (+ ...)
  54985. * but now this is handled in clm2xen.c
  54986. */
  54987. s7_pointer args, val, val1;
  54988. args = caddr(code); /* (* (- b c) d) */
  54989. val1 = cadr(args);
  54990. val = find_symbol_checked(sc, cadr(val1)); /* b */
  54991. set_car(sc->t2_2, find_symbol_checked(sc, caddr(val1))); /* c */
  54992. set_car(sc->t2_1, val);
  54993. val = find_symbol_checked(sc, caddr(args)); /* d */
  54994. set_car(sc->t2_1, c_call(val1)(sc, sc->t2_1)); /* (- b c) */
  54995. set_car(sc->t2_2, val);
  54996. set_car(sc->t2_2, c_call(args)(sc, sc->t2_1)); /* (* ...) */
  54997. set_car(sc->t2_1, find_symbol_checked(sc, cadr(code))); /* a */
  54998. sc->value = c_call(code)(sc, sc->t2_1); /* (+ ...) */
  54999. goto START;
  55000. }
  55001. case OP_SAFE_C_S_op_S_opSSqq:
  55002. if ((!c_function_is_ok(sc, code)) || (!c_function_is_ok(sc, caddr(code))) || (!c_function_is_ok(sc, caddr(caddr(code))))) break;
  55003. case HOP_SAFE_C_S_op_S_opSSqq:
  55004. {
  55005. /* (let () (define (hi a b c d) (+ a (* d (- b c)))) (define (ho) (hi 1 2 3 4)) (ho)) */
  55006. s7_pointer args, val, val1;
  55007. args = caddr(code); /* (* d (- b c)) */
  55008. val1 = caddr(args);
  55009. val = find_symbol_checked(sc, cadr(val1)); /* b */
  55010. set_car(sc->t2_2, find_symbol_checked(sc, caddr(val1))); /* c */
  55011. set_car(sc->t2_1, val);
  55012. val = find_symbol_checked(sc, cadr(args)); /* d */
  55013. set_car(sc->t2_2, c_call(val1)(sc, sc->t2_1)); /* (- b c) */
  55014. set_car(sc->t2_1, val);
  55015. set_car(sc->t2_2, c_call(args)(sc, sc->t2_1)); /* (* ...) */
  55016. set_car(sc->t2_1, find_symbol_checked(sc, cadr(code))); /* a */
  55017. sc->value = c_call(code)(sc, sc->t2_1); /* (+ ...) */
  55018. goto START;
  55019. }
  55020. case OP_SAFE_C_S_op_opSSq_opSSqq:
  55021. if (!a_is_ok(sc, code)) break;
  55022. case HOP_SAFE_C_S_op_opSSq_opSSqq:
  55023. {
  55024. /* (* s (f3 (f1 a b) (f2 c d))) */
  55025. s7_pointer args, f1, op1, op2;
  55026. args = caddr(code);
  55027. op1 = cadr(args);
  55028. op2 = caddr(args);
  55029. set_car(sc->t2_1, find_symbol_checked(sc, cadr(op1)));
  55030. set_car(sc->t2_2, find_symbol_checked(sc, caddr(op1)));
  55031. f1 = c_call(op1)(sc, sc->t2_1);
  55032. set_car(sc->t2_1, find_symbol_checked(sc, cadr(op2)));
  55033. set_car(sc->t2_2, find_symbol_checked(sc, caddr(op2)));
  55034. set_car(sc->t2_2, c_call(op2)(sc, sc->t2_1));
  55035. set_car(sc->t2_1, f1);
  55036. set_car(sc->t2_2, c_call(args)(sc, sc->t2_1));
  55037. set_car(sc->t2_1, find_symbol_checked(sc, cadr(code)));
  55038. sc->value = c_call(code)(sc, sc->t2_1);
  55039. goto START;
  55040. }
  55041. case OP_SAFE_C_opSCq_S:
  55042. if (!c_function_is_ok_cadr(sc, code)) break;
  55043. case HOP_SAFE_C_opSCq_S:
  55044. {
  55045. s7_pointer args, val1;
  55046. args = cdr(code);
  55047. val1 = find_symbol_checked(sc, cadr(args));
  55048. set_car(sc->t2_1, find_symbol_checked(sc, cadr(car(args))));
  55049. set_car(sc->t2_2, caddr(car(args)));
  55050. set_car(sc->t2_1, c_call(car(args))(sc, sc->t2_1));
  55051. set_car(sc->t2_2, val1);
  55052. sc->value = c_call(code)(sc, sc->t2_1);
  55053. goto START;
  55054. }
  55055. case OP_SAFE_C_opSCq_C:
  55056. if (!c_function_is_ok_cadr(sc, code)) break;
  55057. case HOP_SAFE_C_opSCq_C:
  55058. {
  55059. s7_pointer args;
  55060. args = cdr(code);
  55061. set_car(sc->t2_1, find_symbol_checked(sc, cadr(car(args))));
  55062. set_car(sc->t2_2, caddr(car(args)));
  55063. set_car(sc->t2_1, c_call(car(args))(sc, sc->t2_1));
  55064. set_car(sc->t2_2, cadr(args));
  55065. sc->value = c_call(code)(sc, sc->t2_1);
  55066. goto START;
  55067. }
  55068. case OP_SAFE_C_opCSq_S:
  55069. if (!c_function_is_ok_cadr(sc, code)) break;
  55070. case HOP_SAFE_C_opCSq_S:
  55071. {
  55072. s7_pointer args, val1;
  55073. args = cdr(code);
  55074. val1 = find_symbol_checked(sc, cadr(args));
  55075. set_car(sc->t2_2, find_symbol_checked(sc, caddr(car(args))));
  55076. set_car(sc->t2_1, cadr(car(args)));
  55077. set_car(sc->t2_1, c_call(car(args))(sc, sc->t2_1));
  55078. set_car(sc->t2_2, val1);
  55079. sc->value = c_call(code)(sc, sc->t2_1);
  55080. goto START;
  55081. }
  55082. case OP_SAFE_C_S_opSCq:
  55083. if (!c_function_is_ok_caddr(sc, code)) break;
  55084. case HOP_SAFE_C_S_opSCq:
  55085. {
  55086. s7_pointer val1, args;
  55087. args = cdr(code);
  55088. val1 = find_symbol_checked(sc, car(args));
  55089. set_car(sc->t2_1, find_symbol_checked(sc, opt_sym1(args)));
  55090. set_car(sc->t2_2, opt_con2(args));
  55091. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t2_1));
  55092. set_car(sc->t2_1, val1);
  55093. sc->value = c_call(code)(sc, sc->t2_1);
  55094. goto START;
  55095. }
  55096. case OP_SAFE_C_C_opSCq:
  55097. if (!c_function_is_ok_caddr(sc, code)) break;
  55098. case HOP_SAFE_C_C_opSCq:
  55099. {
  55100. s7_pointer args;
  55101. args = cdr(code);
  55102. set_car(sc->t2_1, find_symbol_checked(sc, opt_sym1(args)));
  55103. set_car(sc->t2_2, opt_con2(args));
  55104. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t2_1));
  55105. set_car(sc->t2_1, car(args));
  55106. sc->value = c_call(code)(sc, sc->t2_1);
  55107. goto START;
  55108. }
  55109. case OP_SAFE_C_S_opSSq:
  55110. if (!c_function_is_ok_caddr(sc, code)) break;
  55111. case HOP_SAFE_C_S_opSSq:
  55112. {
  55113. /* (* a (- b c)) */
  55114. s7_pointer val1, val2, args;
  55115. args = cdr(code);
  55116. val1 = find_symbol_checked(sc, car(args));
  55117. val2 = find_symbol_checked(sc, opt_sym1(args));
  55118. set_car(sc->t2_2, find_symbol_checked(sc, opt_sym2(args)));
  55119. set_car(sc->t2_1, val2);
  55120. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t2_1));
  55121. set_car(sc->t2_1, val1);
  55122. sc->value = c_call(code)(sc, sc->t2_1);
  55123. goto START;
  55124. }
  55125. case OP_SAFE_C_S_opCSq:
  55126. if (!c_function_is_ok_caddr(sc, code)) break;
  55127. case HOP_SAFE_C_S_opCSq:
  55128. {
  55129. /* (* a (- 1 b)) or (logand a (ash 1 b)) */
  55130. s7_pointer val1, args;
  55131. args = cdr(code);
  55132. val1 = find_symbol_checked(sc, car(args)); /* a */
  55133. set_car(sc->t2_2, find_symbol_checked(sc, opt_sym2(args))); /* b */
  55134. set_car(sc->t2_1, opt_con1(args)); /* 1 */
  55135. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t2_1)); /* (- 1 b) */
  55136. set_car(sc->t2_1, val1);
  55137. sc->value = c_call(code)(sc, sc->t2_1);
  55138. goto START;
  55139. }
  55140. case OP_SAFE_C_opSq_S:
  55141. if (!c_function_is_ok_cadr(sc, code)) break;
  55142. case HOP_SAFE_C_opSq_S:
  55143. {
  55144. s7_pointer args;
  55145. args = cdr(code);
  55146. set_car(sc->t1_1, find_symbol_checked(sc, cadr(car(args))));
  55147. sc->temp3 = c_call(car(args))(sc, sc->t1_1);
  55148. set_car(sc->t2_2, find_symbol_checked(sc, cadr(args)));
  55149. set_car(sc->t2_1, sc->temp3);
  55150. sc->temp3 = sc->nil;
  55151. sc->value = c_call(code)(sc, sc->t2_1);
  55152. goto START;
  55153. }
  55154. case OP_SAFE_C_opSq_P:
  55155. if (!c_function_is_ok_cadr(sc, code)) break;
  55156. case HOP_SAFE_C_opSq_P:
  55157. {
  55158. s7_pointer args;
  55159. args = cadr(code);
  55160. set_car(sc->t1_1, find_symbol_checked(sc, cadr(args)));
  55161. push_stack(sc, OP_SAFE_C_opSq_P_1, c_call(args)(sc, sc->t1_1), sc->code);
  55162. sc->code = caddr(code);
  55163. goto EVAL;
  55164. }
  55165. case OP_SAFE_C_opSq_Q:
  55166. if (!c_function_is_ok_cadr(sc, code)) break;
  55167. case HOP_SAFE_C_opSq_Q:
  55168. {
  55169. s7_pointer arg1; /* (let-ref (cdr v) 'x) */
  55170. arg1 = cadr(code);
  55171. set_car(sc->t1_1, find_symbol_checked(sc, cadr(arg1)));
  55172. set_car(sc->t2_1, c_call(arg1)(sc, sc->t1_1));
  55173. set_car(sc->t2_2, cadr(caddr(code)));
  55174. sc->value = c_call(code)(sc, sc->t2_1);
  55175. goto START;
  55176. }
  55177. case OP_SAFE_C_opSq_Q_S:
  55178. if (!c_function_is_ok_cadr(sc, code)) break;
  55179. case HOP_SAFE_C_opSq_Q_S:
  55180. {
  55181. s7_pointer arg1, arg3; /* (let-set! (cdr v) 'x y) */
  55182. arg1 = cadr(code);
  55183. arg3 = find_symbol_checked(sc, cadddr(code));
  55184. set_car(sc->t1_1, find_symbol_checked(sc, cadr(arg1)));
  55185. set_car(sc->t3_1, c_call(arg1)(sc, sc->t1_1));
  55186. set_car(sc->t3_2, cadr(caddr(code)));
  55187. set_car(sc->t3_3, arg3);
  55188. sc->value = c_call(code)(sc, sc->t3_1);
  55189. goto START;
  55190. }
  55191. case OP_SAFE_C_opCq_S:
  55192. if (!c_function_is_ok_cadr(sc, code)) break;
  55193. case HOP_SAFE_C_opCq_S:
  55194. {
  55195. s7_pointer args, val;
  55196. args = cdr(code);
  55197. val = find_symbol_checked(sc, cadr(args));
  55198. set_car(sc->t2_1, c_call(car(args))(sc, cdr(car(args))));
  55199. set_car(sc->t2_2, val);
  55200. sc->value = c_call(code)(sc, sc->t2_1);
  55201. goto START;
  55202. }
  55203. case OP_SAFE_C_opCq_C:
  55204. if (!c_function_is_ok_cadr(sc, code)) break;
  55205. case HOP_SAFE_C_opCq_C:
  55206. {
  55207. s7_pointer args;
  55208. args = cdr(code);
  55209. set_car(sc->t2_1, c_call(car(args))(sc, cdr(car(args))));
  55210. set_car(sc->t2_2, cadr(args)); /* the second C stands for 1 arg? */
  55211. sc->value = c_call(code)(sc, sc->t2_1);
  55212. goto START;
  55213. }
  55214. case OP_SAFE_C_opSq_C:
  55215. if (!c_function_is_ok_cadr(sc, code)) break;
  55216. case HOP_SAFE_C_opSq_C:
  55217. {
  55218. s7_pointer args;
  55219. args = cdr(code);
  55220. set_car(sc->t1_1, find_symbol_checked(sc, cadr(car(args))));
  55221. set_car(sc->t2_1, c_call(car(args))(sc, sc->t1_1));
  55222. set_car(sc->t2_2, cadr(args));
  55223. sc->value = c_call(code)(sc, sc->t2_1);
  55224. goto START;
  55225. }
  55226. case OP_SAFE_C_C_op_S_opCqq:
  55227. if (!a_is_ok(sc, code)) break;
  55228. case HOP_SAFE_C_C_op_S_opCqq:
  55229. {
  55230. /* (define (hi a) (< 1.0 (+ a (* a 2)))) */
  55231. s7_pointer args, arg1, arg2;
  55232. args = cdr(code); /* C_op_S_opCqq */
  55233. arg1 = cadr(args); /* op_S_opCqq */
  55234. arg2 = caddr(arg1); /* opCq */
  55235. set_car(sc->t2_2, c_call(arg2)(sc, cdr(arg2)));
  55236. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg1)));
  55237. set_car(sc->t2_2, c_call(arg1)(sc, sc->t2_1));
  55238. set_car(sc->t2_1, car(args));
  55239. sc->value = c_call(code)(sc, sc->t2_1);
  55240. goto START;
  55241. }
  55242. case OP_SAFE_C_opSq_opSq:
  55243. if (!c_function_is_ok_cadr_caddr(sc, code)) break;
  55244. case HOP_SAFE_C_opSq_opSq:
  55245. {
  55246. s7_pointer args;
  55247. args = cdr(code);
  55248. set_car(sc->t1_1, find_symbol_checked(sc, cadr(car(args))));
  55249. sc->temp3 = c_call(car(args))(sc, sc->t1_1);
  55250. args = cadr(args);
  55251. set_car(sc->t1_1, find_symbol_checked(sc, cadr(args)));
  55252. set_car(sc->t2_2, c_call(args)(sc, sc->t1_1));
  55253. set_car(sc->t2_1, sc->temp3);
  55254. sc->temp3 = sc->nil;
  55255. sc->value = c_call(code)(sc, sc->t2_1);
  55256. goto START;
  55257. }
  55258. case OP_SAFE_C_opCq_opCq:
  55259. if (!c_function_is_ok_cadr_caddr(sc, code)) break;
  55260. case HOP_SAFE_C_opCq_opCq:
  55261. {
  55262. s7_pointer args;
  55263. args = cdr(code);
  55264. set_car(sc->t2_1, c_call(car(args))(sc, cdr(car(args))));
  55265. set_car(sc->t2_2, c_call(cadr(args))(sc, cdr(cadr(args))));
  55266. sc->value = c_call(code)(sc, sc->t2_1);
  55267. goto START;
  55268. }
  55269. case OP_SAFE_C_opCq_opSSq:
  55270. if (!c_function_is_ok_cadr_caddr(sc, code)) break;
  55271. case HOP_SAFE_C_opCq_opSSq:
  55272. {
  55273. s7_pointer args, val;
  55274. /* code: (/ (+ bn 1) (+ bn an)) */
  55275. args = cdr(code);
  55276. val = c_call(car(args))(sc, cdr(car(args)));
  55277. args = cdr(args);
  55278. set_car(sc->t2_1, find_symbol_checked(sc, cadar(args)));
  55279. set_car(sc->t2_2, find_symbol_checked(sc, caddar(args)));
  55280. set_car(sc->t2_2, c_call(car(args))(sc, sc->t2_1));
  55281. set_car(sc->t2_1, val);
  55282. sc->value = c_call(code)(sc, sc->t2_1);
  55283. goto START;
  55284. }
  55285. case OP_SAFE_C_opSCq_opSCq:
  55286. if (!c_function_is_ok_cadr_caddr(sc, code)) break;
  55287. case HOP_SAFE_C_opSCq_opSCq:
  55288. {
  55289. s7_pointer args, val2;
  55290. args = cdr(code);
  55291. val2 = find_symbol_checked(sc, cadr(cadr(args)));
  55292. set_car(sc->t2_1, find_symbol_checked(sc, cadr(car(args))));
  55293. set_car(sc->t2_2, caddr(car(args)));
  55294. sc->temp3 = c_call(car(args))(sc, sc->t2_1);
  55295. set_car(sc->t2_1, val2);
  55296. set_car(sc->t2_2, caddr(cadr(args)));
  55297. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t2_1));
  55298. set_car(sc->t2_1, sc->temp3);
  55299. sc->temp3 = sc->nil;
  55300. sc->value = c_call(code)(sc, sc->t2_1);
  55301. goto START;
  55302. }
  55303. case OP_SAFE_C_opSSq_opSSq:
  55304. if (!c_function_is_ok_cadr_caddr(sc, code)) break;
  55305. case HOP_SAFE_C_opSSq_opSSq:
  55306. {
  55307. s7_pointer args, val3, val4;
  55308. args = cdr(code);
  55309. val3 = find_symbol_checked(sc, caddr(car(args)));
  55310. val4 = find_symbol_checked(sc, caddr(cadr(args)));
  55311. set_car(sc->t2_1, find_symbol_checked(sc, cadr(car(args))));
  55312. set_car(sc->t2_2, val3);
  55313. sc->temp3 = c_call(car(args))(sc, sc->t2_1);
  55314. set_car(sc->t2_1, find_symbol_checked(sc, cadr(cadr(args))));
  55315. set_car(sc->t2_2, val4);
  55316. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t2_1));
  55317. set_car(sc->t2_1, sc->temp3);
  55318. sc->temp3 = sc->nil;
  55319. sc->value = c_call(code)(sc, sc->t2_1);
  55320. goto START;
  55321. }
  55322. case OP_SAFE_C_opSSq_opSq:
  55323. if (!c_function_is_ok_cadr_caddr(sc, code)) break;
  55324. case HOP_SAFE_C_opSSq_opSq:
  55325. {
  55326. s7_pointer args, val3;
  55327. args = cdr(code);
  55328. val3 = find_symbol_checked(sc, caddr(car(args)));
  55329. set_car(sc->t2_1, find_symbol_checked(sc, cadr(car(args))));
  55330. set_car(sc->t2_2, val3);
  55331. val3 = c_call(car(args))(sc, sc->t2_1);
  55332. set_car(sc->t1_1, find_symbol_checked(sc, cadr(cadr(args))));
  55333. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t1_1));
  55334. set_car(sc->t2_1, val3);
  55335. sc->value = c_call(code)(sc, sc->t2_1);
  55336. goto START;
  55337. }
  55338. case OP_SAFE_C_opSq_opSSq:
  55339. if (!c_function_is_ok_cadr_caddr(sc, code)) break;
  55340. case HOP_SAFE_C_opSq_opSSq:
  55341. {
  55342. s7_pointer args, val3;
  55343. args = cdr(code);
  55344. set_car(sc->t1_1, find_symbol_checked(sc, cadr(car(args))));
  55345. val3 = c_call(car(args))(sc, sc->t1_1);
  55346. set_car(sc->t2_2, find_symbol_checked(sc, caddr(cadr(args))));
  55347. set_car(sc->t2_1, find_symbol_checked(sc, cadr(cadr(args))));
  55348. set_car(sc->t2_2, c_call(cadr(args))(sc, sc->t2_1));
  55349. set_car(sc->t2_1, val3);
  55350. sc->value = c_call(code)(sc, sc->t2_1);
  55351. goto START;
  55352. }
  55353. case OP_SAFE_C_opSSq_opCq:
  55354. if (!c_function_is_ok_cadr_caddr(sc, code)) break;
  55355. case HOP_SAFE_C_opSSq_opCq:
  55356. {
  55357. s7_pointer arg1, arg2, val3;
  55358. arg1 = cadr(code);
  55359. arg2 = caddr(code);
  55360. val3 = find_symbol_checked(sc, caddr(arg1));
  55361. set_car(sc->t2_1, find_symbol_checked(sc, cadr(arg1)));
  55362. set_car(sc->t2_2, val3);
  55363. set_car(sc->t2_1, c_call(arg1)(sc, sc->t2_1));
  55364. set_car(sc->t2_2, c_call(arg2)(sc, cdr(arg2)));
  55365. sc->value = c_call(code)(sc, sc->t2_1);
  55366. goto START;
  55367. }
  55368. /* -------------------------------------------------------------------------------- */
  55369. case OP_C_S:
  55370. if (!c_function_is_ok(sc, code)) break;
  55371. case HOP_C_S:
  55372. sc->args = list_1(sc, find_symbol_checked(sc, cadr(code)));
  55373. sc->value = c_call(code)(sc, sc->args);
  55374. goto START;
  55375. case OP_READ_S:
  55376. if (!c_function_is_ok(sc, code)) break;
  55377. case HOP_READ_S:
  55378. read_s_ex(sc);
  55379. goto START;
  55380. case OP_C_A:
  55381. if (!a_is_ok_cadr(sc, code)) break;
  55382. case HOP_C_A:
  55383. sc->args = list_1(sc, c_call(cdr(code))(sc, cadr(code)));
  55384. sc->value = c_call(code)(sc, sc->args);
  55385. goto START;
  55386. case OP_C_Z:
  55387. if (!c_function_is_ok(sc, code)) break;
  55388. case HOP_C_Z:
  55389. push_stack(sc, OP_C_P_1, sc->nil, code);
  55390. sc->code = cadr(code);
  55391. goto OPT_EVAL;
  55392. case OP_C_P:
  55393. if (!c_function_is_ok(sc, code)) break;
  55394. case HOP_C_P:
  55395. push_stack(sc, OP_C_P_1, sc->nil, code);
  55396. sc->code = cadr(code);
  55397. goto EVAL;
  55398. case OP_C_SS:
  55399. if (!c_function_is_ok(sc, code)) break;
  55400. case HOP_C_SS:
  55401. sc->args = list_2(sc, find_symbol_checked(sc, cadr(code)), find_symbol_checked(sc, caddr(code)));
  55402. sc->value = c_call(code)(sc, sc->args);
  55403. goto START;
  55404. case OP_C_SZ:
  55405. if (!c_function_is_ok(sc, code)) break;
  55406. case HOP_C_SZ:
  55407. push_stack(sc, OP_C_SP_1, find_symbol_checked(sc, cadr(code)), code);
  55408. sc->code = caddr(code);
  55409. goto OPT_EVAL;
  55410. case OP_C_SP:
  55411. if (!c_function_is_ok(sc, code)) break;
  55412. case HOP_C_SP:
  55413. push_stack(sc, OP_C_SP_1, find_symbol_checked(sc, cadr(code)), code);
  55414. sc->code = caddr(code);
  55415. goto EVAL;
  55416. case OP_APPLY_SS:
  55417. if (!c_function_is_ok(sc, code)) break;
  55418. case HOP_APPLY_SS:
  55419. sc->code = find_symbol_checked(sc, cadr(code)); /* global search here was slower */
  55420. sc->args = find_symbol_checked(sc, opt_sym2(code));
  55421. if (!is_proper_list(sc, sc->args)) /* (apply + #f) etc */
  55422. return(apply_list_error(sc, sc->args));
  55423. if (needs_copied_args(sc->code))
  55424. sc->args = copy_list(sc, sc->args);
  55425. goto APPLY;
  55426. case OP_C_S_opSq:
  55427. if ((!c_function_is_ok(sc, code)) || (!indirect_c_function_is_ok(sc, caddr(code)))) break;
  55428. case HOP_C_S_opSq:
  55429. {
  55430. s7_pointer args, val;
  55431. args = cdr(code);
  55432. val = find_symbol_checked(sc, car(args));
  55433. set_car(sc->t1_1, find_symbol_checked(sc, opt_sym1(args)));
  55434. sc->args = list_2(sc, val, c_call(cadr(args))(sc, sc->t1_1));
  55435. sc->value = c_call(code)(sc, sc->args);
  55436. goto START;
  55437. }
  55438. case OP_C_S_opCq:
  55439. if ((!c_function_is_ok(sc, code)) || (!indirect_c_function_is_ok(sc, caddr(code)))) break;
  55440. case HOP_C_S_opCq:
  55441. {
  55442. s7_pointer args, val;
  55443. args = cdr(code);
  55444. sc->temp3 = find_symbol_checked(sc, car(args));
  55445. val = c_call(cadr(args))(sc, opt_pair1(args));
  55446. sc->args = list_2(sc, sc->temp3, val);
  55447. sc->temp3 = sc->nil;
  55448. sc->value = c_call(code)(sc, sc->args);
  55449. goto START;
  55450. }
  55451. case OP_C_SCS:
  55452. if (!c_function_is_ok(sc, code)) break;
  55453. case HOP_C_SCS:
  55454. {
  55455. s7_pointer a1, a2;
  55456. a1 = cdr(code);
  55457. a2 = cdr(a1);
  55458. sc->args = list_3(sc, find_symbol_checked(sc, car(a1)), car(a2), find_symbol_checked(sc, cadr(a2))); /* was unchecked? */
  55459. sc->value = c_call(code)(sc, sc->args);
  55460. goto START;
  55461. }
  55462. case OP_C_ALL_X:
  55463. if (!c_function_is_ok(sc, code)) break;
  55464. case HOP_C_ALL_X:
  55465. { /* (set-cdr! lst ()) */
  55466. s7_pointer args, p;
  55467. sc->args = make_list(sc, integer(arglist_length(code)), sc->nil);
  55468. for (args = cdr(code), p = sc->args; is_pair(args); args = cdr(args), p = cdr(p))
  55469. set_car(p, c_call(args)(sc, car(args)));
  55470. sc->value = c_call(code)(sc, sc->args);
  55471. goto START;
  55472. }
  55473. case OP_CALL_WITH_EXIT:
  55474. if (!c_function_is_ok(sc, code)) break;
  55475. check_lambda_args(sc, cadr(cadr(code)), NULL);
  55476. case HOP_CALL_WITH_EXIT:
  55477. {
  55478. s7_pointer go, args;
  55479. args = opt_pair2(code);
  55480. go = make_goto(sc);
  55481. push_stack(sc, OP_DEACTIVATE_GOTO, go, code); /* code arg is ignored, but perhaps this is safer in GC? */
  55482. new_frame_with_slot(sc, sc->envir, sc->envir, caar(args), go);
  55483. sc->code = cdr(args);
  55484. goto BEGIN1;
  55485. }
  55486. case OP_C_CATCH:
  55487. if (!c_function_is_ok(sc, code)) break;
  55488. check_lambda_args(sc, cadr(cadddr(code)), NULL);
  55489. case HOP_C_CATCH:
  55490. {
  55491. /* (catch #t (lambda () (set! ("hi") #\a)) (lambda args args))
  55492. * code is (catch #t (lambda () ....) (lambda args ....))
  55493. */
  55494. s7_pointer p, f, args, tag;
  55495. args = cddr(code);
  55496. /* defer making the error lambda */
  55497. /* z = cdadr(args); make_closure_with_let(sc, y, car(z), cdr(z), sc->envir); */
  55498. /* check catch tag */
  55499. f = cadr(code);
  55500. if (!is_pair(f)) /* (catch #t ...) or (catch sym ...) */
  55501. {
  55502. if (is_symbol(f))
  55503. tag = find_symbol_checked(sc, f);
  55504. else tag = f;
  55505. }
  55506. else tag = cadr(f); /* (catch 'sym ...) */
  55507. new_cell(sc, p, T_CATCH); /* the catch object sitting on the stack */
  55508. catch_tag(p) = tag;
  55509. catch_goto_loc(p) = s7_stack_top(sc);
  55510. catch_op_loc(p) = (int)(sc->op_stack_now - sc->op_stack);
  55511. catch_handler(p) = cdadr(args); /* not yet a closure... */
  55512. push_stack(sc, OP_CATCH_1, code, p); /* code ignored here, except by GC */
  55513. new_frame(sc, sc->envir, sc->envir);
  55514. sc->code = cddar(args);
  55515. goto BEGIN1;
  55516. }
  55517. case OP_C_CATCH_ALL:
  55518. if (!c_function_is_ok(sc, code)) break;
  55519. case HOP_C_CATCH_ALL:
  55520. {
  55521. /* (catch #t (lambda () ...) (lambda args #f) */
  55522. s7_pointer p;
  55523. new_frame(sc, sc->envir, sc->envir);
  55524. /* catch_all needs 3 pieces of info: the goto/op locs and the result
  55525. * the locs are unsigned ints, so this fits in the new frame's dox1/2 fields.
  55526. */
  55527. p = sc->envir;
  55528. catch_all_set_goto_loc(p, s7_stack_top(sc));
  55529. catch_all_set_op_loc(p, (int)(sc->op_stack_now - sc->op_stack));
  55530. catch_all_set_result(p, opt_con2(code));
  55531. push_stack_no_args(sc, OP_CATCH_ALL, code);
  55532. sc->code = opt_pair1(cdr(code)); /* the body of the first lambda */
  55533. goto BEGIN1; /* removed one_liner check here -- rare */
  55534. }
  55535. /* -------------------------------------------------------------------------------- */
  55536. case OP_THUNK:
  55537. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, 0)) {set_optimize_op(code, OP_UNKNOWN); goto OPT_EVAL;}
  55538. case HOP_THUNK:
  55539. check_stack_size(sc);
  55540. /* this recursion check is consistent with the other unsafe closure calls, but we're probably in big trouble:
  55541. * (letrec ((a (lambda () (cons 1 (b)))) (b (lambda () (a)))) (b))
  55542. * unfortunately the alternative is a segfault when we wander off the end of the stack.
  55543. *
  55544. * It seems that we could use the hop bit here (since it is always off) to choose between BEGIN1 and OPT_EVAL or EVAL,
  55545. * but the EVAL choice gains nothing in time, and the OPT_EVAL choice is too tricky -- it is a two-level optimization,
  55546. * so if the inner (car(closure_body)) gets unopt'd for some reason, the outer HOP_THUNK never finds
  55547. * out, and peculiar things start to happen. (Also, is_h_optimized would need to be smarter).
  55548. */
  55549. new_frame(sc, closure_let(opt_lambda(code)), sc->envir);
  55550. sc->code = closure_body(opt_lambda(code));
  55551. goto BEGIN1;
  55552. case OP_SAFE_THUNK:
  55553. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 0)) {set_optimize_op(code, OP_UNKNOWN); goto OPT_EVAL;}
  55554. case HOP_SAFE_THUNK: /* no frame needed */
  55555. /* (let ((x 1)) (let () (define (f) x) (let ((x 0)) (define (g) (set! x 32) (f)) (g)))) */
  55556. sc->envir = closure_let(opt_lambda(code));
  55557. sc->code = closure_body(opt_lambda(code));
  55558. goto BEGIN1;
  55559. case OP_SAFE_THUNK_E:
  55560. if (find_symbol_unexamined(sc, car(code)) != opt_any1(code)) {set_optimize_op(code, OP_UNKNOWN); goto OPT_EVAL;}
  55561. case HOP_SAFE_THUNK_E:
  55562. sc->envir = closure_let(opt_lambda(code));
  55563. sc->code = car(closure_body(opt_lambda(code)));
  55564. goto OPT_EVAL;
  55565. case OP_SAFE_THUNK_P:
  55566. if (find_symbol_unexamined(sc, car(code)) != opt_any1(code)) {set_optimize_op(code, OP_UNKNOWN); goto OPT_EVAL;}
  55567. case HOP_SAFE_THUNK_P:
  55568. sc->envir = closure_let(opt_lambda(code));
  55569. sc->code = car(closure_body(opt_lambda(code)));
  55570. sc->op = (opcode_t)pair_syntax_op(sc->code);
  55571. sc->code = cdr(sc->code);
  55572. goto START_WITHOUT_POP_STACK;
  55573. case OP_SAFE_CLOSURE_S:
  55574. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 1)) {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55575. case HOP_SAFE_CLOSURE_S:
  55576. /* since a tail call is safe, we can't change the current env's let_id until
  55577. * after we do the lookup -- it might be the current func's arg, and we're
  55578. * about to call the same func.
  55579. */
  55580. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, opt_sym2(code)));
  55581. sc->code = closure_body(opt_lambda(code));
  55582. goto BEGIN1;
  55583. case OP_SAFE_CLOSURE_S_P:
  55584. if (find_symbol_unexamined(sc, car(code)) != opt_any1(code)) {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55585. case HOP_SAFE_CLOSURE_S_P:
  55586. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, opt_sym2(code)));
  55587. sc->code = car(closure_body(opt_lambda(code)));
  55588. sc->op = (opcode_t)pair_syntax_op(sc->code);
  55589. sc->code = cdr(sc->code);
  55590. goto START_WITHOUT_POP_STACK;
  55591. case OP_SAFE_GLOSURE_S:
  55592. if ((symbol_id(car(code)) != 0) ||(opt_any1(code) != slot_value(global_slot(car(code)))))
  55593. {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55594. case HOP_SAFE_GLOSURE_S:
  55595. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, opt_sym2(code)));
  55596. sc->code = closure_body(opt_lambda(code));
  55597. goto BEGIN1;
  55598. case OP_SAFE_GLOSURE_S_E:
  55599. if ((symbol_id(car(code)) != 0) || (opt_any1(code) != slot_value(global_slot(car(code)))))
  55600. {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55601. case HOP_SAFE_GLOSURE_S_E:
  55602. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, opt_sym2(code)));
  55603. sc->code = car(closure_body(opt_lambda(code)));
  55604. goto OPT_EVAL;
  55605. case OP_SAFE_CLOSURE_C:
  55606. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 1)) {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55607. case HOP_SAFE_CLOSURE_C:
  55608. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), cadr(code));
  55609. sc->code = closure_body(opt_lambda(code));
  55610. goto BEGIN1;
  55611. case OP_SAFE_CLOSURE_Q:
  55612. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 1)) {set_optimize_op(code, OP_UNKNOWN_A); goto OPT_EVAL;}
  55613. case HOP_SAFE_CLOSURE_Q:
  55614. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), cadr(cadr(code)));
  55615. sc->code = closure_body(opt_lambda(code));
  55616. goto BEGIN1;
  55617. case OP_SAFE_GLOSURE_P:
  55618. if ((symbol_id(car(code)) != 0) || (opt_any1(code) != slot_value(global_slot(car(code))))) break;
  55619. case HOP_SAFE_GLOSURE_P:
  55620. push_stack(sc, OP_SAFE_CLOSURE_P_1, sc->nil, code);
  55621. sc->code = cadr(code);
  55622. goto EVAL;
  55623. case OP_SAFE_CLOSURE_A:
  55624. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 1)) {set_optimize_op(code, OP_UNKNOWN_A); goto OPT_EVAL;}
  55625. if (!indirect_c_function_is_ok(sc, cadr(code))) break;
  55626. case HOP_SAFE_CLOSURE_A:
  55627. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), c_call(cdr(code))(sc, cadr(code)));
  55628. sc->code = closure_body(opt_lambda(code));
  55629. goto BEGIN1;
  55630. case OP_SAFE_GLOSURE_A:
  55631. if ((symbol_id(car(code)) != 0) || (opt_any1(code) != slot_value(global_slot(car(code)))))
  55632. {set_optimize_op(code, OP_UNKNOWN_A); goto OPT_EVAL;}
  55633. if (!indirect_c_function_is_ok(sc, cadr(code))) break;
  55634. case HOP_SAFE_GLOSURE_A:
  55635. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), c_call(cdr(code))(sc, cadr(code)));
  55636. sc->code = closure_body(opt_lambda(code));
  55637. goto BEGIN1;
  55638. case OP_SAFE_CLOSURE_SS:
  55639. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 2)) {set_optimize_op(code, OP_UNKNOWN_GG); goto OPT_EVAL;}
  55640. case HOP_SAFE_CLOSURE_SS:
  55641. sc->envir = old_frame_with_two_slots(sc, closure_let(opt_lambda(code)),
  55642. find_symbol_checked(sc, cadr(code)),
  55643. find_symbol_checked(sc, opt_sym2(code)));
  55644. sc->code = closure_body(opt_lambda(code));
  55645. goto BEGIN1;
  55646. case OP_SAFE_CLOSURE_SC:
  55647. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 2)) {set_optimize_op(code, OP_UNKNOWN_GG); goto OPT_EVAL;}
  55648. case HOP_SAFE_CLOSURE_SC:
  55649. sc->envir = old_frame_with_two_slots(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, cadr(code)), opt_con2(code));
  55650. sc->code = closure_body(opt_lambda(code));
  55651. goto BEGIN1;
  55652. case OP_SAFE_CLOSURE_CS:
  55653. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 2)) {set_optimize_op(code, OP_UNKNOWN_GG); goto OPT_EVAL;}
  55654. case HOP_SAFE_CLOSURE_CS:
  55655. sc->envir = old_frame_with_two_slots(sc, closure_let(opt_lambda(code)), cadr(code), find_symbol_checked(sc, opt_sym2(code)));
  55656. sc->code = closure_body(opt_lambda(code));
  55657. goto BEGIN1;
  55658. case OP_SAFE_CLOSURE_SA:
  55659. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 2)) {set_optimize_op(code, OP_UNKNOWN_AA); goto OPT_EVAL;}
  55660. case HOP_SAFE_CLOSURE_SA:
  55661. {
  55662. s7_pointer args;
  55663. args = cddr(code);
  55664. args = c_call(args)(sc, car(args));
  55665. sc->envir = old_frame_with_two_slots(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, cadr(code)), args);
  55666. sc->code = closure_body(opt_lambda(code));
  55667. goto BEGIN1;
  55668. }
  55669. case OP_SAFE_CLOSURE_AA:
  55670. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 2)) {set_optimize_op(code, OP_UNKNOWN_AA); goto OPT_EVAL;}
  55671. case HOP_SAFE_CLOSURE_AA:
  55672. {
  55673. s7_pointer args, y, z;
  55674. args = cdr(code);
  55675. y = c_call(args)(sc, car(args));
  55676. args = cdr(args);
  55677. z = c_call(args)(sc, car(args));
  55678. sc->envir = old_frame_with_two_slots(sc, closure_let(opt_lambda(code)), y, z);
  55679. sc->code = closure_body(opt_lambda(code));
  55680. goto BEGIN1;
  55681. }
  55682. case OP_SAFE_CLOSURE_SAA:
  55683. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, 3)) break;
  55684. case HOP_SAFE_CLOSURE_SAA:
  55685. {
  55686. s7_pointer args, y, z;
  55687. args = cddr(code);
  55688. y = c_call(args)(sc, car(args));
  55689. args = cdr(args);
  55690. z = c_call(args)(sc, car(args));
  55691. sc->envir = old_frame_with_three_slots(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, cadr(code)), y, z);
  55692. sc->code = closure_body(opt_lambda(code));
  55693. goto BEGIN1;
  55694. }
  55695. case OP_SAFE_CLOSURE_ALL_X:
  55696. if (!closure_is_ok(sc, code, MATCH_SAFE_CLOSURE, integer(arglist_length(code)))) break;
  55697. case HOP_SAFE_CLOSURE_ALL_X:
  55698. {
  55699. s7_pointer args, p, env, x, z;
  55700. int num_args;
  55701. unsigned long long int id;
  55702. num_args = integer(arglist_length(code));
  55703. if ((num_args != 0) &&
  55704. (num_args < NUM_SAFE_LISTS) &&
  55705. (!list_is_in_use(sc->safe_lists[num_args])))
  55706. {
  55707. sc->args = sc->safe_lists[num_args];
  55708. set_list_in_use(sc->args);
  55709. }
  55710. else sc->args = make_list(sc, num_args, sc->nil);
  55711. for (args = cdr(code), p = sc->args; is_pair(args); args = cdr(args), p = cdr(p))
  55712. set_car(p, c_call(args)(sc, car(args)));
  55713. clear_list_in_use(sc->args);
  55714. sc->code = opt_lambda(code);
  55715. id = ++sc->let_number;
  55716. env = closure_let(sc->code);
  55717. let_id(env) = id;
  55718. for (x = let_slots(env), z = sc->args; is_slot(x); x = next_slot(x), z = cdr(z))
  55719. {
  55720. slot_set_value(x, car(z));
  55721. symbol_set_local(slot_symbol(x), id, x);
  55722. }
  55723. sc->envir = env;
  55724. sc->code = closure_body(sc->code);
  55725. if (is_pair(cdr(sc->code)))
  55726. {
  55727. push_stack_no_args(sc, OP_BEGIN1, cdr(sc->code));
  55728. sc->code = car(sc->code);
  55729. }
  55730. else
  55731. {
  55732. sc->code = car(sc->code);
  55733. if (is_optimized(sc->code))
  55734. goto OPT_EVAL;
  55735. }
  55736. goto EVAL;
  55737. }
  55738. /* -------------------------------------------------------------------------------- */
  55739. case OP_SAFE_CLOSURE_STAR_SS:
  55740. if (!closure_star_is_ok(sc, code, MATCH_SAFE_CLOSURE_STAR, 2)) {set_optimize_op(code, OP_UNKNOWN_GG); goto OPT_EVAL;}
  55741. case HOP_SAFE_CLOSURE_STAR_SS:
  55742. {
  55743. s7_pointer x, val1, val2;
  55744. /* the finders have to operate in the current environment, so we can't change sc->envir until later */
  55745. val1 = find_symbol_checked(sc, cadr(code));
  55746. val2 = find_symbol_checked(sc, opt_sym2(code)); /* caddr */
  55747. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), val1);
  55748. x = next_slot(let_slots(closure_let(opt_lambda(code))));
  55749. slot_set_value(x, val2);
  55750. symbol_set_local(slot_symbol(x), let_id(sc->envir), x);
  55751. fill_safe_closure_star(sc, next_slot(x), cddr(closure_args(opt_lambda(code))));
  55752. goto BEGIN1;
  55753. }
  55754. case OP_SAFE_CLOSURE_STAR_SC:
  55755. if (!closure_star_is_ok(sc, code, MATCH_SAFE_CLOSURE_STAR, 2)) {set_optimize_op(code, OP_UNKNOWN_GG); goto OPT_EVAL;}
  55756. case HOP_SAFE_CLOSURE_STAR_SC:
  55757. {
  55758. s7_pointer x;
  55759. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, cadr(code)));
  55760. x = next_slot(let_slots(closure_let(opt_lambda(code))));
  55761. slot_set_value(x, caddr(code));
  55762. symbol_set_local(slot_symbol(x), let_id(sc->envir), x);
  55763. fill_safe_closure_star(sc, next_slot(x), cddr(closure_args(opt_lambda(code))));
  55764. goto BEGIN1;
  55765. }
  55766. case OP_SAFE_CLOSURE_STAR_SA:
  55767. if (!closure_star_is_ok(sc, code, MATCH_SAFE_CLOSURE_STAR, 2)) break;
  55768. case HOP_SAFE_CLOSURE_STAR_SA:
  55769. {
  55770. s7_pointer arg;
  55771. /* the second arg needs to be evaluated before we set sc->envir.
  55772. * we checked at optimize time that this closure takes only 2 args.
  55773. */
  55774. arg = cddr(code);
  55775. arg = c_call(arg)(sc, car(arg));
  55776. sc->envir = old_frame_with_two_slots(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, cadr(code)), arg);
  55777. sc->code = closure_body(opt_lambda(code));
  55778. goto BEGIN1;
  55779. }
  55780. case OP_SAFE_CLOSURE_STAR_ALL_X:
  55781. if (!closure_star_is_ok(sc, code, MATCH_SAFE_CLOSURE_STAR, integer(arglist_length(code)))) break;
  55782. case HOP_SAFE_CLOSURE_STAR_ALL_X:
  55783. {
  55784. s7_pointer args, p, orig_args, e;
  55785. /* (let () (define* (hi (a 1)) (+ a 1)) (define (ho) (hi (* 2 3))) (ho))
  55786. * (do ((i 0 (+ i 1))) ((= i 11)) (envelope-interp (/ i 21) '(0 0 100 1)))
  55787. */
  55788. e = closure_let(opt_lambda(code));
  55789. for (args = cdr(code), p = let_slots(e), orig_args = closure_args(opt_lambda(code));
  55790. is_pair(args);
  55791. args = cdr(args), orig_args = cdr(orig_args), p = next_slot(p))
  55792. slot_set_pending_value(p, c_call(args)(sc, car(args)));
  55793. /* we're out of caller's args, so fill rest of environment slots from the defaults */
  55794. for (; is_slot(p); p = next_slot(p), orig_args = cdr(orig_args))
  55795. {
  55796. s7_pointer defval;
  55797. if (is_pair(car(orig_args)))
  55798. {
  55799. defval = cadar(orig_args);
  55800. if (is_pair(defval))
  55801. slot_set_pending_value(p, cadr(defval));
  55802. else slot_set_pending_value(p, defval);
  55803. }
  55804. else slot_set_pending_value(p, sc->F);
  55805. }
  55806. /* we have to put off the actual environment update in case this is a tail recursive call */
  55807. let_id(e) = ++sc->let_number;
  55808. for (p = let_slots(e); is_slot(p); p = next_slot(p))
  55809. {
  55810. slot_set_value(p, slot_pending_value(p));
  55811. symbol_set_local(slot_symbol(p), let_id(e), p);
  55812. }
  55813. sc->envir = e;
  55814. sc->code = closure_body(opt_lambda(code));
  55815. goto BEGIN1;
  55816. }
  55817. case OP_SAFE_CLOSURE_STAR:
  55818. if (!closure_star_is_ok(sc, code, MATCH_SAFE_CLOSURE_STAR, 0)) {set_optimize_op(code, OP_UNKNOWN); goto OPT_EVAL;}
  55819. case HOP_SAFE_CLOSURE_STAR:
  55820. /* (let () (define* (hi (a 100)) (random a)) (define (ho) (hi)) (ho)) */
  55821. sc->envir = closure_let(opt_lambda(code));
  55822. let_id(sc->envir) = ++sc->let_number;
  55823. fill_safe_closure_star(sc, let_slots(closure_let(opt_lambda(code))), closure_args(opt_lambda(code)));
  55824. goto BEGIN1;
  55825. case OP_SAFE_CLOSURE_STAR_S0:
  55826. if (find_symbol_unexamined(sc, car(code)) != opt_any1(code)) {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55827. case HOP_SAFE_CLOSURE_STAR_S0:
  55828. /* here we know we have (let-set! arg1 'name arg2) (with-env arg1 ...) as the safe closure body.
  55829. * since no errors can come from the first, there's no need for the procedure env.
  55830. * so do the set and with-env by hand, leaving with the env body.
  55831. */
  55832. {
  55833. s7_pointer e;
  55834. e = find_symbol_checked(sc, cadr(code)); /* S of S0 above */
  55835. if (e == sc->rootlet)
  55836. sc->envir = sc->nil;
  55837. else
  55838. {
  55839. if (!is_let(e))
  55840. eval_type_error(sc, "with-let takes an environment argument: ~A", e);
  55841. sc->envir = e;
  55842. set_with_let_let(e);
  55843. }
  55844. if (e != sc->rootlet)
  55845. {
  55846. s7_pointer p;
  55847. let_id(e) = ++sc->let_number;
  55848. for (p = let_slots(e); is_slot(p); p = next_slot(p))
  55849. {
  55850. s7_pointer sym;
  55851. sym = slot_symbol(p);
  55852. symbol_set_local(sym, sc->let_number, p);
  55853. }
  55854. slot_set_value(local_slot(opt_sym1(cdr(code))), real_zero); /* "arg2" above */
  55855. }
  55856. sc->code = opt_pair2(cdr(code));
  55857. goto BEGIN1;
  55858. }
  55859. case OP_SAFE_CLOSURE_STAR_S:
  55860. if (!closure_star_is_ok(sc, code, MATCH_SAFE_CLOSURE_STAR, 1)) {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55861. case HOP_SAFE_CLOSURE_STAR_S:
  55862. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(code)), find_symbol_checked(sc, opt_sym2(code)));
  55863. /* that sets the first arg to the passed symbol value; now set default values, if any */
  55864. fill_safe_closure_star(sc, next_slot(let_slots(closure_let(opt_lambda(code)))), cdr(closure_args(opt_lambda(code))));
  55865. goto BEGIN1;
  55866. /* -------------------------------------------------------------------------------- */
  55867. case OP_GOTO:
  55868. set_opt_goto(code, find_symbol_checked(sc, car(code)));
  55869. if (!is_goto(opt_goto(code))) {set_optimize_op(code, OP_UNKNOWN); goto OPT_EVAL;}
  55870. case HOP_GOTO:
  55871. sc->args = sc->nil;
  55872. sc->code = opt_goto(code);
  55873. call_with_exit(sc);
  55874. goto START;
  55875. case OP_GOTO_C:
  55876. /* call-with-exit repeat use internally is very rare, so let's just look it up */
  55877. set_opt_goto(code, find_symbol_checked(sc, car(code)));
  55878. if (!is_goto(opt_goto(code)))
  55879. {
  55880. set_optimize_op(code, OP_UNKNOWN_G);
  55881. goto OPT_EVAL;
  55882. }
  55883. case HOP_GOTO_C:
  55884. /* (return #t) -- recognized via OP_UNKNOWN_G, opt_goto(code) is the function [parallels OP_CLOSURE_C] */
  55885. sc->args = cdr(code);
  55886. sc->code = opt_goto(code);
  55887. call_with_exit(sc);
  55888. goto START;
  55889. case OP_GOTO_S:
  55890. set_opt_goto(code, find_symbol_checked(sc, car(code)));
  55891. if (!is_goto(opt_goto(code))) {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55892. case HOP_GOTO_S:
  55893. sc->args = list_1(sc, find_symbol_checked(sc, cadr(code)));
  55894. /* I think this needs listification because call_with_exit might call dynamic unwinders etc. */
  55895. sc->code = opt_goto(code);
  55896. call_with_exit(sc);
  55897. goto START;
  55898. case OP_GOTO_A:
  55899. set_opt_goto(code, find_symbol_checked(sc, car(code)));
  55900. if (!is_goto(opt_goto(code))) {set_optimize_op(code, OP_UNKNOWN_A); goto OPT_EVAL;}
  55901. case HOP_GOTO_A:
  55902. sc->args = list_1(sc, c_call(cdr(code))(sc, cadr(code)));
  55903. sc->code = opt_goto(code);
  55904. call_with_exit(sc);
  55905. goto START;
  55906. /* for T_CONTINUATION, set sc->args to list_1(sc, ...) as in goto (and code?), then call_with_current_continuation */
  55907. case OP_CLOSURE_C:
  55908. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, 1)) {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55909. case HOP_CLOSURE_C:
  55910. check_stack_size(sc);
  55911. code = opt_lambda(code);
  55912. new_frame_with_slot(sc, closure_let(code), sc->envir, car(closure_args(code)), cadr(sc->code));
  55913. sc->code = closure_body(code);
  55914. goto BEGIN1;
  55915. case OP_CLOSURE_Q:
  55916. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, 1)) {set_optimize_op(code, OP_UNKNOWN_A); goto OPT_EVAL;}
  55917. case HOP_CLOSURE_Q:
  55918. check_stack_size(sc);
  55919. code = opt_lambda(code);
  55920. new_frame_with_slot(sc, closure_let(code), sc->envir, car(closure_args(code)), cadr(cadr(sc->code)));
  55921. sc->code = closure_body(code);
  55922. goto BEGIN1;
  55923. case OP_CLOSURE_A:
  55924. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, 1)) {set_optimize_op(code, OP_UNKNOWN_A); goto OPT_EVAL;}
  55925. if (!indirect_c_function_is_ok(sc, cadr(code))) break;
  55926. case HOP_CLOSURE_A:
  55927. sc->value = c_call(cdr(code))(sc, cadr(code));
  55928. check_stack_size(sc);
  55929. code = opt_lambda(code);
  55930. new_frame_with_slot(sc, closure_let(code), sc->envir, car(closure_args(code)), sc->value);
  55931. sc->code = closure_body(code);
  55932. goto BEGIN1;
  55933. case OP_GLOSURE_A:
  55934. if ((symbol_id(car(code)) != 0) || (opt_lambda_unchecked(code) != slot_value(global_slot(car(code)))))
  55935. {set_optimize_op(code, OP_UNKNOWN_A); goto OPT_EVAL;}
  55936. if (!indirect_c_function_is_ok(sc, cadr(code))) break;
  55937. case HOP_GLOSURE_A:
  55938. sc->value = c_call(cdr(code))(sc, cadr(code));
  55939. check_stack_size(sc);
  55940. code = opt_lambda(code);
  55941. new_frame_with_slot(sc, closure_let(code), sc->envir, car(closure_args(code)), sc->value);
  55942. sc->code = closure_body(code);
  55943. goto BEGIN1;
  55944. case OP_GLOSURE_P:
  55945. if ((symbol_id(car(code)) != 0) || (opt_lambda_unchecked(code) != slot_value(global_slot(car(code))))) break;
  55946. case HOP_GLOSURE_P:
  55947. push_stack(sc, OP_CLOSURE_P_1, sc->nil, code);
  55948. sc->code = cadr(code);
  55949. goto EVAL;
  55950. case OP_GLOSURE_S:
  55951. if ((symbol_id(car(code)) != 0) || (opt_any1(code) != slot_value(global_slot(car(code)))))
  55952. {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55953. case HOP_GLOSURE_S:
  55954. sc->value = find_symbol_checked(sc, opt_sym2(code));
  55955. check_stack_size(sc);
  55956. code = opt_lambda(code);
  55957. new_frame_with_slot(sc, closure_let(code), sc->envir, car(closure_args(code)), sc->value);
  55958. sc->code = closure_body(code);
  55959. goto BEGIN1;
  55960. case OP_CLOSURE_S:
  55961. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, 1)) {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  55962. case HOP_CLOSURE_S:
  55963. sc->value = find_symbol_checked(sc, opt_sym2(code));
  55964. check_stack_size(sc);
  55965. code = opt_lambda(code);
  55966. new_frame_with_slot(sc, closure_let(code), sc->envir, car(closure_args(code)), sc->value);
  55967. sc->code = closure_body(code);
  55968. goto BEGIN1;
  55969. case OP_CLOSURE_SS:
  55970. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, 2)) {set_optimize_op(code, OP_UNKNOWN_GG); goto OPT_EVAL;}
  55971. case HOP_CLOSURE_SS: /* only called if one of these symbols has an accessor */
  55972. unsafe_closure_2(sc, find_symbol_checked(sc, cadr(code)), find_symbol_checked(sc, opt_sym2(code)));
  55973. goto BEGIN1;
  55974. case OP_CLOSURE_SC:
  55975. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, 2)) {set_optimize_op(code, OP_UNKNOWN_GG); goto OPT_EVAL;}
  55976. case HOP_CLOSURE_SC:
  55977. unsafe_closure_2(sc, find_symbol_checked(sc, cadr(code)), opt_con2(code));
  55978. goto BEGIN1;
  55979. case OP_CLOSURE_CS:
  55980. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, 2)) {set_optimize_op(code, OP_UNKNOWN_GG); goto OPT_EVAL;}
  55981. case HOP_CLOSURE_CS:
  55982. unsafe_closure_2(sc, cadr(code), find_symbol_checked(sc, opt_sym2(code)));
  55983. goto BEGIN1;
  55984. case OP_CLOSURE_AA:
  55985. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, 2)) {set_optimize_op(code, OP_UNKNOWN_AA); goto OPT_EVAL;}
  55986. if ((is_optimized(cadr(code))) && (!indirect_c_function_is_ok(sc, cadr(code)))) break;
  55987. if ((is_optimized(caddr(code))) && (!indirect_c_function_is_ok(sc, caddr(code)))) break;
  55988. case HOP_CLOSURE_AA:
  55989. {
  55990. s7_pointer args;
  55991. args = cdr(code);
  55992. sc->temp2 = c_call(args)(sc, car(args));
  55993. unsafe_closure_2(sc, sc->temp2, c_call(cdr(args))(sc, cadr(args)));
  55994. goto BEGIN1;
  55995. }
  55996. case OP_CLOSURE_ALL_S:
  55997. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, integer(arglist_length(code)))) {set_optimize_op(code, OP_UNKNOWN_ALL_S); goto OPT_EVAL;}
  55998. case HOP_CLOSURE_ALL_S:
  55999. {
  56000. s7_pointer args, p, func, e;
  56001. /* in this case, we have just lambda (not lambda*), and no dotted arglist,
  56002. * and no accessed symbols in the arglist, and we know the arglist matches the parameter list.
  56003. */
  56004. check_stack_size(sc);
  56005. func = opt_lambda(code);
  56006. /* we need to get the slot names from the current function, but the values from the calling environment */
  56007. new_frame(sc, closure_let(func), e);
  56008. sc->z = e;
  56009. for (p = closure_args(func), args = cdr(code); is_pair(p); p = cdr(p), args = cdr(args))
  56010. add_slot(e, car(p), find_symbol_checked(sc, car(args)));
  56011. sc->envir = e;
  56012. sc->z = sc->nil;
  56013. sc->code = closure_body(func);
  56014. goto BEGIN1;
  56015. }
  56016. case OP_CLOSURE_ALL_X:
  56017. check_stack_size(sc);
  56018. if (!closure_is_ok(sc, code, MATCH_UNSAFE_CLOSURE, integer(arglist_length(code)))) {set_optimize_op(code, OP_UNKNOWN_ALL_X); goto OPT_EVAL;}
  56019. case HOP_CLOSURE_ALL_X:
  56020. {
  56021. s7_pointer args, p, func, e;
  56022. func = opt_lambda(code);
  56023. new_frame(sc, closure_let(func), e);
  56024. sc->z = e;
  56025. for (p = closure_args(func), args = cdr(code); is_pair(p); p = cdr(p), args = cdr(args))
  56026. {
  56027. s7_pointer val;
  56028. val = c_call(args)(sc, car(args));
  56029. add_slot_checked(e, car(p), val); /* can't use add_slot here -- all_x_c_* hit trigger? */
  56030. }
  56031. sc->envir = e;
  56032. sc->z = sc->nil;
  56033. sc->code = closure_body(func);
  56034. goto BEGIN1;
  56035. }
  56036. /* -------------------------------------------------------------------------------- */
  56037. case OP_CLOSURE_STAR_ALL_X:
  56038. if (!closure_star_is_ok(sc, code, MATCH_UNSAFE_CLOSURE_STAR, integer(arglist_length(code))))
  56039. {
  56040. set_optimize_op(code, OP_UNKNOWN_ALL_X);
  56041. goto OPT_EVAL;
  56042. }
  56043. case HOP_CLOSURE_STAR_ALL_X:
  56044. {
  56045. /* here also, all the args are simple */
  56046. /* (let () (define* (hi (a 1)) (list a)) (define (ho) (hi (* 2 3))) (ho))
  56047. */
  56048. s7_pointer args, p, func, new_args;
  56049. func = opt_lambda(code);
  56050. sc->args = make_list(sc, closure_star_arity_to_int(sc, func), sc->nil);
  56051. new_args = sc->args;
  56052. for (p = closure_args(func), args = cdr(code); is_pair(args); p = cdr(p), args = cdr(args), new_args = cdr(new_args))
  56053. set_car(new_args, c_call(args)(sc, car(args)));
  56054. for (; is_pair(p); p = cdr(p), new_args = cdr(new_args))
  56055. {
  56056. s7_pointer defval;
  56057. if (is_pair(car(p)))
  56058. {
  56059. defval = cadar(p);
  56060. if (is_pair(defval))
  56061. set_car(new_args, cadr(defval));
  56062. else set_car(new_args, defval);
  56063. }
  56064. else set_car(new_args, sc->F);
  56065. }
  56066. sc->code = opt_lambda(code);
  56067. unsafe_closure_star(sc);
  56068. goto BEGIN1;
  56069. }
  56070. case OP_CLOSURE_STAR_SX:
  56071. if (!closure_star_is_ok(sc, code, MATCH_UNSAFE_CLOSURE_STAR, 2)) {set_optimize_op(code, OP_UNKNOWN_GG); goto OPT_EVAL;}
  56072. case HOP_CLOSURE_STAR_SX:
  56073. {
  56074. s7_pointer val1, val2, args;
  56075. args = cddr(closure_args(opt_lambda(code)));
  56076. val1 = find_symbol_checked(sc, cadr(code));
  56077. val2 = caddr(code);
  56078. if (is_symbol(val2))
  56079. val2 = find_symbol_checked(sc, val2);
  56080. if (is_null(args))
  56081. {
  56082. set_car(sc->t2_1, val1);
  56083. set_car(sc->t2_2, val2);
  56084. code = opt_lambda(sc->code);
  56085. args = closure_args(code);
  56086. new_frame_with_two_slots(sc, closure_let(code), sc->envir,
  56087. (is_pair(car(args))) ? caar(args) : car(args), car(sc->t2_1),
  56088. (is_pair(cadr(args))) ? caadr(args) : cadr(args), car(sc->t2_2));
  56089. sc->code = closure_body(code);
  56090. }
  56091. else
  56092. {
  56093. sc->args = list_2(sc, val2, val1);
  56094. fill_closure_star(sc, args);
  56095. unsafe_closure_star(sc);
  56096. }
  56097. goto BEGIN1;
  56098. }
  56099. case OP_CLOSURE_STAR:
  56100. if (!closure_star_is_ok(sc, code, MATCH_UNSAFE_CLOSURE_STAR, 0)) {set_optimize_op(code, OP_UNKNOWN); goto OPT_EVAL;}
  56101. case HOP_CLOSURE_STAR:
  56102. /* (let () (define* (hi (a 1)) (list a)) (define (ho) (hi)) (ho)) */
  56103. sc->args = sc->nil;
  56104. fill_closure_star(sc, closure_args(opt_lambda(code)));
  56105. unsafe_closure_star(sc);
  56106. goto BEGIN1;
  56107. case OP_CLOSURE_STAR_S:
  56108. if (!closure_star_is_ok(sc, code, MATCH_UNSAFE_CLOSURE_STAR, 1)) {set_optimize_op(code, OP_UNKNOWN_G); goto OPT_EVAL;}
  56109. case HOP_CLOSURE_STAR_S:
  56110. sc->args = list_1(sc, find_symbol_checked(sc, opt_sym2(code)));
  56111. fill_closure_star(sc, cdr(closure_args(opt_lambda(code))));
  56112. unsafe_closure_star(sc);
  56113. goto BEGIN1;
  56114. /* -------------------------------------------------------------------------------- */
  56115. case OP_UNKNOWN:
  56116. case HOP_UNKNOWN:
  56117. if (unknown_ex(sc, find_symbol_checked(sc, car(code))) == goto_OPT_EVAL)
  56118. goto OPT_EVAL;
  56119. break;
  56120. case OP_UNKNOWN_G:
  56121. case HOP_UNKNOWN_G:
  56122. if (unknown_g_ex(sc, find_symbol_checked(sc, car(code))) == goto_OPT_EVAL)
  56123. goto OPT_EVAL;
  56124. break;
  56125. case OP_UNKNOWN_GG:
  56126. case HOP_UNKNOWN_GG:
  56127. if (unknown_gg_ex(sc, find_symbol_checked(sc, car(code))) == goto_OPT_EVAL)
  56128. goto OPT_EVAL;
  56129. break;
  56130. case OP_UNKNOWN_ALL_S:
  56131. case HOP_UNKNOWN_ALL_S:
  56132. if (unknown_all_s_ex(sc, find_symbol_checked(sc, car(code))) == goto_OPT_EVAL)
  56133. goto OPT_EVAL;
  56134. break;
  56135. case OP_UNKNOWN_A:
  56136. case HOP_UNKNOWN_A:
  56137. if (unknown_a_ex(sc, find_symbol_checked(sc, car(code))) == goto_OPT_EVAL)
  56138. goto OPT_EVAL;
  56139. break;
  56140. case OP_UNKNOWN_AA:
  56141. case HOP_UNKNOWN_AA:
  56142. if (unknown_aa_ex(sc, find_symbol_checked(sc, car(code))) == goto_OPT_EVAL)
  56143. goto OPT_EVAL;
  56144. break;
  56145. case OP_UNKNOWN_ALL_X:
  56146. case HOP_UNKNOWN_ALL_X:
  56147. if (unknown_all_x_ex(sc, find_symbol_checked(sc, car(code))) == goto_OPT_EVAL)
  56148. goto OPT_EVAL;
  56149. break;
  56150. /* -------------------------------------------------------------------------------- */
  56151. case OP_VECTOR_C:
  56152. case HOP_VECTOR_C:
  56153. if (vector_c_ex(sc) == goto_START) goto START;
  56154. break;
  56155. case OP_VECTOR_CC:
  56156. case HOP_VECTOR_CC:
  56157. if (vector_cc_ex(sc) == goto_START) goto START;
  56158. break;
  56159. case OP_VECTOR_A:
  56160. if (!indirect_cq_function_is_ok(sc, cadr(code))) break;
  56161. case HOP_VECTOR_A:
  56162. if (vector_a_ex(sc) == goto_START) goto START;
  56163. break;
  56164. case OP_VECTOR_S:
  56165. case HOP_VECTOR_S:
  56166. if (vector_s_ex(sc) == goto_START) goto START;
  56167. break;
  56168. case OP_STRING_C:
  56169. case HOP_STRING_C:
  56170. if (string_c_ex(sc) == goto_START) goto START;
  56171. break;
  56172. case OP_STRING_A:
  56173. if (!indirect_cq_function_is_ok(sc, cadr(code))) break;
  56174. case HOP_STRING_A:
  56175. if (string_a_ex(sc) == goto_START) goto START;
  56176. break;
  56177. case OP_STRING_S:
  56178. case HOP_STRING_S:
  56179. if (string_s_ex(sc) == goto_START) goto START;
  56180. break;
  56181. case OP_HASH_TABLE_C:
  56182. case HOP_HASH_TABLE_C:
  56183. {
  56184. s7_pointer s;
  56185. s = find_symbol_checked(sc, car(code));
  56186. if (!is_hash_table(s)) break;
  56187. sc->value = s7_hash_table_ref(sc, s, cadr(code));
  56188. goto START;
  56189. }
  56190. case OP_HASH_TABLE_S:
  56191. case HOP_HASH_TABLE_S:
  56192. {
  56193. s7_pointer s;
  56194. s = find_symbol_checked(sc, car(code));
  56195. if (!is_hash_table(s)) break;
  56196. sc->value = s7_hash_table_ref(sc, s, find_symbol_checked(sc, cadr(code)));
  56197. goto START;
  56198. }
  56199. case OP_HASH_TABLE_A:
  56200. if (!indirect_cq_function_is_ok(sc, cadr(code))) break;
  56201. case HOP_HASH_TABLE_A:
  56202. {
  56203. s7_pointer s;
  56204. s = find_symbol_checked(sc, car(code));
  56205. if (!is_hash_table(s)) break;
  56206. sc->value = s7_hash_table_ref(sc, s, c_call(cdr(code))(sc, cadr(code)));
  56207. goto START;
  56208. }
  56209. case OP_ENVIRONMENT_C:
  56210. case HOP_ENVIRONMENT_C:
  56211. {
  56212. s7_pointer s;
  56213. s = find_symbol_checked(sc, car(code));
  56214. if (!is_let(s)) break;
  56215. sc->value = s7_let_ref(sc, s, cadr(code));
  56216. goto START;
  56217. }
  56218. case OP_ENVIRONMENT_S:
  56219. case HOP_ENVIRONMENT_S:
  56220. {
  56221. s7_pointer s;
  56222. s = find_symbol_checked(sc, car(code));
  56223. if (!is_let(s)) break;
  56224. sc->value = s7_let_ref(sc, s, find_symbol_checked(sc, cadr(code)));
  56225. goto START;
  56226. }
  56227. case OP_ENVIRONMENT_Q:
  56228. case HOP_ENVIRONMENT_Q:
  56229. {
  56230. s7_pointer s, sym;
  56231. s = find_symbol_checked(sc, car(code));
  56232. if (!is_let(s)) break;
  56233. sym = cadr(cadr(code));
  56234. if (is_symbol(sym))
  56235. sc->value = let_ref_1(sc, s, sym);
  56236. else return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 2, sym, a_symbol_string)); /* (e '(1)) */
  56237. goto START;
  56238. }
  56239. case OP_ENVIRONMENT_A:
  56240. if (!indirect_cq_function_is_ok(sc, cadr(code))) break;
  56241. case HOP_ENVIRONMENT_A:
  56242. {
  56243. s7_pointer s, sym;
  56244. s = find_symbol_checked(sc, car(code));
  56245. if (!is_let(s)) break;
  56246. sym = c_call(cdr(code))(sc, cadr(code));
  56247. if (is_symbol(sym))
  56248. sc->value = let_ref_1(sc, s, sym);
  56249. else return(wrong_type_argument_with_type(sc, sc->let_ref_symbol, 2, sym, a_symbol_string)); /* (e expr) where expr->#f */
  56250. goto START;
  56251. }
  56252. case OP_PAIR_C:
  56253. case HOP_PAIR_C:
  56254. {
  56255. s7_pointer s;
  56256. s = find_symbol_checked(sc, car(code));
  56257. if (!is_pair(s)) break; /* this used to check is_integer(cadr(code)) but surely an error is correct if s is a pair? */
  56258. sc->value = list_ref_1(sc, s, cadr(code));
  56259. goto START;
  56260. }
  56261. case OP_PAIR_A:
  56262. if (!indirect_cq_function_is_ok(sc, cadr(code))) break;
  56263. case HOP_PAIR_A:
  56264. {
  56265. s7_pointer s, x;
  56266. s = find_symbol_checked(sc, car(code));
  56267. if (!is_pair(s)) break;
  56268. x = c_call(cdr(code))(sc, cadr(code));
  56269. sc->value = list_ref_1(sc, s, x);
  56270. goto START;
  56271. }
  56272. case OP_PAIR_S:
  56273. case HOP_PAIR_S:
  56274. {
  56275. s7_pointer s, ind;
  56276. s = find_symbol_checked(sc, car(code));
  56277. if (!is_pair(s)) break;
  56278. ind = find_symbol_checked(sc, cadr(code));
  56279. sc->value = list_ref_1(sc, s, ind);
  56280. goto START;
  56281. }
  56282. case OP_C_OBJECT:
  56283. case HOP_C_OBJECT:
  56284. {
  56285. s7_pointer c;
  56286. c = find_symbol_checked(sc, car(code));
  56287. if (!is_c_object(c)) break;
  56288. sc->value = (*(c_object_ref(c)))(sc, c, sc->nil);
  56289. goto START;
  56290. }
  56291. case OP_C_OBJECT_C:
  56292. case HOP_C_OBJECT_C:
  56293. {
  56294. s7_pointer c;
  56295. c = find_symbol_checked(sc, car(code));
  56296. if (!is_c_object(c)) break;
  56297. sc->value = (*(c_object_ref(c)))(sc, c, cdr(code));
  56298. goto START;
  56299. }
  56300. case OP_C_OBJECT_A:
  56301. if (!indirect_cq_function_is_ok(sc, cadr(code))) break;
  56302. case HOP_C_OBJECT_A:
  56303. {
  56304. s7_pointer c;
  56305. c = find_symbol_checked(sc, car(code));
  56306. if (!is_c_object(c)) break;
  56307. set_car(sc->t1_1, c_call(cdr(code))(sc, cadr(code)));
  56308. sc->value = (*(c_object_ref(c)))(sc, c, sc->t1_1);
  56309. goto START;
  56310. }
  56311. case OP_C_OBJECT_S:
  56312. case HOP_C_OBJECT_S:
  56313. {
  56314. s7_pointer c;
  56315. c = find_symbol_checked(sc, car(code));
  56316. if (!is_c_object(c)) break;
  56317. set_car(sc->t1_1, find_symbol_checked(sc, cadr(code)));
  56318. sc->value = (*(c_object_ref(c)))(sc, c, sc->t1_1);
  56319. goto START;
  56320. }
  56321. default:
  56322. fprintf(stderr, "bad op in opt_eval: op %u, is_opt: %d, %s\n", optimize_op(code), is_optimized(code), DISPLAY_80(code));
  56323. break;
  56324. }
  56325. /* else cancel all the optimization info -- someone stepped on our symbol */
  56326. /* there is a problem with this -- if the caller still insists on goto OPT_EVAL, for example,
  56327. * we get here over and over. (let ((x (list (car y))))...) where list is redefined away.
  56328. */
  56329. #if DEBUGGING
  56330. /* we hit this in zauto (cdr-constants ...) h_vector_s|c (there is no difference here between hop_ and op_)
  56331. */
  56332. if ((is_h_optimized(sc->code)) &&
  56333. (optimize_op(sc->code) != HOP_VECTOR_C) &&
  56334. (optimize_op(sc->code) != HOP_VECTOR_S))
  56335. fprintf(stderr, "%s[%d]: clearing %s in %s\n", __func__, __LINE__, opt_names[optimize_op(sc->code)], DISPLAY(sc->code));
  56336. #endif
  56337. clear_all_optimizations(sc, code);
  56338. /* and fall into the normal evaluator */
  56339. }
  56340. /* fprintf(stderr, "trail: %s\n", DISPLAY(sc->code)); */
  56341. {
  56342. s7_pointer code, carc;
  56343. code = sc->code;
  56344. if (is_pair(code))
  56345. {
  56346. #if WITH_PROFILE
  56347. profile(sc, code);
  56348. #endif
  56349. set_current_code(sc, code);
  56350. carc = car(code);
  56351. if (typesflag(carc) == SYNTACTIC_TYPE)
  56352. {
  56353. set_syntactic_pair(code); /* leave other bits (T_LINE_NUMBER) intact */
  56354. set_car(code, syntax_symbol(slot_value(initial_slot(carc)))); /* clear possible optimization confusion */
  56355. sc->op = (opcode_t)symbol_syntax_op(car(code));
  56356. pair_set_syntax_op(code, sc->op);
  56357. sc->code = cdr(code);
  56358. goto START_WITHOUT_POP_STACK;
  56359. }
  56360. /* -------------------------------------------------------------------------------- */
  56361. /* trailers */
  56362. if (is_symbol(carc))
  56363. {
  56364. /* car is a symbol, sc->code a list */
  56365. sc->value = find_global_symbol_checked(sc, carc);
  56366. sc->code = cdr(code);
  56367. /* drop into eval args */
  56368. }
  56369. else
  56370. {
  56371. /* very uncommon case: car is either itself a pair or some non-symbol */
  56372. if (is_pair(carc))
  56373. {
  56374. /* evaluate the inner list but that list can be circular: carc: #1=(#1# #1#)!
  56375. * and the cycle can be well-hidden -- #1=((#1 2) . 2) and other such stuff
  56376. */
  56377. if (sc->stack_end >= sc->stack_resize_trigger)
  56378. check_for_cyclic_code(sc, code);
  56379. push_stack(sc, OP_EVAL_ARGS, sc->nil, cdr(code));
  56380. if (typesflag(car(carc)) == SYNTACTIC_TYPE)
  56381. /* was checking for is_syntactic here but that can be confused by successive optimizer passes:
  56382. * (define (hi) (((lambda () list)) 1 2 3)) etc
  56383. */
  56384. {
  56385. if ((car(carc) == sc->quote_symbol) && /* ('and #f) */
  56386. ((!is_pair(cdr(carc))) || /* ((quote . #\h) (2 . #\i)) ! */
  56387. (is_syntactic(cadr(carc)))))
  56388. return(apply_error(sc, (is_pair(cdr(carc))) ? cadr(carc) : carc, cdr(code)));
  56389. sc->op = (opcode_t)symbol_syntax_op(car(carc));
  56390. sc->code = cdr(carc);
  56391. goto START_WITHOUT_POP_STACK;
  56392. }
  56393. push_stack(sc, OP_EVAL_ARGS, sc->nil, cdr(carc));
  56394. sc->code = car(carc);
  56395. goto EVAL;
  56396. }
  56397. else
  56398. {
  56399. /* car must be the function to be applied */
  56400. sc->value = _NFre(carc);
  56401. sc->code = cdr(code);
  56402. /* drop into OP_EVAL_ARGS */
  56403. }
  56404. }
  56405. }
  56406. else /* sc->code is not a pair */
  56407. {
  56408. if (is_symbol(code))
  56409. {
  56410. sc->value = find_symbol_checked(sc, code);
  56411. pop_stack(sc);
  56412. if (sc->op != OP_EVAL_ARGS)
  56413. goto START_WITHOUT_POP_STACK;
  56414. /* drop into OP_EVAL_ARGS */
  56415. }
  56416. else
  56417. {
  56418. /* sc->code is not a pair or a symbol */
  56419. sc->value = _NFre(code);
  56420. goto START;
  56421. }
  56422. }
  56423. /* sc->value is car=something applicable
  56424. * sc->code = rest of expression
  56425. * sc->args is nil (set by the drop-through cases above -- perhaps clearer to bring that down?)
  56426. */
  56427. }
  56428. case OP_EVAL_ARGS:
  56429. if (dont_eval_args(sc->value))
  56430. {
  56431. if (is_any_macro(sc->value))
  56432. {
  56433. /* macro expansion */
  56434. sc->args = copy_list_with_arglist_error(sc, sc->code);
  56435. sc->code = sc->value;
  56436. goto APPLY; /* not UNSAFE_CLOSURE because it might be a bacro */
  56437. }
  56438. /* (define progn begin) (progn (display "hi") (+ 1 23)) */
  56439. if (!is_syntax(sc->value))
  56440. eval_error(sc, "attempt to evaluate: ~A?", sc->code);
  56441. sc->op = (opcode_t)syntax_opcode(sc->value);
  56442. goto START_WITHOUT_POP_STACK;
  56443. }
  56444. /* sc->value is the func
  56445. * we don't have to delay lookup of the func because arg evaluation order is not specified, so
  56446. * (let ((func +)) (func (let () (set! func -) 3) 2))
  56447. * can return 5.
  56448. */
  56449. /* if (is_null(sc->code)) {sc->code = sc->value; goto APPLY;}
  56450. * this is hit very rarely so it costs more than it saves
  56451. */
  56452. push_op_stack(sc, sc->value);
  56453. if (sc->op_stack_now >= sc->op_stack_end)
  56454. resize_op_stack(sc);
  56455. sc->args = sc->nil;
  56456. goto EVAL_ARGS;
  56457. /* moving eval_args up here (to avoid this goto) was slightly slower, probably by chance. */
  56458. case OP_EVAL_ARGS5:
  56459. /* sc->value is the last arg, sc->code is the previous */
  56460. {
  56461. s7_pointer x, y;
  56462. new_cell(sc, x, T_PAIR);
  56463. new_cell_no_check(sc, y, T_PAIR);
  56464. set_car(x, sc->code);
  56465. set_cdr(x, sc->args);
  56466. set_car(y, sc->value);
  56467. set_cdr(y, x);
  56468. sc->args = safe_reverse_in_place(sc, y);
  56469. sc->code = pop_op_stack(sc);
  56470. goto APPLY;
  56471. }
  56472. case OP_EVAL_ARGS2:
  56473. /* sc->value is the last arg, [so if is_null(cdr(sc->code) and current is pair, push args2] */
  56474. {
  56475. s7_pointer x;
  56476. sc->code = pop_op_stack(sc);
  56477. new_cell(sc, x, T_PAIR);
  56478. set_car(x, sc->value);
  56479. set_cdr(x, sc->args);
  56480. if (!is_null(sc->args))
  56481. sc->args = safe_reverse_in_place(sc, x);
  56482. else sc->args = x;
  56483. goto APPLY;
  56484. }
  56485. /* tricky cases here all involve values (i.e. multiple-values) */
  56486. case OP_EVAL_ARGS_P_2:
  56487. /* from HOP_SAFE_C_SP||CP|QP, handled like P_1 case above
  56488. * primarily involves generators: (outa i (nrcos gen)) etc
  56489. */
  56490. set_car(sc->t2_1, sc->args);
  56491. set_car(sc->t2_2, sc->value);
  56492. sc->value = c_call(sc->code)(sc, sc->t2_1);
  56493. break;
  56494. case OP_EVAL_ARGS_P_2_MV:
  56495. sc->args = cons(sc, sc->args, sc->value);
  56496. sc->code = c_function_base(opt_cfunc(sc->code));
  56497. goto APPLY;
  56498. case OP_EVAL_ARGS_SSP_1:
  56499. /* from HOP_SAFE_C_SSP */
  56500. set_car(sc->t3_3, sc->value);
  56501. set_car(sc->t3_1, find_symbol_checked(sc, cadr(sc->code)));
  56502. set_car(sc->t3_2, find_symbol_checked(sc, caddr(sc->code)));
  56503. sc->value = c_call(sc->code)(sc, sc->t3_1);
  56504. break;
  56505. case OP_EVAL_ARGS_SSP_MV:
  56506. sc->args = cons(sc, find_symbol_checked(sc, cadr(sc->code)), cons(sc, find_symbol_checked(sc, caddr(sc->code)), sc->value));
  56507. sc->code = c_function_base(opt_cfunc(sc->code));
  56508. goto APPLY;
  56509. case OP_EVAL_ARGS_P_3:
  56510. set_car(sc->t2_2, find_symbol_checked(sc, caddr(sc->code)));
  56511. /* we have to wait because we say the evaluation order is always left to right
  56512. * and the first arg's evaluation might change the value of the second arg.
  56513. */
  56514. set_car(sc->t2_1, sc->value);
  56515. sc->value = c_call(sc->code)(sc, sc->t2_1);
  56516. break;
  56517. case OP_EVAL_ARGS_P_3_MV:
  56518. /* (define (hi a) (+ (values 1 2) a))
  56519. * (define (hi a) (log (values 1 2) a))
  56520. */
  56521. sc->w = sc->value;
  56522. sc->args = cons(sc, find_symbol_checked(sc, caddr(sc->code)), sc->w);
  56523. sc->code = c_function_base(opt_cfunc(sc->code));
  56524. goto APPLY;
  56525. case OP_EVAL_ARGS_P_4:
  56526. set_car(sc->t2_1, sc->value);
  56527. set_car(sc->t2_2, sc->args);
  56528. sc->value = c_call(sc->code)(sc, sc->t2_1);
  56529. break;
  56530. case OP_EVAL_ARGS_P_4_MV: /* same as P_2_MV) */
  56531. sc->args = cons(sc, sc->args, sc->value);
  56532. sc->code = c_function_base(opt_cfunc(sc->code));
  56533. goto APPLY; /* (define (hi) (log (values 1 2) 3)) ? */
  56534. case OP_SAFE_C_ZC_1:
  56535. set_car(sc->t2_1, sc->value);
  56536. set_car(sc->t2_2, sc->args);
  56537. sc->value = c_call(sc->code)(sc, sc->t2_1);
  56538. break;
  56539. case OP_SAFE_C_SZ_1:
  56540. set_car(sc->t2_1, sc->args);
  56541. set_car(sc->t2_2, sc->value);
  56542. sc->value = c_call(sc->code)(sc, sc->t2_1);
  56543. break;
  56544. case OP_SAFE_C_SZ_SZ:
  56545. /* S_opSZq actually, in (nominal second, only actual) SZ, S=args, Z=value,
  56546. * SZ from the SP combiner for SZ
  56547. */
  56548. set_car(sc->t2_1, sc->args);
  56549. set_car(sc->t2_2, sc->value);
  56550. set_car(sc->t2_2, c_call(caddr(sc->code))(sc, sc->t2_1));
  56551. set_car(sc->t2_1, find_symbol_checked(sc, cadr(sc->code)));
  56552. sc->value = c_call(sc->code)(sc, sc->t2_1);
  56553. break;
  56554. case OP_SAFE_C_ZA_1:
  56555. set_car(sc->t2_2, c_call(cddr(sc->code))(sc, caddr(sc->code)));
  56556. set_car(sc->t2_1, sc->value);
  56557. sc->value = c_call(sc->code)(sc, sc->t2_1);
  56558. break;
  56559. case OP_SAFE_C_ZZ_1:
  56560. push_stack(sc, OP_SAFE_C_ZZ_2, sc->value, sc->code);
  56561. sc->code = caddr(sc->code);
  56562. goto OPT_EVAL;
  56563. case OP_SAFE_C_ZZ_2:
  56564. set_car(sc->t2_1, sc->args);
  56565. set_car(sc->t2_2, sc->value);
  56566. sc->value = c_call(sc->code)(sc, sc->t2_1);
  56567. break;
  56568. case OP_SAFE_C_ZAA_1:
  56569. set_car(sc->a3_1, sc->value);
  56570. set_car(sc->a3_2, c_call(cddr(sc->code))(sc, caddr(sc->code)));
  56571. set_car(sc->a3_3, c_call(cdddr(sc->code))(sc, cadddr(sc->code)));
  56572. sc->value = c_call(sc->code)(sc, sc->a3_1);
  56573. break;
  56574. case OP_SAFE_C_AZA_1:
  56575. set_car(sc->t3_3, c_call(cdddr(sc->code))(sc, cadddr(sc->code)));
  56576. set_car(sc->t3_2, sc->value);
  56577. set_car(sc->t3_1, sc->args);
  56578. sc->value = c_call(sc->code)(sc, sc->t3_1);
  56579. break;
  56580. case OP_SAFE_C_SSZ_1:
  56581. set_car(sc->t3_1, sc->args);
  56582. set_car(sc->t3_3, sc->value);
  56583. set_car(sc->t3_2, find_symbol_checked(sc, caddr(sc->code)));
  56584. sc->value = c_call(sc->code)(sc, sc->t3_1);
  56585. break;
  56586. case OP_SAFE_C_AAZ_1:
  56587. set_car(sc->t3_1, pop_op_stack(sc));
  56588. set_car(sc->t3_2, sc->args);
  56589. set_car(sc->t3_3, sc->value);
  56590. sc->value = c_call(sc->code)(sc, sc->t3_1);
  56591. break;
  56592. case OP_SAFE_C_ZZA_1:
  56593. push_op_stack(sc, sc->value);
  56594. push_stack(sc, OP_SAFE_C_ZZA_2, sc->args, sc->code);
  56595. sc->code = caddr(sc->code);
  56596. goto OPT_EVAL;
  56597. case OP_SAFE_C_ZZA_2:
  56598. set_car(sc->a3_1, pop_op_stack(sc));
  56599. set_car(sc->a3_2, sc->value);
  56600. set_car(sc->a3_3, c_call(cdddr(sc->code))(sc, cadddr(sc->code)));
  56601. sc->value = c_call(sc->code)(sc, sc->a3_1);
  56602. break;
  56603. case OP_SAFE_C_ZAZ_1:
  56604. push_op_stack(sc, sc->value);
  56605. push_stack(sc, OP_SAFE_C_ZAZ_2, c_call(cddr(sc->code))(sc, caddr(sc->code)), sc->code);
  56606. sc->code = cadddr(sc->code);
  56607. goto OPT_EVAL;
  56608. case OP_SAFE_C_ZAZ_2:
  56609. set_car(sc->t3_1, pop_op_stack(sc));
  56610. set_car(sc->t3_2, sc->args);
  56611. set_car(sc->t3_3, sc->value);
  56612. sc->value = c_call(sc->code)(sc, sc->t3_1);
  56613. break;
  56614. case OP_SAFE_C_AZZ_1:
  56615. push_op_stack(sc, sc->value);
  56616. push_stack(sc, OP_SAFE_C_AZZ_2, sc->args, sc->code);
  56617. sc->code = cadddr(sc->code);
  56618. goto OPT_EVAL;
  56619. case OP_SAFE_C_AZZ_2:
  56620. set_car(sc->t3_1, sc->args);
  56621. set_car(sc->t3_2, pop_op_stack(sc));
  56622. set_car(sc->t3_3, sc->value);
  56623. sc->value = c_call(sc->code)(sc, sc->t3_1);
  56624. break;
  56625. case OP_SAFE_C_ZZZ_1:
  56626. push_stack(sc, OP_SAFE_C_ZZZ_2, sc->value, sc->code);
  56627. sc->code = caddr(sc->code);
  56628. goto OPT_EVAL;
  56629. case OP_SAFE_C_ZZZ_2:
  56630. push_op_stack(sc, sc->value);
  56631. push_stack(sc, OP_SAFE_C_ZZZ_3, sc->args, sc->code);
  56632. sc->code = cadddr(sc->code);
  56633. goto OPT_EVAL;
  56634. case OP_SAFE_C_ZZZ_3:
  56635. set_car(sc->t3_1, sc->args);
  56636. set_car(sc->t3_2, pop_op_stack(sc));
  56637. set_car(sc->t3_3, sc->value);
  56638. sc->value = c_call(sc->code)(sc, sc->t3_1);
  56639. break;
  56640. case OP_SAFE_C_opSq_P_1:
  56641. /* this is the no-multiple-values case */
  56642. set_car(sc->t2_1, sc->args);
  56643. set_car(sc->t2_2, sc->value);
  56644. sc->value = c_call(sc->code)(sc, sc->t2_1);
  56645. break;
  56646. case OP_SAFE_C_opSq_P_MV:
  56647. /* here we need an argnum check since values could have appended any number of args
  56648. */
  56649. sc->args = cons(sc, sc->args, sc->value);
  56650. /* can values return an improper or circular list? I don't think so:
  56651. * (values 1 . 2) -> improper arg list error (same with apply values)
  56652. *
  56653. * currently (values) does not simply erase itself:
  56654. * :(let () (define (arg2 a) (let ((b 1)) (set! b (+ a b)) (values))) (define (hi c) (expt (abs c) (arg2 2))) (hi 2))
  56655. * ;expt power, argument 2, #<unspecified>, is an untyped but should be a number
  56656. * :(s7-version (values))
  56657. * ;s7-version: too many arguments: (#<unspecified>)
  56658. * :(exp (values) 0.0)
  56659. * ;exp: too many arguments: (#<unspecified> 0.0)
  56660. *
  56661. * map is explicitly a special case, and surely it is more confusing to have (values) scattered at random.
  56662. * also this is consistent with the unoptimized version
  56663. */
  56664. sc->code = c_function_base(opt_cfunc(sc->code));
  56665. goto APPLY; /* (define (hi a) (+ (abs a) (values 1 2 3))) */
  56666. case OP_EVAL_ARGS3:
  56667. /* 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!)
  56668. */
  56669. {
  56670. s7_pointer x, y, val;
  56671. val = sc->code;
  56672. if (is_symbol(val))
  56673. val = find_symbol_checked(sc, val);
  56674. new_cell(sc, x, T_PAIR);
  56675. new_cell_no_check(sc, y, T_PAIR);
  56676. set_car(x, sc->value);
  56677. set_cdr(x, sc->args);
  56678. set_car(y, val);
  56679. set_cdr(y, x);
  56680. sc->args = safe_reverse_in_place(sc, y);
  56681. sc->code = pop_op_stack(sc);
  56682. goto APPLY;
  56683. }
  56684. case OP_EVAL_ARGS4:
  56685. /* sc->code is a pair, and either cdr(sc->code) is not null or car(sc->code) is a pair
  56686. *
  56687. * (#f #f) (env #f) etc. args is very often nil here, so we're looking at 3 simple args
  56688. * or even just 2 in some cases: (+ req opt) with value 2 and args ()
  56689. */
  56690. {
  56691. s7_pointer x;
  56692. new_cell(sc, x, T_PAIR);
  56693. set_car(x, sc->value);
  56694. set_cdr(x, sc->args);
  56695. sc->args = x; /* all the others reverse -- why not this case? -- reverse is at end? (below) */
  56696. goto EVAL_ARGS_PAIR;
  56697. }
  56698. case OP_EVAL_ARGS1:
  56699. {
  56700. s7_pointer x;
  56701. new_cell(sc, x, T_PAIR);
  56702. set_car(x, sc->value);
  56703. set_cdr(x, sc->args);
  56704. sc->args = x;
  56705. }
  56706. EVAL_ARGS:
  56707. /* first time, value = op, args = nil, code is args */
  56708. if (is_pair(sc->code)) /* evaluate current arg -- must check for pair here, not sc->nil (improper list as args) */
  56709. {
  56710. s7_pointer car_code;
  56711. EVAL_ARGS_PAIR:
  56712. car_code = car(sc->code);
  56713. /* switch statement here is much slower for some reason */
  56714. if (is_pair(car_code))
  56715. {
  56716. if (sc->stack_end >= sc->stack_resize_trigger)
  56717. check_for_cyclic_code(sc, sc->code);
  56718. /* all 3 of these push_stacks can result in stack overflow, see above 64065 */
  56719. if (is_null(cdr(sc->code)))
  56720. push_stack(sc, OP_EVAL_ARGS2, sc->args, sc->nil);
  56721. else
  56722. {
  56723. if (!is_pair(cdr(sc->code))) /* (= 0 '(1 . 2) . 3) */
  56724. improper_arglist_error(sc);
  56725. if ((is_null(cddr(sc->code))) &&
  56726. (!is_pair(cadr(sc->code))))
  56727. push_stack(sc, OP_EVAL_ARGS3, sc->args, cadr(sc->code));
  56728. else push_stack(sc, OP_EVAL_ARGS4, sc->args, cdr(sc->code));
  56729. }
  56730. sc->code = car_code;
  56731. if (is_optimized(sc->code))
  56732. goto OPT_EVAL;
  56733. goto EVAL;
  56734. }
  56735. /* car(sc->code) is not a pair */
  56736. if (is_pair(cdr(sc->code)))
  56737. {
  56738. sc->code = cdr(sc->code);
  56739. if (is_symbol(car_code))
  56740. sc->value = find_symbol_checked(sc, car_code);
  56741. else sc->value = _NFre(car_code);
  56742. /* sc->value is the current arg's value, sc->code is pointing to the next */
  56743. /* cdr(sc->code) may not be a pair or nil here!
  56744. * (eq? #f . 1) -> sc->code is 1
  56745. */
  56746. if (is_null(cdr(sc->code)))
  56747. {
  56748. s7_pointer x, y, val;
  56749. /* we're at the last arg, sc->value is the previous one, not yet saved in the args list */
  56750. car_code = car(sc->code);
  56751. if (is_pair(car_code))
  56752. {
  56753. if (sc->stack_end >= sc->stack_resize_trigger)
  56754. check_for_cyclic_code(sc, sc->code);
  56755. push_stack(sc, OP_EVAL_ARGS5, sc->args, sc->value);
  56756. sc->code = car_code;
  56757. goto EVAL;
  56758. }
  56759. /* get the last arg */
  56760. if (is_symbol(car_code))
  56761. val = find_symbol_checked(sc, car_code);
  56762. else val = car_code;
  56763. sc->temp4 = val;
  56764. /* get the current arg, which is not a list */
  56765. sc->code = pop_op_stack(sc);
  56766. new_cell(sc, x, T_PAIR);
  56767. new_cell_no_check(sc, y, T_PAIR);
  56768. set_car(x, sc->value);
  56769. set_cdr(x, sc->args);
  56770. set_car(y, val);
  56771. set_cdr(y, x);
  56772. sc->args = safe_reverse_in_place(sc, y);
  56773. /* drop into APPLY */
  56774. }
  56775. else
  56776. {
  56777. /* here we know sc->code is a pair, cdr(sc->code) is not null
  56778. * sc->value is the previous arg's value
  56779. */
  56780. s7_pointer x;
  56781. new_cell(sc, x, T_PAIR);
  56782. set_car(x, sc->value);
  56783. set_cdr(x, sc->args);
  56784. sc->args = x;
  56785. goto EVAL_ARGS_PAIR;
  56786. }
  56787. }
  56788. else
  56789. {
  56790. /* here we've reached the last arg (sc->code == nil), it is not a pair */
  56791. s7_pointer x, val;
  56792. if (!is_null(cdr(sc->code)))
  56793. improper_arglist_error(sc);
  56794. sc->code = pop_op_stack(sc);
  56795. if (is_symbol(car_code))
  56796. val = find_symbol_checked(sc, car_code); /* this has to precede the set_type below */
  56797. else val = car_code;
  56798. sc->temp4 = val;
  56799. new_cell(sc, x, T_PAIR);
  56800. set_car(x, val);
  56801. set_cdr(x, sc->args);
  56802. if (!is_null(sc->args))
  56803. sc->args = safe_reverse_in_place(sc, x);
  56804. else sc->args = x;
  56805. /* drop into APPLY */
  56806. }
  56807. }
  56808. else /* got all args -- go to apply */
  56809. {
  56810. if (is_not_null(sc->code))
  56811. improper_arglist_error(sc);
  56812. else
  56813. {
  56814. sc->code = pop_op_stack(sc);
  56815. sc->args = safe_reverse_in_place(sc, sc->args);
  56816. /* we could omit the arg reversal in many cases, but lots of code assumes the args are in order;
  56817. * adding a bit for this in the type field saves some time in s7test (many + and * tests), but costs
  56818. * about the same time in other cases, so it's not a clear win.
  56819. */
  56820. }
  56821. }
  56822. /* turning this into a call on an array of functions was not a complete disaster, but tauto.scm was ~1.5% slower.
  56823. * the array-index overhead is the same as the current switch statement's, but there was also the boolean+jump overhead,
  56824. * and the function-local overhead currently otherwise 0 (I assume because the compiler can simply plug it in here).
  56825. */
  56826. APPLY:
  56827. /* fprintf(stderr, "apply %s to %s\n", DISPLAY(sc->code), DISPLAY(sc->args)); */
  56828. switch (type(sc->code))
  56829. {
  56830. case T_C_FUNCTION: apply_c_function(sc); goto START;
  56831. case T_C_ANY_ARGS_FUNCTION: apply_c_any_args_function(sc); goto START;
  56832. case T_C_FUNCTION_STAR: apply_c_function_star(sc); goto START;
  56833. case T_C_OPT_ARGS_FUNCTION: apply_c_opt_args_function(sc); goto START;
  56834. case T_C_RST_ARGS_FUNCTION: apply_c_rst_args_function(sc); goto START;
  56835. case T_C_MACRO: apply_c_macro(sc); goto EVAL;
  56836. case T_CONTINUATION: apply_continuation(sc); goto START;
  56837. case T_GOTO: call_with_exit(sc); goto START;
  56838. case T_C_OBJECT: apply_c_object(sc); goto START;
  56839. case T_INT_VECTOR:
  56840. case T_FLOAT_VECTOR:
  56841. case T_VECTOR: apply_vector(sc); goto START;
  56842. case T_STRING: apply_string(sc); goto START;
  56843. case T_HASH_TABLE: apply_hash_table(sc); goto START;
  56844. case T_ITERATOR: apply_iterator(sc); goto START;
  56845. case T_LET: apply_let(sc); goto START;
  56846. case T_SYNTAX: apply_syntax(sc); goto START_WITHOUT_POP_STACK;
  56847. case T_PAIR:
  56848. if (apply_pair(sc) == goto_APPLY) goto APPLY;
  56849. goto START;
  56850. case T_MACRO:
  56851. if (is_expansion(sc->code))
  56852. push_stack(sc, OP_EXPANSION, sc->nil, sc->nil);
  56853. else push_stack(sc, OP_EVAL_MACRO, sc->nil, sc->nil);
  56854. new_frame(sc, closure_let(sc->code), sc->envir);
  56855. apply_lambda(sc);
  56856. goto BEGIN1;
  56857. case T_BACRO:
  56858. push_stack(sc, OP_EVAL_MACRO, sc->nil, sc->nil);
  56859. new_frame(sc, sc->envir, sc->envir); /* like let* -- we'll be adding macro args, so might as well sequester things here */
  56860. apply_lambda(sc);
  56861. goto BEGIN1;
  56862. case T_CLOSURE:
  56863. check_stack_size(sc);
  56864. new_frame(sc, closure_let(sc->code), sc->envir);
  56865. apply_lambda(sc);
  56866. goto BEGIN1;
  56867. case T_MACRO_STAR:
  56868. push_stack(sc, OP_EVAL_MACRO, sc->nil, sc->nil);
  56869. new_frame(sc, closure_let(sc->code), sc->envir);
  56870. if (apply_lambda_star(sc) == goto_EVAL) goto EVAL;
  56871. goto BEGIN1;
  56872. case T_BACRO_STAR:
  56873. push_stack(sc, OP_EVAL_MACRO, sc->nil, sc->nil);
  56874. new_frame(sc, sc->envir, sc->envir);
  56875. if (apply_lambda_star(sc) == goto_EVAL) goto EVAL;
  56876. goto BEGIN1;
  56877. case T_CLOSURE_STAR:
  56878. check_stack_size(sc);
  56879. sc->envir = new_frame_in_env(sc, closure_let(sc->code));
  56880. if (apply_lambda_star(sc) == goto_EVAL) goto EVAL;
  56881. goto BEGIN1;
  56882. default:
  56883. return(apply_error(sc, sc->code, sc->args));
  56884. }
  56885. case OP_APPLY: /* apply 'code' to 'args' */
  56886. if (needs_copied_args(sc->code))
  56887. sc->args = copy_list(sc, sc->args);
  56888. goto APPLY;
  56889. /* (let ((lst '((1 2)))) (define (identity x) x) (cons (apply identity lst) lst)) */
  56890. case OP_LAMBDA_STAR_DEFAULT:
  56891. /* sc->args is the current closure arg list position, sc->value is the default expression's value */
  56892. slot_set_value(sc->args, sc->value);
  56893. sc->args = slot_pending_value(sc->args);
  56894. if (lambda_star_default(sc) == goto_EVAL) goto EVAL;
  56895. pop_stack_no_op(sc);
  56896. sc->code = closure_body(sc->code);
  56897. goto BEGIN1;
  56898. case OP_MACROEXPAND_1:
  56899. sc->args = cdar(sc->code);
  56900. sc->code = sc->value;
  56901. goto MACROEXPAND;
  56902. case OP_MACROEXPAND:
  56903. /* mimic APPLY above, but don't push OP_EVAL_MACRO or OP_EXPANSION
  56904. * (define-macro (mac a) `(+ ,a 1)) (macroexpand (mac 3)), sc->code: ((mac 3))
  56905. */
  56906. if ((!is_pair(sc->code)) ||
  56907. (!is_pair(car(sc->code))))
  56908. eval_error(sc, "macroexpand argument is not a macro call: ~A", sc->code);
  56909. if (!is_null(cdr(sc->code)))
  56910. eval_error(sc, "macroexpand: too many arguments: ~A", sc->code);
  56911. if (is_pair(caar(sc->code))) /* (macroexpand ((symbol->value 'mac) (+ 1 2))) */
  56912. {
  56913. push_stack(sc, OP_MACROEXPAND_1, sc->nil, sc->code);
  56914. sc->code = caar(sc->code);
  56915. goto EVAL;
  56916. }
  56917. sc->args = cdar(sc->code);
  56918. if (!is_symbol(caar(sc->code)))
  56919. eval_error(sc, "macroexpand argument is not a macro call: ~A", sc->code);
  56920. sc->code = find_symbol_checked(sc, caar(sc->code));
  56921. MACROEXPAND:
  56922. switch (type(sc->code))
  56923. {
  56924. case T_MACRO:
  56925. new_frame(sc, closure_let(sc->code), sc->envir);
  56926. apply_lambda(sc);
  56927. goto BEGIN1;
  56928. case T_BACRO:
  56929. new_frame(sc, sc->envir, sc->envir);
  56930. apply_lambda(sc);
  56931. goto BEGIN1;
  56932. case T_MACRO_STAR:
  56933. new_frame(sc, closure_let(sc->code), sc->envir);
  56934. if (apply_lambda_star(sc) == goto_EVAL) goto EVAL;
  56935. goto BEGIN1;
  56936. case T_BACRO_STAR:
  56937. new_frame(sc, sc->envir, sc->envir);
  56938. if (apply_lambda_star(sc) == goto_EVAL) goto EVAL;
  56939. goto BEGIN1;
  56940. case T_C_MACRO:
  56941. sc->value = c_macro_call(sc->code)(sc, sc->args);
  56942. goto START;
  56943. }
  56944. eval_error(sc, "macroexpand argument is not a macro call: ~A", sc->args);
  56945. case OP_QUOTE:
  56946. case OP_QUOTE_UNCHECKED:
  56947. /* I think a quoted list in another list can be applied to a function, come here and
  56948. * be changed to unchecked, set-cdr! or something clobbers the argument so we get
  56949. * here on the next time around with the equivalent of (quote . 0) so unchecked
  56950. * quote needs more thought.
  56951. */
  56952. check_quote(sc);
  56953. sc->value = car(sc->code);
  56954. break;
  56955. case OP_DEFINE_FUNCHECKED:
  56956. define_funchecked(sc);
  56957. break;
  56958. case OP_DEFINE_CONSTANT1:
  56959. sc->code = car(sc->code);
  56960. if (is_pair(sc->code)) sc->code = car(sc->code); /* (define-constant (ex3 a)...) */
  56961. if (is_symbol(sc->code))
  56962. set_immutable(sc->code);
  56963. break;
  56964. case OP_DEFINE_CONSTANT:
  56965. if ((!is_pair(sc->code)) || (!is_pair(cdr(sc->code)))) /* (define-constant) */
  56966. eval_error(sc, "define-constant: not enough arguments: ~S", sc->code);
  56967. if ((is_symbol(car(sc->code))) && /* (define-constant abs abs): "abs will not be touched" */
  56968. (car(sc->code) == cadr(sc->code)) &&
  56969. (symbol_id(car(sc->code)) == 0) && /* else (let iter ... (define-constant iter iter) ...) -> segfault on later calls */
  56970. (is_null(cddr(sc->code))))
  56971. {
  56972. set_immutable(car(sc->code));
  56973. sc->value = find_symbol_checked(sc, car(sc->code));
  56974. goto START;
  56975. }
  56976. push_stack(sc, OP_DEFINE_CONSTANT1, sc->nil, sc->code);
  56977. case OP_DEFINE_STAR:
  56978. case OP_DEFINE:
  56979. check_define(sc);
  56980. case OP_DEFINE_CONSTANT_UNCHECKED:
  56981. case OP_DEFINE_STAR_UNCHECKED:
  56982. case OP_DEFINE_UNCHECKED:
  56983. if (define_unchecked_ex(sc) == goto_EVAL) goto EVAL;
  56984. case OP_DEFINE1:
  56985. if (define1_ex(sc) == goto_APPLY) goto APPLY;
  56986. case OP_DEFINE_WITH_ACCESSOR:
  56987. define2_ex(sc);
  56988. break;
  56989. /* -------------------------------- SET! -------------------------------- */
  56990. case OP_SET_PAIR_P:
  56991. /* ([set!] (car a) (cadr a)) */
  56992. /* here the pair can't generate multiple values, or if it does, it's an error (caught below)
  56993. * splice_in_values will notice the OP_SET_PAIR_P_1 and complain.
  56994. * (let () (define (hi) (let ((str "123")) (set! (str 0) (values #\a)) str)) (hi) (hi)) is "a23"
  56995. * (let () (define (hi) (let ((str "123")) (set! (str 0) (values #\a #\b)) str)) (hi) (hi)) is an error from the first call (caught elsewhere)
  56996. * (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
  56997. * (let ((v (make-vector '(2 3) 0))) (set! (v (values 0 1)) 23) v) -> #2D((0 23 0) (0 0 0))
  56998. */
  56999. push_stack_no_args(sc, OP_SET_PAIR_P_1, sc->code);
  57000. sc->code = cadr(sc->code);
  57001. goto EVAL;
  57002. case OP_SET_PAIR_Z:
  57003. push_stack_no_args(sc, OP_SET_PAIR_P_1, sc->code);
  57004. sc->code = cadr(sc->code);
  57005. goto OPT_EVAL;
  57006. case OP_SET_PAIR_A:
  57007. {
  57008. s7_pointer obj, val;
  57009. obj = find_symbol_checked(sc, caar(sc->code));
  57010. val = c_call(cdr(sc->code))(sc, cadr(sc->code)); /* this call can step on sc->Tx_x */
  57011. set_car(sc->t2_1, cadar(sc->code)); /* might be a constant: (set! (mus-sound-srate "oboe.snd") 12345) */
  57012. if (is_symbol(car(sc->t2_1)))
  57013. set_car(sc->t2_1, find_symbol_checked(sc, cadar(sc->code)));
  57014. set_car(sc->t2_2, val);
  57015. sc->value = c_function_call(c_function_setter(obj))(sc, sc->t2_1);
  57016. }
  57017. break;
  57018. case OP_SET_PAIR_C_P: /* ([set!] (name (+ i 1)) (if (eq? (car a) 'car) #\a #\d)) */
  57019. push_stack_no_args(sc, OP_SET_PAIR_C_P_1, sc->code);
  57020. sc->code = cadr(sc->code);
  57021. goto EVAL;
  57022. case OP_SET_PAIR_C_P_1: /* code: ((name (+ i 1)) ...) for example, so cadar is the c_c expr and its args are cdr(cadar) */
  57023. sc->temp8 = sc->value;
  57024. if (set_pair_p_3(sc, find_symbol(sc, caar(sc->code)), c_call(cadar(sc->code))(sc, cdadar(sc->code)), sc->temp8))
  57025. goto APPLY;
  57026. break;
  57027. case OP_SET_PAIR_C: /* ([set!] (name (+ len 1)) #\r) */
  57028. {
  57029. s7_pointer value;
  57030. value = cadr(sc->code);
  57031. if (is_symbol(value))
  57032. value = find_symbol_checked(sc, value);
  57033. if (set_pair_p_3(sc, find_symbol(sc, caar(sc->code)), c_call(cadar(sc->code))(sc, cdadar(sc->code)), value))
  57034. goto APPLY;
  57035. }
  57036. break;
  57037. case OP_SET_LET_S: /* (set! (*s7* 'print-length) i) */
  57038. if (set_pair_p_3(sc, find_symbol(sc, caar(sc->code)), cadr(cadar(sc->code)), find_symbol_checked(sc, cadr(sc->code))))
  57039. goto APPLY;
  57040. break;
  57041. case OP_SET_LET_ALL_X: /* (set! (hook 'result) 123) or (set! (H 'c) 32) */
  57042. if (set_pair_p_3(sc, find_symbol(sc, caar(sc->code)), cadr(cadar(sc->code)), c_call(cdr(sc->code))(sc, cadr(sc->code))))
  57043. goto APPLY;
  57044. break;
  57045. case OP_SET_PAIR_ZA: /* unknown setter pair, but value is easy */
  57046. sc->value = c_call(cdr(sc->code))(sc, cadr(sc->code));
  57047. /* fall through */
  57048. case OP_SET_PAIR_P_1:
  57049. {
  57050. /* 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
  57051. * (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)
  57052. * the inner list is a proper list, with no embedded list at car.
  57053. */
  57054. s7_pointer arg, value;
  57055. value = sc->value;
  57056. arg = cadar(sc->code);
  57057. if (is_symbol(arg))
  57058. arg = find_symbol_checked(sc, arg);
  57059. else
  57060. {
  57061. if (is_pair(arg))
  57062. arg = cadr(arg); /* can only be (quote ...) in this case */
  57063. }
  57064. if (set_pair_p_3(sc, find_symbol(sc, caar(sc->code)), arg, value))
  57065. goto APPLY;
  57066. }
  57067. break;
  57068. case OP_SET_PAIR:
  57069. {
  57070. /* ([set!] (procedure-setter g) s) or ([set!] (str 0) #\a) */
  57071. s7_pointer obj, arg, value;
  57072. value = cadr(sc->code);
  57073. if (is_symbol(value))
  57074. value = find_symbol_checked(sc, value);
  57075. arg = cadar(sc->code);
  57076. if (is_symbol(arg))
  57077. arg = find_symbol_checked(sc, arg);
  57078. else
  57079. {
  57080. if (is_pair(arg))
  57081. arg = cadr(arg); /* can only be (quote ...) in this case */
  57082. }
  57083. obj = caar(sc->code);
  57084. if (is_symbol(obj))
  57085. obj = find_symbol(sc, obj);
  57086. if (set_pair_p_3(sc, obj, arg, value))
  57087. goto APPLY;
  57088. }
  57089. break;
  57090. /* this is (set! (getter) val) where getter is a global c_function (a built-in pws) and val is not a pair */
  57091. case OP_SET_PWS: /* (set! (mus-clipping) #f) */
  57092. set_pws_ex(sc);
  57093. break;
  57094. case OP_INCREMENT_1:
  57095. increment_1_ex(sc);
  57096. break;
  57097. case OP_DECREMENT_1:
  57098. decrement_1_ex(sc);
  57099. break;
  57100. #define SET_CASE(Op, Code) \
  57101. case Op: \
  57102. { \
  57103. s7_pointer lx; \
  57104. lx = find_symbol(sc, _TSet(car(sc->code))); \
  57105. if (!is_slot(lx)) eval_type_error(sc, "set! ~A: unbound variable", sc->code); \
  57106. Code; \
  57107. sc->value = slot_value(lx); \
  57108. goto START; \
  57109. }
  57110. SET_CASE(OP_SET_SYMBOL_C, slot_set_value(lx, cadr(sc->code)))
  57111. SET_CASE(OP_SET_SYMBOL_Q, slot_set_value(lx, cadr(cadr(sc->code))))
  57112. SET_CASE(OP_SET_SYMBOL_A, slot_set_value(lx, c_call(cdr(sc->code))(sc, cadr(sc->code))))
  57113. SET_CASE(OP_SET_SYMBOL_S, slot_set_value(lx, find_symbol_checked(sc, cadr(sc->code))))
  57114. SET_CASE(OP_SET_CONS, slot_set_value(lx, cons(sc, find_symbol_checked(sc, opt_sym2(sc->code)), slot_value(lx)))) /* ([set!] bindings (cons v bindings)) */
  57115. SET_CASE(OP_SET_SYMBOL_opCq, slot_set_value(lx, c_call(cadr(sc->code))(sc, opt_pair2(sc->code))))
  57116. /* here we know the symbols do not have accessors, at least at optimization time */
  57117. SET_CASE(OP_SET_SYMBOL_opSq,
  57118. do { \
  57119. set_car(sc->t1_1, find_symbol_checked(sc, opt_sym2(sc->code))); \
  57120. slot_set_value(lx, c_call(cadr(sc->code))(sc, sc->t1_1)); \
  57121. } while (0))
  57122. SET_CASE(OP_SET_SYMBOL_opSSq,
  57123. do { \
  57124. set_car(sc->t2_1, find_symbol_checked(sc, car(opt_pair2(sc->code)))); \
  57125. set_car(sc->t2_2, find_symbol_checked(sc, cadr(opt_pair2(sc->code)))); \
  57126. slot_set_value(lx, c_call(cadr(sc->code))(sc, sc->t2_1)); \
  57127. } while (0))
  57128. SET_CASE(OP_SET_SYMBOL_opSSSq,
  57129. do { \
  57130. set_car(sc->t3_1, find_symbol_checked(sc, car(opt_pair2(sc->code)))); \
  57131. set_car(sc->t3_2, find_symbol_checked(sc, opt_sym1(opt_pair2(sc->code)))); \
  57132. set_car(sc->t3_3, find_symbol_checked(sc, opt_sym2(opt_pair2(sc->code)))); \
  57133. slot_set_value(lx, c_call(cadr(sc->code))(sc, sc->t3_1)); \
  57134. } while (0))
  57135. SET_CASE(OP_INCREMENT_SS, /* ([set!] x (+ x i)) */
  57136. do { \
  57137. set_car(sc->t2_1, slot_value(lx)); \
  57138. set_car(sc->t2_2, find_symbol_checked(sc, cadr(opt_pair2(sc->code)))); \
  57139. slot_set_value(lx, c_call(cadr(sc->code))(sc, sc->t2_1)); \
  57140. } while (0))
  57141. SET_CASE(OP_INCREMENT_SSS, /* ([set!] x (+ x y z)) -- nearly always involves reals */
  57142. do { \
  57143. s7_pointer x1; s7_pointer x2; s7_pointer x3; \
  57144. x1 = slot_value(lx); \
  57145. x2 = find_symbol_checked(sc, opt_sym1(opt_pair2(sc->code))); \
  57146. x3 = find_symbol_checked(sc, opt_sym2(opt_pair2(sc->code))); \
  57147. if ((is_t_real(x1)) && (is_t_real(x2)) && (is_t_real(x3))) \
  57148. slot_set_value(lx, make_real(sc, real(x1) + real(x2) + real(x3))); \
  57149. else { \
  57150. set_car(sc->t3_1, x1); set_car(sc->t3_2, x2); set_car(sc->t3_3, x3); \
  57151. slot_set_value(lx, global_add(sc, sc->t3_1)); \
  57152. } \
  57153. } while (0))
  57154. SET_CASE(OP_INCREMENT_SA,
  57155. do { \
  57156. s7_pointer arg; \
  57157. arg = opt_pair2(sc->code); \
  57158. set_car(sc->t2_2, c_call(arg)(sc, car(arg))); \
  57159. set_car(sc->t2_1, slot_value(lx)); \
  57160. slot_set_value(lx, c_call(cadr(sc->code))(sc, sc->t2_1)); \
  57161. } while (0))
  57162. SET_CASE(OP_INCREMENT_SAA, /* (set! sum (+ sum (expt k i) (expt (- k) i))) -- oops */
  57163. do { \
  57164. s7_pointer arg; \
  57165. arg = opt_pair2(sc->code); /* cddr(value) */ \
  57166. set_car(sc->a3_3, c_call(cdr(arg))(sc, cadr(arg))); \
  57167. set_car(sc->a3_2, c_call(arg)(sc, car(arg))); \
  57168. set_car(sc->a3_1, slot_value(lx)); \
  57169. slot_set_value(lx, c_call(cadr(sc->code))(sc, sc->a3_1)); \
  57170. } while (0))
  57171. case OP_SET_SAFE:
  57172. {
  57173. s7_pointer lx;
  57174. lx = find_symbol(sc, _TSet(sc->code)); /* SET_CASE above looks for car(sc->code) */
  57175. if (!is_slot(lx)) eval_type_error(sc, "set! ~A: unbound variable", sc->code);
  57176. slot_set_value(lx, sc->value);
  57177. sc->value = slot_value(lx);
  57178. }
  57179. break;
  57180. case OP_SET_SYMBOL_P: /* ([set!] f (lambda () 1)) */
  57181. push_stack_no_args(sc, OP_SET_SAFE, car(sc->code));
  57182. sc->code = cadr(sc->code);
  57183. goto EVAL;
  57184. case OP_SET_SYMBOL_Z:
  57185. /* ([set!] sum (+ sum n)) */
  57186. push_stack_no_args(sc, OP_SET_SAFE, car(sc->code));
  57187. sc->code = cadr(sc->code);
  57188. goto OPT_EVAL;
  57189. case OP_INCREMENT_SZ:
  57190. {
  57191. s7_pointer sym;
  57192. sym = find_symbol(sc, car(sc->code));
  57193. if (is_slot(sym))
  57194. {
  57195. push_stack(sc, OP_INCREMENT_SZ_1, sym, sc->code);
  57196. sc->code = opt_pair2(sc->code); /* caddr(cadr(sc->code)); */
  57197. goto OPT_EVAL;
  57198. }
  57199. eval_type_error(sc, "set! ~A: unbound variable", sc->code);
  57200. }
  57201. case OP_INCREMENT_SZ_1:
  57202. set_car(sc->t2_1, slot_value(sc->args));
  57203. set_car(sc->t2_2, sc->value);
  57204. sc->value = c_call(cadr(sc->code))(sc, sc->t2_1);
  57205. slot_set_value(sc->args, sc->value);
  57206. break;
  57207. case OP_SET2:
  57208. if (is_pair(sc->value))
  57209. {
  57210. /* (let ((L '((1 2 3)))) (set! ((L 0) 1) 32) L)
  57211. * (let ((L '(((1 2 3))))) (set! ((L 0) 0 1) 32) L)
  57212. * any deeper nesting was handled already by the first eval
  57213. * set! looks at its first argument, if it's a symbol, it sets the associated value,
  57214. * if it's a list, it looks at the car of that list to decide which setter to call,
  57215. * if it's a list of lists, it passes the embedded lists to eval, then looks at the
  57216. * car of the result. This means that we can do crazy things like:
  57217. * (let ((x '(1)) (y '(2))) (set! ((if #t x y) 0) 32) x)
  57218. *
  57219. * the other args need to be evaluated (but not the list as if it were code):
  57220. * (let ((L '((1 2 3))) (index 1)) (set! ((L 0) index) 32) L)
  57221. */
  57222. if (!is_proper_list(sc, sc->args)) /* (set! ('(1 2) 1 . 2) 1) */
  57223. eval_error(sc, "set! target arguments are an improper list: ~A", sc->args);
  57224. /* in all of these cases, we might need to GC protect the temporary lists */
  57225. if (is_multiple_value(sc->value))
  57226. sc->code = cons(sc, sc->set_symbol, s7_append(sc, multiple_value(sc->value), s7_append(sc, sc->args, sc->code))); /* drop into OP_SET */
  57227. else
  57228. {
  57229. if (sc->args != sc->nil)
  57230. {
  57231. push_op_stack(sc, sc->list_set_function);
  57232. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, sc->value), s7_append(sc, cdr(sc->args), sc->code));
  57233. sc->code = car(sc->args);
  57234. }
  57235. else eval_error(sc, "list set!: not enough arguments: ~S", sc->code);
  57236. goto EVAL;
  57237. }
  57238. }
  57239. else
  57240. {
  57241. if (s7_is_vector(sc->value))
  57242. {
  57243. /* (let ((L #(#(1 2 3) #(4 5 6)))) (set! ((L 1) 0) 32) L)
  57244. * bad case when args is nil: (let ((L #(#(1 2 3) #(4 5 6)))) (set! ((L 1)) 32) L)
  57245. */
  57246. if (sc->args != sc->nil)
  57247. {
  57248. push_op_stack(sc, sc->vector_set_function);
  57249. push_stack(sc, OP_EVAL_ARGS1, list_1(sc, sc->value), s7_append(sc, cdr(sc->args), sc->code));
  57250. sc->code = car(sc->args);
  57251. }
  57252. else eval_error(sc, "vector set!: not enough arguments: ~S", sc->code);
  57253. goto EVAL;
  57254. }
  57255. sc->code = cons_unchecked(sc, cons(sc, sc->value, sc->args), sc->code);
  57256. }
  57257. /* fall through */
  57258. case OP_SET: /* entry for set! */
  57259. check_set(sc);
  57260. case OP_SET_UNCHECKED:
  57261. if (is_pair(car(sc->code))) /* has accessor */
  57262. {
  57263. int choice;
  57264. choice = set_pair_ex(sc);
  57265. if (choice == goto_EVAL) goto EVAL;
  57266. if (choice == goto_START) goto START;
  57267. if (choice == goto_APPLY) goto APPLY;
  57268. goto EVAL_ARGS;
  57269. }
  57270. /* fall through */
  57271. case OP_SET_NORMAL:
  57272. {
  57273. s7_pointer x;
  57274. x = cadr(sc->code);
  57275. if (is_pair(x))
  57276. {
  57277. push_stack_no_args(sc, OP_SET1, car(sc->code));
  57278. sc->code = x;
  57279. goto EVAL;
  57280. }
  57281. if (is_symbol(x))
  57282. sc->value = find_symbol_checked(sc, x);
  57283. else sc->value = _NFre(x);
  57284. sc->code = car(sc->code);
  57285. }
  57286. case OP_SET1:
  57287. {
  57288. s7_pointer lx;
  57289. /* if unbound variable hook here, we need the binding, not the current value */
  57290. lx = find_symbol(sc, _TSet(sc->code));
  57291. if (is_slot(lx))
  57292. {
  57293. if (slot_has_accessor(lx))
  57294. {
  57295. s7_pointer func;
  57296. func = slot_accessor(lx);
  57297. if (is_procedure_or_macro(func))
  57298. {
  57299. if (is_c_function(func))
  57300. {
  57301. set_car(sc->t2_1, sc->code);
  57302. set_car(sc->t2_2, sc->value);
  57303. sc->value = c_function_call(func)(sc, sc->t2_1);
  57304. if (sc->value == sc->error_symbol) /* backwards compatibility... (but still used I think in g_features_set) */
  57305. return(s7_error(sc, sc->error_symbol, set_elist_3(sc, make_string_wrapper(sc, "can't set ~S to ~S"), car(sc->t2_1), car(sc->t2_2))));
  57306. }
  57307. else
  57308. {
  57309. sc->args = list_2(sc, sc->code, sc->value);
  57310. push_stack(sc, OP_SET_WITH_ACCESSOR, sc->args, lx); /* op, args, code */
  57311. sc->code = func;
  57312. goto APPLY;
  57313. }
  57314. }
  57315. }
  57316. else
  57317. {
  57318. if (is_syntax(slot_value(lx)))
  57319. eval_error(sc, "can't set! ~A", sc->code);
  57320. }
  57321. slot_set_value(lx, sc->value);
  57322. goto START;
  57323. }
  57324. eval_type_error(sc, "set! ~A: unbound variable", sc->code);
  57325. }
  57326. case OP_SET_WITH_ACCESSOR:
  57327. if (sc->value == sc->error_symbol) /* backwards compatibility... */
  57328. return(s7_error(sc, sc->error_symbol, set_elist_2(sc, make_string_wrapper(sc, "can't set ~S"), sc->args)));
  57329. slot_set_value(sc->code, sc->value);
  57330. break;
  57331. case OP_SET_WITH_LET_1:
  57332. /* here sc->value is the new value for the settee, args has the (as yet unevaluated) let and settee-expression. */
  57333. /* fprintf(stderr, "with_let_1: %s %s %s\n", DISPLAY(sc->value), DISPLAY(sc->code), DISPLAY(sc->args)); */
  57334. if (is_symbol(car(sc->args)))
  57335. {
  57336. s7_pointer p;
  57337. p = list_2(sc, cadr(sc->args), sc->value);
  57338. sc->value = find_symbol_checked(sc, car(sc->args));
  57339. sc->args = p;
  57340. /* fall through */
  57341. }
  57342. else
  57343. {
  57344. sc->code = car(sc->args);
  57345. sc->args = list_2(sc, cadr(sc->args), sc->value);
  57346. push_stack(sc, OP_SET_WITH_LET_2, sc->args, sc->code);
  57347. goto EVAL;
  57348. }
  57349. case OP_SET_WITH_LET_2:
  57350. /* fprintf(stderr, "with_let_2: value: %s, code: %s, args: %s\n", DISPLAY(sc->value), DISPLAY(sc->code), DISPLAY(sc->args)); */
  57351. if (is_symbol(car(sc->args)))
  57352. {
  57353. let_set_1(sc, sc->value, car(sc->args), cadr(sc->args));
  57354. sc->value = cadr(sc->args);
  57355. goto START;
  57356. }
  57357. /* avoid double evaluation */
  57358. if ((is_symbol(cadr(sc->args))) ||
  57359. (is_pair(cadr(sc->args))))
  57360. sc->code = cons(sc, sc->set_symbol, list_2(sc, car(sc->args), list_2(sc, sc->quote_symbol, cadr(sc->args))));
  57361. else sc->code = cons(sc, sc->set_symbol, sc->args);
  57362. activate_let(sc); /* this activates sc->value, so the set! will happen in that environment */
  57363. goto EVAL;
  57364. /* -------------------------------- IF -------------------------------- */
  57365. case OP_IF:
  57366. check_if(sc);
  57367. case OP_IF_UNCHECKED:
  57368. push_stack_no_args(sc, OP_IF1, cdr(sc->code));
  57369. sc->code = car(sc->code);
  57370. goto EVAL;
  57371. case OP_IF1:
  57372. if (is_true(sc, sc->value))
  57373. sc->code = car(sc->code);
  57374. else sc->code = cadr(sc->code); /* even pre-optimization, (if #f #f) ==> #<unspecified> because car(sc->nil) = sc->unspecified */
  57375. if (is_pair(sc->code))
  57376. goto EVAL;
  57377. if (is_symbol(sc->code))
  57378. sc->value = find_symbol_checked(sc, sc->code);
  57379. else sc->value = sc->code;
  57380. break;
  57381. #define IF_CASE(Op, Code) \
  57382. case Op ## _P: Code {sc->code = cadr(sc->code); goto EVAL;} else {sc->value = sc->unspecified; goto START;} \
  57383. case Op ## _P_P: Code {sc->code = cadr(sc->code); goto EVAL;} else {sc->code = caddr(sc->code); goto EVAL;}
  57384. IF_CASE(OP_IF_S, if (is_true(sc, find_symbol_checked(sc, car(sc->code)))))
  57385. IF_CASE(OP_IF_NOT_S, if (is_false(sc, find_symbol_checked(sc, opt_sym2(sc->code)))))
  57386. IF_CASE(OP_IF_A, if (is_true(sc, c_call(sc->code)(sc, car(sc->code)))))
  57387. IF_CASE(OP_IF_CC, if (is_true(sc, c_call(car(sc->code))(sc, opt_pair2(sc->code)))))
  57388. IF_CASE(OP_IF_IS_PAIR, if (is_pair(find_symbol_checked(sc, opt_sym2(sc->code)))))
  57389. IF_CASE(OP_IF_IS_SYMBOL, if (is_symbol(find_symbol_checked(sc, opt_sym2(sc->code)))))
  57390. IF_CASE(OP_IF_CS, set_car(sc->t1_1, find_symbol_checked(sc, opt_sym2(sc->code))); \
  57391. if (is_true(sc, c_call(car(sc->code))(sc, sc->t1_1))))
  57392. IF_CASE(OP_IF_CSQ, set_car(sc->t2_1, find_symbol_checked(sc, opt_sym3(sc->code))); \
  57393. set_car(sc->t2_2, opt_con2(sc->code)); \
  57394. if (is_true(sc, c_call(car(sc->code))(sc, sc->t2_1))))
  57395. IF_CASE(OP_IF_CSS, set_car(sc->t2_1, find_symbol_checked(sc, opt_sym3(sc->code))); \
  57396. set_car(sc->t2_2, find_symbol_checked(sc, opt_sym2(sc->code)));
  57397. if (is_true(sc, c_call(car(sc->code))(sc, sc->t2_1))))
  57398. IF_CASE(OP_IF_CSC, set_car(sc->t2_1, find_symbol_checked(sc, opt_sym3(sc->code))); \
  57399. set_car(sc->t2_2, opt_con2(sc->code)); \
  57400. if (is_true(sc, c_call(car(sc->code))(sc, sc->t2_1))))
  57401. IF_CASE(OP_IF_S_opCq, set_car(sc->t2_2, c_call(opt_pair2(sc->code))(sc, cdr(opt_pair2(sc->code)))); \
  57402. set_car(sc->t2_1, find_symbol_checked(sc, opt_sym3(sc->code))); \
  57403. if (is_true(sc, c_call(car(sc->code))(sc, sc->t2_1))))
  57404. IF_CASE(OP_IF_opSSq, {s7_pointer args; s7_pointer val1; \
  57405. args = opt_pair2(sc->code); \
  57406. val1 = find_symbol_checked(sc, cadr(args)); \
  57407. set_car(sc->t2_2, find_symbol_checked(sc, opt_sym3(sc->code))); \
  57408. set_car(sc->t2_1, val1); \
  57409. set_car(sc->t1_1, c_call(args)(sc, sc->t2_1));} \
  57410. if (is_true(sc, c_call(car(sc->code))(sc, sc->t1_1))))
  57411. IF_CASE(OP_IF_AND2, if ((is_true(sc, c_call(opt_pair2(sc->code))(sc, car(opt_pair2(sc->code))))) && \
  57412. (is_true(sc, c_call(opt_and_2_test(sc->code))(sc, car(opt_and_2_test(sc->code)))))))
  57413. case OP_IF_P_P:
  57414. push_stack_no_args(sc, OP_IF_PP, cadr(sc->code));
  57415. sc->code = car(sc->code);
  57416. goto EVAL;
  57417. case OP_IF_P_P_P:
  57418. push_stack_no_args(sc, OP_IF_PPP, cdr(sc->code));
  57419. sc->code = car(sc->code);
  57420. goto EVAL;
  57421. case OP_IF_Z_P:
  57422. push_stack_no_args(sc, OP_IF_PP, opt_con2(sc->code));
  57423. sc->code = car(sc->code);
  57424. goto OPT_EVAL;
  57425. case OP_IF_Z_P_P:
  57426. push_stack_no_args(sc, OP_IF_PPP, cdr(sc->code));
  57427. sc->code = car(sc->code);
  57428. goto OPT_EVAL;
  57429. case OP_IF_ANDP_P:
  57430. push_stack_no_args(sc, OP_IF_PP, cadr(sc->code));
  57431. sc->code = cdar(sc->code);
  57432. goto AND_P;
  57433. case OP_IF_ANDP_P_P:
  57434. push_stack_no_args(sc, OP_IF_PPP, cdr(sc->code));
  57435. sc->code = cdar(sc->code);
  57436. goto AND_P;
  57437. case OP_IF_ORP_P:
  57438. push_stack_no_args(sc, OP_IF_PP, cadr(sc->code));
  57439. sc->code = cdar(sc->code);
  57440. goto OR_P;
  57441. case OP_IF_ORP_P_P:
  57442. push_stack_no_args(sc, OP_IF_PPP, cdr(sc->code));
  57443. sc->code = cdar(sc->code);
  57444. goto OR_P;
  57445. case OP_IF_PPP:
  57446. if (is_true(sc, sc->value))
  57447. sc->code = car(sc->code);
  57448. else sc->code = cadr(sc->code);
  57449. goto EVAL;
  57450. case OP_IF_PP:
  57451. if (is_true(sc, sc->value))
  57452. goto EVAL;
  57453. sc->value = sc->unspecified;
  57454. break;
  57455. case OP_IF_P_FEED:
  57456. /* actually cond right now: (cond (expr => p)) where p is (lambda (s) ...) -- see check_cond */
  57457. push_stack_no_args(sc, OP_IF_P_FEED_1, sc->code);
  57458. sc->code = caar(sc->code);
  57459. goto EVAL;
  57460. case OP_IF_P_FEED_1:
  57461. if (is_true(sc, sc->value))
  57462. {
  57463. if (is_multiple_value(sc->value))
  57464. sc->code = cons(sc, opt_lambda2(sc->code), multiple_value(sc->value));
  57465. else
  57466. {
  57467. new_frame_with_slot(sc, sc->envir, sc->envir, caadr(opt_lambda2(sc->code)), sc->value);
  57468. sc->code = caddr(opt_lambda2(sc->code));
  57469. }
  57470. goto EVAL;
  57471. }
  57472. sc->value = sc->nil; /* since it's actually cond -- perhaps push as sc->args above */
  57473. break;
  57474. case OP_WHEN:
  57475. check_when(sc);
  57476. case OP_WHEN_UNCHECKED:
  57477. push_stack_no_args(sc, OP_WHEN1, cdr(sc->code));
  57478. sc->code = car(sc->code);
  57479. goto EVAL;
  57480. case OP_WHEN1:
  57481. if (is_true(sc, sc->value)) goto BEGIN1;
  57482. sc->value = sc->unspecified;
  57483. break;
  57484. case OP_WHEN_S:
  57485. if (is_true(sc, find_symbol_checked(sc, car(sc->code))))
  57486. {
  57487. sc->code = cdr(sc->code);
  57488. goto BEGIN1;
  57489. }
  57490. sc->value = sc->unspecified;
  57491. break;
  57492. case OP_UNLESS:
  57493. check_unless(sc);
  57494. case OP_UNLESS_UNCHECKED:
  57495. push_stack_no_args(sc, OP_UNLESS1, cdr(sc->code));
  57496. sc->code = car(sc->code);
  57497. goto EVAL;
  57498. case OP_UNLESS1:
  57499. if (is_false(sc, sc->value)) goto BEGIN1;
  57500. sc->value = sc->unspecified;
  57501. break;
  57502. case OP_UNLESS_S:
  57503. if (is_false(sc, find_symbol_checked(sc, car(sc->code))))
  57504. {
  57505. sc->code = cdr(sc->code);
  57506. goto BEGIN1;
  57507. }
  57508. sc->value = sc->unspecified;
  57509. break;
  57510. case OP_SAFE_C_P_1:
  57511. set_car(sc->t1_1, sc->value);
  57512. sc->value = c_call(sc->code)(sc, sc->t1_1);
  57513. break;
  57514. case OP_SAFE_C_PP_1:
  57515. /* unless multiple values from last call (first arg), sc->args == sc->nil because we pushed that.
  57516. * we get here only from OP_SAFE_C_PP.
  57517. *
  57518. * currently splice_in_values changes the operator so if we get here, sc->value is the result of the first arg
  57519. *
  57520. * safe_c_pp -> 1, but if mv, -> 3
  57521. * 1: -> 2, if mv -> 4
  57522. * 2: done (both normal)
  57523. * 3: -> 5, but if mv, -> 6
  57524. * 4: done (1 normal, 2 mv)
  57525. * 5: done (1 mv, 2 normal)
  57526. * 6: done (both mv)
  57527. *
  57528. * I think safe_c_ppp would require 18 branches (or maybe just collect the args and concatenate at the end?)
  57529. */
  57530. push_stack(sc, OP_SAFE_C_PP_2, sc->value, sc->code); /* mv -> 3 */
  57531. sc->code = caddr(sc->code);
  57532. if (is_optimized(sc->code))
  57533. goto OPT_EVAL;
  57534. goto EVAL;
  57535. case OP_SAFE_C_PP_2:
  57536. /* we get here only if neither arg returned multiple values, so sc->args is the first value, and sc->value the second */
  57537. set_car(sc->t2_1, sc->args);
  57538. set_car(sc->t2_2, sc->value);
  57539. sc->value = c_call(sc->code)(sc, sc->t2_1);
  57540. break;
  57541. case OP_SAFE_C_PP_3:
  57542. /* we get here if the first arg returned multiple values */
  57543. push_stack(sc, OP_SAFE_C_PP_5, sc->value, sc->code);
  57544. sc->code = caddr(sc->code);
  57545. if (is_optimized(sc->code))
  57546. goto OPT_EVAL;
  57547. goto EVAL;
  57548. case OP_SAFE_C_PP_4:
  57549. /* we get here if the first arg result was normal, but the second had multiple values */
  57550. sc->args = cons(sc, sc->args, sc->value);
  57551. sc->code = c_function_base(opt_cfunc(sc->code));
  57552. goto APPLY;
  57553. case OP_SAFE_C_PP_5:
  57554. /* 1 mv, 2, normal */
  57555. sc->args = s7_append(sc, sc->args, list_1(sc, sc->value));
  57556. sc->code = c_function_base(opt_cfunc(sc->code));
  57557. goto APPLY;
  57558. case OP_SAFE_C_PP_6:
  57559. /* both mv */
  57560. sc->args = s7_append(sc, sc->args, sc->value);
  57561. /*
  57562. * c_call(sc->code) here is g_add_2, but we have any number of args from a values call
  57563. * the original (unoptimized) function is (hopefully) c_function_base(opt_cfunc(sc->code))?
  57564. * (let () (define (ho a) (+ a 2)) (define (hi) (+ (ho 1) (ho 2))) (hi)) -> 7
  57565. * (let () (define (ho a) (+ a 2)) (define (hi) (+ (ho 1) (values 3 4))) (hi)) -> 10
  57566. * (let () (define (ho a) (+ a 2)) (define (hi) (+ (values 3 4) (ho 1))) (hi)) -> 10
  57567. * (let () (define (hi) (+ (values 1 2) (values 3 4))) (hi)) -> 10
  57568. */
  57569. sc->code = c_function_base(opt_cfunc(sc->code));
  57570. goto APPLY;
  57571. case OP_C_P_1:
  57572. sc->value = c_call(sc->code)(sc, list_1(sc, sc->value));
  57573. break;
  57574. case OP_C_P_2:
  57575. /* op_c_p_1 -> mv case: (define (hi) (format (values #f "~A ~D" 1 2))) */
  57576. sc->code = c_function_base(opt_cfunc(sc->code)); /* see comment above */
  57577. sc->args = copy_list(sc, sc->value);
  57578. goto APPLY;
  57579. case OP_SAFE_CLOSURE_P_1:
  57580. sc->envir = old_frame_with_slot(sc, closure_let(opt_lambda(sc->code)), sc->value);
  57581. sc->code = closure_body(opt_lambda(sc->code));
  57582. goto BEGIN1;
  57583. case OP_CLOSURE_P_1:
  57584. /* sc->value is presumably the argument value */
  57585. check_stack_size(sc);
  57586. sc->code = opt_lambda(sc->code);
  57587. new_frame_with_slot(sc, closure_let(sc->code), sc->envir, car(closure_args(sc->code)), sc->value);
  57588. sc->code = closure_body(sc->code);
  57589. goto BEGIN1;
  57590. case OP_CLOSURE_P_2:
  57591. /* here we got multiple values */
  57592. sc->code = opt_lambda(sc->code);
  57593. sc->args = copy_list(sc, sc->value);
  57594. goto APPLY;
  57595. case OP_C_SP_1:
  57596. sc->value = c_call(sc->code)(sc, list_2(sc, sc->args, sc->value));
  57597. break;
  57598. case OP_C_SP_2:
  57599. /* op_c_sp_1 -> mv case: (map + (values '(1 2 3) #(1 2 3))) */
  57600. sc->code = c_function_base(opt_cfunc(sc->code));
  57601. sc->args = cons(sc, sc->args, copy_list(sc, sc->value));
  57602. goto APPLY;
  57603. /* -------------------------------- LET -------------------------------- */
  57604. case OP_LET_NO_VARS:
  57605. new_frame(sc, sc->envir, sc->envir);
  57606. sc->code = cdr(sc->code); /* ignore the () */
  57607. goto BEGIN1;
  57608. case OP_NAMED_LET_NO_VARS:
  57609. new_frame(sc, sc->envir, sc->envir);
  57610. sc->args = make_closure(sc, sc->nil, cddr(sc->code), T_CLOSURE); /* sc->args is a temp here */
  57611. make_slot_1(sc, sc->envir, car(sc->code), sc->args);
  57612. sc->code = cddr(sc->code);
  57613. goto BEGIN1;
  57614. case OP_LET_C:
  57615. /* one var, init is constant, incoming sc->code is '(((var val))...)! */
  57616. new_frame_with_slot(sc, sc->envir, sc->envir, opt_sym3(sc->code), opt_con2(sc->code));
  57617. sc->code = cdr(sc->code);
  57618. goto BEGIN1;
  57619. case OP_LET_S:
  57620. /* one var, init is symbol, incoming sc->code is '(((var sym))...) */
  57621. sc->value = find_symbol_checked(sc, opt_sym2(sc->code));
  57622. new_frame_with_slot(sc, sc->envir, sc->envir, opt_sym3(sc->code), sc->value);
  57623. sc->code = cdr(sc->code);
  57624. goto BEGIN1;
  57625. case OP_LET_opSq:
  57626. {
  57627. s7_pointer binding;
  57628. binding = caar(sc->code);
  57629. set_car(sc->t1_1, find_symbol_checked(sc, opt_sym2(sc->code)));
  57630. sc->value = c_call(cadr(binding))(sc, sc->t1_1);
  57631. new_frame_with_slot(sc, sc->envir, sc->envir, car(binding), sc->value);
  57632. push_stack_no_args(sc, OP_BEGIN1, cddr(sc->code));
  57633. sc->code = cadr(sc->code);
  57634. goto EVAL;
  57635. }
  57636. case OP_LET_opSq_P:
  57637. {
  57638. s7_pointer binding;
  57639. binding = caar(sc->code);
  57640. set_car(sc->t1_1, find_symbol_checked(sc, opt_sym2(sc->code)));
  57641. sc->value = c_call(cadr(binding))(sc, sc->t1_1);
  57642. new_frame_with_slot(sc, sc->envir, sc->envir, car(binding), sc->value);
  57643. sc->code = cadr(sc->code);
  57644. goto EVAL;
  57645. }
  57646. case OP_LET_opCq: /* one var, init is safe_c_c */
  57647. #if DEBUGGING
  57648. {
  57649. s7_pointer old_code, old_env; /* trying to define lots of Snd function safe -- they crash here if they aren't actually safe */
  57650. old_code = sc->code; /* so, add a bandage while I track them down... */
  57651. old_env = sc->envir;
  57652. sc->value = c_call(opt_pair2(sc->code))(sc, cdr(opt_pair2(sc->code)));
  57653. if ((sc->code != old_code) ||
  57654. (sc->envir != old_env))
  57655. fprintf(stderr, "something changed: %s -> %s, %s -> %s\n",
  57656. DISPLAY(old_code), DISPLAY(sc->code),
  57657. DISPLAY(old_env), DISPLAY(sc->envir));
  57658. new_frame_with_slot(sc, sc->envir, sc->envir, opt_sym3(old_code), sc->value);
  57659. sc->code = cdr(old_code);
  57660. goto BEGIN1;
  57661. }
  57662. #else
  57663. sc->value = c_call(opt_pair2(sc->code))(sc, cdr(opt_pair2(sc->code)));
  57664. new_frame_with_slot(sc, sc->envir, sc->envir, opt_sym3(sc->code), sc->value);
  57665. sc->code = cdr(sc->code);
  57666. goto BEGIN1;
  57667. #endif
  57668. case OP_LET_opSSq: /* one var, init is safe_c_ss */
  57669. {
  57670. s7_pointer largs, in_val;
  57671. largs = opt_pair2(sc->code); /* cadr(caar(sc->code)); */
  57672. in_val = find_symbol_checked(sc, cadr(largs));
  57673. set_car(sc->t2_2, find_symbol_checked(sc, opt_sym3(sc->code))); /* caddr(largs)); */
  57674. set_car(sc->t2_1, in_val);
  57675. sc->value = c_call(largs)(sc, sc->t2_1);
  57676. new_frame_with_slot(sc, sc->envir, sc->envir, caaar(sc->code), sc->value);
  57677. sc->code = cdr(sc->code);
  57678. goto BEGIN1;
  57679. }
  57680. case OP_LET_Z:
  57681. push_stack(sc, OP_LET_Z_1, opt_sym2(cdr(sc->code)), cadr(sc->code));
  57682. sc->code = opt_pair2(sc->code);
  57683. goto OPT_EVAL;
  57684. case OP_LET_Z_1:
  57685. new_frame_with_slot(sc, sc->envir, sc->envir, sc->args, sc->value);
  57686. goto EVAL;
  57687. case OP_LET_ONE:
  57688. /* one var */
  57689. {
  57690. s7_pointer p;
  57691. p = caar(sc->code);
  57692. sc->value = cadr(p);
  57693. if (is_pair(sc->value))
  57694. {
  57695. push_stack(sc, OP_LET_ONE_1, car(p), cdr(sc->code)); /* args code */
  57696. sc->code = sc->value;
  57697. goto EVAL;
  57698. }
  57699. if (is_symbol(sc->value))
  57700. sc->value = find_symbol_checked(sc, sc->value);
  57701. sc->code = cdr(sc->code);
  57702. sc->args = car(p);
  57703. /* drop through */
  57704. }
  57705. case OP_LET_ONE_1:
  57706. new_frame_with_slot(sc, sc->envir, sc->envir, sc->args, sc->value);
  57707. goto BEGIN1;
  57708. case OP_LET_ALL_C:
  57709. {
  57710. s7_pointer p;
  57711. new_frame(sc, sc->envir, sc->envir);
  57712. for (p = car(sc->code); is_pair(p); p = cdr(p))
  57713. add_slot(sc->envir, caar(p), cadar(p));
  57714. sc->code = cdr(sc->code);
  57715. goto BEGIN1;
  57716. }
  57717. case OP_LET_ALL_S:
  57718. /* n vars, all inits are symbols. We need to GC-protect the new frame-list as it is being
  57719. * created without tying the new frame into sc->envir until the end.
  57720. */
  57721. {
  57722. s7_pointer p, frame;
  57723. frame = make_simple_let(sc);
  57724. sc->args = frame;
  57725. for (p = car(sc->code); is_pair(p); p = cdr(p))
  57726. add_slot(frame, caar(p), find_symbol_checked(sc, cadar(p)));
  57727. sc->let_number++;
  57728. sc->envir = frame;
  57729. sc->code = cdr(sc->code);
  57730. goto BEGIN1;
  57731. }
  57732. case OP_LET_ALL_opSq:
  57733. {
  57734. s7_pointer p, frame;
  57735. frame = make_simple_let(sc);
  57736. sc->args = frame;
  57737. for (p = car(sc->code); is_pair(p); p = cdr(p))
  57738. {
  57739. s7_pointer cp;
  57740. cp = cadar(p);
  57741. set_car(sc->t1_1, find_symbol_checked(sc, cadr(cp)));
  57742. add_slot(frame, caar(p), c_call(cp)(sc, sc->t1_1));
  57743. }
  57744. sc->let_number++;
  57745. sc->envir = frame;
  57746. sc->code = cdr(sc->code);
  57747. goto BEGIN1;
  57748. }
  57749. /* it is possible to save the frame+slots in a copied symbol+syntax pair, then reuse them
  57750. * on every call here, but the savings in GC+allocation+setup is less than the cost in
  57751. * marking the saved stuff past its actual life! (If the code is removed from the heap,
  57752. * the frame has to be saved on the permanent_objects list).
  57753. */
  57754. case OP_LET_ALL_X:
  57755. {
  57756. s7_pointer p, frame;
  57757. frame = make_simple_let(sc);
  57758. sc->args = frame;
  57759. for (p = car(sc->code); is_pair(p); p = cdr(p))
  57760. {
  57761. s7_pointer arg;
  57762. arg = cdar(p);
  57763. arg = c_call(arg)(sc, car(arg));
  57764. add_slot(frame, caar(p), arg);
  57765. }
  57766. sc->let_number++;
  57767. sc->envir = frame;
  57768. sc->code = cdr(sc->code);
  57769. goto BEGIN1;
  57770. }
  57771. case OP_NAMED_LET:
  57772. sc->args = sc->nil;
  57773. sc->value = sc->code;
  57774. sc->code = cadr(sc->code);
  57775. goto LET1;
  57776. case OP_LET_UNCHECKED:
  57777. /* not named, but has vars */
  57778. {
  57779. s7_pointer x;
  57780. new_cell(sc, x, T_PAIR);
  57781. set_car(x, sc->code);
  57782. set_cdr(x, sc->nil);
  57783. sc->args = x;
  57784. sc->code = car(sc->code);
  57785. goto LET1A;
  57786. }
  57787. case OP_LET:
  57788. /* sc->code is everything after the let: (let ((a 1)) a) so sc->code is (((a 1)) a) */
  57789. /* car can be either a list or a symbol ("named let") */
  57790. {
  57791. bool named_let;
  57792. check_let(sc);
  57793. sc->args = sc->nil;
  57794. sc->value = sc->code;
  57795. named_let = is_symbol(car(sc->code));
  57796. sc->code = (named_let) ? cadr(sc->code) : car(sc->code);
  57797. if (is_null(sc->code)) /* (let [name] () ...): no bindings, so skip that step */
  57798. {
  57799. sc->code = sc->value;
  57800. new_frame(sc, sc->envir, sc->envir);
  57801. if (named_let)
  57802. {
  57803. sc->x = make_closure(sc, sc->nil, cddr(sc->code), T_CLOSURE); /* args = () in new closure, see NAMED_LET_NO_VARS above */
  57804. /* if this is a safe closure, we can build its env in advance and name it (a thunk in this case) */
  57805. set_function_env(closure_let(sc->x));
  57806. funclet_set_function(closure_let(sc->x), car(sc->code));
  57807. make_slot_1(sc, sc->envir, car(sc->code), sc->x);
  57808. sc->code = cddr(sc->code);
  57809. sc->x = sc->nil;
  57810. }
  57811. else sc->code = cdr(sc->code);
  57812. goto BEGIN1;
  57813. }
  57814. }
  57815. LET1:
  57816. case OP_LET1:
  57817. {
  57818. s7_pointer x, y;
  57819. new_cell(sc, x, T_PAIR);
  57820. set_car(x, sc->value); /* the first time (now handled above), this saves the entire let body across the evaluations -- we pick it up later */
  57821. set_cdr(x, sc->args);
  57822. sc->args = x;
  57823. if (is_pair(sc->code))
  57824. {
  57825. LET1A:
  57826. x = cadar(sc->code);
  57827. if (is_pair(x))
  57828. {
  57829. push_stack(sc, OP_LET1, sc->args, cdr(sc->code));
  57830. sc->code = x;
  57831. if (is_optimized(x))
  57832. goto OPT_EVAL;
  57833. goto EVAL;
  57834. /* this push_stack/goto can't be optimized away via a local optimize_op case statement
  57835. * because any c_call can trigger an embedded call on the evaluator (for example,
  57836. * open-sound involves both hooks, and s7_load if the corresponding .scm code exists),
  57837. * so we have to protect sc->code and sc->args via the stack. (I subsequently added
  57838. * some protection here, but debugging this is hard, and the gain is not huge).
  57839. */
  57840. }
  57841. if (is_symbol(x))
  57842. sc->value = find_symbol_checked(sc, x);
  57843. else sc->value = _NFre(x);
  57844. sc->code = cdr(sc->code);
  57845. goto LET1;
  57846. }
  57847. x = safe_reverse_in_place(sc, sc->args);
  57848. sc->code = car(x); /* restore the original form */
  57849. y = cdr(x); /* use sc->args as the new frame */
  57850. sc->y = y;
  57851. sc->envir = old_frame_in_env(sc, x, sc->envir);
  57852. {
  57853. bool named_let;
  57854. named_let = is_symbol(car(sc->code));
  57855. if (named_let)
  57856. {
  57857. /* we need to check the current environment for ridiculous cases like
  57858. * (let hiho ((hiho 4)) hiho) -- I guess hiho is 4
  57859. */
  57860. s7_pointer let_name;
  57861. let_name = car(sc->code);
  57862. sc->envir = new_frame_in_env(sc, sc->envir);
  57863. sc->w = sc->nil;
  57864. for (x = cadr(sc->code); is_pair(x); x = cdr(x))
  57865. sc->w = cons(sc, caar(x), sc->w);
  57866. sc->x = make_closure(sc, sc->w = safe_reverse_in_place(sc, sc->w), cddr(sc->code), T_CLOSURE);
  57867. sc->w = sc->nil;
  57868. if (is_safe_closure(sc->x))
  57869. {
  57870. s7_pointer arg, new_env;
  57871. new_env = new_frame_in_env(sc, sc->envir);
  57872. closure_set_let(sc->x, new_env);
  57873. for (arg = closure_args(sc->x); is_pair(arg); arg = cdr(arg))
  57874. make_slot_1(sc, new_env, car(arg), sc->nil);
  57875. let_set_slots(new_env, reverse_slots(sc, let_slots(new_env)));
  57876. }
  57877. make_slot_1(sc, sc->envir, let_name, sc->x);
  57878. sc->x = sc->nil;
  57879. sc->envir = new_frame_in_env(sc, sc->envir);
  57880. for (x = cadr(sc->code); is_not_null(y); x = cdr(x))
  57881. {
  57882. s7_pointer sym, args, val;
  57883. /* reuse the value cells as the new frame slots */
  57884. sym = caar(x);
  57885. if (sym == let_name) let_name = sc->nil;
  57886. val = car(y);
  57887. args = cdr(y);
  57888. set_type(y, T_SLOT);
  57889. slot_set_symbol(y, sym);
  57890. slot_set_value(y, val);
  57891. set_next_slot(y, let_slots(sc->envir));
  57892. let_set_slots(sc->envir, y);
  57893. symbol_set_local(sym, let_id(sc->envir), y);
  57894. y = args;
  57895. }
  57896. sc->code = cddr(sc->code);
  57897. }
  57898. else
  57899. {
  57900. s7_pointer e;
  57901. unsigned long long int id;
  57902. e = sc->envir;
  57903. id = let_id(e);
  57904. for (x = car(sc->code); is_not_null(y); x = cdr(x))
  57905. {
  57906. s7_pointer sym, args, val;
  57907. /* reuse the value cells as the new frame slots */
  57908. sym = caar(x);
  57909. val = car(y);
  57910. args = cdr(y);
  57911. set_type(y, T_SLOT);
  57912. slot_set_symbol(y, sym);
  57913. symbol_set_local(sym, id, y);
  57914. slot_set_value(y, val);
  57915. set_next_slot(y, let_slots(e));
  57916. let_set_slots(e, y);
  57917. y = args;
  57918. }
  57919. sc->code = cdr(sc->code);
  57920. }
  57921. }
  57922. sc->y = sc->nil;
  57923. goto BEGIN1;
  57924. }
  57925. /* -------------------------------- LET* -------------------------------- */
  57926. case OP_LET_STAR_ALL_X:
  57927. {
  57928. s7_pointer p;
  57929. for (p = car(sc->code); is_pair(p); p = cdr(p))
  57930. {
  57931. s7_pointer arg;
  57932. arg = cdar(p);
  57933. arg = c_call(arg)(sc, car(arg));
  57934. new_frame_with_slot(sc, sc->envir, sc->envir, caar(p), arg);
  57935. }
  57936. sc->code = cdr(sc->code);
  57937. goto BEGIN1;
  57938. }
  57939. case OP_NAMED_LET_STAR:
  57940. push_stack(sc, OP_LET_STAR1, sc->code, cadr(sc->code));
  57941. sc->code = opt_con2(sc->code);
  57942. goto EVAL;
  57943. case OP_LET_STAR2:
  57944. push_stack(sc, OP_LET_STAR1, sc->code, car(sc->code));
  57945. sc->code = opt_con2(sc->code);
  57946. goto EVAL;
  57947. case OP_LET_STAR:
  57948. check_let_star(sc);
  57949. case OP_LET_STAR_UNCHECKED:
  57950. if (is_symbol(car(sc->code)))
  57951. {
  57952. s7_pointer cx;
  57953. cx = car(sc->code);
  57954. sc->value = cdr(sc->code);
  57955. if (is_null(car(sc->value)))
  57956. {
  57957. sc->envir = new_frame_in_env(sc, sc->envir);
  57958. sc->code = cdr(sc->value);
  57959. make_slot_1(sc, sc->envir, cx, make_closure(sc, sc->nil, sc->code, T_CLOSURE_STAR));
  57960. goto BEGIN1;
  57961. }
  57962. }
  57963. else
  57964. {
  57965. if (is_null(car(sc->code)))
  57966. {
  57967. sc->envir = new_frame_in_env(sc, sc->envir);
  57968. sc->code = cdr(sc->code);
  57969. goto BEGIN1;
  57970. }
  57971. }
  57972. if (is_symbol(car(sc->code)))
  57973. {
  57974. push_stack(sc, OP_LET_STAR1, sc->code, cadr(sc->code));
  57975. sc->code = cadr(caadr(sc->code));
  57976. }
  57977. else
  57978. {
  57979. push_stack(sc, OP_LET_STAR1, sc->code, car(sc->code));
  57980. /* args is the let body, saved for later, code is the list of vars+initial-values */
  57981. sc->code = cadr(caar(sc->code));
  57982. /* caar(code) = first var/val pair, we've checked that all these guys are legit, so cadr of that is the value */
  57983. }
  57984. goto EVAL;
  57985. case OP_LET_STAR1: /* let* -- calculate parameters */
  57986. /* we can't skip (or reuse) this new frame -- we have to imitate a nested let, otherwise
  57987. * (let ((f1 (lambda (arg) (+ arg 1))))
  57988. * (let* ((x 32)
  57989. * (f1 (lambda (arg) (f1 (+ x arg)))))
  57990. * (f1 1)))
  57991. * will hang. (much later -- this worries me... Could we defer making the slot?)
  57992. */
  57993. while (true)
  57994. {
  57995. new_frame_with_slot(sc, sc->envir, sc->envir, caar(sc->code), sc->value);
  57996. sc->code = cdr(sc->code);
  57997. if (is_pair(sc->code))
  57998. {
  57999. s7_pointer x;
  58000. x = cadar(sc->code);
  58001. if (is_pair(x))
  58002. {
  58003. push_stack(sc, OP_LET_STAR1, sc->args, sc->code);
  58004. sc->code = x;
  58005. if (is_optimized(x))
  58006. goto OPT_EVAL;
  58007. goto EVAL;
  58008. }
  58009. if (is_symbol(x))
  58010. sc->value = find_symbol_checked(sc, x);
  58011. else sc->value = _NFre(x);
  58012. }
  58013. else break;
  58014. }
  58015. sc->code = sc->args; /* original sc->code set in push_stack above */
  58016. if (is_symbol(car(sc->code)))
  58017. {
  58018. /* now we need to declare the new function */
  58019. make_slot_1(sc, sc->envir, car(sc->code), make_closure(sc, cadr(sc->code), cddr(sc->code), T_CLOSURE_STAR));
  58020. sc->code = cddr(sc->code);
  58021. }
  58022. else sc->code = cdr(sc->code);
  58023. goto BEGIN1;
  58024. /* -------------------------------- LETREC -------------------------------- */
  58025. case OP_LETREC:
  58026. check_letrec(sc, true);
  58027. case OP_LETREC_UNCHECKED:
  58028. /* get all local vars and set to #<undefined>
  58029. * get parallel list of values
  58030. * eval each member of values list with env still full of #<undefined>'s
  58031. * assign each value to its variable
  58032. * eval body
  58033. *
  58034. * which means that (letrec ((x x)) x) is not an error!
  58035. * but this assumes the environment is not changed by evaluating the exprs?
  58036. * (letrec ((a (define b 1))) b) -- if let, the define takes place in the calling env, not the current env
  58037. * (letrec ((f1 (lambda (x) (f2 (* 2 x))))) (define (f2 y) (- y 1)) (f1 3)) -> 5 (Guile says unbound f2)
  58038. *
  58039. * I think I need to check here that slot_pending_value is set (using the is_checked bit below).
  58040. */
  58041. sc->envir = new_frame_in_env(sc, sc->envir);
  58042. if (is_pair(car(sc->code)))
  58043. {
  58044. s7_pointer x;
  58045. for (x = car(sc->code); is_not_null(x); x = cdr(x))
  58046. {
  58047. s7_pointer slot;
  58048. slot = make_slot_1(sc, sc->envir, caar(x), sc->undefined);
  58049. slot_set_pending_value(slot, sc->undefined);
  58050. slot_set_expression(slot, cadar(x));
  58051. set_checked_slot(slot);
  58052. }
  58053. sc->args = let_slots(sc->envir);
  58054. push_stack(sc, OP_LETREC1, sc->args, sc->code);
  58055. sc->code = slot_expression(sc->args);
  58056. goto EVAL;
  58057. }
  58058. sc->code = cdr(sc->code);
  58059. goto BEGIN1;
  58060. case OP_LETREC1:
  58061. slot_set_pending_value(sc->args, sc->value);
  58062. sc->args = next_slot(sc->args);
  58063. if (is_slot(sc->args))
  58064. {
  58065. push_stack(sc, OP_LETREC1, sc->args, sc->code);
  58066. sc->code = slot_expression(sc->args);
  58067. goto EVAL;
  58068. }
  58069. else
  58070. {
  58071. s7_pointer slot;
  58072. for (slot = let_slots(sc->envir); is_slot(slot); slot = next_slot(slot))
  58073. if (is_checked_slot(slot))
  58074. slot_set_value(slot, slot_pending_value(slot));
  58075. sc->code = cdr(sc->code);
  58076. goto BEGIN1;
  58077. }
  58078. /* -------------------------------- LETREC* -------------------------------- */
  58079. case OP_LETREC_STAR:
  58080. check_letrec(sc, false);
  58081. case OP_LETREC_STAR_UNCHECKED:
  58082. /* get all local vars and set to #<undefined>
  58083. * eval each member of values list and assign immediately, as in let*
  58084. * eval body
  58085. */
  58086. sc->envir = new_frame_in_env(sc, sc->envir);
  58087. if (is_pair(car(sc->code)))
  58088. {
  58089. s7_pointer x, p, q;
  58090. for (x = car(sc->code); is_not_null(x); x = cdr(x))
  58091. {
  58092. s7_pointer slot;
  58093. slot = make_slot_1(sc, sc->envir, caar(x), sc->undefined);
  58094. slot_set_expression(slot, cadar(x));
  58095. }
  58096. /* these are reversed, and for letrec*, they need to be in order, so... (reverse_in_place on the slot list) */
  58097. p = let_slots(sc->envir);
  58098. x = sc->nil;
  58099. while (is_slot(p))
  58100. {
  58101. q = next_slot(p);
  58102. set_next_slot(p, x);
  58103. x = p;
  58104. p = q;
  58105. }
  58106. let_set_slots(sc->envir, x);
  58107. sc->args = let_slots(sc->envir);
  58108. push_stack(sc, OP_LETREC_STAR1, sc->args, sc->code);
  58109. sc->code = slot_expression(sc->args);
  58110. goto EVAL;
  58111. }
  58112. sc->code = cdr(sc->code);
  58113. goto BEGIN1;
  58114. case OP_LETREC_STAR1:
  58115. {
  58116. s7_pointer slot;
  58117. slot = sc->args;
  58118. slot_set_value(slot, sc->value);
  58119. slot = next_slot(slot);
  58120. if (is_slot(slot))
  58121. {
  58122. push_stack(sc, OP_LETREC_STAR1, slot, sc->code);
  58123. sc->code = slot_expression(slot);
  58124. goto EVAL;
  58125. }
  58126. else
  58127. {
  58128. sc->code = cdr(sc->code);
  58129. goto BEGIN1;
  58130. }
  58131. }
  58132. /* -------------------------------- COND -------------------------------- */
  58133. case OP_COND:
  58134. check_cond(sc);
  58135. case OP_COND_UNCHECKED:
  58136. push_stack(sc, OP_COND1, sc->nil, sc->code);
  58137. sc->code = caar(sc->code);
  58138. goto EVAL;
  58139. case OP_COND1:
  58140. if (is_true(sc, sc->value))
  58141. {
  58142. sc->code = cdar(sc->code);
  58143. if (is_null(sc->code))
  58144. {
  58145. if (is_multiple_value(sc->value)) /* (+ 1 (cond ((values 2 3)))) */
  58146. sc->value = splice_in_values(sc, multiple_value(sc->value));
  58147. /* no result clause, so return test, (cond (#t)) -> #t, (cond ((+ 1 2))) -> 3 */
  58148. goto START;
  58149. }
  58150. if (is_pair(sc->code))
  58151. {
  58152. if ((car(sc->code) == sc->feed_to_symbol) &&
  58153. (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
  58154. {
  58155. /* old form (pre 6-June-16): this causes a double evaluation:
  58156. * (let ((x 'y) (y 32)) (cond ((values x y) => list))) -> '(32 32)
  58157. * but it should be '(y 32)
  58158. * it's also extremely slow: make/eval a list?!
  58159. *
  58160. * if (is_multiple_value(sc->value))
  58161. * sc->code = cons(sc, cadr(sc->code), multiple_value(sc->value));
  58162. * else sc->code = list_2(sc, cadr(sc->code), list_2(sc, sc->quote_symbol, sc->value));
  58163. * goto EVAL;
  58164. */
  58165. if (is_multiple_value(sc->value)) /* (cond ((values 1 2) => +)) */
  58166. {
  58167. sc->args = multiple_value(sc->value);
  58168. clear_multiple_value(sc->args);
  58169. }
  58170. else sc->args = list_1(sc, sc->value);
  58171. if (is_symbol(cadr(sc->code)))
  58172. {
  58173. sc->code = find_symbol_checked(sc, cadr(sc->code)); /* car is => */
  58174. if (needs_copied_args(sc->code))
  58175. sc->args = copy_list(sc, sc->args);
  58176. goto APPLY;
  58177. }
  58178. else
  58179. {
  58180. /* need to evaluate the target function */
  58181. push_stack(sc, OP_COND1_1, sc->args, sc->code);
  58182. sc->code = cadr(sc->code);
  58183. sc->args = sc->nil;
  58184. goto EVAL;
  58185. }
  58186. }
  58187. goto BEGIN1;
  58188. }
  58189. eval_error(sc, "cond: unexpected dot? ~A", sc->code); /* (cond (#t . 1)) etc */
  58190. }
  58191. sc->code = cdr(sc->code);
  58192. if (is_null(sc->code))
  58193. {
  58194. sc->value = sc->unspecified; /* changed 31-Dec-15 */
  58195. /* r7rs sez the value if no else clause is unspecified, and this choice makes cond consistent with if and case,
  58196. * and rewrite choices between the three are simpler if they are consistent.
  58197. */
  58198. goto START;
  58199. }
  58200. push_stack_no_args(sc, OP_COND1, sc->code);
  58201. sc->code = caar(sc->code);
  58202. goto EVAL;
  58203. case OP_COND1_1:
  58204. sc->code = sc->value;
  58205. if (needs_copied_args(sc->code))
  58206. sc->args = copy_list(sc, sc->args);
  58207. goto APPLY;
  58208. case OP_COND_SIMPLE:
  58209. push_stack_no_args(sc, OP_COND1_SIMPLE, sc->code);
  58210. sc->code = caar(sc->code);
  58211. goto EVAL;
  58212. case OP_COND1_SIMPLE:
  58213. while (true)
  58214. {
  58215. if (is_true(sc, sc->value))
  58216. {
  58217. sc->code = cdar(sc->code);
  58218. if (is_null(sc->code))
  58219. {
  58220. if (is_multiple_value(sc->value))
  58221. sc->value = splice_in_values(sc, multiple_value(sc->value));
  58222. goto START;
  58223. }
  58224. goto BEGIN1;
  58225. }
  58226. sc->code = cdr(sc->code);
  58227. if (is_null(sc->code))
  58228. {
  58229. sc->value = sc->unspecified;
  58230. goto START;
  58231. }
  58232. if (is_pair(caar(sc->code)))
  58233. {
  58234. push_stack_no_args(sc, OP_COND1_SIMPLE, sc->code);
  58235. sc->code = caar(sc->code);
  58236. goto EVAL;
  58237. }
  58238. sc->value = caar(sc->code);
  58239. if (is_symbol(sc->value))
  58240. sc->value = find_symbol_checked(sc, sc->value);
  58241. }
  58242. case OP_COND_S:
  58243. {
  58244. s7_pointer val = NULL, p;
  58245. if (is_pair(caar(sc->code)))
  58246. val = find_symbol_checked(sc, cadaar(sc->code));
  58247. for (p = sc->code; is_pair(p); p = cdr(p))
  58248. {
  58249. s7_pointer ap;
  58250. ap = caar(p);
  58251. if (is_pair(ap))
  58252. {
  58253. set_car(sc->t1_1, val);
  58254. sc->value = c_call(ap)(sc, sc->t1_1);
  58255. }
  58256. else sc->value = sc->T;
  58257. if (is_true(sc, sc->value))
  58258. {
  58259. sc->code = cdar(p);
  58260. if (is_null(sc->code))
  58261. {
  58262. if (is_multiple_value(sc->value))
  58263. sc->value = splice_in_values(sc, multiple_value(sc->value));
  58264. goto START;
  58265. }
  58266. goto BEGIN1;
  58267. }
  58268. }
  58269. sc->value = sc->unspecified;
  58270. }
  58271. break;
  58272. case OP_COND_ALL_X_2:
  58273. {
  58274. s7_pointer p;
  58275. p = sc->code;
  58276. sc->value = c_call(car(p))(sc, caar(p));
  58277. if (!is_true(sc, sc->value))
  58278. {
  58279. p = cdr(p);
  58280. sc->value = c_call(car(p))(sc, caar(p));
  58281. if (!is_true(sc, sc->value))
  58282. {
  58283. sc->value = sc->unspecified;
  58284. goto START;
  58285. }
  58286. }
  58287. sc->code = cdar(p);
  58288. if (is_null(sc->code))
  58289. {
  58290. if (is_multiple_value(sc->value))
  58291. sc->value = splice_in_values(sc, multiple_value(sc->value));
  58292. goto START;
  58293. }
  58294. goto BEGIN1;
  58295. }
  58296. case OP_COND_ALL_X:
  58297. {
  58298. s7_pointer p;
  58299. for (p = sc->code; is_pair(p); p = cdr(p))
  58300. {
  58301. sc->value = c_call(car(p))(sc, caar(p));
  58302. if (is_true(sc, sc->value))
  58303. {
  58304. sc->code = cdar(p);
  58305. if (is_null(sc->code))
  58306. {
  58307. if (is_multiple_value(sc->value))
  58308. sc->value = splice_in_values(sc, multiple_value(sc->value));
  58309. goto START;
  58310. }
  58311. goto BEGIN1;
  58312. }
  58313. }
  58314. sc->value = sc->unspecified;
  58315. }
  58316. break;
  58317. /* -------------------------------- AND -------------------------------- */
  58318. case OP_AND:
  58319. check_and(sc);
  58320. if (is_null(sc->code))
  58321. {
  58322. sc->value = sc->T;
  58323. goto START;
  58324. }
  58325. goto AND1;
  58326. case OP_AND1:
  58327. if ((is_false(sc, sc->value)) ||
  58328. (is_null(sc->code)))
  58329. goto START;
  58330. AND1:
  58331. case OP_AND_UNCHECKED:
  58332. {
  58333. s7_pointer p;
  58334. p = car(sc->code);
  58335. if (!is_pair(p))
  58336. {
  58337. if (is_symbol(p))
  58338. sc->value = find_global_symbol_checked(sc, p);
  58339. else sc->value = p;
  58340. if ((is_false(sc, sc->value)) ||
  58341. (is_null(cdr(sc->code))))
  58342. goto START;
  58343. sc->code = cdr(sc->code);
  58344. goto AND1;
  58345. }
  58346. if (is_not_null(cdr(sc->code)))
  58347. push_stack_no_args(sc, OP_AND1, cdr(sc->code));
  58348. sc->code = p;
  58349. if (is_optimized(p))
  58350. goto OPT_EVAL;
  58351. goto EVAL;
  58352. }
  58353. case OP_AND_P1:
  58354. if ((is_false(sc, sc->value)) ||
  58355. (is_null(sc->code)))
  58356. goto START;
  58357. /* fall through */
  58358. AND_P:
  58359. case OP_AND_P:
  58360. if (c_callee(sc->code)) /* all c_callee's are set via all_x_eval which can return nil */
  58361. {
  58362. sc->value = c_call(sc->code)(sc, car(sc->code));
  58363. if (is_false(sc, sc->value))
  58364. goto START;
  58365. sc->code = cdr(sc->code);
  58366. if (is_null(sc->code))
  58367. goto START;
  58368. goto AND_P;
  58369. }
  58370. else
  58371. {
  58372. if (is_not_null(cdr(sc->code)))
  58373. push_stack_no_args(sc, OP_AND_P1, cdr(sc->code));
  58374. sc->code = car(sc->code);
  58375. goto EVAL;
  58376. }
  58377. case OP_AND_P2:
  58378. /* we know c_callee is set on sc->code, and there are only two branches */
  58379. sc->value = c_call(sc->code)(sc, car(sc->code));
  58380. if (is_false(sc, sc->value))
  58381. goto START;
  58382. sc->code = cadr(sc->code);
  58383. goto EVAL;
  58384. /* -------------------------------- OR -------------------------------- */
  58385. case OP_OR:
  58386. check_or(sc);
  58387. if (is_null(sc->code))
  58388. {
  58389. sc->value = sc->F;
  58390. goto START;
  58391. }
  58392. goto OR1;
  58393. case OP_OR1:
  58394. if ((is_true(sc, sc->value)) ||
  58395. (is_null(sc->code)))
  58396. goto START;
  58397. OR1:
  58398. case OP_OR_UNCHECKED:
  58399. if (!is_pair(car(sc->code)))
  58400. {
  58401. sc->value = car(sc->code);
  58402. if (is_symbol(sc->value))
  58403. sc->value = find_symbol_checked(sc, sc->value);
  58404. if ((is_true(sc, sc->value)) ||
  58405. (is_null(cdr(sc->code))))
  58406. goto START;
  58407. sc->code = cdr(sc->code);
  58408. goto OR1;
  58409. }
  58410. if (is_not_null(cdr(sc->code)))
  58411. push_stack_no_args(sc, OP_OR1, cdr(sc->code));
  58412. sc->code = car(sc->code);
  58413. goto EVAL;
  58414. case OP_OR_P1:
  58415. if ((is_true(sc, sc->value)) ||
  58416. (is_null(sc->code)))
  58417. goto START;
  58418. /* fall through */
  58419. OR_P:
  58420. case OP_OR_P:
  58421. if (c_callee(sc->code))
  58422. {
  58423. sc->value = c_call(sc->code)(sc, car(sc->code));
  58424. if (is_true(sc, sc->value))
  58425. goto START;
  58426. sc->code = cdr(sc->code);
  58427. if (is_null(sc->code))
  58428. goto START;
  58429. goto OR_P;
  58430. }
  58431. else
  58432. {
  58433. if (is_not_null(cdr(sc->code)))
  58434. push_stack_no_args(sc, OP_OR_P1, cdr(sc->code));
  58435. sc->code = car(sc->code);
  58436. goto EVAL;
  58437. }
  58438. case OP_OR_P2:
  58439. /* we know c_callee is set on sc->code, and there are only two branches */
  58440. sc->value = c_call(sc->code)(sc, car(sc->code));
  58441. if (is_true(sc, sc->value))
  58442. goto START;
  58443. sc->code = cadr(sc->code);
  58444. goto EVAL;
  58445. /* by going direct without a push_stack on the last one we get tail calls,
  58446. * but if the last arg (also in "and" above) is "values", there is a slight
  58447. * inconsistency: the values are returned and spliced into the caller if trailing, but
  58448. * are spliced into the "or" if not trailing, so
  58449. *
  58450. * (+ 10 (or (values 1 2) #f))
  58451. * 11
  58452. * (+ 10 (or #f (values 1 2)))
  58453. * 13
  58454. * (+ 10 (or (or #f (values 1 2)) #f))
  58455. * 11
  58456. *
  58457. * The tail recursion is more important. This behavior matches that of "begin" -- if the
  58458. * values statement is last, it splices into the next outer arglist.
  58459. */
  58460. /* -------------------------------- macro evaluation -------------------------------- */
  58461. case OP_EVAL_MACRO: /* after (scheme-side) macroexpansion, evaluate the resulting expression */
  58462. /*
  58463. * (define-macro (hi a) `(+ ,a 1))
  58464. * (hi 2)
  58465. * here with value: (+ 2 1)
  58466. */
  58467. if (is_multiple_value(sc->value))
  58468. {
  58469. /* a normal macro's result is evaluated (below) and its value replaces the macro invocation,
  58470. * so if a macro returns multiple values, evaluate each one, then replace the macro
  58471. * invocation with (apply values evaluated-results-in-a-list). We need to save the
  58472. * new list of results, and where we are in the macro's output list, so code=macro output,
  58473. * args=new list. If it returns (values), should we use #<unspecified>? I think that
  58474. * happens now without generating a multiple_value object:
  58475. * (define-macro (hi) (values)) (hi) -> #<unspecified>
  58476. *
  58477. * (define-macro (ho) (values '(+ 1 2) '(* 3 4))) (+ 1 (ho) 3) -> 19
  58478. * (define-macro (ha) (values '(define a 1) '(define b 2))) (let () (ha) (+ a b)) -> 3
  58479. */
  58480. push_stack(sc, OP_EVAL_MACRO_MV, sc->nil, cdr(sc->value));
  58481. sc->code = car(sc->value);
  58482. }
  58483. else sc->code = sc->value;
  58484. goto EVAL;
  58485. case OP_EVAL_MACRO_MV:
  58486. if (is_null(sc->code)) /* end of values list */
  58487. {
  58488. sc->value = splice_in_values(sc, multiple_value(safe_reverse_in_place(sc, cons(sc, sc->value, sc->args))));
  58489. goto START;
  58490. }
  58491. push_stack(sc, OP_EVAL_MACRO_MV, cons(sc, sc->value, sc->args), cdr(sc->code));
  58492. sc->code = car(sc->code);
  58493. goto EVAL;
  58494. case OP_EXPANSION:
  58495. /* after the expander has finished, if a list was returned, we need to add some annotations.
  58496. * if the expander returned (values), the list-in-progress vanishes! (This mimics map and *#readers*).
  58497. */
  58498. if (sc->value == sc->no_value)
  58499. sc->stack_end[-1] = (s7_pointer)OP_READ_NEXT;
  58500. else
  58501. {
  58502. if (is_pair(sc->value))
  58503. annotate_expansion(sc->value);
  58504. }
  58505. break;
  58506. case OP_DEFINE_MACRO_WITH_ACCESSOR:
  58507. if (sc->value == sc->error_symbol) /* backwards compatibility... */
  58508. return(s7_error(sc, sc->error_symbol, set_elist_3(sc, make_string_wrapper(sc, "can't define-macro ~S to ~S"), car(sc->args), cadr(sc->args))));
  58509. sc->code = sc->value;
  58510. if ((!is_pair(sc->code)) ||
  58511. (!is_pair(car(sc->code))) ||
  58512. (!is_symbol(caar(sc->code))))
  58513. eval_error(sc, "define-macro: ~S does not look like a macro?", sc->code);
  58514. sc->value = make_macro(sc);
  58515. break;
  58516. case OP_DEFINE_BACRO:
  58517. case OP_DEFINE_BACRO_STAR:
  58518. case OP_DEFINE_EXPANSION:
  58519. case OP_DEFINE_MACRO:
  58520. case OP_DEFINE_MACRO_STAR:
  58521. check_define_macro(sc, sc->op);
  58522. if (symbol_has_accessor(caar(sc->code)))
  58523. {
  58524. s7_pointer x;
  58525. x = find_symbol(sc, caar(sc->code));
  58526. if ((is_slot(x)) &&
  58527. (slot_has_accessor(x)))
  58528. {
  58529. sc->value = bind_accessed_symbol(sc, OP_DEFINE_MACRO_WITH_ACCESSOR, caar(sc->code), sc->code);
  58530. if (sc->value == sc->no_value)
  58531. goto APPLY;
  58532. sc->code = sc->value;
  58533. }
  58534. }
  58535. sc->value = make_macro(sc);
  58536. break;
  58537. case OP_LAMBDA:
  58538. check_lambda(sc);
  58539. case OP_LAMBDA_UNCHECKED:
  58540. make_closure_with_let(sc, sc->value, car(sc->code), cdr(sc->code), sc->envir);
  58541. break;
  58542. case OP_LAMBDA_STAR:
  58543. check_lambda_star(sc);
  58544. case OP_LAMBDA_STAR_UNCHECKED:
  58545. sc->value = make_closure(sc, car(sc->code), cdr(sc->code), T_CLOSURE_STAR);
  58546. break;
  58547. /* -------------------------------- CASE -------------------------------- */
  58548. case OP_CASE: /* case, car(sc->code) is the selector */
  58549. check_case(sc);
  58550. case OP_CASE_UNCHECKED:
  58551. {
  58552. s7_pointer carc;
  58553. carc = car(sc->code);
  58554. if (!is_pair(carc))
  58555. {
  58556. if (is_symbol(carc))
  58557. sc->value = find_symbol_checked(sc, carc);
  58558. else sc->value = carc;
  58559. sc->code = cdr(sc->code);
  58560. /* fall through */
  58561. }
  58562. else
  58563. {
  58564. push_stack_no_args(sc, OP_CASE1, cdr(sc->code));
  58565. sc->code = carc;
  58566. goto EVAL;
  58567. }
  58568. }
  58569. case OP_CASE1:
  58570. {
  58571. s7_pointer x, y;
  58572. if (is_simple(sc->value))
  58573. {
  58574. for (x = sc->code; is_pair(x); x = cdr(x))
  58575. {
  58576. y = caar(x);
  58577. if (!is_pair(y))
  58578. goto ELSE_CASE;
  58579. do {
  58580. if (car(y) == sc->value)
  58581. goto ELSE_CASE;
  58582. y = cdr(y);
  58583. } while (is_pair(y));
  58584. }
  58585. }
  58586. else
  58587. {
  58588. for (x = sc->code; is_pair(x); x = cdr(x))
  58589. {
  58590. y = caar(x);
  58591. if (!is_pair(y))
  58592. goto ELSE_CASE;
  58593. for (; is_pair(y); y = cdr(y))
  58594. if (s7_is_eqv(car(y), sc->value))
  58595. goto ELSE_CASE;
  58596. }
  58597. }
  58598. /* x is the entire matching clause, (case 2 ((2) 3)), x: (((2) 3)) */
  58599. ELSE_CASE:
  58600. if (is_not_null(x))
  58601. {
  58602. sc->code = cdar(x);
  58603. /* check for => */
  58604. if ((car(sc->code) == sc->feed_to_symbol) &&
  58605. (s7_symbol_value(sc, sc->feed_to_symbol) == sc->undefined))
  58606. {
  58607. sc->code = list_2(sc, cadr(sc->code), list_2(sc, sc->quote_symbol, sc->value));
  58608. goto EVAL;
  58609. }
  58610. goto BEGIN1;
  58611. }
  58612. /* no match found */
  58613. sc->value = sc->unspecified; /* this was sc->nil but the spec says case value is unspecified if no clauses match */
  58614. }
  58615. break;
  58616. case OP_CASE_SIMPLE:
  58617. /* assume symbol as selector, all keys are simple, and no => */
  58618. {
  58619. s7_pointer x, y, selector;
  58620. selector = find_symbol_checked(sc, car(sc->code));
  58621. for (x = cdr(sc->code); is_pair(x); x = cdr(x))
  58622. {
  58623. y = opt_key(x);
  58624. if (!is_pair(y)) /* else? */
  58625. {
  58626. sc->code = cdar(x);
  58627. goto BEGIN1;
  58628. }
  58629. do {
  58630. if (car(y) == selector)
  58631. {
  58632. sc->code = cdar(x);
  58633. goto BEGIN1;
  58634. }
  58635. y = cdr(y);
  58636. } while (is_pair(y));
  58637. }
  58638. sc->value = sc->unspecified;
  58639. }
  58640. break;
  58641. case OP_CASE_SIMPLER:
  58642. /* assume symbol as selector, all keys are simple, and no => and no else */
  58643. {
  58644. s7_pointer x, y, selector;
  58645. selector = find_symbol_checked(sc, car(sc->code));
  58646. for (x = cdr(sc->code); is_pair(x); x = cdr(x))
  58647. {
  58648. y = opt_key(x);
  58649. do {
  58650. if (car(y) == selector)
  58651. {
  58652. sc->code = cdar(x);
  58653. goto BEGIN1;
  58654. }
  58655. y = cdr(y);
  58656. } while (is_pair(y));
  58657. }
  58658. sc->value = sc->unspecified;
  58659. }
  58660. break;
  58661. case OP_CASE_SIMPLER_1:
  58662. /* assume symbol as selector, all keys are simple, and no => and no else, bodies are 1 liners */
  58663. {
  58664. s7_pointer x, y, selector;
  58665. selector = find_symbol_checked(sc, car(sc->code));
  58666. for (x = cdr(sc->code); is_pair(x); x = cdr(x))
  58667. {
  58668. y = opt_key(x);
  58669. do {
  58670. if (car(y) == selector)
  58671. {
  58672. sc->code = opt_clause(x); /* cadar(x); */
  58673. goto EVAL;
  58674. }
  58675. y = cdr(y);
  58676. } while (is_pair(y));
  58677. }
  58678. sc->value = sc->unspecified;
  58679. }
  58680. break;
  58681. case OP_CASE_SIMPLER_SS:
  58682. /* assume hop_safe_ss as selector, all keys are simple, and no => and no else, bodies are 1 liners */
  58683. {
  58684. s7_pointer x, y, selector, args;
  58685. args = cdar(sc->code);
  58686. x = find_symbol_checked(sc, car(args));
  58687. set_car(sc->t2_2, find_symbol_checked(sc, cadr(args)));
  58688. set_car(sc->t2_1, x);
  58689. selector = c_call(car(sc->code))(sc, sc->t2_1);
  58690. for (x = cdr(sc->code); is_pair(x); x = cdr(x))
  58691. {
  58692. y = opt_key(x);
  58693. do {
  58694. if (car(y) == selector)
  58695. {
  58696. sc->code = opt_clause(x); /* cadar(x); */
  58697. goto EVAL;
  58698. }
  58699. y = cdr(y);
  58700. } while (is_pair(y));
  58701. }
  58702. sc->value = sc->unspecified;
  58703. }
  58704. break;
  58705. case OP_CASE_SIMPLEST_SS:
  58706. {
  58707. s7_pointer x, selector, args;
  58708. args = cdar(sc->code);
  58709. x = find_symbol_checked(sc, car(args));
  58710. set_car(sc->t2_2, find_symbol_checked(sc, cadr(args)));
  58711. set_car(sc->t2_1, x);
  58712. selector = c_call(car(sc->code))(sc, sc->t2_1);
  58713. for (x = cdr(sc->code); is_pair(x); x = cdr(x))
  58714. if (opt_key(x) == selector)
  58715. {
  58716. sc->code = cdar(x);
  58717. goto BEGIN1;
  58718. }
  58719. sc->value = sc->unspecified;
  58720. }
  58721. break;
  58722. case OP_CASE_SIMPLEST:
  58723. /* assume symbol as selector, all keys are simple and singletons, and no => and no else, bodies are 1 liners */
  58724. {
  58725. s7_pointer x, selector;
  58726. selector = find_symbol_checked(sc, car(sc->code));
  58727. for (x = cdr(sc->code); is_pair(x); x = cdr(x))
  58728. if (opt_key(x) == selector)
  58729. {
  58730. sc->code = opt_clause(x); /* cadar(x); */
  58731. goto EVAL;
  58732. }
  58733. sc->value = sc->unspecified;
  58734. }
  58735. break;
  58736. case OP_ERROR_QUIT:
  58737. case OP_EVAL_DONE:
  58738. /* this is the "time to quit" operator */
  58739. return(sc->F);
  58740. break;
  58741. case OP_BARRIER:
  58742. case OP_CATCH_ALL:
  58743. case OP_CATCH:
  58744. case OP_CATCH_1:
  58745. case OP_CATCH_2:
  58746. break;
  58747. case OP_DEACTIVATE_GOTO:
  58748. call_exit_active(sc->args) = false; /* as we leave the call-with-exit body, deactivate the exiter */
  58749. break;
  58750. case OP_ERROR_HOOK_QUIT:
  58751. sc->error_hook = sc->code; /* restore old value */
  58752. /* now mimic the end of the normal error handler. Since this error hook evaluation can happen
  58753. * in an arbitrary s7_call nesting, we can't just return from the current evaluation --
  58754. * we have to jump to the original (top-level) call. Otherwise '#<unspecified> or whatever
  58755. * is simply treated as the (non-error) return value, and the higher level evaluations
  58756. * get confused.
  58757. */
  58758. stack_reset(sc);
  58759. sc->op = OP_ERROR_QUIT;
  58760. if (sc->longjmp_ok) longjmp(sc->goto_start, ERROR_QUIT_JUMP);
  58761. return(sc->value); /* not executed I hope */
  58762. case OP_GET_OUTPUT_STRING: /* from get-output-string -- return a new string */
  58763. sc->value = s7_make_string_with_length(sc, (const char *)port_data(sc->code), port_position(sc->code));
  58764. break;
  58765. case OP_GET_OUTPUT_STRING_1: /* from call-with-output-string and with-output-to-string -- return the port string directly */
  58766. if ((!is_output_port(sc->code)) ||
  58767. (port_is_closed(sc->code)))
  58768. simple_wrong_type_argument_with_type(sc, sc->with_output_to_string_symbol, sc->code, make_string_wrapper(sc, "an open string output port"));
  58769. if (port_position(sc->code) >= port_data_size(sc->code))
  58770. resize_port_data(sc->code, port_position(sc->code) + 1); /* need room for the trailing #\null */
  58771. sc->value = make_string_uncopied_with_length(sc, (char *)port_data(sc->code), port_position(sc->code));
  58772. string_value(sc->value)[port_position(sc->code)] = 0;
  58773. port_data(sc->code) = NULL;
  58774. port_data_size(sc->code) = 0;
  58775. port_needs_free(sc->code) = false;
  58776. /* fall through */
  58777. case OP_UNWIND_OUTPUT:
  58778. unwind_output_ex(sc);
  58779. break;
  58780. case OP_UNWIND_INPUT:
  58781. unwind_input_ex(sc);
  58782. break;
  58783. case OP_DYNAMIC_WIND:
  58784. if (dynamic_wind_ex(sc) == goto_APPLY) goto APPLY;
  58785. break;
  58786. /* -------------------------------- with-let --------------------------------
  58787. *
  58788. * the extra set! to pull in args, or fixup the outlet is annoying, but
  58789. * but with-let is hard to do right -- what if env is chained as in class/objects?
  58790. * also, currently a mock-let is an error -- perhaps add the method checks?
  58791. * but unless 'values, that would require a 'with-let method (it's not a function)
  58792. */
  58793. case OP_WITH_LET_S:
  58794. {
  58795. s7_pointer e;
  58796. e = find_symbol_checked(sc, car(sc->code));
  58797. if (e == sc->rootlet)
  58798. sc->envir = sc->nil;
  58799. else
  58800. {
  58801. s7_pointer p;
  58802. if (!is_let(e))
  58803. eval_type_error(sc, "with-let takes an environment argument: ~A", e);
  58804. set_with_let_let(e);
  58805. let_id(e) = ++sc->let_number;
  58806. sc->envir = e;
  58807. /* if the let in question has 10,000 names (e.g. *gtk*) this loop (which can't be avoided currently)
  58808. * will be noticeable in a few cases. So, instead of saying (with-let *gtk* ...) use something
  58809. * equivalent to (with-let (sublet *gtk*) ...) which is cleaner anyway. (In my timing tests, even
  58810. * when pounding on this one block, the loop only amounts to 1% of the time. Normally it's
  58811. * negligible).
  58812. */
  58813. for (p = let_slots(e); is_slot(p); p = next_slot(p))
  58814. {
  58815. s7_pointer sym;
  58816. sym = slot_symbol(p);
  58817. if (symbol_id(sym) != sc->let_number)
  58818. symbol_set_local(sym, sc->let_number, p);
  58819. }
  58820. }
  58821. sc->code = cdr(sc->code);
  58822. goto BEGIN1;
  58823. }
  58824. case OP_WITH_LET:
  58825. check_with_let(sc);
  58826. case OP_WITH_LET_UNCHECKED:
  58827. sc->value = car(sc->code);
  58828. if (!is_pair(sc->value))
  58829. {
  58830. if (is_symbol(sc->value))
  58831. sc->value = find_symbol_checked(sc, sc->value);
  58832. sc->code = cdr(sc->code);
  58833. if (!is_pair(sc->code))
  58834. {
  58835. if (!is_let(sc->value)) /* (with-let e abs) */
  58836. eval_type_error(sc, "with-let takes an environment argument: ~A", sc->value);
  58837. if (is_symbol(sc->code))
  58838. sc->value = s7_symbol_local_value(sc, sc->code, sc->value);
  58839. else sc->value = sc->code;
  58840. goto START;
  58841. }
  58842. /* else fall through */
  58843. }
  58844. else
  58845. {
  58846. push_stack(sc, OP_WITH_LET1, sc->nil, cdr(sc->code));
  58847. sc->code = sc->value; /* eval env arg */
  58848. goto EVAL;
  58849. }
  58850. case OP_WITH_LET1:
  58851. activate_let(sc);
  58852. goto BEGIN1;
  58853. case OP_WITH_BAFFLE:
  58854. if (!is_proper_list(sc, sc->code))
  58855. eval_error(sc, "with-baffle: unexpected dot? ~A", sc->code);
  58856. if ((!is_null(sc->code)) &&
  58857. (is_overlaid(sc->code)) &&
  58858. (has_opt_back(sc->code)))
  58859. pair_set_syntax_symbol(sc->code, sc->with_baffle_unchecked_symbol);
  58860. case OP_WITH_BAFFLE_UNCHECKED:
  58861. if (is_null(sc->code))
  58862. {
  58863. sc->value = sc->nil;
  58864. goto START;
  58865. }
  58866. new_frame(sc, sc->envir, sc->envir);
  58867. make_slot_1(sc, sc->envir, sc->baffle_symbol, make_baffle(sc));
  58868. goto BEGIN1;
  58869. /* -------------------------------- the reader -------------------------------- */
  58870. POP_READ_LIST:
  58871. /* push-stack OP_READ_LIST is always no_code and sc->op is always OP_READ_LIST (and not used), sc->envir is apparently not needed here
  58872. */
  58873. sc->stack_end -= 4;
  58874. sc->args = sc->stack_end[2];
  58875. READ_LIST:
  58876. case OP_READ_LIST: /* sc->args is sc->nil at first */
  58877. {
  58878. s7_pointer x;
  58879. new_cell(sc, x, T_PAIR);
  58880. set_car(x, sc->value);
  58881. set_cdr(x, sc->args);
  58882. sc->args = x;
  58883. }
  58884. case OP_READ_NEXT: /* this is 75% of the token calls, so expanding it saves lots of time */
  58885. {
  58886. int c;
  58887. s7_pointer pt;
  58888. pt = sc->input_port;
  58889. c = port_read_white_space(pt)(sc, pt);
  58890. READ_C:
  58891. switch (c)
  58892. {
  58893. case '(':
  58894. c = port_read_white_space(pt)(sc, pt); /* sc->tok = token(sc) */
  58895. switch (c)
  58896. {
  58897. case '(': sc->tok = TOKEN_LEFT_PAREN; break;
  58898. case ')': sc->value = sc->nil; goto READ_LIST; /* was tok = TOKEN_RIGHT_PAREN */
  58899. case '.': sc->tok = read_dot(sc, pt); break;
  58900. case '\'': sc->tok = TOKEN_QUOTE; break;
  58901. case ';': sc->tok = port_read_semicolon(pt)(sc, pt); break;
  58902. case '"': sc->tok = TOKEN_DOUBLE_QUOTE; break;
  58903. case '`': sc->tok = TOKEN_BACK_QUOTE; break;
  58904. case ',': sc->tok = read_comma(sc, pt); break;
  58905. case '#': sc->tok = read_sharp(sc, pt); break;
  58906. case '\0': case EOF: sc->tok = TOKEN_EOF; break;
  58907. default:
  58908. {
  58909. s7_pointer x;
  58910. sc->strbuf[0] = c;
  58911. push_stack_no_code(sc, OP_READ_LIST, sc->args);
  58912. check_stack_size(sc);
  58913. sc->value = port_read_name(pt)(sc, pt);
  58914. new_cell(sc, x, T_PAIR);
  58915. set_car(x, sc->value);
  58916. set_cdr(x, sc->nil);
  58917. sc->args = x;
  58918. c = port_read_white_space(pt)(sc, pt);
  58919. goto READ_C;
  58920. }
  58921. }
  58922. if (sc->tok == TOKEN_ATOM)
  58923. {
  58924. s7_pointer x;
  58925. push_stack_no_code(sc, OP_READ_LIST, sc->args);
  58926. check_stack_size(sc);
  58927. sc->value = port_read_name(pt)(sc, pt);
  58928. new_cell(sc, x, T_PAIR);
  58929. set_car(x, sc->value);
  58930. set_cdr(x, sc->nil);
  58931. sc->args = x;
  58932. c = port_read_white_space(pt)(sc, pt);
  58933. goto READ_C;
  58934. }
  58935. if (sc->tok == TOKEN_RIGHT_PAREN)
  58936. {
  58937. sc->value = sc->nil;
  58938. goto READ_LIST;
  58939. }
  58940. if (sc->tok == TOKEN_DOT)
  58941. {
  58942. do {c = inchar(pt);} while ((c != ')') && (c != EOF));
  58943. return(read_error(sc, "stray dot after '('?")); /* (car '( . )) */
  58944. }
  58945. if (sc->tok == TOKEN_EOF)
  58946. return(missing_close_paren_error(sc));
  58947. push_stack_no_code(sc, OP_READ_LIST, sc->args);
  58948. push_stack_no_code(sc, OP_READ_LIST, sc->nil);
  58949. check_stack_size(sc);
  58950. sc->value = read_expression(sc);
  58951. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  58952. goto START;
  58953. case ')':
  58954. sc->tok = TOKEN_RIGHT_PAREN;
  58955. break;
  58956. case '.':
  58957. sc->tok = read_dot(sc, pt); /* dot or atom */
  58958. break;
  58959. case '\'':
  58960. sc->tok = TOKEN_QUOTE;
  58961. push_stack_no_code(sc, OP_READ_LIST, sc->args);
  58962. sc->value = read_expression(sc);
  58963. goto START;
  58964. case ';':
  58965. sc->tok = port_read_semicolon(pt)(sc, pt);
  58966. break;
  58967. case '"':
  58968. sc->tok = TOKEN_DOUBLE_QUOTE;
  58969. sc->value = read_string_constant(sc, pt);
  58970. if (sc->value == sc->F) /* can happen if input code ends in the middle of a string */
  58971. return(string_read_error(sc, "end of input encountered while in a string"));
  58972. if (sc->value == sc->T)
  58973. return(read_error(sc, "unknown backslash usage -- perhaps you meant two backslashes?"));
  58974. goto READ_LIST;
  58975. case '`':
  58976. sc->tok = TOKEN_BACK_QUOTE;
  58977. push_stack_no_code(sc, OP_READ_LIST, sc->args);
  58978. sc->value = read_expression(sc);
  58979. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  58980. goto START; /* read_unquote */
  58981. case ',':
  58982. sc->tok = read_comma(sc, pt); /* at_mark or comma */
  58983. push_stack_no_code(sc, OP_READ_LIST, sc->args);
  58984. sc->value = read_expression(sc);
  58985. goto START; /* read_unquote */
  58986. case '#':
  58987. sc->tok = read_sharp(sc, pt);
  58988. break;
  58989. case '\0':
  58990. case EOF:
  58991. return(missing_close_paren_error(sc));
  58992. default:
  58993. sc->strbuf[0] = c;
  58994. sc->value = port_read_name(pt)(sc, pt);
  58995. goto READ_LIST;
  58996. }
  58997. }
  58998. READ_TOK:
  58999. switch (sc->tok)
  59000. {
  59001. case TOKEN_RIGHT_PAREN:
  59002. /* sc->args can't be null here */
  59003. sc->value = safe_reverse_in_place(sc, sc->args);
  59004. if (is_symbol(car(sc->value)))
  59005. {
  59006. pair_set_line(sc->value, remember_location(port_line_number(sc->input_port), port_file_number(sc->input_port)));
  59007. set_has_line_number(sc->value); /* sc->input_port above can't be nil(?) -- it falls back on stdin now */
  59008. if ((is_expansion(car(sc->value))) &&
  59009. (expansion_ex(sc) == goto_APPLY))
  59010. goto APPLY;
  59011. if (is_pair(cdr(sc->value)))
  59012. {
  59013. set_opt_back(sc->value);
  59014. set_overlay(cdr(sc->value));
  59015. }
  59016. }
  59017. break;
  59018. case TOKEN_EOF: /* can't happen, I believe */
  59019. return(missing_close_paren_error(sc));
  59020. case TOKEN_ATOM:
  59021. sc->value = port_read_name(sc->input_port)(sc, sc->input_port);
  59022. goto READ_LIST;
  59023. case TOKEN_SHARP_CONST:
  59024. sc->value = port_read_sharp(sc->input_port)(sc, sc->input_port);
  59025. if (is_null(sc->value))
  59026. return(read_error(sc, "undefined # expression"));
  59027. if (sc->value == sc->no_value)
  59028. {
  59029. /* (set! *#readers* (cons (cons #\; (lambda (s) (read) (values))) *#readers*))
  59030. * (+ 1 #;(* 2 3) 4)
  59031. * so we need to get the next token, act on it without any assumptions about read list
  59032. */
  59033. sc->tok = token(sc);
  59034. goto READ_TOK;
  59035. }
  59036. goto READ_LIST;
  59037. case TOKEN_DOUBLE_QUOTE:
  59038. sc->value = read_string_constant(sc, sc->input_port);
  59039. if (sc->value == sc->F) /* can happen if input code ends in the middle of a string */
  59040. return(string_read_error(sc, "end of input encountered while in a string"));
  59041. if (sc->value == sc->T)
  59042. return(read_error(sc, "unknown backslash usage -- perhaps you meant two backslashes?"));
  59043. goto READ_LIST;
  59044. case TOKEN_DOT:
  59045. push_stack_no_code(sc, OP_READ_DOT, sc->args);
  59046. sc->tok = token(sc);
  59047. sc->value = read_expression(sc);
  59048. break;
  59049. default:
  59050. /* by far the main case here is TOKEN_LEFT_PAREN, but it doesn't save anything to move it to this level */
  59051. push_stack_no_code(sc, OP_READ_LIST, sc->args);
  59052. sc->value = read_expression(sc);
  59053. /* check for op_read_list here and explicit pop_stack are slower */
  59054. break;
  59055. }
  59056. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  59057. break;
  59058. case OP_READ_DOT:
  59059. if (token(sc) != TOKEN_RIGHT_PAREN)
  59060. {
  59061. back_up_stack(sc);
  59062. read_error(sc, "stray dot?"); /* (+ 1 . 2 3) or (list . ) */
  59063. }
  59064. /* args = previously read stuff, value = thing just after the dot and before the ')':
  59065. * (list 1 2 . 3)
  59066. * value: 3, args: (2 1 list)
  59067. * '(1 . 2)
  59068. * value: 2, args: (1)
  59069. *
  59070. * but we also get here in a lambda arg list:
  59071. * (lambda (a b . c) #f)
  59072. * value: c, args: (b a)
  59073. *
  59074. * so we have to leave any error checks until later, I guess
  59075. * -- in eval_args1, if we end with non-pair-not-nil then
  59076. * something is fishy
  59077. */
  59078. sc->value = reverse_in_place(sc, sc->value, sc->args);
  59079. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  59080. break;
  59081. case OP_READ_QUOTE:
  59082. /* can't check for sc->value = sc->nil here because we want ''() to be different from '() */
  59083. sc->value = list_2(sc, sc->quote_symbol, sc->value);
  59084. set_opt_back(sc->value);
  59085. set_overlay(cdr(sc->value));
  59086. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  59087. break;
  59088. case OP_READ_QUASIQUOTE:
  59089. /* this was pushed when the backquote was seen, then eventually we popped back to it */
  59090. sc->value = g_quasiquote_1(sc, sc->value);
  59091. /* doing quasiquote at read time means there are minor inconsistencies in
  59092. * various combinations or quote/' and quasiquote/`. A quoted ` will expand
  59093. * but quoted quasiquote will not (` can't be redefined, but quasiquote can).
  59094. * see s7test.scm for examples.
  59095. */
  59096. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  59097. break;
  59098. case OP_READ_VECTOR:
  59099. if (!is_proper_list(sc, sc->value)) /* #(1 . 2) */
  59100. return(read_error(sc, "vector constant data is not a proper list"));
  59101. if (sc->args == small_int(1)) /* sc->args was sc->w earlier from read_sharp */
  59102. sc->value = g_vector(sc, sc->value);
  59103. else sc->value = g_multivector(sc, s7_integer(sc->args), sc->value);
  59104. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  59105. break;
  59106. case OP_READ_BYTE_VECTOR:
  59107. if (!is_proper_list(sc, sc->value)) /* #u8(1 . 2) */
  59108. return(read_error(sc, "byte-vector constant data is not a proper list"));
  59109. sc->value = g_byte_vector(sc, sc->value);
  59110. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  59111. break;
  59112. case OP_READ_UNQUOTE:
  59113. /* here if sc->value is a constant, the unquote is pointless (should we complain?) */
  59114. if ((is_pair(sc->value)) ||
  59115. (is_symbol(sc->value)))
  59116. sc->value = list_2(sc, sc->unquote_symbol, sc->value);
  59117. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  59118. break;
  59119. case OP_READ_APPLY_VALUES:
  59120. if (is_symbol(sc->value))
  59121. {
  59122. s7_pointer lst;
  59123. lst = list_2(sc, sc->qq_apply_values_function, sc->value);
  59124. set_unsafe_optimize_op(lst, HOP_C_S);
  59125. set_c_function(lst, sc->qq_apply_values_function);
  59126. sc->value = list_2(sc, sc->unquote_symbol, lst);
  59127. }
  59128. else sc->value = list_2(sc, sc->unquote_symbol, list_2(sc, sc->qq_apply_values_function, sc->value));
  59129. if (main_stack_op(sc) == OP_READ_LIST) goto POP_READ_LIST;
  59130. break;
  59131. default:
  59132. fprintf(stderr, "unknown operator: " INT_FORMAT " in %s\n", sc->op, DISPLAY(current_code(sc)));
  59133. #if DEBUGGING
  59134. fprintf(stderr, "stack size: %u\n", sc->stack_size);
  59135. if (sc->stack_end < sc->stack_start)
  59136. fprintf(stderr, "%sstack underflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
  59137. if (sc->stack_end >= sc->stack_start + sc->stack_size)
  59138. fprintf(stderr, "%sstack overflow%s\n", BOLD_TEXT, UNBOLD_TEXT);
  59139. abort();
  59140. #endif
  59141. return(sc->F);
  59142. }
  59143. }
  59144. return(sc->F);
  59145. }
  59146. #if WITH_GCC
  59147. #undef new_cell
  59148. #if (!DEBUGGING)
  59149. #define new_cell(Sc, Obj, Type) \
  59150. do { \
  59151. if (Sc->free_heap_top <= Sc->free_heap_trigger) try_to_call_gc(Sc); \
  59152. Obj = (*(--(Sc->free_heap_top))); \
  59153. set_type(Obj, Type); \
  59154. } while (0)
  59155. #else
  59156. #define new_cell(Sc, Obj, Type) \
  59157. do { \
  59158. if ((Sc->free_heap_top <= Sc->free_heap_trigger) || (for_any_other_reason(sc, __LINE__))) {last_gc_line = __LINE__; last_gc_func = __func__; try_to_call_gc(Sc);} \
  59159. Obj = (*(--(Sc->free_heap_top))); \
  59160. Obj->alloc_line = __LINE__; Obj->alloc_func = __func__; \
  59161. set_type(Obj, Type); \
  59162. } while (0)
  59163. #endif
  59164. #endif
  59165. /* needed in s7_gmp_init and s7_init, initialized in s7_init before we get to gmp */
  59166. static s7_pointer pl_bt, pl_p, pl_bc, pcl_bc, pcl_bs, pl_bn, pl_sf, pcl_bt, pcl_i, pcl_t, pcl_r, pcl_n, pcl_s, pcl_v, pcl_f, pcl_c, pl_tl;
  59167. /* -------------------------------- multiprecision arithmetic -------------------------------- */
  59168. #if WITH_GMP
  59169. static mp_prec_t mpc_precision = DEFAULT_BIGNUM_PRECISION; /* global for libs */
  59170. static mp_prec_t mpc_set_default_precision(mp_prec_t prec) {mpc_precision = prec; return(prec);}
  59171. #define mpc_init(Z) mpc_init2(Z, mpc_precision)
  59172. static void mpc_init_set(mpc_ptr z, mpc_ptr y, mpc_rnd_t rnd)
  59173. {
  59174. mpc_init(z);
  59175. mpc_set(z, y, rnd);
  59176. }
  59177. mpfr_t *s7_big_real(s7_pointer x) {return(&big_real(x));}
  59178. mpz_t *s7_big_integer(s7_pointer x) {return(&big_integer(x));}
  59179. mpq_t *s7_big_ratio(s7_pointer x) {return(&big_ratio(x));}
  59180. mpc_t *s7_big_complex(s7_pointer x) {return(&big_complex(x));}
  59181. static char *mpfr_to_string(mpfr_t val, int radix)
  59182. {
  59183. char *str, *tmp, *str1;
  59184. mp_exp_t expptr;
  59185. int i, len, ep;
  59186. if (mpfr_zero_p(val))
  59187. return(copy_string("0.0"));
  59188. if (mpfr_nan_p(val))
  59189. return(copy_string("nan.0"));
  59190. if (mpfr_inf_p(val))
  59191. {
  59192. if (mpfr_signbit(val) == 0)
  59193. return(copy_string("inf.0"));
  59194. return(copy_string("-inf.0"));
  59195. }
  59196. str1 = mpfr_get_str(NULL, &expptr, radix, 0, val, GMP_RNDN);
  59197. /* 0 -> full precision, but it's too hard to make this look like C formatted output.
  59198. * :(format #f "~,3F" pi)
  59199. * "3.141592653589793238462643383279502884195E0"
  59200. * :(format #f "~,3F" 1.1234567890123) ; not a bignum
  59201. * "1.123"
  59202. * :(format #f "~,3F" 1.12345678901234) ; a bignum
  59203. * "1.123456789012339999999999999999999999999E0"
  59204. * but we don't know the exponent or the string length until after we call mpfr_get_str.
  59205. */
  59206. str = str1;
  59207. ep = (int)expptr;
  59208. len = safe_strlen(str);
  59209. /* remove trailing 0's */
  59210. for (i = len - 1; i > 3; i--)
  59211. if (str[i] != '0')
  59212. break;
  59213. if (i < len - 1)
  59214. str[i + 1] = '\0';
  59215. len += 64;
  59216. tmp = (char *)malloc(len * sizeof(char));
  59217. if (str[0] == '-')
  59218. snprintf(tmp, len, "-%c.%s%c%d", str[1], (char *)(str + 2), (radix <= 10) ? 'E' : '@', ep - 1);
  59219. else snprintf(tmp, len, "%c.%s%c%d", str[0], (char *)(str + 1), (radix <= 10) ? 'E' : '@', ep - 1);
  59220. mpfr_free_str(str1);
  59221. return(tmp);
  59222. }
  59223. static char *mpc_to_string(mpc_t val, int radix, use_write_t use_write)
  59224. {
  59225. char *rl, *im, *tmp;
  59226. int len;
  59227. mpfr_t a, b;
  59228. mpfr_init(a);
  59229. mpc_real(a, val, GMP_RNDN);
  59230. rl = mpfr_to_string(a, radix);
  59231. mpfr_init(b);
  59232. mpc_imag(b, val, GMP_RNDN);
  59233. im = mpfr_to_string(b, radix);
  59234. len = safe_strlen(rl) + safe_strlen(im) + 128;
  59235. tmp = (char *)malloc(len * sizeof(char));
  59236. if (use_write == USE_READABLE_WRITE)
  59237. snprintf(tmp, len, "(complex %s %s)", rl, im);
  59238. else snprintf(tmp, len, "%s%s%si", rl, (im[0] == '-') ? "" : "+", im);
  59239. free(rl);
  59240. free(im);
  59241. return(tmp);
  59242. }
  59243. static char *big_number_to_string_with_radix(s7_pointer p, int radix, int width, int *nlen, use_write_t use_write)
  59244. {
  59245. char *str = NULL;
  59246. switch (type(p))
  59247. {
  59248. case T_BIG_INTEGER: str = mpz_get_str(NULL, radix, big_integer(p)); break;
  59249. case T_BIG_RATIO: str = mpq_get_str(NULL, radix, big_ratio(p)); break;
  59250. case T_BIG_REAL: str = mpfr_to_string(big_real(p), radix); break;
  59251. default: str = mpc_to_string(big_complex(p), radix, use_write); break;
  59252. }
  59253. if (width > 0)
  59254. {
  59255. int len;
  59256. len = safe_strlen(str);
  59257. if (width > len)
  59258. {
  59259. int spaces;
  59260. str = (char *)realloc(str, (width + 1) * sizeof(char));
  59261. spaces = width - len;
  59262. str[width] = '\0';
  59263. memmove((void *)(str + spaces), (void *)str, len);
  59264. memset((void *)str, (int)' ', spaces);
  59265. (*nlen) = width;
  59266. }
  59267. else (*nlen) = len;
  59268. }
  59269. else (*nlen) = safe_strlen(str);
  59270. return(str);
  59271. }
  59272. static bool s7_is_one_or_big_one(s7_pointer p)
  59273. {
  59274. bool result = false;
  59275. if (!is_big_number(p))
  59276. return(s7_is_one(p));
  59277. if (is_t_big_integer(p))
  59278. {
  59279. mpz_t n;
  59280. mpz_init_set_si(n, 1);
  59281. result = (mpz_cmp(n, big_integer(p)) == 0);
  59282. mpz_clear(n);
  59283. }
  59284. else
  59285. {
  59286. if (is_t_big_real(p))
  59287. {
  59288. mpfr_t n;
  59289. mpfr_init_set_d(n, 1.0, GMP_RNDN);
  59290. result = (mpfr_cmp(n, big_real(p)) == 0);
  59291. mpfr_clear(n);
  59292. }
  59293. }
  59294. return(result);
  59295. }
  59296. static s7_pointer string_to_big_integer(s7_scheme *sc, const char *str, int radix)
  59297. {
  59298. s7_pointer x;
  59299. new_cell(sc, x, T_BIG_INTEGER);
  59300. add_bigint(sc, x);
  59301. mpz_init_set_str(big_integer(x), (str[0] == '+') ? (const char *)(str + 1) : str, radix);
  59302. return(x);
  59303. }
  59304. static s7_pointer mpz_to_big_integer(s7_scheme *sc, mpz_t val)
  59305. {
  59306. s7_pointer x;
  59307. new_cell(sc, x, T_BIG_INTEGER);
  59308. add_bigint(sc, x);
  59309. mpz_init_set(big_integer(x), val);
  59310. return(x);
  59311. }
  59312. s7_pointer s7_make_big_integer(s7_scheme *sc, mpz_t *val)
  59313. {
  59314. return(mpz_to_big_integer(sc, *val));
  59315. }
  59316. static s7_pointer string_to_big_ratio(s7_scheme *sc, const char *str, int radix)
  59317. {
  59318. s7_pointer x;
  59319. mpq_t n;
  59320. mpq_init(n);
  59321. mpq_set_str(n, str, radix);
  59322. mpq_canonicalize(n);
  59323. if (mpz_cmp_ui(mpq_denref(n), 1) == 0)
  59324. x = mpz_to_big_integer(sc, mpq_numref(n));
  59325. else
  59326. {
  59327. new_cell(sc, x, T_BIG_RATIO);
  59328. add_bigratio(sc, x);
  59329. mpq_init(big_ratio(x));
  59330. mpq_set_num(big_ratio(x), mpq_numref(n));
  59331. mpq_set_den(big_ratio(x), mpq_denref(n));
  59332. }
  59333. mpq_clear(n);
  59334. return(x);
  59335. }
  59336. static s7_pointer mpq_to_big_ratio(s7_scheme *sc, mpq_t val)
  59337. {
  59338. s7_pointer x;
  59339. new_cell(sc, x, T_BIG_RATIO);
  59340. add_bigratio(sc, x);
  59341. mpq_init(big_ratio(x));
  59342. mpq_set_num(big_ratio(x), mpq_numref(val));
  59343. mpq_set_den(big_ratio(x), mpq_denref(val));
  59344. return(x);
  59345. }
  59346. s7_pointer s7_make_big_ratio(s7_scheme *sc, mpq_t *val)
  59347. {
  59348. return(mpq_to_big_ratio(sc, *val));
  59349. }
  59350. static s7_pointer mpz_to_big_ratio(s7_scheme *sc, mpz_t val)
  59351. {
  59352. s7_pointer x;
  59353. new_cell(sc, x, T_BIG_RATIO);
  59354. add_bigratio(sc, x);
  59355. mpq_init(big_ratio(x));
  59356. mpq_set_num(big_ratio(x), val);
  59357. return(x);
  59358. }
  59359. static s7_pointer make_big_integer_or_ratio(s7_scheme *sc, s7_pointer z)
  59360. {
  59361. if (mpz_cmp_ui(mpq_denref(big_ratio(z)), 1) == 0)
  59362. return(mpz_to_big_integer(sc, mpq_numref(big_ratio(z))));
  59363. return(z);
  59364. }
  59365. static s7_pointer string_to_big_real(s7_scheme *sc, const char *str, int radix)
  59366. {
  59367. s7_pointer x;
  59368. new_cell(sc, x, T_BIG_REAL);
  59369. add_bigreal(sc, x);
  59370. mpfr_init_set_str(big_real(x), str, radix, GMP_RNDN);
  59371. return(x);
  59372. }
  59373. static void mpz_init_set_s7_int(mpz_t n, s7_int uval);
  59374. static s7_pointer s7_number_to_big_real(s7_scheme *sc, s7_pointer p)
  59375. {
  59376. s7_pointer x;
  59377. new_cell(sc, x, T_BIG_REAL);
  59378. add_bigreal(sc, x);
  59379. switch (type(p))
  59380. {
  59381. case T_INTEGER:
  59382. if (sizeof(s7_int) == sizeof(long int))
  59383. mpfr_init_set_si(big_real(x), integer(p), GMP_RNDN);
  59384. else mpfr_init_set_ld(big_real(x), (long double)integer(p), GMP_RNDN);
  59385. break;
  59386. case T_RATIO:
  59387. /* here we can't use fraction(number(p)) even though that uses long double division because
  59388. * there are lots of long long int ratios that will still look the same.
  59389. * We have to do the actual bignum divide by hand.
  59390. */
  59391. {
  59392. mpq_t rat;
  59393. mpz_t n1, d1;
  59394. mpz_init_set_s7_int(n1, numerator(p));
  59395. mpz_init_set_s7_int(d1, denominator(p));
  59396. mpq_init(rat);
  59397. mpq_set_num(rat, n1);
  59398. mpq_set_den(rat, d1);
  59399. mpq_canonicalize(rat);
  59400. mpfr_init_set_q(big_real(x), rat, GMP_RNDN);
  59401. mpz_clear(n1);
  59402. mpz_clear(d1);
  59403. mpq_clear(rat);
  59404. }
  59405. break;
  59406. default:
  59407. mpfr_init_set_d(big_real(x), s7_real(p), GMP_RNDN);
  59408. break;
  59409. }
  59410. return(x);
  59411. }
  59412. static s7_pointer mpz_to_big_real(s7_scheme *sc, mpz_t val)
  59413. {
  59414. s7_pointer x;
  59415. new_cell(sc, x, T_BIG_REAL);
  59416. add_bigreal(sc, x);
  59417. mpfr_init_set_z(big_real(x), val, GMP_RNDN);
  59418. return(x);
  59419. }
  59420. static s7_pointer mpq_to_big_real(s7_scheme *sc, mpq_t val)
  59421. {
  59422. s7_pointer x;
  59423. new_cell(sc, x, T_BIG_REAL);
  59424. add_bigreal(sc, x);
  59425. mpfr_init_set_q(big_real(x), val, GMP_RNDN);
  59426. return(x);
  59427. }
  59428. static s7_pointer mpfr_to_big_real(s7_scheme *sc, mpfr_t val)
  59429. {
  59430. s7_pointer x;
  59431. new_cell(sc, x, T_BIG_REAL);
  59432. add_bigreal(sc, x);
  59433. mpfr_init_set(big_real(x), val, GMP_RNDN);
  59434. return(x);
  59435. }
  59436. s7_pointer s7_make_big_real(s7_scheme *sc, mpfr_t *val)
  59437. {
  59438. return(mpfr_to_big_real(sc, *val));
  59439. }
  59440. static s7_pointer big_pi(s7_scheme *sc)
  59441. {
  59442. s7_pointer x;
  59443. new_cell(sc, x, T_BIG_REAL);
  59444. add_bigreal(sc, x);
  59445. mpfr_init(big_real(x));
  59446. mpfr_const_pi(big_real(x), GMP_RNDN);
  59447. return(x);
  59448. }
  59449. static s7_pointer s7_number_to_big_complex(s7_scheme *sc, s7_pointer p)
  59450. {
  59451. s7_pointer x;
  59452. new_cell(sc, x, T_BIG_COMPLEX);
  59453. add_bignumber(sc, x);
  59454. mpc_init(big_complex(x));
  59455. switch (type(p))
  59456. {
  59457. case T_INTEGER:
  59458. if (sizeof(s7_int) == sizeof(long int))
  59459. mpc_set_si(big_complex(x), integer(p), MPC_RNDNN);
  59460. else mpc_set_d(big_complex(x), (double)integer(p), MPC_RNDNN);
  59461. break;
  59462. case T_RATIO:
  59463. /* can't use fraction here */
  59464. {
  59465. mpfr_t temp;
  59466. mpq_t rat;
  59467. mpz_t n1, d1;
  59468. mpz_init_set_s7_int(n1, numerator(p));
  59469. mpz_init_set_s7_int(d1, denominator(p));
  59470. mpq_init(rat);
  59471. mpq_set_num(rat, n1);
  59472. mpq_set_den(rat, d1);
  59473. mpq_canonicalize(rat);
  59474. mpfr_init_set_q(temp, rat, GMP_RNDN);
  59475. mpc_set_fr(big_complex(x), temp, MPC_RNDNN);
  59476. mpz_clear(n1);
  59477. mpz_clear(d1);
  59478. mpq_clear(rat);
  59479. mpfr_clear(temp);
  59480. }
  59481. break;
  59482. case T_REAL:
  59483. mpc_set_d(big_complex(x), s7_real(p), MPC_RNDNN);
  59484. break;
  59485. default:
  59486. mpc_set_d_d(big_complex(x), real_part(p), imag_part(p), MPC_RNDNN);
  59487. break;
  59488. }
  59489. return(x);
  59490. }
  59491. static s7_pointer make_big_real_or_complex(s7_scheme *sc, s7_pointer z)
  59492. {
  59493. double ipart;
  59494. ipart = mpfr_get_d(mpc_imagref(big_complex(z)), GMP_RNDN);
  59495. /* not mpfr_cmp_ui to 0 here because that misleads us when imag_part is NaN or inf */
  59496. if (ipart == 0.0)
  59497. return(mpfr_to_big_real(sc, mpc_realref(big_complex(z))));
  59498. return(z);
  59499. }
  59500. static s7_pointer mpz_to_big_complex(s7_scheme *sc, mpz_t val)
  59501. {
  59502. mpfr_t temp;
  59503. s7_pointer x;
  59504. new_cell(sc, x, T_BIG_COMPLEX);
  59505. add_bignumber(sc, x);
  59506. mpc_init(big_complex(x));
  59507. mpfr_init_set_z(temp, val, GMP_RNDN);
  59508. mpc_set_fr(big_complex(x), temp, MPC_RNDNN);
  59509. mpfr_clear(temp);
  59510. return(x);
  59511. }
  59512. static s7_pointer mpq_to_big_complex(s7_scheme *sc, mpq_t val)
  59513. {
  59514. mpfr_t temp;
  59515. s7_pointer x;
  59516. new_cell(sc, x, T_BIG_COMPLEX);
  59517. add_bignumber(sc, x);
  59518. mpc_init(big_complex(x));
  59519. mpfr_init_set_q(temp, val, GMP_RNDN);
  59520. mpc_set_fr(big_complex(x), temp, MPC_RNDNN);
  59521. mpfr_clear(temp);
  59522. return(x);
  59523. }
  59524. static s7_pointer mpfr_to_big_complex(s7_scheme *sc, mpfr_t val)
  59525. {
  59526. s7_pointer x;
  59527. new_cell(sc, x, T_BIG_COMPLEX);
  59528. add_bignumber(sc, x);
  59529. mpc_init(big_complex(x));
  59530. mpc_set_fr(big_complex(x), val, MPC_RNDNN);
  59531. return(x);
  59532. }
  59533. static s7_pointer mpc_to_big_complex(s7_scheme *sc, mpc_t val)
  59534. {
  59535. s7_pointer x;
  59536. new_cell(sc, x, T_BIG_COMPLEX);
  59537. add_bignumber(sc, x);
  59538. mpc_init(big_complex(x));
  59539. mpc_set(big_complex(x), val, MPC_RNDNN);
  59540. return(x);
  59541. }
  59542. s7_pointer s7_make_big_complex(s7_scheme *sc, mpc_t *val)
  59543. {
  59544. return(mpc_to_big_complex(sc, *val));
  59545. }
  59546. static s7_pointer make_big_complex(s7_scheme *sc, mpfr_t rl, mpfr_t im)
  59547. {
  59548. /* there is no mpc_get_str equivalent, so we need to split up str,
  59549. * use make_big_real to get the 2 halves, then mpc_init, then
  59550. * mpc_set_fr_fr.
  59551. */
  59552. s7_pointer x;
  59553. new_cell(sc, x, T_BIG_COMPLEX);
  59554. add_bignumber(sc, x);
  59555. mpc_init(big_complex(x));
  59556. mpc_set_fr_fr(big_complex(x), rl ,im, MPC_RNDNN);
  59557. return(x);
  59558. }
  59559. /* gmp.h mpz_init_set_si the "si" part is "signed long int", so in 64-bit machines, s7_int already fits (if it's long long int).
  59560. * I guess we can catch the 4-byte long int (since no configure script) by noticing that sizeof(s7_int) == sizeof(long int)?
  59561. */
  59562. static void mpz_init_set_s7_int(mpz_t n, s7_int uval)
  59563. {
  59564. if (sizeof(s7_int) == sizeof(long int))
  59565. mpz_init_set_si(n, uval);
  59566. else
  59567. {
  59568. /* long long int to gmp mpz_t */
  59569. bool need_sign;
  59570. long long int val;
  59571. val = (long long int)uval;
  59572. /* handle one special case (sigh) */
  59573. if (val == s7_int_min)
  59574. mpz_init_set_str(n, "-9223372036854775808", 10);
  59575. else
  59576. {
  59577. need_sign = (val < 0);
  59578. if (need_sign) val = -val;
  59579. mpz_init_set_si(n, val >> 32);
  59580. mpz_mul_2exp(n, n, 32);
  59581. mpz_add_ui(n, n, (unsigned int)(val & 0xffffffff));
  59582. if (need_sign) mpz_neg(n, n);
  59583. }
  59584. }
  59585. }
  59586. static s7_pointer s7_int_to_big_integer(s7_scheme *sc, s7_int val)
  59587. {
  59588. s7_pointer x;
  59589. new_cell(sc, x, T_BIG_INTEGER);
  59590. add_bigint(sc, x);
  59591. mpz_init_set_s7_int(big_integer(x), val);
  59592. return(x);
  59593. }
  59594. static s7_int big_integer_to_s7_int(mpz_t n)
  59595. {
  59596. long long int high, low;
  59597. mpz_t x;
  59598. bool need_sign = false;
  59599. if (mpz_fits_slong_p(n))
  59600. return(mpz_get_si(n));
  59601. if ((hidden_sc->safety > 0) &&
  59602. (sizeof(s7_int) == sizeof(long int)))
  59603. {
  59604. char *str;
  59605. str = mpz_get_str(NULL, 10, n);
  59606. s7_warn(hidden_sc, 256, "can't convert %s to s7_int\n", str);
  59607. free(str);
  59608. }
  59609. mpz_init_set(x, n);
  59610. if (mpz_cmp_ui(x, 0) < 0)
  59611. {
  59612. need_sign = true;
  59613. mpz_neg(x, x);
  59614. }
  59615. low = mpz_get_ui(x);
  59616. if (low == s7_int_min)
  59617. return(s7_int_min);
  59618. mpz_fdiv_q_2exp(x, x, 32);
  59619. high = mpz_get_ui(x);
  59620. mpz_clear(x);
  59621. if (need_sign)
  59622. return(-(low + (high << 32)));
  59623. return(low + (high << 32));
  59624. }
  59625. static mpq_t *s7_ints_to_mpq(s7_int num, s7_int den)
  59626. {
  59627. /* den here always comes from denominator(x) so it is not negative */
  59628. mpq_t *n;
  59629. n = (mpq_t *)malloc(sizeof(mpq_t));
  59630. mpq_init(*n);
  59631. if (sizeof(s7_int) == sizeof(long int))
  59632. mpq_set_si(*n, num, den);
  59633. else
  59634. {
  59635. mpz_t n1, d1;
  59636. mpz_init_set_s7_int(n1, num);
  59637. mpz_init_set_s7_int(d1, den);
  59638. mpq_set_num(*n, n1);
  59639. mpq_set_den(*n, d1);
  59640. mpq_canonicalize(*n);
  59641. mpz_clear(n1);
  59642. mpz_clear(d1);
  59643. }
  59644. return(n);
  59645. }
  59646. static mpfr_t *s7_double_to_mpfr(s7_double val)
  59647. {
  59648. mpfr_t *n;
  59649. n = (mpfr_t *)malloc(sizeof(mpfr_t));
  59650. mpfr_init_set_d(*n, val, GMP_RNDN);
  59651. return(n);
  59652. }
  59653. static mpc_t *s7_doubles_to_mpc(s7_double rl, s7_double im)
  59654. {
  59655. mpc_t *n;
  59656. n = (mpc_t *)malloc(sizeof(mpc_t));
  59657. mpc_init(*n);
  59658. mpc_set_d_d(*n, rl, im, MPC_RNDNN);
  59659. return(n);
  59660. }
  59661. static s7_pointer s7_ratio_to_big_ratio(s7_scheme *sc, s7_int num, s7_int den)
  59662. {
  59663. /* den here always comes from denominator(x) or some positive constant so it is not negative */
  59664. s7_pointer x;
  59665. new_cell(sc, x, T_BIG_RATIO);
  59666. add_bigratio(sc, x);
  59667. mpq_init(big_ratio(x));
  59668. if (sizeof(s7_int) == sizeof(long int))
  59669. mpq_set_si(big_ratio(x), num, den);
  59670. else
  59671. {
  59672. mpz_t n1, d1;
  59673. mpz_init_set_s7_int(n1, num);
  59674. mpz_init_set_s7_int(d1, den);
  59675. mpq_set_num(big_ratio(x), n1);
  59676. mpq_set_den(big_ratio(x), d1);
  59677. mpq_canonicalize(big_ratio(x));
  59678. mpz_clear(n1);
  59679. mpz_clear(d1);
  59680. }
  59681. return(x);
  59682. }
  59683. static bool big_numbers_are_eqv(s7_pointer a, s7_pointer b)
  59684. {
  59685. bool result;
  59686. /* either or both can be big here, but not neither */
  59687. if (s7_is_integer(a))
  59688. {
  59689. mpz_t a1, b1;
  59690. if (!(s7_is_integer(b))) return(false);
  59691. if ((is_big_number(a)) && (is_big_number(b)))
  59692. return(mpz_cmp(big_integer(a), big_integer(b)) == 0);
  59693. if (is_big_number(a))
  59694. mpz_init_set(a1, big_integer(a));
  59695. else mpz_init_set_s7_int(a1, s7_integer(a));
  59696. if (is_big_number(b))
  59697. mpz_init_set(b1, big_integer(b));
  59698. else mpz_init_set_s7_int(b1, s7_integer(b));
  59699. result = (mpz_cmp(a1, b1) == 0);
  59700. mpz_clear(a1);
  59701. mpz_clear(b1);
  59702. return(result);
  59703. }
  59704. if (s7_is_ratio(a))
  59705. {
  59706. mpq_t *a1, *b1;
  59707. if (!s7_is_ratio(b)) return(false);
  59708. if ((is_big_number(a)) && (is_big_number(b)))
  59709. return(mpq_cmp(big_ratio(a), big_ratio(b)) == 0);
  59710. if (is_big_number(a))
  59711. a1 = &big_ratio(a);
  59712. else a1 = s7_ints_to_mpq(numerator(a), denominator(a));
  59713. if (is_big_number(b))
  59714. b1 = &big_ratio(b);
  59715. else b1 = s7_ints_to_mpq(numerator(b), denominator(b));
  59716. result = (mpq_cmp(*a1, *b1) == 0);
  59717. if (!is_big_number(a))
  59718. {
  59719. mpq_clear(*a1);
  59720. free(a1);
  59721. }
  59722. if (!is_big_number(b))
  59723. {
  59724. mpq_clear(*b1);
  59725. free(b1);
  59726. }
  59727. return(result);
  59728. }
  59729. if (s7_is_real(a))
  59730. {
  59731. mpfr_t *a1, *b1;
  59732. /* s7_is_real is not finicky enough here -- (eqv? 1.0 1) should return #f */
  59733. if (is_big_number(b))
  59734. {
  59735. if (type(b) != T_BIG_REAL)
  59736. return(false);
  59737. }
  59738. else
  59739. {
  59740. if (type(b) != T_REAL)
  59741. return(false);
  59742. }
  59743. if ((is_big_number(a)) && (is_big_number(b)))
  59744. return(mpfr_equal_p(big_real(a), big_real(b)));
  59745. if (is_big_number(a))
  59746. a1 = &big_real(a);
  59747. else a1 = s7_double_to_mpfr(s7_real(a));
  59748. if (is_big_number(b))
  59749. b1 = &big_real(b);
  59750. else b1 = s7_double_to_mpfr(s7_real(b));
  59751. result = (mpfr_cmp(*a1, *b1) == 0);
  59752. if (!is_big_number(a))
  59753. {
  59754. mpfr_clear(*a1);
  59755. free(a1);
  59756. }
  59757. if (!is_big_number(b))
  59758. {
  59759. mpfr_clear(*b1);
  59760. free(b1);
  59761. }
  59762. return(result);
  59763. }
  59764. if (s7_is_complex(a))
  59765. {
  59766. mpc_t *a1, *b1;
  59767. /* s7_is_complex is not finicky enough here */
  59768. if ((type(b) != T_BIG_COMPLEX) &&
  59769. (type(b) != T_COMPLEX))
  59770. return(false);
  59771. /* (eqv? (bignum "1+i") 1+1i) */
  59772. if ((is_big_number(a)) && (is_big_number(b)))
  59773. return(mpc_cmp(big_complex(a), big_complex(b)) == 0);
  59774. if (is_big_number(a))
  59775. a1 = &big_complex(a);
  59776. else a1 = s7_doubles_to_mpc(real_part(a), imag_part(a));
  59777. if (is_big_number(b))
  59778. b1 = &big_complex(b);
  59779. else b1 = s7_doubles_to_mpc(real_part(b), imag_part(b));
  59780. result = (mpc_cmp(*a1, *b1) == 0);
  59781. if (!is_big_number(a))
  59782. {
  59783. mpc_clear(*a1);
  59784. free(a1);
  59785. }
  59786. if (!is_big_number(b))
  59787. {
  59788. mpc_clear(*b1);
  59789. free(b1);
  59790. }
  59791. return(result);
  59792. }
  59793. return(false);
  59794. }
  59795. static s7_pointer string_to_either_integer(s7_scheme *sc, const char *str, int radix)
  59796. {
  59797. s7_int val;
  59798. bool overflow = false;
  59799. val = string_to_integer(str, radix, &overflow);
  59800. if (!overflow)
  59801. return(make_integer(sc, val));
  59802. return(string_to_big_integer(sc, str, radix));
  59803. }
  59804. static s7_pointer string_to_either_ratio(s7_scheme *sc, const char *nstr, const char *dstr, int radix)
  59805. {
  59806. s7_int n, d;
  59807. bool overflow = false;
  59808. /* gmp segfaults if passed a bignum/0 so this needs to check first that
  59809. * the denominator is not 0 before letting gmp screw up. Also, if the
  59810. * first character is '+', gmp returns 0!
  59811. */
  59812. d = string_to_integer(dstr, radix, &overflow);
  59813. if (!overflow)
  59814. {
  59815. if (d == 0)
  59816. return(real_NaN);
  59817. n = string_to_integer(nstr, radix, &overflow);
  59818. if (!overflow)
  59819. return(s7_make_ratio(sc, n, d));
  59820. }
  59821. if (nstr[0] == '+')
  59822. return(string_to_big_ratio(sc, (const char *)(nstr + 1), radix));
  59823. return(string_to_big_ratio(sc, nstr, radix));
  59824. }
  59825. static s7_pointer string_to_either_real(s7_scheme *sc, const char *str, int radix)
  59826. {
  59827. bool overflow = false;
  59828. s7_double val;
  59829. val = string_to_double_with_radix((char *)str, radix, &overflow);
  59830. if (!overflow)
  59831. return(make_real(sc, val));
  59832. return(string_to_big_real(sc, str, radix));
  59833. }
  59834. static s7_pointer string_to_either_complex_1(s7_scheme *sc, char *q, char *slash1, char *ex1, bool has_dec_point1, int radix, s7_double *d_rl)
  59835. {
  59836. bool overflow = false;
  59837. /* there's a real problem here -- we don't want to promote s7_double .1 to a bignum because
  59838. * its low order digits are garbage, causing (rationalize .1 0) to return 3602879701896397/36028797018963968
  59839. * no matter what the bignum-precision. But we can't just fallback on gmp's reader because (for example)
  59840. * it reads 1/2+i or 1+0/0i as 1.0. Also format gets screwed up. And string->number signals an error
  59841. * where it should return #f. I wonder what to do.
  59842. */
  59843. if ((has_dec_point1) ||
  59844. (ex1))
  59845. {
  59846. (*d_rl) = string_to_double_with_radix(q, radix, &overflow);
  59847. if (overflow)
  59848. return(string_to_big_real(sc, q, radix));
  59849. }
  59850. else
  59851. {
  59852. if (slash1)
  59853. {
  59854. s7_int n, d;
  59855. /* q can include the slash and denominator */
  59856. n = string_to_integer(q, radix, &overflow);
  59857. if (overflow)
  59858. return(string_to_big_ratio(sc, q, radix));
  59859. else
  59860. {
  59861. d = string_to_integer(slash1, radix, &overflow);
  59862. if (!overflow)
  59863. (*d_rl) = (s7_double)n / (s7_double)d;
  59864. else return(string_to_big_ratio(sc, q, radix));
  59865. }
  59866. }
  59867. else
  59868. {
  59869. s7_int val;
  59870. val = string_to_integer(q, radix, &overflow);
  59871. if (overflow)
  59872. return(string_to_big_integer(sc, q, radix));
  59873. (*d_rl) = (s7_double)val;
  59874. }
  59875. }
  59876. if ((*d_rl) == -0.0) (*d_rl) = 0.0;
  59877. return(NULL);
  59878. }
  59879. static s7_pointer string_to_either_complex(s7_scheme *sc,
  59880. char *q, char *slash1, char *ex1, bool has_dec_point1,
  59881. char *plus, char *slash2, char *ex2, bool has_dec_point2,
  59882. int radix, int has_plus_or_minus)
  59883. {
  59884. /* this can be just about anything involving 2 real/ratio/int portions, +/- in between and 'i' at the end */
  59885. double d_rl = 0.0, d_im = 0.0;
  59886. s7_pointer p_rl = NULL, p_im = NULL, result;
  59887. mpfr_t m_rl, m_im;
  59888. p_rl = string_to_either_complex_1(sc, q, slash1, ex1, has_dec_point1, radix, &d_rl);
  59889. p_im = string_to_either_complex_1(sc, plus, slash2, ex2, has_dec_point2, radix, &d_im);
  59890. if (d_im == 0.0)
  59891. {
  59892. /* 1.0+0.0000000000000000000000000000i */
  59893. if ((!p_im) ||
  59894. (s7_is_zero(p_im)))
  59895. {
  59896. if (!p_rl)
  59897. return(make_real(sc, d_rl));
  59898. return(p_rl);
  59899. }
  59900. }
  59901. if ((!p_rl) && (!p_im))
  59902. return(s7_make_complex(sc, d_rl, (has_plus_or_minus == -1) ? (-d_im) : d_im));
  59903. if (p_rl)
  59904. mpfr_init_set(m_rl, big_real(promote_number(sc, T_BIG_REAL, p_rl)), GMP_RNDN);
  59905. else mpfr_init_set_d(m_rl, d_rl, GMP_RNDN);
  59906. if (p_im)
  59907. mpfr_init_set(m_im, big_real(promote_number(sc, T_BIG_REAL, p_im)), GMP_RNDN);
  59908. else mpfr_init_set_d(m_im, d_im, GMP_RNDN);
  59909. if (has_plus_or_minus == -1)
  59910. mpfr_neg(m_im, m_im, GMP_RNDN);
  59911. result = make_big_complex(sc, m_rl, m_im);
  59912. mpfr_clear(m_rl);
  59913. mpfr_clear(m_im);
  59914. return(result);
  59915. }
  59916. static int big_type_to_result_type(int cur_type, int next_type)
  59917. {
  59918. if ((cur_type == T_BIG_COMPLEX) ||
  59919. (cur_type == T_COMPLEX) ||
  59920. (next_type == T_BIG_COMPLEX))
  59921. return(T_BIG_COMPLEX);
  59922. if ((cur_type == T_BIG_REAL) ||
  59923. (cur_type == T_REAL) ||
  59924. (next_type == T_BIG_REAL))
  59925. return(T_BIG_REAL);
  59926. if ((cur_type == T_BIG_RATIO) ||
  59927. (cur_type == T_RATIO) ||
  59928. (next_type == T_BIG_RATIO))
  59929. return(T_BIG_RATIO);
  59930. return(T_BIG_INTEGER);
  59931. }
  59932. static int normal_type_to_result_type(int cur_type, int next_type)
  59933. {
  59934. if (cur_type > T_COMPLEX)
  59935. next_type += 4;
  59936. if (cur_type > next_type)
  59937. return(cur_type);
  59938. return(next_type);
  59939. }
  59940. static s7_pointer promote_number_1(s7_scheme *sc, int type, s7_pointer x, bool copy)
  59941. {
  59942. /* x can be any number -- need to convert it to the current result type */
  59943. switch (type)
  59944. {
  59945. case T_BIG_INTEGER:
  59946. if (is_big_number(x))
  59947. {
  59948. if (copy)
  59949. return(mpz_to_big_integer(sc, big_integer(x)));
  59950. return(x); /* can only be T_BIG_INTEGER here */
  59951. }
  59952. return(s7_int_to_big_integer(sc, s7_integer(x))); /* can only be integer here */
  59953. case T_BIG_RATIO:
  59954. if (is_big_number(x))
  59955. {
  59956. if (is_t_big_ratio(x))
  59957. {
  59958. if (copy)
  59959. return(mpq_to_big_ratio(sc, big_ratio(x)));
  59960. return(x);
  59961. }
  59962. return(mpz_to_big_ratio(sc, big_integer(x)));
  59963. }
  59964. if (is_t_integer(x))
  59965. return(s7_ratio_to_big_ratio(sc, integer(x), 1));
  59966. return(s7_ratio_to_big_ratio(sc, numerator(x), denominator(x)));
  59967. case T_BIG_REAL:
  59968. if (is_big_number(x))
  59969. {
  59970. if (is_t_big_real(x))
  59971. {
  59972. if (copy)
  59973. return(mpfr_to_big_real(sc, big_real(x)));
  59974. return(x);
  59975. }
  59976. if (is_t_big_ratio(x))
  59977. return(mpq_to_big_real(sc, big_ratio(x)));
  59978. return(mpz_to_big_real(sc, big_integer(x)));
  59979. }
  59980. return(s7_number_to_big_real(sc, x));
  59981. default:
  59982. if (is_big_number(x))
  59983. {
  59984. if (is_t_big_complex(x))
  59985. {
  59986. if (copy)
  59987. return(mpc_to_big_complex(sc, big_complex(x)));
  59988. return(x);
  59989. }
  59990. if (is_t_big_real(x))
  59991. return(mpfr_to_big_complex(sc, big_real(x)));
  59992. if (is_t_big_ratio(x))
  59993. return(mpq_to_big_complex(sc, big_ratio(x)));
  59994. return(mpz_to_big_complex(sc, big_integer(x)));
  59995. }
  59996. return(s7_number_to_big_complex(sc, x));
  59997. }
  59998. return(sc->nil);
  59999. }
  60000. static s7_pointer promote_number(s7_scheme *sc, int type, s7_pointer x)
  60001. {
  60002. return(promote_number_1(sc, type, x, false));
  60003. }
  60004. static s7_pointer to_big(s7_scheme *sc, s7_pointer x)
  60005. {
  60006. if (is_big_number(x))
  60007. return(x);
  60008. switch (type(x))
  60009. {
  60010. case T_INTEGER: return(s7_int_to_big_integer(sc, integer(x)));
  60011. case T_RATIO: return(s7_ratio_to_big_ratio(sc, numerator(x), denominator(x)));
  60012. case T_REAL: return(s7_number_to_big_real(sc, x));
  60013. default: return(s7_number_to_big_complex(sc, x));
  60014. }
  60015. }
  60016. static s7_pointer copy_and_promote_number(s7_scheme *sc, int type, s7_pointer x)
  60017. {
  60018. return(promote_number_1(sc, type, x, true));
  60019. }
  60020. void s7_vector_fill(s7_scheme *sc, s7_pointer vec, s7_pointer obj)
  60021. {
  60022. /* if the same bignum object is assigned to each element, different vector elements
  60023. * are actually the same -- we need to make a copy of obj for each one
  60024. */
  60025. if ((is_normal_vector(vec)) && (is_big_number(obj)))
  60026. {
  60027. int gc_loc;
  60028. s7_int i, len;
  60029. s7_pointer *tp;
  60030. len = vector_length(vec);
  60031. tp = (s7_pointer *)(vector_elements(vec));
  60032. /* we'll be calling new_cell below, hence the GC, so make sure the elements are markable,
  60033. * and the vector itself is GC protected (we can be called within make-vector).
  60034. */
  60035. gc_loc = s7_gc_protect(sc, vec);
  60036. vector_fill(sc, vec, sc->nil);
  60037. switch (type(obj))
  60038. {
  60039. case T_BIG_INTEGER: for (i = 0; i < len; i++) tp[i] = mpz_to_big_integer(sc, big_integer(obj)); break;
  60040. case T_BIG_RATIO: for (i = 0; i < len; i++) tp[i] = mpq_to_big_ratio(sc, big_ratio(obj)); break;
  60041. case T_BIG_REAL: for (i = 0; i < len; i++) tp[i] = mpfr_to_big_real(sc, big_real(obj)); break;
  60042. default: for (i = 0; i < len; i++) tp[i] = mpc_to_big_complex(sc, big_complex(obj)); break;
  60043. }
  60044. s7_gc_unprotect_at(sc, gc_loc);
  60045. }
  60046. else vector_fill(sc, vec, obj);
  60047. }
  60048. static s7_pointer big_bignum(s7_scheme *sc, s7_pointer args)
  60049. {
  60050. #define H_bignum "(bignum val (radix 10)) returns a multiprecision version of the string 'val'"
  60051. #define Q_bignum s7_make_signature(sc, 3, sc->is_bignum_symbol, sc->is_number_symbol, sc->is_integer_symbol)
  60052. s7_pointer p;
  60053. p = g_string_to_number_1(sc, args, sc->bignum_symbol);
  60054. if (is_false(sc, p)) /* (bignum "1/3.0") */
  60055. s7_error(sc, make_symbol(sc, "bignum-error"),
  60056. set_elist_2(sc, make_string_wrapper(sc, "bignum argument does not represent a number: ~S"), car(args)));
  60057. switch (type(p))
  60058. {
  60059. case T_INTEGER:
  60060. return(promote_number(sc, T_BIG_INTEGER, p));
  60061. case T_RATIO:
  60062. return(promote_number(sc, T_BIG_RATIO, p));
  60063. /* we can't use promote_number here because it propagates C-double inaccuracies
  60064. * (rationalize (bignum "0.1") 0) should return 1/10 not 3602879701896397/36028797018963968
  60065. */
  60066. case T_REAL:
  60067. if (is_NaN(real(p))) return(p);
  60068. return(string_to_big_real(sc, string_value(car(args)), (is_pair(cdr(args))) ? s7_integer(cadr(args)) : 10));
  60069. case T_COMPLEX:
  60070. return(promote_number(sc, T_BIG_COMPLEX, p));
  60071. default:
  60072. return(p);
  60073. }
  60074. }
  60075. bool s7_is_bignum(s7_pointer obj)
  60076. {
  60077. return(is_big_number(obj));
  60078. }
  60079. static s7_pointer big_is_bignum(s7_scheme *sc, s7_pointer args)
  60080. {
  60081. #define H_is_bignum "(bignum? obj) returns #t if obj is a multiprecision number."
  60082. #define Q_is_bignum pl_bt
  60083. return(s7_make_boolean(sc, is_big_number(car(args))));
  60084. }
  60085. #define get_result_type(Sc, Type, P) \
  60086. ((is_number(P)) ? normal_type_to_result_type(Type, type(p)) : ((is_big_number(P)) ? big_type_to_result_type(Type, type(p)) : result_type_via_method(Sc, Type, P)))
  60087. static int result_type_via_method(s7_scheme *sc, int result_type, s7_pointer p)
  60088. {
  60089. s7_pointer f;
  60090. if (!has_methods(p)) return(-1);
  60091. f = find_method(sc, find_let(sc, p), sc->is_integer_symbol);
  60092. if ((f != sc->undefined) &&
  60093. (is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil)))))
  60094. return(big_type_to_result_type(result_type, T_BIG_INTEGER));
  60095. f = find_method(sc, find_let(sc, p), sc->is_rational_symbol);
  60096. if ((f != sc->undefined) &&
  60097. (is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil)))))
  60098. return(big_type_to_result_type(result_type, T_BIG_RATIO));
  60099. f = find_method(sc, find_let(sc, p), sc->is_real_symbol);
  60100. if ((f != sc->undefined) &&
  60101. (is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil)))))
  60102. return(big_type_to_result_type(result_type, T_BIG_REAL));
  60103. /* might be a number, but not complex (quaternion) */
  60104. f = find_method(sc, find_let(sc, p), sc->is_complex_symbol);
  60105. if ((f != sc->undefined) &&
  60106. (is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil)))))
  60107. return(big_type_to_result_type(result_type, T_BIG_COMPLEX));
  60108. return(-1);
  60109. }
  60110. static s7_pointer big_add(s7_scheme *sc, s7_pointer args)
  60111. {
  60112. int result_type = T_INTEGER;
  60113. s7_pointer x, result;
  60114. if (is_null(args))
  60115. return(small_int(0));
  60116. if ((is_null(cdr(args))) && (s7_is_number(car(args))))
  60117. return(car(args));
  60118. for (x = args; is_not_null(x); x = cdr(x))
  60119. {
  60120. s7_pointer p;
  60121. p = car(x);
  60122. result_type = get_result_type(sc, result_type, p);
  60123. if (result_type < 0)
  60124. return(g_add(sc, args));
  60125. }
  60126. if (result_type < T_BIG_INTEGER)
  60127. return(g_add(sc, args));
  60128. if (!s7_is_number(car(args)))
  60129. check_method(sc, car(args), sc->add_symbol, args);
  60130. result = copy_and_promote_number(sc, result_type, car(args));
  60131. for (x = cdr(args); is_not_null(x); x = cdr(x))
  60132. {
  60133. s7_pointer arg;
  60134. if (!s7_is_number(car(x)))
  60135. check_method(sc, car(x), sc->add_symbol, cons(sc, result, x));
  60136. arg = promote_number(sc, result_type, car(x));
  60137. switch (result_type)
  60138. {
  60139. case T_BIG_INTEGER: mpz_add(big_integer(result), big_integer(result), big_integer(arg)); break;
  60140. case T_BIG_RATIO: mpq_add(big_ratio(result), big_ratio(result), big_ratio(arg)); break;
  60141. case T_BIG_REAL: mpfr_add(big_real(result), big_real(result), big_real(arg), GMP_RNDN); break;
  60142. case T_BIG_COMPLEX: mpc_add(big_complex(result), big_complex(result), big_complex(arg), MPC_RNDNN); break;
  60143. }
  60144. }
  60145. switch (result_type)
  60146. {
  60147. case T_BIG_RATIO: return(make_big_integer_or_ratio(sc, result));
  60148. case T_BIG_COMPLEX: return(make_big_real_or_complex(sc, result));
  60149. }
  60150. return(result);
  60151. }
  60152. static s7_pointer big_negate(s7_scheme *sc, s7_pointer args)
  60153. {
  60154. /* assume cdr(args) is nil and we're called from subtract, so check for big num else call g_subtract */
  60155. s7_pointer p, x;
  60156. p = car(args);
  60157. switch (type(p))
  60158. {
  60159. case T_BIG_INTEGER:
  60160. x = mpz_to_big_integer(sc, big_integer(p));
  60161. mpz_neg(big_integer(x), big_integer(x));
  60162. return(x);
  60163. case T_BIG_RATIO:
  60164. x = mpq_to_big_ratio(sc, big_ratio(p));
  60165. mpq_neg(big_ratio(x), big_ratio(x));
  60166. return(x);
  60167. case T_BIG_REAL:
  60168. x = mpfr_to_big_real(sc, big_real(p));
  60169. mpfr_neg(big_real(x), big_real(x), GMP_RNDN);
  60170. return(x);
  60171. case T_BIG_COMPLEX:
  60172. x = mpc_to_big_complex(sc, big_complex(p));
  60173. mpc_neg(big_complex(x), big_complex(x), MPC_RNDNN);
  60174. return(x);
  60175. case T_INTEGER:
  60176. if (integer(p) == s7_int_min)
  60177. {
  60178. x = s7_int_to_big_integer(sc, integer(p));
  60179. mpz_neg(big_integer(x), big_integer(x));
  60180. return(x);
  60181. }
  60182. return(make_integer(sc, -integer(p)));
  60183. case T_RATIO:
  60184. return(s7_make_ratio(sc, -numerator(p), denominator(p)));
  60185. case T_REAL:
  60186. return(make_real(sc, -real(p)));
  60187. default:
  60188. return(s7_make_complex(sc, -real_part(p), -imag_part(p)));
  60189. }
  60190. }
  60191. static s7_pointer big_subtract(s7_scheme *sc, s7_pointer args)
  60192. {
  60193. int result_type = T_INTEGER;
  60194. s7_pointer x, result;
  60195. if (!s7_is_number(car(args)))
  60196. method_or_bust_with_type(sc, car(args), sc->subtract_symbol, args, a_number_string, 1);
  60197. if (is_null(cdr(args)))
  60198. return(big_negate(sc, args));
  60199. for (x = args; is_not_null(x); x = cdr(x))
  60200. {
  60201. s7_pointer p;
  60202. p = car(x);
  60203. result_type = get_result_type(sc, result_type, p);
  60204. if (result_type < 0)
  60205. return(g_subtract(sc, args));
  60206. }
  60207. if (result_type < T_BIG_INTEGER)
  60208. return(g_subtract(sc, args));
  60209. if (!s7_is_number(car(args)))
  60210. check_method(sc, car(args), sc->subtract_symbol, args);
  60211. result = copy_and_promote_number(sc, result_type, car(args));
  60212. for (x = cdr(args); is_not_null(x); x = cdr(x))
  60213. {
  60214. s7_pointer arg;
  60215. if (!s7_is_number(car(x)))
  60216. check_method(sc, car(x), sc->subtract_symbol, cons(sc, result, x));
  60217. arg = promote_number(sc, result_type, car(x));
  60218. switch (result_type)
  60219. {
  60220. case T_BIG_INTEGER: mpz_sub(big_integer(result), big_integer(result), big_integer(arg)); break;
  60221. case T_BIG_RATIO: mpq_sub(big_ratio(result), big_ratio(result), big_ratio(arg)); break;
  60222. case T_BIG_REAL: mpfr_sub(big_real(result), big_real(result), big_real(arg), GMP_RNDN); break;
  60223. case T_BIG_COMPLEX: mpc_sub(big_complex(result), big_complex(result), big_complex(arg), MPC_RNDNN); break;
  60224. }
  60225. }
  60226. switch (result_type)
  60227. {
  60228. case T_BIG_RATIO: return(make_big_integer_or_ratio(sc, result));
  60229. case T_BIG_COMPLEX: return(make_big_real_or_complex(sc, result));
  60230. }
  60231. return(result);
  60232. }
  60233. static s7_pointer big_multiply(s7_scheme *sc, s7_pointer args)
  60234. {
  60235. int result_type = T_INTEGER;
  60236. s7_pointer x, result;
  60237. if (is_null(args))
  60238. return(small_int(1));
  60239. if ((is_null(cdr(args))) && (s7_is_number(car(args))))
  60240. return(car(args));
  60241. for (x = args; is_not_null(x); x = cdr(x))
  60242. {
  60243. s7_pointer p;
  60244. p = car(x);
  60245. result_type = get_result_type(sc, result_type, p);
  60246. if (result_type < 0)
  60247. return(g_multiply(sc, args));
  60248. }
  60249. if (result_type < T_BIG_INTEGER)
  60250. return(g_multiply(sc, args));
  60251. if (!s7_is_number(car(args)))
  60252. check_method(sc, car(args), sc->multiply_symbol, args);
  60253. result = copy_and_promote_number(sc, result_type, car(args));
  60254. for (x = cdr(args); is_not_null(x); x = cdr(x))
  60255. {
  60256. s7_pointer arg;
  60257. if (!s7_is_number(car(x)))
  60258. check_method(sc, car(x), sc->multiply_symbol, cons(sc, result, x));
  60259. arg = promote_number(sc, result_type, car(x));
  60260. switch (result_type)
  60261. {
  60262. case T_BIG_INTEGER: mpz_mul(big_integer(result), big_integer(result), big_integer(arg)); break;
  60263. case T_BIG_RATIO: mpq_mul(big_ratio(result), big_ratio(result), big_ratio(arg)); break;
  60264. case T_BIG_REAL: mpfr_mul(big_real(result), big_real(result), big_real(arg), GMP_RNDN); break;
  60265. case T_BIG_COMPLEX: mpc_mul(big_complex(result), big_complex(result), big_complex(arg), MPC_RNDNN); break;
  60266. }
  60267. }
  60268. switch (result_type)
  60269. {
  60270. case T_BIG_RATIO: return(make_big_integer_or_ratio(sc, result));
  60271. case T_BIG_COMPLEX: return(make_big_real_or_complex(sc, result));
  60272. }
  60273. return(result);
  60274. }
  60275. static s7_pointer big_invert(s7_scheme *sc, s7_pointer args)
  60276. {
  60277. /* assume cdr(args) is nil and we're called from divide, so check for big num else call g_divide */
  60278. s7_pointer p, x;
  60279. p = car(args);
  60280. if (s7_is_zero(p))
  60281. return(division_by_zero_error(sc, sc->divide_symbol, p));
  60282. switch (type(p))
  60283. {
  60284. case T_INTEGER:
  60285. if (integer(p) == s7_int_min)
  60286. {
  60287. mpz_t n1, d1;
  60288. new_cell(sc, x, T_BIG_RATIO);
  60289. add_bigratio(sc, x);
  60290. mpz_init_set_s7_int(n1, 1);
  60291. mpz_init_set_s7_int(d1, s7_int_min);
  60292. mpq_set_num(big_ratio(x), n1);
  60293. mpq_set_den(big_ratio(x), d1);
  60294. mpq_canonicalize(big_ratio(x));
  60295. mpz_clear(n1);
  60296. mpz_clear(d1);
  60297. return(x);
  60298. }
  60299. return(s7_make_ratio(sc, 1, integer(p))); /* a already checked, not 0 */
  60300. case T_RATIO:
  60301. return(s7_make_ratio(sc, denominator(p), numerator(p)));
  60302. case T_REAL:
  60303. return(make_real(sc, 1.0 / real(p)));
  60304. case T_COMPLEX:
  60305. {
  60306. s7_double r2, i2, den;
  60307. r2 = real_part(p);
  60308. i2 = imag_part(p);
  60309. den = (r2 * r2 + i2 * i2);
  60310. return(s7_make_complex(sc, r2 / den, -i2 / den));
  60311. }
  60312. case T_BIG_INTEGER:
  60313. /* p might be 1 or -1 */
  60314. {
  60315. mpz_t n;
  60316. mpz_init_set_si(n, 1);
  60317. if (mpz_cmp(n, big_integer(p)) == 0)
  60318. {
  60319. mpz_clear(n);
  60320. return(small_int(1));
  60321. }
  60322. mpz_set_si(n, -1);
  60323. if (mpz_cmp(n, big_integer(p)) == 0)
  60324. {
  60325. mpz_clear(n);
  60326. return(minus_one);
  60327. }
  60328. new_cell(sc, x, T_BIG_RATIO);
  60329. add_bigratio(sc, x);
  60330. mpq_init(big_ratio(x));
  60331. mpz_set_ui(n, 1);
  60332. mpq_set_num(big_ratio(x), n);
  60333. mpz_clear(n);
  60334. mpq_set_den(big_ratio(x), big_integer(p));
  60335. mpq_canonicalize(big_ratio(x));
  60336. return(x);
  60337. }
  60338. case T_BIG_RATIO:
  60339. {
  60340. mpz_t n;
  60341. mpz_init_set_si(n, 1);
  60342. if (mpz_cmp(n, mpq_numref(big_ratio(p))) == 0)
  60343. {
  60344. mpz_clear(n);
  60345. return(mpz_to_big_integer(sc, mpq_denref(big_ratio(p))));
  60346. }
  60347. mpz_set_si(n, -1);
  60348. if (mpz_cmp(n, mpq_numref(big_ratio(p))) == 0)
  60349. {
  60350. mpz_clear(n);
  60351. x = mpz_to_big_integer(sc, mpq_denref(big_ratio(p)));
  60352. mpz_neg(big_integer(x), big_integer(x));
  60353. return(x);
  60354. }
  60355. mpz_clear(n);
  60356. new_cell(sc, x, T_BIG_RATIO);
  60357. add_bigratio(sc, x);
  60358. mpq_init(big_ratio(x));
  60359. mpq_set_num(big_ratio(x), mpq_denref(big_ratio(p)));
  60360. mpq_set_den(big_ratio(x), mpq_numref(big_ratio(p)));
  60361. mpq_canonicalize(big_ratio(x));
  60362. return(x);
  60363. }
  60364. case T_BIG_REAL:
  60365. x = mpfr_to_big_real(sc, big_real(p));
  60366. mpfr_ui_div(big_real(x), 1, big_real(x), GMP_RNDN);
  60367. return(x);
  60368. default:
  60369. x = mpc_to_big_complex(sc, big_complex(p));
  60370. mpc_ui_div(big_complex(x), 1, big_complex(x), MPC_RNDNN);
  60371. return(x);
  60372. }
  60373. }
  60374. static s7_pointer big_divide(s7_scheme *sc, s7_pointer args)
  60375. {
  60376. int result_type = T_INTEGER;
  60377. s7_pointer x, divisor, result;
  60378. if (!s7_is_number(car(args)))
  60379. method_or_bust_with_type(sc, car(args), sc->divide_symbol, args, a_number_string, 1);
  60380. if (is_null(cdr(args)))
  60381. return(big_invert(sc, args));
  60382. for (x = args; is_not_null(x); x = cdr(x))
  60383. {
  60384. s7_pointer p;
  60385. p = car(x);
  60386. /* if divisor is 0, gmp throws an exception and halts s7!
  60387. * I don't think we can trap gmp errors, and the abort is built into the library code.
  60388. */
  60389. result_type = get_result_type(sc, result_type, p);
  60390. if (result_type < 0)
  60391. return(g_divide(sc, args));
  60392. if ((x != args) &&
  60393. (s7_is_zero(p)))
  60394. return(division_by_zero_error(sc, sc->divide_symbol, args));
  60395. }
  60396. if (result_type < T_BIG_INTEGER)
  60397. return(g_divide(sc, args));
  60398. if (!s7_is_number(car(args)))
  60399. check_method(sc, car(args), sc->divide_symbol, args);
  60400. if (!s7_is_number(cadr(args)))
  60401. check_method(sc, cadr(args), sc->divide_symbol, args);
  60402. divisor = copy_and_promote_number(sc, result_type, cadr(args));
  60403. for (x = cddr(args); is_not_null(x); x = cdr(x))
  60404. {
  60405. s7_pointer arg;
  60406. if (!s7_is_number(car(x)))
  60407. {
  60408. s7_pointer func;
  60409. if ((has_methods(car(x))) && ((func = find_method(sc, find_let(sc, car(x)), sc->multiply_symbol)) != sc->undefined))
  60410. {
  60411. divisor = s7_apply_function(sc, func, cons(sc, divisor, x));
  60412. break;
  60413. }
  60414. }
  60415. arg = promote_number(sc, result_type, car(x));
  60416. switch (result_type)
  60417. {
  60418. case T_BIG_INTEGER: mpz_mul(big_integer(divisor), big_integer(divisor), big_integer(arg)); break;
  60419. case T_BIG_RATIO: mpq_mul(big_ratio(divisor), big_ratio(divisor), big_ratio(arg)); break;
  60420. case T_BIG_REAL: mpfr_mul(big_real(divisor), big_real(divisor), big_real(arg), GMP_RNDN); break;
  60421. case T_BIG_COMPLEX: mpc_mul(big_complex(divisor), big_complex(divisor), big_complex(arg), MPC_RNDNN); break;
  60422. }
  60423. }
  60424. if (s7_is_zero(divisor))
  60425. return(division_by_zero_error(sc, sc->divide_symbol, args));
  60426. /* it's possible for the divisor to be the wrong type here (if complex multiply -> real for example */
  60427. divisor = promote_number_1(sc, result_type, divisor, false);
  60428. result = copy_and_promote_number(sc, result_type, car(args));
  60429. switch (result_type)
  60430. {
  60431. case T_BIG_INTEGER:
  60432. {
  60433. new_cell(sc, x, T_BIG_RATIO);
  60434. add_bigratio(sc, x);
  60435. mpq_init(big_ratio(x));
  60436. mpq_set_num(big_ratio(x), big_integer(result));
  60437. mpq_set_den(big_ratio(x), big_integer(divisor));
  60438. mpq_canonicalize(big_ratio(x));
  60439. if (mpz_cmp_ui(mpq_denref(big_ratio(x)), 1) == 0)
  60440. return(mpz_to_big_integer(sc, mpq_numref(big_ratio(x))));
  60441. return(x);
  60442. }
  60443. case T_BIG_RATIO:
  60444. mpq_div(big_ratio(result), big_ratio(result), big_ratio(divisor));
  60445. return(make_big_integer_or_ratio(sc, result));
  60446. case T_BIG_REAL:
  60447. mpfr_div(big_real(result), big_real(result), big_real(divisor), GMP_RNDN);
  60448. break;
  60449. case T_BIG_COMPLEX:
  60450. mpc_div(big_complex(result), big_complex(result), big_complex(divisor), MPC_RNDNN);
  60451. return(make_big_real_or_complex(sc, result));
  60452. }
  60453. return(result);
  60454. }
  60455. static s7_pointer big_abs(s7_scheme *sc, s7_pointer args)
  60456. {
  60457. #define H_abs "(abs x) returns the absolute value of the real number x"
  60458. #define Q_abs s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_real_symbol)
  60459. s7_pointer p, x;
  60460. p = car(args);
  60461. switch (type(p))
  60462. {
  60463. case T_INTEGER:
  60464. if (integer(p) < 0)
  60465. {
  60466. if (integer(p) == s7_int_min)
  60467. {
  60468. x = s7_int_to_big_integer(sc, integer(p));
  60469. mpz_neg(big_integer(x), big_integer(x));
  60470. return(x);
  60471. }
  60472. return(make_integer(sc, -integer(p)));
  60473. }
  60474. return(p);
  60475. case T_RATIO:
  60476. if (numerator(p) < 0)
  60477. return(s7_make_ratio(sc, -numerator(p), denominator(p)));
  60478. return(p);
  60479. case T_REAL:
  60480. if (real(p) < 0.0)
  60481. return(make_real(sc, -real(p)));
  60482. return(p);
  60483. case T_BIG_INTEGER:
  60484. x = mpz_to_big_integer(sc, big_integer(p));
  60485. mpz_abs(big_integer(x), big_integer(x));
  60486. return(x);
  60487. case T_BIG_RATIO:
  60488. x = mpq_to_big_ratio(sc, big_ratio(p));
  60489. mpq_abs(big_ratio(x), big_ratio(x));
  60490. return(x);
  60491. case T_BIG_REAL:
  60492. x = mpfr_to_big_real(sc, big_real(p));
  60493. mpfr_abs(big_real(x), big_real(x), GMP_RNDN);
  60494. return(x);
  60495. default:
  60496. method_or_bust(sc, p, sc->abs_symbol, args, T_REAL, 0);
  60497. }
  60498. }
  60499. static s7_pointer big_magnitude(s7_scheme *sc, s7_pointer args)
  60500. {
  60501. #define H_magnitude "(magnitude z) returns the magnitude of z"
  60502. #define Q_magnitude s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
  60503. s7_pointer p;
  60504. p = car(args);
  60505. if (!s7_is_number(p))
  60506. method_or_bust_with_type(sc, p, sc->magnitude_symbol, args, a_number_string, 0);
  60507. if (is_t_big_complex(p))
  60508. {
  60509. mpfr_t n;
  60510. mpfr_init(n);
  60511. mpc_abs(n, big_complex(p), GMP_RNDN);
  60512. p = mpfr_to_big_real(sc, n);
  60513. mpfr_clear(n);
  60514. return(p);
  60515. }
  60516. if (is_t_complex(p))
  60517. return(make_real(sc, hypot(imag_part(p), real_part(p))));
  60518. return(big_abs(sc, args));
  60519. }
  60520. static s7_pointer big_angle(s7_scheme *sc, s7_pointer args)
  60521. {
  60522. #define H_angle "(angle z) returns the angle of z"
  60523. #define Q_angle s7_make_signature(sc, 2, sc->is_real_symbol, sc->is_number_symbol)
  60524. s7_pointer p;
  60525. p = car(args);
  60526. switch (type(p))
  60527. {
  60528. case T_INTEGER:
  60529. if (integer(p) < 0)
  60530. return(real_pi);
  60531. return(small_int(0));
  60532. case T_RATIO:
  60533. if (numerator(p) < 0)
  60534. return(real_pi);
  60535. return(small_int(0));
  60536. case T_REAL:
  60537. if (is_NaN(real(p))) return(p);
  60538. if (real(p) < 0.0)
  60539. return(real_pi);
  60540. return(real_zero);
  60541. case T_COMPLEX:
  60542. return(make_real(sc, atan2(imag_part(p), real_part(p))));
  60543. case T_BIG_INTEGER:
  60544. if (mpz_cmp_ui(big_integer(p), 0) >= 0)
  60545. return(small_int(0));
  60546. return(big_pi(sc));
  60547. case T_BIG_RATIO:
  60548. if (mpq_cmp_ui(big_ratio(p), 0, 1) >= 0)
  60549. return(small_int(0));
  60550. return(big_pi(sc));
  60551. case T_BIG_REAL:
  60552. {
  60553. double x;
  60554. x = mpfr_get_d(big_real(p), GMP_RNDN);
  60555. /* mpfr_get_d returns inf or -inf if the arg is too large for a double */
  60556. if (is_NaN(x)) return(p);
  60557. if (x >= 0.0)
  60558. return(real_zero);
  60559. return(big_pi(sc));
  60560. }
  60561. case T_BIG_COMPLEX:
  60562. {
  60563. s7_pointer x;
  60564. new_cell(sc, x, T_BIG_REAL);
  60565. add_bigreal(sc, x);
  60566. mpfr_init(big_real(x));
  60567. mpc_arg(big_real(x), big_complex(p), GMP_RNDN);
  60568. return(x);
  60569. }
  60570. default:
  60571. method_or_bust_with_type(sc, p, sc->angle_symbol, args, a_number_string, 0);
  60572. }
  60573. }
  60574. static s7_pointer c_big_complex(s7_scheme *sc, s7_pointer args)
  60575. {
  60576. #define H_complex "(complex x1 x2) returns a complex number with real-part x1 and imaginary-part x2"
  60577. #define Q_complex s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_real_symbol, sc->is_real_symbol)
  60578. s7_pointer p0, p1, p;
  60579. mpfr_t rl, im;
  60580. double x;
  60581. p0 = car(args);
  60582. if (!s7_is_real(p0))
  60583. method_or_bust(sc, p0, sc->complex_symbol, args, T_REAL, 1);
  60584. p1 = cadr(args);
  60585. if (!s7_is_real(p1))
  60586. method_or_bust(sc, p1, sc->complex_symbol, args, T_REAL, 2);
  60587. if ((!is_big_number(p1)) && (real_to_double(sc, p1, "complex") == 0.0)) /* imag-part is not bignum and is 0.0 */
  60588. return(p0);
  60589. mpfr_init_set(im, big_real(promote_number(sc, T_BIG_REAL, p1)), GMP_RNDN);
  60590. x = mpfr_get_d(im, GMP_RNDN);
  60591. if (x == 0.0) /* imag-part is bignum 0.0 */
  60592. {
  60593. mpfr_clear(im);
  60594. return(p0);
  60595. }
  60596. mpfr_init_set(rl, big_real(promote_number(sc, T_BIG_REAL, p0)), GMP_RNDN);
  60597. new_cell(sc, p, T_BIG_COMPLEX);
  60598. add_bignumber(sc, p);
  60599. mpc_init(big_complex(p));
  60600. mpc_set_fr_fr(big_complex(p), rl, im, MPC_RNDNN);
  60601. mpfr_clear(rl);
  60602. mpfr_clear(im);
  60603. return(p);
  60604. }
  60605. /* (make-polar 0 (real-part (log 0))) = 0? or nan? */
  60606. #if (!WITH_PURE_S7)
  60607. static s7_pointer big_make_polar(s7_scheme *sc, s7_pointer args)
  60608. {
  60609. #define H_make_polar "(make-polar mag ang) returns a complex number with magnitude mag and angle ang"
  60610. #define Q_make_polar s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_real_symbol, sc->is_real_symbol)
  60611. s7_pointer p0, p1, p;
  60612. mpfr_t ang, mag, rl, im;
  60613. double x, y;
  60614. p0 = car(args);
  60615. if (!s7_is_real(p0))
  60616. method_or_bust(sc, p0, sc->make_polar_symbol, args, T_REAL, 1);
  60617. p1 = cadr(args);
  60618. if (!s7_is_real(p1))
  60619. method_or_bust(sc, p1, sc->make_polar_symbol, args, T_REAL, 2);
  60620. mpfr_init_set(ang, big_real(promote_number(sc, T_BIG_REAL, p1)), GMP_RNDN);
  60621. y = mpfr_get_d(ang, GMP_RNDN);
  60622. if (is_NaN(y))
  60623. {
  60624. mpfr_clear(ang);
  60625. return(real_NaN);
  60626. }
  60627. mpfr_init_set(mag, big_real(promote_number(sc, T_BIG_REAL, p0)), GMP_RNDN);
  60628. x = mpfr_get_d(mag, GMP_RNDN);
  60629. if (is_NaN(x))
  60630. {
  60631. mpfr_clear(ang);
  60632. mpfr_clear(mag);
  60633. return(real_NaN);
  60634. }
  60635. if ((x == 0.0) || (y == 0.0))
  60636. {
  60637. mpfr_clear(ang);
  60638. mpfr_clear(mag);
  60639. return(p0);
  60640. }
  60641. mpfr_init_set(im, ang, GMP_RNDN);
  60642. mpfr_sin(im, im, GMP_RNDN);
  60643. mpfr_mul(im, im, mag, GMP_RNDN);
  60644. x = mpfr_get_d(im, GMP_RNDN);
  60645. if (x == 0.0)
  60646. {
  60647. mpfr_clear(im);
  60648. mpfr_clear(ang);
  60649. mpfr_clear(mag);
  60650. return(p0);
  60651. }
  60652. mpfr_init_set(rl, ang, GMP_RNDN);
  60653. mpfr_cos(rl, rl, GMP_RNDN);
  60654. mpfr_mul(rl, rl, mag, GMP_RNDN);
  60655. new_cell(sc, p, T_BIG_COMPLEX);
  60656. add_bignumber(sc, p);
  60657. mpc_init(big_complex(p));
  60658. mpc_set_fr_fr(big_complex(p), rl, im, MPC_RNDNN);
  60659. mpfr_clear(rl);
  60660. mpfr_clear(im);
  60661. mpfr_clear(ang);
  60662. mpfr_clear(mag);
  60663. return(p);
  60664. }
  60665. #endif
  60666. static s7_pointer big_log(s7_scheme *sc, s7_pointer args)
  60667. {
  60668. #define H_log "(log z1 (z2 e)) returns log(z1) / log(z2) where z2 (the base) defaults to e: (log 8 2) = 3"
  60669. #define Q_log pcl_n
  60670. /* either arg can be big, second is optional */
  60671. s7_pointer p0, p1 = NULL, p;
  60672. p0 = car(args);
  60673. if (!s7_is_number(p0))
  60674. method_or_bust_with_type(sc, p0, sc->log_symbol, args, a_number_string, 1);
  60675. if (is_not_null(cdr(args)))
  60676. {
  60677. p1 = cadr(args);
  60678. if (!s7_is_number(p1))
  60679. method_or_bust_with_type(sc, p1, sc->log_symbol, args, a_number_string, 2);
  60680. }
  60681. if ((s7_is_real(p0)) &&
  60682. ((!p1) || (s7_is_real(p1))))
  60683. {
  60684. double x, y = 0.0;
  60685. p0 = promote_number(sc, T_BIG_REAL, p0);
  60686. x = mpfr_get_d(big_real(p0), GMP_RNDN);
  60687. if (is_NaN(x))
  60688. return(real_NaN);
  60689. if (p1)
  60690. {
  60691. p1 = promote_number(sc, T_BIG_REAL, p1);
  60692. y = mpfr_get_d(big_real(p1), GMP_RNDN);
  60693. /* we can't check y here for 1.0 (check for 0.0 apparently is ok):
  60694. * :(log 100.0 (+ 1.0 (bignum "1e-16")))
  60695. * ;log base, argument 2, 1.000000000000000100000000000000000000002E0, is out of range (can't be 0.0 or 1.0)
  60696. * :(= 1.0 (+ 1.0 (bignum "1e-16")))
  60697. * #f
  60698. */
  60699. if (is_NaN(y))
  60700. return(real_NaN);
  60701. if (y == 0.0)
  60702. return(out_of_range(sc, sc->log_symbol, small_int(2), p1, make_string_wrapper(sc, "argument can't be 0.0")));
  60703. }
  60704. if (x == 0.0)
  60705. return(s7_make_complex(sc, -INFINITY, M_PI));
  60706. if ((x > 0.0) && (y >= 0.0))
  60707. {
  60708. mpfr_t n, base;
  60709. mpfr_init_set(n, big_real(p0), GMP_RNDN);
  60710. mpfr_log(n, n, GMP_RNDN);
  60711. if (!p1)
  60712. {
  60713. /* presumably log is safe with regard to real-part overflow giving a bogus int? */
  60714. if ((s7_is_rational(car(args))) &&
  60715. (mpfr_integer_p(n) != 0))
  60716. {
  60717. new_cell(sc, p, T_BIG_INTEGER);
  60718. add_bigint(sc, p);
  60719. mpz_init(big_integer(p));
  60720. mpfr_get_z(big_integer(p), n, GMP_RNDN);
  60721. }
  60722. else p = mpfr_to_big_real(sc, n);
  60723. mpfr_clear(n);
  60724. return(p);
  60725. }
  60726. mpfr_init_set(base, big_real(p1), GMP_RNDN);
  60727. mpfr_log(base, base, GMP_RNDN);
  60728. mpfr_div(n, n, base, GMP_RNDN);
  60729. mpfr_clear(base);
  60730. if ((s7_is_rational(car(args))) &&
  60731. (s7_is_rational(cadr(args))) &&
  60732. (mpfr_integer_p(n) != 0))
  60733. {
  60734. new_cell(sc, p, T_BIG_INTEGER);
  60735. add_bigint(sc, p);
  60736. mpz_init(big_integer(p));
  60737. mpfr_get_z(big_integer(p), n, GMP_RNDN);
  60738. }
  60739. else p = mpfr_to_big_real(sc, n);
  60740. mpfr_clear(n);
  60741. return(p);
  60742. }
  60743. }
  60744. p0 = promote_number(sc, T_BIG_COMPLEX, p0);
  60745. if (p1) p1 = promote_number(sc, T_BIG_COMPLEX, p1);
  60746. {
  60747. mpc_t n, base;
  60748. double x;
  60749. mpc_init(n);
  60750. mpc_set(n, big_complex(p0), MPC_RNDNN);
  60751. mpc_log(n, n, MPC_RNDNN);
  60752. if (!p1)
  60753. {
  60754. p = mpc_to_big_complex(sc, n);
  60755. mpc_clear(n);
  60756. return(p);
  60757. }
  60758. mpc_init(base);
  60759. mpc_set(base, big_complex(p1), MPC_RNDNN);
  60760. mpc_log(base, base, MPC_RNDNN);
  60761. mpc_div(n, n, base, MPC_RNDNN);
  60762. mpc_clear(base);
  60763. x = mpfr_get_d(mpc_imagref(n), GMP_RNDN);
  60764. if (x == 0.0)
  60765. p = mpfr_to_big_real(sc, mpc_realref(n));
  60766. else p = mpc_to_big_complex(sc, n);
  60767. mpc_clear(n);
  60768. return(p);
  60769. }
  60770. }
  60771. static s7_pointer big_sqrt(s7_scheme *sc, s7_pointer args)
  60772. {
  60773. /* real >= 0 -> real, else complex */
  60774. #define H_sqrt "(sqrt z) returns the square root of z"
  60775. #define Q_sqrt pcl_n
  60776. s7_pointer p;
  60777. p = car(args);
  60778. if (!s7_is_number(p))
  60779. method_or_bust_with_type(sc, p, sc->sqrt_symbol, args, a_number_string, 0);
  60780. p = to_big(sc, p);
  60781. /* if big integer, try to return int if perfect square */
  60782. if (is_t_big_integer(p))
  60783. {
  60784. if (mpz_cmp_ui(big_integer(p), 0) < 0)
  60785. p = promote_number(sc, T_BIG_COMPLEX, p);
  60786. else
  60787. {
  60788. mpz_t n, rem;
  60789. mpz_init(rem);
  60790. mpz_init_set(n, big_integer(p));
  60791. mpz_sqrtrem(n, rem, n);
  60792. if (mpz_cmp_ui(rem, 0) == 0)
  60793. {
  60794. p = mpz_to_big_integer(sc, n);
  60795. mpz_clear(n);
  60796. mpz_clear(rem);
  60797. return(p);
  60798. }
  60799. mpz_clear(n);
  60800. mpz_clear(rem);
  60801. p = promote_number(sc, T_BIG_REAL, p);
  60802. }
  60803. }
  60804. /* if big ratio, check both num and den for squares */
  60805. if (is_t_big_ratio(p))
  60806. {
  60807. if (mpq_cmp_ui(big_ratio(p), 0, 1) < 0)
  60808. p = promote_number(sc, T_BIG_COMPLEX, p);
  60809. else
  60810. {
  60811. mpz_t n1, rem;
  60812. mpz_init(rem);
  60813. mpz_init_set(n1, mpq_numref(big_ratio(p)));
  60814. mpz_sqrtrem(n1, rem, n1);
  60815. if (mpz_cmp_ui(rem, 0) == 0)
  60816. {
  60817. mpz_t d1;
  60818. mpz_init_set(d1, mpq_denref(big_ratio(p)));
  60819. mpz_sqrtrem(d1, rem, d1);
  60820. if (mpz_cmp_ui(rem, 0) == 0)
  60821. {
  60822. mpq_t n;
  60823. mpq_init(n);
  60824. mpq_set_num(n, n1);
  60825. mpq_set_den(n, d1);
  60826. mpq_canonicalize(n);
  60827. p = mpq_to_big_ratio(sc, n);
  60828. mpz_clear(n1);
  60829. mpz_clear(d1);
  60830. mpz_clear(rem);
  60831. mpq_clear(n);
  60832. return(p);
  60833. }
  60834. mpz_clear(d1);
  60835. }
  60836. mpz_clear(n1);
  60837. mpz_clear(rem);
  60838. p = promote_number(sc, T_BIG_REAL, p);
  60839. }
  60840. }
  60841. /* if real and not negative, use mpfr_sqrt */
  60842. if (is_t_big_real(p))
  60843. {
  60844. if (mpfr_cmp_ui(big_real(p), 0) < 0)
  60845. p = promote_number(sc, T_BIG_COMPLEX, p);
  60846. else
  60847. {
  60848. mpfr_t n;
  60849. mpfr_init_set(n, big_real(p), GMP_RNDN);
  60850. mpfr_sqrt(n, n, GMP_RNDN);
  60851. p = mpfr_to_big_real(sc, n);
  60852. mpfr_clear(n);
  60853. return(p);
  60854. }
  60855. }
  60856. /* p is a big number, so it must be complex at this point */
  60857. {
  60858. mpc_t n;
  60859. mpc_init(n);
  60860. mpc_set(n, big_complex(p), MPC_RNDNN);
  60861. mpc_sqrt(n, n, MPC_RNDNN);
  60862. p = mpc_to_big_complex(sc, n);
  60863. mpc_clear(n);
  60864. return(p);
  60865. }
  60866. }
  60867. /* (define (diff f a) (magnitude (- (f a) (f (bignum (number->string a))))))
  60868. * (sin 1e15+1e15i) hangs in mpc 0.8.2, but appears to be fixed in the current svn sources
  60869. */
  60870. enum {TRIG_NO_CHECK, TRIG_TAN_CHECK, TRIG_TANH_CHECK};
  60871. static s7_pointer big_trig(s7_scheme *sc, s7_pointer args,
  60872. int (*mpfr_trig)(mpfr_ptr, mpfr_srcptr, mpfr_rnd_t),
  60873. int (*mpc_trig)(mpc_ptr, mpc_srcptr, mpc_rnd_t),
  60874. int tan_case, s7_pointer sym)
  60875. /* these declarations mimic the mpfr.h and mpc.h declarations. It seems to me that
  60876. * they ought to be:
  60877. * int (*mpfr_trig)(mpfr_t rop, mpfr_t op, mp_rnd_t rnd),
  60878. * void (*mpc_trig)(mpc_t rop, mpc_t op, mpc_rnd_t rnd))
  60879. */
  60880. {
  60881. s7_pointer p;
  60882. p = car(args);
  60883. /* I think here we should always promote to bignum (otherwise, for example, (exp 800) -> inf)
  60884. */
  60885. if (!s7_is_number(p))
  60886. method_or_bust_with_type(sc, p, sym, args, a_number_string, 0);
  60887. if (s7_is_real(p))
  60888. {
  60889. mpfr_t n;
  60890. mpfr_init_set(n, big_real(promote_number(sc, T_BIG_REAL, p)), GMP_RNDN);
  60891. mpfr_trig(n, n, GMP_RNDN);
  60892. /* it's confusing to check for ints here via mpfr_integer_p because it
  60893. * is dependent on the precision! (exp 617/5) returns an integer if
  60894. * precision is 128, but a float if 512.
  60895. */
  60896. p = mpfr_to_big_real(sc, n);
  60897. mpfr_clear(n);
  60898. return(p);
  60899. }
  60900. if (!is_big_number(p))
  60901. p = promote_number(sc, T_BIG_COMPLEX, p);
  60902. if (tan_case == TRIG_TAN_CHECK)
  60903. {
  60904. if ((MPC_INEX_IM(mpc_cmp_si_si(big_complex(p), 1, 350))) > 0)
  60905. return(s7_make_complex(sc, 0.0, 1.0));
  60906. if ((MPC_INEX_IM(mpc_cmp_si_si(big_complex(p), 1, -350))) < 0)
  60907. return(s7_make_complex(sc, 0.0, -1.0));
  60908. }
  60909. if (tan_case == TRIG_TANH_CHECK)
  60910. {
  60911. if ((MPC_INEX_RE(mpc_cmp_si_si(big_complex(p), 350, 1))) > 0)
  60912. return(real_one);
  60913. if ((MPC_INEX_RE(mpc_cmp_si_si(big_complex(p), -350, 1))) < 0)
  60914. return(make_real(sc, -1.0));
  60915. }
  60916. {
  60917. mpc_t n;
  60918. double ix;
  60919. mpc_init(n);
  60920. mpc_trig(n, big_complex(p), MPC_RNDNN);
  60921. /* (sin (bignum "1e15+1e15i")) causes mpc to hang (e9 is ok, but e10 hangs)
  60922. * (sin (bignum "0+1e10i")) -> 0+inf (sin (bignum "1+1e10i")) hangs
  60923. *
  60924. * before comparing imag-part to 0, we need to look for NaN and inf, else:
  60925. * (sinh 0+0/0i) -> 0.0
  60926. * (sinh (log 0.0)) -> inf.0
  60927. */
  60928. ix = mpfr_get_d(mpc_imagref(n), GMP_RNDN);
  60929. if (ix == 0.0)
  60930. {
  60931. mpfr_t z;
  60932. mpfr_init_set(z, mpc_realref(n), GMP_RNDN);
  60933. p = mpfr_to_big_real(sc, z);
  60934. mpfr_clear(z);
  60935. }
  60936. else p = mpc_to_big_complex(sc, n);
  60937. mpc_clear(n);
  60938. return(p);
  60939. }
  60940. }
  60941. static s7_pointer big_sin(s7_scheme *sc, s7_pointer args)
  60942. {
  60943. #define H_sin "(sin z) returns sin(z)"
  60944. #define Q_sin pcl_n
  60945. return(big_trig(sc, args, mpfr_sin, mpc_sin, TRIG_NO_CHECK, sc->sin_symbol));
  60946. }
  60947. static s7_pointer big_cos(s7_scheme *sc, s7_pointer args)
  60948. {
  60949. #define H_cos "(cos z) returns cos(z)"
  60950. #define Q_cos pcl_n
  60951. return(big_trig(sc, args, mpfr_cos, mpc_cos, TRIG_NO_CHECK, sc->cos_symbol));
  60952. }
  60953. s7_pointer s7_cos(s7_scheme *sc, s7_pointer x)
  60954. {
  60955. return(big_cos(sc, cons(sc, x, sc->nil)));
  60956. }
  60957. static s7_pointer big_tan(s7_scheme *sc, s7_pointer args)
  60958. {
  60959. #define H_tan "(tan z) returns tan(z)"
  60960. #define Q_tan pcl_n
  60961. return(big_trig(sc, args, mpfr_tan, mpc_tan, TRIG_TAN_CHECK, sc->tan_symbol));
  60962. }
  60963. static s7_pointer big_sinh(s7_scheme *sc, s7_pointer args)
  60964. {
  60965. #define H_sinh "(sinh z) returns sinh(z)"
  60966. #define Q_sinh pcl_n
  60967. /* currently (sinh 0+0/0i) -> 0.0? */
  60968. return(big_trig(sc, args, mpfr_sinh, mpc_sinh, TRIG_NO_CHECK, sc->sinh_symbol));
  60969. }
  60970. static s7_pointer big_cosh(s7_scheme *sc, s7_pointer args)
  60971. {
  60972. #define H_cosh "(cosh z) returns cosh(z)"
  60973. #define Q_cosh pcl_n
  60974. return(big_trig(sc, args, mpfr_cosh, mpc_cosh, TRIG_NO_CHECK, sc->cosh_symbol));
  60975. }
  60976. static s7_pointer big_tanh(s7_scheme *sc, s7_pointer args)
  60977. {
  60978. #define H_tanh "(tanh z) returns tanh(z)"
  60979. #define Q_tanh pcl_n
  60980. return(big_trig(sc, args, mpfr_tanh, mpc_tanh, TRIG_TANH_CHECK, sc->tanh_symbol));
  60981. }
  60982. static s7_pointer big_exp(s7_scheme *sc, s7_pointer args)
  60983. {
  60984. #define H_exp "(exp z) returns e^z, (exp 1) is 2.718281828459"
  60985. #define Q_exp pcl_n
  60986. return(big_trig(sc, args, mpfr_exp, mpc_exp, TRIG_NO_CHECK, sc->exp_symbol));
  60987. }
  60988. static s7_pointer big_expt(s7_scheme *sc, s7_pointer args)
  60989. {
  60990. #define H_expt "(expt z1 z2) returns z1^z2"
  60991. #define Q_expt pcl_n
  60992. s7_pointer x, y, p;
  60993. /* see comment under g_expt
  60994. * if (is_not_null(cddr(args)))
  60995. * return(big_expt(sc, set_plist_2(sc, car(args), big_expt(sc, cdr(args)))));
  60996. */
  60997. x = car(args);
  60998. if (!s7_is_number(x))
  60999. method_or_bust_with_type(sc, x, sc->expt_symbol, args, a_number_string, 1);
  61000. y = cadr(args);
  61001. if (!s7_is_number(y))
  61002. method_or_bust_with_type(sc, y, sc->expt_symbol, args, a_number_string, 2);
  61003. if (s7_is_zero(x))
  61004. {
  61005. if ((s7_is_integer(x)) &&
  61006. (s7_is_integer(y)) &&
  61007. (s7_is_zero(y)))
  61008. return(small_int(1));
  61009. if (s7_is_real(y))
  61010. {
  61011. if (s7_is_negative(y))
  61012. return(division_by_zero_error(sc, sc->expt_symbol, args));
  61013. }
  61014. else
  61015. {
  61016. if (s7_is_negative(g_real_part(sc, cdr(args))))
  61017. return(division_by_zero_error(sc, sc->expt_symbol, args));
  61018. }
  61019. if ((s7_is_rational(x)) &&
  61020. (s7_is_rational(y)))
  61021. return(small_int(0));
  61022. return(real_zero);
  61023. }
  61024. if (s7_is_integer(y))
  61025. {
  61026. s7_int yval;
  61027. yval = s7_integer(y);
  61028. if (yval == 0)
  61029. {
  61030. if (s7_is_rational(x))
  61031. return(small_int(1));
  61032. return(real_one);
  61033. }
  61034. if (yval == 1)
  61035. return(x);
  61036. if (!is_big_number(x))
  61037. {
  61038. if ((s7_is_one(x)) || (s7_is_zero(x)))
  61039. return(x);
  61040. }
  61041. if ((yval < s7_int32_max) &&
  61042. (yval > s7_int32_min))
  61043. {
  61044. /* from here yval can fit in an unsigned int
  61045. * (protect against gmp exception if for example (expt 1/9223372036854775807 -9223372036854775807)
  61046. */
  61047. if (s7_is_integer(x))
  61048. {
  61049. mpz_t n;
  61050. mpq_t r;
  61051. x = promote_number(sc, T_BIG_INTEGER, x);
  61052. mpz_init_set(n, big_integer(x));
  61053. if (yval >= 0)
  61054. {
  61055. mpz_pow_ui(n, n, (unsigned int)yval);
  61056. p = mpz_to_big_integer(sc, n);
  61057. mpz_clear(n);
  61058. return(p);
  61059. }
  61060. mpz_pow_ui(n, n, (unsigned int)(-yval));
  61061. mpq_init(r);
  61062. mpq_set_z(r, n);
  61063. mpq_inv(r, r);
  61064. if (mpz_cmp_ui(mpq_denref(r), 1) == 0)
  61065. {
  61066. mpz_t z;
  61067. mpz_init_set(z, mpq_numref(r));
  61068. mpq_clear(r);
  61069. mpz_clear(n);
  61070. p = mpz_to_big_integer(sc, z);
  61071. mpz_clear(z);
  61072. return(p);
  61073. }
  61074. mpz_clear(n);
  61075. p = mpq_to_big_ratio(sc, r);
  61076. mpq_clear(r);
  61077. return(p);
  61078. }
  61079. if (s7_is_ratio(x)) /* here y is an integer */
  61080. {
  61081. mpz_t n, d;
  61082. mpq_t r;
  61083. x = promote_number(sc, T_BIG_RATIO, x);
  61084. mpz_init_set(n, mpq_numref(big_ratio(x)));
  61085. mpz_init_set(d, mpq_denref(big_ratio(x)));
  61086. mpq_init(r);
  61087. if (yval >= 0)
  61088. {
  61089. mpz_pow_ui(n, n, (unsigned int)yval);
  61090. mpz_pow_ui(d, d, (unsigned int)yval);
  61091. mpq_set_num(r, n);
  61092. mpq_set_den(r, d);
  61093. }
  61094. else
  61095. {
  61096. yval = -yval;
  61097. mpz_pow_ui(n, n, (unsigned int)yval);
  61098. mpz_pow_ui(d, d, (unsigned int)yval);
  61099. mpq_set_num(r, d);
  61100. mpq_set_den(r, n);
  61101. mpq_canonicalize(r);
  61102. }
  61103. mpz_clear(n);
  61104. mpz_clear(d);
  61105. if (mpz_cmp_ui(mpq_denref(r), 1) == 0)
  61106. {
  61107. mpz_t z;
  61108. mpz_init_set(z, mpq_numref(r));
  61109. mpq_clear(r);
  61110. p = mpz_to_big_integer(sc, z);
  61111. mpz_clear(z);
  61112. return(p);
  61113. }
  61114. p = mpq_to_big_ratio(sc, r);
  61115. mpq_clear(r);
  61116. return(p);
  61117. }
  61118. if (s7_is_real(x))
  61119. {
  61120. mpfr_t z;
  61121. x = promote_number(sc, T_BIG_REAL, x);
  61122. mpfr_init_set(z, big_real(x), GMP_RNDN);
  61123. mpfr_pow_si(z, z, yval, GMP_RNDN);
  61124. p = mpfr_to_big_real(sc, z);
  61125. mpfr_clear(z);
  61126. return(p);
  61127. }
  61128. }
  61129. }
  61130. if ((is_t_ratio(y)) && /* not s7_is_ratio which accepts bignums */
  61131. (numerator(y) == 1))
  61132. {
  61133. if (denominator(y) == 2)
  61134. return(big_sqrt(sc, args));
  61135. if ((s7_is_real(x)) &&
  61136. (denominator(y) == 3))
  61137. {
  61138. mpfr_t z;
  61139. mpfr_init_set(z, big_real(promote_number(sc, T_BIG_REAL, x)), GMP_RNDN);
  61140. mpfr_cbrt(z, z, GMP_RNDN);
  61141. p = mpfr_to_big_real(sc, z);
  61142. mpfr_clear(z);
  61143. return(p);
  61144. }
  61145. }
  61146. if ((s7_is_real(x)) &&
  61147. (s7_is_real(y)) &&
  61148. (s7_is_positive(x)))
  61149. {
  61150. mpfr_t z;
  61151. mpfr_init_set(z, big_real(promote_number(sc, T_BIG_REAL, x)), GMP_RNDN);
  61152. mpfr_pow(z, z, big_real(promote_number(sc, T_BIG_REAL, y)), GMP_RNDN);
  61153. p = mpfr_to_big_real(sc, z);
  61154. mpfr_clear(z);
  61155. return(p);
  61156. }
  61157. {
  61158. mpc_t cy;
  61159. mpc_t z;
  61160. x = promote_number(sc, T_BIG_COMPLEX, x);
  61161. y = promote_number(sc, T_BIG_COMPLEX, y);
  61162. mpc_init(z);
  61163. mpc_set(z, big_complex(x), MPC_RNDNN);
  61164. if (mpc_cmp_si_si(z, 0, 0) == 0)
  61165. {
  61166. mpc_clear(z);
  61167. return(small_int(0));
  61168. }
  61169. if (mpc_cmp_si_si(z, 1, 0) == 0)
  61170. {
  61171. mpc_clear(z);
  61172. return(small_int(1));
  61173. }
  61174. mpc_init(cy);
  61175. mpc_set(cy, big_complex(y), MPC_RNDNN);
  61176. mpc_pow(z, z, cy, MPC_RNDNN);
  61177. mpc_clear(cy);
  61178. if (mpfr_cmp_ui(mpc_imagref(z), 0) == 0)
  61179. {
  61180. mpfr_t n;
  61181. if ((s7_is_rational(car(args))) &&
  61182. (s7_is_rational(cadr(args))) &&
  61183. (mpfr_integer_p(mpc_realref(z)) != 0))
  61184. {
  61185. /* mpfr_integer_p can be confused: (expt 2718/1000 (bignum "617/5")) returns an int if precision=128, float if 512 */
  61186. /* so first make sure we're within (say) 31 bits */
  61187. mpfr_t zi;
  61188. mpfr_init_set_ui(zi, s7_int32_max, GMP_RNDN);
  61189. if (mpfr_cmpabs(mpc_realref(z), zi) < 0)
  61190. {
  61191. mpz_t k;
  61192. mpz_init(k);
  61193. mpfr_get_z(k, mpc_realref(z), GMP_RNDN);
  61194. mpc_clear(z);
  61195. mpfr_clear(zi);
  61196. p = mpz_to_big_integer(sc, k);
  61197. mpz_clear(k);
  61198. return(p);
  61199. }
  61200. mpfr_clear(zi);
  61201. }
  61202. mpfr_init_set(n, mpc_realref(z), GMP_RNDN);
  61203. mpc_clear(z);
  61204. p = mpfr_to_big_real(sc, n);
  61205. mpfr_clear(n);
  61206. return(p);
  61207. }
  61208. p = mpc_to_big_complex(sc, z);
  61209. mpc_clear(z);
  61210. return(p);
  61211. }
  61212. }
  61213. static s7_pointer big_asinh(s7_scheme *sc, s7_pointer args)
  61214. {
  61215. #define H_asinh "(asinh z) returns asinh(z)"
  61216. #define Q_asinh pcl_n
  61217. s7_pointer p;
  61218. p = car(args);
  61219. if (!s7_is_number(p))
  61220. method_or_bust_with_type(sc, p, sc->asinh_symbol, args, a_number_string, 0);
  61221. if (s7_is_real(p))
  61222. {
  61223. mpfr_t n;
  61224. p = promote_number(sc, T_BIG_REAL, p);
  61225. mpfr_init_set(n, big_real(p), GMP_RNDN);
  61226. mpfr_asinh(n, n, GMP_RNDN);
  61227. p = mpfr_to_big_real(sc, n);
  61228. mpfr_clear(n);
  61229. return(p);
  61230. }
  61231. {
  61232. mpc_t n;
  61233. p = promote_number(sc, T_BIG_COMPLEX, p);
  61234. mpc_init(n);
  61235. mpc_set(n, big_complex(p), MPC_RNDNN);
  61236. mpc_asinh(n, n, MPC_RNDNN);
  61237. p = mpc_to_big_complex(sc, n);
  61238. mpc_clear(n);
  61239. return(p);
  61240. }
  61241. }
  61242. static s7_pointer big_acosh(s7_scheme *sc, s7_pointer args)
  61243. {
  61244. #define H_acosh "(acosh z) returns acosh(z)"
  61245. #define Q_acosh pcl_n
  61246. s7_pointer p;
  61247. double x;
  61248. mpc_t n;
  61249. p = car(args);
  61250. if (!s7_is_number(p))
  61251. method_or_bust_with_type(sc, p, sc->acosh_symbol, args, a_number_string, 0);
  61252. p = promote_number(sc, T_BIG_COMPLEX, p);
  61253. mpc_init(n);
  61254. mpc_set(n, big_complex(p), MPC_RNDNN);
  61255. mpc_acosh(n, n, MPC_RNDNN);
  61256. x = mpfr_get_d(mpc_imagref(n), GMP_RNDN);
  61257. if (x == 0.0)
  61258. p = mpfr_to_big_real(sc, mpc_realref(n));
  61259. else p = mpc_to_big_complex(sc, n);
  61260. mpc_clear(n);
  61261. return(p);
  61262. }
  61263. static s7_pointer big_atanh(s7_scheme *sc, s7_pointer args)
  61264. {
  61265. #define H_atanh "(atanh z) returns atanh(z)"
  61266. #define Q_atanh pcl_n
  61267. s7_pointer p;
  61268. p = car(args);
  61269. if (!s7_is_number(p))
  61270. method_or_bust_with_type(sc, p, sc->atanh_symbol, args, a_number_string, 0);
  61271. if (s7_is_real(p))
  61272. {
  61273. bool ok;
  61274. mpfr_t temp;
  61275. p = promote_number(sc, T_BIG_REAL, p);
  61276. mpfr_init_set_ui(temp, 1, GMP_RNDN);
  61277. ok = (mpfr_cmpabs(big_real(p), temp) < 0);
  61278. mpfr_clear(temp);
  61279. if (ok)
  61280. {
  61281. mpfr_t n;
  61282. mpfr_init_set(n, big_real(p), GMP_RNDN);
  61283. mpfr_atanh(n, n, GMP_RNDN);
  61284. p = mpfr_to_big_real(sc, n);
  61285. mpfr_clear(n);
  61286. return(p);
  61287. }
  61288. }
  61289. {
  61290. mpc_t n;
  61291. p = promote_number(sc, T_BIG_COMPLEX, p);
  61292. mpc_init(n);
  61293. mpc_set(n, big_complex(p), MPC_RNDNN);
  61294. mpc_atanh(n, n, MPC_RNDNN);
  61295. p = mpc_to_big_complex(sc, n);
  61296. mpc_clear(n);
  61297. return(p);
  61298. }
  61299. }
  61300. static s7_pointer big_atan(s7_scheme *sc, s7_pointer args)
  61301. {
  61302. #define H_atan "(atan z) returns atan(z), (atan y x) returns atan(y/x)"
  61303. #define Q_atan s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_number_symbol, sc->is_real_symbol)
  61304. s7_pointer p0, p1 = NULL, p;
  61305. p0 = car(args);
  61306. if (!s7_is_number(p0))
  61307. method_or_bust_with_type(sc, p0, sc->atan_symbol, args, a_number_string, 0);
  61308. if (is_not_null(cdr(args)))
  61309. {
  61310. p1 = cadr(args);
  61311. if (!s7_is_real(p1))
  61312. method_or_bust(sc, p1, sc->atan_symbol, args, T_REAL, 2);
  61313. if (!s7_is_real(p0))
  61314. return(wrong_type_argument(sc, sc->atan_symbol, 1, p0, T_REAL));
  61315. p1 = promote_number(sc, T_BIG_REAL, p1);
  61316. }
  61317. if (s7_is_real(p0))
  61318. {
  61319. mpfr_t n;
  61320. p0 = promote_number(sc, T_BIG_REAL, p0);
  61321. mpfr_init_set(n, big_real(p0), GMP_RNDN);
  61322. if (!p1)
  61323. mpfr_atan(n, n, GMP_RNDN);
  61324. else mpfr_atan2(n, n, big_real(p1), GMP_RNDN);
  61325. p = mpfr_to_big_real(sc, n);
  61326. mpfr_clear(n);
  61327. return(p);
  61328. }
  61329. {
  61330. mpc_t n;
  61331. p0 = promote_number(sc, T_BIG_COMPLEX, p0);
  61332. mpc_init_set(n, big_complex(p0), MPC_RNDNN);
  61333. mpc_atan(n, n, MPC_RNDNN);
  61334. p = mpc_to_big_complex(sc, n);
  61335. mpc_clear(n);
  61336. return(p);
  61337. }
  61338. }
  61339. static s7_pointer big_acos(s7_scheme *sc, s7_pointer args)
  61340. {
  61341. #define H_acos "(acos z) returns acos(z); (cos (acos 1)) = 1"
  61342. #define Q_acos pcl_n
  61343. s7_pointer p;
  61344. p = car(args);
  61345. if (!s7_is_number(p))
  61346. method_or_bust_with_type(sc, p, sc->acos_symbol, args, a_number_string, 0);
  61347. if (s7_is_real(p))
  61348. {
  61349. bool ok;
  61350. mpfr_t temp;
  61351. mpfr_t n;
  61352. p = promote_number(sc, T_BIG_REAL, p);
  61353. mpfr_init_set(n, big_real(p), GMP_RNDN);
  61354. mpfr_init_set_ui(temp, 1, GMP_RNDN);
  61355. ok = (mpfr_cmpabs(n, temp) <= 0);
  61356. mpfr_clear(temp);
  61357. if (ok)
  61358. {
  61359. mpfr_acos(n, n, GMP_RNDN);
  61360. p = mpfr_to_big_real(sc, n);
  61361. mpfr_clear(n);
  61362. return(p);
  61363. }
  61364. mpfr_clear(n);
  61365. }
  61366. {
  61367. mpc_t n;
  61368. p = promote_number(sc, T_BIG_COMPLEX, p);
  61369. mpc_init_set(n, big_complex(p), MPC_RNDNN);
  61370. mpc_acos(n, n, MPC_RNDNN);
  61371. p = mpc_to_big_complex(sc, n);
  61372. mpc_clear(n);
  61373. return(p);
  61374. }
  61375. }
  61376. static s7_pointer big_asin(s7_scheme *sc, s7_pointer args)
  61377. {
  61378. #define H_asin "(asin z) returns asin(z); (sin (asin 1)) = 1"
  61379. #define Q_asin pcl_n
  61380. s7_pointer p;
  61381. p = car(args);
  61382. if (!s7_is_number(p))
  61383. method_or_bust_with_type(sc, p, sc->asin_symbol, args, a_number_string, 0);
  61384. if (s7_is_real(p))
  61385. {
  61386. bool ok;
  61387. mpfr_t temp;
  61388. mpfr_t n;
  61389. p = promote_number(sc, T_BIG_REAL, p);
  61390. mpfr_init_set(n, big_real(p), GMP_RNDN);
  61391. mpfr_init_set_ui(temp, 1, GMP_RNDN);
  61392. ok = (mpfr_cmpabs(n, temp) <= 0);
  61393. mpfr_clear(temp);
  61394. if (ok)
  61395. {
  61396. mpfr_asin(n, n, GMP_RNDN);
  61397. p = mpfr_to_big_real(sc, n);
  61398. mpfr_clear(n);
  61399. return(p);
  61400. }
  61401. mpfr_clear(n);
  61402. }
  61403. {
  61404. mpc_t n;
  61405. p = promote_number(sc, T_BIG_COMPLEX, p);
  61406. mpc_init_set(n, big_complex(p), MPC_RNDNN);
  61407. mpc_asin(n, n, MPC_RNDNN);
  61408. p = mpc_to_big_complex(sc, n);
  61409. mpc_clear(n);
  61410. return(p);
  61411. }
  61412. }
  61413. static s7_pointer big_lognot(s7_scheme *sc, s7_pointer args)
  61414. {
  61415. if (is_t_big_integer(car(args)))
  61416. {
  61417. s7_pointer p;
  61418. mpz_t n;
  61419. mpz_init(n);
  61420. mpz_com(n, big_integer(car(args)));
  61421. p = mpz_to_big_integer(sc, n);
  61422. mpz_clear(n);
  61423. return(p);
  61424. }
  61425. return(g_lognot(sc, args));
  61426. }
  61427. #if (!WITH_PURE_S7)
  61428. static s7_pointer big_integer_length(s7_scheme *sc, s7_pointer args)
  61429. {
  61430. if (is_t_big_integer(car(args)))
  61431. {
  61432. s7_pointer result;
  61433. mpfr_t n;
  61434. mpfr_init_set_z(n, big_integer(car(args)), GMP_RNDN);
  61435. if (mpfr_cmp_ui(n, 0) < 0)
  61436. mpfr_neg(n, n, GMP_RNDN);
  61437. else mpfr_add_ui(n, n, 1, GMP_RNDN);
  61438. mpfr_log2(n, n, GMP_RNDU);
  61439. result = make_integer(sc, mpfr_get_si(n, GMP_RNDU));
  61440. mpfr_clear(n);
  61441. return(result);
  61442. }
  61443. return(g_integer_length(sc, args));
  61444. }
  61445. #endif
  61446. static s7_pointer big_ash(s7_scheme *sc, s7_pointer args)
  61447. {
  61448. s7_pointer p0, p1;
  61449. p0 = car(args);
  61450. p1 = cadr(args);
  61451. /* here, as in expt, there are cases like (ash 1 63) which need to be handled as bignums
  61452. * so there's no way to tell when it's safe to drop into g_ash instead.
  61453. */
  61454. if ((s7_is_integer(p0)) && /* this includes bignum ints... */
  61455. (s7_is_integer(p1)))
  61456. {
  61457. mpz_t n;
  61458. s7_int shift;
  61459. s7_pointer p;
  61460. bool p0_is_big;
  61461. int p0_compared_to_zero = 0;
  61462. p0_is_big = is_big_number(p0);
  61463. if (p0_is_big)
  61464. p0_compared_to_zero = mpz_cmp_ui(big_integer(p0), 0);
  61465. else
  61466. {
  61467. if (s7_integer(p0) > 0)
  61468. p0_compared_to_zero = 1;
  61469. else
  61470. {
  61471. if (s7_integer(p0) < 0)
  61472. p0_compared_to_zero = -1;
  61473. else p0_compared_to_zero = 0;
  61474. }
  61475. }
  61476. if (p0_compared_to_zero == 0)
  61477. return(small_int(0));
  61478. if (is_big_number(p1))
  61479. {
  61480. if (!mpz_fits_sint_p(big_integer(p1)))
  61481. {
  61482. if (mpz_cmp_ui(big_integer(p1), 0) > 0)
  61483. return(out_of_range(sc, sc->ash_symbol, small_int(2), p1, its_too_large_string));
  61484. /* here if p0 is negative, we need to return -1 */
  61485. if (p0_compared_to_zero == 1)
  61486. return(small_int(0));
  61487. return(minus_one);
  61488. }
  61489. shift = mpz_get_si(big_integer(p1));
  61490. }
  61491. else
  61492. {
  61493. shift = s7_integer(p1);
  61494. if (shift < s7_int32_min)
  61495. {
  61496. if (p0_compared_to_zero == 1)
  61497. return(small_int(0));
  61498. return(minus_one);
  61499. }
  61500. }
  61501. mpz_init_set(n, big_integer(promote_number(sc, T_BIG_INTEGER, p0)));
  61502. if (shift > 0) /* left */
  61503. mpz_mul_2exp(n, n, shift);
  61504. else
  61505. {
  61506. if (shift < 0) /* right */
  61507. mpz_fdiv_q_2exp(n, n, (unsigned int)(-shift));
  61508. }
  61509. p = mpz_to_big_integer(sc, n);
  61510. mpz_clear(n);
  61511. return(p);
  61512. }
  61513. return(g_ash(sc, args));
  61514. }
  61515. static bool is_integer_via_method(s7_scheme *sc, s7_pointer p)
  61516. {
  61517. if (s7_is_integer(p))
  61518. return(true);
  61519. if (has_methods(p))
  61520. {
  61521. s7_pointer f;
  61522. f = find_method(sc, find_let(sc, p), sc->is_integer_symbol);
  61523. if (f != sc->undefined)
  61524. return(is_true(sc, s7_apply_function(sc, f, cons(sc, p, sc->nil))));
  61525. }
  61526. return(false);
  61527. }
  61528. static s7_pointer big_bits(s7_scheme *sc, s7_pointer args, s7_pointer sym, int start, s7_function g_bits,
  61529. void (*mpz_bits)(mpz_ptr, mpz_srcptr, mpz_srcptr))
  61530. {
  61531. s7_pointer x, lst;
  61532. bool use_bigs = false;
  61533. for (x = args; is_not_null(x); x = cdr(x))
  61534. {
  61535. if (!is_integer_via_method(sc, car(x)))
  61536. return(wrong_type_argument(sc, sym, position_of(x, args), car(x), T_INTEGER));
  61537. if (!use_bigs) use_bigs = (type(car(x)) != T_INTEGER);
  61538. }
  61539. if (use_bigs)
  61540. {
  61541. mpz_t n;
  61542. mpz_init_set_si(n, 0);
  61543. if (start == -1)
  61544. mpz_sub_ui(n, n, 1);
  61545. for (x = args; is_not_null(x); x = cdr(x))
  61546. {
  61547. s7_pointer i;
  61548. i = car(x);
  61549. switch (type(i))
  61550. {
  61551. case T_BIG_INTEGER:
  61552. mpz_bits(n, n, big_integer(i));
  61553. break;
  61554. case T_INTEGER:
  61555. mpz_bits(n, n, big_integer(s7_int_to_big_integer(sc, integer(i))));
  61556. break;
  61557. default:
  61558. /* we know it's an integer of some sort, but what about the method */
  61559. lst = cons(sc, mpz_to_big_integer(sc, n), x);
  61560. mpz_clear(n);
  61561. method_or_bust(sc, i, sym, lst, T_INTEGER, position_of(x, args));
  61562. }
  61563. }
  61564. x = mpz_to_big_integer(sc, n);
  61565. mpz_clear(n);
  61566. return(x);
  61567. }
  61568. return(g_bits(sc, args));
  61569. }
  61570. static s7_pointer big_logand(s7_scheme *sc, s7_pointer args)
  61571. {
  61572. if (is_null(args))
  61573. return(minus_one);
  61574. return(big_bits(sc, args, sc->logand_symbol, -1, g_logand, mpz_and));
  61575. }
  61576. static s7_pointer big_logior(s7_scheme *sc, s7_pointer args)
  61577. {
  61578. if (is_null(args))
  61579. return(small_int(0));
  61580. return(big_bits(sc, args, sc->logior_symbol, 0, g_logior, mpz_ior));
  61581. }
  61582. static s7_pointer big_logxor(s7_scheme *sc, s7_pointer args)
  61583. {
  61584. if (is_null(args))
  61585. return(small_int(0));
  61586. return(big_bits(sc, args, sc->logxor_symbol, 0, g_logxor, mpz_xor));
  61587. }
  61588. static s7_pointer big_rationalize(s7_scheme *sc, s7_pointer args)
  61589. {
  61590. #define H_rationalize "(rationalize x err) returns the ratio with lowest denominator within err of x"
  61591. #define Q_rationalize s7_make_signature(sc, 3, sc->is_rational_symbol, sc->is_real_symbol, sc->is_real_symbol)
  61592. /* currently (rationalize 1/0 1e18) -> 0
  61593. * remember to pad with many trailing zeros:
  61594. *
  61595. * : (rationalize 0.1 0)
  61596. * 3602879701896397/36028797018963968
  61597. * :(rationalize 0.1000000000000000 0)
  61598. * 1/10
  61599. *
  61600. * perhaps gmp number reader used if gmp -- could this be the trailing zeros problem? (why is the non-gmp case ok?)
  61601. * also the bignum function is faking it.
  61602. * (rationalize (real-part (bignum "0.1+i")) 0) -> 3602879701896397/36028797018963968
  61603. *
  61604. * a confusing case:
  61605. * > (rationalize 5925563891587147521650777143.74135805596e05)
  61606. * should be 148139097289678688041269428593533951399/250000
  61607. * but that requires more than 128 bits of bignum-precision.
  61608. */
  61609. s7_pointer p0, p1 = NULL, p;
  61610. mpfr_t error, ux, x0, x1;
  61611. mpz_t i, i0, i1;
  61612. double xx;
  61613. p0 = car(args);
  61614. if (!s7_is_real(p0))
  61615. method_or_bust(sc, p0, sc->rationalize_symbol, args, T_REAL, 1);
  61616. /* p0 can be exact, but we still have to check it for simplification */
  61617. if (is_not_null(cdr(args)))
  61618. {
  61619. double err_x;
  61620. p1 = cadr(args);
  61621. if (!s7_is_real(p1)) /* (rationalize (expt 2 60) -) */
  61622. method_or_bust(sc, p1, sc->rationalize_symbol, args, T_REAL, 2);
  61623. if (is_big_number(p1))
  61624. mpfr_init_set(error, big_real(promote_number(sc, T_BIG_REAL, p1)), GMP_RNDN);
  61625. else mpfr_init_set_d(error, real_to_double(sc, p1, "rationalize"), GMP_RNDN);
  61626. err_x = mpfr_get_d(error, GMP_RNDN);
  61627. if (is_NaN(err_x))
  61628. {
  61629. mpfr_clear(error);
  61630. return(out_of_range(sc, sc->rationalize_symbol, small_int(2), cadr(args), its_nan_string));
  61631. }
  61632. if (mpfr_inf_p(error) != 0)
  61633. {
  61634. mpfr_clear(error);
  61635. return(small_int(0));
  61636. }
  61637. mpfr_abs(error, error, GMP_RNDN);
  61638. }
  61639. else mpfr_init_set_d(error, sc->default_rationalize_error, GMP_RNDN);
  61640. if (is_big_number(p0))
  61641. mpfr_init_set(ux, big_real(promote_number(sc, T_BIG_REAL, p0)), GMP_RNDN);
  61642. else mpfr_init_set_d(ux, real_to_double(sc, p0, "rationalize"), GMP_RNDN);
  61643. xx = mpfr_get_d(ux, GMP_RNDN);
  61644. if (is_NaN(xx))
  61645. {
  61646. mpfr_clear(ux);
  61647. mpfr_clear(error);
  61648. return(out_of_range(sc, sc->rationalize_symbol, small_int(1), car(args), its_nan_string));
  61649. }
  61650. if (mpfr_inf_p(ux) != 0)
  61651. {
  61652. mpfr_clear(ux);
  61653. mpfr_clear(error);
  61654. return(out_of_range(sc, sc->rationalize_symbol, small_int(1), car(args), its_infinite_string));
  61655. }
  61656. mpfr_init_set(x0, ux, GMP_RNDN); /* x0 = ux - error */
  61657. mpfr_sub(x0, x0, error, GMP_RNDN);
  61658. mpfr_init_set(x1, ux, GMP_RNDN); /* x1 = ux + error */
  61659. mpfr_add(x1, x1, error, GMP_RNDN);
  61660. mpz_init(i);
  61661. mpfr_get_z(i, x0, GMP_RNDU); /* i = ceil(x0) */
  61662. if (mpfr_cmp_ui(error, 1) >= 0) /* if (error >= 1.0) */
  61663. {
  61664. mpz_t n;
  61665. if (mpfr_cmp_ui(x0, 0) < 0) /* if (x0 < 0) */
  61666. {
  61667. if (mpfr_cmp_ui(x1, 0) < 0) /* if (x1 < 0) */
  61668. {
  61669. mpz_init(n);
  61670. mpfr_get_z(n, x1, GMP_RNDD); /* num = floor(x1) */
  61671. }
  61672. else mpz_init_set_ui(n, 0); /* else num = 0 */
  61673. }
  61674. else mpz_init_set(n, i); /* else num = i */
  61675. mpz_clear(i);
  61676. mpfr_clear(ux);
  61677. mpfr_clear(x0);
  61678. mpfr_clear(x1);
  61679. mpfr_clear(error);
  61680. p = mpz_to_big_integer(sc, n);
  61681. mpz_clear(n);
  61682. return(p);
  61683. }
  61684. if (mpfr_cmp_z(x1, i) >= 0) /* if (x1 >= i) */
  61685. {
  61686. mpz_t n;
  61687. if (mpz_cmp_ui(i, 0) >= 0) /* if (i >= 0) */
  61688. mpz_init_set(n, i); /* num = i */
  61689. else
  61690. {
  61691. mpz_init(n);
  61692. mpfr_get_z(n, x1, GMP_RNDD); /* else num = floor(x1) */
  61693. }
  61694. mpz_clear(i);
  61695. mpfr_clear(ux);
  61696. mpfr_clear(x0);
  61697. mpfr_clear(x1);
  61698. mpfr_clear(error);
  61699. p = mpz_to_big_integer(sc, n);
  61700. mpz_clear(n);
  61701. return(p);
  61702. }
  61703. {
  61704. mpz_t p0, q0, r, r1, p1, q1, old_p1, old_q1;
  61705. mpfr_t val, e0, e1, e0p, e1p, old_e0, old_e1, old_e0p;
  61706. mpz_init(i0);
  61707. mpz_init(i1);
  61708. mpfr_get_z(i0, x0, GMP_RNDD); /* i0 = floor(x0) */
  61709. mpfr_get_z(i1, x1, GMP_RNDU); /* i1 = ceil(x1) */
  61710. mpz_init_set(p0, i0); /* p0 = i0 */
  61711. mpz_init_set_ui(q0, 1); /* q0 = 1 */
  61712. mpz_init_set(p1, i1); /* p1 = i1 */
  61713. mpz_init_set_ui(q1, 1); /* q1 = 1 */
  61714. mpfr_init(e0);
  61715. mpfr_init(e1);
  61716. mpfr_init(e0p);
  61717. mpfr_init(e1p);
  61718. mpfr_sub_z(e0, x0, i1, GMP_RNDN); /* e0 = i1 - x0 */
  61719. mpfr_neg(e0, e0, GMP_RNDN);
  61720. mpfr_sub_z(e1, x0, i0, GMP_RNDN); /* e1 = x0 - i0 */
  61721. mpfr_sub_z(e0p, x1, i1, GMP_RNDN); /* e0p = i1 - x1 */
  61722. mpfr_neg(e0p, e0p, GMP_RNDN);
  61723. mpfr_sub_z(e1p, x1, i0, GMP_RNDN); /* e1p = x1 - i0 */
  61724. mpfr_init(val);
  61725. mpfr_init(old_e0);
  61726. mpfr_init(old_e1);
  61727. mpfr_init(old_e0p);
  61728. mpz_init(r);
  61729. mpz_init(r1);
  61730. mpz_init(old_p1);
  61731. mpz_init(old_q1);
  61732. while (true)
  61733. {
  61734. mpfr_set_z(val, p0, GMP_RNDN);
  61735. mpfr_div_z(val, val, q0, GMP_RNDN); /* val = p0/q0 */
  61736. if (((mpfr_cmp(x0, val) <= 0) && /* if ((x0 <= val) && (val <= x1)) */
  61737. (mpfr_cmp(val, x1) <= 0)) ||
  61738. (mpfr_cmp_ui(e1, 0) == 0) ||
  61739. (mpfr_cmp_ui(e1p, 0) == 0))
  61740. /* these last 2 are probably not needed -- they protect against running out of bits in the non-gmp case above */
  61741. {
  61742. mpq_t q;
  61743. mpq_init(q);
  61744. mpq_set_num(q, p0); /* return(p0/q0) */
  61745. mpq_set_den(q, q0);
  61746. mpz_clear(i);
  61747. mpz_clear(i0);
  61748. mpz_clear(i1);
  61749. mpfr_clear(ux);
  61750. mpfr_clear(x0);
  61751. mpfr_clear(x1);
  61752. mpfr_clear(error);
  61753. mpz_clear(p0);
  61754. mpz_clear(q0);
  61755. mpz_clear(r);
  61756. mpz_clear(r1);
  61757. mpz_clear(p1);
  61758. mpz_clear(q1);
  61759. mpz_clear(old_p1);
  61760. mpz_clear(old_q1);
  61761. mpfr_clear(val);
  61762. mpfr_clear(e0);
  61763. mpfr_clear(e1);
  61764. mpfr_clear(e0p);
  61765. mpfr_clear(e1p);
  61766. mpfr_clear(old_e0);
  61767. mpfr_clear(old_e1);
  61768. mpfr_clear(old_e0p);
  61769. p = mpq_to_big_ratio(sc, q);
  61770. mpq_clear(q);
  61771. return(p);
  61772. }
  61773. mpfr_div(val, e0, e1, GMP_RNDN);
  61774. mpfr_get_z(r, val, GMP_RNDD); /* r = floor(e0/e1) */
  61775. mpfr_div(val, e0p, e1p, GMP_RNDN);
  61776. mpfr_get_z(r1, val, GMP_RNDU); /* r1 = ceil(e0p/e1p) */
  61777. if (mpz_cmp(r1, r) < 0) /* if (r1 < r) */
  61778. mpz_set(r, r1); /* r = r1 */
  61779. mpz_set(old_p1, p1); /* old_p1 = p1 */
  61780. mpz_set(p1, p0); /* p1 = p0 */
  61781. mpz_set(old_q1, q1); /* old_q1 = q1 */
  61782. mpz_set(q1, q0); /* q1 = q0 */
  61783. mpfr_set(old_e0, e0, GMP_RNDN); /* old_e0 = e0 */
  61784. mpfr_set(e0, e1p, GMP_RNDN); /* e0 = e1p */
  61785. mpfr_set(old_e0p, e0p, GMP_RNDN); /* old_e0p = e0p */
  61786. mpfr_set(e0p, e1, GMP_RNDN); /* e0p = e1 */
  61787. mpfr_set(old_e1, e1, GMP_RNDN); /* old_e1 = e1 */
  61788. mpz_mul(p0, p0, r); /* p0 = old_p1 + r * p0 */
  61789. mpz_add(p0, p0, old_p1);
  61790. mpz_mul(q0, q0, r); /* q0 = old_q1 + r * q0 */
  61791. mpz_add(q0, q0, old_q1);
  61792. mpfr_mul_z(e1, e1p, r, GMP_RNDN); /* e1 = old_e0p - r * e1p */
  61793. mpfr_sub(e1, old_e0p, e1, GMP_RNDN);
  61794. mpfr_mul_z(e1p, old_e1, r, GMP_RNDN); /* e1p = old_e0 - r * old_e1 */
  61795. mpfr_sub(e1p, old_e0, e1p, GMP_RNDN);
  61796. }
  61797. }
  61798. }
  61799. #if (!WITH_PURE_S7)
  61800. static s7_pointer big_exact_to_inexact(s7_scheme *sc, s7_pointer args)
  61801. {
  61802. #define H_exact_to_inexact "(exact->inexact num) converts num to an inexact number; (exact->inexact 3/2) = 1.5"
  61803. #define Q_exact_to_inexact pcl_r
  61804. s7_pointer p;
  61805. p = car(args);
  61806. if (!s7_is_number(p)) /* apparently (exact->inexact 1+i) is not an error */
  61807. method_or_bust_with_type(sc, p, sc->exact_to_inexact_symbol, args, a_number_string, 0);
  61808. if (!s7_is_rational(p))
  61809. return(p);
  61810. return(promote_number(sc, T_BIG_REAL, to_big(sc, p)));
  61811. }
  61812. static s7_pointer big_inexact_to_exact(s7_scheme *sc, s7_pointer args)
  61813. {
  61814. #define H_inexact_to_exact "(inexact->exact num) converts num to an exact number; (inexact->exact 1.5) = 3/2"
  61815. #define Q_inexact_to_exact s7_make_signature(sc, 2, sc->is_rational_symbol, sc->is_real_symbol)
  61816. s7_pointer p;
  61817. p = car(args);
  61818. if (s7_is_rational(p))
  61819. return(p);
  61820. if (!s7_is_real(p))
  61821. method_or_bust(sc, p, sc->inexact_to_exact_symbol, args, T_REAL, 0);
  61822. return(big_rationalize(sc, args));
  61823. }
  61824. #endif
  61825. static s7_pointer big_convert_to_int(s7_scheme *sc, s7_pointer args, s7_pointer sym,
  61826. void (*div_func)(mpz_ptr, mpz_srcptr, mpz_srcptr),
  61827. mp_rnd_t mode)
  61828. {
  61829. /* we can't go to the normal (non-gmp) functions here */
  61830. s7_pointer p;
  61831. mpz_t n;
  61832. p = car(args);
  61833. if (!s7_is_real(p))
  61834. method_or_bust(sc, p, sym, args, T_REAL, 0);
  61835. if (s7_is_integer(p))
  61836. return(p);
  61837. p = to_big(sc, p);
  61838. if (is_t_big_ratio(p))
  61839. {
  61840. /* apparently we have to do the divide by hand */
  61841. mpz_t d;
  61842. mpz_init_set(n, mpq_numref(big_ratio(p)));
  61843. mpz_init_set(d, mpq_denref(big_ratio(p)));
  61844. div_func(n, n, d);
  61845. mpz_clear(d);
  61846. }
  61847. else
  61848. {
  61849. if ((g_is_nan(sc, args) == sc->T) ||
  61850. (g_is_infinite(sc, args)) == sc->T)
  61851. return(simple_out_of_range(sc, sym, p, (g_is_nan(sc, args) == sc->T) ? its_nan_string : its_infinite_string));
  61852. mpz_init(n);
  61853. mpfr_get_z(n, big_real(p), mode);
  61854. }
  61855. p = mpz_to_big_integer(sc, n);
  61856. mpz_clear(n);
  61857. return(p);
  61858. }
  61859. static s7_pointer big_floor(s7_scheme *sc, s7_pointer args)
  61860. {
  61861. #define H_floor "(floor x) returns the integer closest to x toward -inf"
  61862. #define Q_floor s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
  61863. return(big_convert_to_int(sc, args, sc->floor_symbol, mpz_fdiv_q, GMP_RNDD));
  61864. }
  61865. static s7_pointer big_ceiling(s7_scheme *sc, s7_pointer args)
  61866. {
  61867. #define H_ceiling "(ceiling x) returns the integer closest to x toward inf"
  61868. #define Q_ceiling s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
  61869. return(big_convert_to_int(sc, args, sc->ceiling_symbol, mpz_cdiv_q, GMP_RNDU));
  61870. }
  61871. static s7_pointer big_truncate(s7_scheme *sc, s7_pointer args)
  61872. {
  61873. #define H_truncate "(truncate x) returns the integer closest to x toward 0"
  61874. #define Q_truncate s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
  61875. return(big_convert_to_int(sc, args, sc->truncate_symbol, mpz_tdiv_q, GMP_RNDZ));
  61876. }
  61877. static s7_pointer big_round(s7_scheme *sc, s7_pointer args)
  61878. {
  61879. #define H_round "(round x) returns the integer closest to x"
  61880. #define Q_round s7_make_signature(sc, 2, sc->is_integer_symbol, sc->is_real_symbol)
  61881. s7_pointer p;
  61882. mpz_t n;
  61883. p = car(args);
  61884. if (!s7_is_real(p))
  61885. method_or_bust(sc, p, sc->round_symbol, args, T_REAL, 0);
  61886. if (s7_is_integer(p))
  61887. return(p);
  61888. p = to_big(sc, p);
  61889. if (is_t_big_integer(p))
  61890. return(p);
  61891. if (is_t_big_ratio(p))
  61892. {
  61893. int rnd;
  61894. mpz_t rm;
  61895. mpz_init_set(n, mpq_numref(big_ratio(p)));
  61896. mpz_init(rm);
  61897. mpz_fdiv_qr(n, rm, n, mpq_denref(big_ratio(p)));
  61898. mpz_mul_ui(rm, rm, 2);
  61899. rnd = mpz_cmpabs(rm, mpq_denref(big_ratio(p)));
  61900. mpz_fdiv_q(rm, rm, mpq_denref(big_ratio(p)));
  61901. if (rnd > 0)
  61902. mpz_add(n, n, rm);
  61903. else
  61904. {
  61905. if (rnd == 0)
  61906. {
  61907. if (mpz_odd_p(n))
  61908. mpz_add_ui(n, n, 1);
  61909. }
  61910. }
  61911. mpz_clear(rm);
  61912. p = mpz_to_big_integer(sc, n);
  61913. mpz_clear(n);
  61914. return(p);
  61915. }
  61916. if ((g_is_nan(sc, args) == sc->T) ||
  61917. (g_is_infinite(sc, args)) == sc->T)
  61918. return(simple_out_of_range(sc, sc->round_symbol, p, (g_is_nan(sc, args) == sc->T) ? its_nan_string : its_infinite_string));
  61919. {
  61920. int cmp_res;
  61921. mpz_t fl, ce;
  61922. mpfr_t x, dfl, dce;
  61923. mpfr_init_set(x, big_real(p), GMP_RNDN);
  61924. mpz_init(fl);
  61925. mpfr_get_z(fl, x, GMP_RNDD); /* fl = floor(x) */
  61926. mpz_init(ce);
  61927. mpfr_get_z(ce, x, GMP_RNDU); /* ce = ceil(x) */
  61928. mpfr_init(dfl);
  61929. mpfr_sub_z(dfl, x, fl, GMP_RNDN); /* dfl = x - fl */
  61930. mpfr_init(dce);
  61931. mpfr_sub_z(dce, x, ce, GMP_RNDN); /* dce = -(ce - x) */
  61932. mpfr_neg(dce, dce, GMP_RNDN); /* and reversed */
  61933. cmp_res = mpfr_cmp(dfl, dce);
  61934. if (cmp_res > 0) /* if (dfl > dce) return(ce) */
  61935. mpz_init_set(n, ce);
  61936. else
  61937. {
  61938. if (cmp_res < 0) /* if (dfl < dce) return(fl) */
  61939. mpz_init_set(n, fl);
  61940. else
  61941. {
  61942. if (mpz_even_p(fl))
  61943. mpz_init_set(n, fl); /* if (mod(fl, 2) == 0) return(fl) */
  61944. else mpz_init_set(n, ce); /* else return(ce) */
  61945. }
  61946. }
  61947. mpz_clear(fl);
  61948. mpz_clear(ce);
  61949. mpfr_clear(dfl);
  61950. mpfr_clear(dce);
  61951. mpfr_clear(x);
  61952. p = mpz_to_big_integer(sc, n);
  61953. mpz_clear(n);
  61954. return(p);
  61955. }
  61956. }
  61957. static s7_pointer big_quotient(s7_scheme *sc, s7_pointer args)
  61958. {
  61959. #define H_quotient "(quotient x1 x2) returns the integer quotient of x1 and x2; (quotient 4 3) = 1"
  61960. #define Q_quotient pcl_r
  61961. s7_pointer x, y, p;
  61962. x = car(args);
  61963. y = cadr(args);
  61964. if (!s7_is_real(x))
  61965. method_or_bust(sc, x, sc->quotient_symbol, args, T_REAL, 1);
  61966. if (!s7_is_real(y))
  61967. method_or_bust(sc, y, sc->quotient_symbol, args, T_REAL, 2);
  61968. if ((s7_is_integer(x)) &&
  61969. (s7_is_integer(y)))
  61970. {
  61971. mpz_t n;
  61972. x = to_big(sc, x);
  61973. y = to_big(sc, y);
  61974. if (s7_is_zero(y))
  61975. return(division_by_zero_error(sc, sc->quotient_symbol, args));
  61976. mpz_init_set(n, big_integer(x));
  61977. mpz_tdiv_q(n, n, big_integer(y));
  61978. p = mpz_to_big_integer(sc, n);
  61979. mpz_clear(n);
  61980. return(p);
  61981. }
  61982. return(big_truncate(sc, set_plist_1(sc, big_divide(sc, args))));
  61983. }
  61984. static s7_pointer big_remainder(s7_scheme *sc, s7_pointer args)
  61985. {
  61986. #define H_remainder "(remainder x1 x2) returns the integer remainder of x1 and x2; (remainder 10 3) = 1"
  61987. #define Q_remainder pcl_r
  61988. s7_pointer x, y, p;
  61989. x = car(args);
  61990. y = cadr(args);
  61991. if (!s7_is_real(x))
  61992. method_or_bust(sc, x, sc->remainder_symbol, args, T_REAL, 1);
  61993. if (!s7_is_real(y))
  61994. method_or_bust(sc, y, sc->remainder_symbol, args, T_REAL, 2);
  61995. if ((s7_is_integer(x)) &&
  61996. (s7_is_integer(y)))
  61997. {
  61998. mpz_t n;
  61999. x = to_big(sc, x);
  62000. y = to_big(sc, y);
  62001. if (s7_is_zero(y))
  62002. return(division_by_zero_error(sc, sc->remainder_symbol, args));
  62003. mpz_init_set(n, big_integer(x));
  62004. mpz_tdiv_r(n, n, big_integer(y));
  62005. p = mpz_to_big_integer(sc, n);
  62006. mpz_clear(n);
  62007. return(p);
  62008. }
  62009. return(big_subtract(sc,
  62010. list_2(sc, x,
  62011. big_multiply(sc,
  62012. set_plist_2(sc, y,
  62013. big_quotient(sc, args))))));
  62014. }
  62015. static s7_pointer big_modulo(s7_scheme *sc, s7_pointer args)
  62016. {
  62017. #define H_modulo "(modulo x1 x2) returns x1 mod x2; (modulo 4 3) = 1. The arguments can be real numbers."
  62018. #define Q_modulo pcl_r
  62019. s7_pointer a, b, p;
  62020. a = car(args);
  62021. if (!s7_is_real(a))
  62022. method_or_bust(sc, a, sc->modulo_symbol, args, T_REAL, 1);
  62023. b = cadr(args);
  62024. if (!s7_is_real(b))
  62025. method_or_bust(sc, b, sc->modulo_symbol, args, T_REAL, 2);
  62026. a = to_big(sc, a);
  62027. b = to_big(sc, b);
  62028. if ((s7_is_integer(a)) &&
  62029. (s7_is_integer(b)))
  62030. {
  62031. s7_pointer x, y;
  62032. int cy, cz;
  62033. mpz_t n;
  62034. y = promote_number(sc, T_BIG_INTEGER, b);
  62035. if (mpz_cmp_ui(big_integer(y), 0) == 0)
  62036. return(a);
  62037. x = promote_number(sc, T_BIG_INTEGER, a);
  62038. /* mpz_mod is too tricky here */
  62039. mpz_init_set(n, big_integer(x));
  62040. mpz_fdiv_r(n, n, big_integer(y));
  62041. cy = mpz_cmp_ui(big_integer(y), 0);
  62042. cz = mpz_cmp_ui(n, 0);
  62043. if (((cy < 0) && (cz > 0)) ||
  62044. ((cy > 0) && (cz < 0)))
  62045. mpz_add(n, n, big_integer(y));
  62046. p = mpz_to_big_integer(sc, n);
  62047. mpz_clear(n);
  62048. return(p);
  62049. }
  62050. return(big_subtract(sc,
  62051. list_2(sc, a,
  62052. big_multiply(sc,
  62053. list_2(sc, b,
  62054. big_floor(sc,
  62055. set_plist_1(sc,
  62056. big_divide(sc,
  62057. set_plist_2(sc, a, b)))))))));
  62058. }
  62059. static int big_real_scan_args(s7_scheme *sc, s7_pointer args)
  62060. {
  62061. int i, result_type = T_INTEGER;
  62062. s7_pointer arg;
  62063. for (i = 1, arg = args; is_not_null(arg); i++, arg = cdr(arg))
  62064. {
  62065. s7_pointer p;
  62066. p = car(arg);
  62067. if (!is_real_via_method(sc, p))
  62068. return(-i);
  62069. result_type = get_result_type(sc, result_type, p);
  62070. }
  62071. return(result_type);
  62072. }
  62073. static s7_pointer big_max(s7_scheme *sc, s7_pointer args)
  62074. {
  62075. int result_type;
  62076. s7_pointer x, result, arg;
  62077. result_type = big_real_scan_args(sc, args);
  62078. if (result_type < 0)
  62079. return(wrong_type_argument(sc, sc->max_symbol, -result_type, s7_list_ref(sc, args, -1 - result_type), T_REAL));
  62080. if (result_type < T_BIG_INTEGER)
  62081. return(g_max(sc, args));
  62082. if (!s7_is_number(car(args)))
  62083. check_method(sc, car(args), sc->max_symbol, args);
  62084. result = promote_number(sc, result_type, car(args));
  62085. for (x = cdr(args); is_not_null(x); x = cdr(x))
  62086. {
  62087. if (!s7_is_number(car(x)))
  62088. check_method(sc, car(x), sc->max_symbol, cons(sc, result, x));
  62089. arg = promote_number(sc, result_type, car(x));
  62090. switch (result_type)
  62091. {
  62092. case T_BIG_INTEGER: if (mpz_cmp(big_integer(result), big_integer(arg)) < 0) result = arg; break;
  62093. case T_BIG_RATIO: if (mpq_cmp(big_ratio(result), big_ratio(arg)) < 0) result = arg; break;
  62094. case T_BIG_REAL: if (mpfr_cmp(big_real(result), big_real(arg)) < 0) result = arg; break;
  62095. }
  62096. }
  62097. if (result_type == T_BIG_RATIO) /* maybe actual result was an int */
  62098. {
  62099. if (mpz_cmp_ui(mpq_denref(big_ratio(result)), 1) == 0)
  62100. {
  62101. mpz_t n;
  62102. s7_pointer p;
  62103. mpz_init_set(n, mpq_numref(big_ratio(result)));
  62104. p = mpz_to_big_integer(sc, n);
  62105. mpz_clear(n);
  62106. return(p);
  62107. }
  62108. }
  62109. return(result);
  62110. }
  62111. static s7_pointer big_min(s7_scheme *sc, s7_pointer args)
  62112. {
  62113. int result_type;
  62114. s7_pointer x, result, arg;
  62115. result_type = big_real_scan_args(sc, args);
  62116. if (result_type < 0)
  62117. return(wrong_type_argument(sc, sc->min_symbol, -result_type, s7_list_ref(sc, args, -1 - result_type), T_REAL));
  62118. if (result_type < T_BIG_INTEGER)
  62119. return(g_min(sc, args));
  62120. if (!s7_is_number(car(args)))
  62121. check_method(sc, car(args), sc->min_symbol, args);
  62122. result = promote_number(sc, result_type, car(args));
  62123. for (x = cdr(args); is_not_null(x); x = cdr(x))
  62124. {
  62125. if (!s7_is_number(car(x)))
  62126. check_method(sc, car(x), sc->min_symbol, cons(sc, result, x));
  62127. arg = promote_number(sc, result_type, car(x));
  62128. switch (result_type)
  62129. {
  62130. case T_BIG_INTEGER: if (mpz_cmp(big_integer(result), big_integer(arg)) > 0) result = arg; break;
  62131. case T_BIG_RATIO: if (mpq_cmp(big_ratio(result), big_ratio(arg)) > 0) result = arg; break;
  62132. case T_BIG_REAL: if (mpfr_cmp(big_real(result), big_real(arg)) > 0) result = arg; break;
  62133. }
  62134. }
  62135. if (result_type == T_BIG_RATIO) /* maybe actual result was an int */
  62136. {
  62137. if (mpz_cmp_ui(mpq_denref(big_ratio(result)), 1) == 0)
  62138. {
  62139. mpz_t n;
  62140. s7_pointer p;
  62141. mpz_init_set(n, mpq_numref(big_ratio(result)));
  62142. p = mpz_to_big_integer(sc, n);
  62143. mpz_clear(n);
  62144. return(p);
  62145. }
  62146. }
  62147. return(result);
  62148. }
  62149. static s7_pointer big_less(s7_scheme *sc, s7_pointer args)
  62150. {
  62151. #define H_less "(< x1 ...) returns #t if its arguments are in increasing order"
  62152. #define Q_less s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  62153. int result_type;
  62154. s7_pointer x, previous, current;
  62155. result_type = big_real_scan_args(sc, args);
  62156. if (result_type < 0)
  62157. return(wrong_type_argument(sc, sc->lt_symbol, -result_type, s7_list_ref(sc, args, -1 - result_type), T_REAL));
  62158. /* don't try to use g_less here */
  62159. if (result_type < T_BIG_INTEGER)
  62160. result_type += 4;
  62161. if (!s7_is_number(car(args)))
  62162. check_method(sc, car(args), sc->lt_symbol, args);
  62163. previous = promote_number(sc, result_type, car(args));
  62164. for (x = cdr(args); is_not_null(x); x = cdr(x))
  62165. {
  62166. if (!s7_is_number(car(x)))
  62167. check_method(sc, car(x), sc->lt_symbol, cons(sc, previous, x));
  62168. current = promote_number(sc, result_type, car(x));
  62169. switch (result_type)
  62170. {
  62171. case T_BIG_INTEGER: if (mpz_cmp(big_integer(previous), big_integer(current)) >= 0) return(sc->F); break;
  62172. case T_BIG_RATIO: if (mpq_cmp(big_ratio(previous), big_ratio(current)) >= 0) return(sc->F); break;
  62173. case T_BIG_REAL: if (mpfr_cmp(big_real(previous), big_real(current)) >= 0) return(sc->F); break;
  62174. }
  62175. previous = current;
  62176. }
  62177. return(sc->T);
  62178. }
  62179. static s7_pointer big_less_or_equal(s7_scheme *sc, s7_pointer args)
  62180. {
  62181. #define H_less_or_equal "(<= x1 ...) returns #t if its arguments are in increasing order"
  62182. #define Q_less_or_equal s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  62183. int result_type;
  62184. s7_pointer x, previous, current;
  62185. result_type = big_real_scan_args(sc, args);
  62186. if (result_type < 0)
  62187. return(wrong_type_argument(sc, sc->leq_symbol, -result_type, s7_list_ref(sc, args, -1 - result_type), T_REAL));
  62188. if (result_type < T_BIG_INTEGER)
  62189. result_type += 4;
  62190. if (!s7_is_number(car(args)))
  62191. check_method(sc, car(args), sc->leq_symbol, args);
  62192. previous = promote_number(sc, result_type, car(args));
  62193. for (x = cdr(args); is_not_null(x); x = cdr(x))
  62194. {
  62195. if (!s7_is_number(car(x)))
  62196. check_method(sc, car(x), sc->leq_symbol, cons(sc, previous, x));
  62197. current = promote_number(sc, result_type, car(x));
  62198. switch (result_type)
  62199. {
  62200. case T_BIG_INTEGER: if (mpz_cmp(big_integer(previous), big_integer(current)) > 0) return(sc->F); break;
  62201. case T_BIG_RATIO: if (mpq_cmp(big_ratio(previous), big_ratio(current)) > 0) return(sc->F); break;
  62202. case T_BIG_REAL: if (mpfr_cmp(big_real(previous), big_real(current)) > 0) return(sc->F); break;
  62203. }
  62204. previous = current;
  62205. }
  62206. return(sc->T);
  62207. }
  62208. static s7_pointer big_greater(s7_scheme *sc, s7_pointer args)
  62209. {
  62210. #define H_greater "(> x1 ...) returns #t if its arguments are in decreasing order"
  62211. #define Q_greater s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  62212. int result_type;
  62213. s7_pointer x, previous, current;
  62214. result_type = big_real_scan_args(sc, args);
  62215. if (result_type < 0)
  62216. return(wrong_type_argument(sc, sc->gt_symbol, -result_type, s7_list_ref(sc, args, -1 - result_type), T_REAL));
  62217. if (result_type < T_BIG_INTEGER)
  62218. result_type += 4;
  62219. if (!s7_is_number(car(args)))
  62220. check_method(sc, car(args), sc->gt_symbol, args);
  62221. previous = promote_number(sc, result_type, car(args));
  62222. for (x = cdr(args); is_not_null(x); x = cdr(x))
  62223. {
  62224. if (!s7_is_number(car(x)))
  62225. check_method(sc, car(x), sc->gt_symbol, cons(sc, previous, x));
  62226. current = promote_number(sc, result_type, car(x));
  62227. switch (result_type)
  62228. {
  62229. case T_BIG_INTEGER: if (mpz_cmp(big_integer(previous), big_integer(current)) <= 0) return(sc->F); break;
  62230. case T_BIG_RATIO: if (mpq_cmp(big_ratio(previous), big_ratio(current)) <= 0) return(sc->F); break;
  62231. case T_BIG_REAL: if (mpfr_cmp(big_real(previous), big_real(current)) <= 0) return(sc->F); break;
  62232. }
  62233. previous = current;
  62234. }
  62235. return(sc->T);
  62236. }
  62237. static s7_pointer big_greater_or_equal(s7_scheme *sc, s7_pointer args)
  62238. {
  62239. #define H_greater_or_equal "(>= x1 ...) returns #t if its arguments are in decreasing order"
  62240. #define Q_greater_or_equal s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_real_symbol)
  62241. int result_type;
  62242. s7_pointer x, previous, current;
  62243. result_type = big_real_scan_args(sc, args);
  62244. if (result_type < 0)
  62245. return(wrong_type_argument(sc, sc->geq_symbol, -result_type, s7_list_ref(sc, args, -1 - result_type), T_REAL));
  62246. if (result_type < T_BIG_INTEGER)
  62247. result_type += 4;
  62248. if (!s7_is_number(car(args)))
  62249. check_method(sc, car(args), sc->geq_symbol, args);
  62250. previous = promote_number(sc, result_type, car(args));
  62251. for (x = cdr(args); is_not_null(x); x = cdr(x))
  62252. {
  62253. if (!s7_is_number(car(x)))
  62254. check_method(sc, car(x), sc->geq_symbol, cons(sc, previous, x));
  62255. current = promote_number(sc, result_type, car(x));
  62256. switch (result_type)
  62257. {
  62258. case T_BIG_INTEGER: if (mpz_cmp(big_integer(previous), big_integer(current)) < 0) return(sc->F); break;
  62259. case T_BIG_RATIO: if (mpq_cmp(big_ratio(previous), big_ratio(current)) < 0) return(sc->F); break;
  62260. case T_BIG_REAL: if (mpfr_cmp(big_real(previous), big_real(current)) < 0) return(sc->F); break;
  62261. }
  62262. previous = current;
  62263. }
  62264. return(sc->T);
  62265. }
  62266. static s7_pointer big_equal(s7_scheme *sc, s7_pointer args)
  62267. {
  62268. #define Q_equal s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_number_symbol)
  62269. /* this is morally-equal? for bignums, the other case goes through big_numbers_are_eqv */
  62270. int result_type = T_INTEGER;
  62271. s7_pointer x, y, result;
  62272. bool got_nan = false;
  62273. for (x = args; is_not_null(x); x = cdr(x))
  62274. {
  62275. s7_pointer p;
  62276. p = car(x);
  62277. if (!s7_is_number(p))
  62278. {
  62279. check_method(sc, car(args), sc->eq_symbol, x);
  62280. return(wrong_type_argument_with_type(sc, sc->eq_symbol, position_of(x, args), p, a_number_string));
  62281. }
  62282. result_type = get_result_type(sc, result_type, p);
  62283. if (!got_nan)
  62284. got_nan = (((is_t_real(p)) && (is_NaN(real(p)))) || /* (= (bignum "3") 1/0) */
  62285. ((is_t_complex(p)) && ((is_NaN(real_part(p))) || (is_NaN(imag_part(p))))));
  62286. }
  62287. if (got_nan) return(sc->F); /* put this off until here so that non-numbers anywhere in the arg list will raise an error */
  62288. if (result_type < T_BIG_INTEGER)
  62289. return(g_equal(sc, args));
  62290. result = promote_number(sc, result_type, car(args));
  62291. for (y = cdr(args); is_not_null(y); y = cdr(y))
  62292. {
  62293. s7_pointer arg;
  62294. arg = promote_number(sc, result_type, car(y));
  62295. switch (result_type)
  62296. {
  62297. case T_BIG_INTEGER:
  62298. if (mpz_cmp(big_integer(result), big_integer(arg)) != 0) return(sc->F);
  62299. break;
  62300. case T_BIG_RATIO:
  62301. if (mpq_cmp(big_ratio(result), big_ratio(arg)) != 0) return(sc->F);
  62302. break;
  62303. case T_BIG_REAL:
  62304. {
  62305. mpfr_t *a1;
  62306. a1 = s7_double_to_mpfr(sc->morally_equal_float_epsilon);
  62307. if (mpfr_cmp(big_real(big_abs(sc, set_plist_1(sc, big_subtract(sc, set_plist_2(sc, result, arg))))), *a1) > 0)
  62308. return(sc->F);
  62309. }
  62310. break;
  62311. case T_BIG_COMPLEX:
  62312. {
  62313. mpfr_t *a1;
  62314. a1 = s7_double_to_mpfr(sc->morally_equal_float_epsilon);
  62315. if (mpfr_cmp(big_real(big_magnitude(sc, set_plist_1(sc, big_subtract(sc, set_plist_2(sc, result, arg))))), *a1) > 0)
  62316. return(sc->F);
  62317. }
  62318. break;
  62319. }
  62320. }
  62321. return(sc->T);
  62322. }
  62323. static s7_pointer big_gcd(s7_scheme *sc, s7_pointer args)
  62324. {
  62325. #define H_gcd "(gcd ...) returns the greatest common divisor of its rational arguments"
  62326. #define Q_gcd pcl_f
  62327. bool rats = false;
  62328. s7_pointer x, lst;
  62329. for (x = args; is_not_null(x); x = cdr(x))
  62330. {
  62331. if (!is_rational_via_method(sc, car(x)))
  62332. return(wrong_type_argument_with_type(sc, sc->gcd_symbol, position_of(x, args), car(x), a_rational_string));
  62333. if (!rats)
  62334. rats = (!is_integer_via_method(sc, car(x)));
  62335. }
  62336. if (is_null(cdr(args))) /* (gcd -2305843009213693951/4611686018427387903) */
  62337. return(big_abs(sc, args));
  62338. if (!rats)
  62339. {
  62340. mpz_t n;
  62341. mpz_init(n);
  62342. for (x = args; is_not_null(x); x = cdr(x))
  62343. {
  62344. if (!s7_is_number(car(x)))
  62345. {
  62346. lst = cons(sc, mpz_to_big_integer(sc, n), x);
  62347. mpz_clear(n);
  62348. method_or_bust(sc, car(x), sc->gcd_symbol, lst, T_INTEGER, position_of(x, args));
  62349. }
  62350. mpz_gcd(n, n, big_integer(promote_number(sc, T_BIG_INTEGER, car(x))));
  62351. if (mpz_cmp_ui(n, 1) == 0)
  62352. {
  62353. mpz_clear(n);
  62354. return(small_int(1));
  62355. }
  62356. }
  62357. x = mpz_to_big_integer(sc, n);
  62358. mpz_clear(n);
  62359. return(x);
  62360. }
  62361. {
  62362. s7_pointer rat;
  62363. mpq_t q;
  62364. mpz_t n, d;
  62365. if (!s7_is_number(car(args)))
  62366. check_method(sc, car(args), sc->gcd_symbol, args);
  62367. rat = promote_number(sc, T_BIG_RATIO, car(args));
  62368. mpz_init_set(n, mpq_numref(big_ratio(rat)));
  62369. mpz_init_set(d, mpq_denref(big_ratio(rat)));
  62370. for (x = cdr(args); is_not_null(x); x = cdr(x))
  62371. {
  62372. if (!s7_is_number(car(x)))
  62373. {
  62374. mpq_init(q);
  62375. mpq_set_num(q, n);
  62376. mpq_set_den(q, d);
  62377. lst = cons(sc, mpq_to_big_ratio(sc, q), x);
  62378. mpz_clear(n);
  62379. mpz_clear(d);
  62380. mpq_clear(q);
  62381. method_or_bust_with_type(sc, car(x), sc->gcd_symbol, lst, a_rational_string, position_of(x, args));
  62382. }
  62383. rat = promote_number(sc, T_BIG_RATIO, car(x));
  62384. mpz_gcd(n, n, mpq_numref(big_ratio(rat)));
  62385. mpz_lcm(d, d, mpq_denref(big_ratio(rat)));
  62386. }
  62387. if (mpz_cmp_ui(d, 1) == 0)
  62388. {
  62389. rat = mpz_to_big_integer(sc, n);
  62390. mpz_clear(n);
  62391. mpz_clear(d);
  62392. return(rat);
  62393. }
  62394. mpq_init(q);
  62395. mpq_set_num(q, n);
  62396. mpq_set_den(q, d);
  62397. mpz_clear(n);
  62398. mpz_clear(d);
  62399. x = mpq_to_big_ratio(sc, q);
  62400. mpq_clear(q);
  62401. return(x);
  62402. }
  62403. }
  62404. static s7_pointer big_lcm(s7_scheme *sc, s7_pointer args)
  62405. {
  62406. #define H_lcm "(lcm ...) returns the least common multiple of its rational arguments"
  62407. #define Q_lcm pcl_f
  62408. s7_pointer x, lst;
  62409. bool rats = false;
  62410. for (x = args; is_not_null(x); x = cdr(x))
  62411. {
  62412. if (!is_rational_via_method(sc, car(x)))
  62413. return(wrong_type_argument_with_type(sc, sc->lcm_symbol, position_of(x, args), car(x), a_rational_string));
  62414. if (!rats)
  62415. rats = (!is_integer_via_method(sc, car(x)));
  62416. }
  62417. if (is_null(cdr(args))) /* (lcm -2305843009213693951/4611686018427387903) */
  62418. return(big_abs(sc, args));
  62419. if (!rats)
  62420. {
  62421. mpz_t n;
  62422. mpz_init(n);
  62423. mpz_set_ui(n, 1);
  62424. for (x = args; is_not_null(x); x = cdr(x))
  62425. {
  62426. if (!s7_is_number(car(x)))
  62427. {
  62428. lst = cons(sc, mpz_to_big_integer(sc, n), x);
  62429. mpz_clear(n);
  62430. method_or_bust(sc, car(x), sc->lcm_symbol, lst, T_INTEGER, position_of(x, args));
  62431. }
  62432. mpz_lcm(n, n, big_integer(promote_number(sc, T_BIG_INTEGER, car(x))));
  62433. if (mpz_cmp_ui(n, 0) == 0)
  62434. {
  62435. mpz_clear(n);
  62436. return(small_int(0));
  62437. }
  62438. }
  62439. x = mpz_to_big_integer(sc, n);
  62440. mpz_clear(n);
  62441. return(x);
  62442. }
  62443. {
  62444. s7_pointer rat;
  62445. mpq_t q;
  62446. mpz_t n, d;
  62447. if (!s7_is_number(car(args)))
  62448. check_method(sc, car(args), sc->lcm_symbol, args);
  62449. rat = promote_number(sc, T_BIG_RATIO, car(args));
  62450. mpz_init_set(n, mpq_numref(big_ratio(rat)));
  62451. if (mpz_cmp_ui(n, 0) == 0)
  62452. {
  62453. mpz_clear(n);
  62454. return(small_int(0));
  62455. }
  62456. mpz_init_set(d, mpq_denref(big_ratio(rat)));
  62457. for (x = cdr(args); is_not_null(x); x = cdr(x))
  62458. {
  62459. if (!s7_is_number(car(x)))
  62460. {
  62461. mpq_init(q);
  62462. mpq_set_num(q, n);
  62463. mpq_set_den(q, d);
  62464. lst = cons(sc, mpq_to_big_ratio(sc, q), x);
  62465. mpz_clear(n);
  62466. mpz_clear(d);
  62467. mpq_clear(q);
  62468. method_or_bust_with_type(sc, car(x), sc->lcm_symbol, lst, a_rational_string, position_of(x, args));
  62469. }
  62470. rat = promote_number(sc, T_BIG_RATIO, car(x));
  62471. mpz_lcm(n, n, mpq_numref(big_ratio(rat)));
  62472. if (mpz_cmp_ui(n, 0) == 0)
  62473. {
  62474. mpz_clear(n);
  62475. mpz_clear(d);
  62476. return(small_int(0));
  62477. }
  62478. mpz_gcd(d, d, mpq_denref(big_ratio(rat)));
  62479. }
  62480. if (mpz_cmp_ui(d, 1) == 0)
  62481. {
  62482. rat = mpz_to_big_integer(sc, n);
  62483. mpz_clear(n);
  62484. mpz_clear(d);
  62485. return(rat);
  62486. }
  62487. mpq_init(q);
  62488. mpq_set_num(q, n);
  62489. mpq_set_den(q, d);
  62490. mpz_clear(n);
  62491. mpz_clear(d);
  62492. x = mpq_to_big_ratio(sc, q);
  62493. mpq_clear(q);
  62494. return(x);
  62495. }
  62496. }
  62497. static s7_pointer set_bignum_precision(s7_scheme *sc, int precision)
  62498. {
  62499. mp_prec_t bits;
  62500. if (precision <= 1) /* (set! (*s7* 'bignum-precision) 1) causes mpfr to segfault! (also 0 and -1) */
  62501. return(s7_out_of_range_error(sc, "set! (*s7* 'bignum-precision)", 0, make_integer(sc, precision), "has to be greater than 1"));
  62502. bits = (mp_prec_t)precision;
  62503. mpfr_set_default_prec(bits);
  62504. mpc_set_default_precision(bits);
  62505. s7_symbol_set_value(sc, sc->pi_symbol, big_pi(sc));
  62506. return(sc->F);
  62507. }
  62508. static s7_pointer big_random_state(s7_scheme *sc, s7_pointer args)
  62509. {
  62510. #define H_random_state "(random-state seed) returns a new random number state initialized with 'seed'. \
  62511. Pass this as the second argument to 'random' to get a repeatable random number sequence:\n\
  62512. (let ((seed (random-state 1234))) (random 1.0 seed))"
  62513. #define Q_random_state s7_make_circular_signature(sc, 1, 2, sc->is_random_state_symbol, sc->is_integer_symbol)
  62514. s7_pointer r, seed;
  62515. seed = car(args);
  62516. if (!s7_is_integer(seed))
  62517. method_or_bust(sc, seed, sc->random_state_symbol, args, T_INTEGER, 0);
  62518. if (type(seed) != T_BIG_INTEGER)
  62519. seed = promote_number(sc, T_BIG_INTEGER, seed);
  62520. new_cell(sc, r, T_RANDOM_STATE);
  62521. gmp_randinit_default(random_gmp_state(r));
  62522. gmp_randseed(random_gmp_state(r), big_integer(seed));
  62523. return(r);
  62524. }
  62525. static s7_pointer big_random(s7_scheme *sc, s7_pointer args)
  62526. {
  62527. #define H_random "(random num (state #f)) returns a random number between 0 and num (0 if num=0)."
  62528. #define Q_random s7_make_signature(sc, 3, sc->is_number_symbol, sc->is_number_symbol, sc->is_random_state_symbol)
  62529. s7_pointer num, state, x;
  62530. num = car(args);
  62531. if (!s7_is_number(num))
  62532. method_or_bust_with_type(sc, num, sc->random_symbol, args, a_number_string, 1);
  62533. state = sc->default_rng;
  62534. if (is_not_null(cdr(args)))
  62535. {
  62536. state = cadr(args);
  62537. if (!is_random_state(state))
  62538. return(wrong_type_argument_with_type(sc, sc->random_symbol, 2, state, a_random_state_object_string));
  62539. }
  62540. if (s7_is_zero(num))
  62541. return(num);
  62542. if (!is_big_number(num))
  62543. {
  62544. switch (type(num))
  62545. {
  62546. case T_INTEGER: num = promote_number(sc, T_BIG_INTEGER, num); break;
  62547. case T_RATIO: num = promote_number(sc, T_BIG_RATIO, num); break;
  62548. case T_REAL: num = promote_number(sc, T_BIG_REAL, num); break;
  62549. default: num = promote_number(sc, T_BIG_COMPLEX, num); break;
  62550. }
  62551. }
  62552. switch (type(num))
  62553. {
  62554. case T_BIG_INTEGER:
  62555. {
  62556. mpz_t n;
  62557. mpz_init(n);
  62558. mpz_urandomm(n, random_gmp_state(state), big_integer(num));
  62559. /* this does not work if num is a negative number -- you get positive results.
  62560. * so check num for sign, and negate result if necessary.
  62561. */
  62562. if (mpz_cmp_ui(big_integer(num), 0) < 0)
  62563. mpz_neg(n, n);
  62564. x = mpz_to_big_integer(sc, n);
  62565. mpz_clear(n);
  62566. return(x);
  62567. }
  62568. case T_BIG_RATIO:
  62569. {
  62570. mpfr_t n, e;
  62571. mpfr_t rat;
  62572. mpfr_init_set_ui(n, 1, GMP_RNDN);
  62573. mpfr_urandomb(n, random_gmp_state(state));
  62574. mpfr_init_set_q(rat, big_ratio(num), GMP_RNDN);
  62575. mpfr_mul(n, n, rat, GMP_RNDN);
  62576. mpfr_init_set_str(e, "0.0000001", 10, GMP_RNDN);
  62577. mpfr_mul(e, e, rat, GMP_RNDN);
  62578. mpfr_clear(rat);
  62579. /* as in g_random, small ratios are a problem because the error term (sc->default_rationalize_error = 1e-12 here)
  62580. * clobbers everything to 0.
  62581. */
  62582. x = big_rationalize(sc, set_plist_2(sc, mpfr_to_big_real(sc, n), mpfr_to_big_real(sc, e)));
  62583. mpfr_clear(n);
  62584. mpfr_clear(e);
  62585. return(x);
  62586. }
  62587. case T_BIG_REAL:
  62588. {
  62589. mpfr_t n;
  62590. mpfr_init_set_ui(n, 1, GMP_RNDN);
  62591. mpfr_urandomb(n, random_gmp_state(state));
  62592. mpfr_mul(n, n, big_real(num), GMP_RNDN);
  62593. x = mpfr_to_big_real(sc, n);
  62594. mpfr_clear(n);
  62595. return(x);
  62596. }
  62597. case T_BIG_COMPLEX:
  62598. {
  62599. mpc_t n;
  62600. mpc_init(n);
  62601. mpc_urandom(n, random_gmp_state(state));
  62602. mpfr_mul(mpc_realref(n), mpc_realref(n), mpc_realref(big_complex(num)), GMP_RNDN);
  62603. mpfr_mul(mpc_imagref(n), mpc_imagref(n), mpc_imagref(big_complex(num)), GMP_RNDN);
  62604. x = mpc_to_big_complex(sc, n);
  62605. mpc_clear(n);
  62606. return(x);
  62607. }
  62608. }
  62609. return(sc->F); /* make the compiler happy */
  62610. }
  62611. s7_double s7_random(s7_scheme *sc, s7_pointer state)
  62612. {
  62613. s7_pointer p;
  62614. p = big_random(sc, set_plist_1(sc, (state) ? state : sc->default_rng));
  62615. return((s7_double)mpfr_get_d(big_real(p), GMP_RNDN));
  62616. }
  62617. static void s7_gmp_init(s7_scheme *sc)
  62618. {
  62619. #define big_defun(Scheme_Name, C_Name, Req, Opt, Rst) s7_define_typed_function(sc, Scheme_Name, big_ ## C_Name, Req, Opt, Rst, H_ ## C_Name, Q_ ## C_Name)
  62620. #define c_big_defun(Scheme_Name, C_Name, Req, Opt, Rst) s7_define_typed_function(sc, Scheme_Name, c_big_ ## C_Name, Req, Opt, Rst, H_ ## C_Name, Q_ ## C_Name)
  62621. sc->add_symbol = big_defun("+", add, 0, 0, true);
  62622. sc->subtract_symbol = big_defun("-", subtract, 1, 0, true);
  62623. sc->multiply_symbol = big_defun("*", multiply, 0, 0, true);
  62624. sc->divide_symbol = big_defun("/", divide, 1, 0, true);
  62625. sc->max_symbol = big_defun("max", max, 1, 0, true);
  62626. sc->min_symbol = big_defun("min", min, 1, 0, true);
  62627. sc->lt_symbol = big_defun("<", less, 2, 0, true);
  62628. sc->leq_symbol = big_defun("<=", less_or_equal, 2, 0, true);
  62629. sc->gt_symbol = big_defun(">", greater, 2, 0, true);
  62630. sc->geq_symbol = big_defun(">=", greater_or_equal, 2, 0, true);
  62631. sc->eq_symbol = big_defun("=", equal, 2, 0, true);
  62632. sc->rationalize_symbol = big_defun("rationalize", rationalize, 1, 1, false);
  62633. #if (!WITH_PURE_S7)
  62634. sc->exact_to_inexact_symbol = big_defun("exact->inexact", exact_to_inexact, 1, 0, false);
  62635. sc->inexact_to_exact_symbol = big_defun("inexact->exact", inexact_to_exact, 1, 0, false);
  62636. sc->integer_length_symbol = big_defun("integer-length", integer_length, 1, 0, false);
  62637. sc->make_rectangular_symbol = c_big_defun("make-rectangular", complex, 2, 0, false);
  62638. sc->make_polar_symbol = big_defun("make-polar", make_polar, 2, 0, false);
  62639. #endif
  62640. sc->floor_symbol = big_defun("floor", floor, 1, 0, false);
  62641. sc->ceiling_symbol = big_defun("ceiling", ceiling, 1, 0, false);
  62642. sc->truncate_symbol = big_defun("truncate", truncate, 1, 0, false);
  62643. sc->round_symbol = big_defun("round", round, 1, 0, false);
  62644. sc->quotient_symbol = big_defun("quotient", quotient, 2, 0, false);
  62645. sc->remainder_symbol = big_defun("remainder", remainder, 2, 0, false);
  62646. sc->modulo_symbol = big_defun("modulo", modulo, 2, 0, false);
  62647. sc->gcd_symbol = big_defun("gcd", gcd, 0, 0, true);
  62648. sc->lcm_symbol = big_defun("lcm", lcm, 0, 0, true);
  62649. sc->complex_symbol = c_big_defun("complex", complex, 2, 0, false);
  62650. sc->magnitude_symbol = big_defun("magnitude", magnitude, 1, 0, false);
  62651. sc->angle_symbol = big_defun("angle", angle, 1, 0, false);
  62652. sc->abs_symbol = big_defun("abs", abs, 1, 0, false);
  62653. sc->lognot_symbol = big_defun("lognot", lognot, 1, 0, false);
  62654. sc->logior_symbol = big_defun("logior", logior, 0, 0, true);
  62655. sc->logxor_symbol = big_defun("logxor", logxor, 0, 0, true);
  62656. sc->logand_symbol = big_defun("logand", logand, 0, 0, true);
  62657. sc->ash_symbol = big_defun("ash", ash, 2, 0, false);
  62658. sc->exp_symbol = big_defun("exp", exp, 1, 0, false);
  62659. sc->expt_symbol = big_defun("expt", expt, 2, 0, false);
  62660. sc->log_symbol = big_defun("log", log, 1, 1, false);
  62661. sc->sqrt_symbol = big_defun("sqrt", sqrt, 1, 0, false);
  62662. sc->sin_symbol = big_defun("sin", sin, 1, 0, false);
  62663. sc->cos_symbol = big_defun("cos", cos, 1, 0, false);
  62664. sc->tan_symbol = big_defun("tan", tan, 1, 0, false);
  62665. sc->asin_symbol = big_defun("asin", asin, 1, 0, false);
  62666. sc->acos_symbol = big_defun("acos", acos, 1, 0, false);
  62667. sc->atan_symbol = big_defun("atan", atan, 1, 1, false);
  62668. sc->sinh_symbol = big_defun("sinh", sinh, 1, 0, false);
  62669. sc->cosh_symbol = big_defun("cosh", cosh, 1, 0, false);
  62670. sc->tanh_symbol = big_defun("tanh", tanh, 1, 0, false);
  62671. sc->asinh_symbol = big_defun("asinh", asinh, 1, 0, false);
  62672. sc->acosh_symbol = big_defun("acosh", acosh, 1, 0, false);
  62673. sc->atanh_symbol = big_defun("atanh", atanh, 1, 0, false);
  62674. sc->random_symbol = big_defun("random", random, 1, 1, false);
  62675. sc->random_state_symbol = big_defun("random-state", random_state, 1, 1, false);
  62676. sc->is_bignum_symbol = big_defun("bignum?", is_bignum, 1, 0, false); /* needed by Q_bignum below */
  62677. sc->bignum_symbol = big_defun("bignum", bignum, 1, 1, false);
  62678. sc->bignum_precision = DEFAULT_BIGNUM_PRECISION;
  62679. mpfr_set_default_prec((mp_prec_t)DEFAULT_BIGNUM_PRECISION);
  62680. mpc_set_default_precision((mp_prec_t)DEFAULT_BIGNUM_PRECISION);
  62681. s7_symbol_set_value(sc, sc->pi_symbol, big_pi(sc));
  62682. /* if these fixnum limits were read as strings, they'd be bignums in the gmp case,
  62683. * so for consistency make the symbolic versions bignums as well.
  62684. */
  62685. s7_symbol_set_value(sc, make_symbol(sc, "most-positive-fixnum"), s7_int_to_big_integer(sc, s7_integer(s7_name_to_value(sc, "most-positive-fixnum"))));
  62686. s7_symbol_set_value(sc, make_symbol(sc, "most-negative-fixnum"), s7_int_to_big_integer(sc, s7_integer(s7_name_to_value(sc, "most-negative-fixnum"))));
  62687. s7_provide(sc, "gmp");
  62688. }
  62689. #endif
  62690. /* WITH_GMP */
  62691. /* -------------------------------- *s7* environment -------------------------------- */
  62692. static void init_s7_let(s7_scheme *sc)
  62693. {
  62694. sc->stack_top_symbol = s7_make_symbol(sc, "stack-top");
  62695. sc->stack_size_symbol = s7_make_symbol(sc, "stack-size");
  62696. sc->stacktrace_defaults_symbol = s7_make_symbol(sc, "stacktrace-defaults");
  62697. sc->symbol_table_is_locked_symbol = s7_make_symbol(sc, "symbol-table-locked?");
  62698. sc->heap_size_symbol = s7_make_symbol(sc, "heap-size");
  62699. sc->free_heap_size_symbol = s7_make_symbol(sc, "free-heap-size");
  62700. sc->gc_freed_symbol = s7_make_symbol(sc, "gc-freed");
  62701. sc->gc_protected_objects_symbol = s7_make_symbol(sc, "gc-protected-objects");
  62702. set_immutable(sc->gc_protected_objects_symbol);
  62703. sc->input_ports_symbol = s7_make_symbol(sc, "input-ports");
  62704. sc->output_ports_symbol = s7_make_symbol(sc, "output-ports");
  62705. sc->strings_symbol = s7_make_symbol(sc, "strings");
  62706. sc->gensyms_symbol = s7_make_symbol(sc, "gensyms");
  62707. sc->vectors_symbol = s7_make_symbol(sc, "vectors");
  62708. sc->hash_tables_symbol = s7_make_symbol(sc, "hash-tables");
  62709. sc->continuations_symbol = s7_make_symbol(sc, "continuations");
  62710. sc->c_objects_symbol = s7_make_symbol(sc, "c-objects");
  62711. sc->file_names_symbol = s7_make_symbol(sc, "file-names");
  62712. sc->symbol_table_symbol = s7_make_symbol(sc, "symbol-table");
  62713. sc->rootlet_size_symbol = s7_make_symbol(sc, "rootlet-size");
  62714. sc->c_types_symbol = s7_make_symbol(sc, "c-types");
  62715. sc->safety_symbol = s7_make_symbol(sc, "safety");
  62716. sc->undefined_identifier_warnings_symbol = s7_make_symbol(sc, "undefined-identifier-warnings");
  62717. sc->gc_stats_symbol = s7_make_symbol(sc, "gc-stats");
  62718. sc->max_stack_size_symbol = s7_make_symbol(sc, "max-stack-size");
  62719. sc->cpu_time_symbol = s7_make_symbol(sc, "cpu-time");
  62720. sc->catches_symbol = s7_make_symbol(sc, "catches");
  62721. sc->exits_symbol = s7_make_symbol(sc, "exits");
  62722. sc->stack_symbol = s7_make_symbol(sc, "stack");
  62723. sc->max_string_length_symbol = s7_make_symbol(sc, "max-string-length");
  62724. sc->max_list_length_symbol = s7_make_symbol(sc, "max-list-length");
  62725. sc->max_vector_length_symbol = s7_make_symbol(sc, "max-vector-length");
  62726. sc->max_vector_dimensions_symbol = s7_make_symbol(sc, "max-vector-dimensions");
  62727. sc->default_hash_table_length_symbol = s7_make_symbol(sc, "default-hash-table-length");
  62728. sc->initial_string_port_length_symbol = s7_make_symbol(sc, "initial-string-port-length");
  62729. sc->default_rationalize_error_symbol = s7_make_symbol(sc, "default-rationalize-error");
  62730. sc->default_random_state_symbol = s7_make_symbol(sc, "default-random-state");
  62731. sc->morally_equal_float_epsilon_symbol = s7_make_symbol(sc, "morally-equal-float-epsilon");
  62732. sc->hash_table_float_epsilon_symbol = s7_make_symbol(sc, "hash-table-float-epsilon");
  62733. sc->print_length_symbol = s7_make_symbol(sc, "print-length");
  62734. sc->bignum_precision_symbol = s7_make_symbol(sc, "bignum-precision");
  62735. sc->memory_usage_symbol = s7_make_symbol(sc, "memory-usage");
  62736. sc->float_format_precision_symbol = s7_make_symbol(sc, "float-format-precision");
  62737. sc->history_size_symbol = s7_make_symbol(sc, "history-size");
  62738. sc->profile_info_symbol = s7_make_symbol(sc, "profile-info");
  62739. }
  62740. #ifdef __linux__
  62741. #include <sys/resource.h>
  62742. #endif
  62743. static s7_pointer describe_memory_usage(s7_scheme *sc)
  62744. {
  62745. /* heap, permanent, stack?, doc strings, sigs, c_func structs (and ports etc), vcts, mx_alloc, output bufs,
  62746. * sinc_tables, c-objects, rc_data, strbuf/tmpbuf[reallocs], autoload tables, hash_entrys, symbol_table,
  62747. * small_ints?
  62748. */
  62749. int i, syms = 0, len;
  62750. s7_pointer x;
  62751. #ifdef __linux__
  62752. struct rusage info;
  62753. getrusage(RUSAGE_SELF, &info);
  62754. fprintf(stderr, "process size: %lld\n", (s7_int)(info.ru_maxrss * 1024));
  62755. #endif
  62756. fprintf(stderr, "heap: %u (%lld bytes)", sc->heap_size, (s7_int)(sc->heap_size * (sizeof(s7_pointer) + sizeof(s7_cell))));
  62757. {
  62758. unsigned int k;
  62759. int ts[NUM_TYPES];
  62760. for (i = 0; i < NUM_TYPES; i++) ts[i] = 0;
  62761. for (k = 0; k < sc->heap_size; k++)
  62762. ts[unchecked_type(sc->heap[k])]++;
  62763. for (i = 0; i < NUM_TYPES; i++)
  62764. {
  62765. if ((i % 10) == 0) fprintf(stderr, "\n ");
  62766. fprintf(stderr, " %d", ts[i]);
  62767. }
  62768. fprintf(stderr, "\n");
  62769. }
  62770. fprintf(stderr, "permanent cells: %d (%lld bytes)\n", permanent_cells, (s7_int)(permanent_cells * sizeof(s7_cell)));
  62771. for (i = 0; i < vector_length(sc->symbol_table); i++)
  62772. for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
  62773. syms++;
  62774. fprintf(stderr, "symbol table: %d (%d symbols, %lld bytes)\n", SYMBOL_TABLE_SIZE, syms,
  62775. (s7_int)(SYMBOL_TABLE_SIZE * sizeof(s7_pointer) + syms * 3 * sizeof(s7_cell)));
  62776. fprintf(stderr, "stack: %u (%lld bytes)\n", sc->stack_size, (s7_int)(sc->stack_size * sizeof(s7_pointer)));
  62777. fprintf(stderr, "c_functions: %d (%d bytes)\n", c_functions, (int)(c_functions * sizeof(c_proc_t)));
  62778. len = 0;
  62779. for (i = 0; i < (int)(sc->strings_loc); i++)
  62780. len += string_length(sc->strings[i]);
  62781. fprintf(stderr, "strings: %u, %d bytes\n", sc->strings_loc, len); /* also doc strings, permanent strings, etc */
  62782. {
  62783. int hs;
  62784. hash_entry_t *p;
  62785. for (hs = 0, p = hash_free_list; p; p = (hash_entry_t *)(p->next), hs++);
  62786. len = 0;
  62787. for (i = 0; i < (int)(sc->hash_tables_loc); i++)
  62788. len += (hash_table_mask(sc->hash_tables[i]) + 1);
  62789. fprintf(stderr, "hash tables: %d (%d %d), ", (int)(sc->hash_tables_loc), len, hs);
  62790. }
  62791. {
  62792. int fs;
  62793. port_t *p;
  62794. for (fs = 0, p = sc->port_heap; p; p = (port_t *)(p->next), fs++);
  62795. fprintf(stderr, "vectors: %u, input: %u, output: %u, free port: %d\ncontinuations: %u, c_objects: %u, gensyms: %u, setters: %u\n",
  62796. sc->vectors_loc, sc->input_ports_loc, sc->output_ports_loc, fs, sc->continuations_loc, sc->c_objects_loc, sc->gensyms_loc, sc->setters_loc);
  62797. }
  62798. return(sc->F);
  62799. }
  62800. static s7_pointer g_s7_let_ref_fallback(s7_scheme *sc, s7_pointer args)
  62801. {
  62802. s7_pointer sym;
  62803. sym = cadr(args);
  62804. if (!is_symbol(sym))
  62805. return(simple_wrong_type_argument(sc, sc->let_ref_symbol, sym, T_SYMBOL));
  62806. if (sym == sc->print_length_symbol) /* print-length */
  62807. return(s7_make_integer(sc, sc->print_length));
  62808. if (sym == sc->stack_top_symbol) /* stack-top = how many frames active (4 stack entries per frame) */
  62809. return(s7_make_integer(sc, (sc->stack_end - sc->stack_start) / 4));
  62810. if (sym == sc->stack_size_symbol) /* stack-size (max so far) */
  62811. return(s7_make_integer(sc, sc->stack_size));
  62812. if (sym == sc->max_stack_size_symbol) /* max-stack-size */
  62813. return(s7_make_integer(sc, sc->max_stack_size));
  62814. if (sym == sc->stacktrace_defaults_symbol) /* stacktrace-defaults (used to be *stacktrace*) */
  62815. return(sc->stacktrace_defaults);
  62816. if (sym == sc->symbol_table_is_locked_symbol) /* symbol-table-locked? */
  62817. return(make_boolean(sc, sc->symbol_table_is_locked));
  62818. if (sym == sc->symbol_table_symbol) /* symbol-table (the raw vector) */
  62819. return(sc->symbol_table);
  62820. if (sym == sc->rootlet_size_symbol) /* rootlet-size */
  62821. return(s7_make_integer(sc, sc->rootlet_entries));
  62822. if (sym == sc->safety_symbol) /* safety */
  62823. return(s7_make_integer(sc, sc->safety));
  62824. if (sym == sc->undefined_identifier_warnings_symbol) /* undefined-identifier-warnings */
  62825. return(s7_make_boolean(sc, sc->undefined_identifier_warnings));
  62826. if (sym == sc->cpu_time_symbol) /* cpu-time */
  62827. return(s7_make_real(sc, (double)clock() / (double)CLOCKS_PER_SEC));
  62828. if (sym == sc->catches_symbol) /* catches */
  62829. return(active_catches(sc));
  62830. if (sym == sc->exits_symbol) /* exits */
  62831. return(active_exits(sc));
  62832. if (sym == sc->stack_symbol) /* stack */
  62833. return(stack_entries(sc, sc->stack, s7_stack_top(sc)));
  62834. if (sym == sc->heap_size_symbol) /* heap-size */
  62835. return(s7_make_integer(sc, sc->heap_size));
  62836. if (sym == sc->free_heap_size_symbol) /* free-heap-size (number of unused cells in the heap) */
  62837. return(s7_make_integer(sc, sc->free_heap_top - sc->free_heap));
  62838. if (sym == sc->gc_freed_symbol) /* gc-freed = how many cells freed during last GC sweep */
  62839. return(s7_make_integer(sc, sc->gc_freed));
  62840. if (sym == sc->gc_protected_objects_symbol) /* gc-protected-objects */
  62841. return(sc->protected_objects);
  62842. if (sym == sc->gc_stats_symbol) /* gc-stats */
  62843. return(make_integer(sc, sc->gc_stats));
  62844. if (sym == sc->default_rationalize_error_symbol) /* default-rationalize-error */
  62845. return(make_real(sc, sc->default_rationalize_error));
  62846. if (sym == sc->default_random_state_symbol) /* default-random-state */
  62847. return(sc->default_rng);
  62848. if (sym == sc->history_size_symbol) /* history-size (eval history circular buffer size) */
  62849. return(s7_make_integer(sc, sc->history_size));
  62850. if (sym == sc->profile_info_symbol) /* profile-info -- profiling data hash-table */
  62851. return(sc->profile_info);
  62852. if (sym == sc->max_list_length_symbol) /* max-list-length (as arg to make-list) */
  62853. return(s7_make_integer(sc, sc->max_list_length));
  62854. if (sym == sc->max_vector_length_symbol) /* max-vector-length (as arg to make-vector and make-hash-table) */
  62855. return(s7_make_integer(sc, sc->max_vector_length));
  62856. if (sym == sc->max_vector_dimensions_symbol) /* max-vector-dimensions (make-vector) */
  62857. return(s7_make_integer(sc, sc->max_vector_dimensions));
  62858. if (sym == sc->max_string_length_symbol) /* max-string-length (as arg to make-string and read-string) */
  62859. return(s7_make_integer(sc, sc->max_string_length));
  62860. if (sym == sc->default_hash_table_length_symbol) /* default size for make-hash-table */
  62861. return(s7_make_integer(sc, sc->default_hash_table_length));
  62862. if (sym == sc->morally_equal_float_epsilon_symbol) /* morally-equal-float-epsilon */
  62863. return(s7_make_real(sc, sc->morally_equal_float_epsilon));
  62864. if (sym == sc->hash_table_float_epsilon_symbol) /* hash-table-float-epsilon */
  62865. return(s7_make_real(sc, sc->hash_table_float_epsilon));
  62866. if (sym == sc->initial_string_port_length_symbol) /* initial-string-port-length */
  62867. return(s7_make_integer(sc, sc->initial_string_port_length));
  62868. if (sym == sc->input_ports_symbol) /* input-ports */
  62869. return(make_vector_wrapper(sc, sc->input_ports_loc, sc->input_ports));
  62870. if (sym == sc->output_ports_symbol) /* output-ports */
  62871. return(make_vector_wrapper(sc, sc->output_ports_loc, sc->output_ports));
  62872. if (sym == sc->strings_symbol) /* strings */
  62873. return(make_vector_wrapper(sc, sc->strings_loc, sc->strings));
  62874. if (sym == sc->gensyms_symbol) /* gensyms */
  62875. return(make_vector_wrapper(sc, sc->gensyms_loc, sc->gensyms));
  62876. if (sym == sc->vectors_symbol) /* vectors */
  62877. return(make_vector_wrapper(sc, sc->vectors_loc, sc->vectors));
  62878. if (sym == sc->hash_tables_symbol) /* hash-tables */
  62879. return(make_vector_wrapper(sc, sc->hash_tables_loc, sc->hash_tables));
  62880. if (sym == sc->continuations_symbol) /* continuations */
  62881. return(make_vector_wrapper(sc, sc->continuations_loc, sc->continuations));
  62882. if (sym == sc->c_objects_symbol) /* c-objects */
  62883. return(make_vector_wrapper(sc, sc->c_objects_loc, sc->c_objects));
  62884. if (sym == sc->file_names_symbol) /* file-names (loaded files) */
  62885. return(make_vector_wrapper(sc, sc->file_names_top, sc->file_names));
  62886. if (sym == sc->c_types_symbol) /* c-types */
  62887. {
  62888. s7_pointer res;
  62889. int i;
  62890. sc->w = sc->nil;
  62891. for (i = 0; i < num_object_types; i++) /* c-object type (tag) is i */
  62892. sc->w = cons(sc, object_types[i]->scheme_name, sc->w);
  62893. res = safe_reverse_in_place(sc, sc->w); /* so car(types) has tag 0 */
  62894. sc->w = sc->nil;
  62895. return(res);
  62896. }
  62897. if (sym == sc->bignum_precision_symbol) /* bignum-precision */
  62898. return(s7_make_integer(sc, sc->bignum_precision));
  62899. if (sym == sc->float_format_precision_symbol) /* float-format-precision */
  62900. return(s7_make_integer(sc, float_format_precision));
  62901. if (sym == sc->memory_usage_symbol) /* memory-usage */
  62902. return(describe_memory_usage(sc));
  62903. /* sc->unlet is a scheme vector of slots -- not very useful at the scheme level */
  62904. return(sc->undefined);
  62905. }
  62906. static s7_pointer g_s7_let_set_fallback(s7_scheme *sc, s7_pointer args)
  62907. {
  62908. s7_pointer sym, val;
  62909. sym = cadr(args);
  62910. if (!is_symbol(sym))
  62911. return(simple_wrong_type_argument(sc, sc->let_set_symbol, sym, T_SYMBOL));
  62912. val = caddr(args);
  62913. if ((sym == sc->print_length_symbol) ||
  62914. (sym == sc->max_vector_length_symbol) ||
  62915. (sym == sc->max_vector_dimensions_symbol) ||
  62916. (sym == sc->max_list_length_symbol) ||
  62917. (sym == sc->history_size_symbol) ||
  62918. (sym == sc->max_string_length_symbol))
  62919. {
  62920. if (s7_is_integer(val))
  62921. {
  62922. s7_int iv;
  62923. iv = s7_integer(val); /* might be bignum if gmp */
  62924. if (iv < 0)
  62925. return(simple_out_of_range(sc, sym, val, make_string_wrapper(sc, "should be a positive integer")));
  62926. if (sym == sc->print_length_symbol)
  62927. sc->print_length = iv;
  62928. else
  62929. {
  62930. if (sym == sc->max_vector_length_symbol)
  62931. sc->max_vector_length = iv;
  62932. else
  62933. {
  62934. if (sym == sc->max_vector_dimensions_symbol)
  62935. sc->max_vector_dimensions = iv;
  62936. else
  62937. {
  62938. if (sym == sc->history_size_symbol)
  62939. {
  62940. #if WITH_HISTORY
  62941. s7_pointer p1, p2;
  62942. if (iv > sc->true_history_size)
  62943. {
  62944. /* splice in the new cells, reattach the circles */
  62945. s7_pointer next1, next2;
  62946. next1 = cdr(sc->eval_history1);
  62947. next2 = cdr(sc->eval_history2);
  62948. set_cdr(sc->eval_history1, permanent_list(sc, iv - sc->true_history_size));
  62949. set_cdr(sc->eval_history2, permanent_list(sc, iv - sc->true_history_size));
  62950. for (p1 = sc->eval_history1, p2 = sc->eval_history2; is_pair(cdr(p1)); p1 = cdr(p1), p2 = cdr(p2));
  62951. set_cdr(p1, next1);
  62952. set_cdr(p2, next2);
  62953. sc->true_history_size = iv;
  62954. }
  62955. sc->history_size = iv;
  62956. /* clear out both bufffers to avoid GC confusion */
  62957. for (p1 = sc->eval_history1, p2 = sc->eval_history2; ; p2 = cdr(p2))
  62958. {
  62959. set_car(p1, sc->nil);
  62960. set_car(p2, sc->nil);
  62961. p1 = cdr(p1);
  62962. if (p1 == sc->eval_history1) break;
  62963. }
  62964. #else
  62965. sc->history_size = iv;
  62966. #endif
  62967. }
  62968. else
  62969. {
  62970. if (sym == sc->max_list_length_symbol)
  62971. sc->max_list_length = iv;
  62972. else sc->max_string_length = iv;
  62973. }
  62974. }
  62975. }
  62976. }
  62977. return(val);
  62978. }
  62979. return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
  62980. }
  62981. if (sym == sc->gc_stats_symbol)
  62982. {
  62983. if (s7_is_boolean(val)) {sc->gc_stats = ((val == sc->T) ? GC_STATS : 0); return(val);}
  62984. if (s7_is_integer(val)) {sc->gc_stats = s7_integer(val); return(val);}
  62985. return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
  62986. }
  62987. if (sym == sc->symbol_table_is_locked_symbol)
  62988. {
  62989. if (s7_is_boolean(val)) {sc->symbol_table_is_locked = (val == sc->T); return(val);}
  62990. return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
  62991. }
  62992. if (sym == sc->max_stack_size_symbol)
  62993. {
  62994. if (s7_is_integer(val))
  62995. {
  62996. s7_int size;
  62997. size = s7_integer(val);
  62998. if (size >= INITIAL_STACK_SIZE)
  62999. {
  63000. sc->max_stack_size = (unsigned int)size;
  63001. return(val);
  63002. }
  63003. return(simple_out_of_range(sc, sym, val, make_string_wrapper(sc, "should be greater than the initial stack size (512)")));
  63004. }
  63005. return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
  63006. }
  63007. if (sym == sc->safety_symbol)
  63008. {
  63009. if (s7_is_integer(val)) {sc->safety = s7_integer(val); return(val);}
  63010. return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
  63011. }
  63012. if (sym == sc->undefined_identifier_warnings_symbol)
  63013. {
  63014. if (s7_is_boolean(val)) {sc->undefined_identifier_warnings = s7_boolean(sc, val); return(val);}
  63015. return(simple_wrong_type_argument(sc, sym, val, T_BOOLEAN));
  63016. }
  63017. if (sym == sc->default_hash_table_length_symbol)
  63018. {
  63019. if (s7_is_integer(val)) {sc->default_hash_table_length = s7_integer(val); return(val);}
  63020. return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
  63021. }
  63022. if (sym == sc->initial_string_port_length_symbol)
  63023. {
  63024. if (s7_is_integer(val)) {sc->initial_string_port_length = s7_integer(val); return(val);}
  63025. return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
  63026. }
  63027. if (sym == sc->morally_equal_float_epsilon_symbol)
  63028. {
  63029. if (s7_is_real(val)) {sc->morally_equal_float_epsilon = s7_real(val); return(val);}
  63030. return(simple_wrong_type_argument(sc, sym, val, T_REAL));
  63031. }
  63032. if (sym == sc->hash_table_float_epsilon_symbol)
  63033. {
  63034. if (s7_is_real(val)) {sc->hash_table_float_epsilon = s7_real(val); return(val);}
  63035. return(simple_wrong_type_argument(sc, sym, val, T_REAL));
  63036. }
  63037. if (sym == sc->float_format_precision_symbol)
  63038. {
  63039. if (s7_is_integer(val)) {float_format_precision = s7_integer(val); return(val);}
  63040. return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
  63041. }
  63042. if (sym == sc->default_rationalize_error_symbol)
  63043. {
  63044. if (s7_is_real(val)) {sc->default_rationalize_error = real_to_double(sc, val, "set! default-rationalize-error"); return(val);}
  63045. return(simple_wrong_type_argument(sc, sym, val, T_REAL));
  63046. }
  63047. if (sym == sc->default_random_state_symbol)
  63048. {
  63049. if (is_random_state(val))
  63050. {
  63051. #if (!WITH_GMP)
  63052. random_seed(sc->default_rng) = random_seed(val);
  63053. random_carry(sc->default_rng) = random_carry(val);
  63054. #endif
  63055. return(val);
  63056. }
  63057. return(wrong_type_argument_with_type(sc, sym, 1, val, a_random_state_object_string));
  63058. }
  63059. if (sym == sc->stacktrace_defaults_symbol)
  63060. {
  63061. if (!is_pair(val))
  63062. return(simple_wrong_type_argument(sc, sym, val, T_PAIR));
  63063. if (s7_list_length(sc, val) != 5)
  63064. return(simple_wrong_type_argument_with_type(sc, sym, val, make_string_wrapper(sc, "a list with 5 entries")));
  63065. if (!is_integer(car(val)))
  63066. return(wrong_type_argument_with_type(sc, sym, 1, car(val), make_string_wrapper(sc, "an integer (stack frames)")));
  63067. if (!is_integer(cadr(val)))
  63068. return(wrong_type_argument_with_type(sc, sym, 2, cadr(val), make_string_wrapper(sc, "an integer (cols-for-data)")));
  63069. if (!is_integer(caddr(val)))
  63070. return(wrong_type_argument_with_type(sc, sym, 3, caddr(val), make_string_wrapper(sc, "an integer (line length)")));
  63071. if (!is_integer(cadddr(val)))
  63072. return(wrong_type_argument_with_type(sc, sym, 4, cadddr(val), make_string_wrapper(sc, "an integer (comment position)")));
  63073. if (!s7_is_boolean(s7_list_ref(sc,val, 4)))
  63074. return(wrong_type_argument_with_type(sc, sym, 5, s7_list_ref(sc, val, 4), make_string_wrapper(sc, "a boolean (treat-data-as-comment)")));
  63075. sc->stacktrace_defaults = copy_list(sc, val);
  63076. return(val);
  63077. }
  63078. if (sym == sc->bignum_precision_symbol)
  63079. {
  63080. if (s7_is_integer(val))
  63081. {
  63082. sc->bignum_precision = s7_integer(val);
  63083. #if WITH_GMP
  63084. set_bignum_precision(sc, sc->bignum_precision);
  63085. #endif
  63086. return(val);
  63087. }
  63088. return(simple_wrong_type_argument(sc, sym, val, T_INTEGER));
  63089. }
  63090. if ((sym == sc->cpu_time_symbol) ||
  63091. (sym == sc->heap_size_symbol) || (sym == sc->free_heap_size_symbol) ||
  63092. (sym == sc->gc_freed_symbol) || (sym == sc->gc_protected_objects_symbol) ||
  63093. (sym == sc->file_names_symbol) || (sym == sc->c_types_symbol) || (sym == sc->catches_symbol) || (sym == sc->exits_symbol) ||
  63094. (sym == sc->rootlet_size_symbol) || (sym == sc->profile_info_symbol) ||
  63095. (sym == sc->stack_top_symbol) || (sym == sc->stack_size_symbol))
  63096. return(s7_error(sc, sc->error_symbol, set_elist_2(sc, make_string_wrapper(sc, "can't set (*s7* '~S)"), sym)));
  63097. return(sc->undefined);
  63098. }
  63099. /* some procedure-signature support functions */
  63100. static s7_pointer g_is_float(s7_scheme *sc, s7_pointer args)
  63101. {
  63102. #define H_is_float "(float? x) returns #t is x is real and not rational."
  63103. #define Q_is_float pl_bt
  63104. s7_pointer p;
  63105. p = car(args);
  63106. return(make_boolean(sc, ((is_real(p)) && (!is_rational(p)))));
  63107. }
  63108. static s7_pointer g_is_proper_list(s7_scheme *sc, s7_pointer args)
  63109. {
  63110. #define H_is_proper_list "(proper-list? x) returns #t is x is a list that is neither circular nor dotted."
  63111. #define Q_is_proper_list pl_bt
  63112. s7_pointer p;
  63113. p = car(args);
  63114. return(make_boolean(sc, is_proper_list(sc, p)));
  63115. }
  63116. /* how to handle this? (float-vector-set! and vector-set! signature entries) */
  63117. static s7_pointer g_is_integer_or_real_at_end(s7_scheme *sc, s7_pointer args) {return(sc->T);}
  63118. static s7_pointer g_is_integer_or_any_at_end(s7_scheme *sc, s7_pointer args) {return(sc->T);}
  63119. #ifndef _MSC_VER
  63120. /* gdb stacktrace decoding */
  63121. static bool is_decodable(s7_scheme *sc, s7_pointer p)
  63122. {
  63123. int i;
  63124. s7_pointer x;
  63125. s7_pointer *tp, *heap_top;
  63126. if ((void *)p == (void *)sc) return(false);
  63127. /* check basic constants */
  63128. if ((p == sc->nil) || (p == sc->T) || (p == sc->F) || (p == sc->eof_object) || (p == sc->else_object) || (p == sc->rootlet) ||
  63129. (p == sc->undefined) || (p == sc->unspecified) || (p == sc->no_value) || (p == sc->gc_nil) ||
  63130. (p == sc->t1_1) || (p == sc->t2_1) || (p == sc->t3_1) || (p == sc->a1_1) || (p == sc->a2_1) || (p == sc->a3_1) || (p == sc->a4_1))
  63131. return(true);
  63132. /* check symbol-table */
  63133. for (i = 0; i < vector_length(sc->symbol_table); i++)
  63134. for (x = vector_element(sc->symbol_table, i); is_not_null(x); x = cdr(x))
  63135. {
  63136. s7_pointer sym;
  63137. sym = car(x);
  63138. if ((sym == p) ||
  63139. ((is_global(sym)) && (is_slot(global_slot(sym))) && (p == slot_value(global_slot(sym)))))
  63140. return(true);
  63141. }
  63142. for (i = 0; i < NUM_CHARS; i++) if (p == chars[i]) return(true);
  63143. for (i = 0; i <= NUM_SMALL_INTS; i++) if (p == small_ints[i]) return(true);
  63144. /* also real_one and friends, sc->safe_lists, tmp_strs? p|elist? */
  63145. /* check the heap */
  63146. tp = sc->heap;
  63147. heap_top = (s7_pointer *)(sc->heap + sc->heap_size);
  63148. while (tp < heap_top)
  63149. if (p == (*tp++))
  63150. return(true);
  63151. return(false);
  63152. }
  63153. char *s7_decode_bt(void)
  63154. {
  63155. FILE *fp;
  63156. fp = fopen("gdb.txt", "r");
  63157. if (fp)
  63158. {
  63159. long i, size;
  63160. size_t bytes;
  63161. bool in_quotes = false;
  63162. unsigned char *bt;
  63163. s7_scheme *sc;
  63164. sc = hidden_sc;
  63165. fseek(fp, 0, SEEK_END);
  63166. size = ftell(fp);
  63167. rewind(fp);
  63168. bt = (unsigned char *)malloc((size + 1) * sizeof(unsigned char));
  63169. bytes = fread(bt, sizeof(unsigned char), size, fp);
  63170. if (bytes != (size_t)size)
  63171. {
  63172. fclose(fp);
  63173. free(bt);
  63174. return((char *)" oops ");
  63175. }
  63176. bt[size] = '\0';
  63177. fclose(fp);
  63178. for (i = 0; i < size; i++)
  63179. {
  63180. fputc(bt[i], stdout);
  63181. if ((bt[i] == '"') && ((i == 0) || (bt[i - 1] != '\\')))
  63182. in_quotes = (!in_quotes);
  63183. else
  63184. {
  63185. if ((!in_quotes) && (i < size - 8))
  63186. {
  63187. if ((bt[i] == '=') &&
  63188. (((bt[i + 1] == '0') && (bt[i + 2] == 'x')) ||
  63189. ((bt[i + 1] == ' ') && (bt[i + 2] == '0') && (bt[i + 3] == 'x'))))
  63190. {
  63191. void *vp;
  63192. int vals;
  63193. vals = sscanf((const char *)(bt + i + 1), "%p", &vp);
  63194. if (vals == 1)
  63195. {
  63196. int k;
  63197. for (k = i + ((bt[i + 2] == 'x') ? 3 : 4); (k < size) && (IS_DIGIT(bt[k], 16)); k++);
  63198. if ((bt[k] != ' ') || (bt[k + 1] != '"'))
  63199. {
  63200. s7_pointer p;
  63201. p = (s7_pointer)vp;
  63202. if ((is_decodable(sc, p)) &&
  63203. (!is_free(p)))
  63204. {
  63205. if (bt[i + 1] == ' ') fputc(' ', stdout);
  63206. i = k - 1;
  63207. if (s7_is_valid(sc, p))
  63208. {
  63209. char *str;
  63210. str = s7_object_to_c_string(sc, p);
  63211. fprintf(stdout, "%s%s%s", BOLD_TEXT, str, UNBOLD_TEXT);
  63212. free(str);
  63213. }
  63214. else
  63215. {
  63216. if (is_free(p))
  63217. fprintf(stderr, "%p: %sfree cell%s", p, BOLD_TEXT, UNBOLD_TEXT);
  63218. else fprintf(stderr, "%p: %sunprintable?%s", p, BOLD_TEXT, UNBOLD_TEXT);
  63219. }
  63220. }
  63221. }
  63222. }
  63223. }
  63224. }
  63225. }
  63226. }
  63227. free(bt);
  63228. }
  63229. return((char *)"");
  63230. }
  63231. #endif
  63232. /* ---------------- an experiment ---------------- */
  63233. static s7_int tree_len(s7_scheme *sc, s7_pointer p, s7_int i)
  63234. {
  63235. if (is_null(p))
  63236. return(i);
  63237. if ((!is_pair(p)) ||
  63238. (car(p) == sc->quote_symbol))
  63239. return(i + 1);
  63240. return(tree_len(sc, car(p), tree_len(sc, cdr(p), i)));
  63241. }
  63242. static s7_pointer g_tree_leaves(s7_scheme *sc, s7_pointer args)
  63243. {
  63244. return(s7_make_integer(sc, tree_len(sc, car(args), 0)));
  63245. }
  63246. /* -------------------------------- initialization -------------------------------- */
  63247. static s7_pointer make_unique_object(const char* name, unsigned int typ)
  63248. {
  63249. s7_pointer p;
  63250. p = alloc_pointer();
  63251. set_type(p, typ | T_IMMUTABLE);
  63252. unique_name_length(p) = safe_strlen(name);
  63253. unique_name(p) = copy_string_with_length(name, unique_name_length(p));
  63254. unheap(p);
  63255. return(p);
  63256. }
  63257. s7_scheme *s7_init(void)
  63258. {
  63259. int i;
  63260. s7_scheme *sc;
  63261. s7_pointer sym;
  63262. static bool already_inited = false;
  63263. #ifndef _MSC_VER
  63264. setlocale(LC_NUMERIC, "C"); /* use decimal point in floats */
  63265. #endif
  63266. if (!already_inited)
  63267. {
  63268. init_types();
  63269. init_ctables();
  63270. init_mark_functions();
  63271. init_equals();
  63272. init_hash_maps();
  63273. init_pows();
  63274. #if (!WITH_GMP)
  63275. init_add_ops();
  63276. init_multiply_ops();
  63277. #endif
  63278. init_uppers();
  63279. all_x_function_init();
  63280. init_catchers();
  63281. /* sizeof(__float128) == sizeof(long double) so how to distinguish them for printf (L vs Q)? */
  63282. /* if (sizeof(s7_double) >= 16) float_format_g = "%.*Qg"; */ /* __float128 */
  63283. if (sizeof(s7_double) > 8)
  63284. float_format_g = "%.*Lg"; /* long double (80-bit precision?) */
  63285. else float_format_g = "%.*g"; /* float and double */
  63286. }
  63287. sc = (s7_scheme *)calloc(1, sizeof(s7_scheme)); /* malloc is not recommended here */
  63288. hidden_sc = sc; /* for gdb/debugging */
  63289. sc->gc_off = true; /* sc->args and so on are not set yet, so a gc during init -> segfault */
  63290. sc->gc_stats = 0;
  63291. init_gc_caches(sc);
  63292. sc->longjmp_ok = false;
  63293. sc->setjmp_loc = NO_SET_JUMP;
  63294. sc->symbol_table_is_locked = false;
  63295. if (sizeof(s7_int) == 4)
  63296. sc->max_vector_length = (1 << 24);
  63297. else sc->max_vector_length = (1LL << 32);
  63298. sc->max_string_length = 1073741824;
  63299. sc->max_list_length = 1073741824;
  63300. sc->max_vector_dimensions = 512;
  63301. sc->strbuf_size = INITIAL_STRBUF_SIZE;
  63302. sc->strbuf = (char *)calloc(sc->strbuf_size, sizeof(char));
  63303. sc->tmpbuf = (char *)calloc(TMPBUF_SIZE, sizeof(char));
  63304. sc->print_width = sc->max_string_length;
  63305. sc->short_print = false;
  63306. sc->initial_string_port_length = 128;
  63307. sc->format_depth = -1;
  63308. sc->slash_str_size = 0;
  63309. sc->slash_str = NULL;
  63310. sc->singletons = (s7_pointer *)calloc(256, sizeof(s7_pointer));
  63311. sc->read_line_buf = NULL;
  63312. sc->read_line_buf_size = 0;
  63313. sc->cur_rf = NULL;
  63314. sc->rf_free_list = NULL;
  63315. sc->rf_stack = NULL;
  63316. sc->nil = make_unique_object("()", T_NIL);
  63317. sc->gc_nil = make_unique_object("#<nil>", T_UNIQUE);
  63318. sc->T = make_unique_object("#t", T_BOOLEAN);
  63319. sc->F = make_unique_object("#f", T_BOOLEAN);
  63320. sc->eof_object = make_unique_object("#<eof>", T_UNIQUE);
  63321. sc->undefined = make_unique_object("#<undefined>", T_UNIQUE);
  63322. sc->else_object = make_unique_object("else", T_UNIQUE);
  63323. /* "else" is added to the rootlet below -- can't do it here because the symbol table and environment don't exist yet. */
  63324. sc->unspecified = make_unique_object("#<unspecified>", T_UNSPECIFIED);
  63325. sc->no_value = make_unique_object("#<unspecified>", T_UNSPECIFIED);
  63326. set_car(sc->nil, set_cdr(sc->nil, sc->unspecified));
  63327. /* this is mixing two different s7_cell structs, cons and envr, but luckily
  63328. * envr has two initial s7_pointer fields, equivalent to car and cdr, so
  63329. * let_id which is the same as opt1 is unaffected. To get the names
  63330. * built-in, I'll append unique_name and unique_name_length fields to
  63331. * the envr struct.
  63332. */
  63333. let_id(sc->nil) = -1;
  63334. unique_cdr(sc->unspecified) = sc->unspecified;
  63335. unique_cdr(sc->undefined) = sc->undefined;
  63336. /* this way find_symbol of an undefined symbol returns #<undefined> not #<unspecified> */
  63337. sc->temp_cell_1 = permanent_cons(sc->nil, sc->nil, T_PAIR | T_IMMUTABLE);
  63338. sc->temp_cell = permanent_cons(sc->temp_cell_1, sc->nil, T_PAIR | T_IMMUTABLE);
  63339. sc->temp_cell_2 = permanent_cons(sc->nil, sc->nil, T_PAIR | T_IMMUTABLE);
  63340. sc->t1_1 = permanent_cons(sc->nil, sc->nil, T_PAIR | T_IMMUTABLE);
  63341. sc->t2_2 = permanent_cons(sc->nil, sc->nil, T_PAIR | T_IMMUTABLE);
  63342. sc->t2_1 = permanent_cons(sc->nil, sc->t2_2, T_PAIR | T_IMMUTABLE);
  63343. sc->z2_2 = permanent_cons(sc->nil, sc->nil, T_PAIR | T_IMMUTABLE);
  63344. sc->z2_1 = permanent_cons(sc->nil, sc->z2_2, T_PAIR | T_IMMUTABLE);
  63345. sc->t3_3 = permanent_cons(sc->nil, sc->nil, T_PAIR | T_IMMUTABLE);
  63346. sc->t3_2 = permanent_cons(sc->nil, sc->t3_3, T_PAIR | T_IMMUTABLE);
  63347. sc->t3_1 = permanent_cons(sc->nil, sc->t3_2, T_PAIR | T_IMMUTABLE);
  63348. sc->a4_4 = permanent_cons(sc->nil, sc->nil, T_PAIR | T_IMMUTABLE);
  63349. sc->a4_3 = permanent_cons(sc->nil, sc->a4_4, T_PAIR | T_IMMUTABLE);
  63350. sc->a4_2 = permanent_cons(sc->nil, sc->a4_3, T_PAIR | T_IMMUTABLE);
  63351. sc->a4_1 = permanent_cons(sc->nil, sc->a4_2, T_PAIR | T_IMMUTABLE);
  63352. sc->a1_1 = sc->a4_4;
  63353. sc->a2_1 = sc->a4_3;
  63354. sc->a2_2 = sc->a4_4;
  63355. sc->a3_1 = sc->a4_2;
  63356. sc->a3_2 = sc->a4_3;
  63357. sc->a3_3 = sc->a4_4;
  63358. sc->safe_lists = (s7_pointer *)calloc(NUM_SAFE_LISTS, sizeof(s7_pointer));
  63359. for (i = 1; i < NUM_SAFE_LISTS; i++)
  63360. sc->safe_lists[i] = permanent_list(sc, i);
  63361. sc->input_port_stack = sc->nil;
  63362. sc->code = sc->nil;
  63363. #if WITH_HISTORY
  63364. sc->eval_history1 = permanent_list(sc, DEFAULT_HISTORY_SIZE);
  63365. sc->eval_history2 = permanent_list(sc, DEFAULT_HISTORY_SIZE);
  63366. {
  63367. s7_pointer p1, p2;
  63368. for (p1 = sc->eval_history1, p2 = sc->eval_history2; is_pair(cdr(p1)); p1 = cdr(p1), p2 = cdr(p2));
  63369. set_cdr(p1, sc->eval_history1);
  63370. set_cdr(p2, sc->eval_history2);
  63371. sc->cur_code = sc->eval_history1;
  63372. sc->using_history1 = true;
  63373. }
  63374. #else
  63375. sc->cur_code = sc->F;
  63376. #endif
  63377. sc->args = sc->nil;
  63378. sc->value = sc->nil;
  63379. sc->v = sc->nil;
  63380. sc->w = sc->nil;
  63381. sc->x = sc->nil;
  63382. sc->y = sc->nil;
  63383. sc->z = sc->nil;
  63384. sc->temp1 = sc->nil;
  63385. sc->temp2 = sc->nil;
  63386. sc->temp3 = sc->nil;
  63387. sc->temp4 = sc->nil;
  63388. sc->temp5 = sc->nil;
  63389. sc->temp6 = sc->nil;
  63390. sc->temp7 = sc->nil;
  63391. sc->temp8 = sc->nil;
  63392. sc->temp9 = sc->nil;
  63393. sc->temp10 = sc->nil;
  63394. sc->begin_hook = NULL;
  63395. sc->autoload_table = sc->nil;
  63396. sc->autoload_names = NULL;
  63397. sc->autoload_names_sizes = NULL;
  63398. sc->autoloaded_already = NULL;
  63399. sc->autoload_names_loc = 0;
  63400. sc->port_heap = NULL;
  63401. sc->permanent_objects = NULL;
  63402. sc->heap_size = INITIAL_HEAP_SIZE;
  63403. if ((sc->heap_size % 32) != 0)
  63404. sc->heap_size = 32 * (int)ceil((double)(sc->heap_size) / 32.0);
  63405. sc->heap = (s7_pointer *)malloc(sc->heap_size * sizeof(s7_pointer));
  63406. sc->free_heap = (s7_cell **)malloc(sc->heap_size * sizeof(s7_cell *));
  63407. sc->free_heap_top = (s7_cell **)(sc->free_heap + INITIAL_HEAP_SIZE);
  63408. sc->free_heap_trigger = (s7_cell **)(sc->free_heap + GC_TRIGGER_SIZE);
  63409. sc->previous_free_heap_top = sc->free_heap_top;
  63410. {
  63411. s7_cell *cells;
  63412. cells = (s7_cell *)calloc(INITIAL_HEAP_SIZE, sizeof(s7_cell));
  63413. for (i = 0; i < INITIAL_HEAP_SIZE; i++)
  63414. {
  63415. sc->heap[i] = &cells[i];
  63416. sc->free_heap[i] = sc->heap[i];
  63417. heap_location(sc->heap[i]) = i;
  63418. i++;
  63419. sc->heap[i] = &cells[i];
  63420. sc->free_heap[i] = sc->heap[i];
  63421. heap_location(sc->heap[i]) = i;
  63422. }
  63423. }
  63424. /* this has to precede s7_make_* allocations */
  63425. sc->protected_objects_size = INITIAL_PROTECTED_OBJECTS_SIZE;
  63426. sc->gpofl = (unsigned int *)malloc(INITIAL_PROTECTED_OBJECTS_SIZE * sizeof(unsigned int));
  63427. sc->gpofl_loc = INITIAL_PROTECTED_OBJECTS_SIZE - 1;
  63428. sc->protected_objects = s7_make_vector(sc, INITIAL_PROTECTED_OBJECTS_SIZE);
  63429. sc->protected_accessors_size = INITIAL_PROTECTED_OBJECTS_SIZE;
  63430. sc->protected_accessors_loc = 0;
  63431. sc->protected_accessors = s7_make_vector(sc, INITIAL_PROTECTED_OBJECTS_SIZE);
  63432. for (i = 0; i < INITIAL_PROTECTED_OBJECTS_SIZE; i++)
  63433. {
  63434. vector_element(sc->protected_objects, i) = sc->gc_nil;
  63435. vector_element(sc->protected_accessors, i) = sc->gc_nil;
  63436. sc->gpofl[i] = i;
  63437. }
  63438. sc->stack = s7_make_vector(sc, INITIAL_STACK_SIZE);
  63439. sc->stack_start = vector_elements(sc->stack);
  63440. sc->stack_end = sc->stack_start;
  63441. sc->stack_size = INITIAL_STACK_SIZE;
  63442. sc->stack_resize_trigger = (s7_pointer *)(sc->stack_start + sc->stack_size / 2);
  63443. set_type(sc->stack, T_STACK);
  63444. sc->max_stack_size = (1 << 30);
  63445. initialize_op_stack(sc);
  63446. /* keep the symbol table out of the heap */
  63447. sc->symbol_table = (s7_pointer)calloc(1, sizeof(s7_cell));
  63448. set_type(sc->symbol_table, T_VECTOR);
  63449. vector_length(sc->symbol_table) = SYMBOL_TABLE_SIZE;
  63450. vector_elements(sc->symbol_table) = (s7_pointer *)malloc(SYMBOL_TABLE_SIZE * sizeof(s7_pointer));
  63451. vector_getter(sc->symbol_table) = default_vector_getter;
  63452. vector_setter(sc->symbol_table) = default_vector_setter;
  63453. s7_vector_fill(sc, sc->symbol_table, sc->nil);
  63454. unheap(sc->symbol_table);
  63455. sc->tmp_strs = (s7_pointer *)malloc(2 * sizeof(s7_pointer));
  63456. for (i = 0; i < 2; i++)
  63457. {
  63458. s7_pointer p;
  63459. p = alloc_pointer();
  63460. sc->tmp_strs[i] = p;
  63461. unheap(p);
  63462. set_type(p, T_STRING | T_SAFE_PROCEDURE);
  63463. string_hash(p) = 0;
  63464. string_needs_free(p) = false;
  63465. string_length(p) = 0;
  63466. string_value(p) = (char *)malloc(INITIAL_TMP_STR_SIZE * sizeof(char));
  63467. string_temp_true_length(p) = INITIAL_TMP_STR_SIZE;
  63468. }
  63469. sc->typnam = NULL;
  63470. sc->typnam_len = 0;
  63471. sc->help_arglist = NULL;
  63472. sc->default_rationalize_error = 1.0e-12;
  63473. sc->hash_table_float_epsilon = 1.0e-12;
  63474. sc->morally_equal_float_epsilon = 1.0e-15;
  63475. sc->default_hash_table_length = 8;
  63476. sc->gensym_counter = 0;
  63477. sc->capture_let_counter = 0;
  63478. sc->f_class = 0;
  63479. sc->add_class = 0;
  63480. sc->equal_class = 0;
  63481. sc->let_number = 0;
  63482. sc->format_column = 0;
  63483. sc->file_names = NULL;
  63484. sc->file_names_size = 0;
  63485. sc->file_names_top = -1;
  63486. sc->no_values = 0;
  63487. sc->s7_call_line = 0;
  63488. sc->s7_call_file = NULL;
  63489. sc->s7_call_name = NULL;
  63490. sc->safety = 0;
  63491. sc->print_length = 8;
  63492. sc->history_size = DEFAULT_HISTORY_SIZE;
  63493. sc->true_history_size = DEFAULT_HISTORY_SIZE;
  63494. sc->profile_info = sc->nil;
  63495. sc->baffle_ctr = 0;
  63496. sc->syms_tag = 0;
  63497. sc->class_name_symbol = make_symbol(sc, "class-name");
  63498. sc->circle_info = NULL;
  63499. sc->fdats = (format_data **)calloc(8, sizeof(format_data *));
  63500. sc->num_fdats = 8;
  63501. sc->plist_1 = permanent_list(sc, 1);
  63502. sc->plist_2 = permanent_list(sc, 2);
  63503. sc->plist_3 = permanent_list(sc, 3);
  63504. sc->elist_1 = permanent_list(sc, 1);
  63505. sc->elist_2 = permanent_list(sc, 2);
  63506. sc->elist_3 = permanent_list(sc, 3);
  63507. sc->elist_4 = permanent_list(sc, 4);
  63508. sc->elist_5 = permanent_list(sc, 5);
  63509. sc->direct_str = s7_make_permanent_string(NULL);
  63510. sc->undefined_identifier_warnings = false;
  63511. sc->wrap_only = make_wrap_only(sc);
  63512. sc->dox_slot_symbol = s7_make_symbol(sc, "(dox_slot)");
  63513. sc->rootlet = s7_make_vector(sc, ROOTLET_SIZE);
  63514. set_type(sc->rootlet, T_LET);
  63515. sc->rootlet_entries = 0;
  63516. for (i = 0; i < ROOTLET_SIZE; i++)
  63517. vector_element(sc->rootlet, i) = sc->nil;
  63518. sc->envir = sc->nil;
  63519. sc->shadow_rootlet = sc->nil;
  63520. if (!already_inited)
  63521. {
  63522. /* keep the small_ints out of the heap */
  63523. small_ints = (s7_pointer *)malloc((NUM_SMALL_INTS + 1) * sizeof(s7_pointer));
  63524. {
  63525. s7_cell *cells;
  63526. cells = (s7_cell *)calloc((NUM_SMALL_INTS + 1), sizeof(s7_cell));
  63527. for (i = 0; i <= NUM_SMALL_INTS; i++)
  63528. {
  63529. s7_pointer p;
  63530. small_ints[i] = &cells[i];
  63531. p = small_ints[i];
  63532. typeflag(p) = T_IMMUTABLE | T_INTEGER;
  63533. unheap(p);
  63534. integer(p) = i;
  63535. }
  63536. }
  63537. real_zero = make_permanent_real(0.0);
  63538. real_one = make_permanent_real(1.0);
  63539. real_NaN = make_permanent_real(NAN);
  63540. real_infinity = make_permanent_real(INFINITY);
  63541. real_minus_infinity = make_permanent_real(-INFINITY);
  63542. real_pi = make_permanent_real(3.1415926535897932384626433832795029L); /* M_PI is not good enough for s7_double = long double */
  63543. arity_not_set = make_permanent_integer_unchecked(CLOSURE_ARITY_NOT_SET);
  63544. max_arity = make_permanent_integer_unchecked(MAX_ARITY);
  63545. minus_one = make_permanent_integer_unchecked(-1);
  63546. minus_two = make_permanent_integer_unchecked(-2);
  63547. /* prebuilt null string is tricky mainly because it overlaps #u8() */
  63548. /* keep the characters out of the heap */
  63549. chars = (s7_pointer *)malloc((NUM_CHARS + 1) * sizeof(s7_pointer));
  63550. chars[0] = sc->eof_object;
  63551. chars++; /* now chars[EOF] == chars[-1] == sc->eof_object */
  63552. {
  63553. s7_cell *cells;
  63554. cells = (s7_cell *)calloc(NUM_CHARS, sizeof(s7_cell));
  63555. for (i = 0; i < NUM_CHARS; i++)
  63556. {
  63557. s7_pointer cp;
  63558. unsigned char c;
  63559. c = (unsigned char)i;
  63560. cp = &cells[i];
  63561. typeflag(cp) = T_IMMUTABLE | T_CHARACTER;
  63562. unheap(cp);
  63563. character(cp) = c;
  63564. upper_character(cp) = (unsigned char)toupper(i);
  63565. is_char_alphabetic(cp) = (bool)isalpha(i);
  63566. is_char_numeric(cp) = (bool)isdigit(i);
  63567. is_char_whitespace(cp) = white_space[i];
  63568. is_char_uppercase(cp) = (((bool)isupper(i)) || ((i >= 192) && (i < 208)));
  63569. is_char_lowercase(cp) = (bool)islower(i);
  63570. chars[i] = cp;
  63571. #define make_character_name(C, S) strncat((char *)(&(character_name(C))), S, character_name_length(C) = strlen(S))
  63572. switch (c)
  63573. {
  63574. case ' ': make_character_name(cp, "#\\space"); break;
  63575. case '\n': make_character_name(cp, "#\\newline"); break;
  63576. case '\r': make_character_name(cp, "#\\return"); break;
  63577. case '\t': make_character_name(cp, "#\\tab"); break;
  63578. case '\0': make_character_name(cp, "#\\null"); break;
  63579. case (char)0x1b: make_character_name(cp, "#\\escape"); break;
  63580. case (char)0x7f: make_character_name(cp, "#\\delete"); break;
  63581. case (char)7: make_character_name(cp, "#\\alarm"); break;
  63582. case (char)8: make_character_name(cp, "#\\backspace"); break;
  63583. default:
  63584. {
  63585. #define P_SIZE 12
  63586. int len;
  63587. if ((c < 32) || (c >= 127))
  63588. len = snprintf((char *)(&(character_name(cp))), P_SIZE, "#\\x%x", c);
  63589. else len = snprintf((char *)(&(character_name(cp))), P_SIZE, "#\\%c", c);
  63590. character_name_length(cp) = len;
  63591. break;
  63592. }
  63593. }
  63594. }
  63595. }
  63596. }
  63597. make_standard_ports(sc);
  63598. sc->syn_docs = (s7_pointer *)calloc(OP_MAX_DEFINED, sizeof(s7_pointer));
  63599. #define QUOTE_HELP "(quote obj) returns obj unevaluated. 'obj is an abbreviation for (quote obj)."
  63600. #define IF_HELP "(if expr true-stuff optional-false-stuff) evaluates expr, then if it is true, evaluates true-stuff; otherwise, \
  63601. if optional-false-stuff exists, it is evaluated."
  63602. #define WHEN_HELP "(when expr ...) evaluates expr, and if it is true, evaluates each form in its body, returning the value of the last"
  63603. #define UNLESS_HELP "(unless expr ...) evaluates expr, and if it is false, evaluates each form in its body, returning the value of the last"
  63604. #define BEGIN_HELP "(begin ...) evaluates each form in its body, returning the value of the last one"
  63605. #define SET_HELP "(set! variable value) sets the value of variable to value."
  63606. #define LET_HELP "(let ((var val)...) ...) binds each variable to its initial value, then evaluates its body,\
  63607. returning the value of the last form. The let variables are local to it, and \
  63608. are not available for use until all have been initialized."
  63609. #define LET_STAR_HELP "(let* ((var val)...) ...) binds each variable to its initial value, then evaluates its body, \
  63610. returning the value of the last form. The let* variables are local to it, and are available immediately."
  63611. #define LETREC_HELP "(letrec ((var (lambda ...)))...) is like let, but var can refer to itself in its value \
  63612. (i.e. you can define local recursive functions)"
  63613. #define LETREC_STAR_HELP "(letrec* ((var val))...) is like letrec, but successive bindings are handled as in let*"
  63614. #define COND_HELP "(cond (expr clause...)...) is like if..then. Each expr is evaluated in order, and if one is not #f, \
  63615. the associated clauses are evaluated, whereupon cond returns."
  63616. #define AND_HELP "(and expr expr ...) evaluates each of its arguments in order, quitting (and returning #f) \
  63617. as soon as one of them returns #f. If all are non-#f, it returns the last value."
  63618. #define OR_HELP "(or expr expr ...) evaluates each of its argments in order, quitting as soon as one of them is not #f. \
  63619. If all are #f, or returns #f."
  63620. #define CASE_HELP "(case val ((key...) clause...)...) looks for val in the various lists of keys, and if a \
  63621. match is found (via eqv?), the associated clauses are evaluated, and case returns."
  63622. #define DO_HELP "(do (vars...) (loop control and return value) ...) is a do-loop."
  63623. #define LAMBDA_HELP "(lambda args ...) returns a function."
  63624. #define LAMBDA_STAR_HELP "(lambda* args ...) returns a function; the args list can have default values, \
  63625. the parameters themselves can be accessed via keywords."
  63626. #define DEFINE_HELP "(define var val) assigns val to the variable (symbol) var. (define (func args) ...) is \
  63627. shorthand for (define func (lambda args ...))"
  63628. #define DEFINE_STAR_HELP "(define* (func args) ...) defines a function with optional/keyword arguments."
  63629. #define DEFINE_CONSTANT_HELP "(define-constant var val) defines var to be a constant (it can't be set or bound), with the value val."
  63630. #define DEFINE_MACRO_HELP "(define-macro (mac args) ...) defines mac to be a macro."
  63631. #define DEFINE_MACRO_STAR_HELP "(define-macro* (mac args) ...) defines mac to be a macro with optional/keyword arguments."
  63632. #define DEFINE_EXPANSION_HELP "(define-expansion (mac args) ...) defines mac to be a read-time macro."
  63633. #define DEFINE_BACRO_HELP "(define-bacro (mac args) ...) defines mac to be a bacro."
  63634. #define DEFINE_BACRO_STAR_HELP "(define-bacro* (mac args) ...) defines mac to be a bacro with optional/keyword arguments."
  63635. #define WITH_BAFFLE_HELP "(with-baffle ...) evaluates its body in a context that is safe from outside interference."
  63636. #define MACROEXPAND_HELP "(macroexpand macro-call) returns the result of the expansion phase of evaluating the macro call."
  63637. #define WITH_LET_HELP "(with-let env ...) evaluates its body in the environment env."
  63638. sc->quote_symbol = assign_syntax(sc, "quote", OP_QUOTE, small_int(1), small_int(1), QUOTE_HELP);
  63639. sc->if_symbol = assign_syntax(sc, "if", OP_IF, small_int(2), small_int(3), IF_HELP);
  63640. sc->when_symbol = assign_syntax(sc, "when", OP_WHEN, small_int(2), max_arity, WHEN_HELP);
  63641. sc->unless_symbol = assign_syntax(sc, "unless", OP_UNLESS, small_int(2), max_arity, UNLESS_HELP);
  63642. sc->begin_symbol = assign_syntax(sc, "begin", OP_BEGIN, small_int(0), max_arity, BEGIN_HELP);
  63643. sc->set_symbol = assign_syntax(sc, "set!", OP_SET, small_int(2), small_int(2), SET_HELP);
  63644. sc->let_symbol = assign_syntax(sc, "let", OP_LET, small_int(2), max_arity, LET_HELP);
  63645. sc->let_star_symbol = assign_syntax(sc, "let*", OP_LET_STAR, small_int(2), max_arity, LET_STAR_HELP);
  63646. sc->letrec_symbol = assign_syntax(sc, "letrec", OP_LETREC, small_int(2), max_arity, LETREC_HELP);
  63647. sc->letrec_star_symbol = assign_syntax(sc, "letrec*", OP_LETREC_STAR, small_int(2), max_arity, LETREC_STAR_HELP);
  63648. sc->cond_symbol = assign_syntax(sc, "cond", OP_COND, small_int(1), max_arity, COND_HELP);
  63649. sc->and_symbol = assign_syntax(sc, "and", OP_AND, small_int(0), max_arity, AND_HELP);
  63650. sc->or_symbol = assign_syntax(sc, "or", OP_OR, small_int(0), max_arity, OR_HELP);
  63651. sc->case_symbol = assign_syntax(sc, "case", OP_CASE, small_int(2), max_arity, CASE_HELP);
  63652. sc->do_symbol = assign_syntax(sc, "do", OP_DO, small_int(2), max_arity, DO_HELP); /* 2 because body can be null */
  63653. sc->lambda_symbol = assign_syntax(sc, "lambda", OP_LAMBDA, small_int(2), max_arity, LAMBDA_HELP);
  63654. sc->lambda_star_symbol = assign_syntax(sc, "lambda*", OP_LAMBDA_STAR, small_int(2), max_arity, LAMBDA_STAR_HELP);
  63655. sc->define_symbol = assign_syntax(sc, "define", OP_DEFINE, small_int(2), max_arity, DEFINE_HELP);
  63656. sc->define_star_symbol = assign_syntax(sc, "define*", OP_DEFINE_STAR, small_int(2), max_arity, DEFINE_STAR_HELP);
  63657. sc->define_constant_symbol = assign_syntax(sc, "define-constant", OP_DEFINE_CONSTANT, small_int(2), max_arity, DEFINE_CONSTANT_HELP);
  63658. sc->define_macro_symbol = assign_syntax(sc, "define-macro", OP_DEFINE_MACRO, small_int(2), max_arity, DEFINE_MACRO_HELP);
  63659. sc->define_macro_star_symbol = assign_syntax(sc, "define-macro*", OP_DEFINE_MACRO_STAR, small_int(2), max_arity, DEFINE_MACRO_STAR_HELP);
  63660. sc->define_expansion_symbol = assign_syntax(sc, "define-expansion",OP_DEFINE_EXPANSION, small_int(2), max_arity, DEFINE_EXPANSION_HELP);
  63661. sc->define_bacro_symbol = assign_syntax(sc, "define-bacro", OP_DEFINE_BACRO, small_int(2), max_arity, DEFINE_BACRO_HELP);
  63662. sc->define_bacro_star_symbol = assign_syntax(sc, "define-bacro*", OP_DEFINE_BACRO_STAR, small_int(2), max_arity, DEFINE_BACRO_STAR_HELP);
  63663. sc->with_baffle_symbol = assign_syntax(sc, "with-baffle", OP_WITH_BAFFLE, small_int(1), max_arity, WITH_BAFFLE_HELP);
  63664. sc->macroexpand_symbol = assign_syntax(sc, "macroexpand", OP_MACROEXPAND, small_int(1), small_int(1), MACROEXPAND_HELP);
  63665. sc->with_let_symbol = assign_syntax(sc, "with-let", OP_WITH_LET, small_int(1), max_arity, WITH_LET_HELP);
  63666. set_immutable(sc->with_let_symbol);
  63667. #if WITH_OPTIMIZATION
  63668. syntax_rp(slot_value(global_slot(sc->set_symbol))) = set_rf;
  63669. syntax_ip(slot_value(global_slot(sc->set_symbol))) = set_if;
  63670. syntax_pp(slot_value(global_slot(sc->set_symbol))) = set_pf;
  63671. syntax_rp(slot_value(global_slot(sc->if_symbol))) = if_rf;
  63672. syntax_pp(slot_value(global_slot(sc->if_symbol))) = if_pf;
  63673. syntax_pp(slot_value(global_slot(sc->or_symbol))) = or_pf;
  63674. syntax_pp(slot_value(global_slot(sc->and_symbol))) = and_pf;
  63675. syntax_pp(slot_value(global_slot(sc->quote_symbol))) = quote_pf;
  63676. #endif
  63677. sc->quote_unchecked_symbol = assign_internal_syntax(sc, "quote", OP_QUOTE_UNCHECKED);
  63678. sc->begin_unchecked_symbol = assign_internal_syntax(sc, "begin", OP_BEGIN_UNCHECKED);
  63679. sc->with_baffle_unchecked_symbol = assign_internal_syntax(sc, "with-baffle", OP_WITH_BAFFLE_UNCHECKED);
  63680. sc->let_unchecked_symbol = assign_internal_syntax(sc, "let", OP_LET_UNCHECKED);
  63681. sc->let_star_unchecked_symbol = assign_internal_syntax(sc, "let*", OP_LET_STAR_UNCHECKED);
  63682. sc->letrec_unchecked_symbol = assign_internal_syntax(sc, "letrec", OP_LETREC_UNCHECKED);
  63683. sc->letrec_star_unchecked_symbol = assign_internal_syntax(sc, "letrec*", OP_LETREC_STAR_UNCHECKED);
  63684. sc->let_no_vars_symbol = assign_internal_syntax(sc, "let", OP_LET_NO_VARS);
  63685. sc->let_c_symbol = assign_internal_syntax(sc, "let", OP_LET_C);
  63686. sc->let_s_symbol = assign_internal_syntax(sc, "let", OP_LET_S);
  63687. sc->let_all_c_symbol = assign_internal_syntax(sc, "let", OP_LET_ALL_C);
  63688. sc->let_all_s_symbol = assign_internal_syntax(sc, "let", OP_LET_ALL_S);
  63689. sc->let_all_x_symbol = assign_internal_syntax(sc, "let", OP_LET_ALL_X);
  63690. sc->let_star_all_x_symbol = assign_internal_syntax(sc, "let*", OP_LET_STAR_ALL_X);
  63691. sc->let_opcq_symbol = assign_internal_syntax(sc, "let", OP_LET_opCq);
  63692. sc->let_opssq_symbol = assign_internal_syntax(sc, "let", OP_LET_opSSq);
  63693. sc->let_opsq_symbol = assign_internal_syntax(sc, "let", OP_LET_opSq);
  63694. sc->let_opsq_p_symbol = assign_internal_syntax(sc, "let", OP_LET_opSq_P);
  63695. sc->let_one_symbol = assign_internal_syntax(sc, "let", OP_LET_ONE);
  63696. sc->let_z_symbol = assign_internal_syntax(sc, "let", OP_LET_Z);
  63697. sc->let_all_opsq_symbol = assign_internal_syntax(sc, "let", OP_LET_ALL_opSq);
  63698. sc->named_let_no_vars_symbol = assign_internal_syntax(sc, "let", OP_NAMED_LET_NO_VARS);
  63699. sc->named_let_symbol = assign_internal_syntax(sc, "let", OP_NAMED_LET);
  63700. sc->named_let_star_symbol = assign_internal_syntax(sc, "let*", OP_NAMED_LET_STAR);
  63701. sc->let_star2_symbol = assign_internal_syntax(sc, "let*", OP_LET_STAR2);
  63702. sc->with_let_unchecked_symbol = assign_internal_syntax(sc, "with-let", OP_WITH_LET_UNCHECKED);
  63703. sc->with_let_s_symbol = assign_internal_syntax(sc, "with-let", OP_WITH_LET_S);
  63704. sc->case_unchecked_symbol = assign_internal_syntax(sc, "case", OP_CASE_UNCHECKED);
  63705. sc->case_simple_symbol = assign_internal_syntax(sc, "case", OP_CASE_SIMPLE);
  63706. sc->case_simpler_symbol = assign_internal_syntax(sc, "case", OP_CASE_SIMPLER);
  63707. sc->case_simpler_1_symbol = assign_internal_syntax(sc, "case", OP_CASE_SIMPLER_1);
  63708. sc->case_simpler_ss_symbol = assign_internal_syntax(sc, "case", OP_CASE_SIMPLER_SS);
  63709. sc->case_simplest_symbol = assign_internal_syntax(sc, "case", OP_CASE_SIMPLEST);
  63710. sc->case_simplest_ss_symbol = assign_internal_syntax(sc, "case", OP_CASE_SIMPLEST_SS);
  63711. sc->cond_unchecked_symbol = assign_internal_syntax(sc, "cond", OP_COND_UNCHECKED);
  63712. sc->cond_simple_symbol = assign_internal_syntax(sc, "cond", OP_COND_SIMPLE);
  63713. sc->do_unchecked_symbol = assign_internal_syntax(sc, "do", OP_DO_UNCHECKED);
  63714. sc->lambda_unchecked_symbol = assign_internal_syntax(sc, "lambda", OP_LAMBDA_UNCHECKED);
  63715. sc->lambda_star_unchecked_symbol = assign_internal_syntax(sc, "lambda*", OP_LAMBDA_STAR_UNCHECKED);
  63716. sc->define_unchecked_symbol = assign_internal_syntax(sc, "define", OP_DEFINE_UNCHECKED);
  63717. sc->define_funchecked_symbol = assign_internal_syntax(sc, "define", OP_DEFINE_FUNCHECKED);
  63718. sc->define_star_unchecked_symbol = assign_internal_syntax(sc, "define*", OP_DEFINE_STAR_UNCHECKED);
  63719. sc->define_constant_unchecked_symbol = assign_internal_syntax(sc, "define-constant", OP_DEFINE_CONSTANT_UNCHECKED);
  63720. sc->set_unchecked_symbol = assign_internal_syntax(sc, "set!", OP_SET_UNCHECKED);
  63721. sc->set_symbol_c_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_C);
  63722. sc->set_symbol_s_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_S);
  63723. sc->set_symbol_q_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_Q);
  63724. sc->set_symbol_opsq_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_opSq);
  63725. sc->set_symbol_opssq_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_opSSq);
  63726. sc->set_symbol_opsssq_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_opSSSq);
  63727. sc->set_symbol_opcq_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_opCq);
  63728. sc->set_symbol_p_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_P);
  63729. sc->set_symbol_z_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_Z);
  63730. sc->set_symbol_a_symbol = assign_internal_syntax(sc, "set!", OP_SET_SYMBOL_A);
  63731. sc->set_normal_symbol = assign_internal_syntax(sc, "set!", OP_SET_NORMAL);
  63732. sc->set_pws_symbol = assign_internal_syntax(sc, "set!", OP_SET_PWS);
  63733. sc->set_pair_symbol = assign_internal_syntax(sc, "set!", OP_SET_PAIR);
  63734. sc->set_pair_p_symbol = assign_internal_syntax(sc, "set!", OP_SET_PAIR_P);
  63735. sc->set_pair_z_symbol = assign_internal_syntax(sc, "set!", OP_SET_PAIR_Z);
  63736. sc->set_pair_a_symbol = assign_internal_syntax(sc, "set!", OP_SET_PAIR_A);
  63737. sc->set_pair_za_symbol = assign_internal_syntax(sc, "set!", OP_SET_PAIR_ZA);
  63738. sc->set_let_s_symbol = assign_internal_syntax(sc, "set!", OP_SET_LET_S);
  63739. sc->set_let_all_x_symbol = assign_internal_syntax(sc, "set!", OP_SET_LET_ALL_X);
  63740. sc->set_pair_c_symbol = assign_internal_syntax(sc, "set!", OP_SET_PAIR_C);
  63741. sc->set_pair_c_p_symbol = assign_internal_syntax(sc, "set!", OP_SET_PAIR_C_P);
  63742. sc->increment_1_symbol = assign_internal_syntax(sc, "set!", OP_INCREMENT_1);
  63743. sc->increment_ss_symbol = assign_internal_syntax(sc, "set!", OP_INCREMENT_SS);
  63744. sc->increment_sss_symbol = assign_internal_syntax(sc, "set!", OP_INCREMENT_SSS);
  63745. sc->increment_sz_symbol = assign_internal_syntax(sc, "set!", OP_INCREMENT_SZ);
  63746. sc->increment_sa_symbol = assign_internal_syntax(sc, "set!", OP_INCREMENT_SA);
  63747. sc->increment_saa_symbol = assign_internal_syntax(sc, "set!", OP_INCREMENT_SAA);
  63748. sc->decrement_1_symbol = assign_internal_syntax(sc, "set!", OP_DECREMENT_1);
  63749. sc->set_cons_symbol = assign_internal_syntax(sc, "set!", OP_SET_CONS);
  63750. sc->and_unchecked_symbol = assign_internal_syntax(sc, "and", OP_AND_UNCHECKED);
  63751. sc->and_p_symbol = assign_internal_syntax(sc, "and", OP_AND_P);
  63752. sc->and_p2_symbol = assign_internal_syntax(sc, "and", OP_AND_P2);
  63753. sc->or_unchecked_symbol = assign_internal_syntax(sc, "or", OP_OR_UNCHECKED);
  63754. sc->or_p_symbol = assign_internal_syntax(sc, "or", OP_OR_P);
  63755. sc->or_p2_symbol = assign_internal_syntax(sc, "or", OP_OR_P2);
  63756. sc->if_unchecked_symbol = assign_internal_syntax(sc, "if", OP_IF_UNCHECKED);
  63757. sc->if_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_P_P);
  63758. sc->if_p_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_P_P_P);
  63759. sc->if_andp_p_symbol = assign_internal_syntax(sc, "if", OP_IF_ANDP_P);
  63760. sc->if_andp_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_ANDP_P_P);
  63761. sc->if_orp_p_symbol = assign_internal_syntax(sc, "if", OP_IF_ORP_P);
  63762. sc->if_orp_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_ORP_P_P);
  63763. sc->if_s_p_symbol = assign_internal_syntax(sc, "if", OP_IF_S_P);
  63764. sc->if_s_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_S_P_P);
  63765. sc->if_p_feed_symbol = assign_internal_syntax(sc, "cond", OP_IF_P_FEED);
  63766. sc->cond_all_x_symbol = assign_internal_syntax(sc, "cond", OP_COND_ALL_X);
  63767. sc->cond_all_x_2_symbol = assign_internal_syntax(sc, "cond", OP_COND_ALL_X_2);
  63768. sc->cond_s_symbol = assign_internal_syntax(sc, "cond", OP_COND_S);
  63769. sc->if_z_p_symbol = assign_internal_syntax(sc, "if", OP_IF_Z_P);
  63770. sc->if_z_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_Z_P_P);
  63771. sc->if_a_p_symbol = assign_internal_syntax(sc, "if", OP_IF_A_P);
  63772. sc->if_a_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_A_P_P);
  63773. sc->if_cc_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CC_P);
  63774. sc->if_cc_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CC_P_P);
  63775. sc->if_cs_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CS_P);
  63776. sc->if_cs_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CS_P_P);
  63777. sc->if_csq_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CSQ_P);
  63778. sc->if_csq_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CSQ_P_P);
  63779. sc->if_css_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CSS_P);
  63780. sc->if_css_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CSS_P_P);
  63781. sc->if_csc_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CSC_P);
  63782. sc->if_csc_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_CSC_P_P);
  63783. sc->if_s_opcq_p_symbol = assign_internal_syntax(sc, "if", OP_IF_S_opCq_P);
  63784. sc->if_s_opcq_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_S_opCq_P_P);
  63785. sc->if_opssq_p_symbol = assign_internal_syntax(sc, "if", OP_IF_opSSq_P);
  63786. sc->if_opssq_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_opSSq_P_P);
  63787. sc->if_is_pair_p_symbol = assign_internal_syntax(sc, "if", OP_IF_IS_PAIR_P);
  63788. sc->if_is_pair_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_IS_PAIR_P_P);
  63789. sc->if_is_symbol_p_symbol = assign_internal_syntax(sc, "if", OP_IF_IS_SYMBOL_P);
  63790. sc->if_is_symbol_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_IS_SYMBOL_P_P);
  63791. sc->if_not_s_p_symbol = assign_internal_syntax(sc, "if", OP_IF_NOT_S_P);
  63792. sc->if_not_s_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_NOT_S_P_P);
  63793. sc->if_and2_p_symbol = assign_internal_syntax(sc, "if", OP_IF_AND2_P);
  63794. sc->if_and2_p_p_symbol = assign_internal_syntax(sc, "if", OP_IF_AND2_P_P);
  63795. sc->when_s_symbol = assign_internal_syntax(sc, "when", OP_WHEN_S);
  63796. sc->unless_s_symbol = assign_internal_syntax(sc, "unless", OP_UNLESS_S);
  63797. sc->when_unchecked_symbol = assign_internal_syntax(sc, "when", OP_WHEN_UNCHECKED);
  63798. sc->unless_unchecked_symbol = assign_internal_syntax(sc, "unless", OP_UNLESS_UNCHECKED);
  63799. sc->dotimes_p_symbol = assign_internal_syntax(sc, "do", OP_DOTIMES_P);
  63800. sc->simple_do_symbol = assign_internal_syntax(sc, "do", OP_SIMPLE_DO);
  63801. sc->simple_do_p_symbol = assign_internal_syntax(sc, "do", OP_SIMPLE_DO_P);
  63802. sc->simple_do_a_symbol = assign_internal_syntax(sc, "do", OP_SIMPLE_DO_A);
  63803. sc->simple_do_e_symbol = assign_internal_syntax(sc, "do", OP_SIMPLE_DO_E);
  63804. sc->safe_dotimes_symbol = assign_internal_syntax(sc, "do", OP_SAFE_DOTIMES);
  63805. sc->safe_do_symbol = assign_internal_syntax(sc, "do", OP_SAFE_DO);
  63806. sc->dox_symbol = assign_internal_syntax(sc, "do", OP_DOX);
  63807. sc->documentation_symbol = make_symbol(sc, "documentation");
  63808. sc->signature_symbol = make_symbol(sc, "signature");
  63809. #if WITH_IMMUTABLE_UNQUOTE
  63810. /* this code solves the various unquote redefinition troubles
  63811. * if "," -> "(unquote...)" in the reader, (let (, (lambda (x) (+ x 1))) ,,,,1) -> 5
  63812. * in s7, this requires a quote: (let (, (lambda (x) (+ x 1))) ,,,,'1)
  63813. */
  63814. sc->unquote_symbol = make_symbol(sc, ",");
  63815. set_immutable(sc->unquote_symbol);
  63816. #else
  63817. sc->unquote_symbol = make_symbol(sc, "unquote");
  63818. #endif
  63819. sc->feed_to_symbol = make_symbol(sc, "=>");
  63820. sc->baffle_symbol = make_symbol(sc, "(baffle)");
  63821. sc->body_symbol = make_symbol(sc, "body");
  63822. sc->error_symbol = make_symbol(sc, "error");
  63823. sc->read_error_symbol = make_symbol(sc, "read-error");
  63824. sc->string_read_error_symbol = make_symbol(sc, "string-read-error");
  63825. sc->syntax_error_symbol = make_symbol(sc, "syntax-error");
  63826. sc->wrong_type_arg_symbol = make_symbol(sc, "wrong-type-arg");
  63827. sc->wrong_number_of_args_symbol = make_symbol(sc, "wrong-number-of-args");
  63828. sc->format_error_symbol = make_symbol(sc, "format-error");
  63829. sc->out_of_range_symbol = make_symbol(sc, "out-of-range");
  63830. sc->no_catch_symbol = make_symbol(sc, "no-catch");
  63831. sc->io_error_symbol = make_symbol(sc, "io-error");
  63832. sc->invalid_escape_function_symbol = make_symbol(sc, "invalid-escape-function");
  63833. sc->baffled_symbol = make_symbol(sc, "baffled!");
  63834. sc->key_allow_other_keys_symbol = s7_make_keyword(sc, "allow-other-keys");
  63835. sc->key_rest_symbol = s7_make_keyword(sc, "rest");
  63836. sc->key_readable_symbol = s7_make_keyword(sc, "readable");
  63837. sc->value_symbol = s7_make_symbol(sc, "value");
  63838. sc->type_symbol = s7_make_symbol(sc, "type");
  63839. sc->__func___symbol = make_symbol(sc, "__func__");
  63840. s7_make_slot(sc, sc->nil, sc->else_symbol = make_symbol(sc, "else"), sc->else_object);
  63841. sc->owlet = init_owlet(sc);
  63842. sc->wrong_type_arg_info = permanent_list(sc, 6);
  63843. set_car(sc->wrong_type_arg_info, s7_make_permanent_string("~A argument ~D, ~S, is ~A but should be ~A"));
  63844. sc->simple_wrong_type_arg_info = permanent_list(sc, 5);
  63845. set_car(sc->simple_wrong_type_arg_info, s7_make_permanent_string("~A argument, ~S, is ~A but should be ~A"));
  63846. sc->out_of_range_info = permanent_list(sc, 5);
  63847. set_car(sc->out_of_range_info, s7_make_permanent_string("~A argument ~D, ~S, is out of range (~A)"));
  63848. sc->simple_out_of_range_info = permanent_list(sc, 4);
  63849. set_car(sc->simple_out_of_range_info, s7_make_permanent_string("~A argument, ~S, is out of range (~A)"));
  63850. sc->too_many_arguments_string = s7_make_permanent_string("~A: too many arguments: ~A");
  63851. sc->not_enough_arguments_string = s7_make_permanent_string("~A: not enough arguments: ~A");
  63852. sc->division_by_zero_error_string = s7_make_permanent_string("~A: division by zero, ~S");
  63853. sc->division_by_zero_symbol = make_symbol(sc, "division-by-zero");
  63854. if (!already_inited)
  63855. init_car_a_list();
  63856. for (i = 0; i < NUM_TYPES; i++)
  63857. {
  63858. const char *str;
  63859. str = type_name_from_type(sc, i, INDEFINITE_ARTICLE);
  63860. if (str)
  63861. prepackaged_type_names[i] = s7_make_permanent_string(str);
  63862. else prepackaged_type_names[i] = sc->F;
  63863. }
  63864. /* unset built-ins: T_STACK (can't happen), T_C_OBJECT (want actual name), T_INPUT|OUTPUT_PORT (want string|file|etc included) */
  63865. sc->gc_off = false;
  63866. #define defun(Scheme_Name, C_Name, Req, Opt, Rst) s7_define_typed_function(sc, Scheme_Name, g_ ## C_Name, Req, Opt, Rst, H_ ## C_Name, Q_ ## C_Name)
  63867. #define unsafe_defun(Scheme_Name, C_Name, Req, Opt, Rst) s7_define_unsafe_typed_function(sc, Scheme_Name, g_ ## C_Name, Req, Opt, Rst, H_ ## C_Name, Q_ ## C_Name)
  63868. /* we need the sc->IS_* symbols first for the procedure signature lists */
  63869. sc->is_boolean_symbol = make_symbol(sc, "boolean?");
  63870. pl_bt = s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->T);
  63871. sc->is_symbol_symbol = defun("symbol?", is_symbol, 1, 0, false);
  63872. sc->is_gensym_symbol = defun("gensym?", is_gensym, 1, 0, false);
  63873. sc->is_keyword_symbol = defun("keyword?", is_keyword, 1, 0, false);
  63874. sc->is_let_symbol = defun("let?", is_let, 1, 0, false);
  63875. sc->is_openlet_symbol = defun("openlet?", is_openlet, 1, 0, false);
  63876. sc->is_iterator_symbol = defun("iterator?", is_iterator, 1, 0, false);
  63877. sc->is_constant_symbol = defun("constant?", is_constant, 1, 0, false);
  63878. sc->is_macro_symbol = defun("macro?", is_macro, 1, 0, false);
  63879. sc->is_c_pointer_symbol = defun("c-pointer?", is_c_pointer, 1, 0, false);
  63880. sc->is_c_object_symbol = defun("c-object?", is_c_object, 1, 0, false);
  63881. sc->is_input_port_symbol = defun("input-port?", is_input_port, 1, 0, false);
  63882. sc->is_output_port_symbol = defun("output-port?", is_output_port, 1, 0, false);
  63883. sc->is_eof_object_symbol = defun("eof-object?", is_eof_object, 1, 0, false);
  63884. sc->is_integer_symbol = defun("integer?", is_integer, 1, 0, false);
  63885. sc->is_number_symbol = defun("number?", is_number, 1, 0, false);
  63886. sc->is_real_symbol = defun("real?", is_real, 1, 0, false);
  63887. sc->is_complex_symbol = defun("complex?", is_complex, 1, 0, false);
  63888. sc->is_rational_symbol = defun("rational?", is_rational, 1, 0, false);
  63889. sc->is_random_state_symbol = defun("random-state?", is_random_state, 1, 0, false);
  63890. sc->is_char_symbol = defun("char?", is_char, 1, 0, false);
  63891. sc->is_string_symbol = defun("string?", is_string, 1, 0, false);
  63892. sc->is_list_symbol = defun("list?", is_list, 1, 0, false);
  63893. sc->is_pair_symbol = defun("pair?", is_pair, 1, 0, false);
  63894. sc->is_vector_symbol = defun("vector?", is_vector, 1, 0, false);
  63895. sc->is_float_vector_symbol = defun("float-vector?", is_float_vector, 1, 0, false);
  63896. sc->is_int_vector_symbol = defun("int-vector?", is_int_vector, 1, 0, false);
  63897. sc->is_byte_vector_symbol = defun("byte-vector?", is_byte_vector, 1, 0, false);
  63898. sc->is_hash_table_symbol = defun("hash-table?", is_hash_table, 1, 0, false);
  63899. sc->is_continuation_symbol = defun("continuation?", is_continuation, 1, 0, false);
  63900. sc->is_procedure_symbol = defun("procedure?", is_procedure, 1, 0, false);
  63901. sc->is_dilambda_symbol = defun("dilambda?", is_dilambda, 1, 0, false);
  63902. /* set above */ defun("boolean?", is_boolean, 1, 0, false);
  63903. sc->is_float_symbol = defun("float?", is_float, 1, 0, false);
  63904. sc->is_proper_list_symbol = defun("proper-list?", is_proper_list, 1, 0, false);
  63905. sc->is_sequence_symbol = defun("sequence?", is_sequence, 1, 0, false);
  63906. sc->is_null_symbol = defun("null?", is_null, 1, 0, false);
  63907. /* do we need 'syntax? */
  63908. sc->is_integer_or_real_at_end_symbol = s7_define_function(sc, "integer:real?", g_is_integer_or_real_at_end, 1, 0, false, "internal signature helper");
  63909. sc->is_integer_or_any_at_end_symbol = s7_define_function(sc, "integer:any?", g_is_integer_or_any_at_end, 1, 0, false, "internal signature helper");
  63910. pl_p = s7_make_signature(sc, 2, sc->T, sc->is_pair_symbol);
  63911. pl_tl = s7_make_signature(sc, 3, s7_make_signature(sc, 2, sc->is_pair_symbol, sc->is_boolean_symbol), sc->T, sc->is_list_symbol); /* memq and memv signature */
  63912. pl_bc = s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_char_symbol);
  63913. pl_bn = s7_make_signature(sc, 2, sc->is_boolean_symbol, sc->is_number_symbol);
  63914. pl_sf = s7_make_signature(sc, 3, sc->T, sc->is_string_symbol, sc->is_procedure_symbol);
  63915. pcl_bt = s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->T);
  63916. pcl_bc = s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_char_symbol);
  63917. pcl_bs = s7_make_circular_signature(sc, 1, 2, sc->is_boolean_symbol, sc->is_string_symbol);
  63918. pcl_i = s7_make_circular_signature(sc, 0, 1, sc->is_integer_symbol);
  63919. pcl_t = s7_make_circular_signature(sc, 0, 1, sc->T);
  63920. pcl_r = s7_make_circular_signature(sc, 0, 1, sc->is_real_symbol);
  63921. pcl_f = s7_make_circular_signature(sc, 0, 1, sc->is_rational_symbol);
  63922. pcl_n = s7_make_circular_signature(sc, 0, 1, sc->is_number_symbol);
  63923. pcl_s = s7_make_circular_signature(sc, 0, 1, sc->is_string_symbol);
  63924. pcl_v = s7_make_circular_signature(sc, 0, 1, sc->is_vector_symbol);
  63925. pcl_c = s7_make_circular_signature(sc, 0, 1, sc->is_char_symbol);
  63926. sc->values_symbol = make_symbol(sc, "values");
  63927. sc->gensym_symbol = defun("gensym", gensym, 0, 1, false);
  63928. defun("symbol-table", symbol_table, 0, 0, false);
  63929. sc->symbol_to_string_symbol = defun("symbol->string", symbol_to_string, 1, 0, false);
  63930. sc->string_to_symbol_symbol = defun("string->symbol", string_to_symbol, 1, 0, false);
  63931. sc->symbol_symbol = defun("symbol", symbol, 1, 0, true);
  63932. sc->symbol_to_value_symbol = defun("symbol->value", symbol_to_value, 1, 1, false);
  63933. sc->symbol_to_dynamic_value_symbol = defun("symbol->dynamic-value", symbol_to_dynamic_value, 1, 0, false);
  63934. s7_typed_dilambda(sc, "symbol-access", g_symbol_access, 1, 1, g_symbol_set_access, 2, 1, H_symbol_access, Q_symbol_access, NULL);
  63935. sc->symbol_access_symbol = make_symbol(sc, "symbol-access");
  63936. sc->make_keyword_symbol = defun("make-keyword", make_keyword, 1, 0, false);
  63937. sc->symbol_to_keyword_symbol = defun("symbol->keyword", symbol_to_keyword, 1, 0, false);
  63938. sc->keyword_to_symbol_symbol = defun("keyword->symbol", keyword_to_symbol, 1, 0, false);
  63939. sc->outlet_symbol = defun("outlet", outlet, 1, 0, false);
  63940. sc->rootlet_symbol = defun("rootlet", rootlet, 0, 0, false);
  63941. sc->curlet_symbol = defun("curlet", curlet, 0, 0, false);
  63942. sc->unlet_symbol = defun("unlet", unlet, 0, 0, false);
  63943. set_immutable(sc->unlet_symbol);
  63944. /* unlet (and with-let) don't actually need to be immutable, but s7.html says they are... */
  63945. sc->sublet_symbol = defun("sublet", sublet, 1, 0, true);
  63946. sc->varlet_symbol = unsafe_defun("varlet", varlet, 1, 0, true);
  63947. sc->cutlet_symbol = unsafe_defun("cutlet", cutlet, 1, 0, true);
  63948. sc->inlet_symbol = defun("inlet", inlet, 0, 0, true);
  63949. sc->owlet_symbol = defun("owlet", owlet, 0, 0, false);
  63950. sc->coverlet_symbol = defun("coverlet", coverlet, 1, 0, false);
  63951. sc->openlet_symbol = defun("openlet", openlet, 1, 0, false);
  63952. sc->let_ref_symbol = defun("let-ref", let_ref, 2, 0, false);
  63953. sc->let_set_symbol = defun("let-set!", let_set, 3, 0, false);
  63954. sc->let_ref_fallback_symbol = make_symbol(sc, "let-ref-fallback");
  63955. sc->let_set_fallback_symbol = make_symbol(sc, "let-set!-fallback");
  63956. sc->make_iterator_symbol = defun("make-iterator", make_iterator, 1, 1, false);
  63957. sc->iterate_symbol = defun("iterate", iterate, 1, 0, false);
  63958. sc->iterator_sequence_symbol = defun("iterator-sequence", iterator_sequence, 1, 0, false);
  63959. sc->iterator_is_at_end_symbol = defun("iterator-at-end?", iterator_is_at_end, 1, 0, false);
  63960. sc->is_provided_symbol = defun("provided?", is_provided, 1, 0, false);
  63961. sc->provide_symbol = defun("provide", provide, 1, 0, false);
  63962. sc->is_defined_symbol = defun("defined?", is_defined, 1, 2, false);
  63963. sc->c_pointer_symbol = defun("c-pointer", c_pointer, 1, 0, false);
  63964. sc->port_line_number_symbol = defun("port-line-number", port_line_number, 0, 1, false);
  63965. sc->port_filename_symbol = defun("port-filename", port_filename, 0, 1, false);
  63966. sc->pair_line_number_symbol = defun("pair-line-number", pair_line_number, 1, 0, false);
  63967. sc->pair_filename_symbol = defun("pair-filename", pair_filename, 1, 0, false);
  63968. sc->is_port_closed_symbol = defun("port-closed?", is_port_closed, 1, 0, false);
  63969. sc->current_input_port_symbol = defun("current-input-port", current_input_port, 0, 0, false);
  63970. sc->current_output_port_symbol = defun("current-output-port", current_output_port, 0, 0, false);
  63971. sc->current_error_port_symbol = defun("current-error-port", current_error_port, 0, 0, false);
  63972. defun("set-current-error-port", set_current_error_port, 1, 0, false);
  63973. #if (!WITH_PURE_S7)
  63974. sc->let_to_list_symbol = defun("let->list", let_to_list, 1, 0, false);
  63975. defun("set-current-input-port", set_current_input_port, 1, 0, false);
  63976. defun("set-current-output-port", set_current_output_port, 1, 0, false);
  63977. sc->is_char_ready_symbol = defun("char-ready?", is_char_ready, 0, 1, false); /* the least-used scheme function */
  63978. #endif
  63979. sc->close_input_port_symbol = defun("close-input-port", close_input_port, 1, 0, false);
  63980. sc->close_output_port_symbol = defun("close-output-port", close_output_port, 1, 0, false);
  63981. sc->flush_output_port_symbol = defun("flush-output-port", flush_output_port, 0, 1, false);
  63982. sc->open_input_file_symbol = defun("open-input-file", open_input_file, 1, 1, false);
  63983. sc->open_output_file_symbol = defun("open-output-file", open_output_file, 1, 1, false);
  63984. sc->open_input_string_symbol = defun("open-input-string", open_input_string, 1, 0, false);
  63985. defun("open-output-string", open_output_string, 0, 0, false);
  63986. sc->get_output_string_symbol = defun("get-output-string", get_output_string, 1, 1, false);
  63987. sc->newline_symbol = defun("newline", newline, 0, 1, false);
  63988. sc->write_symbol = defun("write", write, 1, 1, false);
  63989. sc->display_symbol = defun("display", display, 1, 1, false);
  63990. sc->read_char_symbol = defun("read-char", read_char, 0, 1, false);
  63991. sc->peek_char_symbol = defun("peek-char", peek_char, 0, 1, false);
  63992. sc->write_char_symbol = defun("write-char", write_char, 1, 1, false);
  63993. sc->write_string_symbol = defun("write-string", write_string, 1, 3, false);
  63994. sc->read_byte_symbol = defun("read-byte", read_byte, 0, 1, false);
  63995. sc->write_byte_symbol = defun("write-byte", write_byte, 1, 1, false);
  63996. sc->read_line_symbol = defun("read-line", read_line, 0, 2, false);
  63997. sc->read_string_symbol = defun("read-string", read_string, 1, 1, false);
  63998. sc->read_symbol = unsafe_defun("read", read, 0, 1, false);
  63999. /* read can't be safe because it messes with the stack, expecting to be all by itself in the call sequence
  64000. * (not embedded in OP_SAFE_C_opSq for example) -- that is, it pushes OP_READ_INTERNAL, then returns
  64001. * expecting goto START, which would be nonsense if arg=c_call(read) -> c_call(arg).
  64002. * a safe procedure leaves its argument list alone and does not push anything on the stack
  64003. */
  64004. sc->call_with_input_string_symbol = unsafe_defun("call-with-input-string", call_with_input_string, 2, 0, false);
  64005. sc->call_with_input_file_symbol = unsafe_defun("call-with-input-file", call_with_input_file, 2, 0, false);
  64006. sc->with_input_from_string_symbol = unsafe_defun("with-input-from-string", with_input_from_string, 2, 0, false);
  64007. sc->with_input_from_file_symbol = unsafe_defun("with-input-from-file", with_input_from_file, 2, 0, false);
  64008. sc->call_with_output_string_symbol = unsafe_defun("call-with-output-string", call_with_output_string, 1, 0, false);
  64009. sc->call_with_output_file_symbol = unsafe_defun("call-with-output-file", call_with_output_file, 2, 0, false);
  64010. sc->with_output_to_string_symbol = unsafe_defun("with-output-to-string", with_output_to_string, 1, 0, false);
  64011. sc->with_output_to_file_symbol = unsafe_defun("with-output-to-file", with_output_to_file, 2, 0, false);
  64012. #if WITH_SYSTEM_EXTRAS
  64013. sc->is_directory_symbol = defun("directory?", is_directory, 1, 0, false);
  64014. sc->file_exists_symbol = defun("file-exists?", file_exists, 1, 0, false);
  64015. sc->delete_file_symbol = defun("delete-file", delete_file, 1, 0, false);
  64016. sc->getenv_symbol = defun("getenv", getenv, 1, 0, false);
  64017. sc->system_symbol = defun("system", system, 1, 1, false);
  64018. #ifndef _MSC_VER
  64019. sc->directory_to_list_symbol = defun("directory->list", directory_to_list, 1, 0, false);
  64020. sc->file_mtime_symbol = defun("file-mtime", file_mtime, 1, 0, false);
  64021. #endif
  64022. #endif
  64023. sc->real_part_symbol = defun("real-part", real_part, 1, 0, false);
  64024. sc->imag_part_symbol = defun("imag-part", imag_part, 1, 0, false);
  64025. sc->numerator_symbol = defun("numerator", numerator, 1, 0, false);
  64026. sc->denominator_symbol = defun("denominator", denominator, 1, 0, false);
  64027. sc->is_even_symbol = defun("even?", is_even, 1, 0, false);
  64028. sc->is_odd_symbol = defun("odd?", is_odd, 1, 0, false);
  64029. sc->is_zero_symbol = defun("zero?", is_zero, 1, 0, false);
  64030. sc->is_positive_symbol = defun("positive?", is_positive, 1, 0, false);
  64031. sc->is_negative_symbol = defun("negative?", is_negative, 1, 0, false);
  64032. sc->is_infinite_symbol = defun("infinite?", is_infinite, 1, 0, false);
  64033. sc->is_nan_symbol = defun("nan?", is_nan, 1, 0, false);
  64034. #if (!WITH_GMP)
  64035. sc->complex_symbol = defun("complex", complex, 2, 0, false);
  64036. sc->magnitude_symbol = defun("magnitude", magnitude, 1, 0, false);
  64037. sc->angle_symbol = defun("angle", angle, 1, 0, false);
  64038. sc->rationalize_symbol = defun("rationalize", rationalize, 1, 1, false);
  64039. sc->abs_symbol = defun("abs", abs, 1, 0, false);
  64040. sc->exp_symbol = defun("exp", exp, 1, 0, false);
  64041. sc->log_symbol = defun("log", log, 1, 1, false);
  64042. sc->sin_symbol = defun("sin", sin, 1, 0, false);
  64043. sc->cos_symbol = defun("cos", cos, 1, 0, false);
  64044. sc->tan_symbol = defun("tan", tan, 1, 0, false);
  64045. sc->asin_symbol = defun("asin", asin, 1, 0, false);
  64046. sc->acos_symbol = defun("acos", acos, 1, 0, false);
  64047. sc->atan_symbol = defun("atan", atan, 1, 1, false);
  64048. sc->sinh_symbol = defun("sinh", sinh, 1, 0, false);
  64049. sc->cosh_symbol = defun("cosh", cosh, 1, 0, false);
  64050. sc->tanh_symbol = defun("tanh", tanh, 1, 0, false);
  64051. sc->asinh_symbol = defun("asinh", asinh, 1, 0, false);
  64052. sc->acosh_symbol = defun("acosh", acosh, 1, 0, false);
  64053. sc->atanh_symbol = defun("atanh", atanh, 1, 0, false);
  64054. sc->sqrt_symbol = defun("sqrt", sqrt, 1, 0, false);
  64055. sc->expt_symbol = defun("expt", expt, 2, 0, false);
  64056. sc->floor_symbol = defun("floor", floor, 1, 0, false);
  64057. sc->ceiling_symbol = defun("ceiling", ceiling, 1, 0, false);
  64058. sc->truncate_symbol = defun("truncate", truncate, 1, 0, false);
  64059. sc->round_symbol = defun("round", round, 1, 0, false);
  64060. sc->lcm_symbol = defun("lcm", lcm, 0, 0, true);
  64061. sc->gcd_symbol = defun("gcd", gcd, 0, 0, true);
  64062. sc->add_symbol = defun("+", add, 0, 0, true);
  64063. sc->subtract_symbol = defun("-", subtract, 1, 0, true);
  64064. sc->multiply_symbol = defun("*", multiply, 0, 0, true);
  64065. sc->divide_symbol = defun("/", divide, 1, 0, true);
  64066. sc->max_symbol = defun("max", max, 1, 0, true);
  64067. sc->min_symbol = defun("min", min, 1, 0, true);
  64068. sc->quotient_symbol = defun("quotient", quotient, 2, 0, false);
  64069. sc->remainder_symbol = defun("remainder", remainder, 2, 0, false);
  64070. sc->modulo_symbol = defun("modulo", modulo, 2, 0, false);
  64071. sc->eq_symbol = defun("=", equal, 2, 0, true);
  64072. sc->lt_symbol = defun("<", less, 2, 0, true);
  64073. sc->gt_symbol = defun(">", greater, 2, 0, true);
  64074. sc->leq_symbol = defun("<=", less_or_equal, 2, 0, true);
  64075. sc->geq_symbol = defun(">=", greater_or_equal, 2, 0, true);
  64076. sc->logior_symbol = defun("logior", logior, 0, 0, true);
  64077. sc->logxor_symbol = defun("logxor", logxor, 0, 0, true);
  64078. sc->logand_symbol = defun("logand", logand, 0, 0, true);
  64079. sc->lognot_symbol = defun("lognot", lognot, 1, 0, false);
  64080. sc->ash_symbol = defun("ash", ash, 2, 0, false);
  64081. sc->random_state_symbol = defun("random-state", random_state, 1, 1, false);
  64082. sc->random_symbol = defun("random", random, 1, 1, false);
  64083. #if (!WITH_PURE_S7)
  64084. sc->inexact_to_exact_symbol = defun("inexact->exact", inexact_to_exact, 1, 0, false);
  64085. sc->exact_to_inexact_symbol = defun("exact->inexact", exact_to_inexact, 1, 0, false);
  64086. sc->integer_length_symbol = defun("integer-length", integer_length, 1, 0, false);
  64087. sc->make_polar_symbol = defun("make-polar", make_polar, 2, 0, false);
  64088. sc->make_rectangular_symbol = defun("make-rectangular", complex, 2, 0, false);
  64089. #endif
  64090. #endif /* !gmp */
  64091. sc->logbit_symbol = defun("logbit?", logbit, 2, 0, false);
  64092. sc->integer_decode_float_symbol = defun("integer-decode-float", integer_decode_float, 1, 0, false);
  64093. #if (!WITH_PURE_S7)
  64094. sc->is_exact_symbol = defun("exact?", is_exact, 1, 0, false);
  64095. sc->is_inexact_symbol = defun("inexact?", is_inexact, 1, 0, false);
  64096. #endif
  64097. sc->random_state_to_list_symbol = defun("random-state->list", random_state_to_list, 0, 1, false);
  64098. sc->number_to_string_symbol = defun("number->string", number_to_string, 1, 1, false);
  64099. sc->string_to_number_symbol = defun("string->number", string_to_number, 1, 1, false);
  64100. sc->char_upcase_symbol = defun("char-upcase", char_upcase, 1, 0, false);
  64101. sc->char_downcase_symbol = defun("char-downcase", char_downcase, 1, 0, false);
  64102. sc->char_to_integer_symbol = defun("char->integer", char_to_integer, 1, 0, false);
  64103. sc->integer_to_char_symbol = defun("integer->char", integer_to_char, 1, 0, false);
  64104. sc->is_char_upper_case_symbol = defun("char-upper-case?", is_char_upper_case, 1, 0, false);
  64105. sc->is_char_lower_case_symbol = defun("char-lower-case?", is_char_lower_case, 1, 0, false);
  64106. sc->is_char_alphabetic_symbol = defun("char-alphabetic?", is_char_alphabetic, 1, 0, false);
  64107. sc->is_char_numeric_symbol = defun("char-numeric?", is_char_numeric, 1, 0, false);
  64108. sc->is_char_whitespace_symbol = defun("char-whitespace?", is_char_whitespace, 1, 0, false);
  64109. sc->char_eq_symbol = defun("char=?", chars_are_equal, 2, 0, true);
  64110. sc->char_lt_symbol = defun("char<?", chars_are_less, 2, 0, true);
  64111. sc->char_gt_symbol = defun("char>?", chars_are_greater, 2, 0, true);
  64112. sc->char_leq_symbol = defun("char<=?", chars_are_leq, 2, 0, true);
  64113. sc->char_geq_symbol = defun("char>=?", chars_are_geq, 2, 0, true);
  64114. sc->char_position_symbol = defun("char-position", char_position, 2, 1, false);
  64115. sc->string_position_symbol = defun("string-position", string_position, 2, 1, false);
  64116. sc->make_string_symbol = defun("make-string", make_string, 1, 1, false);
  64117. sc->string_ref_symbol = defun("string-ref", string_ref, 2, 0, false);
  64118. sc->string_set_symbol = defun("string-set!", string_set, 3, 0, false);
  64119. sc->string_eq_symbol = defun("string=?", strings_are_equal, 2, 0, true);
  64120. sc->string_lt_symbol = defun("string<?", strings_are_less, 2, 0, true);
  64121. sc->string_gt_symbol = defun("string>?", strings_are_greater, 2, 0, true);
  64122. sc->string_leq_symbol = defun("string<=?", strings_are_leq, 2, 0, true);
  64123. sc->string_geq_symbol = defun("string>=?", strings_are_geq, 2, 0, true);
  64124. #if (!WITH_PURE_S7)
  64125. sc->char_ci_eq_symbol = defun("char-ci=?", chars_are_ci_equal, 2, 0, true);
  64126. sc->char_ci_lt_symbol = defun("char-ci<?", chars_are_ci_less, 2, 0, true);
  64127. sc->char_ci_gt_symbol = defun("char-ci>?", chars_are_ci_greater, 2, 0, true);
  64128. sc->char_ci_leq_symbol = defun("char-ci<=?", chars_are_ci_leq, 2, 0, true);
  64129. sc->char_ci_geq_symbol = defun("char-ci>=?", chars_are_ci_geq, 2, 0, true);
  64130. sc->string_ci_eq_symbol = defun("string-ci=?", strings_are_ci_equal, 2, 0, true);
  64131. sc->string_ci_lt_symbol = defun("string-ci<?", strings_are_ci_less, 2, 0, true);
  64132. sc->string_ci_gt_symbol = defun("string-ci>?", strings_are_ci_greater, 2, 0, true);
  64133. sc->string_ci_leq_symbol = defun("string-ci<=?", strings_are_ci_leq, 2, 0, true);
  64134. sc->string_ci_geq_symbol = defun("string-ci>=?", strings_are_ci_geq, 2, 0, true);
  64135. sc->string_copy_symbol = defun("string-copy", string_copy, 1, 0, false);
  64136. sc->string_fill_symbol = defun("string-fill!", string_fill, 2, 2, false);
  64137. sc->list_to_string_symbol = defun("list->string", list_to_string, 1, 0, false);
  64138. sc->string_length_symbol = defun("string-length", string_length, 1, 0, false);
  64139. sc->string_to_list_symbol = defun("string->list", string_to_list, 1, 2, false);
  64140. #endif
  64141. sc->string_downcase_symbol = defun("string-downcase", string_downcase, 1, 0, false);
  64142. sc->string_upcase_symbol = defun("string-upcase", string_upcase, 1, 0, false);
  64143. sc->string_append_symbol = defun("string-append", string_append, 0, 0, true);
  64144. sc->substring_symbol = defun("substring", substring, 2, 1, false);
  64145. sc->string_symbol = defun("string", string, 0, 0, true);
  64146. sc->object_to_string_symbol = defun("object->string", object_to_string, 1, 1, false);
  64147. sc->format_symbol = defun("format", format, 1, 0, true);
  64148. /* this was unsafe, but was that due to the (ill-advised) use of temp_call_2 in the arg lists? */
  64149. sc->object_to_let_symbol = defun("object->let", object_to_let, 1, 0, false);
  64150. sc->cons_symbol = defun("cons", cons, 2, 0, false);
  64151. sc->car_symbol = defun("car", car, 1, 0, false);
  64152. sc->cdr_symbol = defun("cdr", cdr, 1, 0, false);
  64153. sc->set_car_symbol = defun("set-car!", set_car, 2, 0, false);
  64154. sc->set_cdr_symbol = unsafe_defun("set-cdr!", set_cdr, 2, 0, false);
  64155. sc->caar_symbol = defun("caar", caar, 1, 0, false);
  64156. sc->cadr_symbol = defun("cadr", cadr, 1, 0, false);
  64157. sc->cdar_symbol = defun("cdar", cdar, 1, 0, false);
  64158. sc->cddr_symbol = defun("cddr", cddr, 1, 0, false);
  64159. sc->caaar_symbol = defun("caaar", caaar, 1, 0, false);
  64160. sc->caadr_symbol = defun("caadr", caadr, 1, 0, false);
  64161. sc->cadar_symbol = defun("cadar", cadar, 1, 0, false);
  64162. sc->cdaar_symbol = defun("cdaar", cdaar, 1, 0, false);
  64163. sc->caddr_symbol = defun("caddr", caddr, 1, 0, false);
  64164. sc->cdddr_symbol = defun("cdddr", cdddr, 1, 0, false);
  64165. sc->cdadr_symbol = defun("cdadr", cdadr, 1, 0, false);
  64166. sc->cddar_symbol = defun("cddar", cddar, 1, 0, false);
  64167. sc->caaaar_symbol = defun("caaaar", caaaar, 1, 0, false);
  64168. sc->caaadr_symbol = defun("caaadr", caaadr, 1, 0, false);
  64169. sc->caadar_symbol = defun("caadar", caadar, 1, 0, false);
  64170. sc->cadaar_symbol = defun("cadaar", cadaar, 1, 0, false);
  64171. sc->caaddr_symbol = defun("caaddr", caaddr, 1, 0, false);
  64172. sc->cadddr_symbol = defun("cadddr", cadddr, 1, 0, false);
  64173. sc->cadadr_symbol = defun("cadadr", cadadr, 1, 0, false);
  64174. sc->caddar_symbol = defun("caddar", caddar, 1, 0, false);
  64175. sc->cdaaar_symbol = defun("cdaaar", cdaaar, 1, 0, false);
  64176. sc->cdaadr_symbol = defun("cdaadr", cdaadr, 1, 0, false);
  64177. sc->cdadar_symbol = defun("cdadar", cdadar, 1, 0, false);
  64178. sc->cddaar_symbol = defun("cddaar", cddaar, 1, 0, false);
  64179. sc->cdaddr_symbol = defun("cdaddr", cdaddr, 1, 0, false);
  64180. sc->cddddr_symbol = defun("cddddr", cddddr, 1, 0, false);
  64181. sc->cddadr_symbol = defun("cddadr", cddadr, 1, 0, false);
  64182. sc->cdddar_symbol = defun("cdddar", cdddar, 1, 0, false);
  64183. sc->assq_symbol = defun("assq", assq, 2, 0, false);
  64184. sc->assv_symbol = defun("assv", assv, 2, 0, false);
  64185. sc->assoc_symbol = unsafe_defun("assoc", assoc, 2, 1, false);
  64186. set_is_possibly_safe(slot_value(global_slot(sc->assoc_symbol)));
  64187. sc->memq_symbol = defun("memq", memq, 2, 0, false);
  64188. sc->memv_symbol = defun("memv", memv, 2, 0, false);
  64189. sc->member_symbol = unsafe_defun("member", member, 2, 1, false);
  64190. set_is_possibly_safe(slot_value(global_slot(sc->member_symbol)));
  64191. sc->list_symbol = defun("list", list, 0, 0, true);
  64192. sc->list_ref_symbol = defun("list-ref", list_ref, 2, 0, true);
  64193. sc->list_set_symbol = defun("list-set!", list_set, 3, 0, true);
  64194. sc->list_tail_symbol = defun("list-tail", list_tail, 2, 0, false);
  64195. sc->make_list_symbol = defun("make-list", make_list, 1, 1, false);
  64196. sc->length_symbol = defun("length", length, 1, 0, false);
  64197. sc->copy_symbol = defun("copy", copy, 1, 3, false);
  64198. sc->fill_symbol = defun("fill!", fill, 2, 2, false);
  64199. sc->reverse_symbol = defun("reverse", reverse, 1, 0, false);
  64200. sc->reverseb_symbol = defun("reverse!", reverse_in_place, 1, 0, false);
  64201. sc->sort_symbol = unsafe_defun("sort!", sort, 2, 0, false);
  64202. sc->append_symbol = defun("append", append, 0, 0, true);
  64203. #if (!WITH_PURE_S7)
  64204. sc->vector_append_symbol = defun("vector-append", vector_append, 0, 0, true);
  64205. sc->list_to_vector_symbol = defun("list->vector", list_to_vector, 1, 0, false);
  64206. sc->vector_fill_symbol = defun("vector-fill!", vector_fill, 2, 2, false);
  64207. sc->vector_length_symbol = defun("vector-length", vector_length, 1, 0, false);
  64208. sc->vector_to_list_symbol = defun("vector->list", vector_to_list, 1, 2, false);
  64209. #else
  64210. sc->vector_append_symbol = sc->append_symbol;
  64211. sc->vector_fill_symbol = sc->fill_symbol;
  64212. sc->string_fill_symbol = sc->fill_symbol;
  64213. #endif
  64214. sc->vector_ref_symbol = defun("vector-ref", vector_ref, 2, 0, true);
  64215. sc->vector_set_symbol = defun("vector-set!", vector_set, 3, 0, true);
  64216. sc->vector_dimensions_symbol = defun("vector-dimensions", vector_dimensions, 1, 0, false);
  64217. sc->make_vector_symbol = defun("make-vector", make_vector, 1, 1, false);
  64218. sc->make_shared_vector_symbol = defun("make-shared-vector", make_shared_vector, 2, 1, false);
  64219. sc->vector_symbol = defun("vector", vector, 0, 0, true);
  64220. set_setter(sc->vector_symbol); /* like cons, I guess */
  64221. sc->vector_function = slot_value(global_slot(sc->vector_symbol));
  64222. sc->float_vector_symbol = defun("float-vector", float_vector, 0, 0, true);
  64223. sc->make_float_vector_symbol = defun("make-float-vector", make_float_vector, 1, 1, false);
  64224. sc->float_vector_set_symbol = defun("float-vector-set!", float_vector_set, 3, 0, true);
  64225. sc->float_vector_ref_symbol = defun("float-vector-ref", float_vector_ref, 2, 0, true);
  64226. sc->int_vector_symbol = defun("int-vector", int_vector, 0, 0, true);
  64227. sc->make_int_vector_symbol = defun("make-int-vector", make_int_vector, 1, 1, false);
  64228. sc->int_vector_set_symbol = defun("int-vector-set!", int_vector_set, 3, 0, true);
  64229. sc->int_vector_ref_symbol = defun("int-vector-ref", int_vector_ref, 2, 0, true);
  64230. sc->string_to_byte_vector_symbol = defun("string->byte-vector", string_to_byte_vector, 1, 0, false);
  64231. sc->byte_vector_symbol = defun("byte-vector", byte_vector, 0, 0, true);
  64232. sc->make_byte_vector_symbol = defun("make-byte-vector", make_byte_vector, 1, 1, false);
  64233. sc->hash_table_symbol = defun("hash-table", hash_table, 0, 0, true);
  64234. sc->hash_table_star_symbol = defun("hash-table*", hash_table_star, 0, 0, true);
  64235. sc->make_hash_table_symbol = defun("make-hash-table", make_hash_table, 0, 2, false);
  64236. sc->hash_table_ref_symbol = defun("hash-table-ref", hash_table_ref, 2, 0, true);
  64237. sc->hash_table_set_symbol = defun("hash-table-set!", hash_table_set, 3, 0, false);
  64238. sc->hash_table_entries_symbol = defun("hash-table-entries", hash_table_entries, 1, 0, false);
  64239. defun("cyclic-sequences", cyclic_sequences, 1, 0, false);
  64240. sc->call_cc_symbol = unsafe_defun("call/cc", call_cc, 1, 0, false);
  64241. sc->call_with_current_continuation_symbol = unsafe_defun("call-with-current-continuation", call_cc, 1, 0, false);
  64242. sc->call_with_exit_symbol = unsafe_defun("call-with-exit", call_with_exit, 1, 0, false);
  64243. sc->load_symbol = unsafe_defun("load", load, 1, 1, false);
  64244. sc->autoload_symbol = unsafe_defun("autoload", autoload, 2, 0, false);
  64245. sc->eval_symbol = unsafe_defun("eval", eval, 1, 1, false);
  64246. sc->eval_string_symbol = unsafe_defun("eval-string", eval_string, 1, 1, false);
  64247. sc->apply_symbol = unsafe_defun("apply", apply, 1, 0, true);
  64248. sc->apply_function = slot_value(global_slot(sc->apply_symbol));
  64249. set_type(sc->apply_function, type(sc->apply_function) | T_COPY_ARGS | T_PROCEDURE);
  64250. /* (let ((x '((1 2) 3 4))) (catch #t (lambda () (apply apply apply x)) (lambda args 'error)) x) should not mess up x! */
  64251. sc->for_each_symbol = unsafe_defun("for-each", for_each, 2, 0, true);
  64252. sc->map_symbol = unsafe_defun("map", map, 2, 0, true);
  64253. sc->dynamic_wind_symbol = unsafe_defun("dynamic-wind", dynamic_wind, 3, 0, false);
  64254. /* sc->values_symbol = */ unsafe_defun("values", values, 0, 0, true);
  64255. sc->catch_symbol = unsafe_defun("catch", catch, 3, 0, false);
  64256. sc->throw_symbol = unsafe_defun("throw", throw, 1, 0, true);
  64257. sc->error_symbol = unsafe_defun("error", error, 0, 0, true);
  64258. /* it's faster to leave error/throw unsafe than to set needs_copied_args and use s7_define_safe_function because copy_list overwhelms any other savings */
  64259. sc->stacktrace_symbol = defun("stacktrace", stacktrace, 0, 5, false);
  64260. { /* these are internal for quasiquote's use */
  64261. s7_pointer sym;
  64262. sym = unsafe_defun("{apply_values}", apply_values, 0, 0, true);
  64263. set_immutable(sym);
  64264. sc->qq_apply_values_function = slot_value(global_slot(sym));
  64265. sym = unsafe_defun("{append}", append, 0, 0, true);
  64266. set_immutable(sym);
  64267. sc->qq_append_function = slot_value(global_slot(sym));
  64268. sym = unsafe_defun("{list}", qq_list, 0, 0, true);
  64269. set_immutable(sym);
  64270. sc->qq_list_function = slot_value(global_slot(sym));
  64271. set_type(sc->qq_list_function, T_C_RST_ARGS_FUNCTION | T_PROCEDURE | T_COPY_ARGS);
  64272. }
  64273. sc->procedure_documentation_symbol = defun("procedure-documentation", procedure_documentation, 1, 0, false);
  64274. sc->procedure_signature_symbol = defun("procedure-signature", procedure_signature, 1, 0, false);
  64275. sc->help_symbol = defun("help", help, 1, 0, false);
  64276. sc->procedure_source_symbol = defun("procedure-source", procedure_source, 1, 0, false);
  64277. sc->funclet_symbol = defun("funclet", funclet, 1, 0, false);
  64278. sc->dilambda_symbol = defun("dilambda", dilambda, 2, 0, false);
  64279. s7_typed_dilambda(sc, "procedure-setter", g_procedure_setter, 1, 0, g_procedure_set_setter, 2, 0, H_procedure_setter, Q_procedure_setter, NULL);
  64280. sc->arity_symbol = defun("arity", arity, 1, 0, false);
  64281. sc->is_aritable_symbol = defun("aritable?", is_aritable, 2, 0, false);
  64282. sc->not_symbol = defun("not", not, 1, 0, false);
  64283. sc->is_eq_symbol = defun("eq?", is_eq, 2, 0, false);
  64284. sc->is_eqv_symbol = defun("eqv?", is_eqv, 2, 0, false);
  64285. sc->is_equal_symbol = defun("equal?", is_equal, 2, 0, false);
  64286. sc->is_morally_equal_symbol = defun("morally-equal?", is_morally_equal, 2, 0, false);
  64287. sc->gc_symbol = defun("gc", gc, 0, 1, false);
  64288. defun("s7-version", s7_version, 0, 0, false);
  64289. defun("emergency-exit", emergency_exit, 0, 1, false);
  64290. defun("exit", exit, 0, 1, false);
  64291. #if DEBUGGING
  64292. s7_define_function(sc, "abort", g_abort, 0, 0, true, "drop into gdb I hope");
  64293. #endif
  64294. sym = s7_define_function(sc, "(c-object set)", g_internal_object_set, 1, 0, true, "internal object setter redirection");
  64295. sc->object_set_function = slot_value(global_slot(sym));
  64296. s7_define_safe_function(sc, "tree-leaves", g_tree_leaves, 1, 0, false, "an experiment");
  64297. /* -------- *features* -------- */
  64298. sc->features_symbol = s7_define_variable(sc, "*features*", sc->nil);
  64299. s7_symbol_set_access(sc, sc->features_symbol, s7_make_function(sc, "(set *features*)", g_features_set, 2, 0, false, "*features* accessor"));
  64300. /* -------- *load-path* -------- */
  64301. sc->load_path_symbol = s7_define_variable_with_documentation(sc, "*load-path*", sc->nil,
  64302. "*load-path* is a list of directories (strings) that the load function searches if it is passed an incomplete file name");
  64303. s7_symbol_set_access(sc, sc->load_path_symbol, s7_make_function(sc, "(set *load-path*)", g_load_path_set, 2, 0, false, "*load-path* accessor"));
  64304. #ifdef CLOAD_DIR
  64305. sc->cload_directory_symbol = s7_define_variable(sc, "*cload-directory*", s7_make_string(sc, (char *)CLOAD_DIR));
  64306. s7_add_to_load_path(sc, (const char *)CLOAD_DIR);
  64307. #else
  64308. sc->cload_directory_symbol = s7_define_variable(sc, "*cload-directory*", make_empty_string(sc, 0, 0));
  64309. #endif
  64310. s7_symbol_set_access(sc, sc->cload_directory_symbol, s7_make_function(sc, "(set *cload-directory*)", g_cload_directory_set, 2, 0, false,
  64311. "*cload-directory* accessor"));
  64312. /* -------- *autoload* --------
  64313. * this pretends to be a hash-table or environment, but it's actually a function
  64314. */
  64315. sc->autoloader_symbol = s7_define_function(sc, "*autoload*", g_autoloader, 1, 0, false, H_autoloader);
  64316. sym = s7_define_variable(sc, "*libraries*", sc->nil);
  64317. sc->libraries = global_slot(sym);
  64318. s7_autoload(sc, make_symbol(sc, "cload.scm"), s7_make_permanent_string("cload.scm"));
  64319. s7_autoload(sc, make_symbol(sc, "lint.scm"), s7_make_permanent_string("lint.scm"));
  64320. s7_autoload(sc, make_symbol(sc, "stuff.scm"), s7_make_permanent_string("stuff.scm"));
  64321. s7_autoload(sc, make_symbol(sc, "mockery.scm"), s7_make_permanent_string("mockery.scm"));
  64322. s7_autoload(sc, make_symbol(sc, "write.scm"), s7_make_permanent_string("write.scm"));
  64323. s7_autoload(sc, make_symbol(sc, "repl.scm"), s7_make_permanent_string("repl.scm"));
  64324. s7_autoload(sc, make_symbol(sc, "r7rs.scm"), s7_make_permanent_string("r7rs.scm"));
  64325. s7_autoload(sc, make_symbol(sc, "libc.scm"), s7_make_permanent_string("libc.scm"));
  64326. s7_autoload(sc, make_symbol(sc, "libm.scm"), s7_make_permanent_string("libm.scm"));
  64327. s7_autoload(sc, make_symbol(sc, "libdl.scm"), s7_make_permanent_string("libdl.scm"));
  64328. s7_autoload(sc, make_symbol(sc, "libgsl.scm"), s7_make_permanent_string("libgsl.scm"));
  64329. s7_autoload(sc, make_symbol(sc, "libgdbm.scm"), s7_make_permanent_string("libgdbm.scm"));
  64330. s7_autoload(sc, make_symbol(sc, "libutf8proc.scm"), s7_make_permanent_string("libutf8proc.scm"));
  64331. sc->require_symbol = s7_define_macro(sc, "require", g_require, 0, 0, true, H_require);
  64332. sc->stacktrace_defaults = s7_list(sc, 5, small_int(3), small_int(45), small_int(80), small_int(45), sc->T);
  64333. /* -------- *#readers* -------- */
  64334. sym = s7_define_variable(sc, "*#readers*", sc->nil);
  64335. sc->sharp_readers = global_slot(sym);
  64336. s7_symbol_set_access(sc, sym, s7_make_function(sc, "(set *#readers*)", g_sharp_readers_set, 2, 0, false, "*#readers* accessor"));
  64337. /* sigh... I don't like these! */
  64338. s7_define_constant(sc, "nan.0", real_NaN);
  64339. s7_define_constant(sc, "-nan.0", real_NaN);
  64340. s7_define_constant(sc, "inf.0", real_infinity);
  64341. s7_define_constant(sc, "-inf.0", real_minus_infinity);
  64342. /* *features* */
  64343. s7_provide(sc, "s7");
  64344. s7_provide(sc, "s7-" S7_VERSION);
  64345. s7_provide(sc, "ratio");
  64346. #if WITH_PURE_S7
  64347. s7_provide(sc, "pure-s7");
  64348. #endif
  64349. #if WITH_EXTRA_EXPONENT_MARKERS
  64350. s7_provide(sc, "dfls-exponents");
  64351. #endif
  64352. #if WITH_SYSTEM_EXTRAS
  64353. s7_provide(sc, "system-extras");
  64354. #endif
  64355. #if WITH_IMMUTABLE_UNQUOTE
  64356. s7_provide(sc, "immutable-unquote");
  64357. #endif
  64358. #if DEBUGGING
  64359. s7_provide(sc, "debugging");
  64360. #endif
  64361. #if WITH_PROFILE
  64362. s7_provide(sc, "profiling");
  64363. #endif
  64364. #if HAVE_COMPLEX_NUMBERS
  64365. s7_provide(sc, "complex-numbers");
  64366. #endif
  64367. #if WITH_C_LOADER
  64368. s7_provide(sc, "dlopen");
  64369. #endif
  64370. #if (!DISABLE_AUTOLOAD)
  64371. s7_provide(sc, "autoload");
  64372. #endif
  64373. #ifdef __APPLE__
  64374. s7_provide(sc, "osx");
  64375. #endif
  64376. #ifdef __linux__
  64377. s7_provide(sc, "linux");
  64378. #endif
  64379. #ifdef __OpenBSD__
  64380. s7_provide(sc, "openbsd");
  64381. #endif
  64382. #ifdef __NetBSD__
  64383. s7_provide(sc, "netbsd");
  64384. #endif
  64385. #ifdef __FreeBSD__
  64386. s7_provide(sc, "freebsd");
  64387. #endif
  64388. #if MS_WINDOWS
  64389. s7_provide(sc, "windows");
  64390. #endif
  64391. #ifdef __bfin__
  64392. s7_provide(sc, "blackfin");
  64393. #endif
  64394. #ifdef __ANDROID__
  64395. s7_provide(sc, "android");
  64396. #endif
  64397. #ifdef __CYGWIN__
  64398. s7_provide(sc, "cygwin");
  64399. #endif
  64400. #ifdef __hpux
  64401. s7_provide(sc, "hpux");
  64402. #endif
  64403. #if defined(__sun) && defined(__SVR4)
  64404. s7_provide(sc, "solaris");
  64405. #endif
  64406. #ifdef __SUNPRO_C
  64407. s7_provide(sc, "sunpro_c");
  64408. #endif
  64409. sc->vector_set_function = slot_value(global_slot(sc->vector_set_symbol));
  64410. set_setter(sc->vector_set_symbol);
  64411. /* not float-vector-set! here */
  64412. sc->list_set_function = slot_value(global_slot(sc->list_set_symbol));
  64413. set_setter(sc->list_set_symbol);
  64414. sc->hash_table_set_function = slot_value(global_slot(sc->hash_table_set_symbol));
  64415. set_setter(sc->hash_table_set_symbol);
  64416. sc->let_set_function = slot_value(global_slot(sc->let_set_symbol));
  64417. set_setter(sc->let_set_symbol);
  64418. set_setter(sc->cons_symbol); /* (this blocks an over-eager do loop optimization -- see do-test-15 in s7test) */
  64419. sc->string_set_function = slot_value(global_slot(sc->string_set_symbol));
  64420. set_setter(sc->string_set_symbol);
  64421. set_setter(sc->set_car_symbol);
  64422. set_setter(sc->set_cdr_symbol);
  64423. #if (!WITH_PURE_S7)
  64424. set_setter(s7_make_symbol(sc, "set-current-input-port"));
  64425. set_setter(s7_make_symbol(sc, "set-current-output-port"));
  64426. s7_function_set_setter(sc, "current-input-port", "set-current-input-port");
  64427. s7_function_set_setter(sc, "current-output-port", "set-current-output-port");
  64428. #endif
  64429. set_setter(s7_make_symbol(sc, "set-current-error-port"));
  64430. s7_function_set_setter(sc, "current-error-port", "set-current-error-port");
  64431. /* despite the similar names, current-error-port is different from the other two, and a setter is needed
  64432. * in scheme because error and warn send output to it by default. It is not a "dynamic variable" unlike
  64433. * the other two. In the input/output cases, setting the port can only cause confusion.
  64434. * current-error-port should simply be an s7 variable with a name like *error-port* and an accessor to
  64435. * ensure its new value, if any, is an output port.
  64436. */
  64437. s7_function_set_setter(sc, "car", "set-car!");
  64438. s7_function_set_setter(sc, "cdr", "set-cdr!");
  64439. s7_function_set_setter(sc, "hash-table-ref", "hash-table-set!");
  64440. s7_function_set_setter(sc, "vector-ref", "vector-set!");
  64441. s7_function_set_setter(sc, "float-vector-ref", "float-vector-set!");
  64442. s7_function_set_setter(sc, "int-vector-ref", "int-vector-set!");
  64443. s7_function_set_setter(sc, "list-ref", "list-set!");
  64444. s7_function_set_setter(sc, "let-ref", "let-set!");
  64445. s7_function_set_setter(sc, "string-ref", "string-set!");
  64446. c_function_set_setter(slot_value(global_slot(sc->outlet_symbol)), s7_make_function(sc, "(set! outlet)", g_set_outlet, 2, 0, false, "outlet setter"));
  64447. c_function_set_setter(slot_value(global_slot(sc->port_line_number_symbol)), s7_make_function(sc, "(set! port-line-number)", g_set_port_line_number, 1, 1, false, "port line setter"));
  64448. {
  64449. int i, top;
  64450. #if WITH_GMP
  64451. #define S7_LOG_LLONG_MAX 36.736800
  64452. #define S7_LOG_LONG_MAX 16.6355322
  64453. #else
  64454. /* actually not safe = (log (- (expt 2 63) 1)) and (log (- (expt 2 31) 1))
  64455. * (using 63 and 31 bits)
  64456. */
  64457. #define S7_LOG_LLONG_MAX 43.668274
  64458. #define S7_LOG_LONG_MAX 21.487562
  64459. #endif
  64460. top = sizeof(s7_int);
  64461. s7_int32_max = (top == 8) ? S7_LONG_MAX : S7_SHORT_MAX;
  64462. s7_int32_min = (top == 8) ? S7_LONG_MIN : S7_SHORT_MIN;
  64463. s7_int_bits = (top == 8) ? 63 : 31;
  64464. s7_int_digits = (top == 8) ? 18 : 8;
  64465. s7_int_max = (top == 8) ? S7_LLONG_MAX : S7_LONG_MAX;
  64466. s7_int_min = (top == 8) ? S7_LLONG_MIN : S7_LONG_MIN;
  64467. s7_int_digits_by_radix[0] = 0;
  64468. s7_int_digits_by_radix[1] = 0;
  64469. for (i = 2; i < 17; i++)
  64470. s7_int_digits_by_radix[i] = (int)(floor(((top == 8) ? S7_LOG_LLONG_MAX : S7_LOG_LONG_MAX) / log((double)i)));
  64471. s7_define_constant(sc, "most-positive-fixnum", make_permanent_integer_unchecked((top == 8) ? s7_int_max : ((top == 4) ? S7_LONG_MAX : S7_SHORT_MAX)));
  64472. s7_define_constant(sc, "most-negative-fixnum", make_permanent_integer_unchecked((top == 8) ? s7_int_min : ((top == 4) ? S7_LONG_MIN : S7_SHORT_MIN)));
  64473. if (top == 4) sc->default_rationalize_error = 1.0e-6;
  64474. s7_define_constant(sc, "pi", real_pi);
  64475. sc->pi_symbol = s7_make_symbol(sc, "pi");
  64476. {
  64477. s7_pointer p;
  64478. new_cell(sc, p, T_RANDOM_STATE);
  64479. #if WITH_GMP
  64480. {
  64481. mpz_t seed;
  64482. mpz_init_set_ui(seed, (unsigned int)time(NULL));
  64483. gmp_randinit_default(random_gmp_state(p));
  64484. gmp_randseed(random_gmp_state(p), seed);
  64485. mpz_clear(seed);
  64486. }
  64487. #else
  64488. random_seed(p) = (unsigned long long int)time(NULL);
  64489. random_carry(p) = 1675393560;
  64490. #endif
  64491. sc->default_rng = p;
  64492. }
  64493. for (i = 0; i < 10; i++) sc->singletons[(unsigned char)'0' + i] = small_int(i);
  64494. sc->singletons[(unsigned char)'+'] = sc->add_symbol;
  64495. sc->singletons[(unsigned char)'-'] = sc->subtract_symbol;
  64496. sc->singletons[(unsigned char)'*'] = sc->multiply_symbol;
  64497. sc->singletons[(unsigned char)'/'] = sc->divide_symbol;
  64498. sc->singletons[(unsigned char)'<'] = sc->lt_symbol;
  64499. sc->singletons[(unsigned char)'>'] = sc->gt_symbol;
  64500. sc->singletons[(unsigned char)'='] = sc->eq_symbol;
  64501. }
  64502. #if WITH_GMP
  64503. s7_gmp_init(sc);
  64504. #endif
  64505. init_choosers(sc);
  64506. s7_define_macro(sc, "quasiquote", g_quasiquote, 1, 0, false, H_quasiquote);
  64507. #if (!WITH_PURE_S7)
  64508. s7_eval_c_string(sc, "(define-macro (defmacro name args . body) `(define-macro ,(cons name args) ,@body))");
  64509. s7_eval_c_string(sc, "(define-macro (defmacro* name args . body) `(define-macro* ,(cons name args) ,@body))");
  64510. s7_eval_c_string(sc, "(define-macro (call-with-values producer consumer) `(,consumer (,producer)))");
  64511. /* (call-with-values (lambda () (values 1 2 3)) +) */
  64512. s7_eval_c_string(sc, "(define-macro (multiple-value-bind vars expression . body) \n\
  64513. `((lambda ,vars ,@body) ,expression))");
  64514. s7_eval_c_string(sc, "(define-macro (cond-expand . clauses) \n\
  64515. (letrec ((traverse (lambda (tree) \n\
  64516. (if (pair? tree) \n\
  64517. (cons (traverse (car tree)) \n\
  64518. (if (null? (cdr tree)) () (traverse (cdr tree)))) \n\
  64519. (if (memq tree '(and or not else)) tree \n\
  64520. (and (symbol? tree) (provided? tree))))))) \n\
  64521. `(cond ,@(map (lambda (clause) \n\
  64522. (cons (traverse (car clause)) \n\
  64523. (if (null? (cdr clause)) '(#f) (cdr clause)))) \n\
  64524. clauses))))");
  64525. #endif
  64526. s7_eval_c_string(sc, "(define-expansion (reader-cond . clauses) \n\
  64527. (call-with-exit \n\
  64528. (lambda (return) \n\
  64529. (for-each \n\
  64530. (lambda (clause) \n\
  64531. (let ((val (eval (car clause)))) \n\
  64532. (if val \n\
  64533. (return (if (null? (cdr clause)) \n\
  64534. val \n\
  64535. (if (null? (cddr clause)) \n\
  64536. (cadr clause) \n\
  64537. (apply values (map quote (cdr clause))))))))) \n\
  64538. clauses) \n\
  64539. (values))))");
  64540. s7_eval_c_string(sc, "(define make-hook \n\
  64541. (let ((signature '(procedure?)) \n\
  64542. (documentation \"(make-hook . pars) returns a new hook (a function) that passes the parameters to its function list.\")) \n\
  64543. (lambda args \n\
  64544. (let ((body ())) \n\
  64545. (apply lambda* args \n\
  64546. '(let ((result #<unspecified>)) \n\
  64547. (let ((hook (curlet))) \n\
  64548. (for-each (lambda (hook-function) (hook-function hook)) body) \n\
  64549. result)) \n\
  64550. ())))))");
  64551. s7_eval_c_string(sc, "(define hook-functions \n\
  64552. (let ((signature '(list? procedure?)) \n\
  64553. (documentation \"(hook-functions hook) gets or sets the list of functions associated with the hook\")) \n\
  64554. (dilambda \n\
  64555. (lambda (hook) \n\
  64556. ((funclet hook) 'body)) \n\
  64557. (lambda (hook lst) \n\
  64558. (if (or (null? lst) \n\
  64559. (and (pair? lst) \n\
  64560. (apply and (map (lambda (f) \n\
  64561. (and (procedure? f) \n\
  64562. (aritable? f 1))) \n\
  64563. lst)))) \n\
  64564. (set! ((funclet hook) 'body) lst) \n\
  64565. (error 'wrong-type-arg \"hook-functions must be a list of functions, each accepting one argument: ~S\" lst))))))");
  64566. s7_eval_c_string(sc, "(define-macro (let-temporarily vars . body) \n\
  64567. `(with-let (#_inlet :orig (#_curlet) \n\
  64568. :saved (#_list ,@(map car vars)) \n\
  64569. :new (#_list ,@(map cadr vars))) \n\
  64570. (when (memq #<undefined> saved) \n\
  64571. (error 'unbound-variable \"let-temporarily: ~A is unbound\" \n\
  64572. (car (list-ref ',vars (- (length saved) (length (memq #<undefined> saved))))))) \n\
  64573. (dynamic-wind \n\
  64574. (lambda () #f) \n\
  64575. (lambda () \n\
  64576. ,@(map (let ((ctr -1)) \n\
  64577. (lambda (v) \n\
  64578. (if (symbol? (car v)) \n\
  64579. `(set! (orig ',(car v)) (list-ref new ,(set! ctr (+ ctr 1)))) \n\
  64580. `(set! (with-let orig ,(car v)) (list-ref new ,(set! ctr (+ ctr 1))))))) \n\
  64581. vars) \n\
  64582. ,(and (pair? body) `(with-let orig ,@body))) \n\
  64583. (lambda () \n\
  64584. ,@(map (let ((ctr -1)) \n\
  64585. (lambda (v) \n\
  64586. (if (symbol? (car v)) \n\
  64587. `(set! (orig ',(car v)) (list-ref saved ,(set! ctr (+ ctr 1)))) \n\
  64588. `(set! (with-let orig ,(car v)) (list-ref saved ,(set! ctr (+ ctr 1))))))) \n\
  64589. vars)))))");
  64590. /* -------- *unbound-variable-hook* -------- */
  64591. sc->unbound_variable_hook = s7_eval_c_string(sc, "(make-hook 'variable)");
  64592. s7_define_constant_with_documentation(sc, "*unbound-variable-hook*", sc->unbound_variable_hook,
  64593. "*unbound-variable-hook* functions are called when an unbound variable is encountered, passed (hook 'variable).");
  64594. /* -------- *missing-close-paren-hook* -------- */
  64595. sc->missing_close_paren_hook = s7_eval_c_string(sc, "(make-hook)");
  64596. s7_define_constant_with_documentation(sc, "*missing-close-paren-hook*", sc->missing_close_paren_hook,
  64597. "*missing-close-paren-hook* functions are called when the reader thinks a close paren is missing");
  64598. /* -------- *load-hook* -------- */
  64599. sc->load_hook = s7_eval_c_string(sc, "(make-hook 'name)");
  64600. s7_define_constant_with_documentation(sc, "*load-hook*", sc->load_hook,
  64601. "*load-hook* functions are invoked by load, passing the to-be-loaded filename as (hook 'name)");
  64602. /* -------- *error-hook* -------- */
  64603. sc->error_hook = s7_eval_c_string(sc, "(make-hook 'type 'data)");
  64604. s7_define_constant_with_documentation(sc, "*error-hook*", sc->error_hook,
  64605. "*error-hook* functions are called in the error handler, passed (hook 'type) and (hook 'data).");
  64606. /* -------- *read-error-hook* -------- */
  64607. sc->read_error_hook = s7_eval_c_string(sc, "(make-hook 'type 'data)");
  64608. s7_define_constant_with_documentation(sc, "*read-error-hook*", sc->read_error_hook,
  64609. "*read-error-hook* functions are called by the reader if it is unhappy, passing the current program string as (hook 'data).");
  64610. s7_define_constant(sc, "*s7*",
  64611. s7_openlet(sc, s7_inlet(sc,
  64612. s7_list(sc, 2,
  64613. s7_cons(sc, sc->let_ref_fallback_symbol, s7_make_function(sc, "s7-let-ref", g_s7_let_ref_fallback, 2, 0, false, "*s7* reader")),
  64614. s7_cons(sc, sc->let_set_fallback_symbol, s7_make_function(sc, "s7-let-set", g_s7_let_set_fallback, 3, 0, false, "*s7* writer"))))));
  64615. #if (!DISABLE_DEPRECATED)
  64616. s7_eval_c_string(sc, "(begin \n\
  64617. (define global-environment rootlet) \n\
  64618. (define current-environment curlet) \n\
  64619. (define make-procedure-with-setter dilambda) \n\
  64620. (define procedure-with-setter? dilambda?)\n\
  64621. (define make-random-state random-state) \n\
  64622. (define make-complex complex) \n\
  64623. (define ->byte-vector string->byte-vector) \n\
  64624. (define (procedure-arity obj) (let ((c (arity obj))) (list (car c) (- (cdr c) (car c)) (> (cdr c) 100000)))))");
  64625. #endif
  64626. /* fprintf(stderr, "size: %d, max op: %d, opt: %d\n", (int)sizeof(s7_cell), OP_MAX_DEFINED, OPT_MAX_DEFINED); */
  64627. /* 64 bit machine: size: 48 [size 72 if gmp], op: 321, opt: 400 */
  64628. if (sizeof(void *) > sizeof(s7_int))
  64629. fprintf(stderr, "s7_int is too small: it has %d bytes, but void* has %d\n", (int)sizeof(s7_int), (int)sizeof(void *));
  64630. save_unlet(sc);
  64631. init_s7_let(sc); /* set up *s7* */
  64632. already_inited = true;
  64633. return(sc);
  64634. }
  64635. /* -------------------------------- repl -------------------------------- */
  64636. #ifndef USE_SND
  64637. #define USE_SND 0
  64638. #endif
  64639. #ifndef WITH_MAIN
  64640. #define WITH_MAIN 0
  64641. #endif
  64642. #if (WITH_MAIN && (!USE_SND))
  64643. int main(int argc, char **argv)
  64644. {
  64645. s7_scheme *sc;
  64646. sc = s7_init();
  64647. if (argc == 2)
  64648. {
  64649. fprintf(stderr, "load %s\n", argv[1]);
  64650. s7_load(sc, argv[1]);
  64651. }
  64652. else
  64653. {
  64654. #ifndef _MSC_VER
  64655. s7_load(sc, "repl.scm"); /* this is libc dependent */
  64656. s7_eval_c_string(sc, "((*repl* 'run))");
  64657. #else
  64658. while (1) /* a minimal repl -- taken from s7.html */
  64659. {
  64660. char buffer[512];
  64661. char response[1024];
  64662. fprintf(stdout, "\n> ");
  64663. fgets(buffer, 512, stdin);
  64664. if ((buffer[0] != '\n') || (strlen(buffer) > 1))
  64665. {
  64666. sprintf(response, "(write %s)", buffer);
  64667. s7_eval_c_string(sc, response);
  64668. }
  64669. }
  64670. #endif
  64671. }
  64672. return(0);
  64673. }
  64674. /* in Linux: gcc s7.c -o repl -DWITH_MAIN -I. -g3 -ldl -lm -Wl,-export-dynamic
  64675. * in *BSD: gcc s7.c -o repl -DWITH_MAIN -I. -g3 -lm -Wl,-export-dynamic
  64676. * in OSX: gcc s7.c -o repl -DWITH_MAIN -I. -g3 -lm
  64677. * (clang also needs LDFLAGS="-Wl,-export-dynamic" in Linux)
  64678. */
  64679. #endif
  64680. /* --------------------------------------------------------------------
  64681. *
  64682. * 12 | 13 | 14 | 15 | 16.0 16.7 16.8
  64683. *
  64684. * s7test 1721 | 1358 | 995 | 1194 | 1122 1928
  64685. * index 44.3 | 3291 | 1725 | 1276 | 1156 1166
  64686. * teq | | | 6612 | 2380 2382
  64687. * tauto 265 | 89 | 9 | 8.4 | 2638 2688
  64688. * tcopy | | | 13.6 | 3204 3133
  64689. * bench 42.7 | 8752 | 4220 | 3506 | 3230 3220
  64690. * tform | | | 6816 | 3627 3709
  64691. * tmap | | | 9.3 | 4176 4172
  64692. * titer | | | 7503 | 5218 5235
  64693. * thash | | | 50.7 | 8491 8496
  64694. * lg | | | | 180.
  64695. * | | | |
  64696. * tgen | 71 | 70.6 | 38.0 | 12.0 11.8
  64697. * tall 90 | 43 | 14.5 | 12.7 | 15.0 14.9
  64698. * calls 359 | 275 | 54 | 34.7 | 37.1 39.1
  64699. *
  64700. * --------------------------------------------------------------------
  64701. *
  64702. * new snd version: snd.h configure.ac HISTORY.Snd NEWS barchive
  64703. *
  64704. * with-set setter (op_set_with_let) still sometimes conses up the new expression
  64705. * if with_history, each func could keep a (circular) history of calls(args/results/stack), vars via symbol-access?
  64706. *
  64707. * Snd:
  64708. * dac loop [need start/end of loop in dac_info, reader goes to start when end reached (requires rebuffering)
  64709. * looper does not stop/restart -- just keep going]
  64710. * play_selection_1 could put ends somewhere, set ends to NO_END_SPECIFIED, dac_loop_sample can
  64711. * use begs/other-ends to get loop points, so free_dac_info does not need to restart the loop(?)
  64712. * If start/end selection changed while playing, are these loop points updated?
  64713. *
  64714. * gtk gl: I can't see how to switch gl in and out as in the motif version -- I guess I need both gl_area and drawing_area
  64715. * the old mus-audio-* code needs to use play or something, especially bess*
  64716. * musglyphs gtk version is broken (probably cairo_t confusion)
  64717. * snd+gtk+script->eps fails?? Also why not make a graph in the no-gui case? t415.scm.
  64718. * remove as many edpos args as possible, and num+bool->num
  64719. * snd namespaces: clm2xen, dac, edits, fft, gxcolormaps, mix, region, snd
  64720. * for snd-mix, tie-ins are in place
  64721. */