Projects : gscm : gscm_usrbin
1 | ;;; Gales Scheme standard library and toplevel |
2 | ;;; Includes program loader and READ-EVAL-PRINT loop. |
3 | ;;; J. Welsh, 2017-2018 |
4 | |
5 | (begin |
6 | |
7 | ;;; Syntax library (R5RS: 4.2. Derived expression types) |
8 | |
9 | (define-syntax and |
10 | (syntax-rules () |
11 | ((and) #t) |
12 | ((and a) a) |
13 | ((and a . b) (if a (and . b) #f)))) |
14 | |
15 | (define-syntax or |
16 | (syntax-rules () |
17 | ((or) #f) |
18 | ((or a) a) |
19 | ((or (a . b) . c) (let ((tmp5f920465446f5c2d (a . b))) |
20 | (if tmp5f920465446f5c2d tmp5f920465446f5c2d |
21 | (or . c)))) |
22 | ;; ^ The macro machinery ought to rename temporaries automatically, but an "official random number" is adequate because we only need to avoid shadowing free references within C. Further bindings to the same "gensym" within A, B or C do not conflict with the outer one. |
23 | ((or a . b) (if a a (or . b))))) |
24 | |
25 | (define-syntax let* |
26 | (syntax-rules () |
27 | ((let* () body . a) (let () body . a)) |
28 | ((let* ((n v)) body . a) (let ((n v)) body . a)) |
29 | ((let* ((n v) . b) body . a) (let ((n v)) (let* b body . a))))) |
30 | |
31 | (define-syntax quasiquote |
32 | (syntax-rules (unquote unquote-splicing) |
33 | ((quasiquote (unquote a)) a) |
34 | ((quasiquote ((unquote-splicing a) . b)) (append a (quasiquote b))) |
35 | ((quasiquote (a . b)) (cons (quasiquote a) (quasiquote b))) |
36 | ;((quasiquote #(a ...)) (vector (quasiquote a) ...)) |
37 | ((quasiquote a) (quote a)))) |
38 | |
39 | (define-syntax cond |
40 | (syntax-rules (else =>) |
41 | ((cond (else a . b)) (begin a . b)) |
42 | ((cond (t => r)) (let ((tmp5f920465446f5c2d t)) |
43 | (if tmp5f920465446f5c2d (r tmp5f920465446f5c2d)))) |
44 | ((cond (t => r) . c) (let ((tmp5f920465446f5c2d t)) |
45 | (if tmp5f920465446f5c2d (r tmp5f920465446f5c2d) |
46 | (cond . c)))) |
47 | ;; return unspecified when no tests pass |
48 | ((cond (t)) (or t '())) |
49 | ((cond (t) . c) (or t (cond . c))) |
50 | ((cond (t a . b)) (if t (begin a . b))) |
51 | ((cond (t a . b) . c) (if t (begin a . b) (cond . c))))) |
52 | |
53 | (define-syntax case |
54 | (syntax-rules (else) |
55 | ((case (a . b) c . d) (let ((tmp5f920465446f5c2d (a . b))) |
56 | (case tmp5f920465446f5c2d c . d))) |
57 | ((case k (else a . b)) (begin a . b)) |
58 | ;; return unspecified when no tests pass |
59 | ((case k (() a . b)) '()) |
60 | ((case k (() a . b) c . d) (case k c . d)) |
61 | ((case k ((s) a . b)) (if (eqv? k 's) (begin a . b))) |
62 | ((case k ((s) a . b) c . d) (if (eqv? k 's) (begin a . b) |
63 | (case k c . d))) |
64 | ((case k ((s . t) a . b)) (if (memv k '(s . t)) (begin a . b))) |
65 | ((case k ((s . t) a . b) c . d) (if (memv k '(s . t)) (begin a . b) |
66 | (case k c . d))))) |
67 | |
68 | ;; SRFI 8 |
69 | (define-syntax receive |
70 | (syntax-rules () |
71 | ((receive names expr body . a) |
72 | (call-with-values (lambda () expr) (lambda names body . a))))) |
73 | |
74 | ;;; Toplevel |
75 | |
76 | (let ((prompt "GSCM> ") |
77 | (result-prefix " => ") |
78 | (*args* (eval '*args* (interaction-environment))) |
79 | (intr-env (interaction-environment)) |
80 | (error-cont #f) |
81 | (exit-cont #f) |
82 | (repl-cont #f) |
83 | (error-handler #f) |
84 | (trace-ring-length 8)) |
85 | |
86 | ;;; Various constants |
87 | ;; Inexact number and named char literals unsupported in bootstrap reader |
88 | (define flo-1 (flonum/unchecked -1)) |
89 | (define flo0 (flonum/unchecked 0)) |
90 | (define flo1 (flonum/unchecked 1)) |
91 | (define flo2 (flonum/unchecked 2)) |
92 | (define flo10 (flonum/unchecked 10)) |
93 | (define flo1/10 (flodiv/unchecked (flonum/unchecked 1) |
94 | (flonum/unchecked 10))) |
95 | (define flo-log-10 (log/unchecked (flonum/unchecked 10))) |
96 | (define nl (integer->char 10)) |
97 | (define sp (integer->char 32)) |
98 | |
99 | (define *fixnum-width*-1 (fx-/unchecked *fixnum-width* 1)) |
100 | |
101 | ;;; Tracing |
102 | ;; When a library procedure is called externally, its name is recorded in a circular log structure. On error, this is copied to a proper list and passed to the handler. Crude, perhaps, but fairly effective. (Errors signalled by builtins already include the builtin name in the message.) |
103 | (define trace-ring |
104 | (let ((head (cons #f '()))) |
105 | (do ((p head (cons #f p)) |
106 | (k 1 (fx+/wrap k 1))) |
107 | ((fx= k trace-ring-length) (set-cdr! head p) head)))) |
108 | |
109 | (define (clear-trace-ring) |
110 | (do ((p trace-ring (cdr p)) |
111 | (k 0 (fx+/wrap k 1))) |
112 | ((fx= k trace-ring-length)) |
113 | (set-car! p #f))) |
114 | |
115 | (define (get-trace-log) |
116 | (do ((p trace-ring (cdr p)) |
117 | (acc '() (if (car p) (cons (car p) acc) acc)) |
118 | (k 0 (fx+/wrap k 1))) |
119 | ((fx= k trace-ring-length) (reverse acc)))) |
120 | |
121 | (define (trace . args) |
122 | (set-car/unchecked! trace-ring args) |
123 | (set! trace-ring (cdr/unchecked trace-ring))) |
124 | |
125 | (define (traced-procedure name proc) |
126 | (lambda args (trace name) (apply/unchecked proc args))) |
127 | |
128 | (define (define-traced injector name proc) |
129 | (injector name (traced-procedure name proc))) |
130 | |
131 | (define (write-line val) (write val) (newline)) |
132 | |
133 | (define (print-error message args trace-log) |
134 | (display "ERROR: ") |
135 | (display message) |
136 | (for-each (lambda (arg) (write-char sp) (write arg)) args) |
137 | (newline) |
138 | (display "Trace log: ") |
139 | (write-line trace-log)) |
140 | |
141 | (define (repl) |
142 | (clear-trace-ring) |
143 | (display prompt) |
144 | (flush-output-port) |
145 | (let ((expr (read))) |
146 | (if (eof-object? expr) (newline) |
147 | (receive vals (eval expr intr-env) |
148 | (for-each (lambda (val) |
149 | (display result-prefix) |
150 | (write-line val)) vals) |
151 | (flush-output-port) |
152 | (repl))))) |
153 | |
154 | (define (repl-error message args trace-log) |
155 | (print-error message args trace-log) |
156 | (repl-cont '())) |
157 | |
158 | (define (exec-from-port p) |
159 | (do ((expr (read p) (read p)) |
160 | (acc '() (cons expr acc))) |
161 | ((eof-object? expr) |
162 | (close-input-port p) |
163 | (for-each (lambda (expr) (eval expr intr-env)) |
164 | (reverse acc))))) |
165 | |
166 | (define (not-integer x) (error "not an integer:" x)) |
167 | (define (not-list) (error "not a list")) |
168 | (define (not-number x) (error "not a number:" x)) |
169 | (define (not-exact-int x) (error "not an exact integer:" x)) |
170 | (define (not-output-port x) (error "not an output port:" x)) |
171 | (define (not-procedure x) (error "not a procedure:" x)) |
172 | |
173 | (define (too-many-args) (error "too many arguments")) |
174 | (define (zero-divisor) (error "zero divisor")) |
175 | (define (bad-radix x) (error "invalid radix:" x)) |
176 | (define (uneven-lists) (error "uneven lists")) |
177 | |
178 | (define (require-integer n) (if (integer? n) n (not-integer n))) |
179 | (define (require-procedure p) (if (procedure? p) p (not-procedure p))) |
180 | |
181 | (define (check-exact-non-negative-int k) |
182 | (if (cond ((fixnum? k) (fxnegative/unchecked? k)) |
183 | ((bignum? k) (bignum-negative? k)) |
184 | (else #t)) |
185 | (error "not an exact non-negative integer:" k))) |
186 | |
187 | (define (foldl f) |
188 | ;; type-safe but doesn't detect improper or cyclic list |
189 | (define (loop accum l) |
190 | (if (pair? l) (loop (f accum (car/unchecked l)) |
191 | (cdr/unchecked l)) |
192 | accum)) |
193 | loop) |
194 | |
195 | (define (all pred) |
196 | ;; type-safe but doesn't detect improper or cyclic list |
197 | (define (loop l) |
198 | (if (pair? l) (and (pred (car/unchecked l)) |
199 | (loop (cdr/unchecked l))) |
200 | #t)) |
201 | loop) |
202 | |
203 | (define (all-pairwise pred) |
204 | ;; type-safe but doesn't detect improper or cyclic list |
205 | (define (loop a b l) |
206 | (and (pred a b) |
207 | (if (pair? l) (loop b (car/unchecked l) (cdr/unchecked l)) |
208 | #t))) |
209 | loop) |
210 | |
211 | ;; not tail recursive |
212 | (define (map1 proc) |
213 | ;; type-safe but doesn't detect improper or cyclic list |
214 | (define (loop l) |
215 | (if (pair? l) |
216 | (cons (proc (car/unchecked l)) |
217 | (loop (cdr/unchecked l))) |
218 | l)) |
219 | loop) |
220 | |
221 | (define (copy-list l) |
222 | (define r (list '())) |
223 | (define (loop tail l) |
224 | (cond ((pair? l) (set-cdr/unchecked! tail (cons (car/unchecked l) '())) |
225 | (loop (cdr/unchecked tail) (cdr/unchecked l))) |
226 | ((null? l) (cdr/unchecked r)) |
227 | (else (not-list)))) |
228 | (loop r l)) |
229 | |
230 | (define (append2 x y) |
231 | (define r (list '())) |
232 | (define (loop tail x) |
233 | (cond ((pair? x) (set-cdr/unchecked! tail (cons (car/unchecked x) '())) |
234 | (loop (cdr/unchecked tail) (cdr/unchecked x))) |
235 | ((null? x) (set-cdr/unchecked! tail y) |
236 | (cdr/unchecked r)) |
237 | (else (not-list)))) |
238 | (loop r x)) |
239 | |
240 | (define (saving-values thunk after) |
241 | (call-with-values thunk |
242 | (lambda results |
243 | (after) |
244 | (apply/unchecked values results)))) |
245 | |
246 | (define (opt-args args . defaults) |
247 | (let loop ((acc '()) (args args) (defaults defaults)) |
248 | (if (pair? defaults) |
249 | (if (pair? args) |
250 | (loop (cons (car/unchecked args) acc) |
251 | (cdr/unchecked args) (cdr/unchecked defaults)) |
252 | (loop (cons (car/unchecked defaults) acc) |
253 | '() (cdr/unchecked defaults))) |
254 | (if (pair? args) (too-many-args) |
255 | (apply/unchecked values (reverse acc)))))) |
256 | |
257 | (define (first a . args) a) |
258 | (define (second a b . args) b) |
259 | |
260 | (define (fxquotient/unsigned/unchecked a b) |
261 | (call-with-values (lambda () (fxdiv/unsigned/unchecked a b)) first)) |
262 | |
263 | (define (fxremainder/unsigned/unchecked a b) |
264 | (call-with-values (lambda () (fxdiv/unsigned/unchecked a b)) second)) |
265 | |
266 | (define (fxquotient/ext/unsigned/unchecked al ah b) |
267 | (call-with-values |
268 | (lambda () (fxdiv/ext/unsigned/unchecked al ah b)) first)) |
269 | |
270 | ;;; Bignums |
271 | ;; |
272 | ;; Bignums are represented in a tagged sign-magnitude form. (I first tried two's complement but got stuck on efficient multiplication.) The magnitude is a vector of one or more fixnum words, least significant first. Bignums are normalized to drop trailing zeros or demoted to fixnum when possible. Words are considered unsigned, thus may appear negative to ordinary (signed) fixnum operations. |
273 | ;; |
274 | ;; Privileged primitives are as follows. Unless specified, all might omit type checks, and most internal bignum procedures inherit this! |
275 | ;; |
276 | ;; (MAKE-BIGNUM K) => bignum of K words |
277 | ;; Fixnum K is checked against the largest possible size, if any. The words may be uninitialized. |
278 | ;; (BIGNUM? OBJ) => boolean |
279 | ;; (BIGNUM-NEGATIVE? BN) => boolean |
280 | ;; (BIGNUM-SET-NEGATIVE! BN) => BN |
281 | ;; (BIGNUM-REF BN K) => word K of BN |
282 | ;; (BIGNUM-SET! BN K V) => unspecified, updating word K of BN to fixnum V |
283 | ;; (BIGNUM-LENGTH BN) => fixnum |
284 | ;; (BIGNUM N) => bignum of one word (not demoting) |
285 | ;; Constructs bignum with the value of N (signed). |
286 | ;; (BIGNUM/UNSIGNED N) => bignum of one word (not demoting) |
287 | ;; Constructs bignum with single word N |
288 | ;; (BIGNUM2 LO HI) => fixnum or bignum of one or two words |
289 | ;; Constructs bignum, demoting, from double-width signed value represented in two's complement by fixnums LO and HI. |
290 | ;; (BIGNUM-TRUNCATE! BN K) => bignum (not demoting) |
291 | ;; Returns truncation of BN to K words, possibly in-place. |
292 | |
293 | (define (fx+/promote a b) |
294 | (call-with-values (lambda () (fx+/carry a b)) bignum2)) |
295 | |
296 | (define (fx*/promote a b) |
297 | (call-with-values (lambda () (fx*/carry a b)) bignum2)) |
298 | |
299 | (define (fxneg/promote n) |
300 | (if (fx=/unchecked n *least-fixnum*) (bignum/unsigned n) |
301 | (fxneg/unchecked n))) |
302 | |
303 | (define (fxquotient/promote/unchecked a b) |
304 | (if (fxnegative/unchecked? b) |
305 | (if (fxnegative/unchecked? a) |
306 | (let ((q (fxquotient/unsigned/unchecked (fxneg/unchecked a) |
307 | (fxneg/unchecked b)))) |
308 | (if (fx=/unchecked q *least-fixnum*) (bignum/unsigned q) q)) |
309 | (fxneg/unchecked (fxquotient/unsigned/unchecked |
310 | a (fxneg/unchecked b)))) |
311 | (if (fxnegative/unchecked? a) |
312 | (fxneg/unchecked (fxquotient/unsigned/unchecked |
313 | (fxneg/unchecked a) b)) |
314 | (fxquotient/unsigned/unchecked a b)))) |
315 | |
316 | (define (fxremainder/unchecked a b) |
317 | (if (fxnegative/unchecked? b) |
318 | (if (fxnegative/unchecked? a) |
319 | (fxneg/unchecked (fxremainder/unsigned/unchecked |
320 | (fxneg/unchecked a) (fxneg/unchecked b))) |
321 | (fxremainder/unsigned/unchecked a (fxneg/unchecked b))) |
322 | (if (fxnegative/unchecked? a) |
323 | (fxneg/unchecked (fxremainder/unsigned/unchecked |
324 | (fxneg/unchecked a) b)) |
325 | (fxremainder/unsigned/unchecked a b)))) |
326 | |
327 | (define (bnneg n) |
328 | (let ((len (bignum-length n))) |
329 | (define r (make-bignum len)) |
330 | (define (copy k) |
331 | (bignum-set! r k (bignum-ref n k)) |
332 | (if (fx=/unchecked k 0) r (copy (fx-/unchecked k 1)))) |
333 | (if (bignum-negative? n) (copy (fx-/unchecked len 1)) |
334 | (if (and (fx=/unchecked len 1) |
335 | (fx=/unchecked (bignum-ref n 0) *least-fixnum*)) |
336 | *least-fixnum* |
337 | (bignum-set-negative! (copy (fx-/unchecked len 1))))))) |
338 | |
339 | (define (bignum-normalize! n) |
340 | (let loop ((k (fx-/unchecked (bignum-length n) 1))) |
341 | (cond ((fx=/unchecked k 0) |
342 | (let ((lo (bignum-ref n 0))) |
343 | (if (fxnegative/unchecked? lo) |
344 | ;; high bit set: fits in signed fixnum in singular case |
345 | (if (and (bignum-negative? n) |
346 | (fx=/unchecked lo *least-fixnum*)) lo |
347 | (bignum-truncate! n 1)) |
348 | ;; high bit clear: always fits in signed fixnum |
349 | (if (bignum-negative? n) (fxneg/unchecked lo) lo)))) |
350 | ((fx=/unchecked (bignum-ref n k) 0) (loop (fx-/unchecked k 1))) |
351 | (else (bignum-truncate! n (fx+/unchecked k 1)))))) |
352 | |
353 | (define (bignum-bit-stream n) |
354 | (define nwords (bignum-length n)) |
355 | (define (loop word seen-words bits-left) |
356 | (if (fx=/unchecked bits-left 0) |
357 | (if (fx=/unchecked seen-words nwords) '() |
358 | (loop (bignum-ref n seen-words) (fx+/unchecked seen-words 1) |
359 | *fixnum-width*)) |
360 | (cons (fxand word 1) |
361 | (delay (loop (fxshift word -1) seen-words |
362 | (fx-/unchecked bits-left 1)))))) |
363 | (loop (bignum-ref n 0) 1 *fixnum-width*)) |
364 | |
365 | (define stream-head car) |
366 | (define (stream-tail s) (force (cdr s))) |
367 | |
368 | (define (bn< a b) |
369 | (if (bignum-negative? a) |
370 | (if (bignum-negative? b) |
371 | (fxnegative/unchecked? (bncompare/unsigned b a)) |
372 | #t) |
373 | (if (bignum-negative? b) |
374 | #f |
375 | (fxnegative/unchecked? (bncompare/unsigned a b))))) |
376 | |
377 | (define (bncompare/unsigned a b) |
378 | (let ((alen (bignum-length a)) |
379 | (blen (bignum-length b))) |
380 | (cond ((fx=/unchecked alen blen) |
381 | (let loop ((k (fx-/unchecked alen 1))) |
382 | (if (fx=/unchecked k -1) 0 |
383 | (let ((ak (bignum-ref a k)) |
384 | (bk (bignum-ref b k))) |
385 | (cond ((fx=/unchecked ak bk) (loop (fx-/unchecked k 1))) |
386 | ((fx</unsigned ak bk) -1) |
387 | (else 1)))))) |
388 | ((fx</unsigned alen blen) -1) |
389 | (else 1)))) |
390 | |
391 | (define (bn= a b) |
392 | (and (eq? (bignum-negative? a) (bignum-negative? b)) |
393 | (let ((len (bignum-length a))) |
394 | (and (fx=/unchecked len (bignum-length b)) |
395 | (let loop ((k (fx-/unchecked len 1))) |
396 | (if (fx=/unchecked k -1) #t |
397 | (and (fx=/unchecked (bignum-ref a k) (bignum-ref b k)) |
398 | (loop (fx-/unchecked k 1))))))))) |
399 | |
400 | (define (bn+ a b) |
401 | (bignum-normalize! |
402 | (if (bignum-negative? a) |
403 | (if (bignum-negative? b) |
404 | (bignum-set-negative! (bn+/unsigned a b)) |
405 | (bn-/unsigned b a)) |
406 | (if (bignum-negative? b) |
407 | (bn-/unsigned a b) |
408 | (bn+/unsigned a b))))) |
409 | |
410 | (define (bn+/unsigned a b) |
411 | (if (fx</unsigned (bignum-length a) (bignum-length b)) |
412 | (bn+/ordered b a) |
413 | (bn+/ordered a b))) |
414 | |
415 | (define (bn+/ordered long short) |
416 | (let ((llen (bignum-length long)) |
417 | (slen (bignum-length short)) |
418 | (r (make-bignum (fx+/unchecked (bignum-length long) 1))) |
419 | (carry-in 0)) |
420 | (do ((k 0 (fx+/unchecked k 1))) ((fx=/unchecked k slen)) |
421 | (receive (sum carry-out) (fx+/carry-unsigned (bignum-ref long k) |
422 | (bignum-ref short k) |
423 | carry-in) |
424 | (bignum-set! r k sum) |
425 | (set! carry-in carry-out))) |
426 | (do ((k slen (fx+/unchecked k 1))) ((fx=/unchecked k llen)) |
427 | (receive (sum carry-out) (fx+/carry-unsigned (bignum-ref long k) |
428 | carry-in) |
429 | (bignum-set! r k sum) |
430 | (set! carry-in carry-out))) |
431 | (bignum-set! r llen carry-in) |
432 | r)) |
433 | |
434 | (define (bn- a b) |
435 | (bignum-normalize! |
436 | (if (bignum-negative? a) |
437 | (if (bignum-negative? b) |
438 | (bn-/unsigned b a) |
439 | (bignum-set-negative! (bn+/unsigned a b))) |
440 | (if (bignum-negative? b) |
441 | (bn+/unsigned a b) |
442 | (bn-/unsigned a b))))) |
443 | |
444 | (define (bn-/unsigned a b) |
445 | (let ((d (bncompare/unsigned a b))) |
446 | (cond ((fxnegative/unchecked? d) |
447 | (bignum-set-negative! (bn-/ordered b a))) |
448 | ((fx=/unchecked d 0) (bignum/unsigned 0)) |
449 | (else (bn-/ordered a b))))) |
450 | |
451 | (define (bn-/ordered large small) |
452 | (let ((llen (bignum-length large)) |
453 | (slen (bignum-length small)) |
454 | (r (make-bignum (bignum-length large))) |
455 | (borrow-in 0)) |
456 | (do ((k 0 (fx+/unchecked k 1))) ((fx=/unchecked k slen)) |
457 | (receive (diff borrow-out) (fx-/borrow-unsigned (bignum-ref large k) |
458 | (bignum-ref small k) |
459 | borrow-in) |
460 | (bignum-set! r k diff) |
461 | (set! borrow-in borrow-out))) |
462 | (do ((k slen (fx+/unchecked k 1))) ((fx=/unchecked k llen)) |
463 | (receive (diff borrow-out) (fx-/borrow-unsigned (bignum-ref large k) |
464 | borrow-in) |
465 | (bignum-set! r k diff) |
466 | (set! borrow-in borrow-out))) |
467 | r)) |
468 | |
469 | (define (bn* a b) |
470 | (bignum-normalize! |
471 | (if (eq? (bignum-negative? a) (bignum-negative? b)) |
472 | (bn*/unsigned a b) |
473 | (bignum-set-negative! (bn*/unsigned a b))))) |
474 | |
475 | (define (bn*/unsigned a b) |
476 | (if (fx</unsigned (bignum-length a) (bignum-length b)) |
477 | (bn*/comba b a) |
478 | (bn*/comba a b))) |
479 | |
480 | ;; Comba's algorithm: base case (quadratic) multiply that avoids excess carrying and temporary allocation by proceeding column-wise. http://www.loper-os.org/?p=2186 |
481 | (define (bn*/comba long short) |
482 | (define llen (bignum-length long)) |
483 | (define slen (bignum-length short)) |
484 | (define rlen #f) |
485 | (define r #f) |
486 | ;; Intra-column accumulator / inter-column carry. Three words are enough as at most SLEN two-word terms are summed, and SLEN fits in a word. |
487 | (define acc0 0) |
488 | (define acc1 0) |
489 | (define acc2 0) |
490 | (define (column col start stop) |
491 | (do ((k start (fx+/unchecked k 1))) ((fx=/unchecked k stop)) |
492 | (receive (lo hi) (fx*/carry-unsigned |
493 | (bignum-ref long (fx-/unchecked col k)) |
494 | (bignum-ref short k)) |
495 | (receive (sum c) (fx+/carry-unsigned acc0 lo) |
496 | (set! acc0 sum) |
497 | (receive (sum c) (fx+/carry-unsigned acc1 hi c) |
498 | (set! acc1 sum) |
499 | (set! acc2 (fx+/unchecked acc2 c)))))) |
500 | (bignum-set! r col acc0) |
501 | ;; down-shift for carry-in to the next column |
502 | (set! acc0 acc1) |
503 | (set! acc1 acc2) |
504 | (set! acc2 0)) |
505 | (define (loop-lo col) |
506 | (if (fx=/unchecked col slen) (loop-mid col) |
507 | (let ((col+1 (fx+/unchecked col 1))) |
508 | (column col 0 col+1) |
509 | (loop-lo col+1)))) |
510 | (define (loop-mid col) ;; for when lengths differ |
511 | (if (fx=/unchecked col llen) (loop-hi col) |
512 | (begin (column col 0 slen) |
513 | (loop-mid (fx+/unchecked col 1))))) |
514 | (define (loop-hi col) |
515 | (if (fx=/unchecked col rlen) r |
516 | (let ((col+1 (fx+/unchecked col 1))) |
517 | (column col (fx-/unchecked col+1 llen) slen) |
518 | (loop-hi col+1)))) |
519 | (set! rlen (fx+/unchecked llen slen)) |
520 | (set! r (make-bignum rlen)) |
521 | (loop-lo 0)) |
522 | |
523 | ;; High-radix restoring division: Algorithm 1.6 BasecaseDivRem from Richard P. Brent and Paul Zimmerman, "Modern Computer Arithmetic", 2010. |
524 | (define (bndiv A B) |
525 | (define n (bignum-length B)) ;; divisor length |
526 | (define m #f) ;; dividend-divisor length difference |
527 | (define Bn-1 #f) ;; high word of divisor |
528 | (define norm-shift #f) ;; bit shift for normalization step |
529 | (define Q #f) ;; quotient of m+1 words |
530 | (define j #f) ;; index of quotient word being computed |
531 | (define Qj #f) ;; guessed quotient word |
532 | (define n+j #f) ;; index of high word of reduced divisor |
533 | (define QjB #f) ;; product of divisor by guessed quotient word |
534 | |
535 | ;; Specialized scalar multiply, shifted comparison, shifted subtract-in-place, and sub-word shift operations for performance. |
536 | (define (mul-Qj k carry) |
537 | (if (fx=/unchecked k n) (bignum-set! QjB k carry) |
538 | (receive (prod-lo prod-hi) (fx*/carry-unsigned (bignum-ref B k) Qj) |
539 | (receive (sum carry) (fx+/carry-unsigned prod-lo carry) |
540 | (bignum-set! QjB k sum) |
541 | (mul-Qj (fx+/unchecked k 1) |
542 | (fx+/unchecked prod-hi carry)))))) |
543 | (define (A< X shift) |
544 | (let loop ((k (fx-/unchecked (bignum-length X) 1))) |
545 | (if (fx=/unchecked k -1) #f |
546 | (let ((Ak+shift (bignum-ref A (fx+/unchecked k shift))) |
547 | (Xk (bignum-ref X k))) |
548 | (cond ((fx</unsigned Ak+shift Xk) #t) |
549 | ((fx=/unchecked Ak+shift Xk) (loop (fx-/unchecked k 1))) |
550 | (else #f)))))) |
551 | (define (sub-in-place X Y shift) |
552 | (define len (bignum-length Y)) |
553 | (define k 0) |
554 | (define k+shift shift) |
555 | (define (loop borrow) |
556 | (if (fx=/unchecked k len) |
557 | (if (fx=/unchecked borrow 1) |
558 | (let ((Xk+shift (bignum-ref X k+shift))) |
559 | (if (fx=/unchecked Xk+shift 0) |
560 | (error "BUG: sub-in-place underflow")) |
561 | (bignum-set! X k+shift (fx-/unchecked Xk+shift 1)))) |
562 | (receive (diff borrow) (fx-/borrow-unsigned |
563 | (bignum-ref X k+shift) |
564 | (bignum-ref Y k) |
565 | borrow) |
566 | (bignum-set! X k+shift diff) |
567 | (set! k (fx+/unchecked k 1)) |
568 | (set! k+shift (fx+/unchecked k+shift 1)) |
569 | (loop borrow)))) |
570 | (loop 0)) |
571 | (define (shift-up X) |
572 | (define r (make-bignum (fx+/unchecked (bignum-length X) 1))) |
573 | (define len (bignum-length X)) |
574 | (define complement (fx-/unchecked norm-shift *fixnum-width*)) |
575 | (define k 0) |
576 | (define carry 0) |
577 | (define (loop) |
578 | (if (fx=/unchecked k len) |
579 | (if (fx=/unchecked carry 0) (bignum-truncate! r len) |
580 | (begin (bignum-set! r k carry) r)) |
581 | (let ((word (bignum-ref X k))) |
582 | (bignum-set! r k (fxior carry (fxshift/unsigned word |
583 | norm-shift))) |
584 | (set! carry (fxshift/unsigned word complement)) |
585 | (set! k (fx+/unchecked k 1)) |
586 | (loop)))) |
587 | (loop)) |
588 | (define (shift-down-in-place X) |
589 | (define neg-bits (fxneg/unchecked norm-shift)) |
590 | (define complement (fx-/unchecked *fixnum-width* norm-shift)) |
591 | (define k (fx-/unchecked (bignum-length X) 1)) |
592 | (define carry 0) |
593 | (define (loop) |
594 | (if (fx=/unchecked k -1) '() |
595 | (let ((word (bignum-ref X k))) |
596 | (bignum-set! X k (fxior carry (fxshift/unsigned word |
597 | neg-bits))) |
598 | (set! carry (fxshift/unsigned word complement)) |
599 | (set! k (fx-/unchecked k 1)) |
600 | (loop)))) |
601 | (loop)) |
602 | |
603 | ;; Long division proper |
604 | (define (loop-j) |
605 | (if (fxnegative/unchecked? j) '() |
606 | (begin (set! n+j (fx+/unchecked n j)) |
607 | (set! Qj (if (fx<=/unsigned Bn-1 (bignum-ref A n+j)) -1 |
608 | ;; ^ I think the < case is impossible |
609 | (fxquotient/ext/unsigned/unchecked |
610 | (bignum-ref A (fx+/unchecked n+j -1)) |
611 | (bignum-ref A n+j) |
612 | Bn-1))) |
613 | (mul-Qj 0 0) |
614 | (check-Qj)))) |
615 | (define (check-Qj) |
616 | (if (A< QjB j) |
617 | (begin (set! Qj (fx-/unchecked Qj 1)) |
618 | (sub-in-place QjB B 0) |
619 | (check-Qj)) |
620 | (begin (bignum-set! Q j Qj) |
621 | (sub-in-place A QjB j) |
622 | (if (not (fx=/unchecked (bignum-ref A n+j) 0)) |
623 | (error "BUG: remainder not reduced")) |
624 | (set! j (fx-/unchecked j 1)) |
625 | (loop-j)))) |
626 | |
627 | ;; Normalize: scale inputs so high bit of divisor is 1 |
628 | (set! norm-shift (fx-/unchecked *fixnum-width* |
629 | (fxlength/unsigned |
630 | (bignum-ref B (fx-/unchecked n 1))))) |
631 | (if (fx=/unchecked norm-shift *fixnum-width*) (zero-divisor)) |
632 | (set! A (shift-up A)) ;; copying A enables mutation |
633 | (set! B (shift-up B)) |
634 | (set! Bn-1 (bignum-ref B (fx-/unchecked n 1))) |
635 | |
636 | (set! m (fx-/unchecked (bignum-length A) n)) |
637 | (if (fxnegative/unchecked? m) (set! Q (bignum/unsigned 0)) |
638 | (begin (set! Q (make-bignum (fx+/unchecked m 1))) |
639 | (if (not (eq? (bignum-negative? A) (bignum-negative? B))) |
640 | (bignum-set-negative! Q)) |
641 | (if (A< B m) (bignum-set! Q m 0) |
642 | (begin (bignum-set! Q m 1) |
643 | (sub-in-place A B m))) |
644 | (set! QjB (make-bignum (fx+/unchecked n 1))) |
645 | (set! j (fx-/unchecked m 1)) |
646 | (loop-j) |
647 | ;; save looping over leading zeros, assuming truncate-in-place |
648 | (bignum-truncate! A n))) |
649 | (shift-down-in-place A) |
650 | (values (bignum-normalize! Q) (bignum-normalize! A))) |
651 | |
652 | (define (bnquotient a b) |
653 | (call-with-values (lambda () (bndiv a b)) first)) |
654 | |
655 | (define (bnremainder a b) |
656 | (call-with-values (lambda () (bndiv a b)) second)) |
657 | |
658 | (define flo-bn-radix (delay (flo*/unchecked flo2 (flonum/unsigned/unchecked |
659 | *least-fixnum*)))) |
660 | (define flo-log-bn-radix (delay (log/unchecked flo-bn-radix))) |
661 | |
662 | (define (bignum->flonum n) |
663 | (define len (bignum-length n)) |
664 | (define (loop k acc bits) |
665 | (cond ((fx=/unchecked k -1) acc) |
666 | ((fx<=/unchecked 53 bits) ;; significant bits in IEEE 754 double |
667 | ;; TODO use LOAD-EXPONENT/UNCHECKED, but beware of fixnum overflow in computing exponent |
668 | (flo*/unchecked |
669 | acc (exp/unchecked (flo*/unchecked |
670 | (flonum/unchecked (fx+/unchecked k 1)) |
671 | flo-log-bn-radix)))) |
672 | (else (loop (fx-/unchecked k 1) |
673 | (flo+/unchecked (flo*/unchecked acc flo-bn-radix) |
674 | (flonum/unsigned/unchecked |
675 | (bignum-ref n k))) |
676 | (fx+/unchecked bits *fixnum-width*))))) |
677 | (let ((r (loop (fx-/unchecked len 2) |
678 | (flonum/unsigned/unchecked |
679 | (bignum-ref n (fx-/unchecked len 1))) |
680 | 1))) ;; high word might only have one significant bit |
681 | (if (bignum-negative? n) (floneg/unchecked r) r))) |
682 | |
683 | ;; Convert nonzero bignum to minimal list of digits in a smaller power-of-two radix, least significant first, "reflowing" in linear time. |
684 | (define (bignum->digits n bits) |
685 | (define len (bignum-length n)) |
686 | (define mask (fx-/unchecked (fxshift 1 bits) 1)) |
687 | (define acc '()) |
688 | (define (push! digit) |
689 | (set! acc (cons (fxand mask digit) acc))) |
690 | (define (loop word bit) |
691 | (if (fx</unchecked word len) |
692 | (let ((low-bits (fxshift/unsigned (bignum-ref n word) |
693 | (fxneg/unchecked bit))) |
694 | (next-bit (fx+/unchecked bit bits)) |
695 | (next-word (fx+/unchecked word 1))) |
696 | (if (fx</unchecked *fixnum-width* next-bit) |
697 | ;; Join slices from adjacent words... |
698 | (if (fx</unchecked next-word len) |
699 | (begin (push! (fxior low-bits |
700 | (fxshift (bignum-ref n next-word) |
701 | (fx-/unchecked |
702 | *fixnum-width* bit)))) |
703 | (loop next-word (fx-/unchecked |
704 | next-bit *fixnum-width*))) |
705 | ;; unless this is the last word... |
706 | (push! low-bits)) |
707 | ;; or digit is entirely in the current word. |
708 | (begin (push! low-bits) |
709 | (if (fx=/unchecked next-bit *fixnum-width*) |
710 | (loop next-word 0) |
711 | (loop word next-bit))))))) |
712 | (loop 0 0) |
713 | ;; Strip leading zeros |
714 | (do ((acc acc (cdr/unchecked acc))) |
715 | ((fx</unsigned 0 (car/unchecked acc)) (reverse acc)))) |
716 | |
717 | (define (extend-padded acc chunk width) |
718 | (cons (make-string (fx-/unchecked width (string-length chunk)) #\0) |
719 | (cons chunk acc))) |
720 | |
721 | (define (press-num-string neg chunks) |
722 | (apply/unchecked string-append (if neg (cons "-" chunks) chunks))) |
723 | |
724 | (define dec-chunk-digits (delay (quotient (* *fixnum-width*-1 3) 10))) |
725 | (define dec-chunk-radix (delay (bignum (expt 10 dec-chunk-digits)))) |
726 | |
727 | (define (bignum->dec n) |
728 | ;; Quadratic (repeated division by fixnum constant) |
729 | (define (loop acc n) |
730 | (cond ((bignum? n) |
731 | (receive (q r) (bndiv n dec-chunk-radix) |
732 | (loop (extend-padded acc (fixnum->dec/unchecked r) |
733 | dec-chunk-digits) |
734 | q))) |
735 | ((fx=/unchecked n 0) acc) |
736 | (else (cons (fixnum->dec/unchecked n) acc)))) |
737 | (let ((neg (bignum-negative? n))) |
738 | (press-num-string neg (loop '() (if neg (bnneg n) n))))) |
739 | |
740 | (define hex-chunk-digits (delay (quotient *fixnum-width*-1 4))) |
741 | (define hex-chunk-bits (delay (* hex-chunk-digits 4))) |
742 | |
743 | (define (bignum->hex n) |
744 | (do ((digits (bignum->digits n hex-chunk-bits) (cdr/unchecked digits)) |
745 | (acc '() (extend-padded |
746 | acc (fixnum->hex/unchecked (car/unchecked digits)) |
747 | hex-chunk-digits))) |
748 | ((null? (cdr/unchecked digits)) |
749 | (press-num-string |
750 | (bignum-negative? n) |
751 | (cons (fixnum->hex/unchecked (car/unchecked digits)) acc))))) |
752 | |
753 | (define oct-chunk-digits (delay (quotient *fixnum-width*-1 3))) |
754 | (define oct-chunk-bits (delay (fx*/wrap 3 oct-chunk-digits))) |
755 | |
756 | (define (bignum->oct n) |
757 | (do ((digits (bignum->digits n oct-chunk-bits) (cdr/unchecked digits)) |
758 | (acc '() (extend-padded |
759 | acc (fixnum->oct/unchecked (car/unchecked digits)) |
760 | oct-chunk-digits))) |
761 | ((null? (cdr/unchecked digits)) |
762 | (press-num-string |
763 | (bignum-negative? n) |
764 | (cons (fixnum->oct/unchecked (car/unchecked digits)) acc))))) |
765 | |
766 | (define (bignum->bin n) |
767 | (define len-1 (fx-/unchecked (bignum-length n) 1)) |
768 | (define (loop k acc) |
769 | (if (fx=/unchecked k len-1) |
770 | (cons (fixnum->bin/unsigned/unchecked (bignum-ref n k)) acc) |
771 | (loop (fx+/unchecked k 1) |
772 | (extend-padded acc (fixnum->bin/unsigned/unchecked |
773 | (bignum-ref n k)) |
774 | *fixnum-width*)))) |
775 | (press-num-string (bignum-negative? n) (loop 0 '()))) |
776 | |
777 | ;;; Procedure library |
778 | |
779 | ;;; 6.1 Equivalence predicates |
780 | |
781 | (define (eqv? a b) |
782 | (cond ((eq? a b) #t) |
783 | ;; char and fixnum covered by EQ? (implementation dependent) |
784 | ((bignum? a) (and (bignum? b) (bn= a b))) |
785 | ;; exactness must match |
786 | ((flonum? a) (and (flonum? b) (flo=/unchecked a b))) |
787 | (else #f))) |
788 | |
789 | (define (vector=? a b) |
790 | (define len (vector-length a)) |
791 | (define (loop k) |
792 | (if (fx=/unchecked k len) #t |
793 | (and (equal? (vector-ref/unchecked a k) (vector-ref/unchecked b k)) |
794 | (loop (fx+/unchecked k 1))))) |
795 | (and (fx=/unchecked len (vector-length b)) |
796 | (loop 0))) |
797 | |
798 | (define (equal? a b) |
799 | (cond ((eqv? a b) #t) |
800 | ((pair? a) (and (pair? b) |
801 | (equal? (car/unchecked a) (car/unchecked b)) |
802 | (equal? (cdr/unchecked a) (cdr/unchecked b)))) |
803 | ((vector? a) (and (vector? b) (vector=? a b))) |
804 | ((string? a) (and (string? b) (string=? a b))) |
805 | (else #f))) |
806 | |
807 | ;;; 6.2.5 Numerical operations |
808 | |
809 | (define (exp10/flonum x) |
810 | (exp/unchecked (flo*/unchecked flo-log-10 x))) |
811 | |
812 | ;; For comparisons of mixed exactness to be transitive, arguments must not be converted inexactly (e.g. "promoting" to flonum) if this could cause the result to differ from a true comparison of the represented values. |
813 | |
814 | (define (=/mixed flonum exact-int) |
815 | (and (integer? flonum) |
816 | (not (inf/unchecked? flonum)) |
817 | (=/generic (inexact->exact flonum) exact-int))) |
818 | |
819 | (define (</mixed flonum exact-int) |
820 | (if (inf/unchecked? flonum) (flonegative/unchecked? flonum) |
821 | (</generic (inexact->exact (floor/unchecked flonum)) exact-int))) |
822 | |
823 | (define (>/mixed flonum exact-int) |
824 | (if (inf/unchecked? flonum) (not (flonegative/unchecked? flonum)) |
825 | (>/generic (inexact->exact (ceiling/unchecked flonum)) exact-int))) |
826 | |
827 | (define (<=/mixed flonum exact-int) |
828 | (if (inf/unchecked? flonum) (flonegative/unchecked? flonum) |
829 | (<=/generic (inexact->exact (ceiling/unchecked flonum)) exact-int))) |
830 | |
831 | (define (>=/mixed flonum exact-int) |
832 | (if (inf/unchecked? flonum) (not (flonegative/unchecked? flonum)) |
833 | (>=/generic (inexact->exact (floor/unchecked flonum)) exact-int))) |
834 | |
835 | ;; The convention for 2-arg generics is to dispatch on the type of the second argument first, as some operations (subtraction, division) do special things based on it but not the first. |
836 | |
837 | (define (=/fixnum z fx) |
838 | (cond ((fixnum? z) (fx=/unchecked z fx)) |
839 | ((bignum? z) #f) ;; assuming demotion |
840 | ((flonum? z) (=/mixed z fx)) |
841 | (else (not-number z)))) |
842 | |
843 | (define (</fixnum x fx) |
844 | (cond ((fixnum? x) (fx</unchecked x fx)) |
845 | ((bignum? x) (bignum-negative? x)) ;; assuming demotion |
846 | ((flonum? x) (</mixed x fx)) |
847 | (else (not-number x)))) |
848 | |
849 | (define (<=/fixnum x fx) |
850 | (cond ((fixnum? x) (fx<=/unchecked x fx)) |
851 | ((bignum? x) (bignum-negative? x)) ;; assuming demotion |
852 | ((flonum? x) (<=/mixed x fx)) |
853 | (else (not-number x)))) |
854 | |
855 | (define (=/bignum z bn) |
856 | (cond ((fixnum? z) #f) ;; assuming demotion |
857 | ((bignum? z) (bn= z bn)) |
858 | ((flonum? z) (=/mixed z bn)) |
859 | (else (not-number z)))) |
860 | |
861 | (define (</bignum x bn) |
862 | (cond ((fixnum? x) (not (bignum-negative? bn))) ;; assuming demotion |
863 | ((bignum? x) (bn< x bn)) |
864 | ((flonum? x) (</mixed x bn)) |
865 | (else (not-number x)))) |
866 | |
867 | (define (<=/bignum x bn) |
868 | (cond ((fixnum? x) (not (bignum-negative? bn))) ;; assuming demotion |
869 | ((bignum? x) (not (bn< bn x))) ;; reversing |
870 | ((flonum? x) (<=/mixed x bn)) |
871 | (else (not-number x)))) |
872 | |
873 | (define (=/flonum z fl) |
874 | (cond ((flonum? z) (flo=/unchecked z fl)) |
875 | ((integer? z) (=/mixed fl z)) ;; reversing |
876 | (else (not-number z)))) |
877 | |
878 | (define (</flonum x fl) |
879 | (cond ((flonum? x) (flo</unchecked x fl)) |
880 | ((integer? x) (>/mixed fl x)) ;; reversing |
881 | (else (not-number x)))) |
882 | |
883 | (define (<=/flonum x fl) |
884 | (cond ((flonum? x) (flo<=/unchecked x fl)) |
885 | ((integer? x) (>=/mixed fl x)) ;; reversing |
886 | (else (not-number x)))) |
887 | |
888 | (define (=/generic z1 z2) |
889 | (cond ((fixnum? z2) (=/fixnum z1 z2)) |
890 | ((bignum? z2) (=/bignum z1 z2)) |
891 | ((flonum? z2) (=/flonum z1 z2)) |
892 | (else (not-number z2)))) |
893 | |
894 | (define (</generic x1 x2) |
895 | (cond ((fixnum? x2) (</fixnum x1 x2)) |
896 | ((bignum? x2) (</bignum x1 x2)) |
897 | ((flonum? x2) (</flonum x1 x2)) |
898 | (else (not-number x2)))) |
899 | |
900 | (define (>/generic x1 x2) ;; reversing dispatch order |
901 | (cond ((fixnum? x1) (</fixnum x2 x1)) |
902 | ((bignum? x1) (</bignum x2 x1)) |
903 | ((flonum? x1) (</flonum x2 x1)) |
904 | (else (not-number x1)))) |
905 | |
906 | (define (<=/generic x1 x2) |
907 | (cond ((fixnum? x2) (<=/fixnum x1 x2)) |
908 | ((bignum? x2) (<=/bignum x1 x2)) |
909 | ((flonum? x2) (<=/flonum x1 x2)) |
910 | (else (not-number x2)))) |
911 | |
912 | (define (>=/generic x1 x2) ;; reversing dispatch order |
913 | (cond ((fixnum? x1) (<=/fixnum x2 x1)) |
914 | ((bignum? x1) (<=/bignum x2 x1)) |
915 | ((flonum? x1) (<=/flonum x2 x1)) |
916 | (else (not-number x1)))) |
917 | |
918 | (define =* (delay (all-pairwise =/generic))) |
919 | (define <* (delay (all-pairwise </generic))) |
920 | (define >* (delay (all-pairwise >/generic))) |
921 | (define <=* (delay (all-pairwise <=/generic))) |
922 | (define >=* (delay (all-pairwise >=/generic))) |
923 | |
924 | (define (= z1 z2 . zs) (=* z1 z2 zs)) |
925 | (define (< x1 x2 . xs) (<* x1 x2 xs)) |
926 | (define (> x1 x2 . xs) (>* x1 x2 xs)) |
927 | (define (<= x1 x2 . xs) (<=* x1 x2 xs)) |
928 | (define (>= x1 x2 . xs) (>=* x1 x2 xs)) |
929 | |
930 | (define (zero? z) |
931 | (cond ((fixnum? z) (fx=/unchecked z 0)) |
932 | ((bignum? z) #f) |
933 | ((flonum? z) (flo=/unchecked z flo0)) |
934 | (else (not-number z)))) |
935 | |
936 | (define (positive? x) |
937 | (cond ((fixnum? x) (fx</unchecked 0 x)) |
938 | ((bignum? x) (not (bignum-negative? x))) |
939 | ((flonum? x) (flo</unchecked flo0 x)) |
940 | (else (not-number x)))) |
941 | |
942 | (define (negative? x) |
943 | (cond ((fixnum? x) (fxnegative/unchecked? x)) |
944 | ((bignum? x) (bignum-negative? x)) |
945 | ((flonum? x) (flonegative/unchecked? x)) |
946 | (else (not-number x)))) |
947 | |
948 | (define (odd? n) |
949 | (cond ((fixnum? n) (fx=/unchecked (fxand n 1) 1)) |
950 | ((bignum? n) (fx=/unchecked (fxand (bignum-ref n 0) 1) 1)) |
951 | ((flonum? n) (flo=/unchecked (floremainder/unchecked |
952 | (if (flonegative/unchecked? n) |
953 | (floneg/unchecked n) n) flo2) |
954 | flo1)) |
955 | (else (not-number n)))) |
956 | |
957 | (define (even? n) |
958 | (cond ((fixnum? n) (fx=/unchecked (fxand n 1) 0)) |
959 | ((bignum? n) (fx=/unchecked (fxand (bignum-ref n 0) 1) 0)) |
960 | ((flonum? n) (flo=/unchecked (floremainder/unchecked n flo2) flo0)) |
961 | (else (not-number n)))) |
962 | |
963 | (define (flonum/generic x) |
964 | (cond ((fixnum? x) (flonum/unchecked x)) |
965 | ((bignum? x) (bignum->flonum x)) |
966 | ((flonum? x) x) |
967 | (else (not-number x)))) |
968 | |
969 | (define (max2 x1 x2) |
970 | (cond ((flonum? x1) (flonum/generic (if (</flonum x2 x1) x1 x2))) |
971 | ((flonum? x2) (flonum/generic (if (</flonum x1 x2) x2 x1))) |
972 | (else (if (</generic x1 x2) x2 x1)))) |
973 | |
974 | (define (min2 x1 x2) |
975 | (cond ((flonum? x1) (flonum/generic (if (</flonum x2 x1) x2 x1))) |
976 | ((flonum? x2) (flonum/generic (if (</flonum x1 x2) x1 x2))) |
977 | (else (if (</generic x1 x2) x1 x2)))) |
978 | |
979 | (define max* (delay (foldl max2))) |
980 | (define min* (delay (foldl min2))) |
981 | |
982 | (define (max x1 . xs) (max* x1 xs)) |
983 | (define (min x1 . xs) (min* x1 xs)) |
984 | |
985 | ;; Common dispatch patterns based on type promotion |
986 | |
987 | (define (dispatch-fixnum fx-op bn-op flo-op) |
988 | (lambda (z fx) |
989 | (cond ((fixnum? z) (fx-op z fx)) |
990 | ((bignum? z) (bn-op z (bignum fx))) |
991 | ((flonum? z) (flo-op z (flonum/unchecked fx))) |
992 | (else (not-number z))))) |
993 | |
994 | (define (dispatch-bignum bn-op flo-op) |
995 | (lambda (z bn) |
996 | (cond ((fixnum? z) (bn-op (bignum z) bn)) |
997 | ((bignum? z) (bn-op z bn)) |
998 | ((flonum? z) (flo-op z (bignum->flonum bn))) |
999 | (else (not-number z))))) |
1000 | |
1001 | (define (dispatch-num2 fx-op bn-op flo-op) |
1002 | (let ((dfx (dispatch-fixnum fx-op bn-op flo-op)) |
1003 | (dbn (dispatch-bignum bn-op flo-op))) |
1004 | (lambda (z1 z2) |
1005 | (cond ((fixnum? z2) (dfx z1 z2)) |
1006 | ((bignum? z2) (dbn z1 z2)) |
1007 | ((flonum? z2) (flo-op (flonum/generic z1) z2)) |
1008 | (else (not-number z2)))))) |
1009 | |
1010 | (define add2 (delay (dispatch-num2 fx+/promote bn+ flo+/unchecked))) |
1011 | (define mul2 (delay (dispatch-num2 fx*/promote bn* flo*/unchecked))) |
1012 | |
1013 | (define sub/bignum (delay (dispatch-bignum bn- flo-/unchecked))) |
1014 | |
1015 | (define (sub2 z1 z2) |
1016 | (cond ((fixnum? z2) (add2 z1 (fxneg/promote z2))) |
1017 | ((bignum? z2) (sub/bignum z1 z2)) |
1018 | ((flonum? z2) (flo-/unchecked (flonum/generic z1) z2)) |
1019 | (else (not-number z2)))) |
1020 | |
1021 | (define (div2 z1 z2) |
1022 | (flodiv/unchecked |
1023 | (flonum/generic z1) |
1024 | (cond ((fixnum? z2) (if (fx=/unchecked z2 0) (zero-divisor) |
1025 | (flonum/unchecked z2))) |
1026 | ((bignum? z2) (bignum->flonum z2)) |
1027 | ((flonum? z2) (if (flo=/unchecked z2 flo0) (zero-divisor) z2)) |
1028 | (else (not-number z2))))) |
1029 | |
1030 | (define add* (delay (foldl add2))) |
1031 | (define mul* (delay (foldl mul2))) |
1032 | (define sub* (delay (foldl sub2))) |
1033 | (define div* (delay (foldl div2))) |
1034 | |
1035 | (define (+ . zs) |
1036 | (if (pair? zs) (add* (car/unchecked zs) (cdr/unchecked zs)) 0)) |
1037 | |
1038 | (define (* . zs) |
1039 | (if (pair? zs) (mul* (car/unchecked zs) (cdr/unchecked zs)) 1)) |
1040 | |
1041 | (define (- z . zs) |
1042 | (cond ((pair? zs) (sub* (sub2 z (car/unchecked zs)) |
1043 | (cdr/unchecked zs))) |
1044 | ((fixnum? z) (fxneg/promote z)) |
1045 | ((bignum? z) (bnneg z)) |
1046 | ((flonum? z) (floneg/unchecked z)) |
1047 | (else (not-number z)))) |
1048 | |
1049 | (define (/ z . zs) |
1050 | (if (pair? zs) (div* (div2 z (car/unchecked zs)) |
1051 | (cdr/unchecked zs)) |
1052 | (div2 flo1 z))) |
1053 | |
1054 | (define (abs x) |
1055 | (cond ((fixnum? x) (if (fxnegative/unchecked? x) (fxneg/promote x) x)) |
1056 | ((bignum? x) (if (bignum-negative? x) (bnneg x) x)) |
1057 | ((flonum? x) (if (flonegative/unchecked? x) (floneg/unchecked x) |
1058 | x)) |
1059 | (else (not-number x)))) |
1060 | |
1061 | (define (floquotient/int/unchecked n1 n2) |
1062 | (floquotient/unchecked (require-integer n1) (require-integer n2))) |
1063 | |
1064 | (define (floremainder/int/unchecked n1 n2) |
1065 | (floremainder/unchecked (require-integer n1) (require-integer n2))) |
1066 | |
1067 | (define quotient/fixnum |
1068 | (delay (dispatch-fixnum fxquotient/promote/unchecked bnquotient |
1069 | floquotient/int/unchecked))) |
1070 | |
1071 | (define quotient/bignum |
1072 | (delay (dispatch-bignum bnquotient floquotient/int/unchecked))) |
1073 | |
1074 | (define remainder/fixnum |
1075 | (delay (dispatch-fixnum fxremainder/unchecked bnremainder |
1076 | floremainder/int/unchecked))) |
1077 | |
1078 | (define remainder/bignum |
1079 | (delay (dispatch-bignum bnremainder floremainder/int/unchecked))) |
1080 | |
1081 | (define (quotient n1 n2) |
1082 | (cond ((fixnum? n2) |
1083 | (if (fx=/unchecked n2 0) (zero-divisor) (quotient/fixnum n1 n2))) |
1084 | ((bignum? n2) (quotient/bignum n1 n2)) |
1085 | ((flonum? n2) |
1086 | (if (flo=/unchecked n2 flo0) (zero-divisor) |
1087 | (floquotient/int/unchecked (flonum/generic n1) n2))) |
1088 | (else (not-integer n2)))) |
1089 | |
1090 | (define (remainder n1 n2) |
1091 | (cond ((fixnum? n2) |
1092 | (if (fx=/unchecked n2 0) (zero-divisor) (remainder/fixnum n1 n2))) |
1093 | ((bignum? n2) (remainder/bignum n1 n2)) |
1094 | ((flonum? n2) |
1095 | (if (flo=/unchecked n2 flo0) (zero-divisor) |
1096 | (floremainder/int/unchecked (flonum/generic n1) n2))) |
1097 | (else (not-integer n2)))) |
1098 | |
1099 | (define (modulo n1 n2) |
1100 | (let ((r (remainder n1 n2))) |
1101 | (if (eq? (negative? r) (negative? n2)) r |
1102 | (add2 r n2)))) |
1103 | |
1104 | (define (gcd2 n1 n2) |
1105 | (if (= n2 0) n1 |
1106 | (gcd2 n2 (remainder n1 n2)))) |
1107 | |
1108 | (define gcd* (delay (foldl gcd2))) |
1109 | |
1110 | (define (gcd . ns) |
1111 | (if (pair? ns) (gcd* (car/unchecked ns) (cdr/unchecked ns)) 0)) |
1112 | |
1113 | (define (lcm . ns) |
1114 | (if (pair? ns) |
1115 | (quotient (mul* (car/unchecked ns) (cdr/unchecked ns)) |
1116 | (gcd* (car/unchecked ns) (cdr/unchecked ns))) |
1117 | 1)) |
1118 | |
1119 | ; numerator |
1120 | ; denominator |
1121 | |
1122 | (define (floor x) |
1123 | (cond ((flonum? x) (floor/unchecked x)) |
1124 | ((exact? x) x) |
1125 | (else (not-number x)))) |
1126 | |
1127 | (define (ceiling x) |
1128 | (cond ((flonum? x) (ceiling/unchecked x)) |
1129 | ((exact? x) x) |
1130 | (else (not-number x)))) |
1131 | |
1132 | (define (truncate x) |
1133 | (cond ((flonum? x) (truncate/unchecked x)) |
1134 | ((exact? x) x) |
1135 | (else (not-number x)))) |
1136 | |
1137 | (define (round x) |
1138 | (cond ((flonum? x) (round/unchecked x)) |
1139 | ((exact? x) x) |
1140 | (else (not-number x)))) |
1141 | |
1142 | ; rationalize |
1143 | |
1144 | (define (irrational flo-op special-fx-arg special-result) |
1145 | (lambda (z) |
1146 | (cond ((flonum? z) (flo-op z)) |
1147 | ((fixnum? z) (if (fx=/unchecked z special-fx-arg) special-result |
1148 | (flo-op (flonum/unchecked z)))) |
1149 | ((bignum? z) (flo-op (bignum->flonum z))) |
1150 | (else (not-number z))))) |
1151 | |
1152 | (define atan1 (delay (irrational atan/unchecked 0 0))) |
1153 | |
1154 | (define (atan2 y x) |
1155 | (cond ((flonum? y) (atan2/unchecked y (flonum/generic x))) |
1156 | ((fixnum? y) (if (and (fx=/unchecked y 0) (positive? x)) 0 |
1157 | (atan2/unchecked (flonum/unchecked y) |
1158 | (flonum/generic x)))) |
1159 | ((bignum? y) (atan2/unchecked (bignum->flonum y) |
1160 | (flonum/generic x))) |
1161 | (else (not-number y)))) |
1162 | |
1163 | (define (atan z . zs) |
1164 | (cond ((null? zs) (atan1 z)) |
1165 | ((null? (cdr/unchecked zs)) (atan2 z (car/unchecked zs))) |
1166 | (else (too-many-args)))) |
1167 | |
1168 | ;; For exact base and non-negative fixnum power |
1169 | (define (expt/exact/fixnum base power) |
1170 | (do ((base base (* base base)) |
1171 | (power power (fxshift power -1)) |
1172 | (acc 1 (if (fx=/unchecked (fxand power 1) 1) (* acc base) acc))) |
1173 | ((fx=/unchecked power 0) acc))) |
1174 | |
1175 | ;; For exact base and sign-ignored bignum power. XXX this seems a bit ridiculous to compute, but who am I to stop you from trying? |
1176 | (define (expt/exact/bignum base power) |
1177 | (do ((base base (* base base)) |
1178 | (power (bignum-bit-stream power) (stream-tail power)) |
1179 | (acc 1 (if (fx=/unchecked (stream-head power) 1) (* acc base) acc))) |
1180 | ((null? power) acc))) |
1181 | |
1182 | ;; For positive flonum base, flonum power and result |
1183 | (define (expt/inexact/+base base power) |
1184 | (exp/unchecked (flo*/unchecked (log/unchecked base) power))) |
1185 | |
1186 | ;; For nonzero flonum base, flonum power and result |
1187 | (define (expt/inexact base power) |
1188 | (if (and (flonegative/unchecked? base) (integer? power)) |
1189 | (if (odd? power) |
1190 | (floneg/unchecked |
1191 | (expt/inexact/+base (floneg/unchecked base) power)) |
1192 | (expt/inexact/+base (floneg/unchecked base) power)) |
1193 | ;; For non-integer power of negative base, proceed anyway to get NaN (unspecified, but consistent with sqrt) |
1194 | (expt/inexact/+base base power))) |
1195 | |
1196 | ;; For fixnum power |
1197 | (define (expt/fixnum base power) |
1198 | (cond ((or (fixnum? base) (bignum? base)) |
1199 | (if (fxnegative/unchecked? power) |
1200 | (/ (expt/exact/fixnum base (fxneg/promote power))) |
1201 | (expt/exact/fixnum base power))) |
1202 | ((flonum? base) |
1203 | (cond ((fx=/unchecked power 0) 1) |
1204 | ((flo=/unchecked base flo0) flo0) |
1205 | ((flonegative/unchecked? base) |
1206 | (if (odd? power) |
1207 | (floneg/unchecked |
1208 | (expt/inexact/+base (floneg/unchecked base) |
1209 | (flonum/unchecked power))) |
1210 | (expt/inexact/+base (floneg/unchecked base) |
1211 | (flonum/unchecked power)))) |
1212 | (else (expt/inexact/+base base (flonum/unchecked power))))) |
1213 | (else (not-number base)))) |
1214 | |
1215 | ;; For bignum power |
1216 | (define (expt/bignum base power) |
1217 | (cond ((fixnum? base) |
1218 | (cond ((fx=/unchecked base 0) 0) |
1219 | ((fx=/unchecked base 1) 1) |
1220 | ((fx=/unchecked base -1) (if (odd? power) -1 1)) |
1221 | ((bignum-negative? power) |
1222 | (/ (expt/exact/bignum base power))) |
1223 | (else (expt/exact/bignum base power)))) |
1224 | ((bignum? base) |
1225 | (cond ((bignum-negative? power) |
1226 | (/ (expt/exact/bignum base power))) |
1227 | (else (expt/exact/bignum base power)))) |
1228 | ((flonum? base) |
1229 | (cond ((flo=/unchecked base flo0) flo0) |
1230 | ((flo=/unchecked base flo1) flo1) |
1231 | ((flo=/unchecked base flo-1) (if (odd? power) flo-1 flo1)) |
1232 | ((flonegative/unchecked? base) |
1233 | (if (odd? power) |
1234 | (floneg/unchecked |
1235 | (expt/inexact/+base (floneg/unchecked base) |
1236 | (bignum->flonum power))) |
1237 | (expt/inexact/+base (floneg/unchecked base) |
1238 | (bignum->flonum power)))) |
1239 | (else (expt/inexact/+base base (bignum->flonum power))))) |
1240 | (else (not-number base)))) |
1241 | |
1242 | ;; For flonum power (result could still be exact) |
1243 | (define (expt/flonum base power) |
1244 | (cond ((fixnum? base) |
1245 | (cond ((flo=/unchecked power flo0) flo1) |
1246 | ((fx=/unchecked base 0) flo0) |
1247 | ;; ^ inexact due to the 0^0 case (a low-valued inexact power could be a zero with error) |
1248 | ((fx=/unchecked base 1) 1) |
1249 | (else (expt/inexact (flonum/unchecked base) power)))) |
1250 | ((bignum? base) |
1251 | (cond ((flo=/unchecked power flo0) flo1) |
1252 | (else (expt/inexact (bignum->flonum base) power)))) |
1253 | ((flonum? base) |
1254 | (cond ((flo=/unchecked power flo0) flo1) |
1255 | ((flo=/unchecked base flo0) flo0) |
1256 | (else (expt/inexact base power)))) |
1257 | (else (not-number base)))) |
1258 | |
1259 | (define (expt z1 z2) |
1260 | (cond ((fixnum? z2) (expt/fixnum z1 z2)) |
1261 | ((bignum? z2) (expt/bignum z1 z2)) |
1262 | ((flonum? z2) (expt/flonum z1 z2)) |
1263 | (else (not-number z2)))) |
1264 | |
1265 | ; make-rectangular |
1266 | ; make-polar |
1267 | ; real-part |
1268 | ; imag-part |
1269 | ; magnitude |
1270 | ; angle |
1271 | |
1272 | (define (flonum->exact-int fraction exponent) |
1273 | (let ((n (load-exponent/unchecked fraction *fixnum-width*-1)) |
1274 | (exponent (fx-/unchecked exponent *fixnum-width*-1))) |
1275 | (let ((word (flonum->fixnum/unchecked n))) |
1276 | (if (fxnegative/unchecked? exponent) |
1277 | (fxshift word exponent) |
1278 | (let ((fraction (flo-/unchecked n (flonum/unchecked word)))) |
1279 | (if (flo=/unchecked fraction flo0) |
1280 | (* word (expt/exact/fixnum 2 exponent)) |
1281 | (+ (* word (expt/exact/fixnum 2 exponent)) |
1282 | (flonum->exact-int fraction exponent)))))))) |
1283 | |
1284 | (define (inexact->exact z) |
1285 | (cond ((flonum? z) |
1286 | (cond ((flo=/unchecked z flo0) 0) |
1287 | ((inf/unchecked? z) (error "infinite flonum")) |
1288 | ((integer? z) (call-with-values |
1289 | (lambda () (fraction/exponent/unchecked z)) |
1290 | flonum->exact-int)) |
1291 | (else (error "non-integer flonum:" z)))) ;; includes NaN |
1292 | ((exact? z) z) |
1293 | (else (not-number z)))) |
1294 | |
1295 | ;;; 6.2.6 Numerical I/O |
1296 | |
1297 | (define (number->string z . args) |
1298 | (define radix 10) |
1299 | (if (pair? args) |
1300 | (begin (if (pair? (cdr args)) (too-many-args)) |
1301 | (set! radix (car args)) |
1302 | (if (not (fixnum? radix)) |
1303 | (if (inexact? radix) (not-exact-int radix) |
1304 | (bad-radix radix))))) |
1305 | (cond ((fixnum? z) |
1306 | ((cond ((fx=/unchecked radix 10) fixnum->dec/unchecked) |
1307 | ((fx=/unchecked radix 16) fixnum->hex/unchecked) |
1308 | ((fx=/unchecked radix 8) fixnum->oct/unchecked) |
1309 | ((fx=/unchecked radix 2) fixnum->bin/unchecked) |
1310 | (else (bad-radix radix))) z)) |
1311 | ((bignum? z) |
1312 | ((cond ((fx=/unchecked radix 10) bignum->dec) |
1313 | ((fx=/unchecked radix 16) bignum->hex) |
1314 | ((fx=/unchecked radix 8) bignum->oct) |
1315 | ((fx=/unchecked radix 2) bignum->bin) |
1316 | (else (bad-radix radix))) z)) |
1317 | ((flonum? z) |
1318 | (cond ((fx=/unchecked radix 10) (flonum->dec/unchecked z)) |
1319 | ((memv radix '(16 8 2)) |
1320 | ;; XXX the spec is confusing here: seems to be allowed, but point and exponent notation are only allowed in decimal radix. So inexact integers could pass the round-trip test e.g. "#iabcdef000000000", but ew. |
1321 | (error "non-decimal radix for inexact number")) |
1322 | (else (bad-radix radix)))) |
1323 | (else (not-number z)))) |
1324 | |
1325 | (define (string->number s . args) |
1326 | ;; XXX what to do if both #e prefix and point/exponent/#? |
1327 | (define fail #f) |
1328 | (define acc #f) |
1329 | |
1330 | (define radix 10) |
1331 | (define exact #t) |
1332 | (define got-radix #f) |
1333 | (define got-exact #f) |
1334 | (define (set-radix! r) |
1335 | (if got-radix (fail)) (set! got-radix #t) (set! radix r)) |
1336 | (define (set-exact! e) |
1337 | (if got-exact (fail)) (set! got-exact #t) (set! exact e)) |
1338 | |
1339 | (define pos 0) |
1340 | (define len #f) |
1341 | (define (peek) (string-ref s pos)) |
1342 | (define (next!) |
1343 | (let ((c (string-ref s pos))) |
1344 | (set! pos (fx+/unchecked pos 1)) c)) |
1345 | (define (end?) (fx=/unchecked pos len)) |
1346 | |
1347 | (define (char->digit c) |
1348 | ;; Simultaneous ASCII digit conversion and range checking with memoized radix specialization. |
1349 | (set! char->digit |
1350 | (cond ((fx=/unchecked radix 2) |
1351 | (lambda (c) |
1352 | (cond ((char<? c #\0) #f) |
1353 | ;; (char->integer #\0) -> 48 |
1354 | ((char<=? c #\1) (fx-/unchecked (char->integer c) 48)) |
1355 | (else #f)))) |
1356 | ((fx=/unchecked radix 8) |
1357 | (lambda (c) |
1358 | (cond ((char<? c #\0) #f) |
1359 | ((char<=? c #\7) (fx-/unchecked (char->integer c) 48)) |
1360 | (else #f)))) |
1361 | ((fx=/unchecked radix 10) |
1362 | (lambda (c) |
1363 | (cond ((char<? c #\0) #f) |
1364 | ((char<=? c #\9) (fx-/unchecked (char->integer c) 48)) |
1365 | (else #f)))) |
1366 | ((fx=/unchecked radix 16) |
1367 | (lambda (c) |
1368 | (set! c (char->integer (char-upcase c))) |
1369 | ;; (- (char->integer #\A) 10) -> 55 |
1370 | (set! c (fx-/unchecked c (if (fx</unsigned c 58) 48 55))) |
1371 | (and (fx</unsigned c 16) c))))) ;; wrap negatives |
1372 | (char->digit c)) |
1373 | |
1374 | (define (<prefix>) |
1375 | (cond ((end?) (fail)) |
1376 | ((char=? (peek) #\#) |
1377 | (next!) |
1378 | (if (end?) (fail)) |
1379 | (case (char-downcase (next!)) |
1380 | ((#\e) (set-exact! #t)) |
1381 | ((#\i) (set-exact! #f)) |
1382 | ((#\b) (set-radix! 2)) |
1383 | ((#\o) (set-radix! 8)) |
1384 | ((#\d) (set-radix! 10)) |
1385 | ((#\x) (set-radix! 16)) |
1386 | (else (fail))) |
1387 | (<prefix>)) |
1388 | (else (<complex>)))) |
1389 | |
1390 | (define (<complex>) |
1391 | (let ((r (<real>))) |
1392 | (if (end?) r (fail)))) ;; stub |
1393 | |
1394 | (define (<real>) |
1395 | (let ((proc (if (fx=/unchecked radix 10) <ureal-10> <ureal-pow2>))) |
1396 | (cond ((end?) (fail)) |
1397 | ((char=? (peek) #\+) (next!) (proc)) |
1398 | ((char=? (peek) #\-) (next!) (- (proc))) |
1399 | (else (proc))))) |
1400 | |
1401 | (define (<ureal-pow2>) |
1402 | (if (end?) (fail)) |
1403 | (let ((d (char->digit (next!)))) |
1404 | (cond (d (set! acc (if exact d (flonum/unchecked d))) |
1405 | (ureal-pow2-loop)) |
1406 | (else (fail))))) |
1407 | (define (ureal-pow2-loop) |
1408 | (if (end?) acc |
1409 | (let* ((c (peek)) (d (char->digit c))) |
1410 | ;; XXX naive algorithm |
1411 | (cond (d (next!) |
1412 | (set! acc (+ (* acc radix) d)) |
1413 | (ureal-pow2-loop)) |
1414 | ((char=? c #\#) (set! acc (flonum/generic acc)) |
1415 | (sharp-loop)) |
1416 | ((char=? c #\/) (next!) |
1417 | (fraction)) |
1418 | (else acc))))) |
1419 | |
1420 | (define (<ureal-10>) |
1421 | (if (end?) (fail)) |
1422 | (let* ((c (next!)) (d (char->digit c))) |
1423 | (cond (d (set! acc (if exact d (flonum/unchecked d))) |
1424 | (ureal-10-loop)) |
1425 | ((char=? c #\.) (initial-point)) |
1426 | (else (fail))))) |
1427 | (define (ureal-10-loop) |
1428 | (if (end?) acc |
1429 | (let* ((c (peek)) (d (char->digit c))) |
1430 | ;; XXX naive algorithm |
1431 | (cond (d (next!) |
1432 | (set! acc (+ (* acc 10) d)) |
1433 | (ureal-10-loop)) |
1434 | ((char=? c #\.) (next!) |
1435 | (set! acc (flonum/generic acc)) |
1436 | (point-loop flo1/10)) |
1437 | ((char=? c #\#) (set! acc (flonum/generic acc)) |
1438 | (sharp-loop)) |
1439 | ((char=? c #\/) (next!) (fraction)) |
1440 | (else (<suffix>)))))) |
1441 | |
1442 | (define (sharp-loop) |
1443 | (cond ((end?) acc) |
1444 | ((char=? (peek) #\#) (next!) |
1445 | (set! acc (* radix acc)) |
1446 | (sharp-loop)) |
1447 | ((char=? (peek) #\.) (next!) |
1448 | (if (fx=/unchecked radix 10) |
1449 | (point-sharp-loop) (fail))) |
1450 | ((char=? (peek) #\/) (next!) |
1451 | (fraction)) |
1452 | (else acc))) |
1453 | |
1454 | (define (initial-point) |
1455 | (if (end?) (fail)) |
1456 | (let ((d (char->digit (next!)))) |
1457 | (cond (d (set! acc (flo*/unchecked (flonum/unchecked d) flo1/10)) |
1458 | (point-loop (flo*/unchecked flo1/10 flo1/10))) |
1459 | (else (fail))))) |
1460 | (define (point-loop place-val) |
1461 | (if (end?) acc |
1462 | (let ((d (char->digit (peek)))) |
1463 | ;; XXX naive algorithm |
1464 | (cond (d (next!) |
1465 | (set! acc (flo+/unchecked |
1466 | acc (flo*/unchecked place-val |
1467 | (flonum/unchecked d)))) |
1468 | (point-loop (flo*/unchecked place-val flo1/10))) |
1469 | (else (point-sharp-loop)))))) |
1470 | (define (point-sharp-loop) |
1471 | (cond ((end?) acc) |
1472 | ((char=? (peek) #\#) (next!) (point-sharp-loop)) |
1473 | (else (<suffix>)))) |
1474 | |
1475 | (define (<suffix>) |
1476 | (cond ((end?) acc) |
1477 | ((memv (char-downcase (peek)) '(#\e #\s #\f #\d #\l)) |
1478 | ;; all markers equivalent as we only have one float precision |
1479 | (next!) (exponent-sign)) |
1480 | (else acc))) |
1481 | |
1482 | (define (fraction) |
1483 | (fail)) ;; stub |
1484 | |
1485 | (define (exponent-sign) |
1486 | (define (exponent negative) |
1487 | (if (end?) (fail) |
1488 | (let ((d (char->digit (next!)))) |
1489 | (if d (let ((e (loop (flonum/unchecked d)))) |
1490 | (flo*/unchecked |
1491 | (flonum/generic acc) |
1492 | (exp10/flonum (if negative (floneg/unchecked e) e)))) |
1493 | (fail))))) |
1494 | (define (loop e) |
1495 | (if (end?) e |
1496 | (let ((d (char->digit (peek)))) |
1497 | (if d (begin (next!) (loop (flo+/unchecked |
1498 | (flo*/unchecked e flo10) |
1499 | (flonum/unchecked d)))) |
1500 | e)))) |
1501 | (cond ((end?) (fail)) |
1502 | ((char=? (peek) #\+) (next!) (exponent #f)) |
1503 | ((char=? (peek) #\-) (next!) (exponent #t)) |
1504 | (else (exponent #f)))) |
1505 | |
1506 | (set! len (string-length s)) |
1507 | (if (pair? args) |
1508 | (if (pair? (cdr args)) (too-many-args) |
1509 | (begin (set! radix (car args)) |
1510 | (if (memv radix '(2 8 10 16)) |
1511 | (if (not (fixnum? radix)) (not-exact-int radix)) |
1512 | (bad-radix radix))))) |
1513 | (call/cc (lambda (return) (set! fail (lambda () (return #f))) |
1514 | (<prefix>)))) |
1515 | ;; end of string->number (whew!) |
1516 | |
1517 | ;;; 6.3.2 Pairs and lists |
1518 | |
1519 | (define (list . args) args) |
1520 | |
1521 | ;; not tail recursive |
1522 | (define (append . args) |
1523 | (if (pair? args) |
1524 | (let loop ((lists args)) |
1525 | (let ((next (cdr/unchecked lists))) |
1526 | (if (pair? next) |
1527 | (append2 (car/unchecked lists) (loop next)) |
1528 | (car/unchecked lists)))) |
1529 | '())) |
1530 | |
1531 | (define (reverse l) |
1532 | (let loop ((accum '()) (l l)) |
1533 | (cond ((pair? l) (loop (cons (car/unchecked l) accum) |
1534 | (cdr/unchecked l))) |
1535 | ((null? l) accum) |
1536 | (else (not-list))))) |
1537 | |
1538 | (define (list-tail l k) |
1539 | (check-exact-non-negative-int k) |
1540 | (do ((k k (- k 1)) (l l (cdr l))) ((zero? k) l))) |
1541 | |
1542 | (define (list-ref l k) (car (list-tail l k))) |
1543 | |
1544 | (define (memq x l) |
1545 | (cond ((pair? l) (if (eq? x (car/unchecked l)) l |
1546 | (memq x (cdr/unchecked l)))) |
1547 | ((null? l) #f) |
1548 | (else (not-list)))) |
1549 | |
1550 | (define (memv x l) |
1551 | (cond ((pair? l) (if (eqv? x (car/unchecked l)) l |
1552 | (memv x (cdr/unchecked l)))) |
1553 | ((null? l) #f) |
1554 | (else (not-list)))) |
1555 | |
1556 | (define (member x l) |
1557 | (cond ((pair? l) (if (equal? x (car/unchecked l)) l |
1558 | (member x (cdr/unchecked l)))) |
1559 | ((null? l) #f) |
1560 | (else (not-list)))) |
1561 | |
1562 | (define (assq x l) |
1563 | (cond ((pair? l) (if (eq? x (caar l)) (car/unchecked l) |
1564 | (assq x (cdr/unchecked l)))) |
1565 | ((null? l) #f) |
1566 | (else (not-list)))) |
1567 | |
1568 | (define (assv x l) |
1569 | (cond ((pair? l) (if (eqv? x (caar l)) (car/unchecked l) |
1570 | (assv x (cdr/unchecked l)))) |
1571 | ((null? l) #f) |
1572 | (else (not-list)))) |
1573 | |
1574 | (define (assoc x l) |
1575 | (cond ((pair? l) (if (equal? x (caar l)) (car/unchecked l) |
1576 | (assoc x (cdr/unchecked l)))) |
1577 | ((null? l) #f) |
1578 | (else (not-list)))) |
1579 | |
1580 | ;;; 6.3.5 Strings |
1581 | |
1582 | (define (string . args) (list->string args)) |
1583 | |
1584 | (define (string->list s) |
1585 | (do ((k (fx+/unchecked (string-length s) -1) (fx+/unchecked k -1)) |
1586 | (accum '() (cons (string-ref/unchecked s k) accum))) |
1587 | ((fx=/unchecked k -1) accum))) |
1588 | |
1589 | ;;; 6.3.6 Vectors |
1590 | |
1591 | (define (vector . args) (list->vector args)) |
1592 | |
1593 | (define (vector->list v) |
1594 | (do ((k (fx-/unchecked (vector-length v) 1) (fx-/unchecked k 1)) |
1595 | (accum '() (cons (vector-ref/unchecked v k) accum))) |
1596 | ((fx=/unchecked k -1) accum))) |
1597 | |
1598 | ;;; 6.4 Control Features |
1599 | |
1600 | (define (apply proc . args) |
1601 | (if (pair? args) |
1602 | (let ((p2 (cdr/unchecked args))) |
1603 | (if (pair? p2) |
1604 | (do ((p1 args p2) |
1605 | (p2 p2 p3) |
1606 | (p3 (cdr/unchecked p2) (cdr/unchecked p3))) |
1607 | ((null? p3) |
1608 | (set-cdr/unchecked! p1 (copy-list (car/unchecked p2))))) |
1609 | (set! args (copy-list (car/unchecked args))))) |
1610 | (error "missing argument list")) |
1611 | (apply/unchecked proc args)) |
1612 | |
1613 | (define all-null? (delay (all null?))) |
1614 | (define all-pair? (delay (all pair?))) |
1615 | (define car*unchecked (delay (map1 car/unchecked))) |
1616 | (define cdr*unchecked (delay (map1 cdr/unchecked))) |
1617 | |
1618 | ;; not tail recursive |
1619 | (define (map proc list1 . lists) |
1620 | (define (loop lists) |
1621 | (cond ((pair? (car/unchecked lists)) |
1622 | (if (all-pair? (cdr/unchecked lists)) |
1623 | (cons (apply/unchecked proc (car*unchecked lists)) |
1624 | (loop (cdr*unchecked lists))) |
1625 | (uneven-lists))) |
1626 | ((null? (car/unchecked lists)) |
1627 | (if (all-null? (cdr/unchecked lists)) '() (uneven-lists))) |
1628 | (else (not-list)))) |
1629 | (loop (cons list1 lists))) |
1630 | |
1631 | (define (for-each proc list1 . lists) |
1632 | (define (loop lists) |
1633 | (cond ((pair? (car/unchecked lists)) |
1634 | (if (not (all-pair? (cdr/unchecked lists))) (uneven-lists)) |
1635 | (apply/unchecked proc (car*unchecked lists)) |
1636 | (loop (cdr*unchecked lists))) |
1637 | ((null? (car/unchecked lists)) |
1638 | (if (all-null? (cdr/unchecked lists)) '() |
1639 | (uneven-lists))) |
1640 | (else (not-list)))) |
1641 | (loop (cons list1 lists))) |
1642 | |
1643 | (define (dynamic-wind before thunk after) |
1644 | (call/cc (lambda (return) |
1645 | (push-winding! before after) |
1646 | (before) |
1647 | (call-with-values thunk return)))) |
1648 | |
1649 | ;;; 6.6.1 Ports |
1650 | |
1651 | (define (call-with-input-file filename proc) |
1652 | (let ((port (open-input-file filename))) |
1653 | (saving-values (lambda () (proc port)) |
1654 | (lambda () (close-input-port port))))) |
1655 | |
1656 | (define (call-with-output-file filename proc . options) |
1657 | (let ((port (apply open-output-file filename options))) |
1658 | (saving-values (lambda () (proc port)) |
1659 | (lambda () (close-output-port port))))) |
1660 | |
1661 | (define (with-input-from-file filename proc) |
1662 | (let ((saved (current-input-port)) |
1663 | (port (open-input-file filename))) |
1664 | (saving-values |
1665 | (lambda () (dynamic-wind (lambda () (set-input-port! port)) |
1666 | proc |
1667 | (lambda () (set-input-port! saved)))) |
1668 | (lambda () (close-input-port port))))) |
1669 | |
1670 | (define (with-output-to-file filename proc . options) |
1671 | (let ((saved (current-output-port)) |
1672 | (port (apply open-output-file filename options))) |
1673 | (saving-values |
1674 | (lambda () (dynamic-wind (lambda () (set-output-port! port)) |
1675 | proc |
1676 | (lambda () (set-output-port! saved)))) |
1677 | (lambda () (close-output-port port))))) |
1678 | |
1679 | ;;; 6.6.2 Input |
1680 | |
1681 | ;; Reader sentinels: newly allocated so not EQ? to any readable object (not sure if this would be guaranteed with a quoted pair...) |
1682 | (define rd-close-paren (cons 'special 'close-paren)) |
1683 | (define rd-dot (cons 'special 'dot)) |
1684 | |
1685 | (define (read . port) |
1686 | (define (eof-list) (error "unexpected end-of-file in list")) |
1687 | (define (read-datum) |
1688 | (let ((t (apply/unchecked read-token port))) |
1689 | (if (eof-object? t) t |
1690 | (case (car t) |
1691 | ((identifier) (string->symbol (cdr t))) |
1692 | ((open-paren) (build-list (read-datum))) |
1693 | ((close-paren) rd-close-paren) |
1694 | ((literal) (cdr t)) |
1695 | ((number) (or (string->number (cdr t)) |
1696 | (error "bad number token:" (cdr t)))) |
1697 | ((abbrev) (abbrev (cdr t) (read-datum))) |
1698 | ((dot) rd-dot) |
1699 | ((open-vector) (build-vector '() (read-datum))) |
1700 | ((named-char) (named-char (cdr t))) |
1701 | (else (error "BUG: unmatched token type")))))) |
1702 | (define (build-list d) |
1703 | (cond ((eq? d rd-close-paren) '()) |
1704 | ((eq? d rd-dot) (error "dotted list without first item")) |
1705 | ((eof-object? d) (eof-list)) |
1706 | (else (extend-list (list d))))) |
1707 | (define (extend-list head) |
1708 | (define tail head) |
1709 | (define (loop d) |
1710 | (cond ((eq? d rd-close-paren) head) |
1711 | ((eq? d rd-dot) (improper (read-datum))) |
1712 | ((eof-object? d) (eof-list)) |
1713 | (else (set-cdr! tail (list d)) |
1714 | (set! tail (cdr tail)) |
1715 | (loop (read-datum))))) |
1716 | (define (improper d) |
1717 | (cond ((eof-object? d) (eof-list)) |
1718 | ((eq? d rd-close-paren) |
1719 | (error "dotted list without last item")) |
1720 | ((eq? d rd-dot) (error "extra dot in dotted list"))) |
1721 | (let ((t (apply/unchecked read-token port))) |
1722 | (cond ((eof-object? t) (eof-list)) |
1723 | ((eq? (car t) 'close-paren) (set-cdr! tail d) head) |
1724 | (else (error "excess item in tail of dotted list"))))) |
1725 | (loop (read-datum))) |
1726 | (define (abbrev sym d) |
1727 | (cond ((eof-object? d) |
1728 | (error "unexpected end-of-file in abbreviation")) |
1729 | ((eq? d rd-close-paren) |
1730 | (error "unexpected close-paren in abbreviation")) |
1731 | ((eq? d rd-dot) |
1732 | (error "unexpected dot in abbreviation"))) |
1733 | (list sym d)) |
1734 | (define (build-vector acc d) |
1735 | (cond ((eof-object? d) (error "unexpected end-of-file in vector")) |
1736 | ((eq? d rd-close-paren) (reverse-list->vector/unchecked acc)) |
1737 | ((eq? d rd-dot) (error "unexpected dot in vector")) |
1738 | (else (build-vector (cons d acc) (read-datum))))) |
1739 | (define (named-char n) |
1740 | (integer->char |
1741 | (cond ((string=? n "space") 32) |
1742 | ((string=? n "newline") 10) |
1743 | (else (error "bad character name:" n))))) |
1744 | (let ((d (read-datum))) |
1745 | (cond ((eq? d rd-close-paren) (error "unexpected close-paren")) |
1746 | ((eq? d rd-dot) (error "unexpected dot")) |
1747 | (else d)))) |
1748 | |
1749 | ;;; 6.6.3 Output |
1750 | |
1751 | (define char-printer #f) |
1752 | (define string-printer #f) |
1753 | |
1754 | (define environment-specs |
1755 | `((,(null-environment 5) "NULL") |
1756 | (,(scheme-report-environment 5) "SCHEME-REPORT") |
1757 | (,(gales-scheme-environment) "GALES-SCHEME") |
1758 | (,(interaction-environment) "INTERACTION") |
1759 | (,(toplevel-environment) "TOPLEVEL"))) |
1760 | |
1761 | (define (write-char/quoted c) |
1762 | (write-string "#\\") |
1763 | (case (char->integer c) |
1764 | ((32) (write-string "space")) |
1765 | ((10) (write-string "newline")) |
1766 | (else (write-char c)))) |
1767 | |
1768 | (define (print obj) |
1769 | (cond ((pair? obj) |
1770 | (let ((head (car/unchecked obj)) |
1771 | (tail (cdr/unchecked obj))) |
1772 | (cond ((and (symbol? head) |
1773 | (pair? tail) |
1774 | (null? (cdr/unchecked tail)) |
1775 | (assq head '((quote "'") |
1776 | (quasiquote "`") |
1777 | (unquote ",") |
1778 | (unquote-splicing ",@")))) |
1779 | => (lambda (r) |
1780 | (write-string (cadr r)) |
1781 | (print (car/unchecked tail)))) |
1782 | (else (write-char #\() |
1783 | (let loop ((head head) (tail tail)) |
1784 | (print head) |
1785 | (cond ((pair? tail) |
1786 | (write-char sp) |
1787 | (loop (car/unchecked tail) |
1788 | (cdr/unchecked tail))) |
1789 | ((null? tail)) |
1790 | (else (write-string " . ") |
1791 | (print tail)))) |
1792 | (write-char #\)))))) |
1793 | ((null? obj) (write-string "()")) |
1794 | ((eq? obj #t) (write-string "#t")) |
1795 | ((eq? obj #f) (write-string "#f")) |
1796 | ((char? obj) (char-printer obj)) |
1797 | ((number? obj) (write-string (number->string obj))) |
1798 | ((string? obj) (string-printer obj)) |
1799 | ((symbol? obj) (write-string obj)) |
1800 | ((vector? obj) (write-string "#(") |
1801 | (let ((len (vector-length obj))) |
1802 | (if (> len 0) |
1803 | (begin |
1804 | (print (vector-ref obj 0)) |
1805 | (let loop ((k 1)) |
1806 | (if (< k len) |
1807 | (begin (write-char sp) |
1808 | (print (vector-ref obj k)) |
1809 | (loop (+ k 1)))))))) |
1810 | (write-char #\))) |
1811 | ((builtin? obj) (write-string "#BUILTIN:") |
1812 | (write-string (builtin-name obj))) |
1813 | ((continuation? obj) (write-string "#CONTINUATION")) |
1814 | ((procedure? obj) (write-string "#PROCEDURE")) |
1815 | ((promise? obj) (write-string "#PROMISE")) |
1816 | ((input-port? obj) (write-string "#INPUT-PORT")) |
1817 | ((output-port? obj) (write-string "#OUTPUT-PORT")) |
1818 | ((eof-object? obj) (write-string "#EOF")) |
1819 | ((assq obj environment-specs) |
1820 | => (lambda (r) |
1821 | (write-string "#ENVSPEC:") (write-string (cadr r)))) |
1822 | (else (error "BUG: unmatched type")))) |
1823 | |
1824 | (define (with-output-port-option thunk args) |
1825 | (if (pair? args) |
1826 | (if (null? (cdr/unchecked args)) |
1827 | (let ((port (car/unchecked args)) |
1828 | (saved (current-output-port))) |
1829 | (if (output-port? port) |
1830 | (dynamic-wind (lambda () (set-output-port! port)) thunk |
1831 | (lambda () (set-output-port! saved))) |
1832 | (not-output-port port))) |
1833 | (too-many-args)) |
1834 | (thunk))) |
1835 | |
1836 | (define (write obj . args) |
1837 | (set! char-printer write-char/quoted) |
1838 | (set! string-printer write-string/quoted) |
1839 | (with-output-port-option (lambda () (print obj)) args)) |
1840 | |
1841 | (define (display obj . args) |
1842 | (set! char-printer write-char) |
1843 | (set! string-printer write-string) |
1844 | (with-output-port-option (lambda () (print obj)) args)) |
1845 | |
1846 | (define (newline . args) |
1847 | (apply/unchecked write-char (cons nl args))) |
1848 | |
1849 | ;;; 6.6.4 System Interface |
1850 | |
1851 | (define (load filename) (call-with-input-file filename exec-from-port)) |
1852 | |
1853 | ;;; Extensions |
1854 | |
1855 | (define (set-error-handler! p) |
1856 | (set! error-handler (require-procedure p)) |
1857 | ;; (re)register hook for internal errors |
1858 | (set-error-continuation! error-cont)) |
1859 | |
1860 | (define (exit . args) |
1861 | (let ((status (opt-args args 0))) |
1862 | (if (and (exact? status) (integer? status)) |
1863 | (exit-cont (modulo status 256)) |
1864 | ;; ^ ensures fixnum, and seems to be what unix does anyway |
1865 | (not-exact-int status)))) |
1866 | |
1867 | ;;; Lispy socket interface based on internal Unixy one. |
1868 | ;; |
1869 | ;; A socket object is a dispatch a-list of methods and constants. This object-oriented design avoids exposing bare file descriptors while allowing for more esoteric methods to be added in the future if needed. Unnecessary mutators are avoided, and stream sockets are not conflated with listeners. |
1870 | ;; |
1871 | ;; Explicitly closing one of the directional ports of a stream socket is interpreted as a promise that no further data will be read/written, including through other aliases of the underlying socket. Thus it is a half-shutdown visible to the peer as well as any external processes sharing the socket (e.g. if a fork extension is implemented). When closing listeners or datagram sockets shared by external processes, the usual Unix reference counting semantics apply. |
1872 | ;; |
1873 | ;; Host and service lookup is intended to be implemented in Scheme, at a higher layer. (That is, open-* won't do implicit lookups when the address looks like a name.) |
1874 | |
1875 | ;;; Internal constructors for general socket types |
1876 | |
1877 | (define (make-socket fd) |
1878 | `((type socket) |
1879 | (address ,(getsockname fd)))) ;; immutable |
1880 | |
1881 | (define (make-stream-socket fd) |
1882 | (receive (i o) (socket-ports fd) |
1883 | `((type stream-socket) |
1884 | (input-port ,i) |
1885 | (output-port ,o) |
1886 | (peer-address ,(getpeername fd)) ;; immutable |
1887 | . ,(make-socket fd)))) |
1888 | |
1889 | (define (make-listener fd) |
1890 | `((type listener) |
1891 | (accept ,(lambda () (make-stream-socket (accept fd)))) |
1892 | (close ,(lambda () (close fd))) |
1893 | . ,(make-socket fd))) |
1894 | |
1895 | (define (make-dgram-socket fd) |
1896 | `((type datagram-socket) |
1897 | (send ,(lambda (address msg) (sendto fd address msg))) |
1898 | (receive ,(lambda () (recvfrom fd))) |
1899 | (close ,(lambda () (close fd))) |
1900 | . ,(make-socket fd))) |
1901 | |
1902 | ;;; Specific constructors |
1903 | |
1904 | (define (open-tcp-connection address . args) |
1905 | (let* ((bind-address (opt-args args #f)) |
1906 | (fd (if bind-address (inet-stream-socket bind-address) |
1907 | (inet-stream-socket)))) |
1908 | (connect-inet fd address) |
1909 | (make-stream-socket fd))) |
1910 | |
1911 | (define (open-tcp-listener backlog . args) |
1912 | (let* ((address (opt-args args #f)) |
1913 | (fd (if address (inet-stream-socket address) |
1914 | (inet-stream-socket)))) |
1915 | (listen fd backlog) |
1916 | (make-listener fd))) |
1917 | |
1918 | (define (open-udp-socket . args) |
1919 | (let* ((address (opt-args args #f)) |
1920 | (fd (if address (inet-dgram-socket address) |
1921 | (inet-dgram-socket)))) |
1922 | (make-dgram-socket fd))) |
1923 | |
1924 | (define (open-unix-connection address . args) |
1925 | (let* ((bind-address (opt-args args #f)) |
1926 | (fd (if bind-address (unix-stream-socket bind-address) |
1927 | (unix-stream-socket)))) |
1928 | (connect-unix fd address) |
1929 | (make-stream-socket fd))) |
1930 | |
1931 | (define (open-unix-listener backlog address) |
1932 | ;; address required as Unix listeners can't bind to an automatic path |
1933 | (let ((fd (unix-stream-socket address))) |
1934 | (listen fd backlog) |
1935 | (make-listener fd))) |
1936 | |
1937 | (define (open-unix-datagram-socket . args) |
1938 | (let* ((address (opt-args args #f)) |
1939 | (fd (if address (unix-dgram-socket address) |
1940 | (unix-dgram-socket)))) |
1941 | (make-dgram-socket fd))) |
1942 | |
1943 | ;;; Higher-level wrappers |
1944 | |
1945 | (define (: object field) (cadr (assq field object))) |
1946 | |
1947 | (define (close-io i o) (close-input-port i) (close-output-port o)) |
1948 | |
1949 | (define (call-with-connection sock proc) |
1950 | (let ((i (: sock 'input-port)) |
1951 | (o (: sock 'output-port))) |
1952 | (saving-values (lambda () (proc i o)) |
1953 | (lambda () (close-io i o))))) |
1954 | |
1955 | (define (sequential-server listener handler) |
1956 | (let ((accept (: listener 'accept))) |
1957 | (let loop () |
1958 | (let ((sock (accept))) |
1959 | (let ((i (: sock 'input-port)) |
1960 | (o (: sock 'output-port))) |
1961 | (let ((r (handler i o (: sock 'peer-address)))) |
1962 | (close-io i o) |
1963 | (if r (loop) ((: listener 'close))))))))) |
1964 | |
1965 | (define (call-with-tcp-connection address proc) |
1966 | ;; parse IP / resolve name here... |
1967 | (call-with-connection (open-tcp-connection address) proc)) |
1968 | |
1969 | (define (call-with-unix-connection address proc) |
1970 | (call-with-connection (open-unix-connection address) proc)) |
1971 | |
1972 | (define (sequential-tcp-server backlog address handler) |
1973 | (sequential-server (open-tcp-listener backlog address) handler)) |
1974 | |
1975 | (define (sequential-unix-server backlog address handler) |
1976 | (sequential-server (open-unix-listener backlog address) handler)) |
1977 | |
1978 | ;;; End of internal definitions; apply deferred initializations (implicit forcing or R6's letrec* semantics could avoid this) |
1979 | |
1980 | (set! flo-bn-radix (force flo-bn-radix)) |
1981 | (set! flo-log-bn-radix (force flo-log-bn-radix)) |
1982 | (set! =* (force =*)) |
1983 | (set! <* (force <*)) |
1984 | (set! >* (force >*)) |
1985 | (set! <=* (force <=*)) |
1986 | (set! >=* (force >=*)) |
1987 | (set! max* (force max*)) |
1988 | (set! min* (force min*)) |
1989 | (set! add2 (force add2)) |
1990 | (set! mul2 (force mul2)) |
1991 | (set! sub/bignum (force sub/bignum)) |
1992 | (set! add* (force add*)) |
1993 | (set! mul* (force mul*)) |
1994 | (set! sub* (force sub*)) |
1995 | (set! div* (force div*)) |
1996 | (set! quotient/fixnum (force quotient/fixnum)) |
1997 | (set! quotient/bignum (force quotient/bignum)) |
1998 | (set! remainder/fixnum (force remainder/fixnum)) |
1999 | (set! remainder/bignum (force remainder/bignum)) |
2000 | (set! gcd* (force gcd*)) |
2001 | (set! atan1 (force atan1)) |
2002 | (set! all-null? (force all-null?)) |
2003 | (set! all-pair? (force all-pair?)) |
2004 | (set! car*unchecked (force car*unchecked)) |
2005 | (set! cdr*unchecked (force cdr*unchecked)) |
2006 | (set! dec-chunk-digits (force dec-chunk-digits)) |
2007 | (set! dec-chunk-radix (force dec-chunk-radix)) |
2008 | (set! hex-chunk-digits (force hex-chunk-digits)) |
2009 | (set! oct-chunk-digits (force oct-chunk-digits)) |
2010 | (set! hex-chunk-bits (force hex-chunk-bits)) |
2011 | (set! oct-chunk-bits (force oct-chunk-bits)) |
2012 | |
2013 | (for-each |
2014 | (lambda (rec) (define-traced define-r5rs (car rec) (cadr rec))) |
2015 | `((eqv? ,eqv?) |
2016 | (equal? ,equal?) |
2017 | (= ,=) |
2018 | (< ,<) |
2019 | (> ,>) |
2020 | (<= ,<=) |
2021 | (>= ,>=) |
2022 | (zero? ,zero?) |
2023 | (positive? ,positive?) |
2024 | (negative? ,negative?) |
2025 | (odd? ,odd?) |
2026 | (even? ,even?) |
2027 | (max ,max) |
2028 | (min ,min) |
2029 | (+ ,+) |
2030 | (* ,*) |
2031 | (- ,-) |
2032 | (/ ,/) |
2033 | (abs ,abs) |
2034 | (quotient ,quotient) |
2035 | (remainder ,remainder) |
2036 | (modulo ,modulo) |
2037 | (gcd ,gcd) |
2038 | (lcm ,lcm) |
2039 | (floor ,floor) |
2040 | (ceiling ,ceiling) |
2041 | (truncate ,truncate) |
2042 | (round ,round) |
2043 | (exp ,(irrational exp/unchecked 0 1)) |
2044 | (log ,(irrational log/unchecked 1 0)) |
2045 | (sin ,(irrational sin/unchecked 0 0)) |
2046 | (cos ,(irrational cos/unchecked 0 1)) |
2047 | (tan ,(irrational tan/unchecked 0 0)) |
2048 | (asin ,(irrational asin/unchecked 0 0)) |
2049 | (acos ,(irrational acos/unchecked 1 0)) |
2050 | (atan ,atan) |
2051 | (sqrt ,(irrational sqrt/unchecked 0 0)) |
2052 | ;; ^ could be refined to handle exact perfect squares, or bignums with greater precision and range |
2053 | (expt ,expt) |
2054 | (exact->inexact ,flonum/generic) |
2055 | (inexact->exact ,inexact->exact) |
2056 | (number->string ,number->string) |
2057 | (string->number ,string->number) |
2058 | (list ,list) |
2059 | (append ,append) |
2060 | (reverse ,reverse) |
2061 | (list-tail ,list-tail) |
2062 | (list-ref ,list-ref) |
2063 | (memq ,memq) |
2064 | (memv ,memv) |
2065 | (member ,member) |
2066 | (assq ,assq) |
2067 | (assv ,assv) |
2068 | (assoc ,assoc) |
2069 | (string ,string) |
2070 | (string->list ,string->list) |
2071 | (vector ,vector) |
2072 | (vector->list ,vector->list) |
2073 | (apply ,apply) |
2074 | (map ,map) |
2075 | (for-each ,for-each) |
2076 | (dynamic-wind ,dynamic-wind) |
2077 | (call-with-input-file ,call-with-input-file) |
2078 | (call-with-output-file ,call-with-output-file) |
2079 | (with-input-from-file ,with-input-from-file) |
2080 | (with-output-to-file ,with-output-to-file) |
2081 | (read ,read) |
2082 | (write ,write) |
2083 | (display ,display) |
2084 | (newline ,newline) |
2085 | (load ,load))) |
2086 | |
2087 | (for-each |
2088 | (lambda (rec) (define-traced define-gscm (car rec) (cadr rec))) |
2089 | `((set-error-handler! ,set-error-handler!) |
2090 | (exit ,exit) |
2091 | (open-tcp-connection ,open-tcp-connection) |
2092 | (open-tcp-listener ,open-tcp-listener) |
2093 | (open-udp-socket ,open-udp-socket) |
2094 | (open-unix-connection ,open-unix-connection) |
2095 | (open-unix-listener ,open-unix-listener) |
2096 | (open-unix-datagram-socket ,open-unix-datagram-socket) |
2097 | (call-with-tcp-connection ,call-with-tcp-connection) |
2098 | (call-with-unix-connection ,call-with-unix-connection) |
2099 | (sequential-tcp-server ,sequential-tcp-server) |
2100 | (sequential-unix-server ,sequential-unix-server))) |
2101 | |
2102 | (cond ((call/cc (lambda (c) (set! error-cont c) #f)) |
2103 | => (lambda (args) |
2104 | (let ((h error-handler) |
2105 | (msg (car args)) |
2106 | (args (cdr args))) |
2107 | (set! error-handler print-error) |
2108 | (h msg args (get-trace-log))) |
2109 | 1)) |
2110 | ((call/cc (lambda (c) (set! exit-cont c) #f))) |
2111 | (else (set-error-handler! print-error) |
2112 | (define-traced |
2113 | define-gscm 'error |
2114 | (lambda (msg . args) |
2115 | (if (string? msg) (error-cont (cons msg args)) |
2116 | (error "not a string:" msg)))) |
2117 | (cond ((member *args* '(() ("--"))) |
2118 | (call/cc (lambda (c) (set! repl-cont c))) |
2119 | (set-error-handler! repl-error) |
2120 | (repl)) |
2121 | ((string=? (car *args*) "-") |
2122 | (exec-from-port (current-input-port))) |
2123 | ((string=? (car *args*) "--") |
2124 | (set! *args* (cdr *args*)) |
2125 | (eval `(set! *args* ',*args*) intr-env) |
2126 | (load (car *args*))) |
2127 | (else (load (car *args*)))) |
2128 | 0)))) |