X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fboot.lisp;h=736c07dd35e2d4667787fff2d3cb6f970ab4aa20;hb=95984c591c75b8085adde1d478b224c2ed29eaa5;hp=de32e754be331d29320c11591ca31d561590eea3;hpb=ec5a0cce4f4b450e991db0d47f0e7998dbeda662;p=jscl.git diff --git a/src/boot.lisp b/src/boot.lisp index de32e75..736c07d 100644 --- a/src/boot.lisp +++ b/src/boot.lisp @@ -3,18 +3,18 @@ ;; Copyright (C) 2012, 2013 David Vazquez ;; Copyright (C) 2012 Raimon Grau -;; This program is free software: you can redistribute it and/or +;; JSCL is free software: you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation, either version 3 of the ;; License, or (at your option) any later version. ;; -;; This program is distributed in the hope that it will be useful, but +;; JSCL is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . +;; along with JSCL. If not, see . ;;; This code is executed when JSCL compiles this file itself. The ;;; compiler provides compilation of some special forms, as well as @@ -22,22 +22,23 @@ ;;; Lisp world from scratch. This code has to define enough language ;;; to the compiler to be able to run. -(eval-when-compile - (%compile-defmacro 'defmacro - '(function - (lambda (name args &rest body) - `(eval-when-compile - (%compile-defmacro ',name - '(function - (lambda ,(mapcar #'(lambda (x) - (if (eq x '&body) - '&rest - x)) - args) - ,@body)))))))) +(/debug "loading boot.lisp!") + +(eval-when (:compile-toplevel) + (let ((defmacro-macroexpander + '#'(lambda (form) + (destructuring-bind (name args &body body) + form + (let ((whole (gensym))) + `(eval-when (:compile-toplevel :execute) + (%compile-defmacro ',name + '#'(lambda (,whole) + (destructuring-bind ,args ,whole + ,@body))))))))) + (%compile-defmacro 'defmacro defmacro-macroexpander))) (defmacro declaim (&rest decls) - `(eval-when-compile + `(eval-when (:compile-toplevel :execute) ,@(mapcar (lambda (decl) `(!proclaim ',decl)) decls))) (defmacro defconstant (name value &optional docstring) @@ -45,7 +46,7 @@ (declaim (special ,name)) (declaim (constant ,name)) (setq ,name ,value) - ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring))) + ,@(when (stringp docstring) `((oset ,docstring ',name "vardoc"))) ',name)) (defconstant t 't) @@ -61,44 +62,24 @@ (defmacro unless (condition &body body) `(if ,condition nil (progn ,@body))) -(defmacro defvar (name value &optional docstring) +(defmacro defvar (name &optional (value nil value-p) docstring) `(progn (declaim (special ,name)) - (unless (boundp ',name) (setq ,name ,value)) - ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring))) + ,@(when value-p `((unless (boundp ',name) (setq ,name ,value)))) + ,@(when (stringp docstring) `((oset ,docstring ',name "vardoc"))) ',name)) (defmacro defparameter (name value &optional docstring) `(progn (setq ,name ,value) - ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring))) + ,@(when (stringp docstring) `((oset ,docstring ',name "vardoc"))) ',name)) -(defmacro named-lambda (name args &rest body) - (let ((x (gensym "FN"))) - `(let ((,x (lambda ,args ,@body))) - (oset ,x "fname" ,name) - ,x))) - (defmacro defun (name args &rest body) `(progn - (fset ',name - (named-lambda ,(symbol-name name) ,args - ,@(if (and (stringp (car body)) (not (null (cdr body)))) - `(,(car body) (block ,name ,@(cdr body))) - `((block ,name ,@body))))) + (fset ',name #'(named-lambda ,name ,args ,@body)) ',name)) -(defun null (x) - (eq x nil)) - -(defun endp (x) - (if (null x) - t - (if (consp x) - nil - (error "type-error")))) - (defmacro return (&optional value) `(return-from nil ,value)) @@ -108,139 +89,90 @@ (defvar *gensym-counter* 0) (defun gensym (&optional (prefix "G")) (setq *gensym-counter* (+ *gensym-counter* 1)) - (make-symbol (concat-two prefix (integer-to-string *gensym-counter*)))) + (make-symbol (concat prefix (integer-to-string *gensym-counter*)))) (defun boundp (x) (boundp x)) -;; Basic functions -(defun = (x y) (= x y)) -(defun * (x y) (* x y)) -(defun / (x y) (/ x y)) -(defun 1+ (x) (+ x 1)) -(defun 1- (x) (- x 1)) -(defun zerop (x) (= x 0)) - -(defun truncate (x &optional (y 1)) - (floor (/ x y))) +(defun fboundp (x) + (fboundp x)) +(defun eq (x y) (eq x y)) (defun eql (x y) (eq x y)) (defun not (x) (if x nil t)) -(defun cons (x y ) (cons x y)) -(defun consp (x) (consp x)) - -(defun car (x) - "Return the CAR part of a cons, or NIL if X is null." - (car x)) - -(defun cdr (x) (cdr x)) -(defun caar (x) (car (car x))) -(defun cadr (x) (car (cdr x))) -(defun cdar (x) (cdr (car x))) -(defun cddr (x) (cdr (cdr x))) -(defun cadar (x) (car (cdr (car x)))) -(defun caddr (x) (car (cdr (cdr x)))) -(defun cdddr (x) (cdr (cdr (cdr x)))) -(defun cadddr (x) (car (cdr (cdr (cdr x))))) -(defun first (x) (car x)) -(defun second (x) (cadr x)) -(defun third (x) (caddr x)) -(defun fourth (x) (cadddr x)) -(defun rest (x) (cdr x)) - -(defun list (&rest args) args) -(defun atom (x) - (not (consp x))) - -;; Basic macros - -(defmacro incf (place &optional (delta 1)) - (multiple-value-bind (dummies vals newval setter getter) - (get-setf-expansion place) - (let ((d (gensym))) - `(let* (,@(mapcar #'list dummies vals) - (,d ,delta) - (,(car newval) (+ ,getter ,d)) - ,@(cdr newval)) - ,setter)))) +(defun funcall (function &rest args) + (apply function args)) -(defmacro decf (place &optional (delta 1)) - (multiple-value-bind (dummies vals newval setter getter) - (get-setf-expansion place) - (let ((d (gensym))) - `(let* (,@(mapcar #'list dummies vals) - (,d ,delta) - (,(car newval) (- ,getter ,d)) - ,@(cdr newval)) - ,setter)))) +(defun apply (function arg &rest args) + (apply function (apply #'list* arg args))) -(defmacro push (x place) - (multiple-value-bind (dummies vals newval setter getter) - (get-setf-expansion place) - (let ((g (gensym))) - `(let* ((,g ,x) - ,@(mapcar #'list dummies vals) - (,(car newval) (cons ,g ,getter)) - ,@(cdr newval)) - ,setter)))) +;; Basic macros -(defmacro dolist (iter &body body) - (let ((var (first iter)) - (g!list (gensym))) +(defmacro dolist ((var list &optional result) &body body) + (let ((g!list (gensym))) + (unless (symbolp var) (error "`~S' is not a symbol." var)) `(block nil - (let ((,g!list ,(second iter)) + (let ((,g!list ,list) (,var nil)) (%while ,g!list (setq ,var (car ,g!list)) (tagbody ,@body) (setq ,g!list (cdr ,g!list))) - ,(third iter))))) + ,result)))) -(defmacro dotimes (iter &body body) - (let ((g!to (gensym)) - (var (first iter)) - (to (second iter)) - (result (third iter))) +(defmacro dotimes ((var count &optional result) &body body) + (let ((g!count (gensym))) + (unless (symbolp var) (error "`~S' is not a symbol." var)) `(block nil (let ((,var 0) - (,g!to ,to)) - (%while (< ,var ,g!to) + (,g!count ,count)) + (%while (< ,var ,g!count) (tagbody ,@body) (incf ,var)) ,result)))) (defmacro cond (&rest clausules) - (if (null clausules) - nil - (if (eq (caar clausules) t) - `(progn ,@(cdar clausules)) - (let ((test-symbol (gensym))) - `(let ((,test-symbol ,(caar clausules))) - (if ,test-symbol - ,(if (null (cdar clausules)) - test-symbol - `(progn ,@(cdar clausules))) - (cond ,@(cdr clausules)))))))) + (unless (null clausules) + (destructuring-bind (condition &body body) + (first clausules) + (cond + ((eq condition t) + `(progn ,@body)) + ((null body) + (let ((test-symbol (gensym))) + `(let ((,test-symbol ,condition)) + (if ,test-symbol + ,test-symbol + (cond ,@(rest clausules)))))) + (t + `(if ,condition + (progn ,@body) + (cond ,@(rest clausules)))))))) (defmacro case (form &rest clausules) (let ((!form (gensym))) `(let ((,!form ,form)) (cond ,@(mapcar (lambda (clausule) - (if (eq (car clausule) t) + (destructuring-bind (keys &body body) clausule - `((eql ,!form ',(car clausule)) - ,@(cdr clausule)))) + (if (or (eq keys 't) (eq keys 'otherwise)) + `(t nil ,@body) + (let ((keys (if (listp keys) keys (list keys)))) + `((or ,@(mapcar (lambda (key) `(eql ,!form ',key)) keys)) + nil ,@body))))) clausules))))) (defmacro ecase (form &rest clausules) - `(case ,form - ,@(append - clausules - `((t - (error "ECASE expression failed.")))))) + (let ((g!form (gensym))) + `(let ((,g!form ,form)) + (case ,g!form + ,@(append + clausules + `((t + (error "ECASE expression failed for the object `~S'." ,g!form)))))))) (defmacro and (&rest forms) (cond @@ -273,40 +205,12 @@ (defmacro prog2 (form1 result &body body) `(prog1 (progn ,form1 ,result) ,@body)) - - -;;; Go on growing the Lisp language in Ecmalisp, with more high level -;;; utilities as well as correct versions of other constructions. - -(defun + (&rest args) - (let ((r 0)) - (dolist (x args r) - (incf r x)))) - -(defun - (x &rest others) - (if (null others) - (- x) - (let ((r x)) - (dolist (y others r) - (decf r y))))) - -(defun append-two (list1 list2) - (if (null list1) - list2 - (cons (car list1) - (append (cdr list1) list2)))) - -(defun append (&rest lists) - (!reduce #'append-two lists)) - -(defun revappend (list1 list2) - (while list1 - (push (car list1) list2) - (setq list1 (cdr list1))) - list2) - -(defun reverse (list) - (revappend list '())) +(defmacro prog (inits &rest body ) + (multiple-value-bind (forms decls docstring) (parse-body body) + `(block nil + (let ,inits + ,@decls + (tagbody ,@forms))))) (defmacro psetq (&rest pairs) (let (;; For each pair, we store here a list of the form @@ -325,11 +229,13 @@ (setq assignments (reverse assignments)) ;; `(let ,(mapcar #'cdr assignments) - (setq ,@(!reduce #'append (mapcar #'butlast assignments)))))) + (setq ,@(!reduce #'append (mapcar #'butlast assignments) nil))))) (defmacro do (varlist endlist &body body) `(block nil - (let ,(mapcar (lambda (x) (list (first x) (second x))) varlist) + (let ,(mapcar (lambda (x) (if (symbolp x) + (list x nil) + (list (first x) (second x)))) varlist) (while t (when ,(car endlist) (return (progn ,@(cdr endlist)))) @@ -337,13 +243,16 @@ (psetq ,@(apply #'append (mapcar (lambda (v) - (and (consp (cddr v)) + (and (listp v) + (consp (cddr v)) (list (first v) (third v)))) varlist))))))) (defmacro do* (varlist endlist &body body) `(block nil - (let* ,(mapcar (lambda (x) (list (first x) (second x))) varlist) + (let* ,(mapcar (lambda (x1) (if (symbolp x1) + (list x1 nil) + (list (first x1) (second x1)))) varlist) (while t (when ,(car endlist) (return (progn ,@(cdr endlist)))) @@ -351,29 +260,11 @@ (setq ,@(apply #'append (mapcar (lambda (v) - (and (consp (cddr v)) + (and (listp v) + (consp (cddr v)) (list (first v) (third v)))) varlist))))))) -(defun list-length (list) - (let ((l 0)) - (while (not (null list)) - (incf l) - (setq list (cdr list))) - l)) - -(defun length (seq) - (cond - ((stringp seq) - (string-length seq)) - ((arrayp seq) - (oget seq "length")) - ((listp seq) - (list-length seq)))) - -(defun concat-two (s1 s2) - (concat-two s1 s2)) - (defmacro with-collect (&body body) (let ((head (gensym)) (tail (gensym))) @@ -386,186 +277,58 @@ ,@body) (cdr ,head)))) -(defun map1 (func list) - (with-collect - (while list - (collect (funcall func (car list))) - (setq list (cdr list))))) (defmacro loop (&body body) `(while t ,@body)) -(defun mapcar (func list &rest lists) - (let ((lists (cons list lists))) - (with-collect - (block loop - (loop - (let ((elems (map1 #'car lists))) - (do ((tail lists (cdr tail))) - ((null tail)) - (when (null (car tail)) (return-from loop)) - (rplaca tail (cdar tail))) - (collect (apply func elems)))))))) - (defun identity (x) x) +(defun complement (x) + (lambda (&rest args) + (not (apply x args)))) + (defun constantly (x) (lambda (&rest args) x)) -(defun copy-list (x) - (mapcar #'identity x)) - -(defun list* (arg &rest others) - (cond ((null others) arg) - ((null (cdr others)) (cons arg (car others))) - (t (do ((x others (cdr x))) - ((null (cddr x)) (rplacd x (cadr x)))) - (cons arg others)))) - -(defun code-char (x) x) -(defun char-code (x) x) -(defun char= (x y) (= x y)) - -(defun integerp (x) - (and (numberp x) (= (floor x) x))) - -(defun floatp (x) - (and (numberp x) (not (integerp x)))) - -(defun plusp (x) (< 0 x)) -(defun minusp (x) (< x 0)) - -(defun listp (x) - (or (consp x) (null x))) +(defun code-char (x) + (code-char x)) -(defun nthcdr (n list) - (while (and (plusp n) list) - (setq n (1- n)) - (setq list (cdr list))) - list) +(defun char-code (x) + (char-code x)) -(defun nth (n list) - (car (nthcdr n list))) +(defun char= (x y) + (eql x y)) -(defun last (x) - (while (consp (cdr x)) - (setq x (cdr x))) - x) +(defun char< (x y) + (< (char-code x) (char-code y))) -(defun butlast (x) - (and (consp (cdr x)) - (cons (car x) (butlast (cdr x))))) - -(defun member (x list) - (while list - (when (eql x (car list)) - (return list)) - (setq list (cdr list)))) - -(defun find (item list &key key (test #'eql)) - (dolist (x list) - (when (funcall test (funcall key x) item) - (return x)))) - -(defun remove (x list) - (cond - ((null list) - nil) - ((eql x (car list)) - (remove x (cdr list))) - (t - (cons (car list) (remove x (cdr list)))))) - -(defun remove-if (func list) - (cond - ((null list) - nil) - ((funcall func (car list)) - (remove-if func (cdr list))) - (t - ;; - (cons (car list) (remove-if func (cdr list)))))) +(defun atom (x) + (not (consp x))) -(defun remove-if-not (func list) - (cond - ((null list) - nil) - ((funcall func (car list)) - (cons (car list) (remove-if-not func (cdr list)))) - (t - (remove-if-not func (cdr list))))) +(defun alpha-char-p (x) + (or (<= (char-code #\a) (char-code x) (char-code #\z)) + (<= (char-code #\A) (char-code x) (char-code #\Z)))) (defun digit-char-p (x) - (if (and (<= #\0 x) (<= x #\9)) - (- x #\0) + (if (and (<= (char-code #\0) (char-code x) (char-code #\9))) + (- (char-code x) (char-code #\0)) nil)) (defun digit-char (weight) (and (<= 0 weight 9) (char "0123456789" weight))) -(defun subseq (seq a &optional b) +(defun equal (x y) (cond - ((stringp seq) - (if b - (slice seq a b) - (slice seq a))) - (t - (error "Unsupported argument.")))) - -(defmacro do-sequence (iteration &body body) - (let ((seq (gensym)) - (index (gensym))) - `(let ((,seq ,(second iteration))) - (cond - ;; Strings - ((stringp ,seq) - (let ((,index 0)) - (dotimes (,index (length ,seq)) - (let ((,(first iteration) - (char ,seq ,index))) - ,@body)))) - ;; Lists - ((listp ,seq) - (dolist (,(first iteration) ,seq) - ,@body)) - (t - (error "type-error!")))))) - -(defun some (function seq) - (do-sequence (elt seq) - (when (funcall function elt) - (return-from some t)))) - -(defun every (function seq) - (do-sequence (elt seq) - (unless (funcall function elt) - (return-from every nil))) - t) - -(defun position (elt sequence) - (let ((pos 0)) - (do-sequence (x seq) - (when (eq elt x) - (return)) - (incf pos)) - pos)) - -(defun assoc (x alist) - (while alist - (if (eql x (caar alist)) - (return) - (setq alist (cdr alist)))) - (car alist)) - -(defun string (x) - (cond ((stringp x) x) - ((symbolp x) (symbol-name x)) - (t (char-to-string x)))) - -(defun string= (s1 s2) - (equal s1 s2)) + ((eql x y) t) + ((consp x) + (and (consp y) + (equal (car x) (car y)) + (equal (cdr x) (cdr y)))) + ((stringp x) + (and (stringp y) (string= x y))) + (t nil))) (defun fdefinition (x) (cond @@ -574,23 +337,12 @@ ((symbolp x) (symbol-function x)) (t - (error "Invalid function")))) + (error "Invalid function `~S'." x)))) (defun disassemble (function) (write-line (lambda-code (fdefinition function))) nil) -(defun documentation (x type) - "Return the documentation of X. TYPE must be the symbol VARIABLE or FUNCTION." - (ecase type - (function - (let ((func (fdefinition x))) - (oget func "docstring"))) - (variable - (unless (symbolp x) - (error "Wrong argument type! it should be a symbol")) - (oget x "vardoc")))) - (defmacro multiple-value-bind (variables value-from &body body) `(multiple-value-call (lambda (&optional ,@variables &rest ,(gensym)) ,@body) @@ -602,29 +354,31 @@ ;;; Generalized references (SETF) -(defvar *setf-expanders* nil) - -(defun get-setf-expansion (place) - (if (symbolp place) - (let ((value (gensym))) - (values nil - nil - `(,value) - `(setq ,place ,value) - place)) - (let ((place (ls-macroexpand-1 place))) - (let* ((access-fn (car place)) - (expander (cdr (assoc access-fn *setf-expanders*)))) - (when (null expander) - (error "Unknown generalized reference.")) - (apply expander (cdr place)))))) +(eval-when(:compile-toplevel :load-toplevel :execute) + (defvar *setf-expanders* nil) + (defun !get-setf-expansion (place) + (if (symbolp place) + (let ((value (gensym))) + (values nil + nil + `(,value) + `(setq ,place ,value) + place)) + (let ((place (!macroexpand-1 place))) + (let* ((access-fn (car place)) + (expander (cdr (assoc access-fn *setf-expanders*)))) + (when (null expander) + (error "Unknown generalized reference.")) + (apply expander (cdr place))))))) +(fset 'get-setf-expansion (fdefinition '!get-setf-expansion)) (defmacro define-setf-expander (access-fn lambda-list &body body) (unless (symbolp access-fn) - (error "ACCESS-FN must be a symbol.")) - `(progn (push (cons ',access-fn (lambda ,lambda-list ,@body)) - *setf-expanders*) - ',access-fn)) + (error "ACCESS-FN `~S' must be a symbol." access-fn)) + `(eval-when (:compile-toplevel :load-toplevel :execute) + (push (cons ',access-fn (lambda ,lambda-list ,@body)) + *setf-expanders*) + ',access-fn)) (defmacro setf (&rest pairs) (cond @@ -633,16 +387,17 @@ ((null (cdr pairs)) (error "Odd number of arguments to setf.")) ((null (cddr pairs)) - (let ((place (ls-macroexpand-1 (first pairs))) + (let ((place (!macroexpand-1 (first pairs))) (value (second pairs))) (multiple-value-bind (vars vals store-vars writer-form reader-form) - (get-setf-expansion place) + (!get-setf-expansion place) ;; TODO: Optimize the expansion a little bit to avoid let* ;; or multiple-value-bind when unnecesary. `(let* ,(mapcar #'list vars vals) (multiple-value-bind ,store-vars ,value - ,writer-form))))) + ,writer-form + ,reader-form))))) (t `(progn ,@(do ((pairs pairs (cddr pairs)) @@ -650,23 +405,63 @@ ((null pairs) (reverse result))))))) -(define-setf-expander car (x) - (let ((cons (gensym)) - (new-value (gensym))) - (values (list cons) - (list x) - (list new-value) - `(progn (rplaca ,cons ,new-value) ,new-value) - `(car ,cons)))) - -(define-setf-expander cdr (x) - (let ((cons (gensym)) - (new-value (gensym))) - (values (list cons) - (list x) - (list new-value) - `(progn (rplacd ,cons ,new-value) ,new-value) - `(car ,cons)))) +(defmacro incf (place &optional (delta 1)) + (multiple-value-bind (dummies vals newval setter getter) + (!get-setf-expansion place) + (let ((d (gensym))) + `(let* (,@(mapcar #'list dummies vals) + (,d ,delta) + (,(car newval) (+ ,getter ,d)) + ,@(cdr newval)) + ,setter)))) + +(defmacro decf (place &optional (delta 1)) + (multiple-value-bind (dummies vals newval setter getter) + (!get-setf-expansion place) + (let ((d (gensym))) + `(let* (,@(mapcar #'list dummies vals) + (,d ,delta) + (,(car newval) (- ,getter ,d)) + ,@(cdr newval)) + ,setter)))) + +(defmacro push (x place) + (multiple-value-bind (dummies vals newval setter getter) + (!get-setf-expansion place) + (let ((g (gensym))) + `(let* ((,g ,x) + ,@(mapcar #'list dummies vals) + (,(car newval) (cons ,g ,getter)) + ,@(cdr newval)) + ,setter)))) + +(defmacro pop (place) + (multiple-value-bind (dummies vals newval setter getter) + (!get-setf-expansion place) + (let ((head (gensym))) + `(let* (,@(mapcar #'list dummies vals) + (,head ,getter) + (,(car newval) (cdr ,head)) + ,@(cdr newval)) + ,setter + (car ,head))))) + +(defmacro pushnew (x place &rest keys &key key test test-not) + (declare (ignore key test test-not)) + (multiple-value-bind (dummies vals newval setter getter) + (!get-setf-expansion place) + (let ((g (gensym)) + (v (gensym))) + `(let* ((,g ,x) + ,@(mapcar #'list dummies vals) + ,@(cdr newval) + (,v ,getter)) + (if (member ,g ,v ,@keys) + ,v + (let ((,(car newval) (cons ,g ,getter))) + ,setter)))))) + + ;; Incorrect typecase, but used in NCONC. (defmacro typecase (x &rest clausules) @@ -674,199 +469,39 @@ `(let ((,value ,x)) (cond ,@(mapcar (lambda (c) - (if (eq (car c) t) - `((t ,@(rest c))) + (if (find (car c) '(t otherwise)) + `(t ,@(rest c)) `((,(ecase (car c) (integer 'integerp) (cons 'consp) + (list 'listp) + (vector 'vectorp) + (character 'characterp) + (sequence 'sequencep) + (symbol 'symbolp) + (function 'functionp) + (float 'floatp) + (array 'arrayp) (string 'stringp) (atom 'atom) - (null 'null)) + (null 'null) + (package 'packagep)) ,value) ,@(or (rest c) (list nil))))) clausules))))) -;; The NCONC function is based on the SBCL's one. -(defun nconc (&rest lists) - (flet ((fail (object) - (error "type-error in nconc"))) - (do ((top lists (cdr top))) - ((null top) nil) - (let ((top-of-top (car top))) - (typecase top-of-top - (cons - (let* ((result top-of-top) - (splice result)) - (do ((elements (cdr top) (cdr elements))) - ((endp elements)) - (let ((ele (car elements))) - (typecase ele - (cons (rplacd (last splice) ele) - (setf splice ele)) - (null (rplacd (last splice) nil)) - (atom (if (cdr elements) - (fail ele) - (rplacd (last splice) ele)))))) - (return result))) - (null) - (atom - (if (cdr top) - (fail top-of-top) - (return top-of-top)))))))) - -(defun nreconc (x y) - (do ((1st (cdr x) (if (endp 1st) 1st (cdr 1st))) - (2nd x 1st) ; 2nd follows first down the list. - (3rd y 2nd)) ;3rd follows 2nd down the list. - ((atom 2nd) 3rd) - (rplacd 2nd 3rd))) +(defmacro etypecase (x &rest clausules) + (let ((g!x (gensym))) + `(let ((,g!x ,x)) + (typecase ,g!x + ,@clausules + (t (error "~S fell through etypecase expression." ,g!x)))))) (defun notany (fn seq) (not (some fn seq))) - -;; Packages - -(defvar *package-list* nil) - -(defun list-all-packages () - *package-list*) - -(defun make-package (name &key use) - (let ((package (new)) - (use (mapcar #'find-package-or-fail use))) - (oset package "packageName" name) - (oset package "symbols" (new)) - (oset package "exports" (new)) - (oset package "use" use) - (push package *package-list*) - package)) - -(defun packagep (x) - (and (objectp x) (in "symbols" x))) - -(defun find-package (package-designator) - (when (packagep package-designator) - (return-from find-package package-designator)) - (let ((name (string package-designator))) - (dolist (package *package-list*) - (when (string= (package-name package) name) - (return package))))) - -(defun find-package-or-fail (package-designator) - (or (find-package package-designator) - (error "Package unknown."))) - -(defun package-name (package-designator) - (let ((package (find-package-or-fail package-designator))) - (oget package "packageName"))) - -(defun %package-symbols (package-designator) - (let ((package (find-package-or-fail package-designator))) - (oget package "symbols"))) - -(defun package-use-list (package-designator) - (let ((package (find-package-or-fail package-designator))) - (oget package "use"))) - -(defun %package-external-symbols (package-designator) - (let ((package (find-package-or-fail package-designator))) - (oget package "exports"))) - -(defvar *common-lisp-package* - (make-package "CL")) - -(defvar *js-package* - (make-package "JS")) - -(defvar *user-package* - (make-package "CL-USER" :use (list *common-lisp-package*))) - -(defvar *keyword-package* - (make-package "KEYWORD")) - -(defun keywordp (x) - (and (symbolp x) (eq (symbol-package x) *keyword-package*))) - -(defvar *package* *common-lisp-package*) - -(defmacro in-package (package-designator) - `(eval-when-compile - (setq *package* (find-package-or-fail ,package-designator)))) - -;; This function is used internally to initialize the CL package -;; with the symbols built during bootstrap. -(defun %intern-symbol (symbol) - (let* ((package - (if (in "package" symbol) - (find-package-or-fail (oget symbol "package")) - *common-lisp-package*)) - (symbols (%package-symbols package))) - (oset symbol "package" package) - (when (eq package *keyword-package*) - (oset symbol "value" symbol)) - (oset symbols (symbol-name symbol) symbol))) - -(defun find-symbol (name &optional (package *package*)) - (let* ((package (find-package-or-fail package)) - (externals (%package-external-symbols package)) - (symbols (%package-symbols package))) - (cond - ((in name externals) - (values (oget externals name) :external)) - ((in name symbols) - (values (oget symbols name) :internal)) - (t - (dolist (used (package-use-list package) (values nil nil)) - (let ((exports (%package-external-symbols used))) - (when (in name exports) - (return (values (oget exports name) :inherit))))))))) - -(defun intern (name &optional (package *package*)) - (let ((package (find-package-or-fail package))) - (multiple-value-bind (symbol foundp) - (find-symbol name package) - (if foundp - (values symbol foundp) - (let ((symbols (%package-symbols package))) - (oget symbols name) - (let ((symbol (make-symbol name))) - (oset symbol "package" package) - (when (eq package *keyword-package*) - (oset symbol "value" symbol) - (export (list symbol) package)) - (when (eq package *js-package*) - (let ((sym-name (symbol-name symbol)) - (args (gensym))) - ;; Generate a trampoline to call the JS function - ;; properly. This trampoline is very inefficient, - ;; but it still works. Ideas to optimize this are - ;; provide a special lambda keyword - ;; cl::&rest-vector to avoid list argument - ;; consing, as well as allow inline declarations. - (fset symbol - (eval `(lambda (&rest ,args) - (let ((,args (list-to-vector ,args))) - (%js-call (%js-vref ,sym-name) ,args))))) - ;; Define it as a symbol macro to access to the - ;; Javascript variable literally. - (%define-symbol-macro symbol `(%js-vref ,(string symbol))))) - (oset symbols name symbol) - (values symbol nil))))))) - -(defun symbol-package (symbol) - (unless (symbolp symbol) - (error "it is not a symbol")) - (oget symbol "package")) - -(defun export (symbols &optional (package *package*)) - (let ((exports (%package-external-symbols package))) - (dolist (symb symbols t) - (oset exports (symbol-name symb) symb)))) - - -(defconstant internal-time-units-per-second 1000) +(defconstant internal-time-units-per-second 1000) (defun get-internal-real-time () (get-internal-real-time)) @@ -877,11 +512,16 @@ (defun get-universal-time () (+ (get-unix-time) 2208988800)) -(defun concat (&rest strs) - (!reduce #'concat-two strs :initial-value "")) - (defun values-list (list) (values-array (list-to-vector list))) (defun values (&rest args) (values-list args)) + +(defun error (fmt &rest args) + (%throw (apply #'format nil fmt args))) + +(defmacro nth-value (n form) + `(multiple-value-call (lambda (&rest values) + (nth ,n values)) + ,form))