1 ;;; boot.lisp --- First forms to be cross compiled
3 ;; Copyright (C) 2012, 2013 David Vazquez
4 ;; Copyright (C) 2012 Raimon Grau
6 ;; JSCL is free software: you can redistribute it and/or
7 ;; modify it under the terms of the GNU General Public License as
8 ;; published by the Free Software Foundation, either version 3 of the
9 ;; License, or (at your option) any later version.
11 ;; JSCL is distributed in the hope that it will be useful, but
12 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ;; General Public License for more details.
16 ;; You should have received a copy of the GNU General Public License
17 ;; along with JSCL. If not, see <http://www.gnu.org/licenses/>.
19 ;;; This code is executed when JSCL compiles this file itself. The
20 ;;; compiler provides compilation of some special forms, as well as
21 ;;; funcalls and macroexpansion, but no functions. So, we define the
22 ;;; Lisp world from scratch. This code has to define enough language
23 ;;; to the compiler to be able to run.
26 (%compile-defmacro 'defmacro
28 (lambda (name args &rest body)
30 (%compile-defmacro ',name
32 (lambda ,(mapcar #'(lambda (x)
39 (defmacro declaim (&rest decls)
41 ,@(mapcar (lambda (decl) `(!proclaim ',decl)) decls)))
43 (defmacro defconstant (name value &optional docstring)
45 (declaim (special ,name))
46 (declaim (constant ,name))
48 ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
52 (defconstant nil 'nil)
55 (defmacro lambda (args &body body)
56 `(function (lambda ,args ,@body)))
58 (defmacro when (condition &body body)
59 `(if ,condition (progn ,@body) nil))
61 (defmacro unless (condition &body body)
62 `(if ,condition nil (progn ,@body)))
64 (defmacro defvar (name value &optional docstring)
66 (declaim (special ,name))
67 (unless (boundp ',name) (setq ,name ,value))
68 ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
71 (defmacro defparameter (name value &optional docstring)
74 ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
77 (defmacro defun (name args &rest body)
79 (fset ',name #'(named-lambda ,name ,args ,@body))
82 (defmacro return (&optional value)
83 `(return-from nil ,value))
85 (defmacro while (condition &body body)
86 `(block nil (%while ,condition ,@body)))
88 (defvar *gensym-counter* 0)
89 (defun gensym (&optional (prefix "G"))
90 (setq *gensym-counter* (+ *gensym-counter* 1))
91 (make-symbol (concat-two prefix (integer-to-string *gensym-counter*))))
97 (defun = (x y) (= x y))
98 (defun * (x y) (* x y))
99 (defun / (x y) (/ x y))
100 (defun 1+ (x) (+ x 1))
101 (defun 1- (x) (- x 1))
102 (defun zerop (x) (= x 0))
104 (defun truncate (x &optional (y 1))
107 (defun eql (x y) (eq x y))
109 (defun not (x) (if x nil t))
113 (defmacro incf (place &optional (delta 1))
114 (multiple-value-bind (dummies vals newval setter getter)
115 (get-setf-expansion place)
117 `(let* (,@(mapcar #'list dummies vals)
119 (,(car newval) (+ ,getter ,d))
123 (defmacro decf (place &optional (delta 1))
124 (multiple-value-bind (dummies vals newval setter getter)
125 (get-setf-expansion place)
127 `(let* (,@(mapcar #'list dummies vals)
129 (,(car newval) (- ,getter ,d))
133 (defmacro push (x place)
134 (multiple-value-bind (dummies vals newval setter getter)
135 (get-setf-expansion place)
138 ,@(mapcar #'list dummies vals)
139 (,(car newval) (cons ,g ,getter))
143 (defmacro dolist (iter &body body)
144 (let ((var (first iter))
147 (let ((,g!list ,(second iter))
150 (setq ,var (car ,g!list))
152 (setq ,g!list (cdr ,g!list)))
155 (defmacro dotimes (iter &body body)
156 (let ((g!to (gensym))
159 (result (third iter)))
163 (%while (< ,var ,g!to)
168 (defmacro cond (&rest clausules)
171 (if (eq (caar clausules) t)
172 `(progn ,@(cdar clausules))
173 (let ((test-symbol (gensym)))
174 `(let ((,test-symbol ,(caar clausules)))
176 ,(if (null (cdar clausules))
178 `(progn ,@(cdar clausules)))
179 (cond ,@(cdr clausules))))))))
181 (defmacro case (form &rest clausules)
182 (let ((!form (gensym)))
183 `(let ((,!form ,form))
185 ,@(mapcar (lambda (clausule)
186 (if (or (eq (car clausule) t)
187 (eq (car clausule) 'otherwise))
188 `(t ,@(cdr clausule))
189 `((eql ,!form ',(car clausule))
193 (defmacro ecase (form &rest clausules)
194 (let ((g!form (gensym)))
195 `(let ((,g!form ,form))
200 (error "ECASE expression failed for the object `~S'." ,g!form))))))))
202 (defmacro and (&rest forms)
213 (defmacro or (&rest forms)
221 `(let ((,g ,(car forms)))
222 (if ,g ,g (or ,@(cdr forms))))))))
224 (defmacro prog1 (form &body body)
225 (let ((value (gensym)))
226 `(let ((,value ,form))
230 (defmacro prog2 (form1 result &body body)
231 `(prog1 (progn ,form1 ,result) ,@body))
235 ;;; Go on growing the Lisp language in Ecmalisp, with more high level
236 ;;; utilities as well as correct versions of other constructions.
238 (defun + (&rest args)
243 (defun - (x &rest others)
250 (defun append-two (list1 list2)
254 (append (cdr list1) list2))))
256 (defun append (&rest lists)
257 (!reduce #'append-two lists))
259 (defun revappend (list1 list2)
261 (push (car list1) list2)
262 (setq list1 (cdr list1)))
265 (defun reverse (list)
266 (revappend list '()))
268 (defmacro psetq (&rest pairs)
269 (let (;; For each pair, we store here a list of the form
270 ;; (VARIABLE GENSYM VALUE).
274 ((null pairs) (return))
276 (error "Odd paris in PSETQ"))
278 (let ((variable (car pairs))
279 (value (cadr pairs)))
280 (push `(,variable ,(gensym) ,value) assignments)
281 (setq pairs (cddr pairs))))))
282 (setq assignments (reverse assignments))
284 `(let ,(mapcar #'cdr assignments)
285 (setq ,@(!reduce #'append (mapcar #'butlast assignments))))))
287 (defmacro do (varlist endlist &body body)
289 (let ,(mapcar (lambda (x) (list (first x) (second x))) varlist)
292 (return (progn ,@(cdr endlist))))
297 (and (consp (cddr v))
298 (list (first v) (third v))))
301 (defmacro do* (varlist endlist &body body)
303 (let* ,(mapcar (lambda (x) (list (first x) (second x))) varlist)
306 (return (progn ,@(cdr endlist))))
311 (and (consp (cddr v))
312 (list (first v) (third v))))
315 (defun list-length (list)
317 (while (not (null list))
319 (setq list (cdr list)))
331 (defun concat-two (s1 s2)
334 (defmacro with-collect (&body body)
335 (let ((head (gensym))
337 `(let* ((,head (cons 'sentinel nil))
340 (rplacd ,tail (cons x nil))
341 (setq ,tail (cdr ,tail))
347 (defmacro loop (&body body)
350 (defun identity (x) x)
352 (defun constantly (x)
366 (and (numberp x) (= (floor x) x)))
369 (and (numberp x) (not (integerp x))))
371 (defun plusp (x) (< 0 x))
372 (defun minusp (x) (< x 0))
377 (defun find (item list &key key (test #'eql))
379 (when (funcall test (funcall key x) item)
382 (defun remove (x list)
387 (remove x (cdr list)))
389 (cons (car list) (remove x (cdr list))))))
391 (defun remove-if (func list)
395 ((funcall func (car list))
396 (remove-if func (cdr list)))
399 (cons (car list) (remove-if func (cdr list))))))
401 (defun remove-if-not (func list)
405 ((funcall func (car list))
406 (cons (car list) (remove-if-not func (cdr list))))
408 (remove-if-not func (cdr list)))))
410 (defun digit-char-p (x)
411 (if (and (<= (char-code #\0) (char-code x) (char-code #\9)))
412 (- (char-code x) (char-code #\0))
415 (defun digit-char (weight)
417 (char "0123456789" weight)))
419 (defun subseq (seq a &optional b)
426 (error "Unsupported argument."))))
428 (defmacro do-sequence (iteration &body body)
431 `(let ((,seq ,(second iteration)))
436 (dotimes (,index (length ,seq))
437 (let ((,(first iteration)
442 (dolist (,(first iteration) ,seq)
445 (error "type-error!"))))))
447 (defun some (function seq)
448 (do-sequence (elt seq)
449 (when (funcall function elt)
450 (return-from some t))))
452 (defun every (function seq)
453 (do-sequence (elt seq)
454 (unless (funcall function elt)
455 (return-from every nil)))
458 (defun position (elt sequence)
467 (cond ((stringp x) x)
468 ((symbolp x) (symbol-name x))
469 (t (char-to-string x))))
476 (equal (car x) (car y))
477 (equal (cdr x) (cdr y))))
480 (let ((n (length x)))
481 (when (= (length y) n)
483 (unless (equal (aref x i) (aref y i))
484 (return-from equal nil)))
488 (defun string= (s1 s2)
491 (defun fdefinition (x)
498 (error "Invalid function `~S'." x))))
500 (defun disassemble (function)
501 (write-line (lambda-code (fdefinition function)))
504 (defun documentation (x type)
505 "Return the documentation of X. TYPE must be the symbol VARIABLE or FUNCTION."
508 (let ((func (fdefinition x)))
509 (oget func "docstring")))
512 (error "The type of documentation `~S' is not a symbol." type))
515 (defmacro multiple-value-bind (variables value-from &body body)
516 `(multiple-value-call (lambda (&optional ,@variables &rest ,(gensym))
520 (defmacro multiple-value-list (value-from)
521 `(multiple-value-call #'list ,value-from))
524 ;;; Generalized references (SETF)
526 (defvar *setf-expanders* nil)
528 (defun get-setf-expansion (place)
530 (let ((value (gensym)))
534 `(setq ,place ,value)
536 (let ((place (!macroexpand-1 place)))
537 (let* ((access-fn (car place))
538 (expander (cdr (assoc access-fn *setf-expanders*))))
539 (when (null expander)
540 (error "Unknown generalized reference."))
541 (apply expander (cdr place))))))
543 (defmacro define-setf-expander (access-fn lambda-list &body body)
544 (unless (symbolp access-fn)
545 (error "ACCESS-FN `~S' must be a symbol." access-fn))
546 `(progn (push (cons ',access-fn (lambda ,lambda-list ,@body))
550 (defmacro setf (&rest pairs)
555 (error "Odd number of arguments to setf."))
557 (let ((place (!macroexpand-1 (first pairs)))
558 (value (second pairs)))
559 (multiple-value-bind (vars vals store-vars writer-form)
560 (get-setf-expansion place)
561 ;; TODO: Optimize the expansion a little bit to avoid let*
562 ;; or multiple-value-bind when unnecesary.
563 `(let* ,(mapcar #'list vars vals)
564 (multiple-value-bind ,store-vars
569 ,@(do ((pairs pairs (cddr pairs))
570 (result '() (cons `(setf ,(car pairs) ,(cadr pairs)) result)))
572 (reverse result)))))))
574 ;; Incorrect typecase, but used in NCONC.
575 (defmacro typecase (x &rest clausules)
576 (let ((value (gensym)))
579 ,@(mapcar (lambda (c)
595 (defun notany (fn seq)
599 (defconstant internal-time-units-per-second 1000)
601 (defun get-internal-real-time ()
602 (get-internal-real-time))
604 (defun get-unix-time ()
605 (truncate (/ (get-internal-real-time) 1000)))
607 (defun get-universal-time ()
608 (+ (get-unix-time) 2208988800))
610 (defun concat (&rest strs)
611 (!reduce #'concat-two strs :initial-value ""))
613 (defun values-list (list)
614 (values-array (list-to-vector list)))
616 (defun values (&rest args)
619 (defun error (fmt &rest args)
620 (%throw (apply #'format nil fmt args)))