~ chicken-core (master) /library.scm
Trap1;;;; library.scm - R5RS/R7RS library for the CHICKEN compiler
2;
3; Copyright (c) 2008-2022, The CHICKEN Team
4; Copyright (c) 2000-2007, Felix L. Winkelmann
5; All rights reserved.
6;
7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
8; conditions are met:
9;
10; Redistributions of source code must retain the above copyright notice, this list of conditions and the following
11; disclaimer.
12; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
13; disclaimer in the documentation and/or other materials provided with the distribution.
14; Neither the name of the author nor the names of its contributors may be used to endorse or promote
15; products derived from this software without specific prior written permission.
16;
17; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25; POSSIBILITY OF SUCH DAMAGE.
26
27
28(declare
29 (unit library)
30 (uses build-version)
31 (disable-interrupts)
32 (hide ##sys#dynamic-unwind
33 ##sys#vector-resize ##sys#default-parameter-vector
34 current-print-length setter-tag
35 ##sys#print-exit ##sys#r7rs-exn-handlers
36 ##sys#format-here-doc-warning
37 exit-in-progress cleanup-before-exit chicken.base#cleanup-tasks
38 maximal-string-length find-ratio-between find-ratio
39 make-complex flonum->ratnum ratnum
40 +maximum-allowed-exponent+ mantexp->dbl ldexp round-quotient
41 ##sys#string->compnum ##sys#internal-gcd)
42 (not inline chicken.base#sleep-hook ##sys#change-directory-hook
43 ##sys#user-read-hook ##sys#error-hook ##sys#signal-hook ##sys#signal-hook/errno
44 ##sys#default-read-info-hook ##sys#infix-list-hook
45 ##sys#sharp-number-hook ##sys#user-print-hook
46 ##sys#user-interrupt-hook ##sys#windows-platform
47 ##sys#resume-thread-on-event ##sys#suspend-thread-on-event
48 ##sys#schedule ##sys#features)
49 (foreign-declare #<<EOF
50#include <errno.h>
51#include <float.h>
52
53#ifdef HAVE_SYSEXITS_H
54# include <sysexits.h>
55#endif
56
57#ifndef EX_SOFTWARE
58# define EX_SOFTWARE 70
59#endif
60
61#define C_close_file(p) (C_fclose((C_FILEPTR)(C_port_file(p))), C_SCHEME_UNDEFINED)
62#define C_a_f64peek(ptr, c, b, i) C_flonum(ptr, ((double *)C_data_pointer(b))[ C_unfix(i) ])
63#define C_fetch_c_strlen(b, i) C_fix(strlen((C_char *)C_block_item(b, C_unfix(i))))
64#define C_asciiz_strlen(str) C_fix(strlen(C_c_string(str)))
65#define C_peek_c_string(b, i, to, len) (C_memcpy(C_data_pointer(to), (C_char *)C_block_item(b, C_unfix(i)), C_unfix(len)), C_SCHEME_UNDEFINED)
66#define C_free_mptr(p, i) (C_free((void *)C_block_item(p, C_unfix(i))), C_SCHEME_UNDEFINED)
67#define C_free_sptr(p, i) (C_free((void *)(((C_char **)C_block_item(p, 0))[ C_unfix(i) ])), C_SCHEME_UNDEFINED)
68
69#define C_a_get_current_seconds(ptr, c, dummy) C_int64_to_num(ptr, time(NULL))
70#define C_peek_c_string_at(ptr, i) ((C_char *)(((C_char **)ptr)[ i ]))
71
72#define C_utf_bytes_needed(b) C_fix(C_utf_expect(C_unfix(b)))
73
74static C_word
75fast_read_line_from_file(C_word str, C_word port, C_word size) {
76 int n = C_unfix(size);
77 int i;
78 int c;
79 char *buf = C_c_string(str);
80 C_FILEPTR fp = C_port_file(port);
81
82 if ((c = C_getc(fp)) == EOF) {
83 if (ferror(fp)) {
84 clearerr(fp);
85 return C_fix(-1);
86 } else { /* feof (fp) */
87 return C_SCHEME_END_OF_FILE;
88 }
89 }
90
91 C_ungetc(c, fp);
92
93 for (i = 0; i < n; i++) {
94 c = C_getc(fp);
95
96 if(c == EOF && ferror(fp)) {
97 clearerr(fp);
98 return C_fix(-(i + 1));
99 }
100
101 switch (c) {
102 case '\r': if ((c = C_getc(fp)) != '\n') C_ungetc(c, fp);
103 case EOF: clearerr(fp);
104 case '\n': return C_fix(i);
105 }
106 buf[i] = c;
107 }
108 return C_SCHEME_FALSE;
109}
110
111static C_word
112fast_read_string_from_file(C_word dest, C_word port, C_word len, C_word pos)
113{
114 size_t m;
115 int n = C_unfix (len);
116 C_char * buf = C_c_string(dest) + C_unfix(pos);
117 C_FILEPTR fp = C_port_file (port);
118
119 if(feof(fp)) return C_SCHEME_END_OF_FILE;
120
121 m = fread (buf, sizeof (char), n, fp);
122
123 if (m < n) {
124 if (ferror(fp)) /* Report to Scheme, which may retry, so clear errors */
125 clearerr(fp);
126 else if (feof(fp) && 0 == m) /* eof but m > 0? Return data first, below */
127 return C_SCHEME_END_OF_FILE; /* Calling again will get us here */
128 }
129
130 return C_fix (m);
131}
132
133static C_word
134shallow_equal(C_word x, C_word y)
135{
136 /* assumes x and y are non-immediate */
137 int i, len = C_header_size(x);
138
139 if(C_header_size(y) != len) return C_SCHEME_FALSE;
140 else return C_mk_bool(!C_memcmp((void *)x, (void *)y, len * sizeof(C_word)));
141}
142
143static C_word
144signal_debug_event(C_word mode, C_word msg, C_word args)
145{
146 C_DEBUG_INFO cell;
147 C_word av[ 3 ];
148 cell.enabled = 1;
149 cell.event = C_DEBUG_SIGNAL;
150 cell.loc = "";
151 cell.val = "";
152 av[ 0 ] = mode;
153 av[ 1 ] = msg;
154 av[ 2 ] = args;
155 C_debugger(&cell, 3, av);
156 return C_SCHEME_UNDEFINED;
157}
158
159static C_word C_i_sleep_until_interrupt(C_word secs)
160{
161 while(C_i_process_sleep(secs) == C_fix(-1) && errno == EINTR);
162 return C_SCHEME_UNDEFINED;
163}
164
165#ifdef NO_DLOAD2
166# define HAVE_DLOAD 0
167#else
168# define HAVE_DLOAD 1
169#endif
170
171#ifdef C_ENABLE_PTABLES
172# define HAVE_PTABLES 1
173#else
174# define HAVE_PTABLES 0
175#endif
176
177#ifdef C_GC_HOOKS
178# define HAVE_GCHOOKS 1
179#else
180# define HAVE_GCHOOKS 0
181#endif
182
183#if defined(C_CROSS_CHICKEN) && C_CROSS_CHICKEN
184# define IS_CROSS_CHICKEN 1
185#else
186# define IS_CROSS_CHICKEN 0
187#endif
188EOF
189) )
190
191;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
192;; NOTE: Modules defined here will typically exclude syntax
193;; definitions, those are handled by expand.scm or modules.scm.
194;; Handwritten import libraries (or a special-case module in
195;; modules.scm for scheme) contain the value exports merged with
196;; syntactic exports. The upshot of this is that any module that
197;; refers to another module defined *earlier* in this file cannot use
198;; macros from the earlier module!
199;;
200;; We get around this problem by using the "chicken.internal.syntax"
201;; module, which is baked in and exports *every* available core macro.
202;; See modules.scm, expand.scm and chicken-syntax.scm for details.
203;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
204
205;; Pre-declaration of scheme, so it can be used later on. We only use
206;; scheme macros and core language forms in here, to avoid a cyclic
207;; dependency on itself. All actual definitions are set! below.
208;; Also, this declaration is incomplete: the module itself is defined
209;; as a primitive module due to syntax exports, which are missing
210;; here. See modules.scm for the full definition.
211(module scheme
212 (;; [syntax]
213 ;; We are reexporting these because otherwise the module here
214 ;; will be inconsistent with the built-in one, and be void of
215 ;; syntax definitions, causing problems below.
216 begin and case cond define define-syntax delay do lambda
217 if let let* let-syntax letrec letrec-syntax or
218 quasiquote quote set! syntax-rules
219
220 not boolean? eq? eqv? equal? pair? boolean=? symbol=?
221 cons car cdr caar cadr cdar cddr caaar caadr cadar caddr cdaar
222 cdadr cddar cdddr caaaar caaadr caadar caaddr cadaar cadadr
223 caddar cadddr cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar
224 cddddr set-car! set-cdr!
225 null? list? list length list-tail list-ref append reverse memq memv
226 member assq assv assoc symbol? symbol->string string->symbol number?
227 integer? exact? real? complex? inexact? rational? zero? odd? even?
228 positive? negative? max min + - * / = > < >= <= quotient remainder
229 modulo gcd lcm abs floor ceiling truncate round rationalize
230 exact->inexact inexact->exact exp log expt sqrt
231 sin cos tan asin acos atan
232 number->string string->number char? char=? char>? char<? char>=?
233 char<=? char-ci=? char-ci<? char-ci>? char-ci>=? char-ci<=?
234 char-alphabetic? char-whitespace? char-numeric? char-upper-case?
235 char-lower-case? char-upcase char-downcase
236 char->integer integer->char
237 string? string=? string>? string<? string>=? string<=? string-ci=?
238 string-ci<? string-ci>? string-ci>=? string-ci<=? make-string
239 string-length string-ref string-set! string-append string-copy string-copy!
240 string->list list->string substring string-fill! vector? make-vector
241 vector-ref vector-set! string vector vector-length vector->list
242 list->vector vector-fill! procedure? map for-each apply force
243 call-with-current-continuation call/cc input-port? output-port?
244 current-input-port current-output-port call-with-input-file
245 call-with-output-file open-input-file open-output-file
246 close-input-port close-output-port
247 read read-char peek-char write display write-char newline
248 eof-object? with-input-from-file with-output-to-file
249 char-ready? imag-part real-part make-rectangular make-polar angle
250 magnitude numerator denominator values call-with-values dynamic-wind
251
252 open-input-string open-output-string open-input-bytevector
253 open-output-bytevector get-output-string get-output-bytevector
254 features make-list port? call-with-port peek-u8 make-parameter
255 string-map vector-map string-for-each vector-for-each
256 make-list list-set! write-string eof-object list-copy
257 string->vector vector->string textual-port? binary-port?
258 input-port-open? output-port-open? floor/ truncate/
259 exact inexact floor-remainder floor-quotient close-port
260
261 ;; The following procedures are overwritten in eval.scm:
262 eval interaction-environment null-environment
263 scheme-report-environment load)
264
265(import chicken.internal.syntax) ;; See note above
266
267;;; Operations on booleans:
268
269(define (not x) (##core#inline "C_i_not" x))
270(define (boolean? x) (##core#inline "C_booleanp" x))
271
272
273;;; Equivalence predicates:
274
275(define (eq? x y) (##core#inline "C_eqp" x y))
276(define (eqv? x y) (##core#inline "C_i_eqvp" x y))
277(define (equal? x y) (##core#inline "C_i_equalp" x y))
278
279(define (boolean=? x y . more)
280 (##sys#check-boolean x 'boolean=?)
281 (##sys#check-boolean y 'boolean=?)
282 (let loop ((bs more) (f (eq? x y)))
283 (if (null? bs)
284 f
285 (let ((b (##sys#slot bs 0)))
286 (##sys#check-boolean b 'boolean=?)
287 (loop (##sys#slot bs 1)
288 (and f (eq? b y)))))))
289
290(define (symbol=? x y . more)
291 (##sys#check-symbol x 'symbol=?)
292 (##sys#check-symbol y 'symbol=?)
293 (let loop ((bs more) (f (eq? x y)))
294 (if (null? bs)
295 f
296 (let ((b (##sys#slot bs 0)))
297 (##sys#check-symbol b 'symbol=?)
298 (loop (##sys#slot bs 1)
299 (and f (eq? b y)))))))
300
301
302;;; Pairs and lists:
303
304(define (pair? x) (##core#inline "C_i_pairp" x))
305(define (cons x y) (##core#inline_allocate ("C_a_i_cons" 3) x y))
306(define (car x) (##core#inline "C_i_car" x))
307(define (cdr x) (##core#inline "C_i_cdr" x))
308
309(define (set-car! x y) (##core#inline "C_i_set_car" x y))
310(define (set-cdr! x y) (##core#inline "C_i_set_cdr" x y))
311(define (cadr x) (##core#inline "C_i_cadr" x))
312(define (caddr x) (##core#inline "C_i_caddr" x))
313(define (cadddr x) (##core#inline "C_i_cadddr" x))
314(define (cddddr x) (##core#inline "C_i_cddddr" x))
315
316(define (caar x) (##core#inline "C_i_caar" x))
317(define (cdar x) (##core#inline "C_i_cdar" x))
318(define (cddr x) (##core#inline "C_i_cddr" x))
319(define (caaar x) (car (car (car x))))
320(define (caadr x) (car (##core#inline "C_i_cadr" x)))
321(define (cadar x) (##core#inline "C_i_cadr" (car x)))
322(define (cdaar x) (cdr (car (car x))))
323(define (cdadr x) (cdr (##core#inline "C_i_cadr" x)))
324(define (cddar x) (cdr (cdr (car x))))
325(define (cdddr x) (cdr (cdr (cdr x))))
326(define (caaaar x) (car (car (car (car x)))))
327(define (caaadr x) (car (car (##core#inline "C_i_cadr" x))))
328(define (caadar x) (car (##core#inline "C_i_cadr" (car x))))
329(define (caaddr x) (car (##core#inline "C_i_caddr" x)))
330(define (cadaar x) (##core#inline "C_i_cadr" (car (car x))))
331(define (cadadr x) (##core#inline "C_i_cadr" (##core#inline "C_i_cadr" x)))
332(define (caddar x) (##core#inline "C_i_caddr" (car x)))
333(define (cdaaar x) (cdr (car (car (car x)))))
334(define (cdaadr x) (cdr (car (##core#inline "C_i_cadr" x))))
335(define (cdadar x) (cdr (##core#inline "C_i_cadr" (car x))))
336(define (cdaddr x) (cdr (##core#inline "C_i_caddr" x)))
337(define (cddaar x) (cdr (cdr (car (car x)))))
338(define (cddadr x) (cdr (cdr (##core#inline "C_i_cadr" x))))
339(define (cdddar x) (cdr (cdr (cdr (car x)))))
340
341(define (null? x) (eq? x '()))
342(define (list . lst) lst)
343(define (length lst) (##core#inline "C_i_length" lst))
344(define (list-tail lst i) (##core#inline "C_i_list_tail" lst i))
345(define (list-ref lst i) (##core#inline "C_i_list_ref" lst i))
346
347(define append)
348
349(define (reverse lst0)
350 (let loop ((lst lst0) (rest '()))
351 (cond ((eq? lst '()) rest)
352 ((pair? lst)
353 (loop (##sys#slot lst 1) (cons (##sys#slot lst 0) rest)) )
354 (else (##sys#error-not-a-proper-list lst0 'reverse)) ) ))
355
356(define (memq x lst) (##core#inline "C_i_memq" x lst))
357(define (memv x lst) (##core#inline "C_i_memv" x lst))
358
359(define (member x lst #!optional eq)
360 (if eq
361 (let loop ((lst lst))
362 (and (pair? lst)
363 (if (eq x (##sys#slot lst 0))
364 lst
365 (loop (##sys#slot lst 1)))))
366 (##core#inline "C_i_member" x lst)))
367
368(define (assq x lst) (##core#inline "C_i_assq" x lst))
369(define (assv x lst) (##core#inline "C_i_assv" x lst))
370
371(define (assoc x lst #!optional eq)
372 (if eq
373 (let loop ((lst lst))
374 (and (pair? lst)
375 (if (eq x (car (##sys#slot lst 0)))
376 (car lst)
377 (loop (##sys#slot lst 1)))))
378 (##core#inline "C_i_assoc" x lst)))
379
380(define (list? x) (##core#inline "C_i_listp" x))
381
382;;; Strings:
383
384(define make-string)
385
386(define (string? x) (##core#inline "C_i_stringp" x))
387(define (string-length s) (##core#inline "C_i_string_length" s))
388(define (string-ref s i) (##core#inline "C_i_string_ref" s i))
389(define (string-set! s i c) (##core#inline "C_i_string_set" s i c))
390
391(define (string=? x y . more)
392 (let loop ((s y) (ss more) (f (##core#inline "C_i_string_equal_p" x y)))
393 (if (null? ss)
394 f
395 (let ((s2 (##sys#slot ss 0)))
396 (##sys#check-string s2 'string=?)
397 (loop s2 (##sys#slot ss 1)
398 (and f (##core#inline "C_i_string_equal_p" s s2)))))))
399
400(define (string-ci=? x y . more)
401 (let loop ((s y) (ss more) (f (##core#inline "C_i_string_ci_equal_p" x y)))
402 (if (null? ss)
403 f
404 (let ((s2 (##sys#slot ss 0)))
405 (##sys#check-string s2 'string-ci=?)
406 (loop s2 (##sys#slot ss 1)
407 (and f (##core#inline "C_i_string_ci_equal_p" s s2)))))))
408
409(define string->list)
410(define list->string)
411(define string-copy)
412(define string-copy!)
413(define substring)
414(define string-fill!)
415
416(define string<?)
417(define string>?)
418(define string<=?)
419(define string>=?)
420
421(define string-ci<?)
422(define string-ci>?)
423(define string-ci<=?)
424(define string-ci>=?)
425
426(define string)
427(define string-append)
428
429(define open-input-string)
430(define open-output-string)
431(define open-input-bytevector)
432(define open-output-bytevector)
433(define get-output-string)
434(define get-output-bytevector)
435(define features)
436(define make-list)
437(define port?)
438(define call-with-port)
439(define close-port)
440(define peek-u8)
441(define string-map)
442(define vector-map)
443(define string-for-each)
444(define vector-for-each)
445(define make-list)
446(define list-set!)
447(define write-string)
448(define eof-object)
449(define list-copy)
450(define string->vector)
451(define vector->string)
452(define input-port-open?)
453(define output-port-open?)
454(define floor/)
455(define truncate/)
456(define exact)
457(define inexact)
458(define floor-remainder)
459(define floor-quotient)
460(define make-parameter)
461
462;; Complex numbers
463(define make-rectangular)
464(define make-polar)
465(define real-part)
466(define imag-part)
467(define angle)
468(define magnitude)
469
470;; Rational numbers
471(define numerator)
472(define denominator)
473(define inexact->exact)
474(define (exact->inexact x)
475 (##core#inline_allocate ("C_a_i_exact_to_inexact" 12) x))
476
477;; Numerical operations
478(define (abs x) (##core#inline_allocate ("C_s_a_i_abs" 7) x))
479(define + (##core#primitive "C_plus"))
480(define - (##core#primitive "C_minus"))
481(define * (##core#primitive "C_times"))
482(define /)
483(define floor)
484(define ceiling)
485(define truncate)
486(define round)
487(define rationalize)
488
489(define (quotient a b) (##core#inline_allocate ("C_s_a_i_quotient" 5) a b))
490(define (remainder a b) (##core#inline_allocate ("C_s_a_i_remainder" 5) a b))
491(define (modulo a b) (##core#inline_allocate ("C_s_a_i_modulo" 5) a b))
492
493(define (even? n) (##core#inline "C_i_evenp" n))
494(define (odd? n) (##core#inline "C_i_oddp" n))
495
496(define max)
497(define min)
498(define exp)
499(define log)
500(define sin)
501(define cos)
502(define tan)
503(define asin)
504(define acos)
505(define atan)
506
507(define sqrt)
508(define expt)
509(define gcd)
510(define lcm)
511
512(define = (##core#primitive "C_nequalp"))
513(define > (##core#primitive "C_greaterp"))
514(define < (##core#primitive "C_lessp"))
515(define >= (##core#primitive "C_greater_or_equal_p"))
516(define <= (##core#primitive "C_less_or_equal_p"))
517(define (number? x) (##core#inline "C_i_numberp" x))
518(define complex? number?)
519(define (real? x) (##core#inline "C_i_realp" x))
520(define (rational? n) (##core#inline "C_i_rationalp" n))
521(define (integer? x) (##core#inline "C_i_integerp" x))
522(define (exact? x) (##core#inline "C_i_exactp" x))
523(define (inexact? x) (##core#inline "C_i_inexactp" x))
524(define (zero? n) (##core#inline "C_i_zerop" n))
525(define (positive? n) (##core#inline "C_i_positivep" n))
526(define (negative? n) (##core#inline "C_i_negativep" n))
527
528(define number->string (##core#primitive "C_number_to_string"))
529(define string->number)
530
531
532;;; Symbols:
533
534(define (symbol? x) (##core#inline "C_i_symbolp" x))
535(define symbol->string)
536(define string->symbol)
537
538;;; Vectors:
539
540(define (vector? x) (##core#inline "C_i_vectorp" x))
541(define (vector-length v) (##core#inline "C_i_vector_length" v))
542(define (vector-ref v i) (##core#inline "C_i_vector_ref" v i))
543(define (vector-set! v i x) (##core#inline "C_i_vector_set" v i x))
544(define make-vector)
545(define list->vector)
546(define vector->list)
547(define vector)
548(define vector-fill!)
549
550;;; Characters:
551
552(define (char? x) (##core#inline "C_charp" x))
553
554(define (char->integer c)
555 (##sys#check-char c 'char->integer)
556 (##core#inline "C_fix" (##core#inline "C_character_code" c)) )
557
558(define (integer->char n)
559 (##sys#check-fixnum n 'integer->char)
560 (##core#inline "C_make_character" (##core#inline "C_unfix" n)) )
561
562(define (char=? c1 c2 . more)
563 (##sys#check-char c1 'char=?)
564 (##sys#check-char c2 'char=?)
565 (let loop ((c c2) (cs more)
566 (f (##core#inline "C_u_i_char_equalp" c1 c2)))
567 (if (null? cs)
568 f
569 (let ((c2 (##sys#slot cs 0)))
570 (##sys#check-char c2 'char=?)
571 (loop c2 (##sys#slot cs 1)
572 (and f (##core#inline "C_u_i_char_equalp" c c2)))))))
573
574(define (char>? c1 c2 . more)
575 (##sys#check-char c1 'char>?)
576 (##sys#check-char c2 'char>?)
577 (let loop ((c c2) (cs more)
578 (f (##core#inline "C_u_i_char_greaterp" c1 c2)))
579 (if (null? cs)
580 f
581 (let ((c2 (##sys#slot cs 0)))
582 (##sys#check-char c2 'char>?)
583 (loop c2 (##sys#slot cs 1)
584 (and f (##core#inline "C_u_i_char_greaterp" c c2)))))))
585
586(define (char<? c1 c2 . more)
587 (##sys#check-char c1 'char<?)
588 (##sys#check-char c2 'char<?)
589 (let loop ((c c2) (cs more)
590 (f (##core#inline "C_u_i_char_lessp" c1 c2)))
591 (if (null? cs)
592 f
593 (let ((c2 (##sys#slot cs 0)))
594 (##sys#check-char c2 'char<?)
595 (loop c2 (##sys#slot cs 1)
596 (and f (##core#inline "C_u_i_char_lessp" c c2)))))))
597
598(define (char>=? c1 c2 . more)
599 (##sys#check-char c1 'char>=?)
600 (##sys#check-char c2 'char>=?)
601 (let loop ((c c2) (cs more)
602 (f (##core#inline "C_u_i_char_greater_or_equal_p" c1 c2)))
603 (if (null? cs)
604 f
605 (let ((c2 (##sys#slot cs 0)))
606 (##sys#check-char c2 'char>=?)
607 (loop c2 (##sys#slot cs 1)
608 (and f (##core#inline "C_u_i_char_greater_or_equal_p" c c2)))))))
609
610(define (char<=? c1 c2 . more)
611 (##sys#check-char c1 'char<=?)
612 (##sys#check-char c2 'char<=?)
613 (let loop ((c c2) (cs more)
614 (f (##core#inline "C_u_i_char_less_or_equal_p" c1 c2)))
615 (if (null? cs)
616 f
617 (let ((c2 (##sys#slot cs 0)))
618 (##sys#check-char c2 'char<=?)
619 (loop c2 (##sys#slot cs 1)
620 (and f (##core#inline "C_u_i_char_less_or_equal_p" c c2)))))))
621
622(define (char-upcase c)
623 (##sys#check-char c 'char-upcase)
624 (##core#inline "C_u_i_char_upcase" c))
625
626(define (char-downcase c)
627 (##sys#check-char c 'char-downcase)
628 (##core#inline "C_u_i_char_downcase" c))
629
630(define char-ci=?)
631(define char-ci>?)
632(define char-ci<?)
633(define char-ci>=?)
634(define char-ci<=?)
635
636(define (char-upper-case? c)
637 (##sys#check-char c 'char-upper-case?)
638 (##core#inline "C_u_i_char_upper_casep" c) )
639
640(define (char-lower-case? c)
641 (##sys#check-char c 'char-lower-case?)
642 (##core#inline "C_u_i_char_lower_casep" c) )
643
644(define (char-numeric? c)
645 (##sys#check-char c 'char-numeric?)
646 (##core#inline "C_u_i_char_numericp" c) )
647
648(define (char-whitespace? c)
649 (##sys#check-char c 'char-whitespace?)
650 (##core#inline "C_u_i_char_whitespacep" c) )
651
652(define (char-alphabetic? c)
653 (##sys#check-char c 'char-alphabetic?)
654 (##core#inline "C_u_i_char_alphabeticp" c) )
655
656(define (scheme.char#digit-value c)
657 (##sys#check-char c 'digit-value)
658 (let ((n (##core#inline "C_u_i_digit_value" c)))
659 (and (not (eq? n 0))
660 (##core#inline "C_fixnum_difference" n 1))))
661
662;;; Procedures:
663
664(define (procedure? x) (##core#inline "C_i_closurep" x))
665(define apply (##core#primitive "C_apply"))
666(define values (##core#primitive "C_values"))
667(define call-with-values (##core#primitive "C_call_with_values"))
668(define call-with-current-continuation)
669(define call/cc)
670
671;;; Ports:
672
673(define (input-port? x)
674 (and (##core#inline "C_blockp" x)
675 (##core#inline "C_input_portp" x)))
676
677(define (output-port? x)
678 (and (##core#inline "C_blockp" x)
679 (##core#inline "C_output_portp" x)))
680
681(define (binary-port? port)
682 (and (port? port)
683 (eq? 'binary (##sys#slot port 14))))
684
685(define (textual-port? port)
686 (and (port? port)
687 (eq? 'textual (##sys#slot port 14))))
688
689(set! scheme#port?
690 (lambda (x)
691 (and (##core#inline "C_blockp" x)
692 (##core#inline "C_portp" x))))
693
694(set! scheme#input-port-open?
695 (lambda (p)
696 (##sys#check-input-port p 'input-port-open?)
697 (##core#inline "C_input_port_openp" p)))
698
699(set! scheme#output-port-open?
700 (lambda (p)
701 (##sys#check-output-port p 'output-port-open?)
702 (##core#inline "C_output_port_openp" p)))
703
704(define current-input-port)
705(define current-output-port)
706(define open-input-file)
707(define open-output-file)
708(define close-input-port)
709(define close-output-port)
710(define call-with-input-file)
711(define call-with-output-file)
712(define with-input-from-file)
713(define with-output-to-file)
714
715;;; Input:
716
717(define (eof-object? x) (##core#inline "C_eofp" x))
718(define char-ready?)
719(define read-char)
720(define peek-char)
721(define read)
722
723;;; Output:
724
725(define write-char)
726(define newline)
727(define write)
728(define display)
729
730;;; Evaluation environments:
731
732;; All of the stuff below is overwritten with their "real"
733;; implementations by chicken.eval (see eval.scm)
734
735(define (eval x . env)
736 (##sys#error 'eval "`eval' is not defined - the `eval' unit was probably not linked with this executable"))
737
738(define (interaction-environment)
739 (##sys#error 'interaction-environment "`interaction-environment' is not defined - the `eval' unit was probably not linked with this executable"))
740
741(define (scheme-report-environment n)
742 (##sys#error 'scheme-report-environment "`scheme-report-environment' is not defined - the `eval' unit was probably not linked with this executable"))
743
744(define (null-environment)
745 (##sys#error 'null-environment "`null-environment' is not defined - the `eval' unit was probably not linked with this executable"))
746
747(define (load filename . evaluator)
748 (##sys#error 'load "`load' is not defined - the `eval' unit was probably not linked with this executable"))
749
750;; Other stuff:
751
752(define force)
753(define for-each)
754(define map)
755(define dynamic-wind)
756
757) ; scheme
758
759(import scheme)
760(import (only (scheme base) make-parameter open-output-string get-output-string))
761
762;; Pre-declaration of chicken.base, so it can be used later on. Much
763;; like the "scheme" module, most declarations will be set! further
764;; down in this file, mostly to avoid a cyclic dependency on itself.
765;; The full definition (with macros) is in its own import library.
766(module chicken.base
767 (;; [syntax] and-let* case-lambda cut cute declare define-constant
768 ;; define-inline define-record define-record-type
769 ;; define-values delay-force fluid-let include
770 ;; include-relative let-optionals let-values let*-values letrec*
771 ;; letrec-values nth-value optional parameterize rec receive
772 ;; require-library require-extension set!-values syntax unless when
773 bignum? flonum? fixnum? ratnum? cplxnum? finite? infinite? nan?
774 exact-integer? exact-integer-sqrt exact-integer-nth-root
775
776 port-closed? flush-output
777 get-call-chain print print* add1 sub1 sleep
778 current-error-port error void gensym print-call-chain
779 char-name enable-warnings
780 equal=? finite? foldl foldr getter-with-setter
781 notice procedure-information setter signum string->uninterned-symbol
782 subvector symbol-append vector-resize
783 warning quotient&remainder quotient&modulo
784 record-printer set-record-printer!
785 make-promise promise?
786 alist-ref alist-update alist-update! rassoc atom? butlast chop
787 compress flatten intersperse join list-of? tail? constantly
788 complement compose conjoin disjoin each flip identity o
789
790 char-foldcase string-foldcase
791
792 case-sensitive keyword-style parentheses-synonyms symbol-escape
793
794 on-exit exit exit-handler implicit-exit-handler emergency-exit
795 bwp-object? weak-cons weak-pair?)
796
797(import scheme chicken.internal.syntax)
798
799(define (fixnum? x) (##core#inline "C_fixnump" x))
800(define (flonum? x) (##core#inline "C_i_flonump" x))
801(define (bignum? x) (##core#inline "C_i_bignump" x))
802(define (ratnum? x) (##core#inline "C_i_ratnump" x))
803(define (cplxnum? x) (##core#inline "C_i_cplxnump" x))
804(define (exact-integer? x) (##core#inline "C_i_exact_integerp" x))
805(define exact-integer-sqrt)
806(define exact-integer-nth-root)
807
808(define quotient&remainder (##core#primitive "C_quotient_and_remainder"))
809;; Modulo's sign follows y (whereas remainder's sign follows x)
810;; Inlining this is not much use: quotient&remainder is primitive
811(define (quotient&modulo x y)
812 (call-with-values (lambda () (quotient&remainder x y))
813 (lambda (div rem)
814 (if (positive? y)
815 (if (negative? rem)
816 (values div (+ rem y))
817 (values div rem))
818 (if (positive? rem)
819 (values div (+ rem y))
820 (values div rem))))))
821
822
823(define (finite? x) (##core#inline "C_i_finitep" x))
824(define (infinite? x) (##core#inline "C_i_infinitep" x))
825(define (nan? x) (##core#inline "C_i_nanp" x))
826
827(define signum (##core#primitive "C_signum"))
828
829(define equal=?)
830(define get-call-chain)
831(define print-call-chain)
832(define print)
833(define print*)
834(define (add1 n) (+ n 1))
835(define (sub1 n) (- n 1))
836(define current-error-port)
837
838(define (error . args)
839 (if (pair? args)
840 (apply ##sys#signal-hook #:error args)
841 (##sys#signal-hook #:error #f)))
842
843(define (void . _) (##core#undefined))
844
845(define sleep)
846
847(define char-name)
848(define enable-warnings)
849; (define enable-notices)???
850(define getter-with-setter)
851(define procedure-information)
852(define setter)
853(define string->uninterned-symbol)
854(define record-printer)
855(define set-record-printer!)
856
857(define gensym)
858
859(define subvector)
860(define vector-resize)
861
862(define symbol-append)
863(define warning)
864(define notice)
865
866(define port-closed?)
867(define flush-output)
868
869;;; Promises:
870
871(define (promise? x)
872 (##sys#structure? x 'promise))
873
874(define (##sys#make-promise proc)
875 (##sys#make-structure 'promise proc))
876
877(define (make-promise obj)
878 (if (promise? obj) obj
879 (##sys#make-promise (lambda () obj))))
880
881;;; fast folds with correct argument order
882
883(define (foldl f z lst)
884 (##sys#check-list lst 'foldl)
885 (let loop ((lst lst) (z z))
886 (if (not (pair? lst))
887 z
888 (loop (##sys#slot lst 1) (f z (##sys#slot lst 0))))))
889
890(define (foldr f z lst)
891 (##sys#check-list lst 'foldr)
892 (let loop ((lst lst))
893 (if (not (pair? lst))
894 z
895 (f (##sys#slot lst 0) (loop (##sys#slot lst 1))))))
896
897;;; Exit:
898
899(define implicit-exit-handler)
900(define exit-handler)
901
902(define chicken.base#cleanup-tasks '())
903
904(define (on-exit thunk)
905 (set! cleanup-tasks (cons thunk chicken.base#cleanup-tasks)))
906
907(define (exit #!optional (code 0))
908 ((exit-handler) code))
909
910(define (emergency-exit #!optional (code 0))
911 (##sys#check-fixnum code 'emergency-exit)
912 (##core#inline "C_exit_runtime" code))
913
914;;; Parameters:
915
916(define case-sensitive)
917(define keyword-style)
918(define parentheses-synonyms)
919(define symbol-escape)
920
921;;; Combinators:
922
923(define (identity x) x)
924
925(define (conjoin . preds)
926 (lambda (x)
927 (let loop ((preds preds))
928 (or (null? preds)
929 (and ((##sys#slot preds 0) x)
930 (loop (##sys#slot preds 1)) ) ) ) ) )
931
932(define (disjoin . preds)
933 (lambda (x)
934 (let loop ((preds preds))
935 (and (not (null? preds))
936 (or ((##sys#slot preds 0) x)
937 (loop (##sys#slot preds 1)) ) ) ) ) )
938
939(define (constantly . xs)
940 (if (eq? 1 (length xs))
941 (let ((x (car xs)))
942 (lambda _ x) )
943 (lambda _ (apply values xs)) ) )
944
945(define (flip proc) (lambda (x y) (proc y x)))
946
947(define complement
948 (lambda (p)
949 (lambda args (not (apply p args))) ) )
950
951(define (compose . fns)
952 (define (rec f0 . fns)
953 (if (null? fns)
954 f0
955 (lambda args
956 (call-with-values
957 (lambda () (apply (apply rec fns) args))
958 f0) ) ) )
959 (if (null? fns)
960 values
961 (apply rec fns) ) )
962
963(define (o . fns)
964 (if (null? fns)
965 identity
966 (let loop ((fns fns))
967 (let ((h (##sys#slot fns 0))
968 (t (##sys#slot fns 1)) )
969 (if (null? t)
970 h
971 (lambda (x) (h ((loop t) x))))))))
972
973(define (list-of? pred)
974 (lambda (lst)
975 (let loop ((lst lst))
976 (cond ((null? lst) #t)
977 ((not (pair? lst)) #f)
978 ((pred (##sys#slot lst 0)) (loop (##sys#slot lst 1)))
979 (else #f) ) ) ) )
980
981(define (each . procs)
982 (cond ((null? procs) (lambda _ (void)))
983 ((null? (##sys#slot procs 1)) (##sys#slot procs 0))
984 (else
985 (lambda args
986 (let loop ((procs procs))
987 (let ((h (##sys#slot procs 0))
988 (t (##sys#slot procs 1)) )
989 (if (null? t)
990 (apply h args)
991 (begin
992 (apply h args)
993 (loop t) ) ) ) ) ) ) ) )
994
995
996;;; Weak pairs:
997(define (bwp-object? x) (##core#inline "C_bwpp" x))
998(define (weak-cons x y) (##core#inline_allocate ("C_a_i_weak_cons" 3) x y))
999(define (weak-pair? x) (##core#inline "C_i_weak_pairp" x))
1000
1001;;; List operators:
1002
1003(define (atom? x) (##core#inline "C_i_not_pair_p" x))
1004
1005(define (tail? x y)
1006 (##sys#check-list y 'tail?)
1007 (let loop ((y y))
1008 (cond ((##core#inline "C_eqp" x y) #t)
1009 ((and (##core#inline "C_blockp" y)
1010 (##core#inline "C_pairp" y))
1011 (loop (##sys#slot y 1)))
1012 (else #f))))
1013
1014(define intersperse
1015 (lambda (lst x)
1016 (let loop ((ns lst))
1017 (if (##core#inline "C_eqp" ns '())
1018 ns
1019 (let ((tail (cdr ns)))
1020 (if (##core#inline "C_eqp" tail '())
1021 ns
1022 (cons (##sys#slot ns 0) (cons x (loop tail))) ) ) ) ) ) )
1023
1024(define (butlast lst)
1025 (##sys#check-pair lst 'butlast)
1026 (let loop ((lst lst))
1027 (let ((next (##sys#slot lst 1)))
1028 (if (and (##core#inline "C_blockp" next) (##core#inline "C_pairp" next))
1029 (cons (##sys#slot lst 0) (loop next))
1030 '() ) ) ) )
1031
1032(define (flatten . lists0)
1033 (let loop ((lists lists0) (rest '()))
1034 (cond ((null? lists) rest)
1035 (else
1036 (let ((head (##sys#slot lists 0))
1037 (tail (##sys#slot lists 1)) )
1038 (if (list? head)
1039 (loop head (loop tail rest))
1040 (cons head (loop tail rest)) ) ) ) ) ) )
1041
1042(define chop)
1043
1044(define (join lsts . lst)
1045 (let ((lst (if (pair? lst) (car lst) '())))
1046 (##sys#check-list lst 'join)
1047 (let loop ((lsts lsts))
1048 (cond ((null? lsts) '())
1049 ((not (pair? lsts))
1050 (##sys#error-not-a-proper-list lsts) )
1051 (else
1052 (let ((l (##sys#slot lsts 0))
1053 (r (##sys#slot lsts 1)) )
1054 (if (null? r)
1055 l
1056 (##sys#append l lst (loop r)) ) ) ) ) ) ) )
1057
1058(define compress
1059 (lambda (blst lst)
1060 (let ((msg "bad argument type - not a proper list"))
1061 (##sys#check-list lst 'compress)
1062 (let loop ((blst blst) (lst lst))
1063 (cond ((null? blst) '())
1064 ((not (pair? blst))
1065 (##sys#signal-hook #:type-error 'compress msg blst) )
1066 ((not (pair? lst))
1067 (##sys#signal-hook #:type-error 'compress msg lst) )
1068 ((##sys#slot blst 0)
1069 (cons (##sys#slot lst 0) (loop (##sys#slot blst 1) (##sys#slot lst 1))))
1070 (else (loop (##sys#slot blst 1) (##sys#slot lst 1))) ) ) ) ) )
1071
1072
1073;; case folding
1074
1075(define (char-foldcase c)
1076 (##sys#check-char c 'char-foldcase)
1077 (##core#inline "C_utf_char_foldcase" c))
1078
1079(define (string-foldcase str)
1080 (##sys#check-string str 'string-foldcase)
1081 (let* ((bv (##sys#slot str 0))
1082 (n (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
1083 (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" n 2)))
1084 (len (##core#inline "C_utf_string_foldcase" bv buf n)))
1085 (##sys#buffer->string buf 0 len)))
1086
1087
1088;;; Alists:
1089
1090(define (alist-update! x y lst #!optional (cmp eqv?))
1091 (let* ((aq (cond ((eq? eq? cmp) assq)
1092 ((eq? eqv? cmp) assv)
1093 ((eq? equal? cmp) assoc)
1094 (else
1095 (lambda (x lst)
1096 (let loop ((lst lst))
1097 (and (pair? lst)
1098 (let ((a (##sys#slot lst 0)))
1099 (if (and (pair? a) (cmp x (##sys#slot a 0)))
1100 a
1101 (loop (##sys#slot lst 1)) ) ) ) ) ) ) ) )
1102 (item (aq x lst)) )
1103 (if item
1104 (begin
1105 (##sys#setslot item 1 y)
1106 lst)
1107 (cons (cons x y) lst) ) ) )
1108
1109(define (alist-update k v lst #!optional (cmp eqv?))
1110 (let loop ((lst lst))
1111 (cond ((null? lst)
1112 (list (cons k v)))
1113 ((not (pair? lst))
1114 (error 'alist-update "bad argument type" lst))
1115 (else
1116 (let ((a (##sys#slot lst 0)))
1117 (cond ((not (pair? a))
1118 (error 'alist-update "bad argument type" a))
1119 ((cmp k (##sys#slot a 0))
1120 (cons (cons k v) (##sys#slot lst 1)))
1121 (else
1122 (cons (cons (##sys#slot a 0) (##sys#slot a 1))
1123 (loop (##sys#slot lst 1))))))))))
1124
1125(define (alist-ref x lst #!optional (cmp eqv?) (default #f))
1126 (let* ((aq (cond ((eq? eq? cmp) assq)
1127 ((eq? eqv? cmp) assv)
1128 ((eq? equal? cmp) assoc)
1129 (else
1130 (lambda (x lst)
1131 (let loop ((lst lst))
1132 (cond
1133 ((null? lst) #f)
1134 ((pair? lst)
1135 (let ((a (##sys#slot lst 0)))
1136 (##sys#check-pair a 'alist-ref)
1137 (if (cmp x (##sys#slot a 0))
1138 a
1139 (loop (##sys#slot lst 1)) ) ))
1140 (else (error 'alist-ref "bad argument type" lst)) ) ) ) ) ) )
1141 (item (aq x lst)) )
1142 (if item
1143 (##sys#slot item 1)
1144 default) ) )
1145
1146;; TODO: Make inlineable in C without "tst", to be more like assoc?
1147(define (rassoc x lst . tst)
1148 (##sys#check-list lst 'rassoc)
1149 (let ((tst (if (pair? tst) (car tst) eqv?)))
1150 (let loop ((l lst))
1151 (and (pair? l)
1152 (let ((a (##sys#slot l 0)))
1153 (##sys#check-pair a 'rassoc)
1154 (if (tst x (##sys#slot a 1))
1155 a
1156 (loop (##sys#slot l 1)) ) ) ) ) ) )
1157
1158) ; chicken.base
1159
1160(import chicken.base)
1161
1162(define-constant output-string-initial-size 256)
1163
1164(set! scheme#open-input-string
1165 (lambda (string)
1166 (##sys#check-string string 'open-input-string)
1167 (let* ((port (##sys#make-port 1 ##sys#string-port-class "(string)" 'string))
1168 (bv (##sys#slot string 0))
1169 (len (##core#inline "C_fixnum_difference" (##sys#size bv) 1))
1170 (bv2 (##sys#make-bytevector len)))
1171 (##core#inline "C_copy_memory" bv2 bv len)
1172 (##sys#setislot port 10 0)
1173 (##sys#setislot port 11 len)
1174 (##sys#setslot port 12 bv2)
1175 port)))
1176
1177(set! scheme#open-output-string
1178 (lambda ()
1179 (let ((port (##sys#make-port 2 ##sys#string-port-class "(string)" 'string)))
1180 (##sys#setislot port 10 0)
1181 (##sys#setislot port 11 output-string-initial-size)
1182 (##sys#setslot port 12 (##sys#make-bytevector output-string-initial-size))
1183 port)))
1184
1185(set! scheme#get-output-string
1186 (lambda (port)
1187 (##sys#check-output-port port #f 'get-output-string)
1188 (if (not (eq? 'string (##sys#slot port 7)))
1189 (##sys#signal-hook
1190 #:type-error 'get-output-string "argument is not a string-output-port" port)
1191 (##sys#buffer->string (##sys#slot port 12) 0 (##sys#slot port 10)))))
1192
1193(set! scheme#open-input-bytevector
1194 (lambda (bv)
1195 (let ((port (##sys#make-port 1 #f "(bytevector)" 'custom)))
1196 (##sys#check-bytevector bv 'open-input-bytevector)
1197 (##sys#setslot port 14 'binary)
1198 (##sys#setslot
1199 port
1200 2
1201 (let ((index 0)
1202 (bv-len (##sys#size bv)))
1203 (vector (lambda (_) ; read-char
1204 (if (eq? index bv-len)
1205 #!eof
1206 (let ((c (##core#inline "C_i_bytevector_ref" bv index)))
1207 (set! index (##core#inline "C_fixnum_plus" index 1))
1208 (integer->char c))))
1209 (lambda (_) ; peek-char
1210 (if (eq? index bv-len)
1211 #!eof
1212 (##core#inline "C_i_bytevector_ref" bv index)))
1213 #f ; write-char
1214 #f ; write-bytevector
1215 (lambda (_ _) ; close
1216 (##sys#setislot port 8 #t))
1217 #f ; flush-output
1218 (lambda (_) ; char-ready?
1219 (not (eq? index bv-len)))
1220 (lambda (p n dest start) ; read-bytevector!
1221 (let ((n2 (min n (##core#inline "C_fixnum_difference" bv-len index))))
1222 (##core#inline "C_copy_memory_with_offset" dest bv start index n2)
1223 (set! index (##core#inline "C_fixnum_plus" index n2))
1224 n2))
1225 #f ; read-line
1226 #f))) ; read-buffered
1227 port)))
1228
1229(set! scheme#open-output-bytevector
1230 (lambda ()
1231 (let ((port (##sys#make-port 2 #f "(bytevector)" 'custom))
1232 (buffer (##sys#make-bytevector 256))
1233 (index 0)
1234 (size 256))
1235 (define (add bv start end)
1236 (let* ((len (##core#inline "C_fixnum_difference" end start))
1237 (i2 (##core#inline "C_fixnum_plus" index len)))
1238 (when (##core#inline "C_fixnum_greaterp" i2 size)
1239 (let* ((sz2 (##core#inline "C_fixnum_times" size 2))
1240 (bv2 (##sys#make-bytevector sz2)))
1241 (##core#inline "C_copy_memory_with_offset" bv2 buffer 0 0 index)
1242 (set! size sz2)
1243 (set! buffer bv2)))
1244 (##core#inline "C_copy_memory_with_offset" buffer bv index start len)
1245 (set! index i2)))
1246 (define (getter)
1247 (let ((bv (##sys#make-bytevector index)))
1248 (##core#inline "C_copy_memory_with_offset" bv buffer 0 0 index)
1249 bv))
1250 (##sys#setslot port 9 getter)
1251 (##sys#setslot port 14 'binary)
1252 (##sys#setslot
1253 port
1254 2
1255 (vector #f ; read-char
1256 #f ; peek-char
1257 (lambda (p c) ; write-char
1258 (let* ((s (string c))
1259 (bv (##sys#slot s 0)))
1260 (add bv 0 (##core#inline "C_fixnum_difference" (##sys#size bv) 1))))
1261 (lambda (p bv start end) ; write-bytevector
1262 (add bv start end))
1263 (lambda (_ _) ; close
1264 (##sys#setislot port 8 #t))
1265 #f ; flush-output
1266 #f ; char-ready?
1267 #f ; read-bytevector!
1268 #f ; read-line
1269 #f)) ; read-buffered
1270 port)))
1271
1272(set! scheme#get-output-bytevector
1273 (lambda (p)
1274 (define (fail) (error 'get-output-bytevector "not an output-bytevector" p))
1275 (##sys#check-port p 'get-output-bytevector)
1276 (if (eq? (##sys#slot p 7) 'custom)
1277 (let ((getter (##sys#slot p 9)))
1278 (if (procedure? getter)
1279 (getter)
1280 (fail)))
1281 (fail))))
1282
1283(define-constant char-name-table-size 37)
1284(define-constant read-line-buffer-initial-size 1024)
1285(define-constant default-parameter-vector-size 16)
1286(define maximal-string-length (- (foreign-value "C_HEADER_SIZE_MASK" unsigned-long) 1))
1287
1288;;; Fixnum arithmetic:
1289
1290(module chicken.fixnum *
1291(import scheme)
1292(import chicken.foreign)
1293
1294(define most-positive-fixnum (foreign-value "C_MOST_POSITIVE_FIXNUM" int))
1295(define most-negative-fixnum (foreign-value "C_MOST_NEGATIVE_FIXNUM" int))
1296(define fixnum-bits (foreign-value "(C_WORD_SIZE - 1)" int))
1297(define fixnum-precision (foreign-value "(C_WORD_SIZE - (1 + 1))" int))
1298
1299(define (fx+ x y) (##core#inline "C_fixnum_plus" x y))
1300(define (fx- x y) (##core#inline "C_fixnum_difference" x y))
1301(define (fx* x y) (##core#inline "C_fixnum_times" x y))
1302(define (fx= x y) (eq? x y))
1303(define (fx> x y) (##core#inline "C_fixnum_greaterp" x y))
1304(define (fx< x y) (##core#inline "C_fixnum_lessp" x y))
1305(define (fx>= x y) (##core#inline "C_fixnum_greater_or_equal_p" x y))
1306(define (fx<= x y) (##core#inline "C_fixnum_less_or_equal_p" x y))
1307(define (fxmin x y) (##core#inline "C_i_fixnum_min" x y))
1308(define (fxmax x y) (##core#inline "C_i_fixnum_max" x y))
1309(define (fxneg x) (##core#inline "C_fixnum_negate" x))
1310(define (fxand x y) (##core#inline "C_fixnum_and" x y))
1311(define (fxior x y) (##core#inline "C_fixnum_or" x y))
1312(define (fxxor x y) (##core#inline "C_fixnum_xor" x y))
1313(define (fxnot x) (##core#inline "C_fixnum_not" x))
1314(define (fxshl x y) (##core#inline "C_fixnum_shift_left" x y))
1315(define (fxshr x y) (##core#inline "C_fixnum_shift_right" x y))
1316(define (fxodd? x) (##core#inline "C_i_fixnumoddp" x))
1317(define (fxeven? x) (##core#inline "C_i_fixnumevenp" x))
1318(define (fxlen x) (##core#inline "C_i_fixnum_length" x))
1319(define (fx/ x y) (##core#inline "C_fixnum_divide" x y) )
1320(define (fxgcd x y) (##core#inline "C_i_fixnum_gcd" x y))
1321(define (fxmod x y) (##core#inline "C_fixnum_modulo" x y) )
1322(define (fxrem x y) (##core#inline "C_i_fixnum_remainder_checked" x y) )
1323
1324;; Overflow-detecting versions of some of the above
1325(define (fx+? x y) (##core#inline "C_i_o_fixnum_plus" x y) )
1326(define (fx-? x y) (##core#inline "C_i_o_fixnum_difference" x y) )
1327(define (fx*? x y) (##core#inline "C_i_o_fixnum_times" x y) )
1328(define (fx/? x y) (##core#inline "C_i_o_fixnum_quotient" x y))
1329
1330) ; chicken.fixnum
1331
1332(import chicken.fixnum)
1333
1334
1335;;; System routines:
1336
1337(define (##sys#debug-mode?) (##core#inline "C_i_debug_modep"))
1338
1339(define ##sys#warnings-enabled #t)
1340(define ##sys#notices-enabled (##sys#debug-mode?))
1341
1342(set! chicken.base#warning
1343 (lambda (msg . args)
1344 (when ##sys#warnings-enabled
1345 (apply ##sys#signal-hook #:warning msg args))))
1346
1347(set! chicken.base#notice
1348 (lambda (msg . args)
1349 (when (and ##sys#notices-enabled
1350 ##sys#warnings-enabled)
1351 (apply ##sys#signal-hook #:notice msg args))))
1352
1353(set! chicken.base#enable-warnings
1354 (lambda bool
1355 (if (pair? bool)
1356 (set! ##sys#warnings-enabled (car bool))
1357 ##sys#warnings-enabled)))
1358
1359(define ##sys#error error)
1360(define ##sys#warn warning)
1361(define ##sys#notice notice)
1362
1363(define (##sys#error/errno err . args)
1364 (if (pair? args)
1365 (apply ##sys#signal-hook/errno #:error err #f args)
1366 (##sys#signal-hook/errno #:error err #f)))
1367
1368(define-foreign-variable strerror c-string "strerror(errno)")
1369
1370(define ##sys#gc (##core#primitive "C_gc"))
1371(define (##sys#setslot x i y) (##core#inline "C_i_setslot" x i y))
1372(define (##sys#setislot x i y) (##core#inline "C_i_set_i_slot" x i y))
1373(define ##sys#allocate-vector (##core#primitive "C_allocate_vector"))
1374(define ##sys#allocate-bytevector (##core#primitive "C_allocate_bytevector"))
1375(define ##sys#make-structure (##core#primitive "C_make_structure"))
1376(define ##sys#ensure-heap-reserve (##core#primitive "C_ensure_heap_reserve"))
1377(define ##sys#symbol-table-info (##core#primitive "C_get_symbol_table_info"))
1378(define ##sys#memory-info (##core#primitive "C_get_memory_info"))
1379
1380(define (##sys#start-timer)
1381 (##sys#gc #t)
1382 (##core#inline "C_start_timer"))
1383
1384(define (##sys#stop-timer)
1385 (let ((info ((##core#primitive "C_stop_timer"))))
1386 ;; Run a major GC one more time to get memory usage information in
1387 ;; case there was no major GC while the timer was running
1388 (##sys#gc #t)
1389 (##sys#setslot info 6 (##sys#slot ((##core#primitive "C_stop_timer")) 6))
1390 info))
1391
1392(define (##sys#immediate? x) (not (##core#inline "C_blockp" x)))
1393(define (##sys#message str) (##core#inline "C_message" str))
1394(define (##sys#byte x i) (##core#inline "C_subbyte" x i))
1395(define ##sys#void void)
1396(define ##sys#undefined-value (##core#undefined))
1397(define (##sys#halt msg) (##core#inline "C_halt" msg))
1398(define ##sys#become! (##core#primitive "C_become"))
1399(define (##sys#block-ref x i) (##core#inline "C_i_block_ref" x i))
1400(define ##sys#apply-values (##core#primitive "C_apply_values"))
1401(define ##sys#copy-closure (##core#primitive "C_copy_closure"))
1402
1403(define (##sys#block-set! x i y)
1404 (when (or (not (##core#inline "C_blockp" x))
1405 (and (##core#inline "C_specialp" x) (fx= i 0))
1406 (##core#inline "C_byteblockp" x) )
1407 (##sys#signal-hook '#:type-error '##sys#block-set! "slot not accessible" x) )
1408 (##sys#check-range i 0 (##sys#size x) '##sys#block-set!)
1409 (##sys#setslot x i y) )
1410
1411(module chicken.time
1412 ;; NOTE: We don't emit the import lib. Due to syntax exports, it has
1413 ;; to be a hardcoded primitive module.
1414 ;;
1415 ;; [syntax] time
1416 (cpu-time
1417 current-process-milliseconds current-seconds)
1418
1419(import scheme)
1420(import (only chicken.module reexport))
1421
1422(define (current-process-milliseconds)
1423 (##core#inline_allocate ("C_a_i_current_process_milliseconds" 7) #f))
1424
1425(define (current-seconds)
1426 (##core#inline_allocate ("C_a_get_current_seconds" 7) #f))
1427
1428(define cpu-time
1429 (let () ;; ((buf (vector #f #f))) Disabled for now: vector is defined below!
1430 (lambda ()
1431 (let ((buf (vector #f #f)))
1432 ;; should be thread-safe as no context-switch will occur after
1433 ;; function entry and `buf' contents will have been extracted
1434 ;; before `values' gets called.
1435 (##core#inline_allocate ("C_a_i_cpu_time" 8) buf)
1436 (values (##sys#slot buf 0) (##sys#slot buf 1)) )) ))
1437
1438) ; chicken.time
1439
1440(define (##sys#check-structure x y . loc)
1441 (if (pair? loc)
1442 (##core#inline "C_i_check_structure_2" x y (car loc))
1443 (##core#inline "C_i_check_structure" x y) ) )
1444
1445;; DEPRECATED
1446(define (##sys#check-blob x . loc)
1447 (if (pair? loc)
1448 (##core#inline "C_i_check_bytevector_2" x (car loc))
1449 (##core#inline "C_i_check_bytevector" x) ) )
1450
1451(define ##sys#check-bytevector ##sys#check-blob)
1452
1453(define (##sys#check-pair x . loc)
1454 (if (pair? loc)
1455 (##core#inline "C_i_check_pair_2" x (car loc))
1456 (##core#inline "C_i_check_pair" x) ) )
1457
1458(define (##sys#check-list x . loc)
1459 (if (pair? loc)
1460 (##core#inline "C_i_check_list_2" x (car loc))
1461 (##core#inline "C_i_check_list" x) ) )
1462
1463(define (##sys#check-string x . loc)
1464 (if (pair? loc)
1465 (##core#inline "C_i_check_string_2" x (car loc))
1466 (##core#inline "C_i_check_string" x) ) )
1467
1468(define (##sys#check-number x . loc)
1469 (if (pair? loc)
1470 (##core#inline "C_i_check_number_2" x (car loc))
1471 (##core#inline "C_i_check_number" x) ) )
1472
1473(define (##sys#check-fixnum x . loc)
1474 (if (pair? loc)
1475 (##core#inline "C_i_check_fixnum_2" x (car loc))
1476 (##core#inline "C_i_check_fixnum" x) ) )
1477
1478(define (##sys#check-bytevector x . loc)
1479 (if (pair? loc)
1480 (##core#inline "C_i_check_bytevector_2" x (car loc))
1481 (##core#inline "C_i_check_bytevector" x) ) )
1482
1483(define (##sys#check-exact x . loc) ;; DEPRECATED
1484 (if (pair? loc)
1485 (##core#inline "C_i_check_exact_2" x (car loc))
1486 (##core#inline "C_i_check_exact" x) ) )
1487
1488(define (##sys#check-inexact x . loc)
1489 (if (pair? loc)
1490 (##core#inline "C_i_check_inexact_2" x (car loc))
1491 (##core#inline "C_i_check_inexact" x) ) )
1492
1493(define (##sys#check-symbol x . loc)
1494 (if (pair? loc)
1495 (##core#inline "C_i_check_symbol_2" x (car loc))
1496 (##core#inline "C_i_check_symbol" x) ) )
1497
1498(define (##sys#check-keyword x . loc)
1499 (if (pair? loc)
1500 (##core#inline "C_i_check_keyword_2" x (car loc))
1501 (##core#inline "C_i_check_keyword" x) ) )
1502
1503(define (##sys#check-vector x . loc)
1504 (if (pair? loc)
1505 (##core#inline "C_i_check_vector_2" x (car loc))
1506 (##core#inline "C_i_check_vector" x) ) )
1507
1508(define (##sys#check-char x . loc)
1509 (if (pair? loc)
1510 (##core#inline "C_i_check_char_2" x (car loc))
1511 (##core#inline "C_i_check_char" x) ) )
1512
1513(define (##sys#check-boolean x . loc)
1514 (if (pair? loc)
1515 (##core#inline "C_i_check_boolean_2" x (car loc))
1516 (##core#inline "C_i_check_boolean" x) ) )
1517
1518(define (##sys#check-locative x . loc)
1519 (if (pair? loc)
1520 (##core#inline "C_i_check_locative_2" x (car loc))
1521 (##core#inline "C_i_check_locative" x) ) )
1522
1523(define (##sys#check-integer x . loc)
1524 (unless (##core#inline "C_i_integerp" x)
1525 (##sys#error-bad-integer x (and (pair? loc) (car loc))) ) )
1526
1527(define (##sys#check-exact-integer x . loc)
1528 (unless (##core#inline "C_i_exact_integerp" x)
1529 (##sys#error-bad-exact-integer x (and (pair? loc) (car loc))) ) )
1530
1531(define (##sys#check-exact-uinteger x . loc)
1532 (when (or (not (##core#inline "C_i_exact_integerp" x))
1533 (##core#inline "C_i_integer_negativep" x))
1534 (##sys#error-bad-exact-uinteger x (and (pair? loc) (car loc))) ) )
1535
1536(define (##sys#check-real x . loc)
1537 (unless (##core#inline "C_i_realp" x)
1538 (##sys#error-bad-real x (and (pair? loc) (car loc))) ) )
1539
1540(define (##sys#check-range i from to . loc)
1541 (if (pair? loc)
1542 (##core#inline "C_i_check_range_2" i from to (car loc))
1543 (##core#inline "C_i_check_range" i from to) ) )
1544
1545(define (##sys#check-range/including i from to . loc)
1546 (if (pair? loc)
1547 (##core#inline "C_i_check_range_including_2" i from to (car loc))
1548 (##core#inline "C_i_check_range_including" i from to) ) )
1549
1550(define (##sys#check-special ptr . loc)
1551 (unless (and (##core#inline "C_blockp" ptr) (##core#inline "C_specialp" ptr))
1552 (##sys#signal-hook #:type-error (and (pair? loc) (car loc)) "bad argument type - not a pointer-like object" ptr) ) )
1553
1554(define (##sys#check-closure x . loc)
1555 (if (pair? loc)
1556 (##core#inline "C_i_check_closure_2" x (car loc))
1557 (##core#inline "C_i_check_closure" x) ) )
1558
1559(set! scheme#force
1560 (lambda (obj)
1561 (if (##sys#structure? obj 'promise)
1562 (let lp ((promise obj)
1563 (forward #f))
1564 (let ((val (##sys#slot promise 1)))
1565 (cond ((null? val) (##sys#values))
1566 ((pair? val) (apply ##sys#values val))
1567 ((procedure? val)
1568 (when forward (##sys#setslot forward 1 promise))
1569 (let ((results (##sys#call-with-values val ##sys#list)))
1570 (cond ((not (procedure? (##sys#slot promise 1)))
1571 (lp promise forward)) ; in case of reentrance
1572 ((and (not (null? results)) (null? (cdr results))
1573 (##sys#structure? (##sys#slot results 0) 'promise))
1574 (let ((result0 (##sys#slot results 0)))
1575 (##sys#setslot promise 1 (##sys#slot result0 1))
1576 (lp promise result0)))
1577 (else
1578 (##sys#setslot promise 1 results)
1579 (apply ##sys#values results)))))
1580 ((##sys#structure? val 'promise)
1581 (lp val forward)))))
1582 obj)))
1583
1584
1585;;; Dynamic Load
1586
1587(define ##sys#dload (##core#primitive "C_dload"))
1588(define ##sys#set-dlopen-flags! (##core#primitive "C_set_dlopen_flags"))
1589
1590(define (##sys#error-not-a-proper-list arg #!optional loc)
1591 (##sys#error-hook
1592 (foreign-value "C_NOT_A_PROPER_LIST_ERROR" int) loc arg))
1593
1594(define (##sys#error-bad-number arg #!optional loc)
1595 (##sys#error-hook
1596 (foreign-value "C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR" int) loc arg))
1597
1598(define (##sys#error-bad-integer arg #!optional loc)
1599 (##sys#error-hook
1600 (foreign-value "C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR" int) loc arg))
1601
1602(define (##sys#error-bad-exact-integer arg #!optional loc)
1603 (##sys#error-hook
1604 (foreign-value "C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR" int) loc arg))
1605
1606(define (##sys#error-bad-exact-uinteger arg #!optional loc)
1607 (##sys#error-hook
1608 (foreign-value "C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR" int) loc arg))
1609
1610(define (##sys#error-bad-inexact arg #!optional loc)
1611 (##sys#error-hook
1612 (foreign-value "C_CANT_REPRESENT_INEXACT_ERROR" int) loc arg))
1613
1614(define (##sys#error-bad-real arg #!optional loc)
1615 (##sys#error-hook
1616 (foreign-value "C_BAD_ARGUMENT_TYPE_NO_REAL_ERROR" int) loc arg))
1617
1618(define (##sys#error-bad-base arg #!optional loc)
1619 (##sys#error-hook
1620 (foreign-value "C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR" int) loc arg))
1621
1622(set! scheme#append
1623 (lambda lsts
1624 (if (eq? lsts '())
1625 lsts
1626 (let loop ((lsts lsts))
1627 (if (eq? (##sys#slot lsts 1) '())
1628 (##sys#slot lsts 0)
1629 (let copy ((node (##sys#slot lsts 0)))
1630 (cond ((eq? node '()) (loop (##sys#slot lsts 1)))
1631 ((pair? node)
1632 (cons (##sys#slot node 0) (copy (##sys#slot node 1))) )
1633 (else
1634 (##sys#error-not-a-proper-list
1635 (##sys#slot lsts 0) 'append)) ) )))) ) )
1636
1637(define (##sys#fast-reverse lst0)
1638 (let loop ((lst lst0) (rest '()))
1639 (if (pair? lst)
1640 (loop (##sys#slot lst 1) (cons (##sys#slot lst 0) rest))
1641 rest)))
1642
1643
1644;;; Strings:
1645
1646(define (##sys#make-bytevector size #!optional (fill 0))
1647 (##sys#allocate-bytevector size fill))
1648
1649(define (##sys#make-string size #!optional (fill #\space))
1650 (let* ((count (##core#inline "C_utf_bytes" fill))
1651 (n (fx* count size))
1652 (bv (##sys#allocate-bytevector (fx+ n 1) 0)))
1653 (##core#inline "C_utf_fill" bv fill)
1654 (##core#inline_allocate ("C_a_ustring" 5) bv size)))
1655
1656(define (##sys#buffer->string buf start len)
1657 (let ((bv (##sys#make-bytevector (fx+ len 1))))
1658 (##core#inline "C_copy_memory_with_offset" bv buf 0 start len)
1659 (##core#inline_allocate ("C_a_ustring" 5) bv
1660 (##core#inline "C_utf_range_length" bv 0 len))))
1661
1662(define (##sys#utf-decoder buf start len k)
1663 (k buf start len))
1664
1665(define (##sys#utf-encoder buf start len k)
1666 (k buf start len))
1667
1668(define (##sys#utf-scanner state byte)
1669 (if state
1670 (if (fx> state 1)
1671 (fx- state 1)
1672 #f)
1673 (let ((n (##core#inline "C_utf_bytes_needed" byte)))
1674 (if (eq? n 1)
1675 #f
1676 (fx- n 1)))))
1677
1678(define (##sys#latin-decoder bv start len k)
1679 (let* ((buf (##sys#make-bytevector (fx* len 2)))
1680 (n (##core#inline "C_latin_to_utf" bv buf start len)))
1681 (k buf 0 n)))
1682
1683(define (##sys#latin-encoder bv start len k)
1684 (let* ((buf (##sys#make-bytevector (fx+ len 1)))
1685 (n (##core#inline "C_utf_to_latin" bv buf start len)))
1686 (k buf 0 n)))
1687
1688(define (##sys#latin-scanner state byte) #f)
1689
1690(define (##sys#binary-decoder bv start len k)
1691 (k bv start len) )
1692
1693(define (##sys#binary-encoder bv start len k)
1694 (k bv start len) )
1695
1696(define (##sys#binary-scanner state byte) #f)
1697
1698;; invokes k with encoding and decoding procedures
1699(define (##sys#encoding-hook enc k)
1700 (case enc
1701 ((binary) (k ##sys#binary-decoder ##sys#binary-encoder ##sys#binary-scanner))
1702 ((utf-8) (k ##sys#utf-decoder ##sys#utf-encoder ##sys#utf-scanner))
1703 ((latin-1) (k ##sys#latin-decoder ##sys#latin-encoder ##sys#latin-scanner))
1704 (else (##sys#signal-hook #:type-error #f "invalid file port encoding" enc))))
1705
1706(define (##sys#register-encoding names dec enc scan)
1707 (let ((old ##sys#encoding-hook))
1708 (set! ##sys#encoding-hook
1709 (lambda (enc k)
1710 (if (or (eq? enc names)
1711 (and (pair? names) (memq enc names)))
1712 (k dec enc scan)
1713 (old enc k))))))
1714
1715;; decode buffer and create string
1716(define (##sys#buffer->string/encoding buf start len enc)
1717 (##sys#encoding-hook
1718 enc
1719 (lambda (decoder _ _) (decoder buf start len ##sys#buffer->string))))
1720
1721;; encode buffer into bytevector
1722(define (##sys#encode-buffer bv start len enc k)
1723 (##sys#encoding-hook
1724 enc
1725 (lambda (_ encoder _) (encoder bv start len k))))
1726
1727;; decode buffer into bytevector
1728(define (##sys#decode-buffer bv start len enc k)
1729 (##sys#encoding-hook
1730 enc
1731 (lambda (decoder _ _) (decoder bv start len k))))
1732
1733;; encode a single character into bytevector, return number of bytes
1734(define (##sys#encode-char c bv enc)
1735 (##sys#encoding-hook
1736 enc
1737 (lambda (_ encoder _)
1738 (let* ((bv1 (##sys#make-bytevector 4))
1739 (n (##core#inline "C_utf_insert" bv1 0 c)))
1740 (encoder bv1 0 n
1741 (lambda (buf start len)
1742 (##core#inline "C_copy_memory_with_offset" bv buf 0 start len)
1743 len))))))
1744
1745(define (##sys#decode-char bv enc start)
1746 (##sys#decode-buffer
1747 bv start (##sys#size bv) enc
1748 (lambda (buf start _)
1749 (##core#inline "C_utf_decode" buf start))))
1750
1751;; read char from port with encoding, scanning minimal number of bytes ahead
1752(define (##sys#read-char/encoding p enc k)
1753 (##sys#encoding-hook
1754 enc
1755 (lambda (dec _ scan)
1756 (let ((buf (##sys#make-bytevector 4))
1757 (rbv! (##sys#slot (##sys#slot p 2) 7))) ; read-bytevector!
1758 (let loop ((state #f) (i 0))
1759 (let ((rn (rbv! p 1 buf i)))
1760 (if (eq? 0 rn)
1761 (if (eq? i 0)
1762 #!eof
1763 (##sys#signal-hook #:file-error 'read-char "incomplete character sequence while decoding" buf i))
1764 (let ((s2 (scan state (##core#inline "C_subbyte" buf i))))
1765 (if s2
1766 (loop s2 (fx+ i 1))
1767 (k buf 0 (fx+ i 1) dec))))))))))
1768
1769(set! scheme#make-string
1770 (lambda (size . fill)
1771 (##sys#check-fixnum size 'make-string)
1772 (when (fx< size 0)
1773 (##sys#signal-hook #:bounds-error 'make-string "size is negative" size))
1774 (##sys#make-string
1775 size
1776 (if (null? fill)
1777 #\space
1778 (let ((c (car fill)))
1779 (##sys#check-char c 'make-string)
1780 c ) ) ) ) )
1781
1782(set! scheme#string->list
1783 (lambda (s #!optional start end)
1784 (##sys#check-string s 'string->list)
1785 (let ((len (##sys#slot s 1)))
1786 (if start
1787 (##sys#check-range/including start 0 len 'string->list)
1788 (set! start 0))
1789 (if end
1790 (##sys#check-range/including end 0 len 'string->list)
1791 (set! end len))
1792 (let loop ((i (fx- end 1)) (ls '()))
1793 (if (fx< i start)
1794 ls
1795 (loop (fx- i 1)
1796 (cons (string-ref s i) ls)) ) ) )))
1797
1798(define ##sys#string->list string->list)
1799
1800(set! scheme#list->string
1801 (lambda (lst0)
1802 (if (not (list? lst0))
1803 (##sys#error-not-a-proper-list lst0 'list->string)
1804 (let* ((len (##core#inline "C_utf_list_size" lst0))
1805 (bv (##sys#make-bytevector (fx+ 1 len))))
1806 (let loop ((i 0)
1807 (p 0)
1808 (lst lst0))
1809 (if (not (pair? lst))
1810 (##core#inline_allocate ("C_a_ustring" 5) bv i)
1811 (let ((c (##sys#slot lst 0)))
1812 (##sys#check-char c 'list->string)
1813 (##core#inline "C_utf_insert" bv p c)
1814 (loop (fx+ i 1)
1815 (fx+ p (##core#inline "C_utf_bytes" c))
1816 (##sys#slot lst 1)))))))))
1817
1818(define ##sys#list->string list->string)
1819
1820(define (##sys#reverse-list->string l)
1821 (let* ((sz (##core#inline "C_utf_list_size" l))
1822 (bv (##sys#make-bytevector (fx+ sz 1))))
1823 (let loop ((p sz) (l l) (n 0))
1824 (cond ((null? l)
1825 (##core#inline_allocate ("C_a_ustring" 5) bv n))
1826 ((pair? l)
1827 (let ((c (##sys#slot l 0)))
1828 (##sys#check-char c 'reverse-list->string)
1829 (let* ((bs (##core#inline "C_utf_bytes" c))
1830 (p2 (fx- p bs)))
1831 (##core#inline "C_utf_insert" bv p2 c)
1832 (loop p2 (##sys#slot l 1) (fx+ n 1)))))
1833 (else (##sys#error-not-a-proper-list l 'reverse-list->string) ) ))))
1834
1835(set! scheme#string-fill!
1836 (lambda (s c #!optional start end)
1837 (##sys#check-string s 'string-fill!)
1838 (##sys#check-char c 'string-fill!)
1839 (let ((len (string-length s)))
1840 (cond (start (##sys#check-range start 0 len 'string-fill!)
1841 (if end
1842 (##sys#check-range end 0 len 'string-fill!)
1843 (set! end len)))
1844 (else
1845 (set! start 0)
1846 (set! end len))))
1847 (let* ((bv (##sys#slot s 0))
1848 (bvlen (##sys#size bv))
1849 (count (fxmax 0 (fx- end start)))
1850 (code (char->integer c)))
1851 (if (and (eq? (fx- bvlen 1) (##sys#slot s 1))
1852 (fx< code 128))
1853 (##core#inline "C_fill_bytevector" bv code start count)
1854 (do ((i start (fx+ i 1)))
1855 ((fx>= i end))
1856 (string-set! s i c))))))
1857
1858(set! scheme#string-copy
1859 (lambda (s #!optional start end)
1860 (##sys#check-string s 'string-copy)
1861 (let ((len (string-length s))
1862 (start1 0))
1863 (when start
1864 (##sys#check-range/including start 0 len 'string-copy)
1865 (set! start1 start))
1866 (if end
1867 (##sys#check-range/including end 0 len 'string-copy)
1868 (set! end len))
1869 (let* ((bv (if start
1870 (##sys#substring s start1 end)
1871 (##sys#slot s 0)))
1872 (len (##sys#size bv))
1873 (n (fx- end start1))
1874 (bv2 (##sys#make-bytevector len)) )
1875 (##core#inline "C_copy_memory" bv2 bv len)
1876 (##core#inline_allocate ("C_a_ustring" 5) bv2 n)))))
1877
1878(set! scheme#string-copy!
1879 (lambda (to at from #!optional start end)
1880 (##sys#check-string to 'string-copy!)
1881 (##sys#check-string from 'string-copy!)
1882 (let ((tlen (string-length to))
1883 (flen (string-length from))
1884 (d (fx- end start)))
1885 (##sys#check-range at 0 tlen 'string-copy!)
1886 (if start
1887 (begin
1888 (##sys#check-range/including start 0 flen 'string-copy!)
1889 (if end
1890 (##sys#check-range/including end 0 flen 'string-copy!)
1891 (set! end flen)))
1892 (set! start 0))
1893 (if (and (eq? to from) (fx< start at))
1894 (do ((at (fx- (fx+ at d) 1) (fx- at 1))
1895 (i (fx- end 1) (fx- i 1)))
1896 ((fx< i start))
1897 (string-set! to at (string-ref from i)))
1898 (do ((at at (fx+ at 1))
1899 (i start (fx+ i 1)))
1900 ((fx>= i end))
1901 (string-set! to at (string-ref from i)))))))
1902
1903(define (##sys#substring s start end)
1904 (let* ((n (##core#inline "C_utf_range" s start end))
1905 (bv (##sys#make-bytevector (fx+ n 1)))
1906 (str (##core#inline_allocate ("C_a_ustring" 5) bv (fx- end start))))
1907 (##core#inline "C_utf_copy" s str start end 0)
1908 str ) )
1909
1910(set! scheme#substring
1911 (lambda (s start . end)
1912 (##sys#check-string s 'substring)
1913 (##sys#check-fixnum start 'substring)
1914 (let ((end (if (pair? end)
1915 (let ((end (car end)))
1916 (##sys#check-fixnum end 'substring)
1917 end)
1918 (string-length s) ) ) )
1919 (let ((len (string-length s)))
1920 (if (and (fx<= start end)
1921 (fx>= start 0)
1922 (fx<= end len) )
1923 (##sys#substring s start end)
1924 (##sys#error-hook
1925 (foreign-value "C_OUT_OF_BOUNDS_ERROR" int)
1926 'substring s start) ) ) )))
1927
1928(let ((compare
1929 (lambda (s1 s2 more loc cmp)
1930 (##sys#check-string s1 loc)
1931 (##sys#check-string s2 loc)
1932 (let* ((len1 (string-length s1))
1933 (len2 (string-length s2))
1934 (c (##core#inline "C_utf_compare"
1935 s1 s2 0 0
1936 (if (fx< len1 len2) len1 len2))))
1937 (let loop ((s s2) (len len2) (ss more)
1938 (f (cmp (##core#inline "C_utf_compare"
1939 s1 s2 0 0
1940 (if (fx< len1 len2) len1 len2))
1941 len1 len2)))
1942 (if (null? ss)
1943 f
1944 (let* ((s2 (##sys#slot more 0))
1945 (len2 (string-length s2))
1946 (c (##core#inline "C_utf_compare_ci"
1947 s s2 0 0
1948 (if (fx< len len2) len len2))))
1949 (loop s2 len2 (##sys#slot more 1)
1950 (and f (cmp c len len2))))))))))
1951 (set! scheme#string<? (lambda (s1 s2 . more)
1952 (compare
1953 s1 s2 more 'string<?
1954 (lambda (cmp len1 len2)
1955 (or (fx< cmp 0)
1956 (and (fx< len1 len2)
1957 (eq? cmp 0) ) ) ) ) ) )
1958 (set! scheme#string>? (lambda (s1 s2 . more)
1959 (compare
1960 s1 s2 more 'string>?
1961 (lambda (cmp len1 len2)
1962 (or (fx> cmp 0)
1963 (and (fx< len2 len1)
1964 (eq? cmp 0) ) ) ) ) ) )
1965 (set! scheme#string<=? (lambda (s1 s2 . more)
1966 (compare
1967 s1 s2 more 'string<=?
1968 (lambda (cmp len1 len2)
1969 (if (eq? cmp 0)
1970 (fx<= len1 len2)
1971 (fx< cmp 0) ) ) ) ) )
1972 (set! scheme#string>=? (lambda (s1 s2 . more)
1973 (compare
1974 s1 s2 more 'string>=?
1975 (lambda (cmp len1 len2)
1976 (if (eq? cmp 0)
1977 (fx>= len1 len2)
1978 (fx> cmp 0) ) ) ) ) ) )
1979
1980(let ((compare
1981 (lambda (s1 s2 more loc cmp)
1982 (##sys#check-string s1 loc)
1983 (##sys#check-string s2 loc)
1984 (let* ((len1 (string-length s1))
1985 (len2 (string-length s2))
1986 (c (##core#inline "C_utf_compare_ci"
1987 s1 s2 0 0
1988 (if (fx< len1 len2) len1 len2))))
1989 (let loop ((s s2) (len len2) (ss more)
1990 (f (cmp c len1 len2)))
1991 (if (null? ss)
1992 f
1993 (let* ((s2 (##sys#slot ss 0))
1994 (len2 (string-length s2))
1995 (c (##core#inline "C_utf_compare_ci"
1996 s s2 0 0
1997 (if (fx< len len2) len len2))))
1998 (loop s2 len2 (##sys#slot ss 1)
1999 (and f (cmp c len len2))))))))))
2000 (set! scheme#string-ci<? (lambda (s1 s2 . more)
2001 (compare
2002 s1 s2 more 'string-ci<?
2003 (lambda (cmp len1 len2)
2004 (or (fx< cmp 0)
2005 (and (fx< len1 len2)
2006 (eq? cmp 0) ) )))))
2007 (set! scheme#string-ci>? (lambda (s1 s2 . more)
2008 (compare
2009 s1 s2 more 'string-ci>?
2010 (lambda (cmp len1 len2)
2011 (or (fx> cmp 0)
2012 (and (fx< len2 len1)
2013 (eq? cmp 0) ) ) ) ) ) )
2014 (set! scheme#string-ci<=? (lambda (s1 s2 . more)
2015 (compare
2016 s1 s2 more 'string-ci<=?
2017 (lambda (cmp len1 len2)
2018 (if (eq? cmp 0)
2019 (fx<= len1 len2)
2020 (fx< cmp 0) ) ) ) ) )
2021 (set! scheme#string-ci>=? (lambda (s1 s2 . more)
2022 (compare
2023 s1 s2 more 'string-ci>=?
2024 (lambda (cmp len1 len2)
2025 (if (eq? cmp 0)
2026 (fx>= len1 len2)
2027 (fx> cmp 0) ) ) ) ) ) )
2028
2029(define (##sys#string-append x y)
2030 (let* ((bv1 (##sys#slot x 0))
2031 (bv2 (##sys#slot y 0))
2032 (s1 (fx- (##sys#size bv1) 1))
2033 (s2 (fx- (##sys#size bv2) 1))
2034 (z (##sys#make-bytevector (fx+ s1 (fx+ s2 1)) 0)))
2035 (##core#inline "C_copy_memory_with_offset" z bv1 0 0 s1)
2036 (##core#inline "C_copy_memory_with_offset" z bv2 s1 0 s2)
2037 (##core#inline_allocate ("C_a_ustring" 5) z
2038 (fx+ (##sys#slot x 1) (##sys#slot y 1)))))
2039
2040(set! scheme#string-append
2041 (lambda all
2042 (let ((snew #f)
2043 (slen 0))
2044 (let loop ((strs all) (n 0) (ul 0))
2045 (cond ((eq? strs '())
2046 (set! snew (##sys#make-bytevector (fx+ n 1) 0))
2047 (set! slen ul))
2048 (else
2049 (let ((s (##sys#slot strs 0)))
2050 (##sys#check-string s 'string-append)
2051 (let* ((bv (##sys#slot s 0))
2052 (len (fx- (##sys#size bv) 1))
2053 (ulen (##sys#slot s 1)))
2054 (loop (##sys#slot strs 1) (fx+ n len) (fx+ ul ulen))
2055 (##core#inline "C_copy_memory_with_offset" snew bv n 0 len) ) ) ) ) )
2056 (##core#inline_allocate ("C_a_ustring" 5) snew slen))))
2057
2058(set! scheme#string
2059 (let ([list->string list->string])
2060 (lambda chars (list->string chars)) ) )
2061
2062;; legacy procedure, used in some eggs, should be removed one day...
2063(define (##sys#char->utf8-string c)
2064 (scheme#string c))
2065
2066(set! chicken.base#chop
2067 (lambda (lst n)
2068 (##sys#check-fixnum n 'chop)
2069 (when (fx<= n 0) (##sys#error 'chop "invalid numeric argument" n))
2070 (let ((len (length lst)))
2071 (let loop ((lst lst) (i len))
2072 (cond ((null? lst) '())
2073 ((fx< i n) (list lst))
2074 (else
2075 (do ((hd '() (cons (##sys#slot tl 0) hd))
2076 (tl lst (##sys#slot tl 1))
2077 (c n (fx- c 1)) )
2078 ((fx= c 0)
2079 (cons (reverse hd) (loop tl (fx- i n))) ) ) ) ) ) ) ) )
2080
2081;;; Numeric routines:
2082;; Abbreviations of paper and book titles used in comments are:
2083;; [Knuth] Donald E. Knuth, "The Art of Computer Programming", Volume 2
2084;; [MpNT] Tiplea at al., "MpNT: A Multi-Precision Number Theory Package"
2085;; [MCA] Richard P. Brent & Paul Zimmermann, "Modern Computer Arithmetic"
2086
2087(module chicken.flonum *
2088(import scheme)
2089(import chicken.foreign)
2090(import (only chicken.base flonum?))
2091(import chicken.internal.syntax)
2092
2093(define maximum-flonum (foreign-value "DBL_MAX" double))
2094(define minimum-flonum (foreign-value "DBL_MIN" double))
2095(define flonum-radix (foreign-value "FLT_RADIX" int))
2096(define flonum-epsilon (foreign-value "DBL_EPSILON" double))
2097(define flonum-precision (foreign-value "DBL_MANT_DIG" int))
2098(define flonum-decimal-precision (foreign-value "DBL_DIG" int))
2099(define flonum-maximum-exponent (foreign-value "DBL_MAX_EXP" int))
2100(define flonum-minimum-exponent (foreign-value "DBL_MIN_EXP" int))
2101(define flonum-maximum-decimal-exponent (foreign-value "DBL_MAX_10_EXP" int))
2102(define flonum-minimum-decimal-exponent (foreign-value "DBL_MIN_10_EXP" int))
2103
2104(define-inline (fp-check-flonum x loc)
2105 (unless (flonum? x)
2106 (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int) loc x) ) )
2107
2108(define-inline (fp-check-flonums x y loc)
2109 (unless (and (flonum? x) (flonum? y))
2110 (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int) loc x y) ) )
2111
2112(define (fp+ x y)
2113 (fp-check-flonums x y 'fp+)
2114 (##core#inline_allocate ("C_a_i_flonum_plus" 4) x y) )
2115
2116(define (fp- x y)
2117 (fp-check-flonums x y 'fp-)
2118 (##core#inline_allocate ("C_a_i_flonum_difference" 4) x y) )
2119
2120(define (fp* x y)
2121 (fp-check-flonums x y 'fp*)
2122 (##core#inline_allocate ("C_a_i_flonum_times" 4) x y) )
2123
2124(define (fp/ x y)
2125 (fp-check-flonums x y 'fp/)
2126 (##core#inline_allocate ("C_a_i_flonum_quotient" 4) x y) )
2127
2128(define (fp*+ x y z)
2129 (unless (and (flonum? x) (flonum? y) (flonum? z))
2130 (##sys#error-hook (foreign-value "C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR" int)
2131 'fp*+ x y z) )
2132 (##core#inline_allocate ("C_a_i_flonum_multiply_add" 4) x y z) )
2133
2134(define (fpgcd x y)
2135 (fp-check-flonums x y 'fpgcd)
2136 (##core#inline_allocate ("C_a_i_flonum_gcd" 4) x y))
2137
2138(define (fp/? x y) ; undocumented
2139 (fp-check-flonums x y 'fp/?)
2140 (##core#inline_allocate ("C_a_i_flonum_quotient_checked" 4) x y) )
2141
2142(define (fp= x y)
2143 (fp-check-flonums x y 'fp=)
2144 (##core#inline "C_flonum_equalp" x y) )
2145
2146(define (fp> x y)
2147 (fp-check-flonums x y 'fp>)
2148 (##core#inline "C_flonum_greaterp" x y) )
2149
2150(define (fp< x y)
2151 (fp-check-flonums x y 'fp<)
2152 (##core#inline "C_flonum_lessp" x y) )
2153
2154(define (fp>= x y)
2155 (fp-check-flonums x y 'fp>=)
2156 (##core#inline "C_flonum_greater_or_equal_p" x y) )
2157
2158(define (fp<= x y)
2159 (fp-check-flonums x y 'fp<=)
2160 (##core#inline "C_flonum_less_or_equal_p" x y) )
2161
2162(define (fpneg x)
2163 (fp-check-flonum x 'fpneg)
2164 (##core#inline_allocate ("C_a_i_flonum_negate" 4) x) )
2165
2166(define (fpmax x y)
2167 (fp-check-flonums x y 'fpmax)
2168 (##core#inline "C_i_flonum_max" x y) )
2169
2170(define (fpmin x y)
2171 (fp-check-flonums x y 'fpmin)
2172 (##core#inline "C_i_flonum_min" x y) )
2173
2174(define (fpfloor x)
2175 (fp-check-flonum x 'fpfloor)
2176 (##core#inline_allocate ("C_a_i_flonum_floor" 4) x))
2177
2178(define (fptruncate x)
2179 (fp-check-flonum x 'fptruncate)
2180 (##core#inline_allocate ("C_a_i_flonum_truncate" 4) x))
2181
2182(define (fpround x)
2183 (fp-check-flonum x 'fpround)
2184 (##core#inline_allocate ("C_a_i_flonum_round" 4) x))
2185
2186(define (fpceiling x)
2187 (fp-check-flonum x 'fpceiling)
2188 (##core#inline_allocate ("C_a_i_flonum_ceiling" 4) x))
2189
2190(define (fpsin x)
2191 (fp-check-flonum x 'fpsin)
2192 (##core#inline_allocate ("C_a_i_flonum_sin" 4) x))
2193
2194(define (fpcos x)
2195 (fp-check-flonum x 'fpcos)
2196 (##core#inline_allocate ("C_a_i_flonum_cos" 4) x))
2197
2198(define (fptan x)
2199 (fp-check-flonum x 'fptan)
2200 (##core#inline_allocate ("C_a_i_flonum_tan" 4) x))
2201
2202(define (fpasin x)
2203 (fp-check-flonum x 'fpasin)
2204 (##core#inline_allocate ("C_a_i_flonum_asin" 4) x))
2205
2206(define (fpacos x)
2207 (fp-check-flonum x 'fpacos)
2208 (##core#inline_allocate ("C_a_i_flonum_acos" 4) x))
2209
2210(define (fpatan x)
2211 (fp-check-flonum x 'fpatan)
2212 (##core#inline_allocate ("C_a_i_flonum_atan" 4) x))
2213
2214(define (fpatan2 x y)
2215 (fp-check-flonums x y 'fpatan2)
2216 (##core#inline_allocate ("C_a_i_flonum_atan2" 4) x y))
2217
2218(define (fpsinh x)
2219 (fp-check-flonum x 'fpsinh)
2220 (##core#inline_allocate ("C_a_i_flonum_sinh" 4) x))
2221
2222(define (fpcosh x)
2223 (fp-check-flonum x 'fpcosh)
2224 (##core#inline_allocate ("C_a_i_flonum_cosh" 4) x))
2225
2226(define (fptanh x)
2227 (fp-check-flonum x 'fptanh)
2228 (##core#inline_allocate ("C_a_i_flonum_tanh" 4) x))
2229
2230(define (fpasinh x)
2231 (fp-check-flonum x 'fpasinh)
2232 (##core#inline_allocate ("C_a_i_flonum_asinh" 4) x))
2233
2234(define (fpacosh x)
2235 (fp-check-flonum x 'fpacosh)
2236 (##core#inline_allocate ("C_a_i_flonum_acosh" 4) x))
2237
2238(define (fpatanh x)
2239 (fp-check-flonum x 'fpatanh)
2240 (##core#inline_allocate ("C_a_i_flonum_atanh" 4) x))
2241
2242(define (fpexp x)
2243 (fp-check-flonum x 'fpexp)
2244 (##core#inline_allocate ("C_a_i_flonum_exp" 4) x))
2245
2246(define (fpexpt x y)
2247 (fp-check-flonums x y 'fpexpt)
2248 (##core#inline_allocate ("C_a_i_flonum_expt" 4) x y))
2249
2250(define (fplog x)
2251 (fp-check-flonum x 'fplog)
2252 (##core#inline_allocate ("C_a_i_flonum_log" 4) x))
2253
2254(define (fpsqrt x)
2255 (fp-check-flonum x 'fpsqrt)
2256 (##core#inline_allocate ("C_a_i_flonum_sqrt" 4) x))
2257
2258(define (fpabs x)
2259 (fp-check-flonum x 'fpabs)
2260 (##core#inline_allocate ("C_a_i_flonum_abs" 4) x))
2261
2262(define (fpinteger? x)
2263 (fp-check-flonum x 'fpinteger?)
2264 (##core#inline "C_u_i_fpintegerp" x))
2265
2266(define (flonum-print-precision #!optional prec)
2267 (let ((prev (##core#inline "C_get_print_precision")))
2268 (when prec
2269 (##sys#check-fixnum prec 'flonum-print-precision)
2270 (##core#inline "C_set_print_precision" prec))
2271 prev)))
2272
2273(import chicken.flonum)
2274
2275(define-inline (integer-negate x)
2276 (##core#inline_allocate ("C_s_a_u_i_integer_negate" 5) x))
2277
2278;;; Complex numbers
2279
2280(define-inline (%cplxnum-real c) (##core#inline "C_u_i_cplxnum_real" c))
2281(define-inline (%cplxnum-imag c) (##core#inline "C_u_i_cplxnum_imag" c))
2282
2283(define (make-complex r i)
2284 (if (or (eq? i 0) (and (##core#inline "C_i_flonump" i) (fp= i 0.0)))
2285 r
2286 (##core#inline_allocate ("C_a_i_cplxnum" 3)
2287 (if (inexact? i) (exact->inexact r) r)
2288 (if (inexact? r) (exact->inexact i) i)) ) )
2289
2290(set! scheme#make-rectangular
2291 (lambda (r i)
2292 (##sys#check-real r 'make-rectangular)
2293 (##sys#check-real i 'make-rectangular)
2294 (make-complex r i) ))
2295
2296(set! scheme#make-polar
2297 (lambda (r phi)
2298 (##sys#check-real r 'make-polar)
2299 (##sys#check-real phi 'make-polar)
2300 (let ((fphi (exact->inexact phi)))
2301 (make-complex
2302 (* r (##core#inline_allocate ("C_a_i_cos" 4) fphi))
2303 (* r (##core#inline_allocate ("C_a_i_sin" 4) fphi))) ) ))
2304
2305(set! scheme#real-part
2306 (lambda (x)
2307 (cond ((cplxnum? x) (%cplxnum-real x))
2308 ((number? x) x)
2309 (else (##sys#error-bad-number x 'real-part)) )))
2310
2311(set! scheme#imag-part
2312 (lambda (x)
2313 (cond ((cplxnum? x) (%cplxnum-imag x))
2314 ((##core#inline "C_i_flonump" x) 0.0)
2315 ((number? x) 0)
2316 (else (##sys#error-bad-number x 'imag-part)) )))
2317
2318(set! scheme#angle
2319 (lambda (n)
2320 (##sys#check-number n 'angle)
2321 (##core#inline_allocate ("C_a_i_atan2" 4)
2322 (exact->inexact (imag-part n))
2323 (exact->inexact (real-part n))) ))
2324
2325(set! scheme#magnitude
2326 (lambda (x)
2327 (cond ((cplxnum? x)
2328 (let ((r (%cplxnum-real x))
2329 (i (%cplxnum-imag x)) )
2330 (sqrt (+ (* r r) (* i i))) ))
2331 ((number? x) (abs x))
2332 (else (##sys#error-bad-number x 'magnitude))) ))
2333
2334;;; Rational numbers
2335
2336(define-inline (%ratnum-numerator r) (##core#inline "C_u_i_ratnum_num" r))
2337(define-inline (%ratnum-denominator r) (##core#inline "C_u_i_ratnum_denom" r))
2338(define-inline (%make-ratnum n d) (##core#inline_allocate ("C_a_i_ratnum" 3) n d))
2339
2340(define (ratnum m n)
2341 (cond
2342 ((eq? n 1) m)
2343 ((eq? n -1) (integer-negate m))
2344 ((negative? n)
2345 (%make-ratnum (integer-negate m) (integer-negate n)))
2346 (else (%make-ratnum m n))))
2347
2348(set! scheme#numerator
2349 (lambda (n)
2350 (cond ((exact-integer? n) n)
2351 ((##core#inline "C_i_flonump" n)
2352 (cond ((not (finite? n)) (##sys#error-bad-inexact n 'numerator))
2353 ((##core#inline "C_u_i_fpintegerp" n) n)
2354 (else (exact->inexact (numerator (inexact->exact n))))))
2355 ((ratnum? n) (%ratnum-numerator n))
2356 (else (##sys#signal-hook
2357 #:type-error 'numerator
2358 "bad argument type - not a rational number" n) ) )))
2359
2360(set! scheme#denominator
2361 (lambda (n)
2362 (cond ((exact-integer? n) 1)
2363 ((##core#inline "C_i_flonump" n)
2364 (cond ((not (finite? n)) (##sys#error-bad-inexact n 'denominator))
2365 ((##core#inline "C_u_i_fpintegerp" n) 1.0)
2366 (else (exact->inexact (denominator (inexact->exact n))))))
2367 ((ratnum? n) (%ratnum-denominator n))
2368 (else (##sys#signal-hook
2369 #:type-error 'numerator
2370 "bad argument type - not a rational number" n) ) )))
2371
2372(define (##sys#extended-signum x)
2373 (cond
2374 ((ratnum? x) (##core#inline "C_u_i_integer_signum" (%ratnum-numerator x)))
2375 ((cplxnum? x) (make-polar 1 (angle x)))
2376 (else (##sys#error-bad-number x 'signum))))
2377
2378(define-inline (%flo->int x)
2379 (##core#inline_allocate ("C_s_a_u_i_flo_to_int" 5) x))
2380
2381(define (flonum->ratnum x)
2382 ;; Try to multiply by two until we reach an integer
2383 (define (float-fraction-length x)
2384 (do ((x x (fp* x 2.0))
2385 (i 0 (fx+ i 1)))
2386 ((##core#inline "C_u_i_fpintegerp" x) i)))
2387
2388 (define (deliver y d)
2389 (let* ((q (##sys#integer-power 2 (float-fraction-length y)))
2390 (scaled-y (* y (exact->inexact q))))
2391 (if (finite? scaled-y) ; Shouldn't this always be true?
2392 (##sys#/-2 (##sys#/-2 (%flo->int scaled-y) q) d)
2393 (##sys#error-bad-inexact x 'inexact->exact))))
2394
2395 (if (and (fp< x 1.0) ; Watch out for denormalized numbers
2396 (fp> x -1.0)) ; XXX: Needs a test, it seems pointless
2397 (deliver (* x (expt 2.0 flonum-precision))
2398 ;; Can be bignum (is on 32-bit), so must wait until after init.
2399 ;; We shouldn't need to calculate this every single time, tho..
2400 (##sys#integer-power 2 flonum-precision))
2401 (deliver x 1)))
2402
2403(set! scheme#inexact->exact
2404 (lambda (x)
2405 (cond ((exact? x) x)
2406 ((##core#inline "C_i_flonump" x)
2407 (cond ((##core#inline "C_u_i_fpintegerp" x) (%flo->int x))
2408 ((##core#inline "C_u_i_flonum_finitep" x) (flonum->ratnum x))
2409 (else (##sys#error-bad-inexact x 'inexact->exact))))
2410 ((cplxnum? x)
2411 (make-complex (inexact->exact (%cplxnum-real x))
2412 (inexact->exact (%cplxnum-imag x))))
2413 (else (##sys#error-bad-number x 'inexact->exact)) )))
2414
2415
2416;;; Bitwise operations:
2417
2418;; From SRFI-33
2419
2420(module chicken.bitwise *
2421(import scheme)
2422(define bitwise-and (##core#primitive "C_bitwise_and"))
2423(define bitwise-ior (##core#primitive "C_bitwise_ior"))
2424(define bitwise-xor (##core#primitive "C_bitwise_xor"))
2425(define (bitwise-not n) (##core#inline_allocate ("C_s_a_i_bitwise_not" 5) n))
2426(define (bit->boolean n i) (##core#inline "C_i_bit_to_bool" n i)) ; DEPRECATED
2427;; XXX NOT YET! Reintroduce at a later time. See #1385:
2428;; (define (bit-set? i n) (##core#inline "C_i_bit_setp" i n))
2429(define (integer-length x) (##core#inline "C_i_integer_length" x))
2430(define (arithmetic-shift n m)
2431 (##core#inline_allocate ("C_s_a_i_arithmetic_shift" 5) n m))
2432
2433) ; chicken.bitwise
2434
2435(import chicken.bitwise)
2436
2437;;; Basic arithmetic:
2438
2439(define-inline (%integer-gcd a b)
2440 (##core#inline_allocate ("C_s_a_u_i_integer_gcd" 5) a b))
2441
2442(set! scheme#/
2443 (lambda (arg1 . args)
2444 (if (null? args)
2445 (##sys#/-2 1 arg1)
2446 (let loop ((args (##sys#slot args 1))
2447 (x (##sys#/-2 arg1 (##sys#slot args 0))))
2448 (if (null? args)
2449 x
2450 (loop (##sys#slot args 1)
2451 (##sys#/-2 x (##sys#slot args 0))) ) ) ) ))
2452
2453(define-inline (%integer-quotient a b)
2454 (##core#inline_allocate ("C_s_a_u_i_integer_quotient" 5) a b))
2455
2456(define (##sys#/-2 x y)
2457 (when (eq? y 0)
2458 (##sys#error-hook (foreign-value "C_DIVISION_BY_ZERO_ERROR" int) '/ x y))
2459 (cond ((and (exact-integer? x) (exact-integer? y))
2460 (let ((g (%integer-gcd x y)))
2461 (ratnum (%integer-quotient x g) (%integer-quotient y g))))
2462 ;; Compnum *must* be checked first
2463 ((or (cplxnum? x) (cplxnum? y))
2464 (let* ((a (real-part x)) (b (imag-part x))
2465 (c (real-part y)) (d (imag-part y))
2466 (r (+ (* c c) (* d d)))
2467 (x (##sys#/-2 (+ (* a c) (* b d)) r))
2468 (y (##sys#/-2 (- (* b c) (* a d)) r)) )
2469 (make-complex x y) ))
2470 ((or (##core#inline "C_i_flonump" x) (##core#inline "C_i_flonump" y))
2471 ;; This may be incorrect when one is a ratnum consisting of bignums
2472 (fp/ (exact->inexact x) (exact->inexact y)))
2473 ((ratnum? x)
2474 (if (ratnum? y)
2475 ;; a/b / c/d = a*d / b*c [generic]
2476 ;; = ((a / g1) * (d / g2) * sign(a)) / abs((b / g2) * (c / g1))
2477 ;; With g1 = gcd(a, c) and g2 = gcd(b, d) [Knuth, 4.5.1 ex. 4]
2478 (let* ((a (%ratnum-numerator x)) (b (%ratnum-denominator x))
2479 (c (%ratnum-numerator y)) (d (%ratnum-denominator y))
2480 (g1 (%integer-gcd a c))
2481 (g2 (%integer-gcd b d)))
2482 (ratnum (* (quotient a g1) (quotient d g2))
2483 (* (quotient b g2) (quotient c g1))))
2484 ;; a/b / c/d = a*d / b*c [with d = 1]
2485 ;; = ((a / g) * sign(a)) / abs(b * (c / g))
2486 ;; With g = gcd(a, c) and c = y [Knuth, 4.5.1 ex. 4]
2487 (let* ((a (%ratnum-numerator x))
2488 (g (##sys#internal-gcd '/ a y))
2489 (num (quotient a g))
2490 (denom (* (%ratnum-denominator x) (quotient y g))))
2491 (if (##core#inline "C_i_flonump" denom)
2492 (##sys#/-2 num denom)
2493 (ratnum num denom)))))
2494 ((ratnum? y)
2495 ;; a/b / c/d = a*d / b*c [with b = 1]
2496 ;; = ((a / g1) * d * sign(a)) / abs(c / g1)
2497 ;; With g1 = gcd(a, c) and a = x [Knuth, 4.5.1 ex. 4]
2498 (let* ((c (%ratnum-numerator y))
2499 (g (##sys#internal-gcd '/ x c))
2500 (num (* (quotient x g) (%ratnum-denominator y)))
2501 (denom (quotient c g)))
2502 (if (##core#inline "C_i_flonump" denom)
2503 (##sys#/-2 num denom)
2504 (ratnum num denom))))
2505 ((not (number? x)) (##sys#error-bad-number x '/))
2506 (else (##sys#error-bad-number y '/))) )
2507
2508(set! scheme#floor
2509 (lambda (x)
2510 (cond ((exact-integer? x) x)
2511 ((##core#inline "C_i_flonump" x) (fpfloor x))
2512 ;; (floor x) = greatest integer <= x
2513 ((ratnum? x) (let* ((n (%ratnum-numerator x))
2514 (q (quotient n (%ratnum-denominator x))))
2515 (if (>= n 0) q (- q 1))))
2516 (else (##sys#error-bad-real x 'floor)) )))
2517
2518(set! scheme#ceiling
2519 (lambda (x)
2520 (cond ((exact-integer? x) x)
2521 ((##core#inline "C_i_flonump" x) (fpceiling x))
2522 ;; (ceiling x) = smallest integer >= x
2523 ((ratnum? x) (let* ((n (%ratnum-numerator x))
2524 (q (quotient n (%ratnum-denominator x))))
2525 (if (>= n 0) (+ q 1) q)))
2526 (else (##sys#error-bad-real x 'ceiling)) )))
2527
2528(set! scheme#truncate
2529 (lambda (x)
2530 (cond ((exact-integer? x) x)
2531 ((##core#inline "C_i_flonump" x) (fptruncate x))
2532 ;; (rational-truncate x) = integer of largest magnitude <= (abs x)
2533 ((ratnum? x) (quotient (%ratnum-numerator x)
2534 (%ratnum-denominator x)))
2535 (else (##sys#error-bad-real x 'truncate)) )))
2536
2537(set! scheme#round
2538 (lambda (x)
2539 (cond ((exact-integer? x) x)
2540 ((##core#inline "C_i_flonump" x)
2541 (##core#inline_allocate ("C_a_i_flonum_round_proper" 4) x))
2542 ((ratnum? x)
2543 (let* ((x+1/2 (+ x (%make-ratnum 1 2)))
2544 (r (floor x+1/2)))
2545 (if (and (= r x+1/2) (odd? r)) (- r 1) r)))
2546 (else (##sys#error-bad-real x 'round)) )))
2547
2548(define (find-ratio-between x y)
2549 (define (sr x y)
2550 (let ((fx (inexact->exact (floor x)))
2551 (fy (inexact->exact (floor y))))
2552 (cond ((not (< fx x)) (list fx 1))
2553 ((= fx fy)
2554 (let ((rat (sr (##sys#/-2 1 (- y fy))
2555 (##sys#/-2 1 (- x fx)))))
2556 (list (+ (cadr rat) (* fx (car rat)))
2557 (car rat))))
2558 (else (list (+ 1 fx) 1)))))
2559 (cond ((< y x) (find-ratio-between y x))
2560 ((not (< x y)) (list x 1))
2561 ((positive? x) (sr x y))
2562 ((negative? y) (let ((rat (sr (- y) (- x))))
2563 (list (- (car rat)) (cadr rat))))
2564 (else '(0 1))))
2565
2566(define (find-ratio x e) (find-ratio-between (- x e) (+ x e)))
2567
2568(set! scheme#rationalize
2569 (lambda (x e)
2570 (let ((result (apply ##sys#/-2 (find-ratio x e))))
2571 (if (or (inexact? x) (inexact? e))
2572 (exact->inexact result)
2573 result)) ))
2574
2575(set! scheme#max
2576 (lambda (x1 . xs)
2577 (let loop ((i (##core#inline "C_i_flonump" x1)) (m x1) (xs xs))
2578 (##sys#check-number m 'max)
2579 (if (null? xs)
2580 (if i (exact->inexact m) m)
2581 (let ((h (##sys#slot xs 0)))
2582 (loop (or i (##core#inline "C_i_flonump" h))
2583 (if (> h m) h m)
2584 (##sys#slot xs 1)) ) ) ) ))
2585
2586(set! scheme#min
2587 (lambda (x1 . xs)
2588 (let loop ((i (##core#inline "C_i_flonump" x1)) (m x1) (xs xs))
2589 (##sys#check-number m 'min)
2590 (if (null? xs)
2591 (if i (exact->inexact m) m)
2592 (let ((h (##sys#slot xs 0)))
2593 (loop (or i (##core#inline "C_i_flonump" h))
2594 (if (< h m) h m)
2595 (##sys#slot xs 1)) ) ) ) ))
2596
2597(set! scheme#exp
2598 (lambda (n)
2599 (##sys#check-number n 'exp)
2600 (if (cplxnum? n)
2601 (* (##core#inline_allocate ("C_a_i_exp" 4)
2602 (exact->inexact (%cplxnum-real n)))
2603 (let ((p (%cplxnum-imag n)))
2604 (make-complex
2605 (##core#inline_allocate ("C_a_i_cos" 4) (exact->inexact p))
2606 (##core#inline_allocate ("C_a_i_sin" 4) (exact->inexact p)) ) ) )
2607 (##core#inline_allocate ("C_a_i_flonum_exp" 4) (exact->inexact n)) ) ))
2608
2609(define (##sys#log-1 x) ; log_e(x)
2610 (cond
2611 ((eq? x 0) ; Exact zero? That's undefined
2612 (##sys#signal-hook #:arithmetic-error 'log "log of exact 0 is undefined" x))
2613 ;; avoid calling inexact->exact on X here (to avoid overflow?)
2614 ((or (cplxnum? x) (negative? x)) ; General case
2615 (+ (##sys#log-1 (magnitude x))
2616 (* (make-complex 0 1) (angle x))))
2617 (else ; Real number case (< already ensured the argument type is a number)
2618 (##core#inline_allocate ("C_a_i_log" 4) (exact->inexact x)))))
2619
2620(set! scheme#log
2621 (lambda (a #!optional b)
2622 (if b (##sys#/-2 (##sys#log-1 a) (##sys#log-1 b)) (##sys#log-1 a))))
2623
2624(set! scheme#sin
2625 (lambda (n)
2626 (##sys#check-number n 'sin)
2627 (if (cplxnum? n)
2628 (let ((in (* +i n)))
2629 (##sys#/-2 (- (exp in) (exp (- in))) +2i))
2630 (##core#inline_allocate ("C_a_i_sin" 4) (exact->inexact n)) ) ))
2631
2632(set! scheme#cos
2633 (lambda (n)
2634 (##sys#check-number n 'cos)
2635 (if (cplxnum? n)
2636 (let ((in (* +i n)))
2637 (##sys#/-2 (+ (exp in) (exp (- in))) 2) )
2638 (##core#inline_allocate ("C_a_i_cos" 4) (exact->inexact n)) ) ))
2639
2640(set! scheme#tan
2641 (lambda (n)
2642 (##sys#check-number n 'tan)
2643 (if (cplxnum? n)
2644 (##sys#/-2 (sin n) (cos n))
2645 (##core#inline_allocate ("C_a_i_tan" 4) (exact->inexact n)) ) ))
2646
2647;; General case: sin^{-1}(z) = -i\ln(iz + \sqrt{1-z^2})
2648(set! scheme#asin
2649 (lambda (n)
2650 (##sys#check-number n 'asin)
2651 (cond ((and (##core#inline "C_i_flonump" n) (fp>= n -1.0) (fp<= n 1.0))
2652 (##core#inline_allocate ("C_a_i_asin" 4) n))
2653 ((and (##core#inline "C_fixnump" n) (fx>= n -1) (fx<= n 1))
2654 (##core#inline_allocate ("C_a_i_asin" 4)
2655 (##core#inline_allocate
2656 ("C_a_i_fix_to_flo" 4) n)))
2657 ;; General definition can return compnums
2658 (else (* -i (##sys#log-1
2659 (+ (* +i n)
2660 (##sys#sqrt/loc 'asin (- 1 (* n n))))) )) ) ))
2661
2662;; General case:
2663;; cos^{-1}(z) = 1/2\pi + i\ln(iz + \sqrt{1-z^2}) = 1/2\pi - sin^{-1}(z) = sin(1) - sin(z)
2664(set! scheme#acos
2665 (let ((asin1 (##core#inline_allocate ("C_a_i_asin" 4) 1)))
2666 (lambda (n)
2667 (##sys#check-number n 'acos)
2668 (cond ((and (##core#inline "C_i_flonump" n) (fp>= n -1.0) (fp<= n 1.0))
2669 (##core#inline_allocate ("C_a_i_acos" 4) n))
2670 ((and (##core#inline "C_fixnump" n) (fx>= n -1) (fx<= n 1))
2671 (##core#inline_allocate ("C_a_i_acos" 4)
2672 (##core#inline_allocate
2673 ("C_a_i_fix_to_flo" 4) n)))
2674 ;; General definition can return compnums
2675 (else (- asin1 (asin n)))))))
2676
2677(set! scheme#atan
2678 (lambda (n #!optional b)
2679 (##sys#check-number n 'atan)
2680 (cond ((cplxnum? n)
2681 (if b
2682 (##sys#error-bad-real n 'atan)
2683 (let ((in (* +i n)))
2684 (##sys#/-2 (- (##sys#log-1 (+ 1 in))
2685 (##sys#log-1 (- 1 in))) +2i))))
2686 (b
2687 (##core#inline_allocate
2688 ("C_a_i_atan2" 4) (exact->inexact n) (exact->inexact b)))
2689 (else
2690 (##core#inline_allocate
2691 ("C_a_i_atan" 4) (exact->inexact n))) ) ))
2692
2693;; This is "Karatsuba Square Root" as described by Paul Zimmermann,
2694;; which is 3/2K(n) + O(n log n) for an input of 2n words, where K(n)
2695;; is the number of operations performed by Karatsuba multiplication.
2696(define (##sys#exact-integer-sqrt a)
2697 ;; Because we assume a3b+a2 >= b^2/4, we must check a few edge cases:
2698 (if (and (fixnum? a) (fx<= a 4))
2699 (case a
2700 ((0 1) (values a 0))
2701 ((2) (values 1 1))
2702 ((3) (values 1 2))
2703 ((4) (values 2 0))
2704 (else (error "this should never happen")))
2705 (let*-values
2706 (((len/4) (fxshr (fx+ (integer-length a) 1) 2))
2707 ((len/2) (fxshl len/4 1))
2708 ((s^ r^) (##sys#exact-integer-sqrt
2709 (arithmetic-shift a (fxneg len/2))))
2710 ((mask) (- (arithmetic-shift 1 len/4) 1))
2711 ((a0) (bitwise-and a mask))
2712 ((a1) (bitwise-and (arithmetic-shift a (fxneg len/4)) mask))
2713 ((q u) ((##core#primitive "C_u_integer_quotient_and_remainder")
2714 (+ (arithmetic-shift r^ len/4) a1)
2715 (arithmetic-shift s^ 1)))
2716 ((s) (+ (arithmetic-shift s^ len/4) q))
2717 ((r) (+ (arithmetic-shift u len/4) (- a0 (* q q)))))
2718 (if (negative? r)
2719 (values (- s 1)
2720 (- (+ r (arithmetic-shift s 1)) 1))
2721 (values s r)))))
2722
2723(set! scheme#exact-integer-sqrt
2724 (lambda (x)
2725 (##sys#check-exact-uinteger x 'exact-integer-sqrt)
2726 (##sys#exact-integer-sqrt x)))
2727
2728;; This procedure is so large because it tries very hard to compute
2729;; exact results if at all possible.
2730(define (##sys#sqrt/loc loc n)
2731 (cond ((cplxnum? n) ; Must be checked before we call "negative?"
2732 (let ((p (##sys#/-2 (angle n) 2))
2733 (m (##core#inline_allocate ("C_a_i_sqrt" 4) (magnitude n))) )
2734 (make-complex (* m (cos p)) (* m (sin p)) ) ))
2735 ((negative? n)
2736 (make-complex .0 (##core#inline_allocate
2737 ("C_a_i_sqrt" 4) (exact->inexact (- n)))))
2738 ((exact-integer? n)
2739 (receive (s^2 r) (##sys#exact-integer-sqrt n)
2740 (if (eq? 0 r)
2741 s^2
2742 (##core#inline_allocate ("C_a_i_sqrt" 4) (exact->inexact n)))))
2743 ((ratnum? n) ; Try to compute exact sqrt (we already know n is positive)
2744 (receive (ns^2 nr) (##sys#exact-integer-sqrt (%ratnum-numerator n))
2745 (if (eq? nr 0)
2746 (receive (ds^2 dr)
2747 (##sys#exact-integer-sqrt (%ratnum-denominator n))
2748 (if (eq? dr 0)
2749 (##sys#/-2 ns^2 ds^2)
2750 (##sys#sqrt/loc loc (exact->inexact n))))
2751 (##sys#sqrt/loc loc (exact->inexact n)))))
2752 (else (##core#inline_allocate ("C_a_i_sqrt" 4) (exact->inexact n)))))
2753
2754(set! scheme#sqrt (lambda (x) (##sys#sqrt/loc 'sqrt x)))
2755
2756;; XXX These are bad bad bad definitions; very inefficient.
2757;; But to improve it we would need to provide another implementation
2758;; of the quotient procedure which floors instead of truncates.
2759(define scheme#truncate/ quotient&remainder)
2760
2761(define (scheme#floor/ x y)
2762 (receive (div rem) (quotient&remainder x y)
2763 (if (positive? y)
2764 (if (negative? rem)
2765 (values (- div 1) (+ rem y))
2766 (values div rem))
2767 (if (positive? rem)
2768 (values (- div 1) (+ rem y))
2769 (values div rem)))))
2770
2771(define (scheme#floor-remainder x y)
2772 (receive (div rem) (scheme#floor/ x y) rem))
2773
2774(define (scheme#floor-quotient x y)
2775 (receive (div rem) (scheme#floor/ x y) div))
2776
2777(define (scheme#square n) (* n n))
2778
2779(set! chicken.base#exact-integer-nth-root
2780 (lambda (k n)
2781 (##sys#check-exact-uinteger k 'exact-integer-nth-root)
2782 (##sys#check-exact-uinteger n 'exact-integer-nth-root)
2783 (##sys#exact-integer-nth-root/loc 'exact-integer-nth-root k n)))
2784
2785;; Generalized Newton's algorithm for positive integers, with a little help
2786;; from Wikipedia ;) https://en.wikipedia.org/wiki/Nth_root_algorithm
2787(define (##sys#exact-integer-nth-root/loc loc k n)
2788 (if (or (eq? 0 k) (eq? 1 k) (eq? 1 n)) ; Maybe call exact-integer-sqrt on n=2?
2789 (values k 0)
2790 (let ((len (integer-length k)))
2791 (if (< len n) ; Idea from Gambit: 2^{len-1} <= k < 2^{len}
2792 (values 1 (- k 1)) ; Since x >= 2, we know x^{n} can't exist
2793 ;; Set initial guess to (at least) 2^ceil(ceil(log2(k))/n)
2794 (let* ((shift-amount (inexact->exact (ceiling (/ (fx+ len 1) n))))
2795 (g0 (arithmetic-shift 1 shift-amount))
2796 (n-1 (- n 1)))
2797 (let lp ((g0 g0)
2798 (g1 (quotient
2799 (+ (* n-1 g0)
2800 (quotient k (##sys#integer-power g0 n-1)))
2801 n)))
2802 (if (< g1 g0)
2803 (lp g1 (quotient
2804 (+ (* n-1 g1)
2805 (quotient k (##sys#integer-power g1 n-1)))
2806 n))
2807 (values g0 (- k (##sys#integer-power g0 n))))))))))
2808
2809(define (##sys#integer-power base e)
2810 (define (square x) (* x x))
2811 (if (negative? e)
2812 (##sys#/-2 1 (##sys#integer-power base (integer-negate e)))
2813 (let lp ((res 1) (e2 e))
2814 (cond
2815 ((eq? e2 0) res)
2816 ((even? e2) ; recursion is faster than iteration here
2817 (* res (square (lp 1 (arithmetic-shift e2 -1)))))
2818 (else
2819 (lp (* res base) (- e2 1)))))))
2820
2821(set! scheme#expt
2822 (lambda (a b)
2823 (define (log-expt a b)
2824 (exp (* b (##sys#log-1 a))))
2825 (define (slow-expt a b)
2826 (if (eq? 0 a)
2827 (##sys#signal-hook
2828 #:arithmetic-error 'expt
2829 "exponent of exact 0 with complex argument is undefined" a b)
2830 (exp (* b (##sys#log-1 a)))))
2831 (cond ((not (number? a)) (##sys#error-bad-number a 'expt))
2832 ((not (number? b)) (##sys#error-bad-number b 'expt))
2833 ((and (ratnum? a) (not (inexact? b)))
2834 ;; (n*d)^b = n^b * d^b = n^b * x^{-b} | x = 1/b
2835 ;; Hopefully faster than integer-power
2836 (* (expt (%ratnum-numerator a) b)
2837 (expt (%ratnum-denominator a) (- b))))
2838 ((ratnum? b)
2839 ;; x^{a/b} = (x^{1/b})^a
2840 (cond
2841 ((exact-integer? a)
2842 (if (negative? a)
2843 (log-expt (exact->inexact a) (exact->inexact b))
2844 (receive (ds^n r)
2845 (##sys#exact-integer-nth-root/loc
2846 'expt a (%ratnum-denominator b))
2847 (if (eq? r 0)
2848 (##sys#integer-power ds^n (%ratnum-numerator b))
2849 (##core#inline_allocate ("C_a_i_flonum_expt" 4)
2850 (exact->inexact a)
2851 (exact->inexact b))))))
2852 ((##core#inline "C_i_flonump" a)
2853 (log-expt a (exact->inexact b)))
2854 (else (slow-expt a b))))
2855 ((or (cplxnum? b) (and (cplxnum? a) (not (integer? b))))
2856 (slow-expt a b))
2857 ((and (##core#inline "C_i_flonump" b)
2858 (not (##core#inline "C_u_i_fpintegerp" b)))
2859 (if (negative? a)
2860 (log-expt (exact->inexact a) (exact->inexact b))
2861 (##core#inline_allocate
2862 ("C_a_i_flonum_expt" 4) (exact->inexact a) b)))
2863 ((##core#inline "C_i_flonump" a)
2864 (##core#inline_allocate ("C_a_i_flonum_expt" 4) a (exact->inexact b)))
2865 ;; this doesn't work that well, yet...
2866 ;; (XXX: What does this mean? why not? I do know this is ugly... :P)
2867 (else (if (or (inexact? a) (inexact? b))
2868 (exact->inexact (##sys#integer-power a (inexact->exact b)))
2869 (##sys#integer-power a b)))) ))
2870
2871;; Useful for sane error messages
2872(define (##sys#internal-gcd loc a b)
2873 (cond ((exact-integer? a)
2874 (cond ((exact-integer? b) (%integer-gcd a b))
2875 ((and (##core#inline "C_i_flonump" b)
2876 (##core#inline "C_u_i_fpintegerp" b))
2877 (exact->inexact (%integer-gcd a (inexact->exact b))))
2878 (else (##sys#error-bad-integer b loc))))
2879 ((and (##core#inline "C_i_flonump" a)
2880 (##core#inline "C_u_i_fpintegerp" a))
2881 (cond ((##core#inline "C_i_flonump" b)
2882 (##core#inline_allocate ("C_a_i_flonum_gcd" 4) a b))
2883 ((exact-integer? b)
2884 (exact->inexact (%integer-gcd (inexact->exact a) b)))
2885 (else (##sys#error-bad-integer b loc))))
2886 (else (##sys#error-bad-integer a loc))))
2887;; For compat reasons, we define this
2888(define (##sys#gcd a b) (##sys#internal-gcd 'gcd a b))
2889
2890(set! scheme#gcd
2891 (lambda ns
2892 (if (eq? ns '())
2893 0
2894 (let loop ((head (##sys#slot ns 0))
2895 (next (##sys#slot ns 1)))
2896 (if (null? next)
2897 (if (integer? head) (abs head) (##sys#error-bad-integer head 'gcd))
2898 (let ((n2 (##sys#slot next 0)))
2899 (loop (##sys#internal-gcd 'gcd head n2)
2900 (##sys#slot next 1)) ) ) ) ) ))
2901
2902(define (##sys#lcm x y)
2903 (let ((gcd (##sys#internal-gcd 'lcm x y))) ; Ensure better error message
2904 (abs (quotient (* x y) gcd) ) ) )
2905
2906(set! scheme#lcm
2907 (lambda ns
2908 (if (null? ns)
2909 1
2910 (let loop ((head (##sys#slot ns 0))
2911 (next (##sys#slot ns 1)))
2912 (if (null? next)
2913 (if (integer? head) (abs head) (##sys#error-bad-integer head 'lcm))
2914 (let* ((n2 (##sys#slot next 0))
2915 (gcd (##sys#internal-gcd 'lcm head n2)))
2916 (loop (quotient (* head n2) gcd)
2917 (##sys#slot next 1)) ) ) ) ) ))
2918
2919;; This simple enough idea is from
2920;; http://www.numberworld.org/y-cruncher/internals/radix-conversion.html
2921(define (##sys#integer->string/recursive n base expected-string-size)
2922 (let*-values (((halfsize) (fxshr (fx+ expected-string-size 1) 1))
2923 ((b^M/2) (##sys#integer-power base halfsize))
2924 ((hi lo) ((##core#primitive "C_u_integer_quotient_and_remainder")
2925 n b^M/2))
2926 ((strhi) (number->string hi base))
2927 ((strlo) (number->string (abs lo) base)))
2928 (string-append strhi
2929 ;; Fix up any leading zeroes that were stripped from strlo
2930 (make-string (fx- halfsize (string-length strlo)) #\0)
2931 strlo)))
2932
2933(define ##sys#extended-number->string
2934 (let ((string-append string-append))
2935 (lambda (n base)
2936 (cond
2937 ((ratnum? n)
2938 (string-append (number->string (%ratnum-numerator n) base)
2939 "/"
2940 (number->string (%ratnum-denominator n) base)))
2941 ;; What about bases that include an "i"? That could lead to
2942 ;; ambiguous results.
2943 ((cplxnum? n) (let ((r (%cplxnum-real n))
2944 (i (%cplxnum-imag n)) )
2945 (string-append
2946 (number->string r base)
2947 ;; The infinities and NaN always print their sign
2948 (if (and (finite? i) (positive? i)) "+" "")
2949 (number->string i base) "i") ))
2950 (else (##sys#error-bad-number n 'number->string))) ) ) )
2951
2952(define ##sys#number->string number->string) ; for printer
2953
2954;; We try to prevent memory exhaustion attacks by limiting the
2955;; maximum exponent value. Perhaps this should be a parameter?
2956(define-constant +maximum-allowed-exponent+ 10000)
2957
2958;; From "Easy Accurate Reading and Writing of Floating-Point Numbers"
2959;; by Aubrey Jaffer.
2960(define (mantexp->dbl mant point)
2961 (if (not (negative? point))
2962 (exact->inexact (* mant (##sys#integer-power 10 point)))
2963 (let* ((scl (##sys#integer-power 10 (abs point)))
2964 (bex (fx- (fx- (integer-length mant)
2965 (integer-length scl))
2966 flonum-precision)))
2967 (if (fx< bex 0)
2968 (let* ((num (arithmetic-shift mant (fxneg bex)))
2969 (quo (round-quotient num scl)))
2970 (cond ((> (integer-length quo) flonum-precision)
2971 ;; Too many bits of quotient; readjust
2972 (set! bex (fx+ 1 bex))
2973 (set! quo (round-quotient num (* scl 2)))))
2974 (ldexp (exact->inexact quo) bex))
2975 ;; Fall back to exact calculation in extreme cases
2976 (* mant (##sys#integer-power 10 point))))))
2977
2978(define ldexp (foreign-lambda double "ldexp" double int))
2979
2980;; Should we export this?
2981(define (round-quotient n d)
2982 (let ((q (%integer-quotient n d)))
2983 (if ((if (even? q) > >=) (* (abs (remainder n d)) 2) (abs d))
2984 (+ q (if (eqv? (negative? n) (negative? d)) 1 -1))
2985 q)))
2986
2987(define (##sys#string->compnum radix str offset exactness)
2988 ;; Flipped when a sign is encountered (for inexact numbers only)
2989 (define negative #f)
2990 ;; Go inexact unless exact was requested (with #e prefix)
2991 (define (go-inexact! neg?)
2992 (unless (eq? exactness 'e)
2993 (set! exactness 'i)
2994 (set! negative (or negative neg?))))
2995 (define (safe-exponent value e)
2996 (and e (cond
2997 ((not value) 0)
2998 ((> e +maximum-allowed-exponent+)
2999 (and (eq? exactness 'i)
3000 (cond ((zero? value) 0.0)
3001 ((> value 0.0) +inf.0)
3002 (else -inf.0))))
3003 ((< e (fxneg +maximum-allowed-exponent+))
3004 (and (eq? exactness 'i) +0.0))
3005 ((eq? exactness 'i) (mantexp->dbl value e))
3006 (else (* value (##sys#integer-power 10 e))))))
3007 (define (make-nan)
3008 ;; Return fresh NaNs, so eqv? returns #f on two read NaNs. This
3009 ;; is not mandated by the standard, but compatible with earlier
3010 ;; CHICKENs and it just makes more sense.
3011 (##core#inline_allocate ("C_a_i_flonum_quotient" 4) 0.0 0.0))
3012 (let* ((len (string-length str))
3013 (0..r (integer->char (fx+ (char->integer #\0) (fx- radix 1))))
3014 (a..r (integer->char (fx+ (char->integer #\a) (fx- radix 11))))
3015 (A..r (integer->char (fx+ (char->integer #\A) (fx- radix 11))))
3016 ;; Ugly flag which we need (note that "exactness" is mutated too!)
3017 ;; Since there is (almost) no backtracking we can do this.
3018 (seen-hashes? #f)
3019 ;; All these procedures return #f or an object consed onto an end
3020 ;; position. If the cdr is false, that's the end of the string.
3021 ;; If just #f is returned, the string contains invalid number syntax.
3022 (scan-digits
3023 (lambda (start)
3024 (let lp ((i start))
3025 (if (fx= i len)
3026 (and (fx> i start) (cons i #f))
3027 (let ((c (string-ref str i)))
3028 (if (fx<= radix 10)
3029 (if (and (char>=? c #\0) (char<=? c 0..r))
3030 (lp (fx+ i 1))
3031 (and (fx> i start) (cons i i)))
3032 (if (or (and (char>=? c #\0) (char<=? c #\9))
3033 (and (char>=? c #\a) (char<=? c a..r))
3034 (and (char>=? c #\A) (char<=? c A..r)))
3035 (lp (fx+ i 1))
3036 (and (fx> i start) (cons i i)))))))))
3037 (scan-hashes
3038 (lambda (start)
3039 (let lp ((i start))
3040 (if (fx= i len)
3041 (and (fx> i start) (cons i #f))
3042 (let ((c (string-ref str i)))
3043 (if (eq? c #\#)
3044 (lp (fx+ i 1))
3045 (and (fx> i start) (cons i i))))))))
3046 (scan-digits+hashes
3047 (lambda (start neg? all-hashes-ok?)
3048 (let* ((digits (and (not seen-hashes?) (scan-digits start)))
3049 (hashes (if digits
3050 (and (cdr digits) (scan-hashes (cdr digits)))
3051 (and all-hashes-ok? (scan-hashes start))))
3052 (end (or hashes digits)))
3053 (and-let* ((end)
3054 (num (##core#inline_allocate
3055 ("C_s_a_i_digits_to_integer" 6)
3056 str start (car end) radix neg?)))
3057 (when hashes ; Eeewww. Feeling dirty yet?
3058 (set! seen-hashes? #t)
3059 (go-inexact! neg?))
3060 (cons num (cdr end))))))
3061 (scan-exponent
3062 (lambda (start)
3063 (and (fx< start len)
3064 (let ((sign (case (string-ref str start)
3065 ((#\+) 'pos) ((#\-) 'neg) (else #f))))
3066 (and-let* ((start (if sign (fx+ start 1) start))
3067 (end (scan-digits start)))
3068 (cons (##core#inline_allocate
3069 ("C_s_a_i_digits_to_integer" 6)
3070 str start (car end) radix (eq? sign 'neg))
3071 (cdr end)))))))
3072 (scan-decimal-tail ; The part after the decimal dot
3073 (lambda (start neg? decimal-head)
3074 (and (fx< start len)
3075 (let* ((tail (scan-digits+hashes start neg? decimal-head))
3076 (next (if tail (cdr tail) start)))
3077 (and (or decimal-head (not next)
3078 (fx> next start)) ; Don't allow empty "."
3079 (case (and next (string-ref str next))
3080 ((#\e #\s #\f #\d #\l
3081 #\E #\S #\F #\D #\L)
3082 (and-let* (((fx> len next))
3083 (ee (scan-exponent (fx+ next 1)))
3084 (e (car ee))
3085 (h (safe-exponent decimal-head e)))
3086 (let* ((te (and tail (fx- e (fx- (cdr tail) start))))
3087 (num (and tail (car tail)))
3088 (t (safe-exponent num te)))
3089 (cons (if t (+ h t) h) (cdr ee)))))
3090 (else (let* ((last (or next len))
3091 (te (and tail (fx- start last)))
3092 (num (and tail (car tail)))
3093 (t (safe-exponent num te))
3094 (h (or decimal-head 0)))
3095 (cons (if t (+ h t) h) next)))))))))
3096 (scan-ureal
3097 (lambda (start neg?)
3098 (if (and (fx> len (fx+ start 1)) (eq? radix 10)
3099 (eq? (string-ref str start) #\.))
3100 (begin
3101 (go-inexact! neg?)
3102 (scan-decimal-tail (fx+ start 1) neg? #f))
3103 (and-let* ((end (scan-digits+hashes start neg? #f)))
3104 (case (and (cdr end) (string-ref str (cdr end)))
3105 ((#\.)
3106 (go-inexact! neg?)
3107 (and (eq? radix 10)
3108 (if (fx> len (fx+ (cdr end) 1))
3109 (scan-decimal-tail (fx+ (cdr end) 1) neg? (car end))
3110 (cons (car end) #f))))
3111 ((#\e #\s #\f #\d #\l
3112 #\E #\S #\F #\D #\L)
3113 (go-inexact! neg?)
3114 (and-let* (((eq? radix 10))
3115 ((fx> len (cdr end)))
3116 (ee (scan-exponent (fx+ (cdr end) 1)))
3117 (num (car end))
3118 (val (safe-exponent num (car ee))))
3119 (cons val (cdr ee))))
3120 ((#\/)
3121 (set! seen-hashes? #f) ; Reset flag for denominator
3122 (and-let* (((fx> len (cdr end)))
3123 (d (scan-digits+hashes (fx+ (cdr end) 1) #f #f))
3124 (num (car end))
3125 (denom (car d)))
3126 (if (not (eq? denom 0))
3127 (cons (##sys#/-2 num denom) (cdr d))
3128 ;; Hacky: keep around an inexact until we decide we
3129 ;; *really* need exact values, then fail at the end.
3130 (and (not (eq? exactness 'e))
3131 (case (signum num)
3132 ((-1) (cons -inf.0 (cdr d)))
3133 ((0) (cons (make-nan) (cdr d)))
3134 ((+1) (cons +inf.0 (cdr d))))))))
3135 (else end))))))
3136 (scan-real
3137 (lambda (start)
3138 (and (fx< start len)
3139 (let* ((sign (case (string-ref str start)
3140 ((#\+) 'pos) ((#\-) 'neg) (else #f)))
3141 (next (if sign (fx+ start 1) start)))
3142 (and (fx< next len)
3143 (case (string-ref str next)
3144 ((#\i #\I)
3145 (or (and sign
3146 (cond
3147 ((fx= (fx+ next 1) len) ; [+-]i
3148 (cons (if (eq? sign 'neg) -1 1) next))
3149 ((and (fx<= (fx+ next 5) len)
3150 (string-ci=? (substring str next (fx+ next 5)) "inf.0"))
3151 (go-inexact! (eq? sign 'neg))
3152 (cons (if (eq? sign 'neg) -inf.0 +inf.0)
3153 (and (fx< (fx+ next 5) len)
3154 (fx+ next 5))))
3155 (else #f)))
3156 (scan-ureal next (eq? sign 'neg))))
3157 ((#\n #\N)
3158 (or (and sign
3159 (fx<= (fx+ next 5) len)
3160 (string-ci=? (substring str next (fx+ next 5)) "nan.0")
3161 (begin (go-inexact! (eq? sign 'neg))
3162 (cons (make-nan)
3163 (and (fx< (fx+ next 5) len)
3164 (fx+ next 5)))))
3165 (scan-ureal next (eq? sign 'neg))))
3166 (else (scan-ureal next (eq? sign 'neg)))))))))
3167 (number (and-let* ((r1 (scan-real offset)))
3168 (case (and (cdr r1) (string-ref str (cdr r1)))
3169 ((#f) (car r1))
3170 ((#\i #\I) (and (fx= len (fx+ (cdr r1) 1))
3171 (or (eq? (string-ref str offset) #\+) ; ugh
3172 (eq? (string-ref str offset) #\-))
3173 (make-rectangular 0 (car r1))))
3174 ((#\+ #\-)
3175 (set! seen-hashes? #f) ; Reset flag for imaginary part
3176 (and-let* ((r2 (scan-real (cdr r1)))
3177 ((cdr r2))
3178 ((fx= len (fx+ (cdr r2) 1)))
3179 ((or (eq? (string-ref str (cdr r2)) #\i)
3180 (eq? (string-ref str (cdr r2)) #\I))))
3181 (make-rectangular (car r1) (car r2))))
3182 ((#\@)
3183 (set! seen-hashes? #f) ; Reset flag for angle
3184 (and-let* ((r2 (scan-real (fx+ (cdr r1) 1)))
3185 ((not (cdr r2))))
3186 (make-polar (car r1) (car r2))))
3187 (else #f)))))
3188 (and number (if (eq? exactness 'i)
3189 (let ((r (exact->inexact number)))
3190 ;; Stupid hack because flonums can represent negative zero,
3191 ;; but we're coming from an exact which has no such thing.
3192 (if (and negative (zero? r)) (fpneg r) r))
3193 ;; Ensure we didn't encounter +inf.0 or +nan.0 with #e
3194 (and (finite? number) number)))))
3195
3196(set! scheme#string->number
3197 (lambda (str #!optional (base 10))
3198 (##sys#check-string str 'string->number)
3199 (unless (and (##core#inline "C_fixnump" base)
3200 (fx< 1 base) (fx< base 37)) ; We only have 0-9 and the alphabet!
3201 (##sys#error-bad-base base 'string->number))
3202 (let scan-prefix ((i 0)
3203 (exness #f)
3204 (radix #f)
3205 (len (string-length str)))
3206 (if (and (fx< (fx+ i 2) len) (eq? (string-ref str i) #\#))
3207 (case (string-ref str (fx+ i 1))
3208 ((#\i #\I) (and (not exness) (scan-prefix (fx+ i 2) 'i radix len)))
3209 ((#\e #\E) (and (not exness) (scan-prefix (fx+ i 2) 'e radix len)))
3210 ((#\b #\B) (and (not radix) (scan-prefix (fx+ i 2) exness 2 len)))
3211 ((#\o #\O) (and (not radix) (scan-prefix (fx+ i 2) exness 8 len)))
3212 ((#\d #\D) (and (not radix) (scan-prefix (fx+ i 2) exness 10 len)))
3213 ((#\x #\X) (and (not radix) (scan-prefix (fx+ i 2) exness 16 len)))
3214 (else #f))
3215 (##sys#string->compnum (or radix base) str i exness)))))
3216
3217(define (##sys#string->number str #!optional (radix 10) exactness)
3218 (##sys#string->compnum radix str 0 exactness))
3219
3220(define ##sys#fixnum->string (##core#primitive "C_fixnum_to_string"))
3221(define ##sys#flonum->string (##core#primitive "C_flonum_to_string"))
3222(define ##sys#integer->string (##core#primitive "C_integer_to_string"))
3223(define ##sys#number->string number->string)
3224
3225(set! chicken.base#equal=?
3226 (lambda (x y)
3227 (define (compare-slots x y start)
3228 (let ((l1 (##sys#size x))
3229 (l2 (##sys#size y)))
3230 (and (eq? l1 l2)
3231 (or (fx<= l1 start)
3232 (let ((l1n (fx- l1 1)))
3233 (let loop ((i start))
3234 (if (fx= i l1n)
3235 (walk (##sys#slot x i) (##sys#slot y i)) ; tailcall
3236 (and (walk (##sys#slot x i) (##sys#slot y i))
3237 (loop (fx+ i 1))))))))))
3238 (define (walk x y)
3239 (cond ((eq? x y))
3240 ((number? x)
3241 (if (number? y)
3242 (= x y)
3243 (eq? x y)))
3244 ((not (##core#inline "C_blockp" x)) #f)
3245 ((not (##core#inline "C_blockp" y)) #f)
3246 ((not (##core#inline "C_sametypep" x y)) #f)
3247 ((##core#inline "C_specialp" x)
3248 (and (##core#inline "C_specialp" y)
3249 (if (##core#inline "C_closurep" x)
3250 (##core#inline "shallow_equal" x y)
3251 (compare-slots x y 1))))
3252 ((##core#inline "C_stringp" x)
3253 (walk (##sys#slot x 0) (##sys#slot y 0)))
3254 ((##core#inline "C_byteblockp" x)
3255 (and (##core#inline "C_byteblockp" y)
3256 (let ((s1 (##sys#size x)))
3257 (and (eq? s1 (##sys#size y))
3258 (##core#inline "C_bv_compare" x y s1)))))
3259 (else
3260 (let ((s1 (##sys#size x)))
3261 (and (eq? s1 (##sys#size y))
3262 (compare-slots x y 0))))))
3263 (walk x y) ))
3264
3265
3266;;; Symbols:
3267
3268(define ##sys#snafu '##sys#fnord)
3269(define ##sys#intern-symbol (##core#primitive "C_string_to_symbol"))
3270(define ##sys#intern-keyword (##core#primitive "C_string_to_keyword"))
3271(define ##sys#make-symbol (##core#primitive "C_make_symbol"))
3272(define (##sys#interned-symbol? x) (##core#inline "C_lookup_symbol" x))
3273
3274(define (##sys#string->symbol-name s)
3275 (let* ((bv (##sys#slot s 0))
3276 (len (##sys#size bv))
3277 (s2 (##sys#make-bytevector len)))
3278 (##core#inline "C_copy_bytevector" bv s2 len)))
3279
3280(define (##sys#symbol->string/shared s)
3281 (let* ((bv (##sys#slot s 1))
3282 (count (##core#inline "C_utf_length" bv)))
3283 (##core#inline_allocate ("C_a_ustring" 5)
3284 bv
3285 count)))
3286
3287(define (##sys#symbol->string s)
3288 (let* ((bv (##sys#slot s 1))
3289 (len (##sys#size bv))
3290 (s2 (##sys#make-bytevector len))
3291 (count (##core#inline "C_utf_length" bv)))
3292 (##core#inline_allocate ("C_a_ustring" 5)
3293 (##core#inline "C_copy_bytevector" bv s2 len)
3294 count)))
3295
3296(define (##sys#string->symbol str)
3297 (##sys#intern-symbol (##sys#string->symbol-name str) ))
3298
3299(set! scheme#symbol->string
3300 (lambda (s)
3301 (##sys#check-symbol s 'symbol->string)
3302 (##sys#symbol->string s) ) )
3303
3304(set! scheme#string->symbol
3305 (lambda (str)
3306 (##sys#check-string str 'string->symbol)
3307 (##sys#string->symbol str)))
3308
3309(set! chicken.base#string->uninterned-symbol
3310 (lambda (str)
3311 (##sys#check-string str 'string->uninterned-symbol)
3312 (##sys#make-symbol (##sys#string->symbol-name str))))
3313
3314(set! chicken.base#gensym
3315 (let ((counter -1))
3316 (lambda str-or-sym
3317 (let ((err (lambda (prefix) (##sys#signal-hook #:type-error 'gensym "argument is not a string or symbol" prefix))))
3318 (set! counter (fx+ counter 1))
3319 (##sys#make-symbol
3320 (##sys#string->symbol-name
3321 (##sys#string-append
3322 (if (eq? str-or-sym '())
3323 "g"
3324 (let ((prefix (car str-or-sym)))
3325 (or (and (##core#inline "C_blockp" prefix)
3326 (cond ((##core#inline "C_stringp" prefix) prefix)
3327 ((##core#inline "C_symbolp" prefix) (##sys#symbol->string/shared prefix))
3328 (else (err prefix))))
3329 (err prefix) ) ) )
3330 (##sys#number->string counter) ) ) ) ) ) ) )
3331
3332(set! chicken.base#symbol-append
3333 (let ((string-append string-append))
3334 (lambda ss
3335 (##sys#string->symbol
3336 (apply
3337 string-append
3338 (map (lambda (s)
3339 (##sys#check-symbol s 'symbol-append)
3340 (##sys#symbol->string/shared s))
3341 ss))))))
3342
3343;;; Keywords:
3344
3345(module chicken.keyword
3346 (keyword? get-keyword keyword->string string->keyword)
3347
3348(import scheme)
3349(import chicken.fixnum)
3350
3351(define (keyword? x) (##core#inline "C_i_keywordp" x) )
3352
3353(define string->keyword
3354 (let ([string string] )
3355 (lambda (s)
3356 (##sys#check-string s 'string->keyword)
3357 (##sys#intern-keyword (##sys#string->symbol-name s) ) ) ))
3358
3359(define keyword->string
3360 (let ([keyword? keyword?])
3361 (lambda (kw)
3362 (if (keyword? kw)
3363 (##sys#symbol->string kw)
3364 (##sys#signal-hook #:type-error 'keyword->string "bad argument type - not a keyword" kw) ) ) ) )
3365
3366(define get-keyword
3367 (let ((tag (list 'tag)))
3368 (lambda (key args #!optional thunk)
3369 (##sys#check-keyword key 'get-keyword)
3370 (##sys#check-list args 'get-keyword)
3371 (let ((r (##core#inline "C_i_get_keyword" key args tag)))
3372 (if (eq? r tag) ; not found
3373 (and thunk (thunk))
3374 r)))))
3375
3376(define ##sys#get-keyword get-keyword))
3377
3378(import chicken.keyword)
3379
3380
3381;;; bytevectors:
3382
3383(define (##sys#bytevector->list v)
3384 (let ((n (##sys#size v)))
3385 (let loop ((i (fx- n 1)) (lst '()))
3386 (if (fx< i 0)
3387 lst
3388 (loop (fx- i 1)
3389 (cons (##core#inline "C_subbyte" v i) lst))))))
3390
3391(define (##sys#list->bytevector lst0)
3392 (let* ((n (length lst0))
3393 (bv (##sys#make-bytevector n)))
3394 (let loop ((lst lst0) (i 0))
3395 (if (null? lst)
3396 bv
3397 (let ((b (car lst)))
3398 (if (##core#inline "C_fixnump" b)
3399 (##core#inline "C_setsubbyte" bv i b)
3400 (##sys#signal-hook #:type-error "can not convert list to bytevector" lst0))
3401 (loop (cdr lst) (fx+ i 1)))))))
3402
3403(module chicken.bytevector
3404 (bytevector? bytevector=? bytevector-length
3405 make-bytevector bytevector bytevector-u8-ref
3406 bytevector-u8-set! bytevector-copy bytevector-copy!
3407 bytevector-append utf8->string string->utf8
3408 latin1->string string->latin1)
3409
3410(import scheme (chicken foreign))
3411
3412(define (make-bytevector size #!optional fill)
3413 (##sys#check-fixnum size 'make-bytevector)
3414 (if fill (##sys#check-fixnum fill 'make-bytevector))
3415 (##sys#make-bytevector size fill) )
3416
3417(define (bytevector? x)
3418 (and (##core#inline "C_blockp" x)
3419 (##core#inline "C_bytevectorp" x) ) )
3420
3421(define (bytevector-length bv)
3422 (##sys#check-bytevector bv 'bytevector-size)
3423 (##sys#size bv) )
3424
3425(define (bytevector-u8-ref bv i)
3426 (##core#inline "C_i_bytevector_ref" bv i))
3427
3428(define (bytevector-u8-set! bv i b)
3429 (##core#inline "C_i_bytevector_set" bv i b))
3430
3431(define (string->utf8 s)
3432 (##sys#check-string s 'string->utf8)
3433 (let* ((sbv (##sys#slot s 0))
3434 (n (##core#inline "C_fixnum_difference" (##sys#size sbv) 1))
3435 (bv (##sys#make-bytevector n)) )
3436 (##core#inline "C_copy_memory" bv sbv n)
3437 bv) )
3438
3439(define (utf8->string bv #!optional (validate #t))
3440 (##sys#check-bytevector bv 'utf8->string)
3441 (if (and validate (not (##core#inline "C_utf_validate" bv (##sys#size bv))))
3442 (##sys#error-hook (foreign-value "C_DECODING_ERROR" int)
3443 'utf8->string bv))
3444 (##sys#buffer->string bv 0 (##sys#size bv)))
3445
3446(define (string->latin1 s)
3447 (##sys#check-string s 'string->latin1)
3448 (let* ((sbv (##sys#slot s 0))
3449 (len (##sys#slot s 1))
3450 (blen (##core#inline "C_fixnum_difference" (##sys#size sbv) 1))
3451 (bv (##sys#make-bytevector len)) )
3452 (##core#inline "C_utf_to_latin" sbv bv 0 blen)
3453 bv))
3454
3455(define (latin1->string bv)
3456 (##sys#check-bytevector bv 'latin1->string)
3457 (let* ((len (##sys#size bv))
3458 (buf (##sys#make-bytevector (##core#inline "C_fixnum_times" len 2)))
3459 (n (##core#inline "C_latin_to_utf" bv buf 0 len)))
3460 (##sys#buffer->string buf 0 n)))
3461
3462(define (bytevector=? b1 b2)
3463 (##sys#check-bytevector b1 'bytevector=?)
3464 (##sys#check-bytevector b2 'bytevector=?)
3465 (let ((n (##sys#size b1)))
3466 (and (eq? (##sys#size b2) n)
3467 (##core#inline "C_bv_compare" b1 b2 n))))
3468
3469(define (bytevector . args)
3470 (let* ((n (length args))
3471 (bv (##sys#make-bytevector n)))
3472 (let loop ((args args) (i 0))
3473 (cond ((null? args) bv)
3474 (else
3475 (let ((b (car args)))
3476 (##sys#check-fixnum b 'bytevector)
3477 (##core#inline "C_setsubbyte" bv i b)
3478 (loop (cdr args) (##core#inline "C_fixnum_plus" i 1))))))))
3479
3480(define (bytevector-copy bv #!optional (start 0) end)
3481 (##sys#check-bytevector bv 'bytevector-copy)
3482 (let* ((n (##sys#size bv))
3483 (to (or end n)))
3484 (if end
3485 (##sys#check-range/including end 0 n 'bytevector->copy))
3486 (cond ((and (eq? n 0) (eq? start 0) (eq? 0 to))
3487 (##sys#make-bytevector 0))
3488 (else
3489 (##sys#check-range/including start 0 n 'bytevector->copy)
3490 (let* ((n2 (##core#inline "C_fixnum_difference" to start))
3491 (v2 (##sys#make-bytevector n2)))
3492 (##core#inline "C_copy_memory_with_offset" v2 bv 0 start n2)
3493 v2)))))
3494
3495(define (bytevector-copy! bv1 at bv2 #!optional (start 0) end)
3496 (##sys#check-bytevector bv1 'bytevector-copy!)
3497 (##sys#check-bytevector bv2 'bytevector-copy!)
3498 (let* ((n1 (##sys#size bv1))
3499 (n2 (##sys#size bv2))
3500 (to (or end n2))
3501 (nc (##core#inline "C_fixnum_difference" to start)))
3502 (cond ((and (eq? n2 0) (eq? nc 0) (eq? start 0)) (##core#undefined))
3503 (else
3504 (##sys#check-range/including start 0 n2 'bytevector->copy!)
3505 (##sys#check-range/including at 0 n1 'bytevector->copy!)
3506 (##sys#check-range/including (##core#inline "C_fixnum_plus" at nc)
3507 0 n1 'bytevector->copy!)
3508 (##core#inline "C_copy_memory_with_offset" bv1 bv2 at start nc)))))
3509
3510(define (bytevector-append . bvs)
3511 (let loop ((lst bvs) (len 0))
3512 (if (null? lst)
3513 (let ((bv (##sys#make-bytevector len)))
3514 (let loop ((lst bvs) (i 0))
3515 (if (null? lst)
3516 bv
3517 (let* ((bv1 (car lst))
3518 (n (##sys#size bv1)))
3519 (##core#inline "C_copy_memory_with_offset" bv bv1 i 0 n)
3520 (loop (cdr lst) (##core#inline "C_fixnum_plus" i n))))))
3521 (let ((bv (car lst)))
3522 (##sys#check-bytevector bv 'bytevector-append)
3523 (loop (cdr lst) (##core#inline "C_fixnum_plus" len (##sys#size bv)))))))
3524
3525) ; chicken.bytevector
3526
3527
3528;;; Vectors:
3529(set! scheme#make-vector
3530 (lambda (size . fill)
3531 (##sys#check-fixnum size 'make-vector)
3532 (when (fx< size 0) (##sys#error 'make-vector "size is negative" size))
3533 (##sys#allocate-vector
3534 size
3535 (if (null? fill)
3536 (##core#undefined)
3537 (car fill) ))))
3538
3539(define ##sys#make-vector make-vector)
3540
3541(set! scheme#list->vector
3542 (lambda (lst0)
3543 (if (not (list? lst0))
3544 (##sys#error-not-a-proper-list lst0 'list->vector)
3545 (let* ([len (length lst0)]
3546 [v (##sys#make-vector len)] )
3547 (let loop ([lst lst0]
3548 [i 0])
3549 (if (null? lst)
3550 v
3551 (begin
3552 (##sys#setslot v i (##sys#slot lst 0))
3553 (loop (##sys#slot lst 1) (fx+ i 1)) ) ) ) ) )))
3554
3555(set! scheme#vector->list
3556 (lambda (v #!optional start end)
3557 (##sys#check-vector v 'vector->list)
3558 (let ((len (##sys#size v)))
3559 (if start
3560 (##sys#check-range/including start 0 len 'vector->list)
3561 (set! start 0))
3562 (if end
3563 (##sys#check-range/including end 0 len 'vector->list)
3564 (set! end len))
3565 (let loop ((i start))
3566 (if (fx>= i end)
3567 '()
3568 (cons (##sys#slot v i)
3569 (loop (fx+ i 1)) ) ) ) ) ))
3570
3571(set! scheme#vector (lambda xs (list->vector xs) ))
3572
3573(set! scheme#vector-fill!
3574 (lambda (v x #!optional start end)
3575 (##sys#check-vector v 'vector-fill!)
3576 (let ((len (##sys#size v)))
3577 (if start
3578 (##sys#check-range/including start 0 len 'vector-fill!)
3579 (set! start 0))
3580 (if end
3581 (##sys#check-range/including end 0 len 'vector-fill!)
3582 (set! end len))
3583 (do ((i start (fx+ i 1)))
3584 ((fx>= i end))
3585 (##sys#setslot v i x) ) ) ))
3586
3587(define (scheme#vector-copy v #!optional start end)
3588 (##sys#check-vector v 'vector-copy)
3589 (let ((copy (lambda (v start end)
3590 (let* ((len (##sys#size v)))
3591 (##sys#check-range/including start 0 end 'vector-copy)
3592 (##sys#check-range/including end start len 'vector-copy)
3593 (let ((vec (##sys#make-vector (fx- end start))))
3594 (do ((ti 0 (fx+ ti 1))
3595 (fi start (fx+ fi 1)))
3596 ((fx>= fi end) vec)
3597 (##sys#setslot vec ti (##sys#slot v fi))))))))
3598 (if end
3599 (copy v start end)
3600 (copy v (or start 0) (##sys#size v)))))
3601
3602(define (scheme#vector-copy! to at from #!optional start end)
3603 (##sys#check-vector to 'vector-copy!)
3604 (##sys#check-vector from 'vector-copy!)
3605 (let ((copy! (lambda (to at from start end)
3606 (let* ((tlen (##sys#size to))
3607 (flen (##sys#size from))
3608 (d (fx- end start)))
3609 (##sys#check-range/including at 0 tlen 'vector-copy!)
3610 (##sys#check-range/including start 0 end 'vector-copy!)
3611 (##sys#check-range/including end start flen 'vector-copy!)
3612 (##sys#check-range/including d 0 (fx- tlen at) 'vector-copy!)
3613 (if (and (eq? to from) (fx< start at))
3614 (do ((fi (fx- end 1) (fx- fi 1))
3615 (ti (fx- (fx+ at d) 1) (fx- ti 1)))
3616 ((fx< fi start))
3617 (##sys#setslot to ti (##sys#slot from fi)))
3618 (do ((fi start (fx+ fi 1))
3619 (ti at (fx+ ti 1)))
3620 ((fx= fi end))
3621 (##sys#setslot to ti (##sys#slot from fi))))))))
3622 (if end
3623 (copy! to at from start end)
3624 (copy! to at from (or start 0) (##sys#size from)))))
3625
3626(define (scheme#vector-append . vs)
3627 (##sys#for-each (cut ##sys#check-vector <> 'vector-append) vs)
3628 (let* ((lens (map ##sys#size vs))
3629 (vec (##sys#make-vector (foldl fx+ 0 lens))))
3630 (do ((vs vs (cdr vs))
3631 (lens lens (cdr lens))
3632 (i 0 (fx+ i (car lens))))
3633 ((null? vs) vec)
3634 (scheme#vector-copy! vec i (car vs) 0 (car lens)))))
3635
3636(set! chicken.base#subvector
3637 (lambda (v i #!optional j)
3638 (##sys#check-vector v 'subvector)
3639 (let* ((len (##sys#size v))
3640 (j (or j len))
3641 (len2 (fx- j i)))
3642 (##sys#check-range/including i 0 len 'subvector)
3643 (##sys#check-range/including j 0 len 'subvector)
3644 (let ((v2 (make-vector len2)))
3645 (do ((k 0 (fx+ k 1)))
3646 ((fx>= k len2) v2)
3647 (##sys#setslot v2 k (##sys#slot v (fx+ k i))))))))
3648
3649(set! chicken.base#vector-resize
3650 (lambda (v n #!optional init)
3651 (##sys#check-vector v 'vector-resize)
3652 (##sys#check-fixnum n 'vector-resize)
3653 (##sys#vector-resize v n init)))
3654
3655(define (##sys#vector-resize v n init)
3656 (let ((v2 (##sys#make-vector n init))
3657 (len (min (##sys#size v) n)) )
3658 (do ((i 0 (fx+ i 1)))
3659 ((fx>= i len) v2)
3660 (##sys#setslot v2 i (##sys#slot v i)) ) ) )
3661
3662;;; Characters:
3663
3664(set! scheme#char-ci=?
3665 (lambda (x y . more)
3666 (##sys#check-char x 'char-ci=?)
3667 (##sys#check-char y 'char-ci=?)
3668 (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3669 (let loop ((c c2) (cs more)
3670 (f (eq? (##core#inline "C_utf_char_foldcase" x) c2)))
3671 (if (null? cs)
3672 f
3673 (let ((c2 (##sys#slot cs 0)))
3674 (##sys#check-char c2 'char-ci=?)
3675 (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3676 (loop c2 (##sys#slot cs 1)
3677 (and f (eq? c c2))))))))))
3678
3679(set! scheme#char-ci>?
3680 (lambda (x y . more)
3681 (##sys#check-char x 'char-ci>?)
3682 (##sys#check-char y 'char-ci>?)
3683 (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3684 (let loop ((c c2) (cs more)
3685 (f (##core#inline "C_u_i_char_greaterp"
3686 (##core#inline "C_utf_char_foldcase" x)
3687 c2)))
3688 (if (null? cs)
3689 f
3690 (let ((c2 (##sys#slot cs 0)))
3691 (##sys#check-char c2 'char-ci>?)
3692 (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3693 (loop c2 (##sys#slot cs 1)
3694 (and f (##core#inline "C_u_i_char_greaterp" c c2))))))))))
3695
3696(set! scheme#char-ci<?
3697 (lambda (x y . more)
3698 (##sys#check-char x 'char-ci<?)
3699 (##sys#check-char y 'char-ci<?)
3700 (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3701 (let loop ((c c2) (cs more)
3702 (f (##core#inline "C_u_i_char_lessp"
3703 (##core#inline "C_utf_char_foldcase" x)
3704 c2)))
3705 (if (null? cs)
3706 f
3707 (let ((c2 (##sys#slot cs 0)))
3708 (##sys#check-char c2 'char-ci<?)
3709 (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3710 (loop c2 (##sys#slot cs 1)
3711 (and f (##core#inline "C_u_i_char_lessp" c c2))))))))))
3712
3713(set! scheme#char-ci>=?
3714 (lambda (x y . more)
3715 (##sys#check-char x 'char-ci>=?)
3716 (##sys#check-char y 'char-ci>=?)
3717 (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3718 (let loop ((c c2) (cs more)
3719 (f (##core#inline "C_u_i_char_greater_or_equal_p"
3720 (##core#inline "C_utf_char_foldcase" x)
3721 c2)))
3722 (if (null? cs)
3723 f
3724 (let ((c2 (##sys#slot cs 0)))
3725 (##sys#check-char c2 'char-ci>=?)
3726 (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3727 (loop c2 (##sys#slot cs 1)
3728 (and f (##core#inline "C_u_i_char_greater_or_equal_p" c c2))))))))))
3729
3730(set! scheme#char-ci<=?
3731 (lambda (x y . more)
3732 (##sys#check-char x 'char-ci<=?)
3733 (##sys#check-char y 'char-ci<=?)
3734 (let ((c2 (##core#inline "C_utf_char_foldcase" y)))
3735 (let loop ((c c2) (cs more)
3736 (f (##core#inline "C_u_i_char_less_or_equal_p"
3737 (##core#inline "C_utf_char_foldcase" x)
3738 c2)))
3739 (if (null? cs)
3740 f
3741 (let ((c2 (##sys#slot cs 0)))
3742 (##sys#check-char c2 'char-ci<=?)
3743 (let ((c2 ((##core#inline "C_utf_char_foldcase" c2))))
3744 (loop c2 (##sys#slot cs 1)
3745 (and f (##core#inline "C_u_i_char_less_or_equal_p" c c2))))))))))
3746
3747(set! chicken.base#char-name
3748 (let ((chars-to-names (make-vector char-name-table-size '()))
3749 (names-to-chars '()))
3750 (define (lookup-char c)
3751 (let* ([code (char->integer c)]
3752 [key (##core#inline "C_fixnum_modulo" code char-name-table-size)] )
3753 (let loop ([b (##sys#slot chars-to-names key)])
3754 (and (pair? b)
3755 (let ([a (##sys#slot b 0)])
3756 (if (eq? (##sys#slot a 0) c)
3757 a
3758 (loop (##sys#slot b 1)) ) ) ) ) ) )
3759 (lambda (x . y)
3760 (let ([chr (if (pair? y) (car y) #f)])
3761 (cond [(char? x)
3762 (and-let* ([a (lookup-char x)])
3763 (##sys#slot a 1) ) ]
3764 [chr
3765 (##sys#check-symbol x 'char-name)
3766 (##sys#check-char chr 'char-name)
3767 (when (fx< (##sys#size (##sys#slot x 1)) 2)
3768 (##sys#signal-hook #:type-error 'char-name "invalid character name" x) )
3769 (let ([a (lookup-char chr)])
3770 (if a
3771 (let ([b (assq x names-to-chars)])
3772 (##sys#setslot a 1 x)
3773 (if b
3774 (##sys#setislot b 1 chr)
3775 (set! names-to-chars (cons (cons x chr) names-to-chars)) ) )
3776 (let ([key (##core#inline "C_fixnum_modulo" (char->integer chr) char-name-table-size)])
3777 (set! names-to-chars (cons (cons x chr) names-to-chars))
3778 (##sys#setslot
3779 chars-to-names key
3780 (cons (cons chr x) (##sys#slot chars-to-names key))) ) ) ) ]
3781 [else
3782 (##sys#check-symbol x 'char-name)
3783 (and-let* ([a (assq x names-to-chars)])
3784 (##sys#slot a 1) ) ] ) ) ) ) )
3785
3786;; TODO: Use the character names here in the next release? Or just
3787;; use the numbers everywhere, for clarity?
3788(char-name 'space #\space)
3789(char-name 'tab #\tab)
3790(char-name 'linefeed #\linefeed)
3791(char-name 'newline #\newline)
3792(char-name 'vtab (integer->char 11))
3793(char-name 'delete (integer->char 127))
3794(char-name 'esc (integer->char 27))
3795(char-name 'escape (integer->char 27))
3796(char-name 'alarm (integer->char 7))
3797(char-name 'nul (integer->char 0))
3798(char-name 'null (integer->char 0))
3799(char-name 'return #\return)
3800(char-name 'page (integer->char 12))
3801(char-name 'backspace (integer->char 8))
3802
3803
3804;;; Procedures:
3805
3806(define ##sys#call-with-current-continuation (##core#primitive "C_call_cc"))
3807(define ##sys#call-with-cthulhu (##core#primitive "C_call_with_cthulhu"))
3808(define ##sys#call-with-values call-with-values)
3809
3810(define (##sys#for-each p lst0)
3811 (let loop ((lst lst0))
3812 (cond ((eq? lst '()) (##core#undefined))
3813 ((pair? lst)
3814 (p (##sys#slot lst 0))
3815 (loop (##sys#slot lst 1)) )
3816 (else (##sys#error-not-a-proper-list lst0 'for-each)) ) ))
3817
3818(define (##sys#map p lst0)
3819 (let loop ((lst lst0))
3820 (cond ((eq? lst '()) lst)
3821 ((pair? lst)
3822 (cons (p (##sys#slot lst 0)) (loop (##sys#slot lst 1))) )
3823 (else (##sys#error-not-a-proper-list lst0 'map)) ) ))
3824
3825(letrec ((mapsafe
3826 (lambda (p lsts loc)
3827 (call-with-current-continuation
3828 (lambda (empty)
3829 (let lp ((lsts lsts))
3830 (if (eq? lsts '())
3831 lsts
3832 (let ((item (##sys#slot lsts 0)))
3833 (cond ((eq? item '()) (empty '()))
3834 ((pair? item)
3835 (cons (p item) (lp (##sys#slot lsts 1))))
3836 (else (##sys#error-not-a-proper-list item loc)))))))))))
3837
3838 (set! scheme#for-each
3839 (lambda (fn lst1 . lsts)
3840 (if (null? lsts)
3841 (##sys#for-each fn lst1)
3842 (let loop ((all (cons lst1 lsts)))
3843 (let* ((first (##sys#slot all 0))
3844 (safe-args (mapsafe (lambda (x) (car x)) all 'for-each))) ; ensure inlining
3845 (when (pair? safe-args)
3846 (apply fn safe-args)
3847 (loop (mapsafe (lambda (x) (cdr x)) all 'for-each))))))))
3848
3849 (set! scheme#map
3850 (lambda (fn lst1 . lsts)
3851 (if (null? lsts)
3852 (##sys#map fn lst1)
3853 (let loop ((all (cons lst1 lsts)))
3854 (let* ((first (##sys#slot all 0))
3855 (safe-args (mapsafe (lambda (x) (car x)) all 'map)))
3856 (if (pair? safe-args)
3857 (cons (apply fn safe-args)
3858 (loop (mapsafe (lambda (x) (cdr x)) all 'map)))
3859 '())))))))
3860
3861
3862;;; dynamic-wind:
3863;
3864; (taken more or less directly from SLIB)
3865;
3866; This implementation is relatively costly: we have to shadow call/cc
3867; with a new version that unwinds suspended thunks, but for this to
3868; happen the return-values of the escaping procedure have to be saved
3869; temporarily in a list. Since call/cc is very efficient under this
3870; implementation, and because allocation of memory that is to be
3871; garbage soon has also quite low overhead, the performance-penalty
3872; might be acceptable (ctak needs about 4 times longer).
3873
3874(define ##sys#dynamic-winds '())
3875
3876(set! scheme#dynamic-wind
3877 (lambda (before thunk after)
3878 (before)
3879 (set! ##sys#dynamic-winds (cons (cons before after) ##sys#dynamic-winds))
3880 (##sys#call-with-values
3881 thunk
3882 (lambda results
3883 (set! ##sys#dynamic-winds (##sys#slot ##sys#dynamic-winds 1))
3884 (after)
3885 (apply ##sys#values results) ) ) ))
3886
3887(define ##sys#dynamic-wind dynamic-wind)
3888
3889(set! scheme#call-with-current-continuation
3890 (lambda (proc)
3891 (let ((winds ##sys#dynamic-winds))
3892 (##sys#call-with-current-continuation
3893 (lambda (cont)
3894 (define (continuation . results)
3895 (unless (eq? ##sys#dynamic-winds winds)
3896 (##sys#dynamic-unwind winds (fx- (length ##sys#dynamic-winds) (length winds))) )
3897 (apply cont results) )
3898 (proc continuation) ))) ))
3899
3900(set! scheme#call/cc call-with-current-continuation)
3901
3902(define (##sys#dynamic-unwind winds n)
3903 (cond [(eq? ##sys#dynamic-winds winds)]
3904 [(fx< n 0)
3905 (##sys#dynamic-unwind (##sys#slot winds 1) (fx+ n 1))
3906 ((##sys#slot (##sys#slot winds 0) 0))
3907 (set! ##sys#dynamic-winds winds) ]
3908 [else
3909 (let ([after (##sys#slot (##sys#slot ##sys#dynamic-winds 0) 1)])
3910 (set! ##sys#dynamic-winds (##sys#slot ##sys#dynamic-winds 1))
3911 (after)
3912 (##sys#dynamic-unwind winds (fx- n 1)) ) ] ) )
3913
3914
3915;;; Ports:
3916
3917(set! chicken.base#port-closed?
3918 (lambda (p)
3919 (##sys#check-port p 'port-closed?)
3920 (eq? (##sys#slot p 8) 0)))
3921
3922;;; Custom ports:
3923
3924;;; Port layout:
3925;
3926; 0: file ptr (special)
3927; 1: direction (fixnum, 1 = input)
3928; 2: class (vector of procedures)
3929; 3: name (string)
3930; 4: row (fixnum)
3931; 5: col (fixnum)
3932; 6: EOF (bool)
3933; 7: type ('stream | 'custom | 'string | 'socket)
3934; 8: closed (fixnum)
3935; 9: data
3936; 10-12: reserved, port class specific
3937; 13: case sensitive? (boolean)
3938; 14: mode ('textual | 'binary)
3939; 15: reserved (encoding)
3940;
3941; Port-class:
3942;
3943; 0: (read-char PORT) -> CHAR | EOF
3944; 1: (peek-char PORT) -> CHAR | EOF
3945; 2: (write-char PORT CHAR)
3946; 3: (write-bytevector PORT BYTEVECTOR START END)
3947; 4: (close PORT DIRECTION)
3948; 5: (flush-output PORT)
3949; 6: (char-ready? PORT) -> BOOL
3950; 7: (read-bytevector! PORT COUNT BYTEVECTOR START) -> COUNT'
3951; 8: (read-line PORT LIMIT) -> STRING | EOF
3952; 9: (read-buffered PORT) -> STRING
3953
3954(define (##sys#make-port i/o class name type)
3955 (let ((port (##core#inline_allocate ("C_a_i_port" 17))))
3956 (##sys#setislot port 1 i/o)
3957 (##sys#setslot port 2 class)
3958 (##sys#setslot port 3 name)
3959 (##sys#setislot port 4 1)
3960 (##sys#setislot port 5 0)
3961 (##sys#setislot port 6 #f)
3962 (##sys#setslot port 7 type)
3963 (##sys#setslot port 8 i/o)
3964 (##sys#setislot port 10 #f)
3965 (##sys#setislot port 13 #t)
3966 (##sys#setislot port 14 'textual) ; default, only used for R7RS port predicates
3967 (##sys#setslot port 15 'utf-8)
3968 port) )
3969
3970;;; Stream ports:
3971; Input port slots:
3972; 10: peek buffer
3973; 12: Static buffer for read-line, allocated on-demand
3974
3975(define ##sys#stream-port-class
3976 (vector (lambda (p) ; read-char
3977 (let loop ()
3978 (let ((peeked (##sys#slot p 10)))
3979 (cond (peeked
3980 (##sys#setislot p 10 #f)
3981 (##sys#decode-char peeked (##sys#slot p 15) 0))
3982 ((eq? 'utf-8 (##sys#slot p 15)) ; fast path
3983 (let ((c (##core#inline "C_read_char" p)))
3984 (if (eq? -1 c)
3985 (let ((err (##sys#update-errno)))
3986 (if (eq? err (foreign-value "EINTR" int))
3987 (##sys#dispatch-interrupt loop)
3988 (##sys#signal-hook/errno
3989 #:file-error err 'read-char
3990 (##sys#string-append "cannot read from port - " strerror)
3991 p)))
3992 c)))
3993 (else (##sys#read-char/encoding
3994 p (##sys#slot p 15)
3995 (lambda (buf start len dec)
3996 (dec buf start len
3997 (lambda (buf start len)
3998 (##core#inline "C_utf_decode" buf start))))))))))
3999 (lambda (p) ; peek-char
4000 (let ((pb (##sys#slot p 10))
4001 (enc (##sys#slot p 15)))
4002 (if pb
4003 (##sys#decode-char pb enc 0)
4004 (##sys#read-char/encoding
4005 p enc
4006 (lambda (buf start len dec)
4007 (let ((pb (##sys#make-bytevector len)))
4008 (##core#inline "C_copy_memory_with_offset" pb buf 0 start len)
4009 (##sys#setslot p 10 pb)
4010 (dec buf start len
4011 (lambda (buf start _)
4012 (##core#inline "C_utf_decode" buf start)))))))))
4013 (lambda (p c) ; write-char
4014 (let ((enc (##sys#slot p 15)))
4015 (if (eq? enc 'utf-8) ;; fast path
4016 (##core#inline "C_display_char" p c)
4017 (let* ((bv (##sys#make-bytevector 4))
4018 (n (##sys#encode-char c bv enc)))
4019 ((##sys#slot (##sys#slot p 2) 3) p bv 0 n))))) ; write-bytevector
4020 (lambda (p bv from to) ; write-bytevector
4021 (##sys#encode-buffer
4022 bv from (fx- to from) (##sys#slot p 15)
4023 (lambda (bv start len)
4024 (##core#inline "C_display_string" p bv start len))))
4025 (lambda (p d) ; close
4026 (##core#inline "C_close_file" p)
4027 (##sys#update-errno) )
4028 (lambda (p) ; flush-output
4029 (##core#inline "C_flush_output" p) )
4030 (lambda (p) ; char-ready?
4031 (##core#inline "C_char_ready_p" p) )
4032 (lambda (p n dest start) ; read-bytevector!
4033 (let ((pb (##sys#slot p 10))
4034 (nc 0))
4035 (when pb
4036 (set! nc (##sys#size pb))
4037 (##core#inline "C_copy_memory_with_offset" dest pb start 0 nc)
4038 (set! start (fx+ start nc))
4039 (set! n (fx- n nc))
4040 (##sys#setislot p 10 #f))
4041 ;;XXX "n" below always true?
4042 (let loop ((rem (or n (fx- (##sys#size dest) start)))
4043 (act nc)
4044 (start start))
4045 (let ((len (##core#inline "fast_read_string_from_file" dest p rem start)))
4046 (cond ((eof-object? len) ; EOF returns 0 bytes read
4047 act)
4048 ((fx< len 0)
4049 (let ((err (##sys#update-errno)))
4050 (if (eq? err (foreign-value "EINTR" int))
4051 (##sys#dispatch-interrupt
4052 (lambda () (loop rem act start)))
4053 (##sys#signal-hook/errno
4054 #:file-error err 'read-bytevector!
4055 (##sys#string-append "cannot read from port - " strerror)
4056 p n dest start))))
4057 ((fx< len rem)
4058 (loop (fx- rem len) (fx+ act len) (fx+ start len)))
4059 (else (fx+ act len) ) ) ))))
4060 (lambda (p rlimit) ; read-line
4061 (when rlimit (##sys#check-fixnum rlimit 'read-line))
4062 (let ((sblen read-line-buffer-initial-size))
4063 (unless (##sys#slot p 12)
4064 (##sys#setslot p 12 (##sys#make-bytevector sblen)))
4065 (let loop ([len sblen]
4066 [limit (or rlimit maximal-string-length)]
4067 [buffer (##sys#slot p 12)]
4068 [result ""]
4069 [f #f])
4070 (let* ((nlimit (fxmin limit len))
4071 (n (##core#inline "fast_read_line_from_file" buffer
4072 p nlimit)))
4073 (cond ((eof-object? n) (if f result #!eof))
4074 ((not n)
4075 (let ((prev (##sys#buffer->string/encoding buffer 0 nlimit
4076 (##sys#slot p 15))))
4077 (if (fx< limit len)
4078 (##sys#string-append result prev)
4079 (loop (fx* len 2)
4080 (fx- limit len)
4081 (##sys#make-bytevector (fx* len 2))
4082 (##sys#string-append result prev)
4083 #t)) ) )
4084 ((fx< n 0)
4085 (let ((err (##sys#update-errno)))
4086 (if (eq? err (foreign-value "EINTR" int))
4087 (let ((n (fx- (fxneg n) 1)))
4088 (##sys#dispatch-interrupt
4089 (lambda ()
4090 (loop len limit buffer
4091 (##sys#string-append
4092 result
4093 (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15)))
4094 #t))))
4095 (##sys#signal-hook/errno
4096 #:file-error err 'read-line
4097 (##sys#string-append "cannot read from port - " strerror)
4098 p rlimit))))
4099 (f (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4100 (##sys#string-append result
4101 (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15))))
4102 (else
4103 (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4104 (##sys#buffer->string/encoding buffer 0 n (##sys#slot p 15))))))))
4105 #f ; read-buffered
4106 ) )
4107
4108(define ##sys#open-file-port (##core#primitive "C_open_file_port"))
4109
4110(define ##sys#standard-input (##sys#make-port 1 ##sys#stream-port-class "(stdin)" 'stream))
4111(define ##sys#standard-output (##sys#make-port 2 ##sys#stream-port-class "(stdout)" 'stream))
4112(define ##sys#standard-error (##sys#make-port 2 ##sys#stream-port-class "(stderr)" 'stream))
4113
4114(##sys#open-file-port ##sys#standard-input 0 #f)
4115(##sys#open-file-port ##sys#standard-output 1 #f)
4116(##sys#open-file-port ##sys#standard-error 2 #f)
4117
4118(define (##sys#check-input-port x open . loc)
4119 (if (pair? loc)
4120 (##core#inline "C_i_check_port_2" x 1 open (car loc))
4121 (##core#inline "C_i_check_port" x 1 open)))
4122
4123(define (##sys#check-output-port x open . loc)
4124 (if (pair? loc)
4125 (##core#inline "C_i_check_port_2" x 2 open (car loc))
4126 (##core#inline "C_i_check_port" x 2 open)))
4127
4128(define (##sys#check-port x . loc)
4129 (if (pair? loc)
4130 (##core#inline "C_i_check_port_2" x 0 #f (car loc))
4131 (##core#inline "C_i_check_port" x 0 #f) ) )
4132
4133(define (##sys#check-open-port x . loc)
4134 (if (pair? loc)
4135 (##core#inline "C_i_check_port_2" x 0 #t (car loc))
4136 (##core#inline "C_i_check_port" x 0 #t) ) )
4137
4138(set! scheme#current-input-port
4139 (lambda args
4140 (if (null? args)
4141 ##sys#standard-input
4142 (let ((p (car args)))
4143 (##sys#check-port p 'current-input-port)
4144 (let-optionals (cdr args) ((convert? #t) (set? #t))
4145 (when set? (set! ##sys#standard-input p)))
4146 p) ) ))
4147
4148(set! scheme#current-output-port
4149 (lambda args
4150 (if (null? args)
4151 ##sys#standard-output
4152 (let ((p (car args)))
4153 (##sys#check-port p 'current-output-port)
4154 (let-optionals (cdr args) ((convert? #t) (set? #t))
4155 (when set? (set! ##sys#standard-output p)))
4156 p) ) ))
4157
4158(set! chicken.base#current-error-port
4159 (lambda args
4160 (if (null? args)
4161 ##sys#standard-error
4162 (let ((p (car args)))
4163 (##sys#check-port p 'current-error-port)
4164 (let-optionals (cdr args) ((convert? #t) (set? #t))
4165 (when set? (set! ##sys#standard-error p)))
4166 p))))
4167
4168(define (##sys#tty-port? port)
4169 (and (not (zero? (##sys#peek-unsigned-integer port 0)))
4170 (##core#inline "C_tty_portp" port) ) )
4171
4172(define (##sys#port-data port) (##sys#slot port 9))
4173(define (##sys#set-port-data! port data) (##sys#setslot port 9 data))
4174
4175(define ##sys#default-file-encoding)
4176
4177(let ()
4178 (define (open name inp modes loc)
4179 (##sys#check-string name loc)
4180 (let ((fmode (if inp "r" "w"))
4181 (bmode "")
4182 (enc (##sys#default-file-encoding)))
4183 (do ((modes modes (##sys#slot modes 1)))
4184 ((null? modes))
4185 (let ((o (##sys#slot modes 0)))
4186 (case o
4187 ((#:binary binary)
4188 (set! bmode "b")
4189 (set! enc 'binary))
4190 ((#:text text) (set! bmode ""))
4191 ((#:utf-8 utf-8)
4192 (set! enc 'utf-8))
4193 ((#:latin-1 latin-1 #:iso-8859-1 iso-8859-1)
4194 (set! enc 'latin-1))
4195 ((#:unix #:nl unix nl)
4196 (set! bmode "b"))
4197 ((#:crnl crnl)
4198 (set! bmode ""))
4199 ((#:append append)
4200 (if inp
4201 (##sys#error loc "cannot use append mode with input file")
4202 (set! fmode "a") ) )
4203 (else (##sys#error loc "invalid file option" o)) ) ) )
4204 (let ((port (##sys#make-port (if inp 1 2) ##sys#stream-port-class name 'stream)))
4205 (##sys#setslot port 15 enc)
4206 (unless (##sys#open-file-port port name (##sys#string-append fmode bmode))
4207 (##sys#signal-hook/errno #:file-error (##sys#update-errno) loc
4208 (##sys#string-append "cannot open file - " strerror)
4209 name))
4210 port) ) )
4211
4212 (define (close port inp loc)
4213 (##sys#check-port port loc)
4214 ; repeated closing is ignored
4215 (let ((direction (if inp 1 2)))
4216 (when (##core#inline "C_port_openp" port direction)
4217 (##sys#setislot port 8 (fxand (##sys#slot port 8) (fxnot direction)))
4218 ((##sys#slot (##sys#slot port 2) 4) port direction))))
4219
4220 (set! scheme#open-input-file (lambda (name . mode) (open name #t mode 'open-input-file)))
4221 (set! scheme#open-output-file (lambda (name . mode) (open name #f mode 'open-output-file)))
4222 (set! scheme#close-input-port (lambda (port) (close port #t 'close-input-port)))
4223 (set! scheme#close-output-port (lambda (port) (close port #f 'close-output-port))))
4224
4225(set! scheme#call-with-input-file
4226 (let ((open-input-file open-input-file)
4227 (close-input-port close-input-port) )
4228 (lambda (name p . mode)
4229 (let ((f (apply open-input-file name mode)))
4230 (##sys#call-with-values
4231 (lambda () (p f))
4232 (lambda results
4233 (close-input-port f)
4234 (apply ##sys#values results) ) ) ) ) ) )
4235
4236(set! scheme#call-with-output-file
4237 (let ((open-output-file open-output-file)
4238 (close-output-port close-output-port) )
4239 (lambda (name p . mode)
4240 (let ((f (apply open-output-file name mode)))
4241 (##sys#call-with-values
4242 (lambda () (p f))
4243 (lambda results
4244 (close-output-port f)
4245 (apply ##sys#values results) ) ) ) ) ) )
4246
4247(set! scheme#with-input-from-file
4248 (let ((open-input-file open-input-file)
4249 (close-input-port close-input-port) )
4250 (lambda (str thunk . mode)
4251 (let ((file (apply open-input-file str mode)))
4252 (fluid-let ((##sys#standard-input file))
4253 (##sys#call-with-values thunk
4254 (lambda results
4255 (close-input-port file)
4256 (apply ##sys#values results) ) ) ) ) ) ) )
4257
4258(set! scheme#with-output-to-file
4259 (let ((open-output-file open-output-file)
4260 (close-output-port close-output-port) )
4261 (lambda (str thunk . mode)
4262 (let ((file (apply open-output-file str mode)))
4263 (fluid-let ((##sys#standard-output file))
4264 (##sys#call-with-values thunk
4265 (lambda results
4266 (close-output-port file)
4267 (apply ##sys#values results) ) ) ) ) ) ) )
4268
4269(define (##sys#file-exists? name file? dir? loc)
4270 (case (##core#inline "C_i_file_exists_p" (##sys#make-c-string name loc) file? dir?)
4271 ((#f) #f)
4272 ((#t) #t)
4273 (else
4274 (##sys#signal-hook
4275 #:file-error loc "system error while trying to access file"
4276 name))))
4277
4278(define (##sys#flush-output port)
4279 ((##sys#slot (##sys#slot port 2) 5) port) ; flush-output
4280 (##core#undefined) )
4281
4282(set! chicken.base#flush-output
4283 (lambda (#!optional (port ##sys#standard-output))
4284 (##sys#check-output-port port #t 'flush-output)
4285 (##sys#flush-output port)))
4286
4287(define (##sys#port-line port)
4288 (and (##core#inline "C_input_portp" port)
4289 (##sys#slot port 4) ) )
4290
4291;;; Decorate procedure with arbitrary data
4292;
4293; warning: may modify proc, if it already has a suitable decoration!
4294
4295(define (##sys#decorate-lambda proc pred decorator)
4296 (let ((len (##sys#size proc)))
4297 (let loop ((i (fx- len 1)))
4298 (cond ((zero? i)
4299 (let ((p2 (make-vector (fx+ len 1))))
4300 (do ((i 1 (fx+ i 1)))
4301 ((fx>= i len)
4302 (##core#inline "C_vector_to_closure" p2)
4303 (##core#inline "C_copy_pointer" proc p2)
4304 (decorator p2 i) )
4305 (##sys#setslot p2 i (##sys#slot proc i)) ) ) )
4306 (else
4307 (let ((x (##sys#slot proc i)))
4308 (if (pred x)
4309 (decorator proc i)
4310 (loop (fx- i 1)) ) ) ) ) ) ) )
4311
4312(define (##sys#lambda-decoration proc pred)
4313 (let loop ((i (fx- (##sys#size proc) 1)))
4314 (and (fx> i 0)
4315 (let ((x (##sys#slot proc i)))
4316 (if (pred x)
4317 x
4318 (loop (fx- i 1)) ) ) ) ) )
4319
4320
4321;;; Create lambda-info object
4322
4323(define (##sys#make-lambda-info str)
4324 (let* ((bv (##sys#slot str 0))
4325 (sz (fx- (##sys#size bv) 1))
4326 (info (##sys#make-bytevector sz)))
4327 (##core#inline "C_copy_memory" info bv sz)
4328 (##core#inline "C_bytevector_to_lambdainfo" info)
4329 info) )
4330
4331
4332;;; Function debug info:
4333
4334(define (##sys#lambda-info? x)
4335 (and (not (##sys#immediate? x)) (##core#inline "C_lambdainfop" x)))
4336
4337(define (##sys#lambda-info proc)
4338 (##sys#lambda-decoration proc ##sys#lambda-info?))
4339
4340(define (##sys#lambda-info->string info)
4341 (let* ((sz (##sys#size info))
4342 (bv (##sys#make-bytevector (fx+ sz 1))) )
4343 (##core#inline "C_copy_memory" bv info sz)
4344 (##core#inline_allocate ("C_a_ustring" 5) bv
4345 (##core#inline "C_utf_length" bv))))
4346
4347(set! chicken.base#procedure-information
4348 (lambda (x)
4349 (##sys#check-closure x 'procedure-information)
4350 (and-let* ((info (##sys#lambda-info x)))
4351 (##sys#read (scheme#open-input-string (##sys#lambda-info->string info)) #f) ) ) )
4352
4353
4354;;; SRFI-17
4355
4356(define setter-tag (vector 'setter))
4357
4358(define-inline (setter? x)
4359 (and (pair? x) (eq? setter-tag (##sys#slot x 0))) )
4360
4361(set! chicken.base#setter
4362 (##sys#decorate-lambda
4363 (lambda (proc)
4364 (or (and-let* (((procedure? proc))
4365 (d (##sys#lambda-decoration proc setter?)) )
4366 (##sys#slot d 1) )
4367 (##sys#error 'setter "no setter defined" proc) ) )
4368 setter?
4369 (lambda (proc i)
4370 (##sys#setslot
4371 proc i
4372 (cons
4373 setter-tag
4374 (lambda (get set)
4375 (if (procedure? get)
4376 (let ((get2 (##sys#decorate-lambda
4377 get
4378 setter?
4379 (lambda (proc i) (##sys#setslot proc i (cons setter-tag set)) proc))))
4380 (if (eq? get get2)
4381 get
4382 (##sys#become! (list (cons get get2))) ) )
4383 (error "can not set setter of non-procedure" get) ) ) ) )
4384 proc) ) )
4385
4386(define ##sys#setter setter)
4387
4388(set! chicken.base#getter-with-setter
4389 (lambda (get set #!optional info)
4390 (##sys#check-closure get 'getter-with-setter)
4391 (##sys#check-closure set 'getter-with-setter)
4392 (let ((getdec (cond (info
4393 (##sys#check-string info 'getter-with-setter)
4394 (##sys#make-lambda-info info))
4395 (else (##sys#lambda-info get))))
4396 (p1 (##sys#decorate-lambda
4397 (##sys#copy-closure get)
4398 setter?
4399 (lambda (proc i)
4400 (##sys#setslot proc i (cons setter-tag set))
4401 proc))))
4402 (if getdec
4403 (##sys#decorate-lambda
4404 p1
4405 ##sys#lambda-info?
4406 (lambda (p i)
4407 (##sys#setslot p i getdec)
4408 p))
4409 p1))))
4410
4411(set! scheme#car (getter-with-setter scheme#car set-car!))
4412(set! scheme#cdr (getter-with-setter scheme#cdr set-cdr!))
4413(set! scheme#caar (getter-with-setter scheme#caar (lambda (x y) (set-car! (car x) y))))
4414(set! scheme#cadr (getter-with-setter scheme#cadr (lambda (x y) (set-car! (cdr x) y))))
4415(set! scheme#cdar (getter-with-setter scheme#cdar (lambda (x y) (set-cdr! (car x) y))))
4416(set! scheme#cddr (getter-with-setter scheme#cddr (lambda (x y) (set-cdr! (cdr x) y))))
4417(set! scheme#caaar (getter-with-setter scheme#caaar (lambda (x y) (set-car! (caar x) y))))
4418(set! scheme#caadr (getter-with-setter scheme#caadr (lambda (x y) (set-car! (cadr x) y))))
4419(set! scheme#cadar (getter-with-setter scheme#cadar (lambda (x y) (set-car! (cdar x) y))))
4420(set! scheme#caddr (getter-with-setter scheme#caddr (lambda (x y) (set-car! (cddr x) y))))
4421(set! scheme#cdaar (getter-with-setter scheme#cdaar (lambda (x y) (set-cdr! (caar x) y))))
4422(set! scheme#cdadr (getter-with-setter scheme#cdadr (lambda (x y) (set-cdr! (cadr x) y))))
4423(set! scheme#cddar (getter-with-setter scheme#cddar (lambda (x y) (set-cdr! (cdar x) y))))
4424(set! scheme#cdddr (getter-with-setter scheme#cdddr (lambda (x y) (set-cdr! (cddr x) y))))
4425(set! scheme#string-ref (getter-with-setter scheme#string-ref string-set!))
4426(set! scheme#vector-ref (getter-with-setter scheme#vector-ref vector-set!))
4427
4428(set! scheme#list-ref
4429 (getter-with-setter
4430 scheme#list-ref
4431 (lambda (x i y) (set-car! (list-tail x i) y))))
4432
4433(set! chicken.bytevector#bytevector-u8-ref
4434 (getter-with-setter chicken.bytevector#bytevector-u8-ref
4435 chicken.bytevector#bytevector-u8-set!
4436 "(chicken.bytevector#bytevector-u8-ref v i)"))
4437
4438
4439;;; Parameters:
4440
4441(define ##sys#default-parameter-vector (##sys#make-vector default-parameter-vector-size))
4442(define ##sys#current-parameter-vector '#())
4443
4444(set! scheme#make-parameter
4445 (let ((count 0))
4446 (lambda (init #!optional (guard (lambda (x) x)))
4447 (let* ((val (guard init))
4448 (i count)
4449 (assign (lambda (val n convert? set?)
4450 (when (fx>= i n)
4451 (set! ##sys#current-parameter-vector
4452 (##sys#vector-resize
4453 ##sys#current-parameter-vector
4454 (fx+ i 1)
4455 ##sys#snafu) ) )
4456 (let ((val (if convert? (guard val) val)))
4457 (when set?
4458 (##sys#setslot ##sys#current-parameter-vector i val))
4459 val))))
4460
4461 (set! count (fx+ count 1))
4462 (when (fx>= i (##sys#size ##sys#default-parameter-vector))
4463 (set! ##sys#default-parameter-vector
4464 (##sys#vector-resize
4465 ##sys#default-parameter-vector
4466 (fx+ i 1)
4467 (##core#undefined)) ) )
4468 (##sys#setslot ##sys#default-parameter-vector i val)
4469 (getter-with-setter
4470 (lambda args
4471 (let ((n (##sys#size ##sys#current-parameter-vector)))
4472 (cond ((pair? args)
4473 (let-optionals (cdr args) ((convert? #t)
4474 (set? #t))
4475 (assign (car args) n convert? set?)))
4476 ((fx>= i n)
4477 (##sys#slot ##sys#default-parameter-vector i) )
4478 (else
4479 (let ((val (##sys#slot ##sys#current-parameter-vector i)))
4480 (if (eq? val ##sys#snafu)
4481 (##sys#slot ##sys#default-parameter-vector i)
4482 val) ) ) ) ) )
4483 (lambda (val)
4484 (let ((n (##sys#size ##sys#current-parameter-vector)))
4485 (assign val n #f #t))))))))
4486
4487
4488;;; Input:
4489
4490(set! scheme#char-ready?
4491 (lambda (#!optional (port ##sys#standard-input))
4492 (##sys#check-input-port port #t 'char-ready?)
4493 ((##sys#slot (##sys#slot port 2) 6) port) )) ; char-ready?
4494
4495(set! scheme#read-char
4496 (lambda (#!optional (port ##sys#standard-input))
4497 (##sys#check-input-port port #t 'read-char)
4498 (##sys#read-char-0 port) ))
4499
4500(define (##sys#read-char-0 p)
4501 (let ([c (if (##sys#slot p 6)
4502 (begin
4503 (##sys#setislot p 6 #f)
4504 #!eof)
4505 ((##sys#slot (##sys#slot p 2) 0) p) ) ] ) ; read-char
4506 (cond [(eq? c #\newline)
4507 (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
4508 (##sys#setislot p 5 0) ]
4509 [(not (##core#inline "C_eofp" c))
4510 (##sys#setislot p 5 (fx+ (##sys#slot p 5) 1)) ] )
4511 c) )
4512
4513(define (##sys#read-char/port port)
4514 (##sys#check-input-port port #t 'read-char)
4515 (##sys#read-char-0 port) )
4516
4517(define (##sys#peek-char-0 p)
4518 (if (##sys#slot p 6)
4519 #!eof
4520 (let ((c ((##sys#slot (##sys#slot p 2) 1) p))) ; peek-char
4521 (when (##core#inline "C_eofp" c)
4522 (##sys#setislot p 6 #t) )
4523 c) ) )
4524
4525(set! scheme#peek-char
4526 (lambda (#!optional (port ##sys#standard-input))
4527 (##sys#check-input-port port #t 'peek-char)
4528 (##sys#peek-char-0 port) ))
4529
4530(set! scheme#read
4531 (lambda (#!optional (port ##sys#standard-input))
4532 (##sys#check-input-port port #t 'read)
4533 (##sys#read port ##sys#default-read-info-hook) ))
4534
4535(define ##sys#default-read-info-hook #f)
4536(define ##sys#read-error-with-line-number #f)
4537(define (##sys#read-prompt-hook) #f) ; just here so that srfi-18 works without eval
4538(define (##sys#infix-list-hook lst) lst)
4539
4540(set! ##sys#default-file-encoding (make-parameter 'utf-8))
4541
4542(define (##sys#sharp-number-hook port n)
4543 (##sys#read-error port "invalid `#...' read syntax" n) )
4544
4545(set! chicken.base#case-sensitive (make-parameter #t))
4546(set! chicken.base#parentheses-synonyms (make-parameter #t))
4547(set! chicken.base#symbol-escape (make-parameter #t))
4548
4549(set! chicken.base#keyword-style
4550 (make-parameter #:suffix (lambda (x) (when x (##sys#check-keyword x 'keyword-style)) x)))
4551
4552(define ##sys#current-read-table (make-parameter (##sys#make-structure 'read-table #f #f #f)))
4553
4554(define ##sys#read-warning
4555 (let ([string-append string-append])
4556 (lambda (port msg . args)
4557 (apply
4558 ##sys#warn
4559 (let ((ln (##sys#port-line port)))
4560 (if (and ##sys#read-error-with-line-number ln)
4561 (string-append "(line " (##sys#number->string ln) ") " msg)
4562 msg) )
4563 args) ) ) )
4564
4565(define ##sys#read-error
4566 (let ([string-append string-append] )
4567 (lambda (port msg . args)
4568 (apply
4569 ##sys#signal-hook
4570 #:syntax-error
4571 (let ((ln (##sys#port-line port)))
4572 (if (and ##sys#read-error-with-line-number ln)
4573 (string-append "(line " (##sys#number->string ln) ") " msg)
4574 msg) )
4575 args) ) ) )
4576
4577(define ##sys#read
4578 (let ((string-append string-append)
4579 (keyword-style keyword-style)
4580 (parentheses-synonyms parentheses-synonyms)
4581 (case-sensitive case-sensitive)
4582 (symbol-escape symbol-escape)
4583 (current-read-table ##sys#current-read-table))
4584 (lambda (port infohandler)
4585 (let ((csp (and (case-sensitive) (##sys#slot port 13)))
4586 (ksp (keyword-style))
4587 (psp (parentheses-synonyms))
4588 (sep (symbol-escape))
4589 (crt (current-read-table))
4590 (warn #f)
4591 (shared '())
4592 ; set below - needs more state to make a decision
4593 (terminating-characters '(#\, #\; #\( #\) #\' #\" #\[ #\] #\{ #\}))
4594 (reserved-characters #f) )
4595
4596 (define (container c)
4597 (##sys#read-error port "unexpected list terminator" c) )
4598
4599 (define (info class data val)
4600 (if infohandler
4601 (infohandler class data val)
4602 data) )
4603
4604 (define (skip-to-eol)
4605 (let skip ((c (##sys#read-char-0 port)))
4606 (if (and (not (##core#inline "C_eofp" c)) (not (eq? #\newline c)))
4607 (skip (##sys#read-char-0 port)) ) ) )
4608
4609 (define (reserved-character c)
4610 (##sys#read-char-0 port)
4611 (##sys#read-error port "reserved character" c) )
4612
4613 (define (read-unreserved-char-0 port)
4614 (let ((c (##sys#read-char-0 port)))
4615 (if (memq c reserved-characters)
4616 (reserved-character c)
4617 c) ) )
4618
4619 (define (register-shared! n thunk)
4620 (set! shared (cons (cons n thunk) shared)))
4621
4622 (define (unthunk o fail)
4623 (let ((v (o)))
4624 (cond ((not (procedure? v)) v)
4625 ((eq? v o)
4626 (fail "self-referential datum"))
4627 (else
4628 (unthunk v fail)))))
4629
4630 ;; Fills holes in `o` destructively.
4631 (define (unthunkify! o fail)
4632 (let loop! ((o o))
4633 (cond ((pair? o)
4634 (if (not (procedure? (car o)))
4635 (loop! (car o))
4636 (set-car! o (unthunk (car o) fail)))
4637 (if (not (procedure? (cdr o)))
4638 (loop! (cdr o))
4639 (set-cdr! o (unthunk (cdr o) fail))))
4640 ((vector? o)
4641 (let ((len (##sys#size o)))
4642 (do ((i 0 (fx+ i 1)))
4643 ((eq? i len))
4644 (let ((v (##sys#slot o i)))
4645 (if (not (procedure? v))
4646 (loop! v)
4647 (##sys#setslot o i (unthunk v fail))))))))))
4648
4649 (define (readrec)
4650
4651 (define (r-spaces)
4652 (let loop ([c (##sys#peek-char-0 port)])
4653 (cond ((##core#inline "C_eofp" c))
4654 ((eq? #\; c)
4655 (skip-to-eol)
4656 (loop (##sys#peek-char-0 port)) )
4657 ((char-whitespace? c)
4658 (##sys#read-char-0 port)
4659 (loop (##sys#peek-char-0 port)) ) ) ) )
4660
4661 (define (r-usequence u n base)
4662 (let loop ((seq '()) (n n))
4663 (if (eq? n 0)
4664 (let* ((str (##sys#reverse-list->string seq))
4665 (n (string->number str base)))
4666 (or n
4667 (##sys#read-error
4668 port
4669 (string-append
4670 "invalid escape-sequence '\\" u str "\'")) ) )
4671 (let ((x (##sys#read-char-0 port)))
4672 (if (or (eof-object? x) (char=? #\" x))
4673 (##sys#read-error port "unterminated string constant")
4674 (loop (cons x seq) (fx- n 1)) ) ) ) ) )
4675
4676 (define (r-xsequence delim)
4677 (define (parse seq)
4678 (let* ((str (##sys#reverse-list->string seq))
4679 (n (string->number str 16)))
4680 (or n
4681 (##sys#read-error port
4682 (string-append "invalid escape-sequence '\\x"
4683 str ";\'")))))
4684 (define (complain)
4685 (set! warn "unterminated hexadecimal escape sequence"))
4686 (define (abort)
4687 (##sys#read-error port "unterminated hexadecimal escape sequence") )
4688 (let loop ((seq '()))
4689 (let ((x (##sys#peek-char-0 port)))
4690 (cond ((eof-object? x) (abort))
4691 ((eq? delim x)
4692 (let ((n (parse seq)))
4693 (if (fx> n #x1ffff)
4694 (abort)
4695 (begin (complain) n))))
4696 ((eq? #\; x)
4697 (##sys#read-char-0 port)
4698 (parse seq))
4699 ((or (and (char>=? x #\0) (char<=? x #\9))
4700 (and (char>=? x #\a) (char<=? x #\f))
4701 (and (char>=? x #\A) (char<=? x #\F)))
4702 (loop (cons (##sys#read-char-0 port) seq)))
4703 (else
4704 (let ((n (parse seq)))
4705 (if (fx> n #x1ffff)
4706 (abort)
4707 (begin (complain) n))))))))
4708
4709 (define (r-string term)
4710 (let loop ((c (##sys#read-char-0 port)) (lst '()))
4711 (cond ((##core#inline "C_eofp" c)
4712 (##sys#read-error port "unterminated string") )
4713 ((eq? #\\ c)
4714 (set! c (##sys#read-char-0 port))
4715 (case c
4716 ((#\t) (loop (##sys#read-char-0 port) (cons #\tab lst)))
4717 ((#\r) (loop (##sys#read-char-0 port) (cons #\return lst)))
4718 ((#\b) (loop (##sys#read-char-0 port) (cons #\backspace lst)))
4719 ((#\n) (loop (##sys#read-char-0 port) (cons #\newline lst)))
4720 ((#\a) (loop (##sys#read-char-0 port) (cons (integer->char 7) lst)))
4721 ((#\v) (loop (##sys#read-char-0 port) (cons (integer->char 11) lst)))
4722 ((#\f) (loop (##sys#read-char-0 port) (cons (integer->char 12) lst)))
4723 ((#\x)
4724 (let ((ch (integer->char (r-xsequence term))))
4725 (loop (##sys#read-char-0 port) (cons ch lst)) ) )
4726 ((#\u)
4727 (let ((n (r-usequence "u" 4 16)))
4728 (loop (##sys#read-char-0 port)
4729 (cons (integer->char n) lst)) ) )
4730 ((#\U)
4731 (let ((n (r-usequence "U" 8 16)))
4732 (loop (##sys#read-char-0 port)
4733 (cons (integer->char n) lst)) ))
4734 ((#\\ #\' #\" #\|)
4735 (loop (##sys#read-char-0 port) (cons c lst)))
4736 ((#\newline #\return #\space #\tab)
4737 ;; Read "escaped" <intraline ws>* <nl> <intraline ws>*
4738 (let eat-ws ((c c) (nl? #f))
4739 (case c
4740 ((#\space #\tab)
4741 (eat-ws (##sys#read-char-0 port) nl?))
4742 ((#\return)
4743 (if nl?
4744 (loop c lst)
4745 (let ((nc (##sys#read-char-0 port)))
4746 (if (eq? nc #\newline) ; collapse \r\n
4747 (eat-ws (##sys#read-char-0 port) #t)
4748 (eat-ws nc #t)))))
4749 ((#\newline)
4750 (if nl?
4751 (loop c lst)
4752 (eat-ws (##sys#read-char-0 port) #t)))
4753 (else
4754 (unless nl?
4755 (##sys#read-warning
4756 port
4757 "escaped whitespace, but no newline - collapsing anyway"))
4758 (loop c lst)))))
4759 (else
4760 (cond ((##core#inline "C_eofp" c)
4761 (##sys#read-error port "unterminated string"))
4762 ((and (char-numeric? c)
4763 (char>=? c #\0)
4764 (char<=? c #\7))
4765 (let ((ch (integer->char
4766 (fx+ (fx* (fx- (char->integer c) 48) 64)
4767 (r-usequence "" 2 8)))))
4768 (loop (##sys#read-char-0 port) (cons ch lst)) ))
4769 (else
4770 (##sys#read-warning
4771 port
4772 "undefined escape sequence in string - probably forgot backslash"
4773 c)
4774 (loop (##sys#read-char-0 port) (cons c lst))) ) )))
4775 ((eq? term c) (##sys#reverse-list->string lst))
4776 (else (loop (##sys#read-char-0 port) (cons c lst))) ) ))
4777
4778 (define (r-list start end)
4779 (if (eq? (##sys#read-char-0 port) start)
4780 (let ((first #f)
4781 (ln0 #f)
4782 (outer-container container) )
4783 (define (starting-line msg)
4784 (if (and ln0 ##sys#read-error-with-line-number)
4785 (string-append
4786 msg ", starting in line "
4787 (##sys#number->string ln0))
4788 msg))
4789 (##sys#call-with-current-continuation
4790 (lambda (return)
4791 (set! container
4792 (lambda (c)
4793 (if (eq? c end)
4794 (return #f)
4795 (##sys#read-error
4796 port
4797 (starting-line "list-terminator mismatch")
4798 c end) ) ) )
4799 (let loop ([last '()])
4800 (r-spaces)
4801 (unless first (set! ln0 (##sys#port-line port)))
4802 (let ([c (##sys#peek-char-0 port)])
4803 (cond ((##core#inline "C_eofp" c)
4804 (##sys#read-error
4805 port
4806 (starting-line "unterminated list") ) )
4807 ((eq? c end)
4808 (##sys#read-char-0 port) )
4809 ((eq? c #\.)
4810 (##sys#read-char-0 port)
4811 (let ((c2 (##sys#peek-char-0 port)))
4812 (cond ((or (char-whitespace? c2)
4813 (eq? c2 #\()
4814 (eq? c2 #\))
4815 (eq? c2 #\")
4816 (eq? c2 #\;) )
4817 (unless (pair? last)
4818 (##sys#read-error port "invalid use of `.'") )
4819 (r-spaces)
4820 (##sys#setslot last 1 (readrec))
4821 (r-spaces)
4822 (unless (eq? (##sys#read-char-0 port) end)
4823 (##sys#read-error
4824 port
4825 (starting-line "missing list terminator")
4826 end)))
4827 (else
4828 (r-xtoken
4829 (lambda (tok kw)
4830 (let* ((tok (##sys#string-append "." tok))
4831 (val
4832 (cond ((and (string=? tok ".:")
4833 (eq? ksp #:suffix))
4834 ;; Edge case: r-xtoken sees
4835 ;; a bare ":" and sets kw to #f
4836 (build-keyword "."))
4837 (kw (build-keyword tok))
4838 ((and (char-numeric? c2)
4839 (##sys#string->number tok)))
4840 (else (build-symbol tok))))
4841 (node (cons val '())))
4842 (if first
4843 (##sys#setslot last 1 node)
4844 (set! first node) )
4845 (loop node))))))))
4846 (else
4847 (let ([node (cons (readrec) '())])
4848 (if first
4849 (##sys#setslot last 1 node)
4850 (set! first node) )
4851 (loop node) ) ) ) ) ) ) )
4852 (set! container outer-container)
4853 (if first
4854 (info 'list-info (##sys#infix-list-hook first) ln0)
4855 '() ) )
4856 (##sys#read-error port "missing token" start) ) )
4857
4858 (define (r-vector)
4859 (let ((lst (r-list #\( #\))))
4860 (if (list? lst)
4861 (##sys#list->vector lst)
4862 (##sys#read-error port "invalid vector syntax" lst) ) ) )
4863
4864 (define (r-number radix exactness)
4865 (r-xtoken
4866 (lambda (tok kw)
4867 (cond (kw
4868 (let ((s (build-keyword tok)))
4869 (info 'symbol-info s (##sys#port-line port)) ))
4870 ((string=? tok ".")
4871 (##sys#read-error port "invalid use of `.'"))
4872 ((and (fx> (string-length tok) 0) (char=? (string-ref tok 0) #\#))
4873 (##sys#read-error port "unexpected prefix in number syntax" tok))
4874 ((##sys#string->number tok (or radix 10) exactness))
4875 (radix (##sys#read-error port "illegal number syntax" tok))
4876 (else (build-symbol tok)) ) ) ))
4877
4878 (define (r-number-with-exactness radix)
4879 (cond [(eq? #\# (##sys#peek-char-0 port))
4880 (##sys#read-char-0 port)
4881 (let ([c2 (##sys#read-char-0 port)])
4882 (cond [(eof-object? c2)
4883 (##sys#read-error port "unexpected end of numeric literal")]
4884 [(char=? c2 #\i) (r-number radix 'i)]
4885 [(char=? c2 #\e) (r-number radix 'e)]
4886 [else
4887 (##sys#read-error
4888 port
4889 "illegal number syntax - invalid exactness prefix" c2)] ) ) ]
4890 [else (r-number radix #f)] ) )
4891
4892 (define (r-number-with-radix exactness)
4893 (cond [(eq? #\# (##sys#peek-char-0 port))
4894 (##sys#read-char-0 port)
4895 (let ([c2 (##sys#read-char-0 port)])
4896 (cond [(eof-object? c2) (##sys#read-error port "unexpected end of numeric literal")]
4897 [(char=? c2 #\x) (r-number 16 exactness)]
4898 [(char=? c2 #\d) (r-number 10 exactness)]
4899 [(char=? c2 #\o) (r-number 8 exactness)]
4900 [(char=? c2 #\b) (r-number 2 exactness)]
4901 [else (##sys#read-error port "illegal number syntax - invalid radix" c2)] ) ) ]
4902 [else (r-number 10 exactness)] ) )
4903
4904 (define (r-token)
4905 (let loop ((c (##sys#peek-char-0 port)) (lst '()))
4906 (cond ((or (eof-object? c)
4907 (char-whitespace? c)
4908 (memq c terminating-characters) )
4909 (##sys#reverse-list->string lst) )
4910 ((char=? c #\x00)
4911 (##sys#read-error port "attempt to read expression from something that looks like binary data"))
4912 (else
4913 (read-unreserved-char-0 port)
4914 (loop (##sys#peek-char-0 port)
4915 (cons (if csp c (char-foldcase c)) lst) ) ) ) ) )
4916
4917 (define (r-digits)
4918 (let loop ((c (##sys#peek-char-0 port)) (lst '()))
4919 (cond ((or (eof-object? c) (not (char-numeric? c)))
4920 (##sys#reverse-list->string lst) )
4921 (else
4922 (##sys#read-char-0 port)
4923 (loop (##sys#peek-char-0 port) (cons c lst)) ) ) ) )
4924
4925 (define (r-symbol)
4926 (r-xtoken
4927 (lambda (str kw)
4928 (let ((s (if kw (build-keyword str) (build-symbol str))))
4929 (info 'symbol-info s (##sys#port-line port)) ) )))
4930
4931 (define (r-xtoken k)
4932 (define pkw ; check for prefix keyword immediately
4933 (and (eq? ksp #:prefix)
4934 (eq? #\: (##sys#peek-char-0 port))
4935 (begin (##sys#read-char-0 port) #t)))
4936 (let loop ((lst '()) (skw #f) (qtd #f))
4937 (let ((c (##sys#peek-char-0 port)))
4938 (cond ((or (eof-object? c)
4939 (char-whitespace? c)
4940 (memq c terminating-characters))
4941 ;; The various cases here cover:
4942 ;; - Nonempty keywords formed with colon in the ksp position
4943 ;; - Empty keywords formed explicitly with vbar quotes
4944 ;; - Bare colon, which should always be a symbol
4945 (cond ((and skw (eq? ksp #:suffix) (or qtd (not (null? (cdr lst)))))
4946 (k (##sys#reverse-list->string (cdr lst)) #t))
4947 ((and pkw (or qtd (not (null? lst))))
4948 (k (##sys#reverse-list->string lst) #t))
4949 ((and pkw (not qtd) (null? lst))
4950 (k ":" #f))
4951 (else
4952 (k (##sys#reverse-list->string lst) #f))))
4953 ((memq c reserved-characters)
4954 (reserved-character c))
4955 (else
4956 (let ((c (##sys#read-char-0 port)))
4957 (case c
4958 ((#\|)
4959 (let ((part (r-string #\|)))
4960 (loop (append (##sys#fast-reverse (##sys#string->list part)) lst)
4961 #f #t)))
4962 ((#\newline)
4963 (##sys#read-warning
4964 port "escaped symbol syntax spans multiple lines"
4965 (##sys#reverse-list->string lst))
4966 (loop (cons #\newline lst) #f qtd))
4967 ((#\:)
4968 (loop (cons #\: lst) #t qtd))
4969 ((#\\)
4970 (let ((c (##sys#read-char-0 port)))
4971 (if (eof-object? c)
4972 (##sys#read-error
4973 port
4974 "unexpected end of file while reading escaped character")
4975 (loop (cons c lst) #f qtd))))
4976 (else
4977 (loop
4978 (cons (if csp c (char-foldcase c)) lst)
4979 #f qtd)))))))))
4980
4981 (define (r-char)
4982 ;; Code contributed by Alex Shinn
4983 (let* ([c (##sys#peek-char-0 port)]
4984 [tk (r-token)]
4985 [len (string-length tk)])
4986 (cond [(fx> len 1)
4987 (cond [(and (or (char=? #\x c) (char=? #\u c) (char=? #\U c))
4988 (##sys#string->number (##sys#substring tk 1 len) 16) )
4989 => (lambda (n) (integer->char n)) ]
4990 [(and-let* ((c0 (char->integer (string-ref tk 0)))
4991 ((fx<= #xC0 c0)) ((fx<= c0 #xF7))
4992 (n0 (fxand (fxshr c0 4) 3))
4993 (n (fx+ 2 (fxand (fxior n0 (fxshr n0 1)) (fx- n0 1))))
4994 ((fx= len n))
4995 (res (fx+ (fxshl (fxand c0 (fx- (fxshl 1 (fx- 8 n)) 1))
4996 6)
4997 (fxand (char->integer
4998 (string-ref tk 1))
4999 #b111111))))
5000 (cond ((fx>= n 3)
5001 (set! res (fx+ (fxshl res 6)
5002 (fxand
5003 (char->integer
5004 (string-ref tk 2))
5005 #b111111)))
5006 (if (fx= n 4)
5007 (set! res (fx+ (fxshl res 6)
5008 (fxand (char->integer
5009 (string-ref tk 3))
5010 #b111111))))))
5011 (integer->char res))]
5012 [(char-name (##sys#string->symbol tk))]
5013 [else (##sys#read-error port "unknown named character" tk)] ) ]
5014 [(memq c terminating-characters) (##sys#read-char-0 port)]
5015 [else c] ) ) )
5016
5017 (define (r-comment)
5018 (let loop ((i 0))
5019 (let ((c (##sys#read-char-0 port)))
5020 (case c
5021 ((#\|) (if (eq? #\# (##sys#read-char-0 port))
5022 (if (not (eq? i 0))
5023 (loop (fx- i 1)) )
5024 (loop i) ) )
5025 ((#\#) (loop (if (eq? #\| (##sys#read-char-0 port))
5026 (fx+ i 1)
5027 i) ) )
5028 (else (if (eof-object? c)
5029 (##sys#read-error port "unterminated block-comment")
5030 (loop i) ) ) ) ) ) )
5031
5032 (define (r-ext-symbol)
5033 (let ((tok (r-token)))
5034 (build-symbol (string-append "##" tok))))
5035
5036 (define (r-quote q)
5037 (let ((ln (##sys#port-line port)))
5038 (info 'list-info (list q (readrec)) ln)))
5039
5040 (define (build-symbol tok)
5041 (##sys#string->symbol tok) )
5042
5043 (define (build-keyword tok)
5044 (##sys#intern-keyword (##sys#string->symbol-name tok)))
5045
5046 ;; now have the state to make a decision.
5047 (set! reserved-characters
5048 (append (if (not psp) '(#\[ #\] #\{ #\}) '())
5049 (if (not sep) '(#\|) '())))
5050 (r-spaces)
5051 (let* ((c (##sys#peek-char-0 port))
5052 (srst (##sys#slot crt 1))
5053 (h (and (not (eof-object? c)) srst
5054 (##sys#slot srst (char->integer c)) ) ) )
5055 (if h
5056 ;; then handled by read-table entry
5057 (##sys#call-with-values
5058 (lambda () (h c port))
5059 (lambda xs (if (null? xs) (readrec) (car xs))))
5060 ;; otherwise chicken extended r5rs syntax
5061 (case c
5062 ((#\')
5063 (##sys#read-char-0 port)
5064 (r-quote 'quote))
5065 ((#\`)
5066 (##sys#read-char-0 port)
5067 (r-quote 'quasiquote))
5068 ((#\,)
5069 (##sys#read-char-0 port)
5070 (cond ((eq? (##sys#peek-char-0 port) #\@)
5071 (##sys#read-char-0 port)
5072 (r-quote 'unquote-splicing))
5073 (else (r-quote 'unquote))))
5074 ((#\#)
5075 (##sys#read-char-0 port)
5076 (let ((dchar (##sys#peek-char-0 port)))
5077 (cond
5078 ((eof-object? dchar)
5079 (##sys#read-error
5080 port "unexpected end of input after reading #-sign"))
5081 ((char-numeric? dchar)
5082 (let* ((n (string->number (r-digits)))
5083 (dchar2 (##sys#peek-char-0 port))
5084 (spdrst (##sys#slot crt 3)))
5085 (cond ((eof-object? dchar2)
5086 (##sys#read-error
5087 port "unexpected end of input after reading"
5088 c n))
5089 ;; #<num>=...
5090 ((eq? #\= dchar2)
5091 (##sys#read-char-0 port)
5092 (letrec ((datum (begin
5093 (register-shared! n (lambda () datum))
5094 (readrec))))
5095 datum))
5096 ;; #<num>#
5097 ((eq? #\# dchar2)
5098 (##sys#read-char-0 port)
5099 (cond ((assq n shared) => cdr)
5100 (else (##sys#read-error port "undefined datum" n))))
5101 ;; #<num> handled by parameterized # read-table entry?
5102 ((and (char? dchar2)
5103 spdrst
5104 (##sys#slot spdrst (char->integer dchar2))) =>
5105 (lambda (h)
5106 (h (##sys#call-with-values
5107 (lambda () (h dchar2 port n))
5108 (lambda xs (if (null? xs) (readrec) (car xs)))))))
5109 ;; #<num>
5110 ((or (eq? dchar2 #\)) (char-whitespace? dchar2))
5111 (##sys#sharp-number-hook port n))
5112 (else (##sys#read-char-0 port) ; Consume it first
5113 (##sys#read-error
5114 port
5115 "invalid parameterized read syntax"
5116 c n dchar2) ) ) ))
5117 (else (let* ((sdrst (##sys#slot crt 2))
5118 (h (and sdrst (##sys#slot sdrst (char->integer dchar)) ) ) )
5119 (if h
5120 ;; then handled by # read-table entry
5121 (##sys#call-with-values
5122 (lambda () (h dchar port))
5123 (lambda xs (if (null? xs) (readrec) (car xs))))
5124 ;; otherwise chicken extended R7RS syntax
5125 (case (char-downcase dchar)
5126 ((#\x) (##sys#read-char-0 port) (r-number-with-exactness 16))
5127 ((#\d) (##sys#read-char-0 port) (r-number-with-exactness 10))
5128 ((#\o) (##sys#read-char-0 port) (r-number-with-exactness 8))
5129 ((#\b) (##sys#read-char-0 port) (r-number-with-exactness 2))
5130 ((#\i) (##sys#read-char-0 port) (r-number-with-radix 'i))
5131 ((#\e) (##sys#read-char-0 port) (r-number-with-radix 'e))
5132 ((#\() (r-vector))
5133 ((#\\) (##sys#read-char-0 port) (r-char))
5134 ((#\|)
5135 (##sys#read-char-0 port)
5136 (r-comment) (readrec) )
5137 ((#\#)
5138 (##sys#read-char-0 port)
5139 (r-ext-symbol) )
5140 ((#\;)
5141 (##sys#read-char-0 port)
5142 (readrec) (readrec) )
5143 ((#\`)
5144 (##sys#read-char-0 port)
5145 (r-quote 'quasisyntax))
5146 ((#\$)
5147 (##sys#read-char-0 port)
5148 ;; HACK: reuse r-quote to add line number info
5149 (r-quote 'location))
5150 ((#\:)
5151 (##sys#read-char-0 port)
5152 (let ((c (##sys#peek-char-0 port)))
5153 (fluid-let ((ksp #f))
5154 (r-xtoken
5155 (lambda (str kw)
5156 (if (and (eq? 0 (string-length str))
5157 (not (char=? c #\|)))
5158 (##sys#read-error port "empty keyword")
5159 (build-keyword str)))))))
5160 ((#\+)
5161 (##sys#read-char-0 port)
5162 (let* ((ln (##sys#port-line port))
5163 (tst (readrec)))
5164 (info 'list-info
5165 (list 'cond-expand (list tst (readrec)) '(else))
5166 ln)))
5167 ((#\!)
5168 (##sys#read-char-0 port)
5169 (let ((c (##sys#peek-char-0 port)))
5170 (cond ((and (char? c)
5171 (or (char-whitespace? c) (char=? #\/ c)))
5172 (skip-to-eol)
5173 (readrec) )
5174 (else
5175 (let ([tok (r-token)])
5176 (cond ((string=? "eof" tok) #!eof)
5177 ((string=? "bwp" tok) #!bwp)
5178 ((string=? "fold-case" tok)
5179 (set! csp #f)
5180 (##sys#setislot port 13 csp)
5181 (readrec))
5182 ((string=? "no-fold-case" tok)
5183 (set! csp #t)
5184 (##sys#setislot port 13 csp)
5185 (readrec))
5186 ((member tok '("optional" "rest" "key"))
5187 (build-symbol (##sys#string-append "#!" tok)) )
5188 (else
5189 (let ((a (assq (string->symbol tok) ##sys#read-marks)))
5190 (if a
5191 ((##sys#slot a 1) port)
5192 (##sys#read-error
5193 port
5194 "invalid `#!' token" tok) ) ) ) ) ) ) ) ) )
5195 (else
5196 (##sys#call-with-values (lambda () (##sys#user-read-hook dchar port))
5197 (lambda xs (if (null? xs) (readrec) (car xs)))) ) ) ) )) ) ) )
5198 ((#\() (r-list #\( #\)))
5199 ((#\)) (##sys#read-char-0 port) (container c))
5200 ((#\") (##sys#read-char-0 port) (r-string #\"))
5201 ((#\.) (r-number #f #f))
5202 ((#\- #\+) (r-number #f #f))
5203 (else
5204 (cond [(eof-object? c) c]
5205 [(char-numeric? c) (r-number #f #f)]
5206 ((memq c reserved-characters)
5207 (reserved-character c))
5208 (else
5209 (case c
5210 ((#\[) (r-list #\[ #\]))
5211 ((#\{) (r-list #\{ #\}))
5212 ((#\] #\}) (##sys#read-char-0 port) (container c))
5213 (else (r-symbol) ) ) ) ) ) ) ) ) )
5214
5215 (let ((x (readrec)))
5216 (when warn (##sys#read-warning port warn))
5217 (when (pair? shared)
5218 (unthunkify! x (lambda a (apply ##sys#read-error p a))))
5219 x)))))
5220
5221;;; Hooks for user-defined read-syntax:
5222;
5223; - Redefine this to handle new read-syntaxes. If 'char' doesn't match
5224; your character then call the previous handler.
5225; - Don't forget to read 'char', it's only peeked at this point.
5226
5227(define (##sys#user-read-hook char port)
5228 (define (fail item) (##sys#read-error port "invalid sharp-sign read syntax" item))
5229 (case char
5230 ((#\f #\t #\u)
5231 (let ((sym (##sys#read port ##sys#default-read-info-hook)))
5232 (if (not (symbol? sym))
5233 (fail char)
5234 (case sym
5235 ((t true) #t)
5236 ((f false) #f)
5237 ((u8)
5238 ;; u8vectors, srfi-4 handles this already via read-hook but we reimplement it
5239 ;; here in case srfi-4 is not loaded
5240 (let ((d (##sys#read-numvector-data port)))
5241 (if (or (null? d) (pair? d))
5242 (##sys#list->bytevector (##sys#canonicalize-number-list! d))
5243 ;; reuse already created bytevector
5244 (##core#inline "C_chop_bv" (##sys#slot d 0)))))
5245 (else (fail sym))))))
5246 (else (fail char))))
5247
5248(define (##sys#read-numvector-data port)
5249 (let ((c (##sys#peek-char-0 port)))
5250 (case c
5251 ((#\() (##sys#read port ##sys#default-read-info-hook))
5252 ((#\") (##sys#read port ##sys#default-read-info-hook))
5253 (else (##sys#read-error port "invalid numeric vector syntax" c)))))
5254
5255;; This code is too complicated. We try to avoid mapping over
5256;; a potentially large list and creating lots of garbage in the
5257;; process, therefore the final result list is constructed
5258;; via destructive updates and thus rather inelegant yet avoids
5259;; any re-consing unless elements are non-numeric.
5260(define (##sys#canonicalize-number-list! lst1)
5261 (let loop ((lst lst1) (prev #f))
5262 (if (and (##core#inline "C_blockp" lst)
5263 (##core#inline "C_pairp" lst))
5264 (let retry ((x (##sys#slot lst 0)))
5265 (cond ((char? x) (retry (string x)))
5266 ((string? x)
5267 (if (zero? (string-length x))
5268 (loop (##sys#slot lst 1) prev)
5269 (let loop2 ((ns (string->list x)) (prev prev))
5270 (let ((n (cons (char->integer (##sys#slot ns 0))
5271 (##sys#slot lst 1))))
5272 (if prev
5273 (##sys#setslot prev 1 n)
5274 (set! lst1 n))
5275 (let ((ns2 (##sys#slot ns 1)))
5276 (if (null? ns2)
5277 (loop (##sys#slot lst 1) n)
5278 (loop2 (##sys#slot ns 1) n)))))))
5279 (else (loop (##sys#slot lst 1) lst))))
5280 (cond (prev (##sys#setslot prev 1 '())
5281 lst1)
5282 (else '())))))
5283
5284;;; Table for specially-handled read-syntax:
5285;
5286; - entries should be #f or a 256-element vector containing procedures
5287; - each procedure is called with two arguments, a char (peeked) and a
5288; port, and should return an expression
5289
5290(define ##sys#read-marks '()) ; TODO move to read-syntax module
5291
5292
5293;;; Output:
5294
5295(define (##sys#write-char-0 c p)
5296 ((##sys#slot (##sys#slot p 2) 2) p c)
5297 (##sys#void))
5298
5299(define (##sys#write-char/port c port)
5300 (##sys#check-output-port port #t 'write-char)
5301 (##sys#check-char c 'write-char)
5302 (##sys#write-char-0 c port) )
5303
5304(set! scheme#write-char
5305 (lambda (c #!optional (port ##sys#standard-output))
5306 (##sys#check-char c 'write-char)
5307 (##sys#check-output-port port #t 'write-char)
5308 (##sys#write-char-0 c port) ))
5309
5310(set! scheme#newline
5311 (lambda (#!optional (port ##sys#standard-output))
5312 (##sys#write-char/port #\newline port) ))
5313
5314(set! scheme#write
5315 (lambda (x #!optional (port ##sys#standard-output))
5316 (##sys#check-output-port port #t 'write)
5317 (##sys#print x #t port) ))
5318
5319(set! scheme#display
5320 (lambda (x #!optional (port ##sys#standard-output))
5321 (##sys#check-output-port port #t 'display)
5322 (##sys#print x #f port) ))
5323
5324(define-inline (*print-each lst)
5325 (for-each (cut ##sys#print <> #f ##sys#standard-output) lst) )
5326
5327(set! chicken.base#print
5328 (lambda args
5329 (##sys#check-output-port ##sys#standard-output #t 'print)
5330 (*print-each args)
5331 (##sys#write-char-0 #\newline ##sys#standard-output)
5332 (void)))
5333
5334(set! chicken.base#print*
5335 (lambda args
5336 (##sys#check-output-port ##sys#standard-output #t 'print)
5337 (*print-each args)
5338 (##sys#flush-output ##sys#standard-output)
5339 (void)))
5340
5341(define current-print-length (make-parameter 0))
5342(define ##sys#print-length-limit (make-parameter #f))
5343(define ##sys#print-exit (make-parameter #f))
5344
5345(define ##sys#print
5346 (let ((case-sensitive case-sensitive)
5347 (symbol-escape symbol-escape)
5348 (keyword-style keyword-style))
5349 (lambda (x readable port)
5350 (##sys#check-output-port port #t #f)
5351 (let ((csp (case-sensitive))
5352 (ksp (keyword-style))
5353 (sep (symbol-escape))
5354 (length-limit (##sys#print-length-limit))
5355 (special-characters '(#\( #\) #\, #\[ #\] #\{ #\} #\' #\" #\; #\ #\` #\| #\\)) )
5356
5357 (define (outstr port str)
5358 (if length-limit
5359 (let* ((len (string-length str))
5360 (cpp0 (current-print-length))
5361 (cpl (fx+ cpp0 len)) )
5362 (if (fx> cpl length-limit)
5363 (let ((n (fx- length-limit cpp0)))
5364 (when (fx> n 0) (outstr0 port (##sys#substring str 0 n)))
5365 (outstr0 port "...")
5366 ((##sys#print-exit) (##sys#void)))
5367 (outstr0 port str) )
5368 (current-print-length cpl) )
5369 (outstr0 port str) ) )
5370
5371 (define (outstr0 port str)
5372 (let ((bv (##sys#slot str 0)))
5373 ((##sys#slot (##sys#slot port 2) 3) port bv 0 (fx- (##sys#size bv) 1)))) ; write-bytevector
5374
5375 (define (outchr port chr)
5376 (when length-limit
5377 (let ((cpp0 (current-print-length)))
5378 (current-print-length (fx+ cpp0 1))
5379 (when (fx>= cpp0 length-limit)
5380 (outstr0 port "...")
5381 ((##sys#print-exit) (##sys#void)))))
5382 ((##sys#slot (##sys#slot port 2) 2) port chr)) ; write-char
5383
5384 (define (specialchar? chr)
5385 (let ([c (char->integer chr)])
5386 (or (fx<= c 32)
5387 (memq chr special-characters) ) ) )
5388
5389 (define (outsym port sym)
5390 (let ((str (##sys#symbol->string/shared sym)))
5391 (if (or (not sep) (not readable) (sym-is-readable? str))
5392 (outstr port str)
5393 (outreadablesym port str))))
5394
5395 (define (outreadablesym port str)
5396 (let ((len (string-length str)))
5397 (outchr port #\|)
5398 (let loop ((i 0))
5399 (if (fx>= i len)
5400 (outchr port #\|)
5401 (let ((c (string-ref str i)))
5402 (cond ((or (char<? c #\space) (char>? c #\~))
5403 (outstr port "\\x")
5404 (let ((n (char->integer c)))
5405 (outstr port (##sys#number->string n 16))
5406 (outchr port #\;)
5407 (loop (fx+ i 1))))
5408 (else
5409 (when (or (eq? c #\|) (eq? c #\\)) (outchr port #\\))
5410 (outchr port c)
5411 (loop (fx+ i 1)) ) ) ) ) )))
5412
5413 (define (sym-is-readable? str)
5414 (let ((len (string-length str)))
5415 (cond ((eq? len 0) #f)
5416 ((eq? len 1)
5417 (let ((c (string-ref str 0)))
5418 (cond ((or (eq? #\# c) (eq? #\. c)) #f)
5419 ((specialchar? c) #f)
5420 ((char-numeric? c) #f)
5421 (else #t))))
5422 (else
5423 (let loop ((i (fx- len 1)))
5424 (if (eq? i 0)
5425 (let ((c (string-ref str 0)))
5426 (cond ((char-numeric? c) #f)
5427 ((or (eq? c #\+) (eq? c #\-))
5428 (or (fx= len 1)
5429 (not (char-numeric? (string-ref str 1)))))
5430 ((eq? c #\.)
5431 (and (fx> len 1)
5432 (not (char-numeric? (string-ref str 1)))))
5433 ((eq? c #\:) #f)
5434 ((and (eq? c #\#)
5435 ;; Not a qualified symbol?
5436 (not (and (fx> len 2)
5437 (eq? (string-ref str 1) #\#)
5438 (not (eq? (string-ref str 2) #\#)))))
5439 (member str '("#!rest" "#!key" "#!optional"
5440 "#!fold-case" "#!no-fold-case")))
5441 ((specialchar? c) #f)
5442 (else #t) ) )
5443 (let ((c (string-ref str i)))
5444 (and (or csp (not (char-upper-case? c)))
5445 (not (specialchar? c))
5446 (or (not (eq? c #\:))
5447 (fx< i (fx- len 1)))
5448 (loop (fx- i 1)) ) ) ) ) ) ) ) )
5449
5450 (let out ([x x])
5451 (cond ((eq? x '()) (outstr port "()"))
5452 ((eq? x #t) (outstr port "#t"))
5453 ((eq? x #f) (outstr port "#f"))
5454 ((##core#inline "C_eofp" x) (outstr port "#!eof"))
5455 ((##core#inline "C_undefinedp" x) (outstr port "#<unspecified>"))
5456 ((##core#inline "C_bwpp" x) (outstr port "#!bwp"))
5457 ((##core#inline "C_charp" x)
5458 (cond [readable
5459 (outstr port "#\\")
5460 (let ([code (char->integer x)])
5461 (cond [(char-name x)
5462 => (lambda (cn)
5463 (outstr port (##sys#symbol->string/shared cn)) ) ]
5464 [(or (fx< code 32) (fx> code #x1ffff))
5465 (outchr port #\x)
5466 (outstr port (##sys#number->string code 16)) ]
5467 [else (outchr port x)] ) ) ]
5468 [else (outchr port x)] ) )
5469 ((##core#inline "C_fixnump" x) (outstr port (##sys#number->string x)))
5470 ((##core#inline "C_unboundvaluep" x) (outstr port "#<unbound value>"))
5471 ((not (##core#inline "C_blockp" x)) (outstr port "#<invalid immediate object>"))
5472 ((##core#inline "C_forwardedp" x) (outstr port "#<invalid forwarded object>"))
5473 ((##core#inline "C_i_keywordp" x)
5474 ;; Force portable #: style for readable output
5475 (case (and (not readable) ksp)
5476 ((#:prefix)
5477 (outchr port #\:)
5478 (outsym port x))
5479 ((#:suffix)
5480 (outsym port x)
5481 (outchr port #\:))
5482 (else
5483 (outstr port "#:")
5484 (outsym port x))))
5485 ((##core#inline "C_i_symbolp" x) (outsym port x))
5486 ((number? x) (outstr port (##sys#number->string x)))
5487 ((##core#inline "C_anypointerp" x) (outstr port (##sys#pointer->string x)))
5488 ((##core#inline "C_stringp" x)
5489 (cond (readable
5490 (outchr port #\")
5491 (do ((i 0 (fx+ i 1))
5492 (c (string-length x) (fx- c 1)) )
5493 ((eq? c 0)
5494 (outchr port #\") )
5495 (let ((chr (char->integer (string-ref x i))))
5496 (case chr
5497 ((34) (outstr port "\\\""))
5498 ((92) (outstr port "\\\\"))
5499 (else
5500 (cond ((or (fx< chr 32)
5501 (fx= chr #x1ffff))
5502 (outchr port #\\)
5503 (case chr
5504 ((7) (outchr port #\a))
5505 ((8) (outchr port #\b))
5506 ((9) (outchr port #\t))
5507 ((10) (outchr port #\n))
5508 ((11) (outchr port #\v))
5509 ((12) (outchr port #\f))
5510 ((13) (outchr port #\r))
5511 (else
5512 (outchr port #\x)
5513 (when (fx< chr 16) (outchr port #\0))
5514 (outstr port (##sys#number->string chr 16))
5515 (outchr port #\;) ) ) )
5516 (else (outchr port (##core#inline "C_fix_to_char" chr)) ) ) ) ) ) ) )
5517 (else (outstr port x)) ) )
5518 ((##core#inline "C_pairp" x)
5519 (outchr port #\()
5520 (out (##sys#slot x 0))
5521 (do ((x (##sys#slot x 1) (##sys#slot x 1)))
5522 ((or (not (##core#inline "C_blockp" x)) (not (##core#inline "C_pairp" x)))
5523 (if (not (eq? x '()))
5524 (begin
5525 (outstr port " . ")
5526 (out x) ) )
5527 (outchr port #\)) )
5528 (outchr port #\space)
5529 (out (##sys#slot x 0)) ) )
5530 ((##core#inline "C_bytevectorp" x)
5531 (outstr port "#u8")
5532 (out (##sys#bytevector->list x)))
5533 ((##core#inline "C_structurep" x) (##sys#user-print-hook x readable port))
5534 ((##core#inline "C_closurep" x) (outstr port (##sys#procedure->string x)))
5535 ((##core#inline "C_locativep" x) (outstr port "#<locative>"))
5536 ((##core#inline "C_lambdainfop" x)
5537 (outstr port "#<lambda info ")
5538 (outstr port (##sys#lambda-info->string x))
5539 (outchr port #\>) )
5540 ((##core#inline "C_portp" x)
5541 (case (##sys#slot x 1)
5542 ((1) (outstr port "#<input port \""))
5543 ((2) (outstr port "#<output port \""))
5544 (else (outstr port "#<port \"")))
5545 (outstr port (##sys#slot x 3))
5546 (outstr port "\">") )
5547 ((##core#inline "C_vectorp" x)
5548 (let ((n (##sys#size x)))
5549 (cond ((eq? 0 n)
5550 (outstr port "#()") )
5551 (else
5552 (outstr port "#(")
5553 (out (##sys#slot x 0))
5554 (do ((i 1 (fx+ i 1))
5555 (c (fx- n 1) (fx- c 1)) )
5556 ((eq? c 0)
5557 (outchr port #\)) )
5558 (outchr port #\space)
5559 (out (##sys#slot x i)) ) ) ) ) )
5560 (else (##sys#error "unprintable block object encountered")))))
5561 (##sys#void))))
5562
5563(define ##sys#procedure->string
5564 (let ((string-append string-append))
5565 (lambda (x)
5566 (let ((info (##sys#lambda-info x)))
5567 (if info
5568 (string-append "#<procedure " (##sys#lambda-info->string info) ">")
5569 "#<procedure>") ) ) ) )
5570
5571(define ##sys#record-printers '())
5572
5573(set! chicken.base#record-printer
5574 (lambda (type)
5575 (let ((a (assq type ##sys#record-printers)))
5576 (and a (cdr a)))))
5577
5578(set! chicken.base#set-record-printer!
5579 (lambda (type proc)
5580 (##sys#check-closure proc 'set-record-printer!)
5581 (let ((a (assq type ##sys#record-printers)))
5582 (if a
5583 (##sys#setslot a 1 proc)
5584 (set! ##sys#record-printers (cons (cons type proc) ##sys#record-printers)))
5585 (##core#undefined))))
5586
5587;; OBSOLETE can be removed after bootstrapping
5588(set! ##sys#register-record-printer chicken.base#set-record-printer!)
5589
5590(set! chicken.base#record-printer
5591 (getter-with-setter record-printer set-record-printer!))
5592
5593(define (##sys#user-print-hook x readable port)
5594 (let* ((type (##sys#slot x 0))
5595 (a (assq type ##sys#record-printers))
5596 (name (if (vector? type) (##sys#slot type 0) type)))
5597 (cond (a (handle-exceptions ex
5598 (begin
5599 (##sys#print "#<Error in printer of record type `" #f port)
5600 (##sys#print name #f port)
5601 (if (##sys#structure? ex 'condition)
5602 (and-let* ((a (member '(exn . message) (##sys#slot ex 2))))
5603 (##sys#print "': " #f port)
5604 (##sys#print (cadr a) #f port)
5605 (##sys#write-char-0 #\> port))
5606 (##sys#print "'>" #f port)))
5607 ((##sys#slot a 1) x port)))
5608 (else
5609 (##sys#print "#<" #f port)
5610 (##sys#print name #f port)
5611 (case type
5612 ((condition)
5613 (##sys#print ": " #f port)
5614 (##sys#print (##sys#slot x 1) #f port) )
5615 ((thread)
5616 (##sys#print ": " #f port)
5617 (##sys#print (##sys#slot x 6) #f port) ) )
5618 (##sys#write-char-0 #\> port) ) ) ) )
5619
5620(define ##sys#with-print-length-limit
5621 (let ([call-with-current-continuation call-with-current-continuation])
5622 (lambda (limit thunk)
5623 (call-with-current-continuation
5624 (lambda (return)
5625 (parameterize ((##sys#print-length-limit limit)
5626 (##sys#print-exit return)
5627 (current-print-length 0))
5628 (thunk)))))))
5629
5630
5631;;; String ports:
5632;
5633; - Port-slots:
5634;
5635; Input:
5636;
5637; 10: position (in bytes)
5638; 11: len
5639; 12: input bytevector
5640;
5641; Output:
5642;
5643; 10: position (in bytes)
5644; 11: limit
5645; 12: output bytevector
5646
5647(define ##sys#string-port-class
5648 (letrec ((check
5649 (lambda (p n)
5650 (let* ((position (##sys#slot p 10))
5651 (limit (##sys#slot p 11))
5652 (output (##sys#slot p 12))
5653 (limit2 (fx+ position n)))
5654 (when (fx>= limit2 limit)
5655 (when (fx>= limit2 maximal-string-length)
5656 (##sys#error "string buffer full" p) )
5657 (let* ([limit3 (fxmin maximal-string-length (fx+ limit limit))]
5658 [buf (##sys#make-bytevector limit3)] )
5659 (##core#inline "C_copy_memory_with_offset" buf output 0 0 position)
5660 (##sys#setslot p 12 buf)
5661 (##sys#setislot p 11 limit3)
5662 (check p n) ) ) ) ) ) )
5663 (vector
5664 (lambda (p) ; read-char
5665 (let ((position (##sys#slot p 10))
5666 (input (##sys#slot p 12))
5667 (len (##sys#slot p 11)))
5668 (if (fx>= position len)
5669 #!eof
5670 (let ((c (##core#inline "C_utf_decode" input position)))
5671 (##sys#setislot p 10
5672 (##core#inline "C_utf_advance" input position))
5673 c))))
5674 (lambda (p) ; peek-char
5675 (let ((position (##sys#slot p 10))
5676 (input (##sys#slot p 12))
5677 (len (##sys#slot p 11)))
5678 (if (fx>= position len)
5679 #!eof
5680 (##core#inline "C_utf_decode" input position))))
5681 (lambda (p c) ; write-char
5682 (check p 1)
5683 (let ([position (##sys#slot p 10)]
5684 [output (##sys#slot p 12)] )
5685 (##sys#setislot p 10 (##core#inline "C_utf_insert" output position c))))
5686 (lambda (p bv from to) ; write-bytevector
5687 (let ((len (fx- to from)))
5688 (check p len)
5689 (let* ((position (##sys#slot p 10))
5690 (output (##sys#slot p 12)))
5691 (##core#inline "C_copy_memory_with_offset" output bv position from len)
5692 (##sys#setislot p 10 (fx+ position len)) ) ) )
5693 void ; close
5694 (lambda (p) #f) ; flush-output
5695 (lambda (p) #t) ; char-ready?
5696 (lambda (p n dest start) ; read-bytevector!
5697 (let* ((pos (##sys#slot p 10))
5698 (input (##sys#slot p 12))
5699 (n2 (fx- (##sys#slot p 11) pos)))
5700 (when (or (not n) (fx> n n2)) (set! n n2))
5701 (##core#inline "C_copy_memory_with_offset" dest input start pos n)
5702 (##sys#setislot p 10 (fx+ pos n))
5703 n))
5704 (lambda (p limit) ; read-line
5705 (let* ((pos (##sys#slot p 10))
5706 (size (##sys#slot p 11))
5707 (buf (##sys#slot p 12))
5708 (end (if limit (fx+ pos limit) size)))
5709 (if (fx>= pos size)
5710 #!eof
5711 (receive (next line full-line?)
5712 (##sys#scan-buffer-line
5713 buf (if (fx> end size) size end) pos
5714 (lambda (pos) (values #f pos #f) ) )
5715 ;; Update row & column position
5716 (if full-line?
5717 (begin
5718 (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
5719 (##sys#setislot p 5 0))
5720 (##sys#setislot p 5 (fx+ (##sys#slot p 5) (string-length line))))
5721 (##sys#setislot p 10 next)
5722 line) ) ) )
5723 (lambda (p) ; read-buffered
5724 (let ((pos (##sys#slot p 10))
5725 (buf (##sys#slot p 12))
5726 (len (##sys#slot p 11)) )
5727 (if (fx>= pos len)
5728 ""
5729 (let* ((rest (fx- len pos))
5730 (buffered (##sys#buffer->string buffered pos rest)))
5731 (##sys#setislot p 10 len)
5732 buffered))))
5733 )))
5734
5735;; Invokes the eos handler when EOS is reached to get more data.
5736;; The eos-handler is responsible for stopping, either when EOF is hit or
5737;; a user-supplied limit is reached (ie, it's indistinguishable from EOF)
5738(define (##sys#scan-buffer-line buf limit start-pos eos-handler #!optional enc)
5739 (let* ((hold 1024)
5740 (dpos 0)
5741 (line (##sys#make-bytevector hold)))
5742 (define (grow)
5743 (let* ((h2 (fx* hold 2))
5744 (l2 (##sys#make-bytevector h2)))
5745 (##core#inline "C_copy_memory" l2 line dpos)
5746 (set! line l2)
5747 (set! hold h2)))
5748 (define (conc buf from to)
5749 (let ((len (fx- to from)))
5750 (when (fx>= (fx+ dpos len) hold) (grow))
5751 (##core#inline "C_copy_memory_with_offset" line buf dpos from len)
5752 (set! dpos (fx+ dpos len))))
5753 (define (conc1 b)
5754 (when (fx>= (fx+ dpos 1) hold) (grow))
5755 (##core#inline "C_setsubbyte" line dpos b)
5756 (set! dpos (fx+ dpos 1)))
5757 (define (getline)
5758 (if enc
5759 (##sys#buffer->string/encoding line 0 dpos enc)
5760 (##sys#buffer->string line 0 dpos)))
5761 (let loop ((buf buf)
5762 (offset start-pos)
5763 (pos start-pos)
5764 (limit limit))
5765 (cond ((fx= pos limit)
5766 (conc buf offset pos)
5767 (receive (buf offset limit) (eos-handler pos)
5768 (if buf
5769 (loop buf offset offset limit)
5770 (values offset (getline) #f))))
5771 (else
5772 (let ((c (##core#inline "C_subbyte" buf pos)))
5773 (cond ((eq? c 10)
5774 (conc buf offset pos)
5775 (values (fx+ pos 1) (getline) #t))
5776 ((and (eq? c 13) ; \r\n -> drop \r from string
5777 (fx> limit (fx+ pos 1))
5778 (eq? (##core#inline "C_subbyte" buf (fx+ pos 1)) 10))
5779 (conc buf offset pos)
5780 (values (fx+ pos 2) (getline) #t))
5781 ((and (eq? c 13) ; Edge case (#568): \r{read}[\n|xyz]
5782 (fx= limit (fx+ pos 1)))
5783 (conc buf offset pos)
5784 (receive (buf offset limit) (eos-handler pos)
5785 (if buf
5786 (if (eq? (##core#inline "C_subbyte" buf offset) 10)
5787 (values (fx+ offset 1) (getline) #t)
5788 ;; "Restore" \r we didn't copy, loop w/ new string
5789 (begin
5790 (conc1 13)
5791 (loop buf offset offset limit)))
5792 ;; Restore \r here, too (when we reached EOF)
5793 (begin
5794 (conc1 13)
5795 (values offset (getline) #t)))))
5796 ((eq? c 13)
5797 (conc buf offset pos)
5798 (values (fx+ pos 1) (getline) #t))
5799 (else (loop buf offset (fx+ pos 1) limit)) ) ) ) ) )))
5800
5801(define ##sys#print-to-string
5802 (let ([get-output-string get-output-string]
5803 [open-output-string open-output-string] )
5804 (lambda (xs)
5805 (let ([out (open-output-string)])
5806 (for-each (lambda (x) (##sys#print x #f out)) xs)
5807 (get-output-string out) ) ) ) )
5808
5809(define ##sys#pointer->string
5810 (let ((string-append string-append))
5811 (lambda (x)
5812 (if (##core#inline "C_taggedpointerp" x)
5813 (string-append
5814 "#<tagged pointer "
5815 (##sys#print-to-string
5816 (let ((tag (##sys#slot x 1)))
5817 (list (if (pair? tag) (car tag) tag) ) ) )
5818 " "
5819 (##sys#number->string (##sys#pointer->address x) 16)
5820 ">")
5821 (string-append "#<pointer 0x" (##sys#number->string (##sys#pointer->address x) 16) ">") ) ) ) )
5822
5823
5824;;; Access backtrace:
5825
5826(define-constant +trace-buffer-entry-slot-count+ 5)
5827
5828(set! chicken.base#get-call-chain
5829 (let ((extract
5830 (foreign-lambda* nonnull-c-string ((scheme-object x)) "C_return((C_char *)x);")))
5831 (lambda (#!optional (start 0) (thread ##sys#current-thread))
5832 (let* ((tbl (foreign-value "C_trace_buffer_size" int))
5833 ;; 5 slots: "raw" location (for compiled code), "cooked" location (for interpreted code), cooked1, cooked2, thread
5834 (c +trace-buffer-entry-slot-count+)
5835 (vec (##sys#make-vector (fx* c tbl) #f))
5836 (r (##core#inline "C_fetch_trace" start vec))
5837 (n (if (fixnum? r) r (fx* c tbl)))
5838 (t-id (and thread (##sys#slot thread 14))))
5839 (let loop ((i 0))
5840 (if (fx>= i n)
5841 '()
5842 (let ((t (##sys#slot vec (fx+ i 4)))) ; thread id
5843 (if (or (not t) (not thread) (eq? t-id t))
5844 (cons (vector
5845 (or (##sys#slot vec (fx+ i 1)) ; cooked_location
5846 (extract (##sys#slot vec i))) ; raw_location
5847 (##sys#slot vec (fx+ i 2)) ; cooked1
5848 (##sys#slot vec (fx+ i 3))) ; cooked2
5849 (loop (fx+ i c)))
5850 (loop (fx+ i c))))))))))
5851
5852(define (##sys#really-print-call-chain port chain header)
5853 (when (pair? chain)
5854 (##sys#print header #f port)
5855 (for-each
5856 (lambda (info)
5857 (let* ((more1 (##sys#slot info 1)) ; cooked1 (expr/form)
5858 (more2 (##sys#slot info 2)) ; cooked2 (cntr/frameinfo)
5859 (fi (##sys#structure? more2 'frameinfo)))
5860 (##sys#print "\n\t" #f port)
5861 (##sys#print (##sys#slot info 0) #f port) ; raw (mode)
5862 (##sys#print "\t " #f port)
5863 (when (and more2 (if fi (##sys#slot more2 1)))
5864 (##sys#write-char-0 #\[ port)
5865 (##sys#print
5866 (if fi
5867 (##sys#slot more2 1) ; cntr
5868 more2)
5869 #f port)
5870 (##sys#print "] " #f port))
5871 (when more1
5872 (##sys#with-print-length-limit
5873 100
5874 (lambda ()
5875 (##sys#print more1 #t port))))))
5876 chain)
5877 (##sys#print "\t<--\n" #f port)))
5878
5879(set! chicken.base#print-call-chain
5880 (lambda (#!optional (port ##sys#standard-output) (start 0)
5881 (thread ##sys#current-thread)
5882 (header "\n\tCall history:\n"))
5883 (##sys#check-output-port port #t 'print-call-chain)
5884 (##sys#check-fixnum start 'print-call-chain)
5885 (##sys#check-string header 'print-call-chain)
5886 (##sys#really-print-call-chain port (get-call-chain start thread) header)))
5887
5888
5889;;; Interrupt handling:
5890
5891(define (##sys#user-interrupt-hook)
5892 (define (break) (##sys#signal-hook #:user-interrupt #f))
5893 (if (eq? ##sys#current-thread ##sys#primordial-thread)
5894 (break)
5895 (##sys#setslot ##sys#primordial-thread 1 break) ) )
5896
5897
5898;;; Default handlers
5899
5900(define-foreign-variable _ex_software int "EX_SOFTWARE")
5901
5902(define exit-in-progress #f)
5903
5904(define (cleanup-before-exit)
5905 (set! exit-in-progress #t)
5906 (when (##core#inline "C_i_dump_heap_on_exitp")
5907 (##sys#print "\n" #f ##sys#standard-error)
5908 (##sys#dump-heap-state))
5909 (when (##core#inline "C_i_profilingp")
5910 (##core#inline "C_i_dump_statistical_profile"))
5911 (let loop ()
5912 (let ((tasks chicken.base#cleanup-tasks))
5913 (set! chicken.base#cleanup-tasks '())
5914 (unless (null? tasks)
5915 (for-each (lambda (t) (t)) tasks)
5916 (loop))))
5917 (when (fx> (##sys#slot ##sys#pending-finalizers 0) 0)
5918 (##sys#run-pending-finalizers #f))
5919 (when (fx> (##core#inline "C_i_live_finalizer_count") 0)
5920 (when (##sys#debug-mode?)
5921 (##sys#print "[debug] forcing finalizers...\n" #f ##sys#standard-error))
5922 (when (chicken.gc#force-finalizers)
5923 (##sys#force-finalizers))))
5924
5925(set! chicken.base#exit-handler
5926 (make-parameter
5927 (lambda (#!optional (code 0))
5928 (##sys#check-fixnum code)
5929 (cond (exit-in-progress
5930 (##sys#warn "\"exit\" called while processing on-exit tasks"))
5931 (else
5932 (cleanup-before-exit)
5933 (##core#inline "C_exit_runtime" code))))))
5934
5935(set! chicken.base#implicit-exit-handler
5936 (make-parameter
5937 (lambda ()
5938 (cleanup-before-exit))))
5939
5940(define ##sys#reset-handler ; Exposed by chicken.repl
5941 (make-parameter
5942 (lambda ()
5943 ((exit-handler) _ex_software))))
5944
5945(define (##sys#dbg-hook . args)
5946 (##core#inline "C_dbg_hook" #f)
5947 (##core#undefined))
5948
5949
5950;;; Condition handling:
5951
5952(module chicken.condition
5953 ;; NOTE: We don't emit the import lib. Due to syntax exports, it
5954 ;; has to be a hardcoded primitive module.
5955 (abort signal current-exception-handler
5956 print-error-message with-exception-handler
5957
5958 ;; [syntax] condition-case handle-exceptions
5959
5960 ;; Condition object manipulation
5961 make-property-condition make-composite-condition
5962 condition condition? condition->list condition-predicate
5963 condition-property-accessor get-condition-property)
5964
5965(import scheme chicken.base chicken.fixnum chicken.foreign)
5966(import chicken.internal.syntax)
5967(import (only (scheme base) make-parameter open-output-string get-output-string))
5968
5969(define (##sys#signal-hook/errno mode errno msg . args)
5970 (##core#inline "C_dbg_hook" #f)
5971 (##core#inline "signal_debug_event" mode msg args)
5972 (case mode
5973 [(#:user-interrupt)
5974 (abort
5975 (##sys#make-structure
5976 'condition
5977 '(user-interrupt)
5978 '() ) ) ]
5979 [(#:warning #:notice)
5980 (##sys#print
5981 (if (eq? mode #:warning) "\nWarning: " "\nNote: ")
5982 #f ##sys#standard-error)
5983 (##sys#print msg #f ##sys#standard-error)
5984 (if (or (null? args) (fx> (length args) 1))
5985 (##sys#write-char-0 #\newline ##sys#standard-error)
5986 (##sys#print ": " #f ##sys#standard-error))
5987 (for-each
5988 (lambda (x)
5989 (##sys#with-print-length-limit
5990 400
5991 (lambda ()
5992 (##sys#print x #t ##sys#standard-error)
5993 (##sys#write-char-0 #\newline ##sys#standard-error))))
5994 args)
5995 (##sys#flush-output ##sys#standard-error)]
5996 (else
5997 (when (and (symbol? msg) (null? args))
5998 (set! msg (symbol->string msg)))
5999 (let* ([hasloc (and (or (not msg) (symbol? msg)) (pair? args))]
6000 [loc (and hasloc msg)]
6001 [msg (if hasloc (##sys#slot args 0) msg)]
6002 [args (if hasloc (##sys#slot args 1) args)] )
6003 (abort
6004 (##sys#make-structure
6005 'condition
6006 (case mode
6007 [(#:type-error) '(exn type)]
6008 [(#:syntax-error) '(exn syntax)]
6009 [(#:bounds-error) '(exn bounds)]
6010 [(#:arithmetic-error) '(exn arithmetic)]
6011 [(#:file-error) '(exn i/o file)]
6012 [(#:runtime-error) '(exn runtime)]
6013 [(#:process-error) '(exn process)]
6014 [(#:network-error) '(exn i/o net)]
6015 [(#:network-timeout-error) '(exn i/o net timeout)]
6016 [(#:limit-error) '(exn runtime limit)]
6017 [(#:arity-error) '(exn arity)]
6018 [(#:access-error) '(exn access)]
6019 [(#:domain-error) '(exn domain)]
6020 ((#:memory-error) '(exn memory))
6021 [else '(exn)] )
6022 (let ((props
6023 (list '(exn . message) msg
6024 '(exn . arguments) args
6025 '(exn . call-chain) (get-call-chain)
6026 '(exn . location) loc)))
6027 (if errno
6028 (cons '(exn . errno) (cons errno props))
6029 props))))))))
6030
6031(define (##sys#signal-hook mode msg . args)
6032 (if (pair? args)
6033 (apply ##sys#signal-hook/errno mode #f msg args)
6034 (##sys#signal-hook/errno mode #f msg)))
6035
6036(define (abort x)
6037 (##sys#current-exception-handler x)
6038 (abort
6039 (##sys#make-structure
6040 'condition
6041 '(exn)
6042 (list '(exn . message) "exception handler returned"
6043 '(exn . arguments) '()
6044 '(exn . location) #f) ) ) )
6045
6046(define (signal x)
6047 (##sys#current-exception-handler x) )
6048
6049(define ##sys#error-handler
6050 (make-parameter
6051 (let ([string-append string-append])
6052 (lambda (msg . args)
6053 (##sys#error-handler (lambda args (##core#inline "C_halt" "error in error")))
6054 (cond ((not (foreign-value "C_gui_mode" bool))
6055 (##sys#print "\nError" #f ##sys#standard-error)
6056 (when msg
6057 (##sys#print ": " #f ##sys#standard-error)
6058 (##sys#print msg #f ##sys#standard-error))
6059 (##sys#with-print-length-limit
6060 400
6061 (lambda ()
6062 (cond [(fx= 1 (length args))
6063 (##sys#print ": " #f ##sys#standard-error)
6064 (##sys#print (##sys#slot args 0) #t ##sys#standard-error)]
6065 [else
6066 (##sys#for-each
6067 (lambda (x)
6068 (##sys#print #\newline #f ##sys#standard-error)
6069 (##sys#print x #t ##sys#standard-error))
6070 args)])))
6071 (##sys#print #\newline #f ##sys#standard-error)
6072 (print-call-chain ##sys#standard-error)
6073 (##core#inline "C_halt" #f))
6074 (else
6075 (let ((out (open-output-string)))
6076 (when msg (##sys#print msg #f out))
6077 (##sys#print #\newline #f out)
6078 (##sys#for-each (lambda (x) (##sys#print x #t out) (##sys#print #\newline #f out)) args)
6079 (##core#inline "C_halt" (get-output-string out)))))))))
6080
6081
6082(define ##sys#last-exception #f) ; used in csi for ,exn command
6083
6084(define ##sys#current-exception-handler
6085 ;; Exception-handler for the primordial thread:
6086 (let ((string-append string-append))
6087 (lambda (c)
6088 (when (##sys#structure? c 'condition)
6089 (set! ##sys#last-exception c)
6090 (let ((kinds (##sys#slot c 1)))
6091 (cond ((memq 'exn kinds)
6092 (let* ((props (##sys#slot c 2))
6093 (msga (member '(exn . message) props))
6094 (argsa (member '(exn . arguments) props))
6095 (loca (member '(exn . location) props)) )
6096 (apply
6097 (##sys#error-handler)
6098 (if msga
6099 (let ((msg (cadr msga))
6100 (loc (and loca (cadr loca))) )
6101 (if (and loc (symbol? loc))
6102 (string-append
6103 "(" (##sys#symbol->string/shared loc) ") "
6104 (cond ((symbol? msg) (##sys#slot msg 1))
6105 ((string? msg) msg)
6106 (else "") ) ) ; Hm...
6107 msg) )
6108 "<exn: has no `message' property>")
6109 (if argsa
6110 (cadr argsa)
6111 '() ) )
6112 ;; in case error-handler returns, which shouldn't happen:
6113 ((##sys#reset-handler)) ) )
6114 ((eq? 'user-interrupt (##sys#slot kinds 0))
6115 (##sys#print "\n*** user interrupt ***\n" #f ##sys#standard-error)
6116 ((##sys#reset-handler)) )
6117 ((eq? 'uncaught-exception (##sys#slot kinds 0))
6118 ((##sys#error-handler)
6119 "uncaught exception"
6120 (cadr (member '(uncaught-exception . reason) (##sys#slot c 2))) )
6121 ((##sys#reset-handler)) ) ) ) )
6122 (abort
6123 (##sys#make-structure
6124 'condition
6125 '(uncaught-exception)
6126 (list '(uncaught-exception . reason) c)) ) ) ) )
6127
6128(define (with-exception-handler handler thunk)
6129 (let ([oldh ##sys#current-exception-handler])
6130 (##sys#dynamic-wind
6131 (lambda () (set! ##sys#current-exception-handler handler))
6132 thunk
6133 (lambda () (set! ##sys#current-exception-handler oldh)) ) ) )
6134
6135;; TODO: Make this a proper parameter
6136(define (current-exception-handler . args)
6137 (if (null? args)
6138 ##sys#current-exception-handler
6139 (let ((proc (car args)))
6140 (##sys#check-closure proc 'current-exception-handler)
6141 (let-optionals (cdr args) ((convert? #t) (set? #t))
6142 (when set? (set! ##sys#current-exception-handler proc)))
6143 proc)))
6144
6145;;; Condition object manipulation
6146
6147(define (prop-list->kind-prefixed-prop-list loc kind plist)
6148 (let loop ((props plist))
6149 (cond ((null? props) '())
6150 ((or (not (pair? props)) (not (pair? (cdr props))))
6151 (##sys#signal-hook
6152 #:type-error loc "argument is not an even property list" plist))
6153 (else (cons (cons kind (car props))
6154 (cons (cadr props)
6155 (loop (cddr props))))))))
6156
6157(define (make-property-condition kind . props)
6158 (##sys#make-structure
6159 'condition (list kind)
6160 (prop-list->kind-prefixed-prop-list
6161 'make-property-condition kind props)))
6162
6163(define (make-composite-condition c1 . conds)
6164 (let ([conds (cons c1 conds)])
6165 (for-each (lambda (c) (##sys#check-structure c 'condition 'make-composite-condition)) conds)
6166 (##sys#make-structure
6167 'condition
6168 (apply ##sys#append (map (lambda (c) (##sys#slot c 1)) conds))
6169 (apply ##sys#append (map (lambda (c) (##sys#slot c 2)) conds)) ) ) )
6170
6171(define (condition arg1 . args)
6172 (let* ((args (cons arg1 args))
6173 (keys (apply ##sys#append
6174 (map (lambda (c)
6175 (prop-list->kind-prefixed-prop-list
6176 'condition (car c) (cdr c)))
6177 args))))
6178 (##sys#make-structure 'condition (map car args) keys)))
6179
6180(define (condition? x) (##sys#structure? x 'condition))
6181
6182(define (condition->list x)
6183 (unless (condition? x)
6184 (##sys#signal-hook
6185 #:type-error 'condition->list
6186 "argument is not a condition object" x))
6187 (map (lambda (k)
6188 (cons k (let loop ((props (##sys#slot x 2)))
6189 (cond ((null? props) '())
6190 ((eq? (caar props) k)
6191 (cons (cdar props)
6192 (cons (cadr props)
6193 (loop (cddr props)))))
6194 (else
6195 (loop (cddr props)))))))
6196 (##sys#slot x 1)))
6197
6198(define (condition-predicate kind)
6199 (lambda (c)
6200 (and (condition? c)
6201 (if (memv kind (##sys#slot c 1)) #t #f)) ) )
6202
6203(define (condition-property-accessor kind prop . err-def)
6204 (let ((err? (null? err-def))
6205 (k+p (cons kind prop)) )
6206 (lambda (c)
6207 (##sys#check-structure c 'condition)
6208 (and (memv kind (##sys#slot c 1))
6209 (let ([a (member k+p (##sys#slot c 2))])
6210 (cond [a (cadr a)]
6211 [err? (##sys#signal-hook
6212 #:type-error 'condition-property-accessor
6213 "condition has no such property" prop) ]
6214 [else (car err-def)] ) ) ) ) ) )
6215
6216(define get-condition-property
6217 (lambda (c kind prop . err-def)
6218 ((apply condition-property-accessor kind prop err-def) c)))
6219
6220
6221;;; Convenient error printing:
6222
6223(define print-error-message
6224 (let* ((display display)
6225 (newline newline)
6226 (write write)
6227 (string-append string-append)
6228 (errmsg (condition-property-accessor 'exn 'message #f))
6229 (errloc (condition-property-accessor 'exn 'location #f))
6230 (errargs (condition-property-accessor 'exn 'arguments #f))
6231 (writeargs
6232 (lambda (args port)
6233 (##sys#for-each
6234 (lambda (x)
6235 (##sys#with-print-length-limit 80 (lambda () (write x port)))
6236 (newline port) )
6237 args) ) ) )
6238 (lambda (ex . args)
6239 (let-optionals args ((port ##sys#standard-output)
6240 (header "Error"))
6241 (##sys#check-output-port port #t 'print-error-message)
6242 (newline port)
6243 (display header port)
6244 (cond ((and (not (##sys#immediate? ex)) (eq? 'condition (##sys#slot ex 0)))
6245 (cond ((errmsg ex) =>
6246 (lambda (msg)
6247 (display ": " port)
6248 (let ((loc (errloc ex)))
6249 (when (and loc (symbol? loc))
6250 (display (string-append "(" (##sys#symbol->string/shared loc) ") ") port) ) )
6251 (display msg port) ) )
6252 (else
6253 (let ((kinds (##sys#slot ex 1)))
6254 (if (equal? '(user-interrupt) kinds)
6255 (display ": *** user interrupt ***" port)
6256 (begin
6257 (display ": <condition> " port)
6258 (display (##sys#slot ex 1) port) ) ) ) ) )
6259 (let ((args (errargs ex)))
6260 (cond
6261 ((not args))
6262 ((fx= 1 (length args))
6263 (display ": " port)
6264 (writeargs args port))
6265 (else
6266 (newline port)
6267 (writeargs args port)))))
6268 ((string? ex)
6269 (display ": " port)
6270 (display ex port)
6271 (newline port))
6272 (else
6273 (display ": uncaught exception: " port)
6274 (writeargs (list ex) port) ) ) ) ) ) )
6275
6276
6277;;; Show exception message and backtrace as warning
6278;;; (used for threads and finalizers)
6279
6280(define ##sys#show-exception-warning
6281 (let ((print-error-message print-error-message)
6282 (display display)
6283 (write-char write-char)
6284 (print-call-chain print-call-chain)
6285 (open-output-string open-output-string)
6286 (get-output-string get-output-string) )
6287 (lambda (exn cause #!optional (thread ##sys#current-thread))
6288 (when ##sys#warnings-enabled
6289 (let ((o (open-output-string)))
6290 (display "Warning" o)
6291 (when thread
6292 (display " (" o)
6293 (display thread o)
6294 (write-char #\) o))
6295 (display ": " o)
6296 (display cause o)
6297 (print-error-message exn ##sys#standard-error (get-output-string o))
6298 (print-call-chain ##sys#standard-error 0 thread) ) ))))
6299
6300
6301;;; Error hook (called by runtime-system):
6302
6303(define ##sys#error-hook
6304 (let ([string-append string-append])
6305 (lambda (code loc . args)
6306 (case code
6307 ((1) (let ([c (car args)]
6308 [n (cadr args)]
6309 [fn (caddr args)] )
6310 (apply
6311 ##sys#signal-hook
6312 #:arity-error loc
6313 (string-append "bad argument count - received " (##sys#number->string n) " but expected "
6314 (##sys#number->string c) )
6315 (if fn (list fn) '())) ) )
6316 ((2) (let ([c (car args)]
6317 [n (cadr args)]
6318 [fn (caddr args)] )
6319 (apply
6320 ##sys#signal-hook
6321 #:arity-error loc
6322 (string-append "too few arguments - received " (##sys#number->string n) " but expected "
6323 (##sys#number->string c) )
6324 (if fn (list fn) '()))))
6325 ((3) (apply ##sys#signal-hook #:type-error loc "bad argument type" args))
6326 ((4) (apply ##sys#signal-hook #:runtime-error loc "unbound variable" args))
6327 ((5) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a keyword" args))
6328 ((6) (apply ##sys#signal-hook #:limit-error loc "out of memory" args))
6329 ((7) (apply ##sys#signal-hook #:arithmetic-error loc "division by zero" args))
6330 ((8) (apply ##sys#signal-hook #:bounds-error loc "out of range" args))
6331 ((9) (apply ##sys#signal-hook #:type-error loc "call of non-procedure" args))
6332 ((10) (apply ##sys#signal-hook #:arity-error loc "continuation cannot receive multiple values" args))
6333 ((11) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a non-cyclic list" args))
6334 ((12) (apply ##sys#signal-hook #:limit-error loc "recursion too deep" args))
6335 ((13) (apply ##sys#signal-hook #:type-error loc "inexact number cannot be represented as an exact number" args))
6336 ((14) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a proper list" args))
6337 ((15) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a fixnum" args))
6338 ((16) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a number" args))
6339 ((17) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a string" args))
6340 ((18) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a pair" args))
6341 ((19) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a list" args))
6342 ((20) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a character" args))
6343 ((21) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a vector" args))
6344 ((22) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a symbol" args))
6345 ((23) (apply ##sys#signal-hook #:limit-error loc "stack overflow" args))
6346 ((24) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a structure of the required type" args))
6347 ((25) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a bytevector" args))
6348 ((26) (apply ##sys#signal-hook #:type-error loc "locative refers to reclaimed object" args))
6349 ((27) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a block object" args))
6350 ((28) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a number vector" args))
6351 ((29) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an integer" args))
6352 ((30) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an unsigned integer" args))
6353 ((31) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a pointer" args))
6354 ((32) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a tagged pointer" args))
6355 ((33) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a flonum" args))
6356 ((34) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a procedure" args))
6357 ((35) (apply ##sys#signal-hook #:type-error loc "bad argument type - invalid base" args))
6358 ((36) (apply ##sys#signal-hook #:limit-error loc "recursion too deep or circular data encountered" args))
6359 ((37) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a boolean" args))
6360 ((38) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a locative" args))
6361 ((39) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a port" args))
6362 ((40) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a port of the correct type" args))
6363 ((41) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an input-port" args))
6364 ((42) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an output-port" args))
6365 ((43) (apply ##sys#signal-hook #:file-error loc "port already closed" args))
6366 ((44) (apply ##sys#signal-hook #:type-error loc "cannot represent string with NUL bytes as C string" args))
6367 ((45) (apply ##sys#signal-hook #:memory-error loc "segmentation violation" args))
6368 ((46) (apply ##sys#signal-hook #:arithmetic-error loc "floating-point exception" args))
6369 ((47) (apply ##sys#signal-hook #:runtime-error loc "illegal instruction" args))
6370 ((48) (apply ##sys#signal-hook #:memory-error loc "bus error" args))
6371 ((49) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an exact number" args))
6372 ((50) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an inexact number" args))
6373 ((51) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a real" args))
6374 ((52) (apply ##sys#signal-hook #:type-error loc "bad argument type - complex number has no ordering" args))
6375 ((53) (apply ##sys#signal-hook #:type-error loc "bad argument type - not an exact integer" args))
6376 ((54) (apply ##sys#signal-hook #:type-error loc "number does not fit in foreign type" args))
6377 ((55) (apply ##sys#signal-hook #:type-error loc "cannot compute absolute value of complex number" args))
6378 ((56) (let ((c (car args))
6379 (n (cadr args))
6380 (fn (caddr args)))
6381 (apply
6382 ##sys#signal-hook
6383 #:bounds-error loc
6384 (string-append "attempted rest argument access at index " (##sys#number->string n)
6385 " but rest list length is " (##sys#number->string c) )
6386 (if fn (list fn) '()))))
6387 ((57) (apply ##sys#signal-hook #:type-error loc "string contains invalid UTF-8 sequence" args))
6388 ((58) (apply ##sys#signal-hook #:type-error loc "bad argument type - numeric value exceeds range" args))
6389 (else (apply ##sys#signal-hook #:runtime-error loc "unknown internal error" args)) ) ) ) )
6390
6391) ; chicken.condition
6392
6393(import chicken.condition)
6394
6395;;; R7RS exceptions
6396
6397(define ##sys#r7rs-exn-handlers
6398 (make-parameter
6399 (let ((lst (list ##sys#current-exception-handler)))
6400 (set-cdr! lst lst)
6401 lst)))
6402
6403(define scheme#with-exception-handler
6404 (let ((eh ##sys#r7rs-exn-handlers))
6405 (lambda (handler thunk)
6406 (dynamic-wind
6407 (lambda ()
6408 ;; We might be interoperating with srfi-12 handlers set by intermediate
6409 ;; non-R7RS code, so check if a new handler was set in the meanwhile.
6410 (unless (eq? (car (eh)) ##sys#current-exception-handler)
6411 (eh (cons ##sys#current-exception-handler (eh))))
6412 (eh (cons handler (eh)))
6413 (set! ##sys#current-exception-handler handler))
6414 thunk
6415 (lambda ()
6416 (eh (cdr (eh)))
6417 (set! ##sys#current-exception-handler (car (eh))))))))
6418
6419(define scheme#raise
6420 (let ((eh ##sys#r7rs-exn-handlers))
6421 (lambda (obj)
6422 (scheme#with-exception-handler
6423 (cadr (eh))
6424 (lambda ()
6425 ((cadr (eh)) obj)
6426 ((car (eh))
6427 (make-property-condition
6428 'exn
6429 'message "exception handler returned"
6430 'arguments '()
6431 'location #f)))))))
6432
6433(define scheme#raise-continuable
6434 (let ((eh ##sys#r7rs-exn-handlers))
6435 (lambda (obj)
6436 (scheme#with-exception-handler
6437 (cadr (eh))
6438 (lambda ()
6439 ((cadr (eh)) obj))))))
6440
6441(define scheme#error-object? condition?)
6442(define scheme#error-object-message (condition-property-accessor 'exn 'message))
6443(define scheme#error-object-irritants (condition-property-accessor 'exn 'arguments))
6444
6445(define scheme#read-error?)
6446(define scheme#file-error?)
6447
6448(let ((exn? (condition-predicate 'exn))
6449 (i/o? (condition-predicate 'i/o))
6450 (file? (condition-predicate 'file))
6451 (syntax? (condition-predicate 'syntax)))
6452 (set! scheme#read-error?
6453 (lambda (obj)
6454 (and (exn? obj)
6455 (or (i/o? obj) ; XXX Not fine-grained enough.
6456 (syntax? obj)))))
6457 (set! scheme#file-error?
6458 (lambda (obj)
6459 (and (exn? obj)
6460 (file? obj)))))
6461
6462
6463;;; Miscellaneous low-level routines:
6464
6465(define (##sys#structure? x s) (##core#inline "C_i_structurep" x s))
6466(define (##sys#generic-structure? x) (##core#inline "C_structurep" x))
6467(define (##sys#slot x i) (##core#inline "C_slot" x i))
6468(define (##sys#size x) (##core#inline "C_block_size" x))
6469(define ##sys#make-pointer (##core#primitive "C_make_pointer"))
6470(define ##sys#make-tagged-pointer (##core#primitive "C_make_tagged_pointer"))
6471(define (##sys#pointer? x) (##core#inline "C_anypointerp" x))
6472(define (##sys#set-pointer-address! ptr addr) (##core#inline "C_update_pointer" addr ptr))
6473(define (##sys#bytevector? x) (##core#inline "C_bytevectorp" x))
6474(define (##sys#string->pbytevector s) (##core#inline "C_string_to_pbytevector" s))
6475(define (##sys#permanent? x) (##core#inline "C_permanentp" x))
6476(define (##sys#block-address x) (##core#inline_allocate ("C_block_address" 6) x))
6477(define (##sys#locative? x) (##core#inline "C_locativep" x))
6478
6479(define (##sys#srfi-4-vector? x)
6480 (or (##core#inline "C_i_srfi_4_vectorp" x)
6481 (and (##core#inline "C_blockp" x)
6482 (##core#inline "C_structurep" x)
6483 (let ((t (##sys#slot x 0)))
6484 (or (eq? t 'c64vector) (eq? t 'c128vector))))))
6485
6486(define (##sys#null-pointer)
6487 (let ([ptr (##sys#make-pointer)])
6488 (##core#inline "C_update_pointer" 0 ptr)
6489 ptr) )
6490
6491(define (##sys#null-pointer? x)
6492 (eq? 0 (##sys#pointer->address x)) )
6493
6494(define (##sys#address->pointer addr)
6495 (let ([ptr (##sys#make-pointer)])
6496 (##core#inline "C_update_pointer" addr ptr)
6497 ptr) )
6498
6499(define (##sys#pointer->address ptr)
6500 ;;XXX '6' is platform dependent!
6501 (##core#inline_allocate ("C_a_unsigned_int_to_num" 6) (##sys#slot ptr 0)) )
6502
6503(define (##sys#make-c-string str #!optional loc)
6504 (let ((bv (##sys#slot str 0)))
6505 (if (fx= (##core#inline "C_asciiz_strlen" bv) (fx- (##sys#size bv) 1))
6506 bv
6507 (##sys#error-hook (foreign-value "C_ASCIIZ_REPRESENTATION_ERROR" int)
6508 loc str))) )
6509
6510(define ##sys#peek-signed-integer (##core#primitive "C_peek_signed_integer"))
6511(define ##sys#peek-unsigned-integer (##core#primitive "C_peek_unsigned_integer"))
6512(define (##sys#peek-fixnum b i) (##core#inline "C_peek_fixnum" b i))
6513(define (##sys#peek-byte ptr i) (##core#inline "C_peek_byte" ptr i))
6514
6515(define (##sys#vector->structure! vec) (##core#inline "C_vector_to_structure" vec))
6516
6517(define (##sys#peek-double b i)
6518 (##core#inline_allocate ("C_a_f64peek" 4) b i))
6519
6520(define (##sys#peek-c-string b i)
6521 (and (not (##sys#null-pointer? b))
6522 (##sys#peek-nonnull-c-string b i)))
6523
6524(define (##sys#peek-nonnull-c-string b i)
6525 (let* ([len (##core#inline "C_fetch_c_strlen" b i)]
6526 [bv (##sys#make-bytevector (fx+ len 1) 0)] )
6527 (##core#inline "C_peek_c_string" b i bv len)
6528 (##sys#buffer->string bv 0 len)))
6529
6530(define (##sys#peek-and-free-c-string b i)
6531 (let ((str (##sys#peek-c-string b i)))
6532 (##core#inline "C_free_mptr" b i)
6533 str))
6534
6535(define (##sys#peek-and-free-nonnull-c-string b i)
6536 (let ((str (##sys#peek-nonnull-c-string b i)))
6537 (##core#inline "C_free_mptr" b i)
6538 str))
6539
6540(define (##sys#poke-c-string b i s)
6541 (##core#inline "C_poke_c_string" b i (##sys#make-c-string s) s) )
6542
6543(define (##sys#poke-integer b i n) (##core#inline "C_poke_integer" b i n))
6544(define (##sys#poke-double b i n) (##core#inline "C_poke_double" b i n))
6545
6546(define ##sys#peek-c-string-list
6547 (let ((fetch (foreign-lambda c-string "C_peek_c_string_at" c-pointer int)))
6548 (lambda (ptr n)
6549 (let loop ((i 0))
6550 (if (and n (fx>= i n))
6551 '()
6552 (let ((s (fetch ptr i)))
6553 (if s
6554 (cons s (loop (fx+ i 1)))
6555 '() ) ) ) ) ) ) )
6556
6557(define ##sys#peek-and-free-c-string-list
6558 (let ((fetch (foreign-lambda c-string "C_peek_c_string_at" c-pointer int))
6559 (free (foreign-lambda void "C_free" c-pointer)))
6560 (lambda (ptr n)
6561 (let ((lst (let loop ((i 0))
6562 (if (and n (fx>= i n))
6563 '()
6564 (let ((s (fetch ptr i)))
6565 (cond (s
6566 (##core#inline "C_free_sptr" ptr i)
6567 (cons s (loop (fx+ i 1))) )
6568 (else '() ) ) ) ) ) ) )
6569 (free ptr)
6570 lst) ) ) )
6571
6572(define (##sys#vector->closure! vec addr)
6573 (##core#inline "C_vector_to_closure" vec)
6574 (##core#inline "C_update_pointer" addr vec) )
6575
6576(define (##sys#symbol-has-toplevel-binding? s)
6577 (##core#inline "C_boundp" s))
6578
6579(define (##sys#block-pointer x)
6580 (let ([ptr (##sys#make-pointer)])
6581 (##core#inline "C_pointer_to_block" ptr x)
6582 ptr) )
6583
6584
6585;;; Support routines for foreign-function calling:
6586
6587(define (##sys#foreign-char-argument x) (##core#inline "C_i_foreign_char_argumentp" x))
6588(define (##sys#foreign-fixnum-argument x) (##core#inline "C_i_foreign_fixnum_argumentp" x))
6589(define (##sys#foreign-flonum-argument x) (##core#inline "C_i_foreign_flonum_argumentp" x))
6590(define (##sys#foreign-block-argument x) (##core#inline "C_i_foreign_block_argumentp" x))
6591
6592(define (##sys#foreign-cplxnum-argument x)
6593 (if (##core#inline "C_i_numberp" x)
6594 (##core#inline_allocate ("C_a_i_exact_to_inexact" 12) x)
6595 (##sys#signal-hook
6596 #:type-error #f "bad argument type - not a complex number"
6597 x)))
6598
6599(define (##sys#foreign-struct-wrapper-argument t x)
6600 (##core#inline "C_i_foreign_struct_wrapper_argumentp" t x))
6601
6602(define (##sys#foreign-string-argument x) (##core#inline "C_i_foreign_string_argumentp" x))
6603(define (##sys#foreign-symbol-argument x) (##core#inline "C_i_foreign_symbol_argumentp" x))
6604(define (##sys#foreign-pointer-argument x) (##core#inline "C_i_foreign_pointer_argumentp" x))
6605(define (##sys#foreign-tagged-pointer-argument x tx) (##core#inline "C_i_foreign_tagged_pointer_argumentp" x tx))
6606
6607(define (##sys#foreign-ranged-integer-argument obj size)
6608 (##core#inline "C_i_foreign_ranged_integer_argumentp" obj size))
6609(define (##sys#foreign-unsigned-ranged-integer-argument obj size)
6610 (##core#inline "C_i_foreign_unsigned_ranged_integer_argumentp" obj size))
6611
6612(define (##sys#wrap-struct type rec)
6613 (##sys#setslot rec 0 type)
6614 rec)
6615
6616;;; Low-level threading interface:
6617
6618(define ##sys#default-thread-quantum 10000)
6619
6620(define (##sys#default-exception-handler arg)
6621 (##core#inline "C_halt" "internal error: default exception handler shouldn't be called!") )
6622
6623(define (##sys#make-thread thunk state name q)
6624 (##sys#make-structure
6625 'thread
6626 thunk ; #1 thunk
6627 #f ; #2 result list
6628 state ; #3 state
6629 #f ; #4 block-timeout
6630 (vector ; #5 state buffer
6631 ##sys#dynamic-winds
6632 ##sys#standard-input
6633 ##sys#standard-output
6634 ##sys#standard-error
6635 ##sys#default-exception-handler
6636 (##sys#vector-resize ##sys#current-parameter-vector
6637 (##sys#size ##sys#current-parameter-vector) #f) )
6638 name ; #6 name
6639 (##core#undefined) ; #7 end-exception
6640 '() ; #8 owned mutexes
6641 q ; #9 quantum
6642 (##core#undefined) ; #10 specific
6643 #f ; #11 block object (type depends on blocking type)
6644 '() ; #12 recipients
6645 #f ; #13 unblocked by timeout?
6646 (cons #f #f))) ; #14 ID (just needs to be unique)
6647
6648(define ##sys#primordial-thread
6649 (##sys#make-thread #f 'running 'primordial ##sys#default-thread-quantum))
6650
6651(define ##sys#current-thread ##sys#primordial-thread)
6652
6653(define (##sys#make-mutex id owner)
6654 (##sys#make-structure
6655 'mutex
6656 id ; #1 name
6657 owner ; #2 thread or #f
6658 '() ; #3 list of waiting threads
6659 #f ; #4 abandoned
6660 #f ; #5 locked
6661 (##core#undefined) ) ) ; #6 specific
6662
6663(define (##sys#schedule) ((##sys#slot ##sys#current-thread 1)))
6664
6665(define (##sys#thread-yield!)
6666 (##sys#call-with-current-continuation
6667 (lambda (return)
6668 (let ((ct ##sys#current-thread))
6669 (##sys#setslot ct 1 (lambda () (return (##core#undefined))))
6670 (##sys#schedule) ) ) ) )
6671
6672(define (##sys#kill-other-threads thunk)
6673 (thunk)) ; does nothing, will be modified by scheduler.scm
6674
6675;; these two procedures should redefined in thread APIs (e.g. srfi-18):
6676(define (##sys#resume-thread-on-event t) #f)
6677
6678(define (##sys#suspend-thread-on-event t)
6679 ;; wait until signal handler fires. If we are only waiting for a finalizer,
6680 ;; then this will wait forever:
6681 (##sys#sleep-until-interrupt))
6682
6683(define (##sys#sleep-until-interrupt)
6684 (##core#inline "C_i_sleep_until_interrupt" 100)
6685 (##sys#dispatch-interrupt (lambda _ #f)))
6686
6687
6688;;; event queues (for signals and finalizers)
6689
6690(define (##sys#make-event-queue)
6691 (##sys#make-structure 'event-queue
6692 '() ; head
6693 '() ; tail
6694 #f)) ; suspended thread
6695
6696(define (##sys#add-event-to-queue! q e)
6697 (let ((h (##sys#slot q 1))
6698 (t (##sys#slot q 2))
6699 (item (cons e '())))
6700 (if (null? h)
6701 (##sys#setslot q 1 item)
6702 (##sys#setslot t 1 item))
6703 (##sys#setslot q 2 item)
6704 (let ((st (##sys#slot q 3))) ; thread suspended?
6705 (when st
6706 (##sys#setslot q 3 #f)
6707 (##sys#resume-thread-on-event st)))))
6708
6709(define (##sys#get-next-event q)
6710 (let ((st (##sys#slot q 3)))
6711 (and (not st)
6712 (let ((h (##sys#slot q 1)))
6713 (and (not (null? h))
6714 (let ((x (##sys#slot h 0))
6715 (n (##sys#slot h 1)))
6716 (##sys#setslot q 1 n)
6717 (when (null? n) (##sys#setslot q 2 '()))
6718 x))))))
6719
6720(define (##sys#wait-for-next-event q)
6721 (let ((st (##sys#slot q 3)))
6722 (when st
6723 (##sys#signal-hook #:runtime-error #f "event queue blocked" q))
6724 (let again ()
6725 (let ((h (##sys#slot q 1)))
6726 (cond ((null? h)
6727 (##sys#setslot q 3 ##sys#current-thread)
6728 (##sys#suspend-thread-on-event ##sys#current-thread)
6729 (again))
6730 (else
6731 (let ((x (##sys#slot h 0))
6732 (n (##sys#slot h 1)))
6733 (##sys#setslot q 1 n)
6734 (when (null? n) (##sys#setslot q 2 '()))
6735 x)))))))
6736
6737
6738;;; Sleeping:
6739
6740(define (chicken.base#sleep-hook n) ; modified by scheduler.scm
6741 (##core#inline "C_i_process_sleep" n))
6742
6743(set! chicken.base#sleep
6744 (lambda (n)
6745 (##sys#check-fixnum n 'sleep)
6746 (chicken.base#sleep-hook n)
6747 (##core#undefined)))
6748
6749
6750;;; Interrupt-handling:
6751
6752(define ##sys#context-switch (##core#primitive "C_context_switch"))
6753
6754(define ##sys#signal-vector (make-vector 256 #f))
6755
6756(define (##sys#interrupt-hook reason state)
6757 (let loop ((reason reason))
6758 (when reason
6759 (let ((handler (##sys#slot ##sys#signal-vector reason)))
6760 (when handler
6761 (handler reason))
6762 (loop (##core#inline "C_i_pending_interrupt" #f)))))
6763 (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
6764 (##sys#run-pending-finalizers state) )
6765 ((procedure? state) (state))
6766 (else (##sys#context-switch state) ) ) )
6767
6768(define (##sys#dispatch-interrupt k)
6769 (##sys#interrupt-hook
6770 (##core#inline "C_i_pending_interrupt" #f)
6771 k))
6772
6773
6774;;; Accessing "errno":
6775
6776(define-foreign-variable _errno int "errno")
6777
6778(define ##sys#update-errno)
6779(define ##sys#errno)
6780
6781(let ((n 0))
6782 (set! ##sys#update-errno (lambda () (set! n _errno) n))
6783 (set! ##sys#errno (lambda () n)))
6784
6785
6786;;; Format error string for unterminated here-docs:
6787
6788(define (##sys#format-here-doc-warning end)
6789 (##sys#print-to-string `("unterminated here-doc string literal `" ,end "'")))
6790
6791;;; Special string quoting syntax:
6792
6793(set! ##sys#user-read-hook
6794 (let ([old ##sys#user-read-hook]
6795 [read read]
6796 [display display] )
6797 (define (readln port)
6798 (let ([ln (open-output-string)])
6799 (do ([c (##sys#read-char-0 port) (##sys#read-char-0 port)])
6800 ((or (eof-object? c) (char=? #\newline c))
6801 (if (eof-object? c) c (get-output-string ln)))
6802 (##sys#write-char-0 c ln) ) ) )
6803 (define (read-escaped-sexp port skip-brace?)
6804 (when skip-brace? (##sys#read-char-0 port))
6805 (let* ((form (read port)))
6806 (when skip-brace?
6807 (let loop ()
6808 ;; Skips all characters until #\}
6809 (let ([c (##sys#read-char-0 port)])
6810 (cond [(eof-object? c)
6811 (##sys#read-error port "unexpected end of file - unterminated `#{...}' item in `here' string literal") ]
6812 [(not (char=? #\} c)) (loop)] ) ) ) )
6813 form))
6814 (lambda (char port)
6815 (cond [(not (char=? #\< char)) (old char port)]
6816 [else
6817 (read-char port)
6818 (case (##sys#peek-char-0 port)
6819 [(#\<)
6820 (##sys#read-char-0 port)
6821 (let ([str (open-output-string)]
6822 [end (readln port)]
6823 [f #f] )
6824 (let ((endlen (if (eof-object? end) 0 (string-length end))))
6825 (cond
6826 ((fx= endlen 0)
6827 (##sys#read-warning
6828 port "Missing tag after #<< here-doc token"))
6829 ((or (char=? (string-ref end (fx- endlen 1)) #\space)
6830 (char=? (string-ref end (fx- endlen 1)) #\tab))
6831 (##sys#read-warning
6832 port "Whitespace after #<< here-doc tag"))
6833 ))
6834 (do ([ln (readln port) (readln port)])
6835 ((or (eof-object? ln) (string=? end ln))
6836 (when (eof-object? ln)
6837 (##sys#read-warning port
6838 (##sys#format-here-doc-warning end)))
6839 (get-output-string str) )
6840 (if f
6841 (##sys#write-char-0 #\newline str)
6842 (set! f #t) )
6843 (display ln str) ) ) ]
6844 [(#\#)
6845 (##sys#read-char-0 port)
6846 (let ([end (readln port)]
6847 [str (open-output-string)] )
6848 (define (get/clear-str)
6849 (let ((s (get-output-string str)))
6850 (set! str (open-output-string))
6851 s))
6852
6853 (let ((endlen (if (eof-object? end) 0 (string-length end))))
6854 (cond
6855 ((fx= endlen 0)
6856 (##sys#read-warning
6857 port "Missing tag after #<# here-doc token"))
6858 ((or (char=? (string-ref end (fx- endlen 1)) #\space)
6859 (char=? (string-ref end (fx- endlen 1)) #\tab))
6860 (##sys#read-warning
6861 port "Whitespace after #<# here-doc tag"))
6862 ))
6863
6864 (let loop [(lst '())]
6865 (let ([c (##sys#read-char-0 port)])
6866 (case c
6867 [(#\newline #!eof)
6868 (let ([s (get/clear-str)])
6869 (cond [(or (eof-object? c) (string=? end s))
6870 (when (eof-object? c)
6871 (##sys#read-warning
6872 port (##sys#format-here-doc-warning end)))
6873 `(##sys#print-to-string
6874 ;;Can't just use `(list ,@lst) because of 126 argument apply limit
6875 ,(let loop2 ((lst (cdr lst)) (next-string '()) (acc ''())) ; drop last newline
6876 (cond ((null? lst)
6877 `(cons ,(##sys#print-to-string next-string) ,acc))
6878 ((or (string? (car lst)) (char? (car lst)))
6879 (loop2 (cdr lst) (cons (car lst) next-string) acc))
6880 (else
6881 (loop2 (cdr lst)
6882 '()
6883 `(cons ,(car lst)
6884 (cons ,(##sys#print-to-string next-string) ,acc))))))) ]
6885 [else (loop (cons #\newline (cons s lst)))] ) ) ]
6886 [(#\#)
6887 (let ([c (##sys#peek-char-0 port)])
6888 (case c
6889 [(#\#)
6890 (##sys#write-char-0 (##sys#read-char-0 port) str)
6891 (loop lst) ]
6892 [(#\{) (loop (cons (read-escaped-sexp port #t)
6893 (cons (get/clear-str) lst) ) ) ]
6894 [else (loop (cons (read-escaped-sexp port #f)
6895 (cons (get/clear-str) lst) ) ) ] ) ) ]
6896 [else
6897 (##sys#write-char-0 c str)
6898 (loop lst) ] ) ) ) ) ]
6899 [else (##sys#read-error port "unreadable object")] ) ] ) ) ) )
6900
6901
6902;;; Accessing process information (cwd, environ, etc.)
6903
6904#>
6905
6906#define C_chdir(str) C_fix(chdir(C_c_string(str)))
6907#define C_curdir(buf, size) (getcwd(C_c_string(buf), size) ? C_fix(strlen(C_c_string(buf))) : C_SCHEME_FALSE)
6908
6909<#
6910
6911(module chicken.process-context
6912 (argv argc+argv command-line-arguments
6913 program-name executable-pathname
6914 change-directory current-directory
6915 get-environment-variable get-environment-variables
6916 set-environment-variable! unset-environment-variable!)
6917
6918(import scheme)
6919(import chicken.base chicken.fixnum chicken.foreign)
6920(import chicken.internal.syntax)
6921(import (only (scheme base) make-parameter))
6922
6923;;; Current directory access:
6924
6925(define (change-directory name)
6926 (##sys#check-string name 'change-directory)
6927 (let ((sname (##sys#make-c-string name 'change-directory)))
6928 (unless (fx= (##core#inline "C_chdir" sname) 0)
6929 (##sys#signal-hook/errno #:file-error (##sys#update-errno) 'change-directory
6930 (string-append "cannot change current directory - " strerror) name))
6931 name))
6932
6933(define (##sys#change-directory-hook dir) ; set! by posix for fd support
6934 (change-directory dir))
6935
6936(define current-directory
6937 (getter-with-setter
6938 (lambda ()
6939 (let* ((buffer-size (foreign-value "C_MAX_PATH" size_t))
6940 (buffer (##sys#make-bytevector buffer-size))
6941 (len (##core#inline "C_curdir" buffer buffer-size)))
6942 (unless ##sys#windows-platform ; FIXME need `cond-expand' here
6943 (##sys#update-errno))
6944 (if len
6945 (##sys#buffer->string buffer 0 len)
6946 (##sys#signal-hook/errno
6947 #:file-error
6948 (##sys#errno)
6949 'current-directory "cannot retrieve current directory"))))
6950 (lambda (dir)
6951 (##sys#change-directory-hook dir))
6952 "(chicken.process-context#current-directory)"))
6953
6954
6955;;; Environment access:
6956
6957(define _getenv
6958 (foreign-lambda c-string "C_getenv" scheme-object))
6959
6960(define (get-environment-variable var)
6961 (_getenv (##sys#make-c-string var 'get-environment-variable)))
6962
6963(define get-environment-entry
6964 (foreign-lambda c-string* "C_getenventry" int))
6965
6966(define (set-environment-variable! var val)
6967 (##sys#check-string var 'set-environment-variable!)
6968 (##core#inline "C_i_setenv"
6969 (##sys#make-c-string var 'set-environment-variable!)
6970 (and val
6971 (begin
6972 (##sys#check-string val 'set-environment-variable!)
6973 (##sys#make-c-string val 'set-environment-variable!))))
6974 (##core#undefined))
6975
6976(define (unset-environment-variable! var)
6977 (##sys#check-string var 'unset-environment-variable!)
6978 (##core#inline "C_i_setenv"
6979 (##sys#make-c-string var 'unset-environment-variable!)
6980 #f)
6981 (##core#undefined))
6982
6983(define get-environment-variables
6984 (lambda ()
6985 (let loop ((i 0))
6986 (let ((entry (get-environment-entry i)))
6987 (if entry
6988 (let scan ((j 0))
6989 (if (char=? #\= (string-ref entry j))
6990 (cons (cons (##sys#substring entry 0 j)
6991 (##sys#substring entry (fx+ j 1) (string-length entry)))
6992 (loop (fx+ i 1)))
6993 (scan (fx+ j 1))))
6994 '())))))
6995
6996
6997;;; Command line handling
6998
6999(define-foreign-variable main_argc int "C_main_argc")
7000(define-foreign-variable main_argv c-pointer "C_main_argv")
7001
7002(define executable-pathname
7003 (foreign-lambda c-string* "C_executable_pathname"))
7004
7005(define (argc+argv)
7006 (##sys#values main_argc main_argv))
7007
7008(define argv ; includes program name
7009 (let ((cache #f)
7010 (fetch-arg (foreign-lambda* c-string ((scheme-object i))
7011 "C_return(C_main_argv[C_unfix(i)]);")))
7012 (lambda ()
7013 (unless cache
7014 (set! cache (do ((i (fx- main_argc 1) (fx- i 1))
7015 (v '() (cons (fetch-arg i) v)))
7016 ((fx< i 0) v))))
7017 cache)))
7018
7019(define program-name
7020 (make-parameter
7021 (if (null? (argv))
7022 "<unknown>" ; may happen if embedded in C application
7023 (car (argv)))
7024 (lambda (x)
7025 (##sys#check-string x 'program-name)
7026 x) ) )
7027
7028(define command-line-arguments
7029 (make-parameter
7030 (let ((args (argv)))
7031 (if (pair? args)
7032 (let loop ((args (##sys#slot args 1))) ; Skip over program name (argv[0])
7033 (if (null? args)
7034 '()
7035 (let ((arg (##sys#slot args 0))
7036 (rest (##sys#slot args 1)) )
7037 (cond
7038 ((string=? "-:" arg) ; Consume first "empty" runtime options list, return rest
7039 rest)
7040
7041 ((and (fx>= (string-length arg) 3)
7042 (string=? "-:" (##sys#substring arg 0 2)))
7043 (loop rest))
7044
7045 ;; First non-runtime option and everything following it is returned as-is
7046 (else args) ) ) ) )
7047 args) )
7048 (lambda (x)
7049 (##sys#check-list x 'command-line-arguments)
7050 x) ) )
7051
7052) ; chicken.process-context
7053
7054
7055(module chicken.gc
7056 (current-gc-milliseconds gc memory-statistics
7057 set-finalizer! make-finalizer add-to-finalizer
7058 set-gc-report! force-finalizers)
7059
7060(import scheme)
7061(import chicken.base chicken.fixnum chicken.foreign)
7062(import chicken.internal.syntax)
7063(import (only (scheme base) make-parameter))
7064
7065;;; GC info:
7066
7067(define (current-gc-milliseconds)
7068 (##core#inline "C_i_accumulated_gc_time"))
7069
7070(define (set-gc-report! flag)
7071 (##core#inline "C_set_gc_report" flag))
7072
7073;;; Memory info:
7074
7075(define (memory-statistics)
7076 (let* ((free (##sys#gc #t))
7077 (info (##sys#memory-info))
7078 (half-size (fx/ (##sys#slot info 0) 2)))
7079 (vector half-size (fx- half-size free) (##sys#slot info 1))))
7080
7081;;; Finalization:
7082
7083(define-foreign-variable _max_pending_finalizers int "C_max_pending_finalizers")
7084
7085(define ##sys#pending-finalizers
7086 (##sys#make-vector (fx+ (fx* 2 _max_pending_finalizers) 1) (##core#undefined)) )
7087
7088(##sys#setislot ##sys#pending-finalizers 0 0)
7089
7090(define ##sys#set-finalizer! (##core#primitive "C_register_finalizer"))
7091
7092(define ##sys#init-finalizer
7093 (let ((string-append string-append))
7094 (lambda (x y)
7095 (when (fx>= (##core#inline "C_i_live_finalizer_count") _max_pending_finalizers)
7096 (cond ((##core#inline "C_resize_pending_finalizers" (fx* 2 _max_pending_finalizers))
7097 (set! ##sys#pending-finalizers
7098 (##sys#vector-resize ##sys#pending-finalizers
7099 (fx+ (fx* 2 _max_pending_finalizers) 1)
7100 (##core#undefined)))
7101 (when (##sys#debug-mode?)
7102 (##sys#print
7103 (string-append
7104 "[debug] too many finalizers ("
7105 (##sys#number->string
7106 (##core#inline "C_i_live_finalizer_count"))
7107 "), resized max finalizers to "
7108 (##sys#number->string _max_pending_finalizers)
7109 "\n")
7110 #f ##sys#standard-error)))
7111 (else
7112 (when (##sys#debug-mode?)
7113 (##sys#print
7114 (string-append
7115 "[debug] too many finalizers ("
7116 (##core#inline "C_i_live_finalizer_count")
7117 "), forcing ...\n")
7118 #f ##sys#standard-error))
7119 (##sys#force-finalizers) ) ) )
7120 (##sys#set-finalizer! x y) ) ) )
7121
7122(define set-finalizer! ##sys#init-finalizer)
7123
7124(define finalizer-tag (vector 'finalizer))
7125
7126(define (finalizer? x)
7127 (and (pair? x) (eq? finalizer-tag (##sys#slot x 0))) )
7128
7129(define (make-finalizer . objects)
7130 (let ((q (##sys#make-event-queue)))
7131 (define (handler o) (##sys#add-event-to-queue! q o))
7132 (define (handle o) (##sys#init-finalizer o handler))
7133 (for-each handle objects)
7134 (##sys#decorate-lambda
7135 (lambda (#!optional mode)
7136 (if mode
7137 (##sys#wait-for-next-event q)
7138 (##sys#get-next-event q)))
7139 finalizer?
7140 (lambda (proc i)
7141 (##sys#setslot proc i (cons finalizer-tag handle))
7142 proc))))
7143
7144(define (add-to-finalizer f . objects)
7145 (let ((af (and (procedure? f)
7146 (##sys#lambda-decoration f finalizer?))))
7147 (unless af
7148 (error 'add-to-finalizer "bad argument type - not a finalizer procedure"
7149 f))
7150 (for-each (cdr af) objects)))
7151
7152(define ##sys#run-pending-finalizers
7153 (let ((vector-fill! vector-fill!)
7154 (string-append string-append)
7155 (working-thread #f) )
7156 (lambda (state)
7157 (cond
7158 ((not working-thread)
7159 (set! working-thread ##sys#current-thread)
7160 (let* ((c (##sys#slot ##sys#pending-finalizers 0)) )
7161 (when (##sys#debug-mode?)
7162 (##sys#print
7163 (string-append "[debug] running " (##sys#number->string c)
7164 " finalizer(s) ("
7165 (##sys#number->string
7166 (##core#inline "C_i_live_finalizer_count"))
7167 " live, "
7168 (##sys#number->string
7169 (##core#inline "C_i_allocated_finalizer_count"))
7170 " allocated) ...\n")
7171 #f ##sys#standard-error))
7172 (do ([i 0 (fx+ i 1)])
7173 ((fx>= i c))
7174 (let ([i2 (fx+ 1 (fx* i 2))])
7175 (handle-exceptions ex
7176 (##sys#show-exception-warning ex "in finalizer" #f)
7177 ((##sys#slot ##sys#pending-finalizers (fx+ i2 1))
7178 (##sys#slot ##sys#pending-finalizers i2)) ) ))
7179 (vector-fill! ##sys#pending-finalizers (##core#undefined))
7180 (##sys#setislot ##sys#pending-finalizers 0 0)
7181 (set! working-thread #f)))
7182 (state) ; Got here due to interrupt; continue w/o error
7183 ((eq? working-thread ##sys#current-thread)
7184 (##sys#signal-hook
7185 #:error '##sys#run-pending-finalizers
7186 "re-entry from finalizer thread (maybe (gc #t) was called from a finalizer)"))
7187 (else
7188 ;; Give finalizer thread a change to run
7189 (##sys#thread-yield!)))
7190 (cond ((not state))
7191 ((procedure? state) (state))
7192 (state (##sys#context-switch state) ) ) ) ))
7193
7194(define force-finalizers (make-parameter #t))
7195
7196(define (##sys#force-finalizers)
7197 (let loop ()
7198 (let ([n (##sys#gc)])
7199 (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
7200 (##sys#run-pending-finalizers #f)
7201 (loop) )
7202 (else n) ) ) ))
7203
7204(define (gc . arg)
7205 (let ((a (and (pair? arg) (car arg))))
7206 (if a
7207 (##sys#force-finalizers)
7208 (##sys#gc a)))))
7209
7210;;; Auxilliary definitions for safe use in quasiquoted forms and evaluated code:
7211
7212(define ##sys#list->vector list->vector)
7213(define ##sys#list list)
7214(define ##sys#length length)
7215(define ##sys#cons cons)
7216(define ##sys#append append)
7217(define ##sys#vector vector)
7218(define ##sys#apply apply)
7219(define ##sys#values values)
7220(define ##sys#equal? equal?)
7221(define ##sys#car car)
7222(define ##sys#cdr cdr)
7223(define ##sys#pair? pair?)
7224(define ##sys#vector? vector?)
7225(define ##sys#vector->list vector->list)
7226(define ##sys#vector-length vector-length)
7227(define ##sys#vector-ref vector-ref)
7228(define ##sys#>= >=)
7229(define ##sys#= =)
7230(define ##sys#+ +)
7231(define ##sys#eq? eq?)
7232(define ##sys#eqv? eqv?)
7233(define ##sys#list? list?)
7234(define ##sys#null? null?)
7235(define ##sys#map-n map)
7236
7237;;; We need this here so `location' works:
7238
7239(define (##sys#make-locative obj index weak? loc)
7240 (cond [(##sys#immediate? obj)
7241 (##sys#signal-hook #:type-error loc "locative cannot refer to immediate object" obj) ]
7242 [(or (vector? obj) (pair? obj))
7243 (##sys#check-range index 0 (##sys#size obj) loc)
7244 (##core#inline_allocate ("C_a_i_make_locative" 5) 0 obj index weak?) ]
7245 [(and (##core#inline "C_blockp" obj)
7246 (##core#inline "C_bytevectorp" obj) )
7247 (##sys#check-range index 0 (##sys#size obj) loc)
7248 (##core#inline_allocate ("C_a_i_make_locative" 5) 2 obj index weak?) ]
7249 [(##sys#generic-structure? obj)
7250 (case (##sys#slot obj 0)
7251 ((u8vector)
7252 (let ([v (##sys#slot obj 1)])
7253 (##sys#check-range index 0 (##sys#size v) loc)
7254 (##core#inline_allocate ("C_a_i_make_locative" 5) 2 v index weak?)) )
7255 ((s8vector)
7256 (let ([v (##sys#slot obj 1)])
7257 (##sys#check-range index 0 (##sys#size v) loc)
7258 (##core#inline_allocate ("C_a_i_make_locative" 5) 3 v index weak?) ) )
7259 ((u16vector)
7260 (let ([v (##sys#slot obj 1)])
7261 (##sys#check-range index 0 (##sys#size v) loc)
7262 (##core#inline_allocate ("C_a_i_make_locative" 5) 4 v index weak?) ) )
7263 ((s16vector)
7264 (let ([v (##sys#slot obj 1)])
7265 (##sys#check-range index 0 (##sys#size v) loc)
7266 (##core#inline_allocate ("C_a_i_make_locative" 5) 5 v index weak?) ) )
7267 ((u32vector)
7268 (let ([v (##sys#slot obj 1)])
7269 (##sys#check-range index 0 (##sys#size v) loc)
7270 (##core#inline_allocate ("C_a_i_make_locative" 5) 6 v index weak?) ) )
7271 ((s32vector)
7272 (let ([v (##sys#slot obj 1)])
7273 (##sys#check-range index 0 (##sys#size v) loc)
7274 (##core#inline_allocate ("C_a_i_make_locative" 5) 7 v index weak?) ) )
7275 ((u64vector)
7276 (let ([v (##sys#slot obj 1)])
7277 (##sys#check-range index 0 (##sys#size v) loc)
7278 (##core#inline_allocate ("C_a_i_make_locative" 5) 8 v index weak?) ) )
7279 ((s64vector)
7280 (let ([v (##sys#slot obj 1)])
7281 (##sys#check-range index 0 (##sys#size v) loc)
7282 (##core#inline_allocate ("C_a_i_make_locative" 5) 9 v index weak?) ) )
7283 ((f32vector)
7284 (let ([v (##sys#slot obj 1)])
7285 (##sys#check-range index 0 (##sys#size v) loc)
7286 (##core#inline_allocate ("C_a_i_make_locative" 5) 10 v index weak?) ) )
7287 ((f64vector)
7288 (let ([v (##sys#slot obj 1)])
7289 (##sys#check-range index 0 (##sys#size v) loc)
7290 (##core#inline_allocate ("C_a_i_make_locative" 5) 11 v index weak?) ) )
7291 ;;XXX pointer-vector currently not supported
7292 (else
7293 (##sys#check-range index 0 (fx- (##sys#size obj) 1) loc)
7294 (##core#inline_allocate ("C_a_i_make_locative" 5) 0 obj (fx+ index 1) weak?) ) ) ]
7295 ((string? obj)
7296 (let ((bv (##sys#slot obj 0))
7297 (p (##core#inline "C_utf_position" obj index)))
7298 (##sys#check-range index 0 (##sys#slot obj 1) loc)
7299 (##core#inline_allocate ("C_a_i_make_locative" 5) 1 bv p weak?) ) )
7300 [else
7301 (##sys#signal-hook
7302 #:type-error loc
7303 "bad argument type - locative cannot refer to objects of this type"
7304 obj) ] ) )
7305
7306
7307;;; Property lists
7308
7309(module chicken.plist
7310 (get get-properties put! remprop! symbol-plist)
7311
7312(import scheme)
7313(import (only chicken.base getter-with-setter))
7314(import chicken.internal.syntax)
7315
7316(define (put! sym prop val)
7317 (##sys#check-symbol sym 'put!)
7318 (##core#inline_allocate ("C_a_i_putprop" 8) sym prop val) )
7319
7320(define (get sym prop #!optional default)
7321 (##sys#check-symbol sym 'get)
7322 (##core#inline "C_i_getprop" sym prop default))
7323
7324(define ##sys#put! put!)
7325(define ##sys#get get)
7326
7327(set! get (getter-with-setter get put!))
7328
7329(define (remprop! sym prop)
7330 (##sys#check-symbol sym 'remprop!)
7331 (let loop ((plist (##sys#slot sym 2)) (ptl #f))
7332 (and (not (null? plist))
7333 (let* ((tl (##sys#slot plist 1))
7334 (nxt (##sys#slot tl 1)))
7335 (or (and (eq? (##sys#slot plist 0) prop)
7336 (begin
7337 (if ptl
7338 (##sys#setslot ptl 1 nxt)
7339 (##sys#setslot sym 2 nxt) )
7340 #t ) )
7341 (loop nxt tl) ) ) ) )
7342 (when (null? (##sys#slot sym 2))
7343 ;; This will only unpersist if symbol is also unbound
7344 (##core#inline "C_i_unpersist_symbol" sym) ) )
7345
7346(define symbol-plist
7347 (getter-with-setter
7348 (lambda (sym)
7349 (##sys#check-symbol sym 'symbol-plist)
7350 (##sys#slot sym 2) )
7351 (lambda (sym lst)
7352 (##sys#check-symbol sym 'symbol-plist)
7353 (##sys#check-list lst 'symbol-plist/setter)
7354 (if (##core#inline "C_i_fixnumevenp" (##core#inline "C_i_length" lst))
7355 (##sys#setslot sym 2 lst)
7356 (##sys#signal-hook
7357 #:type-error "property-list must be of even length"
7358 lst sym))
7359 (if (null? lst)
7360 (##core#inline "C_i_unpersist_symbol" sym)
7361 (##core#inline "C_i_persist_symbol" sym)))
7362 "(chicken.plist#symbol-plist sym)"))
7363
7364(define (get-properties sym props)
7365 (##sys#check-symbol sym 'get-properties)
7366 (when (symbol? props)
7367 (set! props (list props)) )
7368 (##sys#check-list props 'get-properties)
7369 (let loop ((plist (##sys#slot sym 2)))
7370 (if (null? plist)
7371 (values #f #f #f)
7372 (let* ((prop (##sys#slot plist 0))
7373 (tl (##sys#slot plist 1))
7374 (nxt (##sys#slot tl 1)))
7375 (if (memq prop props)
7376 (values prop (##sys#slot tl 0) nxt)
7377 (loop nxt) ) ) ) ) )
7378
7379) ; chicken.plist
7380
7381
7382;;; Print timing information (support for "time" macro):
7383
7384(define (##sys#display-times info)
7385 (define (pstr str) (##sys#print str #f ##sys#standard-error))
7386 (define (pchr chr) (##sys#write-char-0 chr ##sys#standard-error))
7387 (define (pnum num)
7388 (##sys#print (if (zero? num) "0" (##sys#number->string num)) #f ##sys#standard-error))
7389 (define (round-to x y) ; Convert to fp with y digits after the point
7390 (/ (round (* x (expt 10 y))) (expt 10.0 y)))
7391 (define (pmem bytes)
7392 (cond ((> bytes (expt 1024 3))
7393 (pnum (round-to (/ bytes (expt 1024 3)) 2)) (pstr " GiB"))
7394 ((> bytes (expt 1024 2))
7395 (pnum (round-to (/ bytes (expt 1024 2)) 2)) (pstr " MiB"))
7396 ((> bytes 1024)
7397 (pnum (round-to (/ bytes 1024) 2)) (pstr " KiB"))
7398 (else (pnum bytes) (pstr " bytes"))))
7399 (##sys#flush-output ##sys#standard-output)
7400 (pnum (##sys#slot info 0))
7401 (pstr "s CPU time")
7402 (let ((gctime (##sys#slot info 1)))
7403 (when (> gctime 0)
7404 (pstr ", ")
7405 (pnum gctime)
7406 (pstr "s GC time (major)")))
7407 (let ((mut (##sys#slot info 2))
7408 (umut (##sys#slot info 3)))
7409 (when (fx> mut 0)
7410 (pstr ", ")
7411 (pnum mut)
7412 (pchr #\/)
7413 (pnum umut)
7414 (pstr " mutations (total/tracked)")))
7415 (let ((minor (##sys#slot info 4))
7416 (major (##sys#slot info 5)))
7417 (when (or (fx> minor 0) (fx> major 0))
7418 (pstr ", ")
7419 (pnum major)
7420 (pchr #\/)
7421 (pnum minor)
7422 (pstr " GCs (major/minor)")))
7423 (let ((maximum-heap-usage (##sys#slot info 6)))
7424 (pstr ", maximum live heap: ")
7425 (pmem maximum-heap-usage))
7426 (##sys#write-char-0 #\newline ##sys#standard-error)
7427 (##sys#flush-output ##sys#standard-error))
7428
7429
7430;;; Dump heap state to stderr:
7431
7432(define ##sys#dump-heap-state (##core#primitive "C_dump_heap_state"))
7433(define ##sys#filter-heap-objects (##core#primitive "C_filter_heap_objects"))
7434
7435
7436;;; Platform configuration inquiry:
7437
7438(module chicken.platform
7439 (build-platform chicken-version chicken-home
7440 feature? machine-byte-order machine-type
7441 repository-path installation-repository
7442 register-feature! unregister-feature! include-path
7443 software-type software-version return-to-host
7444 system-config-directory system-cache-directory
7445 )
7446
7447(import scheme)
7448(import chicken.fixnum chicken.foreign chicken.keyword chicken.process-context)
7449(import chicken.internal.syntax)
7450(import (only (scheme base) make-parameter))
7451
7452(define software-type
7453 (let ((sym (string->symbol ((##core#primitive "C_software_type")))))
7454 (lambda () sym)))
7455
7456(define machine-type
7457 (let ((sym (string->symbol ((##core#primitive "C_machine_type")))))
7458 (lambda () sym)))
7459
7460(define machine-byte-order
7461 (let ((sym (string->symbol ((##core#primitive "C_machine_byte_order")))))
7462 (lambda () sym)))
7463
7464(define software-version
7465 (let ((sym (string->symbol ((##core#primitive "C_software_version")))))
7466 (lambda () sym)))
7467
7468(define build-platform
7469 (let ((sym (string->symbol ((##core#primitive "C_build_platform")))))
7470 (lambda () sym)))
7471
7472(define ##sys#windows-platform
7473 (and (eq? 'windows (software-type))
7474 ;; Still windows even if 'Linux-like'
7475 (not (eq? 'cygwin (software-version)))))
7476
7477(define (chicken-version #!optional full)
7478 (define (get-config)
7479 (let ((bp (build-platform))
7480 (st (software-type))
7481 (sv (software-version))
7482 (mt (machine-type)))
7483 (define (str x)
7484 (if (eq? 'unknown x)
7485 ""
7486 (string-append (symbol->string x) "-")))
7487 (string-append (str sv) (str st) (str bp) (##sys#symbol->string/shared mt))))
7488 (if full
7489 (let ((spec (string-append
7490 " " (number->string (foreign-value "C_WORD_SIZE" int)) "bit"
7491 (if (feature? #:dload) " dload" "")
7492 (if (feature? #:ptables) " ptables" "")
7493 (if (feature? #:gchooks) " gchooks" "")
7494 (if (feature? #:cross-chicken) " cross" ""))))
7495 (string-append
7496 "Version " ##sys#build-version
7497 (if ##sys#build-branch (string-append " (" ##sys#build-branch ")") "")
7498 (if ##sys#build-id (string-append " (rev " ##sys#build-id ")") "")
7499 "\n"
7500 (get-config)
7501 (if (zero? (string-length spec))
7502 ""
7503 (string-append " [" spec " ]"))))
7504 ##sys#build-version))
7505
7506;;; Installation locations
7507
7508(define-foreign-variable binary-version int "C_BINARY_VERSION")
7509(define-foreign-variable installation-home c-string "C_INSTALL_SHARE_HOME")
7510(define-foreign-variable install-egg-home c-string "C_INSTALL_EGG_HOME")
7511
7512;; DEPRECATED
7513(define (chicken-home) installation-home)
7514
7515(define (include-path #!optional new)
7516 (when new
7517 (##sys#check-list new 'include-path)
7518 (set! ##sys#include-pathnames new))
7519 ##include-pathnames)
7520
7521(define path-list-separator
7522 (if ##sys#windows-platform #\; #\:))
7523
7524(define ##sys#split-path
7525 (let ((cache '(#f)))
7526 (lambda (path)
7527 (cond ((not path) '())
7528 ((equal? path (car cache))
7529 (cdr cache))
7530 (else
7531 (let* ((len (string-length path))
7532 (lst (let loop ((start 0) (pos 0))
7533 (cond ((fx>= pos len)
7534 (if (fx= pos start)
7535 '()
7536 (list (substring path start pos))))
7537 ((char=? (string-ref path pos)
7538 path-list-separator)
7539 (cons (substring path start pos)
7540 (loop (fx+ pos 1)
7541 (fx+ pos 1))))
7542 (else
7543 (loop start (fx+ pos 1)))))))
7544 (set! cache (cons path lst))
7545 lst))))))
7546
7547(define repository-path
7548 (make-parameter
7549 (cond ((foreign-value "C_private_repository_path()" c-string)
7550 => list)
7551 ((get-environment-variable "CHICKEN_REPOSITORY_PATH")
7552 => ##sys#split-path)
7553 (install-egg-home
7554 => list)
7555 (else #f))
7556 (lambda (new)
7557 (and new
7558 (begin
7559 (##sys#check-list new 'repository-path)
7560 (for-each (lambda (p) (##sys#check-string p 'repository-path)) new)
7561 new)))))
7562
7563(define installation-repository
7564 (make-parameter
7565 (or (foreign-value "C_private_repository_path()" c-string)
7566 (get-environment-variable "CHICKEN_INSTALL_REPOSITORY")
7567 install-egg-home)))
7568
7569(define (chop-separator str)
7570 (let ((len (fx- (string-length str) 1)))
7571 (if (and (> len 0)
7572 (memq (string-ref str len) '(#\\ #\/)))
7573 (substring str 0 len)
7574 str) ) )
7575
7576(define ##sys#include-pathnames
7577 (cond ((get-environment-variable "CHICKEN_INCLUDE_PATH")
7578 => (lambda (p)
7579 (map chop-separator (##sys#split-path p))))
7580 (else (list installation-home))))
7581
7582(define (include-path) ##sys#include-pathnames)
7583
7584
7585;;; Feature identifiers:
7586
7587(define ->feature-id ; TODO: export this? It might be useful..
7588 (let ()
7589 (define (err . args)
7590 (apply ##sys#signal-hook #:type-error "bad argument type - not a valid feature identifer" args))
7591 (define (prefix s)
7592 (if s (##sys#string-append s "-") ""))
7593 (lambda (x)
7594 (cond ((keyword? x) x)
7595 ((string? x) (string->keyword x))
7596 ((symbol? x) (string->keyword (##sys#symbol->string/shared x)))
7597 (else (err x))))))
7598
7599(define ##sys#features
7600 '(#:chicken
7601 #:srfi-6 #:srfi-12 #:srfi-17 #:srfi-23 #:srfi-30
7602 #:exact-complex #:srfi-39 #:srfi-62 #:srfi-88 #:full-numeric-tower #:full-unicode))
7603
7604;; Add system features:
7605
7606;; all platforms we support have this
7607(set! ##sys#features `(#:posix #:r7rs #:ieee-float #:ratios ,@##sys#features))
7608
7609(let ((check (lambda (f)
7610 (unless (eq? 'unknown f)
7611 (set! ##sys#features (cons (->feature-id f) ##sys#features))))))
7612 (check (software-type))
7613 (check (software-version))
7614 (check (build-platform))
7615 (check (machine-type))
7616 (check (machine-byte-order)))
7617
7618(when (foreign-value "HAVE_DLOAD" bool)
7619 (set! ##sys#features (cons #:dload ##sys#features)))
7620(when (foreign-value "HAVE_PTABLES" bool)
7621 (set! ##sys#features (cons #:ptables ##sys#features)))
7622(when (foreign-value "HAVE_GCHOOKS" bool)
7623 (set! ##sys#features (cons #:gchooks ##sys#features)))
7624(when (foreign-value "IS_CROSS_CHICKEN" bool)
7625 (set! ##sys#features (cons #:cross-chicken ##sys#features)))
7626
7627;; Register a feature to represent the word size (e.g., 32bit, 64bit)
7628(set! ##sys#features
7629 (cons (string->keyword
7630 (string-append
7631 (number->string (foreign-value "C_WORD_SIZE" int))
7632 "bit"))
7633 ##sys#features))
7634
7635(set! ##sys#features
7636 (let ((major (##sys#number->string (foreign-value "C_MAJOR_VERSION" int)))
7637 (minor (##sys#number->string (foreign-value "C_MINOR_VERSION" int))))
7638 (cons (->feature-id (string-append "chicken-" major))
7639 (cons (->feature-id (string-append "chicken-" major "." minor))
7640 ##sys#features))))
7641
7642(define (register-feature! . fs)
7643 (for-each
7644 (lambda (f)
7645 (let ((id (->feature-id f)))
7646 (unless (memq id ##sys#features) (set! ##sys#features (cons id ##sys#features)))))
7647 fs)
7648 (##core#undefined))
7649
7650(define (unregister-feature! . fs)
7651 (let ((fs (map ->feature-id fs)))
7652 (set! ##sys#features
7653 (let loop ((ffs ##sys#features))
7654 (if (null? ffs)
7655 '()
7656 (let ((f (##sys#slot ffs 0))
7657 (r (##sys#slot ffs 1)))
7658 (if (memq f fs)
7659 (loop r)
7660 (cons f (loop r)))))))
7661 (##core#undefined)))
7662
7663(define (feature? . ids)
7664 (let loop ((ids ids))
7665 (or (null? ids)
7666 (and (memq (->feature-id (##sys#slot ids 0)) ##sys#features)
7667 (loop (##sys#slot ids 1))))))
7668
7669(define return-to-host
7670 (##core#primitive "C_return_to_host"))
7671
7672(define (system-config-directory)
7673 (or (get-environment-variable "XDG_CONFIG_HOME")
7674 (if ##sys#windows-platform
7675 (get-environment-variable "APPDATA")
7676 (let ((home (get-environment-variable "HOME")))
7677 (and home (string-append home "/.config"))))))
7678
7679(define (system-cache-directory)
7680 (or (get-environment-variable "XDG_CACHE_HOME")
7681 (if ##sys#windows-platform
7682 (or (get-environment-variable "LOCALAPPDATA")
7683 (get-environment-variable "APPDATA"))
7684 (let ((home (get-environment-variable "HOME")))
7685 (and home (string-append home "/.cache"))))))
7686
7687) ; chicken.platform
7688
7689(set! scheme#features
7690 (lambda ()
7691 (map (lambda (s)
7692 (##sys#string->symbol (##sys#symbol->string s)))
7693 ##sys#features)))
7694
7695(set! scheme#make-list
7696 (lambda (n #!optional fill)
7697 (##sys#check-integer n 'make-list)
7698 (unless (fx>= n 0)
7699 (error 'make-list "not a positive integer" n))
7700 (do ((i n (fx- i 1))
7701 (result '() (cons fill result)))
7702 ((eq? i 0) result))))
7703
7704(set! scheme#list-set!
7705 (lambda (l n obj)
7706 (##sys#check-integer n 'list-set!)
7707 (unless (fx>= n 0)
7708 (error 'list-set! "not a positive integer" n))
7709 (do ((i n (fx- i 1))
7710 (l l (cdr l)))
7711 ((fx= i 0) (set-car! l obj))
7712 (when (null? l)
7713 (error 'list-set! "out of range")))))
7714
7715;; TODO: Test if this is the quickest way to do this, or whether we
7716;; should just cons recursively like our SRFI-1 implementation does.
7717(set! scheme#list-copy
7718 (lambda (lst)
7719 (cond ((pair? lst)
7720 (let lp ((res '())
7721 (lst lst))
7722 (if (pair? lst)
7723 (lp (cons (car lst) res) (cdr lst))
7724 (append (##sys#fast-reverse res) lst))))
7725 (else lst))))
7726
7727(set! scheme#string->vector
7728 (lambda (s #!optional start end)
7729 (let ((s->v (lambda (s start end)
7730 (##sys#check-string s 'string->vector)
7731 (let* ((len (##sys#slot s 1)))
7732 (##sys#check-range/including start 0 end 'string->vector)
7733 (##sys#check-range/including end start len 'string->vector)
7734 (let ((v (##sys#make-vector (fx- end start))))
7735 (do ((ti 0 (fx+ ti 1))
7736 (fi start (fx+ fi 1)))
7737 ((fx= fi end) v)
7738 (##sys#setslot v ti (##core#inline "C_utf_subchar" s fi))))))))
7739 (if end
7740 (s->v s start end)
7741 (s->v s (or start 0) (string-length s))))))
7742
7743(set! scheme#vector->string
7744 (lambda (v #!optional start end)
7745 (let ((v->s (lambda (v start end)
7746 (##sys#check-vector v 'vector->string)
7747 (let* ((len (##sys#size v)))
7748 (##sys#check-range/including start 0 end 'vector->string)
7749 (##sys#check-range/including end start len 'vector->string)
7750 (let ((s (##sys#make-bytevector (fx* 4 (fx- end start)))))
7751 (let loop ((ti 0)
7752 (fi start))
7753 (if (fx= fi end)
7754 (##sys#buffer->string s 0 ti)
7755 (let ((c (##sys#slot v fi)))
7756 (##sys#check-char c 'vector->string)
7757 (loop (fx+ ti (##core#inline "C_utf_insert" s ti c))
7758 (fx+ fi 1))))))))))
7759 (if end
7760 (v->s v start end)
7761 (v->s v (or start 0) (##sys#size v))))))
7762
7763(set! scheme#string-map
7764 (lambda (proc str . more)
7765 (define (%string-map proc s)
7766 (let* ((len (string-length s))
7767 (ans (##sys#make-bytevector (fx* 4 len))))
7768 (let loop ((i 0)
7769 (j 0))
7770 (if (fx>= j len)
7771 (##sys#buffer->string ans 0 i)
7772 (let ((r (proc (string-ref s j))))
7773 (##sys#check-char r 'string-map)
7774 (loop (##core#inline "C_utf_insert" ans i r)
7775 (fx+ j 1)))))))
7776 (if (null? more)
7777 (%string-map proc str)
7778 (let ((strs (cons str more)))
7779 (##sys#check-closure proc 'string-map)
7780 (##sys#for-each (cut ##sys#check-string <> 'string-map) strs)
7781 (let* ((len (foldl fxmin most-positive-fixnum (map string-length strs)))
7782 (str (##sys#make-string len)))
7783 (do ((i 0 (fx+ i 1)))
7784 ((fx= i len) str)
7785 (string-set! str i (apply proc (map (cut string-ref <> i) strs)))))))))
7786
7787(set! scheme#string-for-each
7788 (lambda (proc str . more)
7789 (define (%string-for-each proc s)
7790 (let ((len (string-length s)))
7791 (let lp ((i 0))
7792 (if (fx< i len)
7793 (begin (proc (string-ref s i))
7794 (lp (fx+ i 1)))))))
7795 (if (null? more)
7796 (%string-for-each proc str)
7797 (let ((strs (cons str more)))
7798 (##sys#check-closure proc 'string-for-each)
7799 (##sys#for-each (cut ##sys#check-string <> 'string-for-each) strs)
7800 (let* ((len (foldl fxmin most-positive-fixnum (map string-length strs)))
7801 (str (##sys#make-string len)))
7802 (do ((i 0 (fx+ i 1)))
7803 ((fx= i len))
7804 (apply proc (map (cut string-ref <> i) strs))))))))
7805
7806(set! scheme#vector-map
7807 (lambda (proc v . more)
7808 (cond ((null? more)
7809 (##sys#check-closure proc 'vector-map)
7810 (##sys#check-vector v 'vector-map)
7811 (let* ((len (##sys#size v))
7812 (vec (##sys#make-vector len)))
7813 (do ((i 0 (fx+ i 1)))
7814 ((fx= i len) vec)
7815 (##sys#setslot vec i (proc (##sys#slot v i))))))
7816 (else
7817 (let ((vs (cons v more)))
7818 (##sys#check-closure proc 'vector-map)
7819 (##sys#for-each (cut ##sys#check-vector <> 'vector-map) vs)
7820 (let* ((len (foldl fxmin most-positive-fixnum (map ##sys#size vs)))
7821 (vec (##sys#make-vector len)))
7822 (do ((i 0 (fx+ i 1)))
7823 ((fx= i len) vec)
7824 (##sys#setslot vec i (apply proc (map (cut vector-ref <> i) vs))))))))))
7825
7826(set! scheme#vector-for-each
7827 (lambda (proc v . more)
7828 (cond ((null? more)
7829 (##sys#check-closure proc 'vector-for-each)
7830 (##sys#check-vector v 'vector-for-each)
7831 (let ((len (##sys#size v)))
7832 (do ((i 0 (fx+ i 1)))
7833 ((fx= i len))
7834 (proc (##sys#slot v i)))))
7835 (else
7836 (let ((vs (cons v more)))
7837 (##sys#check-closure proc 'vector-for-each)
7838 (##sys#for-each (cut ##sys#check-vector <> 'vector-for-each) vs)
7839 (let* ((len (foldl fxmin most-positive-fixnum (map ##sys#size vs)))
7840 (vec (##sys#make-vector len)))
7841 (do ((i 0 (fx+ i 1)))
7842 ((fx= i len) vec)
7843 (apply proc (map (cut vector-ref <> i) vs)))))))))
7844
7845(set! scheme#close-port
7846 (lambda (port)
7847 (##sys#check-port port 'close-port)
7848 (when (##core#inline "C_port_openp" port 1)
7849 ((##sys#slot (##sys#slot port 2) 4) port 1))
7850 (when (##core#inline "C_port_openp" port 2)
7851 ((##sys#slot (##sys#slot port 2) 4) port 2))
7852 (##sys#setislot port 8 0)))
7853
7854(set! scheme#call-with-port
7855 (lambda (port proc)
7856 (receive ret
7857 (proc port)
7858 (scheme#close-port port)
7859 (apply values ret))))
7860
7861(set! scheme#eof-object (lambda () #!eof))
7862
7863(set! scheme#peek-u8
7864 (case-lambda
7865 (()
7866 (let ((c (peek-char ##sys#standard-input)))
7867 (if (eof-object? c) c
7868 (char->integer c))))
7869 ((port)
7870 (##sys#check-input-port port #t 'peek-u8)
7871 (let ((c (peek-char port)))
7872 (if (eof-object? c) c
7873 (char->integer c))))))
7874
7875(set! scheme#write-string
7876 (lambda (s #!optional (port ##sys#standard-output) start end)
7877 (##sys#check-string s 'write-string)
7878 (##sys#check-output-port port #t 'write-string)
7879 (if start
7880 (##sys#check-fixnum start 'write-string)
7881 (set! start 0))
7882 (if end
7883 (##sys#check-fixnum end 'write-string)
7884 (set! end (string-length s)))
7885 (let* ((part (if start (substring s start end) s))
7886 (bv (##sys#slot part 0))
7887 (len (fx- (##sys#size bv) 1)))
7888 ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
7889 port bv 0 len))))
7890
7891
7892;; I/O
7893
7894(module chicken.io
7895 (read-list read-buffered read-byte read-line
7896 read-lines read-string read-string! read-token
7897 write-byte write-line write-bytevector read-bytevector
7898 read-bytevector!)
7899
7900(import scheme chicken.base chicken.fixnum)
7901(import chicken.internal.syntax)
7902(import (only (scheme base) open-output-string get-output-string))
7903
7904
7905;;; Read expressions from file:
7906
7907(define read-list
7908 (let ((read read))
7909 (lambda (#!optional (port ##sys#standard-input) (reader read) max)
7910 (##sys#check-input-port port #t 'read-list)
7911 (do ((x (reader port) (reader port))
7912 (i 0 (fx+ i 1))
7913 (xs '() (cons x xs)))
7914 ((or (eof-object? x) (and max (fx>= i max)))
7915 (##sys#fast-reverse xs))))))
7916
7917
7918;;; Line I/O:
7919
7920(define read-line
7921 (let ()
7922 (lambda args
7923 (let* ([parg (pair? args)]
7924 [p (if parg (car args) ##sys#standard-input)]
7925 [limit (and parg (pair? (cdr args)) (cadr args))])
7926 (##sys#check-input-port p #t 'read-line)
7927 (cond ((##sys#slot (##sys#slot p 2) 8) => (lambda (rl) (rl p limit)))
7928 (else
7929 (let* ((buffer-len (if limit limit 256))
7930 (buffer (##sys#make-string buffer-len)))
7931 (let loop ([i 0])
7932 (if (and limit (fx>= i limit))
7933 (##sys#substring buffer 0 i)
7934 (let ([c (##sys#read-char-0 p)])
7935 (if (eof-object? c)
7936 (if (fx= i 0)
7937 c
7938 (##sys#substring buffer 0 i) )
7939 (case c
7940 [(#\newline) (##sys#substring buffer 0 i)]
7941 [(#\return)
7942 (let ([c (peek-char p)])
7943 (if (char=? c #\newline)
7944 (begin (##sys#read-char-0 p)
7945 (##sys#substring buffer 0 i))
7946 (##sys#substring buffer 0 i) ) ) ]
7947 [else
7948 (when (fx>= i buffer-len)
7949 (set! buffer
7950 (##sys#string-append buffer (make-string buffer-len)))
7951 (set! buffer-len (fx+ buffer-len buffer-len)) )
7952 (string-set! buffer i c)
7953 (loop (fx+ i 1)) ] ) ) ) ) ) ) ) ) ) ) ) )
7954
7955(define read-lines
7956 (lambda (#!optional (port ##sys#standard-input) max)
7957 (##sys#check-input-port port #t 'read-lines)
7958 (when max (##sys#check-fixnum max 'read-lines))
7959 (let loop ((lns '())
7960 (n (or max most-positive-fixnum)))
7961 (if (eq? n 0)
7962 (##sys#fast-reverse lns)
7963 (let ((ln (read-line port)))
7964 (if (eof-object? ln)
7965 (##sys#fast-reverse lns)
7966 (loop (cons ln lns) (fx- n 1))))))))
7967
7968(define write-line
7969 (lambda (str . port)
7970 (let* ((p (if (##core#inline "C_eqp" port '())
7971 ##sys#standard-output
7972 (##sys#slot port 0) ) ))
7973 (##sys#check-output-port p #t 'write-line)
7974 (##sys#check-string str 'write-line)
7975 (let ((bv (##sys#slot str 0)))
7976 ((##sys#slot (##sys#slot p 2) 3) ; write-bytevector
7977 p
7978 bv
7979 0
7980 (fx- (##sys#size bv) 1)))
7981 (##sys#write-char-0 #\newline p))))
7982
7983
7984;;; Extended I/O
7985
7986(define (read-bytevector!/port n dest port start)
7987 (if (eq? n 0)
7988 0
7989 (let ((rdbvec (##sys#slot (##sys#slot port 2) 7))) ; read-bytevector!
7990 (let loop ((start start) (n n) (m 0))
7991 (let ((n2 (rdbvec port n dest start)))
7992 (##sys#setislot port 5 ; update port-position
7993 (fx+ (##sys#slot port 5) n2))
7994 (cond ((eq? n2 0) m)
7995 ((or (not n) (fx< n2 n))
7996 (loop (fx+ start n2) (and n (fx- n n2)) (fx+ m n2)))
7997 (else (fx+ n2 m))))))))
7998
7999(define (read-string!/port n dest port start)
8000 (let ((buf (##sys#make-bytevector (fx* n 4)))
8001 (enc (##sys#slot port 15)))
8002 (##sys#encoding-hook
8003 enc
8004 (lambda (decoder _ _)
8005 (define (readb n buf port p)
8006 (let ((bytes (read-bytevector!/port n buf port p)))
8007 (if (eq? enc 'utf-8) ; fast path, avoid copying
8008 bytes
8009 (decoder buf p bytes
8010 (lambda (dbuf start len)
8011 (##core#inline "C_copy_memory_with_offset" buf dbuf p start len)
8012 len)))))
8013 (define (finish un bytes)
8014 (##core#inline "C_utf_overwrite" dest start un buf bytes)
8015 un)
8016 (let loop ((p 0) (n n) (un 0) (bn 0))
8017 (let ((bytes (readb n buf port p)))
8018 (cond ((eq? bytes 0) (finish un bn))
8019 ((eq? enc 'utf-8)
8020 ;; read incomplete fragments
8021 ;; FIXME: hardcoded, should be encoding-specific!
8022 (let recount ((bytes bytes))
8023 (let* ((fc (##core#inline "C_utf_fragment_counts" buf p bytes))
8024 (full (fxshr fc 4))
8025 (left (fxand fc 15))
8026 (total (fx+ un full))
8027 (tbytes (fx+ bn bytes))
8028 (remain (fx- n full)))
8029 (cond ((fx> left 0)
8030 (let ((b2 (readb left buf port (fx+ p bytes))))
8031 (if (fx< b2 left)
8032 (finish total tbytes)
8033 (recount (fx+ bytes b2)))))
8034 ((eq? remain 0) (finish total tbytes))
8035 (else (loop (fx+ p bytes) remain total
8036 tbytes))))))
8037 ((fx> bytes n)
8038 (loop (fx+ p bytes) (fx- n bytes)
8039 (fx+ un bytes) (fx+ bn bytes)))
8040 (else (finish un bn)))))))))
8041
8042(define (read-string! n dest #!optional (port ##sys#standard-input) (start 0))
8043 (##sys#check-input-port port #t 'read-string!)
8044 (##sys#check-string dest 'read-string!)
8045 (when n (##sys#check-fixnum n 'read-string!))
8046 (let ((dest-size (string-length dest)))
8047 (unless (and n (fx<= (fx+ start n) dest-size))
8048 (set! n (fx- dest-size start))))
8049 (##sys#check-fixnum start 'read-string!)
8050 (read-string!/port n dest port start))
8051
8052(define (read-bytevector! dest #!optional (port ##sys#standard-input) (start 0) end)
8053 (##sys#check-input-port port #t 'read-bytevector!)
8054 (##sys#check-bytevector dest 'read-bytevector!)
8055 (##sys#check-fixnum start 'read-bytevector!)
8056 (when end (##sys#check-fixnum end 'read-bytevector!))
8057 (let* ((size (##sys#size dest))
8058 (n (fx- (or end size) start)))
8059 (read-bytevector!/port n dest port start)))
8060
8061(define read-string/port
8062 (lambda (n p)
8063 (cond ((eq? n 0) "") ; Don't attempt to peek (fd might not be ready)
8064 ((eof-object? (##sys#peek-char-0 p)) #!eof)
8065 (n (let* ((str (##sys#make-string n))
8066 (n2 (read-string!/port n str p 0)))
8067 (if (eq? n n2)
8068 str
8069 (##sys#substring str 0 n2))))
8070 (else
8071 (##sys#read-remaining
8072 p
8073 (lambda (buf len)
8074 (##sys#buffer->string/encoding buf 0 len
8075 (##sys#slot p 15))))))))
8076
8077(define (##sys#read-remaining p k)
8078 (let ((len 1024))
8079 (let loop ((buf (##sys#make-bytevector len))
8080 (bsize len)
8081 (pos 0))
8082 (let* ((nr (fx- (##sys#size buf) pos))
8083 (n (read-bytevector!/port nr buf p pos)))
8084 (cond ((eq? n nr)
8085 (let* ((bsize2 (fx* bsize 2))
8086 (buf2 (##sys#make-bytevector bsize2)))
8087 (##core#inline "C_copy_memory" buf2 buf bsize)
8088 (loop buf2 bsize2 (fx+ pos n))))
8089 (else (k buf (fx+ n pos))))))))
8090
8091(define read-bytevector/port
8092 (lambda (n p)
8093 (let* ((bv (##sys#make-bytevector n))
8094 (n2 (read-bytevector!/port n bv p 0)))
8095 (if (eq? n n2)
8096 bv
8097 (let ((bv2 (##sys#make-bytevector n2)))
8098 (##core#inline "C_copy_memory" bv2 bv n2)
8099 bv2)))))
8100
8101(define (read-string #!optional n (port ##sys#standard-input))
8102 (##sys#check-input-port port #t 'read-string)
8103 (when n (##sys#check-fixnum n 'read-string))
8104 (read-string/port n port))
8105
8106(define (read-bytevector #!optional n (port ##sys#standard-input))
8107 (##sys#check-input-port port #t 'read-bytevector)
8108 (cond (n (##sys#check-fixnum n 'read-bytevector)
8109 (let ((r (read-bytevector/port n port)))
8110 (if (eq? (##sys#size r) 0)
8111 #!eof
8112 r)))
8113 (else
8114 (##sys#read-remaining
8115 port
8116 (lambda (buf len)
8117 (if (eq? len 0)
8118 #!eof
8119 (let ((r (##sys#make-bytevector len)))
8120 (##core#inline "C_copy_memory" r buf len)
8121 r)))))))
8122
8123
8124;; Make internal reader procedures available for use in srfi-4.scm:
8125
8126(define chicken.io#read-string/port read-string/port)
8127(define chicken.io#read-string!/port read-string!/port)
8128(define chicken.io#read-bytevector/port read-bytevector/port)
8129(define chicken.io#read-bytevector!/port read-bytevector!/port)
8130
8131(define (read-buffered #!optional (port ##sys#standard-input))
8132 (##sys#check-input-port port #t 'read-buffered)
8133 (let ((rb (##sys#slot (##sys#slot port 2) 9))) ; read-buffered method
8134 (if rb
8135 (rb port)
8136 "")))
8137
8138
8139;;; read token of characters that satisfy a predicate
8140
8141(define read-token
8142 (lambda (pred . port)
8143 (let ([port (optional port ##sys#standard-input)])
8144 (##sys#check-input-port port #t 'read-token)
8145 (let ([out (open-output-string)])
8146 (let loop ()
8147 (let ([c (##sys#peek-char-0 port)])
8148 (if (and (not (eof-object? c)) (pred c))
8149 (begin
8150 (##sys#write-char-0 (##sys#read-char-0 port) out)
8151 (loop) )
8152 (get-output-string out) ) ) ) ) ) ) )
8153
8154
8155;;; Binary I/O
8156
8157(define (read-byte #!optional (port ##sys#standard-input))
8158 (##sys#check-input-port port #t 'read-byte)
8159 (let* ((bv (##sys#make-bytevector 1))
8160 (n (read-bytevector!/port 1 bv port 0)))
8161 (if (fx< n 1)
8162 #!eof
8163 (##core#inline "C_subbyte" bv 0))))
8164
8165(define (write-byte byte #!optional (port ##sys#standard-output))
8166 (##sys#check-fixnum byte 'write-byte)
8167 (##sys#check-output-port port #t 'write-byte)
8168 (let ((bv (##sys#make-bytevector 1 byte)))
8169 ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8170 port bv 0 1)))
8171
8172(define (write-bytevector bv #!optional (port ##sys#standard-output) (start 0)
8173 end)
8174 (##sys#check-bytevector bv 'write-bytevector)
8175 (##sys#check-output-port port #t 'write-bytevector)
8176 (##sys#check-fixnum start 'write-bytevector)
8177 (let ((len (##sys#size bv)))
8178 (##sys#check-range/including start 0 len 'write-bytevector)
8179 (when end (##sys#check-range/including end 0 len 'write-bytevector))
8180 (let ((end (if end (fxmin end len) len)))
8181 ((##sys#slot (##sys#slot port 2) 3) ; write-bytevector
8182 port bv start end))))
8183
8184) ; module chicken.io