8c1d6c2780e81f07f278ca5745ec42cf67fb9078
[jscl.git] / src / boot.lisp
1 ;;; boot.lisp --- First forms to be cross compiled
2
3 ;; Copyright (C) 2012, 2013 David Vazquez
4 ;; Copyright (C) 2012 Raimon Grau
5
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.
10 ;;
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.
15 ;;
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/>.
18
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.
24
25 (eval-when-compile
26   (let ((defmacro-macroexpander
27          '#'(lambda (form)
28               (destructuring-bind (name args &body body)
29                   form
30                 (let ((whole (gensym)))
31                   `(eval-when-compile
32                      (%compile-defmacro ',name
33                                         '#'(lambda (,whole)
34                                              (destructuring-bind ,args ,whole
35                                                ,@body)))))))))
36     (%compile-defmacro 'defmacro defmacro-macroexpander)))
37
38 (defmacro declaim (&rest decls)
39   `(eval-when-compile
40      ,@(mapcar (lambda (decl) `(!proclaim ',decl)) decls)))
41
42 (defmacro defconstant (name value &optional docstring)
43   `(progn
44      (declaim (special ,name))
45      (declaim (constant ,name))
46      (setq ,name ,value)
47      ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
48      ',name))
49
50 (defconstant t 't)
51 (defconstant nil 'nil)
52 (%js-vset "nil" nil)
53
54 (defmacro lambda (args &body body)
55   `(function (lambda ,args ,@body)))
56
57 (defmacro when (condition &body body)
58   `(if ,condition (progn ,@body) nil))
59
60 (defmacro unless (condition &body body)
61   `(if ,condition nil (progn ,@body)))
62
63 (defmacro defvar (name value &optional docstring)
64   `(progn
65      (declaim (special ,name))
66      (unless (boundp ',name) (setq ,name ,value))
67      ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
68      ',name))
69
70 (defmacro defparameter (name value &optional docstring)
71   `(progn
72      (setq ,name ,value)
73      ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
74      ',name))
75
76 (defmacro defun (name args &rest body)
77   `(progn
78      (fset ',name #'(named-lambda ,name ,args ,@body))
79      ',name))
80
81 (defmacro return (&optional value)
82   `(return-from nil ,value))
83
84 (defmacro while (condition &body body)
85   `(block nil (%while ,condition ,@body)))
86
87 (defvar *gensym-counter* 0)
88 (defun gensym (&optional (prefix "G"))
89   (setq *gensym-counter* (+ *gensym-counter* 1))
90   (make-symbol (concat-two prefix (integer-to-string *gensym-counter*))))
91
92 (defun boundp (x)
93   (boundp x))
94
95 ;; Basic functions
96 (defun = (x y) (= x y))
97 (defun * (x y) (* x y))
98 (defun / (x y) (/ x y))
99 (defun 1+ (x) (+ x 1))
100 (defun 1- (x) (- x 1))
101 (defun zerop (x) (= x 0))
102
103 (defun truncate (x &optional (y 1))
104   (floor (/ x y)))
105
106 (defun eql (x y) (eq x y))
107
108 (defun not (x) (if x nil t))
109
110 ;; Basic macros
111
112 (defmacro incf (place &optional (delta 1))
113   (multiple-value-bind (dummies vals newval setter getter)
114       (get-setf-expansion place)
115     (let ((d (gensym)))
116       `(let* (,@(mapcar #'list dummies vals)
117               (,d ,delta)
118                 (,(car newval) (+ ,getter ,d))
119                 ,@(cdr newval))
120          ,setter))))
121
122 (defmacro decf (place &optional (delta 1))
123   (multiple-value-bind (dummies vals newval setter getter)
124       (get-setf-expansion place)
125     (let ((d (gensym)))
126       `(let* (,@(mapcar #'list dummies vals)
127               (,d ,delta)
128               (,(car newval) (- ,getter ,d))
129               ,@(cdr newval))
130          ,setter))))
131
132 (defmacro push (x place)
133   (multiple-value-bind (dummies vals newval setter getter)
134       (get-setf-expansion place)
135     (let ((g (gensym)))
136       `(let* ((,g ,x)
137               ,@(mapcar #'list dummies vals)
138               (,(car newval) (cons ,g ,getter))
139               ,@(cdr newval))
140          ,setter))))
141
142 (defmacro dolist ((var list &optional result) &body body)
143   (let ((g!list (gensym)))
144     (unless (symbolp var) (error "`~S' is not a symbol." var))
145     `(block nil
146        (let ((,g!list ,list)
147              (,var nil))
148          (%while ,g!list
149                  (setq ,var (car ,g!list))
150                  (tagbody ,@body)
151                  (setq ,g!list (cdr ,g!list)))
152          ,result))))
153
154 (defmacro dotimes ((var count &optional result) &body body)
155   (let ((g!count (gensym)))
156     (unless (symbolp var) (error "`~S' is not a symbol." var))
157     `(block nil
158        (let ((,var 0)
159              (,g!count ,count))
160          (%while (< ,var ,g!count)
161                  (tagbody ,@body)
162                  (incf ,var))
163          ,result))))
164
165 (defmacro cond (&rest clausules)
166   (if (null clausules)
167     nil
168     (if (eq (caar clausules) t)
169       `(progn ,@(cdar clausules))
170       (let ((test-symbol (gensym)))
171         `(let ((,test-symbol ,(caar clausules)))
172            (if ,test-symbol
173              ,(if (null (cdar clausules))
174                 test-symbol
175                 `(progn ,@(cdar clausules)))
176              (cond ,@(cdr clausules))))))))
177
178 (defmacro case (form &rest clausules)
179   (let ((!form (gensym)))
180     `(let ((,!form ,form))
181        (cond
182          ,@(mapcar (lambda (clausule)
183                      (if (or (eq (car clausule) t)
184                              (eq (car clausule) 'otherwise))
185                          `(t ,@(cdr clausule))
186                          `((eql ,!form ',(car clausule))
187                            ,@(cdr clausule))))
188                    clausules)))))
189
190 (defmacro ecase (form &rest clausules)
191   (let ((g!form (gensym)))
192     `(let ((,g!form ,form))
193        (case ,g!form
194          ,@(append
195             clausules
196             `((t
197                (error "ECASE expression failed for the object `~S'." ,g!form))))))))
198
199 (defmacro and (&rest forms)
200   (cond
201     ((null forms)
202      t)
203     ((null (cdr forms))
204      (car forms))
205     (t
206      `(if ,(car forms)
207           (and ,@(cdr forms))
208           nil))))
209
210 (defmacro or (&rest forms)
211   (cond
212     ((null forms)
213      nil)
214     ((null (cdr forms))
215      (car forms))
216     (t
217      (let ((g (gensym)))
218        `(let ((,g ,(car forms)))
219           (if ,g ,g (or ,@(cdr forms))))))))
220
221 (defmacro prog1 (form &body body)
222   (let ((value (gensym)))
223     `(let ((,value ,form))
224        ,@body
225        ,value)))
226
227 (defmacro prog2 (form1 result &body body)
228   `(prog1 (progn ,form1 ,result) ,@body))
229
230
231
232 ;;; Go on growing the Lisp language in Ecmalisp, with more high level
233 ;;; utilities as well as correct versions of other constructions.
234
235 (defun + (&rest args)
236   (let ((r 0))
237     (dolist (x args r)
238       (incf r x))))
239
240 (defun - (x &rest others)
241   (if (null others)
242       (- x)
243       (let ((r x))
244         (dolist (y others r)
245           (decf r y)))))
246
247 (defun append-two (list1 list2)
248   (if (null list1)
249       list2
250       (cons (car list1)
251             (append (cdr list1) list2))))
252
253 (defun append (&rest lists)
254   (!reduce #'append-two lists nil))
255
256 (defun revappend (list1 list2)
257   (while list1
258     (push (car list1) list2)
259     (setq list1 (cdr list1)))
260   list2)
261
262 (defun reverse (list)
263   (revappend list '()))
264
265 (defmacro psetq (&rest pairs)
266   (let (;; For each pair, we store here a list of the form
267         ;; (VARIABLE GENSYM VALUE).
268         (assignments '()))
269     (while t
270       (cond
271         ((null pairs) (return))
272         ((null (cdr pairs))
273          (error "Odd paris in PSETQ"))
274         (t
275          (let ((variable (car pairs))
276                (value (cadr pairs)))
277            (push `(,variable ,(gensym) ,value)  assignments)
278            (setq pairs (cddr pairs))))))
279     (setq assignments (reverse assignments))
280     ;;
281     `(let ,(mapcar #'cdr assignments)
282        (setq ,@(!reduce #'append (mapcar #'butlast assignments) nil)))))
283
284 (defmacro do (varlist endlist &body body)
285   `(block nil
286      (let ,(mapcar (lambda (x) (list (first x) (second x))) varlist)
287        (while t
288          (when ,(car endlist)
289            (return (progn ,@(cdr endlist))))
290          (tagbody ,@body)
291          (psetq
292           ,@(apply #'append
293                    (mapcar (lambda (v)
294                              (and (consp (cddr v))
295                                   (list (first v) (third v))))
296                            varlist)))))))
297
298 (defmacro do* (varlist endlist &body body)
299   `(block nil
300      (let* ,(mapcar (lambda (x) (list (first x) (second x))) varlist)
301        (while t
302          (when ,(car endlist)
303            (return (progn ,@(cdr endlist))))
304          (tagbody ,@body)
305          (setq
306           ,@(apply #'append
307                    (mapcar (lambda (v)
308                              (and (consp (cddr v))
309                                   (list (first v) (third v))))
310                            varlist)))))))
311
312 (defun list-length (list)
313   (let ((l 0))
314     (while (not (null list))
315       (incf l)
316       (setq list (cdr list)))
317     l))
318
319 (defun length (seq)
320   (cond
321     ((stringp seq)
322      (string-length seq))
323     ((arrayp seq)
324      (oget seq "length"))
325     ((listp seq)
326      (list-length seq))))
327
328 (defun concat-two (s1 s2)
329   (concat-two s1 s2))
330
331 (defmacro with-collect (&body body)
332   (let ((head (gensym))
333         (tail (gensym)))
334     `(let* ((,head (cons 'sentinel nil))
335             (,tail ,head))
336        (flet ((collect (x)
337                 (rplacd ,tail (cons x nil))
338                 (setq ,tail (cdr ,tail))
339                 x))
340          ,@body)
341        (cdr ,head))))
342
343
344 (defmacro loop (&body body)
345   `(while t ,@body))
346
347 (defun identity (x) x)
348
349 (defun constantly (x)
350   (lambda (&rest args)
351     x))
352
353 (defun code-char (x)
354   (code-char x))
355
356 (defun char-code (x)
357   (char-code x))
358
359 (defun char= (x y)
360   (eql x y))
361
362 (defun integerp (x)
363   (and (numberp x) (= (floor x) x)))
364
365 (defun floatp (x)
366   (and (numberp x) (not (integerp x))))
367
368 (defun plusp (x) (< 0 x))
369 (defun minusp (x) (< x 0))
370
371 (defun atom (x)
372   (not (consp x)))
373
374 (defun remove (x list)
375   (cond
376     ((null list)
377      nil)
378     ((eql x (car list))
379      (remove x (cdr list)))
380     (t
381      (cons (car list) (remove x (cdr list))))))
382
383 (defun remove-if (func list)
384   (cond
385     ((null list)
386      nil)
387     ((funcall func (car list))
388      (remove-if func (cdr list)))
389     (t
390      ;;
391      (cons (car list) (remove-if func (cdr list))))))
392
393 (defun remove-if-not (func list)
394   (cond
395     ((null list)
396      nil)
397     ((funcall func (car list))
398      (cons (car list) (remove-if-not func (cdr list))))
399     (t
400      (remove-if-not func (cdr list)))))
401
402 (defun alpha-char-p (x)
403   (or (<= (char-code #\a) (char-code x) (char-code #\z))
404       (<= (char-code #\Z) (char-code x) (char-code #\Z))))
405
406 (defun digit-char-p (x)
407   (if (and (<= (char-code #\0) (char-code x) (char-code #\9)))
408       (- (char-code x) (char-code #\0))
409       nil))
410
411 (defun digit-char (weight)
412   (and (<= 0 weight 9)
413        (char "0123456789" weight)))
414
415 (defun subseq (seq a &optional b)
416   (if b
417       (slice seq a b)
418       (slice seq a)))
419
420 (defmacro do-sequence (iteration &body body)
421   (let ((seq (gensym))
422         (index (gensym)))
423     `(let ((,seq ,(second iteration)))
424        (cond
425          ;; Strings
426          ((stringp ,seq)
427           (let ((,index 0))
428             (dotimes (,index (length ,seq))
429               (let ((,(first iteration)
430                      (char ,seq ,index)))
431                 ,@body))))
432          ;; Lists
433          ((listp ,seq)
434           (dolist (,(first iteration) ,seq)
435             ,@body))
436          (t
437           (error "type-error!"))))))
438
439 (defun find (item sequence &key (key #'identity) (test #'eql))
440   (do-sequence (x sequence)
441     (when (funcall test (funcall key x) item)
442       (return x))))
443
444 (defun find-if (predicate sequence &key (key #'identity))
445   (do-sequence (x sequence)
446     (when (funcall predicate (funcall key x))
447       (return x))))
448
449 (defun some (function seq)
450   (do-sequence (elt seq)
451     (when (funcall function elt)
452       (return-from some t))))
453
454 (defun every (function seq)
455   (do-sequence (elt seq)
456     (unless (funcall function elt)
457       (return-from every nil)))
458   t)
459
460 (defun position (elt sequence)
461   (let ((pos 0))
462     (do-sequence (x seq)
463       (when (eq elt x)
464         (return))
465       (incf pos))
466     pos))
467
468 (defun equal (x y)
469   (cond
470     ((eql x y) t)
471     ((consp x)
472      (and (consp y)
473           (equal (car x) (car y))
474           (equal (cdr x) (cdr y))))
475     ((stringp x)
476      (and (stringp y) (string= x y)))
477     (t nil)))
478
479 (defun fdefinition (x)
480   (cond
481     ((functionp x)
482      x)
483     ((symbolp x)
484      (symbol-function x))
485     (t
486      (error "Invalid function `~S'." x))))
487
488 (defun disassemble (function)
489   (write-line (lambda-code (fdefinition function)))
490   nil)
491
492 (defun documentation (x type)
493   "Return the documentation of X. TYPE must be the symbol VARIABLE or FUNCTION."
494   (ecase type
495     (function
496      (let ((func (fdefinition x)))
497        (oget func "docstring")))
498     (variable
499      (unless (symbolp x)
500        (error "The type of documentation `~S' is not a symbol." type))
501      (oget x "vardoc"))))
502
503 (defmacro multiple-value-bind (variables value-from &body body)
504   `(multiple-value-call (lambda (&optional ,@variables &rest ,(gensym))
505                           ,@body)
506      ,value-from))
507
508 (defmacro multiple-value-list (value-from)
509   `(multiple-value-call #'list ,value-from))
510
511
512 ;;; Generalized references (SETF)
513
514 (defvar *setf-expanders* nil)
515
516 (defun get-setf-expansion (place)
517   (if (symbolp place)
518       (let ((value (gensym)))
519         (values nil
520                 nil
521                 `(,value)
522                 `(setq ,place ,value)
523                 place))
524       (let ((place (!macroexpand-1 place)))
525         (let* ((access-fn (car place))
526                (expander (cdr (assoc access-fn *setf-expanders*))))
527           (when (null expander)
528             (error "Unknown generalized reference."))
529           (apply expander (cdr place))))))
530
531 (defmacro define-setf-expander (access-fn lambda-list &body body)
532   (unless (symbolp access-fn)
533     (error "ACCESS-FN `~S' must be a symbol." access-fn))
534   `(progn (push (cons ',access-fn (lambda ,lambda-list ,@body))
535                 *setf-expanders*)
536           ',access-fn))
537
538 (defmacro setf (&rest pairs)
539   (cond
540     ((null pairs)
541      nil)
542     ((null (cdr pairs))
543      (error "Odd number of arguments to setf."))
544     ((null (cddr pairs))
545      (let ((place (!macroexpand-1 (first pairs)))
546            (value (second pairs)))
547        (multiple-value-bind (vars vals store-vars writer-form)
548            (get-setf-expansion place)
549          ;; TODO: Optimize the expansion a little bit to avoid let*
550          ;; or multiple-value-bind when unnecesary.
551          `(let* ,(mapcar #'list vars vals)
552             (multiple-value-bind ,store-vars
553                 ,value
554               ,writer-form)))))
555     (t
556      `(progn
557         ,@(do ((pairs pairs (cddr pairs))
558                (result '() (cons `(setf ,(car pairs) ,(cadr pairs)) result)))
559               ((null pairs)
560                (reverse result)))))))
561
562 ;; Incorrect typecase, but used in NCONC.
563 (defmacro typecase (x &rest clausules)
564   (let ((value (gensym)))
565     `(let ((,value ,x))
566        (cond
567          ,@(mapcar (lambda (c)
568                      (if (eq (car c) t)
569                          `((t ,@(rest c)))
570                          `((,(ecase (car c)
571                                     (integer 'integerp)
572                                     (cons 'consp)
573                                     (symbol 'symbolp)
574                                     (array 'arrayp)
575                                     (string 'stringp)
576                                     (atom 'atom)
577                                     (null 'null))
578                              ,value)
579                            ,@(or (rest c)
580                                  (list nil)))))
581                    clausules)))))
582
583 (defmacro etypecase (x &rest clausules)
584   (let ((g!x (gensym)))
585     `(let ((,g!x ,x))
586        (typecase ,g!x
587          ,@clausules
588          (t (error "~X fell through etypeacase expression." ,g!x))))))
589
590 (defun notany (fn seq)
591   (not (some fn seq)))
592
593 (defconstant internal-time-units-per-second 1000) 
594
595 (defun get-internal-real-time ()
596   (get-internal-real-time))
597
598 (defun get-unix-time ()
599   (truncate (/ (get-internal-real-time) 1000)))
600
601 (defun get-universal-time ()
602   (+ (get-unix-time) 2208988800))
603
604 (defun concat (&rest strs)
605   (!reduce #'concat-two strs ""))
606
607 (defun values-list (list)
608   (values-array (list-to-vector list)))
609
610 (defun values (&rest args)
611   (values-list args))
612
613 (defun error (fmt &rest args)
614   (%throw (apply #'format nil fmt args)))
615