1 ;;;============================================================================
3 ;;; File: "_source.scm"
5 ;;; Copyright (c) 1994-2011 by Marc Feeley, All Rights Reserved.
9 (include-adt "_envadt.scm")
10 (include-adt "_gvmadt.scm")
11 (include-adt "_ptreeadt.scm")
12 (include "_sourceadt.scm")
14 '(##include "_hostadt.scm");*******************brad
16 ;;;----------------------------------------------------------------------------
18 ;; Source code manipulation module:
19 ;; -------------------------------
21 ;; This module contains procedures to manipulate source code
22 ;; representations read in from Scheme source files.
24 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
26 ;; A readenv structure maintains the "read environment" throughout the
27 ;; reading of a Scheme datum. It includes the port from which to read,
28 ;; the readtable, the wrap and unwrap procedures, and the position
29 ;; where the currently being read datum started.
31 (define (**make-readenv port readtable error-proc wrapper unwrapper)
32 (vector port readtable error-proc wrapper unwrapper 0 0 0 0))
34 (define (**readenv-port re) (vector-ref re 0))
35 (define (**readenv-readtable re) (vector-ref re 1))
36 (define (**readenv-error-proc re) (vector-ref re 2))
37 (define (**readenv-wrap re x) ((vector-ref re 3) re x))
38 (define (**readenv-unwrap re x) ((vector-ref re 4) re x))
39 (define (**readenv-filepos re) (vector-ref re 5))
40 (define (**readenv-filepos-set! re pos) (vector-set! re 5 pos))
41 (define (**readenv-line-count re) (vector-ref re 6))
42 (define (**readenv-line-count-set! re x) (vector-set! re 6 x))
43 (define (**readenv-char-count re) (vector-ref re 7))
44 (define (**readenv-char-count-set! re x) (vector-set! re 7 x))
45 (define (**readenv-line-start re) (vector-ref re 8))
46 (define (**readenv-line-start-set! re x) (vector-set! re 8 x))
48 (define (**readenv-current-filepos re)
50 (**readenv-line-count re))
52 (**readenv-char-count re))
55 (**readenv-line-start re))))
56 (**make-filepos line char char-count)))
58 (define (**readenv-previous-filepos re offset)
60 (**readenv-line-count re))
62 (- (**readenv-char-count re) offset))
65 (**readenv-line-start re))))
66 (**make-filepos line char char-count)))
68 (define (**peek-next-char-or-eof re) ; possibly returns end-of-file
69 (peek-char (**readenv-port re)))
71 (define (**read-next-char-or-eof re) ; possibly returns end-of-file
72 (let ((c (read-char (**readenv-port re))))
74 (let ((char-count (+ (**readenv-char-count re) 1)))
75 (**readenv-char-count-set! re char-count)
76 (if (char=? c #\newline)
78 (**readenv-line-start-set! re char-count)
79 (**readenv-line-count-set! re
80 (+ (**readenv-line-count re) 1))))))
83 (define (**make-filepos line char char-count)
84 (if (and (< line (max-lines))
85 (not (< (max-fixnum32-div-max-lines) char)))
86 (+ line (* char (max-lines)))
89 (define (**filepos-line filepos)
92 (modulo filepos (max-lines))))
94 (define (**filepos-col filepos)
97 (quotient filepos (max-lines))))
99 (define (**readenv-open filename)
101 (define (error-proc re msg . args)
102 (apply compiler-user-error
103 (cons (re->locat re filename)
107 (define (wrapper re x)
108 (make-source x (re->locat re filename)))
110 (define (unwrapper re x)
113 (let ((port (open-input-file filename)))
120 (define (**readenv-close re)
121 (close-input-port (**readenv-port re)))
126 (define (**append-strings lst)
127 (let loop1 ((n 0) (x lst) (y '()))
130 (loop1 (+ n (string-length s)) (cdr x) (cons s y)))
131 (let ((result (make-string n #\space)))
132 (let loop2 ((k (- n 1)) (y y))
135 (let loop3 ((i k) (j (- (string-length s) 1)))
138 (string-set! result i (string-ref s j))
139 (loop3 (- i 1) (- j 1)))
143 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
145 ;; Symbol "canonicalization".
147 (define (string->canonical-symbol str)
148 (let ((new-str (string-append str "")))
150 (**readtable-string-convert-case! **main-readtable new-str))
151 (string->symbol new-str)))
153 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
155 ;; 'location' manipulation
157 (define (re->locat re filename)
158 (vector filename (**readenv-filepos re)))
160 (define (expr->locat expr source)
161 (vector source expr))
163 (define (locat-show prefix loc)
166 (let ((filename (##container->path (##locat-container loc)))
167 (filepos (##locat-position loc)))
168 (if (string? filename) ; file?
169 (let ((str (format-filepos filename filepos #t)))
174 (let ((line (+ (**filepos-line filepos) 1))
175 (col (+ (**filepos-col filepos) 1))
177 (if (string? filename)
178 (path-expand filename)
186 (let ((source (vector-ref loc 0))
187 (expr (vector-ref loc 1)))
189 (display "EXPRESSION ")
192 (locat-show " " (source-locat source))))))
194 (display "UNKNOWN LOCATION")))
196 (define (locat-filename-and-line loc)
198 (let* ((container (##locat-container loc))
199 (path (##container->path container)))
201 (let* ((position (##locat-position loc))
202 (filepos (##position->filepos position))
203 (line (+ (**filepos-line filepos) 1)))
208 (define (locat-filename loc)
209 (car (locat-filename-and-line loc)))
211 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
213 ;; 'source' manipulation
215 ;; (expression->source expr source) returns the source that represent
216 ;; the Scheme expression 'expr' and is related to the source 'source'
217 ;; (#f if no relation).
219 (define (expression->source expr source)
221 (define (expr->source x)
222 (make-source (cond ((pair? x)
225 (box-object (expr->source (unbox-object x))))
230 (expr->locat x source)))
232 (define (list-convert l)
233 (cons (expr->source (car l))
234 (list-tail-convert (cdr l))))
236 (define (list-tail-convert l)
238 (if (quoting-form? l) ; so that macros which generate quoting-forms
239 (expr->source l) ; at the tail of a list work properly
240 (cons (expr->source (car l))
241 (list-tail-convert (cdr l)))))
247 (define (quoting-form? x)
248 (let ((first (car x))
252 (or (eq? first quote-sym)
253 (eq? first quasiquote-sym)
254 (eq? first unquote-sym)
255 (eq? first unquote-splicing-sym)))))
257 (define (vector-convert v)
258 (let* ((len (vector-length v))
259 (x (make-vector len)))
260 (let loop ((i (- len 1)))
263 (vector-set! x i (expr->source (vector-ref v i)))
269 ;; (source->expression source) returns the Scheme expression represented by the
270 ;; source 'source'. Note that every call with the same argument returns a
271 ;; different (i.e. non eq?) expression.
273 (define (source->expression source)
275 (define (list->expression l)
277 (cons (source->expression (car l)) (list->expression (cdr l))))
281 (source->expression l))))
283 (define (vector->expression v)
284 (let* ((len (vector-length v))
285 (x (make-vector len)))
286 (let loop ((i (- len 1)))
289 (vector-set! x i (source->expression (vector-ref v i)))
293 (let ((code (source-code source)))
295 (list->expression code))
297 (box-object (source->expression (unbox-object code))))
298 ((vector-object? code)
299 (vector->expression code))
303 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
305 ;; (include-expr->source source info-port) returns a list of the
306 ;; source representation for each of the expressions contained in the
309 (define (include-expr->sourcezzzzz source info-port)
311 (define (find-source-file filename)
313 (define (open-error filename)
317 (or (path-expand filename)
320 (let ((expanded-filename (path-expand filename)))
321 (if expanded-filename
322 (if (equal? (path-extension expanded-filename) "")
324 (let loop ((exts (append (map car scheme-file-extensions) '(""))))
326 (let* ((ext (car exts))
327 (full-name (string-append expanded-filename ext))
328 (port (open-input-file* full-name)))
331 (close-input-port port)
334 (open-error filename)))
336 (let ((port (open-input-file* expanded-filename)))
339 (close-input-port port)
341 (open-error filename))))
343 (open-error filename))))
346 (cadr (source-code source)))
348 (source-code filename-src))
352 (path-directory (path-expand (locat-filename (source-locat filename-src))))))
354 (find-source-file rerooted-filename))
356 (**readenv-open final-filename)))
358 (define (read-sources) ; return list of all sources in file
359 ';;;;;;;;;;;;;;;;;;;;;;;;;;;
360 (let ((source ((or read-datum-or-eof **read-datum-or-eof) re)))
361 (if (vector-object? source)
363 (if info-port (display "." info-port))
364 (cons source (read-sources)))
367 (##read-all-as-a-begin-expr-from-port
369 (##current-readtable)
372 (##make-locat (##port-name (macro-readenv-port re))
373 (macro-readenv-filepos re))))
378 1));;;;;;;;;;;;;;;;;;;;;;;
382 (display "(reading " info-port)
383 (write (path-expand final-filename) info-port)))
385 (let ((sources (read-sources)))
387 (if info-port (display ")" info-port))
393 (define (read-source path relative-to-path try-scheme-file-extensions?)
395 (define (read-source-from-path path)
396 (let ((container (##path->container path)))
397 (##read-all-as-a-begin-expr-from-path
399 (##current-readtable);;;;;;;;;;;;;;;;;;;;
402 (##make-locat container
404 (macro-readenv-filepos re)))))
405 (make-source x locat)))
409 (define (read-source-no-extension)
410 (let loop ((lst ##scheme-file-extensions))
412 (let ((x (read-source-from-path (string-append path (caar lst)))))
418 (or (and try-scheme-file-extensions?
419 (string=? (path-extension path) "")
420 (read-source-no-extension))
421 (let* ((abs-path (##path-reference path relative-to-path))
422 (x (read-source-from-path abs-path)))
424 (compiler-error "Can't find file" abs-path)
427 (define (include-expr->source source info-port)
429 (cadr (source-code source)))
431 (source-code filename-src))
433 (read-source filename
434 (locat-filename (source-locat filename-src))
436 (##vector-ref x 1)));;;;;;;;;;;;;;;;;;;;;;;;
438 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
440 ;; Tables for reader.
442 (define **standard-escaped-char-table
445 (cons #\a (unicode->character 7))
446 (cons #\b (unicode->character 8))
447 (cons #\t (unicode->character 9))
449 (cons #\v (unicode->character 11))
450 (cons #\f (unicode->character 12))
451 (cons #\r (unicode->character 13))))
453 (define **standard-named-char-table
455 (cons "newline" #\newline)
457 (cons "nul" (unicode->character 0))
458 (cons "bel" (unicode->character 7))
459 (cons "backspace" (unicode->character 8))
460 (cons "tab" (unicode->character 9))
461 (cons "linefeed" (unicode->character 10))
462 (cons "vt" (unicode->character 11))
463 (cons "page" (unicode->character 12))
464 (cons "return" (unicode->character 13))
465 (cons "rubout" (unicode->character 127))))
467 (define **standard-sharp-bang-table
469 (cons "optional" optional-object)
470 (cons "rest" rest-object)
471 (cons "key" key-object)
472 (cons "eof" end-of-file-object)))
474 (set! **standard-sharp-bang-table;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
475 (append (list (cons "void" (##type-cast -5 2))
476 (cons "unbound1" (##type-cast -7 2))
477 (cons "unbound2" (##type-cast -8 2)))
478 **standard-sharp-bang-table))
480 ;;;============================================================================
484 ;; For compatibility between the interpreter and compiler, this section
485 ;; must be the same as the corresponding section in the file
486 ;; "lib/_io.scm" (except that ## and ** are exchanged).
488 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
490 ;; A chartable structure is a vector-like data structure which is
491 ;; indexed using a character.
493 (define (**make-chartable default)
494 (vector (make-vector 128 default) default '()))
496 (define (**chartable-ref ct c)
497 (let ((i (character->unicode c)))
499 (vector-ref (vector-ref ct 0) i)
500 (let ((x (assq i (vector-ref ct 2))))
503 (vector-ref ct 1))))))
505 (define (**chartable-set! ct c val)
506 (let ((i (character->unicode c)))
508 (vector-set! (vector-ref ct 0) i val)
509 (let ((x (assq i (vector-ref ct 2))))
512 (vector-set! ct 2 (cons (cons i val) (vector-ref ct 2))))))))
514 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
516 ;; A readtable structure contains parsing information for the reader.
517 ;; It indicates what action must be taken when a given character is
520 (define **readtable-tag '#(readtable 0))
522 (define (**make-readtable
528 char-delimiter?-table
538 char-delimiter?-table
540 ;; (subtype-structure))
543 (define (**readtable-case-conversion? rt)
546 (define (**readtable-case-conversion?-set! rt x)
547 (vector-set! rt 1 x))
549 (define (**readtable-keywords-allowed? rt)
552 (define (**readtable-keywords-allowed?-set! rt x)
553 (vector-set! rt 2 x))
555 (define (**readtable-escaped-char-table rt)
558 (define (**readtable-escaped-char-table-set! rt x)
559 (vector-set! rt 3 x))
561 (define (**readtable-named-char-table rt)
564 (define (**readtable-named-char-table-set! rt x)
565 (vector-set! rt 4 x))
567 (define (**readtable-sharp-bang-table rt)
570 (define (**readtable-sharp-bang-table-set! rt x)
571 (vector-set! rt 5 x))
573 (define (**readtable-char-delimiter?-table rt)
576 (define (**readtable-char-delimiter?-table-set! rt x)
577 (vector-set! rt 6 x))
579 (define (**readtable-char-handler-table rt)
582 (define (**readtable-char-handler-table-set! rt x)
583 (vector-set! rt 7 x))
585 (define (**readtable-char-delimiter? rt c)
586 (**chartable-ref (**readtable-char-delimiter?-table rt) c))
588 (define (**readtable-char-delimiter?-set! rt c delimiter?)
589 (**chartable-set! (**readtable-char-delimiter?-table rt) c delimiter?))
591 (define (**readtable-char-handler rt c)
592 (**chartable-ref (**readtable-char-handler-table rt) c))
594 (define (**readtable-char-handler-set! rt c handler)
595 (**chartable-set! (**readtable-char-handler-table rt) c handler))
597 (define (**readtable-char-class-set! rt c delimiter? handler)
599 (**readtable-char-delimiter?-set! rt c delimiter?)
600 (**readtable-char-handler-set! rt c handler)))
602 (define (**readtable-convert-case rt c)
603 (let ((case-conversion? (**readtable-case-conversion? rt)))
605 (if (eq? case-conversion? 'upcase)
610 (define (**readtable-string-convert-case! rt s)
611 (let ((case-conversion? (**readtable-case-conversion? rt)))
613 (if (eq? case-conversion? 'upcase)
614 (let loop ((i (- (string-length s) 1)))
617 (string-set! s i (char-upcase (string-ref s i)))
619 (let loop ((i (- (string-length s) 1)))
622 (string-set! s i (char-downcase (string-ref s i)))
623 (loop (- i 1)))))))))
625 (define (**readtable-parse-keyword rt s)
626 (let ((keywords-allowed? (**readtable-keywords-allowed? rt)))
627 (and keywords-allowed?
628 (let ((len (string-length s)))
630 (if (eq? keywords-allowed? 'prefix)
631 (and (char=? (string-ref s 0) #\:)
632 (string->keyword-object
633 (substring s 1 len)))
634 (and (char=? (string-ref s (- len 1)) #\:)
635 (string->keyword-object
636 (substring s 0 (- len 1))))))))))
638 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
642 (define (**read-error-datum-or-eof-expected re)
643 ((**readenv-error-proc re) re "Datum or EOF expected"))
645 (define (**read-error-datum-expected re)
646 ((**readenv-error-proc re) re "Datum expected"))
648 (define (**read-error-improperly-placed-dot re)
649 ((**readenv-error-proc re) re "Improperly placed dot"))
651 (define (**read-error-incomplete-form-eof-reached re)
652 ((**readenv-error-proc re) re "Incomplete form, EOF reached"))
654 (define (**read-error-incomplete re)
655 ((**readenv-error-proc re) re "Incomplete form"))
657 (define (**read-error-char-name re str)
658 ((**readenv-error-proc re) re "Invalid '#\\' name:" str))
660 (define (**read-error-illegal-char re c)
661 ((**readenv-error-proc re) re "Illegal character:" c))
663 (define (**read-error-u8 re)
664 ((**readenv-error-proc re) re "8 bit exact integer expected"))
666 (define (**read-error-u16 re)
667 ((**readenv-error-proc re) re "16 bit exact integer expected"))
669 (define (**read-error-u32 re)
670 ((**readenv-error-proc re) re "32 bit exact integer expected"))
672 (define (**read-error-u64 re)
673 ((**readenv-error-proc re) re "64 bit exact integer expected"))
675 (define (**read-error-f32/f64 re)
676 ((**readenv-error-proc re) re "Inexact real expected"))
678 (define (**read-error-hex re)
679 ((**readenv-error-proc re) re "Invalid hexadecimal escape"))
681 (define (**read-error-escaped-char re c)
682 ((**readenv-error-proc re) re "Invalid escaped character:" c))
684 (define (**read-error-vector re)
685 ((**readenv-error-proc re) re "'(' expected"))
687 (define (**read-error-sharp-token re str)
688 ((**readenv-error-proc re) re "Invalid token:" str))
690 (define (**read-error-sharp-bang-name re str)
691 ((**readenv-error-proc re) re "Invalid '#!' name:" str))
693 (define (**read-error-char-range re)
694 ((**readenv-error-proc re) re "Character out of range"))
696 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
698 ;; Procedures to read single characters.
700 (define (**peek-next-char re) ; never returns end-of-file
701 (let ((next (**peek-next-char-or-eof re)))
704 (**read-error-incomplete-form-eof-reached re))))
706 (define (**read-next-char re) ; never returns end-of-file
707 (let ((c (**read-next-char-or-eof re)))
710 (**read-error-incomplete-form-eof-reached re))))
712 (define (**read-next-char-expecting re c) ; only accepts c as the next char
713 (let ((x (**read-next-char-or-eof re)))
715 (if (not (char=? x c))
716 (**read-error-incomplete re))
717 (**read-error-incomplete-form-eof-reached re))
720 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
722 ;; Procedures to read datums.
724 ;; (**read-datum-or-eof re) attempts to read a datum in the read
725 ;; environment "re", skipping all whitespace and comments in the
726 ;; process. The "pos" field of the read environment indicates the
727 ;; position where the enclosing datum starts (e.g. list or vector). If
728 ;; a datum is read it is returned (wrapped if the read environment asks
729 ;; for it); if the end-of-file is reached the end-of-file object is
730 ;; returned (never wrapped); otherwise an error is signaled. The read
731 ;; environment's "pos" field is only modified if a datum was read, in
732 ;; which case it is the position where the datum starts.
734 (define (**read-datum-or-eof re)
735 (let ((obj (**read-datum-or-none re)))
736 (if (eq? obj (**none-marker))
737 (let ((c (**peek-next-char-or-eof re)))
740 (**readenv-filepos-set! re (**readenv-current-filepos re))
741 (**read-next-char-or-eof re) ; to make sure reader makes progress
742 (**read-error-datum-or-eof-expected re))
744 (**read-next-char-or-eof re) ; to make sure reader makes progress
745 c))) ; end-of-file was reached so return end-of-file object
748 ;; (**read-datum re) attempts to read a datum in the read environment
749 ;; "re", skipping all whitespace and comments in the process. The
750 ;; "pos" field of the read environment indicates the position where the
751 ;; enclosing datum starts (e.g. list or vector). If a datum is read it
752 ;; is returned (wrapped if the read environment asks for it); if the
753 ;; end-of-file is reached or no datum can be read an error is signaled.
754 ;; The read environment's "pos" field is only modified if a datum was
755 ;; read, in which case it is the position where the datum starts.
757 (define (**read-datum re)
758 (let ((obj (**read-datum-or-none re)))
759 (if (eq? obj (**none-marker))
761 (**readenv-filepos-set! re (**readenv-current-filepos re))
762 (**read-next-char-or-eof re) ; to make sure reader makes progress
763 (**read-error-datum-expected re))
766 ;; (**read-datum-or-none re) attempts to read a datum in the read
767 ;; environment "re", skipping all whitespace and comments in the
768 ;; process. The "pos" field of the read environment indicates the
769 ;; position where the enclosing datum starts (e.g. list or vector). If
770 ;; a datum is read it is returned (wrapped if the read environment asks
771 ;; for it); if the end-of-file is reached or no datum can be read the
772 ;; "none-marker" is returned. The read environment's "pos" field is
773 ;; only modified if a datum was read, in which case it is the position
774 ;; where the datum starts.
776 (define (**read-datum-or-none re)
777 (let ((obj (**read-datum-or-none-or-dot re)))
778 (if (eq? obj (**dot-marker))
780 (**readenv-filepos-set! re (**readenv-previous-filepos re 1))
781 (**read-error-improperly-placed-dot re))
784 ;; (**read-datum-or-none-or-dot re) attempts to read a datum in the
785 ;; read environment "re", skipping all whitespace and comments in the
786 ;; process. The "pos" field of the read environment indicates the
787 ;; position where the enclosing datum starts (e.g. list or vector). If
788 ;; a datum is read it is returned (wrapped if the read environment asks
789 ;; for it); if a lone dot is read the "dot-marker" is returned; if the
790 ;; end-of-file is reached or no datum can be read the "none-marker" is
791 ;; returned. The read environment's "pos" field is only modified if a
792 ;; datum was read, in which case it is the position where the datum
795 (define (**read-datum-or-none-or-dot re)
796 (let ((next (**peek-next-char-or-eof re)))
798 ((**readtable-char-handler (**readenv-readtable re) next) re next)
801 ;; Special objects returned by **read-datum-or-none-or-dot.
803 (define (**none-marker) '#(none)) ; indicates no following datum
804 (define (**dot-marker) '#(dot)) ; indicates an isolated dot
806 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
808 ;; Procedure to read a list of datums (possibly an improper list).
810 (define (**build-list re allow-improper? start-pos close)
811 (let ((obj (**read-datum-or-none re)))
812 (if (eq? obj (**none-marker))
814 (**read-next-char-expecting re close)
816 (let ((lst (cons obj '())))
817 (**readenv-filepos-set! re start-pos) ; restore pos
818 (let loop ((end lst))
821 (**read-datum-or-none-or-dot re)
822 (**read-datum-or-none re))))
823 (cond ((eq? obj (**none-marker))
824 (**read-next-char-expecting re close)
826 ((eq? obj (**dot-marker))
827 (let ((obj (**read-datum re)))
829 (**readenv-filepos-set! re start-pos) ; restore pos
830 (let ((x (**read-datum-or-none re))) ; skip whitespace!
831 (if (eq? x (**none-marker))
833 (**read-next-char-expecting re close)
836 (**readenv-filepos-set! re start-pos) ; restore pos
837 (**read-error-incomplete re))))))
839 (**readenv-filepos-set! re start-pos) ; restore pos
840 (let ((tail (cons obj '())))
844 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
846 ;; Procedure to read a vector or byte vector.
848 (define (**build-vector re kind start-pos close)
850 (define (exact-integer-check n lo hi)
853 (in-integer-range? n lo hi)))
855 (define (inexact-real-check n)
860 (let* ((x (**read-datum-or-none re))
861 (x-pos (**readenv-filepos re)))
862 (**readenv-filepos-set! re start-pos) ; restore pos
863 (if (eq? x (**none-marker))
865 (**read-next-char-expecting re close)
867 ((vector) (make-vector i #f))
868 ((u8vector) (make-u8vect i))
869 ((u16vector) (make-u16vect i))
870 ((u32vector) (make-u32vect i))
871 ((u64vector) (make-u64vect i))
872 ((f32vector) (make-f32vect i))
873 ((f64vector) (make-f64vect i))))
874 (let ((vect (loop (+ i 1))))
877 (vector-set! vect i x))
879 (let ((ux (**readenv-unwrap re x)))
880 (if (not (exact-integer-check ux 0 255))
882 (**readenv-filepos-set! re x-pos) ; restore pos of element
883 (**read-error-u8 re)))
884 (u8vect-set! vect i ux)))
886 (let ((ux (**readenv-unwrap re x)))
887 (if (not (exact-integer-check ux 0 65535))
889 (**readenv-filepos-set! re x-pos) ; restore pos of element
890 (**read-error-u16 re)))
891 (u16vect-set! vect i ux)))
893 (let ((ux (**readenv-unwrap re x)))
894 (if (not (exact-integer-check ux 0 4294967295))
896 (**readenv-filepos-set! re x-pos) ; restore pos of element
897 (**read-error-u32 re)))
898 (u32vect-set! vect i ux)))
900 (let ((ux (**readenv-unwrap re x)))
901 (if (not (exact-integer-check ux 0 18446744073709551615))
903 (**readenv-filepos-set! re x-pos) ; restore pos of element
904 (**read-error-u64 re)))
905 (u64vect-set! vect i ux)))
907 (let ((ux (**readenv-unwrap re x)))
908 (if (not (inexact-real-check ux))
910 (**readenv-filepos-set! re x-pos) ; restore pos of element
911 (**read-error-f32/f64 re)))
912 (f32vect-set! vect i ux)))
914 (let ((ux (**readenv-unwrap re x)))
915 (if (not (inexact-real-check ux))
917 (**readenv-filepos-set! re x-pos) ; restore pos of element
918 (**read-error-f32/f64 re)))
919 (f64vect-set! vect i ux))))
922 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
924 ;; Procedures to read delimited tokens.
926 (define (**build-delimited-string re c i)
928 (let ((next (**peek-next-char-or-eof re)))
929 (if (or (not (char? next))
930 (**readtable-char-delimiter? (**readenv-readtable re) next))
933 (**read-next-char-or-eof re) ; skip "next"
934 (let ((s (loop (+ i 1))))
935 (string-set! s i next)
938 (define (**build-delimited-number/keyword/symbol re c)
939 (let ((s (**build-delimited-string re c 1)))
940 (or (string->number s 10)
942 (**readtable-string-convert-case! (**readenv-readtable re) s)
943 (or (**readtable-parse-keyword (**readenv-readtable re) s)
944 (string->symbol s))))))
946 (define (**build-delimited-symbol re c i)
947 (let ((s (**build-delimited-string re c i)))
948 (**readtable-string-convert-case! (**readenv-readtable re) s)
951 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
953 (define (**build-escaped-string-up-to re close)
955 (define (char-octal? c)
956 (and (not (char<? c #\0)) (not (char<? #\7 c))))
958 (define (char-hexadecimal? c)
959 (or (and (not (char<? c #\0)) (not (char<? #\9 c)))
960 (and (not (char<? c #\a)) (not (char<? #\f c)))
961 (and (not (char<? c #\A)) (not (char<? #\F c)))))
964 (if (in-char-range? n)
965 (unicode->character n)
966 (**read-error-char-range re)))
968 (define (read-escape-octal c)
969 (let ((str (let loop ((i 1))
970 (let ((next (**peek-next-char-or-eof re)))
975 (**read-next-char-or-eof re) ; skip "next"
976 (let ((s (loop (+ i 1))))
977 (string-set! s i next)
979 (make-string i #\space))))))
980 (string-set! str 0 c)
981 (unicode (string->number str 8))))
983 (define (read-escape-hexadecimal)
984 (let ((next (**peek-next-char-or-eof re)))
985 (if (and (char? next)
986 (char-hexadecimal? next))
988 (**read-next-char-or-eof re) ; skip "next"
989 (let ((str (let loop ((i 1))
990 (let ((next2 (**peek-next-char-or-eof re)))
991 (if (and (char? next2)
992 (char-hexadecimal? next2))
994 (**read-next-char-or-eof re) ; skip "next2"
995 (let ((s (loop (+ i 1))))
996 (string-set! s i next2)
998 (make-string i #\space))))))
999 (string-set! str 0 next)
1000 (unicode (string->number str 16))))
1001 (**read-error-hex re))))
1003 (define (read-escape)
1004 (let ((next (**read-next-char re)))
1005 (cond ((char-octal? next)
1006 (read-escape-octal next))
1008 (read-escape-hexadecimal))
1009 ((char=? next close)
1013 (**readtable-escaped-char-table
1014 (**readenv-readtable re)))))
1017 (**read-error-escaped-char re next)))))))
1019 (define max-chunk-length 512)
1021 (define (read-chunk)
1023 (if (< i max-chunk-length)
1024 (let ((c (**read-next-char re)))
1025 (cond ((char=? c close)
1026 (make-string i #\space))
1028 (let* ((c (read-escape))
1033 (let ((s (loop (+ i 1))))
1036 (make-string i #\space))))
1038 (let ((chunk1 (read-chunk)))
1039 (if (< (string-length chunk1) max-chunk-length)
1041 (let loop ((chunks (list chunk1)))
1042 (let* ((new-chunk (read-chunk))
1043 (new-chunks (cons new-chunk chunks)))
1044 (if (< (string-length new-chunk) max-chunk-length)
1045 (**append-strings (reverse new-chunks))
1046 (loop new-chunks)))))))
1048 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1050 ;; Procedures to handle comments.
1052 (define (**skip-extended-comment re open1 open2 close1 close2)
1053 (let loop ((level 0) (c (**read-next-char re)))
1054 (cond ((char=? c open1)
1055 (let ((c (**read-next-char re)))
1056 (if (char=? c open2)
1057 (loop (+ level 1) (**read-next-char re))
1060 (let ((c (**read-next-char re)))
1061 (if (char=? c close2)
1063 (loop (- level 1) (**read-next-char re))
1064 #f) ; comment has ended
1067 (loop level (**read-next-char re))))))
1069 (define (**skip-single-line-comment re)
1071 (let ((next (**peek-next-char-or-eof re)))
1074 (**read-next-char-or-eof re) ; skip "next"
1075 (if (not (char=? next #\newline))
1078 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1080 ;; Procedure to read datums starting with '#'.
1082 (define (**read-sharp re c)
1083 (let ((start-pos (**readenv-current-filepos re)))
1084 (**read-next-char-or-eof re) ; skip #\#
1085 (let ((next (**peek-next-char re)))
1086 (cond ((char=? next #\()
1087 (**read-next-char-or-eof re) ; skip #\(
1088 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1089 (let ((vect (**build-vector re 'vector start-pos #\))))
1090 (**readenv-wrap re vect)))
1092 (**read-next-char-or-eof re) ; skip #\\
1093 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1094 (let ((c (**read-next-char re)))
1095 (if (**readtable-char-delimiter?
1096 (**readenv-readtable re)
1097 (**peek-next-char-or-eof re))
1098 (**readenv-wrap re c)
1099 (let ((name (**build-delimited-string re c 1)))
1100 (let ((x (**read-assoc-string-ci=?
1102 (**readtable-named-char-table
1103 (**readenv-readtable re)))))
1105 (**readenv-wrap re (cdr x))
1106 (let ((n (string->number name 10)))
1110 (if (in-char-range? n)
1111 (**readenv-wrap re (unicode->character n))
1112 (**read-error-char-range re))
1113 (**read-error-char-name re name)))))))))
1115 (let ((old-pos (**readenv-filepos re)))
1116 (**readenv-filepos-set! re start-pos) ; in case error in comment
1117 (**read-next-char-or-eof re) ; skip #\|
1118 (**skip-extended-comment re #\# #\| #\| #\#)
1119 (**readenv-filepos-set! re old-pos) ; restore pos
1120 (**read-datum-or-none-or-dot re))) ; read what follows comment
1122 (**read-next-char-or-eof re) ; skip #\!
1123 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1124 (let ((name (**build-delimited-string re #\space 0)))
1125 (let ((x (**read-assoc-string-ci=?
1127 (**readtable-sharp-bang-table
1128 (**readenv-readtable re)))))
1130 (**readenv-wrap re (cdr x))
1131 (**read-error-sharp-bang-name re name)))))
1133 (**read-next-char-or-eof re) ; skip #\#
1134 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1135 (let ((sym (**build-delimited-symbol re #\# 2)))
1136 (**readenv-wrap re sym)))
1138 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1140 (**build-delimited-string re c 1))
1142 (or (string->number s 10)
1145 (define (build-vect re kind)
1146 (let ((c (**read-next-char re)))
1148 (**build-vector re kind start-pos #\))
1149 (**read-error-vector re))))
1151 (cond ((string-ci=? s "#f")
1153 ((string-ci=? s "#t")
1155 ((string-ci=? s "#u8")
1156 (build-vect re 'u8vector))
1157 ((string-ci=? s "#u16")
1158 (build-vect re 'u16vector))
1159 ((string-ci=? s "#u32")
1160 (build-vect re 'u32vector))
1161 ((string-ci=? s "#u64")
1162 (build-vect re 'u64vector))
1163 ((string-ci=? s "#f32")
1164 (build-vect re 'f32vector))
1165 ((string-ci=? s "#f64")
1166 (build-vect re 'f64vector))
1168 (**read-error-sharp-token re s)))))))
1169 (**readenv-wrap re obj)))))))
1171 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1173 (define (**read-whitespace re c)
1174 (**read-next-char-or-eof re) ; skip whitespace character
1175 (**read-datum-or-none-or-dot re)) ; read what follows whitespace
1177 (define (**read-single-line-comment re c)
1178 (**skip-single-line-comment re) ; skip comment
1179 (**read-datum-or-none-or-dot re)) ; read what follows comment
1181 (define (**read-escaped-string re c)
1182 (let ((start-pos (**readenv-current-filepos re)))
1183 (**read-next-char-or-eof re) ; skip #\"
1184 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1185 (let ((str (**build-escaped-string-up-to re c)))
1186 (**readenv-wrap re str))))
1188 (define (**read-escaped-symbol re c)
1189 (let ((start-pos (**readenv-current-filepos re)))
1190 (**read-next-char-or-eof re) ; skip #\|
1191 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1192 (let ((sym (string->symbol (**build-escaped-string-up-to re c))))
1193 (**readenv-wrap re sym))))
1195 (define (**read-quotation re c)
1196 (let ((start-pos (**readenv-current-filepos re)))
1197 (**read-next-char-or-eof re) ; skip #\'
1198 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1199 (let ((obj (**read-datum re)))
1200 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1203 (list (**readenv-wrap re 'quote) obj)))))
1205 (define (**read-quasiquotation re c)
1206 (let ((start-pos (**readenv-current-filepos re)))
1207 (**read-next-char-or-eof re) ; skip #\`
1208 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1209 (let ((obj (**read-datum re)))
1210 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1213 (list (**readenv-wrap re 'quasiquote) obj)))))
1215 (define (**read-unquotation re c)
1216 (let ((start-pos (**readenv-current-filepos re)))
1217 (**read-next-char-or-eof re) ; skip #\,
1218 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1219 (let ((next (**peek-next-char re)))
1220 (if (char=? next #\@)
1222 (**read-next-char-or-eof re) ; skip #\@
1223 (let ((obj (**read-datum re)))
1224 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1227 (list (**readenv-wrap re 'unquote-splicing) obj))))
1228 (let ((obj (**read-datum re)))
1229 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1232 (list (**readenv-wrap re 'unquote) obj)))))))
1234 (define (**read-list re c)
1235 (let ((start-pos (**readenv-current-filepos re)))
1236 (**read-next-char-or-eof re) ; skip #\( or #\[ or #\{
1237 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1239 (cond ((char=? c #\[) #\])
1240 ((char=? c #\{) #\})
1242 (let ((lst (**build-list re #t start-pos close)))
1243 (**readenv-wrap re lst)))))
1245 (define (**read-none re c)
1248 (define (**read-illegal re c)
1249 (let ((start-pos (**readenv-current-filepos re)))
1250 (**read-next-char-or-eof re) ; skip illegal character
1251 (**readenv-filepos-set! re start-pos) ; set pos to illegal char
1252 (**read-error-illegal-char re c)))
1254 (define (**read-dot re c)
1255 (let ((start-pos (**readenv-current-filepos re)))
1256 (**read-next-char-or-eof re) ; skip #\.
1257 (let ((next (**peek-next-char-or-eof re)))
1258 (if (or (not (char? next))
1259 (**readtable-char-delimiter? (**readenv-readtable re) next))
1262 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1263 (let ((obj (**build-delimited-number/keyword/symbol re c)))
1264 (**readenv-wrap re obj)))))))
1266 (define (**read-number/keyword/symbol re c)
1267 (let ((start-pos (**readenv-current-filepos re)))
1268 (**read-next-char-or-eof re) ; skip "c"
1269 (**readenv-filepos-set! re start-pos) ; set pos to start of datum
1270 (let ((obj (**build-delimited-number/keyword/symbol re c)))
1271 (**readenv-wrap re obj))))
1273 (define (**read-assoc-string-ci=? x lst)
1274 (let loop ((lst lst))
1276 (let ((couple (car lst)))
1277 (let ((y (car couple)))
1278 (if (string-ci=? x y)
1283 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1285 ;; Setup the standard readtable.
1287 (define (**make-standard-readtable)
1290 #f ; preserve case in symbols, character names, etc
1291 #t ; keywords ending with ":" are allowed
1292 **standard-escaped-char-table
1293 **standard-named-char-table
1294 **standard-sharp-bang-table
1295 (**make-chartable #f) ; all chars are non-delimiters
1296 (**make-chartable **read-number/keyword/symbol))))
1298 (if (**comply-to-standard-scheme?) ; force compliance to standard Scheme?
1300 (**readtable-case-conversion?-set! rt #t)
1301 (**readtable-keywords-allowed?-set! rt #f)))
1303 ; setup control characters
1308 (**readtable-char-class-set!
1310 (unicode->character i)
1315 ; setup whitespace characters
1317 (**readtable-char-class-set! rt #\space #t **read-whitespace)
1318 (**readtable-char-class-set! rt #\linefeed #t **read-whitespace)
1319 (**readtable-char-class-set! rt #\return #t **read-whitespace)
1320 (**readtable-char-class-set! rt #\tab #t **read-whitespace)
1321 (**readtable-char-class-set! rt #\page #t **read-whitespace)
1323 ; setup handlers for non-whitespace delimiters
1325 (**readtable-char-class-set! rt #\; #t **read-single-line-comment)
1327 (**readtable-char-class-set! rt #\" #t **read-escaped-string)
1328 (**readtable-char-class-set! rt #\| #t **read-escaped-symbol)
1330 (**readtable-char-class-set! rt #\' #t **read-quotation)
1331 (**readtable-char-class-set! rt #\` #t **read-quasiquotation)
1332 (**readtable-char-class-set! rt #\, #t **read-unquotation)
1334 (**readtable-char-class-set! rt #\( #t **read-list)
1335 (**readtable-char-class-set! rt #\) #t **read-none)
1337 (**readtable-char-class-set! rt #\[ #t **read-list)
1338 (**readtable-char-class-set! rt #\] #t **read-none)
1340 (**readtable-char-class-set! rt #\{ #t **read-illegal)
1341 (**readtable-char-class-set! rt #\} #t **read-illegal)
1343 ; setup handlers for "#" and "." (these are NOT delimiters)
1345 (**readtable-char-class-set! rt #\# #f **read-sharp)
1346 (**readtable-char-class-set! rt #\. #f **read-dot)
1350 (if (not **main-readtable)
1351 (set! **main-readtable
1352 (**make-standard-readtable)))
1354 ;;;============================================================================
1358 (include "fixnum.scm")
1360 (include-adt "_envadt.scm")
1361 (include-adt "_gvmadt.scm")
1362 (include-adt "_ptreeadt.scm")
1363 (include "_sourceadt.scm")
1365 (define (**filepos-line filepos)
1366 (##filepos-line filepos))
1368 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1370 ;; Symbol "canonicalization".
1372 (define (string->canonical-symbol str)
1373 (let ((new-str (string-append str "")))
1374 (##readtable-string-convert-case! (current-readtable) new-str)
1377 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1379 ;; 'location' manipulation
1381 (define (expr->locat expr source)
1382 (vector source expr));;;;;;;;;;;;;;;;;;;;;;
1384 (define (locat-show prefix loc)
1387 (if (string? (vector-ref loc 0)) ; file?
1388 (let* ((filename (vector-ref loc 0))
1389 (filepos (vector-ref loc 1))
1390 (str (format-filepos filename filepos #t)))
1395 (let ((line (+ (**filepos-line filepos) 1))
1396 (col (+ (**filepos-col filepos) 1))
1398 (if (string? filename)
1399 (path-expand filename)
1407 (let ((source (vector-ref loc 0))
1408 (expr (vector-ref loc 1)))
1410 (display "EXPRESSION ")
1413 (locat-show " " (source-locat source)))))
1415 (display "UNKNOWN LOCATION")))
1417 (define (locat-filename-and-line loc)
1419 (if (string? (vector-ref loc 0)) ; file?
1420 (let* ((filename (vector-ref loc 0))
1421 (filepos (vector-ref loc 1))
1422 (line (+ (**filepos-line filepos) 1)))
1423 (cons filename line))
1424 (let ((source (vector-ref loc 0))
1425 (expr (vector-ref loc 1)))
1427 (locat-filename-and-line (source-locat source))
1431 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1433 ;; 'source' manipulation
1435 ;; (expression->source expr source) returns the source that represent
1436 ;; the Scheme expression 'expr' and is related to the source 'source'
1437 ;; (#f if no relation).
1439 (define (expression->source expr source)
1441 (define (expr->source x)
1442 (make-source (cond ((pair? x)
1445 (box-object (expr->source (unbox-object x))))
1450 (expr->locat x source)))
1452 (define (list-convert l)
1453 (cons (expr->source (car l))
1454 (list-tail-convert (cdr l))))
1456 (define (list-tail-convert l)
1458 (if (quoting-form? l) ; so that macros which generate quoting-forms
1459 (expr->source l) ; at the tail of a list work properly
1460 (cons (expr->source (car l))
1461 (list-tail-convert (cdr l)))))
1467 (define (quoting-form? x)
1468 (let ((first (car x))
1472 (or (eq? first quote-sym)
1473 (eq? first quasiquote-sym)
1474 (eq? first unquote-sym)
1475 (eq? first unquote-splicing-sym)))))
1477 (define (vector-convert v)
1478 (let* ((len (vector-length v))
1479 (x (make-vector len)))
1480 (let loop ((i (- len 1)))
1483 (vector-set! x i (expr->source (vector-ref v i)))
1487 (expr->source expr))
1489 ;; (source->expression source) returns the Scheme expression
1490 ;; represented by the source 'source'. Note that every call with the
1491 ;; same argument returns a different (i.e. non eq?) expression.
1493 (define (source->expression source)
1495 (define (list->expression l)
1497 (cons (source->expression (car l)) (list->expression (cdr l))))
1501 (source->expression l))))
1503 (define (vector->expression v)
1504 (let* ((len (vector-length v))
1505 (x (make-vector len)))
1506 (let loop ((i (- len 1)))
1509 (vector-set! x i (source->expression (vector-ref v i)))
1513 (let ((code (source-code source)))
1515 (list->expression code))
1517 (box-object (source->expression (unbox-object code))))
1518 ((vector-object? code)
1519 (vector->expression code))
1523 ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1525 ;; (include-expr->source source info-port) returns the source
1526 ;; representation of a "begin" form containing the expressions
1527 ;; contained in the specified file.
1529 (define (include-expr->source source info-port)
1531 (define (find-source-file filename)
1533 (define (open-error filename)
1537 (or (path-expand filename)
1540 (let ((expanded-filename (path-expand filename)))
1541 (if expanded-filename
1542 (if (equal? (path-extension expanded-filename) "")
1544 (let loop ((exts (append (map car scheme-file-extensions) '(""))))
1546 (let* ((ext (car exts))
1547 (full-name (string-append expanded-filename ext))
1548 (port (open-input-file* full-name)))
1551 (close-input-port port)
1554 (open-error filename)))
1556 (let ((port (open-input-file* expanded-filename)))
1559 (close-input-port port)
1561 (open-error filename))))
1563 (open-error filename))))
1565 (let* ((filename-src
1566 (cadr (source-code source)))
1568 (source-code filename-src))
1572 (path-directory (path-expand (locat-filename (source-locat filename-src))))))
1574 (find-source-file rerooted-filename))
1576 (**readenv-open final-filename)))
1578 (define (read-sources) ; return list of all sources in file
1579 ';;;;;;;;;;;;;;;;;;;;;;;;;;;
1580 (let ((source ((or read-datum-or-eof **read-datum-or-eof) re)))
1581 (if (vector-object? source)
1583 (if info-port (display "." info-port))
1584 (cons source (read-sources)))
1587 (##read-all-as-a-begin-expr-from-port
1589 (##current-readtable)
1591 (make-source x (##readenv->locat re)))
1596 1));;;;;;;;;;;;;;;;;;;;;;;
1600 (display "(reading " info-port)
1601 (write (path-expand final-filename) info-port)))
1603 (let ((sources (read-sources)))
1605 (if info-port (display ")" info-port))
1607 (**readenv-close re)