femtolisp/femtolisp/system.lsp

531 lines
16 KiB
Plaintext
Raw Normal View History

; -*- scheme -*-
2008-06-30 21:54:22 -04:00
; femtoLisp standard library
; by Jeff Bezanson (C) 2009
; Distributed under the BSD License
2008-06-30 21:54:22 -04:00
(set-constant! 'eq eq?)
(set-constant! 'eqv eqv?)
(set-constant! 'equal equal?)
(set-constant! 'booleanp boolean?)
(set-constant! 'consp pair?)
(set-constant! 'null null?)
(set-constant! 'atom atom?)
(set-constant! 'symbolp symbol?)
(set-constant! 'numberp number?)
(set-constant! 'boundp bound?)
(set-constant! 'builtinp builtin?)
(set-constant! 'vectorp vector?)
(set-constant! 'fixnump fixnum?)
(set-constant! 'rplaca set-car!)
(set-constant! 'rplacd set-cdr!)
(set-constant! 'char? (lambda (x) (eq? (typeof x) 'wchar)))
(set-constant! 'T #t)
2008-06-30 21:54:22 -04:00
; convert a sequence of body statements to a single expression.
; this allows define, defun, defmacro, let, etc. to contain multiple
; body expressions as in Common Lisp.
(set! f-body (lambda (e)
2008-06-30 21:54:22 -04:00
(cond ((atom e) e)
((eq (cdr e) ()) (car e))
(T (cons 'begin e)))))
2008-06-30 21:54:22 -04:00
(set-syntax! 'define-macro
(lambda (form . body)
(list 'set-syntax! (list 'quote (car form))
(list 'lambda (cdr form) (f-body body)))))
(define-macro (label name fn)
(list (list 'lambda (list name) (list 'set! name fn)) #f))
2008-06-30 21:54:22 -04:00
(define-macro (define form . body)
(if (symbolp form)
(list 'set! form (car body))
(list 'set! (car form) (list 'lambda (cdr form) (f-body body)))))
2008-06-30 21:54:22 -04:00
(define (set s v) (eval (list 'set! s (list 'quote v))))
(define (identity x) x)
2008-06-30 21:54:22 -04:00
(define (map f lst)
2008-06-30 21:54:22 -04:00
(if (atom lst) lst
(cons (f (car lst)) (map f (cdr lst)))))
2008-06-30 21:54:22 -04:00
(define-macro (let binds . body)
2008-06-30 21:54:22 -04:00
(cons (list 'lambda
(map (lambda (c) (if (consp c) (car c) c)) binds)
(f-body body))
(map (lambda (c) (if (consp c) (cadr c) #f)) binds)))
2008-06-30 21:54:22 -04:00
(define (nconc . lsts)
2008-06-30 21:54:22 -04:00
(cond ((null lsts) ())
((null (cdr lsts)) (car lsts))
((null (car lsts)) (apply nconc (cdr lsts)))
(T (prog1 (car lsts)
(rplacd (last (car lsts))
(apply nconc (cdr lsts)))))))
2008-06-30 21:54:22 -04:00
(define (append . lsts)
2008-06-30 21:54:22 -04:00
(cond ((null lsts) ())
((null (cdr lsts)) (car lsts))
(T ((label append2 (lambda (l d)
(if (null l) d
(cons (car l)
(append2 (cdr l) d)))))
(car lsts) (apply append (cdr lsts))))))
(define (member item lst)
(cond ((atom lst) #f)
((equal (car lst) item) lst)
(T (member item (cdr lst)))))
(define (memq item lst)
(cond ((atom lst) #f)
((eq (car lst) item) lst)
(T (memq item (cdr lst)))))
(define (memv item lst)
(cond ((atom lst) #f)
((eqv (car lst) item) lst)
(T (memv item (cdr lst)))))
(define (assoc item lst)
(cond ((atom lst) #f)
((equal (caar lst) item) (car lst))
(T (assoc item (cdr lst)))))
(define (assv item lst)
(cond ((atom lst) #f)
((eqv (caar lst) item) (car lst))
(T (assv item (cdr lst)))))
(define (macrocall? e) (and (symbolp (car e))
(symbol-syntax (car e))))
(define (function? x)
2008-06-30 21:54:22 -04:00
(or (builtinp x)
(and (consp x) (eq (car x) 'lambda))))
(define procedure? function?)
2008-06-30 21:54:22 -04:00
(define (macroexpand-1 e)
2008-06-30 21:54:22 -04:00
(if (atom e) e
(let ((f (macrocall? e)))
(if f (apply f (cdr e))
e))))
2008-06-30 21:54:22 -04:00
; convert to proper list, i.e. remove "dots", and append
(define (append.2 l tail)
2008-06-30 21:54:22 -04:00
(cond ((null l) tail)
((atom l) (cons l tail))
(T (cons (car l) (append.2 (cdr l) tail)))))
(define (cadr x) (car (cdr x)))
;(set! *special-forms* '(quote cond if and or while lambda trycatch
; set! begin))
2008-07-11 22:58:55 -04:00
(define (macroexpand e)
2008-06-30 21:54:22 -04:00
((label mexpand
(lambda (e env f)
(begin
2008-06-30 21:54:22 -04:00
(while (and (consp e)
(not (member (car e) env))
(set! f (macrocall? e)))
(set! e (apply f (cdr e))))
2008-07-11 22:58:55 -04:00
(cond ((and (consp e)
(not (eq (car e) 'quote)))
(let ((newenv
(if (and (eq (car e) 'lambda)
2008-07-11 22:58:55 -04:00
(consp (cdr e)))
(append.2 (cadr e) env)
env)))
(map (lambda (x) (mexpand x newenv ())) e)))
;((and (symbolp e) (constant? e)) (eval e))
2008-07-11 22:58:55 -04:00
;((and (symbolp e)
; (not (member e *special-forms*))
; (not (member e env))) (cons '%top e))
(T e)))))
e () ()))
(define-macro (define form . body)
(if (symbolp form)
(list 'set! form (car body))
(list 'set! (car form)
(macroexpand (list 'lambda (cdr form) (f-body body))))))
(define-macro (define-macro form . body)
(list 'set-syntax! (list 'quote (car form))
(macroexpand (list 'lambda (cdr form) (f-body body)))))
(define macroexpand (macroexpand macroexpand))
(define = equal)
(define eql eqv)
2008-06-30 21:54:22 -04:00
(define (/= a b) (not (equal a b)))
(define != /=)
(define (> a b) (< b a))
(define (<= a b) (not (< b a)))
(define (>= a b) (not (< a b)))
(define (1+ n) (+ n 1))
(define (1- n) (- n 1))
(define (mod x y) (- x (* (/ x y) y)))
(define (abs x) (if (< x 0) (- x) x))
(define K prog1) ; K combinator ;)
2008-06-30 21:54:22 -04:00
(define (caar x) (car (car x)))
(define (cdar x) (cdr (car x)))
(define (cddr x) (cdr (cdr x)))
(define (caaar x) (car (car (car x))))
(define (caadr x) (car (car (cdr x))))
(define (cadar x) (car (cdr (car x))))
(define (caddr x) (car (cdr (cdr x))))
(define (cadddr x) (car (cdr (cdr (cdr x)))))
2008-06-30 21:54:22 -04:00
(define (cdaar x) (cdr (car (car x))))
(define (cdadr x) (cdr (car (cdr x))))
(define (cddar x) (cdr (cdr (car x))))
(define (cdddr x) (cdr (cdr (cdr x))))
(define (every pred lst)
2008-06-30 21:54:22 -04:00
(or (atom lst)
(and (pred (car lst))
(every pred (cdr lst)))))
(define (any pred lst)
2008-06-30 21:54:22 -04:00
(and (consp lst)
(or (pred (car lst))
(any pred (cdr lst)))))
(define (listp a) (or (null a) (consp a)))
(define (list? a) (or (null a) (and (pair? a) (list? (cdr a)))))
2008-06-30 21:54:22 -04:00
(define (nthcdr lst n)
2008-06-30 21:54:22 -04:00
(if (<= n 0) lst
(nthcdr (cdr lst) (- n 1))))
2008-06-30 21:54:22 -04:00
(define (list-ref lst n)
(car (nthcdr lst n)))
2008-06-30 21:54:22 -04:00
(define (list* . l)
2008-06-30 21:54:22 -04:00
(if (atom (cdr l))
(car l)
(cons (car l) (apply list* (cdr l)))))
2008-06-30 21:54:22 -04:00
(define (nlist* . l)
2008-06-30 21:54:22 -04:00
(if (atom (cdr l))
(car l)
(rplacd l (apply nlist* (cdr l)))))
2008-06-30 21:54:22 -04:00
(define (lastcdr l)
2008-06-30 21:54:22 -04:00
(if (atom l) l
(lastcdr (cdr l))))
2008-06-30 21:54:22 -04:00
(define (last l)
2008-06-30 21:54:22 -04:00
(cond ((atom l) l)
((atom (cdr l)) l)
(T (last (cdr l)))))
(define (map! f lst)
2008-06-30 21:54:22 -04:00
(prog1 lst
(while (consp lst)
(rplaca lst (f (car lst)))
(set! lst (cdr lst)))))
2008-06-30 21:54:22 -04:00
(define (mapcar f . lsts)
2008-06-30 21:54:22 -04:00
((label mapcar-
(lambda (lsts)
(cond ((null lsts) (f))
((atom (car lsts)) (car lsts))
(T (cons (apply f (map car lsts))
(mapcar- (map cdr lsts)))))))
lsts))
(define (transpose M) (apply mapcar (cons list M)))
2008-06-30 21:54:22 -04:00
(define (filter pred lst) (filter- pred lst ()))
(define (filter- pred lst accum)
(cond ((null lst) accum)
((pred (car lst))
(filter- pred (cdr lst) (cons (car lst) accum)))
(T
(filter- pred (cdr lst) accum))))
(define (separate pred lst) (separate- pred lst () ()))
(define (separate- pred lst yes no)
(cond ((null lst) (cons yes no))
((pred (car lst))
(separate- pred (cdr lst) (cons (car lst) yes) no))
(T
(separate- pred (cdr lst) yes (cons (car lst) no)))))
2008-06-30 21:54:22 -04:00
(define (foldr f zero lst)
(if (null lst) zero
(f (car lst) (foldr f zero (cdr lst)))))
(define (foldl f zero lst)
(if (null lst) zero
(foldl f (f (car lst) zero) (cdr lst))))
(define (reverse lst) (foldl cons () lst))
2008-06-30 21:54:22 -04:00
(define (copy-list l)
(if (atom l) l
(cons (car l)
(copy-list (cdr l)))))
(define (copy-tree l)
(if (atom l) l
(cons (copy-tree (car l))
(copy-tree (cdr l)))))
(define (nreverse l)
(let ((prev ()))
2008-06-30 21:54:22 -04:00
(while (consp l)
(set! l (prog1 (cdr l)
(rplacd l (prog1 prev
(set! prev l))))))
2008-06-30 21:54:22 -04:00
prev))
(define-macro (let* binds . body)
2008-06-30 21:54:22 -04:00
(cons (list 'lambda (map car binds)
(cons 'begin
(nconc (map (lambda (b) (cons 'set! b)) binds)
2008-06-30 21:54:22 -04:00
body)))
(map (lambda (x) #f) binds)))
2008-06-30 21:54:22 -04:00
(define-macro (labels binds . body)
2008-06-30 21:54:22 -04:00
(cons (list 'lambda (map car binds)
(cons 'begin
2008-06-30 21:54:22 -04:00
(nconc (map (lambda (b)
(list 'set! (car b) (cons 'lambda (cdr b))))
2008-06-30 21:54:22 -04:00
binds)
body)))
(map (lambda (x) #f) binds)))
2008-06-30 21:54:22 -04:00
(define-macro (when c . body) (list 'if c (f-body body) #f))
(define-macro (unless c . body) (list 'if c #f (f-body body)))
2008-06-30 21:54:22 -04:00
(define-macro (dotimes var . body)
2008-06-30 21:54:22 -04:00
(let ((v (car var))
(cnt (cadr var)))
`(for 0 (- ,cnt 1)
(lambda (,v) ,(f-body body)))))
2008-06-30 21:54:22 -04:00
(define (map-int f n)
2008-06-30 21:54:22 -04:00
(if (<= n 0)
()
(let ((first (cons (f 0) ()))
(acc ()))
(set! acc first)
(for 1 (- n 1)
(lambda (i)
(begin (rplacd acc (cons (f i) ()))
(set! acc (cdr acc)))))
first)))
2008-06-30 21:54:22 -04:00
(define (iota n) (map-int identity n))
(define ι iota)
2008-06-30 21:54:22 -04:00
(define (error . args) (raise (cons 'error args)))
2008-06-30 21:54:22 -04:00
(define-macro (throw tag value) `(raise (list 'thrown-value ,tag ,value)))
(define-macro (catch tag expr)
2008-06-30 21:54:22 -04:00
(let ((e (gensym)))
`(trycatch ,expr
(lambda (,e) (if (and (consp ,e)
(eq (car ,e) 'thrown-value)
(eq (cadr ,e) ,tag))
(caddr ,e)
(raise ,e))))))
2008-06-30 21:54:22 -04:00
(define-macro (unwind-protect expr finally)
2008-06-30 21:54:22 -04:00
(let ((e (gensym)))
`(prog1 (trycatch ,expr
(lambda (,e) (begin ,finally (raise ,e))))
,finally)))
2008-06-30 21:54:22 -04:00
; (try expr
; (catch (type-error e) . exprs)
; (catch (io-error e) . exprs)
; (catch (e) . exprs)
; (finally . exprs))
(define-macro (try expr . forms)
2008-06-30 21:54:22 -04:00
(let* ((e (gensym))
(reraised (gensym))
(final (f-body (cdr (or (assq 'finally forms) '(())))))
2008-06-30 21:54:22 -04:00
(catches (filter (lambda (f) (eq (car f) 'catch)) forms))
(catchblock `(cond
,.(map (lambda (catc)
(let* ((specific (cdr (cadr catc)))
(extype (caadr catc))
(var (if specific (car specific)
extype))
(todo (cddr catc)))
`(,(if specific
; exception matching logic
`(or (eq ,e ',extype)
(and (consp ,e)
(eq (car ,e)
',extype)))
T); (catch (e) ...), match anything
(let ((,var ,e)) (begin ,@todo)))))
2008-06-30 21:54:22 -04:00
catches)
(T (raise ,e))))) ; no matches, reraise
(if final
(if catches
; form with both catch and finally
`(prog1 (trycatch ,expr
(lambda (,e)
(trycatch ,catchblock
(lambda (,reraised)
(begin ,final
2008-06-30 21:54:22 -04:00
(raise ,reraised))))))
,final)
; finally only; same as unwind-protect
`(prog1 (trycatch ,expr (lambda (,e)
(begin ,final (raise ,e))))
2008-06-30 21:54:22 -04:00
,final))
; catch, no finally
`(trycatch ,expr (lambda (,e) ,catchblock)))))
; setf
; expands (setf (place x ...) v) to (mutator (f x ...) v)
; (mutator (identity x ...) v) is interpreted as (mutator x ... v)
(set! *setf-place-list*
2008-06-30 21:54:22 -04:00
; place mutator f
'((car rplaca identity)
(cdr rplacd identity)
(caar rplaca car)
(cadr rplaca cdr)
(cdar rplacd car)
(cddr rplacd cdr)
(caaar rplaca caar)
(caadr rplaca cadr)
(cadar rplaca cdar)
(caddr rplaca cddr)
(cdaar rplacd caar)
(cdadr rplacd cadr)
(cddar rplacd cdar)
(cdddr rplacd cddr)
(list-ref rplaca nthcdr)
2008-06-30 21:54:22 -04:00
(get put identity)
(aref aset identity)
(symbol-syntax set-syntax! identity)))
2008-06-30 21:54:22 -04:00
(define (setf-place-mutator place val)
2008-06-30 21:54:22 -04:00
(if (symbolp place)
(list 'set! place val)
(let ((mutator (assq (car place) *setf-place-list*)))
2008-06-30 21:54:22 -04:00
(if (null mutator)
(error "setf: unknown place " (car place))
(if (eq (caddr mutator) 'identity)
(cons (cadr mutator) (append (cdr place) (list val)))
(list (cadr mutator)
(cons (caddr mutator) (cdr place))
val))))))
(define-macro (setf . args)
2008-06-30 21:54:22 -04:00
(f-body
((label setf-
(lambda (args)
(if (null args)
()
2008-06-30 21:54:22 -04:00
(cons (setf-place-mutator (car args) (cadr args))
(setf- (cddr args))))))
args)))
(define (revappend l1 l2) (nconc (reverse l1) l2))
(define (nreconc l1 l2) (nconc (nreverse l1) l2))
2008-06-30 21:54:22 -04:00
(define (list-to-vector l) (apply vector l))
(define (vector-to-list v)
(let ((n (length v))
(l ()))
(for 1 n
(lambda (i)
(set! l (cons (aref v (- n i)) l))))
2008-06-30 21:54:22 -04:00
l))
(define (self-evaluating? x)
(or (and (atom x)
(not (symbolp x)))
(and (constant? x)
(eq x (eval x)))))
2008-06-30 21:54:22 -04:00
; backquote
(define-macro (backquote x) (bq-process x))
2008-06-30 21:54:22 -04:00
(define (splice-form? x)
2008-06-30 21:54:22 -04:00
(or (and (consp x) (or (eq (car x) '*comma-at*)
(eq (car x) '*comma-dot*)))
(eq x '*comma*)))
(define (bq-process x)
(cond ((self-evaluating? x)
2008-06-30 21:54:22 -04:00
(if (vectorp x)
(let ((body (bq-process (vector-to-list x))))
(if (eq (car body) 'list)
(cons vector (cdr body))
(list apply vector body)))
x))
((atom x) (list 'quote x))
((eq (car x) 'backquote) (bq-process (bq-process (cadr x))))
((eq (car x) '*comma*) (cadr x))
((not (any splice-form? x))
2008-06-30 21:54:22 -04:00
(let ((lc (lastcdr x))
(forms (map bq-bracket1 x)))
(if (null lc)
(cons 'list forms)
(nconc (cons 'nlist* forms) (list (bq-process lc))))))
(T (let ((p x) (q ()))
(while (and (consp p)
(not (eq (car p) '*comma*)))
(set! q (cons (bq-bracket (car p)) q))
(set! p (cdr p)))
2008-06-30 21:54:22 -04:00
(let ((forms
(cond ((consp p) (nreconc q (list (cadr p))))
((null p) (nreverse q))
(T (nreconc q (list (bq-process p)))))))
(if (null (cdr forms))
(car forms)
(cons 'nconc forms)))))))
(define (bq-bracket x)
(cond ((atom x) (list list (bq-process x)))
((eq (car x) '*comma*) (list list (cadr x)))
2008-06-30 21:54:22 -04:00
((eq (car x) '*comma-at*) (list 'copy-list (cadr x)))
((eq (car x) '*comma-dot*) (cadr x))
(T (list list (bq-process x)))))
2008-06-30 21:54:22 -04:00
; bracket without splicing
(define (bq-bracket1 x)
2008-06-30 21:54:22 -04:00
(if (and (consp x) (eq (car x) '*comma*))
(cadr x)
(bq-process x)))
2008-06-30 21:54:22 -04:00
(define-macro (assert expr) `(if ,expr T (raise '(assert-failed ,expr))))
2008-06-30 21:54:22 -04:00
(define-macro (time expr)
2008-06-30 21:54:22 -04:00
(let ((t0 (gensym)))
`(let ((,t0 (time.now)))
(prog1
,expr
(princ "Elapsed time: " (- (time.now) ,t0) " seconds\n")))))
(define (display x) (princ x) (princ "\n"))
(define (vector.map f v)
(let* ((n (length v))
(nv (vector.alloc n)))
(for 0 (- n 1)
(lambda (i)
(aset nv i (f (aref v i)))))
nv))
(define (table.pairs t)
(table.foldl (lambda (k v z) (cons (cons k v) z))
() t))
(define (table.keys t)
(table.foldl (lambda (k v z) (cons k z))
() t))
(define (table.values t)
(table.foldl (lambda (k v z) (cons v z))
() t))
(define (table.clone t)
(let ((nt (table)))
(table.foldl (lambda (k v z) (put nt k v))
() t)
nt))