~ chicken-core (master) /internal.scm
Trap1;;;; internal.scm - Runtime support module 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(declare
28 (unit internal)
29 (disable-interrupts)
30 (fixnum))
31
32;; This is a bit of a grab-bag of stuff that's used in various places
33;; in the runtime and the compiler, but which is not supposed to be
34;; used by the user, and doesn't strictly belong anywhere in
35;; particular.
36(module chicken.internal
37 (;; Convert string into valid C-identifier
38 string->c-identifier
39
40 ;; Parse library specifications
41 library-id valid-library-specifier?
42
43 ;; Requirement identifier for modules
44 module-requirement
45
46 ;;; Check for multiple bindings in "let"-style constructs
47 check-for-multiple-bindings
48
49 ;;; Macro environment manipulation
50 macro-subset fixup-macro-environment
51
52 ;; Low-level hash table support
53 make-hash-table hash-table-ref hash-table-set! hash-table-update!
54 hash-table-for-each hash-table-size
55
56 ;; Modules that are made available to code by default
57 default-imports default-syntax-imports)
58
59(import scheme chicken.base chicken.fixnum)
60(import (only (scheme base) open-output-string get-output-string))
61
62(include "common-declarations.scm")
63(include "mini-srfi-1.scm")
64
65
66;;; Convert string into valid C-identifier:
67
68(define (string->c-identifier str)
69 (let ((out (open-output-string))
70 (n (string-length str)))
71 (do ((i 0 (fx+ i 1)))
72 ((fx>= i n) (get-output-string out))
73 (let ((c (string-ref str i)))
74 (if (and (not (char-alphabetic? c))
75 (or (not (char-numeric? c)) (fx= i 0)))
76 (let ((i (char->integer c)))
77 (write-char #\_ out)
78 (when (fx< i 16) (write-char #\0 out))
79 (display (number->string i 16) out))
80 (write-char c out))))))
81
82
83;;; Parse library specifications:
84
85(define (valid-library-specifier? x)
86 (or (symbol? x)
87 (and (list? x)
88 (not (null? x))
89 (every (lambda (x) (or (symbol? x) (fixnum? x))) x))))
90
91(define (library-id lib)
92 (define (fail)
93 (##sys#error "invalid library specifier" lib))
94 (define (srfi? x)
95 (and (pair? (cdr x))
96 (null? (cddr x))
97 (eq? 'srfi (car x))
98 (fixnum? (cadr x))))
99 (define (library-part->string x)
100 (cond ((symbol? x) (##sys#symbol->string/shared x))
101 ((fixnum? x) (##sys#number->string x))
102 (else (fail))))
103 (cond
104 ((symbol? lib) lib)
105 ((null? lib) (fail))
106 ((not (list? lib)) (fail))
107 ((srfi? lib)
108 (##sys#string->symbol
109 (##sys#string-append "srfi-" (##sys#number->string (cadr lib)))))
110 (else
111 (do ((lst (cdr lib) (cdr lst))
112 (str (library-part->string (car lib))
113 (string-append str "." (library-part->string (car lst)))))
114 ((null? lst)
115 (##sys#string->symbol str))))))
116
117
118;;; Requirement identifier for modules:
119
120(define (module-requirement id)
121 (##sys#string->symbol
122 (##sys#string-append (##sys#symbol->string/shared id) "#")))
123
124
125;;; Check for multiple bindings in "let"-style constructs:
126
127(define (check-for-multiple-bindings bindings form loc)
128 ;; assumes correct syntax
129 (let loop ((bs bindings) (seen '()) (warned '()))
130 (cond ((null? bs))
131 ((and (memq (caar bs) seen)
132 (not (memq (caar bs) warned)))
133 (##sys#warn
134 (string-append "variable bound multiple times in " loc " construct")
135 (caar bs)
136 form)
137 (loop (cdr bs) seen (cons (caar bs) warned)))
138 (else (loop (cdr bs) (cons (caar bs) seen) warned)))))
139
140
141;;; Macro environment manipulation:
142(define (macro-subset me0 #!optional parent-env)
143 (let ((se (let loop ((me (##sys#macro-environment)))
144 (if (or (null? me) (eq? me me0))
145 '()
146 (cons (car me) (loop (cdr me)))))))
147 (fixup-macro-environment se parent-env)))
148
149;;XXX clarify what this does!
150(define (fixup-macro-environment se #!optional parent-env)
151 (let ((se2 (if parent-env (##sys#append se parent-env) se)))
152 (for-each ; fixup se
153 (lambda (sdef)
154 (when (pair? (cdr sdef))
155 (set-car!
156 (cdr sdef)
157 (if (null? (cadr sdef))
158 se2
159 (##sys#append (cadr sdef) se2)))))
160 se)
161 se))
162
163
164;;; Low-level hashtable support:
165
166(define hash-symbol
167 (let ((cache-s #f)
168 (cache-h #f)
169 ;; NOTE: All low-level hash tables share the same randomization factor
170 (rand (##core#inline "C_rand" #x10000)))
171 (lambda (s n)
172 (if (eq? s cache-s)
173 (##core#inline "C_fixnum_modulo" cache-h n)
174 (let ((bv (##sys#slot s 1)))
175 (set! cache-s s)
176 (set! cache-h (##core#inline "C_u_i_bytevector_hash" bv 0 (fx- (##sys#size bv) 1) rand))
177 (##core#inline "C_fixnum_modulo" cache-h n))))))
178
179(define (make-hash-table #!optional (size 301))
180 (make-vector size '()))
181
182(define (hash-table-ref ht key)
183 (let loop ((bucket (##sys#slot ht (hash-symbol key (##sys#size ht)))))
184 (and (not (eq? '() bucket))
185 (if (eq? key (##sys#slot (##sys#slot bucket 0) 0))
186 (##sys#slot (##sys#slot bucket 0) 1)
187 (loop (##sys#slot bucket 1))))))
188
189(define (hash-table-set! ht key val)
190 (let* ((k (hash-symbol key (##sys#size ht)))
191 (ib (##sys#slot ht k)))
192 (let loop ((bucket ib))
193 (if (eq? '() bucket)
194 (##sys#setslot ht k (cons (cons key val) ib))
195 (if (eq? key (##sys#slot (##sys#slot bucket 0) 0))
196 (##sys#setslot (##sys#slot bucket 0) 1 val)
197 (loop (##sys#slot bucket 1)))))))
198
199(define (hash-table-update! ht key updtfunc valufunc)
200 (hash-table-set! ht key (updtfunc (or (hash-table-ref ht key) (valufunc)))))
201
202(define (hash-table-for-each p ht)
203 (let ((len (##core#inline "C_block_size" ht)))
204 (do ((i 0 (fx+ i 1)))
205 ((fx>= i len))
206 (##sys#for-each (lambda (bucket) (p (##sys#slot bucket 0) (##sys#slot bucket 1)))
207 (##sys#slot ht i)))))
208
209(define (hash-table-size ht)
210 (let loop ((len (##sys#size ht)) (bkt 0) (size 0))
211 (if (fx= bkt len)
212 size
213 (loop len (fx+ bkt 1) (fx+ size (##sys#length (##sys#slot ht bkt)))))))
214
215;;; Modules that are made available to code by default:
216
217;; WARNING: These import libs must all exist. They cannot be emitted,
218;; because the compiler itself needs them to expand macros!
219;; WARNING: These also need to be built into modules.scm, so that
220;; statically linked programs can eval the imports for these modules.
221
222(define default-imports '(scheme chicken.base chicken.syntax))
223(define default-syntax-imports '(scheme chicken.base chicken.syntax))
224
225) ; chicken.internal