spook

A "game" for the 2023 Autumn Lisp Game Jam. Won first place! (from the bottom...)
git clone https://kaka.farm/~git/spook
Log | Files | Refs | LICENSE

library.scm (53524B)


      1 ;;;; library.scm - runtime-library (Scheme part)
      2 
      3 
      4 (let-syntax
      5     ((case-lambda   ; this is not the same as the usual `case-lambda'!
      6       (letrec-syntax ((scan
      7 		       (syntax-rules ()
      8 			 ((_ (x) (lst ...)) (%dispatch lst ... x))
      9 			 ((_ ((llist . body) . more) (lst ...))
     10 			  (scan more (lst ... (lambda llist . body)))))))
     11 	(syntax-rules ()
     12 	  ((_ clause ...)
     13 	   (lambda args
     14 	     (scan (clause ...) ()))))))
     15      (define-inline
     16 	 (syntax-rules 
     17 	     ___ ()
     18 	     ((_ (name . args) body ___)
     19 	      (define-syntax name
     20 		(lambda args body ___))))))
     21   (begin
     22 
     23     (define-library-section internal-essentials
     24 
     25       (default
     26 
     27 	;; (%string->jstring STRING) -> JSTRING
     28 	(define-inline (%string->jstring x) (%inline "SPOCK.jstring" x))
     29 
     30 	;; (%jstring->string JSTRING) -> STRING
     31 	(define-inline (%jstring->string x) (%inline "new SPOCK.String" x))
     32 
     33 	;; (%list ...) -> LIST
     34 	;; used for manifest `lambda' with rest argument
     35 	(define (%list . xs) xs)
     36 
     37 	;; (%car X) -> Y
     38 	(define-inline (%car x) (%property-ref "car" x))
     39 
     40 	;; (%cdr X) -> Y
     41 	(define-inline (%cdr x) (%property-ref "cdr" x))
     42 
     43 	))
     44 
     45 
     46     (define-library-section essentials
     47 
     48       (default
     49 
     50 	(define-inline (eq? x y) 
     51 	  (%inline (1 "===" 2) x y))
     52 
     53 	(define-inline (eqv? x y)
     54 	  (%inline "SPOCK.eqvp" x y))
     55 
     56 	(define-inline (equal? x y) (%inline "SPOCK.equalp" x y))
     57 	(define-inline (not x) (if x #f #t))
     58 
     59 	))
     60 
     61     
     62     (define-library-section basic-type-predicates
     63 
     64       (default
     65 
     66 	(define-inline (symbol? x) (%inline (1 "instanceof SPOCK.Symbol") x))
     67 	(define-inline (pair? x) (%inline (1 "instanceof SPOCK.Pair") x))
     68 	(define-inline (number? x) (eq? (%inline "typeof" x) "number"))
     69 	(define-inline (char? x) (%inline (1 "instanceof SPOCK.Char") x))
     70 	(define-inline (void? x) (%void? x))
     71 	(define-inline (vector? x) (%inline (1 "instanceof Array") x))
     72 	(define-inline (procedure? x) (eq? (%inline "typeof" x) "function"))
     73 	(define-inline (eof-object? x) (eq? x (%host-ref "SPOCK.EOF")))
     74 	(define-inline (boolean? x) (or (eq? x #t) (eq? x #f)))
     75 
     76 	(define-inline (string? x)
     77 	  (or (eq? (%inline "typeof" x) "string")
     78 	      (%inline (1 "instanceof SPOCK.String") x)))
     79 
     80 	))
     81 
     82 
     83     (define-library-section multiple-values
     84 
     85       (default
     86 
     87 	(define values
     88 	  (%native-lambda
     89 	   "return K.apply(SPOCK.global, Array.prototype.slice.call(arguments, 1));"))
     90 
     91 	(define call-with-values
     92 	  (%native-lambda
     93 	   "var thunk = arguments[ 1 ];"
     94 	   "var proc = arguments[ 2 ];"
     95 	   "function k2() {"
     96 	   " var args = Array.prototype.slice.call(arguments);"
     97 	   " args.unshift(K);"
     98 	   " return proc.apply(SPOCK.global, args);}"
     99 	   "return thunk(k2);"))
    100 
    101 	))
    102 
    103 
    104     (define-library-section multiple-value-hacks
    105 
    106       (default
    107 
    108 	;; (%call-with-saved-values THUNK1 THUNK2)
    109 	(define %call-with-saved-values
    110 	  (%native-lambda
    111 	   "var t1 = arguments[ 1 ];"
    112 	   "var t2 = arguments[ 2 ];"
    113 	   "var args;"
    114 	   "function k2() { return K.apply(SPOCK.global, args); }"
    115 	   "function k1() {"
    116 	   " args = Array.prototype.slice.call(arguments);"
    117 	   " return t2(k2);}"
    118 	   "return t1(k1);"))
    119 
    120 	))
    121 
    122 
    123     (define-library-section nonstandard-essentials
    124 
    125       (default
    126 
    127 	(define-inline (void) (%void))	; ignores extra arguments
    128 
    129 	))
    130 
    131 
    132     (define-library-section basic-list-operations
    133 
    134       (default
    135 
    136 	(define-inline (null? x) (eq? x '()))
    137 	(define-inline (car x) (%car (%check ("SPOCK.Pair") x)))
    138 	(define-inline (cdr x) (%cdr (%check ("SPOCK.Pair") x)))
    139 	(define-inline (list . xs) xs)
    140 	(define-inline (cons x y) (%inline "new SPOCK.Pair" x y))
    141 	
    142 	(define-inline (set-car! x y)
    143 	  (%inline (1 ".car = " 2) (%check ("SPOCK.Pair") x) y))
    144 
    145 	(define-inline (set-cdr! x y)
    146 	  (%inline (1 ".cdr = " 2) (%check ("SPOCK.Pair") x) y))
    147 
    148 	(define (list? x)
    149 	  (let loop ((fast x) (slow x))
    150 	    (or (null? fast)
    151 		(and (pair? fast)
    152 		     (let ((fast (%cdr fast)))
    153 		       (or (null? fast)
    154 			   (and (pair? fast)
    155 				(let ((fast (%cdr fast))
    156 				      (slow (%cdr slow)))
    157 				  (and (not (eq? fast slow))
    158 				       (loop fast slow))))))))))
    159 
    160 	(define-inline (caar x) (car (car x)))
    161 	(define-inline (cadr x) (car (cdr x)))
    162 	(define-inline (cdar x) (cdr (car x)))
    163 	(define-inline (cddr x) (cdr (cdr x)))
    164 	(define (caaar x) (car (car (car x))))
    165 	(define (caadr x) (car (car (cdr x))))
    166 	(define (cadar x) (car (cdr (car x))))
    167 	(define (caddr x) (car (cdr (cdr x))))
    168 	(define (cdaar x) (cdr (car (car x))))
    169 	(define (cdadr x) (cdr (car (cdr x))))
    170 	(define (cddar x) (cdr (cdr (car x))))
    171 	(define (cdddr x) (cdr (cdr (cdr x))))
    172 	(define (caaaar x) (car (car (car (car x)))))
    173 	(define (caaadr x) (car (car (car (cdr x)))))
    174 	(define (caadar x) (car (car (cdr (car x)))))
    175 	(define (caaddr x) (car (car (cdr (cdr x)))))
    176 	(define (cadaar x) (car (cdr (car (car x)))))
    177 	(define (cadadr x) (car (cdr (car (cdr x)))))
    178 	(define (caddar x) (car (cdr (cdr (car x)))))
    179 	(define (cadddr x) (car (cdr (cdr (cdr x)))))
    180 	(define (cdaaar x) (cdr (car (car (car x)))))
    181 	(define (cdaadr x) (cdr (car (car (cdr x)))))
    182 	(define (cdadar x) (cdr (car (cdr (car x)))))
    183 	(define (cdaddr x) (cdr (car (cdr (cdr x)))))
    184 	(define (cddaar x) (cdr (cdr (car (car x)))))
    185 	(define (cddadr x) (cdr (cdr (car (cdr x)))))
    186 	(define (cdddar x) (cdr (cdr (cdr (car x)))))
    187 	(define (cddddr x) (cdr (cdr (cdr (cdr x)))))
    188 
    189 	(define-inline (length lst) (%inline "SPOCK.length" lst))
    190 
    191 	(define (append . lsts)
    192 	  (if (null? lsts)
    193 	      '()
    194 	      (let loop ((lsts lsts))
    195 		(if (null? (%cdr lsts))
    196 		    (%car lsts)
    197 		    (let copy ((node (%car lsts)))
    198 		      (if (pair? node)
    199 			  (cons (%car node) (copy (%cdr node)))
    200 			  ;; ignores non-list node
    201 			  (loop (%cdr lsts))))))))
    202 
    203 	(define (reverse lst)
    204 	  (let loop ((lst lst) (rest '()))
    205 	    (if (pair? lst)
    206 		(loop (%cdr lst) (cons (%car lst) rest))
    207 		;; ignores non-list node
    208 		rest)))
    209 
    210 	(define (list-tail lst i)
    211 	  (let loop ((i (%check "number" i))
    212 		     (lst lst))
    213 	    (if (%inline (1 " <= 0") i)
    214 		lst
    215 		(loop (%inline (1 " - 1") i)
    216 		      (%cdr (%check ("SPOCK.Pair") lst))))))
    217 
    218 	(define list-ref
    219 	  (let ((list-tail list-tail))
    220 	    (lambda (lst i)
    221 	      (%car (%check ("SPOCK.Pair") (list-tail lst i))))))
    222 
    223 	(define memq
    224 	  (%native-lambda
    225 	   "var x = arguments[ 1 ];"
    226 	   "for(var n = arguments[ 2 ]; n instanceof SPOCK.Pair; n = n.cdr) {"
    227 	   "  if(n.car === x) return K(n);"
    228 	   "}"
    229 	   "return K(false);"))
    230 
    231 	(define memv
    232 	  (%native-lambda
    233 	   "var x = arguments[ 1 ];"
    234 	   "for(var n = arguments[ 2 ]; n instanceof SPOCK.Pair; n = n.cdr) {"
    235 	   "  if(SPOCK.eqvp(n.car, x)) return K(n);"
    236 	   "}"
    237 	   "return K(false);"))
    238 
    239 	(define member
    240 	  (%native-lambda
    241 	   "var x = arguments[ 1 ];"
    242 	   "for(var n = arguments[ 2 ]; n instanceof SPOCK.Pair; n = n.cdr) {"
    243 	   "  if(SPOCK.equalp(n.car, x)) return K(n);"
    244 	   "}"
    245 	   "return K(false);"))
    246 
    247 	(define assq
    248 	  (%native-lambda
    249 	   "var x = arguments[ 1 ];"
    250 	   "for(var n = arguments[ 2 ]; n instanceof SPOCK.Pair; n = n.cdr) {"
    251 	   "  var p = n.car;"
    252 	   "  if(p instanceof SPOCK.Pair && p.car === x) return K(p);"
    253 	   "}"
    254 	   "return K(false);"))
    255 
    256 	(define assv
    257 	  (%native-lambda
    258 	   "var x = arguments[ 1 ];"
    259 	   "for(var n = arguments[ 2 ]; n instanceof SPOCK.Pair; n = n.cdr) {"
    260 	   "  var p = n.car;"
    261 	   "  if(p instanceof SPOCK.Pair && SPOCK.eqvp(p.car, x)) return K(p);"
    262 	   "}"
    263 	   "return K(false);"))
    264 
    265 	(define assoc
    266 	  (%native-lambda
    267 	   "var x = arguments[ 1 ];"
    268 	   "for(var n = arguments[ 2 ]; n instanceof SPOCK.Pair; n = n.cdr) {"
    269 	   "  var p = n.car;"
    270 	   "  if(p instanceof SPOCK.Pair && SPOCK.equalp(p.car, x)) return K(p);"
    271 	   "}"
    272 	   "return K(false);"))
    273 
    274 	))
    275 
    276 
    277     (define-library-section numeric-predicates
    278 
    279       (default
    280 	
    281 	(define-inline (zero? x) (eq? 0 (%check "number" x)))
    282 	(define-inline (positive? x) (%inline (1 ">" 2) (%check "number" x) 0))
    283 	(define-inline (negative? x) (%inline (1 "<" 2) (%check "number" x) 0))
    284 	(define-inline (odd? x) (not (eq? 0 (%inline (1 "%" 2) (%check "number" x) 2))))
    285 	(define-inline (even? x) (eq? 0 (%inline (1 "%" 2) (%check "number" x) 2)))
    286 	(define-inline (complex? x) (eq? (%inline "typeof" x) "number"))
    287 	(define-inline (rational? x) (eq? (%inline "typeof" x) "number"))
    288 	(define-inline (real? x) (eq? (%inline "typeof" x) "number"))
    289 
    290 	(define-inline (integer? x) 
    291 	  (and (eq? (%inline "typeof" x) "number")
    292 	       (eq? x (%inline "Math.round" x) x)))
    293 
    294 	(define-inline (exact? x)
    295 	  (let ((x (%check "number" x)))
    296 	    (eq? x (%inline "Math.round" x) x)))
    297 	
    298 	(define-inline (inexact? x) (not (exact? x)))
    299 	
    300 	))
    301 
    302 
    303     (define-library-section native-basic-arithmetic
    304 
    305       (debug
    306 
    307 	(define %+
    308 	  (%native-lambda
    309 	   "var len = arguments.length;"
    310 	   "switch(len) {"
    311 	   "case 1: return K(0);"
    312 	   "case 2: return K(SPOCK.check(arguments[ 1 ], 'number', '+'));"
    313 	   "default:"
    314 	   " var p = SPOCK.check(arguments[ 1 ], 'number', '+');"
    315 	   " for(var i = 2; i < len; ++i) {"
    316 	   "  p += SPOCK.check(arguments[ i ], 'number', '+');"
    317 	   " }"
    318 	   " return K(p);}"))
    319 
    320 	(define %-
    321 	  (%native-lambda
    322 	   "var len = arguments.length;"
    323 	   "switch(len) {"
    324 	   "case 1: SPOCK.error('(-) bad argument count', len);"
    325 	   "case 2: return K(-SPOCK.check(arguments[ 1 ], 'number', '-'));"
    326 	   "default:"
    327 	   " var p = SPOCK.check(arguments[ 1 ], 'number', '-');"
    328 	   " for(var i = 2; i < len; ++i) {"
    329 	   "  p -= SPOCK.check(arguments[ i ], 'number', '-');"
    330 	   " }"
    331 	   " return K(p);}"))
    332 
    333 	(define %*
    334 	  (%native-lambda
    335 	   "var len = arguments.length;"
    336 	   "switch(len) {"
    337 	   "case 1: return K(1);"
    338 	   "case 2: return K(SPOCK.check(arguments[ 1 ], 'number', '*'));"
    339 	   "default:"
    340 	   " var p = SPOCK.check(arguments[ 1 ], 'number', '*');"
    341 	   " for(var i = 2; i < len; ++i) {"
    342 	   "  p *= SPOCK.check(arguments[ i ], 'number', '*');"
    343 	   " }"
    344 	   " return K(p);}"))
    345 
    346 	(define %/
    347 	  (%native-lambda
    348 	   "var len = arguments.length;"
    349 	   "switch(len) {"
    350 	   "case 1: SPOCK.error('(/) bad argument count', len);"
    351 	   "case 2: return K(1/SPOCK.check(arguments[ 1 ], 'number', '/'));"
    352 	   "default:"
    353 	   " var p = SPOCK.check(arguments[ 1 ], 'number', '/');"
    354 	   " for(var i = 2; i < len; ++i) {"
    355 	   "  p /= SPOCK.check(arguments[ i ], 'number', '/');"
    356 	   " }"
    357 	   " return K(p);}"))
    358 
    359 	)
    360 
    361       (default
    362 
    363        (define %+
    364 	 (%native-lambda
    365 	  "var len = arguments.length;"
    366 	  "switch(len) {"
    367 	  "case 1: return K(0);"
    368 	  "case 2: return K(arguments[ 1 ]);"
    369 	  "default:"
    370 	  " var p = arguments[ 1 ];"
    371 	  " for(var i = 2; i < len; ++i) {"
    372 	  "  p += arguments[ i ];"
    373 	  " }"
    374 	  " return K(p);}"))
    375 
    376        (define %-
    377 	 (%native-lambda
    378 	  "var len = arguments.length;"
    379 	  "switch(len) {"
    380 	  "case 2: return K(-arguments[ 1 ]);"
    381 	  "default:"
    382 	  " var p = arguments[ 1 ];"
    383 	  " for(var i = 2; i < len; ++i) {"
    384 	  "  p -= arguments[ i ];"
    385 	  " }"
    386 	  " return K(p);}"))
    387 
    388        (define %*
    389 	 (%native-lambda
    390 	  "var len = arguments.length;"
    391 	  "switch(len) {"
    392 	  "case 1: return K(1);"
    393 	  "case 2: return K(arguments[ 1 ]);"
    394 	  "default:"
    395 	  " var p = arguments[ 1 ];"
    396 	  " for(var i = 2; i < len; ++i) {"
    397 	  "  p *= arguments[ i ];"
    398 	  " }"
    399 	  " return K(p);}"))
    400 
    401        (define %/
    402 	 (%native-lambda
    403 	  "var len = arguments.length;"
    404 	  "switch(len) {"
    405 	  "case 2: return K(1/arguments[ 1 ]);"
    406 	  "default:"
    407 	  " var p = arguments[ 1 ];"
    408 	  " for(var i = 2; i < len; ++i) {"
    409 	  "  p /= arguments[ i ];"
    410 	  " }"
    411 	  " return K(p);}"))
    412 
    413 	))
    414 
    415 
    416     (define-library-section basic-arithmetic
    417 
    418       (default
    419 
    420 	(define-syntax +
    421 	  (case-lambda
    422 	   (() 0)
    423 	   ((n) (%check "number" n))
    424 	   ((n1 n2)
    425 	    (%inline (1 " + " 2) (%check "number" n1) (%check "number" n2)))
    426 	   %+))
    427 
    428 	(define-syntax *
    429 	  (case-lambda
    430 	   (() 1)
    431 	   ((n) (%check "number" n))
    432 	   ((n1 n2)
    433 	    (%inline (1 " * " 2) (%check "number" n1) (%check "number" n2)))
    434 	   %*))
    435 
    436 	(define-syntax -
    437 	  (case-lambda
    438 	   ((n) (%inline ("-" 1) (%check number n)))
    439 	   ((n1 n2) 
    440 	    (%inline (1 " - " 2) (%check number n1) (%check number n2)))
    441 	   %-))
    442 
    443 	(define-syntax /
    444 	  (case-lambda
    445 	   ((n) (%inline ("1 / " 1) (%check number n)))
    446 	   ((n1 n2) 
    447 	    (%inline (1 " / " 2) (%check number n1) (%check number n2)))
    448 	   %/))
    449 
    450 	))
    451 
    452 
    453     (define-library-section native-numeric-comparison
    454 
    455       ;;XXX need non-debug versions
    456       (default
    457 
    458 	(define %=
    459 	  (%native-lambda
    460 	   "var argc = arguments.length;"
    461 	   "var last = SPOCK.check(arguments[ 1 ], 'number', '=');"
    462 	   "for(var i = 2; i < argc; ++i) {"
    463 	   " var x = SPOCK.check(arguments[ i ], 'number', '=');"
    464 	   " if(last !== x) return K(false);"
    465 	   " else last = x;}"
    466 	   "return K(true);"))
    467 
    468 	(define %>
    469 	  (%native-lambda
    470 	   "var argc = arguments.length;"
    471 	   "var last = SPOCK.check(arguments[ 1 ], 'number', '>');"
    472 	   "for(var i = 2; i < argc; ++i) {"
    473 	   " var x = SPOCK.check(arguments[ i ], 'number', '>');"
    474 	   " if(last <= x) return K(false);"
    475 	   " else last = x;}"
    476 	   "return K(true);"))
    477 
    478 	(define %<
    479 	  (%native-lambda
    480 	   "var argc = arguments.length;"
    481 	   "var last = SPOCK.check(arguments[ 1 ], 'number', '<');"
    482 	   "for(var i = 2; i < argc; ++i) {"
    483 	   " var x = SPOCK.check(arguments[ i ], 'number', '<');"
    484 	   " if(last >= x) return K(false);"
    485 	   " else last = x;}"
    486 	   "return K(true);"))
    487 
    488 	(define %>=
    489 	  (%native-lambda
    490 	   "var argc = arguments.length;"
    491 	   "var last = SPOCK.check(arguments[ 1 ], 'number', '>=');"
    492 	   "for(var i = 2; i < argc; ++i) {"
    493 	   " var x = SPOCK.check(arguments[ i ], 'number', '>=');"
    494 	   " if(last < x) return K(false);"
    495 	   " else last = x;}"
    496 	   "return K(true);"))
    497 
    498 	(define %<=
    499 	  (%native-lambda
    500 	   "var argc = arguments.length;"
    501 	   "var last = SPOCK.check(arguments[ 1 ], 'number', '<=');"
    502 	   "for(var i = 2; i < argc; ++i) {"
    503 	   " var x = SPOCK.check(arguments[ i ], 'number', '<=');"
    504 	   " if(last > x) return K(false);"
    505 	   " else last = x;}"
    506 	   "return K(true);"))
    507 
    508 	))
    509 
    510 
    511     (define-library-section numeric-comparison
    512 
    513       (default
    514 
    515 	(define-syntax =
    516 	  (case-lambda
    517 	   ((n1 n2)
    518 	    (%inline (1 " === " 2) (%check "number" n1) (%check "number" n2)))
    519 	   %=))
    520 
    521 	(define-syntax >
    522 	  (case-lambda
    523 	   ((n1 n2)
    524 	    (%inline (1 " > " 2) (%check "number" n1) (%check "number" n2)))
    525 	   %>))
    526 
    527 	(define-syntax <
    528 	  (case-lambda
    529 	   ((n1 n2)
    530 	    (%inline (1 " < " 2) (%check "number" n1) (%check "number" n2)))
    531 	   %<))
    532 
    533 	(define-syntax >=
    534 	  (case-lambda
    535 	   ((n1 n2)
    536 	    (%inline (1 " >= " 2) (%check "number" n1) (%check "number" n2)))
    537 	   %>=))
    538 
    539 	(define-syntax <=
    540 	  (case-lambda
    541 	   ((n1 n2)
    542 	    (%inline (1 " <= " 2) (%check "number" n1) (%check "number" n2)))
    543 	   %<=))
    544 
    545 	))
    546 
    547 
    548     (define-library-section native-numeric-operations
    549 
    550       (debug
    551 
    552 	(define %max
    553 	  (%native-lambda
    554 	   "var argc = arguments.length;"
    555 	   "var n = SPOCK.check(arguments[ 1 ], 'number', 'max');"
    556 	   "for(var i = 2; i < argc; ++i) {"
    557 	   " var x = SPOCK.check(arguments[ i ], 'number', 'max');"
    558 	   " if(n < x) n = x;}"
    559 	   "return K(n);"))
    560 
    561 	(define %min
    562 	  (%native-lambda
    563 	   "var argc = arguments.length;"
    564 	   "var n = SPOCK.check(arguments[ 1 ], 'number', 'max');"
    565 	   "for(var i = 2; i < argc; ++i) {"
    566 	   " var x = SPOCK.check(arguments[ i ], 'number', 'max');"
    567 	   " if(n > x) n = x;}"
    568 	   "return K(n);"))
    569 
    570 	)
    571 
    572       (default
    573 
    574        (define %max
    575 	 (%native-lambda
    576 	  "return K(Math.max.apply(SPOCK.global, arguments));"))
    577 
    578        (define %max
    579 	 (%native-lambda
    580 	  "return K(Math.min.apply(SPOCK.global, arguments));"))
    581 
    582 	))
    583 
    584 
    585     (define-library-section numeric-operations
    586 
    587       (default
    588 
    589 	(define-inline (round n) (%inline "Math.round" (%check "number" n)))
    590 	(define-inline (floor n) (%inline "Math.floor" (%check "number" n)))
    591 	(define-inline (ceiling n) (%inline "Math.ceil" (%check "number" n)))
    592 
    593 	(define-inline (truncate n)
    594 	  (%check "number" n)
    595 	  (if (%inline (1 " < 0") n)
    596 	      (%inline "Math.ceil" n)
    597 	      (%inline "Math.floor" n)))
    598 
    599 	(define-inline (log n) (%inline "Math.log" (%check "number" n)))
    600 	(define-inline (abs n) (%inline "Math.abs" (%check "number" n)))
    601 	(define-inline (sin n) (%inline "Math.sin" (%check "number" n)))
    602 	(define-inline (cos n) (%inline "Math.cos" (%check "number" n)))
    603 	(define-inline (tan n) (%inline "Math.tan" (%check "number" n)))
    604 	(define-inline (asin n) (%inline "Math.asin" (%check "number" n)))
    605 	(define-inline (acos n) (%inline "Math.acos" (%check "number" n)))
    606 	(define-inline (sqrt n) (%inline "Math.sqrt" (%check "number" n)))
    607 
    608 	(define-inline (expt n m)
    609 	  (%inline "Math.pow" (%check "number" n) (%check "number" m)))
    610 
    611 	(define-inline (atan y x)
    612 	  (if (void? x)
    613 	      (%inline "Math.atan" (%check "number" y))
    614 	      (%inline "Math.atan2" (%check "number" y) (%check "number" x))))
    615 
    616 	(define-syntax max
    617 	  (case-lambda
    618 	   ((n) (%check "number" n))
    619 	   ((n1 n2)
    620 	    (%inline "Math.max" (%check "number" n1) (%check "number" n2)))
    621 	   %max))
    622 
    623 	(define-syntax min
    624 	  (case-lambda
    625 	   ((n) (%check "number" n))
    626 	   ((n1 n2)
    627 	    (%inline "Math.min" (%check "number" n1) (%check "number" n2)))
    628 	   %min))
    629 
    630 	(define-inline (quotient x y)
    631 	  (truncate (/ x y)))		;XXX correct?
    632 
    633 	(define-inline (remainder x y)
    634 	  (- x (* (quotient x y) y)))
    635 
    636 	(define (modulo a b) ; copied from chibi scheme without asking Alex
    637 	  (let ((res (remainder a b)))
    638 	    (if (< b 0)
    639 		(if (<= res 0) res (+ res b))
    640 		(if (>= res 0) res (+ res b)))))
    641 
    642 	(define-inline (exact->inexact n) (%check "number" n))
    643 	(define-inline (inexact->exact n) (truncate n))
    644 
    645 	;; not implemented: numerator denominator rationalize
    646 	;; not implemented: make-rectangular make-polar imag-part real-part magnitude angle
    647 
    648 	))
    649 
    650 
    651     (define-library-section gcd-and-lcm
    652 
    653       (default
    654 
    655 	;;XXX slow
    656 
    657 	(define %gcd
    658 	  (let ((remainder remainder))
    659 	    (lambda (x y)
    660 	      (let loop ((x x) (y y))
    661 		(if (zero? y)
    662 		    (abs x)
    663 		    (loop y (remainder x y)) ) ) ) ) )
    664 
    665 	(define (gcd . ns)
    666 	  (if (null? ns)
    667 	      0
    668 	      (let loop ((ns ns) (f #t))
    669 		(let ((head (%car ns))
    670 		      (next (%cdr ns)))
    671 		  (when f (%check "number" head))
    672 		  (if (null? next)
    673 		      (abs head)
    674 		      (let ((n2 (%car next)))
    675 			(%check "number" n2)
    676 			(loop 
    677 			 (cons (%gcd head n2) (%cdr next))
    678 			 #f) ) ) ) ) ) )
    679 
    680 	(define (%lcm x y)
    681 	  (quotient (* x y) (%gcd x y)) )
    682 
    683 	(define (lcm . ns)
    684 	  (if (null? ns)
    685 	      1
    686 	      (let loop ((ns ns) (f #t))
    687 		(let ((head (%car ns))
    688 		      (next (%cdr ns)))
    689 		  (when f (%check "number" head))
    690 		  (if (null? next)
    691 		      (abs head)
    692 		      (let ((n2 (%car next)))
    693 			(%check "number" n2)
    694 			(loop
    695 			 (cons (%lcm head n2) (%cdr next))
    696 			 #f) ) ) ) ) ) )
    697 
    698 	))
    699 
    700 
    701     (define-library-section characters
    702 
    703       (default
    704 
    705 	(define-inline (char->integer c)
    706 	  (%inline ".charCodeAt" (%property-ref "character" (%check ("SPOCK.Char") c)) 0))
    707 
    708 	(define-inline (integer->char c)
    709 	  (%inline "new SPOCK.Char" (%inline "String.fromCharCode" (%check "number" c))))
    710 
    711 	(define-inline (char=? x y)
    712 	  (eq? (%property-ref "character" (%check ("SPOCK.Char") x))
    713 	       (%property-ref "character" (%check ("SPOCK.Char") y))))
    714 
    715 	(define-inline (char>? x y)
    716 	  (%inline
    717 	   (1 " > " 2) 
    718 	   (%property-ref "character" (%check ("SPOCK.Char") x))
    719 	   (%property-ref "character" (%check ("SPOCK.Char") y))))
    720 
    721 	(define-inline (char<? x y)
    722 	  (%inline
    723 	   (1 " < " 2) 
    724 	   (%property-ref "character" (%check ("SPOCK.Char") x))
    725 	   (%property-ref "character" (%check ("SPOCK.Char") y))))
    726 
    727 	(define-inline (char>=? x y)
    728 	  (%inline
    729 	   (1 " >= " 2) 
    730 	   (%property-ref "character" (%check ("SPOCK.Char") x))
    731 	   (%property-ref "character" (%check ("SPOCK.Char") y))))
    732 
    733 	(define-inline (char<=? x y)
    734 	  (%inline
    735 	   (1 " <= " 2) 
    736 	   (%property-ref "character" (%check ("SPOCK.Char") x))
    737 	   (%property-ref "character" (%check ("SPOCK.Char") y))))
    738 
    739 	(define-inline (char-ci=? x y)
    740 	  (eq? (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") x)))
    741 	       (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") y)))))
    742 
    743 	(define-inline (char-ci>? x y)
    744 	  (%inline
    745 	   (1 " > " 2)
    746 	   (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") x)))
    747 	   (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") y)))))
    748 
    749 	(define-inline (char-ci<? x y)
    750 	  (%inline
    751 	   (1 " < " 2)
    752 	   (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") x)))
    753 	   (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") y)))))
    754 
    755 	(define-inline (char-ci>=? x y)
    756 	  (%inline
    757 	   (1 " >= " 2)
    758 	   (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") x)))
    759 	   (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") y)))))
    760 
    761 	(define-inline (char-ci<=? x y)
    762 	  (%inline
    763 	   (1 " <= " 2)
    764 	   (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") x)))
    765 	   (%inline ".toLowerCase" (%property-ref "character" (%check ("SPOCK.Char") y)))))
    766 
    767 	(define-inline (char-upcase c)
    768 	  (%inline 
    769 	   "new SPOCK.Char"
    770 	   (%inline 
    771 	    ".toUpperCase"
    772 	    (%property-ref "character" (%check ("SPOCK.Char") c)))))
    773 
    774 	(define-inline (char-downcase c)
    775 	  (%inline 
    776 	   "new SPOCK.Char"
    777 	   (%inline 
    778 	    ".toLowerCase"
    779 	    (%property-ref "character" (%check ("SPOCK.Char") c)))))
    780 
    781 	(define-inline (char-alphabetic? c)	;XXX not unicode aware
    782 	  (not 
    783 	   (null? 
    784 	    (%inline 
    785 	     (1 ".character.match(/^[A-Za-z]$/)") 
    786 	     (%check ("SPOCK.Char") c)))))
    787 
    788 	(define-inline (char-numeric? c)	;XXX not unicode aware?
    789 	  (not (null? (%inline (1 ".character.match(/^\\d$/)") (%check ("SPOCK.Char") c)))))
    790 
    791 	(define-inline (char-whitespace? c)
    792 	  (not (null? (%inline (1 ".character.match(/^\\s$/)") (%check ("SPOCK.Char") c)))))
    793 
    794 	(define-inline (char-upper-case? c)	;XXX not unicode aware
    795 	  (not 
    796 	   (null? 
    797 	    (%inline 
    798 	     (1 ".character.match(/^[A-Z]$/)")
    799 	     (%check ("SPOCK.Char") c)))))
    800 
    801 	(define-inline (char-lower-case? c)	;XXX not unicode aware
    802 	  (not
    803 	   (null?
    804 	    (%inline
    805 	     (1 ".character.match(/^[a-z]$/)")
    806 	     (%check ("SPOCK.Char") c)))))
    807 
    808 	))
    809 
    810 
    811     (define-library-section symbols
    812 
    813       (default
    814 	
    815 	(define-inline (symbol->string sym)
    816 	  (%property-ref "name" (%check ("SPOCK.Symbol") sym)))
    817 
    818 	(define string->symbol
    819 	  (%native-lambda
    820 	   "var str = SPOCK.jstring(arguments[ 1 ]);"
    821 	   "return K(SPOCK.intern(str));"))
    822 
    823 	))
    824 
    825 
    826     (define-library-section property-lists
    827 
    828       (default
    829 	
    830 	(define (get sym prop)
    831 	  (let ((val
    832 		 (%inline
    833 		  (1 ".plist[" 2 "]") 
    834 		  (%check ("SPOCK.Symbol") sym)
    835 		  (%property-ref "name" (%check ("SPOCK.Symbol") prop)))))
    836 	    (and (not (void? val)) val))) ;XXX doesn't allow storing void
    837 
    838 	(define (put! sym prop val)
    839 	  (%inline
    840 	   (1 ".plist[" 2 "] = " 3)
    841 	   (%check ("SPOCK.Symbol") sym)
    842 	   (%property-ref "name" (%check ("SPOCK.Symbol") prop))
    843 	   val))
    844 
    845 	))
    846 
    847 
    848     (define-library-section strings
    849 
    850       (default
    851 
    852 	(define-inline (string-length str)
    853 	  (%property-ref "length" (%string->jstring str)))
    854 
    855 	(define string-append
    856 	  (%native-lambda
    857 	   "var args = Array.prototype.slice.call(arguments, 1);"
    858 	   "var strs = SPOCK.map(function(x) { return SPOCK.jstring(x); }, args);"
    859 	   "return K(new SPOCK.String(strs));"))
    860 
    861 	;;XXX does no bounds/exactness check
    862 	(define-inline (substring str i j)
    863 	  (let ((str (%string->jstring str)))
    864 	    (%inline 
    865 	     ".substring" str
    866 	     (%check "number" i)
    867 	     (if (void? j)
    868 		 (%property-ref "length" str)
    869 		 (%check "number" j)))))
    870 
    871 	;;XXX we need non-debug versions of all of these
    872 
    873 	(define string
    874 	  (%native-lambda
    875 	   "var str = [];"
    876 	   "var len = arguments.length - 1;"
    877 	   "for(var i = 1; i <= len; ++i) {"
    878 	   " var x = arguments[ i ];"
    879 	   " if(x instanceof SPOCK.Char) str.push(x.character);"
    880 	   " else SPOCK.error('bad argument type - not a character', x);}"
    881 	   "return K(new SPOCK.String(str.join('')));"))
    882 
    883 	(define string->list
    884 	  (%native-lambda
    885 	   "var str = SPOCK.jstring(arguments[ 1 ]);"
    886 	   "var lst = null;"
    887 	   "var len = str.length;"
    888 	   "for(var i = len - 1; i >= 0; --i)"
    889 	   " lst = new SPOCK.Pair(new SPOCK.Char(str.charAt(i)), lst);"
    890 	   "return K(lst);"))
    891 
    892 	(define list->string
    893 	  (%native-lambda
    894 	   "var lst = arguments[ 1 ];"
    895 	   "var str = [];"
    896 	   "while(lst instanceof SPOCK.Pair) {"
    897 	   " str.push(SPOCK.check(lst.car, SPOCK.Char).character);"
    898 	   " lst = lst.cdr;}"
    899 	   "return K(new SPOCK.String(str.join('')));"))
    900 
    901 	(define make-string
    902 	  (%native-lambda
    903 	   "var n = SPOCK.check(arguments[ 1 ], 'number', 'make-string');"
    904 	   "var c = arguments[ 2 ];"
    905 	   "var a = new Array(n);"
    906 	   "if(c !== undefined)"
    907 	   " c = SPOCK.check(c, SPOCK.Char, 'make-string').character;"
    908 	   "else c = ' ';"
    909 	   "for(var i = 0; i < n; ++i) a[ i ] = c;"
    910 	   "return K(new SPOCK.String(a.join('')));"))
    911 
    912 	;;XXX no bounds/exactness checks
    913 	(define string-ref     ;XXX consider inlining the fast case
    914 	  (%native-lambda
    915 	   "var str = arguments[ 1 ];"
    916 	   "var i = SPOCK.check(arguments[ 2 ], 'number', 'string-ref');"
    917 	   "if(typeof str === 'string')"
    918 	   " return K(new SPOCK.Char(str.charAt(i)));"
    919 	   "else if(str instanceof SPOCK.String) {"
    920 	   " var parts = str.parts;"
    921 	   " for(var p in parts) {"
    922 	   "  var l = parts[ p ].length;"
    923 	   "  if(i <= l) return K(new SPOCK.Char(parts[ p ].charAt(i)));"
    924 	   "  else i -= l;}"
    925 	   " SPOCK.error('`string-ref\\\' out of range', str, i);}"))
    926 
    927 	(define string-set!
    928 	  (%native-lambda
    929 	   "var str = arguments[ 1 ];"
    930 	   "var i = SPOCK.check(arguments[ 2 ], 'number', 'string-set!');"
    931 	   "var c = SPOCK.check(arguments[ 3 ], SPOCK.Char, 'string-set!');"
    932 	   "if(typeof str === 'string')"
    933 	   " SPOCK.error('argument to `string-set!\\\' is not a mutable string', str);"
    934 	   "else if(str instanceof SPOCK.String) {"
    935 	   " var parts = str.parts;"
    936 	   " for(var p in parts) {"
    937 	   "  var part = parts[ p ];"
    938 	   "  var l = part.length;"
    939 	   "  if(i <= l) {"
    940 	   "   parts[ p ] = part.substring(0, i) + c.character + part.substring(i + 1);"
    941 	   "   return K(undefined);"
    942 	   "  } else i -= l;}"
    943 	   " SPOCK.error('`string-set!\\\' out of range', str, i);}"))
    944 
    945 	(define-inline (string=? s1 s2) 
    946 	  (eq? (%string->jstring s1) (%string->jstring s2))) ;XXX may cons a lot
    947 
    948 	(define-inline (string>? s1 s2)
    949 	  (%inline (1 " > " 2) (%string->jstring s1) (%string->jstring s2)))
    950 
    951 	(define-inline (string<? s1 s2)
    952 	  (%inline (1 " < " 2) (%string->jstring s1) (%string->jstring s2)))
    953 
    954 	(define-inline (string>=? s1 s2)
    955 	  (%inline (1 " >= " 2) (%string->jstring s1) (%string->jstring s2)))
    956 
    957 	(define-inline (string<=? s1 s2)
    958 	  (%inline (1 " <= " 2) (%string->jstring s1) (%string->jstring s2)))
    959 
    960 	(define-inline (string-ci=? s1 s2) ;XXX ugly
    961 	  (eq?
    962 	   (%inline ".toLowerCase" (%string->jstring s1))
    963 	   (%inline ".toLowerCase" (%string->jstring s2))))
    964 
    965 	(define-inline (string-ci>? s1 s2)
    966 	  (%inline 
    967 	   (1 " > " 2)
    968 	   (%inline ".toLowerCase" (%string->jstring s1))
    969 	   (%inline ".toLowerCase" (%string->jstring s2))))
    970 
    971 	(define-inline (string-ci<? s1 s2)
    972 	  (%inline 
    973 	   (1 " < " 2)
    974 	   (%inline ".toLowerCase" (%string->jstring s1))
    975 	   (%inline ".toLowerCase" (%string->jstring s2))))
    976 
    977 	(define-inline (string-ci>=? s1 s2)
    978 	  (%inline 
    979 	   (1 " >= " 2)
    980 	   (%inline ".toLowerCase" (%string->jstring s1))
    981 	   (%inline ".toLowerCase" (%string->jstring s2))))
    982 
    983 	(define-inline (string-ci<=? s1 s2)
    984 	  (%inline 
    985 	   (1 " <= " 2)
    986 	   (%inline ".toLowerCase" (%string->jstring s1))
    987 	   (%inline ".toLowerCase" (%string->jstring s2))))
    988 
    989 	(define (string-copy str from to)
    990 	  (let* ((str (%string->jstring str))
    991 		 (from (if (void? from) 0 (%check "number" from)))
    992 		 (to (if (void? to) (%property-ref "length" str) (%check "number" to))))
    993 	    (%jstring->string (%inline ".slice" str from to))))
    994 
    995 	(define (string-fill! str char from to)
    996 	  (unless (%check (%inline (1 "instanceof SPOCK.String") str))
    997 	    (%error "bad argument type - not a mutable string" str))
    998 	  (let* ((text (%inline ".normalize" str))
    999 		 (char (%check ("SPOCK.Char") char))
   1000 		 (from (if (void? from) 0 (%check "number" from)))
   1001 		 (to (if (void? to) (%property-ref "length" text) (%check "number" to))))
   1002 	    ((%native-lambda
   1003 	      "var str = arguments[ 1 ];"
   1004 	      "var from = arguments[ 2 ];"
   1005 	      "var to = arguments[ 3 ];"
   1006 	      "var c = arguments[ 4 ];"
   1007 	      "var snew = new Array(to - from);"
   1008 	      "for(var i in snew) snew[ i ] = c;"
   1009 	      "str.parts = [str.parts[ 0 ].substring(0, from), snew.join(''),"
   1010 	      " str.parts[ 0 ].substring(to)];"
   1011 	      "return K(str);")
   1012 	     str from to char)))
   1013 
   1014 	))
   1015 
   1016 
   1017     (define-library-section vectors
   1018 
   1019       ;;XXX add non-debug variants
   1020 
   1021       (default
   1022 
   1023 	(define-inline (vector-length v)
   1024 	  (%property-ref "length" (%check ("Array") v)))
   1025 
   1026 	;;XXX make these two safe (bounds-checking and exactness)
   1027 	(define-inline (vector-ref v i)
   1028 	  (%inline (1 "[" 2 "]") (%check ("Array") v) (%check "number" i)))
   1029 
   1030 	(define-inline (vector-set! v i x)
   1031 	  (%inline (1 "[" 2 "] = " 3) (%check ("Array") v) (%check "number" i) x))
   1032 
   1033 	(define vector
   1034 	  (%native-lambda
   1035 	   "return K(Array.prototype.slice.call(arguments, 1));"))
   1036 
   1037 	(define make-vector
   1038 	  (%native-lambda
   1039 	   "var n = SPOCK.check(arguments[ 1 ], 'number', 'make-vector');"
   1040 	   "var x = arguments[ 2 ];"
   1041 	   "var a = new Array(n);"
   1042 	   "if(x !== undefined) {"
   1043 	   " for(var i = 0; i < n; ++i) a[ i ] = x;}"
   1044 	   "return K(a);"))
   1045 
   1046 	(define vector->list
   1047 	  (%native-lambda
   1048 	   "var vec = SPOCK.check(arguments[ 1 ], Array, 'vector->list');"
   1049 	   "var lst = null;"
   1050 	   "var len = vec.length;"
   1051 	   "for(var i = len - 1; i >= 0; --i)"
   1052 	   " lst = new SPOCK.Pair(vec[ i ], lst);"
   1053 	   "return K(lst);"))
   1054 
   1055 	(define list->vector
   1056 	  (%native-lambda
   1057 	   "var lst = arguments[ 1 ];"
   1058 	   "var vec = [];"
   1059 	   "while(lst instanceof SPOCK.Pair) {"
   1060 	   " vec.push(lst.car);"
   1061 	   " lst = lst.cdr;}"
   1062 	   "return K(vec);"))
   1063 
   1064 	(define vector-fill!
   1065 	  (%native-lambda
   1066 	   "var vec = SPOCK.check(arguments[ 1 ], Array, 'vector-fill!');"
   1067 	   "var x = arguments[ 2 ];"
   1068 	   "var from = arguments[ 3 ];"
   1069 	   "var to = arguments[ 4 ];"
   1070 	   "if(from === undefined) from = 0;"
   1071 	   "if(to === undefined) to = vec.length;"
   1072 	   "for(var i = from; i < to; ++i)"
   1073 	   " vec[ i ] = x;"
   1074 	   "return K(undefined);"))
   1075 
   1076 	))
   1077 
   1078 
   1079     (define-library-section number-string-conversion
   1080 
   1081       (default
   1082 
   1083 	(define-inline (number->string num base)
   1084 	  (%inline 
   1085 	   "new SPOCK.String"
   1086 	   (%inline
   1087 	    ".toString" 
   1088 	    (%check "number" num) 
   1089 	    (if (void? base) 
   1090 		10
   1091 		(%check "number" base)))))
   1092 
   1093 	;;XXX add non-debug version?
   1094 	(define string->number
   1095 	  (%native-lambda
   1096 	   "var str = SPOCK.jstring(arguments[ 1 ]);"
   1097 	   "var base = arguments[ 2 ];"
   1098 	   "if(!base) base = 10;"
   1099 	   "else base = SPOCK.check(base, 'number', 'string->number');"
   1100 	   "var m = true, neg = 1;"
   1101 	   "while(m) {"
   1102 	   " m = str.match(/^#[eboxid]/);"
   1103 	   " if(m) {"
   1104 	   "  switch(str[ 1 ]) {"
   1105 	   "  case 'e':"
   1106 	   "  case 'i': break;"
   1107 	   "  case 'd': base = 10; break;"
   1108 	   "  case 'o': base = 8; break;"
   1109 	   "  case 'x': base = 16; break;"
   1110 	   "  case 'b': base = 2; break;"
   1111 	   "  default: return K(false);}"
   1112 	   "  str = str.substring(2);}}"
   1113 	   "switch(str[ 0 ]) {"
   1114 	   "case '-': neg = -1; str = str.substring(1); break;"
   1115 	   "case '+': str = str.substring(1);}"
   1116 	   "var num, den = false;"
   1117 	   "if((m = str.match(/^([^\\/]+)\\/(.+)$/))) {"
   1118 	   "  str = m[ 1 ];"
   1119 	   "  den = m[ 2 ];}"
   1120 	   "function num3(s) {"
   1121 	   " var tr = null;"
   1122 	   " switch(base) {"
   1123 	   " case 2: tr = /^[0-1]+$/; break;"
   1124 	   " case 8: tr = /^[0-7]+$/; break;"
   1125 	   " case 10: tr = /^[#0-9]*\\.?[#0-9]+([esdfl][-+]?[0-9]+)?$/; break;"
   1126 	   " case 16: tr = /^[0-9a-fA-F]+$/;}"
   1127 	   " if(tr && !s.match(tr)) return false;"
   1128 	   " var s2 = s.replace(/#/g, '0');"
   1129 	   " if(base === 10) s2 = parseFloat(s2.replace(/[esdfl]/g, 'e'));"
   1130 	   " else if(s2 !== s) return false;"
   1131 	   " else s2 = parseInt(s2, base);"
   1132 	   " return isNaN(s2) ? false : s2;}"
   1133 	   "if((num = num3(str)) === false) return K(false);"
   1134 	   "if(den && !(den = num3(den))) return K(false);"
   1135 	   "return K(neg * num / (den || 1));"))
   1136 
   1137 	))
   1138 
   1139 
   1140     (define-library-section unsafe-internal-i/o
   1141 
   1142       (default
   1143 
   1144 	;; (%show STRING PORT)
   1145 	(define %show
   1146 	  (%native-lambda
   1147 	   "arguments[ 2 ].write(arguments[ 1 ]);"
   1148 	   "return K(undefined);"))
   1149 
   1150 	;; (%fetch N PORT)
   1151 	(define %fetch
   1152 	  (%native-lambda
   1153 	   "return K(arguments[ 2 ].read(arguments[ 1 ]));"))
   1154 
   1155 	))
   1156 
   1157 
   1158     (define-library-section port-checks
   1159 
   1160       (debug
   1161 
   1162 	;; (%check-port X DIR LOC)
   1163 	(define %check-port
   1164 	  (%native-lambda
   1165 	   "var port = arguments[ 1 ];"
   1166 	   "var dir = arguments[ 2 ];"
   1167 	   "if(port instanceof SPOCK.Port) {"
   1168 	   " if(port.closed)"
   1169 	   "  SPOCK.error('port is already closed', port);"
   1170 	   " else if(port.direction !== dir)"
   1171 	   "  SPOCK.error('bad argument type - not an ' + dir + ' port', port, arguments[ 3 ]);"
   1172 	   "}"
   1173 	   "else SPOCK.error('bad argument type - not a port', port, arguments[ 3 ]);"
   1174 	   "return K(port);"))
   1175 	)
   1176       
   1177       (default
   1178 
   1179        (define-inline (%check-port x dir loc) x)
   1180 
   1181 	))
   1182 
   1183 
   1184     (define-library-section basic-i/o
   1185 
   1186       (default
   1187 
   1188 	(define-inline (current-input-port) (%host-ref "SPOCK.stdin"))
   1189 	(define-inline (current-output-port) (%host-ref "SPOCK.stdout"))
   1190 
   1191 	(define (newline port)
   1192 	  (%show 
   1193 	   "\n" 
   1194 	   (if (void? port) 
   1195 	       (%host-ref "SPOCK.stdout")
   1196 	       (%check-port port "output" "newline"))))
   1197 
   1198 	(define (read-char port)
   1199 	  (let ((s (%fetch
   1200 		    1
   1201 		    (if (void? port)
   1202 			(%host-ref "SPOCK.stdin")
   1203 			(%check-port port "input" "read-char")))))
   1204 	    (if (eof-object? s)
   1205 		s
   1206 		(%inline "new SPOCK.Char" s))))
   1207 
   1208 	(define (write-char chr port)
   1209 	  (%show
   1210 	   (%property-ref "character" (%check ("SPOCK.Char") chr))
   1211 	   (if (void? port)
   1212 	       (%host-ref "SPOCK.stdout")
   1213 	       (%check-port port "output" "write-char"))))
   1214 
   1215 	(define peek-char
   1216 	  (let ((read-char read-char))
   1217 	    (lambda (port)
   1218 	      (let ((c (read-char port)))
   1219 		(unless (eof-object? c)
   1220 		  (%inline (1 ".peeked = " 2) port (%property-ref "character" c)))
   1221 		c))))
   1222 
   1223 	(define (char-ready? port)
   1224 	  (%check-port port "input" "char-ready?")
   1225 	  (%inline ".ready" port))
   1226 
   1227 	))
   1228 
   1229 
   1230     (define-library-section data-output
   1231 
   1232       (default
   1233 
   1234 	;; (%print-hook X PORT READABLE?)         called for unknown object
   1235 	(define (%print-hook x port readable)
   1236 	  (%show "#<unknown object>" port))
   1237 
   1238 	(define (display x port)
   1239 	  (let ((port (if (void? port)
   1240 			  (%host-ref "SPOCK.stdout")
   1241 			  (%check-port port "output" "display"))))
   1242 	    (let show ((x x))
   1243 	      (cond ((null? x) (%show "()" port))
   1244 		    ((number? x)
   1245 		     ;;XXX this could be optimized
   1246 		     (%show (%string->jstring (number->string x)) port))
   1247 		    ((string? x)
   1248 		     (%show (%inline "SPOCK.jstring" x) port))
   1249 		    ((symbol? x)
   1250 		     (%show (%property-ref "name" x) port))
   1251 		    ((char? x)
   1252 		     (%show (%property-ref "character" x) port))
   1253 		    ((eof-object? x) (%show "#<eof>" port))
   1254 		    ((procedure? x) (%show "#<procedure>" port))
   1255 		    ((boolean? x) (%show (if x "#t" "#f") port))
   1256 		    ((pair? x)
   1257 		     (%show "(" port)
   1258 		     (let loop ((y x))
   1259 		       (cond ((null? y) (%show ")" port))
   1260 			     ((not (pair? y))
   1261 			      (%show " . " port)
   1262 			      (show y)
   1263 			      (%show ")" port))
   1264 			     (else
   1265 			      (unless (eq? x y) (%show " " port))
   1266 			      (show (%car y))
   1267 			      (loop (cdr y))))))
   1268 		    ((void? x) (%show "#<undefined>" port))
   1269 		    ((vector? x)
   1270 		     (let ((len (%property-ref "length" x)))
   1271 		       (%show "#(" port)
   1272 		       (do ((i 0 (%inline ("1+" 1) i)))
   1273 			   ((%inline (1 ">=" 2) i len)
   1274 			    (%show ")" port))
   1275 			 (unless (eq? i 0) (%show " " port))
   1276 			 (show (%inline (1 "[" 2 "]") x i)))))
   1277 		    ((%inline (1 "instanceof SPOCK.Port") x)
   1278 		     (%show (%inline "SPOCK.stringify" x) port))
   1279 		    ((%inline (1 "instanceof SPOCK.Promise") x)
   1280 		     (%show "#<promise>" port))
   1281 		    ((eq? "object" (%inline "typeof" x))
   1282 		     (%print-hook x port #f))
   1283 		    (else (%show "#<unknown object>" port))))))
   1284 
   1285 	(define write
   1286 	  (let ((display display))
   1287 	    (define escape 
   1288 	      (%native-lambda 
   1289 	       "var str = arguments[ 1 ];"
   1290 	       "var a = [];"
   1291 	       "var len = str.length;"
   1292 	       "for(var i = 0; i < len; ++i) {"
   1293 	       " var c = str.charAt(i);"
   1294 	       " switch(c) {"
   1295 	       " case '\\n': a.push('\\n'); break;"
   1296 	       " case '\\t': a.push('\\t'); break;"
   1297 	       " case '\\r': a.push('\\r'); break;"
   1298 	       " case '\\\"': a.push('\\\\\"'); break;"
   1299 	       " case '\\\\': a.push('\\\\'); break;"
   1300 	       " default: a.push(c);}}"
   1301 	       "return K(a.join(''));"))
   1302 	    (lambda (x port)
   1303 	      (let ((port (if (void? port)
   1304 			      (%host-ref "SPOCK.stdout")
   1305 			      (%check-port port "output" "write"))))
   1306 		(let show ((x x))
   1307 		  (cond ((string? x)
   1308 			 (%show "\"" port)
   1309 			 (%show (escape (%inline "SPOCK.jstring" x)) port)
   1310 			 (%show "\"" port))
   1311 			((char? x)
   1312 			 (%show "#\\" port)
   1313 			 (%show
   1314 			  (let ((c (%property-ref "character" x)))
   1315 			    (case c
   1316 			      (("\n") "newline") ; don't worry
   1317 			      (("\r") "return")
   1318 			      (("\t") "tab")
   1319 			      ((" ") "space")
   1320 			      (else c)))
   1321 			  port))
   1322 			((pair? x)
   1323 			 (%show "(" port)
   1324 			 (let loop ((y x))
   1325 			   (cond ((null? y) (%show ")" port))
   1326 				 ((not (pair? y))
   1327 				  (%show " . " port)
   1328 				  (show y)
   1329 				  (%show ")" port))
   1330 				 (else
   1331 				  (unless (eq? x y) (%show " " port))
   1332 				  (show (%car y))
   1333 				  (loop (cdr y))))))
   1334 			((vector? x)
   1335 			 (let ((len (%property-ref "length" x)))
   1336 			   (%show "#(" port)
   1337 			   (do ((i 0 (%inline ("1+" 1) i)))
   1338 			       ((%inline (1 ">=" 2) i len)
   1339 				(%show ")" port))
   1340 			     (unless (eq? i 0) (%show " " port))
   1341 			     (show (%inline (1 "[" 2 "]") x i)))))
   1342 			(else (display x port))))))))
   1343 
   1344 	))
   1345 
   1346 
   1347     (define-library-section extended-i/o
   1348 
   1349       (default
   1350 
   1351 	(define-inline (current-error-port) (%host-ref "SPOCK.stderr"))
   1352 
   1353 	))
   1354 
   1355 
   1356     (define-library-section higher-order-operations
   1357 
   1358       (default
   1359 
   1360 	(define apply
   1361 	  (%native-lambda
   1362 	   "var proc = arguments[ 1 ];"
   1363 	   "var argc = arguments.length;"
   1364 	   "var lst = arguments[ argc - 1 ];"
   1365 	   "var vec = [K].concat(Array.prototype.slice.call(arguments, 2, argc - 1));"
   1366 	   "if(lst instanceof Array) vec = vec.concat(lst);"
   1367 	   "else{"
   1368 	   " var len = SPOCK.length(lst);"
   1369 	   " var vec2 = new Array(len);"
   1370 	   " for(var i = 0; lst instanceof SPOCK.Pair; lst = lst.cdr)"
   1371 	   "  vec2[ i++ ] = lst.car;"
   1372 	   " vec = vec.concat(vec2);}"
   1373 	   "return proc.apply(SPOCK.global, vec);"))
   1374 
   1375 	(define (for-each proc lst1 . lsts)
   1376 	  (if (null? lsts)
   1377 	      (if (vector? lst1)
   1378 		  (let ((len (vector-length lst1)))
   1379 		    (do ((i 0 (+ i 1)))
   1380 			((>= i len))
   1381 		      (proc (vector-ref lst1 i))))
   1382 		  (let loop ((lst lst1))
   1383 		    (when (pair? lst)
   1384 		      (proc (%car lst))
   1385 		      (loop (%cdr lst)))))
   1386 	      (let loop ((lsts (cons lst1 lsts)))
   1387 		(let ((hds (let loop2 ((lsts lsts))
   1388 			     (if (null? lsts)
   1389 				 '()
   1390 				 (let ((x (%car lsts)))
   1391 				   (and (pair? x)
   1392 					(cons (%car x) (loop2 (%cdr lsts)))))))))
   1393 		  (when hds
   1394 		    (apply proc hds)
   1395 		    (loop
   1396 		     (let loop3 ((lsts lsts))
   1397 		       (if (null? lsts)
   1398 			   '()
   1399 			   (cons (%cdr (%car lsts)) (loop3 (%cdr lsts)))))))))))
   1400 
   1401 	(define (map proc lst1 . lsts)
   1402 	  (if (null? lsts)
   1403 	      (if (vector? lst1)
   1404 		  (let* ((len (vector-length lst1))
   1405 			 (rv (make-vector len)))
   1406 		    (do ((i 0 (+ i 1)))
   1407 			((>= i len) rv)
   1408 		      (vector-set! rv i (proc (vector-ref lst1 i)))))
   1409 		  (let loop ((lst lst1))
   1410 		    (if (pair? lst)
   1411 			(cons (proc (%car lst))
   1412 			      (loop (%cdr lst)))
   1413 			'())))
   1414 	      (let loop ((lsts (cons lst1 lsts)))
   1415 		(let ((hds (let loop2 ((lsts lsts))
   1416 			     (if (null? lsts)
   1417 				 '()
   1418 				 (let ((x (%car lsts)))
   1419 				   (and (pair? x)
   1420 					(cons (%car x) (loop2 (%cdr lsts)))))))))
   1421 		  (if hds
   1422 		      (cons
   1423 		       (apply proc hds)
   1424 		       (loop
   1425 			(let loop3 ((lsts lsts))
   1426 			  (if (null? lsts)
   1427 			      '()
   1428 			      (cons (%cdr (%car lsts)) (loop3 (%cdr lsts)))))))
   1429 		      '())))))
   1430 
   1431 	))
   1432 
   1433 
   1434     (define-library-section continuations
   1435 
   1436       (default
   1437 
   1438 	(define dynamic-wind
   1439 	  (let ((call-with-values call-with-values)
   1440 		(values values))
   1441 	    (lambda (before thunk after)
   1442 	      (before)
   1443 	      (%host-set! 
   1444 	       "SPOCK.dynwinds" 
   1445 	       (cons (cons before after) (%host-ref "SPOCK.dynwinds")))
   1446 	      (%call-with-saved-values
   1447 	       thunk
   1448 	       (lambda ()
   1449 		 (%host-set! "SPOCK.dynwinds" (%cdr (%host-ref "SPOCK.dynwinds")))
   1450 		 (after))))))
   1451 
   1452 	;; (%call-with-current-continuation PROC)
   1453 	;;
   1454 	;; - does not unwind
   1455 	(define %call-with-current-continuation
   1456 	  (%native-lambda
   1457 	   "var proc = arguments[ 1 ];"
   1458 	   "function cont() {"
   1459 	   " return K.apply(SPOCK.global, Array.prototype.slice.call(arguments, 1));}"
   1460 	   "return proc(K, cont);"))
   1461 
   1462 	(define call-with-current-continuation
   1463 	  (let ()
   1464 	    (define (unwind winds n)
   1465 	      (cond ((eq? (%host-ref "SPOCK.dynwinds") winds))
   1466 		    ((< n 0)
   1467 		     (unwind (%cdr winds) (%inline (1 " + 1") n))
   1468 		     ((%car (%car winds)))
   1469 		     (%host-set! "SPOCK.dynwinds" winds))
   1470 		    (else
   1471 		     (let ((after (%cdr (%car (%host-ref "SPOCK.dynwinds")))))
   1472 		       (%host-set! "SPOCK.dynwinds" (%cdr (%host-ref "SPOCK.dynwinds")))
   1473 		       (after)
   1474 		       (unwind winds (%inline (1 " - 1") n)) ) )))
   1475 	    (lambda (proc)
   1476 	      (let ((winds (%host-ref "SPOCK.dynwinds")))
   1477 		(%call-with-current-continuation
   1478 		 (lambda (cont)
   1479 		   (proc
   1480 		    (lambda results	;XXX suboptimal
   1481 		      (let ((winds2 (%host-ref "SPOCK.dynwinds")))
   1482 			(unless (eq? winds2 winds)
   1483 			  (unwind winds (- (length winds2) (length winds))) )
   1484 			(apply cont results) ) ) ) ) ) ))))
   1485 
   1486 	))
   1487 
   1488 
   1489     (define-library-section suspensions
   1490 
   1491       (default
   1492 
   1493 	(define (%get-context k)
   1494 	  (vector 
   1495 	   k
   1496 	   (%host-ref "SPOCK.dynwinds")
   1497 	   (%host-ref "SPOCK.stdin")
   1498 	   (%host-ref "SPOCK.stdout")
   1499 	   (%host-ref "SPOCK.stderr")))
   1500 
   1501 	(define %restore-context
   1502 	  (%native-lambda
   1503 	   "var state = arguments[ 1 ];"
   1504 	   "SPOCK.dynwinds = state[ 1 ];"
   1505 	   "SPOCK.stdin = state[ 2 ];"
   1506 	   "SPOCK.stdout = state[ 3 ];"
   1507 	   "SPOCK.stderr = state[ 4 ];"
   1508 	   "return (state[ 0 ])(undefined);")) ; drops K
   1509 	
   1510 	;;XXX currently undocumented and untested
   1511 	(define (suspend proc)
   1512 	  (%call-with-current-continuation
   1513 	   (lambda (k)
   1514 	     (proc (%get-context k))
   1515 	     ((%native-lambda "return new SPOCK.Result(undefined);")))))
   1516 
   1517 	;;XXX currently undocumented and untested
   1518 	(define-inline (resume state)
   1519 	  (%restore-context state))
   1520 
   1521 	))
   1522 
   1523 
   1524     (define-library-section promises
   1525 
   1526       (default
   1527 
   1528 	(define (%make-promise thunk)
   1529 	  (%inline
   1530 	   "new SPOCK.Promise"
   1531 	   (let ((ready #f)
   1532 		 (results #f))
   1533 	     (lambda ()
   1534 	       ;;XXX this can possibly be optimized
   1535 	       (if ready
   1536 		   (apply values results)
   1537 		   (call-with-values thunk
   1538 		     (lambda xs
   1539 		       (cond (ready (apply values results))
   1540 			     (else
   1541 			      (set! ready #t)
   1542 			      (set! results xs)
   1543 			      (apply values results))))))))))
   1544 
   1545 	(define (force p)
   1546 	  (if (%inline (1 " instanceof SPOCK.Promise") p)
   1547 	      ((%property-ref "thunk" p))
   1548 	      p))
   1549 
   1550 	))
   1551 
   1552 
   1553     (define-library-section port-redirection
   1554 
   1555       (default
   1556 
   1557 	(define with-input-from-port
   1558 	  (let ((dynamic-wind dynamic-wind))
   1559 	    (lambda (port thunk)
   1560 	      (%check-port port "input" "with-input-from-port")
   1561 	      (let ((old #f))
   1562 		(dynamic-wind
   1563 		    (lambda ()
   1564 		      (set! old (%host-ref "SPOCK.stdin"))
   1565 		      (%host-set! "SPOCK.stdin" port))
   1566 		    thunk
   1567 		    (lambda ()
   1568 		      (%host-set! "SPOCK.stdin" old)))))))
   1569 
   1570 	(define with-output-to-port
   1571 	  (let ((dynamic-wind dynamic-wind))
   1572 	    (lambda (port thunk)
   1573 	      (%check-port port "output" "with-output-to-port")
   1574 	      (let ((old #f))
   1575 		(dynamic-wind
   1576 		    (lambda ()
   1577 		      (set! old (%host-ref "SPOCK.stdout"))
   1578 		      (%host-set! "SPOCK.stdout" port))
   1579 		    thunk
   1580 		    (lambda ()
   1581 		      (%host-set! "SPOCK.stdout" old)))))))
   1582 
   1583 	))
   1584 
   1585 
   1586     (define-library-section file-operations
   1587 
   1588       (default
   1589 
   1590 	(define-inline (input-port? x)
   1591 	  (and (%inline (1 "instanceof SPOCK.Port") x)
   1592 	       (eq? "input" (%property-ref "direction" x))))
   1593 
   1594 	(define-inline (output-port? x)
   1595 	  (and (%inline (1 "instanceof SPOCK.Port") x)
   1596 	       (eq? "output" (%property-ref "direction" x))))
   1597 
   1598 	(define %close-port
   1599 	  (%native-lambda
   1600 	   "var port = arguments[ 1 ];"
   1601 	   "port.close();"
   1602 	   "port.closed = true;"
   1603 	   "return K(port);"))
   1604 
   1605 	(define open-input-file
   1606 	  (%native-lambda
   1607 	   "var fn = SPOCK.check(arguments[ 1 ], 'string', 'open-input-file');"
   1608 	   "return K(SPOCK.openInputFile(fn));"))
   1609 
   1610 	(define open-output-file
   1611 	  (%native-lambda
   1612 	   "var fn = SPOCK.check(arguments[ 1 ], 'string', 'open-input-file');"
   1613 	   "var exp = null;"
   1614 	   "if(arguments.length === 3)"
   1615 	   " exp = SPOCK.check(arguments[ 2 ], 'number', 'open-input-file');"
   1616 	   "return K(SPOCK.openOutputFile(fn, exp));"))
   1617 
   1618 	(define (close-input-port port)
   1619 	  (let ((port (%check-port port "input" "close-input-port")))
   1620 	    (%close-port port)))
   1621 
   1622 	(define (close-output-port port)
   1623 	  (let ((port (%check-port port "output" "close-output-port")))
   1624 	    (%close-port port)))
   1625 
   1626 	(define call-with-input-file
   1627 	  (let ((call-with-values call-with-values)
   1628 		(open-input-file open-input-file)
   1629 		(values values)
   1630 		(apply apply))
   1631 	    (lambda (file proc)
   1632 	      (let ((in (open-input-file file)))
   1633 		(%call-with-saved-values 
   1634 		 (lambda () (proc in))
   1635 		 (lambda ()
   1636 		   (close-input-port in)))))))
   1637 
   1638 	(define call-with-output-file
   1639 	  (let ((call-with-values call-with-values)
   1640 		(open-output-file open-output-file)
   1641 		(values values)
   1642 		(apply apply))
   1643 	    (lambda (file proc)
   1644 	      (let ((out (open-output-file file)))
   1645 		(%call-with-saved-values 
   1646 		 (lambda () (proc out))
   1647 		 (lambda ()
   1648 		   (close-output-port out)))))))
   1649 
   1650 	(define with-input-from-file
   1651 	  (let ((with-input-from-port with-input-from-port)
   1652 		(open-input-file open-input-file)
   1653 		(apply apply)
   1654 		(values values)
   1655 		(call-with-values call-with-values)
   1656 		(close-input-port close-input-port))
   1657 	    (lambda (filename thunk)
   1658 	      (let ((in (open-input-file filename)))
   1659 		(with-input-from-port in 
   1660 		  (lambda ()
   1661 		    (%call-with-saved-values 
   1662 		     thunk
   1663 		     (lambda ()
   1664 		       (close-input-port in)))))))))
   1665 
   1666 	(define with-output-to-file
   1667 	  (let ((with-output-to-port with-output-to-port)
   1668 		(open-output-file open-output-file)
   1669 		(apply apply)
   1670 		(values values)
   1671 		(call-with-values call-with-values)
   1672 		(close-output-port close-output-port))
   1673 	    (lambda (filename thunk)
   1674 	      (let ((out (open-output-file filename)))
   1675 		(with-output-to-port out
   1676 		  (lambda ()
   1677 		    (%call-with-saved-values 
   1678 		     thunk
   1679 		     (lambda ()
   1680 		       (close-output-port out)))))))))
   1681 
   1682 	))
   1683 
   1684 
   1685     (define-library-section string-ports
   1686 
   1687       (default
   1688 
   1689 	(define (open-input-string str)
   1690 	  (define open
   1691 	    (%native-lambda
   1692 	     "var buffer = arguments[ 1 ];"
   1693 	     "var pos = 0;"
   1694 	     "var len = buffer.length;"
   1695 	     "function read(n) {"
   1696 	     " if(pos >= len) return SPOCK.EOF;"
   1697 	     " var str = buffer.substring(pos, pos + n);"
   1698 	     " pos += n;"
   1699 	     " return str;}"
   1700 	     "return K(new SPOCK.Port('input', { read: read }));"))
   1701 	  (open (%string->jstring str)))
   1702 
   1703 	(define open-output-string
   1704 	  (%native-lambda
   1705 	   "var buffer = [];"
   1706 	   "function write(s) { buffer.push(s); }"
   1707 	   "var port = new SPOCK.Port('output', { write: write });"
   1708 	   "port.buffer = buffer;"
   1709 	   "port.isStringPort = true;"
   1710 	   "return K(port);"))
   1711 
   1712 	(define (get-output-string port)
   1713 	  (let ((port (%check ("SPOCK.Port") port)))
   1714 	    (if (not (void? (%property-ref "isStringPort" port)))
   1715 		(let ((str (%jstring->string
   1716 			    (%inline ".join" (%property-ref "buffer" port) ""))))
   1717 		  (%inline (1 ".buffer = []") port)
   1718 		  str)
   1719 		;;XXX unnecessary in non-debug mode
   1720 		(%inline "SPOCK.error" "bad argument type - not a string port" port))))
   1721 
   1722 	(define (with-input-from-string str thunk)
   1723 	  (let ((in (open-input-string str)))
   1724 	    (with-input-from-port in thunk)))
   1725 
   1726 	(define (with-output-to-string thunk)
   1727 	  (let ((out (open-output-string)))
   1728 	    (with-output-to-port out thunk)
   1729 	    (get-output-string out)))
   1730 
   1731 	))
   1732 
   1733 
   1734     (define-library-section reader
   1735 
   1736       (default
   1737 
   1738 	(define read
   1739 	  (let ((read-char read-char)
   1740 		(reverse reverse)
   1741 		(peek-char peek-char)
   1742 		(list->vector list->vector)
   1743 		(list->string list->string)
   1744 		(current-input-port current-input-port)
   1745 		(string->number string->number))
   1746 	    (lambda (port)
   1747 	      (let ((port (if (void? port) (current-input-port) port)))
   1748 		(define (parse-token t)
   1749 		  (or (string->number t)
   1750 		      (string->symbol t)))
   1751 		(define (read1)
   1752 		  (let ((c (read-char port)))
   1753 		    (if (eof-object? c) 
   1754 			c
   1755 			(case c
   1756 			  ((#\#) (read-sharp))
   1757 			  ((#\() (read-list #\)))
   1758 			  ((#\[) (read-list #\]))
   1759 			  ((#\{) (read-list #\}))
   1760 			  ((#\,) (if (eqv? (peek-char port) #\@)
   1761 				     (list 'unquote-splicing (read1))
   1762 				     (list 'unquote (read1))))
   1763 			  ((#\`) (list 'quasiquote (read1)))
   1764 			  ((#\') `',(read1))
   1765 			  ((#\;) (skip-line) (read1))
   1766 			  ((#\") (read-string))
   1767 			  ((#\) #\] #\}) (%error "unexpected delimiter" c))
   1768 			  (else
   1769 			   (if (char-whitespace? c)
   1770 			       (read1)
   1771 			       (parse-token (read-token (list c)))))))))
   1772 		(define (skip-line)
   1773 		  (let ((c (read-char port)))
   1774 		    (unless (or (eof-object? c) (char=? #\newline c))
   1775 		      (skip-line))))
   1776 		(define (skip-whitespace) ; returns peeked char
   1777 		  (let ((c (peek-char port)))
   1778 		    (cond ((char-whitespace? c)
   1779 			   (read-char port)
   1780 			   (skip-whitespace))
   1781 			  (else c))))
   1782 		(define (read-sharp)
   1783 		  (let ((c (read-char port)))
   1784 		    (if (eof-object? c)
   1785 			(%error "unexpected EOF after `#'")
   1786 			(case c
   1787 			  ((#\t #\T) #t)
   1788 			  ((#\f #\F) #f)
   1789 			  ((#\() (list->vector (read-list #\))))
   1790 			  ((#\% #\!) (string->symbol (read-token (list c #\#))))
   1791 			  ((#\\) 
   1792 			   (let ((t (read-token '())))
   1793 			     (cond ((string-ci=? "newline" t) #\newline)
   1794 				   ((string-ci=? "tab" t) #\tab)
   1795 				   ((string-ci=? "space" t) #\space)
   1796 				   ((zero? (string-length t))
   1797 				    (%error "invalid character syntax"))
   1798 				   (else (string-ref t 0)))))
   1799 			  (else (%error "invalid `#' syntax" c))))))
   1800 		(define (read-list delim)
   1801 		  (let loop ((lst '()))
   1802 		    (let ((c (skip-whitespace)))
   1803 		      (cond ((eof-object? c)
   1804 			     (%error "unexpected EOF while reading list"))
   1805 			    ((char=? c delim)
   1806 			     (read-char port)
   1807 			     (reverse lst))
   1808 			    (else
   1809 			     (if (eqv? #\. c)
   1810 				 (let ((t (read-token '())))
   1811 				   (if (string=? "." t)
   1812 				       (let ((rest (read1)))
   1813 					 (skip-whitespace)
   1814 					 (if (eqv? (read-char port) delim)
   1815 					     (append (reverse lst) rest)
   1816 					     (%error "missing closing delimiter" delim)))
   1817 				       (loop (cons (parse-token t)) lst)))
   1818 				 (loop (cons (read1) lst))))))))
   1819 		(define (read-string)
   1820 		  (let loop ((lst '()))
   1821 		    (let ((c (read-char port)))
   1822 		      (cond ((eof-object? c)
   1823 			     (%error "unexpected EOF while reading string"))
   1824 			    ((char=? #\" c) 
   1825 			     (list->string (reverse lst)))
   1826 			    ((char=? #\\ c)
   1827 			     (let ((c (read-char port)))
   1828 			       (if (eof-object? c)
   1829 				   (%error "unexpected EOF while reading string")
   1830 				   (case c
   1831 				     ((#\n) (loop (cons #\newline lst)))
   1832 				     ((#\t) (loop (cons #\tab lst)))
   1833 				     (else (loop (cons c lst)))))))
   1834 			    (else (loop (cons c lst)))))))
   1835 		(define (read-token prefix)
   1836 		  (let loop ((lst prefix)) ; prefix must be in reverse order
   1837 		    (let ((c (peek-char port)))
   1838 		      (if (or (eof-object? c) 
   1839 			      (memv c '(#\{ #\} #\( #\) #\[ #\] #\; #\"))
   1840 			      (char-whitespace? c))
   1841 			  (list->string (reverse lst))
   1842 			  (loop (cons (read-char port) lst))))))
   1843 		(read1)))))
   1844 
   1845 	))
   1846 
   1847 
   1848     (define-library-section loading
   1849       
   1850       (default
   1851 
   1852 	(define (load file k)
   1853 	  (%inline 
   1854 	   "SPOCK.load"
   1855 	   (%string->jstring file) 
   1856 	   (and (not (%void? k))
   1857 		(callback k))))
   1858 
   1859 	))
   1860 
   1861 
   1862     (define-library-section error-handling
   1863 
   1864       (default
   1865 	
   1866 	;; (%error MESSAGE ARGUMENTS ...)
   1867 	(define %error
   1868 	  (%native-lambda
   1869 	   "SPOCK.error.apply(SPOCK.global, Array.prototype.slice.call(arguments, 1));"))
   1870 
   1871 	(define error %error)
   1872 
   1873 	))
   1874 
   1875 
   1876     (define-library-section miscellaneous
   1877 
   1878       (default
   1879 
   1880 	(define (exit code)
   1881 	  (%inline "SPOCK.exit" (if (void? code) 0 (%check "number" code))))
   1882 
   1883 	(define (milliseconds thunk)
   1884 	  (let ((t0 (%inline "(new Date()).getTime")))
   1885 	    (if (void? thunk)
   1886 		t0
   1887 		(let* ((r (thunk)) ;XXX will not handle multiple values
   1888 		       (t1 (%inline "(new Date()).getTime")))
   1889 		  (%inline (1 "-" 2) t1 t0))))) 
   1890 
   1891 	(define-inline (callback proc)
   1892 	  (%inline "SPOCK.callback" proc))
   1893 
   1894 	(define-inline (callback-method proc)
   1895 	  (%inline "SPOCK.callbackMethod" proc))
   1896 
   1897 	(define (print . args)
   1898 	  (for-each display args)
   1899 	  (newline))
   1900 
   1901 	(define-inline (id x) x)
   1902 	(define-inline (const x) (lambda _ x))
   1903 	(define-inline (compl f) (lambda (x) (not (f x))))
   1904 	
   1905 	(define (o . fns)		;XXX optimize this
   1906 	  (if (null? fns)
   1907 	      id
   1908 	      (let loop ((fns fns))
   1909 		(let ((h (%car fns))
   1910 		      (t (%cdr fns)) )
   1911 		  (if (null? t)
   1912 		      h
   1913 		      (lambda (x) (h ((loop t) x))))))))
   1914 
   1915 	(define %
   1916 	  (%native-lambda
   1917 	   "var o = {};"
   1918 	   "for(var i = 1; i < arguments.length; i += 2) {"
   1919 	   " var x = arguments[ i ];"
   1920 	   " if(typeof x === 'string') o[ x ] = arguments[ i + 1 ];"
   1921 	   " else if(x instanceof SPOCK.String)"
   1922 	   "  o[ x.name ] = arguments[ i + 1 ];"
   1923 	   " else SPOCK.error('(%) object key not a string or symbol', x);}"
   1924 	   "return K(o);"))
   1925 
   1926 	(define native 
   1927 	  (%native-lambda 
   1928 	   "var func = arguments[ 1 ];"
   1929 	   "return K(function(k) {"
   1930 	   " var args = Array.prototype.splice.call(arguments, 1);"
   1931 	   " return k(func.apply(SPOCK.global, args));});"))
   1932 
   1933 	(define native-method
   1934 	  (%native-lambda
   1935 	   "var func = arguments[ 1 ];"
   1936 	   "return K(function(k) {"
   1937 	   " var args = Array.prototype.splice.call(arguments, 2);"
   1938 	   " return k(func.apply(arguments[ 1 ], args));});"))
   1939 
   1940 	(define bind-method
   1941 	  (%native-lambda
   1942 	   "var func = arguments[ 1 ];"
   1943 	   "var that = arguments[ 2 ];"
   1944 	   "return K(function() { return func.apply(that, arguments); });"))
   1945 
   1946 	(define-inline (file-exists? filename)
   1947 	  (%inline "SPOCK.fileExists" (%string->jstring filename)))
   1948 
   1949 	(define jstring
   1950 	  (%native-lambda
   1951 	   "var x = arguments[ 1 ];"
   1952 	   "if(typeof x === 'string') return K(x);"
   1953 	   "else if(x instanceof SPOCK.String) return K(x.normalize());"
   1954 	   "else if(x instanceof SPOCK.Char) return K(x.character);"
   1955 	   "else return K(x);"))
   1956 
   1957 	))
   1958 
   1959     ))