├── .gitignore
├── 0.sf
├── 1.sf
├── 2.sf
├── 3.sf
├── 4.sf
├── 5.sf
├── 6.sf
├── 7.sf
├── LICENSE
├── README.md
├── c.sf
├── c.ss
├── doc
├── ch1.html
├── ch2.html
├── ch3.html
├── ch4.html
├── ch5.html
├── ch6.html
├── ch7.html
├── ch8.html
├── intro.html
├── ioe.html
└── toc.html
├── examples
├── compiled
│ ├── hello.c
│ ├── rk.c
│ ├── s4iof.c
│ ├── s5iof.c
│ ├── siof.c
│ ├── stak.c
│ ├── tak.c
│ ├── tfun.c
│ ├── tlib.c
│ └── tmain.c
├── hello.sf
├── rk.sf
├── s4iof.sf
├── s5iof.sf
├── siof.sf
├── stak.sf
├── tak.sf
├── tfun.sf
├── tlib.sf
└── tmain.sf
├── fixpoint
├── 0.c
├── 1.c
├── 2.c
├── 3.c
├── 4.c
├── 5.c
├── 6.c
├── 7.c
└── c.c
├── int
├── README.md
├── intl.sf
├── intm.sf
├── ints.sf
├── scheme
│ ├── README.md
│ ├── base.sld
│ ├── case-lambda.sld
│ ├── char.sld
│ ├── complex.sld
│ ├── cxr.sld
│ ├── eval.sld
│ ├── file.sld
│ ├── inexact.sld
│ ├── lazy.sld
│ ├── load.sld
│ ├── process-context.sld
│ ├── r5rs-null.sld
│ ├── r5rs.sld
│ ├── read.sld
│ ├── repl.sld
│ ├── time.sld
│ └── write.sld
└── tests
│ ├── README.md
│ ├── intl-tests.s
│ ├── intm-tests.s
│ └── ints-tests.s
├── lib
├── README.md
├── libl.sf
├── libm.sf
├── libs.sf
├── libxs.sf
└── libxxs.sf
├── misc
└── lambda-sunrise.png
└── tests
├── Makefile
├── README
├── helpers.sf
├── tests-a.sf
├── tests-b.sf
├── tests-c.sf
├── tests-d.sf
├── tests-e.sf
├── tests-f.sf
├── tests-g.sf
├── tests-h.sf
├── tests-i.sf
├── tests-l.sf
└── tests-m.sf
/.gitignore:
--------------------------------------------------------------------------------
1 | fixpoint/sfc
2 | /platforms
3 | save
4 |
--------------------------------------------------------------------------------
/5.sf:
--------------------------------------------------------------------------------
1 |
2 | ; #F, part 5: SFC post-CPS passes
3 |
4 | ; Copyright (C) 2007 by Sergei Egorov, All Rights Reserved.
5 | ;
6 | ; This code is derived from the "90 minute Scheme to C compiler" presented at the
7 | ; Montreal Scheme/Lisp User Group on October 20, 2004. The original code was
8 | ; Copyright (C) 2004 by Marc Feeley, All Rights Reserved.
9 |
10 | #fload "0.sf"
11 | #fload "3.sf"
12 | ; also refers to typecheck-prim-ctype
13 |
14 | ;------------------------------------------------------------------------------
15 |
16 | ; CPS conversion
17 |
18 | ; See Ch.8 of @book{
19 | ; author = "Daniel P. Friedman and Christopher T. Haynes and Mitchell Wand"
20 | ; title = "Essentials of programming languages (2nd ed.)"
21 | ; year = "2001"
22 | ; isbn = "0-262-06217-8"
23 | ; publisher = "The MIT Press"
24 | ; }
25 |
26 | (define (cps-convert exp)
27 |
28 | (define (cps-complex exp kexp)
29 | (variant-case exp
30 | [gvarassign-exp (id exp)
31 | (cps-one exp
32 | (lambda (val)
33 | (app-exp kexp
34 | (list (noreturn-exp) (gvarassign-exp id val)))))]
35 | [if-exp (test-exp then-exp else-exp)
36 | (let ([xform
37 | (lambda (kexp)
38 | (cps-one test-exp
39 | (lambda (test)
40 | (if-exp test
41 | (cps then-exp kexp)
42 | (cps else-exp kexp)))))])
43 | (if (var-exp? kexp) ; prevent combinatorial explosion
44 | (xform kexp)
45 | (let ([k (lexical-id 'k)])
46 | (let-exp (list k) (list kexp) (xform (var-exp k))))))]
47 | [primapp-exp (effect prim rands)
48 | (cps-list rands
49 | (lambda (args)
50 | (app-exp kexp
51 | (list (noreturn-exp) (primapp-exp effect prim args)))))]
52 | [fix-exp (ids lams body)
53 | (fix-exp ids (map cps-simple lams)
54 | (cps body kexp))]
55 | [degenerate-let-exp (body)
56 | (cps body kexp)]
57 | [begin-exp (exp1 exp2)
58 | (cps exp1
59 | (lambda-exp (list (lexical-id 'ek) (lexical-id begin-id-symbol))
60 | (cps exp2 kexp)))]
61 | [let-exp (ids rands body)
62 | (cps-list rands
63 | (lambda (vals)
64 | (let-exp ids vals (cps body kexp))))]
65 | [app-exp (rator rands)
66 | (cps-list (cons rator rands)
67 | (lambda (fn+args)
68 | (app-exp (car fn+args) (cons kexp (cdr fn+args)))))]
69 | [letcc-exp (id body)
70 | (let-exp (list id) (list kexp)
71 | (cps body (var-exp id)))]
72 | [withcc-exp (cont-exp exp)
73 | (cps-one cont-exp
74 | (lambda (kexp) (cps exp kexp)))]))
75 |
76 | (define (cps-simple? exp)
77 | (variant-case exp
78 | [var-exp (id) #t]
79 | [gvarassign-exp (id exp)
80 | (cps-simple? exp)]
81 | [if-exp (test-exp then-exp else-exp)
82 | (andapp cps-simple? test-exp then-exp else-exp)]
83 | [primapp-exp (effect prim rands)
84 | (andmap cps-simple? rands)]
85 | [lambda-exp (ids body) #t]
86 | [fix-exp (ids lams body)
87 | (cps-simple? body)]
88 | [degenerate-let-exp (body)
89 | (cps-simple? body)]
90 | [begin-exp (exp1 exp2)
91 | (and (cps-simple? exp1) (cps-simple? exp2))]
92 | [let-exp (ids rands body)
93 | (and (andmap cps-simple? rands) (cps-simple? body))]
94 | [app-exp (rator rands) #f]
95 | [letcc-exp (id body) #f]
96 | [withcc-exp (cont-exp exp) #f]))
97 |
98 | (define (cps-simple exp)
99 | (variant-case exp
100 | [var-exp (id) exp]
101 | [gvarassign-exp (id exp)
102 | (gvarassign-exp id (cps-simple exp))]
103 | [if-exp (test-exp then-exp else-exp)
104 | (if-exp (cps-simple test-exp)
105 | (cps-simple then-exp)
106 | (cps-simple else-exp))]
107 | [primapp-exp (effect prim rands)
108 | (let loop ([rands rands] [ids '()] [vals '()] [exps '()])
109 | (if (null? rands)
110 | (let-exp ids vals
111 | (primapp-exp effect prim (reverse exps)))
112 | (let ([rand (cps-simple (car rands))])
113 | (if (var-exp? rand) ; or literal?
114 | (loop (cdr rands) ids vals (cons rand exps))
115 | (let ([tmp (lexical-id 'tmp)])
116 | (loop (cdr rands) (cons tmp ids) (cons rand vals)
117 | (cons (var-exp tmp) exps)))))))]
118 | [lambda-exp (ids body)
119 | (let ([k (lexical-id 'k)])
120 | (lambda-exp (cons k ids) (cps body (var-exp k))))]
121 | [fix-exp (ids lams body)
122 | (fix-exp ids (map cps-simple lams) (cps-simple body))]
123 | [degenerate-let-exp (body)
124 | (cps-simple body)]
125 | [begin-exp (exp1 exp2)
126 | (begin-exp (cps-simple exp1) (cps-simple exp2))]
127 | [let-exp (ids rands body)
128 | (let-exp ids (map cps-simple rands) (cps-simple body))]))
129 |
130 | (define (cps exp kexp)
131 | (if (cps-simple? exp)
132 | (app-exp kexp (list (noreturn-exp) (cps-simple exp)))
133 | (cps-complex exp kexp)))
134 |
135 | (define (cps-list exps inner)
136 | (cond
137 | [(null? exps) (inner '())]
138 | [(cps-simple? (car exps))
139 | (cps-list (cdr exps) ;=>
140 | (lambda (new-exps)
141 | (inner (cons (cps-simple (car exps)) new-exps))))]
142 | [else
143 | (let ([r (lexical-id 'r)])
144 | (cps (car exps)
145 | (lambda-exp (list (lexical-id 'ek) r)
146 | (cps-list (cdr exps)
147 | (lambda (new-exps)
148 | (inner (cons (var-exp r) new-exps)))))))]))
149 |
150 | (define (cps-one exp inner)
151 | (if (cps-simple? exp)
152 | (inner (cps-simple exp))
153 | (let ([r (lexical-id 'r)])
154 | (cps exp
155 | (lambda-exp (list (lexical-id 'ek) r)
156 | (inner (var-exp r)))))))
157 |
158 | (define (noreturn-exp)
159 | (primapp-exp (no-effect) "ktrap()" '()))
160 |
161 | (cps exp
162 | (let ([r (lexical-id 'r)])
163 | (lambda-exp (list (lexical-id 'ek) r)
164 | (halt-exp (var-exp r))))))
165 |
166 |
167 | ;------------------------------------------------------------------------------
168 |
169 | ; Lambda lifting
170 |
171 | ; See @inproceedings{
172 | ; key = "Cli:94"
173 | ; author = "William D. Clinger and Lars Thomas Hansen"
174 | ; title = "Lambda, the ultimate label, or a simple optimizing compiler for
175 | ; Scheme"
176 | ; booktitle = "Proceedings of the 1994 ACM conference on LISP and Functional
177 | ; Programming"
178 | ; year = "1994"
179 | ; pages = "128-139"
180 | ; url = "http://www.acm.org/pubs/citations/proceedings/lfp/182409/p128-clinger/"
181 | ; }
182 | ; and @article{
183 | ; key = "danvy-schultz:tcs2000"
184 | ; author = "Olivier Danvy and Ulrik Pagh Schultz"
185 | ; title = "Lambda-Dropping: Transforming Recursive Equations into Programs
186 | ; with Block Structure"
187 | ; journal = "Theoretical Computer Science"
188 | ; volume = "Volume 248/1-2"
189 | ; month = "November"
190 | ; year = "2000"
191 | ; url = "http://www.daimi.au.dk/~ups/papers/tcs00.ps.gz"
192 | ; url = "http://www.daimi.au.dk/~ups/papers/tcs00.pdf"
193 | ; }
194 |
195 | (define (lambda-lift exp)
196 |
197 | (define top-ids '())
198 | (define top-lams '())
199 |
200 | (define (extra-vars id* lam*) ; => vars*
201 | (define (called-lam-indices lamfvs)
202 | (map (lambda (id) (posq id id*))
203 | (intersectionq lamfvs id*)))
204 | (define (lam-free-outs lamfvs)
205 | (setdiffq lamfvs id*))
206 | (define (make-step-fn lamcalls lamfovs)
207 | (lambda (av) ; av -> a
208 | (reduce-left (lambda (i a) (unionq a (vector-ref av i)))
209 | lamfovs lamcalls)))
210 | (let ([lamfvs* (map exp->free-lexvars lam*)] [n (length id*)])
211 | (let ([lamcalls* (map called-lam-indices lamfvs*)]
212 | [lamfovs* (map lam-free-outs lamfvs*)])
213 | (let ([av (make-vector n '())]
214 | [fv (list->vector (map make-step-fn lamcalls* lamfovs*))])
215 | (vector->list ; => vars*
216 | (let loop ([i 0] [wrap? #f])
217 | (if (= i n) (if wrap? (loop 0 #f) av)
218 | (let ([next-a ((vector-ref fv i) av)] [prev-a (vector-ref av i)])
219 | (if (seteq? next-a prev-a) (loop (+ i 1) wrap?)
220 | (begin (vector-set! av i next-a) (loop (+ i 1) #t)))))))))))
221 |
222 | (define (curry-lam lam xvars tid)
223 | (curry-exp tid ; no xvars? don't eta-reduce!
224 | (map rename-id (lambda-exp->ids lam))
225 | (map var-exp xvars)))
226 |
227 | (define (lift-lam lam xvars id* lam* xvars* tid*)
228 | (variant-case lam
229 | [lambda-exp (ids body)
230 | (lambda-exp (append ids xvars)
231 | (let-exp id* (map curry-lam lam* xvars* tid*)
232 | (lift body)))]))
233 |
234 | (define (lift-lams id* lam* body)
235 | (let ([tid* (map (lambda (id) (label-id (id->symbol id))) id*)]
236 | [xvars* (extra-vars id* lam*)])
237 | (define (float-lam lam xvars tid)
238 | (let ([tlam (lift-lam lam xvars id* lam* xvars* tid*)])
239 | (set! top-ids (cons tid top-ids))
240 | (set! top-lams (cons tlam top-lams))))
241 | (for-each float-lam lam* xvars* tid*)
242 | (let-exp id* (map curry-lam lam* xvars* tid*)
243 | (lift body))))
244 |
245 | (define (lift exp)
246 | (variant-case exp
247 | [var-exp (id) exp]
248 | [gvarassign-exp (id exp)
249 | (gvarassign-exp id (lift exp))]
250 | [if-exp (test-exp then-exp else-exp)
251 | (if-exp (lift test-exp) (lift then-exp) (lift else-exp))]
252 | [primapp-exp (effect prim rands)
253 | (primapp-exp effect prim (map lift rands))]
254 | [let-exp (ids rands body)
255 | (let-exp ids (map lift rands) (lift body))]
256 | [app-exp (rator rands)
257 | (app-exp (lift rator) (map lift rands))]
258 | [lambda-exp (ids body)
259 | (let ([l (lexical-id 'l)])
260 | (lift-lams (list l) (list exp) (var-exp l)))]
261 | [fix-exp (ids lams body)
262 | (lift-lams ids lams body)]))
263 |
264 | (let ([top-body (lift exp)])
265 | (fix-exp top-ids top-lams
266 | top-body)))
267 |
268 |
269 | ;------------------------------------------------------------------------------
270 |
271 | ; Values unboxing
272 |
273 | (define (unbox-values exp)
274 |
275 | (define (unbox-ctype-test test-exp then-exp k ek)
276 | (or (and (primapp-exp? test-exp)
277 | (let ([rands (primapp-exp->rands test-exp)])
278 | (and (= (length rands) 1)
279 | (let ([rand (car rands)])
280 | (and (var-exp? rand)
281 | (let ([id (var-exp->id rand)])
282 | (let ([ctype (var-unboxed-ctype-in-exp id then-exp)])
283 | (and ctype (not (member ctype '("obj" "void")))
284 | (> (var-reference-count id then-exp) 1)
285 | (equal? ctype (typecheck-prim-ctype (primapp-exp->prim test-exp)))
286 | (k id ctype)))))))))
287 | (ek)))
288 |
289 | (define (var-unboxed-ctype id body rand)
290 | (let ([b-ctype (var-unboxed-ctype-in-exp id body)])
291 | (and b-ctype (not (member b-ctype '("obj" "void")))
292 | (let ([r-ctype (exp-ctype rand '())]) ; look for obvious cases
293 | (and r-ctype (not (member r-ctype '("obj" "void")))
294 | (string=? b-ctype r-ctype)
295 | r-ctype)))))
296 |
297 |
298 | (define (unbox-vals exp substs)
299 |
300 | (define (uv exp)
301 | (variant-case exp
302 | [var-exp (id)
303 | (cond [(assq id substs) => cdr] [else exp])]
304 | [gvarassign-exp (id exp)
305 | (gvarassign-exp id (uv exp))]
306 | [if-exp (test-exp then-exp else-exp)
307 | (unbox-ctype-test test-exp then-exp ;=>>
308 | (lambda (id ctype)
309 | (if-exp
310 | (uv test-exp)
311 | (let ([cid (cvar-id (id->symbol id) ctype)])
312 | (let-exp (list cid) (list (var-exp id))
313 | (unbox-vals then-exp
314 | (cons (cons id (var-exp cid)) substs))))
315 | (uv else-exp)))
316 | (lambda ()
317 | (if-exp (uv test-exp) (uv then-exp) (uv else-exp))))]
318 | [degenerate-let-exp (body)
319 | (uv body)]
320 | [let-exp (ids rands body)
321 | (let loop ([in-ids ids] [in-rands (map uv rands)]
322 | [out-ids '()] [out-rands '()] [substs substs])
323 | (if (null? in-ids)
324 | (let-exp out-ids out-rands (unbox-vals body substs))
325 | (let ([id (car in-ids)] [rand (car in-rands)])
326 | (cond [(var-unboxed-ctype id body rand) =>
327 | (lambda (ctype)
328 | (let ([cid (cvar-id (id->symbol id) ctype)])
329 | (loop (cdr in-ids) (cdr in-rands)
330 | (cons cid out-ids) (cons rand out-rands)
331 | (cons (cons id (var-exp cid)) substs))))]
332 | [else (loop (cdr in-ids) (cdr in-rands)
333 | (cons id out-ids) (cons rand out-rands) substs)]))))]
334 | [primapp-exp (effect prim rands)
335 | (primapp-exp effect prim (map uv rands))]
336 | [app-exp (rator rands)
337 | (app-exp (uv rator) (map uv rands))]
338 | [fix-exp (ids lams body)
339 | (fix-exp ids (map uv lams) (uv body))]
340 | [lambda-exp (ids body)
341 | (let loop ([in-ids ids] [out-ids '()] [out-rands '()] [substs substs])
342 | (if (null? in-ids)
343 | (if (null? out-ids)
344 | (lambda-exp ids (uv body))
345 | (lambda-exp ids
346 | (let-exp out-ids out-rands (unbox-vals body substs))))
347 | (let ([id (car in-ids)])
348 | (cond [(and (> (var-reference-count id body) 1)
349 | (var-unboxed-ctype-in-exp id body)) =>
350 | (lambda (ctype)
351 | (let ([cid (cvar-id (id->symbol id) ctype)])
352 | (loop (cdr in-ids) (cons cid out-ids)
353 | (cons (var-exp id) out-rands)
354 | (cons (cons id (var-exp cid)) substs))))]
355 | [else (loop (cdr in-ids) out-ids out-rands substs)]))))]))
356 |
357 | (uv exp))
358 |
359 | (unbox-vals exp '()))
360 |
361 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2019, false-schemers
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/c.ss:
--------------------------------------------------------------------------------
1 |
2 | ; SFC (#F Scheme to C compiler) -- esl
3 |
4 | ; Chez bootstrap code
5 |
6 | (define construct-name
7 | (lambda (template-id . args)
8 | (datum->syntax-object template-id
9 | (string->symbol
10 | (apply string-append
11 | (map (lambda (x)
12 | (if (string? x)
13 | x
14 | (symbol->string (syntax-object->datum x))))
15 | args))))))
16 |
17 | (define-syntax define-variant
18 | (lambda (x)
19 | (syntax-case x ()
20 | [(_ name (field0 ...))
21 | (with-syntax
22 | ([constructor (construct-name (syntax name) (syntax name))]
23 | [predicate (construct-name (syntax name) (syntax name) "?")]
24 | [(reader ...)
25 | (map (lambda (field)
26 | (construct-name (syntax name) (syntax name) "->" field))
27 | (syntax (field0 ...)))]
28 | [count (length (syntax (name field0 ...)))])
29 | (with-syntax
30 | ([(index ...)
31 | (let f ([i 1])
32 | (if (= i (syntax-object->datum (syntax count)))
33 | '()
34 | (cons i (f (1+ i)))))])
35 | (syntax
36 | (begin
37 | (define constructor
38 | (lambda (field0 ...)
39 | (vector 'name field0 ...)))
40 | (define predicate
41 | (lambda (object)
42 | (and (vector? object)
43 | (= (vector-length object) count)
44 | (eq? (vector-ref object 0) 'name))))
45 | (define reader
46 | (lambda (object)
47 | (vector-ref object index)))
48 | ...))))])))
49 |
50 | (define-syntax variant-case
51 | (lambda (x)
52 | (syntax-case x (else)
53 | [(_ var) (syntax (error 'variant-case "no clause matches ~s" var))]
54 | [(_ var (else exp1 exp2 ...)) (syntax (begin exp1 exp2 ...))]
55 | [(_ exp clause ...)
56 | (not (identifier? (syntax exp)))
57 | (syntax (let ([var exp]) (_ var clause ...)))]
58 | [(_ var (name (field ...) exp1 exp2 ...) clause ...)
59 | (with-syntax
60 | ([predicate (construct-name (syntax name) (syntax name) "?")]
61 | [(reader ...)
62 | (map (lambda (fld)
63 | (construct-name (syntax name) (syntax name) "->" fld))
64 | (syntax (field ...)))])
65 | (syntax
66 | (if (predicate var)
67 | (let ([field (reader var)] ...) exp1 exp2 ...)
68 | (_ var clause ...))))])))
69 |
70 |
71 | (define-syntax define-inline
72 | (syntax-rules ()
73 | [(_ (id . args) . body) (define (id . args) . body)]
74 | [(_ id val) (define id val)]))
75 |
76 | (define-syntax define-integrable
77 | (syntax-rules ()
78 | [(_ (id . args) . body) (define (id . args) . body)]
79 | [(_ id val) (define id val)]))
80 |
81 |
82 | (define (argv->list argv) argv)
83 |
84 | (define current-error-port current-output-port)
85 |
86 | (define eof-object
87 | (let ([eof (read-char (open-input-string ""))])
88 | (lambda () eof)))
89 |
90 | (define (sfc . args)
91 | (main (cons "sfc-bootstrap" args)))
92 |
93 | (for-each load '("1.sf" "2.sf" "3.sf" "4.sf" "5.sf" "6.sf" "7.sf" "c.sf"))
94 |
95 | (printf "; now you may run~%; ~s~%; to generate .c files~%"
96 | '(sfc "-v" "0.sf" "1.sf" "2.sf" "3.sf" "4.sf" "5.sf" "6.sf" "7.sf" "c.sf"))
97 |
--------------------------------------------------------------------------------
/doc/ch1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 1. Syntax and semantics
6 |
29 |
36 |
37 |
38 |
39 |
49 |
50 |
51 |
52 |
53 |
1. Syntax and semantics
54 |
55 |
1.1. Syntax
56 |
57 |
Lorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam
58 | eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem.
59 |
60 |
1.2. Semantics
61 |
62 |
Lorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam
63 | eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem.
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/doc/ch2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 2. Notation and terminology
6 |
29 |
36 |
37 |
38 |
39 |
50 |
51 |
52 |
53 |
54 |
2. Notation and terminology
55 |
56 |
2.1. Entry format
57 |
58 |
The chapters describing bindings in the standard environment,
59 | system interface, and command-line interface are organized into
60 | entries. Each entry begins with a header line that usually includes
61 | the name of the form or a feature in monospace font within
62 | a template for its use. The names of the arguments or syntactic
63 | components of the form are italicized. A notation such as
64 |
65 |
thing1 …
66 |
67 |
indicates zero or more occurences of thing. Thus
68 |
69 |
thing1 thing2 …
70 |
71 |
indicates at least one thing. At the right of the header
72 | line one of the following categories will appear:
73 |
74 |
75 | | syntax |
76 | | procedure |
77 | | standard prelude typedef |
78 | | standard prelude #define |
79 | | runtime host variable |
80 | | command line utility |
81 |
82 |
83 |
An entry of a “syntax” category describes a syntactic
84 | class of forms, usually identified by a keyword. The header line for
85 | a syntactic class gives a template for the use of the form, with the
86 | components of the form designated by syntactic variables. Syntactic
87 | variables should be understood to denote other forms.
88 |
89 |
If the category of an entry is “procedure”, then the
90 | entry describes a procedure, and the header line gives a template
91 | for a call to the procedure. The italicized names in the template
92 | denote the arguments to the procedure.
93 |
94 |
95 |
96 |
2.2. Evaluation examples
97 |
98 |
...
99 |
100 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/doc/ch4.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/false-schemers/sharpF/5363370f11dcebd2c6cc75b79ac0476f78cbeb48/doc/ch4.html
--------------------------------------------------------------------------------
/doc/ch5.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 5. Definitions
6 |
29 |
36 |
37 |
38 |
39 |
51 |
52 |
53 |
54 |
5. Definitions
55 |
56 |
Modern Schemes feature a complicated mechanism of assembling a set of top-level or
57 | local bindings by transforming a program or a body
58 | into a sequence of global assignments or mutually recursive bindings. This transformation
59 | is too complex to be performed by a syntax-rules based macroexpander, so a minimal
60 | set of constructs for scopes and definitions is provided in the core language.
61 |
62 |
63 | (define variable expression) | syntax |
64 | (define-syntax keyword datum) | syntax |
65 | (begin definition …) | syntax |
66 |
67 |
68 |
Definitions are valid in some, but not all, contexts where expressions are allowed. They are valid
69 | only at the top level of a compilation unit and at the beginning of a syntax-lambda form.
70 | A definition is not an expression and has no value.
71 |
72 |
5.1. Top level definitions
73 |
74 |
At the top level of a compilation unit, a definition
75 |
76 | (define variable expression)
77 |
78 |
has essentially the same effect as the assignment expression
79 |
80 | (set! variable expression)
81 |
82 |
if variable is bound in the compilation unit. If variable
83 | is not bound, then the definition will bind variable to a new location
84 | before performing the assignment. In #F, all compilation units share a single
85 | global namespace, so variables bound at the top-level in one unit are visible in
86 | all other units. It is an error to bind a variable in more than one compilation unit
87 | of the program. It is also an error to reference a variable which is not bound in
88 | any compilation units constituting a program.
89 |
90 |
During the macroexpansion of the program a top level definition of the form
91 |
92 | (define-syntax keyword datum)
93 |
94 |
extends the top-level syntactic environment by binding keyword
95 | (an identifier) to the result of the expansion of datum in the
96 | original syntactic environment.
97 |
98 |
99 |
5.2. Internal definitions
100 |
101 |
Definitions may Adjacent definitions at the beginning of a syntax-lambda ...
102 |
103 |
Note: All traditional forms with implicit body are constructed as macros which
104 | use syntax-lambda to scope definitions. Traditional forms are available in base library.
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/doc/ch8.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 8. Writing primitives in C
6 |
29 |
36 |
37 |
38 |
39 |
56 |
57 |
58 |
59 |
60 |
8. Writing primitives in C
61 |
62 |
The #F compiler can be seen as a macroassembler which pieces together and
63 | interconnects fragments of C code. These fragments originate as inline C
64 | expressions in #F code, in the same way some C compilers allow embedding
65 | fragments of assembly code. While inline C expressions can appear anywhere
66 | a regular expression appears, they usually are confined to library code. In
67 | this regard
68 |
69 |
8.1. Inline C expressions
70 |
71 |
An inline C expressions consists of a keyword identifying the expression,
72 | followed by a code template and zero or more argument expressions.
73 | Keywords encode the information of side effects and allocation performed
74 | by the code in the template, allowing the compiler to classify the resulting
75 | expressions for code optimization phases.
76 |
77 |
78 |
79 |
80 | (%prim code expression1 …) | syntax |
81 | (%prim* code expression1 …) | syntax |
82 | (%prim? code expression1 …) | syntax |
83 | (%prim! code expression1 …) | syntax |
84 | (%prim?! code expression1 …) | syntax |
85 | (%prim*? code expression1 …) | syntax |
86 | (%prim*! code expression1 …) | syntax |
87 | (%prim*?! code expression1 …) | syntax |
88 |
89 |
90 |
A code template is either a literal string enclosed in double quotes or a
91 | parenthesized sequence of code templates. A parenthesized sequence is equivalent
92 | to a string obtained by the concatenation of its content strings; it is supported
93 | to simplify generation of primitive forms by macroexpansion.
94 |
95 |
96 |
Keywords of inline C expressions encode a combination of three properties:
97 |
98 |
99 | * | allocates from garbage-collectible heap |
100 | ! | has side effects other than allocation |
101 | ? | observes side effects |
102 |
103 |
104 |
In a mutable vector library, make-vector could serve as a good example
105 | of * primitive (allocates from the heap), vector-set! as
106 | ! primitive (produces side effects thet might affect the results
107 | and/or effects of other expressions), and vector-ref as ?
108 | primitive (does not allocate or produce side effects, but its result is affected
109 | by other expressions that may modify the vector). Primitive code can
110 | exibit any combination of these properties, so there are eight keywords
111 | to cover all possible combinations.
112 |
113 |
#F compiler classifies primitives into categories based on their
114 | referential transparency, ability to cause garbage collection, and
115 | suitability for dead code elimination.
116 |
117 |
The %prim keywords marks the referentially transparent code;
118 | referentially transparent (RT) expressions always produce the same value
119 | given the same arguments, allowing for many compiler optimizations.
120 | All other keywords mark the code as not referentially transparent:
121 |
122 |
123 | RT | %prim |
124 | not RT | %prim* %prim? %prim! %prim?! %prim*? %prim*! %prim*?! |
125 |
126 |
127 |
Primitives that never allocate from garbage-collected heap do not
128 | trigger garbage collection (GC), opening possibilities for some
129 | interesting compiler optimizations (#F compiler can use C calling
130 | mechanism for certain GC-safe procedures). Primitives that have no
131 | side effects and which values are not used are subject to dead code
132 | elimination (DCE). The keywords for inline C expressions are
133 | split between these categories as follows:
134 |
135 |
136 | | DCE safe | DCE unsafe |
137 | GC safe | %prim %prim? | %prim! %prim?! |
138 | GC unsafe | %prim* %prim*? | %prim*! %prim*?! |
139 |
140 |
141 |
Note: inline C code that reads from files should
142 | be tagged by %prim?! keyword because such code affects the file
143 | read pointer and depends on the effects of previous reads.
144 |
145 |
146 |
156 |
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/doc/intro.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Introduction
6 |
29 |
36 |
37 |
38 |
39 |
49 |
50 |
51 |
52 |
53 |
introduction
54 |
55 |
#F (False Scheme) is a minimalist Scheme implementation tailored to
56 | the needs of practical programmers comfortable with both Scheme and C and
57 | willing to spend some additional effort in order to build a system that
58 | fits their needs better than any existing Scheme with an FFI interface.
59 | The implementation is based on a (reduced)Scheme-to-C compiler with no
60 | knowledge of any data types and a stripped down set of syntactic forms,
61 | that includes a few basic expression types, a flexible mechanism for
62 | extending the language by combining fragments of C code, and an extended
63 | version of R5RS macro system which doubles as a compiler
64 | backend.
65 |
66 |
Backround
67 |
Henry Baker in his Critique of DIN Kernel Lisp Definition Version 1.2
68 | [1]
69 | laid down the desiderata for a Kernel language:
70 |
71 |
72 | Presumably, a kernel language is a minimal language on top
73 | of which a larger language can be built. Since its primary function
74 | is being an implementation language for function libraries and a target language
75 | for macros, a Kernel language need not be particularly “user-friendly”
76 | or provide a lot of flexibility in its interface. Although it is desirable,
77 | a Kernel language does not have to be a strict subset of the full language,
78 | since some of its features may not be visible in the full language.
79 | A Kernel language should be simpler and more efficient to implement than
80 | the full language, however, to avoid an abstraction inversion,
81 | in which a simpler notion is defined in terms of more complex notions.
82 |
83 |
Later, he adds:
84 |
85 |
86 | Preserving a small definition for DKLisp requires that the standard
87 | ruthlessly eliminate non-primitive notions to focus on simple, efficient,
88 | modular primitives from which the rest of a Lisp system can be easily and
89 | efficiently constructed. In other words, DKLisp primitives must be chosen
90 | not for their ability keep a user program small, but for their ability to
91 | keep an implementation small and fast.
92 |
93 |
Baker's 15-year-old program echoes the central design principle of Scheme
94 | (“removing the weaknesses and restrictions…”) but goes
95 | farther, arguing for a smaller language with greater emphasis on implementation
96 | efficiency and language cleanliness. This approach harmonizes with the modern
97 | trend toward smaller domain-specific languages (DSLs) which do one specific thing
98 | but do it well. Building a DSL atop of a kernel language allows the designer
99 | to concentrate on what is needed for the task at hand, eliminating
100 | excess baggage.
101 |
102 |
Libraries and FFIs
103 |
104 |
In recent years it became more and more obvious that in order to be
105 | able to construct a large system around a simple kernel, the kernel has
106 | to provide an access to low-level system interfaces and libraries. It is
107 | no longer reasonable to expect that every new language will get its own
108 | implementation of regular expressions, an XML parser, a PDF writer, even
109 | though all of them can be implemented from scratch on top of a minimal
110 | number/string/list set of primitives. The situation is even worse when
111 | it comes to system interfaces (interprocess comunications, networking
112 | etc.) — they can only be built on top of a foreign
113 | function interface (FFI).
114 |
115 |
FFIs, as they are implemented in traditional Lisp/Scheme systems,
116 | rely on a complex set of data conversion rules, dynamic code generation
117 | and other platform-specific methods of getting access to the underlying application
118 | binary interface (ABI). Although a lot of effort has been spent on
119 | hiding the internal complexity of the interface from the user and handling
120 | platform-dependent calling conventions, FFIs remain fragile because many
121 | programmatic interfaces are are portable only on a source code level
122 | (and thus should be qualified as APIs, not ABIs).
123 |
124 |
What an ideal FFI can look like is demonstrated by C++. All that
125 | is needed to call C functions from C++ is to wrap their prototypes in
126 | extern "C" {} to prevent name mangling. The
127 | resulting C++ program is (almost) as portable as if it were written in
128 | C directly.
129 |
130 |
#F, being built around a Scheme-to-C compiler, is able to provide an
131 | FFI of comparable simplicity by allowing the programmer to write C code
132 | fragments to be included verbatim into the output code. As an extreme example
133 | of this practice, here is a complete #F source code for the ubiquitous
134 | “Hello World” program:
135 |
136 |
137 | (%include <stdio.h>)
138 |
139 | (define main
140 | (lambda (argv)
141 | (%prim! "void(printf(\"Hello, World!\\n\"))")))
142 |
143 |
144 |
Note: This “Scheme” program does
145 | not use any Scheme data types, so none have to be defined. The resulting
146 | C file is 7KB long and it includes a complete run-time system
147 | needed to execute the code.
148 |
149 |
Portability
150 |
151 |
You are in a maze of twisty little #ifdefs, all different.
152 | — Anon.
153 |
154 |
166 |
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/doc/ioe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Index of Entries
6 |
26 |
33 |
34 |
35 |
36 |
37 |
38 |
index of entries
39 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/doc/toc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Table of Contents
6 |
26 |
33 |
34 |
35 |
36 |
37 |
38 |
table of contents
39 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/examples/compiled/hello.c:
--------------------------------------------------------------------------------
1 | /* hello.sf */
2 | /* Generated by #F $Id$ */
3 | #ifdef PROFILE
4 | #define host host_module_hello
5 | #endif
6 | #define MODULE module_hello
7 | #define LOAD()
8 |
9 | /* standard includes */
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | /* standard definitions */
16 |
17 | typedef ptrdiff_t obj; /* pointers are this size, lower bit zero */
18 | typedef ptrdiff_t cxoint_t; /* same thing, used as integer */
19 | typedef struct { /* type descriptor */
20 | const char *tname; /* name (debug) */
21 | void (*free)(void*); /* deallocator */
22 | } cxtype_t;
23 |
24 | #define notobjptr(o) (((char*)(o) - (char*)cxg_heap) & cxg_hmask)
25 | #define isobjptr(o) (!notobjptr(o))
26 | #define notaptr(o) ((o) & 1)
27 | #define isaptr(o) (!notaptr(o))
28 |
29 | #define obj_from_obj(o) (o)
30 | #define obj_from_objptr(p) ((obj)(p))
31 | #define obj_from_size(n) (((cxoint_t)(n) << 1) | 1)
32 |
33 | #define objptr_from_objptr(p) (p)
34 | #define objptr_from_obj(o) ((obj*)(o))
35 |
36 | #define size_from_obj(o) ((int)((o) >> 1))
37 |
38 | #define obj_from_case(n) obj_from_objptr(cases+(n))
39 | #define case_from_obj(o) (objptr_from_obj(o)-cases)
40 | #define obj_from_ktrap() obj_from_size(0x5D56F806)
41 | #define obj_from_void(v) ((void)(v), obj_from_size(0x6F56DF77))
42 |
43 | #define bool_from_obj(o) (o)
44 | #define bool_from_bool(b) (b)
45 | #define bool_from_size(s) (s)
46 |
47 | #define void_from_void(v) (void)(v)
48 | #define void_from_obj(o) (void)(o)
49 |
50 | #define rreserve(m) if (r + (m) >= cxg_rend) r = cxm_rgc(r, m)
51 | #define hpushptr(p, pt, l) (hreserve(2, l), *--hp = (obj)(p), *--hp = (obj)(pt), (obj)(hp+1))
52 | #define hbsz(s) ((s) + 1) /* 1 extra word to store block size */
53 | #define hreserve(n, l) ((hp < cxg_heap + (n)) ? hp = cxm_hgc(r, r+(l), hp, n) : hp)
54 | #define hendblk(n) (*--hp = obj_from_size(n), (obj)(hp+1))
55 | #define hblklen(p) size_from_obj(((obj*)(p))[-1])
56 | #define hblkref(p, i) (((obj*)(p))[i])
57 |
58 | typedef obj (*cxhost_t)(obj);
59 | typedef struct cxroot_tag {
60 | int globc; obj **globv;
61 | struct cxroot_tag *next;
62 | } cxroot_t;
63 |
64 | extern obj *cxg_heap;
65 | extern obj *cxg_hp;
66 | extern cxoint_t cxg_hmask;
67 | extern cxroot_t *cxg_rootp;
68 | extern obj *cxm_rgc(obj *regs, size_t needs);
69 | extern obj *cxm_hgc(obj *regs, obj *regp, obj *hp, size_t needs);
70 | extern obj *cxg_regs, *cxg_rend;
71 | extern void cxm_check(int x, char *msg);
72 | extern void *cxm_cknull(void *p, char *msg);
73 | extern int cxg_rc;
74 | extern char **cxg_argv;
75 |
76 | /* cx globals */
77 | obj cx_main; /* main */
78 |
79 | /* gc roots */
80 | static cxroot_t root = { 0, NULL, NULL };
81 |
82 | /* entry points */
83 | static obj host(obj);
84 | static obj cases[2] = {
85 | (obj)host, (obj)host,
86 | };
87 |
88 | /* host procedure */
89 | #define MAX_HOSTREGS 14
90 | static obj host(obj pc)
91 | {
92 | register obj *r = cxg_regs;
93 | register obj *hp = cxg_hp;
94 | register int rc = cxg_rc;
95 | rreserve(MAX_HOSTREGS);
96 | jump:
97 | switch (case_from_obj(pc)) {
98 |
99 | case 0: /* load module */
100 | { static obj c[] = { obj_from_case(1) }; cx_main = (obj)c; }
101 | r[0] = obj_from_void(0);
102 | r[1+0] = r[0];
103 | pc = 0; /* exit from module init */
104 | r[1+1] = r[0];
105 | r += 1; /* shift reg wnd */
106 | rc = 2;
107 | goto jump;
108 |
109 | case 1: /* main k argv */
110 | assert(rc == 3);
111 | r += 1; /* shift reg. wnd */
112 | /* k argv */
113 | r[2+0] = r[0];
114 | pc = objptr_from_obj(r[2+0])[0];
115 | r[2+1] = obj_from_ktrap();
116 | r[2+2] = obj_from_void(printf("Hello, World!\n"));
117 | r += 2; /* shift reg wnd */
118 | rreserve(MAX_HOSTREGS);
119 | rc = 3;
120 | goto jump;
121 |
122 | default: /* inter-host call */
123 | cxg_hp = hp;
124 | cxm_rgc(r, MAX_HOSTREGS);
125 | cxg_rc = rc;
126 | return pc;
127 | }
128 | }
129 |
130 | /* module load */
131 | void MODULE(void)
132 | {
133 | obj pc;
134 | if (!root.next) {
135 | root.next = cxg_rootp;
136 | cxg_rootp = &root;
137 | LOAD();
138 | pc = obj_from_case(0);
139 | cxg_rc = 0;
140 | while (pc) pc = (*(cxhost_t*)pc)(pc);
141 | assert(cxg_rc == 2);
142 | }
143 | }
144 |
145 | /* basic runtime */
146 | #define HEAP_SIZE 131072 /* 2^17 */
147 | #define REGS_SIZE 4092
148 |
149 | obj *cxg_heap = NULL;
150 | cxoint_t cxg_hmask = 0;
151 | obj *cxg_hp = NULL;
152 | static cxroot_t cxg_root = { 0, NULL, NULL };
153 | cxroot_t *cxg_rootp = &cxg_root;
154 | obj *cxg_regs = NULL, *cxg_rend = NULL;
155 | int cxg_rc = 0;
156 | char **cxg_argv = NULL;
157 |
158 | static obj *cxg_heap2 = NULL;
159 | static size_t cxg_hsize = 0;
160 | static cxoint_t cxg_hmask2 = 0;
161 | static int cxg_gccount = 0, cxg_bumpcount = 0;
162 |
163 | static obj *toheap2(obj* p, obj *hp, obj *h1, cxoint_t m1, obj *h2, cxoint_t m2)
164 | {
165 | obj o = *p, *op, fo, *fop;
166 | if (((char*)(o) - (char*)h1) & m1) return hp;
167 | fo = (op = objptr_from_obj(o))[-1]; assert(fo);
168 | if (notaptr(fo)) {
169 | fop = op + size_from_obj(fo); while (fop >= op) *--hp = *--fop;
170 | *p = *fop = obj_from_objptr(hp+1);
171 | } else if (((char*)(fo) - (char*)h2) & m2) {
172 | *--hp = *op--; *--hp = *op;
173 | *p = *op = obj_from_objptr(hp+1);
174 | } else *p = fo;
175 | return hp;
176 | }
177 |
178 | static void finalize(obj *hp1, obj *he1, obj *h2, cxoint_t m2)
179 | {
180 | while (hp1 < he1) {
181 | obj fo = *hp1++; assert(fo);
182 | if (notaptr(fo)) hp1 += size_from_obj(fo);
183 | else if (((char*)(fo) - (char*)h2) & m2) ((cxtype_t*)fo)->free((void*)*hp1++);
184 | else if (notaptr(fo = objptr_from_obj(fo)[-1])) hp1 += size_from_obj(fo);
185 | else ++hp1;
186 | } assert(hp1 == he1);
187 | }
188 |
189 | static obj *relocate(cxroot_t *pr, obj *regs, obj *regp,
190 | obj *he2, obj *he1, obj *hp, obj *h1, cxoint_t m1, obj *h2, cxoint_t m2)
191 | {
192 | obj *p, *hp1 = hp; hp = he2;
193 | for (p = regs; p < regp; ++p) hp = toheap2(p, hp, h1, m1, h2, m2);
194 | for (; pr; pr = pr->next) {
195 | obj **pp = pr->globv; int c = pr->globc;
196 | while (c-- > 0) hp = toheap2(*pp++, hp, h1, m1, h2, m2);
197 | }
198 | for (p = he2; p > hp; --p) hp = toheap2(p-1, hp, h1, m1, h2, m2);
199 | if (he1) finalize(hp1, he1, h2, m2);
200 | return hp;
201 | }
202 |
203 | obj *cxm_hgc(obj *regs, obj *regp, obj *hp, size_t needs)
204 | {
205 | obj *h1 = cxg_heap, *h2 = cxg_heap2; cxoint_t m1 = cxg_hmask, m2 = cxg_hmask2;
206 | size_t hs = cxg_hsize; cxroot_t *pr = cxg_rootp;
207 |
208 | obj *h = h1, *he1 = h1 + hs, *he2 = h2 + hs;
209 | ++cxg_gccount;
210 | if (h1) hp = relocate(pr, regs, regp, he2, he1, hp, h1, m1, h2, m2),
211 | needs += (h2 + hs - hp)*2; /* make heap half empty */
212 | else hp = h2 + hs;
213 | if (hs < needs) {
214 | size_t s = HEAP_SIZE; while (s < needs) s *= 2;
215 | m2 = 1 | ~(s*sizeof(obj)-1);
216 | if (!(h = realloc(h1, s*sizeof(obj)))) { perror("alloc[h]"); exit(2); }
217 | h1 = h2; h2 = h; he2 = h2 + s; he1 = 0; /* no finalize flag */
218 | if (h1) hp = relocate(pr, regs, regp, he2, he1, hp, h1, m1, h2, m2);
219 | else hp = h2 + s;
220 | if (!(h = realloc(h1, s*sizeof(obj)))) { perror("alloc[h]"); exit(2); }
221 | hs = s; m1 = m2; ++cxg_bumpcount;
222 | }
223 | h1 = h2; h2 = h;
224 |
225 | cxg_heap = h1; cxg_hmask = m1; cxg_heap2 = h2; cxg_hmask2 = m2;
226 | cxg_hsize = hs; return cxg_hp = hp;
227 | }
228 |
229 | obj *cxm_rgc(obj *regs, size_t needs)
230 | {
231 | obj *p = cxg_regs; assert(needs > 0);
232 | if (!p || cxg_rend < p + needs) {
233 | size_t roff = regs ? regs - p : 0;
234 | if (!(p = realloc(p, needs*sizeof(obj)))) { perror("alloc[r]"); exit(2); }
235 | cxg_regs = p; cxg_rend = p + needs;
236 | regs = p + roff;
237 | }
238 | if (regs && regs > p) while (needs--) *p++ = *regs++;
239 | return cxg_regs;
240 | }
241 |
242 | void cxm_check(int x, char *msg)
243 | {
244 | if (!x) {
245 | perror(msg); exit(2);
246 | }
247 | }
248 |
249 | void *cxm_cknull(void *p, char *msg)
250 | {
251 | cxm_check(p != NULL, msg);
252 | return p;
253 | }
254 |
255 | /* os entry point */
256 | int main(int argc, char **argv) {
257 | int res; obj pc;
258 | obj retcl[1] = { 0 };
259 | cxm_rgc(NULL, REGS_SIZE);
260 | cxg_argv = argv;
261 | MODULE();
262 | cxg_regs[0] = cx_main;
263 | cxg_regs[1] = (obj)retcl;
264 | cxg_regs[2] = (obj)argv;
265 | cxg_rc = 3;
266 | pc = objptr_from_obj(cx_main)[0];
267 | while (pc) pc = (*(cxhost_t*)pc)(pc);
268 | assert(cxg_rc == 3);
269 | res = (cxg_regs[2] != 0);
270 | /* fprintf(stderr, "%d collections, %d reallocs\n", cxg_gccount, cxg_bumpcount); */
271 | return res;
272 | }
273 |
--------------------------------------------------------------------------------
/examples/compiled/tak.c:
--------------------------------------------------------------------------------
1 | /* tak.sf */
2 | /* Generated by #F $Id$ */
3 | #ifdef PROFILE
4 | #define host host_module_tak
5 | #endif
6 | #define MODULE module_tak
7 | #define LOAD()
8 |
9 | /* standard includes */
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | /* standard definitions */
16 |
17 | typedef ptrdiff_t obj; /* pointers are this size, lower bit zero */
18 | typedef ptrdiff_t cxoint_t; /* same thing, used as integer */
19 | typedef struct { /* type descriptor */
20 | const char *tname; /* name (debug) */
21 | void (*free)(void*); /* deallocator */
22 | } cxtype_t;
23 |
24 | #define notobjptr(o) (((char*)(o) - (char*)cxg_heap) & cxg_hmask)
25 | #define isobjptr(o) (!notobjptr(o))
26 | #define notaptr(o) ((o) & 1)
27 | #define isaptr(o) (!notaptr(o))
28 |
29 | #define obj_from_obj(o) (o)
30 | #define obj_from_objptr(p) ((obj)(p))
31 | #define obj_from_size(n) (((cxoint_t)(n) << 1) | 1)
32 |
33 | #define objptr_from_objptr(p) (p)
34 | #define objptr_from_obj(o) ((obj*)(o))
35 |
36 | #define size_from_obj(o) ((int)((o) >> 1))
37 |
38 | #define obj_from_case(n) obj_from_objptr(cases+(n))
39 | #define case_from_obj(o) (objptr_from_obj(o)-cases)
40 | #define obj_from_ktrap() obj_from_size(0x5D56F806)
41 | #define obj_from_void(v) ((void)(v), obj_from_size(0x6F56DF77))
42 |
43 | #define bool_from_obj(o) (o)
44 | #define bool_from_bool(b) (b)
45 | #define bool_from_size(s) (s)
46 |
47 | #define void_from_void(v) (void)(v)
48 | #define void_from_obj(o) (void)(o)
49 |
50 | #define rreserve(m) if (r + (m) >= cxg_rend) r = cxm_rgc(r, m)
51 | #define hpushptr(p, pt, l) (hreserve(2, l), *--hp = (obj)(p), *--hp = (obj)(pt), (obj)(hp+1))
52 | #define hbsz(s) ((s) + 1) /* 1 extra word to store block size */
53 | #define hreserve(n, l) ((hp < cxg_heap + (n)) ? hp = cxm_hgc(r, r+(l), hp, n) : hp)
54 | #define hendblk(n) (*--hp = obj_from_size(n), (obj)(hp+1))
55 | #define hblklen(p) size_from_obj(((obj*)(p))[-1])
56 | #define hblkref(p, i) (((obj*)(p))[i])
57 |
58 | typedef obj (*cxhost_t)(obj);
59 | typedef struct cxroot_tag {
60 | int globc; obj **globv;
61 | struct cxroot_tag *next;
62 | } cxroot_t;
63 |
64 | extern obj *cxg_heap;
65 | extern obj *cxg_hp;
66 | extern cxoint_t cxg_hmask;
67 | extern cxroot_t *cxg_rootp;
68 | extern obj *cxm_rgc(obj *regs, size_t needs);
69 | extern obj *cxm_hgc(obj *regs, obj *regp, obj *hp, size_t needs);
70 | extern obj *cxg_regs, *cxg_rend;
71 | extern void cxm_check(int x, char *msg);
72 | extern void *cxm_cknull(void *p, char *msg);
73 | extern int cxg_rc;
74 | extern char **cxg_argv;
75 |
76 | /* extra definitions */
77 | /* immediate object representation */
78 | #define isimm(o, t) (((o) & 0xff) == (((t) << 1) | 1))
79 | #define getimmu(o, t) (int)(((o) >> 8) & 0xffffff)
80 | #define getimms(o, t) (int)(((((o) >> 8) & 0xffffff) ^ 0x800000) - 0x800000)
81 | #define mkimm(o, t) ((((o) & 0xffffff) << 8) | ((t) << 1) | 1)
82 | /* booleans */
83 | #define TRUE_ITAG 0
84 | typedef int bool_t;
85 | #define is_bool_obj(o) (!((o) & ~(obj)1))
86 | #define is_bool_bool(b) ((b), 1)
87 | #define void_from_bool(b) (void)(b)
88 | #define obj_from_bool(b) ((b) ? mkimm(0, TRUE_ITAG) : 0)
89 | /* fixnums */
90 | #define FIXNUM_ITAG 1
91 | typedef int fixnum_t;
92 | #define is_fixnum_obj(o) (isimm(o, FIXNUM_ITAG))
93 | #define is_fixnum_fixnum(i) ((i), 1)
94 | #define fixnum_from_obj(o) (getimms(o, FIXNUM_ITAG))
95 | #define fixnum_from_fixnum(i) (i)
96 | #define void_from_fixnum(i) (void)(i)
97 | #define obj_from_fixnum(i) mkimm(i, FIXNUM_ITAG)
98 | #define FIXNUM_MIN -8388608
99 | #define FIXNUM_MAX 8388607
100 |
101 | /* cx globals */
102 | obj cx_main; /* main */
103 | obj cx_runtak; /* runtak */
104 | obj cx_tak; /* tak */
105 |
106 | /* helper functions */
107 | /* tak */
108 | static obj cxs_tak(obj v3_x, obj v2_y, obj v1_z)
109 | {
110 | s_tak:
111 | if ((fixnum_from_obj(v2_y) < fixnum_from_obj(v3_x))) {
112 | { /* let */
113 | obj v21_tmp = obj_from_obj(cxs_tak(obj_from_fixnum(fixnum_from_obj(v1_z) - (1)), (v3_x), (v2_y)));
114 | obj v20_tmp = obj_from_obj(cxs_tak(obj_from_fixnum(fixnum_from_obj(v2_y) - (1)), (v1_z), (v3_x)));
115 | obj v19_tmp = obj_from_obj(cxs_tak(obj_from_fixnum(fixnum_from_obj(v3_x) - (1)), (v2_y), (v1_z)));
116 | /* tail call */
117 | v3_x = (v19_tmp);
118 | v2_y = (v20_tmp);
119 | v1_z = (v21_tmp);
120 | goto s_tak;
121 | }
122 | } else {
123 | return (v1_z);
124 | }
125 | }
126 |
127 | /* runtak */
128 | static obj cxs_runtak(obj v6_n, obj v5_r)
129 | {
130 | s_runtak:
131 | if ((fixnum_from_obj(v6_n) == (0))) {
132 | return (v5_r);
133 | } else {
134 | { /* let */
135 | obj v18_tmp = obj_from_fixnum(fixnum_from_obj(v5_r) + fixnum_from_obj(cxs_tak(obj_from_fixnum(18), obj_from_fixnum(12), obj_from_fixnum(6))));
136 | obj v17_tmp = obj_from_fixnum(fixnum_from_obj(v6_n) - (1));
137 | /* tail call */
138 | v6_n = (v17_tmp);
139 | v5_r = (v18_tmp);
140 | goto s_runtak;
141 | }
142 | }
143 | }
144 |
145 | /* gc roots */
146 | static cxroot_t root = { 0, NULL, NULL };
147 |
148 | /* entry points */
149 | static obj host(obj);
150 | static obj cases[4] = {
151 | (obj)host, (obj)host, (obj)host, (obj)host,
152 | };
153 |
154 | /* host procedure */
155 | #define MAX_HOSTREGS 18
156 | static obj host(obj pc)
157 | {
158 | register obj *r = cxg_regs;
159 | register obj *hp = cxg_hp;
160 | register int rc = cxg_rc;
161 | rreserve(MAX_HOSTREGS);
162 | jump:
163 | switch (case_from_obj(pc)) {
164 |
165 | case 0: /* load module */
166 | { static obj c[] = { obj_from_case(1) }; cx_tak = (obj)c; }
167 | { static obj c[] = { obj_from_case(2) }; cx_runtak = (obj)c; }
168 | { static obj c[] = { obj_from_case(3) }; cx_main = (obj)c; }
169 | r[0] = obj_from_void(0);
170 | r[1+0] = r[0];
171 | pc = 0; /* exit from module init */
172 | r[1+1] = r[0];
173 | r += 1; /* shift reg wnd */
174 | rc = 2;
175 | goto jump;
176 |
177 | case 1: /* tak k x y z */
178 | assert(rc == 5);
179 | r += 1; /* shift reg. wnd */
180 | /* k x y z */
181 | r[4+0] = r[0];
182 | pc = objptr_from_obj(r[4+0])[0];
183 | r[4+1] = obj_from_ktrap();
184 | r[4+2] = (cxs_tak((r[1]), (r[2]), (r[3])));
185 | r += 4; /* shift reg wnd */
186 | rreserve(MAX_HOSTREGS);
187 | rc = 3;
188 | goto jump;
189 |
190 | case 2: /* runtak k n r */
191 | assert(rc == 4);
192 | r += 1; /* shift reg. wnd */
193 | /* k n r */
194 | r[3+0] = r[0];
195 | pc = objptr_from_obj(r[3+0])[0];
196 | r[3+1] = obj_from_ktrap();
197 | r[3+2] = (cxs_runtak((r[1]), (r[2])));
198 | r += 3; /* shift reg wnd */
199 | rreserve(MAX_HOSTREGS);
200 | rc = 3;
201 | goto jump;
202 |
203 | case 3: /* main k argv */
204 | assert(rc == 3);
205 | r += 1; /* shift reg. wnd */
206 | /* k argv */
207 | r[2] = (cxs_runtak(obj_from_fixnum(10000), obj_from_fixnum(0)));
208 | (void)(printf("%d", fixnum_from_obj(r[2])));
209 | r[2] = obj_from_void(putchar('\n'));
210 | r[3+0] = r[0];
211 | pc = objptr_from_obj(r[3+0])[0];
212 | r[3+1] = obj_from_ktrap();
213 | r[3+2] = r[2];
214 | r += 3; /* shift reg wnd */
215 | rreserve(MAX_HOSTREGS);
216 | rc = 3;
217 | goto jump;
218 |
219 | default: /* inter-host call */
220 | cxg_hp = hp;
221 | cxm_rgc(r, MAX_HOSTREGS);
222 | cxg_rc = rc;
223 | return pc;
224 | }
225 | }
226 |
227 | /* module load */
228 | void MODULE(void)
229 | {
230 | obj pc;
231 | if (!root.next) {
232 | root.next = cxg_rootp;
233 | cxg_rootp = &root;
234 | LOAD();
235 | pc = obj_from_case(0);
236 | cxg_rc = 0;
237 | while (pc) pc = (*(cxhost_t*)pc)(pc);
238 | assert(cxg_rc == 2);
239 | }
240 | }
241 |
242 | /* basic runtime */
243 | #define HEAP_SIZE 131072 /* 2^17 */
244 | #define REGS_SIZE 4092
245 |
246 | obj *cxg_heap = NULL;
247 | cxoint_t cxg_hmask = 0;
248 | obj *cxg_hp = NULL;
249 | static cxroot_t cxg_root = { 0, NULL, NULL };
250 | cxroot_t *cxg_rootp = &cxg_root;
251 | obj *cxg_regs = NULL, *cxg_rend = NULL;
252 | int cxg_rc = 0;
253 | char **cxg_argv = NULL;
254 |
255 | static obj *cxg_heap2 = NULL;
256 | static size_t cxg_hsize = 0;
257 | static cxoint_t cxg_hmask2 = 0;
258 | static int cxg_gccount = 0, cxg_bumpcount = 0;
259 |
260 | static obj *toheap2(obj* p, obj *hp, obj *h1, cxoint_t m1, obj *h2, cxoint_t m2)
261 | {
262 | obj o = *p, *op, fo, *fop;
263 | if (((char*)(o) - (char*)h1) & m1) return hp;
264 | fo = (op = objptr_from_obj(o))[-1]; assert(fo);
265 | if (notaptr(fo)) {
266 | fop = op + size_from_obj(fo); while (fop >= op) *--hp = *--fop;
267 | *p = *fop = obj_from_objptr(hp+1);
268 | } else if (((char*)(fo) - (char*)h2) & m2) {
269 | *--hp = *op--; *--hp = *op;
270 | *p = *op = obj_from_objptr(hp+1);
271 | } else *p = fo;
272 | return hp;
273 | }
274 |
275 | static void finalize(obj *hp1, obj *he1, obj *h2, cxoint_t m2)
276 | {
277 | while (hp1 < he1) {
278 | obj fo = *hp1++; assert(fo);
279 | if (notaptr(fo)) hp1 += size_from_obj(fo);
280 | else if (((char*)(fo) - (char*)h2) & m2) ((cxtype_t*)fo)->free((void*)*hp1++);
281 | else if (notaptr(fo = objptr_from_obj(fo)[-1])) hp1 += size_from_obj(fo);
282 | else ++hp1;
283 | } assert(hp1 == he1);
284 | }
285 |
286 | static obj *relocate(cxroot_t *pr, obj *regs, obj *regp,
287 | obj *he2, obj *he1, obj *hp, obj *h1, cxoint_t m1, obj *h2, cxoint_t m2)
288 | {
289 | obj *p, *hp1 = hp; hp = he2;
290 | for (p = regs; p < regp; ++p) hp = toheap2(p, hp, h1, m1, h2, m2);
291 | for (; pr; pr = pr->next) {
292 | obj **pp = pr->globv; int c = pr->globc;
293 | while (c-- > 0) hp = toheap2(*pp++, hp, h1, m1, h2, m2);
294 | }
295 | for (p = he2; p > hp; --p) hp = toheap2(p-1, hp, h1, m1, h2, m2);
296 | if (he1) finalize(hp1, he1, h2, m2);
297 | return hp;
298 | }
299 |
300 | obj *cxm_hgc(obj *regs, obj *regp, obj *hp, size_t needs)
301 | {
302 | obj *h1 = cxg_heap, *h2 = cxg_heap2; cxoint_t m1 = cxg_hmask, m2 = cxg_hmask2;
303 | size_t hs = cxg_hsize; cxroot_t *pr = cxg_rootp;
304 |
305 | obj *h = h1, *he1 = h1 + hs, *he2 = h2 + hs;
306 | ++cxg_gccount;
307 | if (h1) hp = relocate(pr, regs, regp, he2, he1, hp, h1, m1, h2, m2),
308 | needs += (h2 + hs - hp)*2; /* make heap half empty */
309 | else hp = h2 + hs;
310 | if (hs < needs) {
311 | size_t s = HEAP_SIZE; while (s < needs) s *= 2;
312 | m2 = 1 | ~(s*sizeof(obj)-1);
313 | if (!(h = realloc(h1, s*sizeof(obj)))) { perror("alloc[h]"); exit(2); }
314 | h1 = h2; h2 = h; he2 = h2 + s; he1 = 0; /* no finalize flag */
315 | if (h1) hp = relocate(pr, regs, regp, he2, he1, hp, h1, m1, h2, m2);
316 | else hp = h2 + s;
317 | if (!(h = realloc(h1, s*sizeof(obj)))) { perror("alloc[h]"); exit(2); }
318 | hs = s; m1 = m2; ++cxg_bumpcount;
319 | }
320 | h1 = h2; h2 = h;
321 |
322 | cxg_heap = h1; cxg_hmask = m1; cxg_heap2 = h2; cxg_hmask2 = m2;
323 | cxg_hsize = hs; return cxg_hp = hp;
324 | }
325 |
326 | obj *cxm_rgc(obj *regs, size_t needs)
327 | {
328 | obj *p = cxg_regs; assert(needs > 0);
329 | if (!p || cxg_rend < p + needs) {
330 | size_t roff = regs ? regs - p : 0;
331 | if (!(p = realloc(p, needs*sizeof(obj)))) { perror("alloc[r]"); exit(2); }
332 | cxg_regs = p; cxg_rend = p + needs;
333 | regs = p + roff;
334 | }
335 | if (regs && regs > p) while (needs--) *p++ = *regs++;
336 | return cxg_regs;
337 | }
338 |
339 | void cxm_check(int x, char *msg)
340 | {
341 | if (!x) {
342 | perror(msg); exit(2);
343 | }
344 | }
345 |
346 | void *cxm_cknull(void *p, char *msg)
347 | {
348 | cxm_check(p != NULL, msg);
349 | return p;
350 | }
351 |
352 | /* os entry point */
353 | int main(int argc, char **argv) {
354 | int res; obj pc;
355 | obj retcl[1] = { 0 };
356 | cxm_rgc(NULL, REGS_SIZE);
357 | cxg_argv = argv;
358 | MODULE();
359 | cxg_regs[0] = cx_main;
360 | cxg_regs[1] = (obj)retcl;
361 | cxg_regs[2] = (obj)argv;
362 | cxg_rc = 3;
363 | pc = objptr_from_obj(cx_main)[0];
364 | while (pc) pc = (*(cxhost_t*)pc)(pc);
365 | assert(cxg_rc == 3);
366 | res = (cxg_regs[2] != 0);
367 | /* fprintf(stderr, "%d collections, %d reallocs\n", cxg_gccount, cxg_bumpcount); */
368 | return res;
369 | }
370 |
--------------------------------------------------------------------------------
/examples/compiled/tfun.c:
--------------------------------------------------------------------------------
1 | /* tfun.sf */
2 | /* Generated by #F $Id$ */
3 | #ifdef PROFILE
4 | #define host host_module_tfun
5 | #endif
6 | #define MODULE module_tfun
7 | #define LOAD()
8 |
9 | /* standard includes */
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | /* standard definitions */
16 |
17 | typedef ptrdiff_t obj; /* pointers are this size, lower bit zero */
18 | typedef ptrdiff_t cxoint_t; /* same thing, used as integer */
19 | typedef struct { /* type descriptor */
20 | const char *tname; /* name (debug) */
21 | void (*free)(void*); /* deallocator */
22 | } cxtype_t;
23 |
24 | #define notobjptr(o) (((char*)(o) - (char*)cxg_heap) & cxg_hmask)
25 | #define isobjptr(o) (!notobjptr(o))
26 | #define notaptr(o) ((o) & 1)
27 | #define isaptr(o) (!notaptr(o))
28 |
29 | #define obj_from_obj(o) (o)
30 | #define obj_from_objptr(p) ((obj)(p))
31 | #define obj_from_size(n) (((cxoint_t)(n) << 1) | 1)
32 |
33 | #define objptr_from_objptr(p) (p)
34 | #define objptr_from_obj(o) ((obj*)(o))
35 |
36 | #define size_from_obj(o) ((int)((o) >> 1))
37 |
38 | #define obj_from_case(n) obj_from_objptr(cases+(n))
39 | #define case_from_obj(o) (objptr_from_obj(o)-cases)
40 | #define obj_from_ktrap() obj_from_size(0x5D56F806)
41 | #define obj_from_void(v) ((void)(v), obj_from_size(0x6F56DF77))
42 |
43 | #define bool_from_obj(o) (o)
44 | #define bool_from_bool(b) (b)
45 | #define bool_from_size(s) (s)
46 |
47 | #define void_from_void(v) (void)(v)
48 | #define void_from_obj(o) (void)(o)
49 |
50 | #define rreserve(m) if (r + (m) >= cxg_rend) r = cxm_rgc(r, m)
51 | #define hpushptr(p, pt, l) (hreserve(2, l), *--hp = (obj)(p), *--hp = (obj)(pt), (obj)(hp+1))
52 | #define hbsz(s) ((s) + 1) /* 1 extra word to store block size */
53 | #define hreserve(n, l) ((hp < cxg_heap + (n)) ? hp = cxm_hgc(r, r+(l), hp, n) : hp)
54 | #define hendblk(n) (*--hp = obj_from_size(n), (obj)(hp+1))
55 | #define hblklen(p) size_from_obj(((obj*)(p))[-1])
56 | #define hblkref(p, i) (((obj*)(p))[i])
57 |
58 | typedef obj (*cxhost_t)(obj);
59 | typedef struct cxroot_tag {
60 | int globc; obj **globv;
61 | struct cxroot_tag *next;
62 | } cxroot_t;
63 |
64 | extern obj *cxg_heap;
65 | extern obj *cxg_hp;
66 | extern cxoint_t cxg_hmask;
67 | extern cxroot_t *cxg_rootp;
68 | extern obj *cxm_rgc(obj *regs, size_t needs);
69 | extern obj *cxm_hgc(obj *regs, obj *regp, obj *hp, size_t needs);
70 | extern obj *cxg_regs, *cxg_rend;
71 | extern void cxm_check(int x, char *msg);
72 | extern void *cxm_cknull(void *p, char *msg);
73 | extern int cxg_rc;
74 | extern char **cxg_argv;
75 |
76 | /* extra definitions */
77 | /* immediate object representation */
78 | #define isimm(o, t) (((o) & 0xff) == (((t) << 1) | 1))
79 | #define getimmu(o, t) (int)(((o) >> 8) & 0xffffff)
80 | #define getimms(o, t) (int)(((((o) >> 8) & 0xffffff) ^ 0x800000) - 0x800000)
81 | #define mkimm(o, t) ((((o) & 0xffffff) << 8) | ((t) << 1) | 1)
82 | extern int istagged(obj o, int t);
83 | #define cktagged(o, t) (o)
84 | #define taggedlen(o, t) (hblklen(o)-1)
85 | #define taggedref(o, t, i) (&hblkref(o, (i)+1))
86 | /* booleans */
87 | #define TRUE_ITAG 0
88 | typedef int bool_t;
89 | #define is_bool_obj(o) (!((o) & ~(obj)1))
90 | #define is_bool_bool(b) ((b), 1)
91 | #define void_from_bool(b) (void)(b)
92 | #define obj_from_bool(b) ((b) ? mkimm(0, TRUE_ITAG) : 0)
93 | /* fixnums */
94 | #define FIXNUM_ITAG 1
95 | typedef int fixnum_t;
96 | #define is_fixnum_obj(o) (isimm(o, FIXNUM_ITAG))
97 | #define is_fixnum_fixnum(i) ((i), 1)
98 | #define fixnum_from_obj(o) (getimms(o, FIXNUM_ITAG))
99 | #define fixnum_from_fixnum(i) (i)
100 | #define void_from_fixnum(i) (void)(i)
101 | #define obj_from_fixnum(i) mkimm(i, FIXNUM_ITAG)
102 | #define FIXNUM_MIN -8388608
103 | #define FIXNUM_MAX 8388607
104 | /* null */
105 | #define NULL_ITAG 2
106 | #define mknull() mkimm(0, NULL_ITAG)
107 | #define isnull(o) ((o) == mkimm(0, NULL_ITAG))
108 | /* pairs and lists */
109 | #define PAIR_BTAG 1
110 | #define ispair(o) istagged(o, PAIR_BTAG)
111 | #define car(o) *taggedref(o, PAIR_BTAG, 0)
112 | #define cdr(o) *taggedref(o, PAIR_BTAG, 1)
113 |
114 | /* cx globals */
115 | obj cx_l12; /* l12 */
116 | obj cx_l18; /* l18 */
117 | obj cx_l6; /* l6 */
118 | obj cx_length; /* length */
119 | obj cx_listn; /* listn */
120 | obj cx_ltak; /* ltak */
121 | obj cx_shorterp; /* shorterp */
122 | obj cx_tak; /* tak */
123 |
124 | /* helper functions */
125 | /* tak */
126 | static obj cxs_tak(obj v3_x, obj v2_y, obj v1_z)
127 | {
128 | s_tak:
129 | if ((fixnum_from_obj(v2_y) < fixnum_from_obj(v3_x))) {
130 | { /* let */
131 | obj v79_tmp = obj_from_obj(cxs_tak(obj_from_fixnum(fixnum_from_obj(v1_z) - (1)), (v3_x), (v2_y)));
132 | obj v78_tmp = obj_from_obj(cxs_tak(obj_from_fixnum(fixnum_from_obj(v2_y) - (1)), (v1_z), (v3_x)));
133 | obj v77_tmp = obj_from_obj(cxs_tak(obj_from_fixnum(fixnum_from_obj(v3_x) - (1)), (v2_y), (v1_z)));
134 | /* tail call */
135 | v3_x = (v77_tmp);
136 | v2_y = (v78_tmp);
137 | v1_z = (v79_tmp);
138 | goto s_tak;
139 | }
140 | } else {
141 | return (v1_z);
142 | }
143 | }
144 |
145 | /* length */
146 | static obj cxs_length(obj v21_l)
147 | {
148 | { /* letrec */
149 | obj v24_l;
150 | obj v23_n;
151 | { /* let */
152 | obj v76_tmp = obj_from_fixnum(0);
153 | obj v75_tmp = (v21_l);
154 | /* tail call */
155 | v24_l = (v75_tmp);
156 | v23_n = (v76_tmp);
157 | goto s_length_2Daux;
158 | }
159 | s_length_2Daux:
160 | if ((ispair((v24_l)))) {
161 | { /* let */
162 | obj v74_tmp = obj_from_fixnum(fixnum_from_obj(v23_n) + (1));
163 | obj v73_tmp = (cdr((v24_l)));
164 | /* tail call */
165 | v24_l = (v73_tmp);
166 | v23_n = (v74_tmp);
167 | goto s_length_2Daux;
168 | }
169 | } else {
170 | return (v23_n);
171 | }
172 | }
173 | }
174 |
175 | /* shorterp */
176 | static obj cxs_shorterp(obj v34_x, obj v33_y)
177 | {
178 | s_shorterp:
179 | if ((ispair((v33_y)))) {
180 | if ((isnull((v34_x)))) {
181 | return obj_from_bool(isnull((v34_x)));
182 | } else {
183 | { /* let */
184 | obj v72_tmp = (cdr((v33_y)));
185 | obj v71_tmp = (cdr((v34_x)));
186 | /* tail call */
187 | v34_x = (v71_tmp);
188 | v33_y = (v72_tmp);
189 | goto s_shorterp;
190 | }
191 | }
192 | } else {
193 | return obj_from_bool(0);
194 | }
195 | }
196 |
197 | /* ltak */
198 | static obj cxs_ltak(obj v46_x, obj v45_y, obj v44_z)
199 | {
200 | s_ltak:
201 | if ((!bool_from_obj(cxs_shorterp((v45_y), (v46_x))))) {
202 | return (v44_z);
203 | } else {
204 | { /* let */
205 | obj v70_tmp = obj_from_obj(cxs_ltak((cdr((v44_z))), (v46_x), (v45_y)));
206 | obj v69_tmp = obj_from_obj(cxs_ltak((cdr((v45_y))), (v44_z), (v46_x)));
207 | obj v68_tmp = obj_from_obj(cxs_ltak((cdr((v46_x))), (v45_y), (v44_z)));
208 | /* tail call */
209 | v46_x = (v68_tmp);
210 | v45_y = (v69_tmp);
211 | v44_z = (v70_tmp);
212 | goto s_ltak;
213 | }
214 | }
215 | }
216 |
217 | /* gc roots */
218 | static obj *globv[] = {
219 | &cx_l12,
220 | &cx_l18,
221 | &cx_l6,
222 | };
223 |
224 | static cxroot_t root = {
225 | sizeof(globv)/sizeof(obj *), globv, NULL
226 | };
227 |
228 | /* entry points */
229 | static obj host(obj);
230 | static obj cases[10] = {
231 | (obj)host, (obj)host, (obj)host, (obj)host, (obj)host,
232 | (obj)host, (obj)host, (obj)host, (obj)host, (obj)host,
233 | };
234 |
235 | /* host procedure */
236 | #define MAX_HOSTREGS 18
237 | static obj host(obj pc)
238 | {
239 | register obj *r = cxg_regs;
240 | register obj *hp = cxg_hp;
241 | register int rc = cxg_rc;
242 | rreserve(MAX_HOSTREGS);
243 | jump:
244 | switch (case_from_obj(pc)) {
245 |
246 | case 0: /* load module */
247 | { static obj c[] = { obj_from_case(1) }; cx_tak = (obj)c; }
248 | { static obj c[] = { obj_from_case(2) }; cx_listn = (obj)c; }
249 | { static obj c[] = { obj_from_case(4) }; cx_length = (obj)c; }
250 | { static obj c[] = { obj_from_case(5) }; cx_shorterp = (obj)c; }
251 | hreserve(hbsz(0+1), 0); /* 0 live regs */
252 | *--hp = obj_from_case(6);
253 | r[0] = (hendblk(0+1));
254 | r[1+0] = r[0];
255 | r[1+1] = obj_from_fixnum(18);
256 | r += 1; /* shift reg wnd */
257 | rreserve(MAX_HOSTREGS);
258 | goto gs_listn;
259 |
260 | case 1: /* tak k x y z */
261 | assert(rc == 5);
262 | r += 1; /* shift reg. wnd */
263 | /* k x y z */
264 | r[4+0] = r[0];
265 | pc = objptr_from_obj(r[4+0])[0];
266 | r[4+1] = obj_from_ktrap();
267 | r[4+2] = (cxs_tak((r[1]), (r[2]), (r[3])));
268 | r += 4; /* shift reg wnd */
269 | rreserve(MAX_HOSTREGS);
270 | rc = 3;
271 | goto jump;
272 |
273 | case 2: /* listn k n */
274 | assert(rc == 3);
275 | r += 1; /* shift reg. wnd */
276 | gs_listn: /* k n */
277 | if (((0) == fixnum_from_obj(r[1]))) {
278 | r[2+0] = r[0];
279 | pc = objptr_from_obj(r[2+0])[0];
280 | r[2+1] = obj_from_ktrap();
281 | r[2+2] = (mknull());
282 | r += 2; /* shift reg wnd */
283 | rreserve(MAX_HOSTREGS);
284 | rc = 3;
285 | goto jump;
286 | } else {
287 | hreserve(hbsz(2+1), 2); /* 2 live regs */
288 | *--hp = r[1];
289 | *--hp = r[0];
290 | *--hp = obj_from_case(3);
291 | r[2] = (hendblk(2+1));
292 | r[0] = r[2];
293 | r[1] = obj_from_fixnum(fixnum_from_obj(r[1]) - (1));
294 | goto gs_listn;
295 | }
296 |
297 | case 3: /* clo ek r */
298 | assert(rc == 3);
299 | { obj* p = objptr_from_obj(r[0]);
300 | r[1+2] = p[1];
301 | r[1+3] = p[2]; }
302 | r += 1; /* shift reg. wnd */
303 | /* ek r k n */
304 | { /* cons */
305 | hreserve(hbsz(3), 4); /* 4 live regs */
306 | *--hp = r[1];
307 | *--hp = r[3];
308 | *--hp = obj_from_size(PAIR_BTAG);
309 | r[4] = (hendblk(3)); }
310 | r[5+0] = r[2];
311 | pc = objptr_from_obj(r[5+0])[0];
312 | r[5+1] = obj_from_ktrap();
313 | r[5+2] = r[4];
314 | r += 5; /* shift reg wnd */
315 | rreserve(MAX_HOSTREGS);
316 | rc = 3;
317 | goto jump;
318 |
319 | case 4: /* length k l */
320 | assert(rc == 3);
321 | r += 1; /* shift reg. wnd */
322 | /* k l */
323 | r[2+0] = r[0];
324 | pc = objptr_from_obj(r[2+0])[0];
325 | r[2+1] = obj_from_ktrap();
326 | r[2+2] = (cxs_length((r[1])));
327 | r += 2; /* shift reg wnd */
328 | rreserve(MAX_HOSTREGS);
329 | rc = 3;
330 | goto jump;
331 |
332 | case 5: /* shorterp k x y */
333 | assert(rc == 4);
334 | r += 1; /* shift reg. wnd */
335 | /* k x y */
336 | r[3+0] = r[0];
337 | pc = objptr_from_obj(r[3+0])[0];
338 | r[3+1] = obj_from_ktrap();
339 | r[3+2] = (cxs_shorterp((r[1]), (r[2])));
340 | r += 3; /* shift reg wnd */
341 | rreserve(MAX_HOSTREGS);
342 | rc = 3;
343 | goto jump;
344 |
345 | case 6: /* clo ek r */
346 | assert(rc == 3);
347 | r += 1; /* shift reg. wnd */
348 | /* ek r */
349 | cx_l18 = r[1];
350 | hreserve(hbsz(0+1), 2); /* 2 live regs */
351 | *--hp = obj_from_case(7);
352 | r[2] = (hendblk(0+1));
353 | r[0] = r[2];
354 | r[1] = obj_from_fixnum(12);
355 | goto gs_listn;
356 |
357 | case 7: /* clo ek r */
358 | assert(rc == 3);
359 | r += 1; /* shift reg. wnd */
360 | /* ek r */
361 | cx_l12 = r[1];
362 | hreserve(hbsz(0+1), 2); /* 2 live regs */
363 | *--hp = obj_from_case(8);
364 | r[2] = (hendblk(0+1));
365 | r[0] = r[2];
366 | r[1] = obj_from_fixnum(6);
367 | goto gs_listn;
368 |
369 | case 8: /* clo ek r */
370 | assert(rc == 3);
371 | r += 1; /* shift reg. wnd */
372 | /* ek r */
373 | cx_l6 = r[1];
374 | { static obj c[] = { obj_from_case(9) }; cx_ltak = (obj)c; }
375 | r[2] = obj_from_void(0);
376 | r[3+0] = r[0];
377 | pc = 0; /* exit from module init */
378 | r[3+1] = r[2];
379 | r += 3; /* shift reg wnd */
380 | rc = 2;
381 | goto jump;
382 |
383 | case 9: /* ltak k x y z */
384 | assert(rc == 5);
385 | r += 1; /* shift reg. wnd */
386 | /* k x y z */
387 | r[4+0] = r[0];
388 | pc = objptr_from_obj(r[4+0])[0];
389 | r[4+1] = obj_from_ktrap();
390 | r[4+2] = (cxs_ltak((r[1]), (r[2]), (r[3])));
391 | r += 4; /* shift reg wnd */
392 | rreserve(MAX_HOSTREGS);
393 | rc = 3;
394 | goto jump;
395 |
396 | default: /* inter-host call */
397 | cxg_hp = hp;
398 | cxm_rgc(r, MAX_HOSTREGS);
399 | cxg_rc = rc;
400 | return pc;
401 | }
402 | }
403 |
404 | /* module load */
405 | void MODULE(void)
406 | {
407 | obj pc;
408 | if (!root.next) {
409 | root.next = cxg_rootp;
410 | cxg_rootp = &root;
411 | LOAD();
412 | pc = obj_from_case(0);
413 | cxg_rc = 0;
414 | while (pc) pc = (*(cxhost_t*)pc)(pc);
415 | assert(cxg_rc == 2);
416 | }
417 | }
418 |
--------------------------------------------------------------------------------
/examples/compiled/tlib.c:
--------------------------------------------------------------------------------
1 | /* tlib.sf */
2 | /* Generated by #F $Id$ */
3 | #ifdef PROFILE
4 | #define host host_module_tlib
5 | #endif
6 | #define MODULE module_tlib
7 | #define LOAD()
8 |
9 | /* standard includes */
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | /* standard definitions */
16 |
17 | typedef ptrdiff_t obj; /* pointers are this size, lower bit zero */
18 | typedef ptrdiff_t cxoint_t; /* same thing, used as integer */
19 | typedef struct { /* type descriptor */
20 | const char *tname; /* name (debug) */
21 | void (*free)(void*); /* deallocator */
22 | } cxtype_t;
23 |
24 | #define notobjptr(o) (((char*)(o) - (char*)cxg_heap) & cxg_hmask)
25 | #define isobjptr(o) (!notobjptr(o))
26 | #define notaptr(o) ((o) & 1)
27 | #define isaptr(o) (!notaptr(o))
28 |
29 | #define obj_from_obj(o) (o)
30 | #define obj_from_objptr(p) ((obj)(p))
31 | #define obj_from_size(n) (((cxoint_t)(n) << 1) | 1)
32 |
33 | #define objptr_from_objptr(p) (p)
34 | #define objptr_from_obj(o) ((obj*)(o))
35 |
36 | #define size_from_obj(o) ((int)((o) >> 1))
37 |
38 | #define obj_from_case(n) obj_from_objptr(cases+(n))
39 | #define case_from_obj(o) (objptr_from_obj(o)-cases)
40 | #define obj_from_ktrap() obj_from_size(0x5D56F806)
41 | #define obj_from_void(v) ((void)(v), obj_from_size(0x6F56DF77))
42 |
43 | #define bool_from_obj(o) (o)
44 | #define bool_from_bool(b) (b)
45 | #define bool_from_size(s) (s)
46 |
47 | #define void_from_void(v) (void)(v)
48 | #define void_from_obj(o) (void)(o)
49 |
50 | #define rreserve(m) if (r + (m) >= cxg_rend) r = cxm_rgc(r, m)
51 | #define hpushptr(p, pt, l) (hreserve(2, l), *--hp = (obj)(p), *--hp = (obj)(pt), (obj)(hp+1))
52 | #define hbsz(s) ((s) + 1) /* 1 extra word to store block size */
53 | #define hreserve(n, l) ((hp < cxg_heap + (n)) ? hp = cxm_hgc(r, r+(l), hp, n) : hp)
54 | #define hendblk(n) (*--hp = obj_from_size(n), (obj)(hp+1))
55 | #define hblklen(p) size_from_obj(((obj*)(p))[-1])
56 | #define hblkref(p, i) (((obj*)(p))[i])
57 |
58 | typedef obj (*cxhost_t)(obj);
59 | typedef struct cxroot_tag {
60 | int globc; obj **globv;
61 | struct cxroot_tag *next;
62 | } cxroot_t;
63 |
64 | extern obj *cxg_heap;
65 | extern obj *cxg_hp;
66 | extern cxoint_t cxg_hmask;
67 | extern cxroot_t *cxg_rootp;
68 | extern obj *cxm_rgc(obj *regs, size_t needs);
69 | extern obj *cxm_hgc(obj *regs, obj *regp, obj *hp, size_t needs);
70 | extern obj *cxg_regs, *cxg_rend;
71 | extern void cxm_check(int x, char *msg);
72 | extern void *cxm_cknull(void *p, char *msg);
73 | extern int cxg_rc;
74 | extern char **cxg_argv;
75 |
76 | /* extra definitions */
77 | /* immediate object representation */
78 | #define isimm(o, t) (((o) & 0xff) == (((t) << 1) | 1))
79 | #define getimmu(o, t) (int)(((o) >> 8) & 0xffffff)
80 | #define getimms(o, t) (int)(((((o) >> 8) & 0xffffff) ^ 0x800000) - 0x800000)
81 | #define mkimm(o, t) ((((o) & 0xffffff) << 8) | ((t) << 1) | 1)
82 | int istagged(obj o, int t) {
83 | return isobjptr(o) && hblklen(o) >= 1 && hblkref(o, 0) == obj_from_size(t);
84 | }
85 | extern int istagged(obj o, int t);
86 | #define cktagged(o, t) (o)
87 | #define taggedlen(o, t) (hblklen(o)-1)
88 | #define taggedref(o, t, i) (&hblkref(o, (i)+1))
89 | /* booleans */
90 | #define TRUE_ITAG 0
91 | typedef int bool_t;
92 | #define is_bool_obj(o) (!((o) & ~(obj)1))
93 | #define is_bool_bool(b) ((b), 1)
94 | #define void_from_bool(b) (void)(b)
95 | #define obj_from_bool(b) ((b) ? mkimm(0, TRUE_ITAG) : 0)
96 | /* fixnums */
97 | #define FIXNUM_ITAG 1
98 | typedef int fixnum_t;
99 | #define is_fixnum_obj(o) (isimm(o, FIXNUM_ITAG))
100 | #define is_fixnum_fixnum(i) ((i), 1)
101 | #define fixnum_from_obj(o) (getimms(o, FIXNUM_ITAG))
102 | #define fixnum_from_fixnum(i) (i)
103 | #define void_from_fixnum(i) (void)(i)
104 | #define obj_from_fixnum(i) mkimm(i, FIXNUM_ITAG)
105 | #define FIXNUM_MIN -8388608
106 | #define FIXNUM_MAX 8388607
107 | /* null */
108 | #define NULL_ITAG 2
109 | #define mknull() mkimm(0, NULL_ITAG)
110 | #define isnull(o) ((o) == mkimm(0, NULL_ITAG))
111 | /* pairs and lists */
112 | #define PAIR_BTAG 1
113 | #define ispair(o) istagged(o, PAIR_BTAG)
114 | #define car(o) *taggedref(o, PAIR_BTAG, 0)
115 | #define cdr(o) *taggedref(o, PAIR_BTAG, 1)
116 |
117 | /* cx globals */
118 |
119 | /* gc roots */
120 | static cxroot_t root = { 0, NULL, NULL };
121 |
122 | /* entry points */
123 | static obj host(obj);
124 | static obj cases[1] = {
125 | (obj)host,
126 | };
127 |
128 | /* host procedure */
129 | #define MAX_HOSTREGS 6
130 | static obj host(obj pc)
131 | {
132 | register obj *r = cxg_regs;
133 | register obj *hp = cxg_hp;
134 | register int rc = cxg_rc;
135 | rreserve(MAX_HOSTREGS);
136 | jump:
137 | switch (case_from_obj(pc)) {
138 |
139 | case 0: /* load module */
140 | r[0+0] = r[0];
141 | pc = 0; /* exit from module init */
142 | r[0+1] = obj_from_void(0);
143 | r += 0; /* shift reg wnd */
144 | rc = 2;
145 | goto jump;
146 |
147 | default: /* inter-host call */
148 | cxg_hp = hp;
149 | cxm_rgc(r, MAX_HOSTREGS);
150 | cxg_rc = rc;
151 | return pc;
152 | }
153 | }
154 |
155 | /* module load */
156 | void MODULE(void)
157 | {
158 | obj pc;
159 | if (!root.next) {
160 | root.next = cxg_rootp;
161 | cxg_rootp = &root;
162 | LOAD();
163 | pc = obj_from_case(0);
164 | cxg_rc = 0;
165 | while (pc) pc = (*(cxhost_t*)pc)(pc);
166 | assert(cxg_rc == 2);
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/examples/compiled/tmain.c:
--------------------------------------------------------------------------------
1 | /* tmain.sf */
2 | /* Generated by #F $Id$ */
3 | #ifdef PROFILE
4 | #define host host_module_tmain
5 | #endif
6 | #define MODULE module_tmain
7 | #define LOAD() module_tfun();
8 | extern void module_tfun(void); /* tfun.sf */
9 |
10 | /* standard includes */
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | /* standard definitions */
17 |
18 | typedef ptrdiff_t obj; /* pointers are this size, lower bit zero */
19 | typedef ptrdiff_t cxoint_t; /* same thing, used as integer */
20 | typedef struct { /* type descriptor */
21 | const char *tname; /* name (debug) */
22 | void (*free)(void*); /* deallocator */
23 | } cxtype_t;
24 |
25 | #define notobjptr(o) (((char*)(o) - (char*)cxg_heap) & cxg_hmask)
26 | #define isobjptr(o) (!notobjptr(o))
27 | #define notaptr(o) ((o) & 1)
28 | #define isaptr(o) (!notaptr(o))
29 |
30 | #define obj_from_obj(o) (o)
31 | #define obj_from_objptr(p) ((obj)(p))
32 | #define obj_from_size(n) (((cxoint_t)(n) << 1) | 1)
33 |
34 | #define objptr_from_objptr(p) (p)
35 | #define objptr_from_obj(o) ((obj*)(o))
36 |
37 | #define size_from_obj(o) ((int)((o) >> 1))
38 |
39 | #define obj_from_case(n) obj_from_objptr(cases+(n))
40 | #define case_from_obj(o) (objptr_from_obj(o)-cases)
41 | #define obj_from_ktrap() obj_from_size(0x5D56F806)
42 | #define obj_from_void(v) ((void)(v), obj_from_size(0x6F56DF77))
43 |
44 | #define bool_from_obj(o) (o)
45 | #define bool_from_bool(b) (b)
46 | #define bool_from_size(s) (s)
47 |
48 | #define void_from_void(v) (void)(v)
49 | #define void_from_obj(o) (void)(o)
50 |
51 | #define rreserve(m) if (r + (m) >= cxg_rend) r = cxm_rgc(r, m)
52 | #define hpushptr(p, pt, l) (hreserve(2, l), *--hp = (obj)(p), *--hp = (obj)(pt), (obj)(hp+1))
53 | #define hbsz(s) ((s) + 1) /* 1 extra word to store block size */
54 | #define hreserve(n, l) ((hp < cxg_heap + (n)) ? hp = cxm_hgc(r, r+(l), hp, n) : hp)
55 | #define hendblk(n) (*--hp = obj_from_size(n), (obj)(hp+1))
56 | #define hblklen(p) size_from_obj(((obj*)(p))[-1])
57 | #define hblkref(p, i) (((obj*)(p))[i])
58 |
59 | typedef obj (*cxhost_t)(obj);
60 | typedef struct cxroot_tag {
61 | int globc; obj **globv;
62 | struct cxroot_tag *next;
63 | } cxroot_t;
64 |
65 | extern obj *cxg_heap;
66 | extern obj *cxg_hp;
67 | extern cxoint_t cxg_hmask;
68 | extern cxroot_t *cxg_rootp;
69 | extern obj *cxm_rgc(obj *regs, size_t needs);
70 | extern obj *cxm_hgc(obj *regs, obj *regp, obj *hp, size_t needs);
71 | extern obj *cxg_regs, *cxg_rend;
72 | extern void cxm_check(int x, char *msg);
73 | extern void *cxm_cknull(void *p, char *msg);
74 | extern int cxg_rc;
75 | extern char **cxg_argv;
76 |
77 | /* extra definitions */
78 | /* immediate object representation */
79 | #define isimm(o, t) (((o) & 0xff) == (((t) << 1) | 1))
80 | #define getimmu(o, t) (int)(((o) >> 8) & 0xffffff)
81 | #define getimms(o, t) (int)(((((o) >> 8) & 0xffffff) ^ 0x800000) - 0x800000)
82 | #define mkimm(o, t) ((((o) & 0xffffff) << 8) | ((t) << 1) | 1)
83 | extern int istagged(obj o, int t);
84 | #define cktagged(o, t) (o)
85 | #define taggedlen(o, t) (hblklen(o)-1)
86 | #define taggedref(o, t, i) (&hblkref(o, (i)+1))
87 | /* booleans */
88 | #define TRUE_ITAG 0
89 | typedef int bool_t;
90 | #define is_bool_obj(o) (!((o) & ~(obj)1))
91 | #define is_bool_bool(b) ((b), 1)
92 | #define void_from_bool(b) (void)(b)
93 | #define obj_from_bool(b) ((b) ? mkimm(0, TRUE_ITAG) : 0)
94 | /* fixnums */
95 | #define FIXNUM_ITAG 1
96 | typedef int fixnum_t;
97 | #define is_fixnum_obj(o) (isimm(o, FIXNUM_ITAG))
98 | #define is_fixnum_fixnum(i) ((i), 1)
99 | #define fixnum_from_obj(o) (getimms(o, FIXNUM_ITAG))
100 | #define fixnum_from_fixnum(i) (i)
101 | #define void_from_fixnum(i) (void)(i)
102 | #define obj_from_fixnum(i) mkimm(i, FIXNUM_ITAG)
103 | #define FIXNUM_MIN -8388608
104 | #define FIXNUM_MAX 8388607
105 | /* null */
106 | #define NULL_ITAG 2
107 | #define mknull() mkimm(0, NULL_ITAG)
108 | #define isnull(o) ((o) == mkimm(0, NULL_ITAG))
109 | /* pairs and lists */
110 | #define PAIR_BTAG 1
111 | #define ispair(o) istagged(o, PAIR_BTAG)
112 | #define car(o) *taggedref(o, PAIR_BTAG, 0)
113 | #define cdr(o) *taggedref(o, PAIR_BTAG, 1)
114 |
115 | /* cx globals */
116 | extern obj cx_l12; /* l12 */
117 | extern obj cx_l18; /* l18 */
118 | extern obj cx_l6; /* l6 */
119 | extern obj cx_length; /* length */
120 | extern obj cx_ltak; /* ltak */
121 | extern obj cx_tak; /* tak */
122 | obj cx_main; /* main */
123 | obj cx_runltak; /* runltak */
124 | obj cx_runtak; /* runtak */
125 |
126 | /* gc roots */
127 | static cxroot_t root = { 0, NULL, NULL };
128 |
129 | /* entry points */
130 | static obj host(obj);
131 | static obj cases[9] = {
132 | (obj)host, (obj)host, (obj)host, (obj)host, (obj)host,
133 | (obj)host, (obj)host, (obj)host, (obj)host,
134 | };
135 |
136 | /* host procedure */
137 | #define MAX_HOSTREGS 20
138 | static obj host(obj pc)
139 | {
140 | register obj *r = cxg_regs;
141 | register obj *hp = cxg_hp;
142 | register int rc = cxg_rc;
143 | rreserve(MAX_HOSTREGS);
144 | jump:
145 | switch (case_from_obj(pc)) {
146 |
147 | case 0: /* load module */
148 | { static obj c[] = { obj_from_case(1) }; cx_runtak = (obj)c; }
149 | { static obj c[] = { obj_from_case(3) }; cx_runltak = (obj)c; }
150 | { static obj c[] = { obj_from_case(6) }; cx_main = (obj)c; }
151 | r[0] = obj_from_void(0);
152 | r[1+0] = r[0];
153 | pc = 0; /* exit from module init */
154 | r[1+1] = r[0];
155 | r += 1; /* shift reg wnd */
156 | rc = 2;
157 | goto jump;
158 |
159 | case 1: /* runtak k n r */
160 | assert(rc == 4);
161 | r += 1; /* shift reg. wnd */
162 | gs_runtak: /* k n r */
163 | if ((fixnum_from_obj(r[1]) == (0))) {
164 | /* r[0] */
165 | pc = objptr_from_obj(r[0])[0];
166 | r[1] = obj_from_ktrap();
167 | /* r[2] */
168 | rreserve(MAX_HOSTREGS);
169 | rc = 3;
170 | goto jump;
171 | } else {
172 | hreserve(hbsz(3+1), 3); /* 3 live regs */
173 | *--hp = r[0];
174 | *--hp = r[1];
175 | *--hp = r[2];
176 | *--hp = obj_from_case(2);
177 | r[3] = (hendblk(3+1));
178 | r[4+0] = (cx_tak);
179 | pc = objptr_from_obj(r[4+0])[0];
180 | r[4+1] = r[3];
181 | r[4+2] = obj_from_fixnum(18);
182 | r[4+3] = obj_from_fixnum(12);
183 | r[4+4] = obj_from_fixnum(6);
184 | r += 4; /* shift reg wnd */
185 | rreserve(MAX_HOSTREGS);
186 | rc = 5;
187 | goto jump;
188 | }
189 |
190 | case 2: /* clo ek r */
191 | assert(rc == 3);
192 | { obj* p = objptr_from_obj(r[0]);
193 | r[1+2] = p[1];
194 | r[1+3] = p[2];
195 | r[1+4] = p[3]; }
196 | r += 1; /* shift reg. wnd */
197 | /* ek r r n k */
198 | r[5+0] = r[4];
199 | r[5+1] = obj_from_fixnum(fixnum_from_obj(r[3]) - (1));
200 | r[5+2] = obj_from_fixnum(fixnum_from_obj(r[2]) + fixnum_from_obj(r[1]));
201 | r += 5; /* shift reg wnd */
202 | rreserve(MAX_HOSTREGS);
203 | goto gs_runtak;
204 |
205 | case 3: /* runltak k n r */
206 | assert(rc == 4);
207 | r += 1; /* shift reg. wnd */
208 | gs_runltak: /* k n r */
209 | if ((fixnum_from_obj(r[1]) == (0))) {
210 | /* r[0] */
211 | pc = objptr_from_obj(r[0])[0];
212 | r[1] = obj_from_ktrap();
213 | /* r[2] */
214 | rreserve(MAX_HOSTREGS);
215 | rc = 3;
216 | goto jump;
217 | } else {
218 | hreserve(hbsz(3+1), 3); /* 3 live regs */
219 | *--hp = r[0];
220 | *--hp = r[1];
221 | *--hp = r[2];
222 | *--hp = obj_from_case(4);
223 | r[3] = (hendblk(3+1));
224 | r[4+0] = (cx_ltak);
225 | pc = objptr_from_obj(r[4+0])[0];
226 | r[4+1] = r[3];
227 | r[4+2] = (cx_l18);
228 | r[4+3] = (cx_l12);
229 | r[4+4] = (cx_l6);
230 | r += 4; /* shift reg wnd */
231 | rreserve(MAX_HOSTREGS);
232 | rc = 5;
233 | goto jump;
234 | }
235 |
236 | case 4: /* clo ek r */
237 | assert(rc == 3);
238 | { obj* p = objptr_from_obj(r[0]);
239 | r[1+2] = p[1];
240 | r[1+3] = p[2];
241 | r[1+4] = p[3]; }
242 | r += 1; /* shift reg. wnd */
243 | /* ek r r n k */
244 | hreserve(hbsz(3+1), 5); /* 5 live regs */
245 | *--hp = r[4];
246 | *--hp = r[3];
247 | *--hp = r[2];
248 | *--hp = obj_from_case(5);
249 | r[5] = (hendblk(3+1));
250 | r[6+0] = (cx_length);
251 | pc = objptr_from_obj(r[6+0])[0];
252 | r[6+1] = r[5];
253 | r[6+2] = r[1];
254 | r += 6; /* shift reg wnd */
255 | rreserve(MAX_HOSTREGS);
256 | rc = 3;
257 | goto jump;
258 |
259 | case 5: /* clo ek r */
260 | assert(rc == 3);
261 | { obj* p = objptr_from_obj(r[0]);
262 | r[1+2] = p[1];
263 | r[1+3] = p[2];
264 | r[1+4] = p[3]; }
265 | r += 1; /* shift reg. wnd */
266 | /* ek r r n k */
267 | r[5+0] = r[4];
268 | r[5+1] = obj_from_fixnum(fixnum_from_obj(r[3]) - (1));
269 | r[5+2] = obj_from_fixnum(fixnum_from_obj(r[2]) + fixnum_from_obj(r[1]));
270 | r += 5; /* shift reg wnd */
271 | rreserve(MAX_HOSTREGS);
272 | goto gs_runltak;
273 |
274 | case 6: /* main k argv */
275 | assert(rc == 3);
276 | r += 1; /* shift reg. wnd */
277 | /* k argv */
278 | hreserve(hbsz(1+1), 2); /* 2 live regs */
279 | *--hp = r[0];
280 | *--hp = obj_from_case(7);
281 | r[2] = (hendblk(1+1));
282 | r[3+0] = r[2];
283 | r[3+1] = obj_from_fixnum(1000);
284 | r[3+2] = obj_from_fixnum(0);
285 | r += 3; /* shift reg wnd */
286 | rreserve(MAX_HOSTREGS);
287 | goto gs_runtak;
288 |
289 | case 7: /* clo ek r */
290 | assert(rc == 3);
291 | { obj* p = objptr_from_obj(r[0]);
292 | r[1+2] = p[1]; }
293 | r += 1; /* shift reg. wnd */
294 | /* ek r k */
295 | (void)(printf("%d", fixnum_from_obj(r[1])));
296 | (void)(putchar('\n'));
297 | hreserve(hbsz(1+1), 3); /* 3 live regs */
298 | *--hp = r[2];
299 | *--hp = obj_from_case(8);
300 | r[3] = (hendblk(1+1));
301 | r[0] = r[3];
302 | r[1] = obj_from_fixnum(1000);
303 | r[2] = obj_from_fixnum(0);
304 | goto gs_runltak;
305 |
306 | case 8: /* clo ek r */
307 | assert(rc == 3);
308 | { obj* p = objptr_from_obj(r[0]);
309 | r[1+2] = p[1]; }
310 | r += 1; /* shift reg. wnd */
311 | /* ek r k */
312 | (void)(printf("%d", fixnum_from_obj(r[1])));
313 | r[0] = r[2];
314 | pc = objptr_from_obj(r[0])[0];
315 | r[1] = obj_from_ktrap();
316 | r[2] = obj_from_void(putchar('\n'));
317 | rreserve(MAX_HOSTREGS);
318 | rc = 3;
319 | goto jump;
320 |
321 | default: /* inter-host call */
322 | cxg_hp = hp;
323 | cxm_rgc(r, MAX_HOSTREGS);
324 | cxg_rc = rc;
325 | return pc;
326 | }
327 | }
328 |
329 | /* module load */
330 | void MODULE(void)
331 | {
332 | obj pc;
333 | if (!root.next) {
334 | root.next = cxg_rootp;
335 | cxg_rootp = &root;
336 | LOAD();
337 | pc = obj_from_case(0);
338 | cxg_rc = 0;
339 | while (pc) pc = (*(cxhost_t*)pc)(pc);
340 | assert(cxg_rc == 2);
341 | }
342 | }
343 |
344 | /* basic runtime */
345 | #define HEAP_SIZE 131072 /* 2^17 */
346 | #define REGS_SIZE 4092
347 |
348 | obj *cxg_heap = NULL;
349 | cxoint_t cxg_hmask = 0;
350 | obj *cxg_hp = NULL;
351 | static cxroot_t cxg_root = { 0, NULL, NULL };
352 | cxroot_t *cxg_rootp = &cxg_root;
353 | obj *cxg_regs = NULL, *cxg_rend = NULL;
354 | int cxg_rc = 0;
355 | char **cxg_argv = NULL;
356 |
357 | static obj *cxg_heap2 = NULL;
358 | static size_t cxg_hsize = 0;
359 | static cxoint_t cxg_hmask2 = 0;
360 | static int cxg_gccount = 0, cxg_bumpcount = 0;
361 |
362 | static obj *toheap2(obj* p, obj *hp, obj *h1, cxoint_t m1, obj *h2, cxoint_t m2)
363 | {
364 | obj o = *p, *op, fo, *fop;
365 | if (((char*)(o) - (char*)h1) & m1) return hp;
366 | fo = (op = objptr_from_obj(o))[-1]; assert(fo);
367 | if (notaptr(fo)) {
368 | fop = op + size_from_obj(fo); while (fop >= op) *--hp = *--fop;
369 | *p = *fop = obj_from_objptr(hp+1);
370 | } else if (((char*)(fo) - (char*)h2) & m2) {
371 | *--hp = *op--; *--hp = *op;
372 | *p = *op = obj_from_objptr(hp+1);
373 | } else *p = fo;
374 | return hp;
375 | }
376 |
377 | static void finalize(obj *hp1, obj *he1, obj *h2, cxoint_t m2)
378 | {
379 | while (hp1 < he1) {
380 | obj fo = *hp1++; assert(fo);
381 | if (notaptr(fo)) hp1 += size_from_obj(fo);
382 | else if (((char*)(fo) - (char*)h2) & m2) ((cxtype_t*)fo)->free((void*)*hp1++);
383 | else if (notaptr(fo = objptr_from_obj(fo)[-1])) hp1 += size_from_obj(fo);
384 | else ++hp1;
385 | } assert(hp1 == he1);
386 | }
387 |
388 | static obj *relocate(cxroot_t *pr, obj *regs, obj *regp,
389 | obj *he2, obj *he1, obj *hp, obj *h1, cxoint_t m1, obj *h2, cxoint_t m2)
390 | {
391 | obj *p, *hp1 = hp; hp = he2;
392 | for (p = regs; p < regp; ++p) hp = toheap2(p, hp, h1, m1, h2, m2);
393 | for (; pr; pr = pr->next) {
394 | obj **pp = pr->globv; int c = pr->globc;
395 | while (c-- > 0) hp = toheap2(*pp++, hp, h1, m1, h2, m2);
396 | }
397 | for (p = he2; p > hp; --p) hp = toheap2(p-1, hp, h1, m1, h2, m2);
398 | if (he1) finalize(hp1, he1, h2, m2);
399 | return hp;
400 | }
401 |
402 | obj *cxm_hgc(obj *regs, obj *regp, obj *hp, size_t needs)
403 | {
404 | obj *h1 = cxg_heap, *h2 = cxg_heap2; cxoint_t m1 = cxg_hmask, m2 = cxg_hmask2;
405 | size_t hs = cxg_hsize; cxroot_t *pr = cxg_rootp;
406 |
407 | obj *h = h1, *he1 = h1 + hs, *he2 = h2 + hs;
408 | ++cxg_gccount;
409 | if (h1) hp = relocate(pr, regs, regp, he2, he1, hp, h1, m1, h2, m2),
410 | needs += (h2 + hs - hp)*2; /* make heap half empty */
411 | else hp = h2 + hs;
412 | if (hs < needs) {
413 | size_t s = HEAP_SIZE; while (s < needs) s *= 2;
414 | m2 = 1 | ~(s*sizeof(obj)-1);
415 | if (!(h = realloc(h1, s*sizeof(obj)))) { perror("alloc[h]"); exit(2); }
416 | h1 = h2; h2 = h; he2 = h2 + s; he1 = 0; /* no finalize flag */
417 | if (h1) hp = relocate(pr, regs, regp, he2, he1, hp, h1, m1, h2, m2);
418 | else hp = h2 + s;
419 | if (!(h = realloc(h1, s*sizeof(obj)))) { perror("alloc[h]"); exit(2); }
420 | hs = s; m1 = m2; ++cxg_bumpcount;
421 | }
422 | h1 = h2; h2 = h;
423 |
424 | cxg_heap = h1; cxg_hmask = m1; cxg_heap2 = h2; cxg_hmask2 = m2;
425 | cxg_hsize = hs; return cxg_hp = hp;
426 | }
427 |
428 | obj *cxm_rgc(obj *regs, size_t needs)
429 | {
430 | obj *p = cxg_regs; assert(needs > 0);
431 | if (!p || cxg_rend < p + needs) {
432 | size_t roff = regs ? regs - p : 0;
433 | if (!(p = realloc(p, needs*sizeof(obj)))) { perror("alloc[r]"); exit(2); }
434 | cxg_regs = p; cxg_rend = p + needs;
435 | regs = p + roff;
436 | }
437 | if (regs && regs > p) while (needs--) *p++ = *regs++;
438 | return cxg_regs;
439 | }
440 |
441 | void cxm_check(int x, char *msg)
442 | {
443 | if (!x) {
444 | perror(msg); exit(2);
445 | }
446 | }
447 |
448 | void *cxm_cknull(void *p, char *msg)
449 | {
450 | cxm_check(p != NULL, msg);
451 | return p;
452 | }
453 |
454 | /* os entry point */
455 | int main(int argc, char **argv) {
456 | int res; obj pc;
457 | obj retcl[1] = { 0 };
458 | cxm_rgc(NULL, REGS_SIZE);
459 | cxg_argv = argv;
460 | MODULE();
461 | cxg_regs[0] = cx_main;
462 | cxg_regs[1] = (obj)retcl;
463 | cxg_regs[2] = (obj)argv;
464 | cxg_rc = 3;
465 | pc = objptr_from_obj(cx_main)[0];
466 | while (pc) pc = (*(cxhost_t*)pc)(pc);
467 | assert(cxg_rc == 3);
468 | res = (cxg_regs[2] != 0);
469 | /* fprintf(stderr, "%d collections, %d reallocs\n", cxg_gccount, cxg_bumpcount); */
470 | return res;
471 | }
472 |
--------------------------------------------------------------------------------
/examples/hello.sf:
--------------------------------------------------------------------------------
1 | ; obligatory hello world example
2 |
3 | (define main
4 | (lambda (argv)
5 | (%prim! "void(printf(\"Hello, World!\\n\"))")))
6 |
7 |
8 |
--------------------------------------------------------------------------------
/examples/stak.sf:
--------------------------------------------------------------------------------
1 |
2 | ; Takeuchi benchmark (strings)
3 |
4 | ; we'll need let-syntax and internal definitions, so let's define them first
5 |
6 | (define-syntax let-syntax
7 | (syntax-rules ()
8 | [(_ ([kw init] ...)) (begin)]
9 | [(_ ([kw init] ...) . body) ((syntax-lambda (kw ...) . body) init ...)]))
10 |
11 | (define-syntax letrec-syntax
12 | (let-syntax ([let-syntax let-syntax] [define-syntax define-syntax])
13 | (syntax-rules ()
14 | [(_ ([kw init] ...) . body)
15 | (let-syntax ()
16 | (define-syntax kw init) ... (let-syntax () . body))])))
17 |
18 | (define-syntax lambda
19 | (let-syntax ([old-lambda lambda])
20 | (syntax-rules () [(_ args . body) (old-lambda args (let-syntax () . body))])))
21 |
22 | (define-syntax define
23 | (let-syntax ([old-define define])
24 | (letrec-syntax
25 | ([new-define
26 | (syntax-rules ()
27 | [(_ exp) (old-define exp)]
28 | [(_ (var-or-prototype . args) . body)
29 | (new-define var-or-prototype (lambda args . body))]
30 | [(_ . other) (old-define . other)])])
31 | new-define)))
32 |
33 | (define-syntax define-inline
34 | (syntax-rules ()
35 | [(_ (op . ll) . body)
36 | (define-syntax op (lambda ll . body))]
37 | [(_ op val)
38 | (define-syntax op val)]))
39 |
40 | (define-syntax define-rule
41 | (syntax-rules ()
42 | [(_ (op . pat) . body)
43 | (define-syntax op (syntax-rule pat . body))]))
44 |
45 | (define-syntax let
46 | (syntax-rules ()
47 | [(_ ([var init] ...) . body)
48 | ((lambda (var ...) . body) init ...)]
49 | [(_ name ([var init] ...) . body)
50 | ((letrec ([name (lambda (var ...) . body)])
51 | name)
52 | init ...)]))
53 |
54 | (define-syntax let*
55 | (syntax-rules ()
56 | [(_ () . body) (let () . body)]
57 | [(_ ([var init] . bindings) . body)
58 | (let ([var init]) (let* bindings . body))]))
59 |
60 | (define-syntax letrec
61 | (syntax-rules ()
62 | [(_ ([var init] ...) . body)
63 | (let () (define var init) ... (let () . body))]))
64 |
65 | (define-syntax do
66 | (let-syntax ([do-step (syntax-rules () [(_ x) x] [(_ x y) y])])
67 | (syntax-rules ()
68 | [(_ ([var init step ...] ...)
69 | [test expr ...]
70 | command ...)
71 | (let loop ([var init] ...)
72 | (if test
73 | (begin (if #f #f) expr ...)
74 | (let ()
75 | command ...
76 | (loop (do-step var step ...) ...))))])))
77 |
78 |
79 | ; Let's make immediate objects from 7-bit tag followed by 24 bits of data
80 | ; tag bits follow lsb which is 1 in all SFC's non-pointer objects
81 |
82 | (%definition "/* immediate object representation */")
83 | (%definition "#define isimm(o, t) (((o) & 0xff) == (((t) << 1) | 1))")
84 | (%definition "#define getimmu(o, t) (int)(((o) >> 8) & 0xffffff)")
85 | (%definition "#define getimms(o, t) (int)(((((o) >> 8) & 0xffffff) ^ 0x800000) - 0x800000)")
86 | (%definition "#define mkimm(o, t) ((((o) & 0xffffff) << 8) | ((t) << 1) | 1)")
87 |
88 |
89 | ; native blocks are 1-element blocks containing a native
90 | ; (non-scheme) pointer as 0th element and cxtype ptr in block header
91 |
92 | (%localdef "#ifndef NDEBUG
93 | int isnative(obj o, cxtype_t *tp) {
94 | return isobjptr(o) && objptr_from_obj(o)[-1] == (obj)tp;
95 | }
96 | void *getnative(obj o, cxtype_t *tp) {
97 | assert(isnative(o, tp));
98 | return (void*)(*objptr_from_obj(o));
99 | }
100 | #endif")
101 |
102 | (%definition "#ifdef NDEBUG
103 | static int isnative(obj o, cxtype_t *tp)
104 | { return isobjptr(o) && objptr_from_obj(o)[-1] == (obj)tp; }
105 | #define getnative(o, t) ((void*)(*objptr_from_obj(o)))
106 | #else
107 | extern int isnative(obj o, cxtype_t *tp);
108 | extern void *getnative(obj o, cxtype_t *tp);
109 | #endif")
110 |
111 |
112 | ; booleans
113 | ; #f is hardwired as (obj)0; let's represent #t as immediate 0 with tag 0
114 | ; this layout is compatible with C conventions (0 = false, 1 = true)
115 | ; note that any obj but #f is counted as true in conditionals and that
116 | ; bool_from_obj and bool_from_bool are already defined in std prelude
117 |
118 | (%definition "/* booleans */")
119 | (%definition "#define TRUE_ITAG 0")
120 | (%definition "typedef int bool_t;")
121 | (%definition "#define is_bool_obj(o) (!((o) & ~(obj)1))")
122 | (%definition "#define is_bool_bool(b) ((b), 1)")
123 | (%definition "#define void_from_bool(b) (void)(b)")
124 | (%definition "#define obj_from_bool(b) ((b) ? mkimm(0, TRUE_ITAG) : 0)")
125 |
126 | ; boolean literals
127 | (define-syntax %const
128 | (let-syntax ([old-%const %const])
129 | (syntax-rules (boolean)
130 | [(_ boolean b) (%prim ("bool(" b ")"))]
131 | [(_ arg ...) (old-%const arg ...)])))
132 |
133 | ; some functions we might need, inlined for speed
134 | (define-syntax not (syntax-rules () [(_ x) (%prim "bool(!bool_from_$arg)" x)]))
135 |
136 | ; fixnums
137 | ; let's represent fixnums as (24-bit) immediates with tag 1
138 |
139 | (%definition "/* fixnums */")
140 | (%definition "#define FIXNUM_ITAG 1")
141 | (%definition "typedef int fixnum_t;")
142 | (%definition "#define is_fixnum_obj(o) (isimm(o, FIXNUM_ITAG))")
143 | (%definition "#define is_fixnum_fixnum(i) ((i), 1)")
144 | (%definition "#define fixnum_from_obj(o) (getimms(o, FIXNUM_ITAG))")
145 | (%definition "#define fixnum_from_fixnum(i) (i)")
146 | (%definition "#define void_from_fixnum(i) (void)(i)")
147 | (%definition "#define obj_from_fixnum(i) mkimm(i, FIXNUM_ITAG)")
148 | (%definition "#define FIXNUM_MIN -8388608")
149 | (%definition "#define FIXNUM_MAX 8388607")
150 |
151 | ; fixnum literals
152 | (define-syntax %const
153 | (let-syntax ([old-%const %const])
154 | (syntax-rules (integer + -)
155 | [(_ integer 8 + digs 10) (%prim ("fixnum(" digs ")"))]
156 | [(_ integer 16 + digs 10) (%prim ("fixnum(" digs ")"))]
157 | [(_ integer 24 + digs 10) (%prim ("fixnum(" digs ")"))]
158 | [(_ integer 8 - digs 10) (%prim ("fixnum(-" digs ")"))]
159 | [(_ integer 16 - digs 10) (%prim ("fixnum(-" digs ")"))]
160 | [(_ integer 24 - digs 10) (%prim ("fixnum(-" digs ")"))]
161 | [(_ arg ...) (old-%const arg ...)])))
162 |
163 | ; functions we will need for stak, as inlined primitives
164 | (define-syntax + (syntax-rules () [(_ x y) (%prim "fixnum(fixnum_from_$arg + fixnum_from_$arg)" x y)]))
165 | (define-syntax - (syntax-rules () [(_ x y) (%prim "fixnum(fixnum_from_$arg - fixnum_from_$arg)" x y)]))
166 | (define-syntax < (syntax-rules () [(_ x y) (%prim "bool(fixnum_from_$arg < fixnum_from_$arg)" x y)]))
167 | (define-syntax > (syntax-rules () [(_ x y) (%prim "bool(fixnum_from_$arg > fixnum_from_$arg)" x y)]))
168 | (define-syntax = (syntax-rules () [(_ x y) (%prim "bool(fixnum_from_$arg == fixnum_from_$arg)" x y)]))
169 | (define-syntax <= (syntax-rules () [(_ x y) (%prim "bool(fixnum_from_$arg <= fixnum_from_$arg)" x y)]))
170 | (define-syntax >= (syntax-rules () [(_ x y) (%prim "bool(fixnum_from_$arg >= fixnum_from_$arg)" x y)]))
171 |
172 |
173 | ; characters
174 |
175 | (%include )
176 |
177 | (%definition "/* characters */")
178 | (%definition "#define CHAR_ITAG 2")
179 | (%definition "typedef int char_t;")
180 | (%definition "#define is_char_obj(o) (isimm(o, CHAR_ITAG))")
181 | (%definition "#define is_char_char(i) ((i), 1)")
182 | (%definition "#define char_from_obj(o) (getimms(o, CHAR_ITAG))")
183 | (%definition "#define char_from_char(i) (i)")
184 | (%definition "#define void_from_char(i) (void)(i)")
185 | (%definition "#define obj_from_char(i) mkimm(i, CHAR_ITAG)")
186 |
187 |
188 | ; strings
189 |
190 | (%include )
191 |
192 | (%definition "/* strings */")
193 | (%localdef "static cxtype_t cxt_string = { \"string\", free };")
194 | (%localdef "cxtype_t *STRING_NTAG = &cxt_string;")
195 | (%definition "extern cxtype_t *STRING_NTAG;")
196 | (%definition "#define isstring(o) (isnative(o, STRING_NTAG))")
197 | (%definition "#define stringdata(o) ((char*)getnative(o, STRING_NTAG))")
198 | (%definition "#define mkstring(l, n, c) hpushptr(allocstring(n, c), STRING_NTAG, l)")
199 | (%definition "#define cpstring(l, s) hpushptr(dupstring(s), STRING_NTAG, l)")
200 | (%definition "extern char *dupstring(char *s);")
201 | (%localdef "char *dupstring(char *s) {
202 | assert(s); return strcpy(cxm_cknull(malloc(strlen(s)+1), \"malloc(string)\"), s);
203 | }")
204 | (%definition "extern char *allocstring(int n, int c);")
205 | (%localdef "char *allocstring(int n, int c) {
206 | char *s; assert(n+1 > 0);
207 | s = cxm_cknull(malloc(n+1), \"malloc(string)\");
208 | memset(s, c, n); s[n] = 0;
209 | return s;
210 | }")
211 |
212 | (%localdef "#ifndef NDEBUG
213 | int stringlen(obj o) {
214 | char *s = stringdata(o);
215 | return (int)strlen(s);
216 | }
217 | char* stringref(obj o, int i) {
218 | char *s = stringdata(o);
219 | int l = (int)strlen(s);
220 | assert(i >= 0 && i < l);
221 | return s+i;
222 | }
223 | #endif")
224 |
225 | (%definition "#ifdef NDEBUG
226 | #define stringlen(o) ((int)strlen(stringdata(o)))
227 | #define stringref(o, i) (stringdata(o)+(i))
228 | #else
229 | extern int stringlen(obj o);
230 | extern char* stringref(obj o, int i);
231 | #endif")
232 |
233 | (%definition "extern int strcmp_ci(char *s1, char*s2);")
234 | (%localdef "int strcmp_ci(char *s1, char *s2) {
235 | int c1, c2, d;
236 | do { c1 = *s1++; c2 = *s2++; d = (unsigned)tolower(c1) - (unsigned)tolower(c2); }
237 | while (!d && c1 && c2);
238 | return d;
239 | }")
240 |
241 | (define-syntax %const
242 | (let-syntax ([old-%const %const])
243 | (syntax-rules (string)
244 | [(_ string s)
245 | (%prim* ("obj(cpstring($live, \"" s "\"))"))]
246 | [(_ string 8 c ...)
247 | (%prim* ("{ static char s[] = { " (c ", ") ... "0 };\n"
248 | " $return obj(cpstring($live, s)); }"))]
249 | [(_ arg ...) (old-%const arg ...)])))
250 |
251 | (define-inline (string? x)
252 | (%prim "bool(isstring(obj_from_$arg))" x))
253 |
254 | (define-syntax make-string
255 | (syntax-rules ()
256 | [(_ k) (%prim* "obj(mkstring($live, fixnum_from_$arg, '?'))" k)]
257 | [(_ k c) (%prim* "obj(mkstring($live, fixnum_from_$arg, char_from_$arg))" k c)]))
258 |
259 | (define-rule (string c ...)
260 | (%prim* "{ /* string */
261 | obj o = mkstring($live, $argc, ' ');
262 | char *s = stringdata(o);
263 | ${*s++ = char_from_$arg;
264 | $}$return obj(o); }" c ...))
265 |
266 | (define-inline (string-length s)
267 | (%prim "fixnum(stringlen(obj_from_$arg))" s))
268 |
269 | (define-inline (string-ref s k)
270 | (%prim? "char(*stringref(obj_from_$arg, fixnum_from_$arg))" s k))
271 |
272 | (define-inline (string-set! s k c)
273 | (%prim! "void(*stringref(obj_from_$arg, fixnum_from_$arg) = char_from_$arg)" s k c))
274 |
275 | (define-inline (string=? x y)
276 | (%prim? "bool(strcmp(stringdata(obj_from_$arg), stringdata(obj_from_$arg)) == 0)" x y))
277 |
278 | (define-inline (string x y)
279 | (%prim? "bool(strcmp(stringdata(obj_from_$arg), stringdata(obj_from_$arg)) < 0)" x y))
280 |
281 | (define (substring s start end)
282 | (let* ([k (- end start)] [ss (make-string k)])
283 | (do ([i 0 (+ i 1)]) [(>= i k) ss]
284 | (string-set! ss i (string-ref s (+ start i))))))
285 |
286 | (define (string-append a b)
287 | (let ([al (string-length a)] [bl (string-length b)])
288 | (let ([s (make-string (+ al bl))])
289 | (do ([i 0 (+ i 1)]) [(>= i al)]
290 | (string-set! s i (string-ref a i)))
291 | (do ([i 0 (+ i 1)]) [(>= i bl)]
292 | (string-set! s (+ al i) (string-ref b i)))
293 | s)))
294 |
295 | (define-inline (string-copy s)
296 | (%prim*? "obj(cpstring($live, stringdata(obj_from_$arg)))" s))
297 |
298 | (define (string-fill! s c)
299 | (let ([n (string-length s)])
300 | (do ([i 0 (+ i 1)]) [(= i n)]
301 | (string-set! s i c))))
302 |
303 |
304 | ; minimalistic i/o, also inlined
305 | (define-syntax display (syntax-rules () [(_ x) (%prim! "void(fputs(stringdata(obj_from_$arg), stdout))" x)]))
306 | (define-syntax newline (syntax-rules () [(_) (%prim! "void(putchar('\\n'))")]))
307 |
308 |
309 | ; the test itself
310 |
311 |
312 | ; "arithmetic" with strings of stars
313 |
314 | (define (string- s1 s2)
315 | (let ([l1 (string-length s1)] [l2 (string-length s2)])
316 | (substring s1 0 (- l1 l2))))
317 |
318 | (define (string+ s1 s2)
319 | (string-append s1 s2))
320 |
321 | (define s18 "******************")
322 | (define s16 "****************")
323 | (define s14 "**************")
324 | (define s12 "************")
325 | (define s10 "**********")
326 | (define s8 "********")
327 | (define s6 "******")
328 | (define s4 "****")
329 | (define s2 "**")
330 | (define s1 "*")
331 | (define s0 "")
332 | (define s20 (string+ s10 s10))
333 | (define s40 (string+ s20 s20))
334 | (define s80 (string+ s40 s40))
335 | (define s100 (string+ s80 s20))
336 |
337 | (define tak
338 | (lambda (x y z)
339 | (if (string y x)
340 | (tak (tak (string- x s1) y z)
341 | (tak (string- y s1) z x)
342 | (tak (string- z s1) x y))
343 | z)))
344 |
345 | (define runtak
346 | (lambda (n r)
347 | (if (string=? n s0)
348 | r
349 | (runtak (string- n s1) (string+ r (tak s18 s12 s6))))))
350 |
351 | (define main
352 | (lambda (argv)
353 | (display (runtak s100 s0))
354 | (newline)))
355 |
356 |
--------------------------------------------------------------------------------
/examples/tak.sf:
--------------------------------------------------------------------------------
1 |
2 | ; Takeuchi benchmark (fixnums)
3 |
4 | ; we'll need let-syntax and internal definitions, so let's define them first
5 |
6 | (define-syntax let-syntax
7 | (syntax-rules ()
8 | [(_ ([kw init] ...)) (begin)]
9 | [(_ ([kw init] ...) . body) ((syntax-lambda (kw ...) . body) init ...)]))
10 |
11 | (define-syntax lambda
12 | (let-syntax ([old-lambda lambda])
13 | (syntax-rules () [(_ args . body) (old-lambda args (let-syntax () . body))])))
14 |
15 |
16 | ; SFC's immediate objects have 7-bit tag followed by 24 bits of data
17 | ; subtype bits follow lsb which is 1 in non-pointer objects
18 |
19 | (%definition "/* immediate object representation */")
20 | (%definition "#define isimm(o, t) (((o) & 0xff) == (((t) << 1) | 1))")
21 | (%definition "#define getimmu(o, t) (int)(((o) >> 8) & 0xffffff)")
22 | (%definition "#define getimms(o, t) (int)(((((o) >> 8) & 0xffffff) ^ 0x800000) - 0x800000)")
23 | (%definition "#define mkimm(o, t) ((((o) & 0xffffff) << 8) | ((t) << 1) | 1)")
24 |
25 | ; booleans
26 | ; #f is hardwired as (obj)0; let's represent #t as immediate 0 with tag 0
27 | ; this layout is compatible with C conventions (0 = false, 1 = true)
28 | ; note that any obj but #f is counted as true in conditionals and that
29 | ; bool_from_obj and bool_from_bool are already defined in std prelude
30 |
31 | (%definition "/* booleans */")
32 | (%definition "#define TRUE_ITAG 0")
33 | (%definition "typedef int bool_t;")
34 | (%definition "#define is_bool_obj(o) (!((o) & ~(obj)1))")
35 | (%definition "#define is_bool_bool(b) ((b), 1)")
36 | (%definition "#define void_from_bool(b) (void)(b)")
37 | (%definition "#define obj_from_bool(b) ((b) ? mkimm(0, TRUE_ITAG) : 0)")
38 |
39 | ; boolean literals
40 | (define-syntax %const
41 | (let-syntax ([old-%const %const])
42 | (syntax-rules (boolean)
43 | [(_ boolean b) (%prim ("bool(" b ")"))]
44 | [(_ arg ...) (old-%const arg ...)])))
45 |
46 | ; some functions we might need, inlined for speed
47 | (define-syntax not (syntax-rules () [(_ x) (%prim "bool(!bool_from_$arg)" x)]))
48 |
49 | ; fixnums
50 | ; let's represent fixnums as (24-bit) immediates with tag 1
51 |
52 | (%definition "/* fixnums */")
53 | (%definition "#define FIXNUM_ITAG 1")
54 | (%definition "typedef int fixnum_t;")
55 | (%definition "#define is_fixnum_obj(o) (isimm(o, FIXNUM_ITAG))")
56 | (%definition "#define is_fixnum_fixnum(i) ((i), 1)")
57 | (%definition "#define fixnum_from_obj(o) (getimms(o, FIXNUM_ITAG))")
58 | (%definition "#define fixnum_from_fixnum(i) (i)")
59 | (%definition "#define void_from_fixnum(i) (void)(i)")
60 | (%definition "#define obj_from_fixnum(i) mkimm(i, FIXNUM_ITAG)")
61 | (%definition "#define FIXNUM_MIN -8388608")
62 | (%definition "#define FIXNUM_MAX 8388607")
63 |
64 | ; fixnum literals (decimal)
65 | (define-syntax %const
66 | (let-syntax ([old-%const %const])
67 | (syntax-rules (integer + -)
68 | [(_ integer 8 + digs 10) (%prim ("fixnum(" digs ")"))]
69 | [(_ integer 16 + digs 10) (%prim ("fixnum(" digs ")"))]
70 | [(_ integer 24 + digs 10) (%prim ("fixnum(" digs ")"))]
71 | [(_ integer 8 - digs 10) (%prim ("fixnum(-" digs ")"))]
72 | [(_ integer 16 - digs 10) (%prim ("fixnum(-" digs ")"))]
73 | [(_ integer 24 - digs 10) (%prim ("fixnum(-" digs ")"))]
74 | [(_ arg ...) (old-%const arg ...)])))
75 |
76 | ; functions we will need for tak, inlined for speed
77 | (define-syntax + (syntax-rules () [(_ x y) (%prim "fixnum(fixnum_from_$arg + fixnum_from_$arg)" x y)]))
78 | (define-syntax - (syntax-rules () [(_ x y) (%prim "fixnum(fixnum_from_$arg - fixnum_from_$arg)" x y)]))
79 | (define-syntax * (syntax-rules () [(_ x y) (%prim "fixnum(fixnum_from_$arg * fixnum_from_$arg)" x y)]))
80 | (define-syntax < (syntax-rules () [(_ x y) (%prim "bool(fixnum_from_$arg < fixnum_from_$arg)" x y)]))
81 | (define-syntax = (syntax-rules () [(_ x y) (%prim "bool(fixnum_from_$arg == fixnum_from_$arg)" x y)]))
82 |
83 | ; minimalistic i/o, also inlined
84 | (define-syntax write (syntax-rules () [(_ x) (%prim! "void(printf(\"%d\", fixnum_from_$arg))" x)]))
85 | (define-syntax newline (syntax-rules () [(_) (%prim! "void(putchar('\\n'))")]))
86 |
87 | ; the test itself
88 |
89 | (define tak
90 | (lambda (x y z)
91 | (if (< y x)
92 | (tak (tak (- x 1) y z)
93 | (tak (- y 1) z x)
94 | (tak (- z 1) x y))
95 | z)))
96 |
97 | (define runtak
98 | (lambda (n r)
99 | (if (= n 0)
100 | r
101 | (runtak (- n 1) (+ r (tak 18 12 6))))))
102 |
103 | (define main
104 | (lambda (argv)
105 | (write (runtak 10000 0))
106 | (newline)))
107 |
--------------------------------------------------------------------------------
/examples/tfun.sf:
--------------------------------------------------------------------------------
1 |
2 | #fload "tlib.sf"
3 |
4 | ; fixnum tak
5 |
6 | (define (tak x y z)
7 | (if (< y x)
8 | (tak (tak (- x 1) y z)
9 | (tak (- y 1) z x)
10 | (tak (- z 1) x y))
11 | z))
12 |
13 |
14 | ; list tak
15 |
16 | (define (listn n)
17 | (if (= 0 n)
18 | '()
19 | (cons n (listn (- n 1)))) )
20 |
21 | (define (length l)
22 | (define (length-aux l n)
23 | (if (pair? l)
24 | (length-aux (cdr l) (+ n 1))
25 | n))
26 | (length-aux l 0))
27 |
28 | (define (shorterp x y)
29 | (and (pair? y)
30 | (or (null? x)
31 | (shorterp (cdr x) (cdr y)))))
32 |
33 | (define l18 (listn 18))
34 | (define l12 (listn 12))
35 | (define l6 (listn 6))
36 |
37 | (define (ltak x y z)
38 | (if (not (shorterp y x))
39 | z
40 | (ltak (ltak (cdr x) y z)
41 | (ltak (cdr y) z x)
42 | (ltak (cdr z) x y))))
43 |
--------------------------------------------------------------------------------
/examples/tlib.sf:
--------------------------------------------------------------------------------
1 |
2 | ; we'll need more realistic syntax, so let's extend the minimalistic core set of
3 | ; simpilfied begin, define, define-syntax, if, lambda, quote, set!, syntax-rules,
4 | ; and syntax-lambda
5 |
6 | (define-syntax let-syntax
7 | (syntax-rules ()
8 | [(_ ([kw init] ...)) (begin)]
9 | [(_ ([kw init] ...) . body) ((syntax-lambda (kw ...) . body) init ...)]))
10 |
11 | (define-syntax letrec-syntax
12 | (let-syntax ([let-syntax let-syntax] [define-syntax define-syntax])
13 | (syntax-rules ()
14 | [(_ ([kw init] ...) . body)
15 | (let-syntax () (define-syntax kw init) ... (let-syntax () . body))])))
16 |
17 | (define-syntax lambda
18 | (let-syntax ([old-lambda lambda])
19 | (syntax-rules () [(_ args . body) (old-lambda args (let-syntax () . body))])))
20 |
21 | (define-syntax define
22 | (let-syntax ([old-define define])
23 | (letrec-syntax
24 | ([new-define
25 | (syntax-rules ()
26 | [(_ exp) (old-define exp)]
27 | [(_ (var-or-prototype . args) . body)
28 | (new-define var-or-prototype (lambda args . body))]
29 | [(_ . other) (old-define . other)])])
30 | new-define)))
31 |
32 | (define-syntax let
33 | (syntax-rules ()
34 | [(_ ([var init] ...) . body)
35 | ((lambda (var ...) . body) init ...)]
36 | [(_ name ([var init] ...) . body)
37 | ((letrec ([name (lambda (var ...) . body)])
38 | name)
39 | init ...)]))
40 |
41 | (define-syntax letrec
42 | (syntax-rules ()
43 | [(_ ([var init] ...) . body)
44 | (let () (define var init) ... (let () . body))]))
45 |
46 | (define-syntax and
47 | (syntax-rules ()
48 | [(_) #t]
49 | [(_ test) (let () test)]
50 | [(_ test . tests) (if test (and . tests) #f)]))
51 |
52 | (define-syntax or
53 | (syntax-rules ()
54 | [(_) #f]
55 | [(_ test) (let () test)]
56 | [(_ test . tests) (let ([x test]) (if x x (or . tests)))]))
57 |
58 | ; extra syntax to simplify primitive definitions
59 |
60 | (define-syntax define-inline
61 | (syntax-rules ()
62 | [(_ (op . ll) . body)
63 | (define-syntax op (lambda ll . body))]
64 | [(_ op val)
65 | (define-syntax op val)]))
66 |
67 | (define-syntax define-integrable
68 | (syntax-rules ()
69 | [(_ (op . ll) . body)
70 | (define-syntax op
71 | (%quote (letrec ([op (lambda ll . body)]) op)))]))
72 |
73 | (define-syntax define-rule
74 | (syntax-rules ()
75 | [(_ (op . pat) . body)
76 | (define-syntax op (syntax-rule pat . body))]))
77 |
78 | (define-syntax %prim*/rev
79 | (letrec-syntax
80 | ([loop
81 | (syntax-rules ()
82 | [(_ prim () args)
83 | (%prim* prim . args)]
84 | [(_ prim (arg . more) args)
85 | (loop prim more (arg . args))])])
86 | (syntax-rules ()
87 | [(_ prim arg ...)
88 | (loop prim (arg ...) ())])))
89 |
90 |
91 | ; SFC's immediate objects have 7-bit tag followed by 24 bits of data
92 | ; subtype bits follow lsb which is 1 in non-pointer objects
93 |
94 | (%definition "/* immediate object representation */")
95 | (%definition "#define isimm(o, t) (((o) & 0xff) == (((t) << 1) | 1))")
96 | (%definition "#define getimmu(o, t) (int)(((o) >> 8) & 0xffffff)")
97 | (%definition "#define getimms(o, t) (int)(((((o) >> 8) & 0xffffff) ^ 0x800000) - 0x800000)")
98 | (%definition "#define mkimm(o, t) ((((o) & 0xffffff) << 8) | ((t) << 1) | 1)")
99 |
100 |
101 | ; SFC's tagged blocks are heap blocks with immediate object as 0th element
102 | ; (disjoint from closures which have a pointer as 0th element)
103 |
104 | (%localdef "int istagged(obj o, int t) {
105 | return isobjptr(o) && hblklen(o) >= 1 && hblkref(o, 0) == obj_from_size(t);
106 | }")
107 |
108 | (%definition "extern int istagged(obj o, int t);")
109 | (%definition "#define cktagged(o, t) (o)")
110 | (%definition "#define taggedlen(o, t) (hblklen(o)-1) ")
111 | (%definition "#define taggedref(o, t, i) (&hblkref(o, (i)+1))")
112 |
113 |
114 | ; booleans
115 | ; #f is hardwired as (obj)0; let's represent #t as immediate 0 with tag 0
116 | ; this layout is compatible with C conventions (0 = false, 1 = true)
117 | ; note that any obj but #f is counted as true in conditionals
118 |
119 | (%definition "/* booleans */")
120 | (%definition "#define TRUE_ITAG 0")
121 | (%definition "typedef int bool_t;")
122 | (%definition "#define is_bool_obj(o) (!((o) & ~(obj)1))")
123 | (%definition "#define is_bool_bool(b) ((b), 1)")
124 | (%definition "#define void_from_bool(b) (void)(b)")
125 | (%definition "#define obj_from_bool(b) ((b) ? mkimm(0, TRUE_ITAG) : 0)")
126 |
127 | ; boolean literals
128 | (define-syntax %const
129 | (let-syntax ([old-%const %const])
130 | (syntax-rules (boolean)
131 | [(_ boolean b) (%prim ("bool(" b ")"))]
132 | [(_ arg ...) (old-%const arg ...)])))
133 |
134 | ; some functions we might need, inlined for speed
135 | (define-inline (not x) (%prim "bool(!bool_from_$arg)" x))
136 |
137 | ; fixnums
138 | ; let's represent fixnums as (24-bit) immediates with tag 1
139 |
140 | (%definition "/* fixnums */")
141 | (%definition "#define FIXNUM_ITAG 1")
142 | (%definition "typedef int fixnum_t;")
143 | (%definition "#define is_fixnum_obj(o) (isimm(o, FIXNUM_ITAG))")
144 | (%definition "#define is_fixnum_fixnum(i) ((i), 1)")
145 | (%definition "#define fixnum_from_obj(o) (getimms(o, FIXNUM_ITAG))")
146 | (%definition "#define fixnum_from_fixnum(i) (i)")
147 | (%definition "#define void_from_fixnum(i) (void)(i)")
148 | (%definition "#define obj_from_fixnum(i) mkimm(i, FIXNUM_ITAG)")
149 | (%definition "#define FIXNUM_MIN -8388608")
150 | (%definition "#define FIXNUM_MAX 8388607")
151 |
152 | ; fixnum literals (decimal)
153 | (define-syntax %const
154 | (let-syntax ([old-%const %const])
155 | (syntax-rules (integer + -)
156 | [(_ integer 8 + digs 10) (%prim ("fixnum(" digs ")"))]
157 | [(_ integer 16 + digs 10) (%prim ("fixnum(" digs ")"))]
158 | [(_ integer 24 + digs 10) (%prim ("fixnum(" digs ")"))]
159 | [(_ integer 8 - digs 10) (%prim ("fixnum(-" digs ")"))]
160 | [(_ integer 16 - digs 10) (%prim ("fixnum(-" digs ")"))]
161 | [(_ integer 24 - digs 10) (%prim ("fixnum(-" digs ")"))]
162 | [(_ arg ...) (old-%const arg ...)])))
163 |
164 | ; functions we will need for tak, inlined for speed
165 | (define-inline (+ x y) (%prim "fixnum(fixnum_from_$arg + fixnum_from_$arg)" x y))
166 | (define-inline (- x y) (%prim "fixnum(fixnum_from_$arg - fixnum_from_$arg)" x y))
167 | (define-inline (* x y) (%prim "fixnum(fixnum_from_$arg * fixnum_from_$arg)" x y))
168 | (define-inline (< x y) (%prim "bool(fixnum_from_$arg < fixnum_from_$arg)" x y))
169 | (define-inline (= x y) (%prim "bool(fixnum_from_$arg == fixnum_from_$arg)" x y))
170 |
171 |
172 | ; null
173 | ; () is immediate 0 with immediate tag 2 (singular null object)
174 |
175 | (%definition "/* null */")
176 | (%definition "#define NULL_ITAG 2")
177 | (%definition "#define mknull() mkimm(0, NULL_ITAG)")
178 | (%definition "#define isnull(o) ((o) == mkimm(0, NULL_ITAG))")
179 |
180 | ; null literal
181 | (define-syntax %const
182 | (let-syntax ([old-%const %const])
183 | (syntax-rules (null)
184 | [(_ null) (%prim "obj(mknull())")]
185 | [(_ arg ...) (old-%const arg ...)])))
186 |
187 | (define-inline (null? x) (%prim "bool(isnull(obj_from_$arg))" x))
188 |
189 |
190 | ; pairs and lists
191 | ; pairs are represented as tagged blocks with tag 1
192 |
193 | (%definition "/* pairs and lists */")
194 | (%definition "#define PAIR_BTAG 1")
195 | (%definition "#define ispair(o) istagged(o, PAIR_BTAG)")
196 | (%definition "#define car(o) *taggedref(o, PAIR_BTAG, 0)")
197 | (%definition "#define cdr(o) *taggedref(o, PAIR_BTAG, 1)")
198 |
199 | (define-inline (pair? o) (%prim "bool(ispair(obj_from_$arg))" o))
200 | (define-inline (car p) (%prim? "obj(car(obj_from_$arg))" p))
201 | (define-inline (cdr p) (%prim? "obj(cdr(obj_from_$arg))" p))
202 |
203 | (define-inline (cons a d)
204 | (%prim* "{ /* cons */
205 | hreserve(hbsz(3), $live); /* $live live regs */
206 | *--hp = obj_from_$arg;
207 | *--hp = obj_from_$arg;
208 | *--hp = obj_from_size(PAIR_BTAG);
209 | $return obj(hendblk(3)); }" d a))
210 |
211 | (define-rule (list i ...)
212 | (%prim*/rev "{ /* list */
213 | obj p = mknull();
214 | hreserve(hbsz(3)*$argc, $live); /* $live live regs */
215 | ${*--hp = p; *--hp = obj_from_$arg;
216 | *--hp = obj_from_size(PAIR_BTAG); p = hendblk(3);
217 | $}$return obj(p); }" i ...))
218 |
219 | ; pair/list literals
220 | (define-syntax %const
221 | (let-syntax ([old-%const %const])
222 | (syntax-rules (pair list)
223 | [(_ pair x y) (cons x y)]
224 | [(_ list x ...) (list x ...)]
225 | [(_ arg ...) (old-%const arg ...)])))
226 |
227 |
228 | ; minimalistic i/o, also inlined
229 | (define-inline (write x) (%prim! "void(printf(\"%d\", fixnum_from_$arg))" x))
230 | (define-inline (newline) (%prim! "void(putchar('\\n'))"))
231 |
232 | (define-integrable (sum a b) (+ a b))
233 |
234 | (define-integrable (sumlist l s)
235 | (if (null? l) s (sumlist (cdr l) (sum s (car l)))))
236 |
--------------------------------------------------------------------------------
/examples/tmain.sf:
--------------------------------------------------------------------------------
1 | #fload "tlib.sf"
2 | #fload "tfun.sf"
3 |
4 | (define (runtak n r)
5 | (if (= n 0)
6 | r
7 | (runtak (- n 1) (+ r (tak 18 12 6)))))
8 |
9 | (define (runltak n r)
10 | (if (= n 0)
11 | r
12 | (runltak (- n 1) (+ r (length (ltak l18 l12 l6))))))
13 |
14 | (define (main argv)
15 | (write (runtak 1000 0))
16 | (newline)
17 | (write (runltak 1000 0))
18 | (newline))
19 |
--------------------------------------------------------------------------------
/int/README.md:
--------------------------------------------------------------------------------
1 | # Interpreters for Compatibility Libraries
2 |
3 | This directory contains interpreters for #F compatibility libraries. Each interpreter is implemented as a single .sf file and needs to be compiled and linked with the corresponding library, e.g.
4 |
5 | ```
6 | $ sfc libs.sf ints.sf # sfc produces 2 C files
7 | $ gcc libs.c ints.c -lm # gcc produces a.out (libs refers to math functions, so -lm may be needed)
8 | ```
9 |
10 | ## IntS, an Interpreter for LibS (Small) Library
11 |
12 | IntS (see [ints.sf](https://raw.githubusercontent.com/false-schemers/sharpF/master/int/ints.sf)) allows interactive calling of LibS functions and use of LibS syntax forms, including `define-syntax` and `syntax-rules`. It provides full argument checking (LibS' own argument checking is limited to C asserts in debug mode).
13 |
14 | There are some restrictions on the functionality available in IntS, compared to the #F code compiled with LibS:
15 |
16 | * `read` uses LibS reader, limited to reading data types implemented in LibS
17 | * fixnum (`fx`) and flonum (`fl`) - specific operations are not available
18 | * C primitives and C code cannot be used
19 | * `main` can be defined, but is not called by the interpreter
20 |
21 | Since in IntS `load` is no longer a special form for separate compilation, it cannot be used to refer
22 | to arbitrary #F files - only to files that can be dynamically loaded and executed by the interpreter. If you want to 'mask' your compile-time `load` forms from the interpreter, you may use the `#fload "myfile.sf"` abbreviated form, which the interpreter ignores.
23 |
24 | Here is the list of IntS additions and things that behave differently between IntS and LibS:
25 |
26 | * single-argument `eval` is available (macroexpands, compiles, and executes the argument)
27 | * single-argument `expand` is available (macroexpands the argument)
28 | * `load` is a procedure that dynamically loads and interprets Scheme code via `eval`
29 | * command-line file arguments are dynamically loaded
30 | * there is a traditional REPL (read-eval-print loop)
31 |
32 |
33 | ## IntM, an Interpreter for LibM (Medium) Library
34 |
35 | IntM (see [intm.sf](https://raw.githubusercontent.com/false-schemers/sharpF/master/int/intm.sf)) is an extended version of IntS, based on LibM. It has the following additional functionality from R7RS-small:
36 |
37 | * support for bytevectors, with basic set of operations
38 | * support for `define-record-type` records
39 | * simple binary input from files and bytevectors
40 | * simple binary output to files and bytevectors
41 | * simple text output to/from strings
42 | * `let-values`, `let*-values`, `define-values`, `make-parameter`, `parameterize`
43 | * exceptions, errors, `guard` form
44 | * current port access procedures are parameters
45 | * additional r7rs math and port operations
46 |
47 |
48 | ## IntL, an Interpreter for LibL (Large) Library
49 |
50 | IntL (see [intl.sf](https://raw.githubusercontent.com/false-schemers/sharpF/master/int/intl.sf)) allows interactive calling of LibL functions and use of LibL syntax forms. In addition, provides full argument checking, `eval`, `load`, support for R7RS-small libraries, and interactive REPL.
51 |
52 | There are some differences in the functionality available in IntL, compared to the #F code compiled with LibL:
53 |
54 | * `read` uses LibL reader, limited to reading data types implemented in LibL
55 | * `read` supports R7RS notation for circular structures, but `eval` and `load` reject them
56 | * fixnum (`fx`) and flonum (`fl`) - specific operations are not available
57 | * C primitives and C code cannot be used
58 | * `main` can be defined, but is not called by the interpreter
59 |
60 | Here is the list of IntL additions and things that behave differently between IntL and LibL:
61 |
62 | * vectors are self-evaluating and don't need to be quoted
63 | * `syntax-error` reports the actual error, not the 'undefined identifier' error
64 | * support for R7RS libraries; IntL forms are available in the built-in `(sharpf base)` library
65 | * `-L` command-line option extends library search path; initial path is `./`
66 | * `cond-expand` is supported (checks against `(features)` and available libraries)
67 | * `environment` is supported; dynamically fetches library definitions from `.sld` files
68 | * `eval` is available (macroexpands, compiles, and executes the argument)
69 | * non-standard `expand` is available (macroexpands the argument)
70 | * `load` is a procedure that dynamically loads and interprets Scheme code via `eval`
71 | * `eval`, `load`, and `expand` accept optional environment argument
72 | * command-line file arguments are dynamically loaded
73 | * there is a traditional REPL (read-eval-print loop)
74 | * both `import` and `define-library` forms can be entered interactively into REPL
75 | * `features` procedure returns `(r7rs exact-closed sharpf sharpf-interpreter sharpf-intl)`
76 |
77 | Please note that IntL's interaction environment exposes bindings for all supported R7RS-small procedures and syntax forms directly, so there is no need to use `import`. In order to use `import` forms and `environment` procedure with R7RS-small libraries, you will need to copy the `scheme` folder with .sld files for the libraries to your system and make sure IntL can locate it (its library search path contains current directory by default and can be extended with the help of `-L` command line option).
78 |
--------------------------------------------------------------------------------
/int/scheme/README.md:
--------------------------------------------------------------------------------
1 | # Scheme Library Definitions
2 |
3 | This directory contains Scheme Library Definition (SLD) files to be used with IntL and SIOF interpreters.
4 | None of the files contain any definitions or expressions -- all of them just import and then re-export the necessary bindings from
5 | the built-in `(sharpf base)` library providing all supported R7RS-small procedures and syntax forms.
6 |
7 | NB: `(scheme r5rs-null)` definitions contained in `r5rs-null.sld` are used internally to assemble bindings
8 | for the `(null-environment 5)` environment.
9 |
--------------------------------------------------------------------------------
/int/scheme/base.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme base)
2 | (import (sharpf base))
3 | (export
4 | *
5 | +
6 | -
7 | ...
8 | /
9 | <
10 | <=
11 | =
12 | =>
13 | >
14 | >=
15 | _
16 | abs
17 | and
18 | append
19 | apply
20 | assoc
21 | assq
22 | assv
23 | begin
24 | binary-port?
25 | boolean=?
26 | boolean?
27 | bytevector
28 | bytevector-append
29 | bytevector-copy
30 | bytevector-copy!
31 | bytevector-length
32 | bytevector-u8-ref
33 | bytevector-u8-set!
34 | bytevector?
35 | caar
36 | cadr
37 | call-with-current-continuation
38 | call-with-port
39 | call-with-values
40 | call/cc
41 | car
42 | case
43 | cdar
44 | cddr
45 | cdr
46 | ceiling
47 | char->integer
48 | char-ready?
49 | char<=?
50 | char
51 | char=?
52 | char>=?
53 | char>?
54 | char?
55 | close-input-port
56 | close-output-port
57 | close-port
58 | complex?
59 | cond
60 | cond-expand
61 | cons
62 | current-error-port
63 | current-input-port
64 | current-output-port
65 | define
66 | define-record-type
67 | define-syntax
68 | define-values
69 | denominator
70 | do
71 | dynamic-wind
72 | else
73 | eof-object
74 | eof-object?
75 | eq?
76 | equal?
77 | eqv?
78 | error
79 | error-object-irritants
80 | error-object-message
81 | error-object?
82 | even?
83 | exact
84 | exact-integer-sqrt
85 | exact-integer?
86 | exact?
87 | expt
88 | features
89 | file-error?
90 | floor
91 | floor-quotient
92 | floor-remainder
93 | floor/
94 | flush-output-port
95 | for-each
96 | gcd
97 | get-output-bytevector
98 | get-output-string
99 | guard
100 | if
101 | include
102 | include-ci
103 | inexact
104 | inexact?
105 | input-port-open?
106 | input-port?
107 | integer->char
108 | integer?
109 | lambda
110 | lcm
111 | length
112 | let
113 | let*
114 | let*-values
115 | let-syntax
116 | let-values
117 | letrec
118 | letrec*
119 | letrec-syntax
120 | list
121 | list->string
122 | list->vector
123 | list-copy
124 | list-ref
125 | list-set!
126 | list-tail
127 | list?
128 | make-bytevector
129 | make-list
130 | make-parameter
131 | make-string
132 | make-vector
133 | map
134 | max
135 | member
136 | memq
137 | memv
138 | min
139 | modulo
140 | negative?
141 | newline
142 | not
143 | null?
144 | number->string
145 | number?
146 | numerator
147 | odd?
148 | open-input-bytevector
149 | open-input-string
150 | open-output-bytevector
151 | open-output-string
152 | or
153 | output-port-open?
154 | output-port?
155 | pair?
156 | parameterize
157 | peek-char
158 | peek-u8
159 | port?
160 | positive?
161 | procedure?
162 | quasiquote
163 | quote
164 | quotient
165 | raise
166 | raise-continuable
167 | rational?
168 | rationalize
169 | read-bytevector
170 | read-bytevector!
171 | read-char
172 | read-error?
173 | read-line
174 | read-string
175 | read-u8
176 | real?
177 | remainder
178 | reverse
179 | round
180 | set!
181 | set-car!
182 | set-cdr!
183 | square
184 | string
185 | string->list
186 | string->number
187 | string->symbol
188 | string->utf8
189 | string->vector
190 | string-append
191 | string-copy
192 | string-copy!
193 | string-fill!
194 | string-for-each
195 | string-length
196 | string-map
197 | string-ref
198 | string-set!
199 | string<=?
200 | string
201 | string=?
202 | string>=?
203 | string>?
204 | string?
205 | substring
206 | symbol->string
207 | symbol=?
208 | symbol?
209 | syntax-error
210 | syntax-rules
211 | textual-port?
212 | truncate
213 | truncate-quotient
214 | truncate-remainder
215 | truncate/
216 | u8-ready?
217 | unless
218 | unquote
219 | unquote-splicing
220 | utf8->string
221 | values
222 | vector
223 | vector->list
224 | vector->string
225 | vector-append
226 | vector-copy
227 | vector-copy!
228 | vector-fill!
229 | vector-for-each
230 | vector-length
231 | vector-map
232 | vector-ref
233 | vector-set!
234 | vector?
235 | when
236 | with-exception-handler
237 | write-bytevector
238 | write-char
239 | write-string
240 | write-u8
241 | zero?))
242 |
--------------------------------------------------------------------------------
/int/scheme/case-lambda.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme case-lambda)
2 | (import (only (sharpf base)
3 | case-lambda))
4 | (export
5 | case-lambda))
6 |
--------------------------------------------------------------------------------
/int/scheme/char.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme char)
2 | (import (only (sharpf base)
3 | char-alphabetic? char-ci<=? char-ci char-ci=? char-ci>=? char-ci>?
4 | char-downcase char-foldcase char-lower-case? char-numeric?
5 | char-upcase char-upper-case? char-whitespace? digit-value
6 | string-ci<=? string-ci string-ci=? string-ci>=? string-ci>?
7 | string-downcase string-foldcase string-upcase))
8 | (export
9 | char-alphabetic? char-ci<=? char-ci char-ci=? char-ci>=? char-ci>?
10 | char-downcase char-foldcase char-lower-case? char-numeric?
11 | char-upcase char-upper-case? char-whitespace? digit-value
12 | string-ci<=? string-ci string-ci=? string-ci>=? string-ci>?
13 | string-downcase string-foldcase string-upcase))
14 |
15 |
--------------------------------------------------------------------------------
/int/scheme/complex.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme complex)
2 | (import (only (sharpf base)
3 | angle imag-part magnitude make-polar
4 | make-rectangular real-part))
5 | (export
6 | angle imag-part magnitude make-polar
7 | make-rectangular real-part))
8 |
9 |
--------------------------------------------------------------------------------
/int/scheme/cxr.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme cxr)
2 | (import (only (sharpf base)
3 | caaar caadr cadar caddr cdaar cdadr cddar cdddr
4 | caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
5 | cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr))
6 | (export
7 | caaar caadr cadar caddr cdaar cdadr cddar cdddr
8 | caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
9 | cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr))
10 |
--------------------------------------------------------------------------------
/int/scheme/eval.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme eval)
2 | (import (only (sharpf base)
3 | environment eval))
4 | (export
5 | environment eval))
6 |
7 |
--------------------------------------------------------------------------------
/int/scheme/file.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme file)
2 | (import (only (sharpf base)
3 | call-with-input-file call-with-output-file
4 | delete-file file-exists?
5 | open-binary-input-file open-binary-output-file
6 | open-input-file open-output-file
7 | with-input-from-file with-output-to-file))
8 | (export
9 | call-with-input-file call-with-output-file
10 | delete-file file-exists?
11 | open-binary-input-file open-binary-output-file
12 | open-input-file open-output-file
13 | with-input-from-file with-output-to-file))
14 |
15 |
--------------------------------------------------------------------------------
/int/scheme/inexact.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme inexact)
2 | (import (only (sharpf base)
3 | acos asin atan cos exp finite?
4 | infinite? log nan? sin sqrt tan))
5 | (export
6 | acos asin atan cos exp finite?
7 | infinite? log nan? sin sqrt tan))
8 |
9 |
--------------------------------------------------------------------------------
/int/scheme/lazy.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme lazy)
2 | (import (only (sharpf base)
3 | delay delay-force force make-promise promise?))
4 | (export
5 | acos asin atan cos exp finite?
6 | delay delay-force force make-promise promise?))
7 |
8 |
--------------------------------------------------------------------------------
/int/scheme/load.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme load)
2 | (import (only (sharpf base)
3 | load))
4 | (export
5 | load))
6 |
7 |
--------------------------------------------------------------------------------
/int/scheme/process-context.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme process-context)
2 | (import (only (sharpf base)
3 | command-line emergency-exit
4 | exit get-environment-variable
5 | get-environment-variables))
6 | (export
7 | command-line emergency-exit
8 | exit get-environment-variable
9 | get-environment-variables))
10 |
11 |
--------------------------------------------------------------------------------
/int/scheme/r5rs-null.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme r5rs-null)
2 | (import (scheme r5rs))
3 | (export
4 | syntax-rules else ... =>
5 | and begin case cond
6 | define define-syntax
7 | delay do if lambda
8 | let let* let-syntax letrec letrec-syntax
9 | or quote
10 | quasiquote unquote unquote-splicing))
11 |
--------------------------------------------------------------------------------
/int/scheme/r5rs.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme r5rs)
2 | (import (sharpf base))
3 | (export
4 | syntax-rules else ... =>
5 | * + - / < <= = > >=
6 | abs acos and angle append apply asin assoc assq assv atan
7 | begin boolean?
8 | caaaar caaadr caaar caadar caaddr caadr caar
9 | cadaar cadadr cadar caddar cadddr caddr cadr
10 | call-with-current-continuation
11 | call-with-input-file call-with-output-file
12 | call-with-values
13 | car
14 | case
15 | cdaaar cdaar cdaddr cdar cddadr cdddar cdddr
16 | cdr
17 | cdaadr cdadar cdadr cddaar cddar cddddr cddr
18 | ceiling
19 | char->integer char-alphabetic?
20 | char-ci<=? char-ci char-ci=? char-ci>=? char-ci>?
21 | char-downcase char-lower-case? char-numeric?
22 | char-ready?
23 | char-upcase char-upper-case? char-whitespace?
24 | char<=? char char=? char>=? char>?
25 | close-input-port close-output-port
26 | complex? cond cons cos
27 | current-input-port current-output-port
28 | define define-syntax
29 | delay denominator display do dynamic-wind
30 | eof-object?
31 | eq? equal? eqv?
32 | eval even? exact->inexact exact? exp expt
33 | floor for-each force
34 | gcd
35 | if imag-part
36 | inexact->exact inexact?
37 | input-port? integer->char integer? interaction-environment
38 | lambda lcm length
39 | let let* let-syntax letrec letrec-syntax
40 | list list->string list->vector list-ref list-tail list?
41 | load log
42 | magnitude make-polar make-rectangular make-string make-vector
43 | map max member memq memv min modulo
44 | negative? newline not null-environment null?
45 | number->string number? numerator
46 | odd? open-input-file open-output-file or output-port?
47 | pair? peek-char positive? procedure?
48 | quasiquote quote quotient
49 | rational? rationalize
50 | read read-char real-part real? remainder reverse round
51 | scheme-report-environment set! set-car! set-cdr! sin sqrt
52 | string string->list string->number string->symbol string-append
53 | string-ci<=? string-ci string-ci=? string-ci>=? string-ci>?
54 | string-copy string-fill! string-length string-ref string-set!
55 | string<=? string string=? string>=? string>?
56 | string? substring symbol->string symbol?
57 | tan truncate
58 | unquote unquote-splicing
59 | values vector vector->list vector-fill!
60 | vector-length vector-ref vector-set! vector?
61 | with-input-from-file with-output-to-file
62 | write write-char zero?))
63 |
--------------------------------------------------------------------------------
/int/scheme/read.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme read)
2 | (import (only (sharpf base)
3 | read))
4 | (export
5 | read))
6 |
7 |
--------------------------------------------------------------------------------
/int/scheme/repl.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme repl)
2 | (import (only (sharpf base)
3 | interaction-environment))
4 | (export
5 | interaction-environment))
6 |
7 |
--------------------------------------------------------------------------------
/int/scheme/time.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme time)
2 | (import (only (sharpf base)
3 | current-jiffy current-second jiffies-per-second))
4 | (export
5 | current-jiffy current-second jiffies-per-second))
6 |
7 |
--------------------------------------------------------------------------------
/int/scheme/write.sld:
--------------------------------------------------------------------------------
1 | (define-library (scheme write)
2 | (import (only (sharpf base)
3 | display write write-shared write-simple))
4 | (export
5 | display write write-shared write-simple))
6 |
7 |
--------------------------------------------------------------------------------
/int/tests/README.md:
--------------------------------------------------------------------------------
1 | # Interpreters tests
2 |
3 | This directory contains tests interpreters for #F compatibility libraries. Tests
4 | are named after the corresponding interpreters and need to be sent to the standard
5 | input, e.g.:
6 |
7 | ```
8 | $ ./ints < ints-tests.s
9 | $ ./intm < intm-tests.s
10 | $ ./intl < intl-tests.s
11 | ```
12 |
13 | Tests are assembled from several test suites (Chibi Scheme* and Larceny** are the main sources).
14 | Sources of the individual tests are attributed to their original authors inside the test files.
15 |
16 | Tests that are not supposed to run on a given interpreter are commented out, so it is
17 | easier to see what is supported and what is not.
18 |
19 |
20 | ----------------------------
21 |
22 | \* available at https://github.com/ashinn/chibi-scheme
23 |
24 | \*\* available at https://github.com/larcenists/larceny
25 |
--------------------------------------------------------------------------------
/lib/README.md:
--------------------------------------------------------------------------------
1 | # Compatibility Libraries
2 |
3 | This directory contains #F libraries for some subsets of Scheme. Each library is implemented as a single .sf file and can be compiled and linked in the regular manner, e.g.
4 |
5 | ```
6 | $ sfc libs.sf myprog.sf # sfc produces 2 C files
7 | $ gcc libs.c myprog.c -lm # gcc produces a.out (libs refers to math functions, so -lm may be needed)
8 | ```
9 |
10 | All libraries adhere to #F's minimalistic approach to error checking: run-time errors are checked with C asserts, so programs compiled in debug mode report them and exit; there is no error checking in release mode. If you need to debug your code that uses one of these libraries, you may use the corresponding interpreter with traditional error checking (interpreters are located in the `/int` subdirectory).
11 |
12 | Please note that to dress an exisiting Scheme source file as a #F program that
13 | uses a library like LibS, one has to add `(load "libs.sf")` line to the beginning of the
14 | file and `(define (main argv) #f)` to the end.
15 |
16 |
17 | ## LibXXS (Extra Extra Small) Library
18 |
19 | LibXXS (see [libxxs.sf](https://raw.githubusercontent.com/false-schemers/sharpF/master/lib/libxxs.sf)) provides bare-bones Scheme-like functionality. It has the following known limitations:
20 |
21 | * SFC reader used to read #F source code is case-sensitive
22 | * library function `string->symbol` is also case-sensitive
23 | * no support for `s`, `f`, `d`, `l` exponent markers and `#` digit placeholders
24 | * there is no support for `eval` and environment functions
25 | * no dynamic `load` or dymamic macroexpansion/compilation
26 | * no support for `read`
27 | * no `dynamic-wind`, so `call/cc` is faster
28 | * fixnums are limited to 24 bits, generic math is fixnum-only
29 | * no support for flonums/bignums/rational/complex numbers
30 | * no support for `sqrt` and trigonometry functions
31 | * no support for dotted/variable-length argument lists
32 | * all variable-argument and high-order primitives like `+` and `map` are macros
33 | * `apply` is a macro limited to macros `+`, `*`, `list`, `append`, `vector`, `string`, `string-append`
34 | * `set!` to built-in bindings is not allowed
35 | * there is no REPL
36 |
37 | LibXXS supports the following additional functions:
38 |
39 | * many fixnum (`fx`) - specific operations
40 | * `letrec*`, `rec`, `when`, `unless` forms
41 | * `error` macro (not based on exceptions)
42 | * `current-jiffy`, `jiffies-per-second`
43 | * `exit`, `abort`, and `reset`
44 |
45 |
46 | ## LibXS (Extra Small) Library
47 |
48 | LibXS (see [libxs.sf](https://raw.githubusercontent.com/false-schemers/sharpF/master/lib/libxs.sf)) is an extended version of LibXXS. It has the following additional functionality:
49 |
50 | * support for flonums, generic math is mixed fixnum/flonum
51 | * many flonum (`fl`) - specific operations
52 | * `sqrt` and trigonometry functions are available in (`fl`) form (e.g. `flsqrt`)
53 |
54 |
55 | ## LibS (Small) Library
56 |
57 | LibS (see [libs.sf](https://raw.githubusercontent.com/false-schemers/sharpF/master/lib/libs.sf)) generally targets
58 | R5RS feature set; most of the forms and procedures behave as expected. Compared to a regular R5RS system, it has the following known limitations:
59 |
60 | * SFC reader used to read #F source code is case-sensitive
61 | * `read` and `string->symbol` are also case-sensitive
62 | * no support for `s`, `f`, `d`, `l` exponent markers and `#` digit placeholders
63 | * there is no support for `eval` and environment functions
64 | * no dynamic `load` or dynamic macroexpansion/compilation
65 | * fixnums are limited to 24 bits, flonums are doubles
66 | * no support for bignums/rational/complex numbers
67 | * `set!` to built-in bindings is not allowed
68 | * there is no REPL and no transcript functions
69 |
70 | In addition to R5RS-level functionality, LibS supports some popular extensions
71 | defined in pre-R5RS Scheme standards, SRFIs, and R7RS libraries:
72 |
73 | * many fixnum (`fx`) and flonum (`fl`) - specific operations
74 | * `letrec*`, `rec`, `receive`, `when`, `unless`, `case-lambda` forms
75 | * operations on boxes: `box?`, `box`, `unbox`, `set-box!`
76 | * `error`, `assertion-violation` (not based on exceptions)
77 | * `file-exists?`, `delete-file`, `rename-file`, `open-input-string`
78 | * `exit`, `abort`, `reset`, `command-line`
79 | * `get-environment-variable`, `system`, `current-jiffy`, `jiffies-per-second`
80 |
81 |
82 | ## LibM (Medium) Library
83 |
84 | LibM (see [libm.sf](https://raw.githubusercontent.com/false-schemers/sharpF/master/lib/libm.sf)) is an extended version of LibS. It has the following additional functionality from R7RS-Small:
85 |
86 | * support for bytevectors, with basic set of operations
87 | * support for `define-record-type` records
88 | * simple binary input from files and bytevectors
89 | * simple binary output to files and bytevectors
90 | * simple text output to/from strings
91 | * `let-values`, `let*-values`, `define-values`, `make-parameter`, `parameterize`
92 | * exceptions, errors, `guard` form
93 | * current port access procedures are parameters
94 | * fixnums are extended to 28 bits
95 | * additional R7RS math and port operations
96 |
97 |
98 | ## LibL (Large) Library
99 |
100 | LibL (see [libl.sf](https://raw.githubusercontent.com/false-schemers/sharpF/master/lib/libl.sf)) targets
101 | R7RS-Small feature set; most of the forms and procedures behave as expected. Compared to a regular R7RS-Small
102 | system, a program compiled with LibL will have the following limitations:
103 |
104 | * there is no support for `eval` and environment functions
105 | * no dynamic `load` or dynamic macroexpansion/compilation
106 | * fixnums are 30 bit long, flonums are doubles
107 | * no support for bignums/rational/complex numbers
108 | * no support for Unicode; strings are 8-bit clean, use system locale
109 | * `set!` to built-in bindings is not allowed
110 | * vectors are not self-evaluating; need to be quoted as in R5RS
111 | * source code literals cannot be circular (R7RS allows this)
112 | * there is no support for libraries and import
113 | * there is no REPL
114 |
115 | Some features of the R7RS-Small standard are not yet implemented or implemented in a simplified or non-conforming way:
116 |
117 | * SFC reader and `read` procedure are always case-sensitive
118 | * `#!fold-case` and `#!no-fold-case` directives are not supported
119 | * `include` and `include-ci` forms are not supported
120 | * `cond-expand` form is not implemented
121 | * `get-environment-variable` is implemented, but `get-environment-variables` is not
122 | * `current-jiffy` and `jiffies-per-second` return inexact integers
123 | * `current-second` is defined as C `difftime(time(0), 0)+37`
124 | * macroexpander treats `_` as a regular identifier, not match-all pattern
125 | * macroexpander does not support `(... escaped)` pattern escapes
126 | * macroexpander does not support patterns with internal ellipsis and improper tail variable
127 |
128 |
129 |
--------------------------------------------------------------------------------
/misc/lambda-sunrise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/false-schemers/sharpF/5363370f11dcebd2c6cc75b79ac0476f78cbeb48/misc/lambda-sunrise.png
--------------------------------------------------------------------------------
/tests/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all clean realclean
2 |
3 | tests = tests-a \
4 | tests-b \
5 | tests-c \
6 | tests-d \
7 | tests-e \
8 | tests-f \
9 | tests-g \
10 | tests-h \
11 | tests-i \
12 | tests-l \
13 | tests-m
14 |
15 | .PHONY: $(tests:%=run-%)
16 |
17 | helpers = ../lib/libs.sf \
18 | helpers.sf
19 |
20 | hroots = $(helpers:%.sf=%)
21 |
22 | exe =
23 | CC = clang -Wno-parentheses-equality
24 | SFC = ../fixpoint/sfc
25 |
26 | roots = $(tests) $(hroots)
27 |
28 | gens = $(roots:%=%.c) $(tests:%=%$(exe))
29 |
30 | all: $(tests:%=run-%)
31 |
32 | clean:
33 | $(RM) $(gens)
34 |
35 | realclean: clean
36 |
37 | $(tests:%=run-%): run-%: %
38 | ./$^
39 |
40 | $(tests): %: %.c $(hroots:%=%.c)
41 | $(CC) -o $@ $^
42 |
43 | $(tests:%=%.c): %.c : %.sf $(hroots:%=%.c)
44 | $(SFC) -v $<
45 |
46 | helpers.c: helpers.sf ../lib/libs.c
47 | $(SFC) -v $<
48 |
49 | ../lib/libs.c: ../lib/libs.sf
50 | $(SFC) -v $<
51 |
--------------------------------------------------------------------------------
/tests/README:
--------------------------------------------------------------------------------
1 | This directory contains r5rs conformance tests.
2 |
--------------------------------------------------------------------------------
/tests/helpers.sf:
--------------------------------------------------------------------------------
1 | ;;(load library "stdlib.qa2")
2 | #fload "../lib/libs.sf"
3 |
4 | (define current-section #f)
5 | (define errors '())
6 |
7 | (define (writeln line) (write line) (newline))
8 |
9 | (define ! string->number)
10 |
11 | (define (convert-! tree)
12 | (cond ((not (pair? tree)) tree)
13 | ((eq? (car tree) '!) (string->number (cadr tree)))
14 | (else (cons (convert-! (car tree)) (convert-! (cdr tree))))))
15 |
16 | (define (every? p xs) (or (null? xs)
17 | (and (p (car xs)) (every? p (cdr xs)))))
18 |
19 | (define SECTION ;; Say that we're entering a new section
20 | (let ((sec 'SECTION))
21 | (lambda args
22 | (set! current-section (cons sec args))
23 | (newline)
24 | (writeln current-section))))
25 |
26 | (define (test got quoted expected . comments)
27 | (let* ((ok (or (eq? expected 'unspecified)
28 | (equal? got (convert-! expected))))
29 | (msg (if ok '() (list '*** 'but 'expected expected)))
30 | (record (append (list quoted '=> got) msg comments)))
31 | (if (not ok)
32 | (set! errors (cons (list current-section record) errors)))
33 | (write-string " ")
34 | (for-each (lambda (x) (write-string " ") (write x)) record)
35 | (newline)))
36 |
37 | (define (report-errors)
38 | (newline)
39 | (if (null? errors)
40 | (begin
41 | (display "ALL TESTS PASSED!\n")
42 | (exit 0))
43 | (begin
44 | (display (length errors))
45 | (display " MISTAKES WERE MADE\n")
46 | (for-each
47 | (lambda (cs&rec)
48 | (write-string " ")
49 | (write (car cs&rec))
50 | (newline)
51 | (write-string " ")
52 | (for-each (lambda (x) (write-string " ") (write x)) (cadr cs&rec))
53 | (newline)
54 | (newline))
55 | (reverse errors))
56 | (writeln (list 'total 'of (length errors) 'errors))
57 | (exit 1))))
58 |
--------------------------------------------------------------------------------
/tests/tests-a.sf:
--------------------------------------------------------------------------------
1 | #fload "../lib/libs.sf"
2 | #fload "helpers.sf"
3 |
4 | (define n-tail-calls 2000000)
5 |
6 | (SECTION 1 3 4) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7 | (test (* 5 8) '(* 5 8) 40)
8 |
9 | (SECTION 2 1) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10 | (define symbols '(+ lambda list-vector <=? q soup V17a a34kTMNs
11 | the-word-recursion-has-many-meanings ...
12 | x! x$ x% x* x+ x- x. x/ x: x< x= x> x? x@ x^ x_ x~))
13 |
14 | (test (every? symbol? symbols) '(every? symbol? symbols) #t "all symbols")
15 | (test (length symbols) '(length symbols) 27)
16 |
17 | (SECTION 2 2) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18 | ;;; The FACT procedure computes the factorial
19 | ;;; of a non-negative integer.
20 | (define fact
21 | (lambda (n)
22 | (if (= n 0)
23 | 1 ;Base case: return 1
24 | (* n (fact (- n 1))))))
25 |
26 | (test (fact 4) '(fact 4) 24)
27 | (test (fact 6) '(fact 6) 720)
28 | ;;(test (fact 20) '(fact 20) 2432902008176640000)
29 | ;;(test (fact 30) '(fact 30) 265252859812191058636308480000000)
30 | ;;(test (number->string (fact 40))
31 | ;; '(number->string (fact 40))
32 | ;; "815915283247897734345611269596115894272000000000")
33 |
34 | (SECTION 3 2) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
35 |
36 | (define type-predicates
37 | (list boolean? symbol? vector? procedure? pair? number? string?))
38 |
39 | (define (types x) (map (lambda (p) (if (p x) 1 0)) type-predicates))
40 | (define (disjoint? x) (= 1 (apply + (types x))))
41 |
42 | (for-each
43 | (lambda (p x y)
44 | (test (disjoint? x) (list 'disjoint? x) #t)
45 | (test (disjoint? y) (list 'disjoint? y) #t)
46 | (test (p x) (list 'p x) #t)
47 | (test (p y) (list 'p y) #t)
48 | (test (equal? (types x) (types y))
49 | (list 'equal? (list 'types x) (list 'types y))
50 | #t))
51 | type-predicates
52 | (list #t 'symbol '#() car '(test) 9739 ""
53 | )
54 | (list #f 'nil '#(a b) test '(t . t) -3252 "test"
55 | ))
56 |
57 | (SECTION 3 3) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 | (test '( 08 13) '( 08 13) '(8 13))
59 | (test '(8 . (13 . ())) '(8 . (13 . ())) '(8 13))
60 |
61 |
62 |
63 | (SECTION 3 5) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
64 | ;; Test for tail recursiveness of each of the expressions on page 8.
65 | ;; You may want to set n-tail-calls lower (if this is too slow)
66 | ;; or higher (to make sure it is larger than the call stack size).
67 | (define n n-tail-calls)
68 |
69 | (test (let go ((i n)) (if (= i 0) 0 (go (- i 1))))
70 | '(let go ((i n)) (if (= i 0) 0 (go (- i 1))))
71 | 0)
72 | (test (let go ((i n)) (cond ((= i 0) 0) (else (go (- i 1)))))
73 | '(let go ((i n)) (cond ((= i 0) 0) (else (go (- i 1)))))
74 | 0)
75 | (test (let go ((i n)) (case i ((0) 0) (else (go (- i 1)))))
76 | '(let go ((i n)) (case i ((0) 0) (else (go (- i 1)))))
77 | 0)
78 | (test (let go ((i n)) (if (= i 0) 0 (and #t (go (- i 1)))))
79 | '(let go ((i n)) (if (= i 0) 0 (and #t (go (- i 1)))))
80 | 0)
81 | (test (let go ((i n)) (if (= i 0) 0 (or #f (go (- i 1)))))
82 | '(let go ((i n)) (if (= i 0) 0 (or #f (go (- i 1)))))
83 | 0)
84 | (test (let go ((i n)) (if (= i 0) 0 (let ((a 0)) (go (- i 1)))))
85 | '(let go ((i n)) (if (= i 0) 0 (let ((a 0)) (go (- i 1)))))
86 | 0)
87 | (test (let go ((i n)) (if (= i 0) 0 (let* ((a 0)) (go (- i 1)))))
88 | '(let go ((i n)) (if (= i 0) 0 (let* ((a 0)) (go (- i 1)))))
89 | 0)
90 | (test (let go ((i n)) (if (= i 0) 0 (letrec ((a 0)) (go (- i 1)))))
91 | '(let go ((i n)) (if (= i 0) 0 (letrec ((a 0)) (go (- i 1)))))
92 | 0)
93 | (test (let go ((i n)) (if (= i 0) 0 (begin #f (go (- i 1)))))
94 | '(let go ((i n)) (if (= i 0) 0 (begin #f (go (- i 1)))))
95 | 0)
96 | (test (do ((i n (- i 1))) ((= i 0) 0) #t)
97 | '(do ((i n (- i 1))) ((= i 0) 0) #t)
98 | 0)
99 | (test (let go ((i n)) (if (= i 0) 0 (do () (#t (go (- i 1))) 1)))
100 | '(let go ((i n)) (if (= i 0) 0 (do () (#t (go (- i 1))) 1)))
101 | 0)
102 | (test (let go ((i n)) (if (= i 0) 0 (apply go (list (- i 1)))))
103 | '(let go ((i n)) (if (= i 0) 0 (apply go (list (- i 1)))))
104 | 0)
105 |
106 | (test (let go ((i n)) (if (= i 0) 0 (call-with-current-continuation
107 | (lambda (ignore) (go (- i 1))))))
108 | '(let go ((i n)) (if (= i 0) 0 (call-with-current-continuation
109 | (lambda (ignore) (go (- i 1))))))
110 | 0)
111 | (test (let go ((i n))
112 | (if (= i 0) 0 (call-with-values (lambda () (- i 1)) go)))
113 | '(let go ((i n))
114 | (if (= i 0) 0 (call-with-values (lambda () (- i 1)) go)))
115 | 0)
116 |
117 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118 | (define (main argv) (report-errors))
119 |
--------------------------------------------------------------------------------
/tests/tests-b.sf:
--------------------------------------------------------------------------------
1 | ;;(load source "helpers.qa2")
2 | #fload "../lib/libs.sf"
3 | #fload "helpers.sf"
4 |
5 |
6 |
7 | (SECTION 4 1 1) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 | (define x 28)
9 | (test x 'x 28)
10 |
11 | (SECTION 4 1 2) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12 | (test (quote a)
13 | '(quote a)
14 | 'a)
15 | (test (quote #(a b c))
16 | '(quote #(a b c))
17 | '#(a b c))
18 | (test (quote (+ 1 2))
19 | '(quote (+ 1 2))
20 | '(+ 1 2))
21 | (test 'a
22 | ''a
23 | 'a)
24 | (test '#(a b c)
25 | ''#(a b c)
26 | '#(a b c))
27 | (test ''a
28 | '''a
29 | '(quote a))
30 | (test '"abc"
31 | ''"abc"
32 | '"abc")
33 | (test "abc"
34 | '"abc"
35 | '"abc")
36 | (test '145932
37 | '145932
38 | '145932)
39 | (test 145932
40 | '145932
41 | '145932)
42 | (test '#t
43 | '#t
44 | '#t)
45 | (test #t
46 | '#t
47 | '#t)
48 |
49 | (SECTION 4 1 3) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50 | (test (+ 3 4)
51 | '(+ 3 4)
52 | '7)
53 | (test ((if #f + *) 3 4)
54 | '((if #f + *) 3 4)
55 | '12)
56 |
57 | (SECTION 4 1 4) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 | (test (procedure? (lambda x (+ x x)))
59 | '(procedure? (lambda x (+ x x)))
60 | '#t)
61 | (define reverse-subtract (lambda (x y) (- y x)))
62 | (test (reverse-subtract 7 10)
63 | '(reverse-subtract 7 10)
64 | '3)
65 | (define add4
66 | (let ((x 4))
67 | (lambda (y) (+ x y))))
68 | (test (add4 6)
69 | '(add4 6)
70 | '10)
71 | (test ((lambda x x) 3 4 5 6)
72 | '((lambda x x) 3 4 5 6)
73 | '(3 4 5 6))
74 | (test ((lambda (x y . z) z) 3 4 5 6)
75 | '((lambda (x y . z) z) 3 4 5 6)
76 | '(5 6))
77 |
78 | (SECTION 4 1 5) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
79 | (test (if (> 3 2) 'yes 'no)
80 | '(if (> 3 2) 'yes 'no)
81 | 'yes)
82 | (test (if (> 2 3) 'yes 'no)
83 | '(if (> 2 3) 'yes 'no)
84 | 'no)
85 | (test (if (> 3 2) (- 3 2) (+ 3 2))
86 | '(if (> 3 2) (- 3 2) (+ 3 2))
87 | '1)
88 |
89 | (SECTION 4 1 6) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
90 | (define x 2)
91 | (test (+ x 1)
92 | '(+ x 1)
93 | '3)
94 | (set! x 4)
95 | (test (+ x 1)
96 | '(+ x 1) '5)
97 |
98 | (SECTION 4 2 1) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
99 | (test (cond ((> 3 2) 'greater)
100 | ((< 3 2) 'less))
101 | '(cond ((> 3 2) 'greater)
102 | ((< 3 2) 'less))
103 | 'greater)
104 | (test (cond ((> 3 3) 'greater)
105 | ((< 3 3) 'less)
106 | (else 'equal))
107 | '(cond ((> 3 3) 'greater)
108 | ((< 3 3) 'less)
109 | (else 'equal))
110 | 'equal)
111 | (test (cond ((assv 'b '((a 1) (b 2))) => cadr)
112 | (else #f))
113 | '(cond ((assv 'b '((a 1) (b 2))) => cadr)
114 | (else #f))
115 | '2)
116 | (test (case (* 2 3)
117 | ((2 3 5 7) 'prime)
118 | ((1 4 6 8 9) 'composite))
119 | '(case (* 2 3)
120 | ((2 3 5 7) 'prime)
121 | ((1 4 6 8 9) 'composite))
122 | 'composite)
123 | (test (case (car '(c d))
124 | ((a e i o u) 'vowel)
125 | ((w y) 'semivowel)
126 | (else 'consonant))
127 | '(case (car '(c d))
128 | ((a e i o u) 'vowel)
129 | ((w y) 'semivowel)
130 | (else 'consonant))
131 | 'consonant)
132 | (test (and (= 2 2) (> 2 1))
133 | '(and (= 2 2) (> 2 1))
134 | '#t)
135 | (test (and (= 2 2) (< 2 1))
136 | '(and (= 2 2) (< 2 1))
137 | '#f)
138 | (test (and 1 2 'c '(f g))
139 | '(and 1 2 'c '(f g))
140 | '(f g))
141 | (test (and)
142 | '(and)
143 | '#t)
144 | (test (or (= 2 2) (> 2 1))
145 | '(or (= 2 2) (> 2 1))
146 | '#t)
147 | (test (or (= 2 2) (< 2 1))
148 | '(or (= 2 2) (< 2 1))
149 | '#t)
150 | (test (or #f #f #f)
151 | '(or #f #f #f)
152 | '#f)
153 | (test (or)
154 | '(or)
155 | '#f)
156 | (test (or (memq 'b '(a b c)) (+ 3 0))
157 | '(or (memq 'b '(a b c)) (+ 3 0))
158 | '(b c))
159 |
160 | (SECTION 4 2 2) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
161 | (test (let ((x 2) (y 3)) (* x y))
162 | '(let ((x 2) (y 3)) (* x y))
163 | '6)
164 | (test (let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x)))
165 | '(let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x)))
166 | '35)
167 | (test (let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x)))
168 | '(let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x)))
169 | '70)
170 | (test (letrec ((even?
171 | (lambda (n) (if (zero? n) #t (odd? (- n 1)))))
172 | (odd?
173 | (lambda (n) (if (zero? n) #f (even? (- n 1))))))
174 | (even? 88))
175 | '(letrec ((even?
176 | (lambda (n) (if (zero? n) #t (odd? (- n 1)))))
177 | (odd?
178 | (lambda (n) (if (zero? n) #f (even? (- n 1))))))
179 | (even? 88))
180 | '#t)
181 |
182 | (define x 34)
183 | (test (let ((x 3)) (define x 5) x)
184 | '(let ((x 3)) (define x 5) x)
185 | 5 '(let ((x 3)) (define x 5) x))
186 | (test x
187 | 'x
188 | 34 'x)
189 | (test (let () (define x 6) x)
190 | '(let () (define x 6) x)
191 | 6 '(let () (define x 6) x))
192 | (test x
193 | 'x
194 | 34 'x)
195 | (test (let* ((x 3)) (define x 7) x)
196 | '(let* ((x 3)) (define x 7) x)
197 | 7 '(let* ((x 3)) (define x 7) x))
198 | (test x
199 | 'x
200 | 34 'x)
201 | (test (let* () (define x 8) x)
202 | '(let* () (define x 8) x)
203 | 8 '(let* () (define x 8) x))
204 | (test x
205 | 'x
206 | 34 'x)
207 | (test (letrec () (define x 9) x)
208 | '(letrec () (define x 9) x)
209 | 9 '(letrec () (define x 9) x))
210 | (test x
211 | 'x
212 | 34 'x)
213 | (test (letrec ((x 3)) (define x 10) x)
214 | '(letrec ((x 3)) (define x 10) x)
215 | 10 '(letrec ((x 3)) (define x 10) x))
216 | (test x
217 | 'x
218 | 34 'x)
219 |
220 |
221 | (SECTION 4 2 3) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
222 | (define x 0)
223 | (test (begin (set! x 5) (+ x 1))
224 | '(begin (set! x 5) (+ x 1))
225 | '6)
226 |
227 | (SECTION 4 2 4) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
228 | (test (do ((vec (make-vector 5))
229 | (i 0 (+ i 1)))
230 | ((= i 5) vec)
231 | (vector-set! vec i i))
232 | '(do ((vec (make-vector 5))
233 | (i 0 (+ i 1)))
234 | ((= i 5) vec)
235 | (vector-set! vec i i))
236 | '#(0 1 2 3 4))
237 | (test (let ((x '(1 3 5 7 9)))
238 | (do ((x x (cdr x))
239 | (sum 0 (+ sum (car x))))
240 | ((null? x) sum)))
241 | '(let ((x '(1 3 5 7 9)))
242 | (do ((x x (cdr x))
243 | (sum 0 (+ sum (car x))))
244 | ((null? x) sum)))
245 | '25)
246 | (test (let loop ((numbers '(3 -2 1 6 -5))
247 | (nonneg '())
248 | (neg '()))
249 | (cond ((null? numbers) (list nonneg neg))
250 | ((negative? (car numbers))
251 | (loop (cdr numbers)
252 | nonneg
253 | (cons (car numbers) neg)))
254 | (else
255 | (loop (cdr numbers)
256 | (cons (car numbers) nonneg)
257 | neg))))
258 | '(let loop ((numbers '(3 -2 1 6 -5))
259 | (nonneg '())
260 | (neg '()))
261 | (cond ((null? numbers) (list nonneg neg))
262 | ((negative? (car numbers))
263 | (loop (cdr numbers)
264 | nonneg
265 | (cons (car numbers) neg)))
266 | (else
267 | (loop (cdr numbers)
268 | (cons (car numbers) nonneg)
269 | neg))))
270 | '((6 1 3) (-5 -2)))
271 | (test (let foo () 1)
272 | '(let foo () 1)
273 | '1)
274 | (test (let ((x 10) (loop 1))
275 | (let loop ((x x) (y loop))
276 | (if (zero? x) y (loop (- x 1) (* y x)))))
277 | '(let ((x 10) (loop 1))
278 | (let loop ((x x) (y loop))
279 | (if (zero? x) y (loop (- x 1) (* y x)))))
280 | '3628800)
281 |
282 |
283 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
284 | (define (main argv) (report-errors))
285 |
--------------------------------------------------------------------------------
/tests/tests-c.sf:
--------------------------------------------------------------------------------
1 | ;;(load source "helpers.qa2")
2 | #fload "../lib/libs.sf"
3 | #fload "helpers.sf"
4 |
5 |
6 | (SECTION 6 3 5) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7 |
8 | (test (string? "The word \"recursion\\\" has many meanings.")
9 | '(string? "The word \"recursion\\\" has many meanings.")
10 | '#t)
11 | (test (string? "")
12 | '(string? "")
13 | '#t)
14 |
15 | (test (string-length "abc")
16 | '(string-length "abc")
17 | '3)
18 | (test (string-length "")
19 | '(string-length "")
20 | '0)
21 |
22 | (test (string=? "" "")
23 | '(string=? "" "")
24 | '#t)
25 | (test (string "" "")
26 | '(string "" "")
27 | '#f)
28 | (test (string>? "" "")
29 | '(string>? "" "")
30 | '#f)
31 | (test (string<=? "" "")
32 | '(string<=? "" "")
33 | '#t)
34 | (test (string>=? "" "")
35 | '(string>=? "" "")
36 | '#t)
37 |
38 | (test (string=? "A" "B")
39 | '(string=? "A" "B")
40 | '#f)
41 | (test (string=? "a" "b")
42 | '(string=? "a" "b")
43 | '#f)
44 | (test (string=? "9" "0")
45 | '(string=? "9" "0")
46 | '#f)
47 | (test (string=? "A" "A")
48 | '(string=? "A" "A")
49 | '#t)
50 |
51 | (test (string "A" "B")
52 | '(string "A" "B")
53 | '#t)
54 | (test (string "a" "b")
55 | '(string "a" "b")
56 | '#t)
57 | (test (string "9" "0")
58 | '(string "9" "0")
59 | '#f)
60 | (test (string "A" "A")
61 | '(string "A" "A")
62 | '#f)
63 |
64 | (test (string>? "A" "B")
65 | '(string>? "A" "B")
66 | '#f)
67 | (test (string>? "a" "b")
68 | '(string>? "a" "b")
69 | '#f)
70 | (test (string>? "9" "0")
71 | '(string>? "9" "0")
72 | '#t)
73 | (test (string>? "A" "A")
74 | '(string>? "A" "A")
75 | '#f)
76 |
77 | (test (string<=? "A" "B")
78 | '(string<=? "A" "B")
79 | '#t)
80 | (test (string<=? "a" "b")
81 | '(string<=? "a" "b")
82 | '#t)
83 | (test (string<=? "9" "0")
84 | '(string<=? "9" "0")
85 | '#f)
86 | (test (string<=? "A" "A")
87 | '(string<=? "A" "A")
88 | '#t)
89 |
90 | (test (string>=? "A" "B")
91 | '(string>=? "A" "B")
92 | '#f)
93 | (test (string>=? "a" "b")
94 | '(string>=? "a" "b")
95 | '#f)
96 | (test (string>=? "9" "0")
97 | '(string>=? "9" "0")
98 | '#t)
99 | (test (string>=? "A" "A")
100 | '(string>=? "A" "A")
101 | '#t)
102 |
103 | (test (string "abcd" "abcz")
104 | '(string "abcd" "abcz")
105 | '#t)
106 | (test (string<=? "abcd" "abcz")
107 | '(string<=? "abcd" "abcz")
108 | '#t)
109 | (test (string "abcd" "abcd")
110 | '(string "abcd" "abcd")
111 | '#f)
112 | (test (string<=? "abcd" "abcd")
113 | '(string<=? "abcd" "abcd")
114 | '#t)
115 | (test (string "abc" "abcz")
116 | '(string "abc" "abcz")
117 | '#t)
118 | (test (string<=? "abc" "abcz")
119 | '(string<=? "abc" "abcz")
120 | '#t)
121 | (test (string>=? "abd" "abcz")
122 | '(string>=? "abd" "abcz")
123 | '#t)
124 | (test (string "" "abcz")
125 | '(string "" "abcz")
126 | '#t)
127 | (test (string<=? "" "abcz")
128 | '(string<=? "" "abcz")
129 | '#t)
130 | (test (string>=? "" "abcz")
131 | '(string>=? "" "abcz")
132 | '#f)
133 |
134 | ;; reversing arg order:
135 | (test (string "abcz" "abcd")
136 | '(string "abcz" "abcd")
137 | '#f)
138 | (test (string<=? "abcz" "abcd")
139 | '(string<=? "abcz" "abcd")
140 | '#f)
141 | (test (string "abcd" "abcd")
142 | '(string "abcd" "abcd")
143 | '#f)
144 | (test (string<=? "abcd" "abcd")
145 | '(string<=? "abcd" "abcd")
146 | '#t)
147 | (test (string "abcz" "abc")
148 | '(string "abcz" "abc")
149 | '#f)
150 | (test (string<=? "abcz" "abc")
151 | '(string<=? "abcz" "abc")
152 | '#f)
153 | (test (string>=? "abcz" "abd")
154 | '(string>=? "abcz" "abd")
155 | '#f)
156 | (test (string "abcz" "")
157 | '(string "abcz" "")
158 | '#f)
159 | (test (string<=? "abcz" "")
160 | '(string<=? "abcz" "")
161 | '#f)
162 | (test (string>=? "abcz" "")
163 | '(string>=? "abcz" "")
164 | '#t)
165 |
166 |
167 | (test (substring "ab" 0 0)
168 | '(substring "ab" 0 0)
169 | '"")
170 | (test (substring "ab" 1 1)
171 | '(substring "ab" 1 1)
172 | '"")
173 | (test (substring "ab" 2 2)
174 | '(substring "ab" 2 2)
175 | '"")
176 | (test (substring "ab" 0 1)
177 | '(substring "ab" 0 1)
178 | '"a")
179 | (test (substring "ab" 1 2)
180 | '(substring "ab" 1 2)
181 | '"b")
182 | (test (substring "ab" 0 2)
183 | '(substring "ab" 0 2)
184 | '"ab")
185 |
186 | (test (string-append)
187 | '(string-append)
188 | '"")
189 | (test (string-append "foo")
190 | '(string-append "foo")
191 | '"foo")
192 | (test (string-append "foo" "bar")
193 | '(string-append "foo" "bar")
194 | '"foobar")
195 | (test (string-append "foo" "bar" "baz")
196 | '(string-append "foo" "bar" "baz")
197 | '"foobarbaz")
198 | (test (string-append "foo" "")
199 | '(string-append "foo" "")
200 | '"foo")
201 | (test (string-append "" "foo")
202 | '(string-append "" "foo")
203 | '"foo")
204 |
205 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
206 | (define (main argv) (report-errors))
207 |
--------------------------------------------------------------------------------
/tests/tests-d.sf:
--------------------------------------------------------------------------------
1 | ;;(load source "helpers.qa2")
2 | #fload "../lib/libs.sf"
3 | #fload "helpers.sf"
4 |
5 |
6 |
7 | (SECTION 6 3 6) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 | (test (vector? '#(0 (2 2 2 2) "Anna"))
9 | '(vector? '#(0 (2 2 2 2) "Anna"))
10 | '#t)
11 | (test '#(0 (2 2 2 2) "Anna")
12 | ''#(0 (2 2 2 2) "Anna")
13 | '#(0 (2 2 2 2) "Anna"))
14 |
15 | (test (vector? '#())
16 | '(vector? '#())
17 | '#t)
18 |
19 | (test (make-vector 2 'hi)
20 | '(make-vector 2 'hi)
21 | '#(hi hi))
22 | (test (make-vector 0)
23 | '(make-vector 0)
24 | '#())
25 | (test (make-vector 0 'a)
26 | '(make-vector 0 'a)
27 | '#())
28 |
29 | (test (vector 'a 'b 'c)
30 | '(vector 'a 'b 'c)
31 | '#(a b c))
32 | (test (vector)
33 | '(vector)
34 | '#())
35 |
36 | (test (vector-length '#(0 (2 2 2 2) "Anna"))
37 | '(vector-length '#(0 (2 2 2 2) "Anna"))
38 | '3)
39 | (test (vector-length '#())
40 | '(vector-length '#())
41 | '0)
42 |
43 | (test (vector-ref '#(1 1 2 3 5 8 13 21) 5)
44 | '(vector-ref '#(1 1 2 3 5 8 13 21) 5)
45 | '8)
46 |
47 | (test (let ((vec (vector 0 '(2 2 2 2) "Anna")))
48 | (vector-set! vec 1 '("Sue" "Sue"))
49 | vec)
50 | '(let ((vec (vector 0 '(2 2 2 2) "Anna")))
51 | (vector-set! vec 1 '("Sue" "Sue"))
52 | vec)
53 | '#(0 ("Sue" "Sue") "Anna"))
54 |
55 | (test (vector->list '#(dah dah didah))
56 | '(vector->list '#(dah dah didah))
57 | '(dah dah didah))
58 | (test (list->vector '(dididit dah))
59 | '(list->vector '(dididit dah))
60 | '#(dididit dah))
61 |
62 | (test (vector->list '#())
63 | '(vector->list '#())
64 | '())
65 | (test (list->vector '())
66 | '(list->vector '())
67 | '#())
68 |
69 | (test (make-vector 3 0)
70 | '(make-vector 3 0)
71 | '#(0 0 0))
72 |
73 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
74 | (define (main argv) (report-errors))
75 |
--------------------------------------------------------------------------------
/tests/tests-f.sf:
--------------------------------------------------------------------------------
1 | ;;(load source "helpers.qa2")
2 | #fload "../lib/libs.sf"
3 | #fload "helpers.sf"
4 |
5 |
6 | (SECTION 6 3 1) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7 | (test #t
8 | '#t
9 | '#t)
10 | (test #f
11 | '#f
12 | '#f)
13 | (test '#f
14 | '#f
15 | '#f)
16 |
17 | (test (not #t)
18 | '(not #t)
19 | '#f)
20 | (test (not 3)
21 | '(not 3)
22 | '#f)
23 | (test (not (list 3))
24 | '(not (list 3))
25 | '#f)
26 | (test (not #f)
27 | '(not #f)
28 | '#t)
29 | (test (not '())
30 | '(not '())
31 | '#f)
32 | (test (not (list))
33 | '(not (list))
34 | '#f)
35 | (test (not 'nil)
36 | '(not 'nil)
37 | '#f)
38 |
39 | (test (boolean? #f)
40 | '(boolean? #f)
41 | '#t)
42 | (test (boolean? 0)
43 | '(boolean? 0)
44 | '#f)
45 | (test (boolean? '())
46 | '(boolean? '())
47 | '#f)
48 |
49 | (SECTION 6 3 2) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50 | (test '(a . (b . (c . (d . (e . ())))))
51 | '(a . (b . (c . (d . (e . ())))))
52 | '(a b c d e))
53 | (test '(a b c . d)
54 | '(a b c . d)
55 | '(a . (b . (c . d))))
56 |
57 | (define x (list 'a 'b 'c))
58 | (define y x)
59 | (test y
60 | 'y
61 | '(a b c))
62 | (test (list? y)
63 | '(list? y)
64 | '#t)
65 |
66 | (test (pair? '(a . b))
67 | '(pair? '(a . b))
68 | '#t)
69 | (test (pair? '(a b c))
70 | '(pair? '(a b c))
71 | '#t)
72 | (test (pair? '())
73 | '(pair? '())
74 | '#f)
75 | (test (pair? '#(a b))
76 | '(pair? '#(a b))
77 | '#f)
78 |
79 | (test (pair? '(a . 1))
80 | '(pair? '(a . 1))
81 | '#t)
82 |
83 | (test (cons 'a '())
84 | '(cons 'a '())
85 | '(a))
86 | (test (cons '(a) '(b c d))
87 | '(cons '(a) '(b c d))
88 | '((a) b c d))
89 | (test (cons "a" '(b c))
90 | '(cons "a" '(b c))
91 | '("a" b c))
92 | (test (cons 'a 3)
93 | '(cons 'a 3)
94 | '(a . 3))
95 | (test (cons '(a b) 'c)
96 | '(cons '(a b) 'c)
97 | '((a b) . c))
98 |
99 | (test (car '(a b c))
100 | '(car '(a b c))
101 | 'a)
102 | (test (car '((a) b c d))
103 | '(car '((a) b c d))
104 | '(a))
105 | (test (car '(1 . 2))
106 | '(car '(1 . 2))
107 | '1)
108 |
109 | (test (cdr '((a) b c d))
110 | '(cdr '((a) b c d))
111 | '(b c d))
112 | (test (cdr '(1 . 2))
113 | '(cdr '(1 . 2))
114 | '2)
115 |
116 | (define (f) (list 'not-a-constant-list))
117 |
118 | (test (list? '(a b c))
119 | '(list? '(a b c))
120 | '#t)
121 | (test (list? '())
122 | '(list? '())
123 | '#t)
124 |
125 | (test (list 'a (+ 3 4) 'c)
126 | '(list 'a (+ 3 4) 'c)
127 | '(a 7 c))
128 | (test (list)
129 | '(list)
130 | '())
131 |
132 | (test (length '(a b c))
133 | '(length '(a b c))
134 | '3)
135 | (test (length '(a (b) (c d e)))
136 | '(length '(a (b) (c d e)))
137 | '3)
138 | (test (length '())
139 | '(length '())
140 | '0)
141 |
142 | (test (append '(x) '(y))
143 | '(append '(x) '(y))
144 | '(x y))
145 | (test (append '(a) '(b c d))
146 | '(append '(a) '(b c d))
147 | '(a b c d))
148 | (test (append '(a (b)) '((c)))
149 | '(append '(a (b)) '((c)))
150 | '(a (b) (c)))
151 | (test (append)
152 | '(append)
153 | '())
154 | (test (append '(a b) '(c . d))
155 | '(append '(a b) '(c . d))
156 | '(a b c . d))
157 | (test (append '() 'a)
158 | '(append '() 'a)
159 | 'a)
160 |
161 | (test (append '(a) '(b c) '(d) '(e f))
162 | '(append '(a) '(b c) '(d) '(e f))
163 | '(a b c d e f))
164 | (test (append '(x y z))
165 | '(append '(x y z))
166 | '(x y z))
167 | (test (eq? x (append x))
168 | '(eq? x (append x))
169 | '#t)
170 |
171 | (test (reverse '(a b c))
172 | '(reverse '(a b c))
173 | '(c b a))
174 | (test (reverse '(a (b c) d (e (f))))
175 | '(reverse '(a (b c) d (e (f))))
176 | '((e (f)) d (b c) a))
177 |
178 | (test (list-ref '(a b c d) 2)
179 | '(list-ref '(a b c d) 2)
180 | 'c)
181 |
182 | (test (memq 'a '(a b c))
183 | '(memq 'a '(a b c))
184 | '(a b c))
185 | (test (memq 'b '(a b c))
186 | '(memq 'b '(a b c))
187 | '(b c))
188 | (test (memq 'a '(b c d))
189 | '(memq 'a '(b c d))
190 | '#f)
191 | (test (memq (list 'a) '(b (a) c))
192 | '(memq (list 'a) '(b (a) c))
193 | '#f)
194 | (test (member (list 'a) '(b (a) c))
195 | '(member (list 'a) '(b (a) c))
196 | '((a) c))
197 | (test (memq 101 '(100 101 102))
198 | '(memq 101 '(100 101 102))
199 | 'unspecified)
200 | (test (memv 101 '(100 101 102))
201 | '(memv 101 '(100 101 102))
202 | '(101 102))
203 |
204 | (define e '((a 1) (b 2) (c 3)))
205 | (test (assq 'a e)
206 | '(assq 'a e)
207 | '(a 1))
208 | (test (assq 'b e)
209 | '(assq 'b e)
210 | '(b 2))
211 | (test (assq 'd e)
212 | '(assq 'd e)
213 | '#f)
214 | (test (assq (list 'a) '(((a)) ((b)) ((c))))
215 | '(assq (list 'a) '(((a)) ((b)) ((c))))
216 | '#f)
217 | (test (assoc (list 'a) '(((a)) ((b)) ((c))))
218 | '(assoc (list 'a) '(((a)) ((b)) ((c))))
219 | '((a)))
220 | (test (assv 5 '((2 3) (5 7) (11 13)))
221 | '(assv 5 '((2 3) (5 7) (11 13)))
222 | '(5 7))
223 |
224 | (SECTION 6 3 3) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
225 | (test (symbol? 'foo)
226 | '(symbol? 'foo)
227 | '#t)
228 | (test (symbol? (car '(a b)))
229 | '(symbol? (car '(a b)))
230 | '#t)
231 | (test (symbol? "bar")
232 | '(symbol? "bar")
233 | '#f)
234 | (test (symbol? 'nil)
235 | '(symbol? 'nil)
236 | '#t)
237 | (test (symbol? '())
238 | '(symbol? '())
239 | '#f)
240 | (test (symbol? #f)
241 | '(symbol? #f)
242 | '#f)
243 |
244 | (test (symbol->string (string->symbol "Malvina"))
245 | '(symbol->string (string->symbol "Malvina"))
246 | '"Malvina")
247 |
248 | (test (eq? 'mISSISSIppi 'mississippi)
249 | '(eq? 'mISSISSIppi 'mississippi)
250 | '#f)
251 | (test (eq? 'bitBlt (string->symbol "bitBlt"))
252 | '(eq? 'bitBlt (string->symbol "bitBlt"))
253 | '#t)
254 | (test (eq? 'JollyWog (string->symbol (symbol->string 'JollyWog)))
255 | '(eq? 'JollyWog (string->symbol (symbol->string 'JollyWog)))
256 | '#t)
257 | (test (string=? "K. Harper, M.D."
258 | (symbol->string (string->symbol "K. Harper, M.D.")))
259 | '(string=? "K. Harper, M.D."
260 | (symbol->string (string->symbol "K. Harper, M.D.")))
261 | '#t)
262 |
263 | (test (string=? (symbol->string 'a) (symbol->string 'A))
264 | '(string=? (symbol->string 'a) (symbol->string 'A))
265 | '#f)
266 | (test (not (or (string=? (symbol->string 'a) "A")
267 | (string=? (symbol->string 'A) "a")))
268 | '(not (or (string=? (symbol->string 'a) "A")
269 | (string=? (symbol->string 'A) "a")))
270 | '#t)
271 |
272 |
273 |
274 | (SECTION 6 4) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
275 | (test (procedure? car)
276 | '(procedure? car)
277 | '#t)
278 | (test (procedure? 'car)
279 | '(procedure? 'car)
280 | '#f)
281 | (test (procedure? (lambda (x) (* x x)))
282 | '(procedure? (lambda (x) (* x x)))
283 | '#t)
284 | (test (procedure? '(lambda (x) (* x x)))
285 | '(procedure? '(lambda (x) (* x x)))
286 | '#f)
287 | (test (procedure? '())
288 | '(procedure? '())
289 | '#f)
290 |
291 | (test (call-with-current-continuation procedure?)
292 | '(call-with-current-continuation procedure?)
293 | #t)
294 | (test (procedure? call-with-current-continuation)
295 | '(procedure? call-with-current-continuation)
296 | #t)
297 |
298 | (test (apply + (list 3 4))
299 | '(apply + (list 3 4))
300 | '7)
301 | (define compose (lambda (f g) (lambda args (f (apply g args)))))
302 | (test ((compose - *) 12 75)
303 | '((compose - *) 12 75)
304 | '-900)
305 |
306 | (test (apply (lambda (a b) (+ a b)) (list 3 4))
307 | '(apply (lambda (a b) (+ a b)) (list 3 4))
308 | '7)
309 | (test (apply + 10 (list 3 4))
310 | '(apply + 10 (list 3 4))
311 | '17)
312 | (test (apply + 100 10 (list 3 4))
313 | '(apply + 100 10 (list 3 4))
314 | '117)
315 | (test (apply list '())
316 | '(apply list '())
317 | '())
318 |
319 | (test (map cadr '((a b) (d e) (g h)))
320 | '(map cadr '((a b) (d e) (g h)))
321 | '(b e h))
322 | (test (map + '(1 2 3) '(4 5 6))
323 | '(map + '(1 2 3) '(4 5 6))
324 | '(5 7 9))
325 |
326 | (test (not (member (let ((count 0))
327 | (map (lambda (ignored)
328 | (set! count (+ count 1))
329 | count)
330 | '(a b))) '((1 2) (2 1))))
331 | '(not (member (let ((count 0))
332 | (map (lambda (ignored)
333 | (set! count (+ count 1))
334 | count)
335 | '(a b))) '((1 2) (2 1))))
336 | '#f)
337 |
338 | (test (let ((v (make-vector 5)))
339 | (for-each (lambda (i) (vector-set! v i (* i i)))
340 | '(0 1 2 3 4))
341 | v)
342 | '(let ((v (make-vector 5)))
343 | (for-each (lambda (i) (vector-set! v i (* i i)))
344 | '(0 1 2 3 4))
345 | v)
346 | '#(0 1 4 9 16))
347 |
348 | ;; force and delay
349 | (test (force (delay (+ 1 2)))
350 | '(force (delay (+ 1 2)))
351 | 3)
352 | (test (let ((p (delay (+ 1 2))))
353 | (list (force p) (force p)))
354 | '(let ((p (delay (+ 1 2))))
355 | (list (force p) (force p)))
356 | '(3 3))
357 |
358 | (define a-stream
359 | (letrec ((next (lambda (n) (cons n (delay (next (+ n 1)))))))
360 | (next 0)))
361 | (define head car)
362 | (define tail (lambda (stream) (force (cdr stream))))
363 | (test (head (tail (tail a-stream)))
364 | '(head (tail (tail a-stream)))
365 | 2)
366 |
367 | (define count 0)
368 | (define p (delay (begin (set! count (+ count 1))
369 | (if (> count x)
370 | count
371 | (force p)))))
372 | (define x 5)
373 | (test (force p)
374 | '(force p)
375 | 6)
376 | (test (begin (set! x 10) (force p))
377 | '(begin (set! x 10) (force p))
378 | 6)
379 |
380 | (test (call-with-current-continuation
381 | (lambda (exit)
382 | (for-each (lambda (x) (if (negative? x) (exit x)))
383 | '(54 0 37 -3 245 19))
384 | #t))
385 | '(call-with-current-continuation
386 | (lambda (exit)
387 | (for-each (lambda (x) (if (negative? x) (exit x)))
388 | '(54 0 37 -3 245 19))
389 | #t))
390 | -3)
391 |
392 | (define list-length
393 | (lambda (obj)
394 | (call-with-current-continuation
395 | (lambda (return)
396 | (letrec ((r (lambda (obj) (cond ((null? obj) 0)
397 | ((pair? obj) (+ (r (cdr obj)) 1))
398 | (else (return #f))))))
399 | (r obj))))))
400 |
401 | (test (list-length '(1 2 3 4))
402 | '(list-length '(1 2 3 4))
403 | 4)
404 | (test (list-length '(a b . c))
405 | '(list-length '(a b . c))
406 | #f)
407 | (test (map cadr '())
408 | '(map cadr '())
409 | '())
410 |
411 | ;;; This tests full conformance of call-with-current-continuation. It
412 | ;;; is a separate test because some schemes do not support call/cc
413 | ;;; other than escape procedures. I am indebted to
414 | ;;; raja@copper.ucs.indiana.edu (Raja Sooriamurthi) for fixing this
415 | ;;; code. The function leaf-eq? compares the leaves of 2 arbitrary
416 | ;;; trees constructed of conses.
417 | (define (next-leaf-generator obj eot)
418 | (letrec ((return #f)
419 | (cont (lambda (x)
420 | (recur obj)
421 | (set! cont (lambda (x) (return eot)))
422 | (cont #f)))
423 | (recur (lambda (obj)
424 | (if (pair? obj)
425 | (for-each recur obj)
426 | (call-with-current-continuation
427 | (lambda (c)
428 | (set! cont c)
429 | (return obj)))))))
430 | (lambda () (call-with-current-continuation
431 | (lambda (ret) (set! return ret) (cont #f))))))
432 | (define (leaf-eq? x y)
433 | (let* ((eot (list 'eot))
434 | (xf (next-leaf-generator x eot))
435 | (yf (next-leaf-generator y eot)))
436 | (letrec ((loop (lambda (x y)
437 | (cond ((not (eq? x y)) #f)
438 | ((eq? eot x) #t)
439 | (else (loop (xf) (yf)))))))
440 | (loop (xf) (yf)))))
441 |
442 | (test (leaf-eq? '(a (b (c))) '((a) b c))
443 | '(leaf-eq? '(a (b (c))) '((a) b c))
444 | #t)
445 | (test (leaf-eq? '(a (b (c))) '((a) b c d))
446 | '(leaf-eq? '(a (b (c))) '((a) b c d))
447 | #f)
448 |
449 | (test (call-with-values (lambda () (values 4 5)) (lambda (a b) b))
450 | '(call-with-values (lambda () (values 4 5)) (lambda (a b) b))
451 | 5)
452 | (test (call-with-values * -)
453 | '(call-with-values * -)
454 | -1)
455 |
456 | (test (let ((path '())
457 | (c #f))
458 | (let ((add (lambda (s) (set! path (cons s path)))))
459 | (dynamic-wind
460 | (lambda () (add 'connect))
461 | (lambda ()
462 | (add (call-with-current-continuation
463 | (lambda (c0)
464 | (set! c c0)
465 | 'talk1))))
466 | (lambda () (add 'disconnect)))
467 | (if (< (length path) 4)
468 | (c 'talk2)
469 | (reverse path))))
470 | '(let ((path '())) ...)
471 | '(connect talk1 disconnect
472 | connect talk2 disconnect))
473 |
474 |
475 |
476 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
477 | (define (main argv) (report-errors))
478 |
--------------------------------------------------------------------------------
/tests/tests-g.sf:
--------------------------------------------------------------------------------
1 | ;;(load source "helpers.qa2")
2 | #fload "../lib/libs.sf"
3 | #fload "helpers.sf"
4 |
5 |
6 | (SECTION 7 1 1) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7 |
8 | (test (symbol? 'a)
9 | '(symbol? 'a)
10 | '#t "")
11 | (test (every? symbol? '(! $ % & * / : < = > ? ^ _ ~))
12 | '(every? symbol? '(! $ % & * / : < = > ? ^ _ ~))
13 | '#t "")
14 | (test (every? symbol? '(!1 $1 %1 &1 *1 /1 :1 <1 =1 >1 ?1 ^1 _1 ~1))
15 | '(every? symbol? '(!1 $1 %1 &1 *1 /1 :1 <1 =1 >1 ?1 ^1 _1 ~1))
16 | '#t
17 | "")
18 | (test (every? symbol? '(+ - ...))
19 | '(every? symbol? '(+ - ...))
20 | '#t "")
21 | (test (every? symbol? '(!+ !- !. !@))
22 | '(every? symbol? '(!+ !- !. !@))
23 | '#t "")
24 | (test (every? symbol? '(!.. $.+ %.- &.! *.: /:. :+. <-. =. >. ?. ~. _. ^.))
25 | '(every? symbol? '(!.. $.+ %.- &.! *.: /:. :+. <-. =. >. ?. ~. _. ^.))
26 | '#t "jaffrey's tests")
27 |
28 | (test (cdr '(1 .2))
29 | '(cdr '(1 .2))
30 | '((! "0.2")))
31 | (test (cadr '(1 ... 2))
32 | '(cadr '(1 ... 2))
33 | '...)
34 |
35 | #;(let ((i -1i))
36 | (test (string->number "3+4i")
37 | '(string->number "3+4i")
38 | (make-rectangular 3 4) '(string->number "3+4i"))
39 | (test (string->number "3-4i")
40 | '(string->number "3-4i")
41 | (make-rectangular 3 -4) '(string->number "3-4i"))
42 | (test (string->number "3+i")
43 | '(string->number "3+i")
44 | (make-rectangular 3 1) '(string->number "3+i"))
45 | (test (string->number "3-i")
46 | '(string->number "3-i")
47 | (make-rectangular 3 -1) '(string->number "3-i"))
48 | (test (string->number "+3i")
49 | '(string->number "+3i")
50 | (* 3 (make-rectangular 0 1)) '(string->number "+3i"))
51 | (test (string->number "-3i")
52 | '(string->number "-3i")
53 | (* -3 (make-rectangular 0 1)) '(string->number "-3i"))
54 | (test (string->number "+i")
55 | '(string->number "+i")
56 | (make-rectangular 0 1) '(string->number "+i"))
57 | (test (string->number "-i")
58 | '(string->number "-i")
59 | (- (make-rectangular 0 1)) '(string->number "-i")))
60 |
61 | ;; This is SFC-specific
62 | (test (string->number "3/4")
63 | '(string->number "3/4")
64 | #f '(string->number "3/4"))
65 | (test (string->number "-3/4")
66 | '(string->number "-3/4")
67 | #f '(string->number "-3/4"))
68 |
69 | #;(test (string->number "#i3")
70 | '(string->number "#i3")
71 | '(! "3.0"))
72 | (test (string->number "#e3.0")
73 | '(string->number "#e3.0")
74 | '3)
75 | ;; Maybe the following belong elsewhere?
76 | (test (string->number "#b111")
77 | '(string->number "#b111")
78 | '7)
79 | (test (string->number "#o111")
80 | '(string->number "#o111")
81 | '73)
82 | (test (string->number "#d111")
83 | '(string->number "#d111")
84 | '111)
85 | (test (string->number "1.0e2")
86 | '(string->number "1.0e2")
87 | '(! "100.0"))
88 | #;(test (string->number "1.0s2")
89 | '(string->number "1.0s2")
90 | '(! "100.0"))
91 | #;(test (string->number "1.0f2")
92 | '(string->number "1.0f2")
93 | '(! "100.0"))
94 | #;(test (string->number "1.0d2")
95 | '(string->number "1.0d2")
96 | '(! "100.0"))
97 | #;(test (string->number "1.0l2")
98 | '(string->number "1.0l2")
99 | '(! "100.0"))
100 |
101 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
102 | (define (main argv) (report-errors))
103 |
--------------------------------------------------------------------------------
/tests/tests-h.sf:
--------------------------------------------------------------------------------
1 | ;;(load source "helpers.qa2")
2 | #fload "../lib/libs.sf"
3 | #fload "helpers.sf"
4 |
5 | (SECTION 'Qa2 'bitwise 'operations);;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6 | (define-syntax logand fxand)
7 | (define-syntax logxor fxxor)
8 | (define-syntax logior fxior)
9 | (define-syntax logor fxior)
10 | (define-syntax lognot fxnot)
11 | (define (ash a b)
12 | (if (< b 0) (fxarithmetic-shift-right a (- b))
13 | (fxarithmetic-shift-left a b)))
14 |
15 | (test (logand -1 -1)
16 | '(logand -1 -1)
17 | '-1)
18 | (test (logand -1 0)
19 | '(logand -1 0)
20 | '0)
21 | (test (logand 5 3)
22 | '(logand 5 3)
23 | '1)
24 | (test (logor -1 -1)
25 | '(logor -1 -1)
26 | '-1)
27 | (test (logor -1 0)
28 | '(logor -1 0)
29 | '-1)
30 | (test (logor 5 3)
31 | '(logor 5 3)
32 | '7)
33 | (test (logxor -1 -1)
34 | '(logxor -1 -1)
35 | '0)
36 | (test (logxor -1 0)
37 | '(logxor -1 0)
38 | '-1)
39 | (test (logxor 5 3)
40 | '(logxor 5 3)
41 | '6)
42 | (test (lognot -2)
43 | '(lognot -2)
44 | '1)
45 | (test (lognot -1)
46 | '(lognot -1)
47 | '0)
48 | (test (lognot 0)
49 | '(lognot 0)
50 | '-1)
51 | (test (lognot 1)
52 | '(lognot 1)
53 | '-2)
54 | (test (lognot 2)
55 | '(lognot 2)
56 | '-3)
57 |
58 | (test (ash 1 2)
59 | '(ash 1 2)
60 | '4)
61 | (test (ash -1 2)
62 | '(ash -1 2)
63 | '-4)
64 |
65 | (test (ash 13 -2)
66 | '(ash 13 -2)
67 | '3)
68 | #;(test (ash -1 -3)
69 | '(ash -1 -3)
70 | '-1)
71 |
72 | (test (ash 4 -2)
73 | '(ash 4 -2)
74 | '1)
75 | #;(test (ash -1 -1)
76 | '(ash -1 -1)
77 | '-1)
78 | (test (ash 64 -3)
79 | '(ash 64 -3)
80 | '8)
81 | #;(test (ash -1 -7)
82 | '(ash -1 -7)
83 | '-1)
84 | #;(test (ash -64 -3)
85 | '(ash -64 -3)
86 | '-8)
87 |
88 |
89 | (test (ash -1 7)
90 | '(ash -1 7)
91 | '-128)
92 | (test (ash -64 3)
93 | '(ash -64 3)
94 | '-512)
95 |
96 | (SECTION 'Qa2 'rounding 'operations);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
97 | (test (floor (! "-4.3"))
98 | '(floor (! "-4.3"))
99 | '(! "-5.0"))
100 | (test (ceiling (! "-4.3"))
101 | '(ceiling (! "-4.3"))
102 | '(! "-4.0"))
103 | (test (truncate (! "-4.3"))
104 | '(truncate (! "-4.3"))
105 | '(! "-4.0"))
106 | (test (round (! "-4.3"))
107 | '(round (! "-4.3"))
108 | '(! "-4.0"))
109 | (test (floor (! "3.5"))
110 | '(floor (! "3.5"))
111 | '(! "3.0"))
112 | (test (ceiling (! "3.5"))
113 | '(ceiling (! "3.5"))
114 | '(! "4.0"))
115 | (test (truncate (! "3.5"))
116 | '(truncate (! "3.5"))
117 | '(! "3.0"))
118 | (test (round (! "3.5"))
119 | '(round (! "3.5"))
120 | '(! "4.0"))
121 |
122 |
123 | (SECTION 'Qa2 'multiple 'values);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
124 | (test (let-values ([(a b c) (values 1 2 3)]) (list b c a c))
125 | '(let-values ([(a b c) (values 1 2 3)]) (list b c a c))
126 | '(2 3 1 3))
127 | (test (let-values ([(a) (values 123)]) a)
128 | '(let-values ([(a) (values 123)]) a)
129 | '123)
130 | (test (let-values ([() (values)]) 'a)
131 | '(let-values ([() (values)]) 'a)
132 | 'a)
133 |
134 | (test (call-with-values (lambda () 1) (lambda (x) (list x x)))
135 | '(call-with-values (lambda () 1) (lambda (x) (list x x)))
136 | '(1 1))
137 | (test (call-with-values (lambda () (values 1 2 3)) list)
138 | '(call-with-values (lambda () (values 1 2 3)) list)
139 | '(1 2 3))
140 |
141 | (SECTION 'Qa2 'top-level 'defines);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
142 | (set! foo 'foo)
143 | (test foo
144 | 'foo
145 | 'foo)
146 |
147 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
148 | (define (main argv) (report-errors))
149 |
--------------------------------------------------------------------------------
/tests/tests-i.sf:
--------------------------------------------------------------------------------
1 | ;; Coverage tests
2 | ;;(load source "helpers.qa2")
3 | #fload "../lib/libs.sf"
4 | #fload "helpers.sf"
5 |
6 | (SECTION 'Qa2 'code 'coverage) ;;;;;;;;;;;;;;;;;;
7 | #;(test '3+4i
8 | '3+4i
9 | 3+4i)
10 | ;;(test {foo 1 2 'a}
11 | ;; '{foo 1 2 'a}
12 | ;; (variant 'foo 1 2 'a))
13 |
14 | (test (+ #xff 1)
15 | '(+ #xff 1)
16 | 256)
17 |
18 | (test (* 100 1e-2)
19 | 1
20 | 1)
21 |
22 | ;; check that keywords are properly handled
23 | (define check-cond
24 | (let ([else 'in-the-else])
25 | (lambda (x)
26 | (cond
27 | [(= x 1) 'one]
28 | [(= x 2) 'two]
29 | [else]))))
30 | (for-each (lambda (x y)
31 | (test (check-cond x)
32 | (list 'check-cond x)
33 | y))
34 | '(1 2 4)
35 | '(one two in-the-else))
36 |
37 | (define check-cond-2
38 | (let ()
39 | (lambda (x)
40 | (cond
41 | [(= x 1) 'one]
42 | [(= x 2) 'two]
43 | [(> x 5) => (lambda (y) (cons x y))]
44 | [#t car x]))))
45 | (for-each (lambda (x y)
46 | (test (check-cond-2 x)
47 | (list 'check-cond-2 x)
48 | y))
49 | '(1 2 10 4)
50 | '(one two (10 . #t) 4))
51 |
52 | (define check-cond-3
53 | (let ()
54 | (lambda (x)
55 | (cond
56 | [(= x 1) 'one]
57 | [(= x 2) 'two]
58 | [(> x 5) => (lambda (y) (cons x y))]))))
59 | (for-each (lambda (x y)
60 | (test (check-cond-3 x)
61 | (list 'check-cond-3 x)
62 | y))
63 | '(1 2 10 4)
64 | '(one two (10 . #t) unspecified))
65 |
66 |
67 | ;; when and unless
68 | #;(test (when (= (+ 2 3) 5) (cons 1 2))
69 | '(when (= (+ 2 3) 5) (cons 1 2))
70 | '(1 . 2))
71 |
72 | #;(test (when (= (+ 2 3) 6) (cons 1 2))
73 | '(when (= (+ 2 3) 6) (cons 1 2))
74 | 'unspecified)
75 |
76 | #;(test (unless (= (+ 2 3) 5) (cons 1 2))
77 | '(unless (= (+ 2 3) 5) (cons 1 2))
78 | 'unspecified)
79 |
80 | #;(test (unless (= (+ 2 3) 6) (cons 1 2))
81 | '(unless (= (+ 2 3) 6) (cons 1 2))
82 | '(1 . 2))
83 |
84 |
85 | ;; We allow empty begins
86 | #;(test (begin)
87 | '(begin)
88 | 'unspecified)
89 |
90 | (SECTION 'Qa2 'case 'handling) ;;;;;;;;;;;;;;;;;;
91 | (let ()
92 | (define (check-case n)
93 | (case (+ n 1)
94 | [(1 3 5) 'even]
95 | [(0 2 4) 'odd]
96 | [(10 11 12 13) => (lambda (y) (list 'large y n))]
97 | [else 'other]))
98 | (for-each (lambda (x y)
99 | (test (check-case x)
100 | (list 'check-case x)
101 | y))
102 | '(1 2 4 5 6 7 10 20 30)
103 | '(odd even even other other other (large 11 10) other other)))
104 |
105 | (let ()
106 | (define (check-case-2 n)
107 | (case (+ n 1)
108 | [(1 3 5) 'even]
109 | [(0 2 4) 'odd]
110 | [(10 11 12 13) => (lambda (y) (list 'large y n))]
111 | [else => -]))
112 | (for-each (lambda (x y)
113 | (test (check-case-2 x)
114 | (list 'check-case-2 x)
115 | y))
116 | '(1 2 4 5 6 7 10 20 30)
117 | '(odd even even -6 -7 -8 (large 11 10) -21 -31)))
118 |
119 | (let ()
120 | (define (check-case-3 n)
121 | (case (+ n 1)
122 | [(1 3 5) 'even]
123 | [(0 2 4) 'odd]
124 | [(10 11 12 13) => (lambda (y) (list 'large y n))]))
125 | (for-each (lambda (x y)
126 | (test (check-case-3 x)
127 | (list 'check-case-3 x)
128 | y))
129 | '(1 2 4 5 6 7 10 20 30)
130 | '(odd even even unspecified unspecified unspecified (large 11 10)
131 | unspecified unspecified)))
132 |
133 | (let ()
134 | (define (check-case-4 n)
135 | (case (+ n 1)
136 | [(1 3 5) 'even]
137 | [(0 2 4) 'odd]
138 | [(10 11 12 13) (list 'large n)]))
139 | (for-each (lambda (x y)
140 | (test (check-case-4 x)
141 | (list 'check-case-4 x)
142 | y))
143 | '(1 2 4 5 6 7 10 20 30)
144 | '(odd even even unspecified unspecified unspecified (large 10)
145 | unspecified unspecified)))
146 |
147 | ;; overwriting a macros should be allowed:
148 | (define cond "abse")
149 | (test cond
150 | 'cond
151 | "abse" "overwritten cond")
152 |
153 |
154 | (SECTION 'Qa2 'lists) ;;;;;;;;;;;;;;;;;;;;;;
155 | (test (list? '())
156 | '(list? '())
157 | #t)
158 | (test (list? list?)
159 | '(list? list?)
160 | #f)
161 | (test (list? '(a b . c))
162 | '(list? '(a b . c))
163 | #f)
164 | (test (reverse '())
165 | '(reverse '())
166 | '())
167 |
168 | (test (list-tail '(1 2 3 4 5) 3)
169 | '(list-tail '(1 2 3 4 5) 3)
170 | '(4 5))
171 |
172 |
173 | (SECTION 'Qa2 'procedures) ;;;;;;;;;;;;;;;;;;;;;;
174 | (test (procedure? list)
175 | '(procedure? list)
176 | #t)
177 |
178 | (SECTION 'Qa2 'equivalence 'preducates) ;;;;;;;;;;;;;;;;;;;;;;
179 | (test (eq? #t #t)
180 | '(eq? #t #t)
181 | #t)
182 |
183 | (test (eqv? #t #f)
184 | '(eqv? #t #f)
185 | #f)
186 |
187 | (test (equal? '(a v) '(x y))
188 | '(equal? '(a v) '(x y))
189 | #f)
190 |
191 | (test (equal? '#(1 2 3) '#(1 5 4))
192 | '(equal? '#(1 2 3) '#(1 5 4))
193 | #f)
194 |
195 | (test (equal? '#(1 2 3) '#(1 5))
196 | '(equal? '#(1 2 3) '#(1 5))
197 | #f)
198 |
199 | (SECTION 'Qa2 'numbers) ;;;;;;;;;;;;;;;;;;;;;;;;;
200 | (test (real-part (! "47"))
201 | '(real-part (! "47"))
202 | 47)
203 |
204 | (test (imag-part (! "4"))
205 | '(imag-part (! "4"))
206 | 0)
207 |
208 | (test (string? (get-environment-variable "HOME"))
209 | '(string? (get-environment-variable "HOME"))
210 | #t)
211 | (test (get-environment-variable "3765b84686784f13bb620d965fa325bd1546b344")
212 | '(get-environment-variable "3765b84686784f13bb620d965fa325bd1546b344")
213 | #f)
214 |
215 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
216 | (define (main argv) (report-errors))
217 |
--------------------------------------------------------------------------------
/tests/tests-l.sf:
--------------------------------------------------------------------------------
1 | #fload "../lib/libs.sf"
2 | #fload "helpers.sf"
3 |
4 | (SECTION "SFC arithmetics") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5 |
6 | (test (/ 4) '(/ 4) 0.25)
7 | (test (/ 1 4) '(/ 1 4) 0.25)
8 |
9 | (test (* 4 (/ 4)) '(* 4 (/ 4)) 1.0)
10 | (test (* (/ 4) 4) '(* (/ 4) 4) 1.0)
11 |
12 | (test (* 4 (/ 4)) '(* 4 (/ 4)) 1)
13 | (test (* (/ 4) 4) '(* (/ 4) 4) 1)
14 |
15 | (test (* 4 (/ 1 4)) '(* 4 (/ 1 4)) 1)
16 | (test (* (/ 1 4) 4) '(* (/ 1 4) 4) 1)
17 |
18 | (test (* 4 0.25) '(* 4 0.25) 1.0)
19 |
20 | (define (main argv) (report-errors))
21 |
--------------------------------------------------------------------------------
/tests/tests-m.sf:
--------------------------------------------------------------------------------
1 | #fload "../lib/libs.sf"
2 | #fload "helpers.sf"
3 |
4 | (SECTION "SFC procedure predicate") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5 |
6 | (define (do-test p n v msg)
7 | (test (procedure? p) (list 'procedure? n) v msg))
8 |
9 | (define (add x y ) (+ x y))
10 | (define (xxx x y . z) (+ x y))
11 |
12 | (do-test car 'car #t "car built-in")
13 | (do-test do-test 'do-test #t "user-defined function")
14 | (do-test list 'list #t "list built-in")
15 | (do-test add 'add #t "defined proc with two args")
16 | (do-test xxx 'xxx #t "defined proc with two args and extras")
17 | (do-test 123 '123 #f "number")
18 |
19 | (define (main argv) (report-errors))
20 |
--------------------------------------------------------------------------------