~ chicken-core (master) /csi.scm
Trap1;;;; csi.scm - Interpreter stub for CHICKEN
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 (usual-integrations)
30 (disable-interrupts)
31 (always-bound ##sys#windows-platform)
32 (foreign-declare #<<EOF
33#include <signal.h>
34
35#if defined(HAVE_DIRECT_H)
36# include <direct.h>
37#else
38# define _getcwd(buf, len) NULL
39#endif
40EOF
41) )
42
43(module chicken.csi
44 (editor-command toplevel-command default-evaluator)
45
46(import scheme
47 chicken.base
48 chicken.condition
49 chicken.fixnum
50 chicken.foreign
51 chicken.format
52 chicken.file
53 chicken.gc
54 chicken.internal
55 chicken.io
56 chicken.keyword
57 chicken.load
58 chicken.pathname
59 chicken.platform
60 chicken.port
61 chicken.pretty-print
62 chicken.process
63 chicken.process-context
64 chicken.repl
65 chicken.sort
66 chicken.string
67 chicken.syntax
68 chicken.time)
69
70(import (rename (only (scheme write) write) (write write/labels)))
71(import (only (scheme base) make-parameter open-input-string open-output-string
72 get-output-string port?))
73
74(include "banner.scm")
75(include "mini-srfi-1.scm")
76
77;;; Parameters:
78
79(define-constant init-file "csirc")
80
81(set! ##sys#repl-print-length-limit 2048)
82(set! ##sys#features (cons #:csi ##sys#features))
83(set! ##sys#notices-enabled #t)
84
85(set! ##sys#repl-print-hook
86 (lambda (o p)
87 (write/labels o p)
88 (newline)))
89
90(define editor-command (make-parameter #f))
91(define selected-frame #f)
92
93(define default-editor
94 (or (get-environment-variable "EDITOR")
95 (get-environment-variable "VISUAL")
96 (if (get-environment-variable "EMACS")
97 "emacsclient"
98 "vi"))) ; shudder
99
100
101;;; Print all sorts of information:
102
103(define (print-usage)
104 (display #<<EOF
105usage: csi [OPTION ...] [FILENAME ...]
106
107 `csi' is the CHICKEN interpreter.
108
109 FILENAME is a Scheme source file name with optional extension. OPTION may be
110 one of the following:
111
112 -h -help display this text and exit
113 -version display version and exit
114 -release print release number and exit
115 -i -case-insensitive enable case-insensitive reading
116 -e -eval EXPRESSION evaluate given expression
117 -p -print EXPRESSION evaluate and print result(s)
118 -P -pretty-print EXPRESSION evaluate and print result(s) prettily
119 -D -feature SYMBOL register feature identifier
120 -no-feature SYMBOL disable built-in feature identifier
121 -q -quiet do not print banner
122
123EOF
124)
125 (display #<#EOF
126 -n -no-init do not load initialization file #{#\`} #{init-file} #{#\'}
127
128EOF
129)
130 (display #<<EOF
131 -b -batch terminate after command-line processing
132 -w -no-warnings disable all warnings
133 -K -keyword-style STYLE enable alternative keyword-syntax
134 (prefix, suffix or none)
135 -no-parentheses-synonyms disables list delimiter synonyms
136 -r7rs-syntax disables the CHICKEN extensions to
137 R7RS syntax
138 -s -script PATHNAME use csi as interpreter for Scheme scripts
139 -ss PATHNAME same as `-s', but invoke `main' procedure
140 -sx PATHNAME same as `-s', but print each expression
141 as it is evaluated
142 -setup-mode prefer the current directory when locating extensions
143 -R -require-extension NAME require extension and import before
144 executing code
145 -I -include-path PATHNAME add PATHNAME to include path
146 -- ignore all following options
147
148EOF
149) ) ;| <--- for emacs font-lock
150
151(define (print-banner)
152 (print +banner+ (chicken-version #t) "\n"))
153
154
155;;; Chop terminating separator from pathname:
156
157(define (dirseparator? c)
158 (or (and ##sys#windows-platform (char=? c #\\))
159 (char=? c #\/)))
160
161(define chop-separator
162 (let ([substring substring] )
163 (lambda (str)
164 (let* ((len (sub1 (string-length str)))
165 (c (string-ref str len)))
166 (if (and (fx> len 0) (dirseparator? c))
167 (substring str 0 len)
168 str) ) ) ) )
169
170
171;;; Find script in PATH (only used for Windows/DOS):
172
173(define lookup-script-file
174 (let* ([buf (make-string 256)]
175 [_getcwd (foreign-lambda nonnull-c-string "_getcwd" scheme-pointer int)] )
176 (define (addext name)
177 (if (file-exists? name)
178 name
179 (let ([n2 (string-append name ".bat")])
180 (and (file-exists? n2) n2) ) ) )
181 (define (string-index proc str1)
182 (let ((len (string-length str1)))
183 (let loop ((i 0))
184 (cond ((fx>= i len) #f)
185 ((proc (string-ref str1 i)) i)
186 (else (loop (fx+ i 1))) ) ) ) )
187 (lambda (name)
188 (let ([path (get-environment-variable "PATH")])
189 (and (> (string-length name) 0)
190 (cond [(dirseparator? (string-ref name 0)) (addext name)]
191 [(string-index dirseparator? name)
192 (let ((p (_getcwd buf 256)))
193 (addext (string-append (chop-separator p) "/" name)) ) ]
194 [(addext name)]
195 [else
196 (let ([name2 (string-append "/" name)])
197 (let loop ((ps (##sys#split-path path)))
198 (and (pair? ps)
199 (let ([name2 (string-append (chop-separator (##sys#slot ps 0)) name2)])
200 (or (addext name2)
201 (loop (##sys#slot ps 1)) ) ) ) ) ) ] ) ) ) ) ) )
202
203
204
205;;; REPL history references:
206
207(define history-list (make-vector 32))
208(define history-count 1)
209
210(define history-add
211 (let ([vector-resize vector-resize])
212 (lambda (vals)
213 (let ([x (if (null? vals) (##sys#void) (##sys#slot vals 0))]
214 [size (##sys#size history-list)] )
215 (when (fx>= history-count size)
216 (set! history-list (vector-resize history-list (fx* 2 size))) )
217 (vector-set! history-list history-count x)
218 (set! history-count (fx+ history-count 1))
219 x) ) ) )
220
221(define (history-clear)
222 (vector-fill! history-list (##sys#void)))
223
224(define history-show
225 (let ((newline newline))
226 (lambda ()
227 (do ((i 1 (fx+ i 1)))
228 ((>= i history-count))
229 (printf "#~a: " i)
230 (##sys#with-print-length-limit
231 80
232 (lambda ()
233 (##sys#print (vector-ref history-list i) #t ##sys#standard-output)))
234 (newline)))))
235
236(define (history-ref index)
237 (let ([i (inexact->exact index)])
238 (if (and (fx> i 0) (fx<= i history-count))
239 (vector-ref history-list i)
240 (##sys#error "history entry index out of range" index) ) ) )
241
242;;; Reader hooks for REPL history:
243
244(define (register-repl-history!)
245 (set! ##sys#user-read-hook
246 (let ((old-hook ##sys#user-read-hook))
247 (lambda (char port)
248 (cond ((or (char=? #\) char) (char-whitespace? char))
249 `',(history-ref (fx- history-count 1)))
250 (else (old-hook char port))))))
251 (set! ##sys#sharp-number-hook
252 (lambda (port n) `',(history-ref n))))
253
254(repl-prompt
255 (let ((sprintf sprintf))
256 (lambda ()
257 (sprintf "#;~A~A> "
258 (let ((m (##sys#current-module)))
259 (if m
260 (sprintf "~a:" (##sys#module-name m))
261 ""))
262 history-count))))
263
264
265;;; Other REPL customizations:
266
267(define (tty-input?)
268 (or (##core#inline "C_i_tty_forcedp")
269 (##sys#tty-port? ##sys#standard-input)))
270
271(set! ##sys#read-prompt-hook
272 (let ([old ##sys#read-prompt-hook])
273 (lambda ()
274 (when (tty-input?) (old)) ) ) )
275
276(define command-table '())
277
278(define (toplevel-command name proc #!optional help)
279 (##sys#check-symbol name 'toplevel-command)
280 (when help (##sys#check-string help 'toplevel-command))
281 (cond ((assq name command-table) =>
282 (lambda (a)
283 (set-cdr! a (list proc help)) ))
284 (else
285 (set! command-table (cons (list name proc help) command-table))))
286 (##sys#void))
287
288(define default-evaluator
289 (let ((eval eval)
290 (load-noisily load-noisily)
291 (read (lambda () (chicken.syntax#read-with-source-info (current-input-port)))) ; OBSOLETE - after bootstrapping we can get rid of this explicit namespacing
292 (read-line read-line)
293 (display display)
294 (string-split string-split)
295 (printf printf)
296 (expand expand)
297 (pretty-print pretty-print)
298 (values values) )
299 (lambda (form)
300 (cond ((eof-object? form) (quit))
301 ((and (pair? form)
302 (eq? 'unquote (##sys#slot form 0)) )
303 (let ((cmd (cadr form)))
304 (cond ((assq cmd command-table) =>
305 (lambda (p)
306 ((cadr p))
307 (##sys#void) ) )
308 (else
309 ;;XXX use `toplevel-command' to define as many as possible of these
310 (case cmd
311 ((x)
312 (let ([x (read)])
313 (pretty-print (strip-syntax (expand x)))
314 (##sys#void) ) )
315 ((p)
316 (let* ([x (read)]
317 [xe (eval x)] )
318 (pretty-print xe)
319 (##sys#void) ) )
320 ((d)
321 (let* ([x (read)]
322 [xe (eval x)] )
323 (describe xe) ) )
324 ((du)
325 (let* ([x (read)]
326 [xe (eval x)] )
327 (dump xe) ) )
328 ((dur)
329 (let* ([x (read)]
330 [n (read)]
331 [xe (eval x)]
332 [xn (eval n)] )
333 (dump xe xn) ) )
334 ((r) (report))
335 ((q) (quit))
336 ((l)
337 (let ((fns (string-split (read-line))))
338 (for-each load fns)
339 (##sys#void) ) )
340 ((ln)
341 (let ((fns (string-split (read-line))))
342 (for-each (cut load-noisily <> printer: (lambda (x) (pretty-print x) (print* "==> "))) fns)
343 (##sys#void) ) )
344 ((t)
345 (let ((x (read)))
346 (receive rs (time (eval x))
347 (history-add rs)
348 (apply values rs) ) ) )
349 ((exn)
350 (when ##sys#last-exception
351 (history-add (list ##sys#last-exception))
352 (describe ##sys#last-exception) ) )
353 ((e)
354 (let ((r (system
355 (string-append
356 (or (editor-command) default-editor)
357 " " (read-line)))))
358 (if (not (zero? r))
359 (printf "editor returned with non-zero exit status ~a" r))))
360 ((ch)
361 (history-clear)
362 (##sys#void))
363 ((h)
364 (history-show)
365 (##sys#void))
366 ((c)
367 (show-frameinfo selected-frame)
368 (##sys#void))
369 ((f)
370 (select-frame (read))
371 (##sys#void))
372 ((g)
373 (copy-from-frame (read)))
374 ((s)
375 (let* ((str (read-line))
376 (r (system str)) )
377 (history-add (list r))
378 r) )
379 ((?)
380 (display
381 "Toplevel commands:
382
383 ,? Show this text
384 ,p EXP Pretty print evaluated expression EXP
385 ,d EXP Describe result of evaluated expression EXP
386 ,du EXP Dump data of expression EXP
387 ,dur EXP N Dump range
388 ,q Quit interpreter
389 ,l FILENAME ... Load one or more files
390 ,ln FILENAME ... Load one or more files and print result of each top-level expression
391 ,r Show system information
392 ,h Show history of expression results
393 ,ch Clear history of expression results
394 ,e FILENAME Run external editor
395 ,s TEXT ... Execute shell-command
396 ,exn Describe last exception
397 ,c Show call-chain of most recent error
398 ,f N Select frame N
399 ,g NAME Get variable NAME from current frame
400 ,t EXP Evaluate form and print elapsed time
401 ,x EXP Pretty print expanded expression EXP\n")
402 (for-each
403 (lambda (a)
404 (let ((help (caddr a)))
405 (if help
406 (print #\space help)
407 (print " ," (car a)) ) ) )
408 command-table)
409 (##sys#void) )
410 (else
411 (printf "undefined toplevel command ~s - enter `,?' for help~%" form)
412 (##sys#void) ) ) ) ) ) )
413 (else
414 (receive rs (eval form)
415 (history-add rs)
416 (apply values rs) ) ) ) ) ) )
417
418
419;;; Builtin toplevel commands:
420
421(toplevel-command
422 'm
423 (let ((printf printf))
424 (lambda ()
425 (let ((name (read)))
426 (cond ((not name)
427 (##sys#switch-module #f)
428 (printf "; resetting current module to toplevel~%"))
429 ((##sys#find-module (##sys#resolve-module-name name #f) #f) =>
430 (lambda (m)
431 (##sys#switch-module m)
432 (printf "; switching current module to `~a'~%" name)))
433 (else
434 (printf "undefined module `~a'~%" name))))))
435 ",m MODULE switch to module with name `MODULE'")
436
437
438;;; Parse options from string:
439
440(define (parse-option-string str)
441 (let ([ins (open-input-string str)])
442 (map (lambda (o)
443 (if (string? o)
444 o
445 (let ([os (open-output-string)])
446 (write o os)
447 (get-output-string os) ) ) )
448 (handle-exceptions ex (##sys#error "invalid option syntax" str)
449 (do ([x (read ins) (read ins)]
450 [xs '() (cons x xs)] )
451 ((eof-object? x) (reverse xs)) ) ) ) ) )
452
453
454;;; Print status information:
455
456(define report
457 (let ((printf printf)
458 (sort sort)
459 (with-output-to-port with-output-to-port)
460 (current-output-port current-output-port)
461 (argv argv)
462 (prefix (foreign-value "C_INSTALL_PREFIX" c-string)))
463 (lambda port
464 (with-output-to-port (if (pair? port) (car port) (current-output-port))
465 (lambda ()
466 (gc)
467 (let ((sinfo (##sys#symbol-table-info))
468 (minfo (memory-statistics))
469 (interrupts (foreign-value "C_interrupts_enabled" bool))
470 (fixed-heap (foreign-value "C_heap_size_is_fixed" bool))
471 (downward-stack (foreign-value "C_STACK_GROWS_DOWNWARD" bool)))
472 (define (shorten n) (/ (truncate (* n 100)) 100))
473 (printf "Features:~%~%")
474 (let ((fs (sort (map keyword->string ##sys#features) string<?))
475 (c 0))
476 (for-each
477 (lambda (f)
478 (printf " ~a" f)
479 (let* ((len (string-length f))
480 (pad (- 16 len)))
481 (set! c (add1 c))
482 (when (<= pad 0)
483 (set! c (add1 c))
484 (set! pad (+ pad 18)))
485 (cond ((>= c 3)
486 (display "\n")
487 (set! c 0))
488 (else
489 (display (make-string pad #\space))))))
490 fs))
491 (printf "~%~%~
492 Machine type: \t~A (~A-bit)~%~
493 Software type: \t~A~%~
494 Software version:\t~A~%~
495 Build platform: \t~A~%~
496 Installation prefix:\t~A~%~
497 Extension installation location:\t~A~%~
498 Extension path: \t~A~%~
499 Include path: \t~A~%~
500 Keyword style: \t~A~%~
501 Symbol-table load:\t~S~% ~
502 Avg bucket length:\t~S~% ~
503 Total symbol count:\t~S~%~
504 Memory:\theap size is ~S bytes~A with ~S bytes currently in use~%~
505 nursery size is ~S bytes, stack grows ~A~%~
506 Command line: \t~S~%"
507 (machine-type)
508 (foreign-value "C_WORD_SIZE" int)
509 (software-type)
510 (software-version)
511 (build-platform)
512 prefix
513 (installation-repository)
514 (repository-path)
515 ##sys#include-pathnames
516 (keyword->string (keyword-style))
517 (shorten (vector-ref sinfo 0))
518 (shorten (vector-ref sinfo 1))
519 (vector-ref sinfo 2)
520 (vector-ref minfo 0)
521 (if fixed-heap " (fixed)" "")
522 (vector-ref minfo 1)
523 (vector-ref minfo 2)
524 (if downward-stack "downward" "upward")
525 (argv))
526 (##sys#write-char-0 #\newline ##sys#standard-output)
527 (when interrupts (display "interrupts are enabled\n"))
528 (##core#undefined) ) ) ) ) ) )
529
530
531;;; Describe & dump:
532
533(define bytevector-data
534 '((u8vector "vector of unsigned bytes" u8vector-length u8vector-ref)
535 (s8vector "vector of signed bytes" s8vector-length s8vector-ref)
536 (u16vector "vector of unsigned 16-bit words" u16vector-length u16vector-ref)
537 (s16vector "vector of signed 16-bit words" s16vector-length s16vector-ref)
538 (u32vector "vector of unsigned 32-bit words" u32vector-length u32vector-ref)
539 (s32vector "vector of signed 32-bit words" s32vector-length s32vector-ref)
540 (u64vector "vector of unsigned 64-bit words" u64vector-length u64vector-ref)
541 (s64vector "vector of signed 64-bit words" s64vector-length s64vector-ref)
542 (f32vector "vector of 32-bit floats" f32vector-length f32vector-ref)
543 (f64vector "vector of 64-bit floats" f64vector-length f64vector-ref) ) )
544
545(define (circular-list? x)
546 (let lp ((x x) (lag x))
547 (and (pair? x)
548 (let ((x (cdr x)))
549 (and (pair? x)
550 (let ((x (cdr x))
551 (lag (cdr lag)))
552 (or (eq? x lag) (lp x lag))))))))
553
554(define (improper-pairs? x)
555 (let lp ((x x))
556 (if (not (pair? x)) #f
557 (or (eq? x (car x))
558 (lp (cdr x))))))
559
560(define-constant max-describe-lines 40)
561
562(define describe
563 (let ([sprintf sprintf]
564 [printf printf]
565 [fprintf fprintf]
566 [length length]
567 [list-ref list-ref]
568 [string-ref string-ref])
569 (lambda (x #!optional (out ##sys#standard-output))
570 (define (descseq name plen pref start)
571 (let ((len (fx- (plen x) start)))
572 (when name (fprintf out "~A of length ~S~%" name len))
573 (let loop1 ((i 0))
574 (cond ((fx>= i len))
575 ((fx>= i max-describe-lines)
576 (fprintf out "~% (~A elements not displayed)~%" (fx- len i)) )
577 (else
578 (let ((v (pref x (fx+ start i))))
579 (let loop2 ((n 1) (j (fx+ i (fx+ start 1))))
580 (cond ((fx>= j len)
581 (##sys#with-print-length-limit
582 1000
583 (lambda ()
584 (fprintf out " ~S: ~S" i v)))
585 (if (fx> n 1)
586 (fprintf out "\t(followed by ~A identical instance~a)~% ...~%"
587 (fx- n 1)
588 (if (eq? n 2) "" "s"))
589 (newline out) )
590 (loop1 (fx+ i n)) )
591 ((eq? v (pref x j)) (loop2 (fx+ n 1) (fx+ j 1)))
592 (else (loop2 n len)) ) ) ) ) ) ) ) )
593 (when (##sys#permanent? x)
594 (fprintf out "statically allocated (0x~X) " (##sys#block-address x)) )
595 (cond ((char? x)
596 (let ([code (char->integer x)])
597 (fprintf out "character ~S, code: ~S, #x~X, #o~O~%" x code code code) ) )
598 ((eq? x #t) (fprintf out "boolean true~%"))
599 ((eq? x #f) (fprintf out "boolean false~%"))
600 ((null? x) (fprintf out "empty list~%"))
601 ((bwp-object? x)
602 (fprintf out "broken weak pointer~%"))
603 ((eof-object? x) (fprintf out "end-of-file object~%"))
604 ((eq? (##sys#void) x) (fprintf out "unspecified object~%"))
605 ((fixnum? x)
606 (fprintf out "exact immediate integer ~S~% #x~X~% #o~O~% #b~B"
607 x x x x)
608 (let ([code (integer->char x)])
609 (when (fx< x #x10000) (fprintf out ", character ~S" code)) )
610 (##sys#write-char-0 #\newline ##sys#standard-output) )
611 ((bignum? x)
612 (fprintf out "exact large integer ~S~% #x~X~% #o~O~% #b~B~%"
613 x x x x) )
614 ((##core#inline "C_unboundvaluep" x)
615 (fprintf out "unbound value~%"))
616 ((flonum? x) (fprintf out "inexact rational number ~S~%" x))
617 ((ratnum? x) (fprintf out "exact ratio ~S~%" x))
618 ((cplxnum? x) (fprintf out "~A complex number ~S~%"
619 (if (exact? x) "exact" "inexact") x))
620 ((number? x) (fprintf out "number ~S~%" x))
621 ((string? x) (descseq "string" string-length string-ref 0))
622 ((vector? x) (descseq "vector" ##sys#size ##sys#slot 0))
623 ((keyword? x)
624 (fprintf out "keyword symbol with name ~s~%"
625 (##sys#symbol->string/shared x)))
626 ((symbol? x)
627 (unless (##sys#symbol-has-toplevel-binding? x)
628 (display "unbound " out))
629 (fprintf out "~asymbol with name ~S~%"
630 (if (##sys#interned-symbol? x) "" "uninterned ")
631 (##sys#symbol->string/shared x))
632 (let ((plist (##sys#slot x 2)))
633 (unless (null? plist)
634 (display " \nproperties:\n\n" out)
635 (do ((plist plist (cddr plist)))
636 ((null? plist))
637 (fprintf out " ~s\t" (car plist))
638 (##sys#with-print-length-limit
639 1000
640 (lambda ()
641 (write (cadr plist) out) ) )
642 (newline out) ) ) ) )
643 ((or (circular-list? x) (improper-pairs? x))
644 (fprintf out "circular structure: ")
645 (let loop-print ((x x)
646 (cdr-refs (list x)))
647 (cond ((or (atom? x)
648 (null? x)) (printf "eol~%"))
649 ((memq (car x) cdr-refs)
650 (fprintf out "(circle)~%" ))
651 ((not (memq (car x) cdr-refs))
652 (fprintf out "~S -> " (car x))
653 (loop-print (cdr x) (cons (car x) cdr-refs) )))))
654 ((list? x) (descseq "list" length list-ref 0))
655 ((pair? x) (fprintf out "pair with car ~S~%and cdr ~S~%" (car x) (cdr x)))
656 ((procedure? x)
657 (let ([len (##sys#size x)])
658 (descseq
659 (sprintf "procedure with code pointer 0x~X" (##sys#peek-unsigned-integer x 0))
660 ##sys#size ##sys#slot 1) ) )
661 ((port? x)
662 (fprintf out
663 "~A port of type ~A with name ~S and ~A encoding~%"
664 (if (##sys#slot x 1) "input" "output")
665 (##sys#slot x 7)
666 (##sys#slot x 3)
667 (##sys#slot x 15) ) )
668 ((not (##core#inline "C_blockp" x))
669 ;; catch immediates here, as ##sys#locative? crashes on non-block
670 (fprintf out "unknown immediate object~%"))
671 ((##sys#locative? x)
672 (fprintf out "locative~% pointer ~X~% index ~A~% type ~A~%"
673 (##sys#peek-unsigned-integer x 0)
674 (##sys#slot x 1)
675 (case (##sys#slot x 2)
676 ((0) "slot")
677 ((1) "char")
678 ((2) "u8vector")
679 ((3) "s8vector")
680 ((4) "u16vector")
681 ((5) "s16vector")
682 ((6) "u32vector")
683 ((7) "s32vector")
684 ((8) "u64vector")
685 ((9) "s64vector")
686 ((10) "f32vector")
687 ((11) "f64vector") ) ) )
688 ((##sys#pointer? x) (fprintf out "machine pointer ~X~%" (##sys#peek-unsigned-integer x 0)))
689 ((##sys#bytevector? x)
690 (let ([len (##sys#size x)])
691 (fprintf out "bytevector of size ~S:~%" len)
692 (hexdump x len ##sys#byte out) ) )
693 ((##core#inline "C_lambdainfop" x)
694 (fprintf out "lambda information: ~s~%" (##sys#lambda-info->string x)) )
695 ((##sys#structure? x 'hash-table)
696 (let ((n (##sys#slot x 2)))
697 (fprintf out "hash-table with ~S element~a~% comparison procedure: ~A~%"
698 n (if (fx= n 1) "" "s") (##sys#slot x 3)) )
699 (fprintf out " hash function: ~a~%" (##sys#slot x 4))
700 ;; this copies code out of srfi-69.scm, but we don't want to depend on it
701 (let* ((vec (##sys#slot x 1))
702 (len (##sys#size vec)) )
703 (do ((i 0 (fx+ i 1)) )
704 ((fx>= i len))
705 (for-each
706 (lambda (bucket)
707 (fprintf out " ~S\t-> ~S~%"
708 (##sys#slot bucket 0) (##sys#slot bucket 1)) )
709 (##sys#slot vec i)) ) ) )
710 ((##sys#structure? x 'condition)
711 (fprintf out "condition: ~s~%" (##sys#slot x 1))
712 (for-each
713 (lambda (k)
714 (fprintf out " ~s~%" k)
715 (let loop ((props (##sys#slot x 2)))
716 (unless (null? props)
717 (when (eq? k (caar props))
718 (##sys#with-print-length-limit
719 100
720 (lambda ()
721 (fprintf out "\t~s: ~s" (cdar props) (cadr props)) ))
722 (newline out))
723 (loop (cddr props)) ) ) )
724 (##sys#slot x 1) ) )
725 ((##sys#generic-structure? x)
726 (let ((st (##sys#slot x 0)))
727 (cond ((assq st bytevector-data) =>
728 (lambda (data)
729 (apply descseq (append (map eval (cdr data)) (list 0)))) )
730 (else
731 (fprintf out "structure of type `~S':~%" (##sys#slot x 0))
732 (descseq #f ##sys#size ##sys#slot 1) ) ) ) )
733 (else (fprintf out "unknown object~%")) )
734 (##sys#void) ) ) )
735
736
737;;; Display hexdump:
738
739(define dump
740 (lambda (x . len-out)
741 (let-optionals len-out
742 ([len #f]
743 [out ##sys#standard-output] )
744 (define (bestlen n) (if len (min len n) n))
745 (cond [(##sys#immediate? x) (##sys#error 'dump "cannot dump immediate object" x)]
746 [(##sys#bytevector? x) (hexdump x (bestlen (##sys#size x)) ##sys#byte out)]
747 [(string? x)
748 (let ((bv (##sys#slot x 0)))
749 (hexdump bv (bestlen (fx- (##sys#size bv) 1)) ##sys#byte out))]
750 [(and (not (##sys#immediate? x)) (##sys#pointer? x))
751 (hexdump x 32 ##sys#peek-byte out) ]
752 [(and (##sys#generic-structure? x) (assq (##sys#slot x 0) bytevector-data))
753 (let ([bv (##sys#slot x 1)])
754 (hexdump bv (bestlen (##sys#size bv)) ##sys#byte out) ) ]
755 [else (##sys#error 'dump "cannot dump object" x)] ) ) ) )
756
757(define hexdump
758 (let ([display display]
759 [string-append string-append]
760 [make-string make-string]
761 [write-char write-char] )
762 (lambda (bv len ref out)
763
764 (define (justify n m base lead)
765 (let* ([s (number->string n base)]
766 [len (string-length s)] )
767 (if (fx< len m)
768 (string-append (make-string (fx- m len) lead) s)
769 s) ) )
770
771 (do ([a 0 (fx+ a 16)])
772 ((fx>= a len))
773 (display (justify a 4 10 #\space) out)
774 (write-char #\: out)
775 (do ([j 0 (fx+ j 1)]
776 [a a (fx+ a 1)] )
777 ((or (fx>= j 16) (fx>= a len))
778 (when (fx>= a len)
779 (let ((o (fxmod len 16)))
780 (unless (fx= o 0)
781 (do ((k (fx- 16 o) (fx- k 1)))
782 ((fx= k 0))
783 (display " " out) ) ) ) ) )
784 (write-char #\space out)
785 (display (justify (ref bv a) 2 16 #\0) out) )
786 (write-char #\space out)
787 (do ([j 0 (fx+ j 1)]
788 [a a (fx+ a 1)] )
789 ((or (fx>= j 16) (fx>= a len)))
790 (let ([c (ref bv a)])
791 (if (and (fx>= c 32) (fx< c 128))
792 (write-char (integer->char c) out)
793 (write-char #\. out) ) ) )
794 (write-char #\newline out) ) ) ) )
795
796
797;;; Frame-info operations:
798
799(define show-frameinfo
800 (let ((newline newline)
801 (display display))
802 (lambda (fn)
803 (define (prin1 x)
804 (##sys#with-print-length-limit
805 100
806 (lambda ()
807 (##sys#print x #t ##sys#standard-output))))
808 (let* ((ct (or ##sys#repl-recent-call-chain '()))
809 (len (length ct)))
810 (set! selected-frame
811 (or (and (memq fn ct) fn)
812 (and (fx> len 0)
813 (list-ref ct (fx- len 1)))))
814 (do ((ct ct (cdr ct))
815 (i (fx- len 1) (fx- i 1)))
816 ((null? ct))
817 (let* ((info (car ct))
818 (here (eq? selected-frame info))
819 (form (##sys#slot info 1)) ; cooked1 (expr/form)
820 (data (##sys#slot info 2)) ; cooked2 (cntr/frameinfo)
821 (finfo (##sys#structure? data 'frameinfo))
822 (cntr (if finfo (##sys#slot data 1) data))) ; cntr
823 (printf "~a~a:~a\t~a\t "
824 (if here #\* #\space)
825 i
826 (if (and finfo (pair? (##sys#slot data 2))) "[]" " ") ; e
827 (##sys#slot info 0)) ; raw
828 (when cntr (printf "[~a] " cntr))
829 (when form (prin1 form))
830 (newline)
831 (when (and here finfo)
832 (for-each
833 (lambda (e v)
834 (unless (null? e)
835 (display " ---\n")
836 (do ((i 0 (fx+ i 1))
837 (be e (cdr be)))
838 ((null? be))
839 (printf " ~s:\t " (car be))
840 (prin1 (##sys#slot v i))
841 (newline))))
842 (##sys#slot data 2) ; e
843 (##sys#slot data 3))))))))) ; v
844
845(define select-frame
846 (let ((display display))
847 (lambda (n)
848 (cond ((or (not (number? n))
849 (not ##sys#repl-recent-call-chain)
850 (fx< n 0)
851 (fx>= n (length ##sys#repl-recent-call-chain)))
852 (display "no such frame\n"))
853 (else
854 (set! selected-frame
855 (list-ref
856 ##sys#repl-recent-call-chain
857 (fx- (length ##sys#repl-recent-call-chain) (fx+ n 1))))
858 (show-frameinfo selected-frame))))))
859
860(define copy-from-frame
861 (let ((display display)
862 (newline newline)
863 (call/cc call-with-current-continuation))
864 (lambda (name)
865 (let* ((ct (or ##sys#repl-recent-call-chain '()))
866 (len (length ct))
867 (name
868 (cond ((symbol? name) (##sys#slot name 1)) ; name
869 ((string? name) name)
870 (else
871 (display "string or symbol required for `,g'\n")
872 #f))))
873 (define (compare sym)
874 (let ((str (##sys#slot sym 1))) ; name
875 (string=?
876 name
877 (substring str 0 (min (string-length name) (string-length str))))))
878 (if name
879 (call/cc
880 (lambda (return)
881 (define (fail msg)
882 (display msg)
883 (newline)
884 (return (##sys#void)))
885 (do ((ct ct (cdr ct)))
886 ((null? ct) (fail "no environment in frame"))
887 ;;XXX this should be refactored as it duplicates the code above
888 (let* ((info (car ct))
889 (here (eq? selected-frame info))
890 (data (##sys#slot info 2)) ; cooked2 (cntr/frameinfo)
891 (finfo (##sys#structure? data 'frameinfo)))
892 (when (and here finfo)
893 (for-each
894 (lambda (e v)
895 (do ((i 0 (fx+ i 1))
896 (be e (cdr be)))
897 ((null? be))
898 (when (compare (car be))
899 (display "; getting ")
900 (display (car be))
901 (newline)
902 (history-add (list (##sys#slot v i)))
903 (return (##sys#slot v i)))))
904 (##sys#slot data 2) ; e
905 (##sys#slot data 3)) ; v
906 (fail (##sys#string-append "no such variable: " name)))))))
907 (##sys#void))))))
908
909
910;;; Handle some signals:
911
912(define-foreign-variable _sigint int "SIGINT")
913
914(define-syntax defhandler
915 (syntax-rules ()
916 ((_ sig handler)
917 (begin
918 (##core#inline "C_establish_signal_handler" sig sig)
919 (##sys#setslot ##sys#signal-vector sig handler)))))
920
921(defhandler _sigint (lambda (n) (##sys#user-interrupt-hook)))
922
923
924;;; Start interpreting:
925
926(define (member* keys set)
927 (let loop ((set set))
928 (and (pair? set)
929 (let find ((ks keys))
930 (cond ((null? ks) (loop (cdr set)))
931 ((equal? (car ks) (car set)) set)
932 (else (find (cdr ks))) ) ) ) ) )
933
934(define-constant short-options
935 '(#\k #\s #\h #\D #\e #\i #\R #\b #\n #\q #\w #\- #\I #\p #\P #\K) )
936
937(define-constant long-options
938 '("-ss" "-sx" "-script" "-version" "-help" "--help" "-feature" "-no-feature" "-eval"
939 "-case-insensitive" "-keyword-style" "-no-parentheses-synonyms" "-no-symbol-escape"
940 "-r7rs-syntax" "-setup-mode"
941 "-require-extension" "-batch" "-quiet" "-no-warnings" "-no-init"
942 "-include-path" "-release" "-print" "-pretty-print" "--") )
943
944(define (canonicalize-args args)
945 (let loop ((args args))
946 (if (null? args)
947 '()
948 (let ((x (car args)))
949 (cond ((member x '("-s" "-ss" "-script" "-sx" "--")) args)
950 ((and (fx= (string-length x) 2)
951 (char=? #\- (string-ref x 0)))
952 (if (memq (string-ref x 1) short-options)
953 (cons x (loop (cdr args)))
954 (##sys#error "invalid option" x)))
955 ((and (fx> (string-length x) 2)
956 (char=? #\- (string-ref x 0))
957 (not (member x long-options)) )
958 (if (char=? #\: (string-ref x 1))
959 (loop (cdr args))
960 (let ((cs (string->list (substring x 1))))
961 (if (findall cs short-options)
962 (append (map (cut string #\- <>) cs) (loop (cdr args)))
963 (##sys#error "invalid option" x) ) ) ) )
964 (else (cons x (loop (cdr args)))))))))
965
966(define (findall chars clist)
967 (let loop ((chars chars))
968 (or (null? chars)
969 (and (memq (car chars) clist)
970 (loop (cdr chars))))))
971
972(define-constant simple-options
973 '("--" "-b" "-batch" "-q" "-quiet" "-n" "-no-init" "-w" "-no-warnings"
974 "-i" "-case-insensitive"
975 "-no-parentheses-synonyms" "-r7rs-syntax" "-setup-mode"
976 ; Not "simple" but processed early
977 "-ss" "-sx" "-s" "-script") )
978
979(define-constant complex-options
980 '("-D" "-feature" "-I" "-include-path" "-K" "-keyword-style" "-no-feature") )
981
982(define (string-trim str)
983 (let loop ((front 0)
984 (back (string-length str)))
985 (cond ((= front back) "")
986 ((char-whitespace? (string-ref str front))
987 (loop (add1 front) back))
988 ((char-whitespace? (string-ref str (sub1 back)))
989 (loop front (sub1 back)))
990 (else (substring str front back)))))
991
992(define (string->extension-name str)
993 (let ((str (string-trim str)))
994 (if (and (positive? (string-length str))
995 (char=? #\( (string-ref str 0)))
996 (handle-exceptions ex
997 (##sys#error "invalid import specification" str)
998 (with-input-from-string str read))
999 (string->symbol str))))
1000
1001(define (run)
1002 (let* ([extraopts (parse-option-string (or (get-environment-variable "CSI_OPTIONS") ""))]
1003 [args (canonicalize-args (command-line-arguments))]
1004 ; Check for these before 'args' is updated by any 'extraopts'
1005 [kwstyle (member* '("-K" "-keyword-style") args)]
1006 [script (member* '("-ss" "-sx" "-s" "-script") args)])
1007 (cond [script
1008 (when (or (not (pair? (cdr script)))
1009 (zero? (string-length (cadr script)))
1010 (char=? #\- (string-ref (cadr script) 0)) )
1011 (##sys#error "missing or invalid script argument"))
1012 (program-name (cadr script))
1013 (command-line-arguments (cddr script))
1014 ;; 2012-10-04 (felix) left 'script activated to avoid breaking too much code
1015 (register-feature! 'chicken-script)
1016 (set-cdr! (cdr script) '())
1017 (when ##sys#windows-platform
1018 (and-let* ((sname (lookup-script-file (cadr script))))
1019 (set-car! (cdr script) sname) ) ) ]
1020 [else
1021 (set! args (append (canonicalize-args extraopts) args))
1022 (and-let* ([p (member "--" args)])
1023 (set-cdr! p '()) ) ] )
1024 (let* ([eval? (member* '("-e" "-p" "-P" "-eval" "-print" "-pretty-print") args)]
1025 [batch (or script (member* '("-b" "-batch") args) eval?)]
1026 [quietflag (member* '("-q" "-quiet") args)]
1027 [quiet (or script quietflag eval?)])
1028 (define (collect-options opt)
1029 (let loop ([opts args])
1030 (cond [(member opt opts)
1031 => (lambda (p)
1032 (if (null? (cdr p))
1033 (##sys#error "missing argument to command-line option" opt)
1034 (cons (cadr p) (loop (cddr p)))) ) ]
1035 [else '()] ) ) )
1036 (define (loadinit)
1037 (let* ((sys-dir (system-config-directory))
1038 (cfg-fn (and sys-dir (make-pathname (list sys-dir "chicken")
1039 init-file)))
1040 (home (get-environment-variable "HOME"))
1041 (home-fn (and home (not (string=? home ""))
1042 (make-pathname home (string-append "." init-file)))))
1043 (cond ((and cfg-fn (file-exists? cfg-fn))
1044 (load cfg-fn))
1045 ((and home-fn (file-exists? home-fn))
1046 (load home-fn) ) ) ) )
1047 (define (evalstring str #!optional (rec (lambda _ (void))))
1048 (let ((in (open-input-string str))
1049 (read-with-source-info chicken.syntax#read-with-source-info)) ; OBSOLETE - after bootstrapping we can get rid of this explicit namespacing
1050 (do ([x (read-with-source-info in) (read-with-source-info in)])
1051 ((eof-object? x))
1052 (rec (receive (eval x))) ) ) )
1053 (when (member* '("-h" "-help" "--help") args)
1054 (print-usage)
1055 (exit 0) )
1056 (when (member "-version" args)
1057 (print-banner)
1058 (exit 0) )
1059 (when (member "-setup-mode" args)
1060 (set! ##sys#setup-mode #t))
1061 (when (member "-release" args)
1062 (print (chicken-version))
1063 (exit 0) )
1064 (when (member* '("-w" "-no-warnings") args)
1065 (unless quiet (display "Warnings are disabled\n"))
1066 (set! ##sys#warnings-enabled #f) )
1067 (when (member* '("-i" "-case-insensitive") args)
1068 (unless quiet (display "Identifiers and symbols are case insensitive\n"))
1069 (register-feature! 'case-insensitive)
1070 (case-sensitive #f) )
1071 (for-each register-feature! (collect-options "-feature"))
1072 (for-each register-feature! (collect-options "-D"))
1073 (for-each unregister-feature! (collect-options "-no-feature"))
1074 (set! ##sys#include-pathnames
1075 (delete-duplicates
1076 (append (map chop-separator (collect-options "-include-path"))
1077 (map chop-separator (collect-options "-I"))
1078 ##sys#include-pathnames)
1079 string=?) )
1080 (when kwstyle
1081 (cond [(not (pair? (cdr kwstyle)))
1082 (##sys#error "missing argument to `-keyword-style' option") ]
1083 [(string=? "prefix" (cadr kwstyle))
1084 (keyword-style #:prefix) ]
1085 [(string=? "none" (cadr kwstyle))
1086 (keyword-style #:none) ]
1087 [(string=? "suffix" (cadr kwstyle))
1088 (keyword-style #:suffix) ] ) )
1089 (when (member* '("-no-parentheses-synonyms") args)
1090 (unless quiet (display "Disabled support for parentheses synonyms\n"))
1091 (parentheses-synonyms #f) )
1092 (when (member* '("-r7rs-syntax") args)
1093 (unless quiet (display "Disabled the CHICKEN extensions to R7RS syntax\n"))
1094 (case-sensitive #f)
1095 (keyword-style #:none)
1096 (parentheses-synonyms #f) )
1097 ;; Load the the default modules into the evaluation environment.
1098 ;; This is done before setting load-verbose => #t to avoid
1099 ;; spurious import messages.
1100 (eval `(import-for-syntax ,@default-syntax-imports))
1101 (eval `(import ,@default-imports))
1102 (unless quiet
1103 (load-verbose #t)
1104 (print-banner)
1105 (print "Type ,? for help."))
1106 (unless (or (member* '("-n" "-no-init") args) script eval?)
1107 (loadinit))
1108 (when batch
1109 (set! ##sys#notices-enabled #f))
1110 (do ([args args (cdr args)])
1111 ((null? args)
1112 (register-repl-history!)
1113 (unless batch
1114 (repl default-evaluator)
1115 (##sys#write-char-0 #\newline ##sys#standard-output) ) )
1116 (let* ((arg (car args)))
1117 (cond ((member arg simple-options))
1118 ((member arg complex-options)
1119 (set! args (cdr args)) )
1120 ((or (string=? "-R" arg) (string=? "-require-extension" arg))
1121 (eval `(import ,(string->extension-name (cadr args))))
1122 (set! args (cdr args)) )
1123 ((or (string=? "-e" arg) (string=? "-eval" arg))
1124 (evalstring (cadr args))
1125 (set! args (cdr args)) )
1126 ((or (string=? "-p" arg) (string=? "-print" arg))
1127 (evalstring (cadr args) (cut for-each print <...>))
1128 (set! args (cdr args)) )
1129 ((or (string=? "-P" arg) (string=? "-pretty-print" arg))
1130 (evalstring (cadr args) (cut for-each pretty-print <...>) )
1131 (set! args (cdr args)) )
1132 (else
1133 (let ((scr (and script (car script))))
1134 (load
1135 arg
1136 (and (equal? "-sx" scr)
1137 (lambda (x)
1138 (let* ((str (with-output-to-string (cut pretty-print x)))
1139 (len (string-length str)))
1140 (flush-output ##sys#standard-output)
1141 (display "\n; " ##sys#standard-error)
1142 (do ((i 0 (fx+ i 1)))
1143 ((fx>= i len))
1144 (let ((c (string-ref str i)))
1145 (write-char c ##sys#standard-error)
1146 (when (char=? #\newline c)
1147 (display "; " ##sys#standard-error))))
1148 (newline ##sys#standard-error)
1149 (eval x)))))
1150 (when (equal? "-ss" scr)
1151 (receive rs ((eval 'main) (command-line-arguments))
1152 (let ((r (optional rs)))
1153 (exit (if (fixnum? r) r 0)))))))))))))
1154
1155(run))