2024-07-20 05:17:06 +02:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
;
|
|
|
|
; Non-C extracts from Large RNRS compatibility library for #F, fixnum/flonums
|
|
|
|
;
|
|
|
|
; #F's predefined forms:
|
|
|
|
;
|
|
|
|
; begin define define-syntax if lambda quote
|
|
|
|
; set! syntax-lambda syntax-rules
|
|
|
|
;
|
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(load "n.sf")
|
|
|
|
|
|
|
|
; basic syntax constructs, extended lambda
|
|
|
|
|
|
|
|
(define-syntax syntax-rule
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ pat tmpl) (syntax-rules () [(__ . pat) tmpl])]))
|
|
|
|
|
|
|
|
(define-syntax let-syntax
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ ([kw init] ...))
|
|
|
|
(begin)]
|
|
|
|
[(_ ([kw init] ...) . body)
|
|
|
|
((syntax-lambda (kw ...) . body)
|
|
|
|
init ...)]))
|
|
|
|
|
|
|
|
(define-syntax letrec-syntax
|
|
|
|
(let-syntax ([let-syntax let-syntax] [define-syntax define-syntax])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ ([kw init] ...) . body)
|
|
|
|
(let-syntax ()
|
|
|
|
(define-syntax kw init) ... (let-syntax () . body))])))
|
|
|
|
|
|
|
|
(define-syntax lambda
|
|
|
|
(let-syntax ([old-lambda lambda])
|
|
|
|
(letrec-syntax
|
|
|
|
([loop
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ (narg . more) (arg ...) . body)
|
|
|
|
(loop more (arg ... narg) . body)]
|
|
|
|
[(_ rarg (arg ...) . body)
|
|
|
|
(make-improper-lambda ; see definition below
|
|
|
|
#&(length (arg ...))
|
|
|
|
(old-lambda (arg ... rarg) (let-syntax () . body)))])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ (arg ...) . body)
|
|
|
|
(old-lambda (arg ...) (let-syntax () . body))]
|
|
|
|
[(_ args . body)
|
|
|
|
(loop args () . body)]))))
|
|
|
|
|
|
|
|
|
|
|
|
; definition forms
|
|
|
|
|
|
|
|
(define-syntax define
|
|
|
|
(let-syntax ([old-define define])
|
|
|
|
(letrec-syntax
|
|
|
|
([new-define
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ exp) (old-define exp)]
|
|
|
|
[(_ (var-or-prototype . args) . body)
|
|
|
|
(new-define var-or-prototype (lambda args . body))]
|
|
|
|
[(_ . other) (old-define . other)])])
|
|
|
|
new-define)))
|
|
|
|
|
|
|
|
(define-syntax define-inline
|
|
|
|
(letrec-syntax
|
|
|
|
([loop
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ id ([v e] ...) () . body)
|
|
|
|
(begin
|
|
|
|
(define-syntax id
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ e ...)
|
|
|
|
((lambda (v ...) . body) e ...)]
|
|
|
|
[_ #&(string->id #&(string-append "%residual-" #&(id->string id)))]))
|
|
|
|
(define #&(string->id #&(string-append "%residual-" #&(id->string id)))
|
|
|
|
(lambda (v ...) . body)))]
|
|
|
|
[(_ id (b ...) (v . vs) . body)
|
|
|
|
(loop id (b ... [v e]) vs . body)])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ (id v ...) . body)
|
|
|
|
(loop id () (v ...) . body)]
|
|
|
|
[(_ #&(id? id) val)
|
|
|
|
(define-syntax id val)])))
|
|
|
|
|
|
|
|
(define-syntax define-integrable
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ (op . ll) . body)
|
|
|
|
(define-syntax op
|
|
|
|
(%quote (letrec ([op (lambda ll . body)]) op)))]))
|
|
|
|
|
|
|
|
|
|
|
|
; primitive definition helpers
|
|
|
|
|
|
|
|
(define-syntax %prim*/rev
|
|
|
|
(letrec-syntax
|
|
|
|
([loop
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ prim () args)
|
|
|
|
(%prim* prim . args)]
|
|
|
|
[(_ prim (arg . more) args)
|
|
|
|
(loop prim more (arg . args))])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ prim arg ...)
|
|
|
|
(loop prim (arg ...) ())])))
|
|
|
|
|
|
|
|
|
|
|
|
; binding forms
|
|
|
|
|
|
|
|
(define-syntax let
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ ([var init] ...) . body)
|
|
|
|
((lambda (var ...) . body) init ...)]
|
|
|
|
[(_ name ([var init] ...) . body)
|
|
|
|
((letrec ([name (lambda (var ...) . body)])
|
|
|
|
name)
|
|
|
|
init ...)]))
|
|
|
|
|
|
|
|
(define-syntax let*
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ () . body) (let () . body)]
|
|
|
|
[(_ ([var init] . bindings) . body)
|
|
|
|
(let ([var init]) (let* bindings . body))]))
|
|
|
|
|
|
|
|
(define-syntax letrec
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ ([var init] ...) . body)
|
|
|
|
(let () (define var init) ... (let () . body))]))
|
|
|
|
|
|
|
|
(define-syntax letrec*
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ ([var expr] ...) . body)
|
|
|
|
(let ([var #f] ...)
|
|
|
|
(set! var expr)
|
|
|
|
...
|
|
|
|
(let () . body))]))
|
|
|
|
|
|
|
|
(define-syntax rec
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ (name . args) . body)
|
|
|
|
(letrec ([name (lambda args . body)]) name)]
|
|
|
|
[(_ name expr)
|
|
|
|
(letrec ([name expr]) name)]))
|
|
|
|
|
|
|
|
(define-syntax letcc
|
|
|
|
(let-syntax ([old-letcc letcc])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ var . body)
|
|
|
|
(old-letcc var (let-syntax () . body))])))
|
|
|
|
|
|
|
|
(define-syntax receive
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ formals expr . body)
|
|
|
|
(call-with-values
|
|
|
|
(lambda () expr)
|
|
|
|
(lambda formals . body))]))
|
|
|
|
|
|
|
|
(define-syntax let*-values
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ () . body) (let () . body)]
|
|
|
|
[(_ ([(a) x] . b*) . body) (let ([a x]) (let*-values b* . body))]
|
|
|
|
[(_ ([aa x] . b*) . body) (call-with-values (lambda () x) (lambda aa (let*-values b* . body)))]))
|
|
|
|
|
|
|
|
(define-syntax let-values
|
|
|
|
(letrec-syntax
|
|
|
|
([loop
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ (new-b ...) new-aa x map-b* () () . body)
|
|
|
|
(let*-values (new-b ... [new-aa x]) (let map-b* . body))]
|
|
|
|
[(_ (new-b ...) new-aa old-x map-b* () ([aa x] . b*) . body)
|
|
|
|
(loop (new-b ... [new-aa old-x]) () x map-b* aa b* . body)]
|
|
|
|
[(_ new-b* (new-a ...) x (map-b ...) (a . aa) b* . body)
|
|
|
|
(loop new-b* (new-a ... tmp-a) x (map-b ... [a tmp-a]) aa b* . body)]
|
|
|
|
[(_ new-b* (new-a ...) x (map-b ...) a b* . body)
|
|
|
|
(loop new-b* (new-a ... . tmp-a) x (map-b ... [a tmp-a]) () b* . body)])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ () . body) (let () . body)]
|
|
|
|
[(_ ([aa x] . b*) . body)
|
|
|
|
(loop () () x () aa b* . body)])))
|
|
|
|
|
|
|
|
#;(define-syntax set!-values
|
|
|
|
(letrec-syntax
|
|
|
|
([loop
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ new-aa ([a tmp-a] ...) () x)
|
|
|
|
(call-with-values (lambda () x) (lambda new-aa (set! a tmp-a) ...))]
|
|
|
|
[(_ (new-a ...) (map-a ...) (a . aa) x)
|
|
|
|
(loop (new-a ... tmp-a) (map-a ... [a tmp-a]) aa x)]
|
|
|
|
[(_ (new-a ...) (map-a ...) a x)
|
|
|
|
(loop (new-a ... . tmp-a) (map-a ... [a tmp-a]) () x)])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ () x) (define x)]
|
|
|
|
[(_ aa x) (loop () () aa x)])))
|
|
|
|
|
|
|
|
(define-syntax define-values
|
|
|
|
(letrec-syntax
|
|
|
|
([loop
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ new-aa ([a tmp-a] ...) () x)
|
|
|
|
(begin
|
|
|
|
(define a (void)) ...
|
|
|
|
(define (call-with-values (lambda () x) (lambda new-aa (set! a tmp-a) ...))))]
|
|
|
|
[(_ (new-a ...) (map-a ...) (a . aa) x)
|
|
|
|
(loop (new-a ... tmp-a) (map-a ... [a tmp-a]) aa x)]
|
|
|
|
[(_ (new-a ...) (map-a ...) a x)
|
|
|
|
(loop (new-a ... . tmp-a) (map-a ... [a tmp-a]) () x)])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ () x) (define x)]
|
|
|
|
[(_ aa x) (loop () () aa x)])))
|
|
|
|
|
|
|
|
|
|
|
|
; control
|
|
|
|
|
|
|
|
(define-syntax when
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ test . body) (if test (let-syntax () . body))]))
|
|
|
|
|
|
|
|
(define-syntax unless
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ test . body) (if test (if #f #f) (let-syntax () . body))]))
|
|
|
|
|
|
|
|
(define-syntax cond
|
|
|
|
(syntax-rules (else =>)
|
|
|
|
[(_) (if #f #f)] ; undefined
|
|
|
|
[(_ [else . exps]) (let () . exps)]
|
|
|
|
[(_ [x] . rest) (or x (cond . rest))]
|
|
|
|
[(_ [x => proc] . rest)
|
|
|
|
(let ([tmp x]) (cond [tmp (proc tmp)] . rest))]
|
|
|
|
[(_ [x . exps] . rest)
|
|
|
|
(if x (let () . exps) (cond . rest))]))
|
|
|
|
|
|
|
|
(define-syntax and
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) #t]
|
|
|
|
[(_ test) (let () test)]
|
|
|
|
[(_ test . tests) (if test (and . tests) #f)]))
|
|
|
|
|
|
|
|
(define-syntax or
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) #f]
|
|
|
|
[(_ test) (let () test)]
|
|
|
|
[(_ test . tests) (let ([x test]) (if x x (or . tests)))]))
|
|
|
|
|
|
|
|
(define-syntax do
|
|
|
|
(let-syntax ([do-step (syntax-rules () [(_ x) x] [(_ x y) y])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ ([var init step ...] ...)
|
|
|
|
[test expr ...]
|
|
|
|
command ...)
|
|
|
|
(let loop ([var init] ...)
|
|
|
|
(if test
|
|
|
|
(begin (if #f #f) expr ...)
|
|
|
|
(let ()
|
|
|
|
command ...
|
|
|
|
(loop (do-step var step ...) ...))))])))
|
|
|
|
|
|
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
; scheme data types
|
|
|
|
|
|
|
|
; booleans
|
|
|
|
|
|
|
|
; #f is (obj)0, #t is immediate 0 with tag 0 (singular true object)
|
|
|
|
; this layout is compatible with C conventions (0 = false, 1 = true)
|
|
|
|
; note that any obj but #f is counted as true in conditionals and that
|
|
|
|
; bool_from_obj and bool_from_bool are already defined in std prelude
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (boolean)
|
|
|
|
[(_ boolean b) (%prim ("bool(" b ")"))]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (boolean? x)
|
|
|
|
(%prim "bool(is_bool_$arg)" x))
|
|
|
|
|
|
|
|
(define-inline (not x)
|
|
|
|
(%prim "bool(!bool_from_$arg)" x))
|
|
|
|
|
|
|
|
(define-syntax boolean=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(bool_from_$arg == bool_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (boolean=? x t) (boolean=? t z ...)))]
|
|
|
|
[_ %residual-boolean=?]))
|
|
|
|
|
|
|
|
|
|
|
|
; void
|
|
|
|
|
|
|
|
; void object redefined as immediate with payload 0 and immediate tag 1
|
|
|
|
|
|
|
|
(define-inline (void) (%prim "void(0)"))
|
|
|
|
(define-inline (void? x) (%prim "bool(obj_from_$arg == obj_from_void(0))" x))
|
|
|
|
|
|
|
|
|
|
|
|
; unit
|
|
|
|
|
|
|
|
; this is the value to be used when zero results are returned to a context
|
|
|
|
; where one result is expected; it is analogous to a 0-element tuple
|
|
|
|
|
|
|
|
|
|
|
|
; fixnums
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(letrec-syntax
|
|
|
|
([bin->oct
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ b sign digs) (bin->oct b sign #&(string->list digs) ())]
|
|
|
|
[(_ b sign () l) (%const integer b sign #&(list->string l) 8)]
|
|
|
|
[(_ b sign (#\0) l) (bin->oct b sign () (#\0 . l))]
|
|
|
|
[(_ b sign (#\1) l) (bin->oct b sign () (#\1 . l))]
|
|
|
|
[(_ b sign (#\0 #\0) l) (bin->oct b sign () (#\0 . l))]
|
|
|
|
[(_ b sign (#\0 #\1) l) (bin->oct b sign () (#\1 . l))]
|
|
|
|
[(_ b sign (#\1 #\0) l) (bin->oct b sign () (#\2 . l))]
|
|
|
|
[(_ b sign (#\1 #\1) l) (bin->oct b sign () (#\3 . l))]
|
|
|
|
[(_ b sign (d ... #\0 #\0 #\0) l) (bin->oct b sign (d ...) (#\0 . l))]
|
|
|
|
[(_ b sign (d ... #\0 #\0 #\1) l) (bin->oct b sign (d ...) (#\1 . l))]
|
|
|
|
[(_ b sign (d ... #\0 #\1 #\0) l) (bin->oct b sign (d ...) (#\2 . l))]
|
|
|
|
[(_ b sign (d ... #\0 #\1 #\1) l) (bin->oct b sign (d ...) (#\3 . l))]
|
|
|
|
[(_ b sign (d ... #\1 #\0 #\0) l) (bin->oct b sign (d ...) (#\4 . l))]
|
|
|
|
[(_ b sign (d ... #\1 #\0 #\1) l) (bin->oct b sign (d ...) (#\5 . l))]
|
|
|
|
[(_ b sign (d ... #\1 #\1 #\0) l) (bin->oct b sign (d ...) (#\6 . l))]
|
|
|
|
[(_ b sign (d ... #\1 #\1 #\1) l) (bin->oct b sign (d ...) (#\7 . l))])])
|
|
|
|
(syntax-rules (integer exact inexact)
|
|
|
|
[(_ integer 8 sign digs 2) (bin->oct 8 sign digs)]
|
|
|
|
[(_ integer 16 sign digs 2) (bin->oct 16 sign digs)]
|
|
|
|
[(_ integer 24 sign digs 2) (bin->oct 24 sign digs)]
|
|
|
|
[(_ integer 8 sign digs 8) (%prim ("fixnum(" #&(id->string sign) "0" digs ")"))]
|
|
|
|
[(_ integer 16 sign digs 8) (%prim ("fixnum(" #&(id->string sign) "0" digs ")"))]
|
|
|
|
[(_ integer 24 sign digs 8) (%prim ("fixnum(" #&(id->string sign) "0" digs ")"))]
|
|
|
|
[(_ integer 8 sign digs 10) (%prim ("fixnum(" #&(id->string sign) digs ")"))]
|
|
|
|
[(_ integer 16 sign digs 10) (%prim ("fixnum(" #&(id->string sign) digs ")"))]
|
|
|
|
[(_ integer 24 sign digs 10) (%prim ("fixnum(" #&(id->string sign) digs ")"))]
|
|
|
|
[(_ integer 8 sign digs 16) (%prim ("fixnum(" #&(id->string sign) "0x" digs ")"))]
|
|
|
|
[(_ integer 16 sign digs 16) (%prim ("fixnum(" #&(id->string sign) "0x" digs ")"))]
|
|
|
|
[(_ integer 24 sign digs 16) (%prim ("fixnum(" #&(id->string sign) "0x" digs ")"))]
|
|
|
|
[(_ exact (integer . r)) (%const integer . r)]
|
|
|
|
[(_ inexact (integer . r)) (exact->inexact (%const integer . r))]
|
|
|
|
[(_ arg ...) (old-%const arg ...)]))))
|
|
|
|
|
|
|
|
(define-inline (fixnum? x)
|
|
|
|
(%prim "bool(is_fixnum_$arg)" x))
|
|
|
|
|
|
|
|
(define-inline (fixnum-width)
|
|
|
|
(%prim "fixnum(FIXNUM_BIT)"))
|
|
|
|
|
|
|
|
(define-inline (least-fixnum)
|
|
|
|
(%prim "fixnum(FIXNUM_MIN)"))
|
|
|
|
|
|
|
|
(define-inline (greatest-fixnum)
|
|
|
|
(%prim "fixnum(FIXNUM_MAX)"))
|
|
|
|
|
|
|
|
(define-syntax fx=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(fixnum_from_$arg == fixnum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fx=? x t) (fx=? t z ...)))]
|
|
|
|
[_ %residual-fx=?]))
|
|
|
|
|
|
|
|
(define-syntax fx<?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(fixnum_from_$arg < fixnum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fx<? x t) (fx<? t z ...)))]
|
|
|
|
[_ %residual-fx<?]))
|
|
|
|
|
|
|
|
(define-syntax fx>?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(fixnum_from_$arg > fixnum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fx>? x t) (fx>? t z ...)))]
|
|
|
|
[_ %residual-fx>?]))
|
|
|
|
|
|
|
|
(define-syntax fx<=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(fixnum_from_$arg <= fixnum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fx<=? x t) (fx<=? t z ...)))]
|
|
|
|
[_ %residual-fx<=?]))
|
|
|
|
|
|
|
|
(define-syntax fx>=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(fixnum_from_$arg >= fixnum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fx>=? x t) (fx>=? t z ...)))]
|
|
|
|
[_ %residual-fx>=?]))
|
|
|
|
|
|
|
|
(define-inline (fxzero? x)
|
|
|
|
(%prim "bool(fixnum_from_$arg == 0)" x))
|
|
|
|
|
|
|
|
(define-inline (fxpositive? x)
|
|
|
|
(%prim "bool(fixnum_from_$arg > 0)" x))
|
|
|
|
|
|
|
|
(define-inline (fxnegative? x)
|
|
|
|
(%prim "bool(fixnum_from_$arg < 0)" x))
|
|
|
|
|
|
|
|
(define-inline (fxodd? x)
|
|
|
|
(%prim "bool((fixnum_from_$arg & 1) != 0)" x))
|
|
|
|
|
|
|
|
(define-inline (fxeven? x)
|
|
|
|
(%prim "bool((fixnum_from_$arg & 1) == 0)" x))
|
|
|
|
|
|
|
|
(define-syntax fxmax
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y) (let ([a x] [b y]) (if (fx>? a b) a b))]
|
|
|
|
[(_ x y z ...) (fxmax (fxmax x y) z ...)]
|
|
|
|
[_ %residual-fxmax]))
|
|
|
|
|
|
|
|
(define-syntax fxmin
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y) (let ([a x] [b y]) (if (fx<? a b) a b))]
|
|
|
|
[(_ x y z ...) (fxmin (fxmin x y) z ...)]
|
|
|
|
[_ %residual-fxmin]))
|
|
|
|
|
|
|
|
(define-syntax fx+
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (%prim "fixnum(0)")] [(_ x) x]
|
|
|
|
[(_ x y) (%prim "fixnum(fxadd(fixnum_from_$arg, fixnum_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (fx+ x (fx+ y z ...))]
|
|
|
|
[_ %residual-fx+]))
|
|
|
|
|
|
|
|
(define-syntax fx*
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (%prim "fixnum(1)")] [(_ x) x]
|
|
|
|
[(_ x y) (%prim "fixnum(fxmul(fixnum_from_$arg, fixnum_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (fx* x (fx* y z ...))]
|
|
|
|
[_ %residual-fx*]))
|
|
|
|
|
|
|
|
(define-syntax fx-
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (%prim "fixnum(fxneg(fixnum_from_$arg))" x)]
|
|
|
|
[(_ x y) (%prim "fixnum(fxsub(fixnum_from_$arg, fixnum_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (fx- (fx- x y) z ...)]
|
|
|
|
[_ %residual-fx-]))
|
|
|
|
|
|
|
|
(define-syntax fx/
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (%prim "fixnum(fxdiv(1, fixnum_from_$arg))" x)]
|
|
|
|
[(_ x y) (%prim "fixnum(fxdiv(fixnum_from_$arg, fixnum_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (fx/ (fx/ x y) z ...)]
|
|
|
|
[_ %residual-fx/]))
|
|
|
|
|
|
|
|
(define-inline (fxquotient x y)
|
|
|
|
(%prim "fixnum(fxquo(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxremainder x y)
|
|
|
|
(%prim "fixnum(fxrem(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxmodquo x y)
|
|
|
|
(%prim "fixnum(fxmqu(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxmodulo x y)
|
|
|
|
(%prim "fixnum(fxmlo(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxeuq x y)
|
|
|
|
(%prim "fixnum(fxeuq(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxeur x y)
|
|
|
|
(%prim "fixnum(fxeur(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxabs x)
|
|
|
|
(%prim "fixnum(fxabs(fixnum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (fxgcd x y)
|
|
|
|
(%prim "fixnum(fxgcd(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxexpt x y)
|
|
|
|
(%prim* "fixnum(fxpow(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxsqrt x)
|
|
|
|
(%prim "fixnum(fxsqrt(fixnum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (fxnot x)
|
|
|
|
(%prim "fixnum(~fixnum_from_$arg)" x))
|
|
|
|
|
|
|
|
(define-inline (fxand x y)
|
|
|
|
(%prim "fixnum(fixnum_from_$arg & fixnum_from_$arg)" x y))
|
|
|
|
|
|
|
|
(define-inline (fxior x y)
|
|
|
|
(%prim "fixnum(fixnum_from_$arg | fixnum_from_$arg)" x y))
|
|
|
|
|
|
|
|
(define-inline (fxxor x y)
|
|
|
|
(%prim "fixnum(fixnum_from_$arg ^ fixnum_from_$arg)" x y))
|
|
|
|
|
|
|
|
(define-inline (fxarithmetic-shift-left x y)
|
|
|
|
(%prim "fixnum(fxasl(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxarithmetic-shift-right x y)
|
|
|
|
(%prim "fixnum(fxasr(fixnum_from_$arg, fixnum_from_$arg))" x y))
|
|
|
|
|
|
|
|
|
|
|
|
; flonums
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (decimal e exact inexact inf nan)
|
|
|
|
[(_ decimal e str)
|
|
|
|
(%prim* ("flonum($live, " str ")"))]
|
|
|
|
[(_ decimal e ms indigs frdigs es exdigs)
|
|
|
|
(%prim* ("flonum($live, " #&(id->string ms)
|
|
|
|
indigs "." frdigs "e" #&(id->string es) exdigs ")"))]
|
|
|
|
[(_ inexact (decimal . r)) (%const decimal . r)]
|
|
|
|
[(_ exact (decimal . r)) (inexact->exact (%const decimal . r))]
|
|
|
|
[(_ inf ms) (%prim* ("flonum($live, " #&(id->string ms) "HUGE_VAL)"))]
|
|
|
|
[(_ inexact (inf . r)) (%const inf . r)]
|
|
|
|
[(_ nan ms) (%prim* ("flonum($live, HUGE_VAL-HUGE_VAL)"))]
|
|
|
|
[(_ inexact (nan . r)) (%const nan . r)]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (flonum? x)
|
|
|
|
(%prim "bool(is_flonum_$arg)" x))
|
|
|
|
|
|
|
|
(define-inline (fixnum->flonum n)
|
|
|
|
(%prim* "flonum($live, (flonum_t)fixnum_from_$arg)" n))
|
|
|
|
|
|
|
|
(define-inline (flonum->fixnum x)
|
|
|
|
(%prim "fixnum(fxflo(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (real->flonum n)
|
|
|
|
(if (flonum? n) n (fixnum->flonum n)))
|
|
|
|
|
|
|
|
(define-inline (real->fixnum n)
|
|
|
|
(if (fixnum? n) n (flonum->fixnum n)))
|
|
|
|
|
|
|
|
(define-syntax fl=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(flonum_from_$arg == flonum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fl=? x t) (fl=? t z ...)))]
|
|
|
|
[_ %residual-fl=?]))
|
|
|
|
|
|
|
|
(define-syntax fl<?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(flonum_from_$arg < flonum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fl<? x t) (fl<? t z ...)))]
|
|
|
|
[_ %residual-fl<?]))
|
|
|
|
|
|
|
|
(define-syntax fl>?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(flonum_from_$arg > flonum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fl>? x t) (fl>? t z ...)))]
|
|
|
|
[_ %residual-fl>?]))
|
|
|
|
|
|
|
|
(define-syntax fl<=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(flonum_from_$arg <= flonum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fl<=? x t) (fl<=? t z ...)))]
|
|
|
|
[_ %residual-fl<=?]))
|
|
|
|
|
|
|
|
(define-syntax fl>=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(flonum_from_$arg >= flonum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (fl>=? x t) (fl>=? t z ...)))]
|
|
|
|
[_ %residual-fl>=?]))
|
|
|
|
|
|
|
|
(define-inline (flinteger? x)
|
|
|
|
(%prim "bool(flisint(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (flzero? x)
|
|
|
|
(%prim "bool(flonum_from_$arg == 0.0)" x))
|
|
|
|
|
|
|
|
(define-inline (flpositive? x)
|
|
|
|
(%prim "bool(flonum_from_$arg > 0.0)" x))
|
|
|
|
|
|
|
|
(define-inline (flnegative? x)
|
|
|
|
(%prim "bool(flonum_from_$arg < 0.0)" x))
|
|
|
|
|
|
|
|
(define-inline (flodd? x)
|
|
|
|
(%prim "bool(flisint((flonum_from_$arg + 1.0) / 2.0))" x))
|
|
|
|
|
|
|
|
(define-inline (fleven? x)
|
|
|
|
(%prim "bool(flisint(flonum_from_$arg / 2.0))" x))
|
|
|
|
|
|
|
|
(define-inline (flnan? x)
|
|
|
|
(%prim "{ /* flnan? */
|
|
|
|
flonum_t f = flonum_from_$arg;
|
|
|
|
$return bool(f != f); }" x))
|
|
|
|
|
|
|
|
(define-inline (flinfinite? x)
|
|
|
|
(%prim "{ /* flinfinite? */
|
|
|
|
flonum_t f = flonum_from_$arg;
|
|
|
|
$return bool(f <= -HUGE_VAL || f >= HUGE_VAL); }" x))
|
|
|
|
|
|
|
|
(define-syntax flmax
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y) (let ([a x] [b y]) (if (fl>? a b) a b))]
|
|
|
|
[(_ x y z ...) (flmax (flmax x y) z ...)]
|
|
|
|
[_ %residual-flmax]))
|
|
|
|
|
|
|
|
(define-syntax flmin
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y) (let ([a x] [b y]) (if (fl<? a b) a b))]
|
|
|
|
[(_ x y z ...) (flmin (flmin x y) z ...)]
|
|
|
|
[_ %residual-flmin]))
|
|
|
|
|
|
|
|
(define-syntax fl+
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (%prim* "flonum($live, 0.0)")] [(_ x) x]
|
|
|
|
[(_ x y) (%prim* "flonum($live, flonum_from_$arg + flonum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (fl+ x (fl+ y z ...))]
|
|
|
|
[_ %residual-fl+]))
|
|
|
|
|
|
|
|
(define-syntax fl*
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (%prim* "flonum($live, 1.0)")] [(_ x) x]
|
|
|
|
[(_ x y) (%prim* "flonum($live, flonum_from_$arg * flonum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (fl* x (fl* y z ...))]
|
|
|
|
[_ %residual-fl*]))
|
|
|
|
|
|
|
|
(define-syntax fl-
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (%prim* "flonum($live, -flonum_from_$arg)" x)]
|
|
|
|
[(_ x y) (%prim* "flonum($live, flonum_from_$arg - flonum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (fl- (fl- x y) z ...)]
|
|
|
|
[_ %residual-fl-]))
|
|
|
|
|
|
|
|
(define-syntax fl/
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (%prim* "flonum($live, 1.0/flonum_from_$arg)" x)]
|
|
|
|
[(_ x y) (%prim* "flonum($live, flonum_from_$arg / flonum_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (fl/ (fl/ x y) z ...)]
|
|
|
|
[_ %residual-fl/]))
|
|
|
|
|
|
|
|
(define-inline (flquotient x y)
|
|
|
|
(%prim* "flonum($live, flquo(flonum_from_$arg, flonum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (flremainder x y)
|
|
|
|
(%prim* "flonum($live, flrem(flonum_from_$arg, flonum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (flmodquo x y)
|
|
|
|
(%prim* "flonum($live, flmqu(flonum_from_$arg, flonum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (flmodulo x y)
|
|
|
|
(%prim* "flonum($live, flmlo(flonum_from_$arg, flonum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (flabs x)
|
|
|
|
(%prim* "flonum($live, fabs(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (flgcd x y)
|
|
|
|
(%prim* "flonum($live, flgcd(flonum_from_$arg, flonum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (flfloor x)
|
|
|
|
(%prim* "flonum($live, floor(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (flceiling x)
|
|
|
|
(%prim* "flonum($live, ceil(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (fltruncate x)
|
|
|
|
(%prim* "{ /* fltruncate */
|
|
|
|
flonum_t x = flonum_from_$arg;
|
|
|
|
double i; modf(x, &i);
|
|
|
|
$return flonum($live, i); }" x))
|
|
|
|
|
|
|
|
(define-inline (flround x)
|
|
|
|
(%prim* "flonum($live, flround(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (flsqrt x)
|
|
|
|
(%prim* "flonum($live, sqrt(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (flexp x)
|
|
|
|
(%prim* "flonum($live, exp(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (fllog x)
|
|
|
|
(%prim* "flonum($live, log(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (fllog10 x)
|
|
|
|
(%prim* "flonum($live, log10(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (flsin x)
|
|
|
|
(%prim* "flonum($live, sin(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (flcos x)
|
|
|
|
(%prim* "flonum($live, cos(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (fltan x)
|
|
|
|
(%prim* "flonum($live, tan(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (flasin x)
|
|
|
|
(%prim* "flonum($live, asin(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (flacos x)
|
|
|
|
(%prim* "flonum($live, acos(flonum_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-syntax flatan
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (%prim* "flonum($live, atan(flonum_from_$arg))" x)]
|
|
|
|
[(_ y x) (%prim* "flonum($live, atan2(flonum_from_$arg, flonum_from_$arg))" y x)]
|
|
|
|
[_ %residual-flatan]))
|
|
|
|
|
|
|
|
(define-inline (flexpt x y)
|
|
|
|
(%prim* "flonum($live, pow(flonum_from_$arg, flonum_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-inline (fxfl/ x y)
|
|
|
|
(%prim* "{ /* fxfl/ */
|
|
|
|
fixnum_t x = fixnum_from_$arg, y = fixnum_from_$arg;
|
|
|
|
long i; double d;
|
|
|
|
if (0) $return obj(0); /* to fool sfc unboxer */
|
|
|
|
else if (fxifdv(x, y, &i, &d)) $return fixnum(i);
|
|
|
|
else $return flonum($live, d); }" x y))
|
|
|
|
|
|
|
|
|
|
|
|
; generic math (fixnum/flonum)
|
|
|
|
|
|
|
|
(define-inline (real? x)
|
|
|
|
(or (fixnum? x) (flonum? x)))
|
|
|
|
|
|
|
|
(define-inline (integer? x)
|
|
|
|
(or (fixnum? x) (and (flonum? x) (flinteger? x))))
|
|
|
|
|
|
|
|
(define-syntax exact-integer? fixnum?)
|
|
|
|
|
|
|
|
(define-inline rational? integer?)
|
|
|
|
(define-inline complex? real?)
|
|
|
|
(define-inline number? real?)
|
|
|
|
|
|
|
|
(define-inline exact? fixnum?)
|
|
|
|
(define-inline inexact? flonum?)
|
|
|
|
(define-inline (exact x)
|
|
|
|
(if (fixnum? x) x (flonum->fixnum x)))
|
|
|
|
(define-inline (inexact x)
|
|
|
|
(if (flonum? x) x (fixnum->flonum x)))
|
|
|
|
(define-syntax inexact->exact exact)
|
|
|
|
(define-syntax exact->inexact inexact)
|
|
|
|
|
|
|
|
(define-syntax real-binop
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y fxop flop)
|
|
|
|
(let ([a x] [b y])
|
|
|
|
(if (fixnum? a)
|
|
|
|
(if (fixnum? b)
|
|
|
|
(fxop a b)
|
|
|
|
(flop (fixnum->flonum a) b))
|
|
|
|
(if (fixnum? b)
|
|
|
|
(flop a (fixnum->flonum b))
|
|
|
|
(flop a b))))]))
|
|
|
|
|
|
|
|
(define-syntax =
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (real-binop x y fx=? fl=?)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (= x t) (= t z ...)))]
|
|
|
|
[_ %residual=]))
|
|
|
|
|
|
|
|
(define-syntax <
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (real-binop x y fx<? fl<?)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (< x t) (< t z ...)))]
|
|
|
|
[_ %residual<]))
|
|
|
|
|
|
|
|
(define-syntax >
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (real-binop x y fx>? fl>?)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (> x t) (> t z ...)))]
|
|
|
|
[_ %residual>]))
|
|
|
|
|
|
|
|
(define-syntax <=
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (real-binop x y fx<=? fl<=?)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (<= x t) (<= t z ...)))]
|
|
|
|
[_ %residual<=]))
|
|
|
|
|
|
|
|
(define-syntax >=
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (real-binop x y fx>=? fl>=?)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (>= x t) (>= t z ...)))]
|
|
|
|
[_ %residual>=]))
|
|
|
|
|
|
|
|
(define-inline (zero? x)
|
|
|
|
(if (fixnum? x) (fxzero? x) (flzero? x)))
|
|
|
|
|
|
|
|
(define-inline (positive? x)
|
|
|
|
(if (fixnum? x) (fxpositive? x) (flpositive? x)))
|
|
|
|
|
|
|
|
(define-inline (negative? x)
|
|
|
|
(if (fixnum? x) (fxnegative? x) (flnegative? x)))
|
|
|
|
|
|
|
|
(define-inline (even? x)
|
|
|
|
(if (fixnum? x) (fxeven? x) (fleven? x)))
|
|
|
|
|
|
|
|
(define-inline (odd? x)
|
|
|
|
(if (fixnum? x) (fxodd? x) (flodd? x)))
|
|
|
|
|
|
|
|
(define-inline (nan? x)
|
|
|
|
(and (flonum? x) (flnan? x)))
|
|
|
|
|
|
|
|
(define-inline (infinite? x)
|
|
|
|
(and (flonum? x) (flinfinite? x)))
|
|
|
|
|
|
|
|
(define-inline (finite? x)
|
|
|
|
(or (fixnum? x) (not (flinfinite? x))))
|
|
|
|
|
|
|
|
(define-syntax max
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y)
|
|
|
|
(let ([a x] [b y])
|
|
|
|
(if (and (fixnum? a) (fixnum? b)) (if (fx>? a b) a b) (%residual-max/2 a b)))]
|
|
|
|
[(_ x y z ...) (%residual-max x y z ...)]
|
|
|
|
[_ %residual-max]))
|
|
|
|
|
|
|
|
(define-syntax min
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y)
|
|
|
|
(let ([a x] [b y])
|
|
|
|
(if (and (fixnum? a) (fixnum? b)) (if (fx<? a b) a b) (%residual-min/2 a b)))]
|
|
|
|
[(_ x y z ...) (%residual-min x y z ...)]
|
|
|
|
[_ %residual-min]))
|
|
|
|
|
|
|
|
(define-syntax +
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) 0]
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y) (real-binop x y fx+ fl+)]
|
|
|
|
[(_ x y z ...) (+ (+ x y) z ...)]
|
|
|
|
[_ %residual+]))
|
|
|
|
|
|
|
|
(define-syntax *
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) 1]
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y) (real-binop x y fx* fl*)]
|
|
|
|
[(_ x y z ...) (* (* x y) z ...)]
|
|
|
|
[_ %residual*]))
|
|
|
|
|
|
|
|
(define-syntax -
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (let ([a x]) (if (fixnum? a) (fx- a) (fl- a)))]
|
|
|
|
[(_ x y) (real-binop x y fx- fl-)]
|
|
|
|
[(_ x y z ...) (- (- x y) z ...)]
|
|
|
|
[_ %residual-]))
|
|
|
|
|
|
|
|
(define-syntax /
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (let ([a x]) (if (fixnum? a) (fxfl/ 1 a) (fl/ a)))]
|
|
|
|
[(_ x y) (real-binop x y fxfl/ fl/)]
|
|
|
|
[(_ x y z ...) (/ (/ x y) z ...)]
|
|
|
|
[_ %residual/]))
|
|
|
|
|
|
|
|
(define-inline (abs x)
|
|
|
|
(if (fixnum? x) (fxabs x) (flabs x)))
|
|
|
|
|
|
|
|
(define-inline (quotient x y)
|
|
|
|
(real-binop x y fxquotient flquotient))
|
|
|
|
|
|
|
|
(define-inline (remainder x y)
|
|
|
|
(real-binop x y fxremainder flremainder))
|
|
|
|
|
|
|
|
(define-syntax truncate-quotient quotient)
|
|
|
|
(define-syntax truncate-remainder remainder)
|
|
|
|
|
|
|
|
(define-inline (modquo x y)
|
|
|
|
(real-binop x y fxmodquo flmodquo))
|
|
|
|
|
|
|
|
(define-inline (modulo x y)
|
|
|
|
(real-binop x y fxmodulo flmodulo))
|
|
|
|
|
|
|
|
(define-syntax floor-quotient modquo)
|
|
|
|
(define-syntax floor-remainder modulo)
|
|
|
|
|
|
|
|
(define-syntax gcd
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) 0]
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y) (real-binop x y fxgcd flgcd)]
|
|
|
|
[(_ x y z ...) (gcd (gcd x y) z ...)]
|
|
|
|
[_ %residual-gcd]))
|
|
|
|
|
|
|
|
(define (lcm/2 x y)
|
|
|
|
(let ([g (gcd x y)])
|
|
|
|
(if (zero? g) g (* (quotient (abs x) g) (abs y)))))
|
|
|
|
|
|
|
|
(define-syntax lcm
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) 1]
|
|
|
|
[(_ x) x]
|
|
|
|
[(_ x y) (lcm/2 x y)]
|
|
|
|
[(_ x y z ...) (lcm (lcm/2 x y) z ...)]
|
|
|
|
[_ %residual-lcm]))
|
|
|
|
|
|
|
|
; no div
|
|
|
|
; no mod
|
|
|
|
|
|
|
|
(define-inline (numerator n)
|
|
|
|
n)
|
|
|
|
|
|
|
|
(define-inline (denominator n)
|
|
|
|
1)
|
|
|
|
|
|
|
|
(define-inline (rationalize n d)
|
|
|
|
n)
|
|
|
|
|
|
|
|
(define-inline (floor x)
|
|
|
|
(if (fixnum? x) x (flfloor x)))
|
|
|
|
|
|
|
|
(define-inline (ceiling x)
|
|
|
|
(if (fixnum? x) x (flceiling x)))
|
|
|
|
|
|
|
|
(define-inline (truncate x)
|
|
|
|
(if (fixnum? x) x (fltruncate x)))
|
|
|
|
|
|
|
|
(define-inline (round x)
|
|
|
|
(if (fixnum? x) x (flround x)))
|
|
|
|
|
|
|
|
; need exact version?
|
|
|
|
(define-inline (sqrt x)
|
|
|
|
(flsqrt (real->flonum x)))
|
|
|
|
|
|
|
|
(define-inline (exp x)
|
|
|
|
(flexp (real->flonum x)))
|
|
|
|
|
|
|
|
(define-syntax log
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (fllog (real->flonum x))]
|
|
|
|
[(_ x b) (if (fx=? b 10) (fllog10 (real->flonum x)) (fl/ (log x) (log b)))]
|
|
|
|
[_ %residual-log]))
|
|
|
|
|
|
|
|
(define-inline (sin x)
|
|
|
|
(flsin (real->flonum x)))
|
|
|
|
|
|
|
|
(define-inline (cos x)
|
|
|
|
(flcos (real->flonum x)))
|
|
|
|
|
|
|
|
(define-inline (tan x)
|
|
|
|
(fltan (real->flonum x)))
|
|
|
|
|
|
|
|
(define-inline (asin x)
|
|
|
|
(flasin (real->flonum x)))
|
|
|
|
|
|
|
|
(define-inline (acos x)
|
|
|
|
(flacos (real->flonum x)))
|
|
|
|
|
|
|
|
(define-syntax atan
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (flatan (real->flonum x))]
|
|
|
|
[(_ y x) (flatan (real->flonum y) (real->flonum x))]
|
|
|
|
[_ %residual-atan]))
|
|
|
|
|
|
|
|
(define-inline (expt x y)
|
|
|
|
(if (and (fixnum? x) (fixnum? y) (fx>=? y 0))
|
|
|
|
(fxexpt x y)
|
|
|
|
(flexpt (real->flonum x) (real->flonum y))))
|
|
|
|
|
|
|
|
(define-inline (square x) (* x x))
|
|
|
|
|
|
|
|
|
|
|
|
; characters
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (char)
|
|
|
|
[(_ char 8 c) (%prim ("char(" c ")"))]
|
|
|
|
[(_ char cs) (%prim ("char('" cs "')"))]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (char? x)
|
|
|
|
(%prim "bool(is_char_$arg)" x))
|
|
|
|
|
|
|
|
(define-syntax char=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(char_from_$arg == char_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char=? x t) (char=? t z ...)))]
|
|
|
|
[_ %residual-char=?]))
|
|
|
|
|
|
|
|
(define-syntax char>?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(char_from_$arg > char_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char>? x t) (char>? t z ...)))]
|
|
|
|
[_ %residual-char>?]))
|
|
|
|
|
|
|
|
(define-syntax char<?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(char_from_$arg < char_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char<? x t) (char<? t z ...)))]
|
|
|
|
[_ %residual-char<?]))
|
|
|
|
|
|
|
|
(define-syntax char>=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(char_from_$arg >= char_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char>=? x t) (char>=? t z ...)))]
|
|
|
|
[_ %residual-char>=?]))
|
|
|
|
|
|
|
|
(define-syntax char<=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(char_from_$arg <= char_from_$arg)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char<=? x t) (char<=? t z ...)))]
|
|
|
|
[_ %residual-char<=?]))
|
|
|
|
|
|
|
|
(define-syntax char-ci=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(tolower(char_from_$arg) == tolower(char_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char-ci=? x t) (char-ci=? t z ...)))]
|
|
|
|
[_ %residual-char-ci=?]))
|
|
|
|
|
|
|
|
(define-syntax char-ci>?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(tolower(char_from_$arg) > tolower(char_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char-ci>? x t) (char-ci>? t z ...)))]
|
|
|
|
[_ %residual-char-ci>?]))
|
|
|
|
|
|
|
|
(define-syntax char-ci<?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(tolower(char_from_$arg) < tolower(char_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char-ci<? x t) (char-ci<? t z ...)))]
|
|
|
|
[_ %residual-char-ci<?]))
|
|
|
|
|
|
|
|
(define-syntax char-ci>=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(tolower(char_from_$arg) >= tolower(char_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char-ci>=? x t) (char-ci>=? t z ...)))]
|
|
|
|
[_ %residual-char-ci>=?]))
|
|
|
|
|
|
|
|
(define-syntax char-ci<=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(tolower(char_from_$arg) <= tolower(char_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (char-ci<=? x t) (char-ci<=? t z ...)))]
|
|
|
|
[_ %residual-char-ci<=?]))
|
|
|
|
|
|
|
|
(define-inline (char-alphabetic? x)
|
|
|
|
(%prim "bool(isalpha(char_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (char-numeric? x)
|
|
|
|
(%prim "bool(isdigit(char_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (char-whitespace? x)
|
|
|
|
(%prim "bool(isspace(char_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (char-upper-case? x)
|
|
|
|
(%prim "bool(isupper(char_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (char-lower-case? x)
|
|
|
|
(%prim "bool(islower(char_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (char->integer x)
|
|
|
|
(%prim "fixnum((fixnum_t)char_from_$arg)" x))
|
|
|
|
|
|
|
|
(define-inline (integer->char x)
|
|
|
|
(%prim "char((char_t)fixnum_from_$arg)" x))
|
|
|
|
|
|
|
|
(define-inline (char-upcase x)
|
|
|
|
(%prim "char(toupper(char_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (char-downcase x)
|
|
|
|
(%prim "char(tolower(char_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-syntax char-foldcase char-downcase)
|
|
|
|
|
|
|
|
(define-inline (digit-value x)
|
|
|
|
(and (char<=? #\0 x #\9) (fx- (char->integer x) (%prim "fixnum('0')"))))
|
|
|
|
|
|
|
|
|
|
|
|
; strings
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (string)
|
|
|
|
[(_ string s)
|
|
|
|
(%prim* ("obj(hpushstr($live, newstring(\"" s "\")))"))]
|
|
|
|
[(_ string 8 c ...)
|
|
|
|
(%prim* ("{ static char s[] = { " (c ", ") ... "0 };\n"
|
|
|
|
" $return obj(hpushstr($live, newstring(s))); }"))]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (string? x)
|
|
|
|
(%prim "bool(isstring(obj_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-syntax make-string
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ k) (%prim* "obj(hpushstr($live, allocstring(fixnum_from_$arg, '?')))" k)]
|
|
|
|
[(_ k c) (%prim* "obj(hpushstr($live, allocstring(fixnum_from_$arg, char_from_$arg)))" k c)]
|
|
|
|
[_ %residual-make-string]))
|
|
|
|
|
|
|
|
(define-syntax string
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ c ...)
|
|
|
|
(%prim* "{ /* string */
|
|
|
|
obj o = hpushstr($live, allocstring($argc, ' '));
|
|
|
|
unsigned char *s = (unsigned char *)stringchars(o);
|
|
|
|
${*s++ = (unsigned char)char_from_$arg;
|
|
|
|
$}$return obj(o); }" c ...)]
|
|
|
|
[_ %residual-string]))
|
|
|
|
|
|
|
|
(define-inline (string-length s)
|
|
|
|
(%prim "fixnum(stringlen(obj_from_$arg))" s))
|
|
|
|
|
|
|
|
(define-inline (string-ref s k)
|
|
|
|
(%prim? "char(*(unsigned char*)stringref(obj_from_$arg, fixnum_from_$arg))" s k))
|
|
|
|
|
|
|
|
(define-inline (string-set! s k c)
|
|
|
|
(%prim! "void(*stringref(obj_from_$arg, fixnum_from_$arg) = char_from_$arg)" s k c))
|
|
|
|
|
|
|
|
(define-syntax string=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) == 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string=? x t) (string=? t z ...)))]
|
|
|
|
[_ %residual-string=?]))
|
|
|
|
|
|
|
|
(define-syntax string<?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) < 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string<? x t) (string<? t z ...)))]
|
|
|
|
[_ %residual-string<?]))
|
|
|
|
|
|
|
|
(define-syntax string>?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) > 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string>? x t) (string>? t z ...)))]
|
|
|
|
[_ %residual-string>?]))
|
|
|
|
|
|
|
|
(define-syntax string<=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) <= 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string<=? x t) (string<=? t z ...)))]
|
|
|
|
[_ %residual-string<=?]))
|
|
|
|
|
|
|
|
(define-syntax string>=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) >= 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string>=? x t) (string>=? t z ...)))]
|
|
|
|
[_ %residual-string>=?]))
|
|
|
|
|
|
|
|
(define-syntax string-ci=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp_ci(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) == 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string-ci=? x t) (string-ci=? t z ...)))]
|
|
|
|
[_ %residual-string-ci=?]))
|
|
|
|
|
|
|
|
(define-syntax string-ci<?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp_ci(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) < 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string-ci<? x t) (string-ci<? t z ...)))]
|
|
|
|
[_ %residual-string-ci<?]))
|
|
|
|
|
|
|
|
(define-syntax string-ci>?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp_ci(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) > 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string-ci>? x t) (string-ci>? t z ...)))]
|
|
|
|
[_ %residual-string-ci>?]))
|
|
|
|
|
|
|
|
(define-syntax string-ci<=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp_ci(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) <= 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string-ci<=? x t) (string-ci<=? t z ...)))]
|
|
|
|
[_ %residual-string-ci<=?]))
|
|
|
|
|
|
|
|
(define-syntax string-ci>=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim? "bool(strcmp_ci(stringchars(obj_from_$arg), stringchars(obj_from_$arg)) >= 0)" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (string-ci>=? x t) (string-ci>=? t z ...)))]
|
|
|
|
[_ %residual-string-ci>=?]))
|
|
|
|
|
|
|
|
(define-inline (string-upcase s)
|
|
|
|
(%prim*? "{ /* string-upcase */
|
|
|
|
int *d = dupstring(stringdata(obj_from_$arg)); char *s;
|
|
|
|
for (s = sdatachars(d); *s; ++s) *s = toupper(*s);
|
|
|
|
$return obj(hpushstr($live, d)); }" s))
|
|
|
|
|
|
|
|
(define-inline (string-downcase s)
|
|
|
|
(%prim*? "{ /* string-downcase */
|
|
|
|
int *d = dupstring(stringdata(obj_from_$arg)); char *s;
|
|
|
|
for (s = sdatachars(d); *s; ++s) *s = tolower(*s);
|
|
|
|
$return obj(hpushstr($live, d)); }" s))
|
|
|
|
|
|
|
|
(define-syntax string-foldcase string-downcase)
|
|
|
|
|
|
|
|
(define-inline (substring s start end)
|
|
|
|
(%prim*? "{ /* substring */
|
|
|
|
int *d = substring(stringdata(obj_from_$arg), fixnum_from_$arg, fixnum_from_$arg);
|
|
|
|
$return obj(hpushstr($live, d)); }" s start end))
|
|
|
|
|
|
|
|
(define-inline (%string-append s1 s2)
|
|
|
|
(%prim*? "{ /* string-append */
|
|
|
|
int *d = stringcat(stringdata(obj_from_$arg), stringdata(obj_from_$arg));
|
|
|
|
$return obj(hpushstr($live, d)); }" s1 s2))
|
|
|
|
|
|
|
|
(define-syntax string-append
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) ""] [(_ x) x]
|
|
|
|
[(_ x y) (%string-append x y)]
|
|
|
|
[(_ x y z ...) (%string-append x (string-append y z ...))]
|
|
|
|
[_ %residual-string-append]))
|
|
|
|
|
|
|
|
(define-inline (%string-copy s)
|
|
|
|
(%prim*? "{ /* string-copy */
|
|
|
|
int *d = dupstring(stringdata(obj_from_$arg));
|
|
|
|
$return obj(hpushstr($live, d)); }" s))
|
|
|
|
|
|
|
|
(define (substring-copy! to at from start end)
|
|
|
|
(let ([limit (fxmin end (fx+ start (fx- (string-length to) at)))])
|
|
|
|
(if (fx<=? at start)
|
|
|
|
(do ([i at (fx+ i 1)] [j start (fx+ j 1)])
|
|
|
|
[(fx>=? j limit)]
|
|
|
|
(string-set! to i (string-ref from j)))
|
|
|
|
(do ([i (fx+ at (fx- end start 1)) (fx- i 1)] [j (fx- limit 1) (fx- j 1)])
|
|
|
|
[(fx<? j start)]
|
|
|
|
(string-set! to i (string-ref from j))))))
|
|
|
|
|
|
|
|
(define (substring-fill! str c start end)
|
|
|
|
(do ([i start (fx+ i 1)]) [(fx>=? i end)] (string-set! str i c)))
|
|
|
|
|
|
|
|
(define-inline (%string-fill! s c)
|
|
|
|
(%prim! "void(stringfill(stringdata(obj_from_$arg), char_from_$arg))" s c))
|
|
|
|
|
|
|
|
(define-inline (string-position c s)
|
|
|
|
(%prim? "{ /* string-position */
|
|
|
|
char *s = stringchars(obj_from_$arg), *p = strchr(s, char_from_$arg);
|
|
|
|
if (p) $return fixnum(p-s); else $return bool(0); }" s c))
|
|
|
|
|
|
|
|
|
|
|
|
; vectors
|
|
|
|
|
|
|
|
(define-inline (vector? o)
|
|
|
|
(%prim "bool(isvector(obj_from_$arg))" o))
|
|
|
|
|
|
|
|
(define-inline (%new-vector n)
|
|
|
|
(%prim* "{ /* new-vector */
|
|
|
|
int c = fixnum_from_$arg;
|
|
|
|
hreserve(hbsz(c+1), $live); /* $live live regs */
|
|
|
|
hp -= c; memset(hp, 0, c * sizeof(obj));
|
|
|
|
*--hp = obj_from_size(VECTOR_BTAG);
|
|
|
|
$return obj(hendblk(c+1)); }" n))
|
|
|
|
|
|
|
|
(define-inline (%make-vector n i)
|
|
|
|
(%prim* "{ /* make-vector */
|
|
|
|
obj o; int i = 0, c = fixnum_from_$arg;
|
|
|
|
hreserve(hbsz(c+1), $live); /* $live live regs */
|
|
|
|
o = obj_from_$arg; /* gc-safe */
|
|
|
|
while (i++ < c) *--hp = o;
|
|
|
|
*--hp = obj_from_size(VECTOR_BTAG);
|
|
|
|
$return obj(hendblk(c+1)); }" n i))
|
|
|
|
|
|
|
|
(define-syntax make-vector
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ n) (%new-vector n)]
|
|
|
|
[(_ n i) (%make-vector n i)]
|
|
|
|
[_ %residual-make-vector]))
|
|
|
|
|
|
|
|
(define-syntax vector
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ i ...)
|
|
|
|
(%prim*/rev "{ /* vector */
|
|
|
|
hreserve(hbsz($argc+1), $live); /* $live live regs */
|
|
|
|
${*--hp = obj_from_$arg;
|
|
|
|
$}*--hp = obj_from_size(VECTOR_BTAG);
|
|
|
|
$return obj(hendblk($argc+1)); }" i ...)]
|
|
|
|
[_ %residual-vector]))
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (vector)
|
|
|
|
[(_ vector x ...) (vector x ...)]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (vector-length v)
|
|
|
|
(%prim "fixnum(vectorlen(obj_from_$arg))" v))
|
|
|
|
|
|
|
|
(define-inline (vector-ref v i)
|
|
|
|
(%prim? "obj(vectorref(obj_from_$arg, fixnum_from_$arg))" v i))
|
|
|
|
|
|
|
|
(define-inline (vector-set! v i x)
|
|
|
|
(%prim! "void(vectorref(obj_from_$arg, fixnum_from_$arg) = obj_from_$arg)" v i x))
|
|
|
|
|
|
|
|
(define (subvector-copy! to at from start end)
|
|
|
|
(let ([limit (fxmin end (fx+ start (fx- (vector-length to) at)))])
|
|
|
|
(if (fx<=? at start)
|
|
|
|
(do ([i at (fx+ i 1)] [j start (fx+ j 1)])
|
|
|
|
[(fx>=? j limit)]
|
|
|
|
(vector-set! to i (vector-ref from j)))
|
|
|
|
(do ([i (fx+ at (fx- end start 1)) (fx- i 1)] [j (fx- limit 1) (fx- j 1)])
|
|
|
|
[(fx<? j start)]
|
|
|
|
(vector-set! to i (vector-ref from j))))))
|
|
|
|
|
|
|
|
(define (subvector vec start end)
|
|
|
|
(let ([v (make-vector (fx- end start))])
|
|
|
|
(subvector-copy! v 0 vec start end)
|
|
|
|
v))
|
|
|
|
|
|
|
|
(define (subvector-fill! vec x start end)
|
|
|
|
(do ([i start (fx+ i 1)]) [(fx>=? i end)] (vector-set! vec i x)))
|
|
|
|
|
|
|
|
|
|
|
|
; bytevectors
|
|
|
|
|
|
|
|
#read #u8<list> as (%const bytevector <list>)
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (bytevector)
|
|
|
|
[(_ bytevector (x ...)) (bytevector x ...)]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (byte? x)
|
|
|
|
(%prim "bool(is_byte_obj(obj_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (bytevector? x)
|
|
|
|
(%prim "bool(isbytevector(obj_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-syntax make-bytevector
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ k) (%prim* "obj(hpushu8v($live, allocbytevector(fixnum_from_$arg)))" k)]
|
|
|
|
[(_ k c) (%prim* "obj(hpushu8v($live, makebytevector(fixnum_from_$arg, byte_from_fixnum(fixnum_from_$arg))))" k c)]
|
|
|
|
[_ %residual-make-bytevector]))
|
|
|
|
|
|
|
|
(define-syntax bytevector
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ b ...)
|
|
|
|
(%prim* "{ /* bytevector */
|
|
|
|
obj o = hpushu8v($live, allocbytevector($argc));
|
|
|
|
unsigned char *s = bytevectorbytes(o);
|
|
|
|
${*s++ = byte_from_fixnum(fixnum_from_$arg);
|
|
|
|
$}$return obj(o); }" b ...)]
|
|
|
|
[_ %residual-bytevector]))
|
|
|
|
|
|
|
|
(define-inline (bytevector-length bv)
|
|
|
|
(%prim "fixnum(bytevectorlen(obj_from_$arg))" bv))
|
|
|
|
|
|
|
|
(define-inline (bytevector-u8-ref bv k)
|
|
|
|
(%prim? "fixnum(*bytevectorref(obj_from_$arg, fixnum_from_$arg))" bv k))
|
|
|
|
|
|
|
|
(define-inline (bytevector-u8-set! bv k b)
|
|
|
|
(%prim! "void(*bytevectorref(obj_from_$arg, fixnum_from_$arg) = byte_from_fixnum(fixnum_from_$arg))" bv k b))
|
|
|
|
|
|
|
|
(define-inline (bytevector=? x y)
|
|
|
|
(%prim? "bool(bytevectoreq(bytevectordata(obj_from_$arg), bytevectordata(obj_from_$arg)))" x y))
|
|
|
|
|
|
|
|
(define (subbytevector-copy! to at from start end)
|
|
|
|
(let ([limit (fxmin end (fx+ start (fx- (bytevector-length to) at)))])
|
|
|
|
(if (fx<=? at start)
|
|
|
|
(do ([i at (fx+ i 1)] [j start (fx+ j 1)])
|
|
|
|
[(fx>=? j limit)]
|
|
|
|
(bytevector-u8-set! to i (bytevector-u8-ref from j)))
|
|
|
|
(do ([i (fx+ at (fx- end start 1)) (fx- i 1)] [j (fx- limit 1) (fx- j 1)])
|
|
|
|
[(fx<? j start)]
|
|
|
|
(bytevector-u8-set! to i (bytevector-u8-ref from j))))))
|
|
|
|
|
|
|
|
(define-inline (subbytevector bv start end)
|
|
|
|
(%prim*? "{ /* subbytevector */
|
|
|
|
int *d = subbytevector(bytevectordata(obj_from_$arg), fixnum_from_$arg, fixnum_from_$arg);
|
|
|
|
$return obj(hpushu8v($live, d)); }" bv start end))
|
|
|
|
|
|
|
|
|
|
|
|
; boxes
|
|
|
|
|
|
|
|
(define-inline (box? o)
|
|
|
|
(%prim "bool(isbox(obj_from_$arg))" o))
|
|
|
|
|
|
|
|
(define-inline (box o)
|
|
|
|
(%prim* "{ /* box */
|
|
|
|
hreserve(hbsz(2), $live); /* $live live regs */
|
|
|
|
*--hp = obj_from_$arg;
|
|
|
|
*--hp = obj_from_size(BOX_BTAG);
|
|
|
|
$return obj(hendblk(2)); }" o))
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (box)
|
|
|
|
[(_ box x) (box x)]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (unbox b)
|
|
|
|
(%prim? "obj(boxref(obj_from_$arg))" b))
|
|
|
|
|
|
|
|
(define-inline (set-box! b o)
|
|
|
|
(%prim! "void(boxref(obj_from_$arg) = obj_from_$arg)" b o))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; null
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (null)
|
|
|
|
[(_ null) (%prim "obj(mknull())")]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (null? x)
|
|
|
|
(%prim "bool(isnull(obj_from_$arg))" x))
|
|
|
|
|
|
|
|
|
|
|
|
; pairs and lists
|
|
|
|
|
|
|
|
(define-inline (pair? o)
|
|
|
|
(%prim "bool(ispair(obj_from_$arg))" o))
|
|
|
|
|
|
|
|
(define-inline (atom? o)
|
|
|
|
(%prim "bool(!ispair(obj_from_$arg))" o))
|
|
|
|
|
|
|
|
(define-inline (list? o)
|
|
|
|
(%prim? "bool(islist(obj_from_$arg))" o))
|
|
|
|
|
|
|
|
(define-inline (cons a d)
|
|
|
|
(%prim* "{ /* cons */
|
|
|
|
hreserve(hbsz(3), $live); /* $live live regs */
|
|
|
|
*--hp = obj_from_$arg;
|
|
|
|
*--hp = obj_from_$arg;
|
|
|
|
*--hp = obj_from_size(PAIR_BTAG);
|
|
|
|
$return obj(hendblk(3)); }" d a))
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (pair list)
|
|
|
|
[(_ pair x y) (cons x y)]
|
|
|
|
[(_ list x ...) (list x ...)]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (car p)
|
|
|
|
(%prim? "obj(car(obj_from_$arg))" p))
|
|
|
|
|
|
|
|
(define-inline (set-car! p a)
|
|
|
|
(%prim! "void(car(obj_from_$arg) = obj_from_$arg)" p a))
|
|
|
|
|
|
|
|
(define-inline (cdr p)
|
|
|
|
(%prim? "obj(cdr(obj_from_$arg))" p))
|
|
|
|
|
|
|
|
(define-inline (set-cdr! p d)
|
|
|
|
(%prim! "void(cdr(obj_from_$arg) = obj_from_$arg)" p d))
|
|
|
|
|
|
|
|
(define-syntax c?r
|
|
|
|
(syntax-rules (a d)
|
|
|
|
[(c?r x) x]
|
|
|
|
[(c?r a ? ... x) (car (c?r ? ... x))]
|
|
|
|
[(c?r d ? ... x) (cdr (c?r ? ... x))]))
|
|
|
|
|
|
|
|
(define-inline (caar x) (c?r a a x))
|
|
|
|
(define-inline (cadr x) (c?r a d x))
|
|
|
|
(define-inline (cdar x) (c?r d a x))
|
|
|
|
(define-inline (cddr x) (c?r d d x))
|
|
|
|
(define-inline (caaar x) (c?r a a a x))
|
|
|
|
(define-inline (caadr x) (c?r a a d x))
|
|
|
|
(define-inline (cadar x) (c?r a d a x))
|
|
|
|
(define-inline (caddr x) (c?r a d d x))
|
|
|
|
(define-inline (cdaar x) (c?r d a a x))
|
|
|
|
(define-inline (cdadr x) (c?r d a d x))
|
|
|
|
(define-inline (cddar x) (c?r d d a x))
|
|
|
|
(define-inline (cdddr x) (c?r d d d x))
|
|
|
|
(define-inline (caaaar x) (c?r a a a a x))
|
|
|
|
(define-inline (caaadr x) (c?r a a a d x))
|
|
|
|
(define-inline (caadar x) (c?r a a d a x))
|
|
|
|
(define-inline (caaddr x) (c?r a a d d x))
|
|
|
|
(define-inline (cadaar x) (c?r a d a a x))
|
|
|
|
(define-inline (cadadr x) (c?r a d a d x))
|
|
|
|
(define-inline (caddar x) (c?r a d d a x))
|
|
|
|
(define-inline (cadddr x) (c?r a d d d x))
|
|
|
|
(define-inline (cdaaar x) (c?r d a a a x))
|
|
|
|
(define-inline (cdaadr x) (c?r d a a d x))
|
|
|
|
(define-inline (cdadar x) (c?r d a d a x))
|
|
|
|
(define-inline (cdaddr x) (c?r d a d d x))
|
|
|
|
(define-inline (cddaar x) (c?r d d a a x))
|
|
|
|
(define-inline (cddadr x) (c?r d d a d x))
|
|
|
|
(define-inline (cdddar x) (c?r d d d a x))
|
|
|
|
(define-inline (cddddr x) (c?r d d d d x))
|
|
|
|
|
|
|
|
(define (%make-list n i)
|
|
|
|
(let loop ([n n] [l '()])
|
|
|
|
(if (<= n 0) l (loop (- n 1) (cons i l)))))
|
|
|
|
|
|
|
|
(define-syntax make-list
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ n) (%make-list n (void))]
|
|
|
|
[(_ n i) (%make-list n i)]
|
|
|
|
[_ %residual-make-list]))
|
|
|
|
|
|
|
|
(define-syntax list
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) '()]
|
|
|
|
[(_ x . more) (cons x (list . more))]
|
|
|
|
[_ %residual-list]))
|
|
|
|
|
|
|
|
(define-syntax cons*
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ i ... j)
|
|
|
|
(%prim*/rev "{ /* cons* */
|
|
|
|
obj p;
|
|
|
|
hreserve(hbsz(3)*$argc, $live); /* $live live regs */
|
|
|
|
p = obj_from_$arg; /* gc-safe */
|
|
|
|
${*--hp = p; *--hp = obj_from_$arg;
|
|
|
|
*--hp = obj_from_size(PAIR_BTAG); p = hendblk(3);
|
|
|
|
$}$return obj(p); }" i ... j)]
|
|
|
|
[_ %residual-cons*]))
|
|
|
|
|
|
|
|
(define-syntax list* cons*)
|
|
|
|
|
|
|
|
(define-inline (length l)
|
|
|
|
(%prim? "{ /* length */
|
|
|
|
int n; obj l = obj_from_$arg;
|
|
|
|
for (n = 0; l != mknull(); ++n, l = cdr(l)) ;
|
|
|
|
$return fixnum(n); }" l))
|
|
|
|
|
|
|
|
(define-inline (reverse l)
|
|
|
|
(%prim*? "{ /* reverse */
|
|
|
|
obj l, o = mknull(); int c = fixnum_from_$arg;
|
|
|
|
hreserve(hbsz(3)*c, $live); /* $live live regs */
|
|
|
|
l = obj_from_$arg; /* gc-safe */
|
|
|
|
for (; l != mknull(); l = cdr(l)) { *--hp = o; *--hp = car(l);
|
|
|
|
*--hp = obj_from_size(PAIR_BTAG); o = hendblk(3); }
|
|
|
|
$return obj(o); }" (length l) l))
|
|
|
|
|
|
|
|
(define-inline (reverse! l)
|
|
|
|
(%prim?! "{ /* reverse! */
|
|
|
|
obj t, v = mknull(), l = obj_from_$arg;
|
|
|
|
while (l != mknull()) t = cdr(l), cdr(l) = v, v = l, l = t;
|
|
|
|
$return obj(v); }" l))
|
|
|
|
|
|
|
|
(define (%append l o)
|
|
|
|
(%prim*? "{ /* append */
|
|
|
|
obj t, l, o, *p, *d; int c = fixnum_from_$arg;
|
|
|
|
hreserve(hbsz(3)*c, $live); /* $live live regs */
|
|
|
|
l = obj_from_$arg; t = obj_from_$arg; /* gc-safe */
|
|
|
|
o = t; p = &o;
|
|
|
|
for (; l != mknull(); l = cdr(l)) {
|
|
|
|
*--hp = t; d = hp; *--hp = car(l);
|
|
|
|
*--hp = obj_from_size(PAIR_BTAG);
|
|
|
|
*p = hendblk(3); p = d; }
|
|
|
|
$return obj(o); }" (length l) l o))
|
|
|
|
|
|
|
|
(define-syntax append
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) '()] [(_ x) x]
|
|
|
|
[(_ x y) (%append x y)]
|
|
|
|
[(_ x y z ...) (%append x (append y z ...))]
|
|
|
|
[_ %residual-append]))
|
|
|
|
|
|
|
|
(define (list-copy obj)
|
|
|
|
(if (pair? obj)
|
|
|
|
(cons (car obj) (list-copy (cdr obj)))
|
|
|
|
obj))
|
|
|
|
|
|
|
|
(define-inline (list-ref l n)
|
|
|
|
(%prim? "{ /* list-ref */
|
|
|
|
obj l = obj_from_$arg; int c = fixnum_from_$arg;
|
|
|
|
while (c-- > 0) l = cdr(l);
|
|
|
|
$return obj(car(l)); }" l n))
|
|
|
|
|
|
|
|
(define-inline (list-tail l n)
|
|
|
|
(%prim? "{ /* list-tail */
|
|
|
|
obj l = obj_from_$arg; int c = fixnum_from_$arg;
|
|
|
|
while (c-- > 0) l = cdr(l);
|
|
|
|
$return obj(l); }" l n))
|
|
|
|
|
|
|
|
(define-inline (list-set! l n obj)
|
|
|
|
(set-car! (list-tail list n) obj))
|
|
|
|
|
|
|
|
(define-inline (last-pair l)
|
|
|
|
(%prim? "{ /* last-pair */
|
|
|
|
obj l = obj_from_$arg, p;
|
|
|
|
for (p = cdr(l); ispair(p); p = cdr(p)) l = p;
|
|
|
|
$return obj(l); }" l))
|
|
|
|
|
|
|
|
(define-syntax map
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ fun lst)
|
|
|
|
(let ([f fun])
|
|
|
|
(let loop ([l lst])
|
|
|
|
(if (pair? l) (cons (f (car l)) (loop (cdr l))) '())))]
|
|
|
|
[(_ fun lst . l*) (%residual-map fun lst . l*)]
|
|
|
|
[_ %residual-map]))
|
|
|
|
|
|
|
|
(define-syntax for-each
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ fun lst)
|
|
|
|
(let ([f fun])
|
|
|
|
(let loop ([l lst])
|
|
|
|
(if (pair? l) (begin (f (car l)) (loop (cdr l))))))]
|
|
|
|
[(_ fun lst . l*) (%residual-for-each fun lst . l*)]
|
|
|
|
[_ %residual-for-each]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; symbols
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (symbol)
|
|
|
|
; wrap code in #() to force constant lifting
|
|
|
|
[(_ symbol s)
|
|
|
|
(%prim #("obj(mksymbol(internsym(\"" s "\")))"))]
|
|
|
|
[(_ symbol 8 c ...)
|
|
|
|
(%prim #("{ static obj o = 0; static char s[] = { " (c ", ") ... "0 };\n"
|
|
|
|
" $return obj(o ? o : (o = mksymbol(internsym(s)))); }"))]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (symbol? x)
|
|
|
|
(%prim "bool(issymbol(obj_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-syntax symbol=?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x y) (%prim "bool(getsymbol(obj_from_$arg) == getsymbol(obj_from_$arg))" x y)]
|
|
|
|
[(_ x y z ...) (let ([t y]) (and (symbol=? x t) (symbol=? t z ...)))]
|
|
|
|
[_ %residual-symbol=?]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; records
|
|
|
|
|
|
|
|
(define-syntax record?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ o) (%prim "bool(isrecord(obj_from_$arg))" o)]
|
|
|
|
[(_ o t) (%prim "{ /* record? */
|
|
|
|
obj o = obj_from_$arg, t = obj_from_$arg;
|
|
|
|
if (!isrecord(o)) $return bool(0);
|
|
|
|
else $return bool(recordrtd(o) == t); }" o t)]
|
|
|
|
[_ %residual-record?]))
|
|
|
|
|
|
|
|
(define-inline (make-record rtd n)
|
|
|
|
(%prim* "{ /* make-record */
|
|
|
|
int c = fixnum_from_$arg;
|
|
|
|
hreserve(hbsz(c+1), $live); /* $live live regs */
|
|
|
|
hp -= c; memset(hp, 0, c * sizeof(obj));
|
|
|
|
*--hp = obj_from_$arg; assert(isobjptr(*hp));
|
|
|
|
$return obj(hendblk(c+1)); }" n rtd))
|
|
|
|
|
|
|
|
(define-inline (record-type-descriptor r)
|
|
|
|
(%prim "obj(recordrtd(obj_from_$arg))" r))
|
|
|
|
|
|
|
|
(define-inline (record-length r)
|
|
|
|
(%prim "fixnum(recordlen(obj_from_$arg))" r))
|
|
|
|
|
|
|
|
(define-inline (record-ref r i)
|
|
|
|
(%prim? "obj(recordref(obj_from_$arg, fixnum_from_$arg))" r i))
|
|
|
|
|
|
|
|
(define-inline (record-set! r i x)
|
|
|
|
(%prim! "void(recordref(obj_from_$arg, fixnum_from_$arg) = obj_from_$arg)" r i x))
|
|
|
|
|
|
|
|
(define-inline (new-record-type name fields) ; stub
|
|
|
|
(cons name fields))
|
|
|
|
|
|
|
|
; works on top and locally, but field names cannot be hygienically generated on top level
|
|
|
|
(define-syntax define-record-type
|
|
|
|
(letrec-syntax
|
|
|
|
([id-eq?? ; see http://okmij.org/ftp/Scheme/macro-symbol-p.txt
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ id b kt kf)
|
|
|
|
((syntax-lambda (id ok) ((syntax-rules () [(_ b) (id)]) ok))
|
|
|
|
(syntax-rules () [(_) kf]) (syntax-rules () [(_) kt]))])]
|
|
|
|
[id-assq??
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ id () kt kf) kf]
|
|
|
|
[(_ id ([id0 . r0] . idr*) kt kf) (id-eq?? id id0 (kt . r0) (id-assq?? id idr* kt kf))])]
|
|
|
|
[init
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ r () fi* (x ...)) (begin x ... r)]
|
|
|
|
[(_ r (id0 . id*) fi* (x ...))
|
|
|
|
(id-assq?? id0 fi*
|
|
|
|
(syntax-rules () [(_ i0) (init r id* fi* (x ... (record-set! r i0 id0)))])
|
|
|
|
(syntax-error "id in define-record-type constructor is not a field:" id0))])]
|
|
|
|
[unroll
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ rtn (consn id ...) predn () ([f i] ...) ([a ia] ...) ([m im] ...))
|
|
|
|
(begin
|
|
|
|
(define rtn (new-record-type 'rtn '(f ...)))
|
|
|
|
(define consn (lambda (id ...) (let ([r (make-record rtn #&(length (f ...)))]) (init r (id ...) ([f i] ...) ()))))
|
|
|
|
(define predn (lambda (obj) (record? obj rtn)))
|
|
|
|
(define a (lambda (obj) (record-ref obj ia))) ...
|
|
|
|
(define m (lambda (obj val) (record-set! obj im val))) ...)]
|
|
|
|
[(_ rtn cf* predn ([fn accn] fam ...) (fi ...) (ai ...) (mi ...))
|
|
|
|
(unroll rtn cf* predn (fam ...)
|
|
|
|
(fi ... [fn #&(length (fi ...))]) (ai ... [accn #&(length (fi ...))]) (mi ...))]
|
|
|
|
[(_ rtn cf* predn ([fn accn modn] fam ...) (fi ...) (ai ...) (mi ...))
|
|
|
|
(unroll rtn cf* predn (fam ...)
|
|
|
|
(fi ... [fn #&(length (fi ...))]) (ai ... [accn #&(length (fi ...))]) (mi ... [modn #&(length (fi ...))]))])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ rtn (consn id ...) predn (fn . am) ...)
|
|
|
|
(unroll rtn (consn id ...) predn ((fn . am) ...) () () ())])))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; conversions
|
|
|
|
|
|
|
|
(define-inline (symbol->string s)
|
|
|
|
(%prim* "obj(hpushstr($live, newstring(symbolname(getsymbol(obj_from_$arg)))))" s))
|
|
|
|
|
|
|
|
(define-inline (string->symbol s)
|
|
|
|
(%prim? "obj(mksymbol(internsym(stringchars(obj_from_$arg))))" s))
|
|
|
|
|
|
|
|
(define (fixnum->string n r)
|
|
|
|
(%prim* "{ /* fixnum->string */
|
|
|
|
char buf[35], *s = buf + sizeof(buf) - 1;
|
|
|
|
int neg = 0;
|
|
|
|
long num = fixnum_from_$arg;
|
|
|
|
long radix = fixnum_from_$arg;
|
|
|
|
if (num < 0) { neg = 1; num = -num; }
|
|
|
|
*s = 0;
|
|
|
|
do { int d = num % radix; *--s = d < 10 ? d + '0' : d - 10 + 'a'; }
|
|
|
|
while (num /= radix);
|
|
|
|
if (neg) *--s = '-';
|
|
|
|
$return obj(hpushstr($live, newstring(s))); }" n r))
|
|
|
|
|
|
|
|
(define (flonum->string x)
|
|
|
|
(%prim* "{ /* flonum->string */
|
|
|
|
char buf[30], *s; double d = flonum_from_$arg; sprintf(buf, \"%.15g\", d);
|
|
|
|
for (s = buf; *s != 0; s++) if (strchr(\".eE\", *s)) break;
|
|
|
|
if (d != d) strcpy(buf, \"+nan.0\"); else if (d <= -HUGE_VAL) strcpy(buf, \"-inf.0\");
|
|
|
|
else if (d >= HUGE_VAL) strcpy(buf, \"+inf.0\"); else if (*s == 'E') *s = 'e';
|
|
|
|
else if (*s == 0) { *s++ = '.'; *s++ = '0'; *s = 0; }
|
|
|
|
$return obj(hpushstr($live, newstring(buf))); }" x))
|
|
|
|
|
|
|
|
(define-syntax number->string
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ n r) (if (fixnum? n) (fixnum->string n r) (flonum->string n))]
|
|
|
|
[(_ n) (if (fixnum? n) (fixnum->string n 10) (flonum->string n))]
|
|
|
|
[_ %residual-number->string]))
|
|
|
|
|
|
|
|
(define (string->fixnum s r)
|
|
|
|
(%prim? "{ /* string->fixnum */
|
|
|
|
char *e, *s = stringchars(obj_from_$arg);
|
|
|
|
int radix = fixnum_from_$arg; long l;
|
|
|
|
if (s[0] == '#' && (s[1] == 'b' || s[1] == 'B')) s += 2, radix = 2;
|
|
|
|
else if (s[0] == '#' && (s[1] == 'o' || s[1] == 'O')) s += 2, radix = 8;
|
|
|
|
else if (s[0] == '#' && (s[1] == 'd' || s[1] == 'D')) s += 2, radix = 10;
|
|
|
|
else if (s[0] == '#' && (s[1] == 'x' || s[1] == 'X')) s += 2, radix = 16;
|
|
|
|
l = (errno = 0, strtol(s, &e, radix));
|
|
|
|
if (errno || l < FIXNUM_MIN || l > FIXNUM_MAX || e == s || *e) $return bool(0);
|
|
|
|
else $return fixnum(l); }" s r))
|
|
|
|
|
|
|
|
(define (string->flonum s)
|
|
|
|
(%prim*? "{ /* string->flonum */
|
|
|
|
char *e = \"\", *s = stringchars(obj_from_$arg); double d; errno = 0;
|
|
|
|
if (*s != '+' && *s != '-') d = strtod(s, &e);
|
|
|
|
else if (strcmp_ci(s+1, \"inf.0\") == 0) d = (*s == '-' ? -HUGE_VAL : HUGE_VAL);
|
|
|
|
else if (strcmp_ci(s+1, \"nan.0\") == 0) d = HUGE_VAL - HUGE_VAL;
|
|
|
|
else d = strtod(s, &e);
|
|
|
|
if (errno || e == s || *e) $return bool(0);
|
|
|
|
else $return flonum($live, d); }" s))
|
|
|
|
|
|
|
|
(define-inline (string->fixnum-or-flonum s r)
|
|
|
|
(%prim*? "{ /* string->fixnum-or-flonum */
|
|
|
|
char *s = stringchars(obj_from_$arg);
|
|
|
|
int radix = fixnum_from_$arg; long l; double d;
|
|
|
|
if (0) $return obj(0); /* to fool sfc unboxer */
|
|
|
|
switch (strtofxfl(s, radix, &l, &d)) {
|
|
|
|
case 'e': $return fixnum(l); break;
|
|
|
|
case 'i': $return flonum($live, d); break;
|
|
|
|
default : $return bool(0); break;
|
|
|
|
} }" s r))
|
|
|
|
|
|
|
|
(define-syntax string->number
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ s r) (string->fixnum-or-flonum s r)]
|
|
|
|
[(_ s) (string->fixnum-or-flonum s 10)]
|
|
|
|
[_ %residual-string->number]))
|
|
|
|
|
|
|
|
(define (subvector->list vec start end)
|
|
|
|
(let loop ([i (fx- end 1)] [l '()])
|
|
|
|
(if (fx<? i start) l (loop (fx- i 1) (cons (vector-ref vec i) l)))))
|
|
|
|
|
|
|
|
(define (list->vector l)
|
|
|
|
(%prim*? "{ /* list->vector */
|
|
|
|
obj l; int i, c = fixnum_from_$arg;
|
|
|
|
hreserve(hbsz(c+1), $live); /* $live live regs */
|
|
|
|
l = obj_from_$arg; /* gc-safe */
|
|
|
|
for (i = 0; i < c; ++i, l = cdr(l)) hp[i-c] = car(l);
|
|
|
|
hp -= c; *--hp = obj_from_size(VECTOR_BTAG);
|
|
|
|
$return obj(hendblk(c+1)); }" (length l) l))
|
|
|
|
|
|
|
|
(define (list->string l)
|
|
|
|
(%prim*? "{ /* list->string */
|
|
|
|
int i, c = fixnum_from_$arg;
|
|
|
|
obj o = hpushstr($live, allocstring(c, ' ')); /* $live live regs */
|
|
|
|
obj l = obj_from_$arg; /* gc-safe */
|
|
|
|
unsigned char *s = (unsigned char *)stringchars(o);
|
|
|
|
for (i = 0; i < c; ++i, l = cdr(l)) s[i] = (unsigned char)char_from_obj(car(l));
|
|
|
|
$return obj(o); }" (length l) l))
|
|
|
|
|
|
|
|
(define (substring->list str start end)
|
|
|
|
(let loop ([i (fx- end 1)] [l '()])
|
|
|
|
(if (fx<? i start) l (loop (fx- i 1) (cons (string-ref str i) l)))))
|
|
|
|
|
|
|
|
(define (%subvector-string-copy! to at from start end)
|
|
|
|
(let ([limit (fxmin end (fx+ start (fx- (string-length to) at)))])
|
|
|
|
(do ([i at (fx+ i 1)] [j start (fx+ j 1)])
|
|
|
|
[(fx>=? j limit) to]
|
|
|
|
(string-set! to i (vector-ref from j)))))
|
|
|
|
|
|
|
|
(define (subvector->string vec start end)
|
|
|
|
(%subvector-string-copy! (make-string (fx- end start)) 0 vec start end))
|
|
|
|
|
|
|
|
(define (%substring-vector-copy! to at from start end)
|
|
|
|
(let ([limit (fxmin end (fx+ start (fx- (vector-length to) at)))])
|
|
|
|
(do ([i at (fx+ i 1)] [j start (fx+ j 1)])
|
|
|
|
[(fx>=? j limit) to]
|
|
|
|
(vector-set! to i (string-ref from j)))))
|
|
|
|
|
|
|
|
(define (substring->vector str start end)
|
|
|
|
(%substring-vector-copy! (make-vector (fx- end start)) 0 str start end))
|
|
|
|
|
|
|
|
(define (list->bytevector l)
|
|
|
|
(%prim*? "{ /* list->bytevector */
|
|
|
|
int i, c = fixnum_from_$arg;
|
|
|
|
obj o = hpushu8v($live, allocbytevector(c)); /* $live live regs */
|
|
|
|
obj l = obj_from_$arg; /* gc-safe */
|
|
|
|
unsigned char *s = bytevectorbytes(o);
|
|
|
|
for (i = 0; i < c; ++i, l = cdr(l)) s[i] = byte_from_obj(car(l));
|
|
|
|
$return obj(o); }" (length l) l))
|
|
|
|
|
|
|
|
(define (subbytevector->list vec start end)
|
|
|
|
(let loop ([i (fx- end 1)] [l '()])
|
|
|
|
(if (fx<? i start) l (loop (fx- i 1) (cons (bytevector-u8-ref vec i) l)))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; control
|
|
|
|
|
|
|
|
; closure procedures are heap blocks of length >= 1 which
|
|
|
|
; have a pointer to the static code entry as 0th element;
|
|
|
|
; sfc allocates env-less global procedures in static memory,
|
|
|
|
; so procedure? answers #t to any nonzero out-of-heap pointer
|
|
|
|
|
|
|
|
(define-inline (procedure? o)
|
|
|
|
(%prim "bool(isprocedure(obj_from_$arg))" o))
|
|
|
|
|
|
|
|
|
|
|
|
; apply, dotted lambda list, argc dispatch, case-lambda
|
|
|
|
|
|
|
|
(%definition "/* apply and dotted lambda list */")
|
|
|
|
(%definition "extern obj appcases[];")
|
|
|
|
(%localdef "/* apply/dotted lambda adapter entry points */")
|
|
|
|
(%localdef "static obj apphost(obj);")
|
|
|
|
(%localdef "obj appcases[5] = { (obj)apphost, (obj)apphost, (obj)apphost, (obj)apphost , (obj)apphost };")
|
|
|
|
(%localdef "/* apphost procedure */
|
|
|
|
#define APPLY_MAX_REGS 1024 /* limit on rc for apply & friends */
|
|
|
|
static obj apphost(obj pc)
|
|
|
|
{
|
|
|
|
register obj *r = cxg_regs;
|
|
|
|
register obj *hp = cxg_hp;
|
|
|
|
register int rc = cxg_rc;
|
|
|
|
jump:
|
|
|
|
switch (objptr_from_obj(pc)-appcases) {
|
|
|
|
|
|
|
|
case 0: /* apply */
|
|
|
|
/* clo k f arg... arglist */
|
|
|
|
assert(rc >= 4);
|
|
|
|
{ int i; obj l;
|
|
|
|
rreserve(APPLY_MAX_REGS);
|
|
|
|
l = r[--rc];
|
|
|
|
r[0] = r[2];
|
|
|
|
/* k in r[1] */
|
|
|
|
for (i = 3; i < rc; ++i) r[i-1] = r[i];
|
|
|
|
for (--rc; l != mknull(); l = cdr(l)) r[rc++] = car(l);
|
|
|
|
/* f k arg... arg... */
|
|
|
|
assert(rc <= APPLY_MAX_REGS);
|
|
|
|
pc = objptr_from_obj(r[0])[0];
|
|
|
|
goto jump; }
|
|
|
|
|
|
|
|
case 1: /* dotted lambda adapter */
|
|
|
|
/* clo k arg... */
|
|
|
|
{ obj* p = objptr_from_obj(r[0]);
|
|
|
|
int n = fixnum_from_obj(p[1]) + 2;
|
|
|
|
r[0] = p[2]; /* f */
|
|
|
|
/* k in r[1] */
|
|
|
|
assert(rc >= n);
|
|
|
|
rreserve(n+1);
|
|
|
|
if (rc == n) r[rc++] = mknull();
|
|
|
|
else { /* collect rest list */
|
|
|
|
obj l = mknull();
|
|
|
|
hreserve(hbsz(3)*(rc-n), rc);
|
|
|
|
while (rc > n) { *--hp = l; *--hp = r[--rc];
|
|
|
|
*--hp = obj_from_size(PAIR_BTAG); l = hendblk(3); }
|
|
|
|
r[rc++] = l; }
|
|
|
|
/* f k arg... arglist */
|
|
|
|
pc = objptr_from_obj(r[0])[0];
|
|
|
|
goto jump; }
|
|
|
|
|
|
|
|
case 2: /* void continuation adapter */
|
|
|
|
/* cclo ek arg ... */
|
|
|
|
assert(rc >= 2);
|
|
|
|
{ obj* p = objptr_from_obj(r[0]);
|
|
|
|
r[0] = p[1]; /* cont */
|
|
|
|
pc = objptr_from_obj(r[0])[0];
|
|
|
|
/* ek in r[1] */
|
|
|
|
rreserve(3);
|
|
|
|
r[2] = obj_from_void(0);
|
|
|
|
rc = 3;
|
|
|
|
goto jump; }
|
|
|
|
|
|
|
|
case 3: /* argc dispatcher */
|
|
|
|
/* clo k arg... */
|
|
|
|
{ obj* p = objptr_from_obj(r[0]);
|
|
|
|
obj pv = p[1]; int vl = vectorlen(pv); assert(vl > 0);
|
|
|
|
if (rc-2 < vl-1) r[0] = vectorref(pv, rc-2); /* matching slot */
|
|
|
|
else r[0] = vectorref(pv, vl-1); /* catch-all slot */
|
|
|
|
pc = objptr_from_obj(r[0])[0];
|
|
|
|
goto jump; }
|
|
|
|
|
|
|
|
case 4: /* case lambda dispatcher */
|
|
|
|
/* clo k arg... */
|
|
|
|
{ obj* p = objptr_from_obj(r[0]); int bl = hblklen(p), i;
|
|
|
|
for (i = 1; i < bl; i += 3) {
|
|
|
|
int min = fixnum_from_obj(hblkref(p, i)), max = fixnum_from_obj(hblkref(p, i+1));
|
|
|
|
if (min <= rc-2 && rc-2 <= max) { r[0] = hblkref(p, i+2); break; }
|
|
|
|
} assert(i < bl); /* at least one of the cases should match! */
|
|
|
|
pc = objptr_from_obj(r[0])[0];
|
|
|
|
goto jump; }
|
|
|
|
|
|
|
|
default: /* inter-host call */
|
|
|
|
cxg_hp = hp;
|
|
|
|
cxm_rgc(r, 1);
|
|
|
|
cxg_rc = rc;
|
|
|
|
return pc;
|
|
|
|
}
|
|
|
|
}")
|
|
|
|
|
|
|
|
(define apply
|
|
|
|
(%prim "{ /* define apply */
|
|
|
|
static obj c[] = { obj_from_objptr(appcases+0) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(define-inline (make-improper-lambda n lam)
|
|
|
|
(%prim* "{ /* make-improper-lambda */
|
|
|
|
hreserve(hbsz(3), $live); /* $live live regs */
|
|
|
|
*--hp = obj_from_$arg;
|
|
|
|
*--hp = obj_from_$arg;
|
|
|
|
*--hp = obj_from_objptr(appcases+1);
|
|
|
|
$return obj(hendblk(3)); }" lam n))
|
|
|
|
|
|
|
|
(define-inline (make-void-continuation k)
|
|
|
|
(%prim* "{ /* make-void-continuation */
|
|
|
|
hreserve(hbsz(2), $live); /* $live live regs */
|
|
|
|
*--hp = obj_from_$arg;
|
|
|
|
*--hp = obj_from_objptr(appcases+2);
|
|
|
|
$return obj(hendblk(2)); }" k))
|
|
|
|
|
|
|
|
(define-inline (make-argc-dispatch-lambda pv)
|
|
|
|
(%prim* "{ /* make-argc-dispatch-lambda */
|
|
|
|
hreserve(hbsz(2), $live); /* $live live regs */
|
|
|
|
*--hp = obj_from_$arg;
|
|
|
|
*--hp = obj_from_objptr(appcases+3);
|
|
|
|
$return obj(hendblk(2)); }" pv))
|
|
|
|
|
|
|
|
(define-syntax argc-dispatch-lambda
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x ...) (make-argc-dispatch-lambda (vector x ...))]))
|
|
|
|
|
|
|
|
(define-inline (argc-dispatch-lambda? x)
|
|
|
|
(%prim "{ /* argc-dispatch-lambda? */
|
|
|
|
obj x = obj_from_$arg;
|
|
|
|
$return bool(isprocedure(x) && *procedureref(x, 0) == obj_from_objptr(appcases+3)); }" x))
|
|
|
|
|
|
|
|
(define-syntax make-case-lambda
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x ...) ; order is: min1 max1 lambda1 min2 max2 lambda2 ...
|
|
|
|
(%prim*/rev "{ /* make-case-lambda */
|
|
|
|
hreserve(hbsz($argc+1), $live); /* $live live regs */
|
|
|
|
${*--hp = obj_from_$arg;
|
|
|
|
$}*--hp = obj_from_objptr(appcases+4);
|
|
|
|
$return obj(hendblk($argc+1)); }" x ...)]
|
|
|
|
[_ %residual-make-case-lambda]))
|
|
|
|
|
|
|
|
(define-syntax case-lambda
|
|
|
|
(letrec-syntax
|
|
|
|
([min-accepted
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ () N) N] [(_ (a . d) N) (min-accepted d #&(+ 1 N))] [(_ ra N) N])]
|
|
|
|
[max-accepted
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ () N) N] [(_ (a . d) N) (max-accepted d #&(+ 1 N))] [(_ ra N) (%prim "fixnum(FIXNUM_MAX)")])]
|
|
|
|
[unroll-cases
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ () c ...)
|
|
|
|
(make-case-lambda c ... 0 (%prim "fixnum(FIXNUM_MAX)") %fail-lambda)]
|
|
|
|
[(_ ([formals . body] . more) c ...)
|
|
|
|
(unroll-cases more c ...
|
|
|
|
(min-accepted formals 0) (max-accepted formals 0) (lambda formals . body))])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ [formals . body] ...)
|
|
|
|
(unroll-cases ([formals . body] ...))])))
|
|
|
|
|
|
|
|
|
|
|
|
; parameters, r7rs-style
|
|
|
|
|
|
|
|
(define make-parameter
|
|
|
|
(case-lambda
|
|
|
|
[(value)
|
|
|
|
(case-lambda
|
|
|
|
[() value]
|
|
|
|
[(x) (set! value x)]
|
|
|
|
[(x s) (if s (set! value x) x)])]
|
|
|
|
[(init converter)
|
|
|
|
(let ([value (converter init)])
|
|
|
|
(case-lambda
|
|
|
|
[() value]
|
|
|
|
[(x) (set! value (converter x))]
|
|
|
|
[(x s) (if s (set! value x) (converter x))]))]))
|
|
|
|
|
|
|
|
(define-syntax parameterize
|
|
|
|
(letrec-syntax
|
|
|
|
([loop
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ ([param value p old new] ...) () body)
|
|
|
|
(let ([p param] ...)
|
|
|
|
(let ([old (p)] ... [new (p value #f)] ...)
|
|
|
|
(dynamic-wind
|
|
|
|
(lambda () (p new #t) ...)
|
|
|
|
(lambda () . body)
|
|
|
|
(lambda () (p old #t) ...))))]
|
|
|
|
[(_ args ([param value] . rest) body)
|
|
|
|
(loop ([param value p old new] . args) rest body)])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ ([param value] ...) . body)
|
|
|
|
(loop () ([param value] ...) body)])))
|
|
|
|
|
|
|
|
|
|
|
|
; delay & force, r7rs-style
|
|
|
|
|
|
|
|
(define promise? box?)
|
|
|
|
|
|
|
|
(define (make-promise o) (box (cons #t o)))
|
|
|
|
(define (make-lazy-promise o) (box (cons #f o)))
|
|
|
|
|
|
|
|
(define (force p)
|
|
|
|
(let ([pc (unbox p)])
|
|
|
|
(if (car pc)
|
|
|
|
(cdr pc)
|
|
|
|
(let* ([newp ((cdr pc))] [pc (unbox p)])
|
|
|
|
(unless (car pc)
|
|
|
|
(set-car! pc (car (unbox newp)))
|
|
|
|
(set-cdr! pc (cdr (unbox newp)))
|
|
|
|
(set-box! newp pc))
|
|
|
|
(force p)))))
|
|
|
|
|
|
|
|
(define-syntax delay-force
|
|
|
|
(syntax-rules () [(_ x) (make-lazy-promise (lambda () x))]))
|
|
|
|
|
|
|
|
(define-syntax delay
|
|
|
|
(syntax-rules () [(_ x) (delay-force (make-promise x))]))
|
|
|
|
|
|
|
|
|
|
|
|
; eof
|
|
|
|
|
|
|
|
(define-syntax %const
|
|
|
|
(let-syntax ([old-%const %const])
|
|
|
|
(syntax-rules (eof)
|
|
|
|
[(_ eof) (%prim "obj(mkeof())")]
|
|
|
|
[(_ arg ...) (old-%const arg ...)])))
|
|
|
|
|
|
|
|
(define-inline (eof-object)
|
|
|
|
(%prim "obj(mkeof())"))
|
|
|
|
|
|
|
|
(define-inline (eof-object? x)
|
|
|
|
(%prim "bool(iseof(obj_from_$arg))" x))
|
|
|
|
|
|
|
|
|
|
|
|
; shebangs
|
|
|
|
|
|
|
|
; i/o ports
|
|
|
|
|
|
|
|
; internal helper for opening regular files
|
|
|
|
(define-inline (open-file* fn mode) ;=> #f (i.e. NULL) or foreign ptr
|
|
|
|
(%prim*?! "obj((obj)fopen(stringchars(obj_from_$arg), stringchars(obj_from_$arg)))" fn mode))
|
|
|
|
|
|
|
|
; input ports
|
|
|
|
|
|
|
|
(define-inline (input-port? x)
|
|
|
|
(%prim "bool(isiport(obj_from_$arg))" x))
|
|
|
|
|
|
|
|
(define-inline (port-fold-case? ip) ;stub
|
|
|
|
(%prim? "bool(((void)ckiportvt(obj_from_$arg), 0))" ip))
|
|
|
|
|
|
|
|
(define-inline (set-port-fold-case! ip b) ;stub
|
|
|
|
(%prim?! "void(ckiportvt(obj_from_$arg))" ip))
|
|
|
|
|
|
|
|
; closed input ports
|
|
|
|
|
|
|
|
(define (close-input-port p)
|
|
|
|
(%prim?! "{ /* close-input-port */
|
|
|
|
obj o = obj_from_$arg; cxtype_iport_t *vt = iportvt(o); assert(vt);
|
|
|
|
vt->close(iportdata(o)); vt->free(iportdata(o));
|
|
|
|
objptr_from_obj(o)[-1] = (obj)IPORT_CLOSED_NTAG;
|
|
|
|
$return void(0); }" p))
|
|
|
|
|
|
|
|
(define-inline (input-port-open? p)
|
|
|
|
(%prim? "bool(ckiportvt(obj_from_$arg) != (cxtype_iport_t *)IPORT_CLOSED_NTAG)" p))
|
|
|
|
|
|
|
|
; file input ports
|
|
|
|
|
|
|
|
(define *current-input-port* (%prim* "obj(mkiport_file($live, stdin))"))
|
|
|
|
|
|
|
|
(define-syntax current-input-port ; parameter
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) *current-input-port*]
|
|
|
|
[(_ p) (set! *current-input-port* p)]
|
|
|
|
[(_ p s) (if s (set! *current-input-port* p) p)]
|
|
|
|
[_ %residual-current-input-port]))
|
|
|
|
|
|
|
|
(define-inline (open-input-file fn)
|
|
|
|
(let ([file* (open-file* fn "r")])
|
|
|
|
(if file* (%prim*?! "obj(mkiport_file($live, (void*)(obj_from_$arg)))" file*)
|
|
|
|
(file-error "cannot open input file" fn))))
|
|
|
|
|
|
|
|
(define-inline (open-binary-input-file fn)
|
|
|
|
(let ([file* (open-file* fn "rb")])
|
|
|
|
(if file* (%prim*?! "obj(mkiport_file($live, (void*)(obj_from_$arg)))" file*)
|
|
|
|
(file-error "cannot open binary input file" fn))))
|
|
|
|
|
|
|
|
; string input ports
|
|
|
|
|
|
|
|
(define-inline (open-input-string s)
|
|
|
|
(%prim*? "{ /* open-input-string */
|
|
|
|
int *d = dupstring(stringdata(obj_from_$arg));
|
|
|
|
$return obj(mkiport_string($live, sialloc(sdatachars(d), d))); }" s))
|
|
|
|
|
|
|
|
; bytevector input ports
|
|
|
|
|
|
|
|
(define-inline (open-input-bytevector s)
|
|
|
|
(%prim*? "{ /* open-input-bytevector */
|
|
|
|
int *d = dupbytevector(bytevectordata(obj_from_$arg));
|
|
|
|
unsigned char *p = bvdatabytes(d), *e = p + *d;
|
|
|
|
$return obj(mkiport_bytevector($live, bvialloc(p, e, d))); }" s))
|
|
|
|
|
|
|
|
; generic output ports
|
|
|
|
|
|
|
|
(define-inline (output-port? x)
|
|
|
|
(%prim "bool(isoport(obj_from_$arg))" x))
|
|
|
|
|
|
|
|
; closed output ports
|
|
|
|
|
|
|
|
(define (close-output-port p)
|
|
|
|
(%prim?! "{ /* close-output-port */
|
|
|
|
obj o = obj_from_$arg; cxtype_oport_t *vt = oportvt(o); assert(vt);
|
|
|
|
vt->close(oportdata(o)); vt->free(oportdata(o));
|
|
|
|
objptr_from_obj(o)[-1] = (obj)OPORT_CLOSED_NTAG;
|
|
|
|
$return void(0); }" p))
|
|
|
|
|
|
|
|
(define-inline (output-port-open? p)
|
|
|
|
(%prim? "bool(ckoportvt(obj_from_$arg) != (cxtype_oport_t *)OPORT_CLOSED_NTAG)" p))
|
|
|
|
|
|
|
|
; file output ports
|
|
|
|
|
|
|
|
(define *current-output-port* (%prim* "obj(mkoport_file($live, stdout))"))
|
|
|
|
|
|
|
|
(define-syntax current-output-port ; parameter
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) *current-output-port*]
|
|
|
|
[(_ p) (set! *current-output-port* p)]
|
|
|
|
[(_ p s) (if s (set! *current-output-port* p) p)]
|
|
|
|
[_ %residual-current-output-port]))
|
|
|
|
|
|
|
|
(define *current-error-port* (%prim* "obj(mkoport_file($live, stderr))"))
|
|
|
|
|
|
|
|
(define-syntax current-error-port ; parameter
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) *current-error-port*]
|
|
|
|
[(_ p) (set! *current-error-port* p)]
|
|
|
|
[(_ p s) (if s (set! *current-error-port* p) p)]
|
|
|
|
[_ %residual-current-error-port]))
|
|
|
|
|
|
|
|
(define-inline (open-output-file fn)
|
|
|
|
(let ([file* (open-file* fn "w")])
|
|
|
|
(if file* (%prim*?! "obj(mkoport_file($live, (void*)(obj_from_$arg)))" file*)
|
|
|
|
(file-error "cannot open output file" fn))))
|
|
|
|
|
|
|
|
(define-inline (open-binary-output-file fn)
|
|
|
|
(let ([file* (open-file* fn "wb")])
|
|
|
|
(if file* (%prim*?! "obj(mkoport_file($live, (void*)(obj_from_$arg)))" file*)
|
|
|
|
(file-error "cannot open binary output file" fn))))
|
|
|
|
|
|
|
|
; string output ports
|
|
|
|
|
|
|
|
(define-inline (open-output-string)
|
|
|
|
(%prim*? "{ /* open-output-string */
|
|
|
|
$return obj(mkoport_string($live, newcb())); }"))
|
|
|
|
|
|
|
|
(define-inline (get-output-string p) ; works on string and bv ports
|
|
|
|
(%prim*? "{ /* get-output-string */
|
|
|
|
obj o = obj_from_$arg; cxtype_oport_t *vt = ckoportvt(o);
|
|
|
|
if (vt != (cxtype_oport_t *)OPORT_STRING_NTAG &&
|
|
|
|
vt != (cxtype_oport_t *)OPORT_BYTEVECTOR_NTAG) $return obj(mkeof());
|
|
|
|
else { cbuf_t *pcb = oportdata(o);
|
|
|
|
$return obj(hpushstr($live, newstring(cbdata(pcb)))); } }" p))
|
|
|
|
|
|
|
|
; bytevector output ports
|
|
|
|
|
|
|
|
(define-inline (open-output-bytevector)
|
|
|
|
(%prim*? "{ /* open-output-bytevector */
|
|
|
|
$return obj(mkoport_bytevector($live, newcb())); }"))
|
|
|
|
|
|
|
|
(define-inline (get-output-bytevector p) ; works on bv and string ports
|
|
|
|
(%prim*? "{ /* get-output-bytevector */
|
|
|
|
obj o = obj_from_$arg; cxtype_oport_t *vt = ckoportvt(o);
|
|
|
|
if (vt != (cxtype_oport_t *)OPORT_BYTEVECTOR_NTAG &&
|
|
|
|
vt != (cxtype_oport_t *)OPORT_STRING_NTAG) $return obj(mkeof());
|
|
|
|
else { cbuf_t *pcb = oportdata(o); int len = (int)(pcb->fill - pcb->buf);
|
|
|
|
$return obj(hpushu8v($live, newbytevector((unsigned char *)pcb->buf, len))); } }" p))
|
|
|
|
|
|
|
|
; port predicates and standard opening/closing convenience ops
|
|
|
|
|
|
|
|
(define-inline (port? x) (or (input-port? x) (output-port? x)))
|
|
|
|
(define-syntax textual-port? port?) ; all ports are bimodal
|
|
|
|
(define-syntax binary-port? port?) ; all ports are bimodal
|
|
|
|
|
|
|
|
(define (close-port p)
|
|
|
|
(if (input-port? p) (close-input-port p))
|
|
|
|
(if (output-port? p) (close-output-port p)))
|
|
|
|
|
|
|
|
; NB: call-with-port defined in the last section, after call-with-values
|
|
|
|
|
|
|
|
(define (call-with-input-file fname proc)
|
|
|
|
(call-with-port (open-input-file fname) proc))
|
|
|
|
|
|
|
|
(define (call-with-output-file fname proc)
|
|
|
|
(call-with-port (open-output-file fname) proc))
|
|
|
|
|
|
|
|
(define (with-input-from-port port thunk) ; extra
|
|
|
|
(parameterize ([current-input-port port]) (thunk)))
|
|
|
|
|
|
|
|
(define (with-output-to-port port thunk) ; extra
|
|
|
|
(parameterize ([current-output-port port]) (thunk)))
|
|
|
|
|
|
|
|
(define (with-input-from-file fname thunk)
|
|
|
|
(call-with-input-file fname (lambda (p) (with-input-from-port p thunk))))
|
|
|
|
|
|
|
|
(define (with-output-to-file fname thunk)
|
|
|
|
(call-with-output-file fname (lambda (p) (with-output-to-port p thunk))))
|
|
|
|
|
|
|
|
; simple text i/o
|
|
|
|
|
|
|
|
(define-syntax read-char
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (read-char (current-input-port))]
|
|
|
|
[(_ p) (%prim?! "{ int c = iportgetc(obj_from_$arg); $return obj(c == EOF ? mkeof() : obj_from_char(c)); }" p)]
|
|
|
|
[_ %residual-read-char]))
|
|
|
|
|
|
|
|
(define-syntax peek-char
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (peek-char (current-input-port))]
|
|
|
|
[(_ p) (%prim?! "{ int c = iportpeekc(obj_from_$arg); $return obj(c == EOF ? mkeof() : obj_from_char(c)); }" p)]
|
|
|
|
[_ %residual-peek-char]))
|
|
|
|
|
|
|
|
(define-syntax char-ready?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (char-ready? (current-input-port))]
|
|
|
|
[(_ p) #t] ; no better solution for FILE/STRING ports
|
|
|
|
[_ %residual-char-ready?]))
|
|
|
|
|
|
|
|
(define (%read-line p)
|
|
|
|
(let ([op (open-output-string)])
|
|
|
|
(let loop ([read-nothing? #t])
|
|
|
|
(let ([c (read-char p)])
|
|
|
|
(cond [(or (eof-object? c) (char=? c #\newline))
|
|
|
|
(let ([s (get-output-string op)])
|
|
|
|
(close-output-port op) ; todo: use get-final-output-string
|
|
|
|
(if (and (eof-object? c) read-nothing?) c s))]
|
|
|
|
[(char=? c #\return) (loop #f)]
|
|
|
|
[else (%prim?! "void(oportputc(char_from_$arg, obj_from_$arg))" c op) (loop #f)])))))
|
|
|
|
|
|
|
|
(define-syntax read-line
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (%read-line (current-input-port))]
|
|
|
|
[(_ p) (%read-line p)]
|
|
|
|
[_ %residual-read-line]))
|
|
|
|
|
|
|
|
(define (read-substring! str start end p)
|
|
|
|
(let loop ([i start])
|
|
|
|
(if (fx>=? i end)
|
|
|
|
(fx- i start)
|
|
|
|
(let ([c (read-char p)])
|
|
|
|
(cond [(eof-object? c) (if (fx=? i start) c (fx- i start))]
|
|
|
|
[else (string-set! str i c) (loop (fx+ i 1))])))))
|
|
|
|
|
|
|
|
(define (read-substring k p)
|
|
|
|
(let ([str (make-string k)])
|
|
|
|
(let ([r (read-substring! str 0 k p)])
|
|
|
|
(if (eof-object? r)
|
|
|
|
r
|
|
|
|
(if (fx=? r k) str (substring str 0 r))))))
|
|
|
|
|
|
|
|
(define-syntax flush-output-port
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (flush-output-port (current-output-port))]
|
|
|
|
[(_ p) (%prim?! "void(oportflush(obj_from_$arg))" p)]
|
|
|
|
[_ %residual-flush-output-port]))
|
|
|
|
|
|
|
|
(define-syntax write-char
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ c) (write-char c (current-output-port))]
|
|
|
|
[(_ c p) (%prim?! "void(oportputc(char_from_$arg, obj_from_$arg))" c p)]
|
|
|
|
[_ %residual-write-char]))
|
|
|
|
|
|
|
|
(define (write-substring from start end p)
|
|
|
|
(do ([i start (fx+ i 1)]) [(fx>=? i end)] (write-char (string-ref from i) p)))
|
|
|
|
|
|
|
|
(define-syntax write-string
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ s) (write-string s (current-output-port))]
|
|
|
|
[(_ s p) (%prim?! "void(oportputs(stringchars(obj_from_$arg), obj_from_$arg))" s p)]
|
|
|
|
[(_ s p start) (let ([str s]) (write-substring str start (string-length str) p))]
|
|
|
|
[(_ s p start end) (write-substring s start end p)]
|
|
|
|
[_ %residual-write-string]))
|
|
|
|
|
|
|
|
(define-syntax newline
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (newline (current-output-port))]
|
|
|
|
[(_ p) (%prim?! "void(oportputc('\\n', obj_from_$arg))" p)]
|
|
|
|
[_ %residual-newline]))
|
|
|
|
|
|
|
|
(define-syntax display-fixnum
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (display-fixnum x (current-output-port))]
|
|
|
|
[(_ x p) (%prim?! "{ /* display-fixnum */
|
|
|
|
char buf[30]; sprintf(buf, \"%ld\", fixnum_from_$arg);
|
|
|
|
$return void(oportputs(buf, obj_from_$arg)); }" x p)]
|
|
|
|
[_ %residual-display-fixnum]))
|
|
|
|
|
|
|
|
(define-syntax display-flonum
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (display-flonum x (current-output-port))]
|
|
|
|
[(_ x p) (%prim?! "{ /* display-flonum */
|
|
|
|
char buf[30], *s; double d = flonum_from_$arg; sprintf(buf, \"%.15g\", d);
|
|
|
|
for (s = buf; *s != 0; s++) if (strchr(\".eE\", *s)) break;
|
|
|
|
if (d != d) strcpy(buf, \"+nan.0\"); else if (d <= -HUGE_VAL) strcpy(buf, \"-inf.0\");
|
|
|
|
else if (d >= HUGE_VAL) strcpy(buf, \"+inf.0\"); else if (*s == 'E') *s = 'e';
|
|
|
|
else if (*s == 0) { *s++ = '.'; *s++ = '0'; *s = 0; }
|
|
|
|
$return void(oportputs(buf, obj_from_$arg)); }" x p)]
|
|
|
|
[_ %residual-display-flonum]))
|
|
|
|
|
|
|
|
(define-syntax display-procedure
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (display-procedure x (current-output-port))]
|
|
|
|
[(_ x p) (%prim?! "{ /* display-procedure */
|
|
|
|
char buf[60]; sprintf(buf, \"#<procedure @%p>\", objptr_from_obj(obj_from_$arg));
|
|
|
|
$return void(oportputs(buf, obj_from_$arg)); }" x p)]
|
|
|
|
[_ %residual-display-procedure]))
|
|
|
|
|
|
|
|
(define-syntax display-input-port
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (display-input-port x (current-output-port))]
|
|
|
|
[(_ x p) (%prim?! "{ /* display-input-port */
|
|
|
|
char buf[60]; sprintf(buf, \"#<%s>\", ckiportvt(obj_from_$arg)->tname);
|
|
|
|
$return void(oportputs(buf, obj_from_$arg)); }" x p)]
|
|
|
|
[_ %residual-display-input-port]))
|
|
|
|
|
|
|
|
(define-syntax display-output-port
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (display-output-port x (current-output-port))]
|
|
|
|
[(_ x p) (%prim?! "{ /* display-output-port */
|
|
|
|
char buf[60]; sprintf(buf, \"#<%s>\", ckoportvt(obj_from_$arg)->tname);
|
|
|
|
$return void(oportputs(buf, obj_from_$arg)); }" x p)]
|
|
|
|
[_ %residual-display-output-port]))
|
|
|
|
|
|
|
|
; simple binary i/o
|
|
|
|
|
|
|
|
(define-syntax read-u8
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (read-u8 (current-input-port))]
|
|
|
|
[(_ p) (%prim?! "{ int c = iportgetc(obj_from_$arg); $return obj(c == EOF ? mkeof() : obj_from_fixnum(c & 0xff)); }" p)]
|
|
|
|
[_ %residual-read-u8]))
|
|
|
|
|
|
|
|
(define-syntax peek-u8
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (peek-u8 (current-input-port))]
|
|
|
|
[(_ p) (%prim?! "{ int c = iportpeekc(obj_from_$arg); $return obj(c == EOF ? mkeof() : obj_from_fixnum(c & 0xff)); }" p)]
|
|
|
|
[_ %residual-peek-char]))
|
|
|
|
|
|
|
|
(define-syntax u8-ready?
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (u8-ready? (current-input-port))]
|
|
|
|
[(_ p) #t] ; no better solution for FILE/STRING ports
|
|
|
|
[_ %residual-u8-ready?]))
|
|
|
|
|
|
|
|
(define (read-subbytevector! vec start end p)
|
|
|
|
(let loop ([i start])
|
|
|
|
(if (fx>=? i end)
|
|
|
|
(fx- i start)
|
|
|
|
(let ([u8 (read-u8 p)])
|
|
|
|
(cond [(eof-object? u8) (if (fx=? i start) u8 (fx- i start))]
|
|
|
|
[else (bytevector-u8-set! vec i u8) (loop (fx+ i 1))])))))
|
|
|
|
|
|
|
|
(define (read-subbytevector k p)
|
|
|
|
(let ([vec (make-bytevector k)])
|
|
|
|
(let ([r (read-subbytevector! vec 0 k p)])
|
|
|
|
(if (eof-object? r)
|
|
|
|
r
|
|
|
|
(if (fx=? r k) vec (subbytevector vec 0 r))))))
|
|
|
|
|
|
|
|
(define-syntax write-u8
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ c) (write-u8 c (current-output-port))]
|
|
|
|
[(_ c p) (%prim?! "void(oportputc(fixnum_from_$arg, obj_from_$arg))" c p)]
|
|
|
|
[_ %residual-write-u8]))
|
|
|
|
|
|
|
|
(define (write-subbytevector from start end p)
|
|
|
|
(do ([i start (fx+ i 1)]) [(fx>=? i end)] (write-u8 (bytevector-u8-ref from i) p)))
|
|
|
|
|
|
|
|
(define-syntax write-bytevector
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ bv) (write-bytevector bv (current-output-port))]
|
|
|
|
[(_ bv p) (%prim?! "{ /* write-bytevector */
|
|
|
|
int *d = bytevectordata(obj_from_$arg);
|
|
|
|
$return void(oportwrite((char *)bvdatabytes(d), *d, obj_from_$arg)); }" bv p)]
|
|
|
|
[(_ bv p start) (let ([vec bv]) (write-subbytevector vec start (bytevector-length vec) p))]
|
|
|
|
[(_ bv p start end) (write-subbytevector bv start end p)]
|
|
|
|
[_ %residual-write-bytevector]))
|
|
|
|
|
|
|
|
|
|
|
|
; circularity
|
|
|
|
|
|
|
|
(define-inline (circular? x)
|
|
|
|
(%prim "bool(iscircular(obj_from_$arg))" x))
|
|
|
|
|
|
|
|
|
|
|
|
; equivalence and case
|
|
|
|
|
|
|
|
(define-inline (eq? x y)
|
|
|
|
(%prim "bool(obj_from_$arg == obj_from_$arg)" x y))
|
|
|
|
|
|
|
|
(define-inline (eqv? x y)
|
|
|
|
(or (eq? x y) ; covers fx=?
|
|
|
|
(and (flonum? x) (flonum? y) (fl=? x y))))
|
|
|
|
|
|
|
|
(define-inline (equal? x y)
|
|
|
|
(%prim? "bool(isequal(obj_from_$arg, obj_from_$arg))" x y))
|
|
|
|
|
|
|
|
(define-syntax case
|
|
|
|
(letrec-syntax
|
|
|
|
([compare
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ key ()) #f]
|
|
|
|
[(_ key (#&(id? datum) . data))
|
|
|
|
(if (eq? key 'datum) #t (compare key data))]
|
|
|
|
[(_ key (datum . data))
|
|
|
|
(if (eqv? key 'datum) #t (compare key data))])]
|
|
|
|
[case
|
|
|
|
(syntax-rules (else =>)
|
|
|
|
[(case key) (if #f #f)]
|
|
|
|
[(case key (else => resproc))
|
|
|
|
(resproc key)]
|
|
|
|
[(case key (else result1 . results))
|
|
|
|
(begin result1 . results)]
|
|
|
|
[(case key ((datum ...) => resproc) . clauses)
|
|
|
|
(if (compare key (datum ...))
|
|
|
|
(resproc key)
|
|
|
|
(case key . clauses))]
|
|
|
|
[(case key ((datum ...) result1 . results) . clauses)
|
|
|
|
(if (compare key (datum ...))
|
|
|
|
(begin result1 . results)
|
|
|
|
(case key . clauses))])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ expr clause1 clause ...)
|
|
|
|
(let ([key expr]) (case key clause1 clause ...))])))
|
|
|
|
|
|
|
|
; equivalence-based member, assoc
|
|
|
|
|
|
|
|
(define-inline (memq x l)
|
|
|
|
(%prim? "{ /* memq */
|
|
|
|
obj x = obj_from_$arg, l = obj_from_$arg;
|
|
|
|
for (; l != mknull(); l = cdr(l)) if (car(l) == x) break;
|
|
|
|
$return obj(l == mknull() ? obj_from_bool(0) : l); }" x l))
|
|
|
|
|
|
|
|
(define-inline (memv x l)
|
|
|
|
(%prim? "obj(ismemv(obj_from_$arg, obj_from_$arg))" x l))
|
|
|
|
|
|
|
|
(define-inline (meml x l)
|
|
|
|
(%prim? "obj(ismember(obj_from_$arg, obj_from_$arg))" x l))
|
|
|
|
|
|
|
|
(define (%member x l eq)
|
|
|
|
(and (pair? l) (if (eq x (car l)) l (%member x (cdr l) eq))))
|
|
|
|
|
|
|
|
(define-syntax member
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x l) (meml x l)]
|
|
|
|
[(_ x l eq) (%member x l eq)]
|
|
|
|
[_ %residual-member]))
|
|
|
|
|
|
|
|
(define-inline (assq x l)
|
|
|
|
(%prim? "{ /* assq */
|
|
|
|
obj x = obj_from_$arg, l = obj_from_$arg, p = mknull();
|
|
|
|
for (; l != mknull(); l = cdr(l)) { p = car(l); if (car(p) == x) break; }
|
|
|
|
$return obj(l == mknull() ? obj_from_bool(0) : p); }" x l))
|
|
|
|
|
|
|
|
(define-inline (assv x l)
|
|
|
|
(%prim? "obj(isassv(obj_from_$arg, obj_from_$arg))" x l))
|
|
|
|
|
|
|
|
(define-inline (assl x l)
|
|
|
|
(%prim? "obj(isassoc(obj_from_$arg, obj_from_$arg))" x l))
|
|
|
|
|
|
|
|
(define (%assoc x al eq)
|
|
|
|
(and (pair? al) (if (eq x (caar al)) (car al) (%assoc x (cdr al) eq))))
|
|
|
|
|
|
|
|
(define-syntax assoc
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x al) (assl x al)]
|
|
|
|
[(_ x al eq) (%assoc x al eq)]
|
|
|
|
[_ %residual-assoc]))
|
|
|
|
|
|
|
|
|
|
|
|
; quasiquote
|
|
|
|
|
|
|
|
#read `<datum> as (quasiquote <datum>)
|
|
|
|
#read ,<datum> as (unquote <datum>)
|
|
|
|
#read ,@<datum> as (unquote-splicing <datum>)
|
|
|
|
|
|
|
|
(define-syntax quasiquote ; from eiod
|
|
|
|
(syntax-rules (unquote unquote-splicing quasiquote)
|
|
|
|
[(_ (unquote x)) x]
|
|
|
|
[(_ ((unquote-splicing x))) x] ;esl: allow `(,@improper-list)
|
|
|
|
[(_ ((unquote-splicing x) . y)) (append x (quasiquote y))]
|
|
|
|
[(_ (quasiquote x) . d) (cons 'quasiquote (quasiquote (x) d))]
|
|
|
|
[(_ (unquote x) d) (cons 'unquote (quasiquote (x) . d))]
|
|
|
|
[(_ (unquote-splicing x) d) (cons 'unquote-splicing (quasiquote (x) . d))]
|
|
|
|
[(_ (x . y) . d) (cons (quasiquote x . d) (quasiquote y . d))]
|
|
|
|
[(_ #(x ...) . d) (list->vector (quasiquote (x ...) . d))]
|
|
|
|
[(_ x . d) 'x]))
|
|
|
|
|
|
|
|
|
|
|
|
; S-expression writer
|
|
|
|
|
|
|
|
(define-syntax write-simple
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (%prim?! "void(oportputsimple(obj_from_$arg, obj_from_$arg, 0))" x (current-output-port))]
|
|
|
|
[(_ x p) (%prim?! "void(oportputsimple(obj_from_$arg, obj_from_$arg, 0))" x p)]
|
|
|
|
[_ %residual-write-simple]))
|
|
|
|
|
|
|
|
(define-syntax write-shared
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (%prim?! "void(oportputshared(obj_from_$arg, obj_from_$arg, 0))" x (current-output-port))]
|
|
|
|
[(_ x p) (%prim?! "void(oportputshared(obj_from_$arg, obj_from_$arg, 0))" x p)]
|
|
|
|
[_ %residual-write-shared]))
|
|
|
|
|
|
|
|
(define-syntax write
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (%prim?! "void(oportputcircular(obj_from_$arg, obj_from_$arg, 0))" x (current-output-port))]
|
|
|
|
[(_ x p) (%prim?! "void(oportputcircular(obj_from_$arg, obj_from_$arg, 0))" x p)]
|
|
|
|
[_ %residual-write]))
|
|
|
|
|
|
|
|
(define-syntax display
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ x) (%prim?! "void(oportputcircular(obj_from_$arg, obj_from_$arg, 1))" x (current-output-port))]
|
|
|
|
[(_ x p) (%prim?! "void(oportputcircular(obj_from_$arg, obj_from_$arg, 1))" x p)]
|
|
|
|
[_ %residual-display]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; simple errors
|
|
|
|
|
|
|
|
(define (print-error-message prefix args ep)
|
|
|
|
(define (pr-where args ep)
|
|
|
|
(when (pair? args)
|
|
|
|
(cond [(not (car args))
|
|
|
|
(write-string ": " ep)
|
|
|
|
(pr-msg (cdr args) ep)]
|
|
|
|
[(symbol? (car args))
|
|
|
|
(write-string " in " ep) (write (car args) ep) (write-string ": " ep)
|
|
|
|
(pr-msg (cdr args) ep)]
|
|
|
|
[else
|
|
|
|
(write-string ": " ep)
|
|
|
|
(pr-msg args ep)])))
|
|
|
|
(define (pr-msg args ep)
|
|
|
|
(when (pair? args)
|
|
|
|
(cond [(string? (car args))
|
|
|
|
(display (car args) ep)
|
|
|
|
(pr-rest (cdr args) ep)]
|
|
|
|
[else (pr-rest args ep)])))
|
|
|
|
(define (pr-rest args ep)
|
|
|
|
(when (pair? args)
|
|
|
|
(write-char #\space ep) (write (car args) ep)
|
|
|
|
(pr-rest (cdr args) ep)))
|
|
|
|
(cond [(or (string? prefix) (symbol? prefix))
|
|
|
|
(write-string prefix ep)]
|
|
|
|
[else (write-string "Error" ep)])
|
|
|
|
(pr-where args ep)
|
|
|
|
(newline ep))
|
|
|
|
|
|
|
|
(define (simple-error . args)
|
|
|
|
(let ([ep (current-error-port)])
|
|
|
|
(newline ep)
|
|
|
|
(print-error-message "Error" args ep)
|
|
|
|
(reset)))
|
|
|
|
|
|
|
|
(define (assertion-violation . args)
|
|
|
|
(let ([ep (current-error-port)])
|
|
|
|
(newline ep)
|
|
|
|
(print-error-message "Assertion violation" args ep)
|
|
|
|
(%prim! "{ assert(0); exit(1); $return void(0); }")))
|
|
|
|
|
|
|
|
|
|
|
|
; S-expression reader
|
|
|
|
|
|
|
|
(define (%read port simple?)
|
|
|
|
|
|
|
|
(define-syntax r-error
|
|
|
|
(syntax-rules () [(_ p msg a ...) (read-error msg a ... 'port: p)])) ; see read-error below
|
|
|
|
|
|
|
|
(define shared '())
|
|
|
|
(define (make-shared-ref loc) (lambda () (unbox loc)))
|
|
|
|
(define (shared-ref? form) (procedure? form))
|
|
|
|
(define (patch-ref! form) (if (procedure? form) (patch-ref! (form)) form))
|
|
|
|
(define (patch-shared! form)
|
|
|
|
(cond [(pair? form)
|
|
|
|
(if (procedure? (car form))
|
|
|
|
(set-car! form (patch-ref! (car form)))
|
|
|
|
(patch-shared! (car form)))
|
|
|
|
(if (procedure? (cdr form))
|
|
|
|
(set-cdr! form (patch-ref! (cdr form)))
|
|
|
|
(patch-shared! (cdr form)))]
|
|
|
|
[(vector? form)
|
|
|
|
(let loop ([i 0])
|
|
|
|
(when (fx<? i (vector-length form))
|
|
|
|
(let ([fi (vector-ref form i)])
|
|
|
|
(if (procedure? fi)
|
|
|
|
(vector-set! form i (patch-ref! fi))
|
|
|
|
(patch-shared! fi)))
|
|
|
|
(loop (fx+ i 1))))]
|
|
|
|
[(box? form)
|
|
|
|
(if (procedure? (unbox form))
|
|
|
|
(set-box! form (patch-shared! (unbox form)))
|
|
|
|
(patch-shared! (unbox form)))]))
|
|
|
|
(define (patch-shared form) (patch-shared! form) form)
|
|
|
|
|
|
|
|
(define reader-token-marker #f)
|
|
|
|
(define close-paren #f)
|
|
|
|
(define close-bracket #f)
|
|
|
|
(define dot #f)
|
|
|
|
(define (let ([rtm (list 'reader-token)])
|
|
|
|
(set! reader-token-marker rtm)
|
|
|
|
(set! close-paren (cons rtm "right parenthesis"))
|
|
|
|
(set! close-bracket (cons rtm "right bracket"))
|
|
|
|
(set! dot (cons rtm "\" . \""))))
|
|
|
|
|
|
|
|
(define (reader-token? form)
|
|
|
|
(and (pair? form) (eq? (car form) reader-token-marker)))
|
|
|
|
|
|
|
|
(define (char-symbolic? c)
|
|
|
|
(string-position c
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!$%&*/:<=>?^_~0123456789+-.@"))
|
|
|
|
|
|
|
|
(define (char-hex-digit? c)
|
|
|
|
(let ([scalar-value (char->integer c)])
|
|
|
|
(or (and (>= scalar-value 48) (<= scalar-value 57))
|
|
|
|
(and (>= scalar-value 65) (<= scalar-value 70))
|
|
|
|
(and (>= scalar-value 97) (<= scalar-value 102)))))
|
|
|
|
|
|
|
|
(define (char-delimiter? c)
|
|
|
|
(or (char-whitespace? c)
|
|
|
|
(char=? c #\)) (char=? c #\()
|
|
|
|
(char=? c #\]) (char=? c #\[)
|
|
|
|
(char=? c #\") (char=? c #\;)))
|
|
|
|
|
|
|
|
(define (sub-read-carefully p)
|
|
|
|
(let ([form (sub-read p)])
|
|
|
|
(cond [(eof-object? form)
|
|
|
|
(r-error p "unexpected end of file")]
|
|
|
|
[(reader-token? form)
|
|
|
|
(r-error p "unexpected token:" (cdr form))]
|
|
|
|
[else form])))
|
|
|
|
|
|
|
|
(define (sub-read p)
|
|
|
|
(let ([c (read-char p)])
|
|
|
|
(cond [(eof-object? c) c]
|
|
|
|
[(char-whitespace? c) (sub-read p)]
|
|
|
|
[(char=? c #\() (sub-read-list c p close-paren #t)]
|
|
|
|
[(char=? c #\)) close-paren]
|
|
|
|
[(char=? c #\[) (sub-read-list c p close-bracket #t)]
|
|
|
|
[(char=? c #\]) close-bracket]
|
|
|
|
[(char=? c #\') (list 'quote (sub-read-carefully p))]
|
|
|
|
[(char=? c #\`) (list 'quasiquote (sub-read-carefully p))]
|
|
|
|
[(char-symbolic? c) (sub-read-number-or-symbol c p)]
|
|
|
|
[(char=? c #\;)
|
|
|
|
(let loop ([c (read-char p)])
|
|
|
|
(or (eof-object? c) (char=? c #\newline)
|
|
|
|
(loop (read-char p))))
|
|
|
|
(sub-read p)]
|
|
|
|
[(char=? c #\,)
|
|
|
|
(let ([next (peek-char p)])
|
|
|
|
(cond [(eof-object? next)
|
|
|
|
(r-error p "end of file after ,")]
|
|
|
|
[(char=? next #\@)
|
|
|
|
(read-char p)
|
|
|
|
(list 'unquote-splicing (sub-read-carefully p))]
|
|
|
|
[else (list 'unquote (sub-read-carefully p))]))]
|
|
|
|
[(char=? c #\")
|
|
|
|
(let loop ([l '()])
|
|
|
|
(let ([c (read-char p)])
|
|
|
|
(cond [(eof-object? c)
|
|
|
|
(r-error p "end of file within a string")]
|
|
|
|
[(char=? c #\\)
|
|
|
|
(let ([e (sub-read-strsym-char-escape p 'string)])
|
|
|
|
(loop (if e (cons e l) l)))]
|
|
|
|
[(char=? c #\") (list->string (reverse! l))]
|
|
|
|
[else (loop (cons c l))])))]
|
|
|
|
[(char=? c #\|)
|
|
|
|
(let loop ([l '()])
|
|
|
|
(let ([c (read-char p)])
|
|
|
|
(cond [(eof-object? c)
|
|
|
|
(r-error p "end of file within a |symbol|")]
|
|
|
|
[(char=? c #\\)
|
|
|
|
(let ([e (sub-read-strsym-char-escape p 'symbol)])
|
|
|
|
(loop (if e (cons e l) l)))]
|
|
|
|
[(char=? c #\|) (string->symbol (list->string (reverse! l)))]
|
|
|
|
[else (loop (cons c l))])))]
|
|
|
|
[(char=? c #\#)
|
|
|
|
(let ([c (peek-char p)])
|
|
|
|
(cond [(eof-object? c) (r-error p "end of file after #")]
|
|
|
|
[(or (char-ci=? c #\t) (char-ci=? c #\f))
|
|
|
|
(let ([name (sub-read-carefully p)])
|
|
|
|
(case name [(t true) #t] [(f false) #f]
|
|
|
|
[else (r-error p "unexpected name after #" name)]))]
|
|
|
|
[(or (char-ci=? c #\b) (char-ci=? c #\o)
|
|
|
|
(char-ci=? c #\d) (char-ci=? c #\x)
|
|
|
|
(char-ci=? c #\i) (char-ci=? c #\e))
|
|
|
|
(sub-read-number-or-symbol #\# p)]
|
|
|
|
[(char=? c #\&)
|
|
|
|
(read-char p)
|
|
|
|
(box (sub-read-carefully p))]
|
|
|
|
[(char=? c #\;)
|
|
|
|
(read-char p)
|
|
|
|
(sub-read-carefully p)
|
|
|
|
(sub-read p)]
|
|
|
|
[(char=? c #\|)
|
|
|
|
(read-char p)
|
|
|
|
(let recur () ;starts right after opening #|
|
|
|
|
(let ([next (read-char p)])
|
|
|
|
(cond
|
|
|
|
[(eof-object? next)
|
|
|
|
(r-error p "end of file in #| comment")]
|
|
|
|
[(char=? next #\|)
|
|
|
|
(let ([next (peek-char p)])
|
|
|
|
(cond
|
|
|
|
[(eof-object? next)
|
|
|
|
(r-error p "end of file in #| comment")]
|
|
|
|
[(char=? next #\#) (read-char p)]
|
|
|
|
[else (recur)]))]
|
|
|
|
[(char=? next #\#)
|
|
|
|
(let ([next (peek-char p)])
|
|
|
|
(cond
|
|
|
|
[(eof-object? next)
|
|
|
|
(r-error p "end of file in #| comment")]
|
|
|
|
[(char=? next #\|) (read-char p) (recur) (recur)]
|
|
|
|
[else (recur)]))]
|
|
|
|
[else (recur)])))
|
|
|
|
(sub-read p)]
|
|
|
|
[(char=? c #\() ;)
|
|
|
|
(read-char p)
|
|
|
|
(list->vector (sub-read-list c p close-paren #f))]
|
|
|
|
[(char=? c #\u)
|
|
|
|
(read-char p)
|
|
|
|
(if (and (eq? (read-char p) #\8) (eq? (read-char p) #\())
|
|
|
|
(list->bytevector (sub-read-byte-list p))
|
|
|
|
(r-error p "invalid bytevector syntax"))]
|
|
|
|
[(char=? c #\\)
|
|
|
|
(read-char p)
|
|
|
|
(let ([c (peek-char p)])
|
|
|
|
(cond
|
|
|
|
[(eof-object? c)
|
|
|
|
(r-error p "end of file after #\\")]
|
|
|
|
[(char=? #\x c)
|
|
|
|
(read-char p)
|
|
|
|
(if (char-delimiter? (peek-char p))
|
|
|
|
c
|
|
|
|
(sub-read-x-char-escape p #f))]
|
|
|
|
[(char-alphabetic? c)
|
|
|
|
(let ([name (sub-read-carefully p)])
|
|
|
|
(if (= (string-length (symbol->string name)) 1)
|
|
|
|
c
|
|
|
|
(case name
|
|
|
|
[(null) (integer->char #x00)]
|
|
|
|
[(space) #\space]
|
|
|
|
[(alarm) #\alarm]
|
|
|
|
[(backspace) #\backspace]
|
|
|
|
[(delete) (integer->char #x7F)] ; todo: support by SFC
|
|
|
|
[(escape) (integer->char #x1B)]
|
|
|
|
[(tab) #\tab]
|
|
|
|
[(newline linefeed) #\newline]
|
|
|
|
[(vtab) #\vtab]
|
|
|
|
[(page) #\page]
|
|
|
|
[(return) #\return]
|
|
|
|
[else (r-error p "unknown #\\ name" name)])))]
|
|
|
|
[else (read-char p) c]))]
|
|
|
|
[(char-numeric? c)
|
|
|
|
(when simple? (r-error p "#N=/#N# notation is not allowed in this mode"))
|
|
|
|
(let loop ([l '()])
|
|
|
|
(let ([c (read-char p)])
|
|
|
|
(cond [(eof-object? c)
|
|
|
|
(r-error p "end of file within a #N notation")]
|
|
|
|
[(char-numeric? c)
|
|
|
|
(loop (cons c l))]
|
|
|
|
[(char=? c #\#)
|
|
|
|
(let* ([s (list->string (reverse! l))] [n (string->number s)])
|
|
|
|
(cond [(and (fixnum? n) (assq n shared)) => cdr]
|
|
|
|
[else (r-error "unknown #n# reference:" s)]))]
|
|
|
|
[(char=? c #\=)
|
|
|
|
(let* ([s (list->string (reverse! l))] [n (string->number s)])
|
|
|
|
(cond [(not (fixnum? n)) (r-error "invalid #n= reference:" s)]
|
|
|
|
[(assq n shared) (r-error "duplicate #n= tag:" n)])
|
|
|
|
(let ([loc (box #f)])
|
|
|
|
(set! shared (cons (cons n (make-shared-ref loc)) shared))
|
|
|
|
(let ([form (sub-read-carefully p)])
|
|
|
|
(cond [(shared-ref? form) (r-error "#n= has another label as target" s)]
|
|
|
|
[else (set-box! loc form) form]))))]
|
|
|
|
[else (r-error p "invalid terminator for #N notation")])))]
|
|
|
|
[else (r-error p "unknown # syntax" c)]))]
|
|
|
|
[else (r-error p "illegal character read" c)])))
|
|
|
|
|
|
|
|
(define (sub-read-list c p close-token dot?)
|
|
|
|
(let ([form (sub-read p)])
|
|
|
|
(if (eq? form dot)
|
|
|
|
(r-error p "missing car -- ( immediately followed by .") ;)
|
|
|
|
(let recur ([form form])
|
|
|
|
(cond [(eof-object? form)
|
|
|
|
(r-error p "eof inside list -- unbalanced parentheses")]
|
|
|
|
[(eq? form close-token) '()]
|
|
|
|
[(eq? form dot)
|
|
|
|
(if dot?
|
|
|
|
(let* ([last-form (sub-read-carefully p)]
|
|
|
|
[another-form (sub-read p)])
|
|
|
|
(if (eq? another-form close-token)
|
|
|
|
last-form
|
|
|
|
(r-error p "randomness after form after dot" another-form)))
|
|
|
|
(r-error p "dot in #(...)"))]
|
|
|
|
[(reader-token? form)
|
|
|
|
(r-error p "error inside list --" (cdr form))]
|
|
|
|
[else (cons form (recur (sub-read p)))])))))
|
|
|
|
|
|
|
|
(define (sub-read-byte-list p)
|
|
|
|
(let recur ([form (sub-read p)])
|
|
|
|
(cond [(eof-object? form)
|
|
|
|
(r-error p "eof inside bytevector")]
|
|
|
|
[(eq? form close-paren) '()]
|
|
|
|
[(reader-token? form)
|
|
|
|
(r-error p "error inside bytevector --" (cdr form))]
|
|
|
|
[(or (not (fixnum? form)) (fx<? form 0) (fx>? form 255))
|
|
|
|
(r-error p "invalid byte inside bytevector --" form)]
|
|
|
|
[else (cons form (recur (sub-read p)))])))
|
|
|
|
|
|
|
|
(define (sub-read-strsym-char-escape p what)
|
|
|
|
(let ([c (read-char p)])
|
|
|
|
(if (eof-object? c)
|
|
|
|
(r-error p "end of file within a" what))
|
|
|
|
(cond [(or (char=? c #\\) (char=? c #\") (char=? c #\|)) c]
|
|
|
|
[(char=? c #\a) #\alarm]
|
|
|
|
[(char=? c #\b) #\backspace]
|
|
|
|
[(char=? c #\t) #\tab]
|
|
|
|
[(char=? c #\n) #\newline]
|
|
|
|
[(char=? c #\v) #\vtab]
|
|
|
|
[(char=? c #\f) #\page]
|
|
|
|
[(char=? c #\r) #\return]
|
|
|
|
[(char=? c #\x) (sub-read-x-char-escape p #t)]
|
|
|
|
[(and (eq? what 'string) (char-whitespace? c))
|
|
|
|
(let loop ([gotnl (char=? c #\newline)] [nc (peek-char p)])
|
|
|
|
(cond [(or (eof-object? nc) (not (char-whitespace? nc)))
|
|
|
|
(if gotnl #f (r-error p "no newline in line ending escape"))]
|
|
|
|
[(and gotnl (char=? nc #\newline)) #f]
|
|
|
|
[else (read-char p) (loop (or gotnl (char=? nc #\newline)) (peek-char p))]))]
|
|
|
|
[else (r-error p "invalid char escape in" what ': c)])))
|
|
|
|
|
|
|
|
(define (sub-read-x-char-escape p in-string?)
|
|
|
|
(define (rev-digits->char l)
|
|
|
|
(if (null? l)
|
|
|
|
(r-error p "\\x escape sequence is too short")
|
|
|
|
(integer->char (string->fixnum (list->string (reverse! l)) 16))))
|
|
|
|
(let loop ([c (peek-char p)] [l '()] [cc 0])
|
|
|
|
(cond [(eof-object? c)
|
|
|
|
(if in-string?
|
|
|
|
(r-error p "end of file within a string")
|
|
|
|
(rev-digits->char l))]
|
|
|
|
[(and in-string? (char=? c #\;))
|
|
|
|
(read-char p)
|
|
|
|
(rev-digits->char l)]
|
|
|
|
[(and (not in-string?) (char-delimiter? c))
|
|
|
|
(rev-digits->char l)]
|
|
|
|
[(not (char-hex-digit? c))
|
|
|
|
(r-error p "unexpected char in \\x escape sequence" c)]
|
|
|
|
[(> cc 2)
|
|
|
|
(r-error p "\\x escape sequence is too long")]
|
|
|
|
[else
|
|
|
|
(read-char p)
|
|
|
|
(loop (peek-char p) (cons c l) (+ cc 1))])))
|
|
|
|
|
|
|
|
(define (suspect-number-or-symbol-peculiar? hash? c l s)
|
|
|
|
(cond [(or hash? (char-numeric? c)) #f]
|
|
|
|
[(or (string-ci=? s "+i") (string-ci=? s "-i")) #f]
|
|
|
|
[(or (string-ci=? s "+nan.0") (string-ci=? s "-nan.0")) #f]
|
|
|
|
[(or (string-ci=? s "+inf.0") (string-ci=? s "-inf.0")) #f]
|
|
|
|
[(or (char=? c #\+) (char=? c #\-))
|
|
|
|
(cond [(null? (cdr l)) #t]
|
|
|
|
[(char=? (cadr l) #\.) (and (pair? (cddr l)) (not (char-numeric? (caddr l))))]
|
|
|
|
[else (not (char-numeric? (cadr l)))])]
|
|
|
|
[else (and (char=? c #\.) (pair? (cdr l)) (not (char-numeric? (cadr l))))]))
|
|
|
|
|
|
|
|
(define (sub-read-number-or-symbol c p)
|
|
|
|
(let loop ([c (peek-char p)] [l (list c)] [hash? (char=? c #\#)])
|
|
|
|
(cond [(or (eof-object? c) (char-delimiter? c))
|
|
|
|
(let* ([l (reverse! l)] [c (car l)] [s (list->string l)])
|
|
|
|
(if (or hash? (char-numeric? c)
|
|
|
|
(char=? c #\+) (char=? c #\-) (char=? c #\.))
|
|
|
|
(cond [(string=? s ".") dot]
|
|
|
|
[(suspect-number-or-symbol-peculiar? hash? c l s) (string->symbol s)]
|
|
|
|
[(string->number s)]
|
|
|
|
[else (r-error p "unsupported number syntax (implementation restriction)" s)])
|
|
|
|
(string->symbol s)))]
|
|
|
|
[(char=? c #\#)
|
|
|
|
(read-char p)
|
|
|
|
(loop (peek-char p) (cons c l) #t)]
|
|
|
|
[(char-symbolic? c)
|
|
|
|
(read-char p)
|
|
|
|
(loop (peek-char p) (cons c l) hash?)]
|
|
|
|
[else (r-error p "unexpected number/symbol char" c)])))
|
|
|
|
|
|
|
|
; body of %read
|
|
|
|
(let ([form (sub-read port)])
|
|
|
|
(if (not (reader-token? form))
|
|
|
|
(if (null? shared) form (patch-shared form))
|
|
|
|
(r-error port "unexpected token:" (cdr form)))))
|
|
|
|
|
|
|
|
(define-syntax read
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (%read (current-input-port) #f)]
|
|
|
|
[(_ p) (%read p #f)]
|
|
|
|
[_ %residual-read]))
|
|
|
|
|
|
|
|
(define-syntax read-simple
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_) (%read (current-input-port) #t)]
|
|
|
|
[(_ p) (%read p #t)]
|
|
|
|
[_ %residual-read-simple]))
|
|
|
|
|
|
|
|
|
|
|
|
; file system
|
|
|
|
|
|
|
|
(define (file-exists? fn) ; fixme?
|
|
|
|
(%prim?! "{ /* file-exists? */
|
|
|
|
FILE *f = fopen(stringchars(obj_from_$arg), \"r\");
|
|
|
|
if (f != NULL) fclose(f);
|
|
|
|
$return bool(f != NULL); }" fn))
|
|
|
|
|
|
|
|
(define (delete-file fn)
|
|
|
|
(unless (%prim?! "{ /* delete-file */
|
|
|
|
int res = remove(stringchars(obj_from_$arg));
|
|
|
|
$return bool(res == 0); }" fn)
|
|
|
|
(file-error "cannot delete file:" fn)))
|
|
|
|
|
|
|
|
(define (rename-file fnold fnnew) ; not in r7rs
|
|
|
|
(unless (%prim?! "{ /* rename-file */
|
|
|
|
int res = rename(stringchars(obj_from_$arg), stringchars(obj_from_$arg));
|
|
|
|
$return bool(res == 0); }" fnold fnnew)
|
|
|
|
(file-error "cannot rename file:" fnold fnnew)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; multiple values & continuations
|
|
|
|
|
|
|
|
(define-inline (call-with-values producer consumer)
|
|
|
|
(letcc k
|
|
|
|
(withcc
|
|
|
|
(lambda results
|
|
|
|
(withcc k (apply consumer results)))
|
|
|
|
(producer))))
|
|
|
|
|
|
|
|
(define *current-dynamic-state* (list #f))
|
|
|
|
|
|
|
|
(define (call-with-current-continuation proc)
|
|
|
|
(let ([here *current-dynamic-state*])
|
|
|
|
(letcc cont
|
|
|
|
(proc
|
|
|
|
(lambda results
|
|
|
|
(dynamic-state-reroot! here)
|
|
|
|
(apply cont results))))))
|
|
|
|
|
|
|
|
(define-syntax call/cc call-with-current-continuation)
|
|
|
|
|
|
|
|
(define-syntax throw
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ k expr ...)
|
|
|
|
(withcc (%prim "ktrap()") (k expr ...))]))
|
|
|
|
|
|
|
|
(define-syntax values
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ expr ...)
|
|
|
|
(call/cc (lambda (k) (throw k expr ...)))]
|
|
|
|
[_ %residual-values]))
|
|
|
|
|
|
|
|
(define (dynamic-wind before during after)
|
|
|
|
(let ([here *current-dynamic-state*])
|
|
|
|
(dynamic-state-reroot! (cons (cons before after) here))
|
|
|
|
(call-with-values during
|
|
|
|
(lambda results
|
|
|
|
(dynamic-state-reroot! here)
|
|
|
|
(apply values results)))))
|
|
|
|
|
|
|
|
(define (dynamic-state-reroot! there)
|
|
|
|
(if (not (eq? *current-dynamic-state* there))
|
|
|
|
(begin (dynamic-state-reroot! (cdr there))
|
|
|
|
(let ([before (caar there)] [after (cdar there)])
|
|
|
|
(set-car! *current-dynamic-state* (cons after before))
|
|
|
|
(set-cdr! *current-dynamic-state* there)
|
|
|
|
(set-car! there #f)
|
|
|
|
(set-cdr! there '())
|
|
|
|
(set! *current-dynamic-state* there)
|
|
|
|
(before)))))
|
|
|
|
|
|
|
|
|
|
|
|
; exceptions and errors
|
|
|
|
|
|
|
|
(define-record-type <error-object>
|
|
|
|
(error-object kind message irritants)
|
|
|
|
error-object?
|
|
|
|
(kind error-object-kind)
|
|
|
|
(message error-object-message)
|
|
|
|
(irritants error-object-irritants))
|
|
|
|
|
|
|
|
(define (error msg . args)
|
|
|
|
(raise (error-object #f msg args)))
|
|
|
|
|
|
|
|
(define current-exception-handler
|
|
|
|
(make-parameter
|
|
|
|
(letrec
|
|
|
|
([default-handler
|
|
|
|
(case-lambda
|
|
|
|
[() default-handler] ;this one its own parent
|
|
|
|
[(obj)
|
|
|
|
(if (error-object? obj)
|
|
|
|
(apply simple-error (error-object-kind obj) (error-object-message obj) (error-object-irritants obj))
|
|
|
|
(simple-error #f "unhandled exception" obj))])])
|
|
|
|
default-handler)))
|
|
|
|
|
|
|
|
(define (with-exception-handler handler thunk)
|
|
|
|
(let ([eh (current-exception-handler)])
|
|
|
|
(parameterize ([current-exception-handler (case-lambda [() eh] [(obj) (handler obj)])])
|
|
|
|
(thunk))))
|
|
|
|
|
|
|
|
(define (raise obj)
|
|
|
|
(let ([eh (current-exception-handler)])
|
|
|
|
(parameterize ([current-exception-handler (eh)])
|
|
|
|
(eh obj)
|
|
|
|
(raise (error-object 'raise "exception handler returned" (list eh obj))))))
|
|
|
|
|
|
|
|
(define (raise-continuable obj)
|
|
|
|
(let ([eh (current-exception-handler)])
|
|
|
|
(parameterize ([current-exception-handler (eh)])
|
|
|
|
(eh obj))))
|
|
|
|
|
|
|
|
(define-inline (abort) (%prim! "void(exit(1))"))
|
|
|
|
(define (reset) (%prim! "void(exit(1))"))
|
|
|
|
(define (set-reset-handler! fn) (set! reset fn))
|
|
|
|
|
|
|
|
(define-syntax guard
|
|
|
|
(letrec-syntax
|
|
|
|
([guard-aux
|
|
|
|
(syntax-rules (else =>)
|
|
|
|
[(guard-aux reraise (else result1 result2 ...))
|
|
|
|
(begin result1 result2 ...)]
|
|
|
|
[(guard-aux reraise (test => result))
|
|
|
|
(let ([temp test]) (if temp (result temp) reraise))]
|
|
|
|
[(guard-aux reraise (test => result) clause1 clause2 ...)
|
|
|
|
(let ([temp test])
|
|
|
|
(if temp
|
|
|
|
(result temp)
|
|
|
|
(guard-aux reraise clause1 clause2 ...)))]
|
|
|
|
[(guard-aux reraise (test)) (or test reraise)]
|
|
|
|
[(guard-aux reraise (test) clause1 clause2 ...)
|
|
|
|
(let ([temp test])
|
|
|
|
(if temp temp (guard-aux reraise clause1 clause2 ...)))]
|
|
|
|
[(guard-aux reraise (test result1 result2 ...))
|
|
|
|
(if test (begin result1 result2 ...) reraise)]
|
|
|
|
[(guard-aux reraise (test result1 result2 ...) clause1 clause2 ...)
|
|
|
|
(if test
|
|
|
|
(begin result1 result2 ...)
|
|
|
|
(guard-aux reraise clause1 clause2 ...))])])
|
|
|
|
(syntax-rules ()
|
|
|
|
[(guard (var clause ...) e1 e2 ...)
|
|
|
|
((call/cc
|
|
|
|
(lambda (guard-k)
|
|
|
|
(with-exception-handler
|
|
|
|
(lambda (condition)
|
|
|
|
((call/cc
|
|
|
|
(lambda (handler-k)
|
|
|
|
(guard-k
|
|
|
|
(lambda ()
|
|
|
|
(let ([var condition])
|
|
|
|
(guard-aux
|
|
|
|
(handler-k
|
|
|
|
(lambda ()
|
|
|
|
(raise-continuable condition)))
|
|
|
|
clause
|
|
|
|
...))))))))
|
|
|
|
(lambda ()
|
|
|
|
(call-with-values
|
|
|
|
(lambda () e1 e2 ...)
|
|
|
|
(lambda args
|
|
|
|
(guard-k (lambda () (apply values args))))))))))])))
|
|
|
|
|
|
|
|
|
|
|
|
(define (read-error msg . args)
|
|
|
|
(raise (error-object 'read msg args)))
|
|
|
|
|
|
|
|
(define (read-error? obj)
|
|
|
|
(and (error-object? obj) (eq? (error-object-kind obj) 'read)))
|
|
|
|
|
|
|
|
(define (file-error msg . args)
|
|
|
|
(raise (error-object 'file msg args)))
|
|
|
|
|
|
|
|
(define (file-error? obj)
|
|
|
|
(and (error-object? obj) (eq? (error-object-kind obj) 'file)))
|
|
|
|
|
|
|
|
|
|
|
|
; time
|
|
|
|
|
|
|
|
(define-inline (current-jiffy)
|
|
|
|
(%prim*! "flonum($live, clock())"))
|
|
|
|
|
|
|
|
(define-inline (jiffies-per-second)
|
|
|
|
(%prim* "flonum($live, CLOCKS_PER_SEC)"))
|
|
|
|
|
|
|
|
(define-inline (current-second)
|
|
|
|
(%prim* "flonum($live, difftime(time(NULL), 0)+37.0)"))
|
|
|
|
|
|
|
|
|
|
|
|
; miscellaneous / system
|
|
|
|
|
|
|
|
(define emergency-exit
|
|
|
|
(case-lambda ; exits no matter what
|
|
|
|
[() (%prim! "void(exit(0))")]
|
|
|
|
[(n) (cond [(eq? n #t) (%prim! "void(exit(0))")]
|
|
|
|
[(fixnum? n) (%prim! "void(exit(fixnum_from_$arg))" n)]
|
|
|
|
[else (%prim! "void(exit(1))")])]
|
|
|
|
[args (%prim! "void(exit(1))")]))
|
|
|
|
|
|
|
|
(define exit
|
|
|
|
(let ([exit-ds *current-dynamic-state*])
|
|
|
|
(lambda args
|
|
|
|
(dynamic-state-reroot! exit-ds)
|
|
|
|
(apply emergency-exit args))))
|
|
|
|
|
|
|
|
(define-inline (argv-ref argv i)
|
|
|
|
(%prim* "{ /* argv-ref */
|
|
|
|
int i = fixnum_from_$arg;
|
|
|
|
char *s = ((char **)(obj_from_$arg))[i];
|
|
|
|
if (s) $return obj(hpushstr($live, newstring(s)));
|
|
|
|
else $return bool(0); }" i argv))
|
|
|
|
|
|
|
|
(define (command-line)
|
|
|
|
(let loop ([r '()] [i (%prim "fixnum(0)")])
|
|
|
|
(let ([arg (argv-ref (%prim "obj(cxg_argv)") i)])
|
|
|
|
(if arg
|
|
|
|
(loop (cons arg r) (fx+ i (%prim "fixnum(1)")))
|
|
|
|
(reverse! r)))))
|
|
|
|
|
|
|
|
(define-inline (get-environment-variable s)
|
|
|
|
(%prim*? "{ /* get-environment-variable */
|
|
|
|
char *v = getenv(stringchars(obj_from_$arg));
|
|
|
|
if (v) $return obj(hpushstr($live, newstring(v)));
|
|
|
|
else $return bool(0); }" s))
|
|
|
|
|
|
|
|
(define-inline (system cmd)
|
|
|
|
(%prim?! "{ /* system */
|
|
|
|
int res = system(stringchars(obj_from_$arg));
|
|
|
|
$return fixnum(res); }" cmd))
|
|
|
|
|
|
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
; stubs
|
|
|
|
|
|
|
|
(define-inline (make-rectangular r i)
|
|
|
|
(if (= i 0) r (error 'make-rectangular "nonzero imag part not supported" i)))
|
|
|
|
(define-inline (make-polar m a)
|
|
|
|
(cond [(= a 0) m]
|
|
|
|
[(= a 3.141592653589793238462643) (- m)]
|
|
|
|
[else (error 'make-polar "angle not supported" a)]))
|
|
|
|
(define-inline (real-part x) x)
|
|
|
|
(define-inline (imag-part x) 0)
|
|
|
|
(define-inline (magnitude x) (abs x))
|
|
|
|
(define-inline (angle x) (if (negative? x) 3.141592653589793238462643 0))
|
|
|
|
|
|
|
|
|
|
|
|
; procedures requiring call-with-values / values
|
|
|
|
|
|
|
|
(define (truncate/ x y)
|
|
|
|
(values (truncate-quotient x y) (truncate-remainder x y)))
|
|
|
|
|
|
|
|
(define (floor/ x y)
|
|
|
|
(values (floor-quotient x y) (floor-remainder x y)))
|
|
|
|
|
|
|
|
(define (exact-integer-sqrt x)
|
|
|
|
(let ([r (fxsqrt x)])
|
|
|
|
(values r (- x (* r r)))))
|
|
|
|
|
|
|
|
(define (call-with-port port proc)
|
|
|
|
(call-with-values (lambda () (proc port))
|
|
|
|
(lambda vals (close-port port) (apply values vals))))
|
|
|
|
|
|
|
|
|
|
|
|
; procedures of variable arity (plain and making use of case-lambda)
|
|
|
|
|
|
|
|
(define string->list
|
|
|
|
(case-lambda
|
|
|
|
[(str) (substring->list str 0 (string-length str))]
|
|
|
|
[(str start) (substring->list str start (string-length str))]
|
|
|
|
[(str start end) (substring->list str start end)]))
|
|
|
|
|
|
|
|
(define string-copy
|
|
|
|
(case-lambda
|
|
|
|
[(str) (%string-copy str)]
|
|
|
|
[(str start) (substring str start (string-length str))]
|
|
|
|
[(str start end) (substring str start end)]))
|
|
|
|
|
|
|
|
(define string-copy!
|
|
|
|
(case-lambda
|
|
|
|
[(to at from) (substring-copy! to at from 0 (string-length from))]
|
|
|
|
[(to at from start) (substring-copy! to at from start (string-length from))]
|
|
|
|
[(to at from start end) (substring-copy! to at from start end)]))
|
|
|
|
|
|
|
|
(define string-fill!
|
|
|
|
(case-lambda
|
|
|
|
[(str c) (%string-fill! str c)]
|
|
|
|
[(str c start) (substring-fill! str c start (string-length str))]
|
|
|
|
[(str c start end) (substring-fill! str c start end)]))
|
|
|
|
|
|
|
|
(define vector->list
|
|
|
|
(case-lambda
|
|
|
|
[(vec) (subvector->list vec 0 (vector-length vec))]
|
|
|
|
[(vec start) (subvector->list vec start (vector-length vec))]
|
|
|
|
[(vec start end) (subvector->list vec start end)]))
|
|
|
|
|
|
|
|
(define vector->string
|
|
|
|
(case-lambda
|
|
|
|
[(vec) (subvector->string vec 0 (vector-length vec))]
|
|
|
|
[(vec start) (subvector->string vec start (vector-length vec))]
|
|
|
|
[(vec start end) (subvector->string vec start end)]))
|
|
|
|
|
|
|
|
(define string->vector
|
|
|
|
(case-lambda
|
|
|
|
[(str) (substring->vector str 0 (string-length str))]
|
|
|
|
[(str start) (substring->vector str start (string-length str))]
|
|
|
|
[(str start end) (substring->vector str start end)]))
|
|
|
|
|
|
|
|
(define vector-copy!
|
|
|
|
(case-lambda
|
|
|
|
[(to at from) (subvector-copy! to at from 0 (vector-length from))]
|
|
|
|
[(to at from start) (subvector-copy! to at from start (vector-length from))]
|
|
|
|
[(to at from start end) (subvector-copy! to at from start end)]))
|
|
|
|
|
|
|
|
(define vector-copy
|
|
|
|
(case-lambda
|
|
|
|
[(vec) (subvector vec 0 (vector-length vec))]
|
|
|
|
[(vec start) (subvector vec start (vector-length vec))]
|
|
|
|
[(vec start end) (subvector vec start end)]))
|
|
|
|
|
|
|
|
(define (%vectors-sum-length vecs)
|
|
|
|
(let loop ([vecs vecs] [l 0])
|
|
|
|
(if (null? vecs) l (loop (cdr vecs) (fx+ l (vector-length (car vecs)))))))
|
|
|
|
|
|
|
|
(define (%vectors-copy-into! to vecs)
|
|
|
|
(let loop ([vecs vecs] [i 0])
|
|
|
|
(if (null? vecs)
|
|
|
|
to
|
|
|
|
(let ([vec (car vecs)] [vecs (cdr vecs)])
|
|
|
|
(let ([len (vector-length vec)])
|
|
|
|
(subvector-copy! to i vec 0 len)
|
|
|
|
(loop vecs (fx+ i len)))))))
|
|
|
|
|
|
|
|
(define (vector-append . vecs)
|
|
|
|
(%vectors-copy-into! (make-vector (%vectors-sum-length vecs)) vecs))
|
|
|
|
|
|
|
|
(define vector-fill!
|
|
|
|
(case-lambda
|
|
|
|
[(vec x) (subvector-fill! vec x 0 (vector-length vec))]
|
|
|
|
[(vec x start) (subvector-fill! vec x start (vector-length vec))]
|
|
|
|
[(vec x start end) (subvector-fill! vec x start end)]))
|
|
|
|
|
|
|
|
(define bytevector->list
|
|
|
|
(case-lambda
|
|
|
|
[(vec) (subbytevector->list vec 0 (bytevector-length vec))]
|
|
|
|
[(vec start) (subbytevector->list vec start (bytevector-length vec))]
|
|
|
|
[(vec start end) (subbytevector->list vec start end)]))
|
|
|
|
|
|
|
|
(define bytevector-copy!
|
|
|
|
(case-lambda
|
|
|
|
[(to at from) (subbytevector-copy! to at from 0 (bytevector-length from))]
|
|
|
|
[(to at from start) (subbytevector-copy! to at from start (bytevector-length from))]
|
|
|
|
[(to at from start end) (subbytevector-copy! to at from start end)]))
|
|
|
|
|
|
|
|
(define bytevector-copy
|
|
|
|
(case-lambda
|
|
|
|
[(vec) (subbytevector vec 0 (bytevector-length vec))]
|
|
|
|
[(vec start) (subbytevector vec start (bytevector-length vec))]
|
|
|
|
[(vec start end) (subbytevector vec start end)]))
|
|
|
|
|
|
|
|
(define (%bytevectors-sum-length vecs)
|
|
|
|
(let loop ([vecs vecs] [l 0])
|
|
|
|
(if (null? vecs) l (loop (cdr vecs) (fx+ l (bytevector-length (car vecs)))))))
|
|
|
|
|
|
|
|
(define (%bytevectors-copy-into! to vecs)
|
|
|
|
(let loop ([vecs vecs] [i 0])
|
|
|
|
(if (null? vecs)
|
|
|
|
to
|
|
|
|
(let ([vec (car vecs)] [vecs (cdr vecs)])
|
|
|
|
(let ([len (bytevector-length vec)])
|
|
|
|
(subbytevector-copy! to i vec 0 len)
|
|
|
|
(loop vecs (fx+ i len)))))))
|
|
|
|
|
|
|
|
(define (bytevector-append . vecs)
|
|
|
|
(%bytevectors-copy-into! (make-bytevector (%bytevectors-sum-length vecs)) vecs))
|
|
|
|
|
|
|
|
(define (subutf8->string vec start end)
|
|
|
|
(let ([p (open-output-string)])
|
|
|
|
(write-subbytevector vec start end p)
|
|
|
|
; todo: make a single operation: get-final-output-string (can reuse cbuf?)
|
|
|
|
(let ([s (get-output-string p)]) (close-output-port p) s)))
|
|
|
|
|
|
|
|
(define utf8->string
|
|
|
|
(case-lambda
|
|
|
|
[(vec) (%prim*? "{ /* bytevector->string */
|
|
|
|
int *d = bytevectordata(obj_from_$arg);
|
|
|
|
$return obj(hpushstr($live, newstringn((char *)bvdatabytes(d), *d))); }" vec)]
|
|
|
|
[(vec start) (subutf8->string vec start (bytevector-length vec))]
|
|
|
|
[(vec start end) (subutf8->string vec start end)]))
|
|
|
|
|
|
|
|
(define (substring->utf8 str start end)
|
|
|
|
(let ([p (open-output-bytevector)])
|
|
|
|
(write-substring str start end p)
|
|
|
|
; todo: make a single operation: get-final-output-bytevector (can reuse cbuf?)
|
|
|
|
(let ([v (get-output-bytevector p)]) (close-output-port p) v)))
|
|
|
|
|
|
|
|
(define string->utf8
|
|
|
|
(case-lambda
|
|
|
|
[(str) (%prim*? "{ /* string->bytevector */
|
|
|
|
int *d = stringdata(obj_from_$arg);
|
|
|
|
$return obj(hpushu8v($live, newbytevector((unsigned char *)sdatachars(d), *d))); }" str)]
|
|
|
|
[(str start) (substring->utf8 str start (string-length str))]
|
|
|
|
[(str start end) (substring->utf8 str start end)]))
|
|
|
|
|
|
|
|
(define read-string!
|
|
|
|
(case-lambda
|
|
|
|
[(str) (read-substring! str 0 (string-length str) (current-input-port))]
|
|
|
|
[(str p) (read-substring! str 0 (string-length str) p)]
|
|
|
|
[(str p start) (read-substring! str start (string-length str) p)]
|
|
|
|
[(str p start end) (read-substring! str start end p)]))
|
|
|
|
|
|
|
|
(define read-string
|
|
|
|
(case-lambda
|
|
|
|
[(k) (read-substring k (current-input-port))]
|
|
|
|
[(k p) (read-substring k p)]))
|
|
|
|
|
|
|
|
(define read-bytevector!
|
|
|
|
(case-lambda
|
|
|
|
[(vec) (read-subbytevector! vec 0 (bytevector-length vec) (current-input-port))]
|
|
|
|
[(vec p) (read-subbytevector! vec 0 (bytevector-length vec) p)]
|
|
|
|
[(vec p start) (read-subbytevector! vec start (bytevector-length vec) p)]
|
|
|
|
[(vec p start end) (read-subbytevector! vec start end p)]))
|
|
|
|
|
|
|
|
(define read-bytevector
|
|
|
|
(case-lambda
|
|
|
|
[(k) (read-subbytevector k (current-input-port))]
|
|
|
|
[(k p) (read-subbytevector k p)]))
|
|
|
|
|
|
|
|
|
|
|
|
; residual versions of inline procedures
|
|
|
|
|
|
|
|
(define (%residual-values . l)
|
|
|
|
(call/cc (lambda (k) (throw apply k l))))
|
|
|
|
|
|
|
|
(define-syntax cmp-reducer
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda args
|
|
|
|
(or (null? args)
|
|
|
|
(let loop ([x (car args)] [args (cdr args)])
|
|
|
|
(or (null? args)
|
|
|
|
(let ([y (car args)])
|
|
|
|
(and (f x y) (loop y (cdr args))))))))]))
|
|
|
|
|
|
|
|
(define %residual-boolean=? (cmp-reducer boolean=?))
|
|
|
|
|
|
|
|
(define %residual-fx=? (cmp-reducer fx=?))
|
|
|
|
(define %residual-fx<? (cmp-reducer fx<?))
|
|
|
|
(define %residual-fx>? (cmp-reducer fx>?))
|
|
|
|
(define %residual-fx<=? (cmp-reducer fx<=?))
|
|
|
|
(define %residual-fx>=? (cmp-reducer fx>=?))
|
|
|
|
(define %residual-fl=? (cmp-reducer fl=?))
|
|
|
|
(define %residual-fl<? (cmp-reducer fl<?))
|
|
|
|
(define %residual-fl>? (cmp-reducer fl>?))
|
|
|
|
(define %residual-fl<=? (cmp-reducer fl<=?))
|
|
|
|
(define %residual-fl>=? (cmp-reducer fl>=?))
|
|
|
|
(define %residual= (cmp-reducer =))
|
|
|
|
(define %residual< (cmp-reducer <))
|
|
|
|
(define %residual> (cmp-reducer >))
|
|
|
|
(define %residual<= (cmp-reducer <=))
|
|
|
|
(define %residual>= (cmp-reducer >=))
|
|
|
|
|
|
|
|
(define-syntax minmax-reducer
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda (x . args)
|
|
|
|
(let loop ([x x] [args args])
|
|
|
|
(if (null? args)
|
|
|
|
x
|
|
|
|
(loop (f x (car args)) (cdr args)))))]))
|
|
|
|
|
|
|
|
(define %residual-fxmax (minmax-reducer fxmax))
|
|
|
|
(define %residual-fxmin (minmax-reducer fxmin))
|
|
|
|
(define %residual-flmax (minmax-reducer flmax))
|
|
|
|
(define %residual-flmin (minmax-reducer flmin))
|
|
|
|
|
|
|
|
(define (%residual-max/2 a b)
|
|
|
|
(if (fixnum? a)
|
|
|
|
(if (fixnum? b)
|
|
|
|
(if (fx>? a b) a b)
|
|
|
|
(let ([a (fixnum->flonum a)]) (if (fl>? a b) a b)))
|
|
|
|
(if (fixnum? b)
|
|
|
|
(let ([b (fixnum->flonum b)]) (if (fl>? a b) a b))
|
|
|
|
(if (fl>? a b) a b))))
|
|
|
|
(define %residual-max (minmax-reducer %residual-max/2))
|
|
|
|
|
|
|
|
(define (%residual-min/2 a b)
|
|
|
|
(if (fixnum? a)
|
|
|
|
(if (fixnum? b)
|
|
|
|
(if (fx<? a b) a b)
|
|
|
|
(let ([a (fixnum->flonum a)]) (if (fl<? a b) a b)))
|
|
|
|
(if (fixnum? b)
|
|
|
|
(let ([b (fixnum->flonum b)]) (if (fl<? a b) a b))
|
|
|
|
(if (fl<? a b) a b))))
|
|
|
|
(define %residual-min (minmax-reducer %residual-min/2))
|
|
|
|
|
|
|
|
(define-syntax addmul-reducer
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f s)
|
|
|
|
(lambda args
|
|
|
|
(if (null? args)
|
|
|
|
s
|
|
|
|
(let loop ([x (car args)] [args (cdr args)])
|
|
|
|
(if (null? args)
|
|
|
|
x
|
|
|
|
(loop (f x (car args)) (cdr args))))))]))
|
|
|
|
|
|
|
|
(define %residual-fx+ (addmul-reducer fx+ 0))
|
|
|
|
(define %residual-fx* (addmul-reducer fx* 1))
|
|
|
|
(define %residual-fl+ (addmul-reducer fl+ 0.0))
|
|
|
|
(define %residual-fl* (addmul-reducer fl* 1.0))
|
|
|
|
(define %residual+ (addmul-reducer + 0))
|
|
|
|
(define %residual* (addmul-reducer * 1))
|
|
|
|
(define %residual-gcd (addmul-reducer gcd 0))
|
|
|
|
(define %residual-lcm (addmul-reducer lcm 1))
|
|
|
|
|
|
|
|
(define-syntax subdiv-reducer
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda (x . args)
|
|
|
|
(if (null? args)
|
|
|
|
(f x)
|
|
|
|
(let loop ([x x] [args args])
|
|
|
|
(if (null? args)
|
|
|
|
x
|
|
|
|
(loop (f x (car args)) (cdr args))))))]))
|
|
|
|
|
|
|
|
(define %residual-fx- (subdiv-reducer fx-))
|
|
|
|
(define %residual-fx/ (subdiv-reducer fx/))
|
|
|
|
(define %residual-fl- (subdiv-reducer fl-))
|
|
|
|
(define %residual-fl/ (subdiv-reducer fl/))
|
|
|
|
(define %residual- (subdiv-reducer -))
|
|
|
|
(define %residual/ (subdiv-reducer /))
|
|
|
|
|
|
|
|
(define-syntax nullary-unary-adaptor
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda args
|
|
|
|
(if (null? args) (f) (f (car args))))]))
|
|
|
|
|
|
|
|
(define-syntax nullary-unary-binary-adaptor
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda args
|
|
|
|
(if (null? args) (f) (if (null? (cdr args)) (f (car args)) (f (car args) (cadr args)))))]))
|
|
|
|
|
|
|
|
(define-syntax unary-binary-adaptor
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda (x . args)
|
|
|
|
(if (null? args) (f x) (f x (car args))))]))
|
|
|
|
|
|
|
|
(define-syntax unary-binary-ternary-adaptor
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda (x . args)
|
|
|
|
(if (null? args) (f x) (if (null? (cdr args)) (f x (car args)) (f x (car args) (cadr args)))))]))
|
|
|
|
|
|
|
|
(define-syntax unary-binary-ternary-quaternary-adaptor
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda (x . args)
|
|
|
|
(if (null? args) (f x) (if (null? (cdr args)) (f x (car args))
|
|
|
|
(if (null? (cddr args)) (f x (car args) (cadr args)) (f x (car args) (cadr args) (caddr args))))))]))
|
|
|
|
|
|
|
|
(define-syntax binary-ternary-adaptor
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda (x y . args)
|
|
|
|
(if (null? args) (f x y) (f x y (car args))))]))
|
|
|
|
|
|
|
|
(define-syntax binary-ternary-quaternary-adaptor
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f)
|
|
|
|
(lambda (x y . args)
|
|
|
|
(if (null? args) (f x y)
|
|
|
|
(if (null? (cdr args)) (f x y (car args)) (f x y (car args) (cadr args)))))]))
|
|
|
|
|
|
|
|
(define %residual-log (unary-binary-adaptor log))
|
|
|
|
|
|
|
|
(define %residual-flatan (unary-binary-adaptor flatan))
|
|
|
|
(define %residual-atan (unary-binary-adaptor atan))
|
|
|
|
|
|
|
|
(define %residual-member (binary-ternary-adaptor member))
|
|
|
|
(define %residual-assoc (binary-ternary-adaptor assoc))
|
|
|
|
|
|
|
|
(define (%residual-map p l . l*)
|
|
|
|
(if (null? l*)
|
|
|
|
(let loop ([l l] [r '()])
|
|
|
|
(if (pair? l) (loop (cdr l) (cons (p (car l)) r)) (reverse! r)))
|
|
|
|
(let loop ([l* (cons l l*)] [r '()])
|
|
|
|
(if (let lp ([l* l*]) (or (null? l*) (and (pair? (car l*)) (lp (cdr l*)))))
|
|
|
|
(loop (map cdr l*) (cons (apply p (map car l*)) r))
|
|
|
|
(reverse! r)))))
|
|
|
|
|
|
|
|
(define (%residual-for-each p l . l*)
|
|
|
|
(if (null? l*)
|
|
|
|
(let loop ([l l]) (if (pair? l) (begin (p (car l)) (loop (cdr l)))))
|
|
|
|
(let loop ([l* (cons l l*)])
|
|
|
|
(if (let lp ([l* l*]) (or (null? l*) (and (pair? (car l*)) (lp (cdr l*)))))
|
|
|
|
(begin (apply p (map car l*)) (loop (map cdr l*)))))))
|
|
|
|
|
|
|
|
(define (string-map p s . s*)
|
|
|
|
(if (null? s*)
|
|
|
|
(let* ([len (string-length s)] [res (make-string len)])
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx>=? i len) res]
|
|
|
|
(string-set! res i (p (string-ref s i)))))
|
|
|
|
(list->string (apply map p (map string->list (cons s s*))))))
|
|
|
|
|
|
|
|
(define (vector-map p v . v*)
|
|
|
|
(if (null? v*)
|
|
|
|
(let* ([len (vector-length v)] [res (make-vector len)])
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx>=? i len) res]
|
|
|
|
(vector-set! res i (p (vector-ref v i)))))
|
|
|
|
(list->vector (apply map p (map vector->list (cons v v*))))))
|
|
|
|
|
|
|
|
(define (string-for-each p s . s*)
|
|
|
|
(if (null? s*)
|
|
|
|
(let ([len (string-length s)])
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx>=? i len)] (p (string-ref s i))))
|
|
|
|
(apply for-each p (map string->list (cons s s*)))))
|
|
|
|
|
|
|
|
(define (vector-for-each p v . v*)
|
|
|
|
(if (null? v*)
|
|
|
|
(let ([len (vector-length v)])
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx>=? i len)] (p (vector-ref v i))))
|
|
|
|
(apply for-each p (map vector->list (cons v v*)))))
|
|
|
|
|
|
|
|
(define-syntax append-reducer
|
|
|
|
(syntax-rules ()
|
|
|
|
[(_ f s)
|
|
|
|
(lambda args
|
|
|
|
(let loop ([args args])
|
|
|
|
(cond [(null? args) s]
|
|
|
|
[(null? (cdr args)) (car args)]
|
|
|
|
[else (f (car args) (loop (cdr args)))])))]))
|
|
|
|
|
|
|
|
(define %residual-char=? (cmp-reducer char=?))
|
|
|
|
(define %residual-char<? (cmp-reducer char<?))
|
|
|
|
(define %residual-char>? (cmp-reducer char>?))
|
|
|
|
(define %residual-char<=? (cmp-reducer char<=?))
|
|
|
|
(define %residual-char>=? (cmp-reducer char>=?))
|
|
|
|
(define %residual-char-ci=? (cmp-reducer char-ci=?))
|
|
|
|
(define %residual-char-ci<? (cmp-reducer char-ci<?))
|
|
|
|
(define %residual-char-ci>? (cmp-reducer char-ci>?))
|
|
|
|
(define %residual-char-ci<=? (cmp-reducer char-ci<=?))
|
|
|
|
(define %residual-char-ci>=? (cmp-reducer char-ci>=?))
|
|
|
|
|
|
|
|
(define %residual-make-string (unary-binary-adaptor make-string))
|
|
|
|
|
|
|
|
(define (%residual-string . l)
|
|
|
|
(list->string l))
|
|
|
|
|
|
|
|
(define %residual-string-append (append-reducer string-append ""))
|
|
|
|
|
|
|
|
(define %residual-string=? (cmp-reducer string=?))
|
|
|
|
(define %residual-string<? (cmp-reducer string<?))
|
|
|
|
(define %residual-string>? (cmp-reducer string>?))
|
|
|
|
(define %residual-string<=? (cmp-reducer string<=?))
|
|
|
|
(define %residual-string>=? (cmp-reducer string>=?))
|
|
|
|
(define %residual-string-ci=? (cmp-reducer string-ci=?))
|
|
|
|
(define %residual-string-ci<? (cmp-reducer string-ci<?))
|
|
|
|
(define %residual-string-ci>? (cmp-reducer string-ci>?))
|
|
|
|
(define %residual-string-ci<=? (cmp-reducer string-ci<=?))
|
|
|
|
(define %residual-string-ci>=? (cmp-reducer string-ci>=?))
|
|
|
|
|
|
|
|
(define %residual-make-vector (unary-binary-adaptor make-vector))
|
|
|
|
|
|
|
|
(define (%residual-vector . l)
|
|
|
|
(list->vector l))
|
|
|
|
|
|
|
|
(define %residual-make-bytevector (unary-binary-adaptor make-bytevector))
|
|
|
|
|
|
|
|
(define (%residual-bytevector . l)
|
|
|
|
(list->bytevector l))
|
|
|
|
|
|
|
|
(define (%residual-list . l) l)
|
|
|
|
|
|
|
|
(define %residual-make-list (unary-binary-adaptor make-list))
|
|
|
|
|
|
|
|
(define (%residual-cons* x . l)
|
|
|
|
(let loop ([x x] [l l])
|
|
|
|
(if (null? l) x (cons x (loop (car l) (cdr l))))))
|
|
|
|
|
|
|
|
(define %residual-append (append-reducer append '()))
|
|
|
|
|
|
|
|
(define %residual-record? (unary-binary-adaptor record?))
|
|
|
|
|
|
|
|
(define %residual-number->string (unary-binary-adaptor number->string))
|
|
|
|
(define %residual-string->number (unary-binary-adaptor string->number))
|
|
|
|
|
|
|
|
(define %residual-symbol=? (cmp-reducer symbol=?))
|
|
|
|
|
|
|
|
(define (%fail-lambda . args)
|
|
|
|
(error 'case-lambda "unexpected number of arguments" args))
|
|
|
|
|
|
|
|
(define (%residual-make-case-lambda . l)
|
|
|
|
(%prim* "{ /* %residual-make-case-lambda */
|
|
|
|
obj l; int i, c = fixnum_from_$arg;
|
|
|
|
hreserve(hbsz(c+1), $live); /* $live live regs */
|
|
|
|
l = obj_from_$arg; /* gc-safe */
|
|
|
|
for (i = 0; i < c; ++i, l = cdr(l)) hp[i-c] = car(l);
|
|
|
|
hp -= c; *--hp = obj_from_objptr(appcases+4);
|
|
|
|
$return obj(hendblk(c+1)); }" (length l) l))
|
|
|
|
|
|
|
|
(define %residual-current-input-port (nullary-unary-binary-adaptor current-input-port))
|
|
|
|
(define %residual-current-output-port (nullary-unary-binary-adaptor current-output-port))
|
|
|
|
(define %residual-current-error-port (nullary-unary-binary-adaptor current-error-port))
|
|
|
|
|
|
|
|
(define %residual-read-char (nullary-unary-adaptor read-char))
|
|
|
|
(define %residual-peek-char (nullary-unary-adaptor peek-char))
|
|
|
|
(define %residual-char-ready? (nullary-unary-adaptor char-ready?))
|
|
|
|
(define %residual-read-line (nullary-unary-adaptor read-line))
|
|
|
|
|
|
|
|
(define %residual-display-fixnum (unary-binary-adaptor display-fixnum))
|
|
|
|
(define %residual-display-flonum (unary-binary-adaptor display-flonum))
|
|
|
|
(define %residual-display-procedure (unary-binary-adaptor display-procedure))
|
|
|
|
(define %residual-display-input-port (unary-binary-adaptor display-input-port))
|
|
|
|
(define %residual-display-output-port (unary-binary-adaptor display-output-port))
|
|
|
|
|
|
|
|
(define %residual-write-char (unary-binary-adaptor write-char))
|
|
|
|
(define %residual-write-string (unary-binary-ternary-quaternary-adaptor write-string))
|
|
|
|
(define %residual-newline (nullary-unary-adaptor newline))
|
|
|
|
(define %residual-flush-output-port (nullary-unary-adaptor flush-output-port))
|
|
|
|
|
|
|
|
(define %residual-read-u8 (nullary-unary-adaptor read-u8))
|
|
|
|
(define %residual-peek-u8 (nullary-unary-adaptor peek-u8))
|
|
|
|
(define %residual-u8-ready? (nullary-unary-adaptor u8-ready?))
|
|
|
|
(define %residual-write-u8 (unary-binary-adaptor write-u8))
|
|
|
|
(define %residual-write-bytevector (unary-binary-ternary-quaternary-adaptor write-bytevector))
|
|
|
|
|
|
|
|
(define %residual-write-simple (unary-binary-adaptor write-simple))
|
|
|
|
(define %residual-write-shared (unary-binary-adaptor write-shared))
|
|
|
|
(define %residual-write (unary-binary-adaptor write))
|
|
|
|
(define %residual-display (unary-binary-adaptor display))
|
|
|
|
|
|
|
|
(define %residual-read (nullary-unary-adaptor read))
|
|
|
|
(define %residual-read-simple (nullary-unary-adaptor read-simple))
|
|
|
|
|
|
|
|
(define %residual-exit (nullary-unary-adaptor exit))
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
;
|
|
|
|
; Stack-Based Model compiler/vm, derived from
|
|
|
|
;
|
|
|
|
; Three Implementation Models for Scheme
|
|
|
|
; TR87-0ll
|
|
|
|
; 1987
|
|
|
|
; R. Kent Dybvig
|
|
|
|
;
|
|
|
|
; https://www.cs.unc.edu/techreports/87-011.pdf
|
|
|
|
;
|
|
|
|
;
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
; Utils
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(define set-member?
|
|
|
|
(lambda (x s)
|
|
|
|
(cond
|
|
|
|
[(null? s) #f]
|
|
|
|
[(eq? x (car s)) #t]
|
|
|
|
[else (set-member? x (cdr s))])))
|
|
|
|
|
|
|
|
(define set-cons
|
|
|
|
(lambda (x s)
|
|
|
|
(if (set-member? x s)
|
|
|
|
s
|
|
|
|
(cons x s))))
|
|
|
|
|
|
|
|
(define set-union
|
2023-03-06 04:19:29 +01:00
|
|
|
(lambda (s1 s2)
|
|
|
|
(if (null? s1)
|
2023-02-28 06:31:08 +01:00
|
|
|
s2
|
2023-03-06 04:19:29 +01:00
|
|
|
(set-union (cdr s1) (set-cons (car s1) s2)))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define set-minus
|
2023-03-06 04:19:29 +01:00
|
|
|
(lambda (s1 s2)
|
|
|
|
(if (null? s1)
|
2023-02-28 06:31:08 +01:00
|
|
|
'()
|
2023-03-06 04:19:29 +01:00
|
|
|
(if (set-member? (car s1) s2)
|
|
|
|
(set-minus (cdr s1) s2)
|
|
|
|
(cons (car s1) (set-minus (cdr s1) s2))))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define set-intersect
|
2023-03-06 04:19:29 +01:00
|
|
|
(lambda (s1 s2)
|
|
|
|
(if (null? s1)
|
2023-02-28 06:31:08 +01:00
|
|
|
'()
|
2023-03-06 04:19:29 +01:00
|
|
|
(if (set-member? (car s1) s2)
|
|
|
|
(cons (car s1) (set-intersect (cdr s1) s2))
|
|
|
|
(set-intersect (cdr s1) s2)))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define-syntax record-case
|
|
|
|
(syntax-rules (else)
|
|
|
|
[(record-case (pa . ir) clause ...)
|
|
|
|
(let ([id (pa . ir)])
|
|
|
|
(record-case id clause ...))]
|
|
|
|
[(record-case id)
|
|
|
|
'record-case-miss]
|
|
|
|
[(record-case id [else exp ...])
|
|
|
|
(begin exp ...)]
|
2024-06-13 21:49:33 +02:00
|
|
|
[(record-case id [(key ...) ids exp ...] clause ...)
|
|
|
|
(if (memq (car id) '(key ...))
|
|
|
|
(apply (lambda ids exp ...) (cdr id))
|
|
|
|
(record-case id clause ...))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(record-case id [key ids exp ...] clause ...)
|
|
|
|
(if (eq? (car id) 'key)
|
|
|
|
(apply (lambda ids exp ...) (cdr id))
|
|
|
|
(record-case id clause ...))]))
|
|
|
|
|
|
|
|
(define syntax-match?
|
|
|
|
(lambda (pat exp)
|
|
|
|
(or (eq? pat '*)
|
|
|
|
(equal? exp pat)
|
|
|
|
(and (pair? pat)
|
|
|
|
(cond
|
|
|
|
[(and (eq? (car pat) '$)
|
|
|
|
(pair? (cdr pat))
|
|
|
|
(null? (cddr pat)))
|
|
|
|
(eq? exp (cadr pat))]
|
|
|
|
[(and (pair? (cdr pat))
|
|
|
|
(eq? (cadr pat) '...)
|
|
|
|
(null? (cddr pat)))
|
|
|
|
(let ([pat (car pat)])
|
|
|
|
(define (f lst)
|
|
|
|
(or (null? lst)
|
|
|
|
(and (pair? lst)
|
|
|
|
(syntax-match? pat (car lst))
|
|
|
|
(f (cdr lst)))))
|
|
|
|
(f exp))]
|
|
|
|
[else
|
|
|
|
(and (pair? exp)
|
|
|
|
(syntax-match? (car pat) (car exp))
|
|
|
|
(syntax-match? (cdr pat) (cdr exp)))])))))
|
|
|
|
|
|
|
|
; unique symbol generator (poor man's version)
|
|
|
|
(define gensym
|
|
|
|
(let ([gsc 0])
|
|
|
|
(lambda args ; (), (symbol), or (#f) for gsc reset
|
|
|
|
(set! gsc (fx+ gsc 1))
|
|
|
|
(if (null? args)
|
|
|
|
(string->symbol
|
|
|
|
(string-append "#" (fixnum->string gsc 10)))
|
|
|
|
(if (symbol? (car args))
|
|
|
|
(string->symbol
|
|
|
|
(string-append (symbol->string (car args))
|
|
|
|
(string-append "#" (fixnum->string gsc 10))))
|
|
|
|
(set! gsc 0))))))
|
|
|
|
|
|
|
|
(define posq
|
|
|
|
(lambda (x l)
|
|
|
|
(let loop ([l l] [n 0])
|
|
|
|
(cond [(null? l) #f]
|
|
|
|
[(eq? x (car l)) n]
|
|
|
|
[else (loop (cdr l) (fx+ n 1))]))))
|
|
|
|
|
|
|
|
(define list-diff
|
|
|
|
(lambda (l t)
|
|
|
|
(if (or (null? l) (eq? l t))
|
|
|
|
'()
|
|
|
|
(cons (car l) (list-diff (cdr l) t)))))
|
|
|
|
|
|
|
|
(define (pair* x . more)
|
|
|
|
(let loop ([x x] [rest more])
|
|
|
|
(if (null? rest) x
|
|
|
|
(cons x (loop (car rest) (cdr rest))))))
|
|
|
|
|
2023-03-12 21:54:44 +01:00
|
|
|
(define (andmap p l)
|
|
|
|
(if (pair? l) (and (p (car l)) (andmap p (cdr l))) #t))
|
|
|
|
|
2023-03-04 06:07:52 +01:00
|
|
|
(define (list1? x) (and (pair? x) (null? (cdr x))))
|
2023-03-11 07:50:00 +01:00
|
|
|
(define (list1+? x) (and (pair? x) (list? (cdr x))))
|
2023-03-04 06:07:52 +01:00
|
|
|
(define (list2? x) (and (pair? x) (list1? (cdr x))))
|
2023-03-11 07:50:00 +01:00
|
|
|
(define (list2+? x) (and (pair? x) (list1+? (cdr x))))
|
2023-03-04 06:07:52 +01:00
|
|
|
|
2023-03-19 00:13:38 +01:00
|
|
|
(define integrable?
|
|
|
|
(%prim "{ /* define integrable? */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+8) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(define lookup-integrable
|
|
|
|
(%prim "{ /* define lookup-integrable */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+9) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(define integrable-type
|
|
|
|
(%prim "{ /* define integrable-type */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+10) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(define integrable-global
|
|
|
|
(%prim "{ /* define integrable-global */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+11) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(define integrable-code
|
|
|
|
(%prim "{ /* define integrable-code */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+12) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
; Syntax of the Scheme Core language
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
; <core> -> (quote <object>)
|
|
|
|
; <core> -> (ref <id>)
|
|
|
|
; <core> -> (set! <id> <core>)
|
2023-03-12 21:54:44 +01:00
|
|
|
; <core> -> (set& <id>)
|
2023-02-28 06:31:08 +01:00
|
|
|
; <core> -> (lambda <ids> <core>) where <ids> -> (<id> ...) | (<id> ... . <id>) | <id>
|
2023-03-22 18:21:48 +01:00
|
|
|
; <core> -> (lambda* (<arity> <core>) ...) where <arity> -> (<cnt> <rest?>)
|
|
|
|
; <core> -> (syntax-lambda (<id> ...) <core>)
|
2023-03-10 23:30:41 +01:00
|
|
|
; <core> -> (letcc <id> <core>)
|
|
|
|
; <core> -> (withcc <core> <core>)
|
2023-02-28 06:31:08 +01:00
|
|
|
; <core> -> (begin <core> ...)
|
|
|
|
; <core> -> (if <core> <core> <core>)
|
2023-03-07 19:11:46 +01:00
|
|
|
; <core> -> (call <core> <core> ...)
|
2023-03-21 20:29:28 +01:00
|
|
|
; <core> -> (integrable <ig> <core> ...) where <ig> is an index in the integrables table
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
; NB: (begin) is legit, returns unspecified value
|
|
|
|
; on top level, these two extra core forms are legal:
|
|
|
|
|
|
|
|
; <core> -> (define <id> <core>)
|
|
|
|
; <core> -> (define-syntax <id> <transformer>)
|
|
|
|
|
2023-03-12 21:54:44 +01:00
|
|
|
(define idslist?
|
|
|
|
(lambda (x)
|
|
|
|
(cond [(null? x) #t]
|
|
|
|
[(pair? x) (and (id? (car x)) (idslist? (cdr x)))]
|
|
|
|
[else (id? x)])))
|
|
|
|
|
2023-03-07 19:11:46 +01:00
|
|
|
(define normalize-arity
|
|
|
|
(lambda (arity)
|
|
|
|
(if (and (list2? arity) (fixnum? (car arity)) (boolean? (cadr arity)))
|
|
|
|
arity
|
|
|
|
(let loop ([cnt 0] [l arity])
|
|
|
|
(cond [(pair? l) (loop (fx+ 1 cnt) (cdr l))]
|
|
|
|
[(null? l) (list cnt #f)]
|
|
|
|
[else (list cnt #t)])))))
|
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
; convention for 'flattened' <ids> is to put rest arg if any at the front
|
|
|
|
(define flatten-idslist
|
|
|
|
(lambda (ilist)
|
|
|
|
(if (list? ilist) ilist
|
|
|
|
(let loop ([l ilist] [r '()])
|
|
|
|
(cond [(pair? l) (loop (cdr l) (cons (car l) r))]
|
|
|
|
[else (if (null? l) (reverse! r) (cons l (reverse! r)))])))))
|
|
|
|
|
|
|
|
(define idslist-req-count
|
|
|
|
(lambda (ilist)
|
|
|
|
(if (pair? ilist)
|
|
|
|
(fx+ 1 (idslist-req-count (cdr ilist)))
|
|
|
|
0)))
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
; Macro transformer (from Scheme to Scheme Core) derived from Al Petrofsky's EIOD 1.17
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
2023-04-16 03:03:39 +02:00
|
|
|
; An environment is a procedure that accepts any identifier and returns a denotation.
|
|
|
|
; The denotation of an identifier is its macro location, which is a cell storing the
|
|
|
|
; identifier's current syntactic value. Location's value can be changed later.
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
; Special forms are either a symbol naming a builtin, or a transformer procedure
|
|
|
|
; that takes two arguments: a macro use and the environment of the macro use.
|
|
|
|
|
2023-04-16 00:08:08 +02:00
|
|
|
; <identifier> -> <symbol> | <thunk returning (sym . den)>
|
2023-04-16 03:03:39 +02:00
|
|
|
; <denotation> -> <location>
|
|
|
|
; <location> -> #&<value>
|
2023-03-01 23:36:24 +01:00
|
|
|
; <value> -> <special> | <core>
|
|
|
|
; <special> -> <builtin> | <transformer>
|
2024-07-07 03:03:12 +02:00
|
|
|
; <builtin> -> syntax-quote | quote | set! | set& | if | lambda | lambda* |
|
2023-04-16 00:08:08 +02:00
|
|
|
; letcc | withcc | body | begin | define | define-syntax |
|
|
|
|
; syntax-lambda | syntax-rules | syntax-length | syntax-error
|
2023-03-01 23:36:24 +01:00
|
|
|
; <transformer> -> <procedure of exp and env returning exp>
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define-inline (val-core? val) (pair? val))
|
|
|
|
|
2023-04-16 03:03:39 +02:00
|
|
|
(define-inline (make-location v) (box v))
|
|
|
|
(define-inline (location-val l) (unbox l))
|
|
|
|
(define-inline (location-set-val! l v) (set-box! l v))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-04-16 03:03:39 +02:00
|
|
|
(define (location-special? l) (not (pair? (unbox l))))
|
2023-04-16 00:08:08 +02:00
|
|
|
(define (new-id sym den) (define p (cons sym den)) (lambda () p))
|
|
|
|
(define (old-sym id) (car (id)))
|
|
|
|
(define (old-den id) (cdr (id)))
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (id? x) (or (symbol? x) (procedure? x)))
|
2023-04-16 00:08:08 +02:00
|
|
|
(define (id->sym id) (if (symbol? id) id (old-sym id)))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (extend-xenv env id bnd) (lambda (i) (if (eq? id i) bnd (env i))))
|
|
|
|
|
2023-04-16 03:03:39 +02:00
|
|
|
(define (add-location key val env) ; adds as-is
|
|
|
|
(extend-xenv env key (make-location val)))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (add-var var val env) ; adds renamed var as <core>
|
2023-04-16 03:03:39 +02:00
|
|
|
(extend-xenv env var (make-location (list 'ref val))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-04-14 20:49:32 +02:00
|
|
|
(define (xform-sexp->datum sexp)
|
|
|
|
(let conv ([sexp sexp])
|
|
|
|
(cond [(id? sexp) (id->sym sexp)]
|
|
|
|
[(pair? sexp) (cons (conv (car sexp)) (conv (cdr sexp)))]
|
|
|
|
[(vector? sexp) (list->vector (map conv (vector->list sexp)))]
|
|
|
|
[else sexp])))
|
|
|
|
|
2023-03-21 23:02:01 +01:00
|
|
|
(define (x-error msg . args)
|
2023-03-22 18:21:48 +01:00
|
|
|
(error* (string-append "transformer: " msg) args))
|
2023-03-21 23:02:01 +01:00
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
; xform receives Scheme s-expressions and returns either Core Scheme <core>
|
|
|
|
; (always a pair) or special-form, which is either a builtin (a symbol) or
|
2023-03-21 23:02:01 +01:00
|
|
|
; a transformer (a procedure). Appos? flag is true when the context can
|
|
|
|
; allow xform to return a transformer; otherwise, only <core> is accepted.
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (xform appos? sexp env)
|
|
|
|
(cond [(id? sexp)
|
|
|
|
(let ([hval (xform-ref sexp env)])
|
2023-03-19 00:13:38 +01:00
|
|
|
(cond [appos? hval]
|
|
|
|
[(integrable? hval) ; integrable id-syntax
|
|
|
|
(list 'ref (integrable-global hval))]
|
|
|
|
[(procedure? hval) ; id-syntax
|
|
|
|
(xform appos? (hval sexp env) env)]
|
2023-04-16 03:03:39 +02:00
|
|
|
[(not (pair? hval)) ; special used out of context
|
2023-03-22 19:20:17 +01:00
|
|
|
(x-error "improper use of syntax form" hval)]
|
2023-04-16 03:03:39 +02:00
|
|
|
[else hval]))] ; core
|
2023-03-19 00:13:38 +01:00
|
|
|
[(not (pair? sexp))
|
2023-03-21 23:02:01 +01:00
|
|
|
(xform-quote (list sexp) env)]
|
2023-03-19 00:13:38 +01:00
|
|
|
[else
|
|
|
|
(let* ([head (car sexp)] [tail (cdr sexp)] [hval (xform #t head env)])
|
|
|
|
(case hval
|
2024-07-07 03:03:12 +02:00
|
|
|
[(syntax-quote) (car tail)] ; internal use only
|
2023-03-21 23:02:01 +01:00
|
|
|
[(quote) (xform-quote tail env)]
|
|
|
|
[(set!) (xform-set! tail env)]
|
|
|
|
[(set&) (xform-set& tail env)]
|
|
|
|
[(if) (xform-if tail env)]
|
|
|
|
[(lambda) (xform-lambda tail env)]
|
|
|
|
[(lambda*) (xform-lambda* tail env)]
|
|
|
|
[(letcc) (xform-letcc tail env)]
|
|
|
|
[(withcc) (xform-withcc tail env)]
|
|
|
|
[(body) (xform-body tail env)]
|
2023-04-14 20:49:32 +02:00
|
|
|
[(begin) (xform-begin tail env)]
|
2023-03-21 23:02:01 +01:00
|
|
|
[(define) (xform-define tail env)]
|
|
|
|
[(define-syntax) (xform-define-syntax tail env)]
|
2023-04-14 00:31:20 +02:00
|
|
|
[(syntax-lambda) (xform-syntax-lambda tail env)]
|
|
|
|
[(syntax-rules) (xform-syntax-rules tail env)]
|
2023-03-29 00:14:45 +02:00
|
|
|
[(syntax-length) (xform-syntax-length tail env)]
|
|
|
|
[(syntax-error) (xform-syntax-error tail env)]
|
2023-03-19 00:13:38 +01:00
|
|
|
[else (if (integrable? hval)
|
|
|
|
(xform-integrable hval tail env)
|
|
|
|
(if (procedure? hval)
|
|
|
|
(xform appos? (hval sexp env) env)
|
|
|
|
(xform-call hval tail env)))]))]))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (xform-ref id env)
|
|
|
|
(let ([den (env id)])
|
2023-04-16 03:03:39 +02:00
|
|
|
(cond [(eq? (location-val den) '...) (x-error "improper use of ...")]
|
|
|
|
[else (location-val den)])))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-21 23:02:01 +01:00
|
|
|
(define (xform-quote tail env)
|
|
|
|
(if (list1? tail)
|
2023-03-29 00:14:45 +02:00
|
|
|
(list 'quote (xform-sexp->datum (car tail)))
|
2023-03-21 23:02:01 +01:00
|
|
|
(x-error "improper quote form" (cons 'quote tail))))
|
|
|
|
|
|
|
|
(define (xform-set! tail env)
|
|
|
|
(if (and (list2? tail) (id? (car tail)))
|
|
|
|
(let ([den (env (car tail))] [xexp (xform #f (cadr tail) env)])
|
2023-04-16 03:03:39 +02:00
|
|
|
(cond [(location-special? den) (location-set-val! den xexp) '(begin)]
|
|
|
|
[else (let ([val (location-val den)])
|
2023-03-21 23:02:01 +01:00
|
|
|
(if (eq? (car val) 'ref)
|
|
|
|
(list 'set! (cadr val) xexp)
|
|
|
|
(x-error "set! to non-identifier form")))]))
|
|
|
|
(x-error "improper set! form" (cons 'set! tail))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-12 21:54:44 +01:00
|
|
|
(define (xform-set& tail env)
|
|
|
|
(if (list1? tail)
|
|
|
|
(let ([den (env (car tail))])
|
2023-04-16 03:03:39 +02:00
|
|
|
(cond [(location-special? den) (x-error "set& of a non-variable")]
|
|
|
|
[else (let ([val (location-val den)])
|
2023-03-12 21:54:44 +01:00
|
|
|
(if (eq? (car val) 'ref)
|
|
|
|
(list 'set& (cadr val))
|
2023-03-21 23:02:01 +01:00
|
|
|
(x-error "set& of a non-variable")))]))
|
|
|
|
(x-error "improper set& form" (cons 'set& tail))))
|
2023-03-12 21:54:44 +01:00
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (xform-if tail env)
|
|
|
|
(if (list? tail)
|
|
|
|
(let ([xexps (map (lambda (sexp) (xform #f sexp env)) tail)])
|
|
|
|
(case (length xexps)
|
|
|
|
[(2) (cons 'if (append xexps '((begin))))]
|
|
|
|
[(3) (cons 'if xexps)]
|
2023-03-21 23:02:01 +01:00
|
|
|
[else (x-error "malformed if form" (cons 'if tail))]))
|
|
|
|
(x-error "improper if form" (cons 'if tail))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (xform-call xexp tail env)
|
|
|
|
(if (list? tail)
|
|
|
|
(let ([xexps (map (lambda (sexp) (xform #f sexp env)) tail)])
|
|
|
|
(if (and (null? xexps) (eq? (car xexp) 'lambda) (null? (cadr xexp)))
|
|
|
|
(caddr xexp) ; ((let () x)) => x
|
|
|
|
(pair* 'call xexp xexps)))
|
2023-03-21 23:02:01 +01:00
|
|
|
(x-error "improper application" (cons xexp tail))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-19 00:13:38 +01:00
|
|
|
(define (integrable-argc-match? igt n)
|
|
|
|
(case igt
|
2023-03-20 21:43:06 +01:00
|
|
|
[(#\0) (= n 0)] [(#\1) (= n 1)] [(#\2) (= n 2)] [(#\3) (= n 3)]
|
|
|
|
[(#\p) (>= n 0)] [(#\m) (>= n 1)] [(#\c) (>= n 2)] [(#\x) (>= n 1)]
|
2023-03-28 21:39:00 +02:00
|
|
|
[(#\u) (<= 0 n 1)] [(#\b) (<= 1 n 2)] [(#\t) (<= 2 n 3)]
|
2023-03-21 18:43:26 +01:00
|
|
|
[(#\#) (>= n 0)] [(#\@) #f]
|
2023-04-14 17:34:47 +02:00
|
|
|
[else #f]))
|
2023-03-19 00:13:38 +01:00
|
|
|
|
|
|
|
(define (xform-integrable ig tail env)
|
|
|
|
(if (integrable-argc-match? (integrable-type ig) (length tail))
|
|
|
|
(cons 'integrable (cons ig (map (lambda (sexp) (xform #f sexp env)) tail)))
|
2023-03-20 18:49:00 +01:00
|
|
|
(xform-call (list 'ref (integrable-global ig)) tail env)))
|
2023-03-19 00:13:38 +01:00
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (xform-lambda tail env)
|
2023-03-12 21:54:44 +01:00
|
|
|
(if (and (list1+? tail) (idslist? (car tail)))
|
2023-02-28 06:31:08 +01:00
|
|
|
(let loop ([vars (car tail)] [ienv env] [ipars '()])
|
|
|
|
(cond [(pair? vars)
|
2023-03-22 18:21:48 +01:00
|
|
|
(let* ([var (car vars)] [nvar (gensym (id->sym var))])
|
|
|
|
(loop (cdr vars) (add-var var nvar ienv) (cons nvar ipars)))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(null? vars)
|
2023-03-22 18:21:48 +01:00
|
|
|
(list 'lambda (reverse ipars) (xform-body (cdr tail) ienv))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[else ; improper
|
2023-03-12 21:54:44 +01:00
|
|
|
(let* ([var vars] [nvar (gensym (id->sym var))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[ienv (add-var var nvar ienv)])
|
2023-03-22 18:21:48 +01:00
|
|
|
(list 'lambda (append (reverse ipars) nvar)
|
|
|
|
(xform-body (cdr tail) ienv)))]))
|
2023-03-21 23:02:01 +01:00
|
|
|
(x-error "improper lambda body" (cons 'lambda tail))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-07 19:11:46 +01:00
|
|
|
(define (xform-lambda* tail env)
|
|
|
|
(if (list? tail)
|
|
|
|
(cons 'lambda*
|
|
|
|
(map (lambda (aexp)
|
2023-03-12 21:54:44 +01:00
|
|
|
(if (and (list2? aexp)
|
2023-03-22 18:21:48 +01:00
|
|
|
(or (and (list2? (car aexp))
|
|
|
|
(fixnum? (caar aexp))
|
|
|
|
(boolean? (cadar aexp)))
|
2023-03-12 21:54:44 +01:00
|
|
|
(idslist? (car aexp))))
|
2023-03-07 19:11:46 +01:00
|
|
|
(list (normalize-arity (car aexp))
|
|
|
|
(xform #f (cadr aexp) env))
|
2023-03-21 23:02:01 +01:00
|
|
|
(x-error "improper lambda* clause" aexp)))
|
2023-03-07 19:11:46 +01:00
|
|
|
tail))
|
2023-03-21 23:02:01 +01:00
|
|
|
(x-error "improper lambda* form" (cons 'lambda* tail))))
|
2023-03-07 19:11:46 +01:00
|
|
|
|
2023-03-10 23:30:41 +01:00
|
|
|
(define (xform-letcc tail env)
|
2023-03-11 07:50:00 +01:00
|
|
|
(if (and (list2+? tail) (id? (car tail)))
|
2023-03-10 23:30:41 +01:00
|
|
|
(let* ([var (car tail)] [nvar (gensym (id->sym var))])
|
|
|
|
(list 'letcc nvar
|
2023-03-11 07:50:00 +01:00
|
|
|
(xform-body (cdr tail) (add-var var nvar env))))
|
2023-03-21 23:02:01 +01:00
|
|
|
(x-error "improper letcc form" (cons 'letcc tail))))
|
2023-03-10 23:30:41 +01:00
|
|
|
|
|
|
|
(define (xform-withcc tail env)
|
2023-03-11 07:50:00 +01:00
|
|
|
(if (list2+? tail)
|
2023-03-10 23:30:41 +01:00
|
|
|
(list 'withcc (xform #f (car tail) env)
|
2023-03-11 07:50:00 +01:00
|
|
|
(xform-body (cdr tail) env))
|
2023-03-21 23:02:01 +01:00
|
|
|
(x-error "improper withcc form" (cons 'withcc tail))))
|
2023-03-10 23:30:41 +01:00
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (xform-body tail env)
|
2023-03-24 19:16:10 +01:00
|
|
|
(cond
|
|
|
|
[(null? tail)
|
|
|
|
(list 'begin)]
|
2023-04-04 02:41:15 +02:00
|
|
|
[(list1? tail) ; can't have defines there
|
|
|
|
(xform #f (car tail) env)]
|
2023-03-24 19:16:10 +01:00
|
|
|
[(not (list? tail))
|
|
|
|
(x-error "improper body form" (cons 'body tail))]
|
|
|
|
[else
|
|
|
|
(let loop ([env env] [ids '()] [inits '()] [nids '()] [body tail])
|
|
|
|
(if (and (pair? body) (pair? (car body)))
|
|
|
|
(let ([first (car body)] [rest (cdr body)])
|
|
|
|
(let* ([head (car first)] [tail (cdr first)] [hval (xform #t head env)])
|
|
|
|
(case hval
|
2023-04-13 23:59:31 +02:00
|
|
|
[(begin) ; internal
|
2023-03-24 19:16:10 +01:00
|
|
|
(if (list? tail)
|
|
|
|
(loop env ids inits nids (append tail rest))
|
|
|
|
(x-error "improper begin form" first))]
|
2023-04-13 23:59:31 +02:00
|
|
|
[(define) ; internal
|
|
|
|
(cond [(and (list2? tail) (null? (car tail))) ; idless
|
|
|
|
(let ([init (cadr tail)])
|
|
|
|
(loop env (cons #f ids) (cons init inits) (cons #f nids) rest))]
|
|
|
|
[(and (list2? tail) (id? (car tail)))
|
|
|
|
(let* ([id (car tail)] [init (cadr tail)]
|
|
|
|
[nid (gensym (id->sym id))] [env (add-var id nid env)])
|
|
|
|
(loop env (cons id ids) (cons init inits) (cons nid nids) rest))]
|
|
|
|
[(and (list2+? tail) (pair? (car tail)) (id? (caar tail)) (idslist? (cdar tail)))
|
2023-04-16 03:03:39 +02:00
|
|
|
(let* ([id (caar tail)] [lambda-id (new-id 'lambda (make-location 'lambda))]
|
2023-04-13 23:59:31 +02:00
|
|
|
[init (cons lambda-id (cons (cdar tail) (cdr tail)))]
|
|
|
|
[nid (gensym (id->sym id))] [env (add-var id nid env)])
|
|
|
|
(loop env (cons id ids) (cons init inits) (cons nid nids) rest))]
|
|
|
|
[else (x-error "improper define form" first)])]
|
|
|
|
[(define-syntax) ; internal
|
2023-03-24 19:16:10 +01:00
|
|
|
(if (and (list2? tail) (id? (car tail)))
|
|
|
|
(let* ([id (car tail)] [init (cadr tail)]
|
2023-04-16 03:03:39 +02:00
|
|
|
[env (add-location id '(undefined) env)])
|
2023-03-24 19:16:10 +01:00
|
|
|
(loop env (cons id ids) (cons init inits) (cons #t nids) rest))
|
|
|
|
(x-error "improper define-syntax form" first))]
|
|
|
|
[else
|
|
|
|
(if (procedure? hval)
|
|
|
|
(loop env ids inits nids (cons (hval first env) rest))
|
|
|
|
(xform-labels (reverse ids) (reverse inits) (reverse nids) body env))])))
|
|
|
|
(xform-labels (reverse ids) (reverse inits) (reverse nids) body env)))]))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (xform-labels ids inits nids body env)
|
|
|
|
(let loop ([ids ids] [inits inits] [nids nids] [sets '()] [lids '()])
|
|
|
|
(cond [(null? ids)
|
2023-03-24 19:16:10 +01:00
|
|
|
(let* ([xexps (append (reverse sets) (map (lambda (x) (xform #f x env)) body))]
|
|
|
|
[xexp (if (list1? xexps) (car xexps) (cons 'begin xexps))])
|
|
|
|
(if (null? lids) xexp
|
2023-02-28 06:31:08 +01:00
|
|
|
(pair* 'call (list 'lambda (reverse lids) xexp)
|
|
|
|
(map (lambda (lid) '(begin)) lids))))]
|
2023-03-24 19:16:10 +01:00
|
|
|
[(not (car ids)) ; idless define
|
|
|
|
(loop (cdr ids) (cdr inits) (cdr nids)
|
|
|
|
(cons (xform #f (car inits) env) sets) lids)]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(symbol? (car nids)) ; define
|
|
|
|
(loop (cdr ids) (cdr inits) (cdr nids)
|
2023-03-21 23:02:01 +01:00
|
|
|
(cons (xform-set! (list (car ids) (car inits)) env) sets)
|
2023-02-28 06:31:08 +01:00
|
|
|
(cons (car nids) lids))]
|
|
|
|
[else ; define-syntax
|
2023-04-16 03:03:39 +02:00
|
|
|
(location-set-val! (env (car ids)) (xform #t (car inits) env))
|
2023-02-28 06:31:08 +01:00
|
|
|
(loop (cdr ids) (cdr inits) (cdr nids) sets lids)])))
|
|
|
|
|
2023-04-14 20:49:32 +02:00
|
|
|
(define (xform-begin tail env) ; top-level
|
|
|
|
(if (list? tail)
|
|
|
|
(let ([xexps (map (lambda (sexp) (xform #f sexp env)) tail)])
|
|
|
|
(if (and (pair? xexps) (null? (cdr xexps)))
|
|
|
|
(car xexps) ; (begin x) => x
|
|
|
|
(cons 'begin xexps)))
|
|
|
|
(x-error "improper begin form" (cons 'begin! tail))))
|
|
|
|
|
2023-04-13 23:59:31 +02:00
|
|
|
(define (xform-define tail env) ; top-level
|
|
|
|
(cond [(and (list2? tail) (null? (car tail))) ; idless
|
|
|
|
(xform #f (cadr tail) env)]
|
|
|
|
[(and (list2? tail) (id? (car tail)))
|
|
|
|
(list 'define (id->sym (car tail))
|
|
|
|
(xform #f (cadr tail) env))]
|
|
|
|
[(and (list2+? tail) (pair? (car tail)) (id? (caar tail)) (idslist? (cdar tail)))
|
|
|
|
(list 'define (id->sym (caar tail))
|
|
|
|
(xform-lambda (cons (cdar tail) (cdr tail)) env))]
|
|
|
|
[else
|
|
|
|
(x-error "improper define form" (cons 'define tail))]))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-04-13 23:59:31 +02:00
|
|
|
(define (xform-define-syntax tail env) ; top-level
|
2023-03-21 23:02:01 +01:00
|
|
|
(if (and (list2? tail) (id? (car tail)))
|
|
|
|
(list 'define-syntax (id->sym (car tail)) (xform #t (cadr tail) env))
|
|
|
|
(x-error "improper define-syntax form" (cons 'define-syntax tail))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-04-14 00:31:20 +02:00
|
|
|
(define (xform-syntax-lambda tail env)
|
|
|
|
(if (and (list2+? tail) (andmap id? (car tail)))
|
|
|
|
(let ([vars (car tail)] [macenv env] [forms (cdr tail)])
|
|
|
|
; return a transformer that wraps xformed body in (syntax ...)
|
|
|
|
(lambda (use useenv)
|
|
|
|
(if (and (list1+? use) (fx=? (length vars) (length (cdr use))))
|
|
|
|
(let loop ([vars vars] [exps (cdr use)] [env macenv])
|
|
|
|
(if (null? vars)
|
2024-07-07 03:03:12 +02:00
|
|
|
(list 'syntax-quote (xform-body forms env))
|
2023-04-14 00:31:20 +02:00
|
|
|
(loop (cdr vars) (cdr exps)
|
2023-04-16 03:03:39 +02:00
|
|
|
(add-location (car vars)
|
2023-04-14 00:31:20 +02:00
|
|
|
(xform #t (car exps) useenv) env))))
|
|
|
|
(x-error "invalif syntax-lambda application" use))))
|
|
|
|
(x-error "improper syntax-lambda body" (cons 'syntax-lambda tail))))
|
|
|
|
|
|
|
|
(define (xform-syntax-rules tail env)
|
|
|
|
(cond [(and (list2+? tail) (id? (car tail)) (andmap id? (cadr tail)))
|
|
|
|
(syntax-rules* env (car tail) (cadr tail) (cddr tail))]
|
|
|
|
[(and (list1+? tail) (andmap id? (car tail)))
|
|
|
|
(syntax-rules* env #f (car tail) (cdr tail))]
|
|
|
|
[else
|
|
|
|
(x-error "improper syntax-rules form" (cons 'syntax-rules tail))]))
|
|
|
|
|
|
|
|
(define (xform-syntax-length tail env)
|
|
|
|
(if (and (list1? tail) (list? (car tail)))
|
|
|
|
(list 'quote (length (car tail)))
|
|
|
|
(x-error "improper syntax-length form" (cons 'syntax-length tail))))
|
|
|
|
|
|
|
|
(define (xform-syntax-error tail env)
|
|
|
|
(let ([args (map xform-sexp->datum tail)])
|
|
|
|
(if (and (list1+? args) (string? (car args)))
|
|
|
|
(apply x-error args)
|
|
|
|
(x-error "improper syntax-error form" (cons 'syntax-error tail)))))
|
|
|
|
|
2023-04-16 03:03:39 +02:00
|
|
|
(define *transformers*
|
2023-03-01 23:36:24 +01:00
|
|
|
(list
|
2024-07-07 03:03:12 +02:00
|
|
|
(cons 'syntax-quote 'syntax-quote)
|
2023-04-16 03:03:39 +02:00
|
|
|
(cons 'quote 'quote)
|
|
|
|
(cons 'set! 'set!)
|
|
|
|
(cons 'set& 'set&)
|
|
|
|
(cons 'if 'if)
|
|
|
|
(cons 'lambda 'lambda)
|
|
|
|
(cons 'lambda* 'lambda*)
|
|
|
|
(cons 'letcc 'letcc)
|
|
|
|
(cons 'withcc 'withcc)
|
|
|
|
(cons 'body 'body)
|
|
|
|
(cons 'begin 'begin)
|
|
|
|
(cons 'define 'define)
|
|
|
|
(cons 'define-syntax 'define-syntax)
|
|
|
|
(cons 'syntax-lambda 'syntax-lambda)
|
|
|
|
(cons 'syntax-rules 'syntax-rules)
|
|
|
|
(cons 'syntax-length 'syntax-length)
|
|
|
|
(cons 'syntax-error 'syntax-error)
|
2024-07-05 19:09:50 +02:00
|
|
|
(cons 'define-library 'define-library)
|
2024-07-15 00:43:44 +02:00
|
|
|
(cons 'program 'program)
|
2024-07-05 19:09:50 +02:00
|
|
|
(cons 'import 'import)
|
2024-07-15 00:43:44 +02:00
|
|
|
(cons 'export 'export)
|
|
|
|
(cons '... '...)
|
|
|
|
(cons '_ '_)))
|
2023-04-16 03:03:39 +02:00
|
|
|
|
|
|
|
(define *top-transformer-env* #f)
|
2023-03-01 23:36:24 +01:00
|
|
|
|
2023-03-03 01:27:09 +01:00
|
|
|
(define (top-transformer-env id)
|
2023-04-16 03:03:39 +02:00
|
|
|
(unless *top-transformer-env*
|
|
|
|
(set! *top-transformer-env*
|
|
|
|
(map (lambda (bnd)
|
|
|
|
(let ([v (cdr bnd)])
|
|
|
|
(when (and (pair? v) (eq? (car v) 'syntax-rules))
|
|
|
|
(set! v
|
|
|
|
(if (id? (cadr v))
|
|
|
|
(syntax-rules* top-transformer-env (cadr v) (caddr v) (cdddr v))
|
|
|
|
(syntax-rules* top-transformer-env #f (cadr v) (cddr v)))))
|
|
|
|
(cons (car bnd) (make-location v))))
|
|
|
|
*transformers*)))
|
|
|
|
(if (procedure? id)
|
|
|
|
(old-den id) ; nonsymbolic ids can't be globally bound
|
|
|
|
(cond [(assq id *top-transformer-env*)
|
|
|
|
=> cdr]
|
|
|
|
[else
|
|
|
|
(let ([loc (make-location (or (lookup-integrable id) (list 'ref id)))])
|
|
|
|
(set! *top-transformer-env* (cons (cons id loc) *top-transformer-env*))
|
|
|
|
loc)])))
|
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-01 23:36:24 +01:00
|
|
|
(define (install-transformer! s t)
|
2023-04-16 03:03:39 +02:00
|
|
|
(location-set-val! (top-transformer-env s) t))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-01 23:36:24 +01:00
|
|
|
(define (transform appos? sexp . optenv)
|
2023-03-10 23:30:41 +01:00
|
|
|
; (gensym #f) ; reset gs counter to make results reproducible
|
2023-03-03 01:27:09 +01:00
|
|
|
(xform appos? sexp (if (null? optenv) top-transformer-env (car optenv))))
|
2023-03-01 23:36:24 +01:00
|
|
|
|
|
|
|
|
2023-04-14 00:31:20 +02:00
|
|
|
; make transformer procedure from the rules
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (syntax-rules* mac-env ellipsis pat-literals rules)
|
2023-04-14 17:34:47 +02:00
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (pat-literal? id) (memq id pat-literals))
|
|
|
|
(define (not-pat-literal? id) (not (pat-literal? id)))
|
|
|
|
(define (ellipsis-pair? x)
|
|
|
|
(and (pair? x) (ellipsis? (car x))))
|
2023-04-14 17:34:47 +02:00
|
|
|
(define (ellipsis-denotation? den)
|
2023-04-16 03:03:39 +02:00
|
|
|
(eq? (location-val den) '...)) ; fixme: need eq? with correct #&...
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (ellipsis? x)
|
|
|
|
(if ellipsis
|
|
|
|
(eq? x ellipsis)
|
2023-04-14 17:34:47 +02:00
|
|
|
(and (id? x) (ellipsis-denotation? (mac-env x)))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
; List-ids returns a list of the non-ellipsis ids in a
|
|
|
|
; pattern or template for which (pred? id) is true. If
|
|
|
|
; include-scalars is false, we only include ids that are
|
|
|
|
; within the scope of at least one ellipsis.
|
|
|
|
(define (list-ids x include-scalars pred?)
|
|
|
|
(let collect ([x x] [inc include-scalars] [l '()])
|
|
|
|
(cond [(id? x) (if (and inc (pred? x)) (cons x l) l)]
|
|
|
|
[(vector? x) (collect (vector->list x) inc l)]
|
|
|
|
[(pair? x)
|
|
|
|
(if (ellipsis-pair? (cdr x))
|
|
|
|
(collect (car x) #t (collect (cddr x) inc l))
|
|
|
|
(collect (car x) inc (collect (cdr x) inc l)))]
|
|
|
|
[else l])))
|
|
|
|
|
|
|
|
; Returns #f or an alist mapping each pattern var to a part of
|
|
|
|
; the input. Ellipsis vars are mapped to lists of parts (or
|
|
|
|
; lists of lists ...).
|
|
|
|
(define (match-pattern pat use use-env)
|
|
|
|
(call-with-current-continuation
|
|
|
|
(lambda (return)
|
|
|
|
(define (fail) (return #f))
|
|
|
|
(let match ([pat pat] [sexp use] [bindings '()])
|
|
|
|
(define (continue-if condition)
|
|
|
|
(if condition bindings (fail)))
|
|
|
|
(cond
|
|
|
|
[(id? pat)
|
|
|
|
(if (pat-literal? pat)
|
|
|
|
(continue-if (and (id? sexp) (eq? (use-env sexp) (mac-env pat))))
|
|
|
|
(cons (cons pat sexp) bindings))]
|
|
|
|
[(vector? pat)
|
|
|
|
(or (vector? sexp) (fail))
|
|
|
|
(match (vector->list pat) (vector->list sexp) bindings)]
|
|
|
|
[(not (pair? pat))
|
|
|
|
(continue-if (equal? pat sexp))]
|
|
|
|
[(ellipsis-pair? (cdr pat))
|
|
|
|
(let* ([tail-len (length (cddr pat))]
|
|
|
|
[sexp-len (if (list? sexp) (length sexp) (fail))]
|
|
|
|
[seq-len (fx- sexp-len tail-len)]
|
|
|
|
[sexp-tail (begin (if (negative? seq-len) (fail)) (list-tail sexp seq-len))]
|
|
|
|
[seq (reverse (list-tail (reverse sexp) tail-len))]
|
|
|
|
[vars (list-ids (car pat) #t not-pat-literal?)])
|
|
|
|
(define (match1 sexp)
|
|
|
|
(map cdr (match (car pat) sexp '())))
|
|
|
|
(append
|
|
|
|
(apply map (cons list (cons vars (map match1 seq))))
|
|
|
|
(match (cddr pat) sexp-tail bindings)))]
|
|
|
|
[(pair? sexp)
|
|
|
|
(match (car pat) (car sexp)
|
|
|
|
(match (cdr pat) (cdr sexp) bindings))]
|
|
|
|
[else (fail)])))))
|
|
|
|
|
|
|
|
(define (expand-template pat tmpl top-bindings)
|
|
|
|
; New-literals is an alist mapping each literal id in the
|
|
|
|
; template to a fresh id for inserting into the output. It
|
|
|
|
; might have duplicate entries mapping an id to two different
|
|
|
|
; fresh ids, but that's okay because when we go to retrieve a
|
|
|
|
; fresh id, assq will always retrieve the first one.
|
|
|
|
(define new-literals
|
2023-04-16 00:08:08 +02:00
|
|
|
(map (lambda (id) (cons id (new-id (id->sym id) (mac-env id))))
|
2023-03-01 23:36:24 +01:00
|
|
|
(list-ids tmpl #t
|
|
|
|
(lambda (id) (not (assq id top-bindings))))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define ellipsis-vars
|
|
|
|
(list-ids pat #f not-pat-literal?))
|
|
|
|
|
|
|
|
(define (list-ellipsis-vars subtmpl)
|
|
|
|
(list-ids subtmpl #t
|
|
|
|
(lambda (id) (memq id ellipsis-vars))))
|
|
|
|
|
|
|
|
(let expand ([tmpl tmpl] [bindings top-bindings])
|
|
|
|
(let expand-part ([tmpl tmpl])
|
|
|
|
(cond
|
|
|
|
[(id? tmpl)
|
|
|
|
(cdr (or (assq tmpl bindings)
|
|
|
|
(assq tmpl top-bindings)
|
|
|
|
(assq tmpl new-literals)))]
|
|
|
|
[(vector? tmpl)
|
|
|
|
(list->vector (expand-part (vector->list tmpl)))]
|
2023-03-18 21:07:10 +01:00
|
|
|
[(and (pair? tmpl) (ellipsis-pair? (cdr tmpl)))
|
|
|
|
(let ([vars-to-iterate (list-ellipsis-vars (car tmpl))])
|
|
|
|
(define (lookup var)
|
|
|
|
(cdr (assq var bindings)))
|
|
|
|
(define (expand-using-vals . vals)
|
|
|
|
(expand (car tmpl)
|
|
|
|
(map cons vars-to-iterate vals)))
|
|
|
|
(if (null? vars-to-iterate)
|
|
|
|
; ellipsis following non-repeatable part is an error, but we don't care
|
|
|
|
(cons (expand-part (car tmpl)) (expand-part (cddr tmpl))) ; repeat once
|
|
|
|
; correct use of ellipsis
|
2023-02-28 06:31:08 +01:00
|
|
|
(let ([val-lists (map lookup vars-to-iterate)])
|
|
|
|
(append
|
|
|
|
(apply map (cons expand-using-vals val-lists))
|
2023-03-18 21:07:10 +01:00
|
|
|
(expand-part (cddr tmpl))))))]
|
|
|
|
[(pair? tmpl)
|
|
|
|
(cons (expand-part (car tmpl)) (expand-part (cdr tmpl)))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[else tmpl]))))
|
|
|
|
|
|
|
|
(lambda (use use-env)
|
|
|
|
(let loop ([rules rules])
|
2023-03-21 23:02:01 +01:00
|
|
|
(if (null? rules) (x-error "invalid syntax" use))
|
2023-02-28 06:31:08 +01:00
|
|
|
(let* ([rule (car rules)] [pat (car rule)] [tmpl (cadr rule)])
|
|
|
|
(cond [(match-pattern pat use use-env) =>
|
|
|
|
(lambda (bindings) (expand-template pat tmpl bindings))]
|
|
|
|
[else (loop (cdr rules))])))))
|
|
|
|
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------------------
|
2023-04-14 00:31:20 +02:00
|
|
|
; Runtime globals
|
2023-02-28 06:31:08 +01:00
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
2023-03-01 00:05:08 +01:00
|
|
|
(%localdef "#include \"i.h\"")
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2024-07-11 01:28:27 +02:00
|
|
|
(define *globals* (make-vector 991 '())) ; nice prime number
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-30 05:18:39 +02:00
|
|
|
(define *dynamic-state* (list #f)) ; for dynamic-wind
|
|
|
|
|
2023-03-31 00:13:07 +02:00
|
|
|
(define *current-input* #f)
|
|
|
|
(define *current-output* #f)
|
|
|
|
(define *current-error* #f)
|
|
|
|
|
2023-03-30 05:18:39 +02:00
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
; String representation of S-expressions and code arguments
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
2023-03-21 23:02:01 +01:00
|
|
|
(define (c-error msg . args)
|
2023-03-22 18:21:48 +01:00
|
|
|
(error* (string-append "compiler: " msg) args))
|
2023-03-21 23:02:01 +01:00
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (write-serialized-char x port)
|
|
|
|
(cond [(or (char=? x #\%) (char=? x #\") (char=? x #\\) (char<? x #\space) (char>? x #\~))
|
|
|
|
(write-char #\% port)
|
|
|
|
(let ([s (fixnum->string (char->integer x) 16)])
|
|
|
|
(if (fx=? (string-length s) 1) (write-char #\0 port))
|
|
|
|
(write-string s port))]
|
|
|
|
[else (write-char x port)]))
|
|
|
|
|
2023-03-26 19:20:33 +02:00
|
|
|
(define (write-serialized-byte x port)
|
|
|
|
(let ([s (fixnum->string x 16)])
|
|
|
|
(if (fx=? (string-length s) 1) (write-char #\0 port))
|
|
|
|
(write-string s port)))
|
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (write-serialized-size n port)
|
|
|
|
(write-string (fixnum->string n 10) port)
|
|
|
|
(write-char #\: port))
|
|
|
|
|
|
|
|
(define (write-serialized-element x port)
|
|
|
|
(write-serialized-sexp x port)
|
|
|
|
(write-char #\; port))
|
|
|
|
|
|
|
|
(define (write-serialized-sexp x port)
|
|
|
|
(cond [(eq? x #f)
|
|
|
|
(write-char #\f port)]
|
|
|
|
[(eq? x #t)
|
|
|
|
(write-char #\t port)]
|
|
|
|
[(eq? x '())
|
|
|
|
(write-char #\n port)]
|
|
|
|
[(char? x)
|
|
|
|
(write-char #\c port)
|
|
|
|
(write-serialized-char x port)]
|
|
|
|
[(number? x)
|
|
|
|
(write-char (if (exact? x) #\i #\j) port)
|
|
|
|
(write-string (number->string x 10) port)]
|
|
|
|
[(list? x)
|
|
|
|
(write-char #\l port)
|
|
|
|
(write-serialized-size (length x) port)
|
|
|
|
(do ([x x (cdr x)]) [(null? x)]
|
|
|
|
(write-serialized-element (car x) port))]
|
|
|
|
[(pair? x)
|
|
|
|
(write-char #\p port)
|
|
|
|
(write-serialized-element (car x) port)
|
|
|
|
(write-serialized-element (cdr x) port)]
|
|
|
|
[(vector? x)
|
|
|
|
(write-char #\v port)
|
|
|
|
(write-serialized-size (vector-length x) port)
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx=? i (vector-length x))]
|
|
|
|
(write-serialized-element (vector-ref x i) port))]
|
|
|
|
[(string? x)
|
|
|
|
(write-char #\s port)
|
|
|
|
(write-serialized-size (string-length x) port)
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx=? i (string-length x))]
|
|
|
|
(write-serialized-char (string-ref x i) port))]
|
2023-03-26 19:20:33 +02:00
|
|
|
[(bytevector? x)
|
|
|
|
(write-char #\b port)
|
|
|
|
(write-serialized-size (bytevector-length x) port)
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx=? i (bytevector-length x))]
|
|
|
|
(write-serialized-byte (bytevector-u8-ref x i) port))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(symbol? x)
|
|
|
|
(write-char #\y port)
|
|
|
|
(let ([x (symbol->string x)])
|
|
|
|
(write-serialized-size (string-length x) port)
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx=? i (string-length x))]
|
|
|
|
(write-serialized-char (string-ref x i) port)))]
|
2023-04-20 17:03:14 +02:00
|
|
|
[(box? x)
|
|
|
|
(write-char #\z port)
|
|
|
|
(write-serialized-element (unbox x) port)]
|
2023-03-24 21:34:11 +01:00
|
|
|
[else (c-error "cannot encode literal" x)]))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (write-serialized-arg arg port)
|
|
|
|
(if (and (number? arg) (exact? arg) (fx<=? 0 arg) (fx<=? arg 9))
|
|
|
|
(write-char (string-ref "0123456789" arg) port)
|
|
|
|
(begin (write-char #\( port)
|
|
|
|
(write-serialized-sexp arg port)
|
|
|
|
(write-char #\) port))))
|
|
|
|
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
; Compiler producing serialized code
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(define find-free*
|
|
|
|
(lambda (x* b)
|
|
|
|
(if (null? x*)
|
|
|
|
'()
|
|
|
|
(set-union
|
|
|
|
(find-free (car x*) b)
|
|
|
|
(find-free* (cdr x*) b)))))
|
|
|
|
|
|
|
|
(define find-free
|
|
|
|
(lambda (x b)
|
|
|
|
(record-case x
|
|
|
|
[quote (obj)
|
|
|
|
'()]
|
|
|
|
[ref (id)
|
|
|
|
(if (set-member? id b) '() (list id))]
|
|
|
|
[set! (id exp)
|
|
|
|
(set-union
|
|
|
|
(if (set-member? id b) '() (list id))
|
|
|
|
(find-free exp b))]
|
2023-03-12 21:54:44 +01:00
|
|
|
[set& (id)
|
|
|
|
(if (set-member? id b) '() (list id))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[lambda (idsi exp)
|
|
|
|
(find-free exp (set-union (flatten-idslist idsi) b))]
|
2023-03-07 19:11:46 +01:00
|
|
|
[lambda* clauses
|
|
|
|
(find-free* (map cadr clauses) b)]
|
2023-03-10 23:30:41 +01:00
|
|
|
[letcc (kid exp)
|
|
|
|
(find-free exp (set-union (list kid) b))]
|
|
|
|
[withcc (kexp exp)
|
|
|
|
(set-union (find-free kexp b) (find-free exp b))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[if (test then else)
|
|
|
|
(set-union
|
|
|
|
(find-free test b)
|
|
|
|
(set-union (find-free then b) (find-free else b)))]
|
|
|
|
[begin exps
|
|
|
|
(find-free* exps b)]
|
2023-03-19 00:13:38 +01:00
|
|
|
[integrable (ig . args)
|
|
|
|
(find-free* args b)]
|
2023-02-28 06:31:08 +01:00
|
|
|
[call (exp . args)
|
2023-03-24 19:16:10 +01:00
|
|
|
(set-union (find-free exp b) (find-free* args b))]
|
|
|
|
[define tail
|
|
|
|
(c-error "misplaced define form" x)])))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define find-sets*
|
|
|
|
(lambda (x* v)
|
|
|
|
(if (null? x*)
|
|
|
|
'()
|
|
|
|
(set-union
|
|
|
|
(find-sets (car x*) v)
|
|
|
|
(find-sets* (cdr x*) v)))))
|
|
|
|
|
|
|
|
(define find-sets
|
|
|
|
(lambda (x v)
|
|
|
|
(record-case x
|
|
|
|
[quote (obj)
|
|
|
|
'()]
|
|
|
|
[ref (id)
|
|
|
|
'()]
|
|
|
|
[set! (id x)
|
|
|
|
(set-union
|
|
|
|
(if (set-member? id v) (list id) '())
|
|
|
|
(find-sets x v))]
|
2023-03-12 21:54:44 +01:00
|
|
|
[set& (id)
|
|
|
|
(if (set-member? id v) (list id) '())]
|
2023-02-28 06:31:08 +01:00
|
|
|
[lambda (idsi exp)
|
|
|
|
(find-sets exp (set-minus v (flatten-idslist idsi)))]
|
2023-03-07 19:11:46 +01:00
|
|
|
[lambda* clauses
|
|
|
|
(find-sets* (map cadr clauses) v)]
|
2023-03-10 23:30:41 +01:00
|
|
|
[letcc (kid exp)
|
|
|
|
(find-sets exp (set-minus v (list kid)))]
|
|
|
|
[withcc (kexp exp)
|
|
|
|
(set-union (find-sets kexp v) (find-sets exp v))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[begin exps
|
|
|
|
(find-sets* exps v)]
|
|
|
|
[if (test then else)
|
|
|
|
(set-union
|
|
|
|
(find-sets test v)
|
|
|
|
(set-union (find-sets then v) (find-sets else v)))]
|
2023-03-19 00:13:38 +01:00
|
|
|
[integrable (ig . args)
|
|
|
|
(find-sets* args v)]
|
2023-02-28 06:31:08 +01:00
|
|
|
[call (exp . args)
|
2023-03-24 19:16:10 +01:00
|
|
|
(set-union (find-sets exp v) (find-sets* args v))]
|
|
|
|
[define tail
|
|
|
|
(c-error "misplaced define form" x)])))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define codegen
|
|
|
|
; x: Scheme Core expression to compile
|
|
|
|
; l: local var list (with #f placeholders for nonvar slots)
|
|
|
|
; f: free var list
|
|
|
|
; s: set! var set
|
|
|
|
; g: global var set
|
|
|
|
; k: #f: x goes to ac, N: x is to be returned after (sdrop n)
|
|
|
|
; port: output code goes here
|
|
|
|
(lambda (x l f s g k port)
|
|
|
|
(record-case x
|
|
|
|
[quote (obj)
|
|
|
|
(case obj
|
|
|
|
[(#t) (write-char #\t port)]
|
|
|
|
[(#f) (write-char #\f port)]
|
|
|
|
[(()) (write-char #\n port)]
|
|
|
|
[else (write-char #\' port) (write-serialized-arg obj port)])
|
|
|
|
(when k (write-char #\] port) (write-serialized-arg k port))]
|
|
|
|
[ref (id)
|
|
|
|
(cond [(posq id l) => ; local
|
|
|
|
(lambda (n)
|
|
|
|
(write-char #\. port)
|
|
|
|
(write-serialized-arg n port)
|
|
|
|
(if (set-member? id s) (write-char #\^ port)))]
|
|
|
|
[(posq id f) => ; free
|
|
|
|
(lambda (n)
|
|
|
|
(write-char #\: port)
|
|
|
|
(write-serialized-arg n port)
|
|
|
|
(if (set-member? id s) (write-char #\^ port)))]
|
|
|
|
[else ; global
|
|
|
|
(write-char #\@ port)
|
|
|
|
(write-serialized-arg id port)])
|
|
|
|
(when k (write-char #\] port) (write-serialized-arg k port))]
|
|
|
|
[set! (id x)
|
|
|
|
(codegen x l f s g #f port)
|
|
|
|
(cond [(posq id l) => ; local
|
|
|
|
(lambda (n)
|
|
|
|
(write-char #\. port) (write-char #\! port)
|
|
|
|
(write-serialized-arg n port))]
|
|
|
|
[(posq id f) => ; free
|
|
|
|
(lambda (n)
|
|
|
|
(write-char #\: port) (write-char #\! port)
|
|
|
|
(write-serialized-arg n port))]
|
|
|
|
[else ; global
|
|
|
|
(write-char #\@ port) (write-char #\! port)
|
|
|
|
(write-serialized-arg id port)])
|
|
|
|
(when k (write-char #\] port) (write-serialized-arg k port))]
|
2023-03-12 21:54:44 +01:00
|
|
|
[set& (id)
|
|
|
|
(cond [(posq id l) => ; local
|
|
|
|
(lambda (n)
|
|
|
|
(write-char #\. port)
|
|
|
|
(write-serialized-arg n port))]
|
|
|
|
[(posq id f) => ; free
|
|
|
|
(lambda (n)
|
|
|
|
(write-char #\: port)
|
|
|
|
(write-serialized-arg n port))]
|
|
|
|
[else ; global
|
|
|
|
(write-char #\` port)
|
|
|
|
(write-serialized-arg id port)])
|
|
|
|
(when k (write-char #\] port) (write-serialized-arg k port))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[begin exps
|
|
|
|
(let loop ([xl exps])
|
|
|
|
(when (pair? xl)
|
|
|
|
(let ([k (if (pair? (cdr xl)) #f k)])
|
|
|
|
(codegen (car xl) l f s g k port)
|
|
|
|
(loop (cdr xl)))))
|
|
|
|
(when (and k (null? exps)) (write-char #\] port) (write-serialized-arg k port))]
|
|
|
|
[if (test then else)
|
|
|
|
(codegen test l f s g #f port)
|
|
|
|
(write-char #\? port)
|
|
|
|
(write-char #\{ port)
|
|
|
|
(codegen then l f s g k port)
|
|
|
|
(write-char #\} port)
|
|
|
|
(cond [k ; tail call: 'then' arm exits, so br around is not needed
|
|
|
|
(codegen else l f s g k port)]
|
|
|
|
[(equal? else '(begin)) ; non-tail with void 'else' arm
|
|
|
|
] ; no code needed -- ac retains #f from failed test
|
|
|
|
[else ; non-tail with 'else' expression; needs br
|
|
|
|
(write-char #\{ port)
|
|
|
|
(codegen else l f s g k port)
|
|
|
|
(write-char #\} port)])]
|
|
|
|
[lambda (idsi exp)
|
|
|
|
(let* ([ids (flatten-idslist idsi)]
|
|
|
|
[free (set-minus (find-free exp ids) g)]
|
|
|
|
[sets (find-sets exp ids)])
|
|
|
|
(do ([free (reverse free) (cdr free)] [l l (cons #f l)]) [(null? free)]
|
|
|
|
; note: called with empty set! var list
|
|
|
|
; to make sure no dereferences are generated
|
|
|
|
(codegen (list 'ref (car free)) l f '() g #f port)
|
|
|
|
(write-char #\, port))
|
|
|
|
(write-char #\& port)
|
|
|
|
(write-serialized-arg (length free) port)
|
|
|
|
(write-char #\{ port)
|
|
|
|
(cond [(list? idsi)
|
|
|
|
(write-char #\% port)
|
|
|
|
(write-serialized-arg (length idsi) port)]
|
|
|
|
[else
|
|
|
|
(write-char #\% port) (write-char #\! port)
|
|
|
|
(write-serialized-arg (idslist-req-count idsi) port)])
|
|
|
|
(do ([ids ids (cdr ids)] [n 0 (fx+ n 1)]) [(null? ids)]
|
|
|
|
(when (set-member? (car ids) sets)
|
|
|
|
(write-char #\# port)
|
|
|
|
(write-serialized-arg n port)))
|
|
|
|
(codegen exp ids free
|
|
|
|
(set-union sets (set-intersect s free))
|
|
|
|
g (length ids) port)
|
|
|
|
(write-char #\} port))
|
|
|
|
(when k (write-char #\] port) (write-serialized-arg k port))]
|
2023-03-07 19:11:46 +01:00
|
|
|
[lambda* clauses
|
|
|
|
(do ([clauses (reverse clauses) (cdr clauses)] [l l (cons #f l)])
|
|
|
|
[(null? clauses)]
|
|
|
|
(codegen (cadr (car clauses)) l f s g #f port)
|
2023-03-07 19:42:29 +01:00
|
|
|
(write-char #\% port) (write-char #\x port)
|
2023-03-07 19:11:46 +01:00
|
|
|
(write-char #\, port))
|
|
|
|
(write-char #\& port)
|
|
|
|
(write-serialized-arg (length clauses) port)
|
|
|
|
(write-char #\{ port)
|
|
|
|
(do ([clauses clauses (cdr clauses)] [i 0 (fx+ i 1)])
|
|
|
|
[(null? clauses)]
|
|
|
|
(let* ([arity (caar clauses)] [cnt (car arity)] [rest? (cadr arity)])
|
|
|
|
(write-char #\| port)
|
|
|
|
(if rest? (write-char #\! port))
|
|
|
|
(write-serialized-arg cnt port)
|
|
|
|
(write-serialized-arg i port)))
|
|
|
|
(write-char #\% port) (write-char #\% port)
|
|
|
|
(write-char #\} port)
|
|
|
|
(when k (write-char #\] port) (write-serialized-arg k port))]
|
2023-03-10 23:30:41 +01:00
|
|
|
[letcc (kid exp)
|
|
|
|
(let* ([ids (list kid)] [sets (find-sets exp ids)]
|
2023-03-11 18:28:51 +01:00
|
|
|
[news (set-union (set-minus s ids) sets)])
|
2023-03-10 23:30:41 +01:00
|
|
|
(cond [k ; tail position with k locals on stack to be disposed of
|
|
|
|
(write-char #\k port) (write-serialized-arg k port)
|
|
|
|
(write-char #\, port)
|
|
|
|
(when (set-member? kid sets)
|
|
|
|
(write-char #\# port) (write-char #\0 port))
|
2023-03-11 18:28:51 +01:00
|
|
|
; stack map here: kid on top
|
|
|
|
(codegen exp (cons kid l) f news g (fx+ k 1) port)]
|
2023-03-10 23:30:41 +01:00
|
|
|
[else ; non-tail position
|
|
|
|
(write-char #\$ port) (write-char #\{ port)
|
|
|
|
(write-char #\k port) (write-char #\0 port)
|
|
|
|
(write-char #\, port)
|
|
|
|
(when (set-member? kid sets)
|
|
|
|
(write-char #\# port) (write-char #\0 port))
|
2023-03-11 18:28:51 +01:00
|
|
|
; stack map here: kid on top, two-slot frame under it
|
|
|
|
(codegen exp (cons kid (cons #f (cons #f l))) f news g #f port)
|
2023-03-10 23:30:41 +01:00
|
|
|
(write-char #\_ port) (write-serialized-arg 3 port)
|
|
|
|
(write-char #\} port)]))]
|
|
|
|
[withcc (kexp exp)
|
|
|
|
(cond [(memq (car exp) '(quote ref lambda)) ; exp is a constant, return it
|
|
|
|
(codegen exp l f s g #f port)
|
2023-03-11 18:28:51 +01:00
|
|
|
(write-char #\, port) ; stack map after: k on top
|
2023-03-10 23:30:41 +01:00
|
|
|
(codegen kexp (cons #f l) f s g #f port)
|
|
|
|
(write-char #\w port) (write-char #\! port)]
|
|
|
|
[else ; exp is not a constant, thunk it and call it from k
|
|
|
|
(codegen (list 'lambda '() exp) l f s g #f port)
|
2023-03-11 18:28:51 +01:00
|
|
|
(write-char #\, port) ; stack map after: k on top
|
2023-03-10 23:30:41 +01:00
|
|
|
(codegen kexp (cons #f l) f s g #f port)
|
|
|
|
(write-char #\w port)])]
|
2023-03-19 00:13:38 +01:00
|
|
|
[integrable (ig . args)
|
|
|
|
(let ([igty (integrable-type ig)] [igc0 (integrable-code ig 0)])
|
|
|
|
(case igty
|
|
|
|
[(#\0 #\1 #\2 #\3) ; 1st arg in a, others on stack
|
|
|
|
(do ([args (reverse args) (cdr args)] [l l (cons #f l)])
|
|
|
|
[(null? args)]
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(unless (null? (cdr args)) (write-char #\, port)))
|
|
|
|
(write-string igc0 port)]
|
2023-03-20 04:31:28 +01:00
|
|
|
[(#\p) ; (length args) >= 0
|
|
|
|
(if (null? args)
|
|
|
|
(let ([igc1 (integrable-code ig 1)])
|
|
|
|
(write-string igc1 port))
|
|
|
|
(let ([opc (fx- (length args) 1)])
|
|
|
|
(do ([args (reverse args) (cdr args)] [l l (cons #f l)])
|
|
|
|
[(null? args)]
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(unless (null? (cdr args)) (write-char #\, port)))
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx>=? i opc)]
|
|
|
|
(write-string igc0 port))))]
|
|
|
|
[(#\m) ; (length args) >= 1
|
|
|
|
(if (null? (cdr args))
|
|
|
|
(let ([igc1 (integrable-code ig 1)])
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(write-string igc1 port))
|
|
|
|
(let ([opc (fx- (length args) 1)])
|
|
|
|
(do ([args (reverse args) (cdr args)] [l l (cons #f l)])
|
|
|
|
[(null? args)]
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(unless (null? (cdr args)) (write-char #\, port)))
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx>=? i opc)]
|
|
|
|
(write-string igc0 port))))]
|
2023-03-20 05:23:42 +01:00
|
|
|
[(#\c) ; (length args) >= 2
|
|
|
|
(let ([opc (fx- (length args) 1)] [args (reverse args)])
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(write-char #\, port)
|
|
|
|
(do ([args (cdr args) (cdr args)] [l (cons #f l) (cons #f (cons #f l))])
|
|
|
|
[(null? args)]
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(unless (null? (cdr args)) (write-char #\, port) (write-char #\, port)))
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx>=? i opc)]
|
|
|
|
(unless (fxzero? i) (write-char #\; port))
|
|
|
|
(write-string igc0 port)))]
|
2023-03-20 18:49:00 +01:00
|
|
|
[(#\x) ; (length args) >= 1
|
|
|
|
(let ([opc (fx- (length args) 1)])
|
|
|
|
(do ([args (reverse args) (cdr args)] [l l (cons #f l)])
|
|
|
|
[(null? args)]
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(unless (null? (cdr args)) (write-char #\, port)))
|
|
|
|
(do ([i 0 (fx+ i 1)]) [(fx>=? i opc)]
|
|
|
|
(write-string igc0 port)))]
|
2023-03-20 21:43:06 +01:00
|
|
|
[(#\u) ; 0 <= (length args) <= 1
|
|
|
|
(if (null? args)
|
|
|
|
(write-string (integrable-code ig 1) port)
|
|
|
|
(codegen (car args) l f s g #f port))
|
|
|
|
(write-string igc0 port)]
|
|
|
|
[(#\b) ; 1 <= (length args) <= 2
|
|
|
|
(if (null? (cdr args))
|
|
|
|
(write-string (integrable-code ig 1) port)
|
|
|
|
(codegen (cadr args) l f s g #f port))
|
|
|
|
(write-char #\, port)
|
|
|
|
(codegen (car args) (cons #f l) f s g #f port)
|
|
|
|
(write-string igc0 port)]
|
2023-03-28 21:39:00 +02:00
|
|
|
[(#\t) ; 2 <= (length args) <= 3
|
|
|
|
(if (null? (cddr args))
|
|
|
|
(write-string (integrable-code ig 1) port)
|
|
|
|
(codegen (caddr args) l f s g #f port))
|
|
|
|
(write-char #\, port)
|
|
|
|
(codegen (cadr args) (cons #f l) f s g #f port)
|
|
|
|
(write-char #\, port)
|
|
|
|
(codegen (car args) (cons #f (cons #f l)) f s g #f port)
|
|
|
|
(write-string igc0 port)]
|
2023-03-21 03:32:33 +01:00
|
|
|
[(#\#) ; (length args) >= 0
|
|
|
|
(do ([args (reverse args) (cdr args)] [l l (cons #f l)])
|
|
|
|
[(null? args)]
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(write-char #\, port))
|
|
|
|
(write-string igc0 port)
|
|
|
|
(write-serialized-arg (length args) port)]
|
2023-03-21 23:02:01 +01:00
|
|
|
[else (c-error "unsupported integrable type" igty)]))
|
2023-03-19 19:52:49 +01:00
|
|
|
(when k (write-char #\] port) (write-serialized-arg k port))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[call (exp . args)
|
|
|
|
(cond [(and (eq? (car exp) 'lambda) (list? (cadr exp))
|
|
|
|
(fx=? (length args) (length (cadr exp))))
|
|
|
|
; let-like call; compile as special lambda + call combo
|
|
|
|
(do ([args (reverse args) (cdr args)] [l l (cons #f l)])
|
|
|
|
[(null? args)]
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(write-char #\, port))
|
|
|
|
(let* ([ids (cadr exp)] [exp (caddr exp)]
|
|
|
|
[sets (find-sets exp ids)]
|
|
|
|
[news (set-union (set-minus s ids) sets)]
|
|
|
|
[newl (append ids l)]) ; with real names
|
|
|
|
(do ([ids ids (cdr ids)] [n 0 (fx+ n 1)]) [(null? ids)]
|
|
|
|
(when (set-member? (car ids) sets)
|
|
|
|
(write-char #\# port)
|
|
|
|
(write-serialized-arg n port)))
|
|
|
|
(if k
|
|
|
|
(codegen exp newl f news g (fx+ k (length args)) port)
|
|
|
|
(begin
|
|
|
|
(codegen exp newl f news g #f port)
|
|
|
|
(write-char #\_ port)
|
|
|
|
(write-serialized-arg (length args) port))))]
|
2023-03-21 20:29:28 +01:00
|
|
|
[k ; tail call with k elements under arguments
|
2023-02-28 06:31:08 +01:00
|
|
|
(do ([args (reverse args) (cdr args)] [l l (cons #f l)])
|
|
|
|
[(null? args) (codegen exp l f s g #f port)]
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(write-char #\, port))
|
|
|
|
(write-char #\[ port)
|
|
|
|
(write-serialized-arg k port)
|
|
|
|
(write-serialized-arg (length args) port)]
|
2023-03-21 20:29:28 +01:00
|
|
|
[else ; non-tail call; 'save' puts 2 extra elements on the stack!
|
2023-02-28 06:31:08 +01:00
|
|
|
(write-char #\$ port) (write-char #\{ port)
|
|
|
|
(do ([args (reverse args) (cdr args)] [l (cons #f (cons #f l)) (cons #f l)])
|
|
|
|
[(null? args) (codegen exp l f s g #f port)]
|
|
|
|
(codegen (car args) l f s g #f port)
|
|
|
|
(write-char #\, port))
|
|
|
|
(write-char #\[ port)
|
|
|
|
(write-serialized-arg 0 port)
|
|
|
|
(write-serialized-arg (length args) port)
|
2023-03-24 19:16:10 +01:00
|
|
|
(write-char #\} port)])]
|
|
|
|
[define tail
|
|
|
|
(c-error "misplaced define form" x)])))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (compile-to-string x)
|
|
|
|
(let ([p (open-output-string)])
|
|
|
|
(codegen x '() '() '() (find-free x '()) #f p)
|
|
|
|
(get-output-string p)))
|
|
|
|
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
; Code deserializer and Evaluator (use built-ins)
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(define execute-thunk-closure
|
|
|
|
(%prim "{ /* define execute-thunk-closure */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+0) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(define make-closure
|
|
|
|
(%prim "{ /* define make-closure */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+1) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(define execute
|
|
|
|
(lambda (code)
|
|
|
|
(execute-thunk-closure (make-closure code))))
|
|
|
|
|
|
|
|
(define decode-sexp
|
|
|
|
(%prim "{ /* define decode-sexp */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+2) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(define decode
|
|
|
|
(%prim "{ /* define decode */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+3) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(define (evaluate x)
|
|
|
|
(execute (decode (compile-to-string (transform #f x)))))
|
|
|
|
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
; File processor (Scheme => Serialized code)
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
2023-03-22 23:13:12 +01:00
|
|
|
(define *hide-refs* '())
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (display-code cstr oport)
|
|
|
|
(let loop ([i 0] [l (string-length cstr)])
|
|
|
|
(let ([r (fx- l i)])
|
|
|
|
(cond [(<= r 70)
|
|
|
|
(display " \"" oport)
|
|
|
|
(display (substring cstr i l))
|
|
|
|
(display "\"," oport)]
|
|
|
|
[else
|
|
|
|
(display " \"" oport)
|
|
|
|
(display (substring cstr i (fx+ i 70)))
|
|
|
|
(display "\"\n" oport)
|
|
|
|
(loop (fx+ i 70) l)]))))
|
|
|
|
|
|
|
|
|
2023-03-22 23:13:12 +01:00
|
|
|
(define (process-syntax id xval oport)
|
2023-02-28 06:31:08 +01:00
|
|
|
(newline oport)
|
2023-03-22 23:13:12 +01:00
|
|
|
(display " \"S\", \"" oport) (display id oport) (display "\",\n" oport)
|
2023-02-28 06:31:08 +01:00
|
|
|
(let ([p (open-output-string)]) (write-serialized-sexp xval p)
|
2023-03-01 00:05:08 +01:00
|
|
|
(display-code (get-output-string p) oport) (newline oport)))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-22 23:13:12 +01:00
|
|
|
(define (process-alias id oldid oport)
|
|
|
|
(newline oport)
|
|
|
|
(display " \"A\", \"" oport) (display id oport) (display "\"," oport)
|
|
|
|
(display " \"" oport) (display oldid oport) (display "\",\n" oport))
|
|
|
|
|
|
|
|
(define (process-command xval oport)
|
2023-02-28 06:31:08 +01:00
|
|
|
(define cstr (compile-to-string xval))
|
|
|
|
(newline oport)
|
2023-03-22 23:13:12 +01:00
|
|
|
(display " \"C\", 0,\n" oport)
|
2023-02-28 06:31:08 +01:00
|
|
|
(display-code cstr oport) (newline oport))
|
|
|
|
|
2023-03-01 00:05:08 +01:00
|
|
|
(define (process-define id xlam oport)
|
2023-03-23 04:14:11 +01:00
|
|
|
(define cstr (compile-to-string xlam))
|
|
|
|
(let ([len (string-length cstr)])
|
|
|
|
(cond [(and (eq? (car xlam) 'lambda)
|
|
|
|
(> len 4)
|
|
|
|
(char=? (string-ref cstr 0) #\&)
|
|
|
|
(char=? (string-ref cstr 1) #\0)
|
|
|
|
(char=? (string-ref cstr 2) #\{)
|
|
|
|
(char=? (string-ref cstr (fx- len 1)) #\}))
|
|
|
|
(newline oport)
|
|
|
|
(display " \"P\", \"" oport) (display id oport) (display "\",\n" oport)
|
|
|
|
(display-code (substring cstr 3 (fx- len 1)) oport) (newline oport)]
|
|
|
|
[else (process-command (list 'set! id xlam) oport)])))
|
2023-03-01 00:05:08 +01:00
|
|
|
|
2023-03-04 06:07:52 +01:00
|
|
|
(define (scan-top-form x)
|
|
|
|
(cond
|
|
|
|
[(and (list2? x) (eq? (car x) 'load) (string? (cadr x)))
|
|
|
|
(let ([iport (open-input-file (cadr x))])
|
|
|
|
(let loop ([x (read iport)])
|
|
|
|
(unless (eof-object? x)
|
|
|
|
(scan-top-form x)
|
|
|
|
(loop (read iport))))
|
|
|
|
(close-input-port iport))]
|
|
|
|
[(pair? x)
|
|
|
|
(let ([hval (transform #t (car x))])
|
|
|
|
(cond
|
|
|
|
[(eq? hval 'begin)
|
|
|
|
(for-each scan-top-form (cdr x))]
|
|
|
|
[(eq? hval 'define-syntax)
|
|
|
|
(let ([xval (transform #t (caddr x))])
|
|
|
|
(install-transformer! (cadr x) xval))]
|
|
|
|
[(procedure? hval)
|
|
|
|
(scan-top-form (hval x top-transformer-env))]))]))
|
|
|
|
|
2023-03-03 01:27:09 +01:00
|
|
|
(define (process-top-form x oport)
|
2023-02-28 06:31:08 +01:00
|
|
|
(cond
|
2023-03-04 06:07:52 +01:00
|
|
|
[(and (list2? x) (eq? (car x) 'load) (string? (cadr x)))
|
|
|
|
(let ([iport (open-input-file (cadr x))])
|
|
|
|
(let loop ([x (read iport)])
|
|
|
|
(unless (eof-object? x)
|
|
|
|
(scan-top-form x)
|
|
|
|
(loop (read iport))))
|
|
|
|
(close-input-port iport))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(pair? x)
|
2023-03-03 01:27:09 +01:00
|
|
|
(let ([hval (transform #t (car x))])
|
2023-02-28 06:31:08 +01:00
|
|
|
(cond
|
|
|
|
[(eq? hval 'begin)
|
2023-03-03 01:27:09 +01:00
|
|
|
(let loop ([x* (cdr x)])
|
|
|
|
(when (pair? x*)
|
2023-03-04 06:07:52 +01:00
|
|
|
(process-top-form (car x*) oport)
|
|
|
|
(loop (cdr x*))))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(eq? hval 'define-syntax)
|
2023-03-03 01:27:09 +01:00
|
|
|
(let ([xval (transform #t (caddr x))])
|
|
|
|
(install-transformer! (cadr x) xval)
|
2023-03-22 23:13:12 +01:00
|
|
|
(unless (memq (cadr x) *hide-refs*)
|
|
|
|
(if (symbol? (caddr x))
|
|
|
|
(process-alias (cadr x) (caddr x) oport)
|
|
|
|
(process-syntax (cadr x) (caddr x) oport))))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(eq? hval 'define)
|
2023-04-13 23:59:31 +02:00
|
|
|
(let* ([dval (transform #f x)] [xval (caddr dval)])
|
|
|
|
(process-define (cadr dval) xval oport))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(procedure? hval)
|
2023-03-03 01:27:09 +01:00
|
|
|
(process-top-form (hval x top-transformer-env) oport)]
|
2023-02-28 06:31:08 +01:00
|
|
|
[else
|
2023-03-22 23:13:12 +01:00
|
|
|
(process-command (transform #f x) oport)]))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[else
|
2023-03-22 23:13:12 +01:00
|
|
|
(process-command (transform #f x) oport)]))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (path-strip-directory filename)
|
|
|
|
(let loop ([l (reverse (string->list filename))] [r '()])
|
|
|
|
(cond [(null? l) (list->string r)]
|
|
|
|
[(memv (car l) '(#\\ #\/ #\:)) (list->string r)]
|
|
|
|
[else (loop (cdr l) (cons (car l) r))])))
|
|
|
|
|
|
|
|
(define (path-strip-extension filename)
|
|
|
|
(let ([l (reverse (string->list filename))])
|
|
|
|
(let ([r (memv #\. l)])
|
|
|
|
(if r (list->string (reverse (cdr r))) filename))))
|
|
|
|
|
|
|
|
(define (module-name filename)
|
2023-03-01 00:05:08 +01:00
|
|
|
(path-strip-extension (path-strip-directory filename)))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (process-file fname)
|
|
|
|
(define iport (open-input-file fname))
|
|
|
|
(define oport (current-output-port))
|
2023-03-01 00:05:08 +01:00
|
|
|
(define mname (module-name fname))
|
|
|
|
(display "/* " oport) (display mname oport)
|
|
|
|
(display ".c -- generated via skint -c " oport)
|
|
|
|
(display (path-strip-directory fname) oport)
|
|
|
|
(display " */" oport) (newline oport) (newline oport)
|
|
|
|
(display "char *" oport) (display mname oport)
|
|
|
|
(display "_code[] = {" oport) (newline oport)
|
2023-03-03 01:27:09 +01:00
|
|
|
(let loop ([x (read iport)])
|
2023-02-28 06:31:08 +01:00
|
|
|
(unless (eof-object? x)
|
2023-03-03 01:27:09 +01:00
|
|
|
(process-top-form x oport)
|
|
|
|
(loop (read iport))))
|
2023-03-23 04:14:11 +01:00
|
|
|
(display "\n 0, 0, 0\n};\n" oport)
|
2023-02-28 06:31:08 +01:00
|
|
|
(close-input-port iport))
|
|
|
|
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------------------
|
2023-03-03 19:18:00 +01:00
|
|
|
; Initial environment
|
2023-02-28 06:31:08 +01:00
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
2023-03-11 19:41:44 +01:00
|
|
|
; adapter code for continuation closures produced by letcc
|
2023-03-30 05:18:39 +02:00
|
|
|
(define continuation-adapter-code #f) ; inited via (decode "k!...") in i.c
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-06 21:53:37 +01:00
|
|
|
; adapter closure for values/call-with-values pair
|
|
|
|
(define callmv-adapter-closure (make-closure (decode "K5")))
|
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
(define install-global-lambdas
|
|
|
|
(%prim "{ /* define install-global-lambdas */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+6) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(install-global-lambdas)
|
|
|
|
|
2023-03-03 19:18:00 +01:00
|
|
|
(define initialize-modules
|
|
|
|
(%prim "{ /* define initialize-modules */
|
|
|
|
static obj c[] = { obj_from_objptr(vmcases+7) };
|
|
|
|
$return objptr(c); }"))
|
|
|
|
|
|
|
|
(initialize-modules)
|
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
; Tests
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(define test1
|
|
|
|
'(let ()
|
|
|
|
(define (sort-list obj pred)
|
|
|
|
(define (loop l)
|
|
|
|
(if (and (pair? l) (pair? (cdr l))) (split l '() '()) l))
|
|
|
|
(define (split l one two)
|
|
|
|
(if (pair? l)
|
|
|
|
(split (cdr l) two (cons (car l) one))
|
|
|
|
(merge (loop one) (loop two))))
|
|
|
|
(define (merge one two)
|
|
|
|
(cond
|
|
|
|
[(null? one) two]
|
|
|
|
[(pred (car two) (car one))
|
|
|
|
(cons (car two) (merge (cdr two) one))]
|
|
|
|
[else (cons (car one) (merge (cdr one) two))]))
|
|
|
|
(loop obj))
|
|
|
|
(sort-list
|
|
|
|
'("one" "two" "three" "four" "five" "six"
|
|
|
|
"seven" "eight" "nine" "ten" "eleven" "twelve")
|
|
|
|
string<?)))
|
|
|
|
|
|
|
|
(define test2
|
|
|
|
'(let ()
|
|
|
|
(define tak
|
|
|
|
(lambda (x y z)
|
|
|
|
(if (< y x)
|
|
|
|
(tak (tak (- x 1) y z)
|
|
|
|
(tak (- y 1) z x)
|
|
|
|
(tak (- z 1) x y))
|
|
|
|
z)))
|
|
|
|
(define runtak
|
|
|
|
(lambda (n r)
|
|
|
|
(let loop ([n n] [r r] [s 7])
|
|
|
|
(if (= n 0) r
|
|
|
|
(let ([v (tak 18 12 (- s 1))])
|
|
|
|
(loop (- n 1) (+ r v) v))))))
|
|
|
|
(runtak 10 0)))
|
|
|
|
|
|
|
|
(define test3
|
|
|
|
'(let ()
|
|
|
|
(define (nqueens n)
|
|
|
|
(define (one-to n)
|
|
|
|
(let loop ((i n) (l '()))
|
|
|
|
(cond
|
|
|
|
((zero? i) l)
|
|
|
|
(else (loop (- i 1) (cons i l))))))
|
|
|
|
(define (try-it x y z)
|
|
|
|
(if (null? x)
|
|
|
|
(if (null? y) 1 0)
|
|
|
|
(+ (if (ok? (car x) 1 z)
|
|
|
|
(try-it (append (cdr x) y) '() (cons (car x) z))
|
|
|
|
0)
|
|
|
|
(try-it (cdr x) (cons (car x) y) z))))
|
|
|
|
(define (ok? row dist placed)
|
|
|
|
(if (null? placed) #t
|
|
|
|
(and (not (= (car placed) (+ row dist)))
|
|
|
|
(not (= (car placed) (- row dist)))
|
|
|
|
(ok? row (+ dist 1) (cdr placed)))))
|
|
|
|
(try-it (one-to n) '() '()))
|
|
|
|
(define (run-test count)
|
|
|
|
(let loop ((n count) (v 92))
|
|
|
|
(cond
|
|
|
|
((zero? n) v)
|
|
|
|
(else (loop (- n 1) (nqueens (- v 84)))))))
|
|
|
|
(run-test 10)))
|
|
|
|
|
|
|
|
(define test4
|
|
|
|
'(let ()
|
|
|
|
(define y
|
|
|
|
(lambda (e)
|
|
|
|
((call/cc call/cc)
|
|
|
|
(lambda (f)
|
|
|
|
(e (lambda (x) (((call/cc (call/cc call/cc)) f) x)))))))
|
|
|
|
(define fakt
|
|
|
|
(y (lambda (self) (lambda (x) (if (= x 0) 1 (* x (self (- x 1))))))))
|
|
|
|
(fakt 10)))
|
|
|
|
|
|
|
|
(define test5
|
|
|
|
'(let ()
|
|
|
|
(define y
|
|
|
|
(lambda (e)
|
|
|
|
((call/cc call/cc)
|
|
|
|
(lambda (f)
|
|
|
|
(e (lambda (x) (((call/cc (call/cc call/cc)) f) x)))))))
|
|
|
|
(define fakty
|
|
|
|
(y (lambda (self)
|
|
|
|
(lambda (x) (if (= x 0) 1 (* x (self (- x 1))))))))
|
|
|
|
(define (fakti x)
|
|
|
|
(let loop ((n 1) (x x))
|
|
|
|
(if (= x 1)
|
|
|
|
n
|
|
|
|
(loop (* n x) (- x 1)))))
|
|
|
|
(define (faktr x)
|
|
|
|
(if (= x 1)
|
|
|
|
1
|
|
|
|
(* x (faktr (- x 1)))))
|
|
|
|
(define faktl
|
|
|
|
(lambda (x)
|
|
|
|
((lambda (self) (self self x))
|
|
|
|
(lambda (self x)
|
|
|
|
(if (= x 1)
|
|
|
|
x
|
|
|
|
(* (self self (- x 1)) x))))))
|
|
|
|
(let ([y (fakty 10)] [i (fakti 10)] [r (faktr 10)] [l (faktl 10)])
|
|
|
|
(cons y (cons i (cons r (cons l '())))))))
|
|
|
|
|
|
|
|
; (evaluate test1) =>
|
|
|
|
; ("eight" "eleven" "five" "four" "nine" "one" "seven" "six" "ten" "three" "twelve" "two")
|
|
|
|
;
|
|
|
|
; (evaluate test2) =>
|
|
|
|
; 70
|
|
|
|
;
|
|
|
|
; (evaluate test3) =>
|
|
|
|
; 92
|
|
|
|
;
|
|
|
|
; (evaluate test4) =>
|
|
|
|
; 3628800
|
|
|
|
;
|
2023-03-01 00:05:08 +01:00
|
|
|
; (evaluate test5) =>
|
|
|
|
; (3628800 3628800 3628800 3628800)
|
|
|
|
;
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
; REPL
|
|
|
|
;---------------------------------------------------------------------------------------------
|
|
|
|
|
2023-03-08 19:03:39 +01:00
|
|
|
(define *verbose* #f)
|
|
|
|
|
2023-03-22 18:21:48 +01:00
|
|
|
(define *reset* #f)
|
|
|
|
|
2024-07-12 01:12:03 +02:00
|
|
|
(define-inline (tty-port? o)
|
|
|
|
(%prim? "{ /* tty-port? */
|
|
|
|
extern int is_tty_port(obj o);
|
|
|
|
int x = is_tty_port(obj_from_$arg);
|
|
|
|
$return bool(x); }" o))
|
|
|
|
|
2023-03-22 18:21:48 +01:00
|
|
|
(define (error* msg args)
|
|
|
|
(if (procedure? *reset*)
|
|
|
|
(let ([p (current-error-port)])
|
|
|
|
(display msg p) (newline p)
|
|
|
|
(for-each (lambda (arg) (write arg p) (newline p)) args)
|
|
|
|
(*reset* #f))
|
|
|
|
(apply error (cons msg args))))
|
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (run-tests)
|
|
|
|
(define start (current-jiffy))
|
|
|
|
(display "Running tests ...") (newline)
|
|
|
|
(write (evaluate test1)) (newline)
|
|
|
|
(write (evaluate test2)) (newline)
|
|
|
|
(write (evaluate test3)) (newline)
|
|
|
|
(write (evaluate test4)) (newline)
|
|
|
|
(write (evaluate test5)) (newline)
|
|
|
|
(display "Elapsed time: ") (write (* 1000 (/ (- (current-jiffy) start) (jiffies-per-second))))
|
|
|
|
(display " ms.") (newline))
|
|
|
|
|
2023-03-03 01:27:09 +01:00
|
|
|
(define (repl-eval x)
|
2023-03-22 18:21:48 +01:00
|
|
|
(letcc catch
|
|
|
|
(set! *reset* catch)
|
|
|
|
(let ([xexp (transform #f x)])
|
|
|
|
(when *verbose* (display "TRANSFORM =>") (newline) (write xexp) (newline))
|
2023-03-22 19:20:17 +01:00
|
|
|
(unless (pair? xexp) (x-error "unexpected transformed output" xexp))
|
2023-03-22 18:21:48 +01:00
|
|
|
(if (eq? (car xexp) 'define) (set-car! xexp 'set!))
|
|
|
|
(when *verbose* (display "COMPILE-TO-STRING =>") (newline))
|
|
|
|
(let ([cstr (compile-to-string xexp)] [start #f])
|
|
|
|
(when *verbose*
|
|
|
|
(display cstr) (newline)
|
|
|
|
(display "DECODE+EXECUTE =>") (newline)
|
|
|
|
(set! start (current-jiffy)))
|
|
|
|
(let* ([thunk (decode cstr)] [res (execute thunk)])
|
2023-03-26 18:02:36 +02:00
|
|
|
(unless (eq? res (void)) (write res) (newline)))
|
2023-03-22 18:21:48 +01:00
|
|
|
(when *verbose*
|
|
|
|
(display "Elapsed time: ") (write (* 1000 (/ (- (current-jiffy) start) (jiffies-per-second))))
|
|
|
|
(display " ms.") (newline))))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-03 01:27:09 +01:00
|
|
|
(define (repl-eval-top-form x)
|
2023-02-28 06:31:08 +01:00
|
|
|
(cond
|
2023-03-04 06:07:52 +01:00
|
|
|
[(and (list2? x) (eq? (car x) 'load) (string? (cadr x)))
|
2023-03-03 01:27:09 +01:00
|
|
|
(let ([iport (open-input-file (cadr x))])
|
|
|
|
(repl-from-port iport)
|
|
|
|
(close-input-port iport))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(pair? x)
|
2023-03-03 01:27:09 +01:00
|
|
|
(let ([hval (transform #t (car x))])
|
2023-02-28 06:31:08 +01:00
|
|
|
(cond
|
|
|
|
[(eq? hval 'begin)
|
2023-03-03 01:27:09 +01:00
|
|
|
(let loop ([x* (cdr x)])
|
|
|
|
(when (pair? x*)
|
|
|
|
(repl-eval-top-form (car x*))
|
|
|
|
(loop (cdr x*))))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(eq? hval 'define-syntax)
|
2023-03-03 01:27:09 +01:00
|
|
|
(let ([xval (transform #t (caddr x))])
|
|
|
|
(install-transformer! (cadr x) xval))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[(procedure? hval)
|
2023-03-03 01:27:09 +01:00
|
|
|
(repl-eval-top-form (hval x top-transformer-env))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[else
|
2023-03-03 01:27:09 +01:00
|
|
|
(repl-eval x)]))]
|
2023-02-28 06:31:08 +01:00
|
|
|
[else
|
2023-03-03 01:27:09 +01:00
|
|
|
(repl-eval x)]))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
|
|
|
(define (repl-read iport)
|
|
|
|
(when (eq? iport (current-input-port))
|
2024-07-14 16:54:25 +02:00
|
|
|
(display "\nservice> ") (flush-output-port))
|
2023-02-28 06:31:08 +01:00
|
|
|
(read iport))
|
|
|
|
|
2023-03-03 01:27:09 +01:00
|
|
|
(define (repl-from-port iport)
|
|
|
|
(let loop ([x (repl-read iport)])
|
|
|
|
(unless (eof-object? x)
|
2023-03-29 05:40:41 +02:00
|
|
|
(repl-eval-top-form x)
|
|
|
|
(loop (repl-read iport)))))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2023-03-26 06:38:50 +02:00
|
|
|
(define (repl-file fname)
|
|
|
|
(define iport (open-input-file fname))
|
|
|
|
(repl-from-port iport)
|
|
|
|
(close-input-port iport))
|
|
|
|
|
2023-03-29 05:40:41 +02:00
|
|
|
(define (benchmark-file fname)
|
|
|
|
(define iport (open-input-file fname))
|
|
|
|
(unless (syntax-match? '(load "libl.sf") (read iport))
|
|
|
|
(error "unexpected benchmark file format" fname))
|
|
|
|
(repl-from-port iport)
|
|
|
|
(repl-eval-top-form '(main #f))
|
|
|
|
(close-input-port iport))
|
2023-03-26 06:38:50 +02:00
|
|
|
|
2024-07-12 01:12:03 +02:00
|
|
|
(define (service-repl)
|
2023-03-03 01:27:09 +01:00
|
|
|
(repl-from-port (current-input-port)))
|
2023-02-28 06:31:08 +01:00
|
|
|
|
2024-07-12 01:12:03 +02:00
|
|
|
(define (tcode-repl)
|
|
|
|
(execute (decode "${@(y4:repl)[00}")))
|
|
|
|
|
|
|
|
(define (debug-repl)
|
|
|
|
(define outer-k #f)
|
|
|
|
(define (loop)
|
2024-07-14 16:54:25 +02:00
|
|
|
(display "\ndebug> ") (flush-output-port)
|
2024-07-12 01:12:03 +02:00
|
|
|
(let ([cmd (read)])
|
|
|
|
(if (eof-object? cmd)
|
|
|
|
#f ; quit scheme with code 0
|
|
|
|
(case cmd
|
|
|
|
[(?)
|
|
|
|
(display "
|
|
|
|
Type r to get back to repl
|
|
|
|
a to abort scheme
|
|
|
|
s to run service repl
|
|
|
|
") (loop)]
|
|
|
|
[(r) (or (eq? (tcode-repl) #t) (loop))]
|
|
|
|
[(a) (%prim! "void(exit(1))")]
|
|
|
|
[(s) (service-repl) (loop)]
|
2024-07-19 06:02:29 +02:00
|
|
|
[else (display "Invalid command. Type ? for options, r to return to REPL.\n") (loop)]))))
|
2024-07-12 01:12:03 +02:00
|
|
|
(when (tty-port? (current-input-port))
|
|
|
|
(call/cc
|
|
|
|
(lambda (k)
|
|
|
|
(set! outer-k k)
|
|
|
|
(loop)))))
|
|
|
|
|
2023-02-28 06:31:08 +01:00
|
|
|
(define (main argv)
|
|
|
|
(let ([args (cdr (command-line))])
|
|
|
|
(cond
|
|
|
|
[(syntax-match? '("-c" *) args)
|
|
|
|
(process-file (cadr args))]
|
2023-03-29 05:40:41 +02:00
|
|
|
[(syntax-match? '("-b" *) args)
|
|
|
|
(benchmark-file (cadr args))]
|
2023-03-08 19:03:39 +01:00
|
|
|
[(syntax-match? '("-t") args)
|
|
|
|
(run-tests)]
|
2024-07-12 01:12:03 +02:00
|
|
|
[(syntax-match? '("-i") args)
|
|
|
|
(service-repl)]
|
|
|
|
[else ; run tcode repl automatically
|
|
|
|
(or (eq? (tcode-repl) #t) (debug-repl))])))
|
2023-02-28 06:31:08 +01:00
|
|
|
|