├── .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 | 76 | 77 | 78 | 79 | 80 | 81 |
syntax
procedure
standard prelude typedef
standard prelude #define
runtime host variable
command line utility
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 | 64 | 65 | 66 |
(define variable expression)syntax
(define-syntax keyword datum)syntax
(begin definition …)syntax
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 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
(%prim code expression1 …)syntax
(%prim* code expression1 …)syntax
(%prim? code expression1 …)syntax
(%prim! code expression1 …)syntax
(%prim?! code expression1 …)syntax
(%prim*? code expression1 …)syntax
(%prim*! code expression1 …)syntax
(%prim*?! code expression1 …)syntax
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 | 100 | 101 | 102 |
*allocates from garbage-collectible heap
!has side effects other than allocation
?observes side effects
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 | 124 | 125 |
RT%prim
not RT%prim* %prim? %prim!
%prim?! %prim*? %prim*! %prim*?!
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 | 137 | 138 | 139 |
 DCE safeDCE unsafe
GC safe%prim  %prim? %prim!  %prim?!
GC unsafe%prim* %prim*? %prim*! %prim*?!
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 | 40 | 41 | 63 | 79 | 90 | 91 |
42 |

lambda   3.3.

43 |

if   3.4.

44 |

set!   3.5.

45 |

letcc   3.6.

46 |

withcc   3.6.

47 |

sequence   3.7.

48 |

begin   3.7.  3.7.

49 |

 

50 |

syntax-lambda   4.3.

51 |

syntax-rules   4.4.

52 |

 

53 |

define   5.

54 |

define-syntax   5.

55 |

 

56 |

#fload   6.1.2.

57 |

main   6.1.4.

58 |

%include   6.2.

59 |

%definition   6.2.

60 |

%localdef   6.2.

61 |

 

62 |
64 |

obj   7.1.

65 |

cxtype_t   7.1.1.

66 |

notobjptr   7.1.1.

67 |

isobjptr   7.1.1.

68 |

notaptr   7.1.1.

69 |

isaptr   7.1.1.

70 |

hblklen   7.1.1.

71 |

hblkref   7.1.1.

72 |

hp   7.2.

73 |

hreserve   7.2.1.

74 |

hbsz   7.2.1.

75 |

hendblk   7.2.1.

76 |

hpushptr   7.2.2.

77 |

 

78 |
80 |

%prim   8.1.

81 |

%prim*   8.1.

82 |

%prim?   8.1.

83 |

%prim!   8.1.

84 |

%prim?!   8.1.

85 |

%prim*?   8.1.

86 |

%prim*!   8.1.

87 |

%prim*?!   8.1.

88 |

 

89 |
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 | 40 | 41 | 64 | 86 | 101 | 102 |
42 |

INTRODUCTION

43 |

Backround

44 |

Libraries and FFIs

45 |

Portability

46 |

 

47 |

1.  Syntax and semantics

48 |

1.1.  Syntax

49 |

1.2.  Semantics

50 |

 

51 |

2.  Notation and terminology

52 |

2.1.  Entry format

53 |

2.2.  Evaluation examples

54 |

 

55 |

3.  Expressions

56 |

3.1.  Variable references

57 |

3.2.  Procedure calls

58 |

3.3.  Procedures

59 |

3.4.  Conditionals

60 |

3.5.  Assignments

61 |

3.6.  Continuations

62 |

3.7.  Sequencing

63 |
65 |

4.  Macros

66 |

4.1.  Syntactic keywords

67 |

4.2.  Macro uses

68 |

4.3.  Macro abstractions

69 |

4.4.  Macro transformers

70 |

 

71 |

5.  Definitions

72 |

5.1.  Top level definitions

73 |

5.2.  Internal definitions

74 |

 

75 |

6.  Compilation

76 |

6.1.  Compilation units

77 |

6.1.1.  Global namespace

78 |

6.1.2.  Unit dependencies

79 |

6.1.3.  Linkage

80 |

6.1.4.  Main entry point

81 |

6.2.  Including C code

82 |

6.3.  Compilation technique

83 |

6.3.1.  Host functions

84 |

6.3.2.  Optimizations

85 |
87 |

7.  Runtime system

88 |

7.1.  Object representation

89 |

7.1.1.  Partitioning of obj values

90 |

7.1.2.  Representation of procedures

91 |

7.1.3.  Representation of locations

92 |

7.2.  Garbage collection

93 |

7.2.1.  Allocation of obj blocks

94 |

7.2.2.  Allocation of native blocks

95 |

 

96 |

8.  Writing primitives in C

97 |

8.1.  Inline C expressions

98 |

 

99 |

index of entries

100 |
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= 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> 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=? 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=? 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>? 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>? 7 | string-downcase string-foldcase string-upcase)) 8 | (export 9 | char-alphabetic? 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>? 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>? 21 | char-downcase char-lower-case? char-numeric? 22 | char-ready? 23 | char-upcase char-upper-case? char-whitespace? 24 | 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>? 54 | string-copy string-fill! string-length string-ref string-set! 55 | 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? "" "") 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") 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=? "abd" "abcz") 122 | '(string>=? "abd" "abcz") 123 | '#t) 124 | (test (string=? "" "abcz") 131 | '(string>=? "" "abcz") 132 | '#f) 133 | 134 | ;; reversing arg order: 135 | (test (string=? "abcz" "abd") 154 | '(string>=? "abcz" "abd") 155 | '#f) 156 | (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 | --------------------------------------------------------------------------------