ref: 24a71723ffbe92ccbdc088a078d776fb869b52ca
parent: 30075dcfce532093f7b9001b3378fe3bc0e81176
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri Mar 21 18:32:01 EDT 2025
lsp → sl
--- a/.gitignore
+++ b/.gitignore
@@ -2,9 +2,9 @@
[05678qvtoa].*
*.out
*.bak
-instructions.lsp
-builtins.lsp
-docs_ops.lsp
+instructions.sl
+builtins.sl
+docs_ops.sl
builtin_fns.h
*.core
sl.boot.s
--- a/meson.build
+++ b/meson.build
@@ -382,18 +382,18 @@
src_dir = meson.current_source_dir()
tests_dir = join_paths(src_dir, 'test')
-test('100x100.lsp', sl, args: ['100x100.lsp'], workdir: tests_dir)
-test('argv.lsp', sl, args: ['argv.lsp'], workdir: tests_dir)
-test('exit0.lsp', sl, args: ['exit0.lsp'], workdir: tests_dir)
-test('exit1.lsp', sl, args: ['exit1.lsp'], workdir: tests_dir, should_fail: true)
-test('bench.lsp', sl, args: ['bench.lsp'], workdir: tests_dir, timeout: -1)
-test('hashtest.lsp', sl, args: ['hashtest.lsp'], workdir: tests_dir)
-test('mp.lsp', sl, args: ['mp.lsp'], workdir: tests_dir)
-test('perf.lsp', sl, args: ['perf.lsp'], workdir: tests_dir, timeout: -1)
-test('tme.lsp', sl, args: ['tme.lsp'], workdir: tests_dir, timeout: -1)
-test('torture.lsp', sl, args: ['-S', '8m', 'torture.lsp'], workdir: tests_dir, timeout: -1)
-test('torus.lsp', sl, args: ['torus.lsp'], workdir: tests_dir)
-test('unit.lsp', sl, args: ['-S', '1m', 'unittest.lsp'], workdir: tests_dir)
+test('100x100.sl', sl, args: ['100x100.sl'], workdir: tests_dir)
+test('argv.sl', sl, args: ['argv.sl'], workdir: tests_dir)
+test('exit0.sl', sl, args: ['exit0.sl'], workdir: tests_dir)
+test('exit1.sl', sl, args: ['exit1.sl'], workdir: tests_dir, should_fail: true)
+test('bench.sl', sl, args: ['bench.sl'], workdir: tests_dir, timeout: -1)
+test('hashtest.sl', sl, args: ['hashtest.sl'], workdir: tests_dir)
+test('mp.sl', sl, args: ['mp.sl'], workdir: tests_dir)
+test('perf.sl', sl, args: ['perf.sl'], workdir: tests_dir, timeout: -1)
+test('tme.sl', sl, args: ['tme.sl'], workdir: tests_dir, timeout: -1)
+test('torture.sl', sl, args: ['-S', '8m', 'torture.sl'], workdir: tests_dir, timeout: -1)
+test('torus.sl', sl, args: ['torus.sl'], workdir: tests_dir)
+test('unit.sl', sl, args: ['-S', '1m', 'unittest.sl'], workdir: tests_dir)
bootstrap = find_program(
'bootstrap.sh',
--- a/mkfile
+++ b/mkfile
@@ -105,14 +105,14 @@
bootstrap:V: $O.out
cd src && \
- ../$O.out ../tools/gen.lsp && \
+ ../$O.out ../tools/gen.sl && \
cp ../boot/sl.boot ../boot/sl.boot.bak && \
- ../$O.out ../tools/mkboot0.lsp builtins.lsp instructions.lsp system.lsp compiler.lsp > ../boot/sl.boot.new && \
+ ../$O.out ../tools/mkboot0.sl builtins.sl instructions.sl system.sl compiler.sl > ../boot/sl.boot.new && \
mv ../boot/sl.boot.new ../boot/sl.boot && \
cd .. && \
mk && \
cd boot && \
- ../$O.out ../tools/mkboot1.lsp && \
+ ../$O.out ../tools/mkboot1.sl && \
cd .. && \
mk
--- a/src/compiler.lsp
+++ /dev/null
@@ -1,870 +1,0 @@
-;; code generation state, constant tables, bytecode encoding
-
-(def (make-code-emitter) (vec NIL (table) 0 NIL 0))
-(defmacro (bcode:code b) `(aref ,b 0))
-(defmacro (bcode:ctable b) `(aref ,b 1))
-(defmacro (bcode:nconst b) `(aref ,b 2))
-(defmacro (bcode:cenv b) `(aref ,b 3))
-(defmacro (bcode:sp b) `(aref ,b 4))
-(defmacro (bcode:stack b n) `(aset! ,b 4 (+ (bcode:sp ,b) ,n)))
-
-;; get an index for a referenced value in a bytecode object
-(def (bcode:indexfor b v)
- (let ((const-to-idx (bcode:ctable b))
- (nconst (bcode:nconst b)))
- (if (has? const-to-idx v)
- (get const-to-idx v)
- (begin (put! const-to-idx v nconst)
- (prog1 nconst
- (aset! b 2 (+ nconst 1)))))))
-
-(def (emit e inst . args)
- (def (load? i)
- (member i '(load0 load1 loadt loadf loadnil loadvoid))) ; FIXME no load immediate here yet
- (let ((bc (aref e 0)))
- (if (not args)
- (if (and (eq? inst 'car)
- (eq? (car bc) 'cdr))
- (set-car! bc 'cadr)
- (cond ((and (eq? inst 'pop) (load? (car bc)))
- (aset! e 0 (cdr bc)))
- (else
- (aset! e 0 (cons inst bc)))))
- (begin
- (when (memq inst '(loadv loadg setg))
- (set! args (list (bcode:indexfor e (car args)))))
- (let ((longform
- (assq inst '((loadv loadv.l) (loadg loadg.l) (setg setg.l)
- (loada loada.l) (seta seta.l) (box box.l)))))
- (when (and longform (> (car args) 255))
- (set! inst (cadr longform))))
- (let ((longform
- (assq inst '((loadc loadc.l)))))
- (when (and longform (> (car args) 255))
- (set! inst (cadr longform))))
- (if (eq? inst 'loada)
- (cond ((equal? args '(0))
- (set! inst 'loada0)
- (set! args NIL))
- ((equal? args '(1))
- (set! inst 'loada1)
- (set! args NIL))))
- (if (eq? inst 'loadc)
- (cond ((equal? args '(0))
- (set! inst 'loadc0)
- (set! args NIL))
- ((equal? args '(1))
- (set! inst 'loadc1)
- (set! args NIL))))
-
- (let ((lasti (car bc)))
- (cond ((and (eq? inst 'brn)
- (cond ((eq? lasti 'not)
- (aset! e 0 (cons (car args) (cons 'brnn (cdr bc)))))
- ((eq? lasti 'eq?)
- (aset! e 0 (cons (car args) (cons 'brne (cdr bc)))))
- (else NIL))))
- (else
- (aset! e 0 (nreconc (cons inst args) bc)))))))
- e))
-
-(defmacro (make-label e) `(gensym))
-(defmacro (mark-label e l) `(emit ,e 'label ,l))
-
-;; convert symbolic bytecode representation to a byte array.
-;; labels are fixed-up.
-(def (encode-byte-code e)
- (let* ((cl (reverse! e))
- (v (list->vec cl))
- (long? (>= (+ (length v) ;; 1 byte for each entry, plus...
- ;; at most half the entries in this vector can be
- ;; instructions accepting 32-bit arguments
- (* 3 (div0 (length v) 2)))
- 65536)))
- (let ((n (length v))
- (i 0)
- (label-to-loc (table))
- (fixup-to-label (table))
- (bcode (buffer))
- (vi NIL)
- (nxt NIL))
- (while (< i n)
- (set! vi (aref v i))
- (if (eq? vi 'label)
- (begin (put! label-to-loc (aref v (+ i 1)) (sizeof bcode))
- (set! i (+ i 2)))
- (begin
- (io-write bcode
- (get Instructions
- (if long?
- (case vi
- (jmp 'jmp.l)
- (brne 'brne.l)
- (brnn 'brnn.l)
- (brn 'brn.l)
- (else vi))
- vi)))
- (set! i (+ i 1))
- (set! nxt (and (< i n) (aref v i)))
- (cond ((memq vi '(jmp brne brnn brn))
- (put! fixup-to-label (sizeof bcode) nxt)
- (io-write bcode ((if long? s32 s16) 0))
- (set! i (+ i 1)))
- ((eq? vi 'brbound)
- (io-write bcode (s32 nxt))
- (set! i (+ i 1)))
- ((num? nxt)
- (case vi
- ((loadv.l loadg.l setg.l loada.l seta.l
- argc.l vargc.l call.l tcall.l loadc.l box.l)
- (io-write bcode (s32 nxt))
- (set! i (+ i 1)))
-
- ((optargs keyargs) ; 2 s32 args
- (io-write bcode (s32 nxt))
- (set! i (+ i 1))
- (io-write bcode (s32 (aref v i)))
- (set! i (+ i 1))
- (when (eq? vi 'keyargs)
- (io-write bcode (s32 (aref v i)))
- (set! i (+ i 1))))
-
- (else
- ; other number arguments are always u8
- (io-write bcode (u8 nxt))
- (set! i (+ i 1)))))
- (else NIL)))))
-
- (for-each
- (λ (addr labl)
- (io-seek bcode addr)
- (io-write bcode ((if long? s32 s16)
- (- (get label-to-loc labl) addr))))
- fixup-to-label)
- (io->str bcode))))
-
-(def (const-to-idx-vec e)
- (let ((cvec (vec-alloc (bcode:nconst e))))
- (for-each (λ (val idx) (aset! cvec idx val))
- (bcode:ctable e))
- cvec))
-
-;; variables
-
-(def (vinfo symbol heap? index) (list symbol heap? index))
-(def vinfo:sym car)
-(def vinfo:heap? cadr)
-(def vinfo:index caddr)
-
-(def (quoted? e) (eq? (car e) 'quote))
-
-(def (capture-var! g s)
- (let ((ce (bcode:cenv g)))
- (let ((n (index-of s ce 0)))
- (or n
- (prog1 (length ce)
- (aset! g 3 (nconc ce (list s))))))))
-
-(def (index-of item lst start)
- (cond ((not lst) NIL)
- ((eq? item (car lst)) start)
- (else (index-of item (cdr lst) (+ start 1)))))
-
-(def (in-env? s env)
- (and (cons? env)
- (or (assq s (car env))
- (in-env? s (cdr env)))))
-
-(def (lookup-sym s env lev)
- (if (not env)
- 'global
- (let* ((curr (car env))
- (vi (assq s curr)))
- (if vi
- (cons lev vi)
- (lookup-sym s
- (cdr env)
- (+ lev 1))))))
-
-(def (printable? x) (not (or (io? x)
- (void? x)
- (eof-object? x))))
-
-(def (compile-sym g env s deref)
- (let ((loc (lookup-sym s env 0)))
- (cond ((eq? loc 'global)
- (if (and (const? s)
- (printable? (top-level-value s)))
- (emit g 'loadv (top-level-value s))
- (emit g 'loadg s)))
-
- ((= (car loc) 0)
- (emit g 'loada (vinfo:index (cdr loc)))
- (when (and deref (vinfo:heap? (cdr loc)))
- (emit g 'car)))
-
- (else
- (emit g 'loadc (capture-var! g s))
- (when (and deref (vinfo:heap? (cdr loc)))
- (emit g 'car))))))
-
-(def (compile-aset! g env args)
- (let ((nref (- (length args) 2)))
- (cond ((= nref 1)
- (compile-app g env NIL (cons 'aset! args)))
- ((> nref 1)
- (compile-app g env NIL (cons 'aref (list-head args nref)))
- (let ((nargs (compile-arglist g env (list-tail args nref))))
- (bcode:stack g (- nargs))
- (emit g 'aset!)))
- (else (argc-error 'aset! 3)))))
-
-(def (compile-set! g env s rhs)
- (let ((loc (lookup-sym s env 0)))
- (if (eq? loc 'global)
- (begin (compile-in g env NIL rhs)
- (emit g 'setg s))
- (let ((arg? (= (car loc) 0)))
- (let ((h? (vinfo:heap? (cdr loc)))
- (idx (if arg?
- (vinfo:index (cdr loc))
- (capture-var! g s))))
- (if h?
- (begin (emit g (if arg? 'loada 'loadc) idx)
- (bcode:stack g 1)
- (compile-in g env NIL rhs)
- (bcode:stack g -1)
- (emit g 'set-car!))
-
- (begin (compile-in g env NIL rhs)
- (unless arg? (error (str "internal error: misallocated var " s)))
- (emit g 'seta idx))))))))
-
-(def (box-vars g env)
- (let loop ((e env))
- (when (cons? e)
- (if (cadr (car e))
- (emit g 'box (caddr (car e))))
- (loop (cdr e)))))
-
-;; control flow
-
-(def (compile-if g env tail? x)
- (let ((thenl (make-label g))
- (elsel (make-label g))
- (endl (make-label g))
- (test (cadr x))
- (then (caddr x))
- (else (if (cons? (cdddr x))
- (cadddr x)
- NIL)))
- (cond ((eq? test T)
- (compile-in g env tail? then))
- ((not test)
- (compile-in g env tail? else))
- (else
- (compile-in g env NIL test elsel)
- (emit g 'brn elsel)
- (mark-label g thenl)
- (compile-in g env tail? then)
- (if tail?
- (emit g 'ret)
- (emit g 'jmp endl))
- (mark-label g elsel)
- (compile-in g env tail? else)
- (mark-label g endl)))))
-
-(def (compile-begin g env tail? forms)
- (cond ((atom? forms) (compile-in g env tail? (void)))
- ((atom? (cdr forms))
- (compile-in g env tail? (car forms)))
- (else
- (compile-in g env NIL (car forms))
- (emit g 'pop)
- (compile-begin g env tail? (cdr forms)))))
-
-(def (compile-prog1 g env x)
- (compile-in g env NIL (cadr x))
- (when (cons? (cddr x))
- (bcode:stack g 1)
- (compile-begin g env NIL (cddr x))
- (emit g 'pop)
- (bcode:stack g -1)))
-
-(def (compile-while g env cond body)
- (let ((top (make-label g))
- (end (make-label g)))
- (compile-in g env NIL (void))
- (bcode:stack g 1)
- (mark-label g top)
- (compile-in g env NIL cond)
- (emit g 'brn end)
- (emit g 'pop)
- (bcode:stack g -1)
- (compile-in g env NIL body)
- (emit g 'jmp top)
- (mark-label g end)))
-
-(def (lambda? a)
- (or (eq? a 'λ)
- (eq? a 'lambda)))
-
-(def (1arg-lambda? func)
- (and (cons? func)
- (lambda? (car func))
- (length= (cadr func) 1)))
-
-(def (compile-short-circuit g env tail? forms default branch outl)
- (cond ((atom? forms) (compile-in g env tail? default outl))
- ((atom? (cdr forms)) (compile-in g env tail? (car forms) outl))
- (else
- (let ((end (or outl (make-label g))))
- (compile-in g env NIL (car forms) outl)
- (bcode:stack g 1)
- (unless outl (emit g 'dup))
- (emit g branch end)
- (bcode:stack g -1)
- (unless outl (emit g 'pop))
- (compile-short-circuit g env tail? (cdr forms) default branch outl)
- (unless outl (mark-label g end))))))
-
-(def (compile-and g env tail? forms outl)
- (compile-short-circuit g env tail? forms T 'brn outl))
-(def (compile-or g env tail? forms)
- (compile-short-circuit g env tail? forms NIL 'brnn NIL))
-
-;; calls
-
-(def (compile-arglist g env lst)
- (for-each (λ (a)
- (compile-in g env NIL a)
- (bcode:stack g 1))
- lst)
- (length lst))
-
-(def (argc-error head count)
- (error "compile error: " head " expects " count
- (if (= count 1)
- " argument."
- " arguments.")))
-
-(def builtin->instruction
- (let ((b2i (table num? 'num? cons 'cons
- fixnum? 'fixnum? equal? 'equal?
- eq? 'eq? sym? 'sym?
- div0 'div0 builtin? 'builtin?
- aset! 'aset! - '- not 'not
- apply 'apply atom? 'atom? nan? 'nan?
- set-cdr! 'set-cdr! / '/
- fn? 'fn? vec 'vec
- list 'list bound? 'bound?
- < '< * '* cdr 'cdr cadr 'cadr
- + '+ eqv? 'eqv? compare 'compare aref 'aref
- set-car! 'set-car! car 'car for 'for
- cons? 'cons? = '= vec? 'vec?)))
- (λ (b)
- (get b2i b NIL))))
-
-(def (compile-builtin-call g env tail? x head b nargs)
- (def (num-compare)
- (if (= nargs 0)
- (argc-error b 1)
- (emit g b nargs)))
- (let ((count (get arg-counts b NIL)))
- (when (and count (not (length= (cdr x) count)))
- (argc-error b count))
- (case b ; handle special cases of vararg builtins
- (list (if (= nargs 0)
- (emit g 'loadnil)
- (emit g b nargs)))
- (< (num-compare))
- (= (num-compare))
- (+ (cond ((= nargs 0) (emit g 'load0))
- ((= nargs 2) (emit g 'add2))
- (else (emit g b nargs))))
- (- (cond ((= nargs 0) (argc-error b 1))
- ((= nargs 1) (emit g 'neg))
- ((= nargs 2) (emit g 'sub2))
- (else (emit g b nargs))))
- (* (if (= nargs 0)
- (emit g 'load1)
- (emit g b nargs)))
- (/ (if (= nargs 0)
- (argc-error b 1)
- (emit g b nargs)))
- (vec (if (= nargs 0)
- (emit g 'loadv #())
- (emit g b nargs)))
- (apply (if (< nargs 2)
- (argc-error b 2)
- (emit g (if tail? 'tapply 'apply) nargs)))
- (aref (cond ((= nargs 2) (emit g 'aref2))
- ((> nargs 2) (emit g b (- nargs 3)))
- (else (argc-error b 2))))
- (else (emit g b)))))
-
-(def (inlineable? form)
- (let ((lam (car form)))
- (and (cons? lam)
- (lambda? (car lam))
- (list? (cadr lam))
- (every sym? (cadr lam))
- (not (length> (cadr lam) 255))
- (length= (cadr lam) (length (cdr form))))))
-
-;; compile call to lambda in head position, inlined
-(def (compile-let g env tail? form)
- (let ((lam (car form))
- (args (cdr form))
- (sp (bcode:sp g)))
- (let ((vars (cadr lam))
- (n (compile-arglist g env args)))
- (let ((newvars
- (vars-to-env vars (complex-bindings (caddr lam) vars) sp)))
- (box-vars g newvars)
- (let ((newenv
- (cons (nconc newvars (car env))
- (cdr env))))
- (compile-in g newenv tail? (caddr lam))
- (bcode:stack g (- n))
- (when (and (> n 0) (not tail?))
- (emit g 'shift n)))))))
-
-(def (compile-app g env tail? x)
- (let ((head (car x)))
- (let ((head
- (if (and (sym? head)
- (not (in-env? head env))
- (bound? head)
- (builtin? (top-level-value head)))
- (top-level-value head)
- head)))
- (if (length> (cdr x) 255)
- ;; more than 255 arguments, need long versions of instructions
- (begin (compile-in g env NIL head)
- (bcode:stack g 1)
- (let ((nargs (compile-arglist g env (cdr x))))
- (bcode:stack g (- nargs))
- (emit g (if tail? 'tcall.l 'call.l) nargs)))
- (let ((b (and (builtin? head)
- (builtin->instruction head))))
- (if (and (eq? head 'cadr)
- (not (in-env? head env))
- (equal? (top-level-value 'cadr) cadr)
- (length= x 2))
- (begin (compile-in g env NIL (cadr x))
- (emit g 'cadr))
- (if (and (cons? head)
- (lambda? (car head))
- (inlineable? x))
- (compile-let g env tail? x)
- (begin
- (unless b
- (compile-in g env NIL head)
- (bcode:stack g 1))
- (let ((nargs (compile-arglist g env (cdr x))))
- (bcode:stack g (- nargs))
- (unless b (bcode:stack g -1))
- (if b
- (compile-builtin-call g env tail? x head b nargs)
- (emit g (if tail? 'tcall 'call) nargs)))))))))))
-
-;; lambda, main compilation loop
-
-(def (fits-i8 x) (and (fixnum? x) (>= 127 x -128)))
-
-(def (compile-in g env tail? x (outl NIL))
- (cond ((sym? x) (compile-sym g env x T))
- ((atom? x)
- (cond ((eq? x 0) (emit g 'load0))
- ((eq? x 1) (emit g 'load1))
- ((eq? x T) (emit g 'loadt))
- ((not x) (emit g 'loadnil))
- ((void? x) (emit g 'loadvoid))
- ((fits-i8 x) (emit g 'loadi8 x))
- (else (emit g 'loadv x))))
- ((eq? (car x) 'aset!)
- (compile-aset! g env (cdr x)))
- ((or (not (sym? (car x))) (bound? (car x)) (in-env? (car x) env))
- (compile-app g env tail? x))
- (else
- (case (car x)
- (quote (if (self-evaluating? (cadr x))
- (compile-in g env tail? (cadr x))
- (emit g 'loadv (cadr x))))
- (if (compile-if g env tail? x))
- (begin (compile-begin g env tail? (cdr x)))
- (prog1 (compile-prog1 g env x))
- (λ (receive (the-f cenv) (compile-f- env x)
- (begin (emit g 'loadv the-f)
- (when cenv
- (for-each (λ (var)
- (compile-sym g env var NIL))
- cenv)
- (emit g 'closure (length cenv))))))
- (and (compile-and g env tail? (cdr x) outl))
- (or (compile-or g env tail? (cdr x)))
- (while (compile-while g env (cadr x) (cons 'begin (cddr x))))
- (return (compile-in g env T (cadr x))
- (emit g 'ret))
- (set! (let* ((name (cadr x))
- (doc+value (separate-doc-from-body (cddr x)))
- (doc (car (car doc+value)))
- (value (cdr doc+value)))
- (unless (sym? name)
- (error "set!: name must be a symbol"))
- (when doc
- (sym-set-doc name doc (and (cons? (car value))
- (lambda? (car (car value)))
- (lambda:vars (car value)))))
- (compile-set! g env name (car value))))
- (trycatch (compile-in g env NIL `(λ () ,(cadr x)))
- (unless (1arg-lambda? (caddr x))
- (error "trycatch: second form must be a 1-argument lambda"))
- (compile-in g env NIL (caddr x))
- (emit g 'trycatch))
- (else (compile-app g env tail? x))))))
-
-;; optional and keyword args
-
-(def (keyword-arg? x) (and (cons? x) (keyword? (car x))))
-(def (keyword->sym k)
- (if (keyword? k)
- (sym (let ((s (str k)))
- (str-sub s 1 (str-length s))))
- k))
-
-(def (lambda-vars l)
- (def (check-formals l o opt kw)
- (cond ((or (not l) (sym? l)) T)
- ((and (cons? l) (sym? (car l)))
- (if (or opt kw)
- (error "compile error: invalid argument list "
- o ": optional arguments must come after required")
- (check-formals (cdr l) o opt kw)))
- ((and (cons? l) (cons? (car l)))
- (unless (and (length= (car l) 2)
- (sym? (caar l)))
- (error "compile error: invalid optional argument " (car l)
- " in list " o))
- (if (keyword? (caar l))
- (check-formals (cdr l) o opt T)
- (if kw
- (error "compile error: invalid argument list "
- o ": keyword arguments must come last.")
- (check-formals (cdr l) o T kw))))
- ((cons? l)
- (error "compile error: invalid formal argument " (car l)
- " in list " o))
- (else
- (if (eq? l o)
- (error "compile error: invalid argument list " o)
- (error "compile error: invalid formal argument " l
- " in list " o)))))
- (check-formals l l NIL NIL)
- (map (λ (s) (if (cons? s) (keyword->sym (car s)) s))
- (to-proper l)))
-
-(def (emit-optional-arg-inits g env opta vars i)
- ; i is the lexical var index of the opt arg to process next
- (when (cons? opta)
- (let ((nxt (make-label g)))
- (emit g 'brbound i)
- (emit g 'brnn nxt)
- (compile-in g (extend-env env (list-head vars i) NIL) NIL (cadar opta))
- (emit g 'seta i)
- (emit g 'pop)
- (mark-label g nxt)
- (emit-optional-arg-inits g env (cdr opta) vars (+ i 1)))))
-
-;; define
-
-(def (expand-define x)
- ;; expand a single `define` expression to `set!`
- (let* ((form (cadr x))
- (body (if (cons? (cddr x))
- (cddr x)
- (if (sym? form)
- #.void
- (error "compile error: invalid syntax " (print-to-str x))))))
- (if (sym? form)
- `(#.void (set! ,form ,(car body)))
- `(#.void (set! ,(car form)
- (λ ,(cdr form) ,@body . ,(car form)))))))
-
-(def get-defined-vars
- (letrec ((get-defined-vars-
- (λ (expr)
- (cond ((atom? expr) NIL)
- ((and (eq? (car expr) 'def)
- (cons? (cdr expr)))
- (or (and (sym? (cadr expr))
- (list (cadr expr)))
- (and (cons? (cadr expr))
- (sym? (caadr expr))
- (list (caadr expr)))))
- ((eq? (car expr) 'begin)
- (apply nconc (map get-defined-vars- (cdr expr))))
- (else NIL)))))
- (λ (expr) (delete-duplicates (get-defined-vars- expr)))))
-
-(def (lower-define e)
- ;; convert lambda to one body expression and process internal defines
- (def (λ-body e)
- (let* ((B (if (cons? (cddr e))
- (if (cons? (cdddr e))
- (cons 'begin (cddr e))
- (caddr e))
- (void)))
- (V (get-defined-vars B))
- (new-B (lower-define B)))
- (if V
- (cons `(λ ,V ,new-B)
- (map void V))
- new-B)))
- (cond ((or (atom? e) (quoted? e))
- e)
- ((eq? (car e) 'def)
- (lower-define (expand-define e)))
- ((lambda? (car e))
- `(λ ,(cadr e) ,(λ-body e) . ,(lastcdr e)))
- (else
- (map lower-define e))))
-
-;; closure analysis
-
-(def (lambda:body e) (caddr e))
-(def (lambda:vars e) (lambda-vars (cadr e)))
-
-(def (diff s1 s2)
- (cond ((not s1) NIL)
- ((memq (car s1) s2) (diff (cdr s1) s2))
- (else (cons (car s1) (diff (cdr s1) s2)))))
-
-;; bindings that are both captured and set!'d
-(def (complex-bindings- e vars head nested capt setd)
- (cond ((not vars) NIL)
- ((sym? e)
- (when (and nested (memq e vars))
- (put! capt e T)))
- ((or (atom? e) (quoted? e)) NIL)
- ((eq? (car e) 'set!)
- (when (memq (cadr e) vars)
- (put! setd (cadr e) T)
- (if nested (put! capt (cadr e) T)))
- (complex-bindings- (caddr e) vars NIL nested capt setd))
- ((lambda? (car e))
- (complex-bindings- (lambda:body e)
- (diff vars (lambda:vars e))
- NIL
- (or (not head) nested)
- capt setd))
- (else
- (cons (complex-bindings- (car e) vars (inlineable? e) nested capt setd)
- (map (λ (x)
- (complex-bindings- x vars NIL nested capt setd))
- (cdr e))))))
-
-(def (complex-bindings e vars)
- (let ((capt (table))
- (setd (table)))
- (complex-bindings- e vars NIL NIL capt setd)
- (filter (λ (x) (has? capt x))
- (table-keys setd))))
-
-(def (vars-to-env vars cb offs)
- (map (λ (var i) (vinfo var (not (not (memq var cb))) (+ i offs)))
- vars (iota (length vars))))
-
-(def (extend-env env vars cb)
- (cons (vars-to-env vars cb 0)
- env))
-
-;; main entry points
-
-(def (compile f) (compile-f NIL (lower-define f)))
-
-(def (compile-thunk expr)
- ;; to eval a top-level expression we need to avoid internal define
- (compile-f NIL `(λ () ,(lower-define expr))))
-
-(def (compile-f env f)
- (receive (ff ignore)
- (compile-f- env f)
- ff))
-
-(def (compile-f- env f)
- (def (any-duplicate-kw kw)
- (let ((k (caar kw))
- (rest (cdr kw)))
- (when rest
- (or (any (λ (next) (and (eq? k (car next)) k)) rest)
- (any-duplicate-kw rest)))))
-
- ;; compile lambda expression, assuming defines already lowered
- (let ((g (make-code-emitter))
- (args (cadr f))
- (atail (lastcdr (cadr f)))
- (vars (lambda:vars f))
- (opta (filter cons? (cadr f)))
- (last (lastcdr f)))
- (let* ((name (if (not last) 'λ last))
- (nargs (if (atom? args) 0 (length args)))
- (nreq (- nargs (length opta)))
- (kwa (filter keyword-arg? opta))
- (dupkw (any-duplicate-kw kwa)))
-
- (when dupkw
- (error "compile error: duplicate keyword " dupkw))
-
- ;; emit argument checking prologue
- (when opta
- (if (not kwa)
- (emit g 'optargs nreq
- (if atail (- nargs) nargs))
- (begin
- (bcode:indexfor g (make-perfect-hash-table
- (map cons
- (map car kwa)
- (iota (length kwa)))))
- (emit g 'keyargs nreq (length kwa)
- (if atail (- nargs) nargs))))
- (emit-optional-arg-inits g env opta vars nreq))
-
- (cond ((> nargs 255) (emit g (if atail 'vargc.l 'argc.l) nargs))
- (atail (emit g 'vargc nargs))
- ((not opta) (emit g 'argc nargs)))
-
- (let ((newenv (extend-env env vars (complex-bindings (lambda:body f) vars))))
- (box-vars g (car newenv))
- ;; set initial stack pointer
- (aset! g 4 (+ (length vars) 4))
- ;; compile body and return
- (compile-in g newenv T (lambda:body f))
- (emit g 'ret)
- (values (fn (encode-byte-code (bcode:code g))
- (const-to-idx-vec g)
- name)
- (bcode:cenv g))))))
-
-;; disassembler
-
-(def (ref-s32-LE a i)
- (s32 (+ (ash (aref a (+ i 0)) 0)
- (ash (aref a (+ i 1)) 8)
- (ash (aref a (+ i 2)) 16)
- (ash (aref a (+ i 3)) 24))))
-
-(def (ref-s16-LE a i)
- (s16 (+ (ash (aref a (+ i 0)) 0)
- (ash (aref a (+ i 1)) 8))))
-
-(def (hex5 n)
- (str-lpad (num->str n 16) 5 #\0))
-
-(def (fn-disasm f (ip NIL) . lev?)
- (when (not lev?)
- (fn-disasm f ip 0)
- (newline)
- (return (void)))
- (let ((lev (car lev?))
- (code (fn-code f))
- (vals (fn-vals f)))
- (def (print-val v)
- (if (and (fn? v) (not (builtin? v)))
- (begin (newline)
- (fn-disasm v NIL (+ lev 1)))
- (print v)))
- (def (print-inst inst s sz) (princ (if (and ip (= lev 0) (>= ip (1- s)) (< ip (+ s sz)))
- " >"
- " ")
- (hex5 (- s 1)) ": "
- inst " "))
- (let ((i 0)
- (N (length code)))
- (while (< i N)
- ; find key whose value matches the current byte
- (let ((inst (table-foldl (λ (k v z)
- (or z (and (= v (aref code i))
- k)))
- NIL Instructions)))
- (when (> i 0) (newline))
- (dotimes (xx lev) (princ "\t"))
- (set! i (+ i 1))
- (case inst
- ((loadv.l loadg.l setg.l)
- (print-inst inst i 4)
- (print-val (aref vals (ref-s32-LE code i)))
- (set! i (+ i 4)))
-
- ((loadv loadg setg)
- (print-inst inst i 1)
- (print-val (aref vals (aref code i)))
- (set! i (+ i 1)))
-
- ((loada seta loadc call tcall list + - * / < = vec
- argc vargc loadi8 apply tapply closure box shift aref)
- (print-inst inst i 1)
- (princ (num->str (+ (aref code i) (if (eq? inst 'aref) 3 0))))
- (set! i (+ i 1)))
-
- ((loada.l seta.l loadc.l argc.l vargc.l call.l tcall.l box.l)
- (print-inst inst i 4)
- (princ (num->str (ref-s32-LE code i)))
- (set! i (+ i 4)))
-
- ((optargs keyargs)
- (print-inst inst i (+ 8 (if (eq? inst 'keyargs) 4 0)))
- (princ (num->str (ref-s32-LE code i)) " ")
- (set! i (+ i 4))
- (princ (num->str (ref-s32-LE code i)))
- (set! i (+ i 4))
- (when (eq? inst 'keyargs)
- (princ " ")
- (princ (num->str (ref-s32-LE code i)) " ")
- (set! i (+ i 4))))
-
- ((brbound)
- (print-inst inst i 4)
- (princ (num->str (ref-s32-LE code i)) " ")
- (set! i (+ i 4)))
-
- ((jmp brne brnn brn)
- (print-inst inst i 2)
- (princ "@" (hex5 (+ i (ref-s16-LE code i))))
- (set! i (+ i 2)))
-
- ((jmp.l brne.l brnn.l brn.l)
- (print-inst inst i 4)
- (princ "@" (hex5 (+ i (ref-s32-LE code i))))
- (set! i (+ i 4)))
-
- (else (print-inst inst i 0))))))))
-
-; From SRFI 89 by Marc Feeley (http://srfi.schemers.org/srfi-89/srfi-89.html)
-; Copyright (C) Marc Feeley 2006. All Rights Reserved.
-;
-; "alist" is a list of pairs of the form "(keyword . value)"
-; The result is a perfect hash-table represented as a vector of
-; length 2*N, where N is the hash modulus. If the keyword K is in
-; the hash-table it is at index
-;
-; X = (* 2 ($hash-keyword K N))
-;
-; and the associated value is at index X+1.
-(def (make-perfect-hash-table alist)
- (def ($hash-keyword key n)
- (mod0 (abs (hash key)) n))
- (let loop1 ((n (length alist)))
- (let ((v (vec-alloc (* 2 n) NIL)))
- (let loop2 ((lst alist))
- (if (cons? lst)
- (let ((key (caar lst)))
- (let ((x (* 2 ($hash-keyword key n))))
- (if (aref v x)
- (loop1 (+ n 1))
- (begin
- (aset! v x key)
- (aset! v (+ x 1) (cdar lst))
- (loop2 (cdr lst))))))
- v)))))
--- /dev/null
+++ b/src/compiler.sl
@@ -1,0 +1,870 @@
+;; code generation state, constant tables, bytecode encoding
+
+(def (make-code-emitter) (vec NIL (table) 0 NIL 0))
+(defmacro (bcode:code b) `(aref ,b 0))
+(defmacro (bcode:ctable b) `(aref ,b 1))
+(defmacro (bcode:nconst b) `(aref ,b 2))
+(defmacro (bcode:cenv b) `(aref ,b 3))
+(defmacro (bcode:sp b) `(aref ,b 4))
+(defmacro (bcode:stack b n) `(aset! ,b 4 (+ (bcode:sp ,b) ,n)))
+
+;; get an index for a referenced value in a bytecode object
+(def (bcode:indexfor b v)
+ (let ((const-to-idx (bcode:ctable b))
+ (nconst (bcode:nconst b)))
+ (if (has? const-to-idx v)
+ (get const-to-idx v)
+ (begin (put! const-to-idx v nconst)
+ (prog1 nconst
+ (aset! b 2 (+ nconst 1)))))))
+
+(def (emit e inst . args)
+ (def (load? i)
+ (member i '(load0 load1 loadt loadf loadnil loadvoid))) ; FIXME no load immediate here yet
+ (let ((bc (aref e 0)))
+ (if (not args)
+ (if (and (eq? inst 'car)
+ (eq? (car bc) 'cdr))
+ (set-car! bc 'cadr)
+ (cond ((and (eq? inst 'pop) (load? (car bc)))
+ (aset! e 0 (cdr bc)))
+ (else
+ (aset! e 0 (cons inst bc)))))
+ (begin
+ (when (memq inst '(loadv loadg setg))
+ (set! args (list (bcode:indexfor e (car args)))))
+ (let ((longform
+ (assq inst '((loadv loadv.l) (loadg loadg.l) (setg setg.l)
+ (loada loada.l) (seta seta.l) (box box.l)))))
+ (when (and longform (> (car args) 255))
+ (set! inst (cadr longform))))
+ (let ((longform
+ (assq inst '((loadc loadc.l)))))
+ (when (and longform (> (car args) 255))
+ (set! inst (cadr longform))))
+ (if (eq? inst 'loada)
+ (cond ((equal? args '(0))
+ (set! inst 'loada0)
+ (set! args NIL))
+ ((equal? args '(1))
+ (set! inst 'loada1)
+ (set! args NIL))))
+ (if (eq? inst 'loadc)
+ (cond ((equal? args '(0))
+ (set! inst 'loadc0)
+ (set! args NIL))
+ ((equal? args '(1))
+ (set! inst 'loadc1)
+ (set! args NIL))))
+
+ (let ((lasti (car bc)))
+ (cond ((and (eq? inst 'brn)
+ (cond ((eq? lasti 'not)
+ (aset! e 0 (cons (car args) (cons 'brnn (cdr bc)))))
+ ((eq? lasti 'eq?)
+ (aset! e 0 (cons (car args) (cons 'brne (cdr bc)))))
+ (else NIL))))
+ (else
+ (aset! e 0 (nreconc (cons inst args) bc)))))))
+ e))
+
+(defmacro (make-label e) `(gensym))
+(defmacro (mark-label e l) `(emit ,e 'label ,l))
+
+;; convert symbolic bytecode representation to a byte array.
+;; labels are fixed-up.
+(def (encode-byte-code e)
+ (let* ((cl (reverse! e))
+ (v (list->vec cl))
+ (long? (>= (+ (length v) ;; 1 byte for each entry, plus...
+ ;; at most half the entries in this vector can be
+ ;; instructions accepting 32-bit arguments
+ (* 3 (div0 (length v) 2)))
+ 65536)))
+ (let ((n (length v))
+ (i 0)
+ (label-to-loc (table))
+ (fixup-to-label (table))
+ (bcode (buffer))
+ (vi NIL)
+ (nxt NIL))
+ (while (< i n)
+ (set! vi (aref v i))
+ (if (eq? vi 'label)
+ (begin (put! label-to-loc (aref v (+ i 1)) (sizeof bcode))
+ (set! i (+ i 2)))
+ (begin
+ (io-write bcode
+ (get Instructions
+ (if long?
+ (case vi
+ (jmp 'jmp.l)
+ (brne 'brne.l)
+ (brnn 'brnn.l)
+ (brn 'brn.l)
+ (else vi))
+ vi)))
+ (set! i (+ i 1))
+ (set! nxt (and (< i n) (aref v i)))
+ (cond ((memq vi '(jmp brne brnn brn))
+ (put! fixup-to-label (sizeof bcode) nxt)
+ (io-write bcode ((if long? s32 s16) 0))
+ (set! i (+ i 1)))
+ ((eq? vi 'brbound)
+ (io-write bcode (s32 nxt))
+ (set! i (+ i 1)))
+ ((num? nxt)
+ (case vi
+ ((loadv.l loadg.l setg.l loada.l seta.l
+ argc.l vargc.l call.l tcall.l loadc.l box.l)
+ (io-write bcode (s32 nxt))
+ (set! i (+ i 1)))
+
+ ((optargs keyargs) ; 2 s32 args
+ (io-write bcode (s32 nxt))
+ (set! i (+ i 1))
+ (io-write bcode (s32 (aref v i)))
+ (set! i (+ i 1))
+ (when (eq? vi 'keyargs)
+ (io-write bcode (s32 (aref v i)))
+ (set! i (+ i 1))))
+
+ (else
+ ; other number arguments are always u8
+ (io-write bcode (u8 nxt))
+ (set! i (+ i 1)))))
+ (else NIL)))))
+
+ (for-each
+ (λ (addr labl)
+ (io-seek bcode addr)
+ (io-write bcode ((if long? s32 s16)
+ (- (get label-to-loc labl) addr))))
+ fixup-to-label)
+ (io->str bcode))))
+
+(def (const-to-idx-vec e)
+ (let ((cvec (vec-alloc (bcode:nconst e))))
+ (for-each (λ (val idx) (aset! cvec idx val))
+ (bcode:ctable e))
+ cvec))
+
+;; variables
+
+(def (vinfo symbol heap? index) (list symbol heap? index))
+(def vinfo:sym car)
+(def vinfo:heap? cadr)
+(def vinfo:index caddr)
+
+(def (quoted? e) (eq? (car e) 'quote))
+
+(def (capture-var! g s)
+ (let ((ce (bcode:cenv g)))
+ (let ((n (index-of s ce 0)))
+ (or n
+ (prog1 (length ce)
+ (aset! g 3 (nconc ce (list s))))))))
+
+(def (index-of item lst start)
+ (cond ((not lst) NIL)
+ ((eq? item (car lst)) start)
+ (else (index-of item (cdr lst) (+ start 1)))))
+
+(def (in-env? s env)
+ (and (cons? env)
+ (or (assq s (car env))
+ (in-env? s (cdr env)))))
+
+(def (lookup-sym s env lev)
+ (if (not env)
+ 'global
+ (let* ((curr (car env))
+ (vi (assq s curr)))
+ (if vi
+ (cons lev vi)
+ (lookup-sym s
+ (cdr env)
+ (+ lev 1))))))
+
+(def (printable? x) (not (or (io? x)
+ (void? x)
+ (eof-object? x))))
+
+(def (compile-sym g env s deref)
+ (let ((loc (lookup-sym s env 0)))
+ (cond ((eq? loc 'global)
+ (if (and (const? s)
+ (printable? (top-level-value s)))
+ (emit g 'loadv (top-level-value s))
+ (emit g 'loadg s)))
+
+ ((= (car loc) 0)
+ (emit g 'loada (vinfo:index (cdr loc)))
+ (when (and deref (vinfo:heap? (cdr loc)))
+ (emit g 'car)))
+
+ (else
+ (emit g 'loadc (capture-var! g s))
+ (when (and deref (vinfo:heap? (cdr loc)))
+ (emit g 'car))))))
+
+(def (compile-aset! g env args)
+ (let ((nref (- (length args) 2)))
+ (cond ((= nref 1)
+ (compile-app g env NIL (cons 'aset! args)))
+ ((> nref 1)
+ (compile-app g env NIL (cons 'aref (list-head args nref)))
+ (let ((nargs (compile-arglist g env (list-tail args nref))))
+ (bcode:stack g (- nargs))
+ (emit g 'aset!)))
+ (else (argc-error 'aset! 3)))))
+
+(def (compile-set! g env s rhs)
+ (let ((loc (lookup-sym s env 0)))
+ (if (eq? loc 'global)
+ (begin (compile-in g env NIL rhs)
+ (emit g 'setg s))
+ (let ((arg? (= (car loc) 0)))
+ (let ((h? (vinfo:heap? (cdr loc)))
+ (idx (if arg?
+ (vinfo:index (cdr loc))
+ (capture-var! g s))))
+ (if h?
+ (begin (emit g (if arg? 'loada 'loadc) idx)
+ (bcode:stack g 1)
+ (compile-in g env NIL rhs)
+ (bcode:stack g -1)
+ (emit g 'set-car!))
+
+ (begin (compile-in g env NIL rhs)
+ (unless arg? (error (str "internal error: misallocated var " s)))
+ (emit g 'seta idx))))))))
+
+(def (box-vars g env)
+ (let loop ((e env))
+ (when (cons? e)
+ (if (cadr (car e))
+ (emit g 'box (caddr (car e))))
+ (loop (cdr e)))))
+
+;; control flow
+
+(def (compile-if g env tail? x)
+ (let ((thenl (make-label g))
+ (elsel (make-label g))
+ (endl (make-label g))
+ (test (cadr x))
+ (then (caddr x))
+ (else (if (cons? (cdddr x))
+ (cadddr x)
+ NIL)))
+ (cond ((eq? test T)
+ (compile-in g env tail? then))
+ ((not test)
+ (compile-in g env tail? else))
+ (else
+ (compile-in g env NIL test elsel)
+ (emit g 'brn elsel)
+ (mark-label g thenl)
+ (compile-in g env tail? then)
+ (if tail?
+ (emit g 'ret)
+ (emit g 'jmp endl))
+ (mark-label g elsel)
+ (compile-in g env tail? else)
+ (mark-label g endl)))))
+
+(def (compile-begin g env tail? forms)
+ (cond ((atom? forms) (compile-in g env tail? (void)))
+ ((atom? (cdr forms))
+ (compile-in g env tail? (car forms)))
+ (else
+ (compile-in g env NIL (car forms))
+ (emit g 'pop)
+ (compile-begin g env tail? (cdr forms)))))
+
+(def (compile-prog1 g env x)
+ (compile-in g env NIL (cadr x))
+ (when (cons? (cddr x))
+ (bcode:stack g 1)
+ (compile-begin g env NIL (cddr x))
+ (emit g 'pop)
+ (bcode:stack g -1)))
+
+(def (compile-while g env cond body)
+ (let ((top (make-label g))
+ (end (make-label g)))
+ (compile-in g env NIL (void))
+ (bcode:stack g 1)
+ (mark-label g top)
+ (compile-in g env NIL cond)
+ (emit g 'brn end)
+ (emit g 'pop)
+ (bcode:stack g -1)
+ (compile-in g env NIL body)
+ (emit g 'jmp top)
+ (mark-label g end)))
+
+(def (lambda? a)
+ (or (eq? a 'λ)
+ (eq? a 'lambda)))
+
+(def (1arg-lambda? func)
+ (and (cons? func)
+ (lambda? (car func))
+ (length= (cadr func) 1)))
+
+(def (compile-short-circuit g env tail? forms default branch outl)
+ (cond ((atom? forms) (compile-in g env tail? default outl))
+ ((atom? (cdr forms)) (compile-in g env tail? (car forms) outl))
+ (else
+ (let ((end (or outl (make-label g))))
+ (compile-in g env NIL (car forms) outl)
+ (bcode:stack g 1)
+ (unless outl (emit g 'dup))
+ (emit g branch end)
+ (bcode:stack g -1)
+ (unless outl (emit g 'pop))
+ (compile-short-circuit g env tail? (cdr forms) default branch outl)
+ (unless outl (mark-label g end))))))
+
+(def (compile-and g env tail? forms outl)
+ (compile-short-circuit g env tail? forms T 'brn outl))
+(def (compile-or g env tail? forms)
+ (compile-short-circuit g env tail? forms NIL 'brnn NIL))
+
+;; calls
+
+(def (compile-arglist g env lst)
+ (for-each (λ (a)
+ (compile-in g env NIL a)
+ (bcode:stack g 1))
+ lst)
+ (length lst))
+
+(def (argc-error head count)
+ (error "compile error: " head " expects " count
+ (if (= count 1)
+ " argument."
+ " arguments.")))
+
+(def builtin->instruction
+ (let ((b2i (table num? 'num? cons 'cons
+ fixnum? 'fixnum? equal? 'equal?
+ eq? 'eq? sym? 'sym?
+ div0 'div0 builtin? 'builtin?
+ aset! 'aset! - '- not 'not
+ apply 'apply atom? 'atom? nan? 'nan?
+ set-cdr! 'set-cdr! / '/
+ fn? 'fn? vec 'vec
+ list 'list bound? 'bound?
+ < '< * '* cdr 'cdr cadr 'cadr
+ + '+ eqv? 'eqv? compare 'compare aref 'aref
+ set-car! 'set-car! car 'car for 'for
+ cons? 'cons? = '= vec? 'vec?)))
+ (λ (b)
+ (get b2i b NIL))))
+
+(def (compile-builtin-call g env tail? x head b nargs)
+ (def (num-compare)
+ (if (= nargs 0)
+ (argc-error b 1)
+ (emit g b nargs)))
+ (let ((count (get arg-counts b NIL)))
+ (when (and count (not (length= (cdr x) count)))
+ (argc-error b count))
+ (case b ; handle special cases of vararg builtins
+ (list (if (= nargs 0)
+ (emit g 'loadnil)
+ (emit g b nargs)))
+ (< (num-compare))
+ (= (num-compare))
+ (+ (cond ((= nargs 0) (emit g 'load0))
+ ((= nargs 2) (emit g 'add2))
+ (else (emit g b nargs))))
+ (- (cond ((= nargs 0) (argc-error b 1))
+ ((= nargs 1) (emit g 'neg))
+ ((= nargs 2) (emit g 'sub2))
+ (else (emit g b nargs))))
+ (* (if (= nargs 0)
+ (emit g 'load1)
+ (emit g b nargs)))
+ (/ (if (= nargs 0)
+ (argc-error b 1)
+ (emit g b nargs)))
+ (vec (if (= nargs 0)
+ (emit g 'loadv #())
+ (emit g b nargs)))
+ (apply (if (< nargs 2)
+ (argc-error b 2)
+ (emit g (if tail? 'tapply 'apply) nargs)))
+ (aref (cond ((= nargs 2) (emit g 'aref2))
+ ((> nargs 2) (emit g b (- nargs 3)))
+ (else (argc-error b 2))))
+ (else (emit g b)))))
+
+(def (inlineable? form)
+ (let ((lam (car form)))
+ (and (cons? lam)
+ (lambda? (car lam))
+ (list? (cadr lam))
+ (every sym? (cadr lam))
+ (not (length> (cadr lam) 255))
+ (length= (cadr lam) (length (cdr form))))))
+
+;; compile call to lambda in head position, inlined
+(def (compile-let g env tail? form)
+ (let ((lam (car form))
+ (args (cdr form))
+ (sp (bcode:sp g)))
+ (let ((vars (cadr lam))
+ (n (compile-arglist g env args)))
+ (let ((newvars
+ (vars-to-env vars (complex-bindings (caddr lam) vars) sp)))
+ (box-vars g newvars)
+ (let ((newenv
+ (cons (nconc newvars (car env))
+ (cdr env))))
+ (compile-in g newenv tail? (caddr lam))
+ (bcode:stack g (- n))
+ (when (and (> n 0) (not tail?))
+ (emit g 'shift n)))))))
+
+(def (compile-app g env tail? x)
+ (let ((head (car x)))
+ (let ((head
+ (if (and (sym? head)
+ (not (in-env? head env))
+ (bound? head)
+ (builtin? (top-level-value head)))
+ (top-level-value head)
+ head)))
+ (if (length> (cdr x) 255)
+ ;; more than 255 arguments, need long versions of instructions
+ (begin (compile-in g env NIL head)
+ (bcode:stack g 1)
+ (let ((nargs (compile-arglist g env (cdr x))))
+ (bcode:stack g (- nargs))
+ (emit g (if tail? 'tcall.l 'call.l) nargs)))
+ (let ((b (and (builtin? head)
+ (builtin->instruction head))))
+ (if (and (eq? head 'cadr)
+ (not (in-env? head env))
+ (equal? (top-level-value 'cadr) cadr)
+ (length= x 2))
+ (begin (compile-in g env NIL (cadr x))
+ (emit g 'cadr))
+ (if (and (cons? head)
+ (lambda? (car head))
+ (inlineable? x))
+ (compile-let g env tail? x)
+ (begin
+ (unless b
+ (compile-in g env NIL head)
+ (bcode:stack g 1))
+ (let ((nargs (compile-arglist g env (cdr x))))
+ (bcode:stack g (- nargs))
+ (unless b (bcode:stack g -1))
+ (if b
+ (compile-builtin-call g env tail? x head b nargs)
+ (emit g (if tail? 'tcall 'call) nargs)))))))))))
+
+;; lambda, main compilation loop
+
+(def (fits-i8 x) (and (fixnum? x) (>= 127 x -128)))
+
+(def (compile-in g env tail? x (outl NIL))
+ (cond ((sym? x) (compile-sym g env x T))
+ ((atom? x)
+ (cond ((eq? x 0) (emit g 'load0))
+ ((eq? x 1) (emit g 'load1))
+ ((eq? x T) (emit g 'loadt))
+ ((not x) (emit g 'loadnil))
+ ((void? x) (emit g 'loadvoid))
+ ((fits-i8 x) (emit g 'loadi8 x))
+ (else (emit g 'loadv x))))
+ ((eq? (car x) 'aset!)
+ (compile-aset! g env (cdr x)))
+ ((or (not (sym? (car x))) (bound? (car x)) (in-env? (car x) env))
+ (compile-app g env tail? x))
+ (else
+ (case (car x)
+ (quote (if (self-evaluating? (cadr x))
+ (compile-in g env tail? (cadr x))
+ (emit g 'loadv (cadr x))))
+ (if (compile-if g env tail? x))
+ (begin (compile-begin g env tail? (cdr x)))
+ (prog1 (compile-prog1 g env x))
+ (λ (receive (the-f cenv) (compile-f- env x)
+ (begin (emit g 'loadv the-f)
+ (when cenv
+ (for-each (λ (var)
+ (compile-sym g env var NIL))
+ cenv)
+ (emit g 'closure (length cenv))))))
+ (and (compile-and g env tail? (cdr x) outl))
+ (or (compile-or g env tail? (cdr x)))
+ (while (compile-while g env (cadr x) (cons 'begin (cddr x))))
+ (return (compile-in g env T (cadr x))
+ (emit g 'ret))
+ (set! (let* ((name (cadr x))
+ (doc+value (separate-doc-from-body (cddr x)))
+ (doc (car (car doc+value)))
+ (value (cdr doc+value)))
+ (unless (sym? name)
+ (error "set!: name must be a symbol"))
+ (when doc
+ (sym-set-doc name doc (and (cons? (car value))
+ (lambda? (car (car value)))
+ (lambda:vars (car value)))))
+ (compile-set! g env name (car value))))
+ (trycatch (compile-in g env NIL `(λ () ,(cadr x)))
+ (unless (1arg-lambda? (caddr x))
+ (error "trycatch: second form must be a 1-argument lambda"))
+ (compile-in g env NIL (caddr x))
+ (emit g 'trycatch))
+ (else (compile-app g env tail? x))))))
+
+;; optional and keyword args
+
+(def (keyword-arg? x) (and (cons? x) (keyword? (car x))))
+(def (keyword->sym k)
+ (if (keyword? k)
+ (sym (let ((s (str k)))
+ (str-sub s 1 (str-length s))))
+ k))
+
+(def (lambda-vars l)
+ (def (check-formals l o opt kw)
+ (cond ((or (not l) (sym? l)) T)
+ ((and (cons? l) (sym? (car l)))
+ (if (or opt kw)
+ (error "compile error: invalid argument list "
+ o ": optional arguments must come after required")
+ (check-formals (cdr l) o opt kw)))
+ ((and (cons? l) (cons? (car l)))
+ (unless (and (length= (car l) 2)
+ (sym? (caar l)))
+ (error "compile error: invalid optional argument " (car l)
+ " in list " o))
+ (if (keyword? (caar l))
+ (check-formals (cdr l) o opt T)
+ (if kw
+ (error "compile error: invalid argument list "
+ o ": keyword arguments must come last.")
+ (check-formals (cdr l) o T kw))))
+ ((cons? l)
+ (error "compile error: invalid formal argument " (car l)
+ " in list " o))
+ (else
+ (if (eq? l o)
+ (error "compile error: invalid argument list " o)
+ (error "compile error: invalid formal argument " l
+ " in list " o)))))
+ (check-formals l l NIL NIL)
+ (map (λ (s) (if (cons? s) (keyword->sym (car s)) s))
+ (to-proper l)))
+
+(def (emit-optional-arg-inits g env opta vars i)
+ ; i is the lexical var index of the opt arg to process next
+ (when (cons? opta)
+ (let ((nxt (make-label g)))
+ (emit g 'brbound i)
+ (emit g 'brnn nxt)
+ (compile-in g (extend-env env (list-head vars i) NIL) NIL (cadar opta))
+ (emit g 'seta i)
+ (emit g 'pop)
+ (mark-label g nxt)
+ (emit-optional-arg-inits g env (cdr opta) vars (+ i 1)))))
+
+;; define
+
+(def (expand-define x)
+ ;; expand a single `define` expression to `set!`
+ (let* ((form (cadr x))
+ (body (if (cons? (cddr x))
+ (cddr x)
+ (if (sym? form)
+ #.void
+ (error "compile error: invalid syntax " (print-to-str x))))))
+ (if (sym? form)
+ `(#.void (set! ,form ,(car body)))
+ `(#.void (set! ,(car form)
+ (λ ,(cdr form) ,@body . ,(car form)))))))
+
+(def get-defined-vars
+ (letrec ((get-defined-vars-
+ (λ (expr)
+ (cond ((atom? expr) NIL)
+ ((and (eq? (car expr) 'def)
+ (cons? (cdr expr)))
+ (or (and (sym? (cadr expr))
+ (list (cadr expr)))
+ (and (cons? (cadr expr))
+ (sym? (caadr expr))
+ (list (caadr expr)))))
+ ((eq? (car expr) 'begin)
+ (apply nconc (map get-defined-vars- (cdr expr))))
+ (else NIL)))))
+ (λ (expr) (delete-duplicates (get-defined-vars- expr)))))
+
+(def (lower-define e)
+ ;; convert lambda to one body expression and process internal defines
+ (def (λ-body e)
+ (let* ((B (if (cons? (cddr e))
+ (if (cons? (cdddr e))
+ (cons 'begin (cddr e))
+ (caddr e))
+ (void)))
+ (V (get-defined-vars B))
+ (new-B (lower-define B)))
+ (if V
+ (cons `(λ ,V ,new-B)
+ (map void V))
+ new-B)))
+ (cond ((or (atom? e) (quoted? e))
+ e)
+ ((eq? (car e) 'def)
+ (lower-define (expand-define e)))
+ ((lambda? (car e))
+ `(λ ,(cadr e) ,(λ-body e) . ,(lastcdr e)))
+ (else
+ (map lower-define e))))
+
+;; closure analysis
+
+(def (lambda:body e) (caddr e))
+(def (lambda:vars e) (lambda-vars (cadr e)))
+
+(def (diff s1 s2)
+ (cond ((not s1) NIL)
+ ((memq (car s1) s2) (diff (cdr s1) s2))
+ (else (cons (car s1) (diff (cdr s1) s2)))))
+
+;; bindings that are both captured and set!'d
+(def (complex-bindings- e vars head nested capt setd)
+ (cond ((not vars) NIL)
+ ((sym? e)
+ (when (and nested (memq e vars))
+ (put! capt e T)))
+ ((or (atom? e) (quoted? e)) NIL)
+ ((eq? (car e) 'set!)
+ (when (memq (cadr e) vars)
+ (put! setd (cadr e) T)
+ (if nested (put! capt (cadr e) T)))
+ (complex-bindings- (caddr e) vars NIL nested capt setd))
+ ((lambda? (car e))
+ (complex-bindings- (lambda:body e)
+ (diff vars (lambda:vars e))
+ NIL
+ (or (not head) nested)
+ capt setd))
+ (else
+ (cons (complex-bindings- (car e) vars (inlineable? e) nested capt setd)
+ (map (λ (x)
+ (complex-bindings- x vars NIL nested capt setd))
+ (cdr e))))))
+
+(def (complex-bindings e vars)
+ (let ((capt (table))
+ (setd (table)))
+ (complex-bindings- e vars NIL NIL capt setd)
+ (filter (λ (x) (has? capt x))
+ (table-keys setd))))
+
+(def (vars-to-env vars cb offs)
+ (map (λ (var i) (vinfo var (not (not (memq var cb))) (+ i offs)))
+ vars (iota (length vars))))
+
+(def (extend-env env vars cb)
+ (cons (vars-to-env vars cb 0)
+ env))
+
+;; main entry points
+
+(def (compile f) (compile-f NIL (lower-define f)))
+
+(def (compile-thunk expr)
+ ;; to eval a top-level expression we need to avoid internal define
+ (compile-f NIL `(λ () ,(lower-define expr))))
+
+(def (compile-f env f)
+ (receive (ff ignore)
+ (compile-f- env f)
+ ff))
+
+(def (compile-f- env f)
+ (def (any-duplicate-kw kw)
+ (let ((k (caar kw))
+ (rest (cdr kw)))
+ (when rest
+ (or (any (λ (next) (and (eq? k (car next)) k)) rest)
+ (any-duplicate-kw rest)))))
+
+ ;; compile lambda expression, assuming defines already lowered
+ (let ((g (make-code-emitter))
+ (args (cadr f))
+ (atail (lastcdr (cadr f)))
+ (vars (lambda:vars f))
+ (opta (filter cons? (cadr f)))
+ (last (lastcdr f)))
+ (let* ((name (if (not last) 'λ last))
+ (nargs (if (atom? args) 0 (length args)))
+ (nreq (- nargs (length opta)))
+ (kwa (filter keyword-arg? opta))
+ (dupkw (any-duplicate-kw kwa)))
+
+ (when dupkw
+ (error "compile error: duplicate keyword " dupkw))
+
+ ;; emit argument checking prologue
+ (when opta
+ (if (not kwa)
+ (emit g 'optargs nreq
+ (if atail (- nargs) nargs))
+ (begin
+ (bcode:indexfor g (make-perfect-hash-table
+ (map cons
+ (map car kwa)
+ (iota (length kwa)))))
+ (emit g 'keyargs nreq (length kwa)
+ (if atail (- nargs) nargs))))
+ (emit-optional-arg-inits g env opta vars nreq))
+
+ (cond ((> nargs 255) (emit g (if atail 'vargc.l 'argc.l) nargs))
+ (atail (emit g 'vargc nargs))
+ ((not opta) (emit g 'argc nargs)))
+
+ (let ((newenv (extend-env env vars (complex-bindings (lambda:body f) vars))))
+ (box-vars g (car newenv))
+ ;; set initial stack pointer
+ (aset! g 4 (+ (length vars) 4))
+ ;; compile body and return
+ (compile-in g newenv T (lambda:body f))
+ (emit g 'ret)
+ (values (fn (encode-byte-code (bcode:code g))
+ (const-to-idx-vec g)
+ name)
+ (bcode:cenv g))))))
+
+;; disassembler
+
+(def (ref-s32-LE a i)
+ (s32 (+ (ash (aref a (+ i 0)) 0)
+ (ash (aref a (+ i 1)) 8)
+ (ash (aref a (+ i 2)) 16)
+ (ash (aref a (+ i 3)) 24))))
+
+(def (ref-s16-LE a i)
+ (s16 (+ (ash (aref a (+ i 0)) 0)
+ (ash (aref a (+ i 1)) 8))))
+
+(def (hex5 n)
+ (str-lpad (num->str n 16) 5 #\0))
+
+(def (fn-disasm f (ip NIL) . lev?)
+ (when (not lev?)
+ (fn-disasm f ip 0)
+ (newline)
+ (return (void)))
+ (let ((lev (car lev?))
+ (code (fn-code f))
+ (vals (fn-vals f)))
+ (def (print-val v)
+ (if (and (fn? v) (not (builtin? v)))
+ (begin (newline)
+ (fn-disasm v NIL (+ lev 1)))
+ (print v)))
+ (def (print-inst inst s sz) (princ (if (and ip (= lev 0) (>= ip (1- s)) (< ip (+ s sz)))
+ " >"
+ " ")
+ (hex5 (- s 1)) ": "
+ inst " "))
+ (let ((i 0)
+ (N (length code)))
+ (while (< i N)
+ ; find key whose value matches the current byte
+ (let ((inst (table-foldl (λ (k v z)
+ (or z (and (= v (aref code i))
+ k)))
+ NIL Instructions)))
+ (when (> i 0) (newline))
+ (dotimes (xx lev) (princ "\t"))
+ (set! i (+ i 1))
+ (case inst
+ ((loadv.l loadg.l setg.l)
+ (print-inst inst i 4)
+ (print-val (aref vals (ref-s32-LE code i)))
+ (set! i (+ i 4)))
+
+ ((loadv loadg setg)
+ (print-inst inst i 1)
+ (print-val (aref vals (aref code i)))
+ (set! i (+ i 1)))
+
+ ((loada seta loadc call tcall list + - * / < = vec
+ argc vargc loadi8 apply tapply closure box shift aref)
+ (print-inst inst i 1)
+ (princ (num->str (+ (aref code i) (if (eq? inst 'aref) 3 0))))
+ (set! i (+ i 1)))
+
+ ((loada.l seta.l loadc.l argc.l vargc.l call.l tcall.l box.l)
+ (print-inst inst i 4)
+ (princ (num->str (ref-s32-LE code i)))
+ (set! i (+ i 4)))
+
+ ((optargs keyargs)
+ (print-inst inst i (+ 8 (if (eq? inst 'keyargs) 4 0)))
+ (princ (num->str (ref-s32-LE code i)) " ")
+ (set! i (+ i 4))
+ (princ (num->str (ref-s32-LE code i)))
+ (set! i (+ i 4))
+ (when (eq? inst 'keyargs)
+ (princ " ")
+ (princ (num->str (ref-s32-LE code i)) " ")
+ (set! i (+ i 4))))
+
+ ((brbound)
+ (print-inst inst i 4)
+ (princ (num->str (ref-s32-LE code i)) " ")
+ (set! i (+ i 4)))
+
+ ((jmp brne brnn brn)
+ (print-inst inst i 2)
+ (princ "@" (hex5 (+ i (ref-s16-LE code i))))
+ (set! i (+ i 2)))
+
+ ((jmp.l brne.l brnn.l brn.l)
+ (print-inst inst i 4)
+ (princ "@" (hex5 (+ i (ref-s32-LE code i))))
+ (set! i (+ i 4)))
+
+ (else (print-inst inst i 0))))))))
+
+; From SRFI 89 by Marc Feeley (http://srfi.schemers.org/srfi-89/srfi-89.html)
+; Copyright (C) Marc Feeley 2006. All Rights Reserved.
+;
+; "alist" is a list of pairs of the form "(keyword . value)"
+; The result is a perfect hash-table represented as a vector of
+; length 2*N, where N is the hash modulus. If the keyword K is in
+; the hash-table it is at index
+;
+; X = (* 2 ($hash-keyword K N))
+;
+; and the associated value is at index X+1.
+(def (make-perfect-hash-table alist)
+ (def ($hash-keyword key n)
+ (mod0 (abs (hash key)) n))
+ (let loop1 ((n (length alist)))
+ (let ((v (vec-alloc (* 2 n) NIL)))
+ (let loop2 ((lst alist))
+ (if (cons? lst)
+ (let ((key (caar lst)))
+ (let ((x (* 2 ($hash-keyword key n))))
+ (if (aref v x)
+ (loop1 (+ n 1))
+ (begin
+ (aset! v x key)
+ (aset! v (+ x 1) (cdar lst))
+ (loop2 (cdr lst))))))
+ v)))))
--- a/src/docs_extra.lsp
+++ /dev/null
@@ -1,119 +1,0 @@
-(defmacro (doc-for term . doc)
- "Define documentation for a top level term.
-
- If `term` is a function signature and `doc` is not specified, just
- the signature will be included in the documentation, without
- replacing any previously defined."
- (let* ((call (cons? term))
- (sym (or (and call (car term))
- term))
- (callvars (and call (cdr term))))
- (if call
- `(sym-set-doc ',sym ',doc ',callvars)
- `(sym-set-doc ',sym ',doc))))
-
-(doc-for (vm-stats)
- "Print various VM-related information, such as the number of GC
- calls so far, heap and stack size, etc.")
-
-(doc-for (lz-pack data (level 0))
- "Return data compressed using Lempel-Ziv.
-
- The data must be an array, returned value will have the same type.
- The optional `level` is between `0` and `10`. With `level` set to
- `0` a simple LZSS using hashing will be performed. Levels between
- `1` and `9` offer a trade-off between time/space and ratio. Level
- `10` is optimal but very slow.")
-
-(doc-for (lz-unpack data :to destination))
-(doc-for (lz-unpack data :size decompressed-bytes)
- "Return decompressed data previously compressed using lz-pack.
-
- Either destination for the decompressed data or the expected size of
- the decompressed data must be specified. In the latter case a new
- array is allocated.")
-
-(doc-for (rand)
- "Return a random non-negative fixnum on its maximum range.")
-
-(doc-for (rand-u64)
- "Return a random integer on interval [0, 2⁶⁴-1].")
-
-(doc-for (rand-u32)
- "Return a random integer on interval [0, 2³²-1].")
-
-(doc-for (rand-double)
- "Return a random double on interval [0.0, 1.0].")
-
-(doc-for (rand-float)
- "Return a random float on [0.0, 1.0] interval.")
-
-(doc-for (exit (status NIL))
- "Terminate the process with the specified status. Does not return.
- The status is expected to be a string in case of an error.
-
- Examples:
-
- (exit)
- (exit \"error\")")
-
-(doc-for (file path (:read NIL)
- (:write NIL)
- (:create NIL)
- (:truncate NIL)
- (:append NIL))
- "Open a file for I/O.
-
- An `io` object is returned. Without any modes specified the file
- is opened in read-only mode.")
-
-(doc-for (io? term)
- "Return `T` if `term` is of `io` type, `NIL` otherwise.")
-
-(doc-for (io->str io)
- "Return an in-memory `io` buffer converted to a string.")
-
-(doc-for (io-eof? io)
- "Return `T` if `io` is currently in the \"end of file\" state, `NIL`
- otherwise.")
-
-(doc-for (eof-object? term)
- "Return `T` if `term` is `#<eof>`, `NIL` otherwise.
-
- This object is returned by I/O functions to signal end of file,
- where applicable.")
-
-(doc-for (buffer)
- "Return an in-memory buffer for I/O, of `io` type.
-
- A buffer can be used for both reading and writing at the same
- time.")
-
-(doc-for NIL
- "An empty list. Also used as the opposite of T.
-
- Examples:
-
- (not NIL) → T
- (if NIL 'yes 'no) → no
- (car NIL) → NIL
- (cdr NIL) → NIL")
-
-(doc-for T
- "A boolean \"true\".
-
- Examples:
-
- (not T) → NIL
- (if T 'yes 'no) → yes")
-
-(doc-for (str . term)
- "Convert terms to a concatenated string.
-
- This is equivalent to `(princ terms…)`, except the string is
- returned, rather than printed.")
-
-(doc-for (sym . term)
- "Convert terms to a symbol.
-
- This is equivalent to `(sym (str terms…))`.")
--- /dev/null
+++ b/src/docs_extra.sl
@@ -1,0 +1,119 @@
+(defmacro (doc-for term . doc)
+ "Define documentation for a top level term.
+
+ If `term` is a function signature and `doc` is not specified, just
+ the signature will be included in the documentation, without
+ replacing any previously defined."
+ (let* ((call (cons? term))
+ (sym (or (and call (car term))
+ term))
+ (callvars (and call (cdr term))))
+ (if call
+ `(sym-set-doc ',sym ',doc ',callvars)
+ `(sym-set-doc ',sym ',doc))))
+
+(doc-for (vm-stats)
+ "Print various VM-related information, such as the number of GC
+ calls so far, heap and stack size, etc.")
+
+(doc-for (lz-pack data (level 0))
+ "Return data compressed using Lempel-Ziv.
+
+ The data must be an array, returned value will have the same type.
+ The optional `level` is between `0` and `10`. With `level` set to
+ `0` a simple LZSS using hashing will be performed. Levels between
+ `1` and `9` offer a trade-off between time/space and ratio. Level
+ `10` is optimal but very slow.")
+
+(doc-for (lz-unpack data :to destination))
+(doc-for (lz-unpack data :size decompressed-bytes)
+ "Return decompressed data previously compressed using lz-pack.
+
+ Either destination for the decompressed data or the expected size of
+ the decompressed data must be specified. In the latter case a new
+ array is allocated.")
+
+(doc-for (rand)
+ "Return a random non-negative fixnum on its maximum range.")
+
+(doc-for (rand-u64)
+ "Return a random integer on interval [0, 2⁶⁴-1].")
+
+(doc-for (rand-u32)
+ "Return a random integer on interval [0, 2³²-1].")
+
+(doc-for (rand-double)
+ "Return a random double on interval [0.0, 1.0].")
+
+(doc-for (rand-float)
+ "Return a random float on [0.0, 1.0] interval.")
+
+(doc-for (exit (status NIL))
+ "Terminate the process with the specified status. Does not return.
+ The status is expected to be a string in case of an error.
+
+ Examples:
+
+ (exit)
+ (exit \"error\")")
+
+(doc-for (file path (:read NIL)
+ (:write NIL)
+ (:create NIL)
+ (:truncate NIL)
+ (:append NIL))
+ "Open a file for I/O.
+
+ An `io` object is returned. Without any modes specified the file
+ is opened in read-only mode.")
+
+(doc-for (io? term)
+ "Return `T` if `term` is of `io` type, `NIL` otherwise.")
+
+(doc-for (io->str io)
+ "Return an in-memory `io` buffer converted to a string.")
+
+(doc-for (io-eof? io)
+ "Return `T` if `io` is currently in the \"end of file\" state, `NIL`
+ otherwise.")
+
+(doc-for (eof-object? term)
+ "Return `T` if `term` is `#<eof>`, `NIL` otherwise.
+
+ This object is returned by I/O functions to signal end of file,
+ where applicable.")
+
+(doc-for (buffer)
+ "Return an in-memory buffer for I/O, of `io` type.
+
+ A buffer can be used for both reading and writing at the same
+ time.")
+
+(doc-for NIL
+ "An empty list. Also used as the opposite of T.
+
+ Examples:
+
+ (not NIL) → T
+ (if NIL 'yes 'no) → no
+ (car NIL) → NIL
+ (cdr NIL) → NIL")
+
+(doc-for T
+ "A boolean \"true\".
+
+ Examples:
+
+ (not T) → NIL
+ (if T 'yes 'no) → yes")
+
+(doc-for (str . term)
+ "Convert terms to a concatenated string.
+
+ This is equivalent to `(princ terms…)`, except the string is
+ returned, rather than printed.")
+
+(doc-for (sym . term)
+ "Convert terms to a symbol.
+
+ This is equivalent to `(sym (str terms…))`.")
--- a/src/plan9/lsd.lsp
+++ /dev/null
@@ -1,375 +1,0 @@
-#!/bin/sl -i
-
-(defstruct reg name type addr size)
-(defstruct symbol name type addr)
-(defstruct global
- "All the global symbols, separated into text and data symbols.
-
- The text and data fields are both tables from syms to symbols."
- text data)
-(defstruct frame
- "A stack frame. Loc is the enclosing function symbol and instruction
- address of the frame. Retpc is the return instruction address.
- Sp is the stack pointer value. Locals are all the local symbols."
- loc retpc sp locals)
-
-(def coref NIL)
-(def textf NIL)
-(def regsf NIL)
-(def fpregsf NIL)
-(def proc-stdin NIL)
-(def pids NIL)
-(def bptbl (table))
-
-(def (procfile s . flags)
- (when (< pid 0) (error "no active pid"))
- (let ((path (str "/proc/" pid "/" s)))
- (apply file (cons path flags))))
-
-(def (writectl msg)
- (let ((ctlf (procfile 'ctl :write)))
- (io-write ctlf msg)
- (io-close ctlf)))
-
-(def (exited)
- (when (< pid 0) (error "no active pid"))
- (princ "process " pid " exited\n")
- (set! pids (cdr pids))
- (set! pid (if pids (car pids) -1))
- (set! bptbl (table))
- (detach))
-
-(def (readnote)
- (trycatch
- (let* ((notef (procfile 'note :read))
- (note (io-readall notef)))
- (io-close notef)
- note)
- (λ (e) (if (and (eq? (car e) 'io-error)
- (= (str-find (cadr e) "could not open") 0))
- (exited)
- (raise e)))))
-
-(def (start) (writectl "start"))
-(def (startstop) (writectl "startstop") (readnote))
-(def (stop) (writectl "stop") (readnote))
-
-(def (follow addr)
- "Return a list of the next possible executing instructions."
- (lsd-follow addr))
-
-(def (io-pread f off rest)
- (io-seek f off)
- (apply io-read (cons f rest)))
-
-(def (io-pwrite f off rest)
- (io-seek f off)
- (apply io-write (cons f rest))
- (io-flush f))
-
-(def (readcore addr . rest)
- (unless coref (error "not attached to proc"))
- (io-pread coref addr rest))
-
-(def (readtext addr . rest)
- (unless textf (error "not attached to proc"))
- (io-pread textf addr rest))
-
-(def (writecore addr . rest)
- (unless coref (error "not attached to proc"))
- (io-pwrite coref addr rest))
-
-(def (readreg reg)
- (unless regsf (error "not attached to proc"))
- (let ((f (case (reg-type reg)
- ((:gpreg) regsf)
- ((:fpreg) fpregsf))))
- (io-pread f (reg-addr reg) (list (reg-size reg)))))
-
-(def (readsym symbol . rest)
- (unless coref (error "not attached to proc"))
- (apply readcore (cons (symbol-addr symbol) rest)))
-
-(def (hex n) (str "0x" (num->str n 16)))
-
-(def (oct n) (str "0" (num->str n 8)))
-
-(def (bpsave a) (readcore a 'byte (length bpinst)))
-
-(let ((bp_init (λ (loc)
- (when (< pid 0) (error "no running process"))
- (unless (eq? (status) 'Stopped)
- (begin (princ "Waiting... " status "\n")
- (stop)))
- (cond ((sym? loc) (symbol-addr
- (get (global-text globals) loc)))
- ((num? loc) (u64 loc))
- ((symbol? loc) (symbol-addr loc))
- ((str? loc) (filepc loc))
- (else (error "sym|num|symbol|file:line"))))))
- (set! bpset (λ (loc)
- (let ((addr (bp_init loc)))
- (when (has? bptbl addr)
- (error "breakpoint already set at " loc))
- (put! bptbl addr (bpsave addr))
- (writecore addr bpinst))))
- (set! bpdel (λ (loc)
- (let ((addr (bp_init loc)))
- (unless (has? bptbl addr)
- (error "breakpoint not set at " loc))
- (writecore addr (get bptbl addr))
- (del! bptbl addr)))))
-
-(doc-for (bpset loc)
- "Set a breakpoint.
-
- The location can be one of the following:
-
- 1. A sym, in which case the address will be retrieved from
- the global text symbols of the process,
- 2. A num which is the address at which to place the break.
- 3. An LSD symbol in which the case the symbol's address is used.
- 4. A string of the form \"file:line\" which specifies a line in a
- file of source code.
-
- Examples:
-
- `(bpset 'strcpy)` ; breakpoint on strcpy function.
- `(bpset (curPC))` ; breakpoint on current instruction.
- `(bpset \"/sys/src/cmd/cat.c:26\")` ; breakpoint on line 26.")
-
-(doc-for (bpdel loc)
- "Delete a breakpoint.
-
- The location can be one of the following:
-
- 1. A sym, in which case the address will be retrieved from
- the global text symbols of the process,
- 2. A num which is the address at which to place the break.
- 3. An LSD symbol in which the case the symbol's address is used.
- 4. A string of the form \"file:line\" which specifies a line in a
- file of source code.
-
- Examples:
-
- `(bpdel 'strcpy)` ; remove breakpoint on strcpy function.
- `(bpdel (curPC))` ; remove breakpoint on current instruction.
- `(bpdel \"/sys/src/cmd/cat.c:26\")` ; remove breakpoint on line 26.")
-
-(def (detach)
- (when regsf (io-close regsf))
- (when fpregsf (io-close fpregsf))
- (when coref (io-close coref))
- (when textf (io-close textf))
- (void))
-
-(def (attach)
- (detach)
- (set! regsf (procfile 'regs :read :write))
- (set! fpregsf (procfile 'fpregs :read :write))
- (set! coref (procfile 'mem :read :write))
- (set! textf (procfile 'text :read))
- (void))
-
-(def (new . args)
- (let ((v (apply lsd-new args)))
- (when proc-stdin (io-close proc-stdin))
- (set! bptbl (table))
- (set! pid (aref v 0))
- (set! proc-stdin (aref v 1))
- (attach)
- (bpset (car (follow (symbol-addr (get (global-text globals) 'main)))))
- (startstop)
- (set! pids (cons pid pids))
- pid))
-
-(def (lsd a)
- (let* ((v (lsd-load a))
- (f (λ (symbol tbl) (put! tbl (sym (symbol-name symbol)) symbol)))
- (text (foldl f (table) (aref v 3)))
- (data (foldl f (table) (aref v 4))))
- (set! pid (aref v 0))
- (set! registers (aref v 1))
- (set! bpinst (aref v 2))
- (set! globals (make-global :text text :data data)))
- (and (>= pid 0) (attach)))
-
-(def (status)
- (let* ((sf (procfile 'status))
- (stats (read-all sf)))
- (io-close sf)
- (caddr stats)))
-
-(def tracers (table
- "386" (λ () (lsd-ctrace (curPC) (readreg SP) (u64 0)))
- "amd64" (λ () (lsd-ctrace (curPC) (readreg SP) (u64 0)))
- "arm64" (λ () (lsd-ctrace (curPC) (readreg SP) (readreg R30)))))
-
-(def ctrace (get tracers (os-getenv "objtype")))
-
-(def (_stk)
- (reverse!
- (map (λ (f) (frame-locals f (reverse! (frame-locals f))) f)
- (ctrace))))
-
-(def (curPC) (and (>= pid 0) (readreg PC)))
-
-(def (step (n 1))
- "Step `n` assembly instructions. Return the next instruction
- address to be executed or `NIL` if the program has exited."
- (if (= n 0)
- (curPC)
- (let* ((addr (curPC))
- (on-bp (has? bptbl addr)))
- (when on-bp (writecore addr (get bptbl addr)))
- (let* ((f (follow addr))
- (o (map bpsave f)))
- (for-each (λ (a) (writecore a bpinst)) f)
- (startstop)
- (map writecore f o)
- (when on-bp (writecore addr bpinst))
- (step (1- n))))))
-
-(def (cont)
- "Continue program execution. Return the next instruction
- address to be executed or `NIL` if the program has exited."
- (let ((addr (curPC)))
- (when (has? bptbl addr) (step))
- (startstop)
- (curPC)))
-
-(def (func)
- "Continue program execution until the current function returns."
- (let* ((bp (frame-retpc (car (_stk))))
- (o (bpsave bp)))
- (writecore bp bpinst)
- (cont)
- (writecore bp o))
- (curPC))
-
-(def (line)
- "Step one line of the source code.
-
- This will step into functions not over."
- (let ((orig (src)))
- (def (go)
- (step)
- (if (not (equal? orig (src)))
- (curPC)
- (go)))
- (go)))
-
-(def (over)
- "Step one line of source code, going over a function call, not in"
- (let ((f (car (_stk))))
- (line)
- (if (equal? f (car (_stk)))
- (curPC)
- (begin (func)
- (line)))))
-
-(def (asmlist (n 5) (addr (curPC)))
- "Return a list of the next `n` disassembled instructions starting at `addr`.
-
- Each element in the list has the form `(address . instr)` where `instr`
- is the disassembled instruction at the `address`.
-
- Examples: just like `(asm)` but returns a list instead of printing."
- (if (<= n 0)
- ()
- (let ((on-bp (has? bptbl addr)))
- (when on-bp (writecore addr (get bptbl addr)))
- (let ((instr (lsd-das addr))
- (isize (lsd-instsize addr)))
- (when on-bp (writecore addr bpinst))
- (cons (cons addr instr) (asmlist (1- n) (+ addr isize)))))))
-
-(def (asm (n 5) (addr (curPC)))
- "Print the next `n` disassembled instructions at addr.
-
- Examples:
-
- `(asm)` ; print out 5 from current program instruction.
- `(asm 10)` ; print out 10 from current program instruction.
- `(asm 3 (sym-addr 'strecpy))` ; 3 instructions from strecpy"
- (for-each (λ (i) (princ (hex (car i)) "\t" (cdr i) "\n"))
- (asmlist n addr)))
-
-(def (src (addr (curPC)))
- "Return a string of the filename and line number corresponding
- to the instruction address."
- (lsd-fileline addr))
-
-(def (Bsrc (addr (curPC)))
- "Send a plumb message of the filename and line number
- corresponding to the instruction address so that the
- source code can be viewed in your text editor."
- (let ((s (src addr))
- (plumbf (file "/mnt/plumb/send" :write)))
- (io-write plumbf
- (str "plumb\n\n"
- (path-cwd)
- "\ntext\n\n"
- (length s)
- "\n" s))
- (io-close plumbf)))
-
-(def (Bline)
- "Step forward one line of source code and then plumb the
- new line (make a bee line) to your editor."
- (line)
- (Bsrc))
-
-(def (Bover)
- "Same as Bline but with `over`"
- (over)
- (Bsrc))
-
-(def (filepc f (line NIL))
- "Return the instruction address corresponding to a filename
- and line number. It is the inverse of (src addr).
-
- Examples:
-
- #;> (filepc \"/sys/src/cmd/cat.c:5\")
- 2097192
- #;> (filepc \"/sys/src/cmd/cat.c\" 5)
- 2097192
- #;> (src 2097192)
- \"/sys/src/cmd/cat.c:5\""
- (if line
- (lsd-file2pc f line)
- (let ((s (str-split f ":")))
- (when (/= (length s) 2) (error "invalid file"))
- (let ((line (str->num (cadr s))))
- (unless line (error "bad line number"))
- (lsd-file2pc (car s) line)))))
-
-(def (sym-find s)
- "Return a symbol from the attached proc's symbol table or NIL.
- Input is a sym.
-
- Examples:
-
- #;> (sym-find 'strecpy)
- #(symbol \"strecpy\" #\\T 2276784)"
- (let* ((find (λ (tbl k) (and (has? tbl k) (get tbl k)))))
- (or (find (global-text globals) s)
- (find (global-data globals) s))))
-
-(def (sym-addr s)
- "Return the address of a symbol from the attached proc's
- symbol table or NIL. Input is a sym."
- (symbol-addr (sym-find s)))
-
-(add-exit-hook
- (λ (s)
- (when proc-stdin (io-close proc-stdin))
- (detach)
- (lsd-cleanup)
- (for-each (λ (p) (princ "echo kill > /proc/" p "/ctl\n"))
- pids)))
-
-(let* ((proc (cadr *argv*))
- (pid (str->num proc)))
- (if pid (lsd pid) (lsd proc)))
--- /dev/null
+++ b/src/plan9/lsd.sl
@@ -1,0 +1,375 @@
+#!/bin/sl -i
+
+(defstruct reg name type addr size)
+(defstruct symbol name type addr)
+(defstruct global
+ "All the global symbols, separated into text and data symbols.
+
+ The text and data fields are both tables from syms to symbols."
+ text data)
+(defstruct frame
+ "A stack frame. Loc is the enclosing function symbol and instruction
+ address of the frame. Retpc is the return instruction address.
+ Sp is the stack pointer value. Locals are all the local symbols."
+ loc retpc sp locals)
+
+(def coref NIL)
+(def textf NIL)
+(def regsf NIL)
+(def fpregsf NIL)
+(def proc-stdin NIL)
+(def pids NIL)
+(def bptbl (table))
+
+(def (procfile s . flags)
+ (when (< pid 0) (error "no active pid"))
+ (let ((path (str "/proc/" pid "/" s)))
+ (apply file (cons path flags))))
+
+(def (writectl msg)
+ (let ((ctlf (procfile 'ctl :write)))
+ (io-write ctlf msg)
+ (io-close ctlf)))
+
+(def (exited)
+ (when (< pid 0) (error "no active pid"))
+ (princ "process " pid " exited\n")
+ (set! pids (cdr pids))
+ (set! pid (if pids (car pids) -1))
+ (set! bptbl (table))
+ (detach))
+
+(def (readnote)
+ (trycatch
+ (let* ((notef (procfile 'note :read))
+ (note (io-readall notef)))
+ (io-close notef)
+ note)
+ (λ (e) (if (and (eq? (car e) 'io-error)
+ (= (str-find (cadr e) "could not open") 0))
+ (exited)
+ (raise e)))))
+
+(def (start) (writectl "start"))
+(def (startstop) (writectl "startstop") (readnote))
+(def (stop) (writectl "stop") (readnote))
+
+(def (follow addr)
+ "Return a list of the next possible executing instructions."
+ (lsd-follow addr))
+
+(def (io-pread f off rest)
+ (io-seek f off)
+ (apply io-read (cons f rest)))
+
+(def (io-pwrite f off rest)
+ (io-seek f off)
+ (apply io-write (cons f rest))
+ (io-flush f))
+
+(def (readcore addr . rest)
+ (unless coref (error "not attached to proc"))
+ (io-pread coref addr rest))
+
+(def (readtext addr . rest)
+ (unless textf (error "not attached to proc"))
+ (io-pread textf addr rest))
+
+(def (writecore addr . rest)
+ (unless coref (error "not attached to proc"))
+ (io-pwrite coref addr rest))
+
+(def (readreg reg)
+ (unless regsf (error "not attached to proc"))
+ (let ((f (case (reg-type reg)
+ ((:gpreg) regsf)
+ ((:fpreg) fpregsf))))
+ (io-pread f (reg-addr reg) (list (reg-size reg)))))
+
+(def (readsym symbol . rest)
+ (unless coref (error "not attached to proc"))
+ (apply readcore (cons (symbol-addr symbol) rest)))
+
+(def (hex n) (str "0x" (num->str n 16)))
+
+(def (oct n) (str "0" (num->str n 8)))
+
+(def (bpsave a) (readcore a 'byte (length bpinst)))
+
+(let ((bp_init (λ (loc)
+ (when (< pid 0) (error "no running process"))
+ (unless (eq? (status) 'Stopped)
+ (begin (princ "Waiting... " status "\n")
+ (stop)))
+ (cond ((sym? loc) (symbol-addr
+ (get (global-text globals) loc)))
+ ((num? loc) (u64 loc))
+ ((symbol? loc) (symbol-addr loc))
+ ((str? loc) (filepc loc))
+ (else (error "sym|num|symbol|file:line"))))))
+ (set! bpset (λ (loc)
+ (let ((addr (bp_init loc)))
+ (when (has? bptbl addr)
+ (error "breakpoint already set at " loc))
+ (put! bptbl addr (bpsave addr))
+ (writecore addr bpinst))))
+ (set! bpdel (λ (loc)
+ (let ((addr (bp_init loc)))
+ (unless (has? bptbl addr)
+ (error "breakpoint not set at " loc))
+ (writecore addr (get bptbl addr))
+ (del! bptbl addr)))))
+
+(doc-for (bpset loc)
+ "Set a breakpoint.
+
+ The location can be one of the following:
+
+ 1. A sym, in which case the address will be retrieved from
+ the global text symbols of the process,
+ 2. A num which is the address at which to place the break.
+ 3. An LSD symbol in which the case the symbol's address is used.
+ 4. A string of the form \"file:line\" which specifies a line in a
+ file of source code.
+
+ Examples:
+
+ `(bpset 'strcpy)` ; breakpoint on strcpy function.
+ `(bpset (curPC))` ; breakpoint on current instruction.
+ `(bpset \"/sys/src/cmd/cat.c:26\")` ; breakpoint on line 26.")
+
+(doc-for (bpdel loc)
+ "Delete a breakpoint.
+
+ The location can be one of the following:
+
+ 1. A sym, in which case the address will be retrieved from
+ the global text symbols of the process,
+ 2. A num which is the address at which to place the break.
+ 3. An LSD symbol in which the case the symbol's address is used.
+ 4. A string of the form \"file:line\" which specifies a line in a
+ file of source code.
+
+ Examples:
+
+ `(bpdel 'strcpy)` ; remove breakpoint on strcpy function.
+ `(bpdel (curPC))` ; remove breakpoint on current instruction.
+ `(bpdel \"/sys/src/cmd/cat.c:26\")` ; remove breakpoint on line 26.")
+
+(def (detach)
+ (when regsf (io-close regsf))
+ (when fpregsf (io-close fpregsf))
+ (when coref (io-close coref))
+ (when textf (io-close textf))
+ (void))
+
+(def (attach)
+ (detach)
+ (set! regsf (procfile 'regs :read :write))
+ (set! fpregsf (procfile 'fpregs :read :write))
+ (set! coref (procfile 'mem :read :write))
+ (set! textf (procfile 'text :read))
+ (void))
+
+(def (new . args)
+ (let ((v (apply lsd-new args)))
+ (when proc-stdin (io-close proc-stdin))
+ (set! bptbl (table))
+ (set! pid (aref v 0))
+ (set! proc-stdin (aref v 1))
+ (attach)
+ (bpset (car (follow (symbol-addr (get (global-text globals) 'main)))))
+ (startstop)
+ (set! pids (cons pid pids))
+ pid))
+
+(def (lsd a)
+ (let* ((v (lsd-load a))
+ (f (λ (symbol tbl) (put! tbl (sym (symbol-name symbol)) symbol)))
+ (text (foldl f (table) (aref v 3)))
+ (data (foldl f (table) (aref v 4))))
+ (set! pid (aref v 0))
+ (set! registers (aref v 1))
+ (set! bpinst (aref v 2))
+ (set! globals (make-global :text text :data data)))
+ (and (>= pid 0) (attach)))
+
+(def (status)
+ (let* ((sf (procfile 'status))
+ (stats (read-all sf)))
+ (io-close sf)
+ (caddr stats)))
+
+(def tracers (table
+ "386" (λ () (lsd-ctrace (curPC) (readreg SP) (u64 0)))
+ "amd64" (λ () (lsd-ctrace (curPC) (readreg SP) (u64 0)))
+ "arm64" (λ () (lsd-ctrace (curPC) (readreg SP) (readreg R30)))))
+
+(def ctrace (get tracers (os-getenv "objtype")))
+
+(def (_stk)
+ (reverse!
+ (map (λ (f) (frame-locals f (reverse! (frame-locals f))) f)
+ (ctrace))))
+
+(def (curPC) (and (>= pid 0) (readreg PC)))
+
+(def (step (n 1))
+ "Step `n` assembly instructions. Return the next instruction
+ address to be executed or `NIL` if the program has exited."
+ (if (= n 0)
+ (curPC)
+ (let* ((addr (curPC))
+ (on-bp (has? bptbl addr)))
+ (when on-bp (writecore addr (get bptbl addr)))
+ (let* ((f (follow addr))
+ (o (map bpsave f)))
+ (for-each (λ (a) (writecore a bpinst)) f)
+ (startstop)
+ (map writecore f o)
+ (when on-bp (writecore addr bpinst))
+ (step (1- n))))))
+
+(def (cont)
+ "Continue program execution. Return the next instruction
+ address to be executed or `NIL` if the program has exited."
+ (let ((addr (curPC)))
+ (when (has? bptbl addr) (step))
+ (startstop)
+ (curPC)))
+
+(def (func)
+ "Continue program execution until the current function returns."
+ (let* ((bp (frame-retpc (car (_stk))))
+ (o (bpsave bp)))
+ (writecore bp bpinst)
+ (cont)
+ (writecore bp o))
+ (curPC))
+
+(def (line)
+ "Step one line of the source code.
+
+ This will step into functions not over."
+ (let ((orig (src)))
+ (def (go)
+ (step)
+ (if (not (equal? orig (src)))
+ (curPC)
+ (go)))
+ (go)))
+
+(def (over)
+ "Step one line of source code, going over a function call, not in"
+ (let ((f (car (_stk))))
+ (line)
+ (if (equal? f (car (_stk)))
+ (curPC)
+ (begin (func)
+ (line)))))
+
+(def (asmlist (n 5) (addr (curPC)))
+ "Return a list of the next `n` disassembled instructions starting at `addr`.
+
+ Each element in the list has the form `(address . instr)` where `instr`
+ is the disassembled instruction at the `address`.
+
+ Examples: just like `(asm)` but returns a list instead of printing."
+ (if (<= n 0)
+ ()
+ (let ((on-bp (has? bptbl addr)))
+ (when on-bp (writecore addr (get bptbl addr)))
+ (let ((instr (lsd-das addr))
+ (isize (lsd-instsize addr)))
+ (when on-bp (writecore addr bpinst))
+ (cons (cons addr instr) (asmlist (1- n) (+ addr isize)))))))
+
+(def (asm (n 5) (addr (curPC)))
+ "Print the next `n` disassembled instructions at addr.
+
+ Examples:
+
+ `(asm)` ; print out 5 from current program instruction.
+ `(asm 10)` ; print out 10 from current program instruction.
+ `(asm 3 (sym-addr 'strecpy))` ; 3 instructions from strecpy"
+ (for-each (λ (i) (princ (hex (car i)) "\t" (cdr i) "\n"))
+ (asmlist n addr)))
+
+(def (src (addr (curPC)))
+ "Return a string of the filename and line number corresponding
+ to the instruction address."
+ (lsd-fileline addr))
+
+(def (Bsrc (addr (curPC)))
+ "Send a plumb message of the filename and line number
+ corresponding to the instruction address so that the
+ source code can be viewed in your text editor."
+ (let ((s (src addr))
+ (plumbf (file "/mnt/plumb/send" :write)))
+ (io-write plumbf
+ (str "plumb\n\n"
+ (path-cwd)
+ "\ntext\n\n"
+ (length s)
+ "\n" s))
+ (io-close plumbf)))
+
+(def (Bline)
+ "Step forward one line of source code and then plumb the
+ new line (make a bee line) to your editor."
+ (line)
+ (Bsrc))
+
+(def (Bover)
+ "Same as Bline but with `over`"
+ (over)
+ (Bsrc))
+
+(def (filepc f (line NIL))
+ "Return the instruction address corresponding to a filename
+ and line number. It is the inverse of (src addr).
+
+ Examples:
+
+ #;> (filepc \"/sys/src/cmd/cat.c:5\")
+ 2097192
+ #;> (filepc \"/sys/src/cmd/cat.c\" 5)
+ 2097192
+ #;> (src 2097192)
+ \"/sys/src/cmd/cat.c:5\""
+ (if line
+ (lsd-file2pc f line)
+ (let ((s (str-split f ":")))
+ (when (/= (length s) 2) (error "invalid file"))
+ (let ((line (str->num (cadr s))))
+ (unless line (error "bad line number"))
+ (lsd-file2pc (car s) line)))))
+
+(def (sym-find s)
+ "Return a symbol from the attached proc's symbol table or NIL.
+ Input is a sym.
+
+ Examples:
+
+ #;> (sym-find 'strecpy)
+ #(symbol \"strecpy\" #\\T 2276784)"
+ (let* ((find (λ (tbl k) (and (has? tbl k) (get tbl k)))))
+ (or (find (global-text globals) s)
+ (find (global-data globals) s))))
+
+(def (sym-addr s)
+ "Return the address of a symbol from the attached proc's
+ symbol table or NIL. Input is a sym."
+ (symbol-addr (sym-find s)))
+
+(add-exit-hook
+ (λ (s)
+ (when proc-stdin (io-close proc-stdin))
+ (detach)
+ (lsd-cleanup)
+ (for-each (λ (p) (princ "echo kill > /proc/" p "/ctl\n"))
+ pids)))
+
+(let* ((proc (cadr *argv*))
+ (pid (str->num proc)))
+ (if pid (lsd pid) (lsd proc)))
--- a/src/system.lsp
+++ /dev/null
@@ -1,1432 +1,0 @@
-; StreetLISP standard library
-; by Jeff Bezanson (C) 2009
-; Distributed under the BSD License
-
-;;; void
-
-(def (void . rest)
- "Return the constant `#<void>` while ignoring any arguments.
-
- `#<void>` is mainly used when a function has side effects but does not
- produce any meaningful value to return, so even though `T` or `NIL` could
- be returned instead, in case of `#<void>` alone, REPL will not print
- it."
- #.(void))
-
-(def (void? x)
- "Return `T` if `x` is `#<void>`, `NIL` otherwise."
- (eq? x #.(void)))
-
-;;; syntax environment
-
-(unless (bound? '*syntax-environment*)
- (def *syntax-environment* (table)))
-
-(def (set-syntax! s v)
- (put! *syntax-environment* s v))
-
-(def (get-syntax s)
- (get *syntax-environment* s NIL))
-
-(def (separate-doc-from-body body (doc NIL))
- (let {[hd (car body)]
- [tl (cdr body)]}
- (cond [(and (not doc) (str? hd) tl)
- (separate-doc-from-body tl (cons hd doc))]
- [(and doc (member hd '(:doc-group :doc-see-also)))
- (separate-doc-from-body (cdr tl) (list* (car tl) hd doc))]
- [else (cons (reverse doc) body)])))
-
-(defmacro (defmacro form . body)
- (let* {[doc+body (separate-doc-from-body body)]
- [doc (car doc+body)]
- [body (cdr doc+body)]}
- (when doc
- (sym-set-doc (car form) doc (cdr form)))
- `(void (set-syntax! ',(car form)
- (λ ,(cdr form) ,@body)))))
-
-(defmacro (letrec binds . body)
- `((λ ,(map car binds)
- ,.(map (λ (b) `(set! ,@b)) binds)
- ,@body)
- ,.(map void binds)))
-
-(defmacro (let binds . body)
- (let ((lname NIL))
- (when (sym? binds)
- (set! lname binds)
- (set! binds (car body))
- (set! body (cdr body)))
- (let ((thelambda
- `(λ ,(map (λ (c) (if (cons? c) (car c) c))
- binds)
- ,@body))
- (theargs
- (map (λ (c) (if (cons? c) (cadr c) (void)))
- binds)))
- (cons (if lname
- `(letrec ((,lname ,thelambda)) ,lname)
- thelambda)
- theargs))))
-
-(defmacro (cond . clauses)
- (def (cond-clauses->if lst)
- (if (atom? lst)
- NIL
- (let ((clause (car lst)))
- (if (or (eq? (car clause) 'else)
- (eq? (car clause) T))
- (if (not (cdr clause))
- (car clause)
- (cons 'begin (cdr clause)))
- (if (not (cdr clause))
- ; test by itself
- (list 'or
- (car clause)
- (cond-clauses->if (cdr lst)))
- ; test => expression
- (if (eq? (cadr clause) '=>)
- (if (1arg-lambda? (caddr clause))
- ; test => (λ (x) ...)
- (let ((var (caadr (caddr clause))))
- `(let ((,var ,(car clause)))
- (if ,var
- ,(cons 'begin (cddr (caddr clause)))
- ,(cond-clauses->if (cdr lst)))))
- ; test => proc
- `(let ((b# ,(car clause)))
- (if b#
- (,(caddr clause) b#)
- ,(cond-clauses->if (cdr lst)))))
- (list 'if
- (car clause)
- (cons 'begin (cdr clause))
- (cond-clauses->if (cdr lst)))))))))
- (cond-clauses->if clauses))
-
-;;; props
-
-;; This is implemented in a slightly different fashion as expected:
-;;
-;; *properties* : key → { symbol → value }
-;;
-;; The assumption here is that keys will most likely be the same across multiple symbols
-;; so it makes more sense to reduce the number of subtables for the *properties* table.
-(unless (bound? '*properties*)
- (def *properties* (table)))
-
-(def (putprop symbol key val)
- "Associate a property value with a symbol."
- (let ((kt (get *properties* key NIL)))
- (unless kt
- (let ((ta (table)))
- (put! *properties* key ta)
- (set! kt ta)))
- (put! kt symbol val)
- val))
-
-(def (getprop symbol key (def NIL))
- "Get a property value associated with a symbol or `def` if missing."
- (let ((kt (get *properties* key NIL)))
- (or (and kt (get kt symbol def)) def)))
-
-(def (remprop symbol key)
- "Remove a property value associated with a symbol."
- (let ((kt (get *properties* key NIL)))
- (and kt (has? kt symbol) (del! kt symbol))))
-
-;;; documentation
-
-(def (sym-set-doc symbol doc-seq . funvars)
- (let {[doc (if (str? doc-seq)
- doc-seq
- (car doc-seq))]}
- (when (and (bound? 'str-join) doc)
- (let* {[lines (str-split doc "\n")]
- [hd (car lines)]
- [tl (cdr lines)]
- [snd (any (λ (s) (and (> (length s) 0)
- (= (aref s 0) #\space)
- s))
- tl)]
- [indent (and snd
- (- (length snd)
- (length (str-trim snd " " ""))))]
- [trimmed (and snd
- (map (λ (s) (if (<= indent (length s))
- (str-sub s indent)
- s))
- tl))]
- [final (str-join (cons hd trimmed) "\n")]}
- (putprop symbol '*doc* final)))
- (when (cons? funvars)
- (let* {[existing (getprop symbol '*funvars* NIL)]
- ; filter out duplicates
- [to-add (filter (λ (funvar) (not (member funvar existing)))
- funvars)]}
- (putprop symbol '*funvars* (append existing to-add))))
- (void)))
-
-;; chicken and egg - properties defined before sym-set-doc
-(sym-set-doc
- '*properties*
- "All properties of symbols recorded with `putprop` are recorded in this table.")
-
-(def (help-print-header term sigs)
- "Format and print term's signature(s) for `(help term)` output."
- (if sigs
- (for-each (λ (sig) (print (cons term sig))
- (newline))
- sigs)
- (begin (print term)
- (newline)))
- (newline))
-
-(defmacro (help term (:print-header help-print-header))
- "Display documentation for the specified term, if available."
- (let* {[doc (getprop term '*doc*)]
- [sigs (getprop term '*funvars* NIL)]}
- (if (or doc sigs)
- `(begin (,print-header ',term ',sigs)
- (when ,doc
- (princ ,doc)
- (newline))
- (void))
- (begin (princ "no help for " term)
- (when (and (sym? term)
- (not (bound? term)))
- (princ " (undefined)"))
- (newline))
- (void))))
-
-;;; standard procedures
-
-(def (member item lst)
- (cond ((equal? (car lst) item) lst)
- (lst (member item (cdr lst)))))
-
-(def (memv item lst)
- (cond ((eqv? (car lst) item) lst)
- (lst (memv item (cdr lst)))))
-
-(def (assoc item lst)
- (cond ((equal? (caar lst) item) (car lst))
- (lst (assoc item (cdr lst)))))
-
-(def (assv item lst)
- (cond ((eqv? (caar lst) item) (car lst))
- (lst (assv item (cdr lst)))))
-
-(def (> a . rest)
- "Return `T` if the arguments are in strictly decreasing order (previous
- one is greater than the next one)."
- (let loop ((a a) (rest rest))
- (or (not rest)
- (and (< (car rest) a)
- (loop (car rest) (cdr rest))))))
-(defmacro (> a . rest)
- `(< ,@(reverse! rest) ,a))
-
-(def (<= a . rest)
- "Return `T` if the arguments are in non-decreasing order (previous
- one is less than or equal to the next one)."
- (let loop ((a a) (rest rest))
- (or (not rest)
- (unless (or (< (car rest) a)
- (nan? a))
- (loop (car rest) (cdr rest))))))
-
-(def (>= a . rest)
- "Return `T` if the arguments are in non-increasing order (previous
- one is greater than or equal to the next one)."
- (let loop ((a a) (rest rest))
- (or (not rest)
- (unless (or (< a (car rest))
- (nan? a))
- (loop (car rest) (cdr rest))))))
-
-(defmacro (/= a . rest)
- "Return `T` if not all arguments are equal. Shorthand for `(not (= …))`."
- `(not (= ,a ,@rest)))
-
-(def (negative? x)
- "Return `T` if `x` is negative."
- (< x 0))
-
-(def (zero? x)
- "Return `T` if `x` is zero."
- (= x 0))
-
-(def (positive? x)
- "Return `T` if `x` is greater than zero."
- (> x 0))
-
-(def (even? x)
- (= (logand x 1) 0))
-
-(def (odd? x)
- (not (even? x)))
-
-(def (identity x)
- "Return `x`."
- x)
-
-(def (1+ n)
- "Equivalent to `(+ n 1)`."
- (+ n 1))
-
-(def (1- n)
- "Equivalent to `(- n 1)`."
- (- n 1))
-
-(def (div x y)
- (+ (div0 x y)
- (or (and (< x 0)
- (or (and (< y 0) 1)
- -1))
- 0)))
-
-(def (mod0 x y)
- (- x (* (div0 x y) y)))
-
-(def (mod x y)
- (- x (* (div x y) y)))
-
-(def (random n)
- (if (int? n)
- (mod (rand) n)
- (* (rand-double) n)))
-
-(def (abs x)
- (if (< x 0)
- (- x)
- x))
-
-(def (max x0 . xs)
- (if xs
- (foldl (λ (a b) (if (< a b) b a))
- x0
- xs)
- x0))
-
-(def (min x0 . xs)
- (if xs
- (foldl (λ (a b) (if (< a b) a b))
- x0
- xs)
- x0))
-
-(def (rune? x)
- (eq? (typeof x) 'rune))
-
-(def (arr? x)
- (or (vec? x)
- (let ((tx (typeof x)))
- (and (cons? tx) (eq? (car tx) 'arr)))))
-
-(def (closure? x)
- (and (fn? x)
- (not (builtin? x))))
-
-(def (caar x) (car (car x)))
-(def (cdar x) (cdr (car x)))
-(def (cddr x) (cdr (cdr x)))
-(def (caaar x) (car (car (car x))))
-(def (caadr x) (car (car (cdr x))))
-(def (cadar x) (car (cdr (car x))))
-(def (caddr x) (car (cdr (cdr x))))
-(def (cdaar x) (cdr (car (car x))))
-(def (cdadr x) (cdr (car (cdr x))))
-(def (cddar x) (cdr (cdr (car x))))
-(def (cdddr x) (cdr (cdr (cdr x))))
-(def (caaaar x) (car (car (car (car x)))))
-(def (caaadr x) (car (car (car (cdr x)))))
-(def (caadar x) (car (car (cdr (car x)))))
-(def (caaddr x) (car (car (cdr (cdr x)))))
-(def (cadaar x) (car (cdr (car (car x)))))
-(def (cadadr x) (car (cdr (car (cdr x)))))
-(def (caddar x) (car (cdr (cdr (car x)))))
-(def (cadddr x) (car (cdr (cdr (cdr x)))))
-(def (cdaaar x) (cdr (car (car (car x)))))
-(def (cdaadr x) (cdr (car (car (cdr x)))))
-(def (cdadar x) (cdr (car (cdr (car x)))))
-(def (cdaddr x) (cdr (car (cdr (cdr x)))))
-(def (cddaar x) (cdr (cdr (car (car x)))))
-(def (cddadr x) (cdr (cdr (car (cdr x)))))
-(def (cdddar x) (cdr (cdr (cdr (car x)))))
-(def (cddddr x) (cdr (cdr (cdr (cdr x)))))
-
-(let ((*values* (list '*values*)))
- (set! values
- (λ vs
- (if (and (cons? vs) (not (cdr vs)))
- (car vs)
- (cons *values* vs))))
- (set! call-with-values
- (λ (producer consumer)
- (let ((res (producer)))
- (if (and (cons? res) (eq? *values* (car res)))
- (apply consumer (cdr res))
- (consumer res))))))
-
-;;; list utilities
-
-(def (every pred lst)
- (or (atom? lst)
- (and (pred (car lst))
- (every pred (cdr lst)))))
-
-(def (any pred lst)
- (and (cons? lst)
- (or (pred (car lst))
- (any pred (cdr lst)))))
-
-(def (list? a)
- (or (not a) (and (cons? a) (list? (cdr a)))))
-
-(def (list-tail lst n)
- (if (<= n 0)
- lst
- (list-tail (cdr lst) (- n 1))))
-
-(def (list-head lst n)
- (and (> n 0)
- (cons (car lst)
- (list-head (cdr lst) (- n 1)))))
-
-(def (list-ref lst n)
- (car (list-tail lst n)))
-
-(def (length= lst n)
- "Perform a bounded length test.
-
- Use this instead of `(= (length lst) n)`, since it avoids unnecessary
- work and always terminates."
- (cond ((< n 0) NIL)
- ((= n 0) (atom? lst))
- ((atom? lst) (= n 0))
- (else (length= (cdr lst) (- n 1)))))
-
-(def (length> lst n)
- (cond ((< n 0) lst)
- ((= n 0) (and (cons? lst) lst))
- ((atom? lst) (< n 0))
- (else (length> (cdr lst) (- n 1)))))
-
-(def (last-pair l)
- (if (atom? (cdr l))
- l
- (last-pair (cdr l))))
-
-(def (lastcdr l)
- (if (atom? l)
- l
- (cdr (last-pair l))))
-
-(def (to-proper l)
- (cond ((not l) l)
- ((atom? l) (list l))
- (else (cons (car l) (to-proper (cdr l))))))
-
-(def (map! f lst)
- (prog1 lst
- (while (cons? lst)
- (set-car! lst (f (car lst)))
- (set! lst (cdr lst)))))
-
-(def (filter pred lst)
- (def (filter- f lst acc)
- (cdr
- (prog1 acc
- (while (cons? lst)
- (when (pred (car lst))
- (set! acc
- (cdr (set-cdr! acc (cons (car lst) NIL)))))
- (set! lst (cdr lst))))))
- (filter- pred lst (list NIL)))
-
-(def (partition pred lst)
- (def (partition- pred lst yes no)
- (let ((vals
- (prog1
- (cons yes no)
- (while (cons? lst)
- (if (pred (car lst))
- (set! yes (cdr (set-cdr! yes (cons (car lst) NIL))))
- (set! no (cdr (set-cdr! no (cons (car lst) NIL)))))
- (set! lst (cdr lst))))))
- (values (cdr (car vals)) (cdr (cdr vals)))))
- (partition- pred lst (list NIL) (list NIL)))
-
-(def (count f l)
- (def (count- f l n)
- (if (not l)
- n
- (count- f (cdr l) (if (f (car l))
- (+ n 1)
- n))))
- (count- f l 0))
-
-(def (nestlist f zero n)
- (and (> n 0)
- (cons zero (nestlist f (f zero) (- n 1)))))
-
-(def (foldr f zero lst)
- (if (not lst)
- zero
- (f (car lst) (foldr f zero (cdr lst)))))
-
-(def (foldl f zero lst)
- (if (not lst)
- zero
- (foldl f (f (car lst) zero) (cdr lst))))
-
-(def (reverse- zero lst)
- (if (not lst)
- zero
- (reverse- (cons (car lst) zero) (cdr lst))))
-
-(def (reverse lst)
- (reverse- NIL lst))
-
-(def (reverse!- prev l)
- (while (cons? l)
- (set! l (prog1 (cdr l)
- (set-cdr! l (prog1 prev
- (set! prev l))))))
- prev)
-
-(def (reverse! l)
- (reverse!- NIL l))
-
-(def (copy-tree l)
- (if (atom? l)
- l
- (cons (copy-tree (car l))
- (copy-tree (cdr l)))))
-
-(def (delete-duplicates lst)
- (if (length> lst 20)
- (let ((ta (table)))
- (let loop ((l lst) (acc NIL))
- (if (atom? l)
- (reverse! acc)
- (if (has? ta (car l))
- (loop (cdr l) acc)
- (begin
- (put! ta (car l) T)
- (loop (cdr l) (cons (car l) acc)))))))
- (if (atom? lst)
- lst
- (let ((elt (car lst))
- (tail (cdr lst)))
- (if (member elt tail)
- (delete-duplicates tail)
- (cons elt
- (delete-duplicates tail)))))))
-
-; you are not expected to understand this -- spew
-
-(def (zip-with f . lst)
- (apply map f lst))
-
-(def (zip . lst)
- (apply map list lst))
-
-;;; backquote
-
-(def (revappend l1 l2)
- (reverse- l2 l1))
-
-(def (nreconc l1 l2)
- (reverse!- l2 l1))
-
-(def (self-evaluating? x)
- (and (not (gensym? x))
- (or (and (atom? x)
- (not (sym? x)))
- (and (const? x)
- (sym? x)
- (eq? x (top-level-value x))))))
-
-(defmacro (quasiquote x) (bq-process x 0))
-
-(def (splice-form? x)
- (or (and (cons? x) (or (eq? (car x) 'unquote-splicing)
- (eq? (car x) 'unquote-nsplicing)
- (and (eq? (car x) 'unquote)
- (length> x 2))))
- (eq? x 'unquote)))
-
-;; bracket without splicing
-(def (bq-bracket1 x d)
- (if (and (cons? x) (eq? (car x) 'unquote))
- (if (= d 0)
- (cadr x)
- (list cons ''unquote
- (bq-process (cdr x) (- d 1))))
- (bq-process x d)))
-
-(def (bq-bracket x d)
- (cond ((atom? x) (list list (bq-process x d)))
- ((eq? (car x) 'unquote)
- (if (= d 0)
- (cons list (cdr x))
- (list list (list cons ''unquote
- (bq-process (cdr x) (- d 1))))))
- ((eq? (car x) 'unquote-splicing)
- (if (= d 0)
- (list 'copy-list (cadr x))
- (list list (list list ''unquote-splicing
- (bq-process (cadr x) (- d 1))))))
- ((eq? (car x) 'unquote-nsplicing)
- (if (= d 0)
- (cadr x)
- (list list (list list ''unquote-nsplicing
- (bq-process (cadr x) (- d 1))))))
- (else (list list (bq-process x d)))))
-
-(def (bq-process x d)
- (cond ((sym? x) (list 'quote x))
- ((vec? x)
- (let ((body (bq-process (vec->list x) d)))
- (if (eq? (car body) list)
- (cons vec (cdr body))
- (list apply vec body))))
- ((atom? x) x)
- ((eq? (car x) 'quasiquote)
- (list list ''quasiquote (bq-process (cadr x) (+ d 1))))
- ((eq? (car x) 'unquote)
- (if (and (= d 0) (length= x 2))
- (cadr x)
- (list cons ''unquote (bq-process (cdr x) (- d 1)))))
- ((not (any splice-form? x))
- (let ((lc (lastcdr x))
- (forms (map (λ (x) (bq-bracket1 x d)) x)))
- (if (not lc)
- (cons list forms)
- (if (not (cdr forms))
- (list cons (car forms) (bq-process lc d))
- (nconc (cons list* forms) (list (bq-process lc d)))))))
- (else
- (let loop ((p x) (q NIL))
- (cond ((not p) ;; proper list
- (cons 'nconc (reverse! q)))
- ((cons? p)
- (cond ((eq? (car p) 'unquote)
- ;; (... . ,x)
- (cons 'nconc
- (nreconc q
- (if (= d 0)
- (cdr p)
- (list (list list ''unquote)
- (bq-process (cdr p)
- (- d 1)))))))
- (else
- (loop (cdr p) (cons (bq-bracket (car p) d) q)))))
- (else
- ;; (... . x)
- (cons 'nconc (reverse! (cons (bq-process p d) q)))))))))
-
-;;; standard macros
-
-(def (quote-value v)
- (if (self-evaluating? v)
- v
- (list 'quote v)))
-
-(defmacro (let* binds . body)
- (if (atom? binds)
- `((λ () ,@body))
- `((λ (,(caar binds))
- ,@(if (cons? (cdr binds))
- `((let* ,(cdr binds) ,@body))
- body))
- ,(cadar binds))))
-
-(defmacro (when c . body)
- (list 'if c (cons 'begin body) NIL))
-
-(defmacro (unless c . body)
- (list 'if c NIL (cons 'begin body)))
-
-(defmacro (case key . clauses)
- (def (vals->cond key v)
- (cond ((eq? v 'else) 'else)
- ((not v) NIL)
- ((sym? v) `(eq? ,key ,(quote-value v)))
- ((atom? v) `(eqv? ,key ,(quote-value v)))
- ((not (cdr v)) `(eqv? ,key ,(quote-value (car v))))
- ((every sym? v)
- `(memq ,key ',v))
- (else `(memv ,key ',v))))
- (let ((g (gensym)))
- `(let ((,g ,key))
- (cond ,.(map (λ (clause)
- (cons (vals->cond g (car clause))
- (cdr clause)))
- clauses)))))
-
-(defmacro (do vars test-spec . commands)
- (let ((test-expr (car test-spec))
- (vars (map car vars))
- (inits (map cadr vars))
- (steps (map (λ (x)
- (if (cons? (cddr x))
- (caddr x)
- (car x)))
- vars)))
- `(letrec ((loop# (λ ,vars
- (if ,test-expr
- (begin
- ,@(cdr test-spec))
- (begin
- ,@commands
- (loop# ,.steps))))))
- (loop# ,.inits))))
-
-; SRFI 8
-(defmacro (receive formals expr . body)
- `(call-with-values (λ () ,expr)
- (λ ,formals ,@body)))
-
-(defmacro (dotimes var . body)
- (let ((v (car var))
- (cnt (cadr var)))
- `(for 0 (- ,cnt 1)
- (λ (,v) ,@body))))
-
-(def (map-int f n)
- (and (> n 0)
- (let ((first (cons (f 0) NIL))
- (acc NIL))
- (set! acc first)
- (for 1 (1- n)
- (λ (i) (set-cdr! acc (cons (f i) NIL))
- (set! acc (cdr acc))))
- first)))
-
-(def (iota n)
- (map-int identity n))
-
-(defmacro (with-bindings binds . body)
- (let ((vars (map car binds))
- (vals (map cadr binds))
- (olds (map (λ (x) (gensym)) binds)))
- `(let ,(map list olds vars)
- ,@(map (λ (v val) `(set! ,v ,val)) vars vals)
- (unwind-protect
- (begin ,@body)
- (begin ,@(map (λ (v old) `(set! ,v ,old)) vars olds))))))
-
-;;; exceptions
-
-(def (error . args)
- (raise (cons 'error args)))
-
-(defmacro (throw tag value)
- `(raise (list 'thrown-value ,tag ,value)))
-
-(defmacro (catch tag expr)
- `(trycatch ,expr
- (λ (e#) (if (and (cons? e#)
- (eq? (car e#) 'thrown-value)
- (eq? (cadr e#) ,tag))
- (caddr e#)
- (raise e#)))))
-
-(defmacro (unwind-protect expr finally)
- `(let ((thk# (λ () ,finally)))
- (prog1 (trycatch ,expr
- (λ (e#) (thk#) (raise e#)))
- (thk#))))
-
-;;; debugging utilities
-
-(defmacro (assert expr)
- `(if ,expr T (raise '(assert-failed ,expr))))
-
-(def traced?
- (let ((sample-traced-lambda (λ args (write (cons 'x args))
- (newline)
- (apply #.apply args))))
- (λ (f)
- (and (closure? f)
- (equal? (fn-code f)
- (fn-code sample-traced-lambda))))))
-
-(def (trace symbol)
- (let ((func (top-level-value symbol)))
- (when (not (traced? func))
- (set-top-level-value! symbol
- (eval
- `(λ args#
- (write (cons ',symbol args#))
- (newline)
- (apply ',func args#))))))
- (void))
-
-(def (untrace symbol)
- (let ((func (top-level-value symbol)))
- (when (traced? func)
- (set-top-level-value! symbol
- (aref (fn-vals func) 3))))
- (void))
-
-(defmacro (time expr)
- `(let ((t0# (time-now)))
- (prog1
- ,expr
- (princ "Elapsed time: " (- (time-now) t0#) " seconds" *linefeed*))))
-
-;;; text I/O
-
-(def (print . args)
- (for-each write args))
-
-(def (princ . args)
- (with-bindings ((*print-readably* NIL))
- (for-each write args)))
-
-(def (newline (io *io-out*))
- (io-write io *linefeed*)
- (void))
-
-(def (io-readline s) (io-readuntil s #\linefeed))
-
-; call f on an io until the io runs out of data
-(def (read-all-of f s)
- (let loop ((lines NIL)
- (curr (f s)))
- (if (io-eof? s)
- (reverse! lines)
- (loop (cons curr lines) (f s)))))
-
-(def (io-readlines s)
- (read-all-of io-readline s))
-
-(def (read-all s)
- (read-all-of read s))
-
-(def (io-readall s)
- (let ((b (buffer)))
- (io-copy b s)
- (io->str b)))
-
-(defmacro (with-output-to io . body)
- `(with-bindings ((*io-out* ,io))
- ,@body))
-
-(defmacro (with-input-from io . body)
- `(with-bindings ((*io-in* ,io))
- ,@body))
-
-;;; vector functions
-
-(def (list->vec l)
- (apply vec l))
-
-(def (vec->list v)
- (let ((n (length v))
- (l NIL))
- (for 1 n
- (λ (i)
- (set! l (cons (aref v (- n i)) l))))
- l))
-
-(def (vec-map f v)
- (let* ((n (length v))
- (nv (vec-alloc n)))
- (for 0 (- n 1)
- (λ (i)
- (aset! nv i (f (aref v i)))))
- nv))
-
-;;; table functions
-
-(def (table-pairs ta)
- (table-foldl (λ (k v z) (cons (cons k v) z))
- NIL ta))
-(def (table-keys ta)
- (table-foldl (λ (k v z) (cons k z))
- NIL ta))
-(def (table-values ta)
- (table-foldl (λ (k v z) (cons v z))
- NIL ta))
-(def (table-clone ta)
- (let ((nt (table)))
- (table-foldl (λ (k v z) (put! nt k v))
- NIL ta)
- nt))
-(def (table-invert ta)
- (let ((nt (table)))
- (table-foldl (λ (k v z) (put! nt v k))
- NIL ta)
- nt))
-
-;;; string functions
-
-(def (str-tail s n)
- (str-sub s n))
-
-(def (str-trim s at-start at-end)
- (def (trim-start s runes i L)
- (if (and (< i L) (str-find runes (str-rune s i)))
- (trim-start s runes (1+ i) L)
- i))
- (def (trim-end s runes i)
- (if (and (> i 0) (str-find runes (str-rune s (1- i))))
- (trim-end s runes (1- i))
- i))
- (let ((L (str-length s)))
- (str-sub s
- (trim-start s at-start 0 L)
- (trim-end s at-end L))))
-
-(def (str-map f s)
- (let ((b (buffer))
- (n (str-length s)))
- (let ((i 0))
- (while (< i n)
- (io-putc b (f (str-rune s i)))
- (set! i (1+ i))))
- (io->str b)))
-
-(def (str-rep s k)
- (cond ((< k 4)
- (cond ((<= k 0) "")
- ((= k 1) (str s))
- ((= k 2) (str s s))
- (else (str s s s))))
- ((odd? k) (str s (str-rep s (- k 1))))
- (else (str-rep (str s s) (/ k 2)))))
-
-(def (str-lpad s n c)
- (str (str-rep c (- n (str-length s))) s))
-
-(def (str-rpad s n c)
- (str s (str-rep c (- n (str-length s)))))
-
-(def (print-to-str . args)
- (let ((b (buffer)))
- (for-each (λ (a) (write a b)) args)
- (io->str b)))
-
-(def (str-join strlist sep)
- (if (not strlist)
- ""
- (let ((b (buffer)))
- (io-write b (car strlist))
- (for-each (λ (s) (io-write b sep)
- (io-write b s))
- (cdr strlist))
- (io->str b))))
-
-;;; structs
-
-(defmacro (defstruct name (:type vec)
- (:named T)
- (:constructor T)
- (:conc-name NIL)
- (:predicate NIL)
- . slots)
- "Defines a structure type with a specific name and slots.
-
- The default underlying type is a \"named\" vector (`:type vec`),
- where the first element is the name of the structure's type, the
- rest are the slot values. If the name as the first element isn't
- required, `:named NIL` should be used. A list can be used instead
- of a vector by adding `:type list` option.
-
- An example of a default constructor signature, based on structure
- definition:
-
- (defstruct blah a b c) →
- (make-blah (:a NIL) (:b NIL) (:c NIL))
-
- It can be customized in several ways. For example:
-
- ; disable the constructor altogether
- (defstruct blah :constructor NIL a b c)
- ; only change its name
- (defstruct blah :constructor blargh a b c)
- ; rename AND avoid using keywords
- (defstruct blah :constructor (blah a b c) a b c)
-
- The option `:conc-name` specifies the slot accessor prefix, which
- defaults to `name-`.
-
- Default predicate name (`name?`) can be changed:
-
- ; use \"blargh?\" instead of \"blah?\"
- (defstruct blah :predicate blargh? a b c)"
- (def (slot-opts slot)
- ; check whether slot options, if any, are valid
- (let ((opts (cddr slot)))
- (for-each (λ (opt) (unless (member opt '(:read-only))
- (error (str "invalid option in slot " (car slot)
- " of struct " name
- ": " opt))))
- opts)
- opts))
- (def (tokw slots)
- ; transform args list to keyworded variant.
- ; eg: (a (b 1) (c :read-only)) → ((:a NIL) (:b 1) (:c NIL :read-only))
- (map! (λ (slot) (let* {[name-cons (and (cons? slot)
- (car slot))]
- [name (or name-cons slot)]
- [tail (or (and name-cons
- (cdr slot))
- (list NIL))]}
- (when (or (not (sym? name))
- (keyword? name))
- (error "invalid slot name: " name))
- (list* (sym #\: name)
- (if (keyword? (car tail))
- (cons NIL tail)
- tail))))
- slots))
- (let* {; first element in slots may be the doc string
- [doc (and (str? (car slots))
- (car slots))]
- ; if it is, rid of it
- [slots (or (and doc (cdr slots))
- slots)]
- [num-slots (length slots)]
- ; list of slot names
- [slots-car (map (λ (f) (if (cons? f) (car f) f))
- slots)]
- ; slots, but with default values added (if not set)
- ; and keywords for names
- [slots-kw (tokw slots)]
- ; struct's underlying type's predicate (either vec? or list?)
- [type? (sym type #\?)]
- ; struct's predicate name
- [is? (or predicate
- (sym name #\?))]
- ; constructor name and arguments
- [constructor
- (and constructor ; NIL means none to make at all
- (or (and (atom? constructor) ; a single argument
- (cons (or (and (eq? constructor T) ; T means the defaults
- (sym "make-" name))
- constructor) ; else a custom name
- slots-kw))
- constructor))] ; anything else means custom name and args
- ; should the struct name appear as the first element?
- [named (and named (list name))]
- ; accessor prefix
- [access (or conc-name
- (str name "-"))]}
- `(begin
- ; predicate
- (def (,is? s)
- (and [,type? s]
- [or (not ',named) (eq? (aref s 0) ',name)]
- [= (length s) ,(+ (length named) num-slots)]))
- ; documentation string
- (when ,doc
- (sym-set-doc ',name ,doc))
- ; constructor
- ,(when constructor `(def ,constructor
- (,type ',@named ,@slots-car)))
- ; accessor per slot
- ,@(map-int (λ (i) [let* {[opts (slot-opts (list-ref slots-kw i))]
- [fld (list-ref slots-car i)]
- [fun (sym access fld)]}
- `(def (,fun s (v #.(void)))
- (assert (,is? s))
- (if (void? v)
- (aref s ,[+ (length named) i])
- ,(if (member :read-only opts)
- `(error (str "slot "
- ',fld
- " in struct "
- ',name
- " is :read-only"))
- `(aset! s ,[+ (length named) i] v))))])
- num-slots))))
-
-(doc-for (defstruct name
- doc
- options…
- (slot-1 DEFAULT)
- slot-2
- (slot-3 :read-only)))
-
-;;; toplevel
-
-(def (macrocall? e)
- (and (sym? (car e))
- (get-syntax (car e))))
-
-(def (macroexpand-1 e)
- (if (atom? e)
- e
- (let ((f (macrocall? e)))
- (if f
- (apply f (cdr e))
- e))))
-
-(def (macroexpand e)
- ; symbol resolves to toplevel; i.e. has no shadowing definition
- (def (top? s env) (not (or (bound? s) (assq s env))))
-
- (def (splice-begin body)
- (cond ((atom? body) body)
- ((equal? body '((begin)))
- body)
- ((and (cons? (car body))
- (eq? (caar body) 'begin))
- (append (splice-begin (cdar body)) (splice-begin (cdr body))))
- (else
- (cons (car body) (splice-begin (cdr body))))))
-
- (def *expanded* (list '*expanded*))
-
- (def (expand-body body env)
- (if (atom? body)
- body
- (let* ((body (if (top? 'begin env)
- (splice-begin body)
- body))
- (def? (top? 'def env))
- (dvars (and def? (get-defined-vars body)))
- (env (nconc (map list dvars) env)))
- (if (not def?)
- (map (λ (x) (expand-in x env)) body)
- (let* ((ex-nondefs ; expand non-definitions
- (let loop ((body body))
- (cond ((atom? body) body)
- ((and (cons? (car body))
- (eq? 'def (caar body)))
- (cons (car body) (loop (cdr body))))
- (else
- (let ((form (expand-in (car body) env)))
- (set! env (nconc
- (map list (get-defined-vars form))
- env))
- (cons
- (cons *expanded* form)
- (loop (cdr body))))))))
- (body ex-nondefs))
- (while (cons? body) ; now expand deferred definitions
- (if (not (eq? *expanded* (caar body)))
- (set-car! body (expand-in (car body) env))
- (set-car! body (cdar body)))
- (set! body (cdr body)))
- ex-nondefs)))))
-
- (def (expand-lambda-list l env)
- (if (atom? l)
- l
- (cons (if (and (cons? (car l)) (cons? (cdr (car l))))
- (list (caar l) (expand-in (cadar l) env))
- (car l))
- (expand-lambda-list (cdr l) env))))
-
- (def (l-vars l)
- (cond ((atom? l) (list l))
- ((cons? (car l)) (cons (caar l) (l-vars (cdr l))))
- (else (cons (car l) (l-vars (cdr l))))))
-
- (def (expand-lambda e env)
- (let ((formals (cadr e))
- (name (lastcdr e))
- (body (cddr e))
- (vars (l-vars (cadr e))))
- (let ((env (nconc (map list vars) env)))
- `(λ ,(expand-lambda-list formals env)
- ,.(expand-body body env)
- . ,name))))
-
- (def (expand-define e env)
- (if (or (not (cdr e)) (atom? (cadr e)))
- (if (not (cddr e))
- e
- (let* ((name (cadr e))
- (doc+body (separate-doc-from-body (cddr e)))
- (doc (car doc+body))
- (body (cdr doc+body)))
- (when doc
- (sym-set-doc name doc))
- `(def ,name ,(expand-in (car body) env))))
- (let* ((formals (cdadr e))
- (name (caadr e))
- (doc+body (separate-doc-from-body (cddr e)))
- (doc (car doc+body))
- (body (cdr doc+body))
- (vars (l-vars formals))
- (menv (nconc (map list vars) env)))
- (when doc
- (sym-set-doc name doc formals))
- `(def ,(cons name (expand-lambda-list formals menv))
- ,.(expand-body body menv)))))
-
- (def (expand-let-syntax e env)
- (let ((binds (cadr e)))
- (cons 'begin
- (expand-body (cddr e)
- (nconc
- (map (λ (bind)
- (list (car bind)
- ((compile-thunk
- (expand-in (cadr bind) env)))
- env))
- binds)
- env)))))
-
- ; given let-syntax definition environment (menv) and environment
- ; at the point of the macro use (lenv), return the environment to
- ; expand the macro use in. TODO
- (def (local-expansion-env menv lenv) menv)
-
- (def (expand-in e env)
- (if (atom? e)
- e
- (let* ((head (car e))
- (bnd (assq head env))
- (default (λ ()
- (let loop ((e e))
- (if (atom? e)
- e
- (cons (if (atom? (car e))
- (car e)
- (expand-in (car e) env))
- (loop (cdr e))))))))
- (cond ((and bnd (cons? (cdr bnd))) ; local macro
- (expand-in (apply (cadr bnd) (cdr e))
- (local-expansion-env (caddr bnd) env)))
- ((macrocall? e) => (λ (f)
- (expand-in (apply f (cdr e)) env)))
- ((or bnd ; bound lexical or toplevel var
- (not (sym? head))
- (bound? head))
- (default))
- ((eq? head 'quote) e)
- ((eq? head 'λ) (expand-lambda e env))
- ((eq? head 'lambda) (expand-lambda e env))
- ((eq? head 'def) (expand-define e env))
- ((eq? head 'let-syntax) (expand-let-syntax e env))
- (else (default))))))
- (expand-in e NIL))
-
-(def (eval x)
- ((compile-thunk (macroexpand x))))
-
-(def (load-process x)
- (eval x))
-
-(def (load filename)
- (let ((F (file filename :read)))
- (trycatch
- (let next (prev E v)
- (if (not (io-eof? F))
- (next (read F)
- prev
- (begin (load-process E) (void)))
- (begin (io-close F)
- ; evaluate last form in almost-tail position
- (void (load-process E)))))
- (λ (e)
- (io-close F)
- (raise `(load-error ,filename ,e))))))
-
-(def (repl)
- (def (prompt)
- (*prompt*)
- (io-flush *io-out*)
- (let ((v (trycatch (read)
- (λ (e) (io-discardbuffer *io-in*)
- (raise e)))))
- (and (not (io-eof? *io-in*))
- (let ((V (load-process v)))
- (unless (void? V) (print V) (newline))
- (void (set! that V))))))
- (def (reploop)
- (when (trycatch (prompt)
- (λ (e)
- (top-level-exception-handler e)
- T))
- (reploop)))
- (reploop)
- (newline))
-
-(def (top-level-exception-handler e)
- (with-output-to *stderr*
- (print-exception e)
- (print-stack-trace (stacktrace))))
-
-(def (print-stack-trace st)
- (def (find-in-f f tgt path)
- (let ((path (cons (fn-name f) path)))
- (if (eq? (fn-code f) (fn-code tgt))
- (throw 'ffound path)
- (let ((v (fn-vals f)))
- (for 0 (1- (length v))
- (λ (i) (when (closure? (aref v i))
- (find-in-f (aref v i) tgt path))))))))
- (def (fname f e)
- (let ((p (catch 'ffound
- (begin
- (for-each (λ (topfun)
- (find-in-f topfun f NIL))
- e)
- NIL))))
- (if p
- (str-join (map str (reverse! p)) "/")
- "λ")))
- (let ((st (reverse! (if (length> st 3)
- (list-tail st (if *interactive* 5 4))
- st)))
- (e (filter closure? (map (λ (s) (and (bound? s)
- (top-level-value s)))
- (environment))))
- (n 0))
- (for-each
- (λ (f)
- (princ "(" (fname (aref f 1) e))
- (for-each (λ (p) (princ " ") (print p))
- (cdr (cdr (vec->list f))))
- (princ ")" *linefeed*)
- (when (= n 0)
- (fn-disasm (aref f 1) (aref f 0)))
- (set! n (+ n 1)))
- st)))
-
-(def (print-exception e)
- (cond ((and (cons? e)
- (eq? (car e) 'type-error)
- (length= e 3))
- (princ "type error: expected " (cadr e) ", got " (typeof (caddr e)) ": ")
- (print (caddr e)))
-
- ((and (cons? e)
- (eq? (car e) 'bounds-error)
- (length= e 3))
- (princ "index " (caddr e) " out of bounds for ")
- (print (cadr e)))
-
- ((and (cons? e)
- (eq? (car e) 'unbound-error)
- (length= e 2))
- (princ "eval: variable " (cadr e) " has no value"))
-
- ((and (cons? e)
- (eq? (car e) 'error))
- (princ "error: ")
- (apply princ (cdr e)))
-
- ((and (cons? e)
- (eq? (car e) 'load-error))
- (print-exception (caddr e))
- (princ "in file " (cadr e)))
-
- ((and (list? e)
- (length= e 2))
- (print (car e))
- (princ ": ")
- (let ((msg (cadr e)))
- ((if (or (str? msg) (sym? msg))
- princ
- print)
- msg)))
-
- (else (princ "*** Unhandled exception: ")
- (print e)))
-
- (princ *linefeed*))
-
-(def (make-system-image fname)
- (def (sort l)
- (if (or (not l) (not (cdr l)))
- l
- (let ((piv (car l)))
- (receive (less grtr)
- (partition (λ (x) (< x piv)) (cdr l))
- (nconc (sort less)
- (list piv)
- (sort grtr))))))
- (let ((f (file fname :write :create :truncate))
- (excludes '(*linefeed* *directory-separator* *argv* that *exit-hooks*
- *print-pretty* *print-width* *print-readably*
- *print-level* *print-length* *os-name* *interactive*
- *prompt* *os-version*)))
- (with-bindings ((*print-pretty* T)
- (*print-readably* T))
- (let* ((syms
- (filter (λ (s)
- (and (bound? s)
- (not (const? s))
- (or (not (builtin? (top-level-value s)))
- (not (equal? (str s) ; alias of builtin
- (str (top-level-value s)))))
- (not (memq s excludes))
- (not (io? (top-level-value s)))))
- (sort (environment))))
- (data (apply nconc (map list syms (map top-level-value syms)))))
- (write data f)
- (io-write f *linefeed*))
- (io-close f))))
-
-; initialize globals that need to be set at load time
-(def (__init_globals)
- (let ((defprompt (if (equal? *os-name* "macos")
- (λ () (princ "\x1b[0m\x1b[1m#;> \x1b[0m"))
- (λ () (princ "#;> ")))))
- (set! *prompt*
- "Function called by REPL to signal the user input is required.
-
- Default function prints `#;> `."
- defprompt))
- (set! *directory-separator* (or (and (equal? *os-name* "dos") "\\") "/"))
- (set! *linefeed* "\n")
- (set! *exit-hooks* NIL)
- (set! *io-out* *stdout*)
- (set! *io-in* *stdin*)
- (set! *io-err* *stderr*))
-
-(def (__script fname)
- (trycatch (load fname)
- (λ (e) (top-level-exception-handler e)
- (exit (str e)))))
-
-(def (__rcscript)
- (let* ((homevar (case *os-name*
- (("unknown") NIL)
- (("plan9") "home")
- (("macos") (princ "\x1b]0;StreetLISP v0.999\007") NIL)
- (else "HOME")))
- (home (and homevar (os-getenv homevar)))
- (rcpath (case *os-name*
- (("plan9") "lib/slrc")
- (else ".slrc")))
- (fname (and home (str home *directory-separator* rcpath))))
- (and fname (path-exists? fname) (load fname))))
-
-(def (__start argv interactive)
- (__init_globals)
- (set! *argv* argv)
- (set! *interactive* interactive)
- (if (cons? (cdr argv))
- (begin (set! *argv* (cdr argv))
- (__script (cadr argv)))
- (set! *interactive* T))
- (when *interactive*
- (__rcscript)
- (repl))
- (exit))
-
-(def (add-exit-hook fun)
- "Puts an one-argument function on top of the list of exit hooks.
-
- On shutdown each exit hook is called with the exit status as a single
- argument, which is (usually) `NIL` on success and a string describing
- an error otherwise."
- (set! *exit-hooks* (cons fun *exit-hooks*))
- (void))
-
-(def (__finish status)
- "A function called right before exit by the VM."
- (for-each (λ (f) (f status)) *exit-hooks*))
--- /dev/null
+++ b/src/system.sl
@@ -1,0 +1,1432 @@
+; StreetLISP standard library
+; by Jeff Bezanson (C) 2009
+; Distributed under the BSD License
+
+;;; void
+
+(def (void . rest)
+ "Return the constant `#<void>` while ignoring any arguments.
+
+ `#<void>` is mainly used when a function has side effects but does not
+ produce any meaningful value to return, so even though `T` or `NIL` could
+ be returned instead, in case of `#<void>` alone, REPL will not print
+ it."
+ #.(void))
+
+(def (void? x)
+ "Return `T` if `x` is `#<void>`, `NIL` otherwise."
+ (eq? x #.(void)))
+
+;;; syntax environment
+
+(unless (bound? '*syntax-environment*)
+ (def *syntax-environment* (table)))
+
+(def (set-syntax! s v)
+ (put! *syntax-environment* s v))
+
+(def (get-syntax s)
+ (get *syntax-environment* s NIL))
+
+(def (separate-doc-from-body body (doc NIL))
+ (let {[hd (car body)]
+ [tl (cdr body)]}
+ (cond [(and (not doc) (str? hd) tl)
+ (separate-doc-from-body tl (cons hd doc))]
+ [(and doc (member hd '(:doc-group :doc-see-also)))
+ (separate-doc-from-body (cdr tl) (list* (car tl) hd doc))]
+ [else (cons (reverse doc) body)])))
+
+(defmacro (defmacro form . body)
+ (let* {[doc+body (separate-doc-from-body body)]
+ [doc (car doc+body)]
+ [body (cdr doc+body)]}
+ (when doc
+ (sym-set-doc (car form) doc (cdr form)))
+ `(void (set-syntax! ',(car form)
+ (λ ,(cdr form) ,@body)))))
+
+(defmacro (letrec binds . body)
+ `((λ ,(map car binds)
+ ,.(map (λ (b) `(set! ,@b)) binds)
+ ,@body)
+ ,.(map void binds)))
+
+(defmacro (let binds . body)
+ (let ((lname NIL))
+ (when (sym? binds)
+ (set! lname binds)
+ (set! binds (car body))
+ (set! body (cdr body)))
+ (let ((thelambda
+ `(λ ,(map (λ (c) (if (cons? c) (car c) c))
+ binds)
+ ,@body))
+ (theargs
+ (map (λ (c) (if (cons? c) (cadr c) (void)))
+ binds)))
+ (cons (if lname
+ `(letrec ((,lname ,thelambda)) ,lname)
+ thelambda)
+ theargs))))
+
+(defmacro (cond . clauses)
+ (def (cond-clauses->if lst)
+ (if (atom? lst)
+ NIL
+ (let ((clause (car lst)))
+ (if (or (eq? (car clause) 'else)
+ (eq? (car clause) T))
+ (if (not (cdr clause))
+ (car clause)
+ (cons 'begin (cdr clause)))
+ (if (not (cdr clause))
+ ; test by itself
+ (list 'or
+ (car clause)
+ (cond-clauses->if (cdr lst)))
+ ; test => expression
+ (if (eq? (cadr clause) '=>)
+ (if (1arg-lambda? (caddr clause))
+ ; test => (λ (x) ...)
+ (let ((var (caadr (caddr clause))))
+ `(let ((,var ,(car clause)))
+ (if ,var
+ ,(cons 'begin (cddr (caddr clause)))
+ ,(cond-clauses->if (cdr lst)))))
+ ; test => proc
+ `(let ((b# ,(car clause)))
+ (if b#
+ (,(caddr clause) b#)
+ ,(cond-clauses->if (cdr lst)))))
+ (list 'if
+ (car clause)
+ (cons 'begin (cdr clause))
+ (cond-clauses->if (cdr lst)))))))))
+ (cond-clauses->if clauses))
+
+;;; props
+
+;; This is implemented in a slightly different fashion as expected:
+;;
+;; *properties* : key → { symbol → value }
+;;
+;; The assumption here is that keys will most likely be the same across multiple symbols
+;; so it makes more sense to reduce the number of subtables for the *properties* table.
+(unless (bound? '*properties*)
+ (def *properties* (table)))
+
+(def (putprop symbol key val)
+ "Associate a property value with a symbol."
+ (let ((kt (get *properties* key NIL)))
+ (unless kt
+ (let ((ta (table)))
+ (put! *properties* key ta)
+ (set! kt ta)))
+ (put! kt symbol val)
+ val))
+
+(def (getprop symbol key (def NIL))
+ "Get a property value associated with a symbol or `def` if missing."
+ (let ((kt (get *properties* key NIL)))
+ (or (and kt (get kt symbol def)) def)))
+
+(def (remprop symbol key)
+ "Remove a property value associated with a symbol."
+ (let ((kt (get *properties* key NIL)))
+ (and kt (has? kt symbol) (del! kt symbol))))
+
+;;; documentation
+
+(def (sym-set-doc symbol doc-seq . funvars)
+ (let {[doc (if (str? doc-seq)
+ doc-seq
+ (car doc-seq))]}
+ (when (and (bound? 'str-join) doc)
+ (let* {[lines (str-split doc "\n")]
+ [hd (car lines)]
+ [tl (cdr lines)]
+ [snd (any (λ (s) (and (> (length s) 0)
+ (= (aref s 0) #\space)
+ s))
+ tl)]
+ [indent (and snd
+ (- (length snd)
+ (length (str-trim snd " " ""))))]
+ [trimmed (and snd
+ (map (λ (s) (if (<= indent (length s))
+ (str-sub s indent)
+ s))
+ tl))]
+ [final (str-join (cons hd trimmed) "\n")]}
+ (putprop symbol '*doc* final)))
+ (when (cons? funvars)
+ (let* {[existing (getprop symbol '*funvars* NIL)]
+ ; filter out duplicates
+ [to-add (filter (λ (funvar) (not (member funvar existing)))
+ funvars)]}
+ (putprop symbol '*funvars* (append existing to-add))))
+ (void)))
+
+;; chicken and egg - properties defined before sym-set-doc
+(sym-set-doc
+ '*properties*
+ "All properties of symbols recorded with `putprop` are recorded in this table.")
+
+(def (help-print-header term sigs)
+ "Format and print term's signature(s) for `(help term)` output."
+ (if sigs
+ (for-each (λ (sig) (print (cons term sig))
+ (newline))
+ sigs)
+ (begin (print term)
+ (newline)))
+ (newline))
+
+(defmacro (help term (:print-header help-print-header))
+ "Display documentation for the specified term, if available."
+ (let* {[doc (getprop term '*doc*)]
+ [sigs (getprop term '*funvars* NIL)]}
+ (if (or doc sigs)
+ `(begin (,print-header ',term ',sigs)
+ (when ,doc
+ (princ ,doc)
+ (newline))
+ (void))
+ (begin (princ "no help for " term)
+ (when (and (sym? term)
+ (not (bound? term)))
+ (princ " (undefined)"))
+ (newline))
+ (void))))
+
+;;; standard procedures
+
+(def (member item lst)
+ (cond ((equal? (car lst) item) lst)
+ (lst (member item (cdr lst)))))
+
+(def (memv item lst)
+ (cond ((eqv? (car lst) item) lst)
+ (lst (memv item (cdr lst)))))
+
+(def (assoc item lst)
+ (cond ((equal? (caar lst) item) (car lst))
+ (lst (assoc item (cdr lst)))))
+
+(def (assv item lst)
+ (cond ((eqv? (caar lst) item) (car lst))
+ (lst (assv item (cdr lst)))))
+
+(def (> a . rest)
+ "Return `T` if the arguments are in strictly decreasing order (previous
+ one is greater than the next one)."
+ (let loop ((a a) (rest rest))
+ (or (not rest)
+ (and (< (car rest) a)
+ (loop (car rest) (cdr rest))))))
+(defmacro (> a . rest)
+ `(< ,@(reverse! rest) ,a))
+
+(def (<= a . rest)
+ "Return `T` if the arguments are in non-decreasing order (previous
+ one is less than or equal to the next one)."
+ (let loop ((a a) (rest rest))
+ (or (not rest)
+ (unless (or (< (car rest) a)
+ (nan? a))
+ (loop (car rest) (cdr rest))))))
+
+(def (>= a . rest)
+ "Return `T` if the arguments are in non-increasing order (previous
+ one is greater than or equal to the next one)."
+ (let loop ((a a) (rest rest))
+ (or (not rest)
+ (unless (or (< a (car rest))
+ (nan? a))
+ (loop (car rest) (cdr rest))))))
+
+(defmacro (/= a . rest)
+ "Return `T` if not all arguments are equal. Shorthand for `(not (= …))`."
+ `(not (= ,a ,@rest)))
+
+(def (negative? x)
+ "Return `T` if `x` is negative."
+ (< x 0))
+
+(def (zero? x)
+ "Return `T` if `x` is zero."
+ (= x 0))
+
+(def (positive? x)
+ "Return `T` if `x` is greater than zero."
+ (> x 0))
+
+(def (even? x)
+ (= (logand x 1) 0))
+
+(def (odd? x)
+ (not (even? x)))
+
+(def (identity x)
+ "Return `x`."
+ x)
+
+(def (1+ n)
+ "Equivalent to `(+ n 1)`."
+ (+ n 1))
+
+(def (1- n)
+ "Equivalent to `(- n 1)`."
+ (- n 1))
+
+(def (div x y)
+ (+ (div0 x y)
+ (or (and (< x 0)
+ (or (and (< y 0) 1)
+ -1))
+ 0)))
+
+(def (mod0 x y)
+ (- x (* (div0 x y) y)))
+
+(def (mod x y)
+ (- x (* (div x y) y)))
+
+(def (random n)
+ (if (int? n)
+ (mod (rand) n)
+ (* (rand-double) n)))
+
+(def (abs x)
+ (if (< x 0)
+ (- x)
+ x))
+
+(def (max x0 . xs)
+ (if xs
+ (foldl (λ (a b) (if (< a b) b a))
+ x0
+ xs)
+ x0))
+
+(def (min x0 . xs)
+ (if xs
+ (foldl (λ (a b) (if (< a b) a b))
+ x0
+ xs)
+ x0))
+
+(def (rune? x)
+ (eq? (typeof x) 'rune))
+
+(def (arr? x)
+ (or (vec? x)
+ (let ((tx (typeof x)))
+ (and (cons? tx) (eq? (car tx) 'arr)))))
+
+(def (closure? x)
+ (and (fn? x)
+ (not (builtin? x))))
+
+(def (caar x) (car (car x)))
+(def (cdar x) (cdr (car x)))
+(def (cddr x) (cdr (cdr x)))
+(def (caaar x) (car (car (car x))))
+(def (caadr x) (car (car (cdr x))))
+(def (cadar x) (car (cdr (car x))))
+(def (caddr x) (car (cdr (cdr x))))
+(def (cdaar x) (cdr (car (car x))))
+(def (cdadr x) (cdr (car (cdr x))))
+(def (cddar x) (cdr (cdr (car x))))
+(def (cdddr x) (cdr (cdr (cdr x))))
+(def (caaaar x) (car (car (car (car x)))))
+(def (caaadr x) (car (car (car (cdr x)))))
+(def (caadar x) (car (car (cdr (car x)))))
+(def (caaddr x) (car (car (cdr (cdr x)))))
+(def (cadaar x) (car (cdr (car (car x)))))
+(def (cadadr x) (car (cdr (car (cdr x)))))
+(def (caddar x) (car (cdr (cdr (car x)))))
+(def (cadddr x) (car (cdr (cdr (cdr x)))))
+(def (cdaaar x) (cdr (car (car (car x)))))
+(def (cdaadr x) (cdr (car (car (cdr x)))))
+(def (cdadar x) (cdr (car (cdr (car x)))))
+(def (cdaddr x) (cdr (car (cdr (cdr x)))))
+(def (cddaar x) (cdr (cdr (car (car x)))))
+(def (cddadr x) (cdr (cdr (car (cdr x)))))
+(def (cdddar x) (cdr (cdr (cdr (car x)))))
+(def (cddddr x) (cdr (cdr (cdr (cdr x)))))
+
+(let ((*values* (list '*values*)))
+ (set! values
+ (λ vs
+ (if (and (cons? vs) (not (cdr vs)))
+ (car vs)
+ (cons *values* vs))))
+ (set! call-with-values
+ (λ (producer consumer)
+ (let ((res (producer)))
+ (if (and (cons? res) (eq? *values* (car res)))
+ (apply consumer (cdr res))
+ (consumer res))))))
+
+;;; list utilities
+
+(def (every pred lst)
+ (or (atom? lst)
+ (and (pred (car lst))
+ (every pred (cdr lst)))))
+
+(def (any pred lst)
+ (and (cons? lst)
+ (or (pred (car lst))
+ (any pred (cdr lst)))))
+
+(def (list? a)
+ (or (not a) (and (cons? a) (list? (cdr a)))))
+
+(def (list-tail lst n)
+ (if (<= n 0)
+ lst
+ (list-tail (cdr lst) (- n 1))))
+
+(def (list-head lst n)
+ (and (> n 0)
+ (cons (car lst)
+ (list-head (cdr lst) (- n 1)))))
+
+(def (list-ref lst n)
+ (car (list-tail lst n)))
+
+(def (length= lst n)
+ "Perform a bounded length test.
+
+ Use this instead of `(= (length lst) n)`, since it avoids unnecessary
+ work and always terminates."
+ (cond ((< n 0) NIL)
+ ((= n 0) (atom? lst))
+ ((atom? lst) (= n 0))
+ (else (length= (cdr lst) (- n 1)))))
+
+(def (length> lst n)
+ (cond ((< n 0) lst)
+ ((= n 0) (and (cons? lst) lst))
+ ((atom? lst) (< n 0))
+ (else (length> (cdr lst) (- n 1)))))
+
+(def (last-pair l)
+ (if (atom? (cdr l))
+ l
+ (last-pair (cdr l))))
+
+(def (lastcdr l)
+ (if (atom? l)
+ l
+ (cdr (last-pair l))))
+
+(def (to-proper l)
+ (cond ((not l) l)
+ ((atom? l) (list l))
+ (else (cons (car l) (to-proper (cdr l))))))
+
+(def (map! f lst)
+ (prog1 lst
+ (while (cons? lst)
+ (set-car! lst (f (car lst)))
+ (set! lst (cdr lst)))))
+
+(def (filter pred lst)
+ (def (filter- f lst acc)
+ (cdr
+ (prog1 acc
+ (while (cons? lst)
+ (when (pred (car lst))
+ (set! acc
+ (cdr (set-cdr! acc (cons (car lst) NIL)))))
+ (set! lst (cdr lst))))))
+ (filter- pred lst (list NIL)))
+
+(def (partition pred lst)
+ (def (partition- pred lst yes no)
+ (let ((vals
+ (prog1
+ (cons yes no)
+ (while (cons? lst)
+ (if (pred (car lst))
+ (set! yes (cdr (set-cdr! yes (cons (car lst) NIL))))
+ (set! no (cdr (set-cdr! no (cons (car lst) NIL)))))
+ (set! lst (cdr lst))))))
+ (values (cdr (car vals)) (cdr (cdr vals)))))
+ (partition- pred lst (list NIL) (list NIL)))
+
+(def (count f l)
+ (def (count- f l n)
+ (if (not l)
+ n
+ (count- f (cdr l) (if (f (car l))
+ (+ n 1)
+ n))))
+ (count- f l 0))
+
+(def (nestlist f zero n)
+ (and (> n 0)
+ (cons zero (nestlist f (f zero) (- n 1)))))
+
+(def (foldr f zero lst)
+ (if (not lst)
+ zero
+ (f (car lst) (foldr f zero (cdr lst)))))
+
+(def (foldl f zero lst)
+ (if (not lst)
+ zero
+ (foldl f (f (car lst) zero) (cdr lst))))
+
+(def (reverse- zero lst)
+ (if (not lst)
+ zero
+ (reverse- (cons (car lst) zero) (cdr lst))))
+
+(def (reverse lst)
+ (reverse- NIL lst))
+
+(def (reverse!- prev l)
+ (while (cons? l)
+ (set! l (prog1 (cdr l)
+ (set-cdr! l (prog1 prev
+ (set! prev l))))))
+ prev)
+
+(def (reverse! l)
+ (reverse!- NIL l))
+
+(def (copy-tree l)
+ (if (atom? l)
+ l
+ (cons (copy-tree (car l))
+ (copy-tree (cdr l)))))
+
+(def (delete-duplicates lst)
+ (if (length> lst 20)
+ (let ((ta (table)))
+ (let loop ((l lst) (acc NIL))
+ (if (atom? l)
+ (reverse! acc)
+ (if (has? ta (car l))
+ (loop (cdr l) acc)
+ (begin
+ (put! ta (car l) T)
+ (loop (cdr l) (cons (car l) acc)))))))
+ (if (atom? lst)
+ lst
+ (let ((elt (car lst))
+ (tail (cdr lst)))
+ (if (member elt tail)
+ (delete-duplicates tail)
+ (cons elt
+ (delete-duplicates tail)))))))
+
+; you are not expected to understand this -- spew
+
+(def (zip-with f . lst)
+ (apply map f lst))
+
+(def (zip . lst)
+ (apply map list lst))
+
+;;; backquote
+
+(def (revappend l1 l2)
+ (reverse- l2 l1))
+
+(def (nreconc l1 l2)
+ (reverse!- l2 l1))
+
+(def (self-evaluating? x)
+ (and (not (gensym? x))
+ (or (and (atom? x)
+ (not (sym? x)))
+ (and (const? x)
+ (sym? x)
+ (eq? x (top-level-value x))))))
+
+(defmacro (quasiquote x) (bq-process x 0))
+
+(def (splice-form? x)
+ (or (and (cons? x) (or (eq? (car x) 'unquote-splicing)
+ (eq? (car x) 'unquote-nsplicing)
+ (and (eq? (car x) 'unquote)
+ (length> x 2))))
+ (eq? x 'unquote)))
+
+;; bracket without splicing
+(def (bq-bracket1 x d)
+ (if (and (cons? x) (eq? (car x) 'unquote))
+ (if (= d 0)
+ (cadr x)
+ (list cons ''unquote
+ (bq-process (cdr x) (- d 1))))
+ (bq-process x d)))
+
+(def (bq-bracket x d)
+ (cond ((atom? x) (list list (bq-process x d)))
+ ((eq? (car x) 'unquote)
+ (if (= d 0)
+ (cons list (cdr x))
+ (list list (list cons ''unquote
+ (bq-process (cdr x) (- d 1))))))
+ ((eq? (car x) 'unquote-splicing)
+ (if (= d 0)
+ (list 'copy-list (cadr x))
+ (list list (list list ''unquote-splicing
+ (bq-process (cadr x) (- d 1))))))
+ ((eq? (car x) 'unquote-nsplicing)
+ (if (= d 0)
+ (cadr x)
+ (list list (list list ''unquote-nsplicing
+ (bq-process (cadr x) (- d 1))))))
+ (else (list list (bq-process x d)))))
+
+(def (bq-process x d)
+ (cond ((sym? x) (list 'quote x))
+ ((vec? x)
+ (let ((body (bq-process (vec->list x) d)))
+ (if (eq? (car body) list)
+ (cons vec (cdr body))
+ (list apply vec body))))
+ ((atom? x) x)
+ ((eq? (car x) 'quasiquote)
+ (list list ''quasiquote (bq-process (cadr x) (+ d 1))))
+ ((eq? (car x) 'unquote)
+ (if (and (= d 0) (length= x 2))
+ (cadr x)
+ (list cons ''unquote (bq-process (cdr x) (- d 1)))))
+ ((not (any splice-form? x))
+ (let ((lc (lastcdr x))
+ (forms (map (λ (x) (bq-bracket1 x d)) x)))
+ (if (not lc)
+ (cons list forms)
+ (if (not (cdr forms))
+ (list cons (car forms) (bq-process lc d))
+ (nconc (cons list* forms) (list (bq-process lc d)))))))
+ (else
+ (let loop ((p x) (q NIL))
+ (cond ((not p) ;; proper list
+ (cons 'nconc (reverse! q)))
+ ((cons? p)
+ (cond ((eq? (car p) 'unquote)
+ ;; (... . ,x)
+ (cons 'nconc
+ (nreconc q
+ (if (= d 0)
+ (cdr p)
+ (list (list list ''unquote)
+ (bq-process (cdr p)
+ (- d 1)))))))
+ (else
+ (loop (cdr p) (cons (bq-bracket (car p) d) q)))))
+ (else
+ ;; (... . x)
+ (cons 'nconc (reverse! (cons (bq-process p d) q)))))))))
+
+;;; standard macros
+
+(def (quote-value v)
+ (if (self-evaluating? v)
+ v
+ (list 'quote v)))
+
+(defmacro (let* binds . body)
+ (if (atom? binds)
+ `((λ () ,@body))
+ `((λ (,(caar binds))
+ ,@(if (cons? (cdr binds))
+ `((let* ,(cdr binds) ,@body))
+ body))
+ ,(cadar binds))))
+
+(defmacro (when c . body)
+ (list 'if c (cons 'begin body) NIL))
+
+(defmacro (unless c . body)
+ (list 'if c NIL (cons 'begin body)))
+
+(defmacro (case key . clauses)
+ (def (vals->cond key v)
+ (cond ((eq? v 'else) 'else)
+ ((not v) NIL)
+ ((sym? v) `(eq? ,key ,(quote-value v)))
+ ((atom? v) `(eqv? ,key ,(quote-value v)))
+ ((not (cdr v)) `(eqv? ,key ,(quote-value (car v))))
+ ((every sym? v)
+ `(memq ,key ',v))
+ (else `(memv ,key ',v))))
+ (let ((g (gensym)))
+ `(let ((,g ,key))
+ (cond ,.(map (λ (clause)
+ (cons (vals->cond g (car clause))
+ (cdr clause)))
+ clauses)))))
+
+(defmacro (do vars test-spec . commands)
+ (let ((test-expr (car test-spec))
+ (vars (map car vars))
+ (inits (map cadr vars))
+ (steps (map (λ (x)
+ (if (cons? (cddr x))
+ (caddr x)
+ (car x)))
+ vars)))
+ `(letrec ((loop# (λ ,vars
+ (if ,test-expr
+ (begin
+ ,@(cdr test-spec))
+ (begin
+ ,@commands
+ (loop# ,.steps))))))
+ (loop# ,.inits))))
+
+; SRFI 8
+(defmacro (receive formals expr . body)
+ `(call-with-values (λ () ,expr)
+ (λ ,formals ,@body)))
+
+(defmacro (dotimes var . body)
+ (let ((v (car var))
+ (cnt (cadr var)))
+ `(for 0 (- ,cnt 1)
+ (λ (,v) ,@body))))
+
+(def (map-int f n)
+ (and (> n 0)
+ (let ((first (cons (f 0) NIL))
+ (acc NIL))
+ (set! acc first)
+ (for 1 (1- n)
+ (λ (i) (set-cdr! acc (cons (f i) NIL))
+ (set! acc (cdr acc))))
+ first)))
+
+(def (iota n)
+ (map-int identity n))
+
+(defmacro (with-bindings binds . body)
+ (let ((vars (map car binds))
+ (vals (map cadr binds))
+ (olds (map (λ (x) (gensym)) binds)))
+ `(let ,(map list olds vars)
+ ,@(map (λ (v val) `(set! ,v ,val)) vars vals)
+ (unwind-protect
+ (begin ,@body)
+ (begin ,@(map (λ (v old) `(set! ,v ,old)) vars olds))))))
+
+;;; exceptions
+
+(def (error . args)
+ (raise (cons 'error args)))
+
+(defmacro (throw tag value)
+ `(raise (list 'thrown-value ,tag ,value)))
+
+(defmacro (catch tag expr)
+ `(trycatch ,expr
+ (λ (e#) (if (and (cons? e#)
+ (eq? (car e#) 'thrown-value)
+ (eq? (cadr e#) ,tag))
+ (caddr e#)
+ (raise e#)))))
+
+(defmacro (unwind-protect expr finally)
+ `(let ((thk# (λ () ,finally)))
+ (prog1 (trycatch ,expr
+ (λ (e#) (thk#) (raise e#)))
+ (thk#))))
+
+;;; debugging utilities
+
+(defmacro (assert expr)
+ `(if ,expr T (raise '(assert-failed ,expr))))
+
+(def traced?
+ (let ((sample-traced-lambda (λ args (write (cons 'x args))
+ (newline)
+ (apply #.apply args))))
+ (λ (f)
+ (and (closure? f)
+ (equal? (fn-code f)
+ (fn-code sample-traced-lambda))))))
+
+(def (trace symbol)
+ (let ((func (top-level-value symbol)))
+ (when (not (traced? func))
+ (set-top-level-value! symbol
+ (eval
+ `(λ args#
+ (write (cons ',symbol args#))
+ (newline)
+ (apply ',func args#))))))
+ (void))
+
+(def (untrace symbol)
+ (let ((func (top-level-value symbol)))
+ (when (traced? func)
+ (set-top-level-value! symbol
+ (aref (fn-vals func) 3))))
+ (void))
+
+(defmacro (time expr)
+ `(let ((t0# (time-now)))
+ (prog1
+ ,expr
+ (princ "Elapsed time: " (- (time-now) t0#) " seconds" *linefeed*))))
+
+;;; text I/O
+
+(def (print . args)
+ (for-each write args))
+
+(def (princ . args)
+ (with-bindings ((*print-readably* NIL))
+ (for-each write args)))
+
+(def (newline (io *io-out*))
+ (io-write io *linefeed*)
+ (void))
+
+(def (io-readline s) (io-readuntil s #\linefeed))
+
+; call f on an io until the io runs out of data
+(def (read-all-of f s)
+ (let loop ((lines NIL)
+ (curr (f s)))
+ (if (io-eof? s)
+ (reverse! lines)
+ (loop (cons curr lines) (f s)))))
+
+(def (io-readlines s)
+ (read-all-of io-readline s))
+
+(def (read-all s)
+ (read-all-of read s))
+
+(def (io-readall s)
+ (let ((b (buffer)))
+ (io-copy b s)
+ (io->str b)))
+
+(defmacro (with-output-to io . body)
+ `(with-bindings ((*io-out* ,io))
+ ,@body))
+
+(defmacro (with-input-from io . body)
+ `(with-bindings ((*io-in* ,io))
+ ,@body))
+
+;;; vector functions
+
+(def (list->vec l)
+ (apply vec l))
+
+(def (vec->list v)
+ (let ((n (length v))
+ (l NIL))
+ (for 1 n
+ (λ (i)
+ (set! l (cons (aref v (- n i)) l))))
+ l))
+
+(def (vec-map f v)
+ (let* ((n (length v))
+ (nv (vec-alloc n)))
+ (for 0 (- n 1)
+ (λ (i)
+ (aset! nv i (f (aref v i)))))
+ nv))
+
+;;; table functions
+
+(def (table-pairs ta)
+ (table-foldl (λ (k v z) (cons (cons k v) z))
+ NIL ta))
+(def (table-keys ta)
+ (table-foldl (λ (k v z) (cons k z))
+ NIL ta))
+(def (table-values ta)
+ (table-foldl (λ (k v z) (cons v z))
+ NIL ta))
+(def (table-clone ta)
+ (let ((nt (table)))
+ (table-foldl (λ (k v z) (put! nt k v))
+ NIL ta)
+ nt))
+(def (table-invert ta)
+ (let ((nt (table)))
+ (table-foldl (λ (k v z) (put! nt v k))
+ NIL ta)
+ nt))
+
+;;; string functions
+
+(def (str-tail s n)
+ (str-sub s n))
+
+(def (str-trim s at-start at-end)
+ (def (trim-start s runes i L)
+ (if (and (< i L) (str-find runes (str-rune s i)))
+ (trim-start s runes (1+ i) L)
+ i))
+ (def (trim-end s runes i)
+ (if (and (> i 0) (str-find runes (str-rune s (1- i))))
+ (trim-end s runes (1- i))
+ i))
+ (let ((L (str-length s)))
+ (str-sub s
+ (trim-start s at-start 0 L)
+ (trim-end s at-end L))))
+
+(def (str-map f s)
+ (let ((b (buffer))
+ (n (str-length s)))
+ (let ((i 0))
+ (while (< i n)
+ (io-putc b (f (str-rune s i)))
+ (set! i (1+ i))))
+ (io->str b)))
+
+(def (str-rep s k)
+ (cond ((< k 4)
+ (cond ((<= k 0) "")
+ ((= k 1) (str s))
+ ((= k 2) (str s s))
+ (else (str s s s))))
+ ((odd? k) (str s (str-rep s (- k 1))))
+ (else (str-rep (str s s) (/ k 2)))))
+
+(def (str-lpad s n c)
+ (str (str-rep c (- n (str-length s))) s))
+
+(def (str-rpad s n c)
+ (str s (str-rep c (- n (str-length s)))))
+
+(def (print-to-str . args)
+ (let ((b (buffer)))
+ (for-each (λ (a) (write a b)) args)
+ (io->str b)))
+
+(def (str-join strlist sep)
+ (if (not strlist)
+ ""
+ (let ((b (buffer)))
+ (io-write b (car strlist))
+ (for-each (λ (s) (io-write b sep)
+ (io-write b s))
+ (cdr strlist))
+ (io->str b))))
+
+;;; structs
+
+(defmacro (defstruct name (:type vec)
+ (:named T)
+ (:constructor T)
+ (:conc-name NIL)
+ (:predicate NIL)
+ . slots)
+ "Defines a structure type with a specific name and slots.
+
+ The default underlying type is a \"named\" vector (`:type vec`),
+ where the first element is the name of the structure's type, the
+ rest are the slot values. If the name as the first element isn't
+ required, `:named NIL` should be used. A list can be used instead
+ of a vector by adding `:type list` option.
+
+ An example of a default constructor signature, based on structure
+ definition:
+
+ (defstruct blah a b c) →
+ (make-blah (:a NIL) (:b NIL) (:c NIL))
+
+ It can be customized in several ways. For example:
+
+ ; disable the constructor altogether
+ (defstruct blah :constructor NIL a b c)
+ ; only change its name
+ (defstruct blah :constructor blargh a b c)
+ ; rename AND avoid using keywords
+ (defstruct blah :constructor (blah a b c) a b c)
+
+ The option `:conc-name` specifies the slot accessor prefix, which
+ defaults to `name-`.
+
+ Default predicate name (`name?`) can be changed:
+
+ ; use \"blargh?\" instead of \"blah?\"
+ (defstruct blah :predicate blargh? a b c)"
+ (def (slot-opts slot)
+ ; check whether slot options, if any, are valid
+ (let ((opts (cddr slot)))
+ (for-each (λ (opt) (unless (member opt '(:read-only))
+ (error (str "invalid option in slot " (car slot)
+ " of struct " name
+ ": " opt))))
+ opts)
+ opts))
+ (def (tokw slots)
+ ; transform args list to keyworded variant.
+ ; eg: (a (b 1) (c :read-only)) → ((:a NIL) (:b 1) (:c NIL :read-only))
+ (map! (λ (slot) (let* {[name-cons (and (cons? slot)
+ (car slot))]
+ [name (or name-cons slot)]
+ [tail (or (and name-cons
+ (cdr slot))
+ (list NIL))]}
+ (when (or (not (sym? name))
+ (keyword? name))
+ (error "invalid slot name: " name))
+ (list* (sym #\: name)
+ (if (keyword? (car tail))
+ (cons NIL tail)
+ tail))))
+ slots))
+ (let* {; first element in slots may be the doc string
+ [doc (and (str? (car slots))
+ (car slots))]
+ ; if it is, rid of it
+ [slots (or (and doc (cdr slots))
+ slots)]
+ [num-slots (length slots)]
+ ; list of slot names
+ [slots-car (map (λ (f) (if (cons? f) (car f) f))
+ slots)]
+ ; slots, but with default values added (if not set)
+ ; and keywords for names
+ [slots-kw (tokw slots)]
+ ; struct's underlying type's predicate (either vec? or list?)
+ [type? (sym type #\?)]
+ ; struct's predicate name
+ [is? (or predicate
+ (sym name #\?))]
+ ; constructor name and arguments
+ [constructor
+ (and constructor ; NIL means none to make at all
+ (or (and (atom? constructor) ; a single argument
+ (cons (or (and (eq? constructor T) ; T means the defaults
+ (sym "make-" name))
+ constructor) ; else a custom name
+ slots-kw))
+ constructor))] ; anything else means custom name and args
+ ; should the struct name appear as the first element?
+ [named (and named (list name))]
+ ; accessor prefix
+ [access (or conc-name
+ (str name "-"))]}
+ `(begin
+ ; predicate
+ (def (,is? s)
+ (and [,type? s]
+ [or (not ',named) (eq? (aref s 0) ',name)]
+ [= (length s) ,(+ (length named) num-slots)]))
+ ; documentation string
+ (when ,doc
+ (sym-set-doc ',name ,doc))
+ ; constructor
+ ,(when constructor `(def ,constructor
+ (,type ',@named ,@slots-car)))
+ ; accessor per slot
+ ,@(map-int (λ (i) [let* {[opts (slot-opts (list-ref slots-kw i))]
+ [fld (list-ref slots-car i)]
+ [fun (sym access fld)]}
+ `(def (,fun s (v #.(void)))
+ (assert (,is? s))
+ (if (void? v)
+ (aref s ,[+ (length named) i])
+ ,(if (member :read-only opts)
+ `(error (str "slot "
+ ',fld
+ " in struct "
+ ',name
+ " is :read-only"))
+ `(aset! s ,[+ (length named) i] v))))])
+ num-slots))))
+
+(doc-for (defstruct name
+ doc
+ options…
+ (slot-1 DEFAULT)
+ slot-2
+ (slot-3 :read-only)))
+
+;;; toplevel
+
+(def (macrocall? e)
+ (and (sym? (car e))
+ (get-syntax (car e))))
+
+(def (macroexpand-1 e)
+ (if (atom? e)
+ e
+ (let ((f (macrocall? e)))
+ (if f
+ (apply f (cdr e))
+ e))))
+
+(def (macroexpand e)
+ ; symbol resolves to toplevel; i.e. has no shadowing definition
+ (def (top? s env) (not (or (bound? s) (assq s env))))
+
+ (def (splice-begin body)
+ (cond ((atom? body) body)
+ ((equal? body '((begin)))
+ body)
+ ((and (cons? (car body))
+ (eq? (caar body) 'begin))
+ (append (splice-begin (cdar body)) (splice-begin (cdr body))))
+ (else
+ (cons (car body) (splice-begin (cdr body))))))
+
+ (def *expanded* (list '*expanded*))
+
+ (def (expand-body body env)
+ (if (atom? body)
+ body
+ (let* ((body (if (top? 'begin env)
+ (splice-begin body)
+ body))
+ (def? (top? 'def env))
+ (dvars (and def? (get-defined-vars body)))
+ (env (nconc (map list dvars) env)))
+ (if (not def?)
+ (map (λ (x) (expand-in x env)) body)
+ (let* ((ex-nondefs ; expand non-definitions
+ (let loop ((body body))
+ (cond ((atom? body) body)
+ ((and (cons? (car body))
+ (eq? 'def (caar body)))
+ (cons (car body) (loop (cdr body))))
+ (else
+ (let ((form (expand-in (car body) env)))
+ (set! env (nconc
+ (map list (get-defined-vars form))
+ env))
+ (cons
+ (cons *expanded* form)
+ (loop (cdr body))))))))
+ (body ex-nondefs))
+ (while (cons? body) ; now expand deferred definitions
+ (if (not (eq? *expanded* (caar body)))
+ (set-car! body (expand-in (car body) env))
+ (set-car! body (cdar body)))
+ (set! body (cdr body)))
+ ex-nondefs)))))
+
+ (def (expand-lambda-list l env)
+ (if (atom? l)
+ l
+ (cons (if (and (cons? (car l)) (cons? (cdr (car l))))
+ (list (caar l) (expand-in (cadar l) env))
+ (car l))
+ (expand-lambda-list (cdr l) env))))
+
+ (def (l-vars l)
+ (cond ((atom? l) (list l))
+ ((cons? (car l)) (cons (caar l) (l-vars (cdr l))))
+ (else (cons (car l) (l-vars (cdr l))))))
+
+ (def (expand-lambda e env)
+ (let ((formals (cadr e))
+ (name (lastcdr e))
+ (body (cddr e))
+ (vars (l-vars (cadr e))))
+ (let ((env (nconc (map list vars) env)))
+ `(λ ,(expand-lambda-list formals env)
+ ,.(expand-body body env)
+ . ,name))))
+
+ (def (expand-define e env)
+ (if (or (not (cdr e)) (atom? (cadr e)))
+ (if (not (cddr e))
+ e
+ (let* ((name (cadr e))
+ (doc+body (separate-doc-from-body (cddr e)))
+ (doc (car doc+body))
+ (body (cdr doc+body)))
+ (when doc
+ (sym-set-doc name doc))
+ `(def ,name ,(expand-in (car body) env))))
+ (let* ((formals (cdadr e))
+ (name (caadr e))
+ (doc+body (separate-doc-from-body (cddr e)))
+ (doc (car doc+body))
+ (body (cdr doc+body))
+ (vars (l-vars formals))
+ (menv (nconc (map list vars) env)))
+ (when doc
+ (sym-set-doc name doc formals))
+ `(def ,(cons name (expand-lambda-list formals menv))
+ ,.(expand-body body menv)))))
+
+ (def (expand-let-syntax e env)
+ (let ((binds (cadr e)))
+ (cons 'begin
+ (expand-body (cddr e)
+ (nconc
+ (map (λ (bind)
+ (list (car bind)
+ ((compile-thunk
+ (expand-in (cadr bind) env)))
+ env))
+ binds)
+ env)))))
+
+ ; given let-syntax definition environment (menv) and environment
+ ; at the point of the macro use (lenv), return the environment to
+ ; expand the macro use in. TODO
+ (def (local-expansion-env menv lenv) menv)
+
+ (def (expand-in e env)
+ (if (atom? e)
+ e
+ (let* ((head (car e))
+ (bnd (assq head env))
+ (default (λ ()
+ (let loop ((e e))
+ (if (atom? e)
+ e
+ (cons (if (atom? (car e))
+ (car e)
+ (expand-in (car e) env))
+ (loop (cdr e))))))))
+ (cond ((and bnd (cons? (cdr bnd))) ; local macro
+ (expand-in (apply (cadr bnd) (cdr e))
+ (local-expansion-env (caddr bnd) env)))
+ ((macrocall? e) => (λ (f)
+ (expand-in (apply f (cdr e)) env)))
+ ((or bnd ; bound lexical or toplevel var
+ (not (sym? head))
+ (bound? head))
+ (default))
+ ((eq? head 'quote) e)
+ ((eq? head 'λ) (expand-lambda e env))
+ ((eq? head 'lambda) (expand-lambda e env))
+ ((eq? head 'def) (expand-define e env))
+ ((eq? head 'let-syntax) (expand-let-syntax e env))
+ (else (default))))))
+ (expand-in e NIL))
+
+(def (eval x)
+ ((compile-thunk (macroexpand x))))
+
+(def (load-process x)
+ (eval x))
+
+(def (load filename)
+ (let ((F (file filename :read)))
+ (trycatch
+ (let next (prev E v)
+ (if (not (io-eof? F))
+ (next (read F)
+ prev
+ (begin (load-process E) (void)))
+ (begin (io-close F)
+ ; evaluate last form in almost-tail position
+ (void (load-process E)))))
+ (λ (e)
+ (io-close F)
+ (raise `(load-error ,filename ,e))))))
+
+(def (repl)
+ (def (prompt)
+ (*prompt*)
+ (io-flush *io-out*)
+ (let ((v (trycatch (read)
+ (λ (e) (io-discardbuffer *io-in*)
+ (raise e)))))
+ (and (not (io-eof? *io-in*))
+ (let ((V (load-process v)))
+ (unless (void? V) (print V) (newline))
+ (void (set! that V))))))
+ (def (reploop)
+ (when (trycatch (prompt)
+ (λ (e)
+ (top-level-exception-handler e)
+ T))
+ (reploop)))
+ (reploop)
+ (newline))
+
+(def (top-level-exception-handler e)
+ (with-output-to *stderr*
+ (print-exception e)
+ (print-stack-trace (stacktrace))))
+
+(def (print-stack-trace st)
+ (def (find-in-f f tgt path)
+ (let ((path (cons (fn-name f) path)))
+ (if (eq? (fn-code f) (fn-code tgt))
+ (throw 'ffound path)
+ (let ((v (fn-vals f)))
+ (for 0 (1- (length v))
+ (λ (i) (when (closure? (aref v i))
+ (find-in-f (aref v i) tgt path))))))))
+ (def (fname f e)
+ (let ((p (catch 'ffound
+ (begin
+ (for-each (λ (topfun)
+ (find-in-f topfun f NIL))
+ e)
+ NIL))))
+ (if p
+ (str-join (map str (reverse! p)) "/")
+ "λ")))
+ (let ((st (reverse! (if (length> st 3)
+ (list-tail st (if *interactive* 5 4))
+ st)))
+ (e (filter closure? (map (λ (s) (and (bound? s)
+ (top-level-value s)))
+ (environment))))
+ (n 0))
+ (for-each
+ (λ (f)
+ (princ "(" (fname (aref f 1) e))
+ (for-each (λ (p) (princ " ") (print p))
+ (cdr (cdr (vec->list f))))
+ (princ ")" *linefeed*)
+ (when (= n 0)
+ (fn-disasm (aref f 1) (aref f 0)))
+ (set! n (+ n 1)))
+ st)))
+
+(def (print-exception e)
+ (cond ((and (cons? e)
+ (eq? (car e) 'type-error)
+ (length= e 3))
+ (princ "type error: expected " (cadr e) ", got " (typeof (caddr e)) ": ")
+ (print (caddr e)))
+
+ ((and (cons? e)
+ (eq? (car e) 'bounds-error)
+ (length= e 3))
+ (princ "index " (caddr e) " out of bounds for ")
+ (print (cadr e)))
+
+ ((and (cons? e)
+ (eq? (car e) 'unbound-error)
+ (length= e 2))
+ (princ "eval: variable " (cadr e) " has no value"))
+
+ ((and (cons? e)
+ (eq? (car e) 'error))
+ (princ "error: ")
+ (apply princ (cdr e)))
+
+ ((and (cons? e)
+ (eq? (car e) 'load-error))
+ (print-exception (caddr e))
+ (princ "in file " (cadr e)))
+
+ ((and (list? e)
+ (length= e 2))
+ (print (car e))
+ (princ ": ")
+ (let ((msg (cadr e)))
+ ((if (or (str? msg) (sym? msg))
+ princ
+ print)
+ msg)))
+
+ (else (princ "*** Unhandled exception: ")
+ (print e)))
+
+ (princ *linefeed*))
+
+(def (make-system-image fname)
+ (def (sort l)
+ (if (or (not l) (not (cdr l)))
+ l
+ (let ((piv (car l)))
+ (receive (less grtr)
+ (partition (λ (x) (< x piv)) (cdr l))
+ (nconc (sort less)
+ (list piv)
+ (sort grtr))))))
+ (let ((f (file fname :write :create :truncate))
+ (excludes '(*linefeed* *directory-separator* *argv* that *exit-hooks*
+ *print-pretty* *print-width* *print-readably*
+ *print-level* *print-length* *os-name* *interactive*
+ *prompt* *os-version*)))
+ (with-bindings ((*print-pretty* T)
+ (*print-readably* T))
+ (let* ((syms
+ (filter (λ (s)
+ (and (bound? s)
+ (not (const? s))
+ (or (not (builtin? (top-level-value s)))
+ (not (equal? (str s) ; alias of builtin
+ (str (top-level-value s)))))
+ (not (memq s excludes))
+ (not (io? (top-level-value s)))))
+ (sort (environment))))
+ (data (apply nconc (map list syms (map top-level-value syms)))))
+ (write data f)
+ (io-write f *linefeed*))
+ (io-close f))))
+
+; initialize globals that need to be set at load time
+(def (__init_globals)
+ (let ((defprompt (if (equal? *os-name* "macos")
+ (λ () (princ "\x1b[0m\x1b[1m#;> \x1b[0m"))
+ (λ () (princ "#;> ")))))
+ (set! *prompt*
+ "Function called by REPL to signal the user input is required.
+
+ Default function prints `#;> `."
+ defprompt))
+ (set! *directory-separator* (or (and (equal? *os-name* "dos") "\\") "/"))
+ (set! *linefeed* "\n")
+ (set! *exit-hooks* NIL)
+ (set! *io-out* *stdout*)
+ (set! *io-in* *stdin*)
+ (set! *io-err* *stderr*))
+
+(def (__script fname)
+ (trycatch (load fname)
+ (λ (e) (top-level-exception-handler e)
+ (exit (str e)))))
+
+(def (__rcscript)
+ (let* ((homevar (case *os-name*
+ (("unknown") NIL)
+ (("plan9") "home")
+ (("macos") (princ "\x1b]0;StreetLISP v0.999\007") NIL)
+ (else "HOME")))
+ (home (and homevar (os-getenv homevar)))
+ (rcpath (case *os-name*
+ (("plan9") "lib/slrc")
+ (else ".slrc")))
+ (fname (and home (str home *directory-separator* rcpath))))
+ (and fname (path-exists? fname) (load fname))))
+
+(def (__start argv interactive)
+ (__init_globals)
+ (set! *argv* argv)
+ (set! *interactive* interactive)
+ (if (cons? (cdr argv))
+ (begin (set! *argv* (cdr argv))
+ (__script (cadr argv)))
+ (set! *interactive* T))
+ (when *interactive*
+ (__rcscript)
+ (repl))
+ (exit))
+
+(def (add-exit-hook fun)
+ "Puts an one-argument function on top of the list of exit hooks.
+
+ On shutdown each exit hook is called with the exit status as a single
+ argument, which is (usually) `NIL` on success and a string describing
+ an error otherwise."
+ (set! *exit-hooks* (cons fun *exit-hooks*))
+ (void))
+
+(def (__finish status)
+ "A function called right before exit by the VM."
+ (for-each (λ (f) (f status)) *exit-hooks*))
--- a/test/100x100.lsp
+++ /dev/null
@@ -1,1 +1,0 @@
-'#0=(#198=(#197=(#196=(#195=(#194=(#193=(#192=(#191=(#190=(#189=(#188=(#187=(#186=(#185=(#184=(#183=(#182=(#181=(#180=(#179=(#178=(#177=(#176=(#175=(#174=(#173=(#172=(#171=(#170=(#169=(#168=(#167=(#166=(#165=(#164=(#163=(#162=(#161=(#160=(#159=(#158=(#157=(#156=(#155=(#154=(#153=(#152=(#151=(#150=(#149=(#148=(#147=(#146=(#145=(#144=(#143=(#142=(#141=(#140=(#139=(#138=(#137=(#136=(#135=(#134=(#133=(#132=(#131=(#130=(#129=(#128=(#127=(#126=(#125=(#124=(#123=(#122=(#121=(#120=(#119=(#118=(#117=(#116=(#115=(#114=(#113=(#112=(#111=(#110=(#109=(#108=(#107=(#106=(#105=(#104=(#103=(#102=(#101=(#100=(#0# . #1=(#9999=(#9998=(#9997=(#9996=(#9995=(#9994=(#9993=(#9992=(#9991=(#9990=(#9989=(#9988=(#9987=(#9986=(#9985=(#9984=(#9983=(#9982=(#9981=(#9980=(#9979=(#9978=(#9977=(#9976=(#9975=(#9974=(#9973=(#9972=(#9971=(#9970=(#9969=(#9968=(#9967=(#9966=(#9965=(#9964=(#9963=(#9962=(#9961=(#9960=(#9959=(#9958=(#9957=(#9956=(#9955=(#9954=(#9953=(#9952=(#9951=(#9950=(#9949=(#9948=(#9947=(#9946=(#9945=(#9944=(#9943=(#9942=(#9941=(#9940=(#9939=(#9938=(#9937=(#9936=(#9935=(#9934=(#9933=(#9932=(#9931=(#9930=(#9929=(#9928=(#9927=(#9926=(#9925=(#9924=(#9923=(#9922=(#9921=(#9920=(#9919=(#9918=(#9917=(#9916=(#9915=(#9914=(#9913=(#9912=(#9911=(#9910=(#9909=(#9908=(#9907=(#9906=(#9905=(#9904=(#9903=(#9902=(#9901=(#1# . #2=(#9900=(#9899=(#9898=(#9897=(#9896=(#9895=(#9894=(#9893=(#9892=(#9891=(#9890=(#9889=(#9888=(#9887=(#9886=(#9885=(#9884=(#9883=(#9882=(#9881=(#9880=(#9879=(#9878=(#9877=(#9876=(#9875=(#9874=(#9873=(#9872=(#9871=(#9870=(#9869=(#9868=(#9867=(#9866=(#9865=(#9864=(#9863=(#9862=(#9861=(#9860=(#9859=(#9858=(#9857=(#9856=(#9855=(#9854=(#9853=(#9852=(#9851=(#9850=(#9849=(#9848=(#9847=(#9846=(#9845=(#9844=(#9843=(#9842=(#9841=(#9840=(#9839=(#9838=(#9837=(#9836=(#9835=(#9834=(#9833=(#9832=(#9831=(#9830=(#9829=(#9828=(#9827=(#9826=(#9825=(#9824=(#9823=(#9822=(#9821=(#9820=(#9819=(#9818=(#9817=(#9816=(#9815=(#9814=(#9813=(#9812=(#9811=(#9810=(#9809=(#9808=(#9807=(#9806=(#9805=(#9804=(#9803=(#9802=(#2# . #3=(#9801=(#9800=(#9799=(#9798=(#9797=(#9796=(#9795=(#9794=(#9793=(#9792=(#9791=(#9790=(#9789=(#9788=(#9787=(#9786=(#9785=(#9784=(#9783=(#9782=(#9781=(#9780=(#9779=(#9778=(#9777=(#9776=(#9775=(#9774=(#9773=(#9772=(#9771=(#9770=(#9769=(#9768=(#9767=(#9766=(#9765=(#9764=(#9763=(#9762=(#9761=(#9760=(#9759=(#9758=(#9757=(#9756=(#9755=(#9754=(#9753=(#9752=(#9751=(#9750=(#9749=(#9748=(#9747=(#9746=(#9745=(#9744=(#9743=(#9742=(#9741=(#9740=(#9739=(#9738=(#9737=(#9736=(#9735=(#9734=(#9733=(#9732=(#9731=(#9730=(#9729=(#9728=(#9727=(#9726=(#9725=(#9724=(#9723=(#9722=(#9721=(#9720=(#9719=(#9718=(#9717=(#9716=(#9715=(#9714=(#9713=(#9712=(#9711=(#9710=(#9709=(#9708=(#9707=(#9706=(#9705=(#9704=(#9703=(#3# . #4=(#9702=(#9701=(#9700=(#9699=(#9698=(#9697=(#9696=(#9695=(#9694=(#9693=(#9692=(#9691=(#9690=(#9689=(#9688=(#9687=(#9686=(#9685=(#9684=(#9683=(#9682=(#9681=(#9680=(#9679=(#9678=(#9677=(#9676=(#9675=(#9674=(#9673=(#9672=(#9671=(#9670=(#9669=(#9668=(#9667=(#9666=(#9665=(#9664=(#9663=(#9662=(#9661=(#9660=(#9659=(#9658=(#9657=(#9656=(#9655=(#9654=(#9653=(#9652=(#9651=(#9650=(#9649=(#9648=(#9647=(#9646=(#9645=(#9644=(#9643=(#9642=(#9641=(#9640=(#9639=(#9638=(#9637=(#9636=(#9635=(#9634=(#9633=(#9632=(#9631=(#9630=(#9629=(#9628=(#9627=(#9626=(#9625=(#9624=(#9623=(#9622=(#9621=(#9620=(#9619=(#9618=(#9617=(#9616=(#9615=(#9614=(#9613=(#9612=(#9611=(#9610=(#9609=(#9608=(#9607=(#9606=(#9605=(#9604=(#4# . #5=(#9603=(#9602=(#9601=(#9600=(#9599=(#9598=(#9597=(#9596=(#9595=(#9594=(#9593=(#9592=(#9591=(#9590=(#9589=(#9588=(#9587=(#9586=(#9585=(#9584=(#9583=(#9582=(#9581=(#9580=(#9579=(#9578=(#9577=(#9576=(#9575=(#9574=(#9573=(#9572=(#9571=(#9570=(#9569=(#9568=(#9567=(#9566=(#9565=(#9564=(#9563=(#9562=(#9561=(#9560=(#9559=(#9558=(#9557=(#9556=(#9555=(#9554=(#9553=(#9552=(#9551=(#9550=(#9549=(#9548=(#9547=(#9546=(#9545=(#9544=(#9543=(#9542=(#9541=(#9540=(#9539=(#9538=(#9537=(#9536=(#9535=(#9534=(#9533=(#9532=(#9531=(#9530=(#9529=(#9528=(#9527=(#9526=(#9525=(#9524=(#9523=(#9522=(#9521=(#9520=(#9519=(#9518=(#9517=(#9516=(#9515=(#9514=(#9513=(#9512=(#9511=(#9510=(#9509=(#9508=(#9
\ No newline at end of file
--- /dev/null
+++ b/test/100x100.sl
@@ -1,0 +1,1 @@
+'#0=(#198=(#197=(#196=(#195=(#194=(#193=(#192=(#191=(#190=(#189=(#188=(#187=(#186=(#185=(#184=(#183=(#182=(#181=(#180=(#179=(#178=(#177=(#176=(#175=(#174=(#173=(#172=(#171=(#170=(#169=(#168=(#167=(#166=(#165=(#164=(#163=(#162=(#161=(#160=(#159=(#158=(#157=(#156=(#155=(#154=(#153=(#152=(#151=(#150=(#149=(#148=(#147=(#146=(#145=(#144=(#143=(#142=(#141=(#140=(#139=(#138=(#137=(#136=(#135=(#134=(#133=(#132=(#131=(#130=(#129=(#128=(#127=(#126=(#125=(#124=(#123=(#122=(#121=(#120=(#119=(#118=(#117=(#116=(#115=(#114=(#113=(#112=(#111=(#110=(#109=(#108=(#107=(#106=(#105=(#104=(#103=(#102=(#101=(#100=(#0# . #1=(#9999=(#9998=(#9997=(#9996=(#9995=(#9994=(#9993=(#9992=(#9991=(#9990=(#9989=(#9988=(#9987=(#9986=(#9985=(#9984=(#9983=(#9982=(#9981=(#9980=(#9979=(#9978=(#9977=(#9976=(#9975=(#9974=(#9973=(#9972=(#9971=(#9970=(#9969=(#9968=(#9967=(#9966=(#9965=(#9964=(#9963=(#9962=(#9961=(#9960=(#9959=(#9958=(#9957=(#9956=(#9955=(#9954=(#9953=(#9952=(#9951=(#9950=(#9949=(#9948=(#9947=(#9946=(#9945=(#9944=(#9943=(#9942=(#9941=(#9940=(#9939=(#9938=(#9937=(#9936=(#9935=(#9934=(#9933=(#9932=(#9931=(#9930=(#9929=(#9928=(#9927=(#9926=(#9925=(#9924=(#9923=(#9922=(#9921=(#9920=(#9919=(#9918=(#9917=(#9916=(#9915=(#9914=(#9913=(#9912=(#9911=(#9910=(#9909=(#9908=(#9907=(#9906=(#9905=(#9904=(#9903=(#9902=(#9901=(#1# . #2=(#9900=(#9899=(#9898=(#9897=(#9896=(#9895=(#9894=(#9893=(#9892=(#9891=(#9890=(#9889=(#9888=(#9887=(#9886=(#9885=(#9884=(#9883=(#9882=(#9881=(#9880=(#9879=(#9878=(#9877=(#9876=(#9875=(#9874=(#9873=(#9872=(#9871=(#9870=(#9869=(#9868=(#9867=(#9866=(#9865=(#9864=(#9863=(#9862=(#9861=(#9860=(#9859=(#9858=(#9857=(#9856=(#9855=(#9854=(#9853=(#9852=(#9851=(#9850=(#9849=(#9848=(#9847=(#9846=(#9845=(#9844=(#9843=(#9842=(#9841=(#9840=(#9839=(#9838=(#9837=(#9836=(#9835=(#9834=(#9833=(#9832=(#9831=(#9830=(#9829=(#9828=(#9827=(#9826=(#9825=(#9824=(#9823=(#9822=(#9821=(#9820=(#9819=(#9818=(#9817=(#9816=(#9815=(#9814=(#9813=(#9812=(#9811=(#9810=(#9809=(#9808=(#9807=(#9806=(#9805=(#9804=(#9803=(#9802=(#2# . #3=(#9801=(#9800=(#9799=(#9798=(#9797=(#9796=(#9795=(#9794=(#9793=(#9792=(#9791=(#9790=(#9789=(#9788=(#9787=(#9786=(#9785=(#9784=(#9783=(#9782=(#9781=(#9780=(#9779=(#9778=(#9777=(#9776=(#9775=(#9774=(#9773=(#9772=(#9771=(#9770=(#9769=(#9768=(#9767=(#9766=(#9765=(#9764=(#9763=(#9762=(#9761=(#9760=(#9759=(#9758=(#9757=(#9756=(#9755=(#9754=(#9753=(#9752=(#9751=(#9750=(#9749=(#9748=(#9747=(#9746=(#9745=(#9744=(#9743=(#9742=(#9741=(#9740=(#9739=(#9738=(#9737=(#9736=(#9735=(#9734=(#9733=(#9732=(#9731=(#9730=(#9729=(#9728=(#9727=(#9726=(#9725=(#9724=(#9723=(#9722=(#9721=(#9720=(#9719=(#9718=(#9717=(#9716=(#9715=(#9714=(#9713=(#9712=(#9711=(#9710=(#9709=(#9708=(#9707=(#9706=(#9705=(#9704=(#9703=(#3# . #4=(#9702=(#9701=(#9700=(#9699=(#9698=(#9697=(#9696=(#9695=(#9694=(#9693=(#9692=(#9691=(#9690=(#9689=(#9688=(#9687=(#9686=(#9685=(#9684=(#9683=(#9682=(#9681=(#9680=(#9679=(#9678=(#9677=(#9676=(#9675=(#9674=(#9673=(#9672=(#9671=(#9670=(#9669=(#9668=(#9667=(#9666=(#9665=(#9664=(#9663=(#9662=(#9661=(#9660=(#9659=(#9658=(#9657=(#9656=(#9655=(#9654=(#9653=(#9652=(#9651=(#9650=(#9649=(#9648=(#9647=(#9646=(#9645=(#9644=(#9643=(#9642=(#9641=(#9640=(#9639=(#9638=(#9637=(#9636=(#9635=(#9634=(#9633=(#9632=(#9631=(#9630=(#9629=(#9628=(#9627=(#9626=(#9625=(#9624=(#9623=(#9622=(#9621=(#9620=(#9619=(#9618=(#9617=(#9616=(#9615=(#9614=(#9613=(#9612=(#9611=(#9610=(#9609=(#9608=(#9607=(#9606=(#9605=(#9604=(#4# . #5=(#9603=(#9602=(#9601=(#9600=(#9599=(#9598=(#9597=(#9596=(#9595=(#9594=(#9593=(#9592=(#9591=(#9590=(#9589=(#9588=(#9587=(#9586=(#9585=(#9584=(#9583=(#9582=(#9581=(#9580=(#9579=(#9578=(#9577=(#9576=(#9575=(#9574=(#9573=(#9572=(#9571=(#9570=(#9569=(#9568=(#9567=(#9566=(#9565=(#9564=(#9563=(#9562=(#9561=(#9560=(#9559=(#9558=(#9557=(#9556=(#9555=(#9554=(#9553=(#9552=(#9551=(#9550=(#9549=(#9548=(#9547=(#9546=(#9545=(#9544=(#9543=(#9542=(#9541=(#9540=(#9539=(#9538=(#9537=(#9536=(#9535=(#9534=(#9533=(#9532=(#9531=(#9530=(#9529=(#9528=(#9527=(#9526=(#9525=(#9524=(#9523=(#9522=(#9521=(#9520=(#9519=(#9518=(#9517=(#9516=(#9515=(#9514=(#9513=(#9512=(#9511=(#9510=(#9509=(#9508=(#9
\ No newline at end of file
--- a/test/argv.lsp
+++ /dev/null
@@ -1,1 +1,0 @@
-(print *argv*) (princ "\n")
--- /dev/null
+++ b/test/argv.sl
@@ -1,0 +1,1 @@
+(print *argv*) (princ "\n")
--- a/test/ast/asttools.lsp
+++ /dev/null
@@ -1,167 +1,0 @@
-; utilities for AST processing
-
-(def (list-adjoin item lst)
- (if (member item lst)
- lst
- (cons item lst)))
-
-(def (index-of item lst start)
- (cond ((not lst) NIL)
- ((eq? item (car lst)) start)
- (else (index-of item (cdr lst) (+ start 1)))))
-
-(def (each f l)
- (if (not l) l
- (begin (f (car l))
- (each f (cdr l)))))
-
-(def (maptree-pre f tr)
- (let ((new-t (f tr)))
- (if (cons? new-t)
- (map (lambda (e) (maptree-pre f e)) new-t)
- new-t)))
-
-(def (maptree-post f tr)
- (if (not (cons? tr))
- (f tr)
- (let ((new-t (map (lambda (e) (maptree-post f e)) tr)))
- (f new-t))))
-
-(def (foldtree-pre f tr zero)
- (if (not (cons? tr))
- (f tr zero)
- (foldl tr (lambda (e state) (foldtree-pre f e state)) (f tr zero))))
-
-(def (foldtree-post f tr zero)
- (if (not (cons? tr))
- (f tr zero)
- (f tr (foldl tr (lambda (e state) (foldtree-post f e state)) zero))))
-
-; general tree transformer
-; folds in preorder (foldtree-pre), maps in postorder (maptree-post)
-; therefore state changes occur immediately, just by looking at the current node,
-; while transformation follows evaluation order. this seems to be the most natural
-; approach.
-; (mapper tree state) - should return transformed tree given current state
-; (folder tree state) - should return new state
-(def (map&fold tr zero mapper folder)
- (let ((head (and (cons? tr) (car tr))))
- (cond
- ((eq? head 'quote) tr)
- ((or (eq? head 'the) (eq? head 'meta))
- (list head
- (cadr tr)
- (map&fold (caddr tr) zero mapper folder)))
- (else
- (let ((new-s (folder tr zero)))
- (mapper
- (if (cons? tr)
- ; head symbol is a tag; never transform it
- (cons (car tr)
- (map (lambda (e) (map&fold e new-s mapper folder))
- (cdr tr)))
- tr)
- new-s))))))
-
-; convert to proper list, i.e. remove "dots", and append
-(def (append.2 l tail)
- (cond ((not l) tail)
- ((atom? l) (cons l tail))
- (else (cons (car l) (append.2 (cdr l) tail)))))
-
-; transform code by calling (f expr env) on each subexpr, where
-; env is a list of lexical variables in effect at that point.
-(def (lexical-walk f tr)
- (map&fold tr () f
- (lambda (tree state)
- (if (and (eq? (car tr) 'lambda)
- (cons? (cdr tr)))
- (append.2 (cadr tr) state)
- state))))
-
-; collapse forms like (&& (&& (&& (&& a b) c) d) e) to (&& a b c d e)
-(def (flatten-left-op op e)
- (maptree-post (lambda (node)
- (if (and (cons? node)
- (eq? (car node) op)
- (cons? (cdr node))
- (cons? (cadr node))
- (eq? (caadr node) op))
- (cons op
- (append (cdadr node) (cddr node)))
- node))
- e))
-
-; convert all local variable references to (lexref rib slot name)
-; where rib is the nesting level and slot is the stack slot#
-; name is just there for reference
-; this assumes lambda is the only remaining naming form
-(def (lookup-var v env lev)
- (if (not env) v
- (let ((i (index-of v (car env) 0)))
- (if i (list 'lexref lev i v)
- (lookup-var v (cdr env) (+ lev 1))))))
-(def (lvc- e env)
- (cond ((sym? e) (lookup-var e env 0))
- ((cons? e)
- (if (eq? (car e) 'quote)
- e
- (let* ((newvs (and (eq? (car e) 'lambda) (cadr e)))
- (newenv (if newvs (cons newvs env) env)))
- (if newvs
- (cons 'lambda
- (cons (cadr e)
- (map (lambda (se) (lvc- se newenv))
- (cddr e))))
- (map (lambda (se) (lvc- se env)) e)))))
- (else e)))
-(def (lexical-var-conversion e)
- (lvc- e ()))
-
-; convert let to lambda
-(def (let-expand e)
- (maptree-post (lambda (n)
- (if (and (cons? n) (eq? (car n) 'let))
- `((lambda ,(map car (cadr n)) ,@(cddr n))
- ,@(map cadr (cadr n)))
- n))
- e))
-
-; alpha renaming
-; transl is an assoc list ((old-sym-name . new-sym-name) ...)
-(def (alpha-rename e transl)
- (map&fold e
- ()
- ; mapper: replace symbol if unbound
- (lambda (te env)
- (if (sym? te)
- (let ((found (assq te transl)))
- (if (and found
- (not (memq te env)))
- (cdr found)
- te))
- te))
- ; folder: add locals to environment if entering a new scope
- (lambda (te env)
- (if (and (cons? te) (or (eq? (car te) 'let)
- (eq? (car te) 'lambda)))
- (append (cadr te) env)
- env))))
-
-; flatten op with any associativity
-(defmacro (flatten-all-op op e)
- `(pattern-expand
- (pattern-lambda (,op (-- l ...) (-- inner (,op ...)) (-- r ...))
- (cons ',op (append l (cdr inner) r)))
- ,e))
-
-(defmacro (pattern-lambda pat body)
- (let* ((args (patargs pat))
- (expander `(lambda ,args ,body)))
- `(lambda (expr)
- (let ((m (match ',pat expr)))
- (if m
- ; matches; perform expansion
- (apply ,expander (map (lambda (var) (cdr (or (assq var m) '(0 . NIL))))
- ',args))
- NIL)))))
--- /dev/null
+++ b/test/ast/asttools.sl
@@ -1,0 +1,167 @@
+; utilities for AST processing
+
+(def (list-adjoin item lst)
+ (if (member item lst)
+ lst
+ (cons item lst)))
+
+(def (index-of item lst start)
+ (cond ((not lst) NIL)
+ ((eq? item (car lst)) start)
+ (else (index-of item (cdr lst) (+ start 1)))))
+
+(def (each f l)
+ (if (not l) l
+ (begin (f (car l))
+ (each f (cdr l)))))
+
+(def (maptree-pre f tr)
+ (let ((new-t (f tr)))
+ (if (cons? new-t)
+ (map (lambda (e) (maptree-pre f e)) new-t)
+ new-t)))
+
+(def (maptree-post f tr)
+ (if (not (cons? tr))
+ (f tr)
+ (let ((new-t (map (lambda (e) (maptree-post f e)) tr)))
+ (f new-t))))
+
+(def (foldtree-pre f tr zero)
+ (if (not (cons? tr))
+ (f tr zero)
+ (foldl tr (lambda (e state) (foldtree-pre f e state)) (f tr zero))))
+
+(def (foldtree-post f tr zero)
+ (if (not (cons? tr))
+ (f tr zero)
+ (f tr (foldl tr (lambda (e state) (foldtree-post f e state)) zero))))
+
+; general tree transformer
+; folds in preorder (foldtree-pre), maps in postorder (maptree-post)
+; therefore state changes occur immediately, just by looking at the current node,
+; while transformation follows evaluation order. this seems to be the most natural
+; approach.
+; (mapper tree state) - should return transformed tree given current state
+; (folder tree state) - should return new state
+(def (map&fold tr zero mapper folder)
+ (let ((head (and (cons? tr) (car tr))))
+ (cond
+ ((eq? head 'quote) tr)
+ ((or (eq? head 'the) (eq? head 'meta))
+ (list head
+ (cadr tr)
+ (map&fold (caddr tr) zero mapper folder)))
+ (else
+ (let ((new-s (folder tr zero)))
+ (mapper
+ (if (cons? tr)
+ ; head symbol is a tag; never transform it
+ (cons (car tr)
+ (map (lambda (e) (map&fold e new-s mapper folder))
+ (cdr tr)))
+ tr)
+ new-s))))))
+
+; convert to proper list, i.e. remove "dots", and append
+(def (append.2 l tail)
+ (cond ((not l) tail)
+ ((atom? l) (cons l tail))
+ (else (cons (car l) (append.2 (cdr l) tail)))))
+
+; transform code by calling (f expr env) on each subexpr, where
+; env is a list of lexical variables in effect at that point.
+(def (lexical-walk f tr)
+ (map&fold tr () f
+ (lambda (tree state)
+ (if (and (eq? (car tr) 'lambda)
+ (cons? (cdr tr)))
+ (append.2 (cadr tr) state)
+ state))))
+
+; collapse forms like (&& (&& (&& (&& a b) c) d) e) to (&& a b c d e)
+(def (flatten-left-op op e)
+ (maptree-post (lambda (node)
+ (if (and (cons? node)
+ (eq? (car node) op)
+ (cons? (cdr node))
+ (cons? (cadr node))
+ (eq? (caadr node) op))
+ (cons op
+ (append (cdadr node) (cddr node)))
+ node))
+ e))
+
+; convert all local variable references to (lexref rib slot name)
+; where rib is the nesting level and slot is the stack slot#
+; name is just there for reference
+; this assumes lambda is the only remaining naming form
+(def (lookup-var v env lev)
+ (if (not env) v
+ (let ((i (index-of v (car env) 0)))
+ (if i (list 'lexref lev i v)
+ (lookup-var v (cdr env) (+ lev 1))))))
+(def (lvc- e env)
+ (cond ((sym? e) (lookup-var e env 0))
+ ((cons? e)
+ (if (eq? (car e) 'quote)
+ e
+ (let* ((newvs (and (eq? (car e) 'lambda) (cadr e)))
+ (newenv (if newvs (cons newvs env) env)))
+ (if newvs
+ (cons 'lambda
+ (cons (cadr e)
+ (map (lambda (se) (lvc- se newenv))
+ (cddr e))))
+ (map (lambda (se) (lvc- se env)) e)))))
+ (else e)))
+(def (lexical-var-conversion e)
+ (lvc- e ()))
+
+; convert let to lambda
+(def (let-expand e)
+ (maptree-post (lambda (n)
+ (if (and (cons? n) (eq? (car n) 'let))
+ `((lambda ,(map car (cadr n)) ,@(cddr n))
+ ,@(map cadr (cadr n)))
+ n))
+ e))
+
+; alpha renaming
+; transl is an assoc list ((old-sym-name . new-sym-name) ...)
+(def (alpha-rename e transl)
+ (map&fold e
+ ()
+ ; mapper: replace symbol if unbound
+ (lambda (te env)
+ (if (sym? te)
+ (let ((found (assq te transl)))
+ (if (and found
+ (not (memq te env)))
+ (cdr found)
+ te))
+ te))
+ ; folder: add locals to environment if entering a new scope
+ (lambda (te env)
+ (if (and (cons? te) (or (eq? (car te) 'let)
+ (eq? (car te) 'lambda)))
+ (append (cadr te) env)
+ env))))
+
+; flatten op with any associativity
+(defmacro (flatten-all-op op e)
+ `(pattern-expand
+ (pattern-lambda (,op (-- l ...) (-- inner (,op ...)) (-- r ...))
+ (cons ',op (append l (cdr inner) r)))
+ ,e))
+
+(defmacro (pattern-lambda pat body)
+ (let* ((args (patargs pat))
+ (expander `(lambda ,args ,body)))
+ `(lambda (expr)
+ (let ((m (match ',pat expr)))
+ (if m
+ ; matches; perform expansion
+ (apply ,expander (map (lambda (var) (cdr (or (assq var m) '(0 . NIL))))
+ ',args))
+ NIL)))))
--- a/test/ast/datetimeR.lsp
+++ /dev/null
@@ -1,79 +1,0 @@
-'(r-expressions
- (<- Sys.time (function () (r-call structure (r-call .Internal (r-call Sys.time)) (*named* class (r-call c "POSIXt" "POSIXct"))) ()))
- (<- Sys.timezone (function () (r-call as.vector (r-call Sys.getenv "TZ")) ()))
- (<- as.POSIXlt (function ((*named* x *r-missing*) (*named* tz "")) (r-block (<- fromchar (function ((*named* x *r-missing*)) (r-block (<- xx (r-call r-index x 1)) (if (r-call is.na xx) (r-block (<- j 1) (while (&& (r-call is.na xx) (r-call <= (<- j (r-call + j 1)) (r-call length x))) (<- xx (r-call r-index x j))) (if (r-call is.na xx) (<- f "%Y-%m-%d")))) (if (\|\| (\|\| (\|\| (\|\| (\|\| (\|\| (r-call is.na xx) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y-%m-%d %H:%M:%OS"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y/%m/%d %H:%M:%OS"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y-%m-%d %H:%M"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y/%m/%d %H:%M"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y-%m-%d"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y/%m/%d"))))) (r-block (<- res (r-call strptime x f)) (if (r-call nchar tz) (<- (r-call attr res "tzone") tz)) (return res))) (r-call stop "character string is not in a standard unambiguous format")) ())) (if (r-call inherits x "POSIXlt") (return x)) (if (r-call inherits x "Date") (return (r-call .Internal (r-call Date2POSIXlt x)))) (<- tzone (r-call attr x "tzone")) (if (\|\| (r-call inherits x "date") (r-call inherits x "dates")) (<- x (r-call as.POSIXct x))) (if (r-call is.character x) (return (r-call fromchar (r-call unclass x)))) (if (r-call is.factor x) (return (r-call fromchar (r-call as.character x)))) (if (&& (r-call is.logical x) (r-call all (r-call is.na x))) (<- x (r-call as.POSIXct.default x))) (if (r-call ! (r-call inherits x "POSIXct")) (r-call stop (r-call gettextf "do not know how to convert '%s' to class \"POSIXlt\"" (r-call deparse (substitute x))))) (if (&& (missing tz) (r-call ! (r-call is.null tzone))) (<- tz (r-call r-index tzone 1))) (r-call .Internal (r-call as.POSIXlt x tz))) ()))
- (<- as.POSIXct (function ((*named* x *r-missing*) (*named* tz "")) (r-call UseMethod "as.POSIXct") ()))
- (<- as.POSIXct.Date (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call structure (r-call * (r-call unclass x) 86400) (*named* class (r-call c "POSIXt" "POSIXct"))) ()))
- (<- as.POSIXct.date (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (if (r-call inherits x "date") (r-block (<- x (r-call * (r-call - x 3653) 86400)) (return (r-call structure x (*named* class (r-call c "POSIXt" "POSIXct"))))) (r-call stop (r-call gettextf "'%s' is not a \"date\" object" (r-call deparse (substitute x)))))) ()))
- (<- as.POSIXct.dates (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (if (r-call inherits x "dates") (r-block (<- z (r-call attr x "origin")) (<- x (r-call * (r-call as.numeric x) 86400)) (if (&& (r-call == (r-call length z) 3) (r-call is.numeric z)) (<- x (r-call + x (r-call as.numeric (r-call ISOdate (r-call r-index z 3) (r-call r-index z 1) (r-call r-index z 2) 0))))) (return (r-call structure x (*named* class (r-call c "POSIXt" "POSIXct"))))) (r-call stop (r-call gettextf "'%s' is not a \"dates\" object" (r-call deparse (substitute x)))))) ()))
- (<- as.POSIXct.POSIXlt (function ((*named* x *r-missing*) (*named* tz "")) (r-block (<- tzone (r-call attr x "tzone")) (if (&& (missing tz) (r-call ! (r-call is.null tzone))) (<- tz (r-call r-index tzone 1))) (r-call structure (r-call .Internal (r-call as.POSIXct x tz)) (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone tz))) ()))
- (<- as.POSIXct.default (function ((*named* x *r-missing*) (*named* tz "")) (r-block (if (r-call inherits x "POSIXct") (return x)) (if (\|\| (r-call is.character x) (r-call is.factor x)) (return (r-call as.POSIXct (r-call as.POSIXlt x) tz))) (if (&& (r-call is.logical x) (r-call all (r-call is.na x))) (return (r-call structure (r-call as.numeric x) (*named* class (r-call c "POSIXt" "POSIXct"))))) (r-call stop (r-call gettextf "do not know how to convert '%s' to class \"POSIXlt\"" (r-call deparse (substitute x))))) ()))
- (<- as.numeric.POSIXlt (function ((*named* x *r-missing*)) (r-call as.POSIXct x) ()))
- (<- format.POSIXlt (function ((*named* x *r-missing*) (*named* format "") (*named* usetz *r-false*) (*named* ... *r-missing*)) (r-block (if (r-call ! (r-call inherits x "POSIXlt")) (r-call stop "wrong class")) (if (r-call == format "") (r-block (<- times (r-call unlist (r-call r-index (r-call unclass x) (r-call : 1 3)))) (<- secs ($ x sec)) (<- secs (r-call r-index secs (r-call ! (r-call is.na secs)))) (<- np (r-call getOption "digits.secs")) (if (r-call is.null np) (<- np 0) (<- np (r-call min 6 np))) (if (r-call >= np 1) (r-block (for i (r-call - (r-call : 1 np) 1) (if (r-call all (r-call < (r-call abs (r-call - secs (r-call round secs i))) 1e-06)) (r-block (<- np i) (break)))))) (<- format (if (r-call all (r-call == (r-call r-index times (r-call ! (r-call is.na times))) 0)) "%Y-%m-%d" (if (r-call == np 0) "%Y-%m-%d %H:%M:%S" (r-call paste "%Y-%m-%d %H:%M:%OS" np (*named* sep ""))))))) (r-call .Internal (r-call format.POSIXlt x format usetz))) ()))
- (<- strftime format.POSIXlt)
- (<- strptime (function ((*named* x *r-missing*) (*named* format *r-missing*) (*named* tz "")) (r-call .Internal (r-call strptime (r-call as.character x) format tz)) ()))
- (<- format.POSIXct (function ((*named* x *r-missing*) (*named* format "") (*named* tz "") (*named* usetz *r-false*) (*named* ... *r-missing*)) (r-block (if (r-call ! (r-call inherits x "POSIXct")) (r-call stop "wrong class")) (if (&& (missing tz) (r-call ! (r-call is.null (<- tzone (r-call attr x "tzone"))))) (<- tz tzone)) (r-call structure (r-call format.POSIXlt (r-call as.POSIXlt x tz) format usetz r-dotdotdot) (*named* names (r-call names x)))) ()))
- (<- print.POSIXct (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call print (r-call format x (*named* usetz *r-true*) r-dotdotdot) r-dotdotdot) (r-call invisible x)) ()))
- (<- print.POSIXlt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call print (r-call format x (*named* usetz *r-true*)) r-dotdotdot) (r-call invisible x)) ()))
- (<- summary.POSIXct (function ((*named* object *r-missing*) (*named* digits 15) (*named* ... *r-missing*)) (r-block (<- x (r-call r-index (r-call summary.default (r-call unclass object) (*named* digits digits) r-dotdotdot) (r-call : 1 6))) (<- (r-call class x) (r-call oldClass object)) (<- (r-call attr x "tzone") (r-call attr object "tzone")) x) ()))
- (<- summary.POSIXlt (function ((*named* object *r-missing*) (*named* digits 15) (*named* ... *r-missing*)) (r-call summary (r-call as.POSIXct object) (*named* digits digits) r-dotdotdot) ()))
- (<- "+.POSIXt" (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x)))) ())) (if (r-call == (r-call nargs) 1) (return e1)) (if (&& (r-call inherits e1 "POSIXt") (r-call inherits e2 "POSIXt")) (r-call stop "binary + is not defined for \"POSIXt\" objects")) (if (r-call inherits e1 "POSIXlt") (<- e1 (r-call as.POSIXct e1))) (if (r-call inherits e2 "POSIXlt") (<- e2 (r-call as.POSIXct e2))) (if (r-call inherits e1 "difftime") (<- e1 (r-call coerceTimeUnit e1))) (if (r-call inherits e2 "difftime") (<- e2 (r-call coerceTimeUnit e2))) (r-call structure (r-call + (r-call unclass e1) (r-call unclass e2)) (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone (r-call check_tzones e1 e2)))) ()))
- (<- "-.POSIXt" (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x)))) ())) (if (r-call ! (r-call inherits e1 "POSIXt")) (r-call stop "Can only subtract from POSIXt objects")) (if (r-call == (r-call nargs) 1) (r-call stop "unary - is not defined for \"POSIXt\" objects")) (if (r-call inherits e2 "POSIXt") (return (r-call difftime e1 e2))) (if (r-call inherits e2 "difftime") (<- e2 (r-call unclass (r-call coerceTimeUnit e2)))) (if (r-call ! (r-call is.null (r-call attr e2 "class"))) (r-call stop "can only subtract numbers from POSIXt objects")) (r-call structure (r-call - (r-call unclass (r-call as.POSIXct e1)) e2) (*named* class (r-call c "POSIXt" "POSIXct")))) ()))
- (<- Ops.POSIXt (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (if (r-call == (r-call nargs) 1) (r-call stop "unary" .Generic " not defined for \"POSIXt\" objects")) (<- boolean (switch .Generic (*named* < *r-missing*) (*named* > *r-missing*) (*named* == *r-missing*) (*named* != *r-missing*) (*named* <= *r-missing*) (*named* >= *r-true*) *r-false*)) (if (r-call ! boolean) (r-call stop .Generic " not defined for \"POSIXt\" objects")) (if (\|\| (r-call inherits e1 "POSIXlt") (r-call is.character e1)) (<- e1 (r-call as.POSIXct e1))) (if (\|\| (r-call inherits e2 "POSIXlt") (r-call is.character e1)) (<- e2 (r-call as.POSIXct e2))) (r-call check_tzones e1 e2) (r-call NextMethod .Generic)) ()))
- (<- Math.POSIXt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call stop .Generic " not defined for POSIXt objects")) ()))
- (<- check_tzones (function ((*named* ... *r-missing*)) (r-block (<- tzs (r-call unique (r-call sapply (r-call list r-dotdotdot) (function ((*named* x *r-missing*)) (r-block (<- y (r-call attr x "tzone")) (if (r-call is.null y) "" y)) ())))) (<- tzs (r-call r-index tzs (r-call != tzs ""))) (if (r-call > (r-call length tzs) 1) (r-call warning "'tzone' attributes are inconsistent")) (if (r-call length tzs) (r-call r-index tzs 1) ())) ()))
- (<- Summary.POSIXct (function ((*named* ... *r-missing*) (*named* na.rm *r-missing*)) (r-block (<- ok (switch .Generic (*named* max *r-missing*) (*named* min *r-missing*) (*named* range *r-true*) *r-false*)) (if (r-call ! ok) (r-call stop .Generic " not defined for \"POSIXct\" objects")) (<- args (r-call list r-dotdotdot)) (<- tz (r-call do.call "check_tzones" args)) (<- val (r-call NextMethod .Generic)) (<- (r-call class val) (r-call oldClass (r-call r-aref args 1))) (<- (r-call attr val "tzone") tz) val) ()))
- (<- Summary.POSIXlt (function ((*named* ... *r-missing*) (*named* na.rm *r-missing*)) (r-block (<- ok (switch .Generic (*named* max *r-missing*) (*named* min *r-missing*) (*named* range *r-true*) *r-false*)) (if (r-call ! ok) (r-call stop .Generic " not defined for \"POSIXlt\" objects")) (<- args (r-call list r-dotdotdot)) (<- tz (r-call do.call "check_tzones" args)) (<- args (r-call lapply args as.POSIXct)) (<- val (r-call do.call .Generic (r-call c args (*named* na.rm na.rm)))) (r-call as.POSIXlt (r-call structure val (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone tz)))) ()))
- (<- "[.POSIXct" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* drop *r-true*)) (r-block (<- cl (r-call oldClass x)) (<- (r-call class x) ()) (<- val (r-call NextMethod "[")) (<- (r-call class val) cl) (<- (r-call attr val "tzone") (r-call attr x "tzone")) val) ()))
- (<- "[[.POSIXct" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* drop *r-true*)) (r-block (<- cl (r-call oldClass x)) (<- (r-call class x) ()) (<- val (r-call NextMethod "[[")) (<- (r-call class val) cl) (<- (r-call attr val "tzone") (r-call attr x "tzone")) val) ()))
- (<- "[<-.POSIXct" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* value *r-missing*)) (r-block (if (r-call ! (r-call as.logical (r-call length value))) (return x)) (<- value (r-call as.POSIXct value)) (<- cl (r-call oldClass x)) (<- tz (r-call attr x "tzone")) (<- (r-call class x) (<- (r-call class value) ())) (<- x (r-call NextMethod .Generic)) (<- (r-call class x) cl) (<- (r-call attr x "tzone") tz) x) ()))
- (<- as.character.POSIXt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call format x r-dotdotdot) ()))
- (<- as.data.frame.POSIXct as.data.frame.vector)
- (<- is.na.POSIXlt (function ((*named* x *r-missing*)) (r-call is.na (r-call as.POSIXct x)) ()))
- (<- c.POSIXct (function ((*named* ... *r-missing*) (*named* recursive *r-false*)) (r-call structure (r-call c (r-call unlist (r-call lapply (r-call list r-dotdotdot) unclass))) (*named* class (r-call c "POSIXt" "POSIXct"))) ()))
- (<- c.POSIXlt (function ((*named* ... *r-missing*) (*named* recursive *r-false*)) (r-call as.POSIXlt (r-call do.call "c" (r-call lapply (r-call list r-dotdotdot) as.POSIXct))) ()))
- (<- all.equal.POSIXct (function ((*named* target *r-missing*) (*named* current *r-missing*) (*named* ... *r-missing*) (*named* scale 1)) (r-block (r-call check_tzones target current) (r-call NextMethod "all.equal")) ()))
- (<- ISOdatetime (function ((*named* year *r-missing*) (*named* month *r-missing*) (*named* day *r-missing*) (*named* hour *r-missing*) (*named* min *r-missing*) (*named* sec *r-missing*) (*named* tz "")) (r-block (<- x (r-call paste year month day hour min sec (*named* sep "-"))) (r-call as.POSIXct (r-call strptime x "%Y-%m-%d-%H-%M-%OS" (*named* tz tz)) (*named* tz tz))) ()))
- (<- ISOdate (function ((*named* year *r-missing*) (*named* month *r-missing*) (*named* day *r-missing*) (*named* hour 12) (*named* min 0) (*named* sec 0) (*named* tz "GMT")) (r-call ISOdatetime year month day hour min sec tz) ()))
- (<- as.matrix.POSIXlt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call as.matrix (r-call as.data.frame (r-call unclass x)) r-dotdotdot)) ()))
- (<- mean.POSIXct (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call structure (r-call mean (r-call unclass x) r-dotdotdot) (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone (r-call attr x "tzone"))) ()))
- (<- mean.POSIXlt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call as.POSIXlt (r-call mean (r-call as.POSIXct x) r-dotdotdot)) ()))
- (<- difftime (function ((*named* time1 *r-missing*) (*named* time2 *r-missing*) (*named* tz "") (*named* units (r-call c "auto" "secs" "mins" "hours" "days" "weeks"))) (r-block (<- time1 (r-call as.POSIXct time1 (*named* tz tz))) (<- time2 (r-call as.POSIXct time2 (*named* tz tz))) (<- z (r-call - (r-call unclass time1) (r-call unclass time2))) (<- units (r-call match.arg units)) (if (r-call == units "auto") (r-block (if (r-call all (r-call is.na z)) (<- units "secs") (r-block (<- zz (r-call min (r-call abs z) (*named* na.rm *r-true*))) (if (\|\| (r-call is.na zz) (r-call < zz 60)) (<- units "secs") (if (r-call < zz 3600) (<- units "mins") (if (r-call < zz 86400) (<- units "hours") (<- units "days")))))))) (switch units (*named* secs (r-call structure z (*named* units "secs") (*named* class "difftime"))) (*named* mins (r-call structure (r-call / z 60) (*named* units "mins") (*named* class "difftime"))) (*named* hours (r-call structure (r-call / z 3600) (*named* units "hours") (*named* class "difftime"))) (*named* days (r-call structure (r-call / z 86400) (*named* units "days") (*named* class "difftime"))) (*named* weeks (r-call structure (r-call / z (r-call * 7 86400)) (*named* units "weeks") (*named* class "difftime"))))) ()))
- (<- as.difftime (function ((*named* tim *r-missing*) (*named* format "%X") (*named* units "auto")) (r-block (if (r-call inherits tim "difftime") (return tim)) (if (r-call is.character tim) (r-block (r-call difftime (r-call strptime tim (*named* format format)) (r-call strptime "0:0:0" (*named* format "%X")) (*named* units units))) (r-block (if (r-call ! (r-call is.numeric tim)) (r-call stop "'tim' is not character or numeric")) (if (r-call == units "auto") (r-call stop "need explicit units for numeric conversion")) (if (r-call ! (r-call %in% units (r-call c "secs" "mins" "hours" "days" "weeks"))) (r-call stop "invalid units specified")) (r-call structure tim (*named* units units) (*named* class "difftime"))))) ()))
- (<- units (function ((*named* x *r-missing*)) (r-call UseMethod "units") ()))
- (<- "units<-" (function ((*named* x *r-missing*) (*named* value *r-missing*)) (r-call UseMethod "units<-") ()))
- (<- units.difftime (function ((*named* x *r-missing*)) (r-call attr x "units") ()))
- (<- "units<-.difftime" (function ((*named* x *r-missing*) (*named* value *r-missing*)) (r-block (<- from (r-call units x)) (if (r-call == from value) (return x)) (if (r-call ! (r-call %in% value (r-call c "secs" "mins" "hours" "days" "weeks"))) (r-call stop "invalid units specified")) (<- sc (r-call cumprod (r-call c (*named* secs 1) (*named* mins 60) (*named* hours 60) (*named* days 24) (*named* weeks 7)))) (<- newx (r-call / (r-call * (r-call as.vector x) (r-call r-index sc from)) (r-call r-index sc value))) (r-call structure newx (*named* units value) (*named* class "difftime"))) ()))
- (<- as.double.difftime (function ((*named* x *r-missing*) (*named* units "auto") (*named* ... *r-missing*)) (r-block (if (r-call != units "auto") (<- (r-call units x) units)) (r-call as.double (r-call as.vector x))) ()))
- (<- as.data.frame.difftime as.data.frame.vector)
- (<- format.difftime (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call paste (r-call format (r-call unclass x) r-dotdotdot) (r-call units x)) ()))
- (<- print.difftime (function ((*named* x *r-missing*) (*named* digits (r-call getOption "digits")) (*named* ... *r-missing*)) (r-block (if (\|\| (r-call is.array x) (r-call > (r-call length x) 1)) (r-block (r-call cat "Time differences in " (r-call attr x "units") "\n" (*named* sep "")) (<- y (r-call unclass x)) (<- (r-call attr y "units") ()) (r-call print y)) (r-call cat "Time difference of " (r-call format (r-call unclass x) (*named* digits digits)) " " (r-call attr x "units") "\n" (*named* sep ""))) (r-call invisible x)) ()))
- (<- round.difftime (function ((*named* x *r-missing*) (*named* digits 0) (*named* ... *r-missing*)) (r-block (<- units (r-call attr x "units")) (r-call structure (r-call NextMethod) (*named* units units) (*named* class "difftime"))) ()))
- (<- "[.difftime" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* drop *r-true*)) (r-block (<- cl (r-call oldClass x)) (<- (r-call class x) ()) (<- val (r-call NextMethod "[")) (<- (r-call class val) cl) (<- (r-call attr val "units") (r-call attr x "units")) val) ()))
- (<- Ops.difftime (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x)))) ())) (if (r-call == (r-call nargs) 1) (r-block (switch .Generic (*named* + (r-block)) (*named* - (r-block (<- (r-call r-index e1 *r-missing*) (r-call - (r-call unclass e1))))) (r-call stop "unary" .Generic " not defined for \"difftime\" objects")) (return e1))) (<- boolean (switch .Generic (*named* < *r-missing*) (*named* > *r-missing*) (*named* == *r-missing*) (*named* != *r-missing*) (*named* <= *r-missing*) (*named* >= *r-true*) *r-false*)) (if boolean (r-block (if (&& (r-call inherits e1 "difftime") (r-call inherits e2 "difftime")) (r-block (<- e1 (r-call coerceTimeUnit e1)) (<- e2 (r-call coerceTimeUnit e2)))) (r-call NextMethod .Generic)) (if (\|\| (r-call == .Generic "+") (r-call == .Generic "-")) (r-block (if (&& (r-call inherits e1 "difftime") (r-call ! (r-call inherits e2 "difftime"))) (return (r-call structure (r-call NextMethod .Generic) (*named* units (r-call attr e1 "units")) (*named* class "difftime")))) (if (&& (r-call ! (r-call inherits e1 "difftime")) (r-call inherits e2 "difftime")) (return (r-call structure (r-call NextMethod .Generic) (*named* units (r-call attr e2 "units")) (*named* class "difftime")))) (<- u1 (r-call attr e1 "units")) (if (r-call == (r-call attr e2 "units") u1) (r-block (r-call structure (r-call NextMethod .Generic) (*named* units u1) (*named* class "difftime"))) (r-block (<- e1 (r-call coerceTimeUnit e1)) (<- e2 (r-call coerceTimeUnit e2)) (r-call structure (r-call NextMethod .Generic) (*named* units "secs") (*named* class "difftime"))))) (r-block (r-call stop .Generic "not defined for \"difftime\" objects"))))) ()))
- (<- "*.difftime" (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (if (&& (r-call inherits e1 "difftime") (r-call inherits e2 "difftime")) (r-call stop "both arguments of * cannot be \"difftime\" objects")) (if (r-call inherits e2 "difftime") (r-block (<- tmp e1) (<- e1 e2) (<- e2 tmp))) (r-call structure (r-call * e2 (r-call unclass e1)) (*named* units (r-call attr e1 "units")) (*named* class "difftime"))) ()))
- (<- "/.difftime" (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (if (r-call inherits e2 "difftime") (r-call stop "second argument of / cannot be a \"difftime\" object")) (r-call structure (r-call / (r-call unclass e1) e2) (*named* units (r-call attr e1 "units")) (*named* class "difftime"))) ()))
- (<- Math.difftime (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call stop .Generic "not defined for \"difftime\" objects")) ()))
- (<- mean.difftime (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* na.rm *r-false*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (r-call as.vector (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x))))) ())) (if (r-call length (r-call list r-dotdotdot)) (r-block (<- args (r-call c (r-call lapply (r-call list x r-dotdotdot) coerceTimeUnit) (*named* na.rm na.rm))) (r-call structure (r-call do.call "mean" args) (*named* units "secs") (*named* class "difftime"))) (r-block (r-call structure (r-call mean (r-call as.vector x) (*named* na.rm na.rm)) (*named* units (r-call attr x "units")) (*named* class "difftime"))))) ()))
- (<- Summary.difftime (function ((*named* ... *r-missing*) (*named* na.rm *r-missing*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (r-call as.vector (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x))))) ())) (<- ok (switch .Generic (*named* max *r-missing*) (*named* min *r-missing*) (*named* range *r-true*) *r-false*)) (if (r-call ! ok) (r-call stop .Generic " not defined for \"difftime\" objects")) (<- args (r-call c (r-call lapply (r-call list r-dotdotdot) coerceTimeUnit) (*named* na.rm na.rm))) (r-call structure (r-call do.call .Generic args) (*named* units "secs") (*named* class "difftime"))) ()))
- (<- seq.POSIXt (function ((*named* from *r-missing*) (*named* to *r-missing*) (*named* by *r-missing*) (*named* length.out ()) (*named* along.with ()) (*named* ... *r-missing*)) (r-block (if (missing from) (r-call stop "'from' must be specified")) (if (r-call ! (r-call inherits from "POSIXt")) (r-call stop "'from' must be a POSIXt object")) (<- cfrom (r-call as.POSIXct from)) (if (r-call != (r-call length cfrom) 1) (r-call stop "'from' must be of length 1")) (<- tz (r-call attr cfrom "tzone")) (if (r-call ! (missing to)) (r-block (if (r-call ! (r-call inherits to "POSIXt")) (r-call stop "'to' must be a POSIXt object")) (if (r-call != (r-call length (r-call as.POSIXct to)) 1) (r-call stop "'to' must be of length 1")))) (if (r-call ! (missing along.with)) (r-block (<- length.out (r-call length along.with))) (if (r-call ! (r-call is.null length.out)) (r-block (if (r-call != (r-call length length.out) 1) (r-call stop "'length.out' must be of length 1")) (<- length.out (r-call ceiling length.out))))) (<- status (r-call c (r-call ! (missing to)) (r-call ! (missing by)) (r-call ! (r-call is.null length.out)))) (if (r-call != (r-call sum status) 2) (r-call stop "exactly two of 'to', 'by' and 'length.out' / 'along.with' must be specified")) (if (missing by) (r-block (<- from (r-call unclass cfrom)) (<- to (r-call unclass (r-call as.POSIXct to))) (<- res (r-call seq.int from to (*named* length.out length.out))) (return (r-call structure res (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone tz))))) (if (r-call != (r-call length by) 1) (r-call stop "'by' must be of length 1")) (<- valid 0) (if (r-call inherits by "difftime") (r-block (<- by (r-call * (switch (r-call attr by "units") (*named* secs 1) (*named* mins 60) (*named* hours 3600) (*named* days 86400) (*named* weeks (r-call * 7 86400))) (r-call unclass by)))) (if (r-call is.character by) (r-block (<- by2 (r-call r-aref (r-call strsplit by " " (*named* fixed *r-true*)) 1)) (if (\|\| (r-call > (r-call length by2) 2) (r-call < (r-call length by2) 1)) (r-call stop "invalid 'by' string")) (<- valid (r-call pmatch (r-call r-index by2 (r-call length by2)) (r-call c "secs" "mins" "hours" "days" "weeks" "months" "years" "DSTdays"))) (if (r-call is.na valid) (r-call stop "invalid string for 'by'")) (if (r-call <= valid 5) (r-block (<- by (r-call r-index (r-call c 1 60 3600 86400 (r-call * 7 86400)) valid)) (if (r-call == (r-call length by2) 2) (<- by (r-call * by (r-call as.integer (r-call r-index by2 1)))))) (<- by (if (r-call == (r-call length by2) 2) (r-call as.integer (r-call r-index by2 1)) 1)))) (if (r-call ! (r-call is.numeric by)) (r-call stop "invalid mode for 'by'")))) (if (r-call is.na by) (r-call stop "'by' is NA")) (if (r-call <= valid 5) (r-block (<- from (r-call unclass (r-call as.POSIXct from))) (if (r-call ! (r-call is.null length.out)) (<- res (r-call seq.int from (*named* by by) (*named* length.out length.out))) (r-block (<- to (r-call unclass (r-call as.POSIXct to))) (<- res (r-call + (r-call seq.int 0 (r-call - to from) by) from)))) (return (r-call structure res (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone tz)))) (r-block (<- r1 (r-call as.POSIXlt from)) (if (r-call == valid 7) (r-block (if (missing to) (r-block (<- yr (r-call seq.int ($ r1 year) (*named* by by) (*named* length length.out)))) (r-block (<- to (r-call as.POSIXlt to)) (<- yr (r-call seq.int ($ r1 year) ($ to year) by)))) (<- ($ r1 year) yr) (<- ($ r1 isdst) (r-call - 1)) (<- res (r-call as.POSIXct r1))) (if (r-call == valid 6) (r-block (if (missing to) (r-block (<- mon (r-call seq.int ($ r1 mon) (*named* by by) (*named* length length.out)))) (r-block (<- to (r-call as.POSIXlt to)) (<- mon (r-call seq.int ($ r1 mon) (r-call + (r-call * 12 (r-call - ($ to year) ($ r1 year))) ($ to mon)) by)))) (<- ($ r1 mon) mon) (<- ($ r1 isdst) (r-call - 1)) (<- res (r-call as.POSIXct r1))) (if (r-call == valid 8) (r-block (if (r-call ! (missing to)) (r-block (<- length.out (r-call + 2 (r-call floor (r-call / (r-call - (r-call unclass (r-call as.POSIXct to)) (r-call unclass (r-call as.POSI
\ No newline at end of file
- (<- cut.POSIXt (function ((*named* x *r-missing*) (*named* breaks *r-missing*) (*named* labels ()) (*named* start.on.monday *r-true*) (*named* right *r-false*) (*named* ... *r-missing*)) (r-block (if (r-call ! (r-call inherits x "POSIXt")) (r-call stop "'x' must be a date-time object")) (<- x (r-call as.POSIXct x)) (if (r-call inherits breaks "POSIXt") (r-block (<- breaks (r-call as.POSIXct breaks))) (if (&& (r-call is.numeric breaks) (r-call == (r-call length breaks) 1)) (r-block) (if (&& (r-call is.character breaks) (r-call == (r-call length breaks) 1)) (r-block (<- by2 (r-call r-aref (r-call strsplit breaks " " (*named* fixed *r-true*)) 1)) (if (\|\| (r-call > (r-call length by2) 2) (r-call < (r-call length by2) 1)) (r-call stop "invalid specification of 'breaks'")) (<- valid (r-call pmatch (r-call r-index by2 (r-call length by2)) (r-call c "secs" "mins" "hours" "days" "weeks" "months" "years" "DSTdays"))) (if (r-call is.na valid) (r-call stop "invalid specification of 'breaks'")) (<- start (r-call as.POSIXlt (r-call min x (*named* na.rm *r-true*)))) (<- incr 1) (if (r-call > valid 1) (r-block (<- ($ start sec) 0) (<- incr 59.99))) (if (r-call > valid 2) (r-block (<- ($ start min) 0) (<- incr (r-call - 3600 1)))) (if (r-call > valid 3) (r-block (<- ($ start hour) 0) (<- incr (r-call - 86400 1)))) (if (r-call == valid 5) (r-block (<- ($ start mday) (r-call - ($ start mday) ($ start wday))) (if start.on.monday (<- ($ start mday) (r-call + ($ start mday) (r-call ifelse (r-call > ($ start wday) 0) 1 (r-call - 6))))) (<- incr (r-call * 7 86400)))) (if (r-call == valid 6) (r-block (<- ($ start mday) 1) (<- incr (r-call * 31 86400)))) (if (r-call == valid 7) (r-block (<- ($ start mon) 0) (<- ($ start mday) 1) (<- incr (r-call * 366 86400)))) (if (r-call == valid 8) (<- incr (r-call * 25 3600))) (if (r-call == (r-call length by2) 2) (<- incr (r-call * incr (r-call as.integer (r-call r-index by2 1))))) (<- maxx (r-call max x (*named* na.rm *r-true*))) (<- breaks (r-call seq.int start (r-call + maxx incr) breaks)) (<- breaks (r-call r-index breaks (r-call : 1 (r-call + 1 (r-call max (r-call which (r-call < breaks maxx)))))))) (r-call stop "invalid specification of 'breaks'")))) (<- res (r-call cut (r-call unclass x) (r-call unclass breaks) (*named* labels labels) (*named* right right) r-dotdotdot)) (if (r-call is.null labels) (<- (r-call levels res) (r-call as.character (r-call r-index breaks (r-call - (r-call length breaks)))))) res) ()))
- (<- julian (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call UseMethod "julian") ()))
- (<- julian.POSIXt (function ((*named* x *r-missing*) (*named* origin (r-call as.POSIXct "1970-01-01" (*named* tz "GMT"))) (*named* ... *r-missing*)) (r-block (if (r-call != (r-call length origin) 1) (r-call stop "'origin' must be of length one")) (<- res (r-call difftime (r-call as.POSIXct x) origin (*named* units "days"))) (r-call structure res (*named* origin origin))) ()))
- (<- weekdays (function ((*named* x *r-missing*) (*named* abbreviate *r-missing*)) (r-call UseMethod "weekdays") ()))
- (<- weekdays.POSIXt (function ((*named* x *r-missing*) (*named* abbreviate *r-false*)) (r-block (r-call format x (r-call ifelse abbreviate "%a" "%A"))) ()))
- (<- months (function ((*named* x *r-missing*) (*named* abbreviate *r-missing*)) (r-call UseMethod "months") ()))
- (<- months.POSIXt (function ((*named* x *r-missing*) (*named* abbreviate *r-false*)) (r-block (r-call format x (r-call ifelse abbreviate "%b" "%B"))) ()))
- (<- quarters (function ((*named* x *r-missing*) (*named* abbreviate *r-missing*)) (r-call UseMethod "quarters") ()))
- (<- quarters.POSIXt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (<- x (r-call %/% ($ (r-call as.POSIXlt x) mon) 3)) (r-call paste "Q" (r-call + x 1) (*named* sep ""))) ()))
- (<- trunc.POSIXt (function ((*named* x *r-missing*) (*named* units (r-call c "secs" "mins" "hours" "days"))) (r-block (<- units (r-call match.arg units)) (<- x (r-call as.POSIXlt x)) (if (r-call > (r-call length ($ x sec)) 0) (switch units (*named* secs (r-block (<- ($ x sec) (r-call trunc ($ x sec))))) (*named* mins (r-block (<- ($ x sec) 0))) (*named* hours (r-block (<- ($ x sec) 0) (<- ($ x min) 0))) (*named* days (r-block (<- ($ x sec) 0) (<- ($ x min) 0) (<- ($ x hour) 0) (<- ($ x isdst) (r-call - 1)))))) x) ()))
- (<- round.POSIXt (function ((*named* x *r-missing*) (*named* units (r-call c "secs" "mins" "hours" "days"))) (r-block (if (&& (r-call is.numeric units) (r-call == units 0)) (<- units "secs")) (<- units (r-call match.arg units)) (<- x (r-call as.POSIXct x)) (<- x (r-call + x (switch units (*named* secs 0.5) (*named* mins 30) (*named* hours 1800) (*named* days 43200)))) (r-call trunc.POSIXt x (*named* units units))) ()))
- (<- "[.POSIXlt" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* drop *r-true*)) (r-block (<- val (r-call lapply x "[" r-dotdotdot (*named* drop drop))) (<- (r-call attributes val) (r-call attributes x)) val) ()))
- (<- "[<-.POSIXlt" (function ((*named* x *r-missing*) (*named* i *r-missing*) (*named* value *r-missing*)) (r-block (if (r-call ! (r-call as.logical (r-call length value))) (return x)) (<- value (r-call as.POSIXlt value)) (<- cl (r-call oldClass x)) (<- (r-call class x) (<- (r-call class value) ())) (for n (r-call names x) (<- (r-call r-index (r-call r-aref x n) i) (r-call r-aref value n))) (<- (r-call class x) cl) x) ()))
- (<- as.data.frame.POSIXlt (function ((*named* x *r-missing*) (*named* row.names ()) (*named* optional *r-false*) (*named* ... *r-missing*)) (r-block (<- value (r-call as.data.frame.POSIXct (r-call as.POSIXct x) row.names optional r-dotdotdot)) (if (r-call ! optional) (<- (r-call names value) (r-call r-aref (r-call deparse (substitute x)) 1))) value) ()))
- (<- rep.POSIXct (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (<- y (r-call NextMethod)) (r-call structure y (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone (r-call attr x "tzone")))) ()))
- (<- rep.POSIXlt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (<- y (r-call lapply x rep r-dotdotdot)) (<- (r-call attributes y) (r-call attributes x)) y) ()))
- (<- diff.POSIXt (function ((*named* x *r-missing*) (*named* lag 1) (*named* differences 1) (*named* ... *r-missing*)) (r-block (<- ismat (r-call is.matrix x)) (<- r (if (r-call inherits x "POSIXlt") (r-call as.POSIXct x) x)) (<- xlen (if ismat (r-call r-index (r-call dim x) 1) (r-call length r))) (if (\|\| (\|\| (\|\| (r-call > (r-call length lag) 1) (r-call > (r-call length differences) 1)) (r-call < lag 1)) (r-call < differences 1)) (r-call stop "'lag' and 'differences' must be integers >= 1")) (if (r-call >= (r-call * lag differences) xlen) (return (r-call structure (r-call numeric 0) (*named* class "difftime") (*named* units "secs")))) (<- i1 (r-call : (r-call - 1) (r-call - lag))) (if ismat (for i (r-call : 1 differences) (<- r (r-call - (r-call r-index r i1 *r-missing* (*named* drop *r-false*)) (r-call r-index r (r-call : (r-call - (r-call nrow r)) (r-call - (r-call + (r-call - (r-call nrow r) lag) 1))) *r-missing* (*named* drop *r-false*))))) (for i (r-call : 1 differences) (<- r (r-call - (r-call r-index r i1) (r-call r-index r (r-call : (r-call - (r-call length r)) (r-call - (r-call + (r-call - (r-call length r) lag) 1)))))))) r) ()))
- (<- duplicated.POSIXlt (function ((*named* x *r-missing*) (*named* incomparables *r-false*) (*named* ... *r-missing*)) (r-block (<- x (r-call as.POSIXct x)) (r-call NextMethod "duplicated" x)) ()))
- (<- unique.POSIXlt (function ((*named* x *r-missing*) (*named* incomparables *r-false*) (*named* ... *r-missing*)) (r-call r-index x (r-call ! (r-call duplicated x incomparables r-dotdotdot))) ()))
- (<- sort.POSIXlt (function ((*named* x *r-missing*) (*named* decreasing *r-false*) (*named* na.last NA) (*named* ... *r-missing*)) (r-call r-index x (r-call order (r-call as.POSIXct x) (*named* na.last na.last) (*named* decreasing decreasing))) ())))
--- /dev/null
+++ b/test/ast/datetimeR.sl
@@ -1,0 +1,79 @@
+'(r-expressions
+ (<- Sys.time (function () (r-call structure (r-call .Internal (r-call Sys.time)) (*named* class (r-call c "POSIXt" "POSIXct"))) ()))
+ (<- Sys.timezone (function () (r-call as.vector (r-call Sys.getenv "TZ")) ()))
+ (<- as.POSIXlt (function ((*named* x *r-missing*) (*named* tz "")) (r-block (<- fromchar (function ((*named* x *r-missing*)) (r-block (<- xx (r-call r-index x 1)) (if (r-call is.na xx) (r-block (<- j 1) (while (&& (r-call is.na xx) (r-call <= (<- j (r-call + j 1)) (r-call length x))) (<- xx (r-call r-index x j))) (if (r-call is.na xx) (<- f "%Y-%m-%d")))) (if (\|\| (\|\| (\|\| (\|\| (\|\| (\|\| (r-call is.na xx) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y-%m-%d %H:%M:%OS"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y/%m/%d %H:%M:%OS"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y-%m-%d %H:%M"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y/%m/%d %H:%M"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y-%m-%d"))))) (r-call ! (r-call is.na (r-call strptime xx (<- f "%Y/%m/%d"))))) (r-block (<- res (r-call strptime x f)) (if (r-call nchar tz) (<- (r-call attr res "tzone") tz)) (return res))) (r-call stop "character string is not in a standard unambiguous format")) ())) (if (r-call inherits x "POSIXlt") (return x)) (if (r-call inherits x "Date") (return (r-call .Internal (r-call Date2POSIXlt x)))) (<- tzone (r-call attr x "tzone")) (if (\|\| (r-call inherits x "date") (r-call inherits x "dates")) (<- x (r-call as.POSIXct x))) (if (r-call is.character x) (return (r-call fromchar (r-call unclass x)))) (if (r-call is.factor x) (return (r-call fromchar (r-call as.character x)))) (if (&& (r-call is.logical x) (r-call all (r-call is.na x))) (<- x (r-call as.POSIXct.default x))) (if (r-call ! (r-call inherits x "POSIXct")) (r-call stop (r-call gettextf "do not know how to convert '%s' to class \"POSIXlt\"" (r-call deparse (substitute x))))) (if (&& (missing tz) (r-call ! (r-call is.null tzone))) (<- tz (r-call r-index tzone 1))) (r-call .Internal (r-call as.POSIXlt x tz))) ()))
+ (<- as.POSIXct (function ((*named* x *r-missing*) (*named* tz "")) (r-call UseMethod "as.POSIXct") ()))
+ (<- as.POSIXct.Date (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call structure (r-call * (r-call unclass x) 86400) (*named* class (r-call c "POSIXt" "POSIXct"))) ()))
+ (<- as.POSIXct.date (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (if (r-call inherits x "date") (r-block (<- x (r-call * (r-call - x 3653) 86400)) (return (r-call structure x (*named* class (r-call c "POSIXt" "POSIXct"))))) (r-call stop (r-call gettextf "'%s' is not a \"date\" object" (r-call deparse (substitute x)))))) ()))
+ (<- as.POSIXct.dates (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (if (r-call inherits x "dates") (r-block (<- z (r-call attr x "origin")) (<- x (r-call * (r-call as.numeric x) 86400)) (if (&& (r-call == (r-call length z) 3) (r-call is.numeric z)) (<- x (r-call + x (r-call as.numeric (r-call ISOdate (r-call r-index z 3) (r-call r-index z 1) (r-call r-index z 2) 0))))) (return (r-call structure x (*named* class (r-call c "POSIXt" "POSIXct"))))) (r-call stop (r-call gettextf "'%s' is not a \"dates\" object" (r-call deparse (substitute x)))))) ()))
+ (<- as.POSIXct.POSIXlt (function ((*named* x *r-missing*) (*named* tz "")) (r-block (<- tzone (r-call attr x "tzone")) (if (&& (missing tz) (r-call ! (r-call is.null tzone))) (<- tz (r-call r-index tzone 1))) (r-call structure (r-call .Internal (r-call as.POSIXct x tz)) (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone tz))) ()))
+ (<- as.POSIXct.default (function ((*named* x *r-missing*) (*named* tz "")) (r-block (if (r-call inherits x "POSIXct") (return x)) (if (\|\| (r-call is.character x) (r-call is.factor x)) (return (r-call as.POSIXct (r-call as.POSIXlt x) tz))) (if (&& (r-call is.logical x) (r-call all (r-call is.na x))) (return (r-call structure (r-call as.numeric x) (*named* class (r-call c "POSIXt" "POSIXct"))))) (r-call stop (r-call gettextf "do not know how to convert '%s' to class \"POSIXlt\"" (r-call deparse (substitute x))))) ()))
+ (<- as.numeric.POSIXlt (function ((*named* x *r-missing*)) (r-call as.POSIXct x) ()))
+ (<- format.POSIXlt (function ((*named* x *r-missing*) (*named* format "") (*named* usetz *r-false*) (*named* ... *r-missing*)) (r-block (if (r-call ! (r-call inherits x "POSIXlt")) (r-call stop "wrong class")) (if (r-call == format "") (r-block (<- times (r-call unlist (r-call r-index (r-call unclass x) (r-call : 1 3)))) (<- secs ($ x sec)) (<- secs (r-call r-index secs (r-call ! (r-call is.na secs)))) (<- np (r-call getOption "digits.secs")) (if (r-call is.null np) (<- np 0) (<- np (r-call min 6 np))) (if (r-call >= np 1) (r-block (for i (r-call - (r-call : 1 np) 1) (if (r-call all (r-call < (r-call abs (r-call - secs (r-call round secs i))) 1e-06)) (r-block (<- np i) (break)))))) (<- format (if (r-call all (r-call == (r-call r-index times (r-call ! (r-call is.na times))) 0)) "%Y-%m-%d" (if (r-call == np 0) "%Y-%m-%d %H:%M:%S" (r-call paste "%Y-%m-%d %H:%M:%OS" np (*named* sep ""))))))) (r-call .Internal (r-call format.POSIXlt x format usetz))) ()))
+ (<- strftime format.POSIXlt)
+ (<- strptime (function ((*named* x *r-missing*) (*named* format *r-missing*) (*named* tz "")) (r-call .Internal (r-call strptime (r-call as.character x) format tz)) ()))
+ (<- format.POSIXct (function ((*named* x *r-missing*) (*named* format "") (*named* tz "") (*named* usetz *r-false*) (*named* ... *r-missing*)) (r-block (if (r-call ! (r-call inherits x "POSIXct")) (r-call stop "wrong class")) (if (&& (missing tz) (r-call ! (r-call is.null (<- tzone (r-call attr x "tzone"))))) (<- tz tzone)) (r-call structure (r-call format.POSIXlt (r-call as.POSIXlt x tz) format usetz r-dotdotdot) (*named* names (r-call names x)))) ()))
+ (<- print.POSIXct (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call print (r-call format x (*named* usetz *r-true*) r-dotdotdot) r-dotdotdot) (r-call invisible x)) ()))
+ (<- print.POSIXlt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call print (r-call format x (*named* usetz *r-true*)) r-dotdotdot) (r-call invisible x)) ()))
+ (<- summary.POSIXct (function ((*named* object *r-missing*) (*named* digits 15) (*named* ... *r-missing*)) (r-block (<- x (r-call r-index (r-call summary.default (r-call unclass object) (*named* digits digits) r-dotdotdot) (r-call : 1 6))) (<- (r-call class x) (r-call oldClass object)) (<- (r-call attr x "tzone") (r-call attr object "tzone")) x) ()))
+ (<- summary.POSIXlt (function ((*named* object *r-missing*) (*named* digits 15) (*named* ... *r-missing*)) (r-call summary (r-call as.POSIXct object) (*named* digits digits) r-dotdotdot) ()))
+ (<- "+.POSIXt" (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x)))) ())) (if (r-call == (r-call nargs) 1) (return e1)) (if (&& (r-call inherits e1 "POSIXt") (r-call inherits e2 "POSIXt")) (r-call stop "binary + is not defined for \"POSIXt\" objects")) (if (r-call inherits e1 "POSIXlt") (<- e1 (r-call as.POSIXct e1))) (if (r-call inherits e2 "POSIXlt") (<- e2 (r-call as.POSIXct e2))) (if (r-call inherits e1 "difftime") (<- e1 (r-call coerceTimeUnit e1))) (if (r-call inherits e2 "difftime") (<- e2 (r-call coerceTimeUnit e2))) (r-call structure (r-call + (r-call unclass e1) (r-call unclass e2)) (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone (r-call check_tzones e1 e2)))) ()))
+ (<- "-.POSIXt" (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x)))) ())) (if (r-call ! (r-call inherits e1 "POSIXt")) (r-call stop "Can only subtract from POSIXt objects")) (if (r-call == (r-call nargs) 1) (r-call stop "unary - is not defined for \"POSIXt\" objects")) (if (r-call inherits e2 "POSIXt") (return (r-call difftime e1 e2))) (if (r-call inherits e2 "difftime") (<- e2 (r-call unclass (r-call coerceTimeUnit e2)))) (if (r-call ! (r-call is.null (r-call attr e2 "class"))) (r-call stop "can only subtract numbers from POSIXt objects")) (r-call structure (r-call - (r-call unclass (r-call as.POSIXct e1)) e2) (*named* class (r-call c "POSIXt" "POSIXct")))) ()))
+ (<- Ops.POSIXt (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (if (r-call == (r-call nargs) 1) (r-call stop "unary" .Generic " not defined for \"POSIXt\" objects")) (<- boolean (switch .Generic (*named* < *r-missing*) (*named* > *r-missing*) (*named* == *r-missing*) (*named* != *r-missing*) (*named* <= *r-missing*) (*named* >= *r-true*) *r-false*)) (if (r-call ! boolean) (r-call stop .Generic " not defined for \"POSIXt\" objects")) (if (\|\| (r-call inherits e1 "POSIXlt") (r-call is.character e1)) (<- e1 (r-call as.POSIXct e1))) (if (\|\| (r-call inherits e2 "POSIXlt") (r-call is.character e1)) (<- e2 (r-call as.POSIXct e2))) (r-call check_tzones e1 e2) (r-call NextMethod .Generic)) ()))
+ (<- Math.POSIXt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call stop .Generic " not defined for POSIXt objects")) ()))
+ (<- check_tzones (function ((*named* ... *r-missing*)) (r-block (<- tzs (r-call unique (r-call sapply (r-call list r-dotdotdot) (function ((*named* x *r-missing*)) (r-block (<- y (r-call attr x "tzone")) (if (r-call is.null y) "" y)) ())))) (<- tzs (r-call r-index tzs (r-call != tzs ""))) (if (r-call > (r-call length tzs) 1) (r-call warning "'tzone' attributes are inconsistent")) (if (r-call length tzs) (r-call r-index tzs 1) ())) ()))
+ (<- Summary.POSIXct (function ((*named* ... *r-missing*) (*named* na.rm *r-missing*)) (r-block (<- ok (switch .Generic (*named* max *r-missing*) (*named* min *r-missing*) (*named* range *r-true*) *r-false*)) (if (r-call ! ok) (r-call stop .Generic " not defined for \"POSIXct\" objects")) (<- args (r-call list r-dotdotdot)) (<- tz (r-call do.call "check_tzones" args)) (<- val (r-call NextMethod .Generic)) (<- (r-call class val) (r-call oldClass (r-call r-aref args 1))) (<- (r-call attr val "tzone") tz) val) ()))
+ (<- Summary.POSIXlt (function ((*named* ... *r-missing*) (*named* na.rm *r-missing*)) (r-block (<- ok (switch .Generic (*named* max *r-missing*) (*named* min *r-missing*) (*named* range *r-true*) *r-false*)) (if (r-call ! ok) (r-call stop .Generic " not defined for \"POSIXlt\" objects")) (<- args (r-call list r-dotdotdot)) (<- tz (r-call do.call "check_tzones" args)) (<- args (r-call lapply args as.POSIXct)) (<- val (r-call do.call .Generic (r-call c args (*named* na.rm na.rm)))) (r-call as.POSIXlt (r-call structure val (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone tz)))) ()))
+ (<- "[.POSIXct" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* drop *r-true*)) (r-block (<- cl (r-call oldClass x)) (<- (r-call class x) ()) (<- val (r-call NextMethod "[")) (<- (r-call class val) cl) (<- (r-call attr val "tzone") (r-call attr x "tzone")) val) ()))
+ (<- "[[.POSIXct" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* drop *r-true*)) (r-block (<- cl (r-call oldClass x)) (<- (r-call class x) ()) (<- val (r-call NextMethod "[[")) (<- (r-call class val) cl) (<- (r-call attr val "tzone") (r-call attr x "tzone")) val) ()))
+ (<- "[<-.POSIXct" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* value *r-missing*)) (r-block (if (r-call ! (r-call as.logical (r-call length value))) (return x)) (<- value (r-call as.POSIXct value)) (<- cl (r-call oldClass x)) (<- tz (r-call attr x "tzone")) (<- (r-call class x) (<- (r-call class value) ())) (<- x (r-call NextMethod .Generic)) (<- (r-call class x) cl) (<- (r-call attr x "tzone") tz) x) ()))
+ (<- as.character.POSIXt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call format x r-dotdotdot) ()))
+ (<- as.data.frame.POSIXct as.data.frame.vector)
+ (<- is.na.POSIXlt (function ((*named* x *r-missing*)) (r-call is.na (r-call as.POSIXct x)) ()))
+ (<- c.POSIXct (function ((*named* ... *r-missing*) (*named* recursive *r-false*)) (r-call structure (r-call c (r-call unlist (r-call lapply (r-call list r-dotdotdot) unclass))) (*named* class (r-call c "POSIXt" "POSIXct"))) ()))
+ (<- c.POSIXlt (function ((*named* ... *r-missing*) (*named* recursive *r-false*)) (r-call as.POSIXlt (r-call do.call "c" (r-call lapply (r-call list r-dotdotdot) as.POSIXct))) ()))
+ (<- all.equal.POSIXct (function ((*named* target *r-missing*) (*named* current *r-missing*) (*named* ... *r-missing*) (*named* scale 1)) (r-block (r-call check_tzones target current) (r-call NextMethod "all.equal")) ()))
+ (<- ISOdatetime (function ((*named* year *r-missing*) (*named* month *r-missing*) (*named* day *r-missing*) (*named* hour *r-missing*) (*named* min *r-missing*) (*named* sec *r-missing*) (*named* tz "")) (r-block (<- x (r-call paste year month day hour min sec (*named* sep "-"))) (r-call as.POSIXct (r-call strptime x "%Y-%m-%d-%H-%M-%OS" (*named* tz tz)) (*named* tz tz))) ()))
+ (<- ISOdate (function ((*named* year *r-missing*) (*named* month *r-missing*) (*named* day *r-missing*) (*named* hour 12) (*named* min 0) (*named* sec 0) (*named* tz "GMT")) (r-call ISOdatetime year month day hour min sec tz) ()))
+ (<- as.matrix.POSIXlt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call as.matrix (r-call as.data.frame (r-call unclass x)) r-dotdotdot)) ()))
+ (<- mean.POSIXct (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call structure (r-call mean (r-call unclass x) r-dotdotdot) (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone (r-call attr x "tzone"))) ()))
+ (<- mean.POSIXlt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call as.POSIXlt (r-call mean (r-call as.POSIXct x) r-dotdotdot)) ()))
+ (<- difftime (function ((*named* time1 *r-missing*) (*named* time2 *r-missing*) (*named* tz "") (*named* units (r-call c "auto" "secs" "mins" "hours" "days" "weeks"))) (r-block (<- time1 (r-call as.POSIXct time1 (*named* tz tz))) (<- time2 (r-call as.POSIXct time2 (*named* tz tz))) (<- z (r-call - (r-call unclass time1) (r-call unclass time2))) (<- units (r-call match.arg units)) (if (r-call == units "auto") (r-block (if (r-call all (r-call is.na z)) (<- units "secs") (r-block (<- zz (r-call min (r-call abs z) (*named* na.rm *r-true*))) (if (\|\| (r-call is.na zz) (r-call < zz 60)) (<- units "secs") (if (r-call < zz 3600) (<- units "mins") (if (r-call < zz 86400) (<- units "hours") (<- units "days")))))))) (switch units (*named* secs (r-call structure z (*named* units "secs") (*named* class "difftime"))) (*named* mins (r-call structure (r-call / z 60) (*named* units "mins") (*named* class "difftime"))) (*named* hours (r-call structure (r-call / z 3600) (*named* units "hours") (*named* class "difftime"))) (*named* days (r-call structure (r-call / z 86400) (*named* units "days") (*named* class "difftime"))) (*named* weeks (r-call structure (r-call / z (r-call * 7 86400)) (*named* units "weeks") (*named* class "difftime"))))) ()))
+ (<- as.difftime (function ((*named* tim *r-missing*) (*named* format "%X") (*named* units "auto")) (r-block (if (r-call inherits tim "difftime") (return tim)) (if (r-call is.character tim) (r-block (r-call difftime (r-call strptime tim (*named* format format)) (r-call strptime "0:0:0" (*named* format "%X")) (*named* units units))) (r-block (if (r-call ! (r-call is.numeric tim)) (r-call stop "'tim' is not character or numeric")) (if (r-call == units "auto") (r-call stop "need explicit units for numeric conversion")) (if (r-call ! (r-call %in% units (r-call c "secs" "mins" "hours" "days" "weeks"))) (r-call stop "invalid units specified")) (r-call structure tim (*named* units units) (*named* class "difftime"))))) ()))
+ (<- units (function ((*named* x *r-missing*)) (r-call UseMethod "units") ()))
+ (<- "units<-" (function ((*named* x *r-missing*) (*named* value *r-missing*)) (r-call UseMethod "units<-") ()))
+ (<- units.difftime (function ((*named* x *r-missing*)) (r-call attr x "units") ()))
+ (<- "units<-.difftime" (function ((*named* x *r-missing*) (*named* value *r-missing*)) (r-block (<- from (r-call units x)) (if (r-call == from value) (return x)) (if (r-call ! (r-call %in% value (r-call c "secs" "mins" "hours" "days" "weeks"))) (r-call stop "invalid units specified")) (<- sc (r-call cumprod (r-call c (*named* secs 1) (*named* mins 60) (*named* hours 60) (*named* days 24) (*named* weeks 7)))) (<- newx (r-call / (r-call * (r-call as.vector x) (r-call r-index sc from)) (r-call r-index sc value))) (r-call structure newx (*named* units value) (*named* class "difftime"))) ()))
+ (<- as.double.difftime (function ((*named* x *r-missing*) (*named* units "auto") (*named* ... *r-missing*)) (r-block (if (r-call != units "auto") (<- (r-call units x) units)) (r-call as.double (r-call as.vector x))) ()))
+ (<- as.data.frame.difftime as.data.frame.vector)
+ (<- format.difftime (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call paste (r-call format (r-call unclass x) r-dotdotdot) (r-call units x)) ()))
+ (<- print.difftime (function ((*named* x *r-missing*) (*named* digits (r-call getOption "digits")) (*named* ... *r-missing*)) (r-block (if (\|\| (r-call is.array x) (r-call > (r-call length x) 1)) (r-block (r-call cat "Time differences in " (r-call attr x "units") "\n" (*named* sep "")) (<- y (r-call unclass x)) (<- (r-call attr y "units") ()) (r-call print y)) (r-call cat "Time difference of " (r-call format (r-call unclass x) (*named* digits digits)) " " (r-call attr x "units") "\n" (*named* sep ""))) (r-call invisible x)) ()))
+ (<- round.difftime (function ((*named* x *r-missing*) (*named* digits 0) (*named* ... *r-missing*)) (r-block (<- units (r-call attr x "units")) (r-call structure (r-call NextMethod) (*named* units units) (*named* class "difftime"))) ()))
+ (<- "[.difftime" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* drop *r-true*)) (r-block (<- cl (r-call oldClass x)) (<- (r-call class x) ()) (<- val (r-call NextMethod "[")) (<- (r-call class val) cl) (<- (r-call attr val "units") (r-call attr x "units")) val) ()))
+ (<- Ops.difftime (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x)))) ())) (if (r-call == (r-call nargs) 1) (r-block (switch .Generic (*named* + (r-block)) (*named* - (r-block (<- (r-call r-index e1 *r-missing*) (r-call - (r-call unclass e1))))) (r-call stop "unary" .Generic " not defined for \"difftime\" objects")) (return e1))) (<- boolean (switch .Generic (*named* < *r-missing*) (*named* > *r-missing*) (*named* == *r-missing*) (*named* != *r-missing*) (*named* <= *r-missing*) (*named* >= *r-true*) *r-false*)) (if boolean (r-block (if (&& (r-call inherits e1 "difftime") (r-call inherits e2 "difftime")) (r-block (<- e1 (r-call coerceTimeUnit e1)) (<- e2 (r-call coerceTimeUnit e2)))) (r-call NextMethod .Generic)) (if (\|\| (r-call == .Generic "+") (r-call == .Generic "-")) (r-block (if (&& (r-call inherits e1 "difftime") (r-call ! (r-call inherits e2 "difftime"))) (return (r-call structure (r-call NextMethod .Generic) (*named* units (r-call attr e1 "units")) (*named* class "difftime")))) (if (&& (r-call ! (r-call inherits e1 "difftime")) (r-call inherits e2 "difftime")) (return (r-call structure (r-call NextMethod .Generic) (*named* units (r-call attr e2 "units")) (*named* class "difftime")))) (<- u1 (r-call attr e1 "units")) (if (r-call == (r-call attr e2 "units") u1) (r-block (r-call structure (r-call NextMethod .Generic) (*named* units u1) (*named* class "difftime"))) (r-block (<- e1 (r-call coerceTimeUnit e1)) (<- e2 (r-call coerceTimeUnit e2)) (r-call structure (r-call NextMethod .Generic) (*named* units "secs") (*named* class "difftime"))))) (r-block (r-call stop .Generic "not defined for \"difftime\" objects"))))) ()))
+ (<- "*.difftime" (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (if (&& (r-call inherits e1 "difftime") (r-call inherits e2 "difftime")) (r-call stop "both arguments of * cannot be \"difftime\" objects")) (if (r-call inherits e2 "difftime") (r-block (<- tmp e1) (<- e1 e2) (<- e2 tmp))) (r-call structure (r-call * e2 (r-call unclass e1)) (*named* units (r-call attr e1 "units")) (*named* class "difftime"))) ()))
+ (<- "/.difftime" (function ((*named* e1 *r-missing*) (*named* e2 *r-missing*)) (r-block (if (r-call inherits e2 "difftime") (r-call stop "second argument of / cannot be a \"difftime\" object")) (r-call structure (r-call / (r-call unclass e1) e2) (*named* units (r-call attr e1 "units")) (*named* class "difftime"))) ()))
+ (<- Math.difftime (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (r-call stop .Generic "not defined for \"difftime\" objects")) ()))
+ (<- mean.difftime (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* na.rm *r-false*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (r-call as.vector (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x))))) ())) (if (r-call length (r-call list r-dotdotdot)) (r-block (<- args (r-call c (r-call lapply (r-call list x r-dotdotdot) coerceTimeUnit) (*named* na.rm na.rm))) (r-call structure (r-call do.call "mean" args) (*named* units "secs") (*named* class "difftime"))) (r-block (r-call structure (r-call mean (r-call as.vector x) (*named* na.rm na.rm)) (*named* units (r-call attr x "units")) (*named* class "difftime"))))) ()))
+ (<- Summary.difftime (function ((*named* ... *r-missing*) (*named* na.rm *r-missing*)) (r-block (<- coerceTimeUnit (function ((*named* x *r-missing*)) (r-block (r-call as.vector (switch (r-call attr x "units") (*named* secs x) (*named* mins (r-call * 60 x)) (*named* hours (r-call * (r-call * 60 60) x)) (*named* days (r-call * (r-call * (r-call * 60 60) 24) x)) (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60) 24) 7) x))))) ())) (<- ok (switch .Generic (*named* max *r-missing*) (*named* min *r-missing*) (*named* range *r-true*) *r-false*)) (if (r-call ! ok) (r-call stop .Generic " not defined for \"difftime\" objects")) (<- args (r-call c (r-call lapply (r-call list r-dotdotdot) coerceTimeUnit) (*named* na.rm na.rm))) (r-call structure (r-call do.call .Generic args) (*named* units "secs") (*named* class "difftime"))) ()))
+ (<- seq.POSIXt (function ((*named* from *r-missing*) (*named* to *r-missing*) (*named* by *r-missing*) (*named* length.out ()) (*named* along.with ()) (*named* ... *r-missing*)) (r-block (if (missing from) (r-call stop "'from' must be specified")) (if (r-call ! (r-call inherits from "POSIXt")) (r-call stop "'from' must be a POSIXt object")) (<- cfrom (r-call as.POSIXct from)) (if (r-call != (r-call length cfrom) 1) (r-call stop "'from' must be of length 1")) (<- tz (r-call attr cfrom "tzone")) (if (r-call ! (missing to)) (r-block (if (r-call ! (r-call inherits to "POSIXt")) (r-call stop "'to' must be a POSIXt object")) (if (r-call != (r-call length (r-call as.POSIXct to)) 1) (r-call stop "'to' must be of length 1")))) (if (r-call ! (missing along.with)) (r-block (<- length.out (r-call length along.with))) (if (r-call ! (r-call is.null length.out)) (r-block (if (r-call != (r-call length length.out) 1) (r-call stop "'length.out' must be of length 1")) (<- length.out (r-call ceiling length.out))))) (<- status (r-call c (r-call ! (missing to)) (r-call ! (missing by)) (r-call ! (r-call is.null length.out)))) (if (r-call != (r-call sum status) 2) (r-call stop "exactly two of 'to', 'by' and 'length.out' / 'along.with' must be specified")) (if (missing by) (r-block (<- from (r-call unclass cfrom)) (<- to (r-call unclass (r-call as.POSIXct to))) (<- res (r-call seq.int from to (*named* length.out length.out))) (return (r-call structure res (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone tz))))) (if (r-call != (r-call length by) 1) (r-call stop "'by' must be of length 1")) (<- valid 0) (if (r-call inherits by "difftime") (r-block (<- by (r-call * (switch (r-call attr by "units") (*named* secs 1) (*named* mins 60) (*named* hours 3600) (*named* days 86400) (*named* weeks (r-call * 7 86400))) (r-call unclass by)))) (if (r-call is.character by) (r-block (<- by2 (r-call r-aref (r-call strsplit by " " (*named* fixed *r-true*)) 1)) (if (\|\| (r-call > (r-call length by2) 2) (r-call < (r-call length by2) 1)) (r-call stop "invalid 'by' string")) (<- valid (r-call pmatch (r-call r-index by2 (r-call length by2)) (r-call c "secs" "mins" "hours" "days" "weeks" "months" "years" "DSTdays"))) (if (r-call is.na valid) (r-call stop "invalid string for 'by'")) (if (r-call <= valid 5) (r-block (<- by (r-call r-index (r-call c 1 60 3600 86400 (r-call * 7 86400)) valid)) (if (r-call == (r-call length by2) 2) (<- by (r-call * by (r-call as.integer (r-call r-index by2 1)))))) (<- by (if (r-call == (r-call length by2) 2) (r-call as.integer (r-call r-index by2 1)) 1)))) (if (r-call ! (r-call is.numeric by)) (r-call stop "invalid mode for 'by'")))) (if (r-call is.na by) (r-call stop "'by' is NA")) (if (r-call <= valid 5) (r-block (<- from (r-call unclass (r-call as.POSIXct from))) (if (r-call ! (r-call is.null length.out)) (<- res (r-call seq.int from (*named* by by) (*named* length.out length.out))) (r-block (<- to (r-call unclass (r-call as.POSIXct to))) (<- res (r-call + (r-call seq.int 0 (r-call - to from) by) from)))) (return (r-call structure res (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone tz)))) (r-block (<- r1 (r-call as.POSIXlt from)) (if (r-call == valid 7) (r-block (if (missing to) (r-block (<- yr (r-call seq.int ($ r1 year) (*named* by by) (*named* length length.out)))) (r-block (<- to (r-call as.POSIXlt to)) (<- yr (r-call seq.int ($ r1 year) ($ to year) by)))) (<- ($ r1 year) yr) (<- ($ r1 isdst) (r-call - 1)) (<- res (r-call as.POSIXct r1))) (if (r-call == valid 6) (r-block (if (missing to) (r-block (<- mon (r-call seq.int ($ r1 mon) (*named* by by) (*named* length length.out)))) (r-block (<- to (r-call as.POSIXlt to)) (<- mon (r-call seq.int ($ r1 mon) (r-call + (r-call * 12 (r-call - ($ to year) ($ r1 year))) ($ to mon)) by)))) (<- ($ r1 mon) mon) (<- ($ r1 isdst) (r-call - 1)) (<- res (r-call as.POSIXct r1))) (if (r-call == valid 8) (r-block (if (r-call ! (missing to)) (r-block (<- length.out (r-call + 2 (r-call floor (r-call / (r-call - (r-call unclass (r-call as.POSIXct to)) (r-call unclass (r-call as.POSI
\ No newline at end of file
+ (<- cut.POSIXt (function ((*named* x *r-missing*) (*named* breaks *r-missing*) (*named* labels ()) (*named* start.on.monday *r-true*) (*named* right *r-false*) (*named* ... *r-missing*)) (r-block (if (r-call ! (r-call inherits x "POSIXt")) (r-call stop "'x' must be a date-time object")) (<- x (r-call as.POSIXct x)) (if (r-call inherits breaks "POSIXt") (r-block (<- breaks (r-call as.POSIXct breaks))) (if (&& (r-call is.numeric breaks) (r-call == (r-call length breaks) 1)) (r-block) (if (&& (r-call is.character breaks) (r-call == (r-call length breaks) 1)) (r-block (<- by2 (r-call r-aref (r-call strsplit breaks " " (*named* fixed *r-true*)) 1)) (if (\|\| (r-call > (r-call length by2) 2) (r-call < (r-call length by2) 1)) (r-call stop "invalid specification of 'breaks'")) (<- valid (r-call pmatch (r-call r-index by2 (r-call length by2)) (r-call c "secs" "mins" "hours" "days" "weeks" "months" "years" "DSTdays"))) (if (r-call is.na valid) (r-call stop "invalid specification of 'breaks'")) (<- start (r-call as.POSIXlt (r-call min x (*named* na.rm *r-true*)))) (<- incr 1) (if (r-call > valid 1) (r-block (<- ($ start sec) 0) (<- incr 59.99))) (if (r-call > valid 2) (r-block (<- ($ start min) 0) (<- incr (r-call - 3600 1)))) (if (r-call > valid 3) (r-block (<- ($ start hour) 0) (<- incr (r-call - 86400 1)))) (if (r-call == valid 5) (r-block (<- ($ start mday) (r-call - ($ start mday) ($ start wday))) (if start.on.monday (<- ($ start mday) (r-call + ($ start mday) (r-call ifelse (r-call > ($ start wday) 0) 1 (r-call - 6))))) (<- incr (r-call * 7 86400)))) (if (r-call == valid 6) (r-block (<- ($ start mday) 1) (<- incr (r-call * 31 86400)))) (if (r-call == valid 7) (r-block (<- ($ start mon) 0) (<- ($ start mday) 1) (<- incr (r-call * 366 86400)))) (if (r-call == valid 8) (<- incr (r-call * 25 3600))) (if (r-call == (r-call length by2) 2) (<- incr (r-call * incr (r-call as.integer (r-call r-index by2 1))))) (<- maxx (r-call max x (*named* na.rm *r-true*))) (<- breaks (r-call seq.int start (r-call + maxx incr) breaks)) (<- breaks (r-call r-index breaks (r-call : 1 (r-call + 1 (r-call max (r-call which (r-call < breaks maxx)))))))) (r-call stop "invalid specification of 'breaks'")))) (<- res (r-call cut (r-call unclass x) (r-call unclass breaks) (*named* labels labels) (*named* right right) r-dotdotdot)) (if (r-call is.null labels) (<- (r-call levels res) (r-call as.character (r-call r-index breaks (r-call - (r-call length breaks)))))) res) ()))
+ (<- julian (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-call UseMethod "julian") ()))
+ (<- julian.POSIXt (function ((*named* x *r-missing*) (*named* origin (r-call as.POSIXct "1970-01-01" (*named* tz "GMT"))) (*named* ... *r-missing*)) (r-block (if (r-call != (r-call length origin) 1) (r-call stop "'origin' must be of length one")) (<- res (r-call difftime (r-call as.POSIXct x) origin (*named* units "days"))) (r-call structure res (*named* origin origin))) ()))
+ (<- weekdays (function ((*named* x *r-missing*) (*named* abbreviate *r-missing*)) (r-call UseMethod "weekdays") ()))
+ (<- weekdays.POSIXt (function ((*named* x *r-missing*) (*named* abbreviate *r-false*)) (r-block (r-call format x (r-call ifelse abbreviate "%a" "%A"))) ()))
+ (<- months (function ((*named* x *r-missing*) (*named* abbreviate *r-missing*)) (r-call UseMethod "months") ()))
+ (<- months.POSIXt (function ((*named* x *r-missing*) (*named* abbreviate *r-false*)) (r-block (r-call format x (r-call ifelse abbreviate "%b" "%B"))) ()))
+ (<- quarters (function ((*named* x *r-missing*) (*named* abbreviate *r-missing*)) (r-call UseMethod "quarters") ()))
+ (<- quarters.POSIXt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (<- x (r-call %/% ($ (r-call as.POSIXlt x) mon) 3)) (r-call paste "Q" (r-call + x 1) (*named* sep ""))) ()))
+ (<- trunc.POSIXt (function ((*named* x *r-missing*) (*named* units (r-call c "secs" "mins" "hours" "days"))) (r-block (<- units (r-call match.arg units)) (<- x (r-call as.POSIXlt x)) (if (r-call > (r-call length ($ x sec)) 0) (switch units (*named* secs (r-block (<- ($ x sec) (r-call trunc ($ x sec))))) (*named* mins (r-block (<- ($ x sec) 0))) (*named* hours (r-block (<- ($ x sec) 0) (<- ($ x min) 0))) (*named* days (r-block (<- ($ x sec) 0) (<- ($ x min) 0) (<- ($ x hour) 0) (<- ($ x isdst) (r-call - 1)))))) x) ()))
+ (<- round.POSIXt (function ((*named* x *r-missing*) (*named* units (r-call c "secs" "mins" "hours" "days"))) (r-block (if (&& (r-call is.numeric units) (r-call == units 0)) (<- units "secs")) (<- units (r-call match.arg units)) (<- x (r-call as.POSIXct x)) (<- x (r-call + x (switch units (*named* secs 0.5) (*named* mins 30) (*named* hours 1800) (*named* days 43200)))) (r-call trunc.POSIXt x (*named* units units))) ()))
+ (<- "[.POSIXlt" (function ((*named* x *r-missing*) (*named* ... *r-missing*) (*named* drop *r-true*)) (r-block (<- val (r-call lapply x "[" r-dotdotdot (*named* drop drop))) (<- (r-call attributes val) (r-call attributes x)) val) ()))
+ (<- "[<-.POSIXlt" (function ((*named* x *r-missing*) (*named* i *r-missing*) (*named* value *r-missing*)) (r-block (if (r-call ! (r-call as.logical (r-call length value))) (return x)) (<- value (r-call as.POSIXlt value)) (<- cl (r-call oldClass x)) (<- (r-call class x) (<- (r-call class value) ())) (for n (r-call names x) (<- (r-call r-index (r-call r-aref x n) i) (r-call r-aref value n))) (<- (r-call class x) cl) x) ()))
+ (<- as.data.frame.POSIXlt (function ((*named* x *r-missing*) (*named* row.names ()) (*named* optional *r-false*) (*named* ... *r-missing*)) (r-block (<- value (r-call as.data.frame.POSIXct (r-call as.POSIXct x) row.names optional r-dotdotdot)) (if (r-call ! optional) (<- (r-call names value) (r-call r-aref (r-call deparse (substitute x)) 1))) value) ()))
+ (<- rep.POSIXct (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (<- y (r-call NextMethod)) (r-call structure y (*named* class (r-call c "POSIXt" "POSIXct")) (*named* tzone (r-call attr x "tzone")))) ()))
+ (<- rep.POSIXlt (function ((*named* x *r-missing*) (*named* ... *r-missing*)) (r-block (<- y (r-call lapply x rep r-dotdotdot)) (<- (r-call attributes y) (r-call attributes x)) y) ()))
+ (<- diff.POSIXt (function ((*named* x *r-missing*) (*named* lag 1) (*named* differences 1) (*named* ... *r-missing*)) (r-block (<- ismat (r-call is.matrix x)) (<- r (if (r-call inherits x "POSIXlt") (r-call as.POSIXct x) x)) (<- xlen (if ismat (r-call r-index (r-call dim x) 1) (r-call length r))) (if (\|\| (\|\| (\|\| (r-call > (r-call length lag) 1) (r-call > (r-call length differences) 1)) (r-call < lag 1)) (r-call < differences 1)) (r-call stop "'lag' and 'differences' must be integers >= 1")) (if (r-call >= (r-call * lag differences) xlen) (return (r-call structure (r-call numeric 0) (*named* class "difftime") (*named* units "secs")))) (<- i1 (r-call : (r-call - 1) (r-call - lag))) (if ismat (for i (r-call : 1 differences) (<- r (r-call - (r-call r-index r i1 *r-missing* (*named* drop *r-false*)) (r-call r-index r (r-call : (r-call - (r-call nrow r)) (r-call - (r-call + (r-call - (r-call nrow r) lag) 1))) *r-missing* (*named* drop *r-false*))))) (for i (r-call : 1 differences) (<- r (r-call - (r-call r-index r i1) (r-call r-index r (r-call : (r-call - (r-call length r)) (r-call - (r-call + (r-call - (r-call length r) lag) 1)))))))) r) ()))
+ (<- duplicated.POSIXlt (function ((*named* x *r-missing*) (*named* incomparables *r-false*) (*named* ... *r-missing*)) (r-block (<- x (r-call as.POSIXct x)) (r-call NextMethod "duplicated" x)) ()))
+ (<- unique.POSIXlt (function ((*named* x *r-missing*) (*named* incomparables *r-false*) (*named* ... *r-missing*)) (r-call r-index x (r-call ! (r-call duplicated x incomparables r-dotdotdot))) ()))
+ (<- sort.POSIXlt (function ((*named* x *r-missing*) (*named* decreasing *r-false*) (*named* na.last NA) (*named* ... *r-missing*)) (r-call r-index x (r-call order (r-call as.POSIXct x) (*named* na.last na.last) (*named* decreasing decreasing))) ())))
--- a/test/ast/match.lsp
+++ /dev/null
@@ -1,179 +1,0 @@
-; tree regular expression pattern matching
-; by Jeff Bezanson
-
-(def (unique lst)
- (and lst
- (cons (car lst)
- (filter (λ (x) (not (eq? x (car lst))))
- (unique (cdr lst))))))
-
-; list of special pattern symbols that cannot be variable names
-(def metasymbols '(_ ...))
-
-; expression tree pattern matching
-; matches expr against pattern p and returns an assoc list ((var . expr) (var . expr) ...)
-; mapping variables to captured subexpressions, or NIL if no match.
-; when a match succeeds, __ is always bound to the whole matched expression.
-;
-; p is an expression in the following pattern language:
-;
-; _ match anything, not captured
-; <func> any scheme function; matches if (func expr) returns T
-; <var> match anything and capture as <var>. future occurrences of <var> in the pattern
-; must match the same thing.
-; (head <p1> <p2> etc) match an s-expr with 'head' matched literally, and the rest of the
-; subpatterns matched recursively.
-; (-/ <ex>) match <ex> literally
-; (-^ <p>) complement of pattern <p>
-; (-- <var> <p>) match <p> and capture as <var> if match succeeds
-;
-; regular match constructs:
-; ... match any number of anything
-; (-$ <p1> <p2> etc) match any of subpatterns <p1>, <p2>, etc
-; (-* <p>) match any number of <p>
-; (-? <p>) match 0 or 1 of <p>
-; (-+ <p>) match at least 1 of <p>
-; all of these can be wrapped in (-- var ) for capturing purposes
-; This is NP-complete. Be careful.
-;
-(def (match- p expr state)
- (cond ((sym? p)
- (cond ((eq? p '_) state)
- (else
- (let ((capt (assq p state)))
- (if capt
- (and (equal? expr (cdr capt)) state)
- (cons (cons p expr) state))))))
-
- ((fn? p)
- (and (p expr) state))
-
- ((cons? p)
- (cond ((eq? (car p) '-/) (and (equal? (cadr p) expr) state))
- ((eq? (car p) '-^) (and (not (match- (cadr p) expr state)) state))
- ((eq? (car p) '--)
- (and (match- (caddr p) expr state)
- (cons (cons (cadr p) expr) state)))
- ((eq? (car p) '-$) ; greedy alternation for toplevel pattern
- (match-alt (cdr p) NIL (list expr) state NIL 1))
- (else
- (and (cons? expr)
- (equal? (car p) (car expr))
- (match-seq (cdr p) (cdr expr) state (length (cdr expr)))))))
-
- (else
- (and (equal? p expr) state))))
-
-; match an alternation
-(def (match-alt alt prest expr state var L)
- (and alt
- (let ((subma (match- (car alt) (car expr) state)))
- (or (and subma
- (match-seq prest (cdr expr)
- (if var
- (cons (cons var (car expr))
- subma)
- subma)
- (- L 1)))
- (match-alt (cdr alt) prest expr state var L)))))
-
-; match generalized kleene star (try consuming min to max)
-(def (match-star- p prest expr state var min max L sofar)
- (cond ; case 0: impossible to match
- ((> min max) NIL)
- ; case 1: only allowed to match 0 subexpressions
- ((= max 0) (match-seq prest expr
- (if var (cons (cons var (reverse sofar)) state)
- state)
- L))
- ; case 2: must match at least 1
- ((> min 0)
- (and (match- p (car expr) state)
- (match-star- p prest (cdr expr) state var (- min 1) (- max 1) (- L 1)
- (cons (car expr) sofar))))
- ; otherwise, must match either 0 or between 1 and max subexpressions
- (else
- (or (match-star- p prest expr state var 0 0 L sofar)
- (match-star- p prest expr state var 1 max L sofar)))))
-(def (match-star p prest expr state var min max L)
- (match-star- p prest expr state var min max L NIL))
-
-; match sequences of expressions
-(def (match-seq p expr state L)
- (cond ((not state) NIL)
- ((not p) (if (not expr) state NIL))
- (else
- (let ((subp (car p))
- (var NIL))
- (if (and (cons? subp)
- (eq? (car subp) '--))
- (begin (set! var (cadr subp))
- (set! subp (caddr subp)))
- NIL)
- (let ((head (if (cons? subp) (car subp) NIL)))
- (cond ((eq? subp '...)
- (match-star '_ (cdr p) expr state var 0 L L))
- ((eq? head '-*)
- (match-star (cadr subp) (cdr p) expr state var 0 L L))
- ((eq? head '-+)
- (match-star (cadr subp) (cdr p) expr state var 1 L L))
- ((eq? head '-?)
- (match-star (cadr subp) (cdr p) expr state var 0 1 L))
- ((eq? head '-$)
- (match-alt (cdr subp) (cdr p) expr state var L))
- (else
- (and (cons? expr)
- (match-seq (cdr p) (cdr expr)
- (match- (car p) (car expr) state)
- (- L 1))))))))))
-
-(def (match p expr) (match- p expr (list (cons '__ expr))))
-
-; given a pattern p, return the list of capturing variables it uses
-(def (patargs- p)
- (cond ((and (sym? p)
- (not (member p metasymbols)))
- (list p))
-
- ((cons? p)
- (if (eq? (car p) '-/)
- NIL
- (unique (apply append (map patargs- (cdr p))))))
-
- (else NIL)))
-(def (patargs p)
- (cons '__ (patargs- p)))
-
-; try to transform expr using a pattern-lambda from plist
-; returns the new expression, or expr if no matches
-(def (apply-patterns plist expr)
- (if (not plist) expr
- (if (fn? plist)
- (let ((enew (plist expr)))
- (if (not enew)
- expr
- enew))
- (let ((enew ((car plist) expr)))
- (if (not enew)
- (apply-patterns (cdr plist) expr)
- enew)))))
-
-; top-down fixed-point macroexpansion. this is a typical algorithm,
-; but it may leave some structure that matches a pattern unexpanded.
-; the advantage is that non-terminating cases cannot arise as a result
-; of expression composition. in other words, if the outer loop terminates
-; on all inputs for a given set of patterns, then the whole algorithm
-; terminates. pattern sets that violate this should be easier to detect,
-; for example
-; (pattern-lambda (/ 2 3) '(/ 3 2)), (pattern-lambda (/ 3 2) '(/ 2 3))
-; TODO: ignore quoted expressions
-(def (pattern-expand plist expr)
- (if (not (cons? expr))
- expr
- (let ((enew (apply-patterns plist expr)))
- (if (eq? enew expr)
- ; expr didn't change; move to subexpressions
- (cons (car expr)
- (map (lambda (subex) (pattern-expand plist subex)) (cdr expr)))
- ; expr changed; iterate
- (pattern-expand plist enew)))))
--- /dev/null
+++ b/test/ast/match.sl
@@ -1,0 +1,179 @@
+; tree regular expression pattern matching
+; by Jeff Bezanson
+
+(def (unique lst)
+ (and lst
+ (cons (car lst)
+ (filter (λ (x) (not (eq? x (car lst))))
+ (unique (cdr lst))))))
+
+; list of special pattern symbols that cannot be variable names
+(def metasymbols '(_ ...))
+
+; expression tree pattern matching
+; matches expr against pattern p and returns an assoc list ((var . expr) (var . expr) ...)
+; mapping variables to captured subexpressions, or NIL if no match.
+; when a match succeeds, __ is always bound to the whole matched expression.
+;
+; p is an expression in the following pattern language:
+;
+; _ match anything, not captured
+; <func> any scheme function; matches if (func expr) returns T
+; <var> match anything and capture as <var>. future occurrences of <var> in the pattern
+; must match the same thing.
+; (head <p1> <p2> etc) match an s-expr with 'head' matched literally, and the rest of the
+; subpatterns matched recursively.
+; (-/ <ex>) match <ex> literally
+; (-^ <p>) complement of pattern <p>
+; (-- <var> <p>) match <p> and capture as <var> if match succeeds
+;
+; regular match constructs:
+; ... match any number of anything
+; (-$ <p1> <p2> etc) match any of subpatterns <p1>, <p2>, etc
+; (-* <p>) match any number of <p>
+; (-? <p>) match 0 or 1 of <p>
+; (-+ <p>) match at least 1 of <p>
+; all of these can be wrapped in (-- var ) for capturing purposes
+; This is NP-complete. Be careful.
+;
+(def (match- p expr state)
+ (cond ((sym? p)
+ (cond ((eq? p '_) state)
+ (else
+ (let ((capt (assq p state)))
+ (if capt
+ (and (equal? expr (cdr capt)) state)
+ (cons (cons p expr) state))))))
+
+ ((fn? p)
+ (and (p expr) state))
+
+ ((cons? p)
+ (cond ((eq? (car p) '-/) (and (equal? (cadr p) expr) state))
+ ((eq? (car p) '-^) (and (not (match- (cadr p) expr state)) state))
+ ((eq? (car p) '--)
+ (and (match- (caddr p) expr state)
+ (cons (cons (cadr p) expr) state)))
+ ((eq? (car p) '-$) ; greedy alternation for toplevel pattern
+ (match-alt (cdr p) NIL (list expr) state NIL 1))
+ (else
+ (and (cons? expr)
+ (equal? (car p) (car expr))
+ (match-seq (cdr p) (cdr expr) state (length (cdr expr)))))))
+
+ (else
+ (and (equal? p expr) state))))
+
+; match an alternation
+(def (match-alt alt prest expr state var L)
+ (and alt
+ (let ((subma (match- (car alt) (car expr) state)))
+ (or (and subma
+ (match-seq prest (cdr expr)
+ (if var
+ (cons (cons var (car expr))
+ subma)
+ subma)
+ (- L 1)))
+ (match-alt (cdr alt) prest expr state var L)))))
+
+; match generalized kleene star (try consuming min to max)
+(def (match-star- p prest expr state var min max L sofar)
+ (cond ; case 0: impossible to match
+ ((> min max) NIL)
+ ; case 1: only allowed to match 0 subexpressions
+ ((= max 0) (match-seq prest expr
+ (if var (cons (cons var (reverse sofar)) state)
+ state)
+ L))
+ ; case 2: must match at least 1
+ ((> min 0)
+ (and (match- p (car expr) state)
+ (match-star- p prest (cdr expr) state var (- min 1) (- max 1) (- L 1)
+ (cons (car expr) sofar))))
+ ; otherwise, must match either 0 or between 1 and max subexpressions
+ (else
+ (or (match-star- p prest expr state var 0 0 L sofar)
+ (match-star- p prest expr state var 1 max L sofar)))))
+(def (match-star p prest expr state var min max L)
+ (match-star- p prest expr state var min max L NIL))
+
+; match sequences of expressions
+(def (match-seq p expr state L)
+ (cond ((not state) NIL)
+ ((not p) (if (not expr) state NIL))
+ (else
+ (let ((subp (car p))
+ (var NIL))
+ (if (and (cons? subp)
+ (eq? (car subp) '--))
+ (begin (set! var (cadr subp))
+ (set! subp (caddr subp)))
+ NIL)
+ (let ((head (if (cons? subp) (car subp) NIL)))
+ (cond ((eq? subp '...)
+ (match-star '_ (cdr p) expr state var 0 L L))
+ ((eq? head '-*)
+ (match-star (cadr subp) (cdr p) expr state var 0 L L))
+ ((eq? head '-+)
+ (match-star (cadr subp) (cdr p) expr state var 1 L L))
+ ((eq? head '-?)
+ (match-star (cadr subp) (cdr p) expr state var 0 1 L))
+ ((eq? head '-$)
+ (match-alt (cdr subp) (cdr p) expr state var L))
+ (else
+ (and (cons? expr)
+ (match-seq (cdr p) (cdr expr)
+ (match- (car p) (car expr) state)
+ (- L 1))))))))))
+
+(def (match p expr) (match- p expr (list (cons '__ expr))))
+
+; given a pattern p, return the list of capturing variables it uses
+(def (patargs- p)
+ (cond ((and (sym? p)
+ (not (member p metasymbols)))
+ (list p))
+
+ ((cons? p)
+ (if (eq? (car p) '-/)
+ NIL
+ (unique (apply append (map patargs- (cdr p))))))
+
+ (else NIL)))
+(def (patargs p)
+ (cons '__ (patargs- p)))
+
+; try to transform expr using a pattern-lambda from plist
+; returns the new expression, or expr if no matches
+(def (apply-patterns plist expr)
+ (if (not plist) expr
+ (if (fn? plist)
+ (let ((enew (plist expr)))
+ (if (not enew)
+ expr
+ enew))
+ (let ((enew ((car plist) expr)))
+ (if (not enew)
+ (apply-patterns (cdr plist) expr)
+ enew)))))
+
+; top-down fixed-point macroexpansion. this is a typical algorithm,
+; but it may leave some structure that matches a pattern unexpanded.
+; the advantage is that non-terminating cases cannot arise as a result
+; of expression composition. in other words, if the outer loop terminates
+; on all inputs for a given set of patterns, then the whole algorithm
+; terminates. pattern sets that violate this should be easier to detect,
+; for example
+; (pattern-lambda (/ 2 3) '(/ 3 2)), (pattern-lambda (/ 3 2) '(/ 2 3))
+; TODO: ignore quoted expressions
+(def (pattern-expand plist expr)
+ (if (not (cons? expr))
+ expr
+ (let ((enew (apply-patterns plist expr)))
+ (if (eq? enew expr)
+ ; expr didn't change; move to subexpressions
+ (cons (car expr)
+ (map (lambda (subex) (pattern-expand plist subex)) (cdr expr)))
+ ; expr changed; iterate
+ (pattern-expand plist enew)))))
--- a/test/ast/rpasses-out.lsp
+++ /dev/null
@@ -1,1701 +1,0 @@
-'(r-expressions (<- Sys.time (lambda ()
- (let () (r-block (r-call structure (r-call
- .Internal (r-call
- Sys.time))
- (*named* class (r-call
- c "POSIXt" "POSIXct")))))))
- (<- Sys.timezone (lambda ()
- (let ()
- (r-block (r-call as.vector (r-call
- Sys.getenv
- "TZ"))))))
- (<- as.POSIXlt (lambda (x tz)
- (let ((x ())
- (tzone ())
- (fromchar ())
- (tz ()))
- (r-block (when (missing tz)
- (<- tz ""))
- (<- fromchar (lambda (x)
- (let ((res ())
- (f ())
- (j ())
- (xx ()))
- (r-block (<-
- xx (r-call r-index x 1))
- (if (r-call is.na xx) (r-block (<- j 1)
- (while (&& (r-call is.na xx)
- (r-call <= (<- j (r-call + j 1))
- (r-call length x)))
- (<- xx (r-call r-index x j)))
- (if (r-call is.na xx)
- (<- f "%Y-%m-%d"))))
- (if (|\|\|| (r-call is.na xx) (r-call ! (r-call is.na (r-call strptime xx
- (<- f "%Y-%m-%d %H:%M:%OS"))))
- (r-call ! (r-call is.na (r-call strptime xx
- (<- f "%Y/%m/%d %H:%M:%OS"))))
- (r-call ! (r-call is.na (r-call strptime xx
- (<- f "%Y-%m-%d %H:%M"))))
- (r-call ! (r-call is.na (r-call strptime xx
- (<- f "%Y/%m/%d %H:%M"))))
- (r-call ! (r-call is.na (r-call strptime xx
- (<- f "%Y-%m-%d"))))
- (r-call ! (r-call is.na (r-call strptime xx
- (<- f "%Y/%m/%d")))))
- (r-block (<- res (r-call strptime x f))
- (if (r-call nchar tz) (r-block (<- res (r-call attr<- res "tzone"
- tz))
- tz))
- (return res)))
- (r-call stop "character string is not in a standard unambiguous format")))))
- (if (r-call inherits x "POSIXlt")
- (return x))
- (if (r-call inherits x "Date")
- (return (r-call .Internal (r-call
- Date2POSIXlt x))))
- (<- tzone (r-call attr x "tzone"))
- (if (|\|\|| (r-call inherits x "date")
- (r-call inherits x "dates"))
- (<- x (r-call as.POSIXct x)))
- (if (r-call is.character x)
- (return (r-call fromchar (r-call
- unclass x))))
- (if (r-call is.factor x)
- (return (r-call fromchar (r-call
- as.character x))))
- (if (&& (r-call is.logical x)
- (r-call all (r-call is.na
- x)))
- (<- x (r-call
- as.POSIXct.default x)))
- (if (r-call ! (r-call inherits x
- "POSIXct"))
- (r-call stop (r-call gettextf
- "do not know how to convert '%s' to class \"POSIXlt\""
- (r-call deparse (substitute x)))))
- (if (&& (missing tz)
- (r-call ! (r-call is.null
- tzone)))
- (<- tz (r-call r-index tzone
- 1)))
- (r-call .Internal (r-call
- as.POSIXlt x
- tz))))))
- (<- as.POSIXct (lambda (x tz)
- (let ((tz ()))
- (r-block (when (missing tz)
- (<- tz ""))
- (r-call UseMethod "as.POSIXct")))))
- (<- as.POSIXct.Date (lambda (x ...)
- (let ()
- (r-block (r-call structure (r-call *
- (r-call unclass x) 86400)
- (*named* class (r-call
- c "POSIXt" "POSIXct")))))))
- (<- as.POSIXct.date (lambda (x ...)
- (let ((x ()))
- (r-block (if (r-call inherits x "date")
- (r-block (<- x (r-call
- * (r-call - x 3653) 86400))
- (return (r-call
- structure x (*named* class (r-call c "POSIXt" "POSIXct")))))
- (r-call stop (r-call
- gettextf "'%s' is not a \"date\" object"
- (r-call deparse (substitute x)))))))))
- (<- as.POSIXct.dates (lambda (x ...)
- (let ((x ())
- (z ()))
- (r-block (if (r-call inherits x "dates")
- (r-block (<- z (r-call
- attr x "origin"))
- (<- x (r-call
- * (r-call as.numeric x) 86400))
- (if (&& (r-call
- == (r-call length z) 3)
- (r-call is.numeric z))
- (<- x (r-call + x
- (r-call as.numeric (r-call ISOdate (r-call r-index z 3)
- (r-call r-index z 1)
- (r-call r-index z 2) 0)))))
- (return (r-call
- structure x (*named* class (r-call c "POSIXt" "POSIXct")))))
- (r-call stop (r-call
- gettextf "'%s' is not a \"dates\" object"
- (r-call deparse (substitute x)))))))))
- (<- as.POSIXct.POSIXlt (lambda (x tz)
- (let ((tzone ())
- (tz ()))
- (r-block (when (missing tz)
- (<- tz ""))
- (<- tzone (r-call attr x
- "tzone"))
- (if (&& (missing tz)
- (r-call ! (r-call
- is.null tzone)))
- (<- tz (r-call
- r-index tzone
- 1)))
- (r-call structure (r-call
- .Internal (r-call as.POSIXct x tz))
- (*named* class (r-call
- c "POSIXt" "POSIXct"))
- (*named* tzone tz))))))
- (<- as.POSIXct.default (lambda (x tz)
- (let ((tz ()))
- (r-block (when (missing tz)
- (<- tz ""))
- (if (r-call inherits x "POSIXct")
- (return x))
- (if (|\|\|| (r-call
- is.character
- x)
- (r-call
- is.factor x))
- (return (r-call
- as.POSIXct
- (r-call
- as.POSIXlt
- x)
- tz)))
- (if (&& (r-call
- is.logical x)
- (r-call all (r-call
- is.na x)))
- (return (r-call
- structure (r-call
- as.numeric x)
- (*named*
- class (r-call
- c "POSIXt" "POSIXct")))))
- (r-call stop (r-call
- gettextf "do not know how to convert '%s' to class \"POSIXlt\""
- (r-call
- deparse (substitute x))))))))
- (<- as.numeric.POSIXlt (lambda (x)
- (let ()
- (r-block (r-call as.POSIXct x)))))
- (<- format.POSIXlt (lambda (x format usetz ...)
- (let ((np ())
- (secs ())
- (times ())
- (usetz ())
- (format ()))
- (r-block (when (missing format)
- (<- format ""))
- (when (missing usetz)
- (<- usetz *r-false*))
- (if (r-call ! (r-call
- inherits x "POSIXlt"))
- (r-call stop "wrong class"))
- (if (r-call == format "")
- (r-block (<- times (r-call
- unlist (r-call r-index (r-call unclass x)
- (r-call : 1 3))))
- (<- secs (r-call
- r-aref x (index-in-strlist sec (r-call attr x #0="names"))))
- (<- secs (r-call
- r-index secs (r-call ! (r-call is.na secs))))
- (<- np (r-call
- getOption "digits.secs"))
- (if (r-call
- is.null np)
- (<- np 0)
- (<- np (r-call
- min 6 np)))
- (if (r-call >=
- np 1)
- (r-block (for
- i (r-call - (r-call : 1 np) 1)
- (if (r-call all (r-call < (r-call abs (r-call - secs
- (r-call round secs i)))
- 9.9999999999999995e-07))
- (r-block (<- np i) (break))))))
- (<- format (if
- (r-call all (r-call == (r-call r-index times
- (r-call ! (r-call is.na times)))
- 0))
- "%Y-%m-%d" (if (r-call == np 0) "%Y-%m-%d %H:%M:%S"
- (r-call paste "%Y-%m-%d %H:%M:%OS" np
- (*named* sep "")))))))
- (r-call .Internal (r-call
- format.POSIXlt x format usetz))))))
- (<- strftime format.POSIXlt)
- (<- strptime (lambda (x format tz)
- (let ((tz ()))
- (r-block (when (missing tz)
- (<- tz ""))
- (r-call .Internal (r-call strptime
- (r-call as.character x) format tz))))))
- (<- format.POSIXct (lambda (x format tz usetz ...)
- (let ((tzone ())
- (usetz ())
- (tz ())
- (format ()))
- (r-block (when (missing format)
- (<- format ""))
- (when (missing tz)
- (<- tz ""))
- (when (missing usetz)
- (<- usetz *r-false*))
- (if (r-call ! (r-call
- inherits x "POSIXct"))
- (r-call stop "wrong class"))
- (if (&& (missing tz)
- (r-call ! (r-call
- is.null (<- tzone (r-call attr x "tzone")))))
- (<- tz tzone))
- (r-call structure (r-call
- format.POSIXlt (r-call as.POSIXlt x tz) format usetz r-dotdotdot)
- (*named* names (r-call
- names x)))))))
- (<- print.POSIXct (lambda (x ...)
- (let ()
- (r-block (r-call print (r-call format
- x (*named* usetz *r-true*) r-dotdotdot)
- r-dotdotdot)
- (r-call invisible x)))))
- (<- print.POSIXlt (lambda (x ...)
- (let ()
- (r-block (r-call print (r-call format
- x (*named* usetz *r-true*))
- r-dotdotdot)
- (r-call invisible x)))))
- (<- summary.POSIXct (lambda (object digits ...)
- (let ((x ())
- (digits ()))
- (r-block (when (missing digits)
- (<- digits 15))
- (<- x (r-call r-index (r-call
- summary.default (r-call unclass object)
- (*named* digits digits) r-dotdotdot)
- (r-call : 1 6)))
- (r-block (ref= %r:1 (r-call
- oldClass object))
- (<- x (r-call
- class<- x
- %r:1))
- %r:1)
- (r-block (ref= %r:2 (r-call
- attr object "tzone"))
- (<- x (r-call
- attr<- x "tzone"
- %r:2))
- %r:2)
- x))))
- (<- summary.POSIXlt (lambda (object digits ...)
- (let ((digits ()))
- (r-block (when (missing digits)
- (<- digits 15))
- (r-call summary (r-call
- as.POSIXct
- object)
- (*named* digits
- digits)
- r-dotdotdot)))))
- (<- "+.POSIXt" (lambda (e1 e2)
- (let ((e2 ())
- (e1 ())
- (coerceTimeUnit ()))
- (r-block (<- coerceTimeUnit (lambda (x)
- (let ()
- (r-block (switch (r-call attr x "units")
- (*named* secs x) (*named* mins (r-call * 60 x))
- (*named* hours (r-call * (r-call * 60 60) x))
- (*named* days (r-call * (r-call * (r-call * 60 60) 24) x))
- (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60)
- 24)
- 7)
- x)))))))
- (if (r-call == (r-call nargs) 1)
- (return e1))
- (if (&& (r-call inherits e1 "POSIXt")
- (r-call inherits e2 "POSIXt"))
- (r-call stop "binary + is not defined for \"POSIXt\" objects"))
- (if (r-call inherits e1 "POSIXlt")
- (<- e1 (r-call as.POSIXct e1)))
- (if (r-call inherits e2 "POSIXlt")
- (<- e2 (r-call as.POSIXct e2)))
- (if (r-call inherits e1 "difftime")
- (<- e1 (r-call coerceTimeUnit
- e1)))
- (if (r-call inherits e2 "difftime")
- (<- e2 (r-call coerceTimeUnit
- e2)))
- (r-call structure (r-call + (r-call
- unclass e1)
- (r-call unclass e2))
- (*named* class (r-call c
- "POSIXt" "POSIXct"))
- (*named* tzone (r-call
- check_tzones e1 e2)))))))
- (<- "-.POSIXt" (lambda (e1 e2)
- (let ((e2 ())
- (coerceTimeUnit ()))
- (r-block (<- coerceTimeUnit (lambda (x)
- (let ()
- (r-block (switch (r-call attr x "units")
- (*named* secs x) (*named* mins (r-call * 60 x))
- (*named* hours (r-call * (r-call * 60 60) x))
- (*named* days (r-call * (r-call * (r-call * 60 60) 24) x))
- (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60)
- 24)
- 7)
- x)))))))
- (if (r-call ! (r-call inherits e1
- "POSIXt"))
- (r-call stop "Can only subtract from POSIXt objects"))
- (if (r-call == (r-call nargs) 1)
- (r-call stop "unary - is not defined for \"POSIXt\" objects"))
- (if (r-call inherits e2 "POSIXt")
- (return (r-call difftime e1
- e2)))
- (if (r-call inherits e2 "difftime")
- (<- e2 (r-call unclass (r-call
- coerceTimeUnit e2))))
- (if (r-call ! (r-call is.null (r-call
- attr e2 "class")))
- (r-call stop "can only subtract numbers from POSIXt objects"))
- (r-call structure (r-call - (r-call
- unclass (r-call as.POSIXct e1))
- e2)
- (*named* class (r-call c
- "POSIXt" "POSIXct")))))))
- (<- Ops.POSIXt (lambda (e1 e2)
- (let ((e2 ())
- (e1 ())
- (boolean ()))
- (r-block (if (r-call == (r-call nargs) 1)
- (r-call stop "unary" .Generic
- " not defined for \"POSIXt\" objects"))
- (<- boolean (switch .Generic (*named*
- < *r-missing*)
- (*named* >
- *r-missing*)
- (*named* ==
- *r-missing*)
- (*named* !=
- *r-missing*)
- (*named* <=
- *r-missing*)
- (*named* >=
- *r-true*)
- *r-false*))
- (if (r-call ! boolean)
- (r-call stop .Generic
- " not defined for \"POSIXt\" objects"))
- (if (|\|\|| (r-call inherits e1
- "POSIXlt")
- (r-call is.character
- e1))
- (<- e1 (r-call as.POSIXct e1)))
- (if (|\|\|| (r-call inherits e2
- "POSIXlt")
- (r-call is.character
- e1))
- (<- e2 (r-call as.POSIXct e2)))
- (r-call check_tzones e1 e2)
- (r-call NextMethod .Generic)))))
- (<- Math.POSIXt (lambda (x ...)
- (let () (r-block (r-call stop .Generic
- " not defined for POSIXt objects")))))
- (<- check_tzones (lambda (...)
- (let ((tzs ()))
- (r-block (<- tzs (r-call unique (r-call
- sapply (r-call list r-dotdotdot) (lambda (x)
- (let ((y ()))
- (r-block (<- y (r-call attr x "tzone"))
- (if (r-call is.null y) "" y)))))))
- (<- tzs (r-call r-index tzs
- (r-call != tzs
- "")))
- (if (r-call > (r-call length
- tzs)
- 1)
- (r-call warning "'tzone' attributes are inconsistent"))
- (if (r-call length tzs)
- (r-call r-index tzs 1)
- ())))))
- (<- Summary.POSIXct (lambda (... na.rm)
- (let ((val ())
- (tz ())
- (args ())
- (ok ()))
- (r-block (<- ok (switch .Generic (*named*
- max *r-missing*)
- (*named* min
- *r-missing*)
- (*named*
- range
- *r-true*)
- *r-false*))
- (if (r-call ! ok)
- (r-call stop .Generic
- " not defined for \"POSIXct\" objects"))
- (<- args (r-call list
- r-dotdotdot))
- (<- tz (r-call do.call "check_tzones"
- args))
- (<- val (r-call NextMethod
- .Generic))
- (r-block (ref= %r:3 (r-call
- oldClass (r-call r-aref args 1)))
- (<- val (r-call
- class<- val %r:3))
- %r:3)
- (r-block (<- val (r-call
- attr<- val "tzone" tz))
- tz)
- val))))
- (<- Summary.POSIXlt (lambda (... na.rm)
- (let ((val ())
- (tz ())
- (args ())
- (ok ()))
- (r-block (<- ok (switch .Generic (*named*
- max *r-missing*)
- (*named* min
- *r-missing*)
- (*named*
- range
- *r-true*)
- *r-false*))
- (if (r-call ! ok)
- (r-call stop .Generic
- " not defined for \"POSIXlt\" objects"))
- (<- args (r-call list
- r-dotdotdot))
- (<- tz (r-call do.call "check_tzones"
- args))
- (<- args (r-call lapply args
- as.POSIXct))
- (<- val (r-call do.call
- .Generic (r-call
- c args (*named* na.rm na.rm))))
- (r-call as.POSIXlt (r-call
- structure val (*named* class (r-call c "POSIXt" "POSIXct"))
- (*named* tzone tz)))))))
- (<- "[.POSIXct" (lambda (x ... drop)
- (let ((val ())
- (x ())
- (cl ())
- (drop ()))
- (r-block (when (missing drop)
- (<- drop *r-true*))
- (<- cl (r-call oldClass x))
- (r-block (<- x (r-call class<-
- x ()))
- ())
- (<- val (r-call NextMethod "["))
- (r-block (<- val (r-call class<-
- val cl))
- cl)
- (r-block (ref= %r:4 (r-call attr
- x "tzone"))
- (<- val (r-call attr<-
- val "tzone" %r:4))
- %r:4)
- val))))
- (<- "[[.POSIXct" (lambda (x ... drop)
- (let ((val ())
- (x ())
- (cl ())
- (drop ()))
- (r-block (when (missing drop)
- (<- drop *r-true*))
- (<- cl (r-call oldClass x))
- (r-block (<- x (r-call class<-
- x ()))
- ())
- (<- val (r-call NextMethod "[["))
- (r-block (<- val (r-call
- class<- val
- cl))
- cl)
- (r-block (ref= %r:5 (r-call
- attr x "tzone"))
- (<- val (r-call attr<-
- val "tzone" %r:5))
- %r:5)
- val))))
- (<- "[<-.POSIXct" (lambda (x ... value)
- (let ((x ())
- (tz ())
- (cl ())
- (value ()))
- (r-block (if (r-call ! (r-call
- as.logical (r-call
- length value)))
- (return x))
- (<- value (r-call as.POSIXct
- value))
- (<- cl (r-call oldClass x))
- (<- tz (r-call attr x "tzone"))
- (r-block (ref= %r:6 (r-block
- (<- value (r-call class<- value
- ()))
- ()))
- (<- x (r-call class<-
- x %r:6))
- %r:6)
- (<- x (r-call NextMethod
- .Generic))
- (r-block (<- x (r-call class<-
- x cl))
- cl)
- (r-block (<- x (r-call attr<-
- x "tzone" tz))
- tz)
- x))))
- (<- as.character.POSIXt (lambda (x ...)
- (let ()
- (r-block (r-call format x
- r-dotdotdot)))))
- (<- as.data.frame.POSIXct as.data.frame.vector)
- (<- is.na.POSIXlt (lambda (x)
- (let ()
- (r-block (r-call is.na (r-call
- as.POSIXct x))))))
- (<- c.POSIXct (lambda (... recursive)
- (let ((recursive ()))
- (r-block (when (missing recursive)
- (<- recursive *r-false*))
- (r-call structure (r-call c (r-call
- unlist (r-call lapply (r-call list r-dotdotdot) unclass)))
- (*named* class (r-call c
- "POSIXt" "POSIXct")))))))
- (<- c.POSIXlt (lambda (... recursive)
- (let ((recursive ()))
- (r-block (when (missing recursive)
- (<- recursive *r-false*))
- (r-call as.POSIXlt (r-call do.call
- "c" (r-call lapply (r-call list r-dotdotdot) as.POSIXct)))))))
- (<- all.equal.POSIXct (lambda (target current ... scale)
- (let ((scale ()))
- (r-block (when (missing scale)
- (<- scale 1))
- (r-call check_tzones
- target current)
- (r-call NextMethod "all.equal")))))
- (<- ISOdatetime (lambda (year month day hour min sec tz)
- (let ((x ())
- (tz ()))
- (r-block (when (missing tz)
- (<- tz ""))
- (<- x (r-call paste year month
- day hour min sec
- (*named* sep "-")))
- (r-call as.POSIXct (r-call
- strptime x
- "%Y-%m-%d-%H-%M-%OS"
- (*named* tz
- tz))
- (*named* tz tz))))))
- (<- ISOdate (lambda (year month day hour min sec tz)
- (let ((tz ())
- (sec ())
- (min ())
- (hour ()))
- (r-block (when (missing hour)
- (<- hour 12))
- (when (missing min)
- (<- min 0))
- (when (missing sec)
- (<- sec 0))
- (when (missing tz)
- (<- tz "GMT"))
- (r-call ISOdatetime year month day
- hour min sec tz)))))
- (<- as.matrix.POSIXlt (lambda (x ...)
- (let ()
- (r-block (r-call as.matrix (r-call
- as.data.frame (r-call unclass x))
- r-dotdotdot)))))
- (<- mean.POSIXct (lambda (x ...)
- (let ()
- (r-block (r-call structure (r-call mean
- (r-call unclass x) r-dotdotdot)
- (*named* class (r-call
- c "POSIXt" "POSIXct"))
- (*named* tzone (r-call
- attr x "tzone")))))))
- (<- mean.POSIXlt (lambda (x ...)
- (let ()
- (r-block (r-call as.POSIXlt (r-call mean
- (r-call as.POSIXct x) r-dotdotdot))))))
- (<- difftime (lambda (time1 time2 tz units)
- (let ((zz ())
- (z ())
- (time2 ())
- (time1 ())
- (units ())
- (tz ()))
- (r-block (when (missing tz)
- (<- tz ""))
- (when (missing units)
- (<- units (r-call c "auto" "secs"
- "mins" "hours"
- "days" "weeks")))
- (<- time1 (r-call as.POSIXct time1
- (*named* tz tz)))
- (<- time2 (r-call as.POSIXct time2
- (*named* tz tz)))
- (<- z (r-call - (r-call unclass
- time1)
- (r-call unclass time2)))
- (<- units (r-call match.arg units))
- (if (r-call == units "auto")
- (r-block (if (r-call all (r-call
- is.na z))
- (<- units "secs")
- (r-block (<- zz (r-call
- min (r-call abs z) (*named* na.rm *r-true*)))
- (if (|\|\|| (r-call is.na zz) (r-call < zz 60))
- (<- units "secs") (if (r-call < zz 3600)
- (<- units "mins")
- (if (r-call < zz 86400)
- (<- units "hours")
- (<- units "days"))))))))
- (switch units (*named* secs (r-call
- structure z (*named* units "secs")
- (*named* class "difftime")))
- (*named* mins (r-call
- structure (r-call
- / z 60)
- (*named*
- units "mins")
- (*named*
- class "difftime")))
- (*named* hours (r-call
- structure
- (r-call /
- z 3600)
- (*named*
- units "hours")
- (*named*
- class "difftime")))
- (*named* days (r-call
- structure (r-call
- / z 86400)
- (*named*
- units "days")
- (*named*
- class "difftime")))
- (*named* weeks (r-call
- structure
- (r-call /
- z (r-call * 7 86400))
- (*named*
- units "weeks")
- (*named*
- class "difftime"))))))))
- (<- as.difftime (lambda (tim format units)
- (let ((units ())
- (format ()))
- (r-block (when (missing format)
- (<- format "%X"))
- (when (missing units)
- (<- units "auto"))
- (if (r-call inherits tim "difftime")
- (return tim))
- (if (r-call is.character tim)
- (r-block (r-call difftime (r-call
- strptime tim (*named* format format))
- (r-call
- strptime "0:0:0" (*named* format "%X"))
- (*named*
- units units)))
- (r-block (if (r-call ! (r-call
- is.numeric tim))
- (r-call stop "'tim' is not character or numeric"))
- (if (r-call ==
- units "auto")
- (r-call stop "need explicit units for numeric conversion"))
- (if (r-call ! (r-call
- %in% units (r-call c "secs" "mins" "hours" "days" "weeks")))
- (r-call stop "invalid units specified"))
- (r-call structure
- tim (*named*
- units units)
- (*named*
- class "difftime"))))))))
- (<- units (lambda (x)
- (let () (r-block (r-call UseMethod "units")))))
- (<- "units<-" (lambda (x value)
- (let () (r-block (r-call UseMethod "units<-")))))
- (<- units.difftime (lambda (x)
- (let ()
- (r-block (r-call attr x "units")))))
- (<- "units<-.difftime" (lambda (x value)
- (let ((newx ())
- (sc ())
- (from ()))
- (r-block (<- from (r-call units x))
- (if (r-call == from value)
- (return x))
- (if (r-call ! (r-call
- %in% value (r-call c "secs" "mins" "hours" "days" "weeks")))
- (r-call stop "invalid units specified"))
- (<- sc (r-call cumprod (r-call
- c (*named* secs 1) (*named* mins 60)
- (*named* hours 60) (*named* days 24) (*named* weeks 7))))
- (<- newx (r-call / (r-call
- * (r-call as.vector x) (r-call r-index sc from))
- (r-call r-index sc value)))
- (r-call structure newx
- (*named* units
- value)
- (*named* class "difftime"))))))
- (<- as.double.difftime (lambda (x units ...)
- (let ((x ())
- (units ()))
- (r-block (when (missing units)
- (<- units "auto"))
- (if (r-call != units "auto")
- (r-block (<- x (r-call
- units<- x units))
- units))
- (r-call as.double (r-call
- as.vector x))))))
- (<- as.data.frame.difftime
- as.data.frame.vector)
- (<- format.difftime (lambda (x ...)
- (let ()
- (r-block (r-call paste (r-call format
- (r-call unclass x) r-dotdotdot)
- (r-call units x))))))
- (<- print.difftime (lambda (x digits ...)
- (let ((y ())
- (digits ()))
- (r-block (when (missing digits)
- (<- digits (r-call
- getOption
- "digits")))
- (if (|\|\|| (r-call is.array
- x)
- (r-call > (r-call
- length x)
- 1))
- (r-block (r-call cat "Time differences in "
- (r-call attr x "units") "\n" (*named* sep ""))
- (<- y (r-call
- unclass x))
- (r-block (<- y
- (r-call attr<- y "units"
- ()))
- ())
- (r-call print y))
- (r-call cat "Time difference of "
- (r-call format (r-call
- unclass x)
- (*named* digits digits))
- " " (r-call attr
- x "units")
- "\n" (*named* sep
- "")))
- (r-call invisible x)))))
- (<- round.difftime (lambda (x digits ...)
- (let ((units ())
- (digits ()))
- (r-block (when (missing digits)
- (<- digits 0))
- (<- units (r-call attr x "units"))
- (r-call structure (r-call
- NextMethod)
- (*named* units units)
- (*named* class "difftime"))))))
- (<- "[.difftime" (lambda (x ... drop)
- (let ((val ())
- (x ())
- (cl ())
- (drop ()))
- (r-block (when (missing drop)
- (<- drop *r-true*))
- (<- cl (r-call oldClass x))
- (r-block (<- x (r-call class<-
- x ()))
- ())
- (<- val (r-call NextMethod "["))
- (r-block (<- val (r-call
- class<- val
- cl))
- cl)
- (r-block (ref= %r:7 (r-call
- attr x "units"))
- (<- val (r-call attr<-
- val "units" %r:7))
- %r:7)
- val))))
- (<- Ops.difftime (lambda (e1 e2)
- (let ((u1 ())
- (e2 ())
- (boolean ())
- (e1 ())
- (coerceTimeUnit ()))
- (r-block (<- coerceTimeUnit (lambda (x)
- (let () (r-block (switch (r-call attr x "units")
- (*named* secs x)
- (*named* mins (r-call * 60 x))
- (*named* hours (r-call * (r-call * 60 60) x))
- (*named* days (r-call * (r-call * (r-call * 60 60)
- 24)
- x))
- (*named* weeks (r-call * (r-call * (r-call * (r-call
- * 60 60)
- 24)
- 7)
- x)))))))
- (if (r-call == (r-call nargs)
- 1)
- (r-block (switch .Generic
- (*named* + (r-block)) (*named* - (r-block (r-block (ref= %r:8 (r-call - (r-call
- unclass e1)))
- (<- e1 (r-call r-index<-
- e1
- *r-missing*
- %r:8))
- %r:8)))
- (r-call stop "unary" .Generic
- " not defined for \"difftime\" objects"))
- (return e1)))
- (<- boolean (switch .Generic (*named*
- < *r-missing*)
- (*named* >
- *r-missing*)
- (*named* ==
- *r-missing*)
- (*named* !=
- *r-missing*)
- (*named* <=
- *r-missing*)
- (*named* >=
- *r-true*)
- *r-false*))
- (if boolean (r-block (if (&& (r-call
- inherits e1 "difftime")
- (r-call inherits e2 "difftime"))
- (r-block (<- e1 (r-call coerceTimeUnit e1))
- (<- e2 (r-call coerceTimeUnit e2))))
- (r-call NextMethod .Generic))
- (if (|\|\|| (r-call ==
- .Generic "+")
- (r-call ==
- .Generic "-"))
- (r-block (if (&& (r-call
- inherits e1 "difftime")
- (r-call ! (r-call inherits e2 "difftime")))
- (return (r-call structure (r-call NextMethod .Generic)
- (*named* units (r-call attr e1 "units"))
- (*named* class "difftime"))))
- (if (&& (r-call
- ! (r-call inherits e1 "difftime"))
- (r-call inherits e2 "difftime"))
- (return (r-call structure (r-call NextMethod .Generic)
- (*named* units (r-call attr e2 "units"))
- (*named* class "difftime"))))
- (<- u1 (r-call
- attr e1 "units"))
- (if (r-call ==
- (r-call attr e2 "units") u1)
- (r-block (r-call structure (r-call NextMethod .Generic)
- (*named* units u1) (*named* class "difftime")))
- (r-block (<- e1 (r-call coerceTimeUnit e1))
- (<- e2 (r-call coerceTimeUnit e2))
- (r-call structure (r-call NextMethod .Generic)
- (*named* units "secs")
- (*named* class "difftime")))))
- (r-block (r-call stop
- .Generic "not defined for \"difftime\" objects"))))))))
- (<- "*.difftime" (lambda (e1 e2)
- (let ((e2 ())
- (e1 ())
- (tmp ()))
- (r-block (if (&& (r-call inherits e1 "difftime")
- (r-call inherits e2 "difftime"))
- (r-call stop "both arguments of * cannot be \"difftime\" objects"))
- (if (r-call inherits e2 "difftime")
- (r-block (<- tmp e1)
- (<- e1 e2)
- (<- e2 tmp)))
- (r-call structure (r-call * e2
- (r-call unclass e1))
- (*named* units (r-call
- attr e1 "units"))
- (*named* class "difftime"))))))
- (<- "/.difftime" (lambda (e1 e2)
- (let ()
- (r-block (if (r-call inherits e2 "difftime")
- (r-call stop "second argument of / cannot be a \"difftime\" object"))
- (r-call structure (r-call / (r-call
- unclass e1)
- e2)
- (*named* units (r-call
- attr e1 "units"))
- (*named* class "difftime"))))))
- (<- Math.difftime (lambda (x ...)
- (let ()
- (r-block (r-call stop .Generic
- "not defined for \"difftime\" objects")))))
- (<- mean.difftime (lambda (x ... na.rm)
- (let ((args ())
- (coerceTimeUnit ())
- (na.rm ()))
- (r-block (when (missing na.rm)
- (<- na.rm *r-false*))
- (<- coerceTimeUnit (lambda (x)
- (let () (r-block (r-call as.vector (switch (r-call attr x "units")
- (*named* secs x)
- (*named* mins (r-call * 60 x))
- (*named* hours (r-call * (r-call
- * 60 60)
- x))
- (*named* days (r-call * (r-call *
- (r-call * 60 60) 24)
- x))
- (*named* weeks (r-call * (r-call
- * (r-call * (r-call * 60 60) 24) 7)
- x))))))))
- (if (r-call length (r-call
- list r-dotdotdot))
- (r-block (<- args (r-call
- c (r-call lapply (r-call list x r-dotdotdot) coerceTimeUnit)
- (*named* na.rm na.rm)))
- (r-call structure
- (r-call do.call "mean" args) (*named* units "secs")
- (*named* class "difftime")))
- (r-block (r-call structure
- (r-call mean (r-call as.vector x)
- (*named* na.rm na.rm))
- (*named* units (r-call attr x "units"))
- (*named* class "difftime"))))))))
- (<- Summary.difftime (lambda (... na.rm)
- (let ((args ())
- (ok ())
- (coerceTimeUnit ()))
- (r-block (<- coerceTimeUnit (lambda (x)
- (let () (r-block (r-call as.vector (switch (r-call attr x "units")
- (*named* secs x)
- (*named* mins (r-call * 60 x))
- (*named* hours (r-call * (r-call
- * 60 60)
- x))
- (*named* days (r-call * (r-call *
- (r-call * 60 60) 24)
- x))
- (*named* weeks (r-call * (r-call
- * (r-call * (r-call * 60 60) 24) 7)
- x))))))))
- (<- ok (switch .Generic (*named*
- max *r-missing*)
- (*named* min
- *r-missing*)
- (*named*
- range
- *r-true*)
- *r-false*))
- (if (r-call ! ok)
- (r-call stop .Generic
- " not defined for \"difftime\" objects"))
- (<- args (r-call c (r-call
- lapply (r-call list r-dotdotdot) coerceTimeUnit)
- (*named* na.rm na.rm)))
- (r-call structure (r-call
- do.call .Generic args)
- (*named* units "secs")
- (*named* class "difftime"))))))
- (<- seq.POSIXt (lambda (from to by length.out along.with ...)
- (let ((mon ())
- (yr ())
- (r1 ())
- (by2 ())
- (by ())
- (valid ())
- (res ())
- (to ())
- (from ())
- (status ())
- (tz ())
- (cfrom ())
- (along.with ())
- (length.out ()))
- (r-block (when (missing length.out)
- (<- length.out ()))
- (when (missing along.with)
- (<- along.with ()))
- (if (missing from)
- (r-call stop "'from' must be specified"))
- (if (r-call ! (r-call inherits
- from "POSIXt"))
- (r-call stop "'from' must be a POSIXt object"))
- (<- cfrom (r-call as.POSIXct from))
- (if (r-call != (r-call length
- cfrom)
- 1)
- (r-call stop "'from' must be of length 1"))
- (<- tz (r-call attr cfrom "tzone"))
- (if (r-call ! (missing to))
- (r-block (if (r-call ! (r-call
- inherits to "POSIXt"))
- (r-call stop "'to' must be a POSIXt object"))
- (if (r-call != (r-call
- length (r-call as.POSIXct to))
- 1)
- (r-call stop "'to' must be of length 1"))))
- (if (r-call ! (missing along.with))
- (r-block (<- length.out (r-call
- length along.with)))
- (if (r-call ! (r-call is.null
- length.out))
- (r-block (if (r-call !=
- (r-call length length.out) 1)
- (r-call stop
- "'length.out' must be of length 1"))
- (<- length.out
- (r-call
- ceiling
- length.out)))))
- (<- status (r-call c (r-call ! (missing
- to))
- (r-call ! (missing
- by))
- (r-call ! (r-call
- is.null length.out))))
- (if (r-call != (r-call sum status)
- 2)
- (r-call stop "exactly two of 'to', 'by' and 'length.out' / 'along.with' must be specified"))
- (if (missing by)
- (r-block (<- from (r-call
- unclass cfrom))
- (<- to (r-call
- unclass (r-call
- as.POSIXct to)))
- (<- res (r-call
- seq.int
- from to (*named*
- length.out length.out)))
- (return (r-call
- structure
- res (*named*
- class (r-call c "POSIXt" "POSIXct"))
- (*named*
- tzone tz)))))
- (if (r-call != (r-call length by)
- 1)
- (r-call stop "'by' must be of length 1"))
- (<- valid 0)
- (if (r-call inherits by "difftime")
- (r-block (<- by (r-call * (switch
- (r-call attr by "units") (*named* secs 1)
- (*named* mins 60) (*named* hours 3600) (*named* days 86400)
- (*named* weeks (r-call * 7 86400)))
- (r-call unclass by))))
- (if (r-call is.character by)
- (r-block (<- by2 (r-call
- r-aref (r-call strsplit by " "
- (*named* fixed *r-true*))
- 1))
- (if (|\|\|| (r-call
- > (r-call length by2) 2)
- (r-call < (r-call length by2) 1))
- (r-call stop
- "invalid 'by' string"))
- (<- valid (r-call
- pmatch (r-call r-index by2
- (r-call length by2))
- (r-call c "secs" "mins" "hours" "days" "weeks" "months" "years" "DSTdays")))
- (if (r-call
- is.na valid)
- (r-call stop
- "invalid string for 'by'"))
- (if (r-call <=
- valid 5)
- (r-block (<-
- by (r-call r-index (r-call c 1 60 3600 86400
- (r-call * 7 86400))
- valid))
- (if (r-call == (r-call length by2) 2) (<- by (r-call * by
- (r-call as.integer (r-call
- r-index by2 1))))))
- (<- by (if
- (r-call == (r-call length by2) 2) (r-call as.integer (r-call r-index by2 1))
- 1))))
- (if (r-call ! (r-call
- is.numeric by))
- (r-call stop "invalid mode for 'by'"))))
- (if (r-call is.na by)
- (r-call stop "'by' is NA"))
- (if (r-call <= valid 5)
- (r-block (<- from (r-call
- unclass (r-call as.POSIXct from)))
- (if (r-call ! (r-call
- is.null length.out))
- (<- res (r-call
- seq.int from (*named* by by)
- (*named* length.out length.out)))
- (r-block (<- to
- (r-call unclass (r-call as.POSIXct to)))
- (<- res (r-call + (r-call seq.int 0
- (r-call - to from) by)
- from))))
- (return (r-call
- structure
- res (*named*
- class (r-call c "POSIXt" "POSIXct"))
- (*named*
- tzone tz))))
- (r-block (<- r1 (r-call
- as.POSIXlt
- from))
- (if (r-call == valid
- 7)
- (r-block (if (missing
- to)
- (r-block (<- yr (r-call seq.int (r-call r-aref r1
- (index-in-strlist year (r-call attr
- r1 #0#)))
- (*named* by by)
- (*named* length length.out))))
- (r-block (<- to (r-call as.POSIXlt to))
- (<- yr (r-call seq.int (r-call r-aref r1
- (index-in-strlist year (r-call attr
- r1 #0#)))
- (r-call r-aref to
- (index-in-strlist year (r-call attr to #0#)))
- by))))
- (r-block (<- r1 (r-call r-aref<- r1
- (index-in-strlist year (r-call attr r1 #0#)) yr))
- yr)
- (r-block (ref= %r:9 (r-call - 1)) (<- r1 (r-call r-aref<- r1
- (index-in-strlist isdst (r-call
- attr r1 #0#))
- %r:9))
- %r:9)
- (<- res (r-call as.POSIXct r1)))
- (if (r-call ==
- valid 6)
- (r-block (if
- (missing to) (r-block (<- mon (r-call seq.int (r-call r-aref r1
- (index-in-strlist mon
- (r-call attr r1 #0#)))
- (*named* by by)
- (*named* length length.out))))
- (r-block (<- to (r-call as.POSIXlt to))
- (<- mon (r-call seq.int (r-call r-aref r1
- (index-in-strlist mon (r-call attr
- r1 #0#)))
- (r-call + (r-call * 12
- (r-call - (r-call r-aref to
- (index-in-strlist
- year (r-call
- attr to #0#)))
- (r-call r-aref r1
- (index-in-strlist
- year (r-call attr
- r1 #0#)))))
- (r-call r-aref to
- (index-in-strlist mon (r-call attr
- to #0#))))
- by))))
- (r-block (<- r1 (r-call r-aref<- r1
- (index-in-strlist mon (r-call attr r1 #0#)) mon))
- mon)
- (r-block (ref= %r:10 (r-call - 1)) (<- r1 (r-call r-aref<- r1
- (index-in-strlist isdst (r-call
- attr r1 #0#))
- %r:10))
- %r:10)
- (<- res (r-call as.POSIXct r1)))
- (if (r-call
- == valid 8)
- (r-block (if (r-call ! (missing to)) (r-block (<- length.out (r-call + 2
- (r-call floor (r-call / (r-call - (r-call unclass (r-call as.POSIXct to))
- (r-call unclass (r-call as.POSIXct from)))
- 86400))))))
- (r-block (ref= %r:11 (r-call seq.int (r-call r-aref r1
- (index-in-strlist mday
- (r-call attr r1 #0#)))
- (*named* by by)
- (*named* length length.out)))
- (<- r1 (r-call r-aref<- r1
- (index-in-strlist mday (r-call attr r1 #0#))
- %r:11))
- %r:11)
- (r-block (ref= %r:12 (r-call - 1))
- (<- r1 (r-call r-aref<- r1
- (index-in-strlist isdst (r-call attr r1 #0#))
- %r:12))
- %r:12)
- (<- res (r-call as.POSIXct r1))
- (if (r-call ! (missing to)) (<- res (r-call r-index res
- (r-call <= res
- (r-call
- as.POSIXct to)))))))))
- (return res)))))))
- (<- cut.POSIXt (lambda (x breaks labels start.on.monday right
- ...)
- (let ((res ())
- (maxx ())
- (incr ())
- (start ())
- (valid ())
- (by2 ())
- (breaks ())
- (x ())
- (right ())
- (start.on.monday ())
- (labels ()))
- (r-block (when (missing labels)
- (<- labels ()))
- (when (missing start.on.monday)
- (<- start.on.monday
- *r-true*))
- (when (missing right)
- (<- right *r-false*))
- (if (r-call ! (r-call inherits x
- "POSIXt"))
- (r-call stop "'x' must be a date-time object"))
- (<- x (r-call as.POSIXct x))
- (if (r-call inherits breaks "POSIXt")
- (r-block (<- breaks (r-call
- as.POSIXct breaks)))
- (if (&& (r-call is.numeric
- breaks)
- (r-call == (r-call
- length breaks)
- 1))
- (r-block)
- (if (&& (r-call
- is.character
- breaks)
- (r-call == (r-call
- length breaks)
- 1))
- (r-block (<- by2 (r-call
- r-aref (r-call strsplit breaks " "
- (*named* fixed *r-true*))
- 1))
- (if (|\|\||
- (r-call > (r-call length by2) 2) (r-call < (r-call length by2) 1))
- (r-call stop "invalid specification of 'breaks'"))
- (<- valid (r-call
- pmatch (r-call r-index by2
- (r-call length by2))
- (r-call c "secs" "mins" "hours" "days" "weeks" "months" "years" "DSTdays")))
- (if (r-call
- is.na valid)
- (r-call stop "invalid specification of 'breaks'"))
- (<- start (r-call
- as.POSIXlt (r-call min x
- (*named* na.rm *r-true*))))
- (<- incr 1)
- (if (r-call
- > valid 1)
- (r-block (r-block (<- start (r-call r-aref<- start
- (index-in-strlist sec (r-call attr start
- #0#))
- 0))
- 0)
- (<- incr 59.990000000000002)))
- (if (r-call
- > valid 2)
- (r-block (r-block (<- start (r-call r-aref<- start
- (index-in-strlist min (r-call attr start
- #0#))
- 0))
- 0)
- (<- incr (r-call - 3600 1))))
- (if (r-call
- > valid 3)
- (r-block (r-block (<- start (r-call r-aref<- start
- (index-in-strlist hour (r-call attr start
- #0#))
- 0))
- 0)
- (<- incr (r-call - 86400 1))))
- (if (r-call
- == valid 5)
- (r-block (r-block (ref= %r:13 (r-call - (r-call r-aref start
- (index-in-strlist mday (r-call
- attr start #0#)))
- (r-call r-aref start
- (index-in-strlist wday (r-call
- attr start #0#)))))
- (<- start (r-call r-aref<- start
- (index-in-strlist mday (r-call attr start
- #0#))
- %r:13))
- %r:13)
- (if start.on.monday (r-block (ref= %r:14 (r-call + (r-call r-aref
- start (index-in-strlist mday (r-call attr start #0#)))
- (r-call ifelse (r-call
- > (r-call r-aref start
- (index-in-strlist wday (r-call attr start #0#)))
- 0)
- 1 (r-call
- - 6))))
- (<- start (r-call r-aref<- start
- (index-in-strlist
- mday (r-call attr
- start #0#))
- %r:14))
- %r:14))
- (<- incr (r-call * 7 86400))))
- (if (r-call
- == valid 6)
- (r-block (r-block (<- start (r-call r-aref<- start
- (index-in-strlist mday (r-call attr start
- #0#))
- 1))
- 1)
- (<- incr (r-call * 31 86400))))
- (if (r-call
- == valid 7)
- (r-block (r-block (<- start (r-call r-aref<- start
- (index-in-strlist mon (r-call attr start
- #0#))
- 0))
- 0)
- (r-block (<- start (r-call r-aref<- start
- (index-in-strlist mday (r-call attr start
- #0#))
- 1))
- 1)
- (<- incr (r-call * 366 86400))))
- (if (r-call
- == valid 8)
- (<- incr (r-call * 25 3600)))
- (if (r-call
- == (r-call length by2) 2)
- (<- incr (r-call * incr
- (r-call as.integer (r-call r-index by2 1)))))
- (<- maxx (r-call
- max x (*named* na.rm *r-true*)))
- (<- breaks
- (r-call seq.int start
- (r-call + maxx incr) breaks))
- (<- breaks
- (r-call r-index breaks
- (r-call : 1
- (r-call + 1
- (r-call max (r-call which (r-call < breaks maxx))))))))
- (r-call stop "invalid specification of 'breaks'"))))
- (<- res (r-call cut (r-call
- unclass x)
- (r-call unclass
- breaks)
- (*named* labels
- labels)
- (*named* right
- right)
- r-dotdotdot))
- (if (r-call is.null labels)
- (r-block (ref= %r:15 (r-call
- as.character (r-call r-index breaks
- (r-call - (r-call length breaks)))))
- (<- res (r-call
- levels<-
- res %r:15))
- %r:15))
- res))))
- (<- julian (lambda (x ...)
- (let () (r-block (r-call UseMethod "julian")))))
- (<- julian.POSIXt (lambda (x origin ...)
- (let ((res ())
- (origin ()))
- (r-block (when (missing origin)
- (<- origin (r-call
- as.POSIXct
- "1970-01-01"
- (*named* tz
- "GMT"))))
- (if (r-call != (r-call length
- origin)
- 1)
- (r-call stop "'origin' must be of length one"))
- (<- res (r-call difftime (r-call
- as.POSIXct x)
- origin (*named*
- units "days")))
- (r-call structure res
- (*named* origin origin))))))
- (<- weekdays (lambda (x abbreviate)
- (let () (r-block (r-call UseMethod "weekdays")))))
- (<- weekdays.POSIXt (lambda (x abbreviate)
- (let ((abbreviate ()))
- (r-block (when (missing abbreviate)
- (<- abbreviate
- *r-false*))
- (r-call format x
- (r-call ifelse
- abbreviate
- "%a" "%A"))))))
- (<- months (lambda (x abbreviate)
- (let () (r-block (r-call UseMethod "months")))))
- (<- months.POSIXt (lambda (x abbreviate)
- (let ((abbreviate ()))
- (r-block (when (missing abbreviate)
- (<- abbreviate *r-false*))
- (r-call format x
- (r-call ifelse
- abbreviate "%b"
- "%B"))))))
- (<- quarters (lambda (x abbreviate)
- (let () (r-block (r-call UseMethod "quarters")))))
- (<- quarters.POSIXt (lambda (x ...)
- (let ((x ()))
- (r-block (<- x (r-call %/% (r-block
- (ref= %r:0 (r-call as.POSIXlt x)) (r-call r-aref %r:0
- (index-in-strlist mon (r-call attr
- %r:0 #0#))))
- 3))
- (r-call paste "Q"
- (r-call + x 1)
- (*named* sep ""))))))
- (<- trunc.POSIXt (lambda (x units)
- (let ((x ())
- (units ()))
- (r-block (when (missing units)
- (<- units (r-call c "secs"
- "mins" "hours" "days")))
- (<- units (r-call match.arg
- units))
- (<- x (r-call as.POSIXlt x))
- (if (r-call > (r-call length (r-call
- r-aref x (index-in-strlist sec (r-call attr x #0#))))
- 0)
- (switch units (*named* secs
- (r-block (r-block (ref= %r:16 (r-call trunc (r-call r-aref x
- (index-in-strlist sec (r-call
- attr x #0#)))))
- (<- x (r-call r-aref<- x
- (index-in-strlist sec (r-call attr x #0#))
- %r:16))
- %r:16)))
- (*named* mins (r-block
- (r-block (<- x (r-call r-aref<- x
- (index-in-strlist sec (r-call attr x #0#)) 0))
- 0)))
- (*named* hours (r-block
- (r-block (<- x (r-call r-aref<- x
- (index-in-strlist sec (r-call attr x #0#)) 0))
- 0)
- (r-block (<- x (r-call r-aref<- x
- (index-in-strlist min (r-call attr x #0#)) 0))
- 0)))
- (*named* days (r-block
- (r-block (<- x (r-call r-aref<- x
- (index-in-strlist sec (r-call attr x #0#)) 0))
- 0)
- (r-block (<- x (r-call r-aref<- x
- (index-in-strlist min (r-call attr x #0#)) 0))
- 0)
- (r-block (<- x (r-call r-aref<- x
- (index-in-strlist hour (r-call attr x #0#)) 0))
- 0)
- (r-block (ref= %r:17 (r-call - 1)) (<- x (r-call r-aref<- x
- (index-in-strlist isdst (r-call
- attr x #0#))
- %r:17))
- %r:17)))))
- x))))
- (<- round.POSIXt (lambda (x units)
- (let ((x ())
- (units ()))
- (r-block (when (missing units)
- (<- units (r-call c "secs"
- "mins" "hours" "days")))
- (if (&& (r-call is.numeric
- units)
- (r-call == units 0))
- (<- units "secs"))
- (<- units (r-call match.arg
- units))
- (<- x (r-call as.POSIXct x))
- (<- x (r-call + x
- (switch units (*named*
- secs 0.5)
- (*named* mins 30) (*named* hours 1800) (*named* days 43200))))
- (r-call trunc.POSIXt x
- (*named* units units))))))
- (<- "[.POSIXlt" (lambda (x ... drop)
- (let ((val ())
- (drop ()))
- (r-block (when (missing drop)
- (<- drop *r-true*))
- (<- val (r-call lapply x "["
- r-dotdotdot (*named*
- drop drop)))
- (r-block (ref= %r:18 (r-call
- attributes x))
- (<- val (r-call
- attributes<-
- val %r:18))
- %r:18)
- val))))
- (<- "[<-.POSIXlt" (lambda (x i value)
- (let ((x ())
- (cl ())
- (value ()))
- (r-block (if (r-call ! (r-call
- as.logical (r-call
- length value)))
- (return x))
- (<- value (r-call as.POSIXlt
- value))
- (<- cl (r-call oldClass x))
- (r-block (ref= %r:19 (r-block
- (<- value (r-call class<- value
- ()))
- ()))
- (<- x (r-call class<-
- x %r:19))
- %r:19)
- (for n (r-call names x)
- (r-block (ref= %r:20 (r-call
- r-aref value n))
- (r-block (ref=
- %r:21 (r-call r-index<- (r-call r-aref x n) i %r:20))
- (<- x (r-call r-aref<- x n %r:21)) %r:21)
- %r:20))
- (r-block (<- x (r-call class<-
- x cl))
- cl)
- x))))
- (<- as.data.frame.POSIXlt (lambda (x row.names optional ...)
- (let ((value ())
- (optional ())
- (row.names ()))
- (r-block (when (missing
- row.names)
- (<- row.names ()))
- (when (missing
- optional)
- (<- optional
- *r-false*))
- (<- value (r-call
- as.data.frame.POSIXct
- (r-call
- as.POSIXct x)
- row.names
- optional
- r-dotdotdot))
- (if (r-call ! optional)
- (r-block (ref=
- %r:22 (r-call r-aref (r-call deparse (substitute x)) 1))
- (<- value (r-call names<- value %r:22)) %r:22))
- value))))
- (<- rep.POSIXct (lambda (x ...)
- (let ((y ()))
- (r-block (<- y (r-call NextMethod))
- (r-call structure y
- (*named* class (r-call
- c "POSIXt" "POSIXct"))
- (*named* tzone (r-call
- attr x "tzone")))))))
- (<- rep.POSIXlt (lambda (x ...)
- (let ((y ()))
- (r-block (<- y (r-call lapply x rep
- r-dotdotdot))
- (r-block (ref= %r:23 (r-call
- attributes x))
- (<- y (r-call
- attributes<- y
- %r:23))
- %r:23)
- y))))
- (<- diff.POSIXt (lambda (x lag differences ...)
- (let ((i1 ())
- (xlen ())
- (r ())
- (ismat ())
- (differences ())
- (lag ()))
- (r-block (when (missing lag)
- (<- lag 1))
- (when (missing differences)
- (<- differences 1))
- (<- ismat (r-call is.matrix x))
- (<- r (if (r-call inherits x "POSIXlt")
- (r-call as.POSIXct x)
- x))
- (<- xlen (if ismat (r-call
- r-index (r-call
- dim x)
- 1)
- (r-call length r)))
- (if (|\|\|| (r-call > (r-call
- length lag)
- 1)
- (r-call > (r-call
- length differences)
- 1)
- (r-call < lag 1)
- (r-call <
- differences
- 1))
- (r-call stop "'lag' and 'differences' must be integers >= 1"))
- (if (r-call >= (r-call * lag
- differences)
- xlen)
- (return (r-call structure (r-call
- numeric 0)
- (*named*
- class "difftime")
- (*named*
- units "secs"))))
- (<- i1 (r-call : (r-call - 1)
- (r-call - lag)))
- (if ismat (for i (r-call : 1
- differences)
- (<- r (r-call - (r-call
- r-index r i1 *r-missing*
- (*named* drop *r-false*))
- (r-call r-index r
- (r-call : (r-call - (r-call nrow r))
- (r-call - (r-call + (r-call - (r-call nrow r) lag) 1)))
- *r-missing* (*named* drop *r-false*)))))
- (for i (r-call : 1
- differences)
- (<- r (r-call - (r-call
- r-index r i1)
- (r-call
- r-index r
- (r-call :
- (r-call - (r-call length r)) (r-call - (r-call + (r-call - (r-call length r)
- lag)
- 1))))))))
- r))))
- (<- duplicated.POSIXlt (lambda (x incomparables ...)
- (let ((x ())
- (incomparables ()))
- (r-block (when (missing
- incomparables)
- (<- incomparables
- *r-false*))
- (<- x (r-call as.POSIXct
- x))
- (r-call NextMethod "duplicated"
- x)))))
- (<- unique.POSIXlt (lambda (x incomparables ...)
- (let ((incomparables ()))
- (r-block (when (missing incomparables)
- (<- incomparables
- *r-false*))
- (r-call r-index x
- (r-call ! (r-call
- duplicated x incomparables r-dotdotdot)))))))
- (<- sort.POSIXlt (lambda (x decreasing na.last ...)
- (let ((na.last ())
- (decreasing ()))
- (r-block (when (missing decreasing)
- (<- decreasing *r-false*))
- (when (missing na.last)
- (<- na.last NA))
- (r-call r-index x
- (r-call order (r-call
- as.POSIXct x)
- (*named*
- na.last
- na.last)
- (*named*
- decreasing
- decreasing))))))))
--- /dev/null
+++ b/test/ast/rpasses-out.sl
@@ -1,0 +1,1701 @@
+'(r-expressions (<- Sys.time (lambda ()
+ (let () (r-block (r-call structure (r-call
+ .Internal (r-call
+ Sys.time))
+ (*named* class (r-call
+ c "POSIXt" "POSIXct")))))))
+ (<- Sys.timezone (lambda ()
+ (let ()
+ (r-block (r-call as.vector (r-call
+ Sys.getenv
+ "TZ"))))))
+ (<- as.POSIXlt (lambda (x tz)
+ (let ((x ())
+ (tzone ())
+ (fromchar ())
+ (tz ()))
+ (r-block (when (missing tz)
+ (<- tz ""))
+ (<- fromchar (lambda (x)
+ (let ((res ())
+ (f ())
+ (j ())
+ (xx ()))
+ (r-block (<-
+ xx (r-call r-index x 1))
+ (if (r-call is.na xx) (r-block (<- j 1)
+ (while (&& (r-call is.na xx)
+ (r-call <= (<- j (r-call + j 1))
+ (r-call length x)))
+ (<- xx (r-call r-index x j)))
+ (if (r-call is.na xx)
+ (<- f "%Y-%m-%d"))))
+ (if (|\|\|| (r-call is.na xx) (r-call ! (r-call is.na (r-call strptime xx
+ (<- f "%Y-%m-%d %H:%M:%OS"))))
+ (r-call ! (r-call is.na (r-call strptime xx
+ (<- f "%Y/%m/%d %H:%M:%OS"))))
+ (r-call ! (r-call is.na (r-call strptime xx
+ (<- f "%Y-%m-%d %H:%M"))))
+ (r-call ! (r-call is.na (r-call strptime xx
+ (<- f "%Y/%m/%d %H:%M"))))
+ (r-call ! (r-call is.na (r-call strptime xx
+ (<- f "%Y-%m-%d"))))
+ (r-call ! (r-call is.na (r-call strptime xx
+ (<- f "%Y/%m/%d")))))
+ (r-block (<- res (r-call strptime x f))
+ (if (r-call nchar tz) (r-block (<- res (r-call attr<- res "tzone"
+ tz))
+ tz))
+ (return res)))
+ (r-call stop "character string is not in a standard unambiguous format")))))
+ (if (r-call inherits x "POSIXlt")
+ (return x))
+ (if (r-call inherits x "Date")
+ (return (r-call .Internal (r-call
+ Date2POSIXlt x))))
+ (<- tzone (r-call attr x "tzone"))
+ (if (|\|\|| (r-call inherits x "date")
+ (r-call inherits x "dates"))
+ (<- x (r-call as.POSIXct x)))
+ (if (r-call is.character x)
+ (return (r-call fromchar (r-call
+ unclass x))))
+ (if (r-call is.factor x)
+ (return (r-call fromchar (r-call
+ as.character x))))
+ (if (&& (r-call is.logical x)
+ (r-call all (r-call is.na
+ x)))
+ (<- x (r-call
+ as.POSIXct.default x)))
+ (if (r-call ! (r-call inherits x
+ "POSIXct"))
+ (r-call stop (r-call gettextf
+ "do not know how to convert '%s' to class \"POSIXlt\""
+ (r-call deparse (substitute x)))))
+ (if (&& (missing tz)
+ (r-call ! (r-call is.null
+ tzone)))
+ (<- tz (r-call r-index tzone
+ 1)))
+ (r-call .Internal (r-call
+ as.POSIXlt x
+ tz))))))
+ (<- as.POSIXct (lambda (x tz)
+ (let ((tz ()))
+ (r-block (when (missing tz)
+ (<- tz ""))
+ (r-call UseMethod "as.POSIXct")))))
+ (<- as.POSIXct.Date (lambda (x ...)
+ (let ()
+ (r-block (r-call structure (r-call *
+ (r-call unclass x) 86400)
+ (*named* class (r-call
+ c "POSIXt" "POSIXct")))))))
+ (<- as.POSIXct.date (lambda (x ...)
+ (let ((x ()))
+ (r-block (if (r-call inherits x "date")
+ (r-block (<- x (r-call
+ * (r-call - x 3653) 86400))
+ (return (r-call
+ structure x (*named* class (r-call c "POSIXt" "POSIXct")))))
+ (r-call stop (r-call
+ gettextf "'%s' is not a \"date\" object"
+ (r-call deparse (substitute x)))))))))
+ (<- as.POSIXct.dates (lambda (x ...)
+ (let ((x ())
+ (z ()))
+ (r-block (if (r-call inherits x "dates")
+ (r-block (<- z (r-call
+ attr x "origin"))
+ (<- x (r-call
+ * (r-call as.numeric x) 86400))
+ (if (&& (r-call
+ == (r-call length z) 3)
+ (r-call is.numeric z))
+ (<- x (r-call + x
+ (r-call as.numeric (r-call ISOdate (r-call r-index z 3)
+ (r-call r-index z 1)
+ (r-call r-index z 2) 0)))))
+ (return (r-call
+ structure x (*named* class (r-call c "POSIXt" "POSIXct")))))
+ (r-call stop (r-call
+ gettextf "'%s' is not a \"dates\" object"
+ (r-call deparse (substitute x)))))))))
+ (<- as.POSIXct.POSIXlt (lambda (x tz)
+ (let ((tzone ())
+ (tz ()))
+ (r-block (when (missing tz)
+ (<- tz ""))
+ (<- tzone (r-call attr x
+ "tzone"))
+ (if (&& (missing tz)
+ (r-call ! (r-call
+ is.null tzone)))
+ (<- tz (r-call
+ r-index tzone
+ 1)))
+ (r-call structure (r-call
+ .Internal (r-call as.POSIXct x tz))
+ (*named* class (r-call
+ c "POSIXt" "POSIXct"))
+ (*named* tzone tz))))))
+ (<- as.POSIXct.default (lambda (x tz)
+ (let ((tz ()))
+ (r-block (when (missing tz)
+ (<- tz ""))
+ (if (r-call inherits x "POSIXct")
+ (return x))
+ (if (|\|\|| (r-call
+ is.character
+ x)
+ (r-call
+ is.factor x))
+ (return (r-call
+ as.POSIXct
+ (r-call
+ as.POSIXlt
+ x)
+ tz)))
+ (if (&& (r-call
+ is.logical x)
+ (r-call all (r-call
+ is.na x)))
+ (return (r-call
+ structure (r-call
+ as.numeric x)
+ (*named*
+ class (r-call
+ c "POSIXt" "POSIXct")))))
+ (r-call stop (r-call
+ gettextf "do not know how to convert '%s' to class \"POSIXlt\""
+ (r-call
+ deparse (substitute x))))))))
+ (<- as.numeric.POSIXlt (lambda (x)
+ (let ()
+ (r-block (r-call as.POSIXct x)))))
+ (<- format.POSIXlt (lambda (x format usetz ...)
+ (let ((np ())
+ (secs ())
+ (times ())
+ (usetz ())
+ (format ()))
+ (r-block (when (missing format)
+ (<- format ""))
+ (when (missing usetz)
+ (<- usetz *r-false*))
+ (if (r-call ! (r-call
+ inherits x "POSIXlt"))
+ (r-call stop "wrong class"))
+ (if (r-call == format "")
+ (r-block (<- times (r-call
+ unlist (r-call r-index (r-call unclass x)
+ (r-call : 1 3))))
+ (<- secs (r-call
+ r-aref x (index-in-strlist sec (r-call attr x #0="names"))))
+ (<- secs (r-call
+ r-index secs (r-call ! (r-call is.na secs))))
+ (<- np (r-call
+ getOption "digits.secs"))
+ (if (r-call
+ is.null np)
+ (<- np 0)
+ (<- np (r-call
+ min 6 np)))
+ (if (r-call >=
+ np 1)
+ (r-block (for
+ i (r-call - (r-call : 1 np) 1)
+ (if (r-call all (r-call < (r-call abs (r-call - secs
+ (r-call round secs i)))
+ 9.9999999999999995e-07))
+ (r-block (<- np i) (break))))))
+ (<- format (if
+ (r-call all (r-call == (r-call r-index times
+ (r-call ! (r-call is.na times)))
+ 0))
+ "%Y-%m-%d" (if (r-call == np 0) "%Y-%m-%d %H:%M:%S"
+ (r-call paste "%Y-%m-%d %H:%M:%OS" np
+ (*named* sep "")))))))
+ (r-call .Internal (r-call
+ format.POSIXlt x format usetz))))))
+ (<- strftime format.POSIXlt)
+ (<- strptime (lambda (x format tz)
+ (let ((tz ()))
+ (r-block (when (missing tz)
+ (<- tz ""))
+ (r-call .Internal (r-call strptime
+ (r-call as.character x) format tz))))))
+ (<- format.POSIXct (lambda (x format tz usetz ...)
+ (let ((tzone ())
+ (usetz ())
+ (tz ())
+ (format ()))
+ (r-block (when (missing format)
+ (<- format ""))
+ (when (missing tz)
+ (<- tz ""))
+ (when (missing usetz)
+ (<- usetz *r-false*))
+ (if (r-call ! (r-call
+ inherits x "POSIXct"))
+ (r-call stop "wrong class"))
+ (if (&& (missing tz)
+ (r-call ! (r-call
+ is.null (<- tzone (r-call attr x "tzone")))))
+ (<- tz tzone))
+ (r-call structure (r-call
+ format.POSIXlt (r-call as.POSIXlt x tz) format usetz r-dotdotdot)
+ (*named* names (r-call
+ names x)))))))
+ (<- print.POSIXct (lambda (x ...)
+ (let ()
+ (r-block (r-call print (r-call format
+ x (*named* usetz *r-true*) r-dotdotdot)
+ r-dotdotdot)
+ (r-call invisible x)))))
+ (<- print.POSIXlt (lambda (x ...)
+ (let ()
+ (r-block (r-call print (r-call format
+ x (*named* usetz *r-true*))
+ r-dotdotdot)
+ (r-call invisible x)))))
+ (<- summary.POSIXct (lambda (object digits ...)
+ (let ((x ())
+ (digits ()))
+ (r-block (when (missing digits)
+ (<- digits 15))
+ (<- x (r-call r-index (r-call
+ summary.default (r-call unclass object)
+ (*named* digits digits) r-dotdotdot)
+ (r-call : 1 6)))
+ (r-block (ref= %r:1 (r-call
+ oldClass object))
+ (<- x (r-call
+ class<- x
+ %r:1))
+ %r:1)
+ (r-block (ref= %r:2 (r-call
+ attr object "tzone"))
+ (<- x (r-call
+ attr<- x "tzone"
+ %r:2))
+ %r:2)
+ x))))
+ (<- summary.POSIXlt (lambda (object digits ...)
+ (let ((digits ()))
+ (r-block (when (missing digits)
+ (<- digits 15))
+ (r-call summary (r-call
+ as.POSIXct
+ object)
+ (*named* digits
+ digits)
+ r-dotdotdot)))))
+ (<- "+.POSIXt" (lambda (e1 e2)
+ (let ((e2 ())
+ (e1 ())
+ (coerceTimeUnit ()))
+ (r-block (<- coerceTimeUnit (lambda (x)
+ (let ()
+ (r-block (switch (r-call attr x "units")
+ (*named* secs x) (*named* mins (r-call * 60 x))
+ (*named* hours (r-call * (r-call * 60 60) x))
+ (*named* days (r-call * (r-call * (r-call * 60 60) 24) x))
+ (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60)
+ 24)
+ 7)
+ x)))))))
+ (if (r-call == (r-call nargs) 1)
+ (return e1))
+ (if (&& (r-call inherits e1 "POSIXt")
+ (r-call inherits e2 "POSIXt"))
+ (r-call stop "binary + is not defined for \"POSIXt\" objects"))
+ (if (r-call inherits e1 "POSIXlt")
+ (<- e1 (r-call as.POSIXct e1)))
+ (if (r-call inherits e2 "POSIXlt")
+ (<- e2 (r-call as.POSIXct e2)))
+ (if (r-call inherits e1 "difftime")
+ (<- e1 (r-call coerceTimeUnit
+ e1)))
+ (if (r-call inherits e2 "difftime")
+ (<- e2 (r-call coerceTimeUnit
+ e2)))
+ (r-call structure (r-call + (r-call
+ unclass e1)
+ (r-call unclass e2))
+ (*named* class (r-call c
+ "POSIXt" "POSIXct"))
+ (*named* tzone (r-call
+ check_tzones e1 e2)))))))
+ (<- "-.POSIXt" (lambda (e1 e2)
+ (let ((e2 ())
+ (coerceTimeUnit ()))
+ (r-block (<- coerceTimeUnit (lambda (x)
+ (let ()
+ (r-block (switch (r-call attr x "units")
+ (*named* secs x) (*named* mins (r-call * 60 x))
+ (*named* hours (r-call * (r-call * 60 60) x))
+ (*named* days (r-call * (r-call * (r-call * 60 60) 24) x))
+ (*named* weeks (r-call * (r-call * (r-call * (r-call * 60 60)
+ 24)
+ 7)
+ x)))))))
+ (if (r-call ! (r-call inherits e1
+ "POSIXt"))
+ (r-call stop "Can only subtract from POSIXt objects"))
+ (if (r-call == (r-call nargs) 1)
+ (r-call stop "unary - is not defined for \"POSIXt\" objects"))
+ (if (r-call inherits e2 "POSIXt")
+ (return (r-call difftime e1
+ e2)))
+ (if (r-call inherits e2 "difftime")
+ (<- e2 (r-call unclass (r-call
+ coerceTimeUnit e2))))
+ (if (r-call ! (r-call is.null (r-call
+ attr e2 "class")))
+ (r-call stop "can only subtract numbers from POSIXt objects"))
+ (r-call structure (r-call - (r-call
+ unclass (r-call as.POSIXct e1))
+ e2)
+ (*named* class (r-call c
+ "POSIXt" "POSIXct")))))))
+ (<- Ops.POSIXt (lambda (e1 e2)
+ (let ((e2 ())
+ (e1 ())
+ (boolean ()))
+ (r-block (if (r-call == (r-call nargs) 1)
+ (r-call stop "unary" .Generic
+ " not defined for \"POSIXt\" objects"))
+ (<- boolean (switch .Generic (*named*
+ < *r-missing*)
+ (*named* >
+ *r-missing*)
+ (*named* ==
+ *r-missing*)
+ (*named* !=
+ *r-missing*)
+ (*named* <=
+ *r-missing*)
+ (*named* >=
+ *r-true*)
+ *r-false*))
+ (if (r-call ! boolean)
+ (r-call stop .Generic
+ " not defined for \"POSIXt\" objects"))
+ (if (|\|\|| (r-call inherits e1
+ "POSIXlt")
+ (r-call is.character
+ e1))
+ (<- e1 (r-call as.POSIXct e1)))
+ (if (|\|\|| (r-call inherits e2
+ "POSIXlt")
+ (r-call is.character
+ e1))
+ (<- e2 (r-call as.POSIXct e2)))
+ (r-call check_tzones e1 e2)
+ (r-call NextMethod .Generic)))))
+ (<- Math.POSIXt (lambda (x ...)
+ (let () (r-block (r-call stop .Generic
+ " not defined for POSIXt objects")))))
+ (<- check_tzones (lambda (...)
+ (let ((tzs ()))
+ (r-block (<- tzs (r-call unique (r-call
+ sapply (r-call list r-dotdotdot) (lambda (x)
+ (let ((y ()))
+ (r-block (<- y (r-call attr x "tzone"))
+ (if (r-call is.null y) "" y)))))))
+ (<- tzs (r-call r-index tzs
+ (r-call != tzs
+ "")))
+ (if (r-call > (r-call length
+ tzs)
+ 1)
+ (r-call warning "'tzone' attributes are inconsistent"))
+ (if (r-call length tzs)
+ (r-call r-index tzs 1)
+ ())))))
+ (<- Summary.POSIXct (lambda (... na.rm)
+ (let ((val ())
+ (tz ())
+ (args ())
+ (ok ()))
+ (r-block (<- ok (switch .Generic (*named*
+ max *r-missing*)
+ (*named* min
+ *r-missing*)
+ (*named*
+ range
+ *r-true*)
+ *r-false*))
+ (if (r-call ! ok)
+ (r-call stop .Generic
+ " not defined for \"POSIXct\" objects"))
+ (<- args (r-call list
+ r-dotdotdot))
+ (<- tz (r-call do.call "check_tzones"
+ args))
+ (<- val (r-call NextMethod
+ .Generic))
+ (r-block (ref= %r:3 (r-call
+ oldClass (r-call r-aref args 1)))
+ (<- val (r-call
+ class<- val %r:3))
+ %r:3)
+ (r-block (<- val (r-call
+ attr<- val "tzone" tz))
+ tz)
+ val))))
+ (<- Summary.POSIXlt (lambda (... na.rm)
+ (let ((val ())
+ (tz ())
+ (args ())
+ (ok ()))
+ (r-block (<- ok (switch .Generic (*named*
+ max *r-missing*)
+ (*named* min
+ *r-missing*)
+ (*named*
+ range
+ *r-true*)
+ *r-false*))
+ (if (r-call ! ok)
+ (r-call stop .Generic
+ " not defined for \"POSIXlt\" objects"))
+ (<- args (r-call list
+ r-dotdotdot))
+ (<- tz (r-call do.call "check_tzones"
+ args))
+ (<- args (r-call lapply args
+ as.POSIXct))
+ (<- val (r-call do.call
+ .Generic (r-call
+ c args (*named* na.rm na.rm))))
+ (r-call as.POSIXlt (r-call
+ structure val (*named* class (r-call c "POSIXt" "POSIXct"))
+ (*named* tzone tz)))))))
+ (<- "[.POSIXct" (lambda (x ... drop)
+ (let ((val ())
+ (x ())
+ (cl ())
+ (drop ()))
+ (r-block (when (missing drop)
+ (<- drop *r-true*))
+ (<- cl (r-call oldClass x))
+ (r-block (<- x (r-call class<-
+ x ()))
+ ())
+ (<- val (r-call NextMethod "["))
+ (r-block (<- val (r-call class<-
+ val cl))
+ cl)
+ (r-block (ref= %r:4 (r-call attr
+ x "tzone"))
+ (<- val (r-call attr<-
+ val "tzone" %r:4))
+ %r:4)
+ val))))
+ (<- "[[.POSIXct" (lambda (x ... drop)
+ (let ((val ())
+ (x ())
+ (cl ())
+ (drop ()))
+ (r-block (when (missing drop)
+ (<- drop *r-true*))
+ (<- cl (r-call oldClass x))
+ (r-block (<- x (r-call class<-
+ x ()))
+ ())
+ (<- val (r-call NextMethod "[["))
+ (r-block (<- val (r-call
+ class<- val
+ cl))
+ cl)
+ (r-block (ref= %r:5 (r-call
+ attr x "tzone"))
+ (<- val (r-call attr<-
+ val "tzone" %r:5))
+ %r:5)
+ val))))
+ (<- "[<-.POSIXct" (lambda (x ... value)
+ (let ((x ())
+ (tz ())
+ (cl ())
+ (value ()))
+ (r-block (if (r-call ! (r-call
+ as.logical (r-call
+ length value)))
+ (return x))
+ (<- value (r-call as.POSIXct
+ value))
+ (<- cl (r-call oldClass x))
+ (<- tz (r-call attr x "tzone"))
+ (r-block (ref= %r:6 (r-block
+ (<- value (r-call class<- value
+ ()))
+ ()))
+ (<- x (r-call class<-
+ x %r:6))
+ %r:6)
+ (<- x (r-call NextMethod
+ .Generic))
+ (r-block (<- x (r-call class<-
+ x cl))
+ cl)
+ (r-block (<- x (r-call attr<-
+ x "tzone" tz))
+ tz)
+ x))))
+ (<- as.character.POSIXt (lambda (x ...)
+ (let ()
+ (r-block (r-call format x
+ r-dotdotdot)))))
+ (<- as.data.frame.POSIXct as.data.frame.vector)
+ (<- is.na.POSIXlt (lambda (x)
+ (let ()
+ (r-block (r-call is.na (r-call
+ as.POSIXct x))))))
+ (<- c.POSIXct (lambda (... recursive)
+ (let ((recursive ()))
+ (r-block (when (missing recursive)
+ (<- recursive *r-false*))
+ (r-call structure (r-call c (r-call
+ unlist (r-call lapply (r-call list r-dotdotdot) unclass)))
+ (*named* class (r-call c
+ "POSIXt" "POSIXct")))))))
+ (<- c.POSIXlt (lambda (... recursive)
+ (let ((recursive ()))
+ (r-block (when (missing recursive)
+ (<- recursive *r-false*))
+ (r-call as.POSIXlt (r-call do.call
+ "c" (r-call lapply (r-call list r-dotdotdot) as.POSIXct)))))))
+ (<- all.equal.POSIXct (lambda (target current ... scale)
+ (let ((scale ()))
+ (r-block (when (missing scale)
+ (<- scale 1))
+ (r-call check_tzones
+ target current)
+ (r-call NextMethod "all.equal")))))
+ (<- ISOdatetime (lambda (year month day hour min sec tz)
+ (let ((x ())
+ (tz ()))
+ (r-block (when (missing tz)
+ (<- tz ""))
+ (<- x (r-call paste year month
+ day hour min sec
+ (*named* sep "-")))
+ (r-call as.POSIXct (r-call
+ strptime x
+ "%Y-%m-%d-%H-%M-%OS"
+ (*named* tz
+ tz))
+ (*named* tz tz))))))
+ (<- ISOdate (lambda (year month day hour min sec tz)
+ (let ((tz ())
+ (sec ())
+ (min ())
+ (hour ()))
+ (r-block (when (missing hour)
+ (<- hour 12))
+ (when (missing min)
+ (<- min 0))
+ (when (missing sec)
+ (<- sec 0))
+ (when (missing tz)
+ (<- tz "GMT"))
+ (r-call ISOdatetime year month day
+ hour min sec tz)))))
+ (<- as.matrix.POSIXlt (lambda (x ...)
+ (let ()
+ (r-block (r-call as.matrix (r-call
+ as.data.frame (r-call unclass x))
+ r-dotdotdot)))))
+ (<- mean.POSIXct (lambda (x ...)
+ (let ()
+ (r-block (r-call structure (r-call mean
+ (r-call unclass x) r-dotdotdot)
+ (*named* class (r-call
+ c "POSIXt" "POSIXct"))
+ (*named* tzone (r-call
+ attr x "tzone")))))))
+ (<- mean.POSIXlt (lambda (x ...)
+ (let ()
+ (r-block (r-call as.POSIXlt (r-call mean
+ (r-call as.POSIXct x) r-dotdotdot))))))
+ (<- difftime (lambda (time1 time2 tz units)
+ (let ((zz ())
+ (z ())
+ (time2 ())
+ (time1 ())
+ (units ())
+ (tz ()))
+ (r-block (when (missing tz)
+ (<- tz ""))
+ (when (missing units)
+ (<- units (r-call c "auto" "secs"
+ "mins" "hours"
+ "days" "weeks")))
+ (<- time1 (r-call as.POSIXct time1
+ (*named* tz tz)))
+ (<- time2 (r-call as.POSIXct time2
+ (*named* tz tz)))
+ (<- z (r-call - (r-call unclass
+ time1)
+ (r-call unclass time2)))
+ (<- units (r-call match.arg units))
+ (if (r-call == units "auto")
+ (r-block (if (r-call all (r-call
+ is.na z))
+ (<- units "secs")
+ (r-block (<- zz (r-call
+ min (r-call abs z) (*named* na.rm *r-true*)))
+ (if (|\|\|| (r-call is.na zz) (r-call < zz 60))
+ (<- units "secs") (if (r-call < zz 3600)
+ (<- units "mins")
+ (if (r-call < zz 86400)
+ (<- units "hours")
+ (<- units "days"))))))))
+ (switch units (*named* secs (r-call
+ structure z (*named* units "secs")
+ (*named* class "difftime")))
+ (*named* mins (r-call
+ structure (r-call
+ / z 60)
+ (*named*
+ units "mins")
+ (*named*
+ class "difftime")))
+ (*named* hours (r-call
+ structure
+ (r-call /
+ z 3600)
+ (*named*
+ units "hours")
+ (*named*
+ class "difftime")))
+ (*named* days (r-call
+ structure (r-call
+ / z 86400)
+ (*named*
+ units "days")
+ (*named*
+ class "difftime")))
+ (*named* weeks (r-call
+ structure
+ (r-call /
+ z (r-call * 7 86400))
+ (*named*
+ units "weeks")
+ (*named*
+ class "difftime"))))))))
+ (<- as.difftime (lambda (tim format units)
+ (let ((units ())
+ (format ()))
+ (r-block (when (missing format)
+ (<- format "%X"))
+ (when (missing units)
+ (<- units "auto"))
+ (if (r-call inherits tim "difftime")
+ (return tim))
+ (if (r-call is.character tim)
+ (r-block (r-call difftime (r-call
+ strptime tim (*named* format format))
+ (r-call
+ strptime "0:0:0" (*named* format "%X"))
+ (*named*
+ units units)))
+ (r-block (if (r-call ! (r-call
+ is.numeric tim))
+ (r-call stop "'tim' is not character or numeric"))
+ (if (r-call ==
+ units "auto")
+ (r-call stop "need explicit units for numeric conversion"))
+ (if (r-call ! (r-call
+ %in% units (r-call c "secs" "mins" "hours" "days" "weeks")))
+ (r-call stop "invalid units specified"))
+ (r-call structure
+ tim (*named*
+ units units)
+ (*named*
+ class "difftime"))))))))
+ (<- units (lambda (x)
+ (let () (r-block (r-call UseMethod "units")))))
+ (<- "units<-" (lambda (x value)
+ (let () (r-block (r-call UseMethod "units<-")))))
+ (<- units.difftime (lambda (x)
+ (let ()
+ (r-block (r-call attr x "units")))))
+ (<- "units<-.difftime" (lambda (x value)
+ (let ((newx ())
+ (sc ())
+ (from ()))
+ (r-block (<- from (r-call units x))
+ (if (r-call == from value)
+ (return x))
+ (if (r-call ! (r-call
+ %in% value (r-call c "secs" "mins" "hours" "days" "weeks")))
+ (r-call stop "invalid units specified"))
+ (<- sc (r-call cumprod (r-call
+ c (*named* secs 1) (*named* mins 60)
+ (*named* hours 60) (*named* days 24) (*named* weeks 7))))
+ (<- newx (r-call / (r-call
+ * (r-call as.vector x) (r-call r-index sc from))
+ (r-call r-index sc value)))
+ (r-call structure newx
+ (*named* units
+ value)
+ (*named* class "difftime"))))))
+ (<- as.double.difftime (lambda (x units ...)
+ (let ((x ())
+ (units ()))
+ (r-block (when (missing units)
+ (<- units "auto"))
+ (if (r-call != units "auto")
+ (r-block (<- x (r-call
+ units<- x units))
+ units))
+ (r-call as.double (r-call
+ as.vector x))))))
+ (<- as.data.frame.difftime
+ as.data.frame.vector)
+ (<- format.difftime (lambda (x ...)
+ (let ()
+ (r-block (r-call paste (r-call format
+ (r-call unclass x) r-dotdotdot)
+ (r-call units x))))))
+ (<- print.difftime (lambda (x digits ...)
+ (let ((y ())
+ (digits ()))
+ (r-block (when (missing digits)
+ (<- digits (r-call
+ getOption
+ "digits")))
+ (if (|\|\|| (r-call is.array
+ x)
+ (r-call > (r-call
+ length x)
+ 1))
+ (r-block (r-call cat "Time differences in "
+ (r-call attr x "units") "\n" (*named* sep ""))
+ (<- y (r-call
+ unclass x))
+ (r-block (<- y
+ (r-call attr<- y "units"
+ ()))
+ ())
+ (r-call print y))
+ (r-call cat "Time difference of "
+ (r-call format (r-call
+ unclass x)
+ (*named* digits digits))
+ " " (r-call attr
+ x "units")
+ "\n" (*named* sep
+ "")))
+ (r-call invisible x)))))
+ (<- round.difftime (lambda (x digits ...)
+ (let ((units ())
+ (digits ()))
+ (r-block (when (missing digits)
+ (<- digits 0))
+ (<- units (r-call attr x "units"))
+ (r-call structure (r-call
+ NextMethod)
+ (*named* units units)
+ (*named* class "difftime"))))))
+ (<- "[.difftime" (lambda (x ... drop)
+ (let ((val ())
+ (x ())
+ (cl ())
+ (drop ()))
+ (r-block (when (missing drop)
+ (<- drop *r-true*))
+ (<- cl (r-call oldClass x))
+ (r-block (<- x (r-call class<-
+ x ()))
+ ())
+ (<- val (r-call NextMethod "["))
+ (r-block (<- val (r-call
+ class<- val
+ cl))
+ cl)
+ (r-block (ref= %r:7 (r-call
+ attr x "units"))
+ (<- val (r-call attr<-
+ val "units" %r:7))
+ %r:7)
+ val))))
+ (<- Ops.difftime (lambda (e1 e2)
+ (let ((u1 ())
+ (e2 ())
+ (boolean ())
+ (e1 ())
+ (coerceTimeUnit ()))
+ (r-block (<- coerceTimeUnit (lambda (x)
+ (let () (r-block (switch (r-call attr x "units")
+ (*named* secs x)
+ (*named* mins (r-call * 60 x))
+ (*named* hours (r-call * (r-call * 60 60) x))
+ (*named* days (r-call * (r-call * (r-call * 60 60)
+ 24)
+ x))
+ (*named* weeks (r-call * (r-call * (r-call * (r-call
+ * 60 60)
+ 24)
+ 7)
+ x)))))))
+ (if (r-call == (r-call nargs)
+ 1)
+ (r-block (switch .Generic
+ (*named* + (r-block)) (*named* - (r-block (r-block (ref= %r:8 (r-call - (r-call
+ unclass e1)))
+ (<- e1 (r-call r-index<-
+ e1
+ *r-missing*
+ %r:8))
+ %r:8)))
+ (r-call stop "unary" .Generic
+ " not defined for \"difftime\" objects"))
+ (return e1)))
+ (<- boolean (switch .Generic (*named*
+ < *r-missing*)
+ (*named* >
+ *r-missing*)
+ (*named* ==
+ *r-missing*)
+ (*named* !=
+ *r-missing*)
+ (*named* <=
+ *r-missing*)
+ (*named* >=
+ *r-true*)
+ *r-false*))
+ (if boolean (r-block (if (&& (r-call
+ inherits e1 "difftime")
+ (r-call inherits e2 "difftime"))
+ (r-block (<- e1 (r-call coerceTimeUnit e1))
+ (<- e2 (r-call coerceTimeUnit e2))))
+ (r-call NextMethod .Generic))
+ (if (|\|\|| (r-call ==
+ .Generic "+")
+ (r-call ==
+ .Generic "-"))
+ (r-block (if (&& (r-call
+ inherits e1 "difftime")
+ (r-call ! (r-call inherits e2 "difftime")))
+ (return (r-call structure (r-call NextMethod .Generic)
+ (*named* units (r-call attr e1 "units"))
+ (*named* class "difftime"))))
+ (if (&& (r-call
+ ! (r-call inherits e1 "difftime"))
+ (r-call inherits e2 "difftime"))
+ (return (r-call structure (r-call NextMethod .Generic)
+ (*named* units (r-call attr e2 "units"))
+ (*named* class "difftime"))))
+ (<- u1 (r-call
+ attr e1 "units"))
+ (if (r-call ==
+ (r-call attr e2 "units") u1)
+ (r-block (r-call structure (r-call NextMethod .Generic)
+ (*named* units u1) (*named* class "difftime")))
+ (r-block (<- e1 (r-call coerceTimeUnit e1))
+ (<- e2 (r-call coerceTimeUnit e2))
+ (r-call structure (r-call NextMethod .Generic)
+ (*named* units "secs")
+ (*named* class "difftime")))))
+ (r-block (r-call stop
+ .Generic "not defined for \"difftime\" objects"))))))))
+ (<- "*.difftime" (lambda (e1 e2)
+ (let ((e2 ())
+ (e1 ())
+ (tmp ()))
+ (r-block (if (&& (r-call inherits e1 "difftime")
+ (r-call inherits e2 "difftime"))
+ (r-call stop "both arguments of * cannot be \"difftime\" objects"))
+ (if (r-call inherits e2 "difftime")
+ (r-block (<- tmp e1)
+ (<- e1 e2)
+ (<- e2 tmp)))
+ (r-call structure (r-call * e2
+ (r-call unclass e1))
+ (*named* units (r-call
+ attr e1 "units"))
+ (*named* class "difftime"))))))
+ (<- "/.difftime" (lambda (e1 e2)
+ (let ()
+ (r-block (if (r-call inherits e2 "difftime")
+ (r-call stop "second argument of / cannot be a \"difftime\" object"))
+ (r-call structure (r-call / (r-call
+ unclass e1)
+ e2)
+ (*named* units (r-call
+ attr e1 "units"))
+ (*named* class "difftime"))))))
+ (<- Math.difftime (lambda (x ...)
+ (let ()
+ (r-block (r-call stop .Generic
+ "not defined for \"difftime\" objects")))))
+ (<- mean.difftime (lambda (x ... na.rm)
+ (let ((args ())
+ (coerceTimeUnit ())
+ (na.rm ()))
+ (r-block (when (missing na.rm)
+ (<- na.rm *r-false*))
+ (<- coerceTimeUnit (lambda (x)
+ (let () (r-block (r-call as.vector (switch (r-call attr x "units")
+ (*named* secs x)
+ (*named* mins (r-call * 60 x))
+ (*named* hours (r-call * (r-call
+ * 60 60)
+ x))
+ (*named* days (r-call * (r-call *
+ (r-call * 60 60) 24)
+ x))
+ (*named* weeks (r-call * (r-call
+ * (r-call * (r-call * 60 60) 24) 7)
+ x))))))))
+ (if (r-call length (r-call
+ list r-dotdotdot))
+ (r-block (<- args (r-call
+ c (r-call lapply (r-call list x r-dotdotdot) coerceTimeUnit)
+ (*named* na.rm na.rm)))
+ (r-call structure
+ (r-call do.call "mean" args) (*named* units "secs")
+ (*named* class "difftime")))
+ (r-block (r-call structure
+ (r-call mean (r-call as.vector x)
+ (*named* na.rm na.rm))
+ (*named* units (r-call attr x "units"))
+ (*named* class "difftime"))))))))
+ (<- Summary.difftime (lambda (... na.rm)
+ (let ((args ())
+ (ok ())
+ (coerceTimeUnit ()))
+ (r-block (<- coerceTimeUnit (lambda (x)
+ (let () (r-block (r-call as.vector (switch (r-call attr x "units")
+ (*named* secs x)
+ (*named* mins (r-call * 60 x))
+ (*named* hours (r-call * (r-call
+ * 60 60)
+ x))
+ (*named* days (r-call * (r-call *
+ (r-call * 60 60) 24)
+ x))
+ (*named* weeks (r-call * (r-call
+ * (r-call * (r-call * 60 60) 24) 7)
+ x))))))))
+ (<- ok (switch .Generic (*named*
+ max *r-missing*)
+ (*named* min
+ *r-missing*)
+ (*named*
+ range
+ *r-true*)
+ *r-false*))
+ (if (r-call ! ok)
+ (r-call stop .Generic
+ " not defined for \"difftime\" objects"))
+ (<- args (r-call c (r-call
+ lapply (r-call list r-dotdotdot) coerceTimeUnit)
+ (*named* na.rm na.rm)))
+ (r-call structure (r-call
+ do.call .Generic args)
+ (*named* units "secs")
+ (*named* class "difftime"))))))
+ (<- seq.POSIXt (lambda (from to by length.out along.with ...)
+ (let ((mon ())
+ (yr ())
+ (r1 ())
+ (by2 ())
+ (by ())
+ (valid ())
+ (res ())
+ (to ())
+ (from ())
+ (status ())
+ (tz ())
+ (cfrom ())
+ (along.with ())
+ (length.out ()))
+ (r-block (when (missing length.out)
+ (<- length.out ()))
+ (when (missing along.with)
+ (<- along.with ()))
+ (if (missing from)
+ (r-call stop "'from' must be specified"))
+ (if (r-call ! (r-call inherits
+ from "POSIXt"))
+ (r-call stop "'from' must be a POSIXt object"))
+ (<- cfrom (r-call as.POSIXct from))
+ (if (r-call != (r-call length
+ cfrom)
+ 1)
+ (r-call stop "'from' must be of length 1"))
+ (<- tz (r-call attr cfrom "tzone"))
+ (if (r-call ! (missing to))
+ (r-block (if (r-call ! (r-call
+ inherits to "POSIXt"))
+ (r-call stop "'to' must be a POSIXt object"))
+ (if (r-call != (r-call
+ length (r-call as.POSIXct to))
+ 1)
+ (r-call stop "'to' must be of length 1"))))
+ (if (r-call ! (missing along.with))
+ (r-block (<- length.out (r-call
+ length along.with)))
+ (if (r-call ! (r-call is.null
+ length.out))
+ (r-block (if (r-call !=
+ (r-call length length.out) 1)
+ (r-call stop
+ "'length.out' must be of length 1"))
+ (<- length.out
+ (r-call
+ ceiling
+ length.out)))))
+ (<- status (r-call c (r-call ! (missing
+ to))
+ (r-call ! (missing
+ by))
+ (r-call ! (r-call
+ is.null length.out))))
+ (if (r-call != (r-call sum status)
+ 2)
+ (r-call stop "exactly two of 'to', 'by' and 'length.out' / 'along.with' must be specified"))
+ (if (missing by)
+ (r-block (<- from (r-call
+ unclass cfrom))
+ (<- to (r-call
+ unclass (r-call
+ as.POSIXct to)))
+ (<- res (r-call
+ seq.int
+ from to (*named*
+ length.out length.out)))
+ (return (r-call
+ structure
+ res (*named*
+ class (r-call c "POSIXt" "POSIXct"))
+ (*named*
+ tzone tz)))))
+ (if (r-call != (r-call length by)
+ 1)
+ (r-call stop "'by' must be of length 1"))
+ (<- valid 0)
+ (if (r-call inherits by "difftime")
+ (r-block (<- by (r-call * (switch
+ (r-call attr by "units") (*named* secs 1)
+ (*named* mins 60) (*named* hours 3600) (*named* days 86400)
+ (*named* weeks (r-call * 7 86400)))
+ (r-call unclass by))))
+ (if (r-call is.character by)
+ (r-block (<- by2 (r-call
+ r-aref (r-call strsplit by " "
+ (*named* fixed *r-true*))
+ 1))
+ (if (|\|\|| (r-call
+ > (r-call length by2) 2)
+ (r-call < (r-call length by2) 1))
+ (r-call stop
+ "invalid 'by' string"))
+ (<- valid (r-call
+ pmatch (r-call r-index by2
+ (r-call length by2))
+ (r-call c "secs" "mins" "hours" "days" "weeks" "months" "years" "DSTdays")))
+ (if (r-call
+ is.na valid)
+ (r-call stop
+ "invalid string for 'by'"))
+ (if (r-call <=
+ valid 5)
+ (r-block (<-
+ by (r-call r-index (r-call c 1 60 3600 86400
+ (r-call * 7 86400))
+ valid))
+ (if (r-call == (r-call length by2) 2) (<- by (r-call * by
+ (r-call as.integer (r-call
+ r-index by2 1))))))
+ (<- by (if
+ (r-call == (r-call length by2) 2) (r-call as.integer (r-call r-index by2 1))
+ 1))))
+ (if (r-call ! (r-call
+ is.numeric by))
+ (r-call stop "invalid mode for 'by'"))))
+ (if (r-call is.na by)
+ (r-call stop "'by' is NA"))
+ (if (r-call <= valid 5)
+ (r-block (<- from (r-call
+ unclass (r-call as.POSIXct from)))
+ (if (r-call ! (r-call
+ is.null length.out))
+ (<- res (r-call
+ seq.int from (*named* by by)
+ (*named* length.out length.out)))
+ (r-block (<- to
+ (r-call unclass (r-call as.POSIXct to)))
+ (<- res (r-call + (r-call seq.int 0
+ (r-call - to from) by)
+ from))))
+ (return (r-call
+ structure
+ res (*named*
+ class (r-call c "POSIXt" "POSIXct"))
+ (*named*
+ tzone tz))))
+ (r-block (<- r1 (r-call
+ as.POSIXlt
+ from))
+ (if (r-call == valid
+ 7)
+ (r-block (if (missing
+ to)
+ (r-block (<- yr (r-call seq.int (r-call r-aref r1
+ (index-in-strlist year (r-call attr
+ r1 #0#)))
+ (*named* by by)
+ (*named* length length.out))))
+ (r-block (<- to (r-call as.POSIXlt to))
+ (<- yr (r-call seq.int (r-call r-aref r1
+ (index-in-strlist year (r-call attr
+ r1 #0#)))
+ (r-call r-aref to
+ (index-in-strlist year (r-call attr to #0#)))
+ by))))
+ (r-block (<- r1 (r-call r-aref<- r1
+ (index-in-strlist year (r-call attr r1 #0#)) yr))
+ yr)
+ (r-block (ref= %r:9 (r-call - 1)) (<- r1 (r-call r-aref<- r1
+ (index-in-strlist isdst (r-call
+ attr r1 #0#))
+ %r:9))
+ %r:9)
+ (<- res (r-call as.POSIXct r1)))
+ (if (r-call ==
+ valid 6)
+ (r-block (if
+ (missing to) (r-block (<- mon (r-call seq.int (r-call r-aref r1
+ (index-in-strlist mon
+ (r-call attr r1 #0#)))
+ (*named* by by)
+ (*named* length length.out))))
+ (r-block (<- to (r-call as.POSIXlt to))
+ (<- mon (r-call seq.int (r-call r-aref r1
+ (index-in-strlist mon (r-call attr
+ r1 #0#)))
+ (r-call + (r-call * 12
+ (r-call - (r-call r-aref to
+ (index-in-strlist
+ year (r-call
+ attr to #0#)))
+ (r-call r-aref r1
+ (index-in-strlist
+ year (r-call attr
+ r1 #0#)))))
+ (r-call r-aref to
+ (index-in-strlist mon (r-call attr
+ to #0#))))
+ by))))
+ (r-block (<- r1 (r-call r-aref<- r1
+ (index-in-strlist mon (r-call attr r1 #0#)) mon))
+ mon)
+ (r-block (ref= %r:10 (r-call - 1)) (<- r1 (r-call r-aref<- r1
+ (index-in-strlist isdst (r-call
+ attr r1 #0#))
+ %r:10))
+ %r:10)
+ (<- res (r-call as.POSIXct r1)))
+ (if (r-call
+ == valid 8)
+ (r-block (if (r-call ! (missing to)) (r-block (<- length.out (r-call + 2
+ (r-call floor (r-call / (r-call - (r-call unclass (r-call as.POSIXct to))
+ (r-call unclass (r-call as.POSIXct from)))
+ 86400))))))
+ (r-block (ref= %r:11 (r-call seq.int (r-call r-aref r1
+ (index-in-strlist mday
+ (r-call attr r1 #0#)))
+ (*named* by by)
+ (*named* length length.out)))
+ (<- r1 (r-call r-aref<- r1
+ (index-in-strlist mday (r-call attr r1 #0#))
+ %r:11))
+ %r:11)
+ (r-block (ref= %r:12 (r-call - 1))
+ (<- r1 (r-call r-aref<- r1
+ (index-in-strlist isdst (r-call attr r1 #0#))
+ %r:12))
+ %r:12)
+ (<- res (r-call as.POSIXct r1))
+ (if (r-call ! (missing to)) (<- res (r-call r-index res
+ (r-call <= res
+ (r-call
+ as.POSIXct to)))))))))
+ (return res)))))))
+ (<- cut.POSIXt (lambda (x breaks labels start.on.monday right
+ ...)
+ (let ((res ())
+ (maxx ())
+ (incr ())
+ (start ())
+ (valid ())
+ (by2 ())
+ (breaks ())
+ (x ())
+ (right ())
+ (start.on.monday ())
+ (labels ()))
+ (r-block (when (missing labels)
+ (<- labels ()))
+ (when (missing start.on.monday)
+ (<- start.on.monday
+ *r-true*))
+ (when (missing right)
+ (<- right *r-false*))
+ (if (r-call ! (r-call inherits x
+ "POSIXt"))
+ (r-call stop "'x' must be a date-time object"))
+ (<- x (r-call as.POSIXct x))
+ (if (r-call inherits breaks "POSIXt")
+ (r-block (<- breaks (r-call
+ as.POSIXct breaks)))
+ (if (&& (r-call is.numeric
+ breaks)
+ (r-call == (r-call
+ length breaks)
+ 1))
+ (r-block)
+ (if (&& (r-call
+ is.character
+ breaks)
+ (r-call == (r-call
+ length breaks)
+ 1))
+ (r-block (<- by2 (r-call
+ r-aref (r-call strsplit breaks " "
+ (*named* fixed *r-true*))
+ 1))
+ (if (|\|\||
+ (r-call > (r-call length by2) 2) (r-call < (r-call length by2) 1))
+ (r-call stop "invalid specification of 'breaks'"))
+ (<- valid (r-call
+ pmatch (r-call r-index by2
+ (r-call length by2))
+ (r-call c "secs" "mins" "hours" "days" "weeks" "months" "years" "DSTdays")))
+ (if (r-call
+ is.na valid)
+ (r-call stop "invalid specification of 'breaks'"))
+ (<- start (r-call
+ as.POSIXlt (r-call min x
+ (*named* na.rm *r-true*))))
+ (<- incr 1)
+ (if (r-call
+ > valid 1)
+ (r-block (r-block (<- start (r-call r-aref<- start
+ (index-in-strlist sec (r-call attr start
+ #0#))
+ 0))
+ 0)
+ (<- incr 59.990000000000002)))
+ (if (r-call
+ > valid 2)
+ (r-block (r-block (<- start (r-call r-aref<- start
+ (index-in-strlist min (r-call attr start
+ #0#))
+ 0))
+ 0)
+ (<- incr (r-call - 3600 1))))
+ (if (r-call
+ > valid 3)
+ (r-block (r-block (<- start (r-call r-aref<- start
+ (index-in-strlist hour (r-call attr start
+ #0#))
+ 0))
+ 0)
+ (<- incr (r-call - 86400 1))))
+ (if (r-call
+ == valid 5)
+ (r-block (r-block (ref= %r:13 (r-call - (r-call r-aref start
+ (index-in-strlist mday (r-call
+ attr start #0#)))
+ (r-call r-aref start
+ (index-in-strlist wday (r-call
+ attr start #0#)))))
+ (<- start (r-call r-aref<- start
+ (index-in-strlist mday (r-call attr start
+ #0#))
+ %r:13))
+ %r:13)
+ (if start.on.monday (r-block (ref= %r:14 (r-call + (r-call r-aref
+ start (index-in-strlist mday (r-call attr start #0#)))
+ (r-call ifelse (r-call
+ > (r-call r-aref start
+ (index-in-strlist wday (r-call attr start #0#)))
+ 0)
+ 1 (r-call
+ - 6))))
+ (<- start (r-call r-aref<- start
+ (index-in-strlist
+ mday (r-call attr
+ start #0#))
+ %r:14))
+ %r:14))
+ (<- incr (r-call * 7 86400))))
+ (if (r-call
+ == valid 6)
+ (r-block (r-block (<- start (r-call r-aref<- start
+ (index-in-strlist mday (r-call attr start
+ #0#))
+ 1))
+ 1)
+ (<- incr (r-call * 31 86400))))
+ (if (r-call
+ == valid 7)
+ (r-block (r-block (<- start (r-call r-aref<- start
+ (index-in-strlist mon (r-call attr start
+ #0#))
+ 0))
+ 0)
+ (r-block (<- start (r-call r-aref<- start
+ (index-in-strlist mday (r-call attr start
+ #0#))
+ 1))
+ 1)
+ (<- incr (r-call * 366 86400))))
+ (if (r-call
+ == valid 8)
+ (<- incr (r-call * 25 3600)))
+ (if (r-call
+ == (r-call length by2) 2)
+ (<- incr (r-call * incr
+ (r-call as.integer (r-call r-index by2 1)))))
+ (<- maxx (r-call
+ max x (*named* na.rm *r-true*)))
+ (<- breaks
+ (r-call seq.int start
+ (r-call + maxx incr) breaks))
+ (<- breaks
+ (r-call r-index breaks
+ (r-call : 1
+ (r-call + 1
+ (r-call max (r-call which (r-call < breaks maxx))))))))
+ (r-call stop "invalid specification of 'breaks'"))))
+ (<- res (r-call cut (r-call
+ unclass x)
+ (r-call unclass
+ breaks)
+ (*named* labels
+ labels)
+ (*named* right
+ right)
+ r-dotdotdot))
+ (if (r-call is.null labels)
+ (r-block (ref= %r:15 (r-call
+ as.character (r-call r-index breaks
+ (r-call - (r-call length breaks)))))
+ (<- res (r-call
+ levels<-
+ res %r:15))
+ %r:15))
+ res))))
+ (<- julian (lambda (x ...)
+ (let () (r-block (r-call UseMethod "julian")))))
+ (<- julian.POSIXt (lambda (x origin ...)
+ (let ((res ())
+ (origin ()))
+ (r-block (when (missing origin)
+ (<- origin (r-call
+ as.POSIXct
+ "1970-01-01"
+ (*named* tz
+ "GMT"))))
+ (if (r-call != (r-call length
+ origin)
+ 1)
+ (r-call stop "'origin' must be of length one"))
+ (<- res (r-call difftime (r-call
+ as.POSIXct x)
+ origin (*named*
+ units "days")))
+ (r-call structure res
+ (*named* origin origin))))))
+ (<- weekdays (lambda (x abbreviate)
+ (let () (r-block (r-call UseMethod "weekdays")))))
+ (<- weekdays.POSIXt (lambda (x abbreviate)
+ (let ((abbreviate ()))
+ (r-block (when (missing abbreviate)
+ (<- abbreviate
+ *r-false*))
+ (r-call format x
+ (r-call ifelse
+ abbreviate
+ "%a" "%A"))))))
+ (<- months (lambda (x abbreviate)
+ (let () (r-block (r-call UseMethod "months")))))
+ (<- months.POSIXt (lambda (x abbreviate)
+ (let ((abbreviate ()))
+ (r-block (when (missing abbreviate)
+ (<- abbreviate *r-false*))
+ (r-call format x
+ (r-call ifelse
+ abbreviate "%b"
+ "%B"))))))
+ (<- quarters (lambda (x abbreviate)
+ (let () (r-block (r-call UseMethod "quarters")))))
+ (<- quarters.POSIXt (lambda (x ...)
+ (let ((x ()))
+ (r-block (<- x (r-call %/% (r-block
+ (ref= %r:0 (r-call as.POSIXlt x)) (r-call r-aref %r:0
+ (index-in-strlist mon (r-call attr
+ %r:0 #0#))))
+ 3))
+ (r-call paste "Q"
+ (r-call + x 1)
+ (*named* sep ""))))))
+ (<- trunc.POSIXt (lambda (x units)
+ (let ((x ())
+ (units ()))
+ (r-block (when (missing units)
+ (<- units (r-call c "secs"
+ "mins" "hours" "days")))
+ (<- units (r-call match.arg
+ units))
+ (<- x (r-call as.POSIXlt x))
+ (if (r-call > (r-call length (r-call
+ r-aref x (index-in-strlist sec (r-call attr x #0#))))
+ 0)
+ (switch units (*named* secs
+ (r-block (r-block (ref= %r:16 (r-call trunc (r-call r-aref x
+ (index-in-strlist sec (r-call
+ attr x #0#)))))
+ (<- x (r-call r-aref<- x
+ (index-in-strlist sec (r-call attr x #0#))
+ %r:16))
+ %r:16)))
+ (*named* mins (r-block
+ (r-block (<- x (r-call r-aref<- x
+ (index-in-strlist sec (r-call attr x #0#)) 0))
+ 0)))
+ (*named* hours (r-block
+ (r-block (<- x (r-call r-aref<- x
+ (index-in-strlist sec (r-call attr x #0#)) 0))
+ 0)
+ (r-block (<- x (r-call r-aref<- x
+ (index-in-strlist min (r-call attr x #0#)) 0))
+ 0)))
+ (*named* days (r-block
+ (r-block (<- x (r-call r-aref<- x
+ (index-in-strlist sec (r-call attr x #0#)) 0))
+ 0)
+ (r-block (<- x (r-call r-aref<- x
+ (index-in-strlist min (r-call attr x #0#)) 0))
+ 0)
+ (r-block (<- x (r-call r-aref<- x
+ (index-in-strlist hour (r-call attr x #0#)) 0))
+ 0)
+ (r-block (ref= %r:17 (r-call - 1)) (<- x (r-call r-aref<- x
+ (index-in-strlist isdst (r-call
+ attr x #0#))
+ %r:17))
+ %r:17)))))
+ x))))
+ (<- round.POSIXt (lambda (x units)
+ (let ((x ())
+ (units ()))
+ (r-block (when (missing units)
+ (<- units (r-call c "secs"
+ "mins" "hours" "days")))
+ (if (&& (r-call is.numeric
+ units)
+ (r-call == units 0))
+ (<- units "secs"))
+ (<- units (r-call match.arg
+ units))
+ (<- x (r-call as.POSIXct x))
+ (<- x (r-call + x
+ (switch units (*named*
+ secs 0.5)
+ (*named* mins 30) (*named* hours 1800) (*named* days 43200))))
+ (r-call trunc.POSIXt x
+ (*named* units units))))))
+ (<- "[.POSIXlt" (lambda (x ... drop)
+ (let ((val ())
+ (drop ()))
+ (r-block (when (missing drop)
+ (<- drop *r-true*))
+ (<- val (r-call lapply x "["
+ r-dotdotdot (*named*
+ drop drop)))
+ (r-block (ref= %r:18 (r-call
+ attributes x))
+ (<- val (r-call
+ attributes<-
+ val %r:18))
+ %r:18)
+ val))))
+ (<- "[<-.POSIXlt" (lambda (x i value)
+ (let ((x ())
+ (cl ())
+ (value ()))
+ (r-block (if (r-call ! (r-call
+ as.logical (r-call
+ length value)))
+ (return x))
+ (<- value (r-call as.POSIXlt
+ value))
+ (<- cl (r-call oldClass x))
+ (r-block (ref= %r:19 (r-block
+ (<- value (r-call class<- value
+ ()))
+ ()))
+ (<- x (r-call class<-
+ x %r:19))
+ %r:19)
+ (for n (r-call names x)
+ (r-block (ref= %r:20 (r-call
+ r-aref value n))
+ (r-block (ref=
+ %r:21 (r-call r-index<- (r-call r-aref x n) i %r:20))
+ (<- x (r-call r-aref<- x n %r:21)) %r:21)
+ %r:20))
+ (r-block (<- x (r-call class<-
+ x cl))
+ cl)
+ x))))
+ (<- as.data.frame.POSIXlt (lambda (x row.names optional ...)
+ (let ((value ())
+ (optional ())
+ (row.names ()))
+ (r-block (when (missing
+ row.names)
+ (<- row.names ()))
+ (when (missing
+ optional)
+ (<- optional
+ *r-false*))
+ (<- value (r-call
+ as.data.frame.POSIXct
+ (r-call
+ as.POSIXct x)
+ row.names
+ optional
+ r-dotdotdot))
+ (if (r-call ! optional)
+ (r-block (ref=
+ %r:22 (r-call r-aref (r-call deparse (substitute x)) 1))
+ (<- value (r-call names<- value %r:22)) %r:22))
+ value))))
+ (<- rep.POSIXct (lambda (x ...)
+ (let ((y ()))
+ (r-block (<- y (r-call NextMethod))
+ (r-call structure y
+ (*named* class (r-call
+ c "POSIXt" "POSIXct"))
+ (*named* tzone (r-call
+ attr x "tzone")))))))
+ (<- rep.POSIXlt (lambda (x ...)
+ (let ((y ()))
+ (r-block (<- y (r-call lapply x rep
+ r-dotdotdot))
+ (r-block (ref= %r:23 (r-call
+ attributes x))
+ (<- y (r-call
+ attributes<- y
+ %r:23))
+ %r:23)
+ y))))
+ (<- diff.POSIXt (lambda (x lag differences ...)
+ (let ((i1 ())
+ (xlen ())
+ (r ())
+ (ismat ())
+ (differences ())
+ (lag ()))
+ (r-block (when (missing lag)
+ (<- lag 1))
+ (when (missing differences)
+ (<- differences 1))
+ (<- ismat (r-call is.matrix x))
+ (<- r (if (r-call inherits x "POSIXlt")
+ (r-call as.POSIXct x)
+ x))
+ (<- xlen (if ismat (r-call
+ r-index (r-call
+ dim x)
+ 1)
+ (r-call length r)))
+ (if (|\|\|| (r-call > (r-call
+ length lag)
+ 1)
+ (r-call > (r-call
+ length differences)
+ 1)
+ (r-call < lag 1)
+ (r-call <
+ differences
+ 1))
+ (r-call stop "'lag' and 'differences' must be integers >= 1"))
+ (if (r-call >= (r-call * lag
+ differences)
+ xlen)
+ (return (r-call structure (r-call
+ numeric 0)
+ (*named*
+ class "difftime")
+ (*named*
+ units "secs"))))
+ (<- i1 (r-call : (r-call - 1)
+ (r-call - lag)))
+ (if ismat (for i (r-call : 1
+ differences)
+ (<- r (r-call - (r-call
+ r-index r i1 *r-missing*
+ (*named* drop *r-false*))
+ (r-call r-index r
+ (r-call : (r-call - (r-call nrow r))
+ (r-call - (r-call + (r-call - (r-call nrow r) lag) 1)))
+ *r-missing* (*named* drop *r-false*)))))
+ (for i (r-call : 1
+ differences)
+ (<- r (r-call - (r-call
+ r-index r i1)
+ (r-call
+ r-index r
+ (r-call :
+ (r-call - (r-call length r)) (r-call - (r-call + (r-call - (r-call length r)
+ lag)
+ 1))))))))
+ r))))
+ (<- duplicated.POSIXlt (lambda (x incomparables ...)
+ (let ((x ())
+ (incomparables ()))
+ (r-block (when (missing
+ incomparables)
+ (<- incomparables
+ *r-false*))
+ (<- x (r-call as.POSIXct
+ x))
+ (r-call NextMethod "duplicated"
+ x)))))
+ (<- unique.POSIXlt (lambda (x incomparables ...)
+ (let ((incomparables ()))
+ (r-block (when (missing incomparables)
+ (<- incomparables
+ *r-false*))
+ (r-call r-index x
+ (r-call ! (r-call
+ duplicated x incomparables r-dotdotdot)))))))
+ (<- sort.POSIXlt (lambda (x decreasing na.last ...)
+ (let ((na.last ())
+ (decreasing ()))
+ (r-block (when (missing decreasing)
+ (<- decreasing *r-false*))
+ (when (missing na.last)
+ (<- na.last NA))
+ (r-call r-index x
+ (r-call order (r-call
+ as.POSIXct x)
+ (*named*
+ na.last
+ na.last)
+ (*named*
+ decreasing
+ decreasing))))))))
--- a/test/ast/rpasses.lsp
+++ /dev/null
@@ -1,109 +1,0 @@
-(load "match.lsp")
-(load "asttools.lsp")
-
-(def missing-arg-tag '*r-missing*)
-
-; tree inspection utils
-
-(def (assigned-var e)
- (and (cons? e)
- (or (eq? (car e) '<-) (eq? (car e) 'ref=))
- (sym? (cadr e))
- (cadr e)))
-
-(def (func-argnames f)
- (let ((argl (cadr f)))
- (if (eq? argl '*r-null*) nil
- (map cadr argl))))
-
-; transformations
-
-(let ((ctr 0))
- (set! r-gensym (lambda ()
- (prog1 (sym "%r:" ctr)
- (set! ctr (+ ctr 1))))))
-
-(def (dollarsign-transform e)
- (pattern-expand
- (pattern-lambda ($ lhs name)
- (let* ((g (if (not (cons? lhs)) lhs (r-gensym)))
- (n (if (sym? name)
- name ;(str name)
- name))
- (expr `(r-call
- r-aref ,g (index-in-strlist ,n (r-call attr ,g "names")))))
- (if (not (cons? lhs))
- expr
- `(r-block (ref= ,g ,lhs) ,expr))))
- e))
-
-; lower r expressions of the form f(lhs,...) <- rhs
-; TODO: if there are any special forms that can be f in this expression,
-; they need to be handled separately. For example a$b can be lowered
-; to an index assignment (by dollarsign-transform), after which
-; this transform applies. I don't think there are any others though.
-(def (fancy-assignment-transform e)
- (pattern-expand
- (pattern-lambda (-$ (<- (r-call f lhs ...) rhs)
- (<<- (r-call f lhs ...) rhs))
- (let ((g (if (cons? rhs) (r-gensym) rhs))
- (op (car __)))
- `(r-block ,@(if (cons? rhs) `((ref= ,g ,rhs)) nil)
- (,op ,lhs (r-call ,(symconcat f '<-) ,@(cddr (cadr __)) ,g))
- ,g)))
- e))
-
-; map an arglist with default values to appropriate init code
-; function(x=blah) { ... } gets
-; if (missing(x)) x = blah
-; added to its body
-(def (gen-default-inits arglist)
- (map (lambda (arg)
- (let ((name (cadr arg))
- (default (caddr arg)))
- `(when (missing ,name)
- (<- ,name ,default))))
- (filter (lambda (arg) (not (eq? (caddr arg) missing-arg-tag))) arglist)))
-
-; convert r function expressions to lambda
-(def (normalize-r-functions e)
- (maptree-post (lambda (n)
- (if (and (cons? n) (eq? (car n) 'function))
- `(lambda ,(func-argnames n)
- (r-block ,@(gen-default-inits (cadr n))
- ,@(if (and (cons? (caddr n))
- (eq? (car (caddr n)) 'r-block))
- (cdr (caddr n))
- (list (caddr n)))))
- n))
- e))
-
-(def (find-assigned-vars n)
- (let ((vars nil))
- (maptree-pre (lambda (s)
- (if (not (cons? s)) s
- (cond ((eq? (car s) 'lambda) nil)
- ((eq? (car s) '<-)
- (set! vars (list-adjoin (cadr s) vars))
- (cddr s))
- (else s))))
- n)
- vars))
-
-; introduce let based on assignment statements
-(def (letbind-locals e)
- (maptree-post (lambda (n)
- (if (and (cons? n) (eq? (car n) 'lambda))
- (let ((vars (find-assigned-vars (cddr n))))
- `(lambda ,(cadr n) (let ,(map (lambda (v) (list v nil))
- vars)
- ,@(cddr n))))
- n))
- e))
-
-(def (compile-ish e)
- (letbind-locals
- (normalize-r-functions
- (fancy-assignment-transform
- (dollarsign-transform
- (flatten-all-op && (flatten-all-op \|\| e)))))))
--- /dev/null
+++ b/test/ast/rpasses.sl
@@ -1,0 +1,109 @@
+(load "match.sl")
+(load "asttools.sl")
+
+(def missing-arg-tag '*r-missing*)
+
+; tree inspection utils
+
+(def (assigned-var e)
+ (and (cons? e)
+ (or (eq? (car e) '<-) (eq? (car e) 'ref=))
+ (sym? (cadr e))
+ (cadr e)))
+
+(def (func-argnames f)
+ (let ((argl (cadr f)))
+ (if (eq? argl '*r-null*) nil
+ (map cadr argl))))
+
+; transformations
+
+(let ((ctr 0))
+ (set! r-gensym (lambda ()
+ (prog1 (sym "%r:" ctr)
+ (set! ctr (+ ctr 1))))))
+
+(def (dollarsign-transform e)
+ (pattern-expand
+ (pattern-lambda ($ lhs name)
+ (let* ((g (if (not (cons? lhs)) lhs (r-gensym)))
+ (n (if (sym? name)
+ name ;(str name)
+ name))
+ (expr `(r-call
+ r-aref ,g (index-in-strlist ,n (r-call attr ,g "names")))))
+ (if (not (cons? lhs))
+ expr
+ `(r-block (ref= ,g ,lhs) ,expr))))
+ e))
+
+; lower r expressions of the form f(lhs,...) <- rhs
+; TODO: if there are any special forms that can be f in this expression,
+; they need to be handled separately. For example a$b can be lowered
+; to an index assignment (by dollarsign-transform), after which
+; this transform applies. I don't think there are any others though.
+(def (fancy-assignment-transform e)
+ (pattern-expand
+ (pattern-lambda (-$ (<- (r-call f lhs ...) rhs)
+ (<<- (r-call f lhs ...) rhs))
+ (let ((g (if (cons? rhs) (r-gensym) rhs))
+ (op (car __)))
+ `(r-block ,@(if (cons? rhs) `((ref= ,g ,rhs)) nil)
+ (,op ,lhs (r-call ,(symconcat f '<-) ,@(cddr (cadr __)) ,g))
+ ,g)))
+ e))
+
+; map an arglist with default values to appropriate init code
+; function(x=blah) { ... } gets
+; if (missing(x)) x = blah
+; added to its body
+(def (gen-default-inits arglist)
+ (map (lambda (arg)
+ (let ((name (cadr arg))
+ (default (caddr arg)))
+ `(when (missing ,name)
+ (<- ,name ,default))))
+ (filter (lambda (arg) (not (eq? (caddr arg) missing-arg-tag))) arglist)))
+
+; convert r function expressions to lambda
+(def (normalize-r-functions e)
+ (maptree-post (lambda (n)
+ (if (and (cons? n) (eq? (car n) 'function))
+ `(lambda ,(func-argnames n)
+ (r-block ,@(gen-default-inits (cadr n))
+ ,@(if (and (cons? (caddr n))
+ (eq? (car (caddr n)) 'r-block))
+ (cdr (caddr n))
+ (list (caddr n)))))
+ n))
+ e))
+
+(def (find-assigned-vars n)
+ (let ((vars nil))
+ (maptree-pre (lambda (s)
+ (if (not (cons? s)) s
+ (cond ((eq? (car s) 'lambda) nil)
+ ((eq? (car s) '<-)
+ (set! vars (list-adjoin (cadr s) vars))
+ (cddr s))
+ (else s))))
+ n)
+ vars))
+
+; introduce let based on assignment statements
+(def (letbind-locals e)
+ (maptree-post (lambda (n)
+ (if (and (cons? n) (eq? (car n) 'lambda))
+ (let ((vars (find-assigned-vars (cddr n))))
+ `(lambda ,(cadr n) (let ,(map (lambda (v) (list v nil))
+ vars)
+ ,@(cddr n))))
+ n))
+ e))
+
+(def (compile-ish e)
+ (letbind-locals
+ (normalize-r-functions
+ (fancy-assignment-transform
+ (dollarsign-transform
+ (flatten-all-op && (flatten-all-op \|\| e)))))))
--- a/test/bench.lsp
+++ /dev/null
@@ -1,36 +1,0 @@
-(load "test.lsp")
-
-;; each benchmark is repeated N times to accomodate
-;; for the performance increase of current systems
-(def N 100)
-
-;; "Performance and Evaluation of Lisp Systems" (1985), Richard P. Gabriel
-(princ "tak: ")
-(def (tak x y z)
- (if (not (< y x))
- z
- (tak (tak (- x 1) y z)
- (tak (- y 1) z x)
- (tak (- z 1) x y))))
-(time (dotimes (n N) (assert (equal? 7 (tak 18 12 6)))))
-
-;; same as tak, but:
-;; (not (< → (>=
-;; (- ... 1 → (1-
-;; this will show how extra calls (no inlining) make things slow
-(princ "tak_: ")
-(def (tak_ x y z)
- (if (>= y x)
- z
- (tak_ (tak_ (1- x) y z)
- (tak_ (1- y) z x)
- (tak_ (1- z) x y))))
-(time (dotimes (n N) (assert (equal? 7 (tak_ 18 12 6)))))
-
-;; q2 - http://lispology.com/show?314T
-(princ "q2: ")
-(def (q2 x y)
- (if (or (< x 1) (< y 1)) 1
- (+ (q2 (- x (q2 (- x 1) y)) y)
- (q2 x (- y (q2 x (- y 1)))))))
-(time (dotimes (n N) (assert (equal? 31 (q2 7 8)))))
--- /dev/null
+++ b/test/bench.sl
@@ -1,0 +1,36 @@
+(load "test.sl")
+
+;; each benchmark is repeated N times to accomodate
+;; for the performance increase of current systems
+(def N 100)
+
+;; "Performance and Evaluation of Lisp Systems" (1985), Richard P. Gabriel
+(princ "tak: ")
+(def (tak x y z)
+ (if (not (< y x))
+ z
+ (tak (tak (- x 1) y z)
+ (tak (- y 1) z x)
+ (tak (- z 1) x y))))
+(time (dotimes (n N) (assert (equal? 7 (tak 18 12 6)))))
+
+;; same as tak, but:
+;; (not (< → (>=
+;; (- ... 1 → (1-
+;; this will show how extra calls (no inlining) make things slow
+(princ "tak_: ")
+(def (tak_ x y z)
+ (if (>= y x)
+ z
+ (tak_ (tak_ (1- x) y z)
+ (tak_ (1- y) z x)
+ (tak_ (1- z) x y))))
+(time (dotimes (n N) (assert (equal? 7 (tak_ 18 12 6)))))
+
+;; q2 - http://lispology.com/show?314T
+(princ "q2: ")
+(def (q2 x y)
+ (if (or (< x 1) (< y 1)) 1
+ (+ (q2 (- x (q2 (- x 1) y)) y)
+ (q2 x (- y (q2 x (- y 1)))))))
+(time (dotimes (n N) (assert (equal? 31 (q2 7 8)))))
--- a/test/color.lsp
+++ /dev/null
@@ -1,87 +1,0 @@
-; dictionaries ----------------------------------------------------------------
-(def (dict-new) NIL)
-
-(def (dict-extend dl key value)
- (cond ((not dl) (list (cons key value)))
- ((equal? key (caar dl)) (cons (cons key value) (cdr dl)))
- (else (cons (car dl) (dict-extend (cdr dl) key value)))))
-
-(def (dict-lookup dl key)
- (cond ((not dl) NIL)
- ((equal? key (caar dl)) (cdar dl))
- (else (dict-lookup (cdr dl) key))))
-
-(def (dict-keys dl) (map car dl))
-
-; graphs ----------------------------------------------------------------------
-(def (graph-empty) (dict-new))
-
-(def (graph-connect g n1 n2)
- (dict-extend
- (dict-extend g n2 (cons n1 (dict-lookup g n2)))
- n1
- (cons n2 (dict-lookup g n1))))
-
-(def (graph-adjacent? g n1 n2) (member n2 (dict-lookup g n1)))
-
-(def (graph-neighbors g n) (dict-lookup g n))
-
-(def (graph-nodes g) (dict-keys g))
-
-(def (graph-add-node g n1) (dict-extend g n1 NIL))
-
-(def (graph-from-edges edge-list)
- (if (not edge-list)
- (graph-empty)
- (graph-connect (graph-from-edges (cdr edge-list))
- (caar edge-list)
- (cdar edge-list))))
-
-; graph coloring --------------------------------------------------------------
-(def (node-colorable? g coloring node-to-color color-of-node)
- (not (member
- color-of-node
- (map
- (λ (n)
- (let ((color-pair (assq n coloring)))
- (and (cons? color-pair) (cdr color-pair))))
- (graph-neighbors g node-to-color)))))
-
-(def (try-each f lst)
- (if (not lst) nil
- (let ((ret (f (car lst))))
- (if ret ret (try-each f (cdr lst))))))
-
-(def (color-node g coloring colors uncolored-nodes color)
- (cond
- ((not uncolored-nodes) coloring)
- ((node-colorable? g coloring (car uncolored-nodes) color)
- (let ((new-coloring
- (cons (cons (car uncolored-nodes) color) coloring)))
- (try-each (λ (c)
- (color-node g new-coloring colors (cdr uncolored-nodes) c))
- colors)))))
-
-(def (color-graph g colors)
- (if (not colors)
- (and (not (graph-nodes g)) nil)
- (color-node g NIL colors (graph-nodes g) (car colors))))
-
-(def (color-pairs pairs colors)
- (color-graph (graph-from-edges pairs) colors))
-
-; queens ----------------------------------------------------------------------
-(def (can-attack x y)
- (let ((x1 (mod x 5))
- (y1 (truncate (/ x 5)))
- (x2 (mod y 5))
- (y2 (truncate (/ y 5))))
- (or (= x1 x2) (= y1 y2) (= (abs (- y2 y1)) (abs (- x2 x1))))))
-
-(def (generate-5x5-pairs)
- (let ((result NIL))
- (dotimes (x 25)
- (dotimes (y 25)
- (when (and (/= x y) (can-attack x y))
- (set! result (cons (cons x y) result)))))
- result))
--- /dev/null
+++ b/test/color.sl
@@ -1,0 +1,87 @@
+; dictionaries ----------------------------------------------------------------
+(def (dict-new) NIL)
+
+(def (dict-extend dl key value)
+ (cond ((not dl) (list (cons key value)))
+ ((equal? key (caar dl)) (cons (cons key value) (cdr dl)))
+ (else (cons (car dl) (dict-extend (cdr dl) key value)))))
+
+(def (dict-lookup dl key)
+ (cond ((not dl) NIL)
+ ((equal? key (caar dl)) (cdar dl))
+ (else (dict-lookup (cdr dl) key))))
+
+(def (dict-keys dl) (map car dl))
+
+; graphs ----------------------------------------------------------------------
+(def (graph-empty) (dict-new))
+
+(def (graph-connect g n1 n2)
+ (dict-extend
+ (dict-extend g n2 (cons n1 (dict-lookup g n2)))
+ n1
+ (cons n2 (dict-lookup g n1))))
+
+(def (graph-adjacent? g n1 n2) (member n2 (dict-lookup g n1)))
+
+(def (graph-neighbors g n) (dict-lookup g n))
+
+(def (graph-nodes g) (dict-keys g))
+
+(def (graph-add-node g n1) (dict-extend g n1 NIL))
+
+(def (graph-from-edges edge-list)
+ (if (not edge-list)
+ (graph-empty)
+ (graph-connect (graph-from-edges (cdr edge-list))
+ (caar edge-list)
+ (cdar edge-list))))
+
+; graph coloring --------------------------------------------------------------
+(def (node-colorable? g coloring node-to-color color-of-node)
+ (not (member
+ color-of-node
+ (map
+ (λ (n)
+ (let ((color-pair (assq n coloring)))
+ (and (cons? color-pair) (cdr color-pair))))
+ (graph-neighbors g node-to-color)))))
+
+(def (try-each f lst)
+ (if (not lst) nil
+ (let ((ret (f (car lst))))
+ (if ret ret (try-each f (cdr lst))))))
+
+(def (color-node g coloring colors uncolored-nodes color)
+ (cond
+ ((not uncolored-nodes) coloring)
+ ((node-colorable? g coloring (car uncolored-nodes) color)
+ (let ((new-coloring
+ (cons (cons (car uncolored-nodes) color) coloring)))
+ (try-each (λ (c)
+ (color-node g new-coloring colors (cdr uncolored-nodes) c))
+ colors)))))
+
+(def (color-graph g colors)
+ (if (not colors)
+ (and (not (graph-nodes g)) nil)
+ (color-node g NIL colors (graph-nodes g) (car colors))))
+
+(def (color-pairs pairs colors)
+ (color-graph (graph-from-edges pairs) colors))
+
+; queens ----------------------------------------------------------------------
+(def (can-attack x y)
+ (let ((x1 (mod x 5))
+ (y1 (truncate (/ x 5)))
+ (x2 (mod y 5))
+ (y2 (truncate (/ y 5))))
+ (or (= x1 x2) (= y1 y2) (= (abs (- y2 y1)) (abs (- x2 x1))))))
+
+(def (generate-5x5-pairs)
+ (let ((result NIL))
+ (dotimes (x 25)
+ (dotimes (y 25)
+ (when (and (/= x y) (can-attack x y))
+ (set! result (cons (cons x y) result)))))
+ result))
--- a/test/err.lsp
+++ /dev/null
@@ -1,4 +1,0 @@
-(def (f x) (begin (list-tail '(1) 3) 3))
-(f 2)
-a
-(trycatch a (λ (e) (print (stacktrace))))
--- /dev/null
+++ b/test/err.sl
@@ -1,0 +1,4 @@
+(def (f x) (begin (list-tail '(1) 3) 3))
+(f 2)
+a
+(trycatch a (λ (e) (print (stacktrace))))
--- a/test/exit0.lsp
+++ /dev/null
@@ -1,1 +1,0 @@
-(exit)
--- /dev/null
+++ b/test/exit0.sl
@@ -1,0 +1,1 @@
+(exit)
--- a/test/exit1.lsp
+++ /dev/null
@@ -1,1 +1,0 @@
-(exit "error")
--- /dev/null
+++ b/test/exit1.sl
@@ -1,0 +1,1 @@
+(exit "error")
--- a/test/hashtest.lsp
+++ /dev/null
@@ -1,16 +1,0 @@
-(def (hins1)
- (let ((h (table)))
- (dotimes (n 200000)
- (put! h (mod (rand) 1000) 'apple))
- h))
-
-(def (hread h)
- (dotimes (n 200000)
- (get h (mod (rand) 10000) NIL)))
-
-(time (dotimes (i 100000)
- (table :a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :foo 8 :bar 9)))
-(time (dotimes (i 100000) (table :a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :foo 8)))
-(time (dotimes (i 100000) (table :a 1 :b 2 :c 3 :d 4)))
-(time (dotimes (i 100000) (table :a 1 :b 2)))
-(time (dotimes (i 100000) (table)))
--- /dev/null
+++ b/test/hashtest.sl
@@ -1,0 +1,16 @@
+(def (hins1)
+ (let ((h (table)))
+ (dotimes (n 200000)
+ (put! h (mod (rand) 1000) 'apple))
+ h))
+
+(def (hread h)
+ (dotimes (n 200000)
+ (get h (mod (rand) 10000) NIL)))
+
+(time (dotimes (i 100000)
+ (table :a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :foo 8 :bar 9)))
+(time (dotimes (i 100000) (table :a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :foo 8)))
+(time (dotimes (i 100000) (table :a 1 :b 2 :c 3 :d 4)))
+(time (dotimes (i 100000) (table :a 1 :b 2)))
+(time (dotimes (i 100000) (table)))
--- a/test/mkfile
+++ b/test/mkfile
@@ -1,15 +1,15 @@
TESTS=\
- 100x100.lsp\
- unittest.lsp\
- argv.lsp\
- bench.lsp\
- exit0.lsp\
- hashtest.lsp\
- torus.lsp\
- tme.lsp\
- mp.lsp\
- perf.lsp\
- torture.lsp
+ 100x100.sl\
+ unittest.sl\
+ argv.sl\
+ bench.sl\
+ exit0.sl\
+ hashtest.sl\
+ torus.sl\
+ tme.sl\
+ mp.sl\
+ perf.sl\
+ torture.sl
test:QV:
for(t in $TESTS){
--- a/test/mp.lsp
+++ /dev/null
@@ -1,2 +1,0 @@
-(def x 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999)
-(apply * (map-int (λ (_) x) 1000))
--- /dev/null
+++ b/test/mp.sl
@@ -1,0 +1,2 @@
+(def x 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999)
+(apply * (map-int (λ (_) x) 1000))
--- a/test/number-boundaries.lsp
+++ /dev/null
@@ -1,188 +1,0 @@
-; NUMBER BOUNDARIES ------------------------------------------------------------
-(defmacro (half-max-signed numtype)
- `(ash (,numtype 1)
- (- (* 8 (sizeof ',numtype)) 2)))
-
-(defmacro (high-border-signed numtype)
- `(+ (- (half-max-signed ,numtype) 1)
- (half-max-signed ,numtype)))
-
-(defmacro (low-border-signed numtype)
- `(- -1 (high-border-signed ,numtype)))
-
-(defmacro (low-border numtype)
- `(if (< (,numtype -1) 1)
- (low-border-signed ,numtype)
- (,numtype 0)))
-
-(defmacro (high-border numtype)
- `(lognot (low-border ,numtype)))
- ;`(numtype (lognot (low-border ,numtype))))
-
-(defmacro (number-borders numtype)
- `(cons (low-border ,numtype)
- (high-border ,numtype)))
-
-; TESTS ------------------------------------------------------------------------
-(princ "---\n")
-(princ "s8 " (number-borders s8) "\n")
-(princ "s16 " (number-borders s16) "\n")
-(princ "s32 " (number-borders s32) "\n")
-(princ "s64 " (number-borders s64) "\n")
-(princ "u8 " (number-borders u8) "\n")
-(princ "u16 " (number-borders u16) "\n")
-(princ "u32 " (number-borders u32) "\n")
-(princ "u64 " (number-borders u64) "\n")
-(princ "---\n")
-
-; add/sub signed
-(assert (= 128 (+ (high-border s8) 1)))
-(assert (= 128 (+ 1 (high-border s8))))
-(assert (= -129 (- (low-border s8) 1)))
-(assert (= 129 (- 1 (low-border s8))))
-(assert (= 32768 (+ (high-border s16) 1)))
-(assert (= 32768 (+ 1 (high-border s16))))
-(assert (= -32769 (- (low-border s16) 1)))
-(assert (= 32769 (- 1 (low-border s16))))
-(assert (= 2147483648 (+ (high-border s32) 1)))
-(assert (= 2147483648 (+ 1 (high-border s32))))
-(assert (= -2147483649 (- (low-border s32) 1)))
-(assert (= 2147483649 (- 1 (low-border s32))))
-(assert (= 9223372036854775808 (+ (high-border s64) 1)))
-(assert (= 9223372036854775808 (+ 1 (high-border s64))))
-(assert (= -9223372036854775809 (- (low-border s64) 1)))
-(assert (= 9223372036854775809 (- 1 (low-border s64))))
-(assert (= 27670116110564327421 (+ 9223372036854775807 9223372036854775807 9223372036854775807)))
-(assert (= -12297829382473033728 (+ -3074457345618258432 -3074457345618258432 -3074457345618258432 -3074457345618258432)))
-(assert (= 6148914691236516864 (- -3074457345618258432 -3074457345618258432 -3074457345618258432 -3074457345618258432)))
-
-; conversions
-
-(defmacro (int-conv- smaller bigger)
- `(let* ((h (high-border ,smaller))
- (L (low-border ,bigger))
- (l (if (= L 0) 0 (low-border ,smaller))))
- (assert (and (int? h) (int? l) (num? h) (num? l)))
- (assert (and (num? (,smaller h)) (num? (,smaller l))))
- (assert (and (int? (,smaller h)) (int? (,smaller l))))
- (assert (and (int? (,bigger h)) (int? (,bigger l))))
- (assert (and (num? (,bigger h)) (num? (,bigger l))))
- (assert (and (int-valued? h) (int-valued? l)))
- (assert (and (int-valued? (,smaller h)) (int-valued? (,smaller l))))
- (assert (and (int-valued? (,bigger h)) (int-valued? (,bigger l))))
- (assert (= h
- (,smaller h) (,bigger h)
- (,smaller (,bigger h)) (,bigger (,smaller h))))
- (assert (= l
- (,smaller l) (,bigger l)
- (,smaller (,bigger l)) (,bigger (,smaller l))))))
-
-(defmacro (int-conv smaller . biggers)
- `(void ,@(map (λ (bigger) `(int-conv- ,smaller ,bigger)) biggers)))
-
-(int-conv s8 s8 u8 s16 u16 s32 u32 s64 u64 bignum)
-(int-conv s16 s16 u16 s32 u32 s64 u64 bignum)
-(int-conv s32 s32 u32 s64 u64 bignum)
-(int-conv s64 s64 u64 bignum)
-
-(int-conv u8 u8 u16 s16 u32 s32 u64 s64 bignum)
-(int-conv u16 u16 u32 s32 u64 s64 bignum)
-(int-conv u32 u64 s64 bignum)
-(int-conv u64 bignum)
-
-(int-conv bignum bignum)
-
-(defmacro (float-conv- type)
- `(let ((l (low-border ,type))
- (h (high-border ,type)))
- (if (member ,type (list s64 u64))
- (assert (= 12345 (,type (double 12345))))
- (begin (assert (= l (,type (double l))))
- (assert (= h (,type (double h))))))
- (if (member ,type (list s32 u32 s64 u64))
- (assert (= 12345 (,type (float 12345))))
- (begin
- (assert (= l (,type (float l))))
- (assert (= h (,type (float h))))))))
-
-(defmacro (float-conv . types)
- `(void ,@(map (λ (type) `(float-conv- ,type)) types)))
-
-(float-conv s8 u8 s16 u16 s32 u32 s64 u64)
-
-(assert (= (low-border s32) (bignum (double (low-border s32)))))
-(assert (= (high-border s32) (bignum (double (high-border s32)))))
-(assert (= (low-border s16) (bignum (float (low-border s16)))))
-(assert (= (high-border s16) (bignum (float (high-border s16)))))
-
-(assert (= (low-border s32) (double (s64 (low-border s32)))))
-(assert (= (high-border s32) (double (s64 (high-border s32)))))
-
-(assert (= 0.5f (double (float 0.5))))
-(assert (= 0.5 (float (double 0.5f))))
-
-; comparison of different types
-
-(assert (< (u64 (1- (high-border s64))) (s64 (high-border s64))))
-(assert (< (s64 (high-border s64)) (u64 (1+ (high-border s64)))))
-(assert (< (s64 (high-border s64)) (u64 (1+ (high-border s64)))))
-(assert (< (u64 (1- (high-border s16))) (float (high-border s16))))
-(assert (< (float (high-border s16)) (u64 (1+ (high-border s16)))))
-(assert (< (u64 (1- (high-border s64))) (bignum (high-border s64))))
-(assert (> (u64 (1+ (high-border s64))) (bignum (high-border s64))))
-(assert (< (s64 (1- (high-border s64))) (bignum (high-border s64))))
-(assert (> (s64 (high-border s64)) (bignum (1- (high-border s64)))))
-
-(assert (< (u64 0) (s64 1)))
-(assert (< (s64 0) (u64 1)))
-(assert (> (u64 0) (s64 -1)))
-(assert (< (s64 -1) (u64 0)))
-(assert (< (u64 0) (bignum 1)))
-(assert (< (s64 0) (bignum 1)))
-(assert (> (u64 0) (bignum -1)))
-(assert (> (s64 0) (bignum -1)))
-(assert (< (s64 -1) (bignum 0)))
-(assert (> (u64 (+ 10 (high-border s64))) (s64 (low-border s64))))
-
-(assert (= (u64 1) (s64 1)))
-(assert (= (s64 1) (u64 1)))
-(assert (/= (u64 (high-border u64)) (s64 -1)))
-(assert (/= (s64 -1) (u64 (high-border u64))))
-
-; add/sub unsigned
-(assert (= 256 (+ (high-border u8) 1)))
-(assert (= 256 (+ 1 (high-border u8))))
-(assert (= -1 (- (low-border u8) 1)))
-(assert (= 1 (- 1 (low-border u8))))
-(assert (= 65536 (+ (high-border u16) 1)))
-(assert (= 65536 (+ 1 (high-border u16))))
-(assert (= -1 (- (low-border u16) 1)))
-(assert (= 1 (- 1 (low-border u16))))
-(assert (= 4294967296 (+ (high-border u32) 1)))
-(assert (= 4294967296 (+ 1 (high-border u32))))
-(assert (= -1 (- (low-border u32) 1)))
-(assert (= 1 (- 1 (low-border u32))))
-(assert (= 18446744073709551616 (+ (high-border u64) 1)))
-(assert (= 18446744073709551616 (+ 1 (high-border u64))))
-(assert (= 36893488147419103230 (+ (high-border u64) (high-border u64))))
-(assert (= 36893488147419103231 (+ 1 (high-border u64) (high-border u64))))
-(assert (= 36893488147419103231 (+ (high-border u64) 1 (high-border u64))))
-(assert (= 36893488147419103231 (+ (high-border u64) (high-border u64) 1)))
-(assert (= -1 (- (low-border u64) 1)))
-(assert (= 1 (- 1 (low-border u64))))
-
-; mul signed
-(assert (= 18446744073709551614 (* (high-border s64) 2)))
-(assert (= -18446744073709551614 (* (high-border s64) -2)))
-(assert (= 18446744073709551614 (* 2 (high-border s64))))
-(assert (= -18446744073709551616 (* (low-border s64) 2)))
-(assert (= -18446744073709551616 (* 2 (low-border s64))))
-
-; mul unsigned
-(assert (= 36893488147419103230 (* (high-border u64) 2)))
-(assert (= 36893488147419103230 (* 2 (high-border u64))))
-(assert (= -36893488147419103230 (* (high-border u64) -2)))
-(assert (= -36893488147419103230 (* -2 (high-border u64))))
-
-(princ "all number boundaries tests pass")
-(newline)
--- /dev/null
+++ b/test/number-boundaries.sl
@@ -1,0 +1,188 @@
+; NUMBER BOUNDARIES ------------------------------------------------------------
+(defmacro (half-max-signed numtype)
+ `(ash (,numtype 1)
+ (- (* 8 (sizeof ',numtype)) 2)))
+
+(defmacro (high-border-signed numtype)
+ `(+ (- (half-max-signed ,numtype) 1)
+ (half-max-signed ,numtype)))
+
+(defmacro (low-border-signed numtype)
+ `(- -1 (high-border-signed ,numtype)))
+
+(defmacro (low-border numtype)
+ `(if (< (,numtype -1) 1)
+ (low-border-signed ,numtype)
+ (,numtype 0)))
+
+(defmacro (high-border numtype)
+ `(lognot (low-border ,numtype)))
+ ;`(numtype (lognot (low-border ,numtype))))
+
+(defmacro (number-borders numtype)
+ `(cons (low-border ,numtype)
+ (high-border ,numtype)))
+
+; TESTS ------------------------------------------------------------------------
+(princ "---\n")
+(princ "s8 " (number-borders s8) "\n")
+(princ "s16 " (number-borders s16) "\n")
+(princ "s32 " (number-borders s32) "\n")
+(princ "s64 " (number-borders s64) "\n")
+(princ "u8 " (number-borders u8) "\n")
+(princ "u16 " (number-borders u16) "\n")
+(princ "u32 " (number-borders u32) "\n")
+(princ "u64 " (number-borders u64) "\n")
+(princ "---\n")
+
+; add/sub signed
+(assert (= 128 (+ (high-border s8) 1)))
+(assert (= 128 (+ 1 (high-border s8))))
+(assert (= -129 (- (low-border s8) 1)))
+(assert (= 129 (- 1 (low-border s8))))
+(assert (= 32768 (+ (high-border s16) 1)))
+(assert (= 32768 (+ 1 (high-border s16))))
+(assert (= -32769 (- (low-border s16) 1)))
+(assert (= 32769 (- 1 (low-border s16))))
+(assert (= 2147483648 (+ (high-border s32) 1)))
+(assert (= 2147483648 (+ 1 (high-border s32))))
+(assert (= -2147483649 (- (low-border s32) 1)))
+(assert (= 2147483649 (- 1 (low-border s32))))
+(assert (= 9223372036854775808 (+ (high-border s64) 1)))
+(assert (= 9223372036854775808 (+ 1 (high-border s64))))
+(assert (= -9223372036854775809 (- (low-border s64) 1)))
+(assert (= 9223372036854775809 (- 1 (low-border s64))))
+(assert (= 27670116110564327421 (+ 9223372036854775807 9223372036854775807 9223372036854775807)))
+(assert (= -12297829382473033728 (+ -3074457345618258432 -3074457345618258432 -3074457345618258432 -3074457345618258432)))
+(assert (= 6148914691236516864 (- -3074457345618258432 -3074457345618258432 -3074457345618258432 -3074457345618258432)))
+
+; conversions
+
+(defmacro (int-conv- smaller bigger)
+ `(let* ((h (high-border ,smaller))
+ (L (low-border ,bigger))
+ (l (if (= L 0) 0 (low-border ,smaller))))
+ (assert (and (int? h) (int? l) (num? h) (num? l)))
+ (assert (and (num? (,smaller h)) (num? (,smaller l))))
+ (assert (and (int? (,smaller h)) (int? (,smaller l))))
+ (assert (and (int? (,bigger h)) (int? (,bigger l))))
+ (assert (and (num? (,bigger h)) (num? (,bigger l))))
+ (assert (and (int-valued? h) (int-valued? l)))
+ (assert (and (int-valued? (,smaller h)) (int-valued? (,smaller l))))
+ (assert (and (int-valued? (,bigger h)) (int-valued? (,bigger l))))
+ (assert (= h
+ (,smaller h) (,bigger h)
+ (,smaller (,bigger h)) (,bigger (,smaller h))))
+ (assert (= l
+ (,smaller l) (,bigger l)
+ (,smaller (,bigger l)) (,bigger (,smaller l))))))
+
+(defmacro (int-conv smaller . biggers)
+ `(void ,@(map (λ (bigger) `(int-conv- ,smaller ,bigger)) biggers)))
+
+(int-conv s8 s8 u8 s16 u16 s32 u32 s64 u64 bignum)
+(int-conv s16 s16 u16 s32 u32 s64 u64 bignum)
+(int-conv s32 s32 u32 s64 u64 bignum)
+(int-conv s64 s64 u64 bignum)
+
+(int-conv u8 u8 u16 s16 u32 s32 u64 s64 bignum)
+(int-conv u16 u16 u32 s32 u64 s64 bignum)
+(int-conv u32 u64 s64 bignum)
+(int-conv u64 bignum)
+
+(int-conv bignum bignum)
+
+(defmacro (float-conv- type)
+ `(let ((l (low-border ,type))
+ (h (high-border ,type)))
+ (if (member ,type (list s64 u64))
+ (assert (= 12345 (,type (double 12345))))
+ (begin (assert (= l (,type (double l))))
+ (assert (= h (,type (double h))))))
+ (if (member ,type (list s32 u32 s64 u64))
+ (assert (= 12345 (,type (float 12345))))
+ (begin
+ (assert (= l (,type (float l))))
+ (assert (= h (,type (float h))))))))
+
+(defmacro (float-conv . types)
+ `(void ,@(map (λ (type) `(float-conv- ,type)) types)))
+
+(float-conv s8 u8 s16 u16 s32 u32 s64 u64)
+
+(assert (= (low-border s32) (bignum (double (low-border s32)))))
+(assert (= (high-border s32) (bignum (double (high-border s32)))))
+(assert (= (low-border s16) (bignum (float (low-border s16)))))
+(assert (= (high-border s16) (bignum (float (high-border s16)))))
+
+(assert (= (low-border s32) (double (s64 (low-border s32)))))
+(assert (= (high-border s32) (double (s64 (high-border s32)))))
+
+(assert (= 0.5f (double (float 0.5))))
+(assert (= 0.5 (float (double 0.5f))))
+
+; comparison of different types
+
+(assert (< (u64 (1- (high-border s64))) (s64 (high-border s64))))
+(assert (< (s64 (high-border s64)) (u64 (1+ (high-border s64)))))
+(assert (< (s64 (high-border s64)) (u64 (1+ (high-border s64)))))
+(assert (< (u64 (1- (high-border s16))) (float (high-border s16))))
+(assert (< (float (high-border s16)) (u64 (1+ (high-border s16)))))
+(assert (< (u64 (1- (high-border s64))) (bignum (high-border s64))))
+(assert (> (u64 (1+ (high-border s64))) (bignum (high-border s64))))
+(assert (< (s64 (1- (high-border s64))) (bignum (high-border s64))))
+(assert (> (s64 (high-border s64)) (bignum (1- (high-border s64)))))
+
+(assert (< (u64 0) (s64 1)))
+(assert (< (s64 0) (u64 1)))
+(assert (> (u64 0) (s64 -1)))
+(assert (< (s64 -1) (u64 0)))
+(assert (< (u64 0) (bignum 1)))
+(assert (< (s64 0) (bignum 1)))
+(assert (> (u64 0) (bignum -1)))
+(assert (> (s64 0) (bignum -1)))
+(assert (< (s64 -1) (bignum 0)))
+(assert (> (u64 (+ 10 (high-border s64))) (s64 (low-border s64))))
+
+(assert (= (u64 1) (s64 1)))
+(assert (= (s64 1) (u64 1)))
+(assert (/= (u64 (high-border u64)) (s64 -1)))
+(assert (/= (s64 -1) (u64 (high-border u64))))
+
+; add/sub unsigned
+(assert (= 256 (+ (high-border u8) 1)))
+(assert (= 256 (+ 1 (high-border u8))))
+(assert (= -1 (- (low-border u8) 1)))
+(assert (= 1 (- 1 (low-border u8))))
+(assert (= 65536 (+ (high-border u16) 1)))
+(assert (= 65536 (+ 1 (high-border u16))))
+(assert (= -1 (- (low-border u16) 1)))
+(assert (= 1 (- 1 (low-border u16))))
+(assert (= 4294967296 (+ (high-border u32) 1)))
+(assert (= 4294967296 (+ 1 (high-border u32))))
+(assert (= -1 (- (low-border u32) 1)))
+(assert (= 1 (- 1 (low-border u32))))
+(assert (= 18446744073709551616 (+ (high-border u64) 1)))
+(assert (= 18446744073709551616 (+ 1 (high-border u64))))
+(assert (= 36893488147419103230 (+ (high-border u64) (high-border u64))))
+(assert (= 36893488147419103231 (+ 1 (high-border u64) (high-border u64))))
+(assert (= 36893488147419103231 (+ (high-border u64) 1 (high-border u64))))
+(assert (= 36893488147419103231 (+ (high-border u64) (high-border u64) 1)))
+(assert (= -1 (- (low-border u64) 1)))
+(assert (= 1 (- 1 (low-border u64))))
+
+; mul signed
+(assert (= 18446744073709551614 (* (high-border s64) 2)))
+(assert (= -18446744073709551614 (* (high-border s64) -2)))
+(assert (= 18446744073709551614 (* 2 (high-border s64))))
+(assert (= -18446744073709551616 (* (low-border s64) 2)))
+(assert (= -18446744073709551616 (* 2 (low-border s64))))
+
+; mul unsigned
+(assert (= 36893488147419103230 (* (high-border u64) 2)))
+(assert (= 36893488147419103230 (* 2 (high-border u64))))
+(assert (= -36893488147419103230 (* (high-border u64) -2)))
+(assert (= -36893488147419103230 (* -2 (high-border u64))))
+
+(princ "all number boundaries tests pass")
+(newline)
--- a/test/perf.lsp
+++ /dev/null
@@ -1,62 +1,0 @@
-(load "test.lsp")
-
-(def Y
- (λ (f)
- ((λ (h)
- (f (λ (x) ((h h) x))))
- (λ (h)
- (f (λ (x) ((h h) x)))))))
-
-(def yfib
- (Y (λ (fib)
- (λ (n)
- (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))))
-
-(def (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
-
-(princ "colorgraph: ")
-(load "tcolor.lsp")
-
-(princ "fib(34): ")
-(assert (equal? (time (fib 34)) 5702887))
-(princ "yfib(32): ")
-(assert (equal? (time (yfib 32)) 2178309))
-
-(def (simple-sort l)
- (if (or (not l) (not (cdr l)))
- l
- (let ((piv (car l)))
- (receive (less grtr)
- (partition (λ (x) (< x piv)) (cdr l))
- (nconc (simple-sort less)
- (list piv)
- (simple-sort grtr))))))
-
-(princ "sort: ")
-(set! r (map-int (λ (x) (mod (+ (* x 9421) 12345) 1024)) 1000))
-(time (simple-sort r))
-
-(princ "macroexpand: ")
-(time (dotimes (n 5000) (macroexpand '(dotimes (i 100) body1 body2))))
-
-(def (my-append . lsts)
- (cond ((not lsts) NIL)
- ((not (cdr lsts)) (car lsts))
- (else (letrec ((append2 (λ (l d)
- (if (not l)
- d
- (cons (car l)
- (append2 (cdr l) d))))))
- (append2 (car lsts) (apply my-append (cdr lsts)))))))
-
-(princ "append: ")
-(set! L (map-int (λ (x) (map-int identity 20)) 20))
-(time (dotimes (n 1000) (apply my-append L)))
-
-(path-cwd "ast")
-(princ "p-lambda: ")
-(load "rpasses.lsp")
-(def *input* (load "datetimeR.lsp"))
-(time (set! *output* (compile-ish *input*)))
-(assert (equal? *output* (load "rpasses-out.lsp")))
-(path-cwd "..")
--- /dev/null
+++ b/test/perf.sl
@@ -1,0 +1,62 @@
+(load "test.sl")
+
+(def Y
+ (λ (f)
+ ((λ (h)
+ (f (λ (x) ((h h) x))))
+ (λ (h)
+ (f (λ (x) ((h h) x)))))))
+
+(def yfib
+ (Y (λ (fib)
+ (λ (n)
+ (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))))
+
+(def (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
+
+(princ "colorgraph: ")
+(load "tcolor.sl")
+
+(princ "fib(34): ")
+(assert (equal? (time (fib 34)) 5702887))
+(princ "yfib(32): ")
+(assert (equal? (time (yfib 32)) 2178309))
+
+(def (simple-sort l)
+ (if (or (not l) (not (cdr l)))
+ l
+ (let ((piv (car l)))
+ (receive (less grtr)
+ (partition (λ (x) (< x piv)) (cdr l))
+ (nconc (simple-sort less)
+ (list piv)
+ (simple-sort grtr))))))
+
+(princ "sort: ")
+(set! r (map-int (λ (x) (mod (+ (* x 9421) 12345) 1024)) 1000))
+(time (simple-sort r))
+
+(princ "macroexpand: ")
+(time (dotimes (n 5000) (macroexpand '(dotimes (i 100) body1 body2))))
+
+(def (my-append . lsts)
+ (cond ((not lsts) NIL)
+ ((not (cdr lsts)) (car lsts))
+ (else (letrec ((append2 (λ (l d)
+ (if (not l)
+ d
+ (cons (car l)
+ (append2 (cdr l) d))))))
+ (append2 (car lsts) (apply my-append (cdr lsts)))))))
+
+(princ "append: ")
+(set! L (map-int (λ (x) (map-int identity 20)) 20))
+(time (dotimes (n 1000) (apply my-append L)))
+
+(path-cwd "ast")
+(princ "p-lambda: ")
+(load "rpasses.sl")
+(def *input* (load "datetimeR.sl"))
+(time (set! *output* (compile-ish *input*)))
+(assert (equal? *output* (load "rpasses-out.sl")))
+(path-cwd "..")
--- a/test/tcolor.lsp
+++ /dev/null
@@ -1,15 +1,0 @@
-; color for performance
-
-(load "color.lsp")
-
-; 100x color 5 queens
-(def Q (generate-5x5-pairs))
-(def (ct)
- (set! C (color-pairs Q '(a b c d e)))
- (dotimes (n 99) (color-pairs Q '(a b c d e))))
-(time (ct))
-(assert (equal? C
- '((23 . a) (9 . a) (22 . b) (17 . d) (14 . d) (8 . b) (21 . e)
- (19 . b) (16 . c) (13 . c) (11 . b) (7 . e) (24 . c) (20 . d)
- (18 . e) (15 . a) (12 . a) (10 . e) (6 . d) (5 . c) (4 . e)
- (3 . d) (2 . c) (0 . b) (1 . a))))
--- /dev/null
+++ b/test/tcolor.sl
@@ -1,0 +1,15 @@
+; color for performance
+
+(load "color.sl")
+
+; 100x color 5 queens
+(def Q (generate-5x5-pairs))
+(def (ct)
+ (set! C (color-pairs Q '(a b c d e)))
+ (dotimes (n 99) (color-pairs Q '(a b c d e))))
+(time (ct))
+(assert (equal? C
+ '((23 . a) (9 . a) (22 . b) (17 . d) (14 . d) (8 . b) (21 . e)
+ (19 . b) (16 . c) (13 . c) (11 . b) (7 . e) (24 . c) (20 . d)
+ (18 . e) (15 . a) (12 . a) (10 . e) (6 . d) (5 . c) (4 . e)
+ (3 . d) (2 . c) (0 . b) (1 . a))))
--- a/test/test.lsp
+++ /dev/null
@@ -1,56 +1,0 @@
-(let ((*profiles* (table)))
- (set! profile
- (λ (s)
- (let ((f (top-level-value s)))
- (put! *profiles* s (cons 0 0))
- (set-top-level-value! s
- (λ args
- (def tt (get *profiles* s))
- (def count (car tt))
- (def time (cdr tt))
- (def t0 (time-now))
- (def v (apply f args))
- (set-cdr! tt (+ time (- (time-now) t0)))
- (set-car! tt (+ count 1))
- v)))))
- (set! show-profiles
- (λ ()
- (def pr (filter (λ (x) (> (cadr x) 0))
- (table-pairs *profiles*)))
- (def width (+ 4
- (apply max
- (map (λ (x)
- (length (str x)))
- (cons 'Function
- (map car pr))))))
- (princ (str-rpad "Function" width #\ )
- "#Calls Time (seconds)")
- (newline)
- (princ (str-rpad "--------" width #\ )
- "------ --------------")
- (newline)
- (for-each
- (λ (p)
- (princ (str-rpad (str (caddr p)) width #\ )
- (str-rpad (str (cadr p)) 11 #\ )
- (car p))
- (newline))
- (simple-sort (map (λ (l) (reverse (to-proper l)))
- pr)))))
- (set! clear-profiles
- (λ ()
- (for-each (λ (k)
- (put! *profiles* k (cons 0 0)))
- (table-keys *profiles*)))))
-
-#;(for-each profile
- '(emit encode-byte-code const-to-idx-vec
- index-of lookup-sym in-env? any every
- compile-sym compile-if compile-begin
- compile-arglist expand builtin->instruction
- compile-app separate nconc get-defined-vars
- compile-in compile compile-f delete-duplicates
- map length> length= count filter append
- lastcdr to-proper reverse reverse! list->vec
- taboreach list-head list-tail assq memq assoc member
- assv memv nreconc bq-process))
--- /dev/null
+++ b/test/test.sl
@@ -1,0 +1,56 @@
+(let ((*profiles* (table)))
+ (set! profile
+ (λ (s)
+ (let ((f (top-level-value s)))
+ (put! *profiles* s (cons 0 0))
+ (set-top-level-value! s
+ (λ args
+ (def tt (get *profiles* s))
+ (def count (car tt))
+ (def time (cdr tt))
+ (def t0 (time-now))
+ (def v (apply f args))
+ (set-cdr! tt (+ time (- (time-now) t0)))
+ (set-car! tt (+ count 1))
+ v)))))
+ (set! show-profiles
+ (λ ()
+ (def pr (filter (λ (x) (> (cadr x) 0))
+ (table-pairs *profiles*)))
+ (def width (+ 4
+ (apply max
+ (map (λ (x)
+ (length (str x)))
+ (cons 'Function
+ (map car pr))))))
+ (princ (str-rpad "Function" width #\ )
+ "#Calls Time (seconds)")
+ (newline)
+ (princ (str-rpad "--------" width #\ )
+ "------ --------------")
+ (newline)
+ (for-each
+ (λ (p)
+ (princ (str-rpad (str (caddr p)) width #\ )
+ (str-rpad (str (cadr p)) 11 #\ )
+ (car p))
+ (newline))
+ (simple-sort (map (λ (l) (reverse (to-proper l)))
+ pr)))))
+ (set! clear-profiles
+ (λ ()
+ (for-each (λ (k)
+ (put! *profiles* k (cons 0 0)))
+ (table-keys *profiles*)))))
+
+#;(for-each profile
+ '(emit encode-byte-code const-to-idx-vec
+ index-of lookup-sym in-env? any every
+ compile-sym compile-if compile-begin
+ compile-arglist expand builtin->instruction
+ compile-app separate nconc get-defined-vars
+ compile-in compile compile-f delete-duplicates
+ map length> length= count filter append
+ lastcdr to-proper reverse reverse! list->vec
+ taboreach list-head list-tail assq memq assoc member
+ assv memv nreconc bq-process))
--- a/test/tme.lsp
+++ /dev/null
@@ -1,3 +1,0 @@
-(let ((ta (table)))
- (time (dotimes (i 2000000)
- (put! ta (rand) (rand)))))
--- /dev/null
+++ b/test/tme.sl
@@ -1,0 +1,3 @@
+(let ((ta (table)))
+ (time (dotimes (i 2000000)
+ (put! ta (rand) (rand)))))
--- a/test/torture.lsp
+++ /dev/null
@@ -1,30 +1,0 @@
-(def ones (map (λ (x) 1) (iota 1000000)))
-
-(write (apply + ones))
-(newline)
-
-(def (big n)
- (if (<= n 0)
- 0
- `(+ 1 1 1 1 1 1 1 1 1 1 ,(big (- n 1)))))
-
-; https://todo.sr.ht/~ft/sl/2
-;(def nst (big 100000))
-;(write (eval nst))
-;(newline)
-
-(def longg (cons '+ ones))
-(write (eval longg))
-(newline)
-
-(princ "----- before GC") (newline)
-(vm-stats)
-(gc)
-(princ "----- after GC") (newline)
-(vm-stats)
-(makunbound 'ones)
-(makunbound 'big)
-(makunbound 'longg)
-(gc)
-(princ "----- after makunbound+GC") (newline)
-(vm-stats)
--- /dev/null
+++ b/test/torture.sl
@@ -1,0 +1,30 @@
+(def ones (map (λ (x) 1) (iota 1000000)))
+
+(write (apply + ones))
+(newline)
+
+(def (big n)
+ (if (<= n 0)
+ 0
+ `(+ 1 1 1 1 1 1 1 1 1 1 ,(big (- n 1)))))
+
+; https://todo.sr.ht/~ft/sl/2
+;(def nst (big 100000))
+;(write (eval nst))
+;(newline)
+
+(def longg (cons '+ ones))
+(write (eval longg))
+(newline)
+
+(princ "----- before GC") (newline)
+(vm-stats)
+(gc)
+(princ "----- after GC") (newline)
+(vm-stats)
+(makunbound 'ones)
+(makunbound 'big)
+(makunbound 'longg)
+(gc)
+(princ "----- after makunbound+GC") (newline)
+(vm-stats)
--- a/test/torus.lsp
+++ /dev/null
@@ -1,46 +1,0 @@
-(def (maplist f l)
- (and l (cons (f l) (maplist f (cdr l)))))
-
-; produce a beautiful, toroidal cons structure
-; make m copies of a CDR-circular list of length n, and connect corresponding
-; conses in CAR-circular loops
-; replace maplist 'identity' with 'copy-tree' for rapdily exploding memory use
-(def (torus m n)
- (let* ((l (map-int identity n))
- (g l)
- (prev g))
- (dotimes (i (- m 1))
- (set! prev g)
- (set! g (maplist identity g))
- (set-cdr! (last-pair prev) prev))
- (set-cdr! (last-pair g) g)
- (let ((a l)
- (b g))
- (dotimes (i n)
- (set-car! a b)
- (set! a (cdr a))
- (set! b (cdr b))))
- l))
-
-(def (cyl m n)
- (let* ((l (map-int identity n))
- (g l))
- (dotimes (i (- m 1))
- (set! g (maplist identity g)))
- (let ((a l)
- (b g))
- (dotimes (i n)
- (set-car! a b)
- (set! a (cdr a))
- (set! b (cdr b))))
- l))
-
-(time (print (torus 100 100)))
-;(time (dotimes (i 1) (load "100x100.lsp")))
-; with ltable
-; printing time: 0.415sec
-; reading time: 0.165sec
-
-; with ptrhash
-; printing time: 0.081sec
-; reading time: 0.0264sec
--- /dev/null
+++ b/test/torus.sl
@@ -1,0 +1,46 @@
+(def (maplist f l)
+ (and l (cons (f l) (maplist f (cdr l)))))
+
+; produce a beautiful, toroidal cons structure
+; make m copies of a CDR-circular list of length n, and connect corresponding
+; conses in CAR-circular loops
+; replace maplist 'identity' with 'copy-tree' for rapdily exploding memory use
+(def (torus m n)
+ (let* ((l (map-int identity n))
+ (g l)
+ (prev g))
+ (dotimes (i (- m 1))
+ (set! prev g)
+ (set! g (maplist identity g))
+ (set-cdr! (last-pair prev) prev))
+ (set-cdr! (last-pair g) g)
+ (let ((a l)
+ (b g))
+ (dotimes (i n)
+ (set-car! a b)
+ (set! a (cdr a))
+ (set! b (cdr b))))
+ l))
+
+(def (cyl m n)
+ (let* ((l (map-int identity n))
+ (g l))
+ (dotimes (i (- m 1))
+ (set! g (maplist identity g)))
+ (let ((a l)
+ (b g))
+ (dotimes (i n)
+ (set-car! a b)
+ (set! a (cdr a))
+ (set! b (cdr b))))
+ l))
+
+(time (print (torus 100 100)))
+;(time (dotimes (i 1) (load "100x100.sl")))
+; with ltable
+; printing time: 0.415sec
+; reading time: 0.165sec
+
+; with ptrhash
+; printing time: 0.081sec
+; reading time: 0.0264sec
--- a/test/unittest.lsp
+++ /dev/null
@@ -1,773 +1,0 @@
-(defmacro (assert-fail expr . what)
- `(assert (trycatch (begin ,expr NIL)
- (λ (e) ,(if (not what) t
- `(eq? (car e) ',(car what)))))))
-
-(def (every-int n)
- (list (fixnum n) (s8 n) (u8 n) (s16 n) (u16 n) (s32 n) (u32 n)
- (s64 n) (u64 n) (float n) (double n) (bignum n)))
-
-(def (every-sint n)
- (list (fixnum n) (s8 n) (s16 n) (s32 n) (s64 n) (float n) (double n) (bignum n)))
-
-(def (each f l)
- (if (atom? l) NIL
- (begin (f (car l))
- (each f (cdr l)))))
-
-(def (each^2 f l m)
- (each (λ (o) (each (λ (p) (f o p)) m)) l))
-
-(def (test-lt a b)
- (each^2 (λ (neg pos)
- (begin
- (eval `(assert (= -1 (compare ,neg ,pos))))
- (eval `(assert (= 1 (compare ,pos ,neg))))
- (eval `(assert (< ,neg ,pos)))
- (eval `(assert (not (< ,pos ,neg))))))
- a
- b))
-
-(def (test-eq a b)
- (each^2 (λ (a b)
- (begin
- (eval `(assert (= 0 (compare ,a ,b))))))
- a
- b))
-
-(test-lt (every-sint -1) (every-int 1))
-(test-lt (every-int 0) (every-int 1))
-(test-eq (every-int 88) (every-int 88))
-(test-eq (every-sint -88) (every-sint -88))
-
-(def (test-square a)
- (each (λ (i) (eval `(assert (>= (* ,i ,i) 0))))
- a))
-
-(test-square (every-sint -67))
-(test-square (every-int 3))
-(test-square (every-int 0x80000000))
-(test-square (every-sint 0x80000000))
-(test-square (every-sint -0x80000000))
-
-(assert (= (* 128 0x02000001) 0x100000080))
-
-(assert (= (/ 1) 1))
-(assert (= (/ -1) -1))
-(assert (= (/ 2.0) 0.5))
-
-(assert (= (- 4999950000 4999941999) 8001))
-
-(assert (not (eqv? 10 #\newline)))
-(assert (not (eqv? #\newline 10)))
-
-; tricky cases involving INT32_MIN
-(assert (< (- #u32(0x80000000)) 0))
-(assert (> (- #s32(0x80000000)) 0))
-(assert (< (- #u64(0x8000000000000000)) 0))
-(assert (< (- #s64(0x8000000000000000)) 0))
-; fixnum versions
-(assert (= (- -536870912) 536870912))
-(assert (= (- -2305843009213693952) 2305843009213693952))
-
-(assert (not (equal? #s64(0x8000000000000000) #u64(0x8000000000000000))))
-(assert (equal? (+ #s64(0x4000000000000000) #s64(0x4000000000000000))
- #u64(0x8000000000000000)))
-(assert (equal? (* 2 #s64(0x4000000000000000))
- #u64(0x8000000000000000)))
-
-(assert (equal? (u64 (double -123)) #u64(0xffffffffffffff85)))
-
-(assert (equal? (str 'sym #byte(65) #rune(945) "blah") "symA\u03B1blah"))
-(assert (= (length (str #\x0)) 1))
-
-(assert (> 9223372036854775808 9223372036854775807))
-
-(assert (fixnum? (- (aref "0" 0) #\0)))
-
-(assert (= (ash #bignum(1) -9999) 0))
-
-; number boundaries
-(load "number-boundaries.lsp")
-
-; bignum
-(assert (> 0x10000000000000000 0x8fffffffffffffff))
-(assert (< 0x8fffffffffffffff 0x10000000000000000))
-
-(assert (bignum? (ash 2 60)))
-(def (bignum-on-32? x) (if #.(fixnum? 0xffffffff) (not (bignum? x)) (bignum? x)))
-(assert (bignum-on-32? (- (ash 2 60) 1)))
-(assert (bignum? 1606938044258990275541962092341162602522202993782792835301376))
-(assert (bignum? 0xfffffffffffffffff))
-(assert (bignum-on-32? 0xfffffffffffffff))
-
-(assert (= 4764984380238568507752444984131552966909
- (* 66405897020462343733 71755440315342536873)))
-(assert (= 71755440315342536873
- (div 4764984380238568507752444984131552966909 66405897020462343733)))
-(assert (= 3203431780337 (div 576460752303423487 179951)))
-(assert (= 3487 (mod 576460752303423487 18000)))
-(assert (= 7 (mod 576460752303423487 10)))
-
-(assert (= 0xfffffffffffffffff (logior 0xaaaaaaaaaaaaaaaaa 0x55555555555555555)))
-(assert (= 0xaaaaaaaaaaaaaaaaa (logxor 0xfffffffffffffffff 0x55555555555555555)))
-(assert (= 0xaaaaaaaaaaaaaaaaa (logxor 0xfffffffffffffffff 0x55555555555555555)))
-(assert (= 0xaaaaaaaaa (logand 0xaaaaaaaaaaaaaaaaa 0x55555555fffffffff)))
-(assert (= 0 (logand 0 0x55555555555555555)))
-(assert (= 602394779747 (ash 11112222333344445555666677778888 -64)))
-(assert (= 204984321473364576635441321909950327706185271083008
- (ash 11112222333344445555666677778888 64)))
-
-; NaNs
-(assert (nan? +nan.0))
-(assert (nan? -nan.0))
-(assert (nan? (float +nan.0)))
-(assert (nan? (float -nan.0)))
-(assert (equal? +nan.0 +nan.0))
-(assert (equal? -nan.0 -nan.0))
-(assert (equal? (float +nan.0) (float +nan.0)))
-(assert (equal? (float -nan.0) (float -nan.0)))
-(assert (/= +nan.0 +nan.0))
-(assert (/= +nan.0 -nan.0))
-(assert (/= -nan.0 -nan.0))
-(assert (/= (float +nan.0) (float +nan.0)))
-(assert (/= (float +nan.0) (float -nan.0)))
-(assert (/= (float -nan.0) (float -nan.0)))
-(assert (equal? (< +nan.0 3) (> 3 +nan.0)))
-(assert (equal? (< +nan.0 (double 3)) (> (double 3) +nan.0)))
-(assert (equal? (< +nan.0 3) (> (double 3) +nan.0)))
-(assert (equal? (< +nan.0 (double 3)) (> 3 +nan.0)))
-(assert (equal? (< +nan.0 3) (< +nan.0 (double 3))))
-(assert (equal? (> +nan.0 3) (> +nan.0 (double 3))))
-(assert (equal? (< 3 +nan.0) (> +nan.0 (double 3))))
-(assert (equal? (> 3 +nan.0) (> (double 3) +nan.0)))
-(assert (not (>= +nan.0 +nan.0)))
-(assert (not (<= -nan.0 -nan.0)))
-(assert (not (>= (float +nan.0) (float +nan.0))))
-(assert (not (<= (float -nan.0) (float -nan.0))))
-
-; comparing strings
-(assert (< "a" "b"))
-(assert (< "a" "b" "c"))
-(assert (> "b" "a"))
-(assert (> "c" "b" "a"))
-(assert (not (< "a" "a")))
-(assert (not (< "a" "a" "a")))
-(assert (<= "a" "a"))
-(assert (<= "a" "a" "a"))
-(assert (>= "a" "a"))
-(assert (>= "a" "a" "a"))
-(assert (>= "ab" "aa"))
-(assert (>= "ab" "aa" "aa"))
-
-; one or more than two arguments
-(assert (and (> 0) (< 0) (>= 0) (<= 0)))
-(assert (and (> 2 1 0) (< 0 1 2) (>= 2 1 0) (<= 0 1 2)))
-(assert (and (>= 2 1 1) (<= 1 1 2)))
-(assert (not (and (>= 2 1 2) (<= 2 1 2))))
-
-; comparing numbers and runes
-(assert (< 9 #\newline))
-(assert (not (< 10 #\newline)))
-(assert (= 10 #\newline))
-(assert (> 11 #\newline))
-
-; -0.0 etc.
-(assert (not (equal? 0.0 0)))
-(assert (equal? 0.0 0.0))
-(assert (not (equal? -0.0 0.0)))
-(assert (not (equal? -0.0 0)))
-(assert (not (eqv? 0.0 0)))
-(assert (not (eqv? -0.0 0)))
-(assert (not (eqv? -0.0 0.0)))
-(assert (= 0.0 -0.0))
-; same but float
-(assert (not (equal? 0.0f 0)))
-(assert (equal? 0.0f 0.0f))
-(assert (not (equal? -0.0f 0.0f)))
-(assert (not (equal? -0.0f 0)))
-(assert (not (eqv? 0.0f 0)))
-(assert (not (eqv? -0.0f 0)))
-(assert (not (eqv? -0.0f 0.0f)))
-(assert (= 0.0f -0.0f))
-
-; this crashed once
-(for 1 10 (λ (i) 0))
-
-; and, or
-(assert (equal? T (and)))
-(assert (equal? NIL (or)))
-(assert (equal? 1 (and '(1) 'x 1)))
-(assert (equal? 1 (or NIL NIL NIL NIL NIL 1 NIL NIL NIL NIL)))
-(assert (equal? 2 (if (and '(1) 'x 1) 2 0)))
-(assert (equal? 2 (if (or NIL NIL NIL NIL NIL 1 NIL NIL NIL NIL) 2 0)))
-(assert (equal? NIL (and '(1) 1 'x NIL)))
-(assert (equal? NIL (or NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)))
-(assert (equal? 0 (if (and '(1) 1 'x NIL) 2 0)))
-(assert (equal? 0 (if (or NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) 2 0)))
-
-; failing applications
-(assert-fail ((λ (x) x) 1 2))
-(assert-fail ((λ (x) x)))
-(assert-fail ((λ (x y . z) z) 1))
-(assert-fail (car 'x) type-error)
-(assert-fail gjegherqpfdf___trejif unbound-error)
-
-; long argument lists
-(assert (= (apply + (iota 100000)) 4999950000))
-(def ones (map (λ (x) 1) (iota 80000)))
-(assert (= (eval `(if (< 2 1)
- (+ ,@ones)
- (+ ,@(cdr ones))))
- 79999))
-
-(def MAX_ARGS 255)
-
-(def as (apply list* (map-int (λ (x) (gensym)) (+ MAX_ARGS 1))))
-(def f (compile `(λ ,as ,(lastcdr as))))
-(assert (equal? (apply f (iota (+ MAX_ARGS 0))) `()))
-(assert (equal? (apply f (iota (+ MAX_ARGS 1))) `(,MAX_ARGS)))
-(assert (equal? (apply f (iota (+ MAX_ARGS 2))) `(,MAX_ARGS ,(+ MAX_ARGS 1))))
-
-(def as (apply list* (map-int (λ (x) (gensym)) (+ MAX_ARGS 100))))
-(def ff (compile `(λ ,as (set! ,(car (last-pair as)) 42)
- ,(car (last-pair as)))))
-(assert (equal? (apply ff (iota (+ MAX_ARGS 100))) 42))
-(def ff (compile `(λ ,as (set! ,(car (last-pair as)) 42)
- (λ () ,(car (last-pair as))))))
-(assert (equal? ((apply ff (iota (+ MAX_ARGS 100)))) 42))
-
-(def as (map-int (λ (x) (gensym)) 1000))
-(def f (compile `(λ ,as ,(car (last-pair as)))))
-(assert (equal? (apply f (iota 1000)) 999))
-
-(def as (apply list* (map-int (λ (x) (gensym)) 995)))
-(def f (compile `(λ ,as ,(lastcdr as))))
-(assert (equal? (apply f (iota 994)) '()))
-(assert (equal? (apply f (iota 995)) '(994)))
-(assert (equal? (apply f (iota 1000)) '(994 995 996 997 998 999)))
-
-; optional arguments
-(assert (equal? ((λ ((b 0)) b)) 0))
-(assert (equal? ((λ (a (b 2)) (list a b)) 1) '(1 2)))
-(assert (equal? ((λ (a (b 2)) (list a b)) 1 3) '(1 3)))
-(assert (equal? ((λ (a (b 2) (c 3)) (list a b c)) 1) '(1 2 3)))
-(assert (equal? ((λ (a (b 2) (c 3)) (list a b c)) 1 8) '(1 8 3)))
-(assert (equal? ((λ (a (b 2) (c 3)) (list a b c)) 1 8 9) '(1 8 9)))
-(assert (equal? ((λ ((x 0) . r) (list x r))) '(0 NIL)))
-(assert (equal? ((λ ((x 0) . r) (list x r)) 1 2 3) '(1 (2 3))))
-
-; keyword arguments
-(assert (keyword? :kw))
-(assert (not (keyword? 'kw:)))
-(assert (not (keyword? 'kw)))
-(assert (not (keyword? ':)))
-(assert (equal? ((λ (x (a 2) (:b a) . r) (list x a b r)) 1 0 8 4 5)
- '(1 0 0 (8 4 5))))
-(assert (equal? ((λ (x (a 2) (:b a) . r) (list x a b r)) 0 :b 3 1)
- '(0 2 3 (1))))
-(def (keys4 (:a 8) (:b 3) (:c 7) (:d 6)) (list a b c d))
-(assert (equal? (keys4 :a 10) '(10 3 7 6)))
-(assert (equal? (keys4 :b 10) '(8 10 7 6)))
-(assert (equal? (keys4 :c 10) '(8 3 10 6)))
-(assert (equal? (keys4 :d 10) '(8 3 7 10)))
-(assert-fail (keys4 :e 10)) ; unsupported keyword
-(assert-fail (keys4 :a 1 :b)) ; keyword with no argument
-(def (keys1 (:a 8)) (+ a 1))
-(assert (equal? (keys1 :a 11) 12))
-
-; cvalues and arrays
-(assert (equal? (typeof "") '(arr byte)))
-(assert-fail (aref #(1) 3) bounds-error)
-(def iarr (arr 's64 32 16 8 7 1))
-(assert (equal? (aref iarr 0) 32))
-(assert (equal? (aref iarr #s8(3)) 7))
-
-; gensyms
-(assert (gensym? (gensym)))
-(assert (not (gensym? 'a)))
-(assert (not (eq? (gensym) (gensym))))
-(assert (not (equal? (str (gensym)) (str (gensym)))))
-(let ((gs (gensym))) (assert (eq? gs gs)))
-
-(load "color.lsp")
-(assert (equal? (color-pairs (generate-5x5-pairs) '(a b c d e))
- '((23 . a) (9 . a) (22 . b) (17 . d) (14 . d) (8 . b) (21 . e)
- (19 . b) (16 . c) (13 . c) (11 . b) (7 . e) (24 . c) (20 . d)
- (18 . e) (15 . a) (12 . a) (10 . e) (6 . d) (5 . c) (4 . e)
- (3 . d) (2 . c) (0 . b) (1 . a))))
-
-; hashing strange things
-(assert (equal?
- (hash '#0=(1 1 #0# . #0#))
- (hash '#1=(1 1 #1# 1 1 #1# . #1#))))
-
-(assert (not (equal?
- (hash '#0=(1 1 #0# . #0#))
- (hash '#1=(1 2 #1# 1 1 #1# . #1#)))))
-
-(assert (equal?
- (hash '#0=((1 . #0#) . #0#))
- (hash '#1=((1 . #1#) (1 . #1#) . #1#))))
-
-(assert (not (equal?
- (hash '#0=((1 . #0#) . #0#))
- (hash '#1=((2 . #1#) (1 . #1#) . #1#)))))
-
-(assert (not (equal?
- (hash '#0=((1 . #0#) . #0#))
- (hash '#1=((1 . #1#) (2 . #1#) . #1#)))))
-
-(assert (equal?
- (hash '(#0=(#0#) 0))
- (hash '(#1=(((((#1#))))) 0))))
-
-(assert (not (equal?
- (hash '(#0=(#0#) 0))
- (hash '(#1=(((((#1#))))) 1)))))
-
-(assert (equal?
- (hash #0=#(1 #(2 #(#0#)) 3))
- (hash #1=#(1 #(2 #(#(1 #(2 #(#1#)) 3))) 3))))
-
-(assert (not (equal?
- (hash #0=#(1 #(2 #(#0#)) 3))
- (hash #1=#(1 #(2 #(#(5 #(2 #(#1#)) 3))) 3)))))
-
-(assert (equal?
- (hash #0=#(1 #0# #(2 #(#0#)) 3))
- (hash #1=#(1 #1# #(2 #(#(1 #1# #(2 #(#1#)) 3))) 3))))
-
-(assert (not (equal?
- (hash #0=#(1 #0# #(2 #(#0#)) 3))
- (hash #1=#(6 #1# #(2 #(#(1 #1# #(2 #(#1#)) 3))) 3)))))
-
-(assert (equal?
- (hash #(1 #(2 #(#(1 1 #(2 #(1)) 3))) 3))
- (hash #(1 #(2 #(#(1 1 #(2 #(1)) 3))) 3))))
-
-(assert (not (equal?
- (hash #(6 1 #(2 #(#(3 1 #(2 #(1)) 3))) 3))
- (hash #(6 1 #(2 #(#(1 1 #(2 #(1)) 3))) 3)))))
-
-(assert (equal? (hash '#0=(1 . #0#))
- (hash '#1=(1 1 . #1#))))
-
-(assert (not (equal? (hash '#0=(1 1 . #0#))
- (hash '#1=(1 #0# . #1#)))))
-
-(assert (not (equal? (hash (iota 10))
- (hash (iota 20)))))
-
-(assert (not (equal? (hash (iota 41))
- (hash (iota 42)))))
-
-(assert (let ((ts (time->str (time-now))))
- (eqv? ts (time->str (str->time ts)))))
-
-(assert (equal? 0.0 (+ 0.0 0))) ; tests that + no longer does inexact->exact
-
-(assert (equal? 1.0 (* 1.0 1))) ; tests that * no longer does inexact->exact
-
-(def (with-output-to-str nada thunk)
- (let ((b (buffer)))
- (with-output-to b (thunk))
- (io->str b)))
-
-(let ((c #\a))
- (assert (equal? (with-output-to-str NIL (λ () (print (list c c))))
- "(#\\a #\\a)")))
-
-(assert-fail (eval '(set! (car (cons 1 2)) 3)))
-
-(assert (equal? `(a `(b c)) '(a (quasiquote (b c)))))
-(assert (equal? ````x '```x))
-
-(assert-fail (eval '(append 1)))
-(assert-fail (eval '(append NIL 1)))
-(assert (equal? (append) NIL))
-(assert (equal? (append NIL) NIL))
-(assert (equal? (append NIL NIL) NIL))
-(assert (equal? (append '(1 2)) '(1 2)))
-(assert (equal? (append '(1 2) '(3 4)) '(1 2 3 4)))
-
-;; infinite list
-(def a '(1))
-(set-cdr! a a)
-(assert (equal? (length a) +inf.0))
-(eq? (cdr a) a)
-
-;; unbinding
-(def abc 1)
-(assert (equal? (bound? 'abc) T))
-(assert (equal? (eval '(+ abc 1)) 2))
-(makunbound 'abc)
-(assert (equal? (bound? 'abc) NIL))
-(assert-fail (eval '(+ abc 1)))
-
-;; c***r of empty list
-(assert (not (car NIL)))
-(assert (not (cdr NIL)))
-(assert (not (cadr NIL)))
-(assert (not (cdar NIL)))
-(assert (not (caaar NIL)))
-(assert (not (cdddr NIL)))
-
-;; for-each with multiple lists
-(def q NIL)
-(for-each (λ (x y) (set! q (cons (+ x y) q))) #(1 2 3) #vu8(4 5 6))
-(assert (equal? q '(9 7 5)))
-(def q 0)
-(for-each (λ (x y) (set! q (+ x y q))) '(1) '(3 9))
-(assert (equal? q 4))
-(for-each (λ (x y) (set! q (+ x y q))) '(1 2) '(3))
-(assert (equal? q 8))
-(for-each (λ (x y z) (set! q (+ x y z q))) '(1 2) '(3) '(4 5))
-(assert (equal? q 16))
-
-;; map with multiple lists
-(assert (equal? (map (λ (x y z) (+ x y z)) '(1 2 3) '(4 5 6) '(7 8 9)) '(12 15 18)))
-(assert (equal? (map (λ (x y) (+ x y)) '(1) '(3 9)) '(4)))
-(assert (equal? (map (λ (x y) (+ x y)) '(1 2) '(3)) '(4)))
-(assert (equal? (map (λ (x y z) (+ x y z)) '(1 2) '(3) '(4 5)) '(8)))
-
-;; aref with multiple indices
-(def a #(#(0 1 2) #(3 (4 5 6) 7)))
-(assert (equal? 0 (aref a 0 0)))
-(assert (equal? 0 (apply aref (list a 0 0))))
-(assert (equal? 2 (aref a 0 2)))
-(assert (equal? 3 (aref a (1+ 0) 0)))
-(assert (equal? 7 (aref a 1 2)))
-(assert (equal? 5 (aref a 1 (1+ 0) 1)))
-(assert-fail (aref a 1 1 3) bounds-error)
-(assert (equal? (fixnum #\l) (aref #("hello") 0 2)))
-(assert (equal? (fixnum #\o) (aref #("hello") 0 (1+ 3))))
-(assert-fail (aref #("hello") 0 5))
-(assert-fail (aref #("hello") 1 0))
-(assert-fail (aref '(NIL) 0 0))
-(assert-fail (apply aref '((NIL) 0 0)))
-
-;; aset with multiple indices
-(def a #(#(0 1 2) #(3 (4 5 6) 7)))
-(assert (equal? 8 (apply aset! (list a 0 0 8))))
-(assert (equal? 9 (aset! a 1 1 (1+ 1) 9)))
-(assert (equal? "hello" (aset! a (1+ 0) 2 "hello")))
-(assert-fail (aset! a 1 1 3 "nope"))
-(assert (equal? a #(#(8 1 2) #(3 (4 5 9) "hello"))))
-(assert-fail (aset! '(NIL) 0 0 1))
-(assert-fail (apply aset! '((NIL) 0 0 1)))
-
-;; apply with multiple args
-(assert (equal? 15 (apply + 1 2 '(3 4 5))))
-(assert-fail (apply + 1 2 3)) ; last arg not a list
-
-;; make many initialized tables large enough not to be stored in-line
-(for 1 100 (λ (i)
- (table eq? 2 eqv? 2
- equal? 2 atom? 1
- not 1 nan? 1
- cons? 1 sym? 1
- num? 1 bound? 1
- cons? 1 builtin? 1
- vec? 1 fixnum? 1
- cons 2 car 1
- cdr 1 set-car! 2
- set-cdr! 2 = 2
- < 2 compare 2
- aref 2 aset! 3
- div0 2 'hello 4
- 'goodbye 5 'foo 6
- 'bar 7)))
-;; now allocate enough to trigger GC
-(for 1 8000000 (λ (i) (cons 1 2)))
-
-;; brieflz bindings
-(let* ((level 10)
- (s (file "unittest.lsp"))
- (in (io-readall s))
- (packed (lz-pack in level))
- (unpacked (lz-unpack packed :size (sizeof in)))
- (unpacked2 (arr-alloc 'byte (sizeof in) 0)))
- (io-close s)
- (assert (< (sizeof packed) (sizeof in)))
- (assert (equal? in unpacked))
- (assert (eq? unpacked2 (lz-unpack packed :to unpacked2)))
- (assert (equal? in unpacked2))
- (princ "lz packing at level " level ": " (sizeof in) " → " (sizeof packed))
- (newline))
-
-;; macro vs function priority
-(def (!! x y) (- x y))
-(assert (eq? 3 (!! 5 2)))
-(defmacro (!! x y z) (+ z (apply !! (list x y))))
-(assert (eq? 4 (!! 5 2 1)))
-
-(def s "привет\0пока")
-(def s2 "hello \t \n world\n ")
-
-(assert (eq? 21 (sizeof s)))
-(assert (eq? 21 (length s)))
-(assert (eq? 11 (str-length s)))
-(assert (eq? 11 (str-length s 0)))
-(assert (eq? 10 (str-length s 2)))
-(assert (eq? 9 (str-length s 3)))
-(assert (eq? 0 (str-length s 21)))
-(assert-fail (str-length s -1))
-(assert-fail (str-length s 22))
-(assert (eq? 1 (str-length s 0 2)))
-(assert (eq? 2 (str-length s 0 4)))
-(assert (eq? 0 (str-length s 21 20)))
-(assert (eq? 0 (str-length s 21 21)))
-(assert-fail (str-length s 21 22))
-
-(assert (equal? "акоп\0тевирп" (str-reverse s)))
-(assert (equal? "" (str-reverse "")))
-(assert (equal? "й" (str-reverse "й")))
-(assert (equal? "wб☺🡷⁹гq" (str-reverse "qг⁹🡷☺бw")))
-
-(assert (str-utf8? ""))
-(assert (str-utf8? "wб☺🡷⁹гq"))
-(assert (not (str-utf8? "\xfffe")))
-
-(let ((b (buffer)))
- (write "a\x0a\x09\\\x07\x08\x1b\x0c\x0d\x0b" b)
- (assert (equal? (io->str b) "\"a\\n\\t\\\\\\a\\b\\e\\f\\r\\v\"")))
-
-(assert (= 10 (str-width s)))
-(assert (= 0 (str-width "")))
-(assert (= 1 (str-width #\q)))
-(assert (= 1 (str-width #\й)))
-(assert (= 0 (str-width #\nul)))
-(assert-fail (str-width 123))
-(assert-fail (str-width 'blah))
-(assert-fail (str-width str-width))
-
-(assert (equal? '("привет" "пока") (str-split s "\0")))
-(assert (equal? '("пр" "вет" "пок" "") (str-split s "аи\0")))
-(assert (equal? '("" "") (str-split "1" "1")))
-
-(assert (equal? '("hello" "world") (str-split s2 :trim T)))
-(assert (equal? '("hello" "\t" "\n" "world\n") (str-split s2 " " :trim T)))
-(assert (equal? (list s2) (str-split s2 "X" :trim T)))
-(assert (equal? (list s2) (str-split s2 "X")))
-
-(assert (equal? #\а (str-rune s 10)))
-(assert (equal? #\nul (str-rune s 6)))
-(assert-fail (str-rune s 11))
-
-(assert (equal? #\W (rune-upcase #\w)))
-(assert (equal? #\П (rune-upcase #\п)))
-(assert (equal? #\nul (rune-upcase #\nul)))
-
-(assert (rune-upper-case? #\W))
-(assert (rune-upper-case? #\П))
-(assert (not (rune-upper-case? #\nul)))
-(assert (not (rune-upper-case? #\w)))
-(assert (not (rune-upper-case? #\п)))
-(assert (not (rune-upper-case? #\nul)))
-
-(assert (equal? #\w (rune-downcase #\W)))
-(assert (equal? #\п (rune-downcase #\П)))
-(assert (equal? #\nul (rune-downcase #\nul)))
-
-(assert (rune-lower-case? #\w))
-(assert (rune-lower-case? #\п))
-(assert (not (rune-lower-case? #\nul)))
-(assert (not (rune-lower-case? #\W)))
-(assert (not (rune-lower-case? #\П)))
-(assert (not (rune-lower-case? #\nul)))
-
-(assert (rune-numeric? #\0))
-(assert (rune-numeric? #\9))
-(assert (not (rune-numeric? #\⁰)))
-(assert (not (rune-numeric? #\q)))
-
-(assert (rune-whitespace? #\space))
-(assert (rune-whitespace? #\tab))
-(assert (rune-whitespace? #\vtab))
-(assert (rune-whitespace? #\newline))
-(assert (rune-whitespace? #\x00a0))
-(assert (rune-whitespace? #\x3000))
-(assert (not (rune-whitespace? #\x200b)))
-
-(assert (rune-alphabetic? #\q))
-(assert (rune-alphabetic? #\й))
-(assert (not (rune-alphabetic? #\⁰)))
-(assert (not (rune-alphabetic? #\0)))
-
-(assert (not (rune-title-case? #\DŽ)))
-(assert (equal? #\Dž (rune-titlecase #\DŽ)))
-(assert (rune-title-case? #\Dž))
-
-(def s "hello й goodbye")
-(assert (= 4 (str-find s #\o)))
-(assert (= 9 (str-find s #\o 5)))
-(assert (= 10 (str-find s #\o 10)))
-(assert (not (str-find s #\o 11)))
-(assert (not (str-find s #\o 15)))
-(assert (= 4 (str-find s "o")))
-(assert (= 2 (str-find s "ll")))
-(assert (not (str-find s "ll" 3)))
-(assert (= 0 (str-find s "")))
-(assert (= 7 (str-find s "" 7)))
-(assert (= 6 (str-find s #\й)))
-(assert (= 6 (str-find s #\й 6)))
-(assert-fail (str-find s #\o -1))
-(assert-fail (str-find s #\o 16))
-(assert-fail (str-find s 0))
-(assert-fail (str-find s (byte #\o)))
-
-(assert (equal? "1.5" (num->str 1.5)))
-(assert (equal? "-3039" (num->str (s16 -12345) 16)))
-(assert (equal? "111111111111111111111111111111111" (num->str 111111111111111111111111111111111)))
-(assert (equal? "fffffffffffffffffffffffffffffffff" (num->str 0xfffffffffffffffffffffffffffffffff 16)))
-
-(assert-fail (num->str 1.5 16))
-(assert-fail (num->str (bignum 0) 36))
-
-(assert (= 1.5 (str->num "1.5")))
-(assert (= -12345 (str->num "-3039" 16)))
-(assert (= 111111111111111111111111111111111 (str->num "111111111111111111111111111111111")))
-(assert (= 0xfffffffffffffffffffffffffffffffff (str->num "fffffffffffffffffffffffffffffffff" 16)))
-
-(assert (= (length (byte #\f)) 1))
-(assert (= (length #\я) 2))
-(assert (= (length #\⁹) 3))
-(assert-fail (= (length (u8 0)) 1))
-(assert-fail (= (length (u16 0)) 2))
-(assert-fail (= (length (u32 0)) 4))
-(assert-fail (= (length (u64 0)) 4))
-(assert-fail (= (length (bignum 0)) 0))
-
-(assert (eq? (sym 'blah) 'blah))
-(assert (eq? (sym "hi" "there" 'symbol 123) 'hitheresymbol123))
-
-(assert-fail (exit "error" 2))
-
-(assert (int-valued? 1.0))
-(assert (int-valued? -1.0))
-(assert (int-valued? 1.0f))
-(assert (int-valued? -1.0f))
-(assert (int-valued? (bignum 0)))
-
-(assert (num? 1.3))
-(assert (num? -1.3))
-(assert (num? 1.3f))
-(assert (num? -1.3f))
-(assert (not (num? #\я)))
-
-(assert (int? 0))
-(assert (int? (bignum 0)))
-
-(assert (= 12345 (fixnum (bignum 12345))))
-(assert (= -12345 (fixnum (bignum -12345))))
-
-(assert (= 1.0 (truncate 1.3)))
-(assert (= -1.0 (truncate -1.3)))
-(assert (= 1.0 (truncate 1.3)))
-(assert (= -1.0 (truncate -1.3)))
-(assert (= 1.0 (truncate 1.3f)))
-(assert (= -1.0 (truncate -1.3f)))
-(assert (= 1.0 (truncate 1.3f)))
-(assert (= -1.0 (truncate -1.3f)))
-(assert (= 1 (truncate (bignum 1))))
-(assert (= -1 (truncate (bignum -1))))
-(assert (= 123 (truncate (s64 123))))
-(assert (= -123 (truncate (s8 -123))))
-(assert-fail (truncate "blah"))
-(assert-fail (truncate 'blah))
-(assert-fail (truncate truncate))
-
-(assert (= 0 (sin 0)))
-(assert (= 0 (sin 0.0)))
-(assert (= 0 (sin 0.0f)))
-(assert (= 0 (sin (s64 0))))
-(assert (= 0 (sin (bignum 0))))
-(let ((x (cos 0)))
- (assert (and (>= x 0.999999999999999) (<= x 1.0))))
-(assert (= 3 (sqrt 9)))
-(assert (= 3 (log10 1000)))
-(assert (= 0 (log 1)))
-(assert (= 1 (exp 0)))
-(assert (= 1 (log (exp 1))))
-
-(assert-fail (acos acos))
-(assert-fail (asin asin))
-(assert-fail (atan atan))
-(assert-fail (ceiling ceiling))
-(assert-fail (cos cos))
-(assert-fail (cosh cosh))
-(assert-fail (exp exp))
-(assert-fail (expt expt expt))
-(assert-fail (floor floor))
-(assert-fail (log log))
-(assert-fail (log10 log10))
-(assert-fail (sin sin))
-(assert-fail (sinh sinh))
-(assert-fail (sqrt sqrt))
-(assert-fail (tan tan))
-(assert-fail (tanh tanh))
-
-(assert (= (length (table "hello" "goodbye" 123 456)) 2))
-(assert-fail (table 1))
-(assert-fail (table 1 2 3))
-(def ta (table 1 2 "3" 4 'foo 'bar))
-(let ((b (buffer)))
- (write ta b)
- (assert (equal? (io->str b) "#table(1 2 \"3\" 4 foo bar)")))
-(assert (table? ta))
-(assert (not (table? "nope")))
-(assert-fail (get ta 3))
-(assert-fail (get ta "foo"))
-(assert-fail (get ta 1+))
-(assert (= 2 (get ta 1)))
-(assert (= 4 (get ta "3")))
-
-(assert (has? ta 'foo))
-(assert (eq? 'bar (get ta 'foo)))
-(assert (eq? ta (del! ta 'foo)))
-(assert (not (has? ta 'foo)))
-(assert-fail (get ta 'foo))
-(assert-fail (del! ta 'foo))
-
-(assert-fail (get "blah" 0))
-(assert-fail (get (list 0 1) 0))
-
-(assert (equal? (list 1 1 1) #0=(list 1 #1=1 #1#)))
-
-(assert-fail (sleep 1 2))
-(sleep)
-(sleep 0)
-(def t₀ (nanoseconds-monotonic))
-(sleep 1)
-(def t₁ (nanoseconds-monotonic))
-(def Δt (- t₁ t₀))
-(assert (and (< Δt 1010000000 ) (> Δt 999000000)))
-(gc)
-
-(let ((ru32 (table))
- (ru64 (table))
- (rdouble (table))
- (rfloat (table)))
- (dotimes (i 100)
- (put! ru32 (rand-u32) 1)
- (put! ru64 (rand-u64) 1)
- (put! rdouble (rand-double) 1)
- (put! rfloat (rand-float) 1))
- (assert (< 50 (length ru32)))
- (assert (< 50 (length ru64)))
- (assert (< 50 (length rdouble)))
- (assert (< 50 (length rfloat))))
-
-;; auto gensym
-
-(defmacro (f x)
- `(let ((a# 1)) (list a# ,x)))
-
-(defmacro (g x)
- `(let ((a# 2)) (list a# ,x)))
-
-(assert (equal? '(1 (2 3)) (f (g 3))))
-
-(princ "all tests pass")
-(newline)
--- /dev/null
+++ b/test/unittest.sl
@@ -1,0 +1,773 @@
+(defmacro (assert-fail expr . what)
+ `(assert (trycatch (begin ,expr NIL)
+ (λ (e) ,(if (not what) t
+ `(eq? (car e) ',(car what)))))))
+
+(def (every-int n)
+ (list (fixnum n) (s8 n) (u8 n) (s16 n) (u16 n) (s32 n) (u32 n)
+ (s64 n) (u64 n) (float n) (double n) (bignum n)))
+
+(def (every-sint n)
+ (list (fixnum n) (s8 n) (s16 n) (s32 n) (s64 n) (float n) (double n) (bignum n)))
+
+(def (each f l)
+ (if (atom? l) NIL
+ (begin (f (car l))
+ (each f (cdr l)))))
+
+(def (each^2 f l m)
+ (each (λ (o) (each (λ (p) (f o p)) m)) l))
+
+(def (test-lt a b)
+ (each^2 (λ (neg pos)
+ (begin
+ (eval `(assert (= -1 (compare ,neg ,pos))))
+ (eval `(assert (= 1 (compare ,pos ,neg))))
+ (eval `(assert (< ,neg ,pos)))
+ (eval `(assert (not (< ,pos ,neg))))))
+ a
+ b))
+
+(def (test-eq a b)
+ (each^2 (λ (a b)
+ (begin
+ (eval `(assert (= 0 (compare ,a ,b))))))
+ a
+ b))
+
+(test-lt (every-sint -1) (every-int 1))
+(test-lt (every-int 0) (every-int 1))
+(test-eq (every-int 88) (every-int 88))
+(test-eq (every-sint -88) (every-sint -88))
+
+(def (test-square a)
+ (each (λ (i) (eval `(assert (>= (* ,i ,i) 0))))
+ a))
+
+(test-square (every-sint -67))
+(test-square (every-int 3))
+(test-square (every-int 0x80000000))
+(test-square (every-sint 0x80000000))
+(test-square (every-sint -0x80000000))
+
+(assert (= (* 128 0x02000001) 0x100000080))
+
+(assert (= (/ 1) 1))
+(assert (= (/ -1) -1))
+(assert (= (/ 2.0) 0.5))
+
+(assert (= (- 4999950000 4999941999) 8001))
+
+(assert (not (eqv? 10 #\newline)))
+(assert (not (eqv? #\newline 10)))
+
+; tricky cases involving INT32_MIN
+(assert (< (- #u32(0x80000000)) 0))
+(assert (> (- #s32(0x80000000)) 0))
+(assert (< (- #u64(0x8000000000000000)) 0))
+(assert (< (- #s64(0x8000000000000000)) 0))
+; fixnum versions
+(assert (= (- -536870912) 536870912))
+(assert (= (- -2305843009213693952) 2305843009213693952))
+
+(assert (not (equal? #s64(0x8000000000000000) #u64(0x8000000000000000))))
+(assert (equal? (+ #s64(0x4000000000000000) #s64(0x4000000000000000))
+ #u64(0x8000000000000000)))
+(assert (equal? (* 2 #s64(0x4000000000000000))
+ #u64(0x8000000000000000)))
+
+(assert (equal? (u64 (double -123)) #u64(0xffffffffffffff85)))
+
+(assert (equal? (str 'sym #byte(65) #rune(945) "blah") "symA\u03B1blah"))
+(assert (= (length (str #\x0)) 1))
+
+(assert (> 9223372036854775808 9223372036854775807))
+
+(assert (fixnum? (- (aref "0" 0) #\0)))
+
+(assert (= (ash #bignum(1) -9999) 0))
+
+; number boundaries
+(load "number-boundaries.sl")
+
+; bignum
+(assert (> 0x10000000000000000 0x8fffffffffffffff))
+(assert (< 0x8fffffffffffffff 0x10000000000000000))
+
+(assert (bignum? (ash 2 60)))
+(def (bignum-on-32? x) (if #.(fixnum? 0xffffffff) (not (bignum? x)) (bignum? x)))
+(assert (bignum-on-32? (- (ash 2 60) 1)))
+(assert (bignum? 1606938044258990275541962092341162602522202993782792835301376))
+(assert (bignum? 0xfffffffffffffffff))
+(assert (bignum-on-32? 0xfffffffffffffff))
+
+(assert (= 4764984380238568507752444984131552966909
+ (* 66405897020462343733 71755440315342536873)))
+(assert (= 71755440315342536873
+ (div 4764984380238568507752444984131552966909 66405897020462343733)))
+(assert (= 3203431780337 (div 576460752303423487 179951)))
+(assert (= 3487 (mod 576460752303423487 18000)))
+(assert (= 7 (mod 576460752303423487 10)))
+
+(assert (= 0xfffffffffffffffff (logior 0xaaaaaaaaaaaaaaaaa 0x55555555555555555)))
+(assert (= 0xaaaaaaaaaaaaaaaaa (logxor 0xfffffffffffffffff 0x55555555555555555)))
+(assert (= 0xaaaaaaaaaaaaaaaaa (logxor 0xfffffffffffffffff 0x55555555555555555)))
+(assert (= 0xaaaaaaaaa (logand 0xaaaaaaaaaaaaaaaaa 0x55555555fffffffff)))
+(assert (= 0 (logand 0 0x55555555555555555)))
+(assert (= 602394779747 (ash 11112222333344445555666677778888 -64)))
+(assert (= 204984321473364576635441321909950327706185271083008
+ (ash 11112222333344445555666677778888 64)))
+
+; NaNs
+(assert (nan? +nan.0))
+(assert (nan? -nan.0))
+(assert (nan? (float +nan.0)))
+(assert (nan? (float -nan.0)))
+(assert (equal? +nan.0 +nan.0))
+(assert (equal? -nan.0 -nan.0))
+(assert (equal? (float +nan.0) (float +nan.0)))
+(assert (equal? (float -nan.0) (float -nan.0)))
+(assert (/= +nan.0 +nan.0))
+(assert (/= +nan.0 -nan.0))
+(assert (/= -nan.0 -nan.0))
+(assert (/= (float +nan.0) (float +nan.0)))
+(assert (/= (float +nan.0) (float -nan.0)))
+(assert (/= (float -nan.0) (float -nan.0)))
+(assert (equal? (< +nan.0 3) (> 3 +nan.0)))
+(assert (equal? (< +nan.0 (double 3)) (> (double 3) +nan.0)))
+(assert (equal? (< +nan.0 3) (> (double 3) +nan.0)))
+(assert (equal? (< +nan.0 (double 3)) (> 3 +nan.0)))
+(assert (equal? (< +nan.0 3) (< +nan.0 (double 3))))
+(assert (equal? (> +nan.0 3) (> +nan.0 (double 3))))
+(assert (equal? (< 3 +nan.0) (> +nan.0 (double 3))))
+(assert (equal? (> 3 +nan.0) (> (double 3) +nan.0)))
+(assert (not (>= +nan.0 +nan.0)))
+(assert (not (<= -nan.0 -nan.0)))
+(assert (not (>= (float +nan.0) (float +nan.0))))
+(assert (not (<= (float -nan.0) (float -nan.0))))
+
+; comparing strings
+(assert (< "a" "b"))
+(assert (< "a" "b" "c"))
+(assert (> "b" "a"))
+(assert (> "c" "b" "a"))
+(assert (not (< "a" "a")))
+(assert (not (< "a" "a" "a")))
+(assert (<= "a" "a"))
+(assert (<= "a" "a" "a"))
+(assert (>= "a" "a"))
+(assert (>= "a" "a" "a"))
+(assert (>= "ab" "aa"))
+(assert (>= "ab" "aa" "aa"))
+
+; one or more than two arguments
+(assert (and (> 0) (< 0) (>= 0) (<= 0)))
+(assert (and (> 2 1 0) (< 0 1 2) (>= 2 1 0) (<= 0 1 2)))
+(assert (and (>= 2 1 1) (<= 1 1 2)))
+(assert (not (and (>= 2 1 2) (<= 2 1 2))))
+
+; comparing numbers and runes
+(assert (< 9 #\newline))
+(assert (not (< 10 #\newline)))
+(assert (= 10 #\newline))
+(assert (> 11 #\newline))
+
+; -0.0 etc.
+(assert (not (equal? 0.0 0)))
+(assert (equal? 0.0 0.0))
+(assert (not (equal? -0.0 0.0)))
+(assert (not (equal? -0.0 0)))
+(assert (not (eqv? 0.0 0)))
+(assert (not (eqv? -0.0 0)))
+(assert (not (eqv? -0.0 0.0)))
+(assert (= 0.0 -0.0))
+; same but float
+(assert (not (equal? 0.0f 0)))
+(assert (equal? 0.0f 0.0f))
+(assert (not (equal? -0.0f 0.0f)))
+(assert (not (equal? -0.0f 0)))
+(assert (not (eqv? 0.0f 0)))
+(assert (not (eqv? -0.0f 0)))
+(assert (not (eqv? -0.0f 0.0f)))
+(assert (= 0.0f -0.0f))
+
+; this crashed once
+(for 1 10 (λ (i) 0))
+
+; and, or
+(assert (equal? T (and)))
+(assert (equal? NIL (or)))
+(assert (equal? 1 (and '(1) 'x 1)))
+(assert (equal? 1 (or NIL NIL NIL NIL NIL 1 NIL NIL NIL NIL)))
+(assert (equal? 2 (if (and '(1) 'x 1) 2 0)))
+(assert (equal? 2 (if (or NIL NIL NIL NIL NIL 1 NIL NIL NIL NIL) 2 0)))
+(assert (equal? NIL (and '(1) 1 'x NIL)))
+(assert (equal? NIL (or NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)))
+(assert (equal? 0 (if (and '(1) 1 'x NIL) 2 0)))
+(assert (equal? 0 (if (or NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) 2 0)))
+
+; failing applications
+(assert-fail ((λ (x) x) 1 2))
+(assert-fail ((λ (x) x)))
+(assert-fail ((λ (x y . z) z) 1))
+(assert-fail (car 'x) type-error)
+(assert-fail gjegherqpfdf___trejif unbound-error)
+
+; long argument lists
+(assert (= (apply + (iota 100000)) 4999950000))
+(def ones (map (λ (x) 1) (iota 80000)))
+(assert (= (eval `(if (< 2 1)
+ (+ ,@ones)
+ (+ ,@(cdr ones))))
+ 79999))
+
+(def MAX_ARGS 255)
+
+(def as (apply list* (map-int (λ (x) (gensym)) (+ MAX_ARGS 1))))
+(def f (compile `(λ ,as ,(lastcdr as))))
+(assert (equal? (apply f (iota (+ MAX_ARGS 0))) `()))
+(assert (equal? (apply f (iota (+ MAX_ARGS 1))) `(,MAX_ARGS)))
+(assert (equal? (apply f (iota (+ MAX_ARGS 2))) `(,MAX_ARGS ,(+ MAX_ARGS 1))))
+
+(def as (apply list* (map-int (λ (x) (gensym)) (+ MAX_ARGS 100))))
+(def ff (compile `(λ ,as (set! ,(car (last-pair as)) 42)
+ ,(car (last-pair as)))))
+(assert (equal? (apply ff (iota (+ MAX_ARGS 100))) 42))
+(def ff (compile `(λ ,as (set! ,(car (last-pair as)) 42)
+ (λ () ,(car (last-pair as))))))
+(assert (equal? ((apply ff (iota (+ MAX_ARGS 100)))) 42))
+
+(def as (map-int (λ (x) (gensym)) 1000))
+(def f (compile `(λ ,as ,(car (last-pair as)))))
+(assert (equal? (apply f (iota 1000)) 999))
+
+(def as (apply list* (map-int (λ (x) (gensym)) 995)))
+(def f (compile `(λ ,as ,(lastcdr as))))
+(assert (equal? (apply f (iota 994)) '()))
+(assert (equal? (apply f (iota 995)) '(994)))
+(assert (equal? (apply f (iota 1000)) '(994 995 996 997 998 999)))
+
+; optional arguments
+(assert (equal? ((λ ((b 0)) b)) 0))
+(assert (equal? ((λ (a (b 2)) (list a b)) 1) '(1 2)))
+(assert (equal? ((λ (a (b 2)) (list a b)) 1 3) '(1 3)))
+(assert (equal? ((λ (a (b 2) (c 3)) (list a b c)) 1) '(1 2 3)))
+(assert (equal? ((λ (a (b 2) (c 3)) (list a b c)) 1 8) '(1 8 3)))
+(assert (equal? ((λ (a (b 2) (c 3)) (list a b c)) 1 8 9) '(1 8 9)))
+(assert (equal? ((λ ((x 0) . r) (list x r))) '(0 NIL)))
+(assert (equal? ((λ ((x 0) . r) (list x r)) 1 2 3) '(1 (2 3))))
+
+; keyword arguments
+(assert (keyword? :kw))
+(assert (not (keyword? 'kw:)))
+(assert (not (keyword? 'kw)))
+(assert (not (keyword? ':)))
+(assert (equal? ((λ (x (a 2) (:b a) . r) (list x a b r)) 1 0 8 4 5)
+ '(1 0 0 (8 4 5))))
+(assert (equal? ((λ (x (a 2) (:b a) . r) (list x a b r)) 0 :b 3 1)
+ '(0 2 3 (1))))
+(def (keys4 (:a 8) (:b 3) (:c 7) (:d 6)) (list a b c d))
+(assert (equal? (keys4 :a 10) '(10 3 7 6)))
+(assert (equal? (keys4 :b 10) '(8 10 7 6)))
+(assert (equal? (keys4 :c 10) '(8 3 10 6)))
+(assert (equal? (keys4 :d 10) '(8 3 7 10)))
+(assert-fail (keys4 :e 10)) ; unsupported keyword
+(assert-fail (keys4 :a 1 :b)) ; keyword with no argument
+(def (keys1 (:a 8)) (+ a 1))
+(assert (equal? (keys1 :a 11) 12))
+
+; cvalues and arrays
+(assert (equal? (typeof "") '(arr byte)))
+(assert-fail (aref #(1) 3) bounds-error)
+(def iarr (arr 's64 32 16 8 7 1))
+(assert (equal? (aref iarr 0) 32))
+(assert (equal? (aref iarr #s8(3)) 7))
+
+; gensyms
+(assert (gensym? (gensym)))
+(assert (not (gensym? 'a)))
+(assert (not (eq? (gensym) (gensym))))
+(assert (not (equal? (str (gensym)) (str (gensym)))))
+(let ((gs (gensym))) (assert (eq? gs gs)))
+
+(load "color.sl")
+(assert (equal? (color-pairs (generate-5x5-pairs) '(a b c d e))
+ '((23 . a) (9 . a) (22 . b) (17 . d) (14 . d) (8 . b) (21 . e)
+ (19 . b) (16 . c) (13 . c) (11 . b) (7 . e) (24 . c) (20 . d)
+ (18 . e) (15 . a) (12 . a) (10 . e) (6 . d) (5 . c) (4 . e)
+ (3 . d) (2 . c) (0 . b) (1 . a))))
+
+; hashing strange things
+(assert (equal?
+ (hash '#0=(1 1 #0# . #0#))
+ (hash '#1=(1 1 #1# 1 1 #1# . #1#))))
+
+(assert (not (equal?
+ (hash '#0=(1 1 #0# . #0#))
+ (hash '#1=(1 2 #1# 1 1 #1# . #1#)))))
+
+(assert (equal?
+ (hash '#0=((1 . #0#) . #0#))
+ (hash '#1=((1 . #1#) (1 . #1#) . #1#))))
+
+(assert (not (equal?
+ (hash '#0=((1 . #0#) . #0#))
+ (hash '#1=((2 . #1#) (1 . #1#) . #1#)))))
+
+(assert (not (equal?
+ (hash '#0=((1 . #0#) . #0#))
+ (hash '#1=((1 . #1#) (2 . #1#) . #1#)))))
+
+(assert (equal?
+ (hash '(#0=(#0#) 0))
+ (hash '(#1=(((((#1#))))) 0))))
+
+(assert (not (equal?
+ (hash '(#0=(#0#) 0))
+ (hash '(#1=(((((#1#))))) 1)))))
+
+(assert (equal?
+ (hash #0=#(1 #(2 #(#0#)) 3))
+ (hash #1=#(1 #(2 #(#(1 #(2 #(#1#)) 3))) 3))))
+
+(assert (not (equal?
+ (hash #0=#(1 #(2 #(#0#)) 3))
+ (hash #1=#(1 #(2 #(#(5 #(2 #(#1#)) 3))) 3)))))
+
+(assert (equal?
+ (hash #0=#(1 #0# #(2 #(#0#)) 3))
+ (hash #1=#(1 #1# #(2 #(#(1 #1# #(2 #(#1#)) 3))) 3))))
+
+(assert (not (equal?
+ (hash #0=#(1 #0# #(2 #(#0#)) 3))
+ (hash #1=#(6 #1# #(2 #(#(1 #1# #(2 #(#1#)) 3))) 3)))))
+
+(assert (equal?
+ (hash #(1 #(2 #(#(1 1 #(2 #(1)) 3))) 3))
+ (hash #(1 #(2 #(#(1 1 #(2 #(1)) 3))) 3))))
+
+(assert (not (equal?
+ (hash #(6 1 #(2 #(#(3 1 #(2 #(1)) 3))) 3))
+ (hash #(6 1 #(2 #(#(1 1 #(2 #(1)) 3))) 3)))))
+
+(assert (equal? (hash '#0=(1 . #0#))
+ (hash '#1=(1 1 . #1#))))
+
+(assert (not (equal? (hash '#0=(1 1 . #0#))
+ (hash '#1=(1 #0# . #1#)))))
+
+(assert (not (equal? (hash (iota 10))
+ (hash (iota 20)))))
+
+(assert (not (equal? (hash (iota 41))
+ (hash (iota 42)))))
+
+(assert (let ((ts (time->str (time-now))))
+ (eqv? ts (time->str (str->time ts)))))
+
+(assert (equal? 0.0 (+ 0.0 0))) ; tests that + no longer does inexact->exact
+
+(assert (equal? 1.0 (* 1.0 1))) ; tests that * no longer does inexact->exact
+
+(def (with-output-to-str nada thunk)
+ (let ((b (buffer)))
+ (with-output-to b (thunk))
+ (io->str b)))
+
+(let ((c #\a))
+ (assert (equal? (with-output-to-str NIL (λ () (print (list c c))))
+ "(#\\a #\\a)")))
+
+(assert-fail (eval '(set! (car (cons 1 2)) 3)))
+
+(assert (equal? `(a `(b c)) '(a (quasiquote (b c)))))
+(assert (equal? ````x '```x))
+
+(assert-fail (eval '(append 1)))
+(assert-fail (eval '(append NIL 1)))
+(assert (equal? (append) NIL))
+(assert (equal? (append NIL) NIL))
+(assert (equal? (append NIL NIL) NIL))
+(assert (equal? (append '(1 2)) '(1 2)))
+(assert (equal? (append '(1 2) '(3 4)) '(1 2 3 4)))
+
+;; infinite list
+(def a '(1))
+(set-cdr! a a)
+(assert (equal? (length a) +inf.0))
+(eq? (cdr a) a)
+
+;; unbinding
+(def abc 1)
+(assert (equal? (bound? 'abc) T))
+(assert (equal? (eval '(+ abc 1)) 2))
+(makunbound 'abc)
+(assert (equal? (bound? 'abc) NIL))
+(assert-fail (eval '(+ abc 1)))
+
+;; c***r of empty list
+(assert (not (car NIL)))
+(assert (not (cdr NIL)))
+(assert (not (cadr NIL)))
+(assert (not (cdar NIL)))
+(assert (not (caaar NIL)))
+(assert (not (cdddr NIL)))
+
+;; for-each with multiple lists
+(def q NIL)
+(for-each (λ (x y) (set! q (cons (+ x y) q))) #(1 2 3) #vu8(4 5 6))
+(assert (equal? q '(9 7 5)))
+(def q 0)
+(for-each (λ (x y) (set! q (+ x y q))) '(1) '(3 9))
+(assert (equal? q 4))
+(for-each (λ (x y) (set! q (+ x y q))) '(1 2) '(3))
+(assert (equal? q 8))
+(for-each (λ (x y z) (set! q (+ x y z q))) '(1 2) '(3) '(4 5))
+(assert (equal? q 16))
+
+;; map with multiple lists
+(assert (equal? (map (λ (x y z) (+ x y z)) '(1 2 3) '(4 5 6) '(7 8 9)) '(12 15 18)))
+(assert (equal? (map (λ (x y) (+ x y)) '(1) '(3 9)) '(4)))
+(assert (equal? (map (λ (x y) (+ x y)) '(1 2) '(3)) '(4)))
+(assert (equal? (map (λ (x y z) (+ x y z)) '(1 2) '(3) '(4 5)) '(8)))
+
+;; aref with multiple indices
+(def a #(#(0 1 2) #(3 (4 5 6) 7)))
+(assert (equal? 0 (aref a 0 0)))
+(assert (equal? 0 (apply aref (list a 0 0))))
+(assert (equal? 2 (aref a 0 2)))
+(assert (equal? 3 (aref a (1+ 0) 0)))
+(assert (equal? 7 (aref a 1 2)))
+(assert (equal? 5 (aref a 1 (1+ 0) 1)))
+(assert-fail (aref a 1 1 3) bounds-error)
+(assert (equal? (fixnum #\l) (aref #("hello") 0 2)))
+(assert (equal? (fixnum #\o) (aref #("hello") 0 (1+ 3))))
+(assert-fail (aref #("hello") 0 5))
+(assert-fail (aref #("hello") 1 0))
+(assert-fail (aref '(NIL) 0 0))
+(assert-fail (apply aref '((NIL) 0 0)))
+
+;; aset with multiple indices
+(def a #(#(0 1 2) #(3 (4 5 6) 7)))
+(assert (equal? 8 (apply aset! (list a 0 0 8))))
+(assert (equal? 9 (aset! a 1 1 (1+ 1) 9)))
+(assert (equal? "hello" (aset! a (1+ 0) 2 "hello")))
+(assert-fail (aset! a 1 1 3 "nope"))
+(assert (equal? a #(#(8 1 2) #(3 (4 5 9) "hello"))))
+(assert-fail (aset! '(NIL) 0 0 1))
+(assert-fail (apply aset! '((NIL) 0 0 1)))
+
+;; apply with multiple args
+(assert (equal? 15 (apply + 1 2 '(3 4 5))))
+(assert-fail (apply + 1 2 3)) ; last arg not a list
+
+;; make many initialized tables large enough not to be stored in-line
+(for 1 100 (λ (i)
+ (table eq? 2 eqv? 2
+ equal? 2 atom? 1
+ not 1 nan? 1
+ cons? 1 sym? 1
+ num? 1 bound? 1
+ cons? 1 builtin? 1
+ vec? 1 fixnum? 1
+ cons 2 car 1
+ cdr 1 set-car! 2
+ set-cdr! 2 = 2
+ < 2 compare 2
+ aref 2 aset! 3
+ div0 2 'hello 4
+ 'goodbye 5 'foo 6
+ 'bar 7)))
+;; now allocate enough to trigger GC
+(for 1 8000000 (λ (i) (cons 1 2)))
+
+;; brieflz bindings
+(let* ((level 10)
+ (s (file "unittest.sl"))
+ (in (io-readall s))
+ (packed (lz-pack in level))
+ (unpacked (lz-unpack packed :size (sizeof in)))
+ (unpacked2 (arr-alloc 'byte (sizeof in) 0)))
+ (io-close s)
+ (assert (< (sizeof packed) (sizeof in)))
+ (assert (equal? in unpacked))
+ (assert (eq? unpacked2 (lz-unpack packed :to unpacked2)))
+ (assert (equal? in unpacked2))
+ (princ "lz packing at level " level ": " (sizeof in) " → " (sizeof packed))
+ (newline))
+
+;; macro vs function priority
+(def (!! x y) (- x y))
+(assert (eq? 3 (!! 5 2)))
+(defmacro (!! x y z) (+ z (apply !! (list x y))))
+(assert (eq? 4 (!! 5 2 1)))
+
+(def s "привет\0пока")
+(def s2 "hello \t \n world\n ")
+
+(assert (eq? 21 (sizeof s)))
+(assert (eq? 21 (length s)))
+(assert (eq? 11 (str-length s)))
+(assert (eq? 11 (str-length s 0)))
+(assert (eq? 10 (str-length s 2)))
+(assert (eq? 9 (str-length s 3)))
+(assert (eq? 0 (str-length s 21)))
+(assert-fail (str-length s -1))
+(assert-fail (str-length s 22))
+(assert (eq? 1 (str-length s 0 2)))
+(assert (eq? 2 (str-length s 0 4)))
+(assert (eq? 0 (str-length s 21 20)))
+(assert (eq? 0 (str-length s 21 21)))
+(assert-fail (str-length s 21 22))
+
+(assert (equal? "акоп\0тевирп" (str-reverse s)))
+(assert (equal? "" (str-reverse "")))
+(assert (equal? "й" (str-reverse "й")))
+(assert (equal? "wб☺🡷⁹гq" (str-reverse "qг⁹🡷☺бw")))
+
+(assert (str-utf8? ""))
+(assert (str-utf8? "wб☺🡷⁹гq"))
+(assert (not (str-utf8? "\xfffe")))
+
+(let ((b (buffer)))
+ (write "a\x0a\x09\\\x07\x08\x1b\x0c\x0d\x0b" b)
+ (assert (equal? (io->str b) "\"a\\n\\t\\\\\\a\\b\\e\\f\\r\\v\"")))
+
+(assert (= 10 (str-width s)))
+(assert (= 0 (str-width "")))
+(assert (= 1 (str-width #\q)))
+(assert (= 1 (str-width #\й)))
+(assert (= 0 (str-width #\nul)))
+(assert-fail (str-width 123))
+(assert-fail (str-width 'blah))
+(assert-fail (str-width str-width))
+
+(assert (equal? '("привет" "пока") (str-split s "\0")))
+(assert (equal? '("пр" "вет" "пок" "") (str-split s "аи\0")))
+(assert (equal? '("" "") (str-split "1" "1")))
+
+(assert (equal? '("hello" "world") (str-split s2 :trim T)))
+(assert (equal? '("hello" "\t" "\n" "world\n") (str-split s2 " " :trim T)))
+(assert (equal? (list s2) (str-split s2 "X" :trim T)))
+(assert (equal? (list s2) (str-split s2 "X")))
+
+(assert (equal? #\а (str-rune s 10)))
+(assert (equal? #\nul (str-rune s 6)))
+(assert-fail (str-rune s 11))
+
+(assert (equal? #\W (rune-upcase #\w)))
+(assert (equal? #\П (rune-upcase #\п)))
+(assert (equal? #\nul (rune-upcase #\nul)))
+
+(assert (rune-upper-case? #\W))
+(assert (rune-upper-case? #\П))
+(assert (not (rune-upper-case? #\nul)))
+(assert (not (rune-upper-case? #\w)))
+(assert (not (rune-upper-case? #\п)))
+(assert (not (rune-upper-case? #\nul)))
+
+(assert (equal? #\w (rune-downcase #\W)))
+(assert (equal? #\п (rune-downcase #\П)))
+(assert (equal? #\nul (rune-downcase #\nul)))
+
+(assert (rune-lower-case? #\w))
+(assert (rune-lower-case? #\п))
+(assert (not (rune-lower-case? #\nul)))
+(assert (not (rune-lower-case? #\W)))
+(assert (not (rune-lower-case? #\П)))
+(assert (not (rune-lower-case? #\nul)))
+
+(assert (rune-numeric? #\0))
+(assert (rune-numeric? #\9))
+(assert (not (rune-numeric? #\⁰)))
+(assert (not (rune-numeric? #\q)))
+
+(assert (rune-whitespace? #\space))
+(assert (rune-whitespace? #\tab))
+(assert (rune-whitespace? #\vtab))
+(assert (rune-whitespace? #\newline))
+(assert (rune-whitespace? #\x00a0))
+(assert (rune-whitespace? #\x3000))
+(assert (not (rune-whitespace? #\x200b)))
+
+(assert (rune-alphabetic? #\q))
+(assert (rune-alphabetic? #\й))
+(assert (not (rune-alphabetic? #\⁰)))
+(assert (not (rune-alphabetic? #\0)))
+
+(assert (not (rune-title-case? #\DŽ)))
+(assert (equal? #\Dž (rune-titlecase #\DŽ)))
+(assert (rune-title-case? #\Dž))
+
+(def s "hello й goodbye")
+(assert (= 4 (str-find s #\o)))
+(assert (= 9 (str-find s #\o 5)))
+(assert (= 10 (str-find s #\o 10)))
+(assert (not (str-find s #\o 11)))
+(assert (not (str-find s #\o 15)))
+(assert (= 4 (str-find s "o")))
+(assert (= 2 (str-find s "ll")))
+(assert (not (str-find s "ll" 3)))
+(assert (= 0 (str-find s "")))
+(assert (= 7 (str-find s "" 7)))
+(assert (= 6 (str-find s #\й)))
+(assert (= 6 (str-find s #\й 6)))
+(assert-fail (str-find s #\o -1))
+(assert-fail (str-find s #\o 16))
+(assert-fail (str-find s 0))
+(assert-fail (str-find s (byte #\o)))
+
+(assert (equal? "1.5" (num->str 1.5)))
+(assert (equal? "-3039" (num->str (s16 -12345) 16)))
+(assert (equal? "111111111111111111111111111111111" (num->str 111111111111111111111111111111111)))
+(assert (equal? "fffffffffffffffffffffffffffffffff" (num->str 0xfffffffffffffffffffffffffffffffff 16)))
+
+(assert-fail (num->str 1.5 16))
+(assert-fail (num->str (bignum 0) 36))
+
+(assert (= 1.5 (str->num "1.5")))
+(assert (= -12345 (str->num "-3039" 16)))
+(assert (= 111111111111111111111111111111111 (str->num "111111111111111111111111111111111")))
+(assert (= 0xfffffffffffffffffffffffffffffffff (str->num "fffffffffffffffffffffffffffffffff" 16)))
+
+(assert (= (length (byte #\f)) 1))
+(assert (= (length #\я) 2))
+(assert (= (length #\⁹) 3))
+(assert-fail (= (length (u8 0)) 1))
+(assert-fail (= (length (u16 0)) 2))
+(assert-fail (= (length (u32 0)) 4))
+(assert-fail (= (length (u64 0)) 4))
+(assert-fail (= (length (bignum 0)) 0))
+
+(assert (eq? (sym 'blah) 'blah))
+(assert (eq? (sym "hi" "there" 'symbol 123) 'hitheresymbol123))
+
+(assert-fail (exit "error" 2))
+
+(assert (int-valued? 1.0))
+(assert (int-valued? -1.0))
+(assert (int-valued? 1.0f))
+(assert (int-valued? -1.0f))
+(assert (int-valued? (bignum 0)))
+
+(assert (num? 1.3))
+(assert (num? -1.3))
+(assert (num? 1.3f))
+(assert (num? -1.3f))
+(assert (not (num? #\я)))
+
+(assert (int? 0))
+(assert (int? (bignum 0)))
+
+(assert (= 12345 (fixnum (bignum 12345))))
+(assert (= -12345 (fixnum (bignum -12345))))
+
+(assert (= 1.0 (truncate 1.3)))
+(assert (= -1.0 (truncate -1.3)))
+(assert (= 1.0 (truncate 1.3)))
+(assert (= -1.0 (truncate -1.3)))
+(assert (= 1.0 (truncate 1.3f)))
+(assert (= -1.0 (truncate -1.3f)))
+(assert (= 1.0 (truncate 1.3f)))
+(assert (= -1.0 (truncate -1.3f)))
+(assert (= 1 (truncate (bignum 1))))
+(assert (= -1 (truncate (bignum -1))))
+(assert (= 123 (truncate (s64 123))))
+(assert (= -123 (truncate (s8 -123))))
+(assert-fail (truncate "blah"))
+(assert-fail (truncate 'blah))
+(assert-fail (truncate truncate))
+
+(assert (= 0 (sin 0)))
+(assert (= 0 (sin 0.0)))
+(assert (= 0 (sin 0.0f)))
+(assert (= 0 (sin (s64 0))))
+(assert (= 0 (sin (bignum 0))))
+(let ((x (cos 0)))
+ (assert (and (>= x 0.999999999999999) (<= x 1.0))))
+(assert (= 3 (sqrt 9)))
+(assert (= 3 (log10 1000)))
+(assert (= 0 (log 1)))
+(assert (= 1 (exp 0)))
+(assert (= 1 (log (exp 1))))
+
+(assert-fail (acos acos))
+(assert-fail (asin asin))
+(assert-fail (atan atan))
+(assert-fail (ceiling ceiling))
+(assert-fail (cos cos))
+(assert-fail (cosh cosh))
+(assert-fail (exp exp))
+(assert-fail (expt expt expt))
+(assert-fail (floor floor))
+(assert-fail (log log))
+(assert-fail (log10 log10))
+(assert-fail (sin sin))
+(assert-fail (sinh sinh))
+(assert-fail (sqrt sqrt))
+(assert-fail (tan tan))
+(assert-fail (tanh tanh))
+
+(assert (= (length (table "hello" "goodbye" 123 456)) 2))
+(assert-fail (table 1))
+(assert-fail (table 1 2 3))
+(def ta (table 1 2 "3" 4 'foo 'bar))
+(let ((b (buffer)))
+ (write ta b)
+ (assert (equal? (io->str b) "#table(1 2 \"3\" 4 foo bar)")))
+(assert (table? ta))
+(assert (not (table? "nope")))
+(assert-fail (get ta 3))
+(assert-fail (get ta "foo"))
+(assert-fail (get ta 1+))
+(assert (= 2 (get ta 1)))
+(assert (= 4 (get ta "3")))
+
+(assert (has? ta 'foo))
+(assert (eq? 'bar (get ta 'foo)))
+(assert (eq? ta (del! ta 'foo)))
+(assert (not (has? ta 'foo)))
+(assert-fail (get ta 'foo))
+(assert-fail (del! ta 'foo))
+
+(assert-fail (get "blah" 0))
+(assert-fail (get (list 0 1) 0))
+
+(assert (equal? (list 1 1 1) #0=(list 1 #1=1 #1#)))
+
+(assert-fail (sleep 1 2))
+(sleep)
+(sleep 0)
+(def t₀ (nanoseconds-monotonic))
+(sleep 1)
+(def t₁ (nanoseconds-monotonic))
+(def Δt (- t₁ t₀))
+(assert (and (< Δt 1010000000 ) (> Δt 999000000)))
+(gc)
+
+(let ((ru32 (table))
+ (ru64 (table))
+ (rdouble (table))
+ (rfloat (table)))
+ (dotimes (i 100)
+ (put! ru32 (rand-u32) 1)
+ (put! ru64 (rand-u64) 1)
+ (put! rdouble (rand-double) 1)
+ (put! rfloat (rand-float) 1))
+ (assert (< 50 (length ru32)))
+ (assert (< 50 (length ru64)))
+ (assert (< 50 (length rdouble)))
+ (assert (< 50 (length rfloat))))
+
+;; auto gensym
+
+(defmacro (f x)
+ `(let ((a# 1)) (list a# ,x)))
+
+(defmacro (g x)
+ `(let ((a# 2)) (list a# ,x)))
+
+(assert (equal? '(1 (2 3)) (f (g 3))))
+
+(princ "all tests pass")
+(newline)
--- a/tools/bootstrap.sh
+++ b/tools/bootstrap.sh
@@ -5,10 +5,10 @@
test -x $F || { meson setup -Dbuildtype=debug build . && ninja -C build || exit 1; }
test -x $F || { echo no $F found; exit 1; }
cd src && \
-$F ../tools/gen.lsp && \
+$F ../tools/gen.sl && \
cp ../boot/sl.boot ../boot/sl.boot.bak && \
-$F ../tools/mkboot0.lsp builtins.lsp instructions.lsp system.lsp compiler.lsp > ../boot/sl.boot && \
+$F ../tools/mkboot0.sl builtins.sl instructions.sl system.sl compiler.sl > ../boot/sl.boot && \
ninja -C ../build && \
cd ../boot && \
-$F ../tools/mkboot1.lsp && \
+$F ../tools/mkboot1.sl && \
ninja -C ../build || { cp "$P/boot/sl.boot.bak" "$P/boot/sl.boot"; exit 1; }
--- a/tools/disenv.lsp
+++ /dev/null
@@ -1,10 +1,0 @@
-#!/usr/bin/env sl
-(for-each (lambda (e)
- (let ((v (top-level-value e)))
- (when (and (fn? v)
- (not (builtin? v)))
- (print e)
- (newline)
- (fn-disasm v)
- (newline))))
- (environment))
--- /dev/null
+++ b/tools/disenv.sl
@@ -1,0 +1,10 @@
+#!/usr/bin/env sl
+(for-each (lambda (e)
+ (let ((v (top-level-value e)))
+ (when (and (fn? v)
+ (not (builtin? v)))
+ (print e)
+ (newline)
+ (fn-disasm v)
+ (newline))))
+ (environment))
--- a/tools/gen.lsp
+++ /dev/null
@@ -1,461 +1,0 @@
-(defstruct op name cname nargs closure docs)
-
-(def (rune-alphanumeric? r)
- (or (rune-alphabetic? r)
- (rune-numeric? r)))
-
-(def (name->cname name)
- (let {[cname (buffer)]}
- (for 0 (1- (length name))
- (λ (i) (let {[r (rune (aref name i))]}
- (io-write cname
- (cond [(rune-alphanumeric? r) (rune-upcase r)]
- [(= r #\?) #\P]
- [(= r #\_) #\_]
- [else ""])))))
- (io->str cname)))
-
-(defmacro (op symbol (nargs NIL) (closure NIL) (docs NIL) (:cname NIL))
- (let ((name (str symbol)))
- `(make-op :name ,name
- :cname ,(str "OP_" (or cname (name->cname name)))
- :nargs ,nargs
- :closure ',closure
- :docs ',docs)))
-
-(def ops (vec
- (op loada0)
- (op loada1)
- (op loadv)
- (op brn)
- (op pop)
- (op call)
- (op tcall)
- (op loadg)
- (op loada)
- (op loadc)
- (op ret)
- (op dup)
- (op car 1 (λ (x) (car x))
- {[(lst)
- "Return the first element of a cons cell (head of a list) or `NIL` if
- not available.
-
- Examples:
-
- (car NIL) → NIL
- (car '(1 2 3)) → 1
- (car '(1 . 2)) → 1"]})
- (op cdr 1 (λ (x) (cdr x))
- {[(lst)
- "Return the second element of a cons cell (tail of a list) or `NIL` if
- not available.
-
- Examples:
-
- (cdr NIL) → NIL
- (cdr '(1 2 3)) → (2 3)
- (cdr '(1 . 2)) → 2"]})
- (op closure)
- (op seta)
- (op jmp)
- (op loadc0)
- (op cons? 1 (λ (x) (cons? x))
- {[(v)
- "Return `T` if `v` is a cons cell, `NIL` otherwise.
-
- Examples:
-
- (cons? 0) → NIL
- (cons? NIL) → NIL
- (cons? '(1)) → T"]})
- (op brne)
- (op loadt)
- (op load0)
- (op loadc1)
- (op aref2)
- (op atom? 1 (λ (x) (atom? x))
- {[(value)
- "Return `T` if `v` is a _not_ a cons cell, `NIL` otherwise. This is
- the opposite of `cons?`.
-
- The term \"atom\" comes from the idea of being indivisible.
-
- Examples:
-
- (atom? \"a\") → T
- (atom? NIL) → T
- (atom? '(1)) → NIL"]})
- (op loadvoid)
- (op brnn)
- (op load1)
- (op < -1 (λ rest (apply < rest))
- {[(a . rest)
- "Return `T` if the arguments are in strictly increasing order (next
- one is greater than the previous one). With a single argument
- the result is always `T`."]}
- :cname "LT")
- (op add2)
- (op set-cdr! 2 (λ (x y) (set-cdr! x y))
- {[(cell new-second)
- "Modify a cons cell (a list) in-place by putting `new-second` as its
- second element (tail of the list). Return the modified cons
- cell (list).
-
- Examples:
-
- (def q '(1 2 3 4 5))
- (set-cdr! q '(6 7)) → (1 6 7)
- q → (1 6 7)"]})
- (op keyargs)
- (op cons 2 (λ (x y) (cons x y))
- {[(first second)
- "Return a cons cell containing two arguments.
-
- Examples:
-
- (cons 1 2) → (1 . 2)
- (cons 1 '(2)) → (1 2)
- (cons 1 (cons 2 (cons 3 NIL))) → (1 2 3)"]})
- (op eq? 2 (λ (x y) (eq? x y))
- {[(a b)
- "Return `T` if `a` and `b` are the same object, `NIL` otherwise.
-
- Examples:
-
- (eq? 0.0 0) → NIL
- (eq? 0 0) → T
- (def a \"1\")
- (def b \"1\")
- (eq? a b) → NIL
- (def a '(1))
- (def b '(1))
- (eq? a b) → NIL"]})
- (op sym? 1 (λ (x) (sym? x))
- {[(v)
- "Return `T` if `v` is a symbol, `NIL` otherwise."]})
- (op not 1 (λ (x) (not x))
- {[(v)
- "Return `T` if `v` is `NIL`, `T` otherwise."]})
- (op cadr 1 (λ (x) (cadr x))
- {[(cell)
- "Shorthand for `(car (cdr cell))`, that is, \"first element of the
- second element\".
-
- Examples:
-
- (cadr '(1 2 3)) → 2
- (cadr '(1)) → NIL
- (cadr NIL) → NIL"]})
- (op neg)
- (op nan? 1 (λ (x) (nan? x))
- {[(v)
- "Return `T` if `v` is a floating point representation of NaN, either
- negative or positive, `NIL` otherwise."]})
- (op brbound)
- (op num? 1 (λ (x) (num? x))
- {[(v)
- "Return `T` if `v` is of a numerical type, `NIL` otherwise.
-
- Numerical types include floating point, fixnum, bignum, etc.
- Note: ironically, a NaN value is considered a number by this function
- since it's only testing the _type_ of the value."]})
- (op fixnum? 1 (λ (x) (fixnum? x))
- {[(v)
- "Return `T` if `v` is of a fixnum type, `NIL` otherwise."]})
- (op bound? 1 (λ (x) (bound? x))
- {[(symbol)
- "Return `T` if `symbol` has a value associated with it, `NIL` otherwise."]})
- (op builtin? 1 (λ (x) (builtin? x))
- {[(v)
- "Return `T` if `v` is a built-in function implemented in C, `NIL`
- otherwise.
-
- Examples:
-
- (builtin? map) → T
- (builtin? macroexpand) → NIL"]})
- (op fn? 1 (λ (x) (fn? x))
- {[(v)
- "Return `T` if `v` is a function, `NIL` otherwise.
-
- Examples:
-
- (fn? map) → T
- (fn? macroexpand) → T"]})
- (op vec? 1 (λ (x) (vec? x))
- {[(v)
- "Return `T` if `v` is a vector, `NIL` otherwise."]})
- (op shift)
- (op set-car! 2 (λ (x y) (set-car! x y))
- {[(cell new-first)
- "Modify a cons cell (a list) in-place by putting `new-first` as its
- first element (head of the list). Return the modified cons
- cell (list).
-
- Examples:
-
- (def q '(1 2 3 4 5))
- (set-car! q 0) → (0 6 7)
- q → (0 6 7)"]})
- (op jmp.l)
- (op brn.l)
- (op box)
- (op eqv? 2 (λ (x y) (eqv? x y))
- {[(a b)
- "Return `T` if both `a` and `b` are of the same value and primitive
- (leaf) type, `NIL` otherwise. Neither cons cell nor vector are not
- considered primitive types as they may define deep structures.
-
- Examples:
-
- (eqv? 0.0 0) → NIL
- (eqv? 0 0) → T
- (def a \"1\")
- (def b \"1\")
- (eqv? a b) → T
- (def a '(1))
- (def b '(1))
- (eqv? a b) → NIL"]})
- (op equal? 2 (λ (x y) (equal? x y))
- {[(a b)
- "Return `T` if both `a` and `b` are of the same value. For non-leaf
- types (cons cell and vector), the equality test is performed
- throughout the whole structure of the values.
-
- Examples:
-
- (equal? 0.0 0) → NIL
- (equal? 0 0) → T
- (def a \"1\")
- (def b \"1\")
- (equal? a b) → T
- (def a '(1))
- (def b '(1))
- (equal? a b) → T"]})
- (op list T (λ rest rest)
- {[rest
- "Return a list constructed of the arguments.
-
- Examples:
-
- (list) → NIL ; empty list
- (list 1 2.5 \"a\" 'b) → (1 2.5 \"a\" b)"]})
- (op apply -2 (λ rest (apply apply rest))
- {[(fn arg . rest)
- "Return the result of applying a function to a list of arguments.
-
- The last argument must always be a list which gets spliced as
- arguments to the function.
-
- Examples:
-
- (apply + 1 2 '(3 4 5)) → 15
- (apply vec '(1 2 3)) → #(3 4 5)
- (apply arr 'u8 '(3 4 5)) → #vu8(3 4 5)"]})
- (op + T (λ rest (apply + rest))
- {[rest
- "Return sum of the arguments or `0` when none specified."]}
- :cname "ADD")
- (op - -1 (λ rest (apply - rest))
- {[(a . rest)
- "Return the result of subtraction. With only one argument a
- negation is performed.
-
- Examples:
-
- (- 1.5) → -1.5
- (- 3 2) → 1"]}
- :cname "SUB")
- (op * T (λ rest (apply * rest))
- {[rest
- "Return product of the arguments or `1` when none specified."]}
- :cname "MUL")
- (op / -1 (λ rest (apply / rest))
- {[(x . rest)
- "Return the division of the arguments. With only one argument the
- result of `1/x` is returned. If the result is integer-valued, it is
- returned as an integer.
-
- Examples:
-
- (/ 2) → 0.5
- (/ 7 2 2) → 1.75
- (/ 10 -2) → -5 ; a fixnum
- (/ 6.9 1.9) → 3.6315…"]}
- :cname "DIV")
- (op div0 2 (λ rest (apply div0 rest))
- {[(a b)
- "Return the quotient of two numbers. For non-integers this is
- equivalent to `(div0 (floor a) (floor b))`. The result is always an
- integer.
-
- Examples:
-
- (div0 7 2) → 3
- (div0 10 -2) → -5
- (div0 6.9 1.9) → 6"]})
- (op = -1 (λ rest (apply = rest))
- {[(a . rest)
- "Numerical equality test. Return `T` if all numbers are equal,
- `NIL` otherwise."]}
- :cname "NUMEQP")
- (op compare 2 (λ (x y) (compare x y))
- {[(x y)
- "Return -1 if `x` is less than `y`, 0 if equal, and `1` if `y` is
- greater than `x`.
-
- Examples:
-
- (compare 'a 'b) → -1
- (compare 1 1) → 0
- (compare \"b\" \"a\") → 1"]})
- (op argc)
- (op vec T (λ rest (apply vec rest))
- {[rest
- "Return a vector constructed of the arguments.
-
- Examples:
-
- (vec) → #() ; empty vector
- (vec 1 2.5 \"a\" 'b) → #(1 2.5 \"a\" b)"]})
- (op aset! -3 (λ rest (apply aset! rest))
- {[(sequence subscripts… new-value)
- "Modify the sequence element specified by the subscripts and return the
- new value. The sequence can be an array, vector, a list.
- Multi-dimensional sequences of variating types are also supported.
-
- Examples:
-
- (def a '((1 #(2 (3)) 4)))
- (aset! a 1 'x) → index 1 out of bounds
- (aset! a 0 0 'x) → x
- a → ((x #(2 (3)) 4))
- (aset! a 0 1 9) → 9
- a → ((x #(9 (3)) 4))"]})
- (op loadnil)
- (op loadi8)
- (op loadv.l)
- (op loadg.l)
- (op loada.l)
- (op loadc.l)
- (op setg)
- (op setg.l)
- (op seta.l)
- (op vargc)
- (op trycatch)
- (op for 3 (λ (a b f) (for a b (λ (x) (f x))))
- {[(min max fn)
- "Call the function `fn` with a single integer argument, starting from
- `min` and ending with `max`.
-
- Examples:
-
- (for 0 2 (λ (i) (print (- 2 i)))) → 210"]})
- (op tapply)
- (op sub2)
- (op argc.l)
- (op vargc.l)
- (op call.l)
- (op tcall.l)
- (op brne.l)
- (op brnn.l)
- (op aref -2 (λ rest (apply aref rest))
- {[(sequence subscript0 . rest)
- "Return the sequence element specified by the subscripts. The sequence
- can be an array, vector, a list. Multi-dimensional sequences
- of variating types are also supported.
-
- Examples:
-
- (def a '((1 #(2 (3)) 4)))
- (aref a 0) → (1 (2 (3)) 4)
- (aref a 1) → index 1 out of bounds
- (aref a 0 0) → 1
- (aref a 0 1 0) → 2
- (aref a 0 2) → 4"]})
- (op box.l)
- (op optargs)
- (op dummy_eof)
-))
-
-(def (new path)
- (file path :write :create :truncate))
-
-(let ((c-header (buffer)) ; to avoid broken code truncating valid files
- (c-code (buffer))
- (instructions (new "instructions.lsp"))
- (builtins (new "builtins.lsp"))
- (docs-ops (new "docs_ops.lsp"))
- (op-to-byte (table))
- (c-op-to-op-arg (table))
- (op-to-argc (table))
- (op-to-closure ())
- (i 0))
- (io-write c-header "typedef enum {\n")
- (for-each
- (λ (op)
- (let {[lop (sym (op-name op))]
- [argc (op-nargs op)]}
- (io-write c-header (str "\t" (op-cname op) ",\n"))
- (for-each (λ (doc)
- (let* {[args (car doc)]
- [sig (cons lop args)]
- [docargs (cdr doc)]
- [docstr (car docargs)]}
- (unless (str? docstr)
- (error lop ": documentation must be a string"))
- (unless (or (sym? sig) (cons? sig))
- (error lop ": invalid signature"))
- (write `(doc-for ,sig ,@docargs) docs-ops)
- (newline docs-ops)))
- (op-docs op))
- (put! op-to-byte lop (byte i))
- (when argc
- (put! c-op-to-op-arg (op-cname op) (list lop (if (eq? argc T) 'ANYARGS argc)))
- (when (and (num? argc) (>= argc 0))
- (put! op-to-argc lop argc)))
- (set! op-to-closure (cons (op-closure op) op-to-closure))
- (set! i (1+ i))))
- ops)
- (io-close docs-ops)
- (io-write c-header "\tN_OPCODES\n}sl_op;\n\n")
- (io-write c-header "extern const Builtin builtins[N_OPCODES];\n")
-
- (io-write c-code "#include \"sl.h\"\n\n")
- (io-write c-code "const Builtin builtins[N_OPCODES] = {\n")
- (for-each
- (λ (c la) (begin (io-write c-code (str "\t[" c))
- (io-write c-code "] = {\"")
- (write (car la) c-code)
- (io-write c-code "\", ")
- (write (cadr la) c-code)
- (io-write c-code "},\n")))
- c-op-to-op-arg)
- (io-write c-code "};\n")
-
- (write `(def Instructions
- "VM instructions mapped to their encoded byte representation."
- ,op-to-byte)
- instructions)
- (newline instructions)
- (newline instructions)
- (write `(def arg-counts
- "VM instructions mapped to their expected arguments count."
- ,op-to-argc)
- instructions)
- (newline instructions)
- (io-close instructions)
- (set! op-to-closure (cons vec (reverse! op-to-closure)))
- (write `(def *builtins*
- "VM instructions as closures."
- ,op-to-closure)
- builtins)
- (newline builtins)
- (io-close builtins)
-
- ;; at last, copy the buffers to the actual files in git repo.
- (io-seek c-header 0)
- (io-copy (new "opcodes.h") c-header)
- (io-seek c-code 0)
- (io-copy (new "opcodes.c") c-code))
--- /dev/null
+++ b/tools/gen.sl
@@ -1,0 +1,461 @@
+(defstruct op name cname nargs closure docs)
+
+(def (rune-alphanumeric? r)
+ (or (rune-alphabetic? r)
+ (rune-numeric? r)))
+
+(def (name->cname name)
+ (let {[cname (buffer)]}
+ (for 0 (1- (length name))
+ (λ (i) (let {[r (rune (aref name i))]}
+ (io-write cname
+ (cond [(rune-alphanumeric? r) (rune-upcase r)]
+ [(= r #\?) #\P]
+ [(= r #\_) #\_]
+ [else ""])))))
+ (io->str cname)))
+
+(defmacro (op symbol (nargs NIL) (closure NIL) (docs NIL) (:cname NIL))
+ (let ((name (str symbol)))
+ `(make-op :name ,name
+ :cname ,(str "OP_" (or cname (name->cname name)))
+ :nargs ,nargs
+ :closure ',closure
+ :docs ',docs)))
+
+(def ops (vec
+ (op loada0)
+ (op loada1)
+ (op loadv)
+ (op brn)
+ (op pop)
+ (op call)
+ (op tcall)
+ (op loadg)
+ (op loada)
+ (op loadc)
+ (op ret)
+ (op dup)
+ (op car 1 (λ (x) (car x))
+ {[(lst)
+ "Return the first element of a cons cell (head of a list) or `NIL` if
+ not available.
+
+ Examples:
+
+ (car NIL) → NIL
+ (car '(1 2 3)) → 1
+ (car '(1 . 2)) → 1"]})
+ (op cdr 1 (λ (x) (cdr x))
+ {[(lst)
+ "Return the second element of a cons cell (tail of a list) or `NIL` if
+ not available.
+
+ Examples:
+
+ (cdr NIL) → NIL
+ (cdr '(1 2 3)) → (2 3)
+ (cdr '(1 . 2)) → 2"]})
+ (op closure)
+ (op seta)
+ (op jmp)
+ (op loadc0)
+ (op cons? 1 (λ (x) (cons? x))
+ {[(v)
+ "Return `T` if `v` is a cons cell, `NIL` otherwise.
+
+ Examples:
+
+ (cons? 0) → NIL
+ (cons? NIL) → NIL
+ (cons? '(1)) → T"]})
+ (op brne)
+ (op loadt)
+ (op load0)
+ (op loadc1)
+ (op aref2)
+ (op atom? 1 (λ (x) (atom? x))
+ {[(value)
+ "Return `T` if `v` is a _not_ a cons cell, `NIL` otherwise. This is
+ the opposite of `cons?`.
+
+ The term \"atom\" comes from the idea of being indivisible.
+
+ Examples:
+
+ (atom? \"a\") → T
+ (atom? NIL) → T
+ (atom? '(1)) → NIL"]})
+ (op loadvoid)
+ (op brnn)
+ (op load1)
+ (op < -1 (λ rest (apply < rest))
+ {[(a . rest)
+ "Return `T` if the arguments are in strictly increasing order (next
+ one is greater than the previous one). With a single argument
+ the result is always `T`."]}
+ :cname "LT")
+ (op add2)
+ (op set-cdr! 2 (λ (x y) (set-cdr! x y))
+ {[(cell new-second)
+ "Modify a cons cell (a list) in-place by putting `new-second` as its
+ second element (tail of the list). Return the modified cons
+ cell (list).
+
+ Examples:
+
+ (def q '(1 2 3 4 5))
+ (set-cdr! q '(6 7)) → (1 6 7)
+ q → (1 6 7)"]})
+ (op keyargs)
+ (op cons 2 (λ (x y) (cons x y))
+ {[(first second)
+ "Return a cons cell containing two arguments.
+
+ Examples:
+
+ (cons 1 2) → (1 . 2)
+ (cons 1 '(2)) → (1 2)
+ (cons 1 (cons 2 (cons 3 NIL))) → (1 2 3)"]})
+ (op eq? 2 (λ (x y) (eq? x y))
+ {[(a b)
+ "Return `T` if `a` and `b` are the same object, `NIL` otherwise.
+
+ Examples:
+
+ (eq? 0.0 0) → NIL
+ (eq? 0 0) → T
+ (def a \"1\")
+ (def b \"1\")
+ (eq? a b) → NIL
+ (def a '(1))
+ (def b '(1))
+ (eq? a b) → NIL"]})
+ (op sym? 1 (λ (x) (sym? x))
+ {[(v)
+ "Return `T` if `v` is a symbol, `NIL` otherwise."]})
+ (op not 1 (λ (x) (not x))
+ {[(v)
+ "Return `T` if `v` is `NIL`, `T` otherwise."]})
+ (op cadr 1 (λ (x) (cadr x))
+ {[(cell)
+ "Shorthand for `(car (cdr cell))`, that is, \"first element of the
+ second element\".
+
+ Examples:
+
+ (cadr '(1 2 3)) → 2
+ (cadr '(1)) → NIL
+ (cadr NIL) → NIL"]})
+ (op neg)
+ (op nan? 1 (λ (x) (nan? x))
+ {[(v)
+ "Return `T` if `v` is a floating point representation of NaN, either
+ negative or positive, `NIL` otherwise."]})
+ (op brbound)
+ (op num? 1 (λ (x) (num? x))
+ {[(v)
+ "Return `T` if `v` is of a numerical type, `NIL` otherwise.
+
+ Numerical types include floating point, fixnum, bignum, etc.
+ Note: ironically, a NaN value is considered a number by this function
+ since it's only testing the _type_ of the value."]})
+ (op fixnum? 1 (λ (x) (fixnum? x))
+ {[(v)
+ "Return `T` if `v` is of a fixnum type, `NIL` otherwise."]})
+ (op bound? 1 (λ (x) (bound? x))
+ {[(symbol)
+ "Return `T` if `symbol` has a value associated with it, `NIL` otherwise."]})
+ (op builtin? 1 (λ (x) (builtin? x))
+ {[(v)
+ "Return `T` if `v` is a built-in function implemented in C, `NIL`
+ otherwise.
+
+ Examples:
+
+ (builtin? map) → T
+ (builtin? macroexpand) → NIL"]})
+ (op fn? 1 (λ (x) (fn? x))
+ {[(v)
+ "Return `T` if `v` is a function, `NIL` otherwise.
+
+ Examples:
+
+ (fn? map) → T
+ (fn? macroexpand) → T"]})
+ (op vec? 1 (λ (x) (vec? x))
+ {[(v)
+ "Return `T` if `v` is a vector, `NIL` otherwise."]})
+ (op shift)
+ (op set-car! 2 (λ (x y) (set-car! x y))
+ {[(cell new-first)
+ "Modify a cons cell (a list) in-place by putting `new-first` as its
+ first element (head of the list). Return the modified cons
+ cell (list).
+
+ Examples:
+
+ (def q '(1 2 3 4 5))
+ (set-car! q 0) → (0 6 7)
+ q → (0 6 7)"]})
+ (op jmp.l)
+ (op brn.l)
+ (op box)
+ (op eqv? 2 (λ (x y) (eqv? x y))
+ {[(a b)
+ "Return `T` if both `a` and `b` are of the same value and primitive
+ (leaf) type, `NIL` otherwise. Neither cons cell nor vector are not
+ considered primitive types as they may define deep structures.
+
+ Examples:
+
+ (eqv? 0.0 0) → NIL
+ (eqv? 0 0) → T
+ (def a \"1\")
+ (def b \"1\")
+ (eqv? a b) → T
+ (def a '(1))
+ (def b '(1))
+ (eqv? a b) → NIL"]})
+ (op equal? 2 (λ (x y) (equal? x y))
+ {[(a b)
+ "Return `T` if both `a` and `b` are of the same value. For non-leaf
+ types (cons cell and vector), the equality test is performed
+ throughout the whole structure of the values.
+
+ Examples:
+
+ (equal? 0.0 0) → NIL
+ (equal? 0 0) → T
+ (def a \"1\")
+ (def b \"1\")
+ (equal? a b) → T
+ (def a '(1))
+ (def b '(1))
+ (equal? a b) → T"]})
+ (op list T (λ rest rest)
+ {[rest
+ "Return a list constructed of the arguments.
+
+ Examples:
+
+ (list) → NIL ; empty list
+ (list 1 2.5 \"a\" 'b) → (1 2.5 \"a\" b)"]})
+ (op apply -2 (λ rest (apply apply rest))
+ {[(fn arg . rest)
+ "Return the result of applying a function to a list of arguments.
+
+ The last argument must always be a list which gets spliced as
+ arguments to the function.
+
+ Examples:
+
+ (apply + 1 2 '(3 4 5)) → 15
+ (apply vec '(1 2 3)) → #(3 4 5)
+ (apply arr 'u8 '(3 4 5)) → #vu8(3 4 5)"]})
+ (op + T (λ rest (apply + rest))
+ {[rest
+ "Return sum of the arguments or `0` when none specified."]}
+ :cname "ADD")
+ (op - -1 (λ rest (apply - rest))
+ {[(a . rest)
+ "Return the result of subtraction. With only one argument a
+ negation is performed.
+
+ Examples:
+
+ (- 1.5) → -1.5
+ (- 3 2) → 1"]}
+ :cname "SUB")
+ (op * T (λ rest (apply * rest))
+ {[rest
+ "Return product of the arguments or `1` when none specified."]}
+ :cname "MUL")
+ (op / -1 (λ rest (apply / rest))
+ {[(x . rest)
+ "Return the division of the arguments. With only one argument the
+ result of `1/x` is returned. If the result is integer-valued, it is
+ returned as an integer.
+
+ Examples:
+
+ (/ 2) → 0.5
+ (/ 7 2 2) → 1.75
+ (/ 10 -2) → -5 ; a fixnum
+ (/ 6.9 1.9) → 3.6315…"]}
+ :cname "DIV")
+ (op div0 2 (λ rest (apply div0 rest))
+ {[(a b)
+ "Return the quotient of two numbers. For non-integers this is
+ equivalent to `(div0 (floor a) (floor b))`. The result is always an
+ integer.
+
+ Examples:
+
+ (div0 7 2) → 3
+ (div0 10 -2) → -5
+ (div0 6.9 1.9) → 6"]})
+ (op = -1 (λ rest (apply = rest))
+ {[(a . rest)
+ "Numerical equality test. Return `T` if all numbers are equal,
+ `NIL` otherwise."]}
+ :cname "NUMEQP")
+ (op compare 2 (λ (x y) (compare x y))
+ {[(x y)
+ "Return -1 if `x` is less than `y`, 0 if equal, and `1` if `y` is
+ greater than `x`.
+
+ Examples:
+
+ (compare 'a 'b) → -1
+ (compare 1 1) → 0
+ (compare \"b\" \"a\") → 1"]})
+ (op argc)
+ (op vec T (λ rest (apply vec rest))
+ {[rest
+ "Return a vector constructed of the arguments.
+
+ Examples:
+
+ (vec) → #() ; empty vector
+ (vec 1 2.5 \"a\" 'b) → #(1 2.5 \"a\" b)"]})
+ (op aset! -3 (λ rest (apply aset! rest))
+ {[(sequence subscripts… new-value)
+ "Modify the sequence element specified by the subscripts and return the
+ new value. The sequence can be an array, vector, a list.
+ Multi-dimensional sequences of variating types are also supported.
+
+ Examples:
+
+ (def a '((1 #(2 (3)) 4)))
+ (aset! a 1 'x) → index 1 out of bounds
+ (aset! a 0 0 'x) → x
+ a → ((x #(2 (3)) 4))
+ (aset! a 0 1 9) → 9
+ a → ((x #(9 (3)) 4))"]})
+ (op loadnil)
+ (op loadi8)
+ (op loadv.l)
+ (op loadg.l)
+ (op loada.l)
+ (op loadc.l)
+ (op setg)
+ (op setg.l)
+ (op seta.l)
+ (op vargc)
+ (op trycatch)
+ (op for 3 (λ (a b f) (for a b (λ (x) (f x))))
+ {[(min max fn)
+ "Call the function `fn` with a single integer argument, starting from
+ `min` and ending with `max`.
+
+ Examples:
+
+ (for 0 2 (λ (i) (print (- 2 i)))) → 210"]})
+ (op tapply)
+ (op sub2)
+ (op argc.l)
+ (op vargc.l)
+ (op call.l)
+ (op tcall.l)
+ (op brne.l)
+ (op brnn.l)
+ (op aref -2 (λ rest (apply aref rest))
+ {[(sequence subscript0 . rest)
+ "Return the sequence element specified by the subscripts. The sequence
+ can be an array, vector, a list. Multi-dimensional sequences
+ of variating types are also supported.
+
+ Examples:
+
+ (def a '((1 #(2 (3)) 4)))
+ (aref a 0) → (1 (2 (3)) 4)
+ (aref a 1) → index 1 out of bounds
+ (aref a 0 0) → 1
+ (aref a 0 1 0) → 2
+ (aref a 0 2) → 4"]})
+ (op box.l)
+ (op optargs)
+ (op dummy_eof)
+))
+
+(def (new path)
+ (file path :write :create :truncate))
+
+(let ((c-header (buffer)) ; to avoid broken code truncating valid files
+ (c-code (buffer))
+ (instructions (new "instructions.sl"))
+ (builtins (new "builtins.sl"))
+ (docs-ops (new "docs_ops.sl"))
+ (op-to-byte (table))
+ (c-op-to-op-arg (table))
+ (op-to-argc (table))
+ (op-to-closure ())
+ (i 0))
+ (io-write c-header "typedef enum {\n")
+ (for-each
+ (λ (op)
+ (let {[lop (sym (op-name op))]
+ [argc (op-nargs op)]}
+ (io-write c-header (str "\t" (op-cname op) ",\n"))
+ (for-each (λ (doc)
+ (let* {[args (car doc)]
+ [sig (cons lop args)]
+ [docargs (cdr doc)]
+ [docstr (car docargs)]}
+ (unless (str? docstr)
+ (error lop ": documentation must be a string"))
+ (unless (or (sym? sig) (cons? sig))
+ (error lop ": invalid signature"))
+ (write `(doc-for ,sig ,@docargs) docs-ops)
+ (newline docs-ops)))
+ (op-docs op))
+ (put! op-to-byte lop (byte i))
+ (when argc
+ (put! c-op-to-op-arg (op-cname op) (list lop (if (eq? argc T) 'ANYARGS argc)))
+ (when (and (num? argc) (>= argc 0))
+ (put! op-to-argc lop argc)))
+ (set! op-to-closure (cons (op-closure op) op-to-closure))
+ (set! i (1+ i))))
+ ops)
+ (io-close docs-ops)
+ (io-write c-header "\tN_OPCODES\n}sl_op;\n\n")
+ (io-write c-header "extern const Builtin builtins[N_OPCODES];\n")
+
+ (io-write c-code "#include \"sl.h\"\n\n")
+ (io-write c-code "const Builtin builtins[N_OPCODES] = {\n")
+ (for-each
+ (λ (c la) (begin (io-write c-code (str "\t[" c))
+ (io-write c-code "] = {\"")
+ (write (car la) c-code)
+ (io-write c-code "\", ")
+ (write (cadr la) c-code)
+ (io-write c-code "},\n")))
+ c-op-to-op-arg)
+ (io-write c-code "};\n")
+
+ (write `(def Instructions
+ "VM instructions mapped to their encoded byte representation."
+ ,op-to-byte)
+ instructions)
+ (newline instructions)
+ (newline instructions)
+ (write `(def arg-counts
+ "VM instructions mapped to their expected arguments count."
+ ,op-to-argc)
+ instructions)
+ (newline instructions)
+ (io-close instructions)
+ (set! op-to-closure (cons vec (reverse! op-to-closure)))
+ (write `(def *builtins*
+ "VM instructions as closures."
+ ,op-to-closure)
+ builtins)
+ (newline builtins)
+ (io-close builtins)
+
+ ;; at last, copy the buffers to the actual files in git repo.
+ (io-seek c-header 0)
+ (io-copy (new "opcodes.h") c-header)
+ (io-seek c-code 0)
+ (io-copy (new "opcodes.c") c-code))
--- a/tools/mkboot0.lsp
+++ /dev/null
@@ -1,28 +1,0 @@
-(def update-compiler
- (let ((C ()))
- (with-bindings
- ((eval (λ (x) (set! C (cons (compile-thunk (macroexpand x)) C)))))
- (begin
- (load "instructions.lsp")
- (load "compiler.lsp")))
- (λ () (begin
- (for-each (λ (x) (x)) (reverse! C))
- (set! update-compiler (λ () ()))))))
-
-(def (compile-file inf)
- (let ((in (file inf :read)))
- (let next ((E (read in)))
- (if (not (io-eof? in))
- (begin
- (print (compile-thunk (macroexpand E)))
- (newline)
- (next (read in)))))
- (io-close in)))
-
-(def (do-boot0)
- (for-each (λ (file)
- (compile-file file))
- (cdr *argv*)))
-
-(update-compiler)
-(do-boot0)
--- /dev/null
+++ b/tools/mkboot0.sl
@@ -1,0 +1,28 @@
+(def update-compiler
+ (let ((C ()))
+ (with-bindings
+ ((eval (λ (x) (set! C (cons (compile-thunk (macroexpand x)) C)))))
+ (begin
+ (load "instructions.sl")
+ (load "compiler.sl")))
+ (λ () (begin
+ (for-each (λ (x) (x)) (reverse! C))
+ (set! update-compiler (λ () ()))))))
+
+(def (compile-file inf)
+ (let ((in (file inf :read)))
+ (let next ((E (read in)))
+ (if (not (io-eof? in))
+ (begin
+ (print (compile-thunk (macroexpand E)))
+ (newline)
+ (next (read in)))))
+ (io-close in)))
+
+(def (do-boot0)
+ (for-each (λ (file)
+ (compile-file file))
+ (cdr *argv*)))
+
+(update-compiler)
+(do-boot0)
--- a/tools/mkboot1.lsp
+++ /dev/null
@@ -1,7 +1,0 @@
-(load "../src/builtins.lsp")
-(load "../src/instructions.lsp")
-(load "../src/system.lsp")
-#.(load "../src/docs_extra.lsp")
-#.(load "../src/docs_ops.lsp")
-(load "../src/compiler.lsp")
-(make-system-image "sl.boot")
--- /dev/null
+++ b/tools/mkboot1.sl
@@ -1,0 +1,7 @@
+(load "../src/builtins.sl")
+(load "../src/instructions.sl")
+(load "../src/system.sl")
+#.(load "../src/docs_extra.sl")
+#.(load "../src/docs_ops.sl")
+(load "../src/compiler.sl")
+(make-system-image "sl.boot")